diff --git a/.DS_Store b/.DS_Store index 16c61a05..1918b62b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/CLA-entity.md b/CLA-entity.md new file mode 100644 index 00000000..43eb3cfe --- /dev/null +++ b/CLA-entity.md @@ -0,0 +1,82 @@ +OpenMPTCProuter Entity Contributor License Agreement +================================================== + +Thank you for your interest in contributing to OpenMPTCProuter ("We" or "Us"). + +This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please submit a pull request with a file under the `/contributors` directory indicating your acceptance of this agreement. + +This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us. + +## 1. Definitions + +"You" means any Legal Entity on behalf of whom a Contribution has been received by Us. "Legal Entity" means an entity which is not a natural person. "Affiliates" means other Legal Entities that control, are controlled by, or under common control with that Legal Entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such Legal Entity, whether by contract or otherwise, (ii) ownership of fifty percent (50%) or more of the outstanding shares or securities which vote to elect the management or other persons who direct such Legal Entity or (iii) beneficial ownership of such entity. + +"Contribution" means any work of authorship that is Submitted by You to Us in which You own or assert ownership of the Copyright. If You do not own the Copyright in the entire work of authorship, please follow the instructions in . + +"Copyright" means all rights protecting works of authorship owned or controlled by You or Your Affiliates, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You. + +"Material" means the work of authorship which is made available by Us to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material. + +"Submit" means any form of electronic, verbal, or written communication sent to Us or our representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." + +"Submission Date" means the date on which You Submit a Contribution to Us. + +"Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier. + +## 2. Grant of Rights + +2.1 Copyright License + +(a) You retain ownership of the Copyright in Your Contribution and have the same rights to use or license the Contribution which You would have had without entering into the Agreement. + +(b) To the maximum extent permitted by the relevant law, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the Copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3. + +2.2 Patent License + +For patent claims including, without limitation, method, process, and apparatus claims which You or Your Affiliates own, control or have the right to grant, now or in the future, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3. + +2.3 Outbound License + +Based on the grant of rights in Sections 2.1 and 2.2, if We include Your Contribution in a Material, We may license the Contribution under any license, including copyleft, permissive, commercial, or proprietary licenses. As a condition on the exercise of this right, We agree to also license the Contribution under the terms of the license or licenses which We are using for the Material on the Submission Date. + +2.4 Moral Rights. If moral rights apply to the Contribution, to the maximum extent permitted by law, You waive and agree not to assert such moral rights against Us or our successors in interest, or any of our licensees, either direct or indirect. + +2.5 Our Rights. You acknowledge that We are not obligated to use Your Contribution as part of the Material and may decide to include any Contribution We consider appropriate. + +2.6 Reservation of Rights. Any rights not expressly licensed under this section are expressly reserved by You. + +## 3. Agreement + +You confirm that: + +(a) You have the legal authority to enter into this Agreement. + +(b) You or Your Affiliates own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2. + +(c) The grant of rights under Section 2 does not violate any grant of rights which You or Your Affiliates have made to third parties. + +(d) You have followed the instructions in , if You do not own the Copyright in the entire work of authorship Submitted. + +## 4. Disclaimer + +EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. + +## 5. Consequential Damage Waiver + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +## 6. Miscellaneous + +6.1 This Agreement will be governed by and construed in accordance with the laws of excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement. + +6.2 This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings. + +6.3 If You or We assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement. + +6.4 The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety. + +6.5 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law. + +This agreement is derived from the Project Harmony CLA generator: +http://www.harmonyagreements.org/ +Harmony (HA-CLA-E-ANY) Version 1.0 diff --git a/CLA-individual.md b/CLA-individual.md new file mode 100644 index 00000000..bbbba134 --- /dev/null +++ b/CLA-individual.md @@ -0,0 +1,83 @@ +OpenMPTCProuter Individual Contributor License Agreement +====================================================== + +Thank you for your interest in contributing to OpenMPTCProuter ("We" or "Us"). + +This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please submit a pull request with a file under the `/contributors` directory indicating your acceptance of this agreement. + +This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us. + +## 1. Definitions + +"You" means the individual who Submits a Contribution to Us. + +"Contribution" means any work of authorship that is Submitted by You to Us in which You own or assert ownership of the Copyright. If You do not own the Copyright in the entire work of authorship, please follow the instructions in . + +"Copyright" means all rights protecting works of authorship owned or controlled by You, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You. + +"Material" means the work of authorship which is made available by Us to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material. + +"Submit" means any form of electronic, verbal, or written communication sent to Us or our representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." + +"Submission Date" means the date on which You Submit a Contribution to Us. + +"Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier. + +## 2. Grant of Rights + +2.1 Copyright License + +(a) You retain ownership of the Copyright in Your Contribution and have the same rights to use or license the Contribution which You would have had without entering into the Agreement. + +(b) To the maximum extent permitted by the relevant law, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the Copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3. + +2.2 Patent License + +For patent claims including, without limitation, method, process, and apparatus claims which You own, control or have the right to grant, now or in the future, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3. + +2.3 Outbound License + +Based on the grant of rights in Sections 2.1 and 2.2, if We include Your Contribution in a Material, We may license the Contribution under any license, including copyleft, permissive, commercial, or proprietary licenses. As a condition on the exercise of this right, We agree to also license the Contribution under the terms of the license or licenses which We are using for the Material on the Submission Date. + +2.4 Moral Rights. If moral rights apply to the Contribution, to the maximum extent permitted by law, You waive and agree not to assert such moral rights against Us or our successors in interest, or any of our licensees, either direct or indirect. + +2.5 Our Rights. You acknowledge that We are not obligated to use Your Contribution as part of the Material and may decide to include any Contribution We consider appropriate. + +2.6 Reservation of Rights. Any rights not expressly licensed under this section are expressly reserved by You. + +3. Agreement + +You confirm that: + +(a) You have the legal authority to enter into this Agreement. + +(b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2. + +(c) The grant of rights under Section 2 does not violate any grant of rights which You have made to third parties, including Your employer. If You are an employee, You have had Your employer approve this Agreement or sign the Entity version of this document. If You are less than eighteen years old, please have Your parents or guardian sign the Agreement. + +(d) You have followed the instructions in , if You do not own the Copyright in the entire work of authorship Submitted. + +## 4. Disclaimer + +EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. + +## 5. Consequential Damage Waiver + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +## 6. Miscellaneous + +6.1 This Agreement will be governed by and construed in accordance with the laws of excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement. + +6.2 This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings. + +6.3 If You or We assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement. + +6.4 The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety. + +6.5 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law. + +This agreement is derived from the Project Harmony CLA generator: +http://www.harmonyagreements.org/ +Harmony (HA-CLA-I-ANY) Version 1.0 + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..05fbbc85 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@openmptcprouter.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..83235db7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +Contribution + +When submitting a pull request for the first time, you will need to agree to the contributor license agreement (for individuals or entities). To do this, in the pull request please create a file with a name like /contributors/{github_username}.md, and in the content of that file indicate your agreement. An example of what that file should contain can be seen in example agreement file. + +(This method of CLA "signing" is borrowed from Medium's open source project.) diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..9cecc1d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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) {year} {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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 00000000..c198b1ec --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +[![CircleCI](https://circleci.com/gh/Ysurac/openmptcprouter-feeds.svg?style=svg)](https://circleci.com/gh/Ysurac/openmptcprouter-feeds) +![Latest tag](https://img.shields.io/github/tag/ysurac/openmptcprouter-feeds.svg) +[![Paypal](https://www.openmptcprouter.com/img/donate-PayPal-green.svg)](https://www.paypal.me/ycarus) +[![Flattr](https://www.openmptcprouter.com/img/donate-flattr-yellow.svg)](https://flattr.com/@ycarus) +[![Liberapay](https://img.shields.io/liberapay/patrons/Moul.svg?logo=liberapay)](https://liberapay.com/Ycarus/) +[![LinkedIn](https://www.openmptcprouter.com/img/linkedin.png)](https://www.linkedin.com/in/yannick-chabanois-550330146/) +[![Twitter](https://www.openmptcprouter.com/img/twitter.jpg)](https://twitter.com/OpenMPTCProuter) +[![Atom](https://www.openmptcprouter.com/img/feed.png)](https://www.openmptcprouter.com/atom) + +# OpenMPTCProuter + +OpenMPTCProuter is an open source solution to aggregate and encrypt multiple internet connections and terminates it over any VPS which make clients benefit security, reliability, net neutrality, as well as dedicated public IP. + +The aggregation is based on Multipath TCP (MPTCP), which is ISP, WAN type, and latency independent "whether it was Fiber, VDSL, SHDSL, ADSL or even 4G", different scenarios can be configured to have either aggregation or failover based on MPTCP. + +Aggregation via [Multi-link VPN (MLVPN)](https://github.com/markfoodyburton/MLVPN/commits/new-reorder) and [Glorytun UDP](https://github.com/angt/glorytun) with multipath support are also supported. + +The solution takes advantage of the OpenWRT/LEDE system, which is user friendly and also adds the possibility of installing other packages like VPN, QoS, routing protocols, monitoring, etc. through web-interface or terminal. + + +Main website: [https://www.openmptcprouter.com/](https://www.openmptcprouter.com/) + +Packages made for OpenMPTCProuter are available here: [https://github.com/Ysurac/openmptcprouter-feeds](https://github.com/Ysurac/openmptcprouter-feeds) + +OpenMPTCProuter VPS script part: [https://github.com/Ysurac/openmptcprouter-vps](https://github.com/Ysurac/openmptcprouter-vps) + + +## Install from pre-compiled images + +You can download precompiled images from [https://www.openmptcprouter.com/](https://www.openmptcprouter.com/) + +Then copy it to a sdcard: + +```sh +gunzip omr-*.img.gz +dd bs=4M if=omr-*.img of=/dev/sdX conv=fsync +``` + +## Install from source + +[Create image](https://github.com/Ysurac/openmptcprouter/wiki/Create-image-for-unsupported-platform) + + +## Credits + +Our solution is mainly based on: + +* [OpenWRT](https://openwrt.org) +* [MultiPath TCP (MPTCP)](https://multipath-tcp.org) +* [Shadowsocks](https://shadowsocks.org) +* [Glorytun](https://github.com/angt/glorytun) \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..3b4dffd6 --- /dev/null +++ b/build.sh @@ -0,0 +1,326 @@ +#!/bin/sh + +set -e + +umask 0022 +unset GREP_OPTIONS SED + +_get_repo() ( + mkdir -p "$1" + cd "$1" + [ -d .git ] || git init + if git remote get-url origin >/dev/null 2>/dev/null; then + git remote set-url origin "$2" + else + git remote add origin "$2" + fi + git fetch origin -f + git fetch origin --tags -f + git checkout -f "origin/$3" -B "build" 2>/dev/null || git checkout "$3" -B "build" +) + +OMR_DIST=${OMR_DIST:-openmptcprouter} +OMR_HOST=${OMR_HOST:-$(curl -sS ifconfig.co)} +OMR_PORT=${OMR_PORT:-8000} +OMR_KEEPBIN=${OMR_KEEPBIN:-no} +OMR_IMG=${OMR_IMG:-yes} +#OMR_UEFI=${OMR_UEFI:-yes} +OMR_PACKAGES=${OMR_PACKAGES:-full} +OMR_ALL_PACKAGES=${OMR_ALL_PACKAGES:-no} +OMR_TARGET=${OMR_TARGET:-x86_64} +OMR_TARGET_CONFIG="config-$OMR_TARGET" +OMR_KERNEL=${OMR_KERNEL:-5.4} +#OMR_RELEASE=${OMR_RELEASE:-$(git describe --tags `git rev-list --tags --max-count=1` | sed 's/^\([0-9.]*\).*/\1/')} +OMR_RELEASE=${OMR_RELEASE:-$(git tag --sort=committerdate | tail -1)} +OMR_REPO=${OMR_REPO:-http://$OMR_HOST:$OMR_PORT/release/$OMR_RELEASE/$OMR_TARGET} + +OMR_FEED_URL="${OMR_FEED_URL:-https://github.com/ysurac/openmptcprouter-feeds}" +OMR_FEED_SRC="${OMR_FEED_SRC:-develop}" + +CUSTOM_FEED_URL="${CUSTOM_FEED_URL}" + +OMR_OPENWRT=${OMR_OPENWRT:-default} + +if [ ! -f "$OMR_TARGET_CONFIG" ]; then + echo "Target $OMR_TARGET not found !" + #exit 1 +fi + +if [ "$OMR_TARGET" = "rpi3" ]; then + OMR_REAL_TARGET="aarch64_cortex-a53" +elif [ "$OMR_TARGET" = "rpi4" ]; then + OMR_REAL_TARGET="aarch64_cortex-a72" +elif [ "$OMR_TARGET" = "rpi2" ]; then + OMR_REAL_TARGET="arm_cortex-a7_neon-vfpv4" +elif [ "$OMR_TARGET" = "wrt3200acm" ]; then + OMR_REAL_TARGET="arm_cortex-a9_vfpv3" +elif [ "$OMR_TARGET" = "wrt32x" ]; then + OMR_REAL_TARGET="arm_cortex-a9_vfpv3" +elif [ "$OMR_TARGET" = "bpi-r2" ]; then + OMR_REAL_TARGET="arm_cortex-a7_neon-vfpv4" +elif [ "$OMR_TARGET" = "bpi-r64" ]; then + OMR_REAL_TARGET="aarch64_cortex-a53" +elif [ "$OMR_TARGET" = "espressobin" ]; then + OMR_REAL_TARGET="aarch64_cortex-a53" +elif [ "$OMR_TARGET" = "x86" ]; then + OMR_REAL_TARGET="i386_pentium4" +else + OMR_REAL_TARGET=${OMR_TARGET} +fi + +#_get_repo source https://github.com/ysurac/openmptcprouter-source "master" +if [ "$OMR_OPENWRT" = "default" ]; then + _get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "38f6d5d217ca0c42f7f42b08f835a8a9cee71ad7" + _get_repo feeds/packages https://github.com/openwrt/packages "7479b3ecfafa6732185080ddfca68b68e27993b2" + _get_repo feeds/luci https://github.com/openwrt/luci "b95ac83ffd4fcf268be964002c45beba17d6e5c1" +elif [ "$OMR_OPENWRT" = "master" ]; then + _get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "master" + _get_repo feeds/packages https://github.com/openwrt/packages "master" + _get_repo feeds/luci https://github.com/openwrt/luci "master" +else + _get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "${OMR_OPENWRT}" + _get_repo feeds/packages https://github.com/openwrt/packages "${OMR_OPENWRT}" + _get_repo feeds/luci https://github.com/openwrt/luci "${OMR_OPENWRT}" +fi + +if [ -z "$OMR_FEED" ]; then + OMR_FEED=feeds/openmptcprouter + _get_repo "$OMR_FEED" "$OMR_FEED_URL" "$OMR_FEED_SRC" +fi + +if [ -n "$CUSTOM_FEED_URL" ]; then + CUSTOM_FEED=feeds/${OMR_DIST} + _get_repo "$CUSTOM_FEED" "$CUSTOM_FEED_URL" "master" +fi + +if [ -n "$1" ] && [ -f "$OMR_FEED/$1/Makefile" ]; then + OMR_DIST=$1 + shift 1 +fi + +if [ "$OMR_KEEPBIN" = "no" ]; then + rm -rf "$OMR_TARGET/source/bin" +fi +rm -rf "$OMR_TARGET/source/files" "$OMR_TARGET/source/tmp" +#rm -rf "$OMR_TARGET/source/target/linux/mediatek/patches-4.14" +cp -rf root/* "$OMR_TARGET/source" + +cat >> "$OMR_TARGET/source/package/base-files/files/etc/banner" < "$OMR_TARGET/source/feeds.conf" <> "$OMR_TARGET/source/feeds.conf" +fi + +if [ "$OMR_DIST" = "openmptcprouter" ]; then + cat > "$OMR_TARGET/source/package/system/opkg/files/customfeeds.conf" <<-EOF + src/gz openwrt_luci http://packages.openmptcprouter.com/${OMR_RELEASE}/${OMR_REAL_TARGET}/luci + src/gz openwrt_packages http://packages.openmptcprouter.com/${OMR_RELEASE}/${OMR_REAL_TARGET}/packages + src/gz openwrt_base http://packages.openmptcprouter.com/${OMR_RELEASE}/${OMR_REAL_TARGET}/base + src/gz openwrt_routing http://packages.openmptcprouter.com/${OMR_RELEASE}/${OMR_REAL_TARGET}/routing + src/gz openwrt_telephony http://packages.openmptcprouter.com/${OMR_RELEASE}/${OMR_REAL_TARGET}/telephony + EOF +else + cat > "$OMR_TARGET/source/package/system/opkg/files/customfeeds.conf" <<-EOF + src/gz openwrt_luci http://downloads.openwrt.org/snapshots/packages/${OMR_REAL_TARGET}/luci + src/gz openwrt_packages http://downloads.openwrt.org/snapshots/packages/${OMR_REAL_TARGET}/packages + src/gz openwrt_base http://downloads.openwrt.org/snapshots/packages/${OMR_REAL_TARGET}/base + src/gz openwrt_routing http://downloads.openwrt.org/snapshots/packages/${OMR_REAL_TARGET}/routing + src/gz openwrt_telephony http://downloads.openwrt.org/snapshots/packages/${OMR_REAL_TARGET}/telephony + EOF +fi +#cat > "$OMR_TARGET/source/package/system/opkg/files/customfeeds.conf" < "$OMR_TARGET/source/.config" <<-EOF + CONFIG_IMAGEOPT=y + CONFIG_VERSIONOPT=y + CONFIG_VERSION_DIST="$OMR_DIST" + CONFIG_VERSION_REPO="$OMR_REPO" + CONFIG_VERSION_NUMBER="$(git -C "$OMR_FEED" describe --tag --always)" + EOF +else + cat config -> "$OMR_TARGET/source/.config" <<-EOF + CONFIG_IMAGEOPT=y + CONFIG_VERSIONOPT=y + CONFIG_VERSION_DIST="$OMR_DIST" + CONFIG_VERSION_REPO="$OMR_REPO" + CONFIG_VERSION_NUMBER="$(git -C "$OMR_FEED" describe --tag --always)" + EOF +fi +if [ "$OMR_ALL_PACKAGES" = "yes" ]; then + echo 'CONFIG_ALL=y' >> "$OMR_TARGET/source/.config" + echo 'CONFIG_ALL_NONSHARED=y' >> "$OMR_TARGET/source/.config" +fi +if [ "$OMR_IMG" = "yes" ] && [ "$OMR_TARGET" = "x86_64" ]; then + echo 'CONFIG_VDI_IMAGES=y' >> "$OMR_TARGET/source/.config" + echo 'CONFIG_VMDK_IMAGES=y' >> "$OMR_TARGET/source/.config" + echo 'CONFIG_VHDX_IMAGES=y' >> "$OMR_TARGET/source/.config" +fi + +if [ "$OMR_PACKAGES" = "full" ]; then + echo "CONFIG_PACKAGE_${OMR_DIST}-full=y" >> "$OMR_TARGET/source/.config" +fi +if [ "$OMR_PACKAGES" = "mini" ]; then + echo "CONFIG_PACKAGE_${OMR_DIST}-mini=y" >> "$OMR_TARGET/source/.config" +fi + +cd "$OMR_TARGET/source" + +#if [ "$OMR_UEFI" = "yes" ] && [ "$OMR_TARGET" = "x86_64" ]; then +# echo "Checking if UEFI patch is set or not" +# if [ "$(grep 'EFI_IMAGES' target/linux/x86/image/Makefile)" = "" ]; then +# patch -N -p1 -s < ../../patches/uefi.patch +# fi +# echo "Done" +#else +# if [ "$(grep 'EFI_IMAGES' target/linux/x86/image/Makefile)" != "" ]; then +# patch -N -R -p1 -s < ../../patches/uefi.patch +# fi +#fi + +#if [ "$OMR_TARGET" = "x86_64" ]; then +# echo "Checking if Hyper-V patch is set or not" +# if ! patch -Rf -N -p1 -s --dry-run < ../../patches/images.patch; then +# patch -N -p1 -s < ../../patches/images.patch +# fi +# echo "Done" +#fi + +echo "Checking if No check patch is set or not" +if ! patch -Rf -N -p1 -s --dry-run < ../../patches/nocheck.patch; then + echo "apply..." + patch -N -p1 -s < ../../patches/nocheck.patch +fi +echo "Done" + +echo "Checking if Nanqinlang patch is set or not" +if ! patch -Rf -N -p1 -s --dry-run < ../../patches/nanqinlang.patch; then + echo "apply..." + patch -N -p1 -s < ../../patches/nanqinlang.patch +fi +echo "Done" + +echo "Checking if smsc75xx patch is set or not" +if ! patch -Rf -N -p1 -s --dry-run < ../../patches/smsc75xx.patch; then + echo "apply..." + patch -N -p1 -s < ../../patches/smsc75xx.patch +fi +echo "Done" + +#echo "Checking if ipt-nat patch is set or not" +#if ! patch -Rf -N -p1 -s --dry-run < ../../patches/ipt-nat6.patch; then +# echo "apply..." +# patch -N -p1 -s < ../../patches/ipt-nat6.patch +#fi +#echo "Done" + +#echo "Checking if mvebu patch is set or not" +#if [ ! -d target/linux/mvebu/patches-5.4 ]; then +# echo "apply..." +# patch -N -p1 -s < ../../patches/mvebu-5.14.patch +#fi +#echo "Done" + +echo "Checking if opkg install arguement too long patch is set or not" +if ! patch -Rf -N -p1 -s --dry-run < ../../patches/package-too-long.patch; then + echo "apply..." + patch -N -p1 -s < ../../patches/package-too-long.patch +fi +echo "Done" + +echo "Download via IPv4" +if ! patch -Rf -N -p1 -s --dry-run < ../../patches/download-ipv4.patch; then + patch -N -p1 -s < ../../patches/download-ipv4.patch +fi +echo "Done" + +if [ -f target/linux/mediatek/patches-5.4/0999-hnat.patch ]; then + rm -f target/linux/mediatek/patches-5.4/0999-hnat.patch +fi + +#echo "Patch protobuf wrong hash" +#patch -N -R -p1 -s < ../../patches/protobuf_hash.patch +#echo "Done" + +#echo "Remove gtime dependency" +#if ! patch -Rf -N -p1 -s --dry-run < ../../patches/gtime.patch; then +# patch -N -p1 -s < ../../patches/gtime.patch +#fi +#echo "Done" + +if [ "$OMR_KERNEL" = "5.4" ]; then + echo "Set to kernel 5.4 for rpi arch" + find target/linux/bcm27xx -type f -name Makefile -exec sed -i 's%KERNEL_PATCHVER:=4.19%KERNEL_PATCHVER:=5.4%g' {} \; + echo "Done" + echo "Set to kernel 5.4 for x86 arch" + find target/linux/x86 -type f -name Makefile -exec sed -i 's%KERNEL_PATCHVER:=4.19%KERNEL_PATCHVER:=5.4%g' {} \; + echo "Done" + echo "Set to kernel 5.4 for mvebu arch (WRT)" + find target/linux/mvebu -type f -name Makefile -exec sed -i 's%KERNEL_PATCHVER:=4.19%KERNEL_PATCHVER:=5.4%g' {} \; + echo "Done" + echo "Set to kernel 5.4 for mediatek arch (BPI-R2)" + find target/linux/mediatek -type f -name Makefile -exec sed -i 's%KERNEL_PATCHVER:=4.19%KERNEL_PATCHVER:=5.4%g' {} \; + echo "Done" +fi + +#rm -rf feeds/packages/libs/libwebp + +echo "Update feeds index" +rm -rf feeds/luci/modules/luci-mod-network +[ -d feeds/${OMR_DIST}/luci-mod-status ] && rm -rf feeds/luci/modules/luci-mod-status + +cp .config .config.keep +scripts/feeds clean +scripts/feeds update -a + +#cd - +#echo "Checking if fullconenat-luci patch is set or not" +##if ! patch -Rf -N -p1 -s --dry-run < patches/fullconenat-luci.patch; then +# echo "apply..." +# patch -N -p1 -s < patches/fullconenat-luci.patch +#fi +#echo "Done" +#cd "$OMR_TARGET/source" + +if [ "$OMR_ALL_PACKAGES" = "yes" ]; then + scripts/feeds install -a -d m -p packages + scripts/feeds install -a -d m -p luci +fi +if [ -n "$CUSTOM_FEED" ]; then + scripts/feeds install -a -d m -p openmptcprouter + scripts/feeds install -a -d y -f -p ${OMR_DIST} +else + scripts/feeds install -a -d y -f -p openmptcprouter +fi +cp .config.keep .config +echo "Done" + +if [ ! -f "../../$OMR_TARGET_CONFIG" ]; then + echo "Target $OMR_TARGET not found ! You have to configure and compile your kernel manually." + exit 1 +fi + +echo "Building $OMR_DIST for the target $OMR_TARGET" +make defconfig +make IGNORE_ERRORS=m "$@" +echo "Done" diff --git a/config b/config new file mode 100644 index 00000000..c40719ef --- /dev/null +++ b/config @@ -0,0 +1,248 @@ +CONFIG_DEVEL=y +CONFIG_TOOLCHAINOPTS=y +CONFIG_ALL_KMODS=y +CONFIG_BUSYBOX_CUSTOM=y +CONFIG_BUSYBOX_CONFIG_ADDUSER=y +CONFIG_BUSYBOX_CONFIG_ARP=y +CONFIG_BUSYBOX_CONFIG_ARPING=y +CONFIG_BUSYBOX_CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_BUSYBOX_CONFIG_BASE64=y +CONFIG_BUSYBOX_CONFIG_CHPASSWD=y +CONFIG_BUSYBOX_CONFIG_DELUSER=y +CONFIG_BUSYBOX_CONFIG_DIFF=y +CONFIG_BUSYBOX_CONFIG_FEATURE_DATE_NANO=y +CONFIG_BUSYBOX_CONFIG_FEATURE_DIFF_DIR=y +CONFIG_BUSYBOX_CONFIG_FEATURE_PS_LONG=y +CONFIG_BUSYBOX_CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_BUSYBOX_CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_BUSYBOX_CONFIG_FEATURE_STAT_FILESYSTEM=y +CONFIG_BUSYBOX_CONFIG_FEATURE_STAT_FORMAT=y +# CONFIG_BUSYBOX_CONFIG_FEATURE_TOP_DECIMALS is not set +# CONFIG_BUSYBOX_CONFIG_FEATURE_TOP_SMP_CPU is not set +# CONFIG_BUSYBOX_CONFIG_FEATURE_TOP_SMP_PROCESS is not set +CONFIG_BUSYBOX_CONFIG_FEATURE_USE_TERMIOS=y +CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO=y +CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE=y +CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=32 +CONFIG_BUSYBOX_CONFIG_IOSTAT=y +CONFIG_BUSYBOX_CONFIG_LOADKMAP=y +CONFIG_BUSYBOX_CONFIG_LSPCI=y +CONFIG_BUSYBOX_CONFIG_LSUSB=y +CONFIG_BUSYBOX_CONFIG_NOHUP=y +CONFIG_BUSYBOX_CONFIG_PKILL=y +CONFIG_BUSYBOX_CONFIG_STAT=y +CONFIG_BUSYBOX_CONFIG_STTY=y +CONFIG_BUSYBOX_CONFIG_TELNET=y +CONFIG_BUSYBOX_CONFIG_TIMEOUT=y +CONFIG_BUSYBOX_CONFIG_WATCH=y +# CONFIG_GDB is not set +CONFIG_GRUB_SERIAL="" +CONFIG_GRUB_TIMEOUT="0" +CONFIG_GRUB_TITLE="OpenMPTCProuter" +CONFIG_KERNEL_AIO=y +CONFIG_KERNEL_DEBUG_GPIO=y +# CONFIG_KERNEL_DEBUG_INFO is not set +CONFIG_KERNEL_DEBUG_PINCTRL=y +CONFIG_KERNEL_DEVTMPFS=y +CONFIG_KERNEL_DEVTMPFS_MOUNT=y +CONFIG_KERNEL_DIRECT_IO=y +CONFIG_KERNEL_FANOTIFY=y +CONFIG_KERNEL_FHANDLE=y +CONFIG_KERNEL_IPC_NS=y +# CONFIG_KERNEL_MAGIC_SYSRQ is not set +CONFIG_KERNEL_NAMESPACES=y +CONFIG_KERNEL_NET_NS=y +CONFIG_KERNEL_PID_NS=y +# CONFIG_KERNEL_SWAP is not set +CONFIG_KERNEL_USER_NS=y +CONFIG_KERNEL_UTS_NS=y +# CONFIG_PACKAGE_dnsmasq is not set +CONFIG_PACKAGE_kmod-8021q=y +CONFIG_PACKAGE_kmod-ata-ahci=y +CONFIG_PACKAGE_kmod-ata-core=y +CONFIG_PACKAGE_kmod-block2mtd=y +CONFIG_PACKAGE_kmod-bridge=y +CONFIG_PACKAGE_kmod-crypto-gcm=y +CONFIG_PACKAGE_kmod-gpio-button-hotplug=y +CONFIG_PACKAGE_kmod-hid=y +CONFIG_PACKAGE_kmod-hid-generic=y +CONFIG_PACKAGE_kmod-i2c-gpio=y +CONFIG_PACKAGE_kmod-i2c-gpio-custom=y +CONFIG_PACKAGE_kmod-ifb=y +CONFIG_PACKAGE_kmod-ikconfig=y +CONFIG_PACKAGE_kmod-input-evdev=y +CONFIG_PACKAGE_kmod-loop=y +CONFIG_PACKAGE_kmod-macvlan=y +CONFIG_PACKAGE_kmod-mmc=y +CONFIG_PACKAGE_kmod-mmc-spi=y +CONFIG_PACKAGE_kmod-random-core=y +CONFIG_DEFAULT_kmod-r8169=y +CONFIG_PACKAGE_kmod-scsi-core=y +CONFIG_PACKAGE_kmod-sctp=y +CONFIG_PACKAGE_kmod-sdhci=y +CONFIG_PACKAGE_kmod-serial-8250=y +CONFIG_PACKAGE_kmod-stp=y +CONFIG_PACKAGE_kmod-usb-acm=y +CONFIG_PACKAGE_kmod-usb-core=y +CONFIG_PACKAGE_kmod-usb-hid=y +CONFIG_PACKAGE_kmod-usb-net=y +CONFIG_PACKAGE_kmod-usb-net-asix=y +CONFIG_PACKAGE_kmod-usb-net-asix-ax88179=y +CONFIG_PACKAGE_kmod-usb-net-cdc-eem=y +CONFIG_PACKAGE_kmod-usb-net-cdc-ether=y +CONFIG_PACKAGE_kmod-usb-net-cdc-mbim=y +CONFIG_PACKAGE_kmod-usb-net-cdc-ncm=y +CONFIG_PACKAGE_kmod-usb-net-cdc-subset=y +CONFIG_PACKAGE_kmod-usb-net-dm9601-ether=y +CONFIG_PACKAGE_kmod-usb-net-hso=y +CONFIG_PACKAGE_kmod-usb-net-huawei-cdc-ncm=y +CONFIG_PACKAGE_kmod-usb-net-ipheth=y +CONFIG_PACKAGE_kmod-usb-net-kalmia=y +CONFIG_PACKAGE_kmod-usb-net-kaweth=y +CONFIG_PACKAGE_kmod-usb-net-mcs7830=y +CONFIG_PACKAGE_kmod-usb-net-pegasus=y +CONFIG_PACKAGE_kmod-usb-net-qmi-wwan=y +CONFIG_PACKAGE_kmod-usb-net-rndis=y +CONFIG_PACKAGE_kmod-usb-net-rtl8150=y +CONFIG_PACKAGE_kmod-usb-net-rtl8152=y +CONFIG_PACKAGE_kmod-usb-net-sierrawireless=y +CONFIG_PACKAGE_kmod-usb-net-smsc95xx=y +CONFIG_PACKAGE_kmod-usb-net-sr9700=y +CONFIG_PACKAGE_kmod-usb-serial=y +CONFIG_PACKAGE_kmod-usb-serial-ark3116=y +CONFIG_PACKAGE_kmod-usb-serial-belkin=y +CONFIG_PACKAGE_kmod-usb-serial-ch341=y +CONFIG_PACKAGE_kmod-usb-serial-cp210x=y +CONFIG_PACKAGE_kmod-usb-serial-cypress-m8=y +CONFIG_PACKAGE_kmod-usb-serial-ftdi=y +CONFIG_PACKAGE_kmod-usb-serial-garmin=y +CONFIG_PACKAGE_kmod-usb-serial-ipw=y +CONFIG_PACKAGE_kmod-usb-serial-keyspan=y +CONFIG_PACKAGE_kmod-usb-serial-mct=y +CONFIG_PACKAGE_kmod-usb-serial-mos7720=y +CONFIG_PACKAGE_kmod-usb-serial-option=y +CONFIG_PACKAGE_kmod-usb-serial-oti6858=y +CONFIG_PACKAGE_kmod-usb-serial-pl2303=y +CONFIG_PACKAGE_kmod-usb-serial-qualcomm=y +CONFIG_PACKAGE_kmod-usb-serial-sierrawireless=y +CONFIG_PACKAGE_kmod-usb-serial-simple=y +CONFIG_PACKAGE_kmod-usb-serial-ti-usb=y +CONFIG_PACKAGE_kmod-usb-serial-visor=y +CONFIG_PACKAGE_kmod-usb-serial-wwan=y +CONFIG_PACKAGE_kmod-usb-storage=y +CONFIG_PACKAGE_kmod-usb-wdm=y +CONFIG_PACKAGE_kmod-usb2=y +CONFIG_PACKAGE_kmod-usb3=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-3c59x=y +CONFIG_PACKAGE_kmod-8139cp=y +CONFIG_PACKAGE_kmod-8139too=y +CONFIG_PACKAGE_kmod-atl1=y +CONFIG_PACKAGE_kmod-atl1c=y +CONFIG_PACKAGE_kmod-atl1e=y +CONFIG_PACKAGE_kmod-atl2=y +CONFIG_PACKAGE_kmod-b44=y +CONFIG_PACKAGE_kmod-bnx2=y +CONFIG_PACKAGE_kmod-dm9000=y +CONFIG_PACKAGE_kmod-e100=y +CONFIG_PACKAGE_kmod-e1000=y +CONFIG_PACKAGE_kmod-e1000e=y +CONFIG_PACKAGE_kmod-et131x=y +CONFIG_PACKAGE_kmod-ethoc=y +CONFIG_PACKAGE_kmod-forcedeth=y +CONFIG_PACKAGE_kmod-gigaset=y +CONFIG_PACKAGE_kmod-hfcmulti=y +CONFIG_PACKAGE_kmod-hfcpci=y +CONFIG_PACKAGE_kmod-natsemi=y +CONFIG_PACKAGE_kmod-ne2k-pci=y +CONFIG_PACKAGE_kmod-of-mdio=y +CONFIG_PACKAGE_kmod-pcnet32=y +CONFIG_PACKAGE_kmod-phy-broadcom=y +CONFIG_PACKAGE_kmod-ppfe=y +CONFIG_PACKAGE_kmod-r6040=y +CONFIG_PACKAGE_kmod-r8169=y +CONFIG_PACKAGE_kmod-sis190=y +CONFIG_PACKAGE_kmod-sis900=y +CONFIG_PACKAGE_kmod-skge=y +CONFIG_PACKAGE_kmod-sky2=y +CONFIG_PACKAGE_kmod-solos-pci=y +CONFIG_PACKAGE_kmod-spi-ks8995=y +CONFIG_PACKAGE_kmod-tg3=y +CONFIG_PACKAGE_kmod-tulip=y +CONFIG_PACKAGE_kmod-via-rhine=y +CONFIG_PACKAGE_kmod-via-velocity=y +CONFIG_PACKAGE_kmod-vmxnet3=y +CONFIG_PACKAGE_kmod-fs-vfat=y +CONFIG_TARGET_IMAGES_PAD=y +CONFIG_TARGET_ROOTFS_EXT4=y +CONFIG_KERNEL_TCP_CONG_CDG=y +CONFIG_KERNEL_TCP_CONG_HTCP=y +CONFIG_KERNEL_TCP_CONG_HSTCP=y +CONFIG_KERNEL_TCP_CONG_HYBLA=y +CONFIG_KERNEL_TCP_CONG_ILLINOIS=y +CONFIG_KERNEL_TCP_CONG_SCALABLE=y +CONFIG_KERNEL_TCP_CONG_VEGAS=y +CONFIG_KERNEL_TCP_CONG_VENO=y +CONFIG_KERNEL_TCP_CONG_WESTWOOD=y +CONFIG_KERNEL_TCP_CONG_YEAH=y +CONFIG_KERNEL_TCP_CONG_LIA=y +CONFIG_KERNEL_TCP_CONG_BBR=y +CONFIG_KERNEL_TCP_CONG_NANQINLANG=y +CONFIG_KERNEL_TCP_CONG_OLIA=y +CONFIG_KERNEL_TCP_CONG_WVEGAS=y +CONFIG_KERNEL_TCP_CONG_BALIA=y +CONFIG_KERNEL_MPTCP_FULLMESH=y +CONFIG_KERNEL_DEFAULT_FULLMESH=y +CONFIG_KERNEL_MPTCP_NDIFFPORTS=y +# CONFIG_KERNEL_DEFAULT_NDIFFPORTS is not set +CONFIG_KERNEL_MPTCP_BINDER=y +CONFIG_KERNEL_MPTCP_ECF=y +# CONFIG_KERNEL_DEFAULT_BINDER is not set +# CONFIG_KERNEL_DEFAULT_DUMMY is not set +CONFIG_KERNEL_MPTCP_ROUNDROBIN=y +# CONFIG_KERNEL_DEFAULT_ROUNDROBIN is not set +CONFIG_KERNEL_MPTCP_REDUNDANT=y +# CONFIG_KERNEL_DEFAULT_REDUNDANT is not set +CONFIG_KERNEL_DEFAULT_SCHEDULER=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_CRYPTO_SHA256=y +CONFIG_LUCI_LANG_hu=y +CONFIG_LUCI_LANG_pt=y +CONFIG_LUCI_LANG_sk=y +CONFIG_LUCI_LANG_ro=y +CONFIG_LUCI_LANG_en=y +CONFIG_LUCI_LANG_pl=y +CONFIG_LUCI_LANG_uk=y +CONFIG_LUCI_LANG_ja=y +CONFIG_LUCI_LANG_vi=y +CONFIG_LUCI_LANG_de=y +CONFIG_LUCI_LANG_no=y +CONFIG_LUCI_LANG_ms=y +CONFIG_LUCI_LANG_zh_Hans=y +CONFIG_LUCI_LANG_zh_Hant=y +CONFIG_LUCI_LANG_ko=y +CONFIG_LUCI_LANG_he=y +CONFIG_LUCI_LANG_zh-tw=y +CONFIG_LUCI_LANG_tr=y +CONFIG_LUCI_LANG_sv=y +CONFIG_LUCI_LANG_ru=y +CONFIG_LUCI_LANG_el=y +CONFIG_LUCI_LANG_ca=y +CONFIG_LUCI_LANG_es=y +CONFIG_LUCI_LANG_pt_BR=y +CONFIG_LUCI_LANG_cs=y +CONFIG_LUCI_LANG_fr=y +CONFIG_LUCI_LANG_it=y +CONFIG_LUCI_LANG_ar=y +CONFIG_LUCI_LANG_bg=y +CONFIG_LUCI_LANG_bn_BD=y +CONFIG_LUCI_LANG_fi=y +CONFIG_LUCI_LANG_hi=y +CONFIG_LUCI_LANG_mr=y +CONFIG_LUCI_LANG_nb_NO=y +CONFIG_TARGET_ROOTFS_PARTSIZE=512 +CONFIG_TARGET_KERNEL_PARTSIZE=64 +CONFIG_OPENSSL_WITH_CHACHA_POLY1305=y +# CONFIG_LUCI_CSSTIDY is not set +# CONFIG_LIBCURL_WOLFSSL is not set +# CONFIG_PACKAGE_libustream-wolfssl is not set diff --git a/config-bpi-r2 b/config-bpi-r2 new file mode 100644 index 00000000..4022b63d --- /dev/null +++ b/config-bpi-r2 @@ -0,0 +1,19 @@ +CONFIG_TARGET_mediatek=y +CONFIG_TARGET_mediatek_mt7623=y +CONFIG_TARGET_mediatek_mt7623_DEVICE_bpi_bananapi-r2=y +CONFIG_TARGET_ROOTFS_EXT4FS=y +CONFIG_TARGET_ROOTFS_SQUASHFS=y +CONFIG_PACKAGE_kmod-cryptodev=y +CONFIG_OPENSSL_HARDWARE_SUPPORT=y +CONFIG_OPENSSL_ENGINE_CRYPTO=y +CONFIG_OPENSSL_ENGINE_DIGEST=y +CONFIG_PACKAGE_uboot-envtools=y +CONFIG_PACKAGE_attr=y +CONFIG_PACKAGE_f2fs-tools=y +CONFIG_PACKAGE_f2fsck=y +CONFIG_PACKAGE_mkf2fs=y +# CONFIG_PACKAGE_kmod-fs-nfs-v3 is not set +# CONFIG_PACKAGE_kmod-fs-nfs-v4 is not set +# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set +# CONFIG_PACKAGE_kmod-mt6625l-bt is not set +# CONFIG_PACKAGE_kmod-mt6625l-wlan-gen-2 is not set diff --git a/config-espressobin b/config-espressobin new file mode 100644 index 00000000..b11d9a82 --- /dev/null +++ b/config-espressobin @@ -0,0 +1,7 @@ +CONFIG_TARGET_mvebu=y +CONFIG_TARGET_mvebu_cortexa53=y +CONFIG_TARGET_mvebu_cortexa53_DEVICE_globalscale_espressobin-v7=y +CONFIG_PACKAGE_kmod-6lowpan=y +CONFIG_PACKAGE_luci-app-advanced-reboot=y +# CONFIG_KERNEL_CC_OPTIMIZE_FOR_PERFORMANCE is not set +CONFIG_KERNEL_CC_OPTIMIZE_FOR_SIZE=y diff --git a/config-p2w_r619ac b/config-p2w_r619ac new file mode 100644 index 00000000..f4d50da2 --- /dev/null +++ b/config-p2w_r619ac @@ -0,0 +1,6 @@ +CONFIG_TARGET_ipq40xx=y +CONFIG_TARGET_ipq40xx_generic=y +CONFIG_TARGET_ipq40xx_generic_DEVICE_p2w_r619ac-128m=y +CONFIG_PACKAGE_kmod-6lowpan=y +# CONFIG_KERNEL_CC_OPTIMIZE_FOR_PERFORMANCE is not set +CONFIG_KERNEL_CC_OPTIMIZE_FOR_SIZE=y diff --git a/config-r2s b/config-r2s new file mode 100644 index 00000000..15c5d543 --- /dev/null +++ b/config-r2s @@ -0,0 +1,4 @@ +CONFIG_TARGET_rockchip=y +CONFIG_TARGET_rockchip_armv8=y +CONFIG_TARGET_ramips_armv8_DEVICE_friendlyarm_nanopi-r2s=y +CONFIG_PACKAGE_kmod-6lowpan=y diff --git a/config-rpi2 b/config-rpi2 new file mode 100644 index 00000000..e79e72d2 --- /dev/null +++ b/config-rpi2 @@ -0,0 +1,7 @@ +CONFIG_TARGET_bcm27xx=y +CONFIG_TARGET_bcm27xx_bcm2709=y +CONFIG_TARGET_bcm27xx_bcm2709_DEVICE_rpi-2=y +CONFIG_PACKAGE_kmod-ath10k-ct=n +CONFIG_PACKAGE_kmod-ath9k=y +CONFIG_PACKAGE_bcm27xx-eeprom=y +CONFIG_PACKAGE_bcm27xx-userland=y diff --git a/config-rpi3 b/config-rpi3 new file mode 100644 index 00000000..e5370b2d --- /dev/null +++ b/config-rpi3 @@ -0,0 +1,5 @@ +CONFIG_TARGET_bcm27xx=y +CONFIG_TARGET_bcm27xx_bcm2710=y +CONFIG_TARGET_bcm27xx_bcm2710_DEVICE_rpi-3=y +CONFIG_PACKAGE_kmod-ath10k-ct=n +CONFIG_PACKAGE_kmod-ath9k=y diff --git a/config-rpi4 b/config-rpi4 new file mode 100644 index 00000000..7fb408aa --- /dev/null +++ b/config-rpi4 @@ -0,0 +1,7 @@ +CONFIG_TARGET_bcm27xx=y +CONFIG_TARGET_bcm27xx_bcm2711=y +CONFIG_TARGET_bcm27xx_bcm2711_DEVICE_rpi-4=y +CONFIG_PACKAGE_kmod-ath10k-ct=n +CONFIG_PACKAGE_kmod-ath9k=y +CONFIG_PACKAGE_bcm27xx-eeprom=y +CONFIG_PACKAGE_bcm27xx-userland=y diff --git a/config-wrt3200acm b/config-wrt3200acm new file mode 100644 index 00000000..79bae0ff --- /dev/null +++ b/config-wrt3200acm @@ -0,0 +1,5 @@ +CONFIG_TARGET_mvebu=y +CONFIG_TARGET_mvebu_cortexa9=y +CONFIG_TARGET_mvebu_cortexa9_DEVICE_linksys_wrt3200acm=y +CONFIG_PACKAGE_kmod-6lowpan=y +CONFIG_PACKAGE_luci-app-advanced-reboot=y diff --git a/config-wrt32x b/config-wrt32x new file mode 100644 index 00000000..eba5cbec --- /dev/null +++ b/config-wrt32x @@ -0,0 +1,7 @@ +CONFIG_TARGET_mvebu=y +CONFIG_TARGET_mvebu_cortexa9=y +CONFIG_TARGET_mvebu_cortexa9_DEVICE_linksys_wrt32x=y +CONFIG_PACKAGE_kmod-6lowpan=y +CONFIG_PACKAGE_luci-app-advanced-reboot=y +# CONFIG_KERNEL_CC_OPTIMIZE_FOR_PERFORMANCE is not set +CONFIG_KERNEL_CC_OPTIMIZE_FOR_SIZE=y diff --git a/config-x86 b/config-x86 new file mode 100644 index 00000000..fe6382d3 --- /dev/null +++ b/config-x86 @@ -0,0 +1,7 @@ +CONFIG_TARGET_x86=y +CONFIG_TARGET_x86_generic=y +CONFIG_TARGET_x86_generic_Generic=y +CONFIG_TARGET_EXT4_JOURNAL=y +# CONFIG_TARGET_ROOTFS_TARGZ is not set +CONFIG_PACKAGE_open-vm-tools=m +CONFIG_PACKAGE_kmod-ath9k=y diff --git a/config-x86_64 b/config-x86_64 new file mode 100644 index 00000000..25699d13 --- /dev/null +++ b/config-x86_64 @@ -0,0 +1,11 @@ +CONFIG_TARGET_x86=y +CONFIG_TARGET_x86_64=y +CONFIG_TARGET_x86_64_Generic=y +CONFIG_TARGET_EXT4_JOURNAL=y +CONFIG_TARGET_ROOTFS_TARGZ=y +CONFIG_KERNEL_PAGE_TABLE_ISOLATION=y +CONFIG_PACKAGE_open-vm-tools=m +CONFIG_PACKAGE_kmod-ath9k=y +CONFIG_GRUB_IMAGES=y +CONFIG_EFI_IMAGES=y +# CONFIG_VMDK_IMAGES is not set diff --git a/contributors/example.md b/contributors/example.md new file mode 100644 index 00000000..654879dc --- /dev/null +++ b/contributors/example.md @@ -0,0 +1,9 @@ +2018-05-19 + +I hereby agree to the terms of the "OpenMPTCProuter Individual Contributor License Agreement", with MD5 checksum bc827a07eb93611d793ddb7c75083c00. + +I furthermore declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +John Doe https://github.com/johndoe diff --git a/deploy_rsa.enc b/deploy_rsa.enc new file mode 100644 index 00000000..313c0992 Binary files /dev/null and b/deploy_rsa.enc differ diff --git a/patches/download-ipv4.patch b/patches/download-ipv4.patch new file mode 100644 index 00000000..573ea2c4 --- /dev/null +++ b/patches/download-ipv4.patch @@ -0,0 +1,13 @@ +--- a/scripts/download.pl 2020-04-12 21:41:19.548645048 +0200 ++++ b/scripts/download.pl 2020-04-12 21:41:28.752479609 +0200 +@@ -82,8 +82,8 @@ + } + + return $have_curl +- ? (qw(curl -f --connect-timeout 20 --retry 5 --location --insecure), shellwords($ENV{CURL_OPTIONS} || ''), $url) +- : (qw(wget --tries=5 --timeout=20 --no-check-certificate --output-document=-), shellwords($ENV{WGET_OPTIONS} || ''), $url) ++ ? (qw(curl -4 -f --connect-timeout 20 --retry 5 --location --insecure), shellwords($ENV{CURL_OPTIONS} || ''), $url) ++ : (qw(wget -4 --tries=5 --timeout=20 --no-check-certificate --output-document=-), shellwords($ENV{WGET_OPTIONS} || ''), $url) + ; + } + diff --git a/patches/gtime.patch b/patches/gtime.patch new file mode 100644 index 00000000..43779b1a --- /dev/null +++ b/patches/gtime.patch @@ -0,0 +1,10 @@ +--- a/include/subdir.mk 2018-06-29 15:42:35.249190676 +0200 ++++ b/include/b/include/subdir.mk 2018-06-29 15:42:42.373119326 +0200 +@@ -43,7 +43,6 @@ + $(if $(BUILD_LOG), \ + set -o pipefail; \ + mkdir -p $(BUILD_LOG_DIR)/$(1)$(if $(4),/$(4));) \ +- env time -f "time: $(1)$(if $(4),/$(4))/$(if $(3),$(3)-)$(2)\#%U\#%S\#%e" -- \ + $$(SUBMAKE) $(subdir_make_opts) $(if $(3),$(3)-)$(2) \ + $(if $(BUILD_LOG),SILENT= 2>&1 | tee $(BUILD_LOG_DIR)/$(1)$(if $(4),/$(4))/$(if $(3),$(3)-)$(2).txt) + diff --git a/patches/images.patch b/patches/images.patch new file mode 100644 index 00000000..392145d8 --- /dev/null +++ b/patches/images.patch @@ -0,0 +1,42 @@ +--- a/config/Config-images.in.orig 2019-05-28 14:40:45.246749741 +0200 ++++ b/config/Config-images.in 2019-05-28 14:41:14.866378695 +0200 +@@ -251,6 +251,13 @@ + select TARGET_IMAGES_PAD + select PACKAGE_kmod-e1000 + ++ config VHDX_IMAGES ++ bool "Build Hyper-V image files (VHDX)" ++ depends on TARGET_x86 ++ select GRUB_IMAGES ++ select TARGET_IMAGES_PAD ++ select PACKAGE_kmod-e1000 ++ + config TARGET_IMAGES_PAD + bool "Pad images to filesystem size (for JFFS2)" + depends on GRUB_IMAGES +--- a/target/linux/x86/image/Makefile.orig 2019-06-03 14:32:39.094356089 +0200 ++++ b/target/linux/x86/image/Makefile 2019-06-03 19:04:23.875965073 +0200 +@@ -143,6 +143,15 @@ + endef + endif + ++ifneq ($(CONFIG_VHDX_IMAGES),) ++ define Image/Build/vhdx ++ rm $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vhdx || true ++ qemu-img convert -f raw -O vhdx \ ++ $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img \ ++ $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vhdx ++ endef ++endif ++ + define Image/Build/gzip + gzip -f9n $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img + gzip -f9n $(BIN_DIR)/$(IMG_PREFIX)-rootfs-$(1).img +@@ -175,6 +184,7 @@ + $(call Image/Build/grub2,$(1)) + $(call Image/Build/vdi,$(1)) + $(call Image/Build/vmdk,$(1)) ++ $(call Image/Build/vhdx,$(1)) + $(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-rootfs-$(1).img + else + $(CP) $(KDIR)/root.iso $(BIN_DIR)/$(IMG_PREFIX).iso diff --git a/patches/ipt-nat6.patch b/patches/ipt-nat6.patch new file mode 100644 index 00000000..f3006a91 --- /dev/null +++ b/patches/ipt-nat6.patch @@ -0,0 +1,14 @@ +--- a/package/kernel/linux/modules/netfilter.mk 2020-03-20 15:41:58.620893747 +0100 ++++ b/package/kernel/linux/modules/netfilter.mk 2020-03-20 15:45:34.389015301 +0100 +@@ -483,8 +483,10 @@ + define KernelPackage/ipt-nat6 + TITLE:=IPv6 NAT targets + DEPENDS:=@IPV6 + KCONFIG:=$(KCONFIG_IPT_NAT6) +- FILES:=$(foreach mod,$(IPT_NAT6-m),$(LINUX_DIR)/net/$(mod).ko) ++ FILES:= \ ++ $(LINUX_DIR)/net/ipv6/netfilter/ip6t_NPT.ko \ ++ $(LINUX_DIR)/net/ipv6/netfilter/ip6table_nat.ko + AUTOLOAD:=$(call AutoLoad,43,$(notdir $(IPT_NAT6-m))) + $(call AddDepends/ipt,+kmod-nf-nat6) + $(call AddDepends/ipt,+kmod-ipt-conntrack) diff --git a/patches/nanqinlang.patch b/patches/nanqinlang.patch new file mode 100644 index 00000000..9cc3fc3d --- /dev/null +++ b/patches/nanqinlang.patch @@ -0,0 +1,28 @@ +--- a/package/kernel/linux/modules/netsupport.mk 2019-12-18 18:31:28.865626571 +0100 ++++ b/package/kernel/linux/modules/netsupport.mk 2019-12-18 18:33:31.175524777 +0100 +@@ -962,6 +962,25 @@ + + $(eval $(call KernelPackage,tcp-bbr)) + ++define KernelPackage/tcp-nanqinlang ++ SUBMENU:=$(NETWORK_SUPPORT_MENU) ++ TITLE:=BBR NANQINLANG TCP congestion control ++ DEPENDS:=+LINUX_4_9:kmod-sched ++ KCONFIG:= \ ++ CONFIG_TCP_CONG_ADVANCED=y \ ++ CONFIG_TCP_CONG_NANQINLANG ++ FILES:=$(LINUX_DIR)/net/ipv4/tcp_nanqinlang.ko ++ AUTOLOAD:=$(call AutoLoad,74,tcp_nanqinlang) ++endef ++ ++define KernelPackage/tcp-nanqinlang/description ++ Kernel module for BBR (Bottleneck Bandwidth and RTT) TCP congestion ++ control. It requires the fq ("Fair Queue") pacing packet scheduler. ++ For kernel 4.13+, TCP internal pacing is implemented as fallback. ++endef ++ ++$(eval $(call KernelPackage,tcp-nanqinlang)) ++ + + define KernelPackage/ax25 + SUBMENU:=$(NETWORK_SUPPORT_MENU) diff --git a/patches/nocheck.patch b/patches/nocheck.patch new file mode 100644 index 00000000..e4290aab --- /dev/null +++ b/patches/nocheck.patch @@ -0,0 +1,10 @@ +--- a/include/package-ipkg.mk.1 2019-06-02 10:10:48.814882668 +0200 ++++ b/include/package-ipkg.mk 2019-06-02 10:08:20.372736726 +0200 +@@ -79,7 +79,6 @@ + if [ -f "$(PKG_INFO_DIR)/$(1).missing" ]; then \ + echo "Package $(1) is missing dependencies for the following libraries:" >&2; \ + cat "$(PKG_INFO_DIR)/$(1).missing" >&2; \ +- false; \ + fi; \ + ) + endef diff --git a/patches/package-too-long.patch b/patches/package-too-long.patch new file mode 100644 index 00000000..00d7afce --- /dev/null +++ b/patches/package-too-long.patch @@ -0,0 +1,11 @@ +--- a/package/Makefile 2020-04-04 15:52:15.706831084 +0200 ++++ b/package/Makefile 2020-04-04 15:53:54.645052663 +0200 +@@ -66,7 +66,7 @@ + rm -rf $(TARGET_DIR) $(TARGET_DIR_ORIG) + mkdir -p $(TARGET_DIR)/tmp + $(call opkg,$(TARGET_DIR)) install \ +- $(call opkg_package_files,$(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg)))) ++ $(subst $(TOPDIR)/,,$(call opkg_package_files,$(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg))))) + @for file in $(PACKAGE_INSTALL_FILES); do \ + [ -s $$file.flags ] || continue; \ + for flag in `cat $$file.flags`; do \ diff --git a/patches/smsc75xx.patch b/patches/smsc75xx.patch new file mode 100644 index 00000000..e08dab97 --- /dev/null +++ b/patches/smsc75xx.patch @@ -0,0 +1,26 @@ +Index: package/kernel/linux/modules/usb.mk +=================================================================== +--- a/package/kernel/linux/modules/usb.mk (revisione 42462) ++++ b/package/kernel/linux/modules/usb.mk (copia locale) +@@ -1091,8 +1091,21 @@ + endef + + $(eval $(call KernelPackage,usb-net-smsc95xx)) ++ ++define KernelPackage/usb-net-smsc75xx ++ TITLE:=SMSC LAN75XX based USB 2.0 Gigabit ethernet devices ++ KCONFIG:=CONFIG_USB_NET_SMSC75XX ++ FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/smsc75xx.ko ++ AUTOLOAD:=$(call AutoProbe,smsc75xx) ++ $(call AddDepends/usb-net, +kmod-lib-crc16) ++endef + ++define KernelPackage/usb-net-smsc75xx/description ++ Kernel module for SMSC LAN75XX based devices ++endef + ++$(eval $(call KernelPackage,usb-net-smsc75xx)) ++ + define KernelPackage/usb-net-dm9601-ether + TITLE:=Support for DM9601 ethernet connections + KCONFIG:=CONFIG_USB_NET_DM9601 diff --git a/patches/uefi.patch b/patches/uefi.patch new file mode 100644 index 00000000..794d6578 --- /dev/null +++ b/patches/uefi.patch @@ -0,0 +1,1323 @@ +From 964f624954b5e4ea83a4f05a57d79a6af6836d13 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Thu, 4 Apr 2019 02:40:15 +0000 +Subject: [PATCH 1/8] firmware-utils: ptgen: add GPT support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add GPT support to ptgen, so we can generate EFI bootable images. + +Introduced two options: + -g generate GPT partition table + -G GUID use GUID for disk and increase last bit for all partitions + +We drop The alternate partition table to reduce size, This may cause +problems when generate vmdk images or vdi images. We must pad enough +sectors when generate these images. + +Signed-off-by: 李国 +--- + tools/firmware-utils/Makefile | 2 +- + tools/firmware-utils/src/ptgen.c | 337 ++++++++++++++++++++++++++++--- + 2 files changed, 314 insertions(+), 25 deletions(-) + +diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile +index 97c89eec279..561d6d868fe 100644 +--- a/tools/firmware-utils/Makefile ++++ b/tools/firmware-utils/Makefile +@@ -32,7 +32,7 @@ define Host/Compile + $(call cc,dgfirmware) + $(call cc,mksenaofw md5, -Wall --std=gnu99) + $(call cc,trx2usr) +- $(call cc,ptgen) ++ $(call cc,ptgen cyg_crc32) + $(call cc,srec2bin) + $(call cc,mkmylofw) + $(call cc,mkcsysimg) +diff --git a/tools/firmware-utils/src/ptgen.c b/tools/firmware-utils/src/ptgen.c +index 0192bb65e51..caee0f94190 100644 +--- a/tools/firmware-utils/src/ptgen.c ++++ b/tools/firmware-utils/src/ptgen.c +@@ -31,15 +31,62 @@ + #include + #include + #include ++#include ++#include "cyg_crc.h" + + #if __BYTE_ORDER == __BIG_ENDIAN ++#define cpu_to_le16(x) bswap_16(x) + #define cpu_to_le32(x) bswap_32(x) ++#define cpu_to_le64(x) bswap_64(x) + #elif __BYTE_ORDER == __LITTLE_ENDIAN ++#define cpu_to_le16(x) (x) + #define cpu_to_le32(x) (x) ++#define cpu_to_le64(x) (x) + #else + #error unknown endianness! + #endif + ++#define swap(a, b) \ ++ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) ++ ++#ifndef GUID_INIT ++typedef uuid_le guid_t; ++#define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ ++ UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) ++#endif ++ ++#define GUID_STRING_LENGTH 36 ++ ++#define GPT_SIGNATURE 0x5452415020494645ULL ++#define GPT_REVISION 0x00010000 ++ ++#define GUID_PARTITION_SYSTEM \ ++ GUID_INIT( 0xC12A7328, 0xF81F, 0x11d2, \ ++ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) ++ ++#define GUID_PARTITION_BASIC_DATA \ ++ GUID_INIT( 0xEBD0A0A2, 0xB9E5, 0x4433, \ ++ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) ++ ++#define GUID_PARTITION_BIOS_BOOT \ ++ GUID_INIT( 0x21686148, 0x6449, 0x6E6F, \ ++ 0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) ++ ++#define GPT_HEADER_SIZE 92 ++#define GPT_ENTRY_SIZE 128 ++#define GPT_ENTRY_MAX 128 ++#define GPT_ENTRY_NAME_SIZE 72 ++ ++#define GPT_HEADER_SECTOR 1 ++#define GPT_FIRST_ENTRY_SECTOR 2 ++ ++#define MBR_ENTRY_MAX 4 ++#define MBR_DISK_SIGNATURE_OFFSET 440 ++#define MBR_PARTITION_ENTRY_OFFSET 446 ++#define MBR_BOOT_SIGNATURE_OFFSET 510 ++ ++#define DISK_SECTOR_SIZE 512 ++ + /* Partition table entry */ + struct pte { + uint8_t active; +@@ -55,13 +102,43 @@ struct partinfo { + int type; + }; + ++/* GPT Partition table header */ ++struct gpth { ++ uint64_t signature; ++ uint32_t revision; ++ uint32_t size; ++ uint32_t crc32; ++ uint32_t reserved; ++ uint64_t self; ++ uint64_t alternate; ++ uint64_t first_usable; ++ uint64_t last_usable; ++ guid_t disk_guid; ++ uint64_t first_entry; ++ uint32_t entry_num; ++ uint32_t entry_size; ++ uint32_t entry_crc32; ++} __attribute__((packed)); ++ ++/* GPT Partition table entry */ ++struct gpte { ++ guid_t type; ++ guid_t guid; ++ uint64_t start; ++ uint64_t end; ++ uint64_t attr; ++ uint16_t name[GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)]; ++} __attribute__((packed)); ++ ++ + int verbose = 0; + int active = 1; + int heads = -1; + int sectors = -1; + int kb_align = 0; + bool ignore_null_sized_partition = false; +-struct partinfo parts[4]; ++bool use_guid_partition_table = false; ++struct partinfo parts[GPT_ENTRY_MAX]; + char *filename = NULL; + + +@@ -91,7 +168,7 @@ static long to_kbytes(const char *string) + end++; + + if (*end) { +- fprintf(stderr, "garbage after end of number\n"); ++ fputs("garbage after end of number\n", stderr); + return 0; + } + +@@ -132,20 +209,73 @@ static inline unsigned long round_to_kb(long sect) { + return ((sect - 1) / kb_align + 1) * kb_align; + } + ++/* Compute a CRC for guid partition table */ ++static inline unsigned long gpt_crc32(void *buf, unsigned long len) ++{ ++ return cyg_crc32_accumulate(~0L, buf, len) ^ ~0L; ++} ++ ++/* Parse a guid string to guid_t struct */ ++static inline int guid_parse(char *buf, guid_t *guid) ++{ ++ char b[4] = {0}; ++ char *p = buf; ++ unsigned i = 0; ++ if (strnlen(buf, GUID_STRING_LENGTH) != GUID_STRING_LENGTH) ++ return -1; ++ for (i = 0; i < sizeof(guid_t); i++) { ++ if (*p == '-') ++ p++; ++ if (*p == '\0') ++ return -1; ++ memcpy(b, p, 2); ++ guid->b[i] = strtol(b, 0, 16); ++ p += 2; ++ } ++ swap(guid->b[0], guid->b[3]); ++ swap(guid->b[1], guid->b[2]); ++ swap(guid->b[4], guid->b[5]); ++ swap(guid->b[6], guid->b[7]); ++ return 0; ++} ++ ++/* init an utf-16 string from utf-8 string */ ++static inline void init_utf16(char *str, uint16_t *buf, unsigned bufsize) ++{ ++ unsigned i, n = 0; ++ for (i = 0; i < bufsize; i++) { ++ if (str[n] == 0x00) { ++ buf[i] = 0x00; ++ return ; ++ } else if ((str[n] & 0x80) == 0x00) {//0xxxxxxx ++ buf[i] = cpu_to_le16(str[n++]); ++ } else if ((str[n] & 0xE0) == 0xC0) {//110xxxxx ++ buf[i] = cpu_to_le16((str[n] & 0x1F) << 6 | str[n + 1] & 0x3F); ++ n += 2; ++ } else if ((str[n] & 0xF0) == 0xE0) {//1110xxxx ++ buf[i] = cpu_to_le16((str[n] & 0x0F) << 12 | (str[n + 1] & 0x3F) << 6 | str[n + 2] & 0x3F); ++ n += 3; ++ } else { ++ buf[i] = cpu_to_le16('?'); ++ n++; ++ } ++ } ++} ++ + /* check the partition sizes and write the partition table */ + static int gen_ptable(uint32_t signature, int nr) + { +- struct pte pte[4]; +- unsigned long sect = 0; +- int i, fd, ret = -1, start, len; ++ struct pte pte[MBR_ENTRY_MAX]; ++ unsigned long start, len, sect = 0; ++ int i, fd, ret = -1; + +- memset(pte, 0, sizeof(struct pte) * 4); ++ memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX); + for (i = 0; i < nr; i++) { + if (!parts[i].size) { + if (ignore_null_sized_partition) + continue; + fprintf(stderr, "Invalid size in partition %d!\n", i); +- return -1; ++ return ret; + } + + pte[i].active = ((i + 1) == active) ? 0x80 : 0; +@@ -165,30 +295,34 @@ static int gen_ptable(uint32_t signature, int nr) + to_chs(start + len - 1, pte[i].chs_end); + + if (verbose) +- fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long)start * 512, ((long)start + (long)len) * 512, (long)len * 512); +- printf("%ld\n", (long)start * 512); +- printf("%ld\n", (long)len * 512); ++ fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", ++ i, ++ (long)start * DISK_SECTOR_SIZE, ++ (long)(start + len) * DISK_SECTOR_SIZE, ++ (long)len * DISK_SECTOR_SIZE); ++ printf("%ld\n", (long)start * DISK_SECTOR_SIZE); ++ printf("%ld\n", (long)len * DISK_SECTOR_SIZE); + } + + if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { + fprintf(stderr, "Can't open output file '%s'\n",filename); +- return -1; ++ return ret; + } + +- lseek(fd, 440, SEEK_SET); ++ lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); + if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { +- fprintf(stderr, "write failed.\n"); ++ fputs("write failed.\n", stderr); + goto fail; + } + +- lseek(fd, 446, SEEK_SET); +- if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) { +- fprintf(stderr, "write failed.\n"); ++ lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); ++ if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) { ++ fputs("write failed.\n", stderr); + goto fail; + } +- lseek(fd, 510, SEEK_SET); ++ lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); + if (write(fd, "\x55\xaa", 2) != 2) { +- fprintf(stderr, "write failed.\n"); ++ fputs("write failed.\n", stderr); + goto fail; + } + +@@ -198,20 +332,162 @@ static int gen_ptable(uint32_t signature, int nr) + return ret; + } + ++/* check the partition sizes and write the guid partition table */ ++static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) ++{ ++ struct pte pte; ++ struct gpth gpth = { ++ .signature = cpu_to_le64(GPT_SIGNATURE), ++ .revision = cpu_to_le32(GPT_REVISION), ++ .size = cpu_to_le32(GPT_HEADER_SIZE), ++ .self = cpu_to_le64(GPT_HEADER_SECTOR), ++ .first_usable = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE), ++ .first_entry = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR), ++ .disk_guid = guid, ++ .entry_num = cpu_to_le32(GPT_ENTRY_MAX), ++ .entry_size = cpu_to_le32(GPT_ENTRY_SIZE), ++ }; ++ struct gpte gpte[GPT_ENTRY_MAX]; ++ uint64_t start, end, sect = 0; ++ int fd, ret = -1; ++ unsigned i; ++ ++ memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX); ++ for (i = 0; i < nr; i++) { ++ if (!parts[i].size) { ++ if (ignore_null_sized_partition) ++ continue; ++ fprintf(stderr, "Invalid size in partition %d!\n", i); ++ return ret; ++ } ++ start = sect + sectors; ++ if (kb_align != 0) ++ start = round_to_kb(start); ++ gpte[i].start = cpu_to_le64(start); ++ ++ sect = start + parts[i].size * 2; ++ if (kb_align == 0) ++ sect = round_to_cyl(sect); ++ gpte[i].end = cpu_to_le64(sect -1); ++ gpte[i].guid = guid; ++ gpte[i].guid.b[sizeof(guid_t) -1] += i + 1; ++ if (parts[i].type == 0xEF || (i + 1) == active) { ++ gpte[i].type = GUID_PARTITION_SYSTEM; ++ init_utf16("EFI System Partition", gpte[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)); ++ } else { ++ gpte[i].type = GUID_PARTITION_BASIC_DATA; ++ } ++ ++ if (verbose) ++ fprintf(stderr, "Partition %d: start=%lld, end=%lld, size=%lld\n", ++ i, ++ start * DISK_SECTOR_SIZE, sect * DISK_SECTOR_SIZE, ++ (sect - start) * DISK_SECTOR_SIZE); ++ printf("%lld\n", start * DISK_SECTOR_SIZE); ++ printf("%lld\n", (sect - start) * DISK_SECTOR_SIZE); ++ } ++ ++ gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE); ++ gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64((kb_align ? round_to_kb(sectors) : sectors) - 1); ++ gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT; ++ gpte[GPT_ENTRY_MAX - 1].guid = guid; ++ gpte[GPT_ENTRY_MAX - 1].guid.b[sizeof(guid_t) -1] += GPT_ENTRY_MAX; ++ ++ end = sect + sectors - 1; ++ ++ pte.type = 0xEE; ++ pte.start = cpu_to_le32(GPT_HEADER_SECTOR); ++ pte.length = cpu_to_le32(end); ++ to_chs(GPT_HEADER_SECTOR, pte.chs_start); ++ to_chs(end, pte.chs_end); ++ ++ gpth.last_usable = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE - 1); ++ gpth.alternate = cpu_to_le64(end); ++ gpth.entry_crc32 = cpu_to_le32(gpt_crc32(gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX)); ++ gpth.crc32 = cpu_to_le32(gpt_crc32((char *)&gpth, GPT_HEADER_SIZE)); ++ ++ if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { ++ fprintf(stderr, "Can't open output file '%s'\n",filename); ++ return ret; ++ } ++ ++ lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); ++ if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++ lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); ++ if (write(fd, &pte, sizeof(struct pte)) != sizeof(struct pte)) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++ lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); ++ if (write(fd, "\x55\xaa", 2) != 2) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++ //lseek(fd, GPT_HEADER_SECTOR * DISK_SECTOR_SIZE, SEEK_SET); ++ if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++ lseek(fd, GPT_FIRST_ENTRY_SECTOR * DISK_SECTOR_SIZE, SEEK_SET); ++ if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++#if 0 ++ /* The alternate partition table (We omit it) */ ++ swap(gpth.self, gpth.alternate); ++ gpth.first_entry = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE), ++ gpth.crc32 = 0; ++ gpth.crc32 = cpu_to_le32(gpt_crc32(&gpth, GPT_HEADER_SIZE)); ++ ++ lseek(fd, end * DISK_SECTOR_SIZE - GPT_ENTRY_SIZE * GPT_ENTRY_MAX, SEEK_SET); ++ if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ ++ lseek(fd, end * DISK_SECTOR_SIZE, SEEK_SET); ++ if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++ lseek(fd, (end + 1) * DISK_SECTOR_SIZE -1, SEEK_SET); ++ if (write(fd, "\x00", 1) != 1) { ++ fputs("write failed.\n", stderr); ++ goto fail; ++ } ++#endif ++ ++ ret = 0; ++fail: ++ close(fd); ++ return ret; ++} ++ + static void usage(char *prog) + { +- fprintf(stderr, "Usage: %s [-v] [-n] -h -s -o [-a 0..4] [-l ] [[-t ] -p ...] \n", prog); ++ fprintf(stderr, "Usage: %s [-v] [-n] [-g] -h -s -o [-a 0..4] [-l ] [-G ] [[-t ] -p ...] \n", prog); + exit(EXIT_FAILURE); + } + + int main (int argc, char **argv) + { +- char type = 0x83; ++ unsigned char type = 0x83; + int ch; + int part = 0; + uint32_t signature = 0x5452574F; /* 'OWRT' */ ++ guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ ++ 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); + +- while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vnl:S:")) != -1) { ++ while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vngl:S:G:")) != -1) { + switch (ch) { + case 'o': + filename = optarg; +@@ -222,6 +498,9 @@ int main (int argc, char **argv) + case 'n': + ignore_null_sized_partition = true; + break; ++ case 'g': ++ use_guid_partition_table = 1; ++ break; + case 'h': + heads = (int)strtoul(optarg, NULL, 0); + break; +@@ -229,8 +508,8 @@ int main (int argc, char **argv) + sectors = (int)strtoul(optarg, NULL, 0); + break; + case 'p': +- if (part > 3) { +- fprintf(stderr, "Too many partitions\n"); ++ if (part > GPT_ENTRY_MAX - 1 || (!use_guid_partition_table && part > 3)) { ++ fputs("Too many partitions\n", stderr); + exit(EXIT_FAILURE); + } + parts[part].size = to_kbytes(optarg); +@@ -250,6 +529,12 @@ int main (int argc, char **argv) + case 'S': + signature = strtoul(optarg, NULL, 0); + break; ++ case 'G': ++ if (guid_parse(optarg, &guid)) { ++ fputs("Invalid guid string\n", stderr); ++ exit(EXIT_FAILURE); ++ } ++ break; + case '?': + default: + usage(argv[0]); +@@ -259,5 +544,9 @@ int main (int argc, char **argv) + if (argc || (heads <= 0) || (sectors <= 0) || !filename) + usage(argv[0]); + +- return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; ++ if (use_guid_partition_table) { ++ return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS; ++ } else { ++ return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; ++ } + } + +From c634da575c221e6a340884219d78978f56f23976 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Thu, 4 Apr 2019 03:17:01 +0000 +Subject: [PATCH 2/8] grub2: split to grub2 and grub2-efi packages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +EFI bootable images need grub2 host packages with efi platform, +but grub2 can not build efi platform and pc platform together, +so we split it to grub2 and grub2-efi packages. + +Signed-off-by: 李国 +--- + package/boot/grub2/common.mk | 54 +++++++++++++++++++++++++ + package/boot/grub2/grub2-efi/Makefile | 19 +++++++++ + package/boot/grub2/{ => grub2}/Makefile | 50 +---------------------- + 3 files changed, 75 insertions(+), 48 deletions(-) + create mode 100644 package/boot/grub2/common.mk + create mode 100644 package/boot/grub2/grub2-efi/Makefile + rename package/boot/grub2/{ => grub2}/Makefile (66%) + +diff --git a/package/boot/grub2/common.mk b/package/boot/grub2/common.mk +new file mode 100644 +index 00000000000..53ee26552f8 +--- /dev/null ++++ b/package/boot/grub2/common.mk +@@ -0,0 +1,54 @@ ++# ++# Copyright (C) 2006-2015 OpenWrt.org ++# ++# This is free software, licensed under the GNU General Public License v2. ++# See /LICENSE for more information. ++# ++ ++include $(TOPDIR)/rules.mk ++include $(INCLUDE_DIR)/kernel.mk ++ ++PKG_NAME:=grub ++PKG_CPE_ID:=cpe:/a:gnu:grub2 ++PKG_VERSION:=2.04 ++PKG_RELEASE:=2 ++ ++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz ++PKG_SOURCE_URL:=@GNU/grub ++PKG_HASH:=e5292496995ad42dabe843a0192cf2a2c502e7ffcc7479398232b10a472df77d ++ ++HOST_BUILD_PARALLEL:=1 ++ ++PKG_SSP:=0 ++ ++PKG_FLAGS:=nonshared ++ ++PATCH_DIR:=../patches ++ ++HOST_BUILD_DIR ?= $(BUILD_DIR_HOST)/$(PKG_NAME)-$(GRUB_PLATFORM)/$(PKG_NAME)$(if $(PKG_VERSION),-$(PKG_VERSION)) ++HOST_BUILD_PREFIX := $(STAGING_DIR_HOST) ++ ++include $(INCLUDE_DIR)/host-build.mk ++include $(INCLUDE_DIR)/package.mk ++ ++ ++HOST_CONFIGURE_VARS += \ ++ grub_build_mkfont_excuse="don't want fonts" ++ ++HOST_CONFIGURE_ARGS += \ ++ --disable-grub-mkfont \ ++ --target=$(REAL_GNU_TARGET_NAME) \ ++ --sbindir="$(STAGING_DIR_HOST)/bin" \ ++ --disable-werror \ ++ --disable-libzfs \ ++ --disable-nls \ ++ --with-platform=$(GRUB_PLATFORM) ++ ++HOST_MAKE_FLAGS += \ ++ TARGET_RANLIB=$(TARGET_RANLIB) \ ++ LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a ++ ++define Host/Configure ++ $(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in ++ $(Host/Configure/Default) ++endef +diff --git a/package/boot/grub2/grub2-efi/Makefile b/package/boot/grub2/grub2-efi/Makefile +new file mode 100644 +index 00000000000..2fc21fdb890 +--- /dev/null ++++ b/package/boot/grub2/grub2-efi/Makefile +@@ -0,0 +1,19 @@ ++GRUB_PLATFORM:=efi ++ ++PKG_BUILD_DEPENDS:=grub2-efi/host ++include ../common.mk ++ ++define Package/grub2-efi ++ CATEGORY:=Boot Loaders ++ SECTION:=boot ++ TITLE:=GRand Unified Bootloader(EFI) ++ URL:=http://www.gnu.org/software/grub/ ++ DEPENDS:=@TARGET_x86 ++endef ++ ++define Host/Install ++ $(call Host/Compile/Default,install-data) ++endef ++ ++$(eval $(call HostBuild)) ++$(eval $(call BuildPackage,grub2-efi)) +diff --git a/package/boot/grub2/Makefile b/package/boot/grub2/grub2/Makefile +similarity index 66% +rename from package/boot/grub2/Makefile +rename to package/boot/grub2/grub2/Makefile +index 980a6e372a3..7126beab4cf 100644 +--- a/package/boot/grub2/Makefile ++++ b/package/boot/grub2/grub2/Makefile +@@ -1,31 +1,7 @@ +-# +-# Copyright (C) 2006-2015 OpenWrt.org +-# +-# This is free software, licensed under the GNU General Public License v2. +-# See /LICENSE for more information. +-# ++GRUB_PLATFORM:=pc + +-include $(TOPDIR)/rules.mk +-include $(INCLUDE_DIR)/kernel.mk +- +-PKG_NAME:=grub +-PKG_CPE_ID:=cpe:/a:gnu:grub2 +-PKG_VERSION:=2.04 +-PKG_RELEASE:=1 +- +-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +-PKG_SOURCE_URL:=@GNU/grub +-PKG_HASH:=e5292496995ad42dabe843a0192cf2a2c502e7ffcc7479398232b10a472df77d +- +-HOST_BUILD_PARALLEL:=1 + PKG_BUILD_DEPENDS:=grub2/host +- +-PKG_SSP:=0 +- +-PKG_FLAGS:=nonshared +- +-include $(INCLUDE_DIR)/host-build.mk +-include $(INCLUDE_DIR)/package.mk ++include ../common.mk + + define Package/grub2 + CATEGORY:=Boot Loaders +@@ -48,8 +24,6 @@ define Package/grub2-editenv/description + Edit grub2 environment files. + endef + +-HOST_BUILD_PREFIX := $(STAGING_DIR_HOST) +- + CONFIGURE_VARS += \ + grub_build_mkfont_excuse="don't want fonts" + +@@ -62,26 +36,6 @@ CONFIGURE_ARGS += \ + --disable-grub-mkfont \ + --with-platform=none + +-HOST_CONFIGURE_VARS += \ +- grub_build_mkfont_excuse="don't want fonts" +- +-HOST_CONFIGURE_ARGS += \ +- --disable-grub-mkfont \ +- --target=$(REAL_GNU_TARGET_NAME) \ +- --sbindir="$(STAGING_DIR_HOST)/bin" \ +- --disable-werror \ +- --disable-libzfs \ +- --disable-nls +- +-HOST_MAKE_FLAGS += \ +- TARGET_RANLIB=$(TARGET_RANLIB) \ +- LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a +- +-define Host/Configure +- $(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in +- $(Host/Configure/Default) +-endef +- + define Host/Install + $(call Host/Install/Default) + + +From 15212ac11ac95a57f75317fff83bb7d53b581a93 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Thu, 4 Apr 2019 03:42:16 +0000 +Subject: [PATCH 3/8] x86: add EFI images and make iso images EFI bootable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add EFI bootable images for x86 platforms. These images can also +boot from legacy BIOS. And iso images can boot from EFI now. + +EFI System Partition need to be fat12/fat16/fat32 (not need to load +filesystem drivers), so the first partition of EFI images are not ext4 +filesystem any more. + +GPT partition table has an alternate partition table, we did not +generate it. This may cause problems when use these images as qemu disk, +kernel can not find rootfs, we pad enough sectors will be ok. + +Signed-off-by: 李国 +--- + config/Config-images.in | 23 +++++++++++++------ + .../base-files/files/lib/upgrade/common.sh | 11 +++++++++ + scripts/gen_image_generic.sh | 10 ++++++-- + .../x86/base-files/lib/preinit/79_move_config | 6 +++-- + .../x86/base-files/lib/upgrade/platform.sh | 6 +++-- + target/linux/x86/generic/config-4.19 | 1 + + target/linux/x86/generic/config-5.4 | 1 + + target/linux/x86/image/Makefile | 3 +++ + target/linux/x86/image/grub-iso.cfg | 7 +++++- + 9 files changed, 54 insertions(+), 14 deletions(-) + +diff --git a/config/Config-images.in b/config/Config-images.in +index e4db0482ce2..16b575247ea 100644 +--- a/config/Config-images.in ++++ b/config/Config-images.in +@@ -188,19 +188,28 @@ menu "Target Images" + select PACKAGE_grub2 + default y + ++ config EFI_IMAGES ++ bool "Build EFI images (Linux x86 or x86_64 host only)" ++ depends on TARGET_x86 ++ depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_ISO || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS ++ select PACKAGE_grub2 ++ select PACKAGE_grub2-efi ++ select PACKAGE_kmod-fs-vfat ++ default n ++ + config GRUB_CONSOLE + bool "Use Console Terminal (in addition to Serial)" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + default y + + config GRUB_SERIAL + string "Serial port device" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + default "ttyS0" + + config GRUB_BAUDRATE + int "Serial port baud rate" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + default 38400 if TARGET_x86_generic + default 115200 + +@@ -211,20 +220,20 @@ menu "Target Images" + + config GRUB_BOOTOPTS + string "Extra kernel boot options" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + help + If you don't know, just leave it blank. + + config GRUB_TIMEOUT + string "Seconds to wait before booting the default entry" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + default "5" + help + If you don't know, 5 seconds is a reasonable default. + + config GRUB_TITLE + string "Title for the menu entry in GRUB" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + default "OpenWrt" + help + This is the title of the GRUB menu entry. +@@ -272,7 +281,7 @@ menu "Target Images" + + config TARGET_ROOTFS_PARTNAME + string "Root partition on target device" +- depends on GRUB_IMAGES ++ depends on GRUB_IMAGES || EFI_IMAGES + help + Override the root partition on the final device. If left empty, + it will be mounted by PARTUUID which makes the kernel find the +diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh +index a986cc0b5c7..6e967aeffe8 100644 +--- a/package/base-files/files/lib/upgrade/common.sh ++++ b/package/base-files/files/lib/upgrade/common.sh +@@ -136,6 +136,17 @@ export_bootdevice() { + fi + done + ;; ++ PARTUUID=????????-????-????-????-??????????02) ++ uuid="${rootpart#PARTUUID=}" ++ uuid="${uuid%02}00" ++ for disk in $(find /dev -type b); do ++ set -- $(dd if=$disk bs=1 skip=568 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"') ++ if [ "$4$3$2$1-$6$5-$8$7-$9" = "$uuid" ]; then ++ uevent="/sys/class/block/${disk##*/}/uevent" ++ break ++ fi ++ done ++ ;; + /dev/*) + uevent="/sys/class/block/${rootpart##*/}/../uevent" + ;; +diff --git a/scripts/gen_image_generic.sh b/scripts/gen_image_generic.sh +index 2c57d56f073..1df4d0673b3 100755 +--- a/scripts/gen_image_generic.sh ++++ b/scripts/gen_image_generic.sh +@@ -20,7 +20,7 @@ sect=63 + cyl=$(( (KERNELSIZE + ROOTFSSIZE) * 1024 * 1024 / (head * sect * 512))) + + # create partition table +-set $(ptgen -o "$OUTPUT" -h $head -s $sect -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE}) ++set $(ptgen -o "$OUTPUT" -h $head -s $sect ${EFI_SIGNATURE:+-g} -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${EFI_SIGNATURE:+-G $EFI_SIGNATURE}) + + KERNELOFFSET="$(($1 / 512))" + KERNELSIZE="$2" +@@ -30,6 +30,12 @@ ROOTFSSIZE="$(($4 / 512))" + [ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc count="$ROOTFSSIZE" + dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc + +-make_ext4fs -J -L kernel -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR" ++if [ -n "$EFI_SIGNATURE" ]; then ++ [ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$(($ROOTFSOFFSET + $ROOTFSSIZE))" conv=notrunc count="$sect" ++ mkfs.fat -n kernel -C "$OUTPUT.kernel" -S 512 "$(($KERNELSIZE / 1024))" ++ mcopy -s -i "$OUTPUT.kernel" "$KERNELDIR"/* ::/ ++else ++ make_ext4fs -J -L kernel -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR" ++fi + dd if="$OUTPUT.kernel" of="$OUTPUT" bs=512 seek="$KERNELOFFSET" conv=notrunc + rm -f "$OUTPUT.kernel" +diff --git a/target/linux/x86/base-files/lib/preinit/79_move_config b/target/linux/x86/base-files/lib/preinit/79_move_config +index 702da9e873d..015efcf748b 100644 +--- a/target/linux/x86/base-files/lib/preinit/79_move_config ++++ b/target/linux/x86/base-files/lib/preinit/79_move_config +@@ -2,13 +2,15 @@ + # Copyright (C) 2012-2015 OpenWrt.org + + move_config() { +- local partdev ++ local partdev magic parttype=ext4 + + . /lib/upgrade/common.sh + + if export_bootdevice && export_partdevice partdev 1; then + mkdir -p /boot +- mount -t ext4 -o rw,noatime "/dev/$partdev" /boot ++ magic=$(dd if="/dev/$partdev" bs=1 count=3 skip=54 2>/dev/null) ++ [ "$magic" = "FAT" ] && parttype=vfat ++ mount -t $parttype -o rw,noatime "/dev/$partdev" /boot + if [ -f "/boot/$BACKUP_FILE" ]; then + mv -f "/boot/$BACKUP_FILE" / + fi +diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh +index 53c751861cc..1c93f5bd9b9 100644 +--- a/target/linux/x86/base-files/lib/upgrade/platform.sh ++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh +@@ -37,10 +37,12 @@ platform_check_image() { + } + + platform_copy_config() { +- local partdev ++ local partdev magic parttype=ext4 + + if export_partdevice partdev 1; then +- mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt ++ magic=$(dd if="/dev/$partdev" bs=1 count=3 skip=54 2>/dev/null) ++ [ "$magic" = "FAT" ] && parttype=vfat ++ mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt + cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE" + umount /mnt + fi +diff --git a/target/linux/x86/generic/config-4.19 b/target/linux/x86/generic/config-4.19 +index 4a689ca026c..ada81ce04ea 100644 +--- a/target/linux/x86/generic/config-4.19 ++++ b/target/linux/x86/generic/config-4.19 +@@ -139,6 +139,7 @@ CONFIG_FB_DEFERRED_IO=y + CONFIG_FB_EFI=y + CONFIG_FB_HYPERV=y + # CONFIG_FB_I810 is not set ++CONFIG_FB_SIMPLE=y + CONFIG_FB_SYS_COPYAREA=y + CONFIG_FB_SYS_FILLRECT=y + CONFIG_FB_SYS_FOPS=y +diff --git a/target/linux/x86/generic/config-5.4 b/target/linux/x86/generic/config-5.4 +index 4a689ca026c..ada81ce04ea 100644 +--- a/target/linux/x86/generic/config-5.4 ++++ b/target/linux/x86/generic/config-5.4 +@@ -139,6 +139,7 @@ CONFIG_FB_DEFERRED_IO=y + CONFIG_FB_EFI=y + CONFIG_FB_HYPERV=y + # CONFIG_FB_I810 is not set ++CONFIG_FB_SIMPLE=y + CONFIG_FB_SYS_COPYAREA=y + CONFIG_FB_SYS_FILLRECT=y + CONFIG_FB_SYS_FOPS=y +diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile +index c2961e5b9c9..aa80d77b978 100644 +--- a/target/linux/x86/image/Makefile ++++ b/target/linux/x86/image/Makefile +@@ -38,6 +38,9 @@ endif + + ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME)) + ROOTPART:=$(if $(ROOTPART),$(ROOTPART),PARTUUID=$(IMG_PART_SIGNATURE)-02) ++EFI_SIGNATURE:=$(strip $(shell uuidgen | sed -r 's/[a-zA-Z0-9]{2}$$/00/')) ++EFI_ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME)) ++EFI_ROOTPART:=$(if $(EFI_ROOTPART),$(EFI_ROOTPART),PARTUUID=$(shell echo $(EFI_SIGNATURE) | sed 's/00$$/02/')) + + GRUB_TIMEOUT:=$(call qstrip,$(CONFIG_GRUB_TIMEOUT)) + GRUB_TITLE:=$(call qstrip,$(CONFIG_GRUB_TITLE)) +diff --git a/target/linux/x86/image/grub-iso.cfg b/target/linux/x86/image/grub-iso.cfg +index f5848b38534..4bef492a414 100644 +--- a/target/linux/x86/image/grub-iso.cfg ++++ b/target/linux/x86/image/grub-iso.cfg +@@ -3,7 +3,12 @@ + + set default="0" + set timeout="@TIMEOUT@" +-set root='(cd)' ++ ++if [ "${grub_platform}" = "efi" ]; then ++ set root='(cd0)' ++else ++ set root='(cd)' ++fi + + menuentry "@TITLE@" { + linux /boot/vmlinuz root=/dev/sr0 rootfstype=iso9660 rootwait @CMDLINE@ noinitrd + +From c24086b352f6f773c07f15f85b0e5ffe26e206af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Sat, 31 Aug 2019 13:28:05 +0000 +Subject: [PATCH 4/8] x86: fix sysupgrade for EFI images +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. make function get_partitions support GPT disks +2. get more bytes from image to get GPT partition table +3. update the original PARTUUID to new grub.cfg + +Signed-off-by: 李国 +--- + .../base-files/files/lib/upgrade/common.sh | 40 ++++++++++++++----- + .../x86/base-files/lib/upgrade/platform.sh | 20 ++++++++-- + 2 files changed, 45 insertions(+), 15 deletions(-) + +diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh +index 6e967aeffe8..1324b98ed2f 100644 +--- a/package/base-files/files/lib/upgrade/common.sh ++++ b/package/base-files/files/lib/upgrade/common.sh +@@ -218,17 +218,35 @@ get_partitions() { # + rm -f "/tmp/partmap.$filename" + + local part +- for part in 1 2 3 4; do +- set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk") +- +- local type="$(( $(hex_le32_to_cpu $1) % 256))" +- local lba="$(( $(hex_le32_to_cpu $2) ))" +- local num="$(( $(hex_le32_to_cpu $3) ))" +- +- [ $type -gt 0 ] || continue +- +- printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" +- done ++ local magic=$(dd if="$disk" bs=8 count=1 skip=64 2>/dev/null) ++ if [ "$magic" = "EFI PART" ]; then ++ #export_partdevice will fail when partition number is greater than 15, as ++ #the partition major device number is not equal to the disk major device number ++ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do ++ set -- $(hexdump -v -n 48 -s "$((0x380 + $part * 0x80))" -e '4/4 "%08x"" "4/4 "%08x"" "4/4 "0x%08X "' "$disk") ++ ++ local type="$1" ++ local lba="$(( $(hex_le32_to_cpu $4) * 0x100000000 + $(hex_le32_to_cpu $3) ))" ++ local end="$(( $(hex_le32_to_cpu $6) * 0x100000000 + $(hex_le32_to_cpu $5) ))" ++ local num="$(( $end - $lba ))" ++ ++ [ "$type" = "00000000000000000000000000000000" ] && continue ++ ++ printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" ++ done ++ else ++ for part in 1 2 3 4; do ++ set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk") ++ ++ local type="$(( $(hex_le32_to_cpu $1) % 256))" ++ local lba="$(( $(hex_le32_to_cpu $2) ))" ++ local num="$(( $(hex_le32_to_cpu $3) ))" ++ ++ [ $type -gt 0 ] || continue ++ ++ printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" ++ done ++ fi + fi + } + +diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh +index 1c93f5bd9b9..3acee2c7a9c 100644 +--- a/target/linux/x86/base-files/lib/upgrade/platform.sh ++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh +@@ -20,7 +20,7 @@ platform_check_image() { + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image +- get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null ++ get_image "$@" | dd of=/tmp/image.bs count=63 bs=512b 2>/dev/null + + get_partitions /tmp/image.bs image + +@@ -40,7 +40,7 @@ platform_copy_config() { + local partdev magic parttype=ext4 + + if export_partdevice partdev 1; then +- magic=$(dd if="/dev/$partdev" bs=1 count=3 skip=54 2>/dev/null) ++ magic="$(dd if="/dev/$partdev" bs=1 count=3 skip=54 2>/dev/null)" + [ "$magic" = "FAT" ] && parttype=vfat + mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt + cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE" +@@ -83,7 +83,7 @@ platform_do_upgrade() { + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image +- get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b ++ get_image "$@" | dd of=/tmp/image.bs count=63 bs=512b >/dev/null + + get_partitions /tmp/image.bs image + +@@ -108,7 +108,7 @@ platform_do_upgrade() { + while read part start size; do + if export_partdevice partdev $part; then + echo "Writing image to /dev/$partdev..." +- get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync ++ get_image "$@" | dd of="/dev/$partdev" ibs=512 obs=1M skip="$start" count="$size" conv=fsync + else + echo "Unable to find partition $part device, skipped." + fi +@@ -119,4 +119,16 @@ platform_do_upgrade() { + get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync + + platform_do_bootloader_upgrade "$diskdev" ++ local magic parttype=ext4 ++ magic="$(dd if="/dev/$diskdev" bs=8 count=1 skip=64 2>/dev/null)" ++ [ "$magic" = "EFI PART" ] || return 0 ++ if export_partdevice partdev 1; then ++ magic="$(dd if="/dev/$partdev" bs=1 count=3 skip=54 2>/dev/null)" ++ [ "$magic" = "FAT" ] && parttype=vfat ++ mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt ++ set -- $(dd if="/dev/$diskdev" bs=1 skip=1168 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"') ++ sed -i "s/\(PARTUUID=\)[a-f0-9-]\+/\1$4$3$2$1-$6$5-$8$7-$9/ig" /mnt/boot/grub/grub.cfg ++ umount /mnt ++ fi ++ + } + +From b915dff5280cc48a2331f01961f2504b9b12f245 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Tue, 24 Mar 2020 17:12:22 +0800 +Subject: [PATCH 5/8] grub2: grub-early.cfg auto detect efi platform +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: 李国 +--- + package/boot/grub2/files/grub-early.cfg | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/package/boot/grub2/files/grub-early.cfg b/package/boot/grub2/files/grub-early.cfg +index 4a5b5a60927..9e7cad47607 100644 +--- a/package/boot/grub2/files/grub-early.cfg ++++ b/package/boot/grub2/files/grub-early.cfg +@@ -1 +1,5 @@ +-configfile (hd0,msdos1)/boot/grub/grub.cfg ++if [ "${grub_platform}" = "efi" ]; then ++ configfile (hd0,gpt1)/boot/grub/grub.cfg ++else ++ configfile (hd0,msdos1)/boot/grub/grub.cfg ++fi + +From dce4fc3201395f886e496c3bb5f6ffd979558aa3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Tue, 24 Mar 2020 17:13:27 +0800 +Subject: [PATCH 6/8] x86: add efi images + +--- + include/image.mk | 1 + + scripts/gen_image_generic.sh | 4 ++-- + target/linux/x86/image/Makefile | 34 +++++++++++++++++++++++++---- + target/linux/x86/image/grub-efi.cfg | 13 +++++++++++ + 4 files changed, 46 insertions(+), 6 deletions(-) + create mode 100644 target/linux/x86/image/grub-efi.cfg + +diff --git a/include/image.mk b/include/image.mk +index 8af5905c600..051a6206cef 100644 +--- a/include/image.mk ++++ b/include/image.mk +@@ -45,6 +45,7 @@ IMG_PREFIX:=$(VERSION_DIST_SANITIZED)-$(IMG_PREFIX_VERNUM)$(IMG_PREFIX_VERCODE)$ + IMG_ROOTFS:=$(IMG_PREFIX)-rootfs + IMG_COMBINED:=$(IMG_PREFIX)-combined + IMG_PART_SIGNATURE:=$(shell echo $(SOURCE_DATE_EPOCH)$(LINUX_VERMAGIC) | mkhash md5 | cut -b1-8) ++IMG_PART_UUID:=$(shell echo $(SOURCE_DATE_EPOCH)$(LINUX_VERMAGIC) | mkhash md5 | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.{10})../\1-\2-\3-\4-\500/') + + MKFS_DEVTABLE_OPT := -D $(INCLUDE_DIR)/device_table.txt + +diff --git a/scripts/gen_image_generic.sh b/scripts/gen_image_generic.sh +index 1df4d0673b3..e45a8dd417e 100755 +--- a/scripts/gen_image_generic.sh ++++ b/scripts/gen_image_generic.sh +@@ -20,7 +20,7 @@ sect=63 + cyl=$(( (KERNELSIZE + ROOTFSSIZE) * 1024 * 1024 / (head * sect * 512))) + + # create partition table +-set $(ptgen -o "$OUTPUT" -h $head -s $sect ${EFI_SIGNATURE:+-g} -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${EFI_SIGNATURE:+-G $EFI_SIGNATURE}) ++set $(ptgen -o "$OUTPUT" -h $head -s $sect ${UUID:+-g} -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${UUID:+-G $UUID}) + + KERNELOFFSET="$(($1 / 512))" + KERNELSIZE="$2" +@@ -30,7 +30,7 @@ ROOTFSSIZE="$(($4 / 512))" + [ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc count="$ROOTFSSIZE" + dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc + +-if [ -n "$EFI_SIGNATURE" ]; then ++if [ -n "$UUID" ]; then + [ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$(($ROOTFSOFFSET + $ROOTFSSIZE))" conv=notrunc count="$sect" + mkfs.fat -n kernel -C "$OUTPUT.kernel" -S 512 "$(($KERNELSIZE / 1024))" + mcopy -s -i "$OUTPUT.kernel" "$KERNELDIR"/* ::/ +diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile +index aa80d77b978..efb0b1cff99 100644 +--- a/target/linux/x86/image/Makefile ++++ b/target/linux/x86/image/Makefile +@@ -38,9 +38,8 @@ endif + + ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME)) + ROOTPART:=$(if $(ROOTPART),$(ROOTPART),PARTUUID=$(IMG_PART_SIGNATURE)-02) +-EFI_SIGNATURE:=$(strip $(shell uuidgen | sed -r 's/[a-zA-Z0-9]{2}$$/00/')) + EFI_ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME)) +-EFI_ROOTPART:=$(if $(EFI_ROOTPART),$(EFI_ROOTPART),PARTUUID=$(shell echo $(EFI_SIGNATURE) | sed 's/00$$/02/')) ++EFI_ROOTPART:=$(if $(EFI_ROOTPART),$(EFI_ROOTPART),PARTUUID=$(shell echo $(IMG_PART_UUID) | sed 's/00$$/02/')) + + GRUB_TIMEOUT:=$(call qstrip,$(CONFIG_GRUB_TIMEOUT)) + GRUB_TITLE:=$(call qstrip,$(CONFIG_GRUB_TITLE)) +@@ -50,7 +49,8 @@ BOOTOPTS:=$(call qstrip,$(CONFIG_GRUB_BOOTOPTS)) + define Build/combined + $(CP) $(KDIR)/$(KERNEL_NAME) $@.boot/boot/vmlinuz + -$(CP) $(STAGING_DIR_ROOT)/boot/. $@.boot/boot/ +- PADDING="1" SIGNATURE="$(IMG_PART_SIGNATURE)" $(SCRIPT_DIR)/gen_image_generic.sh \ ++ PADDING="1" SIGNATURE="$(IMG_PART_SIGNATURE)" \ ++ $(if $(filter $(1),efi),UUID="$(IMG_PART_UUID)") $(SCRIPT_DIR)/gen_image_generic.sh \ + $@ \ + $(CONFIG_TARGET_KERNEL_PARTSIZE) $@.boot \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) $(IMAGE_ROOTFS) \ +@@ -64,6 +64,7 @@ define Build/grub-config + -e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \ + -e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \ + -e 's#@ROOTPART@#root=$(ROOTPART) rootwait#g' \ ++ -e 's#@EFI_ROOTPART@#root=$(EFI_ROOTPART) rootwait#g' \ + -e 's#@CMDLINE@#$(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE)#g' \ + -e 's#@TIMEOUT@#$(GRUB_TIMEOUT)#g' \ + -e 's#@TITLE@#$(GRUB_TITLE)#g' \ +@@ -80,7 +81,7 @@ define Build/grub-install + $(STAGING_DIR_HOST)/bin/grub-bios-setup \ + -m "$@.grub2/device.map" \ + -d "$@.grub2" \ +- -r "hd0,msdos1" \ ++ -r "hd0,$(if $(filter $(1),efi),gpt1,msdos1)" \ + $@ + endef + +@@ -91,7 +92,9 @@ define Build/iso + $(STAGING_DIR_HOST)/lib/grub/grub2-iso/eltorito.img \ + > $@.boot/boot/grub/eltorito.img + -$(CP) $(STAGING_DIR_ROOT)/boot/. $@.boot/boot/ ++ $(if $(filter $(1),efi),$(CP) $(STAGING_DIR_HOST)/lib/grub/grub2-iso/efiboot.img $@.boot/boot/grub/) + mkisofs -R -b boot/grub/eltorito.img -no-emul-boot -boot-info-table \ ++ $(if $(filter $(1),efi),-boot-load-size 4 -c boot.cat -eltorito-alt-boot -e boot/grub/efiboot.img -no-emul-boot) \ + -o $@ $@.boot $(TARGET_DIR) + endef + +@@ -102,13 +105,25 @@ define Device/Default + IMAGE/combined.img.gz := grub-config pc | combined | grub-install | gzip + IMAGE/combined.vdi := grub-config pc | combined | grub-install | qemu-image vdi + IMAGE/combined.vmdk := grub-config pc | combined | grub-install | qemu-image vmdk + IMAGE/rootfs.img := append-rootfs + IMAGE/rootfs.img.gz := append-rootfs | gzip ++ ARTIFACT/image-efi.iso := grub-config iso | iso efi ++ IMAGE/combined-efi.img := grub-config efi | combined efi | grub-install efi ++ IMAGE/combined-efi.img.gz := grub-config efi | combined efi | grub-install efi | gzip ++ IMAGE/combined-efi.vdi := grub-config efi | combined efi | grub-install efi | qemu-image vdi ++ IMAGE/combined-efi.vmdk := grub-config efi | combined efi | grub-install efi | qemu-image vmdk + ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y) + IMAGES := combined.img.gz rootfs.img.gz + else + IMAGES := combined.img rootfs.img + endif ++ ifeq $(CONFIG_EFI_IMAGES) ++ ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y) ++ IMAGES += combined-efi.img.gz ++ else ++ IMAGES += combined-efi.img ++ endif ++ endif + KERNEL := kernel-bin + KERNEL_INSTALL := 1 + KERNEL_NAME := bzImage +@@ -119,6 +134,17 @@ define Device/Default + ifeq ($(CONFIG_VMDK_IMAGES),y) + IMAGES += combined.vmdk + endif ++ ifeq $(CONFIG_EFI_IMAGES) ++ ifeq ($(CONFIG_ISO_IMAGES),y) ++ ARTIFACTS += image-efi.iso ++ endif ++ ifeq ($(CONFIG_VDI_IMAGES),y) ++ IMAGES += combined-efi.vdi ++ endif ++ ifeq ($(CONFIG_VMDK_IMAGES),y) ++ IMAGES += combined-efi.vmdk ++ endif ++ endif + endef + + $(eval $(call Image/gzip-ext4-padded-squashfs)) +diff --git a/target/linux/x86/image/grub-efi.cfg b/target/linux/x86/image/grub-efi.cfg +new file mode 100644 +index 00000000000..f3f6a02c021 +--- /dev/null ++++ b/target/linux/x86/image/grub-efi.cfg +@@ -0,0 +1,13 @@ ++@SERIAL_CONFIG@ ++@TERMINAL_CONFIG@ ++ ++set default="0" ++set timeout="@TIMEOUT@" ++set root='(hd0,gpt1)' ++ ++menuentry "@TITLE@" { ++ linux /boot/vmlinuz @EFI_ROOTPART@ @CMDLINE@ noinitrd ++} ++menuentry "@TITLE@ (failsafe)" { ++ linux /boot/vmlinuz failsafe=true @EFI_ROOTPART@ @CMDLINE@ noinitrd ++} + +From 317bb3e99c4ad67e6e5680d0fbf03d65294aac2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Tue, 24 Mar 2020 18:01:39 +0800 +Subject: [PATCH 7/8] grub2: fix path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: 李国 +--- + package/boot/grub2/grub2/Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/package/boot/grub2/grub2/Makefile b/package/boot/grub2/grub2/Makefile +index 7126beab4cf..3302838d719 100644 +--- a/package/boot/grub2/grub2/Makefile ++++ b/package/boot/grub2/grub2/Makefile +@@ -44,7 +44,7 @@ define Host/Install + -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ + -p /boot/grub \ + -O i386-pc \ +- -c ./files/grub-early.cfg \ ++ -c ../files/grub-early.cfg \ + -o $(STAGING_DIR_HOST)/lib/grub/grub2-generic/core.img \ + at_keyboard biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga + +@@ -53,7 +53,7 @@ define Host/Install + -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ + -p /boot/grub \ + -O i386-pc \ +- -c ./files/grub-early.cfg \ ++ -c ../files/grub-early.cfg \ + -o $(STAGING_DIR_HOST)/lib/grub/grub2-iso/eltorito.img \ + at_keyboard biosdisk boot chain configfile iso9660 linux ls part_msdos reboot serial vga + +@@ -62,7 +62,7 @@ define Host/Install + -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ + -p /boot/grub \ + -O i386-pc \ +- -c ./files/grub-early.cfg \ ++ -c ../files/grub-early.cfg \ + -o $(STAGING_DIR_HOST)/lib/grub/grub2-legacy/core.img \ + biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga + endef + +From 784fcc94242d146f2ef2c31e292ace8816985d62 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E6=9D=8E=E5=9B=BD?= +Date: Tue, 24 Mar 2020 18:02:57 +0800 +Subject: [PATCH 8/8] x86: fix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: 李国 +--- + target/linux/x86/image/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile +index efb0b1cff99..ff964cde8ab 100644 +--- a/target/linux/x86/image/Makefile ++++ b/target/linux/x86/image/Makefile +@@ -115,7 +115,7 @@ define Device/Default + else + IMAGES := combined.img + endif +- ifeq $(CONFIG_EFI_IMAGES) ++ ifeq ($(CONFIG_EFI_IMAGES),y) + ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y) + IMAGES += combined-efi.img.gz + else +@@ -134,7 +134,7 @@ define Device/Default + ifeq ($(CONFIG_VMDK_IMAGES),y) + IMAGES += combined.vmdk + endif +- ifeq $(CONFIG_EFI_IMAGES) ++ ifeq ($(CONFIG_EFI_IMAGES),y) + ifeq ($(CONFIG_ISO_IMAGES),y) + ARTIFACTS += image-efi.iso + endif diff --git a/root/package/base-files/files/bin/config_generate b/root/package/base-files/files/bin/config_generate new file mode 100755 index 00000000..1deda8e2 --- /dev/null +++ b/root/package/base-files/files/bin/config_generate @@ -0,0 +1,438 @@ +#!/bin/sh + +CFG=/etc/board.json + +. /usr/share/libubox/jshn.sh + +[ -s $CFG ] || /bin/board_detect || exit 1 +[ -s /etc/config/network -a -s /etc/config/system ] && exit 0 + +generate_static_network() { + uci -q batch <<-EOF + delete network.loopback + set network.loopback='interface' + set network.loopback.ifname='lo' + set network.loopback.proto='static' + set network.loopback.ipaddr='127.0.0.1' + set network.loopback.netmask='255.0.0.0' + delete network.globals + set network.globals='globals' + set network.globals.ula_prefix='auto' + EOF + + if json_is_a dsl object; then + json_select dsl + if json_is_a atmbridge object; then + json_select atmbridge + local vpi vci encaps payload + json_get_vars vpi vci encaps payload + uci -q batch <<-EOF + delete network.atm + set network.atm='atm-bridge' + set network.atm.vpi='$vpi' + set network.atm.vci='$vci' + set network.atm.encaps='$encaps' + set network.atm.payload='$payload' + EOF + json_select .. + fi + + if json_is_a modem object; then + json_select modem + local type annex firmware tone xfer_mode + json_get_vars type annex firmware tone xfer_mode + uci -q batch <<-EOF + delete network.dsl + set network.dsl='dsl' + set network.dsl.annex='$annex' + set network.dsl.firmware='$firmware' + set network.dsl.tone='$tone' + set network.dsl.xfer_mode='$xfer_mode' + EOF + json_select .. + fi + json_select .. + fi +} + +addr_offset=2 +generate_network() { + local ifname macaddr protocol type ipaddr netmask + + json_select network + json_select "$1" + json_get_vars ifname macaddr protocol ipaddr netmask + json_select .. + json_select .. + + [ -n "$ifname" ] || return + + case "$1" in + # hack (see /etc/board.d/02_network) + none) return ;; + lan*) proto=${proto:-static} ;; + wan*) proto=${proto:-dhcp} ;; + esac + + if [ -n "$macaddr" ]; then + type=macvlan # useless, only for legacy + uci -q batch <<-EOF + delete network.${1}_dev + set network.${1}_dev='device' + set network.${1}_dev.name='$1' + set network.${1}_dev.type='$type' + set network.${1}_dev.ifname='$ifname' + set network.${1}_dev.macaddr='$macaddr' + EOF + ifname=$1 + fi + + uci -q batch <<-EOF + delete network.$1 + set network.$1='interface' + set network.$1.type='$type' + set network.$1.ifname='$ifname' + set network.$1.proto='none' + EOF + + case "$protocol" in + static) + local ipad + case "$1" in + lan) ipad=${ipaddr:-"192.168.100.1"} ;; + *) ipad=${ipaddr:-"192.168.$((addr_offset++)).1"} ;; + esac + + netm=${netmask:-"255.255.255.0"} + + uci -q batch <<-EOF + set network.$1.proto='static' + set network.$1.ipaddr='$ipad' + set network.$1.netmask='$netm' + set network.$1.ip6assign='60' + EOF + ;; + + dhcp) + # fixup IPv6 slave interface if parent is a bridge + [ "$type" = "bridge" ] && ifname="br-$1" + + uci -q batch <<-EOF + set network.$1.proto='dhcp' + EOF + ;; + + pppoe) + uci -q batch <<-EOF + set network.$1.proto='pppoe' + set network.$1.username='username' + set network.$1.password='password' + set network.$1.ipv6='1' + delete network.${1}6 + set network.${1}6='interface' + set network.${1}6.ifname='@${1}' + set network.${1}6.proto='dhcpv6' + EOF + ;; + esac +} + +generate_switch_vlans_ports() { + local switch="$1" + local port ports role roles num attr val + + # + # autogenerate vlans + # + + if json_is_a roles array; then + json_get_keys roles roles + json_select roles + + for role in $roles; do + json_select "$role" + json_get_vars ports + json_select .. + + uci -q batch <<-EOF + add network switch_vlan + set network.@switch_vlan[-1].device='$switch' + set network.@switch_vlan[-1].vlan='$role' + set network.@switch_vlan[-1].ports='$ports' + EOF + done + + json_select .. + fi + + + # + # write port specific settings + # + + if json_is_a ports array; then + json_get_keys ports ports + json_select ports + + for port in $ports; do + json_select "$port" + json_get_vars num + + if json_is_a attr object; then + json_get_keys attr attr + json_select attr + uci -q batch <<-EOF + add network switch_port + set network.@switch_port[-1].device='$switch' + set network.@switch_port[-1].port=$num + EOF + + for attr in $attr; do + json_get_var val "$attr" + uci -q set network.@switch_port[-1].$attr="$val" + done + json_select .. + fi + json_select .. + done + + json_select .. + fi +} + +generate_switch() { + local key="$1" + local vlans + + json_select switch + json_select "$key" + json_get_vars enable reset blinkrate cpu_port + + uci -q batch <<-EOF + add network switch + set network.@switch[-1].name='$key' + set network.@switch[-1].reset='$reset' + set network.@switch[-1].enable_vlan='$enable' + set network.@switch[-1].blinkrate='$blinkrate' + EOF + + generate_switch_vlans_ports "$1" + + json_select .. + json_select .. +} + + +generate_static_system() { + uci -q batch <<-EOF + delete system.@system[0] + add system system + set system.@system[-1].hostname='OpenMPTCProuter' + set system.@system[-1].timezone='UTC' + set system.@system[-1].ttylogin='0' + set system.@system[-1].log_size='64' + set system.@system[-1].urandom_seed='0' + + delete system.ntp + set system.ntp='timeserver' + set system.ntp.enabled='1' + set system.ntp.enable_server='0' + add_list system.ntp.server='0.openwrt.pool.ntp.org' + add_list system.ntp.server='1.openwrt.pool.ntp.org' + add_list system.ntp.server='2.openwrt.pool.ntp.org' + add_list system.ntp.server='3.openwrt.pool.ntp.org' + EOF + + if json_is_a system object; then + json_select system + local hostname + if json_get_var hostname hostname; then + uci -q set "system.@system[-1].hostname=$hostname" + fi + + if json_is_a ntpserver array; then + local keys key + json_get_keys keys ntpserver + json_select ntpserver + uci -q delete "system.ntp.server" + + for key in $keys; do + local server + if json_get_var server "$key"; then + uci -q add_list "system.ntp.server=$server" + fi + done + json_select .. + fi + json_select .. + fi +} + +generate_rssimon() { + local key="$1" + local cfg="rssid_$key" + local refresh threshold + + json_select rssimon + json_select "$key" + json_get_vars refresh threshold + json_select .. + json_select .. + + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='rssid' + set system.$cfg.dev='$key' + set system.$cfg.refresh='$refresh' + set system.$cfg.threshold='$threshold' + EOF +} + +generate_led() { + local key="$1" + local cfg="led_$key" + + json_select led + json_select "$key" + json_get_vars name sysfs type trigger default + + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='led' + set system.$cfg.name='$name' + set system.$cfg.sysfs='$sysfs' + set system.$cfg.trigger='$trigger' + set system.$cfg.default='$default' + EOF + + case "$type" in + gpio) + local gpio inverted + json_get_vars gpio inverted + uci -q batch <<-EOF + set system.$cfg.trigger='gpio' + set system.$cfg.gpio='$gpio' + set system.$cfg.inverted='$inverted' + EOF + ;; + + netdev) + local device mode + json_get_vars device mode + uci -q batch <<-EOF + set system.$cfg.trigger='netdev' + set system.$cfg.mode='$mode' + set system.$cfg.dev='$device' + EOF + ;; + + usb) + local device + json_get_vars device + uci -q batch <<-EOF + set system.$cfg.trigger='usbdev' + set system.$cfg.interval='50' + set system.$cfg.dev='$device' + EOF + ;; + + usbport) + local ports port + json_get_values ports ports + uci set system.$cfg.trigger='usbport' + for port in $ports; do + uci add_list system.$cfg.port=$port + done + ;; + + rssi) + local iface minq maxq offset factor + json_get_vars iface minq maxq offset factor + uci -q batch <<-EOF + set system.$cfg.trigger='rssi' + set system.$cfg.iface='rssid_$iface' + set system.$cfg.minq='$minq' + set system.$cfg.maxq='$maxq' + set system.$cfg.offset='$offset' + set system.$cfg.factor='$factor' + EOF + ;; + + switch) + local port_mask speed_mask + json_get_vars port_mask speed_mask + uci -q batch <<-EOF + set system.$cfg.port_mask='$port_mask' + set system.$cfg.speed_mask='$speed_mask' + EOF + ;; + + portstate) + local port_state + json_get_vars port_state + uci -q batch <<-EOF + set system.$cfg.port_state='$port_state' + EOF + ;; + + timer|oneshot) + local delayon delayoff + json_get_vars delayon delayoff + uci -q batch <<-EOF + set system.$cfg.trigger='$type' + set system.$cfg.delayon='$delayon' + set system.$cfg.delayoff='$delayoff' + EOF + ;; + esac + + json_select .. + json_select .. +} + +generate_gpioswitch() { + local cfg="$1" + + json_select gpioswitch + json_select "$cfg" + local name pin default + json_get_vars name pin default + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='gpio_switch' + set system.$cfg.name='$name' + set system.$cfg.gpio_pin='$pin' + set system.$cfg.value='$default' + EOF + json_select .. + json_select .. +} + +json_init +json_load "$(cat ${CFG})" + +if [ ! -s /etc/config/network ]; then + touch /etc/config/network + generate_static_network + + json_get_keys keys network + for key in $keys; do generate_network $key; done + + json_get_keys keys switch + for key in $keys; do generate_switch $key; done +fi + +if [ ! -s /etc/config/system ]; then + touch /etc/config/system + generate_static_system + + json_get_keys keys rssimon + for key in $keys; do generate_rssimon $key; done + + json_get_keys keys gpioswitch + for key in $keys; do generate_gpioswitch $key; done + + json_get_keys keys led + for key in $keys; do generate_led $key; done +fi +uci commit diff --git a/root/package/base-files/files/etc/banner b/root/package/base-files/files/etc/banner new file mode 100644 index 00000000..01a091a6 --- /dev/null +++ b/root/package/base-files/files/etc/banner @@ -0,0 +1,8 @@ + ___ __ __ ___ _____ ___ ___ _ + / _ \ _ __ ___ _ _ | \/ | _ \_ _/ __| _ \_ _ ___ _ _| |_ ___ _ _ + | (_) | '_ \/ -_) ' \| |\/| | _/ | || (__| _/ '_/ _ \ || | _/ -_) '_| + \___/| .__/\___|_||_|_| |_|_| |_| \___|_| |_| \___/\_,_|\__\___|_| + |_| +------------------------------------------------------------------------------ + (%C) +------------------------------------------------------------------------------ diff --git a/root/package/base-files/files/etc/board.d/99-default_network b/root/package/base-files/files/etc/board.d/99-default_network new file mode 100755 index 00000000..55d5d79a --- /dev/null +++ b/root/package/base-files/files/etc/board.d/99-default_network @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Copyright (C) 2013-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +json_is_a network object && exit 0 + +ucidef_set_interface_lan 'eth0' + +board_config_flush + +exit 0 diff --git a/root/package/base-files/files/lib/preinit/80_mount_root b/root/package/base-files/files/lib/preinit/80_mount_root new file mode 100644 index 00000000..2be3c19c --- /dev/null +++ b/root/package/base-files/files/lib/preinit/80_mount_root @@ -0,0 +1,30 @@ +#!/bin/sh +# Copyright (C) 2006 OpenWrt.org +# Copyright (C) 2010 Vertical Communications +# Copyright (C) 2018 Ycarus (Yannick Chabanois) + +do_mount_root() { + mount_root + boot_run_hook preinit_mount_root + [ -e /dev/sda1 ] && mount /dev/sda1 /boot >/dev/null 2>&1 + [ -f /boot/sysupgrade.tgz ] && { + mv /boot/sysupgrade.tgz / + } + [ -e /dev/sda1 ] && umount /boot >/dev/null 2>&1 + [ -f /sysupgrade.tgz ] && { + echo "- config restore -" + cd / + tar xzf sysupgrade.tgz + } +} +[ -n "$(mount | grep ext4 | grep ro)" ] && { + [ -e /dev/mmcblk0p2 ] && { + echo "Checking ext4 FS on mmcblk0p2..." + /usr/sbin/e2fsck -y -f /dev/mmcblk0p2 >/dev/null 2>&1 + } + [ -e /dev/sda2 ] && { + echo "Checking ext4 FS on sda2..." + /usr/sbin/e2fsck -y -f /dev/sda2 >/dev/null 2>&1 + } +} +[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main do_mount_root diff --git a/root/package/boot/uboot-envtools/Makefile b/root/package/boot/uboot-envtools/Makefile new file mode 100644 index 00000000..5ea32d88 --- /dev/null +++ b/root/package/boot/uboot-envtools/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (C) 2006-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=uboot-envtools +PKG_DISTNAME:=u-boot +PKG_VERSION:=2020.04 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE:=$(PKG_DISTNAME)-$(PKG_VERSION).tar.bz2 +PKG_SOURCE_SUBDIR:=$(PKG_DISTNAME)-$(PKG_VERSION) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_DISTNAME)-$(PKG_VERSION) +PKG_SOURCE_URL:=https://git.denx.de/u-boot.git +PKG_SOURCE_VERSION:=36fec02b1f90b92cf51ec531564f9284eae27ab4 +PKG_MIRROR_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372 + +PKG_BUILD_DEPENDS:=fstools + +PKG_LICENSE:=GPL-2.0 GPL-2.0+ +PKG_LICENSE_FILES:=Licenses/README + +PKG_FLAGS:=nonshared + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/uboot-envtools + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=Boot Loaders + TITLE:=read/modify U-Boot bootloader environment + URL:=http://www.denx.de/wiki/U-Boot +endef + +define Package/uboot-envtools/description + This package includes tools to read and modify U-Boot bootloader environment. +endef + +define Build/Configure + touch $(PKG_BUILD_DIR)/include/config.h + mkdir -p $(PKG_BUILD_DIR)/include/config + touch $(PKG_BUILD_DIR)/include/config/auto.conf + mkdir -p $(PKG_BUILD_DIR)/include/generated + touch $(PKG_BUILD_DIR)/include/generated/autoconf.h +endef + +MAKE_FLAGS += \ + TARGET_CFLAGS="$(TARGET_CFLAGS)" \ + TARGET_LDFLAGS="$(TARGET_LDFLAGS)" \ + no-dot-config-targets=envtools \ + envtools + +define Package/uboot-envtools/conffiles +/etc/config/ubootenv +/etc/fw_env.config +endef + +define Package/uboot-envtools/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/env/fw_printenv $(1)/usr/sbin + $(LN) fw_printenv $(1)/usr/sbin/fw_setenv + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DATA) ./files/uboot-envtools.sh $(1)/lib + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(if $(wildcard ./files/$(BOARD)), \ + $(INSTALL_DATA) ./files/$(BOARD) \ + $(1)/etc/uci-defaults/30_uboot-envtools \ + ) +endef + +$(eval $(call BuildPackage,uboot-envtools)) diff --git a/root/package/firmware/ipq-wifi/Makefile b/root/package/firmware/ipq-wifi/Makefile new file mode 100644 index 00000000..8bf3b414 --- /dev/null +++ b/root/package/firmware/ipq-wifi/Makefile @@ -0,0 +1,119 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/version.mk + +PKG_NAME:=ipq-wifi +PKG_RELEASE:=1 +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Compile +endef + +# Use ath10k-bdencoder from https://github.com/qca/qca-swiss-army-knife.git +# to generate the board-* files here. +# +# This is intended to be used on an interim basis until device-specific +# board data for new devices is available through the upstream compilation +# +# Please send a mail with your device-specific board files upstream. +# You can find instructions and examples on the linux-wireless wiki: +# + +ALLWIFIBOARDS:= \ + 8dev_habanero-dvk \ + aruba_ap-303 \ + avm_fritzrepeater-1200 \ + buffalo_wtr-m2133hp \ + cellc_rtl30vw \ + dlink_dap2610 \ + engenius_eap2200 \ + engenius_emd1 \ + engenius_emr3500 \ + ezviz_cs-w3-wd1200g-eup \ + glinet_gl-s1300 \ + linksys_ea8300 \ + p2w_r619ac \ + mobipromo_cm520-79f \ + qxwlan_e2600ac + +ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ipq-wifi-$(BOARD)) + +define Package/ipq-wifi-default + SUBMENU:=ath10k Board-Specific Overrides + SECTION:=firmware + CATEGORY:=Firmware + DEPENDS:=@TARGET_ipq40xx + TITLE:=Custom Board +endef + +define ipq-wifi-install-one-to + $(INSTALL_DIR) $(2)/lib/firmware/ath10k/$(3)/ + $(INSTALL_DATA) $(1) $(2)/lib/firmware/ath10k/$(3)/board-2.bin +endef + +define ipq-wifi-install-one + $(if $(filter $(suffix $(1)),.QCA4019 .qca4019),\ + $(call ipq-wifi-install-one-to,$(1),$(2),QCA4019/hw1.0),\ + $(if $(filter $(suffix $(1)),.QCA9888 .qca9888),\ + $(call ipq-wifi-install-one-to,$(1),$(2),QCA9888/hw2.0),\ + $(if $(filter $(suffix $(1)),.QCA9984 .qca9984),\ + $(call ipq-wifi-install-one-to,$(1),$(2),QCA9984/hw1.0),\ + $(error Unrecognized board-file suffix '$(suffix $(1))' for '$(1)')\ + ))) + +endef +# Blank line required at end of above define due to foreach context + +define generate-ipq-wifi-package + define Package/ipq-wifi-$(1) + $(call Package/ipq-wifi-default) + TITLE:=board-2.bin Overrides for $(2) + CONFLICTS:=$(PREV_BOARD) + endef + + define Package/ipq-wifi-$(1)/description +The $(2) requires board-specific, reference ("cal") data +that is not yet present in the upstream wireless firmware distribution. + +This package supplies board-2.bin file(s) that, in the interim, +overwrite those supplied by the ath10k-firmware-* packages. + +This is package is only necessary for the $(2). + +Do not install it for any other device! + endef + + define Package/ipq-wifi-$(1)/install-overlay + $$$$(foreach IPQ_WIFI_BOARD_FILE,$$$$(wildcard board-$(1).*),\ + $$$$(call ipq-wifi-install-one,$$$$(IPQ_WIFI_BOARD_FILE),$$(1))) + endef + + PREV_BOARD+=ipq-wifi-$(1) +endef + +# Add board name to ALLWIFIBOARDS +# Place files in this directory as board-. +# Add $(eval $(call generate-ipq-wifi-package,,)) + +$(eval $(call generate-ipq-wifi-package,8dev_habanero-dvk,8devices Habanero DVK)) +$(eval $(call generate-ipq-wifi-package,aruba_ap-303,Aruba AP-303)) +$(eval $(call generate-ipq-wifi-package,avm_fritzrepeater-1200,AVM FRITZRepeater 1200)) +$(eval $(call generate-ipq-wifi-package,buffalo_wtr-m2133hp,Buffalo WTR-M2133HP)) +$(eval $(call generate-ipq-wifi-package,cellc_rtl30vw, Cell C RTL30VW)) +$(eval $(call generate-ipq-wifi-package,dlink_dap2610,D-Link DAP-2610)) +$(eval $(call generate-ipq-wifi-package,engenius_eap2200,EnGenius EAP2200)) +$(eval $(call generate-ipq-wifi-package,engenius_emd1,EnGenius EMD1)) +$(eval $(call generate-ipq-wifi-package,engenius_emr3500,EnGenius EMR3500)) +$(eval $(call generate-ipq-wifi-package,ezviz_cs-w3-wd1200g-eup,EZVIZ CS-W3-WD1200G EUP)) +$(eval $(call generate-ipq-wifi-package,glinet_gl-s1300,GL.iNet GL-S1300)) +$(eval $(call generate-ipq-wifi-package,linksys_ea8300,Linksys EA8300)) +$(eval $(call generate-ipq-wifi-package,mobipromo_cm520-79f,MobiPromo CM520-79F)) +$(eval $(call generate-ipq-wifi-package,qxwlan_e2600ac,Qxwlan E2600AC)) +$(eval $(call generate-ipq-wifi-package,p2w_r619ac,P&W R619AC)) + +$(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE)))) diff --git a/root/package/firmware/ipq-wifi/board-p2w_r619ac.qca4019 b/root/package/firmware/ipq-wifi/board-p2w_r619ac.qca4019 new file mode 100644 index 00000000..a1b1166f Binary files /dev/null and b/root/package/firmware/ipq-wifi/board-p2w_r619ac.qca4019 differ diff --git a/root/package/network/config/firewall/patches/fullconenat.patch b/root/package/network/config/firewall/patches/fullconenat.patch new file mode 100644 index 00000000..825e8c1d --- /dev/null +++ b/root/package/network/config/firewall/patches/fullconenat.patch @@ -0,0 +1,40 @@ +--- a/options.h ++++ b/options.h +@@ -341,6 +341,8 @@ struct fw3_zone + struct list_head masq_src; + struct list_head masq_dest; + ++ bool fullcone; ++ + bool mtu_fix; + + struct list_head cthelpers; +--- a/zones.c ++++ b/zones.c +@@ -77,6 +77,8 @@ const struct fw3_option fw3_zone_opts[] + FW3_LIST("masq_src", network, zone, masq_src), + FW3_LIST("masq_dest", network, zone, masq_dest), + ++ FW3_OPT("fullcone", bool, zone, fullcone), ++ + FW3_OPT("extra", string, zone, extra_src), + FW3_OPT("extra_src", string, zone, extra_src), + FW3_OPT("extra_dest", string, zone, extra_dest), +@@ -709,7 +711,16 @@ print_zone_rule(struct fw3_ipt_handle *h + (mdest = next_addr(mdest, &zone->masq_dest, + handle->family, false)) || first_dest; + first_dest = false) +- { ++ if (zone->fullcone && (access("/usr/lib/iptables/libipt_FULLCONENAT.so", 0) == 0)) { ++ r = fw3_ipt_rule_new(handle); ++ fw3_ipt_rule_src_dest(r, msrc, mdest); ++ fw3_ipt_rule_target(r, "FULLCONENAT"); ++ fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name); ++ r = fw3_ipt_rule_new(handle); ++ fw3_ipt_rule_src_dest(r, msrc, mdest); ++ fw3_ipt_rule_target(r, "FULLCONENAT"); ++ fw3_ipt_rule_append(r, "zone_%s_prerouting", zone->name); ++ } else { + r = fw3_ipt_rule_new(handle); + fw3_ipt_rule_src_dest(r, msrc, mdest); + fw3_ipt_rule_target(r, "MASQUERADE"); diff --git a/root/package/network/ipv6/6in4/Makefile b/root/package/network/ipv6/6in4/Makefile new file mode 100644 index 00000000..d0f2ad30 --- /dev/null +++ b/root/package/network/ipv6/6in4/Makefile @@ -0,0 +1,45 @@ +# +# Copyright (C) 2010-2015 OpenWrt.org +# Copyright (C) 2018-2019 Ycarus (Yannick Chabanois) +# - Added gateway setting +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=6in4 +PKG_VERSION:=270 +PKG_RELEASE:=2 +PKG_LICENSE:=GPL-2.0 + +include $(INCLUDE_DIR)/package.mk + +define Package/6in4 + SECTION:=net + CATEGORY:=Network + DEPENDS:=@IPV6 +kmod-sit +uclient-fetch + TITLE:=IPv6-in-IPv4 configuration support + MAINTAINER:=Jo-Philipp Wich + PKGARCH:=all +endef + +define Package/6in4/description +Provides support for 6in4 tunnels in /etc/config/network. +Refer to http://wiki.openwrt.org/doc/uci/network for +configuration details. +endef + +define Build/Compile +endef + +define Build/Configure +endef + +define Package/6in4/install + $(INSTALL_DIR) $(1)/lib/netifd/proto + $(INSTALL_BIN) ./files/6in4.sh $(1)/lib/netifd/proto/6in4.sh +endef + +$(eval $(call BuildPackage,6in4)) diff --git a/root/package/network/ipv6/6in4/files/6in4.sh b/root/package/network/ipv6/6in4/files/6in4.sh new file mode 100755 index 00000000..cf17c86d --- /dev/null +++ b/root/package/network/ipv6/6in4/files/6in4.sh @@ -0,0 +1,149 @@ +#!/bin/sh +# 6in4.sh - IPv6-in-IPv4 tunnel backend +# Copyright (c) 2010-2015 OpenWrt.org + +[ -n "$INCLUDE_ONLY" ] || { + . /lib/functions.sh + . /lib/functions/network.sh + . ../netifd-proto.sh + init_proto "$@" +} + +proto_6in4_update() { + sh -c ' + timeout=5 + + (while [ $((timeout--)) -gt 0 ]; do + sleep 1 + kill -0 $$ || exit 0 + done; kill -9 $$) 2>/dev/null & + + exec "$@" + ' "$1" "$@" +} + +proto_6in4_add_prefix() { + append "$3" "$1" +} + +proto_6in4_setup() { + local cfg="$1" + local iface="$2" + local link="6in4-$cfg" + + local mtu ttl tos ipaddr peeraddr ip6addr ip6prefix ip6prefixes tunlink tunnelid username password updatekey gateway + json_get_vars mtu ttl tos ipaddr peeraddr ip6addr tunlink tunnelid username password updatekey gateway + json_for_each_item proto_6in4_add_prefix ip6prefix ip6prefixes + + [ -z "$peeraddr" ] && { + proto_notify_error "$cfg" "MISSING_ADDRESS" + proto_block_restart "$cfg" + return + } + + [ -n "$tunlink" ] && ( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" ) + + [ -z "$ipaddr" ] && { + local wanif="$tunlink" + if [ -z "$wanif" ] && ! network_find_wan wanif; then + proto_notify_error "$cfg" "NO_WAN_LINK" + return + fi + + if ! network_get_ipaddr ipaddr "$wanif"; then + proto_notify_error "$cfg" "NO_WAN_LINK" + return + fi + } + + proto_init_update "$link" 1 + + [ -n "$ip6addr" ] && { + local local6="${ip6addr%%/*}" + local mask6="${ip6addr##*/}" + [[ "$local6" = "$mask6" ]] && mask6= + proto_add_ipv6_address "$local6" "$mask6" + proto_add_ipv6_route "::" 0 "" "" "" "$local6/$mask6" + } + + [ -n "$gateway" ] && { + proto_add_ipv6_route "::" 0 "$gateway" + } + + for ip6prefix in $ip6prefixes; do + proto_add_ipv6_prefix "$ip6prefix" + proto_add_ipv6_route "::" 0 "" "" "" "$ip6prefix" + done + + proto_add_tunnel + json_add_string mode sit + json_add_int mtu "${mtu:-1280}" + json_add_int ttl "${ttl:-64}" + [ -n "$tos" ] && json_add_string tos "$tos" + json_add_string local "$ipaddr" + json_add_string remote "$peeraddr" + [ -n "$tunlink" ] && json_add_string link "$tunlink" + proto_close_tunnel + + proto_send_update "$cfg" + + [ -n "$tunnelid" -a -n "$username" -a \( -n "$password" -o -n "$updatekey" \) ] && { + [ -n "$updatekey" ] && password="$updatekey" + + local http="http" + local urlget="uclient-fetch" + local urlget_opts="-qO-" + local ca_path="${SSL_CERT_DIR:-/etc/ssl/certs}" + + [ -f /lib/libustream-ssl.so ] && http=https + [ "$http" = "https" -a -z "$(find $ca_path -name "*.0" 2>/dev/null)" ] && { + urlget_opts="$urlget_opts --no-check-certificate" + } + + local url="$http://ipv4.tunnelbroker.net/nic/update?hostname=$tunnelid" + local try=0 + local max=3 + + ( + set -o pipefail + while [ $((++try)) -le $max ]; do + if proto_6in4_update $urlget $urlget_opts --user="$username" --password="$password" "$url" 2>&1 | \ + sed -e 's,^Killed$,timeout,' -e "s,^,update $try/$max: ," | \ + logger -t "$link"; + then + logger -t "$link" "updated" + return 0 + fi + sleep 5 + done + logger -t "$link" "update failed" + ) + } +} + +proto_6in4_teardown() { + local cfg="$1" +} + +proto_6in4_init_config() { + no_device=1 + available=1 + + proto_config_add_string "ipaddr" + proto_config_add_string "ip6addr" + proto_config_add_array "ip6prefix" + proto_config_add_string "peeraddr" + proto_config_add_string "tunlink" + proto_config_add_string "tunnelid" + proto_config_add_string "username" + proto_config_add_string "password" + proto_config_add_string "updatekey" + proto_config_add_string "gateway" + proto_config_add_int "mtu" + proto_config_add_int "ttl" + proto_config_add_string "tos" +} + +[ -n "$INCLUDE_ONLY" ] || { + add_protocol 6in4 +} diff --git a/root/package/network/services/dnsmasq/files/dnsmasq.init b/root/package/network/services/dnsmasq/files/dnsmasq.init new file mode 100644 index 00000000..ddd19a54 --- /dev/null +++ b/root/package/network/services/dnsmasq/files/dnsmasq.init @@ -0,0 +1,1134 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2007-2012 OpenWrt.org + +START=19 + +USE_PROCD=1 +PROG=/usr/sbin/dnsmasq + +ADD_LOCAL_DOMAIN=1 +ADD_LOCAL_HOSTNAME=1 +ADD_WAN_FQDN=0 +ADD_LOCAL_FQDN="" + +BASECONFIGFILE="/var/etc/dnsmasq.conf" +BASEHOSTFILE="/tmp/hosts/dhcp" +TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" +TIMEVALIDFILE="/var/state/dnsmasqsec" +BASEDHCPSTAMPFILE="/var/run/dnsmasq" +RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf" +DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh" + +DNSMASQ_DHCP_VER=4 + +xappend() { + local value="$1" + + echo "${value#--}" >> $CONFIGFILE_TMP +} + +hex_to_hostid() { + local var="$1" + local hex="${2#0x}" # strip optional "0x" prefix + + if [ -n "${hex//[0-9a-fA-F]/}" ]; then + # is invalid hex literal + return 1 + fi + + # convert into host id + export "$var=$( + printf "%0x:%0x" \ + $(((0x$hex >> 16) % 65536)) \ + $(( 0x$hex % 65536)) + )" + + return 0 +} + +dhcp_calc() { + local ip="$1" + local res=0 + + while [ -n "$ip" ]; do + part="${ip%%.*}" + res="$(($res * 256))" + res="$(($res + $part))" + [ "${ip%.*}" != "$ip" ] && ip="${ip#*.}" || ip= + done + echo "$res" +} + +dhcp_check() { + local ifname="$1" + local stamp="${BASEDHCPSTAMPFILE_CFG}.${ifname}.dhcp" + local rv=0 + + [ -s "$stamp" ] && return $(cat "$stamp") + + # If there's no carrier yet, skip this interface. + # The init script will be called again once the link is up + case "$(devstatus "$ifname" | jsonfilter -e @.carrier)" in + false) return 1;; + esac + + udhcpc -n -q -s /bin/true -t 1 -i "$ifname" >&- && rv=1 || rv=0 + + [ $rv -eq 1 ] && \ + logger -t dnsmasq \ + "found already running DHCP-server on interface '$ifname'" \ + "refusing to start, use 'option force 1' to override" + + echo $rv > "$stamp" + return $rv +} + +log_once() { + pidof dnsmasq >/dev/null || \ + logger -t dnsmasq "$@" +} + +has_handler() { + local file + + for file in /etc/hotplug.d/dhcp/* /etc/hotplug.d/tftp/* /etc/hotplug.d/neigh/*; do + [ -f "$file" ] && return 0 + done + + return 1 +} + +append_bool() { + local section="$1" + local option="$2" + local value="$3" + local default="$4" + local _loctmp + [ -z "$default" ] && default="0" + config_get_bool _loctmp "$section" "$option" "$default" + [ $_loctmp -gt 0 ] && xappend "$value" +} + +append_parm() { + local section="$1" + local option="$2" + local switch="$3" + local default="$4" + local _loctmp + config_get _loctmp "$section" "$option" "$default" + [ -z "$_loctmp" ] && return 0 + xappend "$switch=$_loctmp" +} + +append_server() { + xappend "--server=$1" +} + +append_rev_server() { + xappend "--rev-server=$1" +} + +append_address() { + xappend "--address=$1" +} + +append_ipset() { + xappend "--ipset=$1" +} + +append_interface() { + network_get_device ifname "$1" || ifname="$1" + xappend "--interface=$ifname" +} + +append_listenaddress() { + xappend "--listen-address=$1" +} + +append_notinterface() { + network_get_device ifname "$1" || ifname="$1" + xappend "--except-interface=$ifname" +} + +append_addnhosts() { + xappend "--addn-hosts=$1" +} + +append_bogusnxdomain() { + xappend "--bogus-nxdomain=$1" +} + +append_pxe_service() { + xappend "--pxe-service=$1" +} + +append_interface_name() { + xappend "--interface-name=$1,$2" +} + +filter_dnsmasq() { + local cfg="$1" func="$2" match_cfg="$3" found_cfg + + # use entry when no instance entry set, or if it matches + config_get found_cfg "$cfg" "instance" + if [ -z "$found_cfg" -o "$found_cfg" = "$match_cfg" ]; then + $func $cfg + fi +} + +dhcp_subscrid_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get subscriberid "$cfg" subscriberid + [ -n "$subscriberid" ] || return 0 + + xappend "--dhcp-subscrid=$networkid,$subscriberid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_remoteid_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get remoteid "$cfg" remoteid + [ -n "$remoteid" ] || return 0 + + xappend "--dhcp-remoteid=$networkid,$remoteid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_circuitid_add() { + # TODO: DHCPV6 does not have circuitid; catch "option6:" + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get circuitid "$cfg" circuitid + [ -n "$circuitid" ] || return 0 + + xappend "--dhcp-circuitid=$networkid,$circuitid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_userclass_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get userclass "$cfg" userclass + [ -n "$userclass" ] || return 0 + + xappend "--dhcp-userclass=$networkid,$userclass" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_vendorclass_add() { + # TODO: DHCPV6 vendor class has stricter definitions; catch? fixup? + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get vendorclass "$cfg" vendorclass + [ -n "$vendorclass" ] || return 0 + + xappend "--dhcp-vendorclass=$networkid,$vendorclass" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_match_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get match "$cfg" match + [ -n "$match" ] || return 0 + + xappend "--dhcp-match=$networkid,$match" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_host_add() { + local cfg="$1" + local hosttag nametime addrs duids macs tags + + config_get_bool force "$cfg" force 0 + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] && dhcp_option_add "$cfg" "$networkid" "$force" + + config_get_bool enable "$cfg" enable 1 + [ "$enable" = "0" ] && return 0 + + config_get name "$cfg" name + config_get ip "$cfg" ip + config_get hostid "$cfg" hostid + + [ -n "$ip" -o -n "$name" -o -n "$hostid" ] || return 0 + + config_get_bool dns "$cfg" dns 0 + [ "$dns" = "1" -a -n "$ip" -a -n "$name" ] && { + echo "$ip $name${DOMAIN:+.$DOMAIN}" >> $HOSTFILE_TMP + } + + config_get mac "$cfg" mac + config_get duid "$cfg" duid + config_get tag "$cfg" tag + config_get gw "$cfg" gw + + if [ -n "$mac" ]; then + # --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap + # many MAC are possible to track a laptop ON/OFF dock + for m in $mac; do append macs "$m" ","; done + fi + + if [ $DNSMASQ_DHCP_VER -eq 6 -a -n "$duid" ]; then + # --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap + # one (virtual) machine gets one DUID per RFC3315 + duids="id:${duid// */}" + fi + + if [ -z "$macs" -a -z "$duids" ]; then + # --dhcp-host=lap,192.168.0.199,[::beef] + [ -n "$name" ] || return 0 + macs="$name" + name="" + fi + + if [ -n "$hostid" ]; then + hex_to_hostid hostid "$hostid" + fi + + if [ -n "$tag" ]; then + for t in $tag; do append tags "$t" ",set:"; done + fi + + if [ -n "$gw" ]; then + append tags "$cfg" ",set:" + fi + + config_get_bool broadcast "$cfg" broadcast 0 + config_get leasetime "$cfg" leasetime + + [ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast" + + hosttag="${networkid:+,set:${networkid}}${tags:+,set:${tags}}$broadcast" + nametime="${name:+,$name}${leasetime:+,$leasetime}" + + if [ $DNSMASQ_DHCP_VER -eq 6 ]; then + addrs="${ip:+,$ip}${hostid:+,[::$hostid]}" + xappend "--dhcp-host=$macs${duids:+,$duids}$hosttag$addrs$nametime" + else + xappend "--dhcp-host=$macs$hosttag${ip:+,$ip}$nametime" + fi + if [ -n "$gw" ]; then + xappend "--dhcp-option=tag:$cfg,option:router,$gw" + fi +} + +dhcp_this_host_add() { + local net="$1" + local ifname="$2" + local mode="$3" + local routerstub routername ifdashname + local lanaddr lanaddr6 lanaddrs6 ulaprefix + + if [ "$mode" -gt 0 ] ; then + ifdashname="${ifname//./-}" + routerstub="$( md5sum /etc/os-release )" + routerstub="router-${routerstub// */}" + routername="$( uci_get system @system[0] hostname $routerstub )" + + if [ "$mode" -gt 1 ] ; then + if [ "$mode" -gt 2 ] ; then + if [ "$mode" -gt 3 ] ; then + append_interface_name "$ifdashname.$routername.$DOMAIN" "$ifname" + fi + + append_interface_name "$routername.$DOMAIN" "$ifname" + fi + + # All IP addresses discovered by dnsmasq will be labeled (except fe80::) + append_interface_name "$routername" "$ifname" + + else + # This uses a static host file entry for only limited addresses. + # Use dnsmasq option "--expandhosts" to enable FQDN on host files. + ulaprefix="$(uci_get network @globals[0] ula_prefix)" + network_get_ipaddr lanaddr "$net" + network_get_ipaddrs6 lanaddrs6 "$net" + + if [ -n "$lanaddr" ] ; then + dhcp_domain_add "" "$routername" "$lanaddr" + fi + + if [ -n "$ulaprefix" -a -n "$lanaddrs6" ] ; then + for lanaddr6 in $lanaddrs6 ; do + case "$lanaddr6" in + "${ulaprefix%%:/*}"*) + dhcp_domain_add "" "$routername" "$lanaddr6" + ;; + esac + done + fi + fi + fi +} + +dhcp_tag_add() { + # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions + local cfg="$1" + + tag="$cfg" + + [ -n "$tag" ] || return 0 + + config_get_bool force "$cfg" force 0 + [ "$force" = "0" ] && force= + + config_get option "$cfg" dhcp_option + for o in $option; do + xappend "--dhcp-option${force:+-force}=tag:$tag,$o" + done +} + +dhcp_mac_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get mac "$cfg" mac + [ -n "$mac" ] || return 0 + + xappend "--dhcp-mac=$networkid,$mac" + + dhcp_option_add "$cfg" "$networkid" +} + +dhcp_boot_add() { + # TODO: BOOTURL is different between DHCPv4 and DHCPv6 + local cfg="$1" + + config_get networkid "$cfg" networkid + + config_get filename "$cfg" filename + [ -n "$filename" ] || return 0 + + config_get servername "$cfg" servername + config_get serveraddress "$cfg" serveraddress + + [ -n "$serveraddress" -a ! -n "$servername" ] && return 0 + + xappend "--dhcp-boot=${networkid:+net:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + + +dhcp_add() { + local cfg="$1" + local dhcp6range="::" + local nettag + local tags + + config_get net "$cfg" interface + [ -n "$net" ] || return 0 + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || networkid="$net" + + network_get_device ifname "$net" || return 0 + + [ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && { + DNS_SERVERS="$DNS_SERVERS $dnsserver" + } + + append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && { + # Many ISP do not have useful names for DHCP customers (your WAN). + dhcp_this_host_add "$net" "$ifname" "$ADD_WAN_FQDN" + return 0 + } + + network_get_subnet subnet "$net" || return 0 + network_get_protocol proto "$net" || return 0 + + # Do not support non-static interfaces for now + [ static = "$proto" ] || return 0 + + # Override interface netmask with dhcp config if applicable + config_get netmask "$cfg" netmask "${subnet##*/}" + + #check for an already active dhcp server on the interface, unless 'force' is set + config_get_bool force "$cfg" force 0 + [ $force -gt 0 ] || dhcp_check "$ifname" || return 0 + + config_get start "$cfg" start 100 + config_get limit "$cfg" limit 150 + config_get leasetime "$cfg" leasetime 12h + config_get options "$cfg" options + config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1 + + config_get dhcpv4 "$cfg" dhcpv4 + config_get dhcpv6 "$cfg" dhcpv6 + + config_get ra "$cfg" ra + config_get ra_management "$cfg" ra_management + config_get ra_preference "$cfg" ra_preference + config_get dns "$cfg" dns + + config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname" + + # Put the router host name on this DHCP served interface address(es) + dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN" + + start="$( dhcp_calc "$start" )" + + add_tag() { + tags="${tags}tag:$1," + } + config_list_foreach "$cfg" tag add_tag + + nettag="${networkid:+set:${networkid},}" + + if [ "$limit" -gt 0 ] ; then + limit=$((limit-1)) + fi + + eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)" + + if [ "$dynamicdhcp" = "0" ] ; then + END="static" + dhcp6range="::,static" + else + dhcp6range="::1000,::ffff" + fi + + + if [ "$dhcpv4" != "disabled" ] ; then + xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}" + fi + + + if [ $DNSMASQ_DHCP_VER -eq 6 -a "$ra" = "server" ] ; then + # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1) + # and let some other machine(s) send RA pointing to it. + + case $ra_preference in + *high*) + xappend "--ra-param=$ifname,high,0,7200" + ;; + *low*) + xappend "--ra-param=$ifname,low,0,7200" + ;; + *) + # Send UNSOLICITED RA at default interval and live for 2 hours. + # TODO: convert flexible lease time into route life time (only seconds). + xappend "--ra-param=$ifname,0,7200" + ;; + esac + + if [ "$dhcpv6" = "disabled" ] ; then + ra_management="3" + fi + + + case $ra_management in + 0) + # SLACC with DCHP for extended options + xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names" + ;; + 2) + # DHCP address and RA only for management redirection + xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime" + ;; + 3) + # SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC + xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names" + ;; + *) + # SLAAC and full DHCP + xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime" + ;; + esac + + if [ -n "$dns" ]; then + dnss="" + for d in $dns; do append dnss "[$d]" ","; done + else + dnss="[::]" + fi + + dhcp_option_append "option6:dns-server,$dnss" "$networkid" + fi + + dhcp_option_add "$cfg" "$networkid" 0 + dhcp_option_add "$cfg" "$networkid" 2 +} + +dhcp_option_append() { + local option="$1" + local networkid="$2" + local force="$3" + + xappend "--dhcp-option${force:+-force}=${networkid:+$networkid,}$option" +} + +dhcp_option_add() { + # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions + local cfg="$1" + local networkid="$2" + local force="$3" + local opt="dhcp_option" + + [ "$force" = "0" ] && force= + [ "$force" = "2" ] && opt="dhcp_option_force" + + local list_len + config_get list_len "$cfg" "${opt}_LENGTH" + + if [ -n "$list_len" ]; then + config_list_foreach "$cfg" "$opt" dhcp_option_append "$networkid" "$force" + else + config_get dhcp_option "$cfg" "$opt" + + [ -n "$dhcp_option" ] && echo "Warning: the 'option $opt' syntax is deprecated, use 'list $opt'" >&2 + + local option + for option in $dhcp_option; do + dhcp_option_append "$option" "$networkid" "$force" + done + fi +} + +dhcp_domain_add() { + local cfg="$1" + local ip name names record + + config_get names "$cfg" name "$2" + [ -n "$names" ] || return 0 + + config_get ip "$cfg" ip "$3" + [ -n "$ip" ] || return 0 + + for name in $names; do + record="${record:+$record }$name" + done + + echo "$ip $record" >> $HOSTFILE_TMP +} + +dhcp_srv_add() { + local cfg="$1" + + config_get srv "$cfg" srv + [ -n "$srv" ] || return 0 + + config_get target "$cfg" target + [ -n "$target" ] || return 0 + + config_get port "$cfg" port + [ -n "$port" ] || return 0 + + config_get class "$cfg" class + config_get weight "$cfg" weight + + local service="$srv,$target,$port${class:+,$class${weight:+,$weight}}" + + xappend "--srv-host=$service" +} + +dhcp_mx_add() { + local cfg="$1" + local domain relay pref + + config_get domain "$cfg" domain + [ -n "$domain" ] || return 0 + + config_get relay "$cfg" relay + [ -n "$relay" ] || return 0 + + config_get pref "$cfg" pref 0 + + local service="$domain,$relay,$pref" + + xappend "--mx-host=$service" +} + +dhcp_cname_add() { + local cfg="$1" + local cname target + + config_get cname "$cfg" cname + [ -n "$cname" ] || return 0 + + config_get target "$cfg" target + [ -n "$target" ] || return 0 + + xappend "--cname=${cname},${target}" +} + +dhcp_hostrecord_add() { + local cfg="$1" + local names addresses record val + + config_get names "$cfg" name "$2" + if [ -z "$names" ]; then + return 0 + fi + + config_get addresses "$cfg" ip "$3" + if [ -z "$addresses" ]; then + return 0 + fi + + for val in $names $addresses; do + record="${record:+$record,}$val" + done + + xappend "--host-record=$record" +} + +dhcp_relay_add() { + local cfg="$1" + local local_addr server_addr interface + + config_get local_addr "$cfg" local_addr + [ -n "$local_addr" ] || return 0 + + config_get server_addr "$cfg" server_addr + [ -n "$server_addr" ] || return 0 + + config_get interface "$cfg" interface + if [ -z "$interface" ]; then + xappend "--dhcp-relay=$local_addr,$server_addr" + else + network_get_device ifname "$interface" || return + xappend "--dhcp-relay=$local_addr,$server_addr,$ifname" + fi +} + +dnsmasq_start() +{ + local cfg="$1" disabled resolvfile user_dhcpscript + + config_get_bool disabled "$cfg" disabled 0 + [ "$disabled" -gt 0 ] && return 0 + + # reset list of DOMAINS and DNS servers (for each dnsmasq instance) + DNS_SERVERS="" + DOMAIN="" + CONFIGFILE="${BASECONFIGFILE}.${cfg}" + CONFIGFILE_TMP="${CONFIGFILE}.$$" + HOSTFILE="${BASEHOSTFILE}.${cfg}" + HOSTFILE_TMP="${HOSTFILE}.$$" + BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}" + + # before we can call xappend + mkdir -p /var/run/dnsmasq/ + mkdir -p $(dirname $CONFIGFILE) + mkdir -p $(dirname $HOSTFILE) + mkdir -p /var/lib/misc + chown dnsmasq:dnsmasq /var/run/dnsmasq + + echo "# auto-generated config file from /etc/config/dhcp" > $CONFIGFILE_TMP + echo "# auto-generated config file from /etc/config/dhcp" > $HOSTFILE_TMP + + local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf" + if [ ! -r "$dnsmasqconffile" ]; then + dnsmasqconffile=/etc/dnsmasq.conf + fi + + # if we did this last, we could override auto-generated config + [ -f "${dnsmasqconffile}" ] && { + xappend "--conf-file=${dnsmasqconffile}" + } + + $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0 + + + if [ -x /usr/sbin/odhcpd -a -x /etc/init.d/odhcpd ] ; then + local odhcpd_is_main odhcpd_is_enabled + config_get odhcpd_is_main odhcpd maindhcp 0 + /etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0 + + + if [ "$odhcpd_is_enabled" -eq 0 -a "$DHCPv6CAPABLE" -eq 1 ] ; then + # DHCP V4 and V6 in DNSMASQ + DNSMASQ_DHCP_VER=6 + elif [ "$odhcpd_is_main" -gt 0 ] ; then + # ODHCPD is doing it all + DNSMASQ_DHCP_VER=0 + else + # You have ODHCPD but use DNSMASQ for DHCPV4 + DNSMASQ_DHCP_VER=4 + fi + + elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then + # DHCP V4 and V6 in DNSMASQ + DNSMASQ_DHCP_VER=6 + else + DNSMASQ_DHCP_VER=4 + fi + + # Allow DHCP/DHCPv6 to be handled by ISC DHCPD + if [ -x /usr/sbin/dhcpd ] ; then + if [ -x /etc/init.d/dhcpd ] ; then + /etc/init.d/dhcpd enabled && DNSMASQ_DHCP_VER=0 + fi + if [ -x /etc/init.d/dhcpd6 -a "$DNSMASQ_DHCP_VER" -gt 0 ] ; then + /etc/init.d/dhcpd6 enabled && DNSMASQ_DHCP_VER=4 + fi + fi + + append_bool "$cfg" authoritative "--dhcp-authoritative" + append_bool "$cfg" nodaemon "--no-daemon" + append_bool "$cfg" domainneeded "--domain-needed" + append_bool "$cfg" filterwin2k "--filterwin2k" + append_bool "$cfg" nohosts "--no-hosts" + append_bool "$cfg" nonegcache "--no-negcache" + append_bool "$cfg" strictorder "--strict-order" + append_bool "$cfg" logqueries "--log-queries=extra" + append_bool "$cfg" noresolv "--no-resolv" + append_bool "$cfg" localise_queries "--localise-queries" + append_bool "$cfg" readethers "--read-ethers" + append_bool "$cfg" dbus "--enable-dbus" + append_bool "$cfg" expandhosts "--expand-hosts" + config_get tftp_root "$cfg" "tftp_root" + [ -n "$tftp_root" ] && mkdir -p "$tftp_root" && append_bool "$cfg" enable_tftp "--enable-tftp" + append_bool "$cfg" tftp_no_fail "--tftp-no-fail" + append_bool "$cfg" nonwildcard "--bind-dynamic" 1 + append_bool "$cfg" fqdn "--dhcp-fqdn" + append_bool "$cfg" proxydnssec "--proxy-dnssec" + append_bool "$cfg" localservice "--local-service" + append_bool "$cfg" logdhcp "--log-dhcp" + append_bool "$cfg" quietdhcp "--quiet-dhcp" + append_bool "$cfg" sequential_ip "--dhcp-sequential-ip" + append_bool "$cfg" allservers "--all-servers" + append_bool "$cfg" noping "--no-ping" + + append_parm "$cfg" logfacility "--log-facility" + + append_parm "$cfg" cachesize "--cache-size" + append_parm "$cfg" dnsforwardmax "--dns-forward-max" + append_parm "$cfg" port "--port" + append_parm "$cfg" ednspacket_max "--edns-packet-max" + append_parm "$cfg" dhcpleasemax "--dhcp-lease-max" + append_parm "$cfg" "queryport" "--query-port" + append_parm "$cfg" "minport" "--min-port" + append_parm "$cfg" "maxport" "--max-port" + append_parm "$cfg" "domain" "--domain" + append_parm "$cfg" "local" "--server" + config_list_foreach "$cfg" "listen_address" append_listenaddress + config_list_foreach "$cfg" "server" append_server + config_list_foreach "$cfg" "rev_server" append_rev_server + config_list_foreach "$cfg" "address" append_address + config_list_foreach "$cfg" "ipset" append_ipset + [ -n "$BOOT" ] || { + config_list_foreach "$cfg" "interface" append_interface + config_list_foreach "$cfg" "notinterface" append_notinterface + } + config_list_foreach "$cfg" "addnhosts" append_addnhosts + config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain + append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases" + append_parm "$cfg" "serversfile" "--servers-file" + append_parm "$cfg" "tftp_root" "--tftp-root" + append_parm "$cfg" "dhcp_boot" "--dhcp-boot" + append_parm "$cfg" "local_ttl" "--local-ttl" + append_parm "$cfg" "pxe_prompt" "--pxe-prompt" + config_list_foreach "$cfg" "pxe_service" append_pxe_service + config_get DOMAIN "$cfg" domain + + config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1 + config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1 + config_get ADD_LOCAL_FQDN "$cfg" add_local_fqdn "" + config_get ADD_WAN_FQDN "$cfg" add_wan_fqdn 0 + + if [ -z "$ADD_LOCAL_FQDN" ] ; then + # maintain support for previous UCI + ADD_LOCAL_FQDN="$ADD_LOCAL_HOSTNAME" + fi + + config_get_bool readethers "$cfg" readethers + [ "$readethers" = "1" -a \! -e "/etc/ethers" ] && touch /etc/ethers + + config_get user_dhcpscript $cfg dhcpscript + if has_handler || [ -n "$user_dhcpscript" ]; then + xappend "--dhcp-script=$DHCPSCRIPT" + fi + + config_get leasefile $cfg leasefile "/tmp/dhcp.leases" + [ -n "$leasefile" -a \! -e "$leasefile" ] && touch "$leasefile" + config_get_bool cachelocal "$cfg" cachelocal 1 + + config_get_bool noresolv "$cfg" noresolv 0 + if [ "$noresolv" != "1" ]; then + config_get resolvfile "$cfg" resolvfile "/tmp/resolv.conf.auto" + # So jail doesn't complain if file missing + [ -n "$resolvfile" -a \! -e "$resolvfile" ] && touch "$resolvfile" + fi + + [ -n "$resolvfile" ] && xappend "--resolv-file=$resolvfile" + + config_get hostsfile "$cfg" dhcphostsfile + [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile" + + local rebind + config_get_bool rebind "$cfg" rebind_protection 1 + [ $rebind -gt 0 ] && { + log_once \ + "DNS rebinding protection is active," \ + "will discard upstream RFC1918 responses!" + xappend "--stop-dns-rebind" + + local rebind_localhost + config_get_bool rebind_localhost "$cfg" rebind_localhost 0 + [ $rebind_localhost -gt 0 ] && { + log_once "Allowing 127.0.0.0/8 responses" + xappend "--rebind-localhost-ok" + } + + append_rebind_domain() { + log_once "Allowing RFC1918 responses for domain $1" + xappend "--rebind-domain-ok=$1" + } + + config_list_foreach "$cfg" rebind_domain append_rebind_domain + } + + config_get_bool dnssec "$cfg" dnssec 0 + [ "$dnssec" -gt 0 ] && { + xappend "--conf-file=$TRUSTANCHORSFILE" + xappend "--dnssec" + [ -x /etc/init.d/sysntpd ] && { + /etc/init.d/sysntpd enabled + [ "$?" -ne 0 -o "$(uci_get system.ntp.enabled)" = "1" ] && { + [ -f "$TIMEVALIDFILE" ] || xappend "--dnssec-no-timecheck" + } + } + append_bool "$cfg" dnsseccheckunsigned "--dnssec-check-unsigned" + } + + config_get addmac "$cfg" addmac 0 + [ "$addmac" != "0" ] && { + [ "$addmac" = "1" ] && addmac= + xappend "--add-mac${addmac:+="$addmac"}" + } + + dhcp_option_add "$cfg" "" 0 + dhcp_option_add "$cfg" "" 2 + + xappend "--dhcp-broadcast=tag:needs-broadcast" + + xappend "--addn-hosts=$(dirname $HOSTFILE)" + + config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d" + xappend "--conf-dir=$dnsmasqconfdir" + dnsmasqconfdir="${dnsmasqconfdir%%,*}" + [ ! -d "$dnsmasqconfdir" ] && mkdir -p $dnsmasqconfdir + xappend "--user=dnsmasq" + xappend "--group=dnsmasq" + echo >> $CONFIGFILE_TMP + + config_get_bool enable_tftp "$cfg" enable_tftp 0 + [ "$enable_tftp" -gt 0 ] && { + config_get tftp_root "$cfg" tftp_root + append EXTRA_MOUNT $tftp_root + } + + config_foreach filter_dnsmasq host dhcp_host_add "$cfg" + echo >> $CONFIGFILE_TMP + config_foreach filter_dnsmasq boot dhcp_boot_add "$cfg" + config_foreach filter_dnsmasq mac dhcp_mac_add "$cfg" + config_foreach filter_dnsmasq tag dhcp_tag_add "$cfg" + config_foreach filter_dnsmasq vendorclass dhcp_vendorclass_add "$cfg" + config_foreach filter_dnsmasq userclass dhcp_userclass_add "$cfg" + config_foreach filter_dnsmasq circuitid dhcp_circuitid_add "$cfg" + config_foreach filter_dnsmasq remoteid dhcp_remoteid_add "$cfg" + config_foreach filter_dnsmasq subscrid dhcp_subscrid_add "$cfg" + config_foreach filter_dnsmasq match dhcp_match_add "$cfg" + config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg" + config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg" + [ -n "$BOOT" ] || config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg" + + echo >> $CONFIGFILE_TMP + config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg" + config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg" + echo >> $CONFIGFILE_TMP + + config_get_bool boguspriv "$cfg" boguspriv 1 + [ "$boguspriv" -gt 0 ] && { + xappend "--bogus-priv" + [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE" + } + + if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then + # Enable RA feature for when/if it is constructed, + # and RA is selected per interface pool (RA, DHCP, or both), + # but no one (should) want RA broadcast in syslog + [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" + xappend "--enable-ra" + xappend "--quiet-ra" + append_bool "$cfg" quietdhcp "--quiet-dhcp6" + + elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then + [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" + fi + + + echo >> $CONFIGFILE_TMP + config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg" + echo >> $CONFIGFILE_TMP + + echo >> $CONFIGFILE_TMP + mv -f $CONFIGFILE_TMP $CONFIGFILE + mv -f $HOSTFILE_TMP $HOSTFILE + + [ "$resolvfile" = "/tmp/resolv.conf.auto" ] && { + rm -f /tmp/resolv.conf + [ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && { + echo "search $DOMAIN" >> /tmp/resolv.conf + } + DNS_SERVERS="$DNS_SERVERS 127.0.0.1" + for DNS_SERVER in $DNS_SERVERS ; do + echo "nameserver $DNS_SERVER" >> /tmp/resolv.conf + done + } + + procd_open_instance $cfg + procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid + procd_set_param file $CONFIGFILE + [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript" + procd_set_param respawn + + procd_add_jail dnsmasq ubus log + procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvfile $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT + procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile + + procd_close_instance +} + +dnsmasq_stop() +{ + local cfg="$1" resolvfile + + config_get resolvfile "$cfg" "resolvfile" + + #relink /tmp/resolve.conf only for main instance + [ "$resolvfile" = "/tmp/resolv.conf.auto" ] && { + [ -f /tmp/resolv.conf ] && { + rm -f /tmp/resolv.conf + ln -s "$resolvfile" /tmp/resolv.conf + } + } + + rm -f ${BASEDHCPSTAMPFILE}.${cfg}.*.dhcp +} + +add_interface_trigger() +{ + local interface ignore + + config_get interface "$1" interface + config_get_bool ignore "$1" ignore 0 + + [ -n "$interface" -a $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload +} + +service_triggers() +{ + procd_add_reload_trigger "dhcp" "system" + + config_load dhcp + config_foreach add_interface_trigger dhcp + config_foreach add_interface_trigger relay +} + +boot() +{ + BOOT=1 + start "$@" +} + +start_service() { + local instance="$1" + local instance_found=0 + + . /lib/functions/network.sh + + config_cb() { + local type="$1" + local name="$2" + if [ "$type" = "dnsmasq" ]; then + if [ -n "$instance" -a "$instance" = "$name" ]; then + instance_found=1 + fi + fi + } + + config_load dhcp + + if [ -n "$instance" ]; then + [ "$instance_found" -gt 0 ] || return + dnsmasq_start "$instance" + else + config_foreach dnsmasq_start dnsmasq + fi +} + +reload_service() { + rc_procd start_service "$@" + procd_send_signal dnsmasq "$@" +} + +stop_service() { + local instance="$1" + local instance_found=0 + + config_cb() { + local type="$1" + local name="$2" + if [ "$type" = "dnsmasq" ]; then + if [ -n "$instance" -a "$instance" = "$name" ]; then + instance_found=1 + fi + fi + } + + config_load dhcp + + if [ -n "$instance" ]; then + [ "$instance_found" -gt 0 ] || return + dnsmasq_stop "$instance" + else + config_foreach dnsmasq_stop dnsmasq + fi +} diff --git a/root/package/network/utils/iperf3/Makefile b/root/package/network/utils/iperf3/Makefile new file mode 100644 index 00000000..1a7f3c83 --- /dev/null +++ b/root/package/network/utils/iperf3/Makefile @@ -0,0 +1,84 @@ +# +# Copyright (C) 2007-2010 OpenWrt.org +# Copyright (C) 2019 Ycarus (Yannick Chabanois) +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=iperf +PKG_SOURCE_VERSION:=40e7c05440583f229edd6b6ca05c5d97b66fcf15 +PKG_VERSION:=3.6-$(PKG_SOURCE_VERSION) +PKG_RELEASE:=2 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/esnet/iperf.git + +PKG_MAINTAINER:=Yannick Chabanois +PKG_LICENSE:=BSD-3-Clause + +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +PKG_FIXUP:=autoreconf + +include $(INCLUDE_DIR)/package.mk + +DISABLE_NLS:= + +define Package/iperf3/default + SECTION:=net + CATEGORY:=Network + TITLE:=Internet Protocol bandwidth measuring tool + URL:=https://github.com/esnet/iperf +endef + +define Package/iperf3 +$(call Package/iperf3/default) + VARIANT:=nossl +endef + +define Package/iperf3-ssl +$(call Package/iperf3/default) + TITLE+= with iperf_auth support + VARIANT:=ssl + DEPENDS:= +libopenssl +endef + +TARGET_CFLAGS += -D_GNU_SOURCE +CONFIGURE_ARGS += --disable-shared + +ifeq ($(BUILD_VARIANT),ssl) + CONFIGURE_ARGS += --with-openssl="$(STAGING_DIR)/usr" +else + CONFIGURE_ARGS += --without-openssl +endif + +MAKE_FLAGS += noinst_PROGRAMS= + +define Package/iperf3/description + Iperf is a modern alternative for measuring TCP and UDP bandwidth + performance, allowing the tuning of various parameters and + characteristics. +endef + +# autoreconf fails if the README file isn't present +define Build/Prepare + $(call Build/Prepare/Default) + touch $(PKG_BUILD_DIR)/README +endef + +define Package/iperf3/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/iperf3 $(1)/usr/bin/ +endef + +define Package/iperf3-ssl/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/iperf3 $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,iperf3)) +$(eval $(call BuildPackage,iperf3-ssl)) diff --git a/root/package/system/fstools/patches/100-disable-lazy-init.patch b/root/package/system/fstools/patches/100-disable-lazy-init.patch new file mode 100644 index 00000000..c3092570 --- /dev/null +++ b/root/package/system/fstools/patches/100-disable-lazy-init.patch @@ -0,0 +1,13 @@ +diff --git a/libfstools/rootdisk.c b/libfstools/rootdisk.c +index dd00c1b..f3b87fc 100644 +--- a/libfstools/rootdisk.c ++++ b/libfstools/rootdisk.c +@@ -270,7 +270,7 @@ static int rootdisk_volume_init(struct volume *v) + if (rootdisk_use_f2fs(p)) + snprintf(str, sizeof(str), "mkfs.f2fs -q -l rootfs_data %s", v->blk); + else +- snprintf(str, sizeof(str), "mkfs.ext4 -q -L rootfs_data %s", v->blk); ++ snprintf(str, sizeof(str), "mkfs.ext4 -q -E lazy_itable_init=0,lazy_journal_init=0 -L rootfs_data %s", v->blk); + ret = system(str); + break; + default: diff --git a/root/package/utils/wmt/Makefile b/root/package/utils/wmt/Makefile new file mode 100644 index 00000000..dffd032e --- /dev/null +++ b/root/package/utils/wmt/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (C) 2009 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=wmt +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/abbradar/wmt +PKG_SOURCE_VERSION:=2127e23dd94df960b12f3ffff806bcf41ebbf4b8 +PKG_MAINTAINER:=Nikolay Amiantov + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Utilities + TITLE:=wmt utility for MT6625L + DEPENDS:=kmod-mt6625l-wlan-gen2 + MAINTAINER:=Jinkai li +endef + +define Package/$(PKG_NAME)/description + Utility for loading MT6625L firmware. +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/stp_uart_launcher $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/wmt_loader $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/wmt_loopback $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/system/etc/firmware + $(INSTALL_DATA) $(PKG_BUILD_DIR)/config/WMT_SOC.cfg $(1)/system/etc/firmware + $(INSTALL_DATA) $(PKG_BUILD_DIR)/config/WMT_SOC.cfg $(1)/system/etc/firmware/WMT.cfg + $(INSTALL_DIR) $(1)/etc/firmware + $(CP) -r $(PKG_BUILD_DIR)/firmware/* $(1)/etc/firmware/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/wmt.init $(1)/etc/init.d/wmt + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/wmt.defaults $(1)/etc/uci-defaults/8803-wmt +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/root/package/utils/wmt/files/wmt.defaults b/root/package/utils/wmt/files/wmt.defaults new file mode 100644 index 00000000..ff619a29 --- /dev/null +++ b/root/package/utils/wmt/files/wmt.defaults @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ -z "$(uci -q get ucitrack.@wmt[0])" ]; then + uci -q batch <<-EOF + set ucitrack.@wmt[-1]=wmt + set ucitrack.@wmt[-1].init=wmt + add_list ucitrack.@wireless[0].affects=wmt + commit ucitrack + EOF +fi +exit 0 diff --git a/root/package/utils/wmt/files/wmt.init b/root/package/utils/wmt/files/wmt.init new file mode 100644 index 00000000..bf4580e3 --- /dev/null +++ b/root/package/utils/wmt/files/wmt.init @@ -0,0 +1,119 @@ +#!/bin/sh /etc/rc.common + +START=69 + +check_mtk_device() { + config_get phy "$1" phy + [ "$phy" = "mtkp2p0" ] && { + [ "$(uci -q get wireless.$1.disabled)" = "1" ] || apmode="$1" + [ -z "$(uci -q get wireless.default_$1.ifname)" ] && { + uci -q batch <<-EOF + set wireless.default_$1.ifname=mtkap0 + set wireless.default_$1.bss_load_update_period=0 + rename wireless.$1=ap + rename wireless.default_$1=default_ap + set wireless.default_$1.device=ap + EOF + } + } + [ "$phy" = "mtkphy0" ] && { + [ "$(uci -q get wireless.$1.disabled)" = "1" ] || wlanmode="$1" + [ "$(uci -q get wireless.default_$1.mode)" = "ap" ] && { + uci -q batch <<-EOF + set wireless.default_$1.mode=sta + EOF + } + [ -z "$(uci -q get wireless.default_$1.ifname)" ] && { + uci -q batch <<-EOF + set wireless.default_$1.ifname=mtkwlan0 + set wireless.default_$1.bss_load_update_period=0 + rename wireless.$1=client + rename wireless.default_$1=default_client + set wireless.default_$1.device=client + EOF + } + } +} + +find_radio() { + config_load wireless + apmode="" + wlanmode="" + config_foreach check_mtk_device wifi-device + uci -q commit wireless +} + +start_ap() { + echo A > /dev/wmtWifi + # Those are recommended by vendor to avoid chip lockup. + tc qdisc add dev mtkap0 root handle 1: htb default 11 + tc class add dev mtkap0 parent 1:1 classid 1:2 htb rate 8Mbit ceil 4Mbit prio 2 + + find_radio + if [ -n "$apmode" ]; then + config_get_bool disabled "$apmode" disabled + [ "$disabled" = "1" ] || wifi up "$apmode" 2>/dev/null + fi +} + +start_wlan() { + echo 1 > /dev/wmtWifi + # Those are recommended by vendor to avoid chip lockup. + tc qdisc add dev mtkap0 root handle 1: htb default 11 + tc class add dev mtkap0 parent 1:1 classid 1:2 htb rate 8Mbit ceil 4Mbit prio 2 + + find_radio + if [ -n "$wlanmode" ]; then + config_get_bool disabled "$wlanmode" disabled + [ "$disabled" = "1" ] || wifi up "$wlanmode" 2>/dev/null + fi +} + +stop_apwlan() { + find_radio + [ -n "$apmode" ] && wifi down "$apmode" 2>/dev/null + [ -n "$wlanmode" ] && wifi down "$wlanmode" 2>/dev/null + echo 0 > /dev/wmtWifi + +} + +start() { + find_radio + + [ -c /dev/stpwmt ] || /usr/bin/wmt_loader 2>&1 + /usr/bin/stp_uart_launcher -p /etc/firmware 2>&1 | logger -t stp_uart_launcher & + echo "$!" > /var/run/stp_uart_launcher.pid + sleep 3 + if [ -c /dev/wmtWifi ]; then + [ -n "$apmode" ] && start_ap + [ -n "$wlanmode" ] && start_wlan + [ -z "$apmode" ] && [ -z "$wlanmode" ] && start_ap + return 0 + else + return 1 + fi +} + +stop() { + find_radio + + if [ -c /dev/wmtWifi ]; then + stop_apwlan + stp_pid="$(cat /var/run/stp_uart_launcher.pid 2>/dev/null)" + if [ -n "$stp_pid" ]; then + kill "$stp_pid" + rm /var/run/stp_uart_launcher.pid + fi + fi +} + +reload() { + find_radio + + if [ -c /dev/wmtWifi ]; then + stop_apwlan + [ -n "$apmode" ] && start_ap + [ -n "$wlanmode" ] && start_wlan + [ -z "$apmode" ] && [ -z "$wlanmode" ] && start_ap + fi +} diff --git a/root/target/linux/bcm27xx/bcm2708/config-4.14 b/root/target/linux/bcm27xx/bcm2708/config-4.14 new file mode 100644 index 00000000..9af3e766 --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2708/config-4.14 @@ -0,0 +1,431 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +# CONFIG_ARCH_WANTS_THP_SWAP is not set +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_ERRATA_411920=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_TIMER_SP804=y +CONFIG_ARM_UNWIND=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +# CONFIG_BCM2835_DEVGPIOMEM is not set +CONFIG_BCM2835_FAST_MEMCPY=y +CONFIG_BCM2835_MBOX=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_TIMER=y +CONFIG_BCM2835_VCHIQ=y +# CONFIG_BCM2835_VCHIQ_SUPPORT_MEMDUMP is not set +CONFIG_BCM2835_WDT=y +CONFIG_BCM_VCIO=y +CONFIG_BCM_VC_SM=y +CONFIG_BCM_VIDEOCORE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BUILD_BIN2C=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_ABRT_EV6=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V6=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PABRT_V6=y +CONFIG_CPU_PM=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V6=y +CONFIG_CPU_V6K=y +CONFIG_CRC16=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_UART_8250 is not set +# CONFIG_DEBUG_USER is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NOOP_OPS is not set +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +# CONFIG_DMA_VIRT_OPS is not set +CONFIG_DNOTIFY=y +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_VC4_HDMI_CEC is not set +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXPORTFS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA is not set +# CONFIG_FB_RPISENSE is not set +CONFIG_FIQ=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FPE_FASTFPE is not set +# CONFIG_FPE_NWFPE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FREEZER=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FUTEX_PI=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_GPIO_BCM_EXP is not set +# CONFIG_GPIO_BCM_VIRT is not set +CONFIG_GPIO_SYSFS=y +# CONFIG_GRO_CELLS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +# CONFIG_HAVE_ARCH_BITREVERSE is not set +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HW_CONSOLE=y +CONFIG_HZ_FIXED=0 +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOMMU_HELPER=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MDIO_BUS is not set +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_RPISENSE_CORE=y +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MTD is not set +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_KM=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_OABI_COMPAT=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PCI_DOMAINS_GENERIC is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_PWM_SYSFS=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +# CONFIG_RCU_NEED_SEGCBLIST is not set +# CONFIG_RCU_STALL_COMMON is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SCHED_INFO is not set +CONFIG_SCSI=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +# CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD is not set +# CONFIG_SND_BCM2708_SOC_RPI_CIRRUS is not set +CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=m +CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=m +CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=m +# CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC is not set +# CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD is not set +CONFIG_SND_SOC_ICS43432=y +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THIN_ARCHIVES=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TINY_SRCU=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_UID16 is not set +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +CONFIG_USB_LAN78XX=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +CONFIG_USE_OF=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VFP=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 diff --git a/root/target/linux/bcm27xx/bcm2709/config-4.14 b/root/target/linux/bcm27xx/bcm2709/config-4.14 new file mode 100644 index 00000000..083c4b94 --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2709/config-4.14 @@ -0,0 +1,472 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MMAP_RND_BITS_MAX=15 +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +# CONFIG_ARCH_WANTS_THP_SWAP is not set +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_TIMER_SP804=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +# CONFIG_BCM2835_DEVGPIOMEM is not set +CONFIG_BCM2835_MBOX=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_TIMER=y +CONFIG_BCM2835_VCHIQ=y +# CONFIG_BCM2835_VCHIQ_SUPPORT_MEMDUMP is not set +CONFIG_BCM2835_WDT=y +CONFIG_BCM_VCIO=y +CONFIG_BCM_VC_SM=y +CONFIG_BCM_VIDEOCORE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BUILD_BIN2C=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_UART_8250 is not set +# CONFIG_DEBUG_USER is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NOOP_OPS is not set +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +# CONFIG_DMA_VIRT_OPS is not set +CONFIG_DNOTIFY=y +# CONFIG_DRM_LIB_RANDOM is not set +CONFIG_DRM_PANEL_LVDS=n +CONFIG_DRM_PANEL_INNOLUX_P079ZCA=n +CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2=n +CONFIG_DRM_PANEL_SITRONIX_ST7789V=n +CONFIG_DRM_VC4_HDMI_CEC=n +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXPORTFS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA is not set +# CONFIG_FB_RPISENSE is not set +CONFIG_FIQ=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FPE_FASTFPE is not set +# CONFIG_FPE_NWFPE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FREEZER=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FUTEX_PI=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_ARIZONA=y +CONFIG_GPIO_BCM_EXP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GRO_CELLS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HW_CONSOLE=y +CONFIG_HZ_FIXED=0 +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOMMU_HELPER=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MDIO_BUS is not set +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_ARIZONA=y +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_RPISENSE_CORE is not set +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MTD is not set +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_OABI_COMPAT=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0x80000000 +# CONFIG_PCI_DOMAINS_GENERIC is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_PWM_SYSFS=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SCHED_INFO is not set +CONFIG_SCSI=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=n +CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=n +CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=n +CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=n +CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=n +CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=n +CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=n +# CONFIG_SND_SOC_ICS43432 is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +# CONFIG_TEE is not set +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THIN_ARCHIVES=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_UID16 is not set +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_LAN78XX=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +CONFIG_USE_OF=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VMSPLIT_2G=y +# CONFIG_VMSPLIT_3G is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 diff --git a/root/target/linux/bcm27xx/bcm2709/config-4.19 b/root/target/linux/bcm27xx/bcm2709/config-4.19 new file mode 100644 index 00000000..0dacdda4 --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2709/config-4.19 @@ -0,0 +1,568 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_ARCH_AXXIA is not set +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +# CONFIG_ARCH_BCM_HR2 is not set +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARGON_MEM=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_ERRATA_643719=y +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_LPAE=y +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_TIMER_SP804=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_AX88796B_PHY is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +CONFIG_BCM2835_DEVGPIOMEM=y +CONFIG_BCM2835_MBOX=y +CONFIG_BCM2835_POWER=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_TIMER=y +CONFIG_BCM2835_VCHIQ=y +CONFIG_BCM2835_VCHIQ_MMAL=y +CONFIG_BCM2835_WDT=y +CONFIG_BCM7XXX_PHY=y +CONFIG_BCMGENET=y +CONFIG_BCM_NET_PHYLIB=y +CONFIG_BCM_VCIO=y +CONFIG_BCM_VC_SM=y +CONFIG_BCM_VC_SM_CMA=y +CONFIG_BCM_VIDEOCORE=y +CONFIG_BLK_DEBUG_FS=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +# CONFIG_BLK_DEV_DM is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +CONFIG_BRCMSTB_THERMAL=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BROADCOM_PHY=y +CONFIG_BUILD_BIN2C=y +CONFIG_CACHE_L2X0=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=5 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_CRYPTO_CHACHA20=y +CONFIG_CRYPTO_CHACHA20_NEON=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32_ARM_CE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_GHASH_ARM_CE=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_CE=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256_ARM=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_SHA512_ARM=y +CONFIG_CRYPTO_SIMD=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_USER is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MPTCP_PM="fullmesh" +CONFIG_DEVMEM=y +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_RPISENSE is not set +CONFIG_FIQ=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FPE_FASTFPE is not set +# CONFIG_FPE_NWFPE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FREEZER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_RASPBERRYPI_EXP=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLBFS is not set +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_BCM2835=y +CONFIG_HW_RANDOM_IPROC_RNG200=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +# CONFIG_I2C_BCM2708 is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MD=y +CONFIG_MDIO_BCM_UNIMAC=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_RPISENSE_CORE is not set +CONFIG_MFD_STMPE=y +CONFIG_MFD_SYSCON=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_IPROC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_OABI_COMPAT=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_BRCMSTB=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +# CONFIG_PCI_V3_SEMI is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_PLUGIN_HOSTCC="g++" +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +# CONFIG_PWM_STMPE is not set +CONFIG_PWM_SYSFS=y +CONFIG_RAS=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +# CONFIG_RPIVID_MEM is not set +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SCSI=y +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_MQ_DEFAULT=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +# CONFIG_SPI_BCM2835AUX is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_SLAVE=y +# CONFIG_SPI_SLAVE_SYSTEM_CONTROL is not set +# CONFIG_SPI_SLAVE_TIME is not set +CONFIG_SRCU=y +CONFIG_STMPE_I2C=y +CONFIG_STMPE_SPI=y +CONFIG_STREAM_PARSER=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_TTY_PRINTK=y +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_UID16 is not set +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_PCI=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_LAN78XX=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VDSO=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 diff --git a/root/target/linux/bcm27xx/bcm2710/config-4.14 b/root/target/linux/bcm27xx/bcm2710/config-4.14 new file mode 100644 index 00000000..f9efa9fe --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2710/config-4.14 @@ -0,0 +1,492 @@ +CONFIG_64BIT=y +# CONFIG_AIO is not set +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set +# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +# CONFIG_ARCH_WANTS_THP_SWAP is not set +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_CONT_SHIFT=4 +# CONFIG_ARM64_CRYPTO is not set +CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_832075=y +CONFIG_ARM64_ERRATUM_843419=y +CONFIG_ARM64_ERRATUM_1024718=y +CONFIG_ARM64_HW_AFDBM=y +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_MODULE_CMODEL_LARGE=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PTDUMP_CORE is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_ARM64_SW_TTBR0_PAN is not set +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VHE=y +CONFIG_ARM64_SSBD=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_TIMER_SP804=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +# CONFIG_BCM2835_DEVGPIOMEM is not set +CONFIG_BCM2835_MBOX=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_VCHIQ=y +# CONFIG_BCM2835_VCHIQ_SUPPORT_MEMDUMP is not set +CONFIG_BCM2835_WDT=y +# CONFIG_BCM_FLEXRM_MBOX is not set +# CONFIG_BCM_VCIO is not set +# CONFIG_BCM_VC_SM is not set +CONFIG_BCM_VIDEOCORE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BUILD_BIN2C=y +CONFIG_CAVIUM_ERRATUM_22375=y +CONFIG_CAVIUM_ERRATUM_23154=y +CONFIG_CAVIUM_ERRATUM_27456=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_VERSATILE is not set +CONFIG_COMMON_CLK_XGENE=y +# CONFIG_COMPAT is not set +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPUFREQ_DT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CRC16=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEFAULT_DUMMY=y +CONFIG_DEFAULT_SCHEDULER=y +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NOOP_OPS is not set +CONFIG_DMA_OF=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +# CONFIG_DMA_VIRT_OPS is not set +CONFIG_DNOTIFY=y +# CONFIG_DRM_LIB_RANDOM is not set +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXPORTFS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA is not set +# CONFIG_FB_RPISENSE is not set +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FREEZER=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FUTEX_PI=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_BCM_EXP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GRO_CELLS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HOLES_IN_ZONE=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLBFS is not set +CONFIG_HW_CONSOLE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOMMU_HELPER=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_SYSCON=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_RELA=y +# CONFIG_MTD is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_IOPORT_MAP=y +CONFIG_NR_CPUS=4 +# CONFIG_NUMA is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_MDIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_PADATA=y +CONFIG_PARTITION_PERCPU=y +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_DOMAINS_GENERIC is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_PHY_XGENE is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_PWM_SYSFS=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SCHED_INFO is not set +CONFIG_SCSI=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THIN_ARCHIVES=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +CONFIG_USB_LAN78XX=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +CONFIG_VMAP_STACK=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_MFD_RPISENSE_CORE=n +CONFIG_DRM_PANEL_LVDS=n +CONFIG_DRM_PANEL_INNOLUX_P079ZCA=n +CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2=n +CONFIG_DRM_PANEL_SITRONIX_ST7789V=n +CONFIG_DRM_VC4_HDMI_CEC=n +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=n +CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=n +CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=n +CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=n +CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=n +CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=n +CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=n +CONFIG_SND_SOC_ICS43432=n diff --git a/root/target/linux/bcm27xx/bcm2710/config-4.19 b/root/target/linux/bcm27xx/bcm2710/config-4.19 new file mode 100644 index 00000000..f8592d40 --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2710/config-4.19 @@ -0,0 +1,545 @@ +CONFIG_64BIT=y +# CONFIG_AIO is not set +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_CONT_SHIFT=4 +# CONFIG_ARM64_CRYPTO is not set +CONFIG_ARM64_ERRATUM_1024718=y +CONFIG_ARM64_ERRATUM_1463225=y +CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_832075=y +CONFIG_ARM64_ERRATUM_843419=y +CONFIG_ARM64_HW_AFDBM=y +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_MODULE_PLTS=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +CONFIG_ARM64_PA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARM64_SVE=y +# CONFIG_ARM64_SW_TTBR0_PAN is not set +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VHE=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_TIMER_SP804=y +# CONFIG_AX88796B_PHY is not set +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +# CONFIG_BCM2835_DEVGPIOMEM is not set +CONFIG_BCM2835_MBOX=y +CONFIG_BCM2835_POWER=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_VCHIQ=y +CONFIG_BCM2835_VCHIQ_MMAL=y +CONFIG_BCM2835_WDT=y +# CONFIG_BCM_VCIO is not set +# CONFIG_BCM_VC_SM is not set +CONFIG_BCM_VIDEOCORE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BRCMSTB_THERMAL=y +CONFIG_BUILD_BIN2C=y +CONFIG_CAVIUM_ERRATUM_22375=y +CONFIG_CAVIUM_ERRATUM_23154=y +CONFIG_CAVIUM_ERRATUM_27456=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_XGENE=y +# CONFIG_COMPAT is not set +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPUFREQ_DT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CRC16=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEFAULT_MPTCP_PM="fullmesh" +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_DIRECT_OPS=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=m +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_RPISENSE is not set +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FREEZER=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_RASPBERRYPI_EXP=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HOLES_IN_ZONE=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLBFS is not set +CONFIG_HW_CONSOLE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MFD_RPISENSE_CORE is not set +CONFIG_MFD_SYSCON=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_RELA=y +# CONFIG_MTD is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_IOPORT_MAP=y +CONFIG_NR_CPUS=4 +# CONFIG_NUMA is not set +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_PADATA=y +CONFIG_PARTITION_PERCPU=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PLUGIN_HOSTCC="g++" +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RFS_ACCEL=y +# CONFIG_RPIVID_MEM is not set +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SCSI=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +# CONFIG_SENSORS_RASPBERRYPI_HWMON is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +# CONFIG_SND_AUDIOSENSE_PI is not set +# CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC is not set +# CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M is not set +# CONFIG_SND_RPI_SIMPLE_SOUNDCARD is not set +# CONFIG_SND_RPI_WM8804_SOUNDCARD is not set +# CONFIG_SND_SOC_AD193X_SPI is not set +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +CONFIG_STREAM_PARSER=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_LAN78XX=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +# CONFIG_VIDEO_CODEC_BCM2835 is not set +CONFIG_VMAP_STACK=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZONE_DMA32=y diff --git a/root/target/linux/bcm27xx/bcm2711/config-4.19 b/root/target/linux/bcm27xx/bcm2711/config-4.19 new file mode 100644 index 00000000..b1691271 --- /dev/null +++ b/root/target/linux/bcm27xx/bcm2711/config-4.19 @@ -0,0 +1,667 @@ +CONFIG_64BIT=y +# CONFIG_AIO is not set +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARGON_MEM=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_CONT_SHIFT=4 +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM64_ERRATUM_1024718=y +CONFIG_ARM64_ERRATUM_1463225=y +CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_832075=y +CONFIG_ARM64_ERRATUM_843419=y +CONFIG_ARM64_HW_AFDBM=y +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_MODULE_PLTS=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +CONFIG_ARM64_PA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARM64_SVE=y +# CONFIG_ARM64_SW_TTBR0_PAN is not set +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VHE=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_ARM_BCM2835_CPUFREQ=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_GIC_V3_ITS_PCI=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_LPAE=y +CONFIG_ARM_PSCI_FW=y +CONFIG_ARM_MODULE_PLTS=y +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ARM_TIMER_SP804=y +# CONFIG_AX88796B_PHY is not set +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BCM2708_VCMEM=y +CONFIG_BCM2835_DEVGPIOMEM=y +CONFIG_BCM2835_MBOX=y +CONFIG_BCM2835_POWER=y +# CONFIG_BCM2835_SMI is not set +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_VCHIQ=y +CONFIG_BCM2835_VCHIQ_MMAL=y +CONFIG_BCM2835_WDT=y +CONFIG_BCM7XXX_PHY=y +CONFIG_BCMGENET=y +CONFIG_BCM_NET_PHYLIB=y +CONFIG_BCM_VCIO=y +# CONFIG_BCM_VC_SM is not set +CONFIG_BCM_VC_SM_CMA=y +CONFIG_BCM_VIDEOCORE=y +CONFIG_BLK_DEBUG_FS=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +# CONFIG_BLK_DEV_DM is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BOUNCE=y +CONFIG_BRCMSTB_THERMAL=y +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BROADCOM_PHY=y +CONFIG_BUILD_BIN2C=y +CONFIG_CACHE_L2X0=y +CONFIG_CAVIUM_ERRATUM_22375=y +CONFIG_CAVIUM_ERRATUM_23154=y +CONFIG_CAVIUM_ERRATUM_27456=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=5 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_XGENE=y +CONFIG_COMPAT=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CP15_BARRIER_EMULATION=y +# CONFIG_CPUFREQ_DT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CRC16=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_BS=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CHACHA20=y +CONFIG_CRYPTO_CHACHA20_NEON=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32_ARM64_CE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA256_ARM64=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA3=y +CONFIG_CRYPTO_SHA3_ARM64=y +CONFIG_CRYPTO_SHA512_ARM64=y +CONFIG_CRYPTO_SHA512_ARM64_CE=y +CONFIG_CRYPTO_SIMD=y +CONFIG_CRYPTO_SM3=y +CONFIG_CRYPTO_SM3_ARM64_CE=y +CONFIG_CRYPTO_SM4=y +CONFIG_CRYPTO_SM4_ARM64_CE=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MPTCP_PM="fullmesh" +CONFIG_DEVMEM=y +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_DIRECT_OPS=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +# CONFIG_FB_RPISENSE is not set +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FREEZER=y +CONFIG_FIXED_PHY=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_RASPBERRYPI_EXP=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_BCM2835=y +CONFIG_HW_RANDOM_IPROC_RNG200=y +CONFIG_HOLES_IN_ZONE=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLBFS is not set +CONFIG_HW_CONSOLE=y +CONFIG_I2C=y +# CONFIG_I2C_BCM2708 is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOSCHED_CFQ=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MD=y +CONFIG_MDIO_BCM_UNIMAC=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_RPISENSE_CORE is not set +CONFIG_MFD_STMPE=y +CONFIG_MFD_SYSCON=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +# CONFIG_MMC_BCM2835 is not set +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_IPROC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MTD_BLOCK2MTD=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +# CONFIG_MTD_UBI_BLOCK is not set +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +# CONFIG_NUMA is not set +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PARTITION_PERCPU=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_BRCMSTB=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PLUGIN_HOSTCC="g++" +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +# CONFIG_PWM_STMPE is not set +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_RAS=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +CONFIG_RAW_DRIVER=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +# CONFIG_RPIVID_MEM is not set +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SCSI=y +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_SCSI_MQ_DEFAULT=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_BCM2835AUX=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SETEND_EMULATION=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +# CONFIG_SPI_BCM2835AUX is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_SLAVE=y +# CONFIG_SPI_SLAVE_SYSTEM_CONTROL is not set +# CONFIG_SPI_SLAVE_TIME is not set +CONFIG_SRCU=y +CONFIG_STMPE_I2C=y +CONFIG_STMPE_SPI=y +CONFIG_STREAM_PARSER=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATION=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TI_ST=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +# CONFIG_UBIFS_FS is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_LAN78XX=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_PCI=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +CONFIG_USB_USBNET=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_VMAP_STACK=y +CONFIG_VDSO=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZONE_DMA32=y diff --git a/root/target/linux/generic/config-4.14 b/root/target/linux/generic/config-4.14 new file mode 100644 index 00000000..37b428b6 --- /dev/null +++ b/root/target/linux/generic/config-4.14 @@ -0,0 +1,5797 @@ +# CONFIG_104_QUAD_8 is not set +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABP060MG is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_HAVE_ECC is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQTION is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_THP_SWAP is not set +# CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_ARM64_RELOC_TEST is not set +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KERNMEM_PERMS is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AXP20X_ADC is not set +# CONFIG_AXP20X_POWER is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_BQ27XXX_HDQ is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1721X is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +CONFIG_BPF=y +CONFIG_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_HI311X is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_MCBA_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_PEAK_PCIEFD is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_CPT is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CCS811 is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFQ_GROUP_IOSCHED is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_HUGETLB is not set +# CONFIG_CGROUP_NET_CLASSID is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_RDMA is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIO_DAC is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_HSDK is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +CONFIG_COMPACTION=y +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CRAMFS is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_AEAD is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DAX is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DELL_LAPTOP is not set +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DPOT_DAC is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set +# CONFIG_DRM_AMDGPU_SI is not set +# CONFIG_DRM_AMDGPU_USERPTR is not set +# CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_MM_SELFTEST is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I915 is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_RADEON_USERPTR is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_STM is not set +# CONFIG_DRM_SUN4I is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VIRTIO_GPU is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DWC_XLGMAC is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENIC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +CONFIG_EXPERT=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_INTEL_INT3496 is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FLEX is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TFT_AGM1264K_FL is not set +# CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set +# CONFIG_FB_TFT_HX8340BN is not set +# CONFIG_FB_TFT_HX8347D is not set +# CONFIG_FB_TFT_HX8353D is not set +# CONFIG_FB_TFT_HX8357D is not set +# CONFIG_FB_TFT_ILI9163 is not set +# CONFIG_FB_TFT_ILI9320 is not set +# CONFIG_FB_TFT_ILI9325 is not set +# CONFIG_FB_TFT_ILI9340 is not set +# CONFIG_FB_TFT_ILI9341 is not set +# CONFIG_FB_TFT_ILI9481 is not set +# CONFIG_FB_TFT_ILI9486 is not set +# CONFIG_FB_TFT_PCD8544 is not set +# CONFIG_FB_TFT_RA8875 is not set +# CONFIG_FB_TFT_S6D02A1 is not set +# CONFIG_FB_TFT_S6D1121 is not set +# CONFIG_FB_TFT_SH1106 is not set +# CONFIG_FB_TFT_SSD1289 is not set +# CONFIG_FB_TFT_SSD1305 is not set +# CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set +# CONFIG_FB_TFT_SSD1331 is not set +# CONFIG_FB_TFT_SSD1351 is not set +# CONFIG_FB_TFT_ST7735R is not set +# CONFIG_FB_TFT_ST7789V is not set +# CONFIG_FB_TFT_TINYLCD is not set +# CONFIG_FB_TFT_TLS8204 is not set +# CONFIG_FB_TFT_UC1611 is not set +# CONFIG_FB_TFT_UC1701 is not set +# CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORTIFY_SOURCE=y +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSI is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPIOLIB is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_XRA1403 is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y +# CONFIG_HAVE_ARCH_HASH is not set +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +# CONFIG_HAVE_ARCH_VMAP_STACK is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_CAT=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HINIC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_CAVIUM is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_TPM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HX711 is not set +# CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_S3C2410 is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IEEE802154_CA8210 is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_AXP20X_PEK is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_CHT_INT33FE is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +# CONFIG_KCOV is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STMPE is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LDISC_AUTOLOAD=y +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LMP91000 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_LTC2632 is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +# CONFIG_MAILBOX is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAX9611 is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_PM8XXX is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLXFW is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CAVIUM_THUNDERX is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_S3C is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MTD_VIRT_CONCAT is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MT7530 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IFE is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_NSH is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DEFAULT is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NFT_FIB_IPV4 is not set +# CONFIG_NFT_FIB_IPV6 is not set +# CONFIG_NFT_FIB_NETDEV is not set +# CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +CONFIG_NF_CONNTRACK_CUSTOM=2 +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set +# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TABLES is not set +# CONFIG_NF_TABLES_NETDEV is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_BCM_OCOTP is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OF_OVERLAY is not set +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +# CONFIG_OPTIMIZE_INLINING is not set +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC104 is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_ENDPOINT is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_SW_SWITCHTEC is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_XGENE is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_STATS is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_XGENE is not set +# CONFIG_PI433 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_SX150X is not set +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_TIMERS=y +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSAMPLE is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_KVM is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWRSEQ_EMMC=y +# CONFIG_PWRSEQ_SD8787 is not set +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCA7000_SPI is not set +# CONFIG_QCA7000_UART is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REFCOUNT_FULL is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VCTRL is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_REMOTEPROC is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_IMX7 is not set +# CONFIG_RESET_LANTIQ is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TEGRA_BPMP is not set +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_RMNET is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPR0521 is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SECCOMP is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_IR35221 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM25066 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2978 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC3815 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16064 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX20751 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX8688 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_PMBUS is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TPS40422 is not set +# CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_UCD9000 is not set +# CONFIG_SENSORS_UCD9200 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XGENE is not set +# CONFIG_SENSORS_ZL6100 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_DIO2125 is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_ICS43432 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SST is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_X86=y +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFTLOCKUP_DETECTOR is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_S3C64XX is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_EMBEDDED=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_ZSTD is not set +# CONFIG_SRAM is not set +# CONFIG_SRF04 is not set +# CONFIG_SRF08 is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKTRACE is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +# CONFIG_STRING_SELFTEST is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_SUN4I_GPADC is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BBR is not set +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEE is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_SORT is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_TLAN is not set +# CONFIG_TLS is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_88PM860X is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set +# CONFIG_TOUCHSCREEN_DA9034 is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_HP600 is not set +# CONFIG_TOUCHSCREEN_HP7XX is not set +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set +# CONFIG_TOUCHSCREEN_IPROC is not set +# CONFIG_TOUCHSCREEN_LPC32XX is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MC13783 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MIGOR is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MX25 is not set +# CONFIG_TOUCHSCREEN_MXS_LRADC is not set +# CONFIG_TOUCHSCREEN_PCAP is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_STMPE is not set +# CONFIG_TOUCHSCREEN_SUN4I is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TS4800 is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_E2I is not set +# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_EGALAX is not set +# CONFIG_TOUCHSCREEN_USB_ELO is not set +# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_JASTEC is not set +# CONFIG_TOUCHSCREEN_USB_NEXIO is not set +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM831X is not set +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9712 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_WM97XX_ATMEL is not set +# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_TYPEC_UCSI is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set +CONFIG_UBIFS_FS_FORMAT4=y +# CONFIG_UBIFS_FS_SECURITY is not set +# CONFIG_UBSAN is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_UNMAP_KERNEL_AT_EL0=y +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENTS is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MTU3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PCI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XHCI_TEGRA is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VDSO is not set +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV2640 is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV6650 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set +# CONFIG_VIRTIO_INPUT is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_VL6180 is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2405 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS2805 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_WDS is not set +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +# CONFIG_WL_MEDIATEK is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XEN is not set +CONFIG_XFRM=y +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_ZX_TDM is not set diff --git a/root/target/linux/generic/config-4.19 b/root/target/linux/generic/config-4.19 new file mode 100644 index 00000000..44f72f2c --- /dev/null +++ b/root/target/linux/generic/config-4.19 @@ -0,0 +1,6136 @@ +# CONFIG_104_QUAD_8 is not set +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABP060MG is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5272 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_HAVE_ECC is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQTION is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NPCM is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_THP_SWAP is not set +# CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set +# CONFIG_ARGON_MEM is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_RELOC_TEST is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KERNMEM_PERMS is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_PTDUMP_DEBUGFS is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +# CONFIG_ARM_SPE_PMU is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_ASIX_PHY is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_AXP20X_ADC is not set +# CONFIG_AXP20X_POWER is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_BQ27XXX_HDQ is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1721X is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_ELF_FDPIC is not set +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BME680 is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +CONFIG_BPF=y +# CONFIG_BPFILTER is not set +CONFIG_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_STREAM_PARSER=y +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_WILINK is not set +CONFIG_BUG=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set +CONFIG_BUILD_SALT="" +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_HI311X is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_MCBA_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_PEAK_PCIEFD is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_UCAN is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_CPT is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CAVIUM_PTP is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CCS811 is not set +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +CONFIG_CC_HAS_STACKPROTECTOR_NONE=y +CONFIG_CC_IS_GCC=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NET_CLASSID is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_RDMA is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHASH_STATS is not set +# CONFIG_CHASH_SELFTEST is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIO_DAC is not set +CONFIG_CLANG_VERSION=0 +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_HSDK is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +CONFIG_COMPACTION=y +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONFIG_KVM_AMD_SEV is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_ISOLATION is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CRAMFS is not set +CONFIG_CRAMFS_BLOCKDEV=y +# CONFIG_CRAMFS_MTD is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_AEAD is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CFB is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_HISI_SEC is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_SP_PSP is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_MORUS1280 is not set +# CONFIG_CRYPTO_MORUS1280_AVX2 is not set +# CONFIG_CRYPTO_MORUS1280_SSE2 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS640_SSE2 is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_SPECK is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DAX is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_DELL_LAPTOP is not set +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DPOT_DAC is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_I915 is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set +# CONFIG_DRM_AMDGPU_SI is not set +# CONFIG_DRM_AMDGPU_USERPTR is not set +# CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DP_CEC is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_RADEON_USERPTR is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_STM is not set +# CONFIG_DRM_SUN4I is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_VIRTIO_GPU is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_XEN is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DS4424 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DWC_XLGMAC is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENIC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_EROFS_FS is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +CONFIG_EXPERT=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_INTEL_INT3496 is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_FAILOVER is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +CONFIG_FAT_FS=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_FLEX is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TFT_AGM1264K_FL is not set +# CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set +# CONFIG_FB_TFT_HX8340BN is not set +# CONFIG_FB_TFT_HX8347D is not set +# CONFIG_FB_TFT_HX8353D is not set +# CONFIG_FB_TFT_HX8357D is not set +# CONFIG_FB_TFT_ILI9163 is not set +# CONFIG_FB_TFT_ILI9320 is not set +# CONFIG_FB_TFT_ILI9325 is not set +# CONFIG_FB_TFT_ILI9340 is not set +# CONFIG_FB_TFT_ILI9341 is not set +# CONFIG_FB_TFT_ILI9481 is not set +# CONFIG_FB_TFT_ILI9486 is not set +# CONFIG_FB_TFT_PCD8544 is not set +# CONFIG_FB_TFT_RA8875 is not set +# CONFIG_FB_TFT_S6D02A1 is not set +# CONFIG_FB_TFT_S6D1121 is not set +# CONFIG_FB_TFT_SH1106 is not set +# CONFIG_FB_TFT_SSD1289 is not set +# CONFIG_FB_TFT_SSD1305 is not set +# CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set +# CONFIG_FB_TFT_SSD1331 is not set +# CONFIG_FB_TFT_SSD1351 is not set +# CONFIG_FB_TFT_ST7735R is not set +# CONFIG_FB_TFT_ST7789V is not set +# CONFIG_FB_TFT_TINYLCD is not set +# CONFIG_FB_TFT_TLS8204 is not set +# CONFIG_FB_TFT_UC1611 is not set +# CONFIG_FB_TFT_UC1701 is not set +# CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORTIFY_SOURCE=y +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSI is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FTWDT010_WATCHDOG is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +CONFIG_GCC_VERSION=70400 +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GEMINI_ETHERNET is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GNSS is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_GPIOLIB is not set +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +# CONFIG_GPIO_104_DIO_48E is not set +# CONFIG_GPIO_104_IDIO_16 is not set +# CONFIG_GPIO_104_IDI_48 is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_XRA1403 is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_HARDEN_EL2_VECTORS=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y +# CONFIG_HAVE_ARCH_HASH is not set +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +# CONFIG_HAVE_ARCH_VMAP_STACK is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_CAT=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_BIGBEN_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GOOGLE_HAMMER is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEAM is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HINIC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_CAVIUM is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_TPM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HX711 is not set +# CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_S3C2410 is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICE is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IEEE802154_CA8210 is not set +# CONFIG_IEEE802154_HWSIM is not set +# CONFIG_IEEE802154_MCR20A is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_BUFFER_HW_CONSUMER is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_RESCALE is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_INDIRECT_PIO is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INPUT_AXP20X_PEK is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_CHT_INT33FE is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_VS is not set +# CONFIG_IP_VS_MH is not set +CONFIG_IP_VS_MH_TAB_INDEX=10 +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISL29501 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +# CONFIG_KCOV is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STMPE is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LAN743X is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_OTM3225A is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LDISC_AUTOLOAD=y +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LMP91000 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_LTC2632 is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LV0104CS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +# CONFIG_MAILBOX is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAX9611 is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_PM8XXX is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_MLXFW is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CAVIUM_THUNDERX is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CQHCI is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_OMAP is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_S3C is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSCC_OCELOT_SWITCH is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BCM2835_SMI is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NAND is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MTD_VIRT_CONCAT is not set +# CONFIG_MTK_MMC is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVSIM is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_LEGACY is not set +# CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MT7530 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_REALTEK_SMI is not set +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_IPT is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IFE is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_NSH is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DEFAULT is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ETF is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETERION=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_PACKET_ENGINES=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_CONNLIMIT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NFT_FIB_IPV4 is not set +# CONFIG_NFT_FIB_IPV6 is not set +# CONFIG_NFT_FIB_NETDEV is not set +# CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set +# CONFIG_NFT_OSF is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set +# CONFIG_NFT_SOCKET is not set +# CONFIG_NFT_TPROXY is not set +# CONFIG_NFT_TUNNEL is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_BRIDGE is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +CONFIG_NF_NAT_MASQUERADE_IPV4=y +CONFIG_NF_NAT_MASQUERADE_IPV6=y +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TABLES is not set +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_TABLES_NETDEV=y +# CONFIG_NF_TABLES_SET is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_BCM_OCOTP is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OF_OVERLAY is not set +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +# CONFIG_OPTIMIZE_INLINING is not set +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_XINO_AUTO=y +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC104 is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +# CONFIG_PCIE_CADENCE_HOST is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_ENDPOINT is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PF_STUB is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_SW_SWITCHTEC is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_XGENE is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_STATS is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_QCOM_USB_HS is not set +# CONFIG_PHY_QCOM_USB_HSIC is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_TUSB1210 is not set +# CONFIG_PHY_XGENE is not set +# CONFIG_PI433 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_SX150X is not set +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +CONFIG_PLUGIN_HOSTCC="" +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_TIMERS=y +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSAMPLE is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_KVM is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWRSEQ_EMMC=y +# CONFIG_PWRSEQ_SD8787 is not set +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCA7000_SPI is not set +# CONFIG_QCA7000_UART is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REFCOUNT_FULL is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VCTRL is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_REMOTEPROC is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_IMX7 is not set +# CONFIG_RESET_LANTIQ is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TEGRA_BPMP is not set +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD77402 is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_RMNET is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_RPR0521 is not set +# CONFIG_RSEQ is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RUNTIME_TESTING_MENU=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SD_ADC_MODULATOR is not set +# CONFIG_SECCOMP is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_IR35221 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM25066 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2978 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC3815 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16064 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX20751 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31785 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX8688 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_PMBUS is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TPS40422 is not set +# CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_UCD9000 is not set +# CONFIG_SENSORS_UCD9200 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XGENE is not set +# CONFIG_SENSORS_ZL6100 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_SIOX is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIMBUS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_MAX_CARDS=16 +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_AD193X_I2C is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_DIO2125 is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_I_SABRE_CODEC is not set +# CONFIG_SND_SOC_ICS43432 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_HASWELL is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SKYLAKE is not set +# CONFIG_SND_SOC_INTEL_SST is not set +CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MAX9867 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8782 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_X86=y +# CONFIG_SND_XEN_FRONTEND is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFTLOCKUP_DETECTOR is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUNDWIRE is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MEM is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_S3C64XX is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_EMBEDDED=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_SQUASHFS_LZ4=y +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_ZSTD is not set +# CONFIG_SRAM is not set +# CONFIG_SRF04 is not set +# CONFIG_SRF08 is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_STACKPROTECTOR_STRONG is not set +# CONFIG_STACKTRACE is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +# CONFIG_STRING_SELFTEST is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_SUN4I_GPADC is not set +# CONFIG_SUN50I_DE2_BUS is not set +# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BBR=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEE is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITFIELD is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_SORT is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_STATISTICS is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_TLAN is not set +# CONFIG_TLS is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_88PM860X is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADC is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_BU21029 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set +# CONFIG_TOUCHSCREEN_DA9034 is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_HIDEEP is not set +# CONFIG_TOUCHSCREEN_HP600 is not set +# CONFIG_TOUCHSCREEN_HP7XX is not set +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set +# CONFIG_TOUCHSCREEN_IPROC is not set +# CONFIG_TOUCHSCREEN_LPC32XX is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MC13783 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MIGOR is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MX25 is not set +# CONFIG_TOUCHSCREEN_MXS_LRADC is not set +# CONFIG_TOUCHSCREEN_PCAP is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_S6SY761 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_STMPE is not set +# CONFIG_TOUCHSCREEN_SUN4I is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TS4800 is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_E2I is not set +# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_EGALAX is not set +# CONFIG_TOUCHSCREEN_USB_ELO is not set +# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_JASTEC is not set +# CONFIG_TOUCHSCREEN_USB_NEXIO is not set +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM831X is not set +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9712 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPEC is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_TYPEC_UCSI is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set +CONFIG_UBIFS_FS_FORMAT4=y +# CONFIG_UBIFS_FS_SECURITY is not set +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBSAN is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_UNISYS_VISORBUS is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENTS is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_HAPS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_ULPI is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MTU3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PCI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_DBGCAP is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VBOXGUEST is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VDSO is not set +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_I2C is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9T112 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V111 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV2640 is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV6650 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV772X is not set +# CONFIG_VIDEO_OV7740 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_RJ54N1 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_TW9910 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_VL6180 is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +CONFIG_VMAP_STACK=y +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VSOCKETS_DIAG is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2405 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS2805 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_DS28E17 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_WDS is not set +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +# CONFIG_WL_MEDIATEK is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XDP_SOCKETS is not set +# CONFIG_XEN is not set +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +# CONFIG_XEN_PVCALLS_FRONTEND is not set +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XFRM=y +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_VCU is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZOPT2201 is not set +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_ZX_TDM is not set +CONFIG_TCP_CONG_LIA=y +CONFIG_TCP_CONG_OLIA=y +CONFIG_TCP_CONG_WVEGAS=y +CONFIG_TCP_CONG_BALIA=y +CONFIG_TCP_CONG_MCTCPDESYNC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_MPTCP=y +# CONFIG_DEFAULT_BALIA is not set +# CONFIG_DEFAULT_LIA is not set +# CONFIG_DEFAULT_OLIA is not set +# CONFIG_DEFAULT_WVEGAS is not set +# CONFIG_DEFAULT_BBR is not set +# CONFIG_DEFAULT_MCTCPDESYNC is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_MPTCP_PM="default" +CONFIG_DEFAULT_MPTCP_SCHED="default" +CONFIG_MPTCP_PM_ADVANCED=y +CONFIG_MPTCP_SCHED_ADVANCED=y +CONFIG_MPTCP_FULLMESH=y +CONFIG_MPTCP_NDIFFPORTS=y +CONFIG_MPTCP_BINDER=y +CONFIG_MPTCP_ROUNDROBIN=y +CONFIG_MPTCP_BLEST=y +CONFIG_MPTCP_REDUNDANT=y +CONFIG_MPTCP_NETLINK=y +CONFIG_MPTCP_ECF=y +CONFIG_DEFAULT_FULLMESH=y +CONFIG_DEFAULT_SCHEDULER=y +# CONFIG_DEFAULT_NDIFFPORTS is not set +# CONFIG_DEFAULT_NETLINK is not set +# CONFIG_DEFAULT_BINDER is not set +# CONFIG_DEFAULT_DUMMY is not set +# CONFIG_DEFAULT_ROUNDROBIN is not set +# CONFIG_DEFAULT_BLEST is not set +# CONFIG_DEFAULT_REDUNDANT is not set +CONFIG_NF_CONNTRACK_CUSTOM=2 \ No newline at end of file diff --git a/root/target/linux/generic/config-4.9 b/root/target/linux/generic/config-4.9 new file mode 100644 index 00000000..ceac7fac --- /dev/null +++ b/root/target/linux/generic/config-4.9 @@ -0,0 +1,5324 @@ +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KERNMEM_PERMS is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +CONFIG_BPF=y +# CONFIG_BPF_JIT is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIO_DAC is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_COMPACTION is not set +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CRAMFS is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_AEAD is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENIC is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +CONFIG_EXPERT=y +# CONFIG_EXPORTFS is not set +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPIOLIB is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y +# CONFIG_HAVE_ARCH_HASH is not set +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +# CONFIG_HAVE_ARCH_VMAP_STACK is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_CAT=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_TPM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HYPERV is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +# CONFIG_KCOV is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +# CONFIG_MAILBOX is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP_NETVF is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set +# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_TABLES is not set +# CONFIG_NF_TABLES_NETDEV is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OF_OVERLAY is not set +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWRSEQ_EMMC=y +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPR0521 is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SECCOMP is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XGENE is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SST is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SRAM is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKTRACE is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BBR=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TLAN is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_FT6236 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_ENUM_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBSAN is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENT is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VDSO is not set +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_INPUT is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +# CONFIG_WL_MEDIATEK is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XEN is not set +CONFIG_XFRM=y +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZSMALLOC is not set +CONFIG_TCP_CONG_LIA=y +CONFIG_TCP_CONG_OLIA=y +CONFIG_TCP_CONG_WVEGAS=y +CONFIG_TCP_CONG_BALIA=y +CONFIG_DEFAULT_TCP_CONG="olia" +CONFIG_MPTCP=y \ No newline at end of file diff --git a/root/target/linux/generic/config-5.4 b/root/target/linux/generic/config-5.4 new file mode 100644 index 00000000..3b71ac91 --- /dev/null +++ b/root/target/linux/generic/config-5.4 @@ -0,0 +1,6501 @@ +# CONFIG_104_QUAD_8 is not set +CONFIG_32BIT=y +CONFIG_64BIT_TIME=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABP060MG is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5272 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7124 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7606_IFACE_PARALLEL is not set +# CONFIG_AD7606_IFACE_SPI is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7768_1 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7949 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADF4371 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16460 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXL372_I2C is not set +# CONFIG_ADXL372_SPI is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_DEBUG_CURSOR is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AL_FIC is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_HAVE_ECC is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQTION is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_AXXIA is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MILBEAUT is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NPCM is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_RDA is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_THP_SWAP is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_ARM64_CRYPTO is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_MODULE_PLTS is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_RELOC_TEST is not set +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_VA_BITS_48 is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_814220 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +# CONFIG_ARM_ERRATA_857271 is not set +# CONFIG_ARM_ERRATA_857272 is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_PTDUMP_DEBUGFS is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SPE_PMU is not set +# CONFIG_ARM_THUMBEE is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_AXP20X_ADC is not set +# CONFIG_AXP20X_POWER is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_BQ27XXX_HDQ is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1721X is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_ELF_FDPIC is not set +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CGROUP_IOCOST is not set +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BME680 is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNX2X_SRIOV is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +CONFIG_BPF=y +# CONFIG_BPFILTER is not set +CONFIG_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +# CONFIG_BT_HCIBTUSB_MTK is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_MTKSDIO is not set +# CONFIG_BT_MTKUART is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set +CONFIG_BUILD_SALT="" +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_HI311X is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_J1939 is not set +# CONFIG_CAN_KVASER_PCIEFD is not set +# CONFIG_CAN_MCBA_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_PEAK_PCIEFD is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_UCAN is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_CPT is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CAVIUM_PTP is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CCS811 is not set +CONFIG_CC_CAN_LINK=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +CONFIG_CC_HAS_STACKPROTECTOR_NONE=y +CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_HUGETLB is not set +# CONFIG_CGROUP_NET_CLASSID is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_RDMA is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHASH_SELFTEST is not set +# CONFIG_CHASH_STATS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIO_DAC is not set +CONFIG_CLANG_VERSION=0 +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_HSDK is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +CONFIG_COMPACTION=y +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONFIG_KVM_AMD_SEV is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_COUNTER is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_ISOLATION is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CRAMFS is not set +CONFIG_CRAMFS_BLOCKDEV=y +# CONFIG_CRAMFS_MTD is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_AEAD is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CFB is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CHACHA20_NEON is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32_ARM_CE is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_HISI_SEC is not set +# CONFIG_CRYPTO_DEV_HISI_ZIP is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_SP_PSP is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_ESSIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_MORUS1280 is not set +# CONFIG_CRYPTO_MORUS1280_AVX2 is not set +# CONFIG_CRYPTO_MORUS1280_SSE2 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS640_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +# CONFIG_CRYPTO_SHA1_ARM_NEON is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA256_ARM is not set +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SHA512_ARM is not set +# CONFIG_CRYPTO_SIMD is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_SPECK is not set +# CONFIG_CRYPTO_STATS is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XXHASH is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DAX is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_BTF is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MISC is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_DELL_LAPTOP is not set +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +CONFIG_DMA_DECLARE_COHERENT=y +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_DMA_JZ4780 is not set +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DPOT_DAC is not set +# CONFIG_DPS310 is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set +# CONFIG_DRM_AMDGPU_SI is not set +# CONFIG_DRM_AMDGPU_USERPTR is not set +# CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_AMD_DC_DCN2_0 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DP_CEC is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I915 is not set +# CONFIG_DRM_KOMEDA is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MCDE is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set +# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set +# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TPG110 is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_RADEON_USERPTR is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_STM is not set +# CONFIG_DRM_SUN4I is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VIRTIO_GPU is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_XEN is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DS4424 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DWC_XLGMAC is not set +# CONFIG_DWMAC_DWC_QOS_ETH is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_EE1004 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENERGY_MODEL is not set +# CONFIG_ENIC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_EROFS_FS is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +# CONFIG_EXFAT_FS is not set +CONFIG_EXPERT=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_FSA9480 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_INTEL_INT3496 is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_PTN5150 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_FS_SECURITY is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_FAILOVER is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FLEX is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TFT_AGM1264K_FL is not set +# CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set +# CONFIG_FB_TFT_HX8340BN is not set +# CONFIG_FB_TFT_HX8347D is not set +# CONFIG_FB_TFT_HX8353D is not set +# CONFIG_FB_TFT_HX8357D is not set +# CONFIG_FB_TFT_ILI9163 is not set +# CONFIG_FB_TFT_ILI9320 is not set +# CONFIG_FB_TFT_ILI9325 is not set +# CONFIG_FB_TFT_ILI9340 is not set +# CONFIG_FB_TFT_ILI9341 is not set +# CONFIG_FB_TFT_ILI9481 is not set +# CONFIG_FB_TFT_ILI9486 is not set +# CONFIG_FB_TFT_PCD8544 is not set +# CONFIG_FB_TFT_RA8875 is not set +# CONFIG_FB_TFT_S6D02A1 is not set +# CONFIG_FB_TFT_S6D1121 is not set +# CONFIG_FB_TFT_SH1106 is not set +# CONFIG_FB_TFT_SSD1289 is not set +# CONFIG_FB_TFT_SSD1305 is not set +# CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set +# CONFIG_FB_TFT_SSD1331 is not set +# CONFIG_FB_TFT_SSD1351 is not set +# CONFIG_FB_TFT_ST7735R is not set +# CONFIG_FB_TFT_ST7789V is not set +# CONFIG_FB_TFT_TINYLCD is not set +# CONFIG_FB_TFT_TLS8204 is not set +# CONFIG_FB_TFT_UC1611 is not set +# CONFIG_FB_TFT_UC1701 is not set +# CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +# CONFIG_FIELDBUS_DEV is not set +CONFIG_FILE_LOCKING=y +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FONTS is not set +# CONFIG_FONT_TER16x32 is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORTIFY_SOURCE=y +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSI is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_QDMA is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FS_VERITY is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FTWDT010_WATCHDOG is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FXAS21002C is not set +# CONFIG_FXOS8700_I2C is not set +# CONFIG_FXOS8700_SPI is not set +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GEMINI_ETHERNET is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GNSS is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_GPIOLIB is not set +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +# CONFIG_GPIO_104_DIO_48E is not set +# CONFIG_GPIO_104_IDIO_16 is not set +# CONFIG_GPIO_104_IDI_48 is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_AMD_FCH is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SAMA5D2_PIOBU is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_XRA1403 is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_GVE is not set +# CONFIG_HABANA_AI is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_HARDEN_EL2_VECTORS=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y +# CONFIG_HAVE_ARCH_HASH is not set +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +# CONFIG_HAVE_ARCH_VMAP_STACK is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_CAT=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_HEADER_TEST is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_BIGBEN_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GOOGLE_HAMMER is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEAM is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HINIC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSA_AMD is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_CAVIUM is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_TPM=y +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HX711 is not set +# CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set +# CONFIG_HZ is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_JZ4780 is not set +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_S3C2410 is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I3C is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICE is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IEEE802154_CA8210 is not set +# CONFIG_IEEE802154_HWSIM is not set +# CONFIG_IEEE802154_MCR20A is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IGC is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_BUFFER_HW_CONSUMER is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_RESCALE is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IIO_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IKHEADERS is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_INDIRECT_PIO is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INGENIC_ADC is not set +# CONFIG_INGENIC_CGU_JZ4725B is not set +# CONFIG_INGENIC_CGU_JZ4740 is not set +# CONFIG_INGENIC_CGU_JZ4770 is not set +# CONFIG_INGENIC_CGU_JZ4780 is not set +# CONFIG_INGENIC_TCU_CLK is not set +# CONFIG_INGENIC_TCU_IRQ is not set +# CONFIG_INGENIC_TIMER is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +CONFIG_INIT_STACK_NONE=y +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_AXP20X_PEK is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_GPIO_VIBRA is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_CHT_INT33FE is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IO_URING is not set +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_VS is not set +# CONFIG_IP_VS_MH is not set +CONFIG_IP_VS_MH_TAB_INDEX=10 +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISL29501 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +CONFIG_KASAN_STACK=1 +# CONFIG_KCOV is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_APPLESPI is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1050 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STMPE is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LAN743X is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_OTM3225A is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LDISC_AUTOLOAD=y +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LMP91000 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_EVENT_COUNTS is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +# CONFIG_LTC1660 is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_LTC2632 is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LV0104CS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +# CONFIG_MAILBOX is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set +# CONFIG_MAX31856 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX44009 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5432 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAX9611 is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MB1232 is not set +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP3911 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP41010 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_AC100 is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77650 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_PM8XXX is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_FP_SUPPORT is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MISC_ALCOR_PCI is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_MLXFW is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CAVIUM_THUNDERX is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CQHCI is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_JZ4740 is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_AM654 is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ASPEED is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_OMAP is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_S3C is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_STM32_SDMMC is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MOXTET is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSCC_OCELOT_SWITCH is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_HYPERBUS is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_ECC_SW_BCH is not set +# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_MXIC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_PHYSMAP_GEMINI is not set +# CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PHYSMAP_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_RAW_NAND is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NAND is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MTD_VIRT_CONCAT is not set +# CONFIG_MTK_MMC is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVSIM is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_CT is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_MPLS is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_LANTIQ_GSWIP is not set +# CONFIG_NET_DSA_LEGACY is not set +# CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MT7530 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_REALTEK_SMI is not set +# CONFIG_NET_DSA_SJA1105 is not set +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_8021Q is not set +# CONFIG_NET_DSA_TAG_BRCM is not set +# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_DSA_TAG_GSWIP is not set +# CONFIG_NET_DSA_TAG_KSZ is not set +# CONFIG_NET_DSA_TAG_LAN9303 is not set +# CONFIG_NET_DSA_TAG_MTK is not set +# CONFIG_NET_DSA_TAG_QCA is not set +# CONFIG_NET_DSA_TAG_SJA1105 is not set +# CONFIG_NET_DSA_TAG_TRAILER is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_IPT is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IFE is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_NSH is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DEFAULT is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ETF is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TC_SKB_EXT is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_GOOGLE=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETERION=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_PACKET_ENGINES=y +CONFIG_NET_VENDOR_PENSANDO=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_CONNLIMIT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NFT_FIB_IPV4 is not set +# CONFIG_NFT_FIB_IPV6 is not set +# CONFIG_NFT_FIB_NETDEV is not set +# CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set +# CONFIG_NFT_OSF is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set +# CONFIG_NFT_SOCKET is not set +# CONFIG_NFT_SYNPROXY is not set +# CONFIG_NFT_TPROXY is not set +# CONFIG_NFT_TUNNEL is not set +# CONFIG_NFT_XFRM is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_BRIDGE is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +CONFIG_NF_NAT_MASQUERADE_IPV4=y +CONFIG_NF_NAT_MASQUERADE_IPV6=y +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TABLES is not set +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_TABLES_NETDEV=y +# CONFIG_NF_TABLES_SET is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +# CONFIG_NI_XGE_MANAGEMENT_ENET is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOA1305 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NULL_TTY is not set +# CONFIG_NUMA is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_BCM_OCOTP is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVMEM_REBOOT_MODE is not set +# CONFIG_NVMEM_SYSFS is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OF_OVERLAY is not set +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +CONFIG_OPTIMIZE_INLINING=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_XINO_AUTO=y +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PACKING is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC104 is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +# CONFIG_PCIE_BW is not set +# CONFIG_PCIE_CADENCE_HOST is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_ENDPOINT is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PF_STUB is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_SW_SWITCHTEC is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_V3_SEMI is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_STATS is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_CADENCE_DP is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_OCELOT_SERDES is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_QCOM_USB_HS is not set +# CONFIG_PHY_QCOM_USB_HSIC is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_TUSB1210 is not set +# CONFIG_PHY_XGENE is not set +# CONFIG_PI433 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_INGENIC is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +# CONFIG_PINCTRL_OCELOT is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_SX150X is not set +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +CONFIG_PLUGIN_HOSTCC="" +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMS7003 is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_TIMERS=y +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_POWER_SUPPLY_HWMON is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSAMPLE is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSI is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_KVM is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PVPANIC is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWRSEQ_EMMC=y +# CONFIG_PWRSEQ_SD8787 is not set +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCA7000_SPI is not set +# CONFIG_QCA7000_UART is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_ADC5 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID6_PQ_BENCHMARK is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RANDOMIZE_BASE is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_BOOST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_REFCOUNT_FULL is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_SLG51000 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VCTRL is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_REMOTEPROC is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_IMX7 is not set +# CONFIG_RESET_LANTIQ is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TEGRA_BPMP is not set +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD77402 is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_RMNET is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_RPR0521 is not set +# CONFIG_RSEQ is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_CADENCE is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SD3078 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RUNTIME_TESTING_MENU=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SD_ADC_MODULATOR is not set +# CONFIG_SECCOMP is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSIRION_SGP30 is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_INSPUR_IPSPS is not set +# CONFIG_SENSORS_IR35221 is not set +# CONFIG_SENSORS_IR38064 is not set +# CONFIG_SENSORS_IRPS5401 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_ISL68137 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM25066 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2978 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC3815 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LTQ_CPUTEMP is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16064 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX20751 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31785 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX8688 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_PMBUS is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_PXE1610 is not set +# CONFIG_SENSORS_RM3100_I2C is not set +# CONFIG_SENSORS_RM3100_SPI is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TPS40422 is not set +# CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_UCD9000 is not set +# CONFIG_SENSORS_UCD9200 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XGENE is not set +# CONFIG_SENSORS_ZL6100 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFI is not set +# CONFIG_SFP is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_SIOX is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIMBUS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_JZ4740_SOC_I2S is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_MAX_CARDS=16 +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AMD_ACP3x is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS35L36 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4341 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_CX2072X is not set +# CONFIG_SND_SOC_DIO2125 is not set +# CONFIG_SND_SOC_DMIC is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_AUDMIX is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_ICS43432 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMIX is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_APL is not set +# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CFL is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_CML_H is not set +# CONFIG_SND_SOC_INTEL_CML_LP is not set +# CONFIG_SND_SOC_INTEL_CNL is not set +# CONFIG_SND_SOC_INTEL_GLK is not set +# CONFIG_SND_SOC_INTEL_HASWELL is not set +# CONFIG_SND_SOC_INTEL_KBL is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SKYLAKE is not set +# CONFIG_SND_SOC_INTEL_SST is not set +CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y +# CONFIG_SND_SOC_JZ4725B_CODEC is not set +# CONFIG_SND_SOC_JZ4740_CODEC is not set +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MAX98088 is not set +# CONFIG_SND_SOC_MAX98357A is not set +# CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MAX9867 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT6358 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_MTK_BTCVSD is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8822 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3060_I2C is not set +# CONFIG_SND_SOC_PCM3060_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RK3328 is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SOF_TOPLEVEL is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_UDA1334 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8782 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set +# CONFIG_SND_SOC_XILINX_I2S is not set +# CONFIG_SND_SOC_XILINX_SPDIF is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_X86=y +# CONFIG_SND_XEN_FRONTEND is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFTLOCKUP_DETECTOR is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUNDWIRE is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MEM is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_MTK_QUADSPI is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_QCOM_QSPI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_S3C64XX is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +# CONFIG_SPS30 is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_EMBEDDED=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_ZSTD is not set +# CONFIG_SRAM is not set +# CONFIG_SRF04 is not set +# CONFIG_SRF08 is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_STACKPROTECTOR_STRONG is not set +# CONFIG_STACKTRACE is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +# CONFIG_STRING_SELFTEST is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_SUN4I_GPADC is not set +# CONFIG_SUN50I_DE2_BUS is not set +# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_MDIO_DRIVER is not set +# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_FTPM_TEE is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BBR is not set +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEE is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITFIELD is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_SORT is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_XARRAY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_MMIO is not set +# CONFIG_THERMAL_STATISTICS is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUMB2_KERNEL is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_MI0283QT is not set +# CONFIG_TINYDRM_REPAPER is not set +# CONFIG_TINYDRM_ST7586 is not set +# CONFIG_TINYDRM_ST7735R is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS124S08 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8344 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPSW_PHY_SEL is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAC7612 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_TLAN is not set +# CONFIG_TLS is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_88PM860X is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADC is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_BU21029 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set +# CONFIG_TOUCHSCREEN_DA9034 is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_HIDEEP is not set +# CONFIG_TOUCHSCREEN_HP600 is not set +# CONFIG_TOUCHSCREEN_HP7XX is not set +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set +# CONFIG_TOUCHSCREEN_IPROC is not set +# CONFIG_TOUCHSCREEN_IQS5XX is not set +# CONFIG_TOUCHSCREEN_LPC32XX is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MC13783 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MIGOR is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MX25 is not set +# CONFIG_TOUCHSCREEN_MXS_LRADC is not set +# CONFIG_TOUCHSCREEN_PCAP is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_S6SY761 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_STMPE is not set +# CONFIG_TOUCHSCREEN_SUN4I is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TS4800 is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_E2I is not set +# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_EGALAX is not set +# CONFIG_TOUCHSCREEN_USB_ELO is not set +# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_JASTEC is not set +# CONFIG_TOUCHSCREEN_USB_NEXIO is not set +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM831X is not set +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9712 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_FOUNDATIONS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPEC is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_TYPEC_UCSI is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBIFS_FS_AUTHENTICATION is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set +CONFIG_UBIFS_FS_FORMAT4=y +# CONFIG_UBIFS_FS_SECURITY is not set +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBSAN is not set +CONFIG_UBSAN_ALIGNMENT=y +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDMABUF is not set +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_UNICODE is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_UNISYS_VISORBUS is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +CONFIG_UNIX_SCM=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UNWINDER_FRAME_POINTER is not set +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENTS is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CONN_GPIO is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_HAPS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_ULPI is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MTU3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PCI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_DBGCAP is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XHCI_MVEBU is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VALIDATE_FS_PARSER is not set +# CONFIG_VBOXGUEST is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VCNL4035 is not set +# CONFIG_VDSO is not set +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_ASPEED is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_I2C is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9T112 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V111 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV2640 is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV6650 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV772X is not set +# CONFIG_VIDEO_OV7740 is not set +# CONFIG_VIDEO_OV9640 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_RJ54N1 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_TW9910 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set +# CONFIG_VIRTIO_FS is not set +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_VL53L0X_I2C is not set +# CONFIG_VL6180 is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VSOCKETS_DIAG is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_MASTER_SGI is not set +# CONFIG_W1_SLAVE_DS2405 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS250X is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS2805 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_DS28E17 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_WDS is not set +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XDP_SOCKETS is not set +# CONFIG_XEN is not set +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +# CONFIG_XEN_PVCALLS_FRONTEND is not set +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XFRM=y +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_XILINX_VCU is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_XADC is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZOPT2201 is not set +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_ZX_TDM is not set +CONFIG_TCP_CONG_LIA=y +CONFIG_TCP_CONG_OLIA=y +CONFIG_TCP_CONG_WVEGAS=y +CONFIG_TCP_CONG_BALIA=y +CONFIG_TCP_CONG_MCTCPDESYNC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_MPTCP=y +# CONFIG_DEFAULT_BALIA is not set +# CONFIG_DEFAULT_LIA is not set +# CONFIG_DEFAULT_OLIA is not set +# CONFIG_DEFAULT_WVEGAS is not set +# CONFIG_DEFAULT_BBR is not set +# CONFIG_DEFAULT_MCTCPDESYNC is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_MPTCP_PM="default" +CONFIG_DEFAULT_MPTCP_SCHED="default" +CONFIG_MPTCP_PM_ADVANCED=y +CONFIG_MPTCP_SCHED_ADVANCED=y +CONFIG_MPTCP_FULLMESH=y +CONFIG_MPTCP_NDIFFPORTS=y +CONFIG_MPTCP_BINDER=y +CONFIG_MPTCP_ROUNDROBIN=y +CONFIG_MPTCP_BLEST=y +CONFIG_MPTCP_REDUNDANT=y +CONFIG_MPTCP_NETLINK=y +CONFIG_MPTCP_ECF=y +CONFIG_DEFAULT_FULLMESH=y +CONFIG_DEFAULT_SCHEDULER=y +# CONFIG_DEFAULT_NDIFFPORTS is not set +# CONFIG_DEFAULT_NETLINK is not set +# CONFIG_DEFAULT_BINDER is not set +# CONFIG_DEFAULT_DUMMY is not set +# CONFIG_DEFAULT_ROUNDROBIN is not set +# CONFIG_DEFAULT_BLEST is not set +# CONFIG_DEFAULT_REDUNDANT is not set +CONFIG_NF_CONNTRACK_CUSTOM=2 +CONFIG_CRYPTO_SHA256=y \ No newline at end of file diff --git a/root/target/linux/generic/hack-4.14/690-mptcp_v0.94.patch b/root/target/linux/generic/hack-4.14/690-mptcp_v0.94.patch new file mode 100644 index 00000000..1df18b04 --- /dev/null +++ b/root/target/linux/generic/hack-4.14/690-mptcp_v0.94.patch @@ -0,0 +1,20725 @@ +diff -aurN linux-4.14.174/Documentation/networking/ip-sysctl.txt mptcp-mptcp_v0.94/Documentation/networking/ip-sysctl.txt +--- linux-4.14.174/Documentation/networking/ip-sysctl.txt 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/Documentation/networking/ip-sysctl.txt 2020-03-23 09:45:33.000000000 +0100 +@@ -734,6 +734,18 @@ + in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) + Default: 100 + ++MPTCP variables: ++ ++mptcp_enabled - INTEGER ++ Enable or disable Multipath TCP for new connections. ++ Possible values are: ++ ++ 0: Multipath TCP is disabled on all TCP-sockets that are newly created. ++ 1: Multipath TCP is enabled by default on all new TCP-sockets. Note that ++ existing sockets in LISTEN-state will still use regular TCP. ++ 2: Enables Multipath TCP only upon the request of the application ++ throught the socket-option MPTCP_ENABLED. ++ + UDP variables: + + udp_l3mdev_accept - BOOLEAN +diff -aurN linux-4.14.174/drivers/infiniband/hw/cxgb4/cm.c mptcp-mptcp_v0.94/drivers/infiniband/hw/cxgb4/cm.c +--- linux-4.14.174/drivers/infiniband/hw/cxgb4/cm.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/drivers/infiniband/hw/cxgb4/cm.c 2020-03-23 09:45:33.000000000 +0100 +@@ -3757,7 +3757,7 @@ + */ + memset(&tmp_opt, 0, sizeof(tmp_opt)); + tcp_clear_options(&tmp_opt); +- tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(&init_net, skb, &tmp_opt, NULL, 0, NULL, NULL); + + req = __skb_push(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); +diff -aurN linux-4.14.174/include/linux/skbuff.h mptcp-mptcp_v0.94/include/linux/skbuff.h +--- linux-4.14.174/include/linux/skbuff.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/linux/skbuff.h 2020-03-23 09:45:33.000000000 +0100 +@@ -690,7 +690,7 @@ + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ +- char cb[48] __aligned(8); ++ char cb[80] __aligned(8); + + unsigned long _skb_refdst; + void (*destructor)(struct sk_buff *skb); +diff -aurN linux-4.14.174/include/linux/tcp.h mptcp-mptcp_v0.94/include/linux/tcp.h +--- linux-4.14.174/include/linux/tcp.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/linux/tcp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -58,7 +58,7 @@ + /* TCP Fast Open */ + #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ + #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ +-#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ ++#define TCP_FASTOPEN_COOKIE_SIZE 4 /* the size employed by this impl. */ + + /* TCP Fast Open Cookie as stored in memory */ + struct tcp_fastopen_cookie { +@@ -83,6 +83,56 @@ + u32 end_seq; + }; + ++struct tcp_out_options { ++ u16 options; /* bit field of OPTION_* */ ++ u8 ws; /* window scale, 0 to disable */ ++ u8 num_sack_blocks;/* number of SACK blocks to include */ ++ u8 hash_size; /* bytes in hash_location */ ++ u16 mss; /* 0 to disable */ ++ __u8 *hash_location; /* temporary pointer, overloaded */ ++ __u32 tsval, tsecr; /* need to include OPTION_TS */ ++ struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ ++#ifdef CONFIG_MPTCP ++ u16 mptcp_options; /* bit field of MPTCP related OPTION_* */ ++ u8 dss_csum:1, /* dss-checksum required? */ ++ add_addr_v4:1, ++ add_addr_v6:1, ++ mptcp_ver:4; ++ ++ union { ++ struct { ++ __u64 sender_key; /* sender's key for mptcp */ ++ __u64 receiver_key; /* receiver's key for mptcp */ ++ } mp_capable; ++ ++ struct { ++ __u64 sender_truncated_mac; ++ __u32 sender_nonce; ++ /* random number of the sender */ ++ __u32 token; /* token for mptcp */ ++ u8 low_prio:1; ++ } mp_join_syns; ++ }; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr4; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in6_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr6; ++ ++ u16 remove_addrs; /* list of address id */ ++ u8 addr_id; /* address id (mp_join or add_address) */ ++#endif /* CONFIG_MPTCP */ ++}; ++ + /*These are used to set the sack_ok field in struct tcp_options_received */ + #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ + #define TCP_FACK_ENABLED (1 << 1) /*1 = FACK is enabled locally*/ +@@ -106,6 +156,9 @@ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + }; + ++struct mptcp_cb; ++struct mptcp_tcp_sock; ++ + static inline void tcp_clear_options(struct tcp_options_received *rx_opt) + { + rx_opt->tstamp_ok = rx_opt->sack_ok = 0; +@@ -141,6 +194,8 @@ + return (struct tcp_request_sock *)req; + } + ++struct tcp_md5sig_key; ++ + struct tcp_sock { + /* inet_connection_sock has to be the first member of tcp_sock */ + struct inet_connection_sock inet_conn; +@@ -363,6 +418,44 @@ + */ + struct request_sock *fastopen_rsk; + u32 *saved_syn; ++ ++ /* MPTCP/TCP-specific callbacks */ ++ const struct tcp_sock_ops *ops; ++ ++ struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ /* We keep these flags even if CONFIG_MPTCP is not checked, because ++ * it allows checking MPTCP capability just by checking the mpc flag, ++ * rather than adding ifdefs everywhere. ++ */ ++ u32 mpc:1, /* Other end is multipath capable */ ++ inside_tk_table:1, /* Is the tcp_sock inside the token-table? */ ++ send_mp_fclose:1, ++ request_mptcp:1, /* Did we send out an MP_CAPABLE? ++ * (this speeds up mptcp_doit() in tcp_recvmsg) ++ */ ++ pf:1, /* Potentially Failed state: when this flag is set, we ++ * stop using the subflow ++ */ ++ mp_killed:1, /* Killed with a tcp_done in mptcp? */ ++ is_master_sk:1, ++ close_it:1, /* Must close socket in mptcp_data_ready? */ ++ closing:1, ++ mptcp_ver:4, ++ mptcp_sched_setsockopt:1, ++ mptcp_pm_setsockopt:1, ++ record_master_info:1, ++ tcp_disconnect:1; ++ struct mptcp_tcp_sock *mptcp; ++#ifdef CONFIG_MPTCP ++#define MPTCP_SCHED_NAME_MAX 16 ++#define MPTCP_PM_NAME_MAX 16 ++ struct hlist_nulls_node tk_table; ++ u32 mptcp_loc_token; ++ u64 mptcp_loc_key; ++ char mptcp_sched_name[MPTCP_SCHED_NAME_MAX]; ++ char mptcp_pm_name[MPTCP_PM_NAME_MAX]; ++#endif /* CONFIG_MPTCP */ + }; + + enum tsq_enum { +@@ -374,6 +467,8 @@ + TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call + * tcp_v{4|6}_mtu_reduced() + */ ++ MPTCP_PATH_MANAGER_DEFERRED, /* MPTCP deferred creation of new subflows */ ++ MPTCP_SUB_DEFERRED, /* A subflow got deferred - process them */ + }; + + enum tsq_flags { +@@ -383,6 +478,8 @@ + TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED), + TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED), + TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED), ++ TCPF_PATH_MANAGER_DEFERRED = (1UL << MPTCP_PATH_MANAGER_DEFERRED), ++ TCPF_SUB_DEFERRED = (1UL << MPTCP_SUB_DEFERRED), + }; + + static inline struct tcp_sock *tcp_sk(const struct sock *sk) +@@ -405,6 +502,7 @@ + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *tw_md5_key; + #endif ++ struct mptcp_tw *mptcp_tw; + }; + + static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) +diff -aurN linux-4.14.174/include/net/inet_common.h mptcp-mptcp_v0.94/include/net/inet_common.h +--- linux-4.14.174/include/net/inet_common.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/inet_common.h 2020-03-23 09:45:33.000000000 +0100 +@@ -2,6 +2,8 @@ + #ifndef _INET_COMMON_H + #define _INET_COMMON_H + ++#include ++ + extern const struct proto_ops inet_stream_ops; + extern const struct proto_ops inet_dgram_ops; + +@@ -14,6 +16,8 @@ + struct sockaddr; + struct socket; + ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern); ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern); + int inet_release(struct socket *sock); + int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags); +diff -aurN linux-4.14.174/include/net/inet_connection_sock.h mptcp-mptcp_v0.94/include/net/inet_connection_sock.h +--- linux-4.14.174/include/net/inet_connection_sock.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/inet_connection_sock.h 2020-03-23 09:45:33.000000000 +0100 +@@ -30,6 +30,7 @@ + + struct inet_bind_bucket; + struct tcp_congestion_ops; ++struct tcp_options_received; + + /* + * Pointers to address related TCP functions +diff -aurN linux-4.14.174/include/net/inet_sock.h mptcp-mptcp_v0.94/include/net/inet_sock.h +--- linux-4.14.174/include/net/inet_sock.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/inet_sock.h 2020-03-23 09:45:33.000000000 +0100 +@@ -90,7 +90,9 @@ + wscale_ok : 1, + ecn_ok : 1, + acked : 1, +- no_srccheck: 1; ++ no_srccheck: 1, ++ mptcp_rqsk : 1, ++ saw_mpc : 1; + u32 ir_mark; + union { + struct ip_options_rcu __rcu *ireq_opt; +diff -aurN linux-4.14.174/include/net/mptcp.h mptcp-mptcp_v0.94/include/net/mptcp.h +--- linux-4.14.174/include/net/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/mptcp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,1529 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_H ++#define _MPTCP_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ #define ntohll(x) be64_to_cpu(x) ++ #define htonll(x) cpu_to_be64(x) ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ #define ntohll(x) (x) ++ #define htonll(x) (x) ++#endif ++ ++struct mptcp_loc4 { ++ u8 loc4_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in_addr addr; ++}; ++ ++struct mptcp_rem4 { ++ u8 rem4_id; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct mptcp_loc6 { ++ u8 loc6_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_rem6 { ++ u8 rem6_id; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_request_sock { ++ struct tcp_request_sock req; ++ struct hlist_nulls_node hash_entry; ++ ++ union { ++ struct { ++ /* Only on initial subflows */ ++ u64 mptcp_loc_key; ++ u64 mptcp_rem_key; ++ u32 mptcp_loc_token; ++ }; ++ ++ struct { ++ /* Only on additional subflows */ ++ u32 mptcp_rem_nonce; ++ u32 mptcp_loc_nonce; ++ u64 mptcp_hash_tmac; ++ }; ++ }; ++ ++ u8 loc_id; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 dss_csum:1, ++ is_sub:1, /* Is this a new subflow? */ ++ low_prio:1, /* Interface set to low-prio? */ ++ rcv_low_prio:1, ++ mptcp_ver:4; ++}; ++ ++struct mptcp_options_received { ++ u16 saw_mpc:1, ++ dss_csum:1, ++ drop_me:1, ++ ++ is_mp_join:1, ++ join_ack:1, ++ ++ saw_low_prio:2, /* 0x1 - low-prio set for this subflow ++ * 0x2 - low-prio set for another subflow ++ */ ++ low_prio:1, ++ ++ saw_add_addr:2, /* Saw at least one add_addr option: ++ * 0x1: IPv4 - 0x2: IPv6 ++ */ ++ more_add_addr:1, /* Saw one more add-addr. */ ++ ++ saw_rem_addr:1, /* Saw at least one rem_addr option */ ++ more_rem_addr:1, /* Saw one more rem-addr. */ ++ ++ mp_fail:1, ++ mp_fclose:1; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 prio_addr_id; /* Address-id in the MP_PRIO */ ++ ++ const unsigned char *add_addr_ptr; /* Pointer to add-address option */ ++ const unsigned char *rem_addr_ptr; /* Pointer to rem-address option */ ++ ++ u32 data_ack; ++ u32 data_seq; ++ u16 data_len; ++ ++ u8 mptcp_ver; /* MPTCP version */ ++ ++ /* Key inside the option (from mp_capable or fast_close) */ ++ u64 mptcp_sender_key; ++ u64 mptcp_receiver_key; ++ ++ u32 mptcp_rem_token; /* Remote token */ ++ ++ u32 mptcp_recv_nonce; ++ u64 mptcp_recv_tmac; ++ u8 mptcp_recv_mac[20]; ++}; ++ ++struct mptcp_tcp_sock { ++ struct tcp_sock *next; /* Next subflow socket */ ++ struct hlist_node cb_list; ++ struct mptcp_options_received rx_opt; ++ ++ /* Those three fields record the current mapping */ ++ u64 map_data_seq; ++ u32 map_subseq; ++ u16 map_data_len; ++ u16 slave_sk:1, ++ fully_established:1, ++ establish_increased:1, ++ second_packet:1, ++ attached:1, ++ send_mp_fail:1, ++ include_mpc:1, ++ mapping_present:1, ++ map_data_fin:1, ++ low_prio:1, /* use this socket as backup */ ++ rcv_low_prio:1, /* Peer sent low-prio option to us */ ++ send_mp_prio:1, /* Trigger to send mp_prio on this socket */ ++ pre_established:1; /* State between sending 3rd ACK and ++ * receiving the fourth ack of new subflows. ++ */ ++ ++ /* isn: needed to translate abs to relative subflow seqnums */ ++ u32 snt_isn; ++ u32 rcv_isn; ++ u8 path_index; ++ u8 loc_id; ++ u8 rem_id; ++ ++#define MPTCP_SCHED_SIZE 16 ++ u8 mptcp_sched[MPTCP_SCHED_SIZE] __aligned(8); ++ ++ int init_rcv_wnd; ++ u32 infinite_cutoff_seq; ++ struct delayed_work work; ++ u32 mptcp_loc_nonce; ++ struct tcp_sock *tp; /* Where is my daddy? */ ++ u32 last_end_data_seq; ++ ++ /* MP_JOIN subflow: timer for retransmitting the 3rd ack */ ++ struct timer_list mptcp_ack_timer; ++ ++ /* HMAC of the third ack */ ++ char sender_mac[20]; ++}; ++ ++struct mptcp_tw { ++ struct list_head list; ++ u64 loc_key; ++ u64 rcv_nxt; ++ struct mptcp_cb __rcu *mpcb; ++ u8 meta_tw:1, ++ in_list:1; ++}; ++ ++#define MPTCP_PM_NAME_MAX 16 ++struct mptcp_pm_ops { ++ struct list_head list; ++ ++ /* Signal the creation of a new MPTCP-session. */ ++ void (*new_session)(const struct sock *meta_sk); ++ void (*release_sock)(struct sock *meta_sk); ++ void (*fully_established)(struct sock *meta_sk); ++ void (*new_remote_address)(struct sock *meta_sk); ++ void (*subflow_error)(struct sock *meta_sk, struct sock *sk); ++ int (*get_local_id)(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio); ++ void (*addr_signal)(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb); ++ void (*add_raddr)(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id); ++ void (*rem_raddr)(struct mptcp_cb *mpcb, u8 rem_id); ++ void (*init_subsocket_v4)(struct sock *sk, struct in_addr addr); ++ void (*init_subsocket_v6)(struct sock *sk, struct in6_addr addr); ++ void (*delete_subflow)(struct sock *sk); ++ ++ char name[MPTCP_PM_NAME_MAX]; ++ struct module *owner; ++}; ++ ++#define MPTCP_SCHED_NAME_MAX 16 ++struct mptcp_sched_ops { ++ struct list_head list; ++ ++ struct sock * (*get_subflow)(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test); ++ struct sk_buff * (*next_segment)(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit); ++ void (*init)(struct sock *sk); ++ void (*release)(struct sock *sk); ++ ++ char name[MPTCP_SCHED_NAME_MAX]; ++ struct module *owner; ++}; ++ ++struct mptcp_cb { ++ /* list of sockets in this multipath connection */ ++ struct tcp_sock *connection_list; ++ /* list of sockets that need a call to release_cb */ ++ struct hlist_head callback_list; ++ ++ /* High-order bits of 64-bit sequence numbers */ ++ u32 snd_high_order[2]; ++ u32 rcv_high_order[2]; ++ ++ u16 send_infinite_mapping:1, ++ in_time_wait:1, ++ list_rcvd:1, /* XXX TO REMOVE */ ++ addr_signal:1, /* Path-manager wants us to call addr_signal */ ++ dss_csum:1, ++ server_side:1, ++ infinite_mapping_rcv:1, ++ infinite_mapping_snd:1, ++ dfin_combined:1, /* Was the DFIN combined with subflow-fin? */ ++ passive_close:1, ++ snd_hiseq_index:1, /* Index in snd_high_order of snd_nxt */ ++ rcv_hiseq_index:1, /* Index in rcv_high_order of rcv_nxt */ ++ tcp_ca_explicit_set:1; /* was meta CC set by app? */ ++ ++ /* socket count in this connection */ ++ u8 cnt_subflows; ++ u8 cnt_established; ++ ++#define MPTCP_SCHED_DATA_SIZE 8 ++ u8 mptcp_sched[MPTCP_SCHED_DATA_SIZE] __aligned(8); ++ struct mptcp_sched_ops *sched_ops; ++ ++ struct sk_buff_head reinject_queue; ++ /* First cache-line boundary is here minus 8 bytes. But from the ++ * reinject-queue only the next and prev pointers are regularly ++ * accessed. Thus, the whole data-path is on a single cache-line. ++ */ ++ ++ u64 csum_cutoff_seq; ++ u64 infinite_rcv_seq; ++ ++ /***** Start of fields, used for connection closure */ ++ spinlock_t tw_lock; ++ unsigned char mptw_state; ++ u8 dfin_path_index; ++ ++ struct list_head tw_list; ++ ++ /***** Start of fields, used for subflow establishment and closure */ ++ atomic_t mpcb_refcnt; ++ ++ /* Mutex needed, because otherwise mptcp_close will complain that the ++ * socket is owned by the user. ++ * E.g., mptcp_sub_close_wq is taking the meta-lock. ++ */ ++ struct mutex mpcb_mutex; ++ ++ /***** Start of fields, used for subflow establishment */ ++ struct sock *meta_sk; ++ ++ /* Master socket, also part of the connection_list, this ++ * socket is the one that the application sees. ++ */ ++ struct sock *master_sk; ++ ++ __u64 mptcp_loc_key; ++ __u64 mptcp_rem_key; ++ __u32 mptcp_loc_token; ++ __u32 mptcp_rem_token; ++ ++#define MPTCP_PM_SIZE 608 ++ u8 mptcp_pm[MPTCP_PM_SIZE] __aligned(8); ++ struct mptcp_pm_ops *pm_ops; ++ ++ u32 path_index_bits; ++ /* Next pi to pick up in case a new path becomes available */ ++ u8 next_path_index; ++ ++ __u8 mptcp_ver; ++ ++ /* Original snd/rcvbuf of the initial subflow. ++ * Used for the new subflows on the server-side to allow correct ++ * autotuning ++ */ ++ int orig_sk_rcvbuf; ++ int orig_sk_sndbuf; ++ u32 orig_window_clamp; ++ ++ struct tcp_info *master_info; ++}; ++ ++#define MPTCP_VERSION_0 0 ++#define MPTCP_VERSION_1 1 ++ ++#define MPTCP_SUB_CAPABLE 0 ++#define MPTCP_SUB_LEN_CAPABLE_SYN 12 ++#define MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_CAPABLE_ACK 20 ++#define MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN 20 ++ ++#define MPTCP_SUB_JOIN 1 ++#define MPTCP_SUB_LEN_JOIN_SYN 12 ++#define MPTCP_SUB_LEN_JOIN_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_JOIN_SYNACK 16 ++#define MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN 16 ++#define MPTCP_SUB_LEN_JOIN_ACK 24 ++#define MPTCP_SUB_LEN_JOIN_ACK_ALIGN 24 ++ ++#define MPTCP_SUB_DSS 2 ++#define MPTCP_SUB_LEN_DSS 4 ++#define MPTCP_SUB_LEN_DSS_ALIGN 4 ++ ++/* Lengths for seq and ack are the ones without the generic MPTCP-option header, ++ * as they are part of the DSS-option. ++ * To get the total length, just add the different options together. ++ */ ++#define MPTCP_SUB_LEN_SEQ 10 ++#define MPTCP_SUB_LEN_SEQ_CSUM 12 ++#define MPTCP_SUB_LEN_SEQ_ALIGN 12 ++ ++#define MPTCP_SUB_LEN_SEQ_64 14 ++#define MPTCP_SUB_LEN_SEQ_CSUM_64 16 ++#define MPTCP_SUB_LEN_SEQ_64_ALIGN 16 ++ ++#define MPTCP_SUB_LEN_ACK 4 ++#define MPTCP_SUB_LEN_ACK_ALIGN 4 ++ ++#define MPTCP_SUB_LEN_ACK_64 8 ++#define MPTCP_SUB_LEN_ACK_64_ALIGN 8 ++ ++/* This is the "default" option-length we will send out most often. ++ * MPTCP DSS-header ++ * 32-bit data sequence number ++ * 32-bit data ack ++ * ++ * It is necessary to calculate the effective MSS we will be using when ++ * sending data. ++ */ ++#define MPTCP_SUB_LEN_DSM_ALIGN (MPTCP_SUB_LEN_DSS_ALIGN + \ ++ MPTCP_SUB_LEN_SEQ_ALIGN + \ ++ MPTCP_SUB_LEN_ACK_ALIGN) ++ ++#define MPTCP_SUB_ADD_ADDR 3 ++#define MPTCP_SUB_LEN_ADD_ADDR4 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_VER1 28 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 28 ++ ++#define MPTCP_SUB_REMOVE_ADDR 4 ++#define MPTCP_SUB_LEN_REMOVE_ADDR 4 ++ ++#define MPTCP_SUB_PRIO 5 ++#define MPTCP_SUB_LEN_PRIO 3 ++#define MPTCP_SUB_LEN_PRIO_ADDR 4 ++#define MPTCP_SUB_LEN_PRIO_ALIGN 4 ++ ++#define MPTCP_SUB_FAIL 6 ++#define MPTCP_SUB_LEN_FAIL 12 ++#define MPTCP_SUB_LEN_FAIL_ALIGN 12 ++ ++#define MPTCP_SUB_FCLOSE 7 ++#define MPTCP_SUB_LEN_FCLOSE 12 ++#define MPTCP_SUB_LEN_FCLOSE_ALIGN 12 ++ ++ ++#define OPTION_MPTCP (1 << 5) ++ ++/* Max number of fastclose retransmissions */ ++#define MPTCP_FASTCLOSE_RETRIES 3 ++ ++#ifdef CONFIG_MPTCP ++ ++/* Used for checking if the mptcp initialization has been successful */ ++extern bool mptcp_init_failed; ++ ++/* MPTCP options */ ++#define OPTION_TYPE_SYN (1 << 0) ++#define OPTION_TYPE_SYNACK (1 << 1) ++#define OPTION_TYPE_ACK (1 << 2) ++#define OPTION_MP_CAPABLE (1 << 3) ++#define OPTION_DATA_ACK (1 << 4) ++#define OPTION_ADD_ADDR (1 << 5) ++#define OPTION_MP_JOIN (1 << 6) ++#define OPTION_MP_FAIL (1 << 7) ++#define OPTION_MP_FCLOSE (1 << 8) ++#define OPTION_REMOVE_ADDR (1 << 9) ++#define OPTION_MP_PRIO (1 << 10) ++ ++/* MPTCP flags: both TX and RX */ ++#define MPTCPHDR_SEQ 0x01 /* DSS.M option is present */ ++#define MPTCPHDR_FIN 0x02 /* DSS.F option is present */ ++#define MPTCPHDR_SEQ64_INDEX 0x04 /* index of seq in mpcb->snd_high_order */ ++/* MPTCP flags: RX only */ ++#define MPTCPHDR_ACK 0x08 ++#define MPTCPHDR_SEQ64_SET 0x10 /* Did we received a 64-bit seq number? */ ++#define MPTCPHDR_SEQ64_OFO 0x20 /* Is it not in our circular array? */ ++#define MPTCPHDR_DSS_CSUM 0x40 ++/* MPTCP flags: TX only */ ++#define MPTCPHDR_INF 0x08 ++#define MPTCP_REINJECT 0x10 /* Did we reinject this segment? */ ++ ++struct mptcp_option { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_capable { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++ __u8 h:1, ++ rsv:5, ++ b:1, ++ a:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++ __u8 a:1, ++ b:1, ++ rsv:5, ++ h:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 sender_key; ++ __u64 receiver_key; ++} __attribute__((__packed__)); ++ ++struct mp_join { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ u32 token; ++ u32 nonce; ++ } syn; ++ struct { ++ __u64 mac; ++ u32 nonce; ++ } synack; ++ struct { ++ __u8 mac[20]; ++ } ack; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_dss { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ A:1, ++ a:1, ++ M:1, ++ m:1, ++ F:1, ++ rsv2:3; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:3, ++ F:1, ++ m:1, ++ M:1, ++ a:1, ++ A:1; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_add_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ipver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ipver:4; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ struct in_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v4; ++ struct { ++ struct in6_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v6; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_remove_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 rsv:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:4; ++#else ++#error "Adjust your defines" ++#endif ++ /* list of addr_id */ ++ __u8 addrs_id; ++}; ++ ++struct mp_fail { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __be64 data_seq; ++} __attribute__((__packed__)); ++ ++struct mp_fclose { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 key; ++} __attribute__((__packed__)); ++ ++struct mp_prio { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++} __attribute__((__packed__)); ++ ++static inline int mptcp_sub_len_dss(const struct mp_dss *m, const int csum) ++{ ++ return 4 + m->A * (4 + m->a * 4) + m->M * (10 + m->m * 4 + csum * 2); ++} ++ ++#define MPTCP_SYSCTL 1 ++ ++extern int sysctl_mptcp_enabled; ++extern int sysctl_mptcp_version; ++extern int sysctl_mptcp_checksum; ++extern int sysctl_mptcp_debug; ++extern int sysctl_mptcp_syn_retries; ++ ++extern struct workqueue_struct *mptcp_wq; ++ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ if (unlikely(sysctl_mptcp_debug)) \ ++ pr_err(fmt, ##args); \ ++ } while (0) ++ ++/* Iterates over all subflows */ ++#define mptcp_for_each_tp(mpcb, tp) \ ++ for ((tp) = (mpcb)->connection_list; (tp); (tp) = (tp)->mptcp->next) ++ ++#define mptcp_for_each_sk(mpcb, sk) \ ++ for ((sk) = (struct sock *)(mpcb)->connection_list; \ ++ sk; \ ++ sk = (struct sock *)tcp_sk(sk)->mptcp->next) ++ ++#define mptcp_for_each_sk_safe(__mpcb, __sk, __temp) \ ++ for (__sk = (struct sock *)(__mpcb)->connection_list, \ ++ __temp = __sk ? (struct sock *)tcp_sk(__sk)->mptcp->next : NULL; \ ++ __sk; \ ++ __sk = __temp, \ ++ __temp = __sk ? (struct sock *)tcp_sk(__sk)->mptcp->next : NULL) ++ ++/* Iterates over all bit set to 1 in a bitset */ ++#define mptcp_for_each_bit_set(b, i) \ ++ for (i = ffs(b) - 1; i >= 0; i = ffs(b >> (i + 1) << (i + 1)) - 1) ++ ++#define mptcp_for_each_bit_unset(b, i) \ ++ mptcp_for_each_bit_set(~b, i) ++ ++#define MPTCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++#define MPTCP_INC_STATS_BH(net, field) __SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++ ++enum ++{ ++ MPTCP_MIB_NUM = 0, ++ MPTCP_MIB_MPCAPABLEPASSIVE, /* Received SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVE, /* Sent SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVEACK, /* Received SYN/ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLERETRANSFALLBACK,/* Client-side stopped sending MP_CAPABLE after too many SYN-retransmissions */ ++ MPTCP_MIB_CSUMENABLED, /* Created MPTCP-connection with DSS-checksum enabled */ ++ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ ++ MPTCP_MIB_MPFAILRX, /* Received an MP_FAIL */ ++ MPTCP_MIB_CSUMFAIL, /* Received segment with invalid checksum */ ++ MPTCP_MIB_FASTCLOSERX, /* Recevied a FAST_CLOSE */ ++ MPTCP_MIB_FASTCLOSETX, /* Sent a FAST_CLOSE */ ++ MPTCP_MIB_FBACKSUB, /* Fallback upon ack without data-ack on new subflow */ ++ MPTCP_MIB_FBACKINIT, /* Fallback upon ack without data-ack on initial subflow */ ++ MPTCP_MIB_FBDATASUB, /* Fallback upon data without DSS at the beginning on new subflow */ ++ MPTCP_MIB_FBDATAINIT, /* Fallback upon data without DSS at the beginning on initial subflow */ ++ MPTCP_MIB_REMADDRSUB, /* Remove subflow due to REMOVE_ADDR */ ++ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ ++ MPTCP_MIB_JOINFALLBACK, /* Received MP_JOIN on session that has fallen back to reg. TCP */ ++ MPTCP_MIB_JOINSYNTX, /* Sent a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNRX, /* Received a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKRX, /* Received a SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKFAIL, /* Third ACK on new subflow did not contain an MP_JOIN */ ++ MPTCP_MIB_JOINACKRTO, /* Retransmission timer for third ACK + MP_JOIN timed out */ ++ MPTCP_MIB_JOINACKRXMIT, /* Retransmitted an ACK + MP_JOIN */ ++ MPTCP_MIB_NODSSWINDOW, /* Received too many packets without a DSS-option */ ++ MPTCP_MIB_DSSNOMATCH, /* Received a new mapping that did not match the previous one */ ++ MPTCP_MIB_INFINITEMAPRX, /* Received an infinite mapping */ ++ MPTCP_MIB_DSSTCPMISMATCH, /* DSS-mapping did not map with TCP's sequence numbers */ ++ MPTCP_MIB_DSSTRIMHEAD, /* Trimmed segment at the head (coalescing middlebox) */ ++ MPTCP_MIB_DSSSPLITTAIL, /* Trimmed segment at the tail (coalescing middlebox) */ ++ MPTCP_MIB_PURGEOLD, /* Removed old skb from the rcv-queue due to missing DSS-mapping */ ++ MPTCP_MIB_ADDADDRRX, /* Received an ADD_ADDR */ ++ MPTCP_MIB_ADDADDRTX, /* Sent an ADD_ADDR */ ++ MPTCP_MIB_REMADDRRX, /* Received a REMOVE_ADDR */ ++ MPTCP_MIB_REMADDRTX, /* Sent a REMOVE_ADDR */ ++ __MPTCP_MIB_MAX ++}; ++ ++#define MPTCP_MIB_MAX __MPTCP_MIB_MAX ++struct mptcp_mib { ++ unsigned long mibs[MPTCP_MIB_MAX]; ++}; ++ ++extern struct lock_class_key meta_key; ++extern char *meta_key_name; ++extern struct lock_class_key meta_slock_key; ++extern char *meta_slock_key_name; ++ ++extern siphash_key_t mptcp_secret; ++ ++/* This is needed to ensure that two subsequent key/nonce-generation result in ++ * different keys/nonces if the IPs and ports are the same. ++ */ ++extern u32 mptcp_seed; ++ ++#define MPTCP_HASH_SIZE 1024 ++ ++extern struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++ ++/* Request-sockets can be hashed in the tk_htb for collision-detection or in ++ * the regular htb for join-connections. We need to define different NULLS ++ * values so that we can correctly detect a request-socket that has been ++ * recycled. See also c25eb3bfb9729. ++ */ ++#define MPTCP_REQSK_NULLS_BASE (1U << 29) ++ ++ ++void mptcp_data_ready(struct sock *sk); ++void mptcp_write_space(struct sock *sk); ++ ++void mptcp_add_meta_ofo_queue(const struct sock *meta_sk, struct sk_buff *skb, ++ struct sock *sk); ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied); ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags); ++void mptcp_del_sock(struct sock *sk); ++void mptcp_update_metasocket(const struct sock *meta_sk); ++void mptcp_reinject_data(struct sock *orig_sk, int clone_it); ++void mptcp_update_sndbuf(const struct tcp_sock *tp); ++void mptcp_send_fin(struct sock *meta_sk); ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority); ++bool mptcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt); ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp); ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size); ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb); ++void mptcp_close(struct sock *meta_sk, long timeout); ++int mptcp_doit(struct sock *sk); ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window); ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req); ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop, u32 tsoff); ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++u32 __mptcp_select_window(struct sock *sk); ++void mptcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); ++unsigned int mptcp_current_mss(struct sock *meta_sk); ++int mptcp_select_size(const struct sock *meta_sk, bool sg, bool first_skb); ++void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn); ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...); ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk); ++void mptcp_fin(struct sock *meta_sk); ++void mptcp_meta_retransmit_timer(struct sock *meta_sk); ++void mptcp_sub_retransmit_timer(struct sock *sk); ++int mptcp_write_wakeup(struct sock *meta_sk, int mib); ++void mptcp_sub_close_wq(struct work_struct *work); ++void mptcp_sub_close(struct sock *sk, unsigned long delay); ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk); ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb); ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_ack_handler(unsigned long); ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time); ++int mptcp_check_snd_buf(const struct tcp_sock *tp); ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb); ++void __init mptcp_init(void); ++void mptcp_destroy_sock(struct sock *sk); ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed); ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw); ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw); ++void mptcp_time_wait(struct sock *sk, int state, int timeo); ++void mptcp_disconnect(struct sock *meta_sk); ++bool mptcp_should_expand_sndbuf(const struct sock *sk); ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_tsq_flags(struct sock *sk); ++void mptcp_tsq_sub_deferred(struct sock *meta_sk); ++struct mp_join *mptcp_find_join(const struct sk_buff *skb); ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp); ++struct sock *mptcp_hash_find(const struct net *net, const u32 token); ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw); ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net); ++void mptcp_reqsk_destructor(struct request_sock *req); ++void mptcp_connect_init(struct sock *sk); ++void mptcp_sub_force_close(struct sock *sk); ++int mptcp_sub_len_remove_addr_align(u16 bitfield); ++void mptcp_init_buffer_space(struct sock *sk); ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb); ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie); ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb); ++void mptcp_enable_sock(struct sock *sk); ++void mptcp_disable_sock(struct sock *sk); ++void mptcp_disable_static_key(void); ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb); ++void mptcp_mpcb_put(struct mptcp_cb *mpcb); ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb); ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen); ++void mptcp_clear_sk(struct sock *sk, int size); ++ ++/* MPTCP-path-manager registration/initialization functions */ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_init_path_manager(struct mptcp_cb *mpcb); ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb); ++void mptcp_fallback_default(struct mptcp_cb *mpcb); ++void mptcp_get_default_path_manager(char *name); ++int mptcp_set_scheduler(struct sock *sk, const char *name); ++int mptcp_set_path_manager(struct sock *sk, const char *name); ++int mptcp_set_default_path_manager(const char *name); ++extern struct mptcp_pm_ops mptcp_pm_default; ++ ++/* MPTCP-scheduler registration/initialization functions */ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_init_scheduler(struct mptcp_cb *mpcb); ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb); ++void mptcp_get_default_scheduler(char *name); ++int mptcp_set_default_scheduler(const char *name); ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test); ++bool mptcp_is_def_unavailable(struct sock *sk); ++bool subflow_is_active(const struct tcp_sock *tp); ++bool subflow_is_backup(const struct tcp_sock *tp); ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test); ++extern struct mptcp_sched_ops mptcp_sched_default; ++ ++/* Initializes function-pointers and MPTCP-flags */ ++static inline void mptcp_init_tcp_sock(struct sock *sk) ++{ ++ if (!mptcp_init_failed && sysctl_mptcp_enabled == MPTCP_SYSCTL) ++ mptcp_enable_sock(sk); ++} ++ ++static inline int mptcp_pi_to_flag(int pi) ++{ ++ return 1 << (pi - 1); ++} ++ ++static inline ++struct mptcp_request_sock *mptcp_rsk(const struct request_sock *req) ++{ ++ return (struct mptcp_request_sock *)req; ++} ++ ++static inline ++struct request_sock *rev_mptcp_rsk(const struct mptcp_request_sock *req) ++{ ++ return (struct request_sock *)req; ++} ++ ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ struct sock *sk_it; ++ ++ if (tcp_sk(sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) { ++ if (!(sk_it->sk_route_caps & NETIF_F_SG) || ++ !sk_check_csum_caps(sk_it)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) ++{ ++ /* We check packets out and send-head here. TCP only checks the ++ * send-head. But, MPTCP also checks packets_out, as this is an ++ * indication that we might want to do opportunistic reinjection. ++ */ ++ if (tcp_sk(meta_sk)->packets_out || tcp_send_head(meta_sk)) { ++ struct tcp_sock *tp = tcp_sk(meta_sk); ++ ++ /* We don't care about the MSS, because it will be set in ++ * mptcp_write_xmit. ++ */ ++ __tcp_push_pending_frames(meta_sk, 0, tp->nonagle); ++ } ++} ++ ++static inline void mptcp_send_reset(struct sock *sk) ++{ ++ if (tcp_need_reset(sk->sk_state)) ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); ++ mptcp_sub_force_close(sk); ++} ++ ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ struct sock *sk_it, *tmp; ++ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmp) { ++ if (sk_it != except) ++ mptcp_send_reset(sk_it); ++ } ++} ++ ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ; ++} ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_FIN; ++} ++ ++/* Is it a data-fin while in infinite mapping mode? ++ * In infinite mode, a subflow-fin is in fact a data-fin. ++ */ ++static inline bool mptcp_is_data_fin2(const struct sk_buff *skb, ++ const struct tcp_sock *tp) ++{ ++ return mptcp_is_data_fin(skb) || ++ (tp->mpcb->infinite_mapping_rcv && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)); ++} ++ ++static inline u8 mptcp_get_64_bit(u64 data_seq, struct mptcp_cb *mpcb) ++{ ++ u64 data_seq_high = (u32)(data_seq >> 32); ++ ++ if (mpcb->rcv_high_order[0] == data_seq_high) ++ return 0; ++ else if (mpcb->rcv_high_order[1] == data_seq_high) ++ return MPTCPHDR_SEQ64_INDEX; ++ else ++ return MPTCPHDR_SEQ64_OFO; ++} ++ ++/* Sets the data_seq and returns pointer to the in-skb field of the data_seq. ++ * If the packet has a 64-bit dseq, the pointer points to the last 32 bits. ++ */ ++static inline __u32 *mptcp_skb_set_data_seq(const struct sk_buff *skb, ++ u32 *data_seq, ++ struct mptcp_cb *mpcb) ++{ ++ __u32 *ptr = (__u32 *)(skb_transport_header(skb) + TCP_SKB_CB(skb)->dss_off); ++ ++ if (TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ64_SET) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ if (mpcb) ++ TCP_SKB_CB(skb)->mptcp_flags |= mptcp_get_64_bit(data_seq64, mpcb); ++ ++ *data_seq = (u32)data_seq64; ++ ptr++; ++ } else { ++ *data_seq = get_unaligned_be32(ptr); ++ } ++ ++ return ptr; ++} ++ ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return tcp_sk(sk)->meta_sk; ++} ++ ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return tcp_sk(tp->meta_sk); ++} ++ ++static inline int is_meta_tp(const struct tcp_sock *tp) ++{ ++ return tp->mpcb && mptcp_meta_tp(tp) == tp; ++} ++ ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return sk->sk_state != TCP_NEW_SYN_RECV && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ mptcp(tcp_sk(sk)) && mptcp_meta_sk(sk) == sk; ++} ++ ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return !mptcp(tp) || (!tp->mptcp->slave_sk && !is_meta_tp(tp)); ++} ++ ++static inline void mptcp_init_mp_opt(struct mptcp_options_received *mopt) ++{ ++ mopt->saw_mpc = 0; ++ mopt->dss_csum = 0; ++ mopt->drop_me = 0; ++ ++ mopt->is_mp_join = 0; ++ mopt->join_ack = 0; ++ ++ mopt->saw_low_prio = 0; ++ mopt->low_prio = 0; ++ ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) ++{ ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ mopt->saw_low_prio = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->join_ack = 0; ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline __be32 mptcp_get_highorder_sndbits(const struct sk_buff *skb, ++ const struct mptcp_cb *mpcb) ++{ ++ return htonl(mpcb->snd_high_order[(TCP_SKB_CB(skb)->mptcp_flags & ++ MPTCPHDR_SEQ64_INDEX) ? 1 : 0]); ++} ++ ++static inline u64 mptcp_get_data_seq_64(const struct mptcp_cb *mpcb, int index, ++ u32 data_seq_32) ++{ ++ return ((u64)mpcb->rcv_high_order[index] << 32) | data_seq_32; ++} ++ ++static inline u64 mptcp_get_rcv_nxt_64(const struct tcp_sock *meta_tp) ++{ ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ return mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_nxt); ++} ++ ++static inline void mptcp_check_sndseq_wrap(struct tcp_sock *meta_tp, int inc) ++{ ++ if (unlikely(meta_tp->snd_nxt > meta_tp->snd_nxt + inc)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] += 2; ++ } ++} ++ ++static inline void mptcp_check_rcvseq_wrap(struct tcp_sock *meta_tp, ++ u32 old_rcv_nxt) ++{ ++ if (unlikely(old_rcv_nxt > meta_tp->rcv_nxt)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->rcv_high_order[mpcb->rcv_hiseq_index] += 2; ++ mpcb->rcv_hiseq_index = mpcb->rcv_hiseq_index ? 0 : 1; ++ } ++} ++ ++static inline int mptcp_sk_can_send(const struct sock *sk) ++{ ++ return tcp_passive_fastopen(sk) || ++ ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && ++ !tcp_sk(sk)->mptcp->pre_established); ++} ++ ++static inline int mptcp_sk_can_recv(const struct sock *sk) ++{ ++ return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2); ++} ++ ++static inline int mptcp_sk_can_send_ack(const struct sock *sk) ++{ ++ return !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | ++ TCPF_CLOSE | TCPF_LISTEN)) && ++ !tcp_sk(sk)->mptcp->pre_established; ++} ++ ++/* Only support GSO if all subflows supports it */ ++static inline bool mptcp_sk_can_gso(const struct sock *meta_sk) ++{ ++ struct sock *sk; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!sk_can_gso(sk)) ++ return false; ++ } ++ return true; ++} ++ ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ struct sock *sk; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!(sk->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ return true; ++} ++ ++static inline void mptcp_set_rto(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *sk_it; ++ struct inet_connection_sock *micsk = inet_csk(mptcp_meta_sk(sk)); ++ __u32 max_rto = 0; ++ ++ /* We are in recovery-phase on the MPTCP-level. Do not update the ++ * RTO, because this would kill exponential backoff. ++ */ ++ if (micsk->icsk_retransmits) ++ return; ++ ++ mptcp_for_each_sk(tp->mpcb, sk_it) { ++ if ((mptcp_sk_can_send(sk_it) || sk_it->sk_state == TCP_SYN_RECV) && ++ inet_csk(sk_it)->icsk_retransmits == 0 && ++ inet_csk(sk_it)->icsk_backoff == 0 && ++ inet_csk(sk_it)->icsk_rto > max_rto) ++ max_rto = inet_csk(sk_it)->icsk_rto; ++ } ++ if (max_rto) { ++ micsk->icsk_rto = max_rto << 1; ++ ++ /* A successfull rto-measurement - reset backoff counter */ ++ micsk->icsk_backoff = 0; ++ } ++} ++ ++static inline void mptcp_sub_close_passive(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(meta_sk); ++ ++ /* Only close, if the app did a send-shutdown (passive close), and we ++ * received the data-ack of the data-fin. ++ */ ++ if (tp->mpcb->passive_close && meta_tp->snd_una == meta_tp->write_seq) ++ mptcp_sub_close(sk, 0); ++} ++ ++static inline bool mptcp_fallback_infinite(struct sock *sk, int flag) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If data has been acknowleged on the meta-level, fully_established ++ * will have been set before and thus we will not fall back to infinite ++ * mapping. ++ */ ++ if (likely(tp->mptcp->fully_established)) ++ return false; ++ ++ if (!(flag & MPTCP_FLAG_DATA_ACKED)) ++ return false; ++ ++ /* Don't fallback twice ;) */ ++ if (mpcb->infinite_mapping_snd) ++ return false; ++ ++ pr_err("%s %#x will fallback - pi %d, src %pI4:%u dst %pI4:%u rcv_nxt %u from %pS\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ &inet_sk(sk)->inet_saddr, ntohs(inet_sk(sk)->inet_sport), ++ &inet_sk(sk)->inet_daddr, ntohs(inet_sk(sk)->inet_dport), ++ tp->rcv_nxt, __builtin_return_address(0)); ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKSUB); ++ return true; ++ } ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ tp->mptcp->fully_established = 1; ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKINIT); ++ ++ return false; ++} ++ ++/* Find the first index whose bit in the bit-field == 0 */ ++static inline u8 mptcp_set_new_pathindex(struct mptcp_cb *mpcb) ++{ ++ u8 base = mpcb->next_path_index; ++ int i; ++ ++ /* Start at 1, because 0 is reserved for the meta-sk */ ++ mptcp_for_each_bit_unset(mpcb->path_index_bits >> base, i) { ++ if (i + base < 1) ++ continue; ++ if (i + base >= sizeof(mpcb->path_index_bits) * 8) ++ break; ++ i += base; ++ mpcb->path_index_bits |= (1 << i); ++ mpcb->next_path_index = i + 1; ++ return i; ++ } ++ mptcp_for_each_bit_unset(mpcb->path_index_bits, i) { ++ if (i >= sizeof(mpcb->path_index_bits) * 8) ++ break; ++ if (i < 1) ++ continue; ++ mpcb->path_index_bits |= (1 << i); ++ mpcb->next_path_index = i + 1; ++ return i; ++ } ++ ++ return 0; ++} ++ ++static inline bool mptcp_v6_is_v4_mapped(const struct sock *sk) ++{ ++ return sk->sk_family == AF_INET6 && ++ ipv6_addr_type(&inet6_sk(sk)->saddr) == IPV6_ADDR_MAPPED; ++} ++ ++/* We are in or are becoming to be in infinite mapping mode */ ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return mpcb->infinite_mapping_rcv || ++ mpcb->infinite_mapping_snd || ++ mpcb->send_infinite_mapping; ++} ++ ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ /* Has been removed from the tk-table. Thus, no new subflows. ++ * ++ * Check for close-state is necessary, because we may have been closed ++ * without passing by mptcp_close(). ++ * ++ * When falling back, no new subflows are allowed either. ++ */ ++ return meta_sk->sk_state != TCP_CLOSE && ++ tcp_sk(meta_sk)->inside_tk_table && ++ !tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv && ++ !tcp_sk(meta_sk)->mpcb->send_infinite_mapping; ++} ++ ++/* TCP and MPTCP mpc flag-depending functions */ ++u16 mptcp_select_window(struct sock *sk); ++void mptcp_init_buffer_space(struct sock *sk); ++void mptcp_tcp_set_rto(struct sock *sk); ++ ++/* TCP and MPTCP flag-depending functions */ ++bool mptcp_prune_ofo_queue(struct sock *sk); ++ ++#else /* CONFIG_MPTCP */ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ } while (0) ++ ++/* Without MPTCP, we just do one iteration ++ * over the only socket available. This assumes that ++ * the sk/tp arg is the socket in that case. ++ */ ++#define mptcp_for_each_sk(mpcb, sk) ++#define mptcp_for_each_sk_safe(__mpcb, __sk, __temp) ++ ++#define MPTCP_INC_STATS(net, field) \ ++ do { \ ++ } while(0) ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return NULL; ++} ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return NULL; ++} ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return 0; ++} ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_del_sock(const struct sock *sk) {} ++static inline void mptcp_update_metasocket(const struct sock *meta_sk) {} ++static inline void mptcp_reinject_data(struct sock *orig_sk, int clone_it) {} ++static inline void mptcp_update_sndbuf(const struct tcp_sock *tp) {} ++static inline void mptcp_clean_rtx_infinite(const struct sk_buff *skb, ++ const struct sock *sk) {} ++static inline void mptcp_sub_close(struct sock *sk, unsigned long delay) {} ++static inline void mptcp_set_rto(const struct sock *sk) {} ++static inline void mptcp_send_fin(const struct sock *meta_sk) {} ++static inline void mptcp_parse_options(const uint8_t *ptr, const int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ const struct tcp_sock *tp) {} ++static inline void mptcp_syn_options(const struct sock *sk, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++static inline void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++ ++static inline void mptcp_established_options(struct sock *sk, ++ struct sk_buff *skb, ++ struct tcp_out_options *opts, ++ unsigned *size) {} ++static inline void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) {} ++static inline void mptcp_close(struct sock *meta_sk, long timeout) {} ++static inline int mptcp_doit(struct sock *sk) ++{ ++ return 0; ++} ++static inline int mptcp_check_req_fastopen(struct sock *child, ++ struct request_sock *req) ++{ ++ return 1; ++} ++static inline int mptcp_check_req_master(const struct sock *sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ const struct sk_buff *skb, ++ int drop, ++ u32 tsoff) ++{ ++ return 1; ++} ++static inline struct sock *mptcp_check_req_child(const struct sock *meta_sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return NULL; ++} ++static inline unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ return 0; ++} ++static inline void mptcp_sub_close_passive(struct sock *sk) {} ++static inline bool mptcp_fallback_infinite(const struct sock *sk, int flag) ++{ ++ return false; ++} ++static inline void mptcp_init_mp_opt(const struct mptcp_options_received *mopt) {} ++static inline void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) {} ++static inline bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ return false; ++} ++static inline int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) {} ++static inline void mptcp_send_reset(const struct sock *sk) {} ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) {} ++static inline bool mptcp_handle_options(struct sock *sk, ++ const struct tcphdr *th, ++ struct sk_buff *skb) ++{ ++ return false; ++} ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) {} ++static inline void __init mptcp_init(void) {} ++static inline bool mptcp_sk_can_gso(const struct sock *sk) ++{ ++ return false; ++} ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ return false; ++} ++static inline unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, ++ u32 mss_now, int large_allowed) ++{ ++ return 0; ++} ++static inline void mptcp_destroy_sock(struct sock *sk) {} ++static inline int mptcp_rcv_synsent_state_process(struct sock *sk, ++ struct sock **skptr, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return 0; ++} ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_init_tw_sock(struct sock *sk, ++ struct tcp_timewait_sock *tw) ++{ ++ return 0; ++} ++static inline void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) {} ++static inline void mptcp_disconnect(struct sock *meta_sk) {} ++static inline void mptcp_tsq_flags(struct sock *sk) {} ++static inline void mptcp_tsq_sub_deferred(struct sock *meta_sk) {} ++static inline void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) {} ++static inline void mptcp_remove_shortcuts(const struct mptcp_cb *mpcb, ++ const struct sk_buff *skb) {} ++static inline void mptcp_init_tcp_sock(struct sock *sk) {} ++static inline void mptcp_disable_static_key(void) {} ++static inline void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) {} ++static inline void mptcp_mpcb_put(struct mptcp_cb *mpcb) {} ++static inline void mptcp_fin(struct sock *meta_sk) {} ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return false; ++} ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_H */ +diff -aurN linux-4.14.174/include/net/mptcp_v4.h mptcp-mptcp_v0.94/include/net/mptcp_v4.h +--- linux-4.14.174/include/net/mptcp_v4.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/mptcp_v4.h 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef MPTCP_V4_H_ ++#define MPTCP_V4_H_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern struct request_sock_ops mptcp_request_sock_ops; ++extern const struct inet_connection_sock_af_ops mptcp_v4_specific; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++#ifdef CONFIG_MPTCP ++ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v4_search_req(const __be16 rport, const __be32 raddr, ++ const __be32 laddr, const struct net *net); ++int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem); ++int mptcp_pm_v4_init(void); ++void mptcp_pm_v4_undo(void); ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport); ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed); ++ ++#else ++ ++static inline int mptcp_v4_do_rcv(const struct sock *meta_sk, ++ const struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* MPTCP_V4_H_ */ +diff -aurN linux-4.14.174/include/net/mptcp_v6.h mptcp-mptcp_v0.94/include/net/mptcp_v6.h +--- linux-4.14.174/include/net/mptcp_v6.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/mptcp_v6.h 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,69 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_V6_H ++#define _MPTCP_V6_H ++ ++#include ++#include ++ ++#include ++ ++ ++#ifdef CONFIG_MPTCP ++extern const struct inet_connection_sock_af_ops mptcp_v6_mapped; ++extern const struct inet_connection_sock_af_ops mptcp_v6_specific; ++extern struct request_sock_ops mptcp6_request_sock_ops; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v6_search_req(const __be16 rport, const struct in6_addr *raddr, ++ const struct in6_addr *laddr, const struct net *net); ++int mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem); ++int mptcp_pm_v6_init(void); ++void mptcp_pm_v6_undo(void); ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport); ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed); ++ ++#else /* CONFIG_MPTCP */ ++ ++#define mptcp_v6_mapped ipv6_mapped ++ ++static inline int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_V6_H */ +diff -aurN linux-4.14.174/include/net/net_namespace.h mptcp-mptcp_v0.94/include/net/net_namespace.h +--- linux-4.14.174/include/net/net_namespace.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/net_namespace.h 2020-03-23 09:45:33.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -101,6 +102,9 @@ + #if IS_ENABLED(CONFIG_IPV6) + struct netns_ipv6 ipv6; + #endif ++#if IS_ENABLED(CONFIG_MPTCP) ++ struct netns_mptcp mptcp; ++#endif + #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) + struct netns_ieee802154_lowpan ieee802154_lowpan; + #endif +diff -aurN linux-4.14.174/include/net/netns/mptcp.h mptcp-mptcp_v0.94/include/net/netns/mptcp.h +--- linux-4.14.174/include/net/netns/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/netns/mptcp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,52 @@ ++/* ++ * MPTCP implementation - MPTCP namespace ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef __NETNS_MPTCP_H__ ++#define __NETNS_MPTCP_H__ ++ ++#include ++ ++enum { ++ MPTCP_PM_FULLMESH = 0, ++ MPTCP_PM_MAX ++}; ++ ++struct mptcp_mib; ++ ++struct netns_mptcp { ++ DEFINE_SNMP_STAT(struct mptcp_mib, mptcp_statistics); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_net_mptcp; ++#endif ++ ++ void *path_managers[MPTCP_PM_MAX]; ++}; ++ ++#endif /* __NETNS_MPTCP_H__ */ +diff -aurN linux-4.14.174/include/net/snmp.h mptcp-mptcp_v0.94/include/net/snmp.h +--- linux-4.14.174/include/net/snmp.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/snmp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -91,7 +91,6 @@ + atomic_long_t mibs[ICMP6MSG_MIB_MAX]; + }; + +- + /* TCP */ + #define TCP_MIB_MAX __TCP_MIB_MAX + struct tcp_mib { +diff -aurN linux-4.14.174/include/net/sock.h mptcp-mptcp_v0.94/include/net/sock.h +--- linux-4.14.174/include/net/sock.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/sock.h 2020-03-23 09:45:33.000000000 +0100 +@@ -786,6 +786,7 @@ + SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ + SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ ++ SOCK_MPTCP, /* MPTCP set on this socket */ + }; + + #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) +@@ -1086,6 +1087,7 @@ + void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); + int (*get_port)(struct sock *sk, unsigned short snum); ++ void (*clear_sk)(struct sock *sk, int size); + + /* Keeping track of sockets in use */ + #ifdef CONFIG_PROC_FS +@@ -1510,9 +1512,6 @@ + + static inline void sock_owned_by_me(const struct sock *sk) + { +-#ifdef CONFIG_LOCKDEP +- WARN_ON_ONCE(!lockdep_sock_is_held(sk) && debug_locks); +-#endif + } + + static inline bool sock_owned_by_user(const struct sock *sk) +diff -aurN linux-4.14.174/include/net/tcp.h mptcp-mptcp_v0.94/include/net/tcp.h +--- linux-4.14.174/include/net/tcp.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/tcp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -187,6 +187,7 @@ + #define TCPOPT_SACK 5 /* SACK Block */ + #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ + #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ ++#define TCPOPT_MPTCP 30 + #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ + #define TCPOPT_EXP 254 /* Experimental */ + /* Magic number to be after the option value for sharing TCP +@@ -240,6 +241,30 @@ + */ + #define TFO_SERVER_WO_SOCKOPT1 0x400 + ++/* Flags from tcp_input.c for tcp_ack */ ++#define FLAG_DATA 0x01 /* Incoming frame contained data. */ ++#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ ++#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ ++#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ ++#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ ++#define FLAG_DATA_SACKED 0x20 /* New SACK. */ ++#define FLAG_ECE 0x40 /* ECE in this ACK */ ++#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ ++#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ ++#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ ++#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ ++#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ ++#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ ++#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ ++#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ ++#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ ++ ++#define MPTCP_FLAG_DATA_ACKED 0x10000 ++ ++#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) ++#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) ++#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) ++#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) + + /* sysctl variables for tcp */ + extern int sysctl_tcp_fastopen; +@@ -341,6 +366,96 @@ + #define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) + #define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) + ++/**** START - Exports needed for MPTCP ****/ ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops; ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops; ++ ++struct mptcp_options_received; ++ ++void tcp_cleanup_rbuf(struct sock *sk, int copied); ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited); ++int tcp_close_state(struct sock *sk); ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb); ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib); ++void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb); ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask); ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle); ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle); ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss); ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, const struct sk_buff *skb); ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++int __pskb_trim_head(struct sk_buff *skb, int len); ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb); ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags); ++void tcp_reset(struct sock *sk); ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin); ++bool tcp_urg_mode(const struct tcp_sock *tp); ++void tcp_ack_probe(struct sock *sk); ++void tcp_rearm_rto(struct sock *sk); ++int tcp_write_timeout(struct sock *sk); ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout); ++void tcp_write_err(struct sock *sk); ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr); ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++ ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb); ++void tcp_v4_reqsk_destructor(struct request_sock *req); ++ ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); ++void tcp_v6_destroy_sock(struct sock *sk); ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); ++void tcp_v6_hash(struct sock *sk); ++struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb); ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req); ++void tcp_v6_reqsk_destructor(struct request_sock *req); ++ ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, ++ int large_allowed); ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb); ++ ++void skb_clone_fraglist(struct sk_buff *skb); ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old); ++ ++void inet_twsk_free(struct inet_timewait_sock *tw); ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb); ++/* These states need RST on ABORT according to RFC793 */ ++static inline bool tcp_need_reset(int state) ++{ ++ return (1 << state) & ++ (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | ++ TCPF_FIN_WAIT2 | TCPF_SYN_RECV); ++} ++ ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen); ++void tcp_ofo_queue(struct sock *sk); ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb); ++int linear_payload_sz(bool first_skb); ++/**** END - Exports needed for MPTCP ****/ ++ + void tcp_tasklet_init(void); + + void tcp_v4_err(struct sk_buff *skb, u32); +@@ -436,7 +551,9 @@ + int flags, int *addr_len); + void tcp_parse_options(const struct net *net, const struct sk_buff *skb, + struct tcp_options_received *opt_rx, +- int estab, struct tcp_fastopen_cookie *foc); ++ struct mptcp_options_received *mopt_rx, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp); + const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); + + /* +@@ -445,6 +562,7 @@ + + void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); + void tcp_v4_mtu_reduced(struct sock *sk); ++void tcp_v6_mtu_reduced(struct sock *sk); + void tcp_req_err(struct sock *sk, u32 seq, bool abort); + int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); + struct sock *tcp_create_openreq_child(const struct sock *sk, +@@ -533,7 +651,8 @@ + + u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, + u16 *mssp); +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + u64 cookie_init_timestamp(struct request_sock *req); + bool cookie_timestamp_decode(const struct net *net, + struct tcp_options_received *opt); +@@ -547,7 +666,8 @@ + + u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, + const struct tcphdr *th, u16 *mssp); +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + /* tcp_output.c */ + +@@ -579,10 +699,17 @@ + void tcp_skb_collapse_tstamp(struct sk_buff *skb, + const struct sk_buff *next_skb); + ++u16 tcp_select_window(struct sock *sk); ++int select_size(const struct sock *sk, bool sg, bool first_skb); ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ + /* tcp_input.c */ + void tcp_rearm_rto(struct sock *sk); + void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); + void tcp_reset(struct sock *sk); ++void tcp_set_rto(struct sock *sk); ++bool tcp_should_expand_sndbuf(const struct sock *sk); + void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); + void tcp_fin(struct sock *sk); + +@@ -621,7 +748,7 @@ + } + + /* tcp.c */ +-void tcp_get_info(struct sock *, struct tcp_info *); ++void tcp_get_info(struct sock *, struct tcp_info *, bool no_lock); + + /* Read 'sendfile()'-style from a TCP socket */ + int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, +@@ -815,6 +942,12 @@ + */ + ktime_t swtstamp; + }; ++ ++#ifdef CONFIG_MPTCP ++ __u8 mptcp_flags; /* flags for the MPTCP layer */ ++ __u8 dss_off; /* Number of 4-byte words until ++ * seq-number */ ++#endif + __u8 tcp_flags; /* TCP header flags. (tcp[13]) */ + + __u8 sacked; /* State flags for SACK/FACK. */ +@@ -833,6 +966,14 @@ + has_rxtstamp:1, /* SKB has a RX timestamp */ + unused:5; + __u32 ack_seq; /* Sequence number ACK'd */ ++ ++#ifdef CONFIG_MPTCP ++ union { /* For MPTCP outgoing frames */ ++ __u32 path_mask; /* paths that tried to send this skb */ ++ __u32 dss[6]; /* DSS options */ ++ }; ++#endif ++ + union { + struct { + /* There is space for up to 24 bytes */ +@@ -1053,6 +1194,8 @@ + int tcp_set_allowed_congestion_control(char *allowed); + int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, + bool reinit, bool cap_net_admin); ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); + u32 tcp_slow_start(struct tcp_sock *tp, u32 acked); + void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked); + +@@ -1335,7 +1478,8 @@ + /* Determine a window scaling and initial window to offer. */ + void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, + __u32 *window_clamp, int wscale_ok, +- __u8 *rcv_wscale, __u32 init_rcv_wnd); ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); + + static inline int tcp_win_from_space(int space) + { +@@ -1346,6 +1490,19 @@ + space - (space>>tcp_adv_win_scale); + } + ++#ifdef CONFIG_MPTCP ++extern struct static_key mptcp_static_key; ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return static_key_false(&mptcp_static_key) && tp->mpc; ++} ++#else ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++#endif ++ + /* Note: caller must be prepared to deal with negative returns */ + static inline int tcp_space(const struct sock *sk) + { +@@ -1622,19 +1779,7 @@ + } + + /* write queue abstraction */ +-static inline void tcp_write_queue_purge(struct sock *sk) +-{ +- struct sk_buff *skb; +- +- tcp_chrono_stop(sk, TCP_CHRONO_BUSY); +- while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) +- sk_wmem_free_skb(sk, skb); +- sk_mem_reclaim(sk); +- tcp_clear_all_retrans_hints(tcp_sk(sk)); +- tcp_init_send_head(sk); +- tcp_sk(sk)->packets_out = 0; +- inet_csk(sk)->icsk_backoff = 0; +-} ++void tcp_write_queue_purge(struct sock *sk); + + static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk) + { +@@ -1918,6 +2063,32 @@ + #endif + }; + ++/* TCP/MPTCP-specific functions */ ++struct tcp_sock_ops { ++ u32 (*__select_window)(struct sock *sk); ++ u16 (*select_window)(struct sock *sk); ++ void (*select_initial_window)(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); ++ int (*select_size)(const struct sock *sk, bool sg, bool first_skb); ++ void (*init_buffer_space)(struct sock *sk); ++ void (*set_rto)(struct sock *sk); ++ bool (*should_expand_sndbuf)(const struct sock *sk); ++ void (*send_fin)(struct sock *sk); ++ bool (*write_xmit)(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ void (*send_active_reset)(struct sock *sk, gfp_t priority); ++ int (*write_wakeup)(struct sock *sk, int mib); ++ void (*retransmit_timer)(struct sock *sk); ++ void (*time_wait)(struct sock *sk, int state, int timeo); ++ void (*cleanup_rbuf)(struct sock *sk, int copied); ++ void (*cwnd_validate)(struct sock *sk, bool is_cwnd_limited); ++ int (*set_cong_ctrl)(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); ++}; ++extern const struct tcp_sock_ops tcp_specific; ++ + struct tcp_request_sock_ops { + u16 mss_clamp; + #ifdef CONFIG_TCP_MD5SIG +@@ -1928,12 +2099,13 @@ + const struct sock *sk, + const struct sk_buff *skb); + #endif +- void (*init_req)(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb); ++ int (*init_req)(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie); + #ifdef CONFIG_SYN_COOKIES +- __u32 (*cookie_init_seq)(const struct sk_buff *skb, +- __u16 *mss); ++ __u32 (*cookie_init_seq)(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, + const struct request_sock *req); +@@ -1947,15 +2119,17 @@ + + #ifdef CONFIG_SYN_COOKIES + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { + tcp_synq_overflow(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); +- return ops->cookie_init_seq(skb, mss); ++ return ops->cookie_init_seq(req, sk, skb, mss); + } + #else + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { +diff -aurN linux-4.14.174/include/net/tcp_states.h mptcp-mptcp_v0.94/include/net/tcp_states.h +--- linux-4.14.174/include/net/tcp_states.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/tcp_states.h 2020-03-23 09:45:33.000000000 +0100 +@@ -26,6 +26,7 @@ + TCP_LISTEN, + TCP_CLOSING, /* Now a valid state */ + TCP_NEW_SYN_RECV, ++ TCP_RST_WAIT, + + TCP_MAX_STATES /* Leave at the end! */ + }; +@@ -47,6 +48,7 @@ + TCPF_LISTEN = (1 << 10), + TCPF_CLOSING = (1 << 11), + TCPF_NEW_SYN_RECV = (1 << 12), ++ TCPF_RST_WAIT = (1 << 13), + }; + + #endif /* _LINUX_TCP_STATES_H */ +diff -aurN linux-4.14.174/include/net/transp_v6.h mptcp-mptcp_v0.94/include/net/transp_v6.h +--- linux-4.14.174/include/net/transp_v6.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/net/transp_v6.h 2020-03-23 09:45:33.000000000 +0100 +@@ -59,6 +59,8 @@ + + /* address family specific functions */ + extern const struct inet_connection_sock_af_ops ipv4_specific; ++extern const struct inet_connection_sock_af_ops ipv6_mapped; ++extern const struct inet_connection_sock_af_ops ipv6_specific; + + void inet6_destroy_sock(struct sock *sk); + +diff -aurN linux-4.14.174/include/uapi/linux/if.h mptcp-mptcp_v0.94/include/uapi/linux/if.h +--- linux-4.14.174/include/uapi/linux/if.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/uapi/linux/if.h 2020-03-23 09:45:33.000000000 +0100 +@@ -132,6 +132,9 @@ + #define IFF_ECHO IFF_ECHO + #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + ++#define IFF_NOMULTIPATH 0x80000 /* Disable for MPTCP */ ++#define IFF_MPBACKUP 0x100000 /* Use as backup path for MPTCP */ ++ + #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +diff -aurN linux-4.14.174/include/uapi/linux/tcp.h mptcp-mptcp_v0.94/include/uapi/linux/tcp.h +--- linux-4.14.174/include/uapi/linux/tcp.h 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/include/uapi/linux/tcp.h 2020-03-23 09:45:33.000000000 +0100 +@@ -18,9 +18,15 @@ + #ifndef _UAPI_LINUX_TCP_H + #define _UAPI_LINUX_TCP_H + +-#include ++#ifndef __KERNEL__ ++#include ++#endif ++ + #include ++#include ++#include + #include ++#include + + struct tcphdr { + __be16 source; +@@ -120,6 +126,12 @@ + #define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect */ + #define TCP_ULP 31 /* Attach a ULP to a TCP connection */ + #define TCP_MD5SIG_EXT 32 /* TCP MD5 Signature with extensions */ ++#define MPTCP_ENABLED 42 ++#define MPTCP_SCHEDULER 43 ++#define MPTCP_PATH_MANAGER 44 ++#define MPTCP_INFO 45 ++ ++#define MPTCP_INFO_FLAG_SAVE_MASTER 0x01 + + struct tcp_repair_opt { + __u32 opt_code; +@@ -242,6 +254,53 @@ + + }; + ++struct mptcp_meta_info { ++ __u8 mptcpi_state; ++ __u8 mptcpi_retransmits; ++ __u8 mptcpi_probes; ++ __u8 mptcpi_backoff; ++ ++ __u32 mptcpi_rto; ++ __u32 mptcpi_unacked; ++ ++ /* Times. */ ++ __u32 mptcpi_last_data_sent; ++ __u32 mptcpi_last_data_recv; ++ __u32 mptcpi_last_ack_recv; ++ ++ __u32 mptcpi_total_retrans; ++ ++ __u64 mptcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ ++ __u64 mptcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ ++}; ++ ++struct mptcp_sub_info { ++ union { ++ struct sockaddr src; ++ struct sockaddr_in src_v4; ++ struct sockaddr_in6 src_v6; ++ }; ++ ++ union { ++ struct sockaddr dst; ++ struct sockaddr_in dst_v4; ++ struct sockaddr_in6 dst_v6; ++ }; ++}; ++ ++struct mptcp_info { ++ __u32 tcp_info_len; /* Length of each struct tcp_info in subflows pointer */ ++ __u32 sub_len; /* Total length of memory pointed to by subflows pointer */ ++ __u32 meta_len; /* Length of memory pointed to by meta_info */ ++ __u32 sub_info_len; /* Length of each struct mptcp_sub_info in subflow_info pointer */ ++ __u32 total_sub_info_len; /* Total length of memory pointed to by subflow_info */ ++ ++ struct mptcp_meta_info *meta_info; ++ struct tcp_info *initial; ++ struct tcp_info *subflows; /* Pointer to array of tcp_info structs */ ++ struct mptcp_sub_info *subflow_info; ++}; ++ + /* for TCP_MD5SIG socket option */ + #define TCP_MD5SIG_MAXKEYLEN 80 + +diff -aurN linux-4.14.174/kernel/rcu/Kconfig.debug mptcp-mptcp_v0.94/kernel/rcu/Kconfig.debug +--- linux-4.14.174/kernel/rcu/Kconfig.debug 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/kernel/rcu/Kconfig.debug 2020-03-23 09:45:33.000000000 +0100 +@@ -4,9 +4,6 @@ + + menu "RCU Debugging" + +-config PROVE_RCU +- def_bool PROVE_LOCKING +- + config TORTURE_TEST + tristate + default n +diff -aurN linux-4.14.174/net/core/dev.c mptcp-mptcp_v0.94/net/core/dev.c +--- linux-4.14.174/net/core/dev.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/core/dev.c 2020-03-23 09:45:33.000000000 +0100 +@@ -6769,7 +6769,7 @@ + + dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | + IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | +- IFF_AUTOMEDIA)) | ++ IFF_AUTOMEDIA | IFF_NOMULTIPATH | IFF_MPBACKUP)) | + (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | + IFF_ALLMULTI)); + +diff -aurN linux-4.14.174/net/core/skbuff.c mptcp-mptcp_v0.94/net/core/skbuff.c +--- linux-4.14.174/net/core/skbuff.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/core/skbuff.c 2020-03-23 09:45:33.000000000 +0100 +@@ -536,7 +536,7 @@ + skb_drop_list(&skb_shinfo(skb)->frag_list); + } + +-static void skb_clone_fraglist(struct sk_buff *skb) ++void skb_clone_fraglist(struct sk_buff *skb) + { + struct sk_buff *list; + +@@ -1305,7 +1305,7 @@ + skb->inner_mac_header += off; + } + +-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) + { + __copy_skb_header(new, old); + +diff -aurN linux-4.14.174/net/core/sock.c mptcp-mptcp_v0.94/net/core/sock.c +--- linux-4.14.174/net/core/sock.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/core/sock.c 2020-03-23 09:45:33.000000000 +0100 +@@ -139,6 +139,11 @@ + + #include + ++#ifdef CONFIG_MPTCP ++#include ++#include ++#endif ++ + #include + #include + +@@ -1413,6 +1418,23 @@ + */ + static inline void sock_lock_init(struct sock *sk) + { ++#ifdef CONFIG_MPTCP ++ /* Reclassify the lock-class for subflows */ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ if (mptcp(tcp_sk(sk)) || tcp_sk(sk)->is_master_sk) { ++ sock_lock_init_class_and_name(sk, meta_slock_key_name, ++ &meta_slock_key, ++ meta_key_name, ++ &meta_key); ++ ++ /* We don't yet have the mptcp-point. ++ * Thus we still need inet_sock_destruct ++ */ ++ sk->sk_destruct = inet_sock_destruct; ++ return; ++ } ++#endif ++ + if (sk->sk_kern_sock) + sock_lock_init_class_and_name( + sk, +@@ -1461,8 +1483,12 @@ + sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); + if (!sk) + return sk; +- if (priority & __GFP_ZERO) +- sk_prot_clear_nulls(sk, prot->obj_size); ++ if (priority & __GFP_ZERO) { ++ if (prot->clear_sk) ++ prot->clear_sk(sk, prot->obj_size); ++ else ++ sk_prot_clear_nulls(sk, prot->obj_size); ++ } + } else + sk = kmalloc(prot->obj_size, priority); + +@@ -1684,6 +1710,7 @@ + atomic_set(&newsk->sk_zckey, 0); + + sock_reset_flag(newsk, SOCK_DONE); ++ sock_reset_flag(newsk, SOCK_MPTCP); + + /* sk->sk_memcg will be populated at accept() time */ + newsk->sk_memcg = NULL; +diff -aurN linux-4.14.174/net/ipv4/af_inet.c mptcp-mptcp_v0.94/net/ipv4/af_inet.c +--- linux-4.14.174/net/ipv4/af_inet.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/af_inet.c 2020-03-23 09:45:33.000000000 +0100 +@@ -104,6 +104,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -149,6 +150,9 @@ + return; + } + ++ if (sock_flag(sk, SOCK_MPTCP)) ++ mptcp_disable_static_key(); ++ + WARN_ON(atomic_read(&sk->sk_rmem_alloc)); + WARN_ON(refcount_read(&sk->sk_wmem_alloc)); + WARN_ON(sk->sk_wmem_queued); +@@ -241,8 +245,7 @@ + * Create an inet socket. + */ + +-static int inet_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct sock *sk; + struct inet_protosw *answer; +@@ -702,6 +705,23 @@ + lock_sock(sk2); + + sock_rps_record_flow(sk2); ++ ++ if (sk2->sk_protocol == IPPROTO_TCP && mptcp(tcp_sk(sk2))) { ++ struct sock *sk_it = sk2; ++ ++ mptcp_for_each_sk(tcp_sk(sk2)->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ ++ if (tcp_sk(sk2)->mpcb->master_sk) { ++ sk_it = tcp_sk(sk2)->mpcb->master_sk; ++ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_it->sk_wq = newsock->wq; ++ sk_it->sk_socket = newsock; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ } ++ + WARN_ON(!((1 << sk2->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | + TCPF_CLOSE_WAIT | TCPF_CLOSE))); +@@ -1883,6 +1903,9 @@ + + ip_init(); + ++ /* We must initialize MPTCP before TCP. */ ++ mptcp_init(); ++ + /* Setup TCP slab cache for open requests. */ + tcp_init(); + +diff -aurN linux-4.14.174/net/ipv4/inet_connection_sock.c mptcp-mptcp_v0.94/net/ipv4/inet_connection_sock.c +--- linux-4.14.174/net/ipv4/inet_connection_sock.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/inet_connection_sock.c 2020-03-23 09:45:33.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -709,7 +710,10 @@ + int max_retries, thresh; + u8 defer_accept; + +- if (sk_state_load(sk_listener) != TCP_LISTEN) ++ if (sk_state_load(sk_listener) != TCP_LISTEN && !is_meta_sk(sk_listener)) ++ goto drop; ++ ++ if (is_meta_sk(sk_listener) && !mptcp_can_new_subflow(sk_listener)) + goto drop; + + max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; +@@ -803,7 +807,9 @@ + const struct request_sock *req, + const gfp_t priority) + { +- struct sock *newsk = sk_clone_lock(sk, priority); ++ struct sock *newsk; ++ ++ newsk = sk_clone_lock(sk, priority); + + if (newsk) { + struct inet_connection_sock *newicsk = inet_csk(newsk); +@@ -1003,7 +1009,14 @@ + */ + while ((req = reqsk_queue_remove(queue, sk)) != NULL) { + struct sock *child = req->sk; ++ bool mutex_taken = false; ++ struct mptcp_cb *mpcb = tcp_sk(child)->mpcb; + ++ if (is_meta_sk(child)) { ++ WARN_ON(atomic_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ mutex_taken = true; ++ } + local_bh_disable(); + bh_lock_sock(child); + WARN_ON(sock_owned_by_user(child)); +@@ -1013,6 +1026,10 @@ + reqsk_put(req); + bh_unlock_sock(child); + local_bh_enable(); ++ if (mutex_taken) { ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ } + sock_put(child); + + cond_resched(); +diff -aurN linux-4.14.174/net/ipv4/ip_sockglue.c mptcp-mptcp_v0.94/net/ipv4/ip_sockglue.c +--- linux-4.14.174/net/ipv4/ip_sockglue.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/ip_sockglue.c 2020-03-23 09:45:33.000000000 +0100 +@@ -44,6 +44,8 @@ + #endif + #include + ++#include ++ + #include + #include + +@@ -658,7 +660,7 @@ + break; + old = rcu_dereference_protected(inet->inet_opt, + lockdep_sock_is_held(sk)); +- if (inet->is_icsk) { ++ if (inet->is_icsk && !is_meta_sk(sk)) { + struct inet_connection_sock *icsk = inet_csk(sk); + #if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family == PF_INET || +@@ -752,6 +754,17 @@ + inet->tos = val; + sk->sk_priority = rt_tos2priority(val); + sk_dst_reset(sk); ++ /* Update TOS on mptcp subflow */ ++ if (is_meta_sk(sk)) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) { ++ if (inet_sk(sk_it)->tos != inet_sk(sk)->tos) { ++ inet_sk(sk_it)->tos = inet_sk(sk)->tos; ++ sk_it->sk_priority = sk->sk_priority; ++ sk_dst_reset(sk_it); ++ } ++ } ++ } + } + break; + case IP_TTL: +diff -aurN linux-4.14.174/net/ipv4/Kconfig mptcp-mptcp_v0.94/net/ipv4/Kconfig +--- linux-4.14.174/net/ipv4/Kconfig 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/Kconfig 2020-03-23 09:45:33.000000000 +0100 +@@ -675,6 +675,38 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_LIA ++ tristate "MPTCP Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Linked Increase Congestion Control ++ To enable it, just put 'lia' in tcp_congestion_control ++ ++config TCP_CONG_OLIA ++ tristate "MPTCP Opportunistic Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Opportunistic Linked Increase Congestion Control ++ To enable it, just put 'olia' in tcp_congestion_control ++ ++config TCP_CONG_WVEGAS ++ tristate "MPTCP WVEGAS CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ wVegas congestion control for MPTCP ++ To enable it, just put 'wvegas' in tcp_congestion_control ++ ++config TCP_CONG_BALIA ++ tristate "MPTCP BALIA CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ Multipath TCP Balanced Linked Adaptation Congestion Control ++ To enable it, just put 'balia' in tcp_congestion_control ++ + choice + prompt "Default TCP congestion control" + default DEFAULT_CUBIC +@@ -712,6 +744,18 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_LIA ++ bool "Lia" if TCP_CONG_LIA=y ++ ++ config DEFAULT_OLIA ++ bool "Olia" if TCP_CONG_OLIA=y ++ ++ config DEFAULT_WVEGAS ++ bool "Wvegas" if TCP_CONG_WVEGAS=y ++ ++ config DEFAULT_BALIA ++ bool "Balia" if TCP_CONG_BALIA=y ++ + config DEFAULT_RENO + bool "Reno" + endchoice +@@ -732,6 +776,10 @@ + default "vegas" if DEFAULT_VEGAS + default "westwood" if DEFAULT_WESTWOOD + default "veno" if DEFAULT_VENO ++ default "lia" if DEFAULT_LIA ++ default "olia" if DEFAULT_OLIA ++ default "wvegas" if DEFAULT_WVEGAS ++ default "balia" if DEFAULT_BALIA + default "reno" if DEFAULT_RENO + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG +diff -aurN linux-4.14.174/net/ipv4/syncookies.c mptcp-mptcp_v0.94/net/ipv4/syncookies.c +--- linux-4.14.174/net/ipv4/syncookies.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/syncookies.c 2020-03-23 09:45:33.000000000 +0100 +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -179,7 +181,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); + +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct iphdr *iph = ip_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -209,9 +212,27 @@ + struct inet_connection_sock *icsk = inet_csk(sk); + struct sock *child; + bool own_req; ++#ifdef CONFIG_MPTCP ++ int ret; ++#endif + + child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst, + NULL, &own_req); ++ ++#ifdef CONFIG_MPTCP ++ if (!child) ++ goto listen_overflow; ++ ++ ret = mptcp_check_req_master(sk, child, req, skb, 0, tsoff); ++ if (ret < 0) ++ return NULL; ++ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ ++listen_overflow: ++#endif ++ + if (child) { + refcount_set(&req->rsk_refcnt, 1); + tcp_sk(child)->tsoffset = tsoff; +@@ -289,6 +310,7 @@ + { + struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct tcp_sock *tp = tcp_sk(sk); +@@ -318,7 +340,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcp_ts_off(sock_net(sk), +@@ -331,7 +354,12 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp_request_sock_ops, sk, false); /* for safety */ ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ + if (!req) + goto out; + +@@ -351,12 +379,17 @@ + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + treq->snt_synack = 0; + treq->tfo_listener = false; + + ireq->ir_iif = inet_request_bound_dev_if(sk, skb); + ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + /* We throwed the options of the initial SYN away, so we hope + * the ACK carries the same options again (see RFC1122 4.2.3.8) + */ +@@ -390,10 +423,10 @@ + /* Try to redo what tcp_v4_send_synack did. */ + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); + +- tcp_select_initial_window(tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(&rt->dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(&rt->dst, RTAX_INITRWND), sk); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); +diff -aurN linux-4.14.174/net/ipv4/tcp.c mptcp-mptcp_v0.94/net/ipv4/tcp.c +--- linux-4.14.174/net/ipv4/tcp.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp.c 2020-03-23 09:45:33.000000000 +0100 +@@ -273,6 +273,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -402,6 +403,25 @@ + return rate64; + } + ++const struct tcp_sock_ops tcp_specific = { ++ .__select_window = __tcp_select_window, ++ .select_window = tcp_select_window, ++ .select_initial_window = tcp_select_initial_window, ++ .select_size = select_size, ++ .init_buffer_space = tcp_init_buffer_space, ++ .set_rto = tcp_set_rto, ++ .should_expand_sndbuf = tcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = tcp_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .cwnd_validate = tcp_cwnd_validate, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ + /* Address-family independent initialization for a tcp_sock. + * + * NOTE: A lot of things set to zero explicitly by call to +@@ -452,6 +472,11 @@ + sk->sk_sndbuf = sysctl_tcp_wmem[1]; + sk->sk_rcvbuf = sysctl_tcp_rmem[1]; + ++ tp->ops = &tcp_specific; ++ ++ /* Initialize MPTCP-specific stuff and function-pointers */ ++ mptcp_init_tcp_sock(sk); ++ + sk_sockets_allocated_inc(sk); + } + EXPORT_SYMBOL(tcp_init_sock); +@@ -766,6 +791,7 @@ + int ret; + + sock_rps_record_flow(sk); ++ + /* + * We can't seek on a socket input + */ +@@ -776,6 +802,14 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tcp_sk(sk))) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++#endif ++ + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); + while (tss.len) { + ret = __tcp_splice_read(sk, &tss); +@@ -879,8 +913,7 @@ + return NULL; + } + +-static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, +- int large_allowed) ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, int large_allowed) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 new_size_goal, size_goal; +@@ -908,8 +941,13 @@ + { + int mss_now; + +- mss_now = tcp_current_mss(sk); +- *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ if (mptcp(tcp_sk(sk))) { ++ mss_now = mptcp_current_mss(sk); ++ *size_goal = mptcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } else { ++ mss_now = tcp_current_mss(sk); ++ *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } + + return mss_now; + } +@@ -944,12 +982,33 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto out_err; + } + ++ if (mptcp(tp)) { ++ struct sock *sk_it = sk; ++ ++ /* We must check this with socket-lock hold because we iterate ++ * over the subflows. ++ */ ++ if (!mptcp_can_sendpage(sk)) { ++ ssize_t ret; ++ ++ release_sock(sk); ++ ret = sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ lock_sock(sk); ++ return ret; ++ } ++ ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++ + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + + mss_now = tcp_send_mss(sk, &size_goal, flags); +@@ -1067,8 +1126,9 @@ + int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, + size_t size, int flags) + { +- if (!(sk->sk_route_caps & NETIF_F_SG) || +- !sk_check_csum_caps(sk)) ++ /* If MPTCP is enabled, we check it later after establishment */ ++ if (!mptcp(tcp_sk(sk)) && (!(sk->sk_route_caps & NETIF_F_SG) || ++ !sk_check_csum_caps(sk))) + return sock_no_sendpage_locked(sk, page, offset, size, flags); + + tcp_rate_check_app_limited(sk); /* is sending application-limited? */ +@@ -1100,14 +1160,14 @@ + * This also speeds up tso_fragment(), since it wont fallback + * to tcp_fragment(). + */ +-static int linear_payload_sz(bool first_skb) ++int linear_payload_sz(bool first_skb) + { + if (first_skb) + return SKB_WITH_OVERHEAD(2048 - MAX_TCP_HEADER); + return 0; + } + +-static int select_size(const struct sock *sk, bool sg, bool first_skb) ++int select_size(const struct sock *sk, bool sg, bool first_skb) + { + const struct tcp_sock *tp = tcp_sk(sk); + int tmp = tp->mss_cache; +@@ -1229,12 +1289,19 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto do_error; + } + ++ if (mptcp(tp)) { ++ struct sock *sk_it = sk; ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++ + if (unlikely(tp->repair)) { + if (tp->repair_queue == TCP_RECV_QUEUE) { + copied = tcp_send_rcvq(sk, msg, size); +@@ -1270,7 +1337,10 @@ + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + goto do_error; + +- sg = !!(sk->sk_route_caps & NETIF_F_SG); ++ if (mptcp(tp)) ++ sg = mptcp_can_sg(sk); ++ else ++ sg = !!(sk->sk_route_caps & NETIF_F_SG); + + while (msg_data_left(msg)) { + int copy = 0; +@@ -1299,7 +1369,7 @@ + } + first_skb = skb_queue_empty(&sk->sk_write_queue); + skb = sk_stream_alloc_skb(sk, +- select_size(sk, sg, first_skb), ++ tp->ops->select_size(sk, sg, first_skb), + sk->sk_allocation, + first_skb); + if (!skb) +@@ -1308,8 +1378,15 @@ + process_backlog = true; + /* + * Check whether we can use HW checksum. ++ * ++ * If dss-csum is enabled, we do not do hw-csum. ++ * In case of non-mptcp we check the ++ * device-capabilities. ++ * In case of mptcp, hw-csum's will be handled ++ * later in mptcp_write_xmit. + */ +- if (sk_check_csum_caps(sk)) ++ if (((mptcp(tp) && !tp->mpcb->dss_csum) || !mptcp(tp)) && ++ (mptcp(tp) || sk_check_csum_caps(sk))) + skb->ip_summed = CHECKSUM_PARTIAL; + + skb_entail(sk, skb); +@@ -1534,7 +1611,7 @@ + * calculation of whether or not we must ACK for the sake of + * a window update. + */ +-static void tcp_cleanup_rbuf(struct sock *sk, int copied) ++void tcp_cleanup_rbuf(struct sock *sk, int copied) + { + struct tcp_sock *tp = tcp_sk(sk); + bool time_to_ack = false; +@@ -1577,7 +1654,7 @@ + + /* Optimize, __tcp_select_window() is not cheap. */ + if (2*rcv_window_now <= tp->window_clamp) { +- __u32 new_window = __tcp_select_window(sk); ++ __u32 new_window = tp->ops->__select_window(sk); + + /* Send ACK now, if this read freed lots of space + * in our buffer. Certainly, new_window is new window. +@@ -1693,7 +1770,7 @@ + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) { + tcp_recv_skb(sk, seq, &offset); +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + } + return copied; + } +@@ -1793,6 +1870,14 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tp)) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++#endif ++ + err = -ENOTCONN; + if (sk->sk_state == TCP_LISTEN) + goto out; +@@ -1913,7 +1998,7 @@ + } + } + +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + if (copied >= target) { + /* Do not sleep, just process backlog. */ +@@ -2006,7 +2091,7 @@ + tcp_recv_timestamp(msg, sk, &tss); + + /* Clean up data we have read: This will do ACK frames. */ +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + release_sock(sk); + return copied; +@@ -2084,7 +2169,7 @@ + [TCP_NEW_SYN_RECV] = TCP_CLOSE, /* should not happen ! */ + }; + +-static int tcp_close_state(struct sock *sk) ++int tcp_close_state(struct sock *sk) + { + int next = (int)new_state[sk->sk_state]; + int ns = next & TCP_STATE_MASK; +@@ -2114,7 +2199,7 @@ + TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { + /* Clear out any half completed packets. FIN if needed. */ + if (tcp_close_state(sk)) +- tcp_send_fin(sk); ++ tcp_sk(sk)->ops->send_fin(sk); + } + } + EXPORT_SYMBOL(tcp_shutdown); +@@ -2139,6 +2224,17 @@ + int data_was_unread = 0; + int state; + ++ if (is_meta_sk(sk)) { ++ /* TODO: Currently forcing timeout to 0 because ++ * sk_stream_wait_close will complain during lockdep because ++ * of the mpcb_mutex (circular lock dependency through ++ * inet_csk_listen_stop()). ++ * We should find a way to get rid of the mpcb_mutex. ++ */ ++ mptcp_close(sk, 0); ++ return; ++ } ++ + lock_sock(sk); + sk->sk_shutdown = SHUTDOWN_MASK; + +@@ -2183,7 +2279,7 @@ + /* Unread data was tossed, zap the connection. */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, sk->sk_allocation); ++ tcp_sk(sk)->ops->send_active_reset(sk, sk->sk_allocation); + } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + /* Check zero linger _after_ checking for unread data. */ + sk->sk_prot->disconnect(sk, 0); +@@ -2257,7 +2353,7 @@ + struct tcp_sock *tp = tcp_sk(sk); + if (tp->linger2 < 0) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONLINGER); + } else { +@@ -2267,7 +2363,8 @@ + inet_csk_reset_keepalive_timer(sk, + tmo - TCP_TIMEWAIT_LEN); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_FIN_WAIT2, ++ tmo); + goto out; + } + } +@@ -2276,7 +2373,7 @@ + sk_mem_reclaim(sk); + if (tcp_check_oom(sk, 0)) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { +@@ -2305,15 +2402,6 @@ + } + EXPORT_SYMBOL(tcp_close); + +-/* These states need RST on ABORT according to RFC793 */ +- +-static inline bool tcp_need_reset(int state) +-{ +- return (1 << state) & +- (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | +- TCPF_FIN_WAIT2 | TCPF_SYN_RECV); +-} +- + int tcp_disconnect(struct sock *sk, int flags) + { + struct inet_sock *inet = inet_sk(sk); +@@ -2336,7 +2424,7 @@ + /* The last check adjusts for discrepancy of Linux wrt. RFC + * states + */ +- tcp_send_active_reset(sk, gfp_any()); ++ tp->ops->send_active_reset(sk, gfp_any()); + sk->sk_err = ECONNRESET; + } else if (old_state == TCP_SYN_SENT) + sk->sk_err = ECONNRESET; +@@ -2352,6 +2440,13 @@ + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) + inet_reset_saddr(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_disconnect(sk); ++ } else { ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ + sk->sk_shutdown = 0; + sock_reset_flag(sk, SOCK_DONE); + tp->srtt_us = 0; +@@ -2406,7 +2501,7 @@ + static inline bool tcp_can_repair_sock(const struct sock *sk) + { + return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && +- (sk->sk_state != TCP_LISTEN); ++ (sk->sk_state != TCP_LISTEN) && !sock_flag(sk, SOCK_MPTCP); + } + + static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) +@@ -2543,6 +2638,61 @@ + release_sock(sk); + return err; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: { ++ char name[MPTCP_SCHED_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_SCHED_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_scheduler(sk, name); ++ release_sock(sk); ++ return err; ++ } ++ ++ case MPTCP_PATH_MANAGER: { ++ char name[MPTCP_PM_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_PM_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_path_manager(sk, name); ++ release_sock(sk); ++ return err; ++ } ++#endif + default: + /* fallthru */ + break; +@@ -2720,6 +2870,12 @@ + break; + + case TCP_DEFER_ACCEPT: ++ /* An established MPTCP-connection (mptcp(tp) only returns true ++ * if the socket is established) should not use DEFER on new ++ * subflows. ++ */ ++ if (mptcp(tp)) ++ break; + /* Translate value in seconds to number of retransmits */ + icsk->icsk_accept_queue.rskq_defer_accept = + secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, +@@ -2747,7 +2903,7 @@ + (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && + inet_csk_ack_scheduled(sk)) { + icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; +- tcp_cleanup_rbuf(sk, 1); ++ tp->ops->cleanup_rbuf(sk, 1); + if (!(val & 1)) + icsk->icsk_ack.pingpong = 1; + } +@@ -2757,7 +2913,7 @@ + #ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: + case TCP_MD5SIG_EXT: +- if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ++ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN) && !sock_flag(sk, SOCK_MPTCP)) + err = tp->af_specific->md5_parse(sk, optname, optval, optlen); + else + err = -EINVAL; +@@ -2808,6 +2964,32 @@ + tp->notsent_lowat = val; + sk->sk_write_space(sk); + break; ++#ifdef CONFIG_MPTCP ++ case MPTCP_ENABLED: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE ++#ifdef CONFIG_TCP_MD5SIG ++ || tp->md5sig_info ++#endif ++ ) { ++ err = -EPERM; ++ break; ++ } ++ ++ if (val) ++ mptcp_enable_sock(sk); ++ else ++ mptcp_disable_sock(sk); ++ break; ++ case MPTCP_INFO: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled) { ++ err = -EPERM; ++ break; ++ } ++ ++ tp->record_master_info = !!(val & MPTCP_INFO_FLAG_SAVE_MASTER); ++ break; ++#endif + default: + err = -ENOPROTOOPT; + break; +@@ -2861,7 +3043,7 @@ + } + + /* Return information about state of tcp endpoint in API format. */ +-void tcp_get_info(struct sock *sk, struct tcp_info *info) ++void tcp_get_info(struct sock *sk, struct tcp_info *info, bool no_lock) + { + const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ + const struct inet_connection_sock *icsk = inet_csk(sk); +@@ -2898,7 +3080,8 @@ + return; + } + +- slow = lock_sock_fast(sk); ++ if (!no_lock) ++ slow = lock_sock_fast(sk); + + info->tcpi_ca_state = icsk->icsk_ca_state; + info->tcpi_retransmits = icsk->icsk_retransmits; +@@ -2967,7 +3150,9 @@ + rate64 = tcp_compute_delivery_rate(tp); + if (rate64) + info->tcpi_delivery_rate = rate64; +- unlock_sock_fast(sk, slow); ++ ++ if (!no_lock) ++ unlock_sock_fast(sk, slow); + } + EXPORT_SYMBOL_GPL(tcp_get_info); + +@@ -3073,7 +3258,7 @@ + if (get_user(len, optlen)) + return -EFAULT; + +- tcp_get_info(sk, &info); ++ tcp_get_info(sk, &info, false); + + len = min_t(unsigned int, len, sizeof(info)); + if (put_user(len, optlen)) +@@ -3235,6 +3420,87 @@ + } + return 0; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_SCHED_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->sched_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_sched_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_PATH_MANAGER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_PM_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->pm_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_pm_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_ENABLED: ++ if (sk->sk_state != TCP_SYN_SENT) ++ val = mptcp(tp) ? 1 : 0; ++ else ++ val = sock_flag(sk, SOCK_MPTCP) ? 1 : 0; ++ break; ++ case MPTCP_INFO: ++ { ++ int ret; ++ ++ if (!mptcp(tp)) ++ return -EINVAL; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(struct mptcp_info)); ++ ++ lock_sock(sk); ++ ret = mptcp_get_info(sk, optval, len); ++ release_sock(sk); ++ ++ if (ret) ++ return ret; ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ return 0; ++ } ++#endif + default: + return -ENOPROTOOPT; + } +@@ -3409,7 +3675,9 @@ + if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); + ++ WARN_ON(sk->sk_state == TCP_CLOSE); + tcp_set_state(sk, TCP_CLOSE); ++ + tcp_clear_xmit_timers(sk); + if (req) + reqsk_fastopen_remove(sk, req, false); +@@ -3425,6 +3693,8 @@ + + int tcp_abort(struct sock *sk, int err) + { ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; ++ + if (!sk_fullsock(sk)) { + if (sk->sk_state == TCP_NEW_SYN_RECV) { + struct request_sock *req = inet_reqsk(sk); +@@ -3438,7 +3708,7 @@ + } + + /* Don't race with userspace socket closes such as tcp_close. */ +- lock_sock(sk); ++ lock_sock(meta_sk); + + if (sk->sk_state == TCP_LISTEN) { + tcp_set_state(sk, TCP_CLOSE); +@@ -3447,7 +3717,7 @@ + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); +- bh_lock_sock(sk); ++ bh_lock_sock(meta_sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = err; +@@ -3455,14 +3725,14 @@ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + local_bh_enable(); + tcp_write_queue_purge(sk); +- release_sock(sk); ++ release_sock(meta_sk); + return 0; + } + EXPORT_SYMBOL_GPL(tcp_abort); +diff -aurN linux-4.14.174/net/ipv4/tcp_cong.c mptcp-mptcp_v0.94/net/ipv4/tcp_cong.c +--- linux-4.14.174/net/ipv4/tcp_cong.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_cong.c 2020-03-23 09:45:33.000000000 +0100 +@@ -333,13 +333,19 @@ + return ret; + } + ++int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) ++{ ++ return tcp_sk(sk)->ops->set_cong_ctrl(sk, name, load, reinit, cap_net_admin); ++} ++ + /* Change congestion control for socket. If load is false, then it is the + * responsibility of the caller to call tcp_init_congestion_control or + * tcp_reinit_congestion_control (if the current congestion control was + * already initialized. + */ +-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, +- bool reinit, bool cap_net_admin) ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) + { + struct inet_connection_sock *icsk = inet_csk(sk); + const struct tcp_congestion_ops *ca; +diff -aurN linux-4.14.174/net/ipv4/tcp_diag.c mptcp-mptcp_v0.94/net/ipv4/tcp_diag.c +--- linux-4.14.174/net/ipv4/tcp_diag.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_diag.c 2020-03-23 09:45:33.000000000 +0100 +@@ -34,7 +34,7 @@ + r->idiag_wqueue = tp->write_seq - tp->snd_una; + } + if (info) +- tcp_get_info(sk, info); ++ tcp_get_info(sk, info, false); + } + + #ifdef CONFIG_TCP_MD5SIG +diff -aurN linux-4.14.174/net/ipv4/tcp_fastopen.c mptcp-mptcp_v0.94/net/ipv4/tcp_fastopen.c +--- linux-4.14.174/net/ipv4/tcp_fastopen.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_fastopen.c 2020-03-23 09:45:33.000000000 +0100 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + int sysctl_tcp_fastopen __read_mostly = TFO_CLIENT_ENABLE; + +@@ -176,8 +177,9 @@ + { + struct tcp_sock *tp; + struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; +- struct sock *child; ++ struct sock *child, *meta_sk; + bool own_req; ++ int ret; + + req->num_retrans = 0; + req->num_timeout = 0; +@@ -216,20 +218,31 @@ + + refcount_set(&req->rsk_refcnt, 2); + ++ tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; ++ ++ tcp_fastopen_add_skb(child, skb); ++ ++ tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; ++ tp->rcv_wup = tp->rcv_nxt; ++ ++ meta_sk = child; ++ ret = mptcp_check_req_fastopen(meta_sk, req); ++ if (ret < 0) ++ return NULL; ++ ++ if (ret == 0) { ++ child = tcp_sk(meta_sk)->mpcb->master_sk; ++ tp = tcp_sk(child); ++ } ++ + /* Now finish processing the fastopen child socket. */ + inet_csk(child)->icsk_af_ops->rebuild_header(child); + tcp_init_congestion_control(child); + tcp_mtup_init(child); + tcp_init_metrics(child); + tcp_call_bpf(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB); +- tcp_init_buffer_space(child); +- +- tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; ++ tp->ops->init_buffer_space(child); + +- tcp_fastopen_add_skb(child, skb); +- +- tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; +- tp->rcv_wup = tp->rcv_nxt; + /* tcp_conn_request() is sending the SYNACK, + * and queues the child into listener accept queue. + */ +diff -aurN linux-4.14.174/net/ipv4/tcp_input.c mptcp-mptcp_v0.94/net/ipv4/tcp_input.c +--- linux-4.14.174/net/ipv4/tcp_input.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_input.c 2020-03-23 09:45:33.000000000 +0100 +@@ -76,6 +76,9 @@ + #include + #include + #include ++#include ++#include ++#include + + int sysctl_tcp_fack __read_mostly; + int sysctl_tcp_max_reordering __read_mostly = 300; +@@ -96,28 +99,6 @@ + int sysctl_tcp_early_retrans __read_mostly = 3; + int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; + +-#define FLAG_DATA 0x01 /* Incoming frame contained data. */ +-#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ +-#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ +-#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +-#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ +-#define FLAG_DATA_SACKED 0x20 /* New SACK. */ +-#define FLAG_ECE 0x40 /* ECE in this ACK */ +-#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ +-#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ +-#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ +-#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ +-#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ +-#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ +-#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ +-#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ +-#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ +- +-#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) +-#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) +-#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) +-#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) +- + #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) + #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) + +@@ -329,8 +310,12 @@ + per_mss = roundup_pow_of_two(per_mss) + + SKB_DATA_ALIGN(sizeof(struct sk_buff)); + +- nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); +- nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ if (mptcp(tp)) { ++ nr_segs = mptcp_check_snd_buf(tp); ++ } else { ++ nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); ++ nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ } + + /* Fast Recovery (RFC 5681 3.2) : + * Cubic needs 1.7 factor, rounded to 2 to include +@@ -339,8 +324,16 @@ + sndmem = ca_ops->sndbuf_expand ? ca_ops->sndbuf_expand(sk) : 2; + sndmem *= nr_segs * per_mss; + +- if (sk->sk_sndbuf < sndmem) ++ /* MPTCP: after this sndmem is the new contribution of the ++ * current subflow to the aggregated sndbuf */ ++ if (sk->sk_sndbuf < sndmem) { ++ int old_sndbuf = sk->sk_sndbuf; + sk->sk_sndbuf = min(sndmem, sysctl_tcp_wmem[2]); ++ /* MPTCP: ok, the subflow sndbuf has grown, reflect ++ * this in the aggregate buffer.*/ ++ if (mptcp(tp) && old_sndbuf != sk->sk_sndbuf) ++ mptcp_update_sndbuf(tp); ++ } + } + + /* 2. Tuning advertised window (window_clamp, rcv_ssthresh) +@@ -389,9 +382,15 @@ + static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); + int room; + +- room = min_t(int, tp->window_clamp, tcp_space(sk)) - tp->rcv_ssthresh; ++ if (is_meta_sk(sk)) ++ return; ++ ++ ++ room = min_t(int, meta_tp->window_clamp, tcp_space(meta_sk)) - meta_tp->rcv_ssthresh; + + /* Check #1 */ + if (room > 0 && !tcp_under_memory_pressure(sk)) { +@@ -401,13 +400,13 @@ + * will fit to rcvbuf in future. + */ + if (tcp_win_from_space(skb->truesize) <= skb->len) +- incr = 2 * tp->advmss; ++ incr = 2 * meta_tp->advmss; + else +- incr = __tcp_grow_window(sk, skb); ++ incr = __tcp_grow_window(meta_sk, skb); + + if (incr) { + incr = max_t(int, incr, 2 * skb->len); +- tp->rcv_ssthresh += min(room, incr); ++ meta_tp->rcv_ssthresh += min(room, incr); + inet_csk(sk)->icsk_ack.quick |= 1; + } + } +@@ -601,7 +600,10 @@ + + tcp_mstamp_refresh(tp); + time = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcvq_space.time); +- if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) ++ if (mptcp(tp)) { ++ if (mptcp_check_rtt(tp, time)) ++ return; ++ } else if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) + return; + + /* Number of bytes copied to user in last RTT */ +@@ -837,7 +839,7 @@ + /* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. + */ +-static void tcp_set_rto(struct sock *sk) ++void tcp_set_rto(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + /* Old crap is replaced with new one. 8) +@@ -1428,7 +1430,11 @@ + int len; + int in_sack; + +- if (!sk_can_gso(sk)) ++ /* For MPTCP we cannot shift skb-data and remove one skb from the ++ * send-queue, because this will make us loose the DSS-option (which ++ * is stored in TCP_SKB_CB(skb)->dss) of the skb we are removing. ++ */ ++ if (!sk_can_gso(sk) || mptcp(tp)) + goto fallback; + + /* Normally R but no L won't result in plain S */ +@@ -2983,7 +2989,7 @@ + */ + tcp_update_rtt_min(sk, ca_rtt_us); + tcp_rtt_estimator(sk, seq_rtt_us); +- tcp_set_rto(sk); ++ tp->ops->set_rto(sk); + + /* RFC6298: only reset backoff on valid RTT measurement. */ + inet_csk(sk)->icsk_backoff = 0; +@@ -3051,7 +3057,7 @@ + } + + /* If we get here, the whole TSO packet has not been acked. */ +-static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 packets_acked; +@@ -3174,6 +3180,8 @@ + */ + if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { + flag |= FLAG_DATA_ACKED; ++ if (mptcp(tp) && mptcp_is_data_seq(skb)) ++ flag |= MPTCP_FLAG_DATA_ACKED; + } else { + flag |= FLAG_SYN_ACKED; + tp->retrans_stamp = 0; +@@ -3286,7 +3294,7 @@ + return flag; + } + +-static void tcp_ack_probe(struct sock *sk) ++void tcp_ack_probe(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -3356,9 +3364,8 @@ + /* Check that window update is acceptable. + * The function assumes that snd_una<=ack<=snd_next. + */ +-static inline bool tcp_may_update_window(const struct tcp_sock *tp, +- const u32 ack, const u32 ack_seq, +- const u32 nwin) ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin) + { + return after(ack, tp->snd_una) || + after(ack_seq, tp->snd_wl1) || +@@ -3578,7 +3585,7 @@ + } + + /* This routine deals with incoming acks, but not outgoing ones. */ +-static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) ++static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -3685,6 +3692,16 @@ + flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked, + &sack_state); + ++ if (mptcp(tp)) { ++ if (mptcp_fallback_infinite(sk, flag)) { ++ pr_err("%s resetting flow\n", __func__); ++ mptcp_send_reset(sk); ++ goto invalid_ack; ++ } ++ ++ mptcp_clean_rtx_infinite(skb, sk); ++ } ++ + if (tp->tlp_high_seq) + tcp_process_tlp_ack(sk, ack, flag); + /* If needed, reset TLP/RTO timer; RACK may later override this. */ +@@ -3763,8 +3780,10 @@ + */ + void tcp_parse_options(const struct net *net, + const struct sk_buff *skb, +- struct tcp_options_received *opt_rx, int estab, +- struct tcp_fastopen_cookie *foc) ++ struct tcp_options_received *opt_rx, ++ struct mptcp_options_received *mopt, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp) + { + const unsigned char *ptr; + const struct tcphdr *th = tcp_hdr(skb); +@@ -3848,6 +3867,10 @@ + */ + break; + #endif ++ case TCPOPT_MPTCP: ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, tp); ++ break; ++ + case TCPOPT_FASTOPEN: + tcp_parse_fastopen_option( + opsize - TCPOLEN_FASTOPEN_BASE, +@@ -3912,7 +3935,9 @@ + return true; + } + +- tcp_parse_options(net, skb, &tp->rx_opt, 1, NULL); ++ tcp_parse_options(net, skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : NULL, 1, NULL, tp); ++ + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -4069,6 +4094,11 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_fin(sk); ++ return; ++ } ++ + inet_csk_schedule_ack(sk); + + sk->sk_shutdown |= RCV_SHUTDOWN; +@@ -4079,6 +4109,10 @@ + case TCP_ESTABLISHED: + /* Move to CLOSE_WAIT */ + tcp_set_state(sk, TCP_CLOSE_WAIT); ++ ++ if (mptcp(tp)) ++ mptcp_sub_close_passive(sk); ++ + inet_csk(sk)->icsk_ack.pingpong = 1; + break; + +@@ -4101,9 +4135,16 @@ + tcp_set_state(sk, TCP_CLOSING); + break; + case TCP_FIN_WAIT2: ++ if (mptcp(tp)) { ++ /* The socket will get closed by mptcp_data_ready. ++ * We first have to process all data-sequences. ++ */ ++ tp->close_it = 1; ++ break; ++ } + /* Received a FIN -- send ACK and enter TIME_WAIT. */ + tcp_send_ack(sk); +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + break; + default: + /* Only TCP_LISTEN and TCP_CLOSE are left, in these +@@ -4125,6 +4166,10 @@ + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + ++ /* Don't wake up MPTCP-subflows */ ++ if (mptcp(tp)) ++ return; ++ + /* Do not send POLL_HUP for half duplex close. */ + if (sk->sk_shutdown == SHUTDOWN_MASK || + sk->sk_state == TCP_CLOSE) +@@ -4331,6 +4376,9 @@ + + *fragstolen = false; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk)) ++ return false; ++ + /* Its possible this segment overlaps with prior segment in queue */ + if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) + return false; +@@ -4382,7 +4430,7 @@ + /* This one checks to see if we can put data from the + * out_of_order queue into the receive_queue. + */ +-static void tcp_ofo_queue(struct sock *sk) ++void tcp_ofo_queue(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + __u32 dsack_high = tp->rcv_nxt; +@@ -4408,7 +4456,14 @@ + if (TCP_SKB_CB(skb)->has_rxtstamp) + skb->tstamp = TCP_SKB_CB(skb)->swtstamp; + +- if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { ++ /* In case of MPTCP, the segment may be empty if it's a ++ * non-data DATA_FIN. (see beginning of tcp_data_queue) ++ * ++ * But this only holds true for subflows, not for the ++ * meta-socket. ++ */ ++ if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt) && ++ (is_meta_sk(sk) || !mptcp(tp) || TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq))) { + SOCK_DEBUG(sk, "ofo packet was already received\n"); + tcp_drop(sk, skb); + continue; +@@ -4443,6 +4498,9 @@ + static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, + unsigned int size) + { ++ if (mptcp(tcp_sk(sk))) ++ sk = mptcp_meta_sk(sk); ++ + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule(sk, skb, size)) { + +@@ -4457,7 +4515,7 @@ + return 0; + } + +-static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + struct rb_node **p, *parent; +@@ -4529,7 +4587,8 @@ + continue; + } + if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { +- if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq) && ++ (is_meta_sk(sk) || !mptcp(tp) || end_seq != seq)) { + /* All the bits are present. Drop. */ + NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPOFOMERGE); +@@ -4576,6 +4635,11 @@ + end_seq); + break; + } ++ /* MPTCP allows non-data data-fin to be in the ofo-queue */ ++ if (mptcp(tp) && !is_meta_sk(sk) && TCP_SKB_CB(skb1)->seq == TCP_SKB_CB(skb1)->end_seq) { ++ skb = skb1; ++ continue; ++ } + rb_erase(&skb1->rbnode, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); +@@ -4587,7 +4651,7 @@ + tp->ooo_last_skb = skb; + + add_sack: +- if (tcp_is_sack(tp)) ++ if (tcp_is_sack(tp) && seq != end_seq) + tcp_sack_new_ofo_skb(sk, seq, end_seq); + end: + if (skb) { +@@ -4597,8 +4661,8 @@ + } + } + +-static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, +- bool *fragstolen) ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen) + { + int eaten; + struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); +@@ -4671,10 +4735,14 @@ + bool fragstolen; + int eaten; + +- if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { ++ /* If no data is present, but a data_fin is in the options, we still ++ * have to call mptcp_queue_skb later on. */ ++ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && ++ !(mptcp(tp) && mptcp_is_data_fin(skb))) { + __kfree_skb(skb); + return; + } ++ + skb_dst_drop(skb); + __skb_pull(skb, tcp_hdr(skb)->doff * 4); + +@@ -4699,7 +4767,7 @@ + + eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); +- if (skb->len) ++ if (skb->len || mptcp_is_data_fin(skb)) + tcp_event_data_recv(sk, skb); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) + tcp_fin(sk); +@@ -4721,7 +4789,11 @@ + + if (eaten > 0) + kfree_skb_partial(skb, fragstolen); +- if (!sock_flag(sk, SOCK_DEAD)) ++ if (!sock_flag(sk, SOCK_DEAD) || mptcp(tp)) ++ /* MPTCP: we always have to call data_ready, because ++ * we may be about to receive a data-fin, which still ++ * must get queued. ++ */ + sk->sk_data_ready(sk); + return; + } +@@ -5060,7 +5132,7 @@ + return -1; + } + +-static bool tcp_should_expand_sndbuf(const struct sock *sk) ++bool tcp_should_expand_sndbuf(const struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + +@@ -5095,7 +5167,7 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + +- if (tcp_should_expand_sndbuf(sk)) { ++ if (tp->ops->should_expand_sndbuf(sk)) { + tcp_sndbuf_expand(sk); + tp->snd_cwnd_stamp = tcp_jiffies32; + } +@@ -5109,10 +5181,11 @@ + sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); + /* pairs with tcp_poll() */ + smp_mb(); +- if (sk->sk_socket && +- test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ if (mptcp(tcp_sk(sk)) || ++ (sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))) { + tcp_new_space(sk); +- if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) ++ if (sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) + tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); + } + } +@@ -5135,8 +5208,14 @@ + if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && + /* ... and right edge of window advances far enough. + * (tcp_recvmsg() will send ACK otherwise). Or... ++ * in the case of mptcp the meta ofo queue may ++ * prevent tcp_recvmsg from being called in time ++ * so no data is available for the application, skip the ++ * receive window check as there is no hope that the application ++ * will do a tcp_recvmsg anytime soon. + */ +- __tcp_select_window(sk) >= tp->rcv_wnd) || ++ (tp->ops->__select_window(sk) >= tp->rcv_wnd || (mptcp(tp) && ++ skb_queue_empty(&mptcp_meta_sk(sk)->sk_receive_queue)))) || + /* We ACK each frame or... */ + tcp_in_quickack_mode(sk) || + /* We have out of order data. */ +@@ -5238,6 +5317,10 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ /* MPTCP urgent data is not yet supported */ ++ if (mptcp(tp)) ++ return; ++ + /* Check if we get a new urgent pointer - normally not. */ + if (th->urg) + tcp_check_urg(sk, th); +@@ -5380,9 +5463,15 @@ + goto discard; + } + ++ /* If valid: post process the received MPTCP options. */ ++ if (mptcp(tp) && mptcp_handle_options(sk, th, skb)) ++ goto discard; ++ + return true; + + discard: ++ if (mptcp(tp)) ++ mptcp_reset_mopt(tp); + tcp_drop(sk, skb); + return false; + } +@@ -5436,6 +5525,10 @@ + + tp->rx_opt.saw_tstamp = 0; + ++ /* MPTCP: force slowpath. */ ++ if (mptcp(tp)) ++ goto slow_path; ++ + /* pred_flags is 0xS?10 << 16 + snd_wnd + * if header_prediction is to be made + * 'S' will always be tp->tcp_header_len >> 2 +@@ -5605,7 +5698,7 @@ + */ + tp->lsndtime = tcp_jiffies32; + +- tcp_init_buffer_space(sk); ++ tp->ops->init_buffer_space(sk); + + if (sock_flag(sk, SOCK_KEEPOPEN)) + inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp)); +@@ -5620,7 +5713,8 @@ + struct tcp_fastopen_cookie *cookie) + { + struct tcp_sock *tp = tcp_sk(sk); +- struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(meta_sk) : NULL; + u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; + bool syn_drop = false; + +@@ -5630,7 +5724,7 @@ + /* Get original SYNACK MSS value if user MSS sets mss_clamp */ + tcp_clear_options(&opt); + opt.user_mss = opt.mss_clamp = 0; +- tcp_parse_options(sock_net(sk), synack, &opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), synack, &opt, NULL, 0, NULL, NULL); + mss = opt.mss_clamp; + } + +@@ -5654,7 +5748,11 @@ + + tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); + +- if (data) { /* Retransmit unacked data in SYN */ ++ /* In mptcp case, we do not rely on "retransmit", but instead on ++ * "transmit", because if fastopen data is not acked, the retransmission ++ * becomes the first MPTCP data (see mptcp_rcv_synsent_fastopen). ++ */ ++ if (data && !mptcp(tp)) { /* Retransmit unacked data in SYN */ + tcp_for_write_queue_from(data, sk) { + if (data == tcp_send_head(sk) || + __tcp_retransmit_skb(sk, data, 1)) +@@ -5682,9 +5780,13 @@ + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_fastopen_cookie foc = { .len = -1 }; + int saved_clamp = tp->rx_opt.mss_clamp; ++ struct mptcp_options_received mopt; + bool fastopen_fail; + +- tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, 0, &foc); ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : &mopt, 0, &foc, tp); + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -5744,6 +5846,35 @@ + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + tcp_ack(sk, skb, FLAG_SLOWPATH); + ++ if (tp->request_mptcp || mptcp(tp)) { ++ int ret; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ ret = mptcp_rcv_synsent_state_process(sk, &sk, ++ skb, &mopt); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ /* May have changed if we support MPTCP */ ++ tp = tcp_sk(sk); ++ icsk = inet_csk(sk); ++ ++ if (ret == 1) ++ goto reset_and_undo; ++ if (ret == 2) ++ goto discard; ++ } ++ ++ if (mptcp(tp) && !is_master_tp(tp)) { ++ /* Timer for repeating the ACK until an answer ++ * arrives. Used only when establishing an additional ++ * subflow inside of an MPTCP connection. ++ */ ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ } ++ + /* Ok.. it's good. Set up sequence numbers and + * move to established. + */ +@@ -5770,6 +5901,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + if (tcp_is_sack(tp) && sysctl_tcp_fack) + tcp_enable_fack(tp); + +@@ -5795,9 +5931,12 @@ + } + if (fastopen_fail) + return -1; +- if (sk->sk_write_pending || ++ /* With MPTCP we cannot send data on the third ack due to the ++ * lack of option-space to combine with an MP_CAPABLE. ++ */ ++ if (!mptcp(tp) && (sk->sk_write_pending || + icsk->icsk_accept_queue.rskq_defer_accept || +- icsk->icsk_ack.pingpong) { ++ icsk->icsk_ack.pingpong)) { + /* Save one ACK. Data will be ready after + * several ticks, if write_pending is set. + * +@@ -5836,6 +5975,7 @@ + tcp_paws_reject(&tp->rx_opt, 0)) + goto discard_and_undo; + ++ /* TODO - check this here for MPTCP */ + if (th->syn) { + /* We see SYN without ACK. It is attempt of + * simultaneous connect with crossed SYNs. +@@ -5852,6 +5992,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + tp->copied_seq = tp->rcv_nxt; + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; +@@ -5910,6 +6055,7 @@ + */ + + int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) ++ __releases(&sk->sk_lock.slock) + { + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -5952,6 +6098,16 @@ + tp->rx_opt.saw_tstamp = 0; + tcp_mstamp_refresh(tp); + queued = tcp_rcv_synsent_state_process(sk, skb, th); ++ if (is_meta_sk(sk)) { ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ tp = tcp_sk(sk); ++ ++ /* Need to call it here, because it will announce new ++ * addresses, which can only be done after the third ack ++ * of the 3-way handshake. ++ */ ++ mptcp_update_metasocket(tp->meta_sk); ++ } + if (queued >= 0) + return queued; + +@@ -6009,7 +6165,7 @@ + + tcp_mtup_init(sk); + tp->copied_seq = tp->rcv_nxt; +- tcp_init_buffer_space(sk); ++ tp->ops->init_buffer_space(sk); + } + smp_mb(); + tcp_set_state(sk, TCP_ESTABLISHED); +@@ -6028,6 +6184,8 @@ + + if (tp->rx_opt.tstamp_ok) + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; ++ if (mptcp(tp)) ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; + + if (req) { + /* Re-arm the timer because data may have been sent out. +@@ -6050,6 +6208,30 @@ + + tcp_initialize_rcv_mss(sk); + tcp_fast_path_on(tp); ++ ++ /* Send an ACK when establishing a new MPTCP subflow, i.e. ++ * using an MP_JOIN subtype. ++ */ ++ if (mptcp(tp)) { ++ if (is_master_tp(tp)) { ++ mptcp_update_metasocket(mptcp_meta_sk(sk)); ++ } else { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ tcp_send_ack(sk); ++ ++ /* Update RTO as it might be worse/better */ ++ mptcp_set_rto(sk); ++ ++ /* If the new RTO would fire earlier, pull it in! */ ++ if (tcp_sk(meta_sk)->packets_out && ++ icsk->icsk_timeout > inet_csk(meta_sk)->icsk_rto + jiffies) { ++ tcp_rearm_rto(meta_sk); ++ } ++ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++ } ++ } + break; + + case TCP_FIN_WAIT1: { +@@ -6097,7 +6279,8 @@ + tmo = tcp_fin_time(sk); + if (tmo > TCP_TIMEWAIT_LEN) { + inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); +- } else if (th->fin || sock_owned_by_user(sk)) { ++ } else if (th->fin || mptcp_is_data_fin(skb) || ++ sock_owned_by_user(sk)) { + /* Bad case. We could lose such FIN otherwise. + * It is not a big problem, but it looks confusing + * and not so rare event. We still can lose it now, +@@ -6106,7 +6289,7 @@ + */ + inet_csk_reset_keepalive_timer(sk, tmo); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto discard; + } + break; +@@ -6114,7 +6297,7 @@ + + case TCP_CLOSING: + if (tp->snd_una == tp->write_seq) { +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + goto discard; + } + break; +@@ -6126,6 +6309,9 @@ + goto discard; + } + break; ++ case TCP_CLOSE: ++ if (tp->mp_killed) ++ goto discard; + } + + /* step 6: check the URG bit */ +@@ -6146,7 +6332,8 @@ + */ + if (sk->sk_shutdown & RCV_SHUTDOWN) { + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && +- after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp(tp)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); + tcp_reset(sk); + return 1; +@@ -6243,6 +6430,8 @@ + ireq->wscale_ok = rx_opt->wscale_ok; + ireq->acked = 0; + ireq->ecn_ok = 0; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + ireq->ir_rmt_port = tcp_hdr(skb)->source; + ireq->ir_num = ntohs(tcp_hdr(skb)->dest); + ireq->ir_mark = inet_request_mark(sk, skb); +@@ -6337,12 +6526,17 @@ + /* TW buckets are converted to open requests without + * limitations, they conserve resources and peer is + * evidently real one. ++ * ++ * MPTCP: new subflows cannot be established in a stateless manner. + */ +- if ((net->ipv4.sysctl_tcp_syncookies == 2 || ++ if (((!is_meta_sk(sk) && net->ipv4.sysctl_tcp_syncookies == 2) || + inet_csk_reqsk_queue_is_full(sk)) && !isn) { + want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); + if (!want_cookie) + goto drop; ++ ++ if (is_meta_sk(sk)) ++ goto drop; + } + + if (sk_acceptq_is_full(sk)) { +@@ -6360,8 +6554,8 @@ + tcp_clear_options(&tmp_opt); + tmp_opt.mss_clamp = af_ops->mss_clamp; + tmp_opt.user_mss = tp->rx_opt.user_mss; +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, +- want_cookie ? NULL : &foc); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, NULL, 0, ++ want_cookie ? NULL : &foc, NULL); + + if (want_cookie && !tmp_opt.saw_tstamp) + tcp_clear_options(&tmp_opt); +@@ -6373,7 +6567,8 @@ + /* Note: tcp_v6_init_req() might override ir_iif for link locals */ + inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); + +- af_ops->init_req(req, sk, skb); ++ if (af_ops->init_req(req, sk, skb, want_cookie)) ++ goto drop_and_free; + + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_free; +@@ -6409,7 +6604,7 @@ + tcp_ecn_create_request(req, skb, sk, dst); + + if (want_cookie) { +- isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); ++ isn = cookie_init_sequence(af_ops, req, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + if (!tmp_opt.tstamp_ok) + inet_rsk(req)->ecn_ok = 0; +@@ -6423,18 +6618,26 @@ + fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc); + } + if (fastopen_sk) { ++ struct sock *meta_sk = fastopen_sk; ++ ++ if (mptcp(tcp_sk(fastopen_sk))) ++ meta_sk = mptcp_meta_sk(fastopen_sk); + af_ops->send_synack(fastopen_sk, dst, &fl, req, + &foc, TCP_SYNACK_FASTOPEN); + /* Add the child socket directly into the accept queue */ +- if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) { ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { + reqsk_fastopen_remove(fastopen_sk, req, false); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + reqsk_put(req); + goto drop; + } + sk->sk_data_ready(sk); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + } else { + tcp_rsk(req)->tfo_listener = false; +diff -aurN linux-4.14.174/net/ipv4/tcp_ipv4.c mptcp-mptcp_v0.94/net/ipv4/tcp_ipv4.c +--- linux-4.14.174/net/ipv4/tcp_ipv4.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_ipv4.c 2020-03-23 09:45:33.000000000 +0100 +@@ -67,6 +67,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -372,7 +374,7 @@ + struct inet_sock *inet; + const int type = icmp_hdr(icmp_skb)->type; + const int code = icmp_hdr(icmp_skb)->code; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + struct sk_buff *skb; + struct request_sock *fastopen; + u32 seq, snd_una; +@@ -401,13 +403,19 @@ + (code == ICMP_NET_UNREACH || + code == ICMP_HOST_UNREACH))); + +- bh_lock_sock(sk); ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); + /* If too many ICMPs get dropped on busy + * servers this needs to be solved differently. + * We do take care of PMTU discovery (RFC1191) special case : + * we can receive locally generated ICMP messages while socket is held. + */ +- if (sock_owned_by_user(sk)) { ++ if (sock_owned_by_user(meta_sk)) { + if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + } +@@ -420,7 +428,6 @@ + } + + icsk = inet_csk(sk); +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -454,11 +461,13 @@ + goto out; + + tp->mtu_info = info; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v4_mtu_reduced(sk); + } else { + if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } + goto out; + } +@@ -472,7 +481,7 @@ + !icsk->icsk_backoff || fastopen) + break; + +- if (sock_owned_by_user(sk)) ++ if (sock_owned_by_user(meta_sk)) + break; + + skb = tcp_write_queue_head(sk); +@@ -495,7 +504,7 @@ + } else { + /* RTO revert clocked out retransmission. + * Will retransmit now */ +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + } + + break; +@@ -515,7 +524,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + + sk->sk_error_report(sk); +@@ -544,7 +553,7 @@ + */ + + inet = inet_sk(sk); +- if (!sock_owned_by_user(sk) && inet->recverr) { ++ if (!sock_owned_by_user(meta_sk) && inet->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else { /* Only an error on timeout */ +@@ -552,7 +561,7 @@ + } + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -594,7 +603,7 @@ + * Exception: precedence violation. We do not implement it in any case. + */ + +-static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -731,10 +740,10 @@ + */ + + static void tcp_v4_send_ack(const struct sock *sk, +- struct sk_buff *skb, u32 seq, u32 ack, ++ struct sk_buff *skb, u32 seq, u32 ack, u32 data_ack, + u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, +- int reply_flags, u8 tos) ++ int reply_flags, u8 tos, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -743,6 +752,10 @@ + #ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) + #endif ++#ifdef CONFIG_MPTCP ++ + ((MPTCP_SUB_LEN_DSS >> 2) + ++ (MPTCP_SUB_LEN_ACK >> 2)) ++#endif + ]; + } rep; + struct net *net = sock_net(sk); +@@ -787,6 +800,21 @@ + ip_hdr(skb)->daddr, &rep.th); + } + #endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ int offset = (tsecr) ? 3 : 0; ++ /* Construction of 32-bit data_ack */ ++ rep.opt[offset++] = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ rep.opt[offset] = htonl(data_ack); ++ ++ arg.iov[0].iov_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++ rep.th.doff = arg.iov[0].iov_len / 4; ++ } ++#endif /* CONFIG_MPTCP */ ++ + arg.flags = reply_flags; + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, /* XXX */ +@@ -810,28 +838,36 @@ + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; ++ ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + + tcp_v4_send_ack(sk, skb, +- tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, + tw->tw_bound_dev_if, + tcp_twsk_md5_key(tcptw), + tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, +- tw->tw_tos ++ tw->tw_tos, mptcp + ); + + inet_twsk_put(tw); + } + +-static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. + */ +- u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : ++ u32 seq = (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? ++ tcp_rsk(req)->snt_isn + 1 : + tcp_sk(sk)->snd_nxt; + + /* RFC 7323 2.3 +@@ -840,7 +876,7 @@ + * Rcv.Wind.Shift bits: + */ + tcp_v4_send_ack(sk, skb, seq, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, +@@ -848,7 +884,7 @@ + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, + AF_INET), + inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, +- ip_hdr(skb)->tos); ++ ip_hdr(skb)->tos, 0); + } + + /* +@@ -856,11 +892,11 @@ + * This still operates on a request_sock only, not on a big + * socket. + */ +-static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, +- struct flowi *fl, +- struct request_sock *req, +- struct tcp_fastopen_cookie *foc, +- enum tcp_synack_type synack_type) ++int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, ++ struct flowi *fl, ++ struct request_sock *req, ++ struct tcp_fastopen_cookie *foc, ++ enum tcp_synack_type synack_type) + { + const struct inet_request_sock *ireq = inet_rsk(req); + struct flowi4 fl4; +@@ -890,7 +926,7 @@ + /* + * IPv4 request_sock destructor. + */ +-static void tcp_v4_reqsk_destructor(struct request_sock *req) ++void tcp_v4_reqsk_destructor(struct request_sock *req) + { + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + } +@@ -1263,9 +1299,10 @@ + return false; + } + +-static void tcp_v4_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v4_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + struct inet_request_sock *ireq = inet_rsk(req); + struct net *net = sock_net(sk_listener); +@@ -1273,6 +1310,8 @@ + sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); + sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); ++ ++ return 0; + } + + static struct dst_entry *tcp_v4_route_req(const struct sock *sk, +@@ -1292,7 +1331,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { + .mss_clamp = TCP_MSS_DEFAULT, + #ifdef CONFIG_TCP_MD5SIG + .req_md5_lookup = tcp_v4_md5_lookup, +@@ -1429,7 +1468,7 @@ + } + EXPORT_SYMBOL(tcp_v4_syn_recv_sock); + +-static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1452,6 +1491,9 @@ + { + struct sock *rsk; + ++ if (is_meta_sk(sk)) ++ return mptcp_v4_do_rcv(sk, skb); ++ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst = sk->sk_rx_dst; + +@@ -1603,6 +1645,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff * 4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); +@@ -1621,8 +1667,8 @@ + int sdif = inet_sdif(skb); + const struct iphdr *iph; + const struct tcphdr *th; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + + if (skb->pkt_type != PACKET_HOST) +@@ -1675,7 +1721,7 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } +@@ -1684,6 +1730,36 @@ + */ + sock_hold(sk); + refcounted = true; ++ ++ if (is_meta_sk(sk)) { ++ bh_lock_sock(sk); ++ ++ if (!mptcp_can_new_subflow(sk)) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ bh_unlock_sock(sk); ++ ++ goto discard_and_relse; ++ } ++ ++ if (sock_owned_by_user(sk)) { ++ mptcp_prepare_for_backlog(sk, skb); ++ if (unlikely(sk_add_backlog(sk, skb, ++ sk->sk_rcvbuf + sk->sk_sndbuf))) { ++ reqsk_put(req); ++ ++ bh_unlock_sock(sk); ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ goto discard_and_relse; ++ } ++ ++ reqsk_put(req); ++ bh_unlock_sock(sk); ++ sock_put(sk); ++ ++ return 0; ++ } ++ } ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1693,11 +1769,15 @@ + } + if (!nsk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + goto discard_and_relse; + } + if (nsk == sk) { + reqsk_put(req); + tcp_v4_restore_cb(skb); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + } else if (tcp_child_process(sk, nsk, skb)) { + tcp_v4_send_reset(nsk, skb); + goto discard_and_relse; +@@ -1734,15 +1814,24 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_v4_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1756,6 +1845,19 @@ + + tcp_v4_fill_cb(skb, iph, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1804,6 +1906,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + /* Fall through to ACK */ + } + case TCP_TW_ACK: +@@ -1872,7 +1986,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; +@@ -1889,6 +2008,11 @@ + + tcp_cleanup_congestion_control(sk); + ++ if (mptcp(tp)) ++ mptcp_destroy_sock(sk); ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ + tcp_cleanup_ulp(sk); + + /* Cleanup up the write buffer. */ +@@ -2437,6 +2561,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + EXPORT_SYMBOL(tcp_prot); + +diff -aurN linux-4.14.174/net/ipv4/tcp_minisocks.c mptcp-mptcp_v0.94/net/ipv4/tcp_minisocks.c +--- linux-4.14.174/net/ipv4/tcp_minisocks.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_minisocks.c 2020-03-23 09:45:33.000000000 +0100 +@@ -18,11 +18,13 @@ + * Jorge Cwik, + */ + ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -95,10 +97,14 @@ + struct tcp_options_received tmp_opt; + struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); + bool paws_reject = false; ++ struct mptcp_options_received mopt; + + tmp_opt.saw_tstamp = 0; +- if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { +- tcp_parse_options(twsk_net(tw), skb, &tmp_opt, 0, NULL); ++ if (th->doff > (sizeof(*th) >> 2) && ++ (tcptw->tw_ts_recent_stamp || tcptw->mptcp_tw)) { ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(twsk_net(tw), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + if (tmp_opt.rcv_tsecr) +@@ -107,6 +113,11 @@ + tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; + paws_reject = tcp_paws_reject(&tmp_opt, th->rst); + } ++ ++ if (unlikely(mopt.mp_fclose) && tcptw->mptcp_tw) { ++ if (mopt.mptcp_sender_key == tcptw->mptcp_tw->loc_key) ++ return TCP_TW_RST; ++ } + } + + if (tw->tw_substate == TCP_FIN_WAIT2) { +@@ -130,6 +141,16 @@ + if (!th->ack || + !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) || + TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { ++ /* If mptcp_is_data_fin() returns true, we are sure that ++ * mopt has been initialized - otherwise it would not ++ * be a DATA_FIN. ++ */ ++ if (tcptw->mptcp_tw && tcptw->mptcp_tw->meta_tw && ++ mptcp_is_data_fin(skb) && ++ TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt && ++ mopt.data_seq + 1 == (u32)tcptw->mptcp_tw->rcv_nxt) ++ return TCP_TW_ACK; ++ + inet_twsk_put(tw); + return TCP_TW_SUCCESS; + } +@@ -274,6 +295,15 @@ + tcptw->tw_ts_offset = tp->tsoffset; + tcptw->tw_last_oow_ack_time = 0; + ++ if (mptcp(tp)) { ++ if (mptcp_init_tw_sock(sk, tcptw)) { ++ inet_twsk_free(tw); ++ goto exit; ++ } ++ } else { ++ tcptw->mptcp_tw = NULL; ++ } ++ + #if IS_ENABLED(CONFIG_IPV6) + if (tw->tw_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -331,15 +361,18 @@ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); + } + ++exit: + tcp_update_metrics(sk); + tcp_done(sk); + } + + void tcp_twsk_destructor(struct sock *sk) + { +-#ifdef CONFIG_TCP_MD5SIG + struct tcp_timewait_sock *twsk = tcp_twsk(sk); + ++ if (twsk->mptcp_tw) ++ mptcp_twsk_destructor(twsk); ++#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_key) + kfree_rcu(twsk->tw_md5_key, rcu); + #endif +@@ -378,13 +411,14 @@ + full_space = rcv_wnd * mss; + + /* tcp_full_space because it is guaranteed to be the first packet */ +- tcp_select_initial_window(full_space, +- mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), ++ tp->ops->select_initial_window(tcp_full_space(sk_listener), ++ mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) - ++ (ireq->saw_mpc ? MPTCP_SUB_LEN_DSM_ALIGN : 0), + &req->rsk_rcv_wnd, + &req->rsk_window_clamp, + ireq->wscale_ok, + &rcv_wscale, +- rcv_wnd); ++ rcv_wnd, sk_listener); + ireq->rcv_wscale = rcv_wscale; + } + EXPORT_SYMBOL(tcp_openreq_init_rwin); +@@ -526,6 +560,8 @@ + newtp->rx_opt.ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } ++ if (ireq->saw_mpc) ++ newtp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; + newtp->tsoffset = treq->ts_off; + #ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ +@@ -541,6 +577,7 @@ + newtp->syn_data_acked = 0; + newtp->rack.mstamp = 0; + newtp->rack.advanced = 0; ++ newtp->inside_tk_table = 0; + + __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); + } +@@ -564,6 +601,7 @@ + bool fastopen) + { + struct tcp_options_received tmp_opt; ++ struct mptcp_options_received mopt; + struct sock *child; + const struct tcphdr *th = tcp_hdr(skb); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); +@@ -571,8 +609,11 @@ + bool own_req; + + tmp_opt.saw_tstamp = 0; ++ ++ mptcp_init_mp_opt(&mopt); ++ + if (th->doff > (sizeof(struct tcphdr)>>2)) { +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + tmp_opt.ts_recent = req->ts_recent; +@@ -613,7 +654,14 @@ + * + * Reset timer after retransmitting SYNACK, similar to + * the idea of fast retransmit in recovery. ++ * ++ * Fall back to TCP if MP_CAPABLE is not set. + */ ++ ++ if (inet_rsk(req)->saw_mpc && !mopt.saw_mpc) ++ inet_rsk(req)->saw_mpc = false; ++ ++ + if (!tcp_oow_rate_limited(sock_net(sk), skb, + LINUX_MIB_TCPACKSKIPPEDSYNRECV, + &tcp_rsk(req)->last_oow_ack_time) && +@@ -766,6 +814,18 @@ + if (!child) + goto listen_overflow; + ++ if (own_req && !is_meta_sk(sk)) { ++ int ret = mptcp_check_req_master(sk, child, req, skb, 1, 0); ++ if (ret < 0) ++ goto listen_overflow; ++ ++ /* MPTCP-supported */ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ } else if (own_req) { ++ return mptcp_check_req_child(sk, child, req, skb, &mopt); ++ } ++ + sock_rps_save_rxhash(child, skb); + tcp_synack_rtt_meas(child, req); + return inet_csk_complete_hashdance(sk, child, req, own_req); +@@ -813,12 +873,13 @@ + { + int ret = 0; + int state = child->sk_state; ++ struct sock *meta_sk = mptcp(tcp_sk(child)) ? mptcp_meta_sk(child) : child; + + /* record NAPI ID of child */ + sk_mark_napi_id(child, skb); + + tcp_segs_in(tcp_sk(child), skb); +- if (!sock_owned_by_user(child)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_rcv_state_process(child, skb); + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && child->sk_state != state) +@@ -828,10 +889,14 @@ + * in main socket hash table and lock on listening + * socket does not protect us more. + */ +- __sk_add_backlog(child, skb); ++ if (mptcp(tcp_sk(child))) ++ mptcp_prepare_for_backlog(child, skb); ++ __sk_add_backlog(meta_sk, skb); + } + +- bh_unlock_sock(child); ++ if (mptcp(tcp_sk(child))) ++ bh_unlock_sock(child); ++ bh_unlock_sock(meta_sk); + sock_put(child); + return ret; + } +diff -aurN linux-4.14.174/net/ipv4/tcp_output.c mptcp-mptcp_v0.94/net/ipv4/tcp_output.c +--- linux-4.14.174/net/ipv4/tcp_output.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_output.c 2020-03-23 09:45:33.000000000 +0100 +@@ -36,6 +36,12 @@ + + #define pr_fmt(fmt) "TCP: " fmt + ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++#include + #include + + #include +@@ -62,11 +68,8 @@ + /* By default, RFC2861 behavior. */ + int sysctl_tcp_slow_start_after_idle __read_mostly = 1; + +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, +- int push_one, gfp_t gfp); +- + /* Account for new data that has been sent to the network. */ +-static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) ++void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -211,7 +214,7 @@ + void tcp_select_initial_window(int __space, __u32 mss, + __u32 *rcv_wnd, __u32 *window_clamp, + int wscale_ok, __u8 *rcv_wscale, +- __u32 init_rcv_wnd) ++ __u32 init_rcv_wnd, const struct sock *sk) + { + unsigned int space = (__space < 0 ? 0 : __space); + +@@ -265,12 +268,16 @@ + * value can be stuffed directly into th->window for an outgoing + * frame. + */ +-static u16 tcp_select_window(struct sock *sk) ++u16 tcp_select_window(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 old_win = tp->rcv_wnd; +- u32 cur_win = tcp_receive_window(tp); +- u32 new_win = __tcp_select_window(sk); ++ /* The window must never shrink at the meta-level. At the subflow we ++ * have to allow this. Otherwise we may announce a window too large ++ * for the current meta-level sk_rcvbuf. ++ */ ++ u32 cur_win = tcp_receive_window(mptcp(tp) ? tcp_sk(mptcp_meta_sk(sk)) : tp); ++ u32 new_win = tp->ops->__select_window(sk); + + /* Never shrink the offered window */ + if (new_win < cur_win) { +@@ -286,6 +293,7 @@ + LINUX_MIB_TCPWANTZEROWINDOWADV); + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + } ++ + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + +@@ -397,7 +405,7 @@ + /* Constructs common control bits of non-data skb. If SYN/FIN is present, + * auto increment end seqno. + */ +-static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) + { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = 0; +@@ -413,7 +421,7 @@ + TCP_SKB_CB(skb)->end_seq = seq; + } + +-static inline bool tcp_urg_mode(const struct tcp_sock *tp) ++bool tcp_urg_mode(const struct tcp_sock *tp) + { + return tp->snd_una != tp->snd_up; + } +@@ -423,17 +431,7 @@ + #define OPTION_MD5 (1 << 2) + #define OPTION_WSCALE (1 << 3) + #define OPTION_FAST_OPEN_COOKIE (1 << 8) +- +-struct tcp_out_options { +- u16 options; /* bit field of OPTION_* */ +- u16 mss; /* 0 to disable */ +- u8 ws; /* window scale, 0 to disable */ +- u8 num_sack_blocks; /* number of SACK blocks to include */ +- u8 hash_size; /* bytes in hash_location */ +- __u8 *hash_location; /* temporary pointer, overloaded */ +- __u32 tsval, tsecr; /* need to include OPTION_TS */ +- struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ +-}; ++/* Before adding here - take a look at OPTION_MPTCP in include/net/mptcp.h */ + + /* Write previously computed TCP options to the packet. + * +@@ -449,7 +447,7 @@ + * (but it may well be that other scenarios fail similarly). + */ + static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, +- struct tcp_out_options *opts) ++ struct tcp_out_options *opts, struct sk_buff *skb) + { + u16 options = opts->options; /* mungable copy */ + +@@ -541,6 +539,9 @@ + } + ptr += (len + 3) >> 2; + } ++ ++ if (unlikely(OPTION_MPTCP & opts->options)) ++ mptcp_options_write(ptr, tp, opts, skb); + } + + /* Compute TCP options for SYN packets. This is not the final +@@ -592,6 +593,8 @@ + if (unlikely(!(OPTION_TS & opts->options))) + remaining -= TCPOLEN_SACKPERM_ALIGNED; + } ++ if (tp->request_mptcp || mptcp(tp)) ++ mptcp_syn_options(sk, opts, &remaining); + + if (fastopen && fastopen->cookie.len >= 0) { + u32 need = fastopen->cookie.len; +@@ -668,6 +671,9 @@ + } + } + ++ if (ireq->saw_mpc) ++ mptcp_synack_options(req, opts, &remaining); ++ + return MAX_TCP_OPTION_SPACE - remaining; + } + +@@ -700,6 +706,8 @@ + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } ++ if (mptcp(tp)) ++ mptcp_established_options(sk, skb, opts, &size); + + eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; + if (unlikely(eff_sacks)) { +@@ -750,8 +758,8 @@ + tcp_xmit_retransmit_queue(sk); + } + +- tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, +- 0, GFP_ATOMIC); ++ tcp_sk(sk)->ops->write_xmit(sk, tcp_current_mss(sk), ++ tcp_sk(sk)->nonagle, 0, GFP_ATOMIC); + } + } + /* +@@ -767,7 +775,7 @@ + unsigned long flags; + struct list_head *q, *n; + struct tcp_sock *tp; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + + local_irq_save(flags); + list_splice_init(&tsq->head, &list); +@@ -781,14 +789,28 @@ + smp_mb__before_atomic(); + clear_bit(TSQ_QUEUED, &sk->sk_tsq_flags); + +- if (!sk->sk_lock.owned && ++ meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ ++ if (!meta_sk->sk_lock.owned && + test_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags)) { +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + clear_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags); + tcp_tsq_handler(sk); ++ if (mptcp(tp)) ++ tcp_tsq_handler(meta_sk); ++ } else if (mptcp(tp)) { ++ if (sk->sk_state != TCP_CLOSE) ++ mptcp_tsq_flags(sk); ++ } ++ bh_unlock_sock(meta_sk); ++ } else { ++ if (mptcp(tp)) { ++ bh_lock_sock(meta_sk); ++ if (sk->sk_state != TCP_CLOSE) ++ mptcp_tsq_flags(sk); ++ bh_unlock_sock(meta_sk); + } +- bh_unlock_sock(sk); + } + + sk_free(sk); +@@ -798,7 +820,9 @@ + #define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \ + TCPF_WRITE_TIMER_DEFERRED | \ + TCPF_DELACK_TIMER_DEFERRED | \ +- TCPF_MTU_REDUCED_DEFERRED) ++ TCPF_MTU_REDUCED_DEFERRED | \ ++ TCPF_PATH_MANAGER_DEFERRED |\ ++ TCPF_SUB_DEFERRED) + /** + * tcp_release_cb - tcp release_sock() callback + * @sk: socket +@@ -818,8 +842,11 @@ + nflags = flags & ~TCP_DEFERRED_ALL; + } while (cmpxchg(&sk->sk_tsq_flags, flags, nflags) != flags); + +- if (flags & TCPF_TSQ_DEFERRED) ++ if (flags & TCPF_TSQ_DEFERRED) { + tcp_tsq_handler(sk); ++ if (mptcp(tcp_sk(sk))) ++ tcp_tsq_handler(mptcp_meta_sk(sk)); ++ } + + /* Here begins the tricky part : + * We are called from release_sock() with : +@@ -844,6 +871,13 @@ + inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); + __sock_put(sk); + } ++ if (flags & TCPF_PATH_MANAGER_DEFERRED) { ++ if (tcp_sk(sk)->mpcb->pm_ops->release_sock) ++ tcp_sk(sk)->mpcb->pm_ops->release_sock(sk); ++ __sock_put(sk); ++ } ++ if (flags & TCPF_SUB_DEFERRED) ++ mptcp_tsq_sub_deferred(sk); + } + EXPORT_SYMBOL(tcp_release_cb); + +@@ -1081,10 +1115,10 @@ + } + } + +- tcp_options_write((__be32 *)(th + 1), tp, &opts); ++ tcp_options_write((__be32 *)(th + 1), tp, &opts, skb); + skb_shinfo(skb)->gso_type = sk->sk_gso_type; + if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) { +- th->window = htons(tcp_select_window(sk)); ++ th->window = htons(tp->ops->select_window(sk)); + tcp_ecn_send(sk, skb, th, tcp_header_size); + } else { + /* RFC1323: The window in SYN & SYN/ACK segments +@@ -1141,8 +1175,8 @@ + return err; + } + +-static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, +- gfp_t gfp_mask) ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask) + { + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +@@ -1153,7 +1187,7 @@ + * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, + * otherwise socket can stall. + */ +-static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1166,7 +1200,7 @@ + } + + /* Initialize TSO segments for a packet. */ +-static void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + if (skb->len <= mss_now || skb->ip_summed == CHECKSUM_NONE) { + /* Avoid the costly divide in the normal +@@ -1198,7 +1232,7 @@ + /* Pcount in the middle of the write queue got changed, we need to do various + * tweaks to fix counters + */ +-static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1364,7 +1398,7 @@ + /* This is similar to __pskb_pull_tail(). The difference is that pulled + * data is not copied, but immediately discarded. + */ +-static int __pskb_trim_head(struct sk_buff *skb, int len) ++int __pskb_trim_head(struct sk_buff *skb, int len) + { + struct skb_shared_info *shinfo; + int i, k, eat; +@@ -1586,6 +1620,7 @@ + + return mss_now; + } ++EXPORT_SYMBOL(tcp_current_mss); + + /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, +@@ -1609,7 +1644,7 @@ + tp->snd_cwnd_stamp = tcp_jiffies32; + } + +-static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) + { + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; + struct tcp_sock *tp = tcp_sk(sk); +@@ -1667,8 +1702,8 @@ + * But we can avoid doing the divide again given we already have + * skb_pcount = skb->len / mss_now + */ +-static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, +- const struct sk_buff *skb) ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb) + { + if (skb->len < tcp_skb_pcount(skb) * mss_now) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; +@@ -1726,11 +1761,11 @@ + } + + /* Returns the portion of skb which can be sent right away */ +-static unsigned int tcp_mss_split_point(const struct sock *sk, +- const struct sk_buff *skb, +- unsigned int mss_now, +- unsigned int max_segs, +- int nonagle) ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle) + { + const struct tcp_sock *tp = tcp_sk(sk); + u32 partial, needed, window, max_len; +@@ -1760,13 +1795,14 @@ + /* Can at least one segment of SKB be sent right now, according to the + * congestion window rules? If so, return how many segments are allowed. + */ +-static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb) ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, ++ const struct sk_buff *skb) + { + u32 in_flight, cwnd, halfcwnd; + + /* Don't be strict about the congestion window for the final FIN. */ +- if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ if (skb && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && + tcp_skb_pcount(skb) == 1) + return 1; + +@@ -1786,7 +1822,7 @@ + * This must be invoked the first time we consider transmitting + * SKB onto the wire. + */ +-static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + int tso_segs = tcp_skb_pcount(skb); + +@@ -1801,8 +1837,8 @@ + /* Return true if the Nagle test allows this packet to be + * sent now. + */ +-static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, +- unsigned int cur_mss, int nonagle) ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle) + { + /* Nagle rule does not apply to frames, which sit in the middle of the + * write_queue (they have no chances to get new data). +@@ -1814,7 +1850,8 @@ + return true; + + /* Don't use the nagle rule for urgent data (or for the final FIN). */ +- if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) ++ if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || ++ mptcp_is_data_fin(skb)) + return true; + + if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) +@@ -1824,9 +1861,8 @@ + } + + /* Does at least the first segment of SKB fit into the send window? */ +-static bool tcp_snd_wnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb, +- unsigned int cur_mss) ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss) + { + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + +@@ -1983,7 +2019,7 @@ + } + + /* If this packet won't get more data, do not wait. */ +- if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || mptcp_is_data_fin(skb)) + goto send_now; + + return true; +@@ -2283,6 +2319,23 @@ + tcp_chrono_set(tp, TCP_CHRONO_BUSY); + } + ++void tcp_write_queue_purge(struct sock *sk) ++{ ++ struct sk_buff *skb; ++ ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk) && !tcp_write_queue_empty(sk)) ++ mptcp_reinject_data(sk, 0); ++ ++ tcp_chrono_stop(sk, TCP_CHRONO_BUSY); ++ while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) ++ sk_wmem_free_skb(sk, skb); ++ sk_mem_reclaim(sk); ++ tcp_clear_all_retrans_hints(tcp_sk(sk)); ++ tcp_init_send_head(sk); ++ tcp_sk(sk)->packets_out = 0; ++ inet_csk(sk)->icsk_backoff = 0; ++} ++ + /* This routine writes packets to the network. It advances the + * send_head. This happens as incoming acks open up the remote + * window for us. +@@ -2297,7 +2350,7 @@ + * Returns true, if no segments are in flight and we have queued segments, + * but cannot send anything now because of SWS or another problem. + */ +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + int push_one, gfp_t gfp) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -2311,7 +2364,12 @@ + sent_pkts = 0; + + tcp_mstamp_refresh(tp); +- if (!push_one) { ++ ++ /* pmtu not yet supported with MPTCP. Should be possible, by early ++ * exiting the loop inside tcp_mtu_probe, making sure that only one ++ * single DSS-mapping gets probed. ++ */ ++ if (!push_one && !mptcp(tp)) { + /* Do MTU probing. */ + result = tcp_mtu_probe(sk); + if (!result) { +@@ -2417,7 +2475,8 @@ + if (push_one != 2) + tcp_schedule_loss_probe(sk, false); + is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); +- tcp_cwnd_validate(sk, is_cwnd_limited); ++ if (tp->ops->cwnd_validate) ++ tp->ops->cwnd_validate(sk, is_cwnd_limited); + return false; + } + return !tp->packets_out && tcp_send_head(sk); +@@ -2502,7 +2561,7 @@ + if (skb) { + if (tcp_snd_wnd_test(tp, skb, mss)) { + pcount = tp->packets_out; +- tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); ++ tp->ops->write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); + if (tp->packets_out > pcount) + goto probe_sent; + goto rearm_timer; +@@ -2569,8 +2628,8 @@ + if (unlikely(sk->sk_state == TCP_CLOSE)) + return; + +- if (tcp_write_xmit(sk, cur_mss, nonagle, 0, +- sk_gfp_mask(sk, GFP_ATOMIC))) ++ if (tcp_sk(sk)->ops->write_xmit(sk, cur_mss, nonagle, 0, ++ sk_gfp_mask(sk, GFP_ATOMIC))) + tcp_check_probe_timer(sk); + } + +@@ -2583,7 +2642,8 @@ + + BUG_ON(!skb || skb->len < mss_now); + +- tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); ++ tcp_sk(sk)->ops->write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, ++ sk->sk_allocation); + } + + /* This function returns the amount that we can raise the +@@ -2816,6 +2876,10 @@ + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + return; + ++ /* Currently not supported for MPTCP - but it should be possible */ ++ if (mptcp(tp)) ++ return; ++ + tcp_for_write_queue_from_safe(skb, tmp, sk) { + if (!tcp_can_collapse(sk, skb)) + break; +@@ -3273,7 +3337,7 @@ + + /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ + th->window = htons(min(req->rsk_rcv_wnd, 65535U)); +- tcp_options_write((__be32 *)(th + 1), NULL, &opts); ++ tcp_options_write((__be32 *)(th + 1), NULL, &opts, skb); + th->doff = (tcp_header_size >> 2); + __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); + +@@ -3354,13 +3418,13 @@ + if (rcv_wnd == 0) + rcv_wnd = dst_metric(dst, RTAX_INITRWND); + +- tcp_select_initial_window(tcp_full_space(sk), +- tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), +- &tp->rcv_wnd, +- &tp->window_clamp, +- sock_net(sk)->ipv4.sysctl_tcp_window_scaling, +- &rcv_wscale, +- rcv_wnd); ++ tp->ops->select_initial_window(tcp_full_space(sk), ++ tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), ++ &tp->rcv_wnd, ++ &tp->window_clamp, ++ sock_net(sk)->ipv4.sysctl_tcp_window_scaling, ++ &rcv_wscale, ++ rcv_wnd, sk); + + tp->rx_opt.rcv_wscale = rcv_wscale; + tp->rcv_ssthresh = tp->rcv_wnd; +@@ -3385,6 +3449,36 @@ + inet_csk(sk)->icsk_rto = tcp_timeout_init(sk); + inet_csk(sk)->icsk_retransmits = 0; + tcp_clear_retrans(tp); ++ ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP) && mptcp_doit(sk)) { ++ if (is_master_tp(tp)) { ++ tp->request_mptcp = 1; ++ mptcp_connect_init(sk); ++ } else if (tp->mptcp) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ tp->mptcp->snt_isn = tp->write_seq; ++ tp->mptcp->init_rcv_wnd = tp->rcv_wnd; ++ ++ /* Set nonce for new subflows */ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp->mptcp_loc_nonce = mptcp_v4_get_nonce( ++ inet->inet_saddr, ++ inet->inet_daddr, ++ inet->inet_sport, ++ inet->inet_dport); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp->mptcp_loc_nonce = mptcp_v6_get_nonce( ++ inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ inet->inet_sport, ++ inet->inet_dport); ++#endif ++ } ++ } ++#endif + } + + static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) +@@ -3645,6 +3739,7 @@ + { + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); + } ++EXPORT_SYMBOL_GPL(tcp_send_ack); + + /* This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. +@@ -3657,7 +3752,7 @@ + * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is + * out-of-date with SND.UNA-1 to probe window. + */ +-static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) + { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; +@@ -3743,7 +3838,7 @@ + unsigned long probe_max; + int err; + +- err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); ++ err = tp->ops->write_wakeup(sk, LINUX_MIB_TCPWINPROBE); + + if (tp->packets_out || !tcp_send_head(sk)) { + /* Cancel probe timer, if it is not required. */ +diff -aurN linux-4.14.174/net/ipv4/tcp_timer.c mptcp-mptcp_v0.94/net/ipv4/tcp_timer.c +--- linux-4.14.174/net/ipv4/tcp_timer.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv4/tcp_timer.c 2020-03-23 09:45:33.000000000 +0100 +@@ -20,6 +20,7 @@ + + #include + #include ++#include + #include + + int sysctl_tcp_thin_linear_timeouts __read_mostly; +@@ -31,7 +32,7 @@ + * Returns: Nothing (void) + */ + +-static void tcp_write_err(struct sock *sk) ++void tcp_write_err(struct sock *sk) + { + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); +@@ -87,7 +88,7 @@ + (!tp->snd_wnd && !tp->packets_out)) + do_reset = true; + if (do_reset) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + return 1; +@@ -162,9 +163,9 @@ + * after "boundary" unsuccessful, exponentially backed-off + * retransmissions with an initial RTO of TCP_RTO_MIN. + */ +-static bool retransmits_timed_out(struct sock *sk, +- unsigned int boundary, +- unsigned int timeout) ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout) + { + const unsigned int rto_base = TCP_RTO_MIN; + unsigned int linear_backoff_thresh, start_ts; +@@ -173,8 +174,14 @@ + return false; + + start_ts = tcp_sk(sk)->retrans_stamp; +- if (unlikely(!start_ts)) +- start_ts = tcp_skb_timestamp(tcp_write_queue_head(sk)); ++ if (unlikely(!start_ts)) { ++ struct sk_buff *skb = tcp_write_queue_head(sk); ++ ++ if (!skb) ++ return false; ++ ++ start_ts = tcp_skb_timestamp(skb); ++ } + + if (likely(timeout == 0)) { + linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base); +@@ -189,7 +196,7 @@ + } + + /* A write timeout has occurred. Process the after effects. */ +-static int tcp_write_timeout(struct sock *sk) ++int tcp_write_timeout(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -209,6 +216,17 @@ + sk_rethink_txhash(sk); + } + retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; ++ ++#ifdef CONFIG_MPTCP ++ /* Stop retransmitting MP_CAPABLE options in SYN if timed out. */ ++ if (tcp_sk(sk)->request_mptcp && ++ icsk->icsk_retransmits >= sysctl_mptcp_syn_retries) { ++ tcp_sk(sk)->request_mptcp = 0; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLERETRANSFALLBACK); ++ } ++#endif /* CONFIG_MPTCP */ ++ + expired = icsk->icsk_retransmits >= retry_until; + } else { + if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) { +@@ -304,18 +322,22 @@ + static void tcp_delack_timer(unsigned long data) + { + struct sock *sk = (struct sock *)data; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_delack_timer_handler(sk); + } else { + inet_csk(sk)->icsk_ack.blocked = 1; +- __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_DELAYEDACKLOCKED); + /* deleguate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -360,6 +382,10 @@ + + if (icsk->icsk_probes_out >= max_probes) { + abort: tcp_write_err(sk); ++ if (is_meta_sk(sk) && ++ mptcp_in_infinite_mapping_weak(tp->mpcb)) { ++ mptcp_sub_force_close_all(tp->mpcb, NULL); ++ } + } else { + /* Only send another probe if we didn't close things up. */ + tcp_send_probe0(sk); +@@ -580,7 +606,7 @@ + break; + case ICSK_TIME_RETRANS: + icsk->icsk_pending = 0; +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + break; + case ICSK_TIME_PROBE0: + icsk->icsk_pending = 0; +@@ -595,16 +621,19 @@ + static void tcp_write_timer(unsigned long data) + { + struct sock *sk = (struct sock *)data; ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_write_timer_handler(sk); + } else { + /* delegate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tcp_sk(sk))) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -634,11 +663,12 @@ + struct sock *sk = (struct sock *) data; + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + u32 elapsed; + + /* Only process if socket is not in use. */ +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { + /* Try again later. */ + inet_csk_reset_keepalive_timer (sk, HZ/20); + goto out; +@@ -650,16 +680,31 @@ + } + + tcp_mstamp_refresh(tp); ++ ++ if (tp->send_mp_fclose) { ++ if (icsk->icsk_retransmits >= MPTCP_FASTCLOSE_RETRIES) { ++ tcp_write_err(sk); ++ goto out; ++ } ++ ++ tcp_send_ack(sk); ++ icsk->icsk_retransmits++; ++ ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ elapsed = icsk->icsk_rto; ++ goto resched; ++ } ++ + if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { + if (tp->linger2 >= 0) { + const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; + + if (tmo > 0) { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto out; + } + } +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + goto death; + } + +@@ -684,11 +729,11 @@ + icsk->icsk_probes_out > 0) || + (icsk->icsk_user_timeout == 0 && + icsk->icsk_probes_out >= keepalive_probes(tp))) { +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_write_err(sk); + goto out; + } +- if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { ++ if (tp->ops->write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { + icsk->icsk_probes_out++; + elapsed = keepalive_intvl_when(tp); + } else { +@@ -712,7 +757,7 @@ + tcp_done(sk); + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +diff -aurN linux-4.14.174/net/ipv6/addrconf.c mptcp-mptcp_v0.94/net/ipv6/addrconf.c +--- linux-4.14.174/net/ipv6/addrconf.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv6/addrconf.c 2020-03-23 09:45:33.000000000 +0100 +@@ -928,6 +928,7 @@ + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +diff -aurN linux-4.14.174/net/ipv6/af_inet6.c mptcp-mptcp_v0.94/net/ipv6/af_inet6.c +--- linux-4.14.174/net/ipv6/af_inet6.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv6/af_inet6.c 2020-03-23 09:45:33.000000000 +0100 +@@ -107,8 +107,7 @@ + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static int inet6_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct inet_sock *inet; + struct ipv6_pinfo *np; +diff -aurN linux-4.14.174/net/ipv6/ipv6_sockglue.c mptcp-mptcp_v0.94/net/ipv6/ipv6_sockglue.c +--- linux-4.14.174/net/ipv6/ipv6_sockglue.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv6/ipv6_sockglue.c 2020-03-23 09:45:33.000000000 +0100 +@@ -48,6 +48,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -222,7 +224,12 @@ + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); + sk->sk_prot = &tcp_prot; +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +diff -aurN linux-4.14.174/net/ipv6/syncookies.c mptcp-mptcp_v0.94/net/ipv6/syncookies.c +--- linux-4.14.174/net/ipv6/syncookies.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv6/syncookies.c 2020-03-23 09:45:33.000000000 +0100 +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define COOKIEBITS 24 /* Upper bits store count */ +@@ -111,7 +113,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); + +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -133,6 +136,7 @@ + struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) + { + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -162,7 +166,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcpv6_ts_off(sock_net(sk), +@@ -175,14 +180,27 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp6_request_sock_ops, sk, false); ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); + if (!req) + goto out; + + ireq = inet_rsk(req); ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + treq = tcp_rsk(req); + treq->tfo_listener = false; + ++ /* Must be done before anything else, as it initializes ++ * hash_entry of the MPTCP request-sock. ++ */ ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + if (security_inet_conn_request(sk, skb, req)) + goto out_free; + +@@ -244,10 +262,10 @@ + } + + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); +- tcp_select_initial_window(tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(dst, RTAX_INITRWND), sk); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); +diff -aurN linux-4.14.174/net/ipv6/tcp_ipv6.c mptcp-mptcp_v0.94/net/ipv6/tcp_ipv6.c +--- linux-4.14.174/net/ipv6/tcp_ipv6.c 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/ipv6/tcp_ipv6.c 2020-03-23 09:45:33.000000000 +0100 +@@ -61,6 +61,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -69,14 +71,6 @@ + #include + #include + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req); +- +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); +- +-static const struct inet_connection_sock_af_ops ipv6_mapped; +-static const struct inet_connection_sock_af_ops ipv6_specific; + #ifdef CONFIG_TCP_MD5SIG + static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; + static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +@@ -88,7 +82,7 @@ + } + #endif + +-static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) + { + struct dst_entry *dst = skb_dst(skb); + +@@ -115,7 +109,7 @@ + ipv6_hdr(skb)->saddr.s6_addr32); + } + +-static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) + { + struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; +@@ -213,7 +207,12 @@ + sin.sin_port = usin->sin6_port; + sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; + +- icsk->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_mapped; + sk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -223,7 +222,12 @@ + + if (err) { + icsk->icsk_ext_hdr_len = exthdrlen; +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + sk->sk_backlog_rcv = tcp_v6_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +@@ -316,7 +320,7 @@ + return err; + } + +-static void tcp_v6_mtu_reduced(struct sock *sk) ++void tcp_v6_mtu_reduced(struct sock *sk) + { + struct dst_entry *dst; + +@@ -343,7 +347,7 @@ + struct ipv6_pinfo *np; + struct tcp_sock *tp; + __u32 seq, snd_una; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + bool fatal; + int err; + +@@ -367,8 +371,14 @@ + if (sk->sk_state == TCP_NEW_SYN_RECV) + return tcp_req_err(sk, seq, fatal); + +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk) && type != ICMPV6_PKT_TOOBIG) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + + if (sk->sk_state == TCP_CLOSE) +@@ -379,7 +389,6 @@ + goto out; + } + +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -413,11 +422,15 @@ + goto out; + + tp->mtu_info = ntohl(info); +- if (!sock_owned_by_user(sk)) ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v6_mtu_reduced(sk); +- else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, +- &sk->sk_tsq_flags)) +- sock_hold(sk); ++ } else { ++ if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, ++ &sk->sk_tsq_flags)) ++ sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); ++ } + goto out; + } + +@@ -432,7 +445,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + +@@ -442,14 +455,14 @@ + goto out; + } + +- if (!sock_owned_by_user(sk) && np->recverr) { ++ if (!sock_owned_by_user(meta_sk) && np->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else + sk->sk_err_soft = err; + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -495,8 +508,7 @@ + return err; + } + +- +-static void tcp_v6_reqsk_destructor(struct request_sock *req) ++void tcp_v6_reqsk_destructor(struct request_sock *req) + { + kfree(inet_rsk(req)->ipv6_opt); + kfree_skb(inet_rsk(req)->pktopts); +@@ -714,9 +726,10 @@ + return false; + } + +-static void tcp_v6_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v6_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); + struct inet_request_sock *ireq = inet_rsk(req); +@@ -738,6 +751,8 @@ + refcount_inc(&skb->users); + ireq->pktopts = skb; + } ++ ++ return 0; + } + + static struct dst_entry *tcp_v6_route_req(const struct sock *sk, +@@ -757,7 +772,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { + .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr), + #ifdef CONFIG_TCP_MD5SIG +@@ -775,9 +790,9 @@ + }; + + static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, + int oif, struct tcp_md5sig_key *key, int rst, +- u8 tclass, __be32 label) ++ u8 tclass, __be32 label, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct tcphdr *t1; +@@ -795,7 +810,10 @@ + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; + #endif +- ++#ifdef CONFIG_MPTCP ++ if (mptcp) ++ tot_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++#endif + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, + GFP_ATOMIC); + if (!buff) +@@ -833,6 +851,17 @@ + tcp_v6_md5_hash_hdr((__u8 *)topt, key, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, t1); ++ topt += 4; ++ } ++#endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ /* Construction of 32-bit data_ack */ ++ *topt++ = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ *topt++ = htonl(data_ack); + } + #endif + +@@ -879,7 +908,7 @@ + kfree_skb(buff); + } + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + u32 seq = 0, ack_seq = 0; +@@ -942,7 +971,7 @@ + (th->doff << 2); + + oif = sk ? sk->sk_bound_dev_if : 0; +- tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0); ++ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, 0, oif, key, 1, 0, 0, 0); + + #ifdef CONFIG_TCP_MD5SIG + out: +@@ -951,30 +980,37 @@ + } + + static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, u8 tclass, +- __be32 label) ++ __be32 label, int mptcp) + { +- tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, +- tclass, label); ++ tcp_v6_send_response(sk, skb, seq, ack, data_ack, win, tsval, tsecr, oif, ++ key, 0, tclass, label, mptcp); + } + + static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; + ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), +- tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); ++ tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), mptcp); + + inet_twsk_put(tw); + } + +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. +@@ -984,18 +1020,18 @@ + * exception of segments, MUST be right-shifted by + * Rcv.Wind.Shift bits: + */ +- tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? ++ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? + tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, sk->sk_bound_dev_if, + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), +- 0, 0); ++ 0, 0, 0); + } + + +-static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1006,7 +1042,7 @@ + return sk; + } + +-static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) + { + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_conn_request(sk, skb); +@@ -1032,11 +1068,11 @@ + sizeof(struct inet6_skb_parm)); + } + +-static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req, +- struct dst_entry *dst, +- struct request_sock *req_unhash, +- bool *own_req) ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req) + { + struct inet_request_sock *ireq; + struct ipv6_pinfo *newnp; +@@ -1073,7 +1109,15 @@ + + newnp->saddr = newsk->sk_v6_rcv_saddr; + +- inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ /* We must check on the request-socket because the listener ++ * socket's flag may have been changed halfway through. ++ */ ++ if (!inet_rsk(req)->saw_mpc) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; + newsk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -1120,6 +1164,14 @@ + if (!newsk) + goto out_nonewsk; + ++#ifdef CONFIG_MPTCP ++ /* If the meta_sk is v6-mapped we can end up here with the wrong af_ops. ++ * Just make sure that this subflow is v6. ++ */ ++ if (is_meta_sk(sk)) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ + /* + * No need to charge this sock to the relevant IPv6 refcnt debug socks + * count here, tcp_create_openreq_child now does this for us, see the +@@ -1248,7 +1300,7 @@ + * This is because we cannot sleep with the original spinlock + * held. + */ +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + { + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp; +@@ -1265,6 +1317,9 @@ + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_do_rcv(sk, skb); + ++ if (is_meta_sk(sk)) ++ return mptcp_v6_do_rcv(sk, skb); ++ + /* + * socket locking is here for SMP purposes as backlog rcv + * is currently called with bh processing disabled. +@@ -1392,6 +1447,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff*4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); +@@ -1405,8 +1464,8 @@ + int sdif = inet6_sdif(skb); + const struct tcphdr *th; + const struct ipv6hdr *hdr; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + struct net *net = dev_net(skb->dev); + +@@ -1459,12 +1518,42 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } + sock_hold(sk); + refcounted = true; ++ ++ if (is_meta_sk(sk)) { ++ bh_lock_sock(sk); ++ ++ if (!mptcp_can_new_subflow(sk)) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ bh_unlock_sock(sk); ++ ++ goto discard_and_relse; ++ } ++ ++ if (sock_owned_by_user(sk)) { ++ mptcp_prepare_for_backlog(sk, skb); ++ if (unlikely(sk_add_backlog(sk, skb, ++ sk->sk_rcvbuf + sk->sk_sndbuf))) { ++ reqsk_put(req); ++ ++ bh_unlock_sock(sk); ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ goto discard_and_relse; ++ } ++ ++ reqsk_put(req); ++ bh_unlock_sock(sk); ++ sock_put(sk); ++ ++ return 0; ++ } ++ } ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1474,10 +1563,14 @@ + } + if (!nsk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + goto discard_and_relse; + } + if (nsk == sk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + tcp_v6_restore_cb(skb); + } else if (tcp_child_process(sk, nsk, skb)) { + tcp_v6_send_reset(nsk, skb); +@@ -1487,6 +1580,7 @@ + return 0; + } + } ++ + if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { + __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); + goto discard_and_relse; +@@ -1513,15 +1607,25 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_v6_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1534,6 +1638,19 @@ + + tcp_v6_fill_cb(skb, hdr, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1586,6 +1703,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + /* Fall through to ACK */ + } + case TCP_TW_ACK: +@@ -1639,13 +1768,13 @@ + } + } + +-static struct timewait_sock_ops tcp6_timewait_sock_ops = { ++struct timewait_sock_ops tcp6_timewait_sock_ops = { + .twsk_obj_size = sizeof(struct tcp6_timewait_sock), + .twsk_unique = tcp_twsk_unique, + .twsk_destructor = tcp_twsk_destructor, + }; + +-static const struct inet_connection_sock_af_ops ipv6_specific = { ++const struct inet_connection_sock_af_ops ipv6_specific = { + .queue_xmit = inet6_csk_xmit, + .send_check = tcp_v6_send_check, + .rebuild_header = inet6_sk_rebuild_header, +@@ -1676,7 +1805,7 @@ + /* + * TCP over IPv4 via INET6 API + */ +-static const struct inet_connection_sock_af_ops ipv6_mapped = { ++const struct inet_connection_sock_af_ops ipv6_mapped = { + .queue_xmit = ip_queue_xmit, + .send_check = tcp_v4_send_check, + .rebuild_header = inet_sk_rebuild_header, +@@ -1712,7 +1841,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; +@@ -1721,7 +1855,7 @@ + return 0; + } + +-static void tcp_v6_destroy_sock(struct sock *sk) ++void tcp_v6_destroy_sock(struct sock *sk) + { + tcp_v4_destroy_sock(sk); + inet6_destroy_sock(sk); +@@ -1955,6 +2089,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + + /* thinking of making this const? Don't. +diff -aurN linux-4.14.174/net/Kconfig mptcp-mptcp_v0.94/net/Kconfig +--- linux-4.14.174/net/Kconfig 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/Kconfig 2020-03-23 09:45:33.000000000 +0100 +@@ -88,6 +88,7 @@ + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" + source "net/netlabel/Kconfig" ++source "net/mptcp/Kconfig" + + endif # if INET + +diff -aurN linux-4.14.174/net/Makefile mptcp-mptcp_v0.94/net/Makefile +--- linux-4.14.174/net/Makefile 2020-03-20 10:54:27.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/Makefile 2020-03-23 09:45:33.000000000 +0100 +@@ -20,6 +20,7 @@ + obj-$(CONFIG_XFRM) += xfrm/ + obj-$(CONFIG_UNIX) += unix/ + obj-$(CONFIG_NET) += ipv6/ ++obj-$(CONFIG_MPTCP) += mptcp/ + obj-$(CONFIG_PACKET) += packet/ + obj-$(CONFIG_NET_KEY) += key/ + obj-$(CONFIG_BRIDGE) += bridge/ +diff -aurN linux-4.14.174/net/mptcp/Kconfig mptcp-mptcp_v0.94/net/mptcp/Kconfig +--- linux-4.14.174/net/mptcp/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/Kconfig 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,129 @@ ++# ++# MPTCP configuration ++# ++config MPTCP ++ bool "MPTCP protocol" ++ depends on (IPV6=y || IPV6=n) ++ ---help--- ++ This replaces the normal TCP stack with a Multipath TCP stack, ++ able to use several paths at once. ++ ++menuconfig MPTCP_PM_ADVANCED ++ bool "MPTCP: advanced path-manager control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different path-managers. You should choose 'Y' here, ++ because otherwise you will not actively create new MPTCP-subflows. ++ ++if MPTCP_PM_ADVANCED ++ ++config MPTCP_FULLMESH ++ tristate "MPTCP Full-Mesh Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create a full-mesh among all IP-addresses. ++ ++config MPTCP_NDIFFPORTS ++ tristate "MPTCP ndiff-ports" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create multiple subflows between the same ++ pair of IP-addresses, modifying the source-port. You can set the number ++ of subflows via the mptcp_ndiffports-sysctl. ++ ++config MPTCP_BINDER ++ tristate "MPTCP Binder" ++ depends on (MPTCP=y) ++ ---help--- ++ This path-management module works like ndiffports, and adds the sysctl ++ option to set the gateway (and/or path to) per each additional subflow ++ via Loose Source Routing (IPv4 only). ++ ++choice ++ prompt "Default MPTCP Path-Manager" ++ default DEFAULT_DUMMY ++ help ++ Select the Path-Manager of your choice ++ ++ config DEFAULT_FULLMESH ++ bool "Full mesh" if MPTCP_FULLMESH=y ++ ++ config DEFAULT_NDIFFPORTS ++ bool "ndiff-ports" if MPTCP_NDIFFPORTS=y ++ ++ config DEFAULT_BINDER ++ bool "binder" if MPTCP_BINDER=y ++ ++ config DEFAULT_DUMMY ++ bool "Default" ++ ++endchoice ++ ++endif ++ ++config DEFAULT_MPTCP_PM ++ string ++ default "default" if DEFAULT_DUMMY ++ default "fullmesh" if DEFAULT_FULLMESH ++ default "ndiffports" if DEFAULT_NDIFFPORTS ++ default "binder" if DEFAULT_BINDER ++ default "default" ++ ++menuconfig MPTCP_SCHED_ADVANCED ++ bool "MPTCP: advanced scheduler control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different schedulers. You should choose 'Y' here, ++ if you want to choose a different scheduler than the default one. ++ ++if MPTCP_SCHED_ADVANCED ++ ++config MPTCP_ROUNDROBIN ++ tristate "MPTCP Round-Robin" ++ depends on (MPTCP=y) ++ ---help--- ++ This is a very simple round-robin scheduler. Probably has bad performance ++ but might be interesting for researchers. ++ ++config MPTCP_REDUNDANT ++ tristate "MPTCP Redundant" ++ depends on (MPTCP=y) ++ ---help--- ++ This scheduler sends all packets redundantly over all subflows to decreases ++ latency and jitter on the cost of lower throughput. ++ ++choice ++ prompt "Default MPTCP Scheduler" ++ default DEFAULT_SCHEDULER ++ help ++ Select the Scheduler of your choice ++ ++ config DEFAULT_SCHEDULER ++ bool "Default" ++ ---help--- ++ This is the default scheduler, sending first on the subflow ++ with the lowest RTT. ++ ++ config DEFAULT_ROUNDROBIN ++ bool "Round-Robin" if MPTCP_ROUNDROBIN=y ++ ---help--- ++ This is the round-rob scheduler, sending in a round-robin ++ fashion.. ++ ++ config DEFAULT_REDUNDANT ++ bool "Redundant" if MPTCP_REDUNDANT=y ++ ---help--- ++ This is the redundant scheduler, sending packets redundantly over ++ all the subflows. ++ ++endchoice ++endif ++ ++config DEFAULT_MPTCP_SCHED ++ string ++ depends on (MPTCP=y) ++ default "default" if DEFAULT_SCHEDULER ++ default "roundrobin" if DEFAULT_ROUNDROBIN ++ default "redundant" if DEFAULT_REDUNDANT ++ default "default" ++ +diff -aurN linux-4.14.174/net/mptcp/Makefile mptcp-mptcp_v0.94/net/mptcp/Makefile +--- linux-4.14.174/net/mptcp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/Makefile 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,22 @@ ++# ++## Makefile for MultiPath TCP support code. ++# ++# ++ ++obj-$(CONFIG_MPTCP) += mptcp.o ++ ++mptcp-y := mptcp_ctrl.o mptcp_ipv4.o mptcp_pm.o \ ++ mptcp_output.o mptcp_input.o mptcp_sched.o ++ ++obj-$(CONFIG_TCP_CONG_LIA) += mptcp_coupled.o ++obj-$(CONFIG_TCP_CONG_OLIA) += mptcp_olia.o ++obj-$(CONFIG_TCP_CONG_WVEGAS) += mptcp_wvegas.o ++obj-$(CONFIG_TCP_CONG_BALIA) += mptcp_balia.o ++obj-$(CONFIG_MPTCP_FULLMESH) += mptcp_fullmesh.o ++obj-$(CONFIG_MPTCP_NDIFFPORTS) += mptcp_ndiffports.o ++obj-$(CONFIG_MPTCP_BINDER) += mptcp_binder.o ++obj-$(CONFIG_MPTCP_ROUNDROBIN) += mptcp_rr.o ++obj-$(CONFIG_MPTCP_REDUNDANT) += mptcp_redundant.o ++ ++mptcp-$(subst m,y,$(CONFIG_IPV6)) += mptcp_ipv6.o ++ +diff -aurN linux-4.14.174/net/mptcp/mptcp_balia.c mptcp-mptcp_v0.94/net/mptcp/mptcp_balia.c +--- linux-4.14.174/net/mptcp/mptcp_balia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_balia.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,268 @@ ++/* ++ * MPTCP implementation - Balia Congestion Control ++ * (Balanced Linked Adaptation Algorithm) ++ * ++ * Analysis, Design and Implementation: ++ * Qiuyu Peng ++ * Anwar Walid ++ * Jaehyun Hwang ++ * Steven H. Low ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++/* The variable 'rate' (i.e., x_r) will be scaled ++ * e.g., from B/s to KB/s, MB/s, or GB/s ++ * if max_rate > 2^rate_scale_limit ++ */ ++ ++static int rate_scale_limit = 25; ++static int alpha_scale = 10; ++static int scale_num = 5; ++ ++struct mptcp_balia { ++ u64 ai; ++ u64 md; ++ bool forced_update; ++}; ++ ++static inline int mptcp_balia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_ai(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai; ++} ++ ++static inline void mptcp_set_ai(const struct sock *meta_sk, u64 ai) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai = ai; ++} ++ ++static inline u64 mptcp_get_md(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md; ++} ++ ++static inline void mptcp_set_md(const struct sock *meta_sk, u64 md) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md = md; ++} ++ ++static inline u64 mptcp_balia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_balia_recalc_ai(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ const struct sock *sub_sk; ++ u64 max_rate = 0, rate = 0, sum_rate = 0; ++ u64 alpha, ai = tp->snd_cwnd, md = (tp->snd_cwnd >> 1); ++ int num_scale_down = 0; ++ ++ if (!mpcb) ++ return; ++ ++ /* Only one subflow left - fall back to normal reno-behavior */ ++ if (mpcb->cnt_established <= 1) ++ goto exit; ++ ++ /* Find max_rate first */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ sum_rate += tmp; ++ ++ if (tp == sub_tp) ++ rate = tmp; ++ ++ if (tmp >= max_rate) ++ max_rate = tmp; ++ } ++ ++ /* At least, the current subflow should be able to send */ ++ if (unlikely(!rate)) ++ goto exit; ++ ++ alpha = div64_u64(max_rate, rate); ++ ++ /* Scale down max_rate if it is too high (e.g., >2^25) */ ++ while (max_rate > mptcp_balia_scale(1, rate_scale_limit)) { ++ max_rate >>= scale_num; ++ num_scale_down++; ++ } ++ ++ if (num_scale_down) { ++ sum_rate = 0; ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ tmp >>= (scale_num * num_scale_down); ++ ++ sum_rate += tmp; ++ } ++ rate >>= (scale_num * num_scale_down); ++ } ++ ++ /* (sum_rate)^2 * 10 * w_r ++ * ai = ------------------------------------ ++ * (x_r + max_rate) * (4x_r + max_rate) ++ */ ++ sum_rate *= sum_rate; ++ ++ ai = div64_u64(sum_rate * 10, rate + max_rate); ++ ai = div64_u64(ai * tp->snd_cwnd, (rate << 2) + max_rate); ++ ++ if (unlikely(!ai)) ++ ai = tp->snd_cwnd; ++ ++ md = ((tp->snd_cwnd >> 1) * min(mptcp_balia_scale(alpha, alpha_scale), ++ mptcp_balia_scale(3, alpha_scale) >> 1)) ++ >> alpha_scale; ++ ++exit: ++ mptcp_set_ai(sk, ai); ++ mptcp_set_md(sk, md); ++} ++ ++static void mptcp_balia_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(sk, 0); ++ mptcp_set_ai(sk, 0); ++ mptcp_set_md(sk, 0); ++ } ++} ++ ++static void mptcp_balia_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_COMPLETE_CWR || event == CA_EVENT_LOSS) ++ mptcp_balia_recalc_ai(sk); ++} ++ ++static void mptcp_balia_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(sk, 1); ++} ++ ++static void mptcp_balia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_balia_recalc_ai(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_balia_recalc_ai(sk); ++ mptcp_set_forced(sk, 0); ++ } ++ ++ if (mpcb->cnt_established > 1) ++ snd_cwnd = (int) mptcp_get_ai(sk); ++ else ++ snd_cwnd = tp->snd_cwnd; ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_balia_recalc_ai(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static u32 mptcp_balia_ssthresh(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ if (unlikely(!mptcp(tp) || mpcb->cnt_established <= 1)) ++ return tcp_reno_ssthresh(sk); ++ else ++ return max((u32)(tp->snd_cwnd - mptcp_get_md(sk)), 1U); ++} ++ ++static struct tcp_congestion_ops mptcp_balia = { ++ .init = mptcp_balia_init, ++ .ssthresh = mptcp_balia_ssthresh, ++ .cong_avoid = mptcp_balia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_balia_cwnd_event, ++ .set_state = mptcp_balia_set_state, ++ .owner = THIS_MODULE, ++ .name = "balia", ++}; ++ ++static int __init mptcp_balia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_balia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_balia); ++} ++ ++static void __exit mptcp_balia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_balia); ++} ++ ++module_init(mptcp_balia_register); ++module_exit(mptcp_balia_unregister); ++ ++MODULE_AUTHOR("Jaehyun Hwang, Anwar Walid, Qiuyu Peng, Steven H. Low"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP BALIA CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_binder.c mptcp-mptcp_v0.94/net/mptcp/mptcp_binder.c +--- linux-4.14.174/net/mptcp/mptcp_binder.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_binder.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,490 @@ ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MPTCP_GW_MAX_LISTS 10 ++#define MPTCP_GW_LIST_MAX_LEN 6 ++#define MPTCP_GW_SYSCTL_MAX_LEN (15 * MPTCP_GW_LIST_MAX_LEN * \ ++ MPTCP_GW_MAX_LISTS) ++ ++struct mptcp_gw_list { ++ struct in_addr list[MPTCP_GW_MAX_LISTS][MPTCP_GW_LIST_MAX_LEN]; ++ u8 len[MPTCP_GW_MAX_LISTS]; ++}; ++ ++struct binder_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++ ++ /* Prevent multiple sub-sockets concurrently iterating over sockets */ ++ spinlock_t *flow_lock; ++}; ++ ++static struct mptcp_gw_list *mptcp_gws; ++static rwlock_t mptcp_gws_lock; ++ ++static int mptcp_binder_ndiffports __read_mostly = 1; ++ ++static char sysctl_mptcp_binder_gateways[MPTCP_GW_SYSCTL_MAX_LEN] __read_mostly; ++ ++static int mptcp_get_avail_list_ipv4(struct sock *sk) ++{ ++ int i, j, list_taken, opt_ret, opt_len; ++ unsigned char *opt_ptr, *opt_end_ptr, opt[MAX_IPOPTLEN]; ++ ++ for (i = 0; i < MPTCP_GW_MAX_LISTS; ++i) { ++ if (mptcp_gws->len[i] == 0) ++ goto error; ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: List %i\n", i); ++ list_taken = 0; ++ ++ /* Loop through all sub-sockets in this connection */ ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: Next sock\n"); ++ ++ /* Reset length and options buffer, then retrieve ++ * from socket ++ */ ++ opt_len = MAX_IPOPTLEN; ++ memset(opt, 0, MAX_IPOPTLEN); ++ opt_ret = ip_getsockopt(sk, IPPROTO_IP, ++ IP_OPTIONS, (char __user *)opt, (int __user *)&opt_len); ++ if (opt_ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket getsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, opt_ret); ++ goto error; ++ } ++ ++ /* If socket has no options, it has no stake in this list */ ++ if (opt_len <= 0) ++ continue; ++ ++ /* Iterate options buffer */ ++ for (opt_ptr = &opt[0]; opt_ptr < &opt[opt_len]; opt_ptr++) { ++ if (*opt_ptr == IPOPT_LSRR) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: LSRR options found\n"); ++ goto sock_lsrr; ++ } ++ } ++ continue; ++ ++sock_lsrr: ++ /* Pointer to the 2nd to last address */ ++ opt_end_ptr = opt_ptr+(*(opt_ptr+1))-4; ++ ++ /* Addresses start 3 bytes after type offset */ ++ opt_ptr += 3; ++ j = 0; ++ ++ /* Different length lists cannot be the same */ ++ if ((opt_end_ptr-opt_ptr)/4 != mptcp_gws->len[i]) ++ continue; ++ ++ /* Iterate if we are still inside options list ++ * and sysctl list ++ */ ++ while (opt_ptr < opt_end_ptr && j < mptcp_gws->len[i]) { ++ /* If there is a different address, this list must ++ * not be set on this socket ++ */ ++ if (memcmp(&mptcp_gws->list[i][j], opt_ptr, 4)) ++ break; ++ ++ /* Jump 4 bytes to next address */ ++ opt_ptr += 4; ++ j++; ++ } ++ ++ /* Reached the end without a differing address, lists ++ * are therefore identical. ++ */ ++ if (j == mptcp_gws->len[i]) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List already used\n"); ++ list_taken = 1; ++ break; ++ } ++ } ++ ++ /* Free list found if not taken by a socket */ ++ if (!list_taken) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List free\n"); ++ break; ++ } ++ } ++ ++ if (i >= MPTCP_GW_MAX_LISTS) ++ goto error; ++ ++ return i; ++error: ++ return -1; ++} ++ ++/* The list of addresses is parsed each time a new connection is opened, ++ * to make sure it's up to date. In case of error, all the lists are ++ * marked as unavailable and the subflow's fingerprint is set to 0. ++ */ ++static void mptcp_v4_add_lsrr(struct sock *sk, struct in_addr addr) ++{ ++ int i, j, ret; ++ unsigned char opt[MAX_IPOPTLEN] = {0}; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct binder_priv *fmp = (struct binder_priv *)&tp->mpcb->mptcp_pm[0]; ++ ++ /* Read lock: multiple sockets can read LSRR addresses at the same ++ * time, but writes are done in mutual exclusion. ++ * Spin lock: must search for free list for one socket at a time, or ++ * multiple sockets could take the same list. ++ */ ++ read_lock(&mptcp_gws_lock); ++ spin_lock(fmp->flow_lock); ++ ++ i = mptcp_get_avail_list_ipv4(sk); ++ ++ /* Execution enters here only if a free path is found. ++ */ ++ if (i >= 0) { ++ opt[0] = IPOPT_NOP; ++ opt[1] = IPOPT_LSRR; ++ opt[2] = sizeof(mptcp_gws->list[i][0].s_addr) * ++ (mptcp_gws->len[i] + 1) + 3; ++ opt[3] = IPOPT_MINOFF; ++ for (j = 0; j < mptcp_gws->len[i]; ++j) ++ memcpy(opt + 4 + ++ (j * sizeof(mptcp_gws->list[i][0].s_addr)), ++ &mptcp_gws->list[i][j].s_addr, ++ sizeof(mptcp_gws->list[i][0].s_addr)); ++ /* Final destination must be part of IP_OPTIONS parameter. */ ++ memcpy(opt + 4 + (j * sizeof(addr.s_addr)), &addr.s_addr, ++ sizeof(addr.s_addr)); ++ ++ /* setsockopt must be inside the lock, otherwise another ++ * subflow could fail to see that we have taken a list. ++ */ ++ ret = ip_setsockopt(sk, IPPROTO_IP, IP_OPTIONS, (char __user *)opt, ++ 4 + sizeof(mptcp_gws->list[i][0].s_addr) * (mptcp_gws->len[i] + 1)); ++ ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsock setsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, ret); ++ } ++ } ++ ++ spin_unlock(fmp->flow_lock); ++ read_unlock(&mptcp_gws_lock); ++ ++ return; ++} ++ ++/* Parses gateways string for a list of paths to different ++ * gateways, and stores them for use with the Loose Source Routing (LSRR) ++ * socket option. Each list must have "," separated addresses, and the lists ++ * themselves must be separated by "-". Returns -1 in case one or more of the ++ * addresses is not a valid ipv4/6 address. ++ */ ++static int mptcp_parse_gateway_ipv4(char *gateways) ++{ ++ int i, j, k, ret; ++ char *tmp_string = NULL; ++ struct in_addr tmp_addr; ++ ++ tmp_string = kzalloc(16, GFP_KERNEL); ++ if (tmp_string == NULL) ++ return -ENOMEM; ++ ++ write_lock(&mptcp_gws_lock); ++ ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ ++ /* A TMP string is used since inet_pton needs a null terminated string ++ * but we do not want to modify the sysctl for obvious reasons. ++ * i will iterate over the SYSCTL string, j will iterate over the ++ * temporary string where each IP is copied into, k will iterate over ++ * the IPs in each list. ++ */ ++ for (i = j = k = 0; ++ i < MPTCP_GW_SYSCTL_MAX_LEN && k < MPTCP_GW_MAX_LISTS; ++ ++i) { ++ if (gateways[i] == '-' || gateways[i] == ',' || gateways[i] == '\0') { ++ /* If the temp IP is empty and the current list is ++ * empty, we are done. ++ */ ++ if (j == 0 && mptcp_gws->len[k] == 0) ++ break; ++ ++ /* Terminate the temp IP string, then if it is ++ * non-empty parse the IP and copy it. ++ */ ++ tmp_string[j] = '\0'; ++ if (j > 0) { ++ mptcp_debug("mptcp_parse_gateway_list tmp: %s i: %d\n", tmp_string, i); ++ ++ ret = in4_pton(tmp_string, strlen(tmp_string), ++ (u8 *)&tmp_addr.s_addr, '\0', ++ NULL); ++ ++ if (ret) { ++ mptcp_debug("mptcp_parse_gateway_list ret: %d s_addr: %pI4\n", ++ ret, ++ &tmp_addr.s_addr); ++ memcpy(&mptcp_gws->list[k][mptcp_gws->len[k]].s_addr, ++ &tmp_addr.s_addr, ++ sizeof(tmp_addr.s_addr)); ++ mptcp_gws->len[k]++; ++ j = 0; ++ tmp_string[j] = '\0'; ++ /* Since we can't impose a limit to ++ * what the user can input, make sure ++ * there are not too many IPs in the ++ * SYSCTL string. ++ */ ++ if (mptcp_gws->len[k] > MPTCP_GW_LIST_MAX_LEN) { ++ mptcp_debug("mptcp_parse_gateway_list too many members in list %i: max %i\n", ++ k, ++ MPTCP_GW_LIST_MAX_LEN); ++ goto error; ++ } ++ } else { ++ goto error; ++ } ++ } ++ ++ if (gateways[i] == '-' || gateways[i] == '\0') ++ ++k; ++ } else { ++ tmp_string[j] = gateways[i]; ++ ++j; ++ } ++ } ++ ++ /* Number of flows is number of gateway lists plus master flow */ ++ mptcp_binder_ndiffports = k+1; ++ ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ ++ return 0; ++ ++error: ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ memset(gateways, 0, sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN); ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ return -1; ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct binder_priv *pm_priv = container_of(work, ++ struct binder_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (mptcp_binder_ndiffports > iter && ++ mptcp_binder_ndiffports > mpcb->cnt_subflows) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void binder_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *fmp = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ static DEFINE_SPINLOCK(flow_lock); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(meta_sk)) { ++ mptcp_fallback_default(mpcb); ++ return; ++ } ++#endif ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ fmp->flow_lock = &flow_lock; ++} ++ ++static void binder_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *pm_priv = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int binder_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++/* Callback functions, executed when syctl mptcp.mptcp_gateways is updated. ++ * Inspired from proc_tcp_congestion_control(). ++ */ ++static int proc_mptcp_gateways(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ struct ctl_table tbl = { ++ .maxlen = MPTCP_GW_SYSCTL_MAX_LEN, ++ }; ++ ++ if (write) { ++ tbl.data = kzalloc(MPTCP_GW_SYSCTL_MAX_LEN, GFP_KERNEL); ++ if (tbl.data == NULL) ++ return -ENOMEM; ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (ret == 0) { ++ ret = mptcp_parse_gateway_ipv4(tbl.data); ++ memcpy(ctl->data, tbl.data, MPTCP_GW_SYSCTL_MAX_LEN); ++ } ++ kfree(tbl.data); ++ } else { ++ ret = proc_dostring(ctl, write, buffer, lenp, ppos); ++ } ++ ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops binder __read_mostly = { ++ .new_session = binder_new_session, ++ .fully_established = binder_create_subflows, ++ .get_local_id = binder_get_local_id, ++ .init_subsocket_v4 = mptcp_v4_add_lsrr, ++ .name = "binder", ++ .owner = THIS_MODULE, ++}; ++ ++static struct ctl_table binder_table[] = { ++ { ++ .procname = "mptcp_binder_gateways", ++ .data = &sysctl_mptcp_binder_gateways, ++ .maxlen = sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN, ++ .mode = 0644, ++ .proc_handler = &proc_mptcp_gateways ++ }, ++ { } ++}; ++ ++static struct ctl_table_header *mptcp_sysctl_binder; ++ ++/* General initialization of MPTCP_PM */ ++static int __init binder_register(void) ++{ ++ mptcp_gws = kzalloc(sizeof(*mptcp_gws), GFP_KERNEL); ++ if (!mptcp_gws) ++ return -ENOMEM; ++ ++ rwlock_init(&mptcp_gws_lock); ++ ++ BUILD_BUG_ON(sizeof(struct binder_priv) > MPTCP_PM_SIZE); ++ ++ mptcp_sysctl_binder = register_net_sysctl(&init_net, "net/mptcp", ++ binder_table); ++ if (!mptcp_sysctl_binder) ++ goto sysctl_fail; ++ ++ if (mptcp_register_path_manager(&binder)) ++ goto pm_failed; ++ ++ return 0; ++ ++pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++sysctl_fail: ++ kfree(mptcp_gws); ++ ++ return -1; ++} ++ ++static void binder_unregister(void) ++{ ++ mptcp_unregister_path_manager(&binder); ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++ kfree(mptcp_gws); ++} ++ ++module_init(binder_register); ++module_exit(binder_unregister); ++ ++MODULE_AUTHOR("Luca Boccassi, Duncan Eastoe, Christoph Paasch (ndiffports)"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BINDER MPTCP"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_coupled.c mptcp-mptcp_v0.94/net/mptcp/mptcp_coupled.c +--- linux-4.14.174/net/mptcp/mptcp_coupled.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_coupled.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,271 @@ ++/* ++ * MPTCP implementation - Linked Increase congestion control Algorithm (LIA) ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++#include ++#include ++ ++#include ++ ++/* Scaling is done in the numerator with alpha_scale_num and in the denominator ++ * with alpha_scale_den. ++ * ++ * To downscale, we just need to use alpha_scale. ++ * ++ * We have: alpha_scale = alpha_scale_num / (alpha_scale_den ^ 2) ++ */ ++static int alpha_scale_den = 10; ++static int alpha_scale_num = 32; ++static int alpha_scale = 12; ++ ++struct mptcp_ccc { ++ u64 alpha; ++ bool forced_update; ++}; ++ ++static inline int mptcp_ccc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_alpha(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha; ++} ++ ++static inline void mptcp_set_alpha(const struct sock *meta_sk, u64 alpha) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha = alpha; ++} ++ ++static inline u64 mptcp_ccc_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_ccc_recalc_alpha(const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ const struct sock *sub_sk; ++ int best_cwnd = 0, best_rtt = 0, can_send = 0; ++ u64 max_numerator = 0, sum_denominator = 0, alpha = 1; ++ ++ if (!mpcb) ++ return; ++ ++ /* Only one subflow left - fall back to normal reno-behavior ++ * (set alpha to 1) ++ */ ++ if (mpcb->cnt_established <= 1) ++ goto exit; ++ ++ /* Do regular alpha-calculation for multiple subflows */ ++ ++ /* Find the max numerator of the alpha-calculation */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ can_send++; ++ ++ /* We need to look for the path, that provides the max-value. ++ * Integer-overflow is not possible here, because ++ * tmp will be in u64. ++ */ ++ tmp = div64_u64(mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_num), (u64)sub_tp->srtt_us * sub_tp->srtt_us); ++ ++ if (tmp >= max_numerator) { ++ max_numerator = tmp; ++ best_cwnd = sub_tp->snd_cwnd; ++ best_rtt = sub_tp->srtt_us; ++ } ++ } ++ ++ /* No subflow is able to send - we don't care anymore */ ++ if (unlikely(!can_send)) ++ goto exit; ++ ++ /* Calculate the denominator */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ sum_denominator += div_u64( ++ mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_den) * best_rtt, ++ sub_tp->srtt_us); ++ } ++ sum_denominator *= sum_denominator; ++ if (unlikely(!sum_denominator)) { ++ pr_err("%s: sum_denominator == 0, cnt_established:%d\n", ++ __func__, mpcb->cnt_established); ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ pr_err("%s: pi:%d, state:%d\n, rtt:%u, cwnd: %u", ++ __func__, sub_tp->mptcp->path_index, ++ sub_sk->sk_state, sub_tp->srtt_us, ++ sub_tp->snd_cwnd); ++ } ++ } ++ ++ alpha = div64_u64(mptcp_ccc_scale(best_cwnd, alpha_scale_num), sum_denominator); ++ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++exit: ++ mptcp_set_alpha(mptcp_meta_sk(sk), alpha); ++} ++ ++static void mptcp_ccc_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ mptcp_set_alpha(mptcp_meta_sk(sk), 1); ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mptcp_ccc_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_LOSS) ++ mptcp_ccc_recalc_alpha(sk); ++} ++ ++static void mptcp_ccc_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(mptcp_meta_sk(sk), 1); ++} ++ ++static void mptcp_ccc_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_ccc_recalc_alpha(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_ccc_recalc_alpha(sk); ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ } ++ ++ if (mpcb->cnt_established > 1) { ++ u64 alpha = mptcp_get_alpha(mptcp_meta_sk(sk)); ++ ++ /* This may happen, if at the initialization, the mpcb ++ * was not yet attached to the sock, and thus ++ * initializing alpha failed. ++ */ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++ snd_cwnd = (int) div_u64 ((u64) mptcp_ccc_scale(1, alpha_scale), ++ alpha); ++ ++ /* snd_cwnd_cnt >= max (scale * tot_cwnd / alpha, cwnd) ++ * Thus, we select here the max value. ++ */ ++ if (snd_cwnd < tp->snd_cwnd) ++ snd_cwnd = tp->snd_cwnd; ++ } else { ++ snd_cwnd = tp->snd_cwnd; ++ } ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_ccc_recalc_alpha(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_ccc = { ++ .init = mptcp_ccc_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_ccc_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_ccc_cwnd_event, ++ .set_state = mptcp_ccc_set_state, ++ .owner = THIS_MODULE, ++ .name = "lia", ++}; ++ ++static int __init mptcp_ccc_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_ccc) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_ccc); ++} ++ ++static void __exit mptcp_ccc_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_ccc); ++} ++ ++module_init(mptcp_ccc_register); ++module_exit(mptcp_ccc_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch, Sébastien Barré"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP LINKED INCREASE CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_ctrl.c mptcp-mptcp_v0.94/net/mptcp/mptcp_ctrl.c +--- linux-4.14.174/net/mptcp/mptcp_ctrl.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_ctrl.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,3038 @@ ++/* ++ * MPTCP implementation - MPTCP-control ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *mptcp_sock_cache __read_mostly; ++static struct kmem_cache *mptcp_cb_cache __read_mostly; ++static struct kmem_cache *mptcp_tw_cache __read_mostly; ++ ++int sysctl_mptcp_enabled __read_mostly = 1; ++EXPORT_SYMBOL(sysctl_mptcp_enabled); ++int sysctl_mptcp_version __read_mostly = 0; ++static int min_mptcp_version; ++static int max_mptcp_version = 1; ++int sysctl_mptcp_checksum __read_mostly = 1; ++int sysctl_mptcp_debug __read_mostly; ++EXPORT_SYMBOL(sysctl_mptcp_debug); ++int sysctl_mptcp_syn_retries __read_mostly = 3; ++ ++bool mptcp_init_failed __read_mostly; ++ ++struct static_key mptcp_static_key = STATIC_KEY_INIT_FALSE; ++EXPORT_SYMBOL(mptcp_static_key); ++ ++static int proc_mptcp_path_manager(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_PM_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_path_manager(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_path_manager(val); ++ return ret; ++} ++ ++static int proc_mptcp_scheduler(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_SCHED_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_scheduler(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_scheduler(val); ++ return ret; ++} ++ ++static struct ctl_table mptcp_table[] = { ++ { ++ .procname = "mptcp_enabled", ++ .data = &sysctl_mptcp_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_version", ++ .data = &sysctl_mptcp_version, ++ .mode = 0644, ++ .maxlen = sizeof(int), ++ .proc_handler = &proc_dointvec_minmax, ++ .extra1 = &min_mptcp_version, ++ .extra2 = &max_mptcp_version, ++ }, ++ { ++ .procname = "mptcp_checksum", ++ .data = &sysctl_mptcp_checksum, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_debug", ++ .data = &sysctl_mptcp_debug, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_syn_retries", ++ .data = &sysctl_mptcp_syn_retries, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_path_manager", ++ .mode = 0644, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ .proc_handler = proc_mptcp_path_manager, ++ }, ++ { ++ .procname = "mptcp_scheduler", ++ .mode = 0644, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ .proc_handler = proc_mptcp_scheduler, ++ }, ++ { } ++}; ++ ++static inline u32 mptcp_hash_tk(u32 token) ++{ ++ return token % MPTCP_HASH_SIZE; ++} ++ ++struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++EXPORT_SYMBOL(tk_hashtable); ++ ++/* The following hash table is used to avoid collision of token */ ++static struct hlist_nulls_head mptcp_reqsk_tk_htb[MPTCP_HASH_SIZE]; ++ ++/* Lock, protecting the two hash-tables that hold the token. Namely, ++ * mptcp_reqsk_tk_htb and tk_hashtable ++ */ ++static spinlock_t mptcp_tk_hashlock; ++ ++static bool mptcp_reqsk_find_tk(const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct mptcp_request_sock *mtreqsk; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(mtreqsk, node, ++ &mptcp_reqsk_tk_htb[hash], hash_entry) { ++ if (token == mtreqsk->mptcp_loc_token) ++ return true; ++ } ++ /* A request-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_reqsk_insert_tk(struct request_sock *reqsk, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ ++ hlist_nulls_add_head_rcu(&mptcp_rsk(reqsk)->hash_entry, ++ &mptcp_reqsk_tk_htb[hash]); ++} ++ ++static void mptcp_reqsk_remove_tk(const struct request_sock *reqsk) ++{ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&mptcp_rsk(reqsk)->hash_entry); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++void mptcp_reqsk_destructor(struct request_sock *req) ++{ ++ if (!mptcp_rsk(req)->is_sub) ++ mptcp_reqsk_remove_tk(req); ++} ++ ++static void __mptcp_hash_insert(struct tcp_sock *meta_tp, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ hlist_nulls_add_head_rcu(&meta_tp->tk_table, &tk_hashtable[hash]); ++ meta_tp->inside_tk_table = 1; ++} ++ ++static bool mptcp_find_token(u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], tk_table) { ++ if (token == meta_tp->mptcp_loc_token) ++ return true; ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_set_key_reqsk(struct request_sock *req, ++ const struct sk_buff *skb, ++ u32 seed) ++{ ++ const struct inet_request_sock *ireq = inet_rsk(req); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ mtreq->mptcp_loc_key = mptcp_v4_get_key(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ mtreq->mptcp_loc_key = mptcp_v6_get_key(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#endif ++ } ++ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++} ++ ++/* New MPTCP-connection request, prepare a new token for the meta-socket that ++ * will be created in mptcp_check_req_master(), and store the received token. ++ */ ++static void mptcp_reqsk_new_mptcp(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tp->mptcp_ver) ++ mtreq->mptcp_ver = tp->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_reqsk(req, skb, mptcp_seed++); ++ } while (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)); ++ mptcp_reqsk_insert_tk(req, mtreq->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++} ++ ++static int mptcp_reqsk_new_cookie(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tcp_sk(sk)->mptcp_ver) ++ mtreq->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ mptcp_set_key_reqsk(req, skb, tcp_rsk(req)->snt_isn); ++ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return false; ++ } ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ ++ return true; ++} ++ ++static void mptcp_set_key_sk(const struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_sock *isk = inet_sk(sk); ++ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp_loc_key = mptcp_v4_get_key(isk->inet_saddr, ++ isk->inet_daddr, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp_loc_key = mptcp_v6_get_key(inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#endif ++ ++ mptcp_key_sha1(tp->mptcp_loc_key, ++ &tp->mptcp_loc_token, NULL); ++} ++ ++#ifdef HAVE_JUMP_LABEL ++static atomic_t mptcp_needed_deferred; ++static atomic_t mptcp_wanted; ++ ++static void mptcp_clear(struct work_struct *work) ++{ ++ int deferred = atomic_xchg(&mptcp_needed_deferred, 0); ++ int wanted; ++ ++ wanted = atomic_add_return(deferred, &mptcp_wanted); ++ if (wanted > 0) ++ static_key_enable(&mptcp_static_key); ++ else ++ static_key_disable(&mptcp_static_key); ++} ++ ++static DECLARE_WORK(mptcp_work, mptcp_clear); ++#endif ++ ++static void mptcp_enable_static_key_bh(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 0) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted + 1) == wanted) ++ return; ++ } ++ atomic_inc(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++static void mptcp_enable_static_key(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ atomic_inc(&mptcp_wanted); ++ static_key_enable(&mptcp_static_key); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_disable_static_key(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 1) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted - 1) == wanted) ++ return; ++ } ++ atomic_dec(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_dec(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_enable_sock(struct sock *sk) ++{ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ sock_set_flag(sk, SOCK_MPTCP); ++ tcp_sk(sk)->mptcp_ver = sysctl_mptcp_version; ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ ++ mptcp_enable_static_key(); ++ } ++} ++ ++void mptcp_disable_sock(struct sock *sk) ++{ ++ if (sock_flag(sk, SOCK_MPTCP)) { ++ sock_reset_flag(sk, SOCK_MPTCP); ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &ipv4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &ipv6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &ipv6_specific; ++#endif ++ ++ mptcp_disable_static_key(); ++ } ++} ++ ++void mptcp_connect_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_sk(sk); ++ } while (mptcp_reqsk_find_tk(tp->mptcp_loc_token) || ++ mptcp_find_token(tp->mptcp_loc_token)); ++ ++ __mptcp_hash_insert(tp, tp->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVE); ++} ++ ++/** ++ * This function increments the refcount of the mpcb struct. ++ * It is the responsibility of the caller to decrement when releasing ++ * the structure. ++ */ ++struct sock *mptcp_hash_find(const struct net *net, const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ struct sock *meta_sk = NULL; ++ const struct hlist_nulls_node *node; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], ++ tk_table) { ++ meta_sk = (struct sock *)meta_tp; ++ if (token == meta_tp->mptcp_loc_token && ++ net_eq(net, sock_net(meta_sk))) { ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ goto out; ++ if (unlikely(token != meta_tp->mptcp_loc_token || ++ !net_eq(net, sock_net(meta_sk)))) { ++ sock_gen_put(meta_sk); ++ goto begin; ++ } ++ goto found; ++ } ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++out: ++ meta_sk = NULL; ++found: ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return meta_sk; ++} ++ ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) ++{ ++ /* remove from the token hashtable */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&meta_tp->tk_table); ++ meta_tp->inside_tk_table = 0; ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk, *rttsk = NULL, *lastsk = NULL; ++ u32 min_time = 0, last_active = 0; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 elapsed; ++ ++ if (!mptcp_sk_can_send_ack(sk) || tp->pf) ++ continue; ++ ++ elapsed = keepalive_time_elapsed(tp); ++ ++ /* We take the one with the lowest RTT within a reasonable ++ * (meta-RTO)-timeframe ++ */ ++ if (elapsed < inet_csk(meta_sk)->icsk_rto) { ++ if (!min_time || tp->srtt_us < min_time) { ++ min_time = tp->srtt_us; ++ rttsk = sk; ++ } ++ continue; ++ } ++ ++ /* Otherwise, we just take the most recent active */ ++ if (!rttsk && (!last_active || elapsed < last_active)) { ++ last_active = elapsed; ++ lastsk = sk; ++ } ++ } ++ ++ if (rttsk) ++ return rttsk; ++ ++ return lastsk; ++} ++EXPORT_SYMBOL(mptcp_select_ack_sock); ++ ++static void mptcp_sock_def_error_report(struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ if (tp->send_mp_fclose && sk->sk_err == ETIMEDOUT) { ++ /* Called by the keep alive timer (tcp_write_timeout), ++ * when the limit of fastclose retransmissions has been ++ * reached. Send a TCP RST to clear the status of any ++ * stateful firewall (typically conntrack) which are ++ * not aware of mptcp and cannot understand the ++ * fastclose option. ++ */ ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ } ++ } ++ ++ if (!tp->tcp_disconnect && mptcp_in_infinite_mapping_weak(mpcb)) { ++ meta_sk->sk_err = sk->sk_err; ++ meta_sk->sk_err_soft = sk->sk_err_soft; ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_error_report(meta_sk); ++ ++ WARN(meta_sk->sk_state == TCP_CLOSE, ++ "Meta already closed i_rcv %u i_snd %u send_i %u flags %#lx\n", ++ mpcb->infinite_mapping_rcv, mpcb->infinite_mapping_snd, ++ mpcb->send_infinite_mapping, meta_sk->sk_flags); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++ } ++ ++ if (mpcb->pm_ops->subflow_error) ++ mpcb->pm_ops->subflow_error(meta_sk, sk); ++ ++ sk->sk_err = 0; ++ return; ++} ++ ++void mptcp_mpcb_put(struct mptcp_cb *mpcb) ++{ ++ if (atomic_dec_and_test(&mpcb->mpcb_refcnt)) { ++ mptcp_cleanup_path_manager(mpcb); ++ mptcp_cleanup_scheduler(mpcb); ++ kfree(mpcb->master_info); ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ } ++} ++EXPORT_SYMBOL(mptcp_mpcb_put); ++ ++static void mptcp_mpcb_cleanup(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tw *mptw; ++ ++ /* The mpcb is disappearing - we can make the final ++ * update to the rcv_nxt of the time-wait-sock and remove ++ * its reference to the mpcb. ++ */ ++ spin_lock_bh(&mpcb->tw_lock); ++ list_for_each_entry_rcu(mptw, &mpcb->tw_list, list) { ++ list_del_rcu(&mptw->list); ++ mptw->in_list = 0; ++ mptcp_mpcb_put(mpcb); ++ rcu_assign_pointer(mptw->mpcb, NULL); ++ } ++ spin_unlock_bh(&mpcb->tw_lock); ++ ++ mptcp_mpcb_put(mpcb); ++} ++ ++static void mptcp_sock_destruct(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!is_meta_sk(sk)) { ++ BUG_ON(!hlist_unhashed(&tp->mptcp->cb_list)); ++ ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ tp->mptcp = NULL; ++ ++ /* Taken when mpcb pointer was set */ ++ sock_put(mptcp_meta_sk(sk)); ++ mptcp_mpcb_put(tp->mpcb); ++ } else { ++ mptcp_debug("%s destroying meta-sk token %#x\n", __func__, ++ tcp_sk(sk)->mpcb->mptcp_loc_token); ++ ++ mptcp_mpcb_cleanup(tp->mpcb); ++ } ++ ++ WARN_ON(!static_key_false(&mptcp_static_key)); ++ ++ /* Must be called here, because this will decrement the jump-label. */ ++ inet_sock_destruct(sk); ++} ++ ++void mptcp_destroy_sock(struct sock *sk) ++{ ++ if (is_meta_sk(sk)) { ++ struct sock *sk_it, *tmpsk; ++ ++ __skb_queue_purge(&tcp_sk(sk)->mpcb->reinject_queue); ++ ++ /* We have to close all remaining subflows. Normally, they ++ * should all be about to get closed. But, if the kernel is ++ * forcing a closure (e.g., tcp_write_err), the subflows might ++ * not have been closed properly (as we are waiting for the ++ * DATA_ACK of the DATA_FIN). ++ */ ++ mptcp_for_each_sk_safe(tcp_sk(sk)->mpcb, sk_it, tmpsk) { ++ /* Already did call tcp_close - waiting for graceful ++ * closure, or if we are retransmitting fast-close on ++ * the subflow. The reset (or timeout) will kill the ++ * subflow.. ++ */ ++ if (tcp_sk(sk_it)->closing || ++ tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ ++ /* Allow the delayed work first to prevent time-wait state */ ++ if (delayed_work_pending(&tcp_sk(sk_it)->mptcp->work)) ++ continue; ++ ++ mptcp_sub_close(sk_it, 0); ++ } ++ } else { ++ mptcp_del_sock(sk); ++ } ++} ++ ++static void mptcp_set_state(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* Meta is not yet established - wake up the application */ ++ if ((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) && ++ sk->sk_state == TCP_ESTABLISHED) { ++ tcp_set_state(meta_sk, TCP_ESTABLISHED); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ sk_wake_async(meta_sk, SOCK_WAKE_IO, POLL_OUT); ++ } ++ ++ tcp_sk(meta_sk)->lsndtime = tcp_jiffies32; ++ } ++ ++ if (sk->sk_state == TCP_ESTABLISHED) { ++ tcp_sk(sk)->mptcp->establish_increased = 1; ++ tcp_sk(sk)->mpcb->cnt_established++; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) { ++ if (!sock_flag(sk, SOCK_DEAD)) ++ mptcp_sub_close(sk, 0); ++ } ++} ++ ++static int mptcp_set_congestion_control(struct sock *meta_sk, const char *name, ++ bool load, bool reinit, bool cap_net_admin) ++{ ++ int err, result = 0; ++ struct sock *sk_it; ++ ++ result = __tcp_set_congestion_control(meta_sk, name, load, reinit, cap_net_admin); ++ ++ tcp_sk(meta_sk)->mpcb->tcp_ca_explicit_set = true; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk_it) { ++ err = __tcp_set_congestion_control(sk_it, name, load, reinit, cap_net_admin); ++ if (err) ++ result = err; ++ } ++ return result; ++} ++ ++static void mptcp_assign_congestion_control(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct inet_connection_sock *meta_icsk = inet_csk(mptcp_meta_sk(sk)); ++ const struct tcp_congestion_ops *ca = meta_icsk->icsk_ca_ops; ++ ++ /* Congestion control is the same as meta. Thus, it has been ++ * try_module_get'd by tcp_assign_congestion_control. ++ * Congestion control on meta was not explicitly configured by ++ * application, leave default or route based. ++ */ ++ if (icsk->icsk_ca_ops == ca || ++ !tcp_sk(mptcp_meta_sk(sk))->mpcb->tcp_ca_explicit_set) ++ return; ++ ++ /* Use the same congestion control as set on the meta-sk */ ++ if (!try_module_get(ca->owner)) { ++ /* This should never happen. The congestion control is linked ++ * to the meta-socket (through tcp_assign_congestion_control) ++ * who "holds" the refcnt on the module. ++ */ ++ WARN(1, "Could not get the congestion control!"); ++ return; ++ } ++ module_put(icsk->icsk_ca_ops->owner); ++ icsk->icsk_ca_ops = ca; ++ ++ /* Clear out private data before diag gets it and ++ * the ca has not been initialized. ++ */ ++ if (ca->get_info) ++ memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); ++ ++ return; ++} ++ ++siphash_key_t mptcp_secret __read_mostly; ++u32 mptcp_seed = 0; ++ ++void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u32 mptcp_hashed_key[SHA_DIGEST_WORDS]; ++ u8 input[64]; ++ int i; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Initialize input with appropriate padding */ ++ memset(&input[9], 0, sizeof(input) - 10); /* -10, because the last byte ++ * is explicitly set too ++ */ ++ memcpy(input, &key, sizeof(key)); /* Copy key to the msg beginning */ ++ input[8] = 0x80; /* Padding: First bit after message = 1 */ ++ input[63] = 0x40; /* Padding: Length of the message = 64 bits */ ++ ++ sha_init(mptcp_hashed_key); ++ sha_transform(mptcp_hashed_key, input, workspace); ++ ++ for (i = 0; i < 5; i++) ++ mptcp_hashed_key[i] = cpu_to_be32(mptcp_hashed_key[i]); ++ ++ if (token) ++ *token = mptcp_hashed_key[0]; ++ if (idsn) ++ *idsn = *((u64 *)&mptcp_hashed_key[3]); ++} ++ ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u8 input[128]; /* 2 512-bit blocks */ ++ int i; ++ int index; ++ int length; ++ u8 *msg; ++ va_list list; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Generate key xored with ipad */ ++ memset(input, 0x36, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ va_start(list, arg_num); ++ index = 64; ++ for (i = 0; i < arg_num; i++) { ++ length = va_arg(list, int); ++ msg = va_arg(list, u8 *); ++ BUG_ON(index + length > 125); /* Message is too long */ ++ memcpy(&input[index], msg, length); ++ index += length; ++ } ++ va_end(list); ++ ++ input[index] = 0x80; /* Padding: First bit after message = 1 */ ++ memset(&input[index + 1], 0, (126 - index)); ++ ++ /* Padding: Length of the message = 512 + message length (bits) */ ++ input[126] = 0x02; ++ input[127] = ((index - 64) * 8); /* Message length (bits) */ ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = cpu_to_be32(hash_out[i]); ++ ++ /* Prepare second part of hmac */ ++ memset(input, 0x5C, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ memcpy(&input[64], hash_out, 20); ++ input[84] = 0x80; ++ memset(&input[85], 0, 41); ++ ++ /* Padding: Length of the message = 512 + 160 bits */ ++ input[126] = 0x02; ++ input[127] = 0xA0; ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = cpu_to_be32(hash_out[i]); ++} ++EXPORT_SYMBOL(mptcp_hmac_sha1); ++ ++static void mptcp_mpcb_inherit_sockopts(struct sock *meta_sk, struct sock *master_sk) ++{ ++ /* Socket-options handled by sk_clone_lock while creating the meta-sk. ++ * ====== ++ * SO_SNDBUF, SO_SNDBUFFORCE, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVLOWAT, ++ * SO_RCVTIMEO, SO_SNDTIMEO, SO_ATTACH_FILTER, SO_DETACH_FILTER, ++ * TCP_NODELAY, TCP_CORK ++ * ++ * Socket-options handled in this function here ++ * ====== ++ * TCP_DEFER_ACCEPT ++ * SO_KEEPALIVE ++ * ++ * Socket-options on the todo-list ++ * ====== ++ * SO_BINDTODEVICE - should probably prevent creation of new subsocks ++ * across other devices. - what about the api-draft? ++ * SO_DEBUG ++ * SO_REUSEADDR - probably we don't care about this ++ * SO_DONTROUTE, SO_BROADCAST ++ * SO_OOBINLINE ++ * SO_LINGER ++ * SO_TIMESTAMP* - I don't think this is of concern for a SOCK_STREAM ++ * SO_PASSSEC - I don't think this is of concern for a SOCK_STREAM ++ * SO_RXQ_OVFL ++ * TCP_COOKIE_TRANSACTIONS ++ * TCP_MAXSEG ++ * TCP_THIN_* - Handled by sk_clone_lock, but we need to support this ++ * in mptcp_meta_retransmit_timer. AND we need to check ++ * what is about the subsockets. ++ * TCP_LINGER2 ++ * TCP_WINDOW_CLAMP ++ * TCP_USER_TIMEOUT ++ * TCP_MD5SIG ++ * ++ * Socket-options of no concern for the meta-socket (but for the subsocket) ++ * ====== ++ * SO_PRIORITY ++ * SO_MARK ++ * TCP_CONGESTION ++ * TCP_SYNCNT ++ * TCP_QUICKACK ++ */ ++ ++ /* DEFER_ACCEPT should not be set on the meta, as we want to accept new subflows directly */ ++ inet_csk(meta_sk)->icsk_accept_queue.rskq_defer_accept = 0; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(meta_sk, SOCK_KEEPOPEN)) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ keepalive_time_when(tcp_sk(meta_sk))); ++ sock_reset_flag(master_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(master_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(master_sk)->recverr = 0; ++} ++ ++static void mptcp_sub_inherit_sockopts(const struct sock *meta_sk, struct sock *sub_sk) ++{ ++ /* IP_TOS also goes to the subflow. */ ++ if (inet_sk(sub_sk)->tos != inet_sk(meta_sk)->tos) { ++ inet_sk(sub_sk)->tos = inet_sk(meta_sk)->tos; ++ sub_sk->sk_priority = meta_sk->sk_priority; ++ sk_dst_reset(sub_sk); ++ } ++ ++ /* Inherit SO_REUSEADDR */ ++ sub_sk->sk_reuse = meta_sk->sk_reuse; ++ ++ /* Inherit SO_MARK: can be used for routing or filtering */ ++ sub_sk->sk_mark = meta_sk->sk_mark; ++ ++ /* Inherit snd/rcv-buffer locks */ ++ sub_sk->sk_userlocks = meta_sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; ++ ++ /* Nagle/Cork is forced off on the subflows. It is handled at the meta-layer */ ++ tcp_sk(sub_sk)->nonagle = TCP_NAGLE_OFF|TCP_NAGLE_PUSH; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(sub_sk, SOCK_KEEPOPEN)) { ++ sock_reset_flag(sub_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(sub_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(sub_sk)->recverr = 0; ++} ++ ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) ++{ ++ /* In case of success (in mptcp_backlog_rcv) and error (in kfree_skb) of ++ * sk_add_backlog, we will decrement the sk refcount. ++ */ ++ sock_hold(sk); ++ skb->sk = sk; ++ skb->destructor = sock_efree; ++} ++ ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ /* skb-sk may be NULL if we receive a packet immediatly after the ++ * SYN/ACK + MP_CAPABLE. ++ */ ++ struct sock *sk = skb->sk ? skb->sk : meta_sk; ++ int ret = 0; ++ ++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) { ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ /* Decrement sk refcnt when calling the skb destructor. ++ * Refcnt is incremented and skb destructor is set in tcp_v{4,6}_rcv via ++ * mptcp_prepare_for_backlog() here above. ++ */ ++ skb_orphan(skb); ++ ++ if (sk->sk_family == AF_INET) ++ ret = tcp_v4_do_rcv(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ ret = tcp_v6_do_rcv(sk, skb); ++#endif ++ ++ sock_put(sk); ++ return ret; ++} ++ ++struct lock_class_key meta_key; ++char *meta_key_name = "sk_lock-AF_INET-MPTCP"; ++struct lock_class_key meta_slock_key; ++char *meta_slock_key_name = "slock-AF_INET-MPTCP"; ++ ++static const struct tcp_sock_ops mptcp_meta_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = mptcp_send_fin, ++ .write_xmit = mptcp_write_xmit, ++ .send_active_reset = mptcp_send_active_reset, ++ .write_wakeup = mptcp_write_wakeup, ++ .retransmit_timer = mptcp_meta_retransmit_timer, ++ .time_wait = mptcp_time_wait, ++ .cleanup_rbuf = mptcp_cleanup_rbuf, ++ .set_cong_ctrl = mptcp_set_congestion_control, ++}; ++ ++static const struct tcp_sock_ops mptcp_sub_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = mptcp_sub_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ ++static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct mptcp_cb *mpcb; ++ struct sock *master_sk; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ struct tcp_sock *master_tp, *meta_tp = tcp_sk(meta_sk); ++ u64 snd_idsn, rcv_idsn; ++ ++ dst_release(meta_sk->sk_rx_dst); ++ meta_sk->sk_rx_dst = NULL; ++ /* This flag is set to announce sock_lock_init to ++ * reclassify the lock-class of the master socket. ++ */ ++ meta_tp->is_master_sk = 1; ++ master_sk = sk_clone_lock(meta_sk, GFP_ATOMIC | __GFP_ZERO); ++ meta_tp->is_master_sk = 0; ++ if (!master_sk) ++ goto err_alloc_master; ++ ++ master_tp = tcp_sk(master_sk); ++ master_tp->inside_tk_table = 0; ++ ++ mpcb = kmem_cache_zalloc(mptcp_cb_cache, GFP_ATOMIC); ++ if (!mpcb) ++ goto err_alloc_mpcb; ++ ++ /* Store the mptcp version agreed on initial handshake */ ++ mpcb->mptcp_ver = mptcp_ver; ++ ++ /* Store the keys and generate the peer's token */ ++ mpcb->mptcp_loc_key = meta_tp->mptcp_loc_key; ++ mpcb->mptcp_loc_token = meta_tp->mptcp_loc_token; ++ ++ /* Generate Initial data-sequence-numbers */ ++ mptcp_key_sha1(mpcb->mptcp_loc_key, NULL, &snd_idsn); ++ snd_idsn = ntohll(snd_idsn) + 1; ++ mpcb->snd_high_order[0] = snd_idsn >> 32; ++ mpcb->snd_high_order[1] = mpcb->snd_high_order[0] - 1; ++ ++ mpcb->mptcp_rem_key = remote_key; ++ mptcp_key_sha1(mpcb->mptcp_rem_key, &mpcb->mptcp_rem_token, &rcv_idsn); ++ rcv_idsn = ntohll(rcv_idsn) + 1; ++ mpcb->rcv_high_order[0] = rcv_idsn >> 32; ++ mpcb->rcv_high_order[1] = mpcb->rcv_high_order[0] + 1; ++ ++ mpcb->meta_sk = meta_sk; ++ mpcb->master_sk = master_sk; ++ ++ skb_queue_head_init(&mpcb->reinject_queue); ++ mutex_init(&mpcb->mpcb_mutex); ++ ++ /* Init time-wait stuff */ ++ INIT_LIST_HEAD(&mpcb->tw_list); ++ spin_lock_init(&mpcb->tw_lock); ++ ++ INIT_HLIST_HEAD(&mpcb->callback_list); ++ ++ mpcb->orig_sk_rcvbuf = meta_sk->sk_rcvbuf; ++ mpcb->orig_sk_sndbuf = meta_sk->sk_sndbuf; ++ mpcb->orig_window_clamp = meta_tp->window_clamp; ++ ++ /* The meta is directly linked - set refcnt to 1 */ ++ atomic_set(&mpcb->mpcb_refcnt, 1); ++ ++ if (!meta_tp->inside_tk_table) { ++ /* Adding the meta_tp in the token hashtable - coming from server-side */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* With lockless listeners, we might process two ACKs at the ++ * same time. With TCP, inet_csk_complete_hashdance takes care ++ * of this. But, for MPTCP this would be too late if we add ++ * this MPTCP-socket in the token table (new subflows might ++ * come in and match on this socket here. ++ * So, we need to check if someone else already added the token ++ * and revert in that case. The other guy won the race... ++ */ ++ if (mptcp_find_token(mpcb->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ goto err_insert_token; ++ } ++ __mptcp_hash_insert(meta_tp, mpcb->mptcp_loc_token); ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_icsk->icsk_af_ops == &mptcp_v6_mapped) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ struct ipv6_txoptions *opt; ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ /* The following heavily inspired from tcp_v6_syn_recv_sock() */ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(master_sk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } ++ inet_csk(master_sk)->icsk_ext_hdr_len = 0; ++ if (opt) ++ inet_csk(master_sk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; ++ } ++#endif ++ ++ meta_tp->mptcp = NULL; ++ ++ meta_tp->write_seq = (u32)snd_idsn; ++ meta_tp->snd_sml = meta_tp->write_seq; ++ meta_tp->snd_una = meta_tp->write_seq; ++ meta_tp->snd_nxt = meta_tp->write_seq; ++ meta_tp->pushed_seq = meta_tp->write_seq; ++ meta_tp->snd_up = meta_tp->write_seq; ++ ++ meta_tp->copied_seq = (u32)rcv_idsn; ++ meta_tp->rcv_nxt = (u32)rcv_idsn; ++ meta_tp->rcv_wup = (u32)rcv_idsn; ++ ++ meta_tp->snd_wl1 = meta_tp->rcv_nxt - 1; ++ meta_tp->snd_wnd = window; ++ meta_tp->retrans_stamp = 0; /* Set in tcp_connect() */ ++ ++ meta_tp->packets_out = 0; ++ meta_icsk->icsk_probes_out = 0; ++ ++ rcu_assign_pointer(inet_sk(meta_sk)->inet_opt, NULL); ++ ++ /* Set mptcp-pointers */ ++ master_tp->mpcb = mpcb; ++ master_tp->meta_sk = meta_sk; ++ meta_tp->mpcb = mpcb; ++ meta_tp->meta_sk = meta_sk; ++ ++ /* Initialize the queues */ ++ master_tp->out_of_order_queue = RB_ROOT; ++ INIT_LIST_HEAD(&master_tp->tsq_node); ++ ++ master_sk->sk_tsq_flags = 0; ++ /* icsk_bind_hash inherited from the meta, but it will be properly set in ++ * mptcp_create_master_sk. Same operation is done in inet_csk_clone_lock. ++ */ ++ inet_csk(master_sk)->icsk_bind_hash = NULL; ++ ++ /* Init the accept_queue structure, we support a queue of 32 pending ++ * connections, it does not need to be huge, since we only store here ++ * pending subflow creations. ++ */ ++ reqsk_queue_alloc(&meta_icsk->icsk_accept_queue); ++ meta_sk->sk_max_ack_backlog = 32; ++ meta_sk->sk_ack_backlog = 0; ++ ++ if (!sock_flag(meta_sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(meta_sk, SOCK_MPTCP); ++ } ++ ++ /* Redefine function-pointers as the meta-sk is now fully ready */ ++ meta_tp->mpc = 1; ++ meta_tp->ops = &mptcp_meta_specific; ++ ++ meta_sk->sk_backlog_rcv = mptcp_backlog_rcv; ++ meta_sk->sk_destruct = mptcp_sock_destruct; ++ ++ /* Meta-level retransmit timer */ ++ meta_icsk->icsk_rto *= 2; /* Double of initial - rto */ ++ ++ tcp_init_xmit_timers(master_sk); ++ /* Has been set for sending out the SYN */ ++ inet_csk_clear_xmit_timer(meta_sk, ICSK_TIME_RETRANS); ++ ++ mptcp_mpcb_inherit_sockopts(meta_sk, master_sk); ++ ++ mptcp_init_path_manager(mpcb); ++ mptcp_init_scheduler(mpcb); ++ ++ if (!try_module_get(inet_csk(master_sk)->icsk_ca_ops->owner)) ++ tcp_assign_congestion_control(master_sk); ++ ++ master_tp->saved_syn = NULL; ++ ++ mptcp_debug("%s: created mpcb with token %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ return 0; ++ ++err_insert_token: ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ ++err_alloc_mpcb: ++ inet_sk(master_sk)->inet_opt = NULL; ++ master_sk->sk_state = TCP_CLOSE; ++ sock_orphan(master_sk); ++ bh_unlock_sock(master_sk); ++ sk_free(master_sk); ++ ++err_alloc_master: ++ return -ENOBUFS; ++} ++ ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tp->mptcp = kmem_cache_zalloc(mptcp_sock_cache, flags); ++ if (!tp->mptcp) ++ return -ENOMEM; ++ ++ tp->mptcp->path_index = mptcp_set_new_pathindex(mpcb); ++ /* No more space for more subflows? */ ++ if (!tp->mptcp->path_index) { ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ return -EPERM; ++ } ++ ++ INIT_HLIST_NODE(&tp->mptcp->cb_list); ++ ++ tp->mptcp->tp = tp; ++ tp->mpcb = mpcb; ++ tp->meta_sk = meta_sk; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(sk, SOCK_MPTCP); ++ } ++ ++ tp->mpc = 1; ++ tp->ops = &mptcp_sub_specific; ++ ++ tp->mptcp->loc_id = loc_id; ++ tp->mptcp->rem_id = rem_id; ++ if (mpcb->sched_ops->init) ++ mpcb->sched_ops->init(sk); ++ ++ /* The corresponding sock_put is in mptcp_sock_destruct(). It cannot be ++ * included in mptcp_del_sock(), because the mpcb must remain alive ++ * until the last subsocket is completely destroyed. ++ */ ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ ++ tp->mptcp->next = mpcb->connection_list; ++ mpcb->connection_list = tp; ++ tp->mptcp->attached = 1; ++ ++ mpcb->cnt_subflows++; ++ ++ mptcp_sub_inherit_sockopts(meta_sk, sk); ++ INIT_DELAYED_WORK(&tp->mptcp->work, mptcp_sub_close_wq); ++ ++ /* Properly inherit CC from the meta-socket */ ++ mptcp_assign_congestion_control(sk); ++ ++ /* As we successfully allocated the mptcp_tcp_sock, we have to ++ * change the function-pointers here (for sk_destruct to work correctly) ++ */ ++ sk->sk_error_report = mptcp_sock_def_error_report; ++ sk->sk_data_ready = mptcp_data_ready; ++ sk->sk_write_space = mptcp_write_space; ++ sk->sk_state_change = mptcp_set_state; ++ sk->sk_destruct = mptcp_sock_destruct; ++ ++ if (sk->sk_family == AF_INET) ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI4:%d dst_addr:%pI4:%d, cnt_subflows now %d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, ++ &((struct inet_sock *)tp)->inet_saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &((struct inet_sock *)tp)->inet_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport), ++ mpcb->cnt_subflows); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI6:%d dst_addr:%pI6:%d, cnt_subflows now %d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &inet6_sk(sk)->saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &sk->sk_v6_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport), ++ mpcb->cnt_subflows); ++#endif ++ ++ return 0; ++} ++ ++void mptcp_del_sock(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *tp_prev; ++ struct mptcp_cb *mpcb; ++ ++ if (!tp->mptcp || !tp->mptcp->attached) ++ return; ++ ++ mpcb = tp->mpcb; ++ tp_prev = mpcb->connection_list; ++ ++ if (mpcb->sched_ops->release) ++ mpcb->sched_ops->release(sk); ++ ++ if (mpcb->pm_ops->delete_subflow) ++ mpcb->pm_ops->delete_subflow(sk); ++ ++ mptcp_debug("%s: Removing subsock tok %#x pi:%d state %d is_meta? %d\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ sk->sk_state, is_meta_sk(sk)); ++ ++ if (tp_prev == tp) { ++ mpcb->connection_list = tp->mptcp->next; ++ } else { ++ for (; tp_prev && tp_prev->mptcp->next; tp_prev = tp_prev->mptcp->next) { ++ if (tp_prev->mptcp->next == tp) { ++ tp_prev->mptcp->next = tp->mptcp->next; ++ break; ++ } ++ } ++ } ++ mpcb->cnt_subflows--; ++ if (tp->mptcp->establish_increased) ++ mpcb->cnt_established--; ++ ++ tp->mptcp->next = NULL; ++ tp->mptcp->attached = 0; ++ mpcb->path_index_bits &= ~(1 << tp->mptcp->path_index); ++ ++ if (!skb_queue_empty(&sk->sk_write_queue)) ++ mptcp_reinject_data(sk, 0); ++ ++ if (is_master_tp(tp)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (meta_tp->record_master_info && ++ !sock_flag(meta_sk, SOCK_DEAD)) { ++ mpcb->master_info = kmalloc(sizeof(*mpcb->master_info), ++ GFP_ATOMIC); ++ ++ if (mpcb->master_info) ++ tcp_get_info(sk, mpcb->master_info, true); ++ } ++ ++ mpcb->master_sk = NULL; ++ } else if (tp->mptcp->pre_established) { ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++} ++ ++/* Updates the MPTCP-session based on path-manager information (e.g., addresses, ++ * low-prio flows,...). ++ */ ++void mptcp_update_metasocket(const struct sock *meta_sk) ++{ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->new_session) ++ tcp_sk(meta_sk)->mpcb->pm_ops->new_session(meta_sk); ++} ++ ++/* Clean up the receive buffer for full frames taken by the user, ++ * then send an ACK if necessary. COPIED is the number of bytes ++ * tcp_recvmsg has given to the user so far, it speeds up the ++ * calculation of whether or not we must ACK for the sake of ++ * a window update. ++ * (inspired from tcp_cleanup_rbuf()) ++ */ ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk; ++ bool recheck_rcv_window = false; ++ __u32 rcv_window_now = 0; ++ ++ if (copied > 0 && !(meta_sk->sk_shutdown & RCV_SHUTDOWN)) { ++ rcv_window_now = tcp_receive_window(meta_tp); ++ ++ /* Optimize, __mptcp_select_window() is not cheap. */ ++ if (2 * rcv_window_now <= meta_tp->window_clamp) ++ recheck_rcv_window = true; ++ } ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (!mptcp_sk_can_send_ack(sk)) ++ continue; ++ ++ if (!inet_csk_ack_scheduled(sk)) ++ goto second_part; ++ /* Delayed ACKs frequently hit locked sockets during bulk ++ * receive. ++ */ ++ if (icsk->icsk_ack.blocked || ++ /* Once-per-two-segments ACK was not sent by tcp_input.c */ ++ tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || ++ /* If this read emptied read buffer, we send ACK, if ++ * connection is not bidirectional, user drained ++ * receive buffer and there was a small segment ++ * in queue. ++ */ ++ (copied > 0 && ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && ++ !icsk->icsk_ack.pingpong)) && ++ !atomic_read(&meta_sk->sk_rmem_alloc))) { ++ tcp_send_ack(sk); ++ continue; ++ } ++ ++second_part: ++ /* This here is the second part of tcp_cleanup_rbuf */ ++ if (recheck_rcv_window) { ++ __u32 new_window = tp->ops->__select_window(sk); ++ ++ /* Send ACK now, if this read freed lots of space ++ * in our buffer. Certainly, new_window is new window. ++ * We can advertise it now, if it is not less than ++ * current one. ++ * "Lots" means "at least twice" here. ++ */ ++ if (new_window && new_window >= 2 * rcv_window_now) ++ tcp_send_ack(sk); ++ } ++ } ++} ++ ++static int mptcp_sub_send_fin(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *skb = tcp_write_queue_tail(sk); ++ int mss_now; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = tcp_current_mss(sk); ++ ++ if (tcp_send_head(sk) != NULL) { ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ tp->write_seq++; ++ } else { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (!skb) ++ return 1; ++ ++ /* Reserve space for headers and prepare control bits. */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ ++ tcp_init_nondata_skb(skb, tp->write_seq, ++ TCPHDR_ACK | TCPHDR_FIN); ++ tcp_queue_skb(sk, skb); ++ } ++ __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF); ++ ++ return 0; ++} ++ ++static void mptcp_sub_close_doit(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sock_flag(sk, SOCK_DEAD)) ++ return; ++ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) { ++ tp->closing = 1; ++ tcp_close(sk, 0); ++ } else if (tcp_close_state(sk)) { ++ sk->sk_shutdown |= SEND_SHUTDOWN; ++ tcp_send_fin(sk); ++ } ++} ++ ++void mptcp_sub_close_wq(struct work_struct *work) ++{ ++ struct tcp_sock *tp = container_of(work, struct mptcp_tcp_sock, work.work)->tp; ++ struct sock *sk = (struct sock *)tp; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_sub_close_doit(sk); ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(sk); ++} ++ ++void mptcp_sub_close(struct sock *sk, unsigned long delay) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct delayed_work *work = &tcp_sk(sk)->mptcp->work; ++ ++ /* We are already closing - e.g., call from sock_def_error_report upon ++ * tcp_disconnect in tcp_close. ++ */ ++ if (tp->closing) ++ return; ++ ++ /* Work already scheduled ? */ ++ if (work_pending(&work->work)) { ++ /* Work present - who will be first ? */ ++ if (jiffies + delay > work->timer.expires) ++ return; ++ ++ /* Try canceling - if it fails, work will be executed soon */ ++ if (!cancel_delayed_work(work)) ++ return; ++ sock_put(sk); ++ mptcp_mpcb_put(tp->mpcb); ++ } ++ ++ if (!delay) { ++ unsigned char old_state = sk->sk_state; ++ ++ /* We directly send the FIN. Because it may take so a long time, ++ * untile the work-queue will get scheduled... ++ * ++ * If mptcp_sub_send_fin returns 1, it failed and thus we reset ++ * the old state so that tcp_close will finally send the fin ++ * in user-context. ++ */ ++ if (!sk->sk_err && old_state != TCP_CLOSE && ++ tcp_close_state(sk) && mptcp_sub_send_fin(sk)) { ++ if (old_state == TCP_ESTABLISHED) ++ TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ sk->sk_state = old_state; ++ } ++ } ++ ++ sock_hold(sk); ++ atomic_inc(&tp->mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, work, delay); ++} ++ ++void mptcp_sub_force_close(struct sock *sk) ++{ ++ /* The below tcp_done may have freed the socket, if he is already dead. ++ * Thus, we are not allowed to access it afterwards. That's why ++ * we have to store the dead-state in this local variable. ++ */ ++ int sock_is_dead = sock_flag(sk, SOCK_DEAD); ++ ++ tcp_sk(sk)->mp_killed = 1; ++ ++ if (sk->sk_state != TCP_CLOSE) ++ tcp_done(sk); ++ ++ if (!sock_is_dead) ++ mptcp_sub_close(sk, 0); ++} ++EXPORT_SYMBOL(mptcp_sub_force_close); ++ ++/* Update the mpcb send window, based on the contributions ++ * of each subflow ++ */ ++void mptcp_update_sndbuf(const struct tcp_sock *tp) ++{ ++ struct sock *meta_sk = tp->meta_sk, *sk; ++ int new_sndbuf = 0, old_sndbuf = meta_sk->sk_sndbuf; ++ ++ mptcp_for_each_sk(tp->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ new_sndbuf += sk->sk_sndbuf; ++ ++ if (new_sndbuf > sysctl_tcp_wmem[2] || new_sndbuf < 0) { ++ new_sndbuf = sysctl_tcp_wmem[2]; ++ break; ++ } ++ } ++ meta_sk->sk_sndbuf = max(min(new_sndbuf, sysctl_tcp_wmem[2]), meta_sk->sk_sndbuf); ++ ++ /* The subflow's call to sk_write_space in tcp_new_space ends up in ++ * mptcp_write_space. ++ * It has nothing to do with waking up the application. ++ * So, we do it here. ++ */ ++ if (old_sndbuf != meta_sk->sk_sndbuf) ++ meta_sk->sk_write_space(meta_sk); ++} ++ ++/* Similar to: tcp_close */ ++void mptcp_close(struct sock *meta_sk, long timeout) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk_it, *tmpsk; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int data_was_unread = 0; ++ int state; ++ ++ mptcp_debug("%s: Close of meta_sk with tok %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ WARN_ON(atomic_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (meta_tp->inside_tk_table) ++ /* Detach the mpcb from the token hashtable */ ++ mptcp_hash_remove_bh(meta_tp); ++ ++ meta_sk->sk_shutdown = SHUTDOWN_MASK; ++ /* We need to flush the recv. buffs. We do this only on the ++ * descriptor close, not protocol-sourced closes, because the ++ * reader process may not have drained the data yet! ++ */ ++ while ((skb = __skb_dequeue(&meta_sk->sk_receive_queue)) != NULL) { ++ u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ len--; ++ data_was_unread += len; ++ __kfree_skb(skb); ++ } ++ ++ sk_mem_reclaim(meta_sk); ++ ++ /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ ++ if (meta_sk->sk_state == TCP_CLOSE) { ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ if (tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ mptcp_sub_close(sk_it, 0); ++ } ++ goto adjudge_to_death; ++ } ++ ++ if (data_was_unread) { ++ /* Unread data was tossed, zap the connection. */ ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONCLOSE); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ tcp_sk(meta_sk)->ops->send_active_reset(meta_sk, ++ meta_sk->sk_allocation); ++ } else if (sock_flag(meta_sk, SOCK_LINGER) && !meta_sk->sk_lingertime) { ++ /* Check zero linger _after_ checking for unread data. */ ++ meta_sk->sk_prot->disconnect(meta_sk, 0); ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ } else if (tcp_close_state(meta_sk)) { ++ mptcp_send_fin(meta_sk); ++ } else if (meta_tp->snd_una == meta_tp->write_seq) { ++ /* The DATA_FIN has been sent and acknowledged ++ * (e.g., by sk_shutdown). Close all the other subflows ++ */ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ unsigned long delay = 0; ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer. - thus we add a delay ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ ++ sk_stream_wait_close(meta_sk, timeout); ++ ++adjudge_to_death: ++ state = meta_sk->sk_state; ++ sock_hold(meta_sk); ++ sock_orphan(meta_sk); ++ ++ /* socket will be freed after mptcp_close - we have to prevent ++ * access from the subflows. ++ */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ /* Similar to sock_orphan, but we don't set it DEAD, because ++ * the callbacks are still set and must be called. ++ */ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_set_socket(sk_it, NULL); ++ sk_it->sk_wq = NULL; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ ++ /* It is the last release_sock in its life. It will remove backlog. */ ++ release_sock(meta_sk); ++ ++ /* Now socket is owned by kernel and we acquire BH lock ++ * to finish close. No need to check for user refs. ++ */ ++ local_bh_disable(); ++ bh_lock_sock(meta_sk); ++ WARN_ON(sock_owned_by_user(meta_sk)); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ /* Have we already been destroyed by a softirq or backlog? */ ++ if (state != TCP_CLOSE && meta_sk->sk_state == TCP_CLOSE) ++ goto out; ++ ++ /* This is a (useful) BSD violating of the RFC. There is a ++ * problem with TCP as specified in that the other end could ++ * keep a socket open forever with no application left this end. ++ * We use a 3 minute timeout (about the same as BSD) then kill ++ * our end. If they send after that then tough - BUT: long enough ++ * that we won't make the old 4*rto = almost no time - whoops ++ * reset mistake. ++ * ++ * Nope, it was not mistake. It is really desired behaviour ++ * f.e. on http servers, when such sockets are useless, but ++ * consume significant resources. Let's do it with special ++ * linger2 option. --ANK ++ */ ++ ++ if (meta_sk->sk_state == TCP_FIN_WAIT2) { ++ if (meta_tp->linger2 < 0) { ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONLINGER); ++ } else { ++ const int tmo = tcp_fin_time(meta_sk); ++ ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ tmo - TCP_TIMEWAIT_LEN); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, ++ tmo); ++ goto out; ++ } ++ } ++ } ++ if (meta_sk->sk_state != TCP_CLOSE) { ++ sk_mem_reclaim(meta_sk); ++ if (tcp_check_oom(meta_sk, 0)) { ++ if (net_ratelimit()) ++ pr_info("MPTCP: out of memory: force closing socket\n"); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONMEMORY); ++ } ++ } ++ ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ inet_csk_destroy_sock(meta_sk); ++ /* Otherwise, socket is reprieved until protocol close. */ ++ ++out: ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); /* Taken by sock_hold */ ++} ++ ++void mptcp_disconnect(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk, *tmpsk; ++ ++ __skb_queue_purge(&meta_tp->mpcb->reinject_queue); ++ ++ if (meta_tp->inside_tk_table) ++ mptcp_hash_remove_bh(meta_tp); ++ ++ local_bh_disable(); ++ mptcp_for_each_sk_safe(meta_tp->mpcb, subsk, tmpsk) { ++ if (spin_is_locked(&subsk->sk_lock.slock)) ++ bh_unlock_sock(subsk); ++ ++ tcp_sk(subsk)->tcp_disconnect = 1; ++ ++ meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); ++ ++ sock_orphan(subsk); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ inet_csk_destroy_sock(subsk); ++ } ++ local_bh_enable(); ++ ++ mptcp_mpcb_cleanup(meta_tp->mpcb); ++ meta_tp->meta_sk = NULL; ++ ++ meta_tp->send_mp_fclose = 0; ++ meta_tp->mpc = 0; ++ meta_tp->ops = &tcp_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6) ++ meta_sk->sk_backlog_rcv = tcp_v6_do_rcv; ++ else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#endif ++ meta_sk->sk_destruct = inet_sock_destruct; ++} ++ ++ ++/* Returns 1 if we should enable MPTCP for that socket. */ ++int mptcp_doit(struct sock *sk) ++{ ++ /* Don't do mptcp over loopback */ ++ if (sk->sk_family == AF_INET && ++ (ipv4_is_loopback(inet_sk(sk)->inet_daddr) || ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr))) ++ return 0; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (sk->sk_family == AF_INET6 && ++ (ipv6_addr_loopback(&sk->sk_v6_daddr) || ++ ipv6_addr_loopback(&inet6_sk(sk)->saddr))) ++ return 0; ++#endif ++ if (mptcp_v6_is_v4_mapped(sk) && ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr)) ++ return 0; ++ ++#ifdef CONFIG_TCP_MD5SIG ++ /* If TCP_MD5SIG is enabled, do not do MPTCP - there is no Option-Space */ ++ if (tcp_sk(sk)->af_specific->md5_lookup(sk, sk)) ++ return 0; ++#endif ++ ++ return 1; ++} ++ ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct tcp_sock *master_tp; ++ struct sock *master_sk; ++ ++ if (mptcp_alloc_mpcb(meta_sk, remote_key, mptcp_ver, window)) ++ goto err_alloc_mpcb; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ master_tp = tcp_sk(master_sk); ++ ++ if (mptcp_add_sock(meta_sk, master_sk, 0, 0, GFP_ATOMIC)) ++ goto err_add_sock; ++ ++ if (__inet_inherit_port(meta_sk, master_sk) < 0) ++ goto err_add_sock; ++ ++ meta_sk->sk_prot->unhash(meta_sk); ++ inet_ehash_nolisten(master_sk, NULL); ++ ++ master_tp->mptcp->init_rcv_wnd = master_tp->rcv_wnd; ++ ++ return 0; ++ ++err_add_sock: ++ inet_csk_prepare_forced_close(master_sk); ++ tcp_done(master_sk); ++ ++err_alloc_mpcb: ++ return -ENOBUFS; ++} ++ ++static int __mptcp_check_req_master(struct sock *child, ++ struct request_sock *req) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct sock *meta_sk = child; ++ struct mptcp_cb *mpcb; ++ struct mptcp_request_sock *mtreq; ++ ++ /* Never contained an MP_CAPABLE */ ++ if (!inet_rsk(req)->mptcp_rqsk) ++ return 1; ++ ++ if (!inet_rsk(req)->saw_mpc) { ++ /* Fallback to regular TCP, because we saw one SYN without ++ * MP_CAPABLE. In tcp_check_req we continue the regular path. ++ * But, the socket has been added to the reqsk_tk_htb, so we ++ * must still remove it. ++ */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); ++ mptcp_reqsk_remove_tk(req); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEACK); ++ ++ /* Just set this values to pass them to mptcp_alloc_mpcb */ ++ mtreq = mptcp_rsk(req); ++ child_tp->mptcp_loc_key = mtreq->mptcp_loc_key; ++ child_tp->mptcp_loc_token = mtreq->mptcp_loc_token; ++ ++ if (mptcp_create_master_sk(meta_sk, mtreq->mptcp_rem_key, ++ mtreq->mptcp_ver, child_tp->snd_wnd)) { ++ inet_csk_prepare_forced_close(meta_sk); ++ tcp_done(meta_sk); ++ ++ return -ENOBUFS; ++ } ++ ++ child = tcp_sk(child)->mpcb->master_sk; ++ child_tp = tcp_sk(child); ++ mpcb = child_tp->mpcb; ++ ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ ++ mpcb->dss_csum = mtreq->dss_csum; ++ mpcb->server_side = 1; ++ ++ /* Needs to be done here additionally, because when accepting a ++ * new connection we pass by __reqsk_free and not reqsk_free. ++ */ ++ mptcp_reqsk_remove_tk(req); ++ ++ /* Hold when creating the meta-sk in tcp_vX_syn_recv_sock. */ ++ sock_put(meta_sk); ++ ++ return 0; ++} ++ ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req) ++{ ++ struct sock *meta_sk = child, *master_sk; ++ struct sk_buff *skb; ++ u32 new_mapping; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ ++ /* We need to rewind copied_seq as it is set to IDSN + 1 and as we have ++ * pre-MPTCP data in the receive queue. ++ */ ++ tcp_sk(meta_sk)->copied_seq -= tcp_sk(master_sk)->rcv_nxt - ++ tcp_rsk(req)->rcv_isn - 1; ++ ++ /* Map subflow sequence number to data sequence numbers. We need to map ++ * these data to [IDSN - len - 1, IDSN[. ++ */ ++ new_mapping = tcp_sk(meta_sk)->copied_seq - tcp_rsk(req)->rcv_isn - 1; ++ ++ /* There should be only one skb: the SYN + data. */ ++ skb_queue_walk(&meta_sk->sk_receive_queue, skb) { ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* With fastopen we change the semantics of the relative subflow ++ * sequence numbers to deal with middleboxes that could add/remove ++ * multiple bytes in the SYN. We chose to start counting at rcv_nxt - 1 ++ * instead of the regular TCP ISN. ++ */ ++ tcp_sk(master_sk)->mptcp->rcv_isn = tcp_sk(master_sk)->rcv_nxt - 1; ++ ++ /* We need to update copied_seq of the master_sk to account for the ++ * already moved data to the meta receive queue. ++ */ ++ tcp_sk(master_sk)->copied_seq = tcp_sk(master_sk)->rcv_nxt; ++ ++ /* Handled by the master_sk */ ++ tcp_sk(meta_sk)->fastopen_rsk = NULL; ++ ++ return 0; ++} ++ ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop, u32 tsoff) ++{ ++ struct sock *meta_sk = child; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ child = tcp_sk(child)->mpcb->master_sk; ++ ++ sock_rps_save_rxhash(child, skb); ++ ++ /* drop indicates that we come from tcp_check_req and thus need to ++ * handle the request-socket fully. ++ */ ++ if (drop) { ++ tcp_synack_rtt_meas(child, req); ++ ++ inet_csk_reqsk_queue_drop(sk, req); ++ reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ return -1; ++ } ++ } else { ++ /* Thus, we come from syn-cookies */ ++ refcount_set(&req->rsk_refcnt, 1); ++ tcp_sk(meta_sk)->tsoffset = tsoff; ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ reqsk_put(req); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ u8 hash_mac_check[20]; ++ ++ child_tp->out_of_order_queue = RB_ROOT; ++ ++ if (!mopt->join_ack) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKFAIL); ++ goto teardown; ++ } ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce); ++ ++ if (memcmp(hash_mac_check, (char *)&mopt->mptcp_recv_mac, 20)) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKMAC); ++ goto teardown; ++ } ++ ++ /* Point it to the same struct socket and wq as the meta_sk */ ++ sk_set_socket(child, meta_sk->sk_socket); ++ child->sk_wq = meta_sk->sk_wq; ++ ++ if (mptcp_add_sock(meta_sk, child, mtreq->loc_id, mtreq->rem_id, GFP_ATOMIC)) { ++ /* Has been inherited, but now child_tp->mptcp is NULL */ ++ child_tp->mpc = 0; ++ child_tp->ops = &tcp_specific; ++ ++ /* TODO when we support acking the third ack for new subflows, ++ * we should silently discard this third ack, by returning NULL. ++ * ++ * Maybe, at the retransmission we will have enough memory to ++ * fully add the socket to the meta-sk. ++ */ ++ goto teardown; ++ } ++ ++ /* The child is a clone of the meta socket, we must now reset ++ * some of the fields ++ */ ++ child_tp->mptcp->rcv_low_prio = mtreq->rcv_low_prio; ++ ++ /* We should allow proper increase of the snd/rcv-buffers. Thus, we ++ * use the original values instead of the bloated up ones from the ++ * clone. ++ */ ++ child->sk_sndbuf = mpcb->orig_sk_sndbuf; ++ child->sk_rcvbuf = mpcb->orig_sk_rcvbuf; ++ ++ child_tp->mptcp->slave_sk = 1; ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ child_tp->mptcp->init_rcv_wnd = req->rsk_rcv_wnd; ++ ++ child->sk_tsq_flags = 0; ++ ++ sock_rps_save_rxhash(child, skb); ++ tcp_synack_rtt_meas(child, req); ++ ++ /* Subflows do not use the accept queue, as they ++ * are attached immediately to the mpcb. ++ */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ ++ /* The refcnt is initialized to 2, because regular TCP will put him ++ * in the socket's listener queue. However, we do not have a listener-queue. ++ * So, we need to make sure that this request-sock indeed gets destroyed. ++ */ ++ reqsk_put(req); ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKRX); ++ return child; ++ ++teardown: ++ req->rsk_ops->send_reset(meta_sk, skb); ++ ++ /* Drop this request - sock creation failed. */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ inet_csk_prepare_forced_close(child); ++ tcp_done(child); ++ return meta_sk; ++} ++ ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_tw *mptw; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* A subsocket in tw can only receive data. So, if we are in ++ * infinite-receive, then we should not reply with a data-ack or act ++ * upon general MPTCP-signaling. We prevent this by simply not creating ++ * the mptcp_tw_sock. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ tw->mptcp_tw = NULL; ++ return 0; ++ } ++ ++ /* Alloc MPTCP-tw-sock */ ++ mptw = kmem_cache_alloc(mptcp_tw_cache, GFP_ATOMIC); ++ if (!mptw) { ++ tw->mptcp_tw = NULL; ++ return -ENOBUFS; ++ } ++ ++ atomic_inc(&mpcb->mpcb_refcnt); ++ ++ tw->mptcp_tw = mptw; ++ mptw->loc_key = mpcb->mptcp_loc_key; ++ mptw->meta_tw = mpcb->in_time_wait; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ if (mptw->meta_tw && mpcb->mptw_state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ rcu_assign_pointer(mptw->mpcb, mpcb); ++ ++ spin_lock_bh(&mpcb->tw_lock); ++ list_add_rcu(&mptw->list, &tp->mpcb->tw_list); ++ mptw->in_list = 1; ++ spin_unlock_bh(&mpcb->tw_lock); ++ ++ return 0; ++} ++ ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_cb *mpcb; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ mpcb = rcu_dereference(tw->mptcp_tw->mpcb); ++ ++ /* If we are still holding a ref to the mpcb, we have to remove ourself ++ * from the list and drop the ref properly. ++ */ ++ if (mpcb && atomic_inc_not_zero(&mpcb->mpcb_refcnt)) { ++ spin_lock(&mpcb->tw_lock); ++ if (tw->mptcp_tw->in_list) { ++ list_del_rcu(&tw->mptcp_tw->list); ++ tw->mptcp_tw->in_list = 0; ++ /* Put, because we added it to the list */ ++ mptcp_mpcb_put(mpcb); ++ } ++ spin_unlock(&mpcb->tw_lock); ++ ++ /* Second time, because we increased it above */ ++ mptcp_mpcb_put(mpcb); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ kmem_cache_free(mptcp_tw_cache, tw->mptcp_tw); ++} ++ ++/* Updates the rcv_nxt of the time-wait-socks and allows them to ack a ++ * data-fin. ++ */ ++void mptcp_time_wait(struct sock *meta_sk, int state, int timeo) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tw *mptw; ++ ++ if (mptcp_in_infinite_mapping_weak(meta_tp->mpcb)) { ++ struct sock *sk_it, *tmp; ++ ++ mptcp_for_each_sk_safe(meta_tp->mpcb, sk_it, tmp) { ++ if (sk_it->sk_state == TCP_CLOSE) ++ continue; ++ ++ tcp_sk(sk_it)->ops->time_wait(sk_it, state, timeo); ++ } ++ } ++ ++ /* Used for sockets that go into tw after the meta ++ * (see mptcp_init_tw_sock()) ++ */ ++ meta_tp->mpcb->in_time_wait = 1; ++ meta_tp->mpcb->mptw_state = state; ++ ++ /* Update the time-wait-sock's information */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ list_for_each_entry_rcu(mptw, &meta_tp->mpcb->tw_list, list) { ++ mptw->meta_tw = 1; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(meta_tp); ++ ++ /* We want to ack a DATA_FIN, but are yet in FIN_WAIT_2 - ++ * pretend as if the DATA_FIN has already reached us, that way ++ * the checks in tcp_timewait_state_process will be good as the ++ * DATA_FIN comes in. ++ */ ++ if (state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ } ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++} ++ ++void mptcp_tsq_flags(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* It will be handled as a regular deferred-call */ ++ if (is_meta_sk(sk)) ++ return; ++ ++ if (hlist_unhashed(&tp->mptcp->cb_list)) { ++ hlist_add_head(&tp->mptcp->cb_list, &tp->mpcb->callback_list); ++ /* We need to hold it here, as the sock_hold is not assured ++ * by the release_sock as it is done in regular TCP. ++ * ++ * The subsocket may get inet_csk_destroy'd while it is inside ++ * the callback_list. ++ */ ++ sock_hold(sk); ++ } ++ ++ if (!test_and_set_bit(MPTCP_SUB_DEFERRED, &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++} ++ ++void mptcp_tsq_sub_deferred(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __sock_put(meta_sk); ++ hlist_for_each_entry_safe(mptcp, tmp, &meta_tp->mpcb->callback_list, cb_list) { ++ struct tcp_sock *tp = mptcp->tp; ++ struct sock *sk = (struct sock *)tp; ++ ++ hlist_del_init(&mptcp->cb_list); ++ sk->sk_prot->release_cb(sk); ++ /* Final sock_put (cfr. mptcp_tsq_flags) */ ++ sock_put(sk); ++ } ++} ++ ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct mptcp_options_received mopt; ++ u8 mptcp_hash_mac[20]; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->is_sub = 1; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ mtreq->mptcp_rem_nonce = mopt.mptcp_recv_nonce; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce); ++ mtreq->mptcp_hash_tmac = *(u64 *)mptcp_hash_mac; ++ ++ mtreq->rem_id = mopt.rem_id; ++ mtreq->rcv_low_prio = mopt.low_prio; ++ inet_rsk(req)->saw_mpc = 1; ++ ++ MPTCP_INC_STATS(sock_net(mpcb->meta_sk), MPTCP_MIB_JOINSYNRX); ++} ++ ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_options_received mopt; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->dss_csum = mopt.dss_csum; ++ ++ if (want_cookie) { ++ if (!mptcp_reqsk_new_cookie(req, sk, &mopt, skb)) ++ /* No key available - back to regular TCP */ ++ inet_rsk(req)->mptcp_rqsk = 0; ++ return; ++ } ++ ++ mptcp_reqsk_new_mptcp(req, sk, &mopt, skb); ++} ++ ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* Absolutely need to always initialize this. */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->mptcp_loc_key = mopt->mptcp_receiver_key; ++ ++ /* Generate the token */ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* Check, if the key is still free */ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) ++ goto out; ++ ++ inet_rsk(req)->saw_mpc = 1; ++ mtreq->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ mtreq->dss_csum = mopt->dss_csum; ++ ++out: ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb) ++{ ++ struct mptcp_options_received mopt; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ if (mopt.is_mp_join) ++ return mptcp_do_join_short(skb, &mopt, sock_net(sk)); ++ if (mopt.drop_me) ++ goto drop; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) ++ mopt.saw_mpc = 0; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ if (mopt.saw_mpc) { ++ if (skb_rtable(skb)->rt_flags & ++ (RTCF_BROADCAST | RTCF_MULTICAST)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_request_sock_ipv4_ops, ++ sk, skb); ++ } ++ ++ return tcp_v4_conn_request(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ if (mopt.saw_mpc) { ++ if (!ipv6_unicast_destination(skb)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_request_sock_ipv6_ops, ++ sk, skb); ++ } ++ ++ return tcp_v6_conn_request(sk, skb); ++#endif ++ } ++drop: ++ __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); ++ return 0; ++} ++ ++static void __mptcp_get_info(const struct sock *meta_sk, ++ struct mptcp_meta_info *info) ++{ ++ const struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 now = tcp_jiffies32; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ info->mptcpi_state = meta_sk->sk_state; ++ info->mptcpi_retransmits = meta_icsk->icsk_retransmits; ++ info->mptcpi_probes = meta_icsk->icsk_probes_out; ++ info->mptcpi_backoff = meta_icsk->icsk_backoff; ++ ++ info->mptcpi_rto = jiffies_to_usecs(meta_icsk->icsk_rto); ++ ++ info->mptcpi_unacked = meta_tp->packets_out; ++ ++ info->mptcpi_last_data_sent = jiffies_to_msecs(now - meta_tp->lsndtime); ++ info->mptcpi_last_data_recv = jiffies_to_msecs(now - meta_icsk->icsk_ack.lrcvtime); ++ info->mptcpi_last_ack_recv = jiffies_to_msecs(now - meta_tp->rcv_tstamp); ++ ++ info->mptcpi_total_retrans = meta_tp->total_retrans; ++ ++ info->mptcpi_bytes_acked = meta_tp->bytes_acked; ++ info->mptcpi_bytes_received = meta_tp->bytes_received; ++} ++ ++static void mptcp_get_sub_info(struct sock *sk, struct mptcp_sub_info *info) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ ++ memset(info, 0, sizeof(*info)); ++ ++ if (sk->sk_family == AF_INET) { ++ info->src_v4.sin_family = AF_INET; ++ info->src_v4.sin_port = inet->inet_sport; ++ ++ info->src_v4.sin_addr.s_addr = inet->inet_rcv_saddr; ++ if (!info->src_v4.sin_addr.s_addr) ++ info->src_v4.sin_addr.s_addr = inet->inet_saddr; ++ ++ info->dst_v4.sin_family = AF_INET; ++ info->dst_v4.sin_port = inet->inet_dport; ++ info->dst_v4.sin_addr.s_addr = inet->inet_daddr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ info->src_v6.sin6_family = AF_INET6; ++ info->src_v6.sin6_port = inet->inet_sport; ++ ++ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) ++ info->src_v6.sin6_addr = np->saddr; ++ else ++ info->src_v6.sin6_addr = sk->sk_v6_rcv_saddr; ++ ++ info->dst_v6.sin6_family = AF_INET6; ++ info->dst_v6.sin6_port = inet->inet_dport; ++ info->dst_v6.sin6_addr = sk->sk_v6_daddr; ++#endif ++ } ++} ++ ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk; ++ ++ struct mptcp_meta_info meta_info; ++ struct mptcp_info m_info; ++ ++ unsigned int info_len; ++ ++ /* Check again with the lock held */ ++ if (!mptcp(meta_tp)) ++ return -EINVAL; ++ ++ if (copy_from_user(&m_info, optval, optlen)) ++ return -EFAULT; ++ ++ if (m_info.meta_info) { ++ unsigned int len; ++ ++ __mptcp_get_info(meta_sk, &meta_info); ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ len = min_t(unsigned int, m_info.meta_len, sizeof(meta_info)); ++ m_info.meta_len = len; ++ ++ if (copy_to_user((void __user *)m_info.meta_info, &meta_info, len)) ++ return -EFAULT; ++ } ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ info_len = min_t(unsigned int, m_info.tcp_info_len, sizeof(struct tcp_info)); ++ m_info.tcp_info_len = info_len; ++ ++ if (m_info.initial) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (mpcb->master_sk) { ++ struct tcp_info info; ++ ++ tcp_get_info(mpcb->master_sk, &info, true); ++ if (copy_to_user((void __user *)m_info.initial, &info, info_len)) ++ return -EFAULT; ++ } else if (meta_tp->record_master_info && mpcb->master_info) { ++ if (copy_to_user((void __user *)m_info.initial, mpcb->master_info, info_len)) ++ return -EFAULT; ++ } else { ++ return meta_tp->record_master_info ? -ENOMEM : -EINVAL; ++ } ++ } ++ ++ if (m_info.subflows) { ++ unsigned int len, sub_len = 0; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflows; ++ len = m_info.sub_len; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_info t_info; ++ unsigned int tmp_len; ++ ++ tcp_get_info(sk, &t_info, true); ++ ++ tmp_len = min_t(unsigned int, len, info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &t_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ sub_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.sub_len = sub_len; ++ } ++ ++ if (m_info.subflow_info) { ++ unsigned int len, sub_info_len, total_sub_info_len = 0; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflow_info; ++ len = m_info.total_sub_info_len; ++ ++ sub_info_len = min_t(unsigned int, m_info.sub_info_len, ++ sizeof(struct mptcp_sub_info)); ++ m_info.sub_info_len = sub_info_len; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct mptcp_sub_info m_sub_info; ++ unsigned int tmp_len; ++ ++ mptcp_get_sub_info(sk, &m_sub_info); ++ ++ tmp_len = min_t(unsigned int, len, sub_info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &m_sub_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ total_sub_info_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.total_sub_info_len = total_sub_info_len; ++ } ++ ++ if (copy_to_user(optval, &m_info, optlen)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++void mptcp_clear_sk(struct sock *sk, int size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* we do not want to clear tk_table field, because of RCU lookups */ ++ sk_prot_clear_nulls(sk, offsetof(struct tcp_sock, tk_table.next)); ++ ++ size -= offsetof(struct tcp_sock, tk_table.pprev); ++ memset((char *)&tp->tk_table.pprev, 0, size); ++} ++ ++static const struct snmp_mib mptcp_snmp_list[] = { ++ SNMP_MIB_ITEM("MPCapableSYNRX", MPTCP_MIB_MPCAPABLEPASSIVE), ++ SNMP_MIB_ITEM("MPCapableSYNTX", MPTCP_MIB_MPCAPABLEACTIVE), ++ SNMP_MIB_ITEM("MPCapableSYNACKRX", MPTCP_MIB_MPCAPABLEACTIVEACK), ++ SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK), ++ SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableRetransFallback", MPTCP_MIB_MPCAPABLERETRANSFALLBACK), ++ SNMP_MIB_ITEM("MPTCPCsumEnabled", MPTCP_MIB_CSUMENABLED), ++ SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), ++ SNMP_MIB_ITEM("MPFailRX", MPTCP_MIB_MPFAILRX), ++ SNMP_MIB_ITEM("MPCsumFail", MPTCP_MIB_CSUMFAIL), ++ SNMP_MIB_ITEM("MPFastcloseRX", MPTCP_MIB_FASTCLOSERX), ++ SNMP_MIB_ITEM("MPFastcloseTX", MPTCP_MIB_FASTCLOSETX), ++ SNMP_MIB_ITEM("MPFallbackAckSub", MPTCP_MIB_FBACKSUB), ++ SNMP_MIB_ITEM("MPFallbackAckInit", MPTCP_MIB_FBACKINIT), ++ SNMP_MIB_ITEM("MPFallbackDataSub", MPTCP_MIB_FBDATASUB), ++ SNMP_MIB_ITEM("MPFallbackDataInit", MPTCP_MIB_FBDATAINIT), ++ SNMP_MIB_ITEM("MPRemoveAddrSubDelete", MPTCP_MIB_REMADDRSUB), ++ SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), ++ SNMP_MIB_ITEM("MPJoinAlreadyFallenback", MPTCP_MIB_JOINFALLBACK), ++ SNMP_MIB_ITEM("MPJoinSynTx", MPTCP_MIB_JOINSYNTX), ++ SNMP_MIB_ITEM("MPJoinSynRx", MPTCP_MIB_JOINSYNRX), ++ SNMP_MIB_ITEM("MPJoinSynAckRx", MPTCP_MIB_JOINSYNACKRX), ++ SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX), ++ SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckMissing", MPTCP_MIB_JOINACKFAIL), ++ SNMP_MIB_ITEM("MPJoinAckRTO", MPTCP_MIB_JOINACKRTO), ++ SNMP_MIB_ITEM("MPJoinAckRexmit", MPTCP_MIB_JOINACKRXMIT), ++ SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), ++ SNMP_MIB_ITEM("DSSNotMatching", MPTCP_MIB_DSSNOMATCH), ++ SNMP_MIB_ITEM("InfiniteMapRx", MPTCP_MIB_INFINITEMAPRX), ++ SNMP_MIB_ITEM("DSSNoMatchTCP", MPTCP_MIB_DSSTCPMISMATCH), ++ SNMP_MIB_ITEM("DSSTrimHead", MPTCP_MIB_DSSTRIMHEAD), ++ SNMP_MIB_ITEM("DSSSplitTail", MPTCP_MIB_DSSSPLITTAIL), ++ SNMP_MIB_ITEM("DSSPurgeOldSubSegs", MPTCP_MIB_PURGEOLD), ++ SNMP_MIB_ITEM("AddAddrRx", MPTCP_MIB_ADDADDRRX), ++ SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), ++ SNMP_MIB_ITEM("RemAddrRx", MPTCP_MIB_REMADDRRX), ++ SNMP_MIB_ITEM("RemAddrTx", MPTCP_MIB_REMADDRTX), ++ SNMP_MIB_SENTINEL ++}; ++ ++struct workqueue_struct *mptcp_wq; ++EXPORT_SYMBOL(mptcp_wq); ++ ++/* Output /proc/net/mptcp */ ++static int mptcp_pm_seq_show(struct seq_file *seq, void *v) ++{ ++ struct tcp_sock *meta_tp; ++ const struct net *net = seq->private; ++ int i, n = 0; ++ ++ seq_printf(seq, " sl loc_tok rem_tok v6 local_address remote_address st ns tx_queue rx_queue inode"); ++ seq_putc(seq, '\n'); ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ struct hlist_nulls_node *node; ++ rcu_read_lock(); ++ local_bh_disable(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &tk_hashtable[i], tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp; ++ struct inet_sock *isk = inet_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (!mptcp(meta_tp) || !net_eq(net, sock_net(meta_sk))) ++ continue; ++ ++ if (!mpcb) ++ continue; ++ ++ if (capable(CAP_NET_ADMIN)) { ++ seq_printf(seq, "%4d: %04X %04X ", n++, ++ mpcb->mptcp_loc_token, ++ mpcb->mptcp_rem_token); ++ } else { ++ seq_printf(seq, "%4d: %04X %04X ", n++, -1, -1); ++ } ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ seq_printf(seq, " 0 %08X:%04X %08X:%04X ", ++ isk->inet_rcv_saddr, ++ ntohs(isk->inet_sport), ++ isk->inet_daddr, ++ ntohs(isk->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct in6_addr *src = &meta_sk->sk_v6_rcv_saddr; ++ struct in6_addr *dst = &meta_sk->sk_v6_daddr; ++ seq_printf(seq, " 1 %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X", ++ src->s6_addr32[0], src->s6_addr32[1], ++ src->s6_addr32[2], src->s6_addr32[3], ++ ntohs(isk->inet_sport), ++ dst->s6_addr32[0], dst->s6_addr32[1], ++ dst->s6_addr32[2], dst->s6_addr32[3], ++ ntohs(isk->inet_dport)); ++#endif ++ } ++ seq_printf(seq, " %02X %02X %08X:%08X %lu", ++ meta_sk->sk_state, mpcb->cnt_subflows, ++ meta_tp->write_seq - meta_tp->snd_una, ++ max_t(int, meta_tp->rcv_nxt - ++ meta_tp->copied_seq, 0), ++ sock_i_ino(meta_sk)); ++ seq_putc(seq, '\n'); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++ return 0; ++} ++ ++static int mptcp_pm_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_pm_seq_show); ++} ++ ++static const struct file_operations mptcp_pm_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_pm_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_snmp_seq_show(struct seq_file *seq, void *v) ++{ ++ struct net *net = seq->private; ++ int i; ++ ++ for (i = 0; mptcp_snmp_list[i].name != NULL; i++) ++ seq_printf(seq, "%-32s\t%ld\n", mptcp_snmp_list[i].name, ++ snmp_fold_field(net->mptcp.mptcp_statistics, ++ mptcp_snmp_list[i].entry)); ++ ++ return 0; ++} ++ ++static int mptcp_snmp_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_snmp_seq_show); ++} ++ ++static const struct file_operations mptcp_snmp_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_snmp_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_pm_init_net(struct net *net) ++{ ++ net->mptcp.mptcp_statistics = alloc_percpu(struct mptcp_mib); ++ if (!net->mptcp.mptcp_statistics) ++ goto out_mptcp_mibs; ++ ++#ifdef CONFIG_PROC_FS ++ net->mptcp.proc_net_mptcp = proc_net_mkdir(net, "mptcp_net", net->proc_net); ++ if (!net->mptcp.proc_net_mptcp) ++ goto out_proc_net_mptcp; ++ if (!proc_create("mptcp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ &mptcp_pm_seq_fops)) ++ goto out_mptcp_net_mptcp; ++ if (!proc_create("snmp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ &mptcp_snmp_seq_fops)) ++ goto out_mptcp_net_snmp; ++#endif ++ ++ return 0; ++ ++#ifdef CONFIG_PROC_FS ++out_mptcp_net_snmp: ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++out_mptcp_net_mptcp: ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ net->mptcp.proc_net_mptcp = NULL; ++out_proc_net_mptcp: ++ free_percpu(net->mptcp.mptcp_statistics); ++#endif ++out_mptcp_mibs: ++ return -ENOMEM; ++} ++ ++static void mptcp_pm_exit_net(struct net *net) ++{ ++ remove_proc_entry("snmp", net->mptcp.proc_net_mptcp); ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ free_percpu(net->mptcp.mptcp_statistics); ++} ++ ++static struct pernet_operations mptcp_pm_proc_ops = { ++ .init = mptcp_pm_init_net, ++ .exit = mptcp_pm_exit_net, ++}; ++ ++/* General initialization of mptcp */ ++void __init mptcp_init(void) ++{ ++ int i; ++ struct ctl_table_header *mptcp_sysctl; ++ ++ mptcp_sock_cache = kmem_cache_create("mptcp_sock", ++ sizeof(struct mptcp_tcp_sock), ++ 0, SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_sock_cache) ++ goto mptcp_sock_cache_failed; ++ ++ mptcp_cb_cache = kmem_cache_create("mptcp_cb", sizeof(struct mptcp_cb), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_cb_cache) ++ goto mptcp_cb_cache_failed; ++ ++ mptcp_tw_cache = kmem_cache_create("mptcp_tw", sizeof(struct mptcp_tw), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_tw_cache) ++ goto mptcp_tw_cache_failed; ++ ++ get_random_bytes(&mptcp_secret, sizeof(mptcp_secret)); ++ ++ mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8); ++ if (!mptcp_wq) ++ goto alloc_workqueue_failed; ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ INIT_HLIST_NULLS_HEAD(&tk_hashtable[i], i); ++ INIT_HLIST_NULLS_HEAD(&mptcp_reqsk_tk_htb[i], i); ++ } ++ ++ spin_lock_init(&mptcp_tk_hashlock); ++ ++ if (register_pernet_subsys(&mptcp_pm_proc_ops)) ++ goto pernet_failed; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_pm_v6_init()) ++ goto mptcp_pm_v6_failed; ++#endif ++ if (mptcp_pm_v4_init()) ++ goto mptcp_pm_v4_failed; ++ ++ mptcp_sysctl = register_net_sysctl(&init_net, "net/mptcp", mptcp_table); ++ if (!mptcp_sysctl) ++ goto register_sysctl_failed; ++ ++ if (mptcp_register_path_manager(&mptcp_pm_default)) ++ goto register_pm_failed; ++ ++ if (mptcp_register_scheduler(&mptcp_sched_default)) ++ goto register_sched_failed; ++ ++ pr_info("MPTCP: Stable release v0.94.7"); ++ ++ mptcp_init_failed = false; ++ ++ return; ++ ++register_sched_failed: ++ mptcp_unregister_path_manager(&mptcp_pm_default); ++register_pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl); ++register_sysctl_failed: ++ mptcp_pm_v4_undo(); ++mptcp_pm_v4_failed: ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_pm_v6_undo(); ++mptcp_pm_v6_failed: ++#endif ++ unregister_pernet_subsys(&mptcp_pm_proc_ops); ++pernet_failed: ++ destroy_workqueue(mptcp_wq); ++alloc_workqueue_failed: ++ kmem_cache_destroy(mptcp_tw_cache); ++mptcp_tw_cache_failed: ++ kmem_cache_destroy(mptcp_cb_cache); ++mptcp_cb_cache_failed: ++ kmem_cache_destroy(mptcp_sock_cache); ++mptcp_sock_cache_failed: ++ mptcp_init_failed = true; ++} +diff -aurN linux-4.14.174/net/mptcp/mptcp_fullmesh.c mptcp-mptcp_v0.94/net/mptcp/mptcp_fullmesh.c +--- linux-4.14.174/net/mptcp/mptcp_fullmesh.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_fullmesh.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,2016 @@ ++#include ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++ ++enum { ++ MPTCP_EVENT_ADD = 1, ++ MPTCP_EVENT_DEL, ++ MPTCP_EVENT_MOD, ++}; ++ ++#define MPTCP_SUBFLOW_RETRY_DELAY 1000 ++ ++/* Max number of local or remote addresses we can store. ++ * When changing, see the bitfield below in fullmesh_rem4/6. ++ */ ++#define MPTCP_MAX_ADDR 8 ++ ++struct fullmesh_rem4 { ++ u8 rem4_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct fullmesh_rem6 { ++ u8 rem6_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_loc_addr { ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ u8 loc4_bits; ++ u8 next_v4_index; ++ ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++ u8 loc6_bits; ++ u8 next_v6_index; ++ struct rcu_head rcu; ++}; ++ ++struct mptcp_addr_event { ++ struct list_head list; ++ unsigned short family; ++ u8 code:7, ++ low_prio:1; ++ int if_idx; ++ union inet_addr addr; ++}; ++ ++struct fullmesh_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ /* Delayed worker, when the routing-tables are not yet ready. */ ++ struct delayed_work subflow_retry_work; ++ ++ /* Remote addresses */ ++ struct fullmesh_rem4 remaddr4[MPTCP_MAX_ADDR]; ++ struct fullmesh_rem6 remaddr6[MPTCP_MAX_ADDR]; ++ ++ struct mptcp_cb *mpcb; ++ ++ u16 remove_addrs; /* Addresses to remove */ ++ u8 announced_addrs_v4; /* IPv4 Addresses we did announce */ ++ u8 announced_addrs_v6; /* IPv6 Addresses we did announce */ ++ ++ u8 add_addr; /* Are we sending an add_addr? */ ++ ++ u8 rem4_bits; ++ u8 rem6_bits; ++ ++ /* Are we established the additional subflows for primary pair? */ ++ u8 first_pair:1; ++}; ++ ++struct mptcp_fm_ns { ++ struct mptcp_loc_addr __rcu *local; ++ spinlock_t local_lock; /* Protecting the above pointer */ ++ struct list_head events; ++ struct delayed_work address_worker; ++ ++ struct net *net; ++}; ++ ++static int num_subflows __read_mostly = 1; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per pair of IP addresses of MPTCP connection"); ++ ++static int create_on_err __read_mostly; ++module_param(create_on_err, int, 0644); ++MODULE_PARM_DESC(create_on_err, "recreate the subflow upon a timeout"); ++ ++static struct mptcp_pm_ops full_mesh __read_mostly; ++ ++static void full_mesh_create_subflows(struct sock *meta_sk); ++ ++static struct mptcp_fm_ns *fm_get_ns(const struct net *net) ++{ ++ return (struct mptcp_fm_ns *)net->mptcp.path_managers[MPTCP_PM_FULLMESH]; ++} ++ ++static struct fullmesh_priv *fullmesh_get_priv(const struct mptcp_cb *mpcb) ++{ ++ return (struct fullmesh_priv *)&mpcb->mptcp_pm[0]; ++} ++ ++/* Find the first free index in the bitfield */ ++static int __mptcp_find_free_index(u8 bitfield, u8 base) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ goto exit; ++ ++ i = ffs(~(bitfield >> base)) - 1; ++ if (i < 0) ++ goto exit; ++ ++ /* No free bits when starting at base, try from 0 on */ ++ if (i + base >= sizeof(bitfield) * 8) ++ return __mptcp_find_free_index(bitfield, 0); ++ ++ return i + base; ++exit: ++ return -1; ++} ++ ++static int mptcp_find_free_index(u8 bitfield) ++{ ++ return __mptcp_find_free_index(bitfield, 0); ++} ++ ++static void mptcp_addv4_raddr(struct mptcp_cb *mpcb, ++ const struct in_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem4 *rem4; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem4->rem4_id == id && ++ rem4->addr.s_addr == addr->s_addr && rem4->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem4->rem4_id == id && rem4->addr.s_addr != addr->s_addr) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr:%pI4 to addr %pI4 with id:%d\n", ++ __func__, &rem4->addr.s_addr, ++ &addr->s_addr, id); ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem4_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI4\n", ++ __func__, MPTCP_MAX_ADDR, &addr->s_addr); ++ return; ++ } ++ ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is not known yet, store it */ ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ rem4->bitfield = 0; ++ rem4->retry_bitfield = 0; ++ rem4->rem4_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem4_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_addv6_raddr(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem6 *rem6; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem6->rem6_id == id && ++ ipv6_addr_equal(&rem6->addr, addr) && rem6->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem6->rem6_id == id) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr: %pI6 to addr %pI6 with id:%d\n", ++ __func__, &rem6->addr, addr, id); ++ rem6->addr = *addr; ++ rem6->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem6_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI6\n", ++ __func__, MPTCP_MAX_ADDR, addr); ++ return; ++ } ++ ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is not known yet, store it */ ++ rem6->addr = *addr; ++ rem6->port = port; ++ rem6->bitfield = 0; ++ rem6->retry_bitfield = 0; ++ rem6->rem6_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem6_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_v4_rem_raddress(struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].rem4_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem4_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++static void mptcp_v6_rem_raddress(const struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (fmp->remaddr6[i].rem6_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem6_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v4_set_init_addr_bit(const struct mptcp_cb *mpcb, ++ const struct in_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].addr.s_addr == addr->s_addr) { ++ fmp->remaddr4[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v6_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (ipv6_addr_equal(&fmp->remaddr6[i].addr, addr)) { ++ fmp->remaddr6[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++static void mptcp_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_v4_set_init_addr_bit(mpcb, &addr->in, id); ++ else ++ mptcp_v6_set_init_addr_bit(mpcb, &addr->in6, id); ++} ++ ++static void mptcp_v4_subflows(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init4_subsockets(meta_sk, loc, rem); ++} ++ ++#if IS_ENABLED(CONFIG_IPV6) ++static void mptcp_v6_subflows(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init6_subsockets(meta_sk, loc, rem); ++} ++#endif ++ ++static void retry_subflow_worker(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct fullmesh_priv *fmp = container_of(delayed_work, ++ struct fullmesh_priv, ++ subflow_retry_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem = &fmp->remaddr4[i]; ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], &rem4); ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem = &fmp->remaddr6[i]; ++ ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], &rem6); ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ struct fullmesh_priv *fmp = container_of(work, struct fullmesh_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, retry = 0; ++ int i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD) || !mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ /* Create the additional subflows for the first pair */ ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_v4_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ iter++; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr4[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc4_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], ++ &rem4) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_v6_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr6[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc6_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], ++ &rem6) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++ if (retry && !delayed_work_pending(&fmp->subflow_retry_work)) { ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, &fmp->subflow_retry_work, ++ msecs_to_jiffies(MPTCP_SUBFLOW_RETRY_DELAY)); ++ } ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void announce_remove_addr(u8 addr_id, struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct sock *sk = mptcp_select_ack_sock(meta_sk); ++ ++ fmp->remove_addrs |= (1 << addr_id); ++ mpcb->addr_signal = 1; ++ ++ if (sk) ++ tcp_send_ack(sk); ++} ++ ++static void update_addr_bitfields(struct sock *meta_sk, ++ const struct mptcp_loc_addr *mptcp_local) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ int i; ++ ++ /* The bits in announced_addrs_* always match with loc*_bits. So, a ++ * simple & operation unsets the correct bits, because these go from ++ * announced to non-announced ++ */ ++ fmp->announced_addrs_v4 &= mptcp_local->loc4_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ fmp->remaddr4[i].bitfield &= mptcp_local->loc4_bits; ++ fmp->remaddr4[i].retry_bitfield &= mptcp_local->loc4_bits; ++ } ++ ++ fmp->announced_addrs_v6 &= mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ fmp->remaddr6[i].bitfield &= mptcp_local->loc6_bits; ++ fmp->remaddr6[i].retry_bitfield &= mptcp_local->loc6_bits; ++ } ++} ++ ++static int mptcp_find_address(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, const union inet_addr *addr, ++ int if_idx) ++{ ++ int i; ++ u8 loc_bits; ++ bool found = false; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ mptcp_local->locaddr4[i].addr.s_addr == addr->in.s_addr) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&mptcp_local->locaddr6[i].addr, ++ &addr->in6)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static int mptcp_find_address_transp(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, int if_idx) ++{ ++ bool found = false; ++ u8 loc_bits; ++ int i; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static void mptcp_address_worker(struct work_struct *work) ++{ ++ const struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct mptcp_fm_ns *fm_ns = container_of(delayed_work, ++ struct mptcp_fm_ns, ++ address_worker); ++ struct net *net = fm_ns->net; ++ struct mptcp_addr_event *event = NULL; ++ struct mptcp_loc_addr *mptcp_local, *old; ++ int i, id = -1; /* id is used in the socket-code on a delete-event */ ++ bool success; /* Used to indicate if we succeeded handling the event */ ++ ++next_event: ++ success = false; ++ kfree(event); ++ ++ /* First, let's dequeue an event from our event-list */ ++ rcu_read_lock_bh(); ++ spin_lock(&fm_ns->local_lock); ++ ++ event = list_first_entry_or_null(&fm_ns->events, ++ struct mptcp_addr_event, list); ++ if (!event) { ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ return; ++ } ++ ++ list_del(&event->list); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ id = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ ++ /* Not in the list - so we don't care */ ++ if (id < 0) { ++ mptcp_debug("%s could not find id\n", __func__); ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) ++ mptcp_local->loc4_bits &= ~(1 << id); ++ else ++ mptcp_local->loc6_bits &= ~(1 << id); ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } else { ++ int i = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ int j = i; ++ ++ if (j < 0) { ++ /* Not in the list, so we have to find an empty slot */ ++ if (event->family == AF_INET) ++ i = __mptcp_find_free_index(mptcp_local->loc4_bits, ++ mptcp_local->next_v4_index); ++ if (event->family == AF_INET6) ++ i = __mptcp_find_free_index(mptcp_local->loc6_bits, ++ mptcp_local->next_v6_index); ++ ++ if (i < 0) { ++ mptcp_debug("%s no more space\n", __func__); ++ goto duno; ++ } ++ ++ /* It might have been a MOD-event. */ ++ event->code = MPTCP_EVENT_ADD; ++ } else { ++ /* Let's check if anything changes */ ++ if (event->family == AF_INET && ++ event->low_prio == mptcp_local->locaddr4[i].low_prio) ++ goto duno; ++ ++ if (event->family == AF_INET6 && ++ event->low_prio == mptcp_local->locaddr6[i].low_prio) ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) { ++ mptcp_local->locaddr4[i].addr.s_addr = event->addr.in.s_addr; ++ mptcp_local->locaddr4[i].loc4_id = i + 1; ++ mptcp_local->locaddr4[i].low_prio = event->low_prio; ++ mptcp_local->locaddr4[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI4 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in.s_addr, ++ event->if_idx, event->low_prio, i + 1); ++ } else { ++ mptcp_local->locaddr6[i].addr = event->addr.in6; ++ mptcp_local->locaddr6[i].loc6_id = i + MPTCP_MAX_ADDR; ++ mptcp_local->locaddr6[i].low_prio = event->low_prio; ++ mptcp_local->locaddr6[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI6 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in6, ++ event->if_idx, event->low_prio, i + MPTCP_MAX_ADDR); ++ } ++ ++ if (j < 0) { ++ if (event->family == AF_INET) { ++ mptcp_local->loc4_bits |= (1 << i); ++ mptcp_local->next_v4_index = i + 1; ++ } else { ++ mptcp_local->loc6_bits |= (1 << i); ++ mptcp_local->next_v6_index = i + 1; ++ } ++ } ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } ++ success = true; ++ ++duno: ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ ++ if (!success) ++ goto next_event; ++ ++ /* Now we iterate over the MPTCP-sockets and apply the event. */ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ const struct hlist_nulls_node *node; ++ struct tcp_sock *meta_tp; ++ ++ rcu_read_lock_bh(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[i], ++ tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp, *sk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_cb *mpcb; ++ ++ if (sock_net(meta_sk) != net) ++ continue; ++ ++ if (meta_v4) { ++ /* skip IPv6 events if meta is IPv4 */ ++ if (event->family == AF_INET6) ++ continue; ++ } else if (event->family == AF_INET && meta_sk->sk_ipv6only) { ++ /* skip IPv4 events if IPV6_V6ONLY is set */ ++ continue; ++ } ++ ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ continue; ++ ++ bh_lock_sock(meta_sk); ++ ++ mpcb = meta_tp->mpcb; ++ if (!mpcb) ++ goto next; ++ ++ if (!mptcp(meta_tp) || !is_meta_sk(meta_sk) || ++ mptcp_in_infinite_mapping_weak(mpcb)) ++ goto next; ++ ++ /* May be that the pm has changed in-between */ ++ if (mpcb->pm_ops != &full_mesh) ++ goto next; ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (!test_and_set_bit(MPTCP_PATH_MANAGER_DEFERRED, ++ &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++ ++ goto next; ++ } ++ ++ if (event->code == MPTCP_EVENT_ADD) { ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ ++ full_mesh_create_subflows(meta_sk); ++ } ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ struct sock *sk, *tmpsk; ++ struct mptcp_loc_addr *mptcp_local; ++ bool found = false; ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ /* In any case, we need to update our bitfields */ ++ if (id >= 0) ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ /* Look for the socket and remove him */ ++ mptcp_for_each_sk_safe(mpcb, sk, tmpsk) { ++ if ((event->family == AF_INET6 && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk))) || ++ (event->family == AF_INET && ++ (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)))) ++ continue; ++ ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr != event->addr.in.s_addr) ++ continue; ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) ++ continue; ++ ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ /* We announce the removal of this id */ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ found = true; ++ } ++ ++ if (found) ++ goto next; ++ ++ /* The id may have been given by the event, ++ * matching on a local address. And it may not ++ * have matched on one of the above sockets, ++ * because the client never created a subflow. ++ * So, we have to finally remove it here. ++ */ ++ if (id >= 0) { ++ u8 loc_id = id ++ + (event->family == AF_INET ? 1 : MPTCP_MAX_ADDR); ++ announce_remove_addr(loc_id, meta_sk); ++ } ++ } ++ ++ if (event->code == MPTCP_EVENT_MOD) { ++ struct sock *sk; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr == event->addr.in.s_addr) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ } ++ } ++next: ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); ++ } ++ rcu_read_unlock_bh(); ++ } ++ goto next_event; ++} ++ ++static struct mptcp_addr_event *lookup_similar_event(const struct net *net, ++ const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ list_for_each_entry(eventq, &fm_ns->events, list) { ++ if (eventq->family != event->family) ++ continue; ++ if (eventq->if_idx != event->if_idx) ++ continue; ++ if (event->family == AF_INET) { ++ if (eventq->addr.in.s_addr == event->addr.in.s_addr) ++ return eventq; ++ } else { ++ if (ipv6_addr_equal(&eventq->addr.in6, &event->addr.in6)) ++ return eventq; ++ } ++ } ++ return NULL; ++} ++ ++/* We already hold the net-namespace MPTCP-lock */ ++static void add_pm_event(struct net *net, const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq = lookup_similar_event(net, event); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ if (eventq) { ++ switch (event->code) { ++ case MPTCP_EVENT_DEL: ++ mptcp_debug("%s del old_code %u\n", __func__, eventq->code); ++ list_del(&eventq->list); ++ kfree(eventq); ++ break; ++ case MPTCP_EVENT_ADD: ++ mptcp_debug("%s add old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_ADD; ++ return; ++ case MPTCP_EVENT_MOD: ++ mptcp_debug("%s mod old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_MOD; ++ return; ++ } ++ } ++ ++ /* OK, we have to add the new address to the wait queue */ ++ eventq = kmemdup(event, sizeof(struct mptcp_addr_event), GFP_ATOMIC); ++ if (!eventq) ++ return; ++ ++ list_add_tail(&eventq->list, &fm_ns->events); ++ ++ /* Create work-queue */ ++ if (!delayed_work_pending(&fm_ns->address_worker)) ++ queue_delayed_work(mptcp_wq, &fm_ns->address_worker, ++ msecs_to_jiffies(500)); ++} ++ ++static void addr4_event_handler(const struct in_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->ifa_dev->dev; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->ifa_scope > RT_SCOPE_LINK || ++ ipv4_is_loopback(ifa->ifa_local)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET; ++ mpevent.addr.in.s_addr = ifa->ifa_local; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI4, code %u prio %u idx %u\n", __func__, ++ &ifa->ifa_local, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv4-addr add/rem-events */ ++static int mptcp_pm_inetaddr_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ const struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net *net = dev_net(ifa->ifa_dev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr4_event_handler(ifa, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_inetaddr_notifier = { ++ .notifier_call = mptcp_pm_inetaddr_event, ++}; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++/* IPV6-related address/interface watchers */ ++struct mptcp_dad_data { ++ struct timer_list timer; ++ struct inet6_ifaddr *ifa; ++}; ++ ++static void dad_callback(unsigned long arg); ++static int inet6_addr_event(struct notifier_block *this, ++ unsigned long event, void *ptr); ++ ++static bool ipv6_dad_finished(const struct inet6_ifaddr *ifa) ++{ ++ return !(ifa->flags & IFA_F_TENTATIVE) || ++ ifa->state > INET6_IFADDR_STATE_DAD; ++} ++ ++static void dad_init_timer(struct mptcp_dad_data *data, ++ struct inet6_ifaddr *ifa) ++{ ++ data->ifa = ifa; ++ data->timer.data = (unsigned long)data; ++ data->timer.function = dad_callback; ++ if (ifa->idev->cnf.rtr_solicit_delay) ++ data->timer.expires = jiffies + ifa->idev->cnf.rtr_solicit_delay; ++ else ++ data->timer.expires = jiffies + (HZ/10); ++} ++ ++static void dad_callback(unsigned long arg) ++{ ++ struct mptcp_dad_data *data = (struct mptcp_dad_data *)arg; ++ ++ /* DAD failed or IP brought down? */ ++ if (data->ifa->state == INET6_IFADDR_STATE_ERRDAD || ++ data->ifa->state == INET6_IFADDR_STATE_DEAD) ++ goto exit; ++ ++ if (!ipv6_dad_finished(data->ifa)) { ++ dad_init_timer(data, data->ifa); ++ add_timer(&data->timer); ++ return; ++ } ++ ++ inet6_addr_event(NULL, NETDEV_UP, data->ifa); ++ ++exit: ++ in6_ifa_put(data->ifa); ++ kfree(data); ++} ++ ++static inline void dad_setup_timer(struct inet6_ifaddr *ifa) ++{ ++ struct mptcp_dad_data *data; ++ ++ data = kmalloc(sizeof(*data), GFP_ATOMIC); ++ ++ if (!data) ++ return; ++ ++ init_timer(&data->timer); ++ dad_init_timer(data, ifa); ++ add_timer(&data->timer); ++ in6_ifa_hold(ifa); ++} ++ ++static void addr6_event_handler(const struct inet6_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->idev->dev; ++ int addr_type = ipv6_addr_type(&ifa->addr); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->scope > RT_SCOPE_LINK || ++ addr_type == IPV6_ADDR_ANY || ++ (addr_type & IPV6_ADDR_LOOPBACK) || ++ (addr_type & IPV6_ADDR_LINKLOCAL)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET6; ++ mpevent.addr.in6 = ifa->addr; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI6, code %u prio %u idx %u\n", __func__, ++ &ifa->addr, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv6-addr add/rem-events */ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ struct inet6_ifaddr *ifa6 = (struct inet6_ifaddr *)ptr; ++ struct net *net = dev_net(ifa6->idev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ if (sysctl_mptcp_enabled && !ipv6_dad_finished(ifa6)) ++ dad_setup_timer(ifa6); ++ else ++ addr6_event_handler(ifa6, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block inet6_addr_notifier = { ++ .notifier_call = inet6_addr_event, ++}; ++ ++#endif ++ ++/* React on ifup/down-events */ ++static int netdev_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ const struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct in_device *in_dev; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct inet6_dev *in6_dev; ++#endif ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ rcu_read_lock(); ++ in_dev = __in_dev_get_rtnl(dev); ++ ++ if (in_dev) { ++ for_ifa(in_dev) { ++ mptcp_pm_inetaddr_event(NULL, event, ifa); ++ } endfor_ifa(in_dev); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ in6_dev = __in6_dev_get(dev); ++ ++ if (in6_dev) { ++ struct inet6_ifaddr *ifa6; ++ list_for_each_entry(ifa6, &in6_dev->addr_list, if_list) ++ inet6_addr_event(NULL, event, ifa6); ++ } ++#endif ++ ++ rcu_read_unlock(); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_netdev_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++static void full_mesh_add_raddr(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_addv4_raddr(mpcb, &addr->in, port, id); ++ else ++ mptcp_addv6_raddr(mpcb, &addr->in6, port, id); ++} ++ ++static void full_mesh_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct tcp_sock *master_tp = tcp_sk(mpcb->master_sk); ++ int i, index, if_idx = 0; ++ union inet_addr saddr, daddr; ++ sa_family_t family = AF_INET; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ /* Init local variables necessary for the rest */ ++ if (meta_sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(meta_sk)) { ++ saddr.ip = inet_sk(meta_sk)->inet_saddr; ++ daddr.ip = inet_sk(meta_sk)->inet_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ saddr.in6 = inet6_sk(meta_sk)->saddr; ++ daddr.in6 = meta_sk->sk_v6_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET6; ++#endif ++ } ++ ++ if (inet_sk(meta_sk)->transparent) ++ if_idx = inet_sk(meta_sk)->rx_dst_ifindex; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (inet_sk(meta_sk)->transparent) ++ index = mptcp_find_address_transp(mptcp_local, family, if_idx); ++ else ++ index = mptcp_find_address(mptcp_local, family, &saddr, if_idx); ++ if (index < 0) ++ goto fallback; ++ ++ if (family == AF_INET) ++ master_tp->mptcp->low_prio = mptcp_local->locaddr4[index].low_prio; ++ else ++ master_tp->mptcp->low_prio = mptcp_local->locaddr6[index].low_prio; ++ master_tp->mptcp->send_mp_prio = master_tp->mptcp->low_prio; ++ ++ full_mesh_add_raddr(mpcb, &daddr, family, 0, 0); ++ mptcp_set_init_addr_bit(mpcb, &daddr, family, index); ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ INIT_DELAYED_WORK(&fmp->subflow_retry_work, retry_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* Look for the address among the local addresses */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ __be32 ifa_address = mptcp_local->locaddr4[i].addr.s_addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ saddr.ip == ifa_address) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto skip_ipv6; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ const struct in6_addr *ifa6 = &mptcp_local->locaddr6[i].addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&saddr.in6, ifa6)) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv6: ++#endif ++ ++ rcu_read_unlock_bh(); ++ ++ if (family == AF_INET) ++ fmp->announced_addrs_v4 |= (1 << index); ++ else ++ fmp->announced_addrs_v6 |= (1 << index); ++ ++ for (i = fmp->add_addr; i && fmp->add_addr; i--) ++ tcp_send_ack(mpcb->master_sk); ++ ++ if (master_tp->mptcp->send_mp_prio) ++ tcp_send_ack(mpcb->master_sk); ++ ++ return; ++ ++fallback: ++ rcu_read_unlock_bh(); ++ mptcp_fallback_default(mpcb); ++ return; ++} ++ ++static void full_mesh_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ return; ++ ++ if (!work_pending(&fmp->subflow_work)) { ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &fmp->subflow_work); ++ } ++} ++ ++static void full_mesh_subflow_error(struct sock *meta_sk, struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (!create_on_err) ++ return; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (sk->sk_err != ETIMEDOUT) ++ return; ++ ++ full_mesh_create_subflows(meta_sk); ++} ++ ++/* Called upon release_sock, if the socket was owned by the user during ++ * a path-management event. ++ */ ++static void full_mesh_release_sock(struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct sock *sk, *tmpsk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ int i; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* First, detect modifications or additions */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct in_addr ifa = mptcp_local->locaddr4[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (inet_sk(sk)->inet_saddr != ifa.s_addr) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr4[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr4[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto removal; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct in6_addr ifa = mptcp_local->locaddr6[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (!ipv6_addr_equal(&inet6_sk(sk)->saddr, &ifa)) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr6[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr6[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++removal: ++#endif ++ ++ /* Now, detect address-removals */ ++ mptcp_for_each_sk_safe(mpcb, sk, tmpsk) { ++ bool shall_remove = true; ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ if (inet_sk(sk)->inet_saddr == mptcp_local->locaddr4[i].addr.s_addr) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } else { ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ if (ipv6_addr_equal(&inet6_sk(sk)->saddr, &mptcp_local->locaddr6[i].addr)) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } ++ ++ if (shall_remove) { ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, ++ meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ } ++ } ++ ++ /* Just call it optimistically. It actually cannot do any harm */ ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ rcu_read_unlock_bh(); ++} ++ ++static int full_mesh_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int index, id = -1; ++ ++ /* Handle the backup-flows */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ index = mptcp_find_address(mptcp_local, family, addr, 0); ++ ++ if (index != -1) { ++ if (family == AF_INET) { ++ id = mptcp_local->locaddr4[index].loc4_id; ++ *low_prio = mptcp_local->locaddr4[index].low_prio; ++ } else { ++ id = mptcp_local->locaddr6[index].loc6_id; ++ *low_prio = mptcp_local->locaddr6[index].low_prio; ++ } ++ } ++ ++ ++ rcu_read_unlock_bh(); ++ ++ return id; ++} ++ ++static void full_mesh_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ int remove_addr_len; ++ u8 unannouncedv4 = 0, unannouncedv6 = 0; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ mpcb->addr_signal = 0; ++ ++ if (likely(!fmp->add_addr)) ++ goto remove_addr; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* IPv4 */ ++ unannouncedv4 = (~fmp->announced_addrs_v4) & mptcp_local->loc4_bits; ++ if (unannouncedv4 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv4); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = mptcp_local->locaddr4[ind].loc4_id; ++ opts->add_addr4.addr = mptcp_local->locaddr4[ind].addr; ++ opts->add_addr_v4 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, ++ 4, (u8 *)&opts->add_addr4.addr.s_addr); ++ opts->add_addr4.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v4 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++ ++ goto skip_ipv6; ++ } ++ ++ if (meta_v4) ++ goto skip_ipv6; ++skip_ipv4: ++ /* IPv6 */ ++ unannouncedv6 = (~fmp->announced_addrs_v6) & mptcp_local->loc6_bits; ++ if (unannouncedv6 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv6); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = mptcp_local->locaddr6[ind].loc6_id; ++ opts->add_addr6.addr = mptcp_local->locaddr6[ind].addr; ++ opts->add_addr_v6 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, ++ 16, (u8 *)&opts->add_addr6.addr.s6_addr); ++ opts->add_addr6.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v6 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++ } ++ ++skip_ipv6: ++ rcu_read_unlock_bh(); ++ ++ if (!unannouncedv4 && !unannouncedv6 && skb) ++ fmp->add_addr--; ++ ++remove_addr: ++ if (likely(!fmp->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(fmp->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = fmp->remove_addrs; ++ *size += remove_addr_len; ++ if (skb) ++ fmp->remove_addrs = 0; ++ ++exit: ++ mpcb->addr_signal = !!(fmp->add_addr || fmp->remove_addrs); ++} ++ ++static void full_mesh_rem_raddr(struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ mptcp_v4_rem_raddress(mpcb, rem_id); ++ mptcp_v6_rem_raddress(mpcb, rem_id); ++} ++ ++static void full_mesh_delete_subflow(struct sock *sk) ++{ ++ struct fullmesh_priv *fmp = fullmesh_get_priv(tcp_sk(sk)->mpcb); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ struct mptcp_loc_addr *mptcp_local; ++ int index, i; ++ ++ if (!create_on_err) ++ return; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ union inet_addr saddr; ++ ++ saddr.ip = inet_sk(sk)->inet_saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem4 = &fmp->remaddr4[i]; ++ ++ if (rem4->addr.s_addr != sk->sk_daddr) ++ continue; ++ ++ if (rem4->port && rem4->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem4->bitfield &= ~(1 << index); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ union inet_addr saddr; ++ ++ saddr.in6 = inet6_sk(sk)->saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET6, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem6 = &fmp->remaddr6[i]; ++ ++ if (!ipv6_addr_equal(&rem6->addr, &sk->sk_v6_daddr)) ++ continue; ++ ++ if (rem6->port && rem6->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem6->bitfield &= ~(1 << index); ++ } ++#endif ++ } ++ ++out: ++ rcu_read_unlock_bh(); ++} ++ ++/* Output /proc/net/mptcp_fullmesh */ ++static int mptcp_fm_seq_show(struct seq_file *seq, void *v) ++{ ++ const struct net *net = seq->private; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int i; ++ ++ seq_printf(seq, "Index, Address-ID, Backup, IP-address, if-idx\n"); ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ seq_printf(seq, "IPv4, next v4-index: %u\n", mptcp_local->next_v4_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct mptcp_loc4 *loc4 = &mptcp_local->locaddr4[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI4 %u\n", i, loc4->loc4_id, ++ loc4->low_prio, &loc4->addr, loc4->if_idx); ++ } ++ ++ seq_printf(seq, "IPv6, next v6-index: %u\n", mptcp_local->next_v6_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct mptcp_loc6 *loc6 = &mptcp_local->locaddr6[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI6 %u\n", i, loc6->loc6_id, ++ loc6->low_prio, &loc6->addr, loc6->if_idx); ++ } ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static int mptcp_fm_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_fm_seq_show); ++} ++ ++static const struct file_operations mptcp_fm_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_fm_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_fm_init_net(struct net *net) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns; ++ int err = 0; ++ ++ fm_ns = kzalloc(sizeof(*fm_ns), GFP_KERNEL); ++ if (!fm_ns) ++ return -ENOBUFS; ++ ++ mptcp_local = kzalloc(sizeof(*mptcp_local), GFP_KERNEL); ++ if (!mptcp_local) { ++ err = -ENOBUFS; ++ goto err_mptcp_local; ++ } ++ ++ if (!proc_create("mptcp_fullmesh", S_IRUGO, net->proc_net, ++ &mptcp_fm_seq_fops)) { ++ err = -ENOMEM; ++ goto err_seq_fops; ++ } ++ ++ mptcp_local->next_v4_index = 1; ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ INIT_DELAYED_WORK(&fm_ns->address_worker, mptcp_address_worker); ++ INIT_LIST_HEAD(&fm_ns->events); ++ spin_lock_init(&fm_ns->local_lock); ++ fm_ns->net = net; ++ net->mptcp.path_managers[MPTCP_PM_FULLMESH] = fm_ns; ++ ++ return 0; ++err_seq_fops: ++ kfree(mptcp_local); ++err_mptcp_local: ++ kfree(fm_ns); ++ return err; ++} ++ ++static void mptcp_fm_exit_net(struct net *net) ++{ ++ struct mptcp_addr_event *eventq, *tmp; ++ struct mptcp_fm_ns *fm_ns; ++ struct mptcp_loc_addr *mptcp_local; ++ ++ fm_ns = fm_get_ns(net); ++ cancel_delayed_work_sync(&fm_ns->address_worker); ++ ++ rcu_read_lock_bh(); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ kfree_rcu(mptcp_local, rcu); ++ ++ spin_lock(&fm_ns->local_lock); ++ list_for_each_entry_safe(eventq, tmp, &fm_ns->events, list) { ++ list_del(&eventq->list); ++ kfree(eventq); ++ } ++ spin_unlock(&fm_ns->local_lock); ++ ++ rcu_read_unlock_bh(); ++ ++ remove_proc_entry("mptcp_fullmesh", net->proc_net); ++ ++ kfree(fm_ns); ++} ++ ++static struct pernet_operations full_mesh_net_ops = { ++ .init = mptcp_fm_init_net, ++ .exit = mptcp_fm_exit_net, ++}; ++ ++static struct mptcp_pm_ops full_mesh __read_mostly = { ++ .new_session = full_mesh_new_session, ++ .release_sock = full_mesh_release_sock, ++ .fully_established = full_mesh_create_subflows, ++ .new_remote_address = full_mesh_create_subflows, ++ .subflow_error = full_mesh_subflow_error, ++ .get_local_id = full_mesh_get_local_id, ++ .addr_signal = full_mesh_addr_signal, ++ .add_raddr = full_mesh_add_raddr, ++ .rem_raddr = full_mesh_rem_raddr, ++ .delete_subflow = full_mesh_delete_subflow, ++ .name = "fullmesh", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init full_mesh_register(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct fullmesh_priv) > MPTCP_PM_SIZE); ++ ++ ret = register_pernet_subsys(&full_mesh_net_ops); ++ if (ret) ++ goto out; ++ ++ ret = register_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ if (ret) ++ goto err_reg_inetaddr; ++ ret = register_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ if (ret) ++ goto err_reg_netdev; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ret = register_inet6addr_notifier(&inet6_addr_notifier); ++ if (ret) ++ goto err_reg_inet6addr; ++#endif ++ ++ ret = mptcp_register_path_manager(&full_mesh); ++ if (ret) ++ goto err_reg_pm; ++ ++out: ++ return ret; ++ ++ ++err_reg_pm: ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++err_reg_inet6addr: ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++err_reg_netdev: ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++err_reg_inetaddr: ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ goto out; ++} ++ ++static void full_mesh_unregister(void) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ mptcp_unregister_path_manager(&full_mesh); ++} ++ ++module_init(full_mesh_register); ++module_exit(full_mesh_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Full-Mesh MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_input.c mptcp-mptcp_v0.94/net/mptcp/mptcp_input.c +--- linux-4.14.174/net/mptcp/mptcp_input.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_input.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,2475 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++/* is seq1 < seq2 ? */ ++static inline bool before64(const u64 seq1, const u64 seq2) ++{ ++ return (s64)(seq1 - seq2) < 0; ++} ++ ++/* is seq1 > seq2 ? */ ++#define after64(seq1, seq2) before64(seq2, seq1) ++ ++static inline void mptcp_become_fully_estab(struct sock *sk) ++{ ++ tcp_sk(sk)->mptcp->fully_established = 1; ++ ++ if (is_master_tp(tcp_sk(sk)) && ++ tcp_sk(sk)->mpcb->pm_ops->fully_established) ++ tcp_sk(sk)->mpcb->pm_ops->fully_established(mptcp_meta_sk(sk)); ++} ++ ++/* Similar to tcp_tso_acked without any memory accounting */ ++static inline int mptcp_tso_acked_reinject(const struct sock *meta_sk, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 packets_acked, len, delta_truesize; ++ ++ BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)); ++ ++ packets_acked = tcp_skb_pcount(skb); ++ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ return 0; ++ ++ len = meta_tp->snd_una - TCP_SKB_CB(skb)->seq; ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq += len; ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ ++ if (delta_truesize) ++ skb->truesize -= delta_truesize; ++ ++ /* Any change of skb->len requires recalculation of tso factor. */ ++ if (tcp_skb_pcount(skb) > 1) ++ tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); ++ packets_acked -= tcp_skb_pcount(skb); ++ ++ if (packets_acked) { ++ BUG_ON(tcp_skb_pcount(skb) == 0); ++ BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); ++ } ++ ++ return packets_acked; ++} ++ ++/** ++ * Cleans the meta-socket retransmission queue and the reinject-queue. ++ * @sk must be the metasocket. ++ */ ++static void mptcp_clean_rtx_queue(struct sock *meta_sk, u32 prior_snd_una) ++{ ++ struct sk_buff *skb, *tmp; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ bool acked = false; ++ u32 acked_pcount; ++ ++ while ((skb = tcp_write_queue_head(meta_sk)) && ++ skb != tcp_send_head(meta_sk)) { ++ bool fully_acked = true; ++ ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ acked_pcount = tcp_tso_acked(meta_sk, skb); ++ if (!acked_pcount) ++ break; ++ ++ fully_acked = false; ++ } else { ++ acked_pcount = tcp_skb_pcount(skb); ++ } ++ ++ acked = true; ++ meta_tp->packets_out -= acked_pcount; ++ meta_tp->retrans_stamp = 0; ++ ++ if (!fully_acked) ++ break; ++ ++ tcp_unlink_write_queue(skb, meta_sk); ++ ++ if (mptcp_is_data_fin(skb)) { ++ struct sock *sk_it, *sk_tmp; ++ ++ /* DATA_FIN has been acknowledged - now we can close ++ * the subflows ++ */ ++ mptcp_for_each_sk_safe(mpcb, sk_it, sk_tmp) { ++ unsigned long delay = 0; ++ ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer - thus we add a delay. ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ sk_wmem_free_skb(meta_sk, skb); ++ } ++ /* Remove acknowledged data from the reinject queue */ ++ skb_queue_walk_safe(&mpcb->reinject_queue, skb, tmp) { ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ mptcp_tso_acked_reinject(meta_sk, skb); ++ break; ++ } ++ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ } ++ ++ if (likely(between(meta_tp->snd_up, prior_snd_una, meta_tp->snd_una))) ++ meta_tp->snd_up = meta_tp->snd_una; ++ ++ if (acked) { ++ tcp_rearm_rto(meta_sk); ++ /* Normally this is done in tcp_try_undo_loss - but MPTCP ++ * does not call this function. ++ */ ++ inet_csk(meta_sk)->icsk_retransmits = 0; ++ } ++} ++ ++/* Inspired by tcp_rcv_state_process */ ++static int mptcp_rcv_state_process(struct sock *meta_sk, struct sock *sk, ++ const struct sk_buff *skb, u32 data_seq, ++ u16 data_len) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ const struct tcphdr *th = tcp_hdr(skb); ++ ++ /* State-machine handling if FIN has been enqueued and he has ++ * been acked (snd_una == write_seq) - it's important that this ++ * here is after sk_wmem_free_skb because otherwise ++ * sk_forward_alloc is wrong upon inet_csk_destroy_sock() ++ */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: { ++ struct dst_entry *dst; ++ int tmo; ++ ++ if (meta_tp->snd_una != meta_tp->write_seq) ++ break; ++ ++ tcp_set_state(meta_sk, TCP_FIN_WAIT2); ++ meta_sk->sk_shutdown |= SEND_SHUTDOWN; ++ ++ dst = __sk_dst_get(sk); ++ if (dst) ++ dst_confirm(dst); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Wake up lingering close() */ ++ meta_sk->sk_state_change(meta_sk); ++ break; ++ } ++ ++ if (meta_tp->linger2 < 0 || ++ (data_len && ++ after(data_seq + data_len - (mptcp_is_data_fin2(skb, tp) ? 1 : 0), ++ meta_tp->rcv_nxt))) { ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_done(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ return 1; ++ } ++ ++ tmo = tcp_fin_time(meta_sk); ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, tmo - TCP_TIMEWAIT_LEN); ++ } else if (mptcp_is_data_fin2(skb, tp) || sock_owned_by_user(meta_sk)) { ++ /* Bad case. We could lose such FIN otherwise. ++ * It is not a big problem, but it looks confusing ++ * and not so rare event. We still can lose it now, ++ * if it spins in bh_lock_sock(), but it is really ++ * marginal case. ++ */ ++ inet_csk_reset_keepalive_timer(meta_sk, tmo); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, tmo); ++ } ++ break; ++ } ++ case TCP_CLOSING: ++ case TCP_LAST_ACK: ++ if (meta_tp->snd_una == meta_tp->write_seq) { ++ tcp_done(meta_sk); ++ return 1; ++ } ++ break; ++ } ++ ++ /* step 7: process the segment text */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: ++ case TCP_FIN_WAIT2: ++ /* RFC 793 says to queue data in these states, ++ * RFC 1122 says we MUST send a reset. ++ * BSD 4.4 also does reset. ++ */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN) { ++ if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp_is_data_fin2(skb, tp)) { ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_reset(meta_sk); ++ return 1; ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/** ++ * @return: ++ * i) 1: Everything's fine. ++ * ii) -1: A reset has been sent on the subflow - csum-failure ++ * iii) 0: csum-failure but no reset sent, because it's the last subflow. ++ * Last packet should not be destroyed by the caller because it has ++ * been done here. ++ */ ++static int mptcp_verif_dss_csum(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1, *last = NULL; ++ __wsum csum_tcp = 0; /* cumulative checksum of pld + mptcp-header */ ++ int ans = 1, overflowed = 0, offset = 0, dss_csum_added = 0; ++ int iter = 0; ++ u32 next_seq, offset_seq; ++ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp, tmp1) { ++ unsigned int csum_len; ++ ++ /* init next seq in first round */ ++ if (!iter) ++ next_seq = TCP_SKB_CB(tmp)->seq; ++ offset_seq = next_seq - TCP_SKB_CB(tmp)->seq; ++ ++ if (before(tp->mptcp->map_subseq + tp->mptcp->map_data_len, TCP_SKB_CB(tmp)->end_seq)) ++ /* Mapping ends in the middle of the packet - ++ * csum only these bytes ++ */ ++ csum_len = tp->mptcp->map_subseq + tp->mptcp->map_data_len - TCP_SKB_CB(tmp)->seq; ++ else ++ csum_len = tmp->len; ++ ++ csum_len -= offset_seq; ++ offset = 0; ++ if (overflowed) { ++ char first_word[4]; ++ first_word[0] = 0; ++ first_word[1] = 0; ++ first_word[2] = 0; ++ first_word[3] = *(tmp->data + offset_seq); ++ csum_tcp = csum_partial(first_word, 4, csum_tcp); ++ offset = 1; ++ csum_len--; ++ overflowed = 0; ++ } ++ ++ csum_tcp = skb_checksum(tmp, offset + offset_seq, csum_len, ++ csum_tcp); ++ ++ /* Was it on an odd-length? Then we have to merge the next byte ++ * correctly (see above) ++ */ ++ if (csum_len != (csum_len & (~1))) ++ overflowed = 1; ++ ++ if (mptcp_is_data_seq(tmp) && !dss_csum_added) { ++ __be32 data_seq = htonl((u32)(tp->mptcp->map_data_seq >> 32)); ++ ++ /* If a 64-bit dss is present, we increase the offset ++ * by 4 bytes, as the high-order 64-bits will be added ++ * in the final csum_partial-call. ++ */ ++ u32 offset = skb_transport_offset(tmp) + ++ TCP_SKB_CB(tmp)->dss_off; ++ if (TCP_SKB_CB(tmp)->mptcp_flags & MPTCPHDR_SEQ64_SET) ++ offset += 4; ++ ++ csum_tcp = skb_checksum(tmp, offset, ++ MPTCP_SUB_LEN_SEQ_CSUM, ++ csum_tcp); ++ ++ csum_tcp = csum_partial(&data_seq, ++ sizeof(data_seq), csum_tcp); ++ ++ dss_csum_added = 1; /* Just do it once */ ++ } ++ last = tmp; ++ iter++; ++ ++ if (!skb_queue_is_last(&sk->sk_receive_queue, tmp) && ++ !before(TCP_SKB_CB(tmp1)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ next_seq = TCP_SKB_CB(tmp)->end_seq; ++ } ++ ++ /* Now, checksum must be 0 */ ++ if (unlikely(csum_fold(csum_tcp))) { ++ pr_err("%s csum is wrong: %#x data_seq %u dss_csum_added %d overflowed %d iterations %d\n", ++ __func__, csum_fold(csum_tcp), TCP_SKB_CB(last)->seq, ++ dss_csum_added, overflowed, iter); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMFAIL); ++ tp->mptcp->send_mp_fail = 1; ++ ++ /* map_data_seq is the data-seq number of the ++ * mapping we are currently checking ++ */ ++ tp->mpcb->csum_cutoff_seq = tp->mptcp->map_data_seq; ++ ++ if (tp->mpcb->cnt_subflows > 1) { ++ mptcp_send_reset(sk); ++ ans = -1; ++ } else { ++ tp->mpcb->send_infinite_mapping = 1; ++ ++ /* Need to purge the rcv-queue as it's no more valid */ ++ while ((tmp = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { ++ tp->copied_seq = TCP_SKB_CB(tmp)->end_seq; ++ kfree_skb(tmp); ++ } ++ ++ ans = 0; ++ } ++ } ++ ++ return ans; ++} ++ ++static inline void mptcp_prepare_skb(struct sk_buff *skb, ++ const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 inc = 0, end_seq = tcb->end_seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ end_seq--; ++ /* If skb is the end of this mapping (end is always at mapping-boundary ++ * thanks to the splitting/trimming), then we need to increase ++ * data-end-seq by 1 if this here is a data-fin. ++ * ++ * We need to do -1 because end_seq includes the subflow-FIN. ++ */ ++ if (tp->mptcp->map_data_fin && ++ end_seq == tp->mptcp->map_subseq + tp->mptcp->map_data_len) { ++ inc = 1; ++ ++ /* We manually set the fin-flag if it is a data-fin. For easy ++ * processing in tcp_recvmsg. ++ */ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } else { ++ /* We may have a subflow-fin with data but without data-fin */ ++ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_FIN; ++ } ++ ++ /* Adapt data-seq's to the packet itself. We kinda transform the ++ * dss-mapping to a per-packet granularity. This is necessary to ++ * correctly handle overlapping mappings coming from different ++ * subflows. Otherwise it would be a complete mess. ++ */ ++ tcb->seq = ((u32)tp->mptcp->map_data_seq) + tcb->seq - tp->mptcp->map_subseq; ++ tcb->end_seq = tcb->seq + skb->len + inc; ++} ++ ++static inline void mptcp_reset_mapping(struct tcp_sock *tp, u32 old_copied_seq) ++{ ++ tp->mptcp->map_data_len = 0; ++ tp->mptcp->map_data_seq = 0; ++ tp->mptcp->map_subseq = 0; ++ tp->mptcp->map_data_fin = 0; ++ tp->mptcp->mapping_present = 0; ++ ++ /* In infinite mapping receiver mode, we have to advance the implied ++ * data-sequence number when we progress the subflow's data. ++ */ ++ if (tp->mpcb->infinite_mapping_rcv) ++ tp->mpcb->infinite_rcv_seq += (tp->copied_seq - old_copied_seq); ++} ++ ++/* The DSS-mapping received on the sk only covers the second half of the skb ++ * (cut at seq). We trim the head from the skb. ++ * Data will be freed upon kfree(). ++ * ++ * Inspired by tcp_trim_head(). ++ */ ++static void mptcp_skb_trim_head(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ int len = seq - TCP_SKB_CB(skb)->seq; ++ u32 new_seq = TCP_SKB_CB(skb)->seq + len; ++ u32 delta_truesize; ++ ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq = new_seq; ++ ++ if (delta_truesize) { ++ skb->truesize -= delta_truesize; ++ atomic_sub(delta_truesize, &sk->sk_rmem_alloc); ++ sk_mem_uncharge(sk, delta_truesize); ++ } ++} ++ ++/* The DSS-mapping received on the sk only covers the first half of the skb ++ * (cut at seq). We create a second skb (@return), and queue it in the rcv-queue ++ * as further packets may resolve the mapping of the second half of data. ++ * ++ * Inspired by tcp_fragment(). ++ */ ++static int mptcp_skb_split_tail(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ struct sk_buff *buff; ++ int nsize; ++ int nlen, len; ++ u8 flags; ++ ++ len = seq - TCP_SKB_CB(skb)->seq; ++ nsize = skb_headlen(skb) - len + tcp_sk(sk)->tcp_header_len; ++ if (nsize < 0) ++ nsize = 0; ++ ++ /* Get a new skb... force flag on. */ ++ buff = alloc_skb(nsize, GFP_ATOMIC); ++ if (buff == NULL) ++ return -ENOMEM; ++ ++ skb_reserve(buff, tcp_sk(sk)->tcp_header_len); ++ skb_reset_transport_header(buff); ++ ++ flags = TCP_SKB_CB(skb)->tcp_flags; ++ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN); ++ TCP_SKB_CB(buff)->tcp_flags = flags; ++ ++ /* We absolutly need to call skb_set_owner_r before refreshing the ++ * truesize of buff, otherwise the moved data will account twice. ++ */ ++ skb_set_owner_r(buff, sk); ++ nlen = skb->len - len - nsize; ++ buff->truesize += nlen; ++ skb->truesize -= nlen; ++ ++ /* Correct the sequence numbers. */ ++ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; ++ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; ++ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; ++ ++ skb_split(skb, buff, len); ++ ++ __skb_queue_after(&sk->sk_receive_queue, skb, buff); ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_prevalidate_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If we are in infinite mode, the subflow-fin is in fact a data-fin. */ ++ if (!skb->len && (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ !mptcp_is_data_fin(skb) && !mpcb->infinite_mapping_rcv) { ++ /* Remove a pure subflow-fin from the queue and increase ++ * copied_seq. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* If we are not yet fully established and do not know the mapping for ++ * this segment, this path has to fallback to infinite or be torn down. ++ */ ++ if (!tp->mptcp->fully_established && !mptcp_is_data_seq(skb) && ++ !tp->mptcp->mapping_present && !mpcb->infinite_mapping_rcv) { ++ pr_err("%s %#x will fallback - pi %d from %pS, seq %u\n", ++ __func__, mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, __builtin_return_address(0), ++ TCP_SKB_CB(skb)->seq); ++ ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATASUB); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATAINIT); ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ /* We do a seamless fallback and should not send a inf.mapping. */ ++ mpcb->send_infinite_mapping = 0; ++ tp->mptcp->fully_established = 1; ++ } ++ ++ /* Receiver-side becomes fully established when a whole rcv-window has ++ * been received without the need to fallback due to the previous ++ * condition. ++ */ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->init_rcv_wnd -= skb->len; ++ if (tp->mptcp->init_rcv_wnd < 0) ++ mptcp_become_fully_estab(sk); ++ } ++ ++ return 0; ++} ++ ++static void mptcp_restart_sending(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* We resend everything that has not been acknowledged */ ++ meta_sk->sk_send_head = tcp_write_queue_head(meta_sk); ++ ++ /* We artificially restart the whole send-queue. Thus, ++ * it is as if no packets are in flight ++ */ ++ meta_tp->packets_out = 0; ++ ++ /* If the snd_nxt already wrapped around, we have to ++ * undo the wrapping, as we are restarting from snd_una ++ * on. ++ */ ++ if (meta_tp->snd_nxt < meta_tp->snd_una) { ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] -= 2; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ } ++ meta_tp->snd_nxt = meta_tp->snd_una; ++ ++ /* Trigger a sending on the meta. */ ++ mptcp_push_pending_frames(meta_sk); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_detect_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 *ptr; ++ u32 data_seq, sub_seq, data_len, tcp_end_seq; ++ bool set_infinite_rcv = false; ++ ++ /* If we are in infinite-mapping-mode, the subflow is guaranteed to be ++ * in-order at the data-level. Thus data-seq-numbers can be inferred ++ * from what is expected at the data-level. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ /* copied_seq may be bigger than tcb->seq (e.g., when the peer ++ * retransmits data that actually has already been acknowledged with ++ * newer data, if he did not receive our acks). Thus, we need ++ * to account for this overlap as well. ++ */ ++ tp->mptcp->map_data_seq = mpcb->infinite_rcv_seq - (tp->copied_seq - tcb->seq); ++ tp->mptcp->map_subseq = tcb->seq; ++ tp->mptcp->map_data_len = skb->len; ++ tp->mptcp->map_data_fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN); ++ tp->mptcp->mapping_present = 1; ++ return 0; ++ } ++ ++ /* No mapping here? Exit - it is either already set or still on its way */ ++ if (!mptcp_is_data_seq(skb)) { ++ /* Too many packets without a mapping - this subflow is broken */ ++ if (!tp->mptcp->mapping_present && ++ tp->rcv_nxt - tp->copied_seq > 65536) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_NODSSWINDOW); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ return 0; ++ } ++ ++ ptr = mptcp_skb_set_data_seq(skb, &data_seq, mpcb); ++ ptr++; ++ sub_seq = get_unaligned_be32(ptr) + tp->mptcp->rcv_isn; ++ ptr++; ++ data_len = get_unaligned_be16(ptr); ++ ++ /* If it's an empty skb with DATA_FIN, sub_seq must get fixed. ++ * The draft sets it to 0, but we really would like to have the ++ * real value, to have an easy handling afterwards here in this ++ * function. ++ */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ sub_seq = TCP_SKB_CB(skb)->seq; ++ ++ /* If there is already a mapping - we check if it maps with the current ++ * one. If not - we reset. ++ */ ++ if (tp->mptcp->mapping_present && ++ (data_seq != (u32)tp->mptcp->map_data_seq || ++ sub_seq != tp->mptcp->map_subseq || ++ data_len != tp->mptcp->map_data_len + tp->mptcp->map_data_fin || ++ mptcp_is_data_fin(skb) != tp->mptcp->map_data_fin)) { ++ /* Mapping in packet is different from what we want */ ++ pr_err("%s Mappings do not match!\n", __func__); ++ pr_err("%s dseq %u mdseq %u, sseq %u msseq %u dlen %u mdlen %u dfin %d mdfin %d\n", ++ __func__, data_seq, (u32)tp->mptcp->map_data_seq, ++ sub_seq, tp->mptcp->map_subseq, data_len, ++ tp->mptcp->map_data_len, mptcp_is_data_fin(skb), ++ tp->mptcp->map_data_fin); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSNOMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* If the previous check was good, the current mapping is valid and we exit. */ ++ if (tp->mptcp->mapping_present) ++ return 0; ++ ++ /* Mapping not yet set on this subflow - we set it here! */ ++ ++ if (!data_len) { ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->send_infinite_mapping = 1; ++ tp->mptcp->fully_established = 1; ++ /* We need to repeat mp_fail's until the sender felt ++ * back to infinite-mapping - here we stop repeating it. ++ */ ++ tp->mptcp->send_mp_fail = 0; ++ ++ /* We have to fixup data_len - it must be the same as skb->len */ ++ data_len = skb->len + (mptcp_is_data_fin(skb) ? 1 : 0); ++ sub_seq = tcb->seq; ++ ++ mptcp_restart_sending(tp->meta_sk); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ /* data_seq and so on are set correctly */ ++ ++ /* At this point, the meta-ofo-queue has to be emptied, ++ * as the following data is guaranteed to be in-order at ++ * the data and subflow-level ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ ++ set_infinite_rcv = true; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_INFINITEMAPRX); ++ } ++ ++ /* We are sending mp-fail's and thus are in fallback mode. ++ * Ignore packets which do not announce the fallback and still ++ * want to provide a mapping. ++ */ ++ if (tp->mptcp->send_mp_fail) { ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* FIN increased the mapping-length by 1 */ ++ if (mptcp_is_data_fin(skb)) ++ data_len--; ++ ++ /* Subflow-sequences of packet must be ++ * (at least partially) be part of the DSS-mapping's ++ * subflow-sequence-space. ++ * ++ * Basically the mapping is not valid, if either of the ++ * following conditions is true: ++ * ++ * 1. It's not a data_fin and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * 2. It's a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * The previous two can be merged into: ++ * TCP-end_seq > TCP-seq and MPTCP-sub_seq >= TCP-end_seq ++ * Because if it's not a data-fin, TCP-end_seq > TCP-seq ++ * ++ * 3. It's a data_fin and skb->len == 0 and ++ * MPTCP-sub_seq > TCP-end_seq ++ * ++ * 4. It's not a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq + MPTCP-data_len <= TCP-seq ++ */ ++ ++ /* subflow-fin is not part of the mapping - ignore it here ! */ ++ tcp_end_seq = tcb->end_seq; ++ if (tcb->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if ((!before(sub_seq, tcb->end_seq) && after(tcp_end_seq, tcb->seq)) || ++ (mptcp_is_data_fin(skb) && skb->len == 0 && after(sub_seq, tcb->end_seq)) || ++ (!after(sub_seq + data_len, tcb->seq) && after(tcp_end_seq, tcb->seq))) { ++ /* Subflow-sequences of packet is different from what is in the ++ * packet's dss-mapping. The peer is misbehaving - reset ++ */ ++ pr_err("%s Packet's mapping does not map to the DSS sub_seq %u " ++ "end_seq %u, tcp_end_seq %u seq %u dfin %u len %u data_len %u" ++ "copied_seq %u\n", __func__, sub_seq, tcb->end_seq, tcp_end_seq, tcb->seq, mptcp_is_data_fin(skb), ++ skb->len, data_len, tp->copied_seq); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTCPMISMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* Does the DSS had 64-bit seqnum's ? */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_SEQ64_SET)) { ++ /* Wrapped around? */ ++ if (unlikely(after(data_seq, meta_tp->rcv_nxt) && data_seq < meta_tp->rcv_nxt)) { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, !mpcb->rcv_hiseq_index, data_seq); ++ } else { ++ /* Else, access the default high-order bits */ ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, data_seq); ++ } ++ } else { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, (tcb->mptcp_flags & MPTCPHDR_SEQ64_INDEX) ? 1 : 0, data_seq); ++ ++ if (unlikely(tcb->mptcp_flags & MPTCPHDR_SEQ64_OFO)) { ++ /* We make sure that the data_seq is invalid. ++ * It will be dropped later. ++ */ ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ } ++ } ++ ++ if (set_infinite_rcv) ++ mpcb->infinite_rcv_seq = tp->mptcp->map_data_seq; ++ ++ tp->mptcp->map_data_len = data_len; ++ tp->mptcp->map_subseq = sub_seq; ++ tp->mptcp->map_data_fin = mptcp_is_data_fin(skb) ? 1 : 0; ++ tp->mptcp->mapping_present = 1; ++ ++ return 0; ++} ++ ++/* Similar to tcp_sequence(...) */ ++static inline bool mptcp_sequence(const struct tcp_sock *meta_tp, ++ u64 data_seq, u64 end_data_seq) ++{ ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u64 rcv_wup64; ++ ++ /* Wrap-around? */ ++ if (meta_tp->rcv_wup > meta_tp->rcv_nxt) { ++ rcv_wup64 = ((u64)(mpcb->rcv_high_order[mpcb->rcv_hiseq_index] - 1) << 32) | ++ meta_tp->rcv_wup; ++ } else { ++ rcv_wup64 = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_wup); ++ } ++ ++ return !before64(end_data_seq, rcv_wup64) && ++ !after64(data_seq, mptcp_get_rcv_nxt_64(meta_tp) + tcp_receive_window(meta_tp)); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_validate_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1; ++ u32 tcp_end_seq; ++ ++ if (!tp->mptcp->mapping_present) ++ return 0; ++ ++ /* either, the new skb gave us the mapping and the first segment ++ * in the sub-rcv-queue has to be trimmed ... ++ */ ++ tmp = skb_peek(&sk->sk_receive_queue); ++ if (before(TCP_SKB_CB(tmp)->seq, tp->mptcp->map_subseq) && ++ after(TCP_SKB_CB(tmp)->end_seq, tp->mptcp->map_subseq)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTRIMHEAD); ++ mptcp_skb_trim_head(tmp, sk, tp->mptcp->map_subseq); ++ } ++ ++ /* ... or the new skb (tail) has to be split at the end. */ ++ tcp_end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if (after(tcp_end_seq, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) { ++ u32 seq = tp->mptcp->map_subseq + tp->mptcp->map_data_len; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSSPLITTAIL); ++ if (mptcp_skb_split_tail(skb, sk, seq)) { /* Allocation failed */ ++ /* TODO : maybe handle this here better. ++ * We now just force meta-retransmission. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ } ++ ++ /* Now, remove old sk_buff's from the receive-queue. ++ * This may happen if the mapping has been lost for these segments and ++ * the next mapping has already been received. ++ */ ++ if (before(TCP_SKB_CB(skb_peek(&sk->sk_receive_queue))->seq, tp->mptcp->map_subseq)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ if (!before(TCP_SKB_CB(tmp1)->seq, tp->mptcp->map_subseq)) ++ break; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PURGEOLD); ++ /* Impossible that we could free skb here, because his ++ * mapping is known to be valid from previous checks ++ */ ++ __kfree_skb(tmp1); ++ } ++ } ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this mapping has been put in the meta-receive-queue ++ * -2 this mapping has been eaten by the application ++ */ ++static int mptcp_queue_skb(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sk_buff *tmp, *tmp1; ++ u64 rcv_nxt64 = mptcp_get_rcv_nxt_64(meta_tp); ++ u32 old_copied_seq = tp->copied_seq; ++ bool data_queued = false; ++ ++ /* Have we not yet received the full mapping? */ ++ if (!tp->mptcp->mapping_present || ++ before(tp->rcv_nxt, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ return 0; ++ ++ /* Is this an overlapping mapping? rcv_nxt >= end_data_seq ++ * OR ++ * This mapping is out of window ++ */ ++ if (!before64(rcv_nxt64, tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin) || ++ !mptcp_sequence(meta_tp, tp->mptcp->map_data_seq, ++ tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return -1; ++ } ++ ++ /* Record it, because we want to send our data_fin on the same path */ ++ if (tp->mptcp->map_data_fin) { ++ mpcb->dfin_path_index = tp->mptcp->path_index; ++ mpcb->dfin_combined = !!(sk->sk_shutdown & RCV_SHUTDOWN); ++ } ++ ++ /* Verify the checksum */ ++ if (mpcb->dss_csum && !mpcb->infinite_mapping_rcv) { ++ int ret = mptcp_verif_dss_csum(sk); ++ ++ if (ret <= 0) { ++ mptcp_reset_mapping(tp, old_copied_seq); ++ return 1; ++ } ++ } ++ ++ if (before64(rcv_nxt64, tp->mptcp->map_data_seq)) { ++ /* Seg's have to go to the meta-ofo-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true later. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ if (!mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ tcp_data_queue_ofo(meta_sk, tmp1); ++ else ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ /* Quick ACK if more 3/4 of the receive window is filled */ ++ if (after64(tp->mptcp->map_data_seq, ++ rcv_nxt64 + 3 * (tcp_receive_window(meta_tp) >> 2))) ++ tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); ++ ++ } else { ++ /* Ready for the meta-rcv-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ int eaten = 0; ++ bool fragstolen = false; ++ u32 old_rcv_nxt = meta_tp->rcv_nxt; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ /* This segment has already been received */ ++ if (!after(TCP_SKB_CB(tmp1)->end_seq, meta_tp->rcv_nxt)) { ++ __kfree_skb(tmp1); ++ goto next; ++ } ++ ++ if (mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ eaten = 1; ++ ++ if (!eaten) ++ eaten = tcp_queue_rcv(meta_sk, tmp1, 0, &fragstolen); ++ ++ meta_tp->rcv_nxt = TCP_SKB_CB(tmp1)->end_seq; ++ ++ if (TCP_SKB_CB(tmp1)->tcp_flags & TCPHDR_FIN) ++ mptcp_fin(meta_sk); ++ ++ /* Check if this fills a gap in the ofo queue */ ++ if (!RB_EMPTY_ROOT(&meta_tp->out_of_order_queue)) ++ tcp_ofo_queue(meta_sk); ++ ++ mptcp_check_rcvseq_wrap(meta_tp, old_rcv_nxt); ++ ++ if (eaten) ++ kfree_skb_partial(tmp1, fragstolen); ++ ++ data_queued = true; ++next: ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ } ++ ++ inet_csk(meta_sk)->icsk_ack.lrcvtime = tcp_jiffies32; ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return data_queued ? -1 : -2; ++} ++ ++void mptcp_data_ready(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb, *tmp; ++ int queued = 0; ++ ++ tcp_mstamp_refresh(tcp_sk(meta_sk)); ++ ++ /* restart before the check, because mptcp_fin might have changed the ++ * state. ++ */ ++restart: ++ /* If the meta cannot receive data, there is no point in pushing data. ++ * If we are in time-wait, we may still be waiting for the final FIN. ++ * So, we should proceed with the processing. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !tcp_sk(sk)->mpcb->in_time_wait) { ++ skb_queue_purge(&sk->sk_receive_queue); ++ tcp_sk(sk)->copied_seq = tcp_sk(sk)->rcv_nxt; ++ goto exit; ++ } ++ ++ /* Iterate over all segments, detect their mapping (if we don't have ++ * one yet), validate them and push everything one level higher. ++ */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { ++ int ret; ++ /* Pre-validation - e.g., early fallback */ ++ ret = mptcp_prevalidate_skb(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Set the current mapping */ ++ ret = mptcp_detect_mapping(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Validation */ ++ if (mptcp_validate_mapping(sk, skb) < 0) ++ goto restart; ++ ++ /* Push a level higher */ ++ ret = mptcp_queue_skb(sk); ++ if (ret < 0) { ++ if (ret == -1) ++ queued = ret; ++ goto restart; ++ } else if (ret == 0) { ++ continue; ++ } else { /* ret == 1 */ ++ break; ++ } ++ } ++ ++exit: ++ if (tcp_sk(sk)->close_it && sk->sk_state == TCP_FIN_WAIT2) { ++ tcp_send_ack(sk); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_TIME_WAIT, 0); ++ } ++ ++ if (queued == -1 && !sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_data_ready(meta_sk); ++} ++ ++struct mp_join *mptcp_find_join(const struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether JOIN is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return NULL; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return NULL; ++ if (opsize > length) ++ return NULL; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)(ptr - 2))->sub == MPTCP_SUB_JOIN) { ++ return (struct mp_join *)(ptr - 2); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return NULL; ++} ++ ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw) ++{ ++ const struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ struct mp_join *join_opt = mptcp_find_join(skb); ++ if (!join_opt) ++ return 0; ++ ++ /* MPTCP structures were not initialized, so return error */ ++ if (mptcp_init_failed) ++ return -1; ++ ++ token = join_opt->u.syn.token; ++ meta_sk = mptcp_hash_find(dev_net(skb_dst(skb)->dev), token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ if (mpcb->infinite_mapping_rcv || mpcb->send_infinite_mapping) { ++ /* We are in fallback-mode on the reception-side - ++ * no new subflows! ++ */ ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINFALLBACK); ++ return -1; ++ } ++ ++ /* Coming from time-wait-sock processing in tcp_v4_rcv. ++ * We have to deschedule it before continuing, because otherwise ++ * mptcp_v4_do_rcv will hit again on it inside tcp_v4_hnd_req. ++ */ ++ if (tw) ++ inet_twsk_deschedule_put(tw); ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ if (unlikely(sk_add_backlog(meta_sk, skb, ++ meta_sk->sk_rcvbuf + meta_sk->sk_sndbuf))) { ++ bh_unlock_sock(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPBACKLOGDROP); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ kfree_skb(skb); ++ return 1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 1; ++} ++ ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ ++ token = mopt->mptcp_rem_token; ++ meta_sk = mptcp_hash_find(net, token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ bh_lock_sock(meta_sk); ++ ++ /* This check is also done in mptcp_vX_do_rcv. But, there we cannot ++ * call tcp_vX_send_reset, because we hold already two socket-locks. ++ * (the listener and the meta from above) ++ * ++ * And the send-reset will try to take yet another one (ip_send_reply). ++ * Thus, we propagate the reset up to tcp_rcv_state_process. ++ */ ++ if (tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv || ++ tcp_sk(meta_sk)->mpcb->send_infinite_mapping || ++ meta_sk->sk_state == TCP_CLOSE || !tcp_sk(meta_sk)->inside_tk_table) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINFALLBACK); ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (unlikely(sk_add_backlog(meta_sk, skb, ++ meta_sk->sk_rcvbuf + meta_sk->sk_sndbuf))) ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ else ++ /* Must make sure that upper layers won't free the ++ * skb if it is added to the backlog-queue. ++ */ ++ skb_get(skb); ++ } else { ++ /* mptcp_v4_do_rcv tries to free the skb - we prevent this, as ++ * the skb will finally be freed by tcp_v4_do_rcv (where we are ++ * coming from) ++ */ ++ skb_get(skb); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { /* IPv6 */ ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ } ++ ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 0; ++} ++ ++/** ++ * Equivalent of tcp_fin() for MPTCP ++ * Can be called only when the FIN is validly part ++ * of the data seqnum space. Not before when we get holes. ++ */ ++void mptcp_fin(struct sock *meta_sk) ++{ ++ struct sock *sk = NULL, *sk_it; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ unsigned char state; ++ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ if (tcp_sk(sk_it)->mptcp->path_index == mpcb->dfin_path_index) { ++ sk = sk_it; ++ break; ++ } ++ } ++ ++ if (!sk || sk->sk_state == TCP_CLOSE) ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ inet_csk_schedule_ack(sk); ++ ++ if (!mpcb->in_time_wait) { ++ meta_sk->sk_shutdown |= RCV_SHUTDOWN; ++ sock_set_flag(meta_sk, SOCK_DONE); ++ state = meta_sk->sk_state; ++ } else { ++ state = mpcb->mptw_state; ++ } ++ ++ switch (state) { ++ case TCP_SYN_RECV: ++ case TCP_ESTABLISHED: ++ /* Move to CLOSE_WAIT */ ++ tcp_set_state(meta_sk, TCP_CLOSE_WAIT); ++ inet_csk(sk)->icsk_ack.pingpong = 1; ++ break; ++ ++ case TCP_CLOSE_WAIT: ++ case TCP_CLOSING: ++ /* Received a retransmission of the FIN, do ++ * nothing. ++ */ ++ break; ++ case TCP_LAST_ACK: ++ /* RFC793: Remain in the LAST-ACK state. */ ++ break; ++ ++ case TCP_FIN_WAIT1: ++ /* This case occurs when a simultaneous close ++ * happens, we must ack the received FIN and ++ * enter the CLOSING state. ++ */ ++ tcp_send_ack(sk); ++ tcp_set_state(meta_sk, TCP_CLOSING); ++ break; ++ case TCP_FIN_WAIT2: ++ /* Received a FIN -- send ACK and enter TIME_WAIT. */ ++ tcp_send_ack(sk); ++ meta_tp->ops->time_wait(meta_sk, TCP_TIME_WAIT, 0); ++ break; ++ default: ++ /* Only TCP_LISTEN and TCP_CLOSE are left, in these ++ * cases we should never reach this piece of code. ++ */ ++ pr_err("%s: Impossible, meta_sk->sk_state=%d\n", __func__, ++ meta_sk->sk_state); ++ break; ++ } ++ ++ /* It _is_ possible, that we have something out-of-order _after_ FIN. ++ * Probably, we should reset in this case. For now drop them. ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ sk_mem_reclaim(meta_sk); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ ++ /* Do not send POLL_HUP for half duplex close. */ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || ++ meta_sk->sk_state == TCP_CLOSE) ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_HUP); ++ else ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_IN); ++ } ++ ++ return; ++} ++ ++static void mptcp_xmit_retransmit_queue(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ ++ if (!meta_tp->packets_out) ++ return; ++ ++ tcp_for_write_queue(skb, meta_sk) { ++ if (skb == tcp_send_head(meta_sk)) ++ break; ++ ++ if (mptcp_retransmit_skb(meta_sk, skb)) ++ return; ++ ++ if (skb == tcp_write_queue_head(meta_sk)) ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ inet_csk(meta_sk)->icsk_rto, ++ TCP_RTO_MAX); ++ } ++} ++ ++static void mptcp_snd_una_update(struct tcp_sock *meta_tp, u32 data_ack) ++{ ++ u32 delta = data_ack - meta_tp->snd_una; ++ ++ sock_owned_by_me((struct sock *)meta_tp); ++ meta_tp->bytes_acked += delta; ++ meta_tp->snd_una = data_ack; ++} ++ ++/* Handle the DATA_ACK */ ++static void mptcp_data_ack(struct sock *sk, const struct sk_buff *skb) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 prior_snd_una = meta_tp->snd_una; ++ int prior_packets; ++ u32 nwin, data_ack, data_seq; ++ u16 data_len = 0; ++ ++ /* A valid packet came in - subflow is operational again */ ++ tp->pf = 0; ++ ++ /* Even if there is no data-ack, we stop retransmitting. ++ * Except if this is a SYN/ACK. Then it is just a retransmission ++ */ ++ if (tp->mptcp->pre_established && !tcp_hdr(skb)->syn) { ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++ ++ /* If we are in infinite mapping mode, rx_opt.data_ack has been ++ * set by mptcp_clean_rtx_infinite. ++ */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_ACK) && !tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ if (unlikely(!tp->mptcp->fully_established) && ++ tp->mptcp->snt_isn + 1 != TCP_SKB_CB(skb)->ack_seq) ++ /* As soon as a subflow-data-ack (not acking syn, thus snt_isn + 1) ++ * includes a data-ack, we are fully established ++ */ ++ mptcp_become_fully_estab(sk); ++ ++ /* After we did the subflow-only processing (stopping timer and marking ++ * subflow as established), check if we can proceed with MPTCP-level ++ * processing. ++ */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ /* Get the data_seq */ ++ if (mptcp_is_data_seq(skb)) { ++ data_seq = tp->mptcp->rx_opt.data_seq; ++ data_len = tp->mptcp->rx_opt.data_len; ++ } else { ++ data_seq = meta_tp->snd_wl1; ++ } ++ ++ data_ack = tp->mptcp->rx_opt.data_ack; ++ ++ /* If the ack is older than previous acks ++ * then we can probably ignore it. ++ */ ++ if (before(data_ack, prior_snd_una)) ++ goto exit; ++ ++ /* If the ack includes data we haven't sent yet, discard ++ * this segment (RFC793 Section 3.9). ++ */ ++ if (after(data_ack, meta_tp->snd_nxt)) ++ goto exit; ++ ++ /*** Now, update the window - inspired by tcp_ack_update_window ***/ ++ nwin = ntohs(tcp_hdr(skb)->window); ++ ++ if (likely(!tcp_hdr(skb)->syn)) ++ nwin <<= tp->rx_opt.snd_wscale; ++ ++ if (tcp_may_update_window(meta_tp, data_ack, data_seq, nwin)) { ++ tcp_update_wl(meta_tp, data_seq); ++ ++ /* Draft v09, Section 3.3.5: ++ * [...] It should only update its local receive window values ++ * when the largest sequence number allowed (i.e. DATA_ACK + ++ * receive window) increases. [...] ++ */ ++ if (meta_tp->snd_wnd != nwin && ++ !before(data_ack + nwin, tcp_wnd_end(meta_tp))) { ++ meta_tp->snd_wnd = nwin; ++ ++ if (nwin > meta_tp->max_window) ++ meta_tp->max_window = nwin; ++ } ++ } ++ /*** Done, update the window ***/ ++ ++ /* We passed data and got it acked, remove any soft error ++ * log. Something worked... ++ */ ++ sk->sk_err_soft = 0; ++ inet_csk(meta_sk)->icsk_probes_out = 0; ++ meta_tp->rcv_tstamp = tcp_jiffies32; ++ prior_packets = meta_tp->packets_out; ++ if (!prior_packets) ++ goto no_queue; ++ ++ mptcp_snd_una_update(meta_tp, data_ack); ++ ++ mptcp_clean_rtx_queue(meta_sk, prior_snd_una); ++ ++ /* We are in loss-state, and something got acked, retransmit the whole ++ * queue now! ++ */ ++ if (inet_csk(meta_sk)->icsk_ca_state == TCP_CA_Loss && ++ after(data_ack, prior_snd_una)) { ++ mptcp_xmit_retransmit_queue(meta_sk); ++ inet_csk(meta_sk)->icsk_ca_state = TCP_CA_Open; ++ } ++ ++ /* Simplified version of tcp_new_space, because the snd-buffer ++ * is handled by all the subflows. ++ */ ++ if (sock_flag(meta_sk, SOCK_QUEUE_SHRUNK)) { ++ sock_reset_flag(meta_sk, SOCK_QUEUE_SHRUNK); ++ if (meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ meta_sk->sk_write_space(meta_sk); ++ } ++ ++ if (meta_sk->sk_state != TCP_ESTABLISHED && ++ mptcp_rcv_state_process(meta_sk, sk, skb, data_seq, data_len)) ++ return; ++ ++exit: ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++ ++no_queue: ++ if (tcp_send_head(meta_sk)) ++ tcp_ack_probe(meta_sk); ++ ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++} ++ ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(mptcp_meta_sk(sk)); ++ ++ if (!tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ /* The difference between both write_seq's represents the offset between ++ * data-sequence and subflow-sequence. As we are infinite, this must ++ * match. ++ * ++ * Thus, from this difference we can infer the meta snd_una. ++ */ ++ tp->mptcp->rx_opt.data_ack = meta_tp->snd_nxt - tp->snd_nxt + ++ tp->snd_una; ++ ++ mptcp_data_ack(sk, skb); ++} ++ ++/**** static functions used by mptcp_parse_options */ ++ ++static void mptcp_send_reset_rem_id(const struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ struct sock *sk_it, *tmpsk; ++ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ if (tcp_sk(sk_it)->mptcp->rem_id == rem_id) { ++ mptcp_reinject_data(sk_it, 0); ++ mptcp_send_reset(sk_it); ++ } ++ } ++} ++ ++static inline bool is_valid_addropt_opsize(u8 mptcp_ver, ++ struct mp_add_addr *mpadd, ++ int opsize) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 6) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 6) ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2; ++#endif ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++ } ++ return false; ++} ++ ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp) ++{ ++ const struct mptcp_option *mp_opt = (struct mptcp_option *)ptr; ++ ++ /* If the socket is mp-capable we would have a mopt. */ ++ if (!mopt) ++ return; ++ ++ switch (mp_opt->sub) { ++ case MPTCP_SUB_CAPABLE: ++ { ++ const struct mp_capable *mpcapable = (struct mp_capable *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_CAPABLE_SYN && ++ opsize != MPTCP_SUB_LEN_CAPABLE_ACK) { ++ mptcp_debug("%s: mp_capable: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "If receiving a message with the 'B' flag set to 1, and this ++ * is not understood, then this SYN MUST be silently ignored; ++ */ ++ if (mpcapable->b) { ++ mopt->drop_me = 1; ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "An implementation that only supports this method MUST set ++ * bit "H" to 1, and bits "C" through "G" to 0." ++ */ ++ if (!mpcapable->h) ++ break; ++ ++ mopt->saw_mpc = 1; ++ mopt->dss_csum = sysctl_mptcp_checksum || mpcapable->a; ++ ++ if (opsize >= MPTCP_SUB_LEN_CAPABLE_SYN) ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ if (opsize == MPTCP_SUB_LEN_CAPABLE_ACK) ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ ++ mopt->mptcp_ver = mpcapable->ver; ++ break; ++ } ++ case MPTCP_SUB_JOIN: ++ { ++ const struct mp_join *mpjoin = (struct mp_join *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_JOIN_SYN && ++ opsize != MPTCP_SUB_LEN_JOIN_SYNACK && ++ opsize != MPTCP_SUB_LEN_JOIN_ACK) { ++ mptcp_debug("%s: mp_join: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* saw_mpc must be set, because in tcp_check_req we assume that ++ * it is set to support falling back to reg. TCP if a rexmitted ++ * SYN has no MP_CAPABLE or MP_JOIN ++ */ ++ switch (opsize) { ++ case MPTCP_SUB_LEN_JOIN_SYN: ++ mopt->is_mp_join = 1; ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_rem_token = mpjoin->u.syn.token; ++ mopt->mptcp_recv_nonce = mpjoin->u.syn.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_SYNACK: ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_recv_tmac = mpjoin->u.synack.mac; ++ mopt->mptcp_recv_nonce = mpjoin->u.synack.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_ACK: ++ mopt->saw_mpc = 1; ++ mopt->join_ack = 1; ++ memcpy(mopt->mptcp_recv_mac, mpjoin->u.ack.mac, 20); ++ break; ++ } ++ break; ++ } ++ case MPTCP_SUB_DSS: ++ { ++ const struct mp_dss *mdss = (struct mp_dss *)ptr; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ ++ /* We check opsize for the csum and non-csum case. We do this, ++ * because the draft says that the csum SHOULD be ignored if ++ * it has not been negotiated in the MP_CAPABLE but still is ++ * present in the data. ++ * ++ * It will get ignored later in mptcp_queue_skb. ++ */ ++ if (opsize != mptcp_sub_len_dss(mdss, 0) && ++ opsize != mptcp_sub_len_dss(mdss, 1)) { ++ mptcp_debug("%s: mp_dss: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ ptr += 4; ++ ++ if (mdss->A) { ++ tcb->mptcp_flags |= MPTCPHDR_ACK; ++ ++ if (mdss->a) { ++ mopt->data_ack = (u32) get_unaligned_be64(ptr); ++ ptr += MPTCP_SUB_LEN_ACK_64; ++ } else { ++ mopt->data_ack = get_unaligned_be32(ptr); ++ ptr += MPTCP_SUB_LEN_ACK; ++ } ++ } ++ ++ tcb->dss_off = (ptr - skb_transport_header(skb)); ++ ++ if (mdss->M) { ++ if (mdss->m) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ64_SET; ++ mopt->data_seq = (u32) data_seq64; ++ ++ ptr += 12; /* 64-bit dseq + subseq */ ++ } else { ++ mopt->data_seq = get_unaligned_be32(ptr); ++ ptr += 8; /* 32-bit dseq + subseq */ ++ } ++ mopt->data_len = get_unaligned_be16(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ /* Is a check-sum present? */ ++ if (opsize == mptcp_sub_len_dss(mdss, 1)) ++ tcb->mptcp_flags |= MPTCPHDR_DSS_CSUM; ++ ++ /* DATA_FIN only possible with DSS-mapping */ ++ if (mdss->F) ++ tcb->mptcp_flags |= MPTCPHDR_FIN; ++ } ++ ++ break; ++ } ++ case MPTCP_SUB_ADD_ADDR: ++ { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ /* If tcp_sock is not available, MPTCP version can't be ++ * retrieved and ADD_ADDR opsize validation is not possible. ++ */ ++ if (!tp || !tp->mpcb) ++ break; ++ ++ if (!is_valid_addropt_opsize(tp->mpcb->mptcp_ver, ++ mpadd, opsize)) { ++ mptcp_debug("%s: mp_add_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* We have to manually parse the options if we got two of them. */ ++ if (mopt->saw_add_addr) { ++ mopt->more_add_addr = 1; ++ break; ++ } ++ mopt->saw_add_addr = 1; ++ mopt->add_addr_ptr = ptr; ++ break; ++ } ++ case MPTCP_SUB_REMOVE_ADDR: ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) { ++ mptcp_debug("%s: mp_remove_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ if (mopt->saw_rem_addr) { ++ mopt->more_rem_addr = 1; ++ break; ++ } ++ mopt->saw_rem_addr = 1; ++ mopt->rem_addr_ptr = ptr; ++ break; ++ case MPTCP_SUB_PRIO: ++ { ++ const struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_PRIO && ++ opsize != MPTCP_SUB_LEN_PRIO_ADDR) { ++ mptcp_debug("%s: mp_prio: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->saw_low_prio = 1; ++ mopt->low_prio = mpprio->b; ++ ++ if (opsize == MPTCP_SUB_LEN_PRIO_ADDR) { ++ mopt->saw_low_prio = 2; ++ mopt->prio_addr_id = mpprio->addr_id; ++ } ++ break; ++ } ++ case MPTCP_SUB_FAIL: ++ if (opsize != MPTCP_SUB_LEN_FAIL) { ++ mptcp_debug("%s: mp_fail: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ mopt->mp_fail = 1; ++ break; ++ case MPTCP_SUB_FCLOSE: ++ if (opsize != MPTCP_SUB_LEN_FCLOSE) { ++ mptcp_debug("%s: mp_fclose: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->mp_fclose = 1; ++ mopt->mptcp_sender_key = ((struct mp_fclose *)ptr)->key; ++ ++ break; ++ default: ++ mptcp_debug("%s: Received unkown subtype: %d\n", ++ __func__, mp_opt->sub); ++ break; ++ } ++} ++ ++/** Parse only MPTCP options */ ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ const unsigned char *ptr = (const unsigned char *)(th + 1); ++ ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP) ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, NULL); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++} ++ ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *sk; ++ u32 rtt_max = 0; ++ ++ /* In MPTCP, we take the max delay across all flows, ++ * in order to take into account meta-reordering buffers. ++ */ ++ mptcp_for_each_sk(mpcb, sk) { ++ if (!mptcp_sk_can_recv(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->rcv_rtt_est.rtt_us) ++ rtt_max = tcp_sk(sk)->rcv_rtt_est.rtt_us; ++ } ++ if (time < (rtt_max >> 3) || !rtt_max) ++ return true; ++ ++ return false; ++} ++ ++static void mptcp_handle_add_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ __be16 port = 0; ++ union inet_addr addr; ++ sa_family_t family; ++ ++ if (mpadd->ipver == 4) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v4; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v4.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v4.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 4, (u8 *)&mpadd->u.v4.addr.s_addr, ++ 2, (u8 *)&mpadd->u.v4.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v4: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2)) ++ port = mpadd->u.v4.port; ++ family = AF_INET; ++ addr.in = mpadd->u.v4.addr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (mpadd->ipver == 6) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v6; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v6.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v6.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 16, (u8 *)&mpadd->u.v6.addr.s6_addr, ++ 2, (u8 *)&mpadd->u.v6.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v6: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2)) ++ port = mpadd->u.v6.port; ++ family = AF_INET6; ++ addr.in6 = mpadd->u.v6.addr; ++#endif /* CONFIG_IPV6 */ ++ } else { ++ return; ++ } ++ ++ if (mpcb->pm_ops->add_raddr) ++ mpcb->pm_ops->add_raddr(mpcb, &addr, family, port, mpadd->addr_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRRX); ++} ++ ++static void mptcp_handle_rem_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ int i; ++ u8 rem_id; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ for (i = 0; i <= mprem->len - MPTCP_SUB_LEN_REMOVE_ADDR; i++) { ++ rem_id = (&mprem->addrs_id)[i]; ++ ++ if (mpcb->pm_ops->rem_raddr) ++ mpcb->pm_ops->rem_raddr(mpcb, rem_id); ++ mptcp_send_reset_rem_id(mpcb, rem_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRSUB); ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRRX); ++} ++ ++static void mptcp_parse_addropt(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether ADD_ADDR is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_ADD_ADDR) { ++ u8 mptcp_ver = tcp_sk(sk)->mpcb->mptcp_ver; ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ if (!is_valid_addropt_opsize(mptcp_ver, mpadd, ++ opsize)) ++ goto cont; ++ ++ mptcp_handle_add_addr(ptr, sk); ++ } ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_REMOVE_ADDR) { ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) ++ goto cont; ++ ++ mptcp_handle_rem_addr(ptr, sk); ++ } ++cont: ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return; ++} ++ ++static bool mptcp_mp_fastclose_rcvd(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ if (likely(!mptcp->rx_opt.mp_fclose)) ++ return false; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FASTCLOSERX); ++ mptcp->rx_opt.mp_fclose = 0; ++ if (mptcp->rx_opt.mptcp_sender_key != mpcb->mptcp_loc_key) ++ return false; ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ tcp_reset(mptcp_meta_sk(sk)); ++ ++ return true; ++} ++ ++static void mptcp_mp_fail_rcvd(struct sock *sk, const struct tcphdr *th) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX); ++ mptcp->rx_opt.mp_fail = 0; ++ ++ if (!th->rst && !mpcb->infinite_mapping_snd) { ++ mpcb->send_infinite_mapping = 1; ++ ++ mptcp_restart_sending(meta_sk); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ } ++} ++ ++static inline void mptcp_path_array_check(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (unlikely(mpcb->list_rcvd)) { ++ mpcb->list_rcvd = 0; ++ if (mpcb->pm_ops->new_remote_address) ++ mpcb->pm_ops->new_remote_address(meta_sk); ++ } ++} ++ ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ if (tp->mpcb->infinite_mapping_rcv || tp->mpcb->infinite_mapping_snd) ++ return false; ++ ++ if (mptcp_mp_fastclose_rcvd(sk)) ++ return true; ++ ++ if (sk->sk_state == TCP_RST_WAIT && !th->rst) ++ return true; ++ ++ if (unlikely(mopt->mp_fail)) ++ mptcp_mp_fail_rcvd(sk, th); ++ ++ /* RFC 6824, Section 3.3: ++ * If a checksum is not present when its use has been negotiated, the ++ * receiver MUST close the subflow with a RST as it is considered broken. ++ */ ++ if (mptcp_is_data_seq(skb) && tp->mpcb->dss_csum && ++ !(TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_DSS_CSUM)) { ++ mptcp_send_reset(sk); ++ return true; ++ } ++ ++ /* We have to acknowledge retransmissions of the third ++ * ack. ++ */ ++ if (mopt->join_ack) { ++ tcp_send_delayed_ack(sk); ++ mopt->join_ack = 0; ++ } ++ ++ if (mopt->saw_add_addr || mopt->saw_rem_addr) { ++ if (mopt->more_add_addr || mopt->more_rem_addr) { ++ mptcp_parse_addropt(skb, sk); ++ } else { ++ if (mopt->saw_add_addr) ++ mptcp_handle_add_addr(mopt->add_addr_ptr, sk); ++ if (mopt->saw_rem_addr) ++ mptcp_handle_rem_addr(mopt->rem_addr_ptr, sk); ++ } ++ ++ mopt->more_add_addr = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->saw_rem_addr = 0; ++ } ++ if (mopt->saw_low_prio) { ++ if (mopt->saw_low_prio == 1) { ++ tp->mptcp->rcv_low_prio = mopt->low_prio; ++ } else { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tp->mpcb, sk_it) { ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk_it)->mptcp; ++ if (mptcp->rem_id == mopt->prio_addr_id) ++ mptcp->rcv_low_prio = mopt->low_prio; ++ } ++ } ++ mopt->saw_low_prio = 0; ++ } ++ ++ mptcp_data_ack(sk, skb); ++ ++ mptcp_path_array_check(mptcp_meta_sk(sk)); ++ /* Socket may have been mp_killed by a REMOVE_ADDR */ ++ if (tp->mp_killed) ++ return true; ++ ++ return false; ++} ++ ++/* In case of fastopen, some data can already be in the write queue. ++ * We need to update the sequence number of the segments as they ++ * were initially TCP sequence numbers. ++ */ ++static void mptcp_rcv_synsent_fastopen(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ struct sk_buff *skb; ++ u32 new_mapping = meta_tp->write_seq - master_tp->snd_una; ++ ++ /* There should only be one skb in write queue: the data not ++ * acknowledged in the SYN+ACK. In this case, we need to map ++ * this data to data sequence numbers. ++ */ ++ skb_queue_walk(&meta_sk->sk_write_queue, skb) { ++ /* If the server only acknowledges partially the data sent in ++ * the SYN, we need to trim the acknowledged part because ++ * we don't want to retransmit this already received data. ++ * When we reach this point, tcp_ack() has already cleaned up ++ * fully acked segments. However, tcp trims partially acked ++ * segments only when retransmitting. Since MPTCP comes into ++ * play only now, we will fake an initial transmit, and ++ * retransmit_skb() will not be called. The following fragment ++ * comes from __tcp_retransmit_skb(). ++ */ ++ if (before(TCP_SKB_CB(skb)->seq, master_tp->snd_una)) { ++ BUG_ON(before(TCP_SKB_CB(skb)->end_seq, ++ master_tp->snd_una)); ++ /* tcp_trim_head can only returns ENOMEM if skb is ++ * cloned. It is not the case here (see ++ * tcp_send_syn_data). ++ */ ++ BUG_ON(tcp_trim_head(meta_sk, skb, master_tp->snd_una - ++ TCP_SKB_CB(skb)->seq)); ++ } ++ ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* We can advance write_seq by the number of bytes unacknowledged ++ * and that were mapped in the previous loop. ++ */ ++ meta_tp->write_seq += master_tp->write_seq - master_tp->snd_una; ++ ++ /* The packets from the master_sk will be entailed to it later ++ * Until that time, its write queue is empty, and ++ * write_seq must align with snd_una ++ */ ++ master_tp->snd_nxt = master_tp->write_seq = master_tp->snd_una; ++ master_tp->packets_out = 0; ++ ++ /* Although these data have been sent already over the subsk, ++ * They have never been sent over the meta_sk, so we rewind ++ * the send_head so that tcp considers it as an initial send ++ * (instead of retransmit). ++ */ ++ meta_sk->sk_send_head = tcp_write_queue_head(meta_sk); ++} ++ ++/* The skptr is needed, because if we become MPTCP-capable, we have to switch ++ * from meta-socket to master-socket. ++ * ++ * @return: 1 - we want to reset this connection ++ * 2 - we want to discard the received syn/ack ++ * 0 - everything is fine - continue ++ */ ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (mptcp(tp)) { ++ u8 hash_mac_check[20]; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce); ++ if (memcmp(hash_mac_check, ++ (char *)&tp->mptcp->rx_opt.mptcp_recv_tmac, 8)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKMAC); ++ mptcp_sub_force_close(sk); ++ return 1; ++ } ++ ++ /* Set this flag in order to postpone data sending ++ * until the 4th ack arrives. ++ */ ++ tp->mptcp->pre_established = 1; ++ tp->mptcp->rcv_low_prio = tp->mptcp->rx_opt.low_prio; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)&tp->mptcp->sender_mac[0], 2, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX); ++ } else if (mopt->saw_mpc) { ++ struct sock *meta_sk = sk; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); ++ if (mopt->mptcp_ver > tcp_sk(sk)->mptcp_ver) ++ /* TODO Consider adding new MPTCP_INC_STATS entry */ ++ goto fallback; ++ ++ if (mptcp_create_master_sk(sk, mopt->mptcp_sender_key, ++ mopt->mptcp_ver, ++ ntohs(tcp_hdr(skb)->window))) ++ return 2; ++ ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ *skptr = sk; ++ tp = tcp_sk(sk); ++ ++ /* If fastopen was used data might be in the send queue. We ++ * need to update their sequence number to MPTCP-level seqno. ++ * Note that it can happen in rare cases that fastopen_req is ++ * NULL and syn_data is 0 but fastopen indeed occurred and ++ * data has been queued in the write queue (but not sent). ++ * Example of such rare cases: connect is non-blocking and ++ * TFO is configured to work without cookies. ++ */ ++ if (!skb_queue_empty(&meta_sk->sk_write_queue)) ++ mptcp_rcv_synsent_fastopen(meta_sk); ++ ++ /* -1, because the SYN consumed 1 byte. In case of TFO, we ++ * start the subflow-sequence number as if the data of the SYN ++ * is not part of any mapping. ++ */ ++ tp->mptcp->snt_isn = tp->snd_una - 1; ++ tp->mpcb->dss_csum = mopt->dss_csum; ++ if (tp->mpcb->dss_csum) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMENABLED); ++ ++ tp->mptcp->include_mpc = 1; ++ ++ /* Ensure that fastopen is handled at the meta-level. */ ++ tp->fastopen_req = NULL; ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ bh_unlock_sock(sk); ++ /* hold in sk_clone_lock due to initialization to 2 */ ++ sock_put(sk); ++ } else { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEFALLBACK); ++fallback: ++ tp->request_mptcp = 0; ++ ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ ++ if (mptcp(tp)) ++ tp->mptcp->rcv_isn = TCP_SKB_CB(skb)->seq; ++ ++ return 0; ++} ++ ++/* Similar to tcp_should_expand_sndbuf */ ++bool mptcp_should_expand_sndbuf(const struct sock *sk) ++{ ++ const struct sock *sk_it; ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int cnt_backups = 0; ++ int backup_available = 0; ++ ++ /* We circumvent this check in tcp_check_space, because we want to ++ * always call sk_write_space. So, we reproduce the check here. ++ */ ++ if (!meta_sk->sk_socket || ++ !test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ return false; ++ ++ /* If the user specified a specific send buffer setting, do ++ * not modify it. ++ */ ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return false; ++ ++ /* If we are under global TCP memory pressure, do not expand. */ ++ if (tcp_under_memory_pressure(meta_sk)) ++ return false; ++ ++ /* If we are under soft global TCP memory pressure, do not expand. */ ++ if (sk_memory_allocated(meta_sk) >= sk_prot_mem_limits(meta_sk, 0)) ++ return false; ++ ++ /* For MPTCP we look for a subsocket that could send data. ++ * If we found one, then we update the send-buffer. ++ */ ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ ++ if (!mptcp_sk_can_send(sk_it)) ++ continue; ++ ++ /* Backup-flows have to be counted - if there is no other ++ * subflow we take the backup-flow into account. ++ */ ++ if (tp_it->mptcp->rcv_low_prio || tp_it->mptcp->low_prio) ++ cnt_backups++; ++ ++ if (tcp_packets_in_flight(tp_it) < tp_it->snd_cwnd) { ++ if (tp_it->mptcp->rcv_low_prio || tp_it->mptcp->low_prio) { ++ backup_available = 1; ++ continue; ++ } ++ return true; ++ } ++ } ++ ++ /* Backup-flow is available for sending - update send-buffer */ ++ if (meta_tp->mpcb->cnt_established == cnt_backups && backup_available) ++ return true; ++ return false; ++} ++ ++void mptcp_init_buffer_space(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int space; ++ ++ tcp_init_buffer_space(sk); ++ ++ if (is_master_tp(tp)) { ++ meta_tp->rcvq_space.space = meta_tp->rcv_wnd; ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->rcvq_space.time = meta_tp->tcp_mstamp; ++ meta_tp->rcvq_space.seq = meta_tp->copied_seq; ++ ++ /* If there is only one subflow, we just use regular TCP ++ * autotuning. User-locks are handled already by ++ * tcp_init_buffer_space ++ */ ++ meta_tp->window_clamp = tp->window_clamp; ++ meta_tp->rcv_ssthresh = tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = sk->sk_rcvbuf; ++ meta_sk->sk_sndbuf = sk->sk_sndbuf; ++ ++ return; ++ } ++ ++ if (meta_sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ goto snd_buf; ++ ++ /* Adding a new subflow to the rcv-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_rcvbuf + sk->sk_rcvbuf, sysctl_tcp_rmem[2]); ++ if (space > meta_sk->sk_rcvbuf) { ++ meta_tp->window_clamp += tp->window_clamp; ++ meta_tp->rcv_ssthresh += tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = space; ++ } ++ ++snd_buf: ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return; ++ ++ /* Adding a new subflow to the send-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_sndbuf + sk->sk_sndbuf, sysctl_tcp_wmem[2]); ++ if (space > meta_sk->sk_sndbuf) { ++ meta_sk->sk_sndbuf = space; ++ meta_sk->sk_write_space(meta_sk); ++ } ++} ++ ++void mptcp_tcp_set_rto(struct sock *sk) ++{ ++ tcp_set_rto(sk); ++ mptcp_set_rto(sk); ++} +diff -aurN linux-4.14.174/net/mptcp/mptcp_ipv4.c mptcp-mptcp_v0.94/net/mptcp/mptcp_ipv4.c +--- linux-4.14.174/net/mptcp/mptcp_ipv4.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_ipv4.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,436 @@ ++/* ++ * MPTCP implementation - IPv4-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) ++{ ++ return siphash_4u32((__force u32)saddr, (__force u32)daddr, ++ (__force u32)sport << 16 | (__force u32)dport, ++ mptcp_seed++, &mptcp_secret); ++} ++ ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed) ++{ ++ return siphash_2u64((__force u64)saddr << 32 | (__force u64)daddr, ++ (__force u64)seed << 32 | (__force u64)sport << 16 | (__force u64)dport, ++ &mptcp_secret); ++} ++ ++ ++static void mptcp_v4_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v4_reqsk_destructor(req); ++} ++ ++static int mptcp_v4_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v4_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v4_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++static int mptcp_v4_join_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v4_get_nonce(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.ip = inet_rsk(req)->ir_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(AF_INET, &addr, sock_net(sk), &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp_request_sock_ops */ ++struct request_sock_ops mptcp_request_sock_ops __read_mostly = { ++ .family = PF_INET, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v4_reqsk_send_ack, ++ .destructor = mptcp_v4_reqsk_destructor, ++ .send_reset = tcp_v4_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v4_conn_request */ ++static int mptcp_v4_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_join_request_sock_ipv4_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb) ++ __releases(&child->sk_lock.slock) ++{ ++ int ret; ++ ++ /* We don't call tcp_child_process here, because we hold ++ * already the meta-sk-lock and are sure that it is not owned ++ * by the user. ++ */ ++ tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ++ ret = tcp_rcv_state_process(child, skb); ++ bh_unlock_sock(child); ++ sock_put(child); ++ ++ return ret; ++} ++ ++ ++/* Similar to: tcp_v4_do_rcv ++ * We only process join requests here. (either the SYN or the final ACK) ++ */ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct iphdr *iph = ip_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = inet_lookup_established(sock_net(meta_sk), &tcp_hashinfo, ++ iph->saddr, th->source, iph->daddr, ++ th->dest, inet_iif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v4_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v4_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v4_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v4_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv4 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ if (mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL)) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ setup_timer(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, (unsigned long)sk); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin_family = AF_INET; ++ rem_in.sin_family = AF_INET; ++ loc_in.sin_port = 0; ++ if (rem->port) ++ rem_in.sin_port = rem->port; ++ else ++ rem_in.sin_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin_addr = loc->addr; ++ rem_in.sin_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI4 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d ifidx: %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin_addr, ++ ntohs(loc_in.sin_port), &rem_in.sin_addr, ++ ntohs(rem_in.sin_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mptcp_init4_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v4_specific = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v4_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ip_setsockopt, ++ .getsockopt = ip_getsockopt, ++ .addr2sockaddr = inet_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ip_setsockopt, ++ .compat_getsockopt = compat_ip_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++/* General initialization of IPv4 for MPTCP */ ++int mptcp_pm_v4_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp_request_sock_ops; ++ ++ mptcp_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_request_sock_ipv4_ops.init_req = mptcp_v4_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv4_ops.cookie_init_seq = mptcp_v4_cookie_init_seq; ++#endif ++ mptcp_join_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_join_request_sock_ipv4_ops.init_req = mptcp_v4_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v4_undo(void) ++{ ++ kmem_cache_destroy(mptcp_request_sock_ops.slab); ++ kfree(mptcp_request_sock_ops.slab_name); ++} +diff -aurN linux-4.14.174/net/mptcp/mptcp_ipv6.c mptcp-mptcp_v0.94/net/mptcp/mptcp_ipv6.c +--- linux-4.14.174/net/mptcp/mptcp_ipv6.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_ipv6.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,465 @@ ++/* ++ * MPTCP implementation - IPv6-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = mptcp_seed++, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = seed, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++static void mptcp_v6_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v6_reqsk_destructor(req); ++} ++ ++static int mptcp_v6_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v6_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v6_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++static int mptcp_v6_join_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v6_get_nonce(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.in6 = inet_rsk(req)->ir_v6_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(AF_INET6, &addr, sock_net(sk), &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp6_request_sock_ops */ ++struct request_sock_ops mptcp6_request_sock_ops __read_mostly = { ++ .family = AF_INET6, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v6_reqsk_send_ack, ++ .destructor = mptcp_v6_reqsk_destructor, ++ .send_reset = tcp_v6_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++static int mptcp_v6_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_join_request_sock_ipv6_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = __inet6_lookup_established(sock_net(meta_sk), ++ &tcp_hashinfo, ++ &ip6h->saddr, th->source, ++ &ip6h->daddr, ntohs(th->dest), ++ tcp_v6_iif(skb), tcp_v6_sdif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v6_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v6_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v6_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v6_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv6 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in6 loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet6_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet6_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ if (mptcp_add_sock(meta_sk, sk, loc->loc6_id, rem->rem6_id, GFP_KERNEL)) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ setup_timer(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, (unsigned long)sk); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin6_family = AF_INET6; ++ rem_in.sin6_family = AF_INET6; ++ loc_in.sin6_port = 0; ++ if (rem->port) ++ rem_in.sin6_port = rem->port; ++ else ++ rem_in.sin6_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin6_addr = loc->addr; ++ rem_in.sin6_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in6)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI6 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin6_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI6:%d dst_addr:%pI6:%d ifidx: %u\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin6_addr, ++ ntohs(loc_in.sin6_port), &rem_in.sin6_addr, ++ ntohs(rem_in.sin6_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in6), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mptcp_init6_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v6_specific = { ++ .queue_xmit = inet6_csk_xmit, ++ .send_check = tcp_v6_send_check, ++ .rebuild_header = inet6_sk_rebuild_header, ++ .sk_rx_dst_set = inet6_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct ipv6hdr), ++ .net_frag_header_len = sizeof(struct frag_hdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v6_mtu_reduced, ++}; ++ ++const struct inet_connection_sock_af_ops mptcp_v6_mapped = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_pm_v6_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp6_request_sock_ops; ++ ++ mptcp_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_request_sock_ipv6_ops.init_req = mptcp_v6_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv6_ops.cookie_init_seq = mptcp_v6_cookie_init_seq; ++#endif ++ ++ mptcp_join_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_join_request_sock_ipv6_ops.init_req = mptcp_v6_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP6"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v6_undo(void) ++{ ++ kmem_cache_destroy(mptcp6_request_sock_ops.slab); ++ kfree(mptcp6_request_sock_ops.slab_name); ++} +diff -aurN linux-4.14.174/net/mptcp/mptcp_ndiffports.c mptcp-mptcp_v0.94/net/mptcp/mptcp_ndiffports.c +--- linux-4.14.174/net/mptcp/mptcp_ndiffports.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_ndiffports.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,173 @@ ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct ndiffports_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++}; ++ ++static int num_subflows __read_mostly = 2; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per MPTCP connection"); ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct ndiffports_priv *pm_priv = container_of(work, ++ struct ndiffports_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (num_subflows > iter && num_subflows > mpcb->cnt_subflows) { ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ } else { ++#if IS_ENABLED(CONFIG_IPV6) ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_init6_subsockets(meta_sk, &loc, &rem); ++#endif ++ } ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void ndiffports_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *fmp = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++} ++ ++static void ndiffports_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *pm_priv = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int ndiffports_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++static struct mptcp_pm_ops ndiffports __read_mostly = { ++ .new_session = ndiffports_new_session, ++ .fully_established = ndiffports_create_subflows, ++ .get_local_id = ndiffports_get_local_id, ++ .name = "ndiffports", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init ndiffports_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ndiffports_priv) > MPTCP_PM_SIZE); ++ ++ if (mptcp_register_path_manager(&ndiffports)) ++ goto exit; ++ ++ return 0; ++ ++exit: ++ return -1; ++} ++ ++static void ndiffports_unregister(void) ++{ ++ mptcp_unregister_path_manager(&ndiffports); ++} ++ ++module_init(ndiffports_register); ++module_exit(ndiffports_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("NDIFF-PORTS MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_olia.c mptcp-mptcp_v0.94/net/mptcp/mptcp_olia.c +--- linux-4.14.174/net/mptcp/mptcp_olia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_olia.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,310 @@ ++/* ++ * MPTCP implementation - OPPORTUNISTIC LINKED INCREASES CONGESTION CONTROL: ++ * ++ * Algorithm design: ++ * Ramin Khalili ++ * Nicolas Gast ++ * Jean-Yves Le Boudec ++ * ++ * Implementation: ++ * Ramin Khalili ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++#include ++ ++static int scale = 10; ++ ++struct mptcp_olia { ++ u32 mptcp_loss1; ++ u32 mptcp_loss2; ++ u32 mptcp_loss3; ++ int epsilon_num; ++ u32 epsilon_den; ++ int mptcp_snd_cwnd_cnt; ++}; ++ ++static inline int mptcp_olia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_olia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++/* take care of artificially inflate (see RFC5681) ++ * of cwnd during fast-retransmit phase ++ */ ++static u32 mptcp_get_crt_cwnd(struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (icsk->icsk_ca_state == TCP_CA_Recovery) ++ return tcp_sk(sk)->snd_ssthresh; ++ else ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* return the dominator of the first term of the increasing term */ ++static u64 mptcp_get_rate(const struct mptcp_cb *mpcb , u32 path_rtt) ++{ ++ struct sock *sk; ++ u64 rate = 1; /* We have to avoid a zero-rate because it is used as a divisor */ ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ u64 scaled_num; ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ scaled_num = mptcp_olia_scale(tmp_cwnd, scale) * path_rtt; ++ rate += div_u64(scaled_num , tp->srtt_us); ++ } ++ rate *= rate; ++ return rate; ++} ++ ++/* find the maximum cwnd, used to find set M */ ++static u32 mptcp_get_max_cwnd(const struct mptcp_cb *mpcb) ++{ ++ struct sock *sk; ++ u32 best_cwnd = 0; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd > best_cwnd) ++ best_cwnd = tmp_cwnd; ++ } ++ return best_cwnd; ++} ++ ++static void mptcp_get_epsilon(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_olia *ca; ++ struct tcp_sock *tp; ++ struct sock *sk; ++ u64 tmp_int, tmp_rtt, best_int = 0, best_rtt = 1; ++ u32 max_cwnd, tmp_cwnd; ++ u8 M = 0, B_not_M = 0; ++ ++ /* TODO - integrate this in the following loop - we just want to iterate once */ ++ ++ max_cwnd = mptcp_get_max_cwnd(mpcb); ++ ++ /* find the best path */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ /* TODO - check here and rename variables */ ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt >= (u64)best_int * tmp_rtt) { ++ best_rtt = tmp_rtt; ++ best_int = tmp_int; ++ } ++ } ++ ++ /* TODO - integrate this here in mptcp_get_max_cwnd and in the previous loop */ ++ /* find the size of M and B_not_M */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd == max_cwnd) { ++ M++; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) ++ B_not_M++; ++ } ++ } ++ ++ /* check if the path is in M or B_not_M and set the value of epsilon accordingly */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ if (B_not_M == 0) { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ ++ if (tmp_cwnd < max_cwnd && ++ (u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) { ++ ca->epsilon_num = 1; ++ ca->epsilon_den = mpcb->cnt_established * B_not_M; ++ } else if (tmp_cwnd == max_cwnd) { ++ ca->epsilon_num = -1; ++ ca->epsilon_den = mpcb->cnt_established * M; ++ } else { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++ } ++ } ++} ++ ++/* setting the initial values */ ++static void mptcp_olia_init(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (mptcp(tp)) { ++ ca->mptcp_loss1 = tp->snd_una; ++ ca->mptcp_loss2 = tp->snd_una; ++ ca->mptcp_loss3 = tp->snd_una; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++} ++ ++/* updating inter-loss distance and ssthresh */ ++static void mptcp_olia_set_state(struct sock *sk, u8 new_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ if (new_state == TCP_CA_Loss || ++ new_state == TCP_CA_Recovery || new_state == TCP_CA_CWR) { ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (ca->mptcp_loss3 != ca->mptcp_loss2 && ++ !inet_csk(sk)->icsk_retransmits) { ++ ca->mptcp_loss1 = ca->mptcp_loss2; ++ ca->mptcp_loss2 = ca->mptcp_loss3; ++ } ++ } ++} ++ ++/* main algorithm */ ++static void mptcp_olia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ u64 inc_num, inc_den, rate, cwnd_scaled; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ ca->mptcp_loss3 = tp->snd_una; ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ /* slow start if it is in the safe area */ ++ if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ return; ++ } ++ ++ mptcp_get_epsilon(mpcb); ++ rate = mptcp_get_rate(mpcb, tp->srtt_us); ++ cwnd_scaled = mptcp_olia_scale(tp->snd_cwnd, scale); ++ inc_den = ca->epsilon_den * tp->snd_cwnd * rate ? : 1; ++ ++ /* calculate the increasing term, scaling is used to reduce the rounding effect */ ++ if (ca->epsilon_num == -1) { ++ if (ca->epsilon_den * cwnd_scaled * cwnd_scaled < rate) { ++ inc_num = rate - ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt -= div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } else { ++ inc_num = ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled - rate; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ } else { ++ inc_num = ca->epsilon_num * rate + ++ ca->epsilon_den * cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ ++ ++ if (ca->mptcp_snd_cwnd_cnt >= (1 << scale) - 1) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) ++ tp->snd_cwnd++; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } else if (ca->mptcp_snd_cwnd_cnt <= 0 - (1 << scale) + 1) { ++ tp->snd_cwnd = max((int) 1 , (int) tp->snd_cwnd - 1); ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_olia = { ++ .init = mptcp_olia_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_olia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .set_state = mptcp_olia_set_state, ++ .owner = THIS_MODULE, ++ .name = "olia", ++}; ++ ++static int __init mptcp_olia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_olia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_olia); ++} ++ ++static void __exit mptcp_olia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_olia); ++} ++ ++module_init(mptcp_olia_register); ++module_exit(mptcp_olia_unregister); ++ ++MODULE_AUTHOR("Ramin Khalili, Nicolas Gast, Jean-Yves Le Boudec"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP COUPLED CONGESTION CONTROL"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_output.c mptcp-mptcp_v0.94/net/mptcp/mptcp_output.c +--- linux-4.14.174/net/mptcp/mptcp_output.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_output.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,1824 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static const int mptcp_dss_len = MPTCP_SUB_LEN_DSS_ALIGN + ++ MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ ++static inline int mptcp_sub_len_remove_addr(u16 bitfield) ++{ ++ unsigned int c; ++ for (c = 0; bitfield; c++) ++ bitfield &= bitfield - 1; ++ return MPTCP_SUB_LEN_REMOVE_ADDR + c - 1; ++} ++ ++int mptcp_sub_len_remove_addr_align(u16 bitfield) ++{ ++ return ALIGN(mptcp_sub_len_remove_addr(bitfield), 4); ++} ++EXPORT_SYMBOL(mptcp_sub_len_remove_addr_align); ++ ++/* get the data-seq and end-data-seq and store them again in the ++ * tcp_skb_cb ++ */ ++static bool mptcp_reconstruct_mapping(struct sk_buff *skb) ++{ ++ const struct mp_dss *mpdss = (struct mp_dss *)TCP_SKB_CB(skb)->dss; ++ u32 *p32; ++ u16 *p16; ++ ++ if (!mptcp_is_data_seq(skb)) ++ return false; ++ ++ if (!mpdss->M) ++ return false; ++ ++ /* Move the pointer to the data-seq */ ++ p32 = (u32 *)mpdss; ++ p32++; ++ if (mpdss->A) { ++ p32++; ++ if (mpdss->a) ++ p32++; ++ } ++ ++ TCP_SKB_CB(skb)->seq = ntohl(*p32); ++ ++ /* Get the data_len to calculate the end_data_seq */ ++ p32++; ++ p32++; ++ p16 = (u16 *)p32; ++ TCP_SKB_CB(skb)->end_seq = ntohs(*p16) + TCP_SKB_CB(skb)->seq; ++ ++ return true; ++} ++ ++static bool mptcp_is_reinjected(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCP_REINJECT; ++} ++ ++static void mptcp_find_and_set_pathmask(const struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct sk_buff *skb_it; ++ ++ skb_it = tcp_write_queue_head(meta_sk); ++ ++ tcp_for_write_queue_from(skb_it, meta_sk) { ++ if (skb_it == tcp_send_head(meta_sk)) ++ break; ++ ++ if (TCP_SKB_CB(skb_it)->seq == TCP_SKB_CB(skb)->seq) { ++ TCP_SKB_CB(skb)->path_mask = TCP_SKB_CB(skb_it)->path_mask; ++ break; ++ } ++ } ++} ++ ++/* Reinject data from one TCP subflow to the meta_sk. If sk == NULL, we are ++ * coming from the meta-retransmit-timer ++ */ ++static void __mptcp_reinject_data(struct sk_buff *orig_skb, struct sock *meta_sk, ++ struct sock *sk, int clone_it) ++{ ++ struct sk_buff *skb, *skb1; ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u32 seq, end_seq; ++ ++ if (clone_it) { ++ /* pskb_copy is necessary here, because the TCP/IP-headers ++ * will be changed when it's going to be reinjected on another ++ * subflow. ++ */ ++ skb = pskb_copy_for_clone(orig_skb, GFP_ATOMIC); ++ } else { ++ __skb_unlink(orig_skb, &sk->sk_write_queue); ++ sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ sk->sk_wmem_queued -= orig_skb->truesize; ++ sk_mem_uncharge(sk, orig_skb->truesize); ++ skb = orig_skb; ++ } ++ if (unlikely(!skb)) ++ return; ++ ++ if (sk && !mptcp_reconstruct_mapping(skb)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ skb->sk = meta_sk; ++ ++ /* Reset subflow-specific TCP control-data */ ++ TCP_SKB_CB(skb)->sacked = 0; ++ TCP_SKB_CB(skb)->tcp_flags &= (TCPHDR_ACK | TCPHDR_PSH); ++ ++ /* If it reached already the destination, we don't have to reinject it */ ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ /* Only reinject segments that are fully covered by the mapping */ ++ if (skb->len + (mptcp_is_data_fin(skb) ? 1 : 0) != ++ TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) { ++ u32 seq = TCP_SKB_CB(skb)->seq; ++ u32 end_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ __kfree_skb(skb); ++ ++ /* Ok, now we have to look for the full mapping in the meta ++ * send-queue :S ++ */ ++ tcp_for_write_queue(skb, meta_sk) { ++ /* Not yet at the mapping? */ ++ if (before(TCP_SKB_CB(skb)->seq, seq)) ++ continue; ++ /* We have passed by the mapping */ ++ if (after(TCP_SKB_CB(skb)->end_seq, end_seq)) ++ return; ++ ++ __mptcp_reinject_data(skb, meta_sk, NULL, 1); ++ } ++ return; ++ } ++ ++ /* Segment goes back to the MPTCP-layer. So, we need to zero the ++ * path_mask/dss. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ /* We need to find out the path-mask from the meta-write-queue ++ * to properly select a subflow. ++ */ ++ mptcp_find_and_set_pathmask(meta_sk, skb); ++ ++ /* If it's empty, just add */ ++ if (skb_queue_empty(&mpcb->reinject_queue)) { ++ skb_queue_head(&mpcb->reinject_queue, skb); ++ return; ++ } ++ ++ /* Find place to insert skb - or even we can 'drop' it, as the ++ * data is already covered by other skb's in the reinject-queue. ++ * ++ * This is inspired by code from tcp_data_queue. ++ */ ++ ++ skb1 = skb_peek_tail(&mpcb->reinject_queue); ++ seq = TCP_SKB_CB(skb)->seq; ++ while (1) { ++ if (!after(TCP_SKB_CB(skb1)->seq, seq)) ++ break; ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) { ++ skb1 = NULL; ++ break; ++ } ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ ++ /* Do skb overlap to previous one? */ ++ end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ /* All the bits are present. Don't reinject */ ++ __kfree_skb(skb); ++ return; ++ } ++ if (seq == TCP_SKB_CB(skb1)->seq) { ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) ++ skb1 = NULL; ++ else ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ } ++ if (!skb1) ++ __skb_queue_head(&mpcb->reinject_queue, skb); ++ else ++ __skb_queue_after(&mpcb->reinject_queue, skb1, skb); ++ ++ /* And clean segments covered by new one as whole. */ ++ while (!skb_queue_is_last(&mpcb->reinject_queue, skb)) { ++ skb1 = skb_queue_next(&mpcb->reinject_queue, skb); ++ ++ if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) ++ break; ++ ++ if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) ++ break; ++ ++ __skb_unlink(skb1, &mpcb->reinject_queue); ++ __kfree_skb(skb1); ++ } ++ return; ++} ++ ++/* Inserts data into the reinject queue */ ++void mptcp_reinject_data(struct sock *sk, int clone_it) ++{ ++ struct sk_buff *skb_it, *tmp; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = tp->meta_sk; ++ ++ /* It has already been closed - there is really no point in reinjecting */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ skb_queue_walk_safe(&sk->sk_write_queue, skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it); ++ } ++ ++ skb_it = tcp_write_queue_tail(meta_sk); ++ /* If sk has sent the empty data-fin, we have to reinject it too. */ ++ if (skb_it && mptcp_is_data_fin(skb_it) && skb_it->len == 0 && ++ TCP_SKB_CB(skb_it)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index)) { ++ __mptcp_reinject_data(skb_it, meta_sk, NULL, 1); ++ } ++ ++ tp->pf = 1; ++ ++ mptcp_push_pending_frames(meta_sk); ++} ++EXPORT_SYMBOL(mptcp_reinject_data); ++ ++static void mptcp_combine_dfin(const struct sk_buff *skb, ++ const struct sock *meta_sk, ++ struct sock *subsk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* In infinite mapping we always try to combine */ ++ if (mpcb->infinite_mapping_snd) ++ goto combine; ++ ++ /* Don't combine, if they didn't combine when closing - otherwise we end ++ * up in TIME_WAIT, even if our app is smart enough to avoid it. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !mpcb->dfin_combined) ++ return; ++ ++ /* Don't combine if there is still outstanding data that remains to be ++ * DATA_ACKed, because otherwise we may never be able to deliver this. ++ */ ++ if (meta_tp->snd_una != TCP_SKB_CB(skb)->seq) ++ return; ++ ++combine: ++ if (tcp_close_state(subsk)) { ++ subsk->sk_shutdown |= SEND_SHUTDOWN; ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } ++} ++ ++static int mptcp_write_dss_mapping(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ const struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *start = ptr; ++ __u16 data_len; ++ ++ *ptr++ = htonl(tcb->seq); /* data_seq */ ++ ++ /* If it's a non-data DATA_FIN, we set subseq to 0 (draft v7) */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ *ptr++ = 0; /* subseq */ ++ else ++ *ptr++ = htonl(tp->write_seq - tp->mptcp->snt_isn); /* subseq */ ++ ++ if (tcb->mptcp_flags & MPTCPHDR_INF) ++ data_len = 0; ++ else ++ data_len = tcb->end_seq - tcb->seq; ++ ++ if (tp->mpcb->dss_csum && data_len) { ++ __be16 *p16 = (__be16 *)ptr; ++ __be32 hdseq = mptcp_get_highorder_sndbits(skb, tp->mpcb); ++ __wsum csum; ++ ++ *ptr = htonl(((data_len) << 16) | ++ (TCPOPT_EOL << 8) | ++ (TCPOPT_EOL)); ++ csum = csum_partial(ptr - 2, 12, skb->csum); ++ p16++; ++ *p16++ = csum_fold(csum_partial(&hdseq, sizeof(hdseq), csum)); ++ } else { ++ *ptr++ = htonl(((data_len) << 16) | ++ (TCPOPT_NOP << 8) | ++ (TCPOPT_NOP)); ++ } ++ ++ return ptr - start; ++} ++ ++static int mptcp_write_dss_data_ack(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ struct mp_dss *mdss = (struct mp_dss *)ptr; ++ __be32 *start = ptr; ++ ++ mdss->kind = TCPOPT_MPTCP; ++ mdss->sub = MPTCP_SUB_DSS; ++ mdss->rsv1 = 0; ++ mdss->rsv2 = 0; ++ mdss->F = mptcp_is_data_fin(skb) ? 1 : 0; ++ mdss->m = 0; ++ mdss->M = mptcp_is_data_seq(skb) ? 1 : 0; ++ mdss->a = 0; ++ mdss->A = 1; ++ mdss->len = mptcp_sub_len_dss(mdss, tp->mpcb->dss_csum); ++ ptr++; ++ ++ *ptr++ = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ return ptr - start; ++} ++ ++/* RFC6824 states that once a particular subflow mapping has been sent ++ * out it must never be changed. However, packets may be split while ++ * they are in the retransmission queue (due to SACK or ACKs) and that ++ * arguably means that we would change the mapping (e.g. it splits it, ++ * our sends out a subset of the initial mapping). ++ * ++ * Furthermore, the skb checksum is not always preserved across splits ++ * (e.g. mptcp_fragment) which would mean that we need to recompute ++ * the DSS checksum in this case. ++ * ++ * To avoid this we save the initial DSS mapping which allows us to ++ * send the same DSS mapping even for fragmented retransmits. ++ */ ++static void mptcp_save_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb) ++{ ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *ptr = (__be32 *)tcb->dss; ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ ptr += mptcp_write_dss_mapping(tp, skb, ptr); ++} ++ ++/* Write the saved DSS mapping to the header */ ++static int mptcp_write_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ __be32 *start = ptr; ++ ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, mptcp_dss_len); ++ ++ /* update the data_ack */ ++ start[1] = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ /* dss is in a union with inet_skb_parm and ++ * the IP layer expects zeroed IPCB fields. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ return mptcp_dss_len/sizeof(*ptr); ++} ++ ++static bool mptcp_skb_entail(struct sock *sk, struct sk_buff *skb, int reinject) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb; ++ struct sk_buff *subskb = NULL; ++ ++ if (!reinject) ++ TCP_SKB_CB(skb)->mptcp_flags |= (mpcb->snd_hiseq_index ? ++ MPTCPHDR_SEQ64_INDEX : 0); ++ ++ subskb = pskb_copy_for_clone(skb, GFP_ATOMIC); ++ if (!subskb) ++ return false; ++ ++ /* At the subflow-level we need to call again tcp_init_tso_segs. We ++ * force this, by setting pcount to 0. It has been set to 1 prior to ++ * the call to mptcp_skb_entail. ++ */ ++ tcp_skb_pcount_set(subskb, 0); ++ ++ TCP_SKB_CB(skb)->path_mask |= mptcp_pi_to_flag(tp->mptcp->path_index); ++ ++ /* Compute checksum, if: ++ * 1. The current route does not support csum offloading but it was ++ * assumed that it does (ip_summed is CHECKSUM_PARTIAL) ++ * 2. We need the DSS-checksum but ended up not pre-computing it ++ * (e.g., in the case of TFO retransmissions). ++ */ ++ if (skb->ip_summed == CHECKSUM_PARTIAL && ++ (!sk_check_csum_caps(sk) || tp->mpcb->dss_csum)) { ++ subskb->csum = skb->csum = skb_checksum(skb, 0, skb->len, 0); ++ subskb->ip_summed = skb->ip_summed = CHECKSUM_NONE; ++ } ++ ++ tcb = TCP_SKB_CB(subskb); ++ ++ if (tp->mpcb->send_infinite_mapping && ++ !tp->mpcb->infinite_mapping_snd && ++ !before(tcb->seq, mptcp_meta_tp(tp)->snd_nxt)) { ++ tp->mptcp->fully_established = 1; ++ tp->mpcb->infinite_mapping_snd = 1; ++ tp->mptcp->infinite_cutoff_seq = tp->write_seq; ++ tcb->mptcp_flags |= MPTCPHDR_INF; ++ } ++ ++ if (mptcp_is_data_fin(subskb)) ++ mptcp_combine_dfin(subskb, meta_sk, sk); ++ ++ mptcp_save_dss_data_seq(tp, subskb); ++ ++ tcb->seq = tp->write_seq; ++ ++ /* Take into account seg len */ ++ tp->write_seq += subskb->len + ((tcb->tcp_flags & TCPHDR_FIN) ? 1 : 0); ++ tcb->end_seq = tp->write_seq; ++ ++ /* If it's a non-payload DATA_FIN (also no subflow-fin), the ++ * segment is not part of the subflow but on a meta-only-level. ++ */ ++ if (!mptcp_is_data_fin(subskb) || tcb->end_seq != tcb->seq) { ++ tcp_add_write_queue_tail(sk, subskb); ++ sk->sk_wmem_queued += subskb->truesize; ++ sk_mem_charge(sk, subskb->truesize); ++ } else { ++ int err; ++ ++ /* Necessary to initialize for tcp_transmit_skb. mss of 1, as ++ * skb->len = 0 will force tso_segs to 1. ++ */ ++ tcp_init_tso_segs(subskb, 1); ++ /* Empty data-fins are sent immediatly on the subflow */ ++ err = tcp_transmit_skb(sk, subskb, 1, GFP_ATOMIC); ++ ++ /* It has not been queued, we can free it now. */ ++ kfree_skb(subskb); ++ ++ if (err) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->second_packet = 1; ++ tp->mptcp->last_end_data_seq = TCP_SKB_CB(skb)->end_seq; ++ } ++ ++ return true; ++} ++ ++/* Fragment an skb and update the mptcp meta-data. Due to reinject, we ++ * might need to undo some operations done by tcp_fragment. ++ */ ++static int mptcp_fragment(struct sock *meta_sk, struct sk_buff *skb, u32 len, ++ gfp_t gfp, int reinject) ++{ ++ int ret, diff, old_factor; ++ struct sk_buff *buff; ++ u8 flags; ++ ++ if (skb_headlen(skb) < len) ++ diff = skb->len - len; ++ else ++ diff = skb->data_len; ++ old_factor = tcp_skb_pcount(skb); ++ ++ /* The mss_now in tcp_fragment is used to set the tso_segs of the skb. ++ * At the MPTCP-level we do not care about the absolute value. All we ++ * care about is that it is set to 1 for accurate packets_out ++ * accounting. ++ */ ++ ret = tcp_fragment(meta_sk, skb, len, UINT_MAX, gfp); ++ if (ret) ++ return ret; ++ ++ buff = skb->next; ++ ++ flags = TCP_SKB_CB(skb)->mptcp_flags; ++ TCP_SKB_CB(skb)->mptcp_flags = flags & ~(MPTCPHDR_FIN); ++ TCP_SKB_CB(buff)->mptcp_flags = flags; ++ TCP_SKB_CB(buff)->path_mask = TCP_SKB_CB(skb)->path_mask; ++ ++ /* If reinject == 1, the buff will be added to the reinject ++ * queue, which is currently not part of memory accounting. So ++ * undo the changes done by tcp_fragment and update the ++ * reinject queue. Also, undo changes to the packet counters. ++ */ ++ if (reinject == 1) { ++ int undo = buff->truesize - diff; ++ meta_sk->sk_wmem_queued -= undo; ++ sk_mem_uncharge(meta_sk, undo); ++ ++ tcp_sk(meta_sk)->mpcb->reinject_queue.qlen++; ++ meta_sk->sk_write_queue.qlen--; ++ ++ if (!before(tcp_sk(meta_sk)->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { ++ undo = old_factor - tcp_skb_pcount(skb) - ++ tcp_skb_pcount(buff); ++ if (undo) ++ tcp_adjust_pcount(meta_sk, skb, -undo); ++ } ++ } ++ ++ return 0; ++} ++ ++/* Inspired by tcp_write_wakeup */ ++int mptcp_write_wakeup(struct sock *meta_sk, int mib) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ struct sock *sk_it; ++ int ans = 0; ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return -1; ++ ++ skb = tcp_send_head(meta_sk); ++ if (skb && ++ before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(meta_tp))) { ++ unsigned int mss; ++ unsigned int seg_size = tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq; ++ struct sock *subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, true); ++ struct tcp_sock *subtp; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ if (!subsk) ++ goto window_probe; ++ subtp = tcp_sk(subsk); ++ mss = tcp_current_mss(subsk); ++ ++ seg_size = min(tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq, ++ tcp_wnd_end(subtp) - subtp->write_seq); ++ ++ if (before(meta_tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) ++ meta_tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ /* We are probing the opening of a window ++ * but the window size is != 0 ++ * must have been a result SWS avoidance ( sender ) ++ */ ++ if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || ++ skb->len > mss) { ++ seg_size = min(seg_size, mss); ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (mptcp_fragment(meta_sk, skb, seg_size, ++ GFP_ATOMIC, 0)) ++ return -1; ++ } else if (!tcp_skb_pcount(skb)) { ++ /* see mptcp_write_xmit on why we use UINT_MAX */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ } ++ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (!mptcp_skb_entail(subsk, skb, 0)) ++ return -1; ++ ++ mptcp_check_sndseq_wrap(meta_tp, TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ ++ __tcp_push_pending_frames(subsk, mss, TCP_NAGLE_PUSH); ++ skb->skb_mstamp = meta_tp->tcp_mstamp; ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ } else { ++window_probe: ++ if (between(meta_tp->snd_up, meta_tp->snd_una + 1, ++ meta_tp->snd_una + 0xFFFF)) { ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ if (mptcp_sk_can_send_ack(sk_it)) ++ tcp_xmit_probe_skb(sk_it, 1, mib); ++ } ++ } ++ ++ /* At least one of the tcp_xmit_probe_skb's has to succeed */ ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ int ret; ++ ++ if (!mptcp_sk_can_send_ack(sk_it)) ++ continue; ++ ++ ret = tcp_xmit_probe_skb(sk_it, 0, mib); ++ if (unlikely(ret > 0)) ++ ans = ret; ++ } ++ return ans; ++ } ++} ++ ++bool mptcp_write_xmit(struct sock *meta_sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *subtp; ++ struct sock *subsk = NULL; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int reinject = 0; ++ unsigned int sublimit; ++ __u32 path_mask = 0; ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ if (inet_csk(meta_sk)->icsk_retransmits) { ++ /* If the timer already once fired, retransmit the head of the ++ * queue to unblock us ASAP. ++ */ ++ if (meta_tp->packets_out && !mpcb->infinite_mapping_snd) ++ mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ } ++ ++ while ((skb = mpcb->sched_ops->next_segment(meta_sk, &reinject, &subsk, ++ &sublimit))) { ++ unsigned int limit; ++ ++ WARN(TCP_SKB_CB(skb)->sacked, "sacked: %u reinject: %u", ++ TCP_SKB_CB(skb)->sacked, reinject); ++ ++ subtp = tcp_sk(subsk); ++ mss_now = tcp_current_mss(subsk); ++ ++ if (reinject == 1) { ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ /* Segment already reached the peer, take the next one */ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ continue; ++ } ++ } ++ ++ /* If the segment was cloned (e.g. a meta retransmission), ++ * the header must be expanded/copied so that there is no ++ * corruption of TSO information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ break; ++ ++ if (unlikely(!tcp_snd_wnd_test(meta_tp, skb, mss_now))) ++ break; ++ ++ /* Force tso_segs to 1 by using UINT_MAX. ++ * We actually don't care about the exact number of segments ++ * emitted on the subflow. We need just to set tso_segs, because ++ * we still need an accurate packets_out count in ++ * tcp_event_new_data_sent. ++ */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ ++ /* Check for nagle, irregardless of tso_segs. If the segment is ++ * actually larger than mss_now (TSO segment), then ++ * tcp_nagle_check will have partial == false and always trigger ++ * the transmission. ++ * tcp_write_xmit has a TSO-level nagle check which is not ++ * subject to the MPTCP-level. It is based on the properties of ++ * the subflow, not the MPTCP-level. ++ */ ++ if (unlikely(!tcp_nagle_test(meta_tp, skb, mss_now, ++ (tcp_skb_is_last(meta_sk, skb) ? ++ nonagle : TCP_NAGLE_PUSH)))) ++ break; ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ /* We limit the size of the skb so that it fits into the ++ * window. Call tcp_mss_split_point to avoid duplicating ++ * code. ++ * We really only care about fitting the skb into the ++ * window. That's why we use UINT_MAX. If the skb does ++ * not fit into the cwnd_quota or the NIC's max-segs ++ * limitation, it will be split by the subflow's ++ * tcp_write_xmit which does the appropriate call to ++ * tcp_mss_split_point. ++ */ ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ nonagle); ++ ++ if (sublimit) ++ limit = min(limit, sublimit); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, skb, limit, gfp, reinject))) ++ break; ++ ++ if (!mptcp_skb_entail(subsk, skb, reinject)) ++ break; ++ /* Nagle is handled at the MPTCP-layer, so ++ * always push on the subflow ++ */ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ skb->skb_mstamp = meta_tp->tcp_mstamp; ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ path_mask |= mptcp_pi_to_flag(subtp->mptcp->path_index); ++ ++ if (!reinject) { ++ mptcp_check_sndseq_wrap(meta_tp, ++ TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ } ++ ++ tcp_minshall_update(meta_tp, mss_now, skb); ++ ++ if (reinject > 0) { ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ kfree_skb(skb); ++ } ++ ++ if (push_one) ++ break; ++ } ++ ++ mptcp_for_each_sk(mpcb, subsk) { ++ subtp = tcp_sk(subsk); ++ ++ if (!(path_mask & mptcp_pi_to_flag(subtp->mptcp->path_index))) ++ continue; ++ ++ /* We have pushed data on this subflow. We ignore the call to ++ * cwnd_validate in tcp_write_xmit as is_cwnd_limited will never ++ * be true (we never push more than what the cwnd can accept). ++ * We need to ensure that we call tcp_cwnd_validate with ++ * is_cwnd_limited set to true if we have filled the cwnd. ++ */ ++ tcp_cwnd_validate(subsk, tcp_packets_in_flight(subtp) >= ++ subtp->snd_cwnd); ++ } ++ ++ return !meta_tp->packets_out && tcp_send_head(meta_sk); ++} ++ ++void mptcp_write_space(struct sock *sk) ++{ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++} ++ ++u32 __mptcp_select_window(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ int mss, free_space, full_space, window; ++ ++ /* MSS for the peer's data. Previous versions used mss_clamp ++ * here. I don't know if the value based on our guesses ++ * of peer's MSS is better for the performance. It's more correct ++ * but may be worse for the performance because of rcv_mss ++ * fluctuations. --SAW 1998/11/1 ++ */ ++ mss = icsk->icsk_ack.rcv_mss; ++ free_space = tcp_space(meta_sk); ++ full_space = min_t(int, meta_tp->window_clamp, ++ tcp_full_space(meta_sk)); ++ ++ if (mss > full_space) ++ mss = full_space; ++ ++ if (free_space < (full_space >> 1)) { ++ /* If free_space is decreasing due to mostly meta-level ++ * out-of-order packets, don't turn off the quick-ack mode. ++ */ ++ if (meta_tp->rcv_nxt - meta_tp->copied_seq > ((full_space - free_space) >> 1)) ++ icsk->icsk_ack.quick = 0; ++ ++ if (tcp_memory_pressure) ++ /* TODO this has to be adapted when we support different ++ * MSS's among the subflows. ++ */ ++ meta_tp->rcv_ssthresh = min(meta_tp->rcv_ssthresh, ++ 4U * meta_tp->advmss); ++ ++ if (free_space < mss) ++ return 0; ++ } ++ ++ if (free_space > meta_tp->rcv_ssthresh) ++ free_space = meta_tp->rcv_ssthresh; ++ ++ /* Don't do rounding if we are using window scaling, since the ++ * scaled window will not line up with the MSS boundary anyway. ++ */ ++ window = meta_tp->rcv_wnd; ++ if (tp->rx_opt.rcv_wscale) { ++ window = free_space; ++ ++ /* Advertise enough space so that it won't get scaled away. ++ * Import case: prevent zero window announcement if ++ * 1< mss. ++ */ ++ if (((window >> tp->rx_opt.rcv_wscale) << tp-> ++ rx_opt.rcv_wscale) != window) ++ window = (((window >> tp->rx_opt.rcv_wscale) + 1) ++ << tp->rx_opt.rcv_wscale); ++ } else { ++ /* Get the largest window that is a nice multiple of mss. ++ * Window clamp already applied above. ++ * If our current window offering is within 1 mss of the ++ * free space we just keep it. This prevents the divide ++ * and multiply from happening most of the time. ++ * We also don't do any window rounding when the free space ++ * is too small. ++ */ ++ if (window <= free_space - mss || window > free_space) ++ window = (free_space / mss) * mss; ++ else if (mss == full_space && ++ free_space > window + (full_space >> 1)) ++ window = free_space; ++ } ++ ++ return window; ++} ++ ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ opts->options |= OPTION_MPTCP; ++ if (is_master_tp(tp)) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYN; ++ opts->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ opts->mp_capable.sender_key = tp->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum; ++ } else { ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYN; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYN_ALIGN; ++ opts->mp_join_syns.token = mpcb->mptcp_rem_token; ++ opts->mp_join_syns.low_prio = tp->mptcp->low_prio; ++ opts->addr_id = tp->mptcp->loc_id; ++ opts->mp_join_syns.sender_nonce = tp->mptcp->mptcp_loc_nonce; ++ } ++} ++ ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, unsigned *remaining) ++{ ++ struct mptcp_request_sock *mtreq; ++ mtreq = mptcp_rsk(req); ++ ++ opts->options |= OPTION_MPTCP; ++ /* MPCB not yet set - thus it's a new MPTCP-session */ ++ if (!mtreq->is_sub) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYNACK; ++ opts->mptcp_ver = mtreq->mptcp_ver; ++ opts->mp_capable.sender_key = mtreq->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum || mtreq->dss_csum; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ } else { ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYNACK; ++ opts->mp_join_syns.sender_truncated_mac = ++ mtreq->mptcp_hash_tmac; ++ opts->mp_join_syns.sender_nonce = mtreq->mptcp_loc_nonce; ++ opts->mp_join_syns.low_prio = mtreq->low_prio; ++ opts->addr_id = mtreq->loc_id; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN; ++ } ++} ++ ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ const struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL; ++ ++ /* We are coming from tcp_current_mss with the meta_sk as an argument. ++ * It does not make sense to check for the options, because when the ++ * segment gets sent, another subflow will be chosen. ++ */ ++ if (!skb && is_meta_sk(sk)) ++ return; ++ ++ if (unlikely(tp->send_mp_fclose)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FCLOSE; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ *size += MPTCP_SUB_LEN_FCLOSE_ALIGN; ++ return; ++ } ++ ++ /* 1. If we are the sender of the infinite-mapping, we need the ++ * MPTCPHDR_INF-flag, because a retransmission of the ++ * infinite-announcment still needs the mptcp-option. ++ * ++ * We need infinite_cutoff_seq, because retransmissions from before ++ * the infinite-cutoff-moment still need the MPTCP-signalling to stay ++ * consistent. ++ * ++ * 2. If we are the receiver of the infinite-mapping, we always skip ++ * mptcp-options, because acknowledgments from before the ++ * infinite-mapping point have already been sent out. ++ * ++ * I know, the whole infinite-mapping stuff is ugly... ++ * ++ * TODO: Handle wrapped data-sequence numbers ++ * (even if it's very unlikely) ++ */ ++ if (unlikely(mpcb->infinite_mapping_snd) && ++ ((mpcb->send_infinite_mapping && tcb && ++ mptcp_is_data_seq(skb) && ++ !(tcb->mptcp_flags & MPTCPHDR_INF) && ++ !before(tcb->seq, tp->mptcp->infinite_cutoff_seq)) || ++ !mpcb->send_infinite_mapping)) ++ return; ++ ++ if (unlikely(tp->mptcp->include_mpc)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_CAPABLE | ++ OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN; ++ opts->mptcp_ver = mpcb->mptcp_ver; ++ opts->mp_capable.sender_key = mpcb->mptcp_loc_key; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ opts->dss_csum = mpcb->dss_csum; ++ ++ if (skb) ++ tp->mptcp->include_mpc = 0; ++ } ++ if (unlikely(tp->mptcp->pre_established) && ++ (!skb || !(tcb->tcp_flags & (TCPHDR_FIN | TCPHDR_RST)))) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_JOIN_ACK_ALIGN; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (opts->add_addr_v6) ++ /* Skip subsequent options */ ++ return; ++ } ++ ++ if (!tp->mptcp->include_mpc && !tp->mptcp->pre_established) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_DATA_ACK; ++ /* If !skb, we come from tcp_current_mss and thus we always ++ * assume that the DSS-option will be set for the data-packet. ++ */ ++ if (skb && !mptcp_is_data_seq(skb)) { ++ *size += MPTCP_SUB_LEN_ACK_ALIGN; ++ } else { ++ /* Doesn't matter, if csum included or not. It will be ++ * either 10 or 12, and thus aligned = 12 ++ */ ++ *size += MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ } ++ ++ *size += MPTCP_SUB_LEN_DSS_ALIGN; ++ } ++ ++ /* In fallback mp_fail-mode, we have to repeat it until the fallback ++ * has been done by the sender ++ */ ++ if (unlikely(tp->mptcp->send_mp_fail) && skb && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_FAIL) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FAIL; ++ *size += MPTCP_SUB_LEN_FAIL; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver < MPTCP_VERSION_1) ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (unlikely(tp->mptcp->send_mp_prio) && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_PRIO_ALIGN) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_PRIO; ++ if (skb) ++ tp->mptcp->send_mp_prio = 0; ++ *size += MPTCP_SUB_LEN_PRIO_ALIGN; ++ } ++ ++ return; ++} ++ ++u16 mptcp_select_window(struct sock *sk) ++{ ++ u16 new_win = tcp_select_window(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *meta_tp = mptcp_meta_tp(tp); ++ ++ meta_tp->rcv_wnd = tp->rcv_wnd; ++ meta_tp->rcv_wup = meta_tp->rcv_nxt; ++ ++ return new_win; ++} ++ ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ if (unlikely(OPTION_MP_CAPABLE & opts->mptcp_options)) { ++ struct mp_capable *mpc = (struct mp_capable *)ptr; ++ ++ mpc->kind = TCPOPT_MPTCP; ++ ++ if ((OPTION_TYPE_SYN & opts->mptcp_options) || ++ (OPTION_TYPE_SYNACK & opts->mptcp_options)) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_SYN; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->receiver_key = opts->mp_capable.receiver_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_ACK; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN >> 2; ++ } ++ ++ mpc->sub = MPTCP_SUB_CAPABLE; ++ mpc->a = opts->dss_csum; ++ mpc->b = 0; ++ mpc->rsv = 0; ++ mpc->h = 1; ++ } ++ if (unlikely(OPTION_MP_JOIN & opts->mptcp_options)) { ++ struct mp_join *mpj = (struct mp_join *)ptr; ++ ++ mpj->kind = TCPOPT_MPTCP; ++ mpj->sub = MPTCP_SUB_JOIN; ++ mpj->rsv = 0; ++ ++ if (OPTION_TYPE_SYN & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYN; ++ mpj->u.syn.token = opts->mp_join_syns.token; ++ mpj->u.syn.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_SYNACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYNACK; ++ mpj->u.synack.mac = ++ opts->mp_join_syns.sender_truncated_mac; ++ mpj->u.synack.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_ACK; ++ mpj->addr_id = 0; /* addr_id is rsv (RFC 6824, p. 21) */ ++ memcpy(mpj->u.ack.mac, &tp->mptcp->sender_mac[0], 20); ++ ptr += MPTCP_SUB_LEN_JOIN_ACK_ALIGN >> 2; ++ } ++ } ++ if (unlikely(OPTION_ADD_ADDR & opts->mptcp_options)) { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mpadd->kind = TCPOPT_MPTCP; ++ if (opts->add_addr_v4) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 4; ++ mpadd->addr_id = opts->add_addr4.addr_id; ++ mpadd->u.v4.addr = opts->add_addr4.addr; ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v4.mac - 2, ++ (char *)&opts->add_addr4.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 >> 2; ++ } ++ } else if (opts->add_addr_v6) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 6; ++ mpadd->addr_id = opts->add_addr6.addr_id; ++ memcpy(&mpadd->u.v6.addr, &opts->add_addr6.addr, ++ sizeof(mpadd->u.v6.addr)); ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v6.mac - 2, ++ (char *)&opts->add_addr6.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 >> 2; ++ } ++ } ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_ADDADDRTX); ++ } ++ if (unlikely(OPTION_REMOVE_ADDR & opts->mptcp_options)) { ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ u8 *addrs_id; ++ int id, len, len_align; ++ ++ len = mptcp_sub_len_remove_addr(opts->remove_addrs); ++ len_align = mptcp_sub_len_remove_addr_align(opts->remove_addrs); ++ ++ mprem->kind = TCPOPT_MPTCP; ++ mprem->len = len; ++ mprem->sub = MPTCP_SUB_REMOVE_ADDR; ++ mprem->rsv = 0; ++ addrs_id = &mprem->addrs_id; ++ ++ mptcp_for_each_bit_set(opts->remove_addrs, id) ++ *(addrs_id++) = id; ++ ++ /* Fill the rest with NOP's */ ++ if (len_align > len) { ++ int i; ++ for (i = 0; i < len_align - len; i++) ++ *(addrs_id++) = TCPOPT_NOP; ++ } ++ ++ ptr += len_align >> 2; ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_REMADDRTX); ++ } ++ if (unlikely(OPTION_MP_FAIL & opts->mptcp_options)) { ++ struct mp_fail *mpfail = (struct mp_fail *)ptr; ++ ++ mpfail->kind = TCPOPT_MPTCP; ++ mpfail->len = MPTCP_SUB_LEN_FAIL; ++ mpfail->sub = MPTCP_SUB_FAIL; ++ mpfail->rsv1 = 0; ++ mpfail->rsv2 = 0; ++ mpfail->data_seq = htonll(tp->mpcb->csum_cutoff_seq); ++ ++ ptr += MPTCP_SUB_LEN_FAIL_ALIGN >> 2; ++ } ++ if (unlikely(OPTION_MP_FCLOSE & opts->mptcp_options)) { ++ struct mp_fclose *mpfclose = (struct mp_fclose *)ptr; ++ ++ mpfclose->kind = TCPOPT_MPTCP; ++ mpfclose->len = MPTCP_SUB_LEN_FCLOSE; ++ mpfclose->sub = MPTCP_SUB_FCLOSE; ++ mpfclose->rsv1 = 0; ++ mpfclose->rsv2 = 0; ++ mpfclose->key = opts->mp_capable.receiver_key; ++ ++ ptr += MPTCP_SUB_LEN_FCLOSE_ALIGN >> 2; ++ } ++ ++ if (OPTION_DATA_ACK & opts->mptcp_options) { ++ if (!mptcp_is_data_seq(skb)) ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ else ++ ptr += mptcp_write_dss_data_seq(tp, skb, ptr); ++ } ++ if (unlikely(OPTION_MP_PRIO & opts->mptcp_options)) { ++ struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ mpprio->kind = TCPOPT_MPTCP; ++ mpprio->len = MPTCP_SUB_LEN_PRIO; ++ mpprio->sub = MPTCP_SUB_PRIO; ++ mpprio->rsv = 0; ++ mpprio->b = tp->mptcp->low_prio; ++ mpprio->addr_id = TCPOPT_NOP; ++ ++ ptr += MPTCP_SUB_LEN_PRIO_ALIGN >> 2; ++ } ++} ++ ++/* Sends the datafin */ ++void mptcp_send_fin(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb = tcp_write_queue_tail(meta_sk); ++ int mss_now; ++ ++ if ((1 << meta_sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK)) ++ meta_tp->mpcb->passive_close = 1; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = mptcp_current_mss(meta_sk); ++ ++ if (tcp_send_head(meta_sk) != NULL) { ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ meta_tp->write_seq++; ++ } else { ++ /* Socket is locked, keep trying until memory is available. */ ++ for (;;) { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, ++ meta_sk->sk_allocation); ++ if (skb) ++ break; ++ yield(); ++ } ++ /* Reserve space for headers and prepare control bits. */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ ++ tcp_init_nondata_skb(skb, meta_tp->write_seq, TCPHDR_ACK); ++ TCP_SKB_CB(skb)->end_seq++; ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ tcp_queue_skb(meta_sk, skb); ++ } ++ __tcp_push_pending_frames(meta_sk, mss_now, TCP_NAGLE_OFF); ++} ++ ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ ++ if (!mpcb->cnt_subflows) ++ return; ++ ++ WARN_ON(meta_tp->send_mp_fclose); ++ ++ /* First - select a socket */ ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ /* May happen if no subflow is in an appropriate state, OR ++ * we are in infinite mode or about to go there - just send a reset ++ */ ++ if (!sk || mptcp_in_infinite_mapping_weak(mpcb)) { ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ return; ++ } ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ tcp_sk(sk)->send_mp_fclose = 1; ++ /** Reset all other subflows */ ++ ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ tcp_set_state(sk, TCP_RST_WAIT); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ ++ tcp_send_ack(sk); ++ tcp_clear_xmit_timers(sk); ++ inet_csk_reset_keepalive_timer(sk, inet_csk(sk)->icsk_rto); ++ ++ meta_tp->send_mp_fclose = 1; ++ inet_csk(sk)->icsk_retransmits = 0; ++ ++ /* Prevent exp backoff reverting on ICMP dest unreachable */ ++ inet_csk(sk)->icsk_backoff = 0; ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_FASTCLOSETX); ++} ++ ++static void mptcp_ack_retransmit_timer(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ struct sk_buff *skb; ++ ++ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) ++ goto out; /* Routing failure or similar */ ++ ++ tcp_mstamp_refresh(tp); ++ ++ if (tcp_write_timeout(sk)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRTO); ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ goto out; ++ } ++ ++ skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (skb == NULL) { ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ /* Reserve space for headers and prepare control bits */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ tcp_init_nondata_skb(skb, tp->snd_una, TCPHDR_ACK); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRXMIT); ++ ++ if (tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC) > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!icsk->icsk_retransmits) ++ icsk->icsk_retransmits = 1; ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ if (!tp->retrans_stamp) ++ tp->retrans_stamp = tcp_time_stamp(tp) ? : 1; ++ ++ icsk->icsk_retransmits++; ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0)) ++ __sk_dst_reset(sk); ++ ++out:; ++} ++ ++void mptcp_ack_handler(unsigned long data) ++{ ++ struct sock *sk = (struct sock *)data; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ /* Try again later */ ++ sk_reset_timer(sk, &tcp_sk(sk)->mptcp->mptcp_ack_timer, ++ jiffies + (HZ / 20)); ++ goto out_unlock; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) ++ goto out_unlock; ++ if (!tcp_sk(sk)->mptcp->pre_established) ++ goto out_unlock; ++ ++ mptcp_ack_retransmit_timer(sk); ++ ++ sk_mem_reclaim(sk); ++ ++out_unlock: ++ bh_unlock_sock(meta_sk); ++ sock_put(sk); ++} ++ ++/* Similar to tcp_retransmit_skb ++ * ++ * The diff is that we handle the retransmission-stats (retrans_stamp) at the ++ * meta-level. ++ */ ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk; ++ unsigned int limit, mss_now; ++ int err = -1; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ /* Do not sent more than we queued. 1/4 is reserved for possible ++ * copying overhead: fragmentation, tunneling, mangling etc. ++ * ++ * This is a meta-retransmission thus we check on the meta-socket. ++ */ ++ if (refcount_read(&meta_sk->sk_wmem_alloc) > ++ min(meta_sk->sk_wmem_queued + (meta_sk->sk_wmem_queued >> 2), meta_sk->sk_sndbuf)) { ++ return -EAGAIN; ++ } ++ ++ /* We need to make sure that the retransmitted segment can be sent on a ++ * subflow right now. If it is too big, it needs to be fragmented. ++ */ ++ subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, false); ++ if (!subsk) { ++ /* We want to increase icsk_retransmits, thus return 0, so that ++ * mptcp_meta_retransmit_timer enters the desired branch. ++ */ ++ err = 0; ++ goto failed; ++ } ++ mss_now = tcp_current_mss(subsk); ++ ++ /* If the segment was cloned (e.g. a meta retransmission), the header ++ * must be expanded/copied so that there is no corruption of TSO ++ * information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Must have been set by mptcp_write_xmit before */ ++ BUG_ON(!tcp_skb_pcount(skb)); ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ TCP_NAGLE_OFF); ++ ++ limit = min(limit, tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, skb, limit, ++ GFP_ATOMIC, 0))) ++ goto failed; ++ ++ if (!mptcp_skb_entail(subsk, skb, -1)) ++ goto failed; ++ ++ /* Update global TCP statistics. */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_RETRANSSEGS); ++ ++ /* Diff to tcp_retransmit_skb */ ++ ++ /* Save stamp of the first retransmit. */ ++ if (!meta_tp->retrans_stamp) { ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->retrans_stamp = tcp_time_stamp(meta_tp); ++ } ++ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ skb->skb_mstamp = meta_tp->tcp_mstamp; ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ ++failed: ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPRETRANSFAIL); ++ return err; ++} ++ ++/* Similar to tcp_retransmit_timer ++ * ++ * The diff is that we have to handle retransmissions of the FAST_CLOSE-message ++ * and that we don't have an srtt estimation at the meta-level. ++ */ ++void mptcp_meta_retransmit_timer(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ int err; ++ ++ /* In fallback, retransmission is handled at the subflow-level */ ++ if (!meta_tp->packets_out || mpcb->infinite_mapping_snd) ++ return; ++ ++ WARN_ON(tcp_write_queue_empty(meta_sk)); ++ ++ if (!meta_tp->snd_wnd && !sock_flag(meta_sk, SOCK_DEAD) && ++ !((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { ++ /* Receiver dastardly shrinks window. Our retransmits ++ * become zero probes, but we should not timeout this ++ * connection. If the socket is an orphan, time it out, ++ * we cannot allow such beasts to hang infinitely. ++ */ ++ struct inet_sock *meta_inet = inet_sk(meta_sk); ++ if (meta_sk->sk_family == AF_INET) { ++ net_dbg_ratelimited("MPTCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_inet->inet_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (meta_sk->sk_family == AF_INET6) { ++ net_dbg_ratelimited("MPTCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_sk->sk_v6_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#endif ++ if (tcp_jiffies32 - meta_tp->rcv_tstamp > TCP_RTO_MAX) { ++ tcp_write_err(meta_sk); ++ return; ++ } ++ ++ mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ goto out_reset_timer; ++ } ++ ++ if (tcp_write_timeout(meta_sk)) ++ return; ++ ++ if (meta_icsk->icsk_retransmits == 0) ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPTIMEOUTS); ++ ++ meta_icsk->icsk_ca_state = TCP_CA_Loss; ++ ++ err = mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ if (err > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!meta_icsk->icsk_retransmits) ++ meta_icsk->icsk_retransmits = 1; ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ min(meta_icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), ++ TCP_RTO_MAX); ++ return; ++ } ++ ++ /* Increase the timeout each time we retransmit. Note that ++ * we do not increase the rtt estimate. rto is initialized ++ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests ++ * that doubling rto each time is the least we can get away with. ++ * In KA9Q, Karn uses this for the first few times, and then ++ * goes to quadratic. netBSD doubles, but only goes up to *64, ++ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is ++ * defined in the protocol as the maximum possible RTT. I guess ++ * we'll have to use something other than TCP to talk to the ++ * University of Mars. ++ * ++ * PAWS allows us longer timeouts and large windows, so once ++ * implemented ftp to mars will work nicely. We will have to fix ++ * the 120 second clamps though! ++ */ ++ meta_icsk->icsk_backoff++; ++ meta_icsk->icsk_retransmits++; ++ ++out_reset_timer: ++ /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is ++ * used to reset timer, set to 0. Recalculate 'icsk_rto' as this ++ * might be increased if the stream oscillates between thin and thick, ++ * thus the old value might already be too high compared to the value ++ * set by 'tcp_set_rto' in tcp_input.c which resets the rto without ++ * backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating ++ * exponential backoff behaviour to avoid continue hammering ++ * linear-timeout retransmissions into a black hole ++ */ ++ if (meta_sk->sk_state == TCP_ESTABLISHED && ++ (meta_tp->thin_lto || sysctl_tcp_thin_linear_timeouts) && ++ tcp_stream_is_thin(meta_tp) && ++ meta_icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { ++ meta_icsk->icsk_backoff = 0; ++ /* We cannot do the same as in tcp_write_timer because the ++ * srtt is not set here. ++ */ ++ mptcp_set_rto(meta_sk); ++ } else { ++ /* Use normal (exponential) backoff */ ++ meta_icsk->icsk_rto = min(meta_icsk->icsk_rto << 1, TCP_RTO_MAX); ++ } ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, meta_icsk->icsk_rto, TCP_RTO_MAX); ++ ++ return; ++} ++ ++void mptcp_sub_retransmit_timer(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_retransmit_timer(sk); ++ ++ if (!tp->fastopen_rsk) { ++ mptcp_reinject_data(sk, 1); ++ mptcp_set_rto(sk); ++ } ++} ++ ++/* Modify values to an mptcp-level for the initial window of new subflows */ ++void mptcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ *window_clamp = mpcb->orig_window_clamp; ++ __space = tcp_win_from_space(mpcb->orig_sk_rcvbuf); ++ ++ tcp_select_initial_window(__space, mss, rcv_wnd, window_clamp, ++ wscale_ok, rcv_wscale, init_rcv_wnd, sk); ++} ++ ++static inline u64 mptcp_calc_rate(const struct sock *meta_sk, unsigned int mss, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ struct sock *sk; ++ u64 rate = 0; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ /* Do not consider subflows without a RTT estimation yet ++ * otherwise this_rate >>> rate. ++ */ ++ if (unlikely(!tp->srtt_us)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* If this_mss is smaller than mss, it means that a segment will ++ * be splitted in two (or more) when pushed on this subflow. If ++ * you consider that mss = 1428 and this_mss = 1420 then two ++ * segments will be generated: a 1420-byte and 8-byte segment. ++ * The latter will introduce a large overhead as for a single ++ * data segment 2 slots will be used in the congestion window. ++ * Therefore reducing by ~2 the potential throughput of this ++ * subflow. Indeed, 1428 will be send while 2840 could have been ++ * sent if mss == 1420 reducing the throughput by 2840 / 1428. ++ * ++ * The following algorithm take into account this overhead ++ * when computing the potential throughput that MPTCP can ++ * achieve when generating mss-byte segments. ++ * ++ * The formulae is the following: ++ * \sum_{\forall sub} ratio * \frac{mss * cwnd_sub}{rtt_sub} ++ * Where ratio is computed as follows: ++ * \frac{mss}{\ceil{mss / mss_sub} * mss_sub} ++ * ++ * ratio gives the reduction factor of the theoretical ++ * throughput a subflow can achieve if MPTCP uses a specific ++ * MSS value. ++ */ ++ this_rate = div64_u64((u64)mss * mss * (USEC_PER_SEC << 3) * ++ max(tp->snd_cwnd, tp->packets_out), ++ (u64)tp->srtt_us * ++ DIV_ROUND_UP(mss, this_mss) * this_mss); ++ rate += this_rate; ++ } ++ ++ return rate; ++} ++ ++static unsigned int __mptcp_current_mss(const struct sock *meta_sk, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ unsigned int mss = 0; ++ u64 rate = 0; ++ struct sock *sk; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* Same mss values will produce the same throughput. */ ++ if (this_mss == mss) ++ continue; ++ ++ /* See whether using this mss value can theoretically improve ++ * the performances. ++ */ ++ this_rate = mptcp_calc_rate(meta_sk, this_mss, mss_cb); ++ if (this_rate >= rate) { ++ mss = this_mss; ++ rate = this_rate; ++ } ++ } ++ ++ return mss; ++} ++ ++unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, tcp_current_mss); ++ ++ /* If no subflow is available, we take a default-mss from the ++ * meta-socket. ++ */ ++ return !mss ? tcp_current_mss(meta_sk) : mss; ++} ++ ++static unsigned int mptcp_select_size_mss(struct sock *sk) ++{ ++ return tcp_sk(sk)->mss_cache; ++} ++ ++int mptcp_select_size(const struct sock *meta_sk, bool sg, bool first_skb) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, mptcp_select_size_mss); ++ ++ if (sg) { ++ if (mptcp_sk_can_gso(meta_sk)) { ++ mss = linear_payload_sz(first_skb); ++ } else { ++ int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); ++ ++ if (mss >= pgbreak && ++ mss <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE) ++ mss = pgbreak; ++ } ++ } ++ ++ return !mss ? tcp_sk(meta_sk)->mss_cache : mss; ++} ++ ++int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ const struct sock *sk; ++ u32 rtt_max = tp->srtt_us; ++ u64 bw_est; ++ ++ if (!tp->srtt_us) ++ return tp->reordering + 1; ++ ++ mptcp_for_each_sk(tp->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->srtt_us) ++ rtt_max = tcp_sk(sk)->srtt_us; ++ } ++ ++ bw_est = div64_u64(((u64)tp->snd_cwnd * rtt_max) << 16, ++ (u64)tp->srtt_us); ++ ++ return max_t(unsigned int, (u32)(bw_est >> 16), ++ tp->reordering + 1); ++} ++ ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed) ++{ ++ struct sock *sk; ++ u32 xmit_size_goal = 0; ++ ++ if (large_allowed && mptcp_sk_can_gso(meta_sk)) { ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ int this_size_goal; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_size_goal = tcp_xmit_size_goal(sk, mss_now, 1); ++ if (this_size_goal > xmit_size_goal) ++ xmit_size_goal = this_size_goal; ++ } ++ } ++ ++ return max(xmit_size_goal, mss_now); ++} ++ +diff -aurN linux-4.14.174/net/mptcp/mptcp_pm.c mptcp-mptcp_v0.94/net/mptcp/mptcp_pm.c +--- linux-4.14.174/net/mptcp/mptcp_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_pm.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,226 @@ ++/* ++ * MPTCP implementation - MPTCP-subflow-management ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_pm_list_lock); ++static LIST_HEAD(mptcp_pm_list); ++ ++static int mptcp_default_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++struct mptcp_pm_ops mptcp_pm_default = { ++ .get_local_id = mptcp_default_id, /* We do not care */ ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_pm_ops *mptcp_pm_find(const char *name) ++{ ++ struct mptcp_pm_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_pm_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm) ++{ ++ int ret = 0; ++ ++ if (!pm->get_local_id) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ if (mptcp_pm_find(pm->name)) { ++ pr_notice("%s already registered\n", pm->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&pm->list, &mptcp_pm_list); ++ pr_info("%s registered\n", pm->name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_path_manager); ++ ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm) ++{ ++ spin_lock(&mptcp_pm_list_lock); ++ list_del_rcu(&pm->list); ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_path_manager); ++ ++void mptcp_get_default_path_manager(char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ BUG_ON(list_empty(&mptcp_pm_list)); ++ ++ rcu_read_lock(); ++ pm = list_entry(mptcp_pm_list.next, struct mptcp_pm_ops, list); ++ strncpy(name, pm->name, MPTCP_PM_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_path_manager(const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ ++ if (pm) { ++ list_move(&pm->list, &mptcp_pm_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops *__mptcp_pm_find_autoload(const char *name) ++{ ++ struct mptcp_pm_ops *pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ return pm; ++} ++ ++void mptcp_init_path_manager(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if path manager was set using socket option */ ++ if (meta_tp->mptcp_pm_setsockopt) { ++ pm = __mptcp_pm_find_autoload(meta_tp->mptcp_pm_name); ++ if (pm && try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(pm, &mptcp_pm_list, list) { ++ if (try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change path manager for socket */ ++int mptcp_set_path_manager(struct sock *sk, const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int err = 0; ++ ++ rcu_read_lock(); ++ pm = __mptcp_pm_find_autoload(name); ++ ++ if (!pm) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_pm_name, name); ++ tcp_sk(sk)->mptcp_pm_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->pm_ops->owner); ++} ++ ++/* Fallback to the default path-manager. */ ++void mptcp_fallback_default(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ mptcp_cleanup_path_manager(mpcb); ++ pm = mptcp_pm_find("default"); ++ ++ /* Cannot fail - it's the default module */ ++ try_module_get(pm->owner); ++ mpcb->pm_ops = pm; ++} ++EXPORT_SYMBOL_GPL(mptcp_fallback_default); ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_path_manager_default(void) ++{ ++ return mptcp_set_default_path_manager(CONFIG_DEFAULT_MPTCP_PM); ++} ++late_initcall(mptcp_path_manager_default); +diff -aurN linux-4.14.174/net/mptcp/mptcp_redundant.c mptcp-mptcp_v0.94/net/mptcp/mptcp_redundant.c +--- linux-4.14.174/net/mptcp/mptcp_redundant.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_redundant.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,301 @@ ++/* ++ * MPTCP Scheduler to reduce latency and jitter. ++ * ++ * This scheduler sends all packets redundantly on all available subflows. ++ * ++ * Initial Design & Implementation: ++ * Tobias Erbshaeusser ++ * Alexander Froemmgen ++ * ++ * Initial corrections & modifications: ++ * Christian Pinedo ++ * Igor Lopez ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++/* Struct to store the data of a single subflow */ ++struct redsched_sock_data { ++ /* The skb or NULL */ ++ struct sk_buff *skb; ++ /* End sequence number of the skb. This number should be checked ++ * to be valid before the skb field is used ++ */ ++ u32 skb_end_seq; ++}; ++ ++/* Struct to store the data of the control block */ ++struct redsched_cb_data { ++ /* The next subflow where a skb should be sent or NULL */ ++ struct tcp_sock *next_subflow; ++}; ++ ++/* Returns the socket data from a given subflow socket */ ++static struct redsched_sock_data *redsched_get_sock_data(struct tcp_sock *tp) ++{ ++ return (struct redsched_sock_data *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* Returns the control block data from a given meta socket */ ++static struct redsched_cb_data *redsched_get_cb_data(struct tcp_sock *tp) ++{ ++ return (struct redsched_cb_data *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static bool redsched_get_active_valid_sks(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ int active_valid_sks = 0; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ if (subflow_is_active((struct tcp_sock *)sk) && ++ !mptcp_is_def_unavailable(sk)) ++ active_valid_sks++; ++ } ++ ++ return active_valid_sks; ++} ++ ++static bool redsched_use_subflow(struct sock *meta_sk, ++ int active_valid_sks, ++ struct tcp_sock *tp, ++ struct sk_buff *skb) ++{ ++ if (!skb || !mptcp_is_available((struct sock *)tp, skb, false)) ++ return false; ++ ++ if (TCP_SKB_CB(skb)->path_mask != 0) ++ return subflow_is_active(tp); ++ ++ if (TCP_SKB_CB(skb)->path_mask == 0) { ++ if (active_valid_sks == -1) ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ if (subflow_is_backup(tp) && active_valid_sks > 0) ++ return false; ++ else ++ return true; ++ } ++ ++ return false; ++} ++ ++static struct sock *redundant_get_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(meta_tp); ++ struct tcp_sock *first_tp = cb_data->next_subflow; ++ struct sock *sk; ++ struct tcp_sock *tp; ++ ++ /* Answer data_fin on same subflow */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == ++ mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ if (!first_tp) ++ first_tp = mpcb->connection_list; ++ tp = first_tp; ++ ++ /* still NULL (no subflow in connection_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ /* Search for any subflow to send it */ ++ do { ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ cb_data->next_subflow = tp->mptcp->next; ++ return (struct sock *)tp; ++ } ++ ++ tp = tp->mptcp->next; ++ if (!tp) ++ tp = mpcb->connection_list; ++ } while (tp != first_tp); ++ ++ /* No space */ ++ return NULL; ++} ++ ++/* Corrects the stored skb pointers if they are invalid */ ++static void redsched_correct_skb_pointers(struct sock *meta_sk, ++ struct redsched_sock_data *sk_data) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (sk_data->skb && !after(sk_data->skb_end_seq, meta_tp->snd_una)) ++ sk_data->skb = NULL; ++} ++ ++/* Returns the next skb from the queue */ ++static struct sk_buff *redundant_next_skb_from_queue(struct sk_buff_head *queue, ++ struct sk_buff *previous, ++ struct sock *meta_sk) ++{ ++ if (skb_queue_empty(queue)) ++ return NULL; ++ ++ if (!previous) ++ return skb_peek(queue); ++ ++ if (skb_queue_is_last(queue, previous)) ++ return NULL; ++ ++ /* sk_data->skb stores the last scheduled packet for this subflow. ++ * If sk_data->skb was scheduled but not sent (e.g., due to nagle), ++ * we have to schedule it again. ++ * ++ * For the redundant scheduler, there are two cases: ++ * 1. sk_data->skb was not sent on another subflow: ++ * we have to schedule it again to ensure that we do not ++ * skip this packet. ++ * 2. sk_data->skb was already sent on another subflow: ++ * with regard to the redundant semantic, we have to ++ * schedule it again. However, we keep it simple and ignore it, ++ * as it was already sent by another subflow. ++ * This might be changed in the future. ++ * ++ * For case 1, send_head is equal previous, as only a single ++ * packet can be skipped. ++ */ ++ if (tcp_send_head(meta_sk) == previous) ++ return tcp_send_head(meta_sk); ++ ++ return skb_queue_next(queue, previous); ++} ++ ++static struct sk_buff *redundant_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(meta_tp); ++ struct tcp_sock *first_tp = cb_data->next_subflow; ++ struct tcp_sock *tp; ++ struct sk_buff *skb; ++ int active_valid_sks = -1; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (skb_queue_empty(&mpcb->reinject_queue) && ++ skb_queue_empty(&meta_sk->sk_write_queue)) ++ /* Nothing to send */ ++ return NULL; ++ ++ /* First try reinjections */ ++ skb = skb_peek(&mpcb->reinject_queue); ++ if (skb) { ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ *reinject = 1; ++ return skb; ++ } ++ ++ /* Then try indistinctly redundant and normal skbs */ ++ ++ if (!first_tp) ++ first_tp = mpcb->connection_list; ++ ++ /* still NULL (no subflow in connection_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ tp = first_tp; ++ ++ *reinject = 0; ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ do { ++ struct redsched_sock_data *sk_data; ++ ++ /* Correct the skb pointers of the current subflow */ ++ sk_data = redsched_get_sock_data(tp); ++ redsched_correct_skb_pointers(meta_sk, sk_data); ++ ++ skb = redundant_next_skb_from_queue(&meta_sk->sk_write_queue, ++ sk_data->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ sk_data->skb = skb; ++ sk_data->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ cb_data->next_subflow = tp->mptcp->next; ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ ++ tp = tp->mptcp->next; ++ if (!tp) ++ tp = mpcb->connection_list; ++ } while (tp != first_tp); ++ ++ /* Nothing to send */ ++ return NULL; ++} ++ ++static void redundant_release(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(tp); ++ ++ /* Check if the next subflow would be the released one. If yes correct ++ * the pointer ++ */ ++ if (cb_data->next_subflow == tp) ++ cb_data->next_subflow = tp->mptcp->next; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_redundant = { ++ .get_subflow = redundant_get_subflow, ++ .next_segment = redundant_next_segment, ++ .release = redundant_release, ++ .name = "redundant", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init redundant_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct redsched_sock_data) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct redsched_cb_data) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_redundant)) ++ return -1; ++ ++ return 0; ++} ++ ++static void redundant_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_redundant); ++} ++ ++module_init(redundant_register); ++module_exit(redundant_unregister); ++ ++MODULE_AUTHOR("Tobias Erbshaeusser, Alexander Froemmgen"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("REDUNDANT MPTCP"); ++MODULE_VERSION("0.90"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_rr.c mptcp-mptcp_v0.94/net/mptcp/mptcp_rr.c +--- linux-4.14.174/net/mptcp/mptcp_rr.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_rr.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,301 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static unsigned char num_segments __read_mostly = 1; ++module_param(num_segments, byte, 0644); ++MODULE_PARM_DESC(num_segments, "The number of consecutive segments that are part of a burst"); ++ ++static bool cwnd_limited __read_mostly = 1; ++module_param(cwnd_limited, bool, 0644); ++MODULE_PARM_DESC(cwnd_limited, "if set to 1, the scheduler tries to fill the congestion-window on all subflows"); ++ ++struct rrsched_priv { ++ unsigned char quota; ++}; ++ ++static struct rrsched_priv *rrsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct rrsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* If the sub-socket sk available to send the skb? */ ++static bool mptcp_rr_is_available(const struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test, bool cwnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int space, in_flight; ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return false; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return false; ++ ++ if (tp->pf) ++ return false; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been acked. ++ * (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return false; ++ else if (tp->snd_una != tp->high_seq) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return false; ++ } ++ ++ if (!cwnd_test) ++ goto zero_wnd_test; ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return false; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return false; ++ ++zero_wnd_test: ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return false; ++ ++ return true; ++} ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_rr_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++/* We just look for any subflow that is available */ ++static struct sock *rr_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk, *bestsk = NULL, *backupsk = NULL; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ return sk; ++ } ++ } ++ ++ /* First, find the best subflow */ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ continue; ++ ++ if (mptcp_rr_dont_reinject_skb(tp, skb)) { ++ backupsk = sk; ++ continue; ++ } ++ ++ bestsk = sk; ++ } ++ ++ if (bestsk) { ++ sk = bestsk; ++ } else if (backupsk) { ++ /* It has been sent on all subflows once - let's give it a ++ * chance again by restarting its pathmask. ++ */ ++ if (skb) ++ TCP_SKB_CB(skb)->path_mask = 0; ++ sk = backupsk; ++ } ++ ++ return sk; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_rr_next_segment(const struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) ++ *reinject = 1; ++ else ++ skb = tcp_send_head(meta_sk); ++ return skb; ++} ++ ++static struct sk_buff *mptcp_rr_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk_it, *choose_sk = NULL; ++ struct sk_buff *skb = __mptcp_rr_next_segment(meta_sk, reinject); ++ unsigned char split = num_segments; ++ unsigned char iter = 0, full_subs = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ if (*reinject) { ++ *subsk = rr_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ return skb; ++ } ++ ++retry: ++ ++ /* First, we look for a subflow who is currently being used */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rsp = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ iter++; ++ ++ /* Is this subflow currently being used? */ ++ if (rsp->quota > 0 && rsp->quota < num_segments) { ++ split = num_segments - rsp->quota; ++ choose_sk = sk_it; ++ goto found; ++ } ++ ++ /* Or, it's totally unused */ ++ if (!rsp->quota) { ++ split = num_segments; ++ choose_sk = sk_it; ++ } ++ ++ /* Or, it must then be fully used */ ++ if (rsp->quota >= num_segments) ++ full_subs++; ++ } ++ ++ /* All considered subflows have a full quota, and we considered at ++ * least one. ++ */ ++ if (iter && iter == full_subs) { ++ /* So, we restart this round by setting quota to 0 and retry ++ * to find a subflow. ++ */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rsp = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ rsp->quota = 0; ++ } ++ ++ goto retry; ++ } ++ ++found: ++ if (choose_sk) { ++ unsigned int mss_now; ++ struct tcp_sock *choose_tp = tcp_sk(choose_sk); ++ struct rrsched_priv *rsp = rrsched_get_priv(choose_tp); ++ ++ if (!mptcp_rr_is_available(choose_sk, skb, false, true)) ++ return NULL; ++ ++ *subsk = choose_sk; ++ mss_now = tcp_current_mss(*subsk); ++ *limit = split * mss_now; ++ ++ if (skb->len > mss_now) ++ rsp->quota += DIV_ROUND_UP(skb->len, mss_now); ++ else ++ rsp->quota++; ++ ++ return skb; ++ } ++ ++ return NULL; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_rr = { ++ .get_subflow = rr_get_available_subflow, ++ .next_segment = mptcp_rr_next_segment, ++ .name = "roundrobin", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init rr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct rrsched_priv) > MPTCP_SCHED_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_rr)) ++ return -1; ++ ++ return 0; ++} ++ ++static void rr_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_rr); ++} ++ ++module_init(rr_register); ++module_exit(rr_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ROUNDROBIN MPTCP"); ++MODULE_VERSION("0.89"); +diff -aurN linux-4.14.174/net/mptcp/mptcp_sched.c mptcp-mptcp_v0.94/net/mptcp/mptcp_sched.c +--- linux-4.14.174/net/mptcp/mptcp_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_sched.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,633 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_sched_list_lock); ++static LIST_HEAD(mptcp_sched_list); ++ ++struct defsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++static struct defsched_priv *defsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct defsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++bool mptcp_is_def_unavailable(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return true; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return true; ++ ++ if (tp->pf) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(mptcp_is_def_unavailable); ++ ++static bool mptcp_is_temp_unavailable(struct sock *sk, ++ const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int mss_now, space, in_flight; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been ++ * acked. (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return true; ++ else if (tp->snd_una != tp->high_seq) ++ return true; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return true; ++ } ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return true; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return true; ++ ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return true; ++ ++ mss_now = tcp_current_mss(sk); ++ ++ /* Don't send on this subflow if we bypass the allowed send-window at ++ * the per-subflow level. Similar to tcp_snd_wnd_test, but manually ++ * calculated end_seq (because here at this point end_seq is still at ++ * the meta-level). ++ */ ++ if (skb && zero_wnd_test && ++ after(tp->write_seq + min(skb->len, mss_now), tcp_wnd_end(tp))) ++ return true; ++ ++ return false; ++} ++ ++/* Is the sub-socket sk available to send the skb? */ ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ return !mptcp_is_def_unavailable(sk) && ++ !mptcp_is_temp_unavailable(sk, skb, zero_wnd_test); ++} ++EXPORT_SYMBOL_GPL(mptcp_is_available); ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++bool subflow_is_backup(const struct tcp_sock *tp) ++{ ++ return tp->mptcp->rcv_low_prio || tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_backup); ++ ++bool subflow_is_active(const struct tcp_sock *tp) ++{ ++ return !tp->mptcp->rcv_low_prio && !tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_active); ++ ++/* Generic function to iterate over used and unused subflows and to select the ++ * best one ++ */ ++static struct sock ++*get_subflow_from_selectors(struct mptcp_cb *mpcb, struct sk_buff *skb, ++ bool (*selector)(const struct tcp_sock *), ++ bool zero_wnd_test, bool *force) ++{ ++ struct sock *bestsk = NULL; ++ u32 min_srtt = 0xffffffff; ++ bool found_unused = false; ++ bool found_unused_una = false; ++ struct sock *sk; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ bool unused = false; ++ ++ /* First, we choose only the wanted sks */ ++ if (!(*selector)(tp)) ++ continue; ++ ++ if (!mptcp_dont_reinject_skb(tp, skb)) ++ unused = true; ++ else if (found_unused) ++ /* If a unused sk was found previously, we continue - ++ * no need to check used sks anymore. ++ */ ++ continue; ++ ++ if (mptcp_is_def_unavailable(sk)) ++ continue; ++ ++ if (mptcp_is_temp_unavailable(sk, skb, zero_wnd_test)) { ++ if (unused) ++ found_unused_una = true; ++ continue; ++ } ++ ++ if (unused) { ++ if (!found_unused) { ++ /* It's the first time we encounter an unused ++ * sk - thus we reset the bestsk (which might ++ * have been set to a used sk). ++ */ ++ min_srtt = 0xffffffff; ++ bestsk = NULL; ++ } ++ found_unused = true; ++ } ++ ++ if (tp->srtt_us < min_srtt) { ++ min_srtt = tp->srtt_us; ++ bestsk = sk; ++ } ++ } ++ ++ if (bestsk) { ++ /* The force variable is used to mark the returned sk as ++ * previously used or not-used. ++ */ ++ if (found_unused) ++ *force = true; ++ else ++ *force = false; ++ } else { ++ /* The force variable is used to mark if there are temporally ++ * unavailable not-used sks. ++ */ ++ if (found_unused_una) ++ *force = true; ++ else ++ *force = false; ++ } ++ ++ return bestsk; ++} ++ ++/* This is the scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy, NULL is returned ++ * The flow is selected based on the shortest RTT. ++ * If all paths have full cong windows, we simply return NULL. ++ * ++ * Additionally, this function is aware of the backup-subflows. ++ */ ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk; ++ bool looping = false, force; ++ ++ /* if there is only one subflow, bypass the scheduling function */ ++ if (mpcb->cnt_subflows == 1) { ++ sk = (struct sock *)mpcb->connection_list; ++ if (!mptcp_is_available(sk, skb, zero_wnd_test)) ++ sk = NULL; ++ return sk; ++ } ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ /* Find the best subflow */ ++restart: ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_active, ++ zero_wnd_test, &force); ++ if (force) ++ /* one unused active sk or one NULL sk when there is at least ++ * one temporally unavailable unused active sk ++ */ ++ return sk; ++ ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_backup, ++ zero_wnd_test, &force); ++ if (!force && skb) { ++ /* one used backup sk or one NULL sk where there is no one ++ * temporally unavailable unused backup sk ++ * ++ * the skb passed through all the available active and backups ++ * sks, so clean the path mask ++ */ ++ TCP_SKB_CB(skb)->path_mask = 0; ++ ++ if (!looping) { ++ looping = true; ++ goto restart; ++ } ++ } ++ return sk; ++} ++EXPORT_SYMBOL_GPL(get_available_subflow); ++ ++static struct sk_buff *mptcp_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *tp_it; ++ struct sk_buff *skb_head; ++ struct defsched_priv *dsp = defsched_get_priv(tp); ++ ++ if (tp->mpcb->cnt_subflows == 1) ++ return NULL; ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_write_queue_head(meta_sk); ++ ++ if (!skb_head || skb_head == tcp_send_head(meta_sk)) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_jiffies32 - dsp->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flows */ ++ mptcp_for_each_tp(tp->mpcb, tp_it) { ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ dsp->last_rbuf_opti = tcp_jiffies32; ++ } ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_tp(tp->mpcb, tp_it) { ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) ++ return skb_head; ++ } ++ return NULL; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = get_available_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++static struct sk_buff *mptcp_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_next_segment(meta_sk, reinject); ++ unsigned int mss_now; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ u32 max_len, max_segs, window, needed; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ * ++ * So, we first limit according to the cwnd/gso-size and then according ++ * to the subflow's window. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ max_len = mss_now * max_segs; ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ needed = min(skb->len, window); ++ if (max_len <= skb->len) ++ /* Take max_win, which is actually the cwnd/gso-size */ ++ *limit = max_len; ++ else ++ /* Or, take the window */ ++ *limit = needed; ++ ++ return skb; ++} ++ ++static void defsched_init(struct sock *sk) ++{ ++ struct defsched_priv *dsp = defsched_get_priv(tcp_sk(sk)); ++ ++ dsp->last_rbuf_opti = tcp_jiffies32; ++} ++ ++struct mptcp_sched_ops mptcp_sched_default = { ++ .get_subflow = get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = defsched_init, ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_sched_ops *mptcp_sched_find(const char *name) ++{ ++ struct mptcp_sched_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_sched_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched) ++{ ++ int ret = 0; ++ ++ if (!sched->get_subflow || !sched->next_segment) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ if (mptcp_sched_find(sched->name)) { ++ pr_notice("%s already registered\n", sched->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&sched->list, &mptcp_sched_list); ++ pr_info("%s registered\n", sched->name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_scheduler); ++ ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched) ++{ ++ spin_lock(&mptcp_sched_list_lock); ++ list_del_rcu(&sched->list); ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_scheduler); ++ ++void mptcp_get_default_scheduler(char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ ++ BUG_ON(list_empty(&mptcp_sched_list)); ++ ++ rcu_read_lock(); ++ sched = list_entry(mptcp_sched_list.next, struct mptcp_sched_ops, list); ++ strncpy(name, sched->name, MPTCP_SCHED_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_scheduler(const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ ++ if (sched) { ++ list_move(&sched->list, &mptcp_sched_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++ ++/* Must be called with rcu lock held */ ++static struct mptcp_sched_ops *__mptcp_sched_find_autoload(const char *name) ++{ ++ struct mptcp_sched_ops *sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ return sched; ++} ++ ++void mptcp_init_scheduler(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_sched_ops *sched; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if scheduler was set using socket option */ ++ if (meta_tp->mptcp_sched_setsockopt) { ++ sched = __mptcp_sched_find_autoload(meta_tp->mptcp_sched_name); ++ if (sched && try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(sched, &mptcp_sched_list, list) { ++ if (try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change scheduler for socket */ ++int mptcp_set_scheduler(struct sock *sk, const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int err = 0; ++ ++ rcu_read_lock(); ++ sched = __mptcp_sched_find_autoload(name); ++ ++ if (!sched) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_sched_name, name); ++ tcp_sk(sk)->mptcp_sched_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->sched_ops->owner); ++} ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_scheduler_default(void) ++{ ++ BUILD_BUG_ON(sizeof(struct defsched_priv) > MPTCP_SCHED_SIZE); ++ ++ return mptcp_set_default_scheduler(CONFIG_DEFAULT_MPTCP_SCHED); ++} ++late_initcall(mptcp_scheduler_default); +diff -aurN linux-4.14.174/net/mptcp/mptcp_wvegas.c mptcp-mptcp_v0.94/net/mptcp/mptcp_wvegas.c +--- linux-4.14.174/net/mptcp/mptcp_wvegas.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.94/net/mptcp/mptcp_wvegas.c 2020-03-23 09:45:33.000000000 +0100 +@@ -0,0 +1,270 @@ ++/* ++ * MPTCP implementation - WEIGHTED VEGAS ++ * ++ * Algorithm design: ++ * Yu Cao ++ * Mingwei Xu ++ * Xiaoming Fu ++ * ++ * Implementation: ++ * Yu Cao ++ * Enhuan Dong ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int initial_alpha = 2; ++static int total_alpha = 10; ++static int gamma = 1; ++ ++module_param(initial_alpha, int, 0644); ++MODULE_PARM_DESC(initial_alpha, "initial alpha for all subflows"); ++module_param(total_alpha, int, 0644); ++MODULE_PARM_DESC(total_alpha, "total alpha for all subflows"); ++module_param(gamma, int, 0644); ++MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)"); ++ ++#define MPTCP_WVEGAS_SCALE 16 ++ ++/* wVegas variables */ ++struct wvegas { ++ u32 beg_snd_nxt; /* right edge during last RTT */ ++ u8 doing_wvegas_now;/* if true, do wvegas for this RTT */ ++ ++ u16 cnt_rtt; /* # of RTTs measured within last RTT */ ++ u32 sampled_rtt; /* cumulative RTTs measured within last RTT (in usec) */ ++ u32 base_rtt; /* the min of all wVegas RTT measurements seen (in usec) */ ++ ++ u64 instant_rate; /* cwnd / srtt_us, unit: pkts/us * 2^16 */ ++ u64 weight; /* the ratio of subflow's rate to the total rate, * 2^16 */ ++ int alpha; /* alpha for each subflows */ ++ ++ u32 queue_delay; /* queue delay*/ ++}; ++ ++ ++static inline u64 mptcp_wvegas_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static void wvegas_enable(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 1; ++ ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ ++ wvegas->instant_rate = 0; ++ wvegas->alpha = initial_alpha; ++ wvegas->weight = mptcp_wvegas_scale(1, MPTCP_WVEGAS_SCALE); ++ ++ wvegas->queue_delay = 0; ++} ++ ++static inline void wvegas_disable(const struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 0; ++} ++ ++static void mptcp_wvegas_init(struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->base_rtt = 0x7fffffff; ++ wvegas_enable(sk); ++} ++ ++static inline u64 mptcp_wvegas_rate(u32 cwnd, u32 rtt_us) ++{ ++ return div_u64(mptcp_wvegas_scale(cwnd, MPTCP_WVEGAS_SCALE), rtt_us); ++} ++ ++static void mptcp_wvegas_pkts_acked(struct sock *sk, ++ const struct ack_sample *sample) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ u32 vrtt; ++ ++ if (sample->rtt_us < 0) ++ return; ++ ++ vrtt = sample->rtt_us + 1; ++ ++ if (vrtt < wvegas->base_rtt) ++ wvegas->base_rtt = vrtt; ++ ++ wvegas->sampled_rtt += vrtt; ++ wvegas->cnt_rtt++; ++} ++ ++static void mptcp_wvegas_state(struct sock *sk, u8 ca_state) ++{ ++ if (ca_state == TCP_CA_Open) ++ wvegas_enable(sk); ++ else ++ wvegas_disable(sk); ++} ++ ++static void mptcp_wvegas_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_CWND_RESTART) { ++ mptcp_wvegas_init(sk); ++ } else if (event == CA_EVENT_LOSS) { ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ wvegas->instant_rate = 0; ++ } ++} ++ ++static inline u32 mptcp_wvegas_ssthresh(const struct tcp_sock *tp) ++{ ++ return min(tp->snd_ssthresh, tp->snd_cwnd); ++} ++ ++static u64 mptcp_wvegas_weight(const struct mptcp_cb *mpcb, const struct sock *sk) ++{ ++ u64 total_rate = 0; ++ struct sock *sub_sk; ++ const struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!mpcb) ++ return wvegas->weight; ++ ++ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct wvegas *sub_wvegas = inet_csk_ca(sub_sk); ++ ++ /* sampled_rtt is initialized by 0 */ ++ if (mptcp_sk_can_send(sub_sk) && (sub_wvegas->sampled_rtt > 0)) ++ total_rate += sub_wvegas->instant_rate; ++ } ++ ++ if (total_rate && wvegas->instant_rate) ++ return div64_u64(mptcp_wvegas_scale(wvegas->instant_rate, MPTCP_WVEGAS_SCALE), total_rate); ++ else ++ return wvegas->weight; ++} ++ ++static void mptcp_wvegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!wvegas->doing_wvegas_now) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (after(ack, wvegas->beg_snd_nxt)) { ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ if (wvegas->cnt_rtt <= 2) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ } else { ++ u32 rtt, diff, q_delay; ++ u64 target_cwnd; ++ ++ rtt = wvegas->sampled_rtt / wvegas->cnt_rtt; ++ target_cwnd = div_u64(((u64)tp->snd_cwnd * wvegas->base_rtt), rtt); ++ ++ diff = div_u64((u64)tp->snd_cwnd * (rtt - wvegas->base_rtt), rtt); ++ ++ if (diff > gamma && tcp_in_slow_start(tp)) { ++ tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ ++ } else if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ } else { ++ if (diff >= wvegas->alpha) { ++ wvegas->instant_rate = mptcp_wvegas_rate(tp->snd_cwnd, rtt); ++ wvegas->weight = mptcp_wvegas_weight(tp->mpcb, sk); ++ wvegas->alpha = max(2U, (u32)((wvegas->weight * total_alpha) >> MPTCP_WVEGAS_SCALE)); ++ } ++ if (diff > wvegas->alpha) { ++ tp->snd_cwnd--; ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ } else if (diff < wvegas->alpha) { ++ tp->snd_cwnd++; ++ } ++ ++ /* Try to drain link queue if needed*/ ++ q_delay = rtt - wvegas->base_rtt; ++ if ((wvegas->queue_delay == 0) || (wvegas->queue_delay > q_delay)) ++ wvegas->queue_delay = q_delay; ++ ++ if (q_delay >= 2 * wvegas->queue_delay) { ++ u32 backoff_factor = div_u64(mptcp_wvegas_scale(wvegas->base_rtt, MPTCP_WVEGAS_SCALE), 2 * rtt); ++ tp->snd_cwnd = ((u64)tp->snd_cwnd * backoff_factor) >> MPTCP_WVEGAS_SCALE; ++ wvegas->queue_delay = 0; ++ } ++ } ++ ++ if (tp->snd_cwnd < 2) ++ tp->snd_cwnd = 2; ++ else if (tp->snd_cwnd > tp->snd_cwnd_clamp) ++ tp->snd_cwnd = tp->snd_cwnd_clamp; ++ ++ tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ } ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ } ++ /* Use normal slow start */ ++ else if (tcp_in_slow_start(tp)) ++ tcp_slow_start(tp, acked); ++} ++ ++ ++static struct tcp_congestion_ops mptcp_wvegas __read_mostly = { ++ .init = mptcp_wvegas_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_wvegas_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .pkts_acked = mptcp_wvegas_pkts_acked, ++ .set_state = mptcp_wvegas_state, ++ .cwnd_event = mptcp_wvegas_cwnd_event, ++ ++ .owner = THIS_MODULE, ++ .name = "wvegas", ++}; ++ ++static int __init mptcp_wvegas_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct wvegas) > ICSK_CA_PRIV_SIZE); ++ tcp_register_congestion_control(&mptcp_wvegas); ++ return 0; ++} ++ ++static void __exit mptcp_wvegas_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_wvegas); ++} ++ ++module_init(mptcp_wvegas_register); ++module_exit(mptcp_wvegas_unregister); ++ ++MODULE_AUTHOR("Yu Cao, Enhuan Dong"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP wVegas"); ++MODULE_VERSION("0.1"); diff --git a/root/target/linux/generic/hack-4.14/998-ndpi-netfilter.patch b/root/target/linux/generic/hack-4.14/998-ndpi-netfilter.patch new file mode 100644 index 00000000..cd8d61a7 --- /dev/null +++ b/root/target/linux/generic/hack-4.14/998-ndpi-netfilter.patch @@ -0,0 +1,116 @@ +diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h +index 21f887c..59980ec 100644 +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -28,7 +28,8 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif +- NF_CT_EXT_NUM, ++ NF_CT_EXT_CUSTOM, ++ NF_CT_EXT_NUM=NF_CT_EXT_CUSTOM+CONFIG_NF_CONNTRACK_CUSTOM, + }; + + #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help +@@ -96,5 +97,6 @@ struct nf_ct_ext_type { + }; + + int nf_ct_extend_register(const struct nf_ct_ext_type *type); ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type,unsigned long int cid); + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type); + #endif /* _NF_CONNTRACK_EXTEND_H */ +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 7581e82..30a11eb 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -85,6 +85,16 @@ config NF_CONNTRACK_SECMARK + + If unsure, say 'N'. + ++config NF_CONNTRACK_CUSTOM ++ int "Number of custom extend" ++ range 0 8 ++ depends on NETFILTER_ADVANCED ++ default "2" ++ help ++ This parameter specifies how many custom extensions can be registered. ++ ++ The default value is 2. ++ + config NF_CONNTRACK_ZONES + bool 'Connection tracking zones' + depends on NETFILTER_ADVANCED +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 85f643c..44e2fdd 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1971,7 +1971,7 @@ int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp) + static __always_inline unsigned int total_extension_size(void) + { + /* remember to add new extensions below */ +- BUILD_BUG_ON(NF_CT_EXT_NUM > 9); ++ BUILD_BUG_ON(NF_CT_EXT_NUM > 12); + + return sizeof(struct nf_ct_ext) + + sizeof(struct nf_conn_help) +diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c +index 9fe0ddc..5a9054e 100644 +--- a/net/netfilter/nf_conntrack_extend.c ++++ b/net/netfilter/nf_conntrack_extend.c +@@ -108,11 +108,56 @@ int nf_ct_extend_register(const struct nf_ct_ext_type *type) + } + EXPORT_SYMBOL_GPL(nf_ct_extend_register); + ++static unsigned long int nf_ct_ext_cust_id[CONFIG_NF_CONNTRACK_CUSTOM]; ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id); ++ ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type, ++ unsigned long int cid) ++{ ++ int ret; ++ enum nf_ct_ext_id new_id = nf_ct_extend_get_custom_id(cid); ++ if(!new_id) ++ return -EBUSY; ++ type->id = new_id; ++ ret = nf_ct_extend_register(type); ++ if(ret < 0) { ++ mutex_lock(&nf_ct_ext_type_mutex); ++ nf_ct_ext_cust_id[new_id - NF_CT_EXT_CUSTOM] = 0; ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(nf_ct_extend_custom_register); ++ ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id) ++{ ++ enum nf_ct_ext_id ret = 0; ++ int i; ++ mutex_lock(&nf_ct_ext_type_mutex); ++ for(i = 0; i < CONFIG_NF_CONNTRACK_CUSTOM; i++) { ++ if(!nf_ct_ext_cust_id[i]) { ++ nf_ct_ext_cust_id[i] = ext_id; ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ if(nf_ct_ext_cust_id[i] == ext_id) { ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ } ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ return ret; ++} ++ + /* This MUST be called in process context. */ + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type) + { + mutex_lock(&nf_ct_ext_type_mutex); + RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); ++ if(type->id >= NF_CT_EXT_CUSTOM && type->id < NF_CT_EXT_NUM) ++ nf_ct_ext_cust_id[type->id-NF_CT_EXT_CUSTOM] = 0; + mutex_unlock(&nf_ct_ext_type_mutex); + synchronize_rcu(); + } diff --git a/root/target/linux/generic/hack-4.14/999-stop-promiscuous-info.patch b/root/target/linux/generic/hack-4.14/999-stop-promiscuous-info.patch new file mode 100644 index 00000000..2dc06ee6 --- /dev/null +++ b/root/target/linux/generic/hack-4.14/999-stop-promiscuous-info.patch @@ -0,0 +1,14 @@ +--- a/net/core/dev.c 2018-08-10 10:31:41.199494561 +0200 ++++ b/net/core/dev.c 2018-08-10 10:32:03.635272509 +0200 +@@ -6613,9 +6613,11 @@ + } + } + if (dev->flags != old_flags) { ++ /* + pr_info("device %s %s promiscuous mode\n", + dev->name, + dev->flags & IFF_PROMISC ? "entered" : "left"); ++ */ + if (audit_enabled) { + current_uid_gid(&uid, &gid); + audit_log(current->audit_context, GFP_ATOMIC, diff --git a/root/target/linux/generic/hack-4.19/690-mptcp_v0.95.patch b/root/target/linux/generic/hack-4.19/690-mptcp_v0.95.patch new file mode 100644 index 00000000..cf58d5a6 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/690-mptcp_v0.95.patch @@ -0,0 +1,22998 @@ +diff -aurN linux-4.19.104/Documentation/networking/ip-sysctl.txt mptcp-mptcp_v0.95/Documentation/networking/ip-sysctl.txt +--- linux-4.19.104/Documentation/networking/ip-sysctl.txt 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/Documentation/networking/ip-sysctl.txt 2020-02-17 11:29:55.000000000 +0100 +@@ -763,6 +763,18 @@ + in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) + Default: 100 + ++MPTCP variables: ++ ++mptcp_enabled - INTEGER ++ Enable or disable Multipath TCP for new connections. ++ Possible values are: ++ ++ 0: Multipath TCP is disabled on all TCP-sockets that are newly created. ++ 1: Multipath TCP is enabled by default on all new TCP-sockets. Note that ++ existing sockets in LISTEN-state will still use regular TCP. ++ 2: Enables Multipath TCP only upon the request of the application ++ throught the socket-option MPTCP_ENABLED. ++ + UDP variables: + + udp_l3mdev_accept - BOOLEAN +diff -aurN linux-4.19.104/drivers/infiniband/hw/cxgb4/cm.c mptcp-mptcp_v0.95/drivers/infiniband/hw/cxgb4/cm.c +--- linux-4.19.104/drivers/infiniband/hw/cxgb4/cm.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/drivers/infiniband/hw/cxgb4/cm.c 2020-02-17 11:29:55.000000000 +0100 +@@ -3782,7 +3782,7 @@ + */ + memset(&tmp_opt, 0, sizeof(tmp_opt)); + tcp_clear_options(&tmp_opt); +- tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(&init_net, skb, &tmp_opt, NULL, 0, NULL, NULL); + + req = __skb_push(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); +diff -aurN linux-4.19.104/include/linux/skbuff.h mptcp-mptcp_v0.95/include/linux/skbuff.h +--- linux-4.19.104/include/linux/skbuff.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/linux/skbuff.h 2020-02-17 11:29:55.000000000 +0100 +@@ -697,7 +697,7 @@ + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ +- char cb[48] __aligned(8); ++ char cb[80] __aligned(8); + + union { + struct { +diff -aurN linux-4.19.104/include/linux/tcp.h mptcp-mptcp_v0.95/include/linux/tcp.h +--- linux-4.19.104/include/linux/tcp.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/linux/tcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -58,7 +58,7 @@ + /* TCP Fast Open */ + #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ + #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ +-#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ ++#define TCP_FASTOPEN_COOKIE_SIZE 4 /* the size employed by this impl. */ + + /* TCP Fast Open Cookie as stored in memory */ + struct tcp_fastopen_cookie { +@@ -83,6 +83,56 @@ + u32 end_seq; + }; + ++struct tcp_out_options { ++ u16 options; /* bit field of OPTION_* */ ++ u16 mss; /* 0 to disable */ ++ u8 ws; /* window scale, 0 to disable */ ++ u8 num_sack_blocks; /* number of SACK blocks to include */ ++ u8 hash_size; /* bytes in hash_location */ ++ __u8 *hash_location; /* temporary pointer, overloaded */ ++ __u32 tsval, tsecr; /* need to include OPTION_TS */ ++ struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ ++#ifdef CONFIG_MPTCP ++ u16 mptcp_options; /* bit field of MPTCP related OPTION_* */ ++ u8 dss_csum:1, /* dss-checksum required? */ ++ add_addr_v4:1, ++ add_addr_v6:1, ++ mptcp_ver:4; ++ ++ union { ++ struct { ++ __u64 sender_key; /* sender's key for mptcp */ ++ __u64 receiver_key; /* receiver's key for mptcp */ ++ } mp_capable; ++ ++ struct { ++ __u64 sender_truncated_mac; ++ __u32 sender_nonce; ++ /* random number of the sender */ ++ __u32 token; /* token for mptcp */ ++ u8 low_prio:1; ++ } mp_join_syns; ++ }; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr4; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in6_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr6; ++ ++ u16 remove_addrs; /* list of address id */ ++ u8 addr_id; /* address id (mp_join or add_address) */ ++#endif /* CONFIG_MPTCP */ ++}; ++ + /*These are used to set the sack_ok field in struct tcp_options_received */ + #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ + #define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/ +@@ -106,6 +156,9 @@ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + }; + ++struct mptcp_cb; ++struct mptcp_tcp_sock; ++ + static inline void tcp_clear_options(struct tcp_options_received *rx_opt) + { + rx_opt->tstamp_ok = rx_opt->sack_ok = 0; +@@ -144,6 +197,8 @@ + return (struct tcp_request_sock *)req; + } + ++struct tcp_md5sig_key; ++ + struct tcp_sock { + /* inet_connection_sock has to be the first member of tcp_sock */ + struct inet_connection_sock inet_conn; +@@ -398,6 +453,44 @@ + */ + struct request_sock *fastopen_rsk; + u32 *saved_syn; ++ ++ /* MPTCP/TCP-specific callbacks */ ++ const struct tcp_sock_ops *ops; ++ ++ struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ /* We keep these flags even if CONFIG_MPTCP is not checked, because ++ * it allows checking MPTCP capability just by checking the mpc flag, ++ * rather than adding ifdefs everywhere. ++ */ ++ u32 mpc:1, /* Other end is multipath capable */ ++ inside_tk_table:1, /* Is the tcp_sock inside the token-table? */ ++ send_mp_fclose:1, ++ request_mptcp:1, /* Did we send out an MP_CAPABLE? ++ * (this speeds up mptcp_doit() in tcp_recvmsg) ++ */ ++ pf:1, /* Potentially Failed state: when this flag is set, we ++ * stop using the subflow ++ */ ++ mp_killed:1, /* Killed with a tcp_done in mptcp? */ ++ is_master_sk:1, ++ close_it:1, /* Must close socket in mptcp_data_ready? */ ++ closing:1, ++ mptcp_ver:4, ++ mptcp_sched_setsockopt:1, ++ mptcp_pm_setsockopt:1, ++ record_master_info:1, ++ tcp_disconnect:1; ++ struct mptcp_tcp_sock *mptcp; ++#ifdef CONFIG_MPTCP ++#define MPTCP_SCHED_NAME_MAX 16 ++#define MPTCP_PM_NAME_MAX 16 ++ struct hlist_nulls_node tk_table; ++ u32 mptcp_loc_token; ++ u64 mptcp_loc_key; ++ char mptcp_sched_name[MPTCP_SCHED_NAME_MAX]; ++ char mptcp_pm_name[MPTCP_PM_NAME_MAX]; ++#endif /* CONFIG_MPTCP */ + }; + + enum tsq_enum { +@@ -409,6 +502,8 @@ + TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call + * tcp_v{4|6}_mtu_reduced() + */ ++ MPTCP_PATH_MANAGER_DEFERRED, /* MPTCP deferred creation of new subflows */ ++ MPTCP_SUB_DEFERRED, /* A subflow got deferred - process them */ + }; + + enum tsq_flags { +@@ -418,6 +513,8 @@ + TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED), + TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED), + TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED), ++ TCPF_PATH_MANAGER_DEFERRED = (1UL << MPTCP_PATH_MANAGER_DEFERRED), ++ TCPF_SUB_DEFERRED = (1UL << MPTCP_SUB_DEFERRED), + }; + + static inline struct tcp_sock *tcp_sk(const struct sock *sk) +@@ -440,6 +537,7 @@ + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *tw_md5_key; + #endif ++ struct mptcp_tw *mptcp_tw; + }; + + static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) +diff -aurN linux-4.19.104/include/net/inet_common.h mptcp-mptcp_v0.95/include/net/inet_common.h +--- linux-4.19.104/include/net/inet_common.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/inet_common.h 2020-02-17 11:29:55.000000000 +0100 +@@ -2,6 +2,8 @@ + #ifndef _INET_COMMON_H + #define _INET_COMMON_H + ++#include ++ + extern const struct proto_ops inet_stream_ops; + extern const struct proto_ops inet_dgram_ops; + +@@ -14,6 +16,8 @@ + struct sockaddr; + struct socket; + ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern); ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern); + int inet_release(struct socket *sock); + int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags); +diff -aurN linux-4.19.104/include/net/inet_connection_sock.h mptcp-mptcp_v0.95/include/net/inet_connection_sock.h +--- linux-4.19.104/include/net/inet_connection_sock.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/inet_connection_sock.h 2020-02-17 11:29:55.000000000 +0100 +@@ -29,6 +29,7 @@ + + struct inet_bind_bucket; + struct tcp_congestion_ops; ++struct tcp_options_received; + + /* + * Pointers to address related TCP functions +diff -aurN linux-4.19.104/include/net/inet_sock.h mptcp-mptcp_v0.95/include/net/inet_sock.h +--- linux-4.19.104/include/net/inet_sock.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/inet_sock.h 2020-02-17 11:29:55.000000000 +0100 +@@ -83,7 +83,7 @@ + #define ireq_state req.__req_common.skc_state + #define ireq_family req.__req_common.skc_family + +- u16 snd_wscale : 4, ++ u32 snd_wscale : 4, + rcv_wscale : 4, + tstamp_ok : 1, + sack_ok : 1, +@@ -91,6 +91,8 @@ + ecn_ok : 1, + acked : 1, + no_srccheck: 1, ++ mptcp_rqsk : 1, ++ saw_mpc : 1, + smc_ok : 1; + u32 ir_mark; + union { +diff -aurN linux-4.19.104/include/net/mptcp.h mptcp-mptcp_v0.95/include/net/mptcp.h +--- linux-4.19.104/include/net/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/mptcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,1498 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_H ++#define _MPTCP_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ #define ntohll(x) be64_to_cpu(x) ++ #define htonll(x) cpu_to_be64(x) ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ #define ntohll(x) (x) ++ #define htonll(x) (x) ++#endif ++ ++struct mptcp_loc4 { ++ u8 loc4_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in_addr addr; ++}; ++ ++struct mptcp_rem4 { ++ u8 rem4_id; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct mptcp_loc6 { ++ u8 loc6_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_rem6 { ++ u8 rem6_id; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_request_sock { ++ struct tcp_request_sock req; ++ struct hlist_nulls_node hash_entry; ++ ++ union { ++ struct { ++ /* Only on initial subflows */ ++ u64 mptcp_loc_key; ++ u64 mptcp_rem_key; ++ u32 mptcp_loc_token; ++ }; ++ ++ struct { ++ /* Only on additional subflows */ ++ u32 mptcp_rem_nonce; ++ u32 mptcp_loc_nonce; ++ u64 mptcp_hash_tmac; ++ }; ++ }; ++ ++ u8 loc_id; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 dss_csum:1, ++ is_sub:1, /* Is this a new subflow? */ ++ low_prio:1, /* Interface set to low-prio? */ ++ rcv_low_prio:1, ++ mptcp_ver:4; ++}; ++ ++struct mptcp_options_received { ++ u16 saw_mpc:1, ++ dss_csum:1, ++ drop_me:1, ++ ++ is_mp_join:1, ++ join_ack:1, ++ ++ saw_low_prio:2, /* 0x1 - low-prio set for this subflow ++ * 0x2 - low-prio set for another subflow ++ */ ++ low_prio:1, ++ ++ saw_add_addr:2, /* Saw at least one add_addr option: ++ * 0x1: IPv4 - 0x2: IPv6 ++ */ ++ more_add_addr:1, /* Saw one more add-addr. */ ++ ++ saw_rem_addr:1, /* Saw at least one rem_addr option */ ++ more_rem_addr:1, /* Saw one more rem-addr. */ ++ ++ mp_fail:1, ++ mp_fclose:1; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 prio_addr_id; /* Address-id in the MP_PRIO */ ++ ++ const unsigned char *add_addr_ptr; /* Pointer to add-address option */ ++ const unsigned char *rem_addr_ptr; /* Pointer to rem-address option */ ++ ++ u32 data_ack; ++ u32 data_seq; ++ u16 data_len; ++ ++ u8 mptcp_ver; /* MPTCP version */ ++ ++ /* Key inside the option (from mp_capable or fast_close) */ ++ u64 mptcp_sender_key; ++ u64 mptcp_receiver_key; ++ ++ u32 mptcp_rem_token; /* Remote token */ ++ ++ u32 mptcp_recv_nonce; ++ u64 mptcp_recv_tmac; ++ u8 mptcp_recv_mac[20]; ++}; ++ ++struct mptcp_tcp_sock { ++ struct hlist_node node; ++ struct hlist_node cb_list; ++ struct mptcp_options_received rx_opt; ++ ++ /* Those three fields record the current mapping */ ++ u64 map_data_seq; ++ u32 map_subseq; ++ u16 map_data_len; ++ u16 slave_sk:1, ++ fully_established:1, ++ second_packet:1, ++ attached:1, ++ send_mp_fail:1, ++ include_mpc:1, ++ mapping_present:1, ++ map_data_fin:1, ++ low_prio:1, /* use this socket as backup */ ++ rcv_low_prio:1, /* Peer sent low-prio option to us */ ++ send_mp_prio:1, /* Trigger to send mp_prio on this socket */ ++ pre_established:1; /* State between sending 3rd ACK and ++ * receiving the fourth ack of new subflows. ++ */ ++ ++ /* isn: needed to translate abs to relative subflow seqnums */ ++ u32 snt_isn; ++ u32 rcv_isn; ++ u8 path_index; ++ u8 loc_id; ++ u8 rem_id; ++ u8 sk_err; ++ ++#define MPTCP_SCHED_SIZE 16 ++ u8 mptcp_sched[MPTCP_SCHED_SIZE] __aligned(8); ++ ++ int init_rcv_wnd; ++ u32 infinite_cutoff_seq; ++ struct delayed_work work; ++ u32 mptcp_loc_nonce; ++ struct tcp_sock *tp; ++ u32 last_end_data_seq; ++ ++ /* MP_JOIN subflow: timer for retransmitting the 3rd ack */ ++ struct timer_list mptcp_ack_timer; ++ ++ /* HMAC of the third ack */ ++ char sender_mac[20]; ++}; ++ ++struct mptcp_tw { ++ struct list_head list; ++ u64 loc_key; ++ u64 rcv_nxt; ++ struct mptcp_cb __rcu *mpcb; ++ u8 meta_tw:1, ++ in_list:1; ++}; ++ ++#define MPTCP_PM_NAME_MAX 16 ++struct mptcp_pm_ops { ++ struct list_head list; ++ ++ /* Signal the creation of a new MPTCP-session. */ ++ void (*new_session)(const struct sock *meta_sk); ++ void (*release_sock)(struct sock *meta_sk); ++ void (*fully_established)(struct sock *meta_sk); ++ void (*close_session)(struct sock *meta_sk); ++ void (*new_remote_address)(struct sock *meta_sk); ++ int (*get_local_id)(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio); ++ void (*addr_signal)(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb); ++ void (*add_raddr)(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id); ++ void (*rem_raddr)(struct mptcp_cb *mpcb, u8 rem_id); ++ void (*init_subsocket_v4)(struct sock *sk, struct in_addr addr); ++ void (*init_subsocket_v6)(struct sock *sk, struct in6_addr addr); ++ void (*established_subflow)(struct sock *sk); ++ void (*delete_subflow)(struct sock *sk); ++ void (*prio_changed)(struct sock *sk, int low_prio); ++ ++ char name[MPTCP_PM_NAME_MAX]; ++ struct module *owner; ++}; ++ ++#define MPTCP_SCHED_NAME_MAX 16 ++struct mptcp_sched_ops { ++ struct list_head list; ++ ++ struct sock * (*get_subflow)(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test); ++ struct sk_buff * (*next_segment)(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit); ++ void (*init)(struct sock *sk); ++ void (*release)(struct sock *sk); ++ ++ char name[MPTCP_SCHED_NAME_MAX]; ++ struct module *owner; ++}; ++ ++struct mptcp_cb { ++ /* list of sockets in this multipath connection */ ++ struct hlist_head conn_list; ++ /* list of sockets that need a call to release_cb */ ++ struct hlist_head callback_list; ++ ++ /* Lock used for protecting the different rcu-lists of mptcp_cb */ ++ spinlock_t mpcb_list_lock; ++ ++ /* High-order bits of 64-bit sequence numbers */ ++ u32 snd_high_order[2]; ++ u32 rcv_high_order[2]; ++ ++ u16 send_infinite_mapping:1, ++ in_time_wait:1, ++ list_rcvd:1, /* XXX TO REMOVE */ ++ addr_signal:1, /* Path-manager wants us to call addr_signal */ ++ dss_csum:1, ++ server_side:1, ++ infinite_mapping_rcv:1, ++ infinite_mapping_snd:1, ++ dfin_combined:1, /* Was the DFIN combined with subflow-fin? */ ++ passive_close:1, ++ snd_hiseq_index:1, /* Index in snd_high_order of snd_nxt */ ++ rcv_hiseq_index:1, /* Index in rcv_high_order of rcv_nxt */ ++ tcp_ca_explicit_set:1; /* was meta CC set by app? */ ++ ++#define MPTCP_SCHED_DATA_SIZE 8 ++ u8 mptcp_sched[MPTCP_SCHED_DATA_SIZE] __aligned(8); ++ const struct mptcp_sched_ops *sched_ops; ++ ++ struct sk_buff_head reinject_queue; ++ /* First cache-line boundary is here minus 8 bytes. But from the ++ * reinject-queue only the next and prev pointers are regularly ++ * accessed. Thus, the whole data-path is on a single cache-line. ++ */ ++ ++ u64 csum_cutoff_seq; ++ u64 infinite_rcv_seq; ++ ++ /***** Start of fields, used for connection closure */ ++ unsigned char mptw_state; ++ u8 dfin_path_index; ++ ++ struct list_head tw_list; ++ ++ /***** Start of fields, used for subflow establishment and closure */ ++ refcount_t mpcb_refcnt; ++ ++ /* Mutex needed, because otherwise mptcp_close will complain that the ++ * socket is owned by the user. ++ * E.g., mptcp_sub_close_wq is taking the meta-lock. ++ */ ++ struct mutex mpcb_mutex; ++ ++ /***** Start of fields, used for subflow establishment */ ++ struct sock *meta_sk; ++ ++ /* Master socket, also part of the conn_list, this ++ * socket is the one that the application sees. ++ */ ++ struct sock *master_sk; ++ ++ __u64 mptcp_loc_key; ++ __u64 mptcp_rem_key; ++ __u32 mptcp_loc_token; ++ __u32 mptcp_rem_token; ++ ++#define MPTCP_PM_SIZE 608 ++ u8 mptcp_pm[MPTCP_PM_SIZE] __aligned(8); ++ const struct mptcp_pm_ops *pm_ops; ++ ++ unsigned long path_index_bits; ++ ++ __u8 mptcp_ver; ++ ++ /* Original snd/rcvbuf of the initial subflow. ++ * Used for the new subflows on the server-side to allow correct ++ * autotuning ++ */ ++ int orig_sk_rcvbuf; ++ int orig_sk_sndbuf; ++ u32 orig_window_clamp; ++ ++ struct tcp_info *master_info; ++}; ++ ++#define MPTCP_VERSION_0 0 ++#define MPTCP_VERSION_1 1 ++ ++#define MPTCP_SUB_CAPABLE 0 ++#define MPTCP_SUB_LEN_CAPABLE_SYN 12 ++#define MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_CAPABLE_ACK 20 ++#define MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN 20 ++ ++#define MPTCP_SUB_JOIN 1 ++#define MPTCP_SUB_LEN_JOIN_SYN 12 ++#define MPTCP_SUB_LEN_JOIN_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_JOIN_SYNACK 16 ++#define MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN 16 ++#define MPTCP_SUB_LEN_JOIN_ACK 24 ++#define MPTCP_SUB_LEN_JOIN_ACK_ALIGN 24 ++ ++#define MPTCP_SUB_DSS 2 ++#define MPTCP_SUB_LEN_DSS 4 ++#define MPTCP_SUB_LEN_DSS_ALIGN 4 ++ ++/* Lengths for seq and ack are the ones without the generic MPTCP-option header, ++ * as they are part of the DSS-option. ++ * To get the total length, just add the different options together. ++ */ ++#define MPTCP_SUB_LEN_SEQ 10 ++#define MPTCP_SUB_LEN_SEQ_CSUM 12 ++#define MPTCP_SUB_LEN_SEQ_ALIGN 12 ++ ++#define MPTCP_SUB_LEN_SEQ_64 14 ++#define MPTCP_SUB_LEN_SEQ_CSUM_64 16 ++#define MPTCP_SUB_LEN_SEQ_64_ALIGN 16 ++ ++#define MPTCP_SUB_LEN_ACK 4 ++#define MPTCP_SUB_LEN_ACK_ALIGN 4 ++ ++#define MPTCP_SUB_LEN_ACK_64 8 ++#define MPTCP_SUB_LEN_ACK_64_ALIGN 8 ++ ++/* This is the "default" option-length we will send out most often. ++ * MPTCP DSS-header ++ * 32-bit data sequence number ++ * 32-bit data ack ++ * ++ * It is necessary to calculate the effective MSS we will be using when ++ * sending data. ++ */ ++#define MPTCP_SUB_LEN_DSM_ALIGN (MPTCP_SUB_LEN_DSS_ALIGN + \ ++ MPTCP_SUB_LEN_SEQ_ALIGN + \ ++ MPTCP_SUB_LEN_ACK_ALIGN) ++ ++#define MPTCP_SUB_ADD_ADDR 3 ++#define MPTCP_SUB_LEN_ADD_ADDR4 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_VER1 28 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 28 ++ ++#define MPTCP_SUB_REMOVE_ADDR 4 ++#define MPTCP_SUB_LEN_REMOVE_ADDR 4 ++ ++#define MPTCP_SUB_PRIO 5 ++#define MPTCP_SUB_LEN_PRIO 3 ++#define MPTCP_SUB_LEN_PRIO_ADDR 4 ++#define MPTCP_SUB_LEN_PRIO_ALIGN 4 ++ ++#define MPTCP_SUB_FAIL 6 ++#define MPTCP_SUB_LEN_FAIL 12 ++#define MPTCP_SUB_LEN_FAIL_ALIGN 12 ++ ++#define MPTCP_SUB_FCLOSE 7 ++#define MPTCP_SUB_LEN_FCLOSE 12 ++#define MPTCP_SUB_LEN_FCLOSE_ALIGN 12 ++ ++ ++#define OPTION_MPTCP (1 << 5) ++ ++/* Max number of fastclose retransmissions */ ++#define MPTCP_FASTCLOSE_RETRIES 3 ++ ++#ifdef CONFIG_MPTCP ++ ++/* Used for checking if the mptcp initialization has been successful */ ++extern bool mptcp_init_failed; ++ ++/* MPTCP options */ ++#define OPTION_TYPE_SYN (1 << 0) ++#define OPTION_TYPE_SYNACK (1 << 1) ++#define OPTION_TYPE_ACK (1 << 2) ++#define OPTION_MP_CAPABLE (1 << 3) ++#define OPTION_DATA_ACK (1 << 4) ++#define OPTION_ADD_ADDR (1 << 5) ++#define OPTION_MP_JOIN (1 << 6) ++#define OPTION_MP_FAIL (1 << 7) ++#define OPTION_MP_FCLOSE (1 << 8) ++#define OPTION_REMOVE_ADDR (1 << 9) ++#define OPTION_MP_PRIO (1 << 10) ++ ++/* MPTCP flags: both TX and RX */ ++#define MPTCPHDR_SEQ 0x01 /* DSS.M option is present */ ++#define MPTCPHDR_FIN 0x02 /* DSS.F option is present */ ++#define MPTCPHDR_SEQ64_INDEX 0x04 /* index of seq in mpcb->snd_high_order */ ++/* MPTCP flags: RX only */ ++#define MPTCPHDR_ACK 0x08 ++#define MPTCPHDR_SEQ64_SET 0x10 /* Did we received a 64-bit seq number? */ ++#define MPTCPHDR_SEQ64_OFO 0x20 /* Is it not in our circular array? */ ++#define MPTCPHDR_DSS_CSUM 0x40 ++/* MPTCP flags: TX only */ ++#define MPTCPHDR_INF 0x08 ++#define MPTCP_REINJECT 0x10 /* Did we reinject this segment? */ ++ ++struct mptcp_option { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_capable { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++ __u8 h:1, ++ rsv:5, ++ b:1, ++ a:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++ __u8 a:1, ++ b:1, ++ rsv:5, ++ h:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 sender_key; ++ __u64 receiver_key; ++} __attribute__((__packed__)); ++ ++struct mp_join { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ u32 token; ++ u32 nonce; ++ } syn; ++ struct { ++ __u64 mac; ++ u32 nonce; ++ } synack; ++ struct { ++ __u8 mac[20]; ++ } ack; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_dss { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ A:1, ++ a:1, ++ M:1, ++ m:1, ++ F:1, ++ rsv2:3; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:3, ++ F:1, ++ m:1, ++ M:1, ++ a:1, ++ A:1; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_add_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ipver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ipver:4; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ struct in_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v4; ++ struct { ++ struct in6_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v6; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_remove_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 rsv:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:4; ++#else ++#error "Adjust your defines" ++#endif ++ /* list of addr_id */ ++ __u8 addrs_id; ++}; ++ ++struct mp_fail { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __be64 data_seq; ++} __attribute__((__packed__)); ++ ++struct mp_fclose { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 key; ++} __attribute__((__packed__)); ++ ++struct mp_prio { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++} __attribute__((__packed__)); ++ ++static inline int mptcp_sub_len_dss(const struct mp_dss *m, const int csum) ++{ ++ return 4 + m->A * (4 + m->a * 4) + m->M * (10 + m->m * 4 + csum * 2); ++} ++ ++#define MPTCP_SYSCTL 1 ++ ++extern int sysctl_mptcp_enabled; ++extern int sysctl_mptcp_version; ++extern int sysctl_mptcp_checksum; ++extern int sysctl_mptcp_debug; ++extern int sysctl_mptcp_syn_retries; ++ ++extern struct workqueue_struct *mptcp_wq; ++ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ if (unlikely(sysctl_mptcp_debug)) \ ++ pr_err(fmt, ##args); \ ++ } while (0) ++ ++static inline struct sock *mptcp_to_sock(const struct mptcp_tcp_sock *mptcp) ++{ ++ return (struct sock *)mptcp->tp; ++} ++ ++#define mptcp_for_each_sub(__mpcb, __mptcp) \ ++ hlist_for_each_entry_rcu(__mptcp, &((__mpcb)->conn_list), node) ++ ++/* Must be called with the appropriate lock held */ ++#define mptcp_for_each_sub_safe(__mpcb, __mptcp, __tmp) \ ++ hlist_for_each_entry_safe(__mptcp, __tmp, &((__mpcb)->conn_list), node) ++ ++/* Iterates over all bit set to 1 in a bitset */ ++#define mptcp_for_each_bit_set(b, i) \ ++ for (i = ffs(b) - 1; i >= 0; i = ffs(b >> (i + 1) << (i + 1)) - 1) ++ ++#define mptcp_for_each_bit_unset(b, i) \ ++ mptcp_for_each_bit_set(~b, i) ++ ++#define MPTCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++#define MPTCP_INC_STATS_BH(net, field) __SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++ ++enum ++{ ++ MPTCP_MIB_NUM = 0, ++ MPTCP_MIB_MPCAPABLEPASSIVE, /* Received SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVE, /* Sent SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVEACK, /* Received SYN/ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLERETRANSFALLBACK,/* Client-side stopped sending MP_CAPABLE after too many SYN-retransmissions */ ++ MPTCP_MIB_CSUMENABLED, /* Created MPTCP-connection with DSS-checksum enabled */ ++ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ ++ MPTCP_MIB_MPFAILRX, /* Received an MP_FAIL */ ++ MPTCP_MIB_CSUMFAIL, /* Received segment with invalid checksum */ ++ MPTCP_MIB_FASTCLOSERX, /* Recevied a FAST_CLOSE */ ++ MPTCP_MIB_FASTCLOSETX, /* Sent a FAST_CLOSE */ ++ MPTCP_MIB_FBACKSUB, /* Fallback upon ack without data-ack on new subflow */ ++ MPTCP_MIB_FBACKINIT, /* Fallback upon ack without data-ack on initial subflow */ ++ MPTCP_MIB_FBDATASUB, /* Fallback upon data without DSS at the beginning on new subflow */ ++ MPTCP_MIB_FBDATAINIT, /* Fallback upon data without DSS at the beginning on initial subflow */ ++ MPTCP_MIB_REMADDRSUB, /* Remove subflow due to REMOVE_ADDR */ ++ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ ++ MPTCP_MIB_JOINFALLBACK, /* Received MP_JOIN on session that has fallen back to reg. TCP */ ++ MPTCP_MIB_JOINSYNTX, /* Sent a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNRX, /* Received a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKRX, /* Received a SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKFAIL, /* Third ACK on new subflow did not contain an MP_JOIN */ ++ MPTCP_MIB_JOINACKRTO, /* Retransmission timer for third ACK + MP_JOIN timed out */ ++ MPTCP_MIB_JOINACKRXMIT, /* Retransmitted an ACK + MP_JOIN */ ++ MPTCP_MIB_NODSSWINDOW, /* Received too many packets without a DSS-option */ ++ MPTCP_MIB_DSSNOMATCH, /* Received a new mapping that did not match the previous one */ ++ MPTCP_MIB_INFINITEMAPRX, /* Received an infinite mapping */ ++ MPTCP_MIB_DSSTCPMISMATCH, /* DSS-mapping did not map with TCP's sequence numbers */ ++ MPTCP_MIB_DSSTRIMHEAD, /* Trimmed segment at the head (coalescing middlebox) */ ++ MPTCP_MIB_DSSSPLITTAIL, /* Trimmed segment at the tail (coalescing middlebox) */ ++ MPTCP_MIB_PURGEOLD, /* Removed old skb from the rcv-queue due to missing DSS-mapping */ ++ MPTCP_MIB_ADDADDRRX, /* Received an ADD_ADDR */ ++ MPTCP_MIB_ADDADDRTX, /* Sent an ADD_ADDR */ ++ MPTCP_MIB_REMADDRRX, /* Received a REMOVE_ADDR */ ++ MPTCP_MIB_REMADDRTX, /* Sent a REMOVE_ADDR */ ++ __MPTCP_MIB_MAX ++}; ++ ++#define MPTCP_MIB_MAX __MPTCP_MIB_MAX ++struct mptcp_mib { ++ unsigned long mibs[MPTCP_MIB_MAX]; ++}; ++ ++extern struct lock_class_key meta_key; ++extern char *meta_key_name; ++extern struct lock_class_key meta_slock_key; ++extern char *meta_slock_key_name; ++ ++extern siphash_key_t mptcp_secret; ++ ++/* This is needed to ensure that two subsequent key/nonce-generation result in ++ * different keys/nonces if the IPs and ports are the same. ++ */ ++extern u32 mptcp_seed; ++ ++#define MPTCP_HASH_SIZE 1024 ++ ++extern struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++ ++/* Request-sockets can be hashed in the tk_htb for collision-detection or in ++ * the regular htb for join-connections. We need to define different NULLS ++ * values so that we can correctly detect a request-socket that has been ++ * recycled. See also c25eb3bfb9729. ++ */ ++#define MPTCP_REQSK_NULLS_BASE (1U << 29) ++ ++ ++void mptcp_data_ready(struct sock *sk); ++void mptcp_write_space(struct sock *sk); ++ ++void mptcp_add_meta_ofo_queue(const struct sock *meta_sk, struct sk_buff *skb, ++ struct sock *sk); ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied); ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags); ++void mptcp_del_sock(struct sock *sk); ++void mptcp_update_metasocket(const struct sock *meta_sk); ++void mptcp_reinject_data(struct sock *orig_sk, int clone_it); ++void mptcp_update_sndbuf(const struct tcp_sock *tp); ++void mptcp_send_fin(struct sock *meta_sk); ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority); ++bool mptcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt); ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp); ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size); ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb); ++void mptcp_close(struct sock *meta_sk, long timeout); ++bool mptcp_doit(struct sock *sk); ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window); ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req); ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop, u32 tsoff); ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++u32 __mptcp_select_window(struct sock *sk); ++void mptcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, ++ __u32 *rcv_wnd, __u32 *window_clamp, ++ int wscale_ok, __u8 *rcv_wscale, ++ __u32 init_rcv_wnd); ++unsigned int mptcp_current_mss(struct sock *meta_sk); ++int mptcp_select_size(const struct sock *meta_sk, bool first_skb, bool zc); ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...); ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk); ++void mptcp_fin(struct sock *meta_sk); ++void mptcp_meta_retransmit_timer(struct sock *meta_sk); ++void mptcp_sub_retransmit_timer(struct sock *sk); ++int mptcp_write_wakeup(struct sock *meta_sk, int mib); ++void mptcp_sub_close_wq(struct work_struct *work); ++void mptcp_sub_close(struct sock *sk, unsigned long delay); ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk); ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb); ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_ack_handler(struct timer_list *t); ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time); ++int mptcp_check_snd_buf(const struct tcp_sock *tp); ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb); ++void __init mptcp_init(void); ++void mptcp_destroy_sock(struct sock *sk); ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed); ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw); ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw); ++void mptcp_time_wait(struct sock *sk, int state, int timeo); ++void mptcp_disconnect(struct sock *meta_sk); ++bool mptcp_should_expand_sndbuf(const struct sock *sk); ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_tsq_flags(struct sock *sk); ++void mptcp_tsq_sub_deferred(struct sock *meta_sk); ++struct mp_join *mptcp_find_join(const struct sk_buff *skb); ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp); ++struct sock *mptcp_hash_find(const struct net *net, const u32 token); ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw); ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net); ++void mptcp_reqsk_destructor(struct request_sock *req); ++void mptcp_connect_init(struct sock *sk); ++void mptcp_sub_force_close(struct sock *sk); ++int mptcp_sub_len_remove_addr_align(u16 bitfield); ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb); ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie); ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb); ++void mptcp_enable_sock(struct sock *sk); ++void mptcp_disable_sock(struct sock *sk); ++void mptcp_disable_static_key(void); ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb); ++void mptcp_mpcb_put(struct mptcp_cb *mpcb); ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb); ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen); ++void mptcp_clear_sk(struct sock *sk, int size); ++ ++/* MPTCP-path-manager registration/initialization functions */ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_init_path_manager(struct mptcp_cb *mpcb); ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb); ++void mptcp_fallback_default(struct mptcp_cb *mpcb); ++void mptcp_get_default_path_manager(char *name); ++int mptcp_set_scheduler(struct sock *sk, const char *name); ++int mptcp_set_path_manager(struct sock *sk, const char *name); ++int mptcp_set_default_path_manager(const char *name); ++extern struct mptcp_pm_ops mptcp_pm_default; ++ ++/* MPTCP-scheduler registration/initialization functions */ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_init_scheduler(struct mptcp_cb *mpcb); ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb); ++void mptcp_get_default_scheduler(char *name); ++int mptcp_set_default_scheduler(const char *name); ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test); ++bool mptcp_is_def_unavailable(struct sock *sk); ++bool subflow_is_active(const struct tcp_sock *tp); ++bool subflow_is_backup(const struct tcp_sock *tp); ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test); ++extern struct mptcp_sched_ops mptcp_sched_default; ++ ++/* Initializes function-pointers and MPTCP-flags */ ++static inline void mptcp_init_tcp_sock(struct sock *sk) ++{ ++ if (!mptcp_init_failed && sysctl_mptcp_enabled == MPTCP_SYSCTL) ++ mptcp_enable_sock(sk); ++} ++ ++static inline int mptcp_pi_to_flag(int pi) ++{ ++ return 1 << (pi - 1); ++} ++ ++static inline ++struct mptcp_request_sock *mptcp_rsk(const struct request_sock *req) ++{ ++ return (struct mptcp_request_sock *)req; ++} ++ ++static inline ++struct request_sock *rev_mptcp_rsk(const struct mptcp_request_sock *req) ++{ ++ return (struct request_sock *)req; ++} ++ ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (tcp_sk(sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (!(sk_it->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) ++{ ++ /* We check packets out and send-head here. TCP only checks the ++ * send-head. But, MPTCP also checks packets_out, as this is an ++ * indication that we might want to do opportunistic reinjection. ++ */ ++ if (tcp_sk(meta_sk)->packets_out || tcp_send_head(meta_sk)) { ++ struct tcp_sock *tp = tcp_sk(meta_sk); ++ ++ /* We don't care about the MSS, because it will be set in ++ * mptcp_write_xmit. ++ */ ++ __tcp_push_pending_frames(meta_sk, 0, tp->nonagle); ++ } ++} ++ ++static inline void mptcp_send_reset(struct sock *sk) ++{ ++ if (tcp_need_reset(sk->sk_state)) ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); ++ mptcp_sub_force_close(sk); ++} ++ ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it != except) ++ mptcp_send_reset(sk_it); ++ } ++} ++ ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ; ++} ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_FIN; ++} ++ ++/* Is it a data-fin while in infinite mapping mode? ++ * In infinite mode, a subflow-fin is in fact a data-fin. ++ */ ++static inline bool mptcp_is_data_fin2(const struct sk_buff *skb, ++ const struct tcp_sock *tp) ++{ ++ return mptcp_is_data_fin(skb) || ++ (tp->mpcb->infinite_mapping_rcv && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)); ++} ++ ++static inline u8 mptcp_get_64_bit(u64 data_seq, struct mptcp_cb *mpcb) ++{ ++ u64 data_seq_high = (u32)(data_seq >> 32); ++ ++ if (mpcb->rcv_high_order[0] == data_seq_high) ++ return 0; ++ else if (mpcb->rcv_high_order[1] == data_seq_high) ++ return MPTCPHDR_SEQ64_INDEX; ++ else ++ return MPTCPHDR_SEQ64_OFO; ++} ++ ++/* Sets the data_seq and returns pointer to the in-skb field of the data_seq. ++ * If the packet has a 64-bit dseq, the pointer points to the last 32 bits. ++ */ ++static inline __u32 *mptcp_skb_set_data_seq(const struct sk_buff *skb, ++ u32 *data_seq, ++ struct mptcp_cb *mpcb) ++{ ++ __u32 *ptr = (__u32 *)(skb_transport_header(skb) + TCP_SKB_CB(skb)->dss_off); ++ ++ if (TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ64_SET) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ if (mpcb) ++ TCP_SKB_CB(skb)->mptcp_flags |= mptcp_get_64_bit(data_seq64, mpcb); ++ ++ *data_seq = (u32)data_seq64; ++ ptr++; ++ } else { ++ *data_seq = get_unaligned_be32(ptr); ++ } ++ ++ return ptr; ++} ++ ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return tcp_sk(sk)->meta_sk; ++} ++ ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return tcp_sk(tp->meta_sk); ++} ++ ++static inline int is_meta_tp(const struct tcp_sock *tp) ++{ ++ return tp->mpcb && mptcp_meta_tp(tp) == tp; ++} ++ ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return sk->sk_state != TCP_NEW_SYN_RECV && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ mptcp(tcp_sk(sk)) && mptcp_meta_sk(sk) == sk; ++} ++ ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return !mptcp(tp) || (!tp->mptcp->slave_sk && !is_meta_tp(tp)); ++} ++ ++static inline void mptcp_init_mp_opt(struct mptcp_options_received *mopt) ++{ ++ mopt->saw_mpc = 0; ++ mopt->dss_csum = 0; ++ mopt->drop_me = 0; ++ ++ mopt->is_mp_join = 0; ++ mopt->join_ack = 0; ++ ++ mopt->saw_low_prio = 0; ++ mopt->low_prio = 0; ++ ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) ++{ ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ mopt->saw_low_prio = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->join_ack = 0; ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline __be32 mptcp_get_highorder_sndbits(const struct sk_buff *skb, ++ const struct mptcp_cb *mpcb) ++{ ++ return htonl(mpcb->snd_high_order[(TCP_SKB_CB(skb)->mptcp_flags & ++ MPTCPHDR_SEQ64_INDEX) ? 1 : 0]); ++} ++ ++static inline u64 mptcp_get_data_seq_64(const struct mptcp_cb *mpcb, int index, ++ u32 data_seq_32) ++{ ++ return ((u64)mpcb->rcv_high_order[index] << 32) | data_seq_32; ++} ++ ++static inline u64 mptcp_get_rcv_nxt_64(const struct tcp_sock *meta_tp) ++{ ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ return mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_nxt); ++} ++ ++static inline void mptcp_check_sndseq_wrap(struct tcp_sock *meta_tp, int inc) ++{ ++ if (unlikely(meta_tp->snd_nxt > meta_tp->snd_nxt + inc)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] += 2; ++ } ++} ++ ++static inline void mptcp_check_rcvseq_wrap(struct tcp_sock *meta_tp, ++ u32 old_rcv_nxt) ++{ ++ if (unlikely(old_rcv_nxt > meta_tp->rcv_nxt)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->rcv_high_order[mpcb->rcv_hiseq_index] += 2; ++ mpcb->rcv_hiseq_index = mpcb->rcv_hiseq_index ? 0 : 1; ++ } ++} ++ ++static inline int mptcp_sk_can_send(const struct sock *sk) ++{ ++ return tcp_passive_fastopen(sk) || ++ ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && ++ !tcp_sk(sk)->mptcp->pre_established); ++} ++ ++static inline int mptcp_sk_can_recv(const struct sock *sk) ++{ ++ return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2); ++} ++ ++static inline int mptcp_sk_can_send_ack(const struct sock *sk) ++{ ++ return !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | ++ TCPF_CLOSE | TCPF_LISTEN)) && ++ !tcp_sk(sk)->mptcp->pre_established; ++} ++ ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!(sk->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ return true; ++} ++ ++static inline void mptcp_set_rto(struct sock *sk) ++{ ++ struct inet_connection_sock *micsk = inet_csk(mptcp_meta_sk(sk)); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ __u32 max_rto = 0; ++ ++ /* We are in recovery-phase on the MPTCP-level. Do not update the ++ * RTO, because this would kill exponential backoff. ++ */ ++ if (micsk->icsk_retransmits) ++ return; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if ((mptcp_sk_can_send(sk_it) || sk_it->sk_state == TCP_SYN_RECV) && ++ inet_csk(sk_it)->icsk_retransmits == 0 && ++ inet_csk(sk_it)->icsk_backoff == 0 && ++ inet_csk(sk_it)->icsk_rto > max_rto) ++ max_rto = inet_csk(sk_it)->icsk_rto; ++ } ++ if (max_rto) { ++ micsk->icsk_rto = max_rto << 1; ++ ++ /* A successfull rto-measurement - reset backoff counter */ ++ micsk->icsk_backoff = 0; ++ } ++} ++ ++static inline void mptcp_sub_close_passive(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(meta_sk); ++ ++ /* Only close, if the app did a send-shutdown (passive close), and we ++ * received the data-ack of the data-fin. ++ */ ++ if (tp->mpcb->passive_close && meta_tp->snd_una == meta_tp->write_seq) ++ mptcp_sub_close(sk, 0); ++} ++ ++static inline void mptcp_fallback_close(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ mptcp_sub_force_close_all(mpcb, except); ++ ++ if (mpcb->pm_ops->close_session) ++ mpcb->pm_ops->close_session(mptcp_meta_sk(except)); ++} ++ ++static inline bool mptcp_fallback_infinite(struct sock *sk, int flag) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If data has been acknowleged on the meta-level, fully_established ++ * will have been set before and thus we will not fall back to infinite ++ * mapping. ++ */ ++ if (likely(tp->mptcp->fully_established)) ++ return false; ++ ++ if (!(flag & MPTCP_FLAG_DATA_ACKED)) ++ return false; ++ ++ /* Don't fallback twice ;) */ ++ if (mpcb->infinite_mapping_snd) ++ return false; ++ ++ pr_debug("%s %#x will fallback - pi %d, src %pI4:%u dst %pI4:%u rcv_nxt %u from %pS\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ &inet_sk(sk)->inet_saddr, ntohs(inet_sk(sk)->inet_sport), ++ &inet_sk(sk)->inet_daddr, ntohs(inet_sk(sk)->inet_dport), ++ tp->rcv_nxt, __builtin_return_address(0)); ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKSUB); ++ return true; ++ } ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ tp->mptcp->fully_established = 1; ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKINIT); ++ ++ return false; ++} ++ ++static inline bool mptcp_v6_is_v4_mapped(const struct sock *sk) ++{ ++ return sk->sk_family == AF_INET6 && ++ ipv6_addr_type(&inet6_sk(sk)->saddr) == IPV6_ADDR_MAPPED; ++} ++ ++/* We are in or are becoming to be in infinite mapping mode */ ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return mpcb->infinite_mapping_rcv || ++ mpcb->infinite_mapping_snd || ++ mpcb->send_infinite_mapping; ++} ++ ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ /* Has been removed from the tk-table. Thus, no new subflows. ++ * ++ * Check for close-state is necessary, because we may have been closed ++ * without passing by mptcp_close(). ++ * ++ * When falling back, no new subflows are allowed either. ++ */ ++ return meta_sk->sk_state != TCP_CLOSE && ++ tcp_sk(meta_sk)->inside_tk_table && ++ !tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv && ++ !tcp_sk(meta_sk)->mpcb->send_infinite_mapping; ++} ++ ++static inline int mptcp_subflow_count(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ int i = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) ++ i++; ++ ++ return i; ++} ++ ++/* TCP and MPTCP mpc flag-depending functions */ ++u16 mptcp_select_window(struct sock *sk); ++void mptcp_tcp_set_rto(struct sock *sk); ++ ++/* TCP and MPTCP flag-depending functions */ ++bool mptcp_prune_ofo_queue(struct sock *sk); ++ ++#else /* CONFIG_MPTCP */ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ } while (0) ++ ++static inline struct sock *mptcp_to_sock(const struct mptcp_tcp_sock *mptcp) ++{ ++ return NULL; ++} ++ ++#define mptcp_for_each_sub(__mpcb, __mptcp) \ ++ if (0) ++ ++#define MPTCP_INC_STATS(net, field) \ ++ do { \ ++ } while(0) ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return NULL; ++} ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return NULL; ++} ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return 0; ++} ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_del_sock(const struct sock *sk) {} ++static inline void mptcp_update_metasocket(const struct sock *meta_sk) {} ++static inline void mptcp_reinject_data(struct sock *orig_sk, int clone_it) {} ++static inline void mptcp_update_sndbuf(const struct tcp_sock *tp) {} ++static inline void mptcp_clean_rtx_infinite(const struct sk_buff *skb, ++ const struct sock *sk) {} ++static inline void mptcp_sub_close(struct sock *sk, unsigned long delay) {} ++static inline void mptcp_set_rto(const struct sock *sk) {} ++static inline void mptcp_send_fin(const struct sock *meta_sk) {} ++static inline void mptcp_parse_options(const uint8_t *ptr, const int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ const struct tcp_sock *tp) {} ++static inline void mptcp_syn_options(const struct sock *sk, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++static inline void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++ ++static inline void mptcp_established_options(struct sock *sk, ++ struct sk_buff *skb, ++ struct tcp_out_options *opts, ++ unsigned *size) {} ++static inline void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) {} ++static inline void mptcp_close(struct sock *meta_sk, long timeout) {} ++static inline bool mptcp_doit(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_check_req_fastopen(struct sock *child, ++ struct request_sock *req) ++{ ++ return 1; ++} ++static inline int mptcp_check_req_master(const struct sock *sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ const struct sk_buff *skb, ++ int drop, ++ u32 tsoff) ++{ ++ return 1; ++} ++static inline struct sock *mptcp_check_req_child(const struct sock *meta_sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return NULL; ++} ++static inline unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ return 0; ++} ++static inline void mptcp_sub_close_passive(struct sock *sk) {} ++static inline bool mptcp_fallback_infinite(const struct sock *sk, int flag) ++{ ++ return false; ++} ++static inline void mptcp_init_mp_opt(const struct mptcp_options_received *mopt) {} ++static inline void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) {} ++static inline bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ return false; ++} ++static inline int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) {} ++static inline void mptcp_send_reset(const struct sock *sk) {} ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) {} ++static inline bool mptcp_handle_options(struct sock *sk, ++ const struct tcphdr *th, ++ struct sk_buff *skb) ++{ ++ return false; ++} ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) {} ++static inline void __init mptcp_init(void) {} ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ return false; ++} ++static inline unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, ++ u32 mss_now, int large_allowed) ++{ ++ return 0; ++} ++static inline void mptcp_destroy_sock(struct sock *sk) {} ++static inline int mptcp_rcv_synsent_state_process(struct sock *sk, ++ struct sock **skptr, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return 0; ++} ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_init_tw_sock(struct sock *sk, ++ struct tcp_timewait_sock *tw) ++{ ++ return 0; ++} ++static inline void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) {} ++static inline void mptcp_disconnect(struct sock *meta_sk) {} ++static inline void mptcp_tsq_flags(struct sock *sk) {} ++static inline void mptcp_tsq_sub_deferred(struct sock *meta_sk) {} ++static inline void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) {} ++static inline void mptcp_remove_shortcuts(const struct mptcp_cb *mpcb, ++ const struct sk_buff *skb) {} ++static inline void mptcp_init_tcp_sock(struct sock *sk) {} ++static inline void mptcp_disable_static_key(void) {} ++static inline void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) {} ++static inline void mptcp_mpcb_put(struct mptcp_cb *mpcb) {} ++static inline void mptcp_fin(struct sock *meta_sk) {} ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return false; ++} ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_H */ +diff -aurN linux-4.19.104/include/net/mptcp_v4.h mptcp-mptcp_v0.95/include/net/mptcp_v4.h +--- linux-4.19.104/include/net/mptcp_v4.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/mptcp_v4.h 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,76 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef MPTCP_V4_H_ ++#define MPTCP_V4_H_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern struct request_sock_ops mptcp_request_sock_ops; ++extern const struct inet_connection_sock_af_ops mptcp_v4_specific; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++#ifdef CONFIG_MPTCP ++ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v4_search_req(const __be16 rport, const __be32 raddr, ++ const __be32 laddr, const struct net *net); ++int __mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ __be16 sport, struct mptcp_rem4 *rem, ++ struct sock **subsk); ++int mptcp_pm_v4_init(void); ++void mptcp_pm_v4_undo(void); ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport); ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed); ++ ++static inline int mptcp_init4_subsockets(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ return __mptcp_init4_subsockets(meta_sk, loc, 0, rem, NULL); ++} ++ ++#else ++ ++static inline int mptcp_v4_do_rcv(const struct sock *meta_sk, ++ const struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* MPTCP_V4_H_ */ +diff -aurN linux-4.19.104/include/net/mptcp_v6.h mptcp-mptcp_v0.95/include/net/mptcp_v6.h +--- linux-4.19.104/include/net/mptcp_v6.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/mptcp_v6.h 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,77 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_V6_H ++#define _MPTCP_V6_H ++ ++#include ++#include ++ ++#include ++ ++ ++#ifdef CONFIG_MPTCP ++extern const struct inet_connection_sock_af_ops mptcp_v6_mapped; ++extern const struct inet_connection_sock_af_ops mptcp_v6_specific; ++extern struct request_sock_ops mptcp6_request_sock_ops; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v6_search_req(const __be16 rport, const struct in6_addr *raddr, ++ const struct in6_addr *laddr, const struct net *net); ++int __mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ __be16 sport, struct mptcp_rem6 *rem, ++ struct sock **subsk); ++int mptcp_pm_v6_init(void); ++void mptcp_pm_v6_undo(void); ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport); ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed); ++ ++static inline int mptcp_init6_subsockets(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ return __mptcp_init6_subsockets(meta_sk, loc, 0, rem, NULL); ++} ++ ++#else /* CONFIG_MPTCP */ ++ ++#define mptcp_v6_mapped ipv6_mapped ++ ++static inline int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_V6_H */ +diff -aurN linux-4.19.104/include/net/net_namespace.h mptcp-mptcp_v0.95/include/net/net_namespace.h +--- linux-4.19.104/include/net/net_namespace.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/net_namespace.h 2020-02-17 11:29:55.000000000 +0100 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -110,6 +111,9 @@ + #if IS_ENABLED(CONFIG_IPV6) + struct netns_ipv6 ipv6; + #endif ++#if IS_ENABLED(CONFIG_MPTCP) ++ struct netns_mptcp mptcp; ++#endif + #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) + struct netns_ieee802154_lowpan ieee802154_lowpan; + #endif +diff -aurN linux-4.19.104/include/net/netns/mptcp.h mptcp-mptcp_v0.95/include/net/netns/mptcp.h +--- linux-4.19.104/include/net/netns/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/netns/mptcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,52 @@ ++/* ++ * MPTCP implementation - MPTCP namespace ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef __NETNS_MPTCP_H__ ++#define __NETNS_MPTCP_H__ ++ ++#include ++ ++enum { ++ MPTCP_PM_FULLMESH = 0, ++ MPTCP_PM_MAX ++}; ++ ++struct mptcp_mib; ++ ++struct netns_mptcp { ++ DEFINE_SNMP_STAT(struct mptcp_mib, mptcp_statistics); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_net_mptcp; ++#endif ++ ++ void *path_managers[MPTCP_PM_MAX]; ++}; ++ ++#endif /* __NETNS_MPTCP_H__ */ +diff -aurN linux-4.19.104/include/net/snmp.h mptcp-mptcp_v0.95/include/net/snmp.h +--- linux-4.19.104/include/net/snmp.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/snmp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -91,7 +91,6 @@ + atomic_long_t mibs[ICMP6MSG_MIB_MAX]; + }; + +- + /* TCP */ + #define TCP_MIB_MAX __TCP_MIB_MAX + struct tcp_mib { +diff -aurN linux-4.19.104/include/net/sock.h mptcp-mptcp_v0.95/include/net/sock.h +--- linux-4.19.104/include/net/sock.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/sock.h 2020-02-17 11:29:55.000000000 +0100 +@@ -815,6 +815,7 @@ + SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ + SOCK_TXTIME, ++ SOCK_MPTCP, /* MPTCP set on this socket */ + }; + + #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) +@@ -1118,6 +1119,7 @@ + void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); + int (*get_port)(struct sock *sk, unsigned short snum); ++ void (*clear_sk)(struct sock *sk, int size); + + /* Keeping track of sockets in use */ + #ifdef CONFIG_PROC_FS +diff -aurN linux-4.19.104/include/net/tcp.h mptcp-mptcp_v0.95/include/net/tcp.h +--- linux-4.19.104/include/net/tcp.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/tcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -185,6 +185,7 @@ + #define TCPOPT_SACK 5 /* SACK Block */ + #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ + #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ ++#define TCPOPT_MPTCP 30 + #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ + #define TCPOPT_EXP 254 /* Experimental */ + /* Magic number to be after the option value for sharing TCP +@@ -241,6 +242,31 @@ + */ + #define TFO_SERVER_WO_SOCKOPT1 0x400 + ++/* Flags from tcp_input.c for tcp_ack */ ++#define FLAG_DATA 0x01 /* Incoming frame contained data. */ ++#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ ++#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ ++#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ ++#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ ++#define FLAG_DATA_SACKED 0x20 /* New SACK. */ ++#define FLAG_ECE 0x40 /* ECE in this ACK */ ++#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ ++#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ ++#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ ++#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ ++#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ ++#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ ++#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ ++#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ ++#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ ++#define FLAG_ACK_MAYBE_DELAYED 0x10000 /* Likely a delayed ACK */ ++ ++#define MPTCP_FLAG_DATA_ACKED 0x20000 ++ ++#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) ++#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) ++#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) ++#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) + + /* sysctl variables for tcp */ + extern int sysctl_tcp_max_orphans; +@@ -313,6 +339,96 @@ + #define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) + #define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) + ++/**** START - Exports needed for MPTCP ****/ ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops; ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops; ++ ++struct mptcp_options_received; ++ ++void tcp_cleanup_rbuf(struct sock *sk, int copied); ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited); ++int tcp_close_state(struct sock *sk); ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb); ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib); ++void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb); ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask); ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle); ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle); ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss); ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, const struct sk_buff *skb); ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++int __pskb_trim_head(struct sk_buff *skb, int len); ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb); ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags); ++void tcp_reset(struct sock *sk); ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin); ++bool tcp_urg_mode(const struct tcp_sock *tp); ++void tcp_ack_probe(struct sock *sk); ++void tcp_rearm_rto(struct sock *sk); ++int tcp_write_timeout(struct sock *sk); ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout); ++void tcp_write_err(struct sock *sk); ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr); ++void tcp_update_skb_after_send(struct tcp_sock *tp, struct sk_buff *skb); ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++ ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb); ++void tcp_v4_reqsk_destructor(struct request_sock *req); ++ ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); ++void tcp_v6_destroy_sock(struct sock *sk); ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); ++void tcp_v6_hash(struct sock *sk); ++struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb); ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req); ++void tcp_v6_reqsk_destructor(struct request_sock *req); ++ ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, ++ int large_allowed); ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb); ++ ++void skb_clone_fraglist(struct sk_buff *skb); ++ ++void inet_twsk_free(struct inet_timewait_sock *tw); ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb); ++/* These states need RST on ABORT according to RFC793 */ ++static inline bool tcp_need_reset(int state) ++{ ++ return (1 << state) & ++ (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | ++ TCPF_FIN_WAIT2 | TCPF_SYN_RECV); ++} ++ ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen); ++void tcp_ofo_queue(struct sock *sk); ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb); ++int linear_payload_sz(bool first_skb); ++/**** END - Exports needed for MPTCP ****/ ++ + void tcp_tasklet_init(void); + + void tcp_v4_err(struct sk_buff *skb, u32); +@@ -412,7 +528,9 @@ + struct vm_area_struct *vma); + void tcp_parse_options(const struct net *net, const struct sk_buff *skb, + struct tcp_options_received *opt_rx, +- int estab, struct tcp_fastopen_cookie *foc); ++ struct mptcp_options_received *mopt_rx, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp); + const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); + + /* +@@ -421,6 +539,7 @@ + + void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); + void tcp_v4_mtu_reduced(struct sock *sk); ++void tcp_v6_mtu_reduced(struct sock *sk); + void tcp_req_err(struct sock *sk, u32 seq, bool abort); + int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); + struct sock *tcp_create_openreq_child(const struct sock *sk, +@@ -538,7 +657,8 @@ + + u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, + u16 *mssp); +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + u64 cookie_init_timestamp(struct request_sock *req); + bool cookie_timestamp_decode(const struct net *net, + struct tcp_options_received *opt); +@@ -552,7 +672,8 @@ + + u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, + const struct tcphdr *th, u16 *mssp); +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + /* tcp_output.c */ + +@@ -588,10 +709,16 @@ + void tcp_skb_collapse_tstamp(struct sk_buff *skb, + const struct sk_buff *next_skb); + ++u16 tcp_select_window(struct sock *sk); ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ + /* tcp_input.c */ + void tcp_rearm_rto(struct sock *sk); + void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); + void tcp_reset(struct sock *sk); ++void tcp_set_rto(struct sock *sk); ++bool tcp_should_expand_sndbuf(const struct sock *sk); + void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); + void tcp_fin(struct sock *sk); + +@@ -635,7 +762,7 @@ + } + + /* tcp.c */ +-void tcp_get_info(struct sock *, struct tcp_info *); ++void tcp_get_info(struct sock *, struct tcp_info *, bool no_lock); + + /* Read 'sendfile()'-style from a TCP socket */ + int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, +@@ -823,6 +950,12 @@ + u16 tcp_gso_size; + }; + }; ++ ++#ifdef CONFIG_MPTCP ++ __u8 mptcp_flags; /* flags for the MPTCP layer */ ++ __u8 dss_off; /* Number of 4-byte words until ++ * seq-number */ ++#endif + __u8 tcp_flags; /* TCP header flags. (tcp[13]) */ + + __u8 sacked; /* State flags for SACK. */ +@@ -841,6 +974,14 @@ + has_rxtstamp:1, /* SKB has a RX timestamp */ + unused:5; + __u32 ack_seq; /* Sequence number ACK'd */ ++ ++#ifdef CONFIG_MPTCP ++ union { /* For MPTCP outgoing frames */ ++ __u32 path_mask; /* paths that tried to send this skb */ ++ __u32 dss[6]; /* DSS options */ ++ }; ++#endif ++ + union { + struct { + /* There is space for up to 24 bytes */ +@@ -1067,6 +1208,8 @@ + int tcp_set_allowed_congestion_control(char *allowed); + int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, + bool reinit, bool cap_net_admin); ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); + u32 tcp_slow_start(struct tcp_sock *tp, u32 acked); + void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked); + +@@ -1361,6 +1504,19 @@ + space - (space>>tcp_adv_win_scale); + } + ++#ifdef CONFIG_MPTCP ++extern struct static_key mptcp_static_key; ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return static_key_false(&mptcp_static_key) && tp->mpc; ++} ++#else ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++#endif ++ + /* Note: caller must be prepared to deal with negative returns */ + static inline int tcp_space(const struct sock *sk) + { +@@ -1893,6 +2049,32 @@ + #endif + }; + ++/* TCP/MPTCP-specific functions */ ++struct tcp_sock_ops { ++ u32 (*__select_window)(struct sock *sk); ++ u16 (*select_window)(struct sock *sk); ++ void (*select_initial_window)(const struct sock *sk, int __space, ++ __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd); ++ int (*select_size)(const struct sock *sk, bool first_skb, bool zc); ++ void (*init_buffer_space)(struct sock *sk); ++ void (*set_rto)(struct sock *sk); ++ bool (*should_expand_sndbuf)(const struct sock *sk); ++ void (*send_fin)(struct sock *sk); ++ bool (*write_xmit)(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ void (*send_active_reset)(struct sock *sk, gfp_t priority); ++ int (*write_wakeup)(struct sock *sk, int mib); ++ void (*retransmit_timer)(struct sock *sk); ++ void (*time_wait)(struct sock *sk, int state, int timeo); ++ void (*cleanup_rbuf)(struct sock *sk, int copied); ++ void (*cwnd_validate)(struct sock *sk, bool is_cwnd_limited); ++ int (*set_cong_ctrl)(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); ++}; ++extern const struct tcp_sock_ops tcp_specific; ++ + struct tcp_request_sock_ops { + u16 mss_clamp; + #ifdef CONFIG_TCP_MD5SIG +@@ -1903,12 +2085,13 @@ + const struct sock *sk, + const struct sk_buff *skb); + #endif +- void (*init_req)(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb); ++ int (*init_req)(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie); + #ifdef CONFIG_SYN_COOKIES +- __u32 (*cookie_init_seq)(const struct sk_buff *skb, +- __u16 *mss); ++ __u32 (*cookie_init_seq)(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, + const struct request_sock *req); +@@ -1922,15 +2105,17 @@ + + #ifdef CONFIG_SYN_COOKIES + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { + tcp_synq_overflow(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); +- return ops->cookie_init_seq(skb, mss); ++ return ops->cookie_init_seq(req, sk, skb, mss); + } + #else + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { +diff -aurN linux-4.19.104/include/net/tcp_states.h mptcp-mptcp_v0.95/include/net/tcp_states.h +--- linux-4.19.104/include/net/tcp_states.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/tcp_states.h 2020-02-17 11:29:55.000000000 +0100 +@@ -26,6 +26,7 @@ + TCP_LISTEN, + TCP_CLOSING, /* Now a valid state */ + TCP_NEW_SYN_RECV, ++ TCP_RST_WAIT, + + TCP_MAX_STATES /* Leave at the end! */ + }; +@@ -47,6 +48,7 @@ + TCPF_LISTEN = (1 << TCP_LISTEN), + TCPF_CLOSING = (1 << TCP_CLOSING), + TCPF_NEW_SYN_RECV = (1 << TCP_NEW_SYN_RECV), ++ TCPF_RST_WAIT = (1 << TCP_RST_WAIT), + }; + + #endif /* _LINUX_TCP_STATES_H */ +diff -aurN linux-4.19.104/include/net/transp_v6.h mptcp-mptcp_v0.95/include/net/transp_v6.h +--- linux-4.19.104/include/net/transp_v6.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/net/transp_v6.h 2020-02-17 11:29:55.000000000 +0100 +@@ -58,6 +58,8 @@ + + /* address family specific functions */ + extern const struct inet_connection_sock_af_ops ipv4_specific; ++extern const struct inet_connection_sock_af_ops ipv6_mapped; ++extern const struct inet_connection_sock_af_ops ipv6_specific; + + void inet6_destroy_sock(struct sock *sk); + +diff -aurN linux-4.19.104/include/trace/events/tcp.h mptcp-mptcp_v0.95/include/trace/events/tcp.h +--- linux-4.19.104/include/trace/events/tcp.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/trace/events/tcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + + #define TP_STORE_V4MAPPED(__entry, saddr, daddr) \ +@@ -178,6 +179,13 @@ + TP_ARGS(sk) + ); + ++DEFINE_EVENT(tcp_event_sk_skb, mptcp_retransmit, ++ ++ TP_PROTO(const struct sock *sk, const struct sk_buff *skb), ++ ++ TP_ARGS(sk, skb) ++); ++ + TRACE_EVENT(tcp_retransmit_synack, + + TP_PROTO(const struct sock *sk, const struct request_sock *req), +@@ -245,6 +253,7 @@ + __field(__u32, srtt) + __field(__u32, rcv_wnd) + __field(__u64, sock_cookie) ++ __field(__u8, mptcp) + ), + + TP_fast_assign( +@@ -271,13 +280,15 @@ + __entry->ssthresh = tcp_current_ssthresh(sk); + __entry->srtt = tp->srtt_us >> 3; + __entry->sock_cookie = sock_gen_cookie(sk); ++ __entry->mptcp = mptcp(tp) ? tp->mptcp->path_index : 0; + ), + +- TP_printk("src=%pISpc dest=%pISpc mark=%#x data_len=%d snd_nxt=%#x snd_una=%#x snd_cwnd=%u ssthresh=%u snd_wnd=%u srtt=%u rcv_wnd=%u sock_cookie=%llx", ++ TP_printk("src=%pISpc dest=%pISpc mark=%#x data_len=%d snd_nxt=%#x snd_una=%#x snd_cwnd=%u ssthresh=%u snd_wnd=%u srtt=%u rcv_wnd=%u sock_cookie=%llx mptcp=%d", + __entry->saddr, __entry->daddr, __entry->mark, + __entry->data_len, __entry->snd_nxt, __entry->snd_una, + __entry->snd_cwnd, __entry->ssthresh, __entry->snd_wnd, +- __entry->srtt, __entry->rcv_wnd, __entry->sock_cookie) ++ __entry->srtt, __entry->rcv_wnd, __entry->sock_cookie, ++ __entry->mptcp) + ); + + #endif /* _TRACE_TCP_H */ +diff -aurN linux-4.19.104/include/uapi/linux/bpf.h mptcp-mptcp_v0.95/include/uapi/linux/bpf.h +--- linux-4.19.104/include/uapi/linux/bpf.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/uapi/linux/bpf.h 2020-02-17 11:29:55.000000000 +0100 +@@ -2674,6 +2674,7 @@ + BPF_TCP_LISTEN, + BPF_TCP_CLOSING, /* Now a valid state */ + BPF_TCP_NEW_SYN_RECV, ++ BPF_TCP_RST_WAIT, + + BPF_TCP_MAX_STATES /* Leave at the end! */ + }; +diff -aurN linux-4.19.104/include/uapi/linux/if.h mptcp-mptcp_v0.95/include/uapi/linux/if.h +--- linux-4.19.104/include/uapi/linux/if.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/uapi/linux/if.h 2020-02-17 11:29:55.000000000 +0100 +@@ -132,6 +132,9 @@ + #define IFF_ECHO IFF_ECHO + #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + ++#define IFF_NOMULTIPATH 0x80000 /* Disable for MPTCP */ ++#define IFF_MPBACKUP 0x100000 /* Use as backup path for MPTCP */ ++ + #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +diff -aurN linux-4.19.104/include/uapi/linux/mptcp.h mptcp-mptcp_v0.95/include/uapi/linux/mptcp.h +--- linux-4.19.104/include/uapi/linux/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/uapi/linux/mptcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,149 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Netlink API for Multipath TCP ++ * ++ * Author: Gregory Detal ++ * ++ * 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. ++ */ ++ ++#ifndef _LINUX_MPTCP_H ++#define _LINUX_MPTCP_H ++ ++#define MPTCP_GENL_NAME "mptcp" ++#define MPTCP_GENL_EV_GRP_NAME "mptcp_events" ++#define MPTCP_GENL_CMD_GRP_NAME "mptcp_commands" ++#define MPTCP_GENL_VER 0x1 ++ ++/* ++ * ATTR types defined for MPTCP ++ */ ++enum { ++ MPTCP_ATTR_UNSPEC = 0, ++ ++ MPTCP_ATTR_TOKEN, /* u32 */ ++ MPTCP_ATTR_FAMILY, /* u16 */ ++ MPTCP_ATTR_LOC_ID, /* u8 */ ++ MPTCP_ATTR_REM_ID, /* u8 */ ++ MPTCP_ATTR_SADDR4, /* u32 */ ++ MPTCP_ATTR_SADDR6, /* struct in6_addr */ ++ MPTCP_ATTR_DADDR4, /* u32 */ ++ MPTCP_ATTR_DADDR6, /* struct in6_addr */ ++ MPTCP_ATTR_SPORT, /* u16 */ ++ MPTCP_ATTR_DPORT, /* u16 */ ++ MPTCP_ATTR_BACKUP, /* u8 */ ++ MPTCP_ATTR_ERROR, /* u8 */ ++ MPTCP_ATTR_FLAGS, /* u16 */ ++ MPTCP_ATTR_TIMEOUT, /* u32 */ ++ MPTCP_ATTR_IF_IDX, /* s32 */ ++ ++ __MPTCP_ATTR_AFTER_LAST ++}; ++ ++#define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) ++ ++/* ++ * Events generated by MPTCP: ++ * - MPTCP_EVENT_CREATED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * A new connection has been created. It is the good time to allocate ++ * memory and send ADD_ADDR if needed. Depending on the traffic-patterns ++ * it can take a long time until the MPTCP_EVENT_ESTABLISHED is sent. ++ * ++ * - MPTCP_EVENT_ESTABLISHED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * A connection is established (can start new subflows). ++ * ++ * - MPTCP_EVENT_CLOSED: token ++ * A connection has stopped. ++ * ++ * - MPTCP_EVENT_ANNOUNCED: token, rem_id, family, daddr4 | daddr6 [, dport] ++ * A new address has been announced by the peer. ++ * ++ * - MPTCP_EVENT_REMOVED: token, rem_id ++ * An address has been lost by the peer. ++ * ++ * - MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6, ++ * daddr4 | daddr6, sport, dport, backup, ++ * if_idx [, error] ++ * A new subflow has been established. 'error' should not be set. ++ * ++ * - MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup, if_idx [, error] ++ * A subflow has been closed. An error (copy of sk_err) could be set if an ++ * error has been detected for this subflow. ++ * ++ * - MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup, if_idx [, error] ++ * The priority of a subflow has changed. 'error' should not be set. ++ * ++ * Commands for MPTCP: ++ * - MPTCP_CMD_ANNOUNCE: token, loc_id, family, saddr4 | saddr6 [, sport] ++ * Announce a new address to the peer. ++ * ++ * - MPTCP_CMD_REMOVE: token, loc_id ++ * Announce that an address has been lost to the peer. ++ * ++ * - MPTCP_CMD_SUB_CREATE: token, family, loc_id, rem_id, [saddr4 | saddr6, ++ * daddr4 | daddr6, dport [, sport, backup, if_idx]] ++ * Create a new subflow. ++ * ++ * - MPTCP_CMD_SUB_DESTROY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * Close a subflow. ++ * ++ * - MPTCP_CMD_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup ++ * Change the priority of a subflow. ++ * ++ * - MPTCP_CMD_SET_FILTER: flags ++ * Set the filter on events. Set MPTCPF_* flags to only receive specific ++ * events. Default is to receive all events. ++ * ++ * - MPTCP_CMD_EXIST: token ++ * Check if this token is linked to an existing socket. ++ */ ++enum { ++ MPTCP_CMD_UNSPEC = 0, ++ ++ MPTCP_EVENT_CREATED, ++ MPTCP_EVENT_ESTABLISHED, ++ MPTCP_EVENT_CLOSED, ++ ++ MPTCP_CMD_ANNOUNCE, ++ MPTCP_CMD_REMOVE, ++ MPTCP_EVENT_ANNOUNCED, ++ MPTCP_EVENT_REMOVED, ++ ++ MPTCP_CMD_SUB_CREATE, ++ MPTCP_CMD_SUB_DESTROY, ++ MPTCP_EVENT_SUB_ESTABLISHED, ++ MPTCP_EVENT_SUB_CLOSED, ++ ++ MPTCP_CMD_SUB_PRIORITY, ++ MPTCP_EVENT_SUB_PRIORITY, ++ ++ MPTCP_CMD_SET_FILTER, ++ ++ MPTCP_CMD_EXIST, ++ ++ __MPTCP_CMD_AFTER_LAST ++}; ++ ++#define MPTCP_CMD_MAX (__MPTCP_CMD_AFTER_LAST - 1) ++ ++enum { ++ MPTCPF_EVENT_CREATED = (1 << 1), ++ MPTCPF_EVENT_ESTABLISHED = (1 << 2), ++ MPTCPF_EVENT_CLOSED = (1 << 3), ++ MPTCPF_EVENT_ANNOUNCED = (1 << 4), ++ MPTCPF_EVENT_REMOVED = (1 << 5), ++ MPTCPF_EVENT_SUB_ESTABLISHED = (1 << 6), ++ MPTCPF_EVENT_SUB_CLOSED = (1 << 7), ++ MPTCPF_EVENT_SUB_PRIORITY = (1 << 8), ++}; ++ ++#endif /* _LINUX_MPTCP_H */ +diff -aurN linux-4.19.104/include/uapi/linux/tcp.h mptcp-mptcp_v0.95/include/uapi/linux/tcp.h +--- linux-4.19.104/include/uapi/linux/tcp.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/include/uapi/linux/tcp.h 2020-02-17 11:29:55.000000000 +0100 +@@ -18,9 +18,15 @@ + #ifndef _UAPI_LINUX_TCP_H + #define _UAPI_LINUX_TCP_H + +-#include ++#ifndef __KERNEL__ ++#include ++#endif ++ + #include ++#include ++#include + #include ++#include + + struct tcphdr { + __be16 source; +@@ -131,6 +137,13 @@ + #define TCP_REPAIR_OFF 0 + #define TCP_REPAIR_OFF_NO_WP -1 /* Turn off without window probes */ + ++#define MPTCP_ENABLED 42 ++#define MPTCP_SCHEDULER 43 ++#define MPTCP_PATH_MANAGER 44 ++#define MPTCP_INFO 45 ++ ++#define MPTCP_INFO_FLAG_SAVE_MASTER 0x01 ++ + struct tcp_repair_opt { + __u32 opt_code; + __u32 opt_val; +@@ -268,6 +281,53 @@ + TCP_NLA_REORD_SEEN, /* reordering events seen */ + }; + ++struct mptcp_meta_info { ++ __u8 mptcpi_state; ++ __u8 mptcpi_retransmits; ++ __u8 mptcpi_probes; ++ __u8 mptcpi_backoff; ++ ++ __u32 mptcpi_rto; ++ __u32 mptcpi_unacked; ++ ++ /* Times. */ ++ __u32 mptcpi_last_data_sent; ++ __u32 mptcpi_last_data_recv; ++ __u32 mptcpi_last_ack_recv; ++ ++ __u32 mptcpi_total_retrans; ++ ++ __u64 mptcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ ++ __u64 mptcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ ++}; ++ ++struct mptcp_sub_info { ++ union { ++ struct sockaddr src; ++ struct sockaddr_in src_v4; ++ struct sockaddr_in6 src_v6; ++ }; ++ ++ union { ++ struct sockaddr dst; ++ struct sockaddr_in dst_v4; ++ struct sockaddr_in6 dst_v6; ++ }; ++}; ++ ++struct mptcp_info { ++ __u32 tcp_info_len; /* Length of each struct tcp_info in subflows pointer */ ++ __u32 sub_len; /* Total length of memory pointed to by subflows pointer */ ++ __u32 meta_len; /* Length of memory pointed to by meta_info */ ++ __u32 sub_info_len; /* Length of each struct mptcp_sub_info in subflow_info pointer */ ++ __u32 total_sub_info_len; /* Total length of memory pointed to by subflow_info */ ++ ++ struct mptcp_meta_info *meta_info; ++ struct tcp_info *initial; ++ struct tcp_info *subflows; /* Pointer to array of tcp_info structs */ ++ struct mptcp_sub_info *subflow_info; ++}; ++ + /* for TCP_MD5SIG socket option */ + #define TCP_MD5SIG_MAXKEYLEN 80 + +diff -aurN linux-4.19.104/net/core/dev.c mptcp-mptcp_v0.95/net/core/dev.c +--- linux-4.19.104/net/core/dev.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/core/dev.c 2020-02-17 11:29:55.000000000 +0100 +@@ -7636,7 +7636,7 @@ + + dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | + IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | +- IFF_AUTOMEDIA)) | ++ IFF_AUTOMEDIA | IFF_NOMULTIPATH | IFF_MPBACKUP)) | + (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | + IFF_ALLMULTI)); + +diff -aurN linux-4.19.104/net/core/net-traces.c mptcp-mptcp_v0.95/net/core/net-traces.c +--- linux-4.19.104/net/core/net-traces.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/core/net-traces.c 2020-02-17 11:29:55.000000000 +0100 +@@ -48,3 +48,5 @@ + EXPORT_TRACEPOINT_SYMBOL_GPL(napi_poll); + + EXPORT_TRACEPOINT_SYMBOL_GPL(tcp_send_reset); ++ ++EXPORT_TRACEPOINT_SYMBOL_GPL(mptcp_retransmit); +diff -aurN linux-4.19.104/net/core/skbuff.c mptcp-mptcp_v0.95/net/core/skbuff.c +--- linux-4.19.104/net/core/skbuff.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/core/skbuff.c 2020-02-17 11:29:55.000000000 +0100 +@@ -536,7 +536,7 @@ + skb_drop_list(&skb_shinfo(skb)->frag_list); + } + +-static void skb_clone_fraglist(struct sk_buff *skb) ++void skb_clone_fraglist(struct sk_buff *skb) + { + struct sk_buff *list; + +diff -aurN linux-4.19.104/net/core/sock.c mptcp-mptcp_v0.95/net/core/sock.c +--- linux-4.19.104/net/core/sock.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/core/sock.c 2020-02-17 11:29:55.000000000 +0100 +@@ -140,6 +140,11 @@ + + #include + ++#ifdef CONFIG_MPTCP ++#include ++#include ++#endif ++ + #include + #include + +@@ -1412,6 +1417,23 @@ + */ + static inline void sock_lock_init(struct sock *sk) + { ++#ifdef CONFIG_MPTCP ++ /* Reclassify the lock-class for subflows */ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ if (mptcp(tcp_sk(sk)) || tcp_sk(sk)->is_master_sk) { ++ sock_lock_init_class_and_name(sk, meta_slock_key_name, ++ &meta_slock_key, ++ meta_key_name, ++ &meta_key); ++ ++ /* We don't yet have the mptcp-point. ++ * Thus we still need inet_sock_destruct ++ */ ++ sk->sk_destruct = inet_sock_destruct; ++ return; ++ } ++#endif ++ + if (sk->sk_kern_sock) + sock_lock_init_class_and_name( + sk, +@@ -1460,8 +1482,12 @@ + sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); + if (!sk) + return sk; +- if (priority & __GFP_ZERO) +- sk_prot_clear_nulls(sk, prot->obj_size); ++ if (priority & __GFP_ZERO) { ++ if (prot->clear_sk) ++ prot->clear_sk(sk, prot->obj_size); ++ else ++ sk_prot_clear_nulls(sk, prot->obj_size); ++ } + } else + sk = kmalloc(prot->obj_size, priority); + +@@ -1689,6 +1715,7 @@ + atomic_set(&newsk->sk_zckey, 0); + + sock_reset_flag(newsk, SOCK_DONE); ++ sock_reset_flag(newsk, SOCK_MPTCP); + mem_cgroup_sk_alloc(newsk); + cgroup_sk_alloc(&newsk->sk_cgrp_data); + +diff -aurN linux-4.19.104/net/ipv4/af_inet.c mptcp-mptcp_v0.95/net/ipv4/af_inet.c +--- linux-4.19.104/net/ipv4/af_inet.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/af_inet.c 2020-02-17 11:29:55.000000000 +0100 +@@ -104,6 +104,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -150,6 +151,9 @@ + return; + } + ++ if (sock_flag(sk, SOCK_MPTCP)) ++ mptcp_disable_static_key(); ++ + WARN_ON(atomic_read(&sk->sk_rmem_alloc)); + WARN_ON(refcount_read(&sk->sk_wmem_alloc)); + WARN_ON(sk->sk_wmem_queued); +@@ -244,8 +248,7 @@ + * Create an inet socket. + */ + +-static int inet_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct sock *sk; + struct inet_protosw *answer; +@@ -739,6 +742,24 @@ + lock_sock(sk2); + + sock_rps_record_flow(sk2); ++ ++ if (sk2->sk_protocol == IPPROTO_TCP && mptcp(tcp_sk(sk2))) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk2)->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ ++ if (tcp_sk(sk2)->mpcb->master_sk) { ++ struct sock *sk_it = tcp_sk(sk2)->mpcb->master_sk; ++ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_it->sk_wq = newsock->wq; ++ sk_it->sk_socket = newsock; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ } ++ + WARN_ON(!((1 << sk2->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | + TCPF_CLOSE_WAIT | TCPF_CLOSE))); +@@ -1955,6 +1976,9 @@ + + ip_init(); + ++ /* We must initialize MPTCP before TCP. */ ++ mptcp_init(); ++ + /* Setup TCP slab cache for open requests. */ + tcp_init(); + +diff -aurN linux-4.19.104/net/ipv4/inet_connection_sock.c mptcp-mptcp_v0.95/net/ipv4/inet_connection_sock.c +--- linux-4.19.104/net/ipv4/inet_connection_sock.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/inet_connection_sock.c 2020-02-17 11:29:55.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -691,7 +692,10 @@ + int max_retries, thresh; + u8 defer_accept; + +- if (inet_sk_state_load(sk_listener) != TCP_LISTEN) ++ if (!is_meta_sk(sk_listener) && inet_sk_state_load(sk_listener) != TCP_LISTEN) ++ goto drop; ++ ++ if (is_meta_sk(sk_listener) && !mptcp_can_new_subflow(sk_listener)) + goto drop; + + max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; +@@ -784,7 +788,9 @@ + const struct request_sock *req, + const gfp_t priority) + { +- struct sock *newsk = sk_clone_lock(sk, priority); ++ struct sock *newsk; ++ ++ newsk = sk_clone_lock(sk, priority); + + if (newsk) { + struct inet_connection_sock *newicsk = inet_csk(newsk); +@@ -984,7 +990,14 @@ + */ + while ((req = reqsk_queue_remove(queue, sk)) != NULL) { + struct sock *child = req->sk; ++ bool mutex_taken = false; ++ struct mptcp_cb *mpcb = tcp_sk(child)->mpcb; + ++ if (is_meta_sk(child)) { ++ WARN_ON(refcount_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ mutex_taken = true; ++ } + local_bh_disable(); + bh_lock_sock(child); + WARN_ON(sock_owned_by_user(child)); +@@ -994,6 +1007,10 @@ + reqsk_put(req); + bh_unlock_sock(child); + local_bh_enable(); ++ if (mutex_taken) { ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ } + sock_put(child); + + cond_resched(); +diff -aurN linux-4.19.104/net/ipv4/ip_sockglue.c mptcp-mptcp_v0.95/net/ipv4/ip_sockglue.c +--- linux-4.19.104/net/ipv4/ip_sockglue.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/ip_sockglue.c 2020-02-17 11:29:55.000000000 +0100 +@@ -44,6 +44,8 @@ + #endif + #include + ++#include ++ + #include + #include + +@@ -655,7 +657,7 @@ + break; + old = rcu_dereference_protected(inet->inet_opt, + lockdep_sock_is_held(sk)); +- if (inet->is_icsk) { ++ if (inet->is_icsk && !is_meta_sk(sk)) { + struct inet_connection_sock *icsk = inet_csk(sk); + #if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family == PF_INET || +@@ -749,6 +751,20 @@ + inet->tos = val; + sk->sk_priority = rt_tos2priority(val); + sk_dst_reset(sk); ++ /* Update TOS on mptcp subflow */ ++ if (is_meta_sk(sk)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (inet_sk(sk_it)->tos != inet_sk(sk)->tos) { ++ inet_sk(sk_it)->tos = inet_sk(sk)->tos; ++ sk_it->sk_priority = sk->sk_priority; ++ sk_dst_reset(sk_it); ++ } ++ } ++ } + } + break; + case IP_TTL: +diff -aurN linux-4.19.104/net/ipv4/Kconfig mptcp-mptcp_v0.95/net/ipv4/Kconfig +--- linux-4.19.104/net/ipv4/Kconfig 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/Kconfig 2020-02-17 11:29:55.000000000 +0100 +@@ -680,6 +680,51 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_LIA ++ tristate "MPTCP Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Linked Increase Congestion Control ++ To enable it, just put 'lia' in tcp_congestion_control ++ ++config TCP_CONG_OLIA ++ tristate "MPTCP Opportunistic Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Opportunistic Linked Increase Congestion Control ++ To enable it, just put 'olia' in tcp_congestion_control ++ ++config TCP_CONG_WVEGAS ++ tristate "MPTCP WVEGAS CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ wVegas congestion control for MPTCP ++ To enable it, just put 'wvegas' in tcp_congestion_control ++ ++config TCP_CONG_BALIA ++ tristate "MPTCP BALIA CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ Multipath TCP Balanced Linked Adaptation Congestion Control ++ To enable it, just put 'balia' in tcp_congestion_control ++ ++config TCP_CONG_MCTCPDESYNC ++ tristate "DESYNCHRONIZED MCTCP CONGESTION CONTROL (EXPERIMENTAL)" ++ depends on MPTCP ++ default n ++ ---help--- ++ Desynchronized MultiChannel TCP Congestion Control. This is experimental ++ code that only supports single path and must have set mptcp_ndiffports ++ larger than one. ++ To enable it, just put 'mctcpdesync' in tcp_congestion_control ++ For further details see: ++ http://ieeexplore.ieee.org/abstract/document/6911722/ ++ https://doi.org/10.1016/j.comcom.2015.07.010 ++ + choice + prompt "Default TCP congestion control" + default DEFAULT_CUBIC +@@ -717,6 +762,21 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_LIA ++ bool "Lia" if TCP_CONG_LIA=y ++ ++ config DEFAULT_OLIA ++ bool "Olia" if TCP_CONG_OLIA=y ++ ++ config DEFAULT_WVEGAS ++ bool "Wvegas" if TCP_CONG_WVEGAS=y ++ ++ config DEFAULT_BALIA ++ bool "Balia" if TCP_CONG_BALIA=y ++ ++ config DEFAULT_MCTCPDESYNC ++ bool "Mctcpdesync (EXPERIMENTAL)" if TCP_CONG_MCTCPDESYNC=y ++ + config DEFAULT_RENO + bool "Reno" + endchoice +@@ -737,6 +797,10 @@ + default "vegas" if DEFAULT_VEGAS + default "westwood" if DEFAULT_WESTWOOD + default "veno" if DEFAULT_VENO ++ default "lia" if DEFAULT_LIA ++ default "olia" if DEFAULT_OLIA ++ default "wvegas" if DEFAULT_WVEGAS ++ default "balia" if DEFAULT_BALIA + default "reno" if DEFAULT_RENO + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG +diff -aurN linux-4.19.104/net/ipv4/syncookies.c mptcp-mptcp_v0.95/net/ipv4/syncookies.c +--- linux-4.19.104/net/ipv4/syncookies.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/syncookies.c 2020-02-17 11:29:55.000000000 +0100 +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -179,7 +181,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); + +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct iphdr *iph = ip_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -209,9 +212,27 @@ + struct inet_connection_sock *icsk = inet_csk(sk); + struct sock *child; + bool own_req; ++#ifdef CONFIG_MPTCP ++ int ret; ++#endif + + child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst, + NULL, &own_req); ++ ++#ifdef CONFIG_MPTCP ++ if (!child) ++ goto listen_overflow; ++ ++ ret = mptcp_check_req_master(sk, child, req, skb, 0, tsoff); ++ if (ret < 0) ++ return NULL; ++ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ ++listen_overflow: ++#endif ++ + if (child) { + refcount_set(&req->rsk_refcnt, 1); + tcp_sk(child)->tsoffset = tsoff; +@@ -289,6 +310,7 @@ + { + struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct tcp_sock *tp = tcp_sk(sk); +@@ -318,7 +340,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcp_ts_off(sock_net(sk), +@@ -331,7 +354,12 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp_request_sock_ops, sk, false); /* for safety */ ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ + if (!req) + goto out; + +@@ -351,6 +379,8 @@ + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + treq->snt_synack = 0; + treq->tfo_listener = false; +@@ -359,6 +389,9 @@ + + ireq->ir_iif = inet_request_bound_dev_if(sk, skb); + ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + /* We throwed the options of the initial SYN away, so we hope + * the ACK carries the same options again (see RFC1122 4.2.3.8) + */ +@@ -392,10 +425,10 @@ + /* Try to redo what tcp_v4_send_synack did. */ + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); + +- tcp_select_initial_window(sk, tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(&rt->dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(&rt->dst, RTAX_INITRWND)); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); +diff -aurN linux-4.19.104/net/ipv4/tcp.c mptcp-mptcp_v0.95/net/ipv4/tcp.c +--- linux-4.19.104/net/ipv4/tcp.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp.c 2020-02-17 11:29:55.000000000 +0100 +@@ -274,6 +274,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -399,6 +400,27 @@ + return rate64; + } + ++static int select_size(const struct sock *sk, bool first_skb, bool zc); ++ ++const struct tcp_sock_ops tcp_specific = { ++ .__select_window = __tcp_select_window, ++ .select_window = tcp_select_window, ++ .select_initial_window = tcp_select_initial_window, ++ .select_size = select_size, ++ .init_buffer_space = tcp_init_buffer_space, ++ .set_rto = tcp_set_rto, ++ .should_expand_sndbuf = tcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = tcp_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .cwnd_validate = tcp_cwnd_validate, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ + /* Address-family independent initialization for a tcp_sock. + * + * NOTE: A lot of things set to zero explicitly by call to +@@ -452,6 +474,11 @@ + sk->sk_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[1]; + sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1]; + ++ tp->ops = &tcp_specific; ++ ++ /* Initialize MPTCP-specific stuff and function-pointers */ ++ mptcp_init_tcp_sock(sk); ++ + sk_sockets_allocated_inc(sk); + sk->sk_route_forced_caps = NETIF_F_GSO; + } +@@ -466,7 +493,7 @@ + tcp_init_metrics(sk); + tcp_call_bpf(sk, bpf_op, 0, NULL); + tcp_init_congestion_control(sk); +- tcp_init_buffer_space(sk); ++ tcp_sk(sk)->ops->init_buffer_space(sk); + } + + static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) +@@ -786,6 +813,7 @@ + int ret; + + sock_rps_record_flow(sk); ++ + /* + * We can't seek on a socket input + */ +@@ -796,6 +824,16 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++#endif ++ + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); + while (tss.len) { + ret = __tcp_splice_read(sk, &tss); +@@ -899,8 +937,7 @@ + return NULL; + } + +-static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, +- int large_allowed) ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, int large_allowed) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 new_size_goal, size_goal; +@@ -928,8 +965,13 @@ + { + int mss_now; + +- mss_now = tcp_current_mss(sk); +- *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ if (mptcp(tcp_sk(sk))) { ++ mss_now = mptcp_current_mss(sk); ++ *size_goal = mptcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } else { ++ mss_now = tcp_current_mss(sk); ++ *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } + + return mss_now; + } +@@ -964,12 +1006,34 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto out_err; + } + ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ /* We must check this with socket-lock hold because we iterate ++ * over the subflows. ++ */ ++ if (!mptcp_can_sendpage(sk)) { ++ ssize_t ret; ++ ++ release_sock(sk); ++ ret = sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ lock_sock(sk); ++ return ret; ++ } ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++ + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + + mss_now = tcp_send_mss(sk, &size_goal, flags); +@@ -1088,7 +1152,8 @@ + int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, + size_t size, int flags) + { +- if (!(sk->sk_route_caps & NETIF_F_SG)) ++ /* If MPTCP is enabled, we check it later after establishment */ ++ if (!mptcp(tcp_sk(sk)) && !(sk->sk_route_caps & NETIF_F_SG)) + return sock_no_sendpage_locked(sk, page, offset, size, flags); + + tcp_rate_check_app_limited(sk); /* is sending application-limited? */ +@@ -1120,14 +1185,14 @@ + * This also speeds up tso_fragment(), since it wont fallback + * to tcp_fragment(). + */ +-static int linear_payload_sz(bool first_skb) ++int linear_payload_sz(bool first_skb) + { + if (first_skb) + return SKB_WITH_OVERHEAD(2048 - MAX_TCP_HEADER); + return 0; + } + +-static int select_size(bool first_skb, bool zc) ++static int select_size(const struct sock *sk, bool first_skb, bool zc) + { + if (zc) + return 0; +@@ -1237,12 +1302,21 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto do_error; + } + ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++ + if (unlikely(tp->repair)) { + if (tp->repair_queue == TCP_RECV_QUEUE) { + copied = tcp_send_rcvq(sk, msg, size); +@@ -1298,7 +1372,7 @@ + goto restart; + } + first_skb = tcp_rtx_and_write_queues_empty(sk); +- linear = select_size(first_skb, zc); ++ linear = tp->ops->select_size(sk, first_skb, zc); + skb = sk_stream_alloc_skb(sk, linear, sk->sk_allocation, + first_skb); + if (!skb) +@@ -1536,7 +1610,7 @@ + * calculation of whether or not we must ACK for the sake of + * a window update. + */ +-static void tcp_cleanup_rbuf(struct sock *sk, int copied) ++void tcp_cleanup_rbuf(struct sock *sk, int copied) + { + struct tcp_sock *tp = tcp_sk(sk); + bool time_to_ack = false; +@@ -1579,7 +1653,7 @@ + + /* Optimize, __tcp_select_window() is not cheap. */ + if (2*rcv_window_now <= tp->window_clamp) { +- __u32 new_window = __tcp_select_window(sk); ++ __u32 new_window = tp->ops->__select_window(sk); + + /* Send ACK now, if this read freed lots of space + * in our buffer. Certainly, new_window is new window. +@@ -1695,7 +1769,7 @@ + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) { + tcp_recv_skb(sk, seq, &offset); +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + } + return copied; + } +@@ -1952,6 +2026,16 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++#endif ++ + err = -ENOTCONN; + if (sk->sk_state == TCP_LISTEN) + goto out; +@@ -2070,7 +2154,7 @@ + } + } + +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + if (copied >= target) { + /* Do not sleep, just process backlog. */ +@@ -2161,7 +2245,7 @@ + */ + + /* Clean up data we have read: This will do ACK frames. */ +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + release_sock(sk); + +@@ -2273,7 +2357,7 @@ + [TCP_NEW_SYN_RECV] = TCP_CLOSE, /* should not happen ! */ + }; + +-static int tcp_close_state(struct sock *sk) ++int tcp_close_state(struct sock *sk) + { + int next = (int)new_state[sk->sk_state]; + int ns = next & TCP_STATE_MASK; +@@ -2303,7 +2387,7 @@ + TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { + /* Clear out any half completed packets. FIN if needed. */ + if (tcp_close_state(sk)) +- tcp_send_fin(sk); ++ tcp_sk(sk)->ops->send_fin(sk); + } + } + EXPORT_SYMBOL(tcp_shutdown); +@@ -2328,6 +2412,17 @@ + int data_was_unread = 0; + int state; + ++ if (is_meta_sk(sk)) { ++ /* TODO: Currently forcing timeout to 0 because ++ * sk_stream_wait_close will complain during lockdep because ++ * of the mpcb_mutex (circular lock dependency through ++ * inet_csk_listen_stop()). ++ * We should find a way to get rid of the mpcb_mutex. ++ */ ++ mptcp_close(sk, 0); ++ return; ++ } ++ + lock_sock(sk); + sk->sk_shutdown = SHUTDOWN_MASK; + +@@ -2372,7 +2467,7 @@ + /* Unread data was tossed, zap the connection. */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, sk->sk_allocation); ++ tcp_sk(sk)->ops->send_active_reset(sk, sk->sk_allocation); + } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + /* Check zero linger _after_ checking for unread data. */ + sk->sk_prot->disconnect(sk, 0); +@@ -2446,7 +2541,7 @@ + struct tcp_sock *tp = tcp_sk(sk); + if (tp->linger2 < 0) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONLINGER); + } else { +@@ -2456,7 +2551,8 @@ + inet_csk_reset_keepalive_timer(sk, + tmo - TCP_TIMEWAIT_LEN); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_FIN_WAIT2, ++ tmo); + goto out; + } + } +@@ -2465,7 +2561,7 @@ + sk_mem_reclaim(sk); + if (tcp_check_oom(sk, 0)) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { +@@ -2494,15 +2590,6 @@ + } + EXPORT_SYMBOL(tcp_close); + +-/* These states need RST on ABORT according to RFC793 */ +- +-static inline bool tcp_need_reset(int state) +-{ +- return (1 << state) & +- (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | +- TCPF_FIN_WAIT2 | TCPF_SYN_RECV); +-} +- + static void tcp_rtx_queue_purge(struct sock *sk) + { + struct rb_node *p = rb_first(&sk->tcp_rtx_queue); +@@ -2524,6 +2611,10 @@ + { + struct sk_buff *skb; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk) && ++ !tcp_rtx_and_write_queues_empty(sk)) ++ mptcp_reinject_data(sk, 0); ++ + tcp_chrono_stop(sk, TCP_CHRONO_BUSY); + while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { + tcp_skb_tsorted_anchor_cleanup(skb); +@@ -2558,7 +2649,7 @@ + /* The last check adjusts for discrepancy of Linux wrt. RFC + * states + */ +- tcp_send_active_reset(sk, gfp_any()); ++ tp->ops->send_active_reset(sk, gfp_any()); + sk->sk_err = ECONNRESET; + } else if (old_state == TCP_SYN_SENT) + sk->sk_err = ECONNRESET; +@@ -2576,6 +2667,13 @@ + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) + inet_reset_saddr(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_disconnect(sk); ++ } else { ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ + sk->sk_shutdown = 0; + sock_reset_flag(sk, SOCK_DONE); + tp->srtt_us = 0; +@@ -2636,7 +2734,7 @@ + static inline bool tcp_can_repair_sock(const struct sock *sk) + { + return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && +- (sk->sk_state != TCP_LISTEN); ++ (sk->sk_state != TCP_LISTEN) && !sock_flag(sk, SOCK_MPTCP); + } + + static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) +@@ -2782,6 +2880,61 @@ + + return tcp_fastopen_reset_cipher(net, sk, key, sizeof(key)); + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: { ++ char name[MPTCP_SCHED_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_SCHED_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_scheduler(sk, name); ++ release_sock(sk); ++ return err; ++ } ++ ++ case MPTCP_PATH_MANAGER: { ++ char name[MPTCP_PM_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_PM_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_path_manager(sk, name); ++ release_sock(sk); ++ return err; ++ } ++#endif + default: + /* fallthru */ + break; +@@ -2962,6 +3115,12 @@ + break; + + case TCP_DEFER_ACCEPT: ++ /* An established MPTCP-connection (mptcp(tp) only returns true ++ * if the socket is established) should not use DEFER on new ++ * subflows. ++ */ ++ if (mptcp(tp)) ++ break; + /* Translate value in seconds to number of retransmits */ + icsk->icsk_accept_queue.rskq_defer_accept = + secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, +@@ -2989,7 +3148,7 @@ + (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && + inet_csk_ack_scheduled(sk)) { + icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; +- tcp_cleanup_rbuf(sk, 1); ++ tp->ops->cleanup_rbuf(sk, 1); + if (!(val & 1)) + icsk->icsk_ack.pingpong = 1; + } +@@ -2999,7 +3158,7 @@ + #ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: + case TCP_MD5SIG_EXT: +- if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ++ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN) && !sock_flag(sk, SOCK_MPTCP)) + err = tp->af_specific->md5_parse(sk, optname, optval, optlen); + else + err = -EINVAL; +@@ -3058,6 +3217,32 @@ + tp->notsent_lowat = val; + sk->sk_write_space(sk); + break; ++#ifdef CONFIG_MPTCP ++ case MPTCP_ENABLED: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE ++#ifdef CONFIG_TCP_MD5SIG ++ || tp->md5sig_info ++#endif ++ ) { ++ err = -EPERM; ++ break; ++ } ++ ++ if (val) ++ mptcp_enable_sock(sk); ++ else ++ mptcp_disable_sock(sk); ++ break; ++ case MPTCP_INFO: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled) { ++ err = -EPERM; ++ break; ++ } ++ ++ tp->record_master_info = !!(val & MPTCP_INFO_FLAG_SAVE_MASTER); ++ break; ++#endif + case TCP_INQ: + if (val > 1 || val < 0) + err = -EINVAL; +@@ -3117,7 +3302,7 @@ + } + + /* Return information about state of tcp endpoint in API format. */ +-void tcp_get_info(struct sock *sk, struct tcp_info *info) ++void tcp_get_info(struct sock *sk, struct tcp_info *info, bool no_lock) + { + const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ + const struct inet_connection_sock *icsk = inet_csk(sk); +@@ -3154,7 +3339,8 @@ + return; + } + +- slow = lock_sock_fast(sk); ++ if (!no_lock) ++ slow = lock_sock_fast(sk); + + info->tcpi_ca_state = icsk->icsk_ca_state; + info->tcpi_retransmits = icsk->icsk_retransmits; +@@ -3228,7 +3414,9 @@ + info->tcpi_bytes_retrans = tp->bytes_retrans; + info->tcpi_dsack_dups = tp->dsack_dups; + info->tcpi_reord_seen = tp->reord_seen; +- unlock_sock_fast(sk, slow); ++ ++ if (!no_lock) ++ unlock_sock_fast(sk, slow); + } + EXPORT_SYMBOL_GPL(tcp_get_info); + +@@ -3373,7 +3561,7 @@ + if (get_user(len, optlen)) + return -EFAULT; + +- tcp_get_info(sk, &info); ++ tcp_get_info(sk, &info, false); + + len = min_t(unsigned int, len, sizeof(info)); + if (put_user(len, optlen)) +@@ -3564,6 +3752,87 @@ + } + return 0; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_SCHED_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->sched_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_sched_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_PATH_MANAGER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_PM_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->pm_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_pm_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_ENABLED: ++ if (sk->sk_state != TCP_SYN_SENT) ++ val = mptcp(tp) ? 1 : 0; ++ else ++ val = sock_flag(sk, SOCK_MPTCP) ? 1 : 0; ++ break; ++ case MPTCP_INFO: ++ { ++ int ret; ++ ++ if (!mptcp(tp)) ++ return -EINVAL; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(struct mptcp_info)); ++ ++ lock_sock(sk); ++ ret = mptcp_get_info(sk, optval, len); ++ release_sock(sk); ++ ++ if (ret) ++ return ret; ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ return 0; ++ } ++#endif + #ifdef CONFIG_MMU + case TCP_ZEROCOPY_RECEIVE: { + struct tcp_zerocopy_receive zc; +@@ -3757,7 +4026,9 @@ + if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); + ++ WARN_ON(sk->sk_state == TCP_CLOSE); + tcp_set_state(sk, TCP_CLOSE); ++ + tcp_clear_xmit_timers(sk); + if (req) + reqsk_fastopen_remove(sk, req, false); +@@ -3773,6 +4044,8 @@ + + int tcp_abort(struct sock *sk, int err) + { ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; ++ + if (!sk_fullsock(sk)) { + if (sk->sk_state == TCP_NEW_SYN_RECV) { + struct request_sock *req = inet_reqsk(sk); +@@ -3786,7 +4059,7 @@ + } + + /* Don't race with userspace socket closes such as tcp_close. */ +- lock_sock(sk); ++ lock_sock(meta_sk); + + if (sk->sk_state == TCP_LISTEN) { + tcp_set_state(sk, TCP_CLOSE); +@@ -3795,7 +4068,7 @@ + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); +- bh_lock_sock(sk); ++ bh_lock_sock(meta_sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = err; +@@ -3803,14 +4076,14 @@ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + local_bh_enable(); + tcp_write_queue_purge(sk); +- release_sock(sk); ++ release_sock(meta_sk); + return 0; + } + EXPORT_SYMBOL_GPL(tcp_abort); +diff -aurN linux-4.19.104/net/ipv4/tcp_cong.c mptcp-mptcp_v0.95/net/ipv4/tcp_cong.c +--- linux-4.19.104/net/ipv4/tcp_cong.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_cong.c 2020-02-17 11:29:55.000000000 +0100 +@@ -327,13 +327,19 @@ + return ret; + } + ++int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) ++{ ++ return tcp_sk(sk)->ops->set_cong_ctrl(sk, name, load, reinit, cap_net_admin); ++} ++ + /* Change congestion control for socket. If load is false, then it is the + * responsibility of the caller to call tcp_init_congestion_control or + * tcp_reinit_congestion_control (if the current congestion control was + * already initialized. + */ +-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, +- bool reinit, bool cap_net_admin) ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) + { + struct inet_connection_sock *icsk = inet_csk(sk); + const struct tcp_congestion_ops *ca; +diff -aurN linux-4.19.104/net/ipv4/tcp_diag.c mptcp-mptcp_v0.95/net/ipv4/tcp_diag.c +--- linux-4.19.104/net/ipv4/tcp_diag.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_diag.c 2020-02-17 11:29:55.000000000 +0100 +@@ -34,7 +34,7 @@ + r->idiag_wqueue = tp->write_seq - tp->snd_una; + } + if (info) +- tcp_get_info(sk, info); ++ tcp_get_info(sk, info, false); + } + + #ifdef CONFIG_TCP_MD5SIG +diff -aurN linux-4.19.104/net/ipv4/tcp_fastopen.c mptcp-mptcp_v0.95/net/ipv4/tcp_fastopen.c +--- linux-4.19.104/net/ipv4/tcp_fastopen.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_fastopen.c 2020-02-17 11:29:55.000000000 +0100 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + void tcp_fastopen_init_key_once(struct net *net) + { +@@ -218,8 +219,9 @@ + { + struct tcp_sock *tp; + struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; +- struct sock *child; ++ struct sock *child, *meta_sk; + bool own_req; ++ int ret; + + req->num_retrans = 0; + req->num_timeout = 0; +@@ -258,15 +260,26 @@ + + refcount_set(&req->rsk_refcnt, 2); + +- /* Now finish processing the fastopen child socket. */ +- tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB); +- + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + + tcp_fastopen_add_skb(child, skb); + + tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; + tp->rcv_wup = tp->rcv_nxt; ++ ++ meta_sk = child; ++ ret = mptcp_check_req_fastopen(meta_sk, req); ++ if (ret < 0) ++ return NULL; ++ ++ if (ret == 0) { ++ child = tcp_sk(meta_sk)->mpcb->master_sk; ++ tp = tcp_sk(child); ++ } ++ ++ /* Now finish processing the fastopen child socket. */ ++ tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB); ++ + /* tcp_conn_request() is sending the SYNACK, + * and queues the child into listener accept queue. + */ +diff -aurN linux-4.19.104/net/ipv4/tcp_input.c mptcp-mptcp_v0.95/net/ipv4/tcp_input.c +--- linux-4.19.104/net/ipv4/tcp_input.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_input.c 2020-02-17 11:29:55.000000000 +0100 +@@ -76,35 +76,15 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include + + int sysctl_tcp_max_orphans __read_mostly = NR_FILE; + +-#define FLAG_DATA 0x01 /* Incoming frame contained data. */ +-#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ +-#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ +-#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +-#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ +-#define FLAG_DATA_SACKED 0x20 /* New SACK. */ +-#define FLAG_ECE 0x40 /* ECE in this ACK */ +-#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ +-#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ +-#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ +-#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ +-#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ +-#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ +-#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ +-#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ +-#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ +-#define FLAG_ACK_MAYBE_DELAYED 0x10000 /* Likely a delayed ACK */ +- +-#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) +-#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) +-#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) +-#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) +- + #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) + #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) + +@@ -342,8 +322,12 @@ + per_mss = roundup_pow_of_two(per_mss) + + SKB_DATA_ALIGN(sizeof(struct sk_buff)); + +- nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); +- nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ if (mptcp(tp)) { ++ nr_segs = mptcp_check_snd_buf(tp); ++ } else { ++ nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); ++ nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ } + + /* Fast Recovery (RFC 5681 3.2) : + * Cubic needs 1.7 factor, rounded to 2 to include +@@ -352,8 +336,16 @@ + sndmem = ca_ops->sndbuf_expand ? ca_ops->sndbuf_expand(sk) : 2; + sndmem *= nr_segs * per_mss; + +- if (sk->sk_sndbuf < sndmem) ++ /* MPTCP: after this sndmem is the new contribution of the ++ * current subflow to the aggregated sndbuf */ ++ if (sk->sk_sndbuf < sndmem) { ++ int old_sndbuf = sk->sk_sndbuf; + sk->sk_sndbuf = min(sndmem, sock_net(sk)->ipv4.sysctl_tcp_wmem[2]); ++ /* MPTCP: ok, the subflow sndbuf has grown, reflect ++ * this in the aggregate buffer.*/ ++ if (mptcp(tp) && old_sndbuf != sk->sk_sndbuf) ++ mptcp_update_sndbuf(tp); ++ } + } + + /* 2. Tuning advertised window (window_clamp, rcv_ssthresh) +@@ -402,9 +394,14 @@ + static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); + int room; + +- room = min_t(int, tp->window_clamp, tcp_space(sk)) - tp->rcv_ssthresh; ++ if (is_meta_sk(sk)) ++ return; ++ ++ room = min_t(int, meta_tp->window_clamp, tcp_space(meta_sk)) - meta_tp->rcv_ssthresh; + + /* Check #1 */ + if (room > 0 && !tcp_under_memory_pressure(sk)) { +@@ -414,13 +411,13 @@ + * will fit to rcvbuf in future. + */ + if (tcp_win_from_space(sk, skb->truesize) <= skb->len) +- incr = 2 * tp->advmss; ++ incr = 2 * meta_tp->advmss; + else +- incr = __tcp_grow_window(sk, skb); ++ incr = __tcp_grow_window(meta_sk, skb); + + if (incr) { + incr = max_t(int, incr, 2 * skb->len); +- tp->rcv_ssthresh += min(room, incr); ++ meta_tp->rcv_ssthresh += min(room, incr); + inet_csk(sk)->icsk_ack.quick |= 1; + } + } +@@ -600,7 +597,10 @@ + + tcp_mstamp_refresh(tp); + time = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcvq_space.time); +- if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) ++ if (mptcp(tp)) { ++ if (mptcp_check_rtt(tp, time)) ++ return; ++ } else if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) + return; + + /* Number of bytes copied to user in last RTT */ +@@ -819,7 +819,7 @@ + /* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. + */ +-static void tcp_set_rto(struct sock *sk) ++void tcp_set_rto(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + /* Old crap is replaced with new one. 8) +@@ -1391,6 +1391,13 @@ + int len; + int in_sack; + ++ /* For MPTCP we cannot shift skb-data and remove one skb from the ++ * send-queue, because this will make us loose the DSS-option (which ++ * is stored in TCP_SKB_CB(skb)->dss) of the skb we are removing. ++ */ ++ if (mptcp(tp)) ++ goto fallback; ++ + /* Normally R but no L won't result in plain S */ + if (!dup_sack && + (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS) +@@ -2942,7 +2949,7 @@ + */ + tcp_update_rtt_min(sk, ca_rtt_us, flag); + tcp_rtt_estimator(sk, seq_rtt_us); +- tcp_set_rto(sk); ++ tp->ops->set_rto(sk); + + /* RFC6298: only reset backoff on valid RTT measurement. */ + inet_csk(sk)->icsk_backoff = 0; +@@ -3010,7 +3017,7 @@ + } + + /* If we get here, the whole TSO packet has not been acked. */ +-static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 packets_acked; +@@ -3136,6 +3143,8 @@ + */ + if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { + flag |= FLAG_DATA_ACKED; ++ if (mptcp(tp) && mptcp_is_data_seq(skb)) ++ flag |= MPTCP_FLAG_DATA_ACKED; + } else { + flag |= FLAG_SYN_ACKED; + tp->retrans_stamp = 0; +@@ -3255,7 +3264,7 @@ + return flag; + } + +-static void tcp_ack_probe(struct sock *sk) ++void tcp_ack_probe(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct sk_buff *head = tcp_send_head(sk); +@@ -3327,9 +3336,8 @@ + /* Check that window update is acceptable. + * The function assumes that snd_una<=ack<=snd_next. + */ +-static inline bool tcp_may_update_window(const struct tcp_sock *tp, +- const u32 ack, const u32 ack_seq, +- const u32 nwin) ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin) + { + return after(ack, tp->snd_una) || + after(ack_seq, tp->snd_wl1) || +@@ -3566,7 +3574,7 @@ + } + + /* This routine deals with incoming acks, but not outgoing ones. */ +-static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) ++static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -3679,6 +3687,16 @@ + + tcp_rack_update_reo_wnd(sk, &rs); + ++ if (mptcp(tp)) { ++ if (mptcp_fallback_infinite(sk, flag)) { ++ pr_debug("%s resetting flow\n", __func__); ++ mptcp_send_reset(sk); ++ goto invalid_ack; ++ } ++ ++ mptcp_clean_rtx_infinite(skb, sk); ++ } ++ + if (tp->tlp_high_seq) + tcp_process_tlp_ack(sk, ack, flag); + /* If needed, reset TLP/RTO timer; RACK may later override this. */ +@@ -3778,8 +3796,10 @@ + */ + void tcp_parse_options(const struct net *net, + const struct sk_buff *skb, +- struct tcp_options_received *opt_rx, int estab, +- struct tcp_fastopen_cookie *foc) ++ struct tcp_options_received *opt_rx, ++ struct mptcp_options_received *mopt, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp) + { + const unsigned char *ptr; + const struct tcphdr *th = tcp_hdr(skb); +@@ -3863,6 +3883,10 @@ + */ + break; + #endif ++ case TCPOPT_MPTCP: ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, tp); ++ break; ++ + case TCPOPT_FASTOPEN: + tcp_parse_fastopen_option( + opsize - TCPOLEN_FASTOPEN_BASE, +@@ -3930,7 +3954,9 @@ + return true; + } + +- tcp_parse_options(net, skb, &tp->rx_opt, 1, NULL); ++ tcp_parse_options(net, skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : NULL, 1, NULL, tp); ++ + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -4089,6 +4115,11 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_fin(sk); ++ return; ++ } ++ + inet_csk_schedule_ack(sk); + + sk->sk_shutdown |= RCV_SHUTDOWN; +@@ -4099,6 +4130,10 @@ + case TCP_ESTABLISHED: + /* Move to CLOSE_WAIT */ + tcp_set_state(sk, TCP_CLOSE_WAIT); ++ ++ if (mptcp(tp)) ++ mptcp_sub_close_passive(sk); ++ + inet_csk(sk)->icsk_ack.pingpong = 1; + break; + +@@ -4121,9 +4156,16 @@ + tcp_set_state(sk, TCP_CLOSING); + break; + case TCP_FIN_WAIT2: ++ if (mptcp(tp)) { ++ /* The socket will get closed by mptcp_data_ready. ++ * We first have to process all data-sequences. ++ */ ++ tp->close_it = 1; ++ break; ++ } + /* Received a FIN -- send ACK and enter TIME_WAIT. */ + tcp_send_ack(sk); +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + break; + default: + /* Only TCP_LISTEN and TCP_CLOSE are left, in these +@@ -4145,6 +4187,10 @@ + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + ++ /* Don't wake up MPTCP-subflows */ ++ if (mptcp(tp)) ++ return; ++ + /* Do not send POLL_HUP for half duplex close. */ + if (sk->sk_shutdown == SHUTDOWN_MASK || + sk->sk_state == TCP_CLOSE) +@@ -4347,6 +4393,9 @@ + + *fragstolen = false; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk)) ++ return false; ++ + /* Its possible this segment overlaps with prior segment in queue */ + if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) + return false; +@@ -4401,7 +4450,7 @@ + /* This one checks to see if we can put data from the + * out_of_order queue into the receive_queue. + */ +-static void tcp_ofo_queue(struct sock *sk) ++void tcp_ofo_queue(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + __u32 dsack_high = tp->rcv_nxt; +@@ -4424,7 +4473,14 @@ + p = rb_next(p); + rb_erase(&skb->rbnode, &tp->out_of_order_queue); + +- if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { ++ /* In case of MPTCP, the segment may be empty if it's a ++ * non-data DATA_FIN. (see beginning of tcp_data_queue) ++ * ++ * But this only holds true for subflows, not for the ++ * meta-socket. ++ */ ++ if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt) && ++ (is_meta_sk(sk) || !mptcp(tp) || TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq))) { + SOCK_DEBUG(sk, "ofo packet was already received\n"); + tcp_drop(sk, skb); + continue; +@@ -4458,6 +4514,9 @@ + static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, + unsigned int size) + { ++ if (mptcp(tcp_sk(sk))) ++ sk = mptcp_meta_sk(sk); ++ + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule(sk, skb, size)) { + +@@ -4472,7 +4531,7 @@ + return 0; + } + +-static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + struct rb_node **p, *parent; +@@ -4540,7 +4599,8 @@ + continue; + } + if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { +- if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq) && ++ (is_meta_sk(sk) || !mptcp(tp) || end_seq != seq)) { + /* All the bits are present. Drop. */ + NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPOFOMERGE); +@@ -4587,6 +4647,11 @@ + end_seq); + break; + } ++ /* MPTCP allows non-data data-fin to be in the ofo-queue */ ++ if (mptcp(tp) && !is_meta_sk(sk) && TCP_SKB_CB(skb1)->seq == TCP_SKB_CB(skb1)->end_seq) { ++ skb = skb1; ++ continue; ++ } + rb_erase(&skb1->rbnode, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); +@@ -4598,7 +4663,7 @@ + tp->ooo_last_skb = skb; + + add_sack: +- if (tcp_is_sack(tp)) ++ if (tcp_is_sack(tp) && seq != end_seq) + tcp_sack_new_ofo_skb(sk, seq, end_seq); + end: + if (skb) { +@@ -4608,8 +4673,8 @@ + } + } + +-static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, +- bool *fragstolen) ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen) + { + int eaten; + struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); +@@ -4683,7 +4748,7 @@ + const struct tcp_sock *tp = tcp_sk(sk); + int avail = tp->rcv_nxt - tp->copied_seq; + +- if (avail < sk->sk_rcvlowat && !sock_flag(sk, SOCK_DONE)) ++ if (avail < sk->sk_rcvlowat && !sock_flag(sk, SOCK_DONE) && !mptcp(tp)) + return; + + sk->sk_data_ready(sk); +@@ -4695,10 +4760,14 @@ + bool fragstolen; + int eaten; + +- if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { ++ /* If no data is present, but a data_fin is in the options, we still ++ * have to call mptcp_queue_skb later on. */ ++ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && ++ !(mptcp(tp) && mptcp_is_data_fin(skb))) { + __kfree_skb(skb); + return; + } ++ + skb_dst_drop(skb); + __skb_pull(skb, tcp_hdr(skb)->doff * 4); + +@@ -4726,7 +4795,7 @@ + } + + eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); +- if (skb->len) ++ if (skb->len || mptcp_is_data_fin(skb)) + tcp_event_data_recv(sk, skb); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) + tcp_fin(sk); +@@ -4748,7 +4817,11 @@ + + if (eaten > 0) + kfree_skb_partial(skb, fragstolen); +- if (!sock_flag(sk, SOCK_DEAD)) ++ if (!sock_flag(sk, SOCK_DEAD) || mptcp(tp)) ++ /* MPTCP: we always have to call data_ready, because ++ * we may be about to receive a data-fin, which still ++ * must get queued. ++ */ + tcp_data_ready(sk); + return; + } +@@ -5096,7 +5169,7 @@ + return -1; + } + +-static bool tcp_should_expand_sndbuf(const struct sock *sk) ++bool tcp_should_expand_sndbuf(const struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + +@@ -5131,7 +5204,7 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + +- if (tcp_should_expand_sndbuf(sk)) { ++ if (tp->ops->should_expand_sndbuf(sk)) { + tcp_sndbuf_expand(sk); + tp->snd_cwnd_stamp = tcp_jiffies32; + } +@@ -5145,10 +5218,11 @@ + sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); + /* pairs with tcp_poll() */ + smp_mb(); +- if (sk->sk_socket && +- test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ if (mptcp(tcp_sk(sk)) || ++ (sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))) { + tcp_new_space(sk); +- if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) ++ if (sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) + tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); + } + } +@@ -5167,6 +5241,8 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + unsigned long rtt, delay; ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); + + /* More than one full frame received... */ + if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && +@@ -5175,8 +5251,8 @@ + * If application uses SO_RCVLOWAT, we want send ack now if + * we have not received enough bytes to satisfy the condition. + */ +- (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || +- __tcp_select_window(sk) >= tp->rcv_wnd)) || ++ (meta_tp->rcv_nxt - meta_tp->copied_seq < meta_sk->sk_rcvlowat || ++ tp->ops->__select_window(sk) >= tp->rcv_wnd)) || + /* We ACK each frame or... */ + tcp_in_quickack_mode(sk) || + /* Protocol state mandates a one-time immediate ACK */ +@@ -5311,6 +5387,10 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ /* MPTCP urgent data is not yet supported */ ++ if (mptcp(tp)) ++ return; ++ + /* Check if we get a new urgent pointer - normally not. */ + if (th->urg) + tcp_check_urg(sk, th); +@@ -5453,9 +5533,15 @@ + goto discard; + } + ++ /* If valid: post process the received MPTCP options. */ ++ if (mptcp(tp) && mptcp_handle_options(sk, th, skb)) ++ goto discard; ++ + return true; + + discard: ++ if (mptcp(tp)) ++ mptcp_reset_mopt(tp); + tcp_drop(sk, skb); + return false; + } +@@ -5512,6 +5598,10 @@ + + tp->rx_opt.saw_tstamp = 0; + ++ /* MPTCP: force slowpath. */ ++ if (mptcp(tp)) ++ goto slow_path; ++ + /* pred_flags is 0xS?10 << 16 + snd_wnd + * if header_prediction is to be made + * 'S' will always be tp->tcp_header_len >> 2 +@@ -5695,17 +5785,24 @@ + struct tcp_fastopen_cookie *cookie) + { + struct tcp_sock *tp = tcp_sk(sk); +- struct sk_buff *data = tp->syn_data ? tcp_rtx_queue_head(sk) : NULL; ++ struct sk_buff *data = NULL; + u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; + bool syn_drop = false; + ++ if (tp->syn_data) { ++ if (mptcp(tp)) ++ data = tcp_write_queue_head(mptcp_meta_sk(sk)); ++ else ++ data = tcp_rtx_queue_head(sk); ++ } ++ + if (mss == tp->rx_opt.user_mss) { + struct tcp_options_received opt; + + /* Get original SYNACK MSS value if user MSS sets mss_clamp */ + tcp_clear_options(&opt); + opt.user_mss = opt.mss_clamp = 0; +- tcp_parse_options(sock_net(sk), synack, &opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), synack, &opt, NULL, 0, NULL, NULL); + mss = opt.mss_clamp; + } + +@@ -5729,7 +5826,11 @@ + + tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); + +- if (data) { /* Retransmit unacked data in SYN */ ++ /* In mptcp case, we do not rely on "retransmit", but instead on ++ * "transmit", because if fastopen data is not acked, the retransmission ++ * becomes the first MPTCP data (see mptcp_rcv_synsent_fastopen). ++ */ ++ if (data && !mptcp(tp)) { /* Retransmit unacked data in SYN */ + skb_rbtree_walk_from(data) { + if (__tcp_retransmit_skb(sk, data, 1)) + break; +@@ -5769,9 +5870,13 @@ + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_fastopen_cookie foc = { .len = -1 }; + int saved_clamp = tp->rx_opt.mss_clamp; ++ struct mptcp_options_received mopt; + bool fastopen_fail; + +- tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, 0, &foc); ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : &mopt, 0, &foc, tp); + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -5831,6 +5936,35 @@ + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + tcp_ack(sk, skb, FLAG_SLOWPATH); + ++ if (tp->request_mptcp || mptcp(tp)) { ++ int ret; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ ret = mptcp_rcv_synsent_state_process(sk, &sk, ++ skb, &mopt); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ /* May have changed if we support MPTCP */ ++ tp = tcp_sk(sk); ++ icsk = inet_csk(sk); ++ ++ if (ret == 1) ++ goto reset_and_undo; ++ if (ret == 2) ++ goto discard; ++ } ++ ++ if (mptcp(tp) && !is_master_tp(tp)) { ++ /* Timer for repeating the ACK until an answer ++ * arrives. Used only when establishing an additional ++ * subflow inside of an MPTCP connection. ++ */ ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ } ++ + /* Ok.. it's good. Set up sequence numbers and + * move to established. + */ +@@ -5857,6 +5991,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); + tcp_initialize_rcv_mss(sk); + +@@ -5880,9 +6019,12 @@ + } + if (fastopen_fail) + return -1; +- if (sk->sk_write_pending || ++ /* With MPTCP we cannot send data on the third ack due to the ++ * lack of option-space to combine with an MP_CAPABLE. ++ */ ++ if (!mptcp(tp) && (sk->sk_write_pending || + icsk->icsk_accept_queue.rskq_defer_accept || +- icsk->icsk_ack.pingpong) { ++ icsk->icsk_ack.pingpong)) { + /* Save one ACK. Data will be ready after + * several ticks, if write_pending is set. + * +@@ -5921,6 +6063,7 @@ + tcp_paws_reject(&tp->rx_opt, 0)) + goto discard_and_undo; + ++ /* TODO - check this here for MPTCP */ + if (th->syn) { + /* We see SYN without ACK. It is attempt of + * simultaneous connect with crossed SYNs. +@@ -5937,6 +6080,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1); + tp->copied_seq = tp->rcv_nxt; + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; +@@ -5995,6 +6143,7 @@ + */ + + int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) ++ __releases(&sk->sk_lock.slock) + { + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -6037,6 +6186,16 @@ + tp->rx_opt.saw_tstamp = 0; + tcp_mstamp_refresh(tp); + queued = tcp_rcv_synsent_state_process(sk, skb, th); ++ if (is_meta_sk(sk)) { ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ tp = tcp_sk(sk); ++ ++ /* Need to call it here, because it will announce new ++ * addresses, which can only be done after the third ack ++ * of the 3-way handshake. ++ */ ++ mptcp_update_metasocket(tp->meta_sk); ++ } + if (queued >= 0) + return queued; + +@@ -6119,6 +6278,8 @@ + + if (tp->rx_opt.tstamp_ok) + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; ++ if (mptcp(tp)) ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; + + if (!inet_csk(sk)->icsk_ca_ops->cong_control) + tcp_update_pacing_rate(sk); +@@ -6128,6 +6289,30 @@ + + tcp_initialize_rcv_mss(sk); + tcp_fast_path_on(tp); ++ ++ /* Send an ACK when establishing a new MPTCP subflow, i.e. ++ * using an MP_JOIN subtype. ++ */ ++ if (mptcp(tp)) { ++ if (is_master_tp(tp)) { ++ mptcp_update_metasocket(mptcp_meta_sk(sk)); ++ } else { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ tcp_send_ack(sk); ++ ++ /* Update RTO as it might be worse/better */ ++ mptcp_set_rto(sk); ++ ++ /* If the new RTO would fire earlier, pull it in! */ ++ if (tcp_sk(meta_sk)->packets_out && ++ icsk->icsk_timeout > inet_csk(meta_sk)->icsk_rto + jiffies) { ++ tcp_rearm_rto(meta_sk); ++ } ++ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++ } ++ } + break; + + case TCP_FIN_WAIT1: { +@@ -6175,7 +6360,8 @@ + tmo = tcp_fin_time(sk); + if (tmo > TCP_TIMEWAIT_LEN) { + inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); +- } else if (th->fin || sock_owned_by_user(sk)) { ++ } else if (th->fin || mptcp_is_data_fin(skb) || ++ sock_owned_by_user(sk)) { + /* Bad case. We could lose such FIN otherwise. + * It is not a big problem, but it looks confusing + * and not so rare event. We still can lose it now, +@@ -6184,7 +6370,7 @@ + */ + inet_csk_reset_keepalive_timer(sk, tmo); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto discard; + } + break; +@@ -6192,7 +6378,7 @@ + + case TCP_CLOSING: + if (tp->snd_una == tp->write_seq) { +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + goto discard; + } + break; +@@ -6204,6 +6390,9 @@ + goto discard; + } + break; ++ case TCP_CLOSE: ++ if (tp->mp_killed) ++ goto discard; + } + + /* step 6: check the URG bit */ +@@ -6225,7 +6414,8 @@ + */ + if (sk->sk_shutdown & RCV_SHUTDOWN) { + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && +- after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp(tp)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); + tcp_reset(sk); + return 1; +@@ -6322,6 +6512,8 @@ + ireq->wscale_ok = rx_opt->wscale_ok; + ireq->acked = 0; + ireq->ecn_ok = 0; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + ireq->ir_rmt_port = tcp_hdr(skb)->source; + ireq->ir_num = ntohs(tcp_hdr(skb)->dest); + ireq->ir_mark = inet_request_mark(sk, skb); +@@ -6419,12 +6611,17 @@ + /* TW buckets are converted to open requests without + * limitations, they conserve resources and peer is + * evidently real one. ++ * ++ * MPTCP: new subflows cannot be established in a stateless manner. + */ +- if ((net->ipv4.sysctl_tcp_syncookies == 2 || ++ if (((!is_meta_sk(sk) && net->ipv4.sysctl_tcp_syncookies == 2) || + inet_csk_reqsk_queue_is_full(sk)) && !isn) { + want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); + if (!want_cookie) + goto drop; ++ ++ if (is_meta_sk(sk)) ++ goto drop; + } + + if (sk_acceptq_is_full(sk)) { +@@ -6442,8 +6639,8 @@ + tcp_clear_options(&tmp_opt); + tmp_opt.mss_clamp = af_ops->mss_clamp; + tmp_opt.user_mss = tp->rx_opt.user_mss; +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, +- want_cookie ? NULL : &foc); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, NULL, 0, ++ want_cookie ? NULL : &foc, NULL); + + if (want_cookie && !tmp_opt.saw_tstamp) + tcp_clear_options(&tmp_opt); +@@ -6458,7 +6655,8 @@ + /* Note: tcp_v6_init_req() might override ir_iif for link locals */ + inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); + +- af_ops->init_req(req, sk, skb); ++ if (af_ops->init_req(req, sk, skb, want_cookie)) ++ goto drop_and_free; + + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_free; +@@ -6494,7 +6692,7 @@ + tcp_ecn_create_request(req, skb, sk, dst); + + if (want_cookie) { +- isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); ++ isn = cookie_init_sequence(af_ops, req, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + if (!tmp_opt.tstamp_ok) + inet_rsk(req)->ecn_ok = 0; +@@ -6509,18 +6707,26 @@ + fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); + } + if (fastopen_sk) { ++ struct sock *meta_sk = fastopen_sk; ++ ++ if (mptcp(tcp_sk(fastopen_sk))) ++ meta_sk = mptcp_meta_sk(fastopen_sk); + af_ops->send_synack(fastopen_sk, dst, &fl, req, + &foc, TCP_SYNACK_FASTOPEN); + /* Add the child socket directly into the accept queue */ +- if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) { ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { + reqsk_fastopen_remove(fastopen_sk, req, false); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + reqsk_put(req); + goto drop; + } + sk->sk_data_ready(sk); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + } else { + tcp_rsk(req)->tfo_listener = false; +diff -aurN linux-4.19.104/net/ipv4/tcp_ipv4.c mptcp-mptcp_v0.95/net/ipv4/tcp_ipv4.c +--- linux-4.19.104/net/ipv4/tcp_ipv4.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_ipv4.c 2020-02-17 11:29:55.000000000 +0100 +@@ -67,6 +67,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -432,7 +434,7 @@ + struct inet_sock *inet; + const int type = icmp_hdr(icmp_skb)->type; + const int code = icmp_hdr(icmp_skb)->code; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + struct sk_buff *skb; + struct request_sock *fastopen; + u32 seq, snd_una; +@@ -461,13 +463,19 @@ + (code == ICMP_NET_UNREACH || + code == ICMP_HOST_UNREACH))); + +- bh_lock_sock(sk); ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); + /* If too many ICMPs get dropped on busy + * servers this needs to be solved differently. + * We do take care of PMTU discovery (RFC1191) special case : + * we can receive locally generated ICMP messages while socket is held. + */ +- if (sock_owned_by_user(sk)) { ++ if (sock_owned_by_user(meta_sk)) { + if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + } +@@ -480,7 +488,6 @@ + } + + icsk = inet_csk(sk); +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -514,11 +521,13 @@ + goto out; + + tp->mtu_info = info; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v4_mtu_reduced(sk); + } else { + if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } + goto out; + } +@@ -532,7 +541,7 @@ + !icsk->icsk_backoff || fastopen) + break; + +- if (sock_owned_by_user(sk)) ++ if (sock_owned_by_user(meta_sk)) + break; + + skb = tcp_rtx_queue_head(sk); +@@ -555,7 +564,7 @@ + } else { + /* RTO revert clocked out retransmission. + * Will retransmit now */ +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + } + + break; +@@ -575,7 +584,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + + sk->sk_error_report(sk); +@@ -604,7 +613,7 @@ + */ + + inet = inet_sk(sk); +- if (!sock_owned_by_user(sk) && inet->recverr) { ++ if (!sock_owned_by_user(meta_sk) && inet->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else { /* Only an error on timeout */ +@@ -612,7 +621,7 @@ + } + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -647,7 +656,7 @@ + * Exception: precedence violation. We do not implement it in any case. + */ + +-static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -793,10 +802,10 @@ + */ + + static void tcp_v4_send_ack(const struct sock *sk, +- struct sk_buff *skb, u32 seq, u32 ack, ++ struct sk_buff *skb, u32 seq, u32 ack, u32 data_ack, + u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, +- int reply_flags, u8 tos) ++ int reply_flags, u8 tos, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -805,6 +814,10 @@ + #ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) + #endif ++#ifdef CONFIG_MPTCP ++ + ((MPTCP_SUB_LEN_DSS >> 2) + ++ (MPTCP_SUB_LEN_ACK >> 2)) ++#endif + ]; + } rep; + struct net *net = sock_net(sk); +@@ -850,6 +863,21 @@ + ip_hdr(skb)->daddr, &rep.th); + } + #endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ int offset = (tsecr) ? 3 : 0; ++ /* Construction of 32-bit data_ack */ ++ rep.opt[offset++] = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ rep.opt[offset] = htonl(data_ack); ++ ++ arg.iov[0].iov_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++ rep.th.doff = arg.iov[0].iov_len / 4; ++ } ++#endif /* CONFIG_MPTCP */ ++ + arg.flags = reply_flags; + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, /* XXX */ +@@ -878,28 +906,36 @@ + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; ++ ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + + tcp_v4_send_ack(sk, skb, +- tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, + tw->tw_bound_dev_if, + tcp_twsk_md5_key(tcptw), + tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, +- tw->tw_tos ++ tw->tw_tos, mptcp + ); + + inet_twsk_put(tw); + } + +-static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. + */ +- u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : ++ u32 seq = (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? ++ tcp_rsk(req)->snt_isn + 1 : + tcp_sk(sk)->snd_nxt; + + /* RFC 7323 2.3 +@@ -908,7 +944,7 @@ + * Rcv.Wind.Shift bits: + */ + tcp_v4_send_ack(sk, skb, seq, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, +@@ -916,7 +952,7 @@ + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, + AF_INET), + inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, +- ip_hdr(skb)->tos); ++ ip_hdr(skb)->tos, 0); + } + + /* +@@ -924,11 +960,11 @@ + * This still operates on a request_sock only, not on a big + * socket. + */ +-static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, +- struct flowi *fl, +- struct request_sock *req, +- struct tcp_fastopen_cookie *foc, +- enum tcp_synack_type synack_type) ++int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, ++ struct flowi *fl, ++ struct request_sock *req, ++ struct tcp_fastopen_cookie *foc, ++ enum tcp_synack_type synack_type) + { + const struct inet_request_sock *ireq = inet_rsk(req); + struct flowi4 fl4; +@@ -958,7 +994,7 @@ + /* + * IPv4 request_sock destructor. + */ +-static void tcp_v4_reqsk_destructor(struct request_sock *req) ++void tcp_v4_reqsk_destructor(struct request_sock *req) + { + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + } +@@ -1331,9 +1367,10 @@ + return false; + } + +-static void tcp_v4_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v4_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + struct inet_request_sock *ireq = inet_rsk(req); + struct net *net = sock_net(sk_listener); +@@ -1341,6 +1378,8 @@ + sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); + sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); ++ ++ return 0; + } + + static struct dst_entry *tcp_v4_route_req(const struct sock *sk, +@@ -1360,7 +1399,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { + .mss_clamp = TCP_MSS_DEFAULT, + #ifdef CONFIG_TCP_MD5SIG + .req_md5_lookup = tcp_v4_md5_lookup, +@@ -1497,7 +1536,7 @@ + } + EXPORT_SYMBOL(tcp_v4_syn_recv_sock); + +-static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1520,6 +1559,9 @@ + { + struct sock *rsk; + ++ if (is_meta_sk(sk)) ++ return mptcp_v4_do_rcv(sk, skb); ++ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst = sk->sk_rx_dst; + +@@ -1671,6 +1713,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff * 4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); +@@ -1689,8 +1735,8 @@ + int sdif = inet_sdif(skb); + const struct iphdr *iph; + const struct tcphdr *th; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + + if (skb->pkt_type != PACKET_HOST) +@@ -1744,7 +1790,11 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ goto lookup; ++ } ++ if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } +@@ -1753,6 +1803,7 @@ + */ + sock_hold(sk); + refcounted = true; ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1813,15 +1864,24 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_v4_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1835,6 +1895,19 @@ + + tcp_v4_fill_cb(skb, iph, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1883,6 +1956,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + } + /* to ACK */ + /* fall through */ +@@ -1952,7 +2037,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; +@@ -1971,6 +2061,11 @@ + + tcp_cleanup_congestion_control(sk); + ++ if (mptcp(tp)) ++ mptcp_destroy_sock(sk); ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ + tcp_cleanup_ulp(sk); + + /* Cleanup up the write buffer. */ +@@ -2475,6 +2570,11 @@ + .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), + .max_header = MAX_TCP_HEADER, + .obj_size = sizeof(struct tcp_sock), ++#ifdef CONFIG_MPTCP ++ .useroffset = offsetof(struct tcp_sock, mptcp_sched_name), ++ .usersize = sizeof_field(struct tcp_sock, mptcp_sched_name) + ++ sizeof_field(struct tcp_sock, mptcp_pm_name), ++#endif + .slab_flags = SLAB_TYPESAFE_BY_RCU, + .twsk_prot = &tcp_timewait_sock_ops, + .rsk_prot = &tcp_request_sock_ops, +@@ -2485,6 +2585,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + EXPORT_SYMBOL(tcp_prot); + +diff -aurN linux-4.19.104/net/ipv4/tcp_minisocks.c mptcp-mptcp_v0.95/net/ipv4/tcp_minisocks.c +--- linux-4.19.104/net/ipv4/tcp_minisocks.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_minisocks.c 2020-02-17 11:29:55.000000000 +0100 +@@ -18,11 +18,13 @@ + * Jorge Cwik, + */ + ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -94,10 +96,14 @@ + struct tcp_options_received tmp_opt; + struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); + bool paws_reject = false; ++ struct mptcp_options_received mopt; + + tmp_opt.saw_tstamp = 0; +- if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { +- tcp_parse_options(twsk_net(tw), skb, &tmp_opt, 0, NULL); ++ if (th->doff > (sizeof(*th) >> 2) && ++ (tcptw->tw_ts_recent_stamp || tcptw->mptcp_tw)) { ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(twsk_net(tw), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + if (tmp_opt.rcv_tsecr) +@@ -106,6 +112,11 @@ + tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; + paws_reject = tcp_paws_reject(&tmp_opt, th->rst); + } ++ ++ if (unlikely(mopt.mp_fclose) && tcptw->mptcp_tw) { ++ if (mopt.mptcp_sender_key == tcptw->mptcp_tw->loc_key) ++ return TCP_TW_RST; ++ } + } + + if (tw->tw_substate == TCP_FIN_WAIT2) { +@@ -129,6 +140,16 @@ + if (!th->ack || + !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) || + TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { ++ /* If mptcp_is_data_fin() returns true, we are sure that ++ * mopt has been initialized - otherwise it would not ++ * be a DATA_FIN. ++ */ ++ if (tcptw->mptcp_tw && tcptw->mptcp_tw->meta_tw && ++ mptcp_is_data_fin(skb) && ++ TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt && ++ mopt.data_seq + 1 == (u32)tcptw->mptcp_tw->rcv_nxt) ++ return TCP_TW_ACK; ++ + inet_twsk_put(tw); + return TCP_TW_SUCCESS; + } +@@ -274,6 +295,15 @@ + tcptw->tw_ts_offset = tp->tsoffset; + tcptw->tw_last_oow_ack_time = 0; + ++ if (mptcp(tp)) { ++ if (mptcp_init_tw_sock(sk, tcptw)) { ++ inet_twsk_free(tw); ++ goto exit; ++ } ++ } else { ++ tcptw->mptcp_tw = NULL; ++ } ++ + #if IS_ENABLED(CONFIG_IPV6) + if (tw->tw_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -330,6 +360,7 @@ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); + } + ++exit: + tcp_update_metrics(sk); + tcp_done(sk); + } +@@ -337,9 +368,11 @@ + + void tcp_twsk_destructor(struct sock *sk) + { +-#ifdef CONFIG_TCP_MD5SIG + struct tcp_timewait_sock *twsk = tcp_twsk(sk); + ++ if (twsk->mptcp_tw) ++ mptcp_twsk_destructor(twsk); ++#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_key) + kfree_rcu(twsk->tw_md5_key, rcu); + #endif +@@ -378,8 +411,9 @@ + full_space = rcv_wnd * mss; + + /* tcp_full_space because it is guaranteed to be the first packet */ +- tcp_select_initial_window(sk_listener, full_space, +- mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), ++ tp->ops->select_initial_window(sk_listener, full_space, ++ mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) - ++ (ireq->saw_mpc ? MPTCP_SUB_LEN_DSM_ALIGN : 0), + &req->rsk_rcv_wnd, + &req->rsk_window_clamp, + ireq->wscale_ok, +@@ -477,6 +511,8 @@ + newtp->snd_sml = newtp->snd_una = + newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1; + ++ newtp->out_of_order_queue = RB_ROOT; ++ newsk->tcp_rtx_queue = RB_ROOT; + INIT_LIST_HEAD(&newtp->tsq_node); + INIT_LIST_HEAD(&newtp->tsorted_sent_queue); + +@@ -547,6 +583,8 @@ + newtp->rx_opt.ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } ++ if (ireq->saw_mpc) ++ newtp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; + newtp->tsoffset = treq->ts_off; + #ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ +@@ -566,6 +604,7 @@ + newtp->rack.last_delivered = 0; + newtp->rack.reo_wnd_persist = 0; + newtp->rack.dsack_seen = 0; ++ newtp->inside_tk_table = 0; + + __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); + +@@ -589,6 +628,7 @@ + bool fastopen, bool *req_stolen) + { + struct tcp_options_received tmp_opt; ++ struct mptcp_options_received mopt; + struct sock *child; + const struct tcphdr *th = tcp_hdr(skb); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); +@@ -596,8 +636,11 @@ + bool own_req; + + tmp_opt.saw_tstamp = 0; ++ ++ mptcp_init_mp_opt(&mopt); ++ + if (th->doff > (sizeof(struct tcphdr)>>2)) { +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + tmp_opt.ts_recent = req->ts_recent; +@@ -638,7 +681,14 @@ + * + * Reset timer after retransmitting SYNACK, similar to + * the idea of fast retransmit in recovery. ++ * ++ * Fall back to TCP if MP_CAPABLE is not set. + */ ++ ++ if (inet_rsk(req)->saw_mpc && !mopt.saw_mpc) ++ inet_rsk(req)->saw_mpc = false; ++ ++ + if (!tcp_oow_rate_limited(sock_net(sk), skb, + LINUX_MIB_TCPACKSKIPPEDSYNRECV, + &tcp_rsk(req)->last_oow_ack_time) && +@@ -786,17 +836,37 @@ + * ESTABLISHED STATE. If it will be dropped after + * socket is created, wait for troubles. + */ ++ if (is_meta_sk(sk)) ++ bh_lock_sock_nested(sk); + child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, + req, &own_req); + if (!child) + goto listen_overflow; + ++ if (own_req && !is_meta_sk(sk)) { ++ int ret = mptcp_check_req_master(sk, child, req, skb, 1, 0); ++ if (ret < 0) ++ goto listen_overflow; ++ ++ /* MPTCP-supported */ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ } else if (own_req) { ++ return mptcp_check_req_child(sk, child, req, skb, &mopt); ++ } ++ ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); ++ + sock_rps_save_rxhash(child, skb); + tcp_synack_rtt_meas(child, req); + *req_stolen = !own_req; + return inet_csk_complete_hashdance(sk, child, req, own_req); + + listen_overflow: ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); ++ + if (!sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow) { + inet_rsk(req)->acked = 1; + return NULL; +@@ -839,12 +909,13 @@ + { + int ret = 0; + int state = child->sk_state; ++ struct sock *meta_sk = mptcp(tcp_sk(child)) ? mptcp_meta_sk(child) : child; + + /* record NAPI ID of child */ + sk_mark_napi_id(child, skb); + + tcp_segs_in(tcp_sk(child), skb); +- if (!sock_owned_by_user(child)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_rcv_state_process(child, skb); + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && child->sk_state != state) +@@ -854,10 +925,14 @@ + * in main socket hash table and lock on listening + * socket does not protect us more. + */ +- __sk_add_backlog(child, skb); ++ if (mptcp(tcp_sk(child))) ++ mptcp_prepare_for_backlog(child, skb); ++ __sk_add_backlog(meta_sk, skb); + } + + bh_unlock_sock(child); ++ if (mptcp(tcp_sk(child))) ++ bh_unlock_sock(meta_sk); + sock_put(child); + return ret; + } +diff -aurN linux-4.19.104/net/ipv4/tcp_output.c mptcp-mptcp_v0.95/net/ipv4/tcp_output.c +--- linux-4.19.104/net/ipv4/tcp_output.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_output.c 2020-02-17 11:29:55.000000000 +0100 +@@ -36,6 +36,12 @@ + + #define pr_fmt(fmt) "TCP: " fmt + ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++#include + #include + + #include +@@ -45,11 +51,8 @@ + + #include + +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, +- int push_one, gfp_t gfp); +- + /* Account for new data that has been sent to the network. */ +-static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) ++void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -242,12 +245,16 @@ + * value can be stuffed directly into th->window for an outgoing + * frame. + */ +-static u16 tcp_select_window(struct sock *sk) ++u16 tcp_select_window(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 old_win = tp->rcv_wnd; +- u32 cur_win = tcp_receive_window(tp); +- u32 new_win = __tcp_select_window(sk); ++ /* The window must never shrink at the meta-level. At the subflow we ++ * have to allow this. Otherwise we may announce a window too large ++ * for the current meta-level sk_rcvbuf. ++ */ ++ u32 cur_win = tcp_receive_window(mptcp(tp) ? tcp_sk(mptcp_meta_sk(sk)) : tp); ++ u32 new_win = tp->ops->__select_window(sk); + + /* Never shrink the offered window */ + if (new_win < cur_win) { +@@ -263,6 +270,7 @@ + LINUX_MIB_TCPWANTZEROWINDOWADV); + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + } ++ + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + +@@ -375,7 +383,7 @@ + /* Constructs common control bits of non-data skb. If SYN/FIN is present, + * auto increment end seqno. + */ +-static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) + { + skb->ip_summed = CHECKSUM_PARTIAL; + +@@ -390,7 +398,7 @@ + TCP_SKB_CB(skb)->end_seq = seq; + } + +-static inline bool tcp_urg_mode(const struct tcp_sock *tp) ++bool tcp_urg_mode(const struct tcp_sock *tp) + { + return tp->snd_una != tp->snd_up; + } +@@ -401,6 +409,7 @@ + #define OPTION_WSCALE (1 << 3) + #define OPTION_FAST_OPEN_COOKIE (1 << 8) + #define OPTION_SMC (1 << 9) ++/* Before adding here - take a look at OPTION_MPTCP in include/net/mptcp.h */ + + static void smc_options_write(__be32 *ptr, u16 *options) + { +@@ -417,17 +426,6 @@ + #endif + } + +-struct tcp_out_options { +- u16 options; /* bit field of OPTION_* */ +- u16 mss; /* 0 to disable */ +- u8 ws; /* window scale, 0 to disable */ +- u8 num_sack_blocks; /* number of SACK blocks to include */ +- u8 hash_size; /* bytes in hash_location */ +- __u8 *hash_location; /* temporary pointer, overloaded */ +- __u32 tsval, tsecr; /* need to include OPTION_TS */ +- struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ +-}; +- + /* Write previously computed TCP options to the packet. + * + * Beware: Something in the Internet is very sensitive to the ordering of +@@ -442,7 +440,7 @@ + * (but it may well be that other scenarios fail similarly). + */ + static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, +- struct tcp_out_options *opts) ++ struct tcp_out_options *opts, struct sk_buff *skb) + { + u16 options = opts->options; /* mungable copy */ + +@@ -536,6 +534,9 @@ + } + + smc_options_write(ptr, &options); ++ ++ if (unlikely(OPTION_MPTCP & opts->options)) ++ mptcp_options_write(ptr, tp, opts, skb); + } + + static void smc_set_option(const struct tcp_sock *tp, +@@ -621,6 +622,8 @@ + if (unlikely(!(OPTION_TS & opts->options))) + remaining -= TCPOLEN_SACKPERM_ALIGNED; + } ++ if (tp->request_mptcp || mptcp(tp)) ++ mptcp_syn_options(sk, opts, &remaining); + + if (fastopen && fastopen->cookie.len >= 0) { + u32 need = fastopen->cookie.len; +@@ -702,6 +705,9 @@ + + smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining); + ++ if (ireq->saw_mpc) ++ mptcp_synack_options(req, opts, &remaining); ++ + return MAX_TCP_OPTION_SPACE - remaining; + } + +@@ -735,6 +741,8 @@ + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } ++ if (mptcp(tp)) ++ mptcp_established_options(sk, skb, opts, &size); + + eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; + if (unlikely(eff_sacks)) { +@@ -785,19 +793,31 @@ + tcp_xmit_retransmit_queue(sk); + } + +- tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, +- 0, GFP_ATOMIC); ++ tcp_sk(sk)->ops->write_xmit(sk, tcp_current_mss(sk), ++ tcp_sk(sk)->nonagle, 0, GFP_ATOMIC); + } + } + + static void tcp_tsq_handler(struct sock *sk) + { +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_tsq_write(sk); +- else if (!test_and_set_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags)) +- sock_hold(sk); +- bh_unlock_sock(sk); ++ ++ if (mptcp(tp)) ++ tcp_tsq_write(meta_sk); ++ } else { ++ if (!test_and_set_bit(TCP_TSQ_DEFERRED, &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++ ++ if ((mptcp(tp)) && (sk->sk_state != TCP_CLOSE)) ++ mptcp_tsq_flags(sk); ++ } ++ ++ bh_unlock_sock(meta_sk); + } + /* + * One tasklet per cpu tries to send more skbs. +@@ -834,7 +854,9 @@ + #define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \ + TCPF_WRITE_TIMER_DEFERRED | \ + TCPF_DELACK_TIMER_DEFERRED | \ +- TCPF_MTU_REDUCED_DEFERRED) ++ TCPF_MTU_REDUCED_DEFERRED | \ ++ TCPF_PATH_MANAGER_DEFERRED |\ ++ TCPF_SUB_DEFERRED) + /** + * tcp_release_cb - tcp release_sock() callback + * @sk: socket +@@ -857,6 +879,9 @@ + if (flags & TCPF_TSQ_DEFERRED) { + tcp_tsq_write(sk); + __sock_put(sk); ++ ++ if (mptcp(tcp_sk(sk))) ++ tcp_tsq_write(mptcp_meta_sk(sk)); + } + /* Here begins the tricky part : + * We are called from release_sock() with : +@@ -881,6 +906,13 @@ + inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); + __sock_put(sk); + } ++ if (flags & TCPF_PATH_MANAGER_DEFERRED) { ++ if (tcp_sk(sk)->mpcb->pm_ops->release_sock) ++ tcp_sk(sk)->mpcb->pm_ops->release_sock(sk); ++ __sock_put(sk); ++ } ++ if (flags & TCPF_SUB_DEFERRED) ++ mptcp_tsq_sub_deferred(sk); + } + EXPORT_SYMBOL(tcp_release_cb); + +@@ -983,7 +1015,7 @@ + sock_hold(sk); + } + +-static void tcp_update_skb_after_send(struct tcp_sock *tp, struct sk_buff *skb) ++void tcp_update_skb_after_send(struct tcp_sock *tp, struct sk_buff *skb) + { + skb->skb_mstamp = tp->tcp_mstamp; + list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); +@@ -1095,10 +1127,10 @@ + } + } + +- tcp_options_write((__be32 *)(th + 1), tp, &opts); ++ tcp_options_write((__be32 *)(th + 1), tp, &opts, skb); + skb_shinfo(skb)->gso_type = sk->sk_gso_type; + if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) { +- th->window = htons(tcp_select_window(sk)); ++ th->window = htons(tp->ops->select_window(sk)); + tcp_ecn_send(sk, skb, th, tcp_header_size); + } else { + /* RFC1323: The window in SYN & SYN/ACK segments +@@ -1156,8 +1188,8 @@ + return err; + } + +-static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, +- gfp_t gfp_mask) ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask) + { + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +@@ -1168,7 +1200,7 @@ + * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, + * otherwise socket can stall. + */ +-static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1181,7 +1213,7 @@ + } + + /* Initialize TSO segments for a packet. */ +-static void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + if (skb->len <= mss_now) { + /* Avoid the costly divide in the normal +@@ -1198,7 +1230,7 @@ + /* Pcount in the middle of the write queue got changed, we need to do various + * tweaks to fix counters + */ +-static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1366,7 +1398,7 @@ + /* This is similar to __pskb_pull_tail(). The difference is that pulled + * data is not copied, but immediately discarded. + */ +-static int __pskb_trim_head(struct sk_buff *skb, int len) ++int __pskb_trim_head(struct sk_buff *skb, int len) + { + struct skb_shared_info *shinfo; + int i, k, eat; +@@ -1588,6 +1620,7 @@ + + return mss_now; + } ++EXPORT_SYMBOL(tcp_current_mss); + + /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, +@@ -1611,7 +1644,7 @@ + tp->snd_cwnd_stamp = tcp_jiffies32; + } + +-static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) + { + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; + struct tcp_sock *tp = tcp_sk(sk); +@@ -1669,8 +1702,8 @@ + * But we can avoid doing the divide again given we already have + * skb_pcount = skb->len / mss_now + */ +-static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, +- const struct sk_buff *skb) ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb) + { + if (skb->len < tcp_skb_pcount(skb) * mss_now) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; +@@ -1729,11 +1762,11 @@ + } + + /* Returns the portion of skb which can be sent right away */ +-static unsigned int tcp_mss_split_point(const struct sock *sk, +- const struct sk_buff *skb, +- unsigned int mss_now, +- unsigned int max_segs, +- int nonagle) ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle) + { + const struct tcp_sock *tp = tcp_sk(sk); + u32 partial, needed, window, max_len; +@@ -1763,13 +1796,14 @@ + /* Can at least one segment of SKB be sent right now, according to the + * congestion window rules? If so, return how many segments are allowed. + */ +-static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb) ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, ++ const struct sk_buff *skb) + { + u32 in_flight, cwnd, halfcwnd; + + /* Don't be strict about the congestion window for the final FIN. */ +- if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ if (skb && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && + tcp_skb_pcount(skb) == 1) + return 1; + +@@ -1784,12 +1818,13 @@ + halfcwnd = max(cwnd >> 1, 1U); + return min(halfcwnd, cwnd - in_flight); + } ++EXPORT_SYMBOL(tcp_cwnd_test); + + /* Initialize TSO state of a skb. + * This must be invoked the first time we consider transmitting + * SKB onto the wire. + */ +-static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + int tso_segs = tcp_skb_pcount(skb); + +@@ -1804,8 +1839,8 @@ + /* Return true if the Nagle test allows this packet to be + * sent now. + */ +-static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, +- unsigned int cur_mss, int nonagle) ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle) + { + /* Nagle rule does not apply to frames, which sit in the middle of the + * write_queue (they have no chances to get new data). +@@ -1817,7 +1852,8 @@ + return true; + + /* Don't use the nagle rule for urgent data (or for the final FIN). */ +- if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) ++ if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || ++ mptcp_is_data_fin(skb)) + return true; + + if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) +@@ -1827,9 +1863,8 @@ + } + + /* Does at least the first segment of SKB fit into the send window? */ +-static bool tcp_snd_wnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb, +- unsigned int cur_mss) ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss) + { + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + +@@ -1838,6 +1873,7 @@ + + return !after(end_seq, tcp_wnd_end(tp)); + } ++EXPORT_SYMBOL(tcp_snd_wnd_test); + + /* Trim TSO SKB to LEN bytes, put the remaining data into a new packet + * which is put after SKB on the list. It is very much like +@@ -1990,7 +2026,7 @@ + } + + /* If this packet won't get more data, do not wait. */ +- if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || mptcp_is_data_fin(skb)) + goto send_now; + + return true; +@@ -2294,7 +2330,7 @@ + * Returns true, if no segments are in flight and we have queued segments, + * but cannot send anything now because of SWS or another problem. + */ +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + int push_one, gfp_t gfp) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -2308,7 +2344,12 @@ + sent_pkts = 0; + + tcp_mstamp_refresh(tp); +- if (!push_one) { ++ ++ /* pmtu not yet supported with MPTCP. Should be possible, by early ++ * exiting the loop inside tcp_mtu_probe, making sure that only one ++ * single DSS-mapping gets probed. ++ */ ++ if (!push_one && !mptcp(tp)) { + /* Do MTU probing. */ + result = tcp_mtu_probe(sk); + if (!result) { +@@ -2413,7 +2454,8 @@ + if (push_one != 2) + tcp_schedule_loss_probe(sk, false); + is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); +- tcp_cwnd_validate(sk, is_cwnd_limited); ++ if (tp->ops->cwnd_validate) ++ tp->ops->cwnd_validate(sk, is_cwnd_limited); + return false; + } + return !tp->packets_out && !tcp_write_queue_empty(sk); +@@ -2496,7 +2538,7 @@ + skb = tcp_send_head(sk); + if (skb && tcp_snd_wnd_test(tp, skb, mss)) { + pcount = tp->packets_out; +- tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); ++ tp->ops->write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); + if (tp->packets_out > pcount) + goto probe_sent; + goto rearm_timer; +@@ -2560,8 +2602,8 @@ + if (unlikely(sk->sk_state == TCP_CLOSE)) + return; + +- if (tcp_write_xmit(sk, cur_mss, nonagle, 0, +- sk_gfp_mask(sk, GFP_ATOMIC))) ++ if (tcp_sk(sk)->ops->write_xmit(sk, cur_mss, nonagle, 0, ++ sk_gfp_mask(sk, GFP_ATOMIC))) + tcp_check_probe_timer(sk); + } + +@@ -2574,7 +2616,8 @@ + + BUG_ON(!skb || skb->len < mss_now); + +- tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); ++ tcp_sk(sk)->ops->write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, ++ sk->sk_allocation); + } + + /* This function returns the amount that we can raise the +@@ -2796,6 +2839,10 @@ + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + return; + ++ /* Currently not supported for MPTCP - but it should be possible */ ++ if (mptcp(tp)) ++ return; ++ + skb_rbtree_walk_from_safe(skb, tmp) { + if (!tcp_can_collapse(sk, skb)) + break; +@@ -3266,7 +3313,7 @@ + + /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ + th->window = htons(min(req->rsk_rcv_wnd, 65535U)); +- tcp_options_write((__be32 *)(th + 1), NULL, &opts); ++ tcp_options_write((__be32 *)(th + 1), NULL, &opts, skb); + th->doff = (tcp_header_size >> 2); + __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); + +@@ -3347,13 +3394,13 @@ + if (rcv_wnd == 0) + rcv_wnd = dst_metric(dst, RTAX_INITRWND); + +- tcp_select_initial_window(sk, tcp_full_space(sk), +- tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), +- &tp->rcv_wnd, +- &tp->window_clamp, +- sock_net(sk)->ipv4.sysctl_tcp_window_scaling, +- &rcv_wscale, +- rcv_wnd); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), ++ tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), ++ &tp->rcv_wnd, ++ &tp->window_clamp, ++ sock_net(sk)->ipv4.sysctl_tcp_window_scaling, ++ &rcv_wscale, ++ rcv_wnd); + + tp->rx_opt.rcv_wscale = rcv_wscale; + tp->rcv_ssthresh = tp->rcv_wnd; +@@ -3378,6 +3425,36 @@ + inet_csk(sk)->icsk_rto = tcp_timeout_init(sk); + inet_csk(sk)->icsk_retransmits = 0; + tcp_clear_retrans(tp); ++ ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP) && mptcp_doit(sk)) { ++ if (is_master_tp(tp)) { ++ tp->request_mptcp = 1; ++ mptcp_connect_init(sk); ++ } else if (tp->mptcp) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ tp->mptcp->snt_isn = tp->write_seq; ++ tp->mptcp->init_rcv_wnd = tp->rcv_wnd; ++ ++ /* Set nonce for new subflows */ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp->mptcp_loc_nonce = mptcp_v4_get_nonce( ++ inet->inet_saddr, ++ inet->inet_daddr, ++ inet->inet_sport, ++ inet->inet_dport); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp->mptcp_loc_nonce = mptcp_v6_get_nonce( ++ inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ inet->inet_sport, ++ inet->inet_dport); ++#endif ++ } ++ } ++#endif + } + + static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) +@@ -3640,6 +3717,7 @@ + { + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); + } ++EXPORT_SYMBOL_GPL(tcp_send_ack); + + /* This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. +@@ -3652,7 +3730,7 @@ + * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is + * out-of-date with SND.UNA-1 to probe window. + */ +-static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) + { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; +@@ -3739,7 +3817,7 @@ + unsigned long probe_max; + int err; + +- err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); ++ err = tp->ops->write_wakeup(sk, LINUX_MIB_TCPWINPROBE); + + if (tp->packets_out || tcp_write_queue_empty(sk)) { + /* Cancel probe timer, if it is not required. */ +diff -aurN linux-4.19.104/net/ipv4/tcp_timer.c mptcp-mptcp_v0.95/net/ipv4/tcp_timer.c +--- linux-4.19.104/net/ipv4/tcp_timer.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv4/tcp_timer.c 2020-02-17 11:29:55.000000000 +0100 +@@ -20,6 +20,7 @@ + + #include + #include ++#include + #include + + static u32 tcp_retransmit_stamp(const struct sock *sk) +@@ -58,7 +59,7 @@ + * Returns: Nothing (void) + */ + +-static void tcp_write_err(struct sock *sk) ++void tcp_write_err(struct sock *sk) + { + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); +@@ -114,7 +115,7 @@ + (!tp->snd_wnd && !tp->packets_out)) + do_reset = true; + if (do_reset) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + return 1; +@@ -186,9 +187,9 @@ + * after "boundary" unsuccessful, exponentially backed-off + * retransmissions with an initial RTO of TCP_RTO_MIN. + */ +-static bool retransmits_timed_out(struct sock *sk, +- unsigned int boundary, +- unsigned int timeout) ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout) + { + const unsigned int rto_base = TCP_RTO_MIN; + unsigned int linear_backoff_thresh, start_ts; +@@ -214,7 +215,7 @@ + } + + /* A write timeout has occurred. Process the after effects. */ +-static int tcp_write_timeout(struct sock *sk) ++int tcp_write_timeout(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -229,6 +230,17 @@ + sk_rethink_txhash(sk); + } + retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; ++ ++#ifdef CONFIG_MPTCP ++ /* Stop retransmitting MP_CAPABLE options in SYN if timed out. */ ++ if (tcp_sk(sk)->request_mptcp && ++ icsk->icsk_retransmits >= sysctl_mptcp_syn_retries) { ++ tcp_sk(sk)->request_mptcp = 0; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLERETRANSFALLBACK); ++ } ++#endif /* CONFIG_MPTCP */ ++ + expired = icsk->icsk_retransmits >= retry_until; + } else { + if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) { +@@ -324,18 +336,22 @@ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_delack_timer); + struct sock *sk = &icsk->icsk_inet.sk; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_delack_timer_handler(sk); + } else { + icsk->icsk_ack.blocked = 1; +- __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_DELAYEDACKLOCKED); + /* deleguate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -380,6 +396,10 @@ + + if (icsk->icsk_probes_out >= max_probes) { + abort: tcp_write_err(sk); ++ if (is_meta_sk(sk) && ++ mptcp_in_infinite_mapping_weak(tp->mpcb)) { ++ mptcp_sub_force_close_all(tp->mpcb, NULL); ++ } + } else { + /* Only send another probe if we didn't close things up. */ + tcp_send_probe0(sk); +@@ -595,7 +615,7 @@ + break; + case ICSK_TIME_RETRANS: + icsk->icsk_pending = 0; +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + break; + case ICSK_TIME_PROBE0: + icsk->icsk_pending = 0; +@@ -612,16 +632,19 @@ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_retransmit_timer); + struct sock *sk = &icsk->icsk_inet.sk; ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_write_timer_handler(sk); + } else { + /* delegate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tcp_sk(sk))) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -651,11 +674,12 @@ + struct sock *sk = from_timer(sk, t, sk_timer); + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + u32 elapsed; + + /* Only process if socket is not in use. */ +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { + /* Try again later. */ + inet_csk_reset_keepalive_timer (sk, HZ/20); + goto out; +@@ -667,16 +691,31 @@ + } + + tcp_mstamp_refresh(tp); ++ ++ if (tp->send_mp_fclose) { ++ if (icsk->icsk_retransmits >= MPTCP_FASTCLOSE_RETRIES) { ++ tcp_write_err(sk); ++ goto out; ++ } ++ ++ tcp_send_ack(sk); ++ icsk->icsk_retransmits++; ++ ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ elapsed = icsk->icsk_rto; ++ goto resched; ++ } ++ + if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { + if (tp->linger2 >= 0) { + const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; + + if (tmo > 0) { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto out; + } + } +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + goto death; + } + +@@ -701,11 +740,11 @@ + icsk->icsk_probes_out > 0) || + (icsk->icsk_user_timeout == 0 && + icsk->icsk_probes_out >= keepalive_probes(tp))) { +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_write_err(sk); + goto out; + } +- if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { ++ if (tp->ops->write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { + icsk->icsk_probes_out++; + elapsed = keepalive_intvl_when(tp); + } else { +@@ -729,7 +768,7 @@ + tcp_done(sk); + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +diff -aurN linux-4.19.104/net/ipv6/addrconf.c mptcp-mptcp_v0.95/net/ipv6/addrconf.c +--- linux-4.19.104/net/ipv6/addrconf.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv6/addrconf.c 2020-02-17 11:29:55.000000000 +0100 +@@ -917,6 +917,7 @@ + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +diff -aurN linux-4.19.104/net/ipv6/af_inet6.c mptcp-mptcp_v0.95/net/ipv6/af_inet6.c +--- linux-4.19.104/net/ipv6/af_inet6.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv6/af_inet6.c 2020-02-17 11:29:55.000000000 +0100 +@@ -107,8 +107,7 @@ + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static int inet6_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct inet_sock *inet; + struct ipv6_pinfo *np; +diff -aurN linux-4.19.104/net/ipv6/ipv6_sockglue.c mptcp-mptcp_v0.95/net/ipv6/ipv6_sockglue.c +--- linux-4.19.104/net/ipv6/ipv6_sockglue.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv6/ipv6_sockglue.c 2020-02-17 11:29:55.000000000 +0100 +@@ -48,6 +48,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -216,7 +218,12 @@ + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); + sk->sk_prot = &tcp_prot; +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +diff -aurN linux-4.19.104/net/ipv6/syncookies.c mptcp-mptcp_v0.95/net/ipv6/syncookies.c +--- linux-4.19.104/net/ipv6/syncookies.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv6/syncookies.c 2020-02-17 11:29:55.000000000 +0100 +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define COOKIEBITS 24 /* Upper bits store count */ +@@ -111,7 +113,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); + +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -133,6 +136,7 @@ + struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) + { + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -162,7 +166,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcpv6_ts_off(sock_net(sk), +@@ -175,14 +180,27 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp6_request_sock_ops, sk, false); ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); + if (!req) + goto out; + + ireq = inet_rsk(req); ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + treq = tcp_rsk(req); + treq->tfo_listener = false; + ++ /* Must be done before anything else, as it initializes ++ * hash_entry of the MPTCP request-sock. ++ */ ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + if (security_inet_conn_request(sk, skb, req)) + goto out_free; + +@@ -246,10 +264,10 @@ + } + + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); +- tcp_select_initial_window(sk, tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(dst, RTAX_INITRWND)); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); +diff -aurN linux-4.19.104/net/ipv6/tcp_ipv6.c mptcp-mptcp_v0.95/net/ipv6/tcp_ipv6.c +--- linux-4.19.104/net/ipv6/tcp_ipv6.c 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/ipv6/tcp_ipv6.c 2020-02-17 11:29:55.000000000 +0100 +@@ -61,6 +61,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -70,15 +72,6 @@ + #include + + #include +- +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req); +- +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); +- +-static const struct inet_connection_sock_af_ops ipv6_mapped; +-static const struct inet_connection_sock_af_ops ipv6_specific; + #ifdef CONFIG_TCP_MD5SIG + static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; + static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +@@ -90,7 +83,7 @@ + } + #endif + +-static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) + { + struct dst_entry *dst = skb_dst(skb); + +@@ -132,7 +125,7 @@ + return BPF_CGROUP_RUN_PROG_INET6_CONNECT(sk, uaddr); + } + +-static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) + { + struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; +@@ -229,7 +222,12 @@ + sin.sin_port = usin->sin6_port; + sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; + +- icsk->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_mapped; + sk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -239,7 +237,12 @@ + + if (err) { + icsk->icsk_ext_hdr_len = exthdrlen; +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + sk->sk_backlog_rcv = tcp_v6_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +@@ -332,7 +335,7 @@ + return err; + } + +-static void tcp_v6_mtu_reduced(struct sock *sk) ++void tcp_v6_mtu_reduced(struct sock *sk) + { + struct dst_entry *dst; + +@@ -359,7 +362,7 @@ + struct ipv6_pinfo *np; + struct tcp_sock *tp; + __u32 seq, snd_una; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + bool fatal; + int err; + +@@ -383,8 +386,14 @@ + if (sk->sk_state == TCP_NEW_SYN_RECV) + return tcp_req_err(sk, seq, fatal); + +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk) && type != ICMPV6_PKT_TOOBIG) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + + if (sk->sk_state == TCP_CLOSE) +@@ -395,7 +404,6 @@ + goto out; + } + +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -429,11 +437,15 @@ + goto out; + + tp->mtu_info = ntohl(info); +- if (!sock_owned_by_user(sk)) ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v6_mtu_reduced(sk); +- else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, +- &sk->sk_tsq_flags)) +- sock_hold(sk); ++ } else { ++ if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, ++ &sk->sk_tsq_flags)) ++ sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); ++ } + goto out; + } + +@@ -448,7 +460,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + +@@ -458,14 +470,14 @@ + goto out; + } + +- if (!sock_owned_by_user(sk) && np->recverr) { ++ if (!sock_owned_by_user(meta_sk) && np->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else + sk->sk_err_soft = err; + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -511,8 +523,7 @@ + return err; + } + +- +-static void tcp_v6_reqsk_destructor(struct request_sock *req) ++void tcp_v6_reqsk_destructor(struct request_sock *req) + { + kfree(inet_rsk(req)->ipv6_opt); + kfree_skb(inet_rsk(req)->pktopts); +@@ -730,9 +741,10 @@ + return false; + } + +-static void tcp_v6_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v6_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); + struct inet_request_sock *ireq = inet_rsk(req); +@@ -754,6 +766,8 @@ + refcount_inc(&skb->users); + ireq->pktopts = skb; + } ++ ++ return 0; + } + + static struct dst_entry *tcp_v6_route_req(const struct sock *sk, +@@ -773,7 +787,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { + .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr), + #ifdef CONFIG_TCP_MD5SIG +@@ -791,9 +805,9 @@ + }; + + static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, + int oif, struct tcp_md5sig_key *key, int rst, +- u8 tclass, __be32 label) ++ u8 tclass, __be32 label, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct tcphdr *t1; +@@ -812,7 +826,10 @@ + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; + #endif +- ++#ifdef CONFIG_MPTCP ++ if (mptcp) ++ tot_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++#endif + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, + GFP_ATOMIC); + if (!buff) +@@ -850,6 +867,17 @@ + tcp_v6_md5_hash_hdr((__u8 *)topt, key, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, t1); ++ topt += 4; ++ } ++#endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ /* Construction of 32-bit data_ack */ ++ *topt++ = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ *topt++ = htonl(data_ack); + } + #endif + +@@ -899,7 +927,7 @@ + kfree_skb(buff); + } + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + u32 seq = 0, ack_seq = 0; +@@ -967,7 +995,7 @@ + trace_tcp_send_reset(sk, skb); + } + +- tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0); ++ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, 0, oif, key, 1, 0, 0, 0); + + #ifdef CONFIG_TCP_MD5SIG + out: +@@ -976,30 +1004,37 @@ + } + + static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, u8 tclass, +- __be32 label) ++ __be32 label, int mptcp) + { +- tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, +- tclass, label); ++ tcp_v6_send_response(sk, skb, seq, ack, data_ack, win, tsval, tsecr, oif, ++ key, 0, tclass, label, mptcp); + } + + static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; + ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), +- tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); ++ tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), mptcp); + + inet_twsk_put(tw); + } + +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. +@@ -1009,18 +1044,18 @@ + * exception of segments, MUST be right-shifted by + * Rcv.Wind.Shift bits: + */ +- tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? ++ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? + tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, sk->sk_bound_dev_if, + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), +- 0, 0); ++ 0, 0, 0); + } + + +-static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1031,7 +1066,7 @@ + return sk; + } + +-static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) + { + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_conn_request(sk, skb); +@@ -1057,11 +1092,11 @@ + sizeof(struct inet6_skb_parm)); + } + +-static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req, +- struct dst_entry *dst, +- struct request_sock *req_unhash, +- bool *own_req) ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req) + { + struct inet_request_sock *ireq; + struct ipv6_pinfo *newnp; +@@ -1098,7 +1133,15 @@ + + newnp->saddr = newsk->sk_v6_rcv_saddr; + +- inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ /* We must check on the request-socket because the listener ++ * socket's flag may have been changed halfway through. ++ */ ++ if (!inet_rsk(req)->saw_mpc) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; + newsk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -1145,6 +1188,14 @@ + if (!newsk) + goto out_nonewsk; + ++#ifdef CONFIG_MPTCP ++ /* If the meta_sk is v6-mapped we can end up here with the wrong af_ops. ++ * Just make sure that this subflow is v6. ++ */ ++ if (is_meta_sk(sk)) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ + /* + * No need to charge this sock to the relevant IPv6 refcnt debug socks + * count here, tcp_create_openreq_child now does this for us, see the +@@ -1273,7 +1324,7 @@ + * This is because we cannot sleep with the original spinlock + * held. + */ +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + { + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp; +@@ -1290,6 +1341,9 @@ + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_do_rcv(sk, skb); + ++ if (is_meta_sk(sk)) ++ return mptcp_v6_do_rcv(sk, skb); ++ + /* + * socket locking is here for SMP purposes as backlog rcv + * is currently called with bh processing disabled. +@@ -1417,6 +1471,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff*4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); +@@ -1430,8 +1488,8 @@ + int sdif = inet6_sdif(skb); + const struct tcphdr *th; + const struct ipv6hdr *hdr; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + struct net *net = dev_net(skb->dev); + +@@ -1485,12 +1543,17 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ goto lookup; ++ } ++ if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } + sock_hold(sk); + refcounted = true; ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1523,6 +1586,7 @@ + return 0; + } + } ++ + if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { + __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); + goto discard_and_relse; +@@ -1549,15 +1613,25 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_v6_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1570,6 +1644,19 @@ + + tcp_v6_fill_cb(skb, hdr, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1622,6 +1709,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + } + /* to ACK */ + /* fall through */ +@@ -1676,13 +1775,13 @@ + } + } + +-static struct timewait_sock_ops tcp6_timewait_sock_ops = { ++struct timewait_sock_ops tcp6_timewait_sock_ops = { + .twsk_obj_size = sizeof(struct tcp6_timewait_sock), + .twsk_unique = tcp_twsk_unique, + .twsk_destructor = tcp_twsk_destructor, + }; + +-static const struct inet_connection_sock_af_ops ipv6_specific = { ++const struct inet_connection_sock_af_ops ipv6_specific = { + .queue_xmit = inet6_csk_xmit, + .send_check = tcp_v6_send_check, + .rebuild_header = inet6_sk_rebuild_header, +@@ -1713,7 +1812,7 @@ + /* + * TCP over IPv4 via INET6 API + */ +-static const struct inet_connection_sock_af_ops ipv6_mapped = { ++const struct inet_connection_sock_af_ops ipv6_mapped = { + .queue_xmit = ip_queue_xmit, + .send_check = tcp_v4_send_check, + .rebuild_header = inet_sk_rebuild_header, +@@ -1749,7 +1848,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; +@@ -1758,7 +1862,7 @@ + return 0; + } + +-static void tcp_v6_destroy_sock(struct sock *sk) ++void tcp_v6_destroy_sock(struct sock *sk) + { + tcp_v4_destroy_sock(sk); + inet6_destroy_sock(sk); +@@ -1981,6 +2085,11 @@ + .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), + .max_header = MAX_TCP_HEADER, + .obj_size = sizeof(struct tcp6_sock), ++#ifdef CONFIG_MPTCP ++ .useroffset = offsetof(struct tcp_sock, mptcp_sched_name), ++ .usersize = sizeof_field(struct tcp_sock, mptcp_sched_name) + ++ sizeof_field(struct tcp_sock, mptcp_pm_name), ++#endif + .slab_flags = SLAB_TYPESAFE_BY_RCU, + .twsk_prot = &tcp6_timewait_sock_ops, + .rsk_prot = &tcp6_request_sock_ops, +@@ -1991,6 +2100,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + + /* thinking of making this const? Don't. +diff -aurN linux-4.19.104/net/Kconfig mptcp-mptcp_v0.95/net/Kconfig +--- linux-4.19.104/net/Kconfig 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/Kconfig 2020-02-17 11:29:55.000000000 +0100 +@@ -89,6 +89,7 @@ + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" + source "net/netlabel/Kconfig" ++source "net/mptcp/Kconfig" + + endif # if INET + +diff -aurN linux-4.19.104/net/Makefile mptcp-mptcp_v0.95/net/Makefile +--- linux-4.19.104/net/Makefile 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/Makefile 2020-02-17 11:29:55.000000000 +0100 +@@ -20,6 +20,7 @@ + obj-$(CONFIG_XFRM) += xfrm/ + obj-$(CONFIG_UNIX) += unix/ + obj-$(CONFIG_NET) += ipv6/ ++obj-$(CONFIG_MPTCP) += mptcp/ + obj-$(CONFIG_BPFILTER) += bpfilter/ + obj-$(CONFIG_PACKET) += packet/ + obj-$(CONFIG_NET_KEY) += key/ +diff -aurN linux-4.19.104/net/mptcp/Kconfig mptcp-mptcp_v0.95/net/mptcp/Kconfig +--- linux-4.19.104/net/mptcp/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/Kconfig 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,146 @@ ++# ++# MPTCP configuration ++# ++config MPTCP ++ bool "MPTCP protocol" ++ depends on (IPV6=y || IPV6=n) ++ ---help--- ++ This replaces the normal TCP stack with a Multipath TCP stack, ++ able to use several paths at once. ++ ++menuconfig MPTCP_PM_ADVANCED ++ bool "MPTCP: advanced path-manager control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different path-managers. You should choose 'Y' here, ++ because otherwise you will not actively create new MPTCP-subflows. ++ ++if MPTCP_PM_ADVANCED ++ ++config MPTCP_FULLMESH ++ tristate "MPTCP Full-Mesh Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create a full-mesh among all IP-addresses. ++ ++config MPTCP_NDIFFPORTS ++ tristate "MPTCP ndiff-ports" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create multiple subflows between the same ++ pair of IP-addresses, modifying the source-port. You can set the number ++ of subflows via the mptcp_ndiffports-sysctl. ++ ++config MPTCP_BINDER ++ tristate "MPTCP Binder" ++ depends on (MPTCP=y) ++ ---help--- ++ This path-management module works like ndiffports, and adds the sysctl ++ option to set the gateway (and/or path to) per each additional subflow ++ via Loose Source Routing (IPv4 only). ++ ++config MPTCP_NETLINK ++ tristate "MPTCP Netlink Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module is controlled over a Netlink interface. A userspace ++ module can therefore control the establishment of new subflows and the policy ++ to apply over those new subflows for every connection. ++ ++choice ++ prompt "Default MPTCP Path-Manager" ++ default DEFAULT ++ help ++ Select the Path-Manager of your choice ++ ++ config DEFAULT_FULLMESH ++ bool "Full mesh" if MPTCP_FULLMESH=y ++ ++ config DEFAULT_NDIFFPORTS ++ bool "ndiff-ports" if MPTCP_NDIFFPORTS=y ++ ++ config DEFAULT_BINDER ++ bool "binder" if MPTCP_BINDER=y ++ ++ config DEFAULT_NETLINK ++ bool "Netlink" if MPTCP_NETLINK=y ++ ++ config DEFAULT_DUMMY ++ bool "Default" ++ ++endchoice ++ ++endif ++ ++config DEFAULT_MPTCP_PM ++ string ++ default "default" if DEFAULT_DUMMY ++ default "fullmesh" if DEFAULT_FULLMESH ++ default "ndiffports" if DEFAULT_NDIFFPORTS ++ default "binder" if DEFAULT_BINDER ++ default "default" ++ ++menuconfig MPTCP_SCHED_ADVANCED ++ bool "MPTCP: advanced scheduler control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different schedulers. You should choose 'Y' here, ++ if you want to choose a different scheduler than the default one. ++ ++if MPTCP_SCHED_ADVANCED ++ ++config MPTCP_BLEST ++ tristate "MPTCP BLEST" ++ depends on MPTCP=y ++ ---help--- ++ This is an experimental BLocking ESTimation-based (BLEST) scheduler. ++ ++config MPTCP_ROUNDROBIN ++ tristate "MPTCP Round-Robin" ++ depends on (MPTCP=y) ++ ---help--- ++ This is a very simple round-robin scheduler. Probably has bad performance ++ but might be interesting for researchers. ++ ++config MPTCP_REDUNDANT ++ tristate "MPTCP Redundant" ++ depends on (MPTCP=y) ++ ---help--- ++ This scheduler sends all packets redundantly over all subflows to decreases ++ latency and jitter on the cost of lower throughput. ++ ++choice ++ prompt "Default MPTCP Scheduler" ++ default DEFAULT ++ help ++ Select the Scheduler of your choice ++ ++ config DEFAULT_SCHEDULER ++ bool "Default" ++ ---help--- ++ This is the default scheduler, sending first on the subflow ++ with the lowest RTT. ++ ++ config DEFAULT_ROUNDROBIN ++ bool "Round-Robin" if MPTCP_ROUNDROBIN=y ++ ---help--- ++ This is the round-rob scheduler, sending in a round-robin ++ fashion.. ++ ++ config DEFAULT_REDUNDANT ++ bool "Redundant" if MPTCP_REDUNDANT=y ++ ---help--- ++ This is the redundant scheduler, sending packets redundantly over ++ all the subflows. ++ ++endchoice ++endif ++ ++config DEFAULT_MPTCP_SCHED ++ string ++ depends on (MPTCP=y) ++ default "default" if DEFAULT_SCHEDULER ++ default "roundrobin" if DEFAULT_ROUNDROBIN ++ default "redundant" if DEFAULT_REDUNDANT ++ default "default" ++ +diff -aurN linux-4.19.104/net/mptcp/Makefile mptcp-mptcp_v0.95/net/mptcp/Makefile +--- linux-4.19.104/net/mptcp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/Makefile 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,24 @@ ++# ++## Makefile for MultiPath TCP support code. ++# ++# ++ ++obj-$(CONFIG_MPTCP) += mptcp.o ++ ++mptcp-y := mptcp_ctrl.o mptcp_ipv4.o mptcp_pm.o \ ++ mptcp_output.o mptcp_input.o mptcp_sched.o ++ ++obj-$(CONFIG_TCP_CONG_LIA) += mptcp_coupled.o ++obj-$(CONFIG_TCP_CONG_OLIA) += mptcp_olia.o ++obj-$(CONFIG_TCP_CONG_WVEGAS) += mptcp_wvegas.o ++obj-$(CONFIG_TCP_CONG_BALIA) += mptcp_balia.o ++obj-$(CONFIG_TCP_CONG_MCTCPDESYNC) += mctcp_desync.o ++obj-$(CONFIG_MPTCP_FULLMESH) += mptcp_fullmesh.o ++obj-$(CONFIG_MPTCP_NDIFFPORTS) += mptcp_ndiffports.o ++obj-$(CONFIG_MPTCP_BINDER) += mptcp_binder.o ++obj-$(CONFIG_MPTCP_NETLINK) += mptcp_netlink.o ++obj-$(CONFIG_MPTCP_ROUNDROBIN) += mptcp_rr.o ++obj-$(CONFIG_MPTCP_REDUNDANT) += mptcp_redundant.o ++obj-$(CONFIG_MPTCP_BLEST) += mptcp_blest.o ++ ++mptcp-$(subst m,y,$(CONFIG_IPV6)) += mptcp_ipv6.o +diff -aurN linux-4.19.104/net/mptcp/mctcp_desync.c mptcp-mptcp_v0.95/net/mptcp/mctcp_desync.c +--- linux-4.19.104/net/mptcp/mctcp_desync.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mctcp_desync.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,193 @@ ++/* ++ * Desynchronized Multi-Channel TCP Congestion Control Algorithm ++ * ++ * Implementation based on publications of "DMCTCP:Desynchronized Multi-Channel ++ * TCP for high speed access networks with tiny buffers" in 23rd international ++ * conference of Computer Communication and Networks (ICCCN), 2014, and ++ * "Exploring parallelism and desynchronization of TCP over high speed networks ++ * with tiny buffers" in Journal of Computer Communications Elsevier, 2015. ++ * ++ * http://ieeexplore.ieee.org/abstract/document/6911722/ ++ * https://doi.org/10.1016/j.comcom.2015.07.010 ++ * ++ * This prototype is for research purpose and is currently experimental code ++ * that only support a single path. Future support of multi-channel over ++ * multi-path requires channels grouping. ++ * ++ * Initial Design and Implementation: ++ * Cheng Cui ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++ ++enum { ++ MASTER_CHANNEL = 1, ++ INI_MIN_CWND = 2, ++}; ++ ++/* private congestion control structure: ++ * off_tstamp: the last backoff timestamp for loss synchronization event ++ * off_subfid: the subflow which was backoff on off_tstamp ++ */ ++struct mctcp_desync { ++ u64 off_tstamp; ++ u8 off_subfid; ++}; ++ ++static inline int mctcp_cc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static void mctcp_desync_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ ca->off_tstamp = 0; ++ ca->off_subfid = 0; ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mctcp_desync_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } else if (!tcp_is_cwnd_limited(sk)) { ++ return; ++ } else { ++ const struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ const u8 subfid = tp->mptcp->path_index; ++ ++ /* current aggregated cwnd */ ++ u32 agg_cwnd = 0; ++ u32 min_cwnd = 0xffffffff; ++ u8 min_cwnd_subfid = 0; ++ ++ /* In "safe" area, increase */ ++ if (tcp_in_slow_start(tp)) { ++ if (ca->off_subfid) { ++ /* passed initial phase, allow slow start */ ++ tcp_slow_start(tp, acked); ++ } else if (MASTER_CHANNEL == tp->mptcp->path_index) { ++ /* master channel is normal slow start in ++ * initial phase */ ++ tcp_slow_start(tp, acked); ++ } else { ++ /* secondary channels increase slowly until ++ * the initial phase passed ++ */ ++ tp->snd_ssthresh = tp->snd_cwnd = INI_MIN_CWND; ++ } ++ return; ++ } else { ++ /* In dangerous area, increase slowly and linearly. */ ++ const struct mptcp_tcp_sock *mptcp; ++ ++ /* get total cwnd and the subflow that has min cwnd */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ ++ if (mctcp_cc_sk_can_send(sub_sk)) { ++ const struct tcp_sock *sub_tp = ++ tcp_sk(sub_sk); ++ agg_cwnd += sub_tp->snd_cwnd; ++ if(min_cwnd > sub_tp->snd_cwnd) { ++ min_cwnd = sub_tp->snd_cwnd; ++ min_cwnd_subfid = ++ sub_tp->mptcp->path_index; ++ } ++ } ++ } ++ /* the smallest subflow grows faster than others */ ++ if (subfid == min_cwnd_subfid) { ++ tcp_cong_avoid_ai(tp, min_cwnd, acked); ++ } else { ++ tcp_cong_avoid_ai(tp, agg_cwnd - min_cwnd, ++ acked); ++ } ++ } ++ } ++} ++ ++static u32 mctcp_desync_ssthresh(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp(tp)) { ++ return max(tp->snd_cwnd >> 1U, 2U); ++ } else { ++ struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ const u8 subfid = tp->mptcp->path_index; ++ const struct mptcp_tcp_sock *mptcp; ++ u32 max_cwnd = 0; ++ u8 max_cwnd_subfid = 0; ++ ++ /* Find the subflow that has the max cwnd. */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ ++ if (mctcp_cc_sk_can_send(sub_sk)) { ++ const struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ if (max_cwnd < sub_tp->snd_cwnd) { ++ max_cwnd = sub_tp->snd_cwnd; ++ max_cwnd_subfid = ++ sub_tp->mptcp->path_index; ++ } ++ } ++ } ++ /* Use high resolution clock. */ ++ if (subfid == max_cwnd_subfid) { ++ u64 now = tcp_clock_us(); ++ u32 delta = tcp_stamp_us_delta(now, ca->off_tstamp); ++ ++ if (delta < (tp->srtt_us >> 3)) { ++ /* desynchronize */ ++ return tp->snd_cwnd; ++ } else { ++ ca->off_tstamp = now; ++ ca->off_subfid = subfid; ++ return max(max_cwnd >> 1U, 2U); ++ } ++ } else { ++ return tp->snd_cwnd; ++ } ++ } ++} ++ ++static struct tcp_congestion_ops mctcp_desync = { ++ .init = mctcp_desync_init, ++ .ssthresh = mctcp_desync_ssthresh, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cong_avoid = mctcp_desync_cong_avoid, ++ .owner = THIS_MODULE, ++ .name = "mctcpdesync", ++}; ++ ++static int __init mctcp_desync_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mctcp_desync) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mctcp_desync); ++} ++ ++static void __exit mctcp_desync_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mctcp_desync); ++} ++ ++module_init(mctcp_desync_register); ++module_exit(mctcp_desync_unregister); ++ ++MODULE_AUTHOR("Cheng Cui"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MCTCP: DESYNCHRONIZED MULTICHANNEL TCP CONGESTION CONTROL"); ++MODULE_VERSION("1.0"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_balia.c mptcp-mptcp_v0.95/net/mptcp/mptcp_balia.c +--- linux-4.19.104/net/mptcp/mptcp_balia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_balia.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,261 @@ ++/* ++ * MPTCP implementation - Balia Congestion Control ++ * (Balanced Linked Adaptation Algorithm) ++ * ++ * Analysis, Design and Implementation: ++ * Qiuyu Peng ++ * Anwar Walid ++ * Jaehyun Hwang ++ * Steven H. Low ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++/* The variable 'rate' (i.e., x_r) will be scaled ++ * e.g., from B/s to KB/s, MB/s, or GB/s ++ * if max_rate > 2^rate_scale_limit ++ */ ++ ++static int rate_scale_limit = 25; ++static int alpha_scale = 10; ++static int scale_num = 5; ++ ++struct mptcp_balia { ++ u64 ai; ++ u64 md; ++ bool forced_update; ++}; ++ ++static inline int mptcp_balia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_ai(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai; ++} ++ ++static inline void mptcp_set_ai(const struct sock *meta_sk, u64 ai) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai = ai; ++} ++ ++static inline u64 mptcp_get_md(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md; ++} ++ ++static inline void mptcp_set_md(const struct sock *meta_sk, u64 md) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md = md; ++} ++ ++static inline u64 mptcp_balia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_balia_recalc_ai(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ u64 max_rate = 0, rate = 0, sum_rate = 0; ++ u64 alpha, ai = tp->snd_cwnd, md = (tp->snd_cwnd >> 1); ++ int num_scale_down = 0; ++ ++ if (!mpcb) ++ return; ++ ++ /* Find max_rate first */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ sum_rate += tmp; ++ ++ if (tp == sub_tp) ++ rate = tmp; ++ ++ if (tmp >= max_rate) ++ max_rate = tmp; ++ } ++ ++ /* At least, the current subflow should be able to send */ ++ if (unlikely(!rate)) ++ goto exit; ++ ++ alpha = div64_u64(max_rate, rate); ++ ++ /* Scale down max_rate if it is too high (e.g., >2^25) */ ++ while (max_rate > mptcp_balia_scale(1, rate_scale_limit)) { ++ max_rate >>= scale_num; ++ num_scale_down++; ++ } ++ ++ if (num_scale_down) { ++ sum_rate = 0; ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ tmp >>= (scale_num * num_scale_down); ++ ++ sum_rate += tmp; ++ } ++ rate >>= (scale_num * num_scale_down); ++ } ++ ++ /* (sum_rate)^2 * 10 * w_r ++ * ai = ------------------------------------ ++ * (x_r + max_rate) * (4x_r + max_rate) ++ */ ++ sum_rate *= sum_rate; ++ ++ ai = div64_u64(sum_rate * 10, rate + max_rate); ++ ai = div64_u64(ai * tp->snd_cwnd, (rate << 2) + max_rate); ++ ++ if (unlikely(!ai)) ++ ai = tp->snd_cwnd; ++ ++ md = ((tp->snd_cwnd >> 1) * min(mptcp_balia_scale(alpha, alpha_scale), ++ mptcp_balia_scale(3, alpha_scale) >> 1)) ++ >> alpha_scale; ++ ++exit: ++ mptcp_set_ai(sk, ai); ++ mptcp_set_md(sk, md); ++} ++ ++static void mptcp_balia_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(sk, 0); ++ mptcp_set_ai(sk, 0); ++ mptcp_set_md(sk, 0); ++ } ++} ++ ++static void mptcp_balia_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_COMPLETE_CWR || event == CA_EVENT_LOSS) ++ mptcp_balia_recalc_ai(sk); ++} ++ ++static void mptcp_balia_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(sk, 1); ++} ++ ++static void mptcp_balia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_balia_recalc_ai(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_balia_recalc_ai(sk); ++ mptcp_set_forced(sk, 0); ++ } ++ ++ snd_cwnd = (int)mptcp_get_ai(sk); ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_balia_recalc_ai(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static u32 mptcp_balia_ssthresh(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (unlikely(!mptcp(tp))) ++ return tcp_reno_ssthresh(sk); ++ else ++ return max((u32)(tp->snd_cwnd - mptcp_get_md(sk)), 1U); ++} ++ ++static struct tcp_congestion_ops mptcp_balia = { ++ .init = mptcp_balia_init, ++ .ssthresh = mptcp_balia_ssthresh, ++ .cong_avoid = mptcp_balia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_balia_cwnd_event, ++ .set_state = mptcp_balia_set_state, ++ .owner = THIS_MODULE, ++ .name = "balia", ++}; ++ ++static int __init mptcp_balia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_balia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_balia); ++} ++ ++static void __exit mptcp_balia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_balia); ++} ++ ++module_init(mptcp_balia_register); ++module_exit(mptcp_balia_unregister); ++ ++MODULE_AUTHOR("Jaehyun Hwang, Anwar Walid, Qiuyu Peng, Steven H. Low"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP BALIA CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_binder.c mptcp-mptcp_v0.95/net/mptcp/mptcp_binder.c +--- linux-4.19.104/net/mptcp/mptcp_binder.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_binder.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,494 @@ ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MPTCP_GW_MAX_LISTS 10 ++#define MPTCP_GW_LIST_MAX_LEN 6 ++#define MPTCP_GW_SYSCTL_MAX_LEN (15 * MPTCP_GW_LIST_MAX_LEN * \ ++ MPTCP_GW_MAX_LISTS) ++ ++struct mptcp_gw_list { ++ struct in_addr list[MPTCP_GW_MAX_LISTS][MPTCP_GW_LIST_MAX_LEN]; ++ u8 len[MPTCP_GW_MAX_LISTS]; ++}; ++ ++struct binder_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++ ++ /* Prevent multiple sub-sockets concurrently iterating over sockets */ ++ spinlock_t *flow_lock; ++}; ++ ++static struct mptcp_gw_list *mptcp_gws; ++static rwlock_t mptcp_gws_lock; ++ ++static int mptcp_binder_ndiffports __read_mostly = 1; ++ ++static char sysctl_mptcp_binder_gateways[MPTCP_GW_SYSCTL_MAX_LEN] __read_mostly; ++ ++static int mptcp_get_avail_list_ipv4(struct sock *sk) ++{ ++ int i, j, list_taken, opt_ret, opt_len; ++ unsigned char *opt_ptr, *opt_end_ptr, opt[MAX_IPOPTLEN]; ++ ++ for (i = 0; i < MPTCP_GW_MAX_LISTS; ++i) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (mptcp_gws->len[i] == 0) ++ goto error; ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: List %i\n", i); ++ list_taken = 0; ++ ++ /* Loop through all sub-sockets in this connection */ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: Next sock\n"); ++ ++ /* Reset length and options buffer, then retrieve ++ * from socket ++ */ ++ opt_len = MAX_IPOPTLEN; ++ memset(opt, 0, MAX_IPOPTLEN); ++ opt_ret = ip_getsockopt(sk, IPPROTO_IP, ++ IP_OPTIONS, (char __user *)opt, (int __user *)&opt_len); ++ if (opt_ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket getsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, opt_ret); ++ goto error; ++ } ++ ++ /* If socket has no options, it has no stake in this list */ ++ if (opt_len <= 0) ++ continue; ++ ++ /* Iterate options buffer */ ++ for (opt_ptr = &opt[0]; opt_ptr < &opt[opt_len]; opt_ptr++) { ++ if (*opt_ptr == IPOPT_LSRR) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: LSRR options found\n"); ++ goto sock_lsrr; ++ } ++ } ++ continue; ++ ++sock_lsrr: ++ /* Pointer to the 2nd to last address */ ++ opt_end_ptr = opt_ptr+(*(opt_ptr+1))-4; ++ ++ /* Addresses start 3 bytes after type offset */ ++ opt_ptr += 3; ++ j = 0; ++ ++ /* Different length lists cannot be the same */ ++ if ((opt_end_ptr-opt_ptr)/4 != mptcp_gws->len[i]) ++ continue; ++ ++ /* Iterate if we are still inside options list ++ * and sysctl list ++ */ ++ while (opt_ptr < opt_end_ptr && j < mptcp_gws->len[i]) { ++ /* If there is a different address, this list must ++ * not be set on this socket ++ */ ++ if (memcmp(&mptcp_gws->list[i][j], opt_ptr, 4)) ++ break; ++ ++ /* Jump 4 bytes to next address */ ++ opt_ptr += 4; ++ j++; ++ } ++ ++ /* Reached the end without a differing address, lists ++ * are therefore identical. ++ */ ++ if (j == mptcp_gws->len[i]) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List already used\n"); ++ list_taken = 1; ++ break; ++ } ++ } ++ ++ /* Free list found if not taken by a socket */ ++ if (!list_taken) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List free\n"); ++ break; ++ } ++ } ++ ++ if (i >= MPTCP_GW_MAX_LISTS) ++ goto error; ++ ++ return i; ++error: ++ return -1; ++} ++ ++/* The list of addresses is parsed each time a new connection is opened, ++ * to make sure it's up to date. In case of error, all the lists are ++ * marked as unavailable and the subflow's fingerprint is set to 0. ++ */ ++static void mptcp_v4_add_lsrr(struct sock *sk, struct in_addr addr) ++{ ++ int i, j, ret; ++ unsigned char opt[MAX_IPOPTLEN] = {0}; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct binder_priv *fmp = (struct binder_priv *)&tp->mpcb->mptcp_pm[0]; ++ ++ /* Read lock: multiple sockets can read LSRR addresses at the same ++ * time, but writes are done in mutual exclusion. ++ * Spin lock: must search for free list for one socket at a time, or ++ * multiple sockets could take the same list. ++ */ ++ read_lock(&mptcp_gws_lock); ++ spin_lock(fmp->flow_lock); ++ ++ i = mptcp_get_avail_list_ipv4(sk); ++ ++ /* Execution enters here only if a free path is found. ++ */ ++ if (i >= 0) { ++ opt[0] = IPOPT_NOP; ++ opt[1] = IPOPT_LSRR; ++ opt[2] = sizeof(mptcp_gws->list[i][0].s_addr) * ++ (mptcp_gws->len[i] + 1) + 3; ++ opt[3] = IPOPT_MINOFF; ++ for (j = 0; j < mptcp_gws->len[i]; ++j) ++ memcpy(opt + 4 + ++ (j * sizeof(mptcp_gws->list[i][0].s_addr)), ++ &mptcp_gws->list[i][j].s_addr, ++ sizeof(mptcp_gws->list[i][0].s_addr)); ++ /* Final destination must be part of IP_OPTIONS parameter. */ ++ memcpy(opt + 4 + (j * sizeof(addr.s_addr)), &addr.s_addr, ++ sizeof(addr.s_addr)); ++ ++ /* setsockopt must be inside the lock, otherwise another ++ * subflow could fail to see that we have taken a list. ++ */ ++ ret = ip_setsockopt(sk, IPPROTO_IP, IP_OPTIONS, (char __user *)opt, ++ 4 + sizeof(mptcp_gws->list[i][0].s_addr) * (mptcp_gws->len[i] + 1)); ++ ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsock setsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, ret); ++ } ++ } ++ ++ spin_unlock(fmp->flow_lock); ++ read_unlock(&mptcp_gws_lock); ++ ++ return; ++} ++ ++/* Parses gateways string for a list of paths to different ++ * gateways, and stores them for use with the Loose Source Routing (LSRR) ++ * socket option. Each list must have "," separated addresses, and the lists ++ * themselves must be separated by "-". Returns -1 in case one or more of the ++ * addresses is not a valid ipv4/6 address. ++ */ ++static int mptcp_parse_gateway_ipv4(char *gateways) ++{ ++ int i, j, k, ret; ++ char *tmp_string = NULL; ++ struct in_addr tmp_addr; ++ ++ tmp_string = kzalloc(16, GFP_KERNEL); ++ if (tmp_string == NULL) ++ return -ENOMEM; ++ ++ write_lock(&mptcp_gws_lock); ++ ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ ++ /* A TMP string is used since inet_pton needs a null terminated string ++ * but we do not want to modify the sysctl for obvious reasons. ++ * i will iterate over the SYSCTL string, j will iterate over the ++ * temporary string where each IP is copied into, k will iterate over ++ * the IPs in each list. ++ */ ++ for (i = j = k = 0; ++ i < MPTCP_GW_SYSCTL_MAX_LEN && k < MPTCP_GW_MAX_LISTS; ++ ++i) { ++ if (gateways[i] == '-' || gateways[i] == ',' || gateways[i] == '\0') { ++ /* If the temp IP is empty and the current list is ++ * empty, we are done. ++ */ ++ if (j == 0 && mptcp_gws->len[k] == 0) ++ break; ++ ++ /* Terminate the temp IP string, then if it is ++ * non-empty parse the IP and copy it. ++ */ ++ tmp_string[j] = '\0'; ++ if (j > 0) { ++ mptcp_debug("mptcp_parse_gateway_list tmp: %s i: %d\n", tmp_string, i); ++ ++ ret = in4_pton(tmp_string, strlen(tmp_string), ++ (u8 *)&tmp_addr.s_addr, '\0', ++ NULL); ++ ++ if (ret) { ++ mptcp_debug("mptcp_parse_gateway_list ret: %d s_addr: %pI4\n", ++ ret, ++ &tmp_addr.s_addr); ++ memcpy(&mptcp_gws->list[k][mptcp_gws->len[k]].s_addr, ++ &tmp_addr.s_addr, ++ sizeof(tmp_addr.s_addr)); ++ mptcp_gws->len[k]++; ++ j = 0; ++ tmp_string[j] = '\0'; ++ /* Since we can't impose a limit to ++ * what the user can input, make sure ++ * there are not too many IPs in the ++ * SYSCTL string. ++ */ ++ if (mptcp_gws->len[k] > MPTCP_GW_LIST_MAX_LEN) { ++ mptcp_debug("mptcp_parse_gateway_list too many members in list %i: max %i\n", ++ k, ++ MPTCP_GW_LIST_MAX_LEN); ++ goto error; ++ } ++ } else { ++ goto error; ++ } ++ } ++ ++ if (gateways[i] == '-' || gateways[i] == '\0') ++ ++k; ++ } else { ++ tmp_string[j] = gateways[i]; ++ ++j; ++ } ++ } ++ ++ /* Number of flows is number of gateway lists plus master flow */ ++ mptcp_binder_ndiffports = k+1; ++ ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ ++ return 0; ++ ++error: ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ memset(gateways, 0, sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN); ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ return -1; ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct binder_priv *pm_priv = container_of(work, ++ struct binder_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (mptcp_binder_ndiffports > iter && ++ mptcp_binder_ndiffports > mptcp_subflow_count(mpcb)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void binder_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *fmp = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ static DEFINE_SPINLOCK(flow_lock); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(meta_sk)) { ++ mptcp_fallback_default(mpcb); ++ return; ++ } ++#endif ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ fmp->flow_lock = &flow_lock; ++} ++ ++static void binder_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *pm_priv = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int binder_get_local_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ return 0; ++} ++ ++/* Callback functions, executed when syctl mptcp.mptcp_gateways is updated. ++ * Inspired from proc_tcp_congestion_control(). ++ */ ++static int proc_mptcp_gateways(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ struct ctl_table tbl = { ++ .maxlen = MPTCP_GW_SYSCTL_MAX_LEN, ++ }; ++ ++ if (write) { ++ tbl.data = kzalloc(MPTCP_GW_SYSCTL_MAX_LEN, GFP_KERNEL); ++ if (tbl.data == NULL) ++ return -ENOMEM; ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (ret == 0) { ++ ret = mptcp_parse_gateway_ipv4(tbl.data); ++ memcpy(ctl->data, tbl.data, MPTCP_GW_SYSCTL_MAX_LEN); ++ } ++ kfree(tbl.data); ++ } else { ++ ret = proc_dostring(ctl, write, buffer, lenp, ppos); ++ } ++ ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops binder __read_mostly = { ++ .new_session = binder_new_session, ++ .fully_established = binder_create_subflows, ++ .get_local_id = binder_get_local_id, ++ .init_subsocket_v4 = mptcp_v4_add_lsrr, ++ .name = "binder", ++ .owner = THIS_MODULE, ++}; ++ ++static struct ctl_table binder_table[] = { ++ { ++ .procname = "mptcp_binder_gateways", ++ .data = &sysctl_mptcp_binder_gateways, ++ .maxlen = sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN, ++ .mode = 0644, ++ .proc_handler = &proc_mptcp_gateways ++ }, ++ { } ++}; ++ ++static struct ctl_table_header *mptcp_sysctl_binder; ++ ++/* General initialization of MPTCP_PM */ ++static int __init binder_register(void) ++{ ++ mptcp_gws = kzalloc(sizeof(*mptcp_gws), GFP_KERNEL); ++ if (!mptcp_gws) ++ return -ENOMEM; ++ ++ rwlock_init(&mptcp_gws_lock); ++ ++ BUILD_BUG_ON(sizeof(struct binder_priv) > MPTCP_PM_SIZE); ++ ++ mptcp_sysctl_binder = register_net_sysctl(&init_net, "net/mptcp", ++ binder_table); ++ if (!mptcp_sysctl_binder) ++ goto sysctl_fail; ++ ++ if (mptcp_register_path_manager(&binder)) ++ goto pm_failed; ++ ++ return 0; ++ ++pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++sysctl_fail: ++ kfree(mptcp_gws); ++ ++ return -1; ++} ++ ++static void binder_unregister(void) ++{ ++ mptcp_unregister_path_manager(&binder); ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++ kfree(mptcp_gws); ++} ++ ++module_init(binder_register); ++module_exit(binder_unregister); ++ ++MODULE_AUTHOR("Luca Boccassi, Duncan Eastoe, Christoph Paasch (ndiffports)"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BINDER MPTCP"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_blest.c mptcp-mptcp_v0.95/net/mptcp/mptcp_blest.c +--- linux-4.19.104/net/mptcp/mptcp_blest.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_blest.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,481 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP Scheduler to reduce HoL-blocking and spurious retransmissions. ++ * ++ * Algorithm Design: ++ * Simone Ferlin ++ * Ozgu Alay ++ * Olivier Mehani ++ * Roksana Boreli ++ * ++ * Initial Implementation: ++ * Simone Ferlin ++ * ++ * Additional Authors: ++ * Daniel Weber ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++static unsigned char lambda __read_mostly = 12; ++module_param(lambda, byte, 0644); ++MODULE_PARM_DESC(lambda, "Divided by 10 for scaling factor of fast flow rate estimation"); ++ ++static unsigned char max_lambda __read_mostly = 13; ++module_param(max_lambda, byte, 0644); ++MODULE_PARM_DESC(max_lambda, "Divided by 10 for maximum scaling factor of fast flow rate estimation"); ++ ++static unsigned char min_lambda __read_mostly = 10; ++module_param(min_lambda, byte, 0644); ++MODULE_PARM_DESC(min_lambda, "Divided by 10 for minimum scaling factor of fast flow rate estimation"); ++ ++static unsigned char dyn_lambda_good = 10; /* 1% */ ++module_param(dyn_lambda_good, byte, 0644); ++MODULE_PARM_DESC(dyn_lambda_good, "Decrease of lambda in positive case."); ++ ++static unsigned char dyn_lambda_bad = 40; /* 4% */ ++module_param(dyn_lambda_bad, byte, 0644); ++MODULE_PARM_DESC(dyn_lambda_bad, "Increase of lambda in negative case."); ++ ++struct blestsched_priv { ++ u32 last_rbuf_opti; ++ u32 min_srtt_us; ++ u32 max_srtt_us; ++}; ++ ++struct blestsched_cb { ++ bool retrans_flag; ++ s16 lambda_1000; /* values range from min_lambda * 100 to max_lambda * 100 */ ++ u32 last_lambda_update; ++}; ++ ++static struct blestsched_priv *blestsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct blestsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++static struct blestsched_cb *blestsched_get_cb(const struct tcp_sock *tp) ++{ ++ return (struct blestsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static void blestsched_update_lambda(struct sock *meta_sk, struct sock *sk) ++{ ++ struct blestsched_cb *blest_cb = blestsched_get_cb(tcp_sk(meta_sk)); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tcp_sk(sk)); ++ ++ if (tcp_jiffies32 - blest_cb->last_lambda_update < usecs_to_jiffies(blest_p->min_srtt_us >> 3)) ++ return; ++ ++ /* if there have been retransmissions of packets of the slow flow ++ * during the slow flows last RTT => increase lambda ++ * otherwise decrease ++ */ ++ if (blest_cb->retrans_flag) { ++ /* need to slow down on the slow flow */ ++ blest_cb->lambda_1000 += dyn_lambda_bad; ++ } else { ++ /* use the slow flow more */ ++ blest_cb->lambda_1000 -= dyn_lambda_good; ++ } ++ blest_cb->retrans_flag = false; ++ ++ /* cap lambda_1000 to its value range */ ++ blest_cb->lambda_1000 = min_t(s16, blest_cb->lambda_1000, max_lambda * 100); ++ blest_cb->lambda_1000 = max_t(s16, blest_cb->lambda_1000, min_lambda * 100); ++ ++ blest_cb->last_lambda_update = tcp_jiffies32; ++} ++ ++/* how many bytes will sk send during the rtt of another, slower flow? */ ++static u32 blestsched_estimate_bytes(struct sock *sk, u32 time_8) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tp); ++ struct blestsched_cb *blest_cb = blestsched_get_cb(mptcp_meta_tp(tp)); ++ u32 avg_rtt, num_rtts, ca_cwnd, packets; ++ ++ avg_rtt = (blest_p->min_srtt_us + blest_p->max_srtt_us) / 2; ++ if (avg_rtt == 0) ++ num_rtts = 1; /* sanity */ ++ else ++ num_rtts = (time_8 / avg_rtt) + 1; /* round up */ ++ ++ /* during num_rtts, how many bytes will be sent on the flow? ++ * assumes for simplification that Reno is applied as congestion-control ++ */ ++ if (tp->snd_ssthresh == TCP_INFINITE_SSTHRESH) { ++ /* we are in initial slow start */ ++ if (num_rtts > 16) ++ num_rtts = 16; /* cap for sanity */ ++ packets = tp->snd_cwnd * ((1 << num_rtts) - 1); /* cwnd + 2*cwnd + 4*cwnd */ ++ } else { ++ ca_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh + 1); /* assume we jump to CA already */ ++ packets = (ca_cwnd + (num_rtts - 1) / 2) * num_rtts; ++ } ++ ++ return div_u64(((u64)packets) * tp->mss_cache * blest_cb->lambda_1000, 1000); ++} ++ ++static u32 blestsched_estimate_linger_time(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tp); ++ u32 estimate, slope, inflight, cwnd; ++ ++ inflight = tcp_packets_in_flight(tp) + 1; /* take into account the new one */ ++ cwnd = tp->snd_cwnd; ++ ++ if (inflight >= cwnd) { ++ estimate = blest_p->max_srtt_us; ++ } else { ++ slope = blest_p->max_srtt_us - blest_p->min_srtt_us; ++ if (cwnd == 0) ++ cwnd = 1; /* sanity */ ++ estimate = blest_p->min_srtt_us + (slope * inflight) / cwnd; ++ } ++ ++ return (tp->srtt_us > estimate) ? tp->srtt_us : estimate; ++} ++ ++/* This is the BLEST scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy or the currently best ++ * subflow is estimated to possibly cause HoL-blocking, NULL is returned. ++ */ ++struct sock *blest_get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *bestsk, *minsk = NULL; ++ struct tcp_sock *meta_tp, *besttp; ++ struct mptcp_tcp_sock *mptcp; ++ struct blestsched_priv *blest_p; ++ u32 min_srtt = U32_MAX; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(bestsk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(bestsk, skb, zero_wnd_test)) ++ return bestsk; ++ } ++ } ++ ++ /* First, find the overall best subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ besttp = tcp_sk(bestsk); ++ blest_p = blestsched_get_priv(besttp); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(bestsk)) ++ continue; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (besttp->mptcp->pre_established) ++ continue; ++ ++ blest_p->min_srtt_us = min(blest_p->min_srtt_us, besttp->srtt_us); ++ blest_p->max_srtt_us = max(blest_p->max_srtt_us, besttp->srtt_us); ++ ++ /* record minimal rtt */ ++ if (besttp->srtt_us < min_srtt) { ++ min_srtt = besttp->srtt_us; ++ minsk = bestsk; ++ } ++ } ++ ++ /* find the current best subflow according to the default scheduler */ ++ bestsk = get_available_subflow(meta_sk, skb, zero_wnd_test); ++ ++ /* if we decided to use a slower flow, we have the option of not using it at all */ ++ if (bestsk && minsk && bestsk != minsk) { ++ u32 slow_linger_time, fast_bytes, slow_inflight_bytes, slow_bytes, avail_space; ++ u32 buffered_bytes = 0; ++ ++ meta_tp = tcp_sk(meta_sk); ++ besttp = tcp_sk(bestsk); ++ ++ blestsched_update_lambda(meta_sk, bestsk); ++ ++ /* if we send this SKB now, it will be acked in besttp->srtt seconds ++ * during this time: how many bytes will we send on the fast flow? ++ */ ++ slow_linger_time = blestsched_estimate_linger_time(bestsk); ++ fast_bytes = blestsched_estimate_bytes(minsk, slow_linger_time); ++ ++ if (skb) ++ buffered_bytes = skb->len; ++ ++ /* is the required space available in the mptcp meta send window? ++ * we assume that all bytes inflight on the slow path will be acked in besttp->srtt seconds ++ * (just like the SKB if it was sent now) -> that means that those inflight bytes will ++ * keep occupying space in the meta window until then ++ */ ++ slow_inflight_bytes = besttp->write_seq - besttp->snd_una; ++ slow_bytes = buffered_bytes + slow_inflight_bytes; // bytes of this SKB plus those in flight already ++ ++ avail_space = (slow_bytes < meta_tp->snd_wnd) ? (meta_tp->snd_wnd - slow_bytes) : 0; ++ ++ if (fast_bytes > avail_space) { ++ /* sending this SKB on the slow flow means ++ * we wouldn't be able to send all the data we'd like to send on the fast flow ++ * so don't do that ++ */ ++ return NULL; ++ } ++ } ++ ++ return bestsk; ++} ++ ++/* copy from mptcp_sched.c: mptcp_rcv_buf_optimization */ ++static struct sk_buff *mptcp_blest_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb_head; ++ struct blestsched_priv *blest_p = blestsched_get_priv(tp); ++ struct blestsched_cb *blest_cb; ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!skb_head) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Record the occurrence of a retransmission to update the lambda value */ ++ blest_cb = blestsched_get_cb(tcp_sk(meta_sk)); ++ blest_cb->retrans_flag = true; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_jiffies32 - blest_p->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flows */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ blest_p->last_rbuf_opti = tcp_jiffies32; ++ } ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) { ++ trace_mptcp_retransmit(sk, skb_head); ++ return skb_head; ++ } ++ } ++ return NULL; ++} ++ ++/* copy from mptcp_sched.c: __mptcp_next_segment */ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_blest_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = blest_get_available_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_blest_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++/* copy from mptcp_sched.c: mptcp_next_segment */ ++static struct sk_buff *mptcp_blest_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_blest_next_segment(meta_sk, reinject); ++ unsigned int mss_now; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ u32 max_len, max_segs, window, needed; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = blest_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_blest_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ * ++ * So, we first limit according to the cwnd/gso-size and then according ++ * to the subflow's window. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ max_len = mss_now * max_segs; ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ needed = min(skb->len, window); ++ if (max_len <= skb->len) ++ /* Take max_win, which is actually the cwnd/gso-size */ ++ *limit = max_len; ++ else ++ /* Or, take the window */ ++ *limit = needed; ++ ++ return skb; ++} ++ ++static void blestsched_init(struct sock *sk) ++{ ++ struct blestsched_priv *blest_p = blestsched_get_priv(tcp_sk(sk)); ++ struct blestsched_cb *blest_cb = blestsched_get_cb(tcp_sk(mptcp_meta_sk(sk))); ++ ++ blest_p->last_rbuf_opti = tcp_jiffies32; ++ blest_p->min_srtt_us = U32_MAX; ++ blest_p->max_srtt_us = 0; ++ ++ if (!blest_cb->lambda_1000) { ++ blest_cb->lambda_1000 = lambda * 100; ++ blest_cb->last_lambda_update = tcp_jiffies32; ++ } ++} ++ ++static struct mptcp_sched_ops mptcp_sched_blest = { ++ .get_subflow = blest_get_available_subflow, ++ .next_segment = mptcp_blest_next_segment, ++ .init = blestsched_init, ++ .name = "blest", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init blest_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct blestsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct blestsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_blest)) ++ return -1; ++ ++ return 0; ++} ++ ++static void blest_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_blest); ++} ++ ++module_init(blest_register); ++module_exit(blest_unregister); ++ ++MODULE_AUTHOR("Simone Ferlin, Daniel Weber"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BLEST scheduler for MPTCP, based on default minimum RTT scheduler"); ++MODULE_VERSION("0.95"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_coupled.c mptcp-mptcp_v0.95/net/mptcp/mptcp_coupled.c +--- linux-4.19.104/net/mptcp/mptcp_coupled.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_coupled.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,262 @@ ++/* ++ * MPTCP implementation - Linked Increase congestion control Algorithm (LIA) ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++#include ++#include ++ ++#include ++ ++/* Scaling is done in the numerator with alpha_scale_num and in the denominator ++ * with alpha_scale_den. ++ * ++ * To downscale, we just need to use alpha_scale. ++ * ++ * We have: alpha_scale = alpha_scale_num / (alpha_scale_den ^ 2) ++ */ ++static int alpha_scale_den = 10; ++static int alpha_scale_num = 32; ++static int alpha_scale = 12; ++ ++struct mptcp_ccc { ++ u64 alpha; ++ bool forced_update; ++}; ++ ++static inline int mptcp_ccc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_alpha(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha; ++} ++ ++static inline void mptcp_set_alpha(const struct sock *meta_sk, u64 alpha) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha = alpha; ++} ++ ++static inline u64 mptcp_ccc_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_ccc_recalc_alpha(const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ const struct mptcp_tcp_sock *mptcp; ++ int best_cwnd = 0, best_rtt = 0, can_send = 0; ++ u64 max_numerator = 0, sum_denominator = 0, alpha = 1; ++ ++ if (!mpcb) ++ return; ++ ++ /* Do regular alpha-calculation for multiple subflows */ ++ ++ /* Find the max numerator of the alpha-calculation */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ can_send++; ++ ++ /* We need to look for the path, that provides the max-value. ++ * Integer-overflow is not possible here, because ++ * tmp will be in u64. ++ */ ++ tmp = div64_u64(mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_num), (u64)sub_tp->srtt_us * sub_tp->srtt_us); ++ ++ if (tmp >= max_numerator) { ++ max_numerator = tmp; ++ best_cwnd = sub_tp->snd_cwnd; ++ best_rtt = sub_tp->srtt_us; ++ } ++ } ++ ++ /* No subflow is able to send - we don't care anymore */ ++ if (unlikely(!can_send)) ++ goto exit; ++ ++ /* Calculate the denominator */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ sum_denominator += div_u64( ++ mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_den) * best_rtt, ++ sub_tp->srtt_us); ++ } ++ sum_denominator *= sum_denominator; ++ if (unlikely(!sum_denominator)) { ++ pr_err("%s: sum_denominator == 0\n", __func__); ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ pr_err("%s: pi:%d, state:%d\n, rtt:%u, cwnd: %u", ++ __func__, sub_tp->mptcp->path_index, ++ sub_sk->sk_state, sub_tp->srtt_us, ++ sub_tp->snd_cwnd); ++ } ++ } ++ ++ alpha = div64_u64(mptcp_ccc_scale(best_cwnd, alpha_scale_num), sum_denominator); ++ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++exit: ++ mptcp_set_alpha(mptcp_meta_sk(sk), alpha); ++} ++ ++static void mptcp_ccc_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ mptcp_set_alpha(mptcp_meta_sk(sk), 1); ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mptcp_ccc_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_LOSS) ++ mptcp_ccc_recalc_alpha(sk); ++} ++ ++static void mptcp_ccc_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(mptcp_meta_sk(sk), 1); ++} ++ ++static void mptcp_ccc_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ int snd_cwnd; ++ u64 alpha; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_ccc_recalc_alpha(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_ccc_recalc_alpha(sk); ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ } ++ ++ alpha = mptcp_get_alpha(mptcp_meta_sk(sk)); ++ ++ /* This may happen, if at the initialization, the mpcb ++ * was not yet attached to the sock, and thus ++ * initializing alpha failed. ++ */ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++ snd_cwnd = (int)div_u64((u64)mptcp_ccc_scale(1, alpha_scale), alpha); ++ ++ /* snd_cwnd_cnt >= max (scale * tot_cwnd / alpha, cwnd) ++ * Thus, we select here the max value. ++ */ ++ if (snd_cwnd < tp->snd_cwnd) ++ snd_cwnd = tp->snd_cwnd; ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_ccc_recalc_alpha(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_ccc = { ++ .init = mptcp_ccc_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_ccc_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_ccc_cwnd_event, ++ .set_state = mptcp_ccc_set_state, ++ .owner = THIS_MODULE, ++ .name = "lia", ++}; ++ ++static int __init mptcp_ccc_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_ccc) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_ccc); ++} ++ ++static void __exit mptcp_ccc_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_ccc); ++} ++ ++module_init(mptcp_ccc_register); ++module_exit(mptcp_ccc_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch, Sébastien Barré"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP LINKED INCREASE CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_ctrl.c mptcp-mptcp_v0.95/net/mptcp/mptcp_ctrl.c +--- linux-4.19.104/net/mptcp/mptcp_ctrl.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_ctrl.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,3140 @@ ++/* ++ * MPTCP implementation - MPTCP-control ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *mptcp_sock_cache __read_mostly; ++static struct kmem_cache *mptcp_cb_cache __read_mostly; ++static struct kmem_cache *mptcp_tw_cache __read_mostly; ++ ++int sysctl_mptcp_enabled __read_mostly = 1; ++int sysctl_mptcp_version __read_mostly = 0; ++static int min_mptcp_version; ++static int max_mptcp_version = 1; ++int sysctl_mptcp_checksum __read_mostly = 1; ++int sysctl_mptcp_debug __read_mostly; ++EXPORT_SYMBOL(sysctl_mptcp_debug); ++int sysctl_mptcp_syn_retries __read_mostly = 3; ++ ++bool mptcp_init_failed __read_mostly; ++ ++struct static_key mptcp_static_key = STATIC_KEY_INIT_FALSE; ++EXPORT_SYMBOL(mptcp_static_key); ++ ++static void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn); ++ ++static int proc_mptcp_path_manager(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_PM_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_path_manager(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_path_manager(val); ++ return ret; ++} ++ ++static int proc_mptcp_scheduler(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_SCHED_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_scheduler(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_scheduler(val); ++ return ret; ++} ++ ++static struct ctl_table mptcp_table[] = { ++ { ++ .procname = "mptcp_enabled", ++ .data = &sysctl_mptcp_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_version", ++ .data = &sysctl_mptcp_version, ++ .mode = 0644, ++ .maxlen = sizeof(int), ++ .proc_handler = &proc_dointvec_minmax, ++ .extra1 = &min_mptcp_version, ++ .extra2 = &max_mptcp_version, ++ }, ++ { ++ .procname = "mptcp_checksum", ++ .data = &sysctl_mptcp_checksum, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_debug", ++ .data = &sysctl_mptcp_debug, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_syn_retries", ++ .data = &sysctl_mptcp_syn_retries, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_path_manager", ++ .mode = 0644, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ .proc_handler = proc_mptcp_path_manager, ++ }, ++ { ++ .procname = "mptcp_scheduler", ++ .mode = 0644, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ .proc_handler = proc_mptcp_scheduler, ++ }, ++ { } ++}; ++ ++static inline u32 mptcp_hash_tk(u32 token) ++{ ++ return token % MPTCP_HASH_SIZE; ++} ++ ++struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++EXPORT_SYMBOL(tk_hashtable); ++ ++/* The following hash table is used to avoid collision of token */ ++static struct hlist_nulls_head mptcp_reqsk_tk_htb[MPTCP_HASH_SIZE]; ++ ++/* Lock, protecting the two hash-tables that hold the token. Namely, ++ * mptcp_reqsk_tk_htb and tk_hashtable ++ */ ++static spinlock_t mptcp_tk_hashlock; ++ ++static bool mptcp_reqsk_find_tk(const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct mptcp_request_sock *mtreqsk; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(mtreqsk, node, ++ &mptcp_reqsk_tk_htb[hash], hash_entry) { ++ if (token == mtreqsk->mptcp_loc_token) ++ return true; ++ } ++ /* A request-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_reqsk_insert_tk(struct request_sock *reqsk, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ ++ hlist_nulls_add_head_rcu(&mptcp_rsk(reqsk)->hash_entry, ++ &mptcp_reqsk_tk_htb[hash]); ++} ++ ++static void mptcp_reqsk_remove_tk(const struct request_sock *reqsk) ++{ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&mptcp_rsk(reqsk)->hash_entry); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++void mptcp_reqsk_destructor(struct request_sock *req) ++{ ++ if (!mptcp_rsk(req)->is_sub) ++ mptcp_reqsk_remove_tk(req); ++} ++ ++static void __mptcp_hash_insert(struct tcp_sock *meta_tp, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ hlist_nulls_add_head_rcu(&meta_tp->tk_table, &tk_hashtable[hash]); ++ meta_tp->inside_tk_table = 1; ++} ++ ++static bool mptcp_find_token(u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], tk_table) { ++ if (token == meta_tp->mptcp_loc_token) ++ return true; ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_set_key_reqsk(struct request_sock *req, ++ const struct sk_buff *skb, ++ u32 seed) ++{ ++ const struct inet_request_sock *ireq = inet_rsk(req); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ mtreq->mptcp_loc_key = mptcp_v4_get_key(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ mtreq->mptcp_loc_key = mptcp_v6_get_key(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#endif ++ } ++ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++} ++ ++/* New MPTCP-connection request, prepare a new token for the meta-socket that ++ * will be created in mptcp_check_req_master(), and store the received token. ++ */ ++static void mptcp_reqsk_new_mptcp(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tp->mptcp_ver) ++ mtreq->mptcp_ver = tp->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_reqsk(req, skb, mptcp_seed++); ++ } while (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)); ++ mptcp_reqsk_insert_tk(req, mtreq->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++} ++ ++static int mptcp_reqsk_new_cookie(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tcp_sk(sk)->mptcp_ver) ++ mtreq->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ mptcp_set_key_reqsk(req, skb, tcp_rsk(req)->snt_isn); ++ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return false; ++ } ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ ++ return true; ++} ++ ++static void mptcp_set_key_sk(const struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_sock *isk = inet_sk(sk); ++ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp_loc_key = mptcp_v4_get_key(isk->inet_saddr, ++ isk->inet_daddr, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp_loc_key = mptcp_v6_get_key(inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#endif ++ ++ mptcp_key_sha1(tp->mptcp_loc_key, ++ &tp->mptcp_loc_token, NULL); ++} ++ ++#ifdef CONFIG_JUMP_LABEL ++static atomic_t mptcp_needed_deferred; ++static atomic_t mptcp_wanted; ++ ++static void mptcp_clear(struct work_struct *work) ++{ ++ int deferred = atomic_xchg(&mptcp_needed_deferred, 0); ++ int wanted; ++ ++ wanted = atomic_add_return(deferred, &mptcp_wanted); ++ if (wanted > 0) ++ static_key_enable(&mptcp_static_key); ++ else ++ static_key_disable(&mptcp_static_key); ++} ++ ++static DECLARE_WORK(mptcp_work, mptcp_clear); ++#endif ++ ++static void mptcp_enable_static_key_bh(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 0) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted + 1) == wanted) ++ return; ++ } ++ atomic_inc(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++static void mptcp_enable_static_key(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ atomic_inc(&mptcp_wanted); ++ static_key_enable(&mptcp_static_key); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_disable_static_key(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 1) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted - 1) == wanted) ++ return; ++ } ++ atomic_dec(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_dec(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_enable_sock(struct sock *sk) ++{ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ sock_set_flag(sk, SOCK_MPTCP); ++ tcp_sk(sk)->mptcp_ver = sysctl_mptcp_version; ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ ++ mptcp_enable_static_key(); ++ } ++} ++ ++void mptcp_disable_sock(struct sock *sk) ++{ ++ if (sock_flag(sk, SOCK_MPTCP)) { ++ sock_reset_flag(sk, SOCK_MPTCP); ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &ipv4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &ipv6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &ipv6_specific; ++#endif ++ ++ mptcp_disable_static_key(); ++ } ++} ++ ++void mptcp_connect_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_sk(sk); ++ } while (mptcp_reqsk_find_tk(tp->mptcp_loc_token) || ++ mptcp_find_token(tp->mptcp_loc_token)); ++ ++ __mptcp_hash_insert(tp, tp->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVE); ++} ++ ++/** ++ * This function increments the refcount of the mpcb struct. ++ * It is the responsibility of the caller to decrement when releasing ++ * the structure. ++ */ ++struct sock *mptcp_hash_find(const struct net *net, const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ struct sock *meta_sk = NULL; ++ const struct hlist_nulls_node *node; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], ++ tk_table) { ++ meta_sk = (struct sock *)meta_tp; ++ if (token == meta_tp->mptcp_loc_token && ++ net_eq(net, sock_net(meta_sk))) { ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ goto out; ++ if (unlikely(token != meta_tp->mptcp_loc_token || ++ !net_eq(net, sock_net(meta_sk)))) { ++ sock_gen_put(meta_sk); ++ goto begin; ++ } ++ goto found; ++ } ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++out: ++ meta_sk = NULL; ++found: ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return meta_sk; ++} ++EXPORT_SYMBOL_GPL(mptcp_hash_find); ++ ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) ++{ ++ /* remove from the token hashtable */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&meta_tp->tk_table); ++ meta_tp->inside_tk_table = 0; ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *rttsk = NULL, *lastsk = NULL; ++ u32 min_time = 0, last_active = 0; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 elapsed; ++ ++ if (!mptcp_sk_can_send_ack(sk) || tp->pf) ++ continue; ++ ++ elapsed = keepalive_time_elapsed(tp); ++ ++ /* We take the one with the lowest RTT within a reasonable ++ * (meta-RTO)-timeframe ++ */ ++ if (elapsed < inet_csk(meta_sk)->icsk_rto) { ++ if (!min_time || tp->srtt_us < min_time) { ++ min_time = tp->srtt_us; ++ rttsk = sk; ++ } ++ continue; ++ } ++ ++ /* Otherwise, we just take the most recent active */ ++ if (!rttsk && (!last_active || elapsed < last_active)) { ++ last_active = elapsed; ++ lastsk = sk; ++ } ++ } ++ ++ if (rttsk) ++ return rttsk; ++ ++ return lastsk; ++} ++EXPORT_SYMBOL(mptcp_select_ack_sock); ++ ++static void mptcp_sock_def_error_report(struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ if (tp->send_mp_fclose && sk->sk_err == ETIMEDOUT) { ++ /* Called by the keep alive timer (tcp_write_timeout), ++ * when the limit of fastclose retransmissions has been ++ * reached. Send a TCP RST to clear the status of any ++ * stateful firewall (typically conntrack) which are ++ * not aware of mptcp and cannot understand the ++ * fastclose option. ++ */ ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ } ++ } ++ ++ /* record this info that can be used by PM after the sf close */ ++ tp->mptcp->sk_err = sk->sk_err; ++ ++ if (!tp->tcp_disconnect && mptcp_in_infinite_mapping_weak(mpcb)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ meta_sk->sk_err = sk->sk_err; ++ meta_sk->sk_err_soft = sk->sk_err_soft; ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_error_report(meta_sk); ++ ++ WARN(meta_sk->sk_state == TCP_CLOSE, ++ "Meta already closed i_rcv %u i_snd %u send_i %u flags %#lx\n", ++ mpcb->infinite_mapping_rcv, mpcb->infinite_mapping_snd, ++ mpcb->send_infinite_mapping, meta_sk->sk_flags); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++ } ++ ++ sk->sk_err = 0; ++ return; ++} ++ ++void mptcp_mpcb_put(struct mptcp_cb *mpcb) ++{ ++ if (refcount_dec_and_test(&mpcb->mpcb_refcnt)) { ++ mptcp_cleanup_path_manager(mpcb); ++ mptcp_cleanup_scheduler(mpcb); ++ kfree(mpcb->master_info); ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ } ++} ++EXPORT_SYMBOL(mptcp_mpcb_put); ++ ++static void mptcp_mpcb_cleanup(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tw *mptw; ++ ++ /* The mpcb is disappearing - we can make the final ++ * update to the rcv_nxt of the time-wait-sock and remove ++ * its reference to the mpcb. ++ */ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ list_for_each_entry_rcu(mptw, &mpcb->tw_list, list) { ++ list_del_rcu(&mptw->list); ++ mptw->in_list = 0; ++ mptcp_mpcb_put(mpcb); ++ rcu_assign_pointer(mptw->mpcb, NULL); ++ } ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ mptcp_mpcb_put(mpcb); ++} ++ ++static void mptcp_sock_destruct(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!is_meta_sk(sk)) { ++ BUG_ON(!hlist_unhashed(&tp->mptcp->cb_list)); ++ ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ tp->mptcp = NULL; ++ ++ /* Taken when mpcb pointer was set */ ++ sock_put(mptcp_meta_sk(sk)); ++ mptcp_mpcb_put(tp->mpcb); ++ } else { ++ mptcp_debug("%s destroying meta-sk token %#x\n", __func__, ++ tcp_sk(sk)->mpcb->mptcp_loc_token); ++ ++ mptcp_mpcb_cleanup(tp->mpcb); ++ } ++ ++ WARN_ON(!static_key_false(&mptcp_static_key)); ++ ++ /* Must be called here, because this will decrement the jump-label. */ ++ inet_sock_destruct(sk); ++} ++ ++void mptcp_destroy_sock(struct sock *sk) ++{ ++ if (is_meta_sk(sk)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __skb_queue_purge(&tcp_sk(sk)->mpcb->reinject_queue); ++ ++ /* We have to close all remaining subflows. Normally, they ++ * should all be about to get closed. But, if the kernel is ++ * forcing a closure (e.g., tcp_write_err), the subflows might ++ * not have been closed properly (as we are waiting for the ++ * DATA_ACK of the DATA_FIN). ++ */ ++ mptcp_for_each_sub_safe(tcp_sk(sk)->mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ /* Already did call tcp_close - waiting for graceful ++ * closure, or if we are retransmitting fast-close on ++ * the subflow. The reset (or timeout) will kill the ++ * subflow.. ++ */ ++ if (tcp_sk(sk_it)->closing || ++ tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ ++ /* Allow the delayed work first to prevent time-wait state */ ++ if (delayed_work_pending(&tcp_sk(sk_it)->mptcp->work)) ++ continue; ++ ++ mptcp_sub_close(sk_it, 0); ++ } ++ } else { ++ mptcp_del_sock(sk); ++ } ++} ++ ++static void mptcp_set_state(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* Meta is not yet established - wake up the application */ ++ if ((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) && ++ sk->sk_state == TCP_ESTABLISHED) { ++ tcp_set_state(meta_sk, TCP_ESTABLISHED); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ sk_wake_async(meta_sk, SOCK_WAKE_IO, POLL_OUT); ++ } ++ ++ tcp_sk(meta_sk)->lsndtime = tcp_jiffies32; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) { ++ if (!sock_flag(sk, SOCK_DEAD)) ++ mptcp_sub_close(sk, 0); ++ } ++} ++ ++static int mptcp_set_congestion_control(struct sock *meta_sk, const char *name, ++ bool load, bool reinit, bool cap_net_admin) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ int err, result = 0; ++ ++ result = __tcp_set_congestion_control(meta_sk, name, load, reinit, cap_net_admin); ++ ++ tcp_sk(meta_sk)->mpcb->tcp_ca_explicit_set = true; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ err = __tcp_set_congestion_control(sk_it, name, load, reinit, cap_net_admin); ++ if (err) ++ result = err; ++ } ++ return result; ++} ++ ++static void mptcp_assign_congestion_control(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct inet_connection_sock *meta_icsk = inet_csk(mptcp_meta_sk(sk)); ++ const struct tcp_congestion_ops *ca = meta_icsk->icsk_ca_ops; ++ ++ /* Congestion control is the same as meta. Thus, it has been ++ * try_module_get'd by tcp_assign_congestion_control. ++ * Congestion control on meta was not explicitly configured by ++ * application, leave default or route based. ++ */ ++ if (icsk->icsk_ca_ops == ca || ++ !tcp_sk(mptcp_meta_sk(sk))->mpcb->tcp_ca_explicit_set) ++ return; ++ ++ /* Use the same congestion control as set on the meta-sk */ ++ if (!try_module_get(ca->owner)) { ++ /* This should never happen. The congestion control is linked ++ * to the meta-socket (through tcp_assign_congestion_control) ++ * who "holds" the refcnt on the module. ++ */ ++ WARN(1, "Could not get the congestion control!"); ++ return; ++ } ++ module_put(icsk->icsk_ca_ops->owner); ++ icsk->icsk_ca_ops = ca; ++ ++ /* Clear out private data before diag gets it and ++ * the ca has not been initialized. ++ */ ++ if (ca->get_info) ++ memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); ++ ++ return; ++} ++ ++siphash_key_t mptcp_secret __read_mostly; ++u32 mptcp_seed = 0; ++ ++static void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u32 mptcp_hashed_key[SHA_DIGEST_WORDS]; ++ u8 input[64]; ++ int i; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Initialize input with appropriate padding */ ++ memset(&input[9], 0, sizeof(input) - 10); /* -10, because the last byte ++ * is explicitly set too ++ */ ++ memcpy(input, &key, sizeof(key)); /* Copy key to the msg beginning */ ++ input[8] = 0x80; /* Padding: First bit after message = 1 */ ++ input[63] = 0x40; /* Padding: Length of the message = 64 bits */ ++ ++ sha_init(mptcp_hashed_key); ++ sha_transform(mptcp_hashed_key, input, workspace); ++ ++ for (i = 0; i < 5; i++) ++ mptcp_hashed_key[i] = (__force u32)cpu_to_be32(mptcp_hashed_key[i]); ++ ++ if (token) ++ *token = mptcp_hashed_key[0]; ++ if (idsn) ++ *idsn = ntohll(*((__be64 *)&mptcp_hashed_key[3])); ++} ++ ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u8 input[128]; /* 2 512-bit blocks */ ++ int i; ++ int index; ++ int length; ++ u8 *msg; ++ va_list list; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Generate key xored with ipad */ ++ memset(input, 0x36, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ va_start(list, arg_num); ++ index = 64; ++ for (i = 0; i < arg_num; i++) { ++ length = va_arg(list, int); ++ msg = va_arg(list, u8 *); ++ BUG_ON(index + length > 125); /* Message is too long */ ++ memcpy(&input[index], msg, length); ++ index += length; ++ } ++ va_end(list); ++ ++ input[index] = 0x80; /* Padding: First bit after message = 1 */ ++ memset(&input[index + 1], 0, (126 - index)); ++ ++ /* Padding: Length of the message = 512 + message length (bits) */ ++ input[126] = 0x02; ++ input[127] = ((index - 64) * 8); /* Message length (bits) */ ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = (__force u32)cpu_to_be32(hash_out[i]); ++ ++ /* Prepare second part of hmac */ ++ memset(input, 0x5C, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ memcpy(&input[64], hash_out, 20); ++ input[84] = 0x80; ++ memset(&input[85], 0, 41); ++ ++ /* Padding: Length of the message = 512 + 160 bits */ ++ input[126] = 0x02; ++ input[127] = 0xA0; ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = (__force u32)cpu_to_be32(hash_out[i]); ++} ++EXPORT_SYMBOL(mptcp_hmac_sha1); ++ ++static void mptcp_mpcb_inherit_sockopts(struct sock *meta_sk, struct sock *master_sk) ++{ ++ /* Socket-options handled by sk_clone_lock while creating the meta-sk. ++ * ====== ++ * SO_SNDBUF, SO_SNDBUFFORCE, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVLOWAT, ++ * SO_RCVTIMEO, SO_SNDTIMEO, SO_ATTACH_FILTER, SO_DETACH_FILTER, ++ * TCP_NODELAY, TCP_CORK ++ * ++ * Socket-options handled in this function here ++ * ====== ++ * TCP_DEFER_ACCEPT ++ * SO_KEEPALIVE ++ * ++ * Socket-options on the todo-list ++ * ====== ++ * SO_BINDTODEVICE - should probably prevent creation of new subsocks ++ * across other devices. - what about the api-draft? ++ * SO_DEBUG ++ * SO_REUSEADDR - probably we don't care about this ++ * SO_DONTROUTE, SO_BROADCAST ++ * SO_OOBINLINE ++ * SO_LINGER ++ * SO_TIMESTAMP* - I don't think this is of concern for a SOCK_STREAM ++ * SO_PASSSEC - I don't think this is of concern for a SOCK_STREAM ++ * SO_RXQ_OVFL ++ * TCP_COOKIE_TRANSACTIONS ++ * TCP_MAXSEG ++ * TCP_THIN_* - Handled by sk_clone_lock, but we need to support this ++ * in mptcp_meta_retransmit_timer. AND we need to check ++ * what is about the subsockets. ++ * TCP_LINGER2 ++ * TCP_WINDOW_CLAMP ++ * TCP_USER_TIMEOUT ++ * TCP_MD5SIG ++ * ++ * Socket-options of no concern for the meta-socket (but for the subsocket) ++ * ====== ++ * SO_PRIORITY ++ * SO_MARK ++ * TCP_CONGESTION ++ * TCP_SYNCNT ++ * TCP_QUICKACK ++ */ ++ ++ /* DEFER_ACCEPT should not be set on the meta, as we want to accept new subflows directly */ ++ inet_csk(meta_sk)->icsk_accept_queue.rskq_defer_accept = 0; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(meta_sk, SOCK_KEEPOPEN)) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ keepalive_time_when(tcp_sk(meta_sk))); ++ sock_reset_flag(master_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(master_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(master_sk)->recverr = 0; ++} ++ ++/* Called without holding lock on meta_sk */ ++static void mptcp_sub_inherit_sockopts(const struct sock *meta_sk, struct sock *sub_sk) ++{ ++ __u8 meta_tos; ++ ++ /* IP_TOS also goes to the subflow. */ ++ meta_tos = READ_ONCE(inet_sk(meta_sk)->tos); ++ if (inet_sk(sub_sk)->tos != meta_tos) { ++ inet_sk(sub_sk)->tos = meta_tos; ++ sub_sk->sk_priority = meta_sk->sk_priority; ++ sk_dst_reset(sub_sk); ++ } ++ ++ /* Inherit SO_REUSEADDR */ ++ sub_sk->sk_reuse = meta_sk->sk_reuse; ++ ++ /* Inherit SO_MARK: can be used for routing or filtering */ ++ sub_sk->sk_mark = meta_sk->sk_mark; ++ ++ /* Inherit snd/rcv-buffer locks */ ++ sub_sk->sk_userlocks = meta_sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; ++ ++ /* Nagle/Cork is forced off on the subflows. It is handled at the meta-layer */ ++ tcp_sk(sub_sk)->nonagle = TCP_NAGLE_OFF|TCP_NAGLE_PUSH; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(sub_sk, SOCK_KEEPOPEN)) { ++ sock_reset_flag(sub_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(sub_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(sub_sk)->recverr = 0; ++} ++ ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) ++{ ++ /* In case of success (in mptcp_backlog_rcv) and error (in kfree_skb) of ++ * sk_add_backlog, we will decrement the sk refcount. ++ */ ++ sock_hold(sk); ++ skb->sk = sk; ++ skb->destructor = sock_efree; ++} ++ ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ /* skb-sk may be NULL if we receive a packet immediatly after the ++ * SYN/ACK + MP_CAPABLE. ++ */ ++ struct sock *sk = skb->sk ? skb->sk : meta_sk; ++ int ret = 0; ++ ++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) { ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ /* Decrement sk refcnt when calling the skb destructor. ++ * Refcnt is incremented and skb destructor is set in tcp_v{4,6}_rcv via ++ * mptcp_prepare_for_backlog() here above. ++ */ ++ skb_orphan(skb); ++ ++ if (sk->sk_family == AF_INET) ++ ret = tcp_v4_do_rcv(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ ret = tcp_v6_do_rcv(sk, skb); ++#endif ++ ++ sock_put(sk); ++ return ret; ++} ++ ++static void mptcp_init_buffer_space(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int space; ++ ++ tcp_init_buffer_space(sk); ++ ++ if (is_master_tp(tp)) { ++ meta_tp->rcvq_space.space = meta_tp->rcv_wnd; ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->rcvq_space.time = meta_tp->tcp_mstamp; ++ meta_tp->rcvq_space.seq = meta_tp->copied_seq; ++ ++ /* If there is only one subflow, we just use regular TCP ++ * autotuning. User-locks are handled already by ++ * tcp_init_buffer_space ++ */ ++ meta_tp->window_clamp = tp->window_clamp; ++ meta_tp->rcv_ssthresh = tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = sk->sk_rcvbuf; ++ meta_sk->sk_sndbuf = sk->sk_sndbuf; ++ ++ return; ++ } ++ ++ if (meta_sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ goto snd_buf; ++ ++ /* Adding a new subflow to the rcv-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_rcvbuf + sk->sk_rcvbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_rmem[2]); ++ if (space > meta_sk->sk_rcvbuf) { ++ meta_tp->window_clamp += tp->window_clamp; ++ meta_tp->rcv_ssthresh += tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = space; ++ } ++ ++snd_buf: ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return; ++ ++ /* Adding a new subflow to the send-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_sndbuf + sk->sk_sndbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]); ++ if (space > meta_sk->sk_sndbuf) { ++ meta_sk->sk_sndbuf = space; ++ meta_sk->sk_write_space(meta_sk); ++ } ++} ++ ++struct lock_class_key meta_key; ++char *meta_key_name = "sk_lock-AF_INET-MPTCP"; ++struct lock_class_key meta_slock_key; ++char *meta_slock_key_name = "slock-AF_INET-MPTCP"; ++ ++static const struct tcp_sock_ops mptcp_meta_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = mptcp_send_fin, ++ .write_xmit = mptcp_write_xmit, ++ .send_active_reset = mptcp_send_active_reset, ++ .write_wakeup = mptcp_write_wakeup, ++ .retransmit_timer = mptcp_meta_retransmit_timer, ++ .time_wait = mptcp_time_wait, ++ .cleanup_rbuf = mptcp_cleanup_rbuf, ++ .set_cong_ctrl = mptcp_set_congestion_control, ++}; ++ ++static const struct tcp_sock_ops mptcp_sub_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = mptcp_sub_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ ++static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct mptcp_cb *mpcb; ++ struct sock *master_sk; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ struct tcp_sock *master_tp, *meta_tp = tcp_sk(meta_sk); ++ u64 snd_idsn, rcv_idsn; ++ ++ dst_release(meta_sk->sk_rx_dst); ++ meta_sk->sk_rx_dst = NULL; ++ /* This flag is set to announce sock_lock_init to ++ * reclassify the lock-class of the master socket. ++ */ ++ meta_tp->is_master_sk = 1; ++ master_sk = sk_clone_lock(meta_sk, GFP_ATOMIC | __GFP_ZERO); ++ meta_tp->is_master_sk = 0; ++ if (!master_sk) ++ goto err_alloc_master; ++ ++ master_tp = tcp_sk(master_sk); ++ master_tp->inside_tk_table = 0; ++ ++ mpcb = kmem_cache_zalloc(mptcp_cb_cache, GFP_ATOMIC); ++ if (!mpcb) ++ goto err_alloc_mpcb; ++ ++ /* Store the mptcp version agreed on initial handshake */ ++ mpcb->mptcp_ver = mptcp_ver; ++ ++ /* Store the keys and generate the peer's token */ ++ mpcb->mptcp_loc_key = meta_tp->mptcp_loc_key; ++ mpcb->mptcp_loc_token = meta_tp->mptcp_loc_token; ++ ++ /* Generate Initial data-sequence-numbers */ ++ mptcp_key_sha1(mpcb->mptcp_loc_key, NULL, &snd_idsn); ++ snd_idsn++; ++ mpcb->snd_high_order[0] = snd_idsn >> 32; ++ mpcb->snd_high_order[1] = mpcb->snd_high_order[0] - 1; ++ ++ mpcb->mptcp_rem_key = remote_key; ++ mptcp_key_sha1(mpcb->mptcp_rem_key, &mpcb->mptcp_rem_token, &rcv_idsn); ++ rcv_idsn++; ++ mpcb->rcv_high_order[0] = rcv_idsn >> 32; ++ mpcb->rcv_high_order[1] = mpcb->rcv_high_order[0] + 1; ++ ++ mpcb->meta_sk = meta_sk; ++ mpcb->master_sk = master_sk; ++ ++ skb_queue_head_init(&mpcb->reinject_queue); ++ mutex_init(&mpcb->mpcb_mutex); ++ ++ /* Init time-wait stuff */ ++ INIT_LIST_HEAD(&mpcb->tw_list); ++ ++ INIT_HLIST_HEAD(&mpcb->callback_list); ++ INIT_HLIST_HEAD(&mpcb->conn_list); ++ spin_lock_init(&mpcb->mpcb_list_lock); ++ ++ mpcb->orig_sk_rcvbuf = meta_sk->sk_rcvbuf; ++ mpcb->orig_sk_sndbuf = meta_sk->sk_sndbuf; ++ mpcb->orig_window_clamp = meta_tp->window_clamp; ++ ++ /* The meta is directly linked - set refcnt to 1 */ ++ refcount_set(&mpcb->mpcb_refcnt, 1); ++ ++ if (!meta_tp->inside_tk_table) { ++ /* Adding the meta_tp in the token hashtable - coming from server-side */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* With lockless listeners, we might process two ACKs at the ++ * same time. With TCP, inet_csk_complete_hashdance takes care ++ * of this. But, for MPTCP this would be too late if we add ++ * this MPTCP-socket in the token table (new subflows might ++ * come in and match on this socket here. ++ * So, we need to check if someone else already added the token ++ * and revert in that case. The other guy won the race... ++ */ ++ if (mptcp_find_token(mpcb->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ goto err_insert_token; ++ } ++ __mptcp_hash_insert(meta_tp, mpcb->mptcp_loc_token); ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_icsk->icsk_af_ops == &mptcp_v6_mapped) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ struct ipv6_txoptions *opt; ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ /* The following heavily inspired from tcp_v6_syn_recv_sock() */ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(master_sk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } ++ inet_csk(master_sk)->icsk_ext_hdr_len = 0; ++ if (opt) ++ inet_csk(master_sk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; ++ } ++#endif ++ ++ meta_tp->mptcp = NULL; ++ ++ meta_tp->write_seq = (u32)snd_idsn; ++ meta_tp->snd_sml = meta_tp->write_seq; ++ meta_tp->snd_una = meta_tp->write_seq; ++ meta_tp->snd_nxt = meta_tp->write_seq; ++ meta_tp->pushed_seq = meta_tp->write_seq; ++ meta_tp->snd_up = meta_tp->write_seq; ++ ++ meta_tp->copied_seq = (u32)rcv_idsn; ++ meta_tp->rcv_nxt = (u32)rcv_idsn; ++ meta_tp->rcv_wup = (u32)rcv_idsn; ++ ++ meta_tp->snd_wl1 = meta_tp->rcv_nxt - 1; ++ meta_tp->snd_wnd = window; ++ meta_tp->retrans_stamp = 0; /* Set in tcp_connect() */ ++ ++ meta_tp->packets_out = 0; ++ meta_icsk->icsk_probes_out = 0; ++ ++ rcu_assign_pointer(inet_sk(meta_sk)->inet_opt, NULL); ++ ++ /* Set mptcp-pointers */ ++ master_tp->mpcb = mpcb; ++ master_tp->meta_sk = meta_sk; ++ meta_tp->mpcb = mpcb; ++ meta_tp->meta_sk = meta_sk; ++ ++ /* Initialize the queues */ ++ master_tp->out_of_order_queue = RB_ROOT; ++ master_sk->tcp_rtx_queue = RB_ROOT; ++ INIT_LIST_HEAD(&master_tp->tsq_node); ++ INIT_LIST_HEAD(&master_tp->tsorted_sent_queue); ++ ++ master_sk->sk_tsq_flags = 0; ++ /* icsk_bind_hash inherited from the meta, but it will be properly set in ++ * mptcp_create_master_sk. Same operation is done in inet_csk_clone_lock. ++ */ ++ inet_csk(master_sk)->icsk_bind_hash = NULL; ++ ++ /* Init the accept_queue structure, we support a queue of 32 pending ++ * connections, it does not need to be huge, since we only store here ++ * pending subflow creations. ++ */ ++ reqsk_queue_alloc(&meta_icsk->icsk_accept_queue); ++ meta_sk->sk_max_ack_backlog = 32; ++ meta_sk->sk_ack_backlog = 0; ++ ++ if (!sock_flag(meta_sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(meta_sk, SOCK_MPTCP); ++ } ++ ++ /* Redefine function-pointers as the meta-sk is now fully ready */ ++ meta_tp->mpc = 1; ++ meta_tp->ops = &mptcp_meta_specific; ++ ++ meta_sk->sk_backlog_rcv = mptcp_backlog_rcv; ++ meta_sk->sk_destruct = mptcp_sock_destruct; ++ ++ /* Meta-level retransmit timer */ ++ meta_icsk->icsk_rto *= 2; /* Double of initial - rto */ ++ ++ tcp_init_xmit_timers(master_sk); ++ /* Has been set for sending out the SYN */ ++ inet_csk_clear_xmit_timer(meta_sk, ICSK_TIME_RETRANS); ++ ++ mptcp_mpcb_inherit_sockopts(meta_sk, master_sk); ++ ++ mptcp_init_path_manager(mpcb); ++ mptcp_init_scheduler(mpcb); ++ ++ if (!try_module_get(inet_csk(master_sk)->icsk_ca_ops->owner)) ++ tcp_assign_congestion_control(master_sk); ++ ++ master_tp->saved_syn = NULL; ++ ++ mptcp_debug("%s: created mpcb with token %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ return 0; ++ ++err_insert_token: ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ ++err_alloc_mpcb: ++ inet_sk(master_sk)->inet_opt = NULL; ++ master_sk->sk_state = TCP_CLOSE; ++ sock_orphan(master_sk); ++ bh_unlock_sock(master_sk); ++ sk_free(master_sk); ++ ++err_alloc_master: ++ return -ENOBUFS; ++} ++ ++/* Called without holding lock on mpcb */ ++static u8 mptcp_set_new_pathindex(struct mptcp_cb *mpcb) ++{ ++ int i; ++ ++ /* Start at 1, because 0 is reserved for the meta-sk */ ++ for (i = 1; i < sizeof(mpcb->path_index_bits) * 8; i++) { ++ if (!test_and_set_bit(i, &mpcb->path_index_bits)) ++ break; ++ } ++ ++ if (i == sizeof(mpcb->path_index_bits) * 8) ++ return 0; ++ return i; ++} ++ ++/* May be called without holding the meta-level lock */ ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tp->mptcp = kmem_cache_zalloc(mptcp_sock_cache, flags); ++ if (!tp->mptcp) ++ return -ENOMEM; ++ ++ tp->mptcp->path_index = mptcp_set_new_pathindex(mpcb); ++ /* No more space for more subflows? */ ++ if (!tp->mptcp->path_index) { ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ return -EPERM; ++ } ++ ++ INIT_HLIST_NODE(&tp->mptcp->cb_list); ++ ++ tp->mptcp->tp = tp; ++ tp->mpcb = mpcb; ++ tp->meta_sk = meta_sk; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(sk, SOCK_MPTCP); ++ } ++ ++ tp->mpc = 1; ++ tp->ops = &mptcp_sub_specific; ++ ++ tp->mptcp->loc_id = loc_id; ++ tp->mptcp->rem_id = rem_id; ++ if (mpcb->sched_ops->init) ++ mpcb->sched_ops->init(sk); ++ ++ /* The corresponding sock_put is in mptcp_sock_destruct(). It cannot be ++ * included in mptcp_del_sock(), because the mpcb must remain alive ++ * until the last subsocket is completely destroyed. ++ */ ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ hlist_add_head_rcu(&tp->mptcp->node, &mpcb->conn_list); ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ tp->mptcp->attached = 1; ++ ++ mptcp_sub_inherit_sockopts(meta_sk, sk); ++ INIT_DELAYED_WORK(&tp->mptcp->work, mptcp_sub_close_wq); ++ ++ /* Properly inherit CC from the meta-socket */ ++ mptcp_assign_congestion_control(sk); ++ ++ /* As we successfully allocated the mptcp_tcp_sock, we have to ++ * change the function-pointers here (for sk_destruct to work correctly) ++ */ ++ sk->sk_error_report = mptcp_sock_def_error_report; ++ sk->sk_data_ready = mptcp_data_ready; ++ sk->sk_write_space = mptcp_write_space; ++ sk->sk_state_change = mptcp_set_state; ++ sk->sk_destruct = mptcp_sock_destruct; ++ ++ if (sk->sk_family == AF_INET) ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI4:%d dst_addr:%pI4:%d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, ++ &((struct inet_sock *)tp)->inet_saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &((struct inet_sock *)tp)->inet_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI6:%d dst_addr:%pI6:%d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &inet6_sk(sk)->saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &sk->sk_v6_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport)); ++#endif ++ ++ return 0; ++} ++ ++void mptcp_del_sock(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb; ++ ++ if (!tp->mptcp || !tp->mptcp->attached) ++ return; ++ ++ mpcb = tp->mpcb; ++ ++ if (mpcb->sched_ops->release) ++ mpcb->sched_ops->release(sk); ++ ++ if (mpcb->pm_ops->delete_subflow) ++ mpcb->pm_ops->delete_subflow(sk); ++ ++ mptcp_debug("%s: Removing subsock tok %#x pi:%d state %d is_meta? %d\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ sk->sk_state, is_meta_sk(sk)); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ hlist_del_init_rcu(&tp->mptcp->node); ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ tp->mptcp->attached = 0; ++ mpcb->path_index_bits &= ~(1 << tp->mptcp->path_index); ++ ++ if (!tcp_write_queue_empty(sk) || !tcp_rtx_queue_empty(sk)) ++ mptcp_reinject_data(sk, 0); ++ ++ if (is_master_tp(tp)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (meta_tp->record_master_info && ++ !sock_flag(meta_sk, SOCK_DEAD)) { ++ mpcb->master_info = kmalloc(sizeof(*mpcb->master_info), ++ GFP_ATOMIC); ++ ++ if (mpcb->master_info) ++ tcp_get_info(sk, mpcb->master_info, true); ++ } ++ ++ mpcb->master_sk = NULL; ++ } else if (tp->mptcp->pre_established) { ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++} ++ ++/* Updates the MPTCP-session based on path-manager information (e.g., addresses, ++ * low-prio flows,...). ++ */ ++void mptcp_update_metasocket(const struct sock *meta_sk) ++{ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->new_session) ++ tcp_sk(meta_sk)->mpcb->pm_ops->new_session(meta_sk); ++} ++ ++/* Clean up the receive buffer for full frames taken by the user, ++ * then send an ACK if necessary. COPIED is the number of bytes ++ * tcp_recvmsg has given to the user so far, it speeds up the ++ * calculation of whether or not we must ACK for the sake of ++ * a window update. ++ * (inspired from tcp_cleanup_rbuf()) ++ */ ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ bool recheck_rcv_window = false; ++ struct mptcp_tcp_sock *mptcp; ++ __u32 rcv_window_now = 0; ++ ++ if (copied > 0 && !(meta_sk->sk_shutdown & RCV_SHUTDOWN)) { ++ rcv_window_now = tcp_receive_window(meta_tp); ++ ++ /* Optimize, __mptcp_select_window() is not cheap. */ ++ if (2 * rcv_window_now <= meta_tp->window_clamp) ++ recheck_rcv_window = true; ++ } ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (!mptcp_sk_can_send_ack(sk)) ++ continue; ++ ++ if (!inet_csk_ack_scheduled(sk)) ++ goto second_part; ++ /* Delayed ACKs frequently hit locked sockets during bulk ++ * receive. ++ */ ++ if (icsk->icsk_ack.blocked || ++ /* Once-per-two-segments ACK was not sent by tcp_input.c */ ++ tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || ++ /* If this read emptied read buffer, we send ACK, if ++ * connection is not bidirectional, user drained ++ * receive buffer and there was a small segment ++ * in queue. ++ */ ++ (copied > 0 && ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && ++ !icsk->icsk_ack.pingpong)) && ++ !atomic_read(&meta_sk->sk_rmem_alloc))) { ++ tcp_send_ack(sk); ++ continue; ++ } ++ ++second_part: ++ /* This here is the second part of tcp_cleanup_rbuf */ ++ if (recheck_rcv_window) { ++ __u32 new_window = tp->ops->__select_window(sk); ++ ++ /* Send ACK now, if this read freed lots of space ++ * in our buffer. Certainly, new_window is new window. ++ * We can advertise it now, if it is not less than ++ * current one. ++ * "Lots" means "at least twice" here. ++ */ ++ if (new_window && new_window >= 2 * rcv_window_now) ++ tcp_send_ack(sk); ++ } ++ } ++} ++ ++static int mptcp_sub_send_fin(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *skb = tcp_write_queue_tail(sk); ++ int mss_now; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = tcp_current_mss(sk); ++ ++ if (tcp_send_head(sk) != NULL) { ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ tp->write_seq++; ++ } else { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (!skb) ++ return 1; ++ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ skb_reserve(skb, MAX_TCP_HEADER); ++ /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ ++ tcp_init_nondata_skb(skb, tp->write_seq, ++ TCPHDR_ACK | TCPHDR_FIN); ++ tcp_queue_skb(sk, skb); ++ } ++ __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF); ++ ++ return 0; ++} ++ ++static void mptcp_sub_close_doit(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sock_flag(sk, SOCK_DEAD)) ++ return; ++ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) { ++ tp->closing = 1; ++ tcp_close(sk, 0); ++ } else if (tcp_close_state(sk)) { ++ sk->sk_shutdown |= SEND_SHUTDOWN; ++ tcp_send_fin(sk); ++ } ++} ++ ++void mptcp_sub_close_wq(struct work_struct *work) ++{ ++ struct tcp_sock *tp = container_of(work, struct mptcp_tcp_sock, work.work)->tp; ++ struct sock *sk = (struct sock *)tp; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_sub_close_doit(sk); ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(sk); ++} ++ ++void mptcp_sub_close(struct sock *sk, unsigned long delay) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct delayed_work *work = &tcp_sk(sk)->mptcp->work; ++ ++ /* We are already closing - e.g., call from sock_def_error_report upon ++ * tcp_disconnect in tcp_close. ++ */ ++ if (tp->closing) ++ return; ++ ++ /* Work already scheduled ? */ ++ if (work_pending(&work->work)) { ++ /* Work present - who will be first ? */ ++ if (jiffies + delay > work->timer.expires) ++ return; ++ ++ /* Try canceling - if it fails, work will be executed soon */ ++ if (!cancel_delayed_work(work)) ++ return; ++ sock_put(sk); ++ mptcp_mpcb_put(tp->mpcb); ++ } ++ ++ if (!delay) { ++ unsigned char old_state = sk->sk_state; ++ ++ /* We directly send the FIN. Because it may take so a long time, ++ * untile the work-queue will get scheduled... ++ * ++ * If mptcp_sub_send_fin returns 1, it failed and thus we reset ++ * the old state so that tcp_close will finally send the fin ++ * in user-context. ++ */ ++ if (!sk->sk_err && old_state != TCP_CLOSE && ++ tcp_close_state(sk) && mptcp_sub_send_fin(sk)) { ++ if (old_state == TCP_ESTABLISHED) ++ TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ sk->sk_state = old_state; ++ } ++ } ++ ++ sock_hold(sk); ++ refcount_inc(&tp->mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, work, delay); ++} ++ ++void mptcp_sub_force_close(struct sock *sk) ++{ ++ /* The below tcp_done may have freed the socket, if he is already dead. ++ * Thus, we are not allowed to access it afterwards. That's why ++ * we have to store the dead-state in this local variable. ++ */ ++ int sock_is_dead = sock_flag(sk, SOCK_DEAD); ++ ++ tcp_sk(sk)->mp_killed = 1; ++ ++ if (sk->sk_state != TCP_CLOSE) ++ tcp_done(sk); ++ ++ if (!sock_is_dead) ++ mptcp_sub_close(sk, 0); ++} ++EXPORT_SYMBOL(mptcp_sub_force_close); ++ ++/* Update the mpcb send window, based on the contributions ++ * of each subflow ++ */ ++void mptcp_update_sndbuf(const struct tcp_sock *tp) ++{ ++ struct sock *meta_sk = tp->meta_sk; ++ int new_sndbuf = 0, old_sndbuf = meta_sk->sk_sndbuf; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ new_sndbuf += sk->sk_sndbuf; ++ ++ if (new_sndbuf > sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2] || ++ new_sndbuf < 0) { ++ new_sndbuf = sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]; ++ break; ++ } ++ } ++ meta_sk->sk_sndbuf = max(min(new_sndbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]), ++ meta_sk->sk_sndbuf); ++ ++ /* The subflow's call to sk_write_space in tcp_new_space ends up in ++ * mptcp_write_space. ++ * It has nothing to do with waking up the application. ++ * So, we do it here. ++ */ ++ if (old_sndbuf != meta_sk->sk_sndbuf) ++ meta_sk->sk_write_space(meta_sk); ++} ++ ++/* Similar to: tcp_close */ ++void mptcp_close(struct sock *meta_sk, long timeout) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb; ++ int data_was_unread = 0; ++ int state; ++ ++ mptcp_debug("%s: Close of meta_sk with tok %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ WARN_ON(refcount_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (meta_tp->inside_tk_table) ++ /* Detach the mpcb from the token hashtable */ ++ mptcp_hash_remove_bh(meta_tp); ++ ++ meta_sk->sk_shutdown = SHUTDOWN_MASK; ++ /* We need to flush the recv. buffs. We do this only on the ++ * descriptor close, not protocol-sourced closes, because the ++ * reader process may not have drained the data yet! ++ */ ++ while ((skb = __skb_dequeue(&meta_sk->sk_receive_queue)) != NULL) { ++ u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ len--; ++ data_was_unread += len; ++ __kfree_skb(skb); ++ } ++ ++ sk_mem_reclaim(meta_sk); ++ ++ /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ ++ if (meta_sk->sk_state == TCP_CLOSE) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ mptcp_sub_close(sk_it, 0); ++ } ++ goto adjudge_to_death; ++ } ++ ++ if (data_was_unread) { ++ /* Unread data was tossed, zap the connection. */ ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONCLOSE); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ tcp_sk(meta_sk)->ops->send_active_reset(meta_sk, ++ meta_sk->sk_allocation); ++ } else if (sock_flag(meta_sk, SOCK_LINGER) && !meta_sk->sk_lingertime) { ++ /* Check zero linger _after_ checking for unread data. */ ++ meta_sk->sk_prot->disconnect(meta_sk, 0); ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ } else if (tcp_close_state(meta_sk)) { ++ mptcp_send_fin(meta_sk); ++ } else if (meta_tp->snd_una == meta_tp->write_seq) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ /* The DATA_FIN has been sent and acknowledged ++ * (e.g., by sk_shutdown). Close all the other subflows ++ */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ unsigned long delay = 0; ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer. - thus we add a delay ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ ++ sk_stream_wait_close(meta_sk, timeout); ++ ++adjudge_to_death: ++ state = meta_sk->sk_state; ++ sock_hold(meta_sk); ++ sock_orphan(meta_sk); ++ ++ /* socket will be freed after mptcp_close - we have to prevent ++ * access from the subflows. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ /* Similar to sock_orphan, but we don't set it DEAD, because ++ * the callbacks are still set and must be called. ++ */ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_set_socket(sk_it, NULL); ++ sk_it->sk_wq = NULL; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ ++ if (mpcb->pm_ops->close_session) ++ mpcb->pm_ops->close_session(meta_sk); ++ ++ /* It is the last release_sock in its life. It will remove backlog. */ ++ release_sock(meta_sk); ++ ++ /* Now socket is owned by kernel and we acquire BH lock ++ * to finish close. No need to check for user refs. ++ */ ++ local_bh_disable(); ++ bh_lock_sock(meta_sk); ++ WARN_ON(sock_owned_by_user(meta_sk)); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ /* Have we already been destroyed by a softirq or backlog? */ ++ if (state != TCP_CLOSE && meta_sk->sk_state == TCP_CLOSE) ++ goto out; ++ ++ /* This is a (useful) BSD violating of the RFC. There is a ++ * problem with TCP as specified in that the other end could ++ * keep a socket open forever with no application left this end. ++ * We use a 3 minute timeout (about the same as BSD) then kill ++ * our end. If they send after that then tough - BUT: long enough ++ * that we won't make the old 4*rto = almost no time - whoops ++ * reset mistake. ++ * ++ * Nope, it was not mistake. It is really desired behaviour ++ * f.e. on http servers, when such sockets are useless, but ++ * consume significant resources. Let's do it with special ++ * linger2 option. --ANK ++ */ ++ ++ if (meta_sk->sk_state == TCP_FIN_WAIT2) { ++ if (meta_tp->linger2 < 0) { ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONLINGER); ++ } else { ++ const int tmo = tcp_fin_time(meta_sk); ++ ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ tmo - TCP_TIMEWAIT_LEN); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, ++ tmo); ++ goto out; ++ } ++ } ++ } ++ if (meta_sk->sk_state != TCP_CLOSE) { ++ sk_mem_reclaim(meta_sk); ++ if (tcp_check_oom(meta_sk, 0)) { ++ if (net_ratelimit()) ++ pr_info("MPTCP: out of memory: force closing socket\n"); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONMEMORY); ++ } ++ } ++ ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ inet_csk_destroy_sock(meta_sk); ++ /* Otherwise, socket is reprieved until protocol close. */ ++ ++out: ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); /* Taken by sock_hold */ ++} ++ ++void mptcp_disconnect(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __skb_queue_purge(&meta_tp->mpcb->reinject_queue); ++ ++ if (meta_tp->inside_tk_table) ++ mptcp_hash_remove_bh(meta_tp); ++ ++ local_bh_disable(); ++ mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ ++ if (spin_is_locked(&subsk->sk_lock.slock)) ++ bh_unlock_sock(subsk); ++ ++ tcp_sk(subsk)->tcp_disconnect = 1; ++ ++ meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); ++ ++ sock_orphan(subsk); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ inet_csk_destroy_sock(subsk); ++ } ++ local_bh_enable(); ++ ++ mptcp_mpcb_cleanup(meta_tp->mpcb); ++ meta_tp->meta_sk = NULL; ++ ++ meta_tp->send_mp_fclose = 0; ++ meta_tp->mpc = 0; ++ meta_tp->ops = &tcp_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6) ++ meta_sk->sk_backlog_rcv = tcp_v6_do_rcv; ++ else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#endif ++ meta_sk->sk_destruct = inet_sock_destruct; ++} ++ ++ ++/* Returns True if we should enable MPTCP for that socket. */ ++bool mptcp_doit(struct sock *sk) ++{ ++ const struct dst_entry *dst = __sk_dst_get(sk); ++ ++ /* Don't do mptcp over loopback */ ++ if (sk->sk_family == AF_INET && ++ (ipv4_is_loopback(inet_sk(sk)->inet_daddr) || ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr))) ++ return false; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (sk->sk_family == AF_INET6 && ++ (ipv6_addr_loopback(&sk->sk_v6_daddr) || ++ ipv6_addr_loopback(&inet6_sk(sk)->saddr))) ++ return false; ++#endif ++ if (mptcp_v6_is_v4_mapped(sk) && ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr)) ++ return false; ++ ++#ifdef CONFIG_TCP_MD5SIG ++ /* If TCP_MD5SIG is enabled, do not do MPTCP - there is no Option-Space */ ++ if (tcp_sk(sk)->af_specific->md5_lookup(sk, sk)) ++ return false; ++#endif ++ ++ if (dst->dev && (dst->dev->flags & IFF_NOMULTIPATH)) ++ return false; ++ ++ return true; ++} ++ ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct tcp_sock *master_tp; ++ struct sock *master_sk; ++ ++ if (mptcp_alloc_mpcb(meta_sk, remote_key, mptcp_ver, window)) ++ goto err_alloc_mpcb; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ master_tp = tcp_sk(master_sk); ++ ++ if (mptcp_add_sock(meta_sk, master_sk, 0, 0, GFP_ATOMIC)) ++ goto err_add_sock; ++ ++ if (__inet_inherit_port(meta_sk, master_sk) < 0) ++ goto err_add_sock; ++ ++ meta_sk->sk_prot->unhash(meta_sk); ++ inet_ehash_nolisten(master_sk, NULL); ++ ++ master_tp->mptcp->init_rcv_wnd = master_tp->rcv_wnd; ++ ++ return 0; ++ ++err_add_sock: ++ inet_csk_prepare_forced_close(master_sk); ++ tcp_done(master_sk); ++ ++err_alloc_mpcb: ++ return -ENOBUFS; ++} ++ ++static int __mptcp_check_req_master(struct sock *child, ++ struct request_sock *req) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct sock *meta_sk = child; ++ struct mptcp_cb *mpcb; ++ struct mptcp_request_sock *mtreq; ++ ++ /* Never contained an MP_CAPABLE */ ++ if (!inet_rsk(req)->mptcp_rqsk) ++ return 1; ++ ++ if (!inet_rsk(req)->saw_mpc) { ++ /* Fallback to regular TCP, because we saw one SYN without ++ * MP_CAPABLE. In tcp_check_req we continue the regular path. ++ * But, the socket has been added to the reqsk_tk_htb, so we ++ * must still remove it. ++ */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); ++ mptcp_reqsk_remove_tk(req); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEACK); ++ ++ /* Just set this values to pass them to mptcp_alloc_mpcb */ ++ mtreq = mptcp_rsk(req); ++ child_tp->mptcp_loc_key = mtreq->mptcp_loc_key; ++ child_tp->mptcp_loc_token = mtreq->mptcp_loc_token; ++ ++ if (mptcp_create_master_sk(meta_sk, mtreq->mptcp_rem_key, ++ mtreq->mptcp_ver, child_tp->snd_wnd)) { ++ inet_csk_prepare_forced_close(meta_sk); ++ tcp_done(meta_sk); ++ ++ return -ENOBUFS; ++ } ++ ++ child = tcp_sk(child)->mpcb->master_sk; ++ child_tp = tcp_sk(child); ++ mpcb = child_tp->mpcb; ++ ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ ++ mpcb->dss_csum = mtreq->dss_csum; ++ mpcb->server_side = 1; ++ ++ /* Needs to be done here additionally, because when accepting a ++ * new connection we pass by __reqsk_free and not reqsk_free. ++ */ ++ mptcp_reqsk_remove_tk(req); ++ ++ /* Hold when creating the meta-sk in tcp_vX_syn_recv_sock. */ ++ sock_put(meta_sk); ++ ++ return 0; ++} ++ ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req) ++{ ++ struct sock *meta_sk = child, *master_sk; ++ struct sk_buff *skb; ++ u32 new_mapping; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ ++ /* We need to rewind copied_seq as it is set to IDSN + 1 and as we have ++ * pre-MPTCP data in the receive queue. ++ */ ++ tcp_sk(meta_sk)->copied_seq -= tcp_sk(master_sk)->rcv_nxt - ++ tcp_rsk(req)->rcv_isn - 1; ++ ++ /* Map subflow sequence number to data sequence numbers. We need to map ++ * these data to [IDSN - len - 1, IDSN[. ++ */ ++ new_mapping = tcp_sk(meta_sk)->copied_seq - tcp_rsk(req)->rcv_isn - 1; ++ ++ /* There should be only one skb: the SYN + data. */ ++ skb_queue_walk(&meta_sk->sk_receive_queue, skb) { ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* With fastopen we change the semantics of the relative subflow ++ * sequence numbers to deal with middleboxes that could add/remove ++ * multiple bytes in the SYN. We chose to start counting at rcv_nxt - 1 ++ * instead of the regular TCP ISN. ++ */ ++ tcp_sk(master_sk)->mptcp->rcv_isn = tcp_sk(master_sk)->rcv_nxt - 1; ++ ++ /* We need to update copied_seq of the master_sk to account for the ++ * already moved data to the meta receive queue. ++ */ ++ tcp_sk(master_sk)->copied_seq = tcp_sk(master_sk)->rcv_nxt; ++ ++ /* Handled by the master_sk */ ++ tcp_sk(meta_sk)->fastopen_rsk = NULL; ++ ++ return 0; ++} ++ ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop, u32 tsoff) ++{ ++ struct sock *meta_sk = child; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ child = tcp_sk(child)->mpcb->master_sk; ++ ++ sock_rps_save_rxhash(child, skb); ++ ++ /* drop indicates that we come from tcp_check_req and thus need to ++ * handle the request-socket fully. ++ */ ++ if (drop) { ++ tcp_synack_rtt_meas(child, req); ++ ++ inet_csk_reqsk_queue_drop(sk, req); ++ reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ return -1; ++ } ++ } else { ++ /* Thus, we come from syn-cookies */ ++ refcount_set(&req->rsk_refcnt, 1); ++ tcp_sk(meta_sk)->tsoffset = tsoff; ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ reqsk_put(req); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* May be called without holding the meta-level lock */ ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct tcp_sock *child_tp = tcp_sk(child); ++ u8 hash_mac_check[20]; ++ ++ if (!mopt->join_ack) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKFAIL); ++ goto teardown; ++ } ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce); ++ ++ if (memcmp(hash_mac_check, (char *)&mopt->mptcp_recv_mac, 20)) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKMAC); ++ goto teardown; ++ } ++ ++ /* Point it to the same struct socket and wq as the meta_sk */ ++ sk_set_socket(child, meta_sk->sk_socket); ++ child->sk_wq = meta_sk->sk_wq; ++ ++ if (mptcp_add_sock(meta_sk, child, mtreq->loc_id, mtreq->rem_id, GFP_ATOMIC)) { ++ /* Has been inherited, but now child_tp->mptcp is NULL */ ++ child_tp->mpc = 0; ++ child_tp->ops = &tcp_specific; ++ ++ /* TODO when we support acking the third ack for new subflows, ++ * we should silently discard this third ack, by returning NULL. ++ * ++ * Maybe, at the retransmission we will have enough memory to ++ * fully add the socket to the meta-sk. ++ */ ++ goto teardown; ++ } ++ ++ /* The child is a clone of the meta socket, we must now reset ++ * some of the fields ++ */ ++ child_tp->mptcp->rcv_low_prio = mtreq->rcv_low_prio; ++ ++ /* We should allow proper increase of the snd/rcv-buffers. Thus, we ++ * use the original values instead of the bloated up ones from the ++ * clone. ++ */ ++ child->sk_sndbuf = mpcb->orig_sk_sndbuf; ++ child->sk_rcvbuf = mpcb->orig_sk_rcvbuf; ++ ++ child_tp->mptcp->slave_sk = 1; ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ child_tp->mptcp->init_rcv_wnd = req->rsk_rcv_wnd; ++ ++ child->sk_tsq_flags = 0; ++ ++ sock_rps_save_rxhash(child, skb); ++ tcp_synack_rtt_meas(child, req); ++ ++ if (mpcb->pm_ops->established_subflow) ++ mpcb->pm_ops->established_subflow(child); ++ ++ /* Subflows do not use the accept queue, as they ++ * are attached immediately to the mpcb. ++ */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ ++ /* The refcnt is initialized to 2, because regular TCP will put him ++ * in the socket's listener queue. However, we do not have a listener-queue. ++ * So, we need to make sure that this request-sock indeed gets destroyed. ++ */ ++ reqsk_put(req); ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKRX); ++ return child; ++ ++teardown: ++ req->rsk_ops->send_reset(meta_sk, skb); ++ ++ /* Drop this request - sock creation failed. */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ inet_csk_prepare_forced_close(child); ++ tcp_done(child); ++ bh_unlock_sock(meta_sk); ++ return meta_sk; ++} ++ ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_tw *mptw; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* A subsocket in tw can only receive data. So, if we are in ++ * infinite-receive, then we should not reply with a data-ack or act ++ * upon general MPTCP-signaling. We prevent this by simply not creating ++ * the mptcp_tw_sock. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ tw->mptcp_tw = NULL; ++ return 0; ++ } ++ ++ /* Alloc MPTCP-tw-sock */ ++ mptw = kmem_cache_alloc(mptcp_tw_cache, GFP_ATOMIC); ++ if (!mptw) { ++ tw->mptcp_tw = NULL; ++ return -ENOBUFS; ++ } ++ ++ refcount_inc(&mpcb->mpcb_refcnt); ++ ++ tw->mptcp_tw = mptw; ++ mptw->loc_key = mpcb->mptcp_loc_key; ++ mptw->meta_tw = mpcb->in_time_wait; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ if (mptw->meta_tw && mpcb->mptw_state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ rcu_assign_pointer(mptw->mpcb, mpcb); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ list_add_rcu(&mptw->list, &tp->mpcb->tw_list); ++ mptw->in_list = 1; ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ return 0; ++} ++ ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_cb *mpcb; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ mpcb = rcu_dereference(tw->mptcp_tw->mpcb); ++ ++ /* If we are still holding a ref to the mpcb, we have to remove ourself ++ * from the list and drop the ref properly. ++ */ ++ if (mpcb && refcount_inc_not_zero(&mpcb->mpcb_refcnt)) { ++ spin_lock(&mpcb->mpcb_list_lock); ++ if (tw->mptcp_tw->in_list) { ++ list_del_rcu(&tw->mptcp_tw->list); ++ tw->mptcp_tw->in_list = 0; ++ /* Put, because we added it to the list */ ++ mptcp_mpcb_put(mpcb); ++ } ++ spin_unlock(&mpcb->mpcb_list_lock); ++ ++ /* Second time, because we increased it above */ ++ mptcp_mpcb_put(mpcb); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ kmem_cache_free(mptcp_tw_cache, tw->mptcp_tw); ++} ++ ++/* Updates the rcv_nxt of the time-wait-socks and allows them to ack a ++ * data-fin. ++ */ ++void mptcp_time_wait(struct sock *meta_sk, int state, int timeo) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tw *mptw; ++ ++ if (mptcp_in_infinite_mapping_weak(meta_tp->mpcb)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it->sk_state == TCP_CLOSE) ++ continue; ++ ++ tcp_sk(sk_it)->ops->time_wait(sk_it, state, timeo); ++ } ++ } ++ ++ /* Used for sockets that go into tw after the meta ++ * (see mptcp_init_tw_sock()) ++ */ ++ meta_tp->mpcb->in_time_wait = 1; ++ meta_tp->mpcb->mptw_state = state; ++ ++ /* Update the time-wait-sock's information */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ list_for_each_entry_rcu(mptw, &meta_tp->mpcb->tw_list, list) { ++ mptw->meta_tw = 1; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(meta_tp); ++ ++ /* We want to ack a DATA_FIN, but are yet in FIN_WAIT_2 - ++ * pretend as if the DATA_FIN has already reached us, that way ++ * the checks in tcp_timewait_state_process will be good as the ++ * DATA_FIN comes in. ++ */ ++ if (state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ } ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++} ++ ++void mptcp_tsq_flags(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* It will be handled as a regular deferred-call */ ++ if (is_meta_sk(sk)) ++ return; ++ ++ if (hlist_unhashed(&tp->mptcp->cb_list)) { ++ hlist_add_head(&tp->mptcp->cb_list, &tp->mpcb->callback_list); ++ /* We need to hold it here, as the sock_hold is not assured ++ * by the release_sock as it is done in regular TCP. ++ * ++ * The subsocket may get inet_csk_destroy'd while it is inside ++ * the callback_list. ++ */ ++ sock_hold(sk); ++ } ++ ++ if (!test_and_set_bit(MPTCP_SUB_DEFERRED, &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++} ++ ++void mptcp_tsq_sub_deferred(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __sock_put(meta_sk); ++ hlist_for_each_entry_safe(mptcp, tmp, &meta_tp->mpcb->callback_list, cb_list) { ++ struct tcp_sock *tp = mptcp->tp; ++ struct sock *sk = (struct sock *)tp; ++ ++ hlist_del_init(&mptcp->cb_list); ++ sk->sk_prot->release_cb(sk); ++ /* Final sock_put (cfr. mptcp_tsq_flags) */ ++ sock_put(sk); ++ } ++} ++ ++/* May be called without holding the meta-level lock */ ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct mptcp_options_received mopt; ++ u8 mptcp_hash_mac[20]; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->is_sub = 1; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ mtreq->mptcp_rem_nonce = mopt.mptcp_recv_nonce; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce); ++ mtreq->mptcp_hash_tmac = *(u64 *)mptcp_hash_mac; ++ ++ mtreq->rem_id = mopt.rem_id; ++ mtreq->rcv_low_prio = mopt.low_prio; ++ inet_rsk(req)->saw_mpc = 1; ++ ++ MPTCP_INC_STATS(sock_net(mpcb->meta_sk), MPTCP_MIB_JOINSYNRX); ++} ++ ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_options_received mopt; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->dss_csum = mopt.dss_csum; ++ ++ if (want_cookie) { ++ if (!mptcp_reqsk_new_cookie(req, sk, &mopt, skb)) ++ /* No key available - back to regular TCP */ ++ inet_rsk(req)->mptcp_rqsk = 0; ++ return; ++ } ++ ++ mptcp_reqsk_new_mptcp(req, sk, &mopt, skb); ++} ++ ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* Absolutely need to always initialize this. */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->mptcp_loc_key = mopt->mptcp_receiver_key; ++ ++ /* Generate the token */ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* Check, if the key is still free */ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) ++ goto out; ++ ++ inet_rsk(req)->saw_mpc = 1; ++ mtreq->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ mtreq->dss_csum = mopt->dss_csum; ++ ++out: ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb) ++{ ++ struct mptcp_options_received mopt; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ if (mopt.is_mp_join) ++ return mptcp_do_join_short(skb, &mopt, sock_net(sk)); ++ if (mopt.drop_me) ++ goto drop; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) ++ mopt.saw_mpc = 0; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ if (mopt.saw_mpc) { ++ if (skb_rtable(skb)->rt_flags & ++ (RTCF_BROADCAST | RTCF_MULTICAST)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_request_sock_ipv4_ops, ++ sk, skb); ++ } ++ ++ return tcp_v4_conn_request(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ if (mopt.saw_mpc) { ++ if (!ipv6_unicast_destination(skb)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_request_sock_ipv6_ops, ++ sk, skb); ++ } ++ ++ return tcp_v6_conn_request(sk, skb); ++#endif ++ } ++drop: ++ __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); ++ return 0; ++} ++ ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb) ++ __releases(&child->sk_lock.slock) ++{ ++ int ret; ++ ++ /* We don't call tcp_child_process here, because we hold ++ * already the meta-sk-lock and are sure that it is not owned ++ * by the user. ++ */ ++ tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ++ ret = tcp_rcv_state_process(child, skb); ++ bh_unlock_sock(child); ++ sock_put(child); ++ ++ return ret; ++} ++ ++static void __mptcp_get_info(const struct sock *meta_sk, ++ struct mptcp_meta_info *info) ++{ ++ const struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 now = tcp_jiffies32; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ info->mptcpi_state = meta_sk->sk_state; ++ info->mptcpi_retransmits = meta_icsk->icsk_retransmits; ++ info->mptcpi_probes = meta_icsk->icsk_probes_out; ++ info->mptcpi_backoff = meta_icsk->icsk_backoff; ++ ++ info->mptcpi_rto = jiffies_to_usecs(meta_icsk->icsk_rto); ++ ++ info->mptcpi_unacked = meta_tp->packets_out; ++ ++ info->mptcpi_last_data_sent = jiffies_to_msecs(now - meta_tp->lsndtime); ++ info->mptcpi_last_data_recv = jiffies_to_msecs(now - meta_icsk->icsk_ack.lrcvtime); ++ info->mptcpi_last_ack_recv = jiffies_to_msecs(now - meta_tp->rcv_tstamp); ++ ++ info->mptcpi_total_retrans = meta_tp->total_retrans; ++ ++ info->mptcpi_bytes_acked = meta_tp->bytes_acked; ++ info->mptcpi_bytes_received = meta_tp->bytes_received; ++} ++ ++static void mptcp_get_sub_info(struct sock *sk, struct mptcp_sub_info *info) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ ++ memset(info, 0, sizeof(*info)); ++ ++ if (sk->sk_family == AF_INET) { ++ info->src_v4.sin_family = AF_INET; ++ info->src_v4.sin_port = inet->inet_sport; ++ ++ info->src_v4.sin_addr.s_addr = inet->inet_rcv_saddr; ++ if (!info->src_v4.sin_addr.s_addr) ++ info->src_v4.sin_addr.s_addr = inet->inet_saddr; ++ ++ info->dst_v4.sin_family = AF_INET; ++ info->dst_v4.sin_port = inet->inet_dport; ++ info->dst_v4.sin_addr.s_addr = inet->inet_daddr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ info->src_v6.sin6_family = AF_INET6; ++ info->src_v6.sin6_port = inet->inet_sport; ++ ++ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) ++ info->src_v6.sin6_addr = np->saddr; ++ else ++ info->src_v6.sin6_addr = sk->sk_v6_rcv_saddr; ++ ++ info->dst_v6.sin6_family = AF_INET6; ++ info->dst_v6.sin6_port = inet->inet_dport; ++ info->dst_v6.sin6_addr = sk->sk_v6_daddr; ++#endif ++ } ++} ++ ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ struct mptcp_meta_info meta_info; ++ struct mptcp_info m_info; ++ ++ unsigned int info_len; ++ ++ /* Check again with the lock held */ ++ if (!mptcp(meta_tp)) ++ return -EINVAL; ++ ++ if (copy_from_user(&m_info, optval, optlen)) ++ return -EFAULT; ++ ++ if (m_info.meta_info) { ++ unsigned int len; ++ ++ __mptcp_get_info(meta_sk, &meta_info); ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ len = min_t(unsigned int, m_info.meta_len, sizeof(meta_info)); ++ m_info.meta_len = len; ++ ++ if (copy_to_user((void __user *)m_info.meta_info, &meta_info, len)) ++ return -EFAULT; ++ } ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ info_len = min_t(unsigned int, m_info.tcp_info_len, sizeof(struct tcp_info)); ++ m_info.tcp_info_len = info_len; ++ ++ if (m_info.initial) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (mpcb->master_sk) { ++ struct tcp_info info; ++ ++ tcp_get_info(mpcb->master_sk, &info, true); ++ if (copy_to_user((void __user *)m_info.initial, &info, info_len)) ++ return -EFAULT; ++ } else if (meta_tp->record_master_info && mpcb->master_info) { ++ if (copy_to_user((void __user *)m_info.initial, mpcb->master_info, info_len)) ++ return -EFAULT; ++ } else { ++ return meta_tp->record_master_info ? -ENOMEM : -EINVAL; ++ } ++ } ++ ++ if (m_info.subflows) { ++ unsigned int len, sub_len = 0; ++ struct mptcp_tcp_sock *mptcp; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflows; ++ len = m_info.sub_len; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct tcp_info t_info; ++ unsigned int tmp_len; ++ ++ tcp_get_info(mptcp_to_sock(mptcp), &t_info, true); ++ ++ tmp_len = min_t(unsigned int, len, info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &t_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ sub_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.sub_len = sub_len; ++ } ++ ++ if (m_info.subflow_info) { ++ unsigned int len, sub_info_len, total_sub_info_len = 0; ++ struct mptcp_tcp_sock *mptcp; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflow_info; ++ len = m_info.total_sub_info_len; ++ ++ sub_info_len = min_t(unsigned int, m_info.sub_info_len, ++ sizeof(struct mptcp_sub_info)); ++ m_info.sub_info_len = sub_info_len; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct mptcp_sub_info m_sub_info; ++ unsigned int tmp_len; ++ ++ mptcp_get_sub_info(mptcp_to_sock(mptcp), &m_sub_info); ++ ++ tmp_len = min_t(unsigned int, len, sub_info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &m_sub_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ total_sub_info_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.total_sub_info_len = total_sub_info_len; ++ } ++ ++ if (copy_to_user(optval, &m_info, optlen)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++void mptcp_clear_sk(struct sock *sk, int size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* we do not want to clear tk_table field, because of RCU lookups */ ++ sk_prot_clear_nulls(sk, offsetof(struct tcp_sock, tk_table.next)); ++ ++ size -= offsetof(struct tcp_sock, tk_table.pprev); ++ memset((char *)&tp->tk_table.pprev, 0, size); ++} ++ ++static const struct snmp_mib mptcp_snmp_list[] = { ++ SNMP_MIB_ITEM("MPCapableSYNRX", MPTCP_MIB_MPCAPABLEPASSIVE), ++ SNMP_MIB_ITEM("MPCapableSYNTX", MPTCP_MIB_MPCAPABLEACTIVE), ++ SNMP_MIB_ITEM("MPCapableSYNACKRX", MPTCP_MIB_MPCAPABLEACTIVEACK), ++ SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK), ++ SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableRetransFallback", MPTCP_MIB_MPCAPABLERETRANSFALLBACK), ++ SNMP_MIB_ITEM("MPTCPCsumEnabled", MPTCP_MIB_CSUMENABLED), ++ SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), ++ SNMP_MIB_ITEM("MPFailRX", MPTCP_MIB_MPFAILRX), ++ SNMP_MIB_ITEM("MPCsumFail", MPTCP_MIB_CSUMFAIL), ++ SNMP_MIB_ITEM("MPFastcloseRX", MPTCP_MIB_FASTCLOSERX), ++ SNMP_MIB_ITEM("MPFastcloseTX", MPTCP_MIB_FASTCLOSETX), ++ SNMP_MIB_ITEM("MPFallbackAckSub", MPTCP_MIB_FBACKSUB), ++ SNMP_MIB_ITEM("MPFallbackAckInit", MPTCP_MIB_FBACKINIT), ++ SNMP_MIB_ITEM("MPFallbackDataSub", MPTCP_MIB_FBDATASUB), ++ SNMP_MIB_ITEM("MPFallbackDataInit", MPTCP_MIB_FBDATAINIT), ++ SNMP_MIB_ITEM("MPRemoveAddrSubDelete", MPTCP_MIB_REMADDRSUB), ++ SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), ++ SNMP_MIB_ITEM("MPJoinAlreadyFallenback", MPTCP_MIB_JOINFALLBACK), ++ SNMP_MIB_ITEM("MPJoinSynTx", MPTCP_MIB_JOINSYNTX), ++ SNMP_MIB_ITEM("MPJoinSynRx", MPTCP_MIB_JOINSYNRX), ++ SNMP_MIB_ITEM("MPJoinSynAckRx", MPTCP_MIB_JOINSYNACKRX), ++ SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX), ++ SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckMissing", MPTCP_MIB_JOINACKFAIL), ++ SNMP_MIB_ITEM("MPJoinAckRTO", MPTCP_MIB_JOINACKRTO), ++ SNMP_MIB_ITEM("MPJoinAckRexmit", MPTCP_MIB_JOINACKRXMIT), ++ SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), ++ SNMP_MIB_ITEM("DSSNotMatching", MPTCP_MIB_DSSNOMATCH), ++ SNMP_MIB_ITEM("InfiniteMapRx", MPTCP_MIB_INFINITEMAPRX), ++ SNMP_MIB_ITEM("DSSNoMatchTCP", MPTCP_MIB_DSSTCPMISMATCH), ++ SNMP_MIB_ITEM("DSSTrimHead", MPTCP_MIB_DSSTRIMHEAD), ++ SNMP_MIB_ITEM("DSSSplitTail", MPTCP_MIB_DSSSPLITTAIL), ++ SNMP_MIB_ITEM("DSSPurgeOldSubSegs", MPTCP_MIB_PURGEOLD), ++ SNMP_MIB_ITEM("AddAddrRx", MPTCP_MIB_ADDADDRRX), ++ SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), ++ SNMP_MIB_ITEM("RemAddrRx", MPTCP_MIB_REMADDRRX), ++ SNMP_MIB_ITEM("RemAddrTx", MPTCP_MIB_REMADDRTX), ++ SNMP_MIB_SENTINEL ++}; ++ ++struct workqueue_struct *mptcp_wq; ++EXPORT_SYMBOL(mptcp_wq); ++ ++/* Output /proc/net/mptcp */ ++static int mptcp_pm_seq_show(struct seq_file *seq, void *v) ++{ ++ struct tcp_sock *meta_tp; ++ const struct net *net = seq->private; ++ int i, n = 0; ++ ++ seq_printf(seq, " sl loc_tok rem_tok v6 local_address remote_address st ns tx_queue rx_queue inode"); ++ seq_putc(seq, '\n'); ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ struct hlist_nulls_node *node; ++ rcu_read_lock(); ++ local_bh_disable(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &tk_hashtable[i], tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp; ++ struct inet_sock *isk = inet_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (!mptcp(meta_tp) || !net_eq(net, sock_net(meta_sk))) ++ continue; ++ ++ if (!mpcb) ++ continue; ++ ++ if (capable(CAP_NET_ADMIN)) { ++ seq_printf(seq, "%4d: %04X %04X ", n++, ++ mpcb->mptcp_loc_token, ++ mpcb->mptcp_rem_token); ++ } else { ++ seq_printf(seq, "%4d: %04X %04X ", n++, -1, -1); ++ } ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ seq_printf(seq, " 0 %08X:%04X %08X:%04X ", ++ isk->inet_rcv_saddr, ++ ntohs(isk->inet_sport), ++ isk->inet_daddr, ++ ntohs(isk->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct in6_addr *src = &meta_sk->sk_v6_rcv_saddr; ++ struct in6_addr *dst = &meta_sk->sk_v6_daddr; ++ seq_printf(seq, " 1 %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X", ++ src->s6_addr32[0], src->s6_addr32[1], ++ src->s6_addr32[2], src->s6_addr32[3], ++ ntohs(isk->inet_sport), ++ dst->s6_addr32[0], dst->s6_addr32[1], ++ dst->s6_addr32[2], dst->s6_addr32[3], ++ ntohs(isk->inet_dport)); ++#endif ++ } ++ ++ seq_printf(seq, " %02X %02X %08X:%08X %lu", ++ meta_sk->sk_state, mptcp_subflow_count(mpcb), ++ meta_tp->write_seq - meta_tp->snd_una, ++ max_t(int, meta_tp->rcv_nxt - ++ meta_tp->copied_seq, 0), ++ sock_i_ino(meta_sk)); ++ seq_putc(seq, '\n'); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++ return 0; ++} ++ ++static int mptcp_snmp_seq_show(struct seq_file *seq, void *v) ++{ ++ struct net *net = seq->private; ++ int i; ++ ++ for (i = 0; mptcp_snmp_list[i].name != NULL; i++) ++ seq_printf(seq, "%-32s\t%ld\n", mptcp_snmp_list[i].name, ++ snmp_fold_field(net->mptcp.mptcp_statistics, ++ mptcp_snmp_list[i].entry)); ++ ++ return 0; ++} ++ ++static int mptcp_pm_init_net(struct net *net) ++{ ++ net->mptcp.mptcp_statistics = alloc_percpu(struct mptcp_mib); ++ if (!net->mptcp.mptcp_statistics) ++ goto out_mptcp_mibs; ++ ++#ifdef CONFIG_PROC_FS ++ net->mptcp.proc_net_mptcp = proc_net_mkdir(net, "mptcp_net", net->proc_net); ++ if (!net->mptcp.proc_net_mptcp) ++ goto out_proc_net_mptcp; ++ if (!proc_create_net_single("mptcp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ mptcp_pm_seq_show, NULL)) ++ goto out_mptcp_net_mptcp; ++ if (!proc_create_net_single("snmp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ mptcp_snmp_seq_show, NULL)) ++ goto out_mptcp_net_snmp; ++#endif ++ ++ return 0; ++ ++#ifdef CONFIG_PROC_FS ++out_mptcp_net_snmp: ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++out_mptcp_net_mptcp: ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ net->mptcp.proc_net_mptcp = NULL; ++out_proc_net_mptcp: ++ free_percpu(net->mptcp.mptcp_statistics); ++#endif ++out_mptcp_mibs: ++ return -ENOMEM; ++} ++ ++static void mptcp_pm_exit_net(struct net *net) ++{ ++ remove_proc_entry("snmp", net->mptcp.proc_net_mptcp); ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ free_percpu(net->mptcp.mptcp_statistics); ++} ++ ++static struct pernet_operations mptcp_pm_proc_ops = { ++ .init = mptcp_pm_init_net, ++ .exit = mptcp_pm_exit_net, ++}; ++ ++/* General initialization of mptcp */ ++void __init mptcp_init(void) ++{ ++ int i; ++ struct ctl_table_header *mptcp_sysctl; ++ ++ mptcp_sock_cache = kmem_cache_create("mptcp_sock", ++ sizeof(struct mptcp_tcp_sock), ++ 0, SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_sock_cache) ++ goto mptcp_sock_cache_failed; ++ ++ mptcp_cb_cache = kmem_cache_create("mptcp_cb", sizeof(struct mptcp_cb), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_cb_cache) ++ goto mptcp_cb_cache_failed; ++ ++ mptcp_tw_cache = kmem_cache_create("mptcp_tw", sizeof(struct mptcp_tw), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_tw_cache) ++ goto mptcp_tw_cache_failed; ++ ++ get_random_bytes(&mptcp_secret, sizeof(mptcp_secret)); ++ ++ mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8); ++ if (!mptcp_wq) ++ goto alloc_workqueue_failed; ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ INIT_HLIST_NULLS_HEAD(&tk_hashtable[i], i); ++ INIT_HLIST_NULLS_HEAD(&mptcp_reqsk_tk_htb[i], i); ++ } ++ ++ spin_lock_init(&mptcp_tk_hashlock); ++ ++ if (register_pernet_subsys(&mptcp_pm_proc_ops)) ++ goto pernet_failed; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_pm_v6_init()) ++ goto mptcp_pm_v6_failed; ++#endif ++ if (mptcp_pm_v4_init()) ++ goto mptcp_pm_v4_failed; ++ ++ mptcp_sysctl = register_net_sysctl(&init_net, "net/mptcp", mptcp_table); ++ if (!mptcp_sysctl) ++ goto register_sysctl_failed; ++ ++ if (mptcp_register_path_manager(&mptcp_pm_default)) ++ goto register_pm_failed; ++ ++ if (mptcp_register_scheduler(&mptcp_sched_default)) ++ goto register_sched_failed; ++ ++ pr_info("MPTCP: Stable release v0.95"); ++ ++ mptcp_init_failed = false; ++ ++ return; ++ ++register_sched_failed: ++ mptcp_unregister_path_manager(&mptcp_pm_default); ++register_pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl); ++register_sysctl_failed: ++ mptcp_pm_v4_undo(); ++mptcp_pm_v4_failed: ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_pm_v6_undo(); ++mptcp_pm_v6_failed: ++#endif ++ unregister_pernet_subsys(&mptcp_pm_proc_ops); ++pernet_failed: ++ destroy_workqueue(mptcp_wq); ++alloc_workqueue_failed: ++ kmem_cache_destroy(mptcp_tw_cache); ++mptcp_tw_cache_failed: ++ kmem_cache_destroy(mptcp_cb_cache); ++mptcp_cb_cache_failed: ++ kmem_cache_destroy(mptcp_sock_cache); ++mptcp_sock_cache_failed: ++ mptcp_init_failed = true; ++} +diff -aurN linux-4.19.104/net/mptcp/mptcp_fullmesh.c mptcp-mptcp_v0.95/net/mptcp/mptcp_fullmesh.c +--- linux-4.19.104/net/mptcp/mptcp_fullmesh.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_fullmesh.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,1941 @@ ++#include ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++ ++enum { ++ MPTCP_EVENT_ADD = 1, ++ MPTCP_EVENT_DEL, ++ MPTCP_EVENT_MOD, ++}; ++ ++#define MPTCP_SUBFLOW_RETRY_DELAY 1000 ++ ++/* Max number of local or remote addresses we can store. ++ * When changing, see the bitfield below in fullmesh_rem4/6. ++ */ ++#define MPTCP_MAX_ADDR 8 ++ ++struct fullmesh_rem4 { ++ u8 rem4_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct fullmesh_rem6 { ++ u8 rem6_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_loc_addr { ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ u8 loc4_bits; ++ u8 next_v4_index; ++ ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++ u8 loc6_bits; ++ u8 next_v6_index; ++ struct rcu_head rcu; ++}; ++ ++struct mptcp_addr_event { ++ struct list_head list; ++ unsigned short family; ++ u8 code:7, ++ low_prio:1; ++ int if_idx; ++ union inet_addr addr; ++}; ++ ++struct fullmesh_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ /* Delayed worker, when the routing-tables are not yet ready. */ ++ struct delayed_work subflow_retry_work; ++ ++ /* Remote addresses */ ++ struct fullmesh_rem4 remaddr4[MPTCP_MAX_ADDR]; ++ struct fullmesh_rem6 remaddr6[MPTCP_MAX_ADDR]; ++ ++ struct mptcp_cb *mpcb; ++ ++ u16 remove_addrs; /* Addresses to remove */ ++ u8 announced_addrs_v4; /* IPv4 Addresses we did announce */ ++ u8 announced_addrs_v6; /* IPv6 Addresses we did announce */ ++ ++ u8 add_addr; /* Are we sending an add_addr? */ ++ ++ u8 rem4_bits; ++ u8 rem6_bits; ++ ++ /* Have we established the additional subflows for primary pair? */ ++ u8 first_pair:1; ++}; ++ ++struct mptcp_fm_ns { ++ struct mptcp_loc_addr __rcu *local; ++ spinlock_t local_lock; /* Protecting the above pointer */ ++ struct list_head events; ++ struct delayed_work address_worker; ++ ++ struct net *net; ++}; ++ ++static int num_subflows __read_mostly = 1; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per pair of IP addresses of MPTCP connection"); ++ ++static int create_on_err __read_mostly; ++module_param(create_on_err, int, 0644); ++MODULE_PARM_DESC(create_on_err, "recreate the subflow upon a timeout"); ++ ++static struct mptcp_pm_ops full_mesh __read_mostly; ++ ++static void full_mesh_create_subflows(struct sock *meta_sk); ++ ++static struct mptcp_fm_ns *fm_get_ns(const struct net *net) ++{ ++ return (struct mptcp_fm_ns *)net->mptcp.path_managers[MPTCP_PM_FULLMESH]; ++} ++ ++static struct fullmesh_priv *fullmesh_get_priv(const struct mptcp_cb *mpcb) ++{ ++ return (struct fullmesh_priv *)&mpcb->mptcp_pm[0]; ++} ++ ++/* Find the first free index in the bitfield */ ++static int __mptcp_find_free_index(u8 bitfield, u8 base) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ goto exit; ++ ++ i = ffs(~(bitfield >> base)) - 1; ++ if (i < 0) ++ goto exit; ++ ++ /* No free bits when starting at base, try from 0 on */ ++ if (i + base >= sizeof(bitfield) * 8) ++ return __mptcp_find_free_index(bitfield, 0); ++ ++ return i + base; ++exit: ++ return -1; ++} ++ ++static int mptcp_find_free_index(u8 bitfield) ++{ ++ return __mptcp_find_free_index(bitfield, 0); ++} ++ ++static void mptcp_addv4_raddr(struct mptcp_cb *mpcb, ++ const struct in_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem4 *rem4; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem4->rem4_id == id && ++ rem4->addr.s_addr == addr->s_addr && rem4->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem4->rem4_id == id && rem4->addr.s_addr != addr->s_addr) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr:%pI4 to addr %pI4 with id:%d\n", ++ __func__, &rem4->addr.s_addr, ++ &addr->s_addr, id); ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem4_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI4\n", ++ __func__, MPTCP_MAX_ADDR, &addr->s_addr); ++ return; ++ } ++ ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is not known yet, store it */ ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ rem4->bitfield = 0; ++ rem4->retry_bitfield = 0; ++ rem4->rem4_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem4_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_addv6_raddr(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem6 *rem6; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem6->rem6_id == id && ++ ipv6_addr_equal(&rem6->addr, addr) && rem6->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem6->rem6_id == id) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr: %pI6 to addr %pI6 with id:%d\n", ++ __func__, &rem6->addr, addr, id); ++ rem6->addr = *addr; ++ rem6->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem6_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI6\n", ++ __func__, MPTCP_MAX_ADDR, addr); ++ return; ++ } ++ ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is not known yet, store it */ ++ rem6->addr = *addr; ++ rem6->port = port; ++ rem6->bitfield = 0; ++ rem6->retry_bitfield = 0; ++ rem6->rem6_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem6_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_v4_rem_raddress(struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].rem4_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem4_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++static void mptcp_v6_rem_raddress(const struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (fmp->remaddr6[i].rem6_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem6_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v4_set_init_addr_bit(const struct mptcp_cb *mpcb, ++ const struct in_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].addr.s_addr == addr->s_addr) { ++ fmp->remaddr4[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v6_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (ipv6_addr_equal(&fmp->remaddr6[i].addr, addr)) { ++ fmp->remaddr6[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++static void mptcp_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_v4_set_init_addr_bit(mpcb, &addr->in, id); ++ else ++ mptcp_v6_set_init_addr_bit(mpcb, &addr->in6, id); ++} ++ ++static void mptcp_v4_subflows(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init4_subsockets(meta_sk, loc, rem); ++} ++ ++#if IS_ENABLED(CONFIG_IPV6) ++static void mptcp_v6_subflows(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init6_subsockets(meta_sk, loc, rem); ++} ++#endif ++ ++static void retry_subflow_worker(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct fullmesh_priv *fmp = container_of(delayed_work, ++ struct fullmesh_priv, ++ subflow_retry_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem = &fmp->remaddr4[i]; ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], &rem4); ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem = &fmp->remaddr6[i]; ++ ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], &rem6); ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ struct fullmesh_priv *fmp = container_of(work, struct fullmesh_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, retry = 0; ++ int i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD) || !mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ /* Create the additional subflows for the first pair */ ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_v4_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ iter++; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr4[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc4_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], ++ &rem4) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_v6_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr6[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc6_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], ++ &rem6) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++ if (retry && !delayed_work_pending(&fmp->subflow_retry_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, &fmp->subflow_retry_work, ++ msecs_to_jiffies(MPTCP_SUBFLOW_RETRY_DELAY)); ++ } ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void announce_remove_addr(u8 addr_id, struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct sock *sk = mptcp_select_ack_sock(meta_sk); ++ ++ fmp->remove_addrs |= (1 << addr_id); ++ mpcb->addr_signal = 1; ++ ++ if (sk) ++ tcp_send_ack(sk); ++} ++ ++static void update_addr_bitfields(struct sock *meta_sk, ++ const struct mptcp_loc_addr *mptcp_local) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ int i; ++ ++ /* The bits in announced_addrs_* always match with loc*_bits. So, a ++ * simple & operation unsets the correct bits, because these go from ++ * announced to non-announced ++ */ ++ fmp->announced_addrs_v4 &= mptcp_local->loc4_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ fmp->remaddr4[i].bitfield &= mptcp_local->loc4_bits; ++ fmp->remaddr4[i].retry_bitfield &= mptcp_local->loc4_bits; ++ } ++ ++ fmp->announced_addrs_v6 &= mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ fmp->remaddr6[i].bitfield &= mptcp_local->loc6_bits; ++ fmp->remaddr6[i].retry_bitfield &= mptcp_local->loc6_bits; ++ } ++} ++ ++static int mptcp_find_address(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, const union inet_addr *addr, ++ int if_idx) ++{ ++ int i; ++ u8 loc_bits; ++ bool found = false; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ mptcp_local->locaddr4[i].addr.s_addr == addr->in.s_addr) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&mptcp_local->locaddr6[i].addr, ++ &addr->in6)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static int mptcp_find_address_transp(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, int if_idx) ++{ ++ bool found = false; ++ u8 loc_bits; ++ int i; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static void mptcp_address_worker(struct work_struct *work) ++{ ++ const struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct mptcp_fm_ns *fm_ns = container_of(delayed_work, ++ struct mptcp_fm_ns, ++ address_worker); ++ struct net *net = fm_ns->net; ++ struct mptcp_addr_event *event = NULL; ++ struct mptcp_loc_addr *mptcp_local, *old; ++ int i, id = -1; /* id is used in the socket-code on a delete-event */ ++ bool success; /* Used to indicate if we succeeded handling the event */ ++ ++next_event: ++ success = false; ++ kfree(event); ++ ++ /* First, let's dequeue an event from our event-list */ ++ rcu_read_lock_bh(); ++ spin_lock(&fm_ns->local_lock); ++ ++ event = list_first_entry_or_null(&fm_ns->events, ++ struct mptcp_addr_event, list); ++ if (!event) { ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ return; ++ } ++ ++ list_del(&event->list); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ id = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ ++ /* Not in the list - so we don't care */ ++ if (id < 0) { ++ mptcp_debug("%s could not find id\n", __func__); ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) ++ mptcp_local->loc4_bits &= ~(1 << id); ++ else ++ mptcp_local->loc6_bits &= ~(1 << id); ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } else { ++ int i = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ int j = i; ++ ++ if (j < 0) { ++ /* Not in the list, so we have to find an empty slot */ ++ if (event->family == AF_INET) ++ i = __mptcp_find_free_index(mptcp_local->loc4_bits, ++ mptcp_local->next_v4_index); ++ if (event->family == AF_INET6) ++ i = __mptcp_find_free_index(mptcp_local->loc6_bits, ++ mptcp_local->next_v6_index); ++ ++ if (i < 0) { ++ mptcp_debug("%s no more space\n", __func__); ++ goto duno; ++ } ++ ++ /* It might have been a MOD-event. */ ++ event->code = MPTCP_EVENT_ADD; ++ } else { ++ /* Let's check if anything changes */ ++ if (event->family == AF_INET && ++ event->low_prio == mptcp_local->locaddr4[i].low_prio) ++ goto duno; ++ ++ if (event->family == AF_INET6 && ++ event->low_prio == mptcp_local->locaddr6[i].low_prio) ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) { ++ mptcp_local->locaddr4[i].addr.s_addr = event->addr.in.s_addr; ++ mptcp_local->locaddr4[i].loc4_id = i + 1; ++ mptcp_local->locaddr4[i].low_prio = event->low_prio; ++ mptcp_local->locaddr4[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI4 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in.s_addr, ++ event->if_idx, event->low_prio, i + 1); ++ } else { ++ mptcp_local->locaddr6[i].addr = event->addr.in6; ++ mptcp_local->locaddr6[i].loc6_id = i + MPTCP_MAX_ADDR; ++ mptcp_local->locaddr6[i].low_prio = event->low_prio; ++ mptcp_local->locaddr6[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI6 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in6, ++ event->if_idx, event->low_prio, i + MPTCP_MAX_ADDR); ++ } ++ ++ if (j < 0) { ++ if (event->family == AF_INET) { ++ mptcp_local->loc4_bits |= (1 << i); ++ mptcp_local->next_v4_index = i + 1; ++ } else { ++ mptcp_local->loc6_bits |= (1 << i); ++ mptcp_local->next_v6_index = i + 1; ++ } ++ } ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } ++ success = true; ++ ++duno: ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ ++ if (!success) ++ goto next_event; ++ ++ /* Now we iterate over the MPTCP-sockets and apply the event. */ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ const struct hlist_nulls_node *node; ++ struct tcp_sock *meta_tp; ++ ++ rcu_read_lock_bh(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[i], ++ tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp, *sk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_cb *mpcb; ++ ++ if (sock_net(meta_sk) != net) ++ continue; ++ ++ if (meta_v4) { ++ /* skip IPv6 events if meta is IPv4 */ ++ if (event->family == AF_INET6) ++ continue; ++ } else if (event->family == AF_INET && meta_sk->sk_ipv6only) { ++ /* skip IPv4 events if IPV6_V6ONLY is set */ ++ continue; ++ } ++ ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ continue; ++ ++ bh_lock_sock(meta_sk); ++ ++ mpcb = meta_tp->mpcb; ++ if (!mpcb) ++ goto next; ++ ++ if (!mptcp(meta_tp) || !is_meta_sk(meta_sk) || ++ mptcp_in_infinite_mapping_weak(mpcb)) ++ goto next; ++ ++ /* May be that the pm has changed in-between */ ++ if (mpcb->pm_ops != &full_mesh) ++ goto next; ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (!test_and_set_bit(MPTCP_PATH_MANAGER_DEFERRED, ++ &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++ ++ goto next; ++ } ++ ++ if (event->code == MPTCP_EVENT_ADD) { ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ ++ full_mesh_create_subflows(meta_sk); ++ } ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ struct mptcp_tcp_sock *mptcp; ++ struct mptcp_loc_addr *mptcp_local; ++ struct hlist_node *tmp; ++ bool found = false; ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ /* In any case, we need to update our bitfields */ ++ if (id >= 0) ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ /* Look for the socket and remove him */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if ((event->family == AF_INET6 && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk))) || ++ (event->family == AF_INET && ++ (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)))) ++ continue; ++ ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr != event->addr.in.s_addr) ++ continue; ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) ++ continue; ++ ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ /* We announce the removal of this id */ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ found = true; ++ } ++ ++ if (found) ++ goto next; ++ ++ /* The id may have been given by the event, ++ * matching on a local address. And it may not ++ * have matched on one of the above sockets, ++ * because the client never created a subflow. ++ * So, we have to finally remove it here. ++ */ ++ if (id >= 0) { ++ u8 loc_id = id ++ + (event->family == AF_INET ? 1 : MPTCP_MAX_ADDR); ++ announce_remove_addr(loc_id, meta_sk); ++ } ++ } ++ ++ if (event->code == MPTCP_EVENT_MOD) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr == event->addr.in.s_addr) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ } ++ } ++next: ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); ++ } ++ rcu_read_unlock_bh(); ++ } ++ goto next_event; ++} ++ ++static struct mptcp_addr_event *lookup_similar_event(const struct net *net, ++ const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ list_for_each_entry(eventq, &fm_ns->events, list) { ++ if (eventq->family != event->family) ++ continue; ++ if (eventq->if_idx != event->if_idx) ++ continue; ++ if (event->family == AF_INET) { ++ if (eventq->addr.in.s_addr == event->addr.in.s_addr) ++ return eventq; ++ } else { ++ if (ipv6_addr_equal(&eventq->addr.in6, &event->addr.in6)) ++ return eventq; ++ } ++ } ++ return NULL; ++} ++ ++/* We already hold the net-namespace MPTCP-lock */ ++static void add_pm_event(struct net *net, const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq = lookup_similar_event(net, event); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ if (eventq) { ++ switch (event->code) { ++ case MPTCP_EVENT_DEL: ++ mptcp_debug("%s del old_code %u\n", __func__, eventq->code); ++ list_del(&eventq->list); ++ kfree(eventq); ++ break; ++ case MPTCP_EVENT_ADD: ++ mptcp_debug("%s add old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_ADD; ++ return; ++ case MPTCP_EVENT_MOD: ++ mptcp_debug("%s mod old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_MOD; ++ return; ++ } ++ } ++ ++ /* OK, we have to add the new address to the wait queue */ ++ eventq = kmemdup(event, sizeof(struct mptcp_addr_event), GFP_ATOMIC); ++ if (!eventq) ++ return; ++ ++ list_add_tail(&eventq->list, &fm_ns->events); ++ ++ /* Create work-queue */ ++ if (!delayed_work_pending(&fm_ns->address_worker)) ++ queue_delayed_work(mptcp_wq, &fm_ns->address_worker, ++ msecs_to_jiffies(500)); ++} ++ ++static void addr4_event_handler(const struct in_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->ifa_dev->dev; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->ifa_scope > RT_SCOPE_LINK || ++ ipv4_is_loopback(ifa->ifa_local)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET; ++ mpevent.addr.in.s_addr = ifa->ifa_local; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI4, code %u prio %u idx %u\n", __func__, ++ &ifa->ifa_local, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv4-addr add/rem-events */ ++static int mptcp_pm_inetaddr_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ const struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net *net = dev_net(ifa->ifa_dev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr4_event_handler(ifa, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_inetaddr_notifier = { ++ .notifier_call = mptcp_pm_inetaddr_event, ++}; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr); ++ ++static void addr6_event_handler(const struct inet6_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->idev->dev; ++ int addr_type = ipv6_addr_type(&ifa->addr); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->scope > RT_SCOPE_LINK || ++ addr_type == IPV6_ADDR_ANY || ++ (addr_type & IPV6_ADDR_LOOPBACK) || ++ (addr_type & IPV6_ADDR_LINKLOCAL)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET6; ++ mpevent.addr.in6 = ifa->addr; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI6, code %u prio %u idx %u\n", __func__, ++ &ifa->addr, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv6-addr add/rem-events */ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ struct inet6_ifaddr *ifa6 = (struct inet6_ifaddr *)ptr; ++ struct net *net = dev_net(ifa6->idev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr6_event_handler(ifa6, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block inet6_addr_notifier = { ++ .notifier_call = inet6_addr_event, ++}; ++ ++#endif ++ ++/* React on ifup/down-events */ ++static int netdev_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ const struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct in_device *in_dev; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct inet6_dev *in6_dev; ++#endif ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ rcu_read_lock(); ++ in_dev = __in_dev_get_rtnl(dev); ++ ++ if (in_dev) { ++ for_ifa(in_dev) { ++ mptcp_pm_inetaddr_event(NULL, event, ifa); ++ } endfor_ifa(in_dev); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ in6_dev = __in6_dev_get(dev); ++ ++ if (in6_dev) { ++ struct inet6_ifaddr *ifa6; ++ list_for_each_entry(ifa6, &in6_dev->addr_list, if_list) ++ inet6_addr_event(NULL, event, ifa6); ++ } ++#endif ++ ++ rcu_read_unlock(); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_netdev_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++static void full_mesh_add_raddr(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_addv4_raddr(mpcb, &addr->in, port, id); ++ else ++ mptcp_addv6_raddr(mpcb, &addr->in6, port, id); ++} ++ ++static void full_mesh_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct tcp_sock *master_tp = tcp_sk(mpcb->master_sk); ++ int i, index, if_idx = 0; ++ union inet_addr saddr, daddr; ++ sa_family_t family = AF_INET; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ /* Init local variables necessary for the rest */ ++ if (meta_sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(meta_sk)) { ++ saddr.ip = inet_sk(meta_sk)->inet_saddr; ++ daddr.ip = inet_sk(meta_sk)->inet_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ saddr.in6 = inet6_sk(meta_sk)->saddr; ++ daddr.in6 = meta_sk->sk_v6_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET6; ++#endif ++ } ++ ++ if (inet_sk(meta_sk)->transparent) ++ if_idx = inet_sk(meta_sk)->rx_dst_ifindex; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (inet_sk(meta_sk)->transparent) ++ index = mptcp_find_address_transp(mptcp_local, family, if_idx); ++ else ++ index = mptcp_find_address(mptcp_local, family, &saddr, if_idx); ++ if (index < 0) ++ goto fallback; ++ ++ if (family == AF_INET) ++ master_tp->mptcp->low_prio = mptcp_local->locaddr4[index].low_prio; ++ else ++ master_tp->mptcp->low_prio = mptcp_local->locaddr6[index].low_prio; ++ master_tp->mptcp->send_mp_prio = master_tp->mptcp->low_prio; ++ ++ full_mesh_add_raddr(mpcb, &daddr, family, 0, 0); ++ mptcp_set_init_addr_bit(mpcb, &daddr, family, index); ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ INIT_DELAYED_WORK(&fmp->subflow_retry_work, retry_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* Look for the address among the local addresses */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ __be32 ifa_address = mptcp_local->locaddr4[i].addr.s_addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ saddr.ip == ifa_address) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto skip_ipv6; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ const struct in6_addr *ifa6 = &mptcp_local->locaddr6[i].addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&saddr.in6, ifa6)) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv6: ++#endif ++ ++ rcu_read_unlock_bh(); ++ ++ if (family == AF_INET) ++ fmp->announced_addrs_v4 |= (1 << index); ++ else ++ fmp->announced_addrs_v6 |= (1 << index); ++ ++ for (i = fmp->add_addr; i && fmp->add_addr; i--) ++ tcp_send_ack(mpcb->master_sk); ++ ++ if (master_tp->mptcp->send_mp_prio) ++ tcp_send_ack(mpcb->master_sk); ++ ++ return; ++ ++fallback: ++ rcu_read_unlock_bh(); ++ mptcp_fallback_default(mpcb); ++ return; ++} ++ ++static void full_mesh_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ return; ++ ++ if (!work_pending(&fmp->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &fmp->subflow_work); ++ } ++} ++ ++/* Called upon release_sock, if the socket was owned by the user during ++ * a path-management event. ++ */ ++static void full_mesh_release_sock(struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ int i; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* First, detect modifications or additions */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct in_addr ifa = mptcp_local->locaddr4[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (inet_sk(sk)->inet_saddr != ifa.s_addr) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr4[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr4[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ struct sock *sk; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto removal; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct in6_addr ifa = mptcp_local->locaddr6[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (!ipv6_addr_equal(&inet6_sk(sk)->saddr, &ifa)) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr6[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr6[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ struct sock *sk; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++removal: ++#endif ++ ++ /* Now, detect address-removals */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ bool shall_remove = true; ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ if (inet_sk(sk)->inet_saddr == mptcp_local->locaddr4[i].addr.s_addr) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } else { ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ if (ipv6_addr_equal(&inet6_sk(sk)->saddr, &mptcp_local->locaddr6[i].addr)) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } ++ ++ if (shall_remove) { ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, ++ meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ } ++ } ++ ++ /* Just call it optimistically. It actually cannot do any harm */ ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ rcu_read_unlock_bh(); ++} ++ ++static int full_mesh_get_local_id(const struct sock *meta_sk, ++ sa_family_t family, union inet_addr *addr, ++ bool *low_prio) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int index, id = -1; ++ ++ /* Handle the backup-flows */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ index = mptcp_find_address(mptcp_local, family, addr, 0); ++ ++ if (index != -1) { ++ if (family == AF_INET) { ++ id = mptcp_local->locaddr4[index].loc4_id; ++ *low_prio = mptcp_local->locaddr4[index].low_prio; ++ } else { ++ id = mptcp_local->locaddr6[index].loc6_id; ++ *low_prio = mptcp_local->locaddr6[index].low_prio; ++ } ++ } ++ ++ ++ rcu_read_unlock_bh(); ++ ++ return id; ++} ++ ++static void full_mesh_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ int remove_addr_len; ++ u8 unannouncedv4 = 0, unannouncedv6 = 0; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ mpcb->addr_signal = 0; ++ ++ if (likely(!fmp->add_addr)) ++ goto remove_addr; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* IPv4 */ ++ unannouncedv4 = (~fmp->announced_addrs_v4) & mptcp_local->loc4_bits; ++ if (unannouncedv4 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv4); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = mptcp_local->locaddr4[ind].loc4_id; ++ opts->add_addr4.addr = mptcp_local->locaddr4[ind].addr; ++ opts->add_addr_v4 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, ++ 4, (u8 *)&opts->add_addr4.addr.s_addr); ++ opts->add_addr4.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v4 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++ ++ goto skip_ipv6; ++ } ++ ++ if (meta_v4) ++ goto skip_ipv6; ++skip_ipv4: ++ /* IPv6 */ ++ unannouncedv6 = (~fmp->announced_addrs_v6) & mptcp_local->loc6_bits; ++ if (unannouncedv6 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv6); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = mptcp_local->locaddr6[ind].loc6_id; ++ opts->add_addr6.addr = mptcp_local->locaddr6[ind].addr; ++ opts->add_addr_v6 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, ++ 16, (u8 *)&opts->add_addr6.addr.s6_addr); ++ opts->add_addr6.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v6 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++ } ++ ++skip_ipv6: ++ rcu_read_unlock_bh(); ++ ++ if (!unannouncedv4 && !unannouncedv6 && skb) ++ fmp->add_addr--; ++ ++remove_addr: ++ if (likely(!fmp->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(fmp->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = fmp->remove_addrs; ++ *size += remove_addr_len; ++ if (skb) ++ fmp->remove_addrs = 0; ++ ++exit: ++ mpcb->addr_signal = !!(fmp->add_addr || fmp->remove_addrs); ++} ++ ++static void full_mesh_rem_raddr(struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ mptcp_v4_rem_raddress(mpcb, rem_id); ++ mptcp_v6_rem_raddress(mpcb, rem_id); ++} ++ ++static void full_mesh_delete_subflow(struct sock *sk) ++{ ++ struct fullmesh_priv *fmp = fullmesh_get_priv(tcp_sk(sk)->mpcb); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_loc_addr *mptcp_local; ++ int index, i; ++ ++ if (!create_on_err) ++ return; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ return; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ union inet_addr saddr; ++ ++ saddr.ip = inet_sk(sk)->inet_saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem4 = &fmp->remaddr4[i]; ++ ++ if (rem4->addr.s_addr != sk->sk_daddr) ++ continue; ++ ++ if (rem4->port && rem4->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem4->bitfield &= ~(1 << index); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ union inet_addr saddr; ++ ++ saddr.in6 = inet6_sk(sk)->saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET6, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem6 = &fmp->remaddr6[i]; ++ ++ if (!ipv6_addr_equal(&rem6->addr, &sk->sk_v6_daddr)) ++ continue; ++ ++ if (rem6->port && rem6->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem6->bitfield &= ~(1 << index); ++ } ++#endif ++ } ++ ++out: ++ rcu_read_unlock_bh(); ++ ++ /* re-schedule the creation of failed subflows */ ++ if (tcp_sk(sk)->mptcp->sk_err == ETIMEDOUT || sk->sk_err == ETIMEDOUT) ++ full_mesh_create_subflows(meta_sk); ++} ++ ++/* Output /proc/net/mptcp_fullmesh */ ++static int mptcp_fm_seq_show(struct seq_file *seq, void *v) ++{ ++ const struct net *net = seq->private; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int i; ++ ++ seq_printf(seq, "Index, Address-ID, Backup, IP-address, if-idx\n"); ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ seq_printf(seq, "IPv4, next v4-index: %u\n", mptcp_local->next_v4_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct mptcp_loc4 *loc4 = &mptcp_local->locaddr4[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI4 %u\n", i, loc4->loc4_id, ++ loc4->low_prio, &loc4->addr, loc4->if_idx); ++ } ++ ++ seq_printf(seq, "IPv6, next v6-index: %u\n", mptcp_local->next_v6_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct mptcp_loc6 *loc6 = &mptcp_local->locaddr6[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI6 %u\n", i, loc6->loc6_id, ++ loc6->low_prio, &loc6->addr, loc6->if_idx); ++ } ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static int mptcp_fm_init_net(struct net *net) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns; ++ int err = 0; ++ ++ fm_ns = kzalloc(sizeof(*fm_ns), GFP_KERNEL); ++ if (!fm_ns) ++ return -ENOBUFS; ++ ++ mptcp_local = kzalloc(sizeof(*mptcp_local), GFP_KERNEL); ++ if (!mptcp_local) { ++ err = -ENOBUFS; ++ goto err_mptcp_local; ++ } ++ ++ if (!proc_create_net_single("mptcp_fullmesh", S_IRUGO, net->proc_net, ++ mptcp_fm_seq_show, NULL)) { ++ err = -ENOMEM; ++ goto err_seq_fops; ++ } ++ ++ mptcp_local->next_v4_index = 1; ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ INIT_DELAYED_WORK(&fm_ns->address_worker, mptcp_address_worker); ++ INIT_LIST_HEAD(&fm_ns->events); ++ spin_lock_init(&fm_ns->local_lock); ++ fm_ns->net = net; ++ net->mptcp.path_managers[MPTCP_PM_FULLMESH] = fm_ns; ++ ++ return 0; ++err_seq_fops: ++ kfree(mptcp_local); ++err_mptcp_local: ++ kfree(fm_ns); ++ return err; ++} ++ ++static void mptcp_fm_exit_net(struct net *net) ++{ ++ struct mptcp_addr_event *eventq, *tmp; ++ struct mptcp_fm_ns *fm_ns; ++ struct mptcp_loc_addr *mptcp_local; ++ ++ fm_ns = fm_get_ns(net); ++ cancel_delayed_work_sync(&fm_ns->address_worker); ++ ++ rcu_read_lock_bh(); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ kfree_rcu(mptcp_local, rcu); ++ ++ spin_lock(&fm_ns->local_lock); ++ list_for_each_entry_safe(eventq, tmp, &fm_ns->events, list) { ++ list_del(&eventq->list); ++ kfree(eventq); ++ } ++ spin_unlock(&fm_ns->local_lock); ++ ++ rcu_read_unlock_bh(); ++ ++ remove_proc_entry("mptcp_fullmesh", net->proc_net); ++ ++ kfree(fm_ns); ++} ++ ++static struct pernet_operations full_mesh_net_ops = { ++ .init = mptcp_fm_init_net, ++ .exit = mptcp_fm_exit_net, ++}; ++ ++static struct mptcp_pm_ops full_mesh __read_mostly = { ++ .new_session = full_mesh_new_session, ++ .release_sock = full_mesh_release_sock, ++ .fully_established = full_mesh_create_subflows, ++ .new_remote_address = full_mesh_create_subflows, ++ .get_local_id = full_mesh_get_local_id, ++ .addr_signal = full_mesh_addr_signal, ++ .add_raddr = full_mesh_add_raddr, ++ .rem_raddr = full_mesh_rem_raddr, ++ .delete_subflow = full_mesh_delete_subflow, ++ .name = "fullmesh", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init full_mesh_register(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct fullmesh_priv) > MPTCP_PM_SIZE); ++ ++ ret = register_pernet_subsys(&full_mesh_net_ops); ++ if (ret) ++ goto out; ++ ++ ret = register_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ if (ret) ++ goto err_reg_inetaddr; ++ ret = register_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ if (ret) ++ goto err_reg_netdev; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ret = register_inet6addr_notifier(&inet6_addr_notifier); ++ if (ret) ++ goto err_reg_inet6addr; ++#endif ++ ++ ret = mptcp_register_path_manager(&full_mesh); ++ if (ret) ++ goto err_reg_pm; ++ ++out: ++ return ret; ++ ++ ++err_reg_pm: ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++err_reg_inet6addr: ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++err_reg_netdev: ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++err_reg_inetaddr: ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ goto out; ++} ++ ++static void full_mesh_unregister(void) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ mptcp_unregister_path_manager(&full_mesh); ++} ++ ++module_init(full_mesh_register); ++module_exit(full_mesh_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Full-Mesh MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_input.c mptcp-mptcp_v0.95/net/mptcp/mptcp_input.c +--- linux-4.19.104/net/mptcp/mptcp_input.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_input.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,2431 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++/* is seq1 < seq2 ? */ ++static inline bool before64(const u64 seq1, const u64 seq2) ++{ ++ return (s64)(seq1 - seq2) < 0; ++} ++ ++/* is seq1 > seq2 ? */ ++#define after64(seq1, seq2) before64(seq2, seq1) ++ ++static inline void mptcp_become_fully_estab(struct sock *sk) ++{ ++ tcp_sk(sk)->mptcp->fully_established = 1; ++ ++ if (is_master_tp(tcp_sk(sk)) && ++ tcp_sk(sk)->mpcb->pm_ops->fully_established) ++ tcp_sk(sk)->mpcb->pm_ops->fully_established(mptcp_meta_sk(sk)); ++} ++ ++/* Similar to tcp_tso_acked without any memory accounting */ ++static inline int mptcp_tso_acked_reinject(const struct sock *meta_sk, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 packets_acked, len, delta_truesize; ++ ++ BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)); ++ ++ packets_acked = tcp_skb_pcount(skb); ++ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ return 0; ++ ++ len = meta_tp->snd_una - TCP_SKB_CB(skb)->seq; ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq += len; ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ ++ if (delta_truesize) ++ skb->truesize -= delta_truesize; ++ ++ /* Any change of skb->len requires recalculation of tso factor. */ ++ if (tcp_skb_pcount(skb) > 1) ++ tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); ++ packets_acked -= tcp_skb_pcount(skb); ++ ++ if (packets_acked) { ++ BUG_ON(tcp_skb_pcount(skb) == 0); ++ BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); ++ } ++ ++ return packets_acked; ++} ++ ++/* Cleans the meta-socket retransmission queue and the reinject-queue. */ ++static void mptcp_clean_rtx_queue(struct sock *meta_sk, u32 prior_snd_una) ++{ ++ struct sk_buff *skb, *tmp, *next; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ bool acked = false; ++ u32 acked_pcount; ++ ++ for (skb = skb_rb_first(&meta_sk->tcp_rtx_queue); skb; skb = next) { ++ bool fully_acked = true; ++ ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ acked_pcount = tcp_tso_acked(meta_sk, skb); ++ if (!acked_pcount) ++ break; ++ ++ fully_acked = false; ++ } else { ++ acked_pcount = tcp_skb_pcount(skb); ++ } ++ ++ acked = true; ++ meta_tp->packets_out -= acked_pcount; ++ meta_tp->retrans_stamp = 0; ++ ++ if (!fully_acked) ++ break; ++ ++ next = skb_rb_next(skb); ++ ++ if (mptcp_is_data_fin(skb)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ /* DATA_FIN has been acknowledged - now we can close ++ * the subflows ++ */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ unsigned long delay = 0; ++ ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer - thus we add a delay. ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ tcp_rtx_queue_unlink_and_free(skb, meta_sk); ++ } ++ /* Remove acknowledged data from the reinject queue */ ++ skb_queue_walk_safe(&mpcb->reinject_queue, skb, tmp) { ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ mptcp_tso_acked_reinject(meta_sk, skb); ++ break; ++ } ++ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ } ++ ++ if (likely(between(meta_tp->snd_up, prior_snd_una, meta_tp->snd_una))) ++ meta_tp->snd_up = meta_tp->snd_una; ++ ++ if (acked) { ++ tcp_rearm_rto(meta_sk); ++ /* Normally this is done in tcp_try_undo_loss - but MPTCP ++ * does not call this function. ++ */ ++ inet_csk(meta_sk)->icsk_retransmits = 0; ++ } ++} ++ ++/* Inspired by tcp_rcv_state_process */ ++static int mptcp_rcv_state_process(struct sock *meta_sk, struct sock *sk, ++ const struct sk_buff *skb, u32 data_seq, ++ u16 data_len) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ const struct tcphdr *th = tcp_hdr(skb); ++ ++ /* State-machine handling if FIN has been enqueued and he has ++ * been acked (snd_una == write_seq) - it's important that this ++ * here is after sk_wmem_free_skb because otherwise ++ * sk_forward_alloc is wrong upon inet_csk_destroy_sock() ++ */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: { ++ struct dst_entry *dst; ++ int tmo; ++ ++ if (meta_tp->snd_una != meta_tp->write_seq) ++ break; ++ ++ tcp_set_state(meta_sk, TCP_FIN_WAIT2); ++ meta_sk->sk_shutdown |= SEND_SHUTDOWN; ++ ++ dst = __sk_dst_get(sk); ++ if (dst) ++ dst_confirm(dst); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Wake up lingering close() */ ++ meta_sk->sk_state_change(meta_sk); ++ break; ++ } ++ ++ if (meta_tp->linger2 < 0 || ++ (data_len && ++ after(data_seq + data_len - (mptcp_is_data_fin2(skb, tp) ? 1 : 0), ++ meta_tp->rcv_nxt))) { ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_done(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ return 1; ++ } ++ ++ tmo = tcp_fin_time(meta_sk); ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, tmo - TCP_TIMEWAIT_LEN); ++ } else if (mptcp_is_data_fin2(skb, tp) || sock_owned_by_user(meta_sk)) { ++ /* Bad case. We could lose such FIN otherwise. ++ * It is not a big problem, but it looks confusing ++ * and not so rare event. We still can lose it now, ++ * if it spins in bh_lock_sock(), but it is really ++ * marginal case. ++ */ ++ inet_csk_reset_keepalive_timer(meta_sk, tmo); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, tmo); ++ } ++ break; ++ } ++ case TCP_CLOSING: ++ case TCP_LAST_ACK: ++ if (meta_tp->snd_una == meta_tp->write_seq) { ++ tcp_done(meta_sk); ++ return 1; ++ } ++ break; ++ } ++ ++ /* step 7: process the segment text */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: ++ case TCP_FIN_WAIT2: ++ /* RFC 793 says to queue data in these states, ++ * RFC 1122 says we MUST send a reset. ++ * BSD 4.4 also does reset. ++ */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN) { ++ if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp_is_data_fin2(skb, tp)) { ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_reset(meta_sk); ++ return 1; ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/** ++ * @return: ++ * i) 1: Everything's fine. ++ * ii) -1: A reset has been sent on the subflow - csum-failure ++ * iii) 0: csum-failure but no reset sent, because it's the last subflow. ++ * Last packet should not be destroyed by the caller because it has ++ * been done here. ++ */ ++static int mptcp_verif_dss_csum(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1, *last = NULL; ++ __wsum csum_tcp = 0; /* cumulative checksum of pld + mptcp-header */ ++ int ans = 1, overflowed = 0, offset = 0, dss_csum_added = 0; ++ int iter = 0; ++ u32 next_seq, offset_seq; ++ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp, tmp1) { ++ unsigned int csum_len; ++ ++ /* init next seq in first round */ ++ if (!iter) ++ next_seq = TCP_SKB_CB(tmp)->seq; ++ offset_seq = next_seq - TCP_SKB_CB(tmp)->seq; ++ ++ if (before(tp->mptcp->map_subseq + tp->mptcp->map_data_len, TCP_SKB_CB(tmp)->end_seq)) ++ /* Mapping ends in the middle of the packet - ++ * csum only these bytes ++ */ ++ csum_len = tp->mptcp->map_subseq + tp->mptcp->map_data_len - TCP_SKB_CB(tmp)->seq; ++ else ++ csum_len = tmp->len; ++ ++ csum_len -= offset_seq; ++ offset = 0; ++ if (overflowed) { ++ char first_word[4]; ++ first_word[0] = 0; ++ first_word[1] = 0; ++ first_word[2] = 0; ++ first_word[3] = *(tmp->data + offset_seq); ++ csum_tcp = csum_partial(first_word, 4, csum_tcp); ++ offset = 1; ++ csum_len--; ++ overflowed = 0; ++ } ++ ++ csum_tcp = skb_checksum(tmp, offset + offset_seq, csum_len, ++ csum_tcp); ++ ++ /* Was it on an odd-length? Then we have to merge the next byte ++ * correctly (see above) ++ */ ++ if (csum_len != (csum_len & (~1))) ++ overflowed = 1; ++ ++ if (mptcp_is_data_seq(tmp) && !dss_csum_added) { ++ __be32 data_seq = htonl((u32)(tp->mptcp->map_data_seq >> 32)); ++ ++ /* If a 64-bit dss is present, we increase the offset ++ * by 4 bytes, as the high-order 64-bits will be added ++ * in the final csum_partial-call. ++ */ ++ u32 offset = skb_transport_offset(tmp) + ++ TCP_SKB_CB(tmp)->dss_off; ++ if (TCP_SKB_CB(tmp)->mptcp_flags & MPTCPHDR_SEQ64_SET) ++ offset += 4; ++ ++ csum_tcp = skb_checksum(tmp, offset, ++ MPTCP_SUB_LEN_SEQ_CSUM, ++ csum_tcp); ++ ++ csum_tcp = csum_partial(&data_seq, ++ sizeof(data_seq), csum_tcp); ++ ++ dss_csum_added = 1; /* Just do it once */ ++ } ++ last = tmp; ++ iter++; ++ ++ if (!skb_queue_is_last(&sk->sk_receive_queue, tmp) && ++ !before(TCP_SKB_CB(tmp1)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ next_seq = TCP_SKB_CB(tmp)->end_seq; ++ } ++ ++ /* Now, checksum must be 0 */ ++ if (unlikely(csum_fold(csum_tcp))) { ++ struct mptcp_tcp_sock *mptcp; ++ struct sock *sk_it = NULL; ++ ++ pr_debug("%s csum is wrong: %#x tcp-seq %u dss_csum_added %d overflowed %d iterations %d\n", ++ __func__, csum_fold(csum_tcp), TCP_SKB_CB(last)->seq, ++ dss_csum_added, overflowed, iter); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMFAIL); ++ tp->mptcp->send_mp_fail = 1; ++ ++ /* map_data_seq is the data-seq number of the ++ * mapping we are currently checking ++ */ ++ tp->mpcb->csum_cutoff_seq = tp->mptcp->map_data_seq; ++ ++ /* Search for another subflow that is fully established */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it != sk && ++ tcp_sk(sk_it)->mptcp->fully_established) ++ break; ++ ++ sk_it = NULL; ++ } ++ ++ if (sk_it) { ++ mptcp_send_reset(sk); ++ ans = -1; ++ } else { ++ tp->mpcb->send_infinite_mapping = 1; ++ ++ /* Need to purge the rcv-queue as it's no more valid */ ++ while ((tmp = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { ++ tp->copied_seq = TCP_SKB_CB(tmp)->end_seq; ++ kfree_skb(tmp); ++ } ++ ++ mptcp_fallback_close(tp->mpcb, sk); ++ ++ ans = 0; ++ } ++ } ++ ++ return ans; ++} ++ ++static inline void mptcp_prepare_skb(struct sk_buff *skb, ++ const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 inc = 0, end_seq = tcb->end_seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ end_seq--; ++ /* If skb is the end of this mapping (end is always at mapping-boundary ++ * thanks to the splitting/trimming), then we need to increase ++ * data-end-seq by 1 if this here is a data-fin. ++ * ++ * We need to do -1 because end_seq includes the subflow-FIN. ++ */ ++ if (tp->mptcp->map_data_fin && ++ end_seq == tp->mptcp->map_subseq + tp->mptcp->map_data_len) { ++ inc = 1; ++ ++ /* We manually set the fin-flag if it is a data-fin. For easy ++ * processing in tcp_recvmsg. ++ */ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } else { ++ /* We may have a subflow-fin with data but without data-fin */ ++ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_FIN; ++ } ++ ++ /* Adapt data-seq's to the packet itself. We kinda transform the ++ * dss-mapping to a per-packet granularity. This is necessary to ++ * correctly handle overlapping mappings coming from different ++ * subflows. Otherwise it would be a complete mess. ++ */ ++ tcb->seq = ((u32)tp->mptcp->map_data_seq) + tcb->seq - tp->mptcp->map_subseq; ++ tcb->end_seq = tcb->seq + skb->len + inc; ++} ++ ++static inline void mptcp_reset_mapping(struct tcp_sock *tp, u32 old_copied_seq) ++{ ++ tp->mptcp->map_data_len = 0; ++ tp->mptcp->map_data_seq = 0; ++ tp->mptcp->map_subseq = 0; ++ tp->mptcp->map_data_fin = 0; ++ tp->mptcp->mapping_present = 0; ++ ++ /* In infinite mapping receiver mode, we have to advance the implied ++ * data-sequence number when we progress the subflow's data. ++ */ ++ if (tp->mpcb->infinite_mapping_rcv) ++ tp->mpcb->infinite_rcv_seq += (tp->copied_seq - old_copied_seq); ++} ++ ++/* The DSS-mapping received on the sk only covers the second half of the skb ++ * (cut at seq). We trim the head from the skb. ++ * Data will be freed upon kfree(). ++ * ++ * Inspired by tcp_trim_head(). ++ */ ++static void mptcp_skb_trim_head(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ int len = seq - TCP_SKB_CB(skb)->seq; ++ u32 new_seq = TCP_SKB_CB(skb)->seq + len; ++ u32 delta_truesize; ++ ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq = new_seq; ++ ++ if (delta_truesize) { ++ skb->truesize -= delta_truesize; ++ atomic_sub(delta_truesize, &sk->sk_rmem_alloc); ++ sk_mem_uncharge(sk, delta_truesize); ++ } ++} ++ ++/* The DSS-mapping received on the sk only covers the first half of the skb ++ * (cut at seq). We create a second skb (@return), and queue it in the rcv-queue ++ * as further packets may resolve the mapping of the second half of data. ++ * ++ * Inspired by tcp_fragment(). ++ */ ++static int mptcp_skb_split_tail(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ struct sk_buff *buff; ++ int nsize; ++ int nlen, len; ++ u8 flags; ++ ++ len = seq - TCP_SKB_CB(skb)->seq; ++ nsize = skb_headlen(skb) - len + tcp_sk(sk)->tcp_header_len; ++ if (nsize < 0) ++ nsize = 0; ++ ++ /* Get a new skb... force flag on. */ ++ buff = alloc_skb(nsize, GFP_ATOMIC); ++ if (buff == NULL) ++ return -ENOMEM; ++ ++ skb_reserve(buff, tcp_sk(sk)->tcp_header_len); ++ skb_reset_transport_header(buff); ++ ++ flags = TCP_SKB_CB(skb)->tcp_flags; ++ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN); ++ TCP_SKB_CB(buff)->tcp_flags = flags; ++ ++ /* We absolutly need to call skb_set_owner_r before refreshing the ++ * truesize of buff, otherwise the moved data will account twice. ++ */ ++ skb_set_owner_r(buff, sk); ++ nlen = skb->len - len - nsize; ++ buff->truesize += nlen; ++ skb->truesize -= nlen; ++ ++ /* Correct the sequence numbers. */ ++ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; ++ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; ++ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; ++ ++ skb_split(skb, buff, len); ++ ++ __skb_queue_after(&sk->sk_receive_queue, skb, buff); ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_prevalidate_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If we are in infinite mode, the subflow-fin is in fact a data-fin. */ ++ if (!skb->len && (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ !mptcp_is_data_fin(skb) && !mpcb->infinite_mapping_rcv) { ++ /* Remove a pure subflow-fin from the queue and increase ++ * copied_seq. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* If we are not yet fully established and do not know the mapping for ++ * this segment, this path has to fallback to infinite or be torn down. ++ */ ++ if (!tp->mptcp->fully_established && !mptcp_is_data_seq(skb) && ++ !tp->mptcp->mapping_present && !mpcb->infinite_mapping_rcv) { ++ pr_debug("%s %#x will fallback - pi %d from %pS, seq %u\n", ++ __func__, mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, __builtin_return_address(0), ++ TCP_SKB_CB(skb)->seq); ++ ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATASUB); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATAINIT); ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ /* We do a seamless fallback and should not send a inf.mapping. */ ++ mpcb->send_infinite_mapping = 0; ++ tp->mptcp->fully_established = 1; ++ } ++ ++ /* Receiver-side becomes fully established when a whole rcv-window has ++ * been received without the need to fallback due to the previous ++ * condition. ++ */ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->init_rcv_wnd -= skb->len; ++ if (tp->mptcp->init_rcv_wnd < 0) ++ mptcp_become_fully_estab(sk); ++ } ++ ++ return 0; ++} ++ ++static void mptcp_restart_sending(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *wq_head, *skb, *tmp; ++ ++ skb = tcp_rtx_queue_head(meta_sk); ++ ++ /* We resend everything that has not been acknowledged, thus we need ++ * to move it from the rtx-tree to the write-queue. ++ */ ++ wq_head = tcp_write_queue_head(meta_sk); ++ ++ skb_rbtree_walk_from_safe(skb, tmp) { ++ list_del(&skb->tcp_tsorted_anchor); ++ tcp_rtx_queue_unlink(skb, meta_sk); ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ ++ if (wq_head) ++ __skb_queue_before(&meta_sk->sk_write_queue, wq_head, skb); ++ else ++ tcp_add_write_queue_tail(meta_sk, skb); ++ } ++ ++ /* We artificially restart the whole send-queue. Thus, ++ * it is as if no packets are in flight ++ */ ++ meta_tp->packets_out = 0; ++ ++ /* If the snd_nxt already wrapped around, we have to ++ * undo the wrapping, as we are restarting from snd_una ++ * on. ++ */ ++ if (meta_tp->snd_nxt < meta_tp->snd_una) { ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] -= 2; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ } ++ meta_tp->snd_nxt = meta_tp->snd_una; ++ ++ /* Trigger a sending on the meta. */ ++ mptcp_push_pending_frames(meta_sk); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_detect_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 *ptr; ++ u32 data_seq, sub_seq, data_len, tcp_end_seq; ++ bool set_infinite_rcv = false; ++ ++ /* If we are in infinite-mapping-mode, the subflow is guaranteed to be ++ * in-order at the data-level. Thus data-seq-numbers can be inferred ++ * from what is expected at the data-level. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ /* copied_seq may be bigger than tcb->seq (e.g., when the peer ++ * retransmits data that actually has already been acknowledged with ++ * newer data, if he did not receive our acks). Thus, we need ++ * to account for this overlap as well. ++ */ ++ tp->mptcp->map_data_seq = mpcb->infinite_rcv_seq - (tp->copied_seq - tcb->seq); ++ tp->mptcp->map_subseq = tcb->seq; ++ tp->mptcp->map_data_len = skb->len; ++ tp->mptcp->map_data_fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN); ++ tp->mptcp->mapping_present = 1; ++ return 0; ++ } ++ ++ /* No mapping here? Exit - it is either already set or still on its way */ ++ if (!mptcp_is_data_seq(skb)) { ++ /* Too many packets without a mapping - this subflow is broken */ ++ if (!tp->mptcp->mapping_present && ++ tp->rcv_nxt - tp->copied_seq > 65536) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_NODSSWINDOW); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ return 0; ++ } ++ ++ ptr = mptcp_skb_set_data_seq(skb, &data_seq, mpcb); ++ ptr++; ++ sub_seq = get_unaligned_be32(ptr) + tp->mptcp->rcv_isn; ++ ptr++; ++ data_len = get_unaligned_be16(ptr); ++ ++ /* If it's an empty skb with DATA_FIN, sub_seq must get fixed. ++ * The draft sets it to 0, but we really would like to have the ++ * real value, to have an easy handling afterwards here in this ++ * function. ++ */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ sub_seq = TCP_SKB_CB(skb)->seq; ++ ++ /* If there is already a mapping - we check if it maps with the current ++ * one. If not - we reset. ++ */ ++ if (tp->mptcp->mapping_present && ++ (data_seq != (u32)tp->mptcp->map_data_seq || ++ sub_seq != tp->mptcp->map_subseq || ++ data_len != tp->mptcp->map_data_len + tp->mptcp->map_data_fin || ++ mptcp_is_data_fin(skb) != tp->mptcp->map_data_fin)) { ++ /* Mapping in packet is different from what we want */ ++ pr_debug("%s Mappings do not match!\n", __func__); ++ pr_debug("%s dseq %u mdseq %u, sseq %u msseq %u dlen %u mdlen %u dfin %d mdfin %d\n", ++ __func__, data_seq, (u32)tp->mptcp->map_data_seq, ++ sub_seq, tp->mptcp->map_subseq, data_len, ++ tp->mptcp->map_data_len, mptcp_is_data_fin(skb), ++ tp->mptcp->map_data_fin); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSNOMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* If the previous check was good, the current mapping is valid and we exit. */ ++ if (tp->mptcp->mapping_present) ++ return 0; ++ ++ /* Mapping not yet set on this subflow - we set it here! */ ++ ++ if (!data_len) { ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->send_infinite_mapping = 1; ++ tp->mptcp->fully_established = 1; ++ /* We need to repeat mp_fail's until the sender felt ++ * back to infinite-mapping - here we stop repeating it. ++ */ ++ tp->mptcp->send_mp_fail = 0; ++ ++ /* We have to fixup data_len - it must be the same as skb->len */ ++ data_len = skb->len + (mptcp_is_data_fin(skb) ? 1 : 0); ++ sub_seq = tcb->seq; ++ ++ mptcp_restart_sending(tp->meta_sk); ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ /* data_seq and so on are set correctly */ ++ ++ /* At this point, the meta-ofo-queue has to be emptied, ++ * as the following data is guaranteed to be in-order at ++ * the data and subflow-level ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ ++ set_infinite_rcv = true; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_INFINITEMAPRX); ++ } ++ ++ /* We are sending mp-fail's and thus are in fallback mode. ++ * Ignore packets which do not announce the fallback and still ++ * want to provide a mapping. ++ */ ++ if (tp->mptcp->send_mp_fail) { ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* FIN increased the mapping-length by 1 */ ++ if (mptcp_is_data_fin(skb)) ++ data_len--; ++ ++ /* Subflow-sequences of packet must be ++ * (at least partially) be part of the DSS-mapping's ++ * subflow-sequence-space. ++ * ++ * Basically the mapping is not valid, if either of the ++ * following conditions is true: ++ * ++ * 1. It's not a data_fin and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * 2. It's a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * The previous two can be merged into: ++ * TCP-end_seq > TCP-seq and MPTCP-sub_seq >= TCP-end_seq ++ * Because if it's not a data-fin, TCP-end_seq > TCP-seq ++ * ++ * 3. It's a data_fin and skb->len == 0 and ++ * MPTCP-sub_seq > TCP-end_seq ++ * ++ * 4. It's not a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq + MPTCP-data_len <= TCP-seq ++ */ ++ ++ /* subflow-fin is not part of the mapping - ignore it here ! */ ++ tcp_end_seq = tcb->end_seq; ++ if (tcb->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if ((!before(sub_seq, tcb->end_seq) && after(tcp_end_seq, tcb->seq)) || ++ (mptcp_is_data_fin(skb) && skb->len == 0 && after(sub_seq, tcb->end_seq)) || ++ (!after(sub_seq + data_len, tcb->seq) && after(tcp_end_seq, tcb->seq))) { ++ /* Subflow-sequences of packet is different from what is in the ++ * packet's dss-mapping. The peer is misbehaving - reset ++ */ ++ pr_debug("%s Packet's mapping does not map to the DSS sub_seq %u end_seq %u, tcp_end_seq %u seq %u dfin %u len %u data_len %u copied_seq %u\n", ++ __func__, sub_seq, tcb->end_seq, tcp_end_seq, ++ tcb->seq, mptcp_is_data_fin(skb), ++ skb->len, data_len, tp->copied_seq); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTCPMISMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* Does the DSS had 64-bit seqnum's ? */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_SEQ64_SET)) { ++ /* Wrapped around? */ ++ if (unlikely(after(data_seq, meta_tp->rcv_nxt) && data_seq < meta_tp->rcv_nxt)) { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, !mpcb->rcv_hiseq_index, data_seq); ++ } else { ++ /* Else, access the default high-order bits */ ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, data_seq); ++ } ++ } else { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, (tcb->mptcp_flags & MPTCPHDR_SEQ64_INDEX) ? 1 : 0, data_seq); ++ ++ if (unlikely(tcb->mptcp_flags & MPTCPHDR_SEQ64_OFO)) { ++ /* We make sure that the data_seq is invalid. ++ * It will be dropped later. ++ */ ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ } ++ } ++ ++ if (set_infinite_rcv) ++ mpcb->infinite_rcv_seq = tp->mptcp->map_data_seq; ++ ++ tp->mptcp->map_data_len = data_len; ++ tp->mptcp->map_subseq = sub_seq; ++ tp->mptcp->map_data_fin = mptcp_is_data_fin(skb) ? 1 : 0; ++ tp->mptcp->mapping_present = 1; ++ ++ return 0; ++} ++ ++/* Similar to tcp_sequence(...) */ ++static inline bool mptcp_sequence(const struct tcp_sock *meta_tp, ++ u64 data_seq, u64 end_data_seq) ++{ ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u64 rcv_wup64; ++ ++ /* Wrap-around? */ ++ if (meta_tp->rcv_wup > meta_tp->rcv_nxt) { ++ rcv_wup64 = ((u64)(mpcb->rcv_high_order[mpcb->rcv_hiseq_index] - 1) << 32) | ++ meta_tp->rcv_wup; ++ } else { ++ rcv_wup64 = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_wup); ++ } ++ ++ return !before64(end_data_seq, rcv_wup64) && ++ !after64(data_seq, mptcp_get_rcv_nxt_64(meta_tp) + tcp_receive_window(meta_tp)); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_validate_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1; ++ u32 tcp_end_seq; ++ ++ if (!tp->mptcp->mapping_present) ++ return 0; ++ ++ /* either, the new skb gave us the mapping and the first segment ++ * in the sub-rcv-queue has to be trimmed ... ++ */ ++ tmp = skb_peek(&sk->sk_receive_queue); ++ if (before(TCP_SKB_CB(tmp)->seq, tp->mptcp->map_subseq) && ++ after(TCP_SKB_CB(tmp)->end_seq, tp->mptcp->map_subseq)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTRIMHEAD); ++ mptcp_skb_trim_head(tmp, sk, tp->mptcp->map_subseq); ++ } ++ ++ /* ... or the new skb (tail) has to be split at the end. */ ++ tcp_end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if (after(tcp_end_seq, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) { ++ u32 seq = tp->mptcp->map_subseq + tp->mptcp->map_data_len; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSSPLITTAIL); ++ if (mptcp_skb_split_tail(skb, sk, seq)) { /* Allocation failed */ ++ /* TODO : maybe handle this here better. ++ * We now just force meta-retransmission. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ } ++ ++ /* Now, remove old sk_buff's from the receive-queue. ++ * This may happen if the mapping has been lost for these segments and ++ * the next mapping has already been received. ++ */ ++ if (before(TCP_SKB_CB(skb_peek(&sk->sk_receive_queue))->seq, tp->mptcp->map_subseq)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ if (!before(TCP_SKB_CB(tmp1)->seq, tp->mptcp->map_subseq)) ++ break; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PURGEOLD); ++ /* Impossible that we could free skb here, because his ++ * mapping is known to be valid from previous checks ++ */ ++ __kfree_skb(tmp1); ++ } ++ } ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this mapping has been put in the meta-receive-queue ++ * -2 this mapping has been eaten by the application ++ */ ++static int mptcp_queue_skb(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sk_buff *tmp, *tmp1; ++ u64 rcv_nxt64 = mptcp_get_rcv_nxt_64(meta_tp); ++ u32 old_copied_seq = tp->copied_seq; ++ bool data_queued = false; ++ ++ /* Have we not yet received the full mapping? */ ++ if (!tp->mptcp->mapping_present || ++ before(tp->rcv_nxt, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ return 0; ++ ++ /* Is this an overlapping mapping? rcv_nxt >= end_data_seq ++ * OR ++ * This mapping is out of window ++ */ ++ if (!before64(rcv_nxt64, tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin) || ++ !mptcp_sequence(meta_tp, tp->mptcp->map_data_seq, ++ tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return -1; ++ } ++ ++ /* Record it, because we want to send our data_fin on the same path */ ++ if (tp->mptcp->map_data_fin) { ++ mpcb->dfin_path_index = tp->mptcp->path_index; ++ mpcb->dfin_combined = !!(sk->sk_shutdown & RCV_SHUTDOWN); ++ } ++ ++ /* Verify the checksum */ ++ if (mpcb->dss_csum && !mpcb->infinite_mapping_rcv) { ++ int ret = mptcp_verif_dss_csum(sk); ++ ++ if (ret <= 0) { ++ mptcp_reset_mapping(tp, old_copied_seq); ++ return 1; ++ } ++ } ++ ++ if (before64(rcv_nxt64, tp->mptcp->map_data_seq)) { ++ /* Seg's have to go to the meta-ofo-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true later. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ if (!mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ tcp_data_queue_ofo(meta_sk, tmp1); ++ else ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ /* Quick ACK if more 3/4 of the receive window is filled */ ++ if (after64(tp->mptcp->map_data_seq, ++ rcv_nxt64 + 3 * (tcp_receive_window(meta_tp) >> 2))) ++ tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); ++ ++ } else { ++ /* Ready for the meta-rcv-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ int eaten = 0; ++ bool fragstolen = false; ++ u32 old_rcv_nxt = meta_tp->rcv_nxt; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ /* This segment has already been received */ ++ if (!after(TCP_SKB_CB(tmp1)->end_seq, meta_tp->rcv_nxt)) { ++ __kfree_skb(tmp1); ++ goto next; ++ } ++ ++ if (mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ eaten = 1; ++ ++ if (!eaten) ++ eaten = tcp_queue_rcv(meta_sk, tmp1, 0, &fragstolen); ++ ++ meta_tp->rcv_nxt = TCP_SKB_CB(tmp1)->end_seq; ++ ++ if (TCP_SKB_CB(tmp1)->tcp_flags & TCPHDR_FIN) ++ mptcp_fin(meta_sk); ++ ++ /* Check if this fills a gap in the ofo queue */ ++ if (!RB_EMPTY_ROOT(&meta_tp->out_of_order_queue)) ++ tcp_ofo_queue(meta_sk); ++ ++ mptcp_check_rcvseq_wrap(meta_tp, old_rcv_nxt); ++ ++ if (eaten) ++ kfree_skb_partial(tmp1, fragstolen); ++ ++ data_queued = true; ++next: ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ } ++ ++ inet_csk(meta_sk)->icsk_ack.lrcvtime = tcp_jiffies32; ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return data_queued ? -1 : -2; ++} ++ ++void mptcp_data_ready(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb, *tmp; ++ int queued = 0; ++ ++ tcp_mstamp_refresh(tcp_sk(meta_sk)); ++ ++ /* restart before the check, because mptcp_fin might have changed the ++ * state. ++ */ ++restart: ++ /* If the meta cannot receive data, there is no point in pushing data. ++ * If we are in time-wait, we may still be waiting for the final FIN. ++ * So, we should proceed with the processing. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !tcp_sk(sk)->mpcb->in_time_wait) { ++ skb_queue_purge(&sk->sk_receive_queue); ++ tcp_sk(sk)->copied_seq = tcp_sk(sk)->rcv_nxt; ++ goto exit; ++ } ++ ++ /* Iterate over all segments, detect their mapping (if we don't have ++ * one yet), validate them and push everything one level higher. ++ */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { ++ int ret; ++ /* Pre-validation - e.g., early fallback */ ++ ret = mptcp_prevalidate_skb(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Set the current mapping */ ++ ret = mptcp_detect_mapping(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Validation */ ++ if (mptcp_validate_mapping(sk, skb) < 0) ++ goto restart; ++ ++ /* Push a level higher */ ++ ret = mptcp_queue_skb(sk); ++ if (ret < 0) { ++ if (ret == -1) ++ queued = ret; ++ goto restart; ++ } else if (ret == 0) { ++ continue; ++ } else { /* ret == 1 */ ++ break; ++ } ++ } ++ ++exit: ++ if (tcp_sk(sk)->close_it && sk->sk_state == TCP_FIN_WAIT2) { ++ tcp_send_ack(sk); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_TIME_WAIT, 0); ++ } ++ ++ if (queued == -1 && !sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_data_ready(meta_sk); ++} ++ ++struct mp_join *mptcp_find_join(const struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether JOIN is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return NULL; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return NULL; ++ if (opsize > length) ++ return NULL; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)(ptr - 2))->sub == MPTCP_SUB_JOIN) { ++ return (struct mp_join *)(ptr - 2); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return NULL; ++} ++ ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ struct mp_join *join_opt = mptcp_find_join(skb); ++ if (!join_opt) ++ return 0; ++ ++ /* MPTCP structures were not initialized, so return error */ ++ if (mptcp_init_failed) ++ return -1; ++ ++ token = join_opt->u.syn.token; ++ meta_sk = mptcp_hash_find(dev_net(skb_dst(skb)->dev), token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* Coming from time-wait-sock processing in tcp_v4_rcv. ++ * We have to deschedule it before continuing, because otherwise ++ * mptcp_v4_do_rcv will hit again on it inside tcp_v4_hnd_req. ++ */ ++ if (tw) ++ inet_twsk_deschedule_put(tw); ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 1; ++} ++ ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ ++ token = mopt->mptcp_rem_token; ++ meta_sk = mptcp_hash_find(net, token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ ++ /* mptcp_v4_do_rcv tries to free the skb - we prevent this, as ++ * the skb will finally be freed by tcp_v4_do_rcv (where we are ++ * coming from) ++ */ ++ skb_get(skb); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { /* IPv6 */ ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 0; ++} ++ ++/** ++ * Equivalent of tcp_fin() for MPTCP ++ * Can be called only when the FIN is validly part ++ * of the data seqnum space. Not before when we get holes. ++ */ ++void mptcp_fin(struct sock *meta_sk) ++{ ++ struct sock *sk = NULL; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ unsigned char state; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->mptcp->path_index == mpcb->dfin_path_index) { ++ sk = sk_it; ++ break; ++ } ++ } ++ ++ if (!sk || sk->sk_state == TCP_CLOSE) ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ inet_csk_schedule_ack(sk); ++ ++ if (!mpcb->in_time_wait) { ++ meta_sk->sk_shutdown |= RCV_SHUTDOWN; ++ sock_set_flag(meta_sk, SOCK_DONE); ++ state = meta_sk->sk_state; ++ } else { ++ state = mpcb->mptw_state; ++ } ++ ++ switch (state) { ++ case TCP_SYN_RECV: ++ case TCP_ESTABLISHED: ++ /* Move to CLOSE_WAIT */ ++ tcp_set_state(meta_sk, TCP_CLOSE_WAIT); ++ inet_csk(sk)->icsk_ack.pingpong = 1; ++ break; ++ ++ case TCP_CLOSE_WAIT: ++ case TCP_CLOSING: ++ /* Received a retransmission of the FIN, do ++ * nothing. ++ */ ++ break; ++ case TCP_LAST_ACK: ++ /* RFC793: Remain in the LAST-ACK state. */ ++ break; ++ ++ case TCP_FIN_WAIT1: ++ /* This case occurs when a simultaneous close ++ * happens, we must ack the received FIN and ++ * enter the CLOSING state. ++ */ ++ tcp_send_ack(sk); ++ tcp_set_state(meta_sk, TCP_CLOSING); ++ break; ++ case TCP_FIN_WAIT2: ++ /* Received a FIN -- send ACK and enter TIME_WAIT. */ ++ tcp_send_ack(sk); ++ meta_tp->ops->time_wait(meta_sk, TCP_TIME_WAIT, 0); ++ break; ++ default: ++ /* Only TCP_LISTEN and TCP_CLOSE are left, in these ++ * cases we should never reach this piece of code. ++ */ ++ pr_err("%s: Impossible, meta_sk->sk_state=%d\n", __func__, ++ meta_sk->sk_state); ++ break; ++ } ++ ++ /* It _is_ possible, that we have something out-of-order _after_ FIN. ++ * Probably, we should reset in this case. For now drop them. ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ sk_mem_reclaim(meta_sk); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ ++ /* Do not send POLL_HUP for half duplex close. */ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || ++ meta_sk->sk_state == TCP_CLOSE) ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_HUP); ++ else ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_IN); ++ } ++ ++ return; ++} ++ ++/* Similar to tcp_xmit_retransmit_queue */ ++static void mptcp_xmit_retransmit_queue(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb, *rtx_head; ++ ++ if (!meta_tp->packets_out) ++ return; ++ ++ skb = rtx_head = tcp_rtx_queue_head(meta_sk); ++ skb_rbtree_walk_from(skb) { ++ if (mptcp_retransmit_skb(meta_sk, skb)) ++ return; ++ ++ if (skb == rtx_head) ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ inet_csk(meta_sk)->icsk_rto, ++ TCP_RTO_MAX); ++ } ++} ++ ++static void mptcp_snd_una_update(struct tcp_sock *meta_tp, u32 data_ack) ++{ ++ u32 delta = data_ack - meta_tp->snd_una; ++ ++ sock_owned_by_me((struct sock *)meta_tp); ++ meta_tp->bytes_acked += delta; ++ meta_tp->snd_una = data_ack; ++} ++ ++/* Handle the DATA_ACK */ ++static void mptcp_data_ack(struct sock *sk, const struct sk_buff *skb) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 prior_snd_una = meta_tp->snd_una; ++ int prior_packets; ++ u32 nwin, data_ack, data_seq; ++ u16 data_len = 0; ++ ++ /* A valid packet came in - subflow is operational again */ ++ tp->pf = 0; ++ ++ /* Even if there is no data-ack, we stop retransmitting. ++ * Except if this is a SYN/ACK. Then it is just a retransmission ++ */ ++ if (tp->mptcp->pre_established && !tcp_hdr(skb)->syn) { ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ ++ if (meta_tp->mpcb->pm_ops->established_subflow) ++ meta_tp->mpcb->pm_ops->established_subflow(sk); ++ } ++ ++ /* If we are in infinite mapping mode, rx_opt.data_ack has been ++ * set by mptcp_clean_rtx_infinite. ++ */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_ACK) && !tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ if (unlikely(!tp->mptcp->fully_established) && ++ tp->mptcp->snt_isn + 1 != TCP_SKB_CB(skb)->ack_seq) ++ /* As soon as a subflow-data-ack (not acking syn, thus snt_isn + 1) ++ * includes a data-ack, we are fully established ++ */ ++ mptcp_become_fully_estab(sk); ++ ++ /* After we did the subflow-only processing (stopping timer and marking ++ * subflow as established), check if we can proceed with MPTCP-level ++ * processing. ++ */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ /* Get the data_seq */ ++ if (mptcp_is_data_seq(skb)) { ++ data_seq = tp->mptcp->rx_opt.data_seq; ++ data_len = tp->mptcp->rx_opt.data_len; ++ } else { ++ data_seq = meta_tp->snd_wl1; ++ } ++ ++ data_ack = tp->mptcp->rx_opt.data_ack; ++ ++ /* If the ack is older than previous acks ++ * then we can probably ignore it. ++ */ ++ if (before(data_ack, prior_snd_una)) ++ goto exit; ++ ++ /* If the ack includes data we haven't sent yet, discard ++ * this segment (RFC793 Section 3.9). ++ */ ++ if (after(data_ack, meta_tp->snd_nxt)) ++ goto exit; ++ ++ /*** Now, update the window - inspired by tcp_ack_update_window ***/ ++ nwin = ntohs(tcp_hdr(skb)->window); ++ ++ if (likely(!tcp_hdr(skb)->syn)) ++ nwin <<= tp->rx_opt.snd_wscale; ++ ++ if (tcp_may_update_window(meta_tp, data_ack, data_seq, nwin)) { ++ tcp_update_wl(meta_tp, data_seq); ++ ++ /* Draft v09, Section 3.3.5: ++ * [...] It should only update its local receive window values ++ * when the largest sequence number allowed (i.e. DATA_ACK + ++ * receive window) increases. [...] ++ */ ++ if (meta_tp->snd_wnd != nwin && ++ !before(data_ack + nwin, tcp_wnd_end(meta_tp))) { ++ meta_tp->snd_wnd = nwin; ++ ++ if (nwin > meta_tp->max_window) ++ meta_tp->max_window = nwin; ++ } ++ } ++ /*** Done, update the window ***/ ++ ++ /* We passed data and got it acked, remove any soft error ++ * log. Something worked... ++ */ ++ sk->sk_err_soft = 0; ++ inet_csk(meta_sk)->icsk_probes_out = 0; ++ meta_tp->rcv_tstamp = tcp_jiffies32; ++ prior_packets = meta_tp->packets_out; ++ if (!prior_packets) ++ goto no_queue; ++ ++ mptcp_snd_una_update(meta_tp, data_ack); ++ ++ mptcp_clean_rtx_queue(meta_sk, prior_snd_una); ++ ++ /* We are in loss-state, and something got acked, retransmit the whole ++ * queue now! ++ */ ++ if (inet_csk(meta_sk)->icsk_ca_state == TCP_CA_Loss && ++ after(data_ack, prior_snd_una)) { ++ mptcp_xmit_retransmit_queue(meta_sk); ++ inet_csk(meta_sk)->icsk_ca_state = TCP_CA_Open; ++ } ++ ++ /* Simplified version of tcp_new_space, because the snd-buffer ++ * is handled by all the subflows. ++ */ ++ if (sock_flag(meta_sk, SOCK_QUEUE_SHRUNK)) { ++ sock_reset_flag(meta_sk, SOCK_QUEUE_SHRUNK); ++ if (meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ meta_sk->sk_write_space(meta_sk); ++ } ++ ++ if (meta_sk->sk_state != TCP_ESTABLISHED && ++ mptcp_rcv_state_process(meta_sk, sk, skb, data_seq, data_len)) ++ return; ++ ++exit: ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++ ++no_queue: ++ if (tcp_send_head(meta_sk)) ++ tcp_ack_probe(meta_sk); ++ ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++} ++ ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(mptcp_meta_sk(sk)); ++ ++ if (!tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ /* The difference between both write_seq's represents the offset between ++ * data-sequence and subflow-sequence. As we are infinite, this must ++ * match. ++ * ++ * Thus, from this difference we can infer the meta snd_una. ++ */ ++ tp->mptcp->rx_opt.data_ack = meta_tp->snd_nxt - tp->snd_nxt + ++ tp->snd_una; ++ ++ mptcp_data_ack(sk, skb); ++} ++ ++/**** static functions used by mptcp_parse_options */ ++ ++static void mptcp_send_reset_rem_id(const struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->mptcp->rem_id == rem_id) { ++ mptcp_reinject_data(sk_it, 0); ++ mptcp_send_reset(sk_it); ++ } ++ } ++} ++ ++static inline bool is_valid_addropt_opsize(u8 mptcp_ver, ++ struct mp_add_addr *mpadd, ++ int opsize) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 6) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 6) ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2; ++#endif ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++ } ++ return false; ++} ++ ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp) ++{ ++ const struct mptcp_option *mp_opt = (struct mptcp_option *)ptr; ++ ++ /* If the socket is mp-capable we would have a mopt. */ ++ if (!mopt) ++ return; ++ ++ switch (mp_opt->sub) { ++ case MPTCP_SUB_CAPABLE: ++ { ++ const struct mp_capable *mpcapable = (struct mp_capable *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_CAPABLE_SYN && ++ opsize != MPTCP_SUB_LEN_CAPABLE_ACK) { ++ mptcp_debug("%s: mp_capable: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "If receiving a message with the 'B' flag set to 1, and this ++ * is not understood, then this SYN MUST be silently ignored; ++ */ ++ if (mpcapable->b) { ++ mopt->drop_me = 1; ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "An implementation that only supports this method MUST set ++ * bit "H" to 1, and bits "C" through "G" to 0." ++ */ ++ if (!mpcapable->h) ++ break; ++ ++ mopt->saw_mpc = 1; ++ mopt->dss_csum = sysctl_mptcp_checksum || mpcapable->a; ++ ++ if (opsize >= MPTCP_SUB_LEN_CAPABLE_SYN) ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ if (opsize == MPTCP_SUB_LEN_CAPABLE_ACK) ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ ++ mopt->mptcp_ver = mpcapable->ver; ++ break; ++ } ++ case MPTCP_SUB_JOIN: ++ { ++ const struct mp_join *mpjoin = (struct mp_join *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_JOIN_SYN && ++ opsize != MPTCP_SUB_LEN_JOIN_SYNACK && ++ opsize != MPTCP_SUB_LEN_JOIN_ACK) { ++ mptcp_debug("%s: mp_join: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* saw_mpc must be set, because in tcp_check_req we assume that ++ * it is set to support falling back to reg. TCP if a rexmitted ++ * SYN has no MP_CAPABLE or MP_JOIN ++ */ ++ switch (opsize) { ++ case MPTCP_SUB_LEN_JOIN_SYN: ++ mopt->is_mp_join = 1; ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_rem_token = mpjoin->u.syn.token; ++ mopt->mptcp_recv_nonce = mpjoin->u.syn.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_SYNACK: ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_recv_tmac = mpjoin->u.synack.mac; ++ mopt->mptcp_recv_nonce = mpjoin->u.synack.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_ACK: ++ mopt->saw_mpc = 1; ++ mopt->join_ack = 1; ++ memcpy(mopt->mptcp_recv_mac, mpjoin->u.ack.mac, 20); ++ break; ++ } ++ break; ++ } ++ case MPTCP_SUB_DSS: ++ { ++ const struct mp_dss *mdss = (struct mp_dss *)ptr; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ ++ /* We check opsize for the csum and non-csum case. We do this, ++ * because the draft says that the csum SHOULD be ignored if ++ * it has not been negotiated in the MP_CAPABLE but still is ++ * present in the data. ++ * ++ * It will get ignored later in mptcp_queue_skb. ++ */ ++ if (opsize != mptcp_sub_len_dss(mdss, 0) && ++ opsize != mptcp_sub_len_dss(mdss, 1)) { ++ mptcp_debug("%s: mp_dss: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ ptr += 4; ++ ++ if (mdss->A) { ++ tcb->mptcp_flags |= MPTCPHDR_ACK; ++ ++ if (mdss->a) { ++ mopt->data_ack = (u32) get_unaligned_be64(ptr); ++ ptr += MPTCP_SUB_LEN_ACK_64; ++ } else { ++ mopt->data_ack = get_unaligned_be32(ptr); ++ ptr += MPTCP_SUB_LEN_ACK; ++ } ++ } ++ ++ tcb->dss_off = (ptr - skb_transport_header(skb)); ++ ++ if (mdss->M) { ++ if (mdss->m) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ64_SET; ++ mopt->data_seq = (u32) data_seq64; ++ ++ ptr += 12; /* 64-bit dseq + subseq */ ++ } else { ++ mopt->data_seq = get_unaligned_be32(ptr); ++ ptr += 8; /* 32-bit dseq + subseq */ ++ } ++ mopt->data_len = get_unaligned_be16(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ /* Is a check-sum present? */ ++ if (opsize == mptcp_sub_len_dss(mdss, 1)) ++ tcb->mptcp_flags |= MPTCPHDR_DSS_CSUM; ++ ++ /* DATA_FIN only possible with DSS-mapping */ ++ if (mdss->F) ++ tcb->mptcp_flags |= MPTCPHDR_FIN; ++ } ++ ++ break; ++ } ++ case MPTCP_SUB_ADD_ADDR: ++ { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ /* If tcp_sock is not available, MPTCP version can't be ++ * retrieved and ADD_ADDR opsize validation is not possible. ++ */ ++ if (!tp || !tp->mpcb) ++ break; ++ ++ if (!is_valid_addropt_opsize(tp->mpcb->mptcp_ver, ++ mpadd, opsize)) { ++ mptcp_debug("%s: mp_add_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* We have to manually parse the options if we got two of them. */ ++ if (mopt->saw_add_addr) { ++ mopt->more_add_addr = 1; ++ break; ++ } ++ mopt->saw_add_addr = 1; ++ mopt->add_addr_ptr = ptr; ++ break; ++ } ++ case MPTCP_SUB_REMOVE_ADDR: ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) { ++ mptcp_debug("%s: mp_remove_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ if (mopt->saw_rem_addr) { ++ mopt->more_rem_addr = 1; ++ break; ++ } ++ mopt->saw_rem_addr = 1; ++ mopt->rem_addr_ptr = ptr; ++ break; ++ case MPTCP_SUB_PRIO: ++ { ++ const struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_PRIO && ++ opsize != MPTCP_SUB_LEN_PRIO_ADDR) { ++ mptcp_debug("%s: mp_prio: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->saw_low_prio = 1; ++ mopt->low_prio = mpprio->b; ++ ++ if (opsize == MPTCP_SUB_LEN_PRIO_ADDR) { ++ mopt->saw_low_prio = 2; ++ mopt->prio_addr_id = mpprio->addr_id; ++ } ++ break; ++ } ++ case MPTCP_SUB_FAIL: ++ if (opsize != MPTCP_SUB_LEN_FAIL) { ++ mptcp_debug("%s: mp_fail: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ mopt->mp_fail = 1; ++ break; ++ case MPTCP_SUB_FCLOSE: ++ if (opsize != MPTCP_SUB_LEN_FCLOSE) { ++ mptcp_debug("%s: mp_fclose: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->mp_fclose = 1; ++ mopt->mptcp_sender_key = ((struct mp_fclose *)ptr)->key; ++ ++ break; ++ default: ++ mptcp_debug("%s: Received unkown subtype: %d\n", ++ __func__, mp_opt->sub); ++ break; ++ } ++} ++ ++/** Parse only MPTCP options */ ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ const unsigned char *ptr = (const unsigned char *)(th + 1); ++ ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP) ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, NULL); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++} ++ ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ u32 rtt_max = 0; ++ ++ /* In MPTCP, we take the max delay across all flows, ++ * in order to take into account meta-reordering buffers. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_recv(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->rcv_rtt_est.rtt_us) ++ rtt_max = tcp_sk(sk)->rcv_rtt_est.rtt_us; ++ } ++ if (time < (rtt_max >> 3) || !rtt_max) ++ return true; ++ ++ return false; ++} ++ ++static void mptcp_handle_add_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ __be16 port = 0; ++ union inet_addr addr; ++ sa_family_t family; ++ ++ if (mpadd->ipver == 4) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v4; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v4.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v4.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 4, (u8 *)&mpadd->u.v4.addr.s_addr, ++ 2, (u8 *)&mpadd->u.v4.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v4: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2)) ++ port = mpadd->u.v4.port; ++ family = AF_INET; ++ addr.in = mpadd->u.v4.addr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (mpadd->ipver == 6) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v6; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v6.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v6.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 16, (u8 *)&mpadd->u.v6.addr.s6_addr, ++ 2, (u8 *)&mpadd->u.v6.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v6: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2)) ++ port = mpadd->u.v6.port; ++ family = AF_INET6; ++ addr.in6 = mpadd->u.v6.addr; ++#endif /* CONFIG_IPV6 */ ++ } else { ++ return; ++ } ++ ++ if (mpcb->pm_ops->add_raddr) ++ mpcb->pm_ops->add_raddr(mpcb, &addr, family, port, mpadd->addr_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRRX); ++} ++ ++static void mptcp_handle_rem_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ int i; ++ u8 rem_id; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ for (i = 0; i <= mprem->len - MPTCP_SUB_LEN_REMOVE_ADDR; i++) { ++ rem_id = (&mprem->addrs_id)[i]; ++ ++ if (mpcb->pm_ops->rem_raddr) ++ mpcb->pm_ops->rem_raddr(mpcb, rem_id); ++ mptcp_send_reset_rem_id(mpcb, rem_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRSUB); ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRRX); ++} ++ ++static void mptcp_parse_addropt(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether ADD_ADDR is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_ADD_ADDR) { ++ u8 mptcp_ver = tcp_sk(sk)->mpcb->mptcp_ver; ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ if (!is_valid_addropt_opsize(mptcp_ver, mpadd, ++ opsize)) ++ goto cont; ++ ++ mptcp_handle_add_addr(ptr, sk); ++ } ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_REMOVE_ADDR) { ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) ++ goto cont; ++ ++ mptcp_handle_rem_addr(ptr, sk); ++ } ++cont: ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return; ++} ++ ++static bool mptcp_mp_fastclose_rcvd(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ if (likely(!mptcp->rx_opt.mp_fclose)) ++ return false; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FASTCLOSERX); ++ mptcp->rx_opt.mp_fclose = 0; ++ if (mptcp->rx_opt.mptcp_sender_key != mpcb->mptcp_loc_key) ++ return false; ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ tcp_reset(mptcp_meta_sk(sk)); ++ ++ return true; ++} ++ ++static void mptcp_mp_fail_rcvd(struct sock *sk, const struct tcphdr *th) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX); ++ mptcp->rx_opt.mp_fail = 0; ++ ++ if (!th->rst && !mpcb->infinite_mapping_snd) { ++ mpcb->send_infinite_mapping = 1; ++ ++ mptcp_restart_sending(meta_sk); ++ ++ mptcp_fallback_close(mpcb, sk); ++ } ++} ++ ++static inline void mptcp_path_array_check(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (unlikely(mpcb->list_rcvd)) { ++ mpcb->list_rcvd = 0; ++ if (mpcb->pm_ops->new_remote_address) ++ mpcb->pm_ops->new_remote_address(meta_sk); ++ } ++} ++ ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ if (tp->mpcb->infinite_mapping_rcv || tp->mpcb->infinite_mapping_snd) ++ return false; ++ ++ if (mptcp_mp_fastclose_rcvd(sk)) ++ return true; ++ ++ if (sk->sk_state == TCP_RST_WAIT && !th->rst) ++ return true; ++ ++ if (unlikely(mopt->mp_fail)) ++ mptcp_mp_fail_rcvd(sk, th); ++ ++ /* RFC 6824, Section 3.3: ++ * If a checksum is not present when its use has been negotiated, the ++ * receiver MUST close the subflow with a RST as it is considered broken. ++ */ ++ if (mptcp_is_data_seq(skb) && tp->mpcb->dss_csum && ++ !(TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_DSS_CSUM)) { ++ mptcp_send_reset(sk); ++ return true; ++ } ++ ++ /* We have to acknowledge retransmissions of the third ++ * ack. ++ */ ++ if (mopt->join_ack) { ++ tcp_send_delayed_ack(sk); ++ mopt->join_ack = 0; ++ } ++ ++ if (mopt->saw_add_addr || mopt->saw_rem_addr) { ++ if (mopt->more_add_addr || mopt->more_rem_addr) { ++ mptcp_parse_addropt(skb, sk); ++ } else { ++ if (mopt->saw_add_addr) ++ mptcp_handle_add_addr(mopt->add_addr_ptr, sk); ++ if (mopt->saw_rem_addr) ++ mptcp_handle_rem_addr(mopt->rem_addr_ptr, sk); ++ } ++ ++ mopt->more_add_addr = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->saw_rem_addr = 0; ++ } ++ if (mopt->saw_low_prio) { ++ if (mopt->saw_low_prio == 1) { ++ tp->mptcp->rcv_low_prio = mopt->low_prio; ++ if (mpcb->pm_ops->prio_changed) ++ mpcb->pm_ops->prio_changed(sk, mopt->low_prio); ++ } else { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ if (mptcp->rem_id == mopt->prio_addr_id) { ++ mptcp->rcv_low_prio = mopt->low_prio; ++ if (mpcb->pm_ops->prio_changed) ++ mpcb->pm_ops->prio_changed(sk, ++ mopt->low_prio); ++ } ++ } ++ } ++ mopt->saw_low_prio = 0; ++ } ++ ++ mptcp_data_ack(sk, skb); ++ ++ mptcp_path_array_check(mptcp_meta_sk(sk)); ++ /* Socket may have been mp_killed by a REMOVE_ADDR */ ++ if (tp->mp_killed) ++ return true; ++ ++ return false; ++} ++ ++static void _mptcp_rcv_synsent_fastopen(struct sock *meta_sk, ++ struct sk_buff *skb, bool rtx_queue) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ u32 new_mapping = meta_tp->write_seq - master_tp->snd_una; ++ ++ /* If the server only acknowledges partially the data sent in ++ * the SYN, we need to trim the acknowledged part because ++ * we don't want to retransmit this already received data. ++ * When we reach this point, tcp_ack() has already cleaned up ++ * fully acked segments. However, tcp trims partially acked ++ * segments only when retransmitting. Since MPTCP comes into ++ * play only now, we will fake an initial transmit, and ++ * retransmit_skb() will not be called. The following fragment ++ * comes from __tcp_retransmit_skb(). ++ */ ++ if (before(TCP_SKB_CB(skb)->seq, master_tp->snd_una)) { ++ BUG_ON(before(TCP_SKB_CB(skb)->end_seq, ++ master_tp->snd_una)); ++ /* tcp_trim_head can only returns ENOMEM if skb is ++ * cloned. It is not the case here (see ++ * tcp_send_syn_data). ++ */ ++ BUG_ON(tcp_trim_head(meta_sk, skb, master_tp->snd_una - ++ TCP_SKB_CB(skb)->seq)); ++ } ++ ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ ++ list_del(&skb->tcp_tsorted_anchor); ++ ++ if (rtx_queue) ++ tcp_rtx_queue_unlink(skb, meta_sk); ++ else ++ tcp_unlink_write_queue(skb, meta_sk); ++ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ ++ tcp_add_write_queue_tail(meta_sk, skb); ++} ++ ++/* In case of fastopen, some data can already be in the write queue. ++ * We need to update the sequence number of the segments as they ++ * were initially TCP sequence numbers. ++ */ ++static void mptcp_rcv_synsent_fastopen(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ struct sk_buff *skb_write_head, *skb_rtx_head, *tmp; ++ ++ skb_write_head = tcp_write_queue_head(meta_sk); ++ skb_rtx_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!(skb_write_head || skb_rtx_head)) ++ return; ++ ++ /* There should only be one skb in {write, rtx} queue: the data not ++ * acknowledged in the SYN+ACK. In this case, we need to map ++ * this data to data sequence numbers. ++ */ ++ ++ WARN_ON(skb_write_head && skb_rtx_head); ++ ++ if (skb_write_head) { ++ skb_queue_walk_from_safe(&meta_sk->sk_write_queue, ++ skb_write_head, tmp) { ++ _mptcp_rcv_synsent_fastopen(meta_sk, skb_write_head, ++ false); ++ } ++ } ++ ++ if (skb_rtx_head) { ++ skb_rbtree_walk_from_safe(skb_rtx_head, tmp) { ++ _mptcp_rcv_synsent_fastopen(meta_sk, skb_rtx_head, ++ true); ++ } ++ } ++ ++ /* We can advance write_seq by the number of bytes unacknowledged ++ * and that were mapped in the previous loop. ++ */ ++ meta_tp->write_seq += master_tp->write_seq - master_tp->snd_una; ++ ++ /* The packets from the master_sk will be entailed to it later ++ * Until that time, its write queue is empty, and ++ * write_seq must align with snd_una ++ */ ++ master_tp->snd_nxt = master_tp->write_seq = master_tp->snd_una; ++ master_tp->packets_out = 0; ++} ++ ++/* The skptr is needed, because if we become MPTCP-capable, we have to switch ++ * from meta-socket to master-socket. ++ * ++ * @return: 1 - we want to reset this connection ++ * 2 - we want to discard the received syn/ack ++ * 0 - everything is fine - continue ++ */ ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (mptcp(tp)) { ++ u8 hash_mac_check[20]; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce); ++ if (memcmp(hash_mac_check, ++ (char *)&tp->mptcp->rx_opt.mptcp_recv_tmac, 8)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKMAC); ++ mptcp_sub_force_close(sk); ++ return 1; ++ } ++ ++ /* Set this flag in order to postpone data sending ++ * until the 4th ack arrives. ++ */ ++ tp->mptcp->pre_established = 1; ++ tp->mptcp->rcv_low_prio = tp->mptcp->rx_opt.low_prio; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)&tp->mptcp->sender_mac[0], 2, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX); ++ } else if (mopt->saw_mpc) { ++ struct sock *meta_sk = sk; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); ++ if (mopt->mptcp_ver > tcp_sk(sk)->mptcp_ver) ++ /* TODO Consider adding new MPTCP_INC_STATS entry */ ++ goto fallback; ++ ++ if (mptcp_create_master_sk(sk, mopt->mptcp_sender_key, ++ mopt->mptcp_ver, ++ ntohs(tcp_hdr(skb)->window))) ++ return 2; ++ ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ *skptr = sk; ++ tp = tcp_sk(sk); ++ ++ /* If fastopen was used data might be in the send queue. We ++ * need to update their sequence number to MPTCP-level seqno. ++ * Note that it can happen in rare cases that fastopen_req is ++ * NULL and syn_data is 0 but fastopen indeed occurred and ++ * data has been queued in the write queue (but not sent). ++ * Example of such rare cases: connect is non-blocking and ++ * TFO is configured to work without cookies. ++ */ ++ mptcp_rcv_synsent_fastopen(meta_sk); ++ ++ /* -1, because the SYN consumed 1 byte. In case of TFO, we ++ * start the subflow-sequence number as if the data of the SYN ++ * is not part of any mapping. ++ */ ++ tp->mptcp->snt_isn = tp->snd_una - 1; ++ tp->mpcb->dss_csum = mopt->dss_csum; ++ if (tp->mpcb->dss_csum) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMENABLED); ++ ++ tp->mptcp->include_mpc = 1; ++ ++ /* Ensure that fastopen is handled at the meta-level. */ ++ tp->fastopen_req = NULL; ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ bh_unlock_sock(sk); ++ /* hold in sk_clone_lock due to initialization to 2 */ ++ sock_put(sk); ++ } else { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEFALLBACK); ++fallback: ++ tp->request_mptcp = 0; ++ ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ ++ if (mptcp(tp)) ++ tp->mptcp->rcv_isn = TCP_SKB_CB(skb)->seq; ++ ++ return 0; ++} ++ ++/* Similar to tcp_should_expand_sndbuf */ ++bool mptcp_should_expand_sndbuf(const struct sock *sk) ++{ ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_tcp_sock *mptcp; ++ ++ /* We circumvent this check in tcp_check_space, because we want to ++ * always call sk_write_space. So, we reproduce the check here. ++ */ ++ if (!meta_sk->sk_socket || ++ !test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ return false; ++ ++ /* If the user specified a specific send buffer setting, do ++ * not modify it. ++ */ ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return false; ++ ++ /* If we are under global TCP memory pressure, do not expand. */ ++ if (tcp_under_memory_pressure(meta_sk)) ++ return false; ++ ++ /* If we are under soft global TCP memory pressure, do not expand. */ ++ if (sk_memory_allocated(meta_sk) >= sk_prot_mem_limits(meta_sk, 0)) ++ return false; ++ ++ /* For MPTCP we look for a subsocket that could send data. ++ * If we found one, then we update the send-buffer. ++ */ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ const struct sock *sk_it = mptcp_to_sock(mptcp); ++ const struct tcp_sock *tp_it = tcp_sk(sk_it); ++ ++ if (!mptcp_sk_can_send(sk_it)) ++ continue; ++ ++ if (tcp_packets_in_flight(tp_it) < tp_it->snd_cwnd) ++ return true; ++ } ++ ++ return false; ++} ++ ++void mptcp_tcp_set_rto(struct sock *sk) ++{ ++ tcp_set_rto(sk); ++ mptcp_set_rto(sk); ++} +diff -aurN linux-4.19.104/net/mptcp/mptcp_ipv4.c mptcp-mptcp_v0.95/net/mptcp/mptcp_ipv4.c +--- linux-4.19.104/net/mptcp/mptcp_ipv4.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_ipv4.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,427 @@ ++/* ++ * MPTCP implementation - IPv4-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) ++{ ++ return siphash_4u32((__force u32)saddr, (__force u32)daddr, ++ (__force u32)sport << 16 | (__force u32)dport, ++ mptcp_seed++, &mptcp_secret); ++} ++ ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed) ++{ ++ return siphash_2u64((__force u64)saddr << 32 | (__force u64)daddr, ++ (__force u64)seed << 32 | (__force u64)sport << 16 | (__force u64)dport, ++ &mptcp_secret); ++} ++ ++ ++static void mptcp_v4_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v4_reqsk_destructor(req); ++} ++ ++static int mptcp_v4_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v4_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v4_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++/* May be called without holding the meta-level lock */ ++static int mptcp_v4_join_init_req(struct request_sock *req, const struct sock *meta_sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv4_ops.init_req(req, meta_sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v4_get_nonce(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.ip = inet_rsk(req)->ir_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(meta_sk, AF_INET, &addr, &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp_request_sock_ops */ ++struct request_sock_ops mptcp_request_sock_ops __read_mostly = { ++ .family = PF_INET, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v4_reqsk_send_ack, ++ .destructor = mptcp_v4_reqsk_destructor, ++ .send_reset = tcp_v4_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v4_conn_request ++ * May be called without holding the meta-level lock ++ */ ++static int mptcp_v4_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_join_request_sock_ipv4_ops, ++ meta_sk, skb); ++} ++ ++/* Similar to: tcp_v4_do_rcv ++ * We only process join requests here. (either the SYN or the final ACK) ++ */ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct iphdr *iph = ip_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = inet_lookup_established(sock_net(meta_sk), &tcp_hashinfo, ++ iph->saddr, th->source, iph->daddr, ++ th->dest, inet_iif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ bool req_stolen; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false, &req_stolen); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v4_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v4_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v4_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v4_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv4 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int __mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ __be16 sport, struct mptcp_rem4 *rem, ++ struct sock **subsk) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ ret = mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL); ++ if (ret) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ timer_setup(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, 0); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin_family = AF_INET; ++ rem_in.sin_family = AF_INET; ++ loc_in.sin_port = sport; ++ if (rem->port) ++ rem_in.sin_port = rem->port; ++ else ++ rem_in.sin_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin_addr = loc->addr; ++ rem_in.sin_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI4 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d ifidx: %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin_addr, ++ ntohs(loc_in.sin_port), &rem_in.sin_addr, ++ ntohs(rem_in.sin_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ if (subsk) ++ *subsk = sk; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(__mptcp_init4_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v4_specific = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v4_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ip_setsockopt, ++ .getsockopt = ip_getsockopt, ++ .addr2sockaddr = inet_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ip_setsockopt, ++ .compat_getsockopt = compat_ip_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++/* General initialization of IPv4 for MPTCP */ ++int mptcp_pm_v4_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp_request_sock_ops; ++ ++ mptcp_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_request_sock_ipv4_ops.init_req = mptcp_v4_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv4_ops.cookie_init_seq = mptcp_v4_cookie_init_seq; ++#endif ++ mptcp_join_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_join_request_sock_ipv4_ops.init_req = mptcp_v4_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v4_undo(void) ++{ ++ kmem_cache_destroy(mptcp_request_sock_ops.slab); ++ kfree(mptcp_request_sock_ops.slab_name); ++} +diff -aurN linux-4.19.104/net/mptcp/mptcp_ipv6.c mptcp-mptcp_v0.95/net/mptcp/mptcp_ipv6.c +--- linux-4.19.104/net/mptcp/mptcp_ipv6.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_ipv6.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,475 @@ ++/* ++ * MPTCP implementation - IPv6-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = mptcp_seed++, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = seed, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++static void mptcp_v6_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v6_reqsk_destructor(req); ++} ++ ++static int mptcp_v6_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v6_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v6_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++/* May be called without holding the meta-level lock */ ++static int mptcp_v6_join_init_req(struct request_sock *req, const struct sock *meta_sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv6_ops.init_req(req, meta_sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v6_get_nonce(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.in6 = inet_rsk(req)->ir_v6_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(meta_sk, AF_INET6, &addr, &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp6_request_sock_ops */ ++struct request_sock_ops mptcp6_request_sock_ops __read_mostly = { ++ .family = AF_INET6, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v6_reqsk_send_ack, ++ .destructor = mptcp_v6_reqsk_destructor, ++ .send_reset = tcp_v6_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v6_conn_request ++ * May be called without holding the meta-level lock ++ */ ++static int mptcp_v6_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_join_request_sock_ipv6_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = __inet6_lookup_established(sock_net(meta_sk), ++ &tcp_hashinfo, ++ &ip6h->saddr, th->source, ++ &ip6h->daddr, ntohs(th->dest), ++ tcp_v6_iif(skb), tcp_v6_sdif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ bool req_stolen; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false, &req_stolen); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v6_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v6_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v6_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v6_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv6 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int __mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ __be16 sport, struct mptcp_rem6 *rem, ++ struct sock **subsk) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in6 loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet6_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet6_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ ret = mptcp_add_sock(meta_sk, sk, loc->loc6_id, rem->rem6_id, GFP_KERNEL); ++ if (ret) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ timer_setup(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, 0); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin6_family = AF_INET6; ++ rem_in.sin6_family = AF_INET6; ++ loc_in.sin6_port = sport; ++ if (rem->port) ++ rem_in.sin6_port = rem->port; ++ else ++ rem_in.sin6_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin6_addr = loc->addr; ++ rem_in.sin6_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in6)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI6 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin6_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI6:%d dst_addr:%pI6:%d ifidx: %u\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin6_addr, ++ ntohs(loc_in.sin6_port), &rem_in.sin6_addr, ++ ntohs(rem_in.sin6_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in6), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ if (subsk) ++ *subsk = sk; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(__mptcp_init6_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v6_specific = { ++ .queue_xmit = inet6_csk_xmit, ++ .send_check = tcp_v6_send_check, ++ .rebuild_header = inet6_sk_rebuild_header, ++ .sk_rx_dst_set = inet6_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct ipv6hdr), ++ .net_frag_header_len = sizeof(struct frag_hdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v6_mtu_reduced, ++}; ++ ++const struct inet_connection_sock_af_ops mptcp_v6_mapped = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_pm_v6_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp6_request_sock_ops; ++ ++ mptcp_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_request_sock_ipv6_ops.init_req = mptcp_v6_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv6_ops.cookie_init_seq = mptcp_v6_cookie_init_seq; ++#endif ++ ++ mptcp_join_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_join_request_sock_ipv6_ops.init_req = mptcp_v6_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP6"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v6_undo(void) ++{ ++ kmem_cache_destroy(mptcp6_request_sock_ops.slab); ++ kfree(mptcp6_request_sock_ops.slab_name); ++} +diff -aurN linux-4.19.104/net/mptcp/mptcp_ndiffports.c mptcp-mptcp_v0.95/net/mptcp/mptcp_ndiffports.c +--- linux-4.19.104/net/mptcp/mptcp_ndiffports.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_ndiffports.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,174 @@ ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct ndiffports_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++}; ++ ++static int num_subflows __read_mostly = 2; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per MPTCP connection"); ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct ndiffports_priv *pm_priv = container_of(work, ++ struct ndiffports_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (num_subflows > iter && num_subflows > mptcp_subflow_count(mpcb)) { ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ } else { ++#if IS_ENABLED(CONFIG_IPV6) ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_init6_subsockets(meta_sk, &loc, &rem); ++#endif ++ } ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void ndiffports_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *fmp = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++} ++ ++static void ndiffports_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *pm_priv = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int ndiffports_get_local_id(const struct sock *meta_sk, ++ sa_family_t family, union inet_addr *addr, ++ bool *low_prio) ++{ ++ return 0; ++} ++ ++static struct mptcp_pm_ops ndiffports __read_mostly = { ++ .new_session = ndiffports_new_session, ++ .fully_established = ndiffports_create_subflows, ++ .get_local_id = ndiffports_get_local_id, ++ .name = "ndiffports", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init ndiffports_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ndiffports_priv) > MPTCP_PM_SIZE); ++ ++ if (mptcp_register_path_manager(&ndiffports)) ++ goto exit; ++ ++ return 0; ++ ++exit: ++ return -1; ++} ++ ++static void ndiffports_unregister(void) ++{ ++ mptcp_unregister_path_manager(&ndiffports); ++} ++ ++module_init(ndiffports_register); ++module_exit(ndiffports_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("NDIFF-PORTS MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_netlink.c mptcp-mptcp_v0.95/net/mptcp/mptcp_netlink.c +--- linux-4.19.104/net/mptcp/mptcp_netlink.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_netlink.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,1277 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP implementation - Netlink Path Manager ++ * ++ * Analysis, Design and Implementation: ++ * - Gregory Detal ++ * - Sébastien Barré ++ * - Matthieu Baerts ++ * - Pau Espin Pedrol ++ * - Detlev Casanova ++ * - David Verbeiren ++ * - Frank Vanbever ++ * - Antoine Maes ++ * - Tim Froidcoeur ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++#define MPTCP_MAX_ADDR 8 ++ ++struct mptcp_nl_priv { ++ /* Unfortunately we need to store this to generate MP_JOINs in case ++ * of the peer generating a subflow (see get_local_id). ++ */ ++ u8 loc4_bits; ++ u8 announced4; ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ u8 loc6_bits; ++ u8 announced6; ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++#endif ++ ++ u16 remove_addrs; ++ ++ bool is_closed; ++}; ++ ++static struct genl_family mptcp_genl_family; ++ ++#define MPTCP_GENL_EV_GRP_OFFSET 0 ++#define MPTCP_GENL_CMD_GRP_OFFSET 1 ++ ++static const struct genl_multicast_group mptcp_mcgrps[] = { ++ [MPTCP_GENL_EV_GRP_OFFSET] = { .name = MPTCP_GENL_EV_GRP_NAME, }, ++ [MPTCP_GENL_CMD_GRP_OFFSET] = { .name = MPTCP_GENL_CMD_GRP_NAME, }, ++}; ++ ++static const struct nla_policy mptcp_nl_genl_policy[MPTCP_ATTR_MAX + 1] = { ++ [MPTCP_ATTR_TOKEN] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_FAMILY] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_LOC_ID] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_REM_ID] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_SADDR4] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_SADDR6] = { .type = NLA_BINARY, ++ .len = sizeof(struct in6_addr), }, ++ [MPTCP_ATTR_DADDR4] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_DADDR6] = { .type = NLA_BINARY, ++ .len = sizeof(struct in6_addr), }, ++ [MPTCP_ATTR_SPORT] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_DPORT] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_BACKUP] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_TIMEOUT] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_IF_IDX] = { .type = NLA_S32, }, ++}; ++ ++/* Defines the userspace PM filter on events. Set events are ignored. */ ++static u16 mptcp_nl_event_filter; ++ ++static inline struct mptcp_nl_priv * ++mptcp_nl_priv(const struct sock *meta_sk) ++{ ++ return (struct mptcp_nl_priv *)&tcp_sk(meta_sk)->mpcb->mptcp_pm[0]; ++} ++ ++static inline bool ++mptcp_nl_must_notify(u16 event, const struct sock *meta_sk) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ ++ /* close_session() can be called before other events because it is ++ * also called when doing a fallback to TCP. We don't want to send ++ * events to the user-space after having sent the CLOSED event. ++ */ ++ if (priv->is_closed) ++ return false; ++ ++ if (event == MPTCPF_EVENT_CLOSED) ++ priv->is_closed = true; ++ ++ if (mptcp_nl_event_filter & event) ++ return false; ++ ++ if (!genl_has_listeners(&mptcp_genl_family, sock_net(meta_sk), 0)) ++ return false; ++ ++ return true; ++} ++ ++/* Find the first free index in the bitfield starting from 0 */ ++static int ++mptcp_nl_find_free_index(u8 bitfield) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ return -1; ++ ++ i = ffs(~bitfield) - 1; ++ if (i < 0) ++ return -1; ++ ++ return i; ++} ++ ++static inline int ++mptcp_nl_put_subsk(struct sk_buff *msg, struct sock *sk) ++{ ++ struct inet_sock *isk = inet_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ u8 backup; ++ u8 sk_err; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_FAMILY, sk->sk_family)) ++ goto nla_put_failure; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_LOC_ID, tcp_sk(sk)->mptcp->loc_id)) ++ goto nla_put_failure; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, tcp_sk(sk)->mptcp->rem_id)) ++ goto nla_put_failure; ++ ++ switch (sk->sk_family) { ++ case AF_INET: ++ if (nla_put_u32(msg, MPTCP_ATTR_SADDR4, isk->inet_saddr)) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, MPTCP_ATTR_DADDR4, isk->inet_daddr)) ++ goto nla_put_failure; ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ if (nla_put(msg, MPTCP_ATTR_SADDR6, sizeof(np->saddr), ++ &np->saddr)) ++ goto nla_put_failure; ++ ++ if (nla_put(msg, MPTCP_ATTR_DADDR6, sizeof(sk->sk_v6_daddr), ++ &sk->sk_v6_daddr)) ++ goto nla_put_failure; ++ break; ++ } ++#endif ++ default: ++ goto nla_put_failure; ++ } ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_SPORT, ntohs(isk->inet_sport))) ++ goto nla_put_failure; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_DPORT, ntohs(isk->inet_dport))) ++ goto nla_put_failure; ++ ++ backup = !!(tcp_sk(sk)->mptcp->rcv_low_prio || ++ tcp_sk(sk)->mptcp->low_prio); ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_BACKUP, backup)) ++ goto nla_put_failure; ++ ++ if (nla_put_s32(msg, MPTCP_ATTR_IF_IDX, sk->sk_bound_dev_if)) ++ goto nla_put_failure; ++ ++ sk_err = sk->sk_err ? : tcp_sk(sk)->mptcp->sk_err; ++ if (unlikely(sk_err != 0) && meta_sk->sk_state == TCP_ESTABLISHED && ++ nla_put_u8(msg, MPTCP_ATTR_ERROR, sk_err)) ++ goto nla_put_failure; ++ ++ return 0; ++ ++nla_put_failure: ++ return -1; ++} ++ ++static inline struct sk_buff * ++mptcp_nl_mcast_prepare(struct mptcp_cb *mpcb, struct sock *sk, int cmd, ++ void **hdr) ++{ ++ struct sk_buff *msg; ++ ++ /* possible optimisation: use the needed size */ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); ++ if (!msg) ++ return NULL; ++ ++ *hdr = genlmsg_put(msg, 0, 0, &mptcp_genl_family, 0, cmd); ++ if (!*hdr) ++ goto free_msg; ++ ++ if (nla_put_u32(msg, MPTCP_ATTR_TOKEN, mpcb->mptcp_loc_token)) ++ goto nla_put_failure; ++ ++ if (sk && mptcp_nl_put_subsk(msg, sk)) ++ goto nla_put_failure; ++ ++ return msg; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, *hdr); ++free_msg: ++ nlmsg_free(msg); ++ return NULL; ++} ++ ++static inline int ++mptcp_nl_mcast_send(struct mptcp_cb *mpcb, struct sk_buff *msg, void *hdr) ++{ ++ int ret; ++ struct sock *meta_sk = mpcb->meta_sk; ++ ++ genlmsg_end(msg, hdr); ++ ++ ret = genlmsg_multicast_netns(&mptcp_genl_family, sock_net(meta_sk), ++ msg, 0, MPTCP_GENL_EV_GRP_OFFSET, ++ GFP_ATOMIC); ++ if (ret && ret != -ESRCH) ++ pr_err("%s: genlmsg_multicast failed with %d\n", __func__, ret); ++ return ret; ++} ++ ++static inline void ++mptcp_nl_mcast(struct mptcp_cb *mpcb, struct sock *sk, int cmd) ++{ ++ void *hdr; ++ struct sk_buff *msg; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, sk, cmd, &hdr); ++ if (msg) ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ else ++ pr_warn("%s: unable to prepare multicast message\n", __func__); ++} ++ ++static inline void ++mptcp_nl_mcast_fail(struct sk_buff *msg, void *hdr) ++{ ++ genlmsg_cancel(msg, hdr); ++ nlmsg_free(msg); ++} ++ ++static void ++mptcp_nl_new(const struct sock *meta_sk, bool established) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mptcp_nl_mcast(mpcb, mpcb->master_sk, ++ established ? MPTCP_EVENT_ESTABLISHED ++ : MPTCP_EVENT_CREATED); ++} ++ ++static void ++mptcp_nl_pm_new_session(const struct sock *meta_sk) ++{ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_CREATED, meta_sk)) ++ return; ++ ++ mptcp_nl_new(meta_sk, false); ++} ++ ++static inline int ++mptcp_nl_loc_id_to_index_lookup(struct sock *meta_sk, sa_family_t family, ++ u8 addr_id) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ int i; ++ ++ switch (family) { ++ case AF_INET: ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == addr_id) ++ return i; ++ } ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == addr_id) ++ return i; ++ } ++ break; ++#endif ++ } ++ return -1; ++} ++ ++static inline void ++mptcp_nl_sk_setup_locaddr(struct sock *meta_sk, struct sock *sk) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ bool backup = !!(tcp_sk(sk)->mptcp->rcv_low_prio || ++ tcp_sk(sk)->mptcp->low_prio); ++ sa_family_t family = mptcp_v6_is_v4_mapped(sk) ? AF_INET ++ : sk->sk_family; ++ u8 addr_id = tcp_sk(sk)->mptcp->loc_id; ++ int idx = mptcp_nl_loc_id_to_index_lookup(meta_sk, family, ++ addr_id); ++ ++ /* Same as in mptcp_fullmesh.c: exception for transparent sockets */ ++ int if_idx = inet_sk(sk)->transparent ? inet_sk(sk)->rx_dst_ifindex : ++ sk->sk_bound_dev_if; ++ ++ switch (family) { ++ case AF_INET: { ++ struct inet_sock *isk = inet_sk(sk); ++ ++ if (idx == -1) ++ idx = mptcp_nl_find_free_index(priv->loc4_bits); ++ if (idx == -1) { ++ pr_warn("No free index for sk loc_id v4\n"); ++ return; ++ } ++ priv->locaddr4[idx].addr.s_addr = isk->inet_saddr; ++ priv->locaddr4[idx].loc4_id = addr_id; ++ priv->locaddr4[idx].low_prio = backup; ++ priv->locaddr4[idx].if_idx = if_idx; ++ priv->loc4_bits |= 1 << idx; ++ priv->announced4 |= 1 << idx; ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ if (idx == -1) ++ idx = mptcp_nl_find_free_index(priv->loc6_bits); ++ if (idx == -1) { ++ pr_warn("No free index for sk loc_id v6\n"); ++ return; ++ } ++ priv->locaddr6[idx].addr = np->saddr; ++ priv->locaddr6[idx].loc6_id = addr_id; ++ priv->locaddr6[idx].low_prio = backup; ++ priv->locaddr6[idx].if_idx = if_idx; ++ priv->loc6_bits |= 1 << idx; ++ priv->announced6 |= 1 << idx; ++ break; ++ } ++#endif ++ } ++} ++ ++static void ++mptcp_nl_pm_fully_established(struct sock *meta_sk) ++{ ++ mptcp_nl_sk_setup_locaddr(meta_sk, tcp_sk(meta_sk)->mpcb->master_sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_ESTABLISHED, meta_sk)) ++ return; ++ ++ mptcp_nl_new(meta_sk, true); ++} ++ ++static void ++mptcp_nl_pm_close_session(struct sock *meta_sk) ++{ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_CLOSED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, NULL, MPTCP_EVENT_CLOSED); ++} ++ ++static void ++mptcp_nl_pm_established_subflow(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mptcp_nl_sk_setup_locaddr(meta_sk, sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_ESTABLISHED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_ESTABLISHED); ++} ++ ++static void ++mptcp_nl_pm_delete_subflow(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_CLOSED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_CLOSED); ++} ++ ++static void ++mptcp_nl_pm_add_raddr(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_ANNOUNCED, mpcb->meta_sk)) ++ return; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, NULL, MPTCP_EVENT_ANNOUNCED, &hdr); ++ if (!msg) ++ return; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, id)) ++ goto nla_put_failure; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_FAMILY, family)) ++ goto nla_put_failure; ++ ++ switch (family) { ++ case AF_INET: ++ if (nla_put_u32(msg, MPTCP_ATTR_DADDR4, addr->ip)) ++ goto nla_put_failure; ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ if (nla_put(msg, MPTCP_ATTR_DADDR6, sizeof(addr->ip6), ++ &addr->ip6)) ++ goto nla_put_failure; ++ break; ++#endif ++ default: ++ goto nla_put_failure; ++ } ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_DPORT, ntohs(port))) ++ goto nla_put_failure; ++ ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ ++ return; ++ ++nla_put_failure: ++ mptcp_nl_mcast_fail(msg, hdr); ++} ++ ++static void ++mptcp_nl_pm_rem_raddr(struct mptcp_cb *mpcb, u8 id) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_REMOVED, mpcb->meta_sk)) ++ return; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, NULL, MPTCP_EVENT_REMOVED, &hdr); ++ ++ if (!msg) ++ return; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, id)) ++ goto nla_put_failure; ++ ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ ++ return; ++ ++nla_put_failure: ++ mptcp_nl_mcast_fail(msg, hdr); ++} ++ ++static int ++mptcp_nl_pm_get_local_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ int i, id = 0; ++ ++ switch (family) { ++ case AF_INET: ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (addr->in.s_addr == priv->locaddr4[i].addr.s_addr) { ++ id = priv->locaddr4[i].loc4_id; ++ *low_prio = priv->locaddr4[i].low_prio; ++ goto out; ++ } ++ } ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (ipv6_addr_equal(&addr->in6, ++ &priv->locaddr6[i].addr)) { ++ id = priv->locaddr6[i].loc6_id; ++ *low_prio = priv->locaddr6[i].low_prio; ++ goto out; ++ } ++ } ++ break; ++#endif ++ } ++ return -1; ++ ++out: ++ return id; ++} ++ ++static void ++mptcp_nl_pm_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ u8 unannounced; ++ int remove_addr_len; ++ ++ unannounced = (~priv->announced4) & priv->loc4_bits; ++ if (unannounced && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) { ++ int i = mptcp_nl_find_free_index(~unannounced); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = priv->locaddr4[i].loc4_id; ++ opts->add_addr4.addr = priv->locaddr4[i].addr; ++ opts->add_addr_v4 = 1; ++ ++ if (skb) ++ priv->announced4 |= (1 << i); ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ unannounced = (~priv->announced6) & priv->loc6_bits; ++ if (unannounced && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) { ++ int i = mptcp_nl_find_free_index(~unannounced); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = priv->locaddr6[i].loc6_id; ++ opts->add_addr6.addr = priv->locaddr6[i].addr; ++ opts->add_addr_v6 = 1; ++ ++ if (skb) ++ priv->announced6 |= (1 << i); ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ } ++#endif ++ ++ if (likely(!priv->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(priv->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = priv->remove_addrs; ++ ++ if (skb) ++ priv->remove_addrs = 0; ++ *size += remove_addr_len; ++ ++exit: ++ mpcb->addr_signal = !!((~priv->announced4) & priv->loc4_bits || ++#if IS_ENABLED(CONFIG_IPV6) ++ (~priv->announced6) & priv->loc6_bits || ++#endif ++ priv->remove_addrs); ++} ++ ++static void ++mptcp_nl_pm_prio_changed(struct sock *sk, int low_prio) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_PRIORITY, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_PRIORITY); ++} ++ ++static int ++mptcp_nl_genl_announce(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u8 addr_id, backup = 0; ++ u16 family; ++ int i, ret = 0; ++ union inet_addr saddr; ++ int if_idx = 0; ++ bool useless; /* unused out parameter "low_prio" */ ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_FAMILY] || ++ !info->attrs[MPTCP_ATTR_LOC_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ priv = mptcp_nl_priv(meta_sk); ++ family = nla_get_u16(info->attrs[MPTCP_ATTR_FAMILY]); ++ addr_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ ++ if (info->attrs[MPTCP_ATTR_BACKUP]) ++ backup = nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]); ++ ++ if (info->attrs[MPTCP_ATTR_IF_IDX]) ++ if_idx = nla_get_s32(info->attrs[MPTCP_ATTR_IF_IDX]); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ switch (family) { ++ case AF_INET: ++ if (!info->attrs[MPTCP_ATTR_SADDR4]) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ saddr.in.s_addr = nla_get_u32(info->attrs[MPTCP_ATTR_SADDR4]); ++ i = mptcp_nl_pm_get_local_id(meta_sk, family, ++ &saddr, &useless); ++ if (i < 0) { ++ i = mptcp_nl_find_free_index(priv->loc4_bits); ++ if (i < 0) { ++ ret = -ENOBUFS; ++ goto exit; ++ } ++ } else if (i != addr_id) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv->locaddr4[i].addr.s_addr = saddr.in.s_addr; ++ priv->locaddr4[i].loc4_id = addr_id; ++ priv->locaddr4[i].low_prio = !!backup; ++ priv->locaddr4[i].if_idx = if_idx; ++ priv->loc4_bits |= 1 << i; ++ priv->announced4 &= ~(1 << i); ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ if (!info->attrs[MPTCP_ATTR_SADDR6]) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ saddr.in6 = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_SADDR6]); ++ i = mptcp_nl_pm_get_local_id(meta_sk, family, &saddr, &useless); ++ if (i < 0) { ++ i = mptcp_nl_find_free_index(priv->loc6_bits); ++ if (i < 0) { ++ ret = -ENOBUFS; ++ goto exit; ++ } ++ } else if (i != addr_id) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv->locaddr6[i].addr = saddr.in6; ++ priv->locaddr6[i].loc6_id = addr_id; ++ priv->locaddr6[i].low_prio = !!backup; ++ priv->locaddr6[i].if_idx = if_idx; ++ priv->loc6_bits |= 1 << i; ++ priv->announced6 &= ~(1 << i); ++ break; ++#endif ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ mpcb->addr_signal = 1; ++ ++ rcu_read_lock_bh(); ++ subsk = mptcp_select_ack_sock(meta_sk); ++ if (subsk) ++ tcp_send_ack(subsk); ++ rcu_read_unlock_bh(); ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_remove(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u8 addr_id; ++ int i; ++ int retcode; ++ bool found = false; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_LOC_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ priv = mptcp_nl_priv(meta_sk); ++ addr_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == addr_id) { ++ priv->loc4_bits &= ~(1 << i); ++ found = true; ++ break; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (!found) { ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == addr_id) { ++ priv->loc6_bits &= ~(1 << i); ++ found = true; ++ break; ++ } ++ } ++ } ++#endif ++ ++ if (found) { ++ priv->remove_addrs |= 1 << addr_id; ++ mpcb->addr_signal = 1; ++ ++ rcu_read_lock_bh(); ++ subsk = mptcp_select_ack_sock(meta_sk); ++ if (subsk) ++ tcp_send_ack(subsk); ++ rcu_read_unlock_bh(); ++ retcode = 0; ++ } else { ++ retcode = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return retcode; ++} ++ ++static int ++mptcp_nl_genl_create(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk = NULL; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u16 family, sport; ++ u8 loc_id, rem_id, backup = 0; ++ int i, ret = 0; ++ int if_idx; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_FAMILY] || ++ !info->attrs[MPTCP_ATTR_LOC_ID] || !info->attrs[MPTCP_ATTR_REM_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ /* We use a more specific value than EINVAL here so that ++ * userspace can handle this specific case easily. This is ++ * useful to check the case in which userspace tries to create a ++ * subflow for a connection which was already destroyed recently ++ * in kernelspace, but userspace didn't have time to realize ++ * about it because there is a gap of time between kernel ++ * destroying the connection and userspace receiving the event ++ * through Netlink. It can easily happen for short life-time ++ * conns. ++ */ ++ return -EBADR; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Same as for the EBADR case. In this case, though, we know for ++ * sure the conn owner of the subflow existed at some point (no ++ * invalid token possibility) ++ */ ++ ret = -EOWNERDEAD; ++ goto unlock; ++ } ++ ++ if (!mptcp_can_new_subflow(meta_sk)) { ++ /* Same as for the EBADR and EOWNERDEAD case but here, the MPTCP ++ * session has just been stopped, it is no longer possible to ++ * create new subflows. ++ */ ++ ret = -ENOTCONN; ++ goto unlock; ++ } ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) { ++ /* First condition is not only in there for safely purposes, it ++ * can also be triggered in the same scenario as in EBADR and ++ * EOWNERDEAD ++ */ ++ ret = -EAGAIN; ++ goto unlock; ++ } ++ ++ priv = mptcp_nl_priv(meta_sk); ++ ++ family = nla_get_u16(info->attrs[MPTCP_ATTR_FAMILY]); ++ loc_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ rem_id = nla_get_u8(info->attrs[MPTCP_ATTR_REM_ID]); ++ ++ sport = info->attrs[MPTCP_ATTR_SPORT] ++ ? htons(nla_get_u16(info->attrs[MPTCP_ATTR_SPORT])) : 0; ++ backup = info->attrs[MPTCP_ATTR_BACKUP] ++ ? nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]) : 0; ++ if_idx = info->attrs[MPTCP_ATTR_IF_IDX] ++ ? nla_get_s32(info->attrs[MPTCP_ATTR_IF_IDX]) : 0; ++ ++ switch (family) { ++ case AF_INET: { ++ struct mptcp_rem4 rem = { ++ .rem4_id = rem_id, ++ }; ++ struct mptcp_loc4 loc = { ++ .loc4_id = loc_id, ++ }; ++ ++ if (!info->attrs[MPTCP_ATTR_DADDR4] || ++ !info->attrs[MPTCP_ATTR_DPORT]) { ++ goto create_failed; ++ } else { ++ rem.addr.s_addr = ++ nla_get_u32(info->attrs[MPTCP_ATTR_DADDR4]); ++ rem.port = ++ ntohs(nla_get_u16(info->attrs[MPTCP_ATTR_DPORT])); ++ } ++ ++ if (!info->attrs[MPTCP_ATTR_SADDR4]) { ++ bool found = false; ++ ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == loc_id) { ++ loc.addr = priv->locaddr4[i].addr; ++ loc.low_prio = ++ priv->locaddr4[i].low_prio; ++ loc.if_idx = ++ priv->locaddr4[i].if_idx; ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto create_failed; ++ } else { ++ loc.addr.s_addr = ++ nla_get_u32(info->attrs[MPTCP_ATTR_SADDR4]); ++ loc.low_prio = backup; ++ loc.if_idx = if_idx; ++ } ++ ++ ret = __mptcp_init4_subsockets(meta_sk, &loc, sport, &rem, ++ &subsk); ++ if (ret < 0) ++ goto unlock; ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct mptcp_rem6 rem = { ++ .rem6_id = rem_id, ++ }; ++ struct mptcp_loc6 loc = { ++ .loc6_id = loc_id, ++ }; ++ ++ if (!info->attrs[MPTCP_ATTR_DADDR6] || ++ !info->attrs[MPTCP_ATTR_DPORT]) { ++ goto create_failed; ++ } else { ++ rem.addr = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_DADDR6]); ++ rem.port = ++ ntohs(nla_get_u16(info->attrs[MPTCP_ATTR_DPORT])); ++ } ++ ++ if (!info->attrs[MPTCP_ATTR_SADDR6]) { ++ bool found = false; ++ ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == loc_id) { ++ loc.addr = priv->locaddr6[i].addr; ++ loc.low_prio = ++ priv->locaddr6[i].low_prio; ++ loc.if_idx = ++ priv->locaddr6[i].if_idx; ++ ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto create_failed; ++ } else { ++ loc.addr = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_SADDR6]); ++ loc.low_prio = backup; ++ loc.if_idx = if_idx; ++ } ++ ++ ret = __mptcp_init6_subsockets(meta_sk, &loc, sport, &rem, ++ &subsk); ++ if (ret < 0) ++ goto unlock; ++ break; ++ } ++#endif ++ default: ++ goto create_failed; ++ } ++ ++unlock: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++ ++create_failed: ++ ret = -EINVAL; ++ goto unlock; ++} ++ ++static struct sock * ++mptcp_nl_subsk_lookup(struct mptcp_cb *mpcb, struct nlattr **attrs) ++{ ++ struct sock *sk; ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ u16 family; ++ __be16 sport, dport; ++ ++ if (!attrs[MPTCP_ATTR_FAMILY] || !attrs[MPTCP_ATTR_SPORT] || ++ !attrs[MPTCP_ATTR_DPORT]) ++ goto exit; ++ ++ family = nla_get_u16(attrs[MPTCP_ATTR_FAMILY]); ++ sport = htons(nla_get_u16(attrs[MPTCP_ATTR_SPORT])); ++ dport = htons(nla_get_u16(attrs[MPTCP_ATTR_DPORT])); ++ ++ switch (family) { ++ case AF_INET: { ++ __be32 saddr, daddr; ++ ++ if (!attrs[MPTCP_ATTR_SADDR4] || !attrs[MPTCP_ATTR_DADDR4]) ++ break; ++ ++ saddr = nla_get_u32(attrs[MPTCP_ATTR_SADDR4]); ++ daddr = nla_get_u32(attrs[MPTCP_ATTR_DADDR4]); ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ struct inet_sock *isk = inet_sk(subsk); ++ ++ if (subsk->sk_family != AF_INET) ++ continue; ++ ++ if (isk->inet_saddr == saddr && ++ isk->inet_daddr == daddr && ++ isk->inet_sport == sport && ++ isk->inet_dport == dport) { ++ sk = subsk; ++ goto found; ++ } ++ } ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct in6_addr saddr, daddr; ++ ++ if (!attrs[MPTCP_ATTR_SADDR6] || !attrs[MPTCP_ATTR_DADDR6]) ++ break; ++ ++ saddr = *(struct in6_addr *)nla_data(attrs[MPTCP_ATTR_SADDR6]); ++ daddr = *(struct in6_addr *)nla_data(attrs[MPTCP_ATTR_DADDR6]); ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ struct inet_sock *isk = inet_sk(subsk); ++ struct ipv6_pinfo *np; ++ ++ if (subsk->sk_family != AF_INET6) ++ continue; ++ ++ np = inet6_sk(subsk); ++ if (ipv6_addr_equal(&saddr, &np->saddr) && ++ ipv6_addr_equal(&daddr, &subsk->sk_v6_daddr) && ++ isk->inet_sport == sport && ++ isk->inet_dport == dport) { ++ sk = subsk; ++ goto found; ++ } ++ } ++ break; ++ } ++#endif ++ } ++ ++exit: ++ sk = NULL; ++found: ++ return sk; ++} ++ ++static int ++mptcp_nl_genl_destroy(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ int ret = 0; ++ u32 token; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ subsk = mptcp_nl_subsk_lookup(mpcb, info->attrs); ++ if (subsk) { ++ local_bh_disable(); ++ mptcp_reinject_data(subsk, 0); ++ mptcp_send_reset(subsk); ++ local_bh_enable(); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_conn_exists(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -ENOTCONN; ++ ++ sock_put(meta_sk); ++ return 0; ++} ++ ++static int ++mptcp_nl_genl_priority(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ int ret = 0; ++ u32 token; ++ u8 backup = 0; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ if (info->attrs[MPTCP_ATTR_BACKUP]) ++ backup = nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ subsk = mptcp_nl_subsk_lookup(mpcb, info->attrs); ++ if (subsk) { ++ tcp_sk(subsk)->mptcp->send_mp_prio = 1; ++ tcp_sk(subsk)->mptcp->low_prio = !!backup; ++ ++ local_bh_disable(); ++ if (mptcp_sk_can_send_ack(subsk)) ++ tcp_send_ack(subsk); ++ else ++ ret = -ENOTCONN; ++ local_bh_enable(); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_set_filter(struct sk_buff *skb, struct genl_info *info) ++{ ++ u16 flags; ++ ++ if (!info->attrs[MPTCP_ATTR_FLAGS]) ++ return -EINVAL; ++ ++ flags = nla_get_u16(info->attrs[MPTCP_ATTR_FLAGS]); ++ ++ /* Only want to receive events that correspond to these flags */ ++ mptcp_nl_event_filter = ~flags; ++ ++ return 0; ++} ++ ++static struct genl_ops mptcp_genl_ops[] = { ++ { ++ .cmd = MPTCP_CMD_ANNOUNCE, ++ .doit = mptcp_nl_genl_announce, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_REMOVE, ++ .doit = mptcp_nl_genl_remove, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_CREATE, ++ .doit = mptcp_nl_genl_create, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_DESTROY, ++ .doit = mptcp_nl_genl_destroy, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_PRIORITY, ++ .doit = mptcp_nl_genl_priority, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SET_FILTER, ++ .doit = mptcp_nl_genl_set_filter, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_EXIST, ++ .doit = mptcp_nl_genl_conn_exists, ++ .policy = mptcp_nl_genl_policy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++}; ++ ++static struct mptcp_pm_ops mptcp_nl_pm_ops = { ++ .new_session = mptcp_nl_pm_new_session, ++ .close_session = mptcp_nl_pm_close_session, ++ .fully_established = mptcp_nl_pm_fully_established, ++ .established_subflow = mptcp_nl_pm_established_subflow, ++ .delete_subflow = mptcp_nl_pm_delete_subflow, ++ .add_raddr = mptcp_nl_pm_add_raddr, ++ .rem_raddr = mptcp_nl_pm_rem_raddr, ++ .get_local_id = mptcp_nl_pm_get_local_id, ++ .addr_signal = mptcp_nl_pm_addr_signal, ++ .prio_changed = mptcp_nl_pm_prio_changed, ++ .name = "netlink", ++ .owner = THIS_MODULE, ++}; ++ ++static struct genl_family mptcp_genl_family = { ++ .hdrsize = 0, ++ .name = MPTCP_GENL_NAME, ++ .version = MPTCP_GENL_VER, ++ .maxattr = MPTCP_ATTR_MAX, ++ .netnsok = true, ++ .module = THIS_MODULE, ++ .ops = mptcp_genl_ops, ++ .n_ops = ARRAY_SIZE(mptcp_genl_ops), ++ .mcgrps = mptcp_mcgrps, ++ .n_mcgrps = ARRAY_SIZE(mptcp_mcgrps), ++}; ++ ++static int __init ++mptcp_nl_init(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct mptcp_nl_priv) > MPTCP_PM_SIZE); ++ ++ ret = genl_register_family(&mptcp_genl_family); ++ if (ret) ++ goto out_genl; ++ ++ ret = mptcp_register_path_manager(&mptcp_nl_pm_ops); ++ if (ret) ++ goto out_pm; ++ ++ return 0; ++out_pm: ++ genl_unregister_family(&mptcp_genl_family); ++out_genl: ++ return ret; ++} ++ ++static void __exit ++mptcp_nl_exit(void) ++{ ++ mptcp_unregister_path_manager(&mptcp_nl_pm_ops); ++ genl_unregister_family(&mptcp_genl_family); ++} ++ ++module_init(mptcp_nl_init); ++module_exit(mptcp_nl_exit); ++ ++MODULE_AUTHOR("Gregory Detal "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP netlink-based path manager"); ++MODULE_ALIAS_GENL_FAMILY(MPTCP_GENL_NAME); +diff -aurN linux-4.19.104/net/mptcp/mptcp_olia.c mptcp-mptcp_v0.95/net/mptcp/mptcp_olia.c +--- linux-4.19.104/net/mptcp/mptcp_olia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_olia.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,318 @@ ++/* ++ * MPTCP implementation - OPPORTUNISTIC LINKED INCREASES CONGESTION CONTROL: ++ * ++ * Algorithm design: ++ * Ramin Khalili ++ * Nicolas Gast ++ * Jean-Yves Le Boudec ++ * ++ * Implementation: ++ * Ramin Khalili ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++#include ++ ++static int scale = 10; ++ ++struct mptcp_olia { ++ u32 mptcp_loss1; ++ u32 mptcp_loss2; ++ u32 mptcp_loss3; ++ int epsilon_num; ++ u32 epsilon_den; ++ int mptcp_snd_cwnd_cnt; ++}; ++ ++static inline int mptcp_olia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_olia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++/* take care of artificially inflate (see RFC5681) ++ * of cwnd during fast-retransmit phase ++ */ ++static u32 mptcp_get_crt_cwnd(struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (icsk->icsk_ca_state == TCP_CA_Recovery) ++ return tcp_sk(sk)->snd_ssthresh; ++ else ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* return the dominator of the first term of the increasing term */ ++static u64 mptcp_get_rate(const struct mptcp_cb *mpcb , u32 path_rtt) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u64 rate = 1; /* We have to avoid a zero-rate because it is used as a divisor */ ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ u64 scaled_num; ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ scaled_num = mptcp_olia_scale(tmp_cwnd, scale) * path_rtt; ++ rate += div_u64(scaled_num , tp->srtt_us); ++ } ++ rate *= rate; ++ return rate; ++} ++ ++/* find the maximum cwnd, used to find set M */ ++static u32 mptcp_get_max_cwnd(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u32 best_cwnd = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd > best_cwnd) ++ best_cwnd = tmp_cwnd; ++ } ++ return best_cwnd; ++} ++ ++static void mptcp_get_epsilon(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct mptcp_olia *ca; ++ struct tcp_sock *tp; ++ struct sock *sk; ++ u64 tmp_int, tmp_rtt, best_int = 0, best_rtt = 1; ++ u32 max_cwnd, tmp_cwnd, established_cnt = 0; ++ u8 M = 0, B_not_M = 0; ++ ++ /* TODO - integrate this in the following loop - we just want to iterate once */ ++ ++ max_cwnd = mptcp_get_max_cwnd(mpcb); ++ ++ /* find the best path */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ established_cnt++; ++ ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ /* TODO - check here and rename variables */ ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt >= (u64)best_int * tmp_rtt) { ++ best_rtt = tmp_rtt; ++ best_int = tmp_int; ++ } ++ } ++ ++ /* TODO - integrate this here in mptcp_get_max_cwnd and in the previous loop */ ++ /* find the size of M and B_not_M */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd == max_cwnd) { ++ M++; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) ++ B_not_M++; ++ } ++ } ++ ++ /* check if the path is in M or B_not_M and set the value of epsilon accordingly */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ if (B_not_M == 0) { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ ++ if (tmp_cwnd < max_cwnd && ++ (u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) { ++ ca->epsilon_num = 1; ++ ca->epsilon_den = established_cnt * B_not_M; ++ } else if (tmp_cwnd == max_cwnd) { ++ ca->epsilon_num = -1; ++ ca->epsilon_den = established_cnt * M; ++ } else { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++ } ++ } ++} ++ ++/* setting the initial values */ ++static void mptcp_olia_init(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (mptcp(tp)) { ++ ca->mptcp_loss1 = tp->snd_una; ++ ca->mptcp_loss2 = tp->snd_una; ++ ca->mptcp_loss3 = tp->snd_una; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++} ++ ++/* updating inter-loss distance and ssthresh */ ++static void mptcp_olia_set_state(struct sock *sk, u8 new_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ if (new_state == TCP_CA_Loss || ++ new_state == TCP_CA_Recovery || new_state == TCP_CA_CWR) { ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (ca->mptcp_loss3 != ca->mptcp_loss2 && ++ !inet_csk(sk)->icsk_retransmits) { ++ ca->mptcp_loss1 = ca->mptcp_loss2; ++ ca->mptcp_loss2 = ca->mptcp_loss3; ++ } ++ } ++} ++ ++/* main algorithm */ ++static void mptcp_olia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ u64 inc_num, inc_den, rate, cwnd_scaled; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ ca->mptcp_loss3 = tp->snd_una; ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ /* slow start if it is in the safe area */ ++ if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ return; ++ } ++ ++ mptcp_get_epsilon(mpcb); ++ rate = mptcp_get_rate(mpcb, tp->srtt_us); ++ cwnd_scaled = mptcp_olia_scale(tp->snd_cwnd, scale); ++ inc_den = ca->epsilon_den * tp->snd_cwnd * rate ? : 1; ++ ++ /* calculate the increasing term, scaling is used to reduce the rounding effect */ ++ if (ca->epsilon_num == -1) { ++ if (ca->epsilon_den * cwnd_scaled * cwnd_scaled < rate) { ++ inc_num = rate - ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt -= div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } else { ++ inc_num = ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled - rate; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ } else { ++ inc_num = ca->epsilon_num * rate + ++ ca->epsilon_den * cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ ++ ++ if (ca->mptcp_snd_cwnd_cnt >= (1 << scale) - 1) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) ++ tp->snd_cwnd++; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } else if (ca->mptcp_snd_cwnd_cnt <= 0 - (1 << scale) + 1) { ++ tp->snd_cwnd = max((int) 1 , (int) tp->snd_cwnd - 1); ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_olia = { ++ .init = mptcp_olia_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_olia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .set_state = mptcp_olia_set_state, ++ .owner = THIS_MODULE, ++ .name = "olia", ++}; ++ ++static int __init mptcp_olia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_olia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_olia); ++} ++ ++static void __exit mptcp_olia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_olia); ++} ++ ++module_init(mptcp_olia_register); ++module_exit(mptcp_olia_unregister); ++ ++MODULE_AUTHOR("Ramin Khalili, Nicolas Gast, Jean-Yves Le Boudec"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP COUPLED CONGESTION CONTROL"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_output.c mptcp-mptcp_v0.95/net/mptcp/mptcp_output.c +--- linux-4.19.104/net/mptcp/mptcp_output.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_output.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,1929 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static const int mptcp_dss_len = MPTCP_SUB_LEN_DSS_ALIGN + ++ MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ ++static inline int mptcp_sub_len_remove_addr(u16 bitfield) ++{ ++ unsigned int c; ++ for (c = 0; bitfield; c++) ++ bitfield &= bitfield - 1; ++ return MPTCP_SUB_LEN_REMOVE_ADDR + c - 1; ++} ++ ++int mptcp_sub_len_remove_addr_align(u16 bitfield) ++{ ++ return ALIGN(mptcp_sub_len_remove_addr(bitfield), 4); ++} ++EXPORT_SYMBOL(mptcp_sub_len_remove_addr_align); ++ ++/* get the data-seq and end-data-seq and store them again in the ++ * tcp_skb_cb ++ */ ++static bool mptcp_reconstruct_mapping(struct sk_buff *skb) ++{ ++ const struct mp_dss *mpdss = (struct mp_dss *)TCP_SKB_CB(skb)->dss; ++ __be32 *p32; ++ __be16 *p16; ++ ++ if (!mptcp_is_data_seq(skb)) ++ return false; ++ ++ if (!mpdss->M) ++ return false; ++ ++ /* Move the pointer to the data-seq */ ++ p32 = (__be32 *)mpdss; ++ p32++; ++ if (mpdss->A) { ++ p32++; ++ if (mpdss->a) ++ p32++; ++ } ++ ++ TCP_SKB_CB(skb)->seq = ntohl(*p32); ++ ++ /* Get the data_len to calculate the end_data_seq */ ++ p32++; ++ p32++; ++ p16 = (__be16 *)p32; ++ TCP_SKB_CB(skb)->end_seq = ntohs(*p16) + TCP_SKB_CB(skb)->seq; ++ ++ return true; ++} ++ ++static bool mptcp_is_reinjected(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCP_REINJECT; ++} ++ ++static void mptcp_find_and_set_pathmask(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct rb_node **p = &meta_sk->tcp_rtx_queue.rb_node; ++ struct rb_node *parent; ++ struct sk_buff *skb_it; ++ ++ while (*p) { ++ parent = *p; ++ skb_it = rb_to_skb(parent); ++ if (before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb_it)->seq)) { ++ p = &parent->rb_left; ++ continue; ++ } ++ if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb_it)->seq)) { ++ p = &parent->rb_right; ++ continue; ++ } ++ ++ TCP_SKB_CB(skb)->path_mask = TCP_SKB_CB(skb_it)->path_mask; ++ break; ++ } ++} ++ ++/* Reinject data from one TCP subflow to the meta_sk. If sk == NULL, we are ++ * coming from the meta-retransmit-timer ++ */ ++static void __mptcp_reinject_data(struct sk_buff *orig_skb, struct sock *meta_sk, ++ struct sock *sk, int clone_it, ++ enum tcp_queue tcp_queue) ++{ ++ struct sk_buff *skb, *skb1; ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u32 seq, end_seq; ++ ++ if (clone_it) { ++ /* pskb_copy is necessary here, because the TCP/IP-headers ++ * will be changed when it's going to be reinjected on another ++ * subflow. ++ */ ++ tcp_skb_tsorted_save(orig_skb) { ++ skb = pskb_copy_for_clone(orig_skb, GFP_ATOMIC); ++ } tcp_skb_tsorted_restore(orig_skb); ++ } else { ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) { ++ __skb_unlink(orig_skb, &sk->sk_write_queue); ++ } else { ++ list_del(&orig_skb->tcp_tsorted_anchor); ++ tcp_rtx_queue_unlink(orig_skb, sk); ++ INIT_LIST_HEAD(&orig_skb->tcp_tsorted_anchor); ++ } ++ sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ sk->sk_wmem_queued -= orig_skb->truesize; ++ sk_mem_uncharge(sk, orig_skb->truesize); ++ skb = orig_skb; ++ } ++ if (unlikely(!skb)) ++ return; ++ ++ /* Make sure that this list is clean */ ++ tcp_skb_tsorted_anchor_cleanup(skb); ++ ++ if (sk && !mptcp_reconstruct_mapping(skb)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ skb->sk = meta_sk; ++ ++ /* Reset subflow-specific TCP control-data */ ++ TCP_SKB_CB(skb)->sacked = 0; ++ TCP_SKB_CB(skb)->tcp_flags &= (TCPHDR_ACK | TCPHDR_PSH); ++ ++ /* If it reached already the destination, we don't have to reinject it */ ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ /* Only reinject segments that are fully covered by the mapping */ ++ if (skb->len + (mptcp_is_data_fin(skb) ? 1 : 0) != ++ TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) { ++ struct rb_node *parent, **p = &meta_sk->tcp_rtx_queue.rb_node; ++ u32 end_seq = TCP_SKB_CB(skb)->end_seq; ++ u32 seq = TCP_SKB_CB(skb)->seq; ++ ++ __kfree_skb(skb); ++ ++ /* Ok, now we have to look for the full mapping in the meta ++ * send-queue :S ++ */ ++ ++ /* First, find the first skb that covers us */ ++ while (*p) { ++ parent = *p; ++ skb = rb_to_skb(parent); ++ ++ /* Not yet at the mapping? */ ++ if (!after(end_seq, TCP_SKB_CB(skb)->seq)) { ++ p = &parent->rb_left; ++ continue; ++ } ++ ++ if (!before(seq, TCP_SKB_CB(skb)->end_seq)) { ++ p = &parent->rb_right; ++ continue; ++ } ++ ++ break; ++ } ++ ++ if (*p) { ++ /* We found it, now let's reinject everything */ ++ skb = rb_to_skb(*p); ++ ++ skb_rbtree_walk_from(skb) { ++ if (after(TCP_SKB_CB(skb)->end_seq, end_seq)) ++ return; ++ __mptcp_reinject_data(skb, meta_sk, NULL, 1, ++ TCP_FRAG_IN_RTX_QUEUE); ++ } ++ } ++ return; ++ } ++ ++ /* Segment goes back to the MPTCP-layer. So, we need to zero the ++ * path_mask/dss. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ /* We need to find out the path-mask from the meta-write-queue ++ * to properly select a subflow. ++ */ ++ mptcp_find_and_set_pathmask(meta_sk, skb); ++ ++ /* If it's empty, just add */ ++ if (skb_queue_empty(&mpcb->reinject_queue)) { ++ skb_queue_head(&mpcb->reinject_queue, skb); ++ return; ++ } ++ ++ /* Find place to insert skb - or even we can 'drop' it, as the ++ * data is already covered by other skb's in the reinject-queue. ++ * ++ * This is inspired by code from tcp_data_queue. ++ */ ++ ++ skb1 = skb_peek_tail(&mpcb->reinject_queue); ++ seq = TCP_SKB_CB(skb)->seq; ++ while (1) { ++ if (!after(TCP_SKB_CB(skb1)->seq, seq)) ++ break; ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) { ++ skb1 = NULL; ++ break; ++ } ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ ++ /* Do skb overlap to previous one? */ ++ end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ /* All the bits are present. Don't reinject */ ++ __kfree_skb(skb); ++ return; ++ } ++ if (seq == TCP_SKB_CB(skb1)->seq) { ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) ++ skb1 = NULL; ++ else ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ } ++ if (!skb1) ++ __skb_queue_head(&mpcb->reinject_queue, skb); ++ else ++ __skb_queue_after(&mpcb->reinject_queue, skb1, skb); ++ ++ /* And clean segments covered by new one as whole. */ ++ while (!skb_queue_is_last(&mpcb->reinject_queue, skb)) { ++ skb1 = skb_queue_next(&mpcb->reinject_queue, skb); ++ ++ if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) ++ break; ++ ++ if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) ++ break; ++ ++ __skb_unlink(skb1, &mpcb->reinject_queue); ++ __kfree_skb(skb1); ++ } ++ return; ++} ++ ++/* Inserts data into the reinject queue */ ++void mptcp_reinject_data(struct sock *sk, int clone_it) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb_it, *tmp; ++ enum tcp_queue tcp_queue; ++ ++ /* It has already been closed - there is really no point in reinjecting */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ skb_queue_walk_safe(&sk->sk_write_queue, skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it, ++ TCP_FRAG_IN_WRITE_QUEUE); ++ } ++ ++ skb_it = tcp_rtx_queue_head(sk); ++ skb_rbtree_walk_from_safe(skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it, ++ TCP_FRAG_IN_RTX_QUEUE); ++ } ++ ++ skb_it = tcp_write_queue_tail(meta_sk); ++ tcp_queue = TCP_FRAG_IN_WRITE_QUEUE; ++ ++ if (!skb_it) { ++ skb_it = skb_rb_last(&meta_sk->tcp_rtx_queue); ++ tcp_queue = TCP_FRAG_IN_RTX_QUEUE; ++ } ++ ++ /* If sk has sent the empty data-fin, we have to reinject it too. */ ++ if (skb_it && mptcp_is_data_fin(skb_it) && skb_it->len == 0 && ++ TCP_SKB_CB(skb_it)->path_mask & mptcp_pi_to_flag(tcp_sk(sk)->mptcp->path_index)) { ++ __mptcp_reinject_data(skb_it, meta_sk, NULL, 1, tcp_queue); ++ } ++ ++ tcp_sk(sk)->pf = 1; ++ ++ mptcp_push_pending_frames(meta_sk); ++} ++EXPORT_SYMBOL(mptcp_reinject_data); ++ ++static void mptcp_combine_dfin(const struct sk_buff *skb, ++ const struct sock *meta_sk, ++ struct sock *subsk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* In infinite mapping we always try to combine */ ++ if (mpcb->infinite_mapping_snd) ++ goto combine; ++ ++ /* Don't combine, if they didn't combine when closing - otherwise we end ++ * up in TIME_WAIT, even if our app is smart enough to avoid it. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !mpcb->dfin_combined) ++ return; ++ ++ /* Don't combine if there is still outstanding data that remains to be ++ * DATA_ACKed, because otherwise we may never be able to deliver this. ++ */ ++ if (meta_tp->snd_una != TCP_SKB_CB(skb)->seq) ++ return; ++ ++combine: ++ if (tcp_close_state(subsk)) { ++ subsk->sk_shutdown |= SEND_SHUTDOWN; ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } ++} ++ ++static int mptcp_write_dss_mapping(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ const struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *start = ptr; ++ __u16 data_len; ++ ++ *ptr++ = htonl(tcb->seq); /* data_seq */ ++ ++ /* If it's a non-data DATA_FIN, we set subseq to 0 (draft v7) */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ *ptr++ = 0; /* subseq */ ++ else ++ *ptr++ = htonl(tp->write_seq - tp->mptcp->snt_isn); /* subseq */ ++ ++ if (tcb->mptcp_flags & MPTCPHDR_INF) ++ data_len = 0; ++ else ++ data_len = tcb->end_seq - tcb->seq; ++ ++ if (tp->mpcb->dss_csum && data_len) { ++ __sum16 *p16 = (__sum16 *)ptr; ++ __be32 hdseq = mptcp_get_highorder_sndbits(skb, tp->mpcb); ++ __wsum csum; ++ ++ *ptr = htonl(((data_len) << 16) | ++ (TCPOPT_EOL << 8) | ++ (TCPOPT_EOL)); ++ csum = csum_partial(ptr - 2, 12, skb->csum); ++ p16++; ++ *p16++ = csum_fold(csum_partial(&hdseq, sizeof(hdseq), csum)); ++ } else { ++ *ptr++ = htonl(((data_len) << 16) | ++ (TCPOPT_NOP << 8) | ++ (TCPOPT_NOP)); ++ } ++ ++ return ptr - start; ++} ++ ++static int mptcp_write_dss_data_ack(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ struct mp_dss *mdss = (struct mp_dss *)ptr; ++ __be32 *start = ptr; ++ ++ mdss->kind = TCPOPT_MPTCP; ++ mdss->sub = MPTCP_SUB_DSS; ++ mdss->rsv1 = 0; ++ mdss->rsv2 = 0; ++ mdss->F = mptcp_is_data_fin(skb) ? 1 : 0; ++ mdss->m = 0; ++ mdss->M = mptcp_is_data_seq(skb) ? 1 : 0; ++ mdss->a = 0; ++ mdss->A = 1; ++ mdss->len = mptcp_sub_len_dss(mdss, tp->mpcb->dss_csum); ++ ptr++; ++ ++ *ptr++ = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ return ptr - start; ++} ++ ++/* RFC6824 states that once a particular subflow mapping has been sent ++ * out it must never be changed. However, packets may be split while ++ * they are in the retransmission queue (due to SACK or ACKs) and that ++ * arguably means that we would change the mapping (e.g. it splits it, ++ * our sends out a subset of the initial mapping). ++ * ++ * Furthermore, the skb checksum is not always preserved across splits ++ * (e.g. mptcp_fragment) which would mean that we need to recompute ++ * the DSS checksum in this case. ++ * ++ * To avoid this we save the initial DSS mapping which allows us to ++ * send the same DSS mapping even for fragmented retransmits. ++ */ ++static void mptcp_save_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb) ++{ ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *ptr = (__be32 *)tcb->dss; ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ ptr += mptcp_write_dss_mapping(tp, skb, ptr); ++} ++ ++/* Write the saved DSS mapping to the header */ ++static int mptcp_write_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ __be32 *start = ptr; ++ ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, mptcp_dss_len); ++ ++ /* update the data_ack */ ++ start[1] = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ /* dss is in a union with inet_skb_parm and ++ * the IP layer expects zeroed IPCB fields. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ return mptcp_dss_len/sizeof(*ptr); ++} ++ ++static bool mptcp_skb_entail(struct sock *sk, struct sk_buff *skb, int reinject) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb; ++ struct sk_buff *subskb = NULL; ++ ++ if (!reinject) ++ TCP_SKB_CB(skb)->mptcp_flags |= (mpcb->snd_hiseq_index ? ++ MPTCPHDR_SEQ64_INDEX : 0); ++ ++ tcp_skb_tsorted_save(skb) { ++ subskb = pskb_copy_for_clone(skb, GFP_ATOMIC); ++ } tcp_skb_tsorted_restore(skb); ++ if (!subskb) ++ return false; ++ ++ /* At the subflow-level we need to call again tcp_init_tso_segs. We ++ * force this, by setting pcount to 0. It has been set to 1 prior to ++ * the call to mptcp_skb_entail. ++ */ ++ tcp_skb_pcount_set(subskb, 0); ++ ++ TCP_SKB_CB(skb)->path_mask |= mptcp_pi_to_flag(tp->mptcp->path_index); ++ ++ /* Compute checksum */ ++ if (tp->mpcb->dss_csum) ++ subskb->csum = skb->csum = skb_checksum(skb, 0, skb->len, 0); ++ ++ tcb = TCP_SKB_CB(subskb); ++ ++ if (tp->mpcb->send_infinite_mapping && ++ !tp->mpcb->infinite_mapping_snd && ++ !before(tcb->seq, mptcp_meta_tp(tp)->snd_nxt)) { ++ tp->mptcp->fully_established = 1; ++ tp->mpcb->infinite_mapping_snd = 1; ++ tp->mptcp->infinite_cutoff_seq = tp->write_seq; ++ tcb->mptcp_flags |= MPTCPHDR_INF; ++ } ++ ++ if (mptcp_is_data_fin(subskb)) ++ mptcp_combine_dfin(subskb, meta_sk, sk); ++ ++ mptcp_save_dss_data_seq(tp, subskb); ++ ++ tcb->seq = tp->write_seq; ++ ++ /* Take into account seg len */ ++ tp->write_seq += subskb->len + ((tcb->tcp_flags & TCPHDR_FIN) ? 1 : 0); ++ tcb->end_seq = tp->write_seq; ++ ++ /* If it's a non-payload DATA_FIN (also no subflow-fin), the ++ * segment is not part of the subflow but on a meta-only-level. ++ */ ++ if (!mptcp_is_data_fin(subskb) || tcb->end_seq != tcb->seq) { ++ /* Make sure that this list is clean */ ++ INIT_LIST_HEAD(&subskb->tcp_tsorted_anchor); ++ ++ tcp_add_write_queue_tail(sk, subskb); ++ sk->sk_wmem_queued += subskb->truesize; ++ sk_mem_charge(sk, subskb->truesize); ++ } else { ++ /* Necessary to initialize for tcp_transmit_skb. mss of 1, as ++ * skb->len = 0 will force tso_segs to 1. ++ */ ++ tcp_init_tso_segs(subskb, 1); ++ ++ /* Empty data-fins are sent immediatly on the subflow */ ++ if (tcp_transmit_skb(sk, subskb, 0, GFP_ATOMIC)) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->second_packet = 1; ++ tp->mptcp->last_end_data_seq = TCP_SKB_CB(skb)->end_seq; ++ } ++ ++ return true; ++} ++ ++/* Fragment an skb and update the mptcp meta-data. Due to reinject, we ++ * might need to undo some operations done by tcp_fragment. ++ * ++ * Be careful, the skb may come from 3 different places: ++ * - The send-queue (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ * - The retransmit-queue (tcp_queue == TCP_FRAG_IN_RTX_QUEUE) ++ * - The reinject-queue (reinject == -1) ++ */ ++static int mptcp_fragment(struct sock *meta_sk, enum tcp_queue tcp_queue, ++ struct sk_buff *skb, u32 len, ++ gfp_t gfp, int reinject) ++{ ++ int ret, diff, old_factor; ++ struct sk_buff *buff; ++ u8 flags; ++ ++ if (skb_headlen(skb) < len) ++ diff = skb->len - len; ++ else ++ diff = skb->data_len; ++ old_factor = tcp_skb_pcount(skb); ++ ++ /* The mss_now in tcp_fragment is used to set the tso_segs of the skb. ++ * At the MPTCP-level we do not care about the absolute value. All we ++ * care about is that it is set to 1 for accurate packets_out ++ * accounting. ++ */ ++ ret = tcp_fragment(meta_sk, tcp_queue, skb, len, UINT_MAX, gfp); ++ if (ret) ++ return ret; ++ ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ buff = skb->next; ++ else ++ buff = skb_rb_next(skb); ++ ++ flags = TCP_SKB_CB(skb)->mptcp_flags; ++ TCP_SKB_CB(skb)->mptcp_flags = flags & ~(MPTCPHDR_FIN); ++ TCP_SKB_CB(buff)->mptcp_flags = flags; ++ TCP_SKB_CB(buff)->path_mask = TCP_SKB_CB(skb)->path_mask; ++ ++ /* If reinject == 1, the buff will be added to the reinject ++ * queue, which is currently not part of memory accounting. So ++ * undo the changes done by tcp_fragment and update the ++ * reinject queue. Also, undo changes to the packet counters. ++ */ ++ if (reinject == 1) { ++ int undo = buff->truesize - diff; ++ meta_sk->sk_wmem_queued -= undo; ++ sk_mem_uncharge(meta_sk, undo); ++ ++ tcp_sk(meta_sk)->mpcb->reinject_queue.qlen++; ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ meta_sk->sk_write_queue.qlen--; ++ ++ if (!before(tcp_sk(meta_sk)->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { ++ undo = old_factor - tcp_skb_pcount(skb) - ++ tcp_skb_pcount(buff); ++ if (undo) ++ tcp_adjust_pcount(meta_sk, skb, -undo); ++ } ++ ++ /* tcp_fragment's call to sk_stream_alloc_skb initializes the ++ * tcp_tsorted_anchor. We need to revert this as it clashes ++ * with the refdst pointer. ++ */ ++ tcp_skb_tsorted_anchor_cleanup(buff); ++ } ++ ++ return 0; ++} ++ ++/* Inspired by tcp_write_wakeup */ ++int mptcp_write_wakeup(struct sock *meta_sk, int mib) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ int ans = 0; ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return -1; ++ ++ skb = tcp_send_head(meta_sk); ++ if (skb && ++ before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(meta_tp))) { ++ unsigned int mss; ++ unsigned int seg_size = tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq; ++ struct sock *subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, true); ++ struct tcp_sock *subtp; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ if (!subsk) ++ goto window_probe; ++ subtp = tcp_sk(subsk); ++ mss = tcp_current_mss(subsk); ++ ++ seg_size = min(tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq, ++ tcp_wnd_end(subtp) - subtp->write_seq); ++ ++ if (before(meta_tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) ++ meta_tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ /* We are probing the opening of a window ++ * but the window size is != 0 ++ * must have been a result SWS avoidance ( sender ) ++ */ ++ if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || ++ skb->len > mss) { ++ seg_size = min(seg_size, mss); ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (mptcp_fragment(meta_sk, TCP_FRAG_IN_WRITE_QUEUE, ++ skb, seg_size, GFP_ATOMIC, 0)) ++ return -1; ++ } else if (!tcp_skb_pcount(skb)) { ++ /* see mptcp_write_xmit on why we use UINT_MAX */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ } ++ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (!mptcp_skb_entail(subsk, skb, 0)) ++ return -1; ++ ++ mptcp_check_sndseq_wrap(meta_tp, TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ ++ __tcp_push_pending_frames(subsk, mss, TCP_NAGLE_PUSH); ++ tcp_update_skb_after_send(meta_tp, skb); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ } else { ++ struct mptcp_tcp_sock *mptcp; ++ ++window_probe: ++ if (between(meta_tp->snd_up, meta_tp->snd_una + 1, ++ meta_tp->snd_una + 0xFFFF)) { ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (mptcp_sk_can_send_ack(sk_it)) ++ tcp_xmit_probe_skb(sk_it, 1, mib); ++ } ++ } ++ ++ /* At least one of the tcp_xmit_probe_skb's has to succeed */ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ int ret; ++ ++ if (!mptcp_sk_can_send_ack(sk_it)) ++ continue; ++ ++ ret = tcp_xmit_probe_skb(sk_it, 0, mib); ++ if (unlikely(ret > 0)) ++ ans = ret; ++ } ++ return ans; ++ } ++} ++ ++bool mptcp_write_xmit(struct sock *meta_sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *subtp; ++ struct mptcp_tcp_sock *mptcp; ++ struct sock *subsk = NULL; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int reinject = 0; ++ unsigned int sublimit; ++ __u32 path_mask = 0; ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ if (inet_csk(meta_sk)->icsk_retransmits) { ++ /* If the timer already once fired, retransmit the head of the ++ * queue to unblock us ASAP. ++ */ ++ if (meta_tp->packets_out && !mpcb->infinite_mapping_snd) ++ mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ } ++ ++ while ((skb = mpcb->sched_ops->next_segment(meta_sk, &reinject, &subsk, ++ &sublimit))) { ++ enum tcp_queue tcp_queue = TCP_FRAG_IN_WRITE_QUEUE; ++ unsigned int limit; ++ ++ WARN(TCP_SKB_CB(skb)->sacked, "sacked: %u reinject: %u", ++ TCP_SKB_CB(skb)->sacked, reinject); ++ ++ subtp = tcp_sk(subsk); ++ mss_now = tcp_current_mss(subsk); ++ ++ if (reinject == 1) { ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ /* Segment already reached the peer, take the next one */ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ continue; ++ } ++ } else if (reinject == -1) { ++ tcp_queue = TCP_FRAG_IN_RTX_QUEUE; ++ } ++ ++ /* If the segment was cloned (e.g. a meta retransmission), ++ * the header must be expanded/copied so that there is no ++ * corruption of TSO information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ break; ++ ++ if (unlikely(!tcp_snd_wnd_test(meta_tp, skb, mss_now))) ++ break; ++ ++ /* Force tso_segs to 1 by using UINT_MAX. ++ * We actually don't care about the exact number of segments ++ * emitted on the subflow. We need just to set tso_segs, because ++ * we still need an accurate packets_out count in ++ * tcp_event_new_data_sent. ++ */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ ++ /* Check for nagle, irregardless of tso_segs. If the segment is ++ * actually larger than mss_now (TSO segment), then ++ * tcp_nagle_check will have partial == false and always trigger ++ * the transmission. ++ * tcp_write_xmit has a TSO-level nagle check which is not ++ * subject to the MPTCP-level. It is based on the properties of ++ * the subflow, not the MPTCP-level. ++ * When the segment is a reinjection or redundant scheduled ++ * segment, nagle check at meta-level may prevent ++ * sending. This could hurt with certain schedulers, as they ++ * to reinjection to recover from a window-stall or reduce latency. ++ * Therefore, Nagle check should be disabled in that case. ++ */ ++ if (!reinject && ++ unlikely(!tcp_nagle_test(meta_tp, skb, mss_now, ++ (tcp_skb_is_last(meta_sk, skb) ? ++ nonagle : TCP_NAGLE_PUSH)))) ++ break; ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ /* We limit the size of the skb so that it fits into the ++ * window. Call tcp_mss_split_point to avoid duplicating ++ * code. ++ * We really only care about fitting the skb into the ++ * window. That's why we use UINT_MAX. If the skb does ++ * not fit into the cwnd_quota or the NIC's max-segs ++ * limitation, it will be split by the subflow's ++ * tcp_write_xmit which does the appropriate call to ++ * tcp_mss_split_point. ++ */ ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ nonagle); ++ ++ if (sublimit) ++ limit = min(limit, sublimit); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, tcp_queue, ++ skb, limit, gfp, reinject))) ++ break; ++ ++ if (!mptcp_skb_entail(subsk, skb, reinject)) ++ break; ++ /* Nagle is handled at the MPTCP-layer, so ++ * always push on the subflow ++ */ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ if (reinject <= 0) ++ tcp_update_skb_after_send(meta_tp, skb); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ path_mask |= mptcp_pi_to_flag(subtp->mptcp->path_index); ++ ++ if (!reinject) { ++ mptcp_check_sndseq_wrap(meta_tp, ++ TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ } ++ ++ tcp_minshall_update(meta_tp, mss_now, skb); ++ ++ if (reinject > 0) { ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ kfree_skb(skb); ++ } ++ ++ if (push_one) ++ break; ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ subsk = mptcp_to_sock(mptcp); ++ subtp = tcp_sk(subsk); ++ ++ if (!(path_mask & mptcp_pi_to_flag(subtp->mptcp->path_index))) ++ continue; ++ ++ /* We have pushed data on this subflow. We ignore the call to ++ * cwnd_validate in tcp_write_xmit as is_cwnd_limited will never ++ * be true (we never push more than what the cwnd can accept). ++ * We need to ensure that we call tcp_cwnd_validate with ++ * is_cwnd_limited set to true if we have filled the cwnd. ++ */ ++ tcp_cwnd_validate(subsk, tcp_packets_in_flight(subtp) >= ++ subtp->snd_cwnd); ++ } ++ ++ return !meta_tp->packets_out && tcp_send_head(meta_sk); ++} ++ ++void mptcp_write_space(struct sock *sk) ++{ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++} ++ ++u32 __mptcp_select_window(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ int mss, free_space, full_space, window; ++ ++ /* MSS for the peer's data. Previous versions used mss_clamp ++ * here. I don't know if the value based on our guesses ++ * of peer's MSS is better for the performance. It's more correct ++ * but may be worse for the performance because of rcv_mss ++ * fluctuations. --SAW 1998/11/1 ++ */ ++ mss = icsk->icsk_ack.rcv_mss; ++ free_space = tcp_space(meta_sk); ++ full_space = min_t(int, meta_tp->window_clamp, ++ tcp_full_space(meta_sk)); ++ ++ if (mss > full_space) ++ mss = full_space; ++ ++ if (free_space < (full_space >> 1)) { ++ /* If free_space is decreasing due to mostly meta-level ++ * out-of-order packets, don't turn off the quick-ack mode. ++ */ ++ if (meta_tp->rcv_nxt - meta_tp->copied_seq > ((full_space - free_space) >> 1)) ++ icsk->icsk_ack.quick = 0; ++ ++ if (tcp_memory_pressure) ++ /* TODO this has to be adapted when we support different ++ * MSS's among the subflows. ++ */ ++ meta_tp->rcv_ssthresh = min(meta_tp->rcv_ssthresh, ++ 4U * meta_tp->advmss); ++ ++ if (free_space < mss) ++ return 0; ++ } ++ ++ if (free_space > meta_tp->rcv_ssthresh) ++ free_space = meta_tp->rcv_ssthresh; ++ ++ /* Don't do rounding if we are using window scaling, since the ++ * scaled window will not line up with the MSS boundary anyway. ++ */ ++ window = meta_tp->rcv_wnd; ++ if (tp->rx_opt.rcv_wscale) { ++ window = free_space; ++ ++ /* Advertise enough space so that it won't get scaled away. ++ * Import case: prevent zero window announcement if ++ * 1< mss. ++ */ ++ if (((window >> tp->rx_opt.rcv_wscale) << tp-> ++ rx_opt.rcv_wscale) != window) ++ window = (((window >> tp->rx_opt.rcv_wscale) + 1) ++ << tp->rx_opt.rcv_wscale); ++ } else { ++ /* Get the largest window that is a nice multiple of mss. ++ * Window clamp already applied above. ++ * If our current window offering is within 1 mss of the ++ * free space we just keep it. This prevents the divide ++ * and multiply from happening most of the time. ++ * We also don't do any window rounding when the free space ++ * is too small. ++ */ ++ if (window <= free_space - mss || window > free_space) ++ window = (free_space / mss) * mss; ++ else if (mss == full_space && ++ free_space > window + (full_space >> 1)) ++ window = free_space; ++ } ++ ++ return window; ++} ++ ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ opts->options |= OPTION_MPTCP; ++ if (is_master_tp(tp)) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYN; ++ opts->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ opts->mp_capable.sender_key = tp->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum; ++ } else { ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYN; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYN_ALIGN; ++ opts->mp_join_syns.token = mpcb->mptcp_rem_token; ++ opts->mp_join_syns.low_prio = tp->mptcp->low_prio; ++ opts->addr_id = tp->mptcp->loc_id; ++ opts->mp_join_syns.sender_nonce = tp->mptcp->mptcp_loc_nonce; ++ } ++} ++ ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, unsigned *remaining) ++{ ++ struct mptcp_request_sock *mtreq; ++ mtreq = mptcp_rsk(req); ++ ++ opts->options |= OPTION_MPTCP; ++ /* MPCB not yet set - thus it's a new MPTCP-session */ ++ if (!mtreq->is_sub) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYNACK; ++ opts->mptcp_ver = mtreq->mptcp_ver; ++ opts->mp_capable.sender_key = mtreq->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum || mtreq->dss_csum; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ } else { ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYNACK; ++ opts->mp_join_syns.sender_truncated_mac = ++ mtreq->mptcp_hash_tmac; ++ opts->mp_join_syns.sender_nonce = mtreq->mptcp_loc_nonce; ++ opts->mp_join_syns.low_prio = mtreq->low_prio; ++ opts->addr_id = mtreq->loc_id; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN; ++ } ++} ++ ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ const struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL; ++ ++ /* We are coming from tcp_current_mss with the meta_sk as an argument. ++ * It does not make sense to check for the options, because when the ++ * segment gets sent, another subflow will be chosen. ++ */ ++ if (!skb && is_meta_sk(sk)) ++ return; ++ ++ if (unlikely(tp->send_mp_fclose)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FCLOSE; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ *size += MPTCP_SUB_LEN_FCLOSE_ALIGN; ++ return; ++ } ++ ++ /* 1. If we are the sender of the infinite-mapping, we need the ++ * MPTCPHDR_INF-flag, because a retransmission of the ++ * infinite-announcment still needs the mptcp-option. ++ * ++ * We need infinite_cutoff_seq, because retransmissions from before ++ * the infinite-cutoff-moment still need the MPTCP-signalling to stay ++ * consistent. ++ * ++ * 2. If we are the receiver of the infinite-mapping, we always skip ++ * mptcp-options, because acknowledgments from before the ++ * infinite-mapping point have already been sent out. ++ * ++ * I know, the whole infinite-mapping stuff is ugly... ++ * ++ * TODO: Handle wrapped data-sequence numbers ++ * (even if it's very unlikely) ++ */ ++ if (unlikely(mpcb->infinite_mapping_snd) && ++ ((mpcb->send_infinite_mapping && tcb && ++ mptcp_is_data_seq(skb) && ++ !(tcb->mptcp_flags & MPTCPHDR_INF) && ++ !before(tcb->seq, tp->mptcp->infinite_cutoff_seq)) || ++ !mpcb->send_infinite_mapping)) ++ return; ++ ++ if (unlikely(tp->mptcp->include_mpc)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_CAPABLE | ++ OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN; ++ opts->mptcp_ver = mpcb->mptcp_ver; ++ opts->mp_capable.sender_key = mpcb->mptcp_loc_key; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ opts->dss_csum = mpcb->dss_csum; ++ ++ if (skb) ++ tp->mptcp->include_mpc = 0; ++ } ++ if (unlikely(tp->mptcp->pre_established) && ++ (!skb || !(tcb->tcp_flags & (TCPHDR_FIN | TCPHDR_RST)))) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_JOIN_ACK_ALIGN; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (opts->add_addr_v6) ++ /* Skip subsequent options */ ++ return; ++ } ++ ++ if (!tp->mptcp->include_mpc && !tp->mptcp->pre_established) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_DATA_ACK; ++ /* If !skb, we come from tcp_current_mss and thus we always ++ * assume that the DSS-option will be set for the data-packet. ++ */ ++ if (skb && !mptcp_is_data_seq(skb)) { ++ *size += MPTCP_SUB_LEN_ACK_ALIGN; ++ } else { ++ /* Doesn't matter, if csum included or not. It will be ++ * either 10 or 12, and thus aligned = 12 ++ */ ++ *size += MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ } ++ ++ *size += MPTCP_SUB_LEN_DSS_ALIGN; ++ } ++ ++ /* In fallback mp_fail-mode, we have to repeat it until the fallback ++ * has been done by the sender ++ */ ++ if (unlikely(tp->mptcp->send_mp_fail) && skb && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_FAIL) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FAIL; ++ *size += MPTCP_SUB_LEN_FAIL; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver < MPTCP_VERSION_1) ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (unlikely(tp->mptcp->send_mp_prio) && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_PRIO_ALIGN) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_PRIO; ++ if (skb) ++ tp->mptcp->send_mp_prio = 0; ++ *size += MPTCP_SUB_LEN_PRIO_ALIGN; ++ } ++ ++ return; ++} ++ ++u16 mptcp_select_window(struct sock *sk) ++{ ++ u16 new_win = tcp_select_window(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *meta_tp = mptcp_meta_tp(tp); ++ ++ meta_tp->rcv_wnd = tp->rcv_wnd; ++ meta_tp->rcv_wup = meta_tp->rcv_nxt; ++ ++ return new_win; ++} ++ ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ if (unlikely(OPTION_MP_CAPABLE & opts->mptcp_options)) { ++ struct mp_capable *mpc = (struct mp_capable *)ptr; ++ ++ mpc->kind = TCPOPT_MPTCP; ++ ++ if ((OPTION_TYPE_SYN & opts->mptcp_options) || ++ (OPTION_TYPE_SYNACK & opts->mptcp_options)) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_SYN; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->receiver_key = opts->mp_capable.receiver_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_ACK; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN >> 2; ++ } ++ ++ mpc->sub = MPTCP_SUB_CAPABLE; ++ mpc->a = opts->dss_csum; ++ mpc->b = 0; ++ mpc->rsv = 0; ++ mpc->h = 1; ++ } ++ if (unlikely(OPTION_MP_JOIN & opts->mptcp_options)) { ++ struct mp_join *mpj = (struct mp_join *)ptr; ++ ++ mpj->kind = TCPOPT_MPTCP; ++ mpj->sub = MPTCP_SUB_JOIN; ++ mpj->rsv = 0; ++ ++ if (OPTION_TYPE_SYN & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYN; ++ mpj->u.syn.token = opts->mp_join_syns.token; ++ mpj->u.syn.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_SYNACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYNACK; ++ mpj->u.synack.mac = ++ opts->mp_join_syns.sender_truncated_mac; ++ mpj->u.synack.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_ACK; ++ mpj->addr_id = 0; /* addr_id is rsv (RFC 6824, p. 21) */ ++ memcpy(mpj->u.ack.mac, &tp->mptcp->sender_mac[0], 20); ++ ptr += MPTCP_SUB_LEN_JOIN_ACK_ALIGN >> 2; ++ } ++ } ++ if (unlikely(OPTION_ADD_ADDR & opts->mptcp_options)) { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mpadd->kind = TCPOPT_MPTCP; ++ if (opts->add_addr_v4) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 4; ++ mpadd->addr_id = opts->add_addr4.addr_id; ++ mpadd->u.v4.addr = opts->add_addr4.addr; ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v4.mac - 2, ++ (char *)&opts->add_addr4.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 >> 2; ++ } ++ } else if (opts->add_addr_v6) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 6; ++ mpadd->addr_id = opts->add_addr6.addr_id; ++ memcpy(&mpadd->u.v6.addr, &opts->add_addr6.addr, ++ sizeof(mpadd->u.v6.addr)); ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v6.mac - 2, ++ (char *)&opts->add_addr6.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 >> 2; ++ } ++ } ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_ADDADDRTX); ++ } ++ if (unlikely(OPTION_REMOVE_ADDR & opts->mptcp_options)) { ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ u8 *addrs_id; ++ int id, len, len_align; ++ ++ len = mptcp_sub_len_remove_addr(opts->remove_addrs); ++ len_align = mptcp_sub_len_remove_addr_align(opts->remove_addrs); ++ ++ mprem->kind = TCPOPT_MPTCP; ++ mprem->len = len; ++ mprem->sub = MPTCP_SUB_REMOVE_ADDR; ++ mprem->rsv = 0; ++ addrs_id = &mprem->addrs_id; ++ ++ mptcp_for_each_bit_set(opts->remove_addrs, id) ++ *(addrs_id++) = id; ++ ++ /* Fill the rest with NOP's */ ++ if (len_align > len) { ++ int i; ++ for (i = 0; i < len_align - len; i++) ++ *(addrs_id++) = TCPOPT_NOP; ++ } ++ ++ ptr += len_align >> 2; ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_REMADDRTX); ++ } ++ if (unlikely(OPTION_MP_FAIL & opts->mptcp_options)) { ++ struct mp_fail *mpfail = (struct mp_fail *)ptr; ++ ++ mpfail->kind = TCPOPT_MPTCP; ++ mpfail->len = MPTCP_SUB_LEN_FAIL; ++ mpfail->sub = MPTCP_SUB_FAIL; ++ mpfail->rsv1 = 0; ++ mpfail->rsv2 = 0; ++ mpfail->data_seq = htonll(tp->mpcb->csum_cutoff_seq); ++ ++ ptr += MPTCP_SUB_LEN_FAIL_ALIGN >> 2; ++ } ++ if (unlikely(OPTION_MP_FCLOSE & opts->mptcp_options)) { ++ struct mp_fclose *mpfclose = (struct mp_fclose *)ptr; ++ ++ mpfclose->kind = TCPOPT_MPTCP; ++ mpfclose->len = MPTCP_SUB_LEN_FCLOSE; ++ mpfclose->sub = MPTCP_SUB_FCLOSE; ++ mpfclose->rsv1 = 0; ++ mpfclose->rsv2 = 0; ++ mpfclose->key = opts->mp_capable.receiver_key; ++ ++ ptr += MPTCP_SUB_LEN_FCLOSE_ALIGN >> 2; ++ } ++ ++ if (OPTION_DATA_ACK & opts->mptcp_options) { ++ if (!mptcp_is_data_seq(skb)) ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ else ++ ptr += mptcp_write_dss_data_seq(tp, skb, ptr); ++ } ++ if (unlikely(OPTION_MP_PRIO & opts->mptcp_options)) { ++ struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ mpprio->kind = TCPOPT_MPTCP; ++ mpprio->len = MPTCP_SUB_LEN_PRIO; ++ mpprio->sub = MPTCP_SUB_PRIO; ++ mpprio->rsv = 0; ++ mpprio->b = tp->mptcp->low_prio; ++ mpprio->addr_id = TCPOPT_NOP; ++ ++ ptr += MPTCP_SUB_LEN_PRIO_ALIGN >> 2; ++ } ++} ++ ++/* Sends the datafin */ ++void mptcp_send_fin(struct sock *meta_sk) ++{ ++ struct sk_buff *skb, *tskb = tcp_write_queue_tail(meta_sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int mss_now; ++ ++ if ((1 << meta_sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK)) ++ meta_tp->mpcb->passive_close = 1; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = mptcp_current_mss(meta_sk); ++ ++ if (tskb) { ++ TCP_SKB_CB(tskb)->mptcp_flags |= MPTCPHDR_FIN; ++ TCP_SKB_CB(tskb)->end_seq++; ++ meta_tp->write_seq++; ++ } else { ++ /* Socket is locked, keep trying until memory is available. */ ++ for (;;) { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, ++ meta_sk->sk_allocation); ++ if (skb) ++ break; ++ yield(); ++ } ++ /* Reserve space for headers and prepare control bits. */ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ skb_reserve(skb, MAX_TCP_HEADER); ++ ++ tcp_init_nondata_skb(skb, meta_tp->write_seq, TCPHDR_ACK); ++ TCP_SKB_CB(skb)->end_seq++; ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ tcp_queue_skb(meta_sk, skb); ++ } ++ __tcp_push_pending_frames(meta_sk, mss_now, TCP_NAGLE_OFF); ++} ++ ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ ++ if (hlist_empty(&mpcb->conn_list)) ++ return; ++ ++ WARN_ON(meta_tp->send_mp_fclose); ++ ++ /* First - select a socket */ ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ /* May happen if no subflow is in an appropriate state, OR ++ * we are in infinite mode or about to go there - just send a reset ++ */ ++ if (!sk || mptcp_in_infinite_mapping_weak(mpcb)) { ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ return; ++ } ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ tcp_sk(sk)->send_mp_fclose = 1; ++ /** Reset all other subflows */ ++ ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ tcp_set_state(sk, TCP_RST_WAIT); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ ++ tcp_send_ack(sk); ++ tcp_clear_xmit_timers(sk); ++ inet_csk_reset_keepalive_timer(sk, inet_csk(sk)->icsk_rto); ++ ++ meta_tp->send_mp_fclose = 1; ++ inet_csk(sk)->icsk_retransmits = 0; ++ ++ /* Prevent exp backoff reverting on ICMP dest unreachable */ ++ inet_csk(sk)->icsk_backoff = 0; ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_FASTCLOSETX); ++} ++ ++static void mptcp_ack_retransmit_timer(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ struct sk_buff *skb; ++ ++ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) ++ goto out; /* Routing failure or similar */ ++ ++ tcp_mstamp_refresh(tp); ++ ++ if (tcp_write_timeout(sk)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRTO); ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ goto out; ++ } ++ ++ skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (skb == NULL) { ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ /* Reserve space for headers and prepare control bits */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ tcp_init_nondata_skb(skb, tp->snd_una, TCPHDR_ACK); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRXMIT); ++ ++ if (tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC) > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!icsk->icsk_retransmits) ++ icsk->icsk_retransmits = 1; ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ if (!tp->retrans_stamp) ++ tp->retrans_stamp = tcp_time_stamp(tp) ? : 1; ++ ++ icsk->icsk_retransmits++; ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0)) ++ __sk_dst_reset(sk); ++ ++out:; ++} ++ ++void mptcp_ack_handler(struct timer_list *t) ++{ ++ struct mptcp_tcp_sock *mptcp = from_timer(mptcp, t, mptcp_ack_timer); ++ struct sock *sk = (struct sock *)mptcp->tp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ /* Try again later */ ++ sk_reset_timer(sk, &tcp_sk(sk)->mptcp->mptcp_ack_timer, ++ jiffies + (HZ / 20)); ++ goto out_unlock; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) ++ goto out_unlock; ++ if (!tcp_sk(sk)->mptcp->pre_established) ++ goto out_unlock; ++ ++ mptcp_ack_retransmit_timer(sk); ++ ++ sk_mem_reclaim(sk); ++ ++out_unlock: ++ bh_unlock_sock(meta_sk); ++ sock_put(sk); ++} ++ ++/* Similar to tcp_retransmit_skb ++ * ++ * The diff is that we handle the retransmission-stats (retrans_stamp) at the ++ * meta-level. ++ */ ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk; ++ unsigned int limit, mss_now; ++ int err = -1; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ /* Do not sent more than we queued. 1/4 is reserved for possible ++ * copying overhead: fragmentation, tunneling, mangling etc. ++ * ++ * This is a meta-retransmission thus we check on the meta-socket. ++ */ ++ if (refcount_read(&meta_sk->sk_wmem_alloc) > ++ min(meta_sk->sk_wmem_queued + (meta_sk->sk_wmem_queued >> 2), meta_sk->sk_sndbuf)) { ++ return -EAGAIN; ++ } ++ ++ /* We need to make sure that the retransmitted segment can be sent on a ++ * subflow right now. If it is too big, it needs to be fragmented. ++ */ ++ subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, false); ++ if (!subsk) { ++ /* We want to increase icsk_retransmits, thus return 0, so that ++ * mptcp_meta_retransmit_timer enters the desired branch. ++ */ ++ err = 0; ++ goto failed; ++ } ++ mss_now = tcp_current_mss(subsk); ++ ++ /* If the segment was cloned (e.g. a meta retransmission), the header ++ * must be expanded/copied so that there is no corruption of TSO ++ * information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Must have been set by mptcp_write_xmit before */ ++ BUG_ON(!tcp_skb_pcount(skb)); ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ TCP_NAGLE_OFF); ++ ++ limit = min(limit, tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, TCP_FRAG_IN_RTX_QUEUE, skb, ++ limit, GFP_ATOMIC, 0))) ++ goto failed; ++ ++ if (!mptcp_skb_entail(subsk, skb, -1)) ++ goto failed; ++ ++ /* Update global TCP statistics. */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_RETRANSSEGS); ++ ++ /* Diff to tcp_retransmit_skb */ ++ ++ /* Save stamp of the first retransmit. */ ++ if (!meta_tp->retrans_stamp) { ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->retrans_stamp = tcp_time_stamp(meta_tp); ++ } ++ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ tcp_update_skb_after_send(meta_tp, skb); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ ++failed: ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPRETRANSFAIL); ++ return err; ++} ++ ++/* Similar to tcp_retransmit_timer ++ * ++ * The diff is that we have to handle retransmissions of the FAST_CLOSE-message ++ * and that we don't have an srtt estimation at the meta-level. ++ */ ++void mptcp_meta_retransmit_timer(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ int err; ++ ++ /* In fallback, retransmission is handled at the subflow-level */ ++ if (!meta_tp->packets_out || mpcb->infinite_mapping_snd) ++ return; ++ ++ WARN_ON(tcp_rtx_queue_empty(meta_sk)); ++ ++ if (!meta_tp->snd_wnd && !sock_flag(meta_sk, SOCK_DEAD) && ++ !((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { ++ /* Receiver dastardly shrinks window. Our retransmits ++ * become zero probes, but we should not timeout this ++ * connection. If the socket is an orphan, time it out, ++ * we cannot allow such beasts to hang infinitely. ++ */ ++ struct inet_sock *meta_inet = inet_sk(meta_sk); ++ if (meta_sk->sk_family == AF_INET) { ++ net_dbg_ratelimited("MPTCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_inet->inet_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (meta_sk->sk_family == AF_INET6) { ++ net_dbg_ratelimited("MPTCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_sk->sk_v6_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#endif ++ if (tcp_jiffies32 - meta_tp->rcv_tstamp > TCP_RTO_MAX) { ++ tcp_write_err(meta_sk); ++ return; ++ } ++ ++ mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ goto out_reset_timer; ++ } ++ ++ if (tcp_write_timeout(meta_sk)) ++ return; ++ ++ if (meta_icsk->icsk_retransmits == 0) ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPTIMEOUTS); ++ ++ meta_icsk->icsk_ca_state = TCP_CA_Loss; ++ ++ err = mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ if (err > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!meta_icsk->icsk_retransmits) ++ meta_icsk->icsk_retransmits = 1; ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ min(meta_icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), ++ TCP_RTO_MAX); ++ return; ++ } ++ ++ /* Increase the timeout each time we retransmit. Note that ++ * we do not increase the rtt estimate. rto is initialized ++ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests ++ * that doubling rto each time is the least we can get away with. ++ * In KA9Q, Karn uses this for the first few times, and then ++ * goes to quadratic. netBSD doubles, but only goes up to *64, ++ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is ++ * defined in the protocol as the maximum possible RTT. I guess ++ * we'll have to use something other than TCP to talk to the ++ * University of Mars. ++ * ++ * PAWS allows us longer timeouts and large windows, so once ++ * implemented ftp to mars will work nicely. We will have to fix ++ * the 120 second clamps though! ++ */ ++ meta_icsk->icsk_backoff++; ++ meta_icsk->icsk_retransmits++; ++ ++out_reset_timer: ++ /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is ++ * used to reset timer, set to 0. Recalculate 'icsk_rto' as this ++ * might be increased if the stream oscillates between thin and thick, ++ * thus the old value might already be too high compared to the value ++ * set by 'tcp_set_rto' in tcp_input.c which resets the rto without ++ * backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating ++ * exponential backoff behaviour to avoid continue hammering ++ * linear-timeout retransmissions into a black hole ++ */ ++ if (meta_sk->sk_state == TCP_ESTABLISHED && ++ (meta_tp->thin_lto || sock_net(meta_sk)->ipv4.sysctl_tcp_thin_linear_timeouts) && ++ tcp_stream_is_thin(meta_tp) && ++ meta_icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { ++ meta_icsk->icsk_backoff = 0; ++ /* We cannot do the same as in tcp_write_timer because the ++ * srtt is not set here. ++ */ ++ mptcp_set_rto(meta_sk); ++ } else { ++ /* Use normal (exponential) backoff */ ++ meta_icsk->icsk_rto = min(meta_icsk->icsk_rto << 1, TCP_RTO_MAX); ++ } ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, meta_icsk->icsk_rto, TCP_RTO_MAX); ++ ++ return; ++} ++ ++void mptcp_sub_retransmit_timer(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_retransmit_timer(sk); ++ ++ if (!tp->fastopen_rsk) { ++ mptcp_reinject_data(sk, 1); ++ mptcp_set_rto(sk); ++ } ++} ++ ++/* Modify values to an mptcp-level for the initial window of new subflows */ ++void mptcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, ++ __u32 *rcv_wnd, __u32 *window_clamp, ++ int wscale_ok, __u8 *rcv_wscale, ++ __u32 init_rcv_wnd) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ *window_clamp = mpcb->orig_window_clamp; ++ __space = tcp_win_from_space(sk, mpcb->orig_sk_rcvbuf); ++ ++ tcp_select_initial_window(sk, __space, mss, rcv_wnd, window_clamp, ++ wscale_ok, rcv_wscale, init_rcv_wnd); ++} ++ ++static inline u64 mptcp_calc_rate(const struct sock *meta_sk, unsigned int mss, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u64 rate = 0; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ /* Do not consider subflows without a RTT estimation yet ++ * otherwise this_rate >>> rate. ++ */ ++ if (unlikely(!tp->srtt_us)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* If this_mss is smaller than mss, it means that a segment will ++ * be splitted in two (or more) when pushed on this subflow. If ++ * you consider that mss = 1428 and this_mss = 1420 then two ++ * segments will be generated: a 1420-byte and 8-byte segment. ++ * The latter will introduce a large overhead as for a single ++ * data segment 2 slots will be used in the congestion window. ++ * Therefore reducing by ~2 the potential throughput of this ++ * subflow. Indeed, 1428 will be send while 2840 could have been ++ * sent if mss == 1420 reducing the throughput by 2840 / 1428. ++ * ++ * The following algorithm take into account this overhead ++ * when computing the potential throughput that MPTCP can ++ * achieve when generating mss-byte segments. ++ * ++ * The formulae is the following: ++ * \sum_{\forall sub} ratio * \frac{mss * cwnd_sub}{rtt_sub} ++ * Where ratio is computed as follows: ++ * \frac{mss}{\ceil{mss / mss_sub} * mss_sub} ++ * ++ * ratio gives the reduction factor of the theoretical ++ * throughput a subflow can achieve if MPTCP uses a specific ++ * MSS value. ++ */ ++ this_rate = div64_u64((u64)mss * mss * (USEC_PER_SEC << 3) * ++ max(tp->snd_cwnd, tp->packets_out), ++ (u64)tp->srtt_us * ++ DIV_ROUND_UP(mss, this_mss) * this_mss); ++ rate += this_rate; ++ } ++ ++ return rate; ++} ++ ++static unsigned int __mptcp_current_mss(const struct sock *meta_sk, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ unsigned int mss = 0; ++ u64 rate = 0; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* Same mss values will produce the same throughput. */ ++ if (this_mss == mss) ++ continue; ++ ++ /* See whether using this mss value can theoretically improve ++ * the performances. ++ */ ++ this_rate = mptcp_calc_rate(meta_sk, this_mss, mss_cb); ++ if (this_rate >= rate) { ++ mss = this_mss; ++ rate = this_rate; ++ } ++ } ++ ++ return mss; ++} ++ ++unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, tcp_current_mss); ++ ++ /* If no subflow is available, we take a default-mss from the ++ * meta-socket. ++ */ ++ return !mss ? tcp_current_mss(meta_sk) : mss; ++} ++ ++static unsigned int mptcp_select_size_mss(struct sock *sk) ++{ ++ return tcp_sk(sk)->mss_cache; ++} ++ ++int mptcp_select_size(const struct sock *meta_sk, bool first_skb, bool zc) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, mptcp_select_size_mss); ++ ++ if (mptcp_can_sg(meta_sk)) { ++ if (zc) ++ return 0; ++ ++ if (!tcp_sk(meta_sk)->mpcb->dss_csum) { ++ mss = linear_payload_sz(first_skb); ++ } else { ++ int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); ++ ++ if (mss >= pgbreak && ++ mss <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE) ++ mss = pgbreak; ++ } ++ } ++ ++ return !mss ? tcp_sk(meta_sk)->mss_cache : mss; ++} ++ ++int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ const struct mptcp_tcp_sock *mptcp; ++ u32 rtt_max = tp->srtt_us; ++ u64 bw_est; ++ ++ if (!tp->srtt_us) ++ return tp->reordering + 1; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->srtt_us) ++ rtt_max = tcp_sk(sk)->srtt_us; ++ } ++ ++ bw_est = div64_u64(((u64)tp->snd_cwnd * rtt_max) << 16, ++ (u64)tp->srtt_us); ++ ++ return max_t(unsigned int, (u32)(bw_est >> 16), ++ tp->reordering + 1); ++} ++ ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed) ++{ ++ u32 xmit_size_goal = 0; ++ ++ if (large_allowed && !tcp_sk(meta_sk)->mpcb->dss_csum) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ int this_size_goal; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_size_goal = tcp_xmit_size_goal(sk, mss_now, 1); ++ if (this_size_goal > xmit_size_goal) ++ xmit_size_goal = this_size_goal; ++ } ++ } ++ ++ return max(xmit_size_goal, mss_now); ++} ++ +diff -aurN linux-4.19.104/net/mptcp/mptcp_pm.c mptcp-mptcp_v0.95/net/mptcp/mptcp_pm.c +--- linux-4.19.104/net/mptcp/mptcp_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_pm.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,226 @@ ++/* ++ * MPTCP implementation - MPTCP-subflow-management ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_pm_list_lock); ++static LIST_HEAD(mptcp_pm_list); ++ ++static int mptcp_default_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ return 0; ++} ++ ++struct mptcp_pm_ops mptcp_pm_default = { ++ .get_local_id = mptcp_default_id, /* We do not care */ ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_pm_ops *mptcp_pm_find(const char *name) ++{ ++ struct mptcp_pm_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_pm_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm) ++{ ++ int ret = 0; ++ ++ if (!pm->get_local_id) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ if (mptcp_pm_find(pm->name)) { ++ pr_notice("%s already registered\n", pm->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&pm->list, &mptcp_pm_list); ++ pr_info("%s registered\n", pm->name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_path_manager); ++ ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm) ++{ ++ spin_lock(&mptcp_pm_list_lock); ++ list_del_rcu(&pm->list); ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_path_manager); ++ ++void mptcp_get_default_path_manager(char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ BUG_ON(list_empty(&mptcp_pm_list)); ++ ++ rcu_read_lock(); ++ pm = list_entry(mptcp_pm_list.next, struct mptcp_pm_ops, list); ++ strncpy(name, pm->name, MPTCP_PM_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_path_manager(const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ ++ if (pm) { ++ list_move(&pm->list, &mptcp_pm_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops *__mptcp_pm_find_autoload(const char *name) ++{ ++ struct mptcp_pm_ops *pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ return pm; ++} ++ ++void mptcp_init_path_manager(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if path manager was set using socket option */ ++ if (meta_tp->mptcp_pm_setsockopt) { ++ pm = __mptcp_pm_find_autoload(meta_tp->mptcp_pm_name); ++ if (pm && try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(pm, &mptcp_pm_list, list) { ++ if (try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change path manager for socket */ ++int mptcp_set_path_manager(struct sock *sk, const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int err = 0; ++ ++ rcu_read_lock(); ++ pm = __mptcp_pm_find_autoload(name); ++ ++ if (!pm) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_pm_name, name); ++ tcp_sk(sk)->mptcp_pm_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->pm_ops->owner); ++} ++ ++/* Fallback to the default path-manager. */ ++void mptcp_fallback_default(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ mptcp_cleanup_path_manager(mpcb); ++ pm = mptcp_pm_find("default"); ++ ++ /* Cannot fail - it's the default module */ ++ try_module_get(pm->owner); ++ mpcb->pm_ops = pm; ++} ++EXPORT_SYMBOL_GPL(mptcp_fallback_default); ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_path_manager_default(void) ++{ ++ return mptcp_set_default_path_manager(CONFIG_DEFAULT_MPTCP_PM); ++} ++late_initcall(mptcp_path_manager_default); +diff -aurN linux-4.19.104/net/mptcp/mptcp_redundant.c mptcp-mptcp_v0.95/net/mptcp/mptcp_redundant.c +--- linux-4.19.104/net/mptcp/mptcp_redundant.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_redundant.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,389 @@ ++/* ++ * MPTCP Scheduler to reduce latency and jitter. ++ * ++ * This scheduler sends all packets redundantly on all available subflows. ++ * ++ * Initial Design & Implementation: ++ * Tobias Erbshaeusser ++ * Alexander Froemmgen ++ * ++ * Initial corrections & modifications: ++ * Christian Pinedo ++ * Igor Lopez ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++/* Struct to store the data of a single subflow */ ++struct redsched_priv { ++ /* The skb or NULL */ ++ struct sk_buff *skb; ++ /* End sequence number of the skb. This number should be checked ++ * to be valid before the skb field is used ++ */ ++ u32 skb_end_seq; ++}; ++ ++/* Struct to store the data of the control block */ ++struct redsched_cb { ++ /* The next subflow where a skb should be sent or NULL */ ++ struct tcp_sock *next_subflow; ++}; ++ ++/* Returns the socket data from a given subflow socket */ ++static struct redsched_priv *redsched_get_priv(struct tcp_sock *tp) ++{ ++ return (struct redsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* Returns the control block data from a given meta socket */ ++static struct redsched_cb *redsched_get_cb(struct tcp_sock *tp) ++{ ++ return (struct redsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static bool redsched_get_active_valid_sks(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ int active_valid_sks = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (subflow_is_active((struct tcp_sock *)sk) && ++ !mptcp_is_def_unavailable(sk)) ++ active_valid_sks++; ++ } ++ ++ return active_valid_sks; ++} ++ ++static bool redsched_use_subflow(struct sock *meta_sk, ++ int active_valid_sks, ++ struct tcp_sock *tp, ++ struct sk_buff *skb) ++{ ++ if (!skb || !mptcp_is_available((struct sock *)tp, skb, false)) ++ return false; ++ ++ if (TCP_SKB_CB(skb)->path_mask != 0) ++ return subflow_is_active(tp); ++ ++ if (TCP_SKB_CB(skb)->path_mask == 0) { ++ if (active_valid_sks == -1) ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ if (subflow_is_backup(tp) && active_valid_sks > 0) ++ return false; ++ else ++ return true; ++ } ++ ++ return false; ++} ++ ++#define mptcp_entry_next_rcu(__mptcp) \ ++ hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ ++ &(__mptcp)->node)), struct mptcp_tcp_sock, node) ++ ++static void redsched_update_next_subflow(struct tcp_sock *tp, ++ struct redsched_cb *red_cb) ++{ ++ struct mptcp_tcp_sock *mptcp = mptcp_entry_next_rcu(tp->mptcp); ++ ++ if (mptcp) ++ red_cb->next_subflow = mptcp->tp; ++ else ++ red_cb->next_subflow = NULL; ++} ++ ++static struct sock *red_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb *red_cb = redsched_get_cb(meta_tp); ++ struct tcp_sock *first_tp = red_cb->next_subflow, *tp; ++ struct mptcp_tcp_sock *mptcp; ++ int found = 0; ++ ++ /* Answer data_fin on same subflow */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk)->mptcp->path_index == ++ mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ if (!first_tp && !hlist_empty(&mpcb->conn_list)) { ++ first_tp = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(&mpcb->conn_list)), ++ struct mptcp_tcp_sock, node)->tp; ++ } ++ tp = first_tp; ++ ++ /* still NULL (no subflow in conn_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ /* Search for a subflow to send it. ++ * ++ * We want to pick a subflow that is after 'first_tp' in the list of subflows. ++ * Thus, the first mptcp_for_each_sub()-loop tries to walk the list up ++ * to the subflow 'tp' and then checks whether any one of the remaining ++ * ones is eligible to send. ++ * The second mptcp_for_each-sub()-loop is then iterating from the ++ * beginning of the list up to 'first_tp'. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ /* We go up to the subflow 'tp' and start from there */ ++ if (tp == mptcp->tp) ++ found = 1; ++ ++ if (!found) ++ continue; ++ tp = mptcp->tp; ++ ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ redsched_update_next_subflow(tp, red_cb); ++ return (struct sock *)tp; ++ } ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ tp = mptcp->tp; ++ ++ if (tp == first_tp) ++ break; ++ ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ redsched_update_next_subflow(tp, red_cb); ++ return (struct sock *)tp; ++ } ++ } ++ ++ /* No space */ ++ return NULL; ++} ++ ++/* Corrects the stored skb pointers if they are invalid */ ++static void redsched_correct_skb_pointers(struct sock *meta_sk, ++ struct redsched_priv *red_p) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (red_p->skb && !after(red_p->skb_end_seq, meta_tp->snd_una)) ++ red_p->skb = NULL; ++} ++ ++/* Returns the next skb from the queue */ ++static struct sk_buff *redsched_next_skb_from_queue(struct sk_buff_head *queue, ++ struct sk_buff *previous, ++ struct sock *meta_sk) ++{ ++ struct sk_buff *skb; ++ ++ if (!previous) ++ return skb_peek(queue); ++ ++ /* sk_data->skb stores the last scheduled packet for this subflow. ++ * If sk_data->skb was scheduled but not sent (e.g., due to nagle), ++ * we have to schedule it again. ++ * ++ * For the redundant scheduler, there are two cases: ++ * 1. sk_data->skb was not sent on another subflow: ++ * we have to schedule it again to ensure that we do not ++ * skip this packet. ++ * 2. sk_data->skb was already sent on another subflow: ++ * with regard to the redundant semantic, we have to ++ * schedule it again. However, we keep it simple and ignore it, ++ * as it was already sent by another subflow. ++ * This might be changed in the future. ++ * ++ * For case 1, send_head is equal previous, as only a single ++ * packet can be skipped. ++ */ ++ if (tcp_send_head(meta_sk) == previous) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_rb_next(previous); ++ if (skb) ++ return skb; ++ ++ return tcp_send_head(meta_sk); ++} ++ ++static struct sk_buff *mptcp_red_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb *red_cb = redsched_get_cb(meta_tp); ++ struct tcp_sock *first_tp = red_cb->next_subflow, *tp; ++ struct mptcp_tcp_sock *mptcp; ++ int active_valid_sks = -1; ++ struct sk_buff *skb; ++ int found = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (skb_queue_empty(&mpcb->reinject_queue) && ++ skb_queue_empty(&meta_sk->sk_write_queue)) ++ /* Nothing to send */ ++ return NULL; ++ ++ /* First try reinjections */ ++ skb = skb_peek(&mpcb->reinject_queue); ++ if (skb) { ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ *reinject = 1; ++ return skb; ++ } ++ ++ /* Then try indistinctly redundant and normal skbs */ ++ ++ if (!first_tp && !hlist_empty(&mpcb->conn_list)) { ++ first_tp = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(&mpcb->conn_list)), ++ struct mptcp_tcp_sock, node)->tp; ++ } ++ ++ /* still NULL (no subflow in conn_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ tp = first_tp; ++ ++ *reinject = 0; ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ /* We want to pick a subflow that is after 'first_tp' in the list of subflows. ++ * Thus, the first mptcp_for_each_sub()-loop tries to walk the list up ++ * to the subflow 'tp' and then checks whether any one of the remaining ++ * ones can send a segment. ++ * The second mptcp_for_each-sub()-loop is then iterating from the ++ * beginning of the list up to 'first_tp'. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct redsched_priv *red_p; ++ ++ if (tp == mptcp->tp) ++ found = 1; ++ ++ if (!found) ++ continue; ++ ++ tp = mptcp->tp; ++ ++ /* Correct the skb pointers of the current subflow */ ++ red_p = redsched_get_priv(tp); ++ redsched_correct_skb_pointers(meta_sk, red_p); ++ ++ skb = redsched_next_skb_from_queue(&meta_sk->sk_write_queue, ++ red_p->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ red_p->skb = skb; ++ red_p->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ redsched_update_next_subflow(tp, red_cb); ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct redsched_priv *red_p; ++ ++ tp = mptcp->tp; ++ ++ if (tp == first_tp) ++ break; ++ ++ /* Correct the skb pointers of the current subflow */ ++ red_p = redsched_get_priv(tp); ++ redsched_correct_skb_pointers(meta_sk, red_p); ++ ++ skb = redsched_next_skb_from_queue(&meta_sk->sk_write_queue, ++ red_p->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ red_p->skb = skb; ++ red_p->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ redsched_update_next_subflow(tp, red_cb); ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ } ++ ++ /* Nothing to send */ ++ return NULL; ++} ++ ++static void redsched_release(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct redsched_cb *red_cb = redsched_get_cb(tp); ++ ++ /* Check if the next subflow would be the released one. If yes correct ++ * the pointer ++ */ ++ if (red_cb->next_subflow == tp) ++ redsched_update_next_subflow(tp, red_cb); ++} ++ ++static struct mptcp_sched_ops mptcp_sched_red = { ++ .get_subflow = red_get_available_subflow, ++ .next_segment = mptcp_red_next_segment, ++ .release = redsched_release, ++ .name = "redundant", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init red_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct redsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct redsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_red)) ++ return -1; ++ ++ return 0; ++} ++ ++static void red_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_red); ++} ++ ++module_init(red_register); ++module_exit(red_unregister); ++ ++MODULE_AUTHOR("Tobias Erbshaeusser, Alexander Froemmgen"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("REDUNDANT MPTCP"); ++MODULE_VERSION("0.90"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_rr.c mptcp-mptcp_v0.95/net/mptcp/mptcp_rr.c +--- linux-4.19.104/net/mptcp/mptcp_rr.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_rr.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,309 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static unsigned char num_segments __read_mostly = 1; ++module_param(num_segments, byte, 0644); ++MODULE_PARM_DESC(num_segments, "The number of consecutive segments that are part of a burst"); ++ ++static bool cwnd_limited __read_mostly = 1; ++module_param(cwnd_limited, bool, 0644); ++MODULE_PARM_DESC(cwnd_limited, "if set to 1, the scheduler tries to fill the congestion-window on all subflows"); ++ ++struct rrsched_priv { ++ unsigned char quota; ++}; ++ ++static struct rrsched_priv *rrsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct rrsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* If the sub-socket sk available to send the skb? */ ++static bool mptcp_rr_is_available(const struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test, bool cwnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int space, in_flight; ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return false; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return false; ++ ++ if (tp->pf) ++ return false; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been acked. ++ * (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return false; ++ else if (tp->snd_una != tp->high_seq) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return false; ++ } ++ ++ if (!cwnd_test) ++ goto zero_wnd_test; ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return false; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return false; ++ ++zero_wnd_test: ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return false; ++ ++ return true; ++} ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_rr_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++/* We just look for any subflow that is available */ ++static struct sock *rr_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk = NULL, *bestsk = NULL, *backupsk = NULL; ++ struct mptcp_tcp_sock *mptcp; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ return sk; ++ } ++ } ++ ++ /* First, find the best subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct tcp_sock *tp; ++ ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ++ if (!mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ continue; ++ ++ if (mptcp_rr_dont_reinject_skb(tp, skb)) { ++ backupsk = sk; ++ continue; ++ } ++ ++ bestsk = sk; ++ } ++ ++ if (bestsk) { ++ sk = bestsk; ++ } else if (backupsk) { ++ /* It has been sent on all subflows once - let's give it a ++ * chance again by restarting its pathmask. ++ */ ++ if (skb) ++ TCP_SKB_CB(skb)->path_mask = 0; ++ sk = backupsk; ++ } ++ ++ return sk; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_rr_next_segment(const struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) ++ *reinject = 1; ++ else ++ skb = tcp_send_head(meta_sk); ++ return skb; ++} ++ ++static struct sk_buff *mptcp_rr_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *choose_sk = NULL; ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb = __mptcp_rr_next_segment(meta_sk, reinject); ++ unsigned char split = num_segments; ++ unsigned char iter = 0, full_subs = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ if (*reinject) { ++ *subsk = rr_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ return skb; ++ } ++ ++retry: ++ ++ /* First, we look for a subflow who is currently being used */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rr_p = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ iter++; ++ ++ /* Is this subflow currently being used? */ ++ if (rr_p->quota > 0 && rr_p->quota < num_segments) { ++ split = num_segments - rr_p->quota; ++ choose_sk = sk_it; ++ goto found; ++ } ++ ++ /* Or, it's totally unused */ ++ if (!rr_p->quota) { ++ split = num_segments; ++ choose_sk = sk_it; ++ } ++ ++ /* Or, it must then be fully used */ ++ if (rr_p->quota >= num_segments) ++ full_subs++; ++ } ++ ++ /* All considered subflows have a full quota, and we considered at ++ * least one. ++ */ ++ if (iter && iter == full_subs) { ++ /* So, we restart this round by setting quota to 0 and retry ++ * to find a subflow. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rr_p = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ rr_p->quota = 0; ++ } ++ ++ goto retry; ++ } ++ ++found: ++ if (choose_sk) { ++ unsigned int mss_now; ++ struct tcp_sock *choose_tp = tcp_sk(choose_sk); ++ struct rrsched_priv *rr_p = rrsched_get_priv(choose_tp); ++ ++ if (!mptcp_rr_is_available(choose_sk, skb, false, true)) ++ return NULL; ++ ++ *subsk = choose_sk; ++ mss_now = tcp_current_mss(*subsk); ++ *limit = split * mss_now; ++ ++ if (skb->len > mss_now) ++ rr_p->quota += DIV_ROUND_UP(skb->len, mss_now); ++ else ++ rr_p->quota++; ++ ++ return skb; ++ } ++ ++ return NULL; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_rr = { ++ .get_subflow = rr_get_available_subflow, ++ .next_segment = mptcp_rr_next_segment, ++ .name = "roundrobin", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init rr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct rrsched_priv) > MPTCP_SCHED_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_rr)) ++ return -1; ++ ++ return 0; ++} ++ ++static void rr_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_rr); ++} ++ ++module_init(rr_register); ++module_exit(rr_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ROUNDROBIN MPTCP"); ++MODULE_VERSION("0.89"); +diff -aurN linux-4.19.104/net/mptcp/mptcp_sched.c mptcp-mptcp_v0.95/net/mptcp/mptcp_sched.c +--- linux-4.19.104/net/mptcp/mptcp_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_sched.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,634 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_sched_list_lock); ++static LIST_HEAD(mptcp_sched_list); ++ ++struct defsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++static struct defsched_priv *defsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct defsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++bool mptcp_is_def_unavailable(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return true; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return true; ++ ++ if (tp->pf) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(mptcp_is_def_unavailable); ++ ++static bool mptcp_is_temp_unavailable(struct sock *sk, ++ const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int mss_now, space, in_flight; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been ++ * acked. (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return true; ++ else if (tp->snd_una != tp->high_seq) ++ return true; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return true; ++ } ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return true; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return true; ++ ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return true; ++ ++ mss_now = tcp_current_mss(sk); ++ ++ /* Don't send on this subflow if we bypass the allowed send-window at ++ * the per-subflow level. Similar to tcp_snd_wnd_test, but manually ++ * calculated end_seq (because here at this point end_seq is still at ++ * the meta-level). ++ */ ++ if (skb && zero_wnd_test && ++ after(tp->write_seq + min(skb->len, mss_now), tcp_wnd_end(tp))) ++ return true; ++ ++ return false; ++} ++ ++/* Is the sub-socket sk available to send the skb? */ ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ return !mptcp_is_def_unavailable(sk) && ++ !mptcp_is_temp_unavailable(sk, skb, zero_wnd_test); ++} ++EXPORT_SYMBOL_GPL(mptcp_is_available); ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++bool subflow_is_backup(const struct tcp_sock *tp) ++{ ++ return tp->mptcp->rcv_low_prio || tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_backup); ++ ++bool subflow_is_active(const struct tcp_sock *tp) ++{ ++ return !tp->mptcp->rcv_low_prio && !tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_active); ++ ++/* Generic function to iterate over used and unused subflows and to select the ++ * best one ++ */ ++static struct sock ++*get_subflow_from_selectors(struct mptcp_cb *mpcb, struct sk_buff *skb, ++ bool (*selector)(const struct tcp_sock *), ++ bool zero_wnd_test, bool *force) ++{ ++ struct sock *bestsk = NULL; ++ u32 min_srtt = 0xffffffff; ++ bool found_unused = false; ++ bool found_unused_una = false; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ bool unused = false; ++ ++ /* First, we choose only the wanted sks */ ++ if (!(*selector)(tp)) ++ continue; ++ ++ if (!mptcp_dont_reinject_skb(tp, skb)) ++ unused = true; ++ else if (found_unused) ++ /* If a unused sk was found previously, we continue - ++ * no need to check used sks anymore. ++ */ ++ continue; ++ ++ if (mptcp_is_def_unavailable(sk)) ++ continue; ++ ++ if (mptcp_is_temp_unavailable(sk, skb, zero_wnd_test)) { ++ if (unused) ++ found_unused_una = true; ++ continue; ++ } ++ ++ if (unused) { ++ if (!found_unused) { ++ /* It's the first time we encounter an unused ++ * sk - thus we reset the bestsk (which might ++ * have been set to a used sk). ++ */ ++ min_srtt = 0xffffffff; ++ bestsk = NULL; ++ } ++ found_unused = true; ++ } ++ ++ if (tp->srtt_us < min_srtt) { ++ min_srtt = tp->srtt_us; ++ bestsk = sk; ++ } ++ } ++ ++ if (bestsk) { ++ /* The force variable is used to mark the returned sk as ++ * previously used or not-used. ++ */ ++ if (found_unused) ++ *force = true; ++ else ++ *force = false; ++ } else { ++ /* The force variable is used to mark if there are temporally ++ * unavailable not-used sks. ++ */ ++ if (found_unused_una) ++ *force = true; ++ else ++ *force = false; ++ } ++ ++ return bestsk; ++} ++ ++/* This is the scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy, NULL is returned ++ * The flow is selected based on the shortest RTT. ++ * If all paths have full cong windows, we simply return NULL. ++ * ++ * Additionally, this function is aware of the backup-subflows. ++ */ ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk; ++ bool looping = false, force; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ /* Find the best subflow */ ++restart: ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_active, ++ zero_wnd_test, &force); ++ if (force) ++ /* one unused active sk or one NULL sk when there is at least ++ * one temporally unavailable unused active sk ++ */ ++ return sk; ++ ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_backup, ++ zero_wnd_test, &force); ++ if (!force && skb) { ++ /* one used backup sk or one NULL sk where there is no one ++ * temporally unavailable unused backup sk ++ * ++ * the skb passed through all the available active and backups ++ * sks, so clean the path mask ++ */ ++ TCP_SKB_CB(skb)->path_mask = 0; ++ ++ if (!looping) { ++ looping = true; ++ goto restart; ++ } ++ } ++ return sk; ++} ++EXPORT_SYMBOL_GPL(get_available_subflow); ++ ++static struct sk_buff *mptcp_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb_head; ++ struct defsched_priv *def_p = defsched_get_priv(tp); ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!skb_head) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_jiffies32 - def_p->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flows */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ def_p->last_rbuf_opti = tcp_jiffies32; ++ } ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) { ++ trace_mptcp_retransmit(sk, skb_head); ++ return skb_head; ++ } ++ } ++ return NULL; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = get_available_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++static struct sk_buff *mptcp_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_next_segment(meta_sk, reinject); ++ unsigned int mss_now; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ u32 max_len, max_segs, window, needed; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ * ++ * So, we first limit according to the cwnd/gso-size and then according ++ * to the subflow's window. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ max_len = mss_now * max_segs; ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ needed = min(skb->len, window); ++ if (max_len <= skb->len) ++ /* Take max_win, which is actually the cwnd/gso-size */ ++ *limit = max_len; ++ else ++ /* Or, take the window */ ++ *limit = needed; ++ ++ return skb; ++} ++ ++static void defsched_init(struct sock *sk) ++{ ++ struct defsched_priv *def_p = defsched_get_priv(tcp_sk(sk)); ++ ++ def_p->last_rbuf_opti = tcp_jiffies32; ++} ++ ++struct mptcp_sched_ops mptcp_sched_default = { ++ .get_subflow = get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = defsched_init, ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_sched_ops *mptcp_sched_find(const char *name) ++{ ++ struct mptcp_sched_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_sched_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched) ++{ ++ int ret = 0; ++ ++ if (!sched->get_subflow || !sched->next_segment) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ if (mptcp_sched_find(sched->name)) { ++ pr_notice("%s already registered\n", sched->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&sched->list, &mptcp_sched_list); ++ pr_info("%s registered\n", sched->name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_scheduler); ++ ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched) ++{ ++ spin_lock(&mptcp_sched_list_lock); ++ list_del_rcu(&sched->list); ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_scheduler); ++ ++void mptcp_get_default_scheduler(char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ ++ BUG_ON(list_empty(&mptcp_sched_list)); ++ ++ rcu_read_lock(); ++ sched = list_entry(mptcp_sched_list.next, struct mptcp_sched_ops, list); ++ strncpy(name, sched->name, MPTCP_SCHED_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_scheduler(const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ ++ if (sched) { ++ list_move(&sched->list, &mptcp_sched_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++ ++/* Must be called with rcu lock held */ ++static struct mptcp_sched_ops *__mptcp_sched_find_autoload(const char *name) ++{ ++ struct mptcp_sched_ops *sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ return sched; ++} ++ ++void mptcp_init_scheduler(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_sched_ops *sched; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if scheduler was set using socket option */ ++ if (meta_tp->mptcp_sched_setsockopt) { ++ sched = __mptcp_sched_find_autoload(meta_tp->mptcp_sched_name); ++ if (sched && try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(sched, &mptcp_sched_list, list) { ++ if (try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change scheduler for socket */ ++int mptcp_set_scheduler(struct sock *sk, const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int err = 0; ++ ++ rcu_read_lock(); ++ sched = __mptcp_sched_find_autoload(name); ++ ++ if (!sched) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_sched_name, name); ++ tcp_sk(sk)->mptcp_sched_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->sched_ops->owner); ++} ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_scheduler_default(void) ++{ ++ BUILD_BUG_ON(sizeof(struct defsched_priv) > MPTCP_SCHED_SIZE); ++ ++ return mptcp_set_default_scheduler(CONFIG_DEFAULT_MPTCP_SCHED); ++} ++late_initcall(mptcp_scheduler_default); +diff -aurN linux-4.19.104/net/mptcp/mptcp_wvegas.c mptcp-mptcp_v0.95/net/mptcp/mptcp_wvegas.c +--- linux-4.19.104/net/mptcp/mptcp_wvegas.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.95/net/mptcp/mptcp_wvegas.c 2020-02-17 11:29:55.000000000 +0100 +@@ -0,0 +1,271 @@ ++/* ++ * MPTCP implementation - WEIGHTED VEGAS ++ * ++ * Algorithm design: ++ * Yu Cao ++ * Mingwei Xu ++ * Xiaoming Fu ++ * ++ * Implementation: ++ * Yu Cao ++ * Enhuan Dong ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int initial_alpha = 2; ++static int total_alpha = 10; ++static int gamma = 1; ++ ++module_param(initial_alpha, int, 0644); ++MODULE_PARM_DESC(initial_alpha, "initial alpha for all subflows"); ++module_param(total_alpha, int, 0644); ++MODULE_PARM_DESC(total_alpha, "total alpha for all subflows"); ++module_param(gamma, int, 0644); ++MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)"); ++ ++#define MPTCP_WVEGAS_SCALE 16 ++ ++/* wVegas variables */ ++struct wvegas { ++ u32 beg_snd_nxt; /* right edge during last RTT */ ++ u8 doing_wvegas_now;/* if true, do wvegas for this RTT */ ++ ++ u16 cnt_rtt; /* # of RTTs measured within last RTT */ ++ u32 sampled_rtt; /* cumulative RTTs measured within last RTT (in usec) */ ++ u32 base_rtt; /* the min of all wVegas RTT measurements seen (in usec) */ ++ ++ u64 instant_rate; /* cwnd / srtt_us, unit: pkts/us * 2^16 */ ++ u64 weight; /* the ratio of subflow's rate to the total rate, * 2^16 */ ++ int alpha; /* alpha for each subflows */ ++ ++ u32 queue_delay; /* queue delay*/ ++}; ++ ++ ++static inline u64 mptcp_wvegas_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static void wvegas_enable(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 1; ++ ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ ++ wvegas->instant_rate = 0; ++ wvegas->alpha = initial_alpha; ++ wvegas->weight = mptcp_wvegas_scale(1, MPTCP_WVEGAS_SCALE); ++ ++ wvegas->queue_delay = 0; ++} ++ ++static inline void wvegas_disable(const struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 0; ++} ++ ++static void mptcp_wvegas_init(struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->base_rtt = 0x7fffffff; ++ wvegas_enable(sk); ++} ++ ++static inline u64 mptcp_wvegas_rate(u32 cwnd, u32 rtt_us) ++{ ++ return div_u64(mptcp_wvegas_scale(cwnd, MPTCP_WVEGAS_SCALE), rtt_us); ++} ++ ++static void mptcp_wvegas_pkts_acked(struct sock *sk, ++ const struct ack_sample *sample) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ u32 vrtt; ++ ++ if (sample->rtt_us < 0) ++ return; ++ ++ vrtt = sample->rtt_us + 1; ++ ++ if (vrtt < wvegas->base_rtt) ++ wvegas->base_rtt = vrtt; ++ ++ wvegas->sampled_rtt += vrtt; ++ wvegas->cnt_rtt++; ++} ++ ++static void mptcp_wvegas_state(struct sock *sk, u8 ca_state) ++{ ++ if (ca_state == TCP_CA_Open) ++ wvegas_enable(sk); ++ else ++ wvegas_disable(sk); ++} ++ ++static void mptcp_wvegas_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_CWND_RESTART) { ++ mptcp_wvegas_init(sk); ++ } else if (event == CA_EVENT_LOSS) { ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ wvegas->instant_rate = 0; ++ } ++} ++ ++static inline u32 mptcp_wvegas_ssthresh(const struct tcp_sock *tp) ++{ ++ return min(tp->snd_ssthresh, tp->snd_cwnd); ++} ++ ++static u64 mptcp_wvegas_weight(const struct mptcp_cb *mpcb, const struct sock *sk) ++{ ++ u64 total_rate = 0; ++ const struct wvegas *wvegas = inet_csk_ca(sk); ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (!mpcb) ++ return wvegas->weight; ++ ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct wvegas *sub_wvegas = inet_csk_ca(sub_sk); ++ ++ /* sampled_rtt is initialized by 0 */ ++ if (mptcp_sk_can_send(sub_sk) && (sub_wvegas->sampled_rtt > 0)) ++ total_rate += sub_wvegas->instant_rate; ++ } ++ ++ if (total_rate && wvegas->instant_rate) ++ return div64_u64(mptcp_wvegas_scale(wvegas->instant_rate, MPTCP_WVEGAS_SCALE), total_rate); ++ else ++ return wvegas->weight; ++} ++ ++static void mptcp_wvegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!wvegas->doing_wvegas_now) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (after(ack, wvegas->beg_snd_nxt)) { ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ if (wvegas->cnt_rtt <= 2) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ } else { ++ u32 rtt, diff, q_delay; ++ u64 target_cwnd; ++ ++ rtt = wvegas->sampled_rtt / wvegas->cnt_rtt; ++ target_cwnd = div_u64(((u64)tp->snd_cwnd * wvegas->base_rtt), rtt); ++ ++ diff = div_u64((u64)tp->snd_cwnd * (rtt - wvegas->base_rtt), rtt); ++ ++ if (diff > gamma && tcp_in_slow_start(tp)) { ++ tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ ++ } else if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ } else { ++ if (diff >= wvegas->alpha) { ++ wvegas->instant_rate = mptcp_wvegas_rate(tp->snd_cwnd, rtt); ++ wvegas->weight = mptcp_wvegas_weight(tp->mpcb, sk); ++ wvegas->alpha = max(2U, (u32)((wvegas->weight * total_alpha) >> MPTCP_WVEGAS_SCALE)); ++ } ++ if (diff > wvegas->alpha) { ++ tp->snd_cwnd--; ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ } else if (diff < wvegas->alpha) { ++ tp->snd_cwnd++; ++ } ++ ++ /* Try to drain link queue if needed*/ ++ q_delay = rtt - wvegas->base_rtt; ++ if ((wvegas->queue_delay == 0) || (wvegas->queue_delay > q_delay)) ++ wvegas->queue_delay = q_delay; ++ ++ if (q_delay >= 2 * wvegas->queue_delay) { ++ u32 backoff_factor = div_u64(mptcp_wvegas_scale(wvegas->base_rtt, MPTCP_WVEGAS_SCALE), 2 * rtt); ++ tp->snd_cwnd = ((u64)tp->snd_cwnd * backoff_factor) >> MPTCP_WVEGAS_SCALE; ++ wvegas->queue_delay = 0; ++ } ++ } ++ ++ if (tp->snd_cwnd < 2) ++ tp->snd_cwnd = 2; ++ else if (tp->snd_cwnd > tp->snd_cwnd_clamp) ++ tp->snd_cwnd = tp->snd_cwnd_clamp; ++ ++ tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ } ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ } ++ /* Use normal slow start */ ++ else if (tcp_in_slow_start(tp)) ++ tcp_slow_start(tp, acked); ++} ++ ++ ++static struct tcp_congestion_ops mptcp_wvegas __read_mostly = { ++ .init = mptcp_wvegas_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_wvegas_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .pkts_acked = mptcp_wvegas_pkts_acked, ++ .set_state = mptcp_wvegas_state, ++ .cwnd_event = mptcp_wvegas_cwnd_event, ++ ++ .owner = THIS_MODULE, ++ .name = "wvegas", ++}; ++ ++static int __init mptcp_wvegas_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct wvegas) > ICSK_CA_PRIV_SIZE); ++ tcp_register_congestion_control(&mptcp_wvegas); ++ return 0; ++} ++ ++static void __exit mptcp_wvegas_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_wvegas); ++} ++ ++module_init(mptcp_wvegas_register); ++module_exit(mptcp_wvegas_unregister); ++ ++MODULE_AUTHOR("Yu Cao, Enhuan Dong"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP wVegas"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.19.104/tools/include/uapi/linux/bpf.h mptcp-mptcp_v0.95/tools/include/uapi/linux/bpf.h +--- linux-4.19.104/tools/include/uapi/linux/bpf.h 2020-02-14 22:33:28.000000000 +0100 ++++ mptcp-mptcp_v0.95/tools/include/uapi/linux/bpf.h 2020-02-17 11:29:55.000000000 +0100 +@@ -2672,6 +2672,7 @@ + BPF_TCP_LISTEN, + BPF_TCP_CLOSING, /* Now a valid state */ + BPF_TCP_NEW_SYN_RECV, ++ BPF_TCP_RST_WAIT, + + BPF_TCP_MAX_STATES /* Leave at the end! */ + }; diff --git a/root/target/linux/generic/hack-4.19/691-mptcp_ecf.patch b/root/target/linux/generic/hack-4.19/691-mptcp_ecf.patch new file mode 100644 index 00000000..d9cf6251 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/691-mptcp_ecf.patch @@ -0,0 +1,434 @@ +From 35f41229b58cb8c2611207827aa4f658b82db67e Mon Sep 17 00:00:00 2001 +From: Daniel Weber +Date: Mon, 5 Aug 2019 14:02:30 +0200 +Subject: [PATCH] mptcp: Earliest Completion First (ECF) Scheduler + +This scheduler works much like the default MPTCP scheduler. It always +prefers the subflow with the smallest round-trip-time that is available. + +Signed-off-by: Daniel Weber +--- + net/mptcp/Kconfig | 6 + + net/mptcp/Makefile | 1 + + net/mptcp/mptcp_ecf.c | 384 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 391 insertions(+) + create mode 100644 net/mptcp/mptcp_ecf.c + +diff --git a/net/mptcp/Kconfig b/net/mptcp/Kconfig +index d22b7b47860f..dd1f859f1070 100644 +--- a/net/mptcp/Kconfig ++++ b/net/mptcp/Kconfig +@@ -109,6 +109,12 @@ config MPTCP_REDUNDANT + This scheduler sends all packets redundantly over all subflows to decreases + latency and jitter on the cost of lower throughput. + ++config MPTCP_ECF ++ tristate "MPTCP ECF" ++ depends on (MPTCP=y) ++ ---help--- ++ This is an experimental Earliest Completion First (ECF) scheduler. ++ + choice + prompt "Default MPTCP Scheduler" + default DEFAULT +diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile +index 82a2d4d945ae..369248a2f68e 100644 +--- a/net/mptcp/Makefile ++++ b/net/mptcp/Makefile +@@ -20,5 +20,6 @@ obj-$(CONFIG_MPTCP_NETLINK) += mptcp_netlink.o + obj-$(CONFIG_MPTCP_ROUNDROBIN) += mptcp_rr.o + obj-$(CONFIG_MPTCP_REDUNDANT) += mptcp_redundant.o + obj-$(CONFIG_MPTCP_BLEST) += mptcp_blest.o ++obj-$(CONFIG_MPTCP_ECF) += mptcp_ecf.o + + mptcp-$(subst m,y,$(CONFIG_IPV6)) += mptcp_ipv6.o +diff --git a/net/mptcp/mptcp_ecf.c b/net/mptcp/mptcp_ecf.c +new file mode 100644 +index 000000000000..d61f4d2ad375 +--- /dev/null ++++ b/net/mptcp/mptcp_ecf.c +@@ -0,0 +1,384 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP ECF Scheduler ++ * ++ * Algorithm Design: ++ * Yeon-sup Lim ++ * Don Towsley ++ * Erich M. Nahum ++ * Richard J. Gibbens ++ * ++ * Initial Implementation: ++ * Yeon-sup Lim ++ * ++ * Additional Authors: ++ * Daniel Weber ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++static unsigned int r_beta __read_mostly = 4; /* beta = 1/r_beta = 0.25 */ ++module_param(r_beta, int, 0644); ++MODULE_PARM_DESC(r_beta, "beta for ECF"); ++ ++struct ecfsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++struct ecfsched_cb { ++ u32 switching_margin; /* this is "waiting" in algorithm description */ ++}; ++ ++static struct ecfsched_priv *ecfsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct ecfsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++static struct ecfsched_cb *ecfsched_get_cb(const struct tcp_sock *tp) ++{ ++ return (struct ecfsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++/* This is the ECF scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy or the currently best ++ * subflow is estimated to be slower than waiting for minsk, NULL is returned. ++ */ ++static struct sock *ecf_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *bestsk, *minsk = NULL; ++ struct tcp_sock *besttp; ++ struct mptcp_tcp_sock *mptcp; ++ struct ecfsched_cb *ecf_cb = ecfsched_get_cb(tcp_sk(meta_sk)); ++ u32 min_srtt = U32_MAX; ++ u32 sub_sndbuf = 0; ++ u32 sub_packets_out = 0; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(bestsk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(bestsk, skb, zero_wnd_test)) ++ return bestsk; ++ } ++ } ++ ++ /* First, find the overall best (fastest) subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ besttp = tcp_sk(bestsk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(bestsk)) ++ continue; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (besttp->mptcp->pre_established) ++ continue; ++ ++ sub_sndbuf += bestsk->sk_wmem_queued; ++ sub_packets_out += besttp->packets_out; ++ ++ /* record minimal rtt */ ++ if (besttp->srtt_us < min_srtt) { ++ min_srtt = besttp->srtt_us; ++ minsk = bestsk; ++ } ++ } ++ ++ /* find the current best subflow according to the default scheduler */ ++ bestsk = get_available_subflow(meta_sk, skb, zero_wnd_test); ++ ++ /* if we decided to use a slower flow, we have the option of not using it at all */ ++ if (bestsk && minsk && bestsk != minsk) { ++ u32 mss = tcp_current_mss(bestsk); /* assuming equal MSS */ ++ u32 sndbuf_meta = meta_sk->sk_wmem_queued; ++ u32 sndbuf_minus = sub_sndbuf; ++ u32 sndbuf = 0; ++ ++ u32 cwnd_f = tcp_sk(minsk)->snd_cwnd; ++ u32 srtt_f = tcp_sk(minsk)->srtt_us >> 3; ++ u32 rttvar_f = tcp_sk(minsk)->rttvar_us >> 1; ++ ++ u32 cwnd_s = tcp_sk(bestsk)->snd_cwnd; ++ u32 srtt_s = tcp_sk(bestsk)->srtt_us >> 3; ++ u32 rttvar_s = tcp_sk(bestsk)->rttvar_us >> 1; ++ ++ u32 delta = max(rttvar_f, rttvar_s); ++ ++ u32 x_f; ++ u64 lhs, rhs; /* to avoid overflow, using u64 */ ++ ++ if (tcp_sk(meta_sk)->packets_out > sub_packets_out) ++ sndbuf_minus += (tcp_sk(meta_sk)->packets_out - sub_packets_out) * mss; ++ ++ if (sndbuf_meta > sndbuf_minus) ++ sndbuf = sndbuf_meta - sndbuf_minus; ++ ++ /* we have something to send. ++ * at least one time tx over fastest subflow is required ++ */ ++ x_f = sndbuf > cwnd_f * mss ? sndbuf : cwnd_f * mss; ++ lhs = srtt_f * (x_f + cwnd_f * mss); ++ rhs = cwnd_f * mss * (srtt_s + delta); ++ ++ if (r_beta * lhs < r_beta * rhs + ecf_cb->switching_margin * rhs) { ++ u32 x_s = sndbuf > cwnd_s * mss ? sndbuf : cwnd_s * mss; ++ u64 lhs_s = srtt_s * x_s; ++ u64 rhs_s = cwnd_s * mss * (2 * srtt_f + delta); ++ ++ if (lhs_s >= rhs_s) { ++ /* too slower than fastest */ ++ ecf_cb->switching_margin = 1; ++ return NULL; ++ } ++ } else { ++ /* use slower one */ ++ ecf_cb->switching_margin = 0; ++ } ++ } ++ ++ return bestsk; ++} ++ ++/* copy from mptcp_sched.c: mptcp_rcv_buf_optimization */ ++static struct sk_buff *mptcp_ecf_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb_head; ++ struct ecfsched_priv *ecf_p = ecfsched_get_priv(tp); ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!skb_head) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_jiffies32 - ecf_p->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flows */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ ecf_p->last_rbuf_opti = tcp_jiffies32; ++ } ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) { ++ trace_mptcp_retransmit(sk, skb_head); ++ return skb_head; ++ } ++ } ++ return NULL; ++} ++ ++/* copy from mptcp_sched.c: __mptcp_next_segment */ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_ecf_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = ecf_get_available_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_ecf_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++/* copy from mptcp_sched.c: mptcp_next_segment */ ++static struct sk_buff *mptcp_ecf_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_ecf_next_segment(meta_sk, reinject); ++ unsigned int mss_now; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ u32 max_len, max_segs, window, needed; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = ecf_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_ecf_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ * ++ * So, we first limit according to the cwnd/gso-size and then according ++ * to the subflow's window. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ max_len = mss_now * max_segs; ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ needed = min(skb->len, window); ++ if (max_len <= skb->len) ++ /* Take max_win, which is actually the cwnd/gso-size */ ++ *limit = max_len; ++ else ++ /* Or, take the window */ ++ *limit = needed; ++ ++ return skb; ++} ++ ++static void ecfsched_init(struct sock *sk) ++{ ++ struct ecfsched_priv *ecf_p = ecfsched_get_priv(tcp_sk(sk)); ++ struct ecfsched_cb *ecf_cb = ecfsched_get_cb(tcp_sk(mptcp_meta_sk(sk))); ++ ++ ecf_p->last_rbuf_opti = tcp_jiffies32; ++ ecf_cb->switching_margin = 0; ++} ++ ++struct mptcp_sched_ops mptcp_sched_ecf = { ++ .get_subflow = ecf_get_available_subflow, ++ .next_segment = mptcp_ecf_next_segment, ++ .init = ecfsched_init, ++ .name = "ecf", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init ecf_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ecfsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct ecfsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_ecf)) ++ return -1; ++ ++ return 0; ++} ++ ++static void ecf_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_ecf); ++} ++ ++module_init(ecf_register); ++module_exit(ecf_unregister); ++ ++MODULE_AUTHOR("Yeon-sup Lim, Daniel Weber"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ECF (Earliest Completion First) scheduler for MPTCP, based on default minimum RTT scheduler"); ++MODULE_VERSION("0.95"); diff --git a/root/target/linux/generic/hack-4.19/692-tcp_nanqinlang.patch b/root/target/linux/generic/hack-4.19/692-tcp_nanqinlang.patch new file mode 100644 index 00000000..56051ae7 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/692-tcp_nanqinlang.patch @@ -0,0 +1,1037 @@ +--- a/net/ipv4/Makefile.anc 2019-11-23 23:01:47.069966970 +0100 ++++ b/net/ipv4/Makefile 2019-11-23 23:03:01.416428035 +0100 +@@ -48,6 +48,7 @@ + obj-$(CONFIG_INET_UDP_DIAG) += udp_diag.o + obj-$(CONFIG_INET_RAW_DIAG) += raw_diag.o + obj-$(CONFIG_TCP_CONG_BBR) += tcp_bbr.o ++obj-$(CONFIG_TCP_CONG_NANQINLANG) += tcp_nanqinlang.o + obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o + obj-$(CONFIG_TCP_CONG_CDG) += tcp_cdg.o + obj-$(CONFIG_TCP_CONG_CUBIC) += tcp_cubic.o +--- a/net/ipv4/Kconfig.anc 2019-11-23 23:01:52.649851417 +0100 ++++ b/net/ipv4/Kconfig 2019-11-23 23:04:21.974762180 +0100 +@@ -681,6 +681,21 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_NANQINLANG ++ tristate "NANGINLANG TCP" ++ default n ++ ---help--- ++ ++ BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to ++ maximize network utilization and minimize queues. It builds an explicit ++ model of the the bottleneck delivery rate and path round-trip ++ propagation delay. It tolerates packet loss and delay unrelated to ++ congestion. It can operate over LAN, WAN, cellular, wifi, or cable ++ modem links. It can coexist with flows that use loss-based congestion ++ control, and can operate with shallow buffers, deep buffers, ++ bufferbloat, policers, or AQM schemes that do not provide a delay ++ signal. It requires the fq ("Fair Queue") pacing packet scheduler. ++ + config TCP_CONG_LIA + tristate "MPTCP Linked Increase" + depends on MPTCP +@@ -763,6 +778,9 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_NANQINLANG ++ bool "BBR" if TCP_CONG_NANQINLANG=y ++ + config DEFAULT_LIA + bool "Lia" if TCP_CONG_LIA=y + +@@ -806,6 +824,7 @@ + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG + default "bbr" if DEFAULT_BBR ++ default "nanqinlang" if DEFAULT_NANQINLANG + default "cubic" + + config TCP_MD5SIG +--- /dev/null 2019-11-25 21:13:36.728349757 +0100 ++++ b/net/ipv4/tcp_nanqinlang.c 2019-11-25 21:10:00.392068414 +0100 +@@ -0,0 +1,982 @@ ++/* Bottleneck Bandwidth and RTT (BBR) congestion control ++ * ++ * BBR congestion control computes the sending rate based on the delivery ++ * rate (throughput) estimated from ACKs. In a nutshell: ++ * ++ * On each ACK, update our model of the network path: ++ * bottleneck_bandwidth = windowed_max(delivered / elapsed, 10 round trips) ++ * min_rtt = windowed_min(rtt, 10 seconds) ++ * pacing_rate = pacing_gain * bottleneck_bandwidth ++ * cwnd = max(cwnd_gain * bottleneck_bandwidth * min_rtt, 4) ++ * ++ * The core algorithm does not react directly to packet losses or delays, ++ * although BBR may adjust the size of next send per ACK when loss is ++ * observed, or adjust the sending rate if it estimates there is a ++ * traffic policer, in order to keep the drop rate reasonable. ++ * ++ * Here is a state transition diagram for BBR: ++ * ++ * | ++ * V ++ * +---> STARTUP ----+ ++ * | | | ++ * | V | ++ * | DRAIN ----+ ++ * | | | ++ * | V | ++ * +---> PROBE_BW ----+ ++ * | ^ | | ++ * | | | | ++ * | +----+ | ++ * | | ++ * +---- PROBE_RTT <--+ ++ * ++ * A BBR flow starts in STARTUP, and ramps up its sending rate quickly. ++ * When it estimates the pipe is full, it enters DRAIN to drain the queue. ++ * In steady state a BBR flow only uses PROBE_BW and PROBE_RTT. ++ * A long-lived BBR flow spends the vast majority of its time remaining ++ * (repeatedly) in PROBE_BW, fully probing and utilizing the pipe's bandwidth ++ * in a fair manner, with a small, bounded queue. *If* a flow has been ++ * continuously sending for the entire min_rtt window, and hasn't seen an RTT ++ * sample that matches or decreases its min_rtt estimate for 10 seconds, then ++ * it briefly enters PROBE_RTT to cut inflight to a minimum value to re-probe ++ * the path's two-way propagation delay (min_rtt). When exiting PROBE_RTT, if ++ * we estimated that we reached the full bw of the pipe then we enter PROBE_BW; ++ * otherwise we enter STARTUP to try to fill the pipe. ++ * ++ * BBR is described in detail in: ++ * "BBR: Congestion-Based Congestion Control", ++ * Neal Cardwell, Yuchung Cheng, C. Stephen Gunn, Soheil Hassas Yeganeh, ++ * Van Jacobson. ACM Queue, Vol. 14 No. 5, September-October 2016. ++ * ++ * There is a public e-mail list for discussing BBR development and testing: ++ * https://groups.google.com/forum/#!forum/bbr-dev ++ * ++ * NOTE: BBR might be used with the fq qdisc ("man tc-fq") with pacing enabled, ++ * otherwise TCP stack falls back to an internal pacing using one high ++ * resolution timer per TCP socket and may use more resources. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Scale factor for rate in pkt/uSec unit to avoid truncation in bandwidth ++ * estimation. The rate unit ~= (1500 bytes / 1 usec / 2^24) ~= 715 bps. ++ * This handles bandwidths from 0.06pps (715bps) to 256Mpps (3Tbps) in a u32. ++ * Since the minimum window is >=4 packets, the lower bound isn't ++ * an issue. The upper bound isn't an issue with existing technologies. ++ */ ++#define BW_SCALE 24 ++#define BW_UNIT (1 << BW_SCALE) ++ ++#define BBR_SCALE 8 /* scaling factor for fractions in BBR (e.g. gains) */ ++#define BBR_UNIT (1 << BBR_SCALE) ++ ++/* BBR has the following modes for deciding how fast to send: */ ++enum bbr_mode { ++ BBR_STARTUP, /* ramp up sending rate rapidly to fill pipe */ ++ BBR_DRAIN, /* drain any queue created during startup */ ++ BBR_PROBE_BW, /* discover, share bw: pace around estimated bw */ ++ BBR_PROBE_RTT, /* cut inflight to min to probe min_rtt */ ++}; ++ ++/* BBR congestion control block */ ++struct bbr { ++ u32 min_rtt_us; /* min RTT in min_rtt_win_sec window */ ++ u32 min_rtt_stamp; /* timestamp of min_rtt_us */ ++ u32 probe_rtt_done_stamp; /* end time for BBR_PROBE_RTT mode */ ++ struct minmax bw; /* Max recent delivery rate in pkts/uS << 24 */ ++ u32 rtt_cnt; /* count of packet-timed rounds elapsed */ ++ u32 next_rtt_delivered; /* scb->tx.delivered at end of round */ ++ u64 cycle_mstamp; /* time of this cycle phase start */ ++ u32 mode:3, /* current bbr_mode in state machine */ ++ prev_ca_state:3, /* CA state on previous ACK */ ++ packet_conservation:1, /* use packet conservation? */ ++ round_start:1, /* start of packet-timed tx->ack round? */ ++ idle_restart:1, /* restarting after idle? */ ++ probe_rtt_round_done:1, /* a BBR_PROBE_RTT round at 4 pkts? */ ++ unused:13, ++ lt_is_sampling:1, /* taking long-term ("LT") samples now? */ ++ lt_rtt_cnt:7, /* round trips in long-term interval */ ++ lt_use_bw:1; /* use lt_bw as our bw estimate? */ ++ u32 lt_bw; /* LT est delivery rate in pkts/uS << 24 */ ++ u32 lt_last_delivered; /* LT intvl start: tp->delivered */ ++ u32 lt_last_stamp; /* LT intvl start: tp->delivered_mstamp */ ++ u32 lt_last_lost; /* LT intvl start: tp->lost */ ++ u32 pacing_gain:10, /* current gain for setting pacing rate */ ++ cwnd_gain:10, /* current gain for setting cwnd */ ++ full_bw_reached:1, /* reached full bw in Startup? */ ++ full_bw_cnt:2, /* number of rounds without large bw gains */ ++ cycle_idx:3, /* current index in pacing_gain cycle array */ ++ has_seen_rtt:1, /* have we seen an RTT sample yet? */ ++ unused_b:5; ++ u32 prior_cwnd; /* prior cwnd upon entering loss recovery */ ++ u32 full_bw; /* recent bw, to estimate if pipe is full */ ++}; ++ ++#define CYCLE_LEN 8 /* number of phases in a pacing gain cycle */ ++ ++/* Window length of bw filter (in rounds): */ ++static const int bbr_bw_rtts = CYCLE_LEN + 2; ++/* Window length of min_rtt filter (in sec): */ ++static const u32 bbr_min_rtt_win_sec = 10; ++/* Minimum time (in ms) spent at bbr_cwnd_min_target in BBR_PROBE_RTT mode: */ ++static const u32 bbr_probe_rtt_mode_ms = 100; ++/* Skip TSO below the following bandwidth (bits/sec): */ ++static const int bbr_min_tso_rate = 1200000; ++ ++/* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain ++ * that will allow a smoothly increasing pacing rate that will double each RTT ++ * and send the same number of packets per RTT that an un-paced, slow-starting ++ * Reno or CUBIC flow would: ++ */ ++static const int bbr_high_gain = BBR_UNIT * 3000 / 1000 + 1; ++/* The pacing gain of 1/high_gain in BBR_DRAIN is calculated to typically drain ++ * the queue created in BBR_STARTUP in a single round: ++ */ ++static const int bbr_drain_gain = BBR_UNIT * 1000 / 3000; ++/* The gain for deriving steady-state cwnd tolerates delayed/stretched ACKs: */ ++static const int bbr_cwnd_gain = BBR_UNIT * 2; ++/* The pacing_gain values for the PROBE_BW gain cycle, to discover/share bw: */ ++static const int bbr_pacing_gain[] = { ++ BBR_UNIT * 6 / 4, /* probe for more available bw */ ++ BBR_UNIT * 3 / 4, /* drain queue and/or yield bw to other flows */ ++ BBR_UNIT * 5 / 4, BBR_UNIT * 5 / 4, BBR_UNIT * 5 / 4, /* cruise at 1.0*bw to utilize pipe, */ ++ BBR_UNIT * 6 / 4, BBR_UNIT * 6 / 4, BBR_UNIT * 6 / 4 /* without creating excess queue... */ ++}; ++/* Randomize the starting gain cycling phase over N phases: */ ++static const u32 bbr_cycle_rand = 7; ++ ++/* Try to keep at least this many packets in flight, if things go smoothly. For ++ * smooth functioning, a sliding window protocol ACKing every other packet ++ * needs at least 4 packets in flight: ++ */ ++static const u32 bbr_cwnd_min_target = 4; ++ ++/* To estimate if BBR_STARTUP mode (i.e. high_gain) has filled pipe... */ ++/* If bw has increased significantly (1.25x), there may be more bw available: */ ++static const u32 bbr_full_bw_thresh = BBR_UNIT * 5 / 4; ++/* But after 3 rounds w/o significant bw growth, estimate pipe is full: */ ++static const u32 bbr_full_bw_cnt = 3; ++ ++/* "long-term" ("LT") bandwidth estimator parameters... */ ++/* The minimum number of rounds in an LT bw sampling interval: */ ++static const u32 bbr_lt_intvl_min_rtts = 4; ++/* If lost/delivered ratio > 20%, interval is "lossy" and we may be policed: */ ++static const u32 bbr_lt_loss_thresh = 50; ++/* If 2 intervals have a bw ratio <= 1/8, their bw is "consistent": */ ++static const u32 bbr_lt_bw_ratio = BBR_UNIT / 4; ++/* If 2 intervals have a bw diff <= 4 Kbit/sec their bw is "consistent": */ ++static const u32 bbr_lt_bw_diff = 4000 / 8; ++/* If we estimate we're policed, use lt_bw for this many round trips: */ ++static const u32 bbr_lt_bw_max_rtts = 48; ++ ++static void bbr_check_probe_rtt_done(struct sock *sk); ++ ++/* Do we estimate that STARTUP filled the pipe? */ ++static bool bbr_full_bw_reached(const struct sock *sk) ++{ ++ const struct bbr *bbr = inet_csk_ca(sk); ++ ++ return bbr->full_bw_reached; ++} ++ ++/* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ ++static u32 bbr_max_bw(const struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return minmax_get(&bbr->bw); ++} ++ ++/* Return the estimated bandwidth of the path, in pkts/uS << BW_SCALE. */ ++static u32 bbr_bw(const struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return bbr->lt_use_bw ? bbr->lt_bw : bbr_max_bw(sk); ++} ++ ++/* Return rate in bytes per second, optionally with a gain. ++ * The order here is chosen carefully to avoid overflow of u64. This should ++ * work for input rates of up to 2.9Tbit/sec and gain of 2.89x. ++ */ ++static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) ++{ ++ unsigned int mss = tcp_sk(sk)->mss_cache; ++ ++ if (!tcp_needs_internal_pacing(sk)) ++ mss = tcp_mss_to_mtu(sk, mss); ++ rate *= mss; ++ rate *= gain; ++ rate >>= BBR_SCALE; ++ rate *= USEC_PER_SEC; ++ return rate >> BW_SCALE; ++} ++ ++/* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ ++static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain) ++{ ++ u64 rate = bw; ++ ++ rate = bbr_rate_bytes_per_sec(sk, rate, gain); ++ rate = min_t(u64, rate, sk->sk_max_pacing_rate); ++ return rate; ++} ++ ++/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */ ++static void bbr_init_pacing_rate_from_rtt(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw; ++ u32 rtt_us; ++ ++ if (tp->srtt_us) { /* any RTT sample yet? */ ++ rtt_us = max(tp->srtt_us >> 3, 1U); ++ bbr->has_seen_rtt = 1; ++ } else { /* no RTT sample yet */ ++ rtt_us = USEC_PER_MSEC; /* use nominal default RTT */ ++ } ++ bw = (u64)tp->snd_cwnd * BW_UNIT; ++ do_div(bw, rtt_us); ++ sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain); ++} ++ ++/* Pace using current bw estimate and a gain factor. In order to help drive the ++ * network toward lower queues while maintaining high utilization and low ++ * latency, the average pacing rate aims to be slightly (~1%) lower than the ++ * estimated bandwidth. This is an important aspect of the design. In this ++ * implementation this slightly lower pacing rate is achieved implicitly by not ++ * including link-layer headers in the packet size used for the pacing rate. ++ */ ++static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain); ++ ++ if (unlikely(!bbr->has_seen_rtt && tp->srtt_us)) ++ bbr_init_pacing_rate_from_rtt(sk); ++ if (bbr_full_bw_reached(sk) || rate > sk->sk_pacing_rate) ++ sk->sk_pacing_rate = rate; ++} ++ ++/* override sysctl_tcp_min_tso_segs */ ++static u32 bbr_min_tso_segs(struct sock *sk) ++{ ++ return sk->sk_pacing_rate < (bbr_min_tso_rate >> 3) ? 1 : 2; ++} ++ ++static u32 bbr_tso_segs_goal(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 segs, bytes; ++ ++ /* Sort of tcp_tso_autosize() but ignoring ++ * driver provided sk_gso_max_size. ++ */ ++ bytes = min_t(u32, sk->sk_pacing_rate >> sk->sk_pacing_shift, ++ GSO_MAX_SIZE - 1 - MAX_TCP_HEADER); ++ segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk)); ++ ++ return min(segs, 0x7FU); ++} ++ ++/* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ ++static void bbr_save_cwnd(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->prev_ca_state < TCP_CA_Recovery && bbr->mode != BBR_PROBE_RTT) ++ bbr->prior_cwnd = tp->snd_cwnd; /* this cwnd is good enough */ ++ else /* loss recovery or BBR_PROBE_RTT have temporarily cut cwnd */ ++ bbr->prior_cwnd = max(bbr->prior_cwnd, tp->snd_cwnd); ++} ++ ++static void bbr_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (event == CA_EVENT_TX_START && tp->app_limited) { ++ bbr->idle_restart = 1; ++ /* Avoid pointless buffer overflows: pace at est. bw if we don't ++ * need more speed (we're restarting from idle and app-limited). ++ */ ++ if (bbr->mode == BBR_PROBE_BW) ++ bbr_set_pacing_rate(sk, bbr_bw(sk), BBR_UNIT); ++ else if (bbr->mode == BBR_PROBE_RTT) ++ bbr_check_probe_rtt_done(sk); ++ } ++} ++ ++/* Find target cwnd. Right-size the cwnd based on min RTT and the ++ * estimated bottleneck bandwidth: ++ * ++ * cwnd = bw * min_rtt * gain = BDP * gain ++ * ++ * The key factor, gain, controls the amount of queue. While a small gain ++ * builds a smaller queue, it becomes more vulnerable to noise in RTT ++ * measurements (e.g., delayed ACKs or other ACK compression effects). This ++ * noise may cause BBR to under-estimate the rate. ++ * ++ * To achieve full performance in high-speed paths, we budget enough cwnd to ++ * fit full-sized skbs in-flight on both end hosts to fully utilize the path: ++ * - one skb in sending host Qdisc, ++ * - one skb in sending host TSO/GSO engine ++ * - one skb being received by receiver host LRO/GRO/delayed-ACK engine ++ * Don't worry, at low rates (bbr_min_tso_rate) this won't bloat cwnd because ++ * in such cases tso_segs_goal is 1. The minimum cwnd is 4 packets, ++ * which allows 2 outstanding 2-packet sequences, to try to keep pipe ++ * full even with ACK-every-other-packet delayed ACKs. ++ */ ++static u32 bbr_target_cwnd(struct sock *sk, u32 bw, int gain) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 cwnd; ++ u64 w; ++ ++ /* If we've never had a valid RTT sample, cap cwnd at the initial ++ * default. This should only happen when the connection is not using TCP ++ * timestamps and has retransmitted all of the SYN/SYNACK/data packets ++ * ACKed so far. In this case, an RTO can cut cwnd to 1, in which ++ * case we need to slow-start up toward something safe: TCP_INIT_CWND. ++ */ ++ if (unlikely(bbr->min_rtt_us == ~0U)) /* no valid RTT samples yet? */ ++ return TCP_INIT_CWND; /* be safe: cap at default initial cwnd*/ ++ ++ w = (u64)bw * bbr->min_rtt_us; ++ ++ /* Apply a gain to the given value, then remove the BW_SCALE shift. */ ++ cwnd = (((w * gain) >> BBR_SCALE) + BW_UNIT - 1) / BW_UNIT; ++ ++ /* Allow enough full-sized skbs in flight to utilize end systems. */ ++ cwnd += 3 * bbr_tso_segs_goal(sk); ++ ++ /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ ++ cwnd = (cwnd + 1) & ~1U; ++ ++ /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ ++ if (bbr->mode == BBR_PROBE_BW && gain > BBR_UNIT) ++ cwnd += 2; ++ ++ return cwnd; ++} ++ ++/* An optimization in BBR to reduce losses: On the first round of recovery, we ++ * follow the packet conservation principle: send P packets per P packets acked. ++ * After that, we slow-start and send at most 2*P packets per P packets acked. ++ * After recovery finishes, or upon undo, we restore the cwnd we had when ++ * recovery started (capped by the target cwnd based on estimated BDP). ++ * ++ * TODO(ycheng/ncardwell): implement a rate-based approach. ++ */ ++static bool bbr_set_cwnd_to_recover_or_restore( ++ struct sock *sk, const struct rate_sample *rs, u32 acked, u32 *new_cwnd) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u8 prev_state = bbr->prev_ca_state, state = inet_csk(sk)->icsk_ca_state; ++ u32 cwnd = tp->snd_cwnd; ++ ++ /* An ACK for P pkts should release at most 2*P packets. We do this ++ * in two steps. First, here we deduct the number of lost packets. ++ * Then, in bbr_set_cwnd() we slow start up toward the target cwnd. ++ */ ++ if (rs->losses > 0) ++ cwnd = max_t(s32, cwnd - rs->losses, 1); ++ ++ if (state == TCP_CA_Recovery && prev_state != TCP_CA_Recovery) { ++ /* Starting 1st round of Recovery, so do packet conservation. */ ++ bbr->packet_conservation = 1; ++ bbr->next_rtt_delivered = tp->delivered; /* start round now */ ++ /* Cut unused cwnd from app behavior, TSQ, or TSO deferral: */ ++ cwnd = tcp_packets_in_flight(tp) + acked; ++ } else if (prev_state >= TCP_CA_Recovery && state < TCP_CA_Recovery) { ++ /* Exiting loss recovery; restore cwnd saved before recovery. */ ++ cwnd = max(cwnd, bbr->prior_cwnd); ++ bbr->packet_conservation = 0; ++ } ++ bbr->prev_ca_state = state; ++ ++ if (bbr->packet_conservation) { ++ *new_cwnd = max(cwnd, tcp_packets_in_flight(tp) + acked); ++ return true; /* yes, using packet conservation */ ++ } ++ *new_cwnd = cwnd; ++ return false; ++} ++ ++/* Slow-start up toward target cwnd (if bw estimate is growing, or packet loss ++ * has drawn us down below target), or snap down to target if we're above it. ++ */ ++static void bbr_set_cwnd(struct sock *sk, const struct rate_sample *rs, ++ u32 acked, u32 bw, int gain) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 cwnd = tp->snd_cwnd, target_cwnd = 0; ++ ++ if (!acked) ++ goto done; /* no packet fully ACKed; just apply caps */ ++ ++ if (bbr_set_cwnd_to_recover_or_restore(sk, rs, acked, &cwnd)) ++ goto done; ++ ++ /* If we're below target cwnd, slow start cwnd toward target cwnd. */ ++ target_cwnd = bbr_target_cwnd(sk, bw, gain); ++ if (bbr_full_bw_reached(sk)) /* only cut cwnd if we filled the pipe */ ++ cwnd = min(cwnd + acked, target_cwnd); ++ else if (cwnd < target_cwnd || tp->delivered < TCP_INIT_CWND) ++ cwnd = cwnd + acked; ++ cwnd = max(cwnd, bbr_cwnd_min_target); ++ ++done: ++ tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp); /* apply global cap */ ++ if (bbr->mode == BBR_PROBE_RTT) /* drain queue, refresh min_rtt */ ++ tp->snd_cwnd = min(tp->snd_cwnd, bbr_cwnd_min_target); ++} ++ ++/* End cycle phase if it's time and/or we hit the phase's in-flight target. */ ++static bool bbr_is_next_cycle_phase(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ bool is_full_length = ++ tcp_stamp_us_delta(tp->delivered_mstamp, bbr->cycle_mstamp) > ++ bbr->min_rtt_us; ++ u32 inflight, bw; ++ ++ /* The pacing_gain of 1.0 paces at the estimated bw to try to fully ++ * use the pipe without increasing the queue. ++ */ ++ if (bbr->pacing_gain == BBR_UNIT) ++ return is_full_length; /* just use wall clock time */ ++ ++ inflight = rs->prior_in_flight; /* what was in-flight before ACK? */ ++ bw = bbr_max_bw(sk); ++ ++ /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at ++ * least pacing_gain*BDP; this may take more than min_rtt if min_rtt is ++ * small (e.g. on a LAN). We do not persist if packets are lost, since ++ * a path with small buffers may not hold that much. ++ */ ++ if (bbr->pacing_gain > BBR_UNIT) ++ return is_full_length && ++ (rs->losses || /* perhaps pacing_gain*BDP won't fit */ ++ inflight >= bbr_target_cwnd(sk, bw, bbr->pacing_gain)); ++ ++ /* A pacing_gain < 1.0 tries to drain extra queue we added if bw ++ * probing didn't find more bw. If inflight falls to match BDP then we ++ * estimate queue is drained; persisting would underutilize the pipe. ++ */ ++ return is_full_length || ++ inflight <= bbr_target_cwnd(sk, bw, BBR_UNIT); ++} ++ ++static void bbr_advance_cycle_phase(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1); ++ bbr->cycle_mstamp = tp->delivered_mstamp; ++ bbr->pacing_gain = bbr->lt_use_bw ? BBR_UNIT : ++ bbr_pacing_gain[bbr->cycle_idx]; ++} ++ ++/* Gain cycling: cycle pacing gain to converge to fair share of available bw. */ ++static void bbr_update_cycle_phase(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs)) ++ bbr_advance_cycle_phase(sk); ++} ++ ++static void bbr_reset_startup_mode(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->mode = BBR_STARTUP; ++ bbr->pacing_gain = bbr_high_gain; ++ bbr->cwnd_gain = bbr_high_gain; ++} ++ ++static void bbr_reset_probe_bw_mode(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->mode = BBR_PROBE_BW; ++ bbr->pacing_gain = BBR_UNIT; ++ bbr->cwnd_gain = bbr_cwnd_gain; ++ bbr->cycle_idx = CYCLE_LEN - 1 - prandom_u32_max(bbr_cycle_rand); ++ bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */ ++} ++ ++static void bbr_reset_mode(struct sock *sk) ++{ ++ if (!bbr_full_bw_reached(sk)) ++ bbr_reset_startup_mode(sk); ++ else ++ bbr_reset_probe_bw_mode(sk); ++} ++ ++/* Start a new long-term sampling interval. */ ++static void bbr_reset_lt_bw_sampling_interval(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->lt_last_stamp = div_u64(tp->delivered_mstamp, USEC_PER_MSEC); ++ bbr->lt_last_delivered = tp->delivered; ++ bbr->lt_last_lost = tp->lost; ++ bbr->lt_rtt_cnt = 0; ++} ++ ++/* Completely reset long-term bandwidth sampling. */ ++static void bbr_reset_lt_bw_sampling(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->lt_bw = 0; ++ bbr->lt_use_bw = 0; ++ bbr->lt_is_sampling = false; ++ bbr_reset_lt_bw_sampling_interval(sk); ++} ++ ++/* Long-term bw sampling interval is done. Estimate whether we're policed. */ ++static void bbr_lt_bw_interval_done(struct sock *sk, u32 bw) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 diff; ++ ++ if (bbr->lt_bw) { /* do we have bw from a previous interval? */ ++ /* Is new bw close to the lt_bw from the previous interval? */ ++ diff = abs(bw - bbr->lt_bw); ++ if ((diff * BBR_UNIT <= bbr_lt_bw_ratio * bbr->lt_bw) || ++ (bbr_rate_bytes_per_sec(sk, diff, BBR_UNIT) <= ++ bbr_lt_bw_diff)) { ++ /* All criteria are met; estimate we're policed. */ ++ bbr->lt_bw = (bw + bbr->lt_bw) >> 1; /* avg 2 intvls */ ++ bbr->lt_use_bw = 1; ++ bbr->pacing_gain = BBR_UNIT; /* try to avoid drops */ ++ bbr->lt_rtt_cnt = 0; ++ return; ++ } ++ } ++ bbr->lt_bw = bw; ++ bbr_reset_lt_bw_sampling_interval(sk); ++} ++ ++/* Token-bucket traffic policers are common (see "An Internet-Wide Analysis of ++ * Traffic Policing", SIGCOMM 2016). BBR detects token-bucket policers and ++ * explicitly models their policed rate, to reduce unnecessary losses. We ++ * estimate that we're policed if we see 2 consecutive sampling intervals with ++ * consistent throughput and high packet loss. If we think we're being policed, ++ * set lt_bw to the "long-term" average delivery rate from those 2 intervals. ++ */ ++static void bbr_lt_bw_sampling(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 lost, delivered; ++ u64 bw; ++ u32 t; ++ ++ if (bbr->lt_use_bw) { /* already using long-term rate, lt_bw? */ ++ if (bbr->mode == BBR_PROBE_BW && bbr->round_start && ++ ++bbr->lt_rtt_cnt >= bbr_lt_bw_max_rtts) { ++ bbr_reset_lt_bw_sampling(sk); /* stop using lt_bw */ ++ bbr_reset_probe_bw_mode(sk); /* restart gain cycling */ ++ } ++ return; ++ } ++ ++ /* Wait for the first loss before sampling, to let the policer exhaust ++ * its tokens and estimate the steady-state rate allowed by the policer. ++ * Starting samples earlier includes bursts that over-estimate the bw. ++ */ ++ if (!bbr->lt_is_sampling) { ++ if (!rs->losses) ++ return; ++ bbr_reset_lt_bw_sampling_interval(sk); ++ bbr->lt_is_sampling = true; ++ } ++ ++ /* To avoid underestimates, reset sampling if we run out of data. */ ++ if (rs->is_app_limited) { ++ bbr_reset_lt_bw_sampling(sk); ++ return; ++ } ++ ++ if (bbr->round_start) ++ bbr->lt_rtt_cnt++; /* count round trips in this interval */ ++ if (bbr->lt_rtt_cnt < bbr_lt_intvl_min_rtts) ++ return; /* sampling interval needs to be longer */ ++ if (bbr->lt_rtt_cnt > 4 * bbr_lt_intvl_min_rtts) { ++ bbr_reset_lt_bw_sampling(sk); /* interval is too long */ ++ return; ++ } ++ ++ /* End sampling interval when a packet is lost, so we estimate the ++ * policer tokens were exhausted. Stopping the sampling before the ++ * tokens are exhausted under-estimates the policed rate. ++ */ ++ if (!rs->losses) ++ return; ++ ++ /* Calculate packets lost and delivered in sampling interval. */ ++ lost = tp->lost - bbr->lt_last_lost; ++ delivered = tp->delivered - bbr->lt_last_delivered; ++ /* Is loss rate (lost/delivered) >= lt_loss_thresh? If not, wait. */ ++ if (!delivered || (lost << BBR_SCALE) < bbr_lt_loss_thresh * delivered) ++ return; ++ ++ /* Find average delivery rate in this sampling interval. */ ++ t = div_u64(tp->delivered_mstamp, USEC_PER_MSEC) - bbr->lt_last_stamp; ++ if ((s32)t < 1) ++ return; /* interval is less than one ms, so wait */ ++ /* Check if can multiply without overflow */ ++ if (t >= ~0U / USEC_PER_MSEC) { ++ bbr_reset_lt_bw_sampling(sk); /* interval too long; reset */ ++ return; ++ } ++ t *= USEC_PER_MSEC; ++ bw = (u64)delivered * BW_UNIT; ++ do_div(bw, t); ++ bbr_lt_bw_interval_done(sk, bw); ++} ++ ++/* Estimate the bandwidth based on how fast packets are delivered */ ++static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw; ++ ++ bbr->round_start = 0; ++ if (rs->delivered < 0 || rs->interval_us <= 0) ++ return; /* Not a valid observation */ ++ ++ /* See if we've reached the next RTT */ ++ if (!before(rs->prior_delivered, bbr->next_rtt_delivered)) { ++ bbr->next_rtt_delivered = tp->delivered; ++ bbr->rtt_cnt++; ++ bbr->round_start = 1; ++ bbr->packet_conservation = 0; ++ } ++ ++ bbr_lt_bw_sampling(sk, rs); ++ ++ /* Divide delivered by the interval to find a (lower bound) bottleneck ++ * bandwidth sample. Delivered is in packets and interval_us in uS and ++ * ratio will be <<1 for most connections. So delivered is first scaled. ++ */ ++ bw = (u64)rs->delivered * BW_UNIT; ++ do_div(bw, rs->interval_us); ++ ++ /* If this sample is application-limited, it is likely to have a very ++ * low delivered count that represents application behavior rather than ++ * the available network rate. Such a sample could drag down estimated ++ * bw, causing needless slow-down. Thus, to continue to send at the ++ * last measured network rate, we filter out app-limited samples unless ++ * they describe the path bw at least as well as our bw model. ++ * ++ * So the goal during app-limited phase is to proceed with the best ++ * network rate no matter how long. We automatically leave this ++ * phase when app writes faster than the network can deliver :) ++ */ ++ if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) { ++ /* Incorporate new sample into our max bw filter. */ ++ minmax_running_max(&bbr->bw, bbr_bw_rtts, bbr->rtt_cnt, bw); ++ } ++} ++ ++/* Estimate when the pipe is full, using the change in delivery rate: BBR ++ * estimates that STARTUP filled the pipe if the estimated bw hasn't changed by ++ * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited ++ * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the ++ * higher rwin, 3: we get higher delivery rate samples. Or transient ++ * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar ++ * design goal, but uses delay and inter-ACK spacing instead of bandwidth. ++ */ ++static void bbr_check_full_bw_reached(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bw_thresh; ++ ++ if (bbr_full_bw_reached(sk) || !bbr->round_start || rs->is_app_limited) ++ return; ++ ++ bw_thresh = (u64)bbr->full_bw * bbr_full_bw_thresh >> BBR_SCALE; ++ if (bbr_max_bw(sk) >= bw_thresh) { ++ bbr->full_bw = bbr_max_bw(sk); ++ bbr->full_bw_cnt = 0; ++ return; ++ } ++ ++bbr->full_bw_cnt; ++ bbr->full_bw_reached = bbr->full_bw_cnt >= bbr_full_bw_cnt; ++} ++ ++/* If pipe is probably full, drain the queue and then enter steady-state. */ ++static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { ++ bbr->mode = BBR_DRAIN; /* drain queue we created */ ++ bbr->pacing_gain = bbr_drain_gain; /* pace slow to drain */ ++ bbr->cwnd_gain = bbr_high_gain; /* maintain cwnd */ ++ tcp_sk(sk)->snd_ssthresh = ++ bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT); ++ } /* fall through to check if in-flight is already small: */ ++ if (bbr->mode == BBR_DRAIN && ++ tcp_packets_in_flight(tcp_sk(sk)) <= ++ bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT)) ++ bbr_reset_probe_bw_mode(sk); /* we estimate queue is drained */ ++} ++ ++static void bbr_check_probe_rtt_done(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (!(bbr->probe_rtt_done_stamp && ++ after(tcp_jiffies32, bbr->probe_rtt_done_stamp))) ++ return; ++ ++ bbr->min_rtt_stamp = tcp_jiffies32; /* wait a while until PROBE_RTT */ ++ tp->snd_cwnd = max(tp->snd_cwnd, bbr->prior_cwnd); ++ bbr_reset_mode(sk); ++} ++ ++/* The goal of PROBE_RTT mode is to have BBR flows cooperatively and ++ * periodically drain the bottleneck queue, to converge to measure the true ++ * min_rtt (unloaded propagation delay). This allows the flows to keep queues ++ * small (reducing queuing delay and packet loss) and achieve fairness among ++ * BBR flows. ++ * ++ * The min_rtt filter window is 10 seconds. When the min_rtt estimate expires, ++ * we enter PROBE_RTT mode and cap the cwnd at bbr_cwnd_min_target=4 packets. ++ * After at least bbr_probe_rtt_mode_ms=200ms and at least one packet-timed ++ * round trip elapsed with that flight size <= 4, we leave PROBE_RTT mode and ++ * re-enter the previous mode. BBR uses 200ms to approximately bound the ++ * performance penalty of PROBE_RTT's cwnd capping to roughly 2% (200ms/10s). ++ * ++ * Note that flows need only pay 2% if they are busy sending over the last 10 ++ * seconds. Interactive applications (e.g., Web, RPCs, video chunks) often have ++ * natural silences or low-rate periods within 10 seconds where the rate is low ++ * enough for long enough to drain its queue in the bottleneck. We pick up ++ * these min RTT measurements opportunistically with our min_rtt filter. :-) ++ */ ++static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ bool filter_expired; ++ ++ /* Track min RTT seen in the min_rtt_win_sec filter window: */ ++ filter_expired = after(tcp_jiffies32, ++ bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ); ++ if (rs->rtt_us >= 0 && ++ (rs->rtt_us <= bbr->min_rtt_us || ++ (filter_expired && !rs->is_ack_delayed))) { ++ bbr->min_rtt_us = rs->rtt_us; ++ bbr->min_rtt_stamp = tcp_jiffies32; ++ } ++ ++ if (bbr_probe_rtt_mode_ms > 0 && filter_expired && ++ !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) { ++ bbr->mode = BBR_PROBE_RTT; /* dip, drain queue */ ++ bbr->pacing_gain = BBR_UNIT; ++ bbr->cwnd_gain = BBR_UNIT; ++ bbr_save_cwnd(sk); /* note cwnd so we can restore it */ ++ bbr->probe_rtt_done_stamp = 0; ++ } ++ ++ if (bbr->mode == BBR_PROBE_RTT) { ++ /* Ignore low rate samples during this mode. */ ++ tp->app_limited = ++ (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; ++ /* Maintain min packets in flight for max(200 ms, 1 round). */ ++ if (!bbr->probe_rtt_done_stamp && ++ tcp_packets_in_flight(tp) <= bbr_cwnd_min_target) { ++ bbr->probe_rtt_done_stamp = tcp_jiffies32 + ++ msecs_to_jiffies(bbr_probe_rtt_mode_ms); ++ bbr->probe_rtt_round_done = 0; ++ bbr->next_rtt_delivered = tp->delivered; ++ } else if (bbr->probe_rtt_done_stamp) { ++ if (bbr->round_start) ++ bbr->probe_rtt_round_done = 1; ++ if (bbr->probe_rtt_round_done) ++ bbr_check_probe_rtt_done(sk); ++ } ++ } ++ /* Restart after idle ends only once we process a new S/ACK for data */ ++ if (rs->delivered > 0) ++ bbr->idle_restart = 0; ++} ++ ++static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) ++{ ++ bbr_update_bw(sk, rs); ++ bbr_update_cycle_phase(sk, rs); ++ bbr_check_full_bw_reached(sk, rs); ++ bbr_check_drain(sk, rs); ++ bbr_update_min_rtt(sk, rs); ++} ++ ++static void bbr_main(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bw; ++ ++ bbr_update_model(sk, rs); ++ ++ bw = bbr_bw(sk); ++ bbr_set_pacing_rate(sk, bw, bbr->pacing_gain); ++ bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain); ++} ++ ++static void bbr_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->prior_cwnd = 0; ++ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ bbr->rtt_cnt = 0; ++ bbr->next_rtt_delivered = 0; ++ bbr->prev_ca_state = TCP_CA_Open; ++ bbr->packet_conservation = 0; ++ ++ bbr->probe_rtt_done_stamp = 0; ++ bbr->probe_rtt_round_done = 0; ++ bbr->min_rtt_us = tcp_min_rtt(tp); ++ bbr->min_rtt_stamp = tcp_jiffies32; ++ ++ minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */ ++ ++ bbr->has_seen_rtt = 0; ++ bbr_init_pacing_rate_from_rtt(sk); ++ ++ bbr->round_start = 0; ++ bbr->idle_restart = 0; ++ bbr->full_bw_reached = 0; ++ bbr->full_bw = 0; ++ bbr->full_bw_cnt = 0; ++ bbr->cycle_mstamp = 0; ++ bbr->cycle_idx = 0; ++ bbr_reset_lt_bw_sampling(sk); ++ bbr_reset_startup_mode(sk); ++ ++ cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); ++} ++ ++static u32 bbr_sndbuf_expand(struct sock *sk) ++{ ++ /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ ++ return 3; ++} ++ ++/* In theory BBR does not need to undo the cwnd since it does not ++ * always reduce cwnd on losses (see bbr_main()). Keep it for now. ++ */ ++static u32 bbr_undo_cwnd(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->full_bw = 0; /* spurious slow-down; reset full pipe detection */ ++ bbr->full_bw_cnt = 0; ++ bbr_reset_lt_bw_sampling(sk); ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* Entering loss recovery, so save cwnd for when we exit or undo recovery. */ ++static u32 bbr_ssthresh(struct sock *sk) ++{ ++ bbr_save_cwnd(sk); ++ return tcp_sk(sk)->snd_ssthresh; ++} ++ ++static size_t bbr_get_info(struct sock *sk, u32 ext, int *attr, ++ union tcp_cc_info *info) ++{ ++ if (ext & (1 << (INET_DIAG_BBRINFO - 1)) || ++ ext & (1 << (INET_DIAG_VEGASINFO - 1))) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw = bbr_bw(sk); ++ ++ bw = bw * tp->mss_cache * USEC_PER_SEC >> BW_SCALE; ++ memset(&info->bbr, 0, sizeof(info->bbr)); ++ info->bbr.bbr_bw_lo = (u32)bw; ++ info->bbr.bbr_bw_hi = (u32)(bw >> 32); ++ info->bbr.bbr_min_rtt = bbr->min_rtt_us; ++ info->bbr.bbr_pacing_gain = bbr->pacing_gain; ++ info->bbr.bbr_cwnd_gain = bbr->cwnd_gain; ++ *attr = INET_DIAG_BBRINFO; ++ return sizeof(info->bbr); ++ } ++ return 0; ++} ++ ++static void bbr_set_state(struct sock *sk, u8 new_state) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (new_state == TCP_CA_Loss) { ++ struct rate_sample rs = { .losses = 1 }; ++ ++ bbr->prev_ca_state = TCP_CA_Loss; ++ bbr->full_bw = 0; ++ bbr->round_start = 1; /* treat RTO like end of a round */ ++ bbr_lt_bw_sampling(sk, &rs); ++ } ++} ++ ++static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = { ++ .flags = TCP_CONG_NON_RESTRICTED, ++ .name = "nanqinlang", ++ .owner = THIS_MODULE, ++ .init = bbr_init, ++ .cong_control = bbr_main, ++ .sndbuf_expand = bbr_sndbuf_expand, ++ .undo_cwnd = bbr_undo_cwnd, ++ .cwnd_event = bbr_cwnd_event, ++ .ssthresh = bbr_ssthresh, ++ .min_tso_segs = bbr_min_tso_segs, ++ .get_info = bbr_get_info, ++ .set_state = bbr_set_state, ++}; ++ ++static int __init bbr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct bbr) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&tcp_bbr_cong_ops); ++} ++ ++static void __exit bbr_unregister(void) ++{ ++ tcp_unregister_congestion_control(&tcp_bbr_cong_ops); ++} ++ ++module_init(bbr_register); ++module_exit(bbr_unregister); ++ ++MODULE_AUTHOR("Van Jacobson "); ++MODULE_AUTHOR("Neal Cardwell "); ++MODULE_AUTHOR("Yuchung Cheng "); ++MODULE_AUTHOR("Soheil Hassas Yeganeh "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("TCP BBR (Bottleneck Bandwidth and RTT)"); ++MODULE_AUTHOR("Nanqinlang "); diff --git a/root/target/linux/generic/hack-4.19/998-ndpi-netfilter.patch b/root/target/linux/generic/hack-4.19/998-ndpi-netfilter.patch new file mode 100644 index 00000000..cd8d61a7 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/998-ndpi-netfilter.patch @@ -0,0 +1,116 @@ +diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h +index 21f887c..59980ec 100644 +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -28,7 +28,8 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif +- NF_CT_EXT_NUM, ++ NF_CT_EXT_CUSTOM, ++ NF_CT_EXT_NUM=NF_CT_EXT_CUSTOM+CONFIG_NF_CONNTRACK_CUSTOM, + }; + + #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help +@@ -96,5 +97,6 @@ struct nf_ct_ext_type { + }; + + int nf_ct_extend_register(const struct nf_ct_ext_type *type); ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type,unsigned long int cid); + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type); + #endif /* _NF_CONNTRACK_EXTEND_H */ +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 7581e82..30a11eb 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -85,6 +85,16 @@ config NF_CONNTRACK_SECMARK + + If unsure, say 'N'. + ++config NF_CONNTRACK_CUSTOM ++ int "Number of custom extend" ++ range 0 8 ++ depends on NETFILTER_ADVANCED ++ default "2" ++ help ++ This parameter specifies how many custom extensions can be registered. ++ ++ The default value is 2. ++ + config NF_CONNTRACK_ZONES + bool 'Connection tracking zones' + depends on NETFILTER_ADVANCED +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 85f643c..44e2fdd 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1971,7 +1971,7 @@ int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp) + static __always_inline unsigned int total_extension_size(void) + { + /* remember to add new extensions below */ +- BUILD_BUG_ON(NF_CT_EXT_NUM > 9); ++ BUILD_BUG_ON(NF_CT_EXT_NUM > 12); + + return sizeof(struct nf_ct_ext) + + sizeof(struct nf_conn_help) +diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c +index 9fe0ddc..5a9054e 100644 +--- a/net/netfilter/nf_conntrack_extend.c ++++ b/net/netfilter/nf_conntrack_extend.c +@@ -108,11 +108,56 @@ int nf_ct_extend_register(const struct nf_ct_ext_type *type) + } + EXPORT_SYMBOL_GPL(nf_ct_extend_register); + ++static unsigned long int nf_ct_ext_cust_id[CONFIG_NF_CONNTRACK_CUSTOM]; ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id); ++ ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type, ++ unsigned long int cid) ++{ ++ int ret; ++ enum nf_ct_ext_id new_id = nf_ct_extend_get_custom_id(cid); ++ if(!new_id) ++ return -EBUSY; ++ type->id = new_id; ++ ret = nf_ct_extend_register(type); ++ if(ret < 0) { ++ mutex_lock(&nf_ct_ext_type_mutex); ++ nf_ct_ext_cust_id[new_id - NF_CT_EXT_CUSTOM] = 0; ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(nf_ct_extend_custom_register); ++ ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id) ++{ ++ enum nf_ct_ext_id ret = 0; ++ int i; ++ mutex_lock(&nf_ct_ext_type_mutex); ++ for(i = 0; i < CONFIG_NF_CONNTRACK_CUSTOM; i++) { ++ if(!nf_ct_ext_cust_id[i]) { ++ nf_ct_ext_cust_id[i] = ext_id; ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ if(nf_ct_ext_cust_id[i] == ext_id) { ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ } ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ return ret; ++} ++ + /* This MUST be called in process context. */ + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type) + { + mutex_lock(&nf_ct_ext_type_mutex); + RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); ++ if(type->id >= NF_CT_EXT_CUSTOM && type->id < NF_CT_EXT_NUM) ++ nf_ct_ext_cust_id[type->id-NF_CT_EXT_CUSTOM] = 0; + mutex_unlock(&nf_ct_ext_type_mutex); + synchronize_rcu(); + } diff --git a/root/target/linux/generic/hack-4.19/999-f2fs-ioerrorfix.patch b/root/target/linux/generic/hack-4.19/999-f2fs-ioerrorfix.patch new file mode 100644 index 00000000..ebc43131 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/999-f2fs-ioerrorfix.patch @@ -0,0 +1,25 @@ +--- + fs/f2fs/checkpoint.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index a7ad1b1e5750..90e1bab86269 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -674,6 +674,12 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi) + if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) + return 0; + ++ if (bdev_read_only(sbi->sb->s_bdev)) { ++ f2fs_msg(sbi->sb, KERN_INFO, "write access " ++ "unavailable, skipping orphan cleanup"); ++ return 0; ++ } ++ + if (s_flags & SB_RDONLY) { + f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs"); + sbi->sb->s_flags &= ~SB_RDONLY; +-- +2.18.0.rc1 + + \ No newline at end of file diff --git a/root/target/linux/generic/hack-4.19/999-stop-promiscuous-info.patch b/root/target/linux/generic/hack-4.19/999-stop-promiscuous-info.patch new file mode 100644 index 00000000..2dc06ee6 --- /dev/null +++ b/root/target/linux/generic/hack-4.19/999-stop-promiscuous-info.patch @@ -0,0 +1,14 @@ +--- a/net/core/dev.c 2018-08-10 10:31:41.199494561 +0200 ++++ b/net/core/dev.c 2018-08-10 10:32:03.635272509 +0200 +@@ -6613,9 +6613,11 @@ + } + } + if (dev->flags != old_flags) { ++ /* + pr_info("device %s %s promiscuous mode\n", + dev->name, + dev->flags & IFF_PROMISC ? "entered" : "left"); ++ */ + if (audit_enabled) { + current_uid_gid(&uid, &gid); + audit_log(current->audit_context, GFP_ATOMIC, diff --git a/root/target/linux/generic/hack-4.9/690-mptcp_v0.93.patch b/root/target/linux/generic/hack-4.9/690-mptcp_v0.93.patch new file mode 100644 index 00000000..2ee5998d --- /dev/null +++ b/root/target/linux/generic/hack-4.9/690-mptcp_v0.93.patch @@ -0,0 +1,20499 @@ +diff -aurN linux-4.9.162/Documentation/networking/ip-sysctl.txt mptcp-mptcp_v0.93/Documentation/networking/ip-sysctl.txt +--- linux-4.9.162/Documentation/networking/ip-sysctl.txt 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/Documentation/networking/ip-sysctl.txt 2019-03-14 14:02:32.000000000 +0100 +@@ -732,6 +732,18 @@ + in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) + Default: 100 + ++MPTCP variables: ++ ++mptcp_enabled - INTEGER ++ Enable or disable Multipath TCP for new connections. ++ Possible values are: ++ ++ 0: Multipath TCP is disabled on all TCP-sockets that are newly created. ++ 1: Multipath TCP is enabled by default on all new TCP-sockets. Note that ++ existing sockets in LISTEN-state will still use regular TCP. ++ 2: Enables Multipath TCP only upon the request of the application ++ throught the socket-option MPTCP_ENABLED. ++ + UDP variables: + + udp_mem - vector of 3 INTEGERs: min, pressure, max +diff -aurN linux-4.9.162/drivers/infiniband/hw/cxgb4/cm.c mptcp-mptcp_v0.93/drivers/infiniband/hw/cxgb4/cm.c +--- linux-4.9.162/drivers/infiniband/hw/cxgb4/cm.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/drivers/infiniband/hw/cxgb4/cm.c 2019-03-14 14:02:32.000000000 +0100 +@@ -3736,7 +3736,7 @@ + */ + memset(&tmp_opt, 0, sizeof(tmp_opt)); + tcp_clear_options(&tmp_opt); +- tcp_parse_options(skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(skb, &tmp_opt, NULL, 0, NULL, NULL); + + req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); +diff -aurN linux-4.9.162/include/linux/skbuff.h mptcp-mptcp_v0.93/include/linux/skbuff.h +--- linux-4.9.162/include/linux/skbuff.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/linux/skbuff.h 2019-03-14 14:02:32.000000000 +0100 +@@ -659,7 +659,7 @@ + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ +- char cb[48] __aligned(8); ++ char cb[80] __aligned(8); + + unsigned long _skb_refdst; + void (*destructor)(struct sk_buff *skb); +diff -aurN linux-4.9.162/include/linux/tcp.h mptcp-mptcp_v0.93/include/linux/tcp.h +--- linux-4.9.162/include/linux/tcp.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/linux/tcp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -58,7 +58,7 @@ + /* TCP Fast Open */ + #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ + #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ +-#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ ++#define TCP_FASTOPEN_COOKIE_SIZE 4 /* the size employed by this impl. */ + + /* TCP Fast Open Cookie as stored in memory */ + struct tcp_fastopen_cookie { +@@ -83,6 +83,56 @@ + u32 end_seq; + }; + ++struct tcp_out_options { ++ u16 options; /* bit field of OPTION_* */ ++ u8 ws; /* window scale, 0 to disable */ ++ u8 num_sack_blocks;/* number of SACK blocks to include */ ++ u8 hash_size; /* bytes in hash_location */ ++ u16 mss; /* 0 to disable */ ++ __u8 *hash_location; /* temporary pointer, overloaded */ ++ __u32 tsval, tsecr; /* need to include OPTION_TS */ ++ struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ ++#ifdef CONFIG_MPTCP ++ u16 mptcp_options; /* bit field of MPTCP related OPTION_* */ ++ u8 dss_csum:1, /* dss-checksum required? */ ++ add_addr_v4:1, ++ add_addr_v6:1, ++ mptcp_ver:4; ++ ++ union { ++ struct { ++ __u64 sender_key; /* sender's key for mptcp */ ++ __u64 receiver_key; /* receiver's key for mptcp */ ++ } mp_capable; ++ ++ struct { ++ __u64 sender_truncated_mac; ++ __u32 sender_nonce; ++ /* random number of the sender */ ++ __u32 token; /* token for mptcp */ ++ u8 low_prio:1; ++ } mp_join_syns; ++ }; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr4; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in6_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr6; ++ ++ u16 remove_addrs; /* list of address id */ ++ u8 addr_id; /* address id (mp_join or add_address) */ ++#endif /* CONFIG_MPTCP */ ++}; ++ + /*These are used to set the sack_ok field in struct tcp_options_received */ + #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ + #define TCP_FACK_ENABLED (1 << 1) /*1 = FACK is enabled locally*/ +@@ -106,6 +156,9 @@ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + }; + ++struct mptcp_cb; ++struct mptcp_tcp_sock; ++ + static inline void tcp_clear_options(struct tcp_options_received *rx_opt) + { + rx_opt->tstamp_ok = rx_opt->sack_ok = 0; +@@ -140,6 +193,8 @@ + return (struct tcp_request_sock *)req; + } + ++struct tcp_md5sig_key; ++ + struct tcp_sock { + /* inet_connection_sock has to be the first member of tcp_sock */ + struct inet_connection_sock inet_conn; +@@ -366,6 +421,44 @@ + */ + struct request_sock *fastopen_rsk; + u32 *saved_syn; ++ ++ /* MPTCP/TCP-specific callbacks */ ++ const struct tcp_sock_ops *ops; ++ ++ struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ /* We keep these flags even if CONFIG_MPTCP is not checked, because ++ * it allows checking MPTCP capability just by checking the mpc flag, ++ * rather than adding ifdefs everywhere. ++ */ ++ u32 mpc:1, /* Other end is multipath capable */ ++ inside_tk_table:1, /* Is the tcp_sock inside the token-table? */ ++ send_mp_fclose:1, ++ request_mptcp:1, /* Did we send out an MP_CAPABLE? ++ * (this speeds up mptcp_doit() in tcp_recvmsg) ++ */ ++ pf:1, /* Potentially Failed state: when this flag is set, we ++ * stop using the subflow ++ */ ++ mp_killed:1, /* Killed with a tcp_done in mptcp? */ ++ was_meta_sk:1, /* This was a meta sk (in case of reuse) */ ++ is_master_sk:1, ++ close_it:1, /* Must close socket in mptcp_data_ready? */ ++ closing:1, ++ mptcp_ver:4, ++ mptcp_sched_setsockopt:1, ++ mptcp_pm_setsockopt:1, ++ record_master_info:1; ++ struct mptcp_tcp_sock *mptcp; ++#ifdef CONFIG_MPTCP ++#define MPTCP_SCHED_NAME_MAX 16 ++#define MPTCP_PM_NAME_MAX 16 ++ struct hlist_nulls_node tk_table; ++ u32 mptcp_loc_token; ++ u64 mptcp_loc_key; ++ char mptcp_sched_name[MPTCP_SCHED_NAME_MAX]; ++ char mptcp_pm_name[MPTCP_PM_NAME_MAX]; ++#endif /* CONFIG_MPTCP */ + }; + + enum tsq_flags { +@@ -377,6 +470,8 @@ + TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call + * tcp_v{4|6}_mtu_reduced() + */ ++ MPTCP_PATH_MANAGER_DEFERRED, /* MPTCP deferred creation of new subflows */ ++ MPTCP_SUB_DEFERRED, /* A subflow got deferred - process them */ + }; + + static inline struct tcp_sock *tcp_sk(const struct sock *sk) +@@ -399,6 +494,7 @@ + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *tw_md5_key; + #endif ++ struct mptcp_tw *mptcp_tw; + }; + + static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) +diff -aurN linux-4.9.162/include/net/inet_common.h mptcp-mptcp_v0.93/include/net/inet_common.h +--- linux-4.9.162/include/net/inet_common.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/inet_common.h 2019-03-14 14:02:32.000000000 +0100 +@@ -1,6 +1,8 @@ + #ifndef _INET_COMMON_H + #define _INET_COMMON_H + ++#include ++ + extern const struct proto_ops inet_stream_ops; + extern const struct proto_ops inet_dgram_ops; + +@@ -13,6 +15,8 @@ + struct sockaddr; + struct socket; + ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern); ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern); + int inet_release(struct socket *sock); + int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags); +diff -aurN linux-4.9.162/include/net/inet_connection_sock.h mptcp-mptcp_v0.93/include/net/inet_connection_sock.h +--- linux-4.9.162/include/net/inet_connection_sock.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/inet_connection_sock.h 2019-03-14 14:02:32.000000000 +0100 +@@ -30,6 +30,7 @@ + + struct inet_bind_bucket; + struct tcp_congestion_ops; ++struct tcp_options_received; + + /* + * Pointers to address related TCP functions +diff -aurN linux-4.9.162/include/net/inet_sock.h mptcp-mptcp_v0.93/include/net/inet_sock.h +--- linux-4.9.162/include/net/inet_sock.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/inet_sock.h 2019-03-14 14:02:32.000000000 +0100 +@@ -92,7 +92,9 @@ + wscale_ok : 1, + ecn_ok : 1, + acked : 1, +- no_srccheck: 1; ++ no_srccheck: 1, ++ mptcp_rqsk : 1, ++ saw_mpc : 1; + kmemcheck_bitfield_end(flags); + u32 ir_mark; + union { +diff -aurN linux-4.9.162/include/net/mptcp.h mptcp-mptcp_v0.93/include/net/mptcp.h +--- linux-4.9.162/include/net/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/mptcp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,1509 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_H ++#define _MPTCP_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ #define ntohll(x) be64_to_cpu(x) ++ #define htonll(x) cpu_to_be64(x) ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ #define ntohll(x) (x) ++ #define htonll(x) (x) ++#endif ++ ++struct mptcp_loc4 { ++ u8 loc4_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in_addr addr; ++}; ++ ++struct mptcp_rem4 { ++ u8 rem4_id; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct mptcp_loc6 { ++ u8 loc6_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_rem6 { ++ u8 rem6_id; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_request_sock { ++ struct tcp_request_sock req; ++ struct hlist_nulls_node hash_entry; ++ ++ union { ++ struct { ++ /* Only on initial subflows */ ++ u64 mptcp_loc_key; ++ u64 mptcp_rem_key; ++ u32 mptcp_loc_token; ++ }; ++ ++ struct { ++ /* Only on additional subflows */ ++ u32 mptcp_rem_nonce; ++ u32 mptcp_loc_nonce; ++ u64 mptcp_hash_tmac; ++ }; ++ }; ++ ++ u8 loc_id; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 dss_csum:1, ++ is_sub:1, /* Is this a new subflow? */ ++ low_prio:1, /* Interface set to low-prio? */ ++ rcv_low_prio:1, ++ mptcp_ver:4; ++}; ++ ++struct mptcp_options_received { ++ u16 saw_mpc:1, ++ dss_csum:1, ++ drop_me:1, ++ ++ is_mp_join:1, ++ join_ack:1, ++ ++ saw_low_prio:2, /* 0x1 - low-prio set for this subflow ++ * 0x2 - low-prio set for another subflow ++ */ ++ low_prio:1, ++ ++ saw_add_addr:2, /* Saw at least one add_addr option: ++ * 0x1: IPv4 - 0x2: IPv6 ++ */ ++ more_add_addr:1, /* Saw one more add-addr. */ ++ ++ saw_rem_addr:1, /* Saw at least one rem_addr option */ ++ more_rem_addr:1, /* Saw one more rem-addr. */ ++ ++ mp_fail:1, ++ mp_fclose:1; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 prio_addr_id; /* Address-id in the MP_PRIO */ ++ ++ const unsigned char *add_addr_ptr; /* Pointer to add-address option */ ++ const unsigned char *rem_addr_ptr; /* Pointer to rem-address option */ ++ ++ u32 data_ack; ++ u32 data_seq; ++ u16 data_len; ++ ++ u8 mptcp_ver; /* MPTCP version */ ++ ++ /* Key inside the option (from mp_capable or fast_close) */ ++ u64 mptcp_sender_key; ++ u64 mptcp_receiver_key; ++ ++ u32 mptcp_rem_token; /* Remote token */ ++ ++ u32 mptcp_recv_nonce; ++ u64 mptcp_recv_tmac; ++ u8 mptcp_recv_mac[20]; ++}; ++ ++struct mptcp_tcp_sock { ++ struct tcp_sock *next; /* Next subflow socket */ ++ struct hlist_node cb_list; ++ struct mptcp_options_received rx_opt; ++ ++ /* Those three fields record the current mapping */ ++ u64 map_data_seq; ++ u32 map_subseq; ++ u16 map_data_len; ++ u16 slave_sk:1, ++ fully_established:1, ++ establish_increased:1, ++ second_packet:1, ++ attached:1, ++ send_mp_fail:1, ++ include_mpc:1, ++ mapping_present:1, ++ map_data_fin:1, ++ low_prio:1, /* use this socket as backup */ ++ rcv_low_prio:1, /* Peer sent low-prio option to us */ ++ send_mp_prio:1, /* Trigger to send mp_prio on this socket */ ++ pre_established:1; /* State between sending 3rd ACK and ++ * receiving the fourth ack of new subflows. ++ */ ++ ++ /* isn: needed to translate abs to relative subflow seqnums */ ++ u32 snt_isn; ++ u32 rcv_isn; ++ u8 path_index; ++ u8 loc_id; ++ u8 rem_id; ++ ++#define MPTCP_SCHED_SIZE 16 ++ u8 mptcp_sched[MPTCP_SCHED_SIZE] __aligned(8); ++ ++ int init_rcv_wnd; ++ u32 infinite_cutoff_seq; ++ struct delayed_work work; ++ u32 mptcp_loc_nonce; ++ struct tcp_sock *tp; /* Where is my daddy? */ ++ u32 last_end_data_seq; ++ ++ /* MP_JOIN subflow: timer for retransmitting the 3rd ack */ ++ struct timer_list mptcp_ack_timer; ++ ++ /* HMAC of the third ack */ ++ char sender_mac[20]; ++}; ++ ++struct mptcp_tw { ++ struct list_head list; ++ u64 loc_key; ++ u64 rcv_nxt; ++ struct mptcp_cb __rcu *mpcb; ++ u8 meta_tw:1, ++ in_list:1; ++}; ++ ++#define MPTCP_PM_NAME_MAX 16 ++struct mptcp_pm_ops { ++ struct list_head list; ++ ++ /* Signal the creation of a new MPTCP-session. */ ++ void (*new_session)(const struct sock *meta_sk); ++ void (*release_sock)(struct sock *meta_sk); ++ void (*fully_established)(struct sock *meta_sk); ++ void (*new_remote_address)(struct sock *meta_sk); ++ void (*subflow_error)(struct sock *meta_sk, struct sock *sk); ++ int (*get_local_id)(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio); ++ void (*addr_signal)(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb); ++ void (*add_raddr)(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id); ++ void (*rem_raddr)(struct mptcp_cb *mpcb, u8 rem_id); ++ void (*init_subsocket_v4)(struct sock *sk, struct in_addr addr); ++ void (*init_subsocket_v6)(struct sock *sk, struct in6_addr addr); ++ void (*delete_subflow)(struct sock *sk); ++ ++ char name[MPTCP_PM_NAME_MAX]; ++ struct module *owner; ++}; ++ ++#define MPTCP_SCHED_NAME_MAX 16 ++struct mptcp_sched_ops { ++ struct list_head list; ++ ++ struct sock * (*get_subflow)(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test); ++ struct sk_buff * (*next_segment)(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit); ++ void (*init)(struct sock *sk); ++ void (*release)(struct sock *sk); ++ ++ char name[MPTCP_SCHED_NAME_MAX]; ++ struct module *owner; ++}; ++ ++struct mptcp_cb { ++ /* list of sockets in this multipath connection */ ++ struct tcp_sock *connection_list; ++ /* list of sockets that need a call to release_cb */ ++ struct hlist_head callback_list; ++ ++ /* High-order bits of 64-bit sequence numbers */ ++ u32 snd_high_order[2]; ++ u32 rcv_high_order[2]; ++ ++ u16 send_infinite_mapping:1, ++ in_time_wait:1, ++ list_rcvd:1, /* XXX TO REMOVE */ ++ addr_signal:1, /* Path-manager wants us to call addr_signal */ ++ dss_csum:1, ++ server_side:1, ++ infinite_mapping_rcv:1, ++ infinite_mapping_snd:1, ++ dfin_combined:1, /* Was the DFIN combined with subflow-fin? */ ++ passive_close:1, ++ snd_hiseq_index:1, /* Index in snd_high_order of snd_nxt */ ++ rcv_hiseq_index:1; /* Index in rcv_high_order of rcv_nxt */ ++ ++ /* socket count in this connection */ ++ u8 cnt_subflows; ++ u8 cnt_established; ++ ++#define MPTCP_SCHED_DATA_SIZE 8 ++ u8 mptcp_sched[MPTCP_SCHED_DATA_SIZE] __aligned(8); ++ struct mptcp_sched_ops *sched_ops; ++ ++ struct sk_buff_head reinject_queue; ++ /* First cache-line boundary is here minus 8 bytes. But from the ++ * reinject-queue only the next and prev pointers are regularly ++ * accessed. Thus, the whole data-path is on a single cache-line. ++ */ ++ ++ u64 csum_cutoff_seq; ++ u64 infinite_rcv_seq; ++ ++ /***** Start of fields, used for connection closure */ ++ spinlock_t tw_lock; ++ unsigned char mptw_state; ++ u8 dfin_path_index; ++ ++ struct list_head tw_list; ++ ++ /***** Start of fields, used for subflow establishment and closure */ ++ atomic_t mpcb_refcnt; ++ ++ /* Mutex needed, because otherwise mptcp_close will complain that the ++ * socket is owned by the user. ++ * E.g., mptcp_sub_close_wq is taking the meta-lock. ++ */ ++ struct mutex mpcb_mutex; ++ ++ /***** Start of fields, used for subflow establishment */ ++ struct sock *meta_sk; ++ ++ /* Master socket, also part of the connection_list, this ++ * socket is the one that the application sees. ++ */ ++ struct sock *master_sk; ++ ++ __u64 mptcp_loc_key; ++ __u64 mptcp_rem_key; ++ __u32 mptcp_loc_token; ++ __u32 mptcp_rem_token; ++ ++#define MPTCP_PM_SIZE 608 ++ u8 mptcp_pm[MPTCP_PM_SIZE] __aligned(8); ++ struct mptcp_pm_ops *pm_ops; ++ ++ u32 path_index_bits; ++ /* Next pi to pick up in case a new path becomes available */ ++ u8 next_path_index; ++ ++ __u8 mptcp_ver; ++ ++ /* Original snd/rcvbuf of the initial subflow. ++ * Used for the new subflows on the server-side to allow correct ++ * autotuning ++ */ ++ int orig_sk_rcvbuf; ++ int orig_sk_sndbuf; ++ u32 orig_window_clamp; ++ ++ struct tcp_info *master_info; ++}; ++ ++#define MPTCP_VERSION_0 0 ++#define MPTCP_VERSION_1 1 ++ ++#define MPTCP_SUB_CAPABLE 0 ++#define MPTCP_SUB_LEN_CAPABLE_SYN 12 ++#define MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_CAPABLE_ACK 20 ++#define MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN 20 ++ ++#define MPTCP_SUB_JOIN 1 ++#define MPTCP_SUB_LEN_JOIN_SYN 12 ++#define MPTCP_SUB_LEN_JOIN_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_JOIN_SYNACK 16 ++#define MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN 16 ++#define MPTCP_SUB_LEN_JOIN_ACK 24 ++#define MPTCP_SUB_LEN_JOIN_ACK_ALIGN 24 ++ ++#define MPTCP_SUB_DSS 2 ++#define MPTCP_SUB_LEN_DSS 4 ++#define MPTCP_SUB_LEN_DSS_ALIGN 4 ++ ++/* Lengths for seq and ack are the ones without the generic MPTCP-option header, ++ * as they are part of the DSS-option. ++ * To get the total length, just add the different options together. ++ */ ++#define MPTCP_SUB_LEN_SEQ 10 ++#define MPTCP_SUB_LEN_SEQ_CSUM 12 ++#define MPTCP_SUB_LEN_SEQ_ALIGN 12 ++ ++#define MPTCP_SUB_LEN_SEQ_64 14 ++#define MPTCP_SUB_LEN_SEQ_CSUM_64 16 ++#define MPTCP_SUB_LEN_SEQ_64_ALIGN 16 ++ ++#define MPTCP_SUB_LEN_ACK 4 ++#define MPTCP_SUB_LEN_ACK_ALIGN 4 ++ ++#define MPTCP_SUB_LEN_ACK_64 8 ++#define MPTCP_SUB_LEN_ACK_64_ALIGN 8 ++ ++/* This is the "default" option-length we will send out most often. ++ * MPTCP DSS-header ++ * 32-bit data sequence number ++ * 32-bit data ack ++ * ++ * It is necessary to calculate the effective MSS we will be using when ++ * sending data. ++ */ ++#define MPTCP_SUB_LEN_DSM_ALIGN (MPTCP_SUB_LEN_DSS_ALIGN + \ ++ MPTCP_SUB_LEN_SEQ_ALIGN + \ ++ MPTCP_SUB_LEN_ACK_ALIGN) ++ ++#define MPTCP_SUB_ADD_ADDR 3 ++#define MPTCP_SUB_LEN_ADD_ADDR4 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_VER1 28 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 28 ++ ++#define MPTCP_SUB_REMOVE_ADDR 4 ++#define MPTCP_SUB_LEN_REMOVE_ADDR 4 ++ ++#define MPTCP_SUB_PRIO 5 ++#define MPTCP_SUB_LEN_PRIO 3 ++#define MPTCP_SUB_LEN_PRIO_ADDR 4 ++#define MPTCP_SUB_LEN_PRIO_ALIGN 4 ++ ++#define MPTCP_SUB_FAIL 6 ++#define MPTCP_SUB_LEN_FAIL 12 ++#define MPTCP_SUB_LEN_FAIL_ALIGN 12 ++ ++#define MPTCP_SUB_FCLOSE 7 ++#define MPTCP_SUB_LEN_FCLOSE 12 ++#define MPTCP_SUB_LEN_FCLOSE_ALIGN 12 ++ ++ ++#define OPTION_MPTCP (1 << 5) ++ ++/* Max number of fastclose retransmissions */ ++#define MPTCP_FASTCLOSE_RETRIES 3 ++ ++#ifdef CONFIG_MPTCP ++ ++/* Used for checking if the mptcp initialization has been successful */ ++extern bool mptcp_init_failed; ++ ++/* MPTCP options */ ++#define OPTION_TYPE_SYN (1 << 0) ++#define OPTION_TYPE_SYNACK (1 << 1) ++#define OPTION_TYPE_ACK (1 << 2) ++#define OPTION_MP_CAPABLE (1 << 3) ++#define OPTION_DATA_ACK (1 << 4) ++#define OPTION_ADD_ADDR (1 << 5) ++#define OPTION_MP_JOIN (1 << 6) ++#define OPTION_MP_FAIL (1 << 7) ++#define OPTION_MP_FCLOSE (1 << 8) ++#define OPTION_REMOVE_ADDR (1 << 9) ++#define OPTION_MP_PRIO (1 << 10) ++ ++/* MPTCP flags: both TX and RX */ ++#define MPTCPHDR_SEQ 0x01 /* DSS.M option is present */ ++#define MPTCPHDR_FIN 0x02 /* DSS.F option is present */ ++#define MPTCPHDR_SEQ64_INDEX 0x04 /* index of seq in mpcb->snd_high_order */ ++/* MPTCP flags: RX only */ ++#define MPTCPHDR_ACK 0x08 ++#define MPTCPHDR_SEQ64_SET 0x10 /* Did we received a 64-bit seq number? */ ++#define MPTCPHDR_SEQ64_OFO 0x20 /* Is it not in our circular array? */ ++#define MPTCPHDR_DSS_CSUM 0x40 ++/* MPTCP flags: TX only */ ++#define MPTCPHDR_INF 0x08 ++#define MPTCP_REINJECT 0x10 /* Did we reinject this segment? */ ++ ++struct mptcp_option { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_capable { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++ __u8 h:1, ++ rsv:5, ++ b:1, ++ a:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++ __u8 a:1, ++ b:1, ++ rsv:5, ++ h:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 sender_key; ++ __u64 receiver_key; ++} __attribute__((__packed__)); ++ ++struct mp_join { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ u32 token; ++ u32 nonce; ++ } syn; ++ struct { ++ __u64 mac; ++ u32 nonce; ++ } synack; ++ struct { ++ __u8 mac[20]; ++ } ack; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_dss { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ A:1, ++ a:1, ++ M:1, ++ m:1, ++ F:1, ++ rsv2:3; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:3, ++ F:1, ++ m:1, ++ M:1, ++ a:1, ++ A:1; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_add_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ipver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ipver:4; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ struct in_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v4; ++ struct { ++ struct in6_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v6; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_remove_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 rsv:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:4; ++#else ++#error "Adjust your defines" ++#endif ++ /* list of addr_id */ ++ __u8 addrs_id; ++}; ++ ++struct mp_fail { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __be64 data_seq; ++} __attribute__((__packed__)); ++ ++struct mp_fclose { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 key; ++} __attribute__((__packed__)); ++ ++struct mp_prio { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++} __attribute__((__packed__)); ++ ++static inline int mptcp_sub_len_dss(const struct mp_dss *m, const int csum) ++{ ++ return 4 + m->A * (4 + m->a * 4) + m->M * (10 + m->m * 4 + csum * 2); ++} ++ ++#define MPTCP_SYSCTL 1 ++ ++extern int sysctl_mptcp_enabled; ++extern int sysctl_mptcp_version; ++extern int sysctl_mptcp_checksum; ++extern int sysctl_mptcp_debug; ++extern int sysctl_mptcp_syn_retries; ++ ++extern struct workqueue_struct *mptcp_wq; ++ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ if (unlikely(sysctl_mptcp_debug)) \ ++ pr_err(__FILE__ ": " fmt, ##args); \ ++ } while (0) ++ ++/* Iterates over all subflows */ ++#define mptcp_for_each_tp(mpcb, tp) \ ++ for ((tp) = (mpcb)->connection_list; (tp); (tp) = (tp)->mptcp->next) ++ ++#define mptcp_for_each_sk(mpcb, sk) \ ++ for ((sk) = (struct sock *)(mpcb)->connection_list; \ ++ sk; \ ++ sk = (struct sock *)tcp_sk(sk)->mptcp->next) ++ ++#define mptcp_for_each_sk_safe(__mpcb, __sk, __temp) \ ++ for (__sk = (struct sock *)(__mpcb)->connection_list, \ ++ __temp = __sk ? (struct sock *)tcp_sk(__sk)->mptcp->next : NULL; \ ++ __sk; \ ++ __sk = __temp, \ ++ __temp = __sk ? (struct sock *)tcp_sk(__sk)->mptcp->next : NULL) ++ ++/* Iterates over all bit set to 1 in a bitset */ ++#define mptcp_for_each_bit_set(b, i) \ ++ for (i = ffs(b) - 1; i >= 0; i = ffs(b >> (i + 1) << (i + 1)) - 1) ++ ++#define mptcp_for_each_bit_unset(b, i) \ ++ mptcp_for_each_bit_set(~b, i) ++ ++#define MPTCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++#define MPTCP_INC_STATS_BH(net, field) __SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++ ++enum ++{ ++ MPTCP_MIB_NUM = 0, ++ MPTCP_MIB_MPCAPABLEPASSIVE, /* Received SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVE, /* Sent SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVEACK, /* Received SYN/ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLERETRANSFALLBACK,/* Client-side stopped sending MP_CAPABLE after too many SYN-retransmissions */ ++ MPTCP_MIB_CSUMENABLED, /* Created MPTCP-connection with DSS-checksum enabled */ ++ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ ++ MPTCP_MIB_MPFAILRX, /* Received an MP_FAIL */ ++ MPTCP_MIB_CSUMFAIL, /* Received segment with invalid checksum */ ++ MPTCP_MIB_FASTCLOSERX, /* Recevied a FAST_CLOSE */ ++ MPTCP_MIB_FASTCLOSETX, /* Sent a FAST_CLOSE */ ++ MPTCP_MIB_FBACKSUB, /* Fallback upon ack without data-ack on new subflow */ ++ MPTCP_MIB_FBACKINIT, /* Fallback upon ack without data-ack on initial subflow */ ++ MPTCP_MIB_FBDATASUB, /* Fallback upon data without DSS at the beginning on new subflow */ ++ MPTCP_MIB_FBDATAINIT, /* Fallback upon data without DSS at the beginning on initial subflow */ ++ MPTCP_MIB_REMADDRSUB, /* Remove subflow due to REMOVE_ADDR */ ++ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ ++ MPTCP_MIB_JOINFALLBACK, /* Received MP_JOIN on session that has fallen back to reg. TCP */ ++ MPTCP_MIB_JOINSYNTX, /* Sent a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNRX, /* Received a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKRX, /* Received a SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKFAIL, /* Third ACK on new subflow did not contain an MP_JOIN */ ++ MPTCP_MIB_JOINACKRTO, /* Retransmission timer for third ACK + MP_JOIN timed out */ ++ MPTCP_MIB_JOINACKRXMIT, /* Retransmitted an ACK + MP_JOIN */ ++ MPTCP_MIB_NODSSWINDOW, /* Received too many packets without a DSS-option */ ++ MPTCP_MIB_DSSNOMATCH, /* Received a new mapping that did not match the previous one */ ++ MPTCP_MIB_INFINITEMAPRX, /* Received an infinite mapping */ ++ MPTCP_MIB_DSSTCPMISMATCH, /* DSS-mapping did not map with TCP's sequence numbers */ ++ MPTCP_MIB_DSSTRIMHEAD, /* Trimmed segment at the head (coalescing middlebox) */ ++ MPTCP_MIB_DSSSPLITTAIL, /* Trimmed segment at the tail (coalescing middlebox) */ ++ MPTCP_MIB_PURGEOLD, /* Removed old skb from the rcv-queue due to missing DSS-mapping */ ++ MPTCP_MIB_ADDADDRRX, /* Received an ADD_ADDR */ ++ MPTCP_MIB_ADDADDRTX, /* Sent an ADD_ADDR */ ++ MPTCP_MIB_REMADDRRX, /* Received a REMOVE_ADDR */ ++ MPTCP_MIB_REMADDRTX, /* Sent a REMOVE_ADDR */ ++ __MPTCP_MIB_MAX ++}; ++ ++#define MPTCP_MIB_MAX __MPTCP_MIB_MAX ++struct mptcp_mib { ++ unsigned long mibs[MPTCP_MIB_MAX]; ++}; ++ ++extern struct lock_class_key meta_key; ++extern char *meta_key_name; ++extern struct lock_class_key meta_slock_key; ++extern char *meta_slock_key_name; ++ ++extern u32 mptcp_secret[MD5_MESSAGE_BYTES / 4]; ++ ++/* This is needed to ensure that two subsequent key/nonce-generation result in ++ * different keys/nonces if the IPs and ports are the same. ++ */ ++extern u32 mptcp_seed; ++ ++#define MPTCP_HASH_SIZE 1024 ++ ++extern struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++ ++/* Request-sockets can be hashed in the tk_htb for collision-detection or in ++ * the regular htb for join-connections. We need to define different NULLS ++ * values so that we can correctly detect a request-socket that has been ++ * recycled. See also c25eb3bfb9729. ++ */ ++#define MPTCP_REQSK_NULLS_BASE (1U << 29) ++ ++ ++void mptcp_data_ready(struct sock *sk); ++void mptcp_write_space(struct sock *sk); ++ ++void mptcp_add_meta_ofo_queue(const struct sock *meta_sk, struct sk_buff *skb, ++ struct sock *sk); ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied); ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags); ++void mptcp_del_sock(struct sock *sk); ++void mptcp_update_metasocket(const struct sock *meta_sk); ++void mptcp_reinject_data(struct sock *orig_sk, int clone_it); ++void mptcp_update_sndbuf(const struct tcp_sock *tp); ++void mptcp_send_fin(struct sock *meta_sk); ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority); ++bool mptcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt); ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp); ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size); ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb); ++void mptcp_close(struct sock *meta_sk, long timeout); ++int mptcp_doit(struct sock *sk); ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window); ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req); ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop); ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++u32 __mptcp_select_window(struct sock *sk); ++void mptcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); ++unsigned int mptcp_current_mss(struct sock *meta_sk); ++int mptcp_select_size(const struct sock *meta_sk, bool sg, bool first_skb); ++void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn); ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...); ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk); ++void mptcp_fin(struct sock *meta_sk); ++void mptcp_meta_retransmit_timer(struct sock *meta_sk); ++void mptcp_sub_retransmit_timer(struct sock *sk); ++int mptcp_write_wakeup(struct sock *meta_sk, int mib); ++void mptcp_sub_close_wq(struct work_struct *work); ++void mptcp_sub_close(struct sock *sk, unsigned long delay); ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk); ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb); ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_ack_handler(unsigned long); ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time); ++int mptcp_check_snd_buf(const struct tcp_sock *tp); ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb); ++void __init mptcp_init(void); ++void mptcp_destroy_sock(struct sock *sk); ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed); ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw); ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw); ++void mptcp_time_wait(struct sock *sk, int state, int timeo); ++void mptcp_disconnect(struct sock *meta_sk); ++bool mptcp_should_expand_sndbuf(const struct sock *sk); ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_tsq_flags(struct sock *sk); ++void mptcp_tsq_sub_deferred(struct sock *meta_sk); ++struct mp_join *mptcp_find_join(const struct sk_buff *skb); ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp); ++struct sock *mptcp_hash_find(const struct net *net, const u32 token); ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw); ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net); ++void mptcp_reqsk_destructor(struct request_sock *req); ++void mptcp_connect_init(struct sock *sk); ++void mptcp_sub_force_close(struct sock *sk); ++int mptcp_sub_len_remove_addr_align(u16 bitfield); ++void mptcp_init_buffer_space(struct sock *sk); ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb); ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie); ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb); ++void mptcp_enable_sock(struct sock *sk); ++void mptcp_disable_sock(struct sock *sk); ++void mptcp_disable_static_key(void); ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb); ++void mptcp_sock_destruct(struct sock *sk); ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb); ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen); ++void mptcp_clear_sk(struct sock *sk, int size); ++ ++/* MPTCP-path-manager registration/initialization functions */ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_init_path_manager(struct mptcp_cb *mpcb); ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb); ++void mptcp_fallback_default(struct mptcp_cb *mpcb); ++void mptcp_get_default_path_manager(char *name); ++int mptcp_set_scheduler(struct sock *sk, const char *name); ++int mptcp_set_path_manager(struct sock *sk, const char *name); ++int mptcp_set_default_path_manager(const char *name); ++extern struct mptcp_pm_ops mptcp_pm_default; ++ ++/* MPTCP-scheduler registration/initialization functions */ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_init_scheduler(struct mptcp_cb *mpcb); ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb); ++void mptcp_get_default_scheduler(char *name); ++int mptcp_set_default_scheduler(const char *name); ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test); ++bool mptcp_is_def_unavailable(struct sock *sk); ++bool subflow_is_active(const struct tcp_sock *tp); ++bool subflow_is_backup(const struct tcp_sock *tp); ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test); ++extern struct mptcp_sched_ops mptcp_sched_default; ++ ++/* Initializes function-pointers and MPTCP-flags */ ++static inline void mptcp_init_tcp_sock(struct sock *sk) ++{ ++ if (!mptcp_init_failed && sysctl_mptcp_enabled == MPTCP_SYSCTL) ++ mptcp_enable_sock(sk); ++} ++ ++static inline int mptcp_pi_to_flag(int pi) ++{ ++ return 1 << (pi - 1); ++} ++ ++static inline ++struct mptcp_request_sock *mptcp_rsk(const struct request_sock *req) ++{ ++ return (struct mptcp_request_sock *)req; ++} ++ ++static inline ++struct request_sock *rev_mptcp_rsk(const struct mptcp_request_sock *req) ++{ ++ return (struct request_sock *)req; ++} ++ ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ struct sock *sk_it; ++ ++ if (tcp_sk(sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) { ++ if (!(sk_it->sk_route_caps & NETIF_F_SG) || ++ !sk_check_csum_caps(sk_it)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) ++{ ++ /* We check packets out and send-head here. TCP only checks the ++ * send-head. But, MPTCP also checks packets_out, as this is an ++ * indication that we might want to do opportunistic reinjection. ++ */ ++ if (tcp_sk(meta_sk)->packets_out || tcp_send_head(meta_sk)) { ++ struct tcp_sock *tp = tcp_sk(meta_sk); ++ ++ /* We don't care about the MSS, because it will be set in ++ * mptcp_write_xmit. ++ */ ++ __tcp_push_pending_frames(meta_sk, 0, tp->nonagle); ++ } ++} ++ ++static inline void mptcp_send_reset(struct sock *sk) ++{ ++ if (tcp_need_reset(sk->sk_state)) ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); ++ mptcp_sub_force_close(sk); ++} ++ ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ struct sock *sk_it, *tmp; ++ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmp) { ++ if (sk_it != except) ++ mptcp_send_reset(sk_it); ++ } ++} ++ ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ; ++} ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_FIN; ++} ++ ++/* Is it a data-fin while in infinite mapping mode? ++ * In infinite mode, a subflow-fin is in fact a data-fin. ++ */ ++static inline bool mptcp_is_data_fin2(const struct sk_buff *skb, ++ const struct tcp_sock *tp) ++{ ++ return mptcp_is_data_fin(skb) || ++ (tp->mpcb->infinite_mapping_rcv && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)); ++} ++ ++static inline u8 mptcp_get_64_bit(u64 data_seq, struct mptcp_cb *mpcb) ++{ ++ u64 data_seq_high = (u32)(data_seq >> 32); ++ ++ if (mpcb->rcv_high_order[0] == data_seq_high) ++ return 0; ++ else if (mpcb->rcv_high_order[1] == data_seq_high) ++ return MPTCPHDR_SEQ64_INDEX; ++ else ++ return MPTCPHDR_SEQ64_OFO; ++} ++ ++/* Sets the data_seq and returns pointer to the in-skb field of the data_seq. ++ * If the packet has a 64-bit dseq, the pointer points to the last 32 bits. ++ */ ++static inline __u32 *mptcp_skb_set_data_seq(const struct sk_buff *skb, ++ u32 *data_seq, ++ struct mptcp_cb *mpcb) ++{ ++ __u32 *ptr = (__u32 *)(skb_transport_header(skb) + TCP_SKB_CB(skb)->dss_off); ++ ++ if (TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ64_SET) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ if (mpcb) ++ TCP_SKB_CB(skb)->mptcp_flags |= mptcp_get_64_bit(data_seq64, mpcb); ++ ++ *data_seq = (u32)data_seq64; ++ ptr++; ++ } else { ++ *data_seq = get_unaligned_be32(ptr); ++ } ++ ++ return ptr; ++} ++ ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return tcp_sk(sk)->meta_sk; ++} ++ ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return tcp_sk(tp->meta_sk); ++} ++ ++static inline int is_meta_tp(const struct tcp_sock *tp) ++{ ++ return tp->mpcb && mptcp_meta_tp(tp) == tp; ++} ++ ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return sk->sk_state != TCP_NEW_SYN_RECV && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ mptcp(tcp_sk(sk)) && mptcp_meta_sk(sk) == sk; ++} ++ ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return !mptcp(tp) || (!tp->mptcp->slave_sk && !is_meta_tp(tp)); ++} ++ ++static inline void mptcp_init_mp_opt(struct mptcp_options_received *mopt) ++{ ++ mopt->saw_mpc = 0; ++ mopt->dss_csum = 0; ++ mopt->drop_me = 0; ++ ++ mopt->is_mp_join = 0; ++ mopt->join_ack = 0; ++ ++ mopt->saw_low_prio = 0; ++ mopt->low_prio = 0; ++ ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) ++{ ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ mopt->saw_low_prio = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->join_ack = 0; ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline __be32 mptcp_get_highorder_sndbits(const struct sk_buff *skb, ++ const struct mptcp_cb *mpcb) ++{ ++ return htonl(mpcb->snd_high_order[(TCP_SKB_CB(skb)->mptcp_flags & ++ MPTCPHDR_SEQ64_INDEX) ? 1 : 0]); ++} ++ ++static inline u64 mptcp_get_data_seq_64(const struct mptcp_cb *mpcb, int index, ++ u32 data_seq_32) ++{ ++ return ((u64)mpcb->rcv_high_order[index] << 32) | data_seq_32; ++} ++ ++static inline u64 mptcp_get_rcv_nxt_64(const struct tcp_sock *meta_tp) ++{ ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ return mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_nxt); ++} ++ ++static inline void mptcp_check_sndseq_wrap(struct tcp_sock *meta_tp, int inc) ++{ ++ if (unlikely(meta_tp->snd_nxt > meta_tp->snd_nxt + inc)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] += 2; ++ } ++} ++ ++static inline void mptcp_check_rcvseq_wrap(struct tcp_sock *meta_tp, ++ u32 old_rcv_nxt) ++{ ++ if (unlikely(old_rcv_nxt > meta_tp->rcv_nxt)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->rcv_high_order[mpcb->rcv_hiseq_index] += 2; ++ mpcb->rcv_hiseq_index = mpcb->rcv_hiseq_index ? 0 : 1; ++ } ++} ++ ++static inline int mptcp_sk_can_send(const struct sock *sk) ++{ ++ return tcp_passive_fastopen(sk) || ++ ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && ++ !tcp_sk(sk)->mptcp->pre_established); ++} ++ ++static inline int mptcp_sk_can_recv(const struct sock *sk) ++{ ++ return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2); ++} ++ ++static inline int mptcp_sk_can_send_ack(const struct sock *sk) ++{ ++ return !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | ++ TCPF_CLOSE | TCPF_LISTEN)) && ++ !tcp_sk(sk)->mptcp->pre_established; ++} ++ ++/* Only support GSO if all subflows supports it */ ++static inline bool mptcp_sk_can_gso(const struct sock *meta_sk) ++{ ++ struct sock *sk; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!sk_can_gso(sk)) ++ return false; ++ } ++ return true; ++} ++ ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ struct sock *sk; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!(sk->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ return true; ++} ++ ++static inline void mptcp_set_rto(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *sk_it; ++ struct inet_connection_sock *micsk = inet_csk(mptcp_meta_sk(sk)); ++ __u32 max_rto = 0; ++ ++ /* We are in recovery-phase on the MPTCP-level. Do not update the ++ * RTO, because this would kill exponential backoff. ++ */ ++ if (micsk->icsk_retransmits) ++ return; ++ ++ mptcp_for_each_sk(tp->mpcb, sk_it) { ++ if ((mptcp_sk_can_send(sk_it) || sk_it->sk_state == TCP_SYN_RECV) && ++ inet_csk(sk_it)->icsk_retransmits == 0 && ++ inet_csk(sk_it)->icsk_rto > max_rto) ++ max_rto = inet_csk(sk_it)->icsk_rto; ++ } ++ if (max_rto) { ++ micsk->icsk_rto = max_rto << 1; ++ ++ /* A successfull rto-measurement - reset backoff counter */ ++ micsk->icsk_backoff = 0; ++ } ++} ++ ++static inline void mptcp_sub_close_passive(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(meta_sk); ++ ++ /* Only close, if the app did a send-shutdown (passive close), and we ++ * received the data-ack of the data-fin. ++ */ ++ if (tp->mpcb->passive_close && meta_tp->snd_una == meta_tp->write_seq) ++ mptcp_sub_close(sk, 0); ++} ++ ++static inline bool mptcp_fallback_infinite(struct sock *sk, int flag) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If data has been acknowleged on the meta-level, fully_established ++ * will have been set before and thus we will not fall back to infinite ++ * mapping. ++ */ ++ if (likely(tp->mptcp->fully_established)) ++ return false; ++ ++ if (!(flag & MPTCP_FLAG_DATA_ACKED)) ++ return false; ++ ++ /* Don't fallback twice ;) */ ++ if (mpcb->infinite_mapping_snd) ++ return false; ++ ++ pr_err("%s %#x will fallback - pi %d, src %pI4:%u dst %pI4:%u rcv_nxt %u from %pS\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ &inet_sk(sk)->inet_saddr, ntohs(inet_sk(sk)->inet_sport), ++ &inet_sk(sk)->inet_daddr, ntohs(inet_sk(sk)->inet_dport), ++ tp->rcv_nxt, __builtin_return_address(0)); ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKSUB); ++ return true; ++ } ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ tp->mptcp->fully_established = 1; ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKINIT); ++ ++ return false; ++} ++ ++/* Find the first index whose bit in the bit-field == 0 */ ++static inline u8 mptcp_set_new_pathindex(struct mptcp_cb *mpcb) ++{ ++ u8 base = mpcb->next_path_index; ++ int i; ++ ++ /* Start at 1, because 0 is reserved for the meta-sk */ ++ mptcp_for_each_bit_unset(mpcb->path_index_bits >> base, i) { ++ if (i + base < 1) ++ continue; ++ if (i + base >= sizeof(mpcb->path_index_bits) * 8) ++ break; ++ i += base; ++ mpcb->path_index_bits |= (1 << i); ++ mpcb->next_path_index = i + 1; ++ return i; ++ } ++ mptcp_for_each_bit_unset(mpcb->path_index_bits, i) { ++ if (i >= sizeof(mpcb->path_index_bits) * 8) ++ break; ++ if (i < 1) ++ continue; ++ mpcb->path_index_bits |= (1 << i); ++ mpcb->next_path_index = i + 1; ++ return i; ++ } ++ ++ return 0; ++} ++ ++static inline bool mptcp_v6_is_v4_mapped(const struct sock *sk) ++{ ++ return sk->sk_family == AF_INET6 && ++ ipv6_addr_type(&inet6_sk(sk)->saddr) == IPV6_ADDR_MAPPED; ++} ++ ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ /* Has been removed from the tk-table. Thus, no new subflows. ++ * ++ * Check for close-state is necessary, because we may have been closed ++ * without passing by mptcp_close(). ++ * ++ * When falling back, no new subflows are allowed either. ++ */ ++ return meta_sk->sk_state != TCP_CLOSE && ++ tcp_sk(meta_sk)->inside_tk_table && ++ !tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv && ++ !tcp_sk(meta_sk)->mpcb->send_infinite_mapping; ++} ++ ++/* TCP and MPTCP mpc flag-depending functions */ ++u16 mptcp_select_window(struct sock *sk); ++void mptcp_init_buffer_space(struct sock *sk); ++void mptcp_tcp_set_rto(struct sock *sk); ++ ++/* TCP and MPTCP flag-depending functions */ ++bool mptcp_prune_ofo_queue(struct sock *sk); ++ ++#else /* CONFIG_MPTCP */ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ } while (0) ++ ++/* Without MPTCP, we just do one iteration ++ * over the only socket available. This assumes that ++ * the sk/tp arg is the socket in that case. ++ */ ++#define mptcp_for_each_sk(mpcb, sk) ++#define mptcp_for_each_sk_safe(__mpcb, __sk, __temp) ++ ++#define MPTCP_INC_STATS(net, field) \ ++ do { \ ++ } while(0) ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return NULL; ++} ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return NULL; ++} ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return 0; ++} ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_del_sock(const struct sock *sk) {} ++static inline void mptcp_update_metasocket(const struct sock *meta_sk) {} ++static inline void mptcp_reinject_data(struct sock *orig_sk, int clone_it) {} ++static inline void mptcp_update_sndbuf(const struct tcp_sock *tp) {} ++static inline void mptcp_clean_rtx_infinite(const struct sk_buff *skb, ++ const struct sock *sk) {} ++static inline void mptcp_sub_close(struct sock *sk, unsigned long delay) {} ++static inline void mptcp_set_rto(const struct sock *sk) {} ++static inline void mptcp_send_fin(const struct sock *meta_sk) {} ++static inline void mptcp_parse_options(const uint8_t *ptr, const int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ const struct tcp_sock *tp) {} ++static inline void mptcp_syn_options(const struct sock *sk, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++static inline void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++ ++static inline void mptcp_established_options(struct sock *sk, ++ struct sk_buff *skb, ++ struct tcp_out_options *opts, ++ unsigned *size) {} ++static inline void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) {} ++static inline void mptcp_close(struct sock *meta_sk, long timeout) {} ++static inline int mptcp_doit(struct sock *sk) ++{ ++ return 0; ++} ++static inline int mptcp_check_req_fastopen(struct sock *child, ++ struct request_sock *req) ++{ ++ return 1; ++} ++static inline int mptcp_check_req_master(const struct sock *sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ const struct sk_buff *skb, ++ int drop) ++{ ++ return 1; ++} ++static inline struct sock *mptcp_check_req_child(const struct sock *meta_sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return NULL; ++} ++static inline unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ return 0; ++} ++static inline void mptcp_sub_close_passive(struct sock *sk) {} ++static inline bool mptcp_fallback_infinite(const struct sock *sk, int flag) ++{ ++ return false; ++} ++static inline void mptcp_init_mp_opt(const struct mptcp_options_received *mopt) {} ++static inline void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) {} ++static inline bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ return false; ++} ++static inline int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_send_reset(const struct sock *sk) {} ++static inline bool mptcp_handle_options(struct sock *sk, ++ const struct tcphdr *th, ++ struct sk_buff *skb) ++{ ++ return false; ++} ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) {} ++static inline void __init mptcp_init(void) {} ++static inline bool mptcp_sk_can_gso(const struct sock *sk) ++{ ++ return false; ++} ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ return false; ++} ++static inline unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, ++ u32 mss_now, int large_allowed) ++{ ++ return 0; ++} ++static inline void mptcp_destroy_sock(struct sock *sk) {} ++static inline int mptcp_rcv_synsent_state_process(struct sock *sk, ++ struct sock **skptr, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return 0; ++} ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_init_tw_sock(struct sock *sk, ++ struct tcp_timewait_sock *tw) ++{ ++ return 0; ++} ++static inline void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) {} ++static inline void mptcp_disconnect(struct sock *meta_sk) {} ++static inline void mptcp_tsq_flags(struct sock *sk) {} ++static inline void mptcp_tsq_sub_deferred(struct sock *meta_sk) {} ++static inline void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) {} ++static inline void mptcp_remove_shortcuts(const struct mptcp_cb *mpcb, ++ const struct sk_buff *skb) {} ++static inline void mptcp_init_tcp_sock(struct sock *sk) {} ++static inline void mptcp_disable_static_key(void) {} ++static inline void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) {} ++static inline void mptcp_fin(struct sock *meta_sk) {} ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_H */ +diff -aurN linux-4.9.162/include/net/mptcp_v4.h mptcp-mptcp_v0.93/include/net/mptcp_v4.h +--- linux-4.9.162/include/net/mptcp_v4.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/mptcp_v4.h 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef MPTCP_V4_H_ ++#define MPTCP_V4_H_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern struct request_sock_ops mptcp_request_sock_ops; ++extern const struct inet_connection_sock_af_ops mptcp_v4_specific; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++#ifdef CONFIG_MPTCP ++ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v4_search_req(const __be16 rport, const __be32 raddr, ++ const __be32 laddr, const struct net *net); ++int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem); ++int mptcp_pm_v4_init(void); ++void mptcp_pm_v4_undo(void); ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport); ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed); ++ ++#else ++ ++static inline int mptcp_v4_do_rcv(const struct sock *meta_sk, ++ const struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* MPTCP_V4_H_ */ +diff -aurN linux-4.9.162/include/net/mptcp_v6.h mptcp-mptcp_v0.93/include/net/mptcp_v6.h +--- linux-4.9.162/include/net/mptcp_v6.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/mptcp_v6.h 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,69 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_V6_H ++#define _MPTCP_V6_H ++ ++#include ++#include ++ ++#include ++ ++ ++#ifdef CONFIG_MPTCP ++extern const struct inet_connection_sock_af_ops mptcp_v6_mapped; ++extern const struct inet_connection_sock_af_ops mptcp_v6_specific; ++extern struct request_sock_ops mptcp6_request_sock_ops; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v6_search_req(const __be16 rport, const struct in6_addr *raddr, ++ const struct in6_addr *laddr, const struct net *net); ++int mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem); ++int mptcp_pm_v6_init(void); ++void mptcp_pm_v6_undo(void); ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport); ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed); ++ ++#else /* CONFIG_MPTCP */ ++ ++#define mptcp_v6_mapped ipv6_mapped ++ ++static inline int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_V6_H */ +diff -aurN linux-4.9.162/include/net/net_namespace.h mptcp-mptcp_v0.93/include/net/net_namespace.h +--- linux-4.9.162/include/net/net_namespace.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/net_namespace.h 2019-03-14 14:02:32.000000000 +0100 +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -96,6 +97,9 @@ + #if IS_ENABLED(CONFIG_IPV6) + struct netns_ipv6 ipv6; + #endif ++#if IS_ENABLED(CONFIG_MPTCP) ++ struct netns_mptcp mptcp; ++#endif + #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) + struct netns_ieee802154_lowpan ieee802154_lowpan; + #endif +diff -aurN linux-4.9.162/include/net/netns/mptcp.h mptcp-mptcp_v0.93/include/net/netns/mptcp.h +--- linux-4.9.162/include/net/netns/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/netns/mptcp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,52 @@ ++/* ++ * MPTCP implementation - MPTCP namespace ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef __NETNS_MPTCP_H__ ++#define __NETNS_MPTCP_H__ ++ ++#include ++ ++enum { ++ MPTCP_PM_FULLMESH = 0, ++ MPTCP_PM_MAX ++}; ++ ++struct mptcp_mib; ++ ++struct netns_mptcp { ++ DEFINE_SNMP_STAT(struct mptcp_mib, mptcp_statistics); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_net_mptcp; ++#endif ++ ++ void *path_managers[MPTCP_PM_MAX]; ++}; ++ ++#endif /* __NETNS_MPTCP_H__ */ +diff -aurN linux-4.9.162/include/net/snmp.h mptcp-mptcp_v0.93/include/net/snmp.h +--- linux-4.9.162/include/net/snmp.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/snmp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -91,7 +91,6 @@ + atomic_long_t mibs[ICMP6MSG_MIB_MAX]; + }; + +- + /* TCP */ + #define TCP_MIB_MAX __TCP_MIB_MAX + struct tcp_mib { +diff -aurN linux-4.9.162/include/net/sock.h mptcp-mptcp_v0.93/include/net/sock.h +--- linux-4.9.162/include/net/sock.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/sock.h 2019-03-14 14:02:32.000000000 +0100 +@@ -743,6 +743,7 @@ + SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ + SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ ++ SOCK_MPTCP, /* MPTCP set on this socket */ + }; + + #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) +@@ -948,6 +949,16 @@ + + int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb); + ++/* START - needed for MPTCP */ ++struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, int family); ++void sock_lock_init(struct sock *sk); ++ ++extern struct lock_class_key af_callback_keys[AF_MAX]; ++extern char *const af_family_clock_key_strings[AF_MAX+1]; ++ ++#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) ++/* END - needed for MPTCP */ ++ + struct request_sock_ops; + struct timewait_sock_ops; + struct inet_hashinfo; +@@ -1022,6 +1033,7 @@ + void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); + int (*get_port)(struct sock *sk, unsigned short snum); ++ void (*clear_sk)(struct sock *sk, int size); + + /* Keeping track of sockets in use */ + #ifdef CONFIG_PROC_FS +diff -aurN linux-4.9.162/include/net/tcp.h mptcp-mptcp_v0.93/include/net/tcp.h +--- linux-4.9.162/include/net/tcp.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/tcp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -178,6 +178,7 @@ + #define TCPOPT_SACK 5 /* SACK Block */ + #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ + #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ ++#define TCPOPT_MPTCP 30 + #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ + #define TCPOPT_EXP 254 /* Experimental */ + /* Magic number to be after the option value for sharing TCP +@@ -231,6 +232,30 @@ + */ + #define TFO_SERVER_WO_SOCKOPT1 0x400 + ++/* Flags from tcp_input.c for tcp_ack */ ++#define FLAG_DATA 0x01 /* Incoming frame contained data. */ ++#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ ++#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ ++#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ ++#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ ++#define FLAG_DATA_SACKED 0x20 /* New SACK. */ ++#define FLAG_ECE 0x40 /* ECE in this ACK */ ++#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ ++#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ ++#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ ++#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ ++#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ ++#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ ++#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ ++#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ ++ ++#define MPTCP_FLAG_DATA_ACKED 0x10000 ++ ++#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) ++#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) ++#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE) ++#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) ++ + extern struct inet_timewait_death_row tcp_death_row; + + /* sysctl variables for tcp */ +@@ -335,6 +360,97 @@ + #define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) + #define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) + ++/**** START - Exports needed for MPTCP ****/ ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops; ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops; ++ ++struct mptcp_options_received; ++ ++void tcp_cleanup_rbuf(struct sock *sk, int copied); ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited); ++int tcp_close_state(struct sock *sk); ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb); ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib); ++void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb); ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask); ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle); ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle); ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss); ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, const struct sk_buff *skb); ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++int __pskb_trim_head(struct sk_buff *skb, int len); ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb); ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags); ++void tcp_reset(struct sock *sk); ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin); ++bool tcp_urg_mode(const struct tcp_sock *tp); ++void tcp_ack_probe(struct sock *sk); ++void tcp_rearm_rto(struct sock *sk); ++int tcp_write_timeout(struct sock *sk); ++bool retransmits_timed_out(struct sock *sk, unsigned int boundary, ++ unsigned int timeout, bool syn_set); ++void tcp_write_err(struct sock *sk); ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr); ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++ ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb); ++void tcp_v4_reqsk_destructor(struct request_sock *req); ++ ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); ++void tcp_v6_destroy_sock(struct sock *sk); ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); ++void tcp_v6_hash(struct sock *sk); ++struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb); ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req); ++void tcp_v6_reqsk_destructor(struct request_sock *req); ++ ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, ++ int large_allowed); ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb); ++ ++void skb_clone_fraglist(struct sk_buff *skb); ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old); ++ ++void inet_twsk_free(struct inet_timewait_sock *tw); ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb); ++/* These states need RST on ABORT according to RFC793 */ ++static inline bool tcp_need_reset(int state) ++{ ++ return (1 << state) & ++ (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | ++ TCPF_FIN_WAIT2 | TCPF_SYN_RECV); ++} ++ ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen); ++bool tcp_try_coalesce(struct sock *sk, struct sk_buff *to, ++ struct sk_buff *from, bool *fragstolen); ++void tcp_ofo_queue(struct sock *sk); ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb); ++int linear_payload_sz(bool first_skb); ++/**** END - Exports needed for MPTCP ****/ ++ + void tcp_tasklet_init(void); + + void tcp_v4_err(struct sk_buff *skb, u32); +@@ -428,7 +544,9 @@ + int flags, int *addr_len); + void tcp_parse_options(const struct sk_buff *skb, + struct tcp_options_received *opt_rx, +- int estab, struct tcp_fastopen_cookie *foc); ++ struct mptcp_options_received *mopt_rx, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp); + const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); + + /* +@@ -437,6 +555,7 @@ + + void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); + void tcp_v4_mtu_reduced(struct sock *sk); ++void tcp_v6_mtu_reduced(struct sock *sk); + void tcp_req_err(struct sock *sk, u32 seq, bool abort); + int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); + struct sock *tcp_create_openreq_child(const struct sock *sk, +@@ -517,7 +636,8 @@ + + u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, + u16 *mssp); +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + __u32 cookie_init_timestamp(struct request_sock *req); + bool cookie_timestamp_decode(struct tcp_options_received *opt); + bool cookie_ecn_ok(const struct tcp_options_received *opt, +@@ -530,7 +650,8 @@ + + u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, + const struct tcphdr *th, u16 *mssp); +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + /* tcp_output.c */ + +@@ -562,11 +683,18 @@ + void tcp_skb_collapse_tstamp(struct sk_buff *skb, + const struct sk_buff *next_skb); + ++u16 tcp_select_window(struct sock *sk); ++int select_size(const struct sock *sk, bool sg, bool first_skb); ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ + /* tcp_input.c */ + void tcp_resume_early_retransmit(struct sock *sk); + void tcp_rearm_rto(struct sock *sk); + void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); + void tcp_reset(struct sock *sk); ++void tcp_set_rto(struct sock *sk); ++bool tcp_should_expand_sndbuf(const struct sock *sk); + void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); + void tcp_fin(struct sock *sk); + +@@ -748,6 +876,12 @@ + u16 tcp_gso_size; + }; + }; ++ ++#ifdef CONFIG_MPTCP ++ __u8 mptcp_flags; /* flags for the MPTCP layer */ ++ __u8 dss_off; /* Number of 4-byte words until ++ * seq-number */ ++#endif + __u8 tcp_flags; /* TCP header flags. (tcp[13]) */ + + __u8 sacked; /* State flags for SACK/FACK. */ +@@ -765,6 +899,14 @@ + eor:1, /* Is skb MSG_EOR marked? */ + unused:6; + __u32 ack_seq; /* Sequence number ACK'd */ ++ ++#ifdef CONFIG_MPTCP ++ union { /* For MPTCP outgoing frames */ ++ __u32 path_mask; /* paths that tried to send this skb */ ++ __u32 dss[6]; /* DSS options */ ++ }; ++#endif ++ + union { + struct { + /* There is space for up to 24 bytes */ +@@ -1261,7 +1403,8 @@ + /* Determine a window scaling and initial window to offer. */ + void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, + __u32 *window_clamp, int wscale_ok, +- __u8 *rcv_wscale, __u32 init_rcv_wnd); ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); + + static inline int tcp_win_from_space(int space) + { +@@ -1272,6 +1415,19 @@ + space - (space>>tcp_adv_win_scale); + } + ++#ifdef CONFIG_MPTCP ++extern struct static_key mptcp_static_key; ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return static_key_false(&mptcp_static_key) && tp->mpc; ++} ++#else ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++#endif ++ + /* Note: caller must be prepared to deal with negative returns */ + static inline int tcp_space(const struct sock *sk) + { +@@ -1791,6 +1947,30 @@ + #endif + }; + ++/* TCP/MPTCP-specific functions */ ++struct tcp_sock_ops { ++ u32 (*__select_window)(struct sock *sk); ++ u16 (*select_window)(struct sock *sk); ++ void (*select_initial_window)(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk); ++ int (*select_size)(const struct sock *sk, bool sg, bool first_skb); ++ void (*init_buffer_space)(struct sock *sk); ++ void (*set_rto)(struct sock *sk); ++ bool (*should_expand_sndbuf)(const struct sock *sk); ++ void (*send_fin)(struct sock *sk); ++ bool (*write_xmit)(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ void (*send_active_reset)(struct sock *sk, gfp_t priority); ++ int (*write_wakeup)(struct sock *sk, int mib); ++ void (*retransmit_timer)(struct sock *sk); ++ void (*time_wait)(struct sock *sk, int state, int timeo); ++ void (*cleanup_rbuf)(struct sock *sk, int copied); ++ void (*cwnd_validate)(struct sock *sk, bool is_cwnd_limited); ++}; ++extern const struct tcp_sock_ops tcp_specific; ++ + struct tcp_request_sock_ops { + u16 mss_clamp; + #ifdef CONFIG_TCP_MD5SIG +@@ -1801,12 +1981,13 @@ + const struct sock *sk, + const struct sk_buff *skb); + #endif +- void (*init_req)(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb); ++ int (*init_req)(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie); + #ifdef CONFIG_SYN_COOKIES +- __u32 (*cookie_init_seq)(const struct sk_buff *skb, +- __u16 *mss); ++ __u32 (*cookie_init_seq)(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, + const struct request_sock *req, +@@ -1820,15 +2001,17 @@ + + #ifdef CONFIG_SYN_COOKIES + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { + tcp_synq_overflow(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); +- return ops->cookie_init_seq(skb, mss); ++ return ops->cookie_init_seq(req, sk, skb, mss); + } + #else + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { +diff -aurN linux-4.9.162/include/net/tcp_states.h mptcp-mptcp_v0.93/include/net/tcp_states.h +--- linux-4.9.162/include/net/tcp_states.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/tcp_states.h 2019-03-14 14:02:32.000000000 +0100 +@@ -26,6 +26,7 @@ + TCP_LISTEN, + TCP_CLOSING, /* Now a valid state */ + TCP_NEW_SYN_RECV, ++ TCP_RST_WAIT, + + TCP_MAX_STATES /* Leave at the end! */ + }; +@@ -47,6 +48,7 @@ + TCPF_LISTEN = (1 << 10), + TCPF_CLOSING = (1 << 11), + TCPF_NEW_SYN_RECV = (1 << 12), ++ TCPF_RST_WAIT = (1 << 13), + }; + + #endif /* _LINUX_TCP_STATES_H */ +diff -aurN linux-4.9.162/include/net/transp_v6.h mptcp-mptcp_v0.93/include/net/transp_v6.h +--- linux-4.9.162/include/net/transp_v6.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/net/transp_v6.h 2019-03-14 14:02:32.000000000 +0100 +@@ -51,6 +51,8 @@ + + /* address family specific functions */ + extern const struct inet_connection_sock_af_ops ipv4_specific; ++extern const struct inet_connection_sock_af_ops ipv6_mapped; ++extern const struct inet_connection_sock_af_ops ipv6_specific; + + void inet6_destroy_sock(struct sock *sk); + +diff -aurN linux-4.9.162/include/uapi/linux/if.h mptcp-mptcp_v0.93/include/uapi/linux/if.h +--- linux-4.9.162/include/uapi/linux/if.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/uapi/linux/if.h 2019-03-14 14:02:32.000000000 +0100 +@@ -127,6 +127,9 @@ + #define IFF_ECHO IFF_ECHO + #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + ++#define IFF_NOMULTIPATH 0x80000 /* Disable for MPTCP */ ++#define IFF_MPBACKUP 0x100000 /* Use as backup path for MPTCP */ ++ + #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +diff -aurN linux-4.9.162/include/uapi/linux/tcp.h mptcp-mptcp_v0.93/include/uapi/linux/tcp.h +--- linux-4.9.162/include/uapi/linux/tcp.h 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/include/uapi/linux/tcp.h 2019-03-14 14:02:32.000000000 +0100 +@@ -17,9 +17,15 @@ + #ifndef _UAPI_LINUX_TCP_H + #define _UAPI_LINUX_TCP_H + +-#include ++#ifndef __KERNEL__ ++#include ++#endif ++ + #include ++#include ++#include + #include ++#include + + struct tcphdr { + __be16 source; +@@ -116,6 +122,12 @@ + #define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */ + #define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */ + #define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */ ++#define MPTCP_ENABLED 42 ++#define MPTCP_SCHEDULER 43 ++#define MPTCP_PATH_MANAGER 44 ++#define MPTCP_INFO 45 ++ ++#define MPTCP_INFO_FLAG_SAVE_MASTER 0x01 + + struct tcp_repair_opt { + __u32 opt_code; +@@ -216,6 +228,53 @@ + __u64 tcpi_delivery_rate; + }; + ++struct mptcp_meta_info { ++ __u8 mptcpi_state; ++ __u8 mptcpi_retransmits; ++ __u8 mptcpi_probes; ++ __u8 mptcpi_backoff; ++ ++ __u32 mptcpi_rto; ++ __u32 mptcpi_unacked; ++ ++ /* Times. */ ++ __u32 mptcpi_last_data_sent; ++ __u32 mptcpi_last_data_recv; ++ __u32 mptcpi_last_ack_recv; ++ ++ __u32 mptcpi_total_retrans; ++ ++ __u64 mptcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ ++ __u64 mptcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ ++}; ++ ++struct mptcp_sub_info { ++ union { ++ struct sockaddr src; ++ struct sockaddr_in src_v4; ++ struct sockaddr_in6 src_v6; ++ }; ++ ++ union { ++ struct sockaddr dst; ++ struct sockaddr_in dst_v4; ++ struct sockaddr_in6 dst_v6; ++ }; ++}; ++ ++struct mptcp_info { ++ __u32 tcp_info_len; /* Length of each struct tcp_info in subflows pointer */ ++ __u32 sub_len; /* Total length of memory pointed to by subflows pointer */ ++ __u32 meta_len; /* Length of memory pointed to by meta_info */ ++ __u32 sub_info_len; /* Length of each struct mptcp_sub_info in subflow_info pointer */ ++ __u32 total_sub_info_len; /* Total length of memory pointed to by subflow_info */ ++ ++ struct mptcp_meta_info *meta_info; ++ struct tcp_info *initial; ++ struct tcp_info *subflows; /* Pointer to array of tcp_info structs */ ++ struct mptcp_sub_info *subflow_info; ++}; ++ + /* for TCP_MD5SIG socket option */ + #define TCP_MD5SIG_MAXKEYLEN 80 + +diff -aurN linux-4.9.162/net/core/dev.c mptcp-mptcp_v0.93/net/core/dev.c +--- linux-4.9.162/net/core/dev.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/core/dev.c 2019-03-14 14:02:32.000000000 +0100 +@@ -6478,7 +6478,7 @@ + + dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | + IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | +- IFF_AUTOMEDIA)) | ++ IFF_AUTOMEDIA | IFF_NOMULTIPATH | IFF_MPBACKUP)) | + (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | + IFF_ALLMULTI)); + +diff -aurN linux-4.9.162/net/core/skbuff.c mptcp-mptcp_v0.93/net/core/skbuff.c +--- linux-4.9.162/net/core/skbuff.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/core/skbuff.c 2019-03-14 14:02:32.000000000 +0100 +@@ -566,7 +566,7 @@ + skb_drop_list(&skb_shinfo(skb)->frag_list); + } + +-static void skb_clone_fraglist(struct sk_buff *skb) ++void skb_clone_fraglist(struct sk_buff *skb) + { + struct sk_buff *list; + +@@ -1062,7 +1062,7 @@ + skb->inner_mac_header += off; + } + +-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) + { + __copy_skb_header(new, old); + +diff -aurN linux-4.9.162/net/core/sock.c mptcp-mptcp_v0.93/net/core/sock.c +--- linux-4.9.162/net/core/sock.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/core/sock.c 2019-03-14 14:02:32.000000000 +0100 +@@ -138,6 +138,11 @@ + + #include + ++#ifdef CONFIG_MPTCP ++#include ++#include ++#endif ++ + #include + #include + +@@ -238,7 +243,7 @@ + "slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_KCM" , + "slock-AF_QIPCRTR", "slock-AF_MAX" + }; +-static const char *const af_family_clock_key_strings[AF_MAX+1] = { ++char *const af_family_clock_key_strings[AF_MAX+1] = { + "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , + "clock-AF_AX25" , "clock-AF_IPX" , "clock-AF_APPLETALK", + "clock-AF_NETROM", "clock-AF_BRIDGE" , "clock-AF_ATMPVC" , +@@ -260,7 +265,7 @@ + * sk_callback_lock locking rules are per-address-family, + * so split the lock classes by using a per-AF key: + */ +-static struct lock_class_key af_callback_keys[AF_MAX]; ++struct lock_class_key af_callback_keys[AF_MAX]; + + /* Take into consideration the size of the struct sk_buff overhead in the + * determination of these values, since that is non-constant across +@@ -1284,8 +1289,25 @@ + * + * (We also register the sk_lock with the lock validator.) + */ +-static inline void sock_lock_init(struct sock *sk) ++void sock_lock_init(struct sock *sk) + { ++#ifdef CONFIG_MPTCP ++ /* Reclassify the lock-class for subflows */ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ if (mptcp(tcp_sk(sk)) || tcp_sk(sk)->is_master_sk) { ++ sock_lock_init_class_and_name(sk, meta_slock_key_name, ++ &meta_slock_key, ++ meta_key_name, ++ &meta_key); ++ ++ /* We don't yet have the mptcp-point. ++ * Thus we still need inet_sock_destruct ++ */ ++ sk->sk_destruct = inet_sock_destruct; ++ return; ++ } ++#endif ++ + sock_lock_init_class_and_name(sk, + af_family_slock_key_strings[sk->sk_family], + af_family_slock_keys + sk->sk_family, +@@ -1314,7 +1336,7 @@ + #endif + } + +-static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, ++struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, + int family) + { + struct sock *sk; +@@ -1325,8 +1347,12 @@ + sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); + if (!sk) + return sk; +- if (priority & __GFP_ZERO) +- sk_prot_clear_nulls(sk, prot->obj_size); ++ if (priority & __GFP_ZERO) { ++ if (prot->clear_sk) ++ prot->clear_sk(sk, prot->obj_size); ++ else ++ sk_prot_clear_nulls(sk, prot->obj_size); ++ } + } else + sk = kmalloc(prot->obj_size, priority); + +@@ -1527,6 +1553,7 @@ + newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; + + sock_reset_flag(newsk, SOCK_DONE); ++ sock_reset_flag(newsk, SOCK_MPTCP); + cgroup_sk_alloc(&newsk->sk_cgrp_data); + skb_queue_head_init(&newsk->sk_error_queue); + +diff -aurN linux-4.9.162/net/ipv4/af_inet.c mptcp-mptcp_v0.93/net/ipv4/af_inet.c +--- linux-4.9.162/net/ipv4/af_inet.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/af_inet.c 2019-03-14 14:02:32.000000000 +0100 +@@ -104,6 +104,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -149,6 +150,9 @@ + return; + } + ++ if (sock_flag(sk, SOCK_MPTCP)) ++ mptcp_disable_static_key(); ++ + WARN_ON(atomic_read(&sk->sk_rmem_alloc)); + WARN_ON(atomic_read(&sk->sk_wmem_alloc)); + WARN_ON(sk->sk_wmem_queued); +@@ -241,8 +245,7 @@ + * Create an inet socket. + */ + +-static int inet_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct sock *sk; + struct inet_protosw *answer; +@@ -674,6 +677,23 @@ + lock_sock(sk2); + + sock_rps_record_flow(sk2); ++ ++ if (sk2->sk_protocol == IPPROTO_TCP && mptcp(tcp_sk(sk2))) { ++ struct sock *sk_it = sk2; ++ ++ mptcp_for_each_sk(tcp_sk(sk2)->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ ++ if (tcp_sk(sk2)->mpcb->master_sk) { ++ sk_it = tcp_sk(sk2)->mpcb->master_sk; ++ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_it->sk_wq = newsock->wq; ++ sk_it->sk_socket = newsock; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ } ++ + WARN_ON(!((1 << sk2->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | + TCPF_CLOSE_WAIT | TCPF_CLOSE))); +@@ -1831,6 +1851,9 @@ + + ip_init(); + ++ /* We must initialize MPTCP before TCP. */ ++ mptcp_init(); ++ + tcp_v4_init(); + + /* Setup TCP slab cache for open requests. */ +diff -aurN linux-4.9.162/net/ipv4/inet_connection_sock.c mptcp-mptcp_v0.93/net/ipv4/inet_connection_sock.c +--- linux-4.9.162/net/ipv4/inet_connection_sock.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/inet_connection_sock.c 2019-03-14 14:02:32.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -557,7 +558,10 @@ + int max_retries, thresh; + u8 defer_accept; + +- if (sk_state_load(sk_listener) != TCP_LISTEN) ++ if (sk_state_load(sk_listener) != TCP_LISTEN && !is_meta_sk(sk_listener)) ++ goto drop; ++ ++ if (is_meta_sk(sk_listener) && !mptcp_can_new_subflow(sk_listener)) + goto drop; + + max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; +@@ -651,7 +655,9 @@ + const struct request_sock *req, + const gfp_t priority) + { +- struct sock *newsk = sk_clone_lock(sk, priority); ++ struct sock *newsk; ++ ++ newsk = sk_clone_lock(sk, priority); + + if (newsk) { + struct inet_connection_sock *newicsk = inet_csk(newsk); +@@ -854,7 +860,12 @@ + */ + while ((req = reqsk_queue_remove(queue, sk)) != NULL) { + struct sock *child = req->sk; ++ bool mutex_taken = false; + ++ if (is_meta_sk(child)) { ++ mutex_lock(&tcp_sk(child)->mpcb->mpcb_mutex); ++ mutex_taken = true; ++ } + local_bh_disable(); + bh_lock_sock(child); + WARN_ON(sock_owned_by_user(child)); +@@ -863,6 +874,8 @@ + inet_child_forget(sk, req, child); + bh_unlock_sock(child); + local_bh_enable(); ++ if (mutex_taken) ++ mutex_unlock(&tcp_sk(child)->mpcb->mpcb_mutex); + sock_put(child); + + cond_resched(); +diff -aurN linux-4.9.162/net/ipv4/ip_sockglue.c mptcp-mptcp_v0.93/net/ipv4/ip_sockglue.c +--- linux-4.9.162/net/ipv4/ip_sockglue.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/ip_sockglue.c 2019-03-14 14:02:32.000000000 +0100 +@@ -43,6 +43,8 @@ + #endif + #include + ++#include ++ + #include + #include + +@@ -734,6 +736,17 @@ + inet->tos = val; + sk->sk_priority = rt_tos2priority(val); + sk_dst_reset(sk); ++ /* Update TOS on mptcp subflow */ ++ if (is_meta_sk(sk)) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) { ++ if (inet_sk(sk_it)->tos != inet_sk(sk)->tos) { ++ inet_sk(sk_it)->tos = inet_sk(sk)->tos; ++ sk_it->sk_priority = sk->sk_priority; ++ sk_dst_reset(sk_it); ++ } ++ } ++ } + } + break; + case IP_TTL: +diff -aurN linux-4.9.162/net/ipv4/Kconfig mptcp-mptcp_v0.93/net/ipv4/Kconfig +--- linux-4.9.162/net/ipv4/Kconfig 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/Kconfig 2019-03-14 14:02:32.000000000 +0100 +@@ -655,6 +655,38 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_LIA ++ tristate "MPTCP Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Linked Increase Congestion Control ++ To enable it, just put 'lia' in tcp_congestion_control ++ ++config TCP_CONG_OLIA ++ tristate "MPTCP Opportunistic Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Opportunistic Linked Increase Congestion Control ++ To enable it, just put 'olia' in tcp_congestion_control ++ ++config TCP_CONG_WVEGAS ++ tristate "MPTCP WVEGAS CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ wVegas congestion control for MPTCP ++ To enable it, just put 'wvegas' in tcp_congestion_control ++ ++config TCP_CONG_BALIA ++ tristate "MPTCP BALIA CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ Multipath TCP Balanced Linked Adaptation Congestion Control ++ To enable it, just put 'balia' in tcp_congestion_control ++ + choice + prompt "Default TCP congestion control" + default DEFAULT_CUBIC +@@ -692,6 +724,18 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_LIA ++ bool "Lia" if TCP_CONG_LIA=y ++ ++ config DEFAULT_OLIA ++ bool "Olia" if TCP_CONG_OLIA=y ++ ++ config DEFAULT_WVEGAS ++ bool "Wvegas" if TCP_CONG_WVEGAS=y ++ ++ config DEFAULT_BALIA ++ bool "Balia" if TCP_CONG_BALIA=y ++ + config DEFAULT_RENO + bool "Reno" + endchoice +@@ -712,6 +756,10 @@ + default "vegas" if DEFAULT_VEGAS + default "westwood" if DEFAULT_WESTWOOD + default "veno" if DEFAULT_VENO ++ default "lia" if DEFAULT_LIA ++ default "olia" if DEFAULT_OLIA ++ default "wvegas" if DEFAULT_WVEGAS ++ default "balia" if DEFAULT_BALIA + default "reno" if DEFAULT_RENO + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG +diff -aurN linux-4.9.162/net/ipv4/syncookies.c mptcp-mptcp_v0.93/net/ipv4/syncookies.c +--- linux-4.9.162/net/ipv4/syncookies.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/syncookies.c 2019-03-14 14:02:32.000000000 +0100 +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + +@@ -189,7 +191,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); + +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct iphdr *iph = ip_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -219,9 +222,27 @@ + struct inet_connection_sock *icsk = inet_csk(sk); + struct sock *child; + bool own_req; ++#ifdef CONFIG_MPTCP ++ int ret; ++#endif + + child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst, + NULL, &own_req); ++ ++#ifdef CONFIG_MPTCP ++ if (!child) ++ goto listen_overflow; ++ ++ ret = mptcp_check_req_master(sk, child, req, skb, 0); ++ if (ret < 0) ++ return NULL; ++ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ ++listen_overflow: ++#endif ++ + if (child) { + atomic_set(&req->rsk_refcnt, 1); + sock_rps_save_rxhash(child, skb); +@@ -292,6 +313,7 @@ + { + struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct tcp_sock *tp = tcp_sk(sk); +@@ -320,13 +342,19 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (!cookie_timestamp_decode(&tcp_opt)) + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp_request_sock_ops, sk, false); /* for safety */ ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ + if (!req) + goto out; + +@@ -345,12 +373,17 @@ + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + treq->snt_synack.v64 = 0; + treq->tfo_listener = false; + + ireq->ir_iif = inet_request_bound_dev_if(sk, skb); + ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + /* We throwed the options of the initial SYN away, so we hope + * the ACK carries the same options again (see RFC1122 4.2.3.8) + */ +@@ -384,10 +417,10 @@ + /* Try to redo what tcp_v4_send_synack did. */ + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); + +- tcp_select_initial_window(tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(&rt->dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(&rt->dst, RTAX_INITRWND), sk); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); +diff -aurN linux-4.9.162/net/ipv4/tcp.c mptcp-mptcp_v0.93/net/ipv4/tcp.c +--- linux-4.9.162/net/ipv4/tcp.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp.c 2019-03-14 14:02:32.000000000 +0100 +@@ -272,6 +272,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -370,6 +371,24 @@ + return period; + } + ++const struct tcp_sock_ops tcp_specific = { ++ .__select_window = __tcp_select_window, ++ .select_window = tcp_select_window, ++ .select_initial_window = tcp_select_initial_window, ++ .select_size = select_size, ++ .init_buffer_space = tcp_init_buffer_space, ++ .set_rto = tcp_set_rto, ++ .should_expand_sndbuf = tcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = tcp_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .cwnd_validate = tcp_cwnd_validate, ++}; ++ + /* Address-family independent initialization for a tcp_sock. + * + * NOTE: A lot of things set to zero explicitly by call to +@@ -423,6 +442,11 @@ + sk->sk_sndbuf = sysctl_tcp_wmem[1]; + sk->sk_rcvbuf = sysctl_tcp_rmem[1]; + ++ tp->ops = &tcp_specific; ++ ++ /* Initialize MPTCP-specific stuff and function-pointers */ ++ mptcp_init_tcp_sock(sk); ++ + local_bh_disable(); + sk_sockets_allocated_inc(sk); + local_bh_enable(); +@@ -733,6 +757,7 @@ + int ret; + + sock_rps_record_flow(sk); ++ + /* + * We can't seek on a socket input + */ +@@ -743,6 +768,14 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tcp_sk(sk))) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++#endif ++ + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); + while (tss.len) { + ret = __tcp_splice_read(sk, &tss); +@@ -846,8 +879,7 @@ + return NULL; + } + +-static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, +- int large_allowed) ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, int large_allowed) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 new_size_goal, size_goal; +@@ -875,8 +907,13 @@ + { + int mss_now; + +- mss_now = tcp_current_mss(sk); +- *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ if (mptcp(tcp_sk(sk))) { ++ mss_now = mptcp_current_mss(sk); ++ *size_goal = mptcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } else { ++ mss_now = tcp_current_mss(sk); ++ *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } + + return mss_now; + } +@@ -895,12 +932,33 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto out_err; + } + ++ if (mptcp(tp)) { ++ struct sock *sk_it = sk; ++ ++ /* We must check this with socket-lock hold because we iterate ++ * over the subflows. ++ */ ++ if (!mptcp_can_sendpage(sk)) { ++ ssize_t ret; ++ ++ release_sock(sk); ++ ret = sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ lock_sock(sk); ++ return ret; ++ } ++ ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++ + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + + mss_now = tcp_send_mss(sk, &size_goal, flags); +@@ -1015,8 +1073,9 @@ + { + ssize_t res; + +- if (!(sk->sk_route_caps & NETIF_F_SG) || +- !sk_check_csum_caps(sk)) ++ /* If MPTCP is enabled, we check it later after establishment */ ++ if (!mptcp(tcp_sk(sk)) && (!(sk->sk_route_caps & NETIF_F_SG) || ++ !sk_check_csum_caps(sk))) + return sock_no_sendpage(sk->sk_socket, page, offset, size, + flags); + +@@ -1040,14 +1099,14 @@ + * This also speeds up tso_fragment(), since it wont fallback + * to tcp_fragment(). + */ +-static int linear_payload_sz(bool first_skb) ++int linear_payload_sz(bool first_skb) + { + if (first_skb) + return SKB_WITH_OVERHEAD(2048 - MAX_TCP_HEADER); + return 0; + } + +-static int select_size(const struct sock *sk, bool sg, bool first_skb) ++int select_size(const struct sock *sk, bool sg, bool first_skb) + { + const struct tcp_sock *tp = tcp_sk(sk); + int tmp = tp->mss_cache; +@@ -1135,12 +1194,19 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto do_error; + } + ++ if (mptcp(tp)) { ++ struct sock *sk_it = sk; ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++ + if (unlikely(tp->repair)) { + if (tp->repair_queue == TCP_RECV_QUEUE) { + copied = tcp_send_rcvq(sk, msg, size); +@@ -1176,7 +1242,10 @@ + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + goto do_error; + +- sg = !!(sk->sk_route_caps & NETIF_F_SG); ++ if (mptcp(tp)) ++ sg = mptcp_can_sg(sk); ++ else ++ sg = !!(sk->sk_route_caps & NETIF_F_SG); + + while (msg_data_left(msg)) { + int copy = 0; +@@ -1205,7 +1274,7 @@ + } + first_skb = skb_queue_empty(&sk->sk_write_queue); + skb = sk_stream_alloc_skb(sk, +- select_size(sk, sg, first_skb), ++ tp->ops->select_size(sk, sg, first_skb), + sk->sk_allocation, + first_skb); + if (!skb) +@@ -1214,8 +1283,15 @@ + process_backlog = true; + /* + * Check whether we can use HW checksum. ++ * ++ * If dss-csum is enabled, we do not do hw-csum. ++ * In case of non-mptcp we check the ++ * device-capabilities. ++ * In case of mptcp, hw-csum's will be handled ++ * later in mptcp_write_xmit. + */ +- if (sk_check_csum_caps(sk)) ++ if (((mptcp(tp) && !tp->mpcb->dss_csum) || !mptcp(tp)) && ++ (mptcp(tp) || sk_check_csum_caps(sk))) + skb->ip_summed = CHECKSUM_PARTIAL; + + skb_entail(sk, skb); +@@ -1424,7 +1500,7 @@ + * calculation of whether or not we must ACK for the sake of + * a window update. + */ +-static void tcp_cleanup_rbuf(struct sock *sk, int copied) ++void tcp_cleanup_rbuf(struct sock *sk, int copied) + { + struct tcp_sock *tp = tcp_sk(sk); + bool time_to_ack = false; +@@ -1467,7 +1543,7 @@ + + /* Optimize, __tcp_select_window() is not cheap. */ + if (2*rcv_window_now <= tp->window_clamp) { +- __u32 new_window = __tcp_select_window(sk); ++ __u32 new_window = tp->ops->__select_window(sk); + + /* Send ACK now, if this read freed lots of space + * in our buffer. Certainly, new_window is new window. +@@ -1597,7 +1673,7 @@ + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) { + tcp_recv_skb(sk, seq, &offset); +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + } + return copied; + } +@@ -1641,6 +1717,14 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tp)) { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tp->mpcb, sk_it) ++ sock_rps_record_flow(sk_it); ++ } ++#endif ++ + err = -ENOTCONN; + if (sk->sk_state == TCP_LISTEN) + goto out; +@@ -1761,7 +1845,7 @@ + } + } + +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) { + /* Install new reader */ +@@ -1936,7 +2020,7 @@ + */ + + /* Clean up data we have read: This will do ACK frames. */ +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + release_sock(sk); + return copied; +@@ -2014,7 +2098,7 @@ + [TCP_NEW_SYN_RECV] = TCP_CLOSE, /* should not happen ! */ + }; + +-static int tcp_close_state(struct sock *sk) ++int tcp_close_state(struct sock *sk) + { + int next = (int)new_state[sk->sk_state]; + int ns = next & TCP_STATE_MASK; +@@ -2044,7 +2128,7 @@ + TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { + /* Clear out any half completed packets. FIN if needed. */ + if (tcp_close_state(sk)) +- tcp_send_fin(sk); ++ tcp_sk(sk)->ops->send_fin(sk); + } + } + EXPORT_SYMBOL(tcp_shutdown); +@@ -2069,6 +2153,17 @@ + int data_was_unread = 0; + int state; + ++ if (is_meta_sk(sk)) { ++ /* TODO: Currently forcing timeout to 0 because ++ * sk_stream_wait_close will complain during lockdep because ++ * of the mpcb_mutex (circular lock dependency through ++ * inet_csk_listen_stop()). ++ * We should find a way to get rid of the mpcb_mutex. ++ */ ++ mptcp_close(sk, 0); ++ return; ++ } ++ + lock_sock(sk); + sk->sk_shutdown = SHUTDOWN_MASK; + +@@ -2113,7 +2208,7 @@ + /* Unread data was tossed, zap the connection. */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, sk->sk_allocation); ++ tcp_sk(sk)->ops->send_active_reset(sk, sk->sk_allocation); + } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + /* Check zero linger _after_ checking for unread data. */ + sk->sk_prot->disconnect(sk, 0); +@@ -2193,7 +2288,7 @@ + struct tcp_sock *tp = tcp_sk(sk); + if (tp->linger2 < 0) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONLINGER); + } else { +@@ -2203,7 +2298,8 @@ + inet_csk_reset_keepalive_timer(sk, + tmo - TCP_TIMEWAIT_LEN); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_FIN_WAIT2, ++ tmo); + goto out; + } + } +@@ -2212,7 +2308,7 @@ + sk_mem_reclaim(sk); + if (tcp_check_oom(sk, 0)) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { +@@ -2240,15 +2336,6 @@ + } + EXPORT_SYMBOL(tcp_close); + +-/* These states need RST on ABORT according to RFC793 */ +- +-static inline bool tcp_need_reset(int state) +-{ +- return (1 << state) & +- (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | +- TCPF_FIN_WAIT2 | TCPF_SYN_RECV); +-} +- + int tcp_disconnect(struct sock *sk, int flags) + { + struct inet_sock *inet = inet_sk(sk); +@@ -2271,7 +2358,7 @@ + /* The last check adjusts for discrepancy of Linux wrt. RFC + * states + */ +- tcp_send_active_reset(sk, gfp_any()); ++ tp->ops->send_active_reset(sk, gfp_any()); + sk->sk_err = ECONNRESET; + } else if (old_state == TCP_SYN_SENT) + sk->sk_err = ECONNRESET; +@@ -2286,6 +2373,13 @@ + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) + inet_reset_saddr(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_disconnect(sk); ++ } else { ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ + sk->sk_shutdown = 0; + sock_reset_flag(sk, SOCK_DONE); + tp->srtt_us = 0; +@@ -2329,7 +2423,8 @@ + static inline bool tcp_can_repair_sock(const struct sock *sk) + { + return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && +- ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED)); ++ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED)) && ++ !sock_flag(sk, SOCK_MPTCP); + } + + static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) +@@ -2444,6 +2539,61 @@ + release_sock(sk); + return err; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: { ++ char name[MPTCP_SCHED_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_SCHED_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_scheduler(sk, name); ++ release_sock(sk); ++ return err; ++ } ++ ++ case MPTCP_PATH_MANAGER: { ++ char name[MPTCP_PM_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_PM_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_path_manager(sk, name); ++ release_sock(sk); ++ return err; ++ } ++#endif + default: + /* fallthru */ + break; +@@ -2625,6 +2775,12 @@ + break; + + case TCP_DEFER_ACCEPT: ++ /* An established MPTCP-connection (mptcp(tp) only returns true ++ * if the socket is established) should not use DEFER on new ++ * subflows. ++ */ ++ if (mptcp(tp)) ++ break; + /* Translate value in seconds to number of retransmits */ + icsk->icsk_accept_queue.rskq_defer_accept = + secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, +@@ -2652,7 +2808,7 @@ + (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && + inet_csk_ack_scheduled(sk)) { + icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; +- tcp_cleanup_rbuf(sk, 1); ++ tp->ops->cleanup_rbuf(sk, 1); + if (!(val & 1)) + icsk->icsk_ack.pingpong = 1; + } +@@ -2661,7 +2817,7 @@ + + #ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: +- if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ++ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN) && !sock_flag(sk, SOCK_MPTCP)) + err = tp->af_specific->md5_parse(sk, optval, optlen); + else + err = -EINVAL; +@@ -2700,6 +2856,32 @@ + tp->notsent_lowat = val; + sk->sk_write_space(sk); + break; ++#ifdef CONFIG_MPTCP ++ case MPTCP_ENABLED: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE ++#ifdef CONFIG_TCP_MD5SIG ++ || tp->md5sig_info ++#endif ++ ) { ++ err = -EPERM; ++ break; ++ } ++ ++ if (val) ++ mptcp_enable_sock(sk); ++ else ++ mptcp_disable_sock(sk); ++ break; ++ case MPTCP_INFO: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled) { ++ err = -EPERM; ++ break; ++ } ++ ++ tp->record_master_info = !!(val & MPTCP_INFO_FLAG_SAVE_MASTER); ++ break; ++#endif + default: + err = -ENOPROTOOPT; + break; +@@ -3042,6 +3224,75 @@ + } + return 0; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_SCHED_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->sched_ops->name, len)) ++ return -EFAULT; ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_sched_name, ++ len)) ++ return -EFAULT; ++ } ++ return 0; ++ ++ case MPTCP_PATH_MANAGER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_PM_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->pm_ops->name, len)) ++ return -EFAULT; ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_pm_name, ++ len)) ++ return -EFAULT; ++ } ++ return 0; ++ ++ case MPTCP_ENABLED: ++ if (sk->sk_state != TCP_SYN_SENT) ++ val = mptcp(tp) ? 1 : 0; ++ else ++ val = sock_flag(sk, SOCK_MPTCP) ? 1 : 0; ++ break; ++ case MPTCP_INFO: ++ { ++ int ret; ++ ++ if (!mptcp(tp)) ++ return -EINVAL; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(struct mptcp_info)); ++ ++ lock_sock(sk); ++ ret = mptcp_get_info(sk, optval, len); ++ release_sock(sk); ++ ++ if (ret) ++ return ret; ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ return 0; ++ } ++#endif + default: + return -ENOPROTOOPT; + } +@@ -3216,7 +3467,9 @@ + if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); + ++ WARN_ON(sk->sk_state == TCP_CLOSE); + tcp_set_state(sk, TCP_CLOSE); ++ + tcp_clear_xmit_timers(sk); + if (req) + reqsk_fastopen_remove(sk, req, false); +@@ -3232,6 +3485,8 @@ + + int tcp_abort(struct sock *sk, int err) + { ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; ++ + if (!sk_fullsock(sk)) { + if (sk->sk_state == TCP_NEW_SYN_RECV) { + struct request_sock *req = inet_reqsk(sk); +@@ -3245,7 +3500,7 @@ + } + + /* Don't race with userspace socket closes such as tcp_close. */ +- lock_sock(sk); ++ lock_sock(meta_sk); + + if (sk->sk_state == TCP_LISTEN) { + tcp_set_state(sk, TCP_CLOSE); +@@ -3254,7 +3509,7 @@ + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); +- bh_lock_sock(sk); ++ bh_lock_sock(meta_sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = err; +@@ -3262,13 +3517,13 @@ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + local_bh_enable(); +- release_sock(sk); ++ release_sock(meta_sk); + return 0; + } + EXPORT_SYMBOL_GPL(tcp_abort); +diff -aurN linux-4.9.162/net/ipv4/tcp_fastopen.c mptcp-mptcp_v0.93/net/ipv4/tcp_fastopen.c +--- linux-4.9.162/net/ipv4/tcp_fastopen.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_fastopen.c 2019-03-14 14:02:32.000000000 +0100 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + int sysctl_tcp_fastopen __read_mostly = TFO_CLIENT_ENABLE; + +@@ -176,8 +177,9 @@ + { + struct tcp_sock *tp; + struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; +- struct sock *child; ++ struct sock *child, *meta_sk; + bool own_req; ++ int ret; + + req->num_retrans = 0; + req->num_timeout = 0; +@@ -216,19 +218,30 @@ + + atomic_set(&req->rsk_refcnt, 2); + +- /* Now finish processing the fastopen child socket. */ +- inet_csk(child)->icsk_af_ops->rebuild_header(child); +- tcp_init_congestion_control(child); +- tcp_mtup_init(child); +- tcp_init_metrics(child); +- tcp_init_buffer_space(child); +- + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + + tcp_fastopen_add_skb(child, skb); + + tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; + tp->rcv_wup = tp->rcv_nxt; ++ ++ meta_sk = child; ++ ret = mptcp_check_req_fastopen(meta_sk, req); ++ if (ret < 0) ++ return NULL; ++ ++ if (ret == 0) { ++ child = tcp_sk(meta_sk)->mpcb->master_sk; ++ tp = tcp_sk(child); ++ } ++ ++ /* Now finish processing the fastopen child socket. */ ++ inet_csk(child)->icsk_af_ops->rebuild_header(child); ++ tcp_init_congestion_control(child); ++ tcp_mtup_init(child); ++ tcp_init_metrics(child); ++ tp->ops->init_buffer_space(child); ++ + /* tcp_conn_request() is sending the SYNACK, + * and queues the child into listener accept queue. + */ +diff -aurN linux-4.9.162/net/ipv4/tcp_input.c mptcp-mptcp_v0.93/net/ipv4/tcp_input.c +--- linux-4.9.162/net/ipv4/tcp_input.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_input.c 2019-03-14 14:02:32.000000000 +0100 +@@ -75,6 +75,9 @@ + #include + #include + #include ++#include ++#include ++#include + + int sysctl_tcp_timestamps __read_mostly = 1; + int sysctl_tcp_window_scaling __read_mostly = 1; +@@ -101,27 +104,6 @@ + int sysctl_tcp_early_retrans __read_mostly = 3; + int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; + +-#define FLAG_DATA 0x01 /* Incoming frame contained data. */ +-#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ +-#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ +-#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +-#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ +-#define FLAG_DATA_SACKED 0x20 /* New SACK. */ +-#define FLAG_ECE 0x40 /* ECE in this ACK */ +-#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ +-#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ +-#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ +-#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ +-#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ +-#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ +-#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ +-#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ +- +-#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) +-#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) +-#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE) +-#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) +- + #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) + #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) + +@@ -329,8 +311,12 @@ + per_mss = roundup_pow_of_two(per_mss) + + SKB_DATA_ALIGN(sizeof(struct sk_buff)); + +- nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); +- nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ if (mptcp(tp)) { ++ nr_segs = mptcp_check_snd_buf(tp); ++ } else { ++ nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); ++ nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ } + + /* Fast Recovery (RFC 5681 3.2) : + * Cubic needs 1.7 factor, rounded to 2 to include +@@ -339,8 +325,16 @@ + sndmem = ca_ops->sndbuf_expand ? ca_ops->sndbuf_expand(sk) : 2; + sndmem *= nr_segs * per_mss; + +- if (sk->sk_sndbuf < sndmem) ++ /* MPTCP: after this sndmem is the new contribution of the ++ * current subflow to the aggregated sndbuf */ ++ if (sk->sk_sndbuf < sndmem) { ++ int old_sndbuf = sk->sk_sndbuf; + sk->sk_sndbuf = min(sndmem, sysctl_tcp_wmem[2]); ++ /* MPTCP: ok, the subflow sndbuf has grown, reflect ++ * this in the aggregate buffer.*/ ++ if (mptcp(tp) && old_sndbuf != sk->sk_sndbuf) ++ mptcp_update_sndbuf(tp); ++ } + } + + /* 2. Tuning advertised window (window_clamp, rcv_ssthresh) +@@ -389,10 +383,15 @@ + static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (is_meta_sk(sk)) ++ return; + + /* Check #1 */ +- if (tp->rcv_ssthresh < tp->window_clamp && +- (int)tp->rcv_ssthresh < tcp_space(sk) && ++ if (meta_tp->rcv_ssthresh < meta_tp->window_clamp && ++ (int)meta_tp->rcv_ssthresh < tcp_space(meta_sk) && + !tcp_under_memory_pressure(sk)) { + int incr; + +@@ -400,14 +399,14 @@ + * will fit to rcvbuf in future. + */ + if (tcp_win_from_space(skb->truesize) <= skb->len) +- incr = 2 * tp->advmss; ++ incr = 2 * meta_tp->advmss; + else +- incr = __tcp_grow_window(sk, skb); ++ incr = __tcp_grow_window(meta_sk, skb); + + if (incr) { + incr = max_t(int, incr, 2 * skb->len); +- tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, +- tp->window_clamp); ++ meta_tp->rcv_ssthresh = min(meta_tp->rcv_ssthresh + incr, ++ meta_tp->window_clamp); + inet_csk(sk)->icsk_ack.quick |= 1; + } + } +@@ -590,7 +589,10 @@ + int time; + + time = tcp_time_stamp - tp->rcvq_space.time; +- if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) ++ if (mptcp(tp)) { ++ if (mptcp_check_rtt(tp, time)) ++ return; ++ } else if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) + return; + + /* Number of bytes copied to user in last RTT */ +@@ -826,7 +828,7 @@ + /* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. + */ +-static void tcp_set_rto(struct sock *sk) ++void tcp_set_rto(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + /* Old crap is replaced with new one. 8) +@@ -1402,7 +1404,11 @@ + int len; + int in_sack; + +- if (!sk_can_gso(sk)) ++ /* For MPTCP we cannot shift skb-data and remove one skb from the ++ * send-queue, because this will make us loose the DSS-option (which ++ * is stored in TCP_SKB_CB(skb)->dss) of the skb we are removing. ++ */ ++ if (!sk_can_gso(sk) || mptcp(tp)) + goto fallback; + + /* Normally R but no L won't result in plain S */ +@@ -2990,7 +2996,7 @@ + */ + tcp_update_rtt_min(sk, ca_rtt_us); + tcp_rtt_estimator(sk, seq_rtt_us); +- tcp_set_rto(sk); ++ tp->ops->set_rto(sk); + + /* RFC6298: only reset backoff on valid RTT measurement. */ + inet_csk(sk)->icsk_backoff = 0; +@@ -3075,7 +3081,7 @@ + } + + /* If we get here, the whole TSO packet has not been acked. */ +-static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 packets_acked; +@@ -3198,6 +3204,8 @@ + */ + if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { + flag |= FLAG_DATA_ACKED; ++ if (mptcp(tp) && mptcp_is_data_seq(skb)) ++ flag |= MPTCP_FLAG_DATA_ACKED; + } else { + flag |= FLAG_SYN_ACKED; + tp->retrans_stamp = 0; +@@ -3308,7 +3316,7 @@ + return flag; + } + +-static void tcp_ack_probe(struct sock *sk) ++void tcp_ack_probe(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -3378,9 +3386,8 @@ + /* Check that window update is acceptable. + * The function assumes that snd_una<=ack<=snd_next. + */ +-static inline bool tcp_may_update_window(const struct tcp_sock *tp, +- const u32 ack, const u32 ack_seq, +- const u32 nwin) ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin) + { + return after(ack, tp->snd_una) || + after(ack_seq, tp->snd_wl1) || +@@ -3604,7 +3611,7 @@ + } + + /* This routine deals with incoming acks, but not outgoing ones. */ +-static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) ++static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -3718,6 +3725,16 @@ + flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked, + &sack_state, &now); + ++ if (mptcp(tp)) { ++ if (mptcp_fallback_infinite(sk, flag)) { ++ pr_err("%s resetting flow\n", __func__); ++ mptcp_send_reset(sk); ++ goto invalid_ack; ++ } ++ ++ mptcp_clean_rtx_infinite(skb, sk); ++ } ++ + if (tcp_ack_is_dubious(sk, flag)) { + is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); + tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit); +@@ -3796,8 +3813,10 @@ + * the fast version below fails. + */ + void tcp_parse_options(const struct sk_buff *skb, +- struct tcp_options_received *opt_rx, int estab, +- struct tcp_fastopen_cookie *foc) ++ struct tcp_options_received *opt_rx, ++ struct mptcp_options_received *mopt, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp) + { + const unsigned char *ptr; + const struct tcphdr *th = tcp_hdr(skb); +@@ -3880,6 +3899,10 @@ + */ + break; + #endif ++ case TCPOPT_MPTCP: ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, tp); ++ break; ++ + case TCPOPT_FASTOPEN: + tcp_parse_fastopen_option( + opsize - TCPOLEN_FASTOPEN_BASE, +@@ -3942,8 +3965,8 @@ + if (tcp_parse_aligned_timestamp(tp, th)) + return true; + } +- +- tcp_parse_options(skb, &tp->rx_opt, 1, NULL); ++ tcp_parse_options(skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : NULL, 1, NULL, tp); + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -4099,6 +4122,11 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_fin(sk); ++ return; ++ } ++ + inet_csk_schedule_ack(sk); + + sk->sk_shutdown |= RCV_SHUTDOWN; +@@ -4109,6 +4137,10 @@ + case TCP_ESTABLISHED: + /* Move to CLOSE_WAIT */ + tcp_set_state(sk, TCP_CLOSE_WAIT); ++ ++ if (mptcp(tp)) ++ mptcp_sub_close_passive(sk); ++ + inet_csk(sk)->icsk_ack.pingpong = 1; + break; + +@@ -4131,9 +4163,16 @@ + tcp_set_state(sk, TCP_CLOSING); + break; + case TCP_FIN_WAIT2: ++ if (mptcp(tp)) { ++ /* The socket will get closed by mptcp_data_ready. ++ * We first have to process all data-sequences. ++ */ ++ tp->close_it = 1; ++ break; ++ } + /* Received a FIN -- send ACK and enter TIME_WAIT. */ + tcp_send_ack(sk); +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + break; + default: + /* Only TCP_LISTEN and TCP_CLOSE are left, in these +@@ -4155,6 +4194,10 @@ + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + ++ /* Don't wake up MPTCP-subflows */ ++ if (mptcp(tp)) ++ return; ++ + /* Do not send POLL_HUP for half duplex close. */ + if (sk->sk_shutdown == SHUTDOWN_MASK || + sk->sk_state == TCP_CLOSE) +@@ -4345,15 +4388,16 @@ + * Better try to coalesce them right now to avoid future collapses. + * Returns true if caller should free @from instead of queueing it + */ +-static bool tcp_try_coalesce(struct sock *sk, +- struct sk_buff *to, +- struct sk_buff *from, +- bool *fragstolen) ++bool tcp_try_coalesce(struct sock *sk, struct sk_buff *to, struct sk_buff *from, ++ bool *fragstolen) + { + int delta; + + *fragstolen = false; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk)) ++ return false; ++ + /* Its possible this segment overlaps with prior segment in queue */ + if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) + return false; +@@ -4396,7 +4440,7 @@ + /* This one checks to see if we can put data from the + * out_of_order queue into the receive_queue. + */ +-static void tcp_ofo_queue(struct sock *sk) ++void tcp_ofo_queue(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + __u32 dsack_high = tp->rcv_nxt; +@@ -4419,7 +4463,14 @@ + p = rb_next(p); + rb_erase(&skb->rbnode, &tp->out_of_order_queue); + +- if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { ++ /* In case of MPTCP, the segment may be empty if it's a ++ * non-data DATA_FIN. (see beginning of tcp_data_queue) ++ * ++ * But this only holds true for subflows, not for the ++ * meta-socket. ++ */ ++ if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt) && ++ (is_meta_sk(sk) || !mptcp(tp) || TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq))) { + SOCK_DEBUG(sk, "ofo packet was already received\n"); + tcp_drop(sk, skb); + continue; +@@ -4453,6 +4504,9 @@ + static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, + unsigned int size) + { ++ if (mptcp(tcp_sk(sk))) ++ sk = mptcp_meta_sk(sk); ++ + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule(sk, skb, size)) { + +@@ -4467,7 +4521,7 @@ + return 0; + } + +-static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + struct rb_node **p, *parent; +@@ -4535,7 +4589,8 @@ + continue; + } + if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { +- if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq) && ++ (is_meta_sk(sk) || !mptcp(tp) || end_seq != seq)) { + /* All the bits are present. Drop. */ + NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPOFOMERGE); +@@ -4582,6 +4637,11 @@ + end_seq); + break; + } ++ /* MPTCP allows non-data data-fin to be in the ofo-queue */ ++ if (mptcp(tp) && !is_meta_sk(sk) && TCP_SKB_CB(skb1)->seq == TCP_SKB_CB(skb1)->end_seq) { ++ skb = skb1; ++ continue; ++ } + rb_erase(&skb1->rbnode, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); +@@ -4593,7 +4653,7 @@ + tp->ooo_last_skb = skb; + + add_sack: +- if (tcp_is_sack(tp)) ++ if (tcp_is_sack(tp) && seq != end_seq) + tcp_sack_new_ofo_skb(sk, seq, end_seq); + end: + if (skb) { +@@ -4602,8 +4662,8 @@ + } + } + +-static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, +- bool *fragstolen) ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, ++ bool *fragstolen) + { + int eaten; + struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); +@@ -4675,10 +4735,14 @@ + bool fragstolen = false; + int eaten = -1; + +- if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { ++ /* If no data is present, but a data_fin is in the options, we still ++ * have to call mptcp_queue_skb later on. */ ++ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && ++ !(mptcp(tp) && mptcp_is_data_fin(skb))) { + __kfree_skb(skb); + return; + } ++ + skb_dst_drop(skb); + __skb_pull(skb, tcp_hdr(skb)->doff * 4); + +@@ -4722,7 +4786,7 @@ + eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); + } + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); +- if (skb->len) ++ if (skb->len || mptcp_is_data_fin(skb)) + tcp_event_data_recv(sk, skb); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) + tcp_fin(sk); +@@ -4744,7 +4808,11 @@ + + if (eaten > 0) + kfree_skb_partial(skb, fragstolen); +- if (!sock_flag(sk, SOCK_DEAD)) ++ if (!sock_flag(sk, SOCK_DEAD) || mptcp(tp)) ++ /* MPTCP: we always have to call data_ready, because ++ * we may be about to receive a data-fin, which still ++ * must get queued. ++ */ + sk->sk_data_ready(sk); + return; + } +@@ -5083,7 +5151,29 @@ + return -1; + } + +-static bool tcp_should_expand_sndbuf(const struct sock *sk) ++/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. ++ * As additional protections, we do not touch cwnd in retransmission phases, ++ * and if application hit its sndbuf limit recently. ++ */ ++void tcp_cwnd_application_limited(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open && ++ sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ /* Limited by application or receiver window. */ ++ u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); ++ u32 win_used = max(tp->snd_cwnd_used, init_win); ++ if (win_used < tp->snd_cwnd) { ++ tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1; ++ } ++ tp->snd_cwnd_used = 0; ++ } ++ tp->snd_cwnd_stamp = tcp_time_stamp; ++} ++ ++bool tcp_should_expand_sndbuf(const struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + +@@ -5118,7 +5208,7 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + +- if (tcp_should_expand_sndbuf(sk)) { ++ if (tp->ops->should_expand_sndbuf(sk)) { + tcp_sndbuf_expand(sk); + tp->snd_cwnd_stamp = tcp_time_stamp; + } +@@ -5132,8 +5222,9 @@ + sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); + /* pairs with tcp_poll() */ + smp_mb(); +- if (sk->sk_socket && +- test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) ++ if (mptcp(tcp_sk(sk)) || ++ (sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))) + tcp_new_space(sk); + } + } +@@ -5156,7 +5247,7 @@ + /* ... and right edge of window advances far enough. + * (tcp_recvmsg() will send ACK otherwise). Or... + */ +- __tcp_select_window(sk) >= tp->rcv_wnd) || ++ tp->ops->__select_window(sk) >= tp->rcv_wnd) || + /* We ACK each frame or... */ + tcp_in_quickack_mode(sk) || + /* We have out of order data. */ +@@ -5258,6 +5349,10 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ /* MPTCP urgent data is not yet supported */ ++ if (mptcp(tp)) ++ return; ++ + /* Check if we get a new urgent pointer - normally not. */ + if (th->urg) + tcp_check_urg(sk, th); +@@ -5389,9 +5484,15 @@ + goto discard; + } + ++ /* If valid: post process the received MPTCP options. */ ++ if (mptcp(tp) && mptcp_handle_options(sk, th, skb)) ++ goto discard; ++ + return true; + + discard: ++ if (mptcp(tp)) ++ mptcp_reset_mopt(tp); + tcp_drop(sk, skb); + return false; + } +@@ -5443,6 +5544,10 @@ + + tp->rx_opt.saw_tstamp = 0; + ++ /* MPTCP: force slowpath. */ ++ if (mptcp(tp)) ++ goto slow_path; ++ + /* pred_flags is 0xS?10 << 16 + snd_wnd + * if header_prediction is to be made + * 'S' will always be tp->tcp_header_len >> 2 +@@ -5640,7 +5745,7 @@ + */ + tp->lsndtime = tcp_time_stamp; + +- tcp_init_buffer_space(sk); ++ tp->ops->init_buffer_space(sk); + + if (sock_flag(sk, SOCK_KEEPOPEN)) + inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp)); +@@ -5656,7 +5761,8 @@ + struct tcp_fastopen_cookie *cookie) + { + struct tcp_sock *tp = tcp_sk(sk); +- struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(meta_sk) : NULL; + u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; + bool syn_drop = false; + +@@ -5666,7 +5772,7 @@ + /* Get original SYNACK MSS value if user MSS sets mss_clamp */ + tcp_clear_options(&opt); + opt.user_mss = opt.mss_clamp = 0; +- tcp_parse_options(synack, &opt, 0, NULL); ++ tcp_parse_options(synack, &opt, NULL, 0, NULL, NULL); + mss = opt.mss_clamp; + } + +@@ -5690,7 +5796,11 @@ + + tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); + +- if (data) { /* Retransmit unacked data in SYN */ ++ /* In mptcp case, we do not rely on "retransmit", but instead on ++ * "transmit", because if fastopen data is not acked, the retransmission ++ * becomes the first MPTCP data (see mptcp_rcv_synsent_fastopen). ++ */ ++ if (data && !mptcp(tp)) { /* Retransmit unacked data in SYN */ + tcp_for_write_queue_from(data, sk) { + if (data == tcp_send_head(sk) || + __tcp_retransmit_skb(sk, data, 1)) +@@ -5718,9 +5828,13 @@ + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_fastopen_cookie foc = { .len = -1 }; + int saved_clamp = tp->rx_opt.mss_clamp; ++ struct mptcp_options_received mopt; + bool fastopen_fail; + +- tcp_parse_options(skb, &tp->rx_opt, 0, &foc); ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : &mopt, 0, &foc, tp); + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -5780,6 +5894,35 @@ + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + tcp_ack(sk, skb, FLAG_SLOWPATH); + ++ if (tp->request_mptcp || mptcp(tp)) { ++ int ret; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ ret = mptcp_rcv_synsent_state_process(sk, &sk, ++ skb, &mopt); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ /* May have changed if we support MPTCP */ ++ tp = tcp_sk(sk); ++ icsk = inet_csk(sk); ++ ++ if (ret == 1) ++ goto reset_and_undo; ++ if (ret == 2) ++ goto discard; ++ } ++ ++ if (mptcp(tp) && !is_master_tp(tp)) { ++ /* Timer for repeating the ACK until an answer ++ * arrives. Used only when establishing an additional ++ * subflow inside of an MPTCP connection. ++ */ ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ } ++ + /* Ok.. it's good. Set up sequence numbers and + * move to established. + */ +@@ -5806,6 +5949,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + if (tcp_is_sack(tp) && sysctl_tcp_fack) + tcp_enable_fack(tp); + +@@ -5831,9 +5979,12 @@ + } + if (fastopen_fail) + return -1; +- if (sk->sk_write_pending || ++ /* With MPTCP we cannot send data on the third ack due to the ++ * lack of option-space to combine with an MP_CAPABLE. ++ */ ++ if (!mptcp(tp) && (sk->sk_write_pending || + icsk->icsk_accept_queue.rskq_defer_accept || +- icsk->icsk_ack.pingpong) { ++ icsk->icsk_ack.pingpong)) { + /* Save one ACK. Data will be ready after + * several ticks, if write_pending is set. + * +@@ -5872,6 +6023,7 @@ + tcp_paws_reject(&tp->rx_opt, 0)) + goto discard_and_undo; + ++ /* TODO - check this here for MPTCP */ + if (th->syn) { + /* We see SYN without ACK. It is attempt of + * simultaneous connect with crossed SYNs. +@@ -5888,6 +6040,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + tp->copied_seq = tp->rcv_nxt; + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; +@@ -5946,6 +6103,7 @@ + */ + + int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) ++ __releases(&sk->sk_lock.slock) + { + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -5987,6 +6145,16 @@ + case TCP_SYN_SENT: + tp->rx_opt.saw_tstamp = 0; + queued = tcp_rcv_synsent_state_process(sk, skb, th); ++ if (is_meta_sk(sk)) { ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ tp = tcp_sk(sk); ++ ++ /* Need to call it here, because it will announce new ++ * addresses, which can only be done after the third ack ++ * of the 3-way handshake. ++ */ ++ mptcp_update_metasocket(tp->meta_sk); ++ } + if (queued >= 0) + return queued; + +@@ -6042,7 +6210,7 @@ + + tcp_mtup_init(sk); + tp->copied_seq = tp->rcv_nxt; +- tcp_init_buffer_space(sk); ++ tp->ops->init_buffer_space(sk); + } + smp_mb(); + tcp_set_state(sk, TCP_ESTABLISHED); +@@ -6061,6 +6229,8 @@ + + if (tp->rx_opt.tstamp_ok) + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; ++ if (mptcp(tp)) ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; + + if (req) { + /* Re-arm the timer because data may have been sent out. +@@ -6083,6 +6253,30 @@ + + tcp_initialize_rcv_mss(sk); + tcp_fast_path_on(tp); ++ ++ /* Send an ACK when establishing a new MPTCP subflow, i.e. ++ * using an MP_JOIN subtype. ++ */ ++ if (mptcp(tp)) { ++ if (is_master_tp(tp)) { ++ mptcp_update_metasocket(mptcp_meta_sk(sk)); ++ } else { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ tcp_send_ack(sk); ++ ++ /* Update RTO as it might be worse/better */ ++ mptcp_set_rto(sk); ++ ++ /* If the new RTO would fire earlier, pull it in! */ ++ if (tcp_sk(meta_sk)->packets_out && ++ icsk->icsk_timeout > inet_csk(meta_sk)->icsk_rto + jiffies) { ++ tcp_rearm_rto(meta_sk); ++ } ++ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++ } ++ } + break; + + case TCP_FIN_WAIT1: { +@@ -6126,7 +6320,8 @@ + tmo = tcp_fin_time(sk); + if (tmo > TCP_TIMEWAIT_LEN) { + inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); +- } else if (th->fin || sock_owned_by_user(sk)) { ++ } else if (th->fin || mptcp_is_data_fin(skb) || ++ sock_owned_by_user(sk)) { + /* Bad case. We could lose such FIN otherwise. + * It is not a big problem, but it looks confusing + * and not so rare event. We still can lose it now, +@@ -6135,7 +6330,7 @@ + */ + inet_csk_reset_keepalive_timer(sk, tmo); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto discard; + } + break; +@@ -6143,7 +6338,7 @@ + + case TCP_CLOSING: + if (tp->snd_una == tp->write_seq) { +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + goto discard; + } + break; +@@ -6155,6 +6350,9 @@ + goto discard; + } + break; ++ case TCP_CLOSE: ++ if (tp->mp_killed) ++ goto discard; + } + + /* step 6: check the URG bit */ +@@ -6175,7 +6373,8 @@ + */ + if (sk->sk_shutdown & RCV_SHUTDOWN) { + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && +- after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp(tp)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); + tcp_reset(sk); + return 1; +@@ -6271,6 +6470,8 @@ + ireq->wscale_ok = rx_opt->wscale_ok; + ireq->acked = 0; + ireq->ecn_ok = 0; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + ireq->ir_rmt_port = tcp_hdr(skb)->source; + ireq->ir_num = ntohs(tcp_hdr(skb)->dest); + ireq->ir_mark = inet_request_mark(sk, skb); +@@ -6366,12 +6567,17 @@ + /* TW buckets are converted to open requests without + * limitations, they conserve resources and peer is + * evidently real one. ++ * ++ * MPTCP: new subflows cannot be established in a stateless manner. + */ +- if ((net->ipv4.sysctl_tcp_syncookies == 2 || ++ if (((!is_meta_sk(sk) && net->ipv4.sysctl_tcp_syncookies == 2) || + inet_csk_reqsk_queue_is_full(sk)) && !isn) { + want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); + if (!want_cookie) + goto drop; ++ ++ if (is_meta_sk(sk)) ++ goto drop; + } + + +@@ -6394,7 +6600,7 @@ + tcp_clear_options(&tmp_opt); + tmp_opt.mss_clamp = af_ops->mss_clamp; + tmp_opt.user_mss = tp->rx_opt.user_mss; +- tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); ++ tcp_parse_options(skb, &tmp_opt, NULL, 0, want_cookie ? NULL : &foc, NULL); + + if (want_cookie && !tmp_opt.saw_tstamp) + tcp_clear_options(&tmp_opt); +@@ -6406,7 +6612,8 @@ + /* Note: tcp_v6_init_req() might override ir_iif for link locals */ + inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); + +- af_ops->init_req(req, sk, skb); ++ if (af_ops->init_req(req, sk, skb, want_cookie)) ++ goto drop_and_free; + + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_free; +@@ -6462,7 +6669,7 @@ + tcp_ecn_create_request(req, skb, sk, dst); + + if (want_cookie) { +- isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); ++ isn = cookie_init_sequence(af_ops, req, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + if (!tmp_opt.tstamp_ok) + inet_rsk(req)->ecn_ok = 0; +@@ -6476,12 +6683,18 @@ + fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); + } + if (fastopen_sk) { ++ struct sock *meta_sk = fastopen_sk; ++ ++ if (mptcp(tcp_sk(fastopen_sk))) ++ meta_sk = mptcp_meta_sk(fastopen_sk); + af_ops->send_synack(fastopen_sk, dst, &fl, req, + &foc, TCP_SYNACK_FASTOPEN); + /* Add the child socket directly into the accept queue */ +- inet_csk_reqsk_queue_add(sk, req, fastopen_sk); ++ inet_csk_reqsk_queue_add(sk, req, meta_sk); + sk->sk_data_ready(sk); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + } else { + tcp_rsk(req)->tfo_listener = false; +diff -aurN linux-4.9.162/net/ipv4/tcp_ipv4.c mptcp-mptcp_v0.93/net/ipv4/tcp_ipv4.c +--- linux-4.9.162/net/ipv4/tcp_ipv4.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_ipv4.c 2019-03-14 14:02:32.000000000 +0100 +@@ -67,6 +67,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -362,7 +364,7 @@ + struct inet_sock *inet; + const int type = icmp_hdr(icmp_skb)->type; + const int code = icmp_hdr(icmp_skb)->code; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + struct sk_buff *skb; + struct request_sock *fastopen; + __u32 seq, snd_una; +@@ -390,13 +392,19 @@ + (code == ICMP_NET_UNREACH || + code == ICMP_HOST_UNREACH))); + +- bh_lock_sock(sk); ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); + /* If too many ICMPs get dropped on busy + * servers this needs to be solved differently. + * We do take care of PMTU discovery (RFC1191) special case : + * we can receive locally generated ICMP messages while socket is held. + */ +- if (sock_owned_by_user(sk)) { ++ if (sock_owned_by_user(meta_sk)) { + if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + } +@@ -409,7 +417,6 @@ + } + + icsk = inet_csk(sk); +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -443,11 +450,13 @@ + goto out; + + tp->mtu_info = info; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v4_mtu_reduced(sk); + } else { + if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } + goto out; + } +@@ -461,7 +470,7 @@ + !icsk->icsk_backoff || fastopen) + break; + +- if (sock_owned_by_user(sk)) ++ if (sock_owned_by_user(meta_sk)) + break; + + skb = tcp_write_queue_head(sk); +@@ -483,7 +492,7 @@ + } else { + /* RTO revert clocked out retransmission. + * Will retransmit now */ +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + } + + break; +@@ -503,7 +512,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + + sk->sk_error_report(sk); +@@ -532,7 +541,7 @@ + */ + + inet = inet_sk(sk); +- if (!sock_owned_by_user(sk) && inet->recverr) { ++ if (!sock_owned_by_user(meta_sk) && inet->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else { /* Only an error on timeout */ +@@ -540,7 +549,7 @@ + } + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -582,7 +591,7 @@ + * Exception: precedence violation. We do not implement it in any case. + */ + +-static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -717,10 +726,10 @@ + */ + + static void tcp_v4_send_ack(struct net *net, +- struct sk_buff *skb, u32 seq, u32 ack, ++ struct sk_buff *skb, u32 seq, u32 ack, u32 data_ack, + u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, +- int reply_flags, u8 tos) ++ int reply_flags, u8 tos, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -729,6 +738,10 @@ + #ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) + #endif ++#ifdef CONFIG_MPTCP ++ + ((MPTCP_SUB_LEN_DSS >> 2) + ++ (MPTCP_SUB_LEN_ACK >> 2)) ++#endif + ]; + } rep; + struct ip_reply_arg arg; +@@ -772,6 +785,21 @@ + ip_hdr(skb)->daddr, &rep.th); + } + #endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ int offset = (tsecr) ? 3 : 0; ++ /* Construction of 32-bit data_ack */ ++ rep.opt[offset++] = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ rep.opt[offset] = htonl(data_ack); ++ ++ arg.iov[0].iov_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++ rep.th.doff = arg.iov[0].iov_len / 4; ++ } ++#endif /* CONFIG_MPTCP */ ++ + arg.flags = reply_flags; + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, /* XXX */ +@@ -794,28 +822,36 @@ + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; ++ ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + + tcp_v4_send_ack(sock_net(sk), skb, +- tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, + tw->tw_bound_dev_if, + tcp_twsk_md5_key(tcptw), + tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, +- tw->tw_tos ++ tw->tw_tos, mptcp + ); + + inet_twsk_put(tw); + } + +-static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. + */ +- u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : ++ u32 seq = (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? ++ tcp_rsk(req)->snt_isn + 1 : + tcp_sk(sk)->snd_nxt; + + /* RFC 7323 2.3 +@@ -824,7 +860,7 @@ + * Rcv.Wind.Shift bits: + */ + tcp_v4_send_ack(sock_net(sk), skb, seq, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp, + req->ts_recent, +@@ -832,7 +868,7 @@ + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, + AF_INET), + inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, +- ip_hdr(skb)->tos); ++ ip_hdr(skb)->tos, 0); + } + + /* +@@ -840,11 +876,11 @@ + * This still operates on a request_sock only, not on a big + * socket. + */ +-static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, +- struct flowi *fl, +- struct request_sock *req, +- struct tcp_fastopen_cookie *foc, +- enum tcp_synack_type synack_type) ++int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, ++ struct flowi *fl, ++ struct request_sock *req, ++ struct tcp_fastopen_cookie *foc, ++ enum tcp_synack_type synack_type) + { + const struct inet_request_sock *ireq = inet_rsk(req); + struct flowi4 fl4; +@@ -874,7 +910,7 @@ + /* + * IPv4 request_sock destructor. + */ +-static void tcp_v4_reqsk_destructor(struct request_sock *req) ++void tcp_v4_reqsk_destructor(struct request_sock *req) + { + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + } +@@ -1194,15 +1230,18 @@ + return false; + } + +-static void tcp_v4_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v4_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + struct inet_request_sock *ireq = inet_rsk(req); + + sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); + sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(skb)); ++ ++ return 0; + } + + static struct dst_entry *tcp_v4_route_req(const struct sock *sk, +@@ -1232,7 +1271,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { + .mss_clamp = TCP_MSS_DEFAULT, + #ifdef CONFIG_TCP_MD5SIG + .req_md5_lookup = tcp_v4_md5_lookup, +@@ -1371,7 +1410,7 @@ + } + EXPORT_SYMBOL(tcp_v4_syn_recv_sock); + +-static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1394,6 +1433,9 @@ + { + struct sock *rsk; + ++ if (is_meta_sk(sk)) ++ return mptcp_v4_do_rcv(sk, skb); ++ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst = sk->sk_rx_dst; + +@@ -1537,7 +1579,7 @@ + } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { + wake_up_interruptible_sync_poll(sk_sleep(sk), + POLLIN | POLLRDNORM | POLLRDBAND); +- if (!inet_csk_ack_scheduled(sk)) ++ if (!inet_csk_ack_scheduled(sk) && !mptcp(tp)) + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + (3 * tcp_rto_min(sk)) / 4, + TCP_RTO_MAX); +@@ -1598,8 +1640,8 @@ + struct net *net = dev_net(skb->dev); + const struct iphdr *iph; + const struct tcphdr *th; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + + if (skb->pkt_type != PACKET_HOST) +@@ -1639,6 +1681,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff * 4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); +@@ -1668,7 +1714,7 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } +@@ -1677,13 +1723,47 @@ + */ + sock_hold(sk); + refcounted = true; ++ ++ if (is_meta_sk(sk)) { ++ bh_lock_sock(sk); ++ ++ if (!mptcp_can_new_subflow(sk)) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ bh_unlock_sock(sk); ++ ++ goto discard_and_relse; ++ } ++ ++ if (sock_owned_by_user(sk)) { ++ mptcp_prepare_for_backlog(sk, skb); ++ if (unlikely(sk_add_backlog(sk, skb, ++ sk->sk_rcvbuf + sk->sk_sndbuf))) { ++ reqsk_put(req); ++ ++ bh_unlock_sock(sk); ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ goto discard_and_relse; ++ } ++ ++ reqsk_put(req); ++ bh_unlock_sock(sk); ++ sock_put(sk); ++ ++ return 0; ++ } ++ } ++ + nsk = tcp_check_req(sk, skb, req, false); + if (!nsk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + goto discard_and_relse; + } + if (nsk == sk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + } else if (tcp_child_process(sk, nsk, skb)) { + tcp_v4_send_reset(nsk, skb); + goto discard_and_relse; +@@ -1719,16 +1799,25 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { +- if (!tcp_prequeue(sk, skb)) ++ if (!sock_owned_by_user(meta_sk)) { ++ if (!tcp_prequeue(meta_sk, skb)) + ret = tcp_v4_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1740,6 +1829,19 @@ + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard_it; + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1784,6 +1886,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + /* Fall through to ACK */ + } + case TCP_TW_ACK: +@@ -1853,7 +1967,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; +@@ -1870,6 +1989,11 @@ + + tcp_cleanup_congestion_control(sk); + ++ if (mptcp(tp)) ++ mptcp_destroy_sock(sk); ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ + /* Cleanup up the write buffer. */ + tcp_write_queue_purge(sk); + +@@ -2415,6 +2539,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + EXPORT_SYMBOL(tcp_prot); + +diff -aurN linux-4.9.162/net/ipv4/tcp_minisocks.c mptcp-mptcp_v0.93/net/ipv4/tcp_minisocks.c +--- linux-4.9.162/net/ipv4/tcp_minisocks.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_minisocks.c 2019-03-14 14:02:32.000000000 +0100 +@@ -18,11 +18,13 @@ + * Jorge Cwik, + */ + ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -100,10 +102,14 @@ + struct tcp_options_received tmp_opt; + struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); + bool paws_reject = false; ++ struct mptcp_options_received mopt; + + tmp_opt.saw_tstamp = 0; +- if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { +- tcp_parse_options(skb, &tmp_opt, 0, NULL); ++ if (th->doff > (sizeof(*th) >> 2) && ++ (tcptw->tw_ts_recent_stamp || tcptw->mptcp_tw)) { ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; +@@ -111,6 +117,11 @@ + tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; + paws_reject = tcp_paws_reject(&tmp_opt, th->rst); + } ++ ++ if (unlikely(mopt.mp_fclose) && tcptw->mptcp_tw) { ++ if (mopt.mptcp_sender_key == tcptw->mptcp_tw->loc_key) ++ return TCP_TW_RST; ++ } + } + + if (tw->tw_substate == TCP_FIN_WAIT2) { +@@ -134,6 +145,16 @@ + if (!th->ack || + !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) || + TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { ++ /* If mptcp_is_data_fin() returns true, we are sure that ++ * mopt has been initialized - otherwise it would not ++ * be a DATA_FIN. ++ */ ++ if (tcptw->mptcp_tw && tcptw->mptcp_tw->meta_tw && ++ mptcp_is_data_fin(skb) && ++ TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt && ++ mopt.data_seq + 1 == (u32)tcptw->mptcp_tw->rcv_nxt) ++ return TCP_TW_ACK; ++ + inet_twsk_put(tw); + return TCP_TW_SUCCESS; + } +@@ -286,6 +307,15 @@ + tcptw->tw_ts_offset = tp->tsoffset; + tcptw->tw_last_oow_ack_time = 0; + ++ if (mptcp(tp)) { ++ if (mptcp_init_tw_sock(sk, tcptw)) { ++ inet_twsk_free(tw); ++ goto exit; ++ } ++ } else { ++ tcptw->mptcp_tw = NULL; ++ } ++ + #if IS_ENABLED(CONFIG_IPV6) + if (tw->tw_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -347,15 +377,18 @@ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); + } + ++exit: + tcp_update_metrics(sk); + tcp_done(sk); + } + + void tcp_twsk_destructor(struct sock *sk) + { +-#ifdef CONFIG_TCP_MD5SIG + struct tcp_timewait_sock *twsk = tcp_twsk(sk); + ++ if (twsk->mptcp_tw) ++ mptcp_twsk_destructor(twsk); ++#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_key) + kfree_rcu(twsk->tw_md5_key, rcu); + #endif +@@ -390,13 +423,14 @@ + req->rsk_window_clamp = full_space; + + /* tcp_full_space because it is guaranteed to be the first packet */ +- tcp_select_initial_window(full_space, +- mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), ++ tp->ops->select_initial_window(tcp_full_space(sk_listener), ++ mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) - ++ (ireq->saw_mpc ? MPTCP_SUB_LEN_DSM_ALIGN : 0), + &req->rsk_rcv_wnd, + &req->rsk_window_clamp, + ireq->wscale_ok, + &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ dst_metric(dst, RTAX_INITRWND), sk_listener); + ireq->rcv_wscale = rcv_wscale; + } + EXPORT_SYMBOL(tcp_openreq_init_rwin); +@@ -540,6 +574,8 @@ + newtp->rx_opt.ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } ++ if (ireq->saw_mpc) ++ newtp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; + newtp->tsoffset = 0; + #ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ +@@ -578,6 +614,7 @@ + bool fastopen) + { + struct tcp_options_received tmp_opt; ++ struct mptcp_options_received mopt; + struct sock *child; + const struct tcphdr *th = tcp_hdr(skb); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); +@@ -585,8 +622,11 @@ + bool own_req; + + tmp_opt.saw_tstamp = 0; ++ ++ mptcp_init_mp_opt(&mopt); ++ + if (th->doff > (sizeof(struct tcphdr)>>2)) { +- tcp_parse_options(skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + tmp_opt.ts_recent = req->ts_recent; +@@ -625,7 +665,14 @@ + * + * Reset timer after retransmitting SYNACK, similar to + * the idea of fast retransmit in recovery. ++ * ++ * Fall back to TCP if MP_CAPABLE is not set. + */ ++ ++ if (inet_rsk(req)->saw_mpc && !mopt.saw_mpc) ++ inet_rsk(req)->saw_mpc = false; ++ ++ + if (!tcp_oow_rate_limited(sock_net(sk), skb, + LINUX_MIB_TCPACKSKIPPEDSYNRECV, + &tcp_rsk(req)->last_oow_ack_time) && +@@ -778,6 +825,18 @@ + if (!child) + goto listen_overflow; + ++ if (own_req && !is_meta_sk(sk)) { ++ int ret = mptcp_check_req_master(sk, child, req, skb, 1); ++ if (ret < 0) ++ goto listen_overflow; ++ ++ /* MPTCP-supported */ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ } else if (own_req) { ++ return mptcp_check_req_child(sk, child, req, skb, &mopt); ++ } ++ + sock_rps_save_rxhash(child, skb); + tcp_synack_rtt_meas(child, req); + return inet_csk_complete_hashdance(sk, child, req, own_req); +@@ -825,9 +884,10 @@ + { + int ret = 0; + int state = child->sk_state; ++ struct sock *meta_sk = mptcp(tcp_sk(child)) ? mptcp_meta_sk(child) : child; + + tcp_segs_in(tcp_sk(child), skb); +- if (!sock_owned_by_user(child)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_rcv_state_process(child, skb); + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && child->sk_state != state) +@@ -837,10 +897,14 @@ + * in main socket hash table and lock on listening + * socket does not protect us more. + */ +- __sk_add_backlog(child, skb); ++ if (mptcp(tcp_sk(child))) ++ mptcp_prepare_for_backlog(child, skb); ++ __sk_add_backlog(meta_sk, skb); + } + +- bh_unlock_sock(child); ++ if (mptcp(tcp_sk(child))) ++ bh_unlock_sock(child); ++ bh_unlock_sock(meta_sk); + sock_put(child); + return ret; + } +diff -aurN linux-4.9.162/net/ipv4/tcp_output.c mptcp-mptcp_v0.93/net/ipv4/tcp_output.c +--- linux-4.9.162/net/ipv4/tcp_output.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_output.c 2019-03-14 14:02:32.000000000 +0100 +@@ -36,6 +36,12 @@ + + #define pr_fmt(fmt) "TCP: " fmt + ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++#include + #include + + #include +@@ -62,11 +68,8 @@ + /* By default, RFC2861 behavior. */ + int sysctl_tcp_slow_start_after_idle __read_mostly = 1; + +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, +- int push_one, gfp_t gfp); +- + /* Account for new data that has been sent to the network. */ +-static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) ++void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -210,7 +213,7 @@ + void tcp_select_initial_window(int __space, __u32 mss, + __u32 *rcv_wnd, __u32 *window_clamp, + int wscale_ok, __u8 *rcv_wscale, +- __u32 init_rcv_wnd) ++ __u32 init_rcv_wnd, const struct sock *sk) + { + unsigned int space = (__space < 0 ? 0 : __space); + +@@ -266,12 +269,16 @@ + * value can be stuffed directly into th->window for an outgoing + * frame. + */ +-static u16 tcp_select_window(struct sock *sk) ++u16 tcp_select_window(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 old_win = tp->rcv_wnd; +- u32 cur_win = tcp_receive_window(tp); +- u32 new_win = __tcp_select_window(sk); ++ /* The window must never shrink at the meta-level. At the subflow we ++ * have to allow this. Otherwise we may announce a window too large ++ * for the current meta-level sk_rcvbuf. ++ */ ++ u32 cur_win = tcp_receive_window(mptcp(tp) ? tcp_sk(mptcp_meta_sk(sk)) : tp); ++ u32 new_win = tp->ops->__select_window(sk); + + /* Never shrink the offered window */ + if (new_win < cur_win) { +@@ -287,6 +294,7 @@ + LINUX_MIB_TCPWANTZEROWINDOWADV); + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + } ++ + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + +@@ -396,7 +404,7 @@ + /* Constructs common control bits of non-data skb. If SYN/FIN is present, + * auto increment end seqno. + */ +-static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) + { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = 0; +@@ -412,7 +420,7 @@ + TCP_SKB_CB(skb)->end_seq = seq; + } + +-static inline bool tcp_urg_mode(const struct tcp_sock *tp) ++bool tcp_urg_mode(const struct tcp_sock *tp) + { + return tp->snd_una != tp->snd_up; + } +@@ -422,17 +430,7 @@ + #define OPTION_MD5 (1 << 2) + #define OPTION_WSCALE (1 << 3) + #define OPTION_FAST_OPEN_COOKIE (1 << 8) +- +-struct tcp_out_options { +- u16 options; /* bit field of OPTION_* */ +- u16 mss; /* 0 to disable */ +- u8 ws; /* window scale, 0 to disable */ +- u8 num_sack_blocks; /* number of SACK blocks to include */ +- u8 hash_size; /* bytes in hash_location */ +- __u8 *hash_location; /* temporary pointer, overloaded */ +- __u32 tsval, tsecr; /* need to include OPTION_TS */ +- struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ +-}; ++/* Before adding here - take a look at OPTION_MPTCP in include/net/mptcp.h */ + + /* Write previously computed TCP options to the packet. + * +@@ -448,7 +446,7 @@ + * (but it may well be that other scenarios fail similarly). + */ + static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, +- struct tcp_out_options *opts) ++ struct tcp_out_options *opts, struct sk_buff *skb) + { + u16 options = opts->options; /* mungable copy */ + +@@ -540,6 +538,9 @@ + } + ptr += (len + 3) >> 2; + } ++ ++ if (unlikely(OPTION_MPTCP & opts->options)) ++ mptcp_options_write(ptr, tp, opts, skb); + } + + /* Compute TCP options for SYN packets. This is not the final +@@ -591,6 +592,8 @@ + if (unlikely(!(OPTION_TS & opts->options))) + remaining -= TCPOLEN_SACKPERM_ALIGNED; + } ++ if (tp->request_mptcp || mptcp(tp)) ++ mptcp_syn_options(sk, opts, &remaining); + + if (fastopen && fastopen->cookie.len >= 0) { + u32 need = fastopen->cookie.len; +@@ -667,6 +670,9 @@ + } + } + ++ if (ireq->saw_mpc) ++ mptcp_synack_options(req, opts, &remaining); ++ + return MAX_TCP_OPTION_SPACE - remaining; + } + +@@ -699,16 +705,22 @@ + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } ++ if (mptcp(tp)) ++ mptcp_established_options(sk, skb, opts, &size); + + eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; + if (unlikely(eff_sacks)) { +- const unsigned int remaining = MAX_TCP_OPTION_SPACE - size; +- opts->num_sack_blocks = +- min_t(unsigned int, eff_sacks, +- (remaining - TCPOLEN_SACK_BASE_ALIGNED) / +- TCPOLEN_SACK_PERBLOCK); +- size += TCPOLEN_SACK_BASE_ALIGNED + +- opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK; ++ const unsigned remaining = MAX_TCP_OPTION_SPACE - size; ++ if (remaining < TCPOLEN_SACK_BASE_ALIGNED) ++ opts->num_sack_blocks = 0; ++ else ++ opts->num_sack_blocks = ++ min_t(unsigned int, eff_sacks, ++ (remaining - TCPOLEN_SACK_BASE_ALIGNED) / ++ TCPOLEN_SACK_PERBLOCK); ++ if (opts->num_sack_blocks) ++ size += TCPOLEN_SACK_BASE_ALIGNED + ++ opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK; + } + + return size; +@@ -746,8 +758,8 @@ + tp->snd_cwnd > tcp_packets_in_flight(tp)) + tcp_xmit_retransmit_queue(sk); + +- tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, +- 0, GFP_ATOMIC); ++ tcp_sk(sk)->ops->write_xmit(sk, tcp_current_mss(sk), ++ tcp_sk(sk)->nonagle, 0, GFP_ATOMIC); + } + } + /* +@@ -763,7 +775,7 @@ + unsigned long flags; + struct list_head *q, *n; + struct tcp_sock *tp; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + + local_irq_save(flags); + list_splice_init(&tsq->head, &list); +@@ -774,15 +786,25 @@ + list_del(&tp->tsq_node); + + sk = (struct sock *)tp; +- bh_lock_sock(sk); ++ meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ bh_lock_sock(meta_sk); + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + tcp_tsq_handler(sk); ++ if (mptcp(tp)) ++ tcp_tsq_handler(meta_sk); + } else { ++ if (mptcp(tp) && sk->sk_state == TCP_CLOSE) ++ goto exit; ++ + /* defer the work to tcp_release_cb() */ + set_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags); ++ ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++exit: ++ bh_unlock_sock(meta_sk); + + clear_bit(TSQ_QUEUED, &tp->tsq_flags); + sk_free(sk); +@@ -792,7 +814,10 @@ + #define TCP_DEFERRED_ALL ((1UL << TCP_TSQ_DEFERRED) | \ + (1UL << TCP_WRITE_TIMER_DEFERRED) | \ + (1UL << TCP_DELACK_TIMER_DEFERRED) | \ +- (1UL << TCP_MTU_REDUCED_DEFERRED)) ++ (1UL << TCP_MTU_REDUCED_DEFERRED) | \ ++ (1UL << MPTCP_PATH_MANAGER_DEFERRED) |\ ++ (1UL << MPTCP_SUB_DEFERRED)) ++ + /** + * tcp_release_cb - tcp release_sock() callback + * @sk: socket +@@ -839,6 +864,13 @@ + inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); + __sock_put(sk); + } ++ if (flags & (1UL << MPTCP_PATH_MANAGER_DEFERRED)) { ++ if (tcp_sk(sk)->mpcb->pm_ops->release_sock) ++ tcp_sk(sk)->mpcb->pm_ops->release_sock(sk); ++ __sock_put(sk); ++ } ++ if (flags & (1UL << MPTCP_SUB_DEFERRED)) ++ mptcp_tsq_sub_deferred(sk); + } + EXPORT_SYMBOL(tcp_release_cb); + +@@ -992,10 +1024,10 @@ + } + } + +- tcp_options_write((__be32 *)(th + 1), tp, &opts); ++ tcp_options_write((__be32 *)(th + 1), tp, &opts, skb); + skb_shinfo(skb)->gso_type = sk->sk_gso_type; + if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) { +- th->window = htons(tcp_select_window(sk)); ++ th->window = htons(tp->ops->select_window(sk)); + tcp_ecn_send(sk, skb, th, tcp_header_size); + } else { + /* RFC1323: The window in SYN & SYN/ACK segments +@@ -1051,8 +1083,8 @@ + return err; + } + +-static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, +- gfp_t gfp_mask) ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask) + { + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +@@ -1063,7 +1095,7 @@ + * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, + * otherwise socket can stall. + */ +-static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1076,7 +1108,7 @@ + } + + /* Initialize TSO segments for a packet. */ +-static void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + if (skb->len <= mss_now || skb->ip_summed == CHECKSUM_NONE) { + /* Avoid the costly divide in the normal +@@ -1108,7 +1140,7 @@ + /* Pcount in the middle of the write queue got changed, we need to do various + * tweaks to fix counters + */ +-static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1261,7 +1293,7 @@ + * eventually). The difference is that pulled data not copied, but + * immediately discarded. + */ +-static int __pskb_trim_head(struct sk_buff *skb, int len) ++int __pskb_trim_head(struct sk_buff *skb, int len) + { + struct skb_shared_info *shinfo; + int i, k, eat; +@@ -1485,6 +1517,7 @@ + + return mss_now; + } ++EXPORT_SYMBOL(tcp_current_mss); + + /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, +@@ -1508,7 +1541,7 @@ + tp->snd_cwnd_stamp = tcp_time_stamp; + } + +-static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) ++void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1552,8 +1585,8 @@ + * But we can avoid doing the divide again given we already have + * skb_pcount = skb->len / mss_now + */ +-static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, +- const struct sk_buff *skb) ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb) + { + if (skb->len < tcp_skb_pcount(skb) * mss_now) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; +@@ -1611,11 +1644,11 @@ + } + + /* Returns the portion of skb which can be sent right away */ +-static unsigned int tcp_mss_split_point(const struct sock *sk, +- const struct sk_buff *skb, +- unsigned int mss_now, +- unsigned int max_segs, +- int nonagle) ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle) + { + const struct tcp_sock *tp = tcp_sk(sk); + u32 partial, needed, window, max_len; +@@ -1645,13 +1678,14 @@ + /* Can at least one segment of SKB be sent right now, according to the + * congestion window rules? If so, return how many segments are allowed. + */ +-static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb) ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, ++ const struct sk_buff *skb) + { + u32 in_flight, cwnd, halfcwnd; + + /* Don't be strict about the congestion window for the final FIN. */ +- if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ if (skb && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && + tcp_skb_pcount(skb) == 1) + return 1; + +@@ -1671,7 +1705,7 @@ + * This must be invoked the first time we consider transmitting + * SKB onto the wire. + */ +-static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + int tso_segs = tcp_skb_pcount(skb); + +@@ -1686,8 +1720,8 @@ + /* Return true if the Nagle test allows this packet to be + * sent now. + */ +-static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, +- unsigned int cur_mss, int nonagle) ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle) + { + /* Nagle rule does not apply to frames, which sit in the middle of the + * write_queue (they have no chances to get new data). +@@ -1699,7 +1733,8 @@ + return true; + + /* Don't use the nagle rule for urgent data (or for the final FIN). */ +- if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) ++ if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || ++ mptcp_is_data_fin(skb)) + return true; + + if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) +@@ -1709,9 +1744,8 @@ + } + + /* Does at least the first segment of SKB fit into the send window? */ +-static bool tcp_snd_wnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb, +- unsigned int cur_mss) ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss) + { + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + +@@ -1827,7 +1861,7 @@ + struct sk_buff *head; + int win_divisor; + +- if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || mptcp_is_data_fin(skb)) + goto send_now; + + if (icsk->icsk_ca_state >= TCP_CA_Recovery) +@@ -2143,7 +2177,7 @@ + * Returns true, if no segments are in flight and we have queued segments, + * but cannot send anything now because of SWS or another problem. + */ +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + int push_one, gfp_t gfp) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -2156,7 +2190,11 @@ + + sent_pkts = 0; + +- if (!push_one) { ++ /* pmtu not yet supported with MPTCP. Should be possible, by early ++ * exiting the loop inside tcp_mtu_probe, making sure that only one ++ * single DSS-mapping gets probed. ++ */ ++ if (!push_one && !mptcp(tp)) { + /* Do MTU probing. */ + result = tcp_mtu_probe(sk); + if (!result) { +@@ -2242,7 +2280,8 @@ + if (push_one != 2) + tcp_schedule_loss_probe(sk); + is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); +- tcp_cwnd_validate(sk, is_cwnd_limited); ++ if (tp->ops->cwnd_validate) ++ tp->ops->cwnd_validate(sk, is_cwnd_limited); + return false; + } + return !tp->packets_out && tcp_send_head(sk); +@@ -2336,7 +2375,7 @@ + if (skb) { + if (tcp_snd_wnd_test(tp, skb, mss)) { + pcount = tp->packets_out; +- tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); ++ tp->ops->write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); + if (tp->packets_out > pcount) + goto probe_sent; + goto rearm_timer; +@@ -2403,8 +2442,8 @@ + if (unlikely(sk->sk_state == TCP_CLOSE)) + return; + +- if (tcp_write_xmit(sk, cur_mss, nonagle, 0, +- sk_gfp_mask(sk, GFP_ATOMIC))) ++ if (tcp_sk(sk)->ops->write_xmit(sk, cur_mss, nonagle, 0, ++ sk_gfp_mask(sk, GFP_ATOMIC))) + tcp_check_probe_timer(sk); + } + +@@ -2417,7 +2456,8 @@ + + BUG_ON(!skb || skb->len < mss_now); + +- tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); ++ tcp_sk(sk)->ops->write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, ++ sk->sk_allocation); + } + + /* This function returns the amount that we can raise the +@@ -2650,6 +2690,10 @@ + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + return; + ++ /* Currently not supported for MPTCP - but it should be possible */ ++ if (mptcp(tp)) ++ return; ++ + tcp_for_write_queue_from_safe(skb, tmp, sk) { + if (!tcp_can_collapse(sk, skb)) + break; +@@ -3162,7 +3206,7 @@ + + /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ + th->window = htons(min(req->rsk_rcv_wnd, 65535U)); +- tcp_options_write((__be32 *)(th + 1), NULL, &opts); ++ tcp_options_write((__be32 *)(th + 1), NULL, &opts, skb); + th->doff = (tcp_header_size >> 2); + __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); + +@@ -3239,13 +3283,13 @@ + (tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0)) + tp->window_clamp = tcp_full_space(sk); + +- tcp_select_initial_window(tcp_full_space(sk), +- tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), +- &tp->rcv_wnd, +- &tp->window_clamp, +- sysctl_tcp_window_scaling, +- &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(tcp_full_space(sk), ++ tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), ++ &tp->rcv_wnd, ++ &tp->window_clamp, ++ sysctl_tcp_window_scaling, ++ &rcv_wscale, ++ dst_metric(dst, RTAX_INITRWND), sk); + + tp->rx_opt.rcv_wscale = rcv_wscale; + tp->rcv_ssthresh = tp->rcv_wnd; +@@ -3270,6 +3314,36 @@ + inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT; + inet_csk(sk)->icsk_retransmits = 0; + tcp_clear_retrans(tp); ++ ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP) && mptcp_doit(sk)) { ++ if (is_master_tp(tp)) { ++ tp->request_mptcp = 1; ++ mptcp_connect_init(sk); ++ } else if (tp->mptcp) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ tp->mptcp->snt_isn = tp->write_seq; ++ tp->mptcp->init_rcv_wnd = tp->rcv_wnd; ++ ++ /* Set nonce for new subflows */ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp->mptcp_loc_nonce = mptcp_v4_get_nonce( ++ inet->inet_saddr, ++ inet->inet_daddr, ++ inet->inet_sport, ++ inet->inet_dport); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp->mptcp_loc_nonce = mptcp_v6_get_nonce( ++ inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ inet->inet_sport, ++ inet->inet_dport); ++#endif ++ } ++ } ++#endif + } + + static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) +@@ -3540,6 +3614,7 @@ + { + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); + } ++EXPORT_SYMBOL_GPL(tcp_send_ack); + + /* This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. +@@ -3552,7 +3627,7 @@ + * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is + * out-of-date with SND.UNA-1 to probe window. + */ +-static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) + { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; +@@ -3637,7 +3712,7 @@ + unsigned long probe_max; + int err; + +- err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); ++ err = tp->ops->write_wakeup(sk, LINUX_MIB_TCPWINPROBE); + + if (tp->packets_out || !tcp_send_head(sk)) { + /* Cancel probe timer, if it is not required. */ +diff -aurN linux-4.9.162/net/ipv4/tcp_timer.c mptcp-mptcp_v0.93/net/ipv4/tcp_timer.c +--- linux-4.9.162/net/ipv4/tcp_timer.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv4/tcp_timer.c 2019-03-14 14:02:32.000000000 +0100 +@@ -20,6 +20,7 @@ + + #include + #include ++#include + #include + + int sysctl_tcp_thin_linear_timeouts __read_mostly; +@@ -31,7 +32,7 @@ + * Returns: Nothing (void) + */ + +-static void tcp_write_err(struct sock *sk) ++void tcp_write_err(struct sock *sk) + { + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); +@@ -86,7 +87,7 @@ + (!tp->snd_wnd && !tp->packets_out)) + do_reset = true; + if (do_reset) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + return 1; +@@ -163,10 +164,8 @@ + * syn_set flag is set. + * + */ +-static bool retransmits_timed_out(struct sock *sk, +- unsigned int boundary, +- unsigned int timeout, +- bool syn_set) ++bool retransmits_timed_out(struct sock *sk, unsigned int boundary, ++ unsigned int timeout, bool syn_set) + { + unsigned int linear_backoff_thresh, start_ts; + unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN; +@@ -191,7 +190,7 @@ + } + + /* A write timeout has occurred. Process the after effects. */ +-static int tcp_write_timeout(struct sock *sk) ++int tcp_write_timeout(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -212,6 +211,16 @@ + } + retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; + syn_set = true; ++ ++#ifdef CONFIG_MPTCP ++ /* Stop retransmitting MP_CAPABLE options in SYN if timed out. */ ++ if (tcp_sk(sk)->request_mptcp && ++ icsk->icsk_retransmits >= sysctl_mptcp_syn_retries) { ++ tcp_sk(sk)->request_mptcp = 0; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLERETRANSFALLBACK); ++ } ++#endif /* CONFIG_MPTCP */ + } else { + if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0, 0)) { + /* Some middle-boxes may black-hole Fast Open _after_ +@@ -318,18 +327,22 @@ + static void tcp_delack_timer(unsigned long data) + { + struct sock *sk = (struct sock *)data; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_delack_timer_handler(sk); + } else { + inet_csk(sk)->icsk_ack.blocked = 1; +- __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_DELAYEDACKLOCKED); + /* deleguate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -588,7 +601,7 @@ + break; + case ICSK_TIME_RETRANS: + icsk->icsk_pending = 0; +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + break; + case ICSK_TIME_PROBE0: + icsk->icsk_pending = 0; +@@ -603,16 +616,19 @@ + static void tcp_write_timer(unsigned long data) + { + struct sock *sk = (struct sock *)data; ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_write_timer_handler(sk); + } else { + /* delegate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) + sock_hold(sk); ++ if (mptcp(tcp_sk(sk))) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -641,11 +657,12 @@ + struct sock *sk = (struct sock *) data; + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + u32 elapsed; + + /* Only process if socket is not in use. */ +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { + /* Try again later. */ + inet_csk_reset_keepalive_timer (sk, HZ/20); + goto out; +@@ -656,16 +673,40 @@ + goto out; + } + ++ if (tp->send_mp_fclose) { ++ /* MUST do this before tcp_write_timeout, because retrans_stamp ++ * may have been set to 0 in another part while we are ++ * retransmitting MP_FASTCLOSE. Then, we would crash, because ++ * retransmits_timed_out accesses the meta-write-queue. ++ * ++ * We make sure that the timestamp is != 0. ++ */ ++ if (!tp->retrans_stamp) ++ tp->retrans_stamp = tcp_time_stamp ? : 1; ++ ++ if (icsk->icsk_retransmits >= MPTCP_FASTCLOSE_RETRIES) { ++ tcp_write_err(sk); ++ goto out; ++ } ++ ++ tcp_send_ack(sk); ++ icsk->icsk_retransmits++; ++ ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ elapsed = icsk->icsk_rto; ++ goto resched; ++ } ++ + if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { + if (tp->linger2 >= 0) { + const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; + + if (tmo > 0) { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto out; + } + } +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + goto death; + } + +@@ -690,11 +731,11 @@ + icsk->icsk_probes_out > 0) || + (icsk->icsk_user_timeout == 0 && + icsk->icsk_probes_out >= keepalive_probes(tp))) { +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_write_err(sk); + goto out; + } +- if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { ++ if (tp->ops->write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { + icsk->icsk_probes_out++; + elapsed = keepalive_intvl_when(tp); + } else { +@@ -718,7 +759,7 @@ + tcp_done(sk); + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +diff -aurN linux-4.9.162/net/ipv6/addrconf.c mptcp-mptcp_v0.93/net/ipv6/addrconf.c +--- linux-4.9.162/net/ipv6/addrconf.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv6/addrconf.c 2019-03-14 14:02:32.000000000 +0100 +@@ -898,6 +898,7 @@ + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +diff -aurN linux-4.9.162/net/ipv6/af_inet6.c mptcp-mptcp_v0.93/net/ipv6/af_inet6.c +--- linux-4.9.162/net/ipv6/af_inet6.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv6/af_inet6.c 2019-03-14 14:02:32.000000000 +0100 +@@ -106,8 +106,7 @@ + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static int inet6_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct inet_sock *inet; + struct ipv6_pinfo *np; +diff -aurN linux-4.9.162/net/ipv6/ipv6_sockglue.c mptcp-mptcp_v0.93/net/ipv6/ipv6_sockglue.c +--- linux-4.9.162/net/ipv6/ipv6_sockglue.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv6/ipv6_sockglue.c 2019-03-14 14:02:32.000000000 +0100 +@@ -48,6 +48,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -215,7 +217,12 @@ + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); + sk->sk_prot = &tcp_prot; +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +@@ -241,7 +248,12 @@ + pktopt = xchg(&np->pktoptions, NULL); + kfree_skb(pktopt); + +- sk->sk_destruct = inet_sock_destruct; ++#ifdef CONFIG_MPTCP ++ if (is_meta_sk(sk)) ++ sk->sk_destruct = mptcp_sock_destruct; ++ else ++#endif ++ sk->sk_destruct = inet_sock_destruct; + /* + * ... and add it to the refcnt debug socks count + * in the new family. -acme +diff -aurN linux-4.9.162/net/ipv6/syncookies.c mptcp-mptcp_v0.93/net/ipv6/syncookies.c +--- linux-4.9.162/net/ipv6/syncookies.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv6/syncookies.c 2019-03-14 14:02:32.000000000 +0100 +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define COOKIEBITS 24 /* Upper bits store count */ +@@ -113,7 +115,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); + +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -135,6 +138,7 @@ + struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) + { + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -163,20 +167,34 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (!cookie_timestamp_decode(&tcp_opt)) + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp6_request_sock_ops, sk, false); ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); + if (!req) + goto out; + + ireq = inet_rsk(req); ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + treq = tcp_rsk(req); + treq->tfo_listener = false; + ++ /* Must be done before anything else, as it initializes ++ * hash_entry of the MPTCP request-sock. ++ */ ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + if (security_inet_conn_request(sk, skb, req)) + goto out_free; + +@@ -236,10 +254,10 @@ + } + + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); +- tcp_select_initial_window(tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(dst, RTAX_INITRWND), sk); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); +diff -aurN linux-4.9.162/net/ipv6/tcp_ipv6.c mptcp-mptcp_v0.93/net/ipv6/tcp_ipv6.c +--- linux-4.9.162/net/ipv6/tcp_ipv6.c 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/ipv6/tcp_ipv6.c 2019-03-14 14:02:32.000000000 +0100 +@@ -61,6 +61,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -69,14 +71,6 @@ + #include + #include + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req); +- +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); +- +-static const struct inet_connection_sock_af_ops ipv6_mapped; +-static const struct inet_connection_sock_af_ops ipv6_specific; + #ifdef CONFIG_TCP_MD5SIG + static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; + static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +@@ -88,7 +82,7 @@ + } + #endif + +-static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) + { + struct dst_entry *dst = skb_dst(skb); + +@@ -109,7 +103,7 @@ + tcp_hdr(skb)->source); + } + +-static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) + { + struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; +@@ -206,7 +200,12 @@ + sin.sin_port = usin->sin6_port; + sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; + +- icsk->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_mapped; + sk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -216,7 +215,12 @@ + + if (err) { + icsk->icsk_ext_hdr_len = exthdrlen; +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + sk->sk_backlog_rcv = tcp_v6_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +@@ -304,7 +308,7 @@ + return err; + } + +-static void tcp_v6_mtu_reduced(struct sock *sk) ++void tcp_v6_mtu_reduced(struct sock *sk) + { + struct dst_entry *dst; + +@@ -331,7 +335,7 @@ + struct ipv6_pinfo *np; + struct tcp_sock *tp; + __u32 seq, snd_una; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + bool fatal; + int err; + +@@ -355,8 +359,14 @@ + if (sk->sk_state == TCP_NEW_SYN_RECV) + return tcp_req_err(sk, seq, fatal); + +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk) && type != ICMPV6_PKT_TOOBIG) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + + if (sk->sk_state == TCP_CLOSE) +@@ -367,7 +377,6 @@ + goto out; + } + +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = tp->fastopen_rsk; + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -401,11 +410,15 @@ + goto out; + + tp->mtu_info = ntohl(info); +- if (!sock_owned_by_user(sk)) ++ if (!sock_owned_by_user(meta_sk)) + tcp_v6_mtu_reduced(sk); +- else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, ++ else { ++ if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, + &tp->tsq_flags)) +- sock_hold(sk); ++ sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); ++ } + goto out; + } + +@@ -420,7 +433,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + +@@ -430,14 +443,14 @@ + goto out; + } + +- if (!sock_owned_by_user(sk) && np->recverr) { ++ if (!sock_owned_by_user(meta_sk) && np->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else + sk->sk_err_soft = err; + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -483,8 +496,7 @@ + return err; + } + +- +-static void tcp_v6_reqsk_destructor(struct request_sock *req) ++void tcp_v6_reqsk_destructor(struct request_sock *req) + { + kfree(inet_rsk(req)->ipv6_opt); + kfree_skb(inet_rsk(req)->pktopts); +@@ -689,9 +701,10 @@ + return false; + } + +-static void tcp_v6_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v6_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + struct inet_request_sock *ireq = inet_rsk(req); + const struct ipv6_pinfo *np = inet6_sk(sk_listener); +@@ -712,6 +725,8 @@ + atomic_inc(&skb->users); + ireq->pktopts = skb; + } ++ ++ return 0; + } + + static struct dst_entry *tcp_v6_route_req(const struct sock *sk, +@@ -734,7 +749,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { + .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr), + #ifdef CONFIG_TCP_MD5SIG +@@ -751,9 +766,9 @@ + }; + + static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, + int oif, struct tcp_md5sig_key *key, int rst, +- u8 tclass, __be32 label) ++ u8 tclass, __be32 label, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct tcphdr *t1; +@@ -771,7 +786,10 @@ + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; + #endif +- ++#ifdef CONFIG_MPTCP ++ if (mptcp) ++ tot_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++#endif + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, + GFP_ATOMIC); + if (!buff) +@@ -809,6 +827,17 @@ + tcp_v6_md5_hash_hdr((__u8 *)topt, key, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, t1); ++ topt += 4; ++ } ++#endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ /* Construction of 32-bit data_ack */ ++ *topt++ = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ *topt++ = htonl(data_ack); + } + #endif + +@@ -854,7 +883,7 @@ + kfree_skb(buff); + } + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + u32 seq = 0, ack_seq = 0; +@@ -915,7 +944,7 @@ + (th->doff << 2); + + oif = sk ? sk->sk_bound_dev_if : 0; +- tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0); ++ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, 0, oif, key, 1, 0, 0, 0); + + #ifdef CONFIG_TCP_MD5SIG + out: +@@ -924,30 +953,37 @@ + } + + static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, u8 tclass, +- __be32 label) ++ __be32 label, int mptcp) + { +- tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, +- tclass, label); ++ tcp_v6_send_response(sk, skb, seq, ack, data_ack, win, tsval, tsecr, oif, ++ key, 0, tclass, label, mptcp); + } + + static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; + ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), +- tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); ++ tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), mptcp); + + inet_twsk_put(tw); + } + +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. +@@ -957,17 +993,17 @@ + * exception of segments, MUST be right-shifted by + * Rcv.Wind.Shift bits: + */ +- tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? ++ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? + tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), +- 0, 0); ++ 0, 0, 0); + } + + +-static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -978,7 +1014,7 @@ + return sk; + } + +-static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) + { + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_conn_request(sk, skb); +@@ -1004,11 +1040,11 @@ + sizeof(struct inet6_skb_parm)); + } + +-static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req, +- struct dst_entry *dst, +- struct request_sock *req_unhash, +- bool *own_req) ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req) + { + struct inet_request_sock *ireq; + struct ipv6_pinfo *newnp; +@@ -1045,7 +1081,15 @@ + + newnp->saddr = newsk->sk_v6_rcv_saddr; + +- inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ /* We must check on the request-socket because the listener ++ * socket's flag may have been changed halfway through. ++ */ ++ if (!inet_rsk(req)->saw_mpc) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; + newsk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -1092,6 +1136,14 @@ + if (!newsk) + goto out_nonewsk; + ++#ifdef CONFIG_MPTCP ++ /* If the meta_sk is v6-mapped we can end up here with the wrong af_ops. ++ * Just make sure that this subflow is v6. ++ */ ++ if (is_meta_sk(sk)) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ + /* + * No need to charge this sock to the relevant IPv6 refcnt debug socks + * count here, tcp_create_openreq_child now does this for us, see the +@@ -1223,7 +1275,7 @@ + * This is because we cannot sleep with the original spinlock + * held. + */ +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + { + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp; +@@ -1240,6 +1292,9 @@ + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_do_rcv(sk, skb); + ++ if (is_meta_sk(sk)) ++ return mptcp_v6_do_rcv(sk, skb); ++ + if (tcp_filter(sk, skb)) + goto discard; + +@@ -1372,6 +1427,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff*4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); +@@ -1382,8 +1441,8 @@ + { + const struct tcphdr *th; + const struct ipv6hdr *hdr; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + struct net *net = dev_net(skb->dev); + +@@ -1437,19 +1496,53 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } + sock_hold(sk); + refcounted = true; ++ ++ if (is_meta_sk(sk)) { ++ bh_lock_sock(sk); ++ ++ if (!mptcp_can_new_subflow(sk)) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ bh_unlock_sock(sk); ++ ++ goto discard_and_relse; ++ } ++ ++ if (sock_owned_by_user(sk)) { ++ mptcp_prepare_for_backlog(sk, skb); ++ if (unlikely(sk_add_backlog(sk, skb, ++ sk->sk_rcvbuf + sk->sk_sndbuf))) { ++ reqsk_put(req); ++ ++ bh_unlock_sock(sk); ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ goto discard_and_relse; ++ } ++ ++ reqsk_put(req); ++ bh_unlock_sock(sk); ++ sock_put(sk); ++ ++ return 0; ++ } ++ } ++ + nsk = tcp_check_req(sk, skb, req, false); + if (!nsk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + goto discard_and_relse; + } + if (nsk == sk) { + reqsk_put(req); ++ if (is_meta_sk(sk)) ++ bh_unlock_sock(sk); + tcp_v6_restore_cb(skb); + } else if (tcp_child_process(sk, nsk, skb)) { + tcp_v6_send_reset(nsk, skb); +@@ -1459,6 +1552,7 @@ + return 0; + } + } ++ + if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { + __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); + goto discard_and_relse; +@@ -1486,16 +1580,26 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { +- if (!tcp_prequeue(sk, skb)) ++ if (!sock_owned_by_user(meta_sk)) { ++ if (!tcp_prequeue(meta_sk, skb)) + ret = tcp_v6_do_rcv(sk, skb); +- } else if (tcp_add_backlog(sk, skb)) { ++ } else if (tcp_add_backlog(meta_sk, skb)) { + goto discard_and_relse; + } +- bh_unlock_sock(sk); ++ ++ bh_unlock_sock(meta_sk); + + put_and_return: + if (refcounted) +@@ -1508,6 +1612,19 @@ + + tcp_v6_fill_cb(skb, hdr, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1558,6 +1675,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + /* Fall through to ACK */ + } + case TCP_TW_ACK: +@@ -1612,13 +1741,13 @@ + } + } + +-static struct timewait_sock_ops tcp6_timewait_sock_ops = { ++struct timewait_sock_ops tcp6_timewait_sock_ops = { + .twsk_obj_size = sizeof(struct tcp6_timewait_sock), + .twsk_unique = tcp_twsk_unique, + .twsk_destructor = tcp_twsk_destructor, + }; + +-static const struct inet_connection_sock_af_ops ipv6_specific = { ++const struct inet_connection_sock_af_ops ipv6_specific = { + .queue_xmit = inet6_csk_xmit, + .send_check = tcp_v6_send_check, + .rebuild_header = inet6_sk_rebuild_header, +@@ -1650,7 +1779,7 @@ + /* + * TCP over IPv4 via INET6 API + */ +-static const struct inet_connection_sock_af_ops ipv6_mapped = { ++const struct inet_connection_sock_af_ops ipv6_mapped = { + .queue_xmit = ip_queue_xmit, + .send_check = tcp_v4_send_check, + .rebuild_header = inet_sk_rebuild_header, +@@ -1687,7 +1816,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; +@@ -1696,7 +1830,7 @@ + return 0; + } + +-static void tcp_v6_destroy_sock(struct sock *sk) ++void tcp_v6_destroy_sock(struct sock *sk) + { + tcp_v4_destroy_sock(sk); + inet6_destroy_sock(sk); +@@ -1928,6 +2062,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + + static const struct inet6_protocol tcpv6_protocol = { +diff -aurN linux-4.9.162/net/Kconfig mptcp-mptcp_v0.93/net/Kconfig +--- linux-4.9.162/net/Kconfig 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/Kconfig 2019-03-14 14:02:32.000000000 +0100 +@@ -86,6 +86,7 @@ + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" + source "net/netlabel/Kconfig" ++source "net/mptcp/Kconfig" + + endif # if INET + +diff -aurN linux-4.9.162/net/Makefile mptcp-mptcp_v0.93/net/Makefile +--- linux-4.9.162/net/Makefile 2019-03-05 17:57:07.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/Makefile 2019-03-14 14:02:32.000000000 +0100 +@@ -18,6 +18,7 @@ + obj-$(CONFIG_XFRM) += xfrm/ + obj-$(CONFIG_UNIX) += unix/ + obj-$(CONFIG_NET) += ipv6/ ++obj-$(CONFIG_MPTCP) += mptcp/ + obj-$(CONFIG_PACKET) += packet/ + obj-$(CONFIG_NET_KEY) += key/ + obj-$(CONFIG_BRIDGE) += bridge/ +diff -aurN linux-4.9.162/net/mptcp/Kconfig mptcp-mptcp_v0.93/net/mptcp/Kconfig +--- linux-4.9.162/net/mptcp/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/Kconfig 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,129 @@ ++# ++# MPTCP configuration ++# ++config MPTCP ++ bool "MPTCP protocol" ++ depends on (IPV6=y || IPV6=n) ++ ---help--- ++ This replaces the normal TCP stack with a Multipath TCP stack, ++ able to use several paths at once. ++ ++menuconfig MPTCP_PM_ADVANCED ++ bool "MPTCP: advanced path-manager control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different path-managers. You should choose 'Y' here, ++ because otherwise you will not actively create new MPTCP-subflows. ++ ++if MPTCP_PM_ADVANCED ++ ++config MPTCP_FULLMESH ++ tristate "MPTCP Full-Mesh Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create a full-mesh among all IP-addresses. ++ ++config MPTCP_NDIFFPORTS ++ tristate "MPTCP ndiff-ports" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create multiple subflows between the same ++ pair of IP-addresses, modifying the source-port. You can set the number ++ of subflows via the mptcp_ndiffports-sysctl. ++ ++config MPTCP_BINDER ++ tristate "MPTCP Binder" ++ depends on (MPTCP=y) ++ ---help--- ++ This path-management module works like ndiffports, and adds the sysctl ++ option to set the gateway (and/or path to) per each additional subflow ++ via Loose Source Routing (IPv4 only). ++ ++choice ++ prompt "Default MPTCP Path-Manager" ++ default DEFAULT ++ help ++ Select the Path-Manager of your choice ++ ++ config DEFAULT_FULLMESH ++ bool "Full mesh" if MPTCP_FULLMESH=y ++ ++ config DEFAULT_NDIFFPORTS ++ bool "ndiff-ports" if MPTCP_NDIFFPORTS=y ++ ++ config DEFAULT_BINDER ++ bool "binder" if MPTCP_BINDER=y ++ ++ config DEFAULT_DUMMY ++ bool "Default" ++ ++endchoice ++ ++endif ++ ++config DEFAULT_MPTCP_PM ++ string ++ default "default" if DEFAULT_DUMMY ++ default "fullmesh" if DEFAULT_FULLMESH ++ default "ndiffports" if DEFAULT_NDIFFPORTS ++ default "binder" if DEFAULT_BINDER ++ default "default" ++ ++menuconfig MPTCP_SCHED_ADVANCED ++ bool "MPTCP: advanced scheduler control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different schedulers. You should choose 'Y' here, ++ if you want to choose a different scheduler than the default one. ++ ++if MPTCP_SCHED_ADVANCED ++ ++config MPTCP_ROUNDROBIN ++ tristate "MPTCP Round-Robin" ++ depends on (MPTCP=y) ++ ---help--- ++ This is a very simple round-robin scheduler. Probably has bad performance ++ but might be interesting for researchers. ++ ++config MPTCP_REDUNDANT ++ tristate "MPTCP Redundant" ++ depends on (MPTCP=y) ++ ---help--- ++ This scheduler sends all packets redundantly over all subflows to decreases ++ latency and jitter on the cost of lower throughput. ++ ++choice ++ prompt "Default MPTCP Scheduler" ++ default DEFAULT ++ help ++ Select the Scheduler of your choice ++ ++ config DEFAULT_SCHEDULER ++ bool "Default" ++ ---help--- ++ This is the default scheduler, sending first on the subflow ++ with the lowest RTT. ++ ++ config DEFAULT_ROUNDROBIN ++ bool "Round-Robin" if MPTCP_ROUNDROBIN=y ++ ---help--- ++ This is the round-rob scheduler, sending in a round-robin ++ fashion.. ++ ++ config DEFAULT_REDUNDANT ++ bool "Redundant" if MPTCP_REDUNDANT=y ++ ---help--- ++ This is the redundant scheduler, sending packets redundantly over ++ all the subflows. ++ ++endchoice ++endif ++ ++config DEFAULT_MPTCP_SCHED ++ string ++ depends on (MPTCP=y) ++ default "default" if DEFAULT_SCHEDULER ++ default "roundrobin" if DEFAULT_ROUNDROBIN ++ default "redundant" if DEFAULT_REDUNDANT ++ default "default" ++ +diff -aurN linux-4.9.162/net/mptcp/Makefile mptcp-mptcp_v0.93/net/mptcp/Makefile +--- linux-4.9.162/net/mptcp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/Makefile 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,22 @@ ++# ++## Makefile for MultiPath TCP support code. ++# ++# ++ ++obj-$(CONFIG_MPTCP) += mptcp.o ++ ++mptcp-y := mptcp_ctrl.o mptcp_ipv4.o mptcp_pm.o \ ++ mptcp_output.o mptcp_input.o mptcp_sched.o ++ ++obj-$(CONFIG_TCP_CONG_LIA) += mptcp_coupled.o ++obj-$(CONFIG_TCP_CONG_OLIA) += mptcp_olia.o ++obj-$(CONFIG_TCP_CONG_WVEGAS) += mptcp_wvegas.o ++obj-$(CONFIG_TCP_CONG_BALIA) += mptcp_balia.o ++obj-$(CONFIG_MPTCP_FULLMESH) += mptcp_fullmesh.o ++obj-$(CONFIG_MPTCP_NDIFFPORTS) += mptcp_ndiffports.o ++obj-$(CONFIG_MPTCP_BINDER) += mptcp_binder.o ++obj-$(CONFIG_MPTCP_ROUNDROBIN) += mptcp_rr.o ++obj-$(CONFIG_MPTCP_REDUNDANT) += mptcp_redundant.o ++ ++mptcp-$(subst m,y,$(CONFIG_IPV6)) += mptcp_ipv6.o ++ +diff -aurN linux-4.9.162/net/mptcp/mptcp_balia.c mptcp-mptcp_v0.93/net/mptcp/mptcp_balia.c +--- linux-4.9.162/net/mptcp/mptcp_balia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_balia.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,267 @@ ++/* ++ * MPTCP implementation - Balia Congestion Control ++ * (Balanced Linked Adaptation Algorithm) ++ * ++ * Analysis, Design and Implementation: ++ * Qiuyu Peng ++ * Anwar Walid ++ * Jaehyun Hwang ++ * Steven H. Low ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++/* The variable 'rate' (i.e., x_r) will be scaled ++ * e.g., from B/s to KB/s, MB/s, or GB/s ++ * if max_rate > 2^rate_scale_limit ++ */ ++ ++static int rate_scale_limit = 25; ++static int alpha_scale = 10; ++static int scale_num = 5; ++ ++struct mptcp_balia { ++ u64 ai; ++ u64 md; ++ bool forced_update; ++}; ++ ++static inline int mptcp_balia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_ai(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai; ++} ++ ++static inline void mptcp_set_ai(const struct sock *meta_sk, u64 ai) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai = ai; ++} ++ ++static inline u64 mptcp_get_md(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md; ++} ++ ++static inline void mptcp_set_md(const struct sock *meta_sk, u64 md) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md = md; ++} ++ ++static inline u64 mptcp_balia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_balia_recalc_ai(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ const struct sock *sub_sk; ++ u64 max_rate = 0, rate = 0, sum_rate = 0; ++ u64 alpha, ai = tp->snd_cwnd, md = (tp->snd_cwnd >> 1); ++ int num_scale_down = 0; ++ ++ if (!mpcb) ++ return; ++ ++ /* Only one subflow left - fall back to normal reno-behavior */ ++ if (mpcb->cnt_established <= 1) ++ goto exit; ++ ++ /* Find max_rate first */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ sum_rate += tmp; ++ ++ if (tp == sub_tp) ++ rate = tmp; ++ ++ if (tmp >= max_rate) ++ max_rate = tmp; ++ } ++ ++ /* At least, the current subflow should be able to send */ ++ if (unlikely(!rate)) ++ goto exit; ++ ++ alpha = div64_u64(max_rate, rate); ++ ++ /* Scale down max_rate if it is too high (e.g., >2^25) */ ++ while (max_rate > mptcp_balia_scale(1, rate_scale_limit)) { ++ max_rate >>= scale_num; ++ num_scale_down++; ++ } ++ ++ if (num_scale_down) { ++ sum_rate = 0; ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ tmp >>= (scale_num * num_scale_down); ++ ++ sum_rate += tmp; ++ } ++ rate >>= (scale_num * num_scale_down); ++ } ++ ++ /* (sum_rate)^2 * 10 * w_r ++ * ai = ------------------------------------ ++ * (x_r + max_rate) * (4x_r + max_rate) ++ */ ++ sum_rate *= sum_rate; ++ ++ ai = div64_u64(sum_rate * 10, rate + max_rate); ++ ai = div64_u64(ai * tp->snd_cwnd, (rate << 2) + max_rate); ++ ++ if (unlikely(!ai)) ++ ai = tp->snd_cwnd; ++ ++ md = ((tp->snd_cwnd >> 1) * min(mptcp_balia_scale(alpha, alpha_scale), ++ mptcp_balia_scale(3, alpha_scale) >> 1)) ++ >> alpha_scale; ++ ++exit: ++ mptcp_set_ai(sk, ai); ++ mptcp_set_md(sk, md); ++} ++ ++static void mptcp_balia_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(sk, 0); ++ mptcp_set_ai(sk, 0); ++ mptcp_set_md(sk, 0); ++ } ++} ++ ++static void mptcp_balia_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_COMPLETE_CWR || event == CA_EVENT_LOSS) ++ mptcp_balia_recalc_ai(sk); ++} ++ ++static void mptcp_balia_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(sk, 1); ++} ++ ++static void mptcp_balia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_balia_recalc_ai(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_balia_recalc_ai(sk); ++ mptcp_set_forced(sk, 0); ++ } ++ ++ if (mpcb->cnt_established > 1) ++ snd_cwnd = (int) mptcp_get_ai(sk); ++ else ++ snd_cwnd = tp->snd_cwnd; ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_balia_recalc_ai(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static u32 mptcp_balia_ssthresh(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ if (unlikely(!mptcp(tp) || mpcb->cnt_established <= 1)) ++ return tcp_reno_ssthresh(sk); ++ else ++ return max((u32)(tp->snd_cwnd - mptcp_get_md(sk)), 1U); ++} ++ ++static struct tcp_congestion_ops mptcp_balia = { ++ .init = mptcp_balia_init, ++ .ssthresh = mptcp_balia_ssthresh, ++ .cong_avoid = mptcp_balia_cong_avoid, ++ .cwnd_event = mptcp_balia_cwnd_event, ++ .set_state = mptcp_balia_set_state, ++ .owner = THIS_MODULE, ++ .name = "balia", ++}; ++ ++static int __init mptcp_balia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_balia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_balia); ++} ++ ++static void __exit mptcp_balia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_balia); ++} ++ ++module_init(mptcp_balia_register); ++module_exit(mptcp_balia_unregister); ++ ++MODULE_AUTHOR("Jaehyun Hwang, Anwar Walid, Qiuyu Peng, Steven H. Low"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP BALIA CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_binder.c mptcp-mptcp_v0.93/net/mptcp/mptcp_binder.c +--- linux-4.9.162/net/mptcp/mptcp_binder.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_binder.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,486 @@ ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MPTCP_GW_MAX_LISTS 10 ++#define MPTCP_GW_LIST_MAX_LEN 6 ++#define MPTCP_GW_SYSCTL_MAX_LEN (15 * MPTCP_GW_LIST_MAX_LEN * \ ++ MPTCP_GW_MAX_LISTS) ++ ++struct mptcp_gw_list { ++ struct in_addr list[MPTCP_GW_MAX_LISTS][MPTCP_GW_LIST_MAX_LEN]; ++ u8 len[MPTCP_GW_MAX_LISTS]; ++}; ++ ++struct binder_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++ ++ /* Prevent multiple sub-sockets concurrently iterating over sockets */ ++ spinlock_t *flow_lock; ++}; ++ ++static struct mptcp_gw_list *mptcp_gws; ++static rwlock_t mptcp_gws_lock; ++ ++static int mptcp_binder_ndiffports __read_mostly = 1; ++ ++static char sysctl_mptcp_binder_gateways[MPTCP_GW_SYSCTL_MAX_LEN] __read_mostly; ++ ++static int mptcp_get_avail_list_ipv4(struct sock *sk) ++{ ++ int i, j, list_taken, opt_ret, opt_len; ++ unsigned char *opt_ptr, *opt_end_ptr, opt[MAX_IPOPTLEN]; ++ ++ for (i = 0; i < MPTCP_GW_MAX_LISTS; ++i) { ++ if (mptcp_gws->len[i] == 0) ++ goto error; ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: List %i\n", i); ++ list_taken = 0; ++ ++ /* Loop through all sub-sockets in this connection */ ++ mptcp_for_each_sk(tcp_sk(sk)->mpcb, sk) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: Next sock\n"); ++ ++ /* Reset length and options buffer, then retrieve ++ * from socket ++ */ ++ opt_len = MAX_IPOPTLEN; ++ memset(opt, 0, MAX_IPOPTLEN); ++ opt_ret = ip_getsockopt(sk, IPPROTO_IP, ++ IP_OPTIONS, (char __user *)opt, (int __user *)&opt_len); ++ if (opt_ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket getsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, opt_ret); ++ goto error; ++ } ++ ++ /* If socket has no options, it has no stake in this list */ ++ if (opt_len <= 0) ++ continue; ++ ++ /* Iterate options buffer */ ++ for (opt_ptr = &opt[0]; opt_ptr < &opt[opt_len]; opt_ptr++) { ++ if (*opt_ptr == IPOPT_LSRR) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: LSRR options found\n"); ++ goto sock_lsrr; ++ } ++ } ++ continue; ++ ++sock_lsrr: ++ /* Pointer to the 2nd to last address */ ++ opt_end_ptr = opt_ptr+(*(opt_ptr+1))-4; ++ ++ /* Addresses start 3 bytes after type offset */ ++ opt_ptr += 3; ++ j = 0; ++ ++ /* Different length lists cannot be the same */ ++ if ((opt_end_ptr-opt_ptr)/4 != mptcp_gws->len[i]) ++ continue; ++ ++ /* Iterate if we are still inside options list ++ * and sysctl list ++ */ ++ while (opt_ptr < opt_end_ptr && j < mptcp_gws->len[i]) { ++ /* If there is a different address, this list must ++ * not be set on this socket ++ */ ++ if (memcmp(&mptcp_gws->list[i][j], opt_ptr, 4)) ++ break; ++ ++ /* Jump 4 bytes to next address */ ++ opt_ptr += 4; ++ j++; ++ } ++ ++ /* Reached the end without a differing address, lists ++ * are therefore identical. ++ */ ++ if (j == mptcp_gws->len[i]) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List already used\n"); ++ list_taken = 1; ++ break; ++ } ++ } ++ ++ /* Free list found if not taken by a socket */ ++ if (!list_taken) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List free\n"); ++ break; ++ } ++ } ++ ++ if (i >= MPTCP_GW_MAX_LISTS) ++ goto error; ++ ++ return i; ++error: ++ return -1; ++} ++ ++/* The list of addresses is parsed each time a new connection is opened, ++ * to make sure it's up to date. In case of error, all the lists are ++ * marked as unavailable and the subflow's fingerprint is set to 0. ++ */ ++static void mptcp_v4_add_lsrr(struct sock *sk, struct in_addr addr) ++{ ++ int i, j, ret; ++ unsigned char opt[MAX_IPOPTLEN] = {0}; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct binder_priv *fmp = (struct binder_priv *)&tp->mpcb->mptcp_pm[0]; ++ ++ /* Read lock: multiple sockets can read LSRR addresses at the same ++ * time, but writes are done in mutual exclusion. ++ * Spin lock: must search for free list for one socket at a time, or ++ * multiple sockets could take the same list. ++ */ ++ read_lock(&mptcp_gws_lock); ++ spin_lock(fmp->flow_lock); ++ ++ i = mptcp_get_avail_list_ipv4(sk); ++ ++ /* Execution enters here only if a free path is found. ++ */ ++ if (i >= 0) { ++ opt[0] = IPOPT_NOP; ++ opt[1] = IPOPT_LSRR; ++ opt[2] = sizeof(mptcp_gws->list[i][0].s_addr) * ++ (mptcp_gws->len[i] + 1) + 3; ++ opt[3] = IPOPT_MINOFF; ++ for (j = 0; j < mptcp_gws->len[i]; ++j) ++ memcpy(opt + 4 + ++ (j * sizeof(mptcp_gws->list[i][0].s_addr)), ++ &mptcp_gws->list[i][j].s_addr, ++ sizeof(mptcp_gws->list[i][0].s_addr)); ++ /* Final destination must be part of IP_OPTIONS parameter. */ ++ memcpy(opt + 4 + (j * sizeof(addr.s_addr)), &addr.s_addr, ++ sizeof(addr.s_addr)); ++ ++ /* setsockopt must be inside the lock, otherwise another ++ * subflow could fail to see that we have taken a list. ++ */ ++ ret = ip_setsockopt(sk, IPPROTO_IP, IP_OPTIONS, (char __user *)opt, ++ 4 + sizeof(mptcp_gws->list[i][0].s_addr) * (mptcp_gws->len[i] + 1)); ++ ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsock setsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, ret); ++ } ++ } ++ ++ spin_unlock(fmp->flow_lock); ++ read_unlock(&mptcp_gws_lock); ++ ++ return; ++} ++ ++/* Parses gateways string for a list of paths to different ++ * gateways, and stores them for use with the Loose Source Routing (LSRR) ++ * socket option. Each list must have "," separated addresses, and the lists ++ * themselves must be separated by "-". Returns -1 in case one or more of the ++ * addresses is not a valid ipv4/6 address. ++ */ ++static int mptcp_parse_gateway_ipv4(char *gateways) ++{ ++ int i, j, k, ret; ++ char *tmp_string = NULL; ++ struct in_addr tmp_addr; ++ ++ tmp_string = kzalloc(16, GFP_KERNEL); ++ if (tmp_string == NULL) ++ return -ENOMEM; ++ ++ write_lock(&mptcp_gws_lock); ++ ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ ++ /* A TMP string is used since inet_pton needs a null terminated string ++ * but we do not want to modify the sysctl for obvious reasons. ++ * i will iterate over the SYSCTL string, j will iterate over the ++ * temporary string where each IP is copied into, k will iterate over ++ * the IPs in each list. ++ */ ++ for (i = j = k = 0; ++ i < MPTCP_GW_SYSCTL_MAX_LEN && k < MPTCP_GW_MAX_LISTS; ++ ++i) { ++ if (gateways[i] == '-' || gateways[i] == ',' || gateways[i] == '\0') { ++ /* If the temp IP is empty and the current list is ++ * empty, we are done. ++ */ ++ if (j == 0 && mptcp_gws->len[k] == 0) ++ break; ++ ++ /* Terminate the temp IP string, then if it is ++ * non-empty parse the IP and copy it. ++ */ ++ tmp_string[j] = '\0'; ++ if (j > 0) { ++ mptcp_debug("mptcp_parse_gateway_list tmp: %s i: %d\n", tmp_string, i); ++ ++ ret = in4_pton(tmp_string, strlen(tmp_string), ++ (u8 *)&tmp_addr.s_addr, '\0', ++ NULL); ++ ++ if (ret) { ++ mptcp_debug("mptcp_parse_gateway_list ret: %d s_addr: %pI4\n", ++ ret, ++ &tmp_addr.s_addr); ++ memcpy(&mptcp_gws->list[k][mptcp_gws->len[k]].s_addr, ++ &tmp_addr.s_addr, ++ sizeof(tmp_addr.s_addr)); ++ mptcp_gws->len[k]++; ++ j = 0; ++ tmp_string[j] = '\0'; ++ /* Since we can't impose a limit to ++ * what the user can input, make sure ++ * there are not too many IPs in the ++ * SYSCTL string. ++ */ ++ if (mptcp_gws->len[k] > MPTCP_GW_LIST_MAX_LEN) { ++ mptcp_debug("mptcp_parse_gateway_list too many members in list %i: max %i\n", ++ k, ++ MPTCP_GW_LIST_MAX_LEN); ++ goto error; ++ } ++ } else { ++ goto error; ++ } ++ } ++ ++ if (gateways[i] == '-' || gateways[i] == '\0') ++ ++k; ++ } else { ++ tmp_string[j] = gateways[i]; ++ ++j; ++ } ++ } ++ ++ /* Number of flows is number of gateway lists plus master flow */ ++ mptcp_binder_ndiffports = k+1; ++ ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ ++ return 0; ++ ++error: ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ memset(gateways, 0, sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN); ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ return -1; ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct binder_priv *pm_priv = container_of(work, ++ struct binder_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (mptcp_binder_ndiffports > iter && ++ mptcp_binder_ndiffports > mpcb->cnt_subflows) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++} ++ ++static void binder_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *fmp = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ static DEFINE_SPINLOCK(flow_lock); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(meta_sk)) { ++ mptcp_fallback_default(mpcb); ++ return; ++ } ++#endif ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ fmp->flow_lock = &flow_lock; ++} ++ ++static void binder_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *pm_priv = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mpcb->infinite_mapping_snd || mpcb->infinite_mapping_rcv || ++ mpcb->send_infinite_mapping || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int binder_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++/* Callback functions, executed when syctl mptcp.mptcp_gateways is updated. ++ * Inspired from proc_tcp_congestion_control(). ++ */ ++static int proc_mptcp_gateways(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ struct ctl_table tbl = { ++ .maxlen = MPTCP_GW_SYSCTL_MAX_LEN, ++ }; ++ ++ if (write) { ++ tbl.data = kzalloc(MPTCP_GW_SYSCTL_MAX_LEN, GFP_KERNEL); ++ if (tbl.data == NULL) ++ return -ENOMEM; ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (ret == 0) { ++ ret = mptcp_parse_gateway_ipv4(tbl.data); ++ memcpy(ctl->data, tbl.data, MPTCP_GW_SYSCTL_MAX_LEN); ++ } ++ kfree(tbl.data); ++ } else { ++ ret = proc_dostring(ctl, write, buffer, lenp, ppos); ++ } ++ ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops binder __read_mostly = { ++ .new_session = binder_new_session, ++ .fully_established = binder_create_subflows, ++ .get_local_id = binder_get_local_id, ++ .init_subsocket_v4 = mptcp_v4_add_lsrr, ++ .name = "binder", ++ .owner = THIS_MODULE, ++}; ++ ++static struct ctl_table binder_table[] = { ++ { ++ .procname = "mptcp_binder_gateways", ++ .data = &sysctl_mptcp_binder_gateways, ++ .maxlen = sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN, ++ .mode = 0644, ++ .proc_handler = &proc_mptcp_gateways ++ }, ++ { } ++}; ++ ++static struct ctl_table_header *mptcp_sysctl_binder; ++ ++/* General initialization of MPTCP_PM */ ++static int __init binder_register(void) ++{ ++ mptcp_gws = kzalloc(sizeof(*mptcp_gws), GFP_KERNEL); ++ if (!mptcp_gws) ++ return -ENOMEM; ++ ++ rwlock_init(&mptcp_gws_lock); ++ ++ BUILD_BUG_ON(sizeof(struct binder_priv) > MPTCP_PM_SIZE); ++ ++ mptcp_sysctl_binder = register_net_sysctl(&init_net, "net/mptcp", ++ binder_table); ++ if (!mptcp_sysctl_binder) ++ goto sysctl_fail; ++ ++ if (mptcp_register_path_manager(&binder)) ++ goto pm_failed; ++ ++ return 0; ++ ++pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++sysctl_fail: ++ kfree(mptcp_gws); ++ ++ return -1; ++} ++ ++static void binder_unregister(void) ++{ ++ mptcp_unregister_path_manager(&binder); ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++ kfree(mptcp_gws); ++} ++ ++module_init(binder_register); ++module_exit(binder_unregister); ++ ++MODULE_AUTHOR("Luca Boccassi, Duncan Eastoe, Christoph Paasch (ndiffports)"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BINDER MPTCP"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_coupled.c mptcp-mptcp_v0.93/net/mptcp/mptcp_coupled.c +--- linux-4.9.162/net/mptcp/mptcp_coupled.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_coupled.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,270 @@ ++/* ++ * MPTCP implementation - Linked Increase congestion control Algorithm (LIA) ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++#include ++#include ++ ++#include ++ ++/* Scaling is done in the numerator with alpha_scale_num and in the denominator ++ * with alpha_scale_den. ++ * ++ * To downscale, we just need to use alpha_scale. ++ * ++ * We have: alpha_scale = alpha_scale_num / (alpha_scale_den ^ 2) ++ */ ++static int alpha_scale_den = 10; ++static int alpha_scale_num = 32; ++static int alpha_scale = 12; ++ ++struct mptcp_ccc { ++ u64 alpha; ++ bool forced_update; ++}; ++ ++static inline int mptcp_ccc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_alpha(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha; ++} ++ ++static inline void mptcp_set_alpha(const struct sock *meta_sk, u64 alpha) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha = alpha; ++} ++ ++static inline u64 mptcp_ccc_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_ccc_recalc_alpha(const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ const struct sock *sub_sk; ++ int best_cwnd = 0, best_rtt = 0, can_send = 0; ++ u64 max_numerator = 0, sum_denominator = 0, alpha = 1; ++ ++ if (!mpcb) ++ return; ++ ++ /* Only one subflow left - fall back to normal reno-behavior ++ * (set alpha to 1) ++ */ ++ if (mpcb->cnt_established <= 1) ++ goto exit; ++ ++ /* Do regular alpha-calculation for multiple subflows */ ++ ++ /* Find the max numerator of the alpha-calculation */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ can_send++; ++ ++ /* We need to look for the path, that provides the max-value. ++ * Integer-overflow is not possible here, because ++ * tmp will be in u64. ++ */ ++ tmp = div64_u64(mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_num), (u64)sub_tp->srtt_us * sub_tp->srtt_us); ++ ++ if (tmp >= max_numerator) { ++ max_numerator = tmp; ++ best_cwnd = sub_tp->snd_cwnd; ++ best_rtt = sub_tp->srtt_us; ++ } ++ } ++ ++ /* No subflow is able to send - we don't care anymore */ ++ if (unlikely(!can_send)) ++ goto exit; ++ ++ /* Calculate the denominator */ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ sum_denominator += div_u64( ++ mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_den) * best_rtt, ++ sub_tp->srtt_us); ++ } ++ sum_denominator *= sum_denominator; ++ if (unlikely(!sum_denominator)) { ++ pr_err("%s: sum_denominator == 0, cnt_established:%d\n", ++ __func__, mpcb->cnt_established); ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ pr_err("%s: pi:%d, state:%d\n, rtt:%u, cwnd: %u", ++ __func__, sub_tp->mptcp->path_index, ++ sub_sk->sk_state, sub_tp->srtt_us, ++ sub_tp->snd_cwnd); ++ } ++ } ++ ++ alpha = div64_u64(mptcp_ccc_scale(best_cwnd, alpha_scale_num), sum_denominator); ++ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++exit: ++ mptcp_set_alpha(mptcp_meta_sk(sk), alpha); ++} ++ ++static void mptcp_ccc_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ mptcp_set_alpha(mptcp_meta_sk(sk), 1); ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mptcp_ccc_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_LOSS) ++ mptcp_ccc_recalc_alpha(sk); ++} ++ ++static void mptcp_ccc_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(mptcp_meta_sk(sk), 1); ++} ++ ++static void mptcp_ccc_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_ccc_recalc_alpha(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_ccc_recalc_alpha(sk); ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ } ++ ++ if (mpcb->cnt_established > 1) { ++ u64 alpha = mptcp_get_alpha(mptcp_meta_sk(sk)); ++ ++ /* This may happen, if at the initialization, the mpcb ++ * was not yet attached to the sock, and thus ++ * initializing alpha failed. ++ */ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++ snd_cwnd = (int) div_u64 ((u64) mptcp_ccc_scale(1, alpha_scale), ++ alpha); ++ ++ /* snd_cwnd_cnt >= max (scale * tot_cwnd / alpha, cwnd) ++ * Thus, we select here the max value. ++ */ ++ if (snd_cwnd < tp->snd_cwnd) ++ snd_cwnd = tp->snd_cwnd; ++ } else { ++ snd_cwnd = tp->snd_cwnd; ++ } ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_ccc_recalc_alpha(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_ccc = { ++ .init = mptcp_ccc_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_ccc_cong_avoid, ++ .cwnd_event = mptcp_ccc_cwnd_event, ++ .set_state = mptcp_ccc_set_state, ++ .owner = THIS_MODULE, ++ .name = "lia", ++}; ++ ++static int __init mptcp_ccc_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_ccc) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_ccc); ++} ++ ++static void __exit mptcp_ccc_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_ccc); ++} ++ ++module_init(mptcp_ccc_register); ++module_exit(mptcp_ccc_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch, Sébastien Barré"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP LINKED INCREASE CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_ctrl.c mptcp-mptcp_v0.93/net/mptcp/mptcp_ctrl.c +--- linux-4.9.162/net/mptcp/mptcp_ctrl.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_ctrl.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,2971 @@ ++/* ++ * MPTCP implementation - MPTCP-control ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *mptcp_sock_cache __read_mostly; ++static struct kmem_cache *mptcp_cb_cache __read_mostly; ++static struct kmem_cache *mptcp_tw_cache __read_mostly; ++ ++int sysctl_mptcp_enabled __read_mostly = 1; ++EXPORT_SYMBOL(sysctl_mptcp_enabled); ++int sysctl_mptcp_version __read_mostly = 0; ++static int min_mptcp_version; ++static int max_mptcp_version = 1; ++int sysctl_mptcp_checksum __read_mostly = 1; ++int sysctl_mptcp_debug __read_mostly; ++EXPORT_SYMBOL(sysctl_mptcp_debug); ++int sysctl_mptcp_syn_retries __read_mostly = 3; ++ ++bool mptcp_init_failed __read_mostly; ++ ++struct static_key mptcp_static_key = STATIC_KEY_INIT_FALSE; ++EXPORT_SYMBOL(mptcp_static_key); ++ ++static int proc_mptcp_path_manager(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_PM_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_path_manager(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_path_manager(val); ++ return ret; ++} ++ ++static int proc_mptcp_scheduler(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_SCHED_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_scheduler(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_scheduler(val); ++ return ret; ++} ++ ++static struct ctl_table mptcp_table[] = { ++ { ++ .procname = "mptcp_enabled", ++ .data = &sysctl_mptcp_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_version", ++ .data = &sysctl_mptcp_version, ++ .mode = 0644, ++ .maxlen = sizeof(int), ++ .proc_handler = &proc_dointvec_minmax, ++ .extra1 = &min_mptcp_version, ++ .extra2 = &max_mptcp_version, ++ }, ++ { ++ .procname = "mptcp_checksum", ++ .data = &sysctl_mptcp_checksum, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_debug", ++ .data = &sysctl_mptcp_debug, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_syn_retries", ++ .data = &sysctl_mptcp_syn_retries, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_path_manager", ++ .mode = 0644, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ .proc_handler = proc_mptcp_path_manager, ++ }, ++ { ++ .procname = "mptcp_scheduler", ++ .mode = 0644, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ .proc_handler = proc_mptcp_scheduler, ++ }, ++ { } ++}; ++ ++static inline u32 mptcp_hash_tk(u32 token) ++{ ++ return token % MPTCP_HASH_SIZE; ++} ++ ++struct hlist_nulls_head tk_hashtable[MPTCP_HASH_SIZE]; ++EXPORT_SYMBOL(tk_hashtable); ++ ++/* The following hash table is used to avoid collision of token */ ++static struct hlist_nulls_head mptcp_reqsk_tk_htb[MPTCP_HASH_SIZE]; ++ ++/* Lock, protecting the two hash-tables that hold the token. Namely, ++ * mptcp_reqsk_tk_htb and tk_hashtable ++ */ ++static spinlock_t mptcp_tk_hashlock; ++ ++static bool mptcp_reqsk_find_tk(const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct mptcp_request_sock *mtreqsk; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(mtreqsk, node, ++ &mptcp_reqsk_tk_htb[hash], hash_entry) { ++ if (token == mtreqsk->mptcp_loc_token) ++ return true; ++ } ++ /* A request-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_reqsk_insert_tk(struct request_sock *reqsk, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ ++ hlist_nulls_add_head_rcu(&mptcp_rsk(reqsk)->hash_entry, ++ &mptcp_reqsk_tk_htb[hash]); ++} ++ ++static void mptcp_reqsk_remove_tk(const struct request_sock *reqsk) ++{ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&mptcp_rsk(reqsk)->hash_entry); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++void mptcp_reqsk_destructor(struct request_sock *req) ++{ ++ if (!mptcp_rsk(req)->is_sub) ++ mptcp_reqsk_remove_tk(req); ++} ++ ++static void __mptcp_hash_insert(struct tcp_sock *meta_tp, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token); ++ hlist_nulls_add_head_rcu(&meta_tp->tk_table, &tk_hashtable[hash]); ++ meta_tp->inside_tk_table = 1; ++} ++ ++static bool mptcp_find_token(u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], tk_table) { ++ if (token == meta_tp->mptcp_loc_token) ++ return true; ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_set_key_reqsk(struct request_sock *req, ++ const struct sk_buff *skb, ++ u32 seed) ++{ ++ const struct inet_request_sock *ireq = inet_rsk(req); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ mtreq->mptcp_loc_key = mptcp_v4_get_key(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ mtreq->mptcp_loc_key = mptcp_v6_get_key(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#endif ++ } ++ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++} ++ ++/* New MPTCP-connection request, prepare a new token for the meta-socket that ++ * will be created in mptcp_check_req_master(), and store the received token. ++ */ ++static void mptcp_reqsk_new_mptcp(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tp->mptcp_ver) ++ mtreq->mptcp_ver = tp->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_reqsk(req, skb, mptcp_seed++); ++ } while (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)); ++ mptcp_reqsk_insert_tk(req, mtreq->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++} ++ ++static int mptcp_reqsk_new_cookie(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tcp_sk(sk)->mptcp_ver) ++ mtreq->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ mptcp_set_key_reqsk(req, skb, tcp_rsk(req)->snt_isn); ++ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return false; ++ } ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ ++ return true; ++} ++ ++static void mptcp_set_key_sk(const struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_sock *isk = inet_sk(sk); ++ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp_loc_key = mptcp_v4_get_key(isk->inet_saddr, ++ isk->inet_daddr, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp_loc_key = mptcp_v6_get_key(inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#endif ++ ++ mptcp_key_sha1(tp->mptcp_loc_key, ++ &tp->mptcp_loc_token, NULL); ++} ++ ++#ifdef HAVE_JUMP_LABEL ++static atomic_t mptcp_needed_deferred; ++static atomic_t mptcp_wanted; ++ ++static void mptcp_clear(struct work_struct *work) ++{ ++ int deferred = atomic_xchg(&mptcp_needed_deferred, 0); ++ int wanted; ++ ++ wanted = atomic_add_return(deferred, &mptcp_wanted); ++ if (wanted > 0) ++ static_key_enable(&mptcp_static_key); ++ else ++ static_key_disable(&mptcp_static_key); ++} ++ ++static DECLARE_WORK(mptcp_work, mptcp_clear); ++#endif ++ ++static void mptcp_enable_static_key_bh(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 0) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted + 1) == wanted) ++ return; ++ } ++ atomic_inc(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++static void mptcp_enable_static_key(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ atomic_inc(&mptcp_wanted); ++ static_key_enable(&mptcp_static_key); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_disable_static_key(void) ++{ ++#ifdef HAVE_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 1) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted - 1) == wanted) ++ return; ++ } ++ atomic_dec(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_dec(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_enable_sock(struct sock *sk) ++{ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ sock_set_flag(sk, SOCK_MPTCP); ++ tcp_sk(sk)->mptcp_ver = sysctl_mptcp_version; ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ ++ mptcp_enable_static_key(); ++ } ++} ++ ++void mptcp_disable_sock(struct sock *sk) ++{ ++ if (sock_flag(sk, SOCK_MPTCP)) { ++ sock_reset_flag(sk, SOCK_MPTCP); ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &ipv4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &ipv6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &ipv6_specific; ++#endif ++ ++ mptcp_disable_static_key(); ++ } ++} ++ ++void mptcp_connect_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_sk(sk); ++ } while (mptcp_reqsk_find_tk(tp->mptcp_loc_token) || ++ mptcp_find_token(tp->mptcp_loc_token)); ++ ++ __mptcp_hash_insert(tp, tp->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVE); ++} ++ ++/** ++ * This function increments the refcount of the mpcb struct. ++ * It is the responsibility of the caller to decrement when releasing ++ * the structure. ++ */ ++struct sock *mptcp_hash_find(const struct net *net, const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token); ++ const struct tcp_sock *meta_tp; ++ struct sock *meta_sk = NULL; ++ const struct hlist_nulls_node *node; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[hash], ++ tk_table) { ++ meta_sk = (struct sock *)meta_tp; ++ if (token == meta_tp->mptcp_loc_token && ++ net_eq(net, sock_net(meta_sk))) { ++ if (unlikely(!atomic_inc_not_zero(&meta_sk->sk_refcnt))) ++ goto out; ++ if (unlikely(token != meta_tp->mptcp_loc_token || ++ !net_eq(net, sock_net(meta_sk)))) { ++ sock_gen_put(meta_sk); ++ goto begin; ++ } ++ goto found; ++ } ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++out: ++ meta_sk = NULL; ++found: ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return meta_sk; ++} ++ ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) ++{ ++ /* remove from the token hashtable */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&meta_tp->tk_table); ++ meta_tp->inside_tk_table = 0; ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk, *rttsk = NULL, *lastsk = NULL; ++ u32 min_time = 0, last_active = 0; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 elapsed; ++ ++ if (!mptcp_sk_can_send_ack(sk) || tp->pf) ++ continue; ++ ++ elapsed = keepalive_time_elapsed(tp); ++ ++ /* We take the one with the lowest RTT within a reasonable ++ * (meta-RTO)-timeframe ++ */ ++ if (elapsed < inet_csk(meta_sk)->icsk_rto) { ++ if (!min_time || tp->srtt_us < min_time) { ++ min_time = tp->srtt_us; ++ rttsk = sk; ++ } ++ continue; ++ } ++ ++ /* Otherwise, we just take the most recent active */ ++ if (!rttsk && (!last_active || elapsed < last_active)) { ++ last_active = elapsed; ++ lastsk = sk; ++ } ++ } ++ ++ if (rttsk) ++ return rttsk; ++ ++ return lastsk; ++} ++EXPORT_SYMBOL(mptcp_select_ack_sock); ++ ++static void mptcp_sock_def_error_report(struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ if (tp->send_mp_fclose && sk->sk_err == ETIMEDOUT) { ++ /* Called by the keep alive timer (tcp_write_timeout), ++ * when the limit of fastclose retransmissions has been ++ * reached. Send a TCP RST to clear the status of any ++ * stateful firewall (typically conntrack) which are ++ * not aware of mptcp and cannot understand the ++ * fastclose option. ++ */ ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ } ++ } ++ ++ if (mpcb->infinite_mapping_rcv || mpcb->infinite_mapping_snd || ++ mpcb->send_infinite_mapping) { ++ ++ meta_sk->sk_err = sk->sk_err; ++ meta_sk->sk_err_soft = sk->sk_err_soft; ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_error_report(meta_sk); ++ ++ WARN(meta_sk->sk_state == TCP_CLOSE, ++ "Meta already closed i_rcv %u i_snd %u send_i %u flags %#lx\n", ++ mpcb->infinite_mapping_rcv, mpcb->infinite_mapping_snd, ++ mpcb->send_infinite_mapping, meta_sk->sk_flags); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++ } ++ ++ if (mpcb->pm_ops->subflow_error) ++ mpcb->pm_ops->subflow_error(meta_sk, sk); ++ ++ sk->sk_err = 0; ++ return; ++} ++ ++static void mptcp_mpcb_put(struct mptcp_cb *mpcb) ++{ ++ if (atomic_dec_and_test(&mpcb->mpcb_refcnt)) { ++ mptcp_cleanup_path_manager(mpcb); ++ mptcp_cleanup_scheduler(mpcb); ++ kfree(mpcb->master_info); ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ } ++} ++ ++void mptcp_sock_destruct(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!is_meta_sk(sk) && !tp->was_meta_sk) { ++ BUG_ON(!hlist_unhashed(&tp->mptcp->cb_list)); ++ ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ tp->mptcp = NULL; ++ ++ /* Taken when mpcb pointer was set */ ++ sock_put(mptcp_meta_sk(sk)); ++ mptcp_mpcb_put(tp->mpcb); ++ } else { ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct mptcp_tw *mptw; ++ ++ /* The mpcb is disappearing - we can make the final ++ * update to the rcv_nxt of the time-wait-sock and remove ++ * its reference to the mpcb. ++ */ ++ spin_lock_bh(&mpcb->tw_lock); ++ list_for_each_entry_rcu(mptw, &mpcb->tw_list, list) { ++ list_del_rcu(&mptw->list); ++ mptw->in_list = 0; ++ mptcp_mpcb_put(mpcb); ++ rcu_assign_pointer(mptw->mpcb, NULL); ++ } ++ spin_unlock_bh(&mpcb->tw_lock); ++ ++ mptcp_mpcb_put(mpcb); ++ ++ mptcp_debug("%s destroying meta-sk\n", __func__); ++ } ++ ++ WARN_ON(!static_key_false(&mptcp_static_key)); ++ ++ /* Must be called here, because this will decrement the jump-label. */ ++ inet_sock_destruct(sk); ++} ++ ++void mptcp_destroy_sock(struct sock *sk) ++{ ++ if (is_meta_sk(sk)) { ++ struct sock *sk_it, *tmpsk; ++ ++ __skb_queue_purge(&tcp_sk(sk)->mpcb->reinject_queue); ++ ++ /* We have to close all remaining subflows. Normally, they ++ * should all be about to get closed. But, if the kernel is ++ * forcing a closure (e.g., tcp_write_err), the subflows might ++ * not have been closed properly (as we are waiting for the ++ * DATA_ACK of the DATA_FIN). ++ */ ++ mptcp_for_each_sk_safe(tcp_sk(sk)->mpcb, sk_it, tmpsk) { ++ /* Already did call tcp_close - waiting for graceful ++ * closure, or if we are retransmitting fast-close on ++ * the subflow. The reset (or timeout) will kill the ++ * subflow.. ++ */ ++ if (tcp_sk(sk_it)->closing || ++ tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ ++ /* Allow the delayed work first to prevent time-wait state */ ++ if (delayed_work_pending(&tcp_sk(sk_it)->mptcp->work)) ++ continue; ++ ++ mptcp_sub_close(sk_it, 0); ++ } ++ } else { ++ mptcp_del_sock(sk); ++ } ++} ++ ++static void mptcp_set_state(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* Meta is not yet established - wake up the application */ ++ if ((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) && ++ sk->sk_state == TCP_ESTABLISHED) { ++ tcp_set_state(meta_sk, TCP_ESTABLISHED); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ sk_wake_async(meta_sk, SOCK_WAKE_IO, POLL_OUT); ++ } ++ ++ tcp_sk(meta_sk)->lsndtime = tcp_time_stamp; ++ } ++ ++ if (sk->sk_state == TCP_ESTABLISHED) { ++ tcp_sk(sk)->mptcp->establish_increased = 1; ++ tcp_sk(sk)->mpcb->cnt_established++; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) { ++ if (!sock_flag(sk, SOCK_DEAD)) ++ mptcp_sub_close(sk, 0); ++ } ++} ++ ++static void mptcp_assign_congestion_control(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct inet_connection_sock *meta_icsk = inet_csk(mptcp_meta_sk(sk)); ++ const struct tcp_congestion_ops *ca = meta_icsk->icsk_ca_ops; ++ ++ /* Congestion control is the same as meta. Thus, it has been ++ * try_module_get'd by tcp_assign_congestion_control. ++ */ ++ if (icsk->icsk_ca_ops == ca) ++ return; ++ ++ /* Use the same congestion control as set on the meta-sk */ ++ if (!try_module_get(ca->owner)) { ++ /* This should never happen. The congestion control is linked ++ * to the meta-socket (through tcp_assign_congestion_control) ++ * who "holds" the refcnt on the module. ++ */ ++ WARN(1, "Could not get the congestion control!"); ++ return; ++ } ++ icsk->icsk_ca_ops = ca; ++ ++ /* Clear out private data before diag gets it and ++ * the ca has not been initialized. ++ */ ++ if (ca->get_info) ++ memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); ++ ++ return; ++} ++ ++u32 mptcp_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; ++u32 mptcp_seed = 0; ++ ++void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u32 mptcp_hashed_key[SHA_DIGEST_WORDS]; ++ u8 input[64]; ++ int i; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Initialize input with appropriate padding */ ++ memset(&input[9], 0, sizeof(input) - 10); /* -10, because the last byte ++ * is explicitly set too ++ */ ++ memcpy(input, &key, sizeof(key)); /* Copy key to the msg beginning */ ++ input[8] = 0x80; /* Padding: First bit after message = 1 */ ++ input[63] = 0x40; /* Padding: Length of the message = 64 bits */ ++ ++ sha_init(mptcp_hashed_key); ++ sha_transform(mptcp_hashed_key, input, workspace); ++ ++ for (i = 0; i < 5; i++) ++ mptcp_hashed_key[i] = cpu_to_be32(mptcp_hashed_key[i]); ++ ++ if (token) ++ *token = mptcp_hashed_key[0]; ++ if (idsn) ++ *idsn = *((u64 *)&mptcp_hashed_key[3]); ++} ++ ++void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, ...) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u8 input[128]; /* 2 512-bit blocks */ ++ int i; ++ int index; ++ int length; ++ u8 *msg; ++ va_list list; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Generate key xored with ipad */ ++ memset(input, 0x36, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ va_start(list, arg_num); ++ index = 64; ++ for (i = 0; i < arg_num; i++) { ++ length = va_arg(list, int); ++ msg = va_arg(list, u8 *); ++ BUG_ON(index + length > 125); /* Message is too long */ ++ memcpy(&input[index], msg, length); ++ index += length; ++ } ++ va_end(list); ++ ++ input[index] = 0x80; /* Padding: First bit after message = 1 */ ++ memset(&input[index + 1], 0, (126 - index)); ++ ++ /* Padding: Length of the message = 512 + message length (bits) */ ++ input[126] = 0x02; ++ input[127] = ((index - 64) * 8); /* Message length (bits) */ ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = cpu_to_be32(hash_out[i]); ++ ++ /* Prepare second part of hmac */ ++ memset(input, 0x5C, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ memcpy(&input[64], hash_out, 20); ++ input[84] = 0x80; ++ memset(&input[85], 0, 41); ++ ++ /* Padding: Length of the message = 512 + 160 bits */ ++ input[126] = 0x02; ++ input[127] = 0xA0; ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = cpu_to_be32(hash_out[i]); ++} ++EXPORT_SYMBOL(mptcp_hmac_sha1); ++ ++static void mptcp_mpcb_inherit_sockopts(struct sock *meta_sk, struct sock *master_sk) ++{ ++ /* Socket-options handled by sk_clone_lock while creating the meta-sk. ++ * ====== ++ * SO_SNDBUF, SO_SNDBUFFORCE, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVLOWAT, ++ * SO_RCVTIMEO, SO_SNDTIMEO, SO_ATTACH_FILTER, SO_DETACH_FILTER, ++ * TCP_NODELAY, TCP_CORK ++ * ++ * Socket-options handled in this function here ++ * ====== ++ * TCP_DEFER_ACCEPT ++ * SO_KEEPALIVE ++ * ++ * Socket-options on the todo-list ++ * ====== ++ * SO_BINDTODEVICE - should probably prevent creation of new subsocks ++ * across other devices. - what about the api-draft? ++ * SO_DEBUG ++ * SO_REUSEADDR - probably we don't care about this ++ * SO_DONTROUTE, SO_BROADCAST ++ * SO_OOBINLINE ++ * SO_LINGER ++ * SO_TIMESTAMP* - I don't think this is of concern for a SOCK_STREAM ++ * SO_PASSSEC - I don't think this is of concern for a SOCK_STREAM ++ * SO_RXQ_OVFL ++ * TCP_COOKIE_TRANSACTIONS ++ * TCP_MAXSEG ++ * TCP_THIN_* - Handled by sk_clone_lock, but we need to support this ++ * in mptcp_meta_retransmit_timer. AND we need to check ++ * what is about the subsockets. ++ * TCP_LINGER2 ++ * TCP_WINDOW_CLAMP ++ * TCP_USER_TIMEOUT ++ * TCP_MD5SIG ++ * ++ * Socket-options of no concern for the meta-socket (but for the subsocket) ++ * ====== ++ * SO_PRIORITY ++ * SO_MARK ++ * TCP_CONGESTION ++ * TCP_SYNCNT ++ * TCP_QUICKACK ++ */ ++ ++ /* DEFER_ACCEPT should not be set on the meta, as we want to accept new subflows directly */ ++ inet_csk(meta_sk)->icsk_accept_queue.rskq_defer_accept = 0; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(meta_sk, SOCK_KEEPOPEN)) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ keepalive_time_when(tcp_sk(meta_sk))); ++ sock_reset_flag(master_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(master_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(master_sk)->recverr = 0; ++} ++ ++static void mptcp_sub_inherit_sockopts(const struct sock *meta_sk, struct sock *sub_sk) ++{ ++ /* IP_TOS also goes to the subflow. */ ++ if (inet_sk(sub_sk)->tos != inet_sk(meta_sk)->tos) { ++ inet_sk(sub_sk)->tos = inet_sk(meta_sk)->tos; ++ sub_sk->sk_priority = meta_sk->sk_priority; ++ sk_dst_reset(sub_sk); ++ } ++ ++ /* Inherit SO_REUSEADDR */ ++ sub_sk->sk_reuse = meta_sk->sk_reuse; ++ ++ /* Inherit SO_MARK: can be used for routing or filtering */ ++ sub_sk->sk_mark = meta_sk->sk_mark; ++ ++ /* Inherit snd/rcv-buffer locks */ ++ sub_sk->sk_userlocks = meta_sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; ++ ++ /* Nagle/Cork is forced off on the subflows. It is handled at the meta-layer */ ++ tcp_sk(sub_sk)->nonagle = TCP_NAGLE_OFF|TCP_NAGLE_PUSH; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(sub_sk, SOCK_KEEPOPEN)) { ++ sock_reset_flag(sub_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(sub_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(sub_sk)->recverr = 0; ++} ++ ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) ++{ ++ /* In case of success (in mptcp_backlog_rcv) and error (in kfree_skb) of ++ * sk_add_backlog, we will decrement the sk refcount. ++ */ ++ sock_hold(sk); ++ skb->sk = sk; ++ skb->destructor = sock_efree; ++} ++ ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ /* skb-sk may be NULL if we receive a packet immediatly after the ++ * SYN/ACK + MP_CAPABLE. ++ */ ++ struct sock *sk = skb->sk ? skb->sk : meta_sk; ++ int ret = 0; ++ ++ if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ /* Decrement sk refcnt when calling the skb destructor. ++ * Refcnt is incremented and skb destructor is set in tcp_v{4,6}_rcv via ++ * mptcp_prepare_for_backlog() here above. ++ */ ++ skb_orphan(skb); ++ ++ if (sk->sk_family == AF_INET) ++ ret = tcp_v4_do_rcv(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ ret = tcp_v6_do_rcv(sk, skb); ++#endif ++ ++ sock_put(sk); ++ return ret; ++} ++ ++struct lock_class_key meta_key; ++char *meta_key_name = "sk_lock-AF_INET-MPTCP"; ++struct lock_class_key meta_slock_key; ++char *meta_slock_key_name = "slock-AF_INET-MPTCP"; ++ ++static const struct tcp_sock_ops mptcp_meta_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = mptcp_send_fin, ++ .write_xmit = mptcp_write_xmit, ++ .send_active_reset = mptcp_send_active_reset, ++ .write_wakeup = mptcp_write_wakeup, ++ .retransmit_timer = mptcp_meta_retransmit_timer, ++ .time_wait = mptcp_time_wait, ++ .cleanup_rbuf = mptcp_cleanup_rbuf, ++}; ++ ++static const struct tcp_sock_ops mptcp_sub_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .select_size = mptcp_select_size, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = mptcp_sub_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++}; ++ ++static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct mptcp_cb *mpcb; ++ struct sock *master_sk; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ struct tcp_sock *master_tp, *meta_tp = tcp_sk(meta_sk); ++ u64 snd_idsn, rcv_idsn; ++ ++ dst_release(meta_sk->sk_rx_dst); ++ meta_sk->sk_rx_dst = NULL; ++ /* This flag is set to announce sock_lock_init to ++ * reclassify the lock-class of the master socket. ++ */ ++ meta_tp->is_master_sk = 1; ++ master_sk = sk_clone_lock(meta_sk, GFP_ATOMIC | __GFP_ZERO); ++ meta_tp->is_master_sk = 0; ++ if (!master_sk) ++ goto err_alloc_master; ++ ++ master_tp = tcp_sk(master_sk); ++ ++ mpcb = kmem_cache_zalloc(mptcp_cb_cache, GFP_ATOMIC); ++ if (!mpcb) ++ goto err_alloc_mpcb; ++ ++ /* Store the mptcp version agreed on initial handshake */ ++ mpcb->mptcp_ver = mptcp_ver; ++ ++ /* Store the keys and generate the peer's token */ ++ mpcb->mptcp_loc_key = meta_tp->mptcp_loc_key; ++ mpcb->mptcp_loc_token = meta_tp->mptcp_loc_token; ++ ++ /* Generate Initial data-sequence-numbers */ ++ mptcp_key_sha1(mpcb->mptcp_loc_key, NULL, &snd_idsn); ++ snd_idsn = ntohll(snd_idsn) + 1; ++ mpcb->snd_high_order[0] = snd_idsn >> 32; ++ mpcb->snd_high_order[1] = mpcb->snd_high_order[0] - 1; ++ ++ mpcb->mptcp_rem_key = remote_key; ++ mptcp_key_sha1(mpcb->mptcp_rem_key, &mpcb->mptcp_rem_token, &rcv_idsn); ++ rcv_idsn = ntohll(rcv_idsn) + 1; ++ mpcb->rcv_high_order[0] = rcv_idsn >> 32; ++ mpcb->rcv_high_order[1] = mpcb->rcv_high_order[0] + 1; ++ ++ mpcb->meta_sk = meta_sk; ++ mpcb->master_sk = master_sk; ++ ++ skb_queue_head_init(&mpcb->reinject_queue); ++ mutex_init(&mpcb->mpcb_mutex); ++ ++ /* Init time-wait stuff */ ++ INIT_LIST_HEAD(&mpcb->tw_list); ++ spin_lock_init(&mpcb->tw_lock); ++ ++ INIT_HLIST_HEAD(&mpcb->callback_list); ++ ++ mpcb->orig_sk_rcvbuf = meta_sk->sk_rcvbuf; ++ mpcb->orig_sk_sndbuf = meta_sk->sk_sndbuf; ++ mpcb->orig_window_clamp = meta_tp->window_clamp; ++ ++ /* The meta is directly linked - set refcnt to 1 */ ++ atomic_set(&mpcb->mpcb_refcnt, 1); ++ ++ if (!meta_tp->inside_tk_table) { ++ /* Adding the meta_tp in the token hashtable - coming from server-side */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* With lockless listeners, we might process two ACKs at the ++ * same time. With TCP, inet_csk_complete_hashdance takes care ++ * of this. But, for MPTCP this would be too late if we add ++ * this MPTCP-socket in the token table (new subflows might ++ * come in and match on this socket here. ++ * So, we need to check if someone else already added the token ++ * and revert in that case. The other guy won the race... ++ */ ++ if (mptcp_find_token(mpcb->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ goto err_insert_token; ++ } ++ __mptcp_hash_insert(meta_tp, mpcb->mptcp_loc_token); ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ master_tp->inside_tk_table = 0; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_icsk->icsk_af_ops == &mptcp_v6_mapped) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ struct ipv6_txoptions *opt; ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ /* The following heavily inspired from tcp_v6_syn_recv_sock() */ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(master_sk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } ++ inet_csk(master_sk)->icsk_ext_hdr_len = 0; ++ if (opt) ++ inet_csk(master_sk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; ++ } ++#endif ++ ++ meta_tp->mptcp = NULL; ++ ++ meta_tp->write_seq = (u32)snd_idsn; ++ meta_tp->snd_sml = meta_tp->write_seq; ++ meta_tp->snd_una = meta_tp->write_seq; ++ meta_tp->snd_nxt = meta_tp->write_seq; ++ meta_tp->pushed_seq = meta_tp->write_seq; ++ meta_tp->snd_up = meta_tp->write_seq; ++ ++ meta_tp->copied_seq = (u32)rcv_idsn; ++ meta_tp->rcv_nxt = (u32)rcv_idsn; ++ meta_tp->rcv_wup = (u32)rcv_idsn; ++ ++ meta_tp->snd_wl1 = meta_tp->rcv_nxt - 1; ++ meta_tp->snd_wnd = window; ++ meta_tp->retrans_stamp = 0; /* Set in tcp_connect() */ ++ ++ meta_tp->packets_out = 0; ++ meta_icsk->icsk_probes_out = 0; ++ ++ /* Set mptcp-pointers */ ++ master_tp->mpcb = mpcb; ++ master_tp->meta_sk = meta_sk; ++ meta_tp->mpcb = mpcb; ++ meta_tp->meta_sk = meta_sk; ++ ++ meta_tp->was_meta_sk = 0; ++ ++ /* Initialize the queues */ ++ master_tp->out_of_order_queue = RB_ROOT; ++ tcp_prequeue_init(master_tp); ++ INIT_LIST_HEAD(&master_tp->tsq_node); ++ ++ master_tp->tsq_flags = 0; ++ /* icsk_bind_hash inherited from the meta, but it will be properly set in ++ * mptcp_create_master_sk. Same operation is done in inet_csk_clone_lock. ++ */ ++ inet_csk(master_sk)->icsk_bind_hash = NULL; ++ ++ /* Init the accept_queue structure, we support a queue of 32 pending ++ * connections, it does not need to be huge, since we only store here ++ * pending subflow creations. ++ */ ++ reqsk_queue_alloc(&meta_icsk->icsk_accept_queue); ++ meta_sk->sk_max_ack_backlog = 32; ++ meta_sk->sk_ack_backlog = 0; ++ ++ if (!sock_flag(meta_sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(meta_sk, SOCK_MPTCP); ++ } ++ ++ /* Redefine function-pointers as the meta-sk is now fully ready */ ++ meta_tp->mpc = 1; ++ meta_tp->ops = &mptcp_meta_specific; ++ ++ meta_sk->sk_backlog_rcv = mptcp_backlog_rcv; ++ meta_sk->sk_destruct = mptcp_sock_destruct; ++ ++ /* Meta-level retransmit timer */ ++ meta_icsk->icsk_rto *= 2; /* Double of initial - rto */ ++ ++ tcp_init_xmit_timers(master_sk); ++ /* Has been set for sending out the SYN */ ++ inet_csk_clear_xmit_timer(meta_sk, ICSK_TIME_RETRANS); ++ ++ mptcp_mpcb_inherit_sockopts(meta_sk, master_sk); ++ ++ mptcp_init_path_manager(mpcb); ++ mptcp_init_scheduler(mpcb); ++ ++ if (!try_module_get(inet_csk(master_sk)->icsk_ca_ops->owner)) ++ tcp_assign_congestion_control(master_sk); ++ ++ master_tp->saved_syn = NULL; ++ ++ mptcp_debug("%s: created mpcb with token %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ return 0; ++ ++err_insert_token: ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ ++err_alloc_mpcb: ++ inet_sk(master_sk)->inet_opt = NULL; ++ master_sk->sk_state = TCP_CLOSE; ++ sock_orphan(master_sk); ++ bh_unlock_sock(master_sk); ++ sk_free(master_sk); ++ ++err_alloc_master: ++ return -ENOBUFS; ++} ++ ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tp->mptcp = kmem_cache_zalloc(mptcp_sock_cache, flags); ++ if (!tp->mptcp) ++ return -ENOMEM; ++ ++ tp->mptcp->path_index = mptcp_set_new_pathindex(mpcb); ++ /* No more space for more subflows? */ ++ if (!tp->mptcp->path_index) { ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ return -EPERM; ++ } ++ ++ INIT_HLIST_NODE(&tp->mptcp->cb_list); ++ ++ tp->mptcp->tp = tp; ++ tp->mpcb = mpcb; ++ tp->meta_sk = meta_sk; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(sk, SOCK_MPTCP); ++ } ++ ++ tp->mpc = 1; ++ tp->ops = &mptcp_sub_specific; ++ ++ tp->mptcp->loc_id = loc_id; ++ tp->mptcp->rem_id = rem_id; ++ if (mpcb->sched_ops->init) ++ mpcb->sched_ops->init(sk); ++ ++ /* The corresponding sock_put is in mptcp_sock_destruct(). It cannot be ++ * included in mptcp_del_sock(), because the mpcb must remain alive ++ * until the last subsocket is completely destroyed. ++ */ ++ sock_hold(meta_sk); ++ atomic_inc(&mpcb->mpcb_refcnt); ++ ++ tp->mptcp->next = mpcb->connection_list; ++ mpcb->connection_list = tp; ++ tp->mptcp->attached = 1; ++ ++ mpcb->cnt_subflows++; ++ atomic_add(atomic_read(&((struct sock *)tp)->sk_rmem_alloc), ++ &meta_sk->sk_rmem_alloc); ++ ++ mptcp_sub_inherit_sockopts(meta_sk, sk); ++ INIT_DELAYED_WORK(&tp->mptcp->work, mptcp_sub_close_wq); ++ ++ /* Properly inherit CC from the meta-socket */ ++ mptcp_assign_congestion_control(sk); ++ ++ /* As we successfully allocated the mptcp_tcp_sock, we have to ++ * change the function-pointers here (for sk_destruct to work correctly) ++ */ ++ sk->sk_error_report = mptcp_sock_def_error_report; ++ sk->sk_data_ready = mptcp_data_ready; ++ sk->sk_write_space = mptcp_write_space; ++ sk->sk_state_change = mptcp_set_state; ++ sk->sk_destruct = mptcp_sock_destruct; ++ ++ if (sk->sk_family == AF_INET) ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI4:%d dst_addr:%pI4:%d, cnt_subflows now %d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, ++ &((struct inet_sock *)tp)->inet_saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &((struct inet_sock *)tp)->inet_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport), ++ mpcb->cnt_subflows); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI6:%d dst_addr:%pI6:%d, cnt_subflows now %d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &inet6_sk(sk)->saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &sk->sk_v6_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport), ++ mpcb->cnt_subflows); ++#endif ++ ++ return 0; ++} ++ ++void mptcp_del_sock(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *tp_prev; ++ struct mptcp_cb *mpcb; ++ ++ if (!tp->mptcp || !tp->mptcp->attached) ++ return; ++ ++ mpcb = tp->mpcb; ++ tp_prev = mpcb->connection_list; ++ ++ if (mpcb->sched_ops->release) ++ mpcb->sched_ops->release(sk); ++ ++ if (mpcb->pm_ops->delete_subflow) ++ mpcb->pm_ops->delete_subflow(sk); ++ ++ mptcp_debug("%s: Removing subsock tok %#x pi:%d state %d is_meta? %d\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ sk->sk_state, is_meta_sk(sk)); ++ ++ if (tp_prev == tp) { ++ mpcb->connection_list = tp->mptcp->next; ++ } else { ++ for (; tp_prev && tp_prev->mptcp->next; tp_prev = tp_prev->mptcp->next) { ++ if (tp_prev->mptcp->next == tp) { ++ tp_prev->mptcp->next = tp->mptcp->next; ++ break; ++ } ++ } ++ } ++ mpcb->cnt_subflows--; ++ if (tp->mptcp->establish_increased) ++ mpcb->cnt_established--; ++ ++ tp->mptcp->next = NULL; ++ tp->mptcp->attached = 0; ++ mpcb->path_index_bits &= ~(1 << tp->mptcp->path_index); ++ ++ if (!skb_queue_empty(&sk->sk_write_queue)) ++ mptcp_reinject_data(sk, 0); ++ ++ if (is_master_tp(tp)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (meta_tp->record_master_info && ++ !sock_flag(meta_sk, SOCK_DEAD)) { ++ mpcb->master_info = kmalloc(sizeof(*mpcb->master_info), ++ GFP_ATOMIC); ++ ++ if (mpcb->master_info) ++ tcp_get_info(sk, mpcb->master_info); ++ } ++ ++ mpcb->master_sk = NULL; ++ } else if (tp->mptcp->pre_established) { ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++ ++ rcu_assign_pointer(inet_sk(sk)->inet_opt, NULL); ++} ++ ++/* Updates the MPTCP-session based on path-manager information (e.g., addresses, ++ * low-prio flows,...). ++ */ ++void mptcp_update_metasocket(const struct sock *meta_sk) ++{ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->new_session) ++ tcp_sk(meta_sk)->mpcb->pm_ops->new_session(meta_sk); ++} ++ ++/* Clean up the receive buffer for full frames taken by the user, ++ * then send an ACK if necessary. COPIED is the number of bytes ++ * tcp_recvmsg has given to the user so far, it speeds up the ++ * calculation of whether or not we must ACK for the sake of ++ * a window update. ++ * (inspired from tcp_cleanup_rbuf()) ++ */ ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk; ++ bool recheck_rcv_window = false; ++ __u32 rcv_window_now = 0; ++ ++ if (copied > 0 && !(meta_sk->sk_shutdown & RCV_SHUTDOWN)) { ++ rcv_window_now = tcp_receive_window(meta_tp); ++ ++ /* Optimize, __mptcp_select_window() is not cheap. */ ++ if (2 * rcv_window_now <= meta_tp->window_clamp) ++ recheck_rcv_window = true; ++ } ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (!mptcp_sk_can_send_ack(sk)) ++ continue; ++ ++ if (!inet_csk_ack_scheduled(sk)) ++ goto second_part; ++ /* Delayed ACKs frequently hit locked sockets during bulk ++ * receive. ++ */ ++ if (icsk->icsk_ack.blocked || ++ /* Once-per-two-segments ACK was not sent by tcp_input.c */ ++ tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || ++ /* If this read emptied read buffer, we send ACK, if ++ * connection is not bidirectional, user drained ++ * receive buffer and there was a small segment ++ * in queue. ++ */ ++ (copied > 0 && ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && ++ !icsk->icsk_ack.pingpong)) && ++ !atomic_read(&meta_sk->sk_rmem_alloc))) { ++ tcp_send_ack(sk); ++ continue; ++ } ++ ++second_part: ++ /* This here is the second part of tcp_cleanup_rbuf */ ++ if (recheck_rcv_window) { ++ __u32 new_window = tp->ops->__select_window(sk); ++ ++ /* Send ACK now, if this read freed lots of space ++ * in our buffer. Certainly, new_window is new window. ++ * We can advertise it now, if it is not less than ++ * current one. ++ * "Lots" means "at least twice" here. ++ */ ++ if (new_window && new_window >= 2 * rcv_window_now) ++ tcp_send_ack(sk); ++ } ++ } ++} ++ ++static int mptcp_sub_send_fin(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *skb = tcp_write_queue_tail(sk); ++ int mss_now; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = tcp_current_mss(sk); ++ ++ if (tcp_send_head(sk) != NULL) { ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ tp->write_seq++; ++ } else { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (!skb) ++ return 1; ++ ++ /* Reserve space for headers and prepare control bits. */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ ++ tcp_init_nondata_skb(skb, tp->write_seq, ++ TCPHDR_ACK | TCPHDR_FIN); ++ tcp_queue_skb(sk, skb); ++ } ++ __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF); ++ ++ return 0; ++} ++ ++static void mptcp_sub_close_doit(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sock_flag(sk, SOCK_DEAD)) ++ return; ++ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) { ++ tp->closing = 1; ++ tcp_close(sk, 0); ++ } else if (tcp_close_state(sk)) { ++ sk->sk_shutdown |= SEND_SHUTDOWN; ++ tcp_send_fin(sk); ++ } ++} ++ ++void mptcp_sub_close_wq(struct work_struct *work) ++{ ++ struct tcp_sock *tp = container_of(work, struct mptcp_tcp_sock, work.work)->tp; ++ struct sock *sk = (struct sock *)tp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mutex_lock(&tp->mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_sub_close_doit(sk); ++ ++ release_sock(meta_sk); ++ mutex_unlock(&tp->mpcb->mpcb_mutex); ++ sock_put(sk); ++} ++ ++void mptcp_sub_close(struct sock *sk, unsigned long delay) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct delayed_work *work = &tcp_sk(sk)->mptcp->work; ++ ++ /* We are already closing - e.g., call from sock_def_error_report upon ++ * tcp_disconnect in tcp_close. ++ */ ++ if (tp->closing) ++ return; ++ ++ /* Work already scheduled ? */ ++ if (work_pending(&work->work)) { ++ /* Work present - who will be first ? */ ++ if (jiffies + delay > work->timer.expires) ++ return; ++ ++ /* Try canceling - if it fails, work will be executed soon */ ++ if (!cancel_delayed_work(work)) ++ return; ++ sock_put(sk); ++ } ++ ++ if (!delay) { ++ unsigned char old_state = sk->sk_state; ++ ++ /* We directly send the FIN. Because it may take so a long time, ++ * untile the work-queue will get scheduled... ++ * ++ * If mptcp_sub_send_fin returns 1, it failed and thus we reset ++ * the old state so that tcp_close will finally send the fin ++ * in user-context. ++ */ ++ if (!sk->sk_err && old_state != TCP_CLOSE && ++ tcp_close_state(sk) && mptcp_sub_send_fin(sk)) { ++ if (old_state == TCP_ESTABLISHED) ++ TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ sk->sk_state = old_state; ++ } ++ } ++ ++ sock_hold(sk); ++ queue_delayed_work(mptcp_wq, work, delay); ++} ++ ++void mptcp_sub_force_close(struct sock *sk) ++{ ++ /* The below tcp_done may have freed the socket, if he is already dead. ++ * Thus, we are not allowed to access it afterwards. That's why ++ * we have to store the dead-state in this local variable. ++ */ ++ int sock_is_dead = sock_flag(sk, SOCK_DEAD); ++ ++ tcp_sk(sk)->mp_killed = 1; ++ ++ if (sk->sk_state != TCP_CLOSE) ++ tcp_done(sk); ++ ++ if (!sock_is_dead) ++ mptcp_sub_close(sk, 0); ++} ++EXPORT_SYMBOL(mptcp_sub_force_close); ++ ++/* Update the mpcb send window, based on the contributions ++ * of each subflow ++ */ ++void mptcp_update_sndbuf(const struct tcp_sock *tp) ++{ ++ struct sock *meta_sk = tp->meta_sk, *sk; ++ int new_sndbuf = 0, old_sndbuf = meta_sk->sk_sndbuf; ++ ++ mptcp_for_each_sk(tp->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ new_sndbuf += sk->sk_sndbuf; ++ ++ if (new_sndbuf > sysctl_tcp_wmem[2] || new_sndbuf < 0) { ++ new_sndbuf = sysctl_tcp_wmem[2]; ++ break; ++ } ++ } ++ meta_sk->sk_sndbuf = max(min(new_sndbuf, sysctl_tcp_wmem[2]), meta_sk->sk_sndbuf); ++ ++ /* The subflow's call to sk_write_space in tcp_new_space ends up in ++ * mptcp_write_space. ++ * It has nothing to do with waking up the application. ++ * So, we do it here. ++ */ ++ if (old_sndbuf != meta_sk->sk_sndbuf) ++ meta_sk->sk_write_space(meta_sk); ++} ++ ++/* Similar to: tcp_close */ ++void mptcp_close(struct sock *meta_sk, long timeout) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk_it, *tmpsk; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int data_was_unread = 0; ++ int state; ++ ++ mptcp_debug("%s: Close of meta_sk with tok %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (meta_tp->inside_tk_table) ++ /* Detach the mpcb from the token hashtable */ ++ mptcp_hash_remove_bh(meta_tp); ++ ++ meta_sk->sk_shutdown = SHUTDOWN_MASK; ++ /* We need to flush the recv. buffs. We do this only on the ++ * descriptor close, not protocol-sourced closes, because the ++ * reader process may not have drained the data yet! ++ */ ++ while ((skb = __skb_dequeue(&meta_sk->sk_receive_queue)) != NULL) { ++ u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ len--; ++ data_was_unread += len; ++ __kfree_skb(skb); ++ } ++ ++ sk_mem_reclaim(meta_sk); ++ ++ /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ ++ if (meta_sk->sk_state == TCP_CLOSE) { ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ if (tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ mptcp_sub_close(sk_it, 0); ++ } ++ goto adjudge_to_death; ++ } ++ ++ if (data_was_unread) { ++ /* Unread data was tossed, zap the connection. */ ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONCLOSE); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ tcp_sk(meta_sk)->ops->send_active_reset(meta_sk, ++ meta_sk->sk_allocation); ++ } else if (sock_flag(meta_sk, SOCK_LINGER) && !meta_sk->sk_lingertime) { ++ /* Check zero linger _after_ checking for unread data. */ ++ meta_sk->sk_prot->disconnect(meta_sk, 0); ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ } else if (tcp_close_state(meta_sk)) { ++ mptcp_send_fin(meta_sk); ++ } else if (meta_tp->snd_una == meta_tp->write_seq) { ++ /* The DATA_FIN has been sent and acknowledged ++ * (e.g., by sk_shutdown). Close all the other subflows ++ */ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ unsigned long delay = 0; ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer. - thus we add a delay ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ ++ sk_stream_wait_close(meta_sk, timeout); ++ ++adjudge_to_death: ++ state = meta_sk->sk_state; ++ sock_hold(meta_sk); ++ sock_orphan(meta_sk); ++ ++ /* socket will be freed after mptcp_close - we have to prevent ++ * access from the subflows. ++ */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ /* Similar to sock_orphan, but we don't set it DEAD, because ++ * the callbacks are still set and must be called. ++ */ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_set_socket(sk_it, NULL); ++ sk_it->sk_wq = NULL; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ ++ /* It is the last release_sock in its life. It will remove backlog. */ ++ release_sock(meta_sk); ++ ++ /* Now socket is owned by kernel and we acquire BH lock ++ * to finish close. No need to check for user refs. ++ */ ++ local_bh_disable(); ++ bh_lock_sock(meta_sk); ++ WARN_ON(sock_owned_by_user(meta_sk)); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ /* Have we already been destroyed by a softirq or backlog? */ ++ if (state != TCP_CLOSE && meta_sk->sk_state == TCP_CLOSE) ++ goto out; ++ ++ /* This is a (useful) BSD violating of the RFC. There is a ++ * problem with TCP as specified in that the other end could ++ * keep a socket open forever with no application left this end. ++ * We use a 3 minute timeout (about the same as BSD) then kill ++ * our end. If they send after that then tough - BUT: long enough ++ * that we won't make the old 4*rto = almost no time - whoops ++ * reset mistake. ++ * ++ * Nope, it was not mistake. It is really desired behaviour ++ * f.e. on http servers, when such sockets are useless, but ++ * consume significant resources. Let's do it with special ++ * linger2 option. --ANK ++ */ ++ ++ if (meta_sk->sk_state == TCP_FIN_WAIT2) { ++ if (meta_tp->linger2 < 0) { ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONLINGER); ++ } else { ++ const int tmo = tcp_fin_time(meta_sk); ++ ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ tmo - TCP_TIMEWAIT_LEN); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, ++ tmo); ++ goto out; ++ } ++ } ++ } ++ if (meta_sk->sk_state != TCP_CLOSE) { ++ sk_mem_reclaim(meta_sk); ++ if (tcp_check_oom(meta_sk, 0)) { ++ if (net_ratelimit()) ++ pr_info("MPTCP: out of memory: force closing socket\n"); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONMEMORY); ++ } ++ } ++ ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ inet_csk_destroy_sock(meta_sk); ++ /* Otherwise, socket is reprieved until protocol close. */ ++ ++out: ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); /* Taken by sock_hold */ ++} ++ ++void mptcp_disconnect(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk, *tmpsk; ++ ++ __skb_queue_purge(&meta_tp->mpcb->reinject_queue); ++ ++ if (meta_tp->inside_tk_table) ++ mptcp_hash_remove_bh(meta_tp); ++ ++ local_bh_disable(); ++ mptcp_for_each_sk_safe(meta_tp->mpcb, subsk, tmpsk) { ++ if (spin_is_locked(&subsk->sk_lock.slock)) ++ bh_unlock_sock(subsk); ++ ++ meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); ++ ++ sock_orphan(subsk); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ inet_csk_destroy_sock(subsk); ++ } ++ local_bh_enable(); ++ ++ meta_tp->was_meta_sk = 1; ++ meta_tp->mpc = 0; ++ meta_tp->ops = &tcp_specific; ++} ++ ++ ++/* Returns 1 if we should enable MPTCP for that socket. */ ++int mptcp_doit(struct sock *sk) ++{ ++ /* Don't do mptcp over loopback */ ++ if (sk->sk_family == AF_INET && ++ (ipv4_is_loopback(inet_sk(sk)->inet_daddr) || ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr))) ++ return 0; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (sk->sk_family == AF_INET6 && ++ (ipv6_addr_loopback(&sk->sk_v6_daddr) || ++ ipv6_addr_loopback(&inet6_sk(sk)->saddr))) ++ return 0; ++#endif ++ if (mptcp_v6_is_v4_mapped(sk) && ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr)) ++ return 0; ++ ++#ifdef CONFIG_TCP_MD5SIG ++ /* If TCP_MD5SIG is enabled, do not do MPTCP - there is no Option-Space */ ++ if (tcp_sk(sk)->af_specific->md5_lookup(sk, sk)) ++ return 0; ++#endif ++ ++ return 1; ++} ++ ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ __u8 mptcp_ver, u32 window) ++{ ++ struct tcp_sock *master_tp; ++ struct sock *master_sk; ++ ++ if (mptcp_alloc_mpcb(meta_sk, remote_key, mptcp_ver, window)) ++ goto err_alloc_mpcb; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ master_tp = tcp_sk(master_sk); ++ ++ if (mptcp_add_sock(meta_sk, master_sk, 0, 0, GFP_ATOMIC)) ++ goto err_add_sock; ++ ++ if (__inet_inherit_port(meta_sk, master_sk) < 0) ++ goto err_add_sock; ++ ++ meta_sk->sk_prot->unhash(meta_sk); ++ inet_ehash_nolisten(master_sk, NULL); ++ ++ master_tp->mptcp->init_rcv_wnd = master_tp->rcv_wnd; ++ ++ return 0; ++ ++err_add_sock: ++ inet_csk_prepare_forced_close(master_sk); ++ tcp_done(master_sk); ++ ++err_alloc_mpcb: ++ return -ENOBUFS; ++} ++ ++static int __mptcp_check_req_master(struct sock *child, ++ struct request_sock *req) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct sock *meta_sk = child; ++ struct mptcp_cb *mpcb; ++ struct mptcp_request_sock *mtreq; ++ ++ /* Never contained an MP_CAPABLE */ ++ if (!inet_rsk(req)->mptcp_rqsk) ++ return 1; ++ ++ if (!inet_rsk(req)->saw_mpc) { ++ /* Fallback to regular TCP, because we saw one SYN without ++ * MP_CAPABLE. In tcp_check_req we continue the regular path. ++ * But, the socket has been added to the reqsk_tk_htb, so we ++ * must still remove it. ++ */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); ++ mptcp_reqsk_remove_tk(req); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEACK); ++ ++ /* Just set this values to pass them to mptcp_alloc_mpcb */ ++ mtreq = mptcp_rsk(req); ++ child_tp->mptcp_loc_key = mtreq->mptcp_loc_key; ++ child_tp->mptcp_loc_token = mtreq->mptcp_loc_token; ++ ++ if (mptcp_create_master_sk(meta_sk, mtreq->mptcp_rem_key, ++ mtreq->mptcp_ver, child_tp->snd_wnd)) { ++ inet_csk_prepare_forced_close(meta_sk); ++ tcp_done(meta_sk); ++ ++ return -ENOBUFS; ++ } ++ ++ child = tcp_sk(child)->mpcb->master_sk; ++ child_tp = tcp_sk(child); ++ mpcb = child_tp->mpcb; ++ ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ ++ mpcb->dss_csum = mtreq->dss_csum; ++ mpcb->server_side = 1; ++ ++ /* Needs to be done here additionally, because when accepting a ++ * new connection we pass by __reqsk_free and not reqsk_free. ++ */ ++ mptcp_reqsk_remove_tk(req); ++ ++ /* Hold when creating the meta-sk in tcp_vX_syn_recv_sock. */ ++ sock_put(meta_sk); ++ ++ return 0; ++} ++ ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req) ++{ ++ struct sock *meta_sk = child, *master_sk; ++ struct sk_buff *skb; ++ u32 new_mapping; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ ++ /* We need to rewind copied_seq as it is set to IDSN + 1 and as we have ++ * pre-MPTCP data in the receive queue. ++ */ ++ tcp_sk(meta_sk)->copied_seq -= tcp_sk(master_sk)->rcv_nxt - ++ tcp_rsk(req)->rcv_isn - 1; ++ ++ /* Map subflow sequence number to data sequence numbers. We need to map ++ * these data to [IDSN - len - 1, IDSN[. ++ */ ++ new_mapping = tcp_sk(meta_sk)->copied_seq - tcp_rsk(req)->rcv_isn - 1; ++ ++ /* There should be only one skb: the SYN + data. */ ++ skb_queue_walk(&meta_sk->sk_receive_queue, skb) { ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* With fastopen we change the semantics of the relative subflow ++ * sequence numbers to deal with middleboxes that could add/remove ++ * multiple bytes in the SYN. We chose to start counting at rcv_nxt - 1 ++ * instead of the regular TCP ISN. ++ */ ++ tcp_sk(master_sk)->mptcp->rcv_isn = tcp_sk(master_sk)->rcv_nxt - 1; ++ ++ /* We need to update copied_seq of the master_sk to account for the ++ * already moved data to the meta receive queue. ++ */ ++ tcp_sk(master_sk)->copied_seq = tcp_sk(master_sk)->rcv_nxt; ++ ++ /* Handled by the master_sk */ ++ tcp_sk(meta_sk)->fastopen_rsk = NULL; ++ ++ return 0; ++} ++ ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ int drop) ++{ ++ struct sock *meta_sk = child; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, req); ++ if (ret) ++ return ret; ++ child = tcp_sk(child)->mpcb->master_sk; ++ ++ sock_rps_save_rxhash(child, skb); ++ ++ /* drop indicates that we come from tcp_check_req and thus need to ++ * handle the request-socket fully. ++ */ ++ if (drop) { ++ tcp_synack_rtt_meas(child, req); ++ inet_csk_complete_hashdance(sk, meta_sk, req, true); ++ } else { ++ /* Thus, we come from syn-cookies */ ++ atomic_set(&req->rsk_refcnt, 1); ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ u8 hash_mac_check[20]; ++ ++ child_tp->out_of_order_queue = RB_ROOT; ++ child_tp->inside_tk_table = 0; ++ ++ if (!mopt->join_ack) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKFAIL); ++ goto teardown; ++ } ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce); ++ ++ if (memcmp(hash_mac_check, (char *)&mopt->mptcp_recv_mac, 20)) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKMAC); ++ goto teardown; ++ } ++ ++ /* Point it to the same struct socket and wq as the meta_sk */ ++ sk_set_socket(child, meta_sk->sk_socket); ++ child->sk_wq = meta_sk->sk_wq; ++ ++ if (mptcp_add_sock(meta_sk, child, mtreq->loc_id, mtreq->rem_id, GFP_ATOMIC)) { ++ /* Has been inherited, but now child_tp->mptcp is NULL */ ++ child_tp->mpc = 0; ++ child_tp->ops = &tcp_specific; ++ ++ /* TODO when we support acking the third ack for new subflows, ++ * we should silently discard this third ack, by returning NULL. ++ * ++ * Maybe, at the retransmission we will have enough memory to ++ * fully add the socket to the meta-sk. ++ */ ++ goto teardown; ++ } ++ ++ /* The child is a clone of the meta socket, we must now reset ++ * some of the fields ++ */ ++ child_tp->mptcp->rcv_low_prio = mtreq->rcv_low_prio; ++ ++ /* We should allow proper increase of the snd/rcv-buffers. Thus, we ++ * use the original values instead of the bloated up ones from the ++ * clone. ++ */ ++ child->sk_sndbuf = mpcb->orig_sk_sndbuf; ++ child->sk_rcvbuf = mpcb->orig_sk_rcvbuf; ++ ++ child_tp->mptcp->slave_sk = 1; ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ child_tp->mptcp->init_rcv_wnd = req->rsk_rcv_wnd; ++ ++ child_tp->tsq_flags = 0; ++ ++ sock_rps_save_rxhash(child, skb); ++ tcp_synack_rtt_meas(child, req); ++ ++ /* Subflows do not use the accept queue, as they ++ * are attached immediately to the mpcb. ++ */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ ++ /* The refcnt is initialized to 2, because regular TCP will put him ++ * in the socket's listener queue. However, we do not have a listener-queue. ++ * So, we need to make sure that this request-sock indeed gets destroyed. ++ */ ++ reqsk_put(req); ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKRX); ++ return child; ++ ++teardown: ++ req->rsk_ops->send_reset(meta_sk, skb); ++ ++ /* Drop this request - sock creation failed. */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ inet_csk_prepare_forced_close(child); ++ tcp_done(child); ++ return meta_sk; ++} ++ ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_tw *mptw; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* A subsocket in tw can only receive data. So, if we are in ++ * infinite-receive, then we should not reply with a data-ack or act ++ * upon general MPTCP-signaling. We prevent this by simply not creating ++ * the mptcp_tw_sock. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ tw->mptcp_tw = NULL; ++ return 0; ++ } ++ ++ /* Alloc MPTCP-tw-sock */ ++ mptw = kmem_cache_alloc(mptcp_tw_cache, GFP_ATOMIC); ++ if (!mptw) { ++ tw->mptcp_tw = NULL; ++ return -ENOBUFS; ++ } ++ ++ atomic_inc(&mpcb->mpcb_refcnt); ++ ++ tw->mptcp_tw = mptw; ++ mptw->loc_key = mpcb->mptcp_loc_key; ++ mptw->meta_tw = mpcb->in_time_wait; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ if (mptw->meta_tw && mpcb->mptw_state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ rcu_assign_pointer(mptw->mpcb, mpcb); ++ ++ spin_lock_bh(&mpcb->tw_lock); ++ list_add_rcu(&mptw->list, &tp->mpcb->tw_list); ++ mptw->in_list = 1; ++ spin_unlock_bh(&mpcb->tw_lock); ++ ++ return 0; ++} ++ ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_cb *mpcb; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ mpcb = rcu_dereference(tw->mptcp_tw->mpcb); ++ ++ /* If we are still holding a ref to the mpcb, we have to remove ourself ++ * from the list and drop the ref properly. ++ */ ++ if (mpcb && atomic_inc_not_zero(&mpcb->mpcb_refcnt)) { ++ spin_lock(&mpcb->tw_lock); ++ if (tw->mptcp_tw->in_list) { ++ list_del_rcu(&tw->mptcp_tw->list); ++ tw->mptcp_tw->in_list = 0; ++ } ++ spin_unlock(&mpcb->tw_lock); ++ ++ /* Twice, because we increased it above */ ++ mptcp_mpcb_put(mpcb); ++ mptcp_mpcb_put(mpcb); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ kmem_cache_free(mptcp_tw_cache, tw->mptcp_tw); ++} ++ ++/* Updates the rcv_nxt of the time-wait-socks and allows them to ack a ++ * data-fin. ++ */ ++void mptcp_time_wait(struct sock *meta_sk, int state, int timeo) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tw *mptw; ++ ++ /* Used for sockets that go into tw after the meta ++ * (see mptcp_init_tw_sock()) ++ */ ++ meta_tp->mpcb->in_time_wait = 1; ++ meta_tp->mpcb->mptw_state = state; ++ ++ /* Update the time-wait-sock's information */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ list_for_each_entry_rcu(mptw, &meta_tp->mpcb->tw_list, list) { ++ mptw->meta_tw = 1; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(meta_tp); ++ ++ /* We want to ack a DATA_FIN, but are yet in FIN_WAIT_2 - ++ * pretend as if the DATA_FIN has already reached us, that way ++ * the checks in tcp_timewait_state_process will be good as the ++ * DATA_FIN comes in. ++ */ ++ if (state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ } ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++} ++ ++void mptcp_tsq_flags(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* It will be handled as a regular deferred-call */ ++ if (is_meta_sk(sk)) ++ return; ++ ++ if (hlist_unhashed(&tp->mptcp->cb_list)) { ++ hlist_add_head(&tp->mptcp->cb_list, &tp->mpcb->callback_list); ++ /* We need to hold it here, as the sock_hold is not assured ++ * by the release_sock as it is done in regular TCP. ++ * ++ * The subsocket may get inet_csk_destroy'd while it is inside ++ * the callback_list. ++ */ ++ sock_hold(sk); ++ } ++ ++ if (!test_and_set_bit(MPTCP_SUB_DEFERRED, &tcp_sk(meta_sk)->tsq_flags)) ++ sock_hold(meta_sk); ++} ++ ++void mptcp_tsq_sub_deferred(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ BUG_ON(!is_meta_sk(meta_sk) && !meta_tp->was_meta_sk); ++ ++ __sock_put(meta_sk); ++ hlist_for_each_entry_safe(mptcp, tmp, &meta_tp->mpcb->callback_list, cb_list) { ++ struct tcp_sock *tp = mptcp->tp; ++ struct sock *sk = (struct sock *)tp; ++ ++ hlist_del_init(&mptcp->cb_list); ++ sk->sk_prot->release_cb(sk); ++ /* Final sock_put (cfr. mptcp_tsq_flags */ ++ sock_put(sk); ++ } ++} ++ ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct mptcp_options_received mopt; ++ u8 mptcp_hash_mac[20]; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->is_sub = 1; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ mtreq->mptcp_rem_nonce = mopt.mptcp_recv_nonce; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce); ++ mtreq->mptcp_hash_tmac = *(u64 *)mptcp_hash_mac; ++ ++ mtreq->rem_id = mopt.rem_id; ++ mtreq->rcv_low_prio = mopt.low_prio; ++ inet_rsk(req)->saw_mpc = 1; ++ ++ MPTCP_INC_STATS(sock_net(mpcb->meta_sk), MPTCP_MIB_JOINSYNRX); ++} ++ ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_options_received mopt; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->dss_csum = mopt.dss_csum; ++ ++ if (want_cookie) { ++ if (!mptcp_reqsk_new_cookie(req, sk, &mopt, skb)) ++ /* No key available - back to regular TCP */ ++ inet_rsk(req)->mptcp_rqsk = 0; ++ return; ++ } ++ ++ mptcp_reqsk_new_mptcp(req, sk, &mopt, skb); ++} ++ ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* Absolutely need to always initialize this. */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->mptcp_loc_key = mopt->mptcp_receiver_key; ++ ++ /* Generate the token */ ++ mptcp_key_sha1(mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* Check, if the key is still free */ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) ++ goto out; ++ ++ inet_rsk(req)->saw_mpc = 1; ++ mtreq->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ mtreq->dss_csum = mopt->dss_csum; ++ ++out: ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb) ++{ ++ struct mptcp_options_received mopt; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ if (mopt.is_mp_join) ++ return mptcp_do_join_short(skb, &mopt, sock_net(sk)); ++ if (mopt.drop_me) ++ goto drop; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) ++ mopt.saw_mpc = 0; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ if (mopt.saw_mpc) { ++ if (skb_rtable(skb)->rt_flags & ++ (RTCF_BROADCAST | RTCF_MULTICAST)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_request_sock_ipv4_ops, ++ sk, skb); ++ } ++ ++ return tcp_v4_conn_request(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ if (mopt.saw_mpc) { ++ if (!ipv6_unicast_destination(skb)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_request_sock_ipv6_ops, ++ sk, skb); ++ } ++ ++ return tcp_v6_conn_request(sk, skb); ++#endif ++ } ++drop: ++ __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); ++ return 0; ++} ++ ++static void __mptcp_get_info(const struct sock *meta_sk, ++ struct mptcp_meta_info *info) ++{ ++ const struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 now = tcp_time_stamp; ++ unsigned int start; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ info->mptcpi_state = meta_sk->sk_state; ++ info->mptcpi_retransmits = meta_icsk->icsk_retransmits; ++ info->mptcpi_probes = meta_icsk->icsk_probes_out; ++ info->mptcpi_backoff = meta_icsk->icsk_backoff; ++ ++ info->mptcpi_rto = jiffies_to_usecs(meta_icsk->icsk_rto); ++ ++ info->mptcpi_unacked = meta_tp->packets_out; ++ ++ info->mptcpi_last_data_sent = jiffies_to_msecs(now - meta_tp->lsndtime); ++ info->mptcpi_last_data_recv = jiffies_to_msecs(now - meta_icsk->icsk_ack.lrcvtime); ++ info->mptcpi_last_ack_recv = jiffies_to_msecs(now - meta_tp->rcv_tstamp); ++ ++ info->mptcpi_total_retrans = meta_tp->total_retrans; ++ ++ do { ++ start = u64_stats_fetch_begin_irq(&meta_tp->syncp); ++ info->mptcpi_bytes_acked = meta_tp->bytes_acked; ++ info->mptcpi_bytes_received = meta_tp->bytes_received; ++ } while (u64_stats_fetch_retry_irq(&meta_tp->syncp, start)); ++} ++ ++static void mptcp_get_sub_info(struct sock *sk, struct mptcp_sub_info *info) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ ++ memset(info, 0, sizeof(*info)); ++ ++ if (sk->sk_family == AF_INET) { ++ info->src_v4.sin_family = AF_INET; ++ info->src_v4.sin_port = inet->inet_sport; ++ ++ info->src_v4.sin_addr.s_addr = inet->inet_rcv_saddr; ++ if (!info->src_v4.sin_addr.s_addr) ++ info->src_v4.sin_addr.s_addr = inet->inet_saddr; ++ ++ info->dst_v4.sin_family = AF_INET; ++ info->dst_v4.sin_port = inet->inet_dport; ++ info->dst_v4.sin_addr.s_addr = inet->inet_daddr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ info->src_v6.sin6_family = AF_INET6; ++ info->src_v6.sin6_port = inet->inet_sport; ++ ++ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) ++ info->src_v6.sin6_addr = np->saddr; ++ else ++ info->src_v6.sin6_addr = sk->sk_v6_rcv_saddr; ++ ++ info->dst_v6.sin6_family = AF_INET6; ++ info->dst_v6.sin6_port = inet->inet_dport; ++ info->dst_v6.sin6_addr = sk->sk_v6_daddr; ++#endif ++ } ++} ++ ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *sk; ++ ++ struct mptcp_meta_info meta_info; ++ struct mptcp_info m_info; ++ ++ unsigned int info_len; ++ ++ if (copy_from_user(&m_info, optval, optlen)) ++ return -EFAULT; ++ ++ if (m_info.meta_info) { ++ unsigned int len; ++ ++ __mptcp_get_info(meta_sk, &meta_info); ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ len = min_t(unsigned int, m_info.meta_len, sizeof(meta_info)); ++ m_info.meta_len = len; ++ ++ if (copy_to_user((void __user *)m_info.meta_info, &meta_info, len)) ++ return -EFAULT; ++ } ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ info_len = min_t(unsigned int, m_info.tcp_info_len, sizeof(struct tcp_info)); ++ m_info.tcp_info_len = info_len; ++ ++ if (m_info.initial) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (mpcb->master_sk) { ++ struct tcp_info info; ++ ++ tcp_get_info(mpcb->master_sk, &info); ++ if (copy_to_user((void __user *)m_info.initial, &info, info_len)) ++ return -EFAULT; ++ } else if (meta_tp->record_master_info && mpcb->master_info) { ++ if (copy_to_user((void __user *)m_info.initial, mpcb->master_info, info_len)) ++ return -EFAULT; ++ } else { ++ return meta_tp->record_master_info ? -ENOMEM : -EINVAL; ++ } ++ } ++ ++ if (m_info.subflows) { ++ unsigned int len, sub_len = 0; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflows; ++ len = m_info.sub_len; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct tcp_info t_info; ++ unsigned int tmp_len; ++ ++ tcp_get_info(sk, &t_info); ++ ++ tmp_len = min_t(unsigned int, len, info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &t_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ sub_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.sub_len = sub_len; ++ } ++ ++ if (m_info.subflow_info) { ++ unsigned int len, sub_info_len, total_sub_info_len = 0; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflow_info; ++ len = m_info.total_sub_info_len; ++ ++ sub_info_len = min_t(unsigned int, m_info.sub_info_len, ++ sizeof(struct mptcp_sub_info)); ++ m_info.sub_info_len = sub_info_len; ++ ++ mptcp_for_each_sk(meta_tp->mpcb, sk) { ++ struct mptcp_sub_info m_sub_info; ++ unsigned int tmp_len; ++ ++ mptcp_get_sub_info(sk, &m_sub_info); ++ ++ tmp_len = min_t(unsigned int, len, sub_info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &m_sub_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ total_sub_info_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.total_sub_info_len = total_sub_info_len; ++ } ++ ++ if (copy_to_user(optval, &m_info, optlen)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++void mptcp_clear_sk(struct sock *sk, int size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* we do not want to clear tk_table field, because of RCU lookups */ ++ sk_prot_clear_nulls(sk, offsetof(struct tcp_sock, tk_table.next)); ++ ++ size -= offsetof(struct tcp_sock, tk_table.pprev); ++ memset((char *)&tp->tk_table.pprev, 0, size); ++} ++ ++static const struct snmp_mib mptcp_snmp_list[] = { ++ SNMP_MIB_ITEM("MPCapableSYNRX", MPTCP_MIB_MPCAPABLEPASSIVE), ++ SNMP_MIB_ITEM("MPCapableSYNTX", MPTCP_MIB_MPCAPABLEACTIVE), ++ SNMP_MIB_ITEM("MPCapableSYNACKRX", MPTCP_MIB_MPCAPABLEACTIVEACK), ++ SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK), ++ SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableRetransFallback", MPTCP_MIB_MPCAPABLERETRANSFALLBACK), ++ SNMP_MIB_ITEM("MPTCPCsumEnabled", MPTCP_MIB_CSUMENABLED), ++ SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), ++ SNMP_MIB_ITEM("MPFailRX", MPTCP_MIB_MPFAILRX), ++ SNMP_MIB_ITEM("MPCsumFail", MPTCP_MIB_CSUMFAIL), ++ SNMP_MIB_ITEM("MPFastcloseRX", MPTCP_MIB_FASTCLOSERX), ++ SNMP_MIB_ITEM("MPFastcloseTX", MPTCP_MIB_FASTCLOSETX), ++ SNMP_MIB_ITEM("MPFallbackAckSub", MPTCP_MIB_FBACKSUB), ++ SNMP_MIB_ITEM("MPFallbackAckInit", MPTCP_MIB_FBACKINIT), ++ SNMP_MIB_ITEM("MPFallbackDataSub", MPTCP_MIB_FBDATASUB), ++ SNMP_MIB_ITEM("MPFallbackDataInit", MPTCP_MIB_FBDATAINIT), ++ SNMP_MIB_ITEM("MPRemoveAddrSubDelete", MPTCP_MIB_REMADDRSUB), ++ SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), ++ SNMP_MIB_ITEM("MPJoinAlreadyFallenback", MPTCP_MIB_JOINFALLBACK), ++ SNMP_MIB_ITEM("MPJoinSynTx", MPTCP_MIB_JOINSYNTX), ++ SNMP_MIB_ITEM("MPJoinSynRx", MPTCP_MIB_JOINSYNRX), ++ SNMP_MIB_ITEM("MPJoinSynAckRx", MPTCP_MIB_JOINSYNACKRX), ++ SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX), ++ SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckMissing", MPTCP_MIB_JOINACKFAIL), ++ SNMP_MIB_ITEM("MPJoinAckRTO", MPTCP_MIB_JOINACKRTO), ++ SNMP_MIB_ITEM("MPJoinAckRexmit", MPTCP_MIB_JOINACKRXMIT), ++ SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), ++ SNMP_MIB_ITEM("DSSNotMatching", MPTCP_MIB_DSSNOMATCH), ++ SNMP_MIB_ITEM("InfiniteMapRx", MPTCP_MIB_INFINITEMAPRX), ++ SNMP_MIB_ITEM("DSSNoMatchTCP", MPTCP_MIB_DSSTCPMISMATCH), ++ SNMP_MIB_ITEM("DSSTrimHead", MPTCP_MIB_DSSTRIMHEAD), ++ SNMP_MIB_ITEM("DSSSplitTail", MPTCP_MIB_DSSSPLITTAIL), ++ SNMP_MIB_ITEM("DSSPurgeOldSubSegs", MPTCP_MIB_PURGEOLD), ++ SNMP_MIB_ITEM("AddAddrRx", MPTCP_MIB_ADDADDRRX), ++ SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), ++ SNMP_MIB_ITEM("RemAddrRx", MPTCP_MIB_REMADDRRX), ++ SNMP_MIB_ITEM("RemAddrTx", MPTCP_MIB_REMADDRTX), ++ SNMP_MIB_SENTINEL ++}; ++ ++struct workqueue_struct *mptcp_wq; ++EXPORT_SYMBOL(mptcp_wq); ++ ++/* Output /proc/net/mptcp */ ++static int mptcp_pm_seq_show(struct seq_file *seq, void *v) ++{ ++ struct tcp_sock *meta_tp; ++ const struct net *net = seq->private; ++ int i, n = 0; ++ ++ seq_printf(seq, " sl loc_tok rem_tok v6 local_address remote_address st ns tx_queue rx_queue inode"); ++ seq_putc(seq, '\n'); ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ struct hlist_nulls_node *node; ++ rcu_read_lock(); ++ local_bh_disable(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &tk_hashtable[i], tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp; ++ struct inet_sock *isk = inet_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (!mptcp(meta_tp) || !net_eq(net, sock_net(meta_sk))) ++ continue; ++ ++ if (!mpcb) ++ continue; ++ ++ if (capable(CAP_NET_ADMIN)) { ++ seq_printf(seq, "%4d: %04X %04X ", n++, ++ mpcb->mptcp_loc_token, ++ mpcb->mptcp_rem_token); ++ } else { ++ seq_printf(seq, "%4d: %04X %04X ", n++, -1, -1); ++ } ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ seq_printf(seq, " 0 %08X:%04X %08X:%04X ", ++ isk->inet_rcv_saddr, ++ ntohs(isk->inet_sport), ++ isk->inet_daddr, ++ ntohs(isk->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct in6_addr *src = &meta_sk->sk_v6_rcv_saddr; ++ struct in6_addr *dst = &meta_sk->sk_v6_daddr; ++ seq_printf(seq, " 1 %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X", ++ src->s6_addr32[0], src->s6_addr32[1], ++ src->s6_addr32[2], src->s6_addr32[3], ++ ntohs(isk->inet_sport), ++ dst->s6_addr32[0], dst->s6_addr32[1], ++ dst->s6_addr32[2], dst->s6_addr32[3], ++ ntohs(isk->inet_dport)); ++#endif ++ } ++ seq_printf(seq, " %02X %02X %08X:%08X %lu", ++ meta_sk->sk_state, mpcb->cnt_subflows, ++ meta_tp->write_seq - meta_tp->snd_una, ++ max_t(int, meta_tp->rcv_nxt - ++ meta_tp->copied_seq, 0), ++ sock_i_ino(meta_sk)); ++ seq_putc(seq, '\n'); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++ return 0; ++} ++ ++static int mptcp_pm_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_pm_seq_show); ++} ++ ++static const struct file_operations mptcp_pm_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_pm_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_snmp_seq_show(struct seq_file *seq, void *v) ++{ ++ struct net *net = seq->private; ++ int i; ++ ++ for (i = 0; mptcp_snmp_list[i].name != NULL; i++) ++ seq_printf(seq, "%-32s\t%ld\n", mptcp_snmp_list[i].name, ++ snmp_fold_field(net->mptcp.mptcp_statistics, ++ mptcp_snmp_list[i].entry)); ++ ++ return 0; ++} ++ ++static int mptcp_snmp_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_snmp_seq_show); ++} ++ ++static const struct file_operations mptcp_snmp_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_snmp_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_pm_init_net(struct net *net) ++{ ++ net->mptcp.mptcp_statistics = alloc_percpu(struct mptcp_mib); ++ if (!net->mptcp.mptcp_statistics) ++ goto out_mptcp_mibs; ++ ++#ifdef CONFIG_PROC_FS ++ net->mptcp.proc_net_mptcp = proc_net_mkdir(net, "mptcp_net", net->proc_net); ++ if (!net->mptcp.proc_net_mptcp) ++ goto out_proc_net_mptcp; ++ if (!proc_create("mptcp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ &mptcp_pm_seq_fops)) ++ goto out_mptcp_net_mptcp; ++ if (!proc_create("snmp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ &mptcp_snmp_seq_fops)) ++ goto out_mptcp_net_snmp; ++#endif ++ ++ return 0; ++ ++#ifdef CONFIG_PROC_FS ++out_mptcp_net_snmp: ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++out_mptcp_net_mptcp: ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ net->mptcp.proc_net_mptcp = NULL; ++out_proc_net_mptcp: ++ free_percpu(net->mptcp.mptcp_statistics); ++#endif ++out_mptcp_mibs: ++ return -ENOMEM; ++} ++ ++static void mptcp_pm_exit_net(struct net *net) ++{ ++ remove_proc_entry("snmp", net->mptcp.proc_net_mptcp); ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ free_percpu(net->mptcp.mptcp_statistics); ++} ++ ++static struct pernet_operations mptcp_pm_proc_ops = { ++ .init = mptcp_pm_init_net, ++ .exit = mptcp_pm_exit_net, ++}; ++ ++/* General initialization of mptcp */ ++void __init mptcp_init(void) ++{ ++ int i; ++ struct ctl_table_header *mptcp_sysctl; ++ ++ mptcp_sock_cache = kmem_cache_create("mptcp_sock", ++ sizeof(struct mptcp_tcp_sock), ++ 0, SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_sock_cache) ++ goto mptcp_sock_cache_failed; ++ ++ mptcp_cb_cache = kmem_cache_create("mptcp_cb", sizeof(struct mptcp_cb), ++ 0, SLAB_DESTROY_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_cb_cache) ++ goto mptcp_cb_cache_failed; ++ ++ mptcp_tw_cache = kmem_cache_create("mptcp_tw", sizeof(struct mptcp_tw), ++ 0, SLAB_DESTROY_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_tw_cache) ++ goto mptcp_tw_cache_failed; ++ ++ get_random_bytes(mptcp_secret, sizeof(mptcp_secret)); ++ ++ mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8); ++ if (!mptcp_wq) ++ goto alloc_workqueue_failed; ++ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ INIT_HLIST_NULLS_HEAD(&tk_hashtable[i], i); ++ INIT_HLIST_NULLS_HEAD(&mptcp_reqsk_tk_htb[i], i); ++ } ++ ++ spin_lock_init(&mptcp_tk_hashlock); ++ ++ if (register_pernet_subsys(&mptcp_pm_proc_ops)) ++ goto pernet_failed; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_pm_v6_init()) ++ goto mptcp_pm_v6_failed; ++#endif ++ if (mptcp_pm_v4_init()) ++ goto mptcp_pm_v4_failed; ++ ++ mptcp_sysctl = register_net_sysctl(&init_net, "net/mptcp", mptcp_table); ++ if (!mptcp_sysctl) ++ goto register_sysctl_failed; ++ ++ if (mptcp_register_path_manager(&mptcp_pm_default)) ++ goto register_pm_failed; ++ ++ if (mptcp_register_scheduler(&mptcp_sched_default)) ++ goto register_sched_failed; ++ ++ pr_info("MPTCP: Stable release v0.93.4"); ++ ++ mptcp_init_failed = false; ++ ++ return; ++ ++register_sched_failed: ++ mptcp_unregister_path_manager(&mptcp_pm_default); ++register_pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl); ++register_sysctl_failed: ++ mptcp_pm_v4_undo(); ++mptcp_pm_v4_failed: ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_pm_v6_undo(); ++mptcp_pm_v6_failed: ++#endif ++ unregister_pernet_subsys(&mptcp_pm_proc_ops); ++pernet_failed: ++ destroy_workqueue(mptcp_wq); ++alloc_workqueue_failed: ++ kmem_cache_destroy(mptcp_tw_cache); ++mptcp_tw_cache_failed: ++ kmem_cache_destroy(mptcp_cb_cache); ++mptcp_cb_cache_failed: ++ kmem_cache_destroy(mptcp_sock_cache); ++mptcp_sock_cache_failed: ++ mptcp_init_failed = true; ++} +diff -aurN linux-4.9.162/net/mptcp/mptcp_fullmesh.c mptcp-mptcp_v0.93/net/mptcp/mptcp_fullmesh.c +--- linux-4.9.162/net/mptcp/mptcp_fullmesh.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_fullmesh.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,2013 @@ ++#include ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++ ++enum { ++ MPTCP_EVENT_ADD = 1, ++ MPTCP_EVENT_DEL, ++ MPTCP_EVENT_MOD, ++}; ++ ++#define MPTCP_SUBFLOW_RETRY_DELAY 1000 ++ ++/* Max number of local or remote addresses we can store. ++ * When changing, see the bitfield below in fullmesh_rem4/6. ++ */ ++#define MPTCP_MAX_ADDR 8 ++ ++struct fullmesh_rem4 { ++ u8 rem4_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct fullmesh_rem6 { ++ u8 rem6_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_loc_addr { ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ u8 loc4_bits; ++ u8 next_v4_index; ++ ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++ u8 loc6_bits; ++ u8 next_v6_index; ++ struct rcu_head rcu; ++}; ++ ++struct mptcp_addr_event { ++ struct list_head list; ++ unsigned short family; ++ u8 code:7, ++ low_prio:1; ++ int if_idx; ++ union inet_addr addr; ++}; ++ ++struct fullmesh_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ /* Delayed worker, when the routing-tables are not yet ready. */ ++ struct delayed_work subflow_retry_work; ++ ++ /* Remote addresses */ ++ struct fullmesh_rem4 remaddr4[MPTCP_MAX_ADDR]; ++ struct fullmesh_rem6 remaddr6[MPTCP_MAX_ADDR]; ++ ++ struct mptcp_cb *mpcb; ++ ++ u16 remove_addrs; /* Addresses to remove */ ++ u8 announced_addrs_v4; /* IPv4 Addresses we did announce */ ++ u8 announced_addrs_v6; /* IPv6 Addresses we did announce */ ++ ++ u8 add_addr; /* Are we sending an add_addr? */ ++ ++ u8 rem4_bits; ++ u8 rem6_bits; ++ ++ /* Are we established the additional subflows for primary pair? */ ++ u8 first_pair:1; ++}; ++ ++struct mptcp_fm_ns { ++ struct mptcp_loc_addr __rcu *local; ++ spinlock_t local_lock; /* Protecting the above pointer */ ++ struct list_head events; ++ struct delayed_work address_worker; ++ ++ struct net *net; ++}; ++ ++static int num_subflows __read_mostly = 1; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per pair of IP addresses of MPTCP connection"); ++ ++static int create_on_err __read_mostly; ++module_param(create_on_err, int, 0644); ++MODULE_PARM_DESC(create_on_err, "recreate the subflow upon a timeout"); ++ ++static struct mptcp_pm_ops full_mesh __read_mostly; ++ ++static void full_mesh_create_subflows(struct sock *meta_sk); ++ ++static struct mptcp_fm_ns *fm_get_ns(const struct net *net) ++{ ++ return (struct mptcp_fm_ns *)net->mptcp.path_managers[MPTCP_PM_FULLMESH]; ++} ++ ++static struct fullmesh_priv *fullmesh_get_priv(const struct mptcp_cb *mpcb) ++{ ++ return (struct fullmesh_priv *)&mpcb->mptcp_pm[0]; ++} ++ ++/* Find the first free index in the bitfield */ ++static int __mptcp_find_free_index(u8 bitfield, u8 base) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ goto exit; ++ ++ i = ffs(~(bitfield >> base)) - 1; ++ if (i < 0) ++ goto exit; ++ ++ /* No free bits when starting at base, try from 0 on */ ++ if (i + base >= sizeof(bitfield) * 8) ++ return __mptcp_find_free_index(bitfield, 0); ++ ++ return i + base; ++exit: ++ return -1; ++} ++ ++static int mptcp_find_free_index(u8 bitfield) ++{ ++ return __mptcp_find_free_index(bitfield, 0); ++} ++ ++static void mptcp_addv4_raddr(struct mptcp_cb *mpcb, ++ const struct in_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem4 *rem4; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem4->rem4_id == id && ++ rem4->addr.s_addr == addr->s_addr && rem4->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem4->rem4_id == id && rem4->addr.s_addr != addr->s_addr) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr:%pI4 to addr %pI4 with id:%d\n", ++ __func__, &rem4->addr.s_addr, ++ &addr->s_addr, id); ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem4_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI4\n", ++ __func__, MPTCP_MAX_ADDR, &addr->s_addr); ++ return; ++ } ++ ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is not known yet, store it */ ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ rem4->bitfield = 0; ++ rem4->retry_bitfield = 0; ++ rem4->rem4_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem4_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_addv6_raddr(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem6 *rem6; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem6->rem6_id == id && ++ ipv6_addr_equal(&rem6->addr, addr) && rem6->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem6->rem6_id == id) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr: %pI6 to addr %pI6 with id:%d\n", ++ __func__, &rem6->addr, addr, id); ++ rem6->addr = *addr; ++ rem6->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem6_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI6\n", ++ __func__, MPTCP_MAX_ADDR, addr); ++ return; ++ } ++ ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is not known yet, store it */ ++ rem6->addr = *addr; ++ rem6->port = port; ++ rem6->bitfield = 0; ++ rem6->retry_bitfield = 0; ++ rem6->rem6_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem6_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_v4_rem_raddress(struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].rem4_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem4_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++static void mptcp_v6_rem_raddress(const struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (fmp->remaddr6[i].rem6_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem6_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v4_set_init_addr_bit(const struct mptcp_cb *mpcb, ++ const struct in_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].addr.s_addr == addr->s_addr) { ++ fmp->remaddr4[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v6_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (ipv6_addr_equal(&fmp->remaddr6[i].addr, addr)) { ++ fmp->remaddr6[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++static void mptcp_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_v4_set_init_addr_bit(mpcb, &addr->in, id); ++ else ++ mptcp_v6_set_init_addr_bit(mpcb, &addr->in6, id); ++} ++ ++static void mptcp_v4_subflows(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init4_subsockets(meta_sk, loc, rem); ++} ++ ++#if IS_ENABLED(CONFIG_IPV6) ++static void mptcp_v6_subflows(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init6_subsockets(meta_sk, loc, rem); ++} ++#endif ++ ++static void retry_subflow_worker(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct fullmesh_priv *fmp = container_of(delayed_work, ++ struct fullmesh_priv, ++ subflow_retry_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem = &fmp->remaddr4[i]; ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], &rem4); ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem = &fmp->remaddr6[i]; ++ ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], &rem6); ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ struct fullmesh_priv *fmp = container_of(work, struct fullmesh_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, retry = 0; ++ int i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ /* Create the additional subflows for the first pair */ ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_v4_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ iter++; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr4[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc4_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], ++ &rem4) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_v6_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr6[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc6_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], ++ &rem6) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++ if (retry && !delayed_work_pending(&fmp->subflow_retry_work)) { ++ sock_hold(meta_sk); ++ queue_delayed_work(mptcp_wq, &fmp->subflow_retry_work, ++ msecs_to_jiffies(MPTCP_SUBFLOW_RETRY_DELAY)); ++ } ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++} ++ ++static void announce_remove_addr(u8 addr_id, struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct sock *sk = mptcp_select_ack_sock(meta_sk); ++ ++ fmp->remove_addrs |= (1 << addr_id); ++ mpcb->addr_signal = 1; ++ ++ if (sk) ++ tcp_send_ack(sk); ++} ++ ++static void update_addr_bitfields(struct sock *meta_sk, ++ const struct mptcp_loc_addr *mptcp_local) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ int i; ++ ++ /* The bits in announced_addrs_* always match with loc*_bits. So, a ++ * simple & operation unsets the correct bits, because these go from ++ * announced to non-announced ++ */ ++ fmp->announced_addrs_v4 &= mptcp_local->loc4_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ fmp->remaddr4[i].bitfield &= mptcp_local->loc4_bits; ++ fmp->remaddr4[i].retry_bitfield &= mptcp_local->loc4_bits; ++ } ++ ++ fmp->announced_addrs_v6 &= mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ fmp->remaddr6[i].bitfield &= mptcp_local->loc6_bits; ++ fmp->remaddr6[i].retry_bitfield &= mptcp_local->loc6_bits; ++ } ++} ++ ++static int mptcp_find_address(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, const union inet_addr *addr, ++ int if_idx) ++{ ++ int i; ++ u8 loc_bits; ++ bool found = false; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ mptcp_local->locaddr4[i].addr.s_addr == addr->in.s_addr) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&mptcp_local->locaddr6[i].addr, ++ &addr->in6)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static int mptcp_find_address_transp(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, int if_idx) ++{ ++ bool found = false; ++ u8 loc_bits; ++ int i; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static void mptcp_address_worker(struct work_struct *work) ++{ ++ const struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct mptcp_fm_ns *fm_ns = container_of(delayed_work, ++ struct mptcp_fm_ns, ++ address_worker); ++ struct net *net = fm_ns->net; ++ struct mptcp_addr_event *event = NULL; ++ struct mptcp_loc_addr *mptcp_local, *old; ++ int i, id = -1; /* id is used in the socket-code on a delete-event */ ++ bool success; /* Used to indicate if we succeeded handling the event */ ++ ++next_event: ++ success = false; ++ kfree(event); ++ ++ /* First, let's dequeue an event from our event-list */ ++ rcu_read_lock_bh(); ++ spin_lock(&fm_ns->local_lock); ++ ++ event = list_first_entry_or_null(&fm_ns->events, ++ struct mptcp_addr_event, list); ++ if (!event) { ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ return; ++ } ++ ++ list_del(&event->list); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ id = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ ++ /* Not in the list - so we don't care */ ++ if (id < 0) { ++ mptcp_debug("%s could not find id\n", __func__); ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) ++ mptcp_local->loc4_bits &= ~(1 << id); ++ else ++ mptcp_local->loc6_bits &= ~(1 << id); ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } else { ++ int i = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ int j = i; ++ ++ if (j < 0) { ++ /* Not in the list, so we have to find an empty slot */ ++ if (event->family == AF_INET) ++ i = __mptcp_find_free_index(mptcp_local->loc4_bits, ++ mptcp_local->next_v4_index); ++ if (event->family == AF_INET6) ++ i = __mptcp_find_free_index(mptcp_local->loc6_bits, ++ mptcp_local->next_v6_index); ++ ++ if (i < 0) { ++ mptcp_debug("%s no more space\n", __func__); ++ goto duno; ++ } ++ ++ /* It might have been a MOD-event. */ ++ event->code = MPTCP_EVENT_ADD; ++ } else { ++ /* Let's check if anything changes */ ++ if (event->family == AF_INET && ++ event->low_prio == mptcp_local->locaddr4[i].low_prio) ++ goto duno; ++ ++ if (event->family == AF_INET6 && ++ event->low_prio == mptcp_local->locaddr6[i].low_prio) ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) { ++ mptcp_local->locaddr4[i].addr.s_addr = event->addr.in.s_addr; ++ mptcp_local->locaddr4[i].loc4_id = i + 1; ++ mptcp_local->locaddr4[i].low_prio = event->low_prio; ++ mptcp_local->locaddr4[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI4 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in.s_addr, ++ event->if_idx, event->low_prio, i + 1); ++ } else { ++ mptcp_local->locaddr6[i].addr = event->addr.in6; ++ mptcp_local->locaddr6[i].loc6_id = i + MPTCP_MAX_ADDR; ++ mptcp_local->locaddr6[i].low_prio = event->low_prio; ++ mptcp_local->locaddr6[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI6 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in6, ++ event->if_idx, event->low_prio, i + MPTCP_MAX_ADDR); ++ } ++ ++ if (j < 0) { ++ if (event->family == AF_INET) { ++ mptcp_local->loc4_bits |= (1 << i); ++ mptcp_local->next_v4_index = i + 1; ++ } else { ++ mptcp_local->loc6_bits |= (1 << i); ++ mptcp_local->next_v6_index = i + 1; ++ } ++ } ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } ++ success = true; ++ ++duno: ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ ++ if (!success) ++ goto next_event; ++ ++ /* Now we iterate over the MPTCP-sockets and apply the event. */ ++ for (i = 0; i < MPTCP_HASH_SIZE; i++) { ++ const struct hlist_nulls_node *node; ++ struct tcp_sock *meta_tp; ++ ++ rcu_read_lock_bh(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, &tk_hashtable[i], ++ tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp, *sk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_cb *mpcb; ++ ++ if (sock_net(meta_sk) != net) ++ continue; ++ ++ if (meta_v4) { ++ /* skip IPv6 events if meta is IPv4 */ ++ if (event->family == AF_INET6) ++ continue; ++ } else if (event->family == AF_INET && meta_sk->sk_ipv6only) { ++ /* skip IPv4 events if IPV6_V6ONLY is set */ ++ continue; ++ } ++ ++ if (unlikely(!atomic_inc_not_zero(&meta_sk->sk_refcnt))) ++ continue; ++ ++ bh_lock_sock(meta_sk); ++ ++ mpcb = meta_tp->mpcb; ++ if (!mpcb) ++ goto next; ++ ++ if (!mptcp(meta_tp) || !is_meta_sk(meta_sk) || ++ mpcb->infinite_mapping_snd || ++ mpcb->infinite_mapping_rcv || ++ mpcb->send_infinite_mapping) ++ goto next; ++ ++ /* May be that the pm has changed in-between */ ++ if (mpcb->pm_ops != &full_mesh) ++ goto next; ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (!test_and_set_bit(MPTCP_PATH_MANAGER_DEFERRED, ++ &meta_tp->tsq_flags)) ++ sock_hold(meta_sk); ++ ++ goto next; ++ } ++ ++ if (event->code == MPTCP_EVENT_ADD) { ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ ++ full_mesh_create_subflows(meta_sk); ++ } ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ struct sock *sk, *tmpsk; ++ struct mptcp_loc_addr *mptcp_local; ++ bool found = false; ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ /* In any case, we need to update our bitfields */ ++ if (id >= 0) ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ /* Look for the socket and remove him */ ++ mptcp_for_each_sk_safe(mpcb, sk, tmpsk) { ++ if ((event->family == AF_INET6 && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk))) || ++ (event->family == AF_INET && ++ (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)))) ++ continue; ++ ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr != event->addr.in.s_addr) ++ continue; ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) ++ continue; ++ ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ /* We announce the removal of this id */ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ found = true; ++ } ++ ++ if (found) ++ goto next; ++ ++ /* The id may have been given by the event, ++ * matching on a local address. And it may not ++ * have matched on one of the above sockets, ++ * because the client never created a subflow. ++ * So, we have to finally remove it here. ++ */ ++ if (id >= 0) { ++ u8 loc_id = id ++ + (event->family == AF_INET ? 1 : MPTCP_MAX_ADDR); ++ announce_remove_addr(loc_id, meta_sk); ++ } ++ } ++ ++ if (event->code == MPTCP_EVENT_MOD) { ++ struct sock *sk; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr == event->addr.in.s_addr) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ } ++ } ++next: ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); ++ } ++ rcu_read_unlock_bh(); ++ } ++ goto next_event; ++} ++ ++static struct mptcp_addr_event *lookup_similar_event(const struct net *net, ++ const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ list_for_each_entry(eventq, &fm_ns->events, list) { ++ if (eventq->family != event->family) ++ continue; ++ if (eventq->if_idx != event->if_idx) ++ continue; ++ if (event->family == AF_INET) { ++ if (eventq->addr.in.s_addr == event->addr.in.s_addr) ++ return eventq; ++ } else { ++ if (ipv6_addr_equal(&eventq->addr.in6, &event->addr.in6)) ++ return eventq; ++ } ++ } ++ return NULL; ++} ++ ++/* We already hold the net-namespace MPTCP-lock */ ++static void add_pm_event(struct net *net, const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq = lookup_similar_event(net, event); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ if (eventq) { ++ switch (event->code) { ++ case MPTCP_EVENT_DEL: ++ mptcp_debug("%s del old_code %u\n", __func__, eventq->code); ++ list_del(&eventq->list); ++ kfree(eventq); ++ break; ++ case MPTCP_EVENT_ADD: ++ mptcp_debug("%s add old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_ADD; ++ return; ++ case MPTCP_EVENT_MOD: ++ mptcp_debug("%s mod old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_MOD; ++ return; ++ } ++ } ++ ++ /* OK, we have to add the new address to the wait queue */ ++ eventq = kmemdup(event, sizeof(struct mptcp_addr_event), GFP_ATOMIC); ++ if (!eventq) ++ return; ++ ++ list_add_tail(&eventq->list, &fm_ns->events); ++ ++ /* Create work-queue */ ++ if (!delayed_work_pending(&fm_ns->address_worker)) ++ queue_delayed_work(mptcp_wq, &fm_ns->address_worker, ++ msecs_to_jiffies(500)); ++} ++ ++static void addr4_event_handler(const struct in_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->ifa_dev->dev; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->ifa_scope > RT_SCOPE_LINK || ++ ipv4_is_loopback(ifa->ifa_local)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET; ++ mpevent.addr.in.s_addr = ifa->ifa_local; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI4, code %u prio %u idx %u\n", __func__, ++ &ifa->ifa_local, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv4-addr add/rem-events */ ++static int mptcp_pm_inetaddr_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ const struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net *net = dev_net(ifa->ifa_dev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr4_event_handler(ifa, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_inetaddr_notifier = { ++ .notifier_call = mptcp_pm_inetaddr_event, ++}; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++/* IPV6-related address/interface watchers */ ++struct mptcp_dad_data { ++ struct timer_list timer; ++ struct inet6_ifaddr *ifa; ++}; ++ ++static void dad_callback(unsigned long arg); ++static int inet6_addr_event(struct notifier_block *this, ++ unsigned long event, void *ptr); ++ ++static bool ipv6_dad_finished(const struct inet6_ifaddr *ifa) ++{ ++ return !(ifa->flags & IFA_F_TENTATIVE) || ++ ifa->state > INET6_IFADDR_STATE_DAD; ++} ++ ++static void dad_init_timer(struct mptcp_dad_data *data, ++ struct inet6_ifaddr *ifa) ++{ ++ data->ifa = ifa; ++ data->timer.data = (unsigned long)data; ++ data->timer.function = dad_callback; ++ if (ifa->idev->cnf.rtr_solicit_delay) ++ data->timer.expires = jiffies + ifa->idev->cnf.rtr_solicit_delay; ++ else ++ data->timer.expires = jiffies + (HZ/10); ++} ++ ++static void dad_callback(unsigned long arg) ++{ ++ struct mptcp_dad_data *data = (struct mptcp_dad_data *)arg; ++ ++ /* DAD failed or IP brought down? */ ++ if (data->ifa->state == INET6_IFADDR_STATE_ERRDAD || ++ data->ifa->state == INET6_IFADDR_STATE_DEAD) ++ goto exit; ++ ++ if (!ipv6_dad_finished(data->ifa)) { ++ dad_init_timer(data, data->ifa); ++ add_timer(&data->timer); ++ return; ++ } ++ ++ inet6_addr_event(NULL, NETDEV_UP, data->ifa); ++ ++exit: ++ in6_ifa_put(data->ifa); ++ kfree(data); ++} ++ ++static inline void dad_setup_timer(struct inet6_ifaddr *ifa) ++{ ++ struct mptcp_dad_data *data; ++ ++ data = kmalloc(sizeof(*data), GFP_ATOMIC); ++ ++ if (!data) ++ return; ++ ++ init_timer(&data->timer); ++ dad_init_timer(data, ifa); ++ add_timer(&data->timer); ++ in6_ifa_hold(ifa); ++} ++ ++static void addr6_event_handler(const struct inet6_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->idev->dev; ++ int addr_type = ipv6_addr_type(&ifa->addr); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->scope > RT_SCOPE_LINK || ++ addr_type == IPV6_ADDR_ANY || ++ (addr_type & IPV6_ADDR_LOOPBACK) || ++ (addr_type & IPV6_ADDR_LINKLOCAL)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET6; ++ mpevent.addr.in6 = ifa->addr; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI6, code %u prio %u idx %u\n", __func__, ++ &ifa->addr, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv6-addr add/rem-events */ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ struct inet6_ifaddr *ifa6 = (struct inet6_ifaddr *)ptr; ++ struct net *net = dev_net(ifa6->idev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ if (sysctl_mptcp_enabled && !ipv6_dad_finished(ifa6)) ++ dad_setup_timer(ifa6); ++ else ++ addr6_event_handler(ifa6, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block inet6_addr_notifier = { ++ .notifier_call = inet6_addr_event, ++}; ++ ++#endif ++ ++/* React on ifup/down-events */ ++static int netdev_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ const struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct in_device *in_dev; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct inet6_dev *in6_dev; ++#endif ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ rcu_read_lock(); ++ in_dev = __in_dev_get_rtnl(dev); ++ ++ if (in_dev) { ++ for_ifa(in_dev) { ++ mptcp_pm_inetaddr_event(NULL, event, ifa); ++ } endfor_ifa(in_dev); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ in6_dev = __in6_dev_get(dev); ++ ++ if (in6_dev) { ++ struct inet6_ifaddr *ifa6; ++ list_for_each_entry(ifa6, &in6_dev->addr_list, if_list) ++ inet6_addr_event(NULL, event, ifa6); ++ } ++#endif ++ ++ rcu_read_unlock(); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_netdev_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++static void full_mesh_add_raddr(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_addv4_raddr(mpcb, &addr->in, port, id); ++ else ++ mptcp_addv6_raddr(mpcb, &addr->in6, port, id); ++} ++ ++static void full_mesh_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct tcp_sock *master_tp = tcp_sk(mpcb->master_sk); ++ int i, index, if_idx = 0; ++ union inet_addr saddr, daddr; ++ sa_family_t family = AF_INET; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ /* Init local variables necessary for the rest */ ++ if (meta_sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(meta_sk)) { ++ saddr.ip = inet_sk(meta_sk)->inet_saddr; ++ daddr.ip = inet_sk(meta_sk)->inet_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ saddr.in6 = inet6_sk(meta_sk)->saddr; ++ daddr.in6 = meta_sk->sk_v6_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET6; ++#endif ++ } ++ ++ if (inet_sk(meta_sk)->transparent) ++ if_idx = inet_sk(meta_sk)->rx_dst_ifindex; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (inet_sk(meta_sk)->transparent) ++ index = mptcp_find_address_transp(mptcp_local, family, if_idx); ++ else ++ index = mptcp_find_address(mptcp_local, family, &saddr, if_idx); ++ if (index < 0) ++ goto fallback; ++ ++ if (family == AF_INET) ++ master_tp->mptcp->low_prio = mptcp_local->locaddr4[index].low_prio; ++ else ++ master_tp->mptcp->low_prio = mptcp_local->locaddr6[index].low_prio; ++ master_tp->mptcp->send_mp_prio = master_tp->mptcp->low_prio; ++ ++ full_mesh_add_raddr(mpcb, &daddr, family, 0, 0); ++ mptcp_set_init_addr_bit(mpcb, &daddr, family, index); ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ INIT_DELAYED_WORK(&fmp->subflow_retry_work, retry_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* Look for the address among the local addresses */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ __be32 ifa_address = mptcp_local->locaddr4[i].addr.s_addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ saddr.ip == ifa_address) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto skip_ipv6; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ const struct in6_addr *ifa6 = &mptcp_local->locaddr6[i].addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&saddr.in6, ifa6)) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv6: ++#endif ++ ++ rcu_read_unlock_bh(); ++ ++ if (family == AF_INET) ++ fmp->announced_addrs_v4 |= (1 << index); ++ else ++ fmp->announced_addrs_v6 |= (1 << index); ++ ++ for (i = fmp->add_addr; i && fmp->add_addr; i--) ++ tcp_send_ack(mpcb->master_sk); ++ ++ if (master_tp->mptcp->send_mp_prio) ++ tcp_send_ack(mpcb->master_sk); ++ ++ return; ++ ++fallback: ++ rcu_read_unlock_bh(); ++ mptcp_fallback_default(mpcb); ++ return; ++} ++ ++static void full_mesh_create_subflows(struct sock *meta_sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ if (mpcb->infinite_mapping_snd || mpcb->infinite_mapping_rcv || ++ mpcb->send_infinite_mapping || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ return; ++ ++ if (!work_pending(&fmp->subflow_work)) { ++ sock_hold(meta_sk); ++ queue_work(mptcp_wq, &fmp->subflow_work); ++ } ++} ++ ++static void full_mesh_subflow_error(struct sock *meta_sk, struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (!create_on_err) ++ return; ++ ++ if (mpcb->infinite_mapping_snd || mpcb->infinite_mapping_rcv || ++ mpcb->send_infinite_mapping || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (sk->sk_err != ETIMEDOUT) ++ return; ++ ++ full_mesh_create_subflows(meta_sk); ++} ++ ++/* Called upon release_sock, if the socket was owned by the user during ++ * a path-management event. ++ */ ++static void full_mesh_release_sock(struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct sock *sk, *tmpsk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ int i; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* First, detect modifications or additions */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct in_addr ifa = mptcp_local->locaddr4[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (inet_sk(sk)->inet_saddr != ifa.s_addr) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr4[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr4[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto removal; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct in6_addr ifa = mptcp_local->locaddr6[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (!ipv6_addr_equal(&inet6_sk(sk)->saddr, &ifa)) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr6[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr6[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++removal: ++#endif ++ ++ /* Now, detect address-removals */ ++ mptcp_for_each_sk_safe(mpcb, sk, tmpsk) { ++ bool shall_remove = true; ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ if (inet_sk(sk)->inet_saddr == mptcp_local->locaddr4[i].addr.s_addr) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } else { ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ if (ipv6_addr_equal(&inet6_sk(sk)->saddr, &mptcp_local->locaddr6[i].addr)) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } ++ ++ if (shall_remove) { ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, ++ meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ } ++ } ++ ++ /* Just call it optimistically. It actually cannot do any harm */ ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ rcu_read_unlock_bh(); ++} ++ ++static int full_mesh_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int index, id = -1; ++ ++ /* Handle the backup-flows */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ index = mptcp_find_address(mptcp_local, family, addr, 0); ++ ++ if (index != -1) { ++ if (family == AF_INET) { ++ id = mptcp_local->locaddr4[index].loc4_id; ++ *low_prio = mptcp_local->locaddr4[index].low_prio; ++ } else { ++ id = mptcp_local->locaddr6[index].loc6_id; ++ *low_prio = mptcp_local->locaddr6[index].low_prio; ++ } ++ } ++ ++ ++ rcu_read_unlock_bh(); ++ ++ return id; ++} ++ ++static void full_mesh_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ int remove_addr_len; ++ u8 unannouncedv4 = 0, unannouncedv6 = 0; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ mpcb->addr_signal = 0; ++ ++ if (likely(!fmp->add_addr)) ++ goto remove_addr; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* IPv4 */ ++ unannouncedv4 = (~fmp->announced_addrs_v4) & mptcp_local->loc4_bits; ++ if (unannouncedv4 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv4); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = mptcp_local->locaddr4[ind].loc4_id; ++ opts->add_addr4.addr = mptcp_local->locaddr4[ind].addr; ++ opts->add_addr_v4 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, ++ 4, (u8 *)&opts->add_addr4.addr.s_addr); ++ opts->add_addr4.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v4 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++ ++ goto skip_ipv6; ++ } ++ ++ if (meta_v4) ++ goto skip_ipv6; ++skip_ipv4: ++ /* IPv6 */ ++ unannouncedv6 = (~fmp->announced_addrs_v6) & mptcp_local->loc6_bits; ++ if (unannouncedv6 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv6); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = mptcp_local->locaddr6[ind].loc6_id; ++ opts->add_addr6.addr = mptcp_local->locaddr6[ind].addr; ++ opts->add_addr_v6 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[20]; ++ u8 no_key[8]; ++ ++ *(u64 *)no_key = 0; ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)no_key, ++ (u32 *)mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, ++ 16, (u8 *)&opts->add_addr6.addr.s6_addr); ++ opts->add_addr6.trunc_mac = *(u64 *)mptcp_hash_mac; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v6 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++ } ++ ++skip_ipv6: ++ rcu_read_unlock_bh(); ++ ++ if (!unannouncedv4 && !unannouncedv6 && skb) ++ fmp->add_addr--; ++ ++remove_addr: ++ if (likely(!fmp->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(fmp->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = fmp->remove_addrs; ++ *size += remove_addr_len; ++ if (skb) ++ fmp->remove_addrs = 0; ++ ++exit: ++ mpcb->addr_signal = !!(fmp->add_addr || fmp->remove_addrs); ++} ++ ++static void full_mesh_rem_raddr(struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ mptcp_v4_rem_raddress(mpcb, rem_id); ++ mptcp_v6_rem_raddress(mpcb, rem_id); ++} ++ ++static void full_mesh_delete_subflow(struct sock *sk) ++{ ++ struct fullmesh_priv *fmp = fullmesh_get_priv(tcp_sk(sk)->mpcb); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ struct mptcp_loc_addr *mptcp_local; ++ int index, i; ++ ++ if (!create_on_err) ++ return; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ union inet_addr saddr; ++ ++ saddr.ip = inet_sk(sk)->inet_saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem4 = &fmp->remaddr4[i]; ++ ++ if (rem4->addr.s_addr != sk->sk_daddr) ++ continue; ++ ++ if (rem4->port && rem4->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem4->bitfield &= ~(1 << index); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ union inet_addr saddr; ++ ++ saddr.in6 = inet6_sk(sk)->saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET6, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem6 = &fmp->remaddr6[i]; ++ ++ if (!ipv6_addr_equal(&rem6->addr, &sk->sk_v6_daddr)) ++ continue; ++ ++ if (rem6->port && rem6->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem6->bitfield &= ~(1 << index); ++ } ++#endif ++ } ++ ++out: ++ rcu_read_unlock_bh(); ++} ++ ++/* Output /proc/net/mptcp_fullmesh */ ++static int mptcp_fm_seq_show(struct seq_file *seq, void *v) ++{ ++ const struct net *net = seq->private; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int i; ++ ++ seq_printf(seq, "Index, Address-ID, Backup, IP-address, if-idx\n"); ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ seq_printf(seq, "IPv4, next v4-index: %u\n", mptcp_local->next_v4_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct mptcp_loc4 *loc4 = &mptcp_local->locaddr4[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI4 %u\n", i, loc4->loc4_id, ++ loc4->low_prio, &loc4->addr, loc4->if_idx); ++ } ++ ++ seq_printf(seq, "IPv6, next v6-index: %u\n", mptcp_local->next_v6_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct mptcp_loc6 *loc6 = &mptcp_local->locaddr6[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI6 %u\n", i, loc6->loc6_id, ++ loc6->low_prio, &loc6->addr, loc6->if_idx); ++ } ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static int mptcp_fm_seq_open(struct inode *inode, struct file *file) ++{ ++ return single_open_net(inode, file, mptcp_fm_seq_show); ++} ++ ++static const struct file_operations mptcp_fm_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = mptcp_fm_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release_net, ++}; ++ ++static int mptcp_fm_init_net(struct net *net) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns; ++ int err = 0; ++ ++ fm_ns = kzalloc(sizeof(*fm_ns), GFP_KERNEL); ++ if (!fm_ns) ++ return -ENOBUFS; ++ ++ mptcp_local = kzalloc(sizeof(*mptcp_local), GFP_KERNEL); ++ if (!mptcp_local) { ++ err = -ENOBUFS; ++ goto err_mptcp_local; ++ } ++ ++ if (!proc_create("mptcp_fullmesh", S_IRUGO, net->proc_net, ++ &mptcp_fm_seq_fops)) { ++ err = -ENOMEM; ++ goto err_seq_fops; ++ } ++ ++ mptcp_local->next_v4_index = 1; ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ INIT_DELAYED_WORK(&fm_ns->address_worker, mptcp_address_worker); ++ INIT_LIST_HEAD(&fm_ns->events); ++ spin_lock_init(&fm_ns->local_lock); ++ fm_ns->net = net; ++ net->mptcp.path_managers[MPTCP_PM_FULLMESH] = fm_ns; ++ ++ return 0; ++err_seq_fops: ++ kfree(mptcp_local); ++err_mptcp_local: ++ kfree(fm_ns); ++ return err; ++} ++ ++static void mptcp_fm_exit_net(struct net *net) ++{ ++ struct mptcp_addr_event *eventq, *tmp; ++ struct mptcp_fm_ns *fm_ns; ++ struct mptcp_loc_addr *mptcp_local; ++ ++ fm_ns = fm_get_ns(net); ++ cancel_delayed_work_sync(&fm_ns->address_worker); ++ ++ rcu_read_lock_bh(); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ kfree_rcu(mptcp_local, rcu); ++ ++ spin_lock(&fm_ns->local_lock); ++ list_for_each_entry_safe(eventq, tmp, &fm_ns->events, list) { ++ list_del(&eventq->list); ++ kfree(eventq); ++ } ++ spin_unlock(&fm_ns->local_lock); ++ ++ rcu_read_unlock_bh(); ++ ++ remove_proc_entry("mptcp_fullmesh", net->proc_net); ++ ++ kfree(fm_ns); ++} ++ ++static struct pernet_operations full_mesh_net_ops = { ++ .init = mptcp_fm_init_net, ++ .exit = mptcp_fm_exit_net, ++}; ++ ++static struct mptcp_pm_ops full_mesh __read_mostly = { ++ .new_session = full_mesh_new_session, ++ .release_sock = full_mesh_release_sock, ++ .fully_established = full_mesh_create_subflows, ++ .new_remote_address = full_mesh_create_subflows, ++ .subflow_error = full_mesh_subflow_error, ++ .get_local_id = full_mesh_get_local_id, ++ .addr_signal = full_mesh_addr_signal, ++ .add_raddr = full_mesh_add_raddr, ++ .rem_raddr = full_mesh_rem_raddr, ++ .delete_subflow = full_mesh_delete_subflow, ++ .name = "fullmesh", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init full_mesh_register(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct fullmesh_priv) > MPTCP_PM_SIZE); ++ ++ ret = register_pernet_subsys(&full_mesh_net_ops); ++ if (ret) ++ goto out; ++ ++ ret = register_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ if (ret) ++ goto err_reg_inetaddr; ++ ret = register_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ if (ret) ++ goto err_reg_netdev; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ret = register_inet6addr_notifier(&inet6_addr_notifier); ++ if (ret) ++ goto err_reg_inet6addr; ++#endif ++ ++ ret = mptcp_register_path_manager(&full_mesh); ++ if (ret) ++ goto err_reg_pm; ++ ++out: ++ return ret; ++ ++ ++err_reg_pm: ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++err_reg_inet6addr: ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++err_reg_netdev: ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++err_reg_inetaddr: ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ goto out; ++} ++ ++static void full_mesh_unregister(void) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ mptcp_unregister_path_manager(&full_mesh); ++} ++ ++module_init(full_mesh_register); ++module_exit(full_mesh_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Full-Mesh MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_input.c mptcp-mptcp_v0.93/net/mptcp/mptcp_input.c +--- linux-4.9.162/net/mptcp/mptcp_input.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_input.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,2501 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++/* is seq1 < seq2 ? */ ++static inline bool before64(const u64 seq1, const u64 seq2) ++{ ++ return (s64)(seq1 - seq2) < 0; ++} ++ ++/* is seq1 > seq2 ? */ ++#define after64(seq1, seq2) before64(seq2, seq1) ++ ++static inline void mptcp_become_fully_estab(struct sock *sk) ++{ ++ tcp_sk(sk)->mptcp->fully_established = 1; ++ ++ if (is_master_tp(tcp_sk(sk)) && ++ tcp_sk(sk)->mpcb->pm_ops->fully_established) ++ tcp_sk(sk)->mpcb->pm_ops->fully_established(mptcp_meta_sk(sk)); ++} ++ ++/* Similar to tcp_tso_acked without any memory accounting */ ++static inline int mptcp_tso_acked_reinject(const struct sock *meta_sk, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 packets_acked, len, delta_truesize; ++ ++ BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)); ++ ++ packets_acked = tcp_skb_pcount(skb); ++ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ return 0; ++ ++ len = meta_tp->snd_una - TCP_SKB_CB(skb)->seq; ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq += len; ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ if (delta_truesize) ++ skb->truesize -= delta_truesize; ++ ++ /* Any change of skb->len requires recalculation of tso factor. */ ++ if (tcp_skb_pcount(skb) > 1) ++ tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); ++ packets_acked -= tcp_skb_pcount(skb); ++ ++ if (packets_acked) { ++ BUG_ON(tcp_skb_pcount(skb) == 0); ++ BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); ++ } ++ ++ return packets_acked; ++} ++ ++/** ++ * Cleans the meta-socket retransmission queue and the reinject-queue. ++ * @sk must be the metasocket. ++ */ ++static void mptcp_clean_rtx_queue(struct sock *meta_sk, u32 prior_snd_una) ++{ ++ struct sk_buff *skb, *tmp; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ bool acked = false; ++ u32 acked_pcount; ++ ++ while ((skb = tcp_write_queue_head(meta_sk)) && ++ skb != tcp_send_head(meta_sk)) { ++ bool fully_acked = true; ++ ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ acked_pcount = tcp_tso_acked(meta_sk, skb); ++ if (!acked_pcount) ++ break; ++ ++ fully_acked = false; ++ } else { ++ acked_pcount = tcp_skb_pcount(skb); ++ } ++ ++ acked = true; ++ meta_tp->packets_out -= acked_pcount; ++ meta_tp->retrans_stamp = 0; ++ ++ if (!fully_acked) ++ break; ++ ++ tcp_unlink_write_queue(skb, meta_sk); ++ ++ if (mptcp_is_data_fin(skb)) { ++ struct sock *sk_it, *sk_tmp; ++ ++ /* DATA_FIN has been acknowledged - now we can close ++ * the subflows ++ */ ++ mptcp_for_each_sk_safe(mpcb, sk_it, sk_tmp) { ++ unsigned long delay = 0; ++ ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer - thus we add a delay. ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ sk_wmem_free_skb(meta_sk, skb); ++ } ++ /* Remove acknowledged data from the reinject queue */ ++ skb_queue_walk_safe(&mpcb->reinject_queue, skb, tmp) { ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ mptcp_tso_acked_reinject(meta_sk, skb); ++ break; ++ } ++ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ } ++ ++ if (likely(between(meta_tp->snd_up, prior_snd_una, meta_tp->snd_una))) ++ meta_tp->snd_up = meta_tp->snd_una; ++ ++ if (acked) { ++ tcp_rearm_rto(meta_sk); ++ /* Normally this is done in tcp_try_undo_loss - but MPTCP ++ * does not call this function. ++ */ ++ inet_csk(meta_sk)->icsk_retransmits = 0; ++ } ++} ++ ++/* Inspired by tcp_rcv_state_process */ ++static int mptcp_rcv_state_process(struct sock *meta_sk, struct sock *sk, ++ const struct sk_buff *skb, u32 data_seq, ++ u16 data_len) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ const struct tcphdr *th = tcp_hdr(skb); ++ ++ /* State-machine handling if FIN has been enqueued and he has ++ * been acked (snd_una == write_seq) - it's important that this ++ * here is after sk_wmem_free_skb because otherwise ++ * sk_forward_alloc is wrong upon inet_csk_destroy_sock() ++ */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: { ++ struct dst_entry *dst; ++ int tmo; ++ ++ if (meta_tp->snd_una != meta_tp->write_seq) ++ break; ++ ++ tcp_set_state(meta_sk, TCP_FIN_WAIT2); ++ meta_sk->sk_shutdown |= SEND_SHUTDOWN; ++ ++ dst = __sk_dst_get(sk); ++ if (dst) ++ dst_confirm(dst); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Wake up lingering close() */ ++ meta_sk->sk_state_change(meta_sk); ++ break; ++ } ++ ++ if (meta_tp->linger2 < 0 || ++ (data_len && ++ after(data_seq + data_len - (mptcp_is_data_fin2(skb, tp) ? 1 : 0), ++ meta_tp->rcv_nxt))) { ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_done(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ return 1; ++ } ++ ++ tmo = tcp_fin_time(meta_sk); ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, tmo - TCP_TIMEWAIT_LEN); ++ } else if (mptcp_is_data_fin2(skb, tp) || sock_owned_by_user(meta_sk)) { ++ /* Bad case. We could lose such FIN otherwise. ++ * It is not a big problem, but it looks confusing ++ * and not so rare event. We still can lose it now, ++ * if it spins in bh_lock_sock(), but it is really ++ * marginal case. ++ */ ++ inet_csk_reset_keepalive_timer(meta_sk, tmo); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, tmo); ++ } ++ break; ++ } ++ case TCP_CLOSING: ++ case TCP_LAST_ACK: ++ if (meta_tp->snd_una == meta_tp->write_seq) { ++ tcp_done(meta_sk); ++ return 1; ++ } ++ break; ++ } ++ ++ /* step 7: process the segment text */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: ++ case TCP_FIN_WAIT2: ++ /* RFC 793 says to queue data in these states, ++ * RFC 1122 says we MUST send a reset. ++ * BSD 4.4 also does reset. ++ */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN) { ++ if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp_is_data_fin2(skb, tp)) { ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_reset(meta_sk); ++ return 1; ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/** ++ * @return: ++ * i) 1: Everything's fine. ++ * ii) -1: A reset has been sent on the subflow - csum-failure ++ * iii) 0: csum-failure but no reset sent, because it's the last subflow. ++ * Last packet should not be destroyed by the caller because it has ++ * been done here. ++ */ ++static int mptcp_verif_dss_csum(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1, *last = NULL; ++ __wsum csum_tcp = 0; /* cumulative checksum of pld + mptcp-header */ ++ int ans = 1, overflowed = 0, offset = 0, dss_csum_added = 0; ++ int iter = 0; ++ u32 next_seq, offset_seq; ++ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp, tmp1) { ++ unsigned int csum_len; ++ ++ /* init next seq in first round */ ++ if (!iter) ++ next_seq = TCP_SKB_CB(tmp)->seq; ++ offset_seq = next_seq - TCP_SKB_CB(tmp)->seq; ++ ++ if (before(tp->mptcp->map_subseq + tp->mptcp->map_data_len, TCP_SKB_CB(tmp)->end_seq)) ++ /* Mapping ends in the middle of the packet - ++ * csum only these bytes ++ */ ++ csum_len = tp->mptcp->map_subseq + tp->mptcp->map_data_len - TCP_SKB_CB(tmp)->seq; ++ else ++ csum_len = tmp->len; ++ ++ csum_len -= offset_seq; ++ offset = 0; ++ if (overflowed) { ++ char first_word[4]; ++ first_word[0] = 0; ++ first_word[1] = 0; ++ first_word[2] = 0; ++ first_word[3] = *(tmp->data + offset_seq); ++ csum_tcp = csum_partial(first_word, 4, csum_tcp); ++ offset = 1; ++ csum_len--; ++ overflowed = 0; ++ } ++ ++ csum_tcp = skb_checksum(tmp, offset + offset_seq, csum_len, ++ csum_tcp); ++ ++ /* Was it on an odd-length? Then we have to merge the next byte ++ * correctly (see above) ++ */ ++ if (csum_len != (csum_len & (~1))) ++ overflowed = 1; ++ ++ if (mptcp_is_data_seq(tmp) && !dss_csum_added) { ++ __be32 data_seq = htonl((u32)(tp->mptcp->map_data_seq >> 32)); ++ ++ /* If a 64-bit dss is present, we increase the offset ++ * by 4 bytes, as the high-order 64-bits will be added ++ * in the final csum_partial-call. ++ */ ++ u32 offset = skb_transport_offset(tmp) + ++ TCP_SKB_CB(tmp)->dss_off; ++ if (TCP_SKB_CB(tmp)->mptcp_flags & MPTCPHDR_SEQ64_SET) ++ offset += 4; ++ ++ csum_tcp = skb_checksum(tmp, offset, ++ MPTCP_SUB_LEN_SEQ_CSUM, ++ csum_tcp); ++ ++ csum_tcp = csum_partial(&data_seq, ++ sizeof(data_seq), csum_tcp); ++ ++ dss_csum_added = 1; /* Just do it once */ ++ } ++ last = tmp; ++ iter++; ++ ++ if (!skb_queue_is_last(&sk->sk_receive_queue, tmp) && ++ !before(TCP_SKB_CB(tmp1)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ next_seq = TCP_SKB_CB(tmp)->end_seq; ++ } ++ ++ /* Now, checksum must be 0 */ ++ if (unlikely(csum_fold(csum_tcp))) { ++ pr_err("%s csum is wrong: %#x data_seq %u dss_csum_added %d overflowed %d iterations %d\n", ++ __func__, csum_fold(csum_tcp), TCP_SKB_CB(last)->seq, ++ dss_csum_added, overflowed, iter); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMFAIL); ++ tp->mptcp->send_mp_fail = 1; ++ ++ /* map_data_seq is the data-seq number of the ++ * mapping we are currently checking ++ */ ++ tp->mpcb->csum_cutoff_seq = tp->mptcp->map_data_seq; ++ ++ if (tp->mpcb->cnt_subflows > 1) { ++ mptcp_send_reset(sk); ++ ans = -1; ++ } else { ++ tp->mpcb->send_infinite_mapping = 1; ++ ++ /* Need to purge the rcv-queue as it's no more valid */ ++ while ((tmp = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { ++ tp->copied_seq = TCP_SKB_CB(tmp)->end_seq; ++ kfree_skb(tmp); ++ } ++ ++ ans = 0; ++ } ++ } ++ ++ return ans; ++} ++ ++static inline void mptcp_prepare_skb(struct sk_buff *skb, ++ const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 inc = 0, end_seq = tcb->end_seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ end_seq--; ++ /* If skb is the end of this mapping (end is always at mapping-boundary ++ * thanks to the splitting/trimming), then we need to increase ++ * data-end-seq by 1 if this here is a data-fin. ++ * ++ * We need to do -1 because end_seq includes the subflow-FIN. ++ */ ++ if (tp->mptcp->map_data_fin && ++ end_seq == tp->mptcp->map_subseq + tp->mptcp->map_data_len) { ++ inc = 1; ++ ++ /* We manually set the fin-flag if it is a data-fin. For easy ++ * processing in tcp_recvmsg. ++ */ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } else { ++ /* We may have a subflow-fin with data but without data-fin */ ++ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_FIN; ++ } ++ ++ /* Adapt data-seq's to the packet itself. We kinda transform the ++ * dss-mapping to a per-packet granularity. This is necessary to ++ * correctly handle overlapping mappings coming from different ++ * subflows. Otherwise it would be a complete mess. ++ */ ++ tcb->seq = ((u32)tp->mptcp->map_data_seq) + tcb->seq - tp->mptcp->map_subseq; ++ tcb->end_seq = tcb->seq + skb->len + inc; ++} ++ ++/** ++ * @return: 1 if the segment has been eaten and can be suppressed, ++ * otherwise 0. ++ */ ++static inline int mptcp_direct_copy(const struct sk_buff *skb, ++ struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int chunk = min_t(unsigned int, skb->len, meta_tp->ucopy.len); ++ int eaten = 0; ++ ++ __set_current_state(TASK_RUNNING); ++ ++ if (!skb_copy_datagram_msg(skb, 0, meta_tp->ucopy.msg, chunk)) { ++ meta_tp->ucopy.len -= chunk; ++ meta_tp->copied_seq += chunk; ++ eaten = (chunk == skb->len); ++ tcp_rcv_space_adjust(meta_sk); ++ } ++ return eaten; ++} ++ ++static inline void mptcp_reset_mapping(struct tcp_sock *tp, u32 old_copied_seq) ++{ ++ tp->mptcp->map_data_len = 0; ++ tp->mptcp->map_data_seq = 0; ++ tp->mptcp->map_subseq = 0; ++ tp->mptcp->map_data_fin = 0; ++ tp->mptcp->mapping_present = 0; ++ ++ /* In infinite mapping receiver mode, we have to advance the implied ++ * data-sequence number when we progress the subflow's data. ++ */ ++ if (tp->mpcb->infinite_mapping_rcv) ++ tp->mpcb->infinite_rcv_seq += (tp->copied_seq - old_copied_seq); ++} ++ ++/* The DSS-mapping received on the sk only covers the second half of the skb ++ * (cut at seq). We trim the head from the skb. ++ * Data will be freed upon kfree(). ++ * ++ * Inspired by tcp_trim_head(). ++ */ ++static void mptcp_skb_trim_head(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ int len = seq - TCP_SKB_CB(skb)->seq; ++ u32 new_seq = TCP_SKB_CB(skb)->seq + len; ++ u32 delta_truesize; ++ ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq = new_seq; ++ ++ if (delta_truesize) { ++ skb->truesize -= delta_truesize; ++ atomic_sub(delta_truesize, &sk->sk_rmem_alloc); ++ sk_mem_uncharge(sk, delta_truesize); ++ } ++} ++ ++/* The DSS-mapping received on the sk only covers the first half of the skb ++ * (cut at seq). We create a second skb (@return), and queue it in the rcv-queue ++ * as further packets may resolve the mapping of the second half of data. ++ * ++ * Inspired by tcp_fragment(). ++ */ ++static int mptcp_skb_split_tail(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ struct sk_buff *buff; ++ int nsize; ++ int nlen, len; ++ u8 flags; ++ ++ len = seq - TCP_SKB_CB(skb)->seq; ++ nsize = skb_headlen(skb) - len + tcp_sk(sk)->tcp_header_len; ++ if (nsize < 0) ++ nsize = 0; ++ ++ /* Get a new skb... force flag on. */ ++ buff = alloc_skb(nsize, GFP_ATOMIC); ++ if (buff == NULL) ++ return -ENOMEM; ++ ++ skb_reserve(buff, tcp_sk(sk)->tcp_header_len); ++ skb_reset_transport_header(buff); ++ ++ flags = TCP_SKB_CB(skb)->tcp_flags; ++ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN); ++ TCP_SKB_CB(buff)->tcp_flags = flags; ++ ++ /* We absolutly need to call skb_set_owner_r before refreshing the ++ * truesize of buff, otherwise the moved data will account twice. ++ */ ++ skb_set_owner_r(buff, sk); ++ nlen = skb->len - len - nsize; ++ buff->truesize += nlen; ++ skb->truesize -= nlen; ++ ++ /* Correct the sequence numbers. */ ++ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; ++ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; ++ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; ++ ++ skb_split(skb, buff, len); ++ ++ __skb_queue_after(&sk->sk_receive_queue, skb, buff); ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_prevalidate_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If we are in infinite mode, the subflow-fin is in fact a data-fin. */ ++ if (!skb->len && (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ !mptcp_is_data_fin(skb) && !mpcb->infinite_mapping_rcv) { ++ /* Remove a pure subflow-fin from the queue and increase ++ * copied_seq. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* If we are not yet fully established and do not know the mapping for ++ * this segment, this path has to fallback to infinite or be torn down. ++ */ ++ if (!tp->mptcp->fully_established && !mptcp_is_data_seq(skb) && ++ !tp->mptcp->mapping_present && !mpcb->infinite_mapping_rcv) { ++ pr_err("%s %#x will fallback - pi %d from %pS, seq %u\n", ++ __func__, mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, __builtin_return_address(0), ++ TCP_SKB_CB(skb)->seq); ++ ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATASUB); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATAINIT); ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ /* We do a seamless fallback and should not send a inf.mapping. */ ++ mpcb->send_infinite_mapping = 0; ++ tp->mptcp->fully_established = 1; ++ } ++ ++ /* Receiver-side becomes fully established when a whole rcv-window has ++ * been received without the need to fallback due to the previous ++ * condition. ++ */ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->init_rcv_wnd -= skb->len; ++ if (tp->mptcp->init_rcv_wnd < 0) ++ mptcp_become_fully_estab(sk); ++ } ++ ++ return 0; ++} ++ ++static void mptcp_restart_sending(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* We resend everything that has not been acknowledged */ ++ meta_sk->sk_send_head = tcp_write_queue_head(meta_sk); ++ ++ /* We artificially restart the whole send-queue. Thus, ++ * it is as if no packets are in flight ++ */ ++ meta_tp->packets_out = 0; ++ ++ /* If the snd_nxt already wrapped around, we have to ++ * undo the wrapping, as we are restarting from snd_una ++ * on. ++ */ ++ if (meta_tp->snd_nxt < meta_tp->snd_una) { ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] -= 2; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ } ++ meta_tp->snd_nxt = meta_tp->snd_una; ++ ++ /* Trigger a sending on the meta. */ ++ mptcp_push_pending_frames(meta_sk); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_detect_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 *ptr; ++ u32 data_seq, sub_seq, data_len, tcp_end_seq; ++ bool set_infinite_rcv = false; ++ ++ /* If we are in infinite-mapping-mode, the subflow is guaranteed to be ++ * in-order at the data-level. Thus data-seq-numbers can be inferred ++ * from what is expected at the data-level. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ /* copied_seq may be bigger than tcb->seq (e.g., when the peer ++ * retransmits data that actually has already been acknowledged with ++ * newer data, if he did not receive our acks). Thus, we need ++ * to account for this overlap as well. ++ */ ++ tp->mptcp->map_data_seq = mpcb->infinite_rcv_seq - (tp->copied_seq - tcb->seq); ++ tp->mptcp->map_subseq = tcb->seq; ++ tp->mptcp->map_data_len = skb->len; ++ tp->mptcp->map_data_fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN); ++ tp->mptcp->mapping_present = 1; ++ return 0; ++ } ++ ++ /* No mapping here? Exit - it is either already set or still on its way */ ++ if (!mptcp_is_data_seq(skb)) { ++ /* Too many packets without a mapping - this subflow is broken */ ++ if (!tp->mptcp->mapping_present && ++ tp->rcv_nxt - tp->copied_seq > 65536) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_NODSSWINDOW); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ return 0; ++ } ++ ++ ptr = mptcp_skb_set_data_seq(skb, &data_seq, mpcb); ++ ptr++; ++ sub_seq = get_unaligned_be32(ptr) + tp->mptcp->rcv_isn; ++ ptr++; ++ data_len = get_unaligned_be16(ptr); ++ ++ /* If it's an empty skb with DATA_FIN, sub_seq must get fixed. ++ * The draft sets it to 0, but we really would like to have the ++ * real value, to have an easy handling afterwards here in this ++ * function. ++ */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ sub_seq = TCP_SKB_CB(skb)->seq; ++ ++ /* If there is already a mapping - we check if it maps with the current ++ * one. If not - we reset. ++ */ ++ if (tp->mptcp->mapping_present && ++ (data_seq != (u32)tp->mptcp->map_data_seq || ++ sub_seq != tp->mptcp->map_subseq || ++ data_len != tp->mptcp->map_data_len + tp->mptcp->map_data_fin || ++ mptcp_is_data_fin(skb) != tp->mptcp->map_data_fin)) { ++ /* Mapping in packet is different from what we want */ ++ pr_err("%s Mappings do not match!\n", __func__); ++ pr_err("%s dseq %u mdseq %u, sseq %u msseq %u dlen %u mdlen %u dfin %d mdfin %d\n", ++ __func__, data_seq, (u32)tp->mptcp->map_data_seq, ++ sub_seq, tp->mptcp->map_subseq, data_len, ++ tp->mptcp->map_data_len, mptcp_is_data_fin(skb), ++ tp->mptcp->map_data_fin); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSNOMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* If the previous check was good, the current mapping is valid and we exit. */ ++ if (tp->mptcp->mapping_present) ++ return 0; ++ ++ /* Mapping not yet set on this subflow - we set it here! */ ++ ++ if (!data_len) { ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->send_infinite_mapping = 1; ++ tp->mptcp->fully_established = 1; ++ /* We need to repeat mp_fail's until the sender felt ++ * back to infinite-mapping - here we stop repeating it. ++ */ ++ tp->mptcp->send_mp_fail = 0; ++ ++ /* We have to fixup data_len - it must be the same as skb->len */ ++ data_len = skb->len + (mptcp_is_data_fin(skb) ? 1 : 0); ++ sub_seq = tcb->seq; ++ ++ mptcp_restart_sending(tp->meta_sk); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ /* data_seq and so on are set correctly */ ++ ++ /* At this point, the meta-ofo-queue has to be emptied, ++ * as the following data is guaranteed to be in-order at ++ * the data and subflow-level ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ ++ set_infinite_rcv = true; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_INFINITEMAPRX); ++ } ++ ++ /* We are sending mp-fail's and thus are in fallback mode. ++ * Ignore packets which do not announce the fallback and still ++ * want to provide a mapping. ++ */ ++ if (tp->mptcp->send_mp_fail) { ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* FIN increased the mapping-length by 1 */ ++ if (mptcp_is_data_fin(skb)) ++ data_len--; ++ ++ /* Subflow-sequences of packet must be ++ * (at least partially) be part of the DSS-mapping's ++ * subflow-sequence-space. ++ * ++ * Basically the mapping is not valid, if either of the ++ * following conditions is true: ++ * ++ * 1. It's not a data_fin and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * 2. It's a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * The previous two can be merged into: ++ * TCP-end_seq > TCP-seq and MPTCP-sub_seq >= TCP-end_seq ++ * Because if it's not a data-fin, TCP-end_seq > TCP-seq ++ * ++ * 3. It's a data_fin and skb->len == 0 and ++ * MPTCP-sub_seq > TCP-end_seq ++ * ++ * 4. It's not a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq + MPTCP-data_len <= TCP-seq ++ */ ++ ++ /* subflow-fin is not part of the mapping - ignore it here ! */ ++ tcp_end_seq = tcb->end_seq; ++ if (tcb->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if ((!before(sub_seq, tcb->end_seq) && after(tcp_end_seq, tcb->seq)) || ++ (mptcp_is_data_fin(skb) && skb->len == 0 && after(sub_seq, tcb->end_seq)) || ++ (!after(sub_seq + data_len, tcb->seq) && after(tcp_end_seq, tcb->seq))) { ++ /* Subflow-sequences of packet is different from what is in the ++ * packet's dss-mapping. The peer is misbehaving - reset ++ */ ++ pr_err("%s Packet's mapping does not map to the DSS sub_seq %u " ++ "end_seq %u, tcp_end_seq %u seq %u dfin %u len %u data_len %u" ++ "copied_seq %u\n", __func__, sub_seq, tcb->end_seq, tcp_end_seq, tcb->seq, mptcp_is_data_fin(skb), ++ skb->len, data_len, tp->copied_seq); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTCPMISMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* Does the DSS had 64-bit seqnum's ? */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_SEQ64_SET)) { ++ /* Wrapped around? */ ++ if (unlikely(after(data_seq, meta_tp->rcv_nxt) && data_seq < meta_tp->rcv_nxt)) { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, !mpcb->rcv_hiseq_index, data_seq); ++ } else { ++ /* Else, access the default high-order bits */ ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, data_seq); ++ } ++ } else { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, (tcb->mptcp_flags & MPTCPHDR_SEQ64_INDEX) ? 1 : 0, data_seq); ++ ++ if (unlikely(tcb->mptcp_flags & MPTCPHDR_SEQ64_OFO)) { ++ /* We make sure that the data_seq is invalid. ++ * It will be dropped later. ++ */ ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ } ++ } ++ ++ if (set_infinite_rcv) ++ mpcb->infinite_rcv_seq = tp->mptcp->map_data_seq; ++ ++ tp->mptcp->map_data_len = data_len; ++ tp->mptcp->map_subseq = sub_seq; ++ tp->mptcp->map_data_fin = mptcp_is_data_fin(skb) ? 1 : 0; ++ tp->mptcp->mapping_present = 1; ++ ++ return 0; ++} ++ ++/* Similar to tcp_sequence(...) */ ++static inline bool mptcp_sequence(const struct tcp_sock *meta_tp, ++ u64 data_seq, u64 end_data_seq) ++{ ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u64 rcv_wup64; ++ ++ /* Wrap-around? */ ++ if (meta_tp->rcv_wup > meta_tp->rcv_nxt) { ++ rcv_wup64 = ((u64)(mpcb->rcv_high_order[mpcb->rcv_hiseq_index] - 1) << 32) | ++ meta_tp->rcv_wup; ++ } else { ++ rcv_wup64 = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_wup); ++ } ++ ++ return !before64(end_data_seq, rcv_wup64) && ++ !after64(data_seq, mptcp_get_rcv_nxt_64(meta_tp) + tcp_receive_window(meta_tp)); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_validate_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1; ++ u32 tcp_end_seq; ++ ++ if (!tp->mptcp->mapping_present) ++ return 0; ++ ++ /* either, the new skb gave us the mapping and the first segment ++ * in the sub-rcv-queue has to be trimmed ... ++ */ ++ tmp = skb_peek(&sk->sk_receive_queue); ++ if (before(TCP_SKB_CB(tmp)->seq, tp->mptcp->map_subseq) && ++ after(TCP_SKB_CB(tmp)->end_seq, tp->mptcp->map_subseq)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTRIMHEAD); ++ mptcp_skb_trim_head(tmp, sk, tp->mptcp->map_subseq); ++ } ++ ++ /* ... or the new skb (tail) has to be split at the end. */ ++ tcp_end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if (after(tcp_end_seq, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) { ++ u32 seq = tp->mptcp->map_subseq + tp->mptcp->map_data_len; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSSPLITTAIL); ++ if (mptcp_skb_split_tail(skb, sk, seq)) { /* Allocation failed */ ++ /* TODO : maybe handle this here better. ++ * We now just force meta-retransmission. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ } ++ ++ /* Now, remove old sk_buff's from the receive-queue. ++ * This may happen if the mapping has been lost for these segments and ++ * the next mapping has already been received. ++ */ ++ if (before(TCP_SKB_CB(skb_peek(&sk->sk_receive_queue))->seq, tp->mptcp->map_subseq)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ if (!before(TCP_SKB_CB(tmp1)->seq, tp->mptcp->map_subseq)) ++ break; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PURGEOLD); ++ /* Impossible that we could free skb here, because his ++ * mapping is known to be valid from previous checks ++ */ ++ __kfree_skb(tmp1); ++ } ++ } ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this mapping has been put in the meta-receive-queue ++ * -2 this mapping has been eaten by the application ++ */ ++static int mptcp_queue_skb(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sk_buff *tmp, *tmp1; ++ u64 rcv_nxt64 = mptcp_get_rcv_nxt_64(meta_tp); ++ u32 old_copied_seq = tp->copied_seq; ++ bool data_queued = false; ++ ++ /* Have we not yet received the full mapping? */ ++ if (!tp->mptcp->mapping_present || ++ before(tp->rcv_nxt, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ return 0; ++ ++ /* Is this an overlapping mapping? rcv_nxt >= end_data_seq ++ * OR ++ * This mapping is out of window ++ */ ++ if (!before64(rcv_nxt64, tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin) || ++ !mptcp_sequence(meta_tp, tp->mptcp->map_data_seq, ++ tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return -1; ++ } ++ ++ /* Record it, because we want to send our data_fin on the same path */ ++ if (tp->mptcp->map_data_fin) { ++ mpcb->dfin_path_index = tp->mptcp->path_index; ++ mpcb->dfin_combined = !!(sk->sk_shutdown & RCV_SHUTDOWN); ++ } ++ ++ /* Verify the checksum */ ++ if (mpcb->dss_csum && !mpcb->infinite_mapping_rcv) { ++ int ret = mptcp_verif_dss_csum(sk); ++ ++ if (ret <= 0) { ++ mptcp_reset_mapping(tp, old_copied_seq); ++ return 1; ++ } ++ } ++ ++ if (before64(rcv_nxt64, tp->mptcp->map_data_seq)) { ++ /* Seg's have to go to the meta-ofo-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true later. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ if (!mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ tcp_data_queue_ofo(meta_sk, tmp1); ++ else ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ /* Quick ACK if more 3/4 of the receive window is filled */ ++ if (after64(tp->mptcp->map_data_seq, ++ rcv_nxt64 + 3 * (tcp_receive_window(meta_tp) >> 2))) ++ tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); ++ ++ } else { ++ /* Ready for the meta-rcv-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ int eaten = 0; ++ bool fragstolen = false; ++ u32 old_rcv_nxt = meta_tp->rcv_nxt; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ /* This segment has already been received */ ++ if (!after(TCP_SKB_CB(tmp1)->end_seq, meta_tp->rcv_nxt)) { ++ __kfree_skb(tmp1); ++ goto next; ++ } ++ ++ /* Is direct copy possible ? */ ++ if (TCP_SKB_CB(tmp1)->seq == meta_tp->rcv_nxt && ++ meta_tp->ucopy.task == current && ++ meta_tp->copied_seq == meta_tp->rcv_nxt && ++ meta_tp->ucopy.len && sock_owned_by_user(meta_sk)) ++ eaten = mptcp_direct_copy(tmp1, meta_sk); ++ ++ if (mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ eaten = 1; ++ ++ if (!eaten) ++ eaten = tcp_queue_rcv(meta_sk, tmp1, 0, &fragstolen); ++ ++ meta_tp->rcv_nxt = TCP_SKB_CB(tmp1)->end_seq; ++ ++ if (TCP_SKB_CB(tmp1)->tcp_flags & TCPHDR_FIN) ++ mptcp_fin(meta_sk); ++ ++ /* Check if this fills a gap in the ofo queue */ ++ if (!RB_EMPTY_ROOT(&meta_tp->out_of_order_queue)) ++ tcp_ofo_queue(meta_sk); ++ ++ mptcp_check_rcvseq_wrap(meta_tp, old_rcv_nxt); ++ ++ if (eaten) ++ kfree_skb_partial(tmp1, fragstolen); ++ ++ data_queued = true; ++next: ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ } ++ ++ inet_csk(meta_sk)->icsk_ack.lrcvtime = tcp_time_stamp; ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return data_queued ? -1 : -2; ++} ++ ++void mptcp_data_ready(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb, *tmp; ++ int queued = 0; ++ ++ /* restart before the check, because mptcp_fin might have changed the ++ * state. ++ */ ++restart: ++ /* If the meta cannot receive data, there is no point in pushing data. ++ * If we are in time-wait, we may still be waiting for the final FIN. ++ * So, we should proceed with the processing. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !tcp_sk(sk)->mpcb->in_time_wait) { ++ skb_queue_purge(&sk->sk_receive_queue); ++ tcp_sk(sk)->copied_seq = tcp_sk(sk)->rcv_nxt; ++ goto exit; ++ } ++ ++ /* Iterate over all segments, detect their mapping (if we don't have ++ * one yet), validate them and push everything one level higher. ++ */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { ++ int ret; ++ /* Pre-validation - e.g., early fallback */ ++ ret = mptcp_prevalidate_skb(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Set the current mapping */ ++ ret = mptcp_detect_mapping(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Validation */ ++ if (mptcp_validate_mapping(sk, skb) < 0) ++ goto restart; ++ ++ /* Push a level higher */ ++ ret = mptcp_queue_skb(sk); ++ if (ret < 0) { ++ if (ret == -1) ++ queued = ret; ++ goto restart; ++ } else if (ret == 0) { ++ continue; ++ } else { /* ret == 1 */ ++ break; ++ } ++ } ++ ++exit: ++ if (tcp_sk(sk)->close_it && sk->sk_state == TCP_FIN_WAIT2) { ++ tcp_send_ack(sk); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_TIME_WAIT, 0); ++ } ++ ++ if (queued == -1 && !sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_data_ready(meta_sk); ++} ++ ++struct mp_join *mptcp_find_join(const struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether JOIN is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return NULL; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return NULL; ++ if (opsize > length) ++ return NULL; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)(ptr - 2))->sub == MPTCP_SUB_JOIN) { ++ return (struct mp_join *)(ptr - 2); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return NULL; ++} ++ ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw) ++{ ++ const struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ struct mp_join *join_opt = mptcp_find_join(skb); ++ if (!join_opt) ++ return 0; ++ ++ /* MPTCP structures were not initialized, so return error */ ++ if (mptcp_init_failed) ++ return -1; ++ ++ token = join_opt->u.syn.token; ++ meta_sk = mptcp_hash_find(dev_net(skb_dst(skb)->dev), token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ if (mpcb->infinite_mapping_rcv || mpcb->send_infinite_mapping) { ++ /* We are in fallback-mode on the reception-side - ++ * no new subflows! ++ */ ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINFALLBACK); ++ return -1; ++ } ++ ++ /* Coming from time-wait-sock processing in tcp_v4_rcv. ++ * We have to deschedule it before continuing, because otherwise ++ * mptcp_v4_do_rcv will hit again on it inside tcp_v4_hnd_req. ++ */ ++ if (tw) ++ inet_twsk_deschedule_put(tw); ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ if (unlikely(sk_add_backlog(meta_sk, skb, ++ meta_sk->sk_rcvbuf + meta_sk->sk_sndbuf))) { ++ bh_unlock_sock(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPBACKLOGDROP); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ kfree_skb(skb); ++ return 1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 1; ++} ++ ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ ++ token = mopt->mptcp_rem_token; ++ meta_sk = mptcp_hash_find(net, token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ bh_lock_sock(meta_sk); ++ ++ /* This check is also done in mptcp_vX_do_rcv. But, there we cannot ++ * call tcp_vX_send_reset, because we hold already two socket-locks. ++ * (the listener and the meta from above) ++ * ++ * And the send-reset will try to take yet another one (ip_send_reply). ++ * Thus, we propagate the reset up to tcp_rcv_state_process. ++ */ ++ if (tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv || ++ tcp_sk(meta_sk)->mpcb->send_infinite_mapping || ++ meta_sk->sk_state == TCP_CLOSE || !tcp_sk(meta_sk)->inside_tk_table) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINFALLBACK); ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (unlikely(sk_add_backlog(meta_sk, skb, ++ meta_sk->sk_rcvbuf + meta_sk->sk_sndbuf))) ++ __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP); ++ else ++ /* Must make sure that upper layers won't free the ++ * skb if it is added to the backlog-queue. ++ */ ++ skb_get(skb); ++ } else { ++ /* mptcp_v4_do_rcv tries to free the skb - we prevent this, as ++ * the skb will finally be freed by tcp_v4_do_rcv (where we are ++ * coming from) ++ */ ++ skb_get(skb); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { /* IPv6 */ ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ } ++ ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 0; ++} ++ ++/** ++ * Equivalent of tcp_fin() for MPTCP ++ * Can be called only when the FIN is validly part ++ * of the data seqnum space. Not before when we get holes. ++ */ ++void mptcp_fin(struct sock *meta_sk) ++{ ++ struct sock *sk = NULL, *sk_it; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ unsigned char state; ++ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ if (tcp_sk(sk_it)->mptcp->path_index == mpcb->dfin_path_index) { ++ sk = sk_it; ++ break; ++ } ++ } ++ ++ if (!sk || sk->sk_state == TCP_CLOSE) ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ inet_csk_schedule_ack(sk); ++ ++ if (!mpcb->in_time_wait) { ++ meta_sk->sk_shutdown |= RCV_SHUTDOWN; ++ sock_set_flag(meta_sk, SOCK_DONE); ++ state = meta_sk->sk_state; ++ } else { ++ state = mpcb->mptw_state; ++ } ++ ++ switch (state) { ++ case TCP_SYN_RECV: ++ case TCP_ESTABLISHED: ++ /* Move to CLOSE_WAIT */ ++ tcp_set_state(meta_sk, TCP_CLOSE_WAIT); ++ inet_csk(sk)->icsk_ack.pingpong = 1; ++ break; ++ ++ case TCP_CLOSE_WAIT: ++ case TCP_CLOSING: ++ /* Received a retransmission of the FIN, do ++ * nothing. ++ */ ++ break; ++ case TCP_LAST_ACK: ++ /* RFC793: Remain in the LAST-ACK state. */ ++ break; ++ ++ case TCP_FIN_WAIT1: ++ /* This case occurs when a simultaneous close ++ * happens, we must ack the received FIN and ++ * enter the CLOSING state. ++ */ ++ tcp_send_ack(sk); ++ tcp_set_state(meta_sk, TCP_CLOSING); ++ break; ++ case TCP_FIN_WAIT2: ++ /* Received a FIN -- send ACK and enter TIME_WAIT. */ ++ tcp_send_ack(sk); ++ meta_tp->ops->time_wait(meta_sk, TCP_TIME_WAIT, 0); ++ break; ++ default: ++ /* Only TCP_LISTEN and TCP_CLOSE are left, in these ++ * cases we should never reach this piece of code. ++ */ ++ pr_err("%s: Impossible, meta_sk->sk_state=%d\n", __func__, ++ meta_sk->sk_state); ++ break; ++ } ++ ++ /* It _is_ possible, that we have something out-of-order _after_ FIN. ++ * Probably, we should reset in this case. For now drop them. ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ sk_mem_reclaim(meta_sk); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ ++ /* Do not send POLL_HUP for half duplex close. */ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || ++ meta_sk->sk_state == TCP_CLOSE) ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_HUP); ++ else ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_IN); ++ } ++ ++ return; ++} ++ ++static void mptcp_xmit_retransmit_queue(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ ++ if (!meta_tp->packets_out) ++ return; ++ ++ tcp_for_write_queue(skb, meta_sk) { ++ if (skb == tcp_send_head(meta_sk)) ++ break; ++ ++ if (mptcp_retransmit_skb(meta_sk, skb)) ++ return; ++ ++ if (skb == tcp_write_queue_head(meta_sk)) ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ inet_csk(meta_sk)->icsk_rto, ++ TCP_RTO_MAX); ++ } ++} ++ ++static void mptcp_snd_una_update(struct tcp_sock *meta_tp, u32 data_ack) ++{ ++ u32 delta = data_ack - meta_tp->snd_una; ++ ++ u64_stats_update_begin(&meta_tp->syncp); ++ meta_tp->bytes_acked += delta; ++ u64_stats_update_end(&meta_tp->syncp); ++ meta_tp->snd_una = data_ack; ++} ++ ++/* Handle the DATA_ACK */ ++static void mptcp_data_ack(struct sock *sk, const struct sk_buff *skb) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 prior_snd_una = meta_tp->snd_una; ++ int prior_packets; ++ u32 nwin, data_ack, data_seq; ++ u16 data_len = 0; ++ ++ /* A valid packet came in - subflow is operational again */ ++ tp->pf = 0; ++ ++ /* Even if there is no data-ack, we stop retransmitting. ++ * Except if this is a SYN/ACK. Then it is just a retransmission ++ */ ++ if (tp->mptcp->pre_established && !tcp_hdr(skb)->syn) { ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++ ++ /* If we are in infinite mapping mode, rx_opt.data_ack has been ++ * set by mptcp_clean_rtx_infinite. ++ */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_ACK) && !tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ if (unlikely(!tp->mptcp->fully_established) && ++ tp->mptcp->snt_isn + 1 != TCP_SKB_CB(skb)->ack_seq) ++ /* As soon as a subflow-data-ack (not acking syn, thus snt_isn + 1) ++ * includes a data-ack, we are fully established ++ */ ++ mptcp_become_fully_estab(sk); ++ ++ /* After we did the subflow-only processing (stopping timer and marking ++ * subflow as established), check if we can proceed with MPTCP-level ++ * processing. ++ */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ /* Get the data_seq */ ++ if (mptcp_is_data_seq(skb)) { ++ data_seq = tp->mptcp->rx_opt.data_seq; ++ data_len = tp->mptcp->rx_opt.data_len; ++ } else { ++ data_seq = meta_tp->snd_wl1; ++ } ++ ++ data_ack = tp->mptcp->rx_opt.data_ack; ++ ++ /* If the ack is older than previous acks ++ * then we can probably ignore it. ++ */ ++ if (before(data_ack, prior_snd_una)) ++ goto exit; ++ ++ /* If the ack includes data we haven't sent yet, discard ++ * this segment (RFC793 Section 3.9). ++ */ ++ if (after(data_ack, meta_tp->snd_nxt)) ++ goto exit; ++ ++ /*** Now, update the window - inspired by tcp_ack_update_window ***/ ++ nwin = ntohs(tcp_hdr(skb)->window); ++ ++ if (likely(!tcp_hdr(skb)->syn)) ++ nwin <<= tp->rx_opt.snd_wscale; ++ ++ if (tcp_may_update_window(meta_tp, data_ack, data_seq, nwin)) { ++ tcp_update_wl(meta_tp, data_seq); ++ ++ /* Draft v09, Section 3.3.5: ++ * [...] It should only update its local receive window values ++ * when the largest sequence number allowed (i.e. DATA_ACK + ++ * receive window) increases. [...] ++ */ ++ if (meta_tp->snd_wnd != nwin && ++ !before(data_ack + nwin, tcp_wnd_end(meta_tp))) { ++ meta_tp->snd_wnd = nwin; ++ ++ if (nwin > meta_tp->max_window) ++ meta_tp->max_window = nwin; ++ } ++ } ++ /*** Done, update the window ***/ ++ ++ /* We passed data and got it acked, remove any soft error ++ * log. Something worked... ++ */ ++ sk->sk_err_soft = 0; ++ inet_csk(meta_sk)->icsk_probes_out = 0; ++ meta_tp->rcv_tstamp = tcp_time_stamp; ++ prior_packets = meta_tp->packets_out; ++ if (!prior_packets) ++ goto no_queue; ++ ++ mptcp_snd_una_update(meta_tp, data_ack); ++ ++ mptcp_clean_rtx_queue(meta_sk, prior_snd_una); ++ ++ /* We are in loss-state, and something got acked, retransmit the whole ++ * queue now! ++ */ ++ if (inet_csk(meta_sk)->icsk_ca_state == TCP_CA_Loss && ++ after(data_ack, prior_snd_una)) { ++ mptcp_xmit_retransmit_queue(meta_sk); ++ inet_csk(meta_sk)->icsk_ca_state = TCP_CA_Open; ++ } ++ ++ /* Simplified version of tcp_new_space, because the snd-buffer ++ * is handled by all the subflows. ++ */ ++ if (sock_flag(meta_sk, SOCK_QUEUE_SHRUNK)) { ++ sock_reset_flag(meta_sk, SOCK_QUEUE_SHRUNK); ++ if (meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ meta_sk->sk_write_space(meta_sk); ++ } ++ ++ if (meta_sk->sk_state != TCP_ESTABLISHED && ++ mptcp_rcv_state_process(meta_sk, sk, skb, data_seq, data_len)) ++ return; ++ ++exit: ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++ ++no_queue: ++ if (tcp_send_head(meta_sk)) ++ tcp_ack_probe(meta_sk); ++ ++ mptcp_push_pending_frames(meta_sk); ++ ++ return; ++} ++ ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(mptcp_meta_sk(sk)); ++ ++ if (!tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ /* The difference between both write_seq's represents the offset between ++ * data-sequence and subflow-sequence. As we are infinite, this must ++ * match. ++ * ++ * Thus, from this difference we can infer the meta snd_una. ++ */ ++ tp->mptcp->rx_opt.data_ack = meta_tp->snd_nxt - tp->snd_nxt + ++ tp->snd_una; ++ ++ mptcp_data_ack(sk, skb); ++} ++ ++/**** static functions used by mptcp_parse_options */ ++ ++static void mptcp_send_reset_rem_id(const struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ struct sock *sk_it, *tmpsk; ++ ++ mptcp_for_each_sk_safe(mpcb, sk_it, tmpsk) { ++ if (tcp_sk(sk_it)->mptcp->rem_id == rem_id) { ++ mptcp_reinject_data(sk_it, 0); ++ mptcp_send_reset(sk_it); ++ } ++ } ++} ++ ++static inline bool is_valid_addropt_opsize(u8 mptcp_ver, ++ struct mp_add_addr *mpadd, ++ int opsize) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 6) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 6) ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2; ++#endif ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1 && mpadd->ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++ } ++ return false; ++} ++ ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp) ++{ ++ const struct mptcp_option *mp_opt = (struct mptcp_option *)ptr; ++ ++ /* If the socket is mp-capable we would have a mopt. */ ++ if (!mopt) ++ return; ++ ++ switch (mp_opt->sub) { ++ case MPTCP_SUB_CAPABLE: ++ { ++ const struct mp_capable *mpcapable = (struct mp_capable *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_CAPABLE_SYN && ++ opsize != MPTCP_SUB_LEN_CAPABLE_ACK) { ++ mptcp_debug("%s: mp_capable: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "If receiving a message with the 'B' flag set to 1, and this ++ * is not understood, then this SYN MUST be silently ignored; ++ */ ++ if (mpcapable->b) { ++ mopt->drop_me = 1; ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "An implementation that only supports this method MUST set ++ * bit "H" to 1, and bits "C" through "G" to 0." ++ */ ++ if (!mpcapable->h) ++ break; ++ ++ mopt->saw_mpc = 1; ++ mopt->dss_csum = sysctl_mptcp_checksum || mpcapable->a; ++ ++ if (opsize >= MPTCP_SUB_LEN_CAPABLE_SYN) ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ if (opsize == MPTCP_SUB_LEN_CAPABLE_ACK) ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ ++ mopt->mptcp_ver = mpcapable->ver; ++ break; ++ } ++ case MPTCP_SUB_JOIN: ++ { ++ const struct mp_join *mpjoin = (struct mp_join *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_JOIN_SYN && ++ opsize != MPTCP_SUB_LEN_JOIN_SYNACK && ++ opsize != MPTCP_SUB_LEN_JOIN_ACK) { ++ mptcp_debug("%s: mp_join: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* saw_mpc must be set, because in tcp_check_req we assume that ++ * it is set to support falling back to reg. TCP if a rexmitted ++ * SYN has no MP_CAPABLE or MP_JOIN ++ */ ++ switch (opsize) { ++ case MPTCP_SUB_LEN_JOIN_SYN: ++ mopt->is_mp_join = 1; ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_rem_token = mpjoin->u.syn.token; ++ mopt->mptcp_recv_nonce = mpjoin->u.syn.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_SYNACK: ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_recv_tmac = mpjoin->u.synack.mac; ++ mopt->mptcp_recv_nonce = mpjoin->u.synack.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_ACK: ++ mopt->saw_mpc = 1; ++ mopt->join_ack = 1; ++ memcpy(mopt->mptcp_recv_mac, mpjoin->u.ack.mac, 20); ++ break; ++ } ++ break; ++ } ++ case MPTCP_SUB_DSS: ++ { ++ const struct mp_dss *mdss = (struct mp_dss *)ptr; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ ++ /* We check opsize for the csum and non-csum case. We do this, ++ * because the draft says that the csum SHOULD be ignored if ++ * it has not been negotiated in the MP_CAPABLE but still is ++ * present in the data. ++ * ++ * It will get ignored later in mptcp_queue_skb. ++ */ ++ if (opsize != mptcp_sub_len_dss(mdss, 0) && ++ opsize != mptcp_sub_len_dss(mdss, 1)) { ++ mptcp_debug("%s: mp_dss: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ ptr += 4; ++ ++ if (mdss->A) { ++ tcb->mptcp_flags |= MPTCPHDR_ACK; ++ ++ if (mdss->a) { ++ mopt->data_ack = (u32) get_unaligned_be64(ptr); ++ ptr += MPTCP_SUB_LEN_ACK_64; ++ } else { ++ mopt->data_ack = get_unaligned_be32(ptr); ++ ptr += MPTCP_SUB_LEN_ACK; ++ } ++ } ++ ++ tcb->dss_off = (ptr - skb_transport_header(skb)); ++ ++ if (mdss->M) { ++ if (mdss->m) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ64_SET; ++ mopt->data_seq = (u32) data_seq64; ++ ++ ptr += 12; /* 64-bit dseq + subseq */ ++ } else { ++ mopt->data_seq = get_unaligned_be32(ptr); ++ ptr += 8; /* 32-bit dseq + subseq */ ++ } ++ mopt->data_len = get_unaligned_be16(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ /* Is a check-sum present? */ ++ if (opsize == mptcp_sub_len_dss(mdss, 1)) ++ tcb->mptcp_flags |= MPTCPHDR_DSS_CSUM; ++ ++ /* DATA_FIN only possible with DSS-mapping */ ++ if (mdss->F) ++ tcb->mptcp_flags |= MPTCPHDR_FIN; ++ } ++ ++ break; ++ } ++ case MPTCP_SUB_ADD_ADDR: ++ { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ /* If tcp_sock is not available, MPTCP version can't be ++ * retrieved and ADD_ADDR opsize validation is not possible. ++ */ ++ if (!tp || !tp->mpcb) ++ break; ++ ++ if (!is_valid_addropt_opsize(tp->mpcb->mptcp_ver, ++ mpadd, opsize)) { ++ mptcp_debug("%s: mp_add_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* We have to manually parse the options if we got two of them. */ ++ if (mopt->saw_add_addr) { ++ mopt->more_add_addr = 1; ++ break; ++ } ++ mopt->saw_add_addr = 1; ++ mopt->add_addr_ptr = ptr; ++ break; ++ } ++ case MPTCP_SUB_REMOVE_ADDR: ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) { ++ mptcp_debug("%s: mp_remove_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ if (mopt->saw_rem_addr) { ++ mopt->more_rem_addr = 1; ++ break; ++ } ++ mopt->saw_rem_addr = 1; ++ mopt->rem_addr_ptr = ptr; ++ break; ++ case MPTCP_SUB_PRIO: ++ { ++ const struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_PRIO && ++ opsize != MPTCP_SUB_LEN_PRIO_ADDR) { ++ mptcp_debug("%s: mp_prio: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->saw_low_prio = 1; ++ mopt->low_prio = mpprio->b; ++ ++ if (opsize == MPTCP_SUB_LEN_PRIO_ADDR) { ++ mopt->saw_low_prio = 2; ++ mopt->prio_addr_id = mpprio->addr_id; ++ } ++ break; ++ } ++ case MPTCP_SUB_FAIL: ++ if (opsize != MPTCP_SUB_LEN_FAIL) { ++ mptcp_debug("%s: mp_fail: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ mopt->mp_fail = 1; ++ break; ++ case MPTCP_SUB_FCLOSE: ++ if (opsize != MPTCP_SUB_LEN_FCLOSE) { ++ mptcp_debug("%s: mp_fclose: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->mp_fclose = 1; ++ mopt->mptcp_sender_key = ((struct mp_fclose *)ptr)->key; ++ ++ break; ++ default: ++ mptcp_debug("%s: Received unkown subtype: %d\n", ++ __func__, mp_opt->sub); ++ break; ++ } ++} ++ ++/** Parse only MPTCP options */ ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ const unsigned char *ptr = (const unsigned char *)(th + 1); ++ ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP) ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, NULL); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++} ++ ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *sk; ++ u32 rtt_max = 0; ++ ++ /* In MPTCP, we take the max delay across all flows, ++ * in order to take into account meta-reordering buffers. ++ */ ++ mptcp_for_each_sk(mpcb, sk) { ++ if (!mptcp_sk_can_recv(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->rcv_rtt_est.rtt) ++ rtt_max = tcp_sk(sk)->rcv_rtt_est.rtt; ++ } ++ if (time < (rtt_max >> 3) || !rtt_max) ++ return true; ++ ++ return false; ++} ++ ++static void mptcp_handle_add_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ __be16 port = 0; ++ union inet_addr addr; ++ sa_family_t family; ++ ++ if (mpadd->ipver == 4) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v4; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v4.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v4.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 4, (u8 *)&mpadd->u.v4.addr.s_addr, ++ 2, (u8 *)&mpadd->u.v4.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v4: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2)) ++ port = mpadd->u.v4.port; ++ family = AF_INET; ++ addr.in = mpadd->u.v4.addr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (mpadd->ipver == 6) { ++ char *recv_hmac; ++ u8 hash_mac_check[20]; ++ u8 no_key[8]; ++ int msg_parts = 0; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v6; ++ ++ *(u64 *)no_key = 0; ++ recv_hmac = (char *)mpadd->u.v6.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v6.port); ++ msg_parts = 2; ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2) { ++ msg_parts = 3; ++ } ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)no_key, ++ (u32 *)hash_mac_check, msg_parts, ++ 1, (u8 *)&mpadd->addr_id, ++ 16, (u8 *)&mpadd->u.v6.addr.s6_addr, ++ 2, (u8 *)&mpadd->u.v6.port); ++ if (memcmp(hash_mac_check, recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v6: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2)) ++ port = mpadd->u.v6.port; ++ family = AF_INET6; ++ addr.in6 = mpadd->u.v6.addr; ++#endif /* CONFIG_IPV6 */ ++ } else { ++ return; ++ } ++ ++ if (mpcb->pm_ops->add_raddr) ++ mpcb->pm_ops->add_raddr(mpcb, &addr, family, port, mpadd->addr_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRRX); ++} ++ ++static void mptcp_handle_rem_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ int i; ++ u8 rem_id; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ for (i = 0; i <= mprem->len - MPTCP_SUB_LEN_REMOVE_ADDR; i++) { ++ rem_id = (&mprem->addrs_id)[i]; ++ ++ if (mpcb->pm_ops->rem_raddr) ++ mpcb->pm_ops->rem_raddr(mpcb, rem_id); ++ mptcp_send_reset_rem_id(mpcb, rem_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRSUB); ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRRX); ++} ++ ++static void mptcp_parse_addropt(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether ADD_ADDR is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_ADD_ADDR) { ++ u8 mptcp_ver = tcp_sk(sk)->mpcb->mptcp_ver; ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ if (!is_valid_addropt_opsize(mptcp_ver, mpadd, ++ opsize)) ++ goto cont; ++ ++ mptcp_handle_add_addr(ptr, sk); ++ } ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_REMOVE_ADDR) { ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) ++ goto cont; ++ ++ mptcp_handle_rem_addr(ptr, sk); ++ } ++cont: ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return; ++} ++ ++static bool mptcp_mp_fastclose_rcvd(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ if (likely(!mptcp->rx_opt.mp_fclose)) ++ return false; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FASTCLOSERX); ++ mptcp->rx_opt.mp_fclose = 0; ++ if (mptcp->rx_opt.mptcp_sender_key != mpcb->mptcp_loc_key) ++ return false; ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ tcp_reset(mptcp_meta_sk(sk)); ++ ++ return true; ++} ++ ++static void mptcp_mp_fail_rcvd(struct sock *sk, const struct tcphdr *th) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX); ++ mptcp->rx_opt.mp_fail = 0; ++ ++ if (!th->rst && !mpcb->infinite_mapping_snd) { ++ mpcb->send_infinite_mapping = 1; ++ ++ mptcp_restart_sending(meta_sk); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ } ++} ++ ++static inline void mptcp_path_array_check(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (unlikely(mpcb->list_rcvd)) { ++ mpcb->list_rcvd = 0; ++ if (mpcb->pm_ops->new_remote_address) ++ mpcb->pm_ops->new_remote_address(meta_sk); ++ } ++} ++ ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ if (tp->mpcb->infinite_mapping_rcv || tp->mpcb->infinite_mapping_snd) ++ return false; ++ ++ if (mptcp_mp_fastclose_rcvd(sk)) ++ return true; ++ ++ if (sk->sk_state == TCP_RST_WAIT && !th->rst) ++ return true; ++ ++ if (unlikely(mopt->mp_fail)) ++ mptcp_mp_fail_rcvd(sk, th); ++ ++ /* RFC 6824, Section 3.3: ++ * If a checksum is not present when its use has been negotiated, the ++ * receiver MUST close the subflow with a RST as it is considered broken. ++ */ ++ if (mptcp_is_data_seq(skb) && tp->mpcb->dss_csum && ++ !(TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_DSS_CSUM)) { ++ mptcp_send_reset(sk); ++ return true; ++ } ++ ++ /* We have to acknowledge retransmissions of the third ++ * ack. ++ */ ++ if (mopt->join_ack) { ++ tcp_send_delayed_ack(sk); ++ mopt->join_ack = 0; ++ } ++ ++ if (mopt->saw_add_addr || mopt->saw_rem_addr) { ++ if (mopt->more_add_addr || mopt->more_rem_addr) { ++ mptcp_parse_addropt(skb, sk); ++ } else { ++ if (mopt->saw_add_addr) ++ mptcp_handle_add_addr(mopt->add_addr_ptr, sk); ++ if (mopt->saw_rem_addr) ++ mptcp_handle_rem_addr(mopt->rem_addr_ptr, sk); ++ } ++ ++ mopt->more_add_addr = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->saw_rem_addr = 0; ++ } ++ if (mopt->saw_low_prio) { ++ if (mopt->saw_low_prio == 1) { ++ tp->mptcp->rcv_low_prio = mopt->low_prio; ++ } else { ++ struct sock *sk_it; ++ mptcp_for_each_sk(tp->mpcb, sk_it) { ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk_it)->mptcp; ++ if (mptcp->rem_id == mopt->prio_addr_id) ++ mptcp->rcv_low_prio = mopt->low_prio; ++ } ++ } ++ mopt->saw_low_prio = 0; ++ } ++ ++ mptcp_data_ack(sk, skb); ++ ++ mptcp_path_array_check(mptcp_meta_sk(sk)); ++ /* Socket may have been mp_killed by a REMOVE_ADDR */ ++ if (tp->mp_killed) ++ return true; ++ ++ return false; ++} ++ ++/* In case of fastopen, some data can already be in the write queue. ++ * We need to update the sequence number of the segments as they ++ * were initially TCP sequence numbers. ++ */ ++static void mptcp_rcv_synsent_fastopen(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ struct sk_buff *skb; ++ u32 new_mapping = meta_tp->write_seq - master_tp->snd_una; ++ ++ /* There should only be one skb in write queue: the data not ++ * acknowledged in the SYN+ACK. In this case, we need to map ++ * this data to data sequence numbers. ++ */ ++ skb_queue_walk(&meta_sk->sk_write_queue, skb) { ++ /* If the server only acknowledges partially the data sent in ++ * the SYN, we need to trim the acknowledged part because ++ * we don't want to retransmit this already received data. ++ * When we reach this point, tcp_ack() has already cleaned up ++ * fully acked segments. However, tcp trims partially acked ++ * segments only when retransmitting. Since MPTCP comes into ++ * play only now, we will fake an initial transmit, and ++ * retransmit_skb() will not be called. The following fragment ++ * comes from __tcp_retransmit_skb(). ++ */ ++ if (before(TCP_SKB_CB(skb)->seq, master_tp->snd_una)) { ++ BUG_ON(before(TCP_SKB_CB(skb)->end_seq, ++ master_tp->snd_una)); ++ /* tcp_trim_head can only returns ENOMEM if skb is ++ * cloned. It is not the case here (see ++ * tcp_send_syn_data). ++ */ ++ BUG_ON(tcp_trim_head(meta_sk, skb, master_tp->snd_una - ++ TCP_SKB_CB(skb)->seq)); ++ } ++ ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* We can advance write_seq by the number of bytes unacknowledged ++ * and that were mapped in the previous loop. ++ */ ++ meta_tp->write_seq += master_tp->write_seq - master_tp->snd_una; ++ ++ /* The packets from the master_sk will be entailed to it later ++ * Until that time, its write queue is empty, and ++ * write_seq must align with snd_una ++ */ ++ master_tp->snd_nxt = master_tp->write_seq = master_tp->snd_una; ++ master_tp->packets_out = 0; ++ ++ /* Although these data have been sent already over the subsk, ++ * They have never been sent over the meta_sk, so we rewind ++ * the send_head so that tcp considers it as an initial send ++ * (instead of retransmit). ++ */ ++ meta_sk->sk_send_head = tcp_write_queue_head(meta_sk); ++} ++ ++/* The skptr is needed, because if we become MPTCP-capable, we have to switch ++ * from meta-socket to master-socket. ++ * ++ * @return: 1 - we want to reset this connection ++ * 2 - we want to discard the received syn/ack ++ * 0 - everything is fine - continue ++ */ ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (mptcp(tp)) { ++ u8 hash_mac_check[20]; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, ++ (u32 *)hash_mac_check, 2, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce); ++ if (memcmp(hash_mac_check, ++ (char *)&tp->mptcp->rx_opt.mptcp_recv_tmac, 8)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKMAC); ++ mptcp_sub_force_close(sk); ++ return 1; ++ } ++ ++ /* Set this flag in order to postpone data sending ++ * until the 4th ack arrives. ++ */ ++ tp->mptcp->pre_established = 1; ++ tp->mptcp->rcv_low_prio = tp->mptcp->rx_opt.low_prio; ++ ++ mptcp_hmac_sha1((u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ (u32 *)&tp->mptcp->sender_mac[0], 2, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX); ++ } else if (mopt->saw_mpc) { ++ struct sock *meta_sk = sk; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); ++ if (mopt->mptcp_ver > tcp_sk(sk)->mptcp_ver) ++ /* TODO Consider adding new MPTCP_INC_STATS entry */ ++ goto fallback; ++ ++ if (mptcp_create_master_sk(sk, mopt->mptcp_sender_key, ++ mopt->mptcp_ver, ++ ntohs(tcp_hdr(skb)->window))) ++ return 2; ++ ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ *skptr = sk; ++ tp = tcp_sk(sk); ++ ++ /* If fastopen was used data might be in the send queue. We ++ * need to update their sequence number to MPTCP-level seqno. ++ * Note that it can happen in rare cases that fastopen_req is ++ * NULL and syn_data is 0 but fastopen indeed occurred and ++ * data has been queued in the write queue (but not sent). ++ * Example of such rare cases: connect is non-blocking and ++ * TFO is configured to work without cookies. ++ */ ++ if (!skb_queue_empty(&meta_sk->sk_write_queue)) ++ mptcp_rcv_synsent_fastopen(meta_sk); ++ ++ /* -1, because the SYN consumed 1 byte. In case of TFO, we ++ * start the subflow-sequence number as if the data of the SYN ++ * is not part of any mapping. ++ */ ++ tp->mptcp->snt_isn = tp->snd_una - 1; ++ tp->mpcb->dss_csum = mopt->dss_csum; ++ if (tp->mpcb->dss_csum) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMENABLED); ++ ++ tp->mptcp->include_mpc = 1; ++ ++ /* Ensure that fastopen is handled at the meta-level. */ ++ tp->fastopen_req = NULL; ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ bh_unlock_sock(sk); ++ /* hold in sk_clone_lock due to initialization to 2 */ ++ sock_put(sk); ++ } else { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEFALLBACK); ++fallback: ++ tp->request_mptcp = 0; ++ ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ ++ if (mptcp(tp)) ++ tp->mptcp->rcv_isn = TCP_SKB_CB(skb)->seq; ++ ++ return 0; ++} ++ ++/* Similar to tcp_should_expand_sndbuf */ ++bool mptcp_should_expand_sndbuf(const struct sock *sk) ++{ ++ const struct sock *sk_it; ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int cnt_backups = 0; ++ int backup_available = 0; ++ ++ /* We circumvent this check in tcp_check_space, because we want to ++ * always call sk_write_space. So, we reproduce the check here. ++ */ ++ if (!meta_sk->sk_socket || ++ !test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ return false; ++ ++ /* If the user specified a specific send buffer setting, do ++ * not modify it. ++ */ ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return false; ++ ++ /* If we are under global TCP memory pressure, do not expand. */ ++ if (tcp_under_memory_pressure(meta_sk)) ++ return false; ++ ++ /* If we are under soft global TCP memory pressure, do not expand. */ ++ if (sk_memory_allocated(meta_sk) >= sk_prot_mem_limits(meta_sk, 0)) ++ return false; ++ ++ /* For MPTCP we look for a subsocket that could send data. ++ * If we found one, then we update the send-buffer. ++ */ ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ ++ if (!mptcp_sk_can_send(sk_it)) ++ continue; ++ ++ /* Backup-flows have to be counted - if there is no other ++ * subflow we take the backup-flow into account. ++ */ ++ if (tp_it->mptcp->rcv_low_prio || tp_it->mptcp->low_prio) ++ cnt_backups++; ++ ++ if (tcp_packets_in_flight(tp_it) < tp_it->snd_cwnd) { ++ if (tp_it->mptcp->rcv_low_prio || tp_it->mptcp->low_prio) { ++ backup_available = 1; ++ continue; ++ } ++ return true; ++ } ++ } ++ ++ /* Backup-flow is available for sending - update send-buffer */ ++ if (meta_tp->mpcb->cnt_established == cnt_backups && backup_available) ++ return true; ++ return false; ++} ++ ++void mptcp_init_buffer_space(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int space; ++ ++ tcp_init_buffer_space(sk); ++ ++ if (is_master_tp(tp)) { ++ meta_tp->rcvq_space.space = meta_tp->rcv_wnd; ++ meta_tp->rcvq_space.time = tcp_time_stamp; ++ meta_tp->rcvq_space.seq = meta_tp->copied_seq; ++ ++ /* If there is only one subflow, we just use regular TCP ++ * autotuning. User-locks are handled already by ++ * tcp_init_buffer_space ++ */ ++ meta_tp->window_clamp = tp->window_clamp; ++ meta_tp->rcv_ssthresh = tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = sk->sk_rcvbuf; ++ meta_sk->sk_sndbuf = sk->sk_sndbuf; ++ ++ return; ++ } ++ ++ if (meta_sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ goto snd_buf; ++ ++ /* Adding a new subflow to the rcv-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_rcvbuf + sk->sk_rcvbuf, sysctl_tcp_rmem[2]); ++ if (space > meta_sk->sk_rcvbuf) { ++ meta_tp->window_clamp += tp->window_clamp; ++ meta_tp->rcv_ssthresh += tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = space; ++ } ++ ++snd_buf: ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return; ++ ++ /* Adding a new subflow to the send-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_sndbuf + sk->sk_sndbuf, sysctl_tcp_wmem[2]); ++ if (space > meta_sk->sk_sndbuf) { ++ meta_sk->sk_sndbuf = space; ++ meta_sk->sk_write_space(meta_sk); ++ } ++} ++ ++void mptcp_tcp_set_rto(struct sock *sk) ++{ ++ tcp_set_rto(sk); ++ mptcp_set_rto(sk); ++} +diff -aurN linux-4.9.162/net/mptcp/mptcp_ipv4.c mptcp-mptcp_v0.93/net/mptcp/mptcp_ipv4.c +--- linux-4.9.162/net/mptcp/mptcp_ipv4.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_ipv4.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,446 @@ ++/* ++ * MPTCP implementation - IPv4-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) ++{ ++ u32 hash[MD5_DIGEST_WORDS]; ++ ++ hash[0] = (__force u32)saddr; ++ hash[1] = (__force u32)daddr; ++ hash[2] = ((__force u16)sport << 16) + (__force u16)dport; ++ hash[3] = mptcp_seed++; ++ ++ md5_transform(hash, mptcp_secret); ++ ++ return hash[0]; ++} ++ ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed) ++{ ++ u32 hash[MD5_DIGEST_WORDS]; ++ ++ hash[0] = (__force u32)saddr; ++ hash[1] = (__force u32)daddr; ++ hash[2] = ((__force u16)sport << 16) + (__force u16)dport; ++ hash[3] = seed; ++ ++ md5_transform(hash, mptcp_secret); ++ ++ return *((u64 *)hash); ++} ++ ++ ++static void mptcp_v4_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v4_reqsk_destructor(req); ++} ++ ++static int mptcp_v4_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v4_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v4_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++static int mptcp_v4_join_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v4_get_nonce(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.ip = inet_rsk(req)->ir_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(AF_INET, &addr, sock_net(sk), &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp_request_sock_ops */ ++struct request_sock_ops mptcp_request_sock_ops __read_mostly = { ++ .family = PF_INET, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v4_reqsk_send_ack, ++ .destructor = mptcp_v4_reqsk_destructor, ++ .send_reset = tcp_v4_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v4_conn_request */ ++static int mptcp_v4_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_join_request_sock_ipv4_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb) ++ __releases(&child->sk_lock.slock) ++{ ++ int ret; ++ ++ /* We don't call tcp_child_process here, because we hold ++ * already the meta-sk-lock and are sure that it is not owned ++ * by the user. ++ */ ++ tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ++ ret = tcp_rcv_state_process(child, skb); ++ bh_unlock_sock(child); ++ sock_put(child); ++ ++ return ret; ++} ++ ++ ++/* Similar to: tcp_v4_do_rcv ++ * We only process join requests here. (either the SYN or the final ACK) ++ */ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct iphdr *iph = ip_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = inet_lookup_established(sock_net(meta_sk), &tcp_hashinfo, ++ iph->saddr, th->source, iph->daddr, ++ th->dest, inet_iif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v4_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v4_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v4_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v4_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv4 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ mptcp_debug("%s inet_create failed ret: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ if (mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL)) ++ goto error; ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ setup_timer(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, (unsigned long)sk); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin_family = AF_INET; ++ rem_in.sin_family = AF_INET; ++ loc_in.sin_port = 0; ++ if (rem->port) ++ rem_in.sin_port = rem->port; ++ else ++ rem_in.sin_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin_addr = loc->addr; ++ rem_in.sin_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in)); ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket bind() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d ifidx: %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin_addr, ++ ntohs(loc_in.sin_port), &rem_in.sin_addr, ++ ntohs(rem_in.sin_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ mptcp_debug("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mptcp_init4_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v4_specific = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v4_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ip_setsockopt, ++ .getsockopt = ip_getsockopt, ++ .addr2sockaddr = inet_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in), ++ .bind_conflict = inet_csk_bind_conflict, ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ip_setsockopt, ++ .compat_getsockopt = compat_ip_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++/* General initialization of IPv4 for MPTCP */ ++int mptcp_pm_v4_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp_request_sock_ops; ++ ++ mptcp_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_request_sock_ipv4_ops.init_req = mptcp_v4_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv4_ops.cookie_init_seq = mptcp_v4_cookie_init_seq; ++#endif ++ mptcp_join_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_join_request_sock_ipv4_ops.init_req = mptcp_v4_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_DESTROY_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v4_undo(void) ++{ ++ kmem_cache_destroy(mptcp_request_sock_ops.slab); ++ kfree(mptcp_request_sock_ops.slab_name); ++} +diff -aurN linux-4.9.162/net/mptcp/mptcp_ipv6.c mptcp-mptcp_v0.93/net/mptcp/mptcp_ipv6.c +--- linux-4.9.162/net/mptcp/mptcp_ipv6.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_ipv6.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,462 @@ ++/* ++ * MPTCP implementation - IPv6-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport) ++{ ++ u32 secret[MD5_MESSAGE_BYTES / 4]; ++ u32 hash[MD5_DIGEST_WORDS]; ++ u32 i; ++ ++ memcpy(hash, saddr, 16); ++ for (i = 0; i < 4; i++) ++ secret[i] = mptcp_secret[i] + (__force u32)daddr[i]; ++ secret[4] = mptcp_secret[4] + ++ (((__force u16)sport << 16) + (__force u16)dport); ++ secret[5] = mptcp_seed++; ++ for (i = 6; i < MD5_MESSAGE_BYTES / 4; i++) ++ secret[i] = mptcp_secret[i]; ++ ++ md5_transform(hash, secret); ++ ++ return hash[0]; ++} ++ ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed) ++{ ++ u32 secret[MD5_MESSAGE_BYTES / 4]; ++ u32 hash[MD5_DIGEST_WORDS]; ++ u32 i; ++ ++ memcpy(hash, saddr, 16); ++ for (i = 0; i < 4; i++) ++ secret[i] = mptcp_secret[i] + (__force u32)daddr[i]; ++ secret[4] = mptcp_secret[4] + ++ (((__force u16)sport << 16) + (__force u16)dport); ++ secret[5] = seed; ++ for (i = 6; i < MD5_MESSAGE_BYTES / 4; i++) ++ secret[i] = mptcp_secret[i]; ++ ++ md5_transform(hash, secret); ++ ++ return *((u64 *)hash); ++} ++ ++static void mptcp_v6_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v6_reqsk_destructor(req); ++} ++ ++static int mptcp_v6_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v6_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v6_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++static int mptcp_v6_join_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v6_get_nonce(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.in6 = inet_rsk(req)->ir_v6_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(AF_INET6, &addr, sock_net(sk), &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp6_request_sock_ops */ ++struct request_sock_ops mptcp6_request_sock_ops __read_mostly = { ++ .family = AF_INET6, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v6_reqsk_send_ack, ++ .destructor = mptcp_v6_reqsk_destructor, ++ .send_reset = tcp_v6_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++static int mptcp_v6_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_join_request_sock_ipv6_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = __inet6_lookup_established(sock_net(meta_sk), ++ &tcp_hashinfo, ++ &ip6h->saddr, th->source, ++ &ip6h->daddr, ntohs(th->dest), ++ tcp_v6_iif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v6_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v6_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v6_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v6_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv6 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in6 loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet6_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ mptcp_debug("%s inet6_create failed ret: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ if (mptcp_add_sock(meta_sk, sk, loc->loc6_id, rem->rem6_id, GFP_KERNEL)) ++ goto error; ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ setup_timer(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, (unsigned long)sk); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin6_family = AF_INET6; ++ rem_in.sin6_family = AF_INET6; ++ loc_in.sin6_port = 0; ++ if (rem->port) ++ rem_in.sin6_port = rem->port; ++ else ++ rem_in.sin6_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin6_addr = loc->addr; ++ rem_in.sin6_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in6)); ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket bind()failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI6:%d dst_addr:%pI6:%d ifidx: %u\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin6_addr, ++ ntohs(loc_in.sin6_port), &rem_in.sin6_addr, ++ ntohs(rem_in.sin6_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in6), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ mptcp_debug("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mptcp_init6_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v6_specific = { ++ .queue_xmit = inet6_csk_xmit, ++ .send_check = tcp_v6_send_check, ++ .rebuild_header = inet6_sk_rebuild_header, ++ .sk_rx_dst_set = inet6_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct ipv6hdr), ++ .net_frag_header_len = sizeof(struct frag_hdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++ .bind_conflict = inet6_csk_bind_conflict, ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v6_mtu_reduced, ++}; ++ ++const struct inet_connection_sock_af_ops mptcp_v6_mapped = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++ .bind_conflict = inet6_csk_bind_conflict, ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_pm_v6_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp6_request_sock_ops; ++ ++ mptcp_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_request_sock_ipv6_ops.init_req = mptcp_v6_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv6_ops.cookie_init_seq = mptcp_v6_cookie_init_seq; ++#endif ++ ++ mptcp_join_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_join_request_sock_ipv6_ops.init_req = mptcp_v6_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP6"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_DESTROY_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v6_undo(void) ++{ ++ kmem_cache_destroy(mptcp6_request_sock_ops.slab); ++ kfree(mptcp6_request_sock_ops.slab_name); ++} +diff -aurN linux-4.9.162/net/mptcp/mptcp_ndiffports.c mptcp-mptcp_v0.93/net/mptcp/mptcp_ndiffports.c +--- linux-4.9.162/net/mptcp/mptcp_ndiffports.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_ndiffports.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,169 @@ ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct ndiffports_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++}; ++ ++static int num_subflows __read_mostly = 2; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per MPTCP connection"); ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct ndiffports_priv *pm_priv = container_of(work, ++ struct ndiffports_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (num_subflows > iter && num_subflows > mpcb->cnt_subflows) { ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ } else { ++#if IS_ENABLED(CONFIG_IPV6) ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_init6_subsockets(meta_sk, &loc, &rem); ++#endif ++ } ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++} ++ ++static void ndiffports_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *fmp = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++} ++ ++static void ndiffports_create_subflows(struct sock *meta_sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *pm_priv = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mpcb->infinite_mapping_snd || mpcb->infinite_mapping_rcv || ++ mpcb->send_infinite_mapping || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int ndiffports_get_local_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++static struct mptcp_pm_ops ndiffports __read_mostly = { ++ .new_session = ndiffports_new_session, ++ .fully_established = ndiffports_create_subflows, ++ .get_local_id = ndiffports_get_local_id, ++ .name = "ndiffports", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init ndiffports_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ndiffports_priv) > MPTCP_PM_SIZE); ++ ++ if (mptcp_register_path_manager(&ndiffports)) ++ goto exit; ++ ++ return 0; ++ ++exit: ++ return -1; ++} ++ ++static void ndiffports_unregister(void) ++{ ++ mptcp_unregister_path_manager(&ndiffports); ++} ++ ++module_init(ndiffports_register); ++module_exit(ndiffports_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("NDIFF-PORTS MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_olia.c mptcp-mptcp_v0.93/net/mptcp/mptcp_olia.c +--- linux-4.9.162/net/mptcp/mptcp_olia.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_olia.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,309 @@ ++/* ++ * MPTCP implementation - OPPORTUNISTIC LINKED INCREASES CONGESTION CONTROL: ++ * ++ * Algorithm design: ++ * Ramin Khalili ++ * Nicolas Gast ++ * Jean-Yves Le Boudec ++ * ++ * Implementation: ++ * Ramin Khalili ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++#include ++ ++static int scale = 10; ++ ++struct mptcp_olia { ++ u32 mptcp_loss1; ++ u32 mptcp_loss2; ++ u32 mptcp_loss3; ++ int epsilon_num; ++ u32 epsilon_den; ++ int mptcp_snd_cwnd_cnt; ++}; ++ ++static inline int mptcp_olia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_olia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++/* take care of artificially inflate (see RFC5681) ++ * of cwnd during fast-retransmit phase ++ */ ++static u32 mptcp_get_crt_cwnd(struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (icsk->icsk_ca_state == TCP_CA_Recovery) ++ return tcp_sk(sk)->snd_ssthresh; ++ else ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* return the dominator of the first term of the increasing term */ ++static u64 mptcp_get_rate(const struct mptcp_cb *mpcb , u32 path_rtt) ++{ ++ struct sock *sk; ++ u64 rate = 1; /* We have to avoid a zero-rate because it is used as a divisor */ ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ u64 scaled_num; ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ scaled_num = mptcp_olia_scale(tmp_cwnd, scale) * path_rtt; ++ rate += div_u64(scaled_num , tp->srtt_us); ++ } ++ rate *= rate; ++ return rate; ++} ++ ++/* find the maximum cwnd, used to find set M */ ++static u32 mptcp_get_max_cwnd(const struct mptcp_cb *mpcb) ++{ ++ struct sock *sk; ++ u32 best_cwnd = 0; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd > best_cwnd) ++ best_cwnd = tmp_cwnd; ++ } ++ return best_cwnd; ++} ++ ++static void mptcp_get_epsilon(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_olia *ca; ++ struct tcp_sock *tp; ++ struct sock *sk; ++ u64 tmp_int, tmp_rtt, best_int = 0, best_rtt = 1; ++ u32 max_cwnd, tmp_cwnd; ++ u8 M = 0, B_not_M = 0; ++ ++ /* TODO - integrate this in the following loop - we just want to iterate once */ ++ ++ max_cwnd = mptcp_get_max_cwnd(mpcb); ++ ++ /* find the best path */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ /* TODO - check here and rename variables */ ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt >= (u64)best_int * tmp_rtt) { ++ best_rtt = tmp_rtt; ++ best_int = tmp_int; ++ } ++ } ++ ++ /* TODO - integrate this here in mptcp_get_max_cwnd and in the previous loop */ ++ /* find the size of M and B_not_M */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd == max_cwnd) { ++ M++; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) ++ B_not_M++; ++ } ++ } ++ ++ /* check if the path is in M or B_not_M and set the value of epsilon accordingly */ ++ mptcp_for_each_sk(mpcb, sk) { ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ if (B_not_M == 0) { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ ++ if (tmp_cwnd < max_cwnd && ++ (u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) { ++ ca->epsilon_num = 1; ++ ca->epsilon_den = mpcb->cnt_established * B_not_M; ++ } else if (tmp_cwnd == max_cwnd) { ++ ca->epsilon_num = -1; ++ ca->epsilon_den = mpcb->cnt_established * M; ++ } else { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++ } ++ } ++} ++ ++/* setting the initial values */ ++static void mptcp_olia_init(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (mptcp(tp)) { ++ ca->mptcp_loss1 = tp->snd_una; ++ ca->mptcp_loss2 = tp->snd_una; ++ ca->mptcp_loss3 = tp->snd_una; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++} ++ ++/* updating inter-loss distance and ssthresh */ ++static void mptcp_olia_set_state(struct sock *sk, u8 new_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ if (new_state == TCP_CA_Loss || ++ new_state == TCP_CA_Recovery || new_state == TCP_CA_CWR) { ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (ca->mptcp_loss3 != ca->mptcp_loss2 && ++ !inet_csk(sk)->icsk_retransmits) { ++ ca->mptcp_loss1 = ca->mptcp_loss2; ++ ca->mptcp_loss2 = ca->mptcp_loss3; ++ } ++ } ++} ++ ++/* main algorithm */ ++static void mptcp_olia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ u64 inc_num, inc_den, rate, cwnd_scaled; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ ca->mptcp_loss3 = tp->snd_una; ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ /* slow start if it is in the safe area */ ++ if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ return; ++ } ++ ++ mptcp_get_epsilon(mpcb); ++ rate = mptcp_get_rate(mpcb, tp->srtt_us); ++ cwnd_scaled = mptcp_olia_scale(tp->snd_cwnd, scale); ++ inc_den = ca->epsilon_den * tp->snd_cwnd * rate ? : 1; ++ ++ /* calculate the increasing term, scaling is used to reduce the rounding effect */ ++ if (ca->epsilon_num == -1) { ++ if (ca->epsilon_den * cwnd_scaled * cwnd_scaled < rate) { ++ inc_num = rate - ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt -= div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } else { ++ inc_num = ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled - rate; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ } else { ++ inc_num = ca->epsilon_num * rate + ++ ca->epsilon_den * cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ ++ ++ if (ca->mptcp_snd_cwnd_cnt >= (1 << scale) - 1) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) ++ tp->snd_cwnd++; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } else if (ca->mptcp_snd_cwnd_cnt <= 0 - (1 << scale) + 1) { ++ tp->snd_cwnd = max((int) 1 , (int) tp->snd_cwnd - 1); ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_olia = { ++ .init = mptcp_olia_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_olia_cong_avoid, ++ .set_state = mptcp_olia_set_state, ++ .owner = THIS_MODULE, ++ .name = "olia", ++}; ++ ++static int __init mptcp_olia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_olia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_olia); ++} ++ ++static void __exit mptcp_olia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_olia); ++} ++ ++module_init(mptcp_olia_register); ++module_exit(mptcp_olia_unregister); ++ ++MODULE_AUTHOR("Ramin Khalili, Nicolas Gast, Jean-Yves Le Boudec"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP COUPLED CONGESTION CONTROL"); ++MODULE_VERSION("0.1"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_output.c mptcp-mptcp_v0.93/net/mptcp/mptcp_output.c +--- linux-4.9.162/net/mptcp/mptcp_output.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_output.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,1818 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static const int mptcp_dss_len = MPTCP_SUB_LEN_DSS_ALIGN + ++ MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ ++static inline int mptcp_sub_len_remove_addr(u16 bitfield) ++{ ++ unsigned int c; ++ for (c = 0; bitfield; c++) ++ bitfield &= bitfield - 1; ++ return MPTCP_SUB_LEN_REMOVE_ADDR + c - 1; ++} ++ ++int mptcp_sub_len_remove_addr_align(u16 bitfield) ++{ ++ return ALIGN(mptcp_sub_len_remove_addr(bitfield), 4); ++} ++EXPORT_SYMBOL(mptcp_sub_len_remove_addr_align); ++ ++/* get the data-seq and end-data-seq and store them again in the ++ * tcp_skb_cb ++ */ ++static bool mptcp_reconstruct_mapping(struct sk_buff *skb) ++{ ++ const struct mp_dss *mpdss = (struct mp_dss *)TCP_SKB_CB(skb)->dss; ++ u32 *p32; ++ u16 *p16; ++ ++ if (!mptcp_is_data_seq(skb)) ++ return false; ++ ++ if (!mpdss->M) ++ return false; ++ ++ /* Move the pointer to the data-seq */ ++ p32 = (u32 *)mpdss; ++ p32++; ++ if (mpdss->A) { ++ p32++; ++ if (mpdss->a) ++ p32++; ++ } ++ ++ TCP_SKB_CB(skb)->seq = ntohl(*p32); ++ ++ /* Get the data_len to calculate the end_data_seq */ ++ p32++; ++ p32++; ++ p16 = (u16 *)p32; ++ TCP_SKB_CB(skb)->end_seq = ntohs(*p16) + TCP_SKB_CB(skb)->seq; ++ ++ return true; ++} ++ ++static bool mptcp_is_reinjected(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCP_REINJECT; ++} ++ ++static void mptcp_find_and_set_pathmask(const struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct sk_buff *skb_it; ++ ++ skb_it = tcp_write_queue_head(meta_sk); ++ ++ tcp_for_write_queue_from(skb_it, meta_sk) { ++ if (skb_it == tcp_send_head(meta_sk)) ++ break; ++ ++ if (TCP_SKB_CB(skb_it)->seq == TCP_SKB_CB(skb)->seq) { ++ TCP_SKB_CB(skb)->path_mask = TCP_SKB_CB(skb_it)->path_mask; ++ break; ++ } ++ } ++} ++ ++/* Reinject data from one TCP subflow to the meta_sk. If sk == NULL, we are ++ * coming from the meta-retransmit-timer ++ */ ++static void __mptcp_reinject_data(struct sk_buff *orig_skb, struct sock *meta_sk, ++ struct sock *sk, int clone_it) ++{ ++ struct sk_buff *skb, *skb1; ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u32 seq, end_seq; ++ ++ if (clone_it) { ++ /* pskb_copy is necessary here, because the TCP/IP-headers ++ * will be changed when it's going to be reinjected on another ++ * subflow. ++ */ ++ skb = pskb_copy_for_clone(orig_skb, GFP_ATOMIC); ++ } else { ++ __skb_unlink(orig_skb, &sk->sk_write_queue); ++ sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ sk->sk_wmem_queued -= orig_skb->truesize; ++ sk_mem_uncharge(sk, orig_skb->truesize); ++ skb = orig_skb; ++ } ++ if (unlikely(!skb)) ++ return; ++ ++ if (sk && !mptcp_reconstruct_mapping(skb)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ skb->sk = meta_sk; ++ ++ /* Reset subflow-specific TCP control-data */ ++ TCP_SKB_CB(skb)->sacked = 0; ++ TCP_SKB_CB(skb)->tcp_flags &= (TCPHDR_ACK | TCPHDR_PSH); ++ ++ /* If it reached already the destination, we don't have to reinject it */ ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ /* Only reinject segments that are fully covered by the mapping */ ++ if (skb->len + (mptcp_is_data_fin(skb) ? 1 : 0) != ++ TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) { ++ u32 seq = TCP_SKB_CB(skb)->seq; ++ u32 end_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ __kfree_skb(skb); ++ ++ /* Ok, now we have to look for the full mapping in the meta ++ * send-queue :S ++ */ ++ tcp_for_write_queue(skb, meta_sk) { ++ /* Not yet at the mapping? */ ++ if (before(TCP_SKB_CB(skb)->seq, seq)) ++ continue; ++ /* We have passed by the mapping */ ++ if (after(TCP_SKB_CB(skb)->end_seq, end_seq)) ++ return; ++ ++ __mptcp_reinject_data(skb, meta_sk, NULL, 1); ++ } ++ return; ++ } ++ ++ /* Segment goes back to the MPTCP-layer. So, we need to zero the ++ * path_mask/dss. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ /* We need to find out the path-mask from the meta-write-queue ++ * to properly select a subflow. ++ */ ++ mptcp_find_and_set_pathmask(meta_sk, skb); ++ ++ /* If it's empty, just add */ ++ if (skb_queue_empty(&mpcb->reinject_queue)) { ++ skb_queue_head(&mpcb->reinject_queue, skb); ++ return; ++ } ++ ++ /* Find place to insert skb - or even we can 'drop' it, as the ++ * data is already covered by other skb's in the reinject-queue. ++ * ++ * This is inspired by code from tcp_data_queue. ++ */ ++ ++ skb1 = skb_peek_tail(&mpcb->reinject_queue); ++ seq = TCP_SKB_CB(skb)->seq; ++ while (1) { ++ if (!after(TCP_SKB_CB(skb1)->seq, seq)) ++ break; ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) { ++ skb1 = NULL; ++ break; ++ } ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ ++ /* Do skb overlap to previous one? */ ++ end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ /* All the bits are present. Don't reinject */ ++ __kfree_skb(skb); ++ return; ++ } ++ if (seq == TCP_SKB_CB(skb1)->seq) { ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) ++ skb1 = NULL; ++ else ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ } ++ if (!skb1) ++ __skb_queue_head(&mpcb->reinject_queue, skb); ++ else ++ __skb_queue_after(&mpcb->reinject_queue, skb1, skb); ++ ++ /* And clean segments covered by new one as whole. */ ++ while (!skb_queue_is_last(&mpcb->reinject_queue, skb)) { ++ skb1 = skb_queue_next(&mpcb->reinject_queue, skb); ++ ++ if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) ++ break; ++ ++ if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) ++ break; ++ ++ __skb_unlink(skb1, &mpcb->reinject_queue); ++ __kfree_skb(skb1); ++ } ++ return; ++} ++ ++/* Inserts data into the reinject queue */ ++void mptcp_reinject_data(struct sock *sk, int clone_it) ++{ ++ struct sk_buff *skb_it, *tmp; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = tp->meta_sk; ++ ++ /* It has already been closed - there is really no point in reinjecting */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ skb_queue_walk_safe(&sk->sk_write_queue, skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it); ++ } ++ ++ skb_it = tcp_write_queue_tail(meta_sk); ++ /* If sk has sent the empty data-fin, we have to reinject it too. */ ++ if (skb_it && mptcp_is_data_fin(skb_it) && skb_it->len == 0 && ++ TCP_SKB_CB(skb_it)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index)) { ++ __mptcp_reinject_data(skb_it, meta_sk, NULL, 1); ++ } ++ ++ tp->pf = 1; ++ ++ mptcp_push_pending_frames(meta_sk); ++} ++EXPORT_SYMBOL(mptcp_reinject_data); ++ ++static void mptcp_combine_dfin(const struct sk_buff *skb, ++ const struct sock *meta_sk, ++ struct sock *subsk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* In infinite mapping we always try to combine */ ++ if (mpcb->infinite_mapping_snd) ++ goto combine; ++ ++ /* Don't combine, if they didn't combine when closing - otherwise we end ++ * up in TIME_WAIT, even if our app is smart enough to avoid it. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !mpcb->dfin_combined) ++ return; ++ ++ /* Don't combine if there is still outstanding data that remains to be ++ * DATA_ACKed, because otherwise we may never be able to deliver this. ++ */ ++ if (meta_tp->snd_una != TCP_SKB_CB(skb)->seq) ++ return; ++ ++combine: ++ if (tcp_close_state(subsk)) { ++ subsk->sk_shutdown |= SEND_SHUTDOWN; ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } ++} ++ ++static int mptcp_write_dss_mapping(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ const struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *start = ptr; ++ __u16 data_len; ++ ++ *ptr++ = htonl(tcb->seq); /* data_seq */ ++ ++ /* If it's a non-data DATA_FIN, we set subseq to 0 (draft v7) */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ *ptr++ = 0; /* subseq */ ++ else ++ *ptr++ = htonl(tp->write_seq - tp->mptcp->snt_isn); /* subseq */ ++ ++ if (tcb->mptcp_flags & MPTCPHDR_INF) ++ data_len = 0; ++ else ++ data_len = tcb->end_seq - tcb->seq; ++ ++ if (tp->mpcb->dss_csum && data_len) { ++ __be16 *p16 = (__be16 *)ptr; ++ __be32 hdseq = mptcp_get_highorder_sndbits(skb, tp->mpcb); ++ __wsum csum; ++ ++ *ptr = htonl(((data_len) << 16) | ++ (TCPOPT_EOL << 8) | ++ (TCPOPT_EOL)); ++ csum = csum_partial(ptr - 2, 12, skb->csum); ++ p16++; ++ *p16++ = csum_fold(csum_partial(&hdseq, sizeof(hdseq), csum)); ++ } else { ++ *ptr++ = htonl(((data_len) << 16) | ++ (TCPOPT_NOP << 8) | ++ (TCPOPT_NOP)); ++ } ++ ++ return ptr - start; ++} ++ ++static int mptcp_write_dss_data_ack(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ struct mp_dss *mdss = (struct mp_dss *)ptr; ++ __be32 *start = ptr; ++ ++ mdss->kind = TCPOPT_MPTCP; ++ mdss->sub = MPTCP_SUB_DSS; ++ mdss->rsv1 = 0; ++ mdss->rsv2 = 0; ++ mdss->F = mptcp_is_data_fin(skb) ? 1 : 0; ++ mdss->m = 0; ++ mdss->M = mptcp_is_data_seq(skb) ? 1 : 0; ++ mdss->a = 0; ++ mdss->A = 1; ++ mdss->len = mptcp_sub_len_dss(mdss, tp->mpcb->dss_csum); ++ ptr++; ++ ++ *ptr++ = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ return ptr - start; ++} ++ ++/* RFC6824 states that once a particular subflow mapping has been sent ++ * out it must never be changed. However, packets may be split while ++ * they are in the retransmission queue (due to SACK or ACKs) and that ++ * arguably means that we would change the mapping (e.g. it splits it, ++ * our sends out a subset of the initial mapping). ++ * ++ * Furthermore, the skb checksum is not always preserved across splits ++ * (e.g. mptcp_fragment) which would mean that we need to recompute ++ * the DSS checksum in this case. ++ * ++ * To avoid this we save the initial DSS mapping which allows us to ++ * send the same DSS mapping even for fragmented retransmits. ++ */ ++static void mptcp_save_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb) ++{ ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *ptr = (__be32 *)tcb->dss; ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ ptr += mptcp_write_dss_mapping(tp, skb, ptr); ++} ++ ++/* Write the saved DSS mapping to the header */ ++static int mptcp_write_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ __be32 *start = ptr; ++ ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, mptcp_dss_len); ++ ++ /* update the data_ack */ ++ start[1] = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ /* dss is in a union with inet_skb_parm and ++ * the IP layer expects zeroed IPCB fields. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ return mptcp_dss_len/sizeof(*ptr); ++} ++ ++static bool mptcp_skb_entail(struct sock *sk, struct sk_buff *skb, int reinject) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb; ++ struct sk_buff *subskb = NULL; ++ ++ if (!reinject) ++ TCP_SKB_CB(skb)->mptcp_flags |= (mpcb->snd_hiseq_index ? ++ MPTCPHDR_SEQ64_INDEX : 0); ++ ++ subskb = pskb_copy_for_clone(skb, GFP_ATOMIC); ++ if (!subskb) ++ return false; ++ ++ /* At the subflow-level we need to call again tcp_init_tso_segs. We ++ * force this, by setting pcount to 0. It has been set to 1 prior to ++ * the call to mptcp_skb_entail. ++ */ ++ tcp_skb_pcount_set(subskb, 0); ++ ++ TCP_SKB_CB(skb)->path_mask |= mptcp_pi_to_flag(tp->mptcp->path_index); ++ ++ /* Compute checksum, if: ++ * 1. The current route does not support csum offloading but it was ++ * assumed that it does (ip_summed is CHECKSUM_PARTIAL) ++ * 2. We need the DSS-checksum but ended up not pre-computing it ++ * (e.g., in the case of TFO retransmissions). ++ */ ++ if (skb->ip_summed == CHECKSUM_PARTIAL && ++ (!sk_check_csum_caps(sk) || tp->mpcb->dss_csum)) { ++ subskb->csum = skb->csum = skb_checksum(skb, 0, skb->len, 0); ++ subskb->ip_summed = skb->ip_summed = CHECKSUM_NONE; ++ } ++ ++ tcb = TCP_SKB_CB(subskb); ++ ++ if (tp->mpcb->send_infinite_mapping && ++ !tp->mpcb->infinite_mapping_snd && ++ !before(tcb->seq, mptcp_meta_tp(tp)->snd_nxt)) { ++ tp->mptcp->fully_established = 1; ++ tp->mpcb->infinite_mapping_snd = 1; ++ tp->mptcp->infinite_cutoff_seq = tp->write_seq; ++ tcb->mptcp_flags |= MPTCPHDR_INF; ++ } ++ ++ if (mptcp_is_data_fin(subskb)) ++ mptcp_combine_dfin(subskb, meta_sk, sk); ++ ++ mptcp_save_dss_data_seq(tp, subskb); ++ ++ tcb->seq = tp->write_seq; ++ ++ /* Take into account seg len */ ++ tp->write_seq += subskb->len + ((tcb->tcp_flags & TCPHDR_FIN) ? 1 : 0); ++ tcb->end_seq = tp->write_seq; ++ ++ /* If it's a non-payload DATA_FIN (also no subflow-fin), the ++ * segment is not part of the subflow but on a meta-only-level. ++ */ ++ if (!mptcp_is_data_fin(subskb) || tcb->end_seq != tcb->seq) { ++ tcp_add_write_queue_tail(sk, subskb); ++ sk->sk_wmem_queued += subskb->truesize; ++ sk_mem_charge(sk, subskb->truesize); ++ } else { ++ int err; ++ ++ /* Necessary to initialize for tcp_transmit_skb. mss of 1, as ++ * skb->len = 0 will force tso_segs to 1. ++ */ ++ tcp_init_tso_segs(subskb, 1); ++ /* Empty data-fins are sent immediatly on the subflow */ ++ err = tcp_transmit_skb(sk, subskb, 1, GFP_ATOMIC); ++ ++ /* It has not been queued, we can free it now. */ ++ kfree_skb(subskb); ++ ++ if (err) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->second_packet = 1; ++ tp->mptcp->last_end_data_seq = TCP_SKB_CB(skb)->end_seq; ++ } ++ ++ return true; ++} ++ ++/* Fragment an skb and update the mptcp meta-data. Due to reinject, we ++ * might need to undo some operations done by tcp_fragment. ++ */ ++static int mptcp_fragment(struct sock *meta_sk, struct sk_buff *skb, u32 len, ++ gfp_t gfp, int reinject) ++{ ++ int ret, diff, old_factor; ++ struct sk_buff *buff; ++ u8 flags; ++ ++ if (skb_headlen(skb) < len) ++ diff = skb->len - len; ++ else ++ diff = skb->data_len; ++ old_factor = tcp_skb_pcount(skb); ++ ++ /* The mss_now in tcp_fragment is used to set the tso_segs of the skb. ++ * At the MPTCP-level we do not care about the absolute value. All we ++ * care about is that it is set to 1 for accurate packets_out ++ * accounting. ++ */ ++ ret = tcp_fragment(meta_sk, skb, len, UINT_MAX, gfp); ++ if (ret) ++ return ret; ++ ++ buff = skb->next; ++ ++ flags = TCP_SKB_CB(skb)->mptcp_flags; ++ TCP_SKB_CB(skb)->mptcp_flags = flags & ~(MPTCPHDR_FIN); ++ TCP_SKB_CB(buff)->mptcp_flags = flags; ++ TCP_SKB_CB(buff)->path_mask = TCP_SKB_CB(skb)->path_mask; ++ ++ /* If reinject == 1, the buff will be added to the reinject ++ * queue, which is currently not part of memory accounting. So ++ * undo the changes done by tcp_fragment and update the ++ * reinject queue. Also, undo changes to the packet counters. ++ */ ++ if (reinject == 1) { ++ int undo = buff->truesize - diff; ++ meta_sk->sk_wmem_queued -= undo; ++ sk_mem_uncharge(meta_sk, undo); ++ ++ tcp_sk(meta_sk)->mpcb->reinject_queue.qlen++; ++ meta_sk->sk_write_queue.qlen--; ++ ++ if (!before(tcp_sk(meta_sk)->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { ++ undo = old_factor - tcp_skb_pcount(skb) - ++ tcp_skb_pcount(buff); ++ if (undo) ++ tcp_adjust_pcount(meta_sk, skb, -undo); ++ } ++ } ++ ++ return 0; ++} ++ ++/* Inspired by tcp_write_wakeup */ ++int mptcp_write_wakeup(struct sock *meta_sk, int mib) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ struct sock *sk_it; ++ int ans = 0; ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return -1; ++ ++ skb = tcp_send_head(meta_sk); ++ if (skb && ++ before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(meta_tp))) { ++ unsigned int mss; ++ unsigned int seg_size = tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq; ++ struct sock *subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, true); ++ struct tcp_sock *subtp; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ if (!subsk) ++ goto window_probe; ++ subtp = tcp_sk(subsk); ++ mss = tcp_current_mss(subsk); ++ ++ seg_size = min(tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq, ++ tcp_wnd_end(subtp) - subtp->write_seq); ++ ++ if (before(meta_tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) ++ meta_tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ /* We are probing the opening of a window ++ * but the window size is != 0 ++ * must have been a result SWS avoidance ( sender ) ++ */ ++ if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || ++ skb->len > mss) { ++ seg_size = min(seg_size, mss); ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (mptcp_fragment(meta_sk, skb, seg_size, ++ GFP_ATOMIC, 0)) ++ return -1; ++ } else if (!tcp_skb_pcount(skb)) { ++ /* see mptcp_write_xmit on why we use UINT_MAX */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ } ++ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (!mptcp_skb_entail(subsk, skb, 0)) ++ return -1; ++ skb_mstamp_get(&skb->skb_mstamp); ++ ++ mptcp_check_sndseq_wrap(meta_tp, TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ ++ __tcp_push_pending_frames(subsk, mss, TCP_NAGLE_PUSH); ++ meta_tp->lsndtime = tcp_time_stamp; ++ ++ return 0; ++ } else { ++window_probe: ++ if (between(meta_tp->snd_up, meta_tp->snd_una + 1, ++ meta_tp->snd_una + 0xFFFF)) { ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ if (mptcp_sk_can_send_ack(sk_it)) ++ tcp_xmit_probe_skb(sk_it, 1, mib); ++ } ++ } ++ ++ /* At least one of the tcp_xmit_probe_skb's has to succeed */ ++ mptcp_for_each_sk(meta_tp->mpcb, sk_it) { ++ int ret; ++ ++ if (!mptcp_sk_can_send_ack(sk_it)) ++ continue; ++ ++ ret = tcp_xmit_probe_skb(sk_it, 0, mib); ++ if (unlikely(ret > 0)) ++ ans = ret; ++ } ++ return ans; ++ } ++} ++ ++bool mptcp_write_xmit(struct sock *meta_sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *subtp; ++ struct sock *subsk = NULL; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int reinject = 0; ++ unsigned int sublimit; ++ __u32 path_mask = 0; ++ ++ if (inet_csk(meta_sk)->icsk_retransmits) { ++ /* If the timer already once fired, retransmit the head of the ++ * queue to unblock us ASAP. ++ */ ++ if (meta_tp->packets_out && !mpcb->infinite_mapping_snd) ++ mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ } ++ ++ while ((skb = mpcb->sched_ops->next_segment(meta_sk, &reinject, &subsk, ++ &sublimit))) { ++ unsigned int limit; ++ ++ WARN(TCP_SKB_CB(skb)->sacked, "sacked: %u reinject: %u", ++ TCP_SKB_CB(skb)->sacked, reinject); ++ ++ subtp = tcp_sk(subsk); ++ mss_now = tcp_current_mss(subsk); ++ ++ if (reinject == 1) { ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ /* Segment already reached the peer, take the next one */ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ continue; ++ } ++ } ++ ++ /* If the segment was cloned (e.g. a meta retransmission), ++ * the header must be expanded/copied so that there is no ++ * corruption of TSO information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ break; ++ ++ if (unlikely(!tcp_snd_wnd_test(meta_tp, skb, mss_now))) ++ break; ++ ++ /* Force tso_segs to 1 by using UINT_MAX. ++ * We actually don't care about the exact number of segments ++ * emitted on the subflow. We need just to set tso_segs, because ++ * we still need an accurate packets_out count in ++ * tcp_event_new_data_sent. ++ */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ ++ /* Check for nagle, irregardless of tso_segs. If the segment is ++ * actually larger than mss_now (TSO segment), then ++ * tcp_nagle_check will have partial == false and always trigger ++ * the transmission. ++ * tcp_write_xmit has a TSO-level nagle check which is not ++ * subject to the MPTCP-level. It is based on the properties of ++ * the subflow, not the MPTCP-level. ++ */ ++ if (unlikely(!tcp_nagle_test(meta_tp, skb, mss_now, ++ (tcp_skb_is_last(meta_sk, skb) ? ++ nonagle : TCP_NAGLE_PUSH)))) ++ break; ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ /* We limit the size of the skb so that it fits into the ++ * window. Call tcp_mss_split_point to avoid duplicating ++ * code. ++ * We really only care about fitting the skb into the ++ * window. That's why we use UINT_MAX. If the skb does ++ * not fit into the cwnd_quota or the NIC's max-segs ++ * limitation, it will be split by the subflow's ++ * tcp_write_xmit which does the appropriate call to ++ * tcp_mss_split_point. ++ */ ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ nonagle); ++ ++ if (sublimit) ++ limit = min(limit, sublimit); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, skb, limit, gfp, reinject))) ++ break; ++ ++ if (!mptcp_skb_entail(subsk, skb, reinject)) ++ break; ++ /* Nagle is handled at the MPTCP-layer, so ++ * always push on the subflow ++ */ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ meta_tp->lsndtime = tcp_time_stamp; ++ ++ path_mask |= mptcp_pi_to_flag(subtp->mptcp->path_index); ++ skb_mstamp_get(&skb->skb_mstamp); ++ ++ if (!reinject) { ++ mptcp_check_sndseq_wrap(meta_tp, ++ TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ } ++ ++ tcp_minshall_update(meta_tp, mss_now, skb); ++ ++ if (reinject > 0) { ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ kfree_skb(skb); ++ } ++ ++ if (push_one) ++ break; ++ } ++ ++ mptcp_for_each_sk(mpcb, subsk) { ++ subtp = tcp_sk(subsk); ++ ++ if (!(path_mask & mptcp_pi_to_flag(subtp->mptcp->path_index))) ++ continue; ++ ++ /* We have pushed data on this subflow. We ignore the call to ++ * cwnd_validate in tcp_write_xmit as is_cwnd_limited will never ++ * be true (we never push more than what the cwnd can accept). ++ * We need to ensure that we call tcp_cwnd_validate with ++ * is_cwnd_limited set to true if we have filled the cwnd. ++ */ ++ tcp_cwnd_validate(subsk, tcp_packets_in_flight(subtp) >= ++ subtp->snd_cwnd); ++ } ++ ++ return !meta_tp->packets_out && tcp_send_head(meta_sk); ++} ++ ++void mptcp_write_space(struct sock *sk) ++{ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++} ++ ++u32 __mptcp_select_window(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ int mss, free_space, full_space, window; ++ ++ /* MSS for the peer's data. Previous versions used mss_clamp ++ * here. I don't know if the value based on our guesses ++ * of peer's MSS is better for the performance. It's more correct ++ * but may be worse for the performance because of rcv_mss ++ * fluctuations. --SAW 1998/11/1 ++ */ ++ mss = icsk->icsk_ack.rcv_mss; ++ free_space = tcp_space(meta_sk); ++ full_space = min_t(int, meta_tp->window_clamp, ++ tcp_full_space(meta_sk)); ++ ++ if (mss > full_space) ++ mss = full_space; ++ ++ if (free_space < (full_space >> 1)) { ++ /* If free_space is decreasing due to mostly meta-level ++ * out-of-order packets, don't turn off the quick-ack mode. ++ */ ++ if (meta_tp->rcv_nxt - meta_tp->copied_seq > ((full_space - free_space) >> 1)) ++ icsk->icsk_ack.quick = 0; ++ ++ if (tcp_memory_pressure) ++ /* TODO this has to be adapted when we support different ++ * MSS's among the subflows. ++ */ ++ meta_tp->rcv_ssthresh = min(meta_tp->rcv_ssthresh, ++ 4U * meta_tp->advmss); ++ ++ if (free_space < mss) ++ return 0; ++ } ++ ++ if (free_space > meta_tp->rcv_ssthresh) ++ free_space = meta_tp->rcv_ssthresh; ++ ++ /* Don't do rounding if we are using window scaling, since the ++ * scaled window will not line up with the MSS boundary anyway. ++ */ ++ window = meta_tp->rcv_wnd; ++ if (tp->rx_opt.rcv_wscale) { ++ window = free_space; ++ ++ /* Advertise enough space so that it won't get scaled away. ++ * Import case: prevent zero window announcement if ++ * 1< mss. ++ */ ++ if (((window >> tp->rx_opt.rcv_wscale) << tp-> ++ rx_opt.rcv_wscale) != window) ++ window = (((window >> tp->rx_opt.rcv_wscale) + 1) ++ << tp->rx_opt.rcv_wscale); ++ } else { ++ /* Get the largest window that is a nice multiple of mss. ++ * Window clamp already applied above. ++ * If our current window offering is within 1 mss of the ++ * free space we just keep it. This prevents the divide ++ * and multiply from happening most of the time. ++ * We also don't do any window rounding when the free space ++ * is too small. ++ */ ++ if (window <= free_space - mss || window > free_space) ++ window = (free_space / mss) * mss; ++ else if (mss == full_space && ++ free_space > window + (full_space >> 1)) ++ window = free_space; ++ } ++ ++ return window; ++} ++ ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ opts->options |= OPTION_MPTCP; ++ if (is_master_tp(tp)) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYN; ++ opts->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ opts->mp_capable.sender_key = tp->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum; ++ } else { ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYN; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYN_ALIGN; ++ opts->mp_join_syns.token = mpcb->mptcp_rem_token; ++ opts->mp_join_syns.low_prio = tp->mptcp->low_prio; ++ opts->addr_id = tp->mptcp->loc_id; ++ opts->mp_join_syns.sender_nonce = tp->mptcp->mptcp_loc_nonce; ++ } ++} ++ ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, unsigned *remaining) ++{ ++ struct mptcp_request_sock *mtreq; ++ mtreq = mptcp_rsk(req); ++ ++ opts->options |= OPTION_MPTCP; ++ /* MPCB not yet set - thus it's a new MPTCP-session */ ++ if (!mtreq->is_sub) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYNACK; ++ opts->mptcp_ver = mtreq->mptcp_ver; ++ opts->mp_capable.sender_key = mtreq->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum || mtreq->dss_csum; ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ } else { ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYNACK; ++ opts->mp_join_syns.sender_truncated_mac = ++ mtreq->mptcp_hash_tmac; ++ opts->mp_join_syns.sender_nonce = mtreq->mptcp_loc_nonce; ++ opts->mp_join_syns.low_prio = mtreq->low_prio; ++ opts->addr_id = mtreq->loc_id; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN; ++ } ++} ++ ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ const struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL; ++ ++ /* We are coming from tcp_current_mss with the meta_sk as an argument. ++ * It does not make sense to check for the options, because when the ++ * segment gets sent, another subflow will be chosen. ++ */ ++ if (!skb && is_meta_sk(sk)) ++ return; ++ ++ if (unlikely(tp->send_mp_fclose)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FCLOSE; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ *size += MPTCP_SUB_LEN_FCLOSE_ALIGN; ++ return; ++ } ++ ++ /* 1. If we are the sender of the infinite-mapping, we need the ++ * MPTCPHDR_INF-flag, because a retransmission of the ++ * infinite-announcment still needs the mptcp-option. ++ * ++ * We need infinite_cutoff_seq, because retransmissions from before ++ * the infinite-cutoff-moment still need the MPTCP-signalling to stay ++ * consistent. ++ * ++ * 2. If we are the receiver of the infinite-mapping, we always skip ++ * mptcp-options, because acknowledgments from before the ++ * infinite-mapping point have already been sent out. ++ * ++ * I know, the whole infinite-mapping stuff is ugly... ++ * ++ * TODO: Handle wrapped data-sequence numbers ++ * (even if it's very unlikely) ++ */ ++ if (unlikely(mpcb->infinite_mapping_snd) && ++ ((mpcb->send_infinite_mapping && tcb && ++ mptcp_is_data_seq(skb) && ++ !(tcb->mptcp_flags & MPTCPHDR_INF) && ++ !before(tcb->seq, tp->mptcp->infinite_cutoff_seq)) || ++ !mpcb->send_infinite_mapping)) ++ return; ++ ++ if (unlikely(tp->mptcp->include_mpc)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_CAPABLE | ++ OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN; ++ opts->mptcp_ver = mpcb->mptcp_ver; ++ opts->mp_capable.sender_key = mpcb->mptcp_loc_key; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ opts->dss_csum = mpcb->dss_csum; ++ ++ if (skb) ++ tp->mptcp->include_mpc = 0; ++ } ++ if (unlikely(tp->mptcp->pre_established) && ++ (!skb || !(tcb->tcp_flags & (TCPHDR_FIN | TCPHDR_RST)))) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_JOIN_ACK_ALIGN; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (opts->add_addr_v6) ++ /* Skip subsequent options */ ++ return; ++ } ++ ++ if (!tp->mptcp->include_mpc && !tp->mptcp->pre_established) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_DATA_ACK; ++ /* If !skb, we come from tcp_current_mss and thus we always ++ * assume that the DSS-option will be set for the data-packet. ++ */ ++ if (skb && !mptcp_is_data_seq(skb)) { ++ *size += MPTCP_SUB_LEN_ACK_ALIGN; ++ } else { ++ /* Doesn't matter, if csum included or not. It will be ++ * either 10 or 12, and thus aligned = 12 ++ */ ++ *size += MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ } ++ ++ *size += MPTCP_SUB_LEN_DSS_ALIGN; ++ } ++ ++ /* In fallback mp_fail-mode, we have to repeat it until the fallback ++ * has been done by the sender ++ */ ++ if (unlikely(tp->mptcp->send_mp_fail) && skb && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_FAIL) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FAIL; ++ *size += MPTCP_SUB_LEN_FAIL; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver < MPTCP_VERSION_1) ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (unlikely(tp->mptcp->send_mp_prio) && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_PRIO_ALIGN) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_PRIO; ++ if (skb) ++ tp->mptcp->send_mp_prio = 0; ++ *size += MPTCP_SUB_LEN_PRIO_ALIGN; ++ } ++ ++ return; ++} ++ ++u16 mptcp_select_window(struct sock *sk) ++{ ++ u16 new_win = tcp_select_window(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *meta_tp = mptcp_meta_tp(tp); ++ ++ meta_tp->rcv_wnd = tp->rcv_wnd; ++ meta_tp->rcv_wup = meta_tp->rcv_nxt; ++ ++ return new_win; ++} ++ ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ if (unlikely(OPTION_MP_CAPABLE & opts->mptcp_options)) { ++ struct mp_capable *mpc = (struct mp_capable *)ptr; ++ ++ mpc->kind = TCPOPT_MPTCP; ++ ++ if ((OPTION_TYPE_SYN & opts->mptcp_options) || ++ (OPTION_TYPE_SYNACK & opts->mptcp_options)) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_SYN; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->receiver_key = opts->mp_capable.receiver_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_ACK; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN >> 2; ++ } ++ ++ mpc->sub = MPTCP_SUB_CAPABLE; ++ mpc->a = opts->dss_csum; ++ mpc->b = 0; ++ mpc->rsv = 0; ++ mpc->h = 1; ++ } ++ if (unlikely(OPTION_MP_JOIN & opts->mptcp_options)) { ++ struct mp_join *mpj = (struct mp_join *)ptr; ++ ++ mpj->kind = TCPOPT_MPTCP; ++ mpj->sub = MPTCP_SUB_JOIN; ++ mpj->rsv = 0; ++ ++ if (OPTION_TYPE_SYN & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYN; ++ mpj->u.syn.token = opts->mp_join_syns.token; ++ mpj->u.syn.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_SYNACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYNACK; ++ mpj->u.synack.mac = ++ opts->mp_join_syns.sender_truncated_mac; ++ mpj->u.synack.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_ACK; ++ mpj->addr_id = 0; /* addr_id is rsv (RFC 6824, p. 21) */ ++ memcpy(mpj->u.ack.mac, &tp->mptcp->sender_mac[0], 20); ++ ptr += MPTCP_SUB_LEN_JOIN_ACK_ALIGN >> 2; ++ } ++ } ++ if (unlikely(OPTION_ADD_ADDR & opts->mptcp_options)) { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mpadd->kind = TCPOPT_MPTCP; ++ if (opts->add_addr_v4) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 4; ++ mpadd->addr_id = opts->add_addr4.addr_id; ++ mpadd->u.v4.addr = opts->add_addr4.addr; ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v4.mac - 2, ++ (char *)&opts->add_addr4.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 >> 2; ++ } ++ } else if (opts->add_addr_v6) { ++ mpadd->sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->ipver = 6; ++ mpadd->addr_id = opts->add_addr6.addr_id; ++ memcpy(&mpadd->u.v6.addr, &opts->add_addr6.addr, ++ sizeof(mpadd->u.v6.addr)); ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN >> 2; ++ } else { ++ memcpy((char *)mpadd->u.v6.mac - 2, ++ (char *)&opts->add_addr6.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 >> 2; ++ } ++ } ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_ADDADDRTX); ++ } ++ if (unlikely(OPTION_REMOVE_ADDR & opts->mptcp_options)) { ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ u8 *addrs_id; ++ int id, len, len_align; ++ ++ len = mptcp_sub_len_remove_addr(opts->remove_addrs); ++ len_align = mptcp_sub_len_remove_addr_align(opts->remove_addrs); ++ ++ mprem->kind = TCPOPT_MPTCP; ++ mprem->len = len; ++ mprem->sub = MPTCP_SUB_REMOVE_ADDR; ++ mprem->rsv = 0; ++ addrs_id = &mprem->addrs_id; ++ ++ mptcp_for_each_bit_set(opts->remove_addrs, id) ++ *(addrs_id++) = id; ++ ++ /* Fill the rest with NOP's */ ++ if (len_align > len) { ++ int i; ++ for (i = 0; i < len_align - len; i++) ++ *(addrs_id++) = TCPOPT_NOP; ++ } ++ ++ ptr += len_align >> 2; ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_REMADDRTX); ++ } ++ if (unlikely(OPTION_MP_FAIL & opts->mptcp_options)) { ++ struct mp_fail *mpfail = (struct mp_fail *)ptr; ++ ++ mpfail->kind = TCPOPT_MPTCP; ++ mpfail->len = MPTCP_SUB_LEN_FAIL; ++ mpfail->sub = MPTCP_SUB_FAIL; ++ mpfail->rsv1 = 0; ++ mpfail->rsv2 = 0; ++ mpfail->data_seq = htonll(tp->mpcb->csum_cutoff_seq); ++ ++ ptr += MPTCP_SUB_LEN_FAIL_ALIGN >> 2; ++ } ++ if (unlikely(OPTION_MP_FCLOSE & opts->mptcp_options)) { ++ struct mp_fclose *mpfclose = (struct mp_fclose *)ptr; ++ ++ mpfclose->kind = TCPOPT_MPTCP; ++ mpfclose->len = MPTCP_SUB_LEN_FCLOSE; ++ mpfclose->sub = MPTCP_SUB_FCLOSE; ++ mpfclose->rsv1 = 0; ++ mpfclose->rsv2 = 0; ++ mpfclose->key = opts->mp_capable.receiver_key; ++ ++ ptr += MPTCP_SUB_LEN_FCLOSE_ALIGN >> 2; ++ } ++ ++ if (OPTION_DATA_ACK & opts->mptcp_options) { ++ if (!mptcp_is_data_seq(skb)) ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ else ++ ptr += mptcp_write_dss_data_seq(tp, skb, ptr); ++ } ++ if (unlikely(OPTION_MP_PRIO & opts->mptcp_options)) { ++ struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ mpprio->kind = TCPOPT_MPTCP; ++ mpprio->len = MPTCP_SUB_LEN_PRIO; ++ mpprio->sub = MPTCP_SUB_PRIO; ++ mpprio->rsv = 0; ++ mpprio->b = tp->mptcp->low_prio; ++ mpprio->addr_id = TCPOPT_NOP; ++ ++ ptr += MPTCP_SUB_LEN_PRIO_ALIGN >> 2; ++ } ++} ++ ++/* Sends the datafin */ ++void mptcp_send_fin(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb = tcp_write_queue_tail(meta_sk); ++ int mss_now; ++ ++ if ((1 << meta_sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK)) ++ meta_tp->mpcb->passive_close = 1; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = mptcp_current_mss(meta_sk); ++ ++ if (tcp_send_head(meta_sk) != NULL) { ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ meta_tp->write_seq++; ++ } else { ++ /* Socket is locked, keep trying until memory is available. */ ++ for (;;) { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, ++ meta_sk->sk_allocation); ++ if (skb) ++ break; ++ yield(); ++ } ++ /* Reserve space for headers and prepare control bits. */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ ++ tcp_init_nondata_skb(skb, meta_tp->write_seq, TCPHDR_ACK); ++ TCP_SKB_CB(skb)->end_seq++; ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ tcp_queue_skb(meta_sk, skb); ++ } ++ __tcp_push_pending_frames(meta_sk, mss_now, TCP_NAGLE_OFF); ++} ++ ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ ++ if (!mpcb->cnt_subflows) ++ return; ++ ++ WARN_ON(meta_tp->send_mp_fclose); ++ ++ /* First - select a socket */ ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ /* May happen if no subflow is in an appropriate state, OR ++ * we are in infinite mode or about to go there - just send a reset ++ */ ++ if (!sk || mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping || ++ mpcb->infinite_mapping_rcv) { ++ ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ return; ++ } ++ ++ ++ tcp_sk(sk)->send_mp_fclose = 1; ++ /** Reset all other subflows */ ++ ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ tcp_set_state(sk, TCP_RST_WAIT); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ ++ tcp_send_ack(sk); ++ tcp_clear_xmit_timers(sk); ++ inet_csk_reset_keepalive_timer(sk, inet_csk(sk)->icsk_rto); ++ ++ meta_tp->send_mp_fclose = 1; ++ inet_csk(sk)->icsk_retransmits = 0; ++ ++ /* Prevent exp backoff reverting on ICMP dest unreachable */ ++ inet_csk(sk)->icsk_backoff = 0; ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_FASTCLOSETX); ++} ++ ++static void mptcp_ack_retransmit_timer(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ struct sk_buff *skb; ++ ++ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) ++ goto out; /* Routing failure or similar */ ++ ++ if (!tp->retrans_stamp) ++ tp->retrans_stamp = tcp_time_stamp ? : 1; ++ ++ if (tcp_write_timeout(sk)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRTO); ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ goto out; ++ } ++ ++ skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (skb == NULL) { ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ /* Reserve space for headers and prepare control bits */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ tcp_init_nondata_skb(skb, tp->snd_una, TCPHDR_ACK); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRXMIT); ++ ++ if (tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC) > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!icsk->icsk_retransmits) ++ icsk->icsk_retransmits = 1; ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ ++ icsk->icsk_retransmits++; ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0, 0)) ++ __sk_dst_reset(sk); ++ ++out:; ++} ++ ++void mptcp_ack_handler(unsigned long data) ++{ ++ struct sock *sk = (struct sock *)data; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ /* Try again later */ ++ sk_reset_timer(sk, &tcp_sk(sk)->mptcp->mptcp_ack_timer, ++ jiffies + (HZ / 20)); ++ goto out_unlock; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) ++ goto out_unlock; ++ if (!tcp_sk(sk)->mptcp->pre_established) ++ goto out_unlock; ++ ++ mptcp_ack_retransmit_timer(sk); ++ ++ sk_mem_reclaim(sk); ++ ++out_unlock: ++ bh_unlock_sock(meta_sk); ++ sock_put(sk); ++} ++ ++/* Similar to tcp_retransmit_skb ++ * ++ * The diff is that we handle the retransmission-stats (retrans_stamp) at the ++ * meta-level. ++ */ ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk; ++ unsigned int limit, mss_now; ++ int err = -1; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ /* Do not sent more than we queued. 1/4 is reserved for possible ++ * copying overhead: fragmentation, tunneling, mangling etc. ++ * ++ * This is a meta-retransmission thus we check on the meta-socket. ++ */ ++ if (atomic_read(&meta_sk->sk_wmem_alloc) > ++ min(meta_sk->sk_wmem_queued + (meta_sk->sk_wmem_queued >> 2), meta_sk->sk_sndbuf)) { ++ return -EAGAIN; ++ } ++ ++ /* We need to make sure that the retransmitted segment can be sent on a ++ * subflow right now. If it is too big, it needs to be fragmented. ++ */ ++ subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, false); ++ if (!subsk) { ++ /* We want to increase icsk_retransmits, thus return 0, so that ++ * mptcp_meta_retransmit_timer enters the desired branch. ++ */ ++ err = 0; ++ goto failed; ++ } ++ mss_now = tcp_current_mss(subsk); ++ ++ /* If the segment was cloned (e.g. a meta retransmission), the header ++ * must be expanded/copied so that there is no corruption of TSO ++ * information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Must have been set by mptcp_write_xmit before */ ++ BUG_ON(!tcp_skb_pcount(skb)); ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ TCP_NAGLE_OFF); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, skb, limit, ++ GFP_ATOMIC, 0))) ++ goto failed; ++ ++ if (!mptcp_skb_entail(subsk, skb, -1)) ++ goto failed; ++ skb_mstamp_get(&skb->skb_mstamp); ++ ++ /* Update global TCP statistics. */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_RETRANSSEGS); ++ ++ /* Diff to tcp_retransmit_skb */ ++ ++ /* Save stamp of the first retransmit. */ ++ if (!meta_tp->retrans_stamp) ++ meta_tp->retrans_stamp = tcp_skb_timestamp(skb); ++ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ meta_tp->lsndtime = tcp_time_stamp; ++ ++ return 0; ++ ++failed: ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPRETRANSFAIL); ++ return err; ++} ++ ++/* Similar to tcp_retransmit_timer ++ * ++ * The diff is that we have to handle retransmissions of the FAST_CLOSE-message ++ * and that we don't have an srtt estimation at the meta-level. ++ */ ++void mptcp_meta_retransmit_timer(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ int err; ++ ++ /* In fallback, retransmission is handled at the subflow-level */ ++ if (!meta_tp->packets_out || mpcb->infinite_mapping_snd) ++ return; ++ ++ WARN_ON(tcp_write_queue_empty(meta_sk)); ++ ++ if (!meta_tp->snd_wnd && !sock_flag(meta_sk, SOCK_DEAD) && ++ !((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { ++ /* Receiver dastardly shrinks window. Our retransmits ++ * become zero probes, but we should not timeout this ++ * connection. If the socket is an orphan, time it out, ++ * we cannot allow such beasts to hang infinitely. ++ */ ++ struct inet_sock *meta_inet = inet_sk(meta_sk); ++ if (meta_sk->sk_family == AF_INET) { ++ net_dbg_ratelimited("MPTCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_inet->inet_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (meta_sk->sk_family == AF_INET6) { ++ net_dbg_ratelimited("MPTCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_sk->sk_v6_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#endif ++ if (tcp_time_stamp - meta_tp->rcv_tstamp > TCP_RTO_MAX) { ++ tcp_write_err(meta_sk); ++ return; ++ } ++ ++ mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ goto out_reset_timer; ++ } ++ ++ if (tcp_write_timeout(meta_sk)) ++ return; ++ ++ if (meta_icsk->icsk_retransmits == 0) ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPTIMEOUTS); ++ ++ meta_icsk->icsk_ca_state = TCP_CA_Loss; ++ ++ err = mptcp_retransmit_skb(meta_sk, tcp_write_queue_head(meta_sk)); ++ if (err > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!meta_icsk->icsk_retransmits) ++ meta_icsk->icsk_retransmits = 1; ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ min(meta_icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), ++ TCP_RTO_MAX); ++ return; ++ } ++ ++ /* Increase the timeout each time we retransmit. Note that ++ * we do not increase the rtt estimate. rto is initialized ++ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests ++ * that doubling rto each time is the least we can get away with. ++ * In KA9Q, Karn uses this for the first few times, and then ++ * goes to quadratic. netBSD doubles, but only goes up to *64, ++ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is ++ * defined in the protocol as the maximum possible RTT. I guess ++ * we'll have to use something other than TCP to talk to the ++ * University of Mars. ++ * ++ * PAWS allows us longer timeouts and large windows, so once ++ * implemented ftp to mars will work nicely. We will have to fix ++ * the 120 second clamps though! ++ */ ++ meta_icsk->icsk_backoff++; ++ meta_icsk->icsk_retransmits++; ++ ++out_reset_timer: ++ /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is ++ * used to reset timer, set to 0. Recalculate 'icsk_rto' as this ++ * might be increased if the stream oscillates between thin and thick, ++ * thus the old value might already be too high compared to the value ++ * set by 'tcp_set_rto' in tcp_input.c which resets the rto without ++ * backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating ++ * exponential backoff behaviour to avoid continue hammering ++ * linear-timeout retransmissions into a black hole ++ */ ++ if (meta_sk->sk_state == TCP_ESTABLISHED && ++ (meta_tp->thin_lto || sysctl_tcp_thin_linear_timeouts) && ++ tcp_stream_is_thin(meta_tp) && ++ meta_icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { ++ meta_icsk->icsk_backoff = 0; ++ /* We cannot do the same as in tcp_write_timer because the ++ * srtt is not set here. ++ */ ++ mptcp_set_rto(meta_sk); ++ } else { ++ /* Use normal (exponential) backoff */ ++ meta_icsk->icsk_rto = min(meta_icsk->icsk_rto << 1, TCP_RTO_MAX); ++ } ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, meta_icsk->icsk_rto, TCP_RTO_MAX); ++ ++ return; ++} ++ ++void mptcp_sub_retransmit_timer(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_retransmit_timer(sk); ++ ++ if (!tp->fastopen_rsk) { ++ mptcp_reinject_data(sk, 1); ++ mptcp_set_rto(sk); ++ } ++} ++ ++/* Modify values to an mptcp-level for the initial window of new subflows */ ++void mptcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd, ++ const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ *window_clamp = mpcb->orig_window_clamp; ++ __space = tcp_win_from_space(mpcb->orig_sk_rcvbuf); ++ ++ tcp_select_initial_window(__space, mss, rcv_wnd, window_clamp, ++ wscale_ok, rcv_wscale, init_rcv_wnd, sk); ++} ++ ++static inline u64 mptcp_calc_rate(const struct sock *meta_sk, unsigned int mss, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ struct sock *sk; ++ u64 rate = 0; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ /* Do not consider subflows without a RTT estimation yet ++ * otherwise this_rate >>> rate. ++ */ ++ if (unlikely(!tp->srtt_us)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* If this_mss is smaller than mss, it means that a segment will ++ * be splitted in two (or more) when pushed on this subflow. If ++ * you consider that mss = 1428 and this_mss = 1420 then two ++ * segments will be generated: a 1420-byte and 8-byte segment. ++ * The latter will introduce a large overhead as for a single ++ * data segment 2 slots will be used in the congestion window. ++ * Therefore reducing by ~2 the potential throughput of this ++ * subflow. Indeed, 1428 will be send while 2840 could have been ++ * sent if mss == 1420 reducing the throughput by 2840 / 1428. ++ * ++ * The following algorithm take into account this overhead ++ * when computing the potential throughput that MPTCP can ++ * achieve when generating mss-byte segments. ++ * ++ * The formulae is the following: ++ * \sum_{\forall sub} ratio * \frac{mss * cwnd_sub}{rtt_sub} ++ * Where ratio is computed as follows: ++ * \frac{mss}{\ceil{mss / mss_sub} * mss_sub} ++ * ++ * ratio gives the reduction factor of the theoretical ++ * throughput a subflow can achieve if MPTCP uses a specific ++ * MSS value. ++ */ ++ this_rate = div64_u64((u64)mss * mss * (USEC_PER_SEC << 3) * ++ max(tp->snd_cwnd, tp->packets_out), ++ (u64)tp->srtt_us * ++ DIV_ROUND_UP(mss, this_mss) * this_mss); ++ rate += this_rate; ++ } ++ ++ return rate; ++} ++ ++static unsigned int __mptcp_current_mss(const struct sock *meta_sk, ++ unsigned int (*mss_cb)(struct sock *sk)) ++{ ++ unsigned int mss = 0; ++ u64 rate = 0; ++ struct sock *sk; ++ ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_mss = mss_cb(sk); ++ ++ /* Same mss values will produce the same throughput. */ ++ if (this_mss == mss) ++ continue; ++ ++ /* See whether using this mss value can theoretically improve ++ * the performances. ++ */ ++ this_rate = mptcp_calc_rate(meta_sk, this_mss, mss_cb); ++ if (this_rate >= rate) { ++ mss = this_mss; ++ rate = this_rate; ++ } ++ } ++ ++ return mss; ++} ++ ++unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, tcp_current_mss); ++ ++ /* If no subflow is available, we take a default-mss from the ++ * meta-socket. ++ */ ++ return !mss ? tcp_current_mss(meta_sk) : mss; ++} ++ ++static unsigned int mptcp_select_size_mss(struct sock *sk) ++{ ++ return tcp_sk(sk)->mss_cache; ++} ++ ++int mptcp_select_size(const struct sock *meta_sk, bool sg, bool first_skb) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk, mptcp_select_size_mss); ++ ++ if (sg) { ++ if (mptcp_sk_can_gso(meta_sk)) { ++ mss = linear_payload_sz(first_skb); ++ } else { ++ int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); ++ ++ if (mss >= pgbreak && ++ mss <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE) ++ mss = pgbreak; ++ } ++ } ++ ++ return !mss ? tcp_sk(meta_sk)->mss_cache : mss; ++} ++ ++int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ const struct sock *sk; ++ u32 rtt_max = tp->srtt_us; ++ u64 bw_est; ++ ++ if (!tp->srtt_us) ++ return tp->reordering + 1; ++ ++ mptcp_for_each_sk(tp->mpcb, sk) { ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->srtt_us) ++ rtt_max = tcp_sk(sk)->srtt_us; ++ } ++ ++ bw_est = div64_u64(((u64)tp->snd_cwnd * rtt_max) << 16, ++ (u64)tp->srtt_us); ++ ++ return max_t(unsigned int, (u32)(bw_est >> 16), ++ tp->reordering + 1); ++} ++ ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed) ++{ ++ struct sock *sk; ++ u32 xmit_size_goal = 0; ++ ++ if (large_allowed && mptcp_sk_can_gso(meta_sk)) { ++ mptcp_for_each_sk(tcp_sk(meta_sk)->mpcb, sk) { ++ int this_size_goal; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_size_goal = tcp_xmit_size_goal(sk, mss_now, 1); ++ if (this_size_goal > xmit_size_goal) ++ xmit_size_goal = this_size_goal; ++ } ++ } ++ ++ return max(xmit_size_goal, mss_now); ++} ++ +diff -aurN linux-4.9.162/net/mptcp/mptcp_pm.c mptcp-mptcp_v0.93/net/mptcp/mptcp_pm.c +--- linux-4.9.162/net/mptcp/mptcp_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_pm.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,226 @@ ++/* ++ * MPTCP implementation - MPTCP-subflow-management ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_pm_list_lock); ++static LIST_HEAD(mptcp_pm_list); ++ ++static int mptcp_default_id(sa_family_t family, union inet_addr *addr, ++ struct net *net, bool *low_prio) ++{ ++ return 0; ++} ++ ++struct mptcp_pm_ops mptcp_pm_default = { ++ .get_local_id = mptcp_default_id, /* We do not care */ ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_pm_ops *mptcp_pm_find(const char *name) ++{ ++ struct mptcp_pm_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_pm_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm) ++{ ++ int ret = 0; ++ ++ if (!pm->get_local_id) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ if (mptcp_pm_find(pm->name)) { ++ pr_notice("%s already registered\n", pm->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&pm->list, &mptcp_pm_list); ++ pr_info("%s registered\n", pm->name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_path_manager); ++ ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm) ++{ ++ spin_lock(&mptcp_pm_list_lock); ++ list_del_rcu(&pm->list); ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_path_manager); ++ ++void mptcp_get_default_path_manager(char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ BUG_ON(list_empty(&mptcp_pm_list)); ++ ++ rcu_read_lock(); ++ pm = list_entry(mptcp_pm_list.next, struct mptcp_pm_ops, list); ++ strncpy(name, pm->name, MPTCP_PM_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_path_manager(const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ ++ if (pm) { ++ list_move(&pm->list, &mptcp_pm_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops *__mptcp_pm_find_autoload(const char *name) ++{ ++ struct mptcp_pm_ops *pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ return pm; ++} ++ ++void mptcp_init_path_manager(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if path manager was set using socket option */ ++ if (meta_tp->mptcp_pm_setsockopt) { ++ pm = __mptcp_pm_find_autoload(meta_tp->mptcp_pm_name); ++ if (pm && try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(pm, &mptcp_pm_list, list) { ++ if (try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change path manager for socket */ ++int mptcp_set_path_manager(struct sock *sk, const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int err = 0; ++ ++ rcu_read_lock(); ++ pm = __mptcp_pm_find_autoload(name); ++ ++ if (!pm) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_pm_name, name); ++ tcp_sk(sk)->mptcp_pm_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->pm_ops->owner); ++} ++ ++/* Fallback to the default path-manager. */ ++void mptcp_fallback_default(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ mptcp_cleanup_path_manager(mpcb); ++ pm = mptcp_pm_find("default"); ++ ++ /* Cannot fail - it's the default module */ ++ try_module_get(pm->owner); ++ mpcb->pm_ops = pm; ++} ++EXPORT_SYMBOL_GPL(mptcp_fallback_default); ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_path_manager_default(void) ++{ ++ return mptcp_set_default_path_manager(CONFIG_DEFAULT_MPTCP_PM); ++} ++late_initcall(mptcp_path_manager_default); +diff -aurN linux-4.9.162/net/mptcp/mptcp_redundant.c mptcp-mptcp_v0.93/net/mptcp/mptcp_redundant.c +--- linux-4.9.162/net/mptcp/mptcp_redundant.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_redundant.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,301 @@ ++/* ++ * MPTCP Scheduler to reduce latency and jitter. ++ * ++ * This scheduler sends all packets redundantly on all available subflows. ++ * ++ * Initial Design & Implementation: ++ * Tobias Erbshaeusser ++ * Alexander Froemmgen ++ * ++ * Initial corrections & modifications: ++ * Christian Pinedo ++ * Igor Lopez ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++/* Struct to store the data of a single subflow */ ++struct redsched_sock_data { ++ /* The skb or NULL */ ++ struct sk_buff *skb; ++ /* End sequence number of the skb. This number should be checked ++ * to be valid before the skb field is used ++ */ ++ u32 skb_end_seq; ++}; ++ ++/* Struct to store the data of the control block */ ++struct redsched_cb_data { ++ /* The next subflow where a skb should be sent or NULL */ ++ struct tcp_sock *next_subflow; ++}; ++ ++/* Returns the socket data from a given subflow socket */ ++static struct redsched_sock_data *redsched_get_sock_data(struct tcp_sock *tp) ++{ ++ return (struct redsched_sock_data *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* Returns the control block data from a given meta socket */ ++static struct redsched_cb_data *redsched_get_cb_data(struct tcp_sock *tp) ++{ ++ return (struct redsched_cb_data *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static bool redsched_get_active_valid_sks(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ int active_valid_sks = 0; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ if (subflow_is_active((struct tcp_sock *)sk) && ++ !mptcp_is_def_unavailable(sk)) ++ active_valid_sks++; ++ } ++ ++ return active_valid_sks; ++} ++ ++static bool redsched_use_subflow(struct sock *meta_sk, ++ int active_valid_sks, ++ struct tcp_sock *tp, ++ struct sk_buff *skb) ++{ ++ if (!skb || !mptcp_is_available((struct sock *)tp, skb, false)) ++ return false; ++ ++ if (TCP_SKB_CB(skb)->path_mask != 0) ++ return subflow_is_active(tp); ++ ++ if (TCP_SKB_CB(skb)->path_mask == 0) { ++ if (active_valid_sks == -1) ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ if (subflow_is_backup(tp) && active_valid_sks > 0) ++ return false; ++ else ++ return true; ++ } ++ ++ return false; ++} ++ ++static struct sock *redundant_get_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(meta_tp); ++ struct tcp_sock *first_tp = cb_data->next_subflow; ++ struct sock *sk; ++ struct tcp_sock *tp; ++ ++ /* Answer data_fin on same subflow */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == ++ mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ if (!first_tp) ++ first_tp = mpcb->connection_list; ++ tp = first_tp; ++ ++ /* still NULL (no subflow in connection_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ /* Search for any subflow to send it */ ++ do { ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ cb_data->next_subflow = tp->mptcp->next; ++ return (struct sock *)tp; ++ } ++ ++ tp = tp->mptcp->next; ++ if (!tp) ++ tp = mpcb->connection_list; ++ } while (tp != first_tp); ++ ++ /* No space */ ++ return NULL; ++} ++ ++/* Corrects the stored skb pointers if they are invalid */ ++static void redsched_correct_skb_pointers(struct sock *meta_sk, ++ struct redsched_sock_data *sk_data) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (sk_data->skb && !after(sk_data->skb_end_seq, meta_tp->snd_una)) ++ sk_data->skb = NULL; ++} ++ ++/* Returns the next skb from the queue */ ++static struct sk_buff *redundant_next_skb_from_queue(struct sk_buff_head *queue, ++ struct sk_buff *previous, ++ struct sock *meta_sk) ++{ ++ if (skb_queue_empty(queue)) ++ return NULL; ++ ++ if (!previous) ++ return skb_peek(queue); ++ ++ if (skb_queue_is_last(queue, previous)) ++ return NULL; ++ ++ /* sk_data->skb stores the last scheduled packet for this subflow. ++ * If sk_data->skb was scheduled but not sent (e.g., due to nagle), ++ * we have to schedule it again. ++ * ++ * For the redundant scheduler, there are two cases: ++ * 1. sk_data->skb was not sent on another subflow: ++ * we have to schedule it again to ensure that we do not ++ * skip this packet. ++ * 2. sk_data->skb was already sent on another subflow: ++ * with regard to the redundant semantic, we have to ++ * schedule it again. However, we keep it simple and ignore it, ++ * as it was already sent by another subflow. ++ * This might be changed in the future. ++ * ++ * For case 1, send_head is equal previous, as only a single ++ * packet can be skipped. ++ */ ++ if (tcp_send_head(meta_sk) == previous) ++ return tcp_send_head(meta_sk); ++ ++ return skb_queue_next(queue, previous); ++} ++ ++static struct sk_buff *redundant_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(meta_tp); ++ struct tcp_sock *first_tp = cb_data->next_subflow; ++ struct tcp_sock *tp; ++ struct sk_buff *skb; ++ int active_valid_sks = -1; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (skb_queue_empty(&mpcb->reinject_queue) && ++ skb_queue_empty(&meta_sk->sk_write_queue)) ++ /* Nothing to send */ ++ return NULL; ++ ++ /* First try reinjections */ ++ skb = skb_peek(&mpcb->reinject_queue); ++ if (skb) { ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ *reinject = 1; ++ return skb; ++ } ++ ++ /* Then try indistinctly redundant and normal skbs */ ++ ++ if (!first_tp) ++ first_tp = mpcb->connection_list; ++ ++ /* still NULL (no subflow in connection_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ tp = first_tp; ++ ++ *reinject = 0; ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ do { ++ struct redsched_sock_data *sk_data; ++ ++ /* Correct the skb pointers of the current subflow */ ++ sk_data = redsched_get_sock_data(tp); ++ redsched_correct_skb_pointers(meta_sk, sk_data); ++ ++ skb = redundant_next_skb_from_queue(&meta_sk->sk_write_queue, ++ sk_data->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ sk_data->skb = skb; ++ sk_data->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ cb_data->next_subflow = tp->mptcp->next; ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ ++ tp = tp->mptcp->next; ++ if (!tp) ++ tp = mpcb->connection_list; ++ } while (tp != first_tp); ++ ++ /* Nothing to send */ ++ return NULL; ++} ++ ++static void redundant_release(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct redsched_cb_data *cb_data = redsched_get_cb_data(tp); ++ ++ /* Check if the next subflow would be the released one. If yes correct ++ * the pointer ++ */ ++ if (cb_data->next_subflow == tp) ++ cb_data->next_subflow = tp->mptcp->next; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_redundant = { ++ .get_subflow = redundant_get_subflow, ++ .next_segment = redundant_next_segment, ++ .release = redundant_release, ++ .name = "redundant", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init redundant_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct redsched_sock_data) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct redsched_cb_data) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_redundant)) ++ return -1; ++ ++ return 0; ++} ++ ++static void redundant_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_redundant); ++} ++ ++module_init(redundant_register); ++module_exit(redundant_unregister); ++ ++MODULE_AUTHOR("Tobias Erbshaeusser, Alexander Froemmgen"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("REDUNDANT MPTCP"); ++MODULE_VERSION("0.90"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_rr.c mptcp-mptcp_v0.93/net/mptcp/mptcp_rr.c +--- linux-4.9.162/net/mptcp/mptcp_rr.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_rr.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,301 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static unsigned char num_segments __read_mostly = 1; ++module_param(num_segments, byte, 0644); ++MODULE_PARM_DESC(num_segments, "The number of consecutive segments that are part of a burst"); ++ ++static bool cwnd_limited __read_mostly = 1; ++module_param(cwnd_limited, bool, 0644); ++MODULE_PARM_DESC(cwnd_limited, "if set to 1, the scheduler tries to fill the congestion-window on all subflows"); ++ ++struct rrsched_priv { ++ unsigned char quota; ++}; ++ ++static struct rrsched_priv *rrsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct rrsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* If the sub-socket sk available to send the skb? */ ++static bool mptcp_rr_is_available(const struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test, bool cwnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int space, in_flight; ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return false; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return false; ++ ++ if (tp->pf) ++ return false; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been acked. ++ * (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return false; ++ else if (tp->snd_una != tp->high_seq) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return false; ++ } ++ ++ if (!cwnd_test) ++ goto zero_wnd_test; ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return false; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return false; ++ ++zero_wnd_test: ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return false; ++ ++ return true; ++} ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_rr_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++/* We just look for any subflow that is available */ ++static struct sock *rr_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk, *bestsk = NULL, *backupsk = NULL; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ return sk; ++ } ++ } ++ ++ /* First, find the best subflow */ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ continue; ++ ++ if (mptcp_rr_dont_reinject_skb(tp, skb)) { ++ backupsk = sk; ++ continue; ++ } ++ ++ bestsk = sk; ++ } ++ ++ if (bestsk) { ++ sk = bestsk; ++ } else if (backupsk) { ++ /* It has been sent on all subflows once - let's give it a ++ * chance again by restarting its pathmask. ++ */ ++ if (skb) ++ TCP_SKB_CB(skb)->path_mask = 0; ++ sk = backupsk; ++ } ++ ++ return sk; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_rr_next_segment(const struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) ++ *reinject = 1; ++ else ++ skb = tcp_send_head(meta_sk); ++ return skb; ++} ++ ++static struct sk_buff *mptcp_rr_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk_it, *choose_sk = NULL; ++ struct sk_buff *skb = __mptcp_rr_next_segment(meta_sk, reinject); ++ unsigned char split = num_segments; ++ unsigned char iter = 0, full_subs = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ if (*reinject) { ++ *subsk = rr_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ return skb; ++ } ++ ++retry: ++ ++ /* First, we look for a subflow who is currently being used */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rsp = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ iter++; ++ ++ /* Is this subflow currently being used? */ ++ if (rsp->quota > 0 && rsp->quota < num_segments) { ++ split = num_segments - rsp->quota; ++ choose_sk = sk_it; ++ goto found; ++ } ++ ++ /* Or, it's totally unused */ ++ if (!rsp->quota) { ++ split = num_segments; ++ choose_sk = sk_it; ++ } ++ ++ /* Or, it must then be fully used */ ++ if (rsp->quota >= num_segments) ++ full_subs++; ++ } ++ ++ /* All considered subflows have a full quota, and we considered at ++ * least one. ++ */ ++ if (iter && iter == full_subs) { ++ /* So, we restart this round by setting quota to 0 and retry ++ * to find a subflow. ++ */ ++ mptcp_for_each_sk(mpcb, sk_it) { ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rsp = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ rsp->quota = 0; ++ } ++ ++ goto retry; ++ } ++ ++found: ++ if (choose_sk) { ++ unsigned int mss_now; ++ struct tcp_sock *choose_tp = tcp_sk(choose_sk); ++ struct rrsched_priv *rsp = rrsched_get_priv(choose_tp); ++ ++ if (!mptcp_rr_is_available(choose_sk, skb, false, true)) ++ return NULL; ++ ++ *subsk = choose_sk; ++ mss_now = tcp_current_mss(*subsk); ++ *limit = split * mss_now; ++ ++ if (skb->len > mss_now) ++ rsp->quota += DIV_ROUND_UP(skb->len, mss_now); ++ else ++ rsp->quota++; ++ ++ return skb; ++ } ++ ++ return NULL; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_rr = { ++ .get_subflow = rr_get_available_subflow, ++ .next_segment = mptcp_rr_next_segment, ++ .name = "roundrobin", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init rr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct rrsched_priv) > MPTCP_SCHED_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_rr)) ++ return -1; ++ ++ return 0; ++} ++ ++static void rr_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_rr); ++} ++ ++module_init(rr_register); ++module_exit(rr_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ROUNDROBIN MPTCP"); ++MODULE_VERSION("0.89"); +diff -aurN linux-4.9.162/net/mptcp/mptcp_sched.c mptcp-mptcp_v0.93/net/mptcp/mptcp_sched.c +--- linux-4.9.162/net/mptcp/mptcp_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_sched.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,634 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_sched_list_lock); ++static LIST_HEAD(mptcp_sched_list); ++ ++struct defsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++static struct defsched_priv *defsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct defsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++bool mptcp_is_def_unavailable(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return true; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return true; ++ ++ if (tp->pf) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(mptcp_is_def_unavailable); ++ ++static bool mptcp_is_temp_unavailable(struct sock *sk, ++ const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int mss_now, space, in_flight; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been ++ * acked. (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return true; ++ else if (tp->snd_una != tp->high_seq) ++ return true; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return true; ++ } ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return true; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return true; ++ ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return true; ++ ++ mss_now = tcp_current_mss(sk); ++ ++ /* Don't send on this subflow if we bypass the allowed send-window at ++ * the per-subflow level. Similar to tcp_snd_wnd_test, but manually ++ * calculated end_seq (because here at this point end_seq is still at ++ * the meta-level). ++ */ ++ if (skb && !zero_wnd_test && ++ after(tp->write_seq + min(skb->len, mss_now), tcp_wnd_end(tp))) ++ return true; ++ ++ return false; ++} ++ ++/* Is the sub-socket sk available to send the skb? */ ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ return !mptcp_is_def_unavailable(sk) && ++ !mptcp_is_temp_unavailable(sk, skb, zero_wnd_test); ++} ++EXPORT_SYMBOL_GPL(mptcp_is_available); ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++bool subflow_is_backup(const struct tcp_sock *tp) ++{ ++ return tp->mptcp->rcv_low_prio || tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_backup); ++ ++bool subflow_is_active(const struct tcp_sock *tp) ++{ ++ return !tp->mptcp->rcv_low_prio && !tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_active); ++ ++/* Generic function to iterate over used and unused subflows and to select the ++ * best one ++ */ ++static struct sock ++*get_subflow_from_selectors(struct mptcp_cb *mpcb, struct sk_buff *skb, ++ bool (*selector)(const struct tcp_sock *), ++ bool zero_wnd_test, bool *force) ++{ ++ struct sock *bestsk = NULL; ++ u32 min_srtt = 0xffffffff; ++ bool found_unused = false; ++ bool found_unused_una = false; ++ struct sock *sk; ++ ++ mptcp_for_each_sk(mpcb, sk) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ bool unused = false; ++ ++ /* First, we choose only the wanted sks */ ++ if (!(*selector)(tp)) ++ continue; ++ ++ if (!mptcp_dont_reinject_skb(tp, skb)) ++ unused = true; ++ else if (found_unused) ++ /* If a unused sk was found previously, we continue - ++ * no need to check used sks anymore. ++ */ ++ continue; ++ ++ if (mptcp_is_def_unavailable(sk)) ++ continue; ++ ++ if (mptcp_is_temp_unavailable(sk, skb, zero_wnd_test)) { ++ if (unused) ++ found_unused_una = true; ++ continue; ++ } ++ ++ if (unused) { ++ if (!found_unused) { ++ /* It's the first time we encounter an unused ++ * sk - thus we reset the bestsk (which might ++ * have been set to a used sk). ++ */ ++ min_srtt = 0xffffffff; ++ bestsk = NULL; ++ } ++ found_unused = true; ++ } ++ ++ if (tp->srtt_us < min_srtt) { ++ min_srtt = tp->srtt_us; ++ bestsk = sk; ++ } ++ } ++ ++ if (bestsk) { ++ /* The force variable is used to mark the returned sk as ++ * previously used or not-used. ++ */ ++ if (found_unused) ++ *force = true; ++ else ++ *force = false; ++ } else { ++ /* The force variable is used to mark if there are temporally ++ * unavailable not-used sks. ++ */ ++ if (found_unused_una) ++ *force = true; ++ else ++ *force = false; ++ } ++ ++ return bestsk; ++} ++ ++/* This is the scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy, NULL is returned ++ * The flow is selected based on the shortest RTT. ++ * If all paths have full cong windows, we simply return NULL. ++ * ++ * Additionally, this function is aware of the backup-subflows. ++ */ ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk; ++ bool looping = false, force; ++ ++ /* if there is only one subflow, bypass the scheduling function */ ++ if (mpcb->cnt_subflows == 1) { ++ sk = (struct sock *)mpcb->connection_list; ++ if (!mptcp_is_available(sk, skb, zero_wnd_test)) ++ sk = NULL; ++ return sk; ++ } ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sk(mpcb, sk) { ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ /* Find the best subflow */ ++restart: ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_active, ++ zero_wnd_test, &force); ++ if (force) ++ /* one unused active sk or one NULL sk when there is at least ++ * one temporally unavailable unused active sk ++ */ ++ return sk; ++ ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_backup, ++ zero_wnd_test, &force); ++ if (!force && skb) { ++ /* one used backup sk or one NULL sk where there is no one ++ * temporally unavailable unused backup sk ++ * ++ * the skb passed through all the available active and backups ++ * sks, so clean the path mask ++ */ ++ TCP_SKB_CB(skb)->path_mask = 0; ++ ++ if (!looping) { ++ looping = true; ++ goto restart; ++ } ++ } ++ return sk; ++} ++EXPORT_SYMBOL_GPL(get_available_subflow); ++ ++static struct sk_buff *mptcp_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *tp_it; ++ struct sk_buff *skb_head; ++ struct defsched_priv *dsp = defsched_get_priv(tp); ++ ++ if (tp->mpcb->cnt_subflows == 1) ++ return NULL; ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_write_queue_head(meta_sk); ++ ++ if (!skb_head || skb_head == tcp_send_head(meta_sk)) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_time_stamp - dsp->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flow */ ++ mptcp_for_each_tp(tp->mpcb, tp_it) { ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ dsp->last_rbuf_opti = tcp_time_stamp; ++ } ++ break; ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_tp(tp->mpcb, tp_it) { ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) ++ return skb_head; ++ } ++ return NULL; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = get_available_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++static struct sk_buff *mptcp_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_next_segment(meta_sk, reinject); ++ unsigned int mss_now; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ u32 max_len, max_segs, window, needed; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ * ++ * So, we first limit according to the cwnd/gso-size and then according ++ * to the subflow's window. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ max_len = mss_now * max_segs; ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ needed = min(skb->len, window); ++ if (max_len <= skb->len) ++ /* Take max_win, which is actually the cwnd/gso-size */ ++ *limit = max_len; ++ else ++ /* Or, take the window */ ++ *limit = needed; ++ ++ return skb; ++} ++ ++static void defsched_init(struct sock *sk) ++{ ++ struct defsched_priv *dsp = defsched_get_priv(tcp_sk(sk)); ++ ++ dsp->last_rbuf_opti = tcp_time_stamp; ++} ++ ++struct mptcp_sched_ops mptcp_sched_default = { ++ .get_subflow = get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = defsched_init, ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_sched_ops *mptcp_sched_find(const char *name) ++{ ++ struct mptcp_sched_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_sched_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched) ++{ ++ int ret = 0; ++ ++ if (!sched->get_subflow || !sched->next_segment) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ if (mptcp_sched_find(sched->name)) { ++ pr_notice("%s already registered\n", sched->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&sched->list, &mptcp_sched_list); ++ pr_info("%s registered\n", sched->name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_scheduler); ++ ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched) ++{ ++ spin_lock(&mptcp_sched_list_lock); ++ list_del_rcu(&sched->list); ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_scheduler); ++ ++void mptcp_get_default_scheduler(char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ ++ BUG_ON(list_empty(&mptcp_sched_list)); ++ ++ rcu_read_lock(); ++ sched = list_entry(mptcp_sched_list.next, struct mptcp_sched_ops, list); ++ strncpy(name, sched->name, MPTCP_SCHED_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_scheduler(const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ ++ if (sched) { ++ list_move(&sched->list, &mptcp_sched_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++ ++/* Must be called with rcu lock held */ ++static struct mptcp_sched_ops *__mptcp_sched_find_autoload(const char *name) ++{ ++ struct mptcp_sched_ops *sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ return sched; ++} ++ ++void mptcp_init_scheduler(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_sched_ops *sched; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if scheduler was set using socket option */ ++ if (meta_tp->mptcp_sched_setsockopt) { ++ sched = __mptcp_sched_find_autoload(meta_tp->mptcp_sched_name); ++ if (sched && try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(sched, &mptcp_sched_list, list) { ++ if (try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change scheduler for socket */ ++int mptcp_set_scheduler(struct sock *sk, const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int err = 0; ++ ++ rcu_read_lock(); ++ sched = __mptcp_sched_find_autoload(name); ++ ++ if (!sched) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_sched_name, name); ++ tcp_sk(sk)->mptcp_sched_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->sched_ops->owner); ++} ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_scheduler_default(void) ++{ ++ BUILD_BUG_ON(sizeof(struct defsched_priv) > MPTCP_SCHED_SIZE); ++ ++ return mptcp_set_default_scheduler(CONFIG_DEFAULT_MPTCP_SCHED); ++} ++late_initcall(mptcp_scheduler_default); +diff -aurN linux-4.9.162/net/mptcp/mptcp_wvegas.c mptcp-mptcp_v0.93/net/mptcp/mptcp_wvegas.c +--- linux-4.9.162/net/mptcp/mptcp_wvegas.c 1970-01-01 01:00:00.000000000 +0100 ++++ mptcp-mptcp_v0.93/net/mptcp/mptcp_wvegas.c 2019-03-14 14:02:32.000000000 +0100 +@@ -0,0 +1,269 @@ ++/* ++ * MPTCP implementation - WEIGHTED VEGAS ++ * ++ * Algorithm design: ++ * Yu Cao ++ * Mingwei Xu ++ * Xiaoming Fu ++ * ++ * Implementation: ++ * Yu Cao ++ * Enhuan Dong ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int initial_alpha = 2; ++static int total_alpha = 10; ++static int gamma = 1; ++ ++module_param(initial_alpha, int, 0644); ++MODULE_PARM_DESC(initial_alpha, "initial alpha for all subflows"); ++module_param(total_alpha, int, 0644); ++MODULE_PARM_DESC(total_alpha, "total alpha for all subflows"); ++module_param(gamma, int, 0644); ++MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)"); ++ ++#define MPTCP_WVEGAS_SCALE 16 ++ ++/* wVegas variables */ ++struct wvegas { ++ u32 beg_snd_nxt; /* right edge during last RTT */ ++ u8 doing_wvegas_now;/* if true, do wvegas for this RTT */ ++ ++ u16 cnt_rtt; /* # of RTTs measured within last RTT */ ++ u32 sampled_rtt; /* cumulative RTTs measured within last RTT (in usec) */ ++ u32 base_rtt; /* the min of all wVegas RTT measurements seen (in usec) */ ++ ++ u64 instant_rate; /* cwnd / srtt_us, unit: pkts/us * 2^16 */ ++ u64 weight; /* the ratio of subflow's rate to the total rate, * 2^16 */ ++ int alpha; /* alpha for each subflows */ ++ ++ u32 queue_delay; /* queue delay*/ ++}; ++ ++ ++static inline u64 mptcp_wvegas_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static void wvegas_enable(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 1; ++ ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ ++ wvegas->instant_rate = 0; ++ wvegas->alpha = initial_alpha; ++ wvegas->weight = mptcp_wvegas_scale(1, MPTCP_WVEGAS_SCALE); ++ ++ wvegas->queue_delay = 0; ++} ++ ++static inline void wvegas_disable(const struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 0; ++} ++ ++static void mptcp_wvegas_init(struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->base_rtt = 0x7fffffff; ++ wvegas_enable(sk); ++} ++ ++static inline u64 mptcp_wvegas_rate(u32 cwnd, u32 rtt_us) ++{ ++ return div_u64(mptcp_wvegas_scale(cwnd, MPTCP_WVEGAS_SCALE), rtt_us); ++} ++ ++static void mptcp_wvegas_pkts_acked(struct sock *sk, ++ const struct ack_sample *sample) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ u32 vrtt; ++ ++ if (sample->rtt_us < 0) ++ return; ++ ++ vrtt = sample->rtt_us + 1; ++ ++ if (vrtt < wvegas->base_rtt) ++ wvegas->base_rtt = vrtt; ++ ++ wvegas->sampled_rtt += vrtt; ++ wvegas->cnt_rtt++; ++} ++ ++static void mptcp_wvegas_state(struct sock *sk, u8 ca_state) ++{ ++ if (ca_state == TCP_CA_Open) ++ wvegas_enable(sk); ++ else ++ wvegas_disable(sk); ++} ++ ++static void mptcp_wvegas_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_CWND_RESTART) { ++ mptcp_wvegas_init(sk); ++ } else if (event == CA_EVENT_LOSS) { ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ wvegas->instant_rate = 0; ++ } ++} ++ ++static inline u32 mptcp_wvegas_ssthresh(const struct tcp_sock *tp) ++{ ++ return min(tp->snd_ssthresh, tp->snd_cwnd); ++} ++ ++static u64 mptcp_wvegas_weight(const struct mptcp_cb *mpcb, const struct sock *sk) ++{ ++ u64 total_rate = 0; ++ struct sock *sub_sk; ++ const struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!mpcb) ++ return wvegas->weight; ++ ++ ++ mptcp_for_each_sk(mpcb, sub_sk) { ++ struct wvegas *sub_wvegas = inet_csk_ca(sub_sk); ++ ++ /* sampled_rtt is initialized by 0 */ ++ if (mptcp_sk_can_send(sub_sk) && (sub_wvegas->sampled_rtt > 0)) ++ total_rate += sub_wvegas->instant_rate; ++ } ++ ++ if (total_rate && wvegas->instant_rate) ++ return div64_u64(mptcp_wvegas_scale(wvegas->instant_rate, MPTCP_WVEGAS_SCALE), total_rate); ++ else ++ return wvegas->weight; ++} ++ ++static void mptcp_wvegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!wvegas->doing_wvegas_now) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (after(ack, wvegas->beg_snd_nxt)) { ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ if (wvegas->cnt_rtt <= 2) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ } else { ++ u32 rtt, diff, q_delay; ++ u64 target_cwnd; ++ ++ rtt = wvegas->sampled_rtt / wvegas->cnt_rtt; ++ target_cwnd = div_u64(((u64)tp->snd_cwnd * wvegas->base_rtt), rtt); ++ ++ diff = div_u64((u64)tp->snd_cwnd * (rtt - wvegas->base_rtt), rtt); ++ ++ if (diff > gamma && tcp_in_slow_start(tp)) { ++ tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ ++ } else if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ } else { ++ if (diff >= wvegas->alpha) { ++ wvegas->instant_rate = mptcp_wvegas_rate(tp->snd_cwnd, rtt); ++ wvegas->weight = mptcp_wvegas_weight(tp->mpcb, sk); ++ wvegas->alpha = max(2U, (u32)((wvegas->weight * total_alpha) >> MPTCP_WVEGAS_SCALE)); ++ } ++ if (diff > wvegas->alpha) { ++ tp->snd_cwnd--; ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ } else if (diff < wvegas->alpha) { ++ tp->snd_cwnd++; ++ } ++ ++ /* Try to drain link queue if needed*/ ++ q_delay = rtt - wvegas->base_rtt; ++ if ((wvegas->queue_delay == 0) || (wvegas->queue_delay > q_delay)) ++ wvegas->queue_delay = q_delay; ++ ++ if (q_delay >= 2 * wvegas->queue_delay) { ++ u32 backoff_factor = div_u64(mptcp_wvegas_scale(wvegas->base_rtt, MPTCP_WVEGAS_SCALE), 2 * rtt); ++ tp->snd_cwnd = ((u64)tp->snd_cwnd * backoff_factor) >> MPTCP_WVEGAS_SCALE; ++ wvegas->queue_delay = 0; ++ } ++ } ++ ++ if (tp->snd_cwnd < 2) ++ tp->snd_cwnd = 2; ++ else if (tp->snd_cwnd > tp->snd_cwnd_clamp) ++ tp->snd_cwnd = tp->snd_cwnd_clamp; ++ ++ tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ } ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ } ++ /* Use normal slow start */ ++ else if (tcp_in_slow_start(tp)) ++ tcp_slow_start(tp, acked); ++} ++ ++ ++static struct tcp_congestion_ops mptcp_wvegas __read_mostly = { ++ .init = mptcp_wvegas_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_wvegas_cong_avoid, ++ .pkts_acked = mptcp_wvegas_pkts_acked, ++ .set_state = mptcp_wvegas_state, ++ .cwnd_event = mptcp_wvegas_cwnd_event, ++ ++ .owner = THIS_MODULE, ++ .name = "wvegas", ++}; ++ ++static int __init mptcp_wvegas_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct wvegas) > ICSK_CA_PRIV_SIZE); ++ tcp_register_congestion_control(&mptcp_wvegas); ++ return 0; ++} ++ ++static void __exit mptcp_wvegas_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_wvegas); ++} ++ ++module_init(mptcp_wvegas_register); ++module_exit(mptcp_wvegas_unregister); ++ ++MODULE_AUTHOR("Yu Cao, Enhuan Dong"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP wVegas"); ++MODULE_VERSION("0.1"); diff --git a/root/target/linux/generic/hack-5.4/690-mptcp_trunk.patch b/root/target/linux/generic/hack-5.4/690-mptcp_trunk.patch new file mode 100644 index 00000000..dfb008e1 --- /dev/null +++ b/root/target/linux/generic/hack-5.4/690-mptcp_trunk.patch @@ -0,0 +1,23662 @@ +diff -aurN linux-5.4.64/Documentation/admin-guide/kernel-parameters.txt linux-5.4.64.mptcp/Documentation/admin-guide/kernel-parameters.txt +--- linux-5.4.64/Documentation/admin-guide/kernel-parameters.txt 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/Documentation/admin-guide/kernel-parameters.txt 2020-09-10 19:25:10.375223065 +0200 +@@ -2734,6 +2734,10 @@ + allocations which rules out almost all kernel + allocations. Use with caution! + ++ mptcp_htable_entries= ++ [KNL,NET] Set number of hash buckets for MPTCP token ++ hashtables. ++ + MTD_Partition= [MTD] + Format: ,,, + +diff -aurN linux-5.4.64/Documentation/networking/ip-sysctl.txt linux-5.4.64.mptcp/Documentation/networking/ip-sysctl.txt +--- linux-5.4.64/Documentation/networking/ip-sysctl.txt 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/Documentation/networking/ip-sysctl.txt 2020-09-10 19:25:10.375223065 +0200 +@@ -818,6 +818,18 @@ + + Default: 0 (disabled) + ++MPTCP variables: ++ ++mptcp_enabled - INTEGER ++ Enable or disable Multipath TCP for new connections. ++ Possible values are: ++ ++ 0: Multipath TCP is disabled on all TCP-sockets that are newly created. ++ 1: Multipath TCP is enabled by default on all new TCP-sockets. Note that ++ existing sockets in LISTEN-state will still use regular TCP. ++ 2: Enables Multipath TCP only upon the request of the application ++ throught the socket-option MPTCP_ENABLED. ++ + UDP variables: + + udp_l3mdev_accept - BOOLEAN +diff -aurN linux-5.4.64/drivers/infiniband/hw/cxgb4/cm.c linux-5.4.64.mptcp/drivers/infiniband/hw/cxgb4/cm.c +--- linux-5.4.64/drivers/infiniband/hw/cxgb4/cm.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/drivers/infiniband/hw/cxgb4/cm.c 2020-09-10 19:25:10.439222000 +0200 +@@ -3949,7 +3949,7 @@ + */ + memset(&tmp_opt, 0, sizeof(tmp_opt)); + tcp_clear_options(&tmp_opt); +- tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(&init_net, skb, &tmp_opt, NULL, 0, NULL, NULL); + + req = __skb_push(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); +diff -aurN linux-5.4.64/include/linux/skbuff.h linux-5.4.64.mptcp/include/linux/skbuff.h +--- linux-5.4.64/include/linux/skbuff.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/linux/skbuff.h 2020-09-10 19:25:10.439222000 +0200 +@@ -717,7 +717,7 @@ + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ +- char cb[48] __aligned(8); ++ char cb[80] __aligned(8); + + union { + struct { +diff -aurN linux-5.4.64/include/linux/tcp.h linux-5.4.64.mptcp/include/linux/tcp.h +--- linux-5.4.64/include/linux/tcp.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/linux/tcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -54,7 +54,7 @@ + /* TCP Fast Open */ + #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ + #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ +-#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ ++#define TCP_FASTOPEN_COOKIE_SIZE 4 /* the size employed by this impl. */ + + /* TCP Fast Open Cookie as stored in memory */ + struct tcp_fastopen_cookie { +@@ -74,6 +74,56 @@ + u32 end_seq; + }; + ++struct tcp_out_options { ++ u16 options; /* bit field of OPTION_* */ ++ u16 mss; /* 0 to disable */ ++ u8 ws; /* window scale, 0 to disable */ ++ u8 num_sack_blocks; /* number of SACK blocks to include */ ++ u8 hash_size; /* bytes in hash_location */ ++ __u8 *hash_location; /* temporary pointer, overloaded */ ++ __u32 tsval, tsecr; /* need to include OPTION_TS */ ++ struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ ++#ifdef CONFIG_MPTCP ++ u16 mptcp_options; /* bit field of MPTCP related OPTION_* */ ++ u8 dss_csum:1, /* dss-checksum required? */ ++ add_addr_v4:1, ++ add_addr_v6:1, ++ mptcp_ver:4; ++ ++ union { ++ struct { ++ __u64 sender_key; /* sender's key for mptcp */ ++ __u64 receiver_key; /* receiver's key for mptcp */ ++ } mp_capable; ++ ++ struct { ++ __u64 sender_truncated_mac; ++ __u32 sender_nonce; ++ /* random number of the sender */ ++ __u32 token; /* token for mptcp */ ++ u8 low_prio:1; ++ } mp_join_syns; ++ }; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr4; ++ ++ struct { ++ __u64 trunc_mac; ++ struct in6_addr addr; ++ u16 port; ++ u8 addr_id; ++ } add_addr6; ++ ++ u16 remove_addrs; /* list of address id */ ++ u8 addr_id; /* address id (mp_join or add_address) */ ++#endif /* CONFIG_MPTCP */ ++}; ++ + /*These are used to set the sack_ok field in struct tcp_options_received */ + #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ + #define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/ +@@ -97,6 +147,9 @@ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + }; + ++struct mptcp_cb; ++struct mptcp_tcp_sock; ++ + static inline void tcp_clear_options(struct tcp_options_received *rx_opt) + { + rx_opt->tstamp_ok = rx_opt->sack_ok = 0; +@@ -135,6 +188,8 @@ + return (struct tcp_request_sock *)req; + } + ++struct tcp_md5sig_key; ++ + struct tcp_sock { + /* inet_connection_sock has to be the first member of tcp_sock */ + struct inet_connection_sock inet_conn; +@@ -397,6 +452,44 @@ + */ + struct request_sock __rcu *fastopen_rsk; + u32 *saved_syn; ++ ++ /* MPTCP/TCP-specific callbacks */ ++ const struct tcp_sock_ops *ops; ++ ++ struct mptcp_cb *mpcb; ++ struct sock *meta_sk; ++ /* We keep these flags even if CONFIG_MPTCP is not checked, because ++ * it allows checking MPTCP capability just by checking the mpc flag, ++ * rather than adding ifdefs everywhere. ++ */ ++ u32 mpc:1, /* Other end is multipath capable */ ++ inside_tk_table:1, /* Is the tcp_sock inside the token-table? */ ++ send_mp_fclose:1, ++ request_mptcp:1, /* Did we send out an MP_CAPABLE? ++ * (this speeds up mptcp_doit() in tcp_recvmsg) ++ */ ++ pf:1, /* Potentially Failed state: when this flag is set, we ++ * stop using the subflow ++ */ ++ mp_killed:1, /* Killed with a tcp_done in mptcp? */ ++ is_master_sk:1, ++ close_it:1, /* Must close socket in mptcp_data_ready? */ ++ closing:1, ++ mptcp_ver:4, ++ mptcp_sched_setsockopt:1, ++ mptcp_pm_setsockopt:1, ++ record_master_info:1, ++ tcp_disconnect:1; ++ struct mptcp_tcp_sock *mptcp; ++#ifdef CONFIG_MPTCP ++#define MPTCP_SCHED_NAME_MAX 16 ++#define MPTCP_PM_NAME_MAX 16 ++ struct hlist_nulls_node tk_table; ++ u32 mptcp_loc_token; ++ u64 mptcp_loc_key; ++ char mptcp_sched_name[MPTCP_SCHED_NAME_MAX]; ++ char mptcp_pm_name[MPTCP_PM_NAME_MAX]; ++#endif /* CONFIG_MPTCP */ + }; + + enum tsq_enum { +@@ -408,6 +501,8 @@ + TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call + * tcp_v{4|6}_mtu_reduced() + */ ++ MPTCP_PATH_MANAGER_DEFERRED, /* MPTCP deferred creation of new subflows */ ++ MPTCP_SUB_DEFERRED, /* A subflow got deferred - process them */ + }; + + enum tsq_flags { +@@ -417,6 +512,8 @@ + TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED), + TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED), + TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED), ++ TCPF_PATH_MANAGER_DEFERRED = (1UL << MPTCP_PATH_MANAGER_DEFERRED), ++ TCPF_SUB_DEFERRED = (1UL << MPTCP_SUB_DEFERRED), + }; + + static inline struct tcp_sock *tcp_sk(const struct sock *sk) +@@ -440,6 +537,7 @@ + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *tw_md5_key; + #endif ++ struct mptcp_tw *mptcp_tw; + }; + + static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) +diff -aurN linux-5.4.64/include/net/inet_common.h linux-5.4.64.mptcp/include/net/inet_common.h +--- linux-5.4.64/include/net/inet_common.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/inet_common.h 2020-09-10 19:25:10.499221003 +0200 +@@ -2,6 +2,7 @@ + #ifndef _INET_COMMON_H + #define _INET_COMMON_H + ++#include + #include + + extern const struct proto_ops inet_stream_ops; +@@ -16,6 +17,8 @@ + struct sockaddr; + struct socket; + ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern); ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern); + int inet_release(struct socket *sock); + int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags); +diff -aurN linux-5.4.64/include/net/inet_connection_sock.h linux-5.4.64.mptcp/include/net/inet_connection_sock.h +--- linux-5.4.64/include/net/inet_connection_sock.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/inet_connection_sock.h 2020-09-10 19:25:10.499221003 +0200 +@@ -25,6 +25,7 @@ + + struct inet_bind_bucket; + struct tcp_congestion_ops; ++struct tcp_options_received; + + /* + * Pointers to address related TCP functions +diff -aurN linux-5.4.64/include/net/inet_sock.h linux-5.4.64.mptcp/include/net/inet_sock.h +--- linux-5.4.64/include/net/inet_sock.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/inet_sock.h 2020-09-10 19:25:10.499221003 +0200 +@@ -79,7 +79,7 @@ + #define ireq_state req.__req_common.skc_state + #define ireq_family req.__req_common.skc_family + +- u16 snd_wscale : 4, ++ u32 snd_wscale : 4, + rcv_wscale : 4, + tstamp_ok : 1, + sack_ok : 1, +@@ -87,6 +87,8 @@ + ecn_ok : 1, + acked : 1, + no_srccheck: 1, ++ mptcp_rqsk : 1, ++ saw_mpc : 1, + smc_ok : 1; + u32 ir_mark; + union { +diff -aurN linux-5.4.64/include/net/mptcp.h linux-5.4.64.mptcp/include/net/mptcp.h +--- linux-5.4.64/include/net/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/include/net/mptcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -0,0 +1,1571 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_H ++#define _MPTCP_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ #define ntohll(x) be64_to_cpu(x) ++ #define htonll(x) cpu_to_be64(x) ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ #define ntohll(x) (x) ++ #define htonll(x) (x) ++#endif ++ ++struct mptcp_loc4 { ++ u8 loc4_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in_addr addr; ++}; ++ ++struct mptcp_rem4 { ++ u8 rem4_id; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct mptcp_loc6 { ++ u8 loc6_id; ++ u8 low_prio:1; ++ int if_idx; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_rem6 { ++ u8 rem6_id; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_request_sock { ++ struct tcp_request_sock req; ++ struct hlist_nulls_node hash_entry; ++ ++ union { ++ struct { ++ /* Only on initial subflows */ ++ u64 mptcp_loc_key; ++ u64 mptcp_rem_key; ++ u32 mptcp_loc_token; ++ }; ++ ++ struct { ++ /* Only on additional subflows */ ++ u32 mptcp_rem_nonce; ++ u32 mptcp_loc_nonce; ++ u64 mptcp_hash_tmac; ++ }; ++ }; ++ ++ u8 loc_id; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u16 dss_csum:1, ++ rem_key_set:1, ++ is_sub:1, /* Is this a new subflow? */ ++ low_prio:1, /* Interface set to low-prio? */ ++ rcv_low_prio:1, ++ mptcp_ver:4; ++}; ++ ++struct mptcp_options_received { ++ u16 saw_mpc:1, ++ dss_csum:1, ++ drop_me:1, ++ ++ is_mp_join:1, ++ join_ack:1, ++ ++ saw_low_prio:2, /* 0x1 - low-prio set for this subflow ++ * 0x2 - low-prio set for another subflow ++ */ ++ low_prio:1, ++ ++ saw_add_addr:2, /* Saw at least one add_addr option: ++ * 0x1: IPv4 - 0x2: IPv6 ++ */ ++ more_add_addr:1, /* Saw one more add-addr. */ ++ ++ saw_rem_addr:1, /* Saw at least one rem_addr option */ ++ more_rem_addr:1, /* Saw one more rem-addr. */ ++ ++ mp_fail:1, ++ mp_fclose:1; ++ u8 rem_id; /* Address-id in the MP_JOIN */ ++ u8 prio_addr_id; /* Address-id in the MP_PRIO */ ++ ++ const unsigned char *add_addr_ptr; /* Pointer to add-address option */ ++ const unsigned char *rem_addr_ptr; /* Pointer to rem-address option */ ++ ++ u32 data_ack; ++ u32 data_seq; ++ u16 data_len; ++ ++ u8 mptcp_ver; /* MPTCP version */ ++ ++ /* Key inside the option (from mp_capable or fast_close) */ ++ u64 mptcp_sender_key; ++ u64 mptcp_receiver_key; ++ ++ u32 mptcp_rem_token; /* Remote token */ ++ ++ u32 mptcp_recv_nonce; ++ u64 mptcp_recv_tmac; ++ u8 mptcp_recv_mac[20]; ++}; ++ ++struct mptcp_tcp_sock { ++ struct hlist_node node; ++ struct hlist_node cb_list; ++ struct mptcp_options_received rx_opt; ++ ++ /* Those three fields record the current mapping */ ++ u64 map_data_seq; ++ u32 map_subseq; ++ u16 map_data_len; ++ u16 slave_sk:1, ++ fully_established:1, ++ second_packet:1, ++ attached:1, ++ send_mp_fail:1, ++ include_mpc:1, ++ mapping_present:1, ++ map_data_fin:1, ++ low_prio:1, /* use this socket as backup */ ++ rcv_low_prio:1, /* Peer sent low-prio option to us */ ++ send_mp_prio:1, /* Trigger to send mp_prio on this socket */ ++ pre_established:1; /* State between sending 3rd ACK and ++ * receiving the fourth ack of new subflows. ++ */ ++ ++ /* isn: needed to translate abs to relative subflow seqnums */ ++ u32 snt_isn; ++ u32 rcv_isn; ++ u8 path_index; ++ u8 loc_id; ++ u8 rem_id; ++ u8 sk_err; ++ ++#define MPTCP_SCHED_SIZE 16 ++ u8 mptcp_sched[MPTCP_SCHED_SIZE] __aligned(8); ++ ++ int init_rcv_wnd; ++ u32 infinite_cutoff_seq; ++ struct delayed_work work; ++ u32 mptcp_loc_nonce; ++ struct tcp_sock *tp; ++ u32 last_end_data_seq; ++ ++ /* MP_JOIN subflow: timer for retransmitting the 3rd ack */ ++ struct timer_list mptcp_ack_timer; ++ ++ /* HMAC of the third ack */ ++ char sender_mac[SHA256_DIGEST_SIZE]; ++}; ++ ++struct mptcp_tw { ++ struct list_head list; ++ u64 loc_key; ++ u64 rcv_nxt; ++ struct mptcp_cb __rcu *mpcb; ++ u8 meta_tw:1, ++ in_list:1; ++}; ++ ++#define MPTCP_PM_NAME_MAX 16 ++struct mptcp_pm_ops { ++ struct list_head list; ++ ++ /* Signal the creation of a new MPTCP-session. */ ++ void (*new_session)(const struct sock *meta_sk); ++ void (*release_sock)(struct sock *meta_sk); ++ void (*fully_established)(struct sock *meta_sk); ++ void (*close_session)(struct sock *meta_sk); ++ void (*new_remote_address)(struct sock *meta_sk); ++ int (*get_local_id)(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio); ++ void (*addr_signal)(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb); ++ void (*add_raddr)(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id); ++ void (*rem_raddr)(struct mptcp_cb *mpcb, u8 rem_id); ++ void (*init_subsocket_v4)(struct sock *sk, struct in_addr addr); ++ void (*init_subsocket_v6)(struct sock *sk, struct in6_addr addr); ++ void (*established_subflow)(struct sock *sk); ++ void (*delete_subflow)(struct sock *sk); ++ void (*prio_changed)(struct sock *sk, int low_prio); ++ ++ char name[MPTCP_PM_NAME_MAX]; ++ struct module *owner; ++}; ++ ++struct mptcp_sched_ops { ++ struct list_head list; ++ ++ struct sock * (*get_subflow)(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test); ++ struct sk_buff * (*next_segment)(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit); ++ void (*init)(struct sock *sk); ++ void (*release)(struct sock *sk); ++ ++ char name[MPTCP_SCHED_NAME_MAX]; ++ struct module *owner; ++}; ++ ++struct mptcp_cb { ++ /* list of sockets in this multipath connection */ ++ struct hlist_head conn_list; ++ /* list of sockets that need a call to release_cb */ ++ struct hlist_head callback_list; ++ ++ /* Lock used for protecting the different rcu-lists of mptcp_cb */ ++ spinlock_t mpcb_list_lock; ++ ++ /* High-order bits of 64-bit sequence numbers */ ++ u32 snd_high_order[2]; ++ u32 rcv_high_order[2]; ++ ++ u16 send_infinite_mapping:1, ++ send_mptcpv1_mpcapable:1, ++ rem_key_set:1, ++ in_time_wait:1, ++ list_rcvd:1, /* XXX TO REMOVE */ ++ addr_signal:1, /* Path-manager wants us to call addr_signal */ ++ dss_csum:1, ++ server_side:1, ++ infinite_mapping_rcv:1, ++ infinite_mapping_snd:1, ++ dfin_combined:1, /* Was the DFIN combined with subflow-fin? */ ++ passive_close:1, ++ snd_hiseq_index:1, /* Index in snd_high_order of snd_nxt */ ++ rcv_hiseq_index:1, /* Index in rcv_high_order of rcv_nxt */ ++ tcp_ca_explicit_set:1; /* was meta CC set by app? */ ++ ++#define MPTCP_SCHED_DATA_SIZE 8 ++ u8 mptcp_sched[MPTCP_SCHED_DATA_SIZE] __aligned(8); ++ const struct mptcp_sched_ops *sched_ops; ++ ++ struct sk_buff_head reinject_queue; ++ /* First cache-line boundary is here minus 8 bytes. But from the ++ * reinject-queue only the next and prev pointers are regularly ++ * accessed. Thus, the whole data-path is on a single cache-line. ++ */ ++ ++ u64 csum_cutoff_seq; ++ u64 infinite_rcv_seq; ++ ++ /***** Start of fields, used for connection closure */ ++ unsigned char mptw_state; ++ u8 dfin_path_index; ++ ++ struct list_head tw_list; ++ ++ /***** Start of fields, used for subflow establishment and closure */ ++ refcount_t mpcb_refcnt; ++ ++ /* Mutex needed, because otherwise mptcp_close will complain that the ++ * socket is owned by the user. ++ * E.g., mptcp_sub_close_wq is taking the meta-lock. ++ */ ++ struct mutex mpcb_mutex; ++ ++ /***** Start of fields, used for subflow establishment */ ++ struct sock *meta_sk; ++ ++ /* Master socket, also part of the conn_list, this ++ * socket is the one that the application sees. ++ */ ++ struct sock *master_sk; ++ ++ __u64 mptcp_loc_key; ++ __u64 mptcp_rem_key; ++ __u32 mptcp_loc_token; ++ __u32 mptcp_rem_token; ++ ++#define MPTCP_PM_SIZE 608 ++ u8 mptcp_pm[MPTCP_PM_SIZE] __aligned(8); ++ const struct mptcp_pm_ops *pm_ops; ++ ++ unsigned long path_index_bits; ++ ++ __u8 mptcp_ver; ++ ++ /* Original snd/rcvbuf of the initial subflow. ++ * Used for the new subflows on the server-side to allow correct ++ * autotuning ++ */ ++ int orig_sk_rcvbuf; ++ int orig_sk_sndbuf; ++ u32 orig_window_clamp; ++ ++ struct tcp_info *master_info; ++}; ++ ++#define MPTCP_VERSION_0 0 ++#define MPTCP_VERSION_1 1 ++ ++#define MPTCP_SUB_CAPABLE 0 ++#define MPTCP_SUB_LEN_CAPABLE_SYN 12 ++#define MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_CAPABLE_ACK 20 ++#define MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN 20 ++ ++#define MPTCPV1_SUB_LEN_CAPABLE_SYN 4 ++#define MPTCPV1_SUB_LEN_CAPABLE_SYN_ALIGN 4 ++#define MPTCPV1_SUB_LEN_CAPABLE_SYNACK 12 ++#define MPTCPV1_SUB_LEN_CAPABLE_SYNACK_ALIGN 12 ++#define MPTCPV1_SUB_LEN_CAPABLE_ACK 20 ++#define MPTCPV1_SUB_LEN_CAPABLE_ACK_ALIGN 20 ++#define MPTCPV1_SUB_LEN_CAPABLE_DATA 22 ++#define MPTCPV1_SUB_LEN_CAPABLE_DATA_CSUM 22 ++#define MPTCPV1_SUB_LEN_CAPABLE_DATA_ALIGN 24 ++ ++#define MPTCP_SUB_JOIN 1 ++#define MPTCP_SUB_LEN_JOIN_SYN 12 ++#define MPTCP_SUB_LEN_JOIN_SYN_ALIGN 12 ++#define MPTCP_SUB_LEN_JOIN_SYNACK 16 ++#define MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN 16 ++#define MPTCP_SUB_LEN_JOIN_ACK 24 ++#define MPTCP_SUB_LEN_JOIN_ACK_ALIGN 24 ++ ++#define MPTCP_SUB_DSS 2 ++#define MPTCP_SUB_LEN_DSS 4 ++#define MPTCP_SUB_LEN_DSS_ALIGN 4 ++ ++/* Lengths for seq and ack are the ones without the generic MPTCP-option header, ++ * as they are part of the DSS-option. ++ * To get the total length, just add the different options together. ++ */ ++#define MPTCP_SUB_LEN_SEQ 10 ++#define MPTCP_SUB_LEN_SEQ_CSUM 12 ++#define MPTCP_SUB_LEN_SEQ_ALIGN 12 ++ ++#define MPTCP_SUB_LEN_SEQ_64 14 ++#define MPTCP_SUB_LEN_SEQ_CSUM_64 16 ++#define MPTCP_SUB_LEN_SEQ_64_ALIGN 16 ++ ++#define MPTCP_SUB_LEN_ACK 4 ++#define MPTCP_SUB_LEN_ACK_ALIGN 4 ++ ++#define MPTCP_SUB_LEN_ACK_64 8 ++#define MPTCP_SUB_LEN_ACK_64_ALIGN 8 ++ ++/* This is the "default" option-length we will send out most often. ++ * MPTCP DSS-header ++ * 32-bit data sequence number ++ * 32-bit data ack ++ * ++ * It is necessary to calculate the effective MSS we will be using when ++ * sending data. ++ */ ++#define MPTCP_SUB_LEN_DSM_ALIGN (MPTCP_SUB_LEN_DSS_ALIGN + \ ++ MPTCP_SUB_LEN_SEQ_ALIGN + \ ++ MPTCP_SUB_LEN_ACK_ALIGN) ++ ++#define MPTCP_SUB_ADD_ADDR 3 ++#define MPTCP_SUB_LEN_ADD_ADDR4 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_VER1 28 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN 8 ++#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 16 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN 20 ++#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 28 ++ ++#define MPTCP_SUB_REMOVE_ADDR 4 ++#define MPTCP_SUB_LEN_REMOVE_ADDR 4 ++ ++#define MPTCP_SUB_PRIO 5 ++#define MPTCP_SUB_LEN_PRIO 3 ++#define MPTCP_SUB_LEN_PRIO_ADDR 4 ++#define MPTCP_SUB_LEN_PRIO_ALIGN 4 ++ ++#define MPTCP_SUB_FAIL 6 ++#define MPTCP_SUB_LEN_FAIL 12 ++#define MPTCP_SUB_LEN_FAIL_ALIGN 12 ++ ++#define MPTCP_SUB_FCLOSE 7 ++#define MPTCP_SUB_LEN_FCLOSE 12 ++#define MPTCP_SUB_LEN_FCLOSE_ALIGN 12 ++ ++ ++#define OPTION_MPTCP (1 << 5) ++ ++/* Max number of fastclose retransmissions */ ++#define MPTCP_FASTCLOSE_RETRIES 3 ++ ++#ifdef CONFIG_MPTCP ++ ++/* Used for checking if the mptcp initialization has been successful */ ++extern bool mptcp_init_failed; ++ ++/* MPTCP options */ ++#define OPTION_TYPE_SYN (1 << 0) ++#define OPTION_TYPE_SYNACK (1 << 1) ++#define OPTION_TYPE_ACK (1 << 2) ++#define OPTION_MP_CAPABLE (1 << 3) ++#define OPTION_DATA_ACK (1 << 4) ++#define OPTION_ADD_ADDR (1 << 5) ++#define OPTION_MP_JOIN (1 << 6) ++#define OPTION_MP_FAIL (1 << 7) ++#define OPTION_MP_FCLOSE (1 << 8) ++#define OPTION_REMOVE_ADDR (1 << 9) ++#define OPTION_MP_PRIO (1 << 10) ++ ++/* MPTCP flags: both TX and RX */ ++#define MPTCPHDR_SEQ 0x01 /* DSS.M option is present */ ++#define MPTCPHDR_FIN 0x02 /* DSS.F option is present */ ++#define MPTCPHDR_SEQ64_INDEX 0x04 /* index of seq in mpcb->snd_high_order */ ++#define MPTCPHDR_MPC_DATA 0x08 ++/* MPTCP flags: RX only */ ++#define MPTCPHDR_ACK 0x10 ++#define MPTCPHDR_SEQ64_SET 0x20 /* Did we received a 64-bit seq number? */ ++#define MPTCPHDR_SEQ64_OFO 0x40 /* Is it not in our circular array? */ ++#define MPTCPHDR_DSS_CSUM 0x80 ++/* MPTCP flags: TX only */ ++#define MPTCPHDR_INF 0x10 ++#define MPTCP_REINJECT 0x20 /* Did we reinject this segment? */ ++ ++struct mptcp_option { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_capable { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ver:4, ++ sub:4; ++ __u8 h:1, ++ rsv:5, ++ b:1, ++ a:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ ver:4; ++ __u8 a:1, ++ b:1, ++ rsv:5, ++ h:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 sender_key; ++ __u64 receiver_key; ++} __attribute__((__packed__)); ++ ++struct mp_join { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ u32 token; ++ u32 nonce; ++ } syn; ++ struct { ++ __u64 mac; ++ u32 nonce; ++ } synack; ++ struct { ++ __u8 mac[20]; ++ } ack; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_dss { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ A:1, ++ a:1, ++ M:1, ++ m:1, ++ F:1, ++ rsv2:3; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:3, ++ F:1, ++ m:1, ++ M:1, ++ a:1, ++ A:1; ++#else ++#error "Adjust your defines" ++#endif ++}; ++ ++struct mp_add_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ union { ++ struct { ++ __u8 ipver:4, ++ sub:4; ++ } v0; ++ struct { ++ __u8 echo:1, ++ rsv:3, ++ sub:4; ++ } v1; ++ } u_bit; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ union { ++ struct { ++ __u8 sub:4, ++ ipver:4; ++ } v0; ++ struct { ++ __u8 sub:4, ++ rsv:3, ++ echo:1; ++ } v1; ++ } u_bit; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++ union { ++ struct { ++ struct in_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v4; ++ struct { ++ struct in6_addr addr; ++ __be16 port; ++ __u8 mac[8]; ++ } v6; ++ } u; ++} __attribute__((__packed__)); ++ ++struct mp_remove_addr { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 rsv:4, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:4; ++#else ++#error "Adjust your defines" ++#endif ++ /* list of addr_id */ ++ __u8 addrs_id; ++}; ++ ++struct mp_fail { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __be64 data_seq; ++} __attribute__((__packed__)); ++ ++struct mp_fclose { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rsv1:4, ++ sub:4, ++ rsv2:8; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 sub:4, ++ rsv1:4, ++ rsv2:8; ++#else ++#error "Adjust your defines" ++#endif ++ __u64 key; ++} __attribute__((__packed__)); ++ ++struct mp_prio { ++ __u8 kind; ++ __u8 len; ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 b:1, ++ rsv:3, ++ sub:4; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u8 sub:4, ++ rsv:3, ++ b:1; ++#else ++#error "Adjust your defines" ++#endif ++ __u8 addr_id; ++} __attribute__((__packed__)); ++ ++struct mptcp_hashtable { ++ struct hlist_nulls_head *hashtable; ++ unsigned int mask; ++}; ++ ++static inline int mptcp_sub_len_dss(const struct mp_dss *m, const int csum) ++{ ++ return 4 + m->A * (4 + m->a * 4) + m->M * (10 + m->m * 4 + csum * 2); ++} ++ ++#define MPTCP_ENABLE 0x01 ++#define MPTCP_SOCKOPT 0x02 ++#define MPTCP_CLIENT_DISABLE 0x04 ++#define MPTCP_SERVER_DISABLE 0x08 ++ ++extern int sysctl_mptcp_enabled; ++extern int sysctl_mptcp_version; ++extern int sysctl_mptcp_checksum; ++extern int sysctl_mptcp_debug; ++extern int sysctl_mptcp_syn_retries; ++ ++extern struct workqueue_struct *mptcp_wq; ++ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ if (unlikely(sysctl_mptcp_debug)) \ ++ pr_err(fmt, ##args); \ ++ } while (0) ++ ++static inline struct sock *mptcp_to_sock(const struct mptcp_tcp_sock *mptcp) ++{ ++ return (struct sock *)mptcp->tp; ++} ++ ++#define mptcp_for_each_sub(__mpcb, __mptcp) \ ++ hlist_for_each_entry_rcu(__mptcp, &((__mpcb)->conn_list), node) ++ ++/* Must be called with the appropriate lock held */ ++#define mptcp_for_each_sub_safe(__mpcb, __mptcp, __tmp) \ ++ hlist_for_each_entry_safe(__mptcp, __tmp, &((__mpcb)->conn_list), node) ++ ++/* Iterates over all bit set to 1 in a bitset */ ++#define mptcp_for_each_bit_set(b, i) \ ++ for (i = ffs(b) - 1; i >= 0; i = ffs(b >> (i + 1) << (i + 1)) - 1) ++ ++#define mptcp_for_each_bit_unset(b, i) \ ++ mptcp_for_each_bit_set(~b, i) ++ ++#define MPTCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++#define MPTCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mptcp.mptcp_statistics, field) ++#define MPTCP_INC_STATS_BH(net, field) __SNMP_INC_STATS((net)->mptcp.mptcp_statistics, field) ++ ++enum ++{ ++ MPTCP_MIB_NUM = 0, ++ MPTCP_MIB_MPCAPABLEPASSIVE, /* Received SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVE, /* Sent SYN with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEACTIVEACK, /* Received SYN/ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */ ++ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */ ++ MPTCP_MIB_MPCAPABLERETRANSFALLBACK,/* Client-side stopped sending MP_CAPABLE after too many SYN-retransmissions */ ++ MPTCP_MIB_CSUMENABLED, /* Created MPTCP-connection with DSS-checksum enabled */ ++ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ ++ MPTCP_MIB_MPFAILRX, /* Received an MP_FAIL */ ++ MPTCP_MIB_CSUMFAIL, /* Received segment with invalid checksum */ ++ MPTCP_MIB_FASTCLOSERX, /* Recevied a FAST_CLOSE */ ++ MPTCP_MIB_FASTCLOSETX, /* Sent a FAST_CLOSE */ ++ MPTCP_MIB_FBACKSUB, /* Fallback upon ack without data-ack on new subflow */ ++ MPTCP_MIB_FBACKINIT, /* Fallback upon ack without data-ack on initial subflow */ ++ MPTCP_MIB_FBDATASUB, /* Fallback upon data without DSS at the beginning on new subflow */ ++ MPTCP_MIB_FBDATAINIT, /* Fallback upon data without DSS at the beginning on initial subflow */ ++ MPTCP_MIB_REMADDRSUB, /* Remove subflow due to REMOVE_ADDR */ ++ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ ++ MPTCP_MIB_JOINFALLBACK, /* Received MP_JOIN on session that has fallen back to reg. TCP */ ++ MPTCP_MIB_JOINSYNTX, /* Sent a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNRX, /* Received a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKRX, /* Received a SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */ ++ MPTCP_MIB_JOINACKFAIL, /* Third ACK on new subflow did not contain an MP_JOIN */ ++ MPTCP_MIB_JOINACKRTO, /* Retransmission timer for third ACK + MP_JOIN timed out */ ++ MPTCP_MIB_JOINACKRXMIT, /* Retransmitted an ACK + MP_JOIN */ ++ MPTCP_MIB_NODSSWINDOW, /* Received too many packets without a DSS-option */ ++ MPTCP_MIB_DSSNOMATCH, /* Received a new mapping that did not match the previous one */ ++ MPTCP_MIB_INFINITEMAPRX, /* Received an infinite mapping */ ++ MPTCP_MIB_DSSTCPMISMATCH, /* DSS-mapping did not map with TCP's sequence numbers */ ++ MPTCP_MIB_DSSTRIMHEAD, /* Trimmed segment at the head (coalescing middlebox) */ ++ MPTCP_MIB_DSSSPLITTAIL, /* Trimmed segment at the tail (coalescing middlebox) */ ++ MPTCP_MIB_PURGEOLD, /* Removed old skb from the rcv-queue due to missing DSS-mapping */ ++ MPTCP_MIB_ADDADDRRX, /* Received an ADD_ADDR */ ++ MPTCP_MIB_ADDADDRTX, /* Sent an ADD_ADDR */ ++ MPTCP_MIB_REMADDRRX, /* Received a REMOVE_ADDR */ ++ MPTCP_MIB_REMADDRTX, /* Sent a REMOVE_ADDR */ ++ MPTCP_MIB_JOINALTERNATEPORT, /* Established a subflow on a different destination port-number */ ++ MPTCP_MIB_CURRESTAB, /* Current established MPTCP connections */ ++ __MPTCP_MIB_MAX ++}; ++ ++#define MPTCP_MIB_MAX __MPTCP_MIB_MAX ++struct mptcp_mib { ++ unsigned long mibs[MPTCP_MIB_MAX]; ++}; ++ ++extern struct lock_class_key meta_key; ++extern char *meta_key_name; ++extern struct lock_class_key meta_slock_key; ++extern char *meta_slock_key_name; ++ ++extern siphash_key_t mptcp_secret; ++ ++/* This is needed to ensure that two subsequent key/nonce-generation result in ++ * different keys/nonces if the IPs and ports are the same. ++ */ ++extern u32 mptcp_seed; ++ ++extern struct mptcp_hashtable mptcp_tk_htable; ++ ++/* Request-sockets can be hashed in the tk_htb for collision-detection or in ++ * the regular htb for join-connections. We need to define different NULLS ++ * values so that we can correctly detect a request-socket that has been ++ * recycled. See also c25eb3bfb9729. ++ */ ++#define MPTCP_REQSK_NULLS_BASE (1U << 29) ++ ++ ++void mptcp_data_ready(struct sock *sk); ++void mptcp_write_space(struct sock *sk); ++ ++void mptcp_add_meta_ofo_queue(const struct sock *meta_sk, struct sk_buff *skb, ++ struct sock *sk); ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied); ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags); ++void mptcp_del_sock(struct sock *sk); ++void mptcp_update_metasocket(const struct sock *meta_sk); ++void mptcp_reinject_data(struct sock *orig_sk, int clone_it); ++void mptcp_update_sndbuf(const struct tcp_sock *tp); ++void mptcp_send_fin(struct sock *meta_sk); ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority); ++bool mptcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt); ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp); ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining); ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size); ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb); ++void mptcp_close(struct sock *meta_sk, long timeout); ++bool mptcp_doit(struct sock *sk); ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ int rem_key_set, __u8 mptcp_ver, u32 window); ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req); ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ int drop, u32 tsoff); ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++u32 __mptcp_select_window(struct sock *sk); ++void mptcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, ++ __u32 *rcv_wnd, __u32 *window_clamp, ++ int wscale_ok, __u8 *rcv_wscale, ++ __u32 init_rcv_wnd); ++unsigned int mptcp_current_mss(struct sock *meta_sk); ++void mptcp_hmac(u8 ver, const u8 *key_1, const u8 *key_2, u8 *hash_out, ++ int arg_num, ...); ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk); ++void mptcp_fin(struct sock *meta_sk); ++void mptcp_meta_retransmit_timer(struct sock *meta_sk); ++void mptcp_sub_retransmit_timer(struct sock *sk); ++int mptcp_write_wakeup(struct sock *meta_sk, int mib); ++void mptcp_sub_close_wq(struct work_struct *work); ++void mptcp_sub_close(struct sock *sk, unsigned long delay); ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk); ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb); ++void mptcp_initialize_recv_vars(struct tcp_sock *meta_tp, struct mptcp_cb *mpcb, ++ __u64 remote_key); ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_ack_handler(struct timer_list *t); ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time); ++int mptcp_check_snd_buf(const struct tcp_sock *tp); ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb); ++void __init mptcp_init(void); ++void mptcp_destroy_sock(struct sock *sk); ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt); ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed); ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw); ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw); ++void mptcp_time_wait(struct sock *sk, int state, int timeo); ++void mptcp_disconnect(struct sock *meta_sk); ++bool mptcp_should_expand_sndbuf(const struct sock *sk); ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb); ++void mptcp_tsq_flags(struct sock *sk); ++void mptcp_tsq_sub_deferred(struct sock *meta_sk); ++struct mp_join *mptcp_find_join(const struct sk_buff *skb); ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp); ++struct sock *mptcp_hash_find(const struct net *net, const u32 token); ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw); ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net); ++void mptcp_reqsk_destructor(struct request_sock *req); ++void mptcp_connect_init(struct sock *sk); ++void mptcp_sub_force_close(struct sock *sk); ++int mptcp_sub_len_remove_addr_align(u16 bitfield); ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb); ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie); ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb); ++void mptcp_enable_sock(struct sock *sk); ++void mptcp_disable_sock(struct sock *sk); ++void mptcp_disable_static_key(void); ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb); ++void mptcp_mpcb_put(struct mptcp_cb *mpcb); ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb); ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen); ++void mptcp_clear_sk(struct sock *sk, int size); ++ ++/* MPTCP-path-manager registration/initialization functions */ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm); ++void mptcp_init_path_manager(struct mptcp_cb *mpcb); ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb); ++void mptcp_fallback_default(struct mptcp_cb *mpcb); ++void mptcp_get_default_path_manager(char *name); ++int mptcp_set_scheduler(struct sock *sk, const char *name); ++int mptcp_set_path_manager(struct sock *sk, const char *name); ++int mptcp_set_default_path_manager(const char *name); ++extern struct mptcp_pm_ops mptcp_pm_default; ++ ++/* MPTCP-scheduler registration/initialization functions */ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched); ++void mptcp_init_scheduler(struct mptcp_cb *mpcb); ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb); ++void mptcp_get_default_scheduler(char *name); ++int mptcp_set_default_scheduler(const char *name); ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test); ++bool mptcp_is_def_unavailable(struct sock *sk); ++bool subflow_is_active(const struct tcp_sock *tp); ++bool subflow_is_backup(const struct tcp_sock *tp); ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test); ++struct sk_buff *mptcp_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit); ++extern struct mptcp_sched_ops mptcp_sched_default; ++ ++/* Initializes function-pointers and MPTCP-flags */ ++static inline void mptcp_init_tcp_sock(struct sock *sk) ++{ ++ if (!mptcp_init_failed && sysctl_mptcp_enabled == MPTCP_ENABLE) ++ mptcp_enable_sock(sk); ++} ++ ++static inline void mptcp_init_listen(struct sock *sk) ++{ ++ if (!mptcp_init_failed && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ sysctl_mptcp_enabled & MPTCP_ENABLE && ++ !(sysctl_mptcp_enabled & MPTCP_SERVER_DISABLE)) ++ mptcp_enable_sock(sk); ++} ++ ++static inline void mptcp_init_connect(struct sock *sk) ++{ ++ if (!mptcp_init_failed && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ sysctl_mptcp_enabled & MPTCP_ENABLE && ++ !(sysctl_mptcp_enabled & MPTCP_CLIENT_DISABLE)) ++ mptcp_enable_sock(sk); ++} ++ ++static inline int mptcp_pi_to_flag(int pi) ++{ ++ return 1 << (pi - 1); ++} ++ ++static inline ++struct mptcp_request_sock *mptcp_rsk(const struct request_sock *req) ++{ ++ return (struct mptcp_request_sock *)req; ++} ++ ++static inline ++struct request_sock *rev_mptcp_rsk(const struct mptcp_request_sock *req) ++{ ++ return (struct request_sock *)req; ++} ++ ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (tcp_sk(sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (!(sk_it->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) ++{ ++ /* We check packets out and send-head here. TCP only checks the ++ * send-head. But, MPTCP also checks packets_out, as this is an ++ * indication that we might want to do opportunistic reinjection. ++ */ ++ if (tcp_sk(meta_sk)->packets_out || tcp_send_head(meta_sk)) { ++ struct tcp_sock *tp = tcp_sk(meta_sk); ++ ++ /* We don't care about the MSS, because it will be set in ++ * mptcp_write_xmit. ++ */ ++ __tcp_push_pending_frames(meta_sk, 0, tp->nonagle); ++ } ++} ++ ++static inline void mptcp_send_reset(struct sock *sk) ++{ ++ if (tcp_need_reset(sk->sk_state)) ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); ++ mptcp_sub_force_close(sk); ++} ++ ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it != except) ++ mptcp_send_reset(sk_it); ++ } ++} ++ ++static inline bool mptcp_is_data_mpcapable(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_MPC_DATA; ++} ++ ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ; ++} ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_FIN; ++} ++ ++/* Is it a data-fin while in infinite mapping mode? ++ * In infinite mode, a subflow-fin is in fact a data-fin. ++ */ ++static inline bool mptcp_is_data_fin2(const struct sk_buff *skb, ++ const struct tcp_sock *tp) ++{ ++ return mptcp_is_data_fin(skb) || ++ (tp->mpcb->infinite_mapping_rcv && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)); ++} ++ ++static inline u8 mptcp_get_64_bit(u64 data_seq, struct mptcp_cb *mpcb) ++{ ++ u64 data_seq_high = (u32)(data_seq >> 32); ++ ++ if (mpcb->rcv_high_order[0] == data_seq_high) ++ return 0; ++ else if (mpcb->rcv_high_order[1] == data_seq_high) ++ return MPTCPHDR_SEQ64_INDEX; ++ else ++ return MPTCPHDR_SEQ64_OFO; ++} ++ ++/* Sets the data_seq and returns pointer to the in-skb field of the data_seq. ++ * If the packet has a 64-bit dseq, the pointer points to the last 32 bits. ++ */ ++static inline __u32 *mptcp_skb_set_data_seq(const struct sk_buff *skb, ++ u32 *data_seq, ++ struct mptcp_cb *mpcb) ++{ ++ __u32 *ptr = (__u32 *)(skb_transport_header(skb) + TCP_SKB_CB(skb)->dss_off); ++ ++ if (TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_SEQ64_SET) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ if (mpcb) ++ TCP_SKB_CB(skb)->mptcp_flags |= mptcp_get_64_bit(data_seq64, mpcb); ++ ++ *data_seq = (u32)data_seq64; ++ ptr++; ++ } else { ++ *data_seq = get_unaligned_be32(ptr); ++ } ++ ++ return ptr; ++} ++ ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return tcp_sk(sk)->meta_sk; ++} ++ ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return tcp_sk(tp->meta_sk); ++} ++ ++static inline int is_meta_tp(const struct tcp_sock *tp) ++{ ++ return tp->mpcb && mptcp_meta_tp(tp) == tp; ++} ++ ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return sk->sk_state != TCP_NEW_SYN_RECV && ++ sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP && ++ mptcp(tcp_sk(sk)) && mptcp_meta_sk(sk) == sk; ++} ++ ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return !mptcp(tp) || (!tp->mptcp->slave_sk && !is_meta_tp(tp)); ++} ++ ++static inline void mptcp_init_mp_opt(struct mptcp_options_received *mopt) ++{ ++ mopt->saw_mpc = 0; ++ mopt->dss_csum = 0; ++ mopt->drop_me = 0; ++ ++ mopt->is_mp_join = 0; ++ mopt->join_ack = 0; ++ ++ mopt->saw_low_prio = 0; ++ mopt->low_prio = 0; ++ ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) ++{ ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ ++ mopt->saw_low_prio = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_add_addr = 0; ++ mopt->saw_rem_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->join_ack = 0; ++ mopt->mp_fail = 0; ++ mopt->mp_fclose = 0; ++} ++ ++static inline __be32 mptcp_get_highorder_sndbits(const struct sk_buff *skb, ++ const struct mptcp_cb *mpcb) ++{ ++ return htonl(mpcb->snd_high_order[(TCP_SKB_CB(skb)->mptcp_flags & ++ MPTCPHDR_SEQ64_INDEX) ? 1 : 0]); ++} ++ ++static inline u64 mptcp_get_data_seq_64(const struct mptcp_cb *mpcb, int index, ++ u32 data_seq_32) ++{ ++ return ((u64)mpcb->rcv_high_order[index] << 32) | data_seq_32; ++} ++ ++static inline u64 mptcp_get_rcv_nxt_64(const struct tcp_sock *meta_tp) ++{ ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ return mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_nxt); ++} ++ ++static inline void mptcp_check_sndseq_wrap(struct tcp_sock *meta_tp, int inc) ++{ ++ if (unlikely(meta_tp->snd_nxt > meta_tp->snd_nxt + inc)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] += 2; ++ } ++} ++ ++static inline void mptcp_check_rcvseq_wrap(struct tcp_sock *meta_tp, ++ u32 old_rcv_nxt) ++{ ++ if (unlikely(old_rcv_nxt > meta_tp->rcv_nxt)) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ mpcb->rcv_high_order[mpcb->rcv_hiseq_index] += 2; ++ mpcb->rcv_hiseq_index = mpcb->rcv_hiseq_index ? 0 : 1; ++ } ++} ++ ++static inline int mptcp_sk_can_send(const struct sock *sk) ++{ ++ return tcp_passive_fastopen(sk) || ++ ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && ++ !tcp_sk(sk)->mptcp->pre_established); ++} ++ ++static inline int mptcp_sk_can_recv(const struct sock *sk) ++{ ++ return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2); ++} ++ ++static inline int mptcp_sk_can_send_ack(const struct sock *sk) ++{ ++ return !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | ++ TCPF_CLOSE | TCPF_LISTEN)) && ++ !tcp_sk(sk)->mptcp->pre_established; ++} ++ ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (tcp_sk(meta_sk)->mpcb->dss_csum) ++ return false; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ if (!(sk->sk_route_caps & NETIF_F_SG)) ++ return false; ++ } ++ return true; ++} ++ ++static inline void mptcp_set_rto(struct sock *sk) ++{ ++ struct inet_connection_sock *micsk = inet_csk(mptcp_meta_sk(sk)); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ __u32 max_rto = 0; ++ ++ /* We are in recovery-phase on the MPTCP-level. Do not update the ++ * RTO, because this would kill exponential backoff. ++ */ ++ if (micsk->icsk_retransmits) ++ return; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if ((mptcp_sk_can_send(sk_it) || sk_it->sk_state == TCP_SYN_RECV) && ++ inet_csk(sk_it)->icsk_retransmits == 0 && ++ inet_csk(sk_it)->icsk_backoff == 0 && ++ inet_csk(sk_it)->icsk_rto > max_rto) ++ max_rto = inet_csk(sk_it)->icsk_rto; ++ } ++ if (max_rto) { ++ micsk->icsk_rto = max_rto << 1; ++ ++ /* A successfull rto-measurement - reset backoff counter */ ++ micsk->icsk_backoff = 0; ++ } ++} ++ ++static inline void mptcp_sub_close_passive(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(meta_sk); ++ ++ /* Only close, if the app did a send-shutdown (passive close), and we ++ * received the data-ack of the data-fin. ++ */ ++ if (tp->mpcb->passive_close && meta_tp->snd_una == meta_tp->write_seq) ++ mptcp_sub_close(sk, 0); ++} ++ ++static inline void mptcp_fallback_close(struct mptcp_cb *mpcb, ++ struct sock *except) ++{ ++ mptcp_sub_force_close_all(mpcb, except); ++ ++ if (mpcb->pm_ops->close_session) ++ mpcb->pm_ops->close_session(mptcp_meta_sk(except)); ++} ++ ++static inline bool mptcp_fallback_infinite(struct sock *sk, int flag) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If data has been acknowleged on the meta-level, fully_established ++ * will have been set before and thus we will not fall back to infinite ++ * mapping. ++ */ ++ if (likely(tp->mptcp->fully_established)) ++ return false; ++ ++ if (!(flag & MPTCP_FLAG_DATA_ACKED)) ++ return false; ++ ++ /* Don't fallback twice ;) */ ++ if (mpcb->infinite_mapping_snd) ++ return false; ++ ++ pr_debug("%s %#x will fallback - pi %d, src %pI4:%u dst %pI4:%u rcv_nxt %u from %pS\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ &inet_sk(sk)->inet_saddr, ntohs(inet_sk(sk)->inet_sport), ++ &inet_sk(sk)->inet_daddr, ntohs(inet_sk(sk)->inet_dport), ++ tp->rcv_nxt, __builtin_return_address(0)); ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKSUB); ++ return true; ++ } ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ tp->mptcp->fully_established = 1; ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBACKINIT); ++ ++ return false; ++} ++ ++static inline bool mptcp_v6_is_v4_mapped(const struct sock *sk) ++{ ++ return sk->sk_family == AF_INET6 && ++ ipv6_addr_type(&inet6_sk(sk)->saddr) == IPV6_ADDR_MAPPED; ++} ++ ++/* We are in or are becoming to be in infinite mapping mode */ ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return mpcb->infinite_mapping_rcv || ++ mpcb->infinite_mapping_snd || ++ mpcb->send_infinite_mapping; ++} ++ ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ /* Has been removed from the tk-table. Thus, no new subflows. ++ * ++ * Check for close-state is necessary, because we may have been closed ++ * without passing by mptcp_close(). ++ * ++ * When falling back, no new subflows are allowed either. ++ */ ++ return meta_sk->sk_state != TCP_CLOSE && ++ tcp_sk(meta_sk)->inside_tk_table && ++ !tcp_sk(meta_sk)->mpcb->infinite_mapping_rcv && ++ !tcp_sk(meta_sk)->mpcb->send_infinite_mapping; ++} ++ ++static inline int mptcp_subflow_count(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ int i = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) ++ i++; ++ ++ return i; ++} ++ ++/* TCP and MPTCP mpc flag-depending functions */ ++u16 mptcp_select_window(struct sock *sk); ++void mptcp_tcp_set_rto(struct sock *sk); ++ ++/* TCP and MPTCP flag-depending functions */ ++bool mptcp_prune_ofo_queue(struct sock *sk); ++ ++#else /* CONFIG_MPTCP */ ++#define mptcp_debug(fmt, args...) \ ++ do { \ ++ } while (0) ++ ++static inline struct sock *mptcp_to_sock(const struct mptcp_tcp_sock *mptcp) ++{ ++ return NULL; ++} ++ ++#define mptcp_for_each_sub(__mpcb, __mptcp) \ ++ if (0) ++ ++#define MPTCP_INC_STATS(net, field) \ ++ do { \ ++ } while(0) ++ ++static inline bool mptcp_is_data_fin(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline bool mptcp_is_data_seq(const struct sk_buff *skb) ++{ ++ return false; ++} ++static inline struct sock *mptcp_meta_sk(const struct sock *sk) ++{ ++ return NULL; ++} ++static inline struct tcp_sock *mptcp_meta_tp(const struct tcp_sock *tp) ++{ ++ return NULL; ++} ++static inline int is_meta_sk(const struct sock *sk) ++{ ++ return 0; ++} ++static inline int is_master_tp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_del_sock(const struct sock *sk) {} ++static inline void mptcp_update_metasocket(const struct sock *meta_sk) {} ++static inline void mptcp_reinject_data(struct sock *orig_sk, int clone_it) {} ++static inline void mptcp_update_sndbuf(const struct tcp_sock *tp) {} ++static inline void mptcp_clean_rtx_infinite(const struct sk_buff *skb, ++ const struct sock *sk) {} ++static inline void mptcp_sub_close(struct sock *sk, unsigned long delay) {} ++static inline void mptcp_set_rto(const struct sock *sk) {} ++static inline void mptcp_send_fin(const struct sock *meta_sk) {} ++static inline void mptcp_parse_options(const uint8_t *ptr, const int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ const struct tcp_sock *tp) {} ++static inline void mptcp_syn_options(const struct sock *sk, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++static inline void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, ++ unsigned *remaining) {} ++ ++static inline void mptcp_established_options(struct sock *sk, ++ struct sk_buff *skb, ++ struct tcp_out_options *opts, ++ unsigned *size) {} ++static inline void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) {} ++static inline void mptcp_close(struct sock *meta_sk, long timeout) {} ++static inline bool mptcp_doit(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_check_req_fastopen(struct sock *child, ++ struct request_sock *req) ++{ ++ return 1; ++} ++static inline int mptcp_check_req_master(const struct sock *sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ int drop, ++ u32 tsoff) ++{ ++ return 1; ++} ++static inline struct sock *mptcp_check_req_child(const struct sock *meta_sk, ++ const struct sock *child, ++ const struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return NULL; ++} ++static inline unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ return 0; ++} ++static inline void mptcp_sub_close_passive(struct sock *sk) {} ++static inline bool mptcp_fallback_infinite(const struct sock *sk, int flag) ++{ ++ return false; ++} ++static inline void mptcp_init_mp_opt(const struct mptcp_options_received *mopt) {} ++static inline void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) {} ++static inline bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ return false; ++} ++static inline int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++static inline void mptcp_push_pending_frames(struct sock *meta_sk) {} ++static inline void mptcp_send_reset(const struct sock *sk) {} ++static inline void mptcp_sub_force_close_all(struct mptcp_cb *mpcb, ++ struct sock *except) {} ++static inline bool mptcp_handle_options(struct sock *sk, ++ const struct tcphdr *th, ++ struct sk_buff *skb) ++{ ++ return false; ++} ++static inline void mptcp_reset_mopt(struct tcp_sock *tp) {} ++static inline void __init mptcp_init(void) {} ++static inline bool mptcp_can_sg(const struct sock *meta_sk) ++{ ++ return false; ++} ++static inline unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, ++ u32 mss_now, int large_allowed) ++{ ++ return 0; ++} ++static inline void mptcp_destroy_sock(struct sock *sk) {} ++static inline int mptcp_rcv_synsent_state_process(struct sock *sk, ++ struct sock **skptr, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ return 0; ++} ++static inline bool mptcp_can_sendpage(struct sock *sk) ++{ ++ return false; ++} ++static inline int mptcp_init_tw_sock(struct sock *sk, ++ struct tcp_timewait_sock *tw) ++{ ++ return 0; ++} ++static inline void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) {} ++static inline void mptcp_disconnect(struct sock *meta_sk) {} ++static inline void mptcp_tsq_flags(struct sock *sk) {} ++static inline void mptcp_tsq_sub_deferred(struct sock *meta_sk) {} ++static inline void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) {} ++static inline void mptcp_remove_shortcuts(const struct mptcp_cb *mpcb, ++ const struct sk_buff *skb) {} ++static inline void mptcp_init_tcp_sock(struct sock *sk) {} ++static inline void mptcp_init_listen(struct sock *sk) {} ++static inline void mptcp_init_connect(struct sock *sk) {} ++static inline void mptcp_disable_static_key(void) {} ++static inline void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) {} ++static inline void mptcp_mpcb_put(struct mptcp_cb *mpcb) {} ++static inline void mptcp_fin(struct sock *meta_sk) {} ++static inline bool mptcp_in_infinite_mapping_weak(const struct mptcp_cb *mpcb) ++{ ++ return false; ++} ++static inline bool mptcp_can_new_subflow(const struct sock *meta_sk) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_H */ +diff -aurN linux-5.4.64/include/net/mptcp_v4.h linux-5.4.64.mptcp/include/net/mptcp_v4.h +--- linux-5.4.64/include/net/mptcp_v4.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/include/net/mptcp_v4.h 2020-09-10 19:25:10.499221003 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef MPTCP_V4_H_ ++#define MPTCP_V4_H_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern struct request_sock_ops mptcp_request_sock_ops; ++extern const struct inet_connection_sock_af_ops mptcp_v4_specific; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++#ifdef CONFIG_MPTCP ++ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v4_search_req(const __be16 rport, const __be32 raddr, ++ const __be32 laddr, const struct net *net); ++int __mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ __be16 sport, struct mptcp_rem4 *rem, ++ struct sock **subsk); ++int mptcp_pm_v4_init(void); ++void mptcp_pm_v4_undo(void); ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport); ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed); ++ ++static inline int mptcp_init4_subsockets(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ return __mptcp_init4_subsockets(meta_sk, loc, 0, rem, NULL); ++} ++ ++#else ++ ++static inline int mptcp_v4_do_rcv(const struct sock *meta_sk, ++ const struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* MPTCP_V4_H_ */ +diff -aurN linux-5.4.64/include/net/mptcp_v6.h linux-5.4.64.mptcp/include/net/mptcp_v6.h +--- linux-5.4.64/include/net/mptcp_v6.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/include/net/mptcp_v6.h 2020-09-10 19:25:10.499221003 +0200 +@@ -0,0 +1,77 @@ ++/* ++ * MPTCP implementation ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef _MPTCP_V6_H ++#define _MPTCP_V6_H ++ ++#include ++#include ++ ++#include ++ ++ ++#ifdef CONFIG_MPTCP ++extern const struct inet_connection_sock_af_ops mptcp_v6_mapped; ++extern const struct inet_connection_sock_af_ops mptcp_v6_specific; ++extern struct request_sock_ops mptcp6_request_sock_ops; ++extern struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++extern struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb); ++struct sock *mptcp_v6_search_req(const __be16 rport, const struct in6_addr *raddr, ++ const struct in6_addr *laddr, const struct net *net); ++int __mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ __be16 sport, struct mptcp_rem6 *rem, ++ struct sock **subsk); ++int mptcp_pm_v6_init(void); ++void mptcp_pm_v6_undo(void); ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport); ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed); ++ ++static inline int mptcp_init6_subsockets(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ return __mptcp_init6_subsockets(meta_sk, loc, 0, rem, NULL); ++} ++ ++#else /* CONFIG_MPTCP */ ++ ++#define mptcp_v6_mapped ipv6_mapped ++ ++static inline int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_MPTCP */ ++ ++#endif /* _MPTCP_V6_H */ +diff -aurN linux-5.4.64/include/net/net_namespace.h linux-5.4.64.mptcp/include/net/net_namespace.h +--- linux-5.4.64/include/net/net_namespace.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/net_namespace.h 2020-09-10 19:25:10.499221003 +0200 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -123,6 +124,9 @@ + #if IS_ENABLED(CONFIG_IPV6) + struct netns_ipv6 ipv6; + #endif ++#if IS_ENABLED(CONFIG_MPTCP) ++ struct netns_mptcp mptcp; ++#endif + #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) + struct netns_ieee802154_lowpan ieee802154_lowpan; + #endif +diff -aurN linux-5.4.64/include/net/netns/mptcp.h linux-5.4.64.mptcp/include/net/netns/mptcp.h +--- linux-5.4.64/include/net/netns/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/include/net/netns/mptcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -0,0 +1,52 @@ ++/* ++ * MPTCP implementation - MPTCP namespace ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#ifndef __NETNS_MPTCP_H__ ++#define __NETNS_MPTCP_H__ ++ ++#include ++ ++enum { ++ MPTCP_PM_FULLMESH = 0, ++ MPTCP_PM_MAX ++}; ++ ++struct mptcp_mib; ++ ++struct netns_mptcp { ++ DEFINE_SNMP_STAT(struct mptcp_mib, mptcp_statistics); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_net_mptcp; ++#endif ++ ++ void *path_managers[MPTCP_PM_MAX]; ++}; ++ ++#endif /* __NETNS_MPTCP_H__ */ +diff -aurN linux-5.4.64/include/net/snmp.h linux-5.4.64.mptcp/include/net/snmp.h +--- linux-5.4.64/include/net/snmp.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/snmp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -86,7 +86,6 @@ + atomic_long_t mibs[ICMP6MSG_MIB_MAX]; + }; + +- + /* TCP */ + #define TCP_MIB_MAX __TCP_MIB_MAX + struct tcp_mib { +diff -aurN linux-5.4.64/include/net/sock.h linux-5.4.64.mptcp/include/net/sock.h +--- linux-5.4.64/include/net/sock.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/sock.h 2020-09-10 19:25:10.499221003 +0200 +@@ -819,6 +819,7 @@ + SOCK_TXTIME, + SOCK_XDP, /* XDP is attached */ + SOCK_TSTAMP_NEW, /* Indicates 64 bit timestamps always */ ++ SOCK_MPTCP, /* MPTCP set on this socket */ + }; + + #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) +@@ -1131,6 +1132,7 @@ + void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); + int (*get_port)(struct sock *sk, unsigned short snum); ++ void (*clear_sk)(struct sock *sk, int size); + + /* Keeping track of sockets in use */ + #ifdef CONFIG_PROC_FS +diff -aurN linux-5.4.64/include/net/tcp.h linux-5.4.64.mptcp/include/net/tcp.h +--- linux-5.4.64/include/net/tcp.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/tcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -182,6 +182,7 @@ + #define TCPOPT_SACK 5 /* SACK Block */ + #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ + #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ ++#define TCPOPT_MPTCP 30 + #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ + #define TCPOPT_EXP 254 /* Experimental */ + /* Magic number to be after the option value for sharing TCP +@@ -238,6 +239,31 @@ + */ + #define TFO_SERVER_WO_SOCKOPT1 0x400 + ++/* Flags from tcp_input.c for tcp_ack */ ++#define FLAG_DATA 0x01 /* Incoming frame contained data. */ ++#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ ++#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ ++#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ ++#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ ++#define FLAG_DATA_SACKED 0x20 /* New SACK. */ ++#define FLAG_ECE 0x40 /* ECE in this ACK */ ++#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ ++#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ ++#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ ++#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ ++#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ ++#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ ++#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ ++#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ ++#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ ++#define FLAG_ACK_MAYBE_DELAYED 0x10000 /* Likely a delayed ACK */ ++ ++#define MPTCP_FLAG_DATA_ACKED 0x20000 ++ ++#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) ++#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) ++#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) ++#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) + + /* sysctl variables for tcp */ + extern int sysctl_tcp_max_orphans; +@@ -310,6 +336,97 @@ + #define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) + #define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) + ++/**** START - Exports needed for MPTCP ****/ ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops; ++extern const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops; ++ ++struct mptcp_options_received; ++ ++void tcp_cleanup_rbuf(struct sock *sk, int copied); ++int tcp_close_state(struct sock *sk); ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb); ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib); ++void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb); ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask); ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle); ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle); ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss); ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, const struct sk_buff *skb); ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++int __pskb_trim_head(struct sk_buff *skb, int len); ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb); ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags); ++void tcp_reset(struct sock *sk); ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin); ++bool tcp_urg_mode(const struct tcp_sock *tp); ++void tcp_ack_probe(struct sock *sk); ++void tcp_rearm_rto(struct sock *sk); ++int tcp_write_timeout(struct sock *sk); ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout); ++void tcp_write_err(struct sock *sk); ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr); ++void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, ++ u64 prior_wstamp); ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now); ++ ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb); ++void tcp_v4_reqsk_destructor(struct request_sock *req); ++ ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); ++void tcp_v6_destroy_sock(struct sock *sk); ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); ++void tcp_v6_hash(struct sock *sk); ++struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb); ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req); ++void tcp_v6_reqsk_destructor(struct request_sock *req); ++ ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, ++ int large_allowed); ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb); ++void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb, u32 prior_snd_una); ++ ++void skb_clone_fraglist(struct sk_buff *skb); ++ ++void inet_twsk_free(struct inet_timewait_sock *tw); ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb); ++/* These states need RST on ABORT according to RFC793 */ ++static inline bool tcp_need_reset(int state) ++{ ++ return (1 << state) & ++ (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | ++ TCPF_FIN_WAIT2 | TCPF_SYN_RECV); ++} ++ ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, ++ bool *fragstolen); ++void tcp_ofo_queue(struct sock *sk); ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb); ++int linear_payload_sz(bool first_skb); ++/**** END - Exports needed for MPTCP ****/ ++ + void tcp_tasklet_init(void); + + int tcp_v4_err(struct sk_buff *skb, u32); +@@ -411,7 +528,9 @@ + #endif + void tcp_parse_options(const struct net *net, const struct sk_buff *skb, + struct tcp_options_received *opt_rx, +- int estab, struct tcp_fastopen_cookie *foc); ++ struct mptcp_options_received *mopt_rx, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp); + const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); + + /* +@@ -430,6 +549,7 @@ + + void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); + void tcp_v4_mtu_reduced(struct sock *sk); ++void tcp_v6_mtu_reduced(struct sock *sk); + void tcp_req_err(struct sock *sk, u32 seq, bool abort); + int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); + struct sock *tcp_create_openreq_child(const struct sock *sk, +@@ -453,6 +573,7 @@ + struct request_sock *req, + struct tcp_fastopen_cookie *foc, + enum tcp_synack_type synack_type); ++void tcp_reset_vars(struct sock *sk); + int tcp_disconnect(struct sock *sk, int flags); + + void tcp_finish_connect(struct sock *sk, struct sk_buff *skb); +@@ -462,6 +583,7 @@ + /* From syncookies.c */ + struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, ++ const struct mptcp_options_received *mopt, + struct dst_entry *dst, u32 tsoff); + int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, + u32 cookie); +@@ -547,7 +669,8 @@ + + u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, + u16 *mssp); +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + u64 cookie_init_timestamp(struct request_sock *req); + bool cookie_timestamp_decode(const struct net *net, + struct tcp_options_received *opt); +@@ -561,7 +684,8 @@ + + u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, + const struct tcphdr *th, u16 *mssp); +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss); ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + /* tcp_output.c */ + +@@ -597,10 +721,16 @@ + void tcp_skb_collapse_tstamp(struct sk_buff *skb, + const struct sk_buff *next_skb); + ++u16 tcp_select_window(struct sock *sk); ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ + /* tcp_input.c */ + void tcp_rearm_rto(struct sock *sk); + void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); + void tcp_reset(struct sock *sk); ++void tcp_set_rto(struct sock *sk); ++bool tcp_should_expand_sndbuf(const struct sock *sk); + void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); + void tcp_fin(struct sock *sk); + +@@ -644,7 +774,7 @@ + } + + /* tcp.c */ +-void tcp_get_info(struct sock *, struct tcp_info *); ++void tcp_get_info(struct sock *, struct tcp_info *, bool no_lock); + + /* Read 'sendfile()'-style from a TCP socket */ + int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, +@@ -828,6 +958,12 @@ + u16 tcp_gso_size; + }; + }; ++ ++#ifdef CONFIG_MPTCP ++ __u8 mptcp_flags; /* flags for the MPTCP layer */ ++ __u8 dss_off; /* Number of 4-byte words until ++ * seq-number */ ++#endif + __u8 tcp_flags; /* TCP header flags. (tcp[13]) */ + + __u8 sacked; /* State flags for SACK. */ +@@ -846,6 +982,14 @@ + has_rxtstamp:1, /* SKB has a RX timestamp */ + unused:5; + __u32 ack_seq; /* Sequence number ACK'd */ ++ ++#ifdef CONFIG_MPTCP ++ union { /* For MPTCP outgoing frames */ ++ __u32 path_mask; /* paths that tried to send this skb */ ++ __u32 dss[6]; /* DSS options */ ++ }; ++#endif ++ + union { + struct { + /* There is space for up to 24 bytes */ +@@ -1087,6 +1231,8 @@ + int tcp_set_allowed_congestion_control(char *allowed); + int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, + bool reinit, bool cap_net_admin); ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); + u32 tcp_slow_start(struct tcp_sock *tp, u32 acked); + void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked); + +@@ -1388,6 +1534,19 @@ + space - (space>>tcp_adv_win_scale); + } + ++#ifdef CONFIG_MPTCP ++extern struct static_key mptcp_static_key; ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return static_key_false(&mptcp_static_key) && tp->mpc; ++} ++#else ++static inline bool mptcp(const struct tcp_sock *tp) ++{ ++ return 0; ++} ++#endif ++ + /* Note: caller must be prepared to deal with negative returns */ + static inline int tcp_space(const struct sock *sk) + { +@@ -1975,6 +2134,30 @@ + #endif + }; + ++/* TCP/MPTCP-specific functions */ ++struct tcp_sock_ops { ++ u32 (*__select_window)(struct sock *sk); ++ u16 (*select_window)(struct sock *sk); ++ void (*select_initial_window)(const struct sock *sk, int __space, ++ __u32 mss, __u32 *rcv_wnd, ++ __u32 *window_clamp, int wscale_ok, ++ __u8 *rcv_wscale, __u32 init_rcv_wnd); ++ void (*init_buffer_space)(struct sock *sk); ++ void (*set_rto)(struct sock *sk); ++ bool (*should_expand_sndbuf)(const struct sock *sk); ++ void (*send_fin)(struct sock *sk); ++ bool (*write_xmit)(struct sock *sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp); ++ void (*send_active_reset)(struct sock *sk, gfp_t priority); ++ int (*write_wakeup)(struct sock *sk, int mib); ++ void (*retransmit_timer)(struct sock *sk); ++ void (*time_wait)(struct sock *sk, int state, int timeo); ++ void (*cleanup_rbuf)(struct sock *sk, int copied); ++ int (*set_cong_ctrl)(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin); ++}; ++extern const struct tcp_sock_ops tcp_specific; ++ + struct tcp_request_sock_ops { + u16 mss_clamp; + #ifdef CONFIG_TCP_MD5SIG +@@ -1985,12 +2168,13 @@ + const struct sock *sk, + const struct sk_buff *skb); + #endif +- void (*init_req)(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb); ++ int (*init_req)(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie); + #ifdef CONFIG_SYN_COOKIES +- __u32 (*cookie_init_seq)(const struct sk_buff *skb, +- __u16 *mss); ++ __u32 (*cookie_init_seq)(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mss); + #endif + struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, + const struct request_sock *req); +@@ -2004,15 +2188,17 @@ + + #ifdef CONFIG_SYN_COOKIES + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { + tcp_synq_overflow(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); +- return ops->cookie_init_seq(skb, mss); ++ return ops->cookie_init_seq(req, sk, skb, mss); + } + #else + static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, ++ struct request_sock *req, + const struct sock *sk, struct sk_buff *skb, + __u16 *mss) + { +diff -aurN linux-5.4.64/include/net/tcp_states.h linux-5.4.64.mptcp/include/net/tcp_states.h +--- linux-5.4.64/include/net/tcp_states.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/tcp_states.h 2020-09-10 19:25:10.499221003 +0200 +@@ -22,6 +22,7 @@ + TCP_LISTEN, + TCP_CLOSING, /* Now a valid state */ + TCP_NEW_SYN_RECV, ++ TCP_RST_WAIT, + + TCP_MAX_STATES /* Leave at the end! */ + }; +@@ -43,6 +44,7 @@ + TCPF_LISTEN = (1 << TCP_LISTEN), + TCPF_CLOSING = (1 << TCP_CLOSING), + TCPF_NEW_SYN_RECV = (1 << TCP_NEW_SYN_RECV), ++ TCPF_RST_WAIT = (1 << TCP_RST_WAIT), + }; + + #endif /* _LINUX_TCP_STATES_H */ +diff -aurN linux-5.4.64/include/net/transp_v6.h linux-5.4.64.mptcp/include/net/transp_v6.h +--- linux-5.4.64/include/net/transp_v6.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/net/transp_v6.h 2020-09-10 19:25:10.499221003 +0200 +@@ -58,6 +58,8 @@ + + /* address family specific functions */ + extern const struct inet_connection_sock_af_ops ipv4_specific; ++extern const struct inet_connection_sock_af_ops ipv6_mapped; ++extern const struct inet_connection_sock_af_ops ipv6_specific; + + void inet6_destroy_sock(struct sock *sk); + +diff -aurN linux-5.4.64/include/trace/events/tcp.h linux-5.4.64.mptcp/include/trace/events/tcp.h +--- linux-5.4.64/include/trace/events/tcp.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/trace/events/tcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + + #define TP_STORE_V4MAPPED(__entry, saddr, daddr) \ +@@ -181,6 +182,13 @@ + TP_ARGS(sk) + ); + ++DEFINE_EVENT(tcp_event_sk_skb, mptcp_retransmit, ++ ++ TP_PROTO(const struct sock *sk, const struct sk_buff *skb), ++ ++ TP_ARGS(sk, skb) ++); ++ + TRACE_EVENT(tcp_retransmit_synack, + + TP_PROTO(const struct sock *sk, const struct request_sock *req), +@@ -248,6 +256,7 @@ + __field(__u32, srtt) + __field(__u32, rcv_wnd) + __field(__u64, sock_cookie) ++ __field(__u8, mptcp) + ), + + TP_fast_assign( +@@ -274,13 +283,15 @@ + __entry->ssthresh = tcp_current_ssthresh(sk); + __entry->srtt = tp->srtt_us >> 3; + __entry->sock_cookie = sock_gen_cookie(sk); ++ __entry->mptcp = mptcp(tp) ? tp->mptcp->path_index : 0; + ), + +- TP_printk("src=%pISpc dest=%pISpc mark=%#x data_len=%d snd_nxt=%#x snd_una=%#x snd_cwnd=%u ssthresh=%u snd_wnd=%u srtt=%u rcv_wnd=%u sock_cookie=%llx", ++ TP_printk("src=%pISpc dest=%pISpc mark=%#x data_len=%d snd_nxt=%#x snd_una=%#x snd_cwnd=%u ssthresh=%u snd_wnd=%u srtt=%u rcv_wnd=%u sock_cookie=%llx mptcp=%d", + __entry->saddr, __entry->daddr, __entry->mark, + __entry->data_len, __entry->snd_nxt, __entry->snd_una, + __entry->snd_cwnd, __entry->ssthresh, __entry->snd_wnd, +- __entry->srtt, __entry->rcv_wnd, __entry->sock_cookie) ++ __entry->srtt, __entry->rcv_wnd, __entry->sock_cookie, ++ __entry->mptcp) + ); + + #endif /* _TRACE_TCP_H */ +diff -aurN linux-5.4.64/include/uapi/linux/bpf.h linux-5.4.64.mptcp/include/uapi/linux/bpf.h +--- linux-5.4.64/include/uapi/linux/bpf.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/uapi/linux/bpf.h 2020-09-10 19:25:10.499221003 +0200 +@@ -3438,6 +3438,7 @@ + BPF_TCP_LISTEN, + BPF_TCP_CLOSING, /* Now a valid state */ + BPF_TCP_NEW_SYN_RECV, ++ BPF_TCP_RST_WAIT, + + BPF_TCP_MAX_STATES /* Leave at the end! */ + }; +diff -aurN linux-5.4.64/include/uapi/linux/if.h linux-5.4.64.mptcp/include/uapi/linux/if.h +--- linux-5.4.64/include/uapi/linux/if.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/uapi/linux/if.h 2020-09-10 19:25:10.499221003 +0200 +@@ -132,6 +132,9 @@ + #define IFF_ECHO IFF_ECHO + #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + ++#define IFF_NOMULTIPATH 0x80000 /* Disable for MPTCP */ ++#define IFF_MPBACKUP 0x100000 /* Use as backup path for MPTCP */ ++ + #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +diff -aurN linux-5.4.64/include/uapi/linux/in.h linux-5.4.64.mptcp/include/uapi/linux/in.h +--- linux-5.4.64/include/uapi/linux/in.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/uapi/linux/in.h 2020-09-10 19:25:10.499221003 +0200 +@@ -76,6 +76,8 @@ + #define IPPROTO_MPLS IPPROTO_MPLS + IPPROTO_RAW = 255, /* Raw IP packets */ + #define IPPROTO_RAW IPPROTO_RAW ++ IPPROTO_MPTCP = 262, /* Multipath TCP connection */ ++#define IPPROTO_MPTCP IPPROTO_MPTCP + IPPROTO_MAX + }; + #endif +diff -aurN linux-5.4.64/include/uapi/linux/mptcp.h linux-5.4.64.mptcp/include/uapi/linux/mptcp.h +--- linux-5.4.64/include/uapi/linux/mptcp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/include/uapi/linux/mptcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -0,0 +1,149 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Netlink API for Multipath TCP ++ * ++ * Author: Gregory Detal ++ * ++ * 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. ++ */ ++ ++#ifndef _LINUX_MPTCP_H ++#define _LINUX_MPTCP_H ++ ++#define MPTCP_GENL_NAME "mptcp" ++#define MPTCP_GENL_EV_GRP_NAME "mptcp_events" ++#define MPTCP_GENL_CMD_GRP_NAME "mptcp_commands" ++#define MPTCP_GENL_VER 0x1 ++ ++/* ++ * ATTR types defined for MPTCP ++ */ ++enum { ++ MPTCP_ATTR_UNSPEC = 0, ++ ++ MPTCP_ATTR_TOKEN, /* u32 */ ++ MPTCP_ATTR_FAMILY, /* u16 */ ++ MPTCP_ATTR_LOC_ID, /* u8 */ ++ MPTCP_ATTR_REM_ID, /* u8 */ ++ MPTCP_ATTR_SADDR4, /* u32 */ ++ MPTCP_ATTR_SADDR6, /* struct in6_addr */ ++ MPTCP_ATTR_DADDR4, /* u32 */ ++ MPTCP_ATTR_DADDR6, /* struct in6_addr */ ++ MPTCP_ATTR_SPORT, /* u16 */ ++ MPTCP_ATTR_DPORT, /* u16 */ ++ MPTCP_ATTR_BACKUP, /* u8 */ ++ MPTCP_ATTR_ERROR, /* u8 */ ++ MPTCP_ATTR_FLAGS, /* u16 */ ++ MPTCP_ATTR_TIMEOUT, /* u32 */ ++ MPTCP_ATTR_IF_IDX, /* s32 */ ++ ++ __MPTCP_ATTR_AFTER_LAST ++}; ++ ++#define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) ++ ++/* ++ * Events generated by MPTCP: ++ * - MPTCP_EVENT_CREATED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * A new connection has been created. It is the good time to allocate ++ * memory and send ADD_ADDR if needed. Depending on the traffic-patterns ++ * it can take a long time until the MPTCP_EVENT_ESTABLISHED is sent. ++ * ++ * - MPTCP_EVENT_ESTABLISHED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * A connection is established (can start new subflows). ++ * ++ * - MPTCP_EVENT_CLOSED: token ++ * A connection has stopped. ++ * ++ * - MPTCP_EVENT_ANNOUNCED: token, rem_id, family, daddr4 | daddr6 [, dport] ++ * A new address has been announced by the peer. ++ * ++ * - MPTCP_EVENT_REMOVED: token, rem_id ++ * An address has been lost by the peer. ++ * ++ * - MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6, ++ * daddr4 | daddr6, sport, dport, backup, ++ * if_idx [, error] ++ * A new subflow has been established. 'error' should not be set. ++ * ++ * - MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup, if_idx [, error] ++ * A subflow has been closed. An error (copy of sk_err) could be set if an ++ * error has been detected for this subflow. ++ * ++ * - MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup, if_idx [, error] ++ * The priority of a subflow has changed. 'error' should not be set. ++ * ++ * Commands for MPTCP: ++ * - MPTCP_CMD_ANNOUNCE: token, loc_id, family, saddr4 | saddr6 [, sport] ++ * Announce a new address to the peer. ++ * ++ * - MPTCP_CMD_REMOVE: token, loc_id ++ * Announce that an address has been lost to the peer. ++ * ++ * - MPTCP_CMD_SUB_CREATE: token, family, loc_id, rem_id, [saddr4 | saddr6, ++ * daddr4 | daddr6, dport [, sport, backup, if_idx]] ++ * Create a new subflow. ++ * ++ * - MPTCP_CMD_SUB_DESTROY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport ++ * Close a subflow. ++ * ++ * - MPTCP_CMD_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6, ++ * sport, dport, backup ++ * Change the priority of a subflow. ++ * ++ * - MPTCP_CMD_SET_FILTER: flags ++ * Set the filter on events. Set MPTCPF_* flags to only receive specific ++ * events. Default is to receive all events. ++ * ++ * - MPTCP_CMD_EXIST: token ++ * Check if this token is linked to an existing socket. ++ */ ++enum { ++ MPTCP_CMD_UNSPEC = 0, ++ ++ MPTCP_EVENT_CREATED, ++ MPTCP_EVENT_ESTABLISHED, ++ MPTCP_EVENT_CLOSED, ++ ++ MPTCP_CMD_ANNOUNCE, ++ MPTCP_CMD_REMOVE, ++ MPTCP_EVENT_ANNOUNCED, ++ MPTCP_EVENT_REMOVED, ++ ++ MPTCP_CMD_SUB_CREATE, ++ MPTCP_CMD_SUB_DESTROY, ++ MPTCP_EVENT_SUB_ESTABLISHED, ++ MPTCP_EVENT_SUB_CLOSED, ++ ++ MPTCP_CMD_SUB_PRIORITY, ++ MPTCP_EVENT_SUB_PRIORITY, ++ ++ MPTCP_CMD_SET_FILTER, ++ ++ MPTCP_CMD_EXIST, ++ ++ __MPTCP_CMD_AFTER_LAST ++}; ++ ++#define MPTCP_CMD_MAX (__MPTCP_CMD_AFTER_LAST - 1) ++ ++enum { ++ MPTCPF_EVENT_CREATED = (1 << 1), ++ MPTCPF_EVENT_ESTABLISHED = (1 << 2), ++ MPTCPF_EVENT_CLOSED = (1 << 3), ++ MPTCPF_EVENT_ANNOUNCED = (1 << 4), ++ MPTCPF_EVENT_REMOVED = (1 << 5), ++ MPTCPF_EVENT_SUB_ESTABLISHED = (1 << 6), ++ MPTCPF_EVENT_SUB_CLOSED = (1 << 7), ++ MPTCPF_EVENT_SUB_PRIORITY = (1 << 8), ++}; ++ ++#endif /* _LINUX_MPTCP_H */ +diff -aurN linux-5.4.64/include/uapi/linux/tcp.h linux-5.4.64.mptcp/include/uapi/linux/tcp.h +--- linux-5.4.64/include/uapi/linux/tcp.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/include/uapi/linux/tcp.h 2020-09-10 19:25:10.499221003 +0200 +@@ -18,9 +18,15 @@ + #ifndef _UAPI_LINUX_TCP_H + #define _UAPI_LINUX_TCP_H + +-#include ++#ifndef __KERNEL__ ++#include ++#endif ++ + #include ++#include ++#include + #include ++#include + + struct tcphdr { + __be16 source; +@@ -134,6 +140,13 @@ + #define TCP_REPAIR_OFF 0 + #define TCP_REPAIR_OFF_NO_WP -1 /* Turn off without window probes */ + ++#define MPTCP_ENABLED 42 ++#define MPTCP_SCHEDULER 43 ++#define MPTCP_PATH_MANAGER 44 ++#define MPTCP_INFO 45 ++ ++#define MPTCP_INFO_FLAG_SAVE_MASTER 0x01 ++ + struct tcp_repair_opt { + __u32 opt_code; + __u32 opt_val; +@@ -305,6 +318,53 @@ + TCP_NLA_SRTT, /* smoothed RTT in usecs */ + }; + ++struct mptcp_meta_info { ++ __u8 mptcpi_state; ++ __u8 mptcpi_retransmits; ++ __u8 mptcpi_probes; ++ __u8 mptcpi_backoff; ++ ++ __u32 mptcpi_rto; ++ __u32 mptcpi_unacked; ++ ++ /* Times. */ ++ __u32 mptcpi_last_data_sent; ++ __u32 mptcpi_last_data_recv; ++ __u32 mptcpi_last_ack_recv; ++ ++ __u32 mptcpi_total_retrans; ++ ++ __u64 mptcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ ++ __u64 mptcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ ++}; ++ ++struct mptcp_sub_info { ++ union { ++ struct sockaddr src; ++ struct sockaddr_in src_v4; ++ struct sockaddr_in6 src_v6; ++ }; ++ ++ union { ++ struct sockaddr dst; ++ struct sockaddr_in dst_v4; ++ struct sockaddr_in6 dst_v6; ++ }; ++}; ++ ++struct mptcp_info { ++ __u32 tcp_info_len; /* Length of each struct tcp_info in subflows pointer */ ++ __u32 sub_len; /* Total length of memory pointed to by subflows pointer */ ++ __u32 meta_len; /* Length of memory pointed to by meta_info */ ++ __u32 sub_info_len; /* Length of each struct mptcp_sub_info in subflow_info pointer */ ++ __u32 total_sub_info_len; /* Total length of memory pointed to by subflow_info */ ++ ++ struct mptcp_meta_info *meta_info; ++ struct tcp_info *initial; ++ struct tcp_info *subflows; /* Pointer to array of tcp_info structs */ ++ struct mptcp_sub_info *subflow_info; ++}; ++ + /* for TCP_MD5SIG socket option */ + #define TCP_MD5SIG_MAXKEYLEN 80 + +diff -aurN linux-5.4.64/net/core/dev.c linux-5.4.64.mptcp/net/core/dev.c +--- linux-5.4.64/net/core/dev.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/core/dev.c 2020-09-10 19:25:10.503220935 +0200 +@@ -7851,7 +7851,7 @@ + + dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | + IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | +- IFF_AUTOMEDIA)) | ++ IFF_AUTOMEDIA | IFF_NOMULTIPATH | IFF_MPBACKUP)) | + (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | + IFF_ALLMULTI)); + +diff -aurN linux-5.4.64/net/core/net-traces.c linux-5.4.64.mptcp/net/core/net-traces.c +--- linux-5.4.64/net/core/net-traces.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/core/net-traces.c 2020-09-10 19:25:10.503220935 +0200 +@@ -60,3 +60,5 @@ + EXPORT_TRACEPOINT_SYMBOL_GPL(napi_poll); + + EXPORT_TRACEPOINT_SYMBOL_GPL(tcp_send_reset); ++ ++EXPORT_TRACEPOINT_SYMBOL_GPL(mptcp_retransmit); +diff -aurN linux-5.4.64/net/core/skbuff.c linux-5.4.64.mptcp/net/core/skbuff.c +--- linux-5.4.64/net/core/skbuff.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/core/skbuff.c 2020-09-10 19:25:10.503220935 +0200 +@@ -573,7 +573,7 @@ + skb_drop_list(&skb_shinfo(skb)->frag_list); + } + +-static void skb_clone_fraglist(struct sk_buff *skb) ++void skb_clone_fraglist(struct sk_buff *skb) + { + struct sk_buff *list; + +diff -aurN linux-5.4.64/net/core/sock.c linux-5.4.64.mptcp/net/core/sock.c +--- linux-5.4.64/net/core/sock.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/core/sock.c 2020-09-10 19:26:53.689504155 +0200 +@@ -135,6 +135,11 @@ + + #include + ++#ifdef CONFIG_MPTCP ++#include ++#include ++#endif ++ + #include + #include + +@@ -1551,6 +1556,23 @@ + */ + static inline void sock_lock_init(struct sock *sk) + { ++#ifdef CONFIG_MPTCP ++ /* Reclassify the lock-class for subflows */ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ if (mptcp(tcp_sk(sk)) || tcp_sk(sk)->is_master_sk) { ++ sock_lock_init_class_and_name(sk, meta_slock_key_name, ++ &meta_slock_key, ++ meta_key_name, ++ &meta_key); ++ ++ /* We don't yet have the mptcp-point. ++ * Thus we still need inet_sock_destruct ++ */ ++ sk->sk_destruct = inet_sock_destruct; ++ return; ++ } ++#endif ++ + if (sk->sk_kern_sock) + sock_lock_init_class_and_name( + sk, +@@ -1599,8 +1621,12 @@ + sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); + if (!sk) + return sk; +- if (want_init_on_alloc(priority)) +- sk_prot_clear_nulls(sk, prot->obj_size); ++ if (want_init_on_alloc(priority)) { ++ if (prot->clear_sk) ++ prot->clear_sk(sk, prot->obj_size); ++ else ++ sk_prot_clear_nulls(sk, prot->obj_size); ++ } + } else + sk = kmalloc(prot->obj_size, priority); + +@@ -1832,7 +1858,7 @@ + newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; + atomic_set(&newsk->sk_zckey, 0); + +- sock_reset_flag(newsk, SOCK_DONE); ++ sock_reset_flag(newsk, SOCK_MPTCP); + + /* sk->sk_memcg will be populated at accept() time */ + newsk->sk_memcg = NULL; +diff -aurN linux-5.4.64/net/ipv4/af_inet.c linux-5.4.64.mptcp/net/ipv4/af_inet.c +--- linux-5.4.64/net/ipv4/af_inet.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/af_inet.c 2020-09-10 19:25:10.503220935 +0200 +@@ -100,6 +100,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -150,6 +151,9 @@ + return; + } + ++ if (sock_flag(sk, SOCK_MPTCP)) ++ mptcp_disable_static_key(); ++ + WARN_ON(atomic_read(&sk->sk_rmem_alloc)); + WARN_ON(refcount_read(&sk->sk_wmem_alloc)); + WARN_ON(sk->sk_wmem_queued); +@@ -227,6 +231,8 @@ + tcp_fastopen_init_key_once(sock_net(sk)); + } + ++ mptcp_init_listen(sk); ++ + err = inet_csk_listen_start(sk, backlog); + if (err) + goto out; +@@ -244,8 +250,7 @@ + * Create an inet socket. + */ + +-static int inet_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct sock *sk; + struct inet_protosw *answer; +@@ -739,6 +744,24 @@ + lock_sock(sk2); + + sock_rps_record_flow(sk2); ++ ++ if (sk2->sk_protocol == IPPROTO_TCP && mptcp(tcp_sk(sk2))) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk2)->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ ++ if (tcp_sk(sk2)->mpcb->master_sk) { ++ struct sock *sk_it = tcp_sk(sk2)->mpcb->master_sk; ++ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ rcu_assign_pointer(sk_it->sk_wq, &newsock->wq); ++ sk_it->sk_socket = newsock; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ } ++ + WARN_ON(!((1 << sk2->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | + TCPF_CLOSE_WAIT | TCPF_CLOSE))); +@@ -1974,6 +1997,9 @@ + + ip_init(); + ++ /* We must initialize MPTCP before TCP. */ ++ mptcp_init(); ++ + /* Setup TCP slab cache for open requests. */ + tcp_init(); + +diff -aurN linux-5.4.64/net/ipv4/inet_connection_sock.c linux-5.4.64.mptcp/net/ipv4/inet_connection_sock.c +--- linux-5.4.64/net/ipv4/inet_connection_sock.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/inet_connection_sock.c 2020-09-10 19:25:10.503220935 +0200 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -727,7 +728,10 @@ + int max_retries, thresh; + u8 defer_accept; + +- if (inet_sk_state_load(sk_listener) != TCP_LISTEN) ++ if (!is_meta_sk(sk_listener) && inet_sk_state_load(sk_listener) != TCP_LISTEN) ++ goto drop; ++ ++ if (is_meta_sk(sk_listener) && !mptcp_can_new_subflow(sk_listener)) + goto drop; + + max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; +@@ -816,7 +820,9 @@ + const struct request_sock *req, + const gfp_t priority) + { +- struct sock *newsk = sk_clone_lock(sk, priority); ++ struct sock *newsk; ++ ++ newsk = sk_clone_lock(sk, priority); + + if (newsk) { + struct inet_connection_sock *newicsk = inet_csk(newsk); +@@ -1015,7 +1021,14 @@ + */ + while ((req = reqsk_queue_remove(queue, sk)) != NULL) { + struct sock *child = req->sk; ++ bool mutex_taken = false; ++ struct mptcp_cb *mpcb = tcp_sk(child)->mpcb; + ++ if (is_meta_sk(child)) { ++ WARN_ON(refcount_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ mutex_taken = true; ++ } + local_bh_disable(); + bh_lock_sock(child); + WARN_ON(sock_owned_by_user(child)); +@@ -1025,6 +1038,10 @@ + reqsk_put(req); + bh_unlock_sock(child); + local_bh_enable(); ++ if (mutex_taken) { ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ } + sock_put(child); + + cond_resched(); +diff -aurN linux-5.4.64/net/ipv4/ip_sockglue.c linux-5.4.64.mptcp/net/ipv4/ip_sockglue.c +--- linux-5.4.64/net/ipv4/ip_sockglue.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/ip_sockglue.c 2020-09-10 19:25:10.503220935 +0200 +@@ -44,6 +44,8 @@ + #endif + #include + ++#include ++ + #include + #include + +@@ -657,7 +659,7 @@ + break; + old = rcu_dereference_protected(inet->inet_opt, + lockdep_sock_is_held(sk)); +- if (inet->is_icsk) { ++ if (inet->is_icsk && !is_meta_sk(sk)) { + struct inet_connection_sock *icsk = inet_csk(sk); + #if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family == PF_INET || +@@ -751,6 +753,20 @@ + inet->tos = val; + sk->sk_priority = rt_tos2priority(val); + sk_dst_reset(sk); ++ /* Update TOS on mptcp subflow */ ++ if (is_meta_sk(sk)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (inet_sk(sk_it)->tos != inet_sk(sk)->tos) { ++ inet_sk(sk_it)->tos = inet_sk(sk)->tos; ++ sk_it->sk_priority = sk->sk_priority; ++ sk_dst_reset(sk_it); ++ } ++ } ++ } + } + break; + case IP_TTL: +diff -aurN linux-5.4.64/net/ipv4/Kconfig linux-5.4.64.mptcp/net/ipv4/Kconfig +--- linux-5.4.64/net/ipv4/Kconfig 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/Kconfig 2020-09-10 19:25:10.503220935 +0200 +@@ -655,6 +655,51 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_LIA ++ tristate "MPTCP Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Linked Increase Congestion Control ++ To enable it, just put 'lia' in tcp_congestion_control ++ ++config TCP_CONG_OLIA ++ tristate "MPTCP Opportunistic Linked Increase" ++ depends on MPTCP ++ default n ++ ---help--- ++ MultiPath TCP Opportunistic Linked Increase Congestion Control ++ To enable it, just put 'olia' in tcp_congestion_control ++ ++config TCP_CONG_WVEGAS ++ tristate "MPTCP WVEGAS CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ wVegas congestion control for MPTCP ++ To enable it, just put 'wvegas' in tcp_congestion_control ++ ++config TCP_CONG_BALIA ++ tristate "MPTCP BALIA CONGESTION CONTROL" ++ depends on MPTCP ++ default n ++ ---help--- ++ Multipath TCP Balanced Linked Adaptation Congestion Control ++ To enable it, just put 'balia' in tcp_congestion_control ++ ++config TCP_CONG_MCTCPDESYNC ++ tristate "DESYNCHRONIZED MCTCP CONGESTION CONTROL (EXPERIMENTAL)" ++ depends on MPTCP ++ default n ++ ---help--- ++ Desynchronized MultiChannel TCP Congestion Control. This is experimental ++ code that only supports single path and must have set mptcp_ndiffports ++ larger than one. ++ To enable it, just put 'mctcpdesync' in tcp_congestion_control ++ For further details see: ++ http://ieeexplore.ieee.org/abstract/document/6911722/ ++ https://doi.org/10.1016/j.comcom.2015.07.010 ++ + choice + prompt "Default TCP congestion control" + default DEFAULT_CUBIC +@@ -692,6 +737,21 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_LIA ++ bool "Lia" if TCP_CONG_LIA=y ++ ++ config DEFAULT_OLIA ++ bool "Olia" if TCP_CONG_OLIA=y ++ ++ config DEFAULT_WVEGAS ++ bool "Wvegas" if TCP_CONG_WVEGAS=y ++ ++ config DEFAULT_BALIA ++ bool "Balia" if TCP_CONG_BALIA=y ++ ++ config DEFAULT_MCTCPDESYNC ++ bool "Mctcpdesync (EXPERIMENTAL)" if TCP_CONG_MCTCPDESYNC=y ++ + config DEFAULT_RENO + bool "Reno" + endchoice +@@ -712,6 +772,10 @@ + default "vegas" if DEFAULT_VEGAS + default "westwood" if DEFAULT_WESTWOOD + default "veno" if DEFAULT_VENO ++ default "lia" if DEFAULT_LIA ++ default "olia" if DEFAULT_OLIA ++ default "wvegas" if DEFAULT_WVEGAS ++ default "balia" if DEFAULT_BALIA + default "reno" if DEFAULT_RENO + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG +diff -aurN linux-5.4.64/net/ipv4/syncookies.c linux-5.4.64.mptcp/net/ipv4/syncookies.c +--- linux-5.4.64/net/ipv4/syncookies.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/syncookies.c 2020-09-10 19:25:10.503220935 +0200 +@@ -12,6 +12,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -175,7 +177,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); + +-__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v4_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct iphdr *iph = ip_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -200,14 +203,33 @@ + + struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, ++ const struct mptcp_options_received *mopt, + struct dst_entry *dst, u32 tsoff) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct sock *child; + bool own_req; ++#ifdef CONFIG_MPTCP ++ int ret; ++#endif + + child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst, + NULL, &own_req); ++ ++#ifdef CONFIG_MPTCP ++ if (!child) ++ goto listen_overflow; ++ ++ ret = mptcp_check_req_master(sk, child, req, skb, mopt, 0, tsoff); ++ if (ret < 0) ++ return NULL; ++ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ ++listen_overflow: ++#endif ++ + if (child) { + refcount_set(&req->rsk_refcnt, 1); + tcp_sk(child)->tsoffset = tsoff; +@@ -284,6 +306,7 @@ + { + struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct tcp_sock *tp = tcp_sk(sk); +@@ -313,7 +336,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcp_ts_off(sock_net(sk), +@@ -326,7 +350,12 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp_request_sock_ops, sk, false); /* for safety */ ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ + if (!req) + goto out; + +@@ -346,6 +375,8 @@ + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + treq->snt_synack = 0; + treq->tfo_listener = false; +@@ -354,6 +385,9 @@ + + ireq->ir_iif = inet_request_bound_dev_if(sk, skb); + ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + /* We throwed the options of the initial SYN away, so we hope + * the ACK carries the same options again (see RFC1122 4.2.3.8) + */ +@@ -387,15 +421,15 @@ + /* Try to redo what tcp_v4_send_synack did. */ + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); + +- tcp_select_initial_window(sk, tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(&rt->dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(&rt->dst, RTAX_INITRWND)); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); + +- ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst, tsoff); ++ ret = tcp_get_cookie_sock(sk, skb, req, &mopt, &rt->dst, tsoff); + /* ip_queue_xmit() depends on our flow being setup + * Normal sockets get it right from inet_csk_route_child_sock() + */ +diff -aurN linux-5.4.64/net/ipv4/tcp.c linux-5.4.64.mptcp/net/ipv4/tcp.c +--- linux-5.4.64/net/ipv4/tcp.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp.c 2020-09-10 19:44:12.204220735 +0200 +@@ -270,6 +270,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -400,6 +401,23 @@ + return rate64; + } + ++const struct tcp_sock_ops tcp_specific = { ++ .__select_window = __tcp_select_window, ++ .select_window = tcp_select_window, ++ .select_initial_window = tcp_select_initial_window, ++ .init_buffer_space = tcp_init_buffer_space, ++ .set_rto = tcp_set_rto, ++ .should_expand_sndbuf = tcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = tcp_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ + /* Address-family independent initialization for a tcp_sock. + * + * NOTE: A lot of things set to zero explicitly by call to +@@ -453,6 +471,11 @@ + WRITE_ONCE(sk->sk_sndbuf, sock_net(sk)->ipv4.sysctl_tcp_wmem[1]); + WRITE_ONCE(sk->sk_rcvbuf, sock_net(sk)->ipv4.sysctl_tcp_rmem[1]); + ++ tp->ops = &tcp_specific; ++ ++ /* Initialize MPTCP-specific stuff and function-pointers */ ++ mptcp_init_tcp_sock(sk); ++ + sk_sockets_allocated_inc(sk); + sk->sk_route_forced_caps = NETIF_F_GSO; + } +@@ -785,6 +808,7 @@ + int ret; + + sock_rps_record_flow(sk); ++ + /* + * We can't seek on a socket input + */ +@@ -795,6 +819,16 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++#endif ++ + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); + while (tss.len) { + ret = __tcp_splice_read(sk, &tss); +@@ -910,8 +944,7 @@ + return NULL; + } + +-static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, +- int large_allowed) ++unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, int large_allowed) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 new_size_goal, size_goal; +@@ -939,8 +972,13 @@ + { + int mss_now; + +- mss_now = tcp_current_mss(sk); +- *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ if (mptcp(tcp_sk(sk))) { ++ mss_now = mptcp_current_mss(sk); ++ *size_goal = mptcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } else { ++ mss_now = tcp_current_mss(sk); ++ *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); ++ } + + return mss_now; + } +@@ -979,12 +1017,34 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto out_err; + } + ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ /* We must check this with socket-lock hold because we iterate ++ * over the subflows. ++ */ ++ if (!mptcp_can_sendpage(sk)) { ++ ssize_t ret; ++ ++ release_sock(sk); ++ ret = sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ lock_sock(sk); ++ return ret; ++ } ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++ + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + + mss_now = tcp_send_mss(sk, &size_goal, flags); +@@ -1106,7 +1166,8 @@ + int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, + size_t size, int flags) + { +- if (!(sk->sk_route_caps & NETIF_F_SG)) ++ /* If MPTCP is enabled, we check it later after establishment */ ++ if (!mptcp(tcp_sk(sk)) && !(sk->sk_route_caps & NETIF_F_SG)) + return sock_no_sendpage_locked(sk, page, offset, size, flags); + + tcp_rate_check_app_limited(sk); /* is sending application-limited? */ +@@ -1228,12 +1289,21 @@ + * is fully established. + */ + if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && +- !tcp_passive_fastopen(sk)) { ++ !tcp_passive_fastopen(mptcp(tp) && tp->mpcb->master_sk ? ++ tp->mpcb->master_sk : sk)) { + err = sk_stream_wait_connect(sk, &timeo); + if (err != 0) + goto do_error; + } + ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++ + if (unlikely(tp->repair)) { + if (tp->repair_queue == TCP_RECV_QUEUE) { + copied = tcp_send_rcvq(sk, msg, size); +@@ -1526,7 +1596,7 @@ + * calculation of whether or not we must ACK for the sake of + * a window update. + */ +-static void tcp_cleanup_rbuf(struct sock *sk, int copied) ++void tcp_cleanup_rbuf(struct sock *sk, int copied) + { + struct tcp_sock *tp = tcp_sk(sk); + bool time_to_ack = false; +@@ -1569,7 +1639,7 @@ + + /* Optimize, __tcp_select_window() is not cheap. */ + if (2*rcv_window_now <= tp->window_clamp) { +- __u32 new_window = __tcp_select_window(sk); ++ __u32 new_window = tp->ops->__select_window(sk); + + /* Send ACK now, if this read freed lots of space + * in our buffer. Certainly, new_window is new window. +@@ -1685,7 +1755,7 @@ + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) { + tcp_recv_skb(sk, seq, &offset); +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + } + return copied; + } +@@ -1976,6 +2046,16 @@ + + lock_sock(sk); + ++#ifdef CONFIG_MPTCP ++ if (mptcp(tp)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sock_rps_record_flow(mptcp_to_sock(mptcp)); ++ } ++ } ++#endif ++ + err = -ENOTCONN; + if (sk->sk_state == TCP_LISTEN) + goto out; +@@ -2094,7 +2174,7 @@ + } + } + +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + if (copied >= target) { + /* Do not sleep, just process backlog. */ +@@ -2186,7 +2266,7 @@ + */ + + /* Clean up data we have read: This will do ACK frames. */ +- tcp_cleanup_rbuf(sk, copied); ++ tp->ops->cleanup_rbuf(sk, copied); + + release_sock(sk); + +@@ -2245,8 +2325,11 @@ + + switch (state) { + case TCP_ESTABLISHED: +- if (oldstate != TCP_ESTABLISHED) ++ if (oldstate != TCP_ESTABLISHED) { + TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ if (is_meta_sk(sk)) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB); ++ } + break; + + case TCP_CLOSE: +@@ -2259,8 +2342,11 @@ + inet_put_port(sk); + /* fall through */ + default: +- if (oldstate == TCP_ESTABLISHED) ++ if (oldstate == TCP_ESTABLISHED) { + TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ if (is_meta_sk(sk)) ++ MPTCP_DEC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB); ++ } + } + + /* Change state AFTER socket is unhashed to avoid closed +@@ -2294,7 +2380,7 @@ + [TCP_NEW_SYN_RECV] = TCP_CLOSE, /* should not happen ! */ + }; + +-static int tcp_close_state(struct sock *sk) ++int tcp_close_state(struct sock *sk) + { + int next = (int)new_state[sk->sk_state]; + int ns = next & TCP_STATE_MASK; +@@ -2324,7 +2410,7 @@ + TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { + /* Clear out any half completed packets. FIN if needed. */ + if (tcp_close_state(sk)) +- tcp_send_fin(sk); ++ tcp_sk(sk)->ops->send_fin(sk); + } + } + EXPORT_SYMBOL(tcp_shutdown); +@@ -2349,6 +2435,17 @@ + int data_was_unread = 0; + int state; + ++ if (is_meta_sk(sk)) { ++ /* TODO: Currently forcing timeout to 0 because ++ * sk_stream_wait_close will complain during lockdep because ++ * of the mpcb_mutex (circular lock dependency through ++ * inet_csk_listen_stop()). ++ * We should find a way to get rid of the mpcb_mutex. ++ */ ++ mptcp_close(sk, 0); ++ return; ++ } ++ + lock_sock(sk); + sk->sk_shutdown = SHUTDOWN_MASK; + +@@ -2393,7 +2490,7 @@ + /* Unread data was tossed, zap the connection. */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, sk->sk_allocation); ++ tcp_sk(sk)->ops->send_active_reset(sk, sk->sk_allocation); + } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + /* Check zero linger _after_ checking for unread data. */ + sk->sk_prot->disconnect(sk, 0); +@@ -2467,7 +2564,7 @@ + struct tcp_sock *tp = tcp_sk(sk); + if (tp->linger2 < 0) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONLINGER); + } else { +@@ -2477,7 +2574,8 @@ + inet_csk_reset_keepalive_timer(sk, + tmo - TCP_TIMEWAIT_LEN); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_FIN_WAIT2, ++ tmo); + goto out; + } + } +@@ -2486,7 +2584,7 @@ + sk_mem_reclaim(sk); + if (tcp_check_oom(sk, 0)) { + tcp_set_state(sk, TCP_CLOSE); +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + __NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { +@@ -2518,15 +2616,6 @@ + } + EXPORT_SYMBOL(tcp_close); + +-/* These states need RST on ABORT according to RFC793 */ +- +-static inline bool tcp_need_reset(int state) +-{ +- return (1 << state) & +- (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | +- TCPF_FIN_WAIT2 | TCPF_SYN_RECV); +-} +- + static void tcp_rtx_queue_purge(struct sock *sk) + { + struct rb_node *p = rb_first(&sk->tcp_rtx_queue); +@@ -2548,6 +2637,10 @@ + { + struct sk_buff *skb; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk) && ++ !tcp_rtx_and_write_queues_empty(sk)) ++ mptcp_reinject_data(sk, 0); ++ + tcp_chrono_stop(sk, TCP_CHRONO_BUSY); + while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { + tcp_skb_tsorted_anchor_cleanup(skb); +@@ -2566,6 +2659,35 @@ + inet_csk(sk)->icsk_backoff = 0; + } + ++void tcp_reset_vars(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tp->srtt_us = 0; ++ tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); ++ tp->rcv_rtt_last_tsecr = 0; ++ icsk->icsk_rto = TCP_TIMEOUT_INIT; ++ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ tp->snd_cwnd = TCP_INIT_CWND; ++ tp->snd_cwnd_cnt = 0; ++ tp->delivered = 0; ++ tp->delivered_ce = 0; ++ tp->is_sack_reneg = 0; ++ tcp_clear_retrans(tp); ++ tp->bytes_sent = 0; ++ tp->bytes_acked = 0; ++ tp->bytes_received = 0; ++ tp->bytes_retrans = 0; ++ tp->total_retrans = 0; ++ tp->segs_in = 0; ++ tp->segs_out = 0; ++ tp->data_segs_in = 0; ++ tp->data_segs_out = 0; ++ /* There's a bubble in the pipe until at least the first ACK. */ ++ tp->app_limited = ~0U; ++} ++ + int tcp_disconnect(struct sock *sk, int flags) + { + struct inet_sock *inet = inet_sk(sk); +@@ -2588,7 +2710,7 @@ + /* The last check adjusts for discrepancy of Linux wrt. RFC + * states + */ +- tcp_send_active_reset(sk, gfp_any()); ++ tp->ops->send_active_reset(sk, gfp_any()); + sk->sk_err = ECONNRESET; + } else if (old_state == TCP_SYN_SENT) + sk->sk_err = ECONNRESET; +@@ -2610,11 +2732,15 @@ + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) + inet_reset_saddr(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_disconnect(sk); ++ } else { ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ + sk->sk_shutdown = 0; + sock_reset_flag(sk, SOCK_DONE); +- tp->srtt_us = 0; +- tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); +- tp->rcv_rtt_last_tsecr = 0; + + seq = tp->write_seq + tp->max_window + 2; + if (!seq) +@@ -2624,20 +2750,14 @@ + icsk->icsk_backoff = 0; + tp->snd_cwnd = 2; + icsk->icsk_probes_out = 0; +- icsk->icsk_rto = TCP_TIMEOUT_INIT; +- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; +- tp->snd_cwnd = TCP_INIT_CWND; +- tp->snd_cwnd_cnt = 0; + tp->window_clamp = 0; +- tp->delivered = 0; +- tp->delivered_ce = 0; ++ ++ tcp_reset_vars(sk); ++ + if (icsk->icsk_ca_ops->release) + icsk->icsk_ca_ops->release(sk); + memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + tcp_set_ca_state(sk, TCP_CA_Open); +- tp->is_sack_reneg = 0; +- tcp_clear_retrans(tp); +- tp->total_retrans = 0; + inet_csk_delack_init(sk); + /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 + * issue in __tcp_select_window() +@@ -2649,14 +2769,6 @@ + sk->sk_rx_dst = NULL; + tcp_saved_syn_free(tp); + tp->compressed_ack = 0; +- tp->segs_in = 0; +- tp->segs_out = 0; +- tp->bytes_sent = 0; +- tp->bytes_acked = 0; +- tp->bytes_received = 0; +- tp->bytes_retrans = 0; +- tp->data_segs_in = 0; +- tp->data_segs_out = 0; + tp->duplicate_sack[0].start_seq = 0; + tp->duplicate_sack[0].end_seq = 0; + tp->dsack_dups = 0; +@@ -2665,8 +2777,6 @@ + tp->sacked_out = 0; + tp->tlp_high_seq = 0; + tp->last_oow_ack_time = 0; +- /* There's a bubble in the pipe until at least the first ACK. */ +- tp->app_limited = ~0U; + tp->rack.mstamp = 0; + tp->rack.advanced = 0; + tp->rack.reo_wnd_steps = 1; +@@ -2700,7 +2810,7 @@ + static inline bool tcp_can_repair_sock(const struct sock *sk) + { + return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && +- (sk->sk_state != TCP_LISTEN); ++ (sk->sk_state != TCP_LISTEN) && !sock_flag(sk, SOCK_MPTCP); + } + + static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) +@@ -2869,6 +2979,61 @@ + + return tcp_fastopen_reset_cipher(net, sk, key, backup_key); + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: { ++ char name[MPTCP_SCHED_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_SCHED_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_scheduler(sk, name); ++ release_sock(sk); ++ return err; ++ } ++ ++ case MPTCP_PATH_MANAGER: { ++ char name[MPTCP_PM_NAME_MAX]; ++ ++ if (optlen < 1) ++ return -EINVAL; ++ ++ /* Cannot be used if MPTCP is not used or we already have ++ * established an MPTCP-connection. ++ */ ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE) ++ return -EPERM; ++ ++ val = strncpy_from_user(name, optval, ++ min_t(long, MPTCP_PM_NAME_MAX - 1, ++ optlen)); ++ ++ if (val < 0) ++ return -EFAULT; ++ name[val] = 0; ++ ++ lock_sock(sk); ++ err = mptcp_set_path_manager(sk, name); ++ release_sock(sk); ++ return err; ++ } ++#endif + default: + /* fallthru */ + break; +@@ -3051,6 +3216,12 @@ + break; + + case TCP_DEFER_ACCEPT: ++ /* An established MPTCP-connection (mptcp(tp) only returns true ++ * if the socket is established) should not use DEFER on new ++ * subflows. ++ */ ++ if (mptcp(tp)) ++ break; + /* Translate value in seconds to number of retransmits */ + icsk->icsk_accept_queue.rskq_defer_accept = + secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, +@@ -3078,7 +3249,7 @@ + (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && + inet_csk_ack_scheduled(sk)) { + icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; +- tcp_cleanup_rbuf(sk, 1); ++ tp->ops->cleanup_rbuf(sk, 1); + if (!(val & 1)) + inet_csk_enter_pingpong_mode(sk); + } +@@ -3144,6 +3315,32 @@ + tp->notsent_lowat = val; + sk->sk_write_space(sk); + break; ++#ifdef CONFIG_MPTCP ++ case MPTCP_ENABLED: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled || ++ sk->sk_state != TCP_CLOSE ++#ifdef CONFIG_TCP_MD5SIG ++ || tp->md5sig_info ++#endif ++ ) { ++ err = -EPERM; ++ break; ++ } ++ ++ if (val) ++ mptcp_enable_sock(sk); ++ else ++ mptcp_disable_sock(sk); ++ break; ++ case MPTCP_INFO: ++ if (mptcp_init_failed || !sysctl_mptcp_enabled) { ++ err = -EPERM; ++ break; ++ } ++ ++ tp->record_master_info = !!(val & MPTCP_INFO_FLAG_SAVE_MASTER); ++ break; ++#endif + case TCP_INQ: + if (val > 1 || val < 0) + err = -EINVAL; +@@ -3208,7 +3405,7 @@ + } + + /* Return information about state of tcp endpoint in API format. */ +-void tcp_get_info(struct sock *sk, struct tcp_info *info) ++void tcp_get_info(struct sock *sk, struct tcp_info *info, bool no_lock) + { + const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ + const struct inet_connection_sock *icsk = inet_csk(sk); +@@ -3245,7 +3442,8 @@ + return; + } + +- slow = lock_sock_fast(sk); ++ if (!no_lock) ++ slow = lock_sock_fast(sk); + + info->tcpi_ca_state = icsk->icsk_ca_state; + info->tcpi_retransmits = icsk->icsk_retransmits; +@@ -3321,7 +3519,9 @@ + info->tcpi_reord_seen = tp->reord_seen; + info->tcpi_rcv_ooopack = tp->rcv_ooopack; + info->tcpi_snd_wnd = tp->snd_wnd; +- unlock_sock_fast(sk, slow); ++ ++ if (!no_lock) ++ unlock_sock_fast(sk, slow); + } + EXPORT_SYMBOL_GPL(tcp_get_info); + +@@ -3468,7 +3668,7 @@ + if (get_user(len, optlen)) + return -EFAULT; + +- tcp_get_info(sk, &info); ++ tcp_get_info(sk, &info, false); + + len = min_t(unsigned int, len, sizeof(info)); + if (put_user(len, optlen)) +@@ -3657,6 +3857,87 @@ + } + return 0; + } ++#ifdef CONFIG_MPTCP ++ case MPTCP_SCHEDULER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_SCHED_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->sched_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_sched_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_PATH_MANAGER: ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ len = min_t(unsigned int, len, MPTCP_PM_NAME_MAX); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ if (mptcp(tcp_sk(sk))) { ++ struct mptcp_cb *mpcb = tcp_sk(mptcp_meta_sk(sk))->mpcb; ++ ++ if (copy_to_user(optval, mpcb->pm_ops->name, len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } else { ++ if (copy_to_user(optval, tcp_sk(sk)->mptcp_pm_name, ++ len)) { ++ release_sock(sk); ++ return -EFAULT; ++ } ++ } ++ release_sock(sk); ++ return 0; ++ ++ case MPTCP_ENABLED: ++ if (sk->sk_state != TCP_SYN_SENT) ++ val = mptcp(tp) ? 1 : 0; ++ else ++ val = sock_flag(sk, SOCK_MPTCP) ? 1 : 0; ++ break; ++ case MPTCP_INFO: ++ { ++ int ret; ++ ++ if (!mptcp(tp)) ++ return -EINVAL; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(struct mptcp_info)); ++ ++ lock_sock(sk); ++ ret = mptcp_get_info(sk, optval, len); ++ release_sock(sk); ++ ++ if (ret) ++ return ret; ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ return 0; ++ } ++#endif + #ifdef CONFIG_MMU + case TCP_ZEROCOPY_RECEIVE: { + struct tcp_zerocopy_receive zc; +@@ -3862,7 +4143,9 @@ + if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); + ++ WARN_ON(sk->sk_state == TCP_CLOSE); + tcp_set_state(sk, TCP_CLOSE); ++ + tcp_clear_xmit_timers(sk); + if (req) + reqsk_fastopen_remove(sk, req, false); +@@ -3878,6 +4161,8 @@ + + int tcp_abort(struct sock *sk, int err) + { ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; ++ + if (!sk_fullsock(sk)) { + if (sk->sk_state == TCP_NEW_SYN_RECV) { + struct request_sock *req = inet_reqsk(sk); +@@ -3891,7 +4176,7 @@ + } + + /* Don't race with userspace socket closes such as tcp_close. */ +- lock_sock(sk); ++ lock_sock(meta_sk); + + if (sk->sk_state == TCP_LISTEN) { + tcp_set_state(sk, TCP_CLOSE); +@@ -3900,7 +4185,7 @@ + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); +- bh_lock_sock(sk); ++ bh_lock_sock(meta_sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = err; +@@ -3908,14 +4193,14 @@ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tcp_sk(sk)->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + local_bh_enable(); + tcp_write_queue_purge(sk); +- release_sock(sk); ++ release_sock(meta_sk); + return 0; + } + EXPORT_SYMBOL_GPL(tcp_abort); +diff -aurN linux-5.4.64/net/ipv4/tcp_cong.c linux-5.4.64.mptcp/net/ipv4/tcp_cong.c +--- linux-5.4.64/net/ipv4/tcp_cong.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_cong.c 2020-09-10 19:25:10.503220935 +0200 +@@ -328,13 +328,19 @@ + return ret; + } + ++int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) ++{ ++ return tcp_sk(sk)->ops->set_cong_ctrl(sk, name, load, reinit, cap_net_admin); ++} ++ + /* Change congestion control for socket. If load is false, then it is the + * responsibility of the caller to call tcp_init_congestion_control or + * tcp_reinit_congestion_control (if the current congestion control was + * already initialized. + */ +-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, +- bool reinit, bool cap_net_admin) ++int __tcp_set_congestion_control(struct sock *sk, const char *name, bool load, ++ bool reinit, bool cap_net_admin) + { + struct inet_connection_sock *icsk = inet_csk(sk); + const struct tcp_congestion_ops *ca; +diff -aurN linux-5.4.64/net/ipv4/tcp_diag.c linux-5.4.64.mptcp/net/ipv4/tcp_diag.c +--- linux-5.4.64/net/ipv4/tcp_diag.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_diag.c 2020-09-10 19:25:10.503220935 +0200 +@@ -31,7 +31,7 @@ + r->idiag_wqueue = READ_ONCE(tp->write_seq) - tp->snd_una; + } + if (info) +- tcp_get_info(sk, info); ++ tcp_get_info(sk, info, false); + } + + #ifdef CONFIG_TCP_MD5SIG +diff -aurN linux-5.4.64/net/ipv4/tcp_fastopen.c linux-5.4.64.mptcp/net/ipv4/tcp_fastopen.c +--- linux-5.4.64/net/ipv4/tcp_fastopen.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_fastopen.c 2020-09-10 19:25:10.503220935 +0200 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + void tcp_fastopen_init_key_once(struct net *net) + { +@@ -136,8 +137,6 @@ + const siphash_key_t *key, + struct tcp_fastopen_cookie *foc) + { +- BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64)); +- + if (req->rsk_ops->family == AF_INET) { + const struct iphdr *iph = ip_hdr(syn); + +@@ -258,8 +257,9 @@ + { + struct tcp_sock *tp; + struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; +- struct sock *child; ++ struct sock *child, *meta_sk; + bool own_req; ++ int ret; + + child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, + NULL, &own_req); +@@ -294,15 +294,26 @@ + + refcount_set(&req->rsk_refcnt, 2); + +- /* Now finish processing the fastopen child socket. */ +- tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB); +- + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + + tcp_fastopen_add_skb(child, skb); + + tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; + tp->rcv_wup = tp->rcv_nxt; ++ ++ meta_sk = child; ++ ret = mptcp_check_req_fastopen(meta_sk, req); ++ if (ret < 0) ++ return NULL; ++ ++ if (ret == 0) { ++ child = tcp_sk(meta_sk)->mpcb->master_sk; ++ tp = tcp_sk(child); ++ } ++ ++ /* Now finish processing the fastopen child socket. */ ++ tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB); ++ + /* tcp_conn_request() is sending the SYNACK, + * and queues the child into listener accept queue. + */ +diff -aurN linux-5.4.64/net/ipv4/tcp_input.c linux-5.4.64.mptcp/net/ipv4/tcp_input.c +--- linux-5.4.64/net/ipv4/tcp_input.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_input.c 2020-09-10 19:32:43.267687285 +0200 +@@ -76,35 +76,15 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include + + int sysctl_tcp_max_orphans __read_mostly = NR_FILE; + +-#define FLAG_DATA 0x01 /* Incoming frame contained data. */ +-#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ +-#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ +-#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +-#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ +-#define FLAG_DATA_SACKED 0x20 /* New SACK. */ +-#define FLAG_ECE 0x40 /* ECE in this ACK */ +-#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ +-#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ +-#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ +-#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ +-#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ +-#define FLAG_SET_XMIT_TIMER 0x1000 /* Set TLP or RTO timer */ +-#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ +-#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ +-#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ +-#define FLAG_ACK_MAYBE_DELAYED 0x10000 /* Likely a delayed ACK */ +- +-#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) +-#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) +-#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK) +-#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) +- + #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) + #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) + +@@ -349,8 +329,12 @@ + per_mss = roundup_pow_of_two(per_mss) + + SKB_DATA_ALIGN(sizeof(struct sk_buff)); + +- nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); +- nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ if (mptcp(tp)) { ++ nr_segs = mptcp_check_snd_buf(tp); ++ } else { ++ nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); ++ nr_segs = max_t(u32, nr_segs, tp->reordering + 1); ++ } + + /* Fast Recovery (RFC 5681 3.2) : + * Cubic needs 1.7 factor, rounded to 2 to include +@@ -359,9 +343,17 @@ + sndmem = ca_ops->sndbuf_expand ? ca_ops->sndbuf_expand(sk) : 2; + sndmem *= nr_segs * per_mss; + +- if (sk->sk_sndbuf < sndmem) ++ /* MPTCP: after this sndmem is the new contribution of the ++ * current subflow to the aggregated sndbuf */ ++ if (sk->sk_sndbuf < sndmem) { ++ int old_sndbuf = sk->sk_sndbuf; + WRITE_ONCE(sk->sk_sndbuf, + min(sndmem, sock_net(sk)->ipv4.sysctl_tcp_wmem[2])); ++ /* MPTCP: ok, the subflow sndbuf has grown, reflect ++ * this in the aggregate buffer.*/ ++ if (mptcp(tp) && old_sndbuf != sk->sk_sndbuf) ++ mptcp_update_sndbuf(tp); ++ } + } + + /* 2. Tuning advertised window (window_clamp, rcv_ssthresh) +@@ -410,9 +402,14 @@ + static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); + int room; + +- room = min_t(int, tp->window_clamp, tcp_space(sk)) - tp->rcv_ssthresh; ++ if (is_meta_sk(sk)) ++ return; ++ ++ room = min_t(int, meta_tp->window_clamp, tcp_space(meta_sk)) - meta_tp->rcv_ssthresh; + + /* Check #1 */ + if (room > 0 && !tcp_under_memory_pressure(sk)) { +@@ -422,13 +419,13 @@ + * will fit to rcvbuf in future. + */ + if (tcp_win_from_space(sk, skb->truesize) <= skb->len) +- incr = 2 * tp->advmss; ++ incr = 2 * meta_tp->advmss; + else +- incr = __tcp_grow_window(sk, skb); ++ incr = __tcp_grow_window(meta_sk, skb); + + if (incr) { + incr = max_t(int, incr, 2 * skb->len); +- tp->rcv_ssthresh += min(room, incr); ++ meta_tp->rcv_ssthresh += min(room, incr); + inet_csk(sk)->icsk_ack.quick |= 1; + } + } +@@ -611,7 +608,10 @@ + + tcp_mstamp_refresh(tp); + time = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcvq_space.time); +- if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) ++ if (mptcp(tp)) { ++ if (mptcp_check_rtt(tp, time)) ++ return; ++ } else if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) + return; + + /* Number of bytes copied to user in last RTT */ +@@ -834,7 +834,7 @@ + /* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. + */ +-static void tcp_set_rto(struct sock *sk) ++void tcp_set_rto(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + /* Old crap is replaced with new one. 8) +@@ -1406,6 +1406,13 @@ + int len; + int in_sack; + ++ /* For MPTCP we cannot shift skb-data and remove one skb from the ++ * send-queue, because this will make us loose the DSS-option (which ++ * is stored in TCP_SKB_CB(skb)->dss) of the skb we are removing. ++ */ ++ if (mptcp(tp)) ++ goto fallback; ++ + /* Normally R but no L won't result in plain S */ + if (!dup_sack && + (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS) +@@ -2960,7 +2967,7 @@ + */ + tcp_update_rtt_min(sk, ca_rtt_us, flag); + tcp_rtt_estimator(sk, seq_rtt_us); +- tcp_set_rto(sk); ++ tp->ops->set_rto(sk); + + /* RFC6298: only reset backoff on valid RTT measurement. */ + inet_csk(sk)->icsk_backoff = 0; +@@ -3028,7 +3035,7 @@ + } + + /* If we get here, the whole TSO packet has not been acked. */ +-static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) ++u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 packets_acked; +@@ -3048,8 +3055,7 @@ + return packets_acked; + } + +-static void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb, +- u32 prior_snd_una) ++void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb, u32 prior_snd_una) + { + const struct skb_shared_info *shinfo; + +@@ -3154,6 +3160,8 @@ + */ + if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { + flag |= FLAG_DATA_ACKED; ++ if (mptcp(tp) && mptcp_is_data_seq(skb)) ++ flag |= MPTCP_FLAG_DATA_ACKED; + } else { + flag |= FLAG_SYN_ACKED; + tp->retrans_stamp = 0; +@@ -3274,7 +3282,7 @@ + return flag; + } + +-static void tcp_ack_probe(struct sock *sk) ++void tcp_ack_probe(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct sk_buff *head = tcp_send_head(sk); +@@ -3346,9 +3354,8 @@ + /* Check that window update is acceptable. + * The function assumes that snd_una<=ack<=snd_next. + */ +-static inline bool tcp_may_update_window(const struct tcp_sock *tp, +- const u32 ack, const u32 ack_seq, +- const u32 nwin) ++bool tcp_may_update_window(const struct tcp_sock *tp, const u32 ack, ++ const u32 ack_seq, const u32 nwin) + { + return after(ack, tp->snd_una) || + after(ack_seq, tp->snd_wl1) || +@@ -3586,7 +3593,7 @@ + } + + /* This routine deals with incoming acks, but not outgoing ones. */ +-static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) ++static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -3709,6 +3716,16 @@ + + tcp_rack_update_reo_wnd(sk, &rs); + ++ if (mptcp(tp)) { ++ if (mptcp_fallback_infinite(sk, flag)) { ++ pr_debug("%s resetting flow\n", __func__); ++ mptcp_send_reset(sk); ++ return -1; ++ } ++ ++ mptcp_clean_rtx_infinite(skb, sk); ++ } ++ + if (tp->tlp_high_seq) + tcp_process_tlp_ack(sk, ack, flag); + /* If needed, reset TLP/RTO timer; RACK may later override this. */ +@@ -3851,8 +3868,10 @@ + */ + void tcp_parse_options(const struct net *net, + const struct sk_buff *skb, +- struct tcp_options_received *opt_rx, int estab, +- struct tcp_fastopen_cookie *foc) ++ struct tcp_options_received *opt_rx, ++ struct mptcp_options_received *mopt, ++ int estab, struct tcp_fastopen_cookie *foc, ++ struct tcp_sock *tp) + { + const unsigned char *ptr; + const struct tcphdr *th = tcp_hdr(skb); +@@ -3938,6 +3957,10 @@ + */ + break; + #endif ++ case TCPOPT_MPTCP: ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, tp); ++ break; ++ + case TCPOPT_FASTOPEN: + tcp_parse_fastopen_option( + opsize - TCPOLEN_FASTOPEN_BASE, +@@ -4005,7 +4028,9 @@ + return true; + } + +- tcp_parse_options(net, skb, &tp->rx_opt, 1, NULL); ++ tcp_parse_options(net, skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : NULL, 1, NULL, tp); ++ + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -4164,6 +4189,11 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ if (is_meta_sk(sk)) { ++ mptcp_fin(sk); ++ return; ++ } ++ + inet_csk_schedule_ack(sk); + + sk->sk_shutdown |= RCV_SHUTDOWN; +@@ -4174,6 +4204,10 @@ + case TCP_ESTABLISHED: + /* Move to CLOSE_WAIT */ + tcp_set_state(sk, TCP_CLOSE_WAIT); ++ ++ if (mptcp(tp)) ++ mptcp_sub_close_passive(sk); ++ + inet_csk_enter_pingpong_mode(sk); + break; + +@@ -4196,9 +4230,16 @@ + tcp_set_state(sk, TCP_CLOSING); + break; + case TCP_FIN_WAIT2: ++ if (mptcp(tp)) { ++ /* The socket will get closed by mptcp_data_ready. ++ * We first have to process all data-sequences. ++ */ ++ tp->close_it = 1; ++ break; ++ } + /* Received a FIN -- send ACK and enter TIME_WAIT. */ + tcp_send_ack(sk); +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + break; + default: + /* Only TCP_LISTEN and TCP_CLOSE are left, in these +@@ -4220,6 +4261,10 @@ + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + ++ /* Don't wake up MPTCP-subflows */ ++ if (mptcp(tp)) ++ return; ++ + /* Do not send POLL_HUP for half duplex close. */ + if (sk->sk_shutdown == SHUTDOWN_MASK || + sk->sk_state == TCP_CLOSE) +@@ -4434,6 +4479,9 @@ + + *fragstolen = false; + ++ if (mptcp(tcp_sk(sk)) && !is_meta_sk(sk)) ++ return false; ++ + /* Its possible this segment overlaps with prior segment in queue */ + if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) + return false; +@@ -4488,7 +4536,7 @@ + /* This one checks to see if we can put data from the + * out_of_order queue into the receive_queue. + */ +-static void tcp_ofo_queue(struct sock *sk) ++void tcp_ofo_queue(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + __u32 dsack_high = tp->rcv_nxt; +@@ -4511,7 +4559,14 @@ + p = rb_next(p); + rb_erase(&skb->rbnode, &tp->out_of_order_queue); + +- if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { ++ /* In case of MPTCP, the segment may be empty if it's a ++ * non-data DATA_FIN. (see beginning of tcp_data_queue) ++ * ++ * But this only holds true for subflows, not for the ++ * meta-socket. ++ */ ++ if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt) && ++ (is_meta_sk(sk) || !mptcp(tp) || TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq))) { + tcp_drop(sk, skb); + continue; + } +@@ -4541,6 +4596,9 @@ + static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, + unsigned int size) + { ++ if (mptcp(tcp_sk(sk))) ++ sk = mptcp_meta_sk(sk); ++ + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule(sk, skb, size)) { + +@@ -4555,7 +4613,7 @@ + return 0; + } + +-static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) ++void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + struct rb_node **p, *parent; +@@ -4627,7 +4685,8 @@ + continue; + } + if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { +- if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq) && ++ (is_meta_sk(sk) || !mptcp(tp) || end_seq != seq)) { + /* All the bits are present. Drop. */ + NET_INC_STATS(sock_net(sk), + LINUX_MIB_TCPOFOMERGE); +@@ -4674,6 +4733,11 @@ + end_seq); + break; + } ++ /* MPTCP allows non-data data-fin to be in the ofo-queue */ ++ if (mptcp(tp) && !is_meta_sk(sk) && TCP_SKB_CB(skb1)->seq == TCP_SKB_CB(skb1)->end_seq) { ++ skb = skb1; ++ continue; ++ } + rb_erase(&skb1->rbnode, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); +@@ -4685,7 +4749,7 @@ + tp->ooo_last_skb = skb; + + add_sack: +- if (tcp_is_sack(tp)) ++ if (tcp_is_sack(tp) && seq != end_seq) + tcp_sack_new_ofo_skb(sk, seq, end_seq); + end: + if (skb) { +@@ -4699,8 +4763,8 @@ + } + } + +-static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, +- bool *fragstolen) ++int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, ++ bool *fragstolen) + { + int eaten; + struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); +@@ -4774,7 +4838,7 @@ + int avail = tp->rcv_nxt - tp->copied_seq; + + if (avail < sk->sk_rcvlowat && !tcp_rmem_pressure(sk) && +- !sock_flag(sk, SOCK_DONE)) ++ !sock_flag(sk, SOCK_DONE) && !mptcp(tp)) + return; + + sk->sk_data_ready(sk); +@@ -4786,10 +4850,14 @@ + bool fragstolen; + int eaten; + +- if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { ++ /* If no data is present, but a data_fin is in the options, we still ++ * have to call mptcp_queue_skb later on. */ ++ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && ++ !(mptcp(tp) && mptcp_is_data_fin(skb))) { + __kfree_skb(skb); + return; + } ++ + skb_dst_drop(skb); + __skb_pull(skb, tcp_hdr(skb)->doff * 4); + +@@ -4816,7 +4884,7 @@ + } + + eaten = tcp_queue_rcv(sk, skb, &fragstolen); +- if (skb->len) ++ if (skb->len || mptcp_is_data_fin(skb)) + tcp_event_data_recv(sk, skb); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) + tcp_fin(sk); +@@ -4838,7 +4906,11 @@ + + if (eaten > 0) + kfree_skb_partial(skb, fragstolen); +- if (!sock_flag(sk, SOCK_DEAD)) ++ if (!sock_flag(sk, SOCK_DEAD) || mptcp(tp)) ++ /* MPTCP: we always have to call data_ready, because ++ * we may be about to receive a data-fin, which still ++ * must get queued. ++ */ + tcp_data_ready(sk); + return; + } +@@ -5181,7 +5253,7 @@ + return -1; + } + +-static bool tcp_should_expand_sndbuf(const struct sock *sk) ++bool tcp_should_expand_sndbuf(const struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + +@@ -5216,7 +5288,7 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + +- if (tcp_should_expand_sndbuf(sk)) { ++ if (tp->ops->should_expand_sndbuf(sk)) { + tcp_sndbuf_expand(sk); + tp->snd_cwnd_stamp = tcp_jiffies32; + } +@@ -5230,10 +5302,11 @@ + sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); + /* pairs with tcp_poll() */ + smp_mb(); +- if (sk->sk_socket && +- test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ if (mptcp(tcp_sk(sk)) || ++ (sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))) { + tcp_new_space(sk); +- if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) ++ if (sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) + tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); + } + } +@@ -5252,6 +5325,8 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + unsigned long rtt, delay; ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); + + /* More than one full frame received... */ + if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && +@@ -5260,8 +5335,8 @@ + * If application uses SO_RCVLOWAT, we want send ack now if + * we have not received enough bytes to satisfy the condition. + */ +- (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || +- __tcp_select_window(sk) >= tp->rcv_wnd)) || ++ (meta_tp->rcv_nxt - meta_tp->copied_seq < meta_sk->sk_rcvlowat || ++ tp->ops->__select_window(sk) >= tp->rcv_wnd)) || + /* We ACK each frame or... */ + tcp_in_quickack_mode(sk) || + /* Protocol state mandates a one-time immediate ACK */ +@@ -5396,6 +5471,10 @@ + { + struct tcp_sock *tp = tcp_sk(sk); + ++ /* MPTCP urgent data is not yet supported */ ++ if (mptcp(tp)) ++ return; ++ + /* Check if we get a new urgent pointer - normally not. */ + if (th->urg) + tcp_check_urg(sk, th); +@@ -5538,9 +5617,15 @@ + goto discard; + } + ++ /* If valid: post process the received MPTCP options. */ ++ if (mptcp(tp) && mptcp_handle_options(sk, th, skb)) ++ goto discard; ++ + return true; + + discard: ++ if (mptcp(tp)) ++ mptcp_reset_mopt(tp); + tcp_drop(sk, skb); + return false; + } +@@ -5597,6 +5682,10 @@ + + tp->rx_opt.saw_tstamp = 0; + ++ /* MPTCP: force slowpath. */ ++ if (mptcp(tp)) ++ goto slow_path; ++ + /* pred_flags is 0xS?10 << 16 + snd_wnd + * if header_prediction is to be made + * 'S' will always be tp->tcp_header_len >> 2 +@@ -5769,7 +5858,7 @@ + + tcp_call_bpf(sk, bpf_op, 0, NULL); + tcp_init_congestion_control(sk); +- tcp_init_buffer_space(sk); ++ tcp_sk(sk)->ops->init_buffer_space(sk); + } + + void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) +@@ -5806,17 +5895,24 @@ + struct tcp_fastopen_cookie *cookie) + { + struct tcp_sock *tp = tcp_sk(sk); +- struct sk_buff *data = tp->syn_data ? tcp_rtx_queue_head(sk) : NULL; ++ struct sk_buff *data = NULL; + u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; + bool syn_drop = false; + ++ if (tp->syn_data) { ++ if (mptcp(tp)) ++ data = tcp_write_queue_head(mptcp_meta_sk(sk)); ++ else ++ data = tcp_rtx_queue_head(sk); ++ } ++ + if (mss == tp->rx_opt.user_mss) { + struct tcp_options_received opt; + + /* Get original SYNACK MSS value if user MSS sets mss_clamp */ + tcp_clear_options(&opt); + opt.user_mss = opt.mss_clamp = 0; +- tcp_parse_options(sock_net(sk), synack, &opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), synack, &opt, NULL, 0, NULL, NULL); + mss = opt.mss_clamp; + } + +@@ -5840,7 +5936,11 @@ + + tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); + +- if (data) { /* Retransmit unacked data in SYN */ ++ /* In mptcp case, we do not rely on "retransmit", but instead on ++ * "transmit", because if fastopen data is not acked, the retransmission ++ * becomes the first MPTCP data (see mptcp_rcv_synsent_fastopen). ++ */ ++ if (data && !mptcp(tp)) { /* Retransmit unacked data in SYN */ + skb_rbtree_walk_from(data) { + if (__tcp_retransmit_skb(sk, data, 1)) + break; +@@ -5895,9 +5995,13 @@ + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_fastopen_cookie foc = { .len = -1 }; + int saved_clamp = tp->rx_opt.mss_clamp; ++ struct mptcp_options_received mopt; + bool fastopen_fail; + +- tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, 0, &foc); ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, ++ mptcp(tp) ? &tp->mptcp->rx_opt : &mopt, 0, &foc, tp); + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) + tp->rx_opt.rcv_tsecr -= tp->tsoffset; + +@@ -5958,6 +6062,35 @@ + tcp_try_undo_spurious_syn(sk); + tcp_ack(sk, skb, FLAG_SLOWPATH); + ++ if (tp->request_mptcp || mptcp(tp)) { ++ int ret; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ ret = mptcp_rcv_synsent_state_process(sk, &sk, ++ skb, &mopt); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ /* May have changed if we support MPTCP */ ++ tp = tcp_sk(sk); ++ icsk = inet_csk(sk); ++ ++ if (ret == 1) ++ goto reset_and_undo; ++ if (ret == 2) ++ goto discard; ++ } ++ ++ if (mptcp(tp) && !is_master_tp(tp)) { ++ /* Timer for repeating the ACK until an answer ++ * arrives. Used only when establishing an additional ++ * subflow inside of an MPTCP connection. ++ */ ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ } ++ + /* Ok.. it's good. Set up sequence numbers and + * move to established. + */ +@@ -5984,6 +6117,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); + tcp_initialize_rcv_mss(sk); + +@@ -6007,9 +6145,12 @@ + } + if (fastopen_fail) + return -1; +- if (sk->sk_write_pending || ++ /* With MPTCP we cannot send data on the third ack due to the ++ * lack of option-space to combine with an MP_CAPABLE. ++ */ ++ if (!mptcp(tp) && (sk->sk_write_pending || + icsk->icsk_accept_queue.rskq_defer_accept || +- inet_csk_in_pingpong_mode(sk)) { ++ inet_csk_in_pingpong_mode(sk))) { + /* Save one ACK. Data will be ready after + * several ticks, if write_pending is set. + * +@@ -6048,6 +6189,7 @@ + tcp_paws_reject(&tp->rx_opt, 0)) + goto discard_and_undo; + ++ /* TODO - check this here for MPTCP */ + if (th->syn) { + /* We see SYN without ACK. It is attempt of + * simultaneous connect with crossed SYNs. +@@ -6064,6 +6206,11 @@ + tp->tcp_header_len = sizeof(struct tcphdr); + } + ++ if (mptcp(tp)) { ++ tp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; ++ } ++ + WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1); + WRITE_ONCE(tp->copied_seq, tp->rcv_nxt); + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; +@@ -6154,6 +6301,7 @@ + */ + + int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) ++ __releases(&sk->sk_lock.slock) + { + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -6196,6 +6344,16 @@ + tp->rx_opt.saw_tstamp = 0; + tcp_mstamp_refresh(tp); + queued = tcp_rcv_synsent_state_process(sk, skb, th); ++ if (is_meta_sk(sk)) { ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ tp = tcp_sk(sk); ++ ++ /* Need to call it here, because it will announce new ++ * addresses, which can only be done after the third ack ++ * of the 3-way handshake. ++ */ ++ mptcp_update_metasocket(tp->meta_sk); ++ } + if (queued >= 0) + return queued; + +@@ -6268,6 +6426,8 @@ + + if (tp->rx_opt.tstamp_ok) + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; ++ if (mptcp(tp)) ++ tp->advmss -= MPTCP_SUB_LEN_DSM_ALIGN; + + if (!inet_csk(sk)->icsk_ca_ops->cong_control) + tcp_update_pacing_rate(sk); +@@ -6277,6 +6437,30 @@ + + tcp_initialize_rcv_mss(sk); + tcp_fast_path_on(tp); ++ ++ /* Send an ACK when establishing a new MPTCP subflow, i.e. ++ * using an MP_JOIN subtype. ++ */ ++ if (mptcp(tp)) { ++ if (is_master_tp(tp)) { ++ mptcp_update_metasocket(mptcp_meta_sk(sk)); ++ } else { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ tcp_send_ack(sk); ++ ++ /* Update RTO as it might be worse/better */ ++ mptcp_set_rto(sk); ++ ++ /* If the new RTO would fire earlier, pull it in! */ ++ if (tcp_sk(meta_sk)->packets_out && ++ icsk->icsk_timeout > inet_csk(meta_sk)->icsk_rto + jiffies) { ++ tcp_rearm_rto(meta_sk); ++ } ++ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++ } ++ } + break; + + case TCP_FIN_WAIT1: { +@@ -6317,7 +6501,8 @@ + tmo = tcp_fin_time(sk); + if (tmo > TCP_TIMEWAIT_LEN) { + inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); +- } else if (th->fin || sock_owned_by_user(sk)) { ++ } else if (th->fin || mptcp_is_data_fin(skb) || ++ sock_owned_by_user(sk)) { + /* Bad case. We could lose such FIN otherwise. + * It is not a big problem, but it looks confusing + * and not so rare event. We still can lose it now, +@@ -6326,7 +6511,7 @@ + */ + inet_csk_reset_keepalive_timer(sk, tmo); + } else { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto discard; + } + break; +@@ -6334,7 +6519,7 @@ + + case TCP_CLOSING: + if (tp->snd_una == tp->write_seq) { +- tcp_time_wait(sk, TCP_TIME_WAIT, 0); ++ tp->ops->time_wait(sk, TCP_TIME_WAIT, 0); + goto discard; + } + break; +@@ -6346,6 +6531,9 @@ + goto discard; + } + break; ++ case TCP_CLOSE: ++ if (tp->mp_killed) ++ goto discard; + } + + /* step 6: check the URG bit */ +@@ -6367,7 +6555,8 @@ + */ + if (sk->sk_shutdown & RCV_SHUTDOWN) { + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && +- after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp(tp)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); + tcp_reset(sk); + return 1; +@@ -6469,6 +6658,8 @@ + ireq->wscale_ok = rx_opt->wscale_ok; + ireq->acked = 0; + ireq->ecn_ok = 0; ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + ireq->ir_rmt_port = tcp_hdr(skb)->source; + ireq->ir_num = ntohs(tcp_hdr(skb)->dest); + ireq->ir_mark = inet_request_mark(sk, skb); +@@ -6594,12 +6785,17 @@ + /* TW buckets are converted to open requests without + * limitations, they conserve resources and peer is + * evidently real one. ++ * ++ * MPTCP: new subflows cannot be established in a stateless manner. + */ +- if ((net->ipv4.sysctl_tcp_syncookies == 2 || ++ if (((!is_meta_sk(sk) && net->ipv4.sysctl_tcp_syncookies == 2) || + inet_csk_reqsk_queue_is_full(sk)) && !isn) { + want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name); + if (!want_cookie) + goto drop; ++ ++ if (is_meta_sk(sk)) ++ goto drop; + } + + if (sk_acceptq_is_full(sk)) { +@@ -6617,8 +6813,8 @@ + tcp_clear_options(&tmp_opt); + tmp_opt.mss_clamp = af_ops->mss_clamp; + tmp_opt.user_mss = tp->rx_opt.user_mss; +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, +- want_cookie ? NULL : &foc); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, NULL, 0, ++ want_cookie ? NULL : &foc, NULL); + + if (want_cookie && !tmp_opt.saw_tstamp) + tcp_clear_options(&tmp_opt); +@@ -6633,7 +6829,8 @@ + /* Note: tcp_v6_init_req() might override ir_iif for link locals */ + inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); + +- af_ops->init_req(req, sk, skb); ++ if (af_ops->init_req(req, sk, skb, want_cookie)) ++ goto drop_and_free; + + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_free; +@@ -6669,7 +6866,7 @@ + tcp_ecn_create_request(req, skb, sk, dst); + + if (want_cookie) { +- isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); ++ isn = cookie_init_sequence(af_ops, req, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + if (!tmp_opt.tstamp_ok) + inet_rsk(req)->ecn_ok = 0; +@@ -6684,17 +6881,25 @@ + fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); + } + if (fastopen_sk) { ++ struct sock *meta_sk = fastopen_sk; ++ ++ if (mptcp(tcp_sk(fastopen_sk))) ++ meta_sk = mptcp_meta_sk(fastopen_sk); + af_ops->send_synack(fastopen_sk, dst, &fl, req, + &foc, TCP_SYNACK_FASTOPEN); + /* Add the child socket directly into the accept queue */ +- if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) { ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { + reqsk_fastopen_remove(fastopen_sk, req, false); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + goto drop_and_free; + } + sk->sk_data_ready(sk); + bh_unlock_sock(fastopen_sk); ++ if (meta_sk != fastopen_sk) ++ bh_unlock_sock(meta_sk); + sock_put(fastopen_sk); + } else { + tcp_rsk(req)->tfo_listener = false; +diff -aurN linux-5.4.64/net/ipv4/tcp_ipv4.c linux-5.4.64.mptcp/net/ipv4/tcp_ipv4.c +--- linux-5.4.64/net/ipv4/tcp_ipv4.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_ipv4.c 2020-09-10 19:25:10.503220935 +0200 +@@ -62,6 +62,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -209,6 +211,8 @@ + struct ip_options_rcu *inet_opt; + struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; + ++ mptcp_init_connect(sk); ++ + if (addr_len < sizeof(struct sockaddr_in)) + return -EINVAL; + +@@ -430,7 +434,7 @@ + struct inet_sock *inet; + const int type = icmp_hdr(icmp_skb)->type; + const int code = icmp_hdr(icmp_skb)->code; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + struct sk_buff *skb; + struct request_sock *fastopen; + u32 seq, snd_una; +@@ -460,13 +464,19 @@ + return 0; + } + +- bh_lock_sock(sk); ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); + /* If too many ICMPs get dropped on busy + * servers this needs to be solved differently. + * We do take care of PMTU discovery (RFC1191) special case : + * we can receive locally generated ICMP messages while socket is held. + */ +- if (sock_owned_by_user(sk)) { ++ if (sock_owned_by_user(meta_sk)) { + if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + } +@@ -479,7 +489,6 @@ + } + + icsk = inet_csk(sk); +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = rcu_dereference(tp->fastopen_rsk); + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -513,11 +522,13 @@ + goto out; + + tp->mtu_info = info; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v4_mtu_reduced(sk); + } else { + if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } + goto out; + } +@@ -531,7 +542,7 @@ + !icsk->icsk_backoff || fastopen) + break; + +- if (sock_owned_by_user(sk)) ++ if (sock_owned_by_user(meta_sk)) + break; + + skb = tcp_rtx_queue_head(sk); +@@ -555,7 +566,7 @@ + } else { + /* RTO revert clocked out retransmission. + * Will retransmit now */ +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + } + + break; +@@ -575,7 +586,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + + sk->sk_error_report(sk); +@@ -604,7 +615,7 @@ + */ + + inet = inet_sk(sk); +- if (!sock_owned_by_user(sk) && inet->recverr) { ++ if (!sock_owned_by_user(meta_sk) && inet->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else { /* Only an error on timeout */ +@@ -612,7 +623,7 @@ + } + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + return 0; + } +@@ -648,7 +659,7 @@ + * Exception: precedence violation. We do not implement it in any case. + */ + +-static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -800,10 +811,10 @@ + */ + + static void tcp_v4_send_ack(const struct sock *sk, +- struct sk_buff *skb, u32 seq, u32 ack, ++ struct sk_buff *skb, u32 seq, u32 ack, u32 data_ack, + u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, +- int reply_flags, u8 tos) ++ int reply_flags, u8 tos, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct { +@@ -812,6 +823,10 @@ + #ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) + #endif ++#ifdef CONFIG_MPTCP ++ + ((MPTCP_SUB_LEN_DSS >> 2) + ++ (MPTCP_SUB_LEN_ACK >> 2)) ++#endif + ]; + } rep; + struct net *net = sock_net(sk); +@@ -858,6 +873,21 @@ + ip_hdr(skb)->daddr, &rep.th); + } + #endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ int offset = (tsecr) ? 3 : 0; ++ /* Construction of 32-bit data_ack */ ++ rep.opt[offset++] = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ rep.opt[offset] = htonl(data_ack); ++ ++ arg.iov[0].iov_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++ rep.th.doff = arg.iov[0].iov_len / 4; ++ } ++#endif /* CONFIG_MPTCP */ ++ + arg.flags = reply_flags; + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, /* XXX */ +@@ -889,28 +919,36 @@ + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; ++ ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + + tcp_v4_send_ack(sk, skb, +- tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, + tw->tw_bound_dev_if, + tcp_twsk_md5_key(tcptw), + tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, +- tw->tw_tos ++ tw->tw_tos, mptcp + ); + + inet_twsk_put(tw); + } + +-static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. + */ +- u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : ++ u32 seq = (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? ++ tcp_rsk(req)->snt_isn + 1 : + tcp_sk(sk)->snd_nxt; + + /* RFC 7323 2.3 +@@ -919,7 +957,7 @@ + * Rcv.Wind.Shift bits: + */ + tcp_v4_send_ack(sk, skb, seq, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, +@@ -927,7 +965,7 @@ + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, + AF_INET), + inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, +- ip_hdr(skb)->tos); ++ ip_hdr(skb)->tos, 0); + } + + /* +@@ -935,11 +973,11 @@ + * This still operates on a request_sock only, not on a big + * socket. + */ +-static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, +- struct flowi *fl, +- struct request_sock *req, +- struct tcp_fastopen_cookie *foc, +- enum tcp_synack_type synack_type) ++int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, ++ struct flowi *fl, ++ struct request_sock *req, ++ struct tcp_fastopen_cookie *foc, ++ enum tcp_synack_type synack_type) + { + const struct inet_request_sock *ireq = inet_rsk(req); + struct flowi4 fl4; +@@ -969,7 +1007,7 @@ + /* + * IPv4 request_sock destructor. + */ +-static void tcp_v4_reqsk_destructor(struct request_sock *req) ++void tcp_v4_reqsk_destructor(struct request_sock *req) + { + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + } +@@ -1354,9 +1392,10 @@ + return false; + } + +-static void tcp_v4_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v4_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + struct inet_request_sock *ireq = inet_rsk(req); + struct net *net = sock_net(sk_listener); +@@ -1364,6 +1403,8 @@ + sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); + sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); ++ ++ return 0; + } + + static struct dst_entry *tcp_v4_route_req(const struct sock *sk, +@@ -1383,7 +1424,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { + .mss_clamp = TCP_MSS_DEFAULT, + #ifdef CONFIG_TCP_MD5SIG + .req_md5_lookup = tcp_v4_md5_lookup, +@@ -1520,7 +1561,7 @@ + } + EXPORT_SYMBOL(tcp_v4_syn_recv_sock); + +-static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1558,6 +1599,9 @@ + { + struct sock *rsk; + ++ if (is_meta_sk(sk)) ++ return mptcp_v4_do_rcv(sk, skb); ++ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst = sk->sk_rx_dst; + +@@ -1802,6 +1846,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff * 4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); +@@ -1821,8 +1869,8 @@ + int sdif = inet_sdif(skb); + const struct iphdr *iph; + const struct tcphdr *th; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + + if (skb->pkt_type != PACKET_HOST) +@@ -1876,7 +1924,11 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ goto lookup; ++ } ++ if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } +@@ -1885,6 +1937,7 @@ + */ + sock_hold(sk); + refcounted = true; ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1945,19 +1998,28 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + skb_to_free = sk->sk_rx_skb_cache; + sk->sk_rx_skb_cache = NULL; + ret = tcp_v4_do_rcv(sk, skb); + } else { +- if (tcp_add_backlog(sk, skb)) ++ if (tcp_add_backlog(meta_sk, skb)) + goto discard_and_relse; + skb_to_free = NULL; + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + if (skb_to_free) + __kfree_skb(skb_to_free); + +@@ -1973,6 +2035,19 @@ + + tcp_v4_fill_cb(skb, iph, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -2021,6 +2096,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v4_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + } + /* to ACK */ + /* fall through */ +@@ -2090,7 +2177,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; +@@ -2109,6 +2201,11 @@ + + tcp_cleanup_congestion_control(sk); + ++ if (mptcp(tp)) ++ mptcp_destroy_sock(sk); ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ + tcp_cleanup_ulp(sk); + + /* Cleanup up the write buffer. */ +@@ -2613,6 +2710,11 @@ + .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), + .max_header = MAX_TCP_HEADER, + .obj_size = sizeof(struct tcp_sock), ++#ifdef CONFIG_MPTCP ++ .useroffset = offsetof(struct tcp_sock, mptcp_sched_name), ++ .usersize = sizeof_field(struct tcp_sock, mptcp_sched_name) + ++ sizeof_field(struct tcp_sock, mptcp_pm_name), ++#endif + .slab_flags = SLAB_TYPESAFE_BY_RCU, + .twsk_prot = &tcp_timewait_sock_ops, + .rsk_prot = &tcp_request_sock_ops, +@@ -2623,6 +2725,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + EXPORT_SYMBOL(tcp_prot); + +diff -aurN linux-5.4.64/net/ipv4/tcp_minisocks.c linux-5.4.64.mptcp/net/ipv4/tcp_minisocks.c +--- linux-5.4.64/net/ipv4/tcp_minisocks.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_minisocks.c 2020-09-10 19:25:10.503220935 +0200 +@@ -19,11 +19,13 @@ + * Jorge Cwik, + */ + ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -95,10 +97,14 @@ + struct tcp_options_received tmp_opt; + struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); + bool paws_reject = false; ++ struct mptcp_options_received mopt; + + tmp_opt.saw_tstamp = 0; +- if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { +- tcp_parse_options(twsk_net(tw), skb, &tmp_opt, 0, NULL); ++ if (th->doff > (sizeof(*th) >> 2) && ++ (tcptw->tw_ts_recent_stamp || tcptw->mptcp_tw)) { ++ mptcp_init_mp_opt(&mopt); ++ ++ tcp_parse_options(twsk_net(tw), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + if (tmp_opt.rcv_tsecr) +@@ -107,6 +113,11 @@ + tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; + paws_reject = tcp_paws_reject(&tmp_opt, th->rst); + } ++ ++ if (unlikely(mopt.mp_fclose) && tcptw->mptcp_tw) { ++ if (mopt.mptcp_sender_key == tcptw->mptcp_tw->loc_key) ++ return TCP_TW_RST; ++ } + } + + if (tw->tw_substate == TCP_FIN_WAIT2) { +@@ -130,6 +141,16 @@ + if (!th->ack || + !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) || + TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { ++ /* If mptcp_is_data_fin() returns true, we are sure that ++ * mopt has been initialized - otherwise it would not ++ * be a DATA_FIN. ++ */ ++ if (tcptw->mptcp_tw && tcptw->mptcp_tw->meta_tw && ++ mptcp_is_data_fin(skb) && ++ TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt && ++ mopt.data_seq + 1 == (u32)tcptw->mptcp_tw->rcv_nxt) ++ return TCP_TW_ACK; ++ + inet_twsk_put(tw); + return TCP_TW_SUCCESS; + } +@@ -275,6 +296,16 @@ + tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; + tcptw->tw_ts_offset = tp->tsoffset; + tcptw->tw_last_oow_ack_time = 0; ++ ++ if (mptcp(tp)) { ++ if (mptcp_init_tw_sock(sk, tcptw)) { ++ inet_twsk_free(tw); ++ goto exit; ++ } ++ } else { ++ tcptw->mptcp_tw = NULL; ++ } ++ + tcptw->tw_tx_delay = tp->tcp_tx_delay; + #if IS_ENABLED(CONFIG_IPV6) + if (tw->tw_family == PF_INET6) { +@@ -336,6 +367,7 @@ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); + } + ++exit: + tcp_update_metrics(sk); + tcp_done(sk); + } +@@ -343,6 +375,10 @@ + + void tcp_twsk_destructor(struct sock *sk) + { ++ struct tcp_timewait_sock *twsk = tcp_twsk(sk); ++ ++ if (twsk->mptcp_tw) ++ mptcp_twsk_destructor(twsk); + #ifdef CONFIG_TCP_MD5SIG + if (static_branch_unlikely(&tcp_md5_needed)) { + struct tcp_timewait_sock *twsk = tcp_twsk(sk); +@@ -386,8 +422,9 @@ + full_space = rcv_wnd * mss; + + /* tcp_full_space because it is guaranteed to be the first packet */ +- tcp_select_initial_window(sk_listener, full_space, +- mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), ++ tp->ops->select_initial_window(sk_listener, full_space, ++ mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) - ++ (ireq->saw_mpc ? MPTCP_SUB_LEN_DSM_ALIGN : 0), + &req->rsk_rcv_wnd, + &req->rsk_window_clamp, + ireq->wscale_ok, +@@ -487,6 +524,8 @@ + WRITE_ONCE(newtp->snd_nxt, seq); + newtp->snd_up = seq; + ++ newtp->out_of_order_queue = RB_ROOT; ++ newsk->tcp_rtx_queue = RB_ROOT; + INIT_LIST_HEAD(&newtp->tsq_node); + INIT_LIST_HEAD(&newtp->tsorted_sent_queue); + +@@ -530,6 +569,8 @@ + newtp->rx_opt.ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } ++ if (ireq->saw_mpc) ++ newtp->tcp_header_len += MPTCP_SUB_LEN_DSM_ALIGN; + if (req->num_timeout) { + newtp->undo_marker = treq->snt_isn; + newtp->retrans_stamp = div_u64(treq->snt_synack, +@@ -547,6 +588,7 @@ + tcp_ecn_openreq_child(newtp, req); + newtp->fastopen_req = NULL; + RCU_INIT_POINTER(newtp->fastopen_rsk, NULL); ++ newtp->inside_tk_table = 0; + + __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); + +@@ -570,15 +612,20 @@ + bool fastopen, bool *req_stolen) + { + struct tcp_options_received tmp_opt; ++ struct mptcp_options_received mopt; + struct sock *child; + const struct tcphdr *th = tcp_hdr(skb); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + bool paws_reject = false; + bool own_req; ++ bool meta_locked = false; + + tmp_opt.saw_tstamp = 0; ++ ++ mptcp_init_mp_opt(&mopt); ++ + if (th->doff > (sizeof(struct tcphdr)>>2)) { +- tcp_parse_options(sock_net(sk), skb, &tmp_opt, 0, NULL); ++ tcp_parse_options(sock_net(sk), skb, &tmp_opt, &mopt, 0, NULL, NULL); + + if (tmp_opt.saw_tstamp) { + tmp_opt.ts_recent = req->ts_recent; +@@ -619,7 +666,14 @@ + * + * Reset timer after retransmitting SYNACK, similar to + * the idea of fast retransmit in recovery. ++ * ++ * Fall back to TCP if MP_CAPABLE is not set. + */ ++ ++ if (inet_rsk(req)->saw_mpc && !mopt.saw_mpc) ++ inet_rsk(req)->saw_mpc = false; ++ ++ + if (!tcp_oow_rate_limited(sock_net(sk), skb, + LINUX_MIB_TCPACKSKIPPEDSYNRECV, + &tcp_rsk(req)->last_oow_ack_time) && +@@ -767,17 +821,40 @@ + * ESTABLISHED STATE. If it will be dropped after + * socket is created, wait for troubles. + */ ++ if (is_meta_sk(sk)) { ++ bh_lock_sock_nested(sk); ++ meta_locked = true; ++ } + child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, + req, &own_req); + if (!child) + goto listen_overflow; + ++ if (own_req && !is_meta_sk(sk)) { ++ int ret = mptcp_check_req_master(sk, child, req, skb, &mopt, 1, 0); ++ if (ret < 0) ++ goto listen_overflow; ++ ++ /* MPTCP-supported */ ++ if (!ret) ++ return tcp_sk(child)->mpcb->master_sk; ++ } else if (own_req) { ++ return mptcp_check_req_child(sk, child, req, skb, &mopt); ++ } ++ ++ if (meta_locked) ++ bh_unlock_sock(sk); ++ + sock_rps_save_rxhash(child, skb); + tcp_synack_rtt_meas(child, req); + *req_stolen = !own_req; ++ + return inet_csk_complete_hashdance(sk, child, req, own_req); + + listen_overflow: ++ if (meta_locked) ++ bh_unlock_sock(sk); ++ + if (!sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow) { + inet_rsk(req)->acked = 1; + return NULL; +@@ -820,12 +897,13 @@ + { + int ret = 0; + int state = child->sk_state; ++ struct sock *meta_sk = mptcp(tcp_sk(child)) ? mptcp_meta_sk(child) : child; + + /* record NAPI ID of child */ + sk_mark_napi_id(child, skb); + + tcp_segs_in(tcp_sk(child), skb); +- if (!sock_owned_by_user(child)) { ++ if (!sock_owned_by_user(meta_sk)) { + ret = tcp_rcv_state_process(child, skb); + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && child->sk_state != state) +@@ -835,10 +913,14 @@ + * in main socket hash table and lock on listening + * socket does not protect us more. + */ +- __sk_add_backlog(child, skb); ++ if (mptcp(tcp_sk(child))) ++ mptcp_prepare_for_backlog(child, skb); ++ __sk_add_backlog(meta_sk, skb); + } + + bh_unlock_sock(child); ++ if (mptcp(tcp_sk(child))) ++ bh_unlock_sock(meta_sk); + sock_put(child); + return ret; + } +diff -aurN linux-5.4.64/net/ipv4/tcp_output.c linux-5.4.64.mptcp/net/ipv4/tcp_output.c +--- linux-5.4.64/net/ipv4/tcp_output.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_output.c 2020-09-10 19:34:56.261474044 +0200 +@@ -37,6 +37,12 @@ + + #define pr_fmt(fmt) "TCP: " fmt + ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++#include + #include + + #include +@@ -57,11 +63,8 @@ + tp->tcp_mstamp = div_u64(val, NSEC_PER_USEC); + } + +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, +- int push_one, gfp_t gfp); +- + /* Account for new data that has been sent to the network. */ +-static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) ++void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -255,12 +258,16 @@ + * value can be stuffed directly into th->window for an outgoing + * frame. + */ +-static u16 tcp_select_window(struct sock *sk) ++u16 tcp_select_window(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); + u32 old_win = tp->rcv_wnd; +- u32 cur_win = tcp_receive_window(tp); +- u32 new_win = __tcp_select_window(sk); ++ /* The window must never shrink at the meta-level. At the subflow we ++ * have to allow this. Otherwise we may announce a window too large ++ * for the current meta-level sk_rcvbuf. ++ */ ++ u32 cur_win = tcp_receive_window(mptcp(tp) ? tcp_sk(mptcp_meta_sk(sk)) : tp); ++ u32 new_win = tp->ops->__select_window(sk); + + /* Never shrink the offered window */ + if (new_win < cur_win) { +@@ -276,6 +283,7 @@ + LINUX_MIB_TCPWANTZEROWINDOWADV); + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + } ++ + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + +@@ -388,7 +396,7 @@ + /* Constructs common control bits of non-data skb. If SYN/FIN is present, + * auto increment end seqno. + */ +-static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) ++void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) + { + skb->ip_summed = CHECKSUM_PARTIAL; + +@@ -403,7 +411,7 @@ + TCP_SKB_CB(skb)->end_seq = seq; + } + +-static inline bool tcp_urg_mode(const struct tcp_sock *tp) ++bool tcp_urg_mode(const struct tcp_sock *tp) + { + return tp->snd_una != tp->snd_up; + } +@@ -414,6 +422,7 @@ + #define OPTION_WSCALE (1 << 3) + #define OPTION_FAST_OPEN_COOKIE (1 << 8) + #define OPTION_SMC (1 << 9) ++/* Before adding here - take a look at OPTION_MPTCP in include/net/mptcp.h */ + + static void smc_options_write(__be32 *ptr, u16 *options) + { +@@ -430,17 +439,6 @@ + #endif + } + +-struct tcp_out_options { +- u16 options; /* bit field of OPTION_* */ +- u16 mss; /* 0 to disable */ +- u8 ws; /* window scale, 0 to disable */ +- u8 num_sack_blocks; /* number of SACK blocks to include */ +- u8 hash_size; /* bytes in hash_location */ +- __u8 *hash_location; /* temporary pointer, overloaded */ +- __u32 tsval, tsecr; /* need to include OPTION_TS */ +- struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ +-}; +- + /* Write previously computed TCP options to the packet. + * + * Beware: Something in the Internet is very sensitive to the ordering of +@@ -455,7 +453,7 @@ + * (but it may well be that other scenarios fail similarly). + */ + static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, +- struct tcp_out_options *opts) ++ struct tcp_out_options *opts, struct sk_buff *skb) + { + u16 options = opts->options; /* mungable copy */ + +@@ -549,6 +547,9 @@ + } + + smc_options_write(ptr, &options); ++ ++ if (unlikely(OPTION_MPTCP & opts->options)) ++ mptcp_options_write(ptr, tp, opts, skb); + } + + static void smc_set_option(const struct tcp_sock *tp, +@@ -635,6 +636,8 @@ + if (unlikely(!(OPTION_TS & opts->options))) + remaining -= TCPOLEN_SACKPERM_ALIGNED; + } ++ if (tp->request_mptcp || mptcp(tp)) ++ mptcp_syn_options(sk, opts, &remaining); + + if (fastopen && fastopen->cookie.len >= 0) { + u32 need = fastopen->cookie.len; +@@ -718,6 +721,9 @@ + + smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining); + ++ if (ireq->saw_mpc) ++ mptcp_synack_options(req, opts, &remaining); ++ + return MAX_TCP_OPTION_SPACE - remaining; + } + +@@ -752,14 +758,19 @@ + opts->tsecr = tp->rx_opt.ts_recent; + size += TCPOLEN_TSTAMP_ALIGNED; + } ++ if (mptcp(tp)) ++ mptcp_established_options(sk, skb, opts, &size); + + eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; + if (unlikely(eff_sacks)) { + const unsigned int remaining = MAX_TCP_OPTION_SPACE - size; +- opts->num_sack_blocks = +- min_t(unsigned int, eff_sacks, +- (remaining - TCPOLEN_SACK_BASE_ALIGNED) / +- TCPOLEN_SACK_PERBLOCK); ++ if (remaining < TCPOLEN_SACK_BASE_ALIGNED) ++ opts->num_sack_blocks = 0; ++ else ++ opts->num_sack_blocks = ++ min_t(unsigned int, eff_sacks, ++ (remaining - TCPOLEN_SACK_BASE_ALIGNED) / ++ TCPOLEN_SACK_PERBLOCK); + if (likely(opts->num_sack_blocks)) + size += TCPOLEN_SACK_BASE_ALIGNED + + opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK; +@@ -802,19 +813,31 @@ + tcp_xmit_retransmit_queue(sk); + } + +- tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, +- 0, GFP_ATOMIC); ++ tcp_sk(sk)->ops->write_xmit(sk, tcp_current_mss(sk), ++ tcp_sk(sk)->nonagle, 0, GFP_ATOMIC); + } + } + + static void tcp_tsq_handler(struct sock *sk) + { +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; ++ ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_tsq_write(sk); +- else if (!test_and_set_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags)) +- sock_hold(sk); +- bh_unlock_sock(sk); ++ ++ if (mptcp(tp)) ++ tcp_tsq_write(meta_sk); ++ } else { ++ if (!test_and_set_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags)) ++ sock_hold(sk); ++ ++ if ((mptcp(tp)) && (sk->sk_state != TCP_CLOSE)) ++ mptcp_tsq_flags(sk); ++ } ++ ++ bh_unlock_sock(meta_sk); + } + /* + * One tasklet per cpu tries to send more skbs. +@@ -851,7 +874,9 @@ + #define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \ + TCPF_WRITE_TIMER_DEFERRED | \ + TCPF_DELACK_TIMER_DEFERRED | \ +- TCPF_MTU_REDUCED_DEFERRED) ++ TCPF_MTU_REDUCED_DEFERRED | \ ++ TCPF_PATH_MANAGER_DEFERRED |\ ++ TCPF_SUB_DEFERRED) + /** + * tcp_release_cb - tcp release_sock() callback + * @sk: socket +@@ -874,6 +899,9 @@ + if (flags & TCPF_TSQ_DEFERRED) { + tcp_tsq_write(sk); + __sock_put(sk); ++ ++ if (mptcp(tcp_sk(sk))) ++ tcp_tsq_write(mptcp_meta_sk(sk)); + } + /* Here begins the tricky part : + * We are called from release_sock() with : +@@ -898,6 +926,13 @@ + inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); + __sock_put(sk); + } ++ if (flags & TCPF_PATH_MANAGER_DEFERRED) { ++ if (tcp_sk(sk)->mpcb->pm_ops->release_sock) ++ tcp_sk(sk)->mpcb->pm_ops->release_sock(sk); ++ __sock_put(sk); ++ } ++ if (flags & TCPF_SUB_DEFERRED) ++ mptcp_tsq_sub_deferred(sk); + } + EXPORT_SYMBOL(tcp_release_cb); + +@@ -981,8 +1016,8 @@ + return HRTIMER_NORESTART; + } + +-static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, +- u64 prior_wstamp) ++void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, ++ u64 prior_wstamp) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1128,10 +1163,10 @@ + } + } + +- tcp_options_write((__be32 *)(th + 1), tp, &opts); ++ tcp_options_write((__be32 *)(th + 1), tp, &opts, skb); + skb_shinfo(skb)->gso_type = sk->sk_gso_type; + if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) { +- th->window = htons(tcp_select_window(sk)); ++ th->window = htons(tp->ops->select_window(sk)); + tcp_ecn_send(sk, skb, th, tcp_header_size); + } else { + /* RFC1323: The window in SYN & SYN/ACK segments +@@ -1189,8 +1224,8 @@ + return err; + } + +-static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, +- gfp_t gfp_mask) ++int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ++ gfp_t gfp_mask) + { + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +@@ -1201,7 +1236,7 @@ + * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, + * otherwise socket can stall. + */ +-static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ++void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1214,7 +1249,7 @@ + } + + /* Initialize TSO segments for a packet. */ +-static void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + if (skb->len <= mss_now) { + /* Avoid the costly divide in the normal +@@ -1231,7 +1266,7 @@ + /* Pcount in the middle of the write queue got changed, we need to do various + * tweaks to fix counters + */ +-static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) ++void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -1400,7 +1435,7 @@ + /* This is similar to __pskb_pull_tail(). The difference is that pulled + * data is not copied, but immediately discarded. + */ +-static int __pskb_trim_head(struct sk_buff *skb, int len) ++int __pskb_trim_head(struct sk_buff *skb, int len) + { + struct skb_shared_info *shinfo; + int i, k, eat; +@@ -1622,6 +1657,7 @@ + + return mss_now; + } ++EXPORT_SYMBOL(tcp_current_mss); + + /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, +@@ -1703,8 +1739,8 @@ + * But we can avoid doing the divide again given we already have + * skb_pcount = skb->len / mss_now + */ +-static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, +- const struct sk_buff *skb) ++void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, ++ const struct sk_buff *skb) + { + if (skb->len < tcp_skb_pcount(skb) * mss_now) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; +@@ -1764,11 +1800,11 @@ + } + + /* Returns the portion of skb which can be sent right away */ +-static unsigned int tcp_mss_split_point(const struct sock *sk, +- const struct sk_buff *skb, +- unsigned int mss_now, +- unsigned int max_segs, +- int nonagle) ++unsigned int tcp_mss_split_point(const struct sock *sk, ++ const struct sk_buff *skb, ++ unsigned int mss_now, ++ unsigned int max_segs, ++ int nonagle) + { + const struct tcp_sock *tp = tcp_sk(sk); + u32 partial, needed, window, max_len; +@@ -1798,13 +1834,14 @@ + /* Can at least one segment of SKB be sent right now, according to the + * congestion window rules? If so, return how many segments are allowed. + */ +-static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb) ++unsigned int tcp_cwnd_test(const struct tcp_sock *tp, ++ const struct sk_buff *skb) + { + u32 in_flight, cwnd, halfcwnd; + + /* Don't be strict about the congestion window for the final FIN. */ +- if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ if (skb && ++ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && + tcp_skb_pcount(skb) == 1) + return 1; + +@@ -1819,12 +1856,13 @@ + halfcwnd = max(cwnd >> 1, 1U); + return min(halfcwnd, cwnd - in_flight); + } ++EXPORT_SYMBOL(tcp_cwnd_test); + + /* Initialize TSO state of a skb. + * This must be invoked the first time we consider transmitting + * SKB onto the wire. + */ +-static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) ++int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) + { + int tso_segs = tcp_skb_pcount(skb); + +@@ -1839,8 +1877,8 @@ + /* Return true if the Nagle test allows this packet to be + * sent now. + */ +-static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, +- unsigned int cur_mss, int nonagle) ++bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss, int nonagle) + { + /* Nagle rule does not apply to frames, which sit in the middle of the + * write_queue (they have no chances to get new data). +@@ -1852,7 +1890,8 @@ + return true; + + /* Don't use the nagle rule for urgent data (or for the final FIN). */ +- if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) ++ if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || ++ mptcp_is_data_fin(skb)) + return true; + + if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) +@@ -1862,9 +1901,8 @@ + } + + /* Does at least the first segment of SKB fit into the send window? */ +-static bool tcp_snd_wnd_test(const struct tcp_sock *tp, +- const struct sk_buff *skb, +- unsigned int cur_mss) ++bool tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb, ++ unsigned int cur_mss) + { + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + +@@ -1873,6 +1911,7 @@ + + return !after(end_seq, tcp_wnd_end(tp)); + } ++EXPORT_SYMBOL(tcp_snd_wnd_test); + + /* Trim TSO SKB to LEN bytes, put the remaining data into a new packet + * which is put after SKB on the list. It is very much like +@@ -2031,7 +2070,8 @@ + + /* If this packet won't get more data, do not wait. */ + if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || +- TCP_SKB_CB(skb)->eor) ++ TCP_SKB_CB(skb)->eor || ++ mptcp_is_data_fin(skb)) + goto send_now; + + return true; +@@ -2364,7 +2404,7 @@ + * Returns true, if no segments are in flight and we have queued segments, + * but cannot send anything now because of SWS or another problem. + */ +-static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, ++bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + int push_one, gfp_t gfp) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -2378,7 +2418,12 @@ + sent_pkts = 0; + + tcp_mstamp_refresh(tp); +- if (!push_one) { ++ ++ /* pmtu not yet supported with MPTCP. Should be possible, by early ++ * exiting the loop inside tcp_mtu_probe, making sure that only one ++ * single DSS-mapping gets probed. ++ */ ++ if (!push_one && !mptcp(tp)) { + /* Do MTU probing. */ + result = tcp_mtu_probe(sk); + if (!result) { +@@ -2572,7 +2617,7 @@ + skb = tcp_send_head(sk); + if (skb && tcp_snd_wnd_test(tp, skb, mss)) { + pcount = tp->packets_out; +- tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); ++ tp->ops->write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); + if (tp->packets_out > pcount) + goto probe_sent; + goto rearm_timer; +@@ -2634,8 +2679,8 @@ + if (unlikely(sk->sk_state == TCP_CLOSE)) + return; + +- if (tcp_write_xmit(sk, cur_mss, nonagle, 0, +- sk_gfp_mask(sk, GFP_ATOMIC))) ++ if (tcp_sk(sk)->ops->write_xmit(sk, cur_mss, nonagle, 0, ++ sk_gfp_mask(sk, GFP_ATOMIC))) + tcp_check_probe_timer(sk); + } + +@@ -2648,7 +2693,8 @@ + + BUG_ON(!skb || skb->len < mss_now); + +- tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); ++ tcp_sk(sk)->ops->write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, ++ sk->sk_allocation); + } + + /* This function returns the amount that we can raise the +@@ -2870,6 +2916,10 @@ + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + return; + ++ /* Currently not supported for MPTCP - but it should be possible */ ++ if (mptcp(tp)) ++ return; ++ + skb_rbtree_walk_from_safe(skb, tmp) { + if (!tcp_can_collapse(sk, skb)) + break; +@@ -3351,7 +3401,7 @@ + + /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ + th->window = htons(min(req->rsk_rcv_wnd, 65535U)); +- tcp_options_write((__be32 *)(th + 1), NULL, &opts); ++ tcp_options_write((__be32 *)(th + 1), NULL, &opts, skb); + th->doff = (tcp_header_size >> 2); + __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); + +@@ -3433,13 +3483,13 @@ + if (rcv_wnd == 0) + rcv_wnd = dst_metric(dst, RTAX_INITRWND); + +- tcp_select_initial_window(sk, tcp_full_space(sk), +- tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), +- &tp->rcv_wnd, +- &tp->window_clamp, +- sock_net(sk)->ipv4.sysctl_tcp_window_scaling, +- &rcv_wscale, +- rcv_wnd); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), ++ tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), ++ &tp->rcv_wnd, ++ &tp->window_clamp, ++ sock_net(sk)->ipv4.sysctl_tcp_window_scaling, ++ &rcv_wscale, ++ rcv_wnd); + + tp->rx_opt.rcv_wscale = rcv_wscale; + tp->rcv_ssthresh = tp->rcv_wnd; +@@ -3464,6 +3514,36 @@ + inet_csk(sk)->icsk_rto = tcp_timeout_init(sk); + inet_csk(sk)->icsk_retransmits = 0; + tcp_clear_retrans(tp); ++ ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP) && mptcp_doit(sk)) { ++ if (is_master_tp(tp)) { ++ tp->request_mptcp = 1; ++ mptcp_connect_init(sk); ++ } else if (tp->mptcp) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ tp->mptcp->snt_isn = tp->write_seq; ++ tp->mptcp->init_rcv_wnd = tp->rcv_wnd; ++ ++ /* Set nonce for new subflows */ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp->mptcp_loc_nonce = mptcp_v4_get_nonce( ++ inet->inet_saddr, ++ inet->inet_daddr, ++ inet->inet_sport, ++ inet->inet_dport); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp->mptcp_loc_nonce = mptcp_v6_get_nonce( ++ inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ inet->inet_sport, ++ inet->inet_dport); ++#endif ++ } ++ } ++#endif + } + + static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) +@@ -3727,6 +3807,7 @@ + { + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); + } ++EXPORT_SYMBOL_GPL(tcp_send_ack); + + /* This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. +@@ -3739,7 +3820,7 @@ + * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is + * out-of-date with SND.UNA-1 to probe window. + */ +-static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) ++int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) + { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; +@@ -3826,7 +3907,7 @@ + unsigned long timeout; + int err; + +- err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); ++ err = tp->ops->write_wakeup(sk, LINUX_MIB_TCPWINPROBE); + + if (tp->packets_out || tcp_write_queue_empty(sk)) { + /* Cancel probe timer, if it is not required. */ +diff -aurN linux-5.4.64/net/ipv4/tcp_timer.c linux-5.4.64.mptcp/net/ipv4/tcp_timer.c +--- linux-5.4.64/net/ipv4/tcp_timer.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv4/tcp_timer.c 2020-09-10 19:25:10.507220869 +0200 +@@ -21,6 +21,7 @@ + + #include + #include ++#include + #include + + static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) +@@ -47,7 +48,7 @@ + * Returns: Nothing (void) + */ + +-static void tcp_write_err(struct sock *sk) ++void tcp_write_err(struct sock *sk) + { + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); +@@ -103,7 +104,7 @@ + (!tp->snd_wnd && !tp->packets_out)) + do_reset = true; + if (do_reset) +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + return 1; +@@ -188,9 +189,9 @@ + * after "boundary" unsuccessful, exponentially backed-off + * retransmissions with an initial RTO of TCP_RTO_MIN. + */ +-static bool retransmits_timed_out(struct sock *sk, +- unsigned int boundary, +- unsigned int timeout) ++bool retransmits_timed_out(struct sock *sk, ++ unsigned int boundary, ++ unsigned int timeout) + { + unsigned int start_ts; + +@@ -210,7 +211,7 @@ + } + + /* A write timeout has occurred. Process the after effects. */ +-static int tcp_write_timeout(struct sock *sk) ++int tcp_write_timeout(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); +@@ -225,6 +226,17 @@ + sk_rethink_txhash(sk); + } + retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; ++ ++#ifdef CONFIG_MPTCP ++ /* Stop retransmitting MP_CAPABLE options in SYN if timed out. */ ++ if (tcp_sk(sk)->request_mptcp && ++ icsk->icsk_retransmits >= sysctl_mptcp_syn_retries) { ++ tcp_sk(sk)->request_mptcp = 0; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLERETRANSFALLBACK); ++ } ++#endif /* CONFIG_MPTCP */ ++ + expired = icsk->icsk_retransmits >= retry_until; + } else { + if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) { +@@ -320,18 +332,22 @@ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_delack_timer); + struct sock *sk = &icsk->icsk_inet.sk; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_delack_timer_handler(sk); + } else { + icsk->icsk_ack.blocked = 1; +- __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_DELAYEDACKLOCKED); + /* deleguate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -375,7 +391,12 @@ + } + + if (icsk->icsk_probes_out >= max_probes) { +-abort: tcp_write_err(sk); ++abort: ++ tcp_write_err(sk); ++ if (is_meta_sk(sk) && ++ mptcp_in_infinite_mapping_weak(tp->mpcb)) { ++ mptcp_sub_force_close_all(tp->mpcb, NULL); ++ } + } else { + /* Only send another probe if we didn't close things up. */ + tcp_send_probe0(sk); +@@ -596,7 +617,7 @@ + break; + case ICSK_TIME_RETRANS: + icsk->icsk_pending = 0; +- tcp_retransmit_timer(sk); ++ tcp_sk(sk)->ops->retransmit_timer(sk); + break; + case ICSK_TIME_PROBE0: + icsk->icsk_pending = 0; +@@ -613,16 +634,19 @@ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_retransmit_timer); + struct sock *sk = &icsk->icsk_inet.sk; ++ struct sock *meta_sk = mptcp(tcp_sk(sk)) ? mptcp_meta_sk(sk) : sk; + +- bh_lock_sock(sk); +- if (!sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (!sock_owned_by_user(meta_sk)) { + tcp_write_timer_handler(sk); + } else { + /* delegate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); ++ if (mptcp(tcp_sk(sk))) ++ mptcp_tsq_flags(sk); + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +@@ -652,11 +676,12 @@ + struct sock *sk = from_timer(sk, t, sk_timer); + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp(tp) ? mptcp_meta_sk(sk) : sk; + u32 elapsed; + + /* Only process if socket is not in use. */ +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk)) { ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { + /* Try again later. */ + inet_csk_reset_keepalive_timer (sk, HZ/20); + goto out; +@@ -668,16 +693,31 @@ + } + + tcp_mstamp_refresh(tp); ++ ++ if (tp->send_mp_fclose) { ++ if (icsk->icsk_retransmits >= MPTCP_FASTCLOSE_RETRIES) { ++ tcp_write_err(sk); ++ goto out; ++ } ++ ++ tcp_send_ack(sk); ++ icsk->icsk_retransmits++; ++ ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ elapsed = icsk->icsk_rto; ++ goto resched; ++ } ++ + if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { + if (tp->linger2 >= 0) { + const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; + + if (tmo > 0) { +- tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); ++ tp->ops->time_wait(sk, TCP_FIN_WAIT2, tmo); + goto out; + } + } +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + goto death; + } + +@@ -702,11 +742,11 @@ + icsk->icsk_probes_out > 0) || + (icsk->icsk_user_timeout == 0 && + icsk->icsk_probes_out >= keepalive_probes(tp))) { +- tcp_send_active_reset(sk, GFP_ATOMIC); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); + tcp_write_err(sk); + goto out; + } +- if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { ++ if (tp->ops->write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { + icsk->icsk_probes_out++; + elapsed = keepalive_intvl_when(tp); + } else { +@@ -730,7 +770,7 @@ + tcp_done(sk); + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + } + +diff -aurN linux-5.4.64/net/ipv6/addrconf.c linux-5.4.64.mptcp/net/ipv6/addrconf.c +--- linux-5.4.64/net/ipv6/addrconf.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv6/addrconf.c 2020-09-10 19:25:10.507220869 +0200 +@@ -967,6 +967,7 @@ + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +diff -aurN linux-5.4.64/net/ipv6/af_inet6.c linux-5.4.64.mptcp/net/ipv6/af_inet6.c +--- linux-5.4.64/net/ipv6/af_inet6.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv6/af_inet6.c 2020-09-10 19:25:10.507220869 +0200 +@@ -104,8 +104,7 @@ + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static int inet6_create(struct net *net, struct socket *sock, int protocol, +- int kern) ++int inet6_create(struct net *net, struct socket *sock, int protocol, int kern) + { + struct inet_sock *inet; + struct ipv6_pinfo *np; +diff -aurN linux-5.4.64/net/ipv6/ipv6_sockglue.c linux-5.4.64.mptcp/net/ipv6/ipv6_sockglue.c +--- linux-5.4.64/net/ipv6/ipv6_sockglue.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv6/ipv6_sockglue.c 2020-09-10 19:25:10.507220869 +0200 +@@ -44,6 +44,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -221,7 +223,12 @@ + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); + sk->sk_prot = &tcp_prot; +- icsk->icsk_af_ops = &ipv4_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v4_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +diff -aurN linux-5.4.64/net/ipv6/syncookies.c linux-5.4.64.mptcp/net/ipv6/syncookies.c +--- linux-5.4.64/net/ipv6/syncookies.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv6/syncookies.c 2020-09-10 19:25:10.507220869 +0200 +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define COOKIEBITS 24 /* Upper bits store count */ +@@ -106,7 +108,8 @@ + } + EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); + +-__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mssp) ++__u32 cookie_v6_init_sequence(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); +@@ -128,6 +131,7 @@ + struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) + { + struct tcp_options_received tcp_opt; ++ struct mptcp_options_received mopt; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct ipv6_pinfo *np = inet6_sk(sk); +@@ -157,7 +161,8 @@ + + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); +- tcp_parse_options(sock_net(sk), skb, &tcp_opt, 0, NULL); ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_options(sock_net(sk), skb, &tcp_opt, &mopt, 0, NULL, NULL); + + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcpv6_ts_off(sock_net(sk), +@@ -170,14 +175,27 @@ + goto out; + + ret = NULL; +- req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); ++#ifdef CONFIG_MPTCP ++ if (mopt.saw_mpc) ++ req = inet_reqsk_alloc(&mptcp6_request_sock_ops, sk, false); ++ else ++#endif ++ req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false); + if (!req) + goto out; + + ireq = inet_rsk(req); ++ ireq->mptcp_rqsk = 0; ++ ireq->saw_mpc = 0; + treq = tcp_rsk(req); + treq->tfo_listener = false; + ++ /* Must be done before anything else, as it initializes ++ * hash_entry of the MPTCP request-sock. ++ */ ++ if (mopt.saw_mpc) ++ mptcp_cookies_reqsk_init(req, &mopt, skb); ++ + if (security_inet_conn_request(sk, skb, req)) + goto out_free; + +@@ -241,15 +259,15 @@ + } + + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); +- tcp_select_initial_window(sk, tcp_full_space(sk), req->mss, +- &req->rsk_rcv_wnd, &req->rsk_window_clamp, +- ireq->wscale_ok, &rcv_wscale, +- dst_metric(dst, RTAX_INITRWND)); ++ tp->ops->select_initial_window(sk, tcp_full_space(sk), req->mss, ++ &req->rsk_rcv_wnd, &req->rsk_window_clamp, ++ ireq->wscale_ok, &rcv_wscale, ++ dst_metric(dst, RTAX_INITRWND)); + + ireq->rcv_wscale = rcv_wscale; + ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); + +- ret = tcp_get_cookie_sock(sk, skb, req, dst, tsoff); ++ ret = tcp_get_cookie_sock(sk, skb, req, &mopt, dst, tsoff); + out: + return ret; + out_free: +diff -aurN linux-5.4.64/net/ipv6/tcp_ipv6.c linux-5.4.64.mptcp/net/ipv6/tcp_ipv6.c +--- linux-5.4.64/net/ipv6/tcp_ipv6.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/ipv6/tcp_ipv6.c 2020-09-10 19:25:10.507220869 +0200 +@@ -58,6 +58,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -67,15 +69,6 @@ + #include + + #include +- +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req); +- +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); +- +-static const struct inet_connection_sock_af_ops ipv6_mapped; +-static const struct inet_connection_sock_af_ops ipv6_specific; + #ifdef CONFIG_TCP_MD5SIG + static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; + static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +@@ -99,7 +92,7 @@ + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) ++void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) + { + struct dst_entry *dst = skb_dst(skb); + +@@ -141,7 +134,7 @@ + return BPF_CGROUP_RUN_PROG_INET6_CONNECT(sk, uaddr); + } + +-static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ++int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) + { + struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; +@@ -157,6 +150,8 @@ + int err; + struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; + ++ mptcp_init_connect(sk); ++ + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; + +@@ -236,7 +231,12 @@ + sin.sin_port = usin->sin6_port; + sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; + +- icsk->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_mapped; + sk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -246,7 +246,12 @@ + + if (err) { + icsk->icsk_ext_hdr_len = exthdrlen; +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + sk->sk_backlog_rcv = tcp_v6_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +@@ -340,7 +345,7 @@ + return err; + } + +-static void tcp_v6_mtu_reduced(struct sock *sk) ++void tcp_v6_mtu_reduced(struct sock *sk) + { + struct dst_entry *dst; + +@@ -367,7 +372,7 @@ + struct ipv6_pinfo *np; + struct tcp_sock *tp; + __u32 seq, snd_una; +- struct sock *sk; ++ struct sock *sk, *meta_sk; + bool fatal; + int err; + +@@ -393,8 +398,14 @@ + return 0; + } + +- bh_lock_sock(sk); +- if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) ++ tp = tcp_sk(sk); ++ if (mptcp(tp)) ++ meta_sk = mptcp_meta_sk(sk); ++ else ++ meta_sk = sk; ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk) && type != ICMPV6_PKT_TOOBIG) + __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); + + if (sk->sk_state == TCP_CLOSE) +@@ -405,7 +416,6 @@ + goto out; + } + +- tp = tcp_sk(sk); + /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ + fastopen = rcu_dereference(tp->fastopen_rsk); + snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; +@@ -439,11 +449,15 @@ + goto out; + + tp->mtu_info = ntohl(info); +- if (!sock_owned_by_user(sk)) ++ if (!sock_owned_by_user(meta_sk)) { + tcp_v6_mtu_reduced(sk); +- else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, +- &sk->sk_tsq_flags)) +- sock_hold(sk); ++ } else { ++ if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, ++ &sk->sk_tsq_flags)) ++ sock_hold(sk); ++ if (mptcp(tp)) ++ mptcp_tsq_flags(sk); ++ } + goto out; + } + +@@ -458,7 +472,7 @@ + if (fastopen && !fastopen->sk) + break; + +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + sk->sk_err = err; + sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + +@@ -468,14 +482,14 @@ + goto out; + } + +- if (!sock_owned_by_user(sk) && np->recverr) { ++ if (!sock_owned_by_user(meta_sk) && np->recverr) { + sk->sk_err = err; + sk->sk_error_report(sk); + } else + sk->sk_err_soft = err; + + out: +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + sock_put(sk); + return 0; + } +@@ -523,8 +537,7 @@ + return err; + } + +- +-static void tcp_v6_reqsk_destructor(struct request_sock *req) ++void tcp_v6_reqsk_destructor(struct request_sock *req) + { + kfree(inet_rsk(req)->ipv6_opt); + kfree_skb(inet_rsk(req)->pktopts); +@@ -742,9 +755,10 @@ + return false; + } + +-static void tcp_v6_init_req(struct request_sock *req, +- const struct sock *sk_listener, +- struct sk_buff *skb) ++static int tcp_v6_init_req(struct request_sock *req, ++ const struct sock *sk_listener, ++ struct sk_buff *skb, ++ bool want_cookie) + { + bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); + struct inet_request_sock *ireq = inet_rsk(req); +@@ -766,6 +780,8 @@ + refcount_inc(&skb->users); + ireq->pktopts = skb; + } ++ ++ return 0; + } + + static struct dst_entry *tcp_v6_route_req(const struct sock *sk, +@@ -785,7 +801,7 @@ + .syn_ack_timeout = tcp_syn_ack_timeout, + }; + +-static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { ++const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { + .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr), + #ifdef CONFIG_TCP_MD5SIG +@@ -803,9 +819,9 @@ + }; + + static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, + int oif, struct tcp_md5sig_key *key, int rst, +- u8 tclass, __be32 label, u32 priority) ++ u8 tclass, __be32 label, u32 priority, int mptcp) + { + const struct tcphdr *th = tcp_hdr(skb); + struct tcphdr *t1; +@@ -824,7 +840,10 @@ + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; + #endif +- ++#ifdef CONFIG_MPTCP ++ if (mptcp) ++ tot_len += MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK; ++#endif + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, + GFP_ATOMIC); + if (!buff) +@@ -862,6 +881,17 @@ + tcp_v6_md5_hash_hdr((__u8 *)topt, key, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, t1); ++ topt += 4; ++ } ++#endif ++#ifdef CONFIG_MPTCP ++ if (mptcp) { ++ /* Construction of 32-bit data_ack */ ++ *topt++ = htonl((TCPOPT_MPTCP << 24) | ++ ((MPTCP_SUB_LEN_DSS + MPTCP_SUB_LEN_ACK) << 16) | ++ (0x20 << 8) | ++ (0x01)); ++ *topt++ = htonl(data_ack); + } + #endif + +@@ -920,7 +950,7 @@ + kfree_skb(buff); + } + +-static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ++void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) + { + const struct tcphdr *th = tcp_hdr(skb); + struct ipv6hdr *ipv6h = ipv6_hdr(skb); +@@ -1005,8 +1035,8 @@ + label = ip6_flowlabel(ipv6h); + } + +- tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, +- label, priority); ++ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, 0, oif, key, 1, 0, ++ label, priority, 0); + + #ifdef CONFIG_TCP_MD5SIG + out: +@@ -1015,30 +1045,37 @@ + } + + static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, +- u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, ++ u32 ack, u32 data_ack, u32 win, u32 tsval, u32 tsecr, int oif, + struct tcp_md5sig_key *key, u8 tclass, +- __be32 label, u32 priority) ++ __be32 label, u32 priority, int mptcp) + { +- tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, +- tclass, label, priority); ++ tcp_v6_send_response(sk, skb, seq, ack, data_ack, win, tsval, tsecr, oif, ++ key, 0, tclass, label, priority, mptcp); + } + + static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) + { + struct inet_timewait_sock *tw = inet_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); ++ u32 data_ack = 0; ++ int mptcp = 0; + ++ if (tcptw->mptcp_tw) { ++ data_ack = (u32)tcptw->mptcp_tw->rcv_nxt; ++ mptcp = 1; ++ } + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, ++ data_ack, + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcp_time_stamp_raw() + tcptw->tw_ts_offset, + tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), +- tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority); ++ tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority, mptcp); + + inet_twsk_put(tw); + } + +-static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req) ++void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) + { + /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV + * sk->sk_state == TCP_SYN_RECV -> for Fast Open. +@@ -1048,18 +1085,18 @@ + * exception of segments, MUST be right-shifted by + * Rcv.Wind.Shift bits: + */ +- tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? ++ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN || is_meta_sk(sk)) ? + tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, +- tcp_rsk(req)->rcv_nxt, ++ tcp_rsk(req)->rcv_nxt, 0, + req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, + tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, + req->ts_recent, sk->sk_bound_dev_if, + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), +- 0, 0, sk->sk_priority); ++ 0, 0, sk->sk_priority, 0); + } + + +-static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) ++struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) + { + #ifdef CONFIG_SYN_COOKIES + const struct tcphdr *th = tcp_hdr(skb); +@@ -1085,7 +1122,7 @@ + return mss; + } + +-static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) + { + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_conn_request(sk, skb); +@@ -1111,11 +1148,11 @@ + sizeof(struct inet6_skb_parm)); + } + +-static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +- struct request_sock *req, +- struct dst_entry *dst, +- struct request_sock *req_unhash, +- bool *own_req) ++struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req, ++ struct dst_entry *dst, ++ struct request_sock *req_unhash, ++ bool *own_req) + { + struct inet_request_sock *ireq; + struct ipv6_pinfo *newnp; +@@ -1150,7 +1187,15 @@ + + newnp->saddr = newsk->sk_v6_rcv_saddr; + +- inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; ++#ifdef CONFIG_MPTCP ++ /* We must check on the request-socket because the listener ++ * socket's flag may have been changed halfway through. ++ */ ++ if (!inet_rsk(req)->saw_mpc) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++#endif ++ inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; + newsk->sk_backlog_rcv = tcp_v4_do_rcv; + #ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +@@ -1197,6 +1242,14 @@ + if (!newsk) + goto out_nonewsk; + ++#ifdef CONFIG_MPTCP ++ /* If the meta_sk is v6-mapped we can end up here with the wrong af_ops. ++ * Just make sure that this subflow is v6. ++ */ ++ if (is_meta_sk(sk)) ++ inet_csk(newsk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ + /* + * No need to charge this sock to the relevant IPv6 refcnt debug socks + * count here, tcp_create_openreq_child now does this for us, see the +@@ -1324,7 +1377,7 @@ + * This is because we cannot sleep with the original spinlock + * held. + */ +-static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ++int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + { + struct ipv6_pinfo *np = tcp_inet6_sk(sk); + struct sk_buff *opt_skb = NULL; +@@ -1341,6 +1394,9 @@ + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_do_rcv(sk, skb); + ++ if (is_meta_sk(sk)) ++ return mptcp_v6_do_rcv(sk, skb); ++ + /* + * socket locking is here for SMP purposes as backlog rcv + * is currently called with bh processing disabled. +@@ -1468,6 +1524,10 @@ + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff*4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ++#ifdef CONFIG_MPTCP ++ TCP_SKB_CB(skb)->mptcp_flags = 0; ++ TCP_SKB_CB(skb)->dss_off = 0; ++#endif + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); +@@ -1482,8 +1542,8 @@ + int sdif = inet6_sdif(skb); + const struct tcphdr *th; + const struct ipv6hdr *hdr; ++ struct sock *sk, *meta_sk = NULL; + bool refcounted; +- struct sock *sk; + int ret; + struct net *net = dev_net(skb->dev); + +@@ -1537,12 +1597,17 @@ + reqsk_put(req); + goto csum_error; + } +- if (unlikely(sk->sk_state != TCP_LISTEN)) { ++ if (unlikely(sk->sk_state != TCP_LISTEN && !is_meta_sk(sk))) { ++ inet_csk_reqsk_queue_drop_and_put(sk, req); ++ goto lookup; ++ } ++ if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) { + inet_csk_reqsk_queue_drop_and_put(sk, req); + goto lookup; + } + sock_hold(sk); + refcounted = true; ++ + nsk = NULL; + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; +@@ -1601,19 +1666,28 @@ + + sk_incoming_cpu_update(sk); + +- bh_lock_sock_nested(sk); ++ if (mptcp(tcp_sk(sk))) { ++ meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock_nested(meta_sk); ++ if (sock_owned_by_user(meta_sk)) ++ mptcp_prepare_for_backlog(sk, skb); ++ } else { ++ meta_sk = sk; ++ bh_lock_sock_nested(sk); ++ } + tcp_segs_in(tcp_sk(sk), skb); + ret = 0; +- if (!sock_owned_by_user(sk)) { ++ if (!sock_owned_by_user(meta_sk)) { + skb_to_free = sk->sk_rx_skb_cache; + sk->sk_rx_skb_cache = NULL; + ret = tcp_v6_do_rcv(sk, skb); + } else { +- if (tcp_add_backlog(sk, skb)) ++ if (tcp_add_backlog(meta_sk, skb)) + goto discard_and_relse; + skb_to_free = NULL; + } +- bh_unlock_sock(sk); ++ bh_unlock_sock(meta_sk); + if (skb_to_free) + __kfree_skb(skb_to_free); + put_and_return: +@@ -1627,6 +1701,19 @@ + + tcp_v6_fill_cb(skb, hdr, th); + ++#ifdef CONFIG_MPTCP ++ if (!sk && th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, NULL); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif ++ + if (tcp_checksum_complete(skb)) { + csum_error: + __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); +@@ -1679,6 +1766,18 @@ + refcounted = false; + goto process; + } ++#ifdef CONFIG_MPTCP ++ if (th->syn && !th->ack) { ++ int ret = mptcp_lookup_join(skb, inet_twsk(sk)); ++ ++ if (ret < 0) { ++ tcp_v6_send_reset(NULL, skb); ++ goto discard_it; ++ } else if (ret > 0) { ++ return 0; ++ } ++ } ++#endif + } + /* to ACK */ + /* fall through */ +@@ -1733,13 +1832,13 @@ + } + } + +-static struct timewait_sock_ops tcp6_timewait_sock_ops = { ++struct timewait_sock_ops tcp6_timewait_sock_ops = { + .twsk_obj_size = sizeof(struct tcp6_timewait_sock), + .twsk_unique = tcp_twsk_unique, + .twsk_destructor = tcp_twsk_destructor, + }; + +-static const struct inet_connection_sock_af_ops ipv6_specific = { ++const struct inet_connection_sock_af_ops ipv6_specific = { + .queue_xmit = inet6_csk_xmit, + .send_check = tcp_v6_send_check, + .rebuild_header = inet6_sk_rebuild_header, +@@ -1770,7 +1869,7 @@ + /* + * TCP over IPv4 via INET6 API + */ +-static const struct inet_connection_sock_af_ops ipv6_mapped = { ++const struct inet_connection_sock_af_ops ipv6_mapped = { + .queue_xmit = ip_queue_xmit, + .send_check = tcp_v4_send_check, + .rebuild_header = inet_sk_rebuild_header, +@@ -1806,7 +1905,12 @@ + + tcp_init_sock(sk); + +- icsk->icsk_af_ops = &ipv6_specific; ++#ifdef CONFIG_MPTCP ++ if (sock_flag(sk, SOCK_MPTCP)) ++ icsk->icsk_af_ops = &mptcp_v6_specific; ++ else ++#endif ++ icsk->icsk_af_ops = &ipv6_specific; + + #ifdef CONFIG_TCP_MD5SIG + tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; +@@ -1815,7 +1919,7 @@ + return 0; + } + +-static void tcp_v6_destroy_sock(struct sock *sk) ++void tcp_v6_destroy_sock(struct sock *sk) + { + tcp_v4_destroy_sock(sk); + inet6_destroy_sock(sk); +@@ -2038,6 +2142,11 @@ + .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), + .max_header = MAX_TCP_HEADER, + .obj_size = sizeof(struct tcp6_sock), ++#ifdef CONFIG_MPTCP ++ .useroffset = offsetof(struct tcp_sock, mptcp_sched_name), ++ .usersize = sizeof_field(struct tcp_sock, mptcp_sched_name) + ++ sizeof_field(struct tcp_sock, mptcp_pm_name), ++#endif + .slab_flags = SLAB_TYPESAFE_BY_RCU, + .twsk_prot = &tcp6_timewait_sock_ops, + .rsk_prot = &tcp6_request_sock_ops, +@@ -2048,6 +2157,9 @@ + .compat_getsockopt = compat_tcp_getsockopt, + #endif + .diag_destroy = tcp_abort, ++#ifdef CONFIG_MPTCP ++ .clear_sk = mptcp_clear_sk, ++#endif + }; + + /* thinking of making this const? Don't. +diff -aurN linux-5.4.64/net/Kconfig linux-5.4.64.mptcp/net/Kconfig +--- linux-5.4.64/net/Kconfig 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/Kconfig 2020-09-10 19:25:10.507220869 +0200 +@@ -94,6 +94,7 @@ + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" + source "net/netlabel/Kconfig" ++source "net/mptcp/Kconfig" + + endif # if INET + +diff -aurN linux-5.4.64/net/Makefile linux-5.4.64.mptcp/net/Makefile +--- linux-5.4.64/net/Makefile 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/Makefile 2020-09-10 19:25:10.507220869 +0200 +@@ -20,6 +20,7 @@ + obj-$(CONFIG_XFRM) += xfrm/ + obj-$(CONFIG_UNIX_SCM) += unix/ + obj-$(CONFIG_NET) += ipv6/ ++obj-$(CONFIG_MPTCP) += mptcp/ + obj-$(CONFIG_BPFILTER) += bpfilter/ + obj-$(CONFIG_PACKET) += packet/ + obj-$(CONFIG_NET_KEY) += key/ +diff -aurN linux-5.4.64/net/mptcp/Kconfig linux-5.4.64.mptcp/net/mptcp/Kconfig +--- linux-5.4.64/net/mptcp/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/Kconfig 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,154 @@ ++# ++# MPTCP configuration ++# ++config MPTCP ++ bool "MPTCP protocol" ++ depends on (IPV6=y || IPV6=n) ++ select CRYPTO_LIB_SHA256 ++ select CRYPTO ++ ---help--- ++ This replaces the normal TCP stack with a Multipath TCP stack, ++ able to use several paths at once. ++ ++menuconfig MPTCP_PM_ADVANCED ++ bool "MPTCP: advanced path-manager control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different path-managers. You should choose 'Y' here, ++ because otherwise you will not actively create new MPTCP-subflows. ++ ++if MPTCP_PM_ADVANCED ++ ++config MPTCP_FULLMESH ++ tristate "MPTCP Full-Mesh Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create a full-mesh among all IP-addresses. ++ ++config MPTCP_NDIFFPORTS ++ tristate "MPTCP ndiff-ports" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module will create multiple subflows between the same ++ pair of IP-addresses, modifying the source-port. You can set the number ++ of subflows via the mptcp_ndiffports-sysctl. ++ ++config MPTCP_BINDER ++ tristate "MPTCP Binder" ++ depends on (MPTCP=y) ++ ---help--- ++ This path-management module works like ndiffports, and adds the sysctl ++ option to set the gateway (and/or path to) per each additional subflow ++ via Loose Source Routing (IPv4 only). ++ ++config MPTCP_NETLINK ++ tristate "MPTCP Netlink Path-Manager" ++ depends on MPTCP=y ++ ---help--- ++ This path-management module is controlled over a Netlink interface. A userspace ++ module can therefore control the establishment of new subflows and the policy ++ to apply over those new subflows for every connection. ++ ++choice ++ prompt "Default MPTCP Path-Manager" ++ default DEFAULT_DUMMY ++ help ++ Select the Path-Manager of your choice ++ ++ config DEFAULT_FULLMESH ++ bool "Full mesh" if MPTCP_FULLMESH=y ++ ++ config DEFAULT_NDIFFPORTS ++ bool "ndiff-ports" if MPTCP_NDIFFPORTS=y ++ ++ config DEFAULT_BINDER ++ bool "binder" if MPTCP_BINDER=y ++ ++ config DEFAULT_NETLINK ++ bool "Netlink" if MPTCP_NETLINK=y ++ ++ config DEFAULT_DUMMY ++ bool "Default" ++ ++endchoice ++ ++endif ++ ++config DEFAULT_MPTCP_PM ++ string ++ default "default" if DEFAULT_DUMMY ++ default "fullmesh" if DEFAULT_FULLMESH ++ default "ndiffports" if DEFAULT_NDIFFPORTS ++ default "binder" if DEFAULT_BINDER ++ default "default" ++ ++menuconfig MPTCP_SCHED_ADVANCED ++ bool "MPTCP: advanced scheduler control" ++ depends on MPTCP=y ++ ---help--- ++ Support for selection of different schedulers. You should choose 'Y' here, ++ if you want to choose a different scheduler than the default one. ++ ++if MPTCP_SCHED_ADVANCED ++ ++config MPTCP_BLEST ++ tristate "MPTCP BLEST" ++ depends on MPTCP=y ++ ---help--- ++ This is an experimental BLocking ESTimation-based (BLEST) scheduler. ++ ++config MPTCP_ROUNDROBIN ++ tristate "MPTCP Round-Robin" ++ depends on (MPTCP=y) ++ ---help--- ++ This is a very simple round-robin scheduler. Probably has bad performance ++ but might be interesting for researchers. ++ ++config MPTCP_REDUNDANT ++ tristate "MPTCP Redundant" ++ depends on (MPTCP=y) ++ ---help--- ++ This scheduler sends all packets redundantly over all subflows to decreases ++ latency and jitter on the cost of lower throughput. ++ ++config MPTCP_ECF ++ tristate "MPTCP ECF" ++ depends on (MPTCP=y) ++ ---help--- ++ This is an experimental Earliest Completion First (ECF) scheduler. ++ ++choice ++ prompt "Default MPTCP Scheduler" ++ default DEFAULT_SCHEDULER ++ help ++ Select the Scheduler of your choice ++ ++ config DEFAULT_SCHEDULER ++ bool "Default" ++ ---help--- ++ This is the default scheduler, sending first on the subflow ++ with the lowest RTT. ++ ++ config DEFAULT_ROUNDROBIN ++ bool "Round-Robin" if MPTCP_ROUNDROBIN=y ++ ---help--- ++ This is the round-rob scheduler, sending in a round-robin ++ fashion.. ++ ++ config DEFAULT_REDUNDANT ++ bool "Redundant" if MPTCP_REDUNDANT=y ++ ---help--- ++ This is the redundant scheduler, sending packets redundantly over ++ all the subflows. ++ ++endchoice ++endif ++ ++config DEFAULT_MPTCP_SCHED ++ string ++ depends on (MPTCP=y) ++ default "default" if DEFAULT_SCHEDULER ++ default "roundrobin" if DEFAULT_ROUNDROBIN ++ default "redundant" if DEFAULT_REDUNDANT ++ default "default" ++ +diff -aurN linux-5.4.64/net/mptcp/Makefile linux-5.4.64.mptcp/net/mptcp/Makefile +--- linux-5.4.64/net/mptcp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/Makefile 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,25 @@ ++# ++## Makefile for MultiPath TCP support code. ++# ++# ++ ++obj-$(CONFIG_MPTCP) += mptcp.o ++ ++mptcp-y := mptcp_ctrl.o mptcp_ipv4.o mptcp_pm.o \ ++ mptcp_output.o mptcp_input.o mptcp_sched.o ++ ++obj-$(CONFIG_TCP_CONG_LIA) += mptcp_coupled.o ++obj-$(CONFIG_TCP_CONG_OLIA) += mptcp_olia.o ++obj-$(CONFIG_TCP_CONG_WVEGAS) += mptcp_wvegas.o ++obj-$(CONFIG_TCP_CONG_BALIA) += mptcp_balia.o ++obj-$(CONFIG_TCP_CONG_MCTCPDESYNC) += mctcp_desync.o ++obj-$(CONFIG_MPTCP_FULLMESH) += mptcp_fullmesh.o ++obj-$(CONFIG_MPTCP_NDIFFPORTS) += mptcp_ndiffports.o ++obj-$(CONFIG_MPTCP_BINDER) += mptcp_binder.o ++obj-$(CONFIG_MPTCP_NETLINK) += mptcp_netlink.o ++obj-$(CONFIG_MPTCP_ROUNDROBIN) += mptcp_rr.o ++obj-$(CONFIG_MPTCP_REDUNDANT) += mptcp_redundant.o ++obj-$(CONFIG_MPTCP_BLEST) += mptcp_blest.o ++obj-$(CONFIG_MPTCP_ECF) += mptcp_ecf.o ++ ++mptcp-$(subst m,y,$(CONFIG_IPV6)) += mptcp_ipv6.o +diff -aurN linux-5.4.64/net/mptcp/mctcp_desync.c linux-5.4.64.mptcp/net/mptcp/mctcp_desync.c +--- linux-5.4.64/net/mptcp/mctcp_desync.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mctcp_desync.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,193 @@ ++/* ++ * Desynchronized Multi-Channel TCP Congestion Control Algorithm ++ * ++ * Implementation based on publications of "DMCTCP:Desynchronized Multi-Channel ++ * TCP for high speed access networks with tiny buffers" in 23rd international ++ * conference of Computer Communication and Networks (ICCCN), 2014, and ++ * "Exploring parallelism and desynchronization of TCP over high speed networks ++ * with tiny buffers" in Journal of Computer Communications Elsevier, 2015. ++ * ++ * http://ieeexplore.ieee.org/abstract/document/6911722/ ++ * https://doi.org/10.1016/j.comcom.2015.07.010 ++ * ++ * This prototype is for research purpose and is currently experimental code ++ * that only support a single path. Future support of multi-channel over ++ * multi-path requires channels grouping. ++ * ++ * Initial Design and Implementation: ++ * Cheng Cui ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++ ++enum { ++ MASTER_CHANNEL = 1, ++ INI_MIN_CWND = 2, ++}; ++ ++/* private congestion control structure: ++ * off_tstamp: the last backoff timestamp for loss synchronization event ++ * off_subfid: the subflow which was backoff on off_tstamp ++ */ ++struct mctcp_desync { ++ u64 off_tstamp; ++ u8 off_subfid; ++}; ++ ++static inline int mctcp_cc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static void mctcp_desync_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ ca->off_tstamp = 0; ++ ca->off_subfid = 0; ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mctcp_desync_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } else if (!tcp_is_cwnd_limited(sk)) { ++ return; ++ } else { ++ const struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ const u8 subfid = tp->mptcp->path_index; ++ ++ /* current aggregated cwnd */ ++ u32 agg_cwnd = 0; ++ u32 min_cwnd = 0xffffffff; ++ u8 min_cwnd_subfid = 0; ++ ++ /* In "safe" area, increase */ ++ if (tcp_in_slow_start(tp)) { ++ if (ca->off_subfid) { ++ /* passed initial phase, allow slow start */ ++ tcp_slow_start(tp, acked); ++ } else if (MASTER_CHANNEL == tp->mptcp->path_index) { ++ /* master channel is normal slow start in ++ * initial phase */ ++ tcp_slow_start(tp, acked); ++ } else { ++ /* secondary channels increase slowly until ++ * the initial phase passed ++ */ ++ tp->snd_ssthresh = tp->snd_cwnd = INI_MIN_CWND; ++ } ++ return; ++ } else { ++ /* In dangerous area, increase slowly and linearly. */ ++ const struct mptcp_tcp_sock *mptcp; ++ ++ /* get total cwnd and the subflow that has min cwnd */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ ++ if (mctcp_cc_sk_can_send(sub_sk)) { ++ const struct tcp_sock *sub_tp = ++ tcp_sk(sub_sk); ++ agg_cwnd += sub_tp->snd_cwnd; ++ if(min_cwnd > sub_tp->snd_cwnd) { ++ min_cwnd = sub_tp->snd_cwnd; ++ min_cwnd_subfid = ++ sub_tp->mptcp->path_index; ++ } ++ } ++ } ++ /* the smallest subflow grows faster than others */ ++ if (subfid == min_cwnd_subfid) { ++ tcp_cong_avoid_ai(tp, min_cwnd, acked); ++ } else { ++ tcp_cong_avoid_ai(tp, agg_cwnd - min_cwnd, ++ acked); ++ } ++ } ++ } ++} ++ ++static u32 mctcp_desync_ssthresh(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!mptcp(tp)) { ++ return max(tp->snd_cwnd >> 1U, 2U); ++ } else { ++ struct mctcp_desync *ca = inet_csk_ca(mptcp_meta_sk(sk)); ++ const u8 subfid = tp->mptcp->path_index; ++ const struct mptcp_tcp_sock *mptcp; ++ u32 max_cwnd = 0; ++ u8 max_cwnd_subfid = 0; ++ ++ /* Find the subflow that has the max cwnd. */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ ++ if (mctcp_cc_sk_can_send(sub_sk)) { ++ const struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ if (max_cwnd < sub_tp->snd_cwnd) { ++ max_cwnd = sub_tp->snd_cwnd; ++ max_cwnd_subfid = ++ sub_tp->mptcp->path_index; ++ } ++ } ++ } ++ /* Use high resolution clock. */ ++ if (subfid == max_cwnd_subfid) { ++ u64 now = tcp_clock_us(); ++ u32 delta = tcp_stamp_us_delta(now, ca->off_tstamp); ++ ++ if (delta < (tp->srtt_us >> 3)) { ++ /* desynchronize */ ++ return tp->snd_cwnd; ++ } else { ++ ca->off_tstamp = now; ++ ca->off_subfid = subfid; ++ return max(max_cwnd >> 1U, 2U); ++ } ++ } else { ++ return tp->snd_cwnd; ++ } ++ } ++} ++ ++static struct tcp_congestion_ops mctcp_desync = { ++ .init = mctcp_desync_init, ++ .ssthresh = mctcp_desync_ssthresh, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cong_avoid = mctcp_desync_cong_avoid, ++ .owner = THIS_MODULE, ++ .name = "mctcpdesync", ++}; ++ ++static int __init mctcp_desync_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mctcp_desync) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mctcp_desync); ++} ++ ++static void __exit mctcp_desync_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mctcp_desync); ++} ++ ++module_init(mctcp_desync_register); ++module_exit(mctcp_desync_unregister); ++ ++MODULE_AUTHOR("Cheng Cui"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MCTCP: DESYNCHRONIZED MULTICHANNEL TCP CONGESTION CONTROL"); ++MODULE_VERSION("1.0"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_balia.c linux-5.4.64.mptcp/net/mptcp/mptcp_balia.c +--- linux-5.4.64/net/mptcp/mptcp_balia.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_balia.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,261 @@ ++/* ++ * MPTCP implementation - Balia Congestion Control ++ * (Balanced Linked Adaptation Algorithm) ++ * ++ * Analysis, Design and Implementation: ++ * Qiuyu Peng ++ * Anwar Walid ++ * Jaehyun Hwang ++ * Steven H. Low ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++/* The variable 'rate' (i.e., x_r) will be scaled ++ * e.g., from B/s to KB/s, MB/s, or GB/s ++ * if max_rate > 2^rate_scale_limit ++ */ ++ ++static int rate_scale_limit = 25; ++static int alpha_scale = 10; ++static int scale_num = 5; ++ ++struct mptcp_balia { ++ u64 ai; ++ u64 md; ++ bool forced_update; ++}; ++ ++static inline int mptcp_balia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_ai(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai; ++} ++ ++static inline void mptcp_set_ai(const struct sock *meta_sk, u64 ai) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->ai = ai; ++} ++ ++static inline u64 mptcp_get_md(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md; ++} ++ ++static inline void mptcp_set_md(const struct sock *meta_sk, u64 md) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->md = md; ++} ++ ++static inline u64 mptcp_balia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_balia *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_balia_recalc_ai(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ u64 max_rate = 0, rate = 0, sum_rate = 0; ++ u64 alpha, ai = tp->snd_cwnd, md = (tp->snd_cwnd >> 1); ++ int num_scale_down = 0; ++ ++ if (!mpcb) ++ return; ++ ++ /* Find max_rate first */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ sum_rate += tmp; ++ ++ if (tp == sub_tp) ++ rate = tmp; ++ ++ if (tmp >= max_rate) ++ max_rate = tmp; ++ } ++ ++ /* At least, the current subflow should be able to send */ ++ if (unlikely(!rate)) ++ goto exit; ++ ++ alpha = div64_u64(max_rate, rate); ++ ++ /* Scale down max_rate if it is too high (e.g., >2^25) */ ++ while (max_rate > mptcp_balia_scale(1, rate_scale_limit)) { ++ max_rate >>= scale_num; ++ num_scale_down++; ++ } ++ ++ if (num_scale_down) { ++ sum_rate = 0; ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_balia_sk_can_send(sub_sk)) ++ continue; ++ ++ tmp = div_u64((u64)tp->mss_cache * sub_tp->snd_cwnd ++ * (USEC_PER_SEC << 3), sub_tp->srtt_us); ++ tmp >>= (scale_num * num_scale_down); ++ ++ sum_rate += tmp; ++ } ++ rate >>= (scale_num * num_scale_down); ++ } ++ ++ /* (sum_rate)^2 * 10 * w_r ++ * ai = ------------------------------------ ++ * (x_r + max_rate) * (4x_r + max_rate) ++ */ ++ sum_rate *= sum_rate; ++ ++ ai = div64_u64(sum_rate * 10, rate + max_rate); ++ ai = div64_u64(ai * tp->snd_cwnd, (rate << 2) + max_rate); ++ ++ if (unlikely(!ai)) ++ ai = tp->snd_cwnd; ++ ++ md = ((tp->snd_cwnd >> 1) * min(mptcp_balia_scale(alpha, alpha_scale), ++ mptcp_balia_scale(3, alpha_scale) >> 1)) ++ >> alpha_scale; ++ ++exit: ++ mptcp_set_ai(sk, ai); ++ mptcp_set_md(sk, md); ++} ++ ++static void mptcp_balia_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(sk, 0); ++ mptcp_set_ai(sk, 0); ++ mptcp_set_md(sk, 0); ++ } ++} ++ ++static void mptcp_balia_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_COMPLETE_CWR || event == CA_EVENT_LOSS) ++ mptcp_balia_recalc_ai(sk); ++} ++ ++static void mptcp_balia_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(sk, 1); ++} ++ ++static void mptcp_balia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ int snd_cwnd; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_balia_recalc_ai(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_balia_recalc_ai(sk); ++ mptcp_set_forced(sk, 0); ++ } ++ ++ snd_cwnd = (int)mptcp_get_ai(sk); ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_balia_recalc_ai(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static u32 mptcp_balia_ssthresh(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (unlikely(!mptcp(tp))) ++ return tcp_reno_ssthresh(sk); ++ else ++ return max((u32)(tp->snd_cwnd - mptcp_get_md(sk)), 1U); ++} ++ ++static struct tcp_congestion_ops mptcp_balia = { ++ .init = mptcp_balia_init, ++ .ssthresh = mptcp_balia_ssthresh, ++ .cong_avoid = mptcp_balia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_balia_cwnd_event, ++ .set_state = mptcp_balia_set_state, ++ .owner = THIS_MODULE, ++ .name = "balia", ++}; ++ ++static int __init mptcp_balia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_balia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_balia); ++} ++ ++static void __exit mptcp_balia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_balia); ++} ++ ++module_init(mptcp_balia_register); ++module_exit(mptcp_balia_unregister); ++ ++MODULE_AUTHOR("Jaehyun Hwang, Anwar Walid, Qiuyu Peng, Steven H. Low"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP BALIA CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_binder.c linux-5.4.64.mptcp/net/mptcp/mptcp_binder.c +--- linux-5.4.64/net/mptcp/mptcp_binder.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_binder.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,494 @@ ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MPTCP_GW_MAX_LISTS 10 ++#define MPTCP_GW_LIST_MAX_LEN 6 ++#define MPTCP_GW_SYSCTL_MAX_LEN (15 * MPTCP_GW_LIST_MAX_LEN * \ ++ MPTCP_GW_MAX_LISTS) ++ ++struct mptcp_gw_list { ++ struct in_addr list[MPTCP_GW_MAX_LISTS][MPTCP_GW_LIST_MAX_LEN]; ++ u8 len[MPTCP_GW_MAX_LISTS]; ++}; ++ ++struct binder_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++ ++ /* Prevent multiple sub-sockets concurrently iterating over sockets */ ++ spinlock_t *flow_lock; ++}; ++ ++static struct mptcp_gw_list *mptcp_gws; ++static rwlock_t mptcp_gws_lock; ++ ++static int mptcp_binder_ndiffports __read_mostly = 1; ++ ++static char sysctl_mptcp_binder_gateways[MPTCP_GW_SYSCTL_MAX_LEN] __read_mostly; ++ ++static int mptcp_get_avail_list_ipv4(struct sock *sk) ++{ ++ int i, j, list_taken, opt_ret, opt_len; ++ unsigned char *opt_ptr, *opt_end_ptr, opt[MAX_IPOPTLEN]; ++ ++ for (i = 0; i < MPTCP_GW_MAX_LISTS; ++i) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (mptcp_gws->len[i] == 0) ++ goto error; ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: List %i\n", i); ++ list_taken = 0; ++ ++ /* Loop through all sub-sockets in this connection */ ++ mptcp_for_each_sub(tcp_sk(sk)->mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ ++ mptcp_debug("mptcp_get_avail_list_ipv4: Next sock\n"); ++ ++ /* Reset length and options buffer, then retrieve ++ * from socket ++ */ ++ opt_len = MAX_IPOPTLEN; ++ memset(opt, 0, MAX_IPOPTLEN); ++ opt_ret = ip_getsockopt(sk, IPPROTO_IP, ++ IP_OPTIONS, (char __user *)opt, (int __user *)&opt_len); ++ if (opt_ret < 0) { ++ mptcp_debug("%s: MPTCP subsocket getsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, opt_ret); ++ goto error; ++ } ++ ++ /* If socket has no options, it has no stake in this list */ ++ if (opt_len <= 0) ++ continue; ++ ++ /* Iterate options buffer */ ++ for (opt_ptr = &opt[0]; opt_ptr < &opt[opt_len]; opt_ptr++) { ++ if (*opt_ptr == IPOPT_LSRR) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: LSRR options found\n"); ++ goto sock_lsrr; ++ } ++ } ++ continue; ++ ++sock_lsrr: ++ /* Pointer to the 2nd to last address */ ++ opt_end_ptr = opt_ptr+(*(opt_ptr+1))-4; ++ ++ /* Addresses start 3 bytes after type offset */ ++ opt_ptr += 3; ++ j = 0; ++ ++ /* Different length lists cannot be the same */ ++ if ((opt_end_ptr-opt_ptr)/4 != mptcp_gws->len[i]) ++ continue; ++ ++ /* Iterate if we are still inside options list ++ * and sysctl list ++ */ ++ while (opt_ptr < opt_end_ptr && j < mptcp_gws->len[i]) { ++ /* If there is a different address, this list must ++ * not be set on this socket ++ */ ++ if (memcmp(&mptcp_gws->list[i][j], opt_ptr, 4)) ++ break; ++ ++ /* Jump 4 bytes to next address */ ++ opt_ptr += 4; ++ j++; ++ } ++ ++ /* Reached the end without a differing address, lists ++ * are therefore identical. ++ */ ++ if (j == mptcp_gws->len[i]) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List already used\n"); ++ list_taken = 1; ++ break; ++ } ++ } ++ ++ /* Free list found if not taken by a socket */ ++ if (!list_taken) { ++ mptcp_debug("mptcp_get_avail_list_ipv4: List free\n"); ++ break; ++ } ++ } ++ ++ if (i >= MPTCP_GW_MAX_LISTS) ++ goto error; ++ ++ return i; ++error: ++ return -1; ++} ++ ++/* The list of addresses is parsed each time a new connection is opened, ++ * to make sure it's up to date. In case of error, all the lists are ++ * marked as unavailable and the subflow's fingerprint is set to 0. ++ */ ++static void mptcp_v4_add_lsrr(struct sock *sk, struct in_addr addr) ++{ ++ int i, j, ret; ++ unsigned char opt[MAX_IPOPTLEN] = {0}; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct binder_priv *fmp = (struct binder_priv *)&tp->mpcb->mptcp_pm[0]; ++ ++ /* Read lock: multiple sockets can read LSRR addresses at the same ++ * time, but writes are done in mutual exclusion. ++ * Spin lock: must search for free list for one socket at a time, or ++ * multiple sockets could take the same list. ++ */ ++ read_lock(&mptcp_gws_lock); ++ spin_lock(fmp->flow_lock); ++ ++ i = mptcp_get_avail_list_ipv4(sk); ++ ++ /* Execution enters here only if a free path is found. ++ */ ++ if (i >= 0) { ++ opt[0] = IPOPT_NOP; ++ opt[1] = IPOPT_LSRR; ++ opt[2] = sizeof(mptcp_gws->list[i][0].s_addr) * ++ (mptcp_gws->len[i] + 1) + 3; ++ opt[3] = IPOPT_MINOFF; ++ for (j = 0; j < mptcp_gws->len[i]; ++j) ++ memcpy(opt + 4 + ++ (j * sizeof(mptcp_gws->list[i][0].s_addr)), ++ &mptcp_gws->list[i][j].s_addr, ++ sizeof(mptcp_gws->list[i][0].s_addr)); ++ /* Final destination must be part of IP_OPTIONS parameter. */ ++ memcpy(opt + 4 + (j * sizeof(addr.s_addr)), &addr.s_addr, ++ sizeof(addr.s_addr)); ++ ++ /* setsockopt must be inside the lock, otherwise another ++ * subflow could fail to see that we have taken a list. ++ */ ++ ret = ip_setsockopt(sk, IPPROTO_IP, IP_OPTIONS, (char __user *)opt, ++ 4 + sizeof(mptcp_gws->list[i][0].s_addr) * (mptcp_gws->len[i] + 1)); ++ ++ if (ret < 0) { ++ mptcp_debug("%s: MPTCP subsock setsockopt() IP_OPTIONS failed, error %d\n", ++ __func__, ret); ++ } ++ } ++ ++ spin_unlock(fmp->flow_lock); ++ read_unlock(&mptcp_gws_lock); ++ ++ return; ++} ++ ++/* Parses gateways string for a list of paths to different ++ * gateways, and stores them for use with the Loose Source Routing (LSRR) ++ * socket option. Each list must have "," separated addresses, and the lists ++ * themselves must be separated by "-". Returns -1 in case one or more of the ++ * addresses is not a valid ipv4/6 address. ++ */ ++static int mptcp_parse_gateway_ipv4(char *gateways) ++{ ++ int i, j, k, ret; ++ char *tmp_string = NULL; ++ struct in_addr tmp_addr; ++ ++ tmp_string = kzalloc(16, GFP_KERNEL); ++ if (tmp_string == NULL) ++ return -ENOMEM; ++ ++ write_lock(&mptcp_gws_lock); ++ ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ ++ /* A TMP string is used since inet_pton needs a null terminated string ++ * but we do not want to modify the sysctl for obvious reasons. ++ * i will iterate over the SYSCTL string, j will iterate over the ++ * temporary string where each IP is copied into, k will iterate over ++ * the IPs in each list. ++ */ ++ for (i = j = k = 0; ++ i < MPTCP_GW_SYSCTL_MAX_LEN && k < MPTCP_GW_MAX_LISTS; ++ ++i) { ++ if (gateways[i] == '-' || gateways[i] == ',' || gateways[i] == '\0') { ++ /* If the temp IP is empty and the current list is ++ * empty, we are done. ++ */ ++ if (j == 0 && mptcp_gws->len[k] == 0) ++ break; ++ ++ /* Terminate the temp IP string, then if it is ++ * non-empty parse the IP and copy it. ++ */ ++ tmp_string[j] = '\0'; ++ if (j > 0) { ++ mptcp_debug("mptcp_parse_gateway_list tmp: %s i: %d\n", tmp_string, i); ++ ++ ret = in4_pton(tmp_string, strlen(tmp_string), ++ (u8 *)&tmp_addr.s_addr, '\0', ++ NULL); ++ ++ if (ret) { ++ mptcp_debug("mptcp_parse_gateway_list ret: %d s_addr: %pI4\n", ++ ret, ++ &tmp_addr.s_addr); ++ memcpy(&mptcp_gws->list[k][mptcp_gws->len[k]].s_addr, ++ &tmp_addr.s_addr, ++ sizeof(tmp_addr.s_addr)); ++ mptcp_gws->len[k]++; ++ j = 0; ++ tmp_string[j] = '\0'; ++ /* Since we can't impose a limit to ++ * what the user can input, make sure ++ * there are not too many IPs in the ++ * SYSCTL string. ++ */ ++ if (mptcp_gws->len[k] > MPTCP_GW_LIST_MAX_LEN) { ++ mptcp_debug("mptcp_parse_gateway_list too many members in list %i: max %i\n", ++ k, ++ MPTCP_GW_LIST_MAX_LEN); ++ goto error; ++ } ++ } else { ++ goto error; ++ } ++ } ++ ++ if (gateways[i] == '-' || gateways[i] == '\0') ++ ++k; ++ } else { ++ tmp_string[j] = gateways[i]; ++ ++j; ++ } ++ } ++ ++ /* Number of flows is number of gateway lists plus master flow */ ++ mptcp_binder_ndiffports = k+1; ++ ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ ++ return 0; ++ ++error: ++ memset(mptcp_gws, 0, sizeof(struct mptcp_gw_list)); ++ memset(gateways, 0, sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN); ++ write_unlock(&mptcp_gws_lock); ++ kfree(tmp_string); ++ return -1; ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct binder_priv *pm_priv = container_of(work, ++ struct binder_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (mptcp_binder_ndiffports > iter && ++ mptcp_binder_ndiffports > mptcp_subflow_count(mpcb)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void binder_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *fmp = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ static DEFINE_SPINLOCK(flow_lock); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(meta_sk)) { ++ mptcp_fallback_default(mpcb); ++ return; ++ } ++#endif ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ fmp->flow_lock = &flow_lock; ++} ++ ++static void binder_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct binder_priv *pm_priv = (struct binder_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int binder_get_local_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ return 0; ++} ++ ++/* Callback functions, executed when syctl mptcp.mptcp_gateways is updated. ++ * Inspired from proc_tcp_congestion_control(). ++ */ ++static int proc_mptcp_gateways(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ int ret; ++ struct ctl_table tbl = { ++ .maxlen = MPTCP_GW_SYSCTL_MAX_LEN, ++ }; ++ ++ if (write) { ++ tbl.data = kzalloc(MPTCP_GW_SYSCTL_MAX_LEN, GFP_KERNEL); ++ if (tbl.data == NULL) ++ return -ENOMEM; ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (ret == 0) { ++ ret = mptcp_parse_gateway_ipv4(tbl.data); ++ memcpy(ctl->data, tbl.data, MPTCP_GW_SYSCTL_MAX_LEN); ++ } ++ kfree(tbl.data); ++ } else { ++ ret = proc_dostring(ctl, write, buffer, lenp, ppos); ++ } ++ ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops binder __read_mostly = { ++ .new_session = binder_new_session, ++ .fully_established = binder_create_subflows, ++ .get_local_id = binder_get_local_id, ++ .init_subsocket_v4 = mptcp_v4_add_lsrr, ++ .name = "binder", ++ .owner = THIS_MODULE, ++}; ++ ++static struct ctl_table binder_table[] = { ++ { ++ .procname = "mptcp_binder_gateways", ++ .data = &sysctl_mptcp_binder_gateways, ++ .maxlen = sizeof(char) * MPTCP_GW_SYSCTL_MAX_LEN, ++ .mode = 0644, ++ .proc_handler = &proc_mptcp_gateways ++ }, ++ { } ++}; ++ ++static struct ctl_table_header *mptcp_sysctl_binder; ++ ++/* General initialization of MPTCP_PM */ ++static int __init binder_register(void) ++{ ++ mptcp_gws = kzalloc(sizeof(*mptcp_gws), GFP_KERNEL); ++ if (!mptcp_gws) ++ return -ENOMEM; ++ ++ rwlock_init(&mptcp_gws_lock); ++ ++ BUILD_BUG_ON(sizeof(struct binder_priv) > MPTCP_PM_SIZE); ++ ++ mptcp_sysctl_binder = register_net_sysctl(&init_net, "net/mptcp", ++ binder_table); ++ if (!mptcp_sysctl_binder) ++ goto sysctl_fail; ++ ++ if (mptcp_register_path_manager(&binder)) ++ goto pm_failed; ++ ++ return 0; ++ ++pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++sysctl_fail: ++ kfree(mptcp_gws); ++ ++ return -1; ++} ++ ++static void binder_unregister(void) ++{ ++ mptcp_unregister_path_manager(&binder); ++ unregister_net_sysctl_table(mptcp_sysctl_binder); ++ kfree(mptcp_gws); ++} ++ ++module_init(binder_register); ++module_exit(binder_unregister); ++ ++MODULE_AUTHOR("Luca Boccassi, Duncan Eastoe, Christoph Paasch (ndiffports)"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BINDER MPTCP"); ++MODULE_VERSION("0.1"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_blest.c linux-5.4.64.mptcp/net/mptcp/mptcp_blest.c +--- linux-5.4.64/net/mptcp/mptcp_blest.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_blest.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,285 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP Scheduler to reduce HoL-blocking and spurious retransmissions. ++ * ++ * Algorithm Design: ++ * Simone Ferlin ++ * Ozgu Alay ++ * Olivier Mehani ++ * Roksana Boreli ++ * ++ * Initial Implementation: ++ * Simone Ferlin ++ * ++ * Additional Authors: ++ * Daniel Weber ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++static unsigned char lambda __read_mostly = 12; ++module_param(lambda, byte, 0644); ++MODULE_PARM_DESC(lambda, "Divided by 10 for scaling factor of fast flow rate estimation"); ++ ++static unsigned char max_lambda __read_mostly = 13; ++module_param(max_lambda, byte, 0644); ++MODULE_PARM_DESC(max_lambda, "Divided by 10 for maximum scaling factor of fast flow rate estimation"); ++ ++static unsigned char min_lambda __read_mostly = 10; ++module_param(min_lambda, byte, 0644); ++MODULE_PARM_DESC(min_lambda, "Divided by 10 for minimum scaling factor of fast flow rate estimation"); ++ ++static unsigned char dyn_lambda_good = 10; /* 1% */ ++module_param(dyn_lambda_good, byte, 0644); ++MODULE_PARM_DESC(dyn_lambda_good, "Decrease of lambda in positive case."); ++ ++static unsigned char dyn_lambda_bad = 40; /* 4% */ ++module_param(dyn_lambda_bad, byte, 0644); ++MODULE_PARM_DESC(dyn_lambda_bad, "Increase of lambda in negative case."); ++ ++struct blestsched_priv { ++ u32 last_rbuf_opti; ++ u32 min_srtt_us; ++ u32 max_srtt_us; ++}; ++ ++struct blestsched_cb { ++ s16 lambda_1000; /* values range from min_lambda * 100 to max_lambda * 100 */ ++ u32 last_lambda_update; ++}; ++ ++static struct blestsched_priv *blestsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct blestsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++static struct blestsched_cb *blestsched_get_cb(const struct tcp_sock *tp) ++{ ++ return (struct blestsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static void blestsched_update_lambda(struct sock *meta_sk, struct sock *sk) ++{ ++ struct blestsched_cb *blest_cb = blestsched_get_cb(tcp_sk(meta_sk)); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tcp_sk(sk)); ++ ++ if (tcp_jiffies32 - blest_cb->last_lambda_update < usecs_to_jiffies(blest_p->min_srtt_us >> 3)) ++ return; ++ ++ /* if there have been retransmissions of packets of the slow flow ++ * during the slow flows last RTT => increase lambda ++ * otherwise decrease ++ */ ++ if (tcp_sk(meta_sk)->retrans_stamp) { ++ /* need to slow down on the slow flow */ ++ blest_cb->lambda_1000 += dyn_lambda_bad; ++ } else { ++ /* use the slow flow more */ ++ blest_cb->lambda_1000 -= dyn_lambda_good; ++ } ++ ++ /* cap lambda_1000 to its value range */ ++ blest_cb->lambda_1000 = min_t(s16, blest_cb->lambda_1000, max_lambda * 100); ++ blest_cb->lambda_1000 = max_t(s16, blest_cb->lambda_1000, min_lambda * 100); ++ ++ blest_cb->last_lambda_update = tcp_jiffies32; ++} ++ ++/* how many bytes will sk send during the rtt of another, slower flow? */ ++static u32 blestsched_estimate_bytes(struct sock *sk, u32 time_8) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tp); ++ struct blestsched_cb *blest_cb = blestsched_get_cb(mptcp_meta_tp(tp)); ++ u32 avg_rtt, num_rtts, ca_cwnd, packets; ++ ++ avg_rtt = (blest_p->min_srtt_us + blest_p->max_srtt_us) / 2; ++ if (avg_rtt == 0) ++ num_rtts = 1; /* sanity */ ++ else ++ num_rtts = (time_8 / avg_rtt) + 1; /* round up */ ++ ++ /* during num_rtts, how many bytes will be sent on the flow? ++ * assumes for simplification that Reno is applied as congestion-control ++ */ ++ if (tp->snd_ssthresh == TCP_INFINITE_SSTHRESH) { ++ /* we are in initial slow start */ ++ if (num_rtts > 16) ++ num_rtts = 16; /* cap for sanity */ ++ packets = tp->snd_cwnd * ((1 << num_rtts) - 1); /* cwnd + 2*cwnd + 4*cwnd */ ++ } else { ++ ca_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh + 1); /* assume we jump to CA already */ ++ packets = (ca_cwnd + (num_rtts - 1) / 2) * num_rtts; ++ } ++ ++ return div_u64(((u64)packets) * tp->mss_cache * blest_cb->lambda_1000, 1000); ++} ++ ++static u32 blestsched_estimate_linger_time(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct blestsched_priv *blest_p = blestsched_get_priv(tp); ++ u32 estimate, slope, inflight, cwnd; ++ ++ inflight = tcp_packets_in_flight(tp) + 1; /* take into account the new one */ ++ cwnd = tp->snd_cwnd; ++ ++ if (inflight >= cwnd) { ++ estimate = blest_p->max_srtt_us; ++ } else { ++ slope = blest_p->max_srtt_us - blest_p->min_srtt_us; ++ if (cwnd == 0) ++ cwnd = 1; /* sanity */ ++ estimate = blest_p->min_srtt_us + (slope * inflight) / cwnd; ++ } ++ ++ return (tp->srtt_us > estimate) ? tp->srtt_us : estimate; ++} ++ ++/* This is the BLEST scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy or the currently best ++ * subflow is estimated to possibly cause HoL-blocking, NULL is returned. ++ */ ++struct sock *blest_get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *bestsk, *minsk = NULL; ++ struct tcp_sock *meta_tp, *besttp; ++ struct mptcp_tcp_sock *mptcp; ++ struct blestsched_priv *blest_p; ++ u32 min_srtt = U32_MAX; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(bestsk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(bestsk, skb, zero_wnd_test)) ++ return bestsk; ++ } ++ } ++ ++ /* First, find the overall best subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ besttp = tcp_sk(bestsk); ++ blest_p = blestsched_get_priv(besttp); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(bestsk)) ++ continue; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (besttp->mptcp->pre_established) ++ continue; ++ ++ blest_p->min_srtt_us = min(blest_p->min_srtt_us, besttp->srtt_us); ++ blest_p->max_srtt_us = max(blest_p->max_srtt_us, besttp->srtt_us); ++ ++ /* record minimal rtt */ ++ if (besttp->srtt_us < min_srtt) { ++ min_srtt = besttp->srtt_us; ++ minsk = bestsk; ++ } ++ } ++ ++ /* find the current best subflow according to the default scheduler */ ++ bestsk = get_available_subflow(meta_sk, skb, zero_wnd_test); ++ ++ /* if we decided to use a slower flow, we have the option of not using it at all */ ++ if (bestsk && minsk && bestsk != minsk) { ++ u32 slow_linger_time, fast_bytes, slow_inflight_bytes, slow_bytes, avail_space; ++ u32 buffered_bytes = 0; ++ ++ meta_tp = tcp_sk(meta_sk); ++ besttp = tcp_sk(bestsk); ++ ++ blestsched_update_lambda(meta_sk, bestsk); ++ ++ /* if we send this SKB now, it will be acked in besttp->srtt seconds ++ * during this time: how many bytes will we send on the fast flow? ++ */ ++ slow_linger_time = blestsched_estimate_linger_time(bestsk); ++ fast_bytes = blestsched_estimate_bytes(minsk, slow_linger_time); ++ ++ if (skb) ++ buffered_bytes = skb->len; ++ ++ /* is the required space available in the mptcp meta send window? ++ * we assume that all bytes inflight on the slow path will be acked in besttp->srtt seconds ++ * (just like the SKB if it was sent now) -> that means that those inflight bytes will ++ * keep occupying space in the meta window until then ++ */ ++ slow_inflight_bytes = besttp->write_seq - besttp->snd_una; ++ slow_bytes = buffered_bytes + slow_inflight_bytes; // bytes of this SKB plus those in flight already ++ ++ avail_space = (slow_bytes < meta_tp->snd_wnd) ? (meta_tp->snd_wnd - slow_bytes) : 0; ++ ++ if (fast_bytes > avail_space) { ++ /* sending this SKB on the slow flow means ++ * we wouldn't be able to send all the data we'd like to send on the fast flow ++ * so don't do that ++ */ ++ return NULL; ++ } ++ } ++ ++ return bestsk; ++} ++ ++static void blestsched_init(struct sock *sk) ++{ ++ struct blestsched_priv *blest_p = blestsched_get_priv(tcp_sk(sk)); ++ struct blestsched_cb *blest_cb = blestsched_get_cb(tcp_sk(mptcp_meta_sk(sk))); ++ ++ blest_p->last_rbuf_opti = tcp_jiffies32; ++ blest_p->min_srtt_us = U32_MAX; ++ blest_p->max_srtt_us = 0; ++ ++ if (!blest_cb->lambda_1000) { ++ blest_cb->lambda_1000 = lambda * 100; ++ blest_cb->last_lambda_update = tcp_jiffies32; ++ } ++} ++ ++static struct mptcp_sched_ops mptcp_sched_blest = { ++ .get_subflow = blest_get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = blestsched_init, ++ .name = "blest", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init blest_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct blestsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct blestsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_blest)) ++ return -1; ++ ++ return 0; ++} ++ ++static void blest_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_blest); ++} ++ ++module_init(blest_register); ++module_exit(blest_unregister); ++ ++MODULE_AUTHOR("Simone Ferlin, Daniel Weber"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BLEST scheduler for MPTCP, based on default minimum RTT scheduler"); ++MODULE_VERSION("0.95"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_coupled.c linux-5.4.64.mptcp/net/mptcp/mptcp_coupled.c +--- linux-5.4.64/net/mptcp/mptcp_coupled.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_coupled.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,262 @@ ++/* ++ * MPTCP implementation - Linked Increase congestion control Algorithm (LIA) ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++#include ++#include ++ ++#include ++ ++/* Scaling is done in the numerator with alpha_scale_num and in the denominator ++ * with alpha_scale_den. ++ * ++ * To downscale, we just need to use alpha_scale. ++ * ++ * We have: alpha_scale = alpha_scale_num / (alpha_scale_den ^ 2) ++ */ ++static int alpha_scale_den = 10; ++static int alpha_scale_num = 32; ++static int alpha_scale = 12; ++ ++struct mptcp_ccc { ++ u64 alpha; ++ bool forced_update; ++}; ++ ++static inline int mptcp_ccc_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_get_alpha(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha; ++} ++ ++static inline void mptcp_set_alpha(const struct sock *meta_sk, u64 alpha) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->alpha = alpha; ++} ++ ++static inline u64 mptcp_ccc_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static inline bool mptcp_get_forced(const struct sock *meta_sk) ++{ ++ return ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update; ++} ++ ++static inline void mptcp_set_forced(const struct sock *meta_sk, bool force) ++{ ++ ((struct mptcp_ccc *)inet_csk_ca(meta_sk))->forced_update = force; ++} ++ ++static void mptcp_ccc_recalc_alpha(const struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ const struct mptcp_tcp_sock *mptcp; ++ int best_cwnd = 0, best_rtt = 0, can_send = 0; ++ u64 max_numerator = 0, sum_denominator = 0, alpha = 1; ++ ++ if (!mpcb) ++ return; ++ ++ /* Do regular alpha-calculation for multiple subflows */ ++ ++ /* Find the max numerator of the alpha-calculation */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ u64 tmp; ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ can_send++; ++ ++ /* We need to look for the path, that provides the max-value. ++ * Integer-overflow is not possible here, because ++ * tmp will be in u64. ++ */ ++ tmp = div64_u64(mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_num), (u64)sub_tp->srtt_us * sub_tp->srtt_us); ++ ++ if (tmp >= max_numerator) { ++ max_numerator = tmp; ++ best_cwnd = sub_tp->snd_cwnd; ++ best_rtt = sub_tp->srtt_us; ++ } ++ } ++ ++ /* No subflow is able to send - we don't care anymore */ ++ if (unlikely(!can_send)) ++ goto exit; ++ ++ /* Calculate the denominator */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ ++ if (!mptcp_ccc_sk_can_send(sub_sk)) ++ continue; ++ ++ sum_denominator += div_u64( ++ mptcp_ccc_scale(sub_tp->snd_cwnd, ++ alpha_scale_den) * best_rtt, ++ sub_tp->srtt_us); ++ } ++ sum_denominator *= sum_denominator; ++ if (unlikely(!sum_denominator)) { ++ pr_err("%s: sum_denominator == 0\n", __func__); ++ mptcp_for_each_sub(mpcb, mptcp) { ++ const struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *sub_tp = tcp_sk(sub_sk); ++ pr_err("%s: pi:%d, state:%d\n, rtt:%u, cwnd: %u", ++ __func__, sub_tp->mptcp->path_index, ++ sub_sk->sk_state, sub_tp->srtt_us, ++ sub_tp->snd_cwnd); ++ } ++ } ++ ++ alpha = div64_u64(mptcp_ccc_scale(best_cwnd, alpha_scale_num), sum_denominator); ++ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++exit: ++ mptcp_set_alpha(mptcp_meta_sk(sk), alpha); ++} ++ ++static void mptcp_ccc_init(struct sock *sk) ++{ ++ if (mptcp(tcp_sk(sk))) { ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ mptcp_set_alpha(mptcp_meta_sk(sk), 1); ++ } ++ /* If we do not mptcp, behave like reno: return */ ++} ++ ++static void mptcp_ccc_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_LOSS) ++ mptcp_ccc_recalc_alpha(sk); ++} ++ ++static void mptcp_ccc_set_state(struct sock *sk, u8 ca_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ mptcp_set_forced(mptcp_meta_sk(sk), 1); ++} ++ ++static void mptcp_ccc_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ int snd_cwnd; ++ u64 alpha; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ if (tcp_in_slow_start(tp)) { ++ /* In "safe" area, increase. */ ++ tcp_slow_start(tp, acked); ++ mptcp_ccc_recalc_alpha(sk); ++ return; ++ } ++ ++ if (mptcp_get_forced(mptcp_meta_sk(sk))) { ++ mptcp_ccc_recalc_alpha(sk); ++ mptcp_set_forced(mptcp_meta_sk(sk), 0); ++ } ++ ++ alpha = mptcp_get_alpha(mptcp_meta_sk(sk)); ++ ++ /* This may happen, if at the initialization, the mpcb ++ * was not yet attached to the sock, and thus ++ * initializing alpha failed. ++ */ ++ if (unlikely(!alpha)) ++ alpha = 1; ++ ++ snd_cwnd = (int)div_u64((u64)mptcp_ccc_scale(1, alpha_scale), alpha); ++ ++ /* snd_cwnd_cnt >= max (scale * tot_cwnd / alpha, cwnd) ++ * Thus, we select here the max value. ++ */ ++ if (snd_cwnd < tp->snd_cwnd) ++ snd_cwnd = tp->snd_cwnd; ++ ++ if (tp->snd_cwnd_cnt >= snd_cwnd) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { ++ tp->snd_cwnd++; ++ mptcp_ccc_recalc_alpha(sk); ++ } ++ ++ tp->snd_cwnd_cnt = 0; ++ } else { ++ tp->snd_cwnd_cnt++; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_ccc = { ++ .init = mptcp_ccc_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_ccc_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .cwnd_event = mptcp_ccc_cwnd_event, ++ .set_state = mptcp_ccc_set_state, ++ .owner = THIS_MODULE, ++ .name = "lia", ++}; ++ ++static int __init mptcp_ccc_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_ccc) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_ccc); ++} ++ ++static void __exit mptcp_ccc_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_ccc); ++} ++ ++module_init(mptcp_ccc_register); ++module_exit(mptcp_ccc_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch, Sébastien Barré"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP LINKED INCREASE CONGESTION CONTROL ALGORITHM"); ++MODULE_VERSION("0.1"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_ctrl.c linux-5.4.64.mptcp/net/mptcp/mptcp_ctrl.c +--- linux-5.4.64/net/mptcp/mptcp_ctrl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_ctrl.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,3309 @@ ++/* ++ * MPTCP implementation - MPTCP-control ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *mptcp_sock_cache __read_mostly; ++static struct kmem_cache *mptcp_cb_cache __read_mostly; ++static struct kmem_cache *mptcp_tw_cache __read_mostly; ++ ++int sysctl_mptcp_enabled __read_mostly = 1; ++int sysctl_mptcp_version __read_mostly = 0; ++static int min_mptcp_version; ++static int max_mptcp_version = 1; ++int sysctl_mptcp_checksum __read_mostly = 1; ++int sysctl_mptcp_debug __read_mostly; ++EXPORT_SYMBOL(sysctl_mptcp_debug); ++int sysctl_mptcp_syn_retries __read_mostly = 3; ++ ++bool mptcp_init_failed __read_mostly; ++ ++struct static_key mptcp_static_key = STATIC_KEY_INIT_FALSE; ++EXPORT_SYMBOL(mptcp_static_key); ++ ++static void mptcp_key_hash(u8 version, u64 key, u32 *token, u64 *idsn); ++ ++static int proc_mptcp_path_manager(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_PM_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_path_manager(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_path_manager(val); ++ return ret; ++} ++ ++static int proc_mptcp_scheduler(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ char val[MPTCP_SCHED_NAME_MAX]; ++ struct ctl_table tbl = { ++ .data = val, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ }; ++ int ret; ++ ++ mptcp_get_default_scheduler(val); ++ ++ ret = proc_dostring(&tbl, write, buffer, lenp, ppos); ++ if (write && ret == 0) ++ ret = mptcp_set_default_scheduler(val); ++ return ret; ++} ++ ++static struct ctl_table mptcp_table[] = { ++ { ++ .procname = "mptcp_enabled", ++ .data = &sysctl_mptcp_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_version", ++ .data = &sysctl_mptcp_version, ++ .mode = 0644, ++ .maxlen = sizeof(int), ++ .proc_handler = &proc_dointvec_minmax, ++ .extra1 = &min_mptcp_version, ++ .extra2 = &max_mptcp_version, ++ }, ++ { ++ .procname = "mptcp_checksum", ++ .data = &sysctl_mptcp_checksum, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_debug", ++ .data = &sysctl_mptcp_debug, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_syn_retries", ++ .data = &sysctl_mptcp_syn_retries, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec ++ }, ++ { ++ .procname = "mptcp_path_manager", ++ .mode = 0644, ++ .maxlen = MPTCP_PM_NAME_MAX, ++ .proc_handler = proc_mptcp_path_manager, ++ }, ++ { ++ .procname = "mptcp_scheduler", ++ .mode = 0644, ++ .maxlen = MPTCP_SCHED_NAME_MAX, ++ .proc_handler = proc_mptcp_scheduler, ++ }, ++ { } ++}; ++ ++static inline u32 mptcp_hash_tk(u32 token, struct mptcp_hashtable *htable) ++{ ++ return token & htable->mask; ++} ++ ++struct mptcp_hashtable mptcp_tk_htable; ++EXPORT_SYMBOL(mptcp_tk_htable); ++ ++/* The following hash table is used to avoid collision of token */ ++static struct mptcp_hashtable mptcp_reqsk_tk_htb; ++ ++/* Lock, protecting the two hash-tables that hold the token. Namely, ++ * mptcp_reqsk_tk_htb and tk_hashtable ++ */ ++static spinlock_t mptcp_tk_hashlock; ++ ++static bool mptcp_reqsk_find_tk(const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token, &mptcp_reqsk_tk_htb); ++ const struct mptcp_request_sock *mtreqsk; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(mtreqsk, node, ++ &mptcp_reqsk_tk_htb.hashtable[hash], ++ hash_entry) { ++ if (token == mtreqsk->mptcp_loc_token) ++ return true; ++ } ++ /* A request-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_reqsk_insert_tk(struct request_sock *reqsk, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token, &mptcp_reqsk_tk_htb); ++ ++ hlist_nulls_add_head_rcu(&mptcp_rsk(reqsk)->hash_entry, ++ &mptcp_reqsk_tk_htb.hashtable[hash]); ++} ++ ++static void mptcp_reqsk_remove_tk(const struct request_sock *reqsk) ++{ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&mptcp_rsk(reqsk)->hash_entry); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++void mptcp_reqsk_destructor(struct request_sock *req) ++{ ++ if (!mptcp_rsk(req)->is_sub) ++ mptcp_reqsk_remove_tk(req); ++} ++ ++static void __mptcp_hash_insert(struct tcp_sock *meta_tp, const u32 token) ++{ ++ u32 hash = mptcp_hash_tk(token, &mptcp_tk_htable); ++ ++ hlist_nulls_add_head_rcu(&meta_tp->tk_table, ++ &mptcp_tk_htable.hashtable[hash]); ++ meta_tp->inside_tk_table = 1; ++} ++ ++static bool mptcp_find_token(u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token, &mptcp_tk_htable); ++ const struct tcp_sock *meta_tp; ++ const struct hlist_nulls_node *node; ++ ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &mptcp_tk_htable.hashtable[hash], ++ tk_table) { ++ if (token == meta_tp->mptcp_loc_token) ++ return true; ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ return false; ++} ++ ++static void mptcp_set_key_reqsk(struct request_sock *req, ++ const struct sk_buff *skb, ++ u32 seed) ++{ ++ const struct inet_request_sock *ireq = inet_rsk(req); ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ mtreq->mptcp_loc_key = mptcp_v4_get_key(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ mtreq->mptcp_loc_key = mptcp_v6_get_key(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ htons(ireq->ir_num), ++ ireq->ir_rmt_port, ++ seed); ++#endif ++ } ++ ++ mptcp_key_hash(mtreq->mptcp_ver, mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++} ++ ++/* New MPTCP-connection request, prepare a new token for the meta-socket that ++ * will be created in mptcp_check_req_master(), and store the received token. ++ */ ++static void mptcp_reqsk_new_mptcp(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tp->mptcp_ver) ++ mtreq->mptcp_ver = tp->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_reqsk(req, skb, mptcp_seed++); ++ } while (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)); ++ mptcp_reqsk_insert_tk(req, mtreq->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (mtreq->mptcp_ver == MPTCP_VERSION_0) { ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->rem_key_set = 1; ++ } ++} ++ ++static int mptcp_reqsk_new_cookie(struct request_sock *req, ++ const struct sock *sk, ++ const struct mptcp_options_received *mopt, ++ const struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* MPTCP version agreement */ ++ if (mopt->mptcp_ver >= tcp_sk(sk)->mptcp_ver) ++ mtreq->mptcp_ver = tcp_sk(sk)->mptcp_ver; ++ else ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ mptcp_set_key_reqsk(req, skb, tcp_rsk(req)->snt_isn); ++ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return false; ++ } ++ ++ inet_rsk(req)->saw_mpc = 1; ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (mtreq->mptcp_ver == MPTCP_VERSION_0) { ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->rem_key_set = 1; ++ } ++ ++ return true; ++} ++ ++static void mptcp_set_key_sk(const struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_sock *isk = inet_sk(sk); ++ ++ if (sk->sk_family == AF_INET) ++ tp->mptcp_loc_key = mptcp_v4_get_key(isk->inet_saddr, ++ isk->inet_daddr, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ tp->mptcp_loc_key = mptcp_v6_get_key(inet6_sk(sk)->saddr.s6_addr32, ++ sk->sk_v6_daddr.s6_addr32, ++ isk->inet_sport, ++ isk->inet_dport, ++ mptcp_seed++); ++#endif ++ ++ mptcp_key_hash(tp->mptcp_ver, tp->mptcp_loc_key, &tp->mptcp_loc_token, NULL); ++} ++ ++#ifdef CONFIG_JUMP_LABEL ++static atomic_t mptcp_needed_deferred; ++static atomic_t mptcp_wanted; ++ ++static void mptcp_clear(struct work_struct *work) ++{ ++ int deferred = atomic_xchg(&mptcp_needed_deferred, 0); ++ int wanted; ++ ++ wanted = atomic_add_return(deferred, &mptcp_wanted); ++ if (wanted > 0) ++ static_key_enable(&mptcp_static_key); ++ else ++ static_key_disable(&mptcp_static_key); ++} ++ ++static DECLARE_WORK(mptcp_work, mptcp_clear); ++#endif ++ ++static void mptcp_enable_static_key_bh(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 0) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted + 1) == wanted) ++ return; ++ } ++ atomic_inc(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++static void mptcp_enable_static_key(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ atomic_inc(&mptcp_wanted); ++ static_key_enable(&mptcp_static_key); ++#else ++ static_key_slow_inc(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_disable_static_key(void) ++{ ++#ifdef CONFIG_JUMP_LABEL ++ int wanted; ++ ++ while (1) { ++ wanted = atomic_read(&mptcp_wanted); ++ if (wanted <= 1) ++ break; ++ if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted - 1) == wanted) ++ return; ++ } ++ atomic_dec(&mptcp_needed_deferred); ++ schedule_work(&mptcp_work); ++#else ++ static_key_slow_dec(&mptcp_static_key); ++#endif ++} ++ ++void mptcp_enable_sock(struct sock *sk) ++{ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ sock_set_flag(sk, SOCK_MPTCP); ++ tcp_sk(sk)->mptcp_ver = sysctl_mptcp_version; ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &mptcp_v6_specific; ++#endif ++ ++ mptcp_enable_static_key(); ++ } ++} ++ ++void mptcp_disable_sock(struct sock *sk) ++{ ++ if (sock_flag(sk, SOCK_MPTCP)) { ++ sock_reset_flag(sk, SOCK_MPTCP); ++ ++ /* Necessary here, because MPTCP can be enabled/disabled through ++ * a setsockopt. ++ */ ++ if (sk->sk_family == AF_INET) ++ inet_csk(sk)->icsk_af_ops = &ipv4_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (mptcp_v6_is_v4_mapped(sk)) ++ inet_csk(sk)->icsk_af_ops = &ipv6_mapped; ++ else ++ inet_csk(sk)->icsk_af_ops = &ipv6_specific; ++#endif ++ ++ mptcp_disable_static_key(); ++ } ++} ++ ++void mptcp_connect_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ do { ++ mptcp_set_key_sk(sk); ++ } while (mptcp_reqsk_find_tk(tp->mptcp_loc_token) || ++ mptcp_find_token(tp->mptcp_loc_token)); ++ ++ __mptcp_hash_insert(tp, tp->mptcp_loc_token); ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVE); ++} ++ ++/** ++ * This function increments the refcount of the mpcb struct. ++ * It is the responsibility of the caller to decrement when releasing ++ * the structure. ++ */ ++struct sock *mptcp_hash_find(const struct net *net, const u32 token) ++{ ++ const u32 hash = mptcp_hash_tk(token, &mptcp_tk_htable); ++ const struct tcp_sock *meta_tp; ++ struct sock *meta_sk = NULL; ++ const struct hlist_nulls_node *node; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++begin: ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &mptcp_tk_htable.hashtable[hash], ++ tk_table) { ++ meta_sk = (struct sock *)meta_tp; ++ if (token == meta_tp->mptcp_loc_token && ++ net_eq(net, sock_net(meta_sk))) { ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ goto out; ++ if (unlikely(token != meta_tp->mptcp_loc_token || ++ !net_eq(net, sock_net(meta_sk)))) { ++ sock_gen_put(meta_sk); ++ goto begin; ++ } ++ goto found; ++ } ++ } ++ /* A TCP-socket is destroyed by RCU. So, it might have been recycled ++ * and put into another hash-table list. So, after the lookup we may ++ * end up in a different list. So, we may need to restart. ++ * ++ * See also the comment in __inet_lookup_established. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++out: ++ meta_sk = NULL; ++found: ++ local_bh_enable(); ++ rcu_read_unlock(); ++ return meta_sk; ++} ++EXPORT_SYMBOL_GPL(mptcp_hash_find); ++ ++void mptcp_hash_remove_bh(struct tcp_sock *meta_tp) ++{ ++ /* remove from the token hashtable */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ hlist_nulls_del_init_rcu(&meta_tp->tk_table); ++ meta_tp->inside_tk_table = 0; ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++struct sock *mptcp_select_ack_sock(const struct sock *meta_sk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *rttsk = NULL, *lastsk = NULL; ++ u32 min_time = 0, last_active = 0; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 elapsed; ++ ++ if (!mptcp_sk_can_send_ack(sk) || tp->pf) ++ continue; ++ ++ elapsed = keepalive_time_elapsed(tp); ++ ++ /* We take the one with the lowest RTT within a reasonable ++ * (meta-RTO)-timeframe ++ */ ++ if (elapsed < inet_csk(meta_sk)->icsk_rto) { ++ if (!min_time || tp->srtt_us < min_time) { ++ min_time = tp->srtt_us; ++ rttsk = sk; ++ } ++ continue; ++ } ++ ++ /* Otherwise, we just take the most recent active */ ++ if (!rttsk && (!last_active || elapsed < last_active)) { ++ last_active = elapsed; ++ lastsk = sk; ++ } ++ } ++ ++ if (rttsk) ++ return rttsk; ++ ++ return lastsk; ++} ++EXPORT_SYMBOL(mptcp_select_ack_sock); ++ ++static void mptcp_sock_def_error_report(struct sock *sk) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ if (tp->send_mp_fclose && sk->sk_err == ETIMEDOUT) { ++ /* Called by the keep alive timer (tcp_write_timeout), ++ * when the limit of fastclose retransmissions has been ++ * reached. Send a TCP RST to clear the status of any ++ * stateful firewall (typically conntrack) which are ++ * not aware of mptcp and cannot understand the ++ * fastclose option. ++ */ ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ } ++ } ++ ++ /* record this info that can be used by PM after the sf close */ ++ tp->mptcp->sk_err = sk->sk_err; ++ ++ if (!tp->tcp_disconnect && mptcp_in_infinite_mapping_weak(mpcb)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ meta_sk->sk_err = sk->sk_err; ++ meta_sk->sk_err_soft = sk->sk_err_soft; ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_error_report(meta_sk); ++ ++ WARN(meta_sk->sk_state == TCP_CLOSE, ++ "Meta already closed i_rcv %u i_snd %u send_i %u flags %#lx\n", ++ mpcb->infinite_mapping_rcv, mpcb->infinite_mapping_snd, ++ mpcb->send_infinite_mapping, meta_sk->sk_flags); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++ } ++ ++ sk->sk_err = 0; ++ return; ++} ++ ++void mptcp_mpcb_put(struct mptcp_cb *mpcb) ++{ ++ if (refcount_dec_and_test(&mpcb->mpcb_refcnt)) { ++ mptcp_cleanup_path_manager(mpcb); ++ mptcp_cleanup_scheduler(mpcb); ++ kfree(mpcb->master_info); ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ } ++} ++EXPORT_SYMBOL(mptcp_mpcb_put); ++ ++static void mptcp_mpcb_cleanup(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tw *mptw; ++ ++ /* The mpcb is disappearing - we can make the final ++ * update to the rcv_nxt of the time-wait-sock and remove ++ * its reference to the mpcb. ++ */ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ list_for_each_entry_rcu(mptw, &mpcb->tw_list, list) { ++ list_del_rcu(&mptw->list); ++ mptw->in_list = 0; ++ mptcp_mpcb_put(mpcb); ++ rcu_assign_pointer(mptw->mpcb, NULL); ++ } ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ mptcp_mpcb_put(mpcb); ++} ++ ++static void mptcp_sock_destruct(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (!is_meta_sk(sk)) { ++ BUG_ON(!hlist_unhashed(&tp->mptcp->cb_list)); ++ ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ tp->mptcp = NULL; ++ ++ /* Taken when mpcb pointer was set */ ++ sock_put(mptcp_meta_sk(sk)); ++ mptcp_mpcb_put(tp->mpcb); ++ } else { ++ mptcp_debug("%s destroying meta-sk token %#x\n", __func__, ++ tcp_sk(sk)->mpcb->mptcp_loc_token); ++ ++ mptcp_mpcb_cleanup(tp->mpcb); ++ } ++ ++ WARN_ON(!static_key_false(&mptcp_static_key)); ++ ++ /* Must be called here, because this will decrement the jump-label. */ ++ inet_sock_destruct(sk); ++} ++ ++void mptcp_destroy_sock(struct sock *sk) ++{ ++ if (is_meta_sk(sk)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __skb_queue_purge(&tcp_sk(sk)->mpcb->reinject_queue); ++ ++ /* We have to close all remaining subflows. Normally, they ++ * should all be about to get closed. But, if the kernel is ++ * forcing a closure (e.g., tcp_write_err), the subflows might ++ * not have been closed properly (as we are waiting for the ++ * DATA_ACK of the DATA_FIN). ++ */ ++ mptcp_for_each_sub_safe(tcp_sk(sk)->mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ /* Already did call tcp_close - waiting for graceful ++ * closure, or if we are retransmitting fast-close on ++ * the subflow. The reset (or timeout) will kill the ++ * subflow.. ++ */ ++ if (tcp_sk(sk_it)->closing || ++ tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ ++ /* Allow the delayed work first to prevent time-wait state */ ++ if (delayed_work_pending(&tcp_sk(sk_it)->mptcp->work)) ++ continue; ++ ++ mptcp_sub_close(sk_it, 0); ++ } ++ } else { ++ mptcp_del_sock(sk); ++ } ++} ++ ++static void mptcp_set_state(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* Meta is not yet established - wake up the application */ ++ if ((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) && ++ sk->sk_state == TCP_ESTABLISHED) { ++ tcp_set_state(meta_sk, TCP_ESTABLISHED); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ sk_wake_async(meta_sk, SOCK_WAKE_IO, POLL_OUT); ++ } ++ ++ tcp_sk(meta_sk)->lsndtime = tcp_jiffies32; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) { ++ if (!sock_flag(sk, SOCK_DEAD)) ++ mptcp_sub_close(sk, 0); ++ } ++} ++ ++static int mptcp_set_congestion_control(struct sock *meta_sk, const char *name, ++ bool load, bool reinit, bool cap_net_admin) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ int err, result = 0; ++ ++ result = __tcp_set_congestion_control(meta_sk, name, load, reinit, cap_net_admin); ++ ++ tcp_sk(meta_sk)->mpcb->tcp_ca_explicit_set = true; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ err = __tcp_set_congestion_control(sk_it, name, load, reinit, cap_net_admin); ++ if (err) ++ result = err; ++ } ++ return result; ++} ++ ++static void mptcp_assign_congestion_control(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct inet_connection_sock *meta_icsk = inet_csk(mptcp_meta_sk(sk)); ++ const struct tcp_congestion_ops *ca = meta_icsk->icsk_ca_ops; ++ ++ /* Congestion control is the same as meta. Thus, it has been ++ * try_module_get'd by tcp_assign_congestion_control. ++ * Congestion control on meta was not explicitly configured by ++ * application, leave default or route based. ++ */ ++ if (icsk->icsk_ca_ops == ca || ++ !tcp_sk(mptcp_meta_sk(sk))->mpcb->tcp_ca_explicit_set) ++ return; ++ ++ /* Use the same congestion control as set on the meta-sk */ ++ if (!try_module_get(ca->owner)) { ++ /* This should never happen. The congestion control is linked ++ * to the meta-socket (through tcp_assign_congestion_control) ++ * who "holds" the refcnt on the module. ++ */ ++ WARN(1, "Could not get the congestion control!"); ++ return; ++ } ++ module_put(icsk->icsk_ca_ops->owner); ++ icsk->icsk_ca_ops = ca; ++ ++ /* Clear out private data before diag gets it and ++ * the ca has not been initialized. ++ */ ++ if (ca->get_info) ++ memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); ++ ++ return; ++} ++ ++siphash_key_t mptcp_secret __read_mostly; ++u32 mptcp_seed = 0; ++ ++#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / 4) ++ ++static void mptcp_key_sha256(const u64 key, u32 *token, u64 *idsn) ++{ ++ u32 mptcp_hashed_key[SHA256_DIGEST_WORDS]; ++ struct sha256_state state; ++ ++ sha256_init(&state); ++ sha256_update(&state, (const u8 *)&key, sizeof(key)); ++ sha256_final(&state, (u8 *)mptcp_hashed_key); ++ ++ if (token) ++ *token = mptcp_hashed_key[0]; ++ if (idsn) ++ *idsn = ntohll(*((__be64 *)&mptcp_hashed_key[6])); ++} ++ ++static void mptcp_hmac_sha256(const u8 *key_1, const u8 *key_2, u8 *hash_out, ++ int arg_num, va_list list) ++{ ++ u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE]; ++ struct sha256_state state; ++ int index, msg_length; ++ int length = 0; ++ u8 *msg; ++ int i; ++ ++ /* Generate key xored with ipad */ ++ memset(input, 0x36, SHA256_BLOCK_SIZE); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ index = SHA256_BLOCK_SIZE; ++ msg_length = 0; ++ for (i = 0; i < arg_num; i++) { ++ length = va_arg(list, int); ++ msg = va_arg(list, u8 *); ++ BUG_ON(index + length >= sizeof(input)); /* Message is too long */ ++ memcpy(&input[index], msg, length); ++ index += length; ++ msg_length += length; ++ } ++ ++ sha256_init(&state); ++ sha256_update(&state, input, SHA256_BLOCK_SIZE + msg_length); ++ sha256_final(&state, &input[SHA256_BLOCK_SIZE]); ++ ++ /* Prepare second part of hmac */ ++ memset(input, 0x5C, SHA256_BLOCK_SIZE); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ sha256_init(&state); ++ sha256_update(&state, input, sizeof(input)); ++ sha256_final(&state, hash_out); ++} ++ ++static void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u32 mptcp_hashed_key[SHA_DIGEST_WORDS]; ++ u8 input[64]; ++ int i; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Initialize input with appropriate padding */ ++ memset(&input[9], 0, sizeof(input) - 10); /* -10, because the last byte ++ * is explicitly set too ++ */ ++ memcpy(input, &key, sizeof(key)); /* Copy key to the msg beginning */ ++ input[8] = 0x80; /* Padding: First bit after message = 1 */ ++ input[63] = 0x40; /* Padding: Length of the message = 64 bits */ ++ ++ sha_init(mptcp_hashed_key); ++ sha_transform(mptcp_hashed_key, input, workspace); ++ ++ for (i = 0; i < 5; i++) ++ mptcp_hashed_key[i] = (__force u32)cpu_to_be32(mptcp_hashed_key[i]); ++ ++ if (token) ++ *token = mptcp_hashed_key[0]; ++ if (idsn) ++ *idsn = ntohll(*((__be64 *)&mptcp_hashed_key[3])); ++} ++ ++static void mptcp_key_hash(u8 version, u64 key, u32 *token, u64 *idsn) ++{ ++ if (version == MPTCP_VERSION_0) ++ mptcp_key_sha1(key, token, idsn); ++ else if (version >= MPTCP_VERSION_1) ++ mptcp_key_sha256(key, token, idsn); ++} ++ ++static void mptcp_hmac_sha1(const u8 *key_1, const u8 *key_2, u32 *hash_out, ++ int arg_num, va_list list) ++{ ++ u32 workspace[SHA_WORKSPACE_WORDS]; ++ u8 input[128]; /* 2 512-bit blocks */ ++ int i; ++ int index; ++ int length; ++ u8 *msg; ++ ++ memset(workspace, 0, sizeof(workspace)); ++ ++ /* Generate key xored with ipad */ ++ memset(input, 0x36, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ index = 64; ++ for (i = 0; i < arg_num; i++) { ++ length = va_arg(list, int); ++ msg = va_arg(list, u8 *); ++ BUG_ON(index + length > 125); /* Message is too long */ ++ memcpy(&input[index], msg, length); ++ index += length; ++ } ++ ++ input[index] = 0x80; /* Padding: First bit after message = 1 */ ++ memset(&input[index + 1], 0, (126 - index)); ++ ++ /* Padding: Length of the message = 512 + message length (bits) */ ++ input[126] = 0x02; ++ input[127] = ((index - 64) * 8); /* Message length (bits) */ ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = (__force u32)cpu_to_be32(hash_out[i]); ++ ++ /* Prepare second part of hmac */ ++ memset(input, 0x5C, 64); ++ for (i = 0; i < 8; i++) ++ input[i] ^= key_1[i]; ++ for (i = 0; i < 8; i++) ++ input[i + 8] ^= key_2[i]; ++ ++ memcpy(&input[64], hash_out, 20); ++ input[84] = 0x80; ++ memset(&input[85], 0, 41); ++ ++ /* Padding: Length of the message = 512 + 160 bits */ ++ input[126] = 0x02; ++ input[127] = 0xA0; ++ ++ sha_init(hash_out); ++ sha_transform(hash_out, input, workspace); ++ memset(workspace, 0, sizeof(workspace)); ++ ++ sha_transform(hash_out, &input[64], workspace); ++ ++ for (i = 0; i < 5; i++) ++ hash_out[i] = (__force u32)cpu_to_be32(hash_out[i]); ++} ++ ++void mptcp_hmac(u8 ver, const u8 *key_1, const u8 *key_2, u8 *hash_out, ++ int arg_num, ...) ++{ ++ va_list args; ++ ++ va_start(args, arg_num); ++ if (ver == MPTCP_VERSION_0) ++ mptcp_hmac_sha1(key_1, key_2, (u32 *)hash_out, arg_num, args); ++ else if (ver >= MPTCP_VERSION_1) ++ mptcp_hmac_sha256(key_1, key_2, hash_out, arg_num, args); ++ va_end(args); ++} ++EXPORT_SYMBOL(mptcp_hmac); ++ ++static void mptcp_mpcb_inherit_sockopts(struct sock *meta_sk, struct sock *master_sk) ++{ ++ /* Socket-options handled by sk_clone_lock while creating the meta-sk. ++ * ====== ++ * SO_SNDBUF, SO_SNDBUFFORCE, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVLOWAT, ++ * SO_RCVTIMEO, SO_SNDTIMEO, SO_ATTACH_FILTER, SO_DETACH_FILTER, ++ * TCP_NODELAY, TCP_CORK ++ * ++ * Socket-options handled in this function here ++ * ====== ++ * TCP_DEFER_ACCEPT ++ * SO_KEEPALIVE ++ * ++ * Socket-options on the todo-list ++ * ====== ++ * SO_BINDTODEVICE - should probably prevent creation of new subsocks ++ * across other devices. - what about the api-draft? ++ * SO_DEBUG ++ * SO_REUSEADDR - probably we don't care about this ++ * SO_DONTROUTE, SO_BROADCAST ++ * SO_OOBINLINE ++ * SO_LINGER ++ * SO_TIMESTAMP* - I don't think this is of concern for a SOCK_STREAM ++ * SO_PASSSEC - I don't think this is of concern for a SOCK_STREAM ++ * SO_RXQ_OVFL ++ * TCP_COOKIE_TRANSACTIONS ++ * TCP_MAXSEG ++ * TCP_THIN_* - Handled by sk_clone_lock, but we need to support this ++ * in mptcp_meta_retransmit_timer. AND we need to check ++ * what is about the subsockets. ++ * TCP_LINGER2 ++ * TCP_WINDOW_CLAMP ++ * TCP_USER_TIMEOUT ++ * TCP_MD5SIG ++ * ++ * Socket-options of no concern for the meta-socket (but for the subsocket) ++ * ====== ++ * SO_PRIORITY ++ * SO_MARK ++ * TCP_CONGESTION ++ * TCP_SYNCNT ++ * TCP_QUICKACK ++ */ ++ ++ /* DEFER_ACCEPT should not be set on the meta, as we want to accept new subflows directly */ ++ inet_csk(meta_sk)->icsk_accept_queue.rskq_defer_accept = 0; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(meta_sk, SOCK_KEEPOPEN)) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ keepalive_time_when(tcp_sk(meta_sk))); ++ sock_reset_flag(master_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(master_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(master_sk)->recverr = 0; ++} ++ ++/* Called without holding lock on meta_sk */ ++static void mptcp_sub_inherit_sockopts(const struct sock *meta_sk, struct sock *sub_sk) ++{ ++ __u8 meta_tos; ++ ++ /* IP_TOS also goes to the subflow. */ ++ meta_tos = READ_ONCE(inet_sk(meta_sk)->tos); ++ if (inet_sk(sub_sk)->tos != meta_tos) { ++ inet_sk(sub_sk)->tos = meta_tos; ++ sub_sk->sk_priority = meta_sk->sk_priority; ++ sk_dst_reset(sub_sk); ++ } ++ ++ /* Inherit SO_REUSEADDR */ ++ sub_sk->sk_reuse = meta_sk->sk_reuse; ++ ++ /* Inherit SO_MARK: can be used for routing or filtering */ ++ sub_sk->sk_mark = meta_sk->sk_mark; ++ ++ /* Inherit snd/rcv-buffer locks */ ++ sub_sk->sk_userlocks = meta_sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; ++ ++ /* Nagle/Cork is forced off on the subflows. It is handled at the meta-layer */ ++ tcp_sk(sub_sk)->nonagle = TCP_NAGLE_OFF|TCP_NAGLE_PUSH; ++ ++ /* Keepalives are handled entirely at the MPTCP-layer */ ++ if (sock_flag(sub_sk, SOCK_KEEPOPEN)) { ++ sock_reset_flag(sub_sk, SOCK_KEEPOPEN); ++ inet_csk_delete_keepalive_timer(sub_sk); ++ } ++ ++ /* Do not propagate subflow-errors up to the MPTCP-layer */ ++ inet_sk(sub_sk)->recverr = 0; ++} ++ ++void mptcp_prepare_for_backlog(struct sock *sk, struct sk_buff *skb) ++{ ++ /* In case of success (in mptcp_backlog_rcv) and error (in kfree_skb) of ++ * sk_add_backlog, we will decrement the sk refcount. ++ */ ++ sock_hold(sk); ++ skb->sk = sk; ++ skb->destructor = sock_efree; ++} ++ ++int mptcp_backlog_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ /* skb-sk may be NULL if we receive a packet immediatly after the ++ * SYN/ACK + MP_CAPABLE. ++ */ ++ struct sock *sk = skb->sk ? skb->sk : meta_sk; ++ int ret = 0; ++ ++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) { ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ /* Decrement sk refcnt when calling the skb destructor. ++ * Refcnt is incremented and skb destructor is set in tcp_v{4,6}_rcv via ++ * mptcp_prepare_for_backlog() here above. ++ */ ++ skb_orphan(skb); ++ ++ if (sk->sk_family == AF_INET) ++ ret = tcp_v4_do_rcv(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ ret = tcp_v6_do_rcv(sk, skb); ++#endif ++ ++ sock_put(sk); ++ return ret; ++} ++ ++static void mptcp_init_buffer_space(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int space; ++ ++ tcp_init_buffer_space(sk); ++ ++ if (is_master_tp(tp)) { ++ meta_tp->rcvq_space.space = meta_tp->rcv_wnd; ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->rcvq_space.time = meta_tp->tcp_mstamp; ++ meta_tp->rcvq_space.seq = meta_tp->copied_seq; ++ ++ /* If there is only one subflow, we just use regular TCP ++ * autotuning. User-locks are handled already by ++ * tcp_init_buffer_space ++ */ ++ meta_tp->window_clamp = tp->window_clamp; ++ meta_tp->rcv_ssthresh = tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = sk->sk_rcvbuf; ++ meta_sk->sk_sndbuf = sk->sk_sndbuf; ++ ++ return; ++ } ++ ++ if (meta_sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ goto snd_buf; ++ ++ /* Adding a new subflow to the rcv-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_rcvbuf + sk->sk_rcvbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_rmem[2]); ++ if (space > meta_sk->sk_rcvbuf) { ++ meta_tp->window_clamp += tp->window_clamp; ++ meta_tp->rcv_ssthresh += tp->rcv_ssthresh; ++ meta_sk->sk_rcvbuf = space; ++ } ++ ++snd_buf: ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return; ++ ++ /* Adding a new subflow to the send-buffer space. We make a simple ++ * addition, to give some space to allow traffic on the new subflow. ++ * Autotuning will increase it further later on. ++ */ ++ space = min(meta_sk->sk_sndbuf + sk->sk_sndbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]); ++ if (space > meta_sk->sk_sndbuf) { ++ meta_sk->sk_sndbuf = space; ++ meta_sk->sk_write_space(meta_sk); ++ } ++} ++ ++struct lock_class_key meta_key; ++char *meta_key_name = "sk_lock-AF_INET-MPTCP"; ++struct lock_class_key meta_slock_key; ++char *meta_slock_key_name = "slock-AF_INET-MPTCP"; ++ ++static const struct tcp_sock_ops mptcp_meta_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = mptcp_send_fin, ++ .write_xmit = mptcp_write_xmit, ++ .send_active_reset = mptcp_send_active_reset, ++ .write_wakeup = mptcp_write_wakeup, ++ .retransmit_timer = mptcp_meta_retransmit_timer, ++ .time_wait = mptcp_time_wait, ++ .cleanup_rbuf = mptcp_cleanup_rbuf, ++ .set_cong_ctrl = mptcp_set_congestion_control, ++}; ++ ++static const struct tcp_sock_ops mptcp_sub_specific = { ++ .__select_window = __mptcp_select_window, ++ .select_window = mptcp_select_window, ++ .select_initial_window = mptcp_select_initial_window, ++ .init_buffer_space = mptcp_init_buffer_space, ++ .set_rto = mptcp_tcp_set_rto, ++ .should_expand_sndbuf = mptcp_should_expand_sndbuf, ++ .send_fin = tcp_send_fin, ++ .write_xmit = tcp_write_xmit, ++ .send_active_reset = tcp_send_active_reset, ++ .write_wakeup = tcp_write_wakeup, ++ .retransmit_timer = mptcp_sub_retransmit_timer, ++ .time_wait = tcp_time_wait, ++ .cleanup_rbuf = tcp_cleanup_rbuf, ++ .set_cong_ctrl = __tcp_set_congestion_control, ++}; ++ ++void mptcp_initialize_recv_vars(struct tcp_sock *meta_tp, struct mptcp_cb *mpcb, ++ __u64 remote_key) ++{ ++ u64 idsn; ++ ++ mpcb->mptcp_rem_key = remote_key; ++ mpcb->rem_key_set = 1; ++ mptcp_key_hash(mpcb->mptcp_ver, mpcb->mptcp_rem_key, &mpcb->mptcp_rem_token, &idsn); ++ ++ idsn++; ++ mpcb->rcv_high_order[0] = idsn >> 32; ++ mpcb->rcv_high_order[1] = mpcb->rcv_high_order[0] + 1; ++ meta_tp->copied_seq = (u32)idsn; ++ meta_tp->rcv_nxt = (u32)idsn; ++ meta_tp->rcv_wup = (u32)idsn; ++ ++ meta_tp->snd_wl1 = meta_tp->rcv_nxt - 1; ++} ++ ++static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, ++ int rem_key_set, __u8 mptcp_ver, u32 window) ++{ ++ struct mptcp_cb *mpcb; ++ struct sock *master_sk; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ struct tcp_sock *master_tp, *meta_tp = tcp_sk(meta_sk); ++ u64 snd_idsn; ++ ++ dst_release(meta_sk->sk_rx_dst); ++ meta_sk->sk_rx_dst = NULL; ++ /* This flag is set to announce sock_lock_init to ++ * reclassify the lock-class of the master socket. ++ */ ++ meta_tp->is_master_sk = 1; ++ master_sk = sk_clone_lock(meta_sk, GFP_ATOMIC | __GFP_ZERO); ++ meta_tp->is_master_sk = 0; ++ if (!master_sk) ++ goto err_alloc_master; ++ ++ /* Same as in inet_csk_clone_lock - need to init to 0 */ ++ memset(&inet_csk(master_sk)->icsk_accept_queue, 0, ++ sizeof(inet_csk(master_sk)->icsk_accept_queue)); ++ ++ master_tp = tcp_sk(master_sk); ++ master_tp->inside_tk_table = 0; ++ ++ mpcb = kmem_cache_zalloc(mptcp_cb_cache, GFP_ATOMIC); ++ if (!mpcb) ++ goto err_alloc_mpcb; ++ ++ /* Store the mptcp version agreed on initial handshake */ ++ mpcb->mptcp_ver = mptcp_ver; ++ ++ /* Store the keys and generate the peer's token */ ++ mpcb->mptcp_loc_key = meta_tp->mptcp_loc_key; ++ mpcb->mptcp_loc_token = meta_tp->mptcp_loc_token; ++ ++ /* Generate Initial data-sequence-numbers */ ++ mptcp_key_hash(mpcb->mptcp_ver, mpcb->mptcp_loc_key, NULL, &snd_idsn); ++ snd_idsn++; ++ mpcb->snd_high_order[0] = snd_idsn >> 32; ++ mpcb->snd_high_order[1] = mpcb->snd_high_order[0] - 1; ++ ++ mpcb->meta_sk = meta_sk; ++ mpcb->master_sk = master_sk; ++ ++ skb_queue_head_init(&mpcb->reinject_queue); ++ mutex_init(&mpcb->mpcb_mutex); ++ ++ /* Init time-wait stuff */ ++ INIT_LIST_HEAD(&mpcb->tw_list); ++ ++ INIT_HLIST_HEAD(&mpcb->callback_list); ++ INIT_HLIST_HEAD(&mpcb->conn_list); ++ spin_lock_init(&mpcb->mpcb_list_lock); ++ ++ mpcb->orig_sk_rcvbuf = meta_sk->sk_rcvbuf; ++ mpcb->orig_sk_sndbuf = meta_sk->sk_sndbuf; ++ mpcb->orig_window_clamp = meta_tp->window_clamp; ++ ++ /* The meta is directly linked - set refcnt to 1 */ ++ refcount_set(&mpcb->mpcb_refcnt, 1); ++ ++ if (!meta_tp->inside_tk_table) { ++ /* Adding the meta_tp in the token hashtable - coming from server-side */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* With lockless listeners, we might process two ACKs at the ++ * same time. With TCP, inet_csk_complete_hashdance takes care ++ * of this. But, for MPTCP this would be too late if we add ++ * this MPTCP-socket in the token table (new subflows might ++ * come in and match on this socket here. ++ * So, we need to check if someone else already added the token ++ * and revert in that case. The other guy won the race... ++ */ ++ if (mptcp_find_token(mpcb->mptcp_loc_token)) { ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ goto err_insert_token; ++ } ++ __mptcp_hash_insert(meta_tp, mpcb->mptcp_loc_token); ++ ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_icsk->icsk_af_ops == &mptcp_v6_mapped) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct tcp6_sock *master_tp6 = (struct tcp6_sock *)master_sk; ++ struct ipv6_pinfo *newnp, *np = inet6_sk(meta_sk); ++ struct ipv6_txoptions *opt; ++ ++ inet_sk(master_sk)->pinet6 = &master_tp6->inet6; ++ ++ /* The following heavily inspired from tcp_v6_syn_recv_sock() */ ++ newnp = inet6_sk(master_sk); ++ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ newnp->pktoptions = NULL; ++ newnp->opt = NULL; ++ ++ newnp->rxopt.all = 0; ++ newnp->repflow = 0; ++ np->rxopt.all = 0; ++ np->repflow = 0; ++ ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(master_sk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } ++ inet_csk(master_sk)->icsk_ext_hdr_len = 0; ++ if (opt) ++ inet_csk(master_sk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; ++ } ++#endif ++ ++ meta_tp->mptcp = NULL; ++ ++ meta_tp->write_seq = (u32)snd_idsn; ++ meta_tp->snd_sml = meta_tp->write_seq; ++ meta_tp->snd_una = meta_tp->write_seq; ++ meta_tp->snd_nxt = meta_tp->write_seq; ++ meta_tp->pushed_seq = meta_tp->write_seq; ++ meta_tp->snd_up = meta_tp->write_seq; ++ ++ if (rem_key_set) ++ mptcp_initialize_recv_vars(meta_tp, mpcb, remote_key); ++ ++ meta_tp->snd_wnd = window; ++ meta_tp->retrans_stamp = 0; /* Set in tcp_connect() */ ++ ++ meta_tp->packets_out = 0; ++ meta_icsk->icsk_probes_out = 0; ++ ++ rcu_assign_pointer(inet_sk(meta_sk)->inet_opt, NULL); ++ ++ /* Set mptcp-pointers */ ++ master_tp->mpcb = mpcb; ++ master_tp->meta_sk = meta_sk; ++ meta_tp->mpcb = mpcb; ++ meta_tp->meta_sk = meta_sk; ++ ++ /* Initialize the queues */ ++ master_tp->out_of_order_queue = RB_ROOT; ++ master_sk->tcp_rtx_queue = RB_ROOT; ++ INIT_LIST_HEAD(&master_tp->tsq_node); ++ INIT_LIST_HEAD(&master_tp->tsorted_sent_queue); ++ ++ master_sk->sk_tsq_flags = 0; ++ /* icsk_bind_hash inherited from the meta, but it will be properly set in ++ * mptcp_create_master_sk. Same operation is done in inet_csk_clone_lock. ++ */ ++ inet_csk(master_sk)->icsk_bind_hash = NULL; ++ ++ /* Init the accept_queue structure, we support a queue of 32 pending ++ * connections, it does not need to be huge, since we only store here ++ * pending subflow creations. ++ */ ++ reqsk_queue_alloc(&meta_icsk->icsk_accept_queue); ++ meta_sk->sk_max_ack_backlog = 32; ++ meta_sk->sk_ack_backlog = 0; ++ ++ if (!sock_flag(meta_sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(meta_sk, SOCK_MPTCP); ++ } ++ ++ /* Redefine function-pointers as the meta-sk is now fully ready */ ++ meta_tp->mpc = 1; ++ meta_tp->ops = &mptcp_meta_specific; ++ ++ meta_sk->sk_backlog_rcv = mptcp_backlog_rcv; ++ meta_sk->sk_destruct = mptcp_sock_destruct; ++ ++ /* Meta-level retransmit timer */ ++ meta_icsk->icsk_rto *= 2; /* Double of initial - rto */ ++ ++ tcp_init_xmit_timers(master_sk); ++ /* Has been set for sending out the SYN */ ++ inet_csk_clear_xmit_timer(meta_sk, ICSK_TIME_RETRANS); ++ ++ mptcp_mpcb_inherit_sockopts(meta_sk, master_sk); ++ ++ mptcp_init_path_manager(mpcb); ++ mptcp_init_scheduler(mpcb); ++ ++ if (!try_module_get(inet_csk(master_sk)->icsk_ca_ops->owner)) ++ tcp_assign_congestion_control(master_sk); ++ ++ master_tp->saved_syn = NULL; ++ ++ mptcp_debug("%s: created mpcb with token %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ return 0; ++ ++err_insert_token: ++ kmem_cache_free(mptcp_cb_cache, mpcb); ++ ++err_alloc_mpcb: ++ inet_sk(master_sk)->inet_opt = NULL; ++ master_sk->sk_state = TCP_CLOSE; ++ sock_orphan(master_sk); ++ bh_unlock_sock(master_sk); ++ sk_free(master_sk); ++ ++err_alloc_master: ++ return -ENOBUFS; ++} ++ ++/* Called without holding lock on mpcb */ ++static u8 mptcp_set_new_pathindex(struct mptcp_cb *mpcb) ++{ ++ int i; ++ ++ /* Start at 1, because 0 is reserved for the meta-sk */ ++ for (i = 1; i < sizeof(mpcb->path_index_bits) * 8; i++) { ++ if (!test_and_set_bit(i, &mpcb->path_index_bits)) ++ break; ++ } ++ ++ if (i == sizeof(mpcb->path_index_bits) * 8) ++ return 0; ++ return i; ++} ++ ++/* May be called without holding the meta-level lock */ ++int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id, ++ gfp_t flags) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tp->mptcp = kmem_cache_zalloc(mptcp_sock_cache, flags); ++ if (!tp->mptcp) ++ return -ENOMEM; ++ ++ tp->mptcp->path_index = mptcp_set_new_pathindex(mpcb); ++ /* No more space for more subflows? */ ++ if (!tp->mptcp->path_index) { ++ kmem_cache_free(mptcp_sock_cache, tp->mptcp); ++ return -EPERM; ++ } ++ ++ INIT_HLIST_NODE(&tp->mptcp->cb_list); ++ ++ tp->mptcp->tp = tp; ++ tp->mpcb = mpcb; ++ tp->meta_sk = meta_sk; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) { ++ mptcp_enable_static_key_bh(); ++ sock_set_flag(sk, SOCK_MPTCP); ++ } ++ ++ tp->mpc = 1; ++ tp->ops = &mptcp_sub_specific; ++ ++ tp->mptcp->loc_id = loc_id; ++ tp->mptcp->rem_id = rem_id; ++ if (mpcb->sched_ops->init) ++ mpcb->sched_ops->init(sk); ++ ++ /* The corresponding sock_put is in mptcp_sock_destruct(). It cannot be ++ * included in mptcp_del_sock(), because the mpcb must remain alive ++ * until the last subsocket is completely destroyed. ++ */ ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ hlist_add_head_rcu(&tp->mptcp->node, &mpcb->conn_list); ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ tp->mptcp->attached = 1; ++ ++ mptcp_sub_inherit_sockopts(meta_sk, sk); ++ INIT_DELAYED_WORK(&tp->mptcp->work, mptcp_sub_close_wq); ++ ++ /* Properly inherit CC from the meta-socket */ ++ mptcp_assign_congestion_control(sk); ++ ++ /* As we successfully allocated the mptcp_tcp_sock, we have to ++ * change the function-pointers here (for sk_destruct to work correctly) ++ */ ++ sk->sk_error_report = mptcp_sock_def_error_report; ++ sk->sk_data_ready = mptcp_data_ready; ++ sk->sk_write_space = mptcp_write_space; ++ sk->sk_state_change = mptcp_set_state; ++ sk->sk_destruct = mptcp_sock_destruct; ++ ++ if (sk->sk_family == AF_INET) ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI4:%d dst_addr:%pI4:%d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, ++ &((struct inet_sock *)tp)->inet_saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &((struct inet_sock *)tp)->inet_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ else ++ mptcp_debug("%s: token %#x pi %d, src_addr:%pI6:%d dst_addr:%pI6:%d\n", ++ __func__ , mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &inet6_sk(sk)->saddr, ++ ntohs(((struct inet_sock *)tp)->inet_sport), ++ &sk->sk_v6_daddr, ++ ntohs(((struct inet_sock *)tp)->inet_dport)); ++#endif ++ ++ return 0; ++} ++ ++void mptcp_del_sock(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb; ++ ++ if (!tp->mptcp || !tp->mptcp->attached) ++ return; ++ ++ mpcb = tp->mpcb; ++ ++ if (mpcb->sched_ops->release) ++ mpcb->sched_ops->release(sk); ++ ++ if (mpcb->pm_ops->delete_subflow) ++ mpcb->pm_ops->delete_subflow(sk); ++ ++ mptcp_debug("%s: Removing subsock tok %#x pi:%d state %d is_meta? %d\n", ++ __func__, mpcb->mptcp_loc_token, tp->mptcp->path_index, ++ sk->sk_state, is_meta_sk(sk)); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ hlist_del_init_rcu(&tp->mptcp->node); ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ tp->mptcp->attached = 0; ++ mpcb->path_index_bits &= ~(1 << tp->mptcp->path_index); ++ ++ if (!tcp_write_queue_empty(sk) || !tcp_rtx_queue_empty(sk)) ++ mptcp_reinject_data(sk, 0); ++ ++ if (is_master_tp(tp)) { ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (meta_tp->record_master_info && ++ !sock_flag(meta_sk, SOCK_DEAD)) { ++ mpcb->master_info = kmalloc(sizeof(*mpcb->master_info), ++ GFP_ATOMIC); ++ ++ if (mpcb->master_info) ++ tcp_get_info(sk, mpcb->master_info, true); ++ } ++ ++ mpcb->master_sk = NULL; ++ } else if (tp->mptcp->pre_established) { ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ } ++} ++ ++/* Updates the MPTCP-session based on path-manager information (e.g., addresses, ++ * low-prio flows,...). ++ */ ++void mptcp_update_metasocket(const struct sock *meta_sk) ++{ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->new_session) ++ tcp_sk(meta_sk)->mpcb->pm_ops->new_session(meta_sk); ++} ++ ++/* Clean up the receive buffer for full frames taken by the user, ++ * then send an ACK if necessary. COPIED is the number of bytes ++ * tcp_recvmsg has given to the user so far, it speeds up the ++ * calculation of whether or not we must ACK for the sake of ++ * a window update. ++ * (inspired from tcp_cleanup_rbuf()) ++ */ ++void mptcp_cleanup_rbuf(struct sock *meta_sk, int copied) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ bool recheck_rcv_window = false; ++ struct mptcp_tcp_sock *mptcp; ++ __u32 rcv_window_now = 0; ++ ++ if (copied > 0 && !(meta_sk->sk_shutdown & RCV_SHUTDOWN)) { ++ rcv_window_now = tcp_receive_window(meta_tp); ++ ++ /* Optimize, __mptcp_select_window() is not cheap. */ ++ if (2 * rcv_window_now <= meta_tp->window_clamp) ++ recheck_rcv_window = true; ++ } ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (!mptcp_sk_can_send_ack(sk)) ++ continue; ++ ++ if (!inet_csk_ack_scheduled(sk)) ++ goto second_part; ++ /* Delayed ACKs frequently hit locked sockets during bulk ++ * receive. ++ */ ++ if (icsk->icsk_ack.blocked || ++ /* Once-per-two-segments ACK was not sent by tcp_input.c */ ++ tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || ++ /* If this read emptied read buffer, we send ACK, if ++ * connection is not bidirectional, user drained ++ * receive buffer and there was a small segment ++ * in queue. ++ */ ++ (copied > 0 && ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || ++ ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && ++ !icsk->icsk_ack.pingpong)) && ++ !atomic_read(&meta_sk->sk_rmem_alloc))) { ++ tcp_send_ack(sk); ++ continue; ++ } ++ ++second_part: ++ /* This here is the second part of tcp_cleanup_rbuf */ ++ if (recheck_rcv_window) { ++ __u32 new_window = tp->ops->__select_window(sk); ++ ++ /* Send ACK now, if this read freed lots of space ++ * in our buffer. Certainly, new_window is new window. ++ * We can advertise it now, if it is not less than ++ * current one. ++ * "Lots" means "at least twice" here. ++ */ ++ if (new_window && new_window >= 2 * rcv_window_now) ++ tcp_send_ack(sk); ++ } ++ } ++} ++ ++static int mptcp_sub_send_fin(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *skb = tcp_write_queue_tail(sk); ++ int mss_now; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = tcp_current_mss(sk); ++ ++ if (tcp_send_head(sk) != NULL) { ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ TCP_SKB_CB(skb)->end_seq++; ++ tp->write_seq++; ++ } else { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (!skb) ++ return 1; ++ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ skb_reserve(skb, MAX_TCP_HEADER); ++ /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ ++ tcp_init_nondata_skb(skb, tp->write_seq, ++ TCPHDR_ACK | TCPHDR_FIN); ++ tcp_queue_skb(sk, skb); ++ } ++ __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF); ++ ++ return 0; ++} ++ ++static void mptcp_sub_close_doit(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sock_flag(sk, SOCK_DEAD)) ++ return; ++ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) { ++ tp->closing = 1; ++ tcp_close(sk, 0); ++ } else if (tcp_close_state(sk)) { ++ sk->sk_shutdown |= SEND_SHUTDOWN; ++ tcp_send_fin(sk); ++ } ++} ++ ++void mptcp_sub_close_wq(struct work_struct *work) ++{ ++ struct tcp_sock *tp = container_of(work, struct mptcp_tcp_sock, work.work)->tp; ++ struct sock *sk = (struct sock *)tp; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_sub_close_doit(sk); ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(sk); ++} ++ ++void mptcp_sub_close(struct sock *sk, unsigned long delay) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct delayed_work *work = &tcp_sk(sk)->mptcp->work; ++ ++ /* We are already closing - e.g., call from sock_def_error_report upon ++ * tcp_disconnect in tcp_close. ++ */ ++ if (tp->closing) ++ return; ++ ++ /* Work already scheduled ? */ ++ if (work_pending(&work->work)) { ++ /* Work present - who will be first ? */ ++ if (jiffies + delay > work->timer.expires) ++ return; ++ ++ /* Try canceling - if it fails, work will be executed soon */ ++ if (!cancel_delayed_work(work)) ++ return; ++ sock_put(sk); ++ mptcp_mpcb_put(tp->mpcb); ++ } ++ ++ if (!delay) { ++ unsigned char old_state = sk->sk_state; ++ ++ /* We directly send the FIN. Because it may take so a long time, ++ * untile the work-queue will get scheduled... ++ * ++ * If mptcp_sub_send_fin returns 1, it failed and thus we reset ++ * the old state so that tcp_close will finally send the fin ++ * in user-context. ++ */ ++ if (!sk->sk_err && old_state != TCP_CLOSE && ++ tcp_close_state(sk) && mptcp_sub_send_fin(sk)) { ++ if (old_state == TCP_ESTABLISHED) ++ TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ sk->sk_state = old_state; ++ } ++ } ++ ++ sock_hold(sk); ++ refcount_inc(&tp->mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, work, delay); ++} ++ ++void mptcp_sub_force_close(struct sock *sk) ++{ ++ /* The below tcp_done may have freed the socket, if he is already dead. ++ * Thus, we are not allowed to access it afterwards. That's why ++ * we have to store the dead-state in this local variable. ++ */ ++ int sock_is_dead = sock_flag(sk, SOCK_DEAD); ++ ++ tcp_sk(sk)->mp_killed = 1; ++ ++ if (sk->sk_state != TCP_CLOSE) ++ tcp_done(sk); ++ ++ if (!sock_is_dead) ++ mptcp_sub_close(sk, 0); ++} ++EXPORT_SYMBOL(mptcp_sub_force_close); ++ ++/* Update the mpcb send window, based on the contributions ++ * of each subflow ++ */ ++void mptcp_update_sndbuf(const struct tcp_sock *tp) ++{ ++ struct sock *meta_sk = tp->meta_sk; ++ int new_sndbuf = 0, old_sndbuf = meta_sk->sk_sndbuf; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ new_sndbuf += sk->sk_sndbuf; ++ ++ if (new_sndbuf > sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2] || ++ new_sndbuf < 0) { ++ new_sndbuf = sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]; ++ break; ++ } ++ } ++ meta_sk->sk_sndbuf = max(min(new_sndbuf, ++ sock_net(meta_sk)->ipv4.sysctl_tcp_wmem[2]), ++ meta_sk->sk_sndbuf); ++ ++ /* The subflow's call to sk_write_space in tcp_new_space ends up in ++ * mptcp_write_space. ++ * It has nothing to do with waking up the application. ++ * So, we do it here. ++ */ ++ if (old_sndbuf != meta_sk->sk_sndbuf) ++ meta_sk->sk_write_space(meta_sk); ++} ++ ++/* Similar to: tcp_close */ ++void mptcp_close(struct sock *meta_sk, long timeout) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb; ++ int data_was_unread = 0; ++ int state; ++ ++ mptcp_debug("%s: Close of meta_sk with tok %#x\n", ++ __func__, mpcb->mptcp_loc_token); ++ ++ WARN_ON(refcount_inc_not_zero(&mpcb->mpcb_refcnt) == 0); ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (meta_tp->inside_tk_table) ++ /* Detach the mpcb from the token hashtable */ ++ mptcp_hash_remove_bh(meta_tp); ++ ++ meta_sk->sk_shutdown = SHUTDOWN_MASK; ++ /* We need to flush the recv. buffs. We do this only on the ++ * descriptor close, not protocol-sourced closes, because the ++ * reader process may not have drained the data yet! ++ */ ++ while ((skb = __skb_dequeue(&meta_sk->sk_receive_queue)) != NULL) { ++ u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ len--; ++ data_was_unread += len; ++ __kfree_skb(skb); ++ } ++ ++ sk_mem_reclaim(meta_sk); ++ ++ /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ ++ if (meta_sk->sk_state == TCP_CLOSE) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->send_mp_fclose) ++ continue; ++ mptcp_sub_close(sk_it, 0); ++ } ++ goto adjudge_to_death; ++ } ++ ++ if (data_was_unread) { ++ /* Unread data was tossed, zap the connection. */ ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONCLOSE); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ tcp_sk(meta_sk)->ops->send_active_reset(meta_sk, ++ meta_sk->sk_allocation); ++ } else if (sock_flag(meta_sk, SOCK_LINGER) && !meta_sk->sk_lingertime) { ++ /* Check zero linger _after_ checking for unread data. */ ++ meta_sk->sk_prot->disconnect(meta_sk, 0); ++ NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ } else if (tcp_close_state(meta_sk)) { ++ mptcp_send_fin(meta_sk); ++ } else if (meta_tp->snd_una == meta_tp->write_seq) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ /* The DATA_FIN has been sent and acknowledged ++ * (e.g., by sk_shutdown). Close all the other subflows ++ */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ unsigned long delay = 0; ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer. - thus we add a delay ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ ++ sk_stream_wait_close(meta_sk, timeout); ++ ++adjudge_to_death: ++ state = meta_sk->sk_state; ++ sock_hold(meta_sk); ++ sock_orphan(meta_sk); ++ ++ /* socket will be freed after mptcp_close - we have to prevent ++ * access from the subflows. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ /* Similar to sock_orphan, but we don't set it DEAD, because ++ * the callbacks are still set and must be called. ++ */ ++ write_lock_bh(&sk_it->sk_callback_lock); ++ sk_set_socket(sk_it, NULL); ++ sk_it->sk_wq = NULL; ++ write_unlock_bh(&sk_it->sk_callback_lock); ++ } ++ ++ if (mpcb->pm_ops->close_session) ++ mpcb->pm_ops->close_session(meta_sk); ++ ++ /* It is the last release_sock in its life. It will remove backlog. */ ++ release_sock(meta_sk); ++ ++ /* Now socket is owned by kernel and we acquire BH lock ++ * to finish close. No need to check for user refs. ++ */ ++ local_bh_disable(); ++ bh_lock_sock(meta_sk); ++ WARN_ON(sock_owned_by_user(meta_sk)); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ /* Have we already been destroyed by a softirq or backlog? */ ++ if (state != TCP_CLOSE && meta_sk->sk_state == TCP_CLOSE) ++ goto out; ++ ++ /* This is a (useful) BSD violating of the RFC. There is a ++ * problem with TCP as specified in that the other end could ++ * keep a socket open forever with no application left this end. ++ * We use a 3 minute timeout (about the same as BSD) then kill ++ * our end. If they send after that then tough - BUT: long enough ++ * that we won't make the old 4*rto = almost no time - whoops ++ * reset mistake. ++ * ++ * Nope, it was not mistake. It is really desired behaviour ++ * f.e. on http servers, when such sockets are useless, but ++ * consume significant resources. Let's do it with special ++ * linger2 option. --ANK ++ */ ++ ++ if (meta_sk->sk_state == TCP_FIN_WAIT2) { ++ if (meta_tp->linger2 < 0) { ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONLINGER); ++ } else { ++ const int tmo = tcp_fin_time(meta_sk); ++ ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, ++ tmo - TCP_TIMEWAIT_LEN); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, ++ tmo); ++ goto out; ++ } ++ } ++ } ++ if (meta_sk->sk_state != TCP_CLOSE) { ++ sk_mem_reclaim(meta_sk); ++ if (tcp_check_oom(meta_sk, 0)) { ++ if (net_ratelimit()) ++ pr_info("MPTCP: out of memory: force closing socket\n"); ++ tcp_set_state(meta_sk, TCP_CLOSE); ++ meta_tp->ops->send_active_reset(meta_sk, GFP_ATOMIC); ++ __NET_INC_STATS(sock_net(meta_sk), ++ LINUX_MIB_TCPABORTONMEMORY); ++ } ++ } ++ ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ inet_csk_destroy_sock(meta_sk); ++ /* Otherwise, socket is reprieved until protocol close. */ ++ ++out: ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); /* Taken by sock_hold */ ++} ++ ++void mptcp_disconnect(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __skb_queue_purge(&meta_tp->mpcb->reinject_queue); ++ ++ if (meta_tp->inside_tk_table) ++ mptcp_hash_remove_bh(meta_tp); ++ ++ local_bh_disable(); ++ mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ ++ if (spin_is_locked(&subsk->sk_lock.slock)) ++ bh_unlock_sock(subsk); ++ ++ tcp_sk(subsk)->tcp_disconnect = 1; ++ ++ meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); ++ ++ sock_orphan(subsk); ++ ++ percpu_counter_inc(meta_sk->sk_prot->orphan_count); ++ ++ inet_csk_destroy_sock(subsk); ++ } ++ local_bh_enable(); ++ ++ mptcp_mpcb_cleanup(meta_tp->mpcb); ++ meta_tp->meta_sk = NULL; ++ ++ meta_tp->send_mp_fclose = 0; ++ meta_tp->mpc = 0; ++ meta_tp->ops = &tcp_specific; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (meta_sk->sk_family == AF_INET6) ++ meta_sk->sk_backlog_rcv = tcp_v6_do_rcv; ++ else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#else ++ meta_sk->sk_backlog_rcv = tcp_v4_do_rcv; ++#endif ++ meta_sk->sk_destruct = inet_sock_destruct; ++} ++ ++ ++/* Returns True if we should enable MPTCP for that socket. */ ++bool mptcp_doit(struct sock *sk) ++{ ++ const struct dst_entry *dst = __sk_dst_get(sk); ++ ++ /* Don't do mptcp over loopback */ ++ if (sk->sk_family == AF_INET && ++ (ipv4_is_loopback(inet_sk(sk)->inet_daddr) || ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr))) ++ return false; ++#if IS_ENABLED(CONFIG_IPV6) ++ if (sk->sk_family == AF_INET6 && ++ (ipv6_addr_loopback(&sk->sk_v6_daddr) || ++ ipv6_addr_loopback(&inet6_sk(sk)->saddr))) ++ return false; ++#endif ++ if (mptcp_v6_is_v4_mapped(sk) && ++ ipv4_is_loopback(inet_sk(sk)->inet_saddr)) ++ return false; ++ ++#ifdef CONFIG_TCP_MD5SIG ++ /* If TCP_MD5SIG is enabled, do not do MPTCP - there is no Option-Space */ ++ if (tcp_sk(sk)->af_specific->md5_lookup(sk, sk)) ++ return false; ++#endif ++ ++ if (dst->dev && (dst->dev->flags & IFF_NOMULTIPATH)) ++ return false; ++ ++ return true; ++} ++ ++int mptcp_create_master_sk(struct sock *meta_sk, __u64 remote_key, ++ int rem_key_set, __u8 mptcp_ver, u32 window) ++{ ++ struct tcp_sock *master_tp; ++ struct sock *master_sk; ++ ++ if (mptcp_alloc_mpcb(meta_sk, remote_key, rem_key_set, mptcp_ver, window)) ++ goto err_alloc_mpcb; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ master_tp = tcp_sk(master_sk); ++ ++ if (mptcp_add_sock(meta_sk, master_sk, 0, 0, GFP_ATOMIC)) ++ goto err_add_sock; ++ ++ if (__inet_inherit_port(meta_sk, master_sk) < 0) ++ goto err_add_sock; ++ ++ meta_sk->sk_prot->unhash(meta_sk); ++ inet_ehash_nolisten(master_sk, NULL); ++ ++ master_tp->mptcp->init_rcv_wnd = master_tp->rcv_wnd; ++ ++ return 0; ++ ++err_add_sock: ++ inet_csk_prepare_forced_close(master_sk); ++ tcp_done(master_sk); ++ ++err_alloc_mpcb: ++ return -ENOBUFS; ++} ++ ++static int __mptcp_check_req_master(struct sock *child, ++ const struct mptcp_options_received *mopt, ++ struct request_sock *req) ++{ ++ struct tcp_sock *child_tp = tcp_sk(child); ++ struct sock *meta_sk = child; ++ struct mptcp_cb *mpcb; ++ struct mptcp_request_sock *mtreq; ++ ++ /* Never contained an MP_CAPABLE */ ++ if (!inet_rsk(req)->mptcp_rqsk) ++ return 1; ++ ++ mtreq = mptcp_rsk(req); ++ ++ if (!inet_rsk(req)->saw_mpc) { ++ /* Fallback to regular TCP, because we saw one SYN without ++ * MP_CAPABLE. In tcp_check_req we continue the regular path. ++ * But, the socket has been added to the reqsk_tk_htb, so we ++ * must still remove it. ++ */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); ++ mptcp_reqsk_remove_tk(req); ++ return 1; ++ } ++ ++ /* mopt can be NULL when coming from FAST-OPEN */ ++ if (mopt && mopt->saw_mpc && mtreq->mptcp_ver == MPTCP_VERSION_1) { ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->rem_key_set = 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEACK); ++ ++ /* Just set this values to pass them to mptcp_alloc_mpcb */ ++ child_tp->mptcp_loc_key = mtreq->mptcp_loc_key; ++ child_tp->mptcp_loc_token = mtreq->mptcp_loc_token; ++ ++ if (mptcp_create_master_sk(meta_sk, mtreq->mptcp_rem_key, ++ mtreq->rem_key_set, mtreq->mptcp_ver, ++ child_tp->snd_wnd)) { ++ inet_csk_prepare_forced_close(meta_sk); ++ tcp_done(meta_sk); ++ ++ return -ENOBUFS; ++ } ++ ++ child = tcp_sk(child)->mpcb->master_sk; ++ child_tp = tcp_sk(child); ++ mpcb = child_tp->mpcb; ++ ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ ++ mpcb->dss_csum = mtreq->dss_csum; ++ mpcb->server_side = 1; ++ ++ /* Needs to be done here additionally, because when accepting a ++ * new connection we pass by __reqsk_free and not reqsk_free. ++ */ ++ mptcp_reqsk_remove_tk(req); ++ ++ /* Hold when creating the meta-sk in tcp_vX_syn_recv_sock. */ ++ sock_put(meta_sk); ++ ++ return 0; ++} ++ ++int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req) ++{ ++ struct sock *meta_sk = child, *master_sk; ++ struct sk_buff *skb; ++ u32 new_mapping; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, NULL, req); ++ if (ret) ++ return ret; ++ ++ master_sk = tcp_sk(meta_sk)->mpcb->master_sk; ++ ++ /* We need to rewind copied_seq as it is set to IDSN + 1 and as we have ++ * pre-MPTCP data in the receive queue. ++ */ ++ tcp_sk(meta_sk)->copied_seq -= tcp_sk(master_sk)->rcv_nxt - ++ tcp_rsk(req)->rcv_isn - 1; ++ ++ /* Map subflow sequence number to data sequence numbers. We need to map ++ * these data to [IDSN - len - 1, IDSN[. ++ */ ++ new_mapping = tcp_sk(meta_sk)->copied_seq - tcp_rsk(req)->rcv_isn - 1; ++ ++ /* There should be only one skb: the SYN + data. */ ++ skb_queue_walk(&meta_sk->sk_receive_queue, skb) { ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ } ++ ++ /* With fastopen we change the semantics of the relative subflow ++ * sequence numbers to deal with middleboxes that could add/remove ++ * multiple bytes in the SYN. We chose to start counting at rcv_nxt - 1 ++ * instead of the regular TCP ISN. ++ */ ++ tcp_sk(master_sk)->mptcp->rcv_isn = tcp_sk(master_sk)->rcv_nxt - 1; ++ ++ /* We need to update copied_seq of the master_sk to account for the ++ * already moved data to the meta receive queue. ++ */ ++ tcp_sk(master_sk)->copied_seq = tcp_sk(master_sk)->rcv_nxt; ++ ++ /* Handled by the master_sk */ ++ tcp_sk(meta_sk)->fastopen_rsk = NULL; ++ ++ return 0; ++} ++ ++int mptcp_check_req_master(struct sock *sk, struct sock *child, ++ struct request_sock *req, const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ int drop, u32 tsoff) ++{ ++ struct sock *meta_sk = child; ++ int ret; ++ ++ ret = __mptcp_check_req_master(child, mopt, req); ++ if (ret) ++ return ret; ++ child = tcp_sk(child)->mpcb->master_sk; ++ ++ sock_rps_save_rxhash(child, skb); ++ ++ /* drop indicates that we come from tcp_check_req and thus need to ++ * handle the request-socket fully. ++ */ ++ if (drop) { ++ tcp_synack_rtt_meas(child, req); ++ ++ inet_csk_reqsk_queue_drop(sk, req); ++ reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ return -1; ++ } ++ } else { ++ /* Thus, we come from syn-cookies */ ++ refcount_set(&req->rsk_refcnt, 1); ++ tcp_sk(meta_sk)->tsoffset = tsoff; ++ if (!inet_csk_reqsk_queue_add(sk, req, meta_sk)) { ++ bh_unlock_sock(meta_sk); ++ /* No sock_put() of the meta needed. The reference has ++ * already been dropped in __mptcp_check_req_master(). ++ */ ++ sock_put(child); ++ reqsk_put(req); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* May be called without holding the meta-level lock */ ++struct sock *mptcp_check_req_child(struct sock *meta_sk, ++ struct sock *child, ++ struct request_sock *req, ++ struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ struct tcp_sock *child_tp = tcp_sk(child); ++ u8 hash_mac_check[SHA256_DIGEST_SIZE]; ++ ++ if (!mopt->join_ack) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKFAIL); ++ goto teardown; ++ } ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, hash_mac_check, 2, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce); ++ ++ if (memcmp(hash_mac_check, (char *)&mopt->mptcp_recv_mac, 20)) { ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKMAC); ++ goto teardown; ++ } ++ ++ /* Point it to the same struct socket and wq as the meta_sk */ ++ sk_set_socket(child, meta_sk->sk_socket); ++ child->sk_wq = meta_sk->sk_wq; ++ ++ if (mptcp_add_sock(meta_sk, child, mtreq->loc_id, mtreq->rem_id, GFP_ATOMIC)) { ++ /* Has been inherited, but now child_tp->mptcp is NULL */ ++ child_tp->mpc = 0; ++ child_tp->ops = &tcp_specific; ++ ++ /* TODO when we support acking the third ack for new subflows, ++ * we should silently discard this third ack, by returning NULL. ++ * ++ * Maybe, at the retransmission we will have enough memory to ++ * fully add the socket to the meta-sk. ++ */ ++ goto teardown; ++ } ++ ++ /* The child is a clone of the meta socket, we must now reset ++ * some of the fields ++ */ ++ child_tp->mptcp->rcv_low_prio = mtreq->rcv_low_prio; ++ ++ /* We should allow proper increase of the snd/rcv-buffers. Thus, we ++ * use the original values instead of the bloated up ones from the ++ * clone. ++ */ ++ child->sk_sndbuf = mpcb->orig_sk_sndbuf; ++ child->sk_rcvbuf = mpcb->orig_sk_rcvbuf; ++ ++ child_tp->mptcp->slave_sk = 1; ++ child_tp->mptcp->snt_isn = tcp_rsk(req)->snt_isn; ++ child_tp->mptcp->rcv_isn = tcp_rsk(req)->rcv_isn; ++ child_tp->mptcp->init_rcv_wnd = req->rsk_rcv_wnd; ++ ++ child->sk_tsq_flags = 0; ++ ++ child_tp->packets_out = 0; ++ ++ tcp_reset_vars(child); ++ ++ sock_rps_save_rxhash(child, skb); ++ tcp_synack_rtt_meas(child, req); ++ ++ if (mpcb->pm_ops->established_subflow) ++ mpcb->pm_ops->established_subflow(child); ++ ++ /* Subflows do not use the accept queue, as they ++ * are attached immediately to the mpcb. ++ */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ ++ /* The refcnt is initialized to 2, because regular TCP will put him ++ * in the socket's listener queue. However, we do not have a listener-queue. ++ * So, we need to make sure that this request-sock indeed gets destroyed. ++ */ ++ reqsk_put(req); ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINACKRX); ++ ++ if (inet_sk(child)->inet_sport != inet_sk(meta_sk)->inet_sport) ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINALTERNATEPORT); ++ ++ return child; ++ ++teardown: ++ req->rsk_ops->send_reset(meta_sk, skb); ++ ++ /* Drop this request - sock creation failed. */ ++ inet_csk_reqsk_queue_drop(meta_sk, req); ++ reqsk_queue_removed(&inet_csk(meta_sk)->icsk_accept_queue, req); ++ inet_csk_prepare_forced_close(child); ++ tcp_done(child); ++ bh_unlock_sock(meta_sk); ++ return meta_sk; ++} ++ ++int mptcp_init_tw_sock(struct sock *sk, struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_tw *mptw; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* A subsocket in tw can only receive data. So, if we are in ++ * infinite-receive, then we should not reply with a data-ack or act ++ * upon general MPTCP-signaling. We prevent this by simply not creating ++ * the mptcp_tw_sock. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ tw->mptcp_tw = NULL; ++ return 0; ++ } ++ ++ /* Alloc MPTCP-tw-sock */ ++ mptw = kmem_cache_alloc(mptcp_tw_cache, GFP_ATOMIC); ++ if (!mptw) { ++ tw->mptcp_tw = NULL; ++ return -ENOBUFS; ++ } ++ ++ refcount_inc(&mpcb->mpcb_refcnt); ++ ++ tw->mptcp_tw = mptw; ++ mptw->loc_key = mpcb->mptcp_loc_key; ++ mptw->meta_tw = mpcb->in_time_wait; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ if (mptw->meta_tw && mpcb->mptw_state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ rcu_assign_pointer(mptw->mpcb, mpcb); ++ ++ spin_lock_bh(&mpcb->mpcb_list_lock); ++ list_add_rcu(&mptw->list, &tp->mpcb->tw_list); ++ mptw->in_list = 1; ++ spin_unlock_bh(&mpcb->mpcb_list_lock); ++ ++ return 0; ++} ++ ++void mptcp_twsk_destructor(struct tcp_timewait_sock *tw) ++{ ++ struct mptcp_cb *mpcb; ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ mpcb = rcu_dereference(tw->mptcp_tw->mpcb); ++ ++ /* If we are still holding a ref to the mpcb, we have to remove ourself ++ * from the list and drop the ref properly. ++ */ ++ if (mpcb && refcount_inc_not_zero(&mpcb->mpcb_refcnt)) { ++ spin_lock(&mpcb->mpcb_list_lock); ++ if (tw->mptcp_tw->in_list) { ++ list_del_rcu(&tw->mptcp_tw->list); ++ tw->mptcp_tw->in_list = 0; ++ /* Put, because we added it to the list */ ++ mptcp_mpcb_put(mpcb); ++ } ++ spin_unlock(&mpcb->mpcb_list_lock); ++ ++ /* Second time, because we increased it above */ ++ mptcp_mpcb_put(mpcb); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ kmem_cache_free(mptcp_tw_cache, tw->mptcp_tw); ++} ++ ++/* Updates the rcv_nxt of the time-wait-socks and allows them to ack a ++ * data-fin. ++ */ ++void mptcp_time_wait(struct sock *meta_sk, int state, int timeo) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tw *mptw; ++ ++ if (mptcp_in_infinite_mapping_weak(meta_tp->mpcb)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it->sk_state == TCP_CLOSE) ++ continue; ++ ++ tcp_sk(sk_it)->ops->time_wait(sk_it, state, timeo); ++ } ++ } ++ ++ /* Used for sockets that go into tw after the meta ++ * (see mptcp_init_tw_sock()) ++ */ ++ meta_tp->mpcb->in_time_wait = 1; ++ meta_tp->mpcb->mptw_state = state; ++ ++ /* Update the time-wait-sock's information */ ++ rcu_read_lock(); ++ local_bh_disable(); ++ list_for_each_entry_rcu(mptw, &meta_tp->mpcb->tw_list, list) { ++ mptw->meta_tw = 1; ++ mptw->rcv_nxt = mptcp_get_rcv_nxt_64(meta_tp); ++ ++ /* We want to ack a DATA_FIN, but are yet in FIN_WAIT_2 - ++ * pretend as if the DATA_FIN has already reached us, that way ++ * the checks in tcp_timewait_state_process will be good as the ++ * DATA_FIN comes in. ++ */ ++ if (state != TCP_TIME_WAIT) ++ mptw->rcv_nxt++; ++ } ++ local_bh_enable(); ++ rcu_read_unlock(); ++ ++ if (meta_sk->sk_state != TCP_CLOSE) ++ tcp_done(meta_sk); ++} ++ ++void mptcp_tsq_flags(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ /* It will be handled as a regular deferred-call */ ++ if (is_meta_sk(sk)) ++ return; ++ ++ if (hlist_unhashed(&tp->mptcp->cb_list)) { ++ hlist_add_head(&tp->mptcp->cb_list, &tp->mpcb->callback_list); ++ /* We need to hold it here, as the sock_hold is not assured ++ * by the release_sock as it is done in regular TCP. ++ * ++ * The subsocket may get inet_csk_destroy'd while it is inside ++ * the callback_list. ++ */ ++ sock_hold(sk); ++ } ++ ++ if (!test_and_set_bit(MPTCP_SUB_DEFERRED, &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++} ++ ++void mptcp_tsq_sub_deferred(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ __sock_put(meta_sk); ++ hlist_for_each_entry_safe(mptcp, tmp, &meta_tp->mpcb->callback_list, cb_list) { ++ struct tcp_sock *tp = mptcp->tp; ++ struct sock *sk = (struct sock *)tp; ++ ++ hlist_del_init(&mptcp->cb_list); ++ sk->sk_prot->release_cb(sk); ++ /* Final sock_put (cfr. mptcp_tsq_flags) */ ++ sock_put(sk); ++ } ++} ++ ++/* May be called without holding the meta-level lock */ ++void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb, ++ const struct request_sock *req, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; ++ struct mptcp_options_received mopt; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->is_sub = 1; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ mtreq->mptcp_rem_nonce = mopt.mptcp_recv_nonce; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, ++ 4, (u8 *)&mtreq->mptcp_loc_nonce, ++ 4, (u8 *)&mtreq->mptcp_rem_nonce); ++ mtreq->mptcp_hash_tmac = *(u64 *)mptcp_hash_mac; ++ ++ mtreq->rem_id = mopt.rem_id; ++ mtreq->rcv_low_prio = mopt.low_prio; ++ inet_rsk(req)->saw_mpc = 1; ++ ++ MPTCP_INC_STATS(sock_net(mpcb->meta_sk), MPTCP_MIB_JOINSYNRX); ++} ++ ++void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_options_received mopt; ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ mtreq->dss_csum = mopt.dss_csum; ++ ++ if (want_cookie) { ++ if (!mptcp_reqsk_new_cookie(req, sk, &mopt, skb)) ++ /* No key available - back to regular TCP */ ++ inet_rsk(req)->mptcp_rqsk = 0; ++ return; ++ } ++ ++ mptcp_reqsk_new_mptcp(req, sk, &mopt, skb); ++} ++ ++void mptcp_cookies_reqsk_init(struct request_sock *req, ++ struct mptcp_options_received *mopt, ++ struct sk_buff *skb) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ ++ /* Absolutely need to always initialize this. */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ mtreq->mptcp_ver = mopt->mptcp_ver; ++ mtreq->mptcp_rem_key = mopt->mptcp_sender_key; ++ mtreq->mptcp_loc_key = mopt->mptcp_receiver_key; ++ mtreq->rem_key_set = 1; ++ ++ /* Generate the token */ ++ mptcp_key_hash(mtreq->mptcp_ver, mtreq->mptcp_loc_key, &mtreq->mptcp_loc_token, NULL); ++ ++ rcu_read_lock(); ++ local_bh_disable(); ++ spin_lock(&mptcp_tk_hashlock); ++ ++ /* Check, if the key is still free */ ++ if (mptcp_reqsk_find_tk(mtreq->mptcp_loc_token) || ++ mptcp_find_token(mtreq->mptcp_loc_token)) ++ goto out; ++ ++ inet_rsk(req)->saw_mpc = 1; ++ mtreq->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ mtreq->dss_csum = mopt->dss_csum; ++ ++out: ++ spin_unlock(&mptcp_tk_hashlock); ++ local_bh_enable(); ++ rcu_read_unlock(); ++} ++ ++int mptcp_conn_request(struct sock *sk, struct sk_buff *skb) ++{ ++ struct mptcp_options_received mopt; ++ ++ mptcp_init_mp_opt(&mopt); ++ tcp_parse_mptcp_options(skb, &mopt); ++ ++ if (mopt.is_mp_join) ++ return mptcp_do_join_short(skb, &mopt, sock_net(sk)); ++ if (mopt.drop_me) ++ goto drop; ++ ++ if (!sock_flag(sk, SOCK_MPTCP)) ++ mopt.saw_mpc = 0; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ if (mopt.saw_mpc) { ++ if (skb_rtable(skb)->rt_flags & ++ (RTCF_BROADCAST | RTCF_MULTICAST)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_request_sock_ipv4_ops, ++ sk, skb); ++ } ++ ++ return tcp_v4_conn_request(sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ if (mopt.saw_mpc) { ++ if (!ipv6_unicast_destination(skb)) ++ goto drop; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVE); ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_request_sock_ipv6_ops, ++ sk, skb); ++ } ++ ++ return tcp_v6_conn_request(sk, skb); ++#endif ++ } ++drop: ++ __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); ++ return 0; ++} ++ ++int mptcp_finish_handshake(struct sock *child, struct sk_buff *skb) ++ __releases(&child->sk_lock.slock) ++{ ++ int ret; ++ ++ /* We don't call tcp_child_process here, because we hold ++ * already the meta-sk-lock and are sure that it is not owned ++ * by the user. ++ */ ++ tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ++ ret = tcp_rcv_state_process(child, skb); ++ bh_unlock_sock(child); ++ sock_put(child); ++ ++ return ret; ++} ++ ++static void __mptcp_get_info(const struct sock *meta_sk, ++ struct mptcp_meta_info *info) ++{ ++ const struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 now = tcp_jiffies32; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ info->mptcpi_state = meta_sk->sk_state; ++ info->mptcpi_retransmits = meta_icsk->icsk_retransmits; ++ info->mptcpi_probes = meta_icsk->icsk_probes_out; ++ info->mptcpi_backoff = meta_icsk->icsk_backoff; ++ ++ info->mptcpi_rto = jiffies_to_usecs(meta_icsk->icsk_rto); ++ ++ info->mptcpi_unacked = meta_tp->packets_out; ++ ++ info->mptcpi_last_data_sent = jiffies_to_msecs(now - meta_tp->lsndtime); ++ info->mptcpi_last_data_recv = jiffies_to_msecs(now - meta_icsk->icsk_ack.lrcvtime); ++ info->mptcpi_last_ack_recv = jiffies_to_msecs(now - meta_tp->rcv_tstamp); ++ ++ info->mptcpi_total_retrans = meta_tp->total_retrans; ++ ++ info->mptcpi_bytes_acked = meta_tp->bytes_acked; ++ info->mptcpi_bytes_received = meta_tp->bytes_received; ++} ++ ++static void mptcp_get_sub_info(struct sock *sk, struct mptcp_sub_info *info) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ ++ memset(info, 0, sizeof(*info)); ++ ++ if (sk->sk_family == AF_INET) { ++ info->src_v4.sin_family = AF_INET; ++ info->src_v4.sin_port = inet->inet_sport; ++ ++ info->src_v4.sin_addr.s_addr = inet->inet_rcv_saddr; ++ if (!info->src_v4.sin_addr.s_addr) ++ info->src_v4.sin_addr.s_addr = inet->inet_saddr; ++ ++ info->dst_v4.sin_family = AF_INET; ++ info->dst_v4.sin_port = inet->inet_dport; ++ info->dst_v4.sin_addr.s_addr = inet->inet_daddr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ info->src_v6.sin6_family = AF_INET6; ++ info->src_v6.sin6_port = inet->inet_sport; ++ ++ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) ++ info->src_v6.sin6_addr = np->saddr; ++ else ++ info->src_v6.sin6_addr = sk->sk_v6_rcv_saddr; ++ ++ info->dst_v6.sin6_family = AF_INET6; ++ info->dst_v6.sin6_port = inet->inet_dport; ++ info->dst_v6.sin6_addr = sk->sk_v6_daddr; ++#endif ++ } ++} ++ ++int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ struct mptcp_meta_info meta_info; ++ struct mptcp_info m_info; ++ ++ unsigned int info_len; ++ ++ /* Check again with the lock held */ ++ if (!mptcp(meta_tp)) ++ return -EINVAL; ++ ++ if (copy_from_user(&m_info, optval, optlen)) ++ return -EFAULT; ++ ++ if (m_info.meta_info) { ++ unsigned int len; ++ ++ __mptcp_get_info(meta_sk, &meta_info); ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ len = min_t(unsigned int, m_info.meta_len, sizeof(meta_info)); ++ m_info.meta_len = len; ++ ++ if (copy_to_user((void __user *)m_info.meta_info, &meta_info, len)) ++ return -EFAULT; ++ } ++ ++ /* Need to set this, if user thinks that tcp_info is bigger than ours */ ++ info_len = min_t(unsigned int, m_info.tcp_info_len, sizeof(struct tcp_info)); ++ m_info.tcp_info_len = info_len; ++ ++ if (m_info.initial) { ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (mpcb->master_sk) { ++ struct tcp_info info; ++ ++ tcp_get_info(mpcb->master_sk, &info, true); ++ if (copy_to_user((void __user *)m_info.initial, &info, info_len)) ++ return -EFAULT; ++ } else if (meta_tp->record_master_info && mpcb->master_info) { ++ if (copy_to_user((void __user *)m_info.initial, mpcb->master_info, info_len)) ++ return -EFAULT; ++ } else { ++ return meta_tp->record_master_info ? -ENOMEM : -EINVAL; ++ } ++ } ++ ++ if (m_info.subflows) { ++ unsigned int len, sub_len = 0; ++ struct mptcp_tcp_sock *mptcp; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflows; ++ len = m_info.sub_len; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct tcp_info t_info; ++ unsigned int tmp_len; ++ ++ tcp_get_info(mptcp_to_sock(mptcp), &t_info, true); ++ ++ tmp_len = min_t(unsigned int, len, info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &t_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ sub_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.sub_len = sub_len; ++ } ++ ++ if (m_info.subflow_info) { ++ unsigned int len, sub_info_len, total_sub_info_len = 0; ++ struct mptcp_tcp_sock *mptcp; ++ char __user *ptr; ++ ++ ptr = (char __user *)m_info.subflow_info; ++ len = m_info.total_sub_info_len; ++ ++ sub_info_len = min_t(unsigned int, m_info.sub_info_len, ++ sizeof(struct mptcp_sub_info)); ++ m_info.sub_info_len = sub_info_len; ++ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct mptcp_sub_info m_sub_info; ++ unsigned int tmp_len; ++ ++ mptcp_get_sub_info(mptcp_to_sock(mptcp), &m_sub_info); ++ ++ tmp_len = min_t(unsigned int, len, sub_info_len); ++ len -= tmp_len; ++ ++ if (copy_to_user(ptr, &m_sub_info, tmp_len)) ++ return -EFAULT; ++ ++ ptr += tmp_len; ++ total_sub_info_len += tmp_len; ++ ++ if (len == 0) ++ break; ++ } ++ ++ m_info.total_sub_info_len = total_sub_info_len; ++ } ++ ++ if (copy_to_user(optval, &m_info, optlen)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++void mptcp_clear_sk(struct sock *sk, int size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* we do not want to clear tk_table field, because of RCU lookups */ ++ sk_prot_clear_nulls(sk, offsetof(struct tcp_sock, tk_table.next)); ++ ++ size -= offsetof(struct tcp_sock, tk_table.pprev); ++ memset((char *)&tp->tk_table.pprev, 0, size); ++} ++ ++static const struct snmp_mib mptcp_snmp_list[] = { ++ SNMP_MIB_ITEM("MPCapableSYNRX", MPTCP_MIB_MPCAPABLEPASSIVE), ++ SNMP_MIB_ITEM("MPCapableSYNTX", MPTCP_MIB_MPCAPABLEACTIVE), ++ SNMP_MIB_ITEM("MPCapableSYNACKRX", MPTCP_MIB_MPCAPABLEACTIVEACK), ++ SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK), ++ SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK), ++ SNMP_MIB_ITEM("MPCapableRetransFallback", MPTCP_MIB_MPCAPABLERETRANSFALLBACK), ++ SNMP_MIB_ITEM("MPTCPCsumEnabled", MPTCP_MIB_CSUMENABLED), ++ SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), ++ SNMP_MIB_ITEM("MPFailRX", MPTCP_MIB_MPFAILRX), ++ SNMP_MIB_ITEM("MPCsumFail", MPTCP_MIB_CSUMFAIL), ++ SNMP_MIB_ITEM("MPFastcloseRX", MPTCP_MIB_FASTCLOSERX), ++ SNMP_MIB_ITEM("MPFastcloseTX", MPTCP_MIB_FASTCLOSETX), ++ SNMP_MIB_ITEM("MPFallbackAckSub", MPTCP_MIB_FBACKSUB), ++ SNMP_MIB_ITEM("MPFallbackAckInit", MPTCP_MIB_FBACKINIT), ++ SNMP_MIB_ITEM("MPFallbackDataSub", MPTCP_MIB_FBDATASUB), ++ SNMP_MIB_ITEM("MPFallbackDataInit", MPTCP_MIB_FBDATAINIT), ++ SNMP_MIB_ITEM("MPRemoveAddrSubDelete", MPTCP_MIB_REMADDRSUB), ++ SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), ++ SNMP_MIB_ITEM("MPJoinAlreadyFallenback", MPTCP_MIB_JOINFALLBACK), ++ SNMP_MIB_ITEM("MPJoinSynTx", MPTCP_MIB_JOINSYNTX), ++ SNMP_MIB_ITEM("MPJoinSynRx", MPTCP_MIB_JOINSYNRX), ++ SNMP_MIB_ITEM("MPJoinSynAckRx", MPTCP_MIB_JOINSYNACKRX), ++ SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX), ++ SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC), ++ SNMP_MIB_ITEM("MPJoinAckMissing", MPTCP_MIB_JOINACKFAIL), ++ SNMP_MIB_ITEM("MPJoinAckRTO", MPTCP_MIB_JOINACKRTO), ++ SNMP_MIB_ITEM("MPJoinAckRexmit", MPTCP_MIB_JOINACKRXMIT), ++ SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), ++ SNMP_MIB_ITEM("DSSNotMatching", MPTCP_MIB_DSSNOMATCH), ++ SNMP_MIB_ITEM("InfiniteMapRx", MPTCP_MIB_INFINITEMAPRX), ++ SNMP_MIB_ITEM("DSSNoMatchTCP", MPTCP_MIB_DSSTCPMISMATCH), ++ SNMP_MIB_ITEM("DSSTrimHead", MPTCP_MIB_DSSTRIMHEAD), ++ SNMP_MIB_ITEM("DSSSplitTail", MPTCP_MIB_DSSSPLITTAIL), ++ SNMP_MIB_ITEM("DSSPurgeOldSubSegs", MPTCP_MIB_PURGEOLD), ++ SNMP_MIB_ITEM("AddAddrRx", MPTCP_MIB_ADDADDRRX), ++ SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), ++ SNMP_MIB_ITEM("RemAddrRx", MPTCP_MIB_REMADDRRX), ++ SNMP_MIB_ITEM("RemAddrTx", MPTCP_MIB_REMADDRTX), ++ SNMP_MIB_ITEM("MPJoinAlternatePort", MPTCP_MIB_JOINALTERNATEPORT), ++ SNMP_MIB_ITEM("MPCurrEstab", MPTCP_MIB_CURRESTAB), ++ SNMP_MIB_SENTINEL ++}; ++ ++struct workqueue_struct *mptcp_wq; ++EXPORT_SYMBOL(mptcp_wq); ++ ++/* Output /proc/net/mptcp */ ++static int mptcp_pm_seq_show(struct seq_file *seq, void *v) ++{ ++ struct tcp_sock *meta_tp; ++ const struct net *net = seq->private; ++ unsigned int i, n = 0; ++ ++ seq_printf(seq, " sl loc_tok rem_tok v6 local_address remote_address st ns tx_queue rx_queue inode"); ++ seq_putc(seq, '\n'); ++ ++ for (i = 0; i <= mptcp_tk_htable.mask; i++) { ++ struct hlist_nulls_node *node; ++ rcu_read_lock(); ++ local_bh_disable(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &mptcp_tk_htable.hashtable[i], ++ tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp; ++ struct inet_sock *isk = inet_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ if (!mptcp(meta_tp) || !net_eq(net, sock_net(meta_sk))) ++ continue; ++ ++ if (!mpcb) ++ continue; ++ ++ if (capable(CAP_NET_ADMIN)) { ++ seq_printf(seq, "%4d: %04X %04X ", n++, ++ mpcb->mptcp_loc_token, ++ mpcb->mptcp_rem_token); ++ } else { ++ seq_printf(seq, "%4d: %04X %04X ", n++, -1, -1); ++ } ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ seq_printf(seq, " 0 %08X:%04X %08X:%04X ", ++ isk->inet_rcv_saddr, ++ ntohs(isk->inet_sport), ++ isk->inet_daddr, ++ ntohs(isk->inet_dport)); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else if (meta_sk->sk_family == AF_INET6) { ++ struct in6_addr *src = &meta_sk->sk_v6_rcv_saddr; ++ struct in6_addr *dst = &meta_sk->sk_v6_daddr; ++ seq_printf(seq, " 1 %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X", ++ src->s6_addr32[0], src->s6_addr32[1], ++ src->s6_addr32[2], src->s6_addr32[3], ++ ntohs(isk->inet_sport), ++ dst->s6_addr32[0], dst->s6_addr32[1], ++ dst->s6_addr32[2], dst->s6_addr32[3], ++ ntohs(isk->inet_dport)); ++#endif ++ } ++ ++ seq_printf(seq, " %02X %02X %08X:%08X %lu", ++ meta_sk->sk_state, mptcp_subflow_count(mpcb), ++ meta_tp->write_seq - meta_tp->snd_una, ++ max_t(int, meta_tp->rcv_nxt - ++ meta_tp->copied_seq, 0), ++ sock_i_ino(meta_sk)); ++ seq_putc(seq, '\n'); ++ } ++ ++ local_bh_enable(); ++ rcu_read_unlock(); ++ } ++ ++ return 0; ++} ++ ++static int mptcp_snmp_seq_show(struct seq_file *seq, void *v) ++{ ++ struct net *net = seq->private; ++ int i; ++ ++ for (i = 0; mptcp_snmp_list[i].name != NULL; i++) ++ seq_printf(seq, "%-32s\t%ld\n", mptcp_snmp_list[i].name, ++ snmp_fold_field(net->mptcp.mptcp_statistics, ++ mptcp_snmp_list[i].entry)); ++ ++ return 0; ++} ++ ++static int mptcp_pm_init_net(struct net *net) ++{ ++ net->mptcp.mptcp_statistics = alloc_percpu(struct mptcp_mib); ++ if (!net->mptcp.mptcp_statistics) ++ goto out_mptcp_mibs; ++ ++#ifdef CONFIG_PROC_FS ++ net->mptcp.proc_net_mptcp = proc_net_mkdir(net, "mptcp_net", net->proc_net); ++ if (!net->mptcp.proc_net_mptcp) ++ goto out_proc_net_mptcp; ++ if (!proc_create_net_single("mptcp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ mptcp_pm_seq_show, NULL)) ++ goto out_mptcp_net_mptcp; ++ if (!proc_create_net_single("snmp", S_IRUGO, net->mptcp.proc_net_mptcp, ++ mptcp_snmp_seq_show, NULL)) ++ goto out_mptcp_net_snmp; ++#endif ++ ++ return 0; ++ ++#ifdef CONFIG_PROC_FS ++out_mptcp_net_snmp: ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++out_mptcp_net_mptcp: ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ net->mptcp.proc_net_mptcp = NULL; ++out_proc_net_mptcp: ++ free_percpu(net->mptcp.mptcp_statistics); ++#endif ++out_mptcp_mibs: ++ return -ENOMEM; ++} ++ ++static void mptcp_pm_exit_net(struct net *net) ++{ ++ remove_proc_entry("snmp", net->mptcp.proc_net_mptcp); ++ remove_proc_entry("mptcp", net->mptcp.proc_net_mptcp); ++ remove_proc_subtree("mptcp_net", net->proc_net); ++ free_percpu(net->mptcp.mptcp_statistics); ++} ++ ++static struct pernet_operations mptcp_pm_proc_ops = { ++ .init = mptcp_pm_init_net, ++ .exit = mptcp_pm_exit_net, ++}; ++ ++static unsigned long mptcp_htable_entries __initdata; ++ ++static int __init set_mptcp_htable_entries(char *str) ++{ ++ ssize_t ret; ++ ++ if (!str) ++ return 0; ++ ++ ret = kstrtoul(str, 0, &mptcp_htable_entries); ++ if (ret) ++ return 0; ++ ++ return 1; ++} ++__setup("mptcp_htable_entries=", set_mptcp_htable_entries); ++ ++/* General initialization of mptcp */ ++void __init mptcp_init(void) ++{ ++ unsigned int i; ++ struct ctl_table_header *mptcp_sysctl; ++ ++ mptcp_sock_cache = kmem_cache_create("mptcp_sock", ++ sizeof(struct mptcp_tcp_sock), ++ 0, SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_sock_cache) ++ goto mptcp_sock_cache_failed; ++ ++ mptcp_cb_cache = kmem_cache_create("mptcp_cb", sizeof(struct mptcp_cb), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_cb_cache) ++ goto mptcp_cb_cache_failed; ++ ++ mptcp_tw_cache = kmem_cache_create("mptcp_tw", sizeof(struct mptcp_tw), ++ 0, SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ if (!mptcp_tw_cache) ++ goto mptcp_tw_cache_failed; ++ ++ get_random_bytes(&mptcp_secret, sizeof(mptcp_secret)); ++ ++ mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8); ++ if (!mptcp_wq) ++ goto alloc_workqueue_failed; ++ ++ mptcp_tk_htable.hashtable = ++ alloc_large_system_hash("MPTCP tokens", ++ sizeof(mptcp_tk_htable.hashtable[0]), ++ mptcp_htable_entries, ++ 18, /* one slot per 256KB of memory */ ++ 0, ++ NULL, ++ &mptcp_tk_htable.mask, ++ 1024, ++ mptcp_htable_entries ? 0 : 1024 * 1024); ++ ++ for (i = 0; i <= mptcp_tk_htable.mask; i++) ++ INIT_HLIST_NULLS_HEAD(&mptcp_tk_htable.hashtable[i], i); ++ ++ mptcp_reqsk_tk_htb.hashtable = ++ alloc_large_system_hash("MPTCP request tokens", ++ sizeof(mptcp_reqsk_tk_htb.hashtable[0]), ++ mptcp_htable_entries, ++ 18, /* one slot per 256KB of memory */ ++ 0, ++ NULL, ++ &mptcp_reqsk_tk_htb.mask, ++ 1024, ++ mptcp_htable_entries ? 0 : 1024 * 1024); ++ ++ for (i = 0; i <= mptcp_reqsk_tk_htb.mask; i++) ++ INIT_HLIST_NULLS_HEAD(&mptcp_reqsk_tk_htb.hashtable[i], i); ++ ++ ++ spin_lock_init(&mptcp_tk_hashlock); ++ ++ if (register_pernet_subsys(&mptcp_pm_proc_ops)) ++ goto pernet_failed; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_pm_v6_init()) ++ goto mptcp_pm_v6_failed; ++#endif ++ if (mptcp_pm_v4_init()) ++ goto mptcp_pm_v4_failed; ++ ++ mptcp_sysctl = register_net_sysctl(&init_net, "net/mptcp", mptcp_table); ++ if (!mptcp_sysctl) ++ goto register_sysctl_failed; ++ ++ if (mptcp_register_path_manager(&mptcp_pm_default)) ++ goto register_pm_failed; ++ ++ if (mptcp_register_scheduler(&mptcp_sched_default)) ++ goto register_sched_failed; ++ ++ pr_info("MPTCP: Unstable branch"); ++ ++ mptcp_init_failed = false; ++ ++ return; ++ ++register_sched_failed: ++ mptcp_unregister_path_manager(&mptcp_pm_default); ++register_pm_failed: ++ unregister_net_sysctl_table(mptcp_sysctl); ++register_sysctl_failed: ++ mptcp_pm_v4_undo(); ++mptcp_pm_v4_failed: ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_pm_v6_undo(); ++mptcp_pm_v6_failed: ++#endif ++ unregister_pernet_subsys(&mptcp_pm_proc_ops); ++pernet_failed: ++ destroy_workqueue(mptcp_wq); ++alloc_workqueue_failed: ++ kmem_cache_destroy(mptcp_tw_cache); ++mptcp_tw_cache_failed: ++ kmem_cache_destroy(mptcp_cb_cache); ++mptcp_cb_cache_failed: ++ kmem_cache_destroy(mptcp_sock_cache); ++mptcp_sock_cache_failed: ++ mptcp_init_failed = true; ++} +diff -aurN linux-5.4.64/net/mptcp/mptcp_ecf.c linux-5.4.64.mptcp/net/mptcp/mptcp_ecf.c +--- linux-5.4.64/net/mptcp/mptcp_ecf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_ecf.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,195 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP ECF Scheduler ++ * ++ * Algorithm Design: ++ * Yeon-sup Lim ++ * Don Towsley ++ * Erich M. Nahum ++ * Richard J. Gibbens ++ * ++ * Initial Implementation: ++ * Yeon-sup Lim ++ * ++ * Additional Authors: ++ * Daniel Weber ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++static unsigned int mptcp_ecf_r_beta __read_mostly = 4; /* beta = 1/r_beta = 0.25 */ ++module_param(mptcp_ecf_r_beta, int, 0644); ++MODULE_PARM_DESC(mptcp_ecf_r_beta, "beta for ECF"); ++ ++struct ecfsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++struct ecfsched_cb { ++ u32 switching_margin; /* this is "waiting" in algorithm description */ ++}; ++ ++static struct ecfsched_priv *ecfsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct ecfsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++static struct ecfsched_cb *ecfsched_get_cb(const struct tcp_sock *tp) ++{ ++ return (struct ecfsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++/* This is the ECF scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy or the currently best ++ * subflow is estimated to be slower than waiting for minsk, NULL is returned. ++ */ ++static struct sock *ecf_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *bestsk, *minsk = NULL; ++ struct tcp_sock *besttp; ++ struct mptcp_tcp_sock *mptcp; ++ struct ecfsched_cb *ecf_cb = ecfsched_get_cb(tcp_sk(meta_sk)); ++ u32 min_srtt = U32_MAX; ++ u32 sub_sndbuf = 0; ++ u32 sub_packets_out = 0; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(bestsk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(bestsk, skb, zero_wnd_test)) ++ return bestsk; ++ } ++ } ++ ++ /* First, find the overall best (fastest) subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ bestsk = mptcp_to_sock(mptcp); ++ besttp = tcp_sk(bestsk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(bestsk)) ++ continue; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (besttp->mptcp->pre_established) ++ continue; ++ ++ sub_sndbuf += bestsk->sk_wmem_queued; ++ sub_packets_out += besttp->packets_out; ++ ++ /* record minimal rtt */ ++ if (besttp->srtt_us < min_srtt) { ++ min_srtt = besttp->srtt_us; ++ minsk = bestsk; ++ } ++ } ++ ++ /* find the current best subflow according to the default scheduler */ ++ bestsk = get_available_subflow(meta_sk, skb, zero_wnd_test); ++ ++ /* if we decided to use a slower flow, we have the option of not using it at all */ ++ if (bestsk && minsk && bestsk != minsk) { ++ u32 mss = tcp_current_mss(bestsk); /* assuming equal MSS */ ++ u32 sndbuf_meta = meta_sk->sk_wmem_queued; ++ u32 sndbuf_minus = sub_sndbuf; ++ u32 sndbuf = 0; ++ ++ u32 cwnd_f = tcp_sk(minsk)->snd_cwnd; ++ u32 srtt_f = tcp_sk(minsk)->srtt_us >> 3; ++ u32 rttvar_f = tcp_sk(minsk)->rttvar_us >> 1; ++ ++ u32 cwnd_s = tcp_sk(bestsk)->snd_cwnd; ++ u32 srtt_s = tcp_sk(bestsk)->srtt_us >> 3; ++ u32 rttvar_s = tcp_sk(bestsk)->rttvar_us >> 1; ++ ++ u32 delta = max(rttvar_f, rttvar_s); ++ ++ u32 x_f; ++ u64 lhs, rhs; /* to avoid overflow, using u64 */ ++ ++ if (tcp_sk(meta_sk)->packets_out > sub_packets_out) ++ sndbuf_minus += (tcp_sk(meta_sk)->packets_out - sub_packets_out) * mss; ++ ++ if (sndbuf_meta > sndbuf_minus) ++ sndbuf = sndbuf_meta - sndbuf_minus; ++ ++ /* we have something to send. ++ * at least one time tx over fastest subflow is required ++ */ ++ x_f = sndbuf > cwnd_f * mss ? sndbuf : cwnd_f * mss; ++ lhs = srtt_f * (x_f + cwnd_f * mss); ++ rhs = cwnd_f * mss * (srtt_s + delta); ++ ++ if (mptcp_ecf_r_beta * lhs < mptcp_ecf_r_beta * rhs + ecf_cb->switching_margin * rhs) { ++ u32 x_s = sndbuf > cwnd_s * mss ? sndbuf : cwnd_s * mss; ++ u64 lhs_s = srtt_s * x_s; ++ u64 rhs_s = cwnd_s * mss * (2 * srtt_f + delta); ++ ++ if (lhs_s >= rhs_s) { ++ /* too slower than fastest */ ++ ecf_cb->switching_margin = 1; ++ return NULL; ++ } ++ } else { ++ /* use slower one */ ++ ecf_cb->switching_margin = 0; ++ } ++ } ++ ++ return bestsk; ++} ++ ++static void ecfsched_init(struct sock *sk) ++{ ++ struct ecfsched_priv *ecf_p = ecfsched_get_priv(tcp_sk(sk)); ++ struct ecfsched_cb *ecf_cb = ecfsched_get_cb(tcp_sk(mptcp_meta_sk(sk))); ++ ++ ecf_p->last_rbuf_opti = tcp_jiffies32; ++ ecf_cb->switching_margin = 0; ++} ++ ++struct mptcp_sched_ops mptcp_sched_ecf = { ++ .get_subflow = ecf_get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = ecfsched_init, ++ .name = "ecf", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init ecf_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ecfsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct ecfsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_ecf)) ++ return -1; ++ ++ return 0; ++} ++ ++static void ecf_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_ecf); ++} ++ ++module_init(ecf_register); ++module_exit(ecf_unregister); ++ ++MODULE_AUTHOR("Yeon-sup Lim, Daniel Weber"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ECF (Earliest Completion First) scheduler for MPTCP, based on default minimum RTT scheduler"); ++MODULE_VERSION("0.95"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_fullmesh.c linux-5.4.64.mptcp/net/mptcp/mptcp_fullmesh.c +--- linux-5.4.64/net/mptcp/mptcp_fullmesh.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_fullmesh.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,1938 @@ ++#include ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#endif ++ ++enum { ++ MPTCP_EVENT_ADD = 1, ++ MPTCP_EVENT_DEL, ++ MPTCP_EVENT_MOD, ++}; ++ ++#define MPTCP_SUBFLOW_RETRY_DELAY 1000 ++ ++/* Max number of local or remote addresses we can store. ++ * When changing, see the bitfield below in fullmesh_rem4/6. ++ */ ++#define MPTCP_MAX_ADDR 8 ++ ++struct fullmesh_rem4 { ++ u8 rem4_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in_addr addr; ++}; ++ ++struct fullmesh_rem6 { ++ u8 rem6_id; ++ u8 bitfield; ++ u8 retry_bitfield; ++ __be16 port; ++ struct in6_addr addr; ++}; ++ ++struct mptcp_loc_addr { ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ u8 loc4_bits; ++ u8 next_v4_index; ++ ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++ u8 loc6_bits; ++ u8 next_v6_index; ++ struct rcu_head rcu; ++}; ++ ++struct mptcp_addr_event { ++ struct list_head list; ++ unsigned short family; ++ u8 code:7, ++ low_prio:1; ++ int if_idx; ++ union inet_addr addr; ++}; ++ ++struct fullmesh_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ /* Delayed worker, when the routing-tables are not yet ready. */ ++ struct delayed_work subflow_retry_work; ++ ++ /* Remote addresses */ ++ struct fullmesh_rem4 remaddr4[MPTCP_MAX_ADDR]; ++ struct fullmesh_rem6 remaddr6[MPTCP_MAX_ADDR]; ++ ++ struct mptcp_cb *mpcb; ++ ++ u16 remove_addrs; /* Addresses to remove */ ++ u8 announced_addrs_v4; /* IPv4 Addresses we did announce */ ++ u8 announced_addrs_v6; /* IPv6 Addresses we did announce */ ++ ++ u8 add_addr; /* Are we sending an add_addr? */ ++ ++ u8 rem4_bits; ++ u8 rem6_bits; ++ ++ /* Have we established the additional subflows for primary pair? */ ++ u8 first_pair:1; ++}; ++ ++struct mptcp_fm_ns { ++ struct mptcp_loc_addr __rcu *local; ++ spinlock_t local_lock; /* Protecting the above pointer */ ++ struct list_head events; ++ struct delayed_work address_worker; ++ ++ struct net *net; ++}; ++ ++static int num_subflows __read_mostly = 1; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per pair of IP addresses of MPTCP connection"); ++ ++static int create_on_err __read_mostly; ++module_param(create_on_err, int, 0644); ++MODULE_PARM_DESC(create_on_err, "recreate the subflow upon a timeout"); ++ ++static struct mptcp_pm_ops full_mesh __read_mostly; ++ ++static void full_mesh_create_subflows(struct sock *meta_sk); ++ ++static struct mptcp_fm_ns *fm_get_ns(const struct net *net) ++{ ++ return (struct mptcp_fm_ns *)net->mptcp.path_managers[MPTCP_PM_FULLMESH]; ++} ++ ++static struct fullmesh_priv *fullmesh_get_priv(const struct mptcp_cb *mpcb) ++{ ++ return (struct fullmesh_priv *)&mpcb->mptcp_pm[0]; ++} ++ ++/* Find the first free index in the bitfield */ ++static int __mptcp_find_free_index(u8 bitfield, u8 base) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ goto exit; ++ ++ i = ffs(~(bitfield >> base)) - 1; ++ if (i < 0) ++ goto exit; ++ ++ /* No free bits when starting at base, try from 0 on */ ++ if (i + base >= sizeof(bitfield) * 8) ++ return __mptcp_find_free_index(bitfield, 0); ++ ++ return i + base; ++exit: ++ return -1; ++} ++ ++static int mptcp_find_free_index(u8 bitfield) ++{ ++ return __mptcp_find_free_index(bitfield, 0); ++} ++ ++static void mptcp_addv4_raddr(struct mptcp_cb *mpcb, ++ const struct in_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem4 *rem4; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem4->rem4_id == id && ++ rem4->addr.s_addr == addr->s_addr && rem4->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem4->rem4_id == id && rem4->addr.s_addr != addr->s_addr) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr:%pI4 to addr %pI4 with id:%d\n", ++ __func__, &rem4->addr.s_addr, ++ &addr->s_addr, id); ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem4_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI4\n", ++ __func__, MPTCP_MAX_ADDR, &addr->s_addr); ++ return; ++ } ++ ++ rem4 = &fmp->remaddr4[i]; ++ ++ /* Address is not known yet, store it */ ++ rem4->addr.s_addr = addr->s_addr; ++ rem4->port = port; ++ rem4->bitfield = 0; ++ rem4->retry_bitfield = 0; ++ rem4->rem4_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem4_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_addv6_raddr(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, ++ __be16 port, u8 id) ++{ ++ int i; ++ struct fullmesh_rem6 *rem6; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is already in the list --- continue */ ++ if (rem6->rem6_id == id && ++ ipv6_addr_equal(&rem6->addr, addr) && rem6->port == port) ++ return; ++ ++ /* This may be the case, when the peer is behind a NAT. He is ++ * trying to JOIN, thus sending the JOIN with a certain ID. ++ * However the src_addr of the IP-packet has been changed. We ++ * update the addr in the list, because this is the address as ++ * OUR BOX sees it. ++ */ ++ if (rem6->rem6_id == id) { ++ /* update the address */ ++ mptcp_debug("%s: updating old addr: %pI6 to addr %pI6 with id:%d\n", ++ __func__, &rem6->addr, addr, id); ++ rem6->addr = *addr; ++ rem6->port = port; ++ mpcb->list_rcvd = 1; ++ return; ++ } ++ } ++ ++ i = mptcp_find_free_index(fmp->rem6_bits); ++ /* Do we have already the maximum number of local/remote addresses? */ ++ if (i < 0) { ++ mptcp_debug("%s: At max num of remote addresses: %d --- not adding address: %pI6\n", ++ __func__, MPTCP_MAX_ADDR, addr); ++ return; ++ } ++ ++ rem6 = &fmp->remaddr6[i]; ++ ++ /* Address is not known yet, store it */ ++ rem6->addr = *addr; ++ rem6->port = port; ++ rem6->bitfield = 0; ++ rem6->retry_bitfield = 0; ++ rem6->rem6_id = id; ++ mpcb->list_rcvd = 1; ++ fmp->rem6_bits |= (1 << i); ++ ++ return; ++} ++ ++static void mptcp_v4_rem_raddress(struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].rem4_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem4_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++static void mptcp_v6_rem_raddress(const struct mptcp_cb *mpcb, u8 id) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (fmp->remaddr6[i].rem6_id == id) { ++ /* remove address from bitfield */ ++ fmp->rem6_bits &= ~(1 << i); ++ ++ break; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v4_set_init_addr_bit(const struct mptcp_cb *mpcb, ++ const struct in_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ if (fmp->remaddr4[i].addr.s_addr == addr->s_addr) { ++ fmp->remaddr4[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++/* Sets the bitfield of the remote-address field */ ++static void mptcp_v6_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const struct in6_addr *addr, u8 index) ++{ ++ int i; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ if (ipv6_addr_equal(&fmp->remaddr6[i].addr, addr)) { ++ fmp->remaddr6[i].bitfield |= (1 << index); ++ return; ++ } ++ } ++} ++ ++static void mptcp_set_init_addr_bit(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_v4_set_init_addr_bit(mpcb, &addr->in, id); ++ else ++ mptcp_v6_set_init_addr_bit(mpcb, &addr->in6, id); ++} ++ ++static void mptcp_v4_subflows(struct sock *meta_sk, ++ const struct mptcp_loc4 *loc, ++ struct mptcp_rem4 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init4_subsockets(meta_sk, loc, rem); ++} ++ ++#if IS_ENABLED(CONFIG_IPV6) ++static void mptcp_v6_subflows(struct sock *meta_sk, ++ const struct mptcp_loc6 *loc, ++ struct mptcp_rem6 *rem) ++{ ++ int i; ++ ++ for (i = 1; i < num_subflows; i++) ++ mptcp_init6_subsockets(meta_sk, loc, rem); ++} ++#endif ++ ++static void retry_subflow_worker(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct fullmesh_priv *fmp = container_of(delayed_work, ++ struct fullmesh_priv, ++ subflow_retry_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem = &fmp->remaddr4[i]; ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], &rem4); ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem = &fmp->remaddr6[i]; ++ ++ /* Do we need to retry establishing a subflow ? */ ++ if (rem->retry_bitfield) { ++ int i = mptcp_find_free_index(~rem->retry_bitfield); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ rem->retry_bitfield &= ~(1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], &rem6); ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ struct fullmesh_priv *fmp = container_of(work, struct fullmesh_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = fmp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int iter = 0, retry = 0; ++ int i; ++ ++ /* We need a local (stable) copy of the address-list. Really, it is not ++ * such a big deal, if the address-list is not 100% up-to-date. ++ */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), GFP_ATOMIC); ++ rcu_read_unlock_bh(); ++ ++ if (!mptcp_local) ++ return; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD) || !mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ /* Create the additional subflows for the first pair */ ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_v4_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ iter++; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr4[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc4_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem4 rem4; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem4.addr = rem->addr; ++ rem4.port = rem->port; ++ rem4.rem4_id = rem->rem4_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init4_subsockets(meta_sk, &mptcp_local->locaddr4[i], ++ &rem4) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v4_subflows(meta_sk, ++ &mptcp_local->locaddr4[i], ++ &rem4); ++ goto next_subflow; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (fmp->first_pair == 0 && mpcb->master_sk) { ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_v6_subflows(meta_sk, &loc, &rem); ++ ++ fmp->first_pair = 1; ++ } ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem; ++ u8 remaining_bits; ++ ++ rem = &fmp->remaddr6[i]; ++ remaining_bits = ~(rem->bitfield) & mptcp_local->loc6_bits; ++ ++ /* Are there still combinations to handle? */ ++ if (remaining_bits) { ++ int i = mptcp_find_free_index(~remaining_bits); ++ struct mptcp_rem6 rem6; ++ ++ rem->bitfield |= (1 << i); ++ ++ rem6.addr = rem->addr; ++ rem6.port = rem->port; ++ rem6.rem6_id = rem->rem6_id; ++ ++ /* If a route is not yet available then retry once */ ++ if (mptcp_init6_subsockets(meta_sk, &mptcp_local->locaddr6[i], ++ &rem6) == -ENETUNREACH) ++ retry = rem->retry_bitfield |= (1 << i); ++ else ++ mptcp_v6_subflows(meta_sk, ++ &mptcp_local->locaddr6[i], ++ &rem6); ++ goto next_subflow; ++ } ++ } ++#endif ++ ++ if (retry && !delayed_work_pending(&fmp->subflow_retry_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_delayed_work(mptcp_wq, &fmp->subflow_retry_work, ++ msecs_to_jiffies(MPTCP_SUBFLOW_RETRY_DELAY)); ++ } ++ ++exit: ++ kfree(mptcp_local); ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void announce_remove_addr(u8 addr_id, struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct sock *sk = mptcp_select_ack_sock(meta_sk); ++ ++ fmp->remove_addrs |= (1 << addr_id); ++ mpcb->addr_signal = 1; ++ ++ if (sk) ++ tcp_send_ack(sk); ++} ++ ++static void update_addr_bitfields(struct sock *meta_sk, ++ const struct mptcp_loc_addr *mptcp_local) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ int i; ++ ++ /* The bits in announced_addrs_* always match with loc*_bits. So, a ++ * simple & operation unsets the correct bits, because these go from ++ * announced to non-announced ++ */ ++ fmp->announced_addrs_v4 &= mptcp_local->loc4_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ fmp->remaddr4[i].bitfield &= mptcp_local->loc4_bits; ++ fmp->remaddr4[i].retry_bitfield &= mptcp_local->loc4_bits; ++ } ++ ++ fmp->announced_addrs_v6 &= mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ fmp->remaddr6[i].bitfield &= mptcp_local->loc6_bits; ++ fmp->remaddr6[i].retry_bitfield &= mptcp_local->loc6_bits; ++ } ++} ++ ++static int mptcp_find_address(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, const union inet_addr *addr, ++ int if_idx) ++{ ++ int i; ++ u8 loc_bits; ++ bool found = false; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ mptcp_local->locaddr4[i].addr.s_addr == addr->in.s_addr) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&mptcp_local->locaddr6[i].addr, ++ &addr->in6)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static int mptcp_find_address_transp(const struct mptcp_loc_addr *mptcp_local, ++ sa_family_t family, int if_idx) ++{ ++ bool found = false; ++ u8 loc_bits; ++ int i; ++ ++ if (family == AF_INET) ++ loc_bits = mptcp_local->loc4_bits; ++ else ++ loc_bits = mptcp_local->loc6_bits; ++ ++ mptcp_for_each_bit_set(loc_bits, i) { ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -1; ++ ++ return i; ++} ++ ++static void mptcp_address_worker(struct work_struct *work) ++{ ++ const struct delayed_work *delayed_work = container_of(work, ++ struct delayed_work, ++ work); ++ struct mptcp_fm_ns *fm_ns = container_of(delayed_work, ++ struct mptcp_fm_ns, ++ address_worker); ++ struct net *net = fm_ns->net; ++ struct mptcp_addr_event *event = NULL; ++ struct mptcp_loc_addr *mptcp_local, *old; ++ int i, id = -1; /* id is used in the socket-code on a delete-event */ ++ bool success; /* Used to indicate if we succeeded handling the event */ ++ ++next_event: ++ success = false; ++ kfree(event); ++ ++ /* First, let's dequeue an event from our event-list */ ++ rcu_read_lock_bh(); ++ spin_lock(&fm_ns->local_lock); ++ ++ event = list_first_entry_or_null(&fm_ns->events, ++ struct mptcp_addr_event, list); ++ if (!event) { ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ return; ++ } ++ ++ list_del(&event->list); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ id = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ ++ /* Not in the list - so we don't care */ ++ if (id < 0) { ++ mptcp_debug("%s could not find id\n", __func__); ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) ++ mptcp_local->loc4_bits &= ~(1 << id); ++ else ++ mptcp_local->loc6_bits &= ~(1 << id); ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } else { ++ int i = mptcp_find_address(mptcp_local, event->family, ++ &event->addr, event->if_idx); ++ int j = i; ++ ++ if (j < 0) { ++ /* Not in the list, so we have to find an empty slot */ ++ if (event->family == AF_INET) ++ i = __mptcp_find_free_index(mptcp_local->loc4_bits, ++ mptcp_local->next_v4_index); ++ if (event->family == AF_INET6) ++ i = __mptcp_find_free_index(mptcp_local->loc6_bits, ++ mptcp_local->next_v6_index); ++ ++ if (i < 0) { ++ mptcp_debug("%s no more space\n", __func__); ++ goto duno; ++ } ++ ++ /* It might have been a MOD-event. */ ++ event->code = MPTCP_EVENT_ADD; ++ } else { ++ /* Let's check if anything changes */ ++ if (event->family == AF_INET && ++ event->low_prio == mptcp_local->locaddr4[i].low_prio) ++ goto duno; ++ ++ if (event->family == AF_INET6 && ++ event->low_prio == mptcp_local->locaddr6[i].low_prio) ++ goto duno; ++ } ++ ++ old = mptcp_local; ++ mptcp_local = kmemdup(mptcp_local, sizeof(*mptcp_local), ++ GFP_ATOMIC); ++ if (!mptcp_local) ++ goto duno; ++ ++ if (event->family == AF_INET) { ++ mptcp_local->locaddr4[i].addr.s_addr = event->addr.in.s_addr; ++ mptcp_local->locaddr4[i].loc4_id = i + 1; ++ mptcp_local->locaddr4[i].low_prio = event->low_prio; ++ mptcp_local->locaddr4[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI4 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in.s_addr, ++ event->if_idx, event->low_prio, i + 1); ++ } else { ++ mptcp_local->locaddr6[i].addr = event->addr.in6; ++ mptcp_local->locaddr6[i].loc6_id = i + MPTCP_MAX_ADDR; ++ mptcp_local->locaddr6[i].low_prio = event->low_prio; ++ mptcp_local->locaddr6[i].if_idx = event->if_idx; ++ ++ mptcp_debug("%s updated IP %pI6 on ifidx %u prio %u id %u\n", ++ __func__, &event->addr.in6, ++ event->if_idx, event->low_prio, i + MPTCP_MAX_ADDR); ++ } ++ ++ if (j < 0) { ++ if (event->family == AF_INET) { ++ mptcp_local->loc4_bits |= (1 << i); ++ mptcp_local->next_v4_index = i + 1; ++ } else { ++ mptcp_local->loc6_bits |= (1 << i); ++ mptcp_local->next_v6_index = i + 1; ++ } ++ } ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ kfree_rcu(old, rcu); ++ } ++ success = true; ++ ++duno: ++ spin_unlock(&fm_ns->local_lock); ++ rcu_read_unlock_bh(); ++ ++ if (!success) ++ goto next_event; ++ ++ /* Now we iterate over the MPTCP-sockets and apply the event. */ ++ for (i = 0; i <= mptcp_tk_htable.mask; i++) { ++ const struct hlist_nulls_node *node; ++ struct tcp_sock *meta_tp; ++ ++ rcu_read_lock_bh(); ++ hlist_nulls_for_each_entry_rcu(meta_tp, node, ++ &mptcp_tk_htable.hashtable[i], ++ tk_table) { ++ struct sock *meta_sk = (struct sock *)meta_tp, *sk; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_cb *mpcb; ++ ++ if (sock_net(meta_sk) != net) ++ continue; ++ ++ if (meta_v4) { ++ /* skip IPv6 events if meta is IPv4 */ ++ if (event->family == AF_INET6) ++ continue; ++ } else if (event->family == AF_INET && meta_sk->sk_ipv6only) { ++ /* skip IPv4 events if IPV6_V6ONLY is set */ ++ continue; ++ } ++ ++ if (unlikely(!refcount_inc_not_zero(&meta_sk->sk_refcnt))) ++ continue; ++ ++ bh_lock_sock(meta_sk); ++ ++ mpcb = meta_tp->mpcb; ++ if (!mpcb) ++ goto next; ++ ++ if (!mptcp(meta_tp) || !is_meta_sk(meta_sk) || ++ mptcp_in_infinite_mapping_weak(mpcb)) ++ goto next; ++ ++ /* May be that the pm has changed in-between */ ++ if (mpcb->pm_ops != &full_mesh) ++ goto next; ++ ++ if (sock_owned_by_user(meta_sk)) { ++ if (!test_and_set_bit(MPTCP_PATH_MANAGER_DEFERRED, ++ &meta_sk->sk_tsq_flags)) ++ sock_hold(meta_sk); ++ ++ goto next; ++ } ++ ++ if (event->code == MPTCP_EVENT_ADD) { ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ ++ full_mesh_create_subflows(meta_sk); ++ } ++ ++ if (event->code == MPTCP_EVENT_DEL) { ++ struct mptcp_tcp_sock *mptcp; ++ struct mptcp_loc_addr *mptcp_local; ++ struct hlist_node *tmp; ++ bool found = false; ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ /* In any case, we need to update our bitfields */ ++ if (id >= 0) ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ /* Look for the socket and remove him */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if ((event->family == AF_INET6 && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk))) || ++ (event->family == AF_INET && ++ (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)))) ++ continue; ++ ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr != event->addr.in.s_addr) ++ continue; ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) ++ continue; ++ ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ /* We announce the removal of this id */ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ found = true; ++ } ++ ++ if (found) ++ goto next; ++ ++ /* The id may have been given by the event, ++ * matching on a local address. And it may not ++ * have matched on one of the above sockets, ++ * because the client never created a subflow. ++ * So, we have to finally remove it here. ++ */ ++ if (id >= 0) { ++ u8 loc_id = id ++ + (event->family == AF_INET ? 1 : MPTCP_MAX_ADDR); ++ announce_remove_addr(loc_id, meta_sk); ++ } ++ } ++ ++ if (event->code == MPTCP_EVENT_MOD) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ if (event->family == AF_INET && ++ (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) && ++ inet_sk(sk)->inet_saddr == event->addr.in.s_addr) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (event->family == AF_INET6 && ++ sk->sk_family == AF_INET6 && ++ !ipv6_addr_equal(&inet6_sk(sk)->saddr, &event->addr.in6)) { ++ if (event->low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = event->low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ } ++ } ++next: ++ bh_unlock_sock(meta_sk); ++ sock_put(meta_sk); ++ } ++ rcu_read_unlock_bh(); ++ } ++ goto next_event; ++} ++ ++static struct mptcp_addr_event *lookup_similar_event(const struct net *net, ++ const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ list_for_each_entry(eventq, &fm_ns->events, list) { ++ if (eventq->family != event->family) ++ continue; ++ if (eventq->if_idx != event->if_idx) ++ continue; ++ if (event->family == AF_INET) { ++ if (eventq->addr.in.s_addr == event->addr.in.s_addr) ++ return eventq; ++ } else { ++ if (ipv6_addr_equal(&eventq->addr.in6, &event->addr.in6)) ++ return eventq; ++ } ++ } ++ return NULL; ++} ++ ++/* We already hold the net-namespace MPTCP-lock */ ++static void add_pm_event(struct net *net, const struct mptcp_addr_event *event) ++{ ++ struct mptcp_addr_event *eventq = lookup_similar_event(net, event); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ ++ if (eventq) { ++ switch (event->code) { ++ case MPTCP_EVENT_DEL: ++ mptcp_debug("%s del old_code %u\n", __func__, eventq->code); ++ list_del(&eventq->list); ++ kfree(eventq); ++ break; ++ case MPTCP_EVENT_ADD: ++ mptcp_debug("%s add old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_ADD; ++ return; ++ case MPTCP_EVENT_MOD: ++ mptcp_debug("%s mod old_code %u\n", __func__, eventq->code); ++ eventq->low_prio = event->low_prio; ++ eventq->code = MPTCP_EVENT_MOD; ++ return; ++ } ++ } ++ ++ /* OK, we have to add the new address to the wait queue */ ++ eventq = kmemdup(event, sizeof(struct mptcp_addr_event), GFP_ATOMIC); ++ if (!eventq) ++ return; ++ ++ list_add_tail(&eventq->list, &fm_ns->events); ++ ++ /* Create work-queue */ ++ if (!delayed_work_pending(&fm_ns->address_worker)) ++ queue_delayed_work(mptcp_wq, &fm_ns->address_worker, ++ msecs_to_jiffies(500)); ++} ++ ++static void addr4_event_handler(const struct in_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->ifa_dev->dev; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->ifa_scope > RT_SCOPE_LINK || ++ ipv4_is_loopback(ifa->ifa_local)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET; ++ mpevent.addr.in.s_addr = ifa->ifa_local; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI4, code %u prio %u idx %u\n", __func__, ++ &ifa->ifa_local, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv4-addr add/rem-events */ ++static int mptcp_pm_inetaddr_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ const struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net *net = dev_net(ifa->ifa_dev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr4_event_handler(ifa, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_inetaddr_notifier = { ++ .notifier_call = mptcp_pm_inetaddr_event, ++}; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr); ++ ++static void addr6_event_handler(const struct inet6_ifaddr *ifa, unsigned long event, ++ struct net *net) ++{ ++ const struct net_device *netdev = ifa->idev->dev; ++ int addr_type = ipv6_addr_type(&ifa->addr); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ struct mptcp_addr_event mpevent; ++ ++ if (ifa->scope > RT_SCOPE_LINK || ++ addr_type == IPV6_ADDR_ANY || ++ (addr_type & IPV6_ADDR_LOOPBACK) || ++ (addr_type & IPV6_ADDR_LINKLOCAL)) ++ return; ++ ++ spin_lock_bh(&fm_ns->local_lock); ++ ++ mpevent.family = AF_INET6; ++ mpevent.addr.in6 = ifa->addr; ++ mpevent.low_prio = (netdev->flags & IFF_MPBACKUP) ? 1 : 0; ++ mpevent.if_idx = netdev->ifindex; ++ ++ if (event == NETDEV_DOWN || !netif_running(netdev) || ++ (netdev->flags & IFF_NOMULTIPATH) || !(netdev->flags & IFF_UP)) ++ mpevent.code = MPTCP_EVENT_DEL; ++ else if (event == NETDEV_UP) ++ mpevent.code = MPTCP_EVENT_ADD; ++ else if (event == NETDEV_CHANGE) ++ mpevent.code = MPTCP_EVENT_MOD; ++ ++ mptcp_debug("%s created event for %pI6, code %u prio %u idx %u\n", __func__, ++ &ifa->addr, mpevent.code, mpevent.low_prio, mpevent.if_idx); ++ add_pm_event(net, &mpevent); ++ ++ spin_unlock_bh(&fm_ns->local_lock); ++ return; ++} ++ ++/* React on IPv6-addr add/rem-events */ ++static int inet6_addr_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ struct inet6_ifaddr *ifa6 = (struct inet6_ifaddr *)ptr; ++ struct net *net = dev_net(ifa6->idev->dev); ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ addr6_event_handler(ifa6, event, net); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block inet6_addr_notifier = { ++ .notifier_call = inet6_addr_event, ++}; ++ ++#endif ++ ++/* React on ifup/down-events */ ++static int netdev_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ const struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct in_device *in_dev; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct inet6_dev *in6_dev; ++#endif ++ ++ if (!(event == NETDEV_UP || event == NETDEV_DOWN || ++ event == NETDEV_CHANGE)) ++ return NOTIFY_DONE; ++ ++ rcu_read_lock(); ++ in_dev = __in_dev_get_rtnl(dev); ++ ++ if (in_dev) { ++ struct in_ifaddr *ifa; ++ ++ in_dev_for_each_ifa_rcu(ifa, in_dev) { ++ mptcp_pm_inetaddr_event(NULL, event, ifa); ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ in6_dev = __in6_dev_get(dev); ++ ++ if (in6_dev) { ++ struct inet6_ifaddr *ifa6; ++ list_for_each_entry(ifa6, &in6_dev->addr_list, if_list) ++ inet6_addr_event(NULL, event, ifa6); ++ } ++#endif ++ ++ rcu_read_unlock(); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mptcp_pm_netdev_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++static void full_mesh_add_raddr(struct mptcp_cb *mpcb, ++ const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ if (family == AF_INET) ++ mptcp_addv4_raddr(mpcb, &addr->in, port, id); ++ else ++ mptcp_addv6_raddr(mpcb, &addr->in6, port, id); ++} ++ ++static void full_mesh_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ struct tcp_sock *master_tp = tcp_sk(mpcb->master_sk); ++ int i, index, if_idx = 0; ++ union inet_addr saddr, daddr; ++ sa_family_t family = AF_INET; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ /* Init local variables necessary for the rest */ ++ if (meta_sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(meta_sk)) { ++ saddr.ip = inet_sk(meta_sk)->inet_saddr; ++ daddr.ip = inet_sk(meta_sk)->inet_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ saddr.in6 = inet6_sk(meta_sk)->saddr; ++ daddr.in6 = meta_sk->sk_v6_daddr; ++ if_idx = mpcb->master_sk->sk_bound_dev_if; ++ family = AF_INET6; ++#endif ++ } ++ ++ if (inet_sk(meta_sk)->transparent) ++ if_idx = inet_sk(meta_sk)->rx_dst_ifindex; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (inet_sk(meta_sk)->transparent) ++ index = mptcp_find_address_transp(mptcp_local, family, if_idx); ++ else ++ index = mptcp_find_address(mptcp_local, family, &saddr, if_idx); ++ if (index < 0) ++ goto fallback; ++ ++ if (family == AF_INET) ++ master_tp->mptcp->low_prio = mptcp_local->locaddr4[index].low_prio; ++ else ++ master_tp->mptcp->low_prio = mptcp_local->locaddr6[index].low_prio; ++ master_tp->mptcp->send_mp_prio = master_tp->mptcp->low_prio; ++ ++ full_mesh_add_raddr(mpcb, &daddr, family, 0, 0); ++ mptcp_set_init_addr_bit(mpcb, &daddr, family, index); ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ INIT_DELAYED_WORK(&fmp->subflow_retry_work, retry_subflow_worker); ++ fmp->mpcb = mpcb; ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* Look for the address among the local addresses */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ __be32 ifa_address = mptcp_local->locaddr4[i].addr.s_addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET && ++ (!if_idx || mptcp_local->locaddr4[i].if_idx == if_idx) && ++ saddr.ip == ifa_address) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto skip_ipv6; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ const struct in6_addr *ifa6 = &mptcp_local->locaddr6[i].addr; ++ ++ /* We do not need to announce the initial subflow's address again */ ++ if (family == AF_INET6 && ++ (!if_idx || mptcp_local->locaddr6[i].if_idx == if_idx) && ++ ipv6_addr_equal(&saddr.in6, ifa6)) ++ continue; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ } ++ ++skip_ipv6: ++#endif ++ ++ rcu_read_unlock_bh(); ++ ++ if (family == AF_INET) ++ fmp->announced_addrs_v4 |= (1 << index); ++ else ++ fmp->announced_addrs_v6 |= (1 << index); ++ ++ for (i = fmp->add_addr; i && fmp->add_addr; i--) ++ tcp_send_ack(mpcb->master_sk); ++ ++ if (master_tp->mptcp->send_mp_prio) ++ tcp_send_ack(mpcb->master_sk); ++ ++ return; ++ ++fallback: ++ rcu_read_unlock_bh(); ++ mptcp_fallback_default(mpcb); ++ return; ++} ++ ++static void full_mesh_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ return; ++ ++ if (!work_pending(&fmp->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &fmp->subflow_work); ++ } ++} ++ ++/* Called upon release_sock, if the socket was owned by the user during ++ * a path-management event. ++ */ ++static void full_mesh_release_sock(struct sock *meta_sk) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ int i; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* First, detect modifications or additions */ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct in_addr ifa = mptcp_local->locaddr4[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET6 && ++ !mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (inet_sk(sk)->inet_saddr != ifa.s_addr) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr4[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr4[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ struct sock *sk; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++skip_ipv4: ++#if IS_ENABLED(CONFIG_IPV6) ++ /* skip IPv6 addresses if meta-socket is IPv4 */ ++ if (meta_v4) ++ goto removal; ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct in6_addr ifa = mptcp_local->locaddr6[i].addr; ++ bool found = false; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(sk)) ++ continue; ++ ++ if (!ipv6_addr_equal(&inet6_sk(sk)->saddr, &ifa)) ++ continue; ++ ++ found = true; ++ ++ if (mptcp_local->locaddr6[i].low_prio != tp->mptcp->low_prio) { ++ tp->mptcp->send_mp_prio = 1; ++ tp->mptcp->low_prio = mptcp_local->locaddr6[i].low_prio; ++ ++ tcp_send_ack(sk); ++ } ++ } ++ ++ if (!found) { ++ struct sock *sk; ++ ++ fmp->add_addr++; ++ mpcb->addr_signal = 1; ++ ++ sk = mptcp_select_ack_sock(meta_sk); ++ if (sk) ++ tcp_send_ack(sk); ++ full_mesh_create_subflows(meta_sk); ++ } ++ } ++ ++removal: ++#endif ++ ++ /* Now, detect address-removals */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ bool shall_remove = true; ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ if (inet_sk(sk)->inet_saddr == mptcp_local->locaddr4[i].addr.s_addr) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } else { ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ if (ipv6_addr_equal(&inet6_sk(sk)->saddr, &mptcp_local->locaddr6[i].addr)) { ++ shall_remove = false; ++ break; ++ } ++ } ++ } ++ ++ if (shall_remove) { ++ /* Reinject, so that pf = 1 and so we ++ * won't select this one as the ++ * ack-sock. ++ */ ++ mptcp_reinject_data(sk, 0); ++ ++ announce_remove_addr(tcp_sk(sk)->mptcp->loc_id, ++ meta_sk); ++ ++ mptcp_sub_force_close(sk); ++ } ++ } ++ ++ /* Just call it optimistically. It actually cannot do any harm */ ++ update_addr_bitfields(meta_sk, mptcp_local); ++ ++ rcu_read_unlock_bh(); ++} ++ ++static int full_mesh_get_local_id(const struct sock *meta_sk, ++ sa_family_t family, union inet_addr *addr, ++ bool *low_prio) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(meta_sk)); ++ int index, id = -1; ++ ++ /* Handle the backup-flows */ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ index = mptcp_find_address(mptcp_local, family, addr, 0); ++ ++ if (index != -1) { ++ if (family == AF_INET) { ++ id = mptcp_local->locaddr4[index].loc4_id; ++ *low_prio = mptcp_local->locaddr4[index].low_prio; ++ } else { ++ id = mptcp_local->locaddr6[index].loc6_id; ++ *low_prio = mptcp_local->locaddr6[index].low_prio; ++ } ++ } ++ ++ ++ rcu_read_unlock_bh(); ++ ++ return id; ++} ++ ++static void full_mesh_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct fullmesh_priv *fmp = fullmesh_get_priv(mpcb); ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ int remove_addr_len; ++ u8 unannouncedv4 = 0, unannouncedv6 = 0; ++ bool meta_v4 = meta_sk->sk_family == AF_INET; ++ ++ mpcb->addr_signal = 0; ++ ++ if (likely(!fmp->add_addr)) ++ goto remove_addr; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ if (!meta_v4 && meta_sk->sk_ipv6only) ++ goto skip_ipv4; ++ ++ /* IPv4 */ ++ unannouncedv4 = (~fmp->announced_addrs_v4) & mptcp_local->loc4_bits; ++ if (unannouncedv4 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv4); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = mptcp_local->locaddr4[ind].loc4_id; ++ opts->add_addr4.addr = mptcp_local->locaddr4[ind].addr; ++ opts->add_addr_v4 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, ++ 4, (u8 *)&opts->add_addr4.addr.s_addr); ++ opts->add_addr4.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v4 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++ ++ goto skip_ipv6; ++ } ++ ++ if (meta_v4) ++ goto skip_ipv6; ++skip_ipv4: ++ /* IPv6 */ ++ unannouncedv6 = (~fmp->announced_addrs_v6) & mptcp_local->loc6_bits; ++ if (unannouncedv6 && ++ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) || ++ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1))) { ++ int ind = mptcp_find_free_index(~unannouncedv6); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = mptcp_local->locaddr6[ind].loc6_id; ++ opts->add_addr6.addr = mptcp_local->locaddr6[ind].addr; ++ opts->add_addr_v6 = 1; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, ++ 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, ++ 16, (u8 *)&opts->add_addr6.addr.s6_addr); ++ opts->add_addr6.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; ++ } ++ ++ if (skb) { ++ fmp->announced_addrs_v6 |= (1 << ind); ++ fmp->add_addr--; ++ } ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++ } ++ ++skip_ipv6: ++ rcu_read_unlock_bh(); ++ ++ if (!unannouncedv4 && !unannouncedv6 && skb) ++ fmp->add_addr--; ++ ++remove_addr: ++ if (likely(!fmp->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(fmp->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = fmp->remove_addrs; ++ *size += remove_addr_len; ++ if (skb) ++ fmp->remove_addrs = 0; ++ ++exit: ++ mpcb->addr_signal = !!(fmp->add_addr || fmp->remove_addrs); ++} ++ ++static void full_mesh_rem_raddr(struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ mptcp_v4_rem_raddress(mpcb, rem_id); ++ mptcp_v6_rem_raddress(mpcb, rem_id); ++} ++ ++static void full_mesh_delete_subflow(struct sock *sk) ++{ ++ struct fullmesh_priv *fmp = fullmesh_get_priv(tcp_sk(sk)->mpcb); ++ struct mptcp_fm_ns *fm_ns = fm_get_ns(sock_net(sk)); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_loc_addr *mptcp_local; ++ int index, i; ++ ++ if (!create_on_err) ++ return; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ return; ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ ++ if (sk->sk_family == AF_INET || mptcp_v6_is_v4_mapped(sk)) { ++ union inet_addr saddr; ++ ++ saddr.ip = inet_sk(sk)->inet_saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem4_bits, i) { ++ struct fullmesh_rem4 *rem4 = &fmp->remaddr4[i]; ++ ++ if (rem4->addr.s_addr != sk->sk_daddr) ++ continue; ++ ++ if (rem4->port && rem4->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem4->bitfield &= ~(1 << index); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ union inet_addr saddr; ++ ++ saddr.in6 = inet6_sk(sk)->saddr; ++ index = mptcp_find_address(mptcp_local, AF_INET6, &saddr, ++ sk->sk_bound_dev_if); ++ if (index < 0) ++ goto out; ++ ++ mptcp_for_each_bit_set(fmp->rem6_bits, i) { ++ struct fullmesh_rem6 *rem6 = &fmp->remaddr6[i]; ++ ++ if (!ipv6_addr_equal(&rem6->addr, &sk->sk_v6_daddr)) ++ continue; ++ ++ if (rem6->port && rem6->port != inet_sk(sk)->inet_dport) ++ continue; ++ ++ rem6->bitfield &= ~(1 << index); ++ } ++#endif ++ } ++ ++out: ++ rcu_read_unlock_bh(); ++ ++ /* re-schedule the creation of failed subflows */ ++ if (tcp_sk(sk)->mptcp->sk_err == ETIMEDOUT || sk->sk_err == ETIMEDOUT) ++ full_mesh_create_subflows(meta_sk); ++} ++ ++/* Output /proc/net/mptcp_fullmesh */ ++static int mptcp_fm_seq_show(struct seq_file *seq, void *v) ++{ ++ const struct net *net = seq->private; ++ struct mptcp_loc_addr *mptcp_local; ++ const struct mptcp_fm_ns *fm_ns = fm_get_ns(net); ++ int i; ++ ++ seq_printf(seq, "Index, Address-ID, Backup, IP-address, if-idx\n"); ++ ++ rcu_read_lock_bh(); ++ mptcp_local = rcu_dereference(fm_ns->local); ++ ++ seq_printf(seq, "IPv4, next v4-index: %u\n", mptcp_local->next_v4_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc4_bits, i) { ++ struct mptcp_loc4 *loc4 = &mptcp_local->locaddr4[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI4, %u\n", i, loc4->loc4_id, ++ loc4->low_prio, &loc4->addr, loc4->if_idx); ++ } ++ ++ seq_printf(seq, "IPv6, next v6-index: %u\n", mptcp_local->next_v6_index); ++ ++ mptcp_for_each_bit_set(mptcp_local->loc6_bits, i) { ++ struct mptcp_loc6 *loc6 = &mptcp_local->locaddr6[i]; ++ ++ seq_printf(seq, "%u, %u, %u, %pI6, %u\n", i, loc6->loc6_id, ++ loc6->low_prio, &loc6->addr, loc6->if_idx); ++ } ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static int mptcp_fm_init_net(struct net *net) ++{ ++ struct mptcp_loc_addr *mptcp_local; ++ struct mptcp_fm_ns *fm_ns; ++ int err = 0; ++ ++ fm_ns = kzalloc(sizeof(*fm_ns), GFP_KERNEL); ++ if (!fm_ns) ++ return -ENOBUFS; ++ ++ mptcp_local = kzalloc(sizeof(*mptcp_local), GFP_KERNEL); ++ if (!mptcp_local) { ++ err = -ENOBUFS; ++ goto err_mptcp_local; ++ } ++ ++ if (!proc_create_net_single("mptcp_fullmesh", S_IRUGO, net->proc_net, ++ mptcp_fm_seq_show, NULL)) { ++ err = -ENOMEM; ++ goto err_seq_fops; ++ } ++ ++ mptcp_local->next_v4_index = 1; ++ ++ rcu_assign_pointer(fm_ns->local, mptcp_local); ++ INIT_DELAYED_WORK(&fm_ns->address_worker, mptcp_address_worker); ++ INIT_LIST_HEAD(&fm_ns->events); ++ spin_lock_init(&fm_ns->local_lock); ++ fm_ns->net = net; ++ net->mptcp.path_managers[MPTCP_PM_FULLMESH] = fm_ns; ++ ++ return 0; ++err_seq_fops: ++ kfree(mptcp_local); ++err_mptcp_local: ++ kfree(fm_ns); ++ return err; ++} ++ ++static void mptcp_fm_exit_net(struct net *net) ++{ ++ struct mptcp_addr_event *eventq, *tmp; ++ struct mptcp_fm_ns *fm_ns; ++ struct mptcp_loc_addr *mptcp_local; ++ ++ fm_ns = fm_get_ns(net); ++ cancel_delayed_work_sync(&fm_ns->address_worker); ++ ++ rcu_read_lock_bh(); ++ ++ mptcp_local = rcu_dereference_bh(fm_ns->local); ++ kfree_rcu(mptcp_local, rcu); ++ ++ spin_lock(&fm_ns->local_lock); ++ list_for_each_entry_safe(eventq, tmp, &fm_ns->events, list) { ++ list_del(&eventq->list); ++ kfree(eventq); ++ } ++ spin_unlock(&fm_ns->local_lock); ++ ++ rcu_read_unlock_bh(); ++ ++ remove_proc_entry("mptcp_fullmesh", net->proc_net); ++ ++ kfree(fm_ns); ++} ++ ++static struct pernet_operations full_mesh_net_ops = { ++ .init = mptcp_fm_init_net, ++ .exit = mptcp_fm_exit_net, ++}; ++ ++static struct mptcp_pm_ops full_mesh __read_mostly = { ++ .new_session = full_mesh_new_session, ++ .release_sock = full_mesh_release_sock, ++ .fully_established = full_mesh_create_subflows, ++ .new_remote_address = full_mesh_create_subflows, ++ .get_local_id = full_mesh_get_local_id, ++ .addr_signal = full_mesh_addr_signal, ++ .add_raddr = full_mesh_add_raddr, ++ .rem_raddr = full_mesh_rem_raddr, ++ .delete_subflow = full_mesh_delete_subflow, ++ .name = "fullmesh", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init full_mesh_register(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct fullmesh_priv) > MPTCP_PM_SIZE); ++ ++ ret = register_pernet_subsys(&full_mesh_net_ops); ++ if (ret) ++ goto out; ++ ++ ret = register_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ if (ret) ++ goto err_reg_inetaddr; ++ ret = register_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ if (ret) ++ goto err_reg_netdev; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ret = register_inet6addr_notifier(&inet6_addr_notifier); ++ if (ret) ++ goto err_reg_inet6addr; ++#endif ++ ++ ret = mptcp_register_path_manager(&full_mesh); ++ if (ret) ++ goto err_reg_pm; ++ ++out: ++ return ret; ++ ++ ++err_reg_pm: ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++err_reg_inet6addr: ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++err_reg_netdev: ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++err_reg_inetaddr: ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ goto out; ++} ++ ++static void full_mesh_unregister(void) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&inet6_addr_notifier); ++#endif ++ unregister_netdevice_notifier(&mptcp_pm_netdev_notifier); ++ unregister_inetaddr_notifier(&mptcp_pm_inetaddr_notifier); ++ unregister_pernet_subsys(&full_mesh_net_ops); ++ mptcp_unregister_path_manager(&full_mesh); ++} ++ ++module_init(full_mesh_register); ++module_exit(full_mesh_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Full-Mesh MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_input.c linux-5.4.64.mptcp/net/mptcp/mptcp_input.c +--- linux-5.4.64/net/mptcp/mptcp_input.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_input.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,2531 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++/* is seq1 < seq2 ? */ ++static inline bool before64(const u64 seq1, const u64 seq2) ++{ ++ return (s64)(seq1 - seq2) < 0; ++} ++ ++/* is seq1 > seq2 ? */ ++#define after64(seq1, seq2) before64(seq2, seq1) ++ ++static inline void mptcp_become_fully_estab(struct sock *sk) ++{ ++ tcp_sk(sk)->mptcp->fully_established = 1; ++ ++ if (is_master_tp(tcp_sk(sk)) && ++ tcp_sk(sk)->mpcb->pm_ops->fully_established) ++ tcp_sk(sk)->mpcb->pm_ops->fully_established(mptcp_meta_sk(sk)); ++} ++ ++/* Similar to tcp_tso_acked without any memory accounting */ ++static inline int mptcp_tso_acked_reinject(const struct sock *meta_sk, ++ struct sk_buff *skb) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ u32 packets_acked, len, delta_truesize; ++ ++ BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)); ++ ++ packets_acked = tcp_skb_pcount(skb); ++ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ return 0; ++ ++ len = meta_tp->snd_una - TCP_SKB_CB(skb)->seq; ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq += len; ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ ++ if (delta_truesize) ++ skb->truesize -= delta_truesize; ++ ++ /* Any change of skb->len requires recalculation of tso factor. */ ++ if (tcp_skb_pcount(skb) > 1) ++ tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); ++ packets_acked -= tcp_skb_pcount(skb); ++ ++ if (packets_acked) { ++ BUG_ON(tcp_skb_pcount(skb) == 0); ++ BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); ++ } ++ ++ return packets_acked; ++} ++ ++/* Cleans the meta-socket retransmission queue and the reinject-queue. */ ++static void mptcp_clean_rtx_queue(struct sock *meta_sk, u32 prior_snd_una) ++{ ++ struct sk_buff *skb, *tmp, *next; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ bool fully_acked = true; ++ bool acked = false; ++ u32 acked_pcount; ++ ++ for (skb = skb_rb_first(&meta_sk->tcp_rtx_queue); skb; skb = next) { ++ struct tcp_skb_cb *scb = TCP_SKB_CB(skb); ++ ++ tcp_ack_tstamp(meta_sk, skb, prior_snd_una); ++ ++ if (after(scb->end_seq, meta_tp->snd_una)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, scb->seq)) ++ break; ++ ++ acked_pcount = tcp_tso_acked(meta_sk, skb); ++ if (!acked_pcount) ++ break; ++ fully_acked = false; ++ } else { ++ acked_pcount = tcp_skb_pcount(skb); ++ } ++ ++ acked = true; ++ meta_tp->packets_out -= acked_pcount; ++ meta_tp->retrans_stamp = 0; ++ ++ if (!fully_acked) ++ break; ++ ++ next = skb_rb_next(skb); ++ ++ if (mptcp_is_data_fin(skb)) { ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ /* DATA_FIN has been acknowledged - now we can close ++ * the subflows ++ */ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ unsigned long delay = 0; ++ ++ /* If we are the passive closer, don't trigger ++ * subflow-fin until the subflow has been finned ++ * by the peer - thus we add a delay. ++ */ ++ if (mpcb->passive_close && ++ sk_it->sk_state == TCP_ESTABLISHED) ++ delay = inet_csk(sk_it)->icsk_rto << 3; ++ ++ mptcp_sub_close(sk_it, delay); ++ } ++ } ++ tcp_rtx_queue_unlink_and_free(skb, meta_sk); ++ } ++ /* Remove acknowledged data from the reinject queue */ ++ skb_queue_walk_safe(&mpcb->reinject_queue, skb, tmp) { ++ if (before(meta_tp->snd_una, TCP_SKB_CB(skb)->end_seq)) { ++ if (tcp_skb_pcount(skb) == 1 || ++ !after(meta_tp->snd_una, TCP_SKB_CB(skb)->seq)) ++ break; ++ ++ mptcp_tso_acked_reinject(meta_sk, skb); ++ break; ++ } ++ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ } ++ ++ if (likely(between(meta_tp->snd_up, prior_snd_una, meta_tp->snd_una))) ++ meta_tp->snd_up = meta_tp->snd_una; ++ ++ if (acked) { ++ tcp_rearm_rto(meta_sk); ++ /* Normally this is done in tcp_try_undo_loss - but MPTCP ++ * does not call this function. ++ */ ++ inet_csk(meta_sk)->icsk_retransmits = 0; ++ } ++} ++ ++/* Inspired by tcp_rcv_state_process */ ++/* Returns 0 if processing the packet can continue ++ * -1 if connection was closed with an active reset ++ * 1 if connection was closed and processing should stop. ++ */ ++static int mptcp_rcv_state_process(struct sock *meta_sk, struct sock *sk, ++ const struct sk_buff *skb, u32 data_seq, ++ u16 data_len) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ const struct tcphdr *th = tcp_hdr(skb); ++ ++ /* State-machine handling if FIN has been enqueued and he has ++ * been acked (snd_una == write_seq) - it's important that this ++ * here is after sk_wmem_free_skb because otherwise ++ * sk_forward_alloc is wrong upon inet_csk_destroy_sock() ++ */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: { ++ struct dst_entry *dst; ++ int tmo; ++ ++ if (meta_tp->snd_una != meta_tp->write_seq) ++ break; ++ ++ tcp_set_state(meta_sk, TCP_FIN_WAIT2); ++ meta_sk->sk_shutdown |= SEND_SHUTDOWN; ++ ++ dst = __sk_dst_get(sk); ++ if (dst) ++ dst_confirm(dst); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Wake up lingering close() */ ++ meta_sk->sk_state_change(meta_sk); ++ break; ++ } ++ ++ if (meta_tp->linger2 < 0 || ++ (data_len && ++ after(data_seq + data_len - (mptcp_is_data_fin2(skb, tp) ? 1 : 0), ++ meta_tp->rcv_nxt))) { ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_done(meta_sk); ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ return -1; ++ } ++ ++ tmo = tcp_fin_time(meta_sk); ++ if (tmo > TCP_TIMEWAIT_LEN) { ++ inet_csk_reset_keepalive_timer(meta_sk, tmo - TCP_TIMEWAIT_LEN); ++ } else if (mptcp_is_data_fin2(skb, tp) || sock_owned_by_user(meta_sk)) { ++ /* Bad case. We could lose such FIN otherwise. ++ * It is not a big problem, but it looks confusing ++ * and not so rare event. We still can lose it now, ++ * if it spins in bh_lock_sock(), but it is really ++ * marginal case. ++ */ ++ inet_csk_reset_keepalive_timer(meta_sk, tmo); ++ } else { ++ meta_tp->ops->time_wait(meta_sk, TCP_FIN_WAIT2, tmo); ++ } ++ break; ++ } ++ case TCP_CLOSING: ++ case TCP_LAST_ACK: ++ if (meta_tp->snd_una == meta_tp->write_seq) { ++ tcp_done(meta_sk); ++ return 1; ++ } ++ break; ++ } ++ ++ /* step 7: process the segment text */ ++ switch (meta_sk->sk_state) { ++ case TCP_FIN_WAIT1: ++ case TCP_FIN_WAIT2: ++ /* RFC 793 says to queue data in these states, ++ * RFC 1122 says we MUST send a reset. ++ * BSD 4.4 also does reset. ++ */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN) { ++ if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && ++ after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt) && ++ !mptcp_is_data_fin2(skb, tp)) { ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPABORTONDATA); ++ mptcp_send_active_reset(meta_sk, GFP_ATOMIC); ++ tcp_reset(meta_sk); ++ return -1; ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/** ++ * @return: ++ * i) 1: Everything's fine. ++ * ii) -1: A reset has been sent on the subflow - csum-failure ++ * iii) 0: csum-failure but no reset sent, because it's the last subflow. ++ * Last packet should not be destroyed by the caller because it has ++ * been done here. ++ */ ++static int mptcp_verif_dss_csum(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1, *last = NULL; ++ __wsum csum_tcp = 0; /* cumulative checksum of pld + mptcp-header */ ++ int ans = 1, overflowed = 0, offset = 0, dss_csum_added = 0; ++ int iter = 0; ++ u32 next_seq, offset_seq; ++ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp, tmp1) { ++ unsigned int csum_len; ++ ++ /* init next seq in first round */ ++ if (!iter) ++ next_seq = TCP_SKB_CB(tmp)->seq; ++ offset_seq = next_seq - TCP_SKB_CB(tmp)->seq; ++ ++ if (before(tp->mptcp->map_subseq + tp->mptcp->map_data_len, TCP_SKB_CB(tmp)->end_seq)) ++ /* Mapping ends in the middle of the packet - ++ * csum only these bytes ++ */ ++ csum_len = tp->mptcp->map_subseq + tp->mptcp->map_data_len - TCP_SKB_CB(tmp)->seq; ++ else ++ csum_len = tmp->len; ++ ++ csum_len -= offset_seq; ++ offset = 0; ++ if (overflowed) { ++ char first_word[4]; ++ first_word[0] = 0; ++ first_word[1] = 0; ++ first_word[2] = 0; ++ first_word[3] = *(tmp->data + offset_seq); ++ csum_tcp = csum_partial(first_word, 4, csum_tcp); ++ offset = 1; ++ csum_len--; ++ overflowed = 0; ++ } ++ ++ csum_tcp = skb_checksum(tmp, offset + offset_seq, csum_len, ++ csum_tcp); ++ ++ /* Was it on an odd-length? Then we have to merge the next byte ++ * correctly (see above) ++ */ ++ if (csum_len != (csum_len & (~1))) ++ overflowed = 1; ++ ++ if (mptcp_is_data_seq(tmp) && !dss_csum_added) { ++ __be32 data_seq = htonl((u32)(tp->mptcp->map_data_seq >> 32)); ++ ++ /* If a 64-bit dss is present, we increase the offset ++ * by 4 bytes, as the high-order 64-bits will be added ++ * in the final csum_partial-call. ++ */ ++ u32 offset = skb_transport_offset(tmp) + ++ TCP_SKB_CB(tmp)->dss_off; ++ if (TCP_SKB_CB(tmp)->mptcp_flags & MPTCPHDR_SEQ64_SET) ++ offset += 4; ++ ++ csum_tcp = skb_checksum(tmp, offset, ++ MPTCP_SUB_LEN_SEQ_CSUM, ++ csum_tcp); ++ ++ csum_tcp = csum_partial(&data_seq, ++ sizeof(data_seq), csum_tcp); ++ ++ dss_csum_added = 1; /* Just do it once */ ++ } else if (mptcp_is_data_mpcapable(tmp) && !dss_csum_added) { ++ u32 offset = skb_transport_offset(tmp) + TCP_SKB_CB(tmp)->dss_off; ++ __be64 data_seq = htonll(tp->mptcp->map_data_seq); ++ __be32 rel_seq = htonl(tp->mptcp->map_subseq - tp->mptcp->rcv_isn); ++ ++ csum_tcp = csum_partial(&data_seq, sizeof(data_seq), csum_tcp); ++ csum_tcp = csum_partial(&rel_seq, sizeof(rel_seq), csum_tcp); ++ ++ csum_tcp = skb_checksum(tmp, offset, 4, csum_tcp); ++ ++ dss_csum_added = 1; ++ } ++ last = tmp; ++ iter++; ++ ++ if (!skb_queue_is_last(&sk->sk_receive_queue, tmp) && ++ !before(TCP_SKB_CB(tmp1)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ next_seq = TCP_SKB_CB(tmp)->end_seq; ++ } ++ ++ /* Now, checksum must be 0 */ ++ if (unlikely(csum_fold(csum_tcp))) { ++ struct mptcp_tcp_sock *mptcp; ++ struct sock *sk_it = NULL; ++ ++ pr_debug("%s csum is wrong: %#x tcp-seq %u dss_csum_added %d overflowed %d iterations %d\n", ++ __func__, csum_fold(csum_tcp), TCP_SKB_CB(last)->seq, ++ dss_csum_added, overflowed, iter); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMFAIL); ++ tp->mptcp->send_mp_fail = 1; ++ ++ /* map_data_seq is the data-seq number of the ++ * mapping we are currently checking ++ */ ++ tp->mpcb->csum_cutoff_seq = tp->mptcp->map_data_seq; ++ ++ /* Search for another subflow that is fully established */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ sk_it = mptcp_to_sock(mptcp); ++ ++ if (sk_it != sk && ++ tcp_sk(sk_it)->mptcp->fully_established) ++ break; ++ ++ sk_it = NULL; ++ } ++ ++ if (sk_it) { ++ mptcp_send_reset(sk); ++ ans = -1; ++ } else { ++ tp->mpcb->send_infinite_mapping = 1; ++ ++ /* Need to purge the rcv-queue as it's no more valid */ ++ while ((tmp = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { ++ tp->copied_seq = TCP_SKB_CB(tmp)->end_seq; ++ kfree_skb(tmp); ++ } ++ ++ mptcp_fallback_close(tp->mpcb, sk); ++ ++ ans = 0; ++ } ++ } ++ ++ return ans; ++} ++ ++static inline void mptcp_prepare_skb(struct sk_buff *skb, ++ const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 inc = 0, end_seq = tcb->end_seq; ++ ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ end_seq--; ++ /* If skb is the end of this mapping (end is always at mapping-boundary ++ * thanks to the splitting/trimming), then we need to increase ++ * data-end-seq by 1 if this here is a data-fin. ++ * ++ * We need to do -1 because end_seq includes the subflow-FIN. ++ */ ++ if (tp->mptcp->map_data_fin && ++ end_seq == tp->mptcp->map_subseq + tp->mptcp->map_data_len) { ++ inc = 1; ++ ++ /* We manually set the fin-flag if it is a data-fin. For easy ++ * processing in tcp_recvmsg. ++ */ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } else { ++ /* We may have a subflow-fin with data but without data-fin */ ++ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_FIN; ++ } ++ ++ /* Adapt data-seq's to the packet itself. We kinda transform the ++ * dss-mapping to a per-packet granularity. This is necessary to ++ * correctly handle overlapping mappings coming from different ++ * subflows. Otherwise it would be a complete mess. ++ */ ++ tcb->seq = ((u32)tp->mptcp->map_data_seq) + tcb->seq - tp->mptcp->map_subseq; ++ tcb->end_seq = tcb->seq + skb->len + inc; ++} ++ ++static inline void mptcp_reset_mapping(struct tcp_sock *tp, u32 old_copied_seq) ++{ ++ tp->mptcp->map_data_len = 0; ++ tp->mptcp->map_data_seq = 0; ++ tp->mptcp->map_subseq = 0; ++ tp->mptcp->map_data_fin = 0; ++ tp->mptcp->mapping_present = 0; ++ ++ /* In infinite mapping receiver mode, we have to advance the implied ++ * data-sequence number when we progress the subflow's data. ++ */ ++ if (tp->mpcb->infinite_mapping_rcv) ++ tp->mpcb->infinite_rcv_seq += (tp->copied_seq - old_copied_seq); ++} ++ ++/* The DSS-mapping received on the sk only covers the second half of the skb ++ * (cut at seq). We trim the head from the skb. ++ * Data will be freed upon kfree(). ++ * ++ * Inspired by tcp_trim_head(). ++ */ ++static void mptcp_skb_trim_head(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ int len = seq - TCP_SKB_CB(skb)->seq; ++ u32 new_seq = TCP_SKB_CB(skb)->seq + len; ++ u32 delta_truesize; ++ ++ delta_truesize = __pskb_trim_head(skb, len); ++ ++ TCP_SKB_CB(skb)->seq = new_seq; ++ ++ if (delta_truesize) { ++ skb->truesize -= delta_truesize; ++ atomic_sub(delta_truesize, &sk->sk_rmem_alloc); ++ sk_mem_uncharge(sk, delta_truesize); ++ } ++} ++ ++/* The DSS-mapping received on the sk only covers the first half of the skb ++ * (cut at seq). We create a second skb (@return), and queue it in the rcv-queue ++ * as further packets may resolve the mapping of the second half of data. ++ * ++ * Inspired by tcp_fragment(). ++ */ ++static int mptcp_skb_split_tail(struct sk_buff *skb, struct sock *sk, u32 seq) ++{ ++ struct sk_buff *buff; ++ int nsize; ++ int nlen, len; ++ u8 flags; ++ ++ len = seq - TCP_SKB_CB(skb)->seq; ++ nsize = skb_headlen(skb) - len + tcp_sk(sk)->tcp_header_len; ++ if (nsize < 0) ++ nsize = 0; ++ ++ /* Get a new skb... force flag on. */ ++ buff = alloc_skb(nsize, GFP_ATOMIC); ++ if (buff == NULL) ++ return -ENOMEM; ++ ++ skb_reserve(buff, tcp_sk(sk)->tcp_header_len); ++ skb_reset_transport_header(buff); ++ ++ flags = TCP_SKB_CB(skb)->tcp_flags; ++ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN); ++ TCP_SKB_CB(buff)->tcp_flags = flags; ++ ++ /* We absolutly need to call skb_set_owner_r before refreshing the ++ * truesize of buff, otherwise the moved data will account twice. ++ */ ++ skb_set_owner_r(buff, sk); ++ nlen = skb->len - len - nsize; ++ buff->truesize += nlen; ++ skb->truesize -= nlen; ++ ++ /* Correct the sequence numbers. */ ++ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; ++ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; ++ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; ++ ++ skb_split(skb, buff, len); ++ ++ __skb_queue_after(&sk->sk_receive_queue, skb, buff); ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_prevalidate_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ /* If we are in infinite mode, the subflow-fin is in fact a data-fin. */ ++ if (!skb->len && (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && ++ !mptcp_is_data_fin(skb) && !mpcb->infinite_mapping_rcv) { ++ /* Remove a pure subflow-fin from the queue and increase ++ * copied_seq. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* If we are not yet fully established and do not know the mapping for ++ * this segment, this path has to fallback to infinite or be torn down. ++ */ ++ if (!tp->mptcp->fully_established && !mptcp_is_data_seq(skb) && ++ !mptcp_is_data_mpcapable(skb) && ++ !tp->mptcp->mapping_present && !mpcb->infinite_mapping_rcv) { ++ pr_debug("%s %#x will fallback - pi %d from %pS, seq %u mptcp-flags %#x\n", ++ __func__, mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, __builtin_return_address(0), ++ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->mptcp_flags); ++ ++ if (!is_master_tp(tp)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATASUB); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FBDATAINIT); ++ ++ mpcb->infinite_mapping_snd = 1; ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->infinite_rcv_seq = mptcp_get_rcv_nxt_64(mptcp_meta_tp(tp)); ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ /* We do a seamless fallback and should not send a inf.mapping. */ ++ mpcb->send_infinite_mapping = 0; ++ tp->mptcp->fully_established = 1; ++ } ++ ++ /* Receiver-side becomes fully established when a whole rcv-window has ++ * been received without the need to fallback due to the previous ++ * condition. ++ */ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->init_rcv_wnd -= skb->len; ++ if (tp->mptcp->init_rcv_wnd < 0) ++ mptcp_become_fully_estab(sk); ++ } ++ ++ return 0; ++} ++ ++static void mptcp_restart_sending(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *wq_head, *skb, *tmp; ++ ++ skb = tcp_rtx_queue_head(meta_sk); ++ ++ /* We resend everything that has not been acknowledged, thus we need ++ * to move it from the rtx-tree to the write-queue. ++ */ ++ wq_head = tcp_write_queue_head(meta_sk); ++ ++ skb_rbtree_walk_from_safe(skb, tmp) { ++ list_del(&skb->tcp_tsorted_anchor); ++ tcp_rtx_queue_unlink(skb, meta_sk); ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ ++ if (wq_head) ++ __skb_queue_before(&meta_sk->sk_write_queue, wq_head, skb); ++ else ++ tcp_add_write_queue_tail(meta_sk, skb); ++ } ++ ++ /* We artificially restart the whole send-queue. Thus, ++ * it is as if no packets are in flight ++ */ ++ meta_tp->packets_out = 0; ++ ++ /* If the snd_nxt already wrapped around, we have to ++ * undo the wrapping, as we are restarting from snd_una ++ * on. ++ */ ++ if (meta_tp->snd_nxt < meta_tp->snd_una) { ++ mpcb->snd_high_order[mpcb->snd_hiseq_index] -= 2; ++ mpcb->snd_hiseq_index = mpcb->snd_hiseq_index ? 0 : 1; ++ } ++ meta_tp->snd_nxt = meta_tp->snd_una; ++ ++ /* Trigger a sending on the meta. */ ++ mptcp_push_pending_frames(meta_sk); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_detect_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 *ptr; ++ u32 data_seq, sub_seq, data_len, tcp_end_seq; ++ bool set_infinite_rcv = false; ++ ++ /* If we are in infinite-mapping-mode, the subflow is guaranteed to be ++ * in-order at the data-level. Thus data-seq-numbers can be inferred ++ * from what is expected at the data-level. ++ */ ++ if (mpcb->infinite_mapping_rcv) { ++ /* copied_seq may be bigger than tcb->seq (e.g., when the peer ++ * retransmits data that actually has already been acknowledged with ++ * newer data, if he did not receive our acks). Thus, we need ++ * to account for this overlap as well. ++ */ ++ tp->mptcp->map_data_seq = mpcb->infinite_rcv_seq - (tp->copied_seq - tcb->seq); ++ tp->mptcp->map_subseq = tcb->seq; ++ tp->mptcp->map_data_len = skb->len; ++ tp->mptcp->map_data_fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN); ++ tp->mptcp->mapping_present = 1; ++ return 0; ++ } ++ ++ if (!tp->mptcp->mapping_present && mptcp_is_data_mpcapable(skb)) { ++ __u32 *ptr = (__u32 *)(skb_transport_header(skb) + TCP_SKB_CB(skb)->dss_off); ++ ++ sub_seq = 1 + tp->mptcp->rcv_isn; ++ data_seq = meta_tp->rcv_nxt; ++ data_len = get_unaligned_be16(ptr); ++ } else if (!mptcp_is_data_seq(skb)) { ++ /* No mapping here? ++ * Exit - it is either already set or still on its way ++ */ ++ if (!tp->mptcp->mapping_present && ++ tp->rcv_nxt - tp->copied_seq > 65536) { ++ /* Too many packets without a mapping, ++ * this subflow is broken ++ */ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_NODSSWINDOW); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ return 0; ++ } else { ++ /* Well, then the DSS-mapping is there. So, read it! */ ++ ptr = mptcp_skb_set_data_seq(skb, &data_seq, mpcb); ++ ptr++; ++ sub_seq = get_unaligned_be32(ptr) + tp->mptcp->rcv_isn; ++ ptr++; ++ data_len = get_unaligned_be16(ptr); ++ } ++ ++ /* If it's an empty skb with DATA_FIN, sub_seq must get fixed. ++ * The draft sets it to 0, but we really would like to have the ++ * real value, to have an easy handling afterwards here in this ++ * function. ++ */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ sub_seq = TCP_SKB_CB(skb)->seq; ++ ++ /* If there is already a mapping - we check if it maps with the current ++ * one. If not - we reset. ++ */ ++ if (tp->mptcp->mapping_present && ++ (data_seq != (u32)tp->mptcp->map_data_seq || ++ sub_seq != tp->mptcp->map_subseq || ++ data_len != tp->mptcp->map_data_len + tp->mptcp->map_data_fin || ++ mptcp_is_data_fin(skb) != tp->mptcp->map_data_fin)) { ++ /* Mapping in packet is different from what we want */ ++ pr_debug("%s Mappings do not match!\n", __func__); ++ pr_debug("%s dseq %u mdseq %u, sseq %u msseq %u dlen %u mdlen %u dfin %d mdfin %d\n", ++ __func__, data_seq, (u32)tp->mptcp->map_data_seq, ++ sub_seq, tp->mptcp->map_subseq, data_len, ++ tp->mptcp->map_data_len, mptcp_is_data_fin(skb), ++ tp->mptcp->map_data_fin); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSNOMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* If the previous check was good, the current mapping is valid and we exit. */ ++ if (tp->mptcp->mapping_present) ++ return 0; ++ ++ /* Mapping not yet set on this subflow - we set it here! */ ++ ++ if (!data_len) { ++ mpcb->infinite_mapping_rcv = 1; ++ mpcb->send_infinite_mapping = 1; ++ tp->mptcp->fully_established = 1; ++ /* We need to repeat mp_fail's until the sender felt ++ * back to infinite-mapping - here we stop repeating it. ++ */ ++ tp->mptcp->send_mp_fail = 0; ++ ++ /* We have to fixup data_len - it must be the same as skb->len */ ++ data_len = skb->len + (mptcp_is_data_fin(skb) ? 1 : 0); ++ sub_seq = tcb->seq; ++ ++ mptcp_restart_sending(tp->meta_sk); ++ ++ mptcp_fallback_close(mpcb, sk); ++ ++ /* data_seq and so on are set correctly */ ++ ++ /* At this point, the meta-ofo-queue has to be emptied, ++ * as the following data is guaranteed to be in-order at ++ * the data and subflow-level ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ ++ set_infinite_rcv = true; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_INFINITEMAPRX); ++ } ++ ++ /* We are sending mp-fail's and thus are in fallback mode. ++ * Ignore packets which do not announce the fallback and still ++ * want to provide a mapping. ++ */ ++ if (tp->mptcp->send_mp_fail) { ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ ++ /* FIN increased the mapping-length by 1 */ ++ if (mptcp_is_data_fin(skb)) ++ data_len--; ++ ++ /* Subflow-sequences of packet must be ++ * (at least partially) be part of the DSS-mapping's ++ * subflow-sequence-space. ++ * ++ * Basically the mapping is not valid, if either of the ++ * following conditions is true: ++ * ++ * 1. It's not a data_fin and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * 2. It's a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq >= TCP-end_seq ++ * ++ * The previous two can be merged into: ++ * TCP-end_seq > TCP-seq and MPTCP-sub_seq >= TCP-end_seq ++ * Because if it's not a data-fin, TCP-end_seq > TCP-seq ++ * ++ * 3. It's a data_fin and skb->len == 0 and ++ * MPTCP-sub_seq > TCP-end_seq ++ * ++ * 4. It's not a data_fin and TCP-end_seq > TCP-seq and ++ * MPTCP-sub_seq + MPTCP-data_len <= TCP-seq ++ */ ++ ++ /* subflow-fin is not part of the mapping - ignore it here ! */ ++ tcp_end_seq = tcb->end_seq; ++ if (tcb->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if ((!before(sub_seq, tcb->end_seq) && after(tcp_end_seq, tcb->seq)) || ++ (mptcp_is_data_fin(skb) && skb->len == 0 && after(sub_seq, tcb->end_seq)) || ++ (!after(sub_seq + data_len, tcb->seq) && after(tcp_end_seq, tcb->seq))) { ++ /* Subflow-sequences of packet is different from what is in the ++ * packet's dss-mapping. The peer is misbehaving - reset ++ */ ++ pr_debug("%s Packet's mapping does not map to the DSS sub_seq %u end_seq %u, tcp_end_seq %u seq %u dfin %u len %u data_len %u copied_seq %u\n", ++ __func__, sub_seq, tcb->end_seq, tcp_end_seq, ++ tcb->seq, mptcp_is_data_fin(skb), ++ skb->len, data_len, tp->copied_seq); ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTCPMISMATCH); ++ mptcp_send_reset(sk); ++ return 1; ++ } ++ ++ /* Does the DSS had 64-bit seqnum's ? */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_SEQ64_SET)) { ++ /* Wrapped around? */ ++ if (unlikely(after(data_seq, meta_tp->rcv_nxt) && data_seq < meta_tp->rcv_nxt)) { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, !mpcb->rcv_hiseq_index, data_seq); ++ } else { ++ /* Else, access the default high-order bits */ ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, data_seq); ++ } ++ } else { ++ tp->mptcp->map_data_seq = mptcp_get_data_seq_64(mpcb, (tcb->mptcp_flags & MPTCPHDR_SEQ64_INDEX) ? 1 : 0, data_seq); ++ ++ if (unlikely(tcb->mptcp_flags & MPTCPHDR_SEQ64_OFO)) { ++ /* We make sure that the data_seq is invalid. ++ * It will be dropped later. ++ */ ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ tp->mptcp->map_data_seq += 0xFFFFFFFF; ++ } ++ } ++ ++ if (set_infinite_rcv) ++ mpcb->infinite_rcv_seq = tp->mptcp->map_data_seq; ++ ++ tp->mptcp->map_data_len = data_len; ++ tp->mptcp->map_subseq = sub_seq; ++ tp->mptcp->map_data_fin = mptcp_is_data_fin(skb) ? 1 : 0; ++ tp->mptcp->mapping_present = 1; ++ ++ return 0; ++} ++ ++/* Similar to tcp_sequence(...) */ ++static inline bool mptcp_sequence(const struct tcp_sock *meta_tp, ++ u64 data_seq, u64 end_data_seq) ++{ ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u64 rcv_wup64; ++ ++ /* Wrap-around? */ ++ if (meta_tp->rcv_wup > meta_tp->rcv_nxt) { ++ rcv_wup64 = ((u64)(mpcb->rcv_high_order[mpcb->rcv_hiseq_index] - 1) << 32) | ++ meta_tp->rcv_wup; ++ } else { ++ rcv_wup64 = mptcp_get_data_seq_64(mpcb, mpcb->rcv_hiseq_index, ++ meta_tp->rcv_wup); ++ } ++ ++ return !before64(end_data_seq, rcv_wup64) && ++ !after64(data_seq, mptcp_get_rcv_nxt_64(meta_tp) + tcp_receive_window(meta_tp)); ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * -1 this packet was broken - continue with the next one. ++ */ ++static int mptcp_validate_mapping(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *tmp, *tmp1; ++ u32 tcp_end_seq; ++ ++ if (!tp->mptcp->mapping_present) ++ return 0; ++ ++ /* either, the new skb gave us the mapping and the first segment ++ * in the sub-rcv-queue has to be trimmed ... ++ */ ++ tmp = skb_peek(&sk->sk_receive_queue); ++ if (before(TCP_SKB_CB(tmp)->seq, tp->mptcp->map_subseq) && ++ after(TCP_SKB_CB(tmp)->end_seq, tp->mptcp->map_subseq)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSTRIMHEAD); ++ mptcp_skb_trim_head(tmp, sk, tp->mptcp->map_subseq); ++ } ++ ++ /* ... or the new skb (tail) has to be split at the end. */ ++ tcp_end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) ++ tcp_end_seq--; ++ if (after(tcp_end_seq, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) { ++ u32 seq = tp->mptcp->map_subseq + tp->mptcp->map_data_len; ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DSSSPLITTAIL); ++ if (mptcp_skb_split_tail(skb, sk, seq)) { /* Allocation failed */ ++ /* TODO : maybe handle this here better. ++ * We now just force meta-retransmission. ++ */ ++ tp->copied_seq = TCP_SKB_CB(skb)->end_seq; ++ __skb_unlink(skb, &sk->sk_receive_queue); ++ __kfree_skb(skb); ++ return -1; ++ } ++ } ++ ++ /* Now, remove old sk_buff's from the receive-queue. ++ * This may happen if the mapping has been lost for these segments and ++ * the next mapping has already been received. ++ */ ++ if (before(TCP_SKB_CB(skb_peek(&sk->sk_receive_queue))->seq, tp->mptcp->map_subseq)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ if (!before(TCP_SKB_CB(tmp1)->seq, tp->mptcp->map_subseq)) ++ break; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PURGEOLD); ++ /* Impossible that we could free skb here, because his ++ * mapping is known to be valid from previous checks ++ */ ++ __kfree_skb(tmp1); ++ } ++ } ++ ++ return 0; ++} ++ ++/* @return: 0 everything is fine. Just continue processing ++ * 1 subflow is broken stop everything ++ * -1 this mapping has been put in the meta-receive-queue ++ * -2 this mapping has been eaten by the application ++ */ ++static int mptcp_queue_skb(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct sk_buff *tmp, *tmp1; ++ u64 rcv_nxt64 = mptcp_get_rcv_nxt_64(meta_tp); ++ u32 old_copied_seq = tp->copied_seq; ++ bool data_queued = false; ++ ++ /* Have we not yet received the full mapping? */ ++ if (!tp->mptcp->mapping_present || ++ before(tp->rcv_nxt, tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ return 0; ++ ++ /* Is this an overlapping mapping? rcv_nxt >= end_data_seq ++ * OR ++ * This mapping is out of window ++ */ ++ if (!before64(rcv_nxt64, tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin) || ++ !mptcp_sequence(meta_tp, tp->mptcp->map_data_seq, ++ tp->mptcp->map_data_seq + tp->mptcp->map_data_len + tp->mptcp->map_data_fin)) { ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return -1; ++ } ++ ++ /* Record it, because we want to send our data_fin on the same path */ ++ if (tp->mptcp->map_data_fin) { ++ mpcb->dfin_path_index = tp->mptcp->path_index; ++ mpcb->dfin_combined = !!(sk->sk_shutdown & RCV_SHUTDOWN); ++ } ++ ++ /* Verify the checksum */ ++ if (mpcb->dss_csum && !mpcb->infinite_mapping_rcv) { ++ int ret = mptcp_verif_dss_csum(sk); ++ ++ if (ret <= 0) { ++ mptcp_reset_mapping(tp, old_copied_seq); ++ return 1; ++ } ++ } ++ ++ if (before64(rcv_nxt64, tp->mptcp->map_data_seq)) { ++ /* Seg's have to go to the meta-ofo-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true later. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ if (!mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ tcp_data_queue_ofo(meta_sk, tmp1); ++ else ++ __kfree_skb(tmp1); ++ ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ ++ /* Quick ACK if more 3/4 of the receive window is filled */ ++ if (after64(tp->mptcp->map_data_seq, ++ rcv_nxt64 + 3 * (tcp_receive_window(meta_tp) >> 2))) ++ tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); ++ ++ } else { ++ /* Ready for the meta-rcv-queue */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, tmp1, tmp) { ++ int eaten = 0; ++ bool fragstolen = false; ++ u32 old_rcv_nxt = meta_tp->rcv_nxt; ++ ++ tp->copied_seq = TCP_SKB_CB(tmp1)->end_seq; ++ mptcp_prepare_skb(tmp1, sk); ++ __skb_unlink(tmp1, &sk->sk_receive_queue); ++ /* MUST be done here, because fragstolen may be true. ++ * Then, kfree_skb_partial will not account the memory. ++ */ ++ skb_orphan(tmp1); ++ ++ /* This segment has already been received */ ++ if (!after(TCP_SKB_CB(tmp1)->end_seq, meta_tp->rcv_nxt)) { ++ __kfree_skb(tmp1); ++ goto next; ++ } ++ ++ if (mpcb->in_time_wait) /* In time-wait, do not receive data */ ++ eaten = 1; ++ ++ if (!eaten) ++ eaten = tcp_queue_rcv(meta_sk, tmp1, &fragstolen); ++ ++ meta_tp->rcv_nxt = TCP_SKB_CB(tmp1)->end_seq; ++ ++ if (TCP_SKB_CB(tmp1)->tcp_flags & TCPHDR_FIN) ++ mptcp_fin(meta_sk); ++ ++ /* Check if this fills a gap in the ofo queue */ ++ if (!RB_EMPTY_ROOT(&meta_tp->out_of_order_queue)) ++ tcp_ofo_queue(meta_sk); ++ ++ mptcp_check_rcvseq_wrap(meta_tp, old_rcv_nxt); ++ ++ if (eaten) ++ kfree_skb_partial(tmp1, fragstolen); ++ ++ data_queued = true; ++next: ++ if (!skb_queue_empty(&sk->sk_receive_queue) && ++ !before(TCP_SKB_CB(tmp)->seq, ++ tp->mptcp->map_subseq + tp->mptcp->map_data_len)) ++ break; ++ } ++ } ++ ++ inet_csk(meta_sk)->icsk_ack.lrcvtime = tcp_jiffies32; ++ mptcp_reset_mapping(tp, old_copied_seq); ++ ++ return data_queued ? -1 : -2; ++} ++ ++void mptcp_data_ready(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb, *tmp; ++ int queued = 0; ++ ++ tcp_mstamp_refresh(tcp_sk(meta_sk)); ++ ++ /* restart before the check, because mptcp_fin might have changed the ++ * state. ++ */ ++restart: ++ /* If the meta cannot receive data, there is no point in pushing data. ++ * If we are in time-wait, we may still be waiting for the final FIN. ++ * So, we should proceed with the processing. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !tcp_sk(sk)->mpcb->in_time_wait) { ++ skb_queue_purge(&sk->sk_receive_queue); ++ tcp_sk(sk)->copied_seq = tcp_sk(sk)->rcv_nxt; ++ goto exit; ++ } ++ ++ /* Iterate over all segments, detect their mapping (if we don't have ++ * one yet), validate them and push everything one level higher. ++ */ ++ skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { ++ int ret; ++ /* Pre-validation - e.g., early fallback */ ++ ret = mptcp_prevalidate_skb(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Set the current mapping */ ++ ret = mptcp_detect_mapping(sk, skb); ++ if (ret < 0) ++ goto restart; ++ else if (ret > 0) ++ break; ++ ++ /* Validation */ ++ if (mptcp_validate_mapping(sk, skb) < 0) ++ goto restart; ++ ++ /* Push a level higher */ ++ ret = mptcp_queue_skb(sk); ++ if (ret < 0) { ++ if (ret == -1) ++ queued = ret; ++ goto restart; ++ } else if (ret == 0) { ++ continue; ++ } else { /* ret == 1 */ ++ break; ++ } ++ } ++ ++exit: ++ if (tcp_sk(sk)->close_it && sk->sk_state == TCP_FIN_WAIT2) { ++ tcp_send_ack(sk); ++ tcp_sk(sk)->ops->time_wait(sk, TCP_TIME_WAIT, 0); ++ } ++ ++ if (queued == -1 && !sock_flag(meta_sk, SOCK_DEAD)) ++ meta_sk->sk_data_ready(meta_sk); ++} ++ ++struct mp_join *mptcp_find_join(const struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether JOIN is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return NULL; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return NULL; ++ if (opsize > length) ++ return NULL; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)(ptr - 2))->sub == MPTCP_SUB_JOIN) { ++ return (struct mp_join *)(ptr - 2); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return NULL; ++} ++ ++int mptcp_lookup_join(struct sk_buff *skb, struct inet_timewait_sock *tw) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ struct mp_join *join_opt = mptcp_find_join(skb); ++ if (!join_opt) ++ return 0; ++ ++ /* MPTCP structures were not initialized, so return error */ ++ if (mptcp_init_failed) ++ return -1; ++ ++ token = join_opt->u.syn.token; ++ meta_sk = mptcp_hash_find(dev_net(skb_dst(skb)->dev), token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* Coming from time-wait-sock processing in tcp_v4_rcv. ++ * We have to deschedule it before continuing, because otherwise ++ * mptcp_v4_do_rcv will hit again on it inside tcp_v4_hnd_req. ++ */ ++ if (tw) ++ inet_twsk_deschedule_put(tw); ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 1; ++} ++ ++int mptcp_do_join_short(struct sk_buff *skb, ++ const struct mptcp_options_received *mopt, ++ struct net *net) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ bool meta_v4; ++ ++ token = mopt->mptcp_rem_token; ++ meta_sk = mptcp_hash_find(net, token); ++ if (!meta_sk) { ++ MPTCP_INC_STATS(dev_net(skb_dst(skb)->dev), MPTCP_MIB_JOINNOTOKEN); ++ mptcp_debug("%s:mpcb not found:%x\n", __func__, token); ++ return -1; ++ } ++ ++ meta_v4 = meta_sk->sk_family == AF_INET; ++ if (meta_v4) { ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ mptcp_debug("SYN+MP_JOIN with IPV6 address on pure IPV4 meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ } else if (skb->protocol == htons(ETH_P_IP) && meta_sk->sk_ipv6only) { ++ mptcp_debug("SYN+MP_JOIN with IPV4 address on IPV6_V6ONLY meta\n"); ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return -1; ++ } ++ ++ /* OK, this is a new syn/join, let's create a new open request and ++ * send syn+ack ++ */ ++ ++ /* mptcp_v4_do_rcv tries to free the skb - we prevent this, as ++ * the skb will finally be freed by tcp_v4_do_rcv (where we are ++ * coming from) ++ */ ++ skb_get(skb); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ tcp_v4_do_rcv(meta_sk, skb); ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { /* IPv6 */ ++ tcp_v6_do_rcv(meta_sk, skb); ++#endif /* CONFIG_IPV6 */ ++ } ++ ++ sock_put(meta_sk); /* Taken by mptcp_hash_find */ ++ return 0; ++} ++ ++/** ++ * Equivalent of tcp_fin() for MPTCP ++ * Can be called only when the FIN is validly part ++ * of the data seqnum space. Not before when we get holes. ++ */ ++void mptcp_fin(struct sock *meta_sk) ++{ ++ struct sock *sk = NULL; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ unsigned char state; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->mptcp->path_index == mpcb->dfin_path_index) { ++ sk = sk_it; ++ break; ++ } ++ } ++ ++ if (!sk || sk->sk_state == TCP_CLOSE) ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ inet_csk_schedule_ack(sk); ++ ++ if (!mpcb->in_time_wait) { ++ meta_sk->sk_shutdown |= RCV_SHUTDOWN; ++ sock_set_flag(meta_sk, SOCK_DONE); ++ state = meta_sk->sk_state; ++ } else { ++ state = mpcb->mptw_state; ++ } ++ ++ switch (state) { ++ case TCP_SYN_RECV: ++ case TCP_ESTABLISHED: ++ /* Move to CLOSE_WAIT */ ++ tcp_set_state(meta_sk, TCP_CLOSE_WAIT); ++ inet_csk(sk)->icsk_ack.pingpong = 1; ++ break; ++ ++ case TCP_CLOSE_WAIT: ++ case TCP_CLOSING: ++ /* Received a retransmission of the FIN, do ++ * nothing. ++ */ ++ break; ++ case TCP_LAST_ACK: ++ /* RFC793: Remain in the LAST-ACK state. */ ++ break; ++ ++ case TCP_FIN_WAIT1: ++ /* This case occurs when a simultaneous close ++ * happens, we must ack the received FIN and ++ * enter the CLOSING state. ++ */ ++ tcp_send_ack(sk); ++ tcp_set_state(meta_sk, TCP_CLOSING); ++ break; ++ case TCP_FIN_WAIT2: ++ /* Received a FIN -- send ACK and enter TIME_WAIT. */ ++ tcp_send_ack(sk); ++ meta_tp->ops->time_wait(meta_sk, TCP_TIME_WAIT, 0); ++ break; ++ default: ++ /* Only TCP_LISTEN and TCP_CLOSE are left, in these ++ * cases we should never reach this piece of code. ++ */ ++ pr_err("%s: Impossible, meta_sk->sk_state=%d\n", __func__, ++ meta_sk->sk_state); ++ break; ++ } ++ ++ /* It _is_ possible, that we have something out-of-order _after_ FIN. ++ * Probably, we should reset in this case. For now drop them. ++ */ ++ skb_rbtree_purge(&meta_tp->out_of_order_queue); ++ sk_mem_reclaim(meta_sk); ++ ++ if (!sock_flag(meta_sk, SOCK_DEAD)) { ++ meta_sk->sk_state_change(meta_sk); ++ ++ /* Do not send POLL_HUP for half duplex close. */ ++ if (meta_sk->sk_shutdown == SHUTDOWN_MASK || ++ meta_sk->sk_state == TCP_CLOSE) ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_HUP); ++ else ++ sk_wake_async(meta_sk, SOCK_WAKE_WAITD, POLL_IN); ++ } ++ ++ return; ++} ++ ++/* Similar to tcp_xmit_retransmit_queue */ ++static void mptcp_xmit_retransmit_queue(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb, *rtx_head; ++ ++ if (!meta_tp->packets_out) ++ return; ++ ++ skb = rtx_head = tcp_rtx_queue_head(meta_sk); ++ skb_rbtree_walk_from(skb) { ++ if (mptcp_retransmit_skb(meta_sk, skb)) ++ return; ++ ++ if (skb == rtx_head) ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ inet_csk(meta_sk)->icsk_rto, ++ TCP_RTO_MAX); ++ } ++} ++ ++static void mptcp_snd_una_update(struct tcp_sock *meta_tp, u32 data_ack) ++{ ++ u32 delta = data_ack - meta_tp->snd_una; ++ ++ sock_owned_by_me((struct sock *)meta_tp); ++ meta_tp->bytes_acked += delta; ++ meta_tp->snd_una = data_ack; ++} ++ ++/* Handle the DATA_ACK */ ++static bool mptcp_process_data_ack(struct sock *sk, const struct sk_buff *skb) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *tp = tcp_sk(sk); ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ u32 prior_snd_una = meta_tp->snd_una; ++ int prior_packets; ++ u32 nwin, data_ack, data_seq; ++ u16 data_len = 0; ++ ++ /* A valid packet came in - subflow is operational again */ ++ tp->pf = 0; ++ ++ /* Even if there is no data-ack, we stop retransmitting. ++ * Except if this is a SYN/ACK. Then it is just a retransmission ++ */ ++ if (tp->mptcp->pre_established && !tcp_hdr(skb)->syn) { ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ ++ if (meta_tp->mpcb->pm_ops->established_subflow) ++ meta_tp->mpcb->pm_ops->established_subflow(sk); ++ } ++ ++ /* If we are in infinite mapping mode, rx_opt.data_ack has been ++ * set by mptcp_clean_rtx_infinite. ++ */ ++ if (!(tcb->mptcp_flags & MPTCPHDR_ACK) && !tp->mpcb->infinite_mapping_snd) ++ return false; ++ ++ if (unlikely(!tp->mptcp->fully_established) && ++ tp->mptcp->snt_isn + 1 != TCP_SKB_CB(skb)->ack_seq) ++ /* As soon as a subflow-data-ack (not acking syn, thus snt_isn + 1) ++ * includes a data-ack, we are fully established ++ */ ++ mptcp_become_fully_estab(sk); ++ ++ /* After we did the subflow-only processing (stopping timer and marking ++ * subflow as established), check if we can proceed with MPTCP-level ++ * processing. ++ */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return false; ++ ++ /* Get the data_seq */ ++ if (mptcp_is_data_seq(skb)) { ++ data_seq = tp->mptcp->rx_opt.data_seq; ++ data_len = tp->mptcp->rx_opt.data_len; ++ } else { ++ data_seq = meta_tp->snd_wl1; ++ } ++ ++ data_ack = tp->mptcp->rx_opt.data_ack; ++ ++ /* If the ack is older than previous acks ++ * then we can probably ignore it. ++ */ ++ if (before(data_ack, prior_snd_una)) ++ goto exit; ++ ++ /* If the ack includes data we haven't sent yet, discard ++ * this segment (RFC793 Section 3.9). ++ */ ++ if (after(data_ack, meta_tp->snd_nxt)) ++ goto exit; ++ ++ /* First valid DATA_ACK, we can stop sending the special MP_CAPABLE */ ++ tp->mpcb->send_mptcpv1_mpcapable = 0; ++ ++ /*** Now, update the window - inspired by tcp_ack_update_window ***/ ++ nwin = ntohs(tcp_hdr(skb)->window); ++ ++ if (likely(!tcp_hdr(skb)->syn)) ++ nwin <<= tp->rx_opt.snd_wscale; ++ ++ if (tcp_may_update_window(meta_tp, data_ack, data_seq, nwin)) { ++ tcp_update_wl(meta_tp, data_seq); ++ ++ /* Draft v09, Section 3.3.5: ++ * [...] It should only update its local receive window values ++ * when the largest sequence number allowed (i.e. DATA_ACK + ++ * receive window) increases. [...] ++ */ ++ if (meta_tp->snd_wnd != nwin && ++ !before(data_ack + nwin, tcp_wnd_end(meta_tp))) { ++ meta_tp->snd_wnd = nwin; ++ ++ if (nwin > meta_tp->max_window) ++ meta_tp->max_window = nwin; ++ } ++ } ++ /*** Done, update the window ***/ ++ ++ /* We passed data and got it acked, remove any soft error ++ * log. Something worked... ++ */ ++ sk->sk_err_soft = 0; ++ inet_csk(meta_sk)->icsk_probes_out = 0; ++ meta_tp->rcv_tstamp = tcp_jiffies32; ++ prior_packets = meta_tp->packets_out; ++ if (!prior_packets) ++ goto no_queue; ++ ++ mptcp_snd_una_update(meta_tp, data_ack); ++ ++ mptcp_clean_rtx_queue(meta_sk, prior_snd_una); ++ ++ /* We are in loss-state, and something got acked, retransmit the whole ++ * queue now! ++ */ ++ if (inet_csk(meta_sk)->icsk_ca_state == TCP_CA_Loss && ++ after(data_ack, prior_snd_una)) { ++ mptcp_xmit_retransmit_queue(meta_sk); ++ inet_csk(meta_sk)->icsk_ca_state = TCP_CA_Open; ++ } ++ ++ /* Simplified version of tcp_new_space, because the snd-buffer ++ * is handled by all the subflows. ++ */ ++ if (sock_flag(meta_sk, SOCK_QUEUE_SHRUNK)) { ++ sock_reset_flag(meta_sk, SOCK_QUEUE_SHRUNK); ++ if (meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ meta_sk->sk_write_space(meta_sk); ++ } ++ ++ if (meta_sk->sk_state != TCP_ESTABLISHED) { ++ int ret = mptcp_rcv_state_process(meta_sk, sk, skb, data_seq, data_len); ++ ++ if (ret < 0) ++ return true; ++ else if (ret > 0) ++ return false; ++ } ++ ++exit: ++ mptcp_push_pending_frames(meta_sk); ++ ++ return false; ++ ++no_queue: ++ if (tcp_send_head(meta_sk)) ++ tcp_ack_probe(meta_sk); ++ ++ mptcp_push_pending_frames(meta_sk); ++ ++ return false; ++} ++ ++void mptcp_clean_rtx_infinite(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = tcp_sk(mptcp_meta_sk(sk)); ++ ++ if (!tp->mpcb->infinite_mapping_snd) ++ return; ++ ++ /* The difference between both write_seq's represents the offset between ++ * data-sequence and subflow-sequence. As we are infinite, this must ++ * match. ++ * ++ * Thus, from this difference we can infer the meta snd_una. ++ */ ++ tp->mptcp->rx_opt.data_ack = meta_tp->snd_nxt - tp->snd_nxt + ++ tp->snd_una; ++ ++ mptcp_process_data_ack(sk, skb); ++} ++ ++/**** static functions used by mptcp_parse_options */ ++ ++static void mptcp_send_reset_rem_id(const struct mptcp_cb *mpcb, u8 rem_id) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk_it)->mptcp->rem_id == rem_id) { ++ mptcp_reinject_data(sk_it, 0); ++ mptcp_send_reset(sk_it); ++ } ++ } ++} ++ ++static inline bool is_valid_addropt_opsize(u8 mptcp_ver, ++ struct mp_add_addr *mpadd, ++ int opsize) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->u_bit.v0.ipver == 6) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1) ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++#endif ++ if (mptcp_ver < MPTCP_VERSION_1 && mpadd->u_bit.v0.ipver == 4) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4 + 2; ++ } ++ if (mptcp_ver >= MPTCP_VERSION_1) { ++ return opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ opsize == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++ } ++ return false; ++} ++ ++void mptcp_parse_options(const uint8_t *ptr, int opsize, ++ struct mptcp_options_received *mopt, ++ const struct sk_buff *skb, ++ struct tcp_sock *tp) ++{ ++ const struct mptcp_option *mp_opt = (struct mptcp_option *)ptr; ++ const struct tcphdr *th = tcp_hdr(skb); ++ ++ /* If the socket is mp-capable we would have a mopt. */ ++ if (!mopt) ++ return; ++ ++ switch (mp_opt->sub) { ++ case MPTCP_SUB_CAPABLE: ++ { ++ const struct mp_capable *mpcapable = (struct mp_capable *)ptr; ++ ++ if (mpcapable->ver == MPTCP_VERSION_0 && ++ ((th->syn && opsize != MPTCP_SUB_LEN_CAPABLE_SYN) || ++ (!th->syn && th->ack && opsize != MPTCP_SUB_LEN_CAPABLE_ACK))) { ++ mptcp_debug("%s: mp_capable v0: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ if (mpcapable->ver == MPTCP_VERSION_1 && ++ ((th->syn && !th->ack && opsize != MPTCPV1_SUB_LEN_CAPABLE_SYN) || ++ (th->syn && th->ack && opsize != MPTCPV1_SUB_LEN_CAPABLE_SYNACK) || ++ (!th->syn && th->ack && opsize != MPTCPV1_SUB_LEN_CAPABLE_ACK && ++ opsize != MPTCPV1_SUB_LEN_CAPABLE_DATA && ++ opsize != MPTCPV1_SUB_LEN_CAPABLE_DATA_CSUM))) { ++ mptcp_debug("%s: mp_capable v1: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "If receiving a message with the 'B' flag set to 1, and this ++ * is not understood, then this SYN MUST be silently ignored; ++ */ ++ if (mpcapable->b) { ++ mopt->drop_me = 1; ++ break; ++ } ++ ++ /* MPTCP-RFC 6824: ++ * "An implementation that only supports this method MUST set ++ * bit "H" to 1, and bits "C" through "G" to 0." ++ */ ++ if (!mpcapable->h) ++ break; ++ ++ mopt->saw_mpc = 1; ++ mopt->dss_csum = sysctl_mptcp_checksum || mpcapable->a; ++ ++ if (mpcapable->ver == MPTCP_VERSION_0) { ++ if (opsize == MPTCP_SUB_LEN_CAPABLE_SYN) ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ ++ if (opsize == MPTCP_SUB_LEN_CAPABLE_ACK) { ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ } ++ } else if (mpcapable->ver == MPTCP_VERSION_1) { ++ if (opsize == MPTCPV1_SUB_LEN_CAPABLE_SYNACK) ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ ++ if (opsize == MPTCPV1_SUB_LEN_CAPABLE_ACK) { ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ } ++ ++ if (opsize == MPTCPV1_SUB_LEN_CAPABLE_DATA || ++ opsize == MPTCPV1_SUB_LEN_CAPABLE_DATA_CSUM) { ++ mopt->mptcp_sender_key = mpcapable->sender_key; ++ mopt->mptcp_receiver_key = mpcapable->receiver_key; ++ ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_MPC_DATA; ++ ++ ptr += sizeof(struct mp_capable); ++ TCP_SKB_CB(skb)->dss_off = (ptr - skb_transport_header(skb)); ++ ++ /* Is a check-sum present? */ ++ if (opsize == MPTCPV1_SUB_LEN_CAPABLE_DATA_CSUM) ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_DSS_CSUM; ++ } ++ } ++ ++ mopt->mptcp_ver = mpcapable->ver; ++ break; ++ } ++ case MPTCP_SUB_JOIN: ++ { ++ const struct mp_join *mpjoin = (struct mp_join *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_JOIN_SYN && ++ opsize != MPTCP_SUB_LEN_JOIN_SYNACK && ++ opsize != MPTCP_SUB_LEN_JOIN_ACK) { ++ mptcp_debug("%s: mp_join: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* saw_mpc must be set, because in tcp_check_req we assume that ++ * it is set to support falling back to reg. TCP if a rexmitted ++ * SYN has no MP_CAPABLE or MP_JOIN ++ */ ++ switch (opsize) { ++ case MPTCP_SUB_LEN_JOIN_SYN: ++ mopt->is_mp_join = 1; ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_rem_token = mpjoin->u.syn.token; ++ mopt->mptcp_recv_nonce = mpjoin->u.syn.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_SYNACK: ++ mopt->saw_mpc = 1; ++ mopt->low_prio = mpjoin->b; ++ mopt->rem_id = mpjoin->addr_id; ++ mopt->mptcp_recv_tmac = mpjoin->u.synack.mac; ++ mopt->mptcp_recv_nonce = mpjoin->u.synack.nonce; ++ break; ++ case MPTCP_SUB_LEN_JOIN_ACK: ++ mopt->saw_mpc = 1; ++ mopt->join_ack = 1; ++ memcpy(mopt->mptcp_recv_mac, mpjoin->u.ack.mac, 20); ++ break; ++ } ++ break; ++ } ++ case MPTCP_SUB_DSS: ++ { ++ const struct mp_dss *mdss = (struct mp_dss *)ptr; ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ ++ /* We check opsize for the csum and non-csum case. We do this, ++ * because the draft says that the csum SHOULD be ignored if ++ * it has not been negotiated in the MP_CAPABLE but still is ++ * present in the data. ++ * ++ * It will get ignored later in mptcp_queue_skb. ++ */ ++ if (opsize != mptcp_sub_len_dss(mdss, 0) && ++ opsize != mptcp_sub_len_dss(mdss, 1)) { ++ mptcp_debug("%s: mp_dss: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ ptr += 4; ++ ++ if (mdss->A) { ++ tcb->mptcp_flags |= MPTCPHDR_ACK; ++ ++ if (mdss->a) { ++ mopt->data_ack = (u32) get_unaligned_be64(ptr); ++ ptr += MPTCP_SUB_LEN_ACK_64; ++ } else { ++ mopt->data_ack = get_unaligned_be32(ptr); ++ ptr += MPTCP_SUB_LEN_ACK; ++ } ++ } ++ ++ tcb->dss_off = (ptr - skb_transport_header(skb)); ++ ++ if (mdss->M) { ++ if (mdss->m) { ++ u64 data_seq64 = get_unaligned_be64(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ64_SET; ++ mopt->data_seq = (u32) data_seq64; ++ ++ ptr += 12; /* 64-bit dseq + subseq */ ++ } else { ++ mopt->data_seq = get_unaligned_be32(ptr); ++ ptr += 8; /* 32-bit dseq + subseq */ ++ } ++ mopt->data_len = get_unaligned_be16(ptr); ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ /* Is a check-sum present? */ ++ if (opsize == mptcp_sub_len_dss(mdss, 1)) ++ tcb->mptcp_flags |= MPTCPHDR_DSS_CSUM; ++ ++ /* DATA_FIN only possible with DSS-mapping */ ++ if (mdss->F) ++ tcb->mptcp_flags |= MPTCPHDR_FIN; ++ } ++ ++ break; ++ } ++ case MPTCP_SUB_ADD_ADDR: ++ { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ /* If tcp_sock is not available, MPTCP version can't be ++ * retrieved and ADD_ADDR opsize validation is not possible. ++ */ ++ if (!tp || !tp->mpcb) ++ break; ++ ++ if (!is_valid_addropt_opsize(tp->mpcb->mptcp_ver, ++ mpadd, opsize)) { ++ mptcp_debug("%s: mp_add_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ /* We have to manually parse the options if we got two of them. */ ++ if (mopt->saw_add_addr) { ++ mopt->more_add_addr = 1; ++ break; ++ } ++ mopt->saw_add_addr = 1; ++ mopt->add_addr_ptr = ptr; ++ break; ++ } ++ case MPTCP_SUB_REMOVE_ADDR: ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) { ++ mptcp_debug("%s: mp_remove_addr: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ if (mopt->saw_rem_addr) { ++ mopt->more_rem_addr = 1; ++ break; ++ } ++ mopt->saw_rem_addr = 1; ++ mopt->rem_addr_ptr = ptr; ++ break; ++ case MPTCP_SUB_PRIO: ++ { ++ const struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ if (opsize != MPTCP_SUB_LEN_PRIO && ++ opsize != MPTCP_SUB_LEN_PRIO_ADDR) { ++ mptcp_debug("%s: mp_prio: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->saw_low_prio = 1; ++ mopt->low_prio = mpprio->b; ++ ++ if (opsize == MPTCP_SUB_LEN_PRIO_ADDR) { ++ mopt->saw_low_prio = 2; ++ mopt->prio_addr_id = mpprio->addr_id; ++ } ++ break; ++ } ++ case MPTCP_SUB_FAIL: ++ if (opsize != MPTCP_SUB_LEN_FAIL) { ++ mptcp_debug("%s: mp_fail: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ mopt->mp_fail = 1; ++ break; ++ case MPTCP_SUB_FCLOSE: ++ if (opsize != MPTCP_SUB_LEN_FCLOSE) { ++ mptcp_debug("%s: mp_fclose: bad option size %d\n", ++ __func__, opsize); ++ break; ++ } ++ ++ mopt->mp_fclose = 1; ++ mopt->mptcp_sender_key = ((struct mp_fclose *)ptr)->key; ++ ++ break; ++ default: ++ mptcp_debug("%s: Received unkown subtype: %d\n", ++ __func__, mp_opt->sub); ++ break; ++ } ++} ++ ++/** Parse only MPTCP options */ ++void tcp_parse_mptcp_options(const struct sk_buff *skb, ++ struct mptcp_options_received *mopt) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ const unsigned char *ptr = (const unsigned char *)(th + 1); ++ ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) /* "silly options" */ ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP) ++ mptcp_parse_options(ptr - 2, opsize, mopt, skb, NULL); ++ } ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++} ++ ++bool mptcp_check_rtt(const struct tcp_sock *tp, int time) ++{ ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ u32 rtt_max = 0; ++ ++ /* In MPTCP, we take the max delay across all flows, ++ * in order to take into account meta-reordering buffers. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_recv(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->rcv_rtt_est.rtt_us) ++ rtt_max = tcp_sk(sk)->rcv_rtt_est.rtt_us; ++ } ++ if (time < (rtt_max >> 3) || !rtt_max) ++ return true; ++ ++ return false; ++} ++ ++static void mptcp_handle_add_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ union inet_addr addr; ++ sa_family_t family; ++ __be16 port = 0; ++ bool is_v4; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ is_v4 = mpadd->u_bit.v0.ipver == 4; ++ } else { ++ is_v4 = mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 || ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2; ++ ++ /* TODO: support ADD_ADDRv1 retransmissions */ ++ if (mpadd->u_bit.v1.echo) ++ return; ++ } ++ ++ if (is_v4) { ++ u8 hash_mac_check[SHA256_DIGEST_SIZE]; ++ __be16 hmacport = 0; ++ char *recv_hmac; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v4; ++ ++ recv_hmac = (char *)mpadd->u.v4.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v4.port); ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2) { ++ hmacport = mpadd->u.v4.port; ++ } ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, hash_mac_check, 3, ++ 1, (u8 *)&mpadd->addr_id, ++ 4, (u8 *)&mpadd->u.v4.addr.s_addr, ++ 2, (u8 *)&hmacport); ++ if (memcmp(&hash_mac_check[SHA256_DIGEST_SIZE - sizeof(u64)], recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v4: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR4_VER1 + 2)) ++ port = mpadd->u.v4.port; ++ family = AF_INET; ++ addr.in = mpadd->u.v4.addr; ++#if IS_ENABLED(CONFIG_IPV6) ++ } else { ++ u8 hash_mac_check[SHA256_DIGEST_SIZE]; ++ __be16 hmacport = 0; ++ char *recv_hmac; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ goto skip_hmac_v6; ++ ++ recv_hmac = (char *)mpadd->u.v6.mac; ++ if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1) { ++ recv_hmac -= sizeof(mpadd->u.v6.port); ++ } else if (mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2) { ++ hmacport = mpadd->u.v6.port; ++ } ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, hash_mac_check, 3, ++ 1, (u8 *)&mpadd->addr_id, ++ 16, (u8 *)&mpadd->u.v6.addr.s6_addr, ++ 2, (u8 *)&hmacport); ++ if (memcmp(&hash_mac_check[SHA256_DIGEST_SIZE - sizeof(u64)], recv_hmac, 8) != 0) ++ /* ADD_ADDR2 discarded */ ++ return; ++skip_hmac_v6: ++ if ((mpcb->mptcp_ver == MPTCP_VERSION_0 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6 + 2) || ++ (mpcb->mptcp_ver == MPTCP_VERSION_1 && ++ mpadd->len == MPTCP_SUB_LEN_ADD_ADDR6_VER1 + 2)) ++ port = mpadd->u.v6.port; ++ family = AF_INET6; ++ addr.in6 = mpadd->u.v6.addr; ++#endif /* CONFIG_IPV6 */ ++ } ++ ++ if (mpcb->pm_ops->add_raddr) ++ mpcb->pm_ops->add_raddr(mpcb, &addr, family, port, mpadd->addr_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRRX); ++} ++ ++static void mptcp_handle_rem_addr(const unsigned char *ptr, struct sock *sk) ++{ ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ int i; ++ u8 rem_id; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ for (i = 0; i <= mprem->len - MPTCP_SUB_LEN_REMOVE_ADDR; i++) { ++ rem_id = (&mprem->addrs_id)[i]; ++ ++ if (mpcb->pm_ops->rem_raddr) ++ mpcb->pm_ops->rem_raddr(mpcb, rem_id); ++ mptcp_send_reset_rem_id(mpcb, rem_id); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRSUB); ++ } ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_REMADDRRX); ++} ++ ++static void mptcp_parse_addropt(const struct sk_buff *skb, struct sock *sk) ++{ ++ struct tcphdr *th = tcp_hdr(skb); ++ unsigned char *ptr; ++ int length = (th->doff * 4) - sizeof(struct tcphdr); ++ ++ /* Jump through the options to check whether ADD_ADDR is there */ ++ ptr = (unsigned char *)(th + 1); ++ while (length > 0) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ return; ++ case TCPOPT_NOP: ++ length--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) ++ return; ++ if (opsize > length) ++ return; /* don't parse partial options */ ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_ADD_ADDR) { ++ u8 mptcp_ver = tcp_sk(sk)->mpcb->mptcp_ver; ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ ++ if (!is_valid_addropt_opsize(mptcp_ver, mpadd, ++ opsize)) ++ goto cont; ++ ++ mptcp_handle_add_addr(ptr, sk); ++ } ++ if (opcode == TCPOPT_MPTCP && ++ ((struct mptcp_option *)ptr)->sub == MPTCP_SUB_REMOVE_ADDR) { ++ if ((opsize - MPTCP_SUB_LEN_REMOVE_ADDR) < 0) ++ goto cont; ++ ++ mptcp_handle_rem_addr(ptr, sk); ++ } ++cont: ++ ptr += opsize - 2; ++ length -= opsize; ++ } ++ } ++ return; ++} ++ ++static bool mptcp_mp_fastclose_rcvd(struct sock *sk) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ if (likely(!mptcp->rx_opt.mp_fclose)) ++ return false; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FASTCLOSERX); ++ mptcp->rx_opt.mp_fclose = 0; ++ if (mptcp->rx_opt.mptcp_sender_key != mpcb->mptcp_loc_key) ++ return false; ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ tcp_reset(mptcp_meta_sk(sk)); ++ ++ return true; ++} ++ ++static void mptcp_mp_fail_rcvd(struct sock *sk, const struct tcphdr *th) ++{ ++ struct mptcp_tcp_sock *mptcp = tcp_sk(sk)->mptcp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX); ++ mptcp->rx_opt.mp_fail = 0; ++ ++ if (!th->rst && !mpcb->infinite_mapping_snd) { ++ mpcb->send_infinite_mapping = 1; ++ ++ mptcp_restart_sending(meta_sk); ++ ++ mptcp_fallback_close(mpcb, sk); ++ } ++} ++ ++static inline void mptcp_path_array_check(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ if (unlikely(mpcb->list_rcvd)) { ++ mpcb->list_rcvd = 0; ++ if (mpcb->pm_ops->new_remote_address) ++ mpcb->pm_ops->new_remote_address(meta_sk); ++ } ++} ++ ++bool mptcp_handle_options(struct sock *sk, const struct tcphdr *th, ++ const struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_options_received *mopt = &tp->mptcp->rx_opt; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ if (tp->mpcb->infinite_mapping_rcv || tp->mpcb->infinite_mapping_snd) ++ return false; ++ ++ if (mptcp_mp_fastclose_rcvd(sk)) ++ return true; ++ ++ if (sk->sk_state == TCP_RST_WAIT && !th->rst) ++ return true; ++ ++ if (mopt->saw_mpc && !tp->mpcb->rem_key_set) ++ mptcp_initialize_recv_vars(mptcp_meta_tp(tp), tp->mpcb, ++ mopt->mptcp_sender_key); ++ ++ if (unlikely(mopt->mp_fail)) ++ mptcp_mp_fail_rcvd(sk, th); ++ ++ /* RFC 6824, Section 3.3: ++ * If a checksum is not present when its use has been negotiated, the ++ * receiver MUST close the subflow with a RST as it is considered broken. ++ */ ++ if ((mptcp_is_data_seq(skb) || mptcp_is_data_mpcapable(skb)) && ++ tp->mpcb->dss_csum && ++ !(TCP_SKB_CB(skb)->mptcp_flags & MPTCPHDR_DSS_CSUM)) { ++ mptcp_send_reset(sk); ++ return true; ++ } ++ ++ /* We have to acknowledge retransmissions of the third ++ * ack. ++ */ ++ if (mopt->join_ack) { ++ tcp_send_delayed_ack(sk); ++ mopt->join_ack = 0; ++ } ++ ++ if (mopt->saw_add_addr || mopt->saw_rem_addr) { ++ if (mopt->more_add_addr || mopt->more_rem_addr) { ++ mptcp_parse_addropt(skb, sk); ++ } else { ++ if (mopt->saw_add_addr) ++ mptcp_handle_add_addr(mopt->add_addr_ptr, sk); ++ if (mopt->saw_rem_addr) ++ mptcp_handle_rem_addr(mopt->rem_addr_ptr, sk); ++ } ++ ++ mopt->more_add_addr = 0; ++ mopt->saw_add_addr = 0; ++ mopt->more_rem_addr = 0; ++ mopt->saw_rem_addr = 0; ++ } ++ if (mopt->saw_low_prio) { ++ if (mopt->saw_low_prio == 1) { ++ tp->mptcp->rcv_low_prio = mopt->low_prio; ++ if (mpcb->pm_ops->prio_changed) ++ mpcb->pm_ops->prio_changed(sk, mopt->low_prio); ++ } else { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ if (mptcp->rem_id == mopt->prio_addr_id) { ++ mptcp->rcv_low_prio = mopt->low_prio; ++ if (mpcb->pm_ops->prio_changed) ++ mpcb->pm_ops->prio_changed(sk, ++ mopt->low_prio); ++ } ++ } ++ } ++ mopt->saw_low_prio = 0; ++ } ++ ++ if (mptcp_process_data_ack(sk, skb)) ++ return true; ++ ++ mptcp_path_array_check(mptcp_meta_sk(sk)); ++ /* Socket may have been mp_killed by a REMOVE_ADDR */ ++ if (tp->mp_killed) ++ return true; ++ ++ return false; ++} ++ ++static void _mptcp_rcv_synsent_fastopen(struct sock *meta_sk, ++ struct sk_buff *skb, bool rtx_queue) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ u32 new_mapping = meta_tp->write_seq - master_tp->snd_una; ++ ++ /* If the server only acknowledges partially the data sent in ++ * the SYN, we need to trim the acknowledged part because ++ * we don't want to retransmit this already received data. ++ * When we reach this point, tcp_ack() has already cleaned up ++ * fully acked segments. However, tcp trims partially acked ++ * segments only when retransmitting. Since MPTCP comes into ++ * play only now, we will fake an initial transmit, and ++ * retransmit_skb() will not be called. The following fragment ++ * comes from __tcp_retransmit_skb(). ++ */ ++ if (before(TCP_SKB_CB(skb)->seq, master_tp->snd_una)) { ++ BUG_ON(before(TCP_SKB_CB(skb)->end_seq, ++ master_tp->snd_una)); ++ /* tcp_trim_head can only returns ENOMEM if skb is ++ * cloned. It is not the case here (see ++ * tcp_send_syn_data). ++ */ ++ BUG_ON(tcp_trim_head(meta_sk, skb, master_tp->snd_una - ++ TCP_SKB_CB(skb)->seq)); ++ } ++ ++ TCP_SKB_CB(skb)->seq += new_mapping; ++ TCP_SKB_CB(skb)->end_seq += new_mapping; ++ TCP_SKB_CB(skb)->sacked = 0; ++ ++ list_del(&skb->tcp_tsorted_anchor); ++ ++ if (rtx_queue) ++ tcp_rtx_queue_unlink(skb, meta_sk); ++ else ++ tcp_unlink_write_queue(skb, meta_sk); ++ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ ++ tcp_add_write_queue_tail(meta_sk, skb); ++} ++ ++/* In case of fastopen, some data can already be in the write queue. ++ * We need to update the sequence number of the segments as they ++ * were initially TCP sequence numbers. ++ */ ++static void mptcp_rcv_synsent_fastopen(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct tcp_sock *master_tp = tcp_sk(meta_tp->mpcb->master_sk); ++ struct sk_buff *skb_write_head, *skb_rtx_head, *tmp; ++ ++ skb_write_head = tcp_write_queue_head(meta_sk); ++ skb_rtx_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!(skb_write_head || skb_rtx_head)) ++ return; ++ ++ /* There should only be one skb in {write, rtx} queue: the data not ++ * acknowledged in the SYN+ACK. In this case, we need to map ++ * this data to data sequence numbers. ++ */ ++ ++ WARN_ON(skb_write_head && skb_rtx_head); ++ ++ if (skb_write_head) { ++ skb_queue_walk_from_safe(&meta_sk->sk_write_queue, ++ skb_write_head, tmp) { ++ _mptcp_rcv_synsent_fastopen(meta_sk, skb_write_head, ++ false); ++ } ++ } ++ ++ if (skb_rtx_head) { ++ skb_rbtree_walk_from_safe(skb_rtx_head, tmp) { ++ _mptcp_rcv_synsent_fastopen(meta_sk, skb_rtx_head, ++ true); ++ } ++ } ++ ++ /* We can advance write_seq by the number of bytes unacknowledged ++ * and that were mapped in the previous loop. ++ */ ++ meta_tp->write_seq += master_tp->write_seq - master_tp->snd_una; ++ ++ /* The packets from the master_sk will be entailed to it later ++ * Until that time, its write queue is empty, and ++ * write_seq must align with snd_una ++ */ ++ master_tp->snd_nxt = master_tp->write_seq = master_tp->snd_una; ++ master_tp->packets_out = 0; ++ tcp_clear_retrans(meta_tp); ++ tcp_clear_retrans(master_tp); ++ tcp_set_ca_state(meta_tp->mpcb->master_sk, TCP_CA_Open); ++ tcp_set_ca_state(meta_sk, TCP_CA_Open); ++} ++ ++/* The skptr is needed, because if we become MPTCP-capable, we have to switch ++ * from meta-socket to master-socket. ++ * ++ * @return: 1 - we want to reset this connection ++ * 2 - we want to discard the received syn/ack ++ * 0 - everything is fine - continue ++ */ ++int mptcp_rcv_synsent_state_process(struct sock *sk, struct sock **skptr, ++ const struct sk_buff *skb, ++ const struct mptcp_options_received *mopt) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (mptcp(tp)) { ++ u8 hash_mac_check[SHA256_DIGEST_SIZE]; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_rem_key, ++ (u8 *)&mpcb->mptcp_loc_key, hash_mac_check, 2, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce); ++ if (memcmp(hash_mac_check, ++ (char *)&tp->mptcp->rx_opt.mptcp_recv_tmac, 8)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKMAC); ++ mptcp_sub_force_close(sk); ++ return 1; ++ } ++ ++ /* Set this flag in order to postpone data sending ++ * until the 4th ack arrives. ++ */ ++ tp->mptcp->pre_established = 1; ++ tp->mptcp->rcv_low_prio = tp->mptcp->rx_opt.low_prio; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, ++ tp->mptcp->sender_mac, 2, ++ 4, (u8 *)&tp->mptcp->mptcp_loc_nonce, ++ 4, (u8 *)&tp->mptcp->rx_opt.mptcp_recv_nonce); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX); ++ } else if (mopt->saw_mpc) { ++ struct sock *meta_sk = sk; ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); ++ if (mopt->mptcp_ver > tcp_sk(sk)->mptcp_ver) ++ /* TODO Consider adding new MPTCP_INC_STATS entry */ ++ goto fallback; ++ if (tcp_sk(sk)->mptcp_ver == MPTCP_VERSION_1 && ++ mopt->mptcp_ver < MPTCP_VERSION_1) ++ /* TODO Consider adding new MPTCP_INC_STATS entry */ ++ /* TODO - record this in the cache - use v0 next time */ ++ goto fallback; ++ ++ if (mptcp_create_master_sk(sk, mopt->mptcp_sender_key, 1, ++ mopt->mptcp_ver, ++ ntohs(tcp_hdr(skb)->window))) ++ return 2; ++ ++ sk = tcp_sk(sk)->mpcb->master_sk; ++ *skptr = sk; ++ tp = tcp_sk(sk); ++ ++ /* If fastopen was used data might be in the send queue. We ++ * need to update their sequence number to MPTCP-level seqno. ++ * Note that it can happen in rare cases that fastopen_req is ++ * NULL and syn_data is 0 but fastopen indeed occurred and ++ * data has been queued in the write queue (but not sent). ++ * Example of such rare cases: connect is non-blocking and ++ * TFO is configured to work without cookies. ++ */ ++ mptcp_rcv_synsent_fastopen(meta_sk); ++ ++ /* -1, because the SYN consumed 1 byte. In case of TFO, we ++ * start the subflow-sequence number as if the data of the SYN ++ * is not part of any mapping. ++ */ ++ tp->mptcp->snt_isn = tp->snd_una - 1; ++ tp->mpcb->dss_csum = mopt->dss_csum; ++ if (tp->mpcb->dss_csum) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CSUMENABLED); ++ ++ if (tp->mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ tp->mpcb->send_mptcpv1_mpcapable = 1; ++ ++ tp->mptcp->include_mpc = 1; ++ ++ /* Ensure that fastopen is handled at the meta-level. */ ++ tp->fastopen_req = NULL; ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ bh_unlock_sock(sk); ++ /* hold in sk_clone_lock due to initialization to 2 */ ++ sock_put(sk); ++ } else { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEFALLBACK); ++fallback: ++ tp->request_mptcp = 0; ++ ++ if (tp->inside_tk_table) ++ mptcp_hash_remove_bh(tp); ++ } ++ ++ if (mptcp(tp)) ++ tp->mptcp->rcv_isn = TCP_SKB_CB(skb)->seq; ++ ++ return 0; ++} ++ ++/* Similar to tcp_should_expand_sndbuf */ ++bool mptcp_should_expand_sndbuf(const struct sock *sk) ++{ ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_tcp_sock *mptcp; ++ ++ /* We circumvent this check in tcp_check_space, because we want to ++ * always call sk_write_space. So, we reproduce the check here. ++ */ ++ if (!meta_sk->sk_socket || ++ !test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags)) ++ return false; ++ ++ /* If the user specified a specific send buffer setting, do ++ * not modify it. ++ */ ++ if (meta_sk->sk_userlocks & SOCK_SNDBUF_LOCK) ++ return false; ++ ++ /* If we are under global TCP memory pressure, do not expand. */ ++ if (tcp_under_memory_pressure(meta_sk)) ++ return false; ++ ++ /* If we are under soft global TCP memory pressure, do not expand. */ ++ if (sk_memory_allocated(meta_sk) >= sk_prot_mem_limits(meta_sk, 0)) ++ return false; ++ ++ /* For MPTCP we look for a subsocket that could send data. ++ * If we found one, then we update the send-buffer. ++ */ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ const struct sock *sk_it = mptcp_to_sock(mptcp); ++ const struct tcp_sock *tp_it = tcp_sk(sk_it); ++ ++ if (!mptcp_sk_can_send(sk_it)) ++ continue; ++ ++ if (tcp_packets_in_flight(tp_it) < tp_it->snd_cwnd) ++ return true; ++ } ++ ++ return false; ++} ++ ++void mptcp_tcp_set_rto(struct sock *sk) ++{ ++ tcp_set_rto(sk); ++ mptcp_set_rto(sk); ++} +diff -aurN linux-5.4.64/net/mptcp/mptcp_ipv4.c linux-5.4.64.mptcp/net/mptcp/mptcp_ipv4.c +--- linux-5.4.64/net/mptcp/mptcp_ipv4.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_ipv4.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,431 @@ ++/* ++ * MPTCP implementation - IPv4-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++u32 mptcp_v4_get_nonce(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) ++{ ++ return siphash_4u32((__force u32)saddr, (__force u32)daddr, ++ (__force u32)sport << 16 | (__force u32)dport, ++ mptcp_seed++, &mptcp_secret); ++} ++ ++u64 mptcp_v4_get_key(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, ++ u32 seed) ++{ ++ return siphash_2u64((__force u64)saddr << 32 | (__force u64)daddr, ++ (__force u64)seed << 32 | (__force u64)sport << 16 | (__force u64)dport, ++ &mptcp_secret); ++} ++ ++ ++static void mptcp_v4_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v4_reqsk_destructor(req); ++} ++ ++static int mptcp_v4_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv4_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v4_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v4_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++/* May be called without holding the meta-level lock */ ++static int mptcp_v4_join_init_req(struct request_sock *req, const struct sock *meta_sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ if (!mpcb->rem_key_set) ++ return -1; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv4_ops.init_req(req, meta_sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v4_get_nonce(ip_hdr(skb)->saddr, ++ ip_hdr(skb)->daddr, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.ip = inet_rsk(req)->ir_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(meta_sk, AF_INET, &addr, &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp_request_sock_ops */ ++struct request_sock_ops mptcp_request_sock_ops __read_mostly = { ++ .family = PF_INET, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v4_reqsk_send_ack, ++ .destructor = mptcp_v4_reqsk_destructor, ++ .send_reset = tcp_v4_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v4_conn_request ++ * May be called without holding the meta-level lock ++ */ ++static int mptcp_v4_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp_request_sock_ops, ++ &mptcp_join_request_sock_ipv4_ops, ++ meta_sk, skb); ++} ++ ++/* Similar to: tcp_v4_do_rcv ++ * We only process join requests here. (either the SYN or the final ACK) ++ */ ++int mptcp_v4_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct iphdr *iph = ip_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = inet_lookup_established(sock_net(meta_sk), &tcp_hashinfo, ++ iph->saddr, th->source, iph->daddr, ++ th->dest, inet_iif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ bool req_stolen; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false, &req_stolen); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v4_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v4_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v4_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v4_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv4 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int __mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, ++ __be16 sport, struct mptcp_rem4 *rem, ++ struct sock **subsk) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ ret = mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL); ++ if (ret) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ timer_setup(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, 0); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin_family = AF_INET; ++ rem_in.sin_family = AF_INET; ++ loc_in.sin_port = sport; ++ if (rem->port) ++ rem_in.sin_port = rem->port; ++ else ++ rem_in.sin_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin_addr = loc->addr; ++ rem_in.sin_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI4 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d ifidx: %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin_addr, ++ ntohs(loc_in.sin_port), &rem_in.sin_addr, ++ ntohs(rem_in.sin_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ if (subsk) ++ *subsk = sk; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(__mptcp_init4_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v4_specific = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v4_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ip_setsockopt, ++ .getsockopt = ip_getsockopt, ++ .addr2sockaddr = inet_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ip_setsockopt, ++ .compat_getsockopt = compat_ip_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv4_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv4_ops; ++ ++/* General initialization of IPv4 for MPTCP */ ++int mptcp_pm_v4_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp_request_sock_ops; ++ ++ mptcp_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_request_sock_ipv4_ops.init_req = mptcp_v4_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv4_ops.cookie_init_seq = mptcp_v4_cookie_init_seq; ++#endif ++ mptcp_join_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops; ++ mptcp_join_request_sock_ipv4_ops.init_req = mptcp_v4_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v4_undo(void) ++{ ++ kmem_cache_destroy(mptcp_request_sock_ops.slab); ++ kfree(mptcp_request_sock_ops.slab_name); ++} +diff -aurN linux-5.4.64/net/mptcp/mptcp_ipv6.c linux-5.4.64.mptcp/net/mptcp/mptcp_ipv6.c +--- linux-5.4.64/net/mptcp/mptcp_ipv6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_ipv6.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,479 @@ ++/* ++ * MPTCP implementation - IPv6-specific functions ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer: ++ * Jaakko Korkeaniemi ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__u32 mptcp_v6_get_nonce(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = mptcp_seed++, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++u64 mptcp_v6_get_key(const __be32 *saddr, const __be32 *daddr, ++ __be16 sport, __be16 dport, u32 seed) ++{ ++ const struct { ++ struct in6_addr saddr; ++ struct in6_addr daddr; ++ u32 seed; ++ __be16 sport; ++ __be16 dport; ++ } __aligned(SIPHASH_ALIGNMENT) combined = { ++ .saddr = *(struct in6_addr *)saddr, ++ .daddr = *(struct in6_addr *)daddr, ++ .seed = seed, ++ .sport = sport, ++ .dport = dport ++ }; ++ ++ return siphash(&combined, offsetofend(typeof(combined), dport), ++ &mptcp_secret); ++} ++ ++static void mptcp_v6_reqsk_destructor(struct request_sock *req) ++{ ++ mptcp_reqsk_destructor(req); ++ ++ tcp_v6_reqsk_destructor(req); ++} ++ ++static int mptcp_v6_init_req(struct request_sock *req, const struct sock *sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ tcp_request_sock_ipv6_ops.init_req(req, sk, skb, want_cookie); ++ ++ mptcp_rsk(req)->hash_entry.pprev = NULL; ++ mptcp_rsk(req)->is_sub = 0; ++ inet_rsk(req)->mptcp_rqsk = 1; ++ ++ /* In case of SYN-cookies, we wait for the isn to be generated - it is ++ * input to the key-generation. ++ */ ++ if (!want_cookie) ++ mptcp_reqsk_init(req, sk, skb, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SYN_COOKIES ++static u32 mptcp_v6_cookie_init_seq(struct request_sock *req, const struct sock *sk, ++ const struct sk_buff *skb, __u16 *mssp) ++{ ++ __u32 isn = cookie_v6_init_sequence(req, sk, skb, mssp); ++ ++ tcp_rsk(req)->snt_isn = isn; ++ ++ mptcp_reqsk_init(req, sk, skb, true); ++ ++ return isn; ++} ++#endif ++ ++/* May be called without holding the meta-level lock */ ++static int mptcp_v6_join_init_req(struct request_sock *req, const struct sock *meta_sk, ++ struct sk_buff *skb, bool want_cookie) ++{ ++ struct mptcp_request_sock *mtreq = mptcp_rsk(req); ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ union inet_addr addr; ++ int loc_id; ++ bool low_prio = false; ++ ++ if (!mpcb->rem_key_set) ++ return -1; ++ ++ /* We need to do this as early as possible. Because, if we fail later ++ * (e.g., get_local_id), then reqsk_free tries to remove the ++ * request-socket from the htb in mptcp_hash_request_remove as pprev ++ * may be different from NULL. ++ */ ++ mtreq->hash_entry.pprev = NULL; ++ ++ tcp_request_sock_ipv6_ops.init_req(req, meta_sk, skb, want_cookie); ++ ++ mtreq->mptcp_loc_nonce = mptcp_v6_get_nonce(ipv6_hdr(skb)->saddr.s6_addr32, ++ ipv6_hdr(skb)->daddr.s6_addr32, ++ tcp_hdr(skb)->source, ++ tcp_hdr(skb)->dest); ++ addr.in6 = inet_rsk(req)->ir_v6_loc_addr; ++ loc_id = mpcb->pm_ops->get_local_id(meta_sk, AF_INET6, &addr, &low_prio); ++ if (loc_id == -1) ++ return -1; ++ mtreq->loc_id = loc_id; ++ mtreq->low_prio = low_prio; ++ ++ mptcp_join_reqsk_init(mpcb, req, skb); ++ ++ return 0; ++} ++ ++/* Similar to tcp6_request_sock_ops */ ++struct request_sock_ops mptcp6_request_sock_ops __read_mostly = { ++ .family = AF_INET6, ++ .obj_size = sizeof(struct mptcp_request_sock), ++ .rtx_syn_ack = tcp_rtx_synack, ++ .send_ack = tcp_v6_reqsk_send_ack, ++ .destructor = mptcp_v6_reqsk_destructor, ++ .send_reset = tcp_v6_send_reset, ++ .syn_ack_timeout = tcp_syn_ack_timeout, ++}; ++ ++/* Similar to: tcp_v6_conn_request ++ * May be called without holding the meta-level lock ++ */ ++static int mptcp_v6_join_request(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ return tcp_conn_request(&mptcp6_request_sock_ops, ++ &mptcp_join_request_sock_ipv6_ops, ++ meta_sk, skb); ++} ++ ++int mptcp_v6_do_rcv(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ const struct tcphdr *th = tcp_hdr(skb); ++ const struct ipv6hdr *ip6h = ipv6_hdr(skb); ++ struct sock *child, *rsk = NULL, *sk; ++ int ret; ++ ++ sk = __inet6_lookup_established(sock_net(meta_sk), ++ &tcp_hashinfo, ++ &ip6h->saddr, th->source, ++ &ip6h->daddr, ntohs(th->dest), ++ tcp_v6_iif(skb), tcp_v6_sdif(skb)); ++ ++ if (!sk) ++ goto new_subflow; ++ ++ if (is_meta_sk(sk)) { ++ WARN("%s Did not find a sub-sk - did found the meta!\n", __func__); ++ sock_put(sk); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_TIME_WAIT) { ++ inet_twsk_put(inet_twsk(sk)); ++ goto discard; ++ } ++ ++ if (sk->sk_state == TCP_NEW_SYN_RECV) { ++ struct request_sock *req = inet_reqsk(sk); ++ bool req_stolen; ++ ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ local_bh_disable(); ++ child = tcp_check_req(meta_sk, skb, req, false, &req_stolen); ++ if (!child) { ++ reqsk_put(req); ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ local_bh_enable(); ++ goto reset_and_discard; ++ } ++ ++ bh_unlock_sock(meta_sk); ++ local_bh_enable(); ++ return 0; ++ } ++ ++ /* tcp_check_req failed */ ++ reqsk_put(req); ++ ++ local_bh_enable(); ++ goto discard; ++ } ++ ++ ret = tcp_v6_do_rcv(sk, skb); ++ sock_put(sk); ++ ++ return ret; ++ ++new_subflow: ++ if (!mptcp_can_new_subflow(meta_sk)) ++ goto reset_and_discard; ++ ++ child = tcp_v6_cookie_check(meta_sk, skb); ++ if (!child) ++ goto discard; ++ ++ if (child != meta_sk) { ++ ret = mptcp_finish_handshake(child, skb); ++ if (ret) { ++ rsk = child; ++ goto reset_and_discard; ++ } ++ } ++ ++ if (tcp_hdr(skb)->syn) { ++ local_bh_disable(); ++ mptcp_v6_join_request(meta_sk, skb); ++ local_bh_enable(); ++ } ++ ++discard: ++ kfree_skb(skb); ++ return 0; ++ ++reset_and_discard: ++ tcp_v6_send_reset(rsk, skb); ++ goto discard; ++} ++ ++/* Create a new IPv6 subflow. ++ * ++ * We are in user-context and meta-sock-lock is hold. ++ */ ++int __mptcp_init6_subsockets(struct sock *meta_sk, const struct mptcp_loc6 *loc, ++ __be16 sport, struct mptcp_rem6 *rem, ++ struct sock **subsk) ++{ ++ struct tcp_sock *tp; ++ struct sock *sk; ++ struct sockaddr_in6 loc_in, rem_in; ++ struct socket_alloc sock_full; ++ struct socket *sock = (struct socket *)&sock_full; ++ int ret; ++ ++ /** First, create and prepare the new socket */ ++ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); ++ sock->state = SS_UNCONNECTED; ++ sock->ops = NULL; ++ ++ ret = inet6_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); ++ if (unlikely(ret < 0)) { ++ net_err_ratelimited("%s inet6_create failed ret: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ sk = sock->sk; ++ tp = tcp_sk(sk); ++ ++ /* All subsockets need the MPTCP-lock-class */ ++ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); ++ lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ++ ++ ret = mptcp_add_sock(meta_sk, sk, loc->loc6_id, rem->rem6_id, GFP_KERNEL); ++ if (ret) { ++ net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ tp->mptcp->slave_sk = 1; ++ tp->mptcp->low_prio = loc->low_prio; ++ ++ /* Initializing the timer for an MPTCP subflow */ ++ timer_setup(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, 0); ++ ++ /** Then, connect the socket to the peer */ ++ loc_in.sin6_family = AF_INET6; ++ rem_in.sin6_family = AF_INET6; ++ loc_in.sin6_port = sport; ++ if (rem->port) ++ rem_in.sin6_port = rem->port; ++ else ++ rem_in.sin6_port = inet_sk(meta_sk)->inet_dport; ++ loc_in.sin6_addr = loc->addr; ++ rem_in.sin6_addr = rem->addr; ++ ++ if (loc->if_idx) ++ sk->sk_bound_dev_if = loc->if_idx; ++ ++ ret = kernel_bind(sock, (struct sockaddr *)&loc_in, ++ sizeof(struct sockaddr_in6)); ++ if (ret < 0) { ++ net_err_ratelimited("%s: token %#x bind() to %pI6 index %d failed, error %d\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ &loc_in.sin6_addr, loc->if_idx, ret); ++ goto error; ++ } ++ ++ mptcp_debug("%s: token %#x pi %d src_addr:%pI6:%d dst_addr:%pI6:%d ifidx: %u\n", ++ __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, ++ tp->mptcp->path_index, &loc_in.sin6_addr, ++ ntohs(loc_in.sin6_port), &rem_in.sin6_addr, ++ ntohs(rem_in.sin6_port), loc->if_idx); ++ ++ if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6) ++ tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v6(sk, rem->addr); ++ ++ ret = kernel_connect(sock, (struct sockaddr *)&rem_in, ++ sizeof(struct sockaddr_in6), O_NONBLOCK); ++ if (ret < 0 && ret != -EINPROGRESS) { ++ net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); ++ ++ sk_set_socket(sk, meta_sk->sk_socket); ++ sk->sk_wq = meta_sk->sk_wq; ++ ++ if (subsk) ++ *subsk = sk; ++ ++ return 0; ++ ++error: ++ /* May happen if mptcp_add_sock fails first */ ++ if (!mptcp(tp)) { ++ tcp_close(sk, 0); ++ } else { ++ local_bh_disable(); ++ mptcp_sub_force_close(sk); ++ local_bh_enable(); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(__mptcp_init6_subsockets); ++ ++const struct inet_connection_sock_af_ops mptcp_v6_specific = { ++ .queue_xmit = inet6_csk_xmit, ++ .send_check = tcp_v6_send_check, ++ .rebuild_header = inet6_sk_rebuild_header, ++ .sk_rx_dst_set = inet6_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct ipv6hdr), ++ .net_frag_header_len = sizeof(struct frag_hdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v6_mtu_reduced, ++}; ++ ++const struct inet_connection_sock_af_ops mptcp_v6_mapped = { ++ .queue_xmit = ip_queue_xmit, ++ .send_check = tcp_v4_send_check, ++ .rebuild_header = inet_sk_rebuild_header, ++ .sk_rx_dst_set = inet_sk_rx_dst_set, ++ .conn_request = mptcp_conn_request, ++ .syn_recv_sock = tcp_v6_syn_recv_sock, ++ .net_header_len = sizeof(struct iphdr), ++ .setsockopt = ipv6_setsockopt, ++ .getsockopt = ipv6_getsockopt, ++ .addr2sockaddr = inet6_csk_addr2sockaddr, ++ .sockaddr_len = sizeof(struct sockaddr_in6), ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_ipv6_setsockopt, ++ .compat_getsockopt = compat_ipv6_getsockopt, ++#endif ++ .mtu_reduced = tcp_v4_mtu_reduced, ++}; ++ ++struct tcp_request_sock_ops mptcp_request_sock_ipv6_ops; ++struct tcp_request_sock_ops mptcp_join_request_sock_ipv6_ops; ++ ++int mptcp_pm_v6_init(void) ++{ ++ int ret = 0; ++ struct request_sock_ops *ops = &mptcp6_request_sock_ops; ++ ++ mptcp_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_request_sock_ipv6_ops.init_req = mptcp_v6_init_req; ++#ifdef CONFIG_SYN_COOKIES ++ mptcp_request_sock_ipv6_ops.cookie_init_seq = mptcp_v6_cookie_init_seq; ++#endif ++ ++ mptcp_join_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops; ++ mptcp_join_request_sock_ipv6_ops.init_req = mptcp_v6_join_init_req; ++ ++ ops->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", "MPTCP6"); ++ if (ops->slab_name == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ops->slab = kmem_cache_create(ops->slab_name, ops->obj_size, 0, ++ SLAB_TYPESAFE_BY_RCU|SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ if (ops->slab == NULL) { ++ ret = -ENOMEM; ++ goto err_reqsk_create; ++ } ++ ++out: ++ return ret; ++ ++err_reqsk_create: ++ kfree(ops->slab_name); ++ ops->slab_name = NULL; ++ goto out; ++} ++ ++void mptcp_pm_v6_undo(void) ++{ ++ kmem_cache_destroy(mptcp6_request_sock_ops.slab); ++ kfree(mptcp6_request_sock_ops.slab_name); ++} +diff -aurN linux-5.4.64/net/mptcp/mptcp_ndiffports.c linux-5.4.64.mptcp/net/mptcp/mptcp_ndiffports.c +--- linux-5.4.64/net/mptcp/mptcp_ndiffports.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_ndiffports.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,174 @@ ++#include ++ ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct ndiffports_priv { ++ /* Worker struct for subflow establishment */ ++ struct work_struct subflow_work; ++ ++ struct mptcp_cb *mpcb; ++}; ++ ++static int num_subflows __read_mostly = 2; ++module_param(num_subflows, int, 0644); ++MODULE_PARM_DESC(num_subflows, "choose the number of subflows per MPTCP connection"); ++ ++/** ++ * Create all new subflows, by doing calls to mptcp_initX_subsockets ++ * ++ * This function uses a goto next_subflow, to allow releasing the lock between ++ * new subflows and giving other processes a chance to do some work on the ++ * socket and potentially finishing the communication. ++ **/ ++static void create_subflow_worker(struct work_struct *work) ++{ ++ const struct ndiffports_priv *pm_priv = container_of(work, ++ struct ndiffports_priv, ++ subflow_work); ++ struct mptcp_cb *mpcb = pm_priv->mpcb; ++ struct sock *meta_sk = mpcb->meta_sk; ++ int iter = 0; ++ ++next_subflow: ++ if (iter) { ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ ++ cond_resched(); ++ } ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (!mptcp(tcp_sk(meta_sk))) ++ goto exit; ++ ++ iter++; ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) ++ goto exit; ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) ++ goto exit; ++ ++ if (num_subflows > iter && num_subflows > mptcp_subflow_count(mpcb)) { ++ if (meta_sk->sk_family == AF_INET || ++ mptcp_v6_is_v4_mapped(meta_sk)) { ++ struct mptcp_loc4 loc; ++ struct mptcp_rem4 rem; ++ ++ loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr; ++ loc.loc4_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem4_id = 0; /* Default 0 */ ++ ++ mptcp_init4_subsockets(meta_sk, &loc, &rem); ++ } else { ++#if IS_ENABLED(CONFIG_IPV6) ++ struct mptcp_loc6 loc; ++ struct mptcp_rem6 rem; ++ ++ loc.addr = inet6_sk(meta_sk)->saddr; ++ loc.loc6_id = 0; ++ loc.low_prio = 0; ++ if (mpcb->master_sk) ++ loc.if_idx = mpcb->master_sk->sk_bound_dev_if; ++ else ++ loc.if_idx = 0; ++ ++ rem.addr = meta_sk->sk_v6_daddr; ++ rem.port = inet_sk(meta_sk)->inet_dport; ++ rem.rem6_id = 0; /* Default 0 */ ++ ++ mptcp_init6_subsockets(meta_sk, &loc, &rem); ++#endif ++ } ++ goto next_subflow; ++ } ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ mptcp_mpcb_put(mpcb); ++ sock_put(meta_sk); ++} ++ ++static void ndiffports_new_session(const struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *fmp = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ /* Initialize workqueue-struct */ ++ INIT_WORK(&fmp->subflow_work, create_subflow_worker); ++ fmp->mpcb = mpcb; ++} ++ ++static void ndiffports_create_subflows(struct sock *meta_sk) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct ndiffports_priv *pm_priv = (struct ndiffports_priv *)&mpcb->mptcp_pm[0]; ++ ++ if (mptcp_in_infinite_mapping_weak(mpcb) || ++ mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD)) ++ return; ++ ++ if (!work_pending(&pm_priv->subflow_work)) { ++ sock_hold(meta_sk); ++ refcount_inc(&mpcb->mpcb_refcnt); ++ queue_work(mptcp_wq, &pm_priv->subflow_work); ++ } ++} ++ ++static int ndiffports_get_local_id(const struct sock *meta_sk, ++ sa_family_t family, union inet_addr *addr, ++ bool *low_prio) ++{ ++ return 0; ++} ++ ++static struct mptcp_pm_ops ndiffports __read_mostly = { ++ .new_session = ndiffports_new_session, ++ .fully_established = ndiffports_create_subflows, ++ .get_local_id = ndiffports_get_local_id, ++ .name = "ndiffports", ++ .owner = THIS_MODULE, ++}; ++ ++/* General initialization of MPTCP_PM */ ++static int __init ndiffports_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct ndiffports_priv) > MPTCP_PM_SIZE); ++ ++ if (mptcp_register_path_manager(&ndiffports)) ++ goto exit; ++ ++ return 0; ++ ++exit: ++ return -1; ++} ++ ++static void ndiffports_unregister(void) ++{ ++ mptcp_unregister_path_manager(&ndiffports); ++} ++ ++module_init(ndiffports_register); ++module_exit(ndiffports_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("NDIFF-PORTS MPTCP"); ++MODULE_VERSION("0.88"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_netlink.c linux-5.4.64.mptcp/net/mptcp/mptcp_netlink.c +--- linux-5.4.64/net/mptcp/mptcp_netlink.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_netlink.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,1271 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* MPTCP implementation - Netlink Path Manager ++ * ++ * Analysis, Design and Implementation: ++ * - Gregory Detal ++ * - Sébastien Barré ++ * - Matthieu Baerts ++ * - Pau Espin Pedrol ++ * - Detlev Casanova ++ * - David Verbeiren ++ * - Frank Vanbever ++ * - Antoine Maes ++ * - Tim Froidcoeur ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++#define MPTCP_MAX_ADDR 8 ++ ++struct mptcp_nl_priv { ++ /* Unfortunately we need to store this to generate MP_JOINs in case ++ * of the peer generating a subflow (see get_local_id). ++ */ ++ u8 loc4_bits; ++ u8 announced4; ++ struct mptcp_loc4 locaddr4[MPTCP_MAX_ADDR]; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ u8 loc6_bits; ++ u8 announced6; ++ struct mptcp_loc6 locaddr6[MPTCP_MAX_ADDR]; ++#endif ++ ++ u16 remove_addrs; ++ ++ bool is_closed; ++}; ++ ++static struct genl_family mptcp_genl_family; ++ ++#define MPTCP_GENL_EV_GRP_OFFSET 0 ++#define MPTCP_GENL_CMD_GRP_OFFSET 1 ++ ++static const struct genl_multicast_group mptcp_mcgrps[] = { ++ [MPTCP_GENL_EV_GRP_OFFSET] = { .name = MPTCP_GENL_EV_GRP_NAME, }, ++ [MPTCP_GENL_CMD_GRP_OFFSET] = { .name = MPTCP_GENL_CMD_GRP_NAME, }, ++}; ++ ++static const struct nla_policy mptcp_nl_genl_policy[MPTCP_ATTR_MAX + 1] = { ++ [MPTCP_ATTR_TOKEN] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_FAMILY] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_LOC_ID] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_REM_ID] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_SADDR4] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_SADDR6] = { .type = NLA_BINARY, ++ .len = sizeof(struct in6_addr), }, ++ [MPTCP_ATTR_DADDR4] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_DADDR6] = { .type = NLA_BINARY, ++ .len = sizeof(struct in6_addr), }, ++ [MPTCP_ATTR_SPORT] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_DPORT] = { .type = NLA_U16, }, ++ [MPTCP_ATTR_BACKUP] = { .type = NLA_U8, }, ++ [MPTCP_ATTR_TIMEOUT] = { .type = NLA_U32, }, ++ [MPTCP_ATTR_IF_IDX] = { .type = NLA_S32, }, ++}; ++ ++/* Defines the userspace PM filter on events. Set events are ignored. */ ++static u16 mptcp_nl_event_filter; ++ ++static inline struct mptcp_nl_priv * ++mptcp_nl_priv(const struct sock *meta_sk) ++{ ++ return (struct mptcp_nl_priv *)&tcp_sk(meta_sk)->mpcb->mptcp_pm[0]; ++} ++ ++static inline bool ++mptcp_nl_must_notify(u16 event, const struct sock *meta_sk) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ ++ /* close_session() can be called before other events because it is ++ * also called when doing a fallback to TCP. We don't want to send ++ * events to the user-space after having sent the CLOSED event. ++ */ ++ if (priv->is_closed) ++ return false; ++ ++ if (event == MPTCPF_EVENT_CLOSED) ++ priv->is_closed = true; ++ ++ if (mptcp_nl_event_filter & event) ++ return false; ++ ++ if (!genl_has_listeners(&mptcp_genl_family, sock_net(meta_sk), 0)) ++ return false; ++ ++ return true; ++} ++ ++/* Find the first free index in the bitfield starting from 0 */ ++static int ++mptcp_nl_find_free_index(u8 bitfield) ++{ ++ int i; ++ ++ /* There are anyways no free bits... */ ++ if (bitfield == 0xff) ++ return -1; ++ ++ i = ffs(~bitfield) - 1; ++ if (i < 0) ++ return -1; ++ ++ return i; ++} ++ ++static inline int ++mptcp_nl_put_subsk(struct sk_buff *msg, struct sock *sk) ++{ ++ struct inet_sock *isk = inet_sk(sk); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ u8 backup; ++ u8 sk_err; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_FAMILY, sk->sk_family)) ++ goto nla_put_failure; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_LOC_ID, tcp_sk(sk)->mptcp->loc_id)) ++ goto nla_put_failure; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, tcp_sk(sk)->mptcp->rem_id)) ++ goto nla_put_failure; ++ ++ switch (sk->sk_family) { ++ case AF_INET: ++ if (nla_put_u32(msg, MPTCP_ATTR_SADDR4, isk->inet_saddr)) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, MPTCP_ATTR_DADDR4, isk->inet_daddr)) ++ goto nla_put_failure; ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ if (nla_put(msg, MPTCP_ATTR_SADDR6, sizeof(np->saddr), ++ &np->saddr)) ++ goto nla_put_failure; ++ ++ if (nla_put(msg, MPTCP_ATTR_DADDR6, sizeof(sk->sk_v6_daddr), ++ &sk->sk_v6_daddr)) ++ goto nla_put_failure; ++ break; ++ } ++#endif ++ default: ++ goto nla_put_failure; ++ } ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_SPORT, ntohs(isk->inet_sport))) ++ goto nla_put_failure; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_DPORT, ntohs(isk->inet_dport))) ++ goto nla_put_failure; ++ ++ backup = !!(tcp_sk(sk)->mptcp->rcv_low_prio || ++ tcp_sk(sk)->mptcp->low_prio); ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_BACKUP, backup)) ++ goto nla_put_failure; ++ ++ if (nla_put_s32(msg, MPTCP_ATTR_IF_IDX, sk->sk_bound_dev_if)) ++ goto nla_put_failure; ++ ++ sk_err = sk->sk_err ? : tcp_sk(sk)->mptcp->sk_err; ++ if (unlikely(sk_err != 0) && meta_sk->sk_state == TCP_ESTABLISHED && ++ nla_put_u8(msg, MPTCP_ATTR_ERROR, sk_err)) ++ goto nla_put_failure; ++ ++ return 0; ++ ++nla_put_failure: ++ return -1; ++} ++ ++static inline struct sk_buff * ++mptcp_nl_mcast_prepare(struct mptcp_cb *mpcb, struct sock *sk, int cmd, ++ void **hdr) ++{ ++ struct sk_buff *msg; ++ ++ /* possible optimisation: use the needed size */ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); ++ if (!msg) ++ return NULL; ++ ++ *hdr = genlmsg_put(msg, 0, 0, &mptcp_genl_family, 0, cmd); ++ if (!*hdr) ++ goto free_msg; ++ ++ if (nla_put_u32(msg, MPTCP_ATTR_TOKEN, mpcb->mptcp_loc_token)) ++ goto nla_put_failure; ++ ++ if (sk && mptcp_nl_put_subsk(msg, sk)) ++ goto nla_put_failure; ++ ++ return msg; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, *hdr); ++free_msg: ++ nlmsg_free(msg); ++ return NULL; ++} ++ ++static inline int ++mptcp_nl_mcast_send(struct mptcp_cb *mpcb, struct sk_buff *msg, void *hdr) ++{ ++ int ret; ++ struct sock *meta_sk = mpcb->meta_sk; ++ ++ genlmsg_end(msg, hdr); ++ ++ ret = genlmsg_multicast_netns(&mptcp_genl_family, sock_net(meta_sk), ++ msg, 0, MPTCP_GENL_EV_GRP_OFFSET, ++ GFP_ATOMIC); ++ if (ret && ret != -ESRCH) ++ pr_err("%s: genlmsg_multicast failed with %d\n", __func__, ret); ++ return ret; ++} ++ ++static inline void ++mptcp_nl_mcast(struct mptcp_cb *mpcb, struct sock *sk, int cmd) ++{ ++ void *hdr; ++ struct sk_buff *msg; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, sk, cmd, &hdr); ++ if (msg) ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ else ++ pr_warn("%s: unable to prepare multicast message\n", __func__); ++} ++ ++static inline void ++mptcp_nl_mcast_fail(struct sk_buff *msg, void *hdr) ++{ ++ genlmsg_cancel(msg, hdr); ++ nlmsg_free(msg); ++} ++ ++static void ++mptcp_nl_new(const struct sock *meta_sk, bool established) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mptcp_nl_mcast(mpcb, mpcb->master_sk, ++ established ? MPTCP_EVENT_ESTABLISHED ++ : MPTCP_EVENT_CREATED); ++} ++ ++static void ++mptcp_nl_pm_new_session(const struct sock *meta_sk) ++{ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_CREATED, meta_sk)) ++ return; ++ ++ mptcp_nl_new(meta_sk, false); ++} ++ ++static inline int ++mptcp_nl_loc_id_to_index_lookup(struct sock *meta_sk, sa_family_t family, ++ u8 addr_id) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ int i; ++ ++ switch (family) { ++ case AF_INET: ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == addr_id) ++ return i; ++ } ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == addr_id) ++ return i; ++ } ++ break; ++#endif ++ } ++ return -1; ++} ++ ++static inline void ++mptcp_nl_sk_setup_locaddr(struct sock *meta_sk, struct sock *sk) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ bool backup = !!(tcp_sk(sk)->mptcp->rcv_low_prio || ++ tcp_sk(sk)->mptcp->low_prio); ++ sa_family_t family = mptcp_v6_is_v4_mapped(sk) ? AF_INET ++ : sk->sk_family; ++ u8 addr_id = tcp_sk(sk)->mptcp->loc_id; ++ int idx = mptcp_nl_loc_id_to_index_lookup(meta_sk, family, ++ addr_id); ++ ++ /* Same as in mptcp_fullmesh.c: exception for transparent sockets */ ++ int if_idx = inet_sk(sk)->transparent ? inet_sk(sk)->rx_dst_ifindex : ++ sk->sk_bound_dev_if; ++ ++ switch (family) { ++ case AF_INET: { ++ struct inet_sock *isk = inet_sk(sk); ++ ++ if (idx == -1) ++ idx = mptcp_nl_find_free_index(priv->loc4_bits); ++ if (idx == -1) { ++ pr_warn("No free index for sk loc_id v4\n"); ++ return; ++ } ++ priv->locaddr4[idx].addr.s_addr = isk->inet_saddr; ++ priv->locaddr4[idx].loc4_id = addr_id; ++ priv->locaddr4[idx].low_prio = backup; ++ priv->locaddr4[idx].if_idx = if_idx; ++ priv->loc4_bits |= 1 << idx; ++ priv->announced4 |= 1 << idx; ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ if (idx == -1) ++ idx = mptcp_nl_find_free_index(priv->loc6_bits); ++ if (idx == -1) { ++ pr_warn("No free index for sk loc_id v6\n"); ++ return; ++ } ++ priv->locaddr6[idx].addr = np->saddr; ++ priv->locaddr6[idx].loc6_id = addr_id; ++ priv->locaddr6[idx].low_prio = backup; ++ priv->locaddr6[idx].if_idx = if_idx; ++ priv->loc6_bits |= 1 << idx; ++ priv->announced6 |= 1 << idx; ++ break; ++ } ++#endif ++ } ++} ++ ++static void ++mptcp_nl_pm_fully_established(struct sock *meta_sk) ++{ ++ mptcp_nl_sk_setup_locaddr(meta_sk, tcp_sk(meta_sk)->mpcb->master_sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_ESTABLISHED, meta_sk)) ++ return; ++ ++ mptcp_nl_new(meta_sk, true); ++} ++ ++static void ++mptcp_nl_pm_close_session(struct sock *meta_sk) ++{ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_CLOSED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, NULL, MPTCP_EVENT_CLOSED); ++} ++ ++static void ++mptcp_nl_pm_established_subflow(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ mptcp_nl_sk_setup_locaddr(meta_sk, sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_ESTABLISHED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_ESTABLISHED); ++} ++ ++static void ++mptcp_nl_pm_delete_subflow(struct sock *sk) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_CLOSED, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_CLOSED); ++} ++ ++static void ++mptcp_nl_pm_add_raddr(struct mptcp_cb *mpcb, const union inet_addr *addr, ++ sa_family_t family, __be16 port, u8 id) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_ANNOUNCED, mpcb->meta_sk)) ++ return; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, NULL, MPTCP_EVENT_ANNOUNCED, &hdr); ++ if (!msg) ++ return; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, id)) ++ goto nla_put_failure; ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_FAMILY, family)) ++ goto nla_put_failure; ++ ++ switch (family) { ++ case AF_INET: ++ if (nla_put_u32(msg, MPTCP_ATTR_DADDR4, addr->ip)) ++ goto nla_put_failure; ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ if (nla_put(msg, MPTCP_ATTR_DADDR6, sizeof(addr->ip6), ++ &addr->ip6)) ++ goto nla_put_failure; ++ break; ++#endif ++ default: ++ goto nla_put_failure; ++ } ++ ++ if (nla_put_u16(msg, MPTCP_ATTR_DPORT, ntohs(port))) ++ goto nla_put_failure; ++ ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ ++ return; ++ ++nla_put_failure: ++ mptcp_nl_mcast_fail(msg, hdr); ++} ++ ++static void ++mptcp_nl_pm_rem_raddr(struct mptcp_cb *mpcb, u8 id) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_REMOVED, mpcb->meta_sk)) ++ return; ++ ++ msg = mptcp_nl_mcast_prepare(mpcb, NULL, MPTCP_EVENT_REMOVED, &hdr); ++ ++ if (!msg) ++ return; ++ ++ if (nla_put_u8(msg, MPTCP_ATTR_REM_ID, id)) ++ goto nla_put_failure; ++ ++ mptcp_nl_mcast_send(mpcb, msg, hdr); ++ ++ return; ++ ++nla_put_failure: ++ mptcp_nl_mcast_fail(msg, hdr); ++} ++ ++static int ++mptcp_nl_pm_get_local_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(meta_sk); ++ int i, id = 0; ++ ++ switch (family) { ++ case AF_INET: ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (addr->in.s_addr == priv->locaddr4[i].addr.s_addr) { ++ id = priv->locaddr4[i].loc4_id; ++ *low_prio = priv->locaddr4[i].low_prio; ++ goto out; ++ } ++ } ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (ipv6_addr_equal(&addr->in6, ++ &priv->locaddr6[i].addr)) { ++ id = priv->locaddr6[i].loc6_id; ++ *low_prio = priv->locaddr6[i].low_prio; ++ goto out; ++ } ++ } ++ break; ++#endif ++ } ++ return -1; ++ ++out: ++ return id; ++} ++ ++static void ++mptcp_nl_pm_addr_signal(struct sock *sk, unsigned *size, ++ struct tcp_out_options *opts, struct sk_buff *skb) ++{ ++ struct mptcp_nl_priv *priv = mptcp_nl_priv(sk); ++ struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ u8 unannounced; ++ int remove_addr_len; ++ ++ unannounced = (~priv->announced4) & priv->loc4_bits; ++ if (unannounced && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) { ++ int i = mptcp_nl_find_free_index(~unannounced); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = priv->locaddr4[i].loc4_id; ++ opts->add_addr4.addr = priv->locaddr4[i].addr; ++ opts->add_addr_v4 = 1; ++ ++ if (skb) ++ priv->announced4 |= (1 << i); ++ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ unannounced = (~priv->announced6) & priv->loc6_bits; ++ if (unannounced && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) { ++ int i = mptcp_nl_find_free_index(~unannounced); ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = priv->locaddr6[i].loc6_id; ++ opts->add_addr6.addr = priv->locaddr6[i].addr; ++ opts->add_addr_v6 = 1; ++ ++ if (skb) ++ priv->announced6 |= (1 << i); ++ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ } ++#endif ++ ++ if (likely(!priv->remove_addrs)) ++ goto exit; ++ ++ remove_addr_len = mptcp_sub_len_remove_addr_align(priv->remove_addrs); ++ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) ++ goto exit; ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = priv->remove_addrs; ++ ++ if (skb) ++ priv->remove_addrs = 0; ++ *size += remove_addr_len; ++ ++exit: ++ mpcb->addr_signal = !!((~priv->announced4) & priv->loc4_bits || ++#if IS_ENABLED(CONFIG_IPV6) ++ (~priv->announced6) & priv->loc6_bits || ++#endif ++ priv->remove_addrs); ++} ++ ++static void ++mptcp_nl_pm_prio_changed(struct sock *sk, int low_prio) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ if (!mptcp_nl_must_notify(MPTCPF_EVENT_SUB_PRIORITY, meta_sk)) ++ return; ++ ++ mptcp_nl_mcast(tcp_sk(meta_sk)->mpcb, sk, MPTCP_EVENT_SUB_PRIORITY); ++} ++ ++static int ++mptcp_nl_genl_announce(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u8 addr_id, backup = 0; ++ u16 family; ++ int i, ret = 0; ++ union inet_addr saddr; ++ int if_idx = 0; ++ bool useless; /* unused out parameter "low_prio" */ ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_FAMILY] || ++ !info->attrs[MPTCP_ATTR_LOC_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ priv = mptcp_nl_priv(meta_sk); ++ family = nla_get_u16(info->attrs[MPTCP_ATTR_FAMILY]); ++ addr_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ ++ if (info->attrs[MPTCP_ATTR_BACKUP]) ++ backup = nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]); ++ ++ if (info->attrs[MPTCP_ATTR_IF_IDX]) ++ if_idx = nla_get_s32(info->attrs[MPTCP_ATTR_IF_IDX]); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ switch (family) { ++ case AF_INET: ++ if (!info->attrs[MPTCP_ATTR_SADDR4]) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ saddr.in.s_addr = nla_get_u32(info->attrs[MPTCP_ATTR_SADDR4]); ++ i = mptcp_nl_pm_get_local_id(meta_sk, family, ++ &saddr, &useless); ++ if (i < 0) { ++ i = mptcp_nl_find_free_index(priv->loc4_bits); ++ if (i < 0) { ++ ret = -ENOBUFS; ++ goto exit; ++ } ++ } else if (i != addr_id) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv->locaddr4[i].addr.s_addr = saddr.in.s_addr; ++ priv->locaddr4[i].loc4_id = addr_id; ++ priv->locaddr4[i].low_prio = !!backup; ++ priv->locaddr4[i].if_idx = if_idx; ++ priv->loc4_bits |= 1 << i; ++ priv->announced4 &= ~(1 << i); ++ break; ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: ++ if (!info->attrs[MPTCP_ATTR_SADDR6]) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ saddr.in6 = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_SADDR6]); ++ i = mptcp_nl_pm_get_local_id(meta_sk, family, &saddr, &useless); ++ if (i < 0) { ++ i = mptcp_nl_find_free_index(priv->loc6_bits); ++ if (i < 0) { ++ ret = -ENOBUFS; ++ goto exit; ++ } ++ } else if (i != addr_id) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv->locaddr6[i].addr = saddr.in6; ++ priv->locaddr6[i].loc6_id = addr_id; ++ priv->locaddr6[i].low_prio = !!backup; ++ priv->locaddr6[i].if_idx = if_idx; ++ priv->loc6_bits |= 1 << i; ++ priv->announced6 &= ~(1 << i); ++ break; ++#endif ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ mpcb->addr_signal = 1; ++ ++ rcu_read_lock_bh(); ++ subsk = mptcp_select_ack_sock(meta_sk); ++ if (subsk) ++ tcp_send_ack(subsk); ++ rcu_read_unlock_bh(); ++ ++exit: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_remove(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u8 addr_id; ++ int i; ++ int retcode; ++ bool found = false; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_LOC_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ priv = mptcp_nl_priv(meta_sk); ++ addr_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == addr_id) { ++ priv->loc4_bits &= ~(1 << i); ++ found = true; ++ break; ++ } ++ } ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (!found) { ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == addr_id) { ++ priv->loc6_bits &= ~(1 << i); ++ found = true; ++ break; ++ } ++ } ++ } ++#endif ++ ++ if (found) { ++ priv->remove_addrs |= 1 << addr_id; ++ mpcb->addr_signal = 1; ++ ++ rcu_read_lock_bh(); ++ subsk = mptcp_select_ack_sock(meta_sk); ++ if (subsk) ++ tcp_send_ack(subsk); ++ rcu_read_unlock_bh(); ++ retcode = 0; ++ } else { ++ retcode = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return retcode; ++} ++ ++static int ++mptcp_nl_genl_create(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk = NULL; ++ struct mptcp_cb *mpcb; ++ struct mptcp_nl_priv *priv; ++ u32 token; ++ u16 family, sport; ++ u8 loc_id, rem_id, backup = 0; ++ int i, ret = 0; ++ int if_idx; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN] || !info->attrs[MPTCP_ATTR_FAMILY] || ++ !info->attrs[MPTCP_ATTR_LOC_ID] || !info->attrs[MPTCP_ATTR_REM_ID]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ /* We use a more specific value than EINVAL here so that ++ * userspace can handle this specific case easily. This is ++ * useful to check the case in which userspace tries to create a ++ * subflow for a connection which was already destroyed recently ++ * in kernelspace, but userspace didn't have time to realize ++ * about it because there is a gap of time between kernel ++ * destroying the connection and userspace receiving the event ++ * through Netlink. It can easily happen for short life-time ++ * conns. ++ */ ++ return -EBADR; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ if (sock_flag(meta_sk, SOCK_DEAD)) { ++ /* Same as for the EBADR case. In this case, though, we know for ++ * sure the conn owner of the subflow existed at some point (no ++ * invalid token possibility) ++ */ ++ ret = -EOWNERDEAD; ++ goto unlock; ++ } ++ ++ if (!mptcp_can_new_subflow(meta_sk)) { ++ /* Same as for the EBADR and EOWNERDEAD case but here, the MPTCP ++ * session has just been stopped, it is no longer possible to ++ * create new subflows. ++ */ ++ ret = -ENOTCONN; ++ goto unlock; ++ } ++ ++ if (mpcb->master_sk && ++ !tcp_sk(mpcb->master_sk)->mptcp->fully_established) { ++ /* First condition is not only in there for safely purposes, it ++ * can also be triggered in the same scenario as in EBADR and ++ * EOWNERDEAD ++ */ ++ ret = -EAGAIN; ++ goto unlock; ++ } ++ ++ priv = mptcp_nl_priv(meta_sk); ++ ++ family = nla_get_u16(info->attrs[MPTCP_ATTR_FAMILY]); ++ loc_id = nla_get_u8(info->attrs[MPTCP_ATTR_LOC_ID]); ++ rem_id = nla_get_u8(info->attrs[MPTCP_ATTR_REM_ID]); ++ ++ sport = info->attrs[MPTCP_ATTR_SPORT] ++ ? htons(nla_get_u16(info->attrs[MPTCP_ATTR_SPORT])) : 0; ++ backup = info->attrs[MPTCP_ATTR_BACKUP] ++ ? nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]) : 0; ++ if_idx = info->attrs[MPTCP_ATTR_IF_IDX] ++ ? nla_get_s32(info->attrs[MPTCP_ATTR_IF_IDX]) : 0; ++ ++ switch (family) { ++ case AF_INET: { ++ struct mptcp_rem4 rem = { ++ .rem4_id = rem_id, ++ }; ++ struct mptcp_loc4 loc = { ++ .loc4_id = loc_id, ++ }; ++ ++ if (!info->attrs[MPTCP_ATTR_DADDR4] || ++ !info->attrs[MPTCP_ATTR_DPORT]) { ++ goto create_failed; ++ } else { ++ rem.addr.s_addr = ++ nla_get_u32(info->attrs[MPTCP_ATTR_DADDR4]); ++ rem.port = ++ ntohs(nla_get_u16(info->attrs[MPTCP_ATTR_DPORT])); ++ } ++ ++ if (!info->attrs[MPTCP_ATTR_SADDR4]) { ++ bool found = false; ++ ++ mptcp_for_each_bit_set(priv->loc4_bits, i) { ++ if (priv->locaddr4[i].loc4_id == loc_id) { ++ loc.addr = priv->locaddr4[i].addr; ++ loc.low_prio = ++ priv->locaddr4[i].low_prio; ++ loc.if_idx = ++ priv->locaddr4[i].if_idx; ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto create_failed; ++ } else { ++ loc.addr.s_addr = ++ nla_get_u32(info->attrs[MPTCP_ATTR_SADDR4]); ++ loc.low_prio = backup; ++ loc.if_idx = if_idx; ++ } ++ ++ ret = __mptcp_init4_subsockets(meta_sk, &loc, sport, &rem, ++ &subsk); ++ if (ret < 0) ++ goto unlock; ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct mptcp_rem6 rem = { ++ .rem6_id = rem_id, ++ }; ++ struct mptcp_loc6 loc = { ++ .loc6_id = loc_id, ++ }; ++ ++ if (!info->attrs[MPTCP_ATTR_DADDR6] || ++ !info->attrs[MPTCP_ATTR_DPORT]) { ++ goto create_failed; ++ } else { ++ rem.addr = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_DADDR6]); ++ rem.port = ++ ntohs(nla_get_u16(info->attrs[MPTCP_ATTR_DPORT])); ++ } ++ ++ if (!info->attrs[MPTCP_ATTR_SADDR6]) { ++ bool found = false; ++ ++ mptcp_for_each_bit_set(priv->loc6_bits, i) { ++ if (priv->locaddr6[i].loc6_id == loc_id) { ++ loc.addr = priv->locaddr6[i].addr; ++ loc.low_prio = ++ priv->locaddr6[i].low_prio; ++ loc.if_idx = ++ priv->locaddr6[i].if_idx; ++ ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto create_failed; ++ } else { ++ loc.addr = *(struct in6_addr *) ++ nla_data(info->attrs[MPTCP_ATTR_SADDR6]); ++ loc.low_prio = backup; ++ loc.if_idx = if_idx; ++ } ++ ++ ret = __mptcp_init6_subsockets(meta_sk, &loc, sport, &rem, ++ &subsk); ++ if (ret < 0) ++ goto unlock; ++ break; ++ } ++#endif ++ default: ++ goto create_failed; ++ } ++ ++unlock: ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++ ++create_failed: ++ ret = -EINVAL; ++ goto unlock; ++} ++ ++static struct sock * ++mptcp_nl_subsk_lookup(struct mptcp_cb *mpcb, struct nlattr **attrs) ++{ ++ struct sock *sk; ++ struct mptcp_tcp_sock *mptcp; ++ struct hlist_node *tmp; ++ u16 family; ++ __be16 sport, dport; ++ ++ if (!attrs[MPTCP_ATTR_FAMILY] || !attrs[MPTCP_ATTR_SPORT] || ++ !attrs[MPTCP_ATTR_DPORT]) ++ goto exit; ++ ++ family = nla_get_u16(attrs[MPTCP_ATTR_FAMILY]); ++ sport = htons(nla_get_u16(attrs[MPTCP_ATTR_SPORT])); ++ dport = htons(nla_get_u16(attrs[MPTCP_ATTR_DPORT])); ++ ++ switch (family) { ++ case AF_INET: { ++ __be32 saddr, daddr; ++ ++ if (!attrs[MPTCP_ATTR_SADDR4] || !attrs[MPTCP_ATTR_DADDR4]) ++ break; ++ ++ saddr = nla_get_u32(attrs[MPTCP_ATTR_SADDR4]); ++ daddr = nla_get_u32(attrs[MPTCP_ATTR_DADDR4]); ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ struct inet_sock *isk = inet_sk(subsk); ++ ++ if (subsk->sk_family != AF_INET) ++ continue; ++ ++ if (isk->inet_saddr == saddr && ++ isk->inet_daddr == daddr && ++ isk->inet_sport == sport && ++ isk->inet_dport == dport) { ++ sk = subsk; ++ goto found; ++ } ++ } ++ break; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ case AF_INET6: { ++ struct in6_addr saddr, daddr; ++ ++ if (!attrs[MPTCP_ATTR_SADDR6] || !attrs[MPTCP_ATTR_DADDR6]) ++ break; ++ ++ saddr = *(struct in6_addr *)nla_data(attrs[MPTCP_ATTR_SADDR6]); ++ daddr = *(struct in6_addr *)nla_data(attrs[MPTCP_ATTR_DADDR6]); ++ ++ mptcp_for_each_sub_safe(mpcb, mptcp, tmp) { ++ struct sock *subsk = mptcp_to_sock(mptcp); ++ struct inet_sock *isk = inet_sk(subsk); ++ struct ipv6_pinfo *np; ++ ++ if (subsk->sk_family != AF_INET6) ++ continue; ++ ++ np = inet6_sk(subsk); ++ if (ipv6_addr_equal(&saddr, &np->saddr) && ++ ipv6_addr_equal(&daddr, &subsk->sk_v6_daddr) && ++ isk->inet_sport == sport && ++ isk->inet_dport == dport) { ++ sk = subsk; ++ goto found; ++ } ++ } ++ break; ++ } ++#endif ++ } ++ ++exit: ++ sk = NULL; ++found: ++ return sk; ++} ++ ++static int ++mptcp_nl_genl_destroy(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ int ret = 0; ++ u32 token; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ subsk = mptcp_nl_subsk_lookup(mpcb, info->attrs); ++ if (subsk) { ++ local_bh_disable(); ++ mptcp_reinject_data(subsk, 0); ++ mptcp_send_reset(subsk); ++ local_bh_enable(); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_conn_exists(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk; ++ u32 token; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -ENOTCONN; ++ ++ sock_put(meta_sk); ++ return 0; ++} ++ ++static int ++mptcp_nl_genl_priority(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct sock *meta_sk, *subsk; ++ struct mptcp_cb *mpcb; ++ int ret = 0; ++ u32 token; ++ u8 backup = 0; ++ ++ if (!info->attrs[MPTCP_ATTR_TOKEN]) ++ return -EINVAL; ++ ++ token = nla_get_u32(info->attrs[MPTCP_ATTR_TOKEN]); ++ if (info->attrs[MPTCP_ATTR_BACKUP]) ++ backup = nla_get_u8(info->attrs[MPTCP_ATTR_BACKUP]); ++ ++ meta_sk = mptcp_hash_find(genl_info_net(info), token); ++ if (!meta_sk) ++ return -EINVAL; ++ ++ mpcb = tcp_sk(meta_sk)->mpcb; ++ ++ mutex_lock(&mpcb->mpcb_mutex); ++ lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING); ++ ++ subsk = mptcp_nl_subsk_lookup(mpcb, info->attrs); ++ if (subsk) { ++ tcp_sk(subsk)->mptcp->send_mp_prio = 1; ++ tcp_sk(subsk)->mptcp->low_prio = !!backup; ++ ++ local_bh_disable(); ++ if (mptcp_sk_can_send_ack(subsk)) ++ tcp_send_ack(subsk); ++ else ++ ret = -ENOTCONN; ++ local_bh_enable(); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ release_sock(meta_sk); ++ mutex_unlock(&mpcb->mpcb_mutex); ++ sock_put(meta_sk); ++ return ret; ++} ++ ++static int ++mptcp_nl_genl_set_filter(struct sk_buff *skb, struct genl_info *info) ++{ ++ u16 flags; ++ ++ if (!info->attrs[MPTCP_ATTR_FLAGS]) ++ return -EINVAL; ++ ++ flags = nla_get_u16(info->attrs[MPTCP_ATTR_FLAGS]); ++ ++ /* Only want to receive events that correspond to these flags */ ++ mptcp_nl_event_filter = ~flags; ++ ++ return 0; ++} ++ ++static struct genl_ops mptcp_genl_ops[] = { ++ { ++ .cmd = MPTCP_CMD_ANNOUNCE, ++ .doit = mptcp_nl_genl_announce, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_REMOVE, ++ .doit = mptcp_nl_genl_remove, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_CREATE, ++ .doit = mptcp_nl_genl_create, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_DESTROY, ++ .doit = mptcp_nl_genl_destroy, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SUB_PRIORITY, ++ .doit = mptcp_nl_genl_priority, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_SET_FILTER, ++ .doit = mptcp_nl_genl_set_filter, ++ .flags = GENL_ADMIN_PERM, ++ }, ++ { ++ .cmd = MPTCP_CMD_EXIST, ++ .doit = mptcp_nl_genl_conn_exists, ++ .flags = GENL_ADMIN_PERM, ++ }, ++}; ++ ++static struct mptcp_pm_ops mptcp_nl_pm_ops = { ++ .new_session = mptcp_nl_pm_new_session, ++ .close_session = mptcp_nl_pm_close_session, ++ .fully_established = mptcp_nl_pm_fully_established, ++ .established_subflow = mptcp_nl_pm_established_subflow, ++ .delete_subflow = mptcp_nl_pm_delete_subflow, ++ .add_raddr = mptcp_nl_pm_add_raddr, ++ .rem_raddr = mptcp_nl_pm_rem_raddr, ++ .get_local_id = mptcp_nl_pm_get_local_id, ++ .addr_signal = mptcp_nl_pm_addr_signal, ++ .prio_changed = mptcp_nl_pm_prio_changed, ++ .name = "netlink", ++ .owner = THIS_MODULE, ++}; ++ ++static struct genl_family mptcp_genl_family = { ++ .hdrsize = 0, ++ .name = MPTCP_GENL_NAME, ++ .version = MPTCP_GENL_VER, ++ .maxattr = MPTCP_ATTR_MAX, ++ .policy = mptcp_nl_genl_policy, ++ .netnsok = true, ++ .module = THIS_MODULE, ++ .ops = mptcp_genl_ops, ++ .n_ops = ARRAY_SIZE(mptcp_genl_ops), ++ .mcgrps = mptcp_mcgrps, ++ .n_mcgrps = ARRAY_SIZE(mptcp_mcgrps), ++}; ++ ++static int __init ++mptcp_nl_init(void) ++{ ++ int ret; ++ ++ BUILD_BUG_ON(sizeof(struct mptcp_nl_priv) > MPTCP_PM_SIZE); ++ ++ ret = genl_register_family(&mptcp_genl_family); ++ if (ret) ++ goto out_genl; ++ ++ ret = mptcp_register_path_manager(&mptcp_nl_pm_ops); ++ if (ret) ++ goto out_pm; ++ ++ return 0; ++out_pm: ++ genl_unregister_family(&mptcp_genl_family); ++out_genl: ++ return ret; ++} ++ ++static void __exit ++mptcp_nl_exit(void) ++{ ++ mptcp_unregister_path_manager(&mptcp_nl_pm_ops); ++ genl_unregister_family(&mptcp_genl_family); ++} ++ ++module_init(mptcp_nl_init); ++module_exit(mptcp_nl_exit); ++ ++MODULE_AUTHOR("Gregory Detal "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP netlink-based path manager"); ++MODULE_ALIAS_GENL_FAMILY(MPTCP_GENL_NAME); +diff -aurN linux-5.4.64/net/mptcp/mptcp_olia.c linux-5.4.64.mptcp/net/mptcp/mptcp_olia.c +--- linux-5.4.64/net/mptcp/mptcp_olia.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_olia.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,318 @@ ++/* ++ * MPTCP implementation - OPPORTUNISTIC LINKED INCREASES CONGESTION CONTROL: ++ * ++ * Algorithm design: ++ * Ramin Khalili ++ * Nicolas Gast ++ * Jean-Yves Le Boudec ++ * ++ * Implementation: ++ * Ramin Khalili ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++#include ++ ++static int scale = 10; ++ ++struct mptcp_olia { ++ u32 mptcp_loss1; ++ u32 mptcp_loss2; ++ u32 mptcp_loss3; ++ int epsilon_num; ++ u32 epsilon_den; ++ int mptcp_snd_cwnd_cnt; ++}; ++ ++static inline int mptcp_olia_sk_can_send(const struct sock *sk) ++{ ++ return mptcp_sk_can_send(sk) && tcp_sk(sk)->srtt_us; ++} ++ ++static inline u64 mptcp_olia_scale(u64 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++/* take care of artificially inflate (see RFC5681) ++ * of cwnd during fast-retransmit phase ++ */ ++static u32 mptcp_get_crt_cwnd(struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ if (icsk->icsk_ca_state == TCP_CA_Recovery) ++ return tcp_sk(sk)->snd_ssthresh; ++ else ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* return the dominator of the first term of the increasing term */ ++static u64 mptcp_get_rate(const struct mptcp_cb *mpcb , u32 path_rtt) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u64 rate = 1; /* We have to avoid a zero-rate because it is used as a divisor */ ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ u64 scaled_num; ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ scaled_num = mptcp_olia_scale(tmp_cwnd, scale) * path_rtt; ++ rate += div_u64(scaled_num , tp->srtt_us); ++ } ++ rate *= rate; ++ return rate; ++} ++ ++/* find the maximum cwnd, used to find set M */ ++static u32 mptcp_get_max_cwnd(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u32 best_cwnd = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ u32 tmp_cwnd; ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd > best_cwnd) ++ best_cwnd = tmp_cwnd; ++ } ++ return best_cwnd; ++} ++ ++static void mptcp_get_epsilon(const struct mptcp_cb *mpcb) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ struct mptcp_olia *ca; ++ struct tcp_sock *tp; ++ struct sock *sk; ++ u64 tmp_int, tmp_rtt, best_int = 0, best_rtt = 1; ++ u32 max_cwnd, tmp_cwnd, established_cnt = 0; ++ u8 M = 0, B_not_M = 0; ++ ++ /* TODO - integrate this in the following loop - we just want to iterate once */ ++ ++ max_cwnd = mptcp_get_max_cwnd(mpcb); ++ ++ /* find the best path */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ established_cnt++; ++ ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ /* TODO - check here and rename variables */ ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt >= (u64)best_int * tmp_rtt) { ++ best_rtt = tmp_rtt; ++ best_int = tmp_int; ++ } ++ } ++ ++ /* TODO - integrate this here in mptcp_get_max_cwnd and in the previous loop */ ++ /* find the size of M and B_not_M */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ if (tmp_cwnd == max_cwnd) { ++ M++; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ ++ if ((u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) ++ B_not_M++; ++ } ++ } ++ ++ /* check if the path is in M or B_not_M and set the value of epsilon accordingly */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ca = inet_csk_ca(sk); ++ ++ if (!mptcp_olia_sk_can_send(sk)) ++ continue; ++ ++ if (B_not_M == 0) { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } else { ++ tmp_rtt = (u64)tp->srtt_us * tp->srtt_us; ++ tmp_int = max(ca->mptcp_loss3 - ca->mptcp_loss2, ++ ca->mptcp_loss2 - ca->mptcp_loss1); ++ tmp_cwnd = mptcp_get_crt_cwnd(sk); ++ ++ if (tmp_cwnd < max_cwnd && ++ (u64)tmp_int * best_rtt == (u64)best_int * tmp_rtt) { ++ ca->epsilon_num = 1; ++ ca->epsilon_den = established_cnt * B_not_M; ++ } else if (tmp_cwnd == max_cwnd) { ++ ca->epsilon_num = -1; ++ ca->epsilon_den = established_cnt * M; ++ } else { ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++ } ++ } ++} ++ ++/* setting the initial values */ ++static void mptcp_olia_init(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (mptcp(tp)) { ++ ca->mptcp_loss1 = tp->snd_una; ++ ca->mptcp_loss2 = tp->snd_una; ++ ca->mptcp_loss3 = tp->snd_una; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ ca->epsilon_num = 0; ++ ca->epsilon_den = 1; ++ } ++} ++ ++/* updating inter-loss distance and ssthresh */ ++static void mptcp_olia_set_state(struct sock *sk, u8 new_state) ++{ ++ if (!mptcp(tcp_sk(sk))) ++ return; ++ ++ if (new_state == TCP_CA_Loss || ++ new_state == TCP_CA_Recovery || new_state == TCP_CA_CWR) { ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ ++ if (ca->mptcp_loss3 != ca->mptcp_loss2 && ++ !inet_csk(sk)->icsk_retransmits) { ++ ca->mptcp_loss1 = ca->mptcp_loss2; ++ ca->mptcp_loss2 = ca->mptcp_loss3; ++ } ++ } ++} ++ ++/* main algorithm */ ++static void mptcp_olia_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_olia *ca = inet_csk_ca(sk); ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ u64 inc_num, inc_den, rate, cwnd_scaled; ++ ++ if (!mptcp(tp)) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ ca->mptcp_loss3 = tp->snd_una; ++ ++ if (!tcp_is_cwnd_limited(sk)) ++ return; ++ ++ /* slow start if it is in the safe area */ ++ if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ return; ++ } ++ ++ mptcp_get_epsilon(mpcb); ++ rate = mptcp_get_rate(mpcb, tp->srtt_us); ++ cwnd_scaled = mptcp_olia_scale(tp->snd_cwnd, scale); ++ inc_den = ca->epsilon_den * tp->snd_cwnd * rate ? : 1; ++ ++ /* calculate the increasing term, scaling is used to reduce the rounding effect */ ++ if (ca->epsilon_num == -1) { ++ if (ca->epsilon_den * cwnd_scaled * cwnd_scaled < rate) { ++ inc_num = rate - ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt -= div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } else { ++ inc_num = ca->epsilon_den * ++ cwnd_scaled * cwnd_scaled - rate; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ } else { ++ inc_num = ca->epsilon_num * rate + ++ ca->epsilon_den * cwnd_scaled * cwnd_scaled; ++ ca->mptcp_snd_cwnd_cnt += div64_u64( ++ mptcp_olia_scale(inc_num , scale) , inc_den); ++ } ++ ++ ++ if (ca->mptcp_snd_cwnd_cnt >= (1 << scale) - 1) { ++ if (tp->snd_cwnd < tp->snd_cwnd_clamp) ++ tp->snd_cwnd++; ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } else if (ca->mptcp_snd_cwnd_cnt <= 0 - (1 << scale) + 1) { ++ tp->snd_cwnd = max((int) 1 , (int) tp->snd_cwnd - 1); ++ ca->mptcp_snd_cwnd_cnt = 0; ++ } ++} ++ ++static struct tcp_congestion_ops mptcp_olia = { ++ .init = mptcp_olia_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_olia_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .set_state = mptcp_olia_set_state, ++ .owner = THIS_MODULE, ++ .name = "olia", ++}; ++ ++static int __init mptcp_olia_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct mptcp_olia) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&mptcp_olia); ++} ++ ++static void __exit mptcp_olia_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_olia); ++} ++ ++module_init(mptcp_olia_register); ++module_exit(mptcp_olia_unregister); ++ ++MODULE_AUTHOR("Ramin Khalili, Nicolas Gast, Jean-Yves Le Boudec"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP COUPLED CONGESTION CONTROL"); ++MODULE_VERSION("0.1"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_output.c linux-5.4.64.mptcp/net/mptcp/mptcp_output.c +--- linux-5.4.64/net/mptcp/mptcp_output.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_output.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,1997 @@ ++/* ++ * MPTCP implementation - Sending side ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static const int mptcp_dss_len = MPTCP_SUB_LEN_DSS_ALIGN + ++ MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ ++static inline int mptcp_sub_len_remove_addr(u16 bitfield) ++{ ++ unsigned int c; ++ for (c = 0; bitfield; c++) ++ bitfield &= bitfield - 1; ++ return MPTCP_SUB_LEN_REMOVE_ADDR + c - 1; ++} ++ ++int mptcp_sub_len_remove_addr_align(u16 bitfield) ++{ ++ return ALIGN(mptcp_sub_len_remove_addr(bitfield), 4); ++} ++EXPORT_SYMBOL(mptcp_sub_len_remove_addr_align); ++ ++/* get the data-seq and end-data-seq and store them again in the ++ * tcp_skb_cb ++ */ ++static bool mptcp_reconstruct_mapping(struct sk_buff *skb) ++{ ++ const struct mp_dss *mpdss = (struct mp_dss *)TCP_SKB_CB(skb)->dss; ++ __be32 *p32; ++ __be16 *p16; ++ ++ if (!mptcp_is_data_seq(skb)) ++ return false; ++ ++ if (!mpdss->M) ++ return false; ++ ++ /* Move the pointer to the data-seq */ ++ p32 = (__be32 *)mpdss; ++ p32++; ++ if (mpdss->A) { ++ p32++; ++ if (mpdss->a) ++ p32++; ++ } ++ ++ TCP_SKB_CB(skb)->seq = ntohl(*p32); ++ ++ /* Get the data_len to calculate the end_data_seq */ ++ p32++; ++ p32++; ++ p16 = (__be16 *)p32; ++ TCP_SKB_CB(skb)->end_seq = ntohs(*p16) + TCP_SKB_CB(skb)->seq; ++ ++ return true; ++} ++ ++static bool mptcp_is_reinjected(const struct sk_buff *skb) ++{ ++ return TCP_SKB_CB(skb)->mptcp_flags & MPTCP_REINJECT; ++} ++ ++static void mptcp_find_and_set_pathmask(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct rb_node **p = &meta_sk->tcp_rtx_queue.rb_node; ++ struct rb_node *parent; ++ struct sk_buff *skb_it; ++ ++ while (*p) { ++ parent = *p; ++ skb_it = rb_to_skb(parent); ++ if (before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb_it)->seq)) { ++ p = &parent->rb_left; ++ continue; ++ } ++ if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb_it)->seq)) { ++ p = &parent->rb_right; ++ continue; ++ } ++ ++ TCP_SKB_CB(skb)->path_mask = TCP_SKB_CB(skb_it)->path_mask; ++ break; ++ } ++} ++ ++/* Reinject data from one TCP subflow to the meta_sk. If sk == NULL, we are ++ * coming from the meta-retransmit-timer ++ */ ++static void __mptcp_reinject_data(struct sk_buff *orig_skb, struct sock *meta_sk, ++ struct sock *sk, int clone_it, ++ enum tcp_queue tcp_queue) ++{ ++ struct sk_buff *skb, *skb1; ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ u32 seq, end_seq; ++ ++ if (clone_it) { ++ /* pskb_copy is necessary here, because the TCP/IP-headers ++ * will be changed when it's going to be reinjected on another ++ * subflow. ++ */ ++ tcp_skb_tsorted_save(orig_skb) { ++ skb = pskb_copy_for_clone(orig_skb, GFP_ATOMIC); ++ } tcp_skb_tsorted_restore(orig_skb); ++ } else { ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) { ++ __skb_unlink(orig_skb, &sk->sk_write_queue); ++ } else { ++ list_del(&orig_skb->tcp_tsorted_anchor); ++ tcp_rtx_queue_unlink(orig_skb, sk); ++ INIT_LIST_HEAD(&orig_skb->tcp_tsorted_anchor); ++ } ++ sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ sk->sk_wmem_queued -= orig_skb->truesize; ++ sk_mem_uncharge(sk, orig_skb->truesize); ++ skb = orig_skb; ++ } ++ if (unlikely(!skb)) ++ return; ++ ++ /* Make sure that this list is clean */ ++ tcp_skb_tsorted_anchor_cleanup(skb); ++ ++ if (sk && !mptcp_reconstruct_mapping(skb)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ skb->sk = meta_sk; ++ ++ /* Reset subflow-specific TCP control-data */ ++ TCP_SKB_CB(skb)->sacked = 0; ++ TCP_SKB_CB(skb)->tcp_flags &= (TCPHDR_ACK | TCPHDR_PSH); ++ ++ /* If it reached already the destination, we don't have to reinject it */ ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ __kfree_skb(skb); ++ return; ++ } ++ ++ /* Only reinject segments that are fully covered by the mapping */ ++ if (skb->len + (mptcp_is_data_fin(skb) ? 1 : 0) != ++ TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) { ++ struct rb_node *parent, **p = &meta_sk->tcp_rtx_queue.rb_node; ++ u32 end_seq = TCP_SKB_CB(skb)->end_seq; ++ u32 seq = TCP_SKB_CB(skb)->seq; ++ ++ __kfree_skb(skb); ++ ++ /* Ok, now we have to look for the full mapping in the meta ++ * send-queue :S ++ */ ++ ++ /* First, find the first skb that covers us */ ++ while (*p) { ++ parent = *p; ++ skb = rb_to_skb(parent); ++ ++ /* Not yet at the mapping? */ ++ if (!after(end_seq, TCP_SKB_CB(skb)->seq)) { ++ p = &parent->rb_left; ++ continue; ++ } ++ ++ if (!before(seq, TCP_SKB_CB(skb)->end_seq)) { ++ p = &parent->rb_right; ++ continue; ++ } ++ ++ break; ++ } ++ ++ if (*p) { ++ /* We found it, now let's reinject everything */ ++ skb = rb_to_skb(*p); ++ ++ skb_rbtree_walk_from(skb) { ++ if (after(TCP_SKB_CB(skb)->end_seq, end_seq)) ++ return; ++ __mptcp_reinject_data(skb, meta_sk, NULL, 1, ++ TCP_FRAG_IN_RTX_QUEUE); ++ } ++ } ++ return; ++ } ++ ++ /* Segment goes back to the MPTCP-layer. So, we need to zero the ++ * path_mask/dss. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ /* We need to find out the path-mask from the meta-write-queue ++ * to properly select a subflow. ++ */ ++ mptcp_find_and_set_pathmask(meta_sk, skb); ++ ++ /* If it's empty, just add */ ++ if (skb_queue_empty(&mpcb->reinject_queue)) { ++ skb_queue_head(&mpcb->reinject_queue, skb); ++ return; ++ } ++ ++ /* Find place to insert skb - or even we can 'drop' it, as the ++ * data is already covered by other skb's in the reinject-queue. ++ * ++ * This is inspired by code from tcp_data_queue. ++ */ ++ ++ skb1 = skb_peek_tail(&mpcb->reinject_queue); ++ seq = TCP_SKB_CB(skb)->seq; ++ while (1) { ++ if (!after(TCP_SKB_CB(skb1)->seq, seq)) ++ break; ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) { ++ skb1 = NULL; ++ break; ++ } ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ ++ /* Do skb overlap to previous one? */ ++ end_seq = TCP_SKB_CB(skb)->end_seq; ++ if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { ++ if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { ++ /* All the bits are present. Don't reinject */ ++ __kfree_skb(skb); ++ return; ++ } ++ if (seq == TCP_SKB_CB(skb1)->seq) { ++ if (skb_queue_is_first(&mpcb->reinject_queue, skb1)) ++ skb1 = NULL; ++ else ++ skb1 = skb_queue_prev(&mpcb->reinject_queue, skb1); ++ } ++ } ++ if (!skb1) ++ __skb_queue_head(&mpcb->reinject_queue, skb); ++ else ++ __skb_queue_after(&mpcb->reinject_queue, skb1, skb); ++ ++ /* And clean segments covered by new one as whole. */ ++ while (!skb_queue_is_last(&mpcb->reinject_queue, skb)) { ++ skb1 = skb_queue_next(&mpcb->reinject_queue, skb); ++ ++ if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) ++ break; ++ ++ if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) ++ break; ++ ++ __skb_unlink(skb1, &mpcb->reinject_queue); ++ __kfree_skb(skb1); ++ } ++ return; ++} ++ ++/* Inserts data into the reinject queue */ ++void mptcp_reinject_data(struct sock *sk, int clone_it) ++{ ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct sk_buff *skb_it, *tmp; ++ enum tcp_queue tcp_queue; ++ ++ /* It has already been closed - there is really no point in reinjecting */ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return; ++ ++ skb_queue_walk_safe(&sk->sk_write_queue, skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it, ++ TCP_FRAG_IN_WRITE_QUEUE); ++ } ++ ++ skb_it = tcp_rtx_queue_head(sk); ++ skb_rbtree_walk_from_safe(skb_it, tmp) { ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb_it); ++ ++ /* Subflow syn's and fin's are not reinjected. ++ * ++ * As well as empty subflow-fins with a data-fin. ++ * They are reinjected below (without the subflow-fin-flag) ++ */ ++ if (tcb->tcp_flags & TCPHDR_SYN || ++ (tcb->tcp_flags & TCPHDR_FIN && !mptcp_is_data_fin(skb_it)) || ++ (tcb->tcp_flags & TCPHDR_FIN && mptcp_is_data_fin(skb_it) && !skb_it->len)) ++ continue; ++ ++ if (mptcp_is_reinjected(skb_it)) ++ continue; ++ ++ tcb->mptcp_flags |= MPTCP_REINJECT; ++ __mptcp_reinject_data(skb_it, meta_sk, sk, clone_it, ++ TCP_FRAG_IN_RTX_QUEUE); ++ } ++ ++ skb_it = tcp_write_queue_tail(meta_sk); ++ tcp_queue = TCP_FRAG_IN_WRITE_QUEUE; ++ ++ if (!skb_it) { ++ skb_it = skb_rb_last(&meta_sk->tcp_rtx_queue); ++ tcp_queue = TCP_FRAG_IN_RTX_QUEUE; ++ } ++ ++ /* If sk has sent the empty data-fin, we have to reinject it too. */ ++ if (skb_it && mptcp_is_data_fin(skb_it) && skb_it->len == 0 && ++ TCP_SKB_CB(skb_it)->path_mask & mptcp_pi_to_flag(tcp_sk(sk)->mptcp->path_index)) { ++ __mptcp_reinject_data(skb_it, meta_sk, NULL, 1, tcp_queue); ++ } ++ ++ tcp_sk(sk)->pf = 1; ++ ++ mptcp_push_pending_frames(meta_sk); ++} ++EXPORT_SYMBOL(mptcp_reinject_data); ++ ++static void mptcp_combine_dfin(const struct sk_buff *skb, ++ const struct sock *meta_sk, ++ struct sock *subsk) ++{ ++ const struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ const struct mptcp_cb *mpcb = meta_tp->mpcb; ++ ++ /* In infinite mapping we always try to combine */ ++ if (mpcb->infinite_mapping_snd) ++ goto combine; ++ ++ /* Don't combine, if they didn't combine when closing - otherwise we end ++ * up in TIME_WAIT, even if our app is smart enough to avoid it. ++ */ ++ if (!mptcp_sk_can_recv(meta_sk) && !mpcb->dfin_combined) ++ return; ++ ++ /* Don't combine if there is still outstanding data that remains to be ++ * DATA_ACKed, because otherwise we may never be able to deliver this. ++ */ ++ if (meta_tp->snd_una != TCP_SKB_CB(skb)->seq) ++ return; ++ ++combine: ++ if (tcp_close_state(subsk)) { ++ subsk->sk_shutdown |= SEND_SHUTDOWN; ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; ++ } ++} ++ ++static int mptcp_write_dss_mapping(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ const struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *start = ptr; ++ __u16 data_len; ++ ++ *ptr++ = htonl(tcb->seq); /* data_seq */ ++ ++ /* If it's a non-data DATA_FIN, we set subseq to 0 (draft v7) */ ++ if (mptcp_is_data_fin(skb) && skb->len == 0) ++ *ptr++ = 0; /* subseq */ ++ else ++ *ptr++ = htonl(tp->write_seq - tp->mptcp->snt_isn); /* subseq */ ++ ++ if (tcb->mptcp_flags & MPTCPHDR_INF) ++ data_len = 0; ++ else ++ data_len = tcb->end_seq - tcb->seq; ++ ++ if (tp->mpcb->dss_csum && data_len) { ++ __sum16 *p16 = (__sum16 *)ptr; ++ __be32 hdseq = mptcp_get_highorder_sndbits(skb, tp->mpcb); ++ __wsum csum; ++ ++ *ptr = htonl(((data_len) << 16) | ++ (TCPOPT_EOL << 8) | ++ (TCPOPT_EOL)); ++ csum = csum_partial(ptr - 2, 12, skb->csum); ++ p16++; ++ *p16++ = csum_fold(csum_partial(&hdseq, sizeof(hdseq), csum)); ++ } else { ++ *ptr++ = htonl(((data_len) << 16) | ++ (TCPOPT_NOP << 8) | ++ (TCPOPT_NOP)); ++ } ++ ++ return ptr - start; ++} ++ ++static int mptcp_write_dss_data_ack(const struct tcp_sock *tp, const struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ struct mp_dss *mdss = (struct mp_dss *)ptr; ++ __be32 *start = ptr; ++ ++ mdss->kind = TCPOPT_MPTCP; ++ mdss->sub = MPTCP_SUB_DSS; ++ mdss->rsv1 = 0; ++ mdss->rsv2 = 0; ++ mdss->F = mptcp_is_data_fin(skb) ? 1 : 0; ++ mdss->m = 0; ++ mdss->M = mptcp_is_data_seq(skb) ? 1 : 0; ++ mdss->a = 0; ++ mdss->A = 1; ++ mdss->len = mptcp_sub_len_dss(mdss, tp->mpcb->dss_csum); ++ ptr++; ++ ++ *ptr++ = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ return ptr - start; ++} ++ ++/* RFC6824 states that once a particular subflow mapping has been sent ++ * out it must never be changed. However, packets may be split while ++ * they are in the retransmission queue (due to SACK or ACKs) and that ++ * arguably means that we would change the mapping (e.g. it splits it, ++ * our sends out a subset of the initial mapping). ++ * ++ * Furthermore, the skb checksum is not always preserved across splits ++ * (e.g. mptcp_fragment) which would mean that we need to recompute ++ * the DSS checksum in this case. ++ * ++ * To avoid this we save the initial DSS mapping which allows us to ++ * send the same DSS mapping even for fragmented retransmits. ++ */ ++static void mptcp_save_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb) ++{ ++ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); ++ __be32 *ptr = (__be32 *)tcb->dss; ++ ++ tcb->mptcp_flags |= MPTCPHDR_SEQ; ++ ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ ptr += mptcp_write_dss_mapping(tp, skb, ptr); ++} ++ ++/* Write the MP_CAPABLE with data-option */ ++static int mptcp_write_mpcapable_data(const struct tcp_sock *tp, ++ struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ struct mp_capable *mpc = (struct mp_capable *)ptr; ++ u8 length; ++ ++ if (tp->mpcb->dss_csum) ++ length = MPTCPV1_SUB_LEN_CAPABLE_DATA_CSUM; ++ else ++ length = MPTCPV1_SUB_LEN_CAPABLE_DATA; ++ ++ mpc->kind = TCPOPT_MPTCP; ++ mpc->len = length; ++ mpc->sub = MPTCP_SUB_CAPABLE; ++ mpc->ver = MPTCP_VERSION_1; ++ mpc->a = tp->mpcb->dss_csum; ++ mpc->b = 0; ++ mpc->rsv = 0; ++ mpc->h = 1; ++ ++ ptr++; ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, mptcp_dss_len); ++ ++ mpc->sender_key = tp->mpcb->mptcp_loc_key; ++ mpc->receiver_key = tp->mpcb->mptcp_rem_key; ++ ++ /* dss is in a union with inet_skb_parm and ++ * the IP layer expects zeroed IPCB fields. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0, mptcp_dss_len); ++ ++ return MPTCPV1_SUB_LEN_CAPABLE_DATA_ALIGN / sizeof(*ptr); ++} ++ ++/* Write the saved DSS mapping to the header */ ++static int mptcp_write_dss_data_seq(const struct tcp_sock *tp, struct sk_buff *skb, ++ __be32 *ptr) ++{ ++ int length; ++ __be32 *start = ptr; ++ ++ if (tp->mpcb->rem_key_set) { ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, mptcp_dss_len); ++ ++ /* update the data_ack */ ++ start[1] = htonl(mptcp_meta_tp(tp)->rcv_nxt); ++ ++ length = mptcp_dss_len / sizeof(*ptr); ++ } else { ++ memcpy(ptr, TCP_SKB_CB(skb)->dss, MPTCP_SUB_LEN_DSS_ALIGN); ++ ++ ptr++; ++ memcpy(ptr, TCP_SKB_CB(skb)->dss + 2, MPTCP_SUB_LEN_SEQ_ALIGN); ++ ++ length = (MPTCP_SUB_LEN_DSS_ALIGN + MPTCP_SUB_LEN_SEQ_ALIGN) / sizeof(*ptr); ++ } ++ ++ /* dss is in a union with inet_skb_parm and ++ * the IP layer expects zeroed IPCB fields. ++ */ ++ memset(TCP_SKB_CB(skb)->dss, 0 , mptcp_dss_len); ++ ++ return length; ++} ++ ++static bool mptcp_skb_entail(struct sock *sk, struct sk_buff *skb, int reinject) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ const struct sock *meta_sk = mptcp_meta_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ struct tcp_skb_cb *tcb; ++ struct sk_buff *subskb = NULL; ++ ++ if (!reinject) ++ TCP_SKB_CB(skb)->mptcp_flags |= (mpcb->snd_hiseq_index ? ++ MPTCPHDR_SEQ64_INDEX : 0); ++ ++ tcp_skb_tsorted_save(skb) { ++ subskb = pskb_copy_for_clone(skb, GFP_ATOMIC); ++ } tcp_skb_tsorted_restore(skb); ++ if (!subskb) ++ return false; ++ ++ /* At the subflow-level we need to call again tcp_init_tso_segs. We ++ * force this, by setting pcount to 0. It has been set to 1 prior to ++ * the call to mptcp_skb_entail. ++ */ ++ tcp_skb_pcount_set(subskb, 0); ++ ++ TCP_SKB_CB(skb)->path_mask |= mptcp_pi_to_flag(tp->mptcp->path_index); ++ ++ /* Compute checksum */ ++ if (tp->mpcb->dss_csum) ++ subskb->csum = skb->csum = skb_checksum(skb, 0, skb->len, 0); ++ ++ tcb = TCP_SKB_CB(subskb); ++ ++ if (tp->mpcb->send_infinite_mapping && ++ !tp->mpcb->infinite_mapping_snd && ++ !before(tcb->seq, mptcp_meta_tp(tp)->snd_nxt)) { ++ tp->mptcp->fully_established = 1; ++ tp->mpcb->infinite_mapping_snd = 1; ++ tp->mptcp->infinite_cutoff_seq = tp->write_seq; ++ tcb->mptcp_flags |= MPTCPHDR_INF; ++ } ++ ++ if (mptcp_is_data_fin(subskb)) ++ mptcp_combine_dfin(subskb, meta_sk, sk); ++ ++ mptcp_save_dss_data_seq(tp, subskb); ++ ++ if (mpcb->send_mptcpv1_mpcapable) { ++ TCP_SKB_CB(subskb)->mptcp_flags |= MPTCPHDR_MPC_DATA; ++ mpcb->send_mptcpv1_mpcapable = 0; ++ } ++ ++ tcb->seq = tp->write_seq; ++ ++ /* Take into account seg len */ ++ tp->write_seq += subskb->len + ((tcb->tcp_flags & TCPHDR_FIN) ? 1 : 0); ++ tcb->end_seq = tp->write_seq; ++ ++ /* txstamp_ack is handled at the meta-level */ ++ tcb->txstamp_ack = 0; ++ ++ /* If it's a non-payload DATA_FIN (also no subflow-fin), the ++ * segment is not part of the subflow but on a meta-only-level. ++ */ ++ if (!mptcp_is_data_fin(subskb) || tcb->end_seq != tcb->seq) { ++ /* Make sure that this list is clean */ ++ INIT_LIST_HEAD(&subskb->tcp_tsorted_anchor); ++ ++ tcp_add_write_queue_tail(sk, subskb); ++ sk->sk_wmem_queued += subskb->truesize; ++ sk_mem_charge(sk, subskb->truesize); ++ } else { ++ /* Necessary to initialize for tcp_transmit_skb. mss of 1, as ++ * skb->len = 0 will force tso_segs to 1. ++ */ ++ tcp_init_tso_segs(subskb, 1); ++ ++ /* Empty data-fins are sent immediatly on the subflow */ ++ if (tcp_transmit_skb(sk, subskb, 0, GFP_ATOMIC)) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ tp->mptcp->second_packet = 1; ++ tp->mptcp->last_end_data_seq = TCP_SKB_CB(skb)->end_seq; ++ } ++ ++ return true; ++} ++ ++/* Fragment an skb and update the mptcp meta-data. Due to reinject, we ++ * might need to undo some operations done by tcp_fragment. ++ * ++ * Be careful, the skb may come from 3 different places: ++ * - The send-queue (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ * - The retransmit-queue (tcp_queue == TCP_FRAG_IN_RTX_QUEUE) ++ * - The reinject-queue (reinject == -1) ++ */ ++static int mptcp_fragment(struct sock *meta_sk, enum tcp_queue tcp_queue, ++ struct sk_buff *skb, u32 len, ++ gfp_t gfp, int reinject) ++{ ++ int ret, diff, old_factor; ++ struct sk_buff *buff; ++ u8 flags; ++ ++ if (skb_headlen(skb) < len) ++ diff = skb->len - len; ++ else ++ diff = skb->data_len; ++ old_factor = tcp_skb_pcount(skb); ++ ++ /* The mss_now in tcp_fragment is used to set the tso_segs of the skb. ++ * At the MPTCP-level we do not care about the absolute value. All we ++ * care about is that it is set to 1 for accurate packets_out ++ * accounting. ++ */ ++ ret = tcp_fragment(meta_sk, tcp_queue, skb, len, UINT_MAX, gfp); ++ if (ret) ++ return ret; ++ ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ buff = skb->next; ++ else ++ buff = skb_rb_next(skb); ++ ++ flags = TCP_SKB_CB(skb)->mptcp_flags; ++ TCP_SKB_CB(skb)->mptcp_flags = flags & ~(MPTCPHDR_FIN); ++ TCP_SKB_CB(buff)->mptcp_flags = flags; ++ TCP_SKB_CB(buff)->path_mask = TCP_SKB_CB(skb)->path_mask; ++ ++ /* If reinject == 1, the buff will be added to the reinject ++ * queue, which is currently not part of memory accounting. So ++ * undo the changes done by tcp_fragment and update the ++ * reinject queue. Also, undo changes to the packet counters. ++ */ ++ if (reinject == 1) { ++ int undo = buff->truesize - diff; ++ meta_sk->sk_wmem_queued -= undo; ++ sk_mem_uncharge(meta_sk, undo); ++ ++ tcp_sk(meta_sk)->mpcb->reinject_queue.qlen++; ++ if (tcp_queue == TCP_FRAG_IN_WRITE_QUEUE) ++ meta_sk->sk_write_queue.qlen--; ++ ++ if (!before(tcp_sk(meta_sk)->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { ++ undo = old_factor - tcp_skb_pcount(skb) - ++ tcp_skb_pcount(buff); ++ if (undo) ++ tcp_adjust_pcount(meta_sk, skb, -undo); ++ } ++ ++ /* tcp_fragment's call to sk_stream_alloc_skb initializes the ++ * tcp_tsorted_anchor. We need to revert this as it clashes ++ * with the refdst pointer. ++ */ ++ tcp_skb_tsorted_anchor_cleanup(buff); ++ } ++ ++ return 0; ++} ++ ++/* Inspired by tcp_write_wakeup */ ++int mptcp_write_wakeup(struct sock *meta_sk, int mib) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sk_buff *skb; ++ int ans = 0; ++ ++ if (meta_sk->sk_state == TCP_CLOSE) ++ return -1; ++ ++ skb = tcp_send_head(meta_sk); ++ if (skb && ++ before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(meta_tp))) { ++ unsigned int mss; ++ unsigned int seg_size = tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq; ++ struct sock *subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, true); ++ struct tcp_sock *subtp; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ if (!subsk) ++ goto window_probe; ++ subtp = tcp_sk(subsk); ++ mss = tcp_current_mss(subsk); ++ ++ seg_size = min(tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq, ++ tcp_wnd_end(subtp) - subtp->write_seq); ++ ++ if (before(meta_tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) ++ meta_tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; ++ ++ /* We are probing the opening of a window ++ * but the window size is != 0 ++ * must have been a result SWS avoidance ( sender ) ++ */ ++ if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || ++ skb->len > mss) { ++ seg_size = min(seg_size, mss); ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (mptcp_fragment(meta_sk, TCP_FRAG_IN_WRITE_QUEUE, ++ skb, seg_size, GFP_ATOMIC, 0)) ++ return -1; ++ } else if (!tcp_skb_pcount(skb)) { ++ /* see mptcp_write_xmit on why we use UINT_MAX */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ } ++ ++ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; ++ if (!mptcp_skb_entail(subsk, skb, 0)) ++ return -1; ++ ++ mptcp_check_sndseq_wrap(meta_tp, TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ ++ __tcp_push_pending_frames(subsk, mss, TCP_NAGLE_PUSH); ++ tcp_update_skb_after_send(meta_sk, skb, meta_tp->tcp_wstamp_ns); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ } else { ++ struct mptcp_tcp_sock *mptcp; ++ ++window_probe: ++ if (between(meta_tp->snd_up, meta_tp->snd_una + 1, ++ meta_tp->snd_una + 0xFFFF)) { ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ ++ if (mptcp_sk_can_send_ack(sk_it)) ++ tcp_xmit_probe_skb(sk_it, 1, mib); ++ } ++ } ++ ++ /* At least one of the tcp_xmit_probe_skb's has to succeed */ ++ mptcp_for_each_sub(meta_tp->mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ int ret; ++ ++ if (!mptcp_sk_can_send_ack(sk_it)) ++ continue; ++ ++ ret = tcp_xmit_probe_skb(sk_it, 0, mib); ++ if (unlikely(ret > 0)) ++ ans = ret; ++ } ++ return ans; ++ } ++} ++ ++bool mptcp_write_xmit(struct sock *meta_sk, unsigned int mss_now, int nonagle, ++ int push_one, gfp_t gfp) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk), *subtp; ++ struct mptcp_tcp_sock *mptcp; ++ struct sock *subsk = NULL; ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sk_buff *skb; ++ int reinject = 0; ++ unsigned int sublimit; ++ __u32 path_mask = 0; ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ if (inet_csk(meta_sk)->icsk_retransmits) { ++ /* If the timer already once fired, retransmit the head of the ++ * queue to unblock us ASAP. ++ */ ++ if (meta_tp->packets_out && !mpcb->infinite_mapping_snd) ++ mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ } ++ ++ while ((skb = mpcb->sched_ops->next_segment(meta_sk, &reinject, &subsk, ++ &sublimit))) { ++ enum tcp_queue tcp_queue = TCP_FRAG_IN_WRITE_QUEUE; ++ unsigned int limit; ++ ++ WARN(TCP_SKB_CB(skb)->sacked, "sacked: %u reinject: %u", ++ TCP_SKB_CB(skb)->sacked, reinject); ++ ++ subtp = tcp_sk(subsk); ++ mss_now = tcp_current_mss(subsk); ++ ++ if (reinject == 1) { ++ if (!after(TCP_SKB_CB(skb)->end_seq, meta_tp->snd_una)) { ++ /* Segment already reached the peer, take the next one */ ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ __kfree_skb(skb); ++ continue; ++ } ++ } else if (reinject == -1) { ++ tcp_queue = TCP_FRAG_IN_RTX_QUEUE; ++ } ++ ++ /* If the segment was cloned (e.g. a meta retransmission), ++ * the header must be expanded/copied so that there is no ++ * corruption of TSO information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) ++ break; ++ ++ if (unlikely(!tcp_snd_wnd_test(meta_tp, skb, mss_now))) ++ break; ++ ++ /* Force tso_segs to 1 by using UINT_MAX. ++ * We actually don't care about the exact number of segments ++ * emitted on the subflow. We need just to set tso_segs, because ++ * we still need an accurate packets_out count in ++ * tcp_event_new_data_sent. ++ */ ++ tcp_set_skb_tso_segs(skb, UINT_MAX); ++ ++ /* Check for nagle, irregardless of tso_segs. If the segment is ++ * actually larger than mss_now (TSO segment), then ++ * tcp_nagle_check will have partial == false and always trigger ++ * the transmission. ++ * tcp_write_xmit has a TSO-level nagle check which is not ++ * subject to the MPTCP-level. It is based on the properties of ++ * the subflow, not the MPTCP-level. ++ * When the segment is a reinjection or redundant scheduled ++ * segment, nagle check at meta-level may prevent ++ * sending. This could hurt with certain schedulers, as they ++ * to reinjection to recover from a window-stall or reduce latency. ++ * Therefore, Nagle check should be disabled in that case. ++ */ ++ if (!reinject && ++ unlikely(!tcp_nagle_test(meta_tp, skb, mss_now, ++ (tcp_skb_is_last(meta_sk, skb) ? ++ nonagle : TCP_NAGLE_PUSH)))) ++ break; ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ /* We limit the size of the skb so that it fits into the ++ * window. Call tcp_mss_split_point to avoid duplicating ++ * code. ++ * We really only care about fitting the skb into the ++ * window. That's why we use UINT_MAX. If the skb does ++ * not fit into the cwnd_quota or the NIC's max-segs ++ * limitation, it will be split by the subflow's ++ * tcp_write_xmit which does the appropriate call to ++ * tcp_mss_split_point. ++ */ ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ nonagle); ++ ++ if (sublimit) ++ limit = min(limit, sublimit); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, tcp_queue, ++ skb, limit, gfp, reinject))) ++ break; ++ ++ if (!mptcp_skb_entail(subsk, skb, reinject)) ++ break; ++ ++ if (reinject <= 0) ++ tcp_update_skb_after_send(meta_sk, skb, meta_tp->tcp_wstamp_ns); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ path_mask |= mptcp_pi_to_flag(subtp->mptcp->path_index); ++ ++ if (!reinject) { ++ mptcp_check_sndseq_wrap(meta_tp, ++ TCP_SKB_CB(skb)->end_seq - ++ TCP_SKB_CB(skb)->seq); ++ tcp_event_new_data_sent(meta_sk, skb); ++ } ++ ++ tcp_minshall_update(meta_tp, mss_now, skb); ++ ++ if (reinject > 0) { ++ __skb_unlink(skb, &mpcb->reinject_queue); ++ kfree_skb(skb); ++ } ++ ++ if (push_one) ++ break; ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ subsk = mptcp_to_sock(mptcp); ++ subtp = tcp_sk(subsk); ++ ++ if (!(path_mask & mptcp_pi_to_flag(subtp->mptcp->path_index))) ++ continue; ++ ++ mss_now = tcp_current_mss(subsk); ++ ++ /* Nagle is handled at the MPTCP-layer, so ++ * always push on the subflow ++ */ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ } ++ ++ return !meta_tp->packets_out && tcp_send_head(meta_sk); ++} ++ ++void mptcp_write_space(struct sock *sk) ++{ ++ mptcp_push_pending_frames(mptcp_meta_sk(sk)); ++} ++ ++u32 __mptcp_select_window(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk), *meta_tp = mptcp_meta_tp(tp); ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ int mss, free_space, full_space, window; ++ ++ /* MSS for the peer's data. Previous versions used mss_clamp ++ * here. I don't know if the value based on our guesses ++ * of peer's MSS is better for the performance. It's more correct ++ * but may be worse for the performance because of rcv_mss ++ * fluctuations. --SAW 1998/11/1 ++ */ ++ mss = icsk->icsk_ack.rcv_mss; ++ free_space = tcp_space(meta_sk); ++ full_space = min_t(int, meta_tp->window_clamp, ++ tcp_full_space(meta_sk)); ++ ++ if (mss > full_space) ++ mss = full_space; ++ ++ if (free_space < (full_space >> 1)) { ++ /* If free_space is decreasing due to mostly meta-level ++ * out-of-order packets, don't turn off the quick-ack mode. ++ */ ++ if (meta_tp->rcv_nxt - meta_tp->copied_seq > ((full_space - free_space) >> 1)) ++ icsk->icsk_ack.quick = 0; ++ ++ if (tcp_memory_pressure) ++ /* TODO this has to be adapted when we support different ++ * MSS's among the subflows. ++ */ ++ meta_tp->rcv_ssthresh = min(meta_tp->rcv_ssthresh, ++ 4U * meta_tp->advmss); ++ ++ if (free_space < mss) ++ return 0; ++ } ++ ++ if (free_space > meta_tp->rcv_ssthresh) ++ free_space = meta_tp->rcv_ssthresh; ++ ++ /* Don't do rounding if we are using window scaling, since the ++ * scaled window will not line up with the MSS boundary anyway. ++ */ ++ window = meta_tp->rcv_wnd; ++ if (tp->rx_opt.rcv_wscale) { ++ window = free_space; ++ ++ /* Advertise enough space so that it won't get scaled away. ++ * Import case: prevent zero window announcement if ++ * 1< mss. ++ */ ++ if (((window >> tp->rx_opt.rcv_wscale) << tp-> ++ rx_opt.rcv_wscale) != window) ++ window = (((window >> tp->rx_opt.rcv_wscale) + 1) ++ << tp->rx_opt.rcv_wscale); ++ } else { ++ /* Get the largest window that is a nice multiple of mss. ++ * Window clamp already applied above. ++ * If our current window offering is within 1 mss of the ++ * free space we just keep it. This prevents the divide ++ * and multiply from happening most of the time. ++ * We also don't do any window rounding when the free space ++ * is too small. ++ */ ++ if (window <= free_space - mss || window > free_space) ++ window = (free_space / mss) * mss; ++ else if (mss == full_space && ++ free_space > window + (full_space >> 1)) ++ window = free_space; ++ } ++ ++ return window; ++} ++ ++void mptcp_syn_options(const struct sock *sk, struct tcp_out_options *opts, ++ unsigned *remaining) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ opts->options |= OPTION_MPTCP; ++ if (is_master_tp(tp)) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYN; ++ opts->mptcp_ver = tp->mptcp_ver; ++ ++ if (tp->mptcp_ver >= MPTCP_VERSION_1) ++ *remaining -= MPTCPV1_SUB_LEN_CAPABLE_SYN_ALIGN; ++ else ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ ++ opts->mp_capable.sender_key = tp->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum; ++ } else { ++ const struct mptcp_cb *mpcb = tp->mpcb; ++ ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYN; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYN_ALIGN; ++ opts->mp_join_syns.token = mpcb->mptcp_rem_token; ++ opts->mp_join_syns.low_prio = tp->mptcp->low_prio; ++ opts->addr_id = tp->mptcp->loc_id; ++ opts->mp_join_syns.sender_nonce = tp->mptcp->mptcp_loc_nonce; ++ } ++} ++ ++void mptcp_synack_options(struct request_sock *req, ++ struct tcp_out_options *opts, unsigned *remaining) ++{ ++ struct mptcp_request_sock *mtreq; ++ mtreq = mptcp_rsk(req); ++ ++ opts->options |= OPTION_MPTCP; ++ /* MPCB not yet set - thus it's a new MPTCP-session */ ++ if (!mtreq->is_sub) { ++ opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYNACK; ++ opts->mptcp_ver = mtreq->mptcp_ver; ++ opts->mp_capable.sender_key = mtreq->mptcp_loc_key; ++ opts->dss_csum = !!sysctl_mptcp_checksum || mtreq->dss_csum; ++ if (mtreq->mptcp_ver >= MPTCP_VERSION_1) { ++ *remaining -= MPTCPV1_SUB_LEN_CAPABLE_SYNACK_ALIGN; ++ } else { ++ *remaining -= MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN; ++ } ++ } else { ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYNACK; ++ opts->mp_join_syns.sender_truncated_mac = ++ mtreq->mptcp_hash_tmac; ++ opts->mp_join_syns.sender_nonce = mtreq->mptcp_loc_nonce; ++ opts->mp_join_syns.low_prio = mtreq->low_prio; ++ opts->addr_id = mtreq->loc_id; ++ *remaining -= MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN; ++ } ++} ++ ++void mptcp_established_options(struct sock *sk, struct sk_buff *skb, ++ struct tcp_out_options *opts, unsigned *size) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_cb *mpcb = tp->mpcb; ++ const struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL; ++ ++ /* We are coming from tcp_current_mss with the meta_sk as an argument. ++ * It does not make sense to check for the options, because when the ++ * segment gets sent, another subflow will be chosen. ++ */ ++ if (!skb && is_meta_sk(sk)) ++ return; ++ ++ if (unlikely(tp->send_mp_fclose)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FCLOSE; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ *size += MPTCP_SUB_LEN_FCLOSE_ALIGN; ++ return; ++ } ++ ++ /* 1. If we are the sender of the infinite-mapping, we need the ++ * MPTCPHDR_INF-flag, because a retransmission of the ++ * infinite-announcment still needs the mptcp-option. ++ * ++ * We need infinite_cutoff_seq, because retransmissions from before ++ * the infinite-cutoff-moment still need the MPTCP-signalling to stay ++ * consistent. ++ * ++ * 2. If we are the receiver of the infinite-mapping, we always skip ++ * mptcp-options, because acknowledgments from before the ++ * infinite-mapping point have already been sent out. ++ * ++ * I know, the whole infinite-mapping stuff is ugly... ++ * ++ * TODO: Handle wrapped data-sequence numbers ++ * (even if it's very unlikely) ++ */ ++ if (unlikely(mpcb->infinite_mapping_snd) && ++ ((mpcb->send_infinite_mapping && tcb && ++ mptcp_is_data_seq(skb) && ++ !(tcb->mptcp_flags & MPTCPHDR_INF) && ++ !before(tcb->seq, tp->mptcp->infinite_cutoff_seq)) || ++ !mpcb->send_infinite_mapping)) ++ return; ++ ++ if (unlikely(tp->mptcp->include_mpc)) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_CAPABLE | ++ OPTION_TYPE_ACK; ++ ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) ++ *size += MPTCPV1_SUB_LEN_CAPABLE_ACK_ALIGN; ++ else ++ *size += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN; ++ ++ opts->mptcp_ver = mpcb->mptcp_ver; ++ opts->mp_capable.sender_key = mpcb->mptcp_loc_key; ++ opts->mp_capable.receiver_key = mpcb->mptcp_rem_key; ++ opts->dss_csum = mpcb->dss_csum; ++ ++ if (skb) ++ tp->mptcp->include_mpc = 0; ++ } ++ if (unlikely(tp->mptcp->pre_established) && ++ (!skb || !(tcb->tcp_flags & (TCPHDR_FIN | TCPHDR_RST)))) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_ACK; ++ *size += MPTCP_SUB_LEN_JOIN_ACK_ALIGN; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (opts->add_addr_v6) ++ /* Skip subsequent options */ ++ return; ++ } ++ ++ if (!tp->mptcp->include_mpc && !tp->mptcp->pre_established) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_DATA_ACK; ++ /* If !skb, we come from tcp_current_mss and thus we always ++ * assume that the DSS-option will be set for the data-packet. ++ */ ++ if (skb && !mptcp_is_data_seq(skb) && mpcb->rem_key_set) { ++ *size += MPTCP_SUB_LEN_ACK_ALIGN; ++ } else if ((skb && mptcp_is_data_mpcapable(skb)) || ++ (!skb && tp->mpcb->send_mptcpv1_mpcapable)) { ++ *size += MPTCPV1_SUB_LEN_CAPABLE_DATA_ALIGN; ++ } else { ++ /* Doesn't matter, if csum included or not. It will be ++ * either 10 or 12, and thus aligned = 12 ++ */ ++ if (mpcb->rem_key_set) ++ *size += MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_SEQ_ALIGN; ++ else ++ *size += MPTCP_SUB_LEN_SEQ_ALIGN; ++ } ++ ++ *size += MPTCP_SUB_LEN_DSS_ALIGN; ++ } ++ ++ /* In fallback mp_fail-mode, we have to repeat it until the fallback ++ * has been done by the sender ++ */ ++ if (unlikely(tp->mptcp->send_mp_fail) && skb && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_FAIL) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_FAIL; ++ *size += MPTCP_SUB_LEN_FAIL; ++ } ++ ++ if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && ++ mpcb->mptcp_ver < MPTCP_VERSION_1) ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (unlikely(tp->mptcp->send_mp_prio) && ++ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_PRIO_ALIGN) { ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_MP_PRIO; ++ if (skb) ++ tp->mptcp->send_mp_prio = 0; ++ *size += MPTCP_SUB_LEN_PRIO_ALIGN; ++ } ++ ++ return; ++} ++ ++u16 mptcp_select_window(struct sock *sk) ++{ ++ u16 new_win = tcp_select_window(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct tcp_sock *meta_tp = mptcp_meta_tp(tp); ++ ++ meta_tp->rcv_wnd = tp->rcv_wnd; ++ meta_tp->rcv_wup = meta_tp->rcv_nxt; ++ ++ return new_win; ++} ++ ++void mptcp_options_write(__be32 *ptr, struct tcp_sock *tp, ++ const struct tcp_out_options *opts, ++ struct sk_buff *skb) ++{ ++ if (unlikely(OPTION_MP_CAPABLE & opts->mptcp_options)) { ++ struct mp_capable *mpc = (struct mp_capable *)ptr; ++ ++ mpc->kind = TCPOPT_MPTCP; ++ ++ if (OPTION_TYPE_SYN & opts->mptcp_options) { ++ mpc->ver = opts->mptcp_ver; ++ ++ if (mpc->ver >= MPTCP_VERSION_1) { ++ mpc->len = MPTCPV1_SUB_LEN_CAPABLE_SYN; ++ ptr += MPTCPV1_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } else { ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_SYN; ++ ptr += MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } ++ } else if (OPTION_TYPE_SYNACK & opts->mptcp_options) { ++ mpc->ver = opts->mptcp_ver; ++ ++ if (mpc->ver >= MPTCP_VERSION_1) { ++ mpc->len = MPTCPV1_SUB_LEN_CAPABLE_SYNACK; ++ ptr += MPTCPV1_SUB_LEN_CAPABLE_SYNACK_ALIGN >> 2; ++ } else { ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_SYN; ++ ptr += MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN >> 2; ++ } ++ ++ mpc->sender_key = opts->mp_capable.sender_key; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpc->len = MPTCP_SUB_LEN_CAPABLE_ACK; ++ mpc->ver = opts->mptcp_ver; ++ ptr += MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN >> 2; ++ ++ mpc->sender_key = opts->mp_capable.sender_key; ++ mpc->receiver_key = opts->mp_capable.receiver_key; ++ } ++ ++ mpc->sub = MPTCP_SUB_CAPABLE; ++ mpc->a = opts->dss_csum; ++ mpc->b = 0; ++ mpc->rsv = 0; ++ mpc->h = 1; ++ } ++ if (unlikely(OPTION_MP_JOIN & opts->mptcp_options)) { ++ struct mp_join *mpj = (struct mp_join *)ptr; ++ ++ mpj->kind = TCPOPT_MPTCP; ++ mpj->sub = MPTCP_SUB_JOIN; ++ mpj->rsv = 0; ++ ++ if (OPTION_TYPE_SYN & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYN; ++ mpj->u.syn.token = opts->mp_join_syns.token; ++ mpj->u.syn.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYN_ALIGN >> 2; ++ } else if (OPTION_TYPE_SYNACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_SYNACK; ++ mpj->u.synack.mac = ++ opts->mp_join_syns.sender_truncated_mac; ++ mpj->u.synack.nonce = opts->mp_join_syns.sender_nonce; ++ mpj->b = opts->mp_join_syns.low_prio; ++ mpj->addr_id = opts->addr_id; ++ ptr += MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN >> 2; ++ } else if (OPTION_TYPE_ACK & opts->mptcp_options) { ++ mpj->len = MPTCP_SUB_LEN_JOIN_ACK; ++ mpj->addr_id = 0; /* addr_id is rsv (RFC 6824, p. 21) */ ++ memcpy(mpj->u.ack.mac, &tp->mptcp->sender_mac[0], 20); ++ ptr += MPTCP_SUB_LEN_JOIN_ACK_ALIGN >> 2; ++ } ++ } ++ if (unlikely(OPTION_ADD_ADDR & opts->mptcp_options)) { ++ struct mp_add_addr *mpadd = (struct mp_add_addr *)ptr; ++ struct mptcp_cb *mpcb = tp->mpcb; ++ ++ mpadd->kind = TCPOPT_MPTCP; ++ if (opts->add_addr_v4) { ++ mpadd->addr_id = opts->add_addr4.addr_id; ++ mpadd->u.v4.addr = opts->add_addr4.addr; ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->u_bit.v0.sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->u_bit.v0.ipver = 4; ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN >> 2; ++ } else { ++ mpadd->u_bit.v1.sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->u_bit.v1.rsv = 0; ++ mpadd->u_bit.v1.echo = 0; ++ memcpy((char *)mpadd->u.v4.mac - 2, ++ (char *)&opts->add_addr4.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR4_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1 >> 2; ++ } ++ } else if (opts->add_addr_v6) { ++ mpadd->addr_id = opts->add_addr6.addr_id; ++ memcpy(&mpadd->u.v6.addr, &opts->add_addr6.addr, ++ sizeof(mpadd->u.v6.addr)); ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) { ++ mpadd->u_bit.v0.sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->u_bit.v0.ipver = 6; ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN >> 2; ++ } else { ++ mpadd->u_bit.v1.sub = MPTCP_SUB_ADD_ADDR; ++ mpadd->u_bit.v1.rsv = 0; ++ mpadd->u_bit.v1.echo = 0; ++ memcpy((char *)mpadd->u.v6.mac - 2, ++ (char *)&opts->add_addr6.trunc_mac, 8); ++ mpadd->len = MPTCP_SUB_LEN_ADD_ADDR6_VER1; ++ ptr += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1 >> 2; ++ } ++ } ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_ADDADDRTX); ++ } ++ if (unlikely(OPTION_REMOVE_ADDR & opts->mptcp_options)) { ++ struct mp_remove_addr *mprem = (struct mp_remove_addr *)ptr; ++ u8 *addrs_id; ++ int id, len, len_align; ++ ++ len = mptcp_sub_len_remove_addr(opts->remove_addrs); ++ len_align = mptcp_sub_len_remove_addr_align(opts->remove_addrs); ++ ++ mprem->kind = TCPOPT_MPTCP; ++ mprem->len = len; ++ mprem->sub = MPTCP_SUB_REMOVE_ADDR; ++ mprem->rsv = 0; ++ addrs_id = &mprem->addrs_id; ++ ++ mptcp_for_each_bit_set(opts->remove_addrs, id) ++ *(addrs_id++) = id; ++ ++ /* Fill the rest with NOP's */ ++ if (len_align > len) { ++ int i; ++ for (i = 0; i < len_align - len; i++) ++ *(addrs_id++) = TCPOPT_NOP; ++ } ++ ++ ptr += len_align >> 2; ++ ++ MPTCP_INC_STATS(sock_net((struct sock *)tp), MPTCP_MIB_REMADDRTX); ++ } ++ if (unlikely(OPTION_MP_FAIL & opts->mptcp_options)) { ++ struct mp_fail *mpfail = (struct mp_fail *)ptr; ++ ++ mpfail->kind = TCPOPT_MPTCP; ++ mpfail->len = MPTCP_SUB_LEN_FAIL; ++ mpfail->sub = MPTCP_SUB_FAIL; ++ mpfail->rsv1 = 0; ++ mpfail->rsv2 = 0; ++ mpfail->data_seq = htonll(tp->mpcb->csum_cutoff_seq); ++ ++ ptr += MPTCP_SUB_LEN_FAIL_ALIGN >> 2; ++ } ++ if (unlikely(OPTION_MP_FCLOSE & opts->mptcp_options)) { ++ struct mp_fclose *mpfclose = (struct mp_fclose *)ptr; ++ ++ mpfclose->kind = TCPOPT_MPTCP; ++ mpfclose->len = MPTCP_SUB_LEN_FCLOSE; ++ mpfclose->sub = MPTCP_SUB_FCLOSE; ++ mpfclose->rsv1 = 0; ++ mpfclose->rsv2 = 0; ++ mpfclose->key = opts->mp_capable.receiver_key; ++ ++ ptr += MPTCP_SUB_LEN_FCLOSE_ALIGN >> 2; ++ } ++ ++ if (OPTION_DATA_ACK & opts->mptcp_options) { ++ if (!mptcp_is_data_seq(skb) && tp->mpcb->rem_key_set) ++ ptr += mptcp_write_dss_data_ack(tp, skb, ptr); ++ else if (mptcp_is_data_mpcapable(skb)) ++ ptr += mptcp_write_mpcapable_data(tp, skb, ptr); ++ else ++ ptr += mptcp_write_dss_data_seq(tp, skb, ptr); ++ } ++ if (unlikely(OPTION_MP_PRIO & opts->mptcp_options)) { ++ struct mp_prio *mpprio = (struct mp_prio *)ptr; ++ ++ mpprio->kind = TCPOPT_MPTCP; ++ mpprio->len = MPTCP_SUB_LEN_PRIO; ++ mpprio->sub = MPTCP_SUB_PRIO; ++ mpprio->rsv = 0; ++ mpprio->b = tp->mptcp->low_prio; ++ mpprio->addr_id = TCPOPT_NOP; ++ ++ ptr += MPTCP_SUB_LEN_PRIO_ALIGN >> 2; ++ } ++} ++ ++/* Sends the datafin */ ++void mptcp_send_fin(struct sock *meta_sk) ++{ ++ struct sk_buff *skb, *tskb = tcp_write_queue_tail(meta_sk); ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ int mss_now; ++ ++ if ((1 << meta_sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK)) ++ meta_tp->mpcb->passive_close = 1; ++ ++ /* Optimization, tack on the FIN if we have a queue of ++ * unsent frames. But be careful about outgoing SACKS ++ * and IP options. ++ */ ++ mss_now = mptcp_current_mss(meta_sk); ++ ++ if (tskb) { ++ TCP_SKB_CB(tskb)->mptcp_flags |= MPTCPHDR_FIN; ++ TCP_SKB_CB(tskb)->end_seq++; ++ meta_tp->write_seq++; ++ } else { ++ /* Socket is locked, keep trying until memory is available. */ ++ for (;;) { ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, ++ meta_sk->sk_allocation); ++ if (skb) ++ break; ++ yield(); ++ } ++ /* Reserve space for headers and prepare control bits. */ ++ INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); ++ skb_reserve(skb, MAX_TCP_HEADER); ++ ++ tcp_init_nondata_skb(skb, meta_tp->write_seq, TCPHDR_ACK); ++ TCP_SKB_CB(skb)->end_seq++; ++ TCP_SKB_CB(skb)->mptcp_flags |= MPTCPHDR_FIN; ++ tcp_queue_skb(meta_sk, skb); ++ } ++ __tcp_push_pending_frames(meta_sk, mss_now, TCP_NAGLE_OFF); ++} ++ ++void mptcp_send_active_reset(struct sock *meta_sk, gfp_t priority) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct sock *sk; ++ ++ if (hlist_empty(&mpcb->conn_list)) ++ return; ++ ++ WARN_ON(meta_tp->send_mp_fclose); ++ ++ /* First - select a socket */ ++ sk = mptcp_select_ack_sock(meta_sk); ++ ++ /* May happen if no subflow is in an appropriate state, OR ++ * we are in infinite mode or about to go there - just send a reset ++ */ ++ if (!sk || mptcp_in_infinite_mapping_weak(mpcb)) { ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, NULL); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ return; ++ } ++ ++ tcp_mstamp_refresh(meta_tp); ++ ++ tcp_sk(sk)->send_mp_fclose = 1; ++ /** Reset all other subflows */ ++ ++ /* tcp_done must be handled with bh disabled */ ++ if (!in_serving_softirq()) ++ local_bh_disable(); ++ ++ mptcp_sub_force_close_all(mpcb, sk); ++ ++ tcp_set_state(sk, TCP_RST_WAIT); ++ ++ if (!in_serving_softirq()) ++ local_bh_enable(); ++ ++ tcp_send_ack(sk); ++ tcp_clear_xmit_timers(sk); ++ inet_csk_reset_keepalive_timer(sk, inet_csk(sk)->icsk_rto); ++ ++ meta_tp->send_mp_fclose = 1; ++ inet_csk(sk)->icsk_retransmits = 0; ++ ++ /* Prevent exp backoff reverting on ICMP dest unreachable */ ++ inet_csk(sk)->icsk_backoff = 0; ++ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_FASTCLOSETX); ++} ++ ++static void mptcp_ack_retransmit_timer(struct sock *sk) ++{ ++ struct inet_connection_sock *icsk = inet_csk(sk); ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ struct sk_buff *skb; ++ ++ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) ++ goto out; /* Routing failure or similar */ ++ ++ tcp_mstamp_refresh(tp); ++ ++ if (tcp_write_timeout(sk)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRTO); ++ tp->mptcp->pre_established = 0; ++ sk_stop_timer(sk, &tp->mptcp->mptcp_ack_timer); ++ tp->ops->send_active_reset(sk, GFP_ATOMIC); ++ goto out; ++ } ++ ++ skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ if (skb == NULL) { ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ /* Reserve space for headers and prepare control bits */ ++ skb_reserve(skb, MAX_TCP_HEADER); ++ tcp_init_nondata_skb(skb, tp->snd_una, TCPHDR_ACK); ++ ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKRXMIT); ++ ++ if (tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC) > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!icsk->icsk_retransmits) ++ icsk->icsk_retransmits = 1; ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ return; ++ } ++ ++ if (!tp->retrans_stamp) ++ tp->retrans_stamp = tcp_time_stamp(tp) ? : 1; ++ ++ icsk->icsk_retransmits++; ++ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); ++ sk_reset_timer(sk, &tp->mptcp->mptcp_ack_timer, ++ jiffies + icsk->icsk_rto); ++ if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0)) ++ __sk_dst_reset(sk); ++ ++out:; ++} ++ ++void mptcp_ack_handler(struct timer_list *t) ++{ ++ struct mptcp_tcp_sock *mptcp = from_timer(mptcp, t, mptcp_ack_timer); ++ struct sock *sk = (struct sock *)mptcp->tp; ++ struct sock *meta_sk = mptcp_meta_sk(sk); ++ ++ bh_lock_sock(meta_sk); ++ if (sock_owned_by_user(meta_sk)) { ++ /* Try again later */ ++ sk_reset_timer(sk, &tcp_sk(sk)->mptcp->mptcp_ack_timer, ++ jiffies + (HZ / 20)); ++ goto out_unlock; ++ } ++ ++ if (sk->sk_state == TCP_CLOSE) ++ goto out_unlock; ++ if (!tcp_sk(sk)->mptcp->pre_established) ++ goto out_unlock; ++ ++ mptcp_ack_retransmit_timer(sk); ++ ++ sk_mem_reclaim(sk); ++ ++out_unlock: ++ bh_unlock_sock(meta_sk); ++ sock_put(sk); ++} ++ ++/* Similar to tcp_retransmit_skb ++ * ++ * The diff is that we handle the retransmission-stats (retrans_stamp) at the ++ * meta-level. ++ */ ++int mptcp_retransmit_skb(struct sock *meta_sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct sock *subsk; ++ unsigned int limit, mss_now; ++ int err = -1; ++ ++ WARN_ON(TCP_SKB_CB(skb)->sacked); ++ ++ /* Do not sent more than we queued. 1/4 is reserved for possible ++ * copying overhead: fragmentation, tunneling, mangling etc. ++ * ++ * This is a meta-retransmission thus we check on the meta-socket. ++ */ ++ if (refcount_read(&meta_sk->sk_wmem_alloc) > ++ min(meta_sk->sk_wmem_queued + (meta_sk->sk_wmem_queued >> 2), meta_sk->sk_sndbuf)) { ++ return -EAGAIN; ++ } ++ ++ /* We need to make sure that the retransmitted segment can be sent on a ++ * subflow right now. If it is too big, it needs to be fragmented. ++ */ ++ subsk = meta_tp->mpcb->sched_ops->get_subflow(meta_sk, skb, false); ++ if (!subsk) { ++ /* We want to increase icsk_retransmits, thus return 0, so that ++ * mptcp_meta_retransmit_timer enters the desired branch. ++ */ ++ err = 0; ++ goto failed; ++ } ++ mss_now = tcp_current_mss(subsk); ++ ++ /* If the segment was cloned (e.g. a meta retransmission), the header ++ * must be expanded/copied so that there is no corruption of TSO ++ * information. ++ */ ++ if (skb_unclone(skb, GFP_ATOMIC)) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Must have been set by mptcp_write_xmit before */ ++ BUG_ON(!tcp_skb_pcount(skb)); ++ ++ limit = mss_now; ++ /* skb->len > mss_now is the equivalent of tso_segs > 1 in ++ * tcp_write_xmit. Otherwise split-point would return 0. ++ */ ++ if (skb->len > mss_now && !tcp_urg_mode(meta_tp)) ++ limit = tcp_mss_split_point(meta_sk, skb, mss_now, ++ UINT_MAX / mss_now, ++ TCP_NAGLE_OFF); ++ ++ limit = min(limit, tcp_wnd_end(meta_tp) - TCP_SKB_CB(skb)->seq); ++ ++ if (skb->len > limit && ++ unlikely(mptcp_fragment(meta_sk, TCP_FRAG_IN_RTX_QUEUE, skb, ++ limit, GFP_ATOMIC, 0))) ++ goto failed; ++ ++ if (!mptcp_skb_entail(subsk, skb, -1)) ++ goto failed; ++ ++ /* Update global TCP statistics. */ ++ MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_RETRANSSEGS); ++ ++ /* Diff to tcp_retransmit_skb */ ++ ++ /* Save stamp of the first retransmit. */ ++ if (!meta_tp->retrans_stamp) { ++ tcp_mstamp_refresh(meta_tp); ++ meta_tp->retrans_stamp = tcp_time_stamp(meta_tp); ++ } ++ ++ __tcp_push_pending_frames(subsk, mss_now, TCP_NAGLE_PUSH); ++ tcp_update_skb_after_send(meta_sk, skb, meta_tp->tcp_wstamp_ns); ++ meta_tp->lsndtime = tcp_jiffies32; ++ ++ return 0; ++ ++failed: ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPRETRANSFAIL); ++ return err; ++} ++ ++/* Similar to tcp_retransmit_timer ++ * ++ * The diff is that we have to handle retransmissions of the FAST_CLOSE-message ++ * and that we don't have an srtt estimation at the meta-level. ++ */ ++void mptcp_meta_retransmit_timer(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct inet_connection_sock *meta_icsk = inet_csk(meta_sk); ++ int err; ++ ++ /* In fallback, retransmission is handled at the subflow-level */ ++ if (!meta_tp->packets_out || mpcb->infinite_mapping_snd) ++ return; ++ ++ WARN_ON(tcp_rtx_queue_empty(meta_sk)); ++ ++ if (!meta_tp->snd_wnd && !sock_flag(meta_sk, SOCK_DEAD) && ++ !((1 << meta_sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { ++ /* Receiver dastardly shrinks window. Our retransmits ++ * become zero probes, but we should not timeout this ++ * connection. If the socket is an orphan, time it out, ++ * we cannot allow such beasts to hang infinitely. ++ */ ++ struct inet_sock *meta_inet = inet_sk(meta_sk); ++ if (meta_sk->sk_family == AF_INET) { ++ net_dbg_ratelimited("MPTCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_inet->inet_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (meta_sk->sk_family == AF_INET6) { ++ net_dbg_ratelimited("MPTCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", ++ &meta_sk->sk_v6_daddr, ++ ntohs(meta_inet->inet_dport), ++ meta_inet->inet_num, meta_tp->snd_una, ++ meta_tp->snd_nxt); ++ } ++#endif ++ if (tcp_jiffies32 - meta_tp->rcv_tstamp > TCP_RTO_MAX) { ++ tcp_write_err(meta_sk); ++ return; ++ } ++ ++ mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ goto out_reset_timer; ++ } ++ ++ if (tcp_write_timeout(meta_sk)) ++ return; ++ ++ if (meta_icsk->icsk_retransmits == 0) ++ __NET_INC_STATS(sock_net(meta_sk), LINUX_MIB_TCPTIMEOUTS); ++ ++ meta_icsk->icsk_ca_state = TCP_CA_Loss; ++ ++ err = mptcp_retransmit_skb(meta_sk, tcp_rtx_queue_head(meta_sk)); ++ if (err > 0) { ++ /* Retransmission failed because of local congestion, ++ * do not backoff. ++ */ ++ if (!meta_icsk->icsk_retransmits) ++ meta_icsk->icsk_retransmits = 1; ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, ++ min(meta_icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), ++ TCP_RTO_MAX); ++ return; ++ } ++ ++ /* Increase the timeout each time we retransmit. Note that ++ * we do not increase the rtt estimate. rto is initialized ++ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests ++ * that doubling rto each time is the least we can get away with. ++ * In KA9Q, Karn uses this for the first few times, and then ++ * goes to quadratic. netBSD doubles, but only goes up to *64, ++ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is ++ * defined in the protocol as the maximum possible RTT. I guess ++ * we'll have to use something other than TCP to talk to the ++ * University of Mars. ++ * ++ * PAWS allows us longer timeouts and large windows, so once ++ * implemented ftp to mars will work nicely. We will have to fix ++ * the 120 second clamps though! ++ */ ++ meta_icsk->icsk_backoff++; ++ meta_icsk->icsk_retransmits++; ++ ++out_reset_timer: ++ /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is ++ * used to reset timer, set to 0. Recalculate 'icsk_rto' as this ++ * might be increased if the stream oscillates between thin and thick, ++ * thus the old value might already be too high compared to the value ++ * set by 'tcp_set_rto' in tcp_input.c which resets the rto without ++ * backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating ++ * exponential backoff behaviour to avoid continue hammering ++ * linear-timeout retransmissions into a black hole ++ */ ++ if (meta_sk->sk_state == TCP_ESTABLISHED && ++ (meta_tp->thin_lto || sock_net(meta_sk)->ipv4.sysctl_tcp_thin_linear_timeouts) && ++ tcp_stream_is_thin(meta_tp) && ++ meta_icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { ++ meta_icsk->icsk_backoff = 0; ++ /* We cannot do the same as in tcp_write_timer because the ++ * srtt is not set here. ++ */ ++ mptcp_set_rto(meta_sk); ++ } else { ++ /* Use normal (exponential) backoff */ ++ meta_icsk->icsk_rto = min(meta_icsk->icsk_rto << 1, TCP_RTO_MAX); ++ } ++ inet_csk_reset_xmit_timer(meta_sk, ICSK_TIME_RETRANS, meta_icsk->icsk_rto, TCP_RTO_MAX); ++ ++ return; ++} ++ ++void mptcp_sub_retransmit_timer(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_retransmit_timer(sk); ++ ++ if (!tp->fastopen_rsk) { ++ mptcp_reinject_data(sk, 1); ++ mptcp_set_rto(sk); ++ } ++} ++ ++/* Modify values to an mptcp-level for the initial window of new subflows */ ++void mptcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, ++ __u32 *rcv_wnd, __u32 *window_clamp, ++ int wscale_ok, __u8 *rcv_wscale, ++ __u32 init_rcv_wnd) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb; ++ ++ *window_clamp = mpcb->orig_window_clamp; ++ __space = tcp_win_from_space(sk, mpcb->orig_sk_rcvbuf); ++ ++ tcp_select_initial_window(sk, __space, mss, rcv_wnd, window_clamp, ++ wscale_ok, rcv_wscale, init_rcv_wnd); ++} ++ ++static inline u64 mptcp_calc_rate(const struct sock *meta_sk, unsigned int mss) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ u64 rate = 0; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ /* Do not consider subflows without a RTT estimation yet ++ * otherwise this_rate >>> rate. ++ */ ++ if (unlikely(!tp->srtt_us)) ++ continue; ++ ++ this_mss = tcp_current_mss(sk); ++ ++ /* If this_mss is smaller than mss, it means that a segment will ++ * be splitted in two (or more) when pushed on this subflow. If ++ * you consider that mss = 1428 and this_mss = 1420 then two ++ * segments will be generated: a 1420-byte and 8-byte segment. ++ * The latter will introduce a large overhead as for a single ++ * data segment 2 slots will be used in the congestion window. ++ * Therefore reducing by ~2 the potential throughput of this ++ * subflow. Indeed, 1428 will be send while 2840 could have been ++ * sent if mss == 1420 reducing the throughput by 2840 / 1428. ++ * ++ * The following algorithm take into account this overhead ++ * when computing the potential throughput that MPTCP can ++ * achieve when generating mss-byte segments. ++ * ++ * The formulae is the following: ++ * \sum_{\forall sub} ratio * \frac{mss * cwnd_sub}{rtt_sub} ++ * Where ratio is computed as follows: ++ * \frac{mss}{\ceil{mss / mss_sub} * mss_sub} ++ * ++ * ratio gives the reduction factor of the theoretical ++ * throughput a subflow can achieve if MPTCP uses a specific ++ * MSS value. ++ */ ++ this_rate = div64_u64((u64)mss * mss * (USEC_PER_SEC << 3) * ++ max(tp->snd_cwnd, tp->packets_out), ++ (u64)tp->srtt_us * ++ DIV_ROUND_UP(mss, this_mss) * this_mss); ++ rate += this_rate; ++ } ++ ++ return rate; ++} ++ ++static unsigned int __mptcp_current_mss(const struct sock *meta_sk) ++{ ++ struct mptcp_tcp_sock *mptcp; ++ unsigned int mss = 0; ++ u64 rate = 0; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ int this_mss; ++ u64 this_rate; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_mss = tcp_current_mss(sk); ++ ++ /* Same mss values will produce the same throughput. */ ++ if (this_mss == mss) ++ continue; ++ ++ /* See whether using this mss value can theoretically improve ++ * the performances. ++ */ ++ this_rate = mptcp_calc_rate(meta_sk, this_mss); ++ if (this_rate >= rate) { ++ mss = this_mss; ++ rate = this_rate; ++ } ++ } ++ ++ return mss; ++} ++ ++unsigned int mptcp_current_mss(struct sock *meta_sk) ++{ ++ unsigned int mss = __mptcp_current_mss(meta_sk); ++ ++ /* If no subflow is available, we take a default-mss from the ++ * meta-socket. ++ */ ++ return !mss ? tcp_current_mss(meta_sk) : mss; ++} ++ ++int mptcp_check_snd_buf(const struct tcp_sock *tp) ++{ ++ const struct mptcp_tcp_sock *mptcp; ++ u32 rtt_max = tp->srtt_us; ++ u64 bw_est; ++ ++ if (!tp->srtt_us) ++ return tp->reordering + 1; ++ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ const struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ if (rtt_max < tcp_sk(sk)->srtt_us) ++ rtt_max = tcp_sk(sk)->srtt_us; ++ } ++ ++ bw_est = div64_u64(((u64)tp->snd_cwnd * rtt_max) << 16, ++ (u64)tp->srtt_us); ++ ++ return max_t(unsigned int, (u32)(bw_est >> 16), ++ tp->reordering + 1); ++} ++ ++unsigned int mptcp_xmit_size_goal(const struct sock *meta_sk, u32 mss_now, ++ int large_allowed) ++{ ++ u32 xmit_size_goal = 0; ++ ++ if (large_allowed && !tcp_sk(meta_sk)->mpcb->dss_csum) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(tcp_sk(meta_sk)->mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ int this_size_goal; ++ ++ if (!mptcp_sk_can_send(sk)) ++ continue; ++ ++ this_size_goal = tcp_xmit_size_goal(sk, mss_now, 1); ++ if (this_size_goal > xmit_size_goal) ++ xmit_size_goal = this_size_goal; ++ } ++ } ++ ++ return max(xmit_size_goal, mss_now); ++} ++ +diff -aurN linux-5.4.64/net/mptcp/mptcp_pm.c linux-5.4.64.mptcp/net/mptcp/mptcp_pm.c +--- linux-5.4.64/net/mptcp/mptcp_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_pm.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,226 @@ ++/* ++ * MPTCP implementation - MPTCP-subflow-management ++ * ++ * Initial Design & Implementation: ++ * Sébastien Barré ++ * ++ * Current Maintainer & Author: ++ * Christoph Paasch ++ * ++ * Additional authors: ++ * Jaakko Korkeaniemi ++ * Gregory Detal ++ * Fabien Duchêne ++ * Andreas Seelinger ++ * Lavkesh Lahngir ++ * Andreas Ripke ++ * Vlad Dogaru ++ * Octavian Purdila ++ * John Ronan ++ * Catalin Nicutar ++ * Brandon Heller ++ * ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_pm_list_lock); ++static LIST_HEAD(mptcp_pm_list); ++ ++static int mptcp_default_id(const struct sock *meta_sk, sa_family_t family, ++ union inet_addr *addr, bool *low_prio) ++{ ++ return 0; ++} ++ ++struct mptcp_pm_ops mptcp_pm_default = { ++ .get_local_id = mptcp_default_id, /* We do not care */ ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_pm_ops *mptcp_pm_find(const char *name) ++{ ++ struct mptcp_pm_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_pm_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_path_manager(struct mptcp_pm_ops *pm) ++{ ++ int ret = 0; ++ ++ if (!pm->get_local_id) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ if (mptcp_pm_find(pm->name)) { ++ pr_notice("%s already registered\n", pm->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&pm->list, &mptcp_pm_list); ++ pr_info("%s registered\n", pm->name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_path_manager); ++ ++void mptcp_unregister_path_manager(struct mptcp_pm_ops *pm) ++{ ++ spin_lock(&mptcp_pm_list_lock); ++ list_del_rcu(&pm->list); ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_path_manager); ++ ++void mptcp_get_default_path_manager(char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ BUG_ON(list_empty(&mptcp_pm_list)); ++ ++ rcu_read_lock(); ++ pm = list_entry(mptcp_pm_list.next, struct mptcp_pm_ops, list); ++ strncpy(name, pm->name, MPTCP_PM_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_path_manager(const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_pm_list_lock); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ ++ if (pm) { ++ list_move(&pm->list, &mptcp_pm_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_pm_list_lock); ++ ++ return ret; ++} ++ ++static struct mptcp_pm_ops *__mptcp_pm_find_autoload(const char *name) ++{ ++ struct mptcp_pm_ops *pm = mptcp_pm_find(name); ++#ifdef CONFIG_MODULES ++ if (!pm && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ pm = mptcp_pm_find(name); ++ } ++#endif ++ return pm; ++} ++ ++void mptcp_init_path_manager(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if path manager was set using socket option */ ++ if (meta_tp->mptcp_pm_setsockopt) { ++ pm = __mptcp_pm_find_autoload(meta_tp->mptcp_pm_name); ++ if (pm && try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(pm, &mptcp_pm_list, list) { ++ if (try_module_get(pm->owner)) { ++ mpcb->pm_ops = pm; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change path manager for socket */ ++int mptcp_set_path_manager(struct sock *sk, const char *name) ++{ ++ struct mptcp_pm_ops *pm; ++ int err = 0; ++ ++ rcu_read_lock(); ++ pm = __mptcp_pm_find_autoload(name); ++ ++ if (!pm) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_pm_name, name); ++ tcp_sk(sk)->mptcp_pm_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_path_manager(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->pm_ops->owner); ++} ++ ++/* Fallback to the default path-manager. */ ++void mptcp_fallback_default(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_pm_ops *pm; ++ ++ mptcp_cleanup_path_manager(mpcb); ++ pm = mptcp_pm_find("default"); ++ ++ /* Cannot fail - it's the default module */ ++ try_module_get(pm->owner); ++ mpcb->pm_ops = pm; ++} ++EXPORT_SYMBOL_GPL(mptcp_fallback_default); ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_path_manager_default(void) ++{ ++ return mptcp_set_default_path_manager(CONFIG_DEFAULT_MPTCP_PM); ++} ++late_initcall(mptcp_path_manager_default); +diff -aurN linux-5.4.64/net/mptcp/mptcp_redundant.c linux-5.4.64.mptcp/net/mptcp/mptcp_redundant.c +--- linux-5.4.64/net/mptcp/mptcp_redundant.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_redundant.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,392 @@ ++/* ++ * MPTCP Scheduler to reduce latency and jitter. ++ * ++ * This scheduler sends all packets redundantly on all available subflows. ++ * ++ * Initial Design & Implementation: ++ * Tobias Erbshaeusser ++ * Alexander Froemmgen ++ * ++ * Initial corrections & modifications: ++ * Christian Pinedo ++ * Igor Lopez ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++/* Struct to store the data of a single subflow */ ++struct redsched_priv { ++ /* The skb or NULL */ ++ struct sk_buff *skb; ++ /* End sequence number of the skb. This number should be checked ++ * to be valid before the skb field is used ++ */ ++ u32 skb_end_seq; ++}; ++ ++/* Struct to store the data of the control block */ ++struct redsched_cb { ++ /* The next subflow where a skb should be sent or NULL */ ++ struct tcp_sock *next_subflow; ++}; ++ ++/* Returns the socket data from a given subflow socket */ ++static struct redsched_priv *redsched_get_priv(struct tcp_sock *tp) ++{ ++ return (struct redsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* Returns the control block data from a given meta socket */ ++static struct redsched_cb *redsched_get_cb(struct tcp_sock *tp) ++{ ++ return (struct redsched_cb *)&tp->mpcb->mptcp_sched[0]; ++} ++ ++static bool redsched_get_active_valid_sks(struct sock *meta_sk) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct mptcp_tcp_sock *mptcp; ++ int active_valid_sks = 0; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (subflow_is_active((struct tcp_sock *)sk) && ++ !mptcp_is_def_unavailable(sk)) ++ active_valid_sks++; ++ } ++ ++ return active_valid_sks; ++} ++ ++static bool redsched_use_subflow(struct sock *meta_sk, ++ int active_valid_sks, ++ struct tcp_sock *tp, ++ struct sk_buff *skb) ++{ ++ if (!skb || !mptcp_is_available((struct sock *)tp, skb, false)) ++ return false; ++ ++ if (TCP_SKB_CB(skb)->path_mask != 0) ++ return subflow_is_active(tp); ++ ++ if (TCP_SKB_CB(skb)->path_mask == 0) { ++ if (active_valid_sks == -1) ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ if (subflow_is_backup(tp) && active_valid_sks > 0) ++ return false; ++ else ++ return true; ++ } ++ ++ return false; ++} ++ ++#define mptcp_entry_next_rcu(__mptcp) \ ++ hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ ++ &(__mptcp)->node)), struct mptcp_tcp_sock, node) ++ ++static void redsched_update_next_subflow(struct tcp_sock *tp, ++ struct redsched_cb *red_cb) ++{ ++ struct mptcp_tcp_sock *mptcp = mptcp_entry_next_rcu(tp->mptcp); ++ ++ if (mptcp) ++ red_cb->next_subflow = mptcp->tp; ++ else ++ red_cb->next_subflow = NULL; ++} ++ ++static struct sock *red_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb *red_cb = redsched_get_cb(meta_tp); ++ struct tcp_sock *first_tp = red_cb->next_subflow, *tp; ++ struct mptcp_tcp_sock *mptcp; ++ int found = 0; ++ ++ /* Answer data_fin on same subflow */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk)->mptcp->path_index == ++ mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ if (!first_tp && !hlist_empty(&mpcb->conn_list)) { ++ first_tp = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(&mpcb->conn_list)), ++ struct mptcp_tcp_sock, node)->tp; ++ } ++ tp = first_tp; ++ ++ /* still NULL (no subflow in conn_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ /* Search for a subflow to send it. ++ * ++ * We want to pick a subflow that is after 'first_tp' in the list of subflows. ++ * Thus, the first mptcp_for_each_sub()-loop tries to walk the list up ++ * to the subflow 'tp' and then checks whether any one of the remaining ++ * ones is eligible to send. ++ * The second mptcp_for_each-sub()-loop is then iterating from the ++ * beginning of the list up to 'first_tp'. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ /* We go up to the subflow 'tp' and start from there */ ++ if (tp == mptcp->tp) ++ found = 1; ++ ++ if (!found) ++ continue; ++ tp = mptcp->tp; ++ ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ redsched_update_next_subflow(tp, red_cb); ++ return (struct sock *)tp; ++ } ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ tp = mptcp->tp; ++ ++ if (tp == first_tp) ++ break; ++ ++ if (mptcp_is_available((struct sock *)tp, skb, ++ zero_wnd_test)) { ++ redsched_update_next_subflow(tp, red_cb); ++ return (struct sock *)tp; ++ } ++ } ++ ++ /* No space */ ++ return NULL; ++} ++ ++/* Corrects the stored skb pointers if they are invalid */ ++static void redsched_correct_skb_pointers(struct sock *meta_sk, ++ struct redsched_priv *red_p) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ if (red_p->skb && ++ (!after(red_p->skb_end_seq, meta_tp->snd_una) || ++ after(red_p->skb_end_seq, meta_tp->snd_nxt))) ++ red_p->skb = NULL; ++} ++ ++/* Returns the next skb from the queue */ ++static struct sk_buff *redsched_next_skb_from_queue(struct sk_buff_head *queue, ++ struct sk_buff *previous, ++ struct sock *meta_sk) ++{ ++ struct sk_buff *skb; ++ ++ if (!previous) ++ return tcp_rtx_queue_head(meta_sk) ? : skb_peek(queue); ++ ++ /* sk_data->skb stores the last scheduled packet for this subflow. ++ * If sk_data->skb was scheduled but not sent (e.g., due to nagle), ++ * we have to schedule it again. ++ * ++ * For the redundant scheduler, there are two cases: ++ * 1. sk_data->skb was not sent on another subflow: ++ * we have to schedule it again to ensure that we do not ++ * skip this packet. ++ * 2. sk_data->skb was already sent on another subflow: ++ * with regard to the redundant semantic, we have to ++ * schedule it again. However, we keep it simple and ignore it, ++ * as it was already sent by another subflow. ++ * This might be changed in the future. ++ * ++ * For case 1, send_head is equal previous, as only a single ++ * packet can be skipped. ++ */ ++ if (tcp_send_head(meta_sk) == previous) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_rb_next(previous); ++ if (skb) ++ return skb; ++ ++ return tcp_send_head(meta_sk); ++} ++ ++static struct sk_buff *mptcp_red_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ struct mptcp_cb *mpcb = meta_tp->mpcb; ++ struct redsched_cb *red_cb = redsched_get_cb(meta_tp); ++ struct tcp_sock *first_tp = red_cb->next_subflow, *tp; ++ struct mptcp_tcp_sock *mptcp; ++ int active_valid_sks = -1; ++ struct sk_buff *skb; ++ int found = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (skb_queue_empty(&mpcb->reinject_queue) && ++ skb_queue_empty(&meta_sk->sk_write_queue) && ++ tcp_rtx_queue_empty(meta_sk)) ++ /* Nothing to send */ ++ return NULL; ++ ++ /* First try reinjections */ ++ skb = skb_peek(&mpcb->reinject_queue); ++ if (skb) { ++ *subsk = get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ *reinject = 1; ++ return skb; ++ } ++ ++ /* Then try indistinctly redundant and normal skbs */ ++ ++ if (!first_tp && !hlist_empty(&mpcb->conn_list)) { ++ first_tp = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(&mpcb->conn_list)), ++ struct mptcp_tcp_sock, node)->tp; ++ } ++ ++ /* still NULL (no subflow in conn_list?) */ ++ if (!first_tp) ++ return NULL; ++ ++ tp = first_tp; ++ ++ *reinject = 0; ++ active_valid_sks = redsched_get_active_valid_sks(meta_sk); ++ ++ /* We want to pick a subflow that is after 'first_tp' in the list of subflows. ++ * Thus, the first mptcp_for_each_sub()-loop tries to walk the list up ++ * to the subflow 'tp' and then checks whether any one of the remaining ++ * ones can send a segment. ++ * The second mptcp_for_each-sub()-loop is then iterating from the ++ * beginning of the list up to 'first_tp'. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct redsched_priv *red_p; ++ ++ if (tp == mptcp->tp) ++ found = 1; ++ ++ if (!found) ++ continue; ++ ++ tp = mptcp->tp; ++ ++ /* Correct the skb pointers of the current subflow */ ++ red_p = redsched_get_priv(tp); ++ redsched_correct_skb_pointers(meta_sk, red_p); ++ ++ skb = redsched_next_skb_from_queue(&meta_sk->sk_write_queue, ++ red_p->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ red_p->skb = skb; ++ red_p->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ redsched_update_next_subflow(tp, red_cb); ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ } ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct redsched_priv *red_p; ++ ++ tp = mptcp->tp; ++ ++ if (tp == first_tp) ++ break; ++ ++ /* Correct the skb pointers of the current subflow */ ++ red_p = redsched_get_priv(tp); ++ redsched_correct_skb_pointers(meta_sk, red_p); ++ ++ skb = redsched_next_skb_from_queue(&meta_sk->sk_write_queue, ++ red_p->skb, meta_sk); ++ if (skb && redsched_use_subflow(meta_sk, active_valid_sks, tp, ++ skb)) { ++ red_p->skb = skb; ++ red_p->skb_end_seq = TCP_SKB_CB(skb)->end_seq; ++ redsched_update_next_subflow(tp, red_cb); ++ *subsk = (struct sock *)tp; ++ ++ if (TCP_SKB_CB(skb)->path_mask) ++ *reinject = -1; ++ return skb; ++ } ++ } ++ ++ /* Nothing to send */ ++ return NULL; ++} ++ ++static void redsched_release(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct redsched_cb *red_cb = redsched_get_cb(tp); ++ ++ /* Check if the next subflow would be the released one. If yes correct ++ * the pointer ++ */ ++ if (red_cb->next_subflow == tp) ++ redsched_update_next_subflow(tp, red_cb); ++} ++ ++static struct mptcp_sched_ops mptcp_sched_red = { ++ .get_subflow = red_get_available_subflow, ++ .next_segment = mptcp_red_next_segment, ++ .release = redsched_release, ++ .name = "redundant", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init red_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct redsched_priv) > MPTCP_SCHED_SIZE); ++ BUILD_BUG_ON(sizeof(struct redsched_cb) > MPTCP_SCHED_DATA_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_red)) ++ return -1; ++ ++ return 0; ++} ++ ++static void red_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_red); ++} ++ ++module_init(red_register); ++module_exit(red_unregister); ++ ++MODULE_AUTHOR("Tobias Erbshaeusser, Alexander Froemmgen"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("REDUNDANT MPTCP"); ++MODULE_VERSION("0.90"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_rr.c linux-5.4.64.mptcp/net/mptcp/mptcp_rr.c +--- linux-5.4.64/net/mptcp/mptcp_rr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_rr.c 2020-09-10 19:25:10.507220869 +0200 +@@ -0,0 +1,309 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++ ++static unsigned char num_segments __read_mostly = 1; ++module_param(num_segments, byte, 0644); ++MODULE_PARM_DESC(num_segments, "The number of consecutive segments that are part of a burst"); ++ ++static bool cwnd_limited __read_mostly = 1; ++module_param(cwnd_limited, bool, 0644); ++MODULE_PARM_DESC(cwnd_limited, "if set to 1, the scheduler tries to fill the congestion-window on all subflows"); ++ ++struct rrsched_priv { ++ unsigned char quota; ++}; ++ ++static struct rrsched_priv *rrsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct rrsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++/* If the sub-socket sk available to send the skb? */ ++static bool mptcp_rr_is_available(const struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test, bool cwnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int space, in_flight; ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return false; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return false; ++ ++ if (tp->pf) ++ return false; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been acked. ++ * (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return false; ++ else if (tp->snd_una != tp->high_seq) ++ return false; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return false; ++ } ++ ++ if (!cwnd_test) ++ goto zero_wnd_test; ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return false; ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * tp->mss_cache; ++ ++ if (tp->write_seq - tp->snd_nxt > space) ++ return false; ++ ++zero_wnd_test: ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return false; ++ ++ return true; ++} ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_rr_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++/* We just look for any subflow that is available */ ++static struct sock *rr_get_available_subflow(struct sock *meta_sk, ++ struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk = NULL, *bestsk = NULL, *backupsk = NULL; ++ struct mptcp_tcp_sock *mptcp; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ return sk; ++ } ++ } ++ ++ /* First, find the best subflow */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct tcp_sock *tp; ++ ++ sk = mptcp_to_sock(mptcp); ++ tp = tcp_sk(sk); ++ ++ if (!mptcp_rr_is_available(sk, skb, zero_wnd_test, true)) ++ continue; ++ ++ if (mptcp_rr_dont_reinject_skb(tp, skb)) { ++ backupsk = sk; ++ continue; ++ } ++ ++ bestsk = sk; ++ } ++ ++ if (bestsk) { ++ sk = bestsk; ++ } else if (backupsk) { ++ /* It has been sent on all subflows once - let's give it a ++ * chance again by restarting its pathmask. ++ */ ++ if (skb) ++ TCP_SKB_CB(skb)->path_mask = 0; ++ sk = backupsk; ++ } ++ ++ return sk; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_rr_next_segment(const struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) ++ *reinject = 1; ++ else ++ skb = tcp_send_head(meta_sk); ++ return skb; ++} ++ ++static struct sk_buff *mptcp_rr_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *choose_sk = NULL; ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb = __mptcp_rr_next_segment(meta_sk, reinject); ++ unsigned char split = num_segments; ++ unsigned char iter = 0, full_subs = 0; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ if (*reinject) { ++ *subsk = rr_get_available_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ return skb; ++ } ++ ++retry: ++ ++ /* First, we look for a subflow who is currently being used */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rr_p = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ iter++; ++ ++ /* Is this subflow currently being used? */ ++ if (rr_p->quota > 0 && rr_p->quota < num_segments) { ++ split = num_segments - rr_p->quota; ++ choose_sk = sk_it; ++ goto found; ++ } ++ ++ /* Or, it's totally unused */ ++ if (!rr_p->quota) { ++ split = num_segments; ++ choose_sk = sk_it; ++ } ++ ++ /* Or, it must then be fully used */ ++ if (rr_p->quota >= num_segments) ++ full_subs++; ++ } ++ ++ /* All considered subflows have a full quota, and we considered at ++ * least one. ++ */ ++ if (iter && iter == full_subs) { ++ /* So, we restart this round by setting quota to 0 and retry ++ * to find a subflow. ++ */ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk_it = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp_it = tcp_sk(sk_it); ++ struct rrsched_priv *rr_p = rrsched_get_priv(tp_it); ++ ++ if (!mptcp_rr_is_available(sk_it, skb, false, cwnd_limited)) ++ continue; ++ ++ rr_p->quota = 0; ++ } ++ ++ goto retry; ++ } ++ ++found: ++ if (choose_sk) { ++ unsigned int mss_now; ++ struct tcp_sock *choose_tp = tcp_sk(choose_sk); ++ struct rrsched_priv *rr_p = rrsched_get_priv(choose_tp); ++ ++ if (!mptcp_rr_is_available(choose_sk, skb, false, true)) ++ return NULL; ++ ++ *subsk = choose_sk; ++ mss_now = tcp_current_mss(*subsk); ++ *limit = split * mss_now; ++ ++ if (skb->len > mss_now) ++ rr_p->quota += DIV_ROUND_UP(skb->len, mss_now); ++ else ++ rr_p->quota++; ++ ++ return skb; ++ } ++ ++ return NULL; ++} ++ ++static struct mptcp_sched_ops mptcp_sched_rr = { ++ .get_subflow = rr_get_available_subflow, ++ .next_segment = mptcp_rr_next_segment, ++ .name = "roundrobin", ++ .owner = THIS_MODULE, ++}; ++ ++static int __init rr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct rrsched_priv) > MPTCP_SCHED_SIZE); ++ ++ if (mptcp_register_scheduler(&mptcp_sched_rr)) ++ return -1; ++ ++ return 0; ++} ++ ++static void rr_unregister(void) ++{ ++ mptcp_unregister_scheduler(&mptcp_sched_rr); ++} ++ ++module_init(rr_register); ++module_exit(rr_unregister); ++ ++MODULE_AUTHOR("Christoph Paasch"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ROUNDROBIN MPTCP"); ++MODULE_VERSION("0.89"); +diff -aurN linux-5.4.64/net/mptcp/mptcp_sched.c linux-5.4.64.mptcp/net/mptcp/mptcp_sched.c +--- linux-5.4.64/net/mptcp/mptcp_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_sched.c 2020-09-10 19:25:10.511220802 +0200 +@@ -0,0 +1,647 @@ ++/* MPTCP Scheduler module selector. Highly inspired by tcp_cong.c */ ++ ++#include ++#include ++#include ++ ++static DEFINE_SPINLOCK(mptcp_sched_list_lock); ++static LIST_HEAD(mptcp_sched_list); ++ ++struct defsched_priv { ++ u32 last_rbuf_opti; ++}; ++ ++static struct defsched_priv *defsched_get_priv(const struct tcp_sock *tp) ++{ ++ return (struct defsched_priv *)&tp->mptcp->mptcp_sched[0]; ++} ++ ++bool mptcp_is_def_unavailable(struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* Set of states for which we are allowed to send data */ ++ if (!mptcp_sk_can_send(sk)) ++ return true; ++ ++ /* We do not send data on this subflow unless it is ++ * fully established, i.e. the 4th ack has been received. ++ */ ++ if (tp->mptcp->pre_established) ++ return true; ++ ++ if (tp->pf) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(mptcp_is_def_unavailable); ++ ++static bool mptcp_is_temp_unavailable(struct sock *sk, ++ const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ unsigned int mss_now, space, in_flight; ++ ++ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) { ++ /* If SACK is disabled, and we got a loss, TCP does not exit ++ * the loss-state until something above high_seq has been ++ * acked. (see tcp_try_undo_recovery) ++ * ++ * high_seq is the snd_nxt at the moment of the RTO. As soon ++ * as we have an RTO, we won't push data on the subflow. ++ * Thus, snd_una can never go beyond high_seq. ++ */ ++ if (!tcp_is_reno(tp)) ++ return true; ++ else if (tp->snd_una != tp->high_seq) ++ return true; ++ } ++ ++ if (!tp->mptcp->fully_established) { ++ /* Make sure that we send in-order data */ ++ if (skb && tp->mptcp->second_packet && ++ tp->mptcp->last_end_data_seq != TCP_SKB_CB(skb)->seq) ++ return true; ++ } ++ ++ in_flight = tcp_packets_in_flight(tp); ++ /* Not even a single spot in the cwnd */ ++ if (in_flight >= tp->snd_cwnd) ++ return true; ++ ++ mss_now = tcp_current_mss(sk); ++ ++ /* Now, check if what is queued in the subflow's send-queue ++ * already fills the cwnd. ++ */ ++ space = (tp->snd_cwnd - in_flight) * mss_now; ++ ++ if (tp->write_seq - tp->snd_nxt >= space) ++ return true; ++ ++ if (zero_wnd_test && !before(tp->write_seq, tcp_wnd_end(tp))) ++ return true; ++ ++ /* Don't send on this subflow if we bypass the allowed send-window at ++ * the per-subflow level. Similar to tcp_snd_wnd_test, but manually ++ * calculated end_seq (because here at this point end_seq is still at ++ * the meta-level). ++ */ ++ if (skb && zero_wnd_test && ++ after(tp->write_seq + min(skb->len, mss_now), tcp_wnd_end(tp))) ++ return true; ++ ++ return false; ++} ++ ++/* Is the sub-socket sk available to send the skb? */ ++bool mptcp_is_available(struct sock *sk, const struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ return !mptcp_is_def_unavailable(sk) && ++ !mptcp_is_temp_unavailable(sk, skb, zero_wnd_test); ++} ++EXPORT_SYMBOL_GPL(mptcp_is_available); ++ ++/* Are we not allowed to reinject this skb on tp? */ ++static int mptcp_dont_reinject_skb(const struct tcp_sock *tp, const struct sk_buff *skb) ++{ ++ /* If the skb has already been enqueued in this sk, try to find ++ * another one. ++ */ ++ return skb && ++ /* Has the skb already been enqueued into this subsocket? */ ++ mptcp_pi_to_flag(tp->mptcp->path_index) & TCP_SKB_CB(skb)->path_mask; ++} ++ ++bool subflow_is_backup(const struct tcp_sock *tp) ++{ ++ return tp->mptcp->rcv_low_prio || tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_backup); ++ ++bool subflow_is_active(const struct tcp_sock *tp) ++{ ++ return !tp->mptcp->rcv_low_prio && !tp->mptcp->low_prio; ++} ++EXPORT_SYMBOL_GPL(subflow_is_active); ++ ++/* Generic function to iterate over used and unused subflows and to select the ++ * best one ++ */ ++static struct sock ++*get_subflow_from_selectors(struct mptcp_cb *mpcb, struct sk_buff *skb, ++ bool (*selector)(const struct tcp_sock *), ++ bool zero_wnd_test, bool *force) ++{ ++ struct sock *bestsk = NULL; ++ u32 min_srtt = 0xffffffff; ++ bool found_unused = false; ++ bool found_unused_una = false; ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sk = mptcp_to_sock(mptcp); ++ struct tcp_sock *tp = tcp_sk(sk); ++ bool unused = false; ++ ++ /* First, we choose only the wanted sks */ ++ if (!(*selector)(tp)) ++ continue; ++ ++ if (!mptcp_dont_reinject_skb(tp, skb)) ++ unused = true; ++ else if (found_unused) ++ /* If a unused sk was found previously, we continue - ++ * no need to check used sks anymore. ++ */ ++ continue; ++ ++ if (mptcp_is_def_unavailable(sk)) ++ continue; ++ ++ if (mptcp_is_temp_unavailable(sk, skb, zero_wnd_test)) { ++ if (unused) ++ found_unused_una = true; ++ continue; ++ } ++ ++ if (unused) { ++ if (!found_unused) { ++ /* It's the first time we encounter an unused ++ * sk - thus we reset the bestsk (which might ++ * have been set to a used sk). ++ */ ++ min_srtt = 0xffffffff; ++ bestsk = NULL; ++ } ++ found_unused = true; ++ } ++ ++ if (tp->srtt_us < min_srtt) { ++ min_srtt = tp->srtt_us; ++ bestsk = sk; ++ } ++ } ++ ++ if (bestsk) { ++ /* The force variable is used to mark the returned sk as ++ * previously used or not-used. ++ */ ++ if (found_unused) ++ *force = true; ++ else ++ *force = false; ++ } else { ++ /* The force variable is used to mark if there are temporally ++ * unavailable not-used sks. ++ */ ++ if (found_unused_una) ++ *force = true; ++ else ++ *force = false; ++ } ++ ++ return bestsk; ++} ++ ++/* This is the scheduler. This function decides on which flow to send ++ * a given MSS. If all subflows are found to be busy, NULL is returned ++ * The flow is selected based on the shortest RTT. ++ * If all paths have full cong windows, we simply return NULL. ++ * ++ * Additionally, this function is aware of the backup-subflows. ++ */ ++struct sock *get_available_subflow(struct sock *meta_sk, struct sk_buff *skb, ++ bool zero_wnd_test) ++{ ++ struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sock *sk; ++ bool looping = false, force; ++ ++ /* Answer data_fin on same subflow!!! */ ++ if (meta_sk->sk_shutdown & RCV_SHUTDOWN && ++ skb && mptcp_is_data_fin(skb)) { ++ struct mptcp_tcp_sock *mptcp; ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ sk = mptcp_to_sock(mptcp); ++ ++ if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index && ++ mptcp_is_available(sk, skb, zero_wnd_test)) ++ return sk; ++ } ++ } ++ ++ /* Find the best subflow */ ++restart: ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_active, ++ zero_wnd_test, &force); ++ if (force) ++ /* one unused active sk or one NULL sk when there is at least ++ * one temporally unavailable unused active sk ++ */ ++ return sk; ++ ++ sk = get_subflow_from_selectors(mpcb, skb, &subflow_is_backup, ++ zero_wnd_test, &force); ++ if (!force && skb) { ++ /* one used backup sk or one NULL sk where there is no one ++ * temporally unavailable unused backup sk ++ * ++ * the skb passed through all the available active and backups ++ * sks, so clean the path mask ++ */ ++ TCP_SKB_CB(skb)->path_mask = 0; ++ ++ if (!looping) { ++ looping = true; ++ goto restart; ++ } ++ } ++ return sk; ++} ++EXPORT_SYMBOL_GPL(get_available_subflow); ++ ++static struct sk_buff *mptcp_rcv_buf_optimization(struct sock *sk, int penal) ++{ ++ struct sock *meta_sk; ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct mptcp_tcp_sock *mptcp; ++ struct sk_buff *skb_head; ++ struct defsched_priv *def_p = defsched_get_priv(tp); ++ ++ meta_sk = mptcp_meta_sk(sk); ++ skb_head = tcp_rtx_queue_head(meta_sk); ++ ++ if (!skb_head) ++ return NULL; ++ ++ /* If penalization is optional (coming from mptcp_next_segment() and ++ * We are not send-buffer-limited we do not penalize. The retransmission ++ * is just an optimization to fix the idle-time due to the delay before ++ * we wake up the application. ++ */ ++ if (!penal && sk_stream_memory_free(meta_sk)) ++ goto retrans; ++ ++ /* Only penalize again after an RTT has elapsed */ ++ if (tcp_jiffies32 - def_p->last_rbuf_opti < usecs_to_jiffies(tp->srtt_us >> 3)) ++ goto retrans; ++ ++ /* Half the cwnd of the slow flows */ ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp->srtt_us < tp_it->srtt_us && inet_csk((struct sock *)tp_it)->icsk_ca_state == TCP_CA_Open) { ++ u32 prior_cwnd = tp_it->snd_cwnd; ++ ++ tp_it->snd_cwnd = max(tp_it->snd_cwnd >> 1U, 1U); ++ ++ /* If in slow start, do not reduce the ssthresh */ ++ if (prior_cwnd >= tp_it->snd_ssthresh) ++ tp_it->snd_ssthresh = max(tp_it->snd_ssthresh >> 1U, 2U); ++ ++ def_p->last_rbuf_opti = tcp_jiffies32; ++ } ++ } ++ } ++ ++retrans: ++ ++ /* Segment not yet injected into this path? Take it!!! */ ++ if (!(TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp->mptcp->path_index))) { ++ bool do_retrans = false; ++ mptcp_for_each_sub(tp->mpcb, mptcp) { ++ struct tcp_sock *tp_it = mptcp->tp; ++ ++ if (tp_it != tp && ++ TCP_SKB_CB(skb_head)->path_mask & mptcp_pi_to_flag(tp_it->mptcp->path_index)) { ++ if (tp_it->snd_cwnd <= 4) { ++ do_retrans = true; ++ break; ++ } ++ ++ if (4 * tp->srtt_us >= tp_it->srtt_us) { ++ do_retrans = false; ++ break; ++ } else { ++ do_retrans = true; ++ } ++ } ++ } ++ ++ if (do_retrans && mptcp_is_available(sk, skb_head, false)) { ++ trace_mptcp_retransmit(sk, skb_head); ++ return skb_head; ++ } ++ } ++ return NULL; ++} ++ ++/* Returns the next segment to be sent from the mptcp meta-queue. ++ * (chooses the reinject queue if any segment is waiting in it, otherwise, ++ * chooses the normal write queue). ++ * Sets *@reinject to 1 if the returned segment comes from the ++ * reinject queue. Sets it to 0 if it is the regular send-head of the meta-sk, ++ * and sets it to -1 if it is a meta-level retransmission to optimize the ++ * receive-buffer. ++ */ ++static struct sk_buff *__mptcp_next_segment(struct sock *meta_sk, int *reinject) ++{ ++ const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb; ++ struct sk_buff *skb = NULL; ++ ++ *reinject = 0; ++ ++ /* If we are in fallback-mode, just take from the meta-send-queue */ ++ if (mpcb->infinite_mapping_snd || mpcb->send_infinite_mapping) ++ return tcp_send_head(meta_sk); ++ ++ skb = skb_peek(&mpcb->reinject_queue); ++ ++ if (skb) { ++ *reinject = 1; ++ } else { ++ skb = tcp_send_head(meta_sk); ++ ++ if (!skb && meta_sk->sk_socket && ++ test_bit(SOCK_NOSPACE, &meta_sk->sk_socket->flags) && ++ sk_stream_wspace(meta_sk) < sk_stream_min_wspace(meta_sk)) { ++ struct sock *subsk = mpcb->sched_ops->get_subflow(meta_sk, NULL, ++ false); ++ if (!subsk) ++ return NULL; ++ ++ skb = mptcp_rcv_buf_optimization(subsk, 0); ++ if (skb) ++ *reinject = -1; ++ } ++ } ++ return skb; ++} ++ ++struct sk_buff *mptcp_next_segment(struct sock *meta_sk, ++ int *reinject, ++ struct sock **subsk, ++ unsigned int *limit) ++{ ++ struct sk_buff *skb = __mptcp_next_segment(meta_sk, reinject); ++ unsigned int mss_now, in_flight_space; ++ int remaining_in_flight_space; ++ u32 max_len, max_segs, window; ++ struct tcp_sock *subtp; ++ u16 gso_max_segs; ++ ++ /* As we set it, we have to reset it as well. */ ++ *limit = 0; ++ ++ if (!skb) ++ return NULL; ++ ++ *subsk = tcp_sk(meta_sk)->mpcb->sched_ops->get_subflow(meta_sk, skb, false); ++ if (!*subsk) ++ return NULL; ++ ++ subtp = tcp_sk(*subsk); ++ mss_now = tcp_current_mss(*subsk); ++ ++ if (!*reinject && unlikely(!tcp_snd_wnd_test(tcp_sk(meta_sk), skb, mss_now))) { ++ skb = mptcp_rcv_buf_optimization(*subsk, 1); ++ if (skb) ++ *reinject = -1; ++ else ++ return NULL; ++ } ++ ++ /* No splitting required, as we will only send one single segment */ ++ if (skb->len <= mss_now) ++ return skb; ++ ++ /* The following is similar to tcp_mss_split_point, but ++ * we do not care about nagle, because we will anyways ++ * use TCP_NAGLE_PUSH, which overrides this. ++ */ ++ ++ gso_max_segs = (*subsk)->sk_gso_max_segs; ++ if (!gso_max_segs) /* No gso supported on the subflow's NIC */ ++ gso_max_segs = 1; ++ max_segs = min_t(unsigned int, tcp_cwnd_test(subtp, skb), gso_max_segs); ++ if (!max_segs) ++ return NULL; ++ ++ /* max_len is what would fit in the cwnd (respecting the 2GSO-limit of ++ * tcp_cwnd_test), but ignoring whatever was already queued. ++ */ ++ max_len = min(mss_now * max_segs, skb->len); ++ ++ in_flight_space = (subtp->snd_cwnd - tcp_packets_in_flight(subtp)) * mss_now; ++ remaining_in_flight_space = (int)in_flight_space - (subtp->write_seq - subtp->snd_nxt); ++ ++ if (remaining_in_flight_space <= 0) ++ WARN_ONCE(1, "in_flight %u cwnd %u wseq %u snxt %u mss_now %u cache %u", ++ tcp_packets_in_flight(subtp), subtp->snd_cwnd, ++ subtp->write_seq, subtp->snd_nxt, mss_now, subtp->mss_cache); ++ else ++ /* max_len now fits exactly in the write-queue, taking into ++ * account what was already queued. ++ */ ++ max_len = min_t(u32, max_len, remaining_in_flight_space); ++ ++ window = tcp_wnd_end(subtp) - subtp->write_seq; ++ ++ /* max_len now also respects the announced receive-window */ ++ max_len = min(max_len, window); ++ ++ *limit = max_len; ++ ++ return skb; ++} ++EXPORT_SYMBOL_GPL(mptcp_next_segment); ++ ++static void defsched_init(struct sock *sk) ++{ ++ struct defsched_priv *def_p = defsched_get_priv(tcp_sk(sk)); ++ ++ def_p->last_rbuf_opti = tcp_jiffies32; ++} ++ ++struct mptcp_sched_ops mptcp_sched_default = { ++ .get_subflow = get_available_subflow, ++ .next_segment = mptcp_next_segment, ++ .init = defsched_init, ++ .name = "default", ++ .owner = THIS_MODULE, ++}; ++ ++static struct mptcp_sched_ops *mptcp_sched_find(const char *name) ++{ ++ struct mptcp_sched_ops *e; ++ ++ list_for_each_entry_rcu(e, &mptcp_sched_list, list) { ++ if (strcmp(e->name, name) == 0) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++int mptcp_register_scheduler(struct mptcp_sched_ops *sched) ++{ ++ int ret = 0; ++ ++ if (!sched->get_subflow || !sched->next_segment) ++ return -EINVAL; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ if (mptcp_sched_find(sched->name)) { ++ pr_notice("%s already registered\n", sched->name); ++ ret = -EEXIST; ++ } else { ++ list_add_tail_rcu(&sched->list, &mptcp_sched_list); ++ pr_info("%s registered\n", sched->name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mptcp_register_scheduler); ++ ++void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched) ++{ ++ spin_lock(&mptcp_sched_list_lock); ++ list_del_rcu(&sched->list); ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ /* Wait for outstanding readers to complete before the ++ * module gets removed entirely. ++ * ++ * A try_module_get() should fail by now as our module is ++ * in "going" state since no refs are held anymore and ++ * module_exit() handler being called. ++ */ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(mptcp_unregister_scheduler); ++ ++void mptcp_get_default_scheduler(char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ ++ BUG_ON(list_empty(&mptcp_sched_list)); ++ ++ rcu_read_lock(); ++ sched = list_entry(mptcp_sched_list.next, struct mptcp_sched_ops, list); ++ strncpy(name, sched->name, MPTCP_SCHED_NAME_MAX); ++ rcu_read_unlock(); ++} ++ ++int mptcp_set_default_scheduler(const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int ret = -ENOENT; ++ ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ request_module("mptcp_%s", name); ++ spin_lock(&mptcp_sched_list_lock); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ ++ if (sched) { ++ list_move(&sched->list, &mptcp_sched_list); ++ ret = 0; ++ } else { ++ pr_info("%s is not available\n", name); ++ } ++ spin_unlock(&mptcp_sched_list_lock); ++ ++ return ret; ++} ++ ++/* Must be called with rcu lock held */ ++static struct mptcp_sched_ops *__mptcp_sched_find_autoload(const char *name) ++{ ++ struct mptcp_sched_ops *sched = mptcp_sched_find(name); ++#ifdef CONFIG_MODULES ++ if (!sched && capable(CAP_NET_ADMIN)) { ++ rcu_read_unlock(); ++ request_module("mptcp_%s", name); ++ rcu_read_lock(); ++ sched = mptcp_sched_find(name); ++ } ++#endif ++ return sched; ++} ++ ++void mptcp_init_scheduler(struct mptcp_cb *mpcb) ++{ ++ struct mptcp_sched_ops *sched; ++ struct sock *meta_sk = mpcb->meta_sk; ++ struct tcp_sock *meta_tp = tcp_sk(meta_sk); ++ ++ rcu_read_lock(); ++ /* if scheduler was set using socket option */ ++ if (meta_tp->mptcp_sched_setsockopt) { ++ sched = __mptcp_sched_find_autoload(meta_tp->mptcp_sched_name); ++ if (sched && try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ goto out; ++ } ++ } ++ ++ list_for_each_entry_rcu(sched, &mptcp_sched_list, list) { ++ if (try_module_get(sched->owner)) { ++ mpcb->sched_ops = sched; ++ break; ++ } ++ } ++out: ++ rcu_read_unlock(); ++} ++ ++/* Change scheduler for socket */ ++int mptcp_set_scheduler(struct sock *sk, const char *name) ++{ ++ struct mptcp_sched_ops *sched; ++ int err = 0; ++ ++ rcu_read_lock(); ++ sched = __mptcp_sched_find_autoload(name); ++ ++ if (!sched) { ++ err = -ENOENT; ++ } else if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ err = -EPERM; ++ } else { ++ strcpy(tcp_sk(sk)->mptcp_sched_name, name); ++ tcp_sk(sk)->mptcp_sched_setsockopt = 1; ++ } ++ rcu_read_unlock(); ++ ++ return err; ++} ++ ++/* Manage refcounts on socket close. */ ++void mptcp_cleanup_scheduler(struct mptcp_cb *mpcb) ++{ ++ module_put(mpcb->sched_ops->owner); ++} ++ ++/* Set default value from kernel configuration at bootup */ ++static int __init mptcp_scheduler_default(void) ++{ ++ BUILD_BUG_ON(sizeof(struct defsched_priv) > MPTCP_SCHED_SIZE); ++ ++ return mptcp_set_default_scheduler(CONFIG_DEFAULT_MPTCP_SCHED); ++} ++late_initcall(mptcp_scheduler_default); +diff -aurN linux-5.4.64/net/mptcp/mptcp_wvegas.c linux-5.4.64.mptcp/net/mptcp/mptcp_wvegas.c +--- linux-5.4.64/net/mptcp/mptcp_wvegas.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-5.4.64.mptcp/net/mptcp/mptcp_wvegas.c 2020-09-10 19:25:10.511220802 +0200 +@@ -0,0 +1,271 @@ ++/* ++ * MPTCP implementation - WEIGHTED VEGAS ++ * ++ * Algorithm design: ++ * Yu Cao ++ * Mingwei Xu ++ * Xiaoming Fu ++ * ++ * Implementation: ++ * Yu Cao ++ * Enhuan Dong ++ * ++ * Ported to the official MPTCP-kernel: ++ * Christoph Paasch ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int initial_alpha = 2; ++static int total_alpha = 10; ++static int gamma = 1; ++ ++module_param(initial_alpha, int, 0644); ++MODULE_PARM_DESC(initial_alpha, "initial alpha for all subflows"); ++module_param(total_alpha, int, 0644); ++MODULE_PARM_DESC(total_alpha, "total alpha for all subflows"); ++module_param(gamma, int, 0644); ++MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)"); ++ ++#define MPTCP_WVEGAS_SCALE 16 ++ ++/* wVegas variables */ ++struct wvegas { ++ u32 beg_snd_nxt; /* right edge during last RTT */ ++ u8 doing_wvegas_now;/* if true, do wvegas for this RTT */ ++ ++ u16 cnt_rtt; /* # of RTTs measured within last RTT */ ++ u32 sampled_rtt; /* cumulative RTTs measured within last RTT (in usec) */ ++ u32 base_rtt; /* the min of all wVegas RTT measurements seen (in usec) */ ++ ++ u64 instant_rate; /* cwnd / srtt_us, unit: pkts/us * 2^16 */ ++ u64 weight; /* the ratio of subflow's rate to the total rate, * 2^16 */ ++ int alpha; /* alpha for each subflows */ ++ ++ u32 queue_delay; /* queue delay*/ ++}; ++ ++ ++static inline u64 mptcp_wvegas_scale(u32 val, int scale) ++{ ++ return (u64) val << scale; ++} ++ ++static void wvegas_enable(const struct sock *sk) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 1; ++ ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ ++ wvegas->instant_rate = 0; ++ wvegas->alpha = initial_alpha; ++ wvegas->weight = mptcp_wvegas_scale(1, MPTCP_WVEGAS_SCALE); ++ ++ wvegas->queue_delay = 0; ++} ++ ++static inline void wvegas_disable(const struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->doing_wvegas_now = 0; ++} ++ ++static void mptcp_wvegas_init(struct sock *sk) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ wvegas->base_rtt = 0x7fffffff; ++ wvegas_enable(sk); ++} ++ ++static inline u64 mptcp_wvegas_rate(u32 cwnd, u32 rtt_us) ++{ ++ return div_u64(mptcp_wvegas_scale(cwnd, MPTCP_WVEGAS_SCALE), rtt_us); ++} ++ ++static void mptcp_wvegas_pkts_acked(struct sock *sk, ++ const struct ack_sample *sample) ++{ ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ u32 vrtt; ++ ++ if (sample->rtt_us < 0) ++ return; ++ ++ vrtt = sample->rtt_us + 1; ++ ++ if (vrtt < wvegas->base_rtt) ++ wvegas->base_rtt = vrtt; ++ ++ wvegas->sampled_rtt += vrtt; ++ wvegas->cnt_rtt++; ++} ++ ++static void mptcp_wvegas_state(struct sock *sk, u8 ca_state) ++{ ++ if (ca_state == TCP_CA_Open) ++ wvegas_enable(sk); ++ else ++ wvegas_disable(sk); ++} ++ ++static void mptcp_wvegas_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_CWND_RESTART) { ++ mptcp_wvegas_init(sk); ++ } else if (event == CA_EVENT_LOSS) { ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ wvegas->instant_rate = 0; ++ } ++} ++ ++static inline u32 mptcp_wvegas_ssthresh(const struct tcp_sock *tp) ++{ ++ return min(tp->snd_ssthresh, tp->snd_cwnd); ++} ++ ++static u64 mptcp_wvegas_weight(const struct mptcp_cb *mpcb, const struct sock *sk) ++{ ++ u64 total_rate = 0; ++ const struct wvegas *wvegas = inet_csk_ca(sk); ++ struct mptcp_tcp_sock *mptcp; ++ ++ if (!mpcb) ++ return wvegas->weight; ++ ++ ++ mptcp_for_each_sub(mpcb, mptcp) { ++ struct sock *sub_sk = mptcp_to_sock(mptcp); ++ struct wvegas *sub_wvegas = inet_csk_ca(sub_sk); ++ ++ /* sampled_rtt is initialized by 0 */ ++ if (mptcp_sk_can_send(sub_sk) && (sub_wvegas->sampled_rtt > 0)) ++ total_rate += sub_wvegas->instant_rate; ++ } ++ ++ if (total_rate && wvegas->instant_rate) ++ return div64_u64(mptcp_wvegas_scale(wvegas->instant_rate, MPTCP_WVEGAS_SCALE), total_rate); ++ else ++ return wvegas->weight; ++} ++ ++static void mptcp_wvegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct wvegas *wvegas = inet_csk_ca(sk); ++ ++ if (!wvegas->doing_wvegas_now) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ return; ++ } ++ ++ if (after(ack, wvegas->beg_snd_nxt)) { ++ wvegas->beg_snd_nxt = tp->snd_nxt; ++ ++ if (wvegas->cnt_rtt <= 2) { ++ tcp_reno_cong_avoid(sk, ack, acked); ++ } else { ++ u32 rtt, diff, q_delay; ++ u64 target_cwnd; ++ ++ rtt = wvegas->sampled_rtt / wvegas->cnt_rtt; ++ target_cwnd = div_u64(((u64)tp->snd_cwnd * wvegas->base_rtt), rtt); ++ ++ diff = div_u64((u64)tp->snd_cwnd * (rtt - wvegas->base_rtt), rtt); ++ ++ if (diff > gamma && tcp_in_slow_start(tp)) { ++ tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ ++ } else if (tcp_in_slow_start(tp)) { ++ tcp_slow_start(tp, acked); ++ } else { ++ if (diff >= wvegas->alpha) { ++ wvegas->instant_rate = mptcp_wvegas_rate(tp->snd_cwnd, rtt); ++ wvegas->weight = mptcp_wvegas_weight(tp->mpcb, sk); ++ wvegas->alpha = max(2U, (u32)((wvegas->weight * total_alpha) >> MPTCP_WVEGAS_SCALE)); ++ } ++ if (diff > wvegas->alpha) { ++ tp->snd_cwnd--; ++ tp->snd_ssthresh = mptcp_wvegas_ssthresh(tp); ++ } else if (diff < wvegas->alpha) { ++ tp->snd_cwnd++; ++ } ++ ++ /* Try to drain link queue if needed*/ ++ q_delay = rtt - wvegas->base_rtt; ++ if ((wvegas->queue_delay == 0) || (wvegas->queue_delay > q_delay)) ++ wvegas->queue_delay = q_delay; ++ ++ if (q_delay >= 2 * wvegas->queue_delay) { ++ u32 backoff_factor = div_u64(mptcp_wvegas_scale(wvegas->base_rtt, MPTCP_WVEGAS_SCALE), 2 * rtt); ++ tp->snd_cwnd = ((u64)tp->snd_cwnd * backoff_factor) >> MPTCP_WVEGAS_SCALE; ++ wvegas->queue_delay = 0; ++ } ++ } ++ ++ if (tp->snd_cwnd < 2) ++ tp->snd_cwnd = 2; ++ else if (tp->snd_cwnd > tp->snd_cwnd_clamp) ++ tp->snd_cwnd = tp->snd_cwnd_clamp; ++ ++ tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ } ++ ++ wvegas->cnt_rtt = 0; ++ wvegas->sampled_rtt = 0; ++ } ++ /* Use normal slow start */ ++ else if (tcp_in_slow_start(tp)) ++ tcp_slow_start(tp, acked); ++} ++ ++ ++static struct tcp_congestion_ops mptcp_wvegas __read_mostly = { ++ .init = mptcp_wvegas_init, ++ .ssthresh = tcp_reno_ssthresh, ++ .cong_avoid = mptcp_wvegas_cong_avoid, ++ .undo_cwnd = tcp_reno_undo_cwnd, ++ .pkts_acked = mptcp_wvegas_pkts_acked, ++ .set_state = mptcp_wvegas_state, ++ .cwnd_event = mptcp_wvegas_cwnd_event, ++ ++ .owner = THIS_MODULE, ++ .name = "wvegas", ++}; ++ ++static int __init mptcp_wvegas_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct wvegas) > ICSK_CA_PRIV_SIZE); ++ tcp_register_congestion_control(&mptcp_wvegas); ++ return 0; ++} ++ ++static void __exit mptcp_wvegas_unregister(void) ++{ ++ tcp_unregister_congestion_control(&mptcp_wvegas); ++} ++ ++module_init(mptcp_wvegas_register); ++module_exit(mptcp_wvegas_unregister); ++ ++MODULE_AUTHOR("Yu Cao, Enhuan Dong"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MPTCP wVegas"); ++MODULE_VERSION("0.1"); +diff -aurN linux-5.4.64/net/socket.c linux-5.4.64.mptcp/net/socket.c +--- linux-5.4.64/net/socket.c 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/net/socket.c 2020-09-10 19:25:10.511220802 +0200 +@@ -91,6 +91,7 @@ + #include + + #include ++#include + #include + #include + +@@ -1350,6 +1351,7 @@ + int err; + struct socket *sock; + const struct net_proto_family *pf; ++ int old_protocol = protocol; + + /* + * Check protocol is in range +@@ -1370,6 +1372,9 @@ + family = PF_PACKET; + } + ++ if (old_protocol == IPPROTO_MPTCP) ++ protocol = IPPROTO_TCP; ++ + err = security_socket_create(family, type, protocol, kern); + if (err) + return err; +@@ -1419,6 +1424,10 @@ + if (err < 0) + goto out_module_put; + ++ if (sysctl_mptcp_enabled && old_protocol == IPPROTO_MPTCP && ++ type == SOCK_STREAM && (family == AF_INET || family == AF_INET6)) ++ mptcp_enable_sock(sock->sk); ++ + /* + * Now to bump the refcnt of the [loadable] module that owns this + * socket at sock_release time we decrement its refcnt. +diff -aurN linux-5.4.64/tools/include/uapi/linux/bpf.h linux-5.4.64.mptcp/tools/include/uapi/linux/bpf.h +--- linux-5.4.64/tools/include/uapi/linux/bpf.h 2020-09-09 19:12:37.000000000 +0200 ++++ linux-5.4.64.mptcp/tools/include/uapi/linux/bpf.h 2020-09-10 19:25:10.511220802 +0200 +@@ -3438,6 +3438,7 @@ + BPF_TCP_LISTEN, + BPF_TCP_CLOSING, /* Now a valid state */ + BPF_TCP_NEW_SYN_RECV, ++ BPF_TCP_RST_WAIT, + + BPF_TCP_MAX_STATES /* Leave at the end! */ + }; diff --git a/root/target/linux/generic/hack-5.4/692-tcp_nanqinlang.patch b/root/target/linux/generic/hack-5.4/692-tcp_nanqinlang.patch new file mode 100644 index 00000000..56051ae7 --- /dev/null +++ b/root/target/linux/generic/hack-5.4/692-tcp_nanqinlang.patch @@ -0,0 +1,1037 @@ +--- a/net/ipv4/Makefile.anc 2019-11-23 23:01:47.069966970 +0100 ++++ b/net/ipv4/Makefile 2019-11-23 23:03:01.416428035 +0100 +@@ -48,6 +48,7 @@ + obj-$(CONFIG_INET_UDP_DIAG) += udp_diag.o + obj-$(CONFIG_INET_RAW_DIAG) += raw_diag.o + obj-$(CONFIG_TCP_CONG_BBR) += tcp_bbr.o ++obj-$(CONFIG_TCP_CONG_NANQINLANG) += tcp_nanqinlang.o + obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o + obj-$(CONFIG_TCP_CONG_CDG) += tcp_cdg.o + obj-$(CONFIG_TCP_CONG_CUBIC) += tcp_cubic.o +--- a/net/ipv4/Kconfig.anc 2019-11-23 23:01:52.649851417 +0100 ++++ b/net/ipv4/Kconfig 2019-11-23 23:04:21.974762180 +0100 +@@ -681,6 +681,21 @@ + bufferbloat, policers, or AQM schemes that do not provide a delay + signal. It requires the fq ("Fair Queue") pacing packet scheduler. + ++config TCP_CONG_NANQINLANG ++ tristate "NANGINLANG TCP" ++ default n ++ ---help--- ++ ++ BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to ++ maximize network utilization and minimize queues. It builds an explicit ++ model of the the bottleneck delivery rate and path round-trip ++ propagation delay. It tolerates packet loss and delay unrelated to ++ congestion. It can operate over LAN, WAN, cellular, wifi, or cable ++ modem links. It can coexist with flows that use loss-based congestion ++ control, and can operate with shallow buffers, deep buffers, ++ bufferbloat, policers, or AQM schemes that do not provide a delay ++ signal. It requires the fq ("Fair Queue") pacing packet scheduler. ++ + config TCP_CONG_LIA + tristate "MPTCP Linked Increase" + depends on MPTCP +@@ -763,6 +778,9 @@ + config DEFAULT_BBR + bool "BBR" if TCP_CONG_BBR=y + ++ config DEFAULT_NANQINLANG ++ bool "BBR" if TCP_CONG_NANQINLANG=y ++ + config DEFAULT_LIA + bool "Lia" if TCP_CONG_LIA=y + +@@ -806,6 +824,7 @@ + default "dctcp" if DEFAULT_DCTCP + default "cdg" if DEFAULT_CDG + default "bbr" if DEFAULT_BBR ++ default "nanqinlang" if DEFAULT_NANQINLANG + default "cubic" + + config TCP_MD5SIG +--- /dev/null 2019-11-25 21:13:36.728349757 +0100 ++++ b/net/ipv4/tcp_nanqinlang.c 2019-11-25 21:10:00.392068414 +0100 +@@ -0,0 +1,982 @@ ++/* Bottleneck Bandwidth and RTT (BBR) congestion control ++ * ++ * BBR congestion control computes the sending rate based on the delivery ++ * rate (throughput) estimated from ACKs. In a nutshell: ++ * ++ * On each ACK, update our model of the network path: ++ * bottleneck_bandwidth = windowed_max(delivered / elapsed, 10 round trips) ++ * min_rtt = windowed_min(rtt, 10 seconds) ++ * pacing_rate = pacing_gain * bottleneck_bandwidth ++ * cwnd = max(cwnd_gain * bottleneck_bandwidth * min_rtt, 4) ++ * ++ * The core algorithm does not react directly to packet losses or delays, ++ * although BBR may adjust the size of next send per ACK when loss is ++ * observed, or adjust the sending rate if it estimates there is a ++ * traffic policer, in order to keep the drop rate reasonable. ++ * ++ * Here is a state transition diagram for BBR: ++ * ++ * | ++ * V ++ * +---> STARTUP ----+ ++ * | | | ++ * | V | ++ * | DRAIN ----+ ++ * | | | ++ * | V | ++ * +---> PROBE_BW ----+ ++ * | ^ | | ++ * | | | | ++ * | +----+ | ++ * | | ++ * +---- PROBE_RTT <--+ ++ * ++ * A BBR flow starts in STARTUP, and ramps up its sending rate quickly. ++ * When it estimates the pipe is full, it enters DRAIN to drain the queue. ++ * In steady state a BBR flow only uses PROBE_BW and PROBE_RTT. ++ * A long-lived BBR flow spends the vast majority of its time remaining ++ * (repeatedly) in PROBE_BW, fully probing and utilizing the pipe's bandwidth ++ * in a fair manner, with a small, bounded queue. *If* a flow has been ++ * continuously sending for the entire min_rtt window, and hasn't seen an RTT ++ * sample that matches or decreases its min_rtt estimate for 10 seconds, then ++ * it briefly enters PROBE_RTT to cut inflight to a minimum value to re-probe ++ * the path's two-way propagation delay (min_rtt). When exiting PROBE_RTT, if ++ * we estimated that we reached the full bw of the pipe then we enter PROBE_BW; ++ * otherwise we enter STARTUP to try to fill the pipe. ++ * ++ * BBR is described in detail in: ++ * "BBR: Congestion-Based Congestion Control", ++ * Neal Cardwell, Yuchung Cheng, C. Stephen Gunn, Soheil Hassas Yeganeh, ++ * Van Jacobson. ACM Queue, Vol. 14 No. 5, September-October 2016. ++ * ++ * There is a public e-mail list for discussing BBR development and testing: ++ * https://groups.google.com/forum/#!forum/bbr-dev ++ * ++ * NOTE: BBR might be used with the fq qdisc ("man tc-fq") with pacing enabled, ++ * otherwise TCP stack falls back to an internal pacing using one high ++ * resolution timer per TCP socket and may use more resources. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Scale factor for rate in pkt/uSec unit to avoid truncation in bandwidth ++ * estimation. The rate unit ~= (1500 bytes / 1 usec / 2^24) ~= 715 bps. ++ * This handles bandwidths from 0.06pps (715bps) to 256Mpps (3Tbps) in a u32. ++ * Since the minimum window is >=4 packets, the lower bound isn't ++ * an issue. The upper bound isn't an issue with existing technologies. ++ */ ++#define BW_SCALE 24 ++#define BW_UNIT (1 << BW_SCALE) ++ ++#define BBR_SCALE 8 /* scaling factor for fractions in BBR (e.g. gains) */ ++#define BBR_UNIT (1 << BBR_SCALE) ++ ++/* BBR has the following modes for deciding how fast to send: */ ++enum bbr_mode { ++ BBR_STARTUP, /* ramp up sending rate rapidly to fill pipe */ ++ BBR_DRAIN, /* drain any queue created during startup */ ++ BBR_PROBE_BW, /* discover, share bw: pace around estimated bw */ ++ BBR_PROBE_RTT, /* cut inflight to min to probe min_rtt */ ++}; ++ ++/* BBR congestion control block */ ++struct bbr { ++ u32 min_rtt_us; /* min RTT in min_rtt_win_sec window */ ++ u32 min_rtt_stamp; /* timestamp of min_rtt_us */ ++ u32 probe_rtt_done_stamp; /* end time for BBR_PROBE_RTT mode */ ++ struct minmax bw; /* Max recent delivery rate in pkts/uS << 24 */ ++ u32 rtt_cnt; /* count of packet-timed rounds elapsed */ ++ u32 next_rtt_delivered; /* scb->tx.delivered at end of round */ ++ u64 cycle_mstamp; /* time of this cycle phase start */ ++ u32 mode:3, /* current bbr_mode in state machine */ ++ prev_ca_state:3, /* CA state on previous ACK */ ++ packet_conservation:1, /* use packet conservation? */ ++ round_start:1, /* start of packet-timed tx->ack round? */ ++ idle_restart:1, /* restarting after idle? */ ++ probe_rtt_round_done:1, /* a BBR_PROBE_RTT round at 4 pkts? */ ++ unused:13, ++ lt_is_sampling:1, /* taking long-term ("LT") samples now? */ ++ lt_rtt_cnt:7, /* round trips in long-term interval */ ++ lt_use_bw:1; /* use lt_bw as our bw estimate? */ ++ u32 lt_bw; /* LT est delivery rate in pkts/uS << 24 */ ++ u32 lt_last_delivered; /* LT intvl start: tp->delivered */ ++ u32 lt_last_stamp; /* LT intvl start: tp->delivered_mstamp */ ++ u32 lt_last_lost; /* LT intvl start: tp->lost */ ++ u32 pacing_gain:10, /* current gain for setting pacing rate */ ++ cwnd_gain:10, /* current gain for setting cwnd */ ++ full_bw_reached:1, /* reached full bw in Startup? */ ++ full_bw_cnt:2, /* number of rounds without large bw gains */ ++ cycle_idx:3, /* current index in pacing_gain cycle array */ ++ has_seen_rtt:1, /* have we seen an RTT sample yet? */ ++ unused_b:5; ++ u32 prior_cwnd; /* prior cwnd upon entering loss recovery */ ++ u32 full_bw; /* recent bw, to estimate if pipe is full */ ++}; ++ ++#define CYCLE_LEN 8 /* number of phases in a pacing gain cycle */ ++ ++/* Window length of bw filter (in rounds): */ ++static const int bbr_bw_rtts = CYCLE_LEN + 2; ++/* Window length of min_rtt filter (in sec): */ ++static const u32 bbr_min_rtt_win_sec = 10; ++/* Minimum time (in ms) spent at bbr_cwnd_min_target in BBR_PROBE_RTT mode: */ ++static const u32 bbr_probe_rtt_mode_ms = 100; ++/* Skip TSO below the following bandwidth (bits/sec): */ ++static const int bbr_min_tso_rate = 1200000; ++ ++/* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain ++ * that will allow a smoothly increasing pacing rate that will double each RTT ++ * and send the same number of packets per RTT that an un-paced, slow-starting ++ * Reno or CUBIC flow would: ++ */ ++static const int bbr_high_gain = BBR_UNIT * 3000 / 1000 + 1; ++/* The pacing gain of 1/high_gain in BBR_DRAIN is calculated to typically drain ++ * the queue created in BBR_STARTUP in a single round: ++ */ ++static const int bbr_drain_gain = BBR_UNIT * 1000 / 3000; ++/* The gain for deriving steady-state cwnd tolerates delayed/stretched ACKs: */ ++static const int bbr_cwnd_gain = BBR_UNIT * 2; ++/* The pacing_gain values for the PROBE_BW gain cycle, to discover/share bw: */ ++static const int bbr_pacing_gain[] = { ++ BBR_UNIT * 6 / 4, /* probe for more available bw */ ++ BBR_UNIT * 3 / 4, /* drain queue and/or yield bw to other flows */ ++ BBR_UNIT * 5 / 4, BBR_UNIT * 5 / 4, BBR_UNIT * 5 / 4, /* cruise at 1.0*bw to utilize pipe, */ ++ BBR_UNIT * 6 / 4, BBR_UNIT * 6 / 4, BBR_UNIT * 6 / 4 /* without creating excess queue... */ ++}; ++/* Randomize the starting gain cycling phase over N phases: */ ++static const u32 bbr_cycle_rand = 7; ++ ++/* Try to keep at least this many packets in flight, if things go smoothly. For ++ * smooth functioning, a sliding window protocol ACKing every other packet ++ * needs at least 4 packets in flight: ++ */ ++static const u32 bbr_cwnd_min_target = 4; ++ ++/* To estimate if BBR_STARTUP mode (i.e. high_gain) has filled pipe... */ ++/* If bw has increased significantly (1.25x), there may be more bw available: */ ++static const u32 bbr_full_bw_thresh = BBR_UNIT * 5 / 4; ++/* But after 3 rounds w/o significant bw growth, estimate pipe is full: */ ++static const u32 bbr_full_bw_cnt = 3; ++ ++/* "long-term" ("LT") bandwidth estimator parameters... */ ++/* The minimum number of rounds in an LT bw sampling interval: */ ++static const u32 bbr_lt_intvl_min_rtts = 4; ++/* If lost/delivered ratio > 20%, interval is "lossy" and we may be policed: */ ++static const u32 bbr_lt_loss_thresh = 50; ++/* If 2 intervals have a bw ratio <= 1/8, their bw is "consistent": */ ++static const u32 bbr_lt_bw_ratio = BBR_UNIT / 4; ++/* If 2 intervals have a bw diff <= 4 Kbit/sec their bw is "consistent": */ ++static const u32 bbr_lt_bw_diff = 4000 / 8; ++/* If we estimate we're policed, use lt_bw for this many round trips: */ ++static const u32 bbr_lt_bw_max_rtts = 48; ++ ++static void bbr_check_probe_rtt_done(struct sock *sk); ++ ++/* Do we estimate that STARTUP filled the pipe? */ ++static bool bbr_full_bw_reached(const struct sock *sk) ++{ ++ const struct bbr *bbr = inet_csk_ca(sk); ++ ++ return bbr->full_bw_reached; ++} ++ ++/* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ ++static u32 bbr_max_bw(const struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return minmax_get(&bbr->bw); ++} ++ ++/* Return the estimated bandwidth of the path, in pkts/uS << BW_SCALE. */ ++static u32 bbr_bw(const struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return bbr->lt_use_bw ? bbr->lt_bw : bbr_max_bw(sk); ++} ++ ++/* Return rate in bytes per second, optionally with a gain. ++ * The order here is chosen carefully to avoid overflow of u64. This should ++ * work for input rates of up to 2.9Tbit/sec and gain of 2.89x. ++ */ ++static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) ++{ ++ unsigned int mss = tcp_sk(sk)->mss_cache; ++ ++ if (!tcp_needs_internal_pacing(sk)) ++ mss = tcp_mss_to_mtu(sk, mss); ++ rate *= mss; ++ rate *= gain; ++ rate >>= BBR_SCALE; ++ rate *= USEC_PER_SEC; ++ return rate >> BW_SCALE; ++} ++ ++/* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ ++static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain) ++{ ++ u64 rate = bw; ++ ++ rate = bbr_rate_bytes_per_sec(sk, rate, gain); ++ rate = min_t(u64, rate, sk->sk_max_pacing_rate); ++ return rate; ++} ++ ++/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */ ++static void bbr_init_pacing_rate_from_rtt(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw; ++ u32 rtt_us; ++ ++ if (tp->srtt_us) { /* any RTT sample yet? */ ++ rtt_us = max(tp->srtt_us >> 3, 1U); ++ bbr->has_seen_rtt = 1; ++ } else { /* no RTT sample yet */ ++ rtt_us = USEC_PER_MSEC; /* use nominal default RTT */ ++ } ++ bw = (u64)tp->snd_cwnd * BW_UNIT; ++ do_div(bw, rtt_us); ++ sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain); ++} ++ ++/* Pace using current bw estimate and a gain factor. In order to help drive the ++ * network toward lower queues while maintaining high utilization and low ++ * latency, the average pacing rate aims to be slightly (~1%) lower than the ++ * estimated bandwidth. This is an important aspect of the design. In this ++ * implementation this slightly lower pacing rate is achieved implicitly by not ++ * including link-layer headers in the packet size used for the pacing rate. ++ */ ++static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain); ++ ++ if (unlikely(!bbr->has_seen_rtt && tp->srtt_us)) ++ bbr_init_pacing_rate_from_rtt(sk); ++ if (bbr_full_bw_reached(sk) || rate > sk->sk_pacing_rate) ++ sk->sk_pacing_rate = rate; ++} ++ ++/* override sysctl_tcp_min_tso_segs */ ++static u32 bbr_min_tso_segs(struct sock *sk) ++{ ++ return sk->sk_pacing_rate < (bbr_min_tso_rate >> 3) ? 1 : 2; ++} ++ ++static u32 bbr_tso_segs_goal(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 segs, bytes; ++ ++ /* Sort of tcp_tso_autosize() but ignoring ++ * driver provided sk_gso_max_size. ++ */ ++ bytes = min_t(u32, sk->sk_pacing_rate >> sk->sk_pacing_shift, ++ GSO_MAX_SIZE - 1 - MAX_TCP_HEADER); ++ segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk)); ++ ++ return min(segs, 0x7FU); ++} ++ ++/* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ ++static void bbr_save_cwnd(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->prev_ca_state < TCP_CA_Recovery && bbr->mode != BBR_PROBE_RTT) ++ bbr->prior_cwnd = tp->snd_cwnd; /* this cwnd is good enough */ ++ else /* loss recovery or BBR_PROBE_RTT have temporarily cut cwnd */ ++ bbr->prior_cwnd = max(bbr->prior_cwnd, tp->snd_cwnd); ++} ++ ++static void bbr_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (event == CA_EVENT_TX_START && tp->app_limited) { ++ bbr->idle_restart = 1; ++ /* Avoid pointless buffer overflows: pace at est. bw if we don't ++ * need more speed (we're restarting from idle and app-limited). ++ */ ++ if (bbr->mode == BBR_PROBE_BW) ++ bbr_set_pacing_rate(sk, bbr_bw(sk), BBR_UNIT); ++ else if (bbr->mode == BBR_PROBE_RTT) ++ bbr_check_probe_rtt_done(sk); ++ } ++} ++ ++/* Find target cwnd. Right-size the cwnd based on min RTT and the ++ * estimated bottleneck bandwidth: ++ * ++ * cwnd = bw * min_rtt * gain = BDP * gain ++ * ++ * The key factor, gain, controls the amount of queue. While a small gain ++ * builds a smaller queue, it becomes more vulnerable to noise in RTT ++ * measurements (e.g., delayed ACKs or other ACK compression effects). This ++ * noise may cause BBR to under-estimate the rate. ++ * ++ * To achieve full performance in high-speed paths, we budget enough cwnd to ++ * fit full-sized skbs in-flight on both end hosts to fully utilize the path: ++ * - one skb in sending host Qdisc, ++ * - one skb in sending host TSO/GSO engine ++ * - one skb being received by receiver host LRO/GRO/delayed-ACK engine ++ * Don't worry, at low rates (bbr_min_tso_rate) this won't bloat cwnd because ++ * in such cases tso_segs_goal is 1. The minimum cwnd is 4 packets, ++ * which allows 2 outstanding 2-packet sequences, to try to keep pipe ++ * full even with ACK-every-other-packet delayed ACKs. ++ */ ++static u32 bbr_target_cwnd(struct sock *sk, u32 bw, int gain) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 cwnd; ++ u64 w; ++ ++ /* If we've never had a valid RTT sample, cap cwnd at the initial ++ * default. This should only happen when the connection is not using TCP ++ * timestamps and has retransmitted all of the SYN/SYNACK/data packets ++ * ACKed so far. In this case, an RTO can cut cwnd to 1, in which ++ * case we need to slow-start up toward something safe: TCP_INIT_CWND. ++ */ ++ if (unlikely(bbr->min_rtt_us == ~0U)) /* no valid RTT samples yet? */ ++ return TCP_INIT_CWND; /* be safe: cap at default initial cwnd*/ ++ ++ w = (u64)bw * bbr->min_rtt_us; ++ ++ /* Apply a gain to the given value, then remove the BW_SCALE shift. */ ++ cwnd = (((w * gain) >> BBR_SCALE) + BW_UNIT - 1) / BW_UNIT; ++ ++ /* Allow enough full-sized skbs in flight to utilize end systems. */ ++ cwnd += 3 * bbr_tso_segs_goal(sk); ++ ++ /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ ++ cwnd = (cwnd + 1) & ~1U; ++ ++ /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ ++ if (bbr->mode == BBR_PROBE_BW && gain > BBR_UNIT) ++ cwnd += 2; ++ ++ return cwnd; ++} ++ ++/* An optimization in BBR to reduce losses: On the first round of recovery, we ++ * follow the packet conservation principle: send P packets per P packets acked. ++ * After that, we slow-start and send at most 2*P packets per P packets acked. ++ * After recovery finishes, or upon undo, we restore the cwnd we had when ++ * recovery started (capped by the target cwnd based on estimated BDP). ++ * ++ * TODO(ycheng/ncardwell): implement a rate-based approach. ++ */ ++static bool bbr_set_cwnd_to_recover_or_restore( ++ struct sock *sk, const struct rate_sample *rs, u32 acked, u32 *new_cwnd) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u8 prev_state = bbr->prev_ca_state, state = inet_csk(sk)->icsk_ca_state; ++ u32 cwnd = tp->snd_cwnd; ++ ++ /* An ACK for P pkts should release at most 2*P packets. We do this ++ * in two steps. First, here we deduct the number of lost packets. ++ * Then, in bbr_set_cwnd() we slow start up toward the target cwnd. ++ */ ++ if (rs->losses > 0) ++ cwnd = max_t(s32, cwnd - rs->losses, 1); ++ ++ if (state == TCP_CA_Recovery && prev_state != TCP_CA_Recovery) { ++ /* Starting 1st round of Recovery, so do packet conservation. */ ++ bbr->packet_conservation = 1; ++ bbr->next_rtt_delivered = tp->delivered; /* start round now */ ++ /* Cut unused cwnd from app behavior, TSQ, or TSO deferral: */ ++ cwnd = tcp_packets_in_flight(tp) + acked; ++ } else if (prev_state >= TCP_CA_Recovery && state < TCP_CA_Recovery) { ++ /* Exiting loss recovery; restore cwnd saved before recovery. */ ++ cwnd = max(cwnd, bbr->prior_cwnd); ++ bbr->packet_conservation = 0; ++ } ++ bbr->prev_ca_state = state; ++ ++ if (bbr->packet_conservation) { ++ *new_cwnd = max(cwnd, tcp_packets_in_flight(tp) + acked); ++ return true; /* yes, using packet conservation */ ++ } ++ *new_cwnd = cwnd; ++ return false; ++} ++ ++/* Slow-start up toward target cwnd (if bw estimate is growing, or packet loss ++ * has drawn us down below target), or snap down to target if we're above it. ++ */ ++static void bbr_set_cwnd(struct sock *sk, const struct rate_sample *rs, ++ u32 acked, u32 bw, int gain) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 cwnd = tp->snd_cwnd, target_cwnd = 0; ++ ++ if (!acked) ++ goto done; /* no packet fully ACKed; just apply caps */ ++ ++ if (bbr_set_cwnd_to_recover_or_restore(sk, rs, acked, &cwnd)) ++ goto done; ++ ++ /* If we're below target cwnd, slow start cwnd toward target cwnd. */ ++ target_cwnd = bbr_target_cwnd(sk, bw, gain); ++ if (bbr_full_bw_reached(sk)) /* only cut cwnd if we filled the pipe */ ++ cwnd = min(cwnd + acked, target_cwnd); ++ else if (cwnd < target_cwnd || tp->delivered < TCP_INIT_CWND) ++ cwnd = cwnd + acked; ++ cwnd = max(cwnd, bbr_cwnd_min_target); ++ ++done: ++ tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp); /* apply global cap */ ++ if (bbr->mode == BBR_PROBE_RTT) /* drain queue, refresh min_rtt */ ++ tp->snd_cwnd = min(tp->snd_cwnd, bbr_cwnd_min_target); ++} ++ ++/* End cycle phase if it's time and/or we hit the phase's in-flight target. */ ++static bool bbr_is_next_cycle_phase(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ bool is_full_length = ++ tcp_stamp_us_delta(tp->delivered_mstamp, bbr->cycle_mstamp) > ++ bbr->min_rtt_us; ++ u32 inflight, bw; ++ ++ /* The pacing_gain of 1.0 paces at the estimated bw to try to fully ++ * use the pipe without increasing the queue. ++ */ ++ if (bbr->pacing_gain == BBR_UNIT) ++ return is_full_length; /* just use wall clock time */ ++ ++ inflight = rs->prior_in_flight; /* what was in-flight before ACK? */ ++ bw = bbr_max_bw(sk); ++ ++ /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at ++ * least pacing_gain*BDP; this may take more than min_rtt if min_rtt is ++ * small (e.g. on a LAN). We do not persist if packets are lost, since ++ * a path with small buffers may not hold that much. ++ */ ++ if (bbr->pacing_gain > BBR_UNIT) ++ return is_full_length && ++ (rs->losses || /* perhaps pacing_gain*BDP won't fit */ ++ inflight >= bbr_target_cwnd(sk, bw, bbr->pacing_gain)); ++ ++ /* A pacing_gain < 1.0 tries to drain extra queue we added if bw ++ * probing didn't find more bw. If inflight falls to match BDP then we ++ * estimate queue is drained; persisting would underutilize the pipe. ++ */ ++ return is_full_length || ++ inflight <= bbr_target_cwnd(sk, bw, BBR_UNIT); ++} ++ ++static void bbr_advance_cycle_phase(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1); ++ bbr->cycle_mstamp = tp->delivered_mstamp; ++ bbr->pacing_gain = bbr->lt_use_bw ? BBR_UNIT : ++ bbr_pacing_gain[bbr->cycle_idx]; ++} ++ ++/* Gain cycling: cycle pacing gain to converge to fair share of available bw. */ ++static void bbr_update_cycle_phase(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs)) ++ bbr_advance_cycle_phase(sk); ++} ++ ++static void bbr_reset_startup_mode(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->mode = BBR_STARTUP; ++ bbr->pacing_gain = bbr_high_gain; ++ bbr->cwnd_gain = bbr_high_gain; ++} ++ ++static void bbr_reset_probe_bw_mode(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->mode = BBR_PROBE_BW; ++ bbr->pacing_gain = BBR_UNIT; ++ bbr->cwnd_gain = bbr_cwnd_gain; ++ bbr->cycle_idx = CYCLE_LEN - 1 - prandom_u32_max(bbr_cycle_rand); ++ bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */ ++} ++ ++static void bbr_reset_mode(struct sock *sk) ++{ ++ if (!bbr_full_bw_reached(sk)) ++ bbr_reset_startup_mode(sk); ++ else ++ bbr_reset_probe_bw_mode(sk); ++} ++ ++/* Start a new long-term sampling interval. */ ++static void bbr_reset_lt_bw_sampling_interval(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->lt_last_stamp = div_u64(tp->delivered_mstamp, USEC_PER_MSEC); ++ bbr->lt_last_delivered = tp->delivered; ++ bbr->lt_last_lost = tp->lost; ++ bbr->lt_rtt_cnt = 0; ++} ++ ++/* Completely reset long-term bandwidth sampling. */ ++static void bbr_reset_lt_bw_sampling(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->lt_bw = 0; ++ bbr->lt_use_bw = 0; ++ bbr->lt_is_sampling = false; ++ bbr_reset_lt_bw_sampling_interval(sk); ++} ++ ++/* Long-term bw sampling interval is done. Estimate whether we're policed. */ ++static void bbr_lt_bw_interval_done(struct sock *sk, u32 bw) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 diff; ++ ++ if (bbr->lt_bw) { /* do we have bw from a previous interval? */ ++ /* Is new bw close to the lt_bw from the previous interval? */ ++ diff = abs(bw - bbr->lt_bw); ++ if ((diff * BBR_UNIT <= bbr_lt_bw_ratio * bbr->lt_bw) || ++ (bbr_rate_bytes_per_sec(sk, diff, BBR_UNIT) <= ++ bbr_lt_bw_diff)) { ++ /* All criteria are met; estimate we're policed. */ ++ bbr->lt_bw = (bw + bbr->lt_bw) >> 1; /* avg 2 intvls */ ++ bbr->lt_use_bw = 1; ++ bbr->pacing_gain = BBR_UNIT; /* try to avoid drops */ ++ bbr->lt_rtt_cnt = 0; ++ return; ++ } ++ } ++ bbr->lt_bw = bw; ++ bbr_reset_lt_bw_sampling_interval(sk); ++} ++ ++/* Token-bucket traffic policers are common (see "An Internet-Wide Analysis of ++ * Traffic Policing", SIGCOMM 2016). BBR detects token-bucket policers and ++ * explicitly models their policed rate, to reduce unnecessary losses. We ++ * estimate that we're policed if we see 2 consecutive sampling intervals with ++ * consistent throughput and high packet loss. If we think we're being policed, ++ * set lt_bw to the "long-term" average delivery rate from those 2 intervals. ++ */ ++static void bbr_lt_bw_sampling(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 lost, delivered; ++ u64 bw; ++ u32 t; ++ ++ if (bbr->lt_use_bw) { /* already using long-term rate, lt_bw? */ ++ if (bbr->mode == BBR_PROBE_BW && bbr->round_start && ++ ++bbr->lt_rtt_cnt >= bbr_lt_bw_max_rtts) { ++ bbr_reset_lt_bw_sampling(sk); /* stop using lt_bw */ ++ bbr_reset_probe_bw_mode(sk); /* restart gain cycling */ ++ } ++ return; ++ } ++ ++ /* Wait for the first loss before sampling, to let the policer exhaust ++ * its tokens and estimate the steady-state rate allowed by the policer. ++ * Starting samples earlier includes bursts that over-estimate the bw. ++ */ ++ if (!bbr->lt_is_sampling) { ++ if (!rs->losses) ++ return; ++ bbr_reset_lt_bw_sampling_interval(sk); ++ bbr->lt_is_sampling = true; ++ } ++ ++ /* To avoid underestimates, reset sampling if we run out of data. */ ++ if (rs->is_app_limited) { ++ bbr_reset_lt_bw_sampling(sk); ++ return; ++ } ++ ++ if (bbr->round_start) ++ bbr->lt_rtt_cnt++; /* count round trips in this interval */ ++ if (bbr->lt_rtt_cnt < bbr_lt_intvl_min_rtts) ++ return; /* sampling interval needs to be longer */ ++ if (bbr->lt_rtt_cnt > 4 * bbr_lt_intvl_min_rtts) { ++ bbr_reset_lt_bw_sampling(sk); /* interval is too long */ ++ return; ++ } ++ ++ /* End sampling interval when a packet is lost, so we estimate the ++ * policer tokens were exhausted. Stopping the sampling before the ++ * tokens are exhausted under-estimates the policed rate. ++ */ ++ if (!rs->losses) ++ return; ++ ++ /* Calculate packets lost and delivered in sampling interval. */ ++ lost = tp->lost - bbr->lt_last_lost; ++ delivered = tp->delivered - bbr->lt_last_delivered; ++ /* Is loss rate (lost/delivered) >= lt_loss_thresh? If not, wait. */ ++ if (!delivered || (lost << BBR_SCALE) < bbr_lt_loss_thresh * delivered) ++ return; ++ ++ /* Find average delivery rate in this sampling interval. */ ++ t = div_u64(tp->delivered_mstamp, USEC_PER_MSEC) - bbr->lt_last_stamp; ++ if ((s32)t < 1) ++ return; /* interval is less than one ms, so wait */ ++ /* Check if can multiply without overflow */ ++ if (t >= ~0U / USEC_PER_MSEC) { ++ bbr_reset_lt_bw_sampling(sk); /* interval too long; reset */ ++ return; ++ } ++ t *= USEC_PER_MSEC; ++ bw = (u64)delivered * BW_UNIT; ++ do_div(bw, t); ++ bbr_lt_bw_interval_done(sk, bw); ++} ++ ++/* Estimate the bandwidth based on how fast packets are delivered */ ++static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw; ++ ++ bbr->round_start = 0; ++ if (rs->delivered < 0 || rs->interval_us <= 0) ++ return; /* Not a valid observation */ ++ ++ /* See if we've reached the next RTT */ ++ if (!before(rs->prior_delivered, bbr->next_rtt_delivered)) { ++ bbr->next_rtt_delivered = tp->delivered; ++ bbr->rtt_cnt++; ++ bbr->round_start = 1; ++ bbr->packet_conservation = 0; ++ } ++ ++ bbr_lt_bw_sampling(sk, rs); ++ ++ /* Divide delivered by the interval to find a (lower bound) bottleneck ++ * bandwidth sample. Delivered is in packets and interval_us in uS and ++ * ratio will be <<1 for most connections. So delivered is first scaled. ++ */ ++ bw = (u64)rs->delivered * BW_UNIT; ++ do_div(bw, rs->interval_us); ++ ++ /* If this sample is application-limited, it is likely to have a very ++ * low delivered count that represents application behavior rather than ++ * the available network rate. Such a sample could drag down estimated ++ * bw, causing needless slow-down. Thus, to continue to send at the ++ * last measured network rate, we filter out app-limited samples unless ++ * they describe the path bw at least as well as our bw model. ++ * ++ * So the goal during app-limited phase is to proceed with the best ++ * network rate no matter how long. We automatically leave this ++ * phase when app writes faster than the network can deliver :) ++ */ ++ if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) { ++ /* Incorporate new sample into our max bw filter. */ ++ minmax_running_max(&bbr->bw, bbr_bw_rtts, bbr->rtt_cnt, bw); ++ } ++} ++ ++/* Estimate when the pipe is full, using the change in delivery rate: BBR ++ * estimates that STARTUP filled the pipe if the estimated bw hasn't changed by ++ * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited ++ * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the ++ * higher rwin, 3: we get higher delivery rate samples. Or transient ++ * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar ++ * design goal, but uses delay and inter-ACK spacing instead of bandwidth. ++ */ ++static void bbr_check_full_bw_reached(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bw_thresh; ++ ++ if (bbr_full_bw_reached(sk) || !bbr->round_start || rs->is_app_limited) ++ return; ++ ++ bw_thresh = (u64)bbr->full_bw * bbr_full_bw_thresh >> BBR_SCALE; ++ if (bbr_max_bw(sk) >= bw_thresh) { ++ bbr->full_bw = bbr_max_bw(sk); ++ bbr->full_bw_cnt = 0; ++ return; ++ } ++ ++bbr->full_bw_cnt; ++ bbr->full_bw_reached = bbr->full_bw_cnt >= bbr_full_bw_cnt; ++} ++ ++/* If pipe is probably full, drain the queue and then enter steady-state. */ ++static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { ++ bbr->mode = BBR_DRAIN; /* drain queue we created */ ++ bbr->pacing_gain = bbr_drain_gain; /* pace slow to drain */ ++ bbr->cwnd_gain = bbr_high_gain; /* maintain cwnd */ ++ tcp_sk(sk)->snd_ssthresh = ++ bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT); ++ } /* fall through to check if in-flight is already small: */ ++ if (bbr->mode == BBR_DRAIN && ++ tcp_packets_in_flight(tcp_sk(sk)) <= ++ bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT)) ++ bbr_reset_probe_bw_mode(sk); /* we estimate queue is drained */ ++} ++ ++static void bbr_check_probe_rtt_done(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (!(bbr->probe_rtt_done_stamp && ++ after(tcp_jiffies32, bbr->probe_rtt_done_stamp))) ++ return; ++ ++ bbr->min_rtt_stamp = tcp_jiffies32; /* wait a while until PROBE_RTT */ ++ tp->snd_cwnd = max(tp->snd_cwnd, bbr->prior_cwnd); ++ bbr_reset_mode(sk); ++} ++ ++/* The goal of PROBE_RTT mode is to have BBR flows cooperatively and ++ * periodically drain the bottleneck queue, to converge to measure the true ++ * min_rtt (unloaded propagation delay). This allows the flows to keep queues ++ * small (reducing queuing delay and packet loss) and achieve fairness among ++ * BBR flows. ++ * ++ * The min_rtt filter window is 10 seconds. When the min_rtt estimate expires, ++ * we enter PROBE_RTT mode and cap the cwnd at bbr_cwnd_min_target=4 packets. ++ * After at least bbr_probe_rtt_mode_ms=200ms and at least one packet-timed ++ * round trip elapsed with that flight size <= 4, we leave PROBE_RTT mode and ++ * re-enter the previous mode. BBR uses 200ms to approximately bound the ++ * performance penalty of PROBE_RTT's cwnd capping to roughly 2% (200ms/10s). ++ * ++ * Note that flows need only pay 2% if they are busy sending over the last 10 ++ * seconds. Interactive applications (e.g., Web, RPCs, video chunks) often have ++ * natural silences or low-rate periods within 10 seconds where the rate is low ++ * enough for long enough to drain its queue in the bottleneck. We pick up ++ * these min RTT measurements opportunistically with our min_rtt filter. :-) ++ */ ++static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ bool filter_expired; ++ ++ /* Track min RTT seen in the min_rtt_win_sec filter window: */ ++ filter_expired = after(tcp_jiffies32, ++ bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ); ++ if (rs->rtt_us >= 0 && ++ (rs->rtt_us <= bbr->min_rtt_us || ++ (filter_expired && !rs->is_ack_delayed))) { ++ bbr->min_rtt_us = rs->rtt_us; ++ bbr->min_rtt_stamp = tcp_jiffies32; ++ } ++ ++ if (bbr_probe_rtt_mode_ms > 0 && filter_expired && ++ !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) { ++ bbr->mode = BBR_PROBE_RTT; /* dip, drain queue */ ++ bbr->pacing_gain = BBR_UNIT; ++ bbr->cwnd_gain = BBR_UNIT; ++ bbr_save_cwnd(sk); /* note cwnd so we can restore it */ ++ bbr->probe_rtt_done_stamp = 0; ++ } ++ ++ if (bbr->mode == BBR_PROBE_RTT) { ++ /* Ignore low rate samples during this mode. */ ++ tp->app_limited = ++ (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; ++ /* Maintain min packets in flight for max(200 ms, 1 round). */ ++ if (!bbr->probe_rtt_done_stamp && ++ tcp_packets_in_flight(tp) <= bbr_cwnd_min_target) { ++ bbr->probe_rtt_done_stamp = tcp_jiffies32 + ++ msecs_to_jiffies(bbr_probe_rtt_mode_ms); ++ bbr->probe_rtt_round_done = 0; ++ bbr->next_rtt_delivered = tp->delivered; ++ } else if (bbr->probe_rtt_done_stamp) { ++ if (bbr->round_start) ++ bbr->probe_rtt_round_done = 1; ++ if (bbr->probe_rtt_round_done) ++ bbr_check_probe_rtt_done(sk); ++ } ++ } ++ /* Restart after idle ends only once we process a new S/ACK for data */ ++ if (rs->delivered > 0) ++ bbr->idle_restart = 0; ++} ++ ++static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) ++{ ++ bbr_update_bw(sk, rs); ++ bbr_update_cycle_phase(sk, rs); ++ bbr_check_full_bw_reached(sk, rs); ++ bbr_check_drain(sk, rs); ++ bbr_update_min_rtt(sk, rs); ++} ++ ++static void bbr_main(struct sock *sk, const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bw; ++ ++ bbr_update_model(sk, rs); ++ ++ bw = bbr_bw(sk); ++ bbr_set_pacing_rate(sk, bw, bbr->pacing_gain); ++ bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain); ++} ++ ++static void bbr_init(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->prior_cwnd = 0; ++ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ bbr->rtt_cnt = 0; ++ bbr->next_rtt_delivered = 0; ++ bbr->prev_ca_state = TCP_CA_Open; ++ bbr->packet_conservation = 0; ++ ++ bbr->probe_rtt_done_stamp = 0; ++ bbr->probe_rtt_round_done = 0; ++ bbr->min_rtt_us = tcp_min_rtt(tp); ++ bbr->min_rtt_stamp = tcp_jiffies32; ++ ++ minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */ ++ ++ bbr->has_seen_rtt = 0; ++ bbr_init_pacing_rate_from_rtt(sk); ++ ++ bbr->round_start = 0; ++ bbr->idle_restart = 0; ++ bbr->full_bw_reached = 0; ++ bbr->full_bw = 0; ++ bbr->full_bw_cnt = 0; ++ bbr->cycle_mstamp = 0; ++ bbr->cycle_idx = 0; ++ bbr_reset_lt_bw_sampling(sk); ++ bbr_reset_startup_mode(sk); ++ ++ cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); ++} ++ ++static u32 bbr_sndbuf_expand(struct sock *sk) ++{ ++ /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ ++ return 3; ++} ++ ++/* In theory BBR does not need to undo the cwnd since it does not ++ * always reduce cwnd on losses (see bbr_main()). Keep it for now. ++ */ ++static u32 bbr_undo_cwnd(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->full_bw = 0; /* spurious slow-down; reset full pipe detection */ ++ bbr->full_bw_cnt = 0; ++ bbr_reset_lt_bw_sampling(sk); ++ return tcp_sk(sk)->snd_cwnd; ++} ++ ++/* Entering loss recovery, so save cwnd for when we exit or undo recovery. */ ++static u32 bbr_ssthresh(struct sock *sk) ++{ ++ bbr_save_cwnd(sk); ++ return tcp_sk(sk)->snd_ssthresh; ++} ++ ++static size_t bbr_get_info(struct sock *sk, u32 ext, int *attr, ++ union tcp_cc_info *info) ++{ ++ if (ext & (1 << (INET_DIAG_BBRINFO - 1)) || ++ ext & (1 << (INET_DIAG_VEGASINFO - 1))) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw = bbr_bw(sk); ++ ++ bw = bw * tp->mss_cache * USEC_PER_SEC >> BW_SCALE; ++ memset(&info->bbr, 0, sizeof(info->bbr)); ++ info->bbr.bbr_bw_lo = (u32)bw; ++ info->bbr.bbr_bw_hi = (u32)(bw >> 32); ++ info->bbr.bbr_min_rtt = bbr->min_rtt_us; ++ info->bbr.bbr_pacing_gain = bbr->pacing_gain; ++ info->bbr.bbr_cwnd_gain = bbr->cwnd_gain; ++ *attr = INET_DIAG_BBRINFO; ++ return sizeof(info->bbr); ++ } ++ return 0; ++} ++ ++static void bbr_set_state(struct sock *sk, u8 new_state) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (new_state == TCP_CA_Loss) { ++ struct rate_sample rs = { .losses = 1 }; ++ ++ bbr->prev_ca_state = TCP_CA_Loss; ++ bbr->full_bw = 0; ++ bbr->round_start = 1; /* treat RTO like end of a round */ ++ bbr_lt_bw_sampling(sk, &rs); ++ } ++} ++ ++static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = { ++ .flags = TCP_CONG_NON_RESTRICTED, ++ .name = "nanqinlang", ++ .owner = THIS_MODULE, ++ .init = bbr_init, ++ .cong_control = bbr_main, ++ .sndbuf_expand = bbr_sndbuf_expand, ++ .undo_cwnd = bbr_undo_cwnd, ++ .cwnd_event = bbr_cwnd_event, ++ .ssthresh = bbr_ssthresh, ++ .min_tso_segs = bbr_min_tso_segs, ++ .get_info = bbr_get_info, ++ .set_state = bbr_set_state, ++}; ++ ++static int __init bbr_register(void) ++{ ++ BUILD_BUG_ON(sizeof(struct bbr) > ICSK_CA_PRIV_SIZE); ++ return tcp_register_congestion_control(&tcp_bbr_cong_ops); ++} ++ ++static void __exit bbr_unregister(void) ++{ ++ tcp_unregister_congestion_control(&tcp_bbr_cong_ops); ++} ++ ++module_init(bbr_register); ++module_exit(bbr_unregister); ++ ++MODULE_AUTHOR("Van Jacobson "); ++MODULE_AUTHOR("Neal Cardwell "); ++MODULE_AUTHOR("Yuchung Cheng "); ++MODULE_AUTHOR("Soheil Hassas Yeganeh "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("TCP BBR (Bottleneck Bandwidth and RTT)"); ++MODULE_AUTHOR("Nanqinlang "); diff --git a/root/target/linux/generic/hack-5.4/998-ndpi-netfilter.patch b/root/target/linux/generic/hack-5.4/998-ndpi-netfilter.patch new file mode 100644 index 00000000..cd8d61a7 --- /dev/null +++ b/root/target/linux/generic/hack-5.4/998-ndpi-netfilter.patch @@ -0,0 +1,116 @@ +diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h +index 21f887c..59980ec 100644 +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -28,7 +28,8 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif +- NF_CT_EXT_NUM, ++ NF_CT_EXT_CUSTOM, ++ NF_CT_EXT_NUM=NF_CT_EXT_CUSTOM+CONFIG_NF_CONNTRACK_CUSTOM, + }; + + #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help +@@ -96,5 +97,6 @@ struct nf_ct_ext_type { + }; + + int nf_ct_extend_register(const struct nf_ct_ext_type *type); ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type,unsigned long int cid); + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type); + #endif /* _NF_CONNTRACK_EXTEND_H */ +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 7581e82..30a11eb 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -85,6 +85,16 @@ config NF_CONNTRACK_SECMARK + + If unsure, say 'N'. + ++config NF_CONNTRACK_CUSTOM ++ int "Number of custom extend" ++ range 0 8 ++ depends on NETFILTER_ADVANCED ++ default "2" ++ help ++ This parameter specifies how many custom extensions can be registered. ++ ++ The default value is 2. ++ + config NF_CONNTRACK_ZONES + bool 'Connection tracking zones' + depends on NETFILTER_ADVANCED +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 85f643c..44e2fdd 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1971,7 +1971,7 @@ int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp) + static __always_inline unsigned int total_extension_size(void) + { + /* remember to add new extensions below */ +- BUILD_BUG_ON(NF_CT_EXT_NUM > 9); ++ BUILD_BUG_ON(NF_CT_EXT_NUM > 12); + + return sizeof(struct nf_ct_ext) + + sizeof(struct nf_conn_help) +diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c +index 9fe0ddc..5a9054e 100644 +--- a/net/netfilter/nf_conntrack_extend.c ++++ b/net/netfilter/nf_conntrack_extend.c +@@ -108,11 +108,56 @@ int nf_ct_extend_register(const struct nf_ct_ext_type *type) + } + EXPORT_SYMBOL_GPL(nf_ct_extend_register); + ++static unsigned long int nf_ct_ext_cust_id[CONFIG_NF_CONNTRACK_CUSTOM]; ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id); ++ ++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type, ++ unsigned long int cid) ++{ ++ int ret; ++ enum nf_ct_ext_id new_id = nf_ct_extend_get_custom_id(cid); ++ if(!new_id) ++ return -EBUSY; ++ type->id = new_id; ++ ret = nf_ct_extend_register(type); ++ if(ret < 0) { ++ mutex_lock(&nf_ct_ext_type_mutex); ++ nf_ct_ext_cust_id[new_id - NF_CT_EXT_CUSTOM] = 0; ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(nf_ct_extend_custom_register); ++ ++static enum nf_ct_ext_id ++nf_ct_extend_get_custom_id(unsigned long int ext_id) ++{ ++ enum nf_ct_ext_id ret = 0; ++ int i; ++ mutex_lock(&nf_ct_ext_type_mutex); ++ for(i = 0; i < CONFIG_NF_CONNTRACK_CUSTOM; i++) { ++ if(!nf_ct_ext_cust_id[i]) { ++ nf_ct_ext_cust_id[i] = ext_id; ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ if(nf_ct_ext_cust_id[i] == ext_id) { ++ ret = i+NF_CT_EXT_CUSTOM; ++ break; ++ } ++ } ++ mutex_unlock(&nf_ct_ext_type_mutex); ++ return ret; ++} ++ + /* This MUST be called in process context. */ + void nf_ct_extend_unregister(const struct nf_ct_ext_type *type) + { + mutex_lock(&nf_ct_ext_type_mutex); + RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); ++ if(type->id >= NF_CT_EXT_CUSTOM && type->id < NF_CT_EXT_NUM) ++ nf_ct_ext_cust_id[type->id-NF_CT_EXT_CUSTOM] = 0; + mutex_unlock(&nf_ct_ext_type_mutex); + synchronize_rcu(); + } diff --git a/root/target/linux/generic/hack-5.4/999-stop-promiscuous-info.patch b/root/target/linux/generic/hack-5.4/999-stop-promiscuous-info.patch new file mode 100644 index 00000000..850613b5 --- /dev/null +++ b/root/target/linux/generic/hack-5.4/999-stop-promiscuous-info.patch @@ -0,0 +1,47 @@ +--- a/net/core/dev.c 2018-08-10 10:31:41.199494561 +0200 ++++ b/net/core/dev.c 2018-08-10 10:32:03.635272509 +0200 +@@ -6613,9 +6613,11 @@ + } + } + if (dev->flags != old_flags) { ++ /* + pr_info("device %s %s promiscuous mode\n", + dev->name, + dev->flags & IFF_PROMISC ? "entered" : "left"); ++ */ + if (audit_enabled) { + current_uid_gid(&uid, &gid); + audit_log(current->audit_context, GFP_ATOMIC, +--- a/drivers/net/usb/r8152.c 2020-08-13 13:11:25.866435255 +0200 ++++ b/drivers/net/usb/r8152.c 2020-08-13 13:11:51.973994306 +0200 +@@ -2353,7 +2353,7 @@ + + if (netdev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ +- netif_notice(tp, link, netdev, "Promiscuous mode enabled\n"); ++ //netif_notice(tp, link, netdev, "Promiscuous mode enabled\n"); + ocp_data |= RCR_AM | RCR_AAP; + mc_filter[1] = 0xffffffff; + mc_filter[0] = 0xffffffff; +--- a/drivers/net/usb/pegasus.c 2020-08-13 13:14:15.519570376 +0200 ++++ b/drivers/net/usb/pegasus.c 2020-08-13 13:14:26.795380006 +0200 +@@ -1031,7 +1031,7 @@ + + if (net->flags & IFF_PROMISC) { + pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; +- netif_info(pegasus, link, net, "Promiscuous mode enabled\n"); ++ //netif_info(pegasus, link, net, "Promiscuous mode enabled\n"); + } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { + pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; + pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; +--- a/drivers/net/ethernet/realtek/r8169_main.c 2020-08-13 13:15:44.478068638 +0200 ++++ b/drivers/net/ethernet/realtek/r8169_main.c 2020-08-13 13:15:59.181820450 +0200 +@@ -4313,7 +4313,7 @@ + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ +- netif_notice(tp, link, dev, "Promiscuous mode enabled\n"); ++ //netif_notice(tp, link, dev, "Promiscuous mode enabled\n"); + rx_mode |= AcceptAllPhys; + } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT || + dev->flags & IFF_ALLMULTI || diff --git a/root/target/linux/ipq40xx/base-files/etc/board.d/02_network b/root/target/linux/ipq40xx/base-files/etc/board.d/02_network new file mode 100755 index 00000000..0ac8b59a --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/board.d/02_network @@ -0,0 +1,173 @@ +#!/bin/sh +# +# Copyright (c) 2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2011-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh +. /lib/functions/system.sh + +ipq40xx_setup_interfaces() +{ + local board="$1" + + case "$board" in + 8dev,habanero-dvk|\ + 8dev,jalapeno|\ + alfa-network,ap120c-ac|\ + engenius,emr3500|\ + engenius,ens620ext) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ;; + aruba,ap-303|\ + aruba,ap-365|\ + avm,fritzrepeater-1200|\ + dlink,dap-2610 |\ + engenius,eap1300|\ + engenius,emd1|\ + meraki,mr33|\ + netgear,ex6100v2|\ + netgear,ex6150v2|\ + zyxel,wre6606) + ucidef_set_interface_lan "eth0" + ;; + aruba,ap-303h) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "0u@eth1" "5:wan" + ;; + asus,map-ac2200|\ + cilab,meshpoint-one|\ + openmesh,a42|\ + openmesh,a62) + ucidef_set_interfaces_lan_wan "eth1" "eth0" + ;; + asus,rt-ac58u|\ + p2w,r619ac-128m|\ + p2w,r619ac|\ + zyxel,nbg6617) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" + ;; + avm,fritzbox-4040|\ + linksys,ea6350v3|\ + linksys,ea8300) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" + ;; + avm,fritzbox-7530) + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" + ;; + avm,fritzrepeater-3000|\ + compex,wpj419|\ + compex,wpj428|\ + engenius,eap2200) + ucidef_set_interface_lan "eth0 eth1" + ;; + buffalo,wtr-m2133hp) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:3" "3:lan:2" "4:lan:1" + ;; + cellc,rtl30vw) + ucidef_set_interface_lan "eth0" + ucidef_add_switch "switch0" \ + "0u@eth0" "3:lan" "4:lan" + ;; + ezviz,cs-w3-wd1200g-eup) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:3" "3:lan:2" "4:lan:1" "0u@eth1" "5:wan" + ;; + glinet,gl-b1300 |\ + glinet,gl-s1300) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "3:lan" "4:lan" + ;; + mobipromo,cm520-79f) + ucidef_add_switch "switch0" \ + "0u@eth0" "3:lan:2" "4:lan:1" + ucidef_set_interface_wan "eth1" + ;; + qxwlan,e2600ac-c1 |\ + qxwlan,e2600ac-c2) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "3:lan" "4:lan" "0u@eth1" "5:wan" + ;; + unielec,u4019-32m) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "0u@eth1" "5:wan" + ;; + *) + echo "Unsupported hardware. Network interfaces not initialized" + ;; + esac +} + +ipq40xx_setup_macs() +{ + local board="$1" + local lan_mac="" + local wan_mac="" + local label_mac="" + + case "$board" in + 8dev,habanero-dvk) + label_mac=$(mtd_get_mac_binary "ART" 0x1006) + ;; + asus,rt-ac58u|\ + p2w,r619ac-128m|\ + p2w,r619ac) + CI_UBIPART=UBI_DEV + wan_mac=$(mtd_get_mac_binary_ubi Factory 0x1006) + lan_mac=$(mtd_get_mac_binary_ubi Factory 0x5006) + label_mac=$wan_mac + ;; + cilab,meshpoint-one) + label_mac=$(mtd_get_mac_binary "ART" 0x1006) + ;; + dlink,dap-2610) + lan_mac=$(mtd_get_mac_ascii bdcfg lanmac) + label_mac=$lan_mac + ;; + engenius,eap2200|\ + engenius,emd1) + lan_mac=$(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + label_mac=$lan_mac + ;; + engenius,emr3500) + wan_mac=$(mtd_get_mac_ascii 0:APPSBLENV wanaddr) + lan_mac=$(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + label_mac=$wan_mac + ;; + engenius,ens620ext) + wan_mac=$(mtd_get_mac_ascii u-boot-env ethaddr) + lan_mac=$(macaddr_add "$wan_mac" 1) + ;; + ezviz,cs-w3-wd1200g-eup) + label_mac=$(mtd_get_mac_binary "ART" 0x6) + ;; + linksys,ea6350v3) + wan_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr) + lan_mac=$(macaddr_add "$wan_mac" 1) + ;; + esac + + [ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac + [ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac + [ -n "$label_mac" ] && ucidef_set_label_macaddr $label_mac +} + +board_config_update +board=$(board_name) +ipq40xx_setup_interfaces $board +ipq40xx_setup_macs $board +board_config_flush + +exit 0 diff --git a/root/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/root/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata new file mode 100644 index 00000000..4b69c79f --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -0,0 +1,242 @@ +#!/bin/sh + +[ -e /lib/firmware/$FIRMWARE ] && exit 0 + +. /lib/functions/caldata.sh + +board=$(board_name) + +case "$FIRMWARE" in +"ath10k/cal-pci-0000:01:00.0.bin") + case "$board" in + meraki,mr33) + caldata_extract_ubi "ART" 0x9000 0x844 + caldata_valid "4408" || caldata_extract "ART" 0x9000 0x844 + ath10k_patch_mac $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 0x66) +1) + ;; + esac + ;; +"ath10k/pre-cal-pci-0000:01:00.0.bin") + case "$board" in + asus,map-ac2200) + caldata_extract_ubi "Factory" 0x9000 0x2f20 + ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \ + /lib/firmware/ath10k/QCA9888/hw2.0/board.bin + ;; + avm,fritzrepeater-3000) + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x212 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") + ;; + buffalo,wtr-m2133hp) + caldata_extract "ART" 0x9000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary ORGDATA 0x32) + ;; + engenius,eap2200 |\ + openmesh,a62) + caldata_extract "0:ART" 0x9000 0x2f20 + ;; + linksys,ea8300) + caldata_extract "ART" 0x9000 0x2f20 + # OEM assigns 4 sequential MACs + ath10k_patch_mac $(macaddr_setbit_la $(macaddr_add "$(cat /sys/class/net/eth0/address)" 4)) + ;; + esac + ;; +"ath10k/pre-cal-ahb-a000000.wifi.bin") + case "$board" in + 8dev,habanero-dvk |\ + 8dev,jalapeno |\ + alfa-network,ap120c-ac |\ + cilab,meshpoint-one |\ + ezviz,cs-w3-wd1200g-eup |\ + glinet,gl-b1300 |\ + glinet,gl-s1300 |\ + linksys,ea6350v3 |\ + mobipromo,cm520-79f |\ + p2w,r619ac-128m |\ + p2w,r619ac |\ + qcom,ap-dk01.1-c1) + caldata_extract "ART" 0x1000 0x2f20 + ;; + aruba,ap-303 |\ + aruba,ap-303h |\ + aruba,ap-365) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary mfginfo 0x1D) + ;; + asus,map-ac2200) + caldata_extract_ubi "Factory" 0x1000 0x2f20 + ;; + asus,rt-ac58u) + CI_UBIPART=UBI_DEV + caldata_extract_ubi "Factory" 0x1000 0x2f20 + ;; + avm,fritzbox-4040) + /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") + ;; + avm,fritzbox-7530 |\ + avm,fritzrepeater-1200 |\ + avm,fritzrepeater-3000) + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") + ;; + buffalo,wtr-m2133hp) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary ORGDATA 0x26) + ;; + cellc,rtl30vw |\ + compex,wpj419 |\ + compex,wpj428 |\ + engenius,eap1300 |\ + engenius,eap2200 |\ + openmesh,a42 |\ + openmesh,a62 |\ + qxwlan,e2600ac-c1 |\ + qxwlan,e2600ac-c2 |\ + unielec,u4019-32m) + caldata_extract "0:ART" 0x1000 0x2f20 + ;; + dlink,dap-2610) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii bdcfg wlanmac) + ;; + engenius,emd1) + caldata_extract "0:ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:APPSBLENV wlanaddr) + ;; + engenius,emr3500) + caldata_extract "0:ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + ;; + engenius,ens620ext) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii u-boot-env ethaddr) +2) + ;; + linksys,ea8300) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 2) + ;; + meraki,mr33) + caldata_extract_ubi "ART" 0x1000 0x2f20 + caldata_valid "202f" || caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 0x66) +2) + ;; + netgear,ex6100v2 |\ + netgear,ex6150v2) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary dnidata 0x0) + ;; + zyxel,nbg6617 |\ + zyxel,wre6606) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -2) + ;; + esac + ;; +"ath10k/pre-cal-ahb-a800000.wifi.bin") + case "$board" in + 8dev,habanero-dvk |\ + 8dev,jalapeno |\ + alfa-network,ap120c-ac |\ + cilab,meshpoint-one |\ + ezviz,cs-w3-wd1200g-eup |\ + glinet,gl-b1300 |\ + glinet,gl-s1300 |\ + linksys,ea6350v3 |\ + mobipromo,cm520-79f |\ + p2w,r619ac-128m |\ + p2w,r619ac |\ + qcom,ap-dk01.1-c1) + caldata_extract "ART" 0x5000 0x2f20 + ;; + aruba,ap-303 |\ + aruba,ap-303h |\ + aruba,ap-365) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary mfginfo 0x1D) +1) + ;; + asus,map-ac2200) + caldata_extract_ubi "Factory" 0x5000 0x2f20 + ;; + asus,rt-ac58u) + CI_UBIPART=UBI_DEV + caldata_extract_ubi "Factory" 0x5000 0x2f20 + ;; + avm,fritzbox-4040) + /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") + ;; + avm,fritzbox-7530 |\ + avm,fritzrepeater-1200 |\ + avm,fritzrepeater-3000) + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") || \ + /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader1") + ;; + buffalo,wtr-m2133hp) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary ORGDATA 0x2c) + ;; + cellc,rtl30vw |\ + compex,wpj419 |\ + compex,wpj428 |\ + engenius,eap1300 |\ + engenius,eap2200 |\ + openmesh,a42 |\ + openmesh,a62 |\ + qxwlan,e2600ac-c1 |\ + qxwlan,e2600ac-c2 |\ + unielec,u4019-32m) + caldata_extract "0:ART" 0x5000 0x2f20 + ;; + dlink,dap-2610) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii bdcfg wlanmac_a) + ;; + engenius,emd1) + caldata_extract "0:ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:APPSBLENV wlanaddr) +1) + ;; + engenius,emr3500) + caldata_extract "0:ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) +1) + ;; + engenius,ens620ext) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii u-boot-env ethaddr) +3) + ;; + linksys,ea8300) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 3) + ;; + meraki,mr33) + caldata_extract_ubi "ART" 0x5000 0x2f20 + caldata_valid "202f" || caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 0x66) +3) + ;; + netgear,ex6100v2 |\ + netgear,ex6150v2) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary dnidata 0xc) + ;; + zyxel,nbg6617 |\ + zyxel,wre6606) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -1) + ;; + esac + ;; +*) + exit 1 + ;; +esac diff --git a/root/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/root/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh new file mode 100644 index 00000000..f874aa4b --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh @@ -0,0 +1,123 @@ +PART_NAME=firmware +REQUIRE_IMAGE_METADATA=1 + +RAMFS_COPY_BIN='fw_printenv fw_setenv' +RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock' + +platform_check_image() { + case "$(board_name)" in + asus,rt-ac58u) + CI_UBIPART="UBI_DEV" + local ubidev=$(nand_find_ubi $CI_UBIPART) + local asus_root=$(nand_find_volume $ubidev jffs2) + + [ -n "$asus_root" ] || return 0 + + cat << EOF +jffs2 partition is still present. +There's probably no space left +to install the filesystem. + +You need to delete the jffs2 partition first: +# ubirmvol /dev/ubi0 --name=jffs2 + +Once this is done. Retry. +EOF + return 1 + ;; + esac + return 0; +} + +askey_do_upgrade() { + local tar_file="$1" + + local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') + board_dir=${board_dir%/} + + tar Oxf $tar_file ${board_dir}/root | mtd write - rootfs + + nand_do_upgrade "$1" +} + +zyxel_do_upgrade() { + local tar_file="$1" + + local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') + board_dir=${board_dir%/} + + tar Oxf $tar_file ${board_dir}/kernel | mtd write - kernel + + if [ -n "$UPGRADE_BACKUP" ]; then + tar Oxf $tar_file ${board_dir}/root | mtd -j "$UPGRADE_BACKUP" write - rootfs + else + tar Oxf $tar_file ${board_dir}/root | mtd write - rootfs + fi +} + +platform_do_upgrade() { + case "$(board_name)" in + 8dev,jalapeno |\ + aruba,ap-303 |\ + aruba,ap-303h |\ + aruba,ap-365 |\ + avm,fritzbox-7530 |\ + avm,fritzrepeater-1200 |\ + avm,fritzrepeater-3000 |\ + buffalo,wtr-m2133hp |\ + cilab,meshpoint-one |\ + engenius,eap2200 |\ + mobipromo,cm520-79f |\ + qxwlan,e2600ac-c2) + nand_do_upgrade "$1" + ;; + alfa-network,ap120c-ac) + part="$(awk -F 'ubi.mtd=' '{printf $2}' /proc/cmdline | sed -e 's/ .*$//')" + if [ "$part" = "rootfs1" ]; then + fw_setenv active 2 || exit 1 + CI_UBIPART="rootfs2" + else + fw_setenv active 1 || exit 1 + CI_UBIPART="rootfs1" + fi + nand_do_upgrade "$1" + ;; + asus,map-ac2200) + CI_KERNPART="linux" + nand_do_upgrade "$1" + ;; + asus,rt-ac58u) + CI_UBIPART="UBI_DEV" + CI_KERNPART="linux" + nand_do_upgrade "$1" + ;; + cellc,rtl30vw) + CI_UBIPART="ubifs" + askey_do_upgrade "$1" + ;; + compex,wpj419|\ + p2w,r619ac-128m|\ + p2w,r619ac) + nand_do_upgrade "$1" + ;; + linksys,ea6350v3 |\ + linksys,ea8300) + platform_do_upgrade_linksys "$1" + ;; + meraki,mr33) + CI_KERNPART="part.safe" + nand_do_upgrade "$1" + ;; + openmesh,a42 |\ + openmesh,a62) + PART_NAME="inactive" + platform_do_upgrade_openmesh "$1" + ;; + zyxel,nbg6617) + zyxel_do_upgrade "$1" + ;; + *) + default_do_upgrade "$1" + ;; + esac +} diff --git a/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac-128m.dts b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac-128m.dts new file mode 100644 index 00000000..b51378a7 --- /dev/null +++ b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac-128m.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019-r619ac.dtsi" + +/ { + model = "P&W R619AC 128M"; + compatible = "p2w,r619ac-128m"; + + chosen { + bootargs-append = " root=/dev/ubiblock0_1 rootfstype=squashfs"; + }; +}; + +&rootfs_part1 { + reg = <0x0 0x8000000>; +}; + +/delete-node/ &rootfs_part2; diff --git a/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dts b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dts new file mode 100644 index 00000000..31010dd1 --- /dev/null +++ b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019-r619ac.dtsi" + +/ { + model = "P&W R619AC"; + compatible = "p2w,r619ac"; + + chosen { + bootargs-append = " root=/dev/ubiblock0_1 rootfstype=squashfs"; + }; +}; diff --git a/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi new file mode 100644 index 00000000..81018dd0 --- /dev/null +++ b/root/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq4019.dtsi" +#include +#include +#include + +/ { + aliases { + led-boot = &led_sys; + led-failsafe = &led_sys; + led-running = &led_sys; + led-upgrade = &led_sys; + label-mac-device = &gmac0; + }; + + soc { + rng@22000 { + status = "okay"; + }; + + mdio@90000 { + status = "okay"; + pinctrl-0 = <&mdio_pins>; + pinctrl-names = "default"; + }; + + ess-psgmii@98000 { + status = "okay"; + }; + + tcsr@1949000 { + compatible = "qcom,tcsr"; + reg = <0x1949000 0x100>; + qcom,wifi_glb_cfg = ; + }; + + tcsr@194b000 { + compatible = "qcom,tcsr"; + reg = <0x194b000 0x100>; + qcom,usb-hsphy-mode-select = ; + }; + + ess_tcsr@1953000 { + compatible = "qcom,tcsr"; + reg = <0x1953000 0x1000>; + qcom,ess-interface-select = ; + }; + + tcsr@1957000 { + compatible = "qcom,tcsr"; + reg = <0x1957000 0x100>; + qcom,wifi_noc_memtype_m0_m2 = ; + }; + + usb2@60f8800 { + status = "okay"; + }; + + usb3@8af8800 { + status = "okay"; + }; + + crypto@8e3a000 { + status = "okay"; + }; + + watchdog@b017000 { + status = "okay"; + }; + + ess-switch@c000000 { + status = "okay"; + }; + + edma@c080000 { + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_sys: sys { + label = "r619ac:blue:sys"; + gpios = <&tlmm 39 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "r619ac:blue:wlan2g"; + gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + wlan5g { + label = "r619ac:blue:wlan5g"; + gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&blsp_dma { + status = "okay"; +}; + +&blsp1_spi1 { + status = "okay"; + + flash@0 { + reg = <0>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <24000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "MIBIB"; + reg = <0x40000 0x20000>; + read-only; + }; + + partition@60000 { + label = "QSEE"; + reg = <0x60000 0x60000>; + read-only; + }; + + partition@c0000 { + label = "CDT"; + reg = <0xc0000 0x10000>; + read-only; + }; + + partition@d0000 { + label = "DDRPARAMS"; + reg = <0xd0000 0x10000>; + read-only; + }; + + partition@e0000 { + label = "APPSBLENV"; + reg = <0xe0000 0x10000>; + read-only; + }; + + partition@f0000 { + label = "APPSBL"; + reg = <0xf0000 0x80000>; + read-only; + }; + + partition@1 { + label = "Bootloader"; + reg = <0x0 0x170000>; + read-only; + }; + + partition@170000 { + label = "ART"; + reg = <0x170000 0x10000>; + read-only; + }; + + partition@180000 { + label = "unused"; + reg = <0x180000 0xe80000>; + }; + }; + }; +}; + +&blsp1_uart1 { + pinctrl-0 = <&serial_0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&cryptobam { + status = "okay"; +}; + +&nand { + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + rootfs_part1: partition@0 { + label = "rootfs"; + reg = <0x0 0x4000000>; + }; + + rootfs_part2: partition@4000000 { + label = "unused1"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&qpic_bam { + status = "okay"; +}; + +&sdhci { + pinctrl-0 = <&sd_0_pins>; + pinctrl-names = "default"; + vqmmc-supply = <&vqmmc>; + status = "okay"; +}; + +&tlmm { + mdio_pins: mdio_pinmux { + mux_1 { + pins = "gpio6"; + function = "mdio"; + bias-pull-up; + }; + + mux_2 { + pins = "gpio7"; + function = "mdc"; + bias-pull-up; + }; + }; + + sd_0_pins: sd_0_pinmux { + mux_1 { + pins = "gpio23", "gpio24", "gpio25", "gpio26", "gpio28"; + function = "sdio"; + drive-strength = <10>; + }; + + mux_2 { + pins = "gpio27"; + function = "sdio"; + drive-strength = <16>; + }; + }; + + serial_0_pins: serial0-pinmux { + mux { + pins = "gpio16", "gpio17"; + function = "blsp_uart0"; + bias-disable; + }; + }; + + led_pins: led_pinmux { + mux { + pins = "gpio32", "gpio39", "gpio50"; + function = "gpio"; + bias-pull-up; + output-low; + }; + + mux_1 { + pins = "gpio52"; + function = "gpio"; + bias-pull-up; + output-high; + }; + + mux_2 { + pins = "gpio61"; + function = "gpio"; + bias-pull-down; + output-high; + }; + }; +}; + +&usb3_ss_phy { + status = "okay"; +}; + +&usb3_hs_phy { + status = "okay"; +}; + +&usb2_hs_phy { + status = "okay"; +}; + +&vqmmc { + status = "okay"; +}; + +&wifi0 { + status = "okay"; + qcom,ath10k-calibration-variant = "R619AC"; +}; + +&wifi1 { + status = "okay"; + qcom,ath10k-calibration-variant = "R619AC"; +}; diff --git a/root/target/linux/ipq40xx/image/Makefile b/root/target/linux/ipq40xx/image/Makefile new file mode 100644 index 00000000..44b6da6d --- /dev/null +++ b/root/target/linux/ipq40xx/image/Makefile @@ -0,0 +1,734 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID +DEVICE_VARS += RAS_BOARD RAS_ROOTFS_SIZE RAS_VERSION +DEVICE_VARS += WRGG_DEVNAME WRGG_SIGNATURE + +define Device/Default + PROFILES := Default + KERNEL_DEPENDS = $$(wildcard $(DTS_DIR)/$$(DEVICE_DTS).dts) + KERNEL_INITRAMFS_PREFIX := $$(IMG_PREFIX)-$(1)-initramfs + KERNEL_PREFIX := $$(IMAGE_PREFIX) + KERNEL_LOADADDR := 0x80208000 + DEVICE_DTS = $$(SOC)-$(lastword $(subst _, ,$(1))) + SUPPORTED_DEVICES := $(subst _,$(comma),$(1)) + IMAGES := sysupgrade.bin + IMAGE/sysupgrade.bin = sysupgrade-tar | append-metadata + IMAGE/sysupgrade.bin/squashfs := +endef + +define Device/FitImage + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/FitImageLzma + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/FitzImage + KERNEL_SUFFIX := -fit-zImage.itb + KERNEL = kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := zImage +endef + +define Device/UbiFit + KERNEL_IN_UBI := 1 + IMAGES := nand-factory.ubi nand-sysupgrade.bin + IMAGE/nand-factory.ubi := append-ubi + IMAGE/nand-sysupgrade.bin := sysupgrade-tar | append-metadata +endef + +define Device/DniImage + $(call Device/FitzImage) + NETGEAR_BOARD_ID := + NETGEAR_HW_ID := + IMAGES += factory.img + IMAGE/factory.img := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | append-rootfs | pad-rootfs | netgear-dni + IMAGE/sysupgrade.bin := append-kernel | pad-offset 64k 64 | append-uImage-fakehdr filesystem | \ + append-rootfs | pad-rootfs | append-metadata | check-size +endef + +define Build/append-rootfshdr + mkimage -A $(LINUX_KARCH) \ + -O linux -T filesystem \ + -C lzma -a $(KERNEL_LOADADDR) -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \ + -n root.squashfs -d $(IMAGE_ROOTFS) $@.new + dd if=$@.new bs=64 count=1 >> $(IMAGE_KERNEL) +endef + +define Build/mkmylofw_32m + $(eval device_id=$(word 1,$(1))) + $(eval revision=$(word 2,$(1))) + + let \ + size="$$(stat -c%s $@)" \ + pad="$(subst k,* 1024,$(BLOCKSIZE))" \ + pad="(pad - (size % pad)) % pad" \ + newsize='size + pad'; \ + $(STAGING_DIR_HOST)/bin/mkmylofw \ + -B WPE72 -i 0x11f6:$(device_id):0x11f6:$(device_id) -r $(revision) \ + -s 0x2000000 -p0x180000:$$newsize:al:0x80208000:"OpenWrt":$@ \ + $@.new + @mv $@.new $@ +endef + +define Build/qsdk-ipq-factory-nand-askey + $(TOPDIR)/scripts/mkits-qsdk-ipq-image.sh $@.its\ + askey_kernel $(IMAGE_KERNEL) \ + askey_fs $(IMAGE_ROOTFS) \ + ubifs $@ + PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new + @mv $@.new $@ +endef + +define Build/SenaoFW + -$(STAGING_DIR_HOST)/bin/mksenaofw \ + -n $(BOARD_NAME) -r $(VENDOR_ID) -p $(1) \ + -c $(DATECODE) -w $(2) -x $(CW_VER) -t 0 \ + -e $@ \ + -o $@.new + @cp $@.new $@ +endef + +define Build/wrgg-image + mkwrggimg -i $@ \ + -o $@.new \ + -d "$(WRGG_DEVNAME)" \ + -s "$(WRGG_SIGNATURE)" \ + -v "" -m "" -B "" + mv $@.new $@ +endef + +define Device/8dev_habanero-dvk + $(call Device/FitImageLzma) + DEVICE_VENDOR := 8devices + DEVICE_MODEL := Habanero DVK + IMAGE_SIZE := 30976k + SOC := qcom-ipq4019 + DEVICE_PACKAGES := ipq-wifi-8dev_habanero-dvk + IMAGE/sysupgrade.bin := append-kernel | pad-to 64k | append-rootfs | pad-rootfs | append-metadata | check-size +endef +TARGET_DEVICES += 8dev_habanero-dvk + +define Device/8dev_jalapeno-common + $(call Device/FitImage) + $(call Device/UbiFit) + BLOCKSIZE := 128k + PAGESIZE := 2048 + SOC := qcom-ipq4018 +endef + +define Device/8dev_jalapeno + $(call Device/8dev_jalapeno-common) + DEVICE_VENDOR := 8devices + DEVICE_MODEL := Jalapeno +endef +TARGET_DEVICES += 8dev_jalapeno + +define Device/alfa-network_ap120c-ac + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := ALFA Network + DEVICE_MODEL := AP120C-AC + SOC := qcom-ipq4018 + DEVICE_PACKAGES := kmod-usb-acm \ + kmod-tpm-i2c-atmel uboot-envtools + BLOCKSIZE := 128k + PAGESIZE := 2048 + IMAGE_SIZE := 65536k + IMAGES := nand-factory.bin nand-sysupgrade.bin + IMAGE/nand-factory.bin := append-ubi | qsdk-ipq-factory-nand +endef +TARGET_DEVICES += alfa-network_ap120c-ac + +define Device/aruba_glenmorangie + $(call Device/FitImageLzma) + DEVICE_VENDOR := Aruba + SOC := qcom-ipq4029 + DEVICE_PACKAGES := ipq-wifi-aruba_ap-303 +endef + +define Device/aruba_ap-303 + $(call Device/aruba_glenmorangie) + DEVICE_MODEL := AP-303 +endef +TARGET_DEVICES += aruba_ap-303 + +define Device/aruba_ap-303h + $(call Device/aruba_glenmorangie) + DEVICE_MODEL := AP-303H +endef +TARGET_DEVICES += aruba_ap-303h + +define Device/aruba_ap-365 + $(call Device/aruba_glenmorangie) + DEVICE_MODEL := AP-365 + DEVICE_PACKAGES += kmod-hwmon-ad7418 +endef +TARGET_DEVICES += aruba_ap-365 + +define Device/asus_map-ac2200 + $(call Device/FitImageLzma) + DEVICE_VENDOR := ASUS + DEVICE_MODEL := Lyra (MAP-AC2200) + SOC := qcom-ipq4019 + DEVICE_PACKAGES := ath10k-firmware-qca9888-ct kmod-ath3k +endef +TARGET_DEVICES += asus_map-ac2200 + +define Device/asus_rt-ac58u + $(call Device/FitImageLzma) + DEVICE_VENDOR := ASUS + DEVICE_MODEL := RT-AC58U + SOC := qcom-ipq4018 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DTB_SIZE := 65536 + IMAGE_SIZE := 20439364 + FILESYSTEMS := squashfs +# Someone - in their infinite wisdom - decided to put the firmware +# version in front of the image name \03\00\00\04 => Version 3.0.0.4 +# Since u-boot works with strings we either need another fixup step +# to add a version... or we are very careful not to add '\0' into that +# string and call it a day.... Yeah, we do the latter! + UIMAGE_NAME:=$(shell echo -e '\03\01\01\01RT-AC58U') + DEVICE_PACKAGES := -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers \ + kmod-usb-ledtrig-usbport +endef +TARGET_DEVICES += asus_rt-ac58u + +define Device/avm_fritzbox-4040 + $(call Device/FitImageLzma) + DEVICE_VENDOR := AVM + DEVICE_MODEL := FRITZ!Box 4040 + SOC := qcom-ipq4018 + BOARD_NAME := fritz4040 + IMAGE_SIZE := 29056k + UBOOT_PATH := $(STAGING_DIR_IMAGE)/uboot-fritz4040.bin + UBOOT_PARTITION_SIZE := 524288 + IMAGES += eva.bin + IMAGE/eva.bin := append-uboot | pad-to $$$$(UBOOT_PARTITION_SIZE) | append-kernel | append-rootfs | pad-rootfs + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata | check-size + DEVICE_PACKAGES := fritz-tffs fritz-caldata +endef +TARGET_DEVICES += avm_fritzbox-4040 + +define Device/avm_fritzbox-7530 + $(call Device/FitImageLzma) + DEVICE_VENDOR := AVM + DEVICE_MODEL := FRITZ!Box 7530 + SOC := qcom-ipq4019 + DEVICE_PACKAGES := fritz-caldata fritz-tffs-nand +endef +TARGET_DEVICES += avm_fritzbox-7530 + +define Device/avm_fritzrepeater-1200 + $(call Device/FitImageLzma) + DEVICE_VENDOR := AVM + DEVICE_MODEL := FRITZ!Repeater 1200 + SOC := qcom-ipq4019 + DEVICE_PACKAGES := fritz-caldata fritz-tffs-nand ipq-wifi-avm_fritzrepeater-1200 +endef +TARGET_DEVICES += avm_fritzrepeater-1200 + +define Device/avm_fritzrepeater-3000 + $(call Device/FitImageLzma) + DEVICE_VENDOR := AVM + DEVICE_MODEL := FRITZ!Repeater 3000 + SOC := qcom-ipq4019 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct fritz-caldata fritz-tffs-nand +endef +TARGET_DEVICES += avm_fritzrepeater-3000 + +define Device/buffalo_wtr-m2133hp + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Buffalo + DEVICE_MODEL := WTR-M2133HP + SOC := qcom-ipq4019 + DEVICE_PACKAGES := uboot-envtools ath10k-firmware-qca9984-ct ipq-wifi-buffalo_wtr-m2133hp + BLOCKSIZE := 128k + PAGESIZE := 2048 +endef +TARGET_DEVICES += buffalo_wtr-m2133hp + +define Device/cellc_rtl30vw + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL_INITRAMFS = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb | uImage lzma | pad-to 2048 + KERNEL_NAME := Image + KERNEL_IN_UBI := + IMAGES := nand-factory.bin nand-sysupgrade.bin + IMAGE/nand-factory.bin := append-rootfshdr | append-ubi | qsdk-ipq-factory-nand-askey + IMAGE/nand-sysupgrade.bin := append-rootfshdr | sysupgrade-tar | append-metadata + DEVICE_VENDOR := Cell C + DEVICE_MODEL := RTL30VW + SOC := qcom-ipq4019 + DEVICE_DTS_CONFIG := config@5 + KERNEL_INSTALL := 1 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 57344k + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := kmod-usb-net-qmi-wwan kmod-usb-serial-option uqmi ipq-wifi-cellc_rtl30vw +endef +TARGET_DEVICES += cellc_rtl30vw + +define Device/cilab_meshpoint-one + $(call Device/8dev_jalapeno-common) + DEVICE_VENDOR := Crisis Innovation Lab + DEVICE_MODEL := MeshPoint.One + DEVICE_PACKAGES := kmod-i2c-gpio kmod-iio-bmp280-i2c kmod-hwmon-ina2xx kmod-rtc-pcf2127 +endef +TARGET_DEVICES += cilab_meshpoint-one + +define Device/compex_wpj419 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Compex + DEVICE_MODEL := WPJ419 + SOC := qcom-ipq4019 + DEVICE_DTS_CONFIG := config@12 + KERNEL_INSTALL := 1 + BLOCKSIZE := 128k + PAGESIZE := 2048 + FILESYSTEMS := squashfs +endef +TARGET_DEVICES += compex_wpj419 + +define Device/compex_wpj428 + $(call Device/FitImage) + DEVICE_VENDOR := Compex + DEVICE_MODEL := WPJ428 + SOC := qcom-ipq4028 + DEVICE_DTS_CONFIG := config@4 + BLOCKSIZE := 64k + IMAGE_SIZE := 31232k + KERNEL_SIZE := 4096k + IMAGES += cpximg-6a04.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + IMAGE/cpximg-6a04.bin := append-kernel | append-rootfs | pad-rootfs | mkmylofw_32m 0x8A2 3 + DEVICE_PACKAGES := kmod-gpio-beeper +endef +TARGET_DEVICES += compex_wpj428 + +define Device/dlink_dap-2610 + $(call Device/FitImageLzma) + DEVICE_VENDOR := D-Link + DEVICE_MODEL := DAP-2610 + SOC := qcom-ipq4018 + DEVICE_DTS_CONFIG := config@ap.dk01.1-c1 + BLOCKSIZE := 64k + WRGG_DEVNAME := /dev/mtdblock/8 + WRGG_SIGNATURE := wapac30_dkbs_dap2610 + IMAGE_SIZE := 14080k + IMAGES += factory.bin + # Bootloader expects a special 160 byte header which is added by + # wrgg-image. + # Factory image size must be larger than 6MB, and size in wrgg header must + # match actual factory image size to be flashable from D-Link http server. + # Bootloader verifies checksum of wrgg image before booting, thus jffs2 + # cannot be part of the wrgg image. This is solved in the factory image by + # having the rootfs at the end of the image (without pad-rootfs). And in + # the sysupgrade image only the kernel is included in the wrgg checksum, + # but this is not flashable from the D-link http server. + # append-rootfs must start on an erase block boundary. + IMAGE/factory.bin := append-kernel | pad-offset 6144k 160 | append-rootfs | wrgg-image | check-size + IMAGE/sysupgrade.bin := append-kernel | wrgg-image | pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size | append-metadata + DEVICE_PACKAGES := ipq-wifi-dlink_dap2610 +endef +TARGET_DEVICES += dlink_dap-2610 + +define Device/engenius_eap1300 + $(call Device/FitImage) + DEVICE_VENDOR := EnGenius + DEVICE_MODEL := EAP1300 + DEVICE_DTS_CONFIG := config@4 + BOARD_NAME := eap1300 + SOC := qcom-ipq4018 + KERNEL_SIZE := 5120k + IMAGE_SIZE := 25344k + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata +endef +TARGET_DEVICES += engenius_eap1300 + +define Device/engenius_eap2200 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := EnGenius + DEVICE_MODEL := EAP2200 + SOC := qcom-ipq4019 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ath10k-firmware-qca9888-ct ipq-wifi-engenius_eap2200 -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers +endef +TARGET_DEVICES += engenius_eap2200 + +define Device/engenius_emd1 + $(call Device/FitImage) + DEVICE_VENDOR := EnGenius + DEVICE_MODEL := EMD1 + DEVICE_DTS_CONFIG := config@4 + SOC := qcom-ipq4018 + IMAGE_SIZE := 30720k + IMAGES += factory.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + IMAGE/factory.bin := qsdk-ipq-factory-nor | check-size +endef +TARGET_DEVICES += engenius_emd1 + +define Device/engenius_emr3500 + $(call Device/FitImage) + DEVICE_VENDOR := EnGenius + DEVICE_MODEL := EMR3500 + DEVICE_DTS_CONFIG := config@4 + SOC := qcom-ipq4018 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 30720k + IMAGES += factory.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + IMAGE/factory.bin := qsdk-ipq-factory-nor | check-size +endef +TARGET_DEVICES += engenius_emr3500 + +define Device/engenius_ens620ext + $(call Device/FitImage) + DEVICE_VENDOR := EnGenius + DEVICE_MODEL := ENS620EXT + SOC := qcom-ipq4018 + DEVICE_DTS_CONFIG := config@4 + BLOCKSIZE := 64k + PAGESIZE := 256 + BOARD_NAME := ENS620EXT + VENDOR_ID := 0x0101 + PRODUCT_ID := 0x79 + PRODUCT_ID_NEW := 0xA4 + DATECODE := 190507 + FW_VER := 3.1.2 + FW_VER_NEW := 3.5.6 + CW_VER := 1.8.99 + IMAGE_SIZE := 21312k + KERNEL_SIZE := 5120k + FILESYSTEMS := squashfs + IMAGES += factory_30.bin factory_35.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata + IMAGE/factory_30.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size | SenaoFW $$$$(PRODUCT_ID) $$$$(FW_VER) + IMAGE/factory_35.bin := qsdk-ipq-factory-nor | check-size | SenaoFW $$$$(PRODUCT_ID_NEW) $$$$(FW_VER_NEW) +endef +TARGET_DEVICES += engenius_ens620ext + +define Device/ezviz_cs-w3-wd1200g-eup + $(call Device/FitImage) + DEVICE_VENDOR := EZVIZ + DEVICE_MODEL := CS-W3-WD1200G + DEVICE_VARIANT := EUP + DEVICE_DTS_CONFIG := config@4 + IMAGE_SIZE := 14848k + SOC := qcom-ipq4018 + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | \ + append-metadata + DEVICE_PACKAGES := -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers \ + ipq-wifi-ezviz_cs-w3-wd1200g-eup +endef +TARGET_DEVICES += ezviz_cs-w3-wd1200g-eup + +define Device/glinet_gl-b1300 + $(call Device/FitImage) + DEVICE_VENDOR := GL.iNet + DEVICE_MODEL := GL-B1300 + BOARD_NAME := gl-b1300 + SOC := qcom-ipq4029 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 26624k + IMAGE/sysupgrade.bin := append-kernel |append-rootfs | pad-rootfs | append-metadata +endef +TARGET_DEVICES += glinet_gl-b1300 + +define Device/glinet_gl-s1300 + $(call Device/FitImage) + DEVICE_VENDOR := GL.iNet + DEVICE_MODEL := GL-S1300 + SOC := qcom-ipq4029 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 26624k + IMAGES := sysupgrade.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + DEVICE_PACKAGES := ipq-wifi-glinet_gl-s1300 kmod-fs-ext4 kmod-mmc kmod-spi-dev +endef +TARGET_DEVICES += glinet_gl-s1300 + +define Device/linksys_ea6350v3 + # The Linksys EA6350v3 has a uboot bootloader that does not + # support either booting lzma kernel images nor booting UBI + # partitions. This uboot, however, supports raw kernel images and + # gzipped images. + # + # As for the time of writing this, the device will boot the kernel + # from a fixed address with a fixed length of 3MiB. Also, the + # device has a hard-coded kernel command line that requieres the + # rootfs and alt_rootfs to be in mtd11 and mtd13 respectively. + # Oh... and the kernel partition overlaps with the rootfs + # partition (the same for alt_kernel and alt_rootfs). + # + # If you are planing re-partitioning the device, you may want to + # keep those details in mind: + # 1. The kernel adresses you should honor are 0x00000000 and + # 0x02800000 respectively. + # 2. The kernel size (plus the dtb) cannot exceed 3.00MiB in size. + # 3. You can use 'zImage', but not a raw 'Image' packed with lzma. + # 4. The kernel command line from uboot is harcoded to boot with + # rootfs either in mtd11 or mtd13. + $(call Device/FitzImage) + DEVICE_VENDOR := Linksys + DEVICE_MODEL := EA6350 + DEVICE_VARIANT := v3 + SOC := qcom-ipq4018 + BLOCKSIZE := 128k + PAGESIZE := 2048 + KERNEL_SIZE := 3072k + IMAGE_SIZE := 37888k + UBINIZE_OPTS := -E 5 + IMAGES += factory.bin + IMAGE/factory.bin := append-kernel | append-uImage-fakehdr filesystem | pad-to $$$$(KERNEL_SIZE) | append-ubi | linksys-image type=EA6350v3 + DEVICE_PACKAGES := uboot-envtools +endef +TARGET_DEVICES += linksys_ea6350v3 + +define Device/linksys_ea8300 + $(call Device/FitzImage) + DEVICE_VENDOR := Linksys + DEVICE_MODEL := EA8300 + SOC := qcom-ipq4019 + KERNEL_SIZE := 3072k + IMAGE_SIZE := 87040k + BLOCKSIZE := 128k + PAGESIZE := 2048 + UBINIZE_OPTS := -E 5 # EOD marks to "hide" factory sig at EOF + IMAGES += factory.bin + IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | linksys-image type=EA8300 + DEVICE_PACKAGES := uboot-envtools ath10k-firmware-qca9888-ct ipq-wifi-linksys_ea8300 kmod-usb-ledtrig-usbport +endef +TARGET_DEVICES += linksys_ea8300 + +define Device/meraki_mr33 + $(call Device/FitImage) + DEVICE_VENDOR := Cisco Meraki + DEVICE_MODEL := MR33 + SOC := qcom-ipq4029 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := -swconfig ath10k-firmware-qca9887-ct +endef +TARGET_DEVICES += meraki_mr33 + +define Device/mobipromo_cm520-79f + $(call Device/FitzImage) + $(call Device/UbiFit) + DEVICE_VENDOR := MobiPromo + DEVICE_MODEL := CM520-79F + SOC := qcom-ipq4019 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ipq-wifi-mobipromo_cm520-79f kmod-usb-ledtrig-usbport +endef +TARGET_DEVICES += mobipromo_cm520-79f + +define Device/netgear_ex61x0v2 + $(call Device/DniImage) + DEVICE_DTS_CONFIG := config@4 + NETGEAR_BOARD_ID := EX6150v2series + NETGEAR_HW_ID := 29765285+16+0+128+2x2 + IMAGE_SIZE := 14400k + SOC := qcom-ipq4018 +endef + +define Device/netgear_ex6100v2 + $(call Device/netgear_ex61x0v2) + DEVICE_VENDOR := Netgear + DEVICE_MODEL := EX6100 + DEVICE_VARIANT := v2 +endef +TARGET_DEVICES += netgear_ex6100v2 + +define Device/netgear_ex6150v2 + $(call Device/netgear_ex61x0v2) + DEVICE_VENDOR := Netgear + DEVICE_MODEL := EX6150 + DEVICE_VARIANT := v2 +endef +TARGET_DEVICES += netgear_ex6150v2 + +define Device/openmesh_a42 + $(call Device/FitImageLzma) + DEVICE_VENDOR := OpenMesh + DEVICE_MODEL := A42 + SOC := qcom-ipq4018 + DEVICE_DTS_CONFIG := config@om.a42 + BLOCKSIZE := 64k + KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb | pad-to $$(BLOCKSIZE) + IMAGE_SIZE := 15616k + IMAGES += factory.bin + IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=A42 + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata + DEVICE_PACKAGES := uboot-envtools +endef +TARGET_DEVICES += openmesh_a42 + +define Device/openmesh_a62 + $(call Device/FitImageLzma) + DEVICE_VENDOR := OpenMesh + DEVICE_MODEL := A62 + SOC := qcom-ipq4019 + DEVICE_DTS_CONFIG := config@om.a62 + BLOCKSIZE := 64k + KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb | pad-to $$(BLOCKSIZE) + IMAGE_SIZE := 15552k + IMAGES += factory.bin + IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=A62 + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata + DEVICE_PACKAGES := ath10k-firmware-qca9888-ct uboot-envtools +endef + +TARGET_DEVICES += openmesh_a62 + +define Device/qcom_ap-dk01.1-c1 + DEVICE_VENDOR := Qualcomm Atheros + DEVICE_MODEL := AP-DK01.1 + DEVICE_VARIANT := C1 + BOARD_NAME := ap-dk01.1-c1 + SOC := qcom-ipq4019 + DEVICE_DTS := qcom-ipq4019-ap.dk01.1-c1 + KERNEL_INSTALL := 1 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 26624k + $(call Device/FitImage) + IMAGE/sysupgrade.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | append-metadata +endef +TARGET_DEVICES += qcom_ap-dk01.1-c1 + +define Device/qcom_ap-dk04.1-c1 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Qualcomm Atheros + DEVICE_MODEL := AP-DK04.1 + DEVICE_VARIANT := C1 + SOC := qcom-ipq4019 + DEVICE_DTS := qcom-ipq4019-ap.dk04.1-c1 + KERNEL_INSTALL := 1 + KERNEL_SIZE := 4048k + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := ap-dk04.1-c1 +endef +TARGET_DEVICES += qcom_ap-dk04.1-c1 + +define Device/p2w_r619ac + $(call Device/FitzImage) + $(call Device/UbiFit) + DEVICE_VENDOR := P&W + DEVICE_MODEL := R619AC + SOC := qcom-ipq4019 + DEVICE_DTS_CONFIG := config@10 + BLOCKSIZE := 128k + PAGESIZE := 2048 + IMAGES += nand-factory.bin + IMAGE/nand-factory.bin := append-ubi | qsdk-ipq-factory-nand + DEVICE_PACKAGES := ipq-wifi-p2w_r619ac +endef +TARGET_DEVICES += p2w_r619ac + +define Device/p2w_r619ac-128m + $(call Device/FitzImage) + $(call Device/UbiFit) + DEVICE_VENDOR := P&W + DEVICE_MODEL := R619AC + DEVICE_VARIANT := 128M + SOC := qcom-ipq4019 + DEVICE_DTS_CONFIG := config@10 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ipq-wifi-p2w_r619ac +endef +TARGET_DEVICES += p2w_r619ac-128m + +define Device/qxwlan_e2600ac-c1 + $(call Device/FitImage) + DEVICE_VENDOR := Qxwlan + DEVICE_MODEL := E2600AC + DEVICE_VARIANT := C1 + BOARD_NAME := e2600ac-c1 + SOC := qcom-ipq4019 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 31232k + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + DEVICE_PACKAGES := ipq-wifi-qxwlan_e2600ac +endef +TARGET_DEVICES += qxwlan_e2600ac-c1 + +define Device/qxwlan_e2600ac-c2 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Qxwlan + DEVICE_MODEL := E2600AC + DEVICE_VARIANT := C2 + SOC := qcom-ipq4019 + KERNEL_INSTALL := 1 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ipq-wifi-qxwlan_e2600ac +endef +TARGET_DEVICES += qxwlan_e2600ac-c2 + +define Device/unielec_u4019-32m + $(call Device/FitImage) + DEVICE_VENDOR := Unielec + DEVICE_MODEL := U4019 + DEVICE_VARIANT := 32M + BOARD_NAME := u4019-32m + SOC := qcom-ipq4019 + KERNEL_SIZE := 4096k + IMAGE_SIZE := 31232k + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata +endef +TARGET_DEVICES += unielec_u4019-32m + +define Device/zyxel_nbg6617 + $(call Device/FitImageLzma) + DEVICE_VENDOR := ZyXEL + DEVICE_MODEL := NBG6617 + SOC := qcom-ipq4018 + KERNEL_SIZE := 4096k + ROOTFS_SIZE := 24960k + RAS_BOARD := NBG6617 + RAS_ROOTFS_SIZE := 19840k + RAS_VERSION := "$(VERSION_DIST) $(REVISION)" + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + IMAGES += factory.bin +# The ZyXEL firmware allows flashing thru the web-gui only when the rootfs is +# at least as large as the one of the initial firmware image (not the current +# one on the device). This only applies to the Web-UI, the bootlaoder ignores +# this minimum-size. However, the larger image can be flashed both ways. + IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k | check-size $$$$(ROOTFS_SIZE) | zyxel-ras-image separate-kernel + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | check-size $$$$(ROOTFS_SIZE) | sysupgrade-tar rootfs=$$$$@ | append-metadata + DEVICE_PACKAGES := uboot-envtools kmod-usb-ledtrig-usbport +endef +TARGET_DEVICES += zyxel_nbg6617 + +define Device/zyxel_wre6606 + $(call Device/FitImage) + DEVICE_VENDOR := ZyXEL + DEVICE_MODEL := WRE6606 + DEVICE_DTS_CONFIG := config@4 + SOC := qcom-ipq4018 + IMAGE_SIZE := 13184k + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata | check-size + DEVICE_PACKAGES := -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers +endef +TARGET_DEVICES += zyxel_wre6606 + +$(eval $(call BuildImage)) diff --git a/root/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch b/root/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch new file mode 100644 index 00000000..ade7a675 --- /dev/null +++ b/root/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch @@ -0,0 +1,65 @@ +From a10fab12a927e60b7141a602e740d70cb4d09e4a Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 11:03:18 +0100 +Subject: [PATCH] arm: boot: add dts files + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/Makefile | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -837,11 +837,52 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-apq8074-dragonboard.dtb \ + qcom-apq8084-ifc6540.dtb \ + qcom-apq8084-mtp.dtb \ ++ qcom-ipq4018-a42.dtb \ ++ qcom-ipq4018-ap120c-ac.dtb \ ++ qcom-ipq4018-dap-2610.dtb \ ++ qcom-ipq4018-cs-w3-wd1200g-eup.dtb \ ++ qcom-ipq4018-ea6350v3.dtb \ ++ qcom-ipq4018-eap1300.dtb \ ++ qcom-ipq4018-emd1.dtb \ ++ qcom-ipq4018-emr3500.dtb \ ++ qcom-ipq4018-ens620ext.dtb \ ++ qcom-ipq4018-ex6100v2.dtb \ ++ qcom-ipq4018-ex6150v2.dtb \ ++ qcom-ipq4018-fritzbox-4040.dtb \ ++ qcom-ipq4018-jalapeno.dtb \ ++ qcom-ipq4018-meshpoint-one.dtb \ ++ qcom-ipq4018-nbg6617.dtb \ ++ qcom-ipq4018-rt-ac58u.dtb \ ++ qcom-ipq4018-wre6606.dtb \ + qcom-ipq4019-ap.dk01.1-c1.dtb \ + qcom-ipq4019-ap.dk04.1-c1.dtb \ + qcom-ipq4019-ap.dk04.1-c3.dtb \ + qcom-ipq4019-ap.dk07.1-c1.dtb \ + qcom-ipq4019-ap.dk07.1-c2.dtb \ ++ qcom-ipq4019-a62.dtb \ ++ qcom-ipq4019-cm520-79f.dtb \ ++ qcom-ipq4019-ea8300.dtb \ ++ qcom-ipq4019-eap2200.dtb \ ++ qcom-ipq4019-fritzbox-7530.dtb \ ++ qcom-ipq4019-fritzrepeater-1200.dtb \ ++ qcom-ipq4019-fritzrepeater-3000.dtb \ ++ qcom-ipq4019-r619ac.dtb \ ++ qcom-ipq4019-r619ac-128m.dtb \ ++ qcom-ipq4019-map-ac2200.dtb \ ++ qcom-ipq4019-e2600ac-c1.dtb \ ++ qcom-ipq4019-e2600ac-c2.dtb \ ++ qcom-ipq4019-habanero-dvk.dtb \ ++ qcom-ipq4019-rtl30vw.dtb \ ++ qcom-ipq4019-u4019-32m.dtb \ ++ qcom-ipq4019-wpj419.dtb \ ++ qcom-ipq4019-wtr-m2133hp.dtb \ ++ qcom-ipq4028-wpj428.dtb \ ++ qcom-ipq4029-ap-303.dtb \ ++ qcom-ipq4029-ap-303h.dtb \ ++ qcom-ipq4029-ap-365.dtb \ ++ qcom-ipq4029-gl-b1300.dtb \ ++ qcom-ipq4029-gl-s1300.dtb \ ++ qcom-ipq4029-mr33.dtb \ + qcom-ipq8064-ap148.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ diff --git a/root/target/linux/mediatek/Makefile b/root/target/linux/mediatek/Makefile new file mode 100644 index 00000000..8ccaa927 --- /dev/null +++ b/root/target/linux/mediatek/Makefile @@ -0,0 +1,19 @@ +# Copyright (c) 2015 OpenWrt.org +# +include $(TOPDIR)/rules.mk + +ARCH:=arm +BOARD:=mediatek +BOARDNAME:=MediaTek Ralink ARM +SUBTARGETS:=mt7622 mt7623 mt7629 +FEATURES:=squashfs nand ramdisk fpu ext4 usb + +KERNEL_PATCHVER:=5.4 +KERNEL_TESTING_PATCHVER:=5.4 + +include $(INCLUDE_DIR)/target.mk +DEFAULT_PACKAGES += \ + kmod-leds-gpio kmod-gpio-button-hotplug \ + wpad-mini uboot-envtools partx-utils e2fsprogs + +$(eval $(call BuildTarget)) diff --git a/root/target/linux/mediatek/base-files/etc/inittab b/root/target/linux/mediatek/base-files/etc/inittab new file mode 100644 index 00000000..18857874 --- /dev/null +++ b/root/target/linux/mediatek/base-files/etc/inittab @@ -0,0 +1,4 @@ +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +::askconsole:/usr/libexec/login.sh +ttyS0::askfirst:/usr/libexec/login.sh diff --git a/root/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps b/root/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps new file mode 100755 index 00000000..674589a1 --- /dev/null +++ b/root/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps @@ -0,0 +1,6 @@ +uci set network.globals.default_rps_val=14 +uci set network.globals.default_rps_flow_cnt=256 +uci set network.globals.default_xps_val=14 +uci set network.globals.default_ps=1 +uci commit +exit 0 diff --git a/root/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface b/root/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface new file mode 100644 index 00000000..0184a7c6 --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface @@ -0,0 +1,9 @@ +#!/bin/sh + +set_preinit_iface() { + ifconfig eth0 up + ifname=lan +} + +boot_hook_add preinit_main set_preinit_iface + diff --git a/root/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow b/root/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow new file mode 100644 index 00000000..9a84ff4b --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow @@ -0,0 +1,8 @@ +#!/bin/sh + +set_rps_sock_flow() { + echo 1024 > /proc/sys/net/core/rps_sock_flow_entries +} + +boot_hook_add preinit_main set_rps_sock_flow + diff --git a/root/target/linux/mediatek/base-files/lib/preinit/07_set_iface_mac b/root/target/linux/mediatek/base-files/lib/preinit/07_set_iface_mac new file mode 100644 index 00000000..1ad70145 --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/preinit/07_set_iface_mac @@ -0,0 +1,48 @@ +#!/bin/sh +# Copyright (C) 2018 OpenWrt.org + +RECOVERY_PART=/dev/mmcblk0p1 + +preinit_set_mac_address() { + local mac + + . /lib/functions.sh + . /lib/functions/system.sh + + case $(board_name) in + 'bananapi,bpi-r2'|\ + "unielec,u7623"*) + if [ -b $RECOVERY_PART ]; then + insmod nls_cp437 + insmod nls_iso8859-1 + insmod fat + insmod vfat + mkdir -p /tmp/recovery + mount -o rw,noatime $RECOVERY_PART /tmp/recovery + + if [ -f "/tmp/recovery/mac_addr" ]; + then + mac=$(cat /tmp/recovery/mac_addr) + else + mac=$(cat /sys/class/net/eth0/address) + echo "$mac" > /tmp/recovery/mac_addr + fi + + sync + umount /tmp/recovery + rm -rf /tmp/recovery + fi + + ip link set dev lan address $mac 2> /dev/null + + mac=$(macaddr_add $mac 1) + + ip link set dev wan1 address $mac 2>/dev/null + ip link set dev wan2 address $mac 2>/dev/null + ip link set dev wan3 address $mac 2>/dev/null + ip link set dev wan4 address $mac 2>/dev/null + ;; + esac +} + +boot_hook_add preinit_main preinit_set_mac_address diff --git a/root/target/linux/mediatek/base-files/lib/preinit/79_move_config b/root/target/linux/mediatek/base-files/lib/preinit/79_move_config new file mode 100644 index 00000000..e8e62883 --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/preinit/79_move_config @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (C) 2015 OpenWrt.org + +RECOVERY_PART=/dev/mmcblk0p1 + +move_config() { + if [ -b $RECOVERY_PART ]; then + insmod nls_cp437 + insmod nls_iso8859-1 + insmod fat + insmod vfat + mkdir -p /recovery + mount -o rw,noatime $RECOVERY_PART /recovery + [ -f /recovery/sysupgrade.tgz ] && mv -f /recovery/sysupgrade.tgz / + umount /recovery + fi +} + +boot_hook_add preinit_mount_root move_config diff --git a/root/target/linux/mediatek/base-files/lib/preinit/90_init_jffs2 b/root/target/linux/mediatek/base-files/lib/preinit/90_init_jffs2 new file mode 100644 index 00000000..8a510b74 --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/preinit/90_init_jffs2 @@ -0,0 +1,7 @@ +#!/bin/sh +do_firstboot() { + if [ "$(mount | grep jffs2)" = "" ]; then + /sbin/firstboot -y + fi +} +boot_hook_add preinit_main do_firstboot \ No newline at end of file diff --git a/root/target/linux/mediatek/base-files/lib/upgrade/platform.sh b/root/target/linux/mediatek/base-files/lib/upgrade/platform.sh new file mode 100755 index 00000000..ee69952e --- /dev/null +++ b/root/target/linux/mediatek/base-files/lib/upgrade/platform.sh @@ -0,0 +1,85 @@ +platform_do_upgrade() { + local board=$(board_name) + case "$board" in + "unielec,u7623"*) + #Keep the persisten random mac address (if it exists) + mkdir -p /tmp/recovery + mount -o rw,noatime /dev/mmcblk0p1 /tmp/recovery + [ -f "/tmp/recovery/mac_addr" ] && \ + mv -f /tmp/recovery/mac_addr /tmp/ + umount /tmp/recovery + + #1310720 is the offset in bytes from the start of eMMC and to + #the location of the kernel (2560 512 byte sectors) + get_image "$1" | dd of=/dev/mmcblk0 bs=1310720 seek=1 conv=fsync + + mount -o rw,noatime /dev/mmcblk0p1 /tmp/recovery + [ -f "/tmp/mac_addr" ] && mv -f /tmp/mac_addr /tmp/recovery + sync + umount /tmp/recovery + ;; + bananapi,bpi-r2) + local tar_file="$1" + + echo "flashing kernel" + tar xf $tar_file sysupgrade-7623n-bananapi-bpi-r2/kernel -O | mtd write - kernel + + echo "flashing rootfs" + tar xf $tar_file sysupgrade-7623n-bananapi-bpi-r2/root -O | mtd write - rootfs + ;; + *) + default_do_upgrade "$ARGV" + ;; + esac +} + +PART_NAME=firmware + +platform_check_image() { + local board=$(board_name) + + [ "$#" -gt 1 ] && return 1 + + case "$board" in + bananapi,bpi-r2) + local tar_file="$1" + local kernel_length=`(tar xf $tar_file sysupgrade-7623n-bananapi-bpi-r2/kernel -O | wc -c) 2> /dev/null` + local rootfs_length=`(tar xf $tar_file sysupgrade-7623n-bananapi-bpi-r2/root -O | wc -c) 2> /dev/null` + [ "$kernel_length" = 0 -o "$rootfs_length" = 0 ] && { + echo "The upgrade image is corrupt." + return 1 + } + ;; + "unielec,u7623"*) + local magic="$(get_magic_long "$1")" + [ "$magic" != "27051956" ] && { + echo "Invalid image type." + return 1 + } + return 0 + ;; + + *) + echo "Sysupgrade is not supported on your board yet." + return 1 + ;; + esac + + return 0 +} + +platform_copy_config_emmc() { + mkdir -p /recovery + mount -o rw,noatime /dev/mmcblk0p1 /recovery + cp -af "$CONF_TAR" /recovery/ + sync + umount /recovery +} + +platform_copy_config() { + case "$(board_name)" in + "unielec,u7623"*) + platform_copy_config_emmc + ;; + esac +} diff --git a/root/target/linux/mediatek/modules.mk b/root/target/linux/mediatek/modules.mk new file mode 100644 index 00000000..eb81afe2 --- /dev/null +++ b/root/target/linux/mediatek/modules.mk @@ -0,0 +1,51 @@ +define KernelPackage/ata-ahci-mtk + TITLE:=Mediatek AHCI Serial ATA support + KCONFIG:=CONFIG_AHCI_MTK + FILES:= \ + $(LINUX_DIR)/drivers/ata/ahci_mtk.ko \ + $(LINUX_DIR)/drivers/ata/libahci_platform.ko + AUTOLOAD:=$(call AutoLoad,40,libahci libahci_platform ahci_mtk,1) + $(call AddDepends/ata) + DEPENDS+=@(TARGET_mediatek_mt7622||TARGET_mediatek_mt7623) +endef + +define KernelPackage/ata-ahci-mtk/description + Mediatek AHCI Serial ATA host controllers +endef + +$(eval $(call KernelPackage,ata-ahci-mtk)) + +define KernelPackage/sdhci-mtk + SUBMENU:=Other modules + TITLE:=Mediatek SDHCI driver + DEPENDS:=@TARGET_mediatek_mt7622 +kmod-sdhci + KCONFIG:=CONFIG_MMC_MTK + FILES:= \ + $(LINUX_DIR)/drivers/mmc/host/mtk-sd.ko + AUTOLOAD:=$(call AutoProbe,mtk-sd,1) +endef + +$(eval $(call KernelPackage,sdhci-mtk)) + +define KernelPackage/crypto-hw-mtk + TITLE:= MediaTek's Crypto Engine module + DEPENDS:=@TARGET_mediatek + KCONFIG:= \ + CONFIG_CRYPTO_HW=y \ + CONFIG_CRYPTO_AES=y \ + CONFIG_CRYPTO_AEAD=y \ + CONFIG_CRYPTO_SHA1=y \ + CONFIG_CRYPTO_SHA256=y \ + CONFIG_CRYPTO_SHA512=y \ + CONFIG_CRYPTO_HMAC=y \ + CONFIG_CRYPTO_DEV_MEDIATEK + FILES:=$(LINUX_DIR)/drivers/crypto/mediatek/mtk-crypto.ko + AUTOLOAD:=$(call AutoLoad,90,mtk-crypto) + $(call AddDepends/crypto) +endef + +define KernelPackage/crypto-hw-mtk/description + MediaTek's EIP97 Cryptographic Engine driver. +endef + +$(eval $(call KernelPackage,crypto-hw-mtk)) diff --git a/root/target/linux/mediatek/mt7623/base-files/etc/board.d/02_network b/root/target/linux/mediatek/mt7623/base-files/etc/board.d/02_network new file mode 100755 index 00000000..a162e373 --- /dev/null +++ b/root/target/linux/mediatek/mt7623/base-files/etc/board.d/02_network @@ -0,0 +1,36 @@ +#!/bin/sh + +. /lib/functions.sh +. /lib/functions/uci-defaults.sh +. /lib/functions/system.sh + +mediatek_setup_interfaces() +{ + local board="$1" + + case $board in + bananapi,bpi-r2|\ + unielec,u7623-02-emmc-512m) + ucidef_set_interfaces_lan_wan "wan1 wan2 wan3 wan4" "lan" + ;; + esac +} + +mediatek_setup_macs() +{ + local board="$1" + + case $board in + unielec,u7623-02-emmc-512m) + ucidef_set_interface_macaddr "lan" "$(cat /sys/class/net/lan/address)" + ;; + esac +} + +board_config_update +board=$(board_name) +mediatek_setup_interfaces $board +mediatek_setup_macs $board +board_config_flush + +exit 0 diff --git a/root/target/linux/mediatek/mt7623/base-files/lib/preinit/07_set_iface_mac b/root/target/linux/mediatek/mt7623/base-files/lib/preinit/07_set_iface_mac new file mode 100644 index 00000000..8141c3db --- /dev/null +++ b/root/target/linux/mediatek/mt7623/base-files/lib/preinit/07_set_iface_mac @@ -0,0 +1,47 @@ +#!/bin/sh +# Copyright (C) 2018 OpenWrt.org + +RECOVERY_PART=/dev/mmcblk0p1 + +preinit_set_mac_address() { + local mac + + . /lib/functions.sh + . /lib/functions/system.sh + + case $(board_name) in + unielec,u7623-02-emmc-512m) + if [ -b $RECOVERY_PART ]; then + insmod nls_cp437 + insmod nls_iso8859-1 + insmod fat + insmod vfat + mkdir -p /tmp/recovery + mount -o rw,noatime $RECOVERY_PART /tmp/recovery + + if [ -f "/tmp/recovery/mac_addr" ]; + then + mac=$(cat /tmp/recovery/mac_addr) + else + mac=$(cat /sys/class/net/eth0/address) + echo "$mac" > /tmp/recovery/mac_addr + fi + + sync + umount /tmp/recovery + rm -rf /tmp/recovery + fi + + ip link set dev lan address $mac 2> /dev/null + + mac=$(macaddr_add $mac 1) + + ip link set dev wan1 address $mac 2>/dev/null + ip link set dev wan2 address $mac 2>/dev/null + ip link set dev wan3 address $mac 2>/dev/null + ip link set dev wan4 address $mac 2>/dev/null + ;; + esac +} + +boot_hook_add preinit_main preinit_set_mac_address diff --git a/root/target/linux/mediatek/mt7623/base-files/lib/preinit/79_move_config b/root/target/linux/mediatek/mt7623/base-files/lib/preinit/79_move_config new file mode 100644 index 00000000..4be18114 --- /dev/null +++ b/root/target/linux/mediatek/mt7623/base-files/lib/preinit/79_move_config @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (C) 2012-2015 OpenWrt.org + +move_config() { + local partdev + + . /lib/upgrade/common.sh + + if export_bootdevice && export_partdevice partdev -1; then + if mount -t vfat -o rw,noatime "/dev/$partdev" /mnt; then + if [ -f /mnt/sysupgrade.tgz ]; then + mv -f /mnt/sysupgrade.tgz / + fi + umount /mnt + fi + fi +} + +boot_hook_add preinit_mount_root move_config diff --git a/root/target/linux/mediatek/mt7623/base-files/lib/upgrade/platform.sh b/root/target/linux/mediatek/mt7623/base-files/lib/upgrade/platform.sh new file mode 100755 index 00000000..f117f98c --- /dev/null +++ b/root/target/linux/mediatek/mt7623/base-files/lib/upgrade/platform.sh @@ -0,0 +1,154 @@ +platform_do_upgrade() { + local board=$(board_name) + + case "$board" in + unielec,u7623-02-emmc-512m) + #Keep the persisten random mac address (if it exists) + mkdir -p /tmp/recovery + mount -o rw,noatime /dev/mmcblk0p1 /tmp/recovery + [ -f "/tmp/recovery/mac_addr" ] && \ + mv -f /tmp/recovery/mac_addr /tmp/ + umount /tmp/recovery + + #1310720 is the offset in bytes from the start of eMMC and to + #the location of the kernel (2560 512 byte sectors) + get_image "$1" | dd of=/dev/mmcblk0 bs=1310720 seek=1 conv=fsync + + mount -o rw,noatime /dev/mmcblk0p1 /tmp/recovery + [ -f "/tmp/mac_addr" ] && mv -f /tmp/mac_addr /tmp/recovery + sync + umount /tmp/recovery + ;; + bananapi,bpi-r2) + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev -2 || { + echo "Unable to determine upgrade device" + return 1 + } + + sync + + if [ "$SAVE_PARTITIONS" = "1" ]; then + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + else + diff=1 + fi + + if [ -n "$diff" ]; then + get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync + + # Separate removal and addtion is necessary; otherwise, partition 1 + # will be missing if it overlaps with the old partition 2 + partx -d - "/dev/$diskdev" + partx -a - "/dev/$diskdev" + + return 0 + fi + + #write uboot image + get_image "$@" | dd of="$diskdev" bs=1024 skip=320 seek=320 count=700 conv=fsync + #iterate over each partition from the image and write it to the boot disk + while read part start size; do + part="$(($part - 2))" + if export_partdevice partdev $part; then + echo "Writing image to /dev/$partdev..." + get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync + else + echo "Unable to find partition $part device, skipped." + fi + done < /tmp/partmap.image + + #copy partition uuid + echo "Writing new UUID to /dev/$diskdev..." + get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync + ;; + *) + default_do_upgrade "$1" + ;; + esac +} + +PART_NAME=firmware + +platform_check_image() { + local board=$(board_name) + local magic="$(get_magic_long "$1")" + + [ "$#" -gt 1 ] && return 1 + + case "$board" in + unielec,u7623-02-emmc-512m) + [ "$magic" != "27051956" ] && { + echo "Invalid image type." + return 1 + } + return 0 + ;; + bananapi,bpi-r2) + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev -2 || { + echo "Unable to determine upgrade device" + return 1 + } + + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + + rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image + + if [ -n "$diff" ]; then + echo "Partition layout has changed. Full image will be written." + ask_bool 0 "Abort" && exit 1 + return 0 + fi + ;; + *) + echo "Sysupgrade is not supported on your board yet." + return 1 + ;; + esac + + return 0 +} + +platform_copy_config_emmc() { + mkdir -p /recovery + mount -o rw,noatime /dev/mmcblk0p1 /recovery + cp -af "$UPGRADE_BACKUP" "/recovery/$BACKUP_FILE" + sync + umount /recovery +} + +platform_copy_config() { + case "$(board_name)" in + unielec,u7623-02-emmc-512m) + platform_copy_config_emmc + ;; + bananapi,bpi-r2) + local partdev + + if export_partdevice partdev -1; then + mount -t vfat -o rw,noatime "/dev/$partdev" /mnt + cp -af "$CONF_TAR" /mnt/ + umount /mnt + fi + ;; + esac +} diff --git a/root/target/linux/mediatek/mt7623/config-4.14 b/root/target/linux/mediatek/mt7623/config-4.14 new file mode 100644 index 00000000..07f6b76d --- /dev/null +++ b/root/target/linux/mediatek/mt7623/config-4.14 @@ -0,0 +1,570 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +# CONFIG_ARCH_WANTS_THP_SWAP is not set +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_MEDIATEK_CPUFREQ=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ATAGS=y +CONFIG_ATAGS_PROC=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CFG80211=m +CONFIG_CFG80211_CRDA_SUPPORT=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +# CONFIG_CFG80211_WEXT is not set +CONFIG_CLEANCACHE=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 vmalloc=256M" +CONFIG_CMDLINE_EXTEND=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_MEDIATEK=y +CONFIG_COMMON_CLK_MT2701=y +CONFIG_COMMON_CLK_MT2701_BDPSYS=y +CONFIG_COMMON_CLK_MT2701_ETHSYS=y +CONFIG_COMMON_CLK_MT2701_HIFSYS=y +CONFIG_COMMON_CLK_MT2701_IMGSYS=y +CONFIG_COMMON_CLK_MT2701_MMSYS=y +CONFIG_COMMON_CLK_MT2701_VDECSYS=y +# CONFIG_COMMON_CLK_MT7622 is not set +# CONFIG_COMMON_CLK_MT8135 is not set +# CONFIG_COMMON_CLK_MT8173 is not set +CONFIG_COMPACTION=y +CONFIG_COREDUMP=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRASH_CORE=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_MEDIATEK=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_MT6589_UART0=y +# CONFIG_DEBUG_MT8127_UART0 is not set +# CONFIG_DEBUG_MT8135_UART3 is not set +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=2 +# CONFIG_DEBUG_UART_8250_WORD is not set +CONFIG_DEBUG_UART_PHYS=0x11004000 +CONFIG_DEBUG_UART_VIRT=0xf1004000 +CONFIG_DEBUG_UNCOMPRESS=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEFAULT_DUMMY=y +CONFIG_DEFAULT_SCHEDULER=y +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NOOP_OPS is not set +CONFIG_DMA_OF=y +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DRM_LIB_RANDOM is not set +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ELF_CORE=y +CONFIG_EXPORTFS=y +CONFIG_EXT4_FS=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FREEZER=y +CONFIG_FS_MBCACHE=y +CONFIG_FUTEX_PI=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GPS is not set +# CONFIG_GRO_CELLS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +# CONFIG_HIGHMEM is not set +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MTK=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_PERIODIC=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MT65XX=y +CONFIG_ICPLUS_PHY=y +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set +CONFIG_INITRAMFS_COMPRESSION="" +# CONFIG_INITRAMFS_FORCE is not set +CONFIG_INITRAMFS_ROOT_GID=1000 +CONFIG_INITRAMFS_ROOT_UID=1000 +CONFIG_INITRAMFS_SOURCE="/openwrt/trunk/build_dir/target-arm_cortex-a7_musl-1.1.14_eabi/root-mediatek /openwrt/trunk/target/linux/generic/image/initramfs-base-files.txt" +CONFIG_IOMMU_HELPER=y +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_KEXEC=y +CONFIG_KEXEC_CORE=y +CONFIG_LDISC_AUTOLOAD=y +CONFIG_LEDS_MT6323=y +CONFIG_LIBFDT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_MACH_MT2701 is not set +# CONFIG_MACH_MT6589 is not set +# CONFIG_MACH_MT6592 is not set +CONFIG_MACH_MT7623=y +# CONFIG_MACH_MT8127 is not set +# CONFIG_MACH_MT8135 is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MEDIATEK_MT6577_AUXADC=y +CONFIG_MEDIATEK_WATCHDOG=y +CONFIG_MFD_CORE=y +CONFIG_MFD_MT6397=y +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_MTK=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MPTCP_BINDER is not set +# CONFIG_MPTCP_FULLMESH is not set +# CONFIG_MPTCP_NDIFFPORTS is not set +# CONFIG_MPTCP_REDUNDANT is not set +# CONFIG_MPTCP_ROUNDROBIN is not set +CONFIG_MTD_BLOCK2MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_MT81xx_NOR=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_MTK=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTK_BTIF=y +CONFIG_MTK_COMBO=y +# CONFIG_MTK_COMBO_BT is not set +CONFIG_MTK_COMBO_CHIP="CONSYS_7623" +# CONFIG_MTK_COMBO_CHIP_CONSYS_6572 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6580 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6582 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6592 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6735 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6752 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6755 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_6797 is not set +CONFIG_MTK_COMBO_CHIP_CONSYS_7623=y +# CONFIG_MTK_COMBO_CHIP_CONSYS_8127 is not set +# CONFIG_MTK_COMBO_CHIP_CONSYS_8163 is not set +# CONFIG_MTK_COMBO_CHIP_MT6620 is not set +# CONFIG_MTK_COMBO_CHIP_MT6628 is not set +# CONFIG_MTK_COMBO_CHIP_MT6630 is not set +# CONFIG_MTK_COMBO_COMM is not set +# CONFIG_MTK_COMBO_BT_HCI is not set +CONFIG_MTK_COMBO_PLAT_PATH="" +CONFIG_MTK_COMBO_WIFI=m +# CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set +CONFIG_MTK_DHCPV6C_WIFI=y +CONFIG_MTK_EFUSE=y +# CONFIG_MTK_GPS_SUPPORT is not set +# CONFIG_MTK_HSDMA is not set +CONFIG_MTK_INFRACFG=y +# CONFIG_MTK_IOMMU is not set +# CONFIG_MTK_IOMMU_V1 is not set +CONFIG_MTK_PASSPOINT_R1_SUPPORT=y +CONFIG_MTK_PASSPOINT_R2_SUPPORT=y +CONFIG_MTK_PLATFORM="mt7623" +CONFIG_MTK_PMIC_WRAP=y +CONFIG_MTK_SCPSYS=y +CONFIG_MTK_THERMAL=y +CONFIG_MTK_TIMER=y +CONFIG_MTK_WAPI_SUPPORT=y +CONFIG_MTK_WIFI_MCC_SUPPORT=y +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_MT7530=y +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +CONFIG_NET_DSA_TAG_MTK=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_MEDIATEK_HNAT=y +CONFIG_NET_MEDIATEK_SOC=y +CONFIG_NET_SWITCHDEV=y +# CONFIG_NET_VENDOR_AURORA is not set +CONFIG_NET_VENDOR_MEDIATEK=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NL80211_TESTMODE=y +CONFIG_NLS=y +CONFIG_NO_BOOTMEM=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PGTABLE_MAPPING=y +CONFIG_PHYLIB=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_MT2701=y +CONFIG_PINCTRL_MT6397=y +CONFIG_PINCTRL_MTK=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PRINTK_TIME=y +CONFIG_PWM=y +CONFIG_PWM_MEDIATEK=y +# CONFIG_PWM_MTK_DISP is not set +CONFIG_PWM_SYSFS=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MT6323=y +# CONFIG_REGULATOR_MT6380 is not set +# CONFIG_REGULATOR_MT6397 is not set +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_MT6397 is not set +# CONFIG_RTC_DRV_MT7622 is not set +CONFIG_RTC_I2C_AND_SPI=y +# CONFIG_RTL8723BS is not set +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SCHED_INFO is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MT65XX=y +CONFIG_SPMI=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWCONFIG=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASKS_RCU=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THIN_ARCHIVES=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_MTU3 is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WILC1000_SDIO is not set +# CONFIG_WILC1000_SPI is not set +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set \ No newline at end of file diff --git a/root/target/linux/mediatek/mt7623/config-4.19 b/root/target/linux/mediatek/mt7623/config-4.19 new file mode 100644 index 00000000..a7853f52 --- /dev/null +++ b/root/target/linux/mediatek/mt7623/config-4.19 @@ -0,0 +1,521 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_ARM_ATAG_DTB_COMPAT is not set +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_MEDIATEK_CPUFREQ=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_BCM84881_PHY is not set +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLEANCACHE=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 rootfstype=squashfs,jffs2" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_MEDIATEK=y +CONFIG_COMMON_CLK_MT2701=y +# CONFIG_COMMON_CLK_MT2701_AUDSYS is not set +CONFIG_COMMON_CLK_MT2701_BDPSYS=y +CONFIG_COMMON_CLK_MT2701_ETHSYS=y +# CONFIG_COMMON_CLK_MT2701_G3DSYS is not set +CONFIG_COMMON_CLK_MT2701_HIFSYS=y +CONFIG_COMMON_CLK_MT2701_IMGSYS=y +CONFIG_COMMON_CLK_MT2701_MMSYS=y +CONFIG_COMMON_CLK_MT2701_VDECSYS=y +# CONFIG_COMMON_CLK_MT7622 is not set +# CONFIG_COMMON_CLK_MT7629 is not set +# CONFIG_COMMON_CLK_MT8135 is not set +# CONFIG_COMMON_CLK_MT8173 is not set +CONFIG_COREDUMP=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_MEDIATEK=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_MT6589_UART0=y +# CONFIG_DEBUG_MT8127_UART0 is not set +# CONFIG_DEBUG_MT8135_UART3 is not set +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=2 +# CONFIG_DEBUG_UART_8250_WORD is not set +CONFIG_DEBUG_UART_PHYS=0x11004000 +CONFIG_DEBUG_UART_VIRT=0xf1004000 +CONFIG_DEBUG_UNCOMPRESS=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEFAULT_MPTCP_PM="fullmesh" +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EINT_MTK=y +CONFIG_ELF_CORE=y +CONFIG_EXT4_FS=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FREEZER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GPS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MTK=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MT65XX=y +CONFIG_ICPLUS_PHY=y +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_LEDS_MT6323=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_MACH_MT2701 is not set +# CONFIG_MACH_MT6589 is not set +# CONFIG_MACH_MT6592 is not set +CONFIG_MACH_MT7623=y +# CONFIG_MACH_MT7629 is not set +# CONFIG_MACH_MT8127 is not set +# CONFIG_MACH_MT8135 is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MEDIATEK_MT6577_AUXADC=y +CONFIG_MEDIATEK_WATCHDOG=y +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_CORE=y +CONFIG_MFD_MT6397=y +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_MTK=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MT753X_GSW is not set +CONFIG_MTD_BLOCK2MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_MT81xx_NOR=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_MTK=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +# CONFIG_MTK_BTIF is not set +# CONFIG_MTK_COMBO is not set +# CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set +# CONFIG_MTK_DHCPV6C_WIFI is not set +CONFIG_MTK_EFUSE=y +# CONFIG_MTK_GPS_SUPPORT is not set +# CONFIG_MTK_HSDMA is not set +CONFIG_MTK_INFRACFG=y +# CONFIG_MTK_IOMMU is not set +# CONFIG_MTK_IOMMU_V1 is not set +CONFIG_MTK_PLATFORM="" +CONFIG_MTK_PMIC_WRAP=y +CONFIG_MTK_SCPSYS=y +CONFIG_MTK_THERMAL=y +CONFIG_MTK_TIMER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_TAG_MTK=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_MEDIATEK_SOC=y +CONFIG_NET_SWITCHDEV=y +# CONFIG_NET_VENDOR_AURORA is not set +CONFIG_NET_VENDOR_MEDIATEK=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NLS=y +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +# CONFIG_PCI_V3_SEMI is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHY_MTK_TPHY=y +# CONFIG_PHY_MTK_XSPHY is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_MT2701=y +CONFIG_PINCTRL_MT6397=y +CONFIG_PINCTRL_MT7623=y +CONFIG_PINCTRL_MTK=y +CONFIG_PINCTRL_MTK_MOORE=y +CONFIG_PLUGIN_HOSTCC="g++" +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PRINTK_TIME=y +CONFIG_PWM=y +CONFIG_PWM_MEDIATEK=y +# CONFIG_PWM_MTK_DISP is not set +CONFIG_PWM_SYSFS=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MT6323=y +# CONFIG_REGULATOR_MT6380 is not set +# CONFIG_REGULATOR_MT6397 is not set +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_MT6397 is not set +# CONFIG_RTC_DRV_MT7622 is not set +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SFP is not set +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_MT65XX=y +# CONFIG_SPI_MTK_SNFI is not set +CONFIG_SPMI=y +CONFIG_SRCU=y +CONFIG_STREAM_PARSER=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWCONFIG=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASKS_RCU=y +# CONFIG_TCP_CONG_NANQINLANG is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/root/target/linux/mediatek/mt7623/config-5.4 b/root/target/linux/mediatek/mt7623/config-5.4 new file mode 100644 index 00000000..6e1ff28b --- /dev/null +++ b/root/target/linux/mediatek/mt7623/config-5.4 @@ -0,0 +1,561 @@ +# CONFIG_AIO is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_BINFMT_FLAT=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_KEEPINITRD=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_SETUP_DMA_OPS=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_ARCH_MILBEAUT is not set +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +# CONFIG_ARCH_RDA is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_ARM_ATAG_DTB_COMPAT is not set +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +# CONFIG_ARM_ERRATA_814220 is not set +# CONFIG_ARM_ERRATA_857271 is not set +# CONFIG_ARM_ERRATA_857272 is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_MEDIATEK_CPUFREQ=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CC_CAN_LINK=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y +CONFIG_CLEANCACHE=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 rootfstype=squashfs,jffs2" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_MEDIATEK=y +CONFIG_COMMON_CLK_MT2701=y +# CONFIG_COMMON_CLK_MT2701_AUDSYS is not set +CONFIG_COMMON_CLK_MT2701_BDPSYS=y +CONFIG_COMMON_CLK_MT2701_ETHSYS=y +# CONFIG_COMMON_CLK_MT2701_G3DSYS is not set +CONFIG_COMMON_CLK_MT2701_HIFSYS=y +CONFIG_COMMON_CLK_MT2701_IMGSYS=y +CONFIG_COMMON_CLK_MT2701_MMSYS=y +CONFIG_COMMON_CLK_MT2701_VDECSYS=y +# CONFIG_COMMON_CLK_MT7622 is not set +# CONFIG_COMMON_CLK_MT7629 is not set +# CONFIG_COMMON_CLK_MT8135 is not set +# CONFIG_COMMON_CLK_MT8173 is not set +CONFIG_COMMON_CLK_MT8516=y +# CONFIG_COMMON_CLK_MT8516_AUDSYS is not set +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_COREDUMP=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +# CONFIG_CPU_THERMAL is not set +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_MEDIATEK=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_MISC=y +CONFIG_DEBUG_MT6589_UART0=y +# CONFIG_DEBUG_MT8127_UART0 is not set +# CONFIG_DEBUG_MT8135_UART3 is not set +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=2 +# CONFIG_DEBUG_UART_8250_WORD is not set +CONFIG_DEBUG_UART_PHYS=0x11004000 +CONFIG_DEBUG_UART_VIRT=0xf1004000 +CONFIG_DEBUG_UNCOMPRESS=y +# CONFIG_DEBUG_USER is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_REMAP=y +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EINT_MTK=y +CONFIG_ELF_CORE=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_EXT4_FS=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FREEZER=y +# CONFIG_FSL_QDMA is not set +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_HABANA_AI is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_COPY_THREAD_TLS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PCI=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MTK=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MT65XX=y +# CONFIG_I2C_NVIDIA_GPU is not set +CONFIG_ICPLUS_PHY=y +# CONFIG_IGC is not set +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set +CONFIG_INITRAMFS_COMPRESSION="" +CONFIG_INITRAMFS_ROOT_GID=1000 +CONFIG_INITRAMFS_ROOT_UID=1000 +CONFIG_INITRAMFS_SOURCE="/openwrt/trunk/build_dir/target-arm_cortex-a7_musl-1.1.14_eabi/root-mediatek /openwrt/trunk/target/linux/generic/image/initramfs-base-files.txt" +CONFIG_INIT_STACK_NONE=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IO_URING=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_LEDS_MT6323=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_MACH_MT2701 is not set +# CONFIG_MACH_MT6589 is not set +# CONFIG_MACH_MT6592 is not set +CONFIG_MACH_MT7623=y +# CONFIG_MACH_MT7629 is not set +# CONFIG_MACH_MT8127 is not set +# CONFIG_MACH_MT8135 is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MEDIATEK_MT6577_AUXADC=y +CONFIG_MEDIATEK_WATCHDOG=y +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_CORE=y +CONFIG_MFD_MT6397=y +# CONFIG_MFD_STPMIC1 is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +# CONFIG_MISC_ALCOR_PCI is not set +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_MTK=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MT753X_GSW is not set +CONFIG_MTD_BLOCK2MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +# CONFIG_MTK_CMDQ is not set +# CONFIG_MTK_CQDMA is not set +CONFIG_MTK_EFUSE=y +# CONFIG_MTK_HSDMA is not set +CONFIG_MTK_INFRACFG=y +# CONFIG_MTK_IOMMU is not set +# CONFIG_MTK_IOMMU_V1 is not set +CONFIG_MTK_PMIC_WRAP=y +CONFIG_MTK_SCPSYS=y +CONFIG_MTK_THERMAL=y +CONFIG_MTK_TIMER=y +# CONFIG_MTK_UART_APDMA is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_TAG_MTK=y +# CONFIG_NET_DSA_TAG_QCA is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_MEDIATEK_SOC=y +CONFIG_NET_SWITCHDEV=y +# CONFIG_NET_VENDOR_AURORA is not set +CONFIG_NET_VENDOR_MEDIATEK=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +# CONFIG_NVMEM_REBOOT_MODE is not set +CONFIG_NVMEM_SYSFS=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +# CONFIG_PCI_MESON is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +# CONFIG_PCI_V3_SEMI is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHY_MTK_TPHY=y +# CONFIG_PHY_MTK_UFS is not set +# CONFIG_PHY_MTK_XSPHY is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_MT2701=y +CONFIG_PINCTRL_MT6397=y +CONFIG_PINCTRL_MT7623=y +CONFIG_PINCTRL_MTK=y +CONFIG_PINCTRL_MTK_MOORE=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_POWER_SUPPLY_HWMON=y +CONFIG_PREEMPT=y +CONFIG_PREEMPTION=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PRINTK_TIME=y +CONFIG_PWM=y +CONFIG_PWM_MEDIATEK=y +# CONFIG_PWM_MTK_DISP is not set +CONFIG_PWM_SYSFS=y +# CONFIG_QCOM_SPMI_ADC5 is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MT6323=y +# CONFIG_REGULATOR_MT6380 is not set +# CONFIG_REGULATOR_MT6397 is not set +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_MT6397 is not set +# CONFIG_RTC_DRV_MT7622 is not set +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_MT65XX=y +CONFIG_SPMI=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWCONFIG=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASKS_RCU=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +# CONFIG_TI_CPSW_PHY_SEL is not set +CONFIG_TREE_SRCU=y +# CONFIG_TRUSTED_FOUNDATIONS is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UBIFS_FS_ZSTD=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_UNWINDER_ARM=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +CONFIG_USB=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/root/target/linux/mediatek/patches-4.14/0229-fix-memory-size-for-bpi-r2.patch b/root/target/linux/mediatek/patches-4.14/0229-fix-memory-size-for-bpi-r2.patch new file mode 100644 index 00000000..517b5be6 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0229-fix-memory-size-for-bpi-r2.patch @@ -0,0 +1,23 @@ +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts 2018-12-26 16:53:06.778501203 +0100 ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts 2018-12-26 16:55:46.280213376 +0100 +@@ -22,6 +22,7 @@ + }; + + memory { +- reg = <0 0x80000000 0 0x20000000>; ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; + }; + +@@ -115,11 +116,6 @@ + }; + }; + +- memory@80000000 { +- device_type = "memory"; +- reg = <0 0x80000000 0 0x40000000>; +- }; +- + mt7530: switch@0 { + compatible = "mediatek,mt7530"; + }; diff --git a/root/target/linux/mediatek/patches-4.14/0229-update-gpio-leds-for-bpi-r2.patch b/root/target/linux/mediatek/patches-4.14/0229-update-gpio-leds-for-bpi-r2.patch new file mode 100644 index 00000000..ef9b4a79 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0229-update-gpio-leds-for-bpi-r2.patch @@ -0,0 +1,27 @@ +Index: linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +=================================================================== +--- linux-4.14.51.orig/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -87,19 +87,19 @@ + + blue { + label = "bpi-r2:pio:blue"; +- gpios = <&pio 241 GPIO_ACTIVE_HIGH>; ++ gpios = <&pio 240 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + green { + label = "bpi-r2:pio:green"; +- gpios = <&pio 240 GPIO_ACTIVE_HIGH>; ++ gpios = <&pio 241 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + red { + label = "bpi-r2:pio:red"; +- gpios = <&pio 239 GPIO_ACTIVE_HIGH>; ++ gpios = <&pio 239 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; diff --git a/root/target/linux/mediatek/patches-4.14/0230-update-pcie-for-bpi-r2.patch b/root/target/linux/mediatek/patches-4.14/0230-update-pcie-for-bpi-r2.patch new file mode 100644 index 00000000..f202cae7 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0230-update-pcie-for-bpi-r2.patch @@ -0,0 +1,48 @@ +Index: linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +=================================================================== +--- linux-4.14.51.orig/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -266,6 +266,28 @@ + vqmmc-supply = <&mt6323_vio18_reg>; + }; + ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_default>; ++ status = "okay"; ++ ++ pcie@0,0 { ++ status = "okay"; ++ }; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pcie0_phy { ++ status = "okay"; ++}; ++ ++&pcie1_phy { ++ status = "okay"; ++}; ++ + &pio { + cir_pins_a:cir@0 { + pins_cir { +@@ -433,6 +455,14 @@ + }; + }; + ++ pcie_default: pcie_pin_default { ++ pins_cmd_dat { ++ pinmux = , ++ ; ++ bias-disable; ++ }; ++ }; ++ + pwm_pins_a: pwm@0 { + pins_pwm { + pinmux = , diff --git a/root/target/linux/mediatek/patches-4.14/0231-enable-trgmii-on-bpi-r2.patch b/root/target/linux/mediatek/patches-4.14/0231-enable-trgmii-on-bpi-r2.patch new file mode 100644 index 00000000..7c30af0a --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0231-enable-trgmii-on-bpi-r2.patch @@ -0,0 +1,22 @@ +Index: linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +=================================================================== +--- linux-4.14.51.orig/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ linux-4.14.51/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -141,7 +141,7 @@ + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; +- phy-mode = "rgmii"; ++ phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; +@@ -206,7 +206,7 @@ + reg = <5>; + label = "cpu"; + ethernet = <&gmac1>; +- phy-mode = "rgmii"; ++ phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; diff --git a/root/target/linux/mediatek/patches-4.14/0232-merge-mt6625l-wifi-driver.patch b/root/target/linux/mediatek/patches-4.14/0232-merge-mt6625l-wifi-driver.patch new file mode 100644 index 00000000..25dca71f --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0232-merge-mt6625l-wifi-driver.patch @@ -0,0 +1,217327 @@ +From e6b369a5ade19206db433b46d0102ae000b87e99 Mon Sep 17 00:00:00 2001 +From: frank +Date: Wed, 20 Dec 2017 22:36:53 +0100 +Subject: [PATCH] merge mt6625l wifi driver + +--- + arch/arm/boot/dts/mt7623.dtsi | 48 + + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 263 + + drivers/misc/Kconfig | 1 + + drivers/misc/Makefile | 2 + + drivers/misc/mediatek/Kconfig | 11 + + drivers/misc/mediatek/Makefile | 19 + + drivers/misc/mediatek/btif/Kconfig | 4 + + drivers/misc/mediatek/btif/Makefile | 33 + + drivers/misc/mediatek/btif/common/Makefile | 31 + + .../misc/mediatek/btif/common/btif_dma_plat.c | 1436 ++ + drivers/misc/mediatek/btif/common/btif_plat.c | 1396 ++ + .../misc/mediatek/btif/common/inc/mtk_btif.h | 370 + + .../mediatek/btif/common/inc/mtk_btif_exp.h | 280 + + drivers/misc/mediatek/btif/common/mtk_btif.c | 3472 +++++ + .../misc/mediatek/btif/common/mtk_btif_exp.c | 786 ++ + .../btif/common/plat_inc/btif_dma_priv.h | 164 + + .../btif/common/plat_inc/btif_dma_pub.h | 197 + + .../mediatek/btif/common/plat_inc/btif_priv.h | 105 + + .../mediatek/btif/common/plat_inc/btif_pub.h | 237 + + .../btif/common/plat_inc/plat_common.h | 307 + + drivers/misc/mediatek/connectivity/Kconfig | 298 + + drivers/misc/mediatek/connectivity/Makefile | 41 + + .../mediatek/connectivity/common/Makefile | 23 + + .../common/common_detect/Makefile | 47 + + .../common/common_detect/drv_init/Makefile | 22 + + .../common_detect/drv_init/ant_drv_init.c | 38 + + .../drv_init/bluetooth_drv_init.c | 35 + + .../common_detect/drv_init/common_drv_init.c | 103 + + .../common_detect/drv_init/conn_drv_init.c | 80 + + .../common_detect/drv_init/fm_drv_init.c | 33 + + .../common_detect/drv_init/gps_drv_init.c | 35 + + .../common_detect/drv_init/inc/ant_drv_init.h | 20 + + .../drv_init/inc/bluetooth_drv_init.h | 20 + + .../drv_init/inc/common_drv_init.h | 31 + + .../drv_init/inc/conn_drv_init.h | 18 + + .../common_detect/drv_init/inc/fm_drv_init.h | 20 + + .../common_detect/drv_init/inc/gps_drv_init.h | 19 + + .../drv_init/inc/wlan_drv_init.h | 30 + + .../common_detect/drv_init/wlan_drv_init.c | 74 + + .../common/common_detect/mtk_wcn_stub_alps.c | 605 + + .../common/common_detect/sdio_detect.c | 269 + + .../common/common_detect/sdio_detect.h | 43 + + .../common/common_detect/wmt_detect.c | 380 + + .../common/common_detect/wmt_detect.h | 114 + + .../common/common_detect/wmt_detect_pwr.c | 232 + + .../common/common_detect/wmt_detect_pwr.h | 29 + + .../common/common_detect/wmt_gpio.c | 371 + + .../common/common_detect/wmt_gpio.h | 103 + + .../common/common_detect/wmt_stp_exp.c | 480 + + .../common/common_detect/wmt_stp_exp.h | 610 + + .../connectivity/common/conn_soc/Makefile | 65 + + .../common/conn_soc/core/Makefile | 22 + + .../common/conn_soc/core/btm_core.c | 1376 ++ + .../common/conn_soc/core/dbg_core.c | 13 + + .../common/conn_soc/core/include/btm_core.h | 133 + + .../common/conn_soc/core/include/dbg_core.h | 69 + + .../common/conn_soc/core/include/psm_core.h | 251 + + .../common/conn_soc/core/include/stp_core.h | 629 + + .../common/conn_soc/core/include/stp_wmt.h | 89 + + .../common/conn_soc/core/include/wmt_conf.h | 74 + + .../common/conn_soc/core/include/wmt_core.h | 428 + + .../common/conn_soc/core/include/wmt_ctrl.h | 120 + + .../common/conn_soc/core/include/wmt_func.h | 140 + + .../common/conn_soc/core/include/wmt_ic.h | 122 + + .../common/conn_soc/core/include/wmt_lib.h | 300 + + .../common/conn_soc/core/psm_core.c | 1889 +++ + .../common/conn_soc/core/stp_core.c | 3358 +++++ + .../common/conn_soc/core/wmt_conf.c | 529 + + .../common/conn_soc/core/wmt_core.c | 2521 ++++ + .../common/conn_soc/core/wmt_ctrl.c | 1019 ++ + .../common/conn_soc/core/wmt_func.c | 713 + + .../common/conn_soc/core/wmt_ic_soc.c | 2452 ++++ + .../common/conn_soc/core/wmt_lib.c | 1938 +++ + .../common/conn_soc/include/stp_exp.h | 252 + + .../common/conn_soc/include/wmt.h | 19 + + .../common/conn_soc/include/wmt_exp.h | 329 + + .../common/conn_soc/include/wmt_plat.h | 295 + + .../common/conn_soc/linux/Makefile | 6 + + .../conn_soc/linux/include/bgw_desense.h | 74 + + .../common/conn_soc/linux/include/osal.h | 348 + + .../conn_soc/linux/include/osal_typedef.h | 90 + + .../common/conn_soc/linux/include/wmt_idc.h | 97 + + .../common/conn_soc/linux/pri/Makefile | 21 + + .../conn_soc/linux/pri/include/stp_btif.h | 31 + + .../conn_soc/linux/pri/include/stp_dbg.h | 316 + + .../conn_soc/linux/pri/include/wmt_dev.h | 71 + + .../common/conn_soc/linux/pri/stp_btif.c | 279 + + .../common/conn_soc/linux/pri/stp_dbg.c | 2060 +++ + .../common/conn_soc/linux/pri/stp_exp.c | 279 + + .../common/conn_soc/linux/pri/wmt_dev.c | 2566 ++++ + .../common/conn_soc/linux/pri/wmt_exp.c | 610 + + .../common/conn_soc/linux/pub/Makefile | 27 + + .../common/conn_soc/linux/pub/bgw_desense.c | 153 + + .../common/conn_soc/linux/pub/osal.c | 1210 ++ + .../common/conn_soc/linux/pub/stp_chrdev_bt.c | 899 ++ + .../conn_soc/linux/pub/wmt_chrdev_wifi.c | 668 + + .../common/conn_soc/linux/pub/wmt_idc.c | 307 + + .../common/conn_soc/mt7623/Makefile | 25 + + .../mt7623/include/mtk_wcn_consys_hw.h | 287 + + .../conn_soc/mt7623/mtk_wcn_consys_hw.c | 737 ++ + .../common/conn_soc/mt7623/wmt_plat_alps.c | 1071 ++ + .../misc/mediatek/connectivity/wlan/Makefile | 8 + + .../mediatek/connectivity/wlan/gen2/Makefile | 237 + + .../connectivity/wlan/gen2/common/debug.c | 165 + + .../connectivity/wlan/gen2/common/dump.c | 345 + + .../connectivity/wlan/gen2/common/wlan_bow.c | 3442 +++++ + .../connectivity/wlan/gen2/common/wlan_lib.c | 6240 +++++++++ + .../connectivity/wlan/gen2/common/wlan_oid.c | 11050 ++++++++++++++++ + .../connectivity/wlan/gen2/common/wlan_p2p.c | 1654 +++ + .../wlan/gen2/include/CFG_Wifi_File.h | 238 + + .../connectivity/wlan/gen2/include/config.h | 1628 +++ + .../connectivity/wlan/gen2/include/debug.h | 466 + + .../connectivity/wlan/gen2/include/link.h | 368 + + .../wlan/gen2/include/mgmt/aa_fsm.h | 188 + + .../wlan/gen2/include/mgmt/ais_fsm.h | 573 + + .../wlan/gen2/include/mgmt/assoc.h | 112 + + .../wlan/gen2/include/mgmt/auth.h | 125 + + .../wlan/gen2/include/mgmt/bow_fsm.h | 184 + + .../connectivity/wlan/gen2/include/mgmt/bss.h | 265 + + .../connectivity/wlan/gen2/include/mgmt/cnm.h | 258 + + .../wlan/gen2/include/mgmt/cnm_mem.h | 1164 ++ + .../wlan/gen2/include/mgmt/cnm_scan.h | 169 + + .../wlan/gen2/include/mgmt/cnm_timer.h | 235 + + .../wlan/gen2/include/mgmt/hem_mbox.h | 446 + + .../wlan/gen2/include/mgmt/hs20.h | 148 + + .../connectivity/wlan/gen2/include/mgmt/mib.h | 153 + + .../wlan/gen2/include/mgmt/p2p_assoc.h | 55 + + .../wlan/gen2/include/mgmt/p2p_bss.h | 56 + + .../wlan/gen2/include/mgmt/p2p_fsm.h | 2190 +++ + .../wlan/gen2/include/mgmt/p2p_func.h | 155 + + .../wlan/gen2/include/mgmt/p2p_ie.h | 156 + + .../wlan/gen2/include/mgmt/p2p_rlm.h | 74 + + .../wlan/gen2/include/mgmt/p2p_rlm_obss.h | 64 + + .../wlan/gen2/include/mgmt/p2p_scan.h | 81 + + .../wlan/gen2/include/mgmt/p2p_state.h | 43 + + .../wlan/gen2/include/mgmt/privacy.h | 230 + + .../wlan/gen2/include/mgmt/rate.h | 93 + + .../connectivity/wlan/gen2/include/mgmt/rlm.h | 396 + + .../wlan/gen2/include/mgmt/rlm_domain.h | 557 + + .../wlan/gen2/include/mgmt/rlm_obss.h | 150 + + .../wlan/gen2/include/mgmt/rlm_protection.h | 122 + + .../wlan/gen2/include/mgmt/rlm_txpwr_init.h | 1213 ++ + .../wlan/gen2/include/mgmt/roaming_fsm.h | 171 + + .../connectivity/wlan/gen2/include/mgmt/rsn.h | 271 + + .../wlan/gen2/include/mgmt/scan.h | 988 ++ + .../wlan/gen2/include/mgmt/sec_fsm.h | 233 + + .../wlan/gen2/include/mgmt/stats.h | 368 + + .../wlan/gen2/include/mgmt/swcr.h | 187 + + .../wlan/gen2/include/mgmt/tdls.h | 262 + + .../wlan/gen2/include/mgmt/wapi.h | 104 + + .../wlan/gen2/include/mgmt/wlan_typedef.h | 87 + + .../connectivity/wlan/gen2/include/mgmt/wnm.h | 95 + + .../wlan/gen2/include/nic/adapter.h | 1506 +++ + .../connectivity/wlan/gen2/include/nic/bow.h | 322 + + .../wlan/gen2/include/nic/cmd_buf.h | 150 + + .../connectivity/wlan/gen2/include/nic/hal.h | 618 + + .../wlan/gen2/include/nic/hif_rx.h | 220 + + .../wlan/gen2/include/nic/hif_tx.h | 214 + + .../connectivity/wlan/gen2/include/nic/mac.h | 2323 ++++ + .../wlan/gen2/include/nic/mtreg.h | 272 + + .../connectivity/wlan/gen2/include/nic/nic.h | 498 + + .../wlan/gen2/include/nic/nic_rx.h | 420 + + .../wlan/gen2/include/nic/nic_tx.h | 642 + + .../connectivity/wlan/gen2/include/nic/p2p.h | 192 + + .../wlan/gen2/include/nic/p2p_cmd_buf.h | 83 + + .../wlan/gen2/include/nic/p2p_mac.h | 207 + + .../wlan/gen2/include/nic/p2p_nic.h | 62 + + .../wlan/gen2/include/nic/p2p_nic_cmd_event.h | 70 + + .../wlan/gen2/include/nic/que_mgt.h | 971 ++ + .../wlan/gen2/include/nic/wlan_def.h | 1010 ++ + .../wlan/gen2/include/nic_cmd_event.h | 2290 ++++ + .../wlan/gen2/include/nic_init_cmd_event.h | 177 + + .../wlan/gen2/include/p2p_precomp.h | 201 + + .../wlan/gen2/include/p2p_typedef.h | 165 + + .../connectivity/wlan/gen2/include/precomp.h | 388 + + .../connectivity/wlan/gen2/include/pwr_mgt.h | 141 + + .../connectivity/wlan/gen2/include/queue.h | 195 + + .../connectivity/wlan/gen2/include/rftest.h | 294 + + .../wlan/gen2/include/tdls_extr.h | 427 + + .../connectivity/wlan/gen2/include/typedef.h | 244 + + .../connectivity/wlan/gen2/include/wlan_bow.h | 352 + + .../connectivity/wlan/gen2/include/wlan_lib.h | 1001 ++ + .../connectivity/wlan/gen2/include/wlan_oid.h | 1715 +++ + .../connectivity/wlan/gen2/include/wlan_p2p.h | 307 + + .../connectivity/wlan/gen2/mgmt/aaa_fsm.c | 1303 ++ + .../connectivity/wlan/gen2/mgmt/ais_fsm.c | 5039 +++++++ + .../connectivity/wlan/gen2/mgmt/assoc.c | 1932 +++ + .../connectivity/wlan/gen2/mgmt/auth.c | 1211 ++ + .../connectivity/wlan/gen2/mgmt/bss.c | 2521 ++++ + .../connectivity/wlan/gen2/mgmt/cnm.c | 738 ++ + .../connectivity/wlan/gen2/mgmt/cnm_mem.c | 1236 ++ + .../connectivity/wlan/gen2/mgmt/cnm_timer.c | 482 + + .../connectivity/wlan/gen2/mgmt/hem_mbox.c | 816 ++ + .../connectivity/wlan/gen2/mgmt/hs20.c | 498 + + .../connectivity/wlan/gen2/mgmt/mib.c | 111 + + .../connectivity/wlan/gen2/mgmt/p2p_assoc.c | 87 + + .../connectivity/wlan/gen2/mgmt/p2p_bss.c | 58 + + .../connectivity/wlan/gen2/mgmt/p2p_fsm.c | 3139 +++++ + .../connectivity/wlan/gen2/mgmt/p2p_func.c | 3796 ++++++ + .../connectivity/wlan/gen2/mgmt/p2p_ie.c | 612 + + .../connectivity/wlan/gen2/mgmt/p2p_rlm.c | 905 ++ + .../wlan/gen2/mgmt/p2p_rlm_obss.c | 313 + + .../connectivity/wlan/gen2/mgmt/p2p_scan.c | 756 ++ + .../connectivity/wlan/gen2/mgmt/p2p_state.c | 466 + + .../connectivity/wlan/gen2/mgmt/privacy.c | 915 ++ + .../connectivity/wlan/gen2/mgmt/rate.c | 497 + + .../connectivity/wlan/gen2/mgmt/rlm.c | 1858 +++ + .../connectivity/wlan/gen2/mgmt/rlm_domain.c | 1791 +++ + .../connectivity/wlan/gen2/mgmt/rlm_obss.c | 436 + + .../wlan/gen2/mgmt/rlm_protection.c | 105 + + .../connectivity/wlan/gen2/mgmt/roaming_fsm.c | 539 + + .../connectivity/wlan/gen2/mgmt/rsn.c | 2533 ++++ + .../connectivity/wlan/gen2/mgmt/saa_fsm.c | 1788 +++ + .../connectivity/wlan/gen2/mgmt/scan.c | 3103 +++++ + .../connectivity/wlan/gen2/mgmt/scan_fsm.c | 2136 +++ + .../connectivity/wlan/gen2/mgmt/sec_fsm.c | 1112 ++ + .../connectivity/wlan/gen2/mgmt/stats.c | 1342 ++ + .../connectivity/wlan/gen2/mgmt/swcr.c | 1170 ++ + .../connectivity/wlan/gen2/mgmt/tdls.c | 5199 ++++++++ + .../connectivity/wlan/gen2/mgmt/tdls_com.c | 741 ++ + .../connectivity/wlan/gen2/mgmt/wapi.c | 491 + + .../connectivity/wlan/gen2/mgmt/wnm.c | 301 + + .../connectivity/wlan/gen2/nic/cmd_buf.c | 254 + + .../mediatek/connectivity/wlan/gen2/nic/nic.c | 4062 ++++++ + .../wlan/gen2/nic/nic_cmd_event.c | 1636 +++ + .../connectivity/wlan/gen2/nic/nic_pwr_mgt.c | 669 + + .../connectivity/wlan/gen2/nic/nic_rx.c | 3782 ++++++ + .../connectivity/wlan/gen2/nic/nic_tx.c | 2350 ++++ + .../connectivity/wlan/gen2/nic/p2p_nic.c | 192 + + .../connectivity/wlan/gen2/nic/que_mgt.c | 5038 +++++++ + .../connectivity/wlan/gen2/os/linux/gl_bow.c | 1177 ++ + .../wlan/gen2/os/linux/gl_cfg80211.c | 3110 +++++ + .../connectivity/wlan/gen2/os/linux/gl_init.c | 3501 +++++ + .../connectivity/wlan/gen2/os/linux/gl_kal.c | 4801 +++++++ + .../connectivity/wlan/gen2/os/linux/gl_p2p.c | 4671 +++++++ + .../wlan/gen2/os/linux/gl_p2p_cfg80211.c | 1935 +++ + .../wlan/gen2/os/linux/gl_p2p_init.c | 433 + + .../wlan/gen2/os/linux/gl_p2p_kal.c | 1314 ++ + .../connectivity/wlan/gen2/os/linux/gl_proc.c | 1020 ++ + .../connectivity/wlan/gen2/os/linux/gl_rst.c | 228 + + .../wlan/gen2/os/linux/gl_vendor.c | 1220 ++ + .../connectivity/wlan/gen2/os/linux/gl_wext.c | 4158 ++++++ + .../wlan/gen2/os/linux/gl_wext_priv.c | 3142 +++++ + .../wlan/gen2/os/linux/hif/ahb/ahb.c | 1643 +++ + .../wlan/gen2/os/linux/hif/ahb/arm.c | 31 + + .../wlan/gen2/os/linux/hif/ahb/include/hif.h | 340 + + .../gen2/os/linux/hif/ahb/include/hif_gdma.h | 154 + + .../gen2/os/linux/hif/ahb/include/hif_pdma.h | 141 + + .../os/linux/hif/ahb/include/mtk_porting.h | 91 + + .../gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c | 480 + + .../wlan/gen2/os/linux/include/gl_cfg80211.h | 341 + + .../wlan/gen2/os/linux/include/gl_kal.h | 1565 +++ + .../wlan/gen2/os/linux/include/gl_os.h | 1270 ++ + .../wlan/gen2/os/linux/include/gl_p2p_ioctl.h | 743 ++ + .../wlan/gen2/os/linux/include/gl_p2p_kal.h | 243 + + .../wlan/gen2/os/linux/include/gl_p2p_os.h | 242 + + .../wlan/gen2/os/linux/include/gl_rst.h | 133 + + .../wlan/gen2/os/linux/include/gl_sec.h | 21 + + .../wlan/gen2/os/linux/include/gl_typedef.h | 298 + + .../wlan/gen2/os/linux/include/gl_vendor.h | 619 + + .../wlan/gen2/os/linux/include/gl_wext.h | 357 + + .../wlan/gen2/os/linux/include/gl_wext_priv.h | 402 + + .../wlan/gen2/os/linux/platform.c | 542 + + .../connectivity/wlan/gen2/os/version.h | 190 + + drivers/misc/mediatek/include/mt-plat/aee.h | 284 + + .../misc/mediatek/include/mt-plat/mrdump.h | 204 + + .../mt-plat/mt7622/include/mach/mtk_thermal.h | 295 + + .../mt8127/include/mach/mt_freqhopping.h | 159 + + .../mt8127/include/mach/mt_spm_mtcmos.h | 37 + + .../mt8127/include/mach/mtk_boot_share_page.h | 40 + + .../mt-plat/mt8127/include/mach/mtk_thermal.h | 301 + + .../misc/mediatek/include/mt-plat/mt_sched.h | 34 + + .../misc/mediatek/include/mt-plat/mtk_io.h | 23 + + .../misc/mediatek/include/mt-plat/mtk_lpae.h | 62 + + .../include/mt-plat/mtk_mdm_monitor.h | 42 + + .../include/mt-plat/mtk_platform_debug.h | 28 + + .../include/mt-plat/mtk_ram_console.h | 162 + + .../misc/mediatek/include/mt-plat/mtk_rtc.h | 85 + + .../include/mt-plat/mtk_thermal_ext_control.h | 69 + + .../include/mt-plat/mtk_thermal_monitor.h | 102 + + .../include/mt-plat/mtk_thermal_platform.h | 114 + + .../include/mt-plat/mtk_thermal_trace.h | 47 + + .../include/mt-plat/mtk_thermal_typedefs.h | 241 + + .../include/mt-plat/mtk_wcn_cmb_stub.h | 185 + + .../misc/mediatek/include/mt-plat/rt-regmap.h | 291 + + .../mediatek/include/mt-plat/sync_write.h | 88 + + .../misc/mediatek/include/mt-plat/wakelock.h | 67 + + drivers/soc/mediatek/mtk-pmic-wrap.c | 16 + + drivers/watchdog/mtk_wdt.c | 363 +- + include/linux/wakelock.h | 67 + + include/net/cfg80211.h | 2 +- + include/net/genetlink.h | 45 + + include/soc/mediatek/pmic_wrap.h | 19 + + include/uapi/linux/genetlink.h | 1 + + 294 files changed, 214777 insertions(+), 12 deletions(-) + create mode 100644 drivers/misc/mediatek/Kconfig + create mode 100644 drivers/misc/mediatek/Makefile + create mode 100644 drivers/misc/mediatek/btif/Kconfig + create mode 100644 drivers/misc/mediatek/btif/Makefile + create mode 100644 drivers/misc/mediatek/btif/common/Makefile + create mode 100644 drivers/misc/mediatek/btif/common/btif_dma_plat.c + create mode 100644 drivers/misc/mediatek/btif/common/btif_plat.c + create mode 100644 drivers/misc/mediatek/btif/common/inc/mtk_btif.h + create mode 100644 drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h + create mode 100644 drivers/misc/mediatek/btif/common/mtk_btif.c + create mode 100644 drivers/misc/mediatek/btif/common/mtk_btif_exp.c + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/plat_common.h + create mode 100644 drivers/misc/mediatek/connectivity/Kconfig + create mode 100644 drivers/misc/mediatek/connectivity/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/aee.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mrdump.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt_sched.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_io.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_lpae.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_rtc.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/rt-regmap.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/sync_write.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/wakelock.h + create mode 100644 include/linux/wakelock.h + create mode 100644 include/soc/mediatek/pmic_wrap.h + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 5361d48a2240..bdfd22bbf7fd 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -263,6 +263,8 @@ + compatible = "mediatek,mt7623-wdt", + "mediatek,mt6589-wdt"; + reg = <0 0x10007000 0 0x100>; ++ interrupts = ; ++ #reset-cells = <1>; + }; + + timer: timer@10008000 { +@@ -486,6 +488,29 @@ + nvmem-cell-names = "calibration-data"; + }; + ++ btif_tx: btif_tx@11000780 { ++ compatible = "mediatek,btif_tx"; ++ reg = <0 0x11000780 0 0x80>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ btif_rx: btif_rx@11000800 { ++ compatible = "mediatek,btif_rx"; ++ reg = <0 0x11000800 0 0x80>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ ++ btif: btif@1100c000 { ++ compatible = "mediatek,btif"; ++ reg = <0 0x1100c000 0 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_BTIF>, <&pericfg CLK_PERI_AP_DMA>; ++ clock-names = "btifc", "apdmac"; ++ status = "okay"; ++ }; ++ + nandc: nfi@1100d000 { + compatible = "mediatek,mt7623-nfc", + "mediatek,mt2701-nfc"; +@@ -660,6 +685,29 @@ + status = "disabled"; + }; + ++ consys: consys@18070000 { ++ compatible = "mediatek,mt7623-consys"; ++ reg = <0 0x18070000 0 0x0200>, /*CONN_MCU_CONFIG_BASE */ ++ <0 0x10001000 0 0x1600>; /*TOPCKGEN_BASE */ ++ clocks = <&infracfg CLK_INFRA_CONNMCU>; ++ clock-names = "consysbus"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_CONN>; ++ interrupts = , /* BGF_EINT */ ++ ; /* WDT_EINT */ ++ resets = <&watchdog MT2701_TOPRGU_CONN_MCU_RST>; ++ reset-names = "connsys"; ++ status="disabled"; ++ }; ++ ++ wifi:wifi@180f0000 { ++ compatible = "mediatek,mt7623-wifi", ++ "mediatek,wifi"; ++ reg = <0 0x180f0000 0 0x005c>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_AP_DMA>; ++ clock-names = "wifi-dma"; ++ }; ++ + hifsys: syscon@1a000000 { + compatible = "mediatek,mt7623-hifsys", + "mediatek,mt2701-hifsys", +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 9ea67ea28a47..0f4c356ebaec 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -57,6 +57,18 @@ + }; + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ consys-reserve-memory { ++ compatible = "mediatek,consys-reserve-memory"; ++ no-map; ++ size = <0 0x100000>; ++ alignment = <0 0x100000>; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +@@ -439,6 +451,24 @@ + ; + }; + }; ++ ++ consys_pins_default: consys_pins_default { ++ adie { ++ pinmux = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ bias-disable; ++ }; ++ }; + }; + + &pwm { +@@ -472,9 +502,239 @@ + default-state = "off"; + }; + }; ++ ++ mt6323regulator: mt6323regulator{ ++ compatible = "mediatek,mt6323-regulator"; ++ ++ mt6323_vproc_reg: buck_vproc{ ++ regulator-name = "vproc"; ++ regulator-min-microvolt = < 700000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-ramp-delay = <12500>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vsys_reg: buck_vsys{ ++ regulator-name = "vsys"; ++ regulator-min-microvolt = <1400000>; ++ regulator-max-microvolt = <2987500>; ++ regulator-ramp-delay = <25000>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vpa_reg: buck_vpa{ ++ regulator-name = "vpa"; ++ regulator-min-microvolt = < 500000>; ++ regulator-max-microvolt = <3650000>; ++ }; ++ ++ mt6323_vtcxo_reg: ldo_vtcxo{ ++ regulator-name = "vtcxo"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-enable-ramp-delay = <90>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vcn28_reg: ldo_vcn28{ ++ regulator-name = "vcn28"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-enable-ramp-delay = <185>; ++ }; ++ ++ mt6323_vcn33_bt_reg: ldo_vcn33_bt{ ++ regulator-name = "vcn33_bt"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3600000>; ++ regulator-enable-ramp-delay = <185>; ++ }; ++ ++ mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{ ++ regulator-name = "vcn33_wifi"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3600000>; ++ regulator-enable-ramp-delay = <185>; ++ }; ++ ++ mt6323_va_reg: ldo_va{ ++ regulator-name = "va"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-enable-ramp-delay = <216>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vcama_reg: ldo_vcama{ ++ regulator-name = "vcama"; ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vio28_reg: ldo_vio28{ ++ regulator-name = "vio28"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-enable-ramp-delay = <216>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vusb_reg: ldo_vusb{ ++ regulator-name = "vusb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <216>; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vmc_reg: ldo_vmc{ ++ regulator-name = "vmc"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <36>; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vmch_reg: ldo_vmch{ ++ regulator-name = "vmch"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <36>; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vemc3v3_reg: ldo_vemc3v3{ ++ regulator-name = "vemc3v3"; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <36>; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vgp1_reg: ldo_vgp1{ ++ regulator-name = "vgp1"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vgp2_reg: ldo_vgp2{ ++ regulator-name = "vgp2"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vgp3_reg: ldo_vgp3{ ++ regulator-name = "vgp3"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vcn18_reg: ldo_vcn18{ ++ regulator-name = "vcn18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vsim1_reg: ldo_vsim1{ ++ regulator-name = "vsim1"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vsim2_reg: ldo_vsim2{ ++ regulator-name = "vsim2"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vrtc_reg: ldo_vrtc{ ++ regulator-name = "vrtc"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vcamaf_reg: ldo_vcamaf{ ++ regulator-name = "vcamaf"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vibr_reg: ldo_vibr{ ++ regulator-name = "vibr"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-enable-ramp-delay = <36>; ++ }; ++ ++ mt6323_vrf18_reg: ldo_vrf18{ ++ regulator-name = "vrf18"; ++ regulator-min-microvolt = <1825000>; ++ regulator-max-microvolt = <1825000>; ++ regulator-enable-ramp-delay = <187>; ++ }; ++ ++ mt6323_vm_reg: ldo_vm{ ++ regulator-name = "vm"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vio18_reg: ldo_vio18{ ++ regulator-name = "vio18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ mt6323_vcamd_reg: ldo_vcamd{ ++ regulator-name = "vcamd"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ ++ mt6323_vcamio_reg: ldo_vcamio{ ++ regulator-name = "vcamio"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-enable-ramp-delay = <216>; ++ }; ++ }; ++ + }; + }; + ++&consys { ++ mediatek,pwrap-regmap = <&pwrap>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&consys_pins_default>; ++ vcn18-supply = <&mt6323_vcn18_reg>; ++ vcn28-supply = <&mt6323_vcn28_reg>; ++ vcn33_bt-supply = <&mt6323_vcn33_bt_reg>; ++ vcn33_wifi-supply = <&mt6323_vcn33_wifi_reg>; ++ status = "okay"; ++}; ++ + &spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins_a>; +@@ -515,3 +775,6 @@ + status = "okay"; + }; + ++&watchdog { ++ status = "okay"; ++}; +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 8136dc7e863d..11ef310bd1c7 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -518,4 +518,5 @@ source "drivers/misc/mic/Kconfig" + source "drivers/misc/genwqe/Kconfig" + source "drivers/misc/echo/Kconfig" + source "drivers/misc/cxl/Kconfig" ++source "drivers/misc/mediatek/Kconfig" + endmenu +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index ad0e64fdba34..c25aa08d17f5 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -74,3 +74,5 @@ OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ + targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o + $(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE + $(call if_changed,objcopy) ++ ++obj-$(CONFIG_MTK_COMBO) += mediatek/ +diff --git a/drivers/misc/mediatek/Kconfig b/drivers/misc/mediatek/Kconfig +new file mode 100644 +index 000000000000..4829a6598c7a +--- /dev/null ++++ b/drivers/misc/mediatek/Kconfig +@@ -0,0 +1,11 @@ ++menu "Mediatek Peripherals " ++ ++config MTK_PLATFORM ++ string "MTK platform name" ++source "drivers/misc/mediatek/btif/Kconfig" ++ ++menu "Modem & Connectivity related configs" ++source "drivers/misc/mediatek/connectivity/Kconfig" ++endmenu ++ ++endmenu # CONN +diff --git a/drivers/misc/mediatek/Makefile b/drivers/misc/mediatek/Makefile +new file mode 100644 +index 000000000000..5e7f06db38f2 +--- /dev/null ++++ b/drivers/misc/mediatek/Makefile +@@ -0,0 +1,19 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++#$(call all-subdir-src-or-makefile) ++subdir-ccflags-y += -Werror ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/ ++ ++obj-$(CONFIG_MTK_COMBO) += connectivity/ ++obj-$(CONFIG_MTK_BTIF) += btif/ +diff --git a/drivers/misc/mediatek/btif/Kconfig b/drivers/misc/mediatek/btif/Kconfig +new file mode 100644 +index 000000000000..908898bd95c3 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/Kconfig +@@ -0,0 +1,4 @@ ++config MTK_BTIF ++ tristate"MediaTek BTIF Driver" ++ help ++ MTK connectivity BTIF driver for A/D die +diff --git a/drivers/misc/mediatek/btif/Makefile b/drivers/misc/mediatek/btif/Makefile +new file mode 100644 +index 000000000000..2be3ab66f426 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/Makefile +@@ -0,0 +1,33 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# BTIF driver for AD DIE ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++ #subdir-ccflags-y can be used in 2.6.34 in the future ++ MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM)) ++ subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include ++ subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/include/mach ++ subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat ++ ++ obj-y += common/ ++ ++# Otherwise we were called directly from the command ++# line; invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/btif/common/Makefile b/drivers/misc/mediatek/btif/common/Makefile +new file mode 100644 +index 000000000000..61e9d4ea9e89 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/Makefile +@@ -0,0 +1,31 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# BTIF driver for AD DIE ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++ ccflags-y += -I$(src)/inc ++ ccflags-y += -I$(src)/plat_inc ++ ++ obj-y += btif.o ++ btif-y := mtk_btif.o mtk_btif_exp.o btif_dma_plat.o btif_plat.o ++ ++# Otherwise we were called directly from the command ++# line; invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/btif/common/btif_dma_plat.c b/drivers/misc/mediatek/btif/common/btif_dma_plat.c +new file mode 100644 +index 000000000000..58be46927953 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/btif_dma_plat.c +@@ -0,0 +1,1436 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF-DMA" ++ ++#include "btif_dma_priv.h" ++ ++#define DMA_USER_ID "btif_driver" ++ ++/************************************Global variable***********************************/ ++ ++static MTK_BTIF_DMA_VFIFO mtk_tx_dma_vfifo = { ++ .vfifo = { ++ .p_vir_addr = NULL, ++ .phy_addr = 0, ++ .vfifo_size = TX_DMA_VFF_SIZE, ++ .thre = DMA_TX_THRE(TX_DMA_VFF_SIZE), ++ }, ++ .wpt = 0, ++ .last_wpt_wrap = 0, ++ .rpt = 0, ++ .last_rpt_wrap = 0, ++}; ++ ++static MTK_BTIF_IRQ_STR mtk_btif_tx_dma_irq = { ++ .name = "mtk btif tx dma irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_DMA_BTIF_TX_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++static MTK_BTIF_DMA_VFIFO mtk_rx_dma_vfifo = { ++ .vfifo = { ++ .p_vir_addr = NULL, ++ .phy_addr = 0, ++ .vfifo_size = RX_DMA_VFF_SIZE, ++ .thre = DMA_RX_THRE(RX_DMA_VFF_SIZE), ++ }, ++ ++ .wpt = 0, ++ .last_wpt_wrap = 0, ++ .rpt = 0, ++ .last_rpt_wrap = 0, ++}; ++ ++static MTK_BTIF_IRQ_STR mtk_btif_rx_dma_irq = { ++ .name = "mtk btif rx dma irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_DMA_BTIF_RX_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++static MTK_DMA_INFO_STR mtk_btif_tx_dma = { ++#ifndef CONFIG_OF ++ .base = AP_DMA_BASE + BTIF_TX_DMA_OFFSET, ++#endif ++ .dir = DMA_DIR_TX, ++ .p_irq = &mtk_btif_tx_dma_irq, ++ .p_vfifo = &(mtk_tx_dma_vfifo.vfifo), ++}; ++ ++static MTK_DMA_INFO_STR mtk_btif_rx_dma = { ++#ifndef CONFIG_OF ++ .base = AP_DMA_BASE + BTIF_RX_DMA_OFFSET, ++#endif ++ .dir = DMA_DIR_RX, ++ .p_irq = &mtk_btif_rx_dma_irq, ++ .p_vfifo = &(mtk_rx_dma_vfifo.vfifo), ++}; ++ ++static spinlock_t g_clk_cg_spinlock; /*dma clock's spinlock */ ++ ++/************************************Function declearation***********************************/ ++static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info); ++static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info); ++static int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_DMA_CTRL ctrl_id); ++static int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_DMA_CTRL ctrl_id); ++static int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++static int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag); ++static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag); ++static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info); ++static int _btif_dma_dump_dbg_reg(void); ++static void hal_btif_tx_dma_vff_set_for_4g(void); ++static void hal_btif_rx_dma_vff_set_for_4g(void); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ier_ctrl ++* DESCRIPTION ++* BTIF Tx DMA's interrupt enable/disable ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* enable [IN] control if tx interrupt enabled or not ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_receive_data ++* DESCRIPTION ++* receive data from btif module in DMA polling mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++static int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ const unsigned int max_len); ++ ++/************************************Function***********************************/ ++#endif ++ ++#ifdef CONFIG_OF ++static void hal_dma_set_default_setting(ENUM_DMA_DIR dma_dir) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = {0, 0, 0}; ++ unsigned int phy_base; ++ ++ if (dma_dir == DMA_DIR_RX) { ++ node = of_find_compatible_node(NULL, NULL, "mediatek,btif_rx"); ++ if (node) { ++ mtk_btif_rx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif_rx_dma.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get rx_dma irq(%d),register base(0x%lx)\n", ++ mtk_btif_rx_dma.p_irq->irq_id, mtk_btif_rx_dma.base); ++ } else { ++ BTIF_ERR_FUNC("get rx_dma device node fail\n"); ++ } ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif_rx_dma.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", ++ mtk_btif_rx_dma.p_irq->irq_flags); ++ } ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { ++ BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", ++ dma_dir); ++ } else { ++ BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", ++ dma_dir, (unsigned int)phy_base); ++ } ++ } else if (dma_dir == DMA_DIR_TX) { ++ node = of_find_compatible_node(NULL, NULL, "mediatek,btif_tx"); ++ if (node) { ++ mtk_btif_tx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif_tx_dma.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get tx_dma irq(%d),register base(0x%lx)\n", ++ mtk_btif_tx_dma.p_irq->irq_id, mtk_btif_tx_dma.base); ++ } else { ++ BTIF_ERR_FUNC("get tx_dma device node fail\n"); ++ } ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif_tx_dma.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", ++ mtk_btif_tx_dma.p_irq->irq_flags); ++ } ++ ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { ++ BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", ++ dma_dir); ++ } else { ++ BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", ++ dma_dir, (unsigned int)phy_base); ++ } ++ } ++ ++} ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_info_get ++* DESCRIPTION ++* get btif tx dma channel's information ++* PARAMETERS ++* dma_dir [IN] DMA's direction ++* RETURNS ++* pointer to btif dma's information structure ++*****************************************************************************/ ++P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = NULL; ++ ++ BTIF_TRC_FUNC(); ++#ifdef CONFIG_OF ++ hal_dma_set_default_setting(dma_dir); ++#endif ++ if (dma_dir == DMA_DIR_RX) ++ /*Rx DMA*/ ++ p_dma_info = &mtk_btif_rx_dma; ++ else if (dma_dir == DMA_DIR_TX) ++ /*Tx DMA*/ ++ p_dma_info = &mtk_btif_tx_dma; ++ else ++ /*print error log*/ ++ BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); ++ spin_lock_init(&g_clk_cg_spinlock); ++ BTIF_TRC_FUNC(); ++ return p_dma_info; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag) ++{ ++/*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/ ++/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ ++ int i_ret = 0; ++ unsigned long irq_flag = 0; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ static atomic_t s_clk_ref = ATOMIC_INIT(0); ++#else ++ static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; ++#endif ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_CTL ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++ if (flag == CLK_OUT_ENABLE) { ++ if (atomic_inc_return(&s_clk_ref) == 1) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); ++ i_ret = clk_enable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++ if (atomic_dec_return(&s_clk_ref) == 0) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif_apdma) calling\n"); ++ clk_disable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ ++#else ++ ++ if (status == flag) { ++ i_ret = 0; ++ BTIF_DBG_FUNC("dma clock already %s\n", ++ CLK_OUT_ENABLE == ++ status ? "enabled" : "disabled"); ++ } else { ++ if (flag == CLK_OUT_ENABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); ++ i_ret = clk_enable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); ++ clk_disable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ } ++#endif ++ ++#else ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++#else ++ ++ status = flag; ++#endif ++ ++ i_ret = 0; ++#endif ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#else ++ ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ BTIF_DBG_FUNC("DMA's clock is %s\n", (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) ? "off" : "on"); ++#endif ++ return i_ret; ++} ++ ++int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int i_ret = 0; ++ unsigned int dat = 0; ++ unsigned long base = p_dma_info->base; ++ unsigned long addr_h = 0; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ if (p_dma_info->dir == DMA_DIR_RX) { ++ /*Rx DMA*/ ++ /*do hardware reset*/ ++ /* BTIF_SET_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ ++ /* BTIF_CLR_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ ++ BTIF_SET_BIT(RX_DMA_RST(base), DMA_WARM_RST); ++ do { ++ dat = BTIF_READ32(RX_DMA_EN(base)); ++ } while (0x01 & dat); ++ /*write vfifo base address to VFF_ADDR*/ ++ btif_reg_sync_writel(p_vfifo->phy_addr, RX_DMA_VFF_ADDR(base)); ++ if (enable_4G()) ++ hal_btif_rx_dma_vff_set_for_4g(); ++ else { ++ addr_h = p_vfifo->phy_addr >> 16; ++ addr_h = addr_h >> 16; ++ btif_reg_sync_writel(addr_h, RX_DMA_VFF_ADDR_H(base)); ++ } ++ /*write vfifo length to VFF_LEN*/ ++ btif_reg_sync_writel(p_vfifo->vfifo_size, RX_DMA_VFF_LEN(base)); ++ /*write wpt to VFF_WPT*/ ++ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, ++ RX_DMA_VFF_WPT(base)); ++ btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, ++ RX_DMA_VFF_RPT(base)); ++ /*write vff_thre to VFF_THRESHOLD*/ ++ btif_reg_sync_writel(p_vfifo->thre, RX_DMA_VFF_THRE(base)); ++ /*clear Rx DMA's interrupt status*/ ++ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), ++ RX_DMA_INT_DONE | RX_DMA_INT_THRE); ++ ++ /*enable Rx IER by default*/ ++ btif_rx_dma_ier_ctrl(p_dma_info, true); ++ } else { ++/*Tx DMA*/ ++/*do hardware reset*/ ++/* BTIF_SET_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ ++/* BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ ++ BTIF_SET_BIT(TX_DMA_RST(base), DMA_WARM_RST); ++ do { ++ dat = BTIF_READ32(TX_DMA_EN(base)); ++ } while (0x01 & dat); ++/*write vfifo base address to VFF_ADDR*/ ++ btif_reg_sync_writel(p_vfifo->phy_addr, TX_DMA_VFF_ADDR(base)); ++ if (enable_4G()) ++ hal_btif_tx_dma_vff_set_for_4g(); ++ else { ++ addr_h = p_vfifo->phy_addr >> 16; ++ addr_h = addr_h >> 16; ++ btif_reg_sync_writel(addr_h, TX_DMA_VFF_ADDR_H(base)); ++ } ++/*write vfifo length to VFF_LEN*/ ++ btif_reg_sync_writel(p_vfifo->vfifo_size, TX_DMA_VFF_LEN(base)); ++/*write wpt to VFF_WPT*/ ++ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, ++ TX_DMA_VFF_WPT(base)); ++ btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, ++ TX_DMA_VFF_RPT(base)); ++/*write vff_thre to VFF_THRESHOLD*/ ++ btif_reg_sync_writel(p_vfifo->thre, TX_DMA_VFF_THRE(base)); ++ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); ++ ++ hal_btif_dma_ier_ctrl(p_dma_info, false); ++ } ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ctrl ++* DESCRIPTION ++* enable/disable Tx DMA channel ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* ctrl_id [IN] enable/disable ID ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ ENUM_DMA_DIR dir = p_dma_info->dir; ++ ++ if (dir == DMA_DIR_RX) ++ i_ret = btif_rx_dma_ctrl(p_dma_info, ctrl_id); ++ else if (dir == DMA_DIR_TX) ++ i_ret = btif_tx_dma_ctrl(p_dma_info, ctrl_id); ++ else { ++ /*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid dma ctrl id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ return i_ret; ++} ++ ++int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ dma_rx_buf_write rx_cb) ++{ ++ if (p_dma_info->rx_cb != NULL) { ++ BTIF_DBG_FUNC ++ ("rx_cb already registered, replace (0x%p) with (0x%p)\n", ++ p_dma_info->rx_cb, rx_cb); ++ } ++ p_dma_info->rx_cb = rx_cb; ++ return 0; ++} ++ ++int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int dat; ++ ++ BTIF_TRC_FUNC(); ++ if (ctrl_id == DMA_CTRL_DISABLE) { ++ /*if write 0 to EN bit, DMA will be stopped imediately*/ ++ /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ ++ /*BTIF_CLR_BIT(TX_DMA_EN(base), DMA_EN_BIT);*/ ++ BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT); ++ do { ++ dat = BTIF_READ32(TX_DMA_STOP(base)); ++ } while (0x1 & dat); ++ BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n", ++ BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base))); ++ i_ret = 0; ++ } else if (ctrl_id == DMA_CTRL_ENABLE) { ++ BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT); ++ BTIF_DBG_FUNC("BTIF Tx DMA enabled\n"); ++ i_ret = 0; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int dat; ++ ++ BTIF_TRC_FUNC(); ++ ++ if (ctrl_id == DMA_CTRL_DISABLE) { ++ /*if write 0 to EN bit, DMA will be stopped imediately*/ ++ /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ ++ /*BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT);*/ ++ BTIF_SET_BIT(RX_DMA_STOP(base), DMA_STOP_BIT); ++ do { ++ dat = BTIF_READ32(RX_DMA_STOP(base)); ++ } while (0x1 & dat); ++ BTIF_DBG_FUNC("BTIF Rx DMA disabled,EN(0x%x),STOP(0x%x)\n", ++ BTIF_READ32(RX_DMA_EN(base)), BTIF_READ32(RX_DMA_STOP(base))); ++ i_ret = 0; ++ } else if (ctrl_id == DMA_CTRL_ENABLE) { ++ BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT); ++ BTIF_DBG_FUNC("BTIF Rx DMA enabled\n"); ++ i_ret = 0; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_vfifo_reset ++* DESCRIPTION ++* reset tx virtual fifo information, except memory information ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ unsigned int i_ret = -1; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ BTIF_TRC_FUNC(); ++ p_mtk_dma_vfifo->rpt = 0; ++ p_mtk_dma_vfifo->last_rpt_wrap = 0; ++ p_mtk_dma_vfifo->wpt = 0; ++ p_mtk_dma_vfifo->last_wpt_wrap = 0; ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ier_ctrl ++* DESCRIPTION ++* BTIF Tx DMA's interrupt enable/disable ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ ENUM_DMA_DIR dir = p_dma_info->dir; ++ ++ if (dir == DMA_DIR_RX) { ++ i_ret = btif_rx_dma_ier_ctrl(p_dma_info, en); ++ } else if (dir == DMA_DIR_TX) { ++ i_ret = btif_tx_dma_ier_ctrl(p_dma_info, en); ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA dma dir (%d)\n", dir); ++ i_ret = ERR_INVALID_PAR; ++ } ++ ++ return i_ret; ++} ++ ++int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++ BTIF_TRC_FUNC(); ++ if (!en) { ++ BTIF_CLR_BIT(RX_DMA_INT_EN(base), ++ (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); ++ } else { ++ BTIF_SET_BIT(RX_DMA_INT_EN(base), ++ (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); ++ } ++ i_ret = 0; ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++ BTIF_TRC_FUNC(); ++ if (!en) ++ BTIF_CLR_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); ++ else ++ BTIF_SET_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); ++ i_ret = 0; ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int tx_irq_done = 0; ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++/*if we enable this clock reference couner, just return , because when enter IRQ handler, DMA's clock will be opened*/ ++ tx_irq_done = 1; ++#else ++ unsigned long flag = 0; ++ unsigned long base = p_dma_info->base; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++ tx_irq_done = ((BTIF_READ32(TX_DMA_INT_FLAG(base)) & TX_DMA_INT_FLAG_MASK) == 0) ? 1 : 0; ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++#endif ++ return tx_irq_done; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++#define MAX_CONTINIOUS_TIMES 512 ++ unsigned int i_ret = -1; ++ unsigned int valid_size = 0; ++ unsigned int vff_len = 0; ++ unsigned int left_len = 0; ++ unsigned long base = p_dma_info->base; ++ static int flush_irq_counter; ++ static struct timeval start_timer; ++ static struct timeval end_timer; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ BTIF_ERR_FUNC ++ ("%s: clock is off before irq status clear done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*check if Tx VFF Left Size equal to VFIFO size or not*/ ++ vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base)); ++ valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ if (flush_irq_counter == 0) ++ do_gettimeofday(&start_timer); ++ if ((valid_size > 0) && (valid_size < 8)) { ++ i_ret = _tx_dma_flush(p_dma_info); ++ flush_irq_counter++; ++ if (flush_irq_counter >= MAX_CONTINIOUS_TIMES) { ++ do_gettimeofday(&end_timer); ++/* ++ * when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while ++ * we assume that btif cannot send data for a long time ++ * in order not to generate interrupt continiously, which may effect system's performance. ++ * we clear tx flag and disable btif tx interrupt ++ */ ++/*clear interrupt flag*/ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), ++ TX_DMA_INT_FLAG_MASK); ++/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ ++ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); ++ BTIF_ERR_FUNC ++ ("**********************ERROR, ERROR, ERROR**************************\n"); ++ BTIF_ERR_FUNC ++ ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n", ++ MAX_CONTINIOUS_TIMES, start_timer.tv_sec, ++ start_timer.tv_usec, end_timer.tv_usec, ++ end_timer.tv_usec); ++ } ++ } else if (vff_len == left_len) { ++ flush_irq_counter = 0; ++/*clear interrupt flag*/ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); ++/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ ++ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); ++ } else { ++#if 0 ++ BTIF_ERR_FUNC ++ ("**********************WARNING**************************\n"); ++ BTIF_ERR_FUNC("invalid irq condition, dump register\n"); ++ hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL); ++#endif ++ BTIF_DBG_FUNC ++ ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n", ++ vff_len, valid_size, left_len); ++ } ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_send_data ++* DESCRIPTION ++* send data through btif in DMA mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, ++ const unsigned char *p_buf, const unsigned int buf_len) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ unsigned int len_to_send = buf_len; ++ unsigned int ava_len = 0; ++ unsigned int wpt = 0; ++ unsigned int last_wpt_wrap = 0; ++ unsigned int vff_size = 0; ++ unsigned char *p_data = (unsigned char *)p_buf; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ BTIF_TRC_FUNC(); ++ if ((p_buf == NULL) || (buf_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid parameters, p_buf:0x%p, buf_len:%d\n", ++ p_buf, buf_len); ++ return i_ret; ++ } ++/*check if tx dma in flush operation? if yes, should wait until DMA finish flush operation*/ ++/*currently uplayer logic will make sure this pre-condition*/ ++/*disable Tx IER, in case Tx irq happens, flush bit may be set in irq handler*/ ++ btif_tx_dma_ier_ctrl(p_dma_info, false); ++ ++ vff_size = p_mtk_vfifo->vfifo.vfifo_size; ++ ava_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_MASK; ++ last_wpt_wrap = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_WRAP; ++ ++/* ++ * copy data to vFIFO, Note: ava_len should always large than buf_len, ++ * otherwise common logic layer will not call hal_dma_send_data ++ */ ++ if (buf_len > ava_len) { ++ BTIF_ERR_FUNC ++ ("length to send:(%d) < length available(%d), abnormal!!!---!!!\n", ++ buf_len, ava_len); ++ WARN_ON(buf_len > ava_len); /* this will cause kernel panic */ ++ } ++ ++ len_to_send = buf_len < ava_len ? buf_len : ava_len; ++ if (len_to_send + wpt >= vff_size) { ++ unsigned int tail_len = vff_size - wpt; ++ ++ memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, tail_len); ++ p_data += tail_len; ++ memcpy(p_mtk_vfifo->vfifo.p_vir_addr, ++ p_data, len_to_send - tail_len); ++/*make sure all data write to memory area tx vfifo locates*/ ++ mb(); ++ ++/*calculate WPT*/ ++ wpt = wpt + len_to_send - vff_size; ++ last_wpt_wrap ^= DMA_WPT_WRAP; ++ } else { ++ memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), ++ p_data, len_to_send); ++/*make sure all data write to memory area tx vfifo locates*/ ++ mb(); ++ ++/*calculate WPT*/ ++ wpt += len_to_send; ++ } ++ p_mtk_vfifo->wpt = wpt; ++ p_mtk_vfifo->last_wpt_wrap = last_wpt_wrap; ++ ++/*make sure tx dma is allowed(tx flush bit is not set) to use before update WPT*/ ++ if (hal_dma_is_tx_allow(p_dma_info)) { ++ /*make sure tx dma enabled*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ ++ /*update WTP to Tx DMA controller's control register*/ ++ btif_reg_sync_writel(wpt | last_wpt_wrap, TX_DMA_VFF_WPT(base)); ++ ++ if ((BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) < 8) && ++ (BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) > 0)) { ++ /* ++ * 0 < valid size in Tx vFIFO < 8 && TX Flush is not in process? ++ * if yes, set flush bit to DMA ++ */ ++ _tx_dma_flush(p_dma_info); ++ } ++ i_ret = len_to_send; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("Tx DMA flush operation is in process, this case should never happen,", ++ "please check if tx operation is allowed before call this API\n"); ++/*if flush operation is in process , we will return 0*/ ++ i_ret = 0; ++ } ++ ++/*Enable Tx IER*/ ++ btif_tx_dma_ier_ctrl(p_dma_info, true); ++ ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ bool b_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); ++ unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info); ++ ++/* ++ * only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0, ++ * we can identify tx operation finished ++ * confirmed with DE. ++ */ ++ if ((valid_size == 0) && (inter_size == 0) && (tx_done == 1)) { ++ b_ret = true; ++ BTIF_DBG_FUNC("DMA tx finished.\n"); ++ } else { ++ BTIF_DBG_FUNC ++ ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n", ++ valid_size, inter_size, tx_done); ++ b_ret = false; ++ } ++ ++ return b_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_get_ava_room ++* DESCRIPTION ++* get tx available room ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* available room size ++*****************************************************************************/ ++int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++/*read vFIFO's left size*/ ++ i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret); ++ if (i_ret == 0) ++ BTIF_INFO_FUNC("DMA tx vfifo is full.\n"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_allow ++* DESCRIPTION ++* is tx operation allowed by DMA ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) ++#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) ++ ++ bool b_ret = false; ++ unsigned int wait_us = 8 / MIN_TX_MB; /*only ava length */ ++/*see if flush operation is in process*/ ++ b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; ++ if (!b_ret) { ++ usleep_range(wait_us, 2 * wait_us); ++ b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; ++ } ++ if (!b_ret) ++ BTIF_WARN_FUNC("btif tx dma is not allowed\n"); ++/*after Tx flush operation finished, HW will set DMA_EN back to 0 and stop DMA*/ ++ return b_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_rx_dma_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++ int i_ret = -1; ++ unsigned int valid_len = 0; ++ unsigned int wpt_wrap = 0; ++ unsigned int rpt_wrap = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int tail_len = 0; ++ unsigned int real_len = 0; ++ unsigned long base = p_dma_info->base; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ dma_rx_buf_write rx_cb = p_dma_info->rx_cb; ++ unsigned char *p_vff_buf = NULL; ++ unsigned char *vff_base = p_vfifo->p_vir_addr; ++ unsigned int vff_size = p_vfifo->vfifo_size; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*disable DMA Rx IER*/ ++ hal_btif_dma_ier_ctrl(p_dma_info, false); ++ ++/*clear Rx DMA's interrupt status*/ ++ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); ++ ++ valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ if ((valid_len == 0) && (rpt == wpt)) { ++ BTIF_DBG_FUNC ++ ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n", ++ rpt, wpt); ++ } ++ ++ i_ret = 0; ++ ++ while ((valid_len > 0) || (rpt != wpt)) { ++ rpt_wrap = rpt & DMA_RPT_WRAP; ++ wpt_wrap = wpt & DMA_WPT_WRAP; ++ rpt &= DMA_RPT_MASK; ++ wpt &= DMA_WPT_MASK; ++ ++/*calcaute length of available data in vFIFO*/ ++ if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) ++ real_len = wpt + vff_size - rpt; ++ else ++ real_len = wpt - rpt; ++ ++ if (rx_cb != NULL) { ++ tail_len = vff_size - rpt; ++ p_vff_buf = vff_base + rpt; ++ if (tail_len >= real_len) { ++ (*rx_cb) (p_dma_info, p_vff_buf, real_len); ++ } else { ++ (*rx_cb) (p_dma_info, p_vff_buf, tail_len); ++ p_vff_buf = vff_base; ++ (*rx_cb) (p_dma_info, p_vff_buf, real_len - ++ tail_len); ++ } ++ i_ret += real_len; ++ } else ++ BTIF_ERR_FUNC("no rx_cb found, please check your init process\n"); ++ mb(); ++ rpt += real_len; ++ if (rpt >= vff_size) { ++ /*read wrap bit should be revert*/ ++ rpt_wrap ^= DMA_RPT_WRAP; ++ rpt %= vff_size; ++ } ++ rpt |= rpt_wrap; ++/*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/ ++ p_mtk_vfifo->wpt = wpt; ++ p_mtk_vfifo->last_wpt_wrap = wpt_wrap; ++ ++ p_mtk_vfifo->rpt = rpt; ++ p_mtk_vfifo->last_rpt_wrap = rpt_wrap; ++ ++/*update rpt information to DMA controller*/ ++ btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base)); ++ ++/*get vff valid size again and check if rx data is processed completely*/ ++ valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ } ++ ++/*enable DMA Rx IER*/ ++ hal_btif_dma_ier_ctrl(p_dma_info, true); ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ ++ return i_ret; ++} ++ ++static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int int_flag = 0; ++ unsigned int enable = 0; ++ unsigned int stop = 0; ++ unsigned int flush = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int int_buf = 0; ++ unsigned int valid_size = 0; ++ /*unsigned long irq_flag = 0;*/ ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ int_flag = BTIF_READ32(TX_DMA_INT_FLAG(base)); ++ enable = BTIF_READ32(TX_DMA_EN(base)); ++ stop = BTIF_READ32(TX_DMA_STOP(base)); ++ flush = BTIF_READ32(TX_DMA_FLUSH(base)); ++ wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)); ++ rpt = BTIF_READ32(TX_DMA_VFF_RPT(base)); ++ int_buf = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); ++ valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ ++ BTIF_INFO_FUNC("DMA's clock is on\n"); ++ BTIF_INFO_FUNC("Tx DMA's base address: 0x%lx\n", base); ++ ++ if (flag == REG_TX_DMA_ALL) { ++ BTIF_INFO_FUNC("TX_EN(:0x%x\n", enable); ++ BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); ++ BTIF_INFO_FUNC("TX_STOP:0x%x\n", stop); ++ BTIF_INFO_FUNC("TX_FLUSH:0x%x\n", flush); ++ BTIF_INFO_FUNC("TX_WPT:0x%x\n", wpt); ++ BTIF_INFO_FUNC("TX_RPT:0x%x\n", rpt); ++ BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); ++ BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); ++ BTIF_INFO_FUNC("INT_EN:0x%x\n", ++ BTIF_READ32(TX_DMA_INT_EN(base))); ++ BTIF_INFO_FUNC("TX_RST:0x%x\n", BTIF_READ32(TX_DMA_RST(base))); ++ BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_ADDR(base))); ++ BTIF_INFO_FUNC("VFF_LEN:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_LEN(base))); ++ BTIF_INFO_FUNC("TX_THRE:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_THRE(base))); ++ BTIF_INFO_FUNC("W_INT_BUF_SIZE:0x%x\n", ++ BTIF_READ32(TX_DMA_W_INT_BUF_SIZE(base))); ++ BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base))); ++ BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", ++ BTIF_READ32(TX_DMA_DEBUG_STATUS(base))); ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("unknown flag:%d\n", flag); ++ } ++ BTIF_INFO_FUNC("tx dma %s\n", (enable & DMA_EN_BIT) && ++ (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); ++ BTIF_INFO_FUNC("data in tx dma is %s sent by HW\n", ++ ((wpt == rpt) && ++ (int_buf == 0)) ? "completely" : "not completely"); ++ ++ return i_ret; ++} ++ ++static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int int_flag = 0; ++ unsigned int enable = 0; ++ unsigned int stop = 0; ++ unsigned int flush = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int int_buf = 0; ++ unsigned int valid_size = 0; ++ /*unsigned long irq_flag = 0;*/ ++#if defined(CONFIG_MTK_CLKMGR) ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ BTIF_INFO_FUNC("dump DMA status register\n"); ++ _btif_dma_dump_dbg_reg(); ++ ++ int_flag = BTIF_READ32(RX_DMA_INT_FLAG(base)); ++ enable = BTIF_READ32(RX_DMA_EN(base)); ++ stop = BTIF_READ32(RX_DMA_STOP(base)); ++ flush = BTIF_READ32(RX_DMA_FLUSH(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ int_buf = BTIF_READ32(RX_DMA_INT_BUF_SIZE(base)); ++ valid_size = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ ++ BTIF_INFO_FUNC("DMA's clock is on\n"); ++ BTIF_INFO_FUNC("Rx DMA's base address: 0x%lx\n", base); ++ ++ if (flag == REG_RX_DMA_ALL) { ++ BTIF_INFO_FUNC("RX_EN(:0x%x\n", enable); ++ BTIF_INFO_FUNC("RX_STOP:0x%x\n", stop); ++ BTIF_INFO_FUNC("RX_FLUSH:0x%x\n", flush); ++ BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); ++ BTIF_INFO_FUNC("RX_WPT:0x%x\n", wpt); ++ BTIF_INFO_FUNC("RX_RPT:0x%x\n", rpt); ++ BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); ++ BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); ++ BTIF_INFO_FUNC("INT_EN:0x%x\n", ++ BTIF_READ32(RX_DMA_INT_EN(base))); ++ BTIF_INFO_FUNC("RX_RST:0x%x\n", BTIF_READ32(RX_DMA_RST(base))); ++ BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_ADDR(base))); ++ BTIF_INFO_FUNC("VFF_LEN:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_LEN(base))); ++ BTIF_INFO_FUNC("RX_THRE:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_THRE(base))); ++ BTIF_INFO_FUNC("RX_FLOW_CTRL_THRE:0x%x\n", ++ BTIF_READ32(RX_DMA_FLOW_CTRL_THRE(base))); ++ BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_LEFT_SIZE(base))); ++ BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", ++ BTIF_READ32(RX_DMA_DEBUG_STATUS(base))); ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("unknown flag:%d\n", flag); ++ } ++ BTIF_INFO_FUNC("rx dma %s\n", (enable & DMA_EN_BIT) && ++ (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); ++ BTIF_INFO_FUNC("data in rx dma is %s by driver\n", ++ ((wpt == rpt) && ++ (int_buf == 0)) ? "received" : "not received"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag) ++{ ++ unsigned int i_ret = -1; ++ ++ if (p_dma_info->dir == DMA_DIR_TX) ++ i_ret = hal_tx_dma_dump_reg(p_dma_info, flag); ++ else if (p_dma_info->dir == DMA_DIR_RX) ++ i_ret = hal_rx_dma_dump_reg(p_dma_info, flag); ++ else ++ BTIF_WARN_FUNC("unknown dir:%d\n", p_dma_info->dir); ++ ++ return i_ret; ++} ++ ++static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int stop = BTIF_READ32(TX_DMA_STOP(base)); ++ ++/*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/ ++ if ((stop && DMA_STOP_BIT) != 0) ++ BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n"); ++ else { ++ BTIF_DBG_FUNC("flush tx dma\n"); ++ BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT); ++ i_ret = 0; ++ } ++ return i_ret; ++} ++ ++static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ bool b_ret = true; ++ unsigned long base = p_dma_info->base; ++ ++/*see if flush operation is in process*/ ++ b_ret = ((DMA_FLUSH_BIT & BTIF_READ32(TX_DMA_FLUSH(base))) != 0) ? true : false; ++ ++ return b_ret; ++} ++ ++int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("op id: %d\n", opid); ++ switch (opid) { ++ case BTIF_PM_DPIDLE_EN: ++ i_ret = 0; ++ break; ++ case BTIF_PM_DPIDLE_DIS: ++ i_ret = 0; ++ break; ++ case BTIF_PM_SUSPEND: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESUME: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESTORE_NOIRQ:{ ++ unsigned int flag = 0; ++ P_MTK_BTIF_IRQ_STR p_irq = p_dma_info->p_irq; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING; ++ else ++ flag = IRQF_TRIGGER_FALLING; /*make this as default type */ ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ default: ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ } ++#endif ++/* irq_set_irq_type(p_irq->irq_id, flag); */ ++ i_ret = 0; ++ } ++ i_ret = 0; ++ break; ++ default: ++ i_ret = ERR_INVALID_PAR; ++ break; ++ } ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_receive_data ++* DESCRIPTION ++* receive data from btif module in DMA polling mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++ unsigned int i_ret = -1; ++ ++ return i_ret; ++} ++#endif ++ ++int _btif_dma_dump_dbg_reg(void) ++{ ++#if 0 ++ static MTK_BTIF_DMA_REG_DMP_DBG g_dma_dbg_regs[] = { ++ {0x10201180, 0x0}, ++ {0x10201184, 0x0}, ++ {0x10201188, 0x0}, ++ {0x1020118C, 0x0}, ++ {0x10201190, 0x0}, ++ {0x1000320C, 0x0}, ++ {0x10003210, 0x0}, ++ {0x10003214, 0x0}, ++ }; ++ ++ int i = 0; ++ char *addr1 = NULL; ++ char *addr2 = NULL; ++ ++ int array_num = ARRAY_SIZE(g_dma_dbg_regs) ++ ++ addr1 = ioremap(g_dma_dbg_regs[0].reg_addr, 0x20); ++ if (addr1) { ++ for (i = 0; i < 5; i++) ++ g_dma_dbg_regs[i].reg_val = *(volatile unsigned int*)(addr1 + i*4); ++ iounmap(addr1); ++ } ++ ++ addr2 = ioremap(g_dma_dbg_regs[5].reg_addr, 0x10); ++ if (addr2) { ++ g_dma_dbg_regs[5].reg_val = *(volatile unsigned int*)(addr2); ++ g_dma_dbg_regs[6].reg_val = *(volatile unsigned int*)(addr2+4); ++ g_dma_dbg_regs[7].reg_val = *(volatile unsigned int*)(addr2+8); ++ iounmap(addr2); ++ } ++ ++ for (i = 0; i < array_num; i++) ++ BTIF_INFO_FUNC("-<0x%lx, 0x%08x>\n", g_dma_dbg_regs[i].reg_addr, g_dma_dbg_regs[i].reg_val); ++#endif ++ return 0; ++} ++ ++static void hal_btif_tx_dma_vff_set_for_4g(void) ++{ ++ BTIF_DBG_FUNC("Set btif tx_vff_addr bit29\n"); ++ BTIF_SET_BIT(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), DMA_VFF_BIT29_OFFSET); ++ BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), ++ BTIF_READ32(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base))); ++} ++static void hal_btif_rx_dma_vff_set_for_4g(void) ++{ ++ BTIF_DBG_FUNC("Set btif rx_vff_addr bit29\n"); ++ BTIF_SET_BIT(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), DMA_VFF_BIT29_OFFSET); ++ BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), ++ BTIF_READ32(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base))); ++} ++ +diff --git a/drivers/misc/mediatek/btif/common/btif_plat.c b/drivers/misc/mediatek/btif/common/btif_plat.c +new file mode 100644 +index 000000000000..baf2a0b6d0c8 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/btif_plat.c +@@ -0,0 +1,1396 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF" ++ ++#define NEW_TX_HANDLING_SUPPORT 1 ++ ++#include "btif_pub.h" ++#include "btif_priv.h" ++ ++#define BTIF_USER_ID "btif_driver" ++ ++static spinlock_t g_clk_cg_spinlock; /*BTIF clock's spinlock */ ++ ++/*-----------------------------BTIF Module Clock and Power Control Defination------------------*/ ++ ++MTK_BTIF_IRQ_STR mtk_btif_irq = { ++ .name = "mtk btif irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_BTIF_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++/* ++ * will call clock manager's API export by WCP to control BTIF's clock, ++ * but we may need to access these registers in case of btif clock control logic is wrong in clock manager ++ */ ++ ++MTK_BTIF_INFO_STR mtk_btif = { ++#ifndef CONFIG_OF ++ .base = MTK_BTIF_REG_BASE, ++#endif ++ .p_irq = &mtk_btif_irq, ++ .tx_fifo_size = BTIF_TX_FIFO_SIZE, ++ .rx_fifo_size = BTIF_RX_FIFO_SIZE, ++ .tx_tri_lvl = BTIF_TX_FIFO_THRE, ++ .rx_tri_lvl = BTIF_RX_FIFO_THRE, ++ .rx_data_len = 0, ++ .p_tx_fifo = NULL, ++}; ++#if !(NEW_TX_HANDLING_SUPPORT) ++static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); ++#endif ++ ++static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ const unsigned int max_len); ++static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_ier_ctrl ++* DESCRIPTION ++* BTIF Rx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if rx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_ier_ctrl ++* DESCRIPTION ++* BTIF Tx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++static int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* _btif_receive_data ++* DESCRIPTION ++* receive data from btif module in FIFO polling mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++static int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len); ++static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count); ++#endif ++ ++static int btif_dump_array(char *string, char *p_buf, int len) ++{ ++ unsigned int idx = 0; ++ unsigned char str[30]; ++ unsigned char *p_str; ++ ++ pr_debug("========dump %s start ========\n", string, len); ++ p_str = &str[0]; ++ for (idx = 0; idx < len; idx++, p_buf++) { ++ sprintf(p_str, "%02x ", *p_buf); ++ p_str += 3; ++ if (7 == (idx % 8)) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ p_str = &str[0]; ++ } ++ } ++ if (len % 8) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ } ++ pr_debug("========dump %s end========\n", string); ++ return 0; ++} ++ ++#if NEW_TX_HANDLING_SUPPORT ++static int _btif_tx_fifo_init(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = -1; ++ ++ spin_lock_init(&(p_btif_info->tx_fifo_spinlock)); ++ ++ if (p_btif_info->p_tx_fifo == NULL) { ++ p_btif_info->p_tx_fifo = kzalloc(sizeof(struct kfifo), ++ GFP_ATOMIC); ++ if (p_btif_info->p_tx_fifo == NULL) { ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); ++ goto ret; ++ } ++ ++ i_ret = kfifo_alloc(p_btif_info->p_tx_fifo, ++ BTIF_HAL_TX_FIFO_SIZE, GFP_ATOMIC); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); ++ i_ret = -ENOMEM; ++ goto ret; ++ } ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC ++ ("p_btif_info->p_tx_fifo is already init p_btif_info->p_tx_fifo(0x%p)\n", ++ p_btif_info->p_tx_fifo); ++ i_ret = 0; ++ } ++ret: ++ return i_ret; ++} ++ ++static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = 0; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag); ++ if (p_btif_info->p_tx_fifo == NULL) ++ i_ret = 0; ++ else ++ i_ret = kfifo_avail(p_btif_info->p_tx_fifo); ++ spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("tx kfifo:0x%p, available room:%d\n", p_btif_info->p_tx_fifo, i_ret); ++ return i_ret; ++} ++ ++static int _btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = 0; ++ ++ if (p_btif_info->p_tx_fifo != NULL) ++ kfifo_reset(p_btif_info->p_tx_fifo); ++ return i_ret; ++} ++ ++#endif ++ ++#ifdef CONFIG_OF ++static void _btif_set_default_setting(void) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = {0, 0, 0}; ++ unsigned int phy_base; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,btif"); ++ if (node) { ++ mtk_btif.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get btif irq(%d),register base(0x%lx)\n", ++ mtk_btif.p_irq->irq_id, mtk_btif.base); ++ } else { ++ BTIF_ERR_FUNC("get btif device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", mtk_btif.p_irq->irq_flags); ++ } ++ ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) ++ BTIF_ERR_FUNC("get register phy base from DTS fail\n"); ++ else ++ BTIF_INFO_FUNC("get register phy base(0x%x)\n", (unsigned int)phy_base); ++} ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_info_get ++* DESCRIPTION ++* get btif's information included base address , irq related information ++* PARAMETERS ++* RETURNS ++* BTIF's information ++*****************************************************************************/ ++P_MTK_BTIF_INFO_STR hal_btif_info_get(void) ++{ ++#if NEW_TX_HANDLING_SUPPORT ++ int i_ret = 0; ++/*tx fifo and fifo lock init*/ ++ i_ret = _btif_tx_fifo_init(&mtk_btif); ++ if (i_ret == 0) ++ BTIF_INFO_FUNC("_btif_tx_fifo_init succeed\n"); ++ else ++ BTIF_ERR_FUNC("_btif_tx_fifo_init failed, i_ret:%d\n", i_ret); ++ ++#endif ++ ++#ifdef CONFIG_OF ++ _btif_set_default_setting(); ++#endif ++ ++ spin_lock_init(&g_clk_cg_spinlock); ++ ++ return &mtk_btif; ++} ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_get_and_prepare ++* DESCRIPTION ++* get clock from device tree and prepare for enable/disable control ++* PARAMETERS ++* pdev device pointer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++#if !defined(CONFIG_MTK_CLKMGR) ++int hal_btif_clk_get_and_prepare(struct platform_device *pdev) ++{ ++ int i_ret = -1; ++ ++ clk_btif = devm_clk_get(&pdev->dev, "btifc"); ++ if (IS_ERR(clk_btif)) { ++ BTIF_ERR_FUNC("[CCF]cannot get clk_btif clock.\n"); ++ return PTR_ERR(clk_btif); ++ } ++ BTIF_ERR_FUNC("[CCF]clk_btif=%p\n", clk_btif); ++ clk_btif_apdma = devm_clk_get(&pdev->dev, "apdmac"); ++ if (IS_ERR(clk_btif_apdma)) { ++ BTIF_ERR_FUNC("[CCF]cannot get clk_btif_apdma clock.\n"); ++ return PTR_ERR(clk_btif_apdma); ++ } ++ BTIF_ERR_FUNC("[CCF]clk_btif_apdma=%p\n", clk_btif_apdma); ++ ++ i_ret = clk_prepare(clk_btif); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("clk_prepare clk_btif failed! ret:%d\n", i_ret); ++ return i_ret; ++ } ++ ++ i_ret = clk_prepare(clk_btif_apdma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("clk_prepare clk_btif_apdma failed! ret:%d\n", i_ret); ++ return i_ret; ++ } ++ return i_ret; ++} ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_unprepare ++* DESCRIPTION ++* unprepare btif clock and apdma clock ++* PARAMETERS ++* none ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_unprepare(void) ++{ ++ clk_unprepare(clk_btif); ++ clk_unprepare(clk_btif_apdma); ++ return 0; ++} ++#endif ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of BTIF module ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag) ++{ ++/*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/ ++/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ ++ int i_ret = 0; ++ unsigned long irq_flag = 0; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ static atomic_t s_clk_ref = ATOMIC_INIT(0); ++#else ++ static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; ++#endif ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_CTL ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++ if (flag == CLK_OUT_ENABLE) { ++ if (atomic_inc_return(&s_clk_ref) == 1) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); ++ i_ret = clk_enable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++ if (atomic_dec_return(&s_clk_ref) == 0) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); ++ clk_disable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ ++#else ++ ++ if (status == flag) { ++ i_ret = 0; ++ BTIF_DBG_FUNC("btif clock already %s\n", ++ CLK_OUT_ENABLE == ++ status ? "enabled" : "disabled"); ++ } else { ++ if (flag == CLK_OUT_ENABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); ++ i_ret = clk_enable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); ++ clk_disable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ } ++#endif ++ ++#else ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++#else ++ ++ status = flag; ++#endif ++ ++ i_ret = 0; ++#endif ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#else ++ ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ BTIF_DBG_FUNC("BTIF's clock is %s\n", (clock_is_on(MTK_BTIF_CG_BIT) == 0) ? "off" : "on"); ++#endif ++ return i_ret; ++} ++ ++static int btif_new_handshake_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool enable) ++{ ++ unsigned long base = p_btif->base; ++ ++ if (enable == true) ++ BTIF_SET_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); ++ else ++ BTIF_CLR_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); ++ return true; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_hw_init ++* DESCRIPTION ++* BTIF hardware init ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ _btif_tx_fifo_reset(p_btif); ++#endif ++ ++/*set to normal mode*/ ++ btif_reg_sync_writel(BTIF_FAKELCR_NORMAL_MODE, BTIF_FAKELCR(base)); ++/*set to newhandshake mode*/ ++ btif_new_handshake_ctrl(p_btif, true); ++/*No need to access: enable sleep mode*/ ++/*No need to access: set Rx timeout count*/ ++/*set Tx threshold*/ ++/*set Rx threshold*/ ++/*disable internal loopback test*/ ++ ++/*set Rx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++/*clear Rx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++/*set Tx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++/*clear Tx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++ btif_reg_sync_writel(BTIF_TRI_LVL_TX(p_btif->tx_tri_lvl) ++ | BTIF_TRI_LVL_RX(p_btif->rx_tri_lvl) ++ | BTIF_TRI_LOOP_DIS, BTIF_TRI_LVL(base)); ++ hal_btif_loopback_ctrl(p_btif, false); ++/*disable BTIF Tx DMA mode*/ ++ hal_btif_tx_mode_ctrl(p_btif, false); ++/*disable BTIF Rx DMA mode*/ ++ hal_btif_rx_mode_ctrl(p_btif, false); ++/*auto reset*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_AUTORST_EN); ++/*disable Tx IER*/ ++ hal_btif_tx_ier_ctrl(p_btif, false); ++/*enable Rx IER by default*/ ++ hal_btif_rx_ier_ctrl(p_btif, true); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_ier_ctrl ++* DESCRIPTION ++* BTIF Rx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if rx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_RXFEN); ++ else ++ BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_RXFEN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_ier_ctrl ++* DESCRIPTION ++* BTIF Tx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_TXEEN); ++ else ++ BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_TXEEN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++ i_ret = 0; ++ ++ return i_ret; ++} ++ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++ ++/***************************************************************************** ++* FUNCTION ++* _btif_receive_data ++* DESCRIPTION ++* receive data from btif module in FIFO polling mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (max_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++ i_ret = btif_rx_irq_handler(p_btif, p_buf, max_len); ++ ++ return i_ret; ++} ++ ++int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); ++ else ++ BTIF_SET_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ unsigned int value = 0; ++ ++/*read BTIF_TRI_LVL*/ ++ value = BTIF_READ32(BTIF_TRI_LVL(base)); ++/*clear Tx threshold bits*/ ++ value &= (~BTIF_TRI_LVL_TX_MASK); ++/*set tx threshold bits*/ ++ value |= BTIF_TRI_LVL_TX(BTIF_TX_FIFO_THRE); ++/*write back to BTIF_TRI_LVL*/ ++ btif_reg_sync_writel(value, BTIF_TRI_LVL(base)); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_rx_fifo_reset ++* DESCRIPTION ++* reset BTIF's rx fifo ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* ec [IN] control if loopback mode is enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_rx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++/*set Rx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++ ++/*clear Rx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_tx_fifo_reset ++* DESCRIPTION ++* reset BTIF's tx fifo ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++/*set Tx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++/*clear Tx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_loopback_ctrl ++* DESCRIPTION ++* BTIF Tx/Rx loopback mode set, this operation can only be done after set BTIF to normal mode ++* PARAMETERS ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); ++ else ++ BTIF_SET_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_handler ++* DESCRIPTION ++* lower level interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success; negative means fail; positive means rx data length ++*****************************************************************************/ ++int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned int iir = 0; ++ unsigned int rx_len = 0; ++ unsigned long base = p_btif->base; ++ ++#if 0 ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (max_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++#endif ++ unsigned long irq_flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*read interrupt identifier register*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ ++/*is rx interrupt exist?*/ ++#if 0 ++ while ((iir & BTIF_IIR_RX) && (rx_len < max_len)) { ++ rx_len += ++ btif_rx_irq_handler(p_btif, (p_buf + rx_len), ++ (max_len - rx_len)); ++ ++/*update IIR*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++#endif ++ ++ while (iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) { ++ rx_len += btif_rx_irq_handler(p_btif, p_buf, max_len); ++ ++/*update IIR*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++ ++/*is tx interrupt exist?*/ ++ if (iir & BTIF_IIR_TX_EMPTY) ++ i_ret = btif_tx_irq_handler(p_btif); ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++ i_ret = rx_len != 0 ? rx_len : i_ret; ++ return i_ret; ++} ++ ++int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, btif_rx_buf_write rx_cb) ++{ ++ if (p_btif_info->rx_cb != NULL) ++ BTIF_DBG_FUNC("rx_cb already registered, replace (0x%p) with (0x%p)\n", ++ p_btif_info->rx_cb, rx_cb); ++ p_btif_info->rx_cb = rx_cb; ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_rx_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* positive means length of rx data , negative means fail ++*****************************************************************************/ ++static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = 0; ++ unsigned int iir = 0; ++ unsigned int rx_len = 0; ++ unsigned long base = p_btif_info->base; ++ unsigned char rx_buf[256]; ++ unsigned int local_buf_len = 256; ++ btif_rx_buf_write rx_cb = p_btif_info->rx_cb; ++ unsigned int total_len = 0; ++ ++/*read interrupt identifier register*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ while ((iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) && ++ (rx_len < local_buf_len)) { ++ rx_buf[rx_len] = BTIF_READ8(base); ++ rx_len++; ++/*need to consult CC Hwang for advice */ ++/* ++ * whether we need to do memory barrier here ++ * Ans: no ++ */ ++/* ++ * whether we need to d memory barrier when call BTIF_SET_BIT or BTIF_CLR_BIT ++ * Ans: no ++ */ ++ if (rx_len == local_buf_len) { ++ if (rx_cb) ++ (*rx_cb) (p_btif_info, rx_buf, rx_len); ++ rx_len = 0; ++ total_len += rx_len; ++ } ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++ total_len += rx_len; ++ if (rx_len && rx_cb) ++ (*rx_cb) (p_btif_info, rx_buf, rx_len); ++ ++/* ++ * make sure all data write back to memory, mb or dsb? ++ * need to consult CC Hwang for advice ++ * Ans: no need here ++ */ ++ i_ret = total_len; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_tx_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ int how_many = 0; ++ unsigned int lsr; ++ unsigned int ava_len = 0; ++ unsigned long base = p_btif->base; ++ char local_buf[BTIF_TX_FIFO_SIZE]; ++ char *p_data = local_buf; ++ unsigned long flag = 0; ++ ++ struct kfifo *p_tx_fifo = p_btif->p_tx_fifo; ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (lsr & BTIF_LSR_TEMT_BIT) ++ /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE; ++ else if (lsr & BTIF_LSR_THRE_BIT) ++ /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; ++ else { ++ /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ++ ava_len = 0; ++ goto ret; ++ } ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++ how_many = kfifo_out(p_tx_fifo, local_buf, ava_len); ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, ++ kfifo_avail(p_tx_fifo)); ++ while (how_many--) ++ btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++/*clear Tx enable flag if necessary*/ ++ if (kfifo_is_empty(p_tx_fifo)) { ++ hal_btif_tx_ier_ctrl(p_btif, false); ++ BTIF_DBG_FUNC("BTIF tx FIFO is empty\n"); ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ret: ++#else ++/*clear Tx enable flag*/ ++ hal_btif_tx_ier_ctrl(p_btif, false); ++#endif ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_mode_ctrl ++* DESCRIPTION ++* set BTIF tx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (mode == BTIF_MODE_DMA) ++ /*set to DMA mode*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); ++ else ++ /*set to PIO mode*/ ++ BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_mode_ctrl ++* DESCRIPTION ++* set BTIF rx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (mode == BTIF_MODE_DMA) ++ /*set to DMA mode*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); ++ else ++ /*set to PIO mode*/ ++ BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_send_data ++* DESCRIPTION ++* send data through btif in FIFO mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* positive means number of data sent; 0 means no data put to FIFO; negative means error happens ++*****************************************************************************/ ++int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, ++ const unsigned char *p_buf, const unsigned int buf_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ ++ unsigned int ava_len = 0; ++ unsigned int sent_len = 0; ++ ++#if !(NEW_TX_HANDLING_SUPPORT) ++ unsigned long base = p_btif->base; ++ unsigned int lsr = 0; ++ unsigned int left_len = 0; ++ unsigned char *p_data = (unsigned char *)p_buf; ++#endif ++ ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (buf_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++#if NEW_TX_HANDLING_SUPPORT ++ ava_len = _get_btif_tx_fifo_room(p_btif); ++ sent_len = buf_len <= ava_len ? buf_len : ava_len; ++ if (sent_len > 0) { ++ int enqueue_len = 0; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++ enqueue_len = kfifo_in(p_btif->p_tx_fifo, ++ (unsigned char *)p_buf, sent_len); ++ if (sent_len != enqueue_len) { ++ BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n", ++ sent_len, enqueue_len); ++ } ++ i_ret = enqueue_len; ++ mb(); ++/*enable BTIF Tx IRQ*/ ++ hal_btif_tx_ier_ctrl(p_btif, true); ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len); ++ } else { ++ i_ret = 0; ++ } ++#else ++ while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) { ++ /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (lsr & BTIF_LSR_TEMT_BIT) ++ /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE; ++ else if (lsr & BTIF_LSR_THRE_BIT) ++ /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; ++ else { ++ /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ++ ava_len = 0; ++ break; ++ } ++ ++ left_len = buf_len - sent_len; ++/*ava_len will be real length will write to BTIF THR*/ ++ ava_len = ava_len > left_len ? left_len : ava_len; ++/*update sent length valud after this operation*/ ++ sent_len += ava_len; ++/* ++ * whether we need memory barrier here? ++ * Ans: No, no memory ordering issue exist, ++ * CPU will make sure logically right ++ */ ++ while (ava_len--) ++ btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); ++ ++ } ++/* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */ ++ ++ i_ret = sent_len; ++ ++/*enable BTIF Tx IRQ*/ ++ hal_btif_tx_ier_ctrl(p_btif, true); ++#endif ++ return i_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_raise_wak_sig ++* DESCRIPTION ++* raise wakeup signal to counterpart ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ BTIF_ERR_FUNC("%s: clock is off before send wakeup signal!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*write 0 to BTIF_WAK to pull ap_wakeup_consyss low */ ++ BTIF_CLR_BIT(BTIF_WAK(base), BTIF_WAK_BIT); ++ ++/*wait for a period for longer than 1/32k period, here we use 40us*/ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ usleep_range(128, 160); ++/* ++ * according to linux/documentation/timers/timers-how-to, we choose usleep_range ++ * SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): * Use usleep_range ++ */ ++/*write 1 to pull ap_wakeup_consyss high*/ ++ BTIF_SET_BIT(BTIF_WAK(base), BTIF_WAK_BIT); ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ int idx = 0; ++ /*unsigned long irq_flag = 0;*/ ++ unsigned long base = p_btif->base; ++ unsigned char reg_map[0xE0 / 4] = { 0 }; ++ unsigned int lsr = 0x0; ++ unsigned int dma_en = 0; ++ ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ dma_en = BTIF_READ32(BTIF_DMA_EN(base)); ++ /* ++ * here we omit 1st register which is THR/RBR register to avoid ++ * Rx data read by this debug information accidently ++ */ ++ for (idx = 1; idx < sizeof(reg_map); idx++) ++ reg_map[idx] = BTIF_READ8(p_btif->base + (4 * idx)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_INFO_FUNC("BTIF's clock is on\n"); ++ BTIF_INFO_FUNC("base address: 0x%lx\n", base); ++ switch (flag) { ++ case REG_BTIF_ALL: ++#if 0 ++ BTIF_INFO_FUNC("BTIF_IER:0x%x\n", BTIF_READ32(BTIF_IER(base))); ++ BTIF_INFO_FUNC("BTIF_IIR:0x%x\n", BTIF_READ32(BTIF_IIR(base))); ++ BTIF_INFO_FUNC("BTIF_FAKELCR:0x%x\n", ++ BTIF_READ32(BTIF_FAKELCR(base))); ++ BTIF_INFO_FUNC("BTIF_LSR:0x%x\n", BTIF_READ32(BTIF_LSR(base))); ++ BTIF_INFO_FUNC("BTIF_SLEEP_EN:0x%x\n", ++ BTIF_READ32(BTIF_SLEEP_EN(base))); ++ BTIF_INFO_FUNC("BTIF_DMA_EN:0x%x\n", ++ BTIF_READ32(BTIF_DMA_EN(base))); ++ BTIF_INFO_FUNC("BTIF_RTOCNT:0x%x\n", ++ BTIF_READ32(BTIF_RTOCNT(base))); ++ BTIF_INFO_FUNC("BTIF_TRI_LVL:0x%x\n", ++ BTIF_READ32(BTIF_TRI_LVL(base))); ++ BTIF_INFO_FUNC("BTIF_WAT_TIME:0x%x\n", ++ BTIF_READ32(BTIF_WAT_TIME(base))); ++ BTIF_INFO_FUNC("BTIF_HANDSHAKE:0x%x\n", ++ BTIF_READ32(BTIF_HANDSHAKE(base))); ++#endif ++ btif_dump_array("BTIF register", reg_map, sizeof(reg_map)); ++ break; ++ default: ++ break; ++ } ++ ++ BTIF_INFO_FUNC("Tx DMA %s\n", ++ (dma_en & BTIF_DMA_EN_TX) ? "enabled" : "disabled"); ++ BTIF_INFO_FUNC("Rx DMA %s\n", ++ (dma_en & BTIF_DMA_EN_RX) ? "enabled" : "disabled"); ++ ++ BTIF_INFO_FUNC("Rx data is %s\n", ++ (lsr & BTIF_LSR_DR_BIT) ? "not empty" : "empty"); ++ BTIF_INFO_FUNC("Tx data is %s\n", ++ (lsr & BTIF_LSR_TEMT_BIT) ? "empty" : "not empty"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ unsigned int lsr = 0; ++ unsigned long flags = 0; ++ unsigned long base = p_btif->base; ++ unsigned int tx_empty = 0; ++ unsigned int rx_dr = 0; ++ unsigned int tx_irq_disable = 0; ++ ++/* ++ * 3 conditions allow clock to be disable ++ * 1. if TEMT is set or not ++ * 2. if DR is set or not ++ * 3. Tx IRQ is disabled or not ++ */ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ tx_empty = lsr & BTIF_LSR_TEMT_BIT; ++ rx_dr = lsr & BTIF_LSR_DR_BIT; ++ tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN; ++ ++ b_ret = ++ (tx_empty && (tx_irq_disable == 0) && (rx_dr == 0)) ? true : false; ++ if (!b_ret) { ++ BTIF_DBG_FUNC ++ ("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", ++ tx_empty, rx_dr, tx_irq_disable); ++ } ++#if NEW_TX_HANDLING_SUPPORT ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); ++/*clear Tx enable flag if necessary*/ ++ if (!(kfifo_is_empty(p_btif->p_tx_fifo))) { ++ BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n"); ++ b_ret = false; ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); ++#endif ++ return b_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_allow ++* DESCRIPTION ++* whether tx is allowed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) ++{ ++#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) ++#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) ++ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); ++/*clear Tx enable flag if necessary*/ ++ if (kfifo_is_full(p_btif->p_tx_fifo)) { ++ BTIF_WARN_FUNC("BTIF tx FIFO is full\n"); ++ b_ret = false; ++ } else { ++ b_ret = true; ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); ++#else ++ unsigned int lsr = 0; ++ unsigned long base = p_btif->base; ++ unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB; /*only ava length */ ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT))) { ++ BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us); ++/* usleep_range(wait_us, 3 * 10 * wait_us); */ ++ usleep_range(wait_us, 3 * wait_us); ++ } ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; ++ if (!b_ret) ++ BTIF_DBG_FUNC(" tx is not allowed for the moment\n"); ++ else ++ BTIF_DBG_FUNC(" tx is allowed\n"); ++#endif ++ return b_ret; ++} ++ ++#if !(NEW_TX_HANDLING_SUPPORT) ++ ++static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ unsigned long base = p_btif->base; ++ unsigned int lsr = 0; ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; ++ return b_ret; ++} ++#endif ++ ++int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid) ++{ ++ int i_ret = -1; ++ ++ BTIF_DBG_FUNC("op id: %d\n", opid); ++ switch (opid) { ++ case BTIF_PM_DPIDLE_EN: ++ i_ret = 0; ++ break; ++ case BTIF_PM_DPIDLE_DIS: ++ i_ret = 0; ++ break; ++ case BTIF_PM_SUSPEND: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESUME: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESTORE_NOIRQ:{ ++ unsigned int flag = 0; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING; ++ else ++ flag = IRQF_TRIGGER_FALLING; /*make this as default type */ ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ default: ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ } ++#endif ++/* irq_set_irq_type(p_irq->irq_id, flag); */ ++ i_ret = 0; ++ } ++ break; ++ default: ++ i_ret = ERR_INVALID_PAR; ++ break; ++ } ++ ++ return i_ret; ++} ++void mtk_btif_read_cpu_sw_rst_debug_plat(void) ++{ ++#define CONSYS_AP2CONN_WAKEUP_OFFSET 0x00000064 ++ BTIF_WARN_FUNC("+CONSYS_AP2CONN_WAKEUP_OFFSET(0x%x)\n", ++ BTIF_READ32(mtk_btif.base + CONSYS_AP2CONN_WAKEUP_OFFSET)); ++} ++ +diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h +new file mode 100644 +index 000000000000..5e2f5a9857d9 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_BTIF_H_ ++#define __MTK_BTIF_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* gettimeofday */ ++#include ++ ++#include "btif_pub.h" ++#include "btif_dma_pub.h" ++#include "mtk_btif_exp.h" ++ ++#define BTIF_PORT_NR 1 ++#define BTIF_USER_NAME_MAX_LEN 32 ++ ++/*-------------Register Defination Start ---------------*/ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) ++#define BTIF_RX_BUFFER_SIZE (1024 * 32) ++#else ++#define BTIF_RX_BUFFER_SIZE (1024 * 64) ++#endif ++#define BTIF_TX_FIFO_SIZE (1024 * 4) ++ ++/*------------Register Defination End ----------------*/ ++ ++/*------------BTIF Module Clock and Power Control Defination---------------*/ ++typedef enum _ENUM_BTIF_RX_TYPE_ { ++ BTIF_IRQ_CTX = 0, ++ BTIF_TASKLET_CTX = BTIF_IRQ_CTX + 1, ++ BTIF_THREAD_CTX = BTIF_TASKLET_CTX + 1, ++ BTIF_WQ_CTX = BTIF_THREAD_CTX + 1, ++ BTIF_RX_TYPE_MAX, ++} ENUM_BTIF_RX_TYPE; ++ ++typedef enum _ENUM_BTIF_TX_TYPE_ { ++ BTIF_TX_USER_CTX = 0, ++ BTIF_TX_SINGLE_CTX = BTIF_TX_USER_CTX + 1, ++ BTIF_TX_TYPE_MAX, ++} ENUM_BTIF_TX_TYPE; ++ ++typedef enum _ENUM_BTIF_STATE_ { ++ B_S_OFF = 0, ++ B_S_SUSPEND = B_S_OFF + 1, ++ B_S_DPIDLE = B_S_SUSPEND + 1, ++ B_S_ON = B_S_DPIDLE + 1, ++ B_S_MAX, ++} ENUM_BTIF_STATE; ++ ++#define ENABLE_BTIF_RX_DMA 1 ++#define ENABLE_BTIF_TX_DMA 1 ++ ++#if ENABLE_BTIF_TX_DMA ++#define BTIF_TX_MODE BTIF_MODE_DMA ++#else ++#define BTIF_TX_MODE BTIF_MODE_PIO ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++#define BTIF_RX_MODE BTIF_MODE_DMA ++#else ++#define BTIF_RX_MODE BTIF_MODE_PIO ++#endif ++ ++#define BTIF_RX_BTM_CTX BTIF_THREAD_CTX/*BTIF_WQ_CTX*//* BTIF_TASKLET_CTX */ ++/* ++ * -- cannot be used because , ++ * mtk_wcn_stp_parser data will call *(stp_if_tx) to send ack, ++ * in which context sleepable lock or usleep operation may be used, ++ * these operation is not allowed in tasklet, may cause schedule_bug ++ */ ++ ++#define BTIF_TX_CTX BTIF_TX_USER_CTX /* BTIF_TX_SINGLE_CTX */ ++ ++#define ENABLE_BTIF_RX_THREAD_RT_SCHED 0 ++#define MAX_BTIF_RXD_TIME_REC 3 ++ ++/*Structure Defination*/ ++ ++/*-----------------BTIF setting--------------*/ ++typedef struct _mtk_btif_setting_ { ++ ENUM_BTIF_MODE tx_mode; /*BTIF Tx Mode Setting */ ++ ENUM_BTIF_MODE rx_mode; /*BTIF Tx Mode Setting */ ++ ENUM_BTIF_RX_TYPE rx_type; /*rx handle type */ ++ ENUM_BTIF_TX_TYPE tx_type; /*tx type */ ++} mtk_btif_setting, *p_mtk_btif_setting; ++/*---------------------------------------------------------------------------*/ ++ ++#if 0 ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_register_ { ++ unsigned int iir; /*Interrupt Identification Register */ ++ unsigned int lsr; /*Line Status Register */ ++ unsigned int fake_lcr; /*Fake Lcr Regiseter */ ++ unsigned int fifo_ctrl; /*FIFO Control Register */ ++ unsigned int ier; /*Interrupt Enable Register */ ++ unsigned int sleep_en; /*Sleep Enable Register */ ++ unsigned int rto_counter; /*Rx Timeout Counter Register */ ++ unsigned int dma_en; /*DMA Enalbe Register */ ++ unsigned int tri_lvl; /*Tx/Rx Trigger Level Register */ ++ unsigned int wat_time; /*Async Wait Time Register */ ++ unsigned int handshake; /*New HandShake Mode Register */ ++ unsigned int sleep_wak; /*Sleep Wakeup Reigster */ ++} mtk_btif_register, *p_mtk_btif_register; ++/*---------------------------------------------------------------------------*/ ++ ++#endif ++ ++typedef struct _btif_buf_str_ { ++ unsigned int size; ++ unsigned char *p_buf; ++ /* ++ * For Tx: next Tx data pointer to FIFO; ++ * For Rx: next read data pointer from BTIF user ++ */ ++ unsigned int rd_idx; ++ /* ++ * For Tx: next Tx data pointer from BTIF user; ++ * For Rx: next write data(from FIFO) pointer ++ */ ++ unsigned int wr_idx; ++} btif_buf_str, *p_btif_buf_str; ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_dma_ { ++ /*p_mtk_btif*/ void *p_btif; ++ /*BTIF pointer to which DMA belongs */ ++ ++#if 0 ++ unsigned int channel; /*DMA's channel */ ++#endif ++ ++ ENUM_BTIF_DIR dir; /*DMA's direction: */ ++ bool enable; /*DMA enable or disable flag */ ++ ++ P_MTK_DMA_INFO_STR p_dma_info; /*DMA's IRQ information */ ++ ++#if 0 ++ mtk_dma_register register; /*DMA's register */ ++#endif ++ ++ spinlock_t iolock; /*io lock for DMA channel */ ++ atomic_t entry; /* entry count */ ++} mtk_btif_dma, *p_mtk_btif_dma; ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) ++#define BTIF_LOG_ENTRY_NUM 10 ++#else ++#define BTIF_LOG_ENTRY_NUM 30 ++#endif ++ ++#define BTIF_LOG_SZ 1536 ++ ++typedef void (*MTK_BTIF_RX_NOTIFY) (void); ++ ++typedef struct _btif_log_buf_t_ { ++ unsigned int len; ++ struct timeval timer; ++ unsigned char buffer[BTIF_LOG_SZ]; ++} BTIF_LOG_BUF_T, *P_BTIF_LOG_BUF_T; ++ ++typedef struct _btif_log_queue_t_ { ++ ENUM_BTIF_DIR dir; ++ bool enable; ++ bool output_flag; ++ unsigned int in; ++ unsigned int out; ++ unsigned int size; ++ spinlock_t lock; ++ P_BTIF_LOG_BUF_T p_queue[BTIF_LOG_ENTRY_NUM]; ++} BTIF_LOG_QUEUE_T, *P_BTIF_LOG_QUEUE_T; ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_ { ++ unsigned int open_counter; /*open counter */ ++ bool enable; /*BTIF module enable flag */ ++ bool lpbk_flag; /*BTIF module enable flag */ ++#if 0 ++ unsigned long base; /* BTIF controller base address */ ++#endif ++ ++ ENUM_BTIF_STATE state; /*BTIF state mechanism */ ++ struct mutex state_mtx; /*lock to BTIF state mechanism's state change */ ++ struct mutex ops_mtx; /*lock to BTIF's open and close */ ++ ++#if 0 ++ mtk_btif_register register; /*BTIF registers */ ++#endif ++ ++ ENUM_BTIF_MODE tx_mode; /* BTIF Tx channel mode */ ++ ENUM_BTIF_MODE rx_mode; /* BTIF Rx channel mode */ ++ struct mutex tx_mtx; /*lock to BTIF's tx process */ ++/*rx handling */ ++ ENUM_BTIF_RX_TYPE btm_type; /*BTIF Rx bottom half context */ ++/*tx handling*/ ++ ENUM_BTIF_TX_TYPE tx_ctx; /*BTIF tx context */ ++/* unsigned char rx_buf[BTIF_RX_BUFFER_SIZE]; */ ++ btif_buf_str btif_buf; ++ spinlock_t rx_irq_spinlock; /*lock for rx irq handling */ ++ ++/*rx workqueue information*/ ++ /*lock to BTIF's rx bottom half when kernel thread is used */ ++ struct mutex rx_mtx; ++ struct workqueue_struct *p_rx_wq; ++ struct work_struct rx_work; ++ ++ struct workqueue_struct *p_tx_wq; ++ struct work_struct tx_work; ++ struct kfifo *p_tx_fifo; ++ ++/*rx tasklet information*/ ++ struct tasklet_struct rx_tasklet; ++ /*lock to BTIF's rx bottom half when tasklet is used */ ++ spinlock_t rx_tasklet_spinlock; ++ ++/*rx thread information*/ ++ struct task_struct *p_task; ++ struct completion rx_comp; ++ ++ mtk_btif_setting *setting; /*BTIF setting */ ++ ++ p_mtk_btif_dma p_tx_dma; /*BTIF Tx channel DMA */ ++ p_mtk_btif_dma p_rx_dma; /*BTIF Rx channel DMA */ ++ ++ MTK_WCN_BTIF_RX_CB rx_cb; /*Rx callback function */ ++ MTK_BTIF_RX_NOTIFY rx_notify; ++ ++ P_MTK_BTIF_INFO_STR p_btif_info; /*BTIF's information */ ++ ++/*Log Tx data to buffer*/ ++ BTIF_LOG_QUEUE_T tx_log; ++ ++/*Log Rx data to buffer*/ ++ BTIF_LOG_QUEUE_T rx_log; ++ ++/* struct list_head *p_user_list; */ ++ struct list_head user_list; ++/* get btif dev pointer*/ ++ void *private_data; ++} mtk_btif, *p_mtk_btif; ++/*---------------------------------------------------------------------------*/ ++ ++/*---------------------------------------------------------------------------*/ ++#if 0 ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_dma_register_ { ++ unsigned int int_flag; /*Tx offset:0x0 Rx offset:0x0 */ ++ unsigned int int_enable; /*Tx offset:0x4 Rx offset:0x4 */ ++ unsigned int dma_enable; /*Tx offset:0x8 Rx offset:0x8 */ ++ unsigned int dma_reset; /*Tx offset:0xc Rx offset:0xc */ ++ unsigned int dma_stop; /*Tx offset:0x10 Rx offset:0x10 */ ++ unsigned int dma_flush; /*Tx offset:0x14 Rx offset:0x14 */ ++ unsigned int vff_addr; /*Tx offset:0x1c Rx offset:0x1c */ ++ unsigned int vff_len; /*Tx offset:0x24 Rx offset:0x24 */ ++ unsigned int vff_thr; /*Tx offset:0x28 Rx offset:0x28 */ ++ unsigned int vff_wpt; /*Tx offset:0x2c Rx offset:0x2c */ ++ unsigned int vff_rpt; /*Tx offset:0x30 Rx offset:0x30 */ ++ unsigned int rx_fc_thr; /*Tx:No this register Rx offset:0x34 */ ++ unsigned int int_buf_size; /*Tx offset:0x38 Rx offset:0x38 */ ++ unsigned int vff_valid_size; /*Tx offset:0x3c Rx offset:0x3c */ ++ unsigned int vff_left_size; /*Tx offset:0x40 Rx offset:0x40 */ ++ unsigned int debug_status; /*Tx offset:0x50 Rx offset:0x50 */ ++} mtk_dma_register, *p_mtk_dma_register; ++/*---------------------------------------------------------------------------*/ ++#endif ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_user_ { ++ bool enable; /*register its state */ ++ struct list_head entry; /*btif_user's bi-direction list table */ ++ /*BTIF's user, static allocation */ ++ char u_name[BTIF_USER_NAME_MAX_LEN]; ++ unsigned long u_id; ++ p_mtk_btif p_btif; ++} mtk_btif_user, *p_mtk_btif_user; ++ ++/*---------------------------------------------------------------------------*/ ++#define BBS_PTR(ptr, idx) ((ptr->p_buf) + idx) ++ ++#define BBS_SIZE(ptr) ((ptr)->size) ++#define BBS_MASK(ptr) (BBS_SIZE(ptr) - 1) ++#define BBS_COUNT(ptr) ((ptr)->wr_idx >= (ptr)->rd_idx ? (ptr)->wr_idx - \ ++(ptr)->rd_idx : BBS_SIZE(ptr) - \ ++((ptr)->rd_idx - (ptr)->wr_idx)) ++#define BBS_COUNT_CUR(ptr, wr_idx) (wr_idx >= (ptr)->rd_idx ? wr_idx - \ ++(ptr)->rd_idx : BBS_SIZE(ptr) - \ ++((ptr)->rd_idx - wr_idx)) ++ ++#define BBS_LEFT(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) ++ ++#define BBS_AVL_SIZE(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) ++#define BBS_FULL(ptr) (BBS_COUNT(ptr) - BBS_SIZE(ptr)) ++#define BBS_EMPTY(ptr) ((ptr)->wr_idx == (ptr)->rd_idx) ++#define BBS_WRITE_MOVE_NEXT(ptr) ((ptr)->wr_idx = \ ++((ptr)->wr_idx + 1) & BBS_MASK(ptr)) ++#define BBS_READ_MOVE_NEXT(ptr) ((ptr)->rd_idx = \ ++((ptr)->rd_idx + 1) & BBS_MASK(ptr)) ++ ++#define BBS_INIT(ptr) \ ++{ \ ++(ptr)->rd_idx = (ptr)->wr_idx = 0; \ ++(ptr)->size = BTIF_RX_BUFFER_SIZE; \ ++} ++ ++ ++#define BTIF_MUTEX_UNLOCK(x) mutex_unlock(x) ++ ++extern mtk_btif g_btif[]; ++ ++int btif_open(p_mtk_btif p_btif); ++int btif_close(p_mtk_btif p_btif); ++int btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++int btif_enter_dpidle(p_mtk_btif p_btif); ++int btif_exit_dpidle(p_mtk_btif p_btif); ++int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb); ++ ++/*for test purpose*/ ++int _btif_suspend(p_mtk_btif p_btif); ++int _btif_resume(p_mtk_btif p_btif); ++int _btif_restore_noirq(p_mtk_btif p_btif); ++ ++int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); ++int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, ++ int len); ++int btif_dump_data(char *p_buf, int len); ++int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_init(p_mtk_btif p_btif); ++int btif_dump_reg(p_mtk_btif p_btif); ++int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify); ++int btif_raise_wak_signal(p_mtk_btif p_btif); ++int btif_clock_ctrl(p_mtk_btif p_btif, int en); ++bool btif_parser_wmt_evt(p_mtk_btif p_btif, ++ const char *sub_str, ++ unsigned int sub_len); ++void mtk_btif_read_cpu_sw_rst_debug(void); ++ ++#endif /*__MTK_BTIF_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h +new file mode 100644 +index 000000000000..3752644fe0aa +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h +@@ -0,0 +1,280 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_BTIF_EXP_H_ ++#define _MTK_BTIF_EXP_H_ ++ ++/*--------------marco defination---------------*/ ++#define BTIF_MAX_LEN_PER_PKT 2048 ++#define BTIF_RXD_BE_BLOCKED_DETECT 1 ++/*--------------Enum Defination---------------*/ ++typedef enum _ENUM_BTIF_DPIDLE_ { ++ BTIF_DPIDLE_DISABLE = 0, ++ BTIF_DPIDLE_ENABLE = BTIF_DPIDLE_DISABLE + 1, ++ BTIF_DPIDLE_MAX, ++} ENUM_BTIF_DPIDLE_CTRL; ++ ++typedef enum _ENUM_BTIF_LPBK_MODE_ { ++ BTIF_LPBK_DISABLE = 0, ++ BTIF_LPBK_ENABLE = BTIF_LPBK_DISABLE + 1, ++ BTIF_LPBK_MAX, ++} ENUM_BTIF_LPBK_MODE; ++ ++typedef enum _ENUM_BTIF_DBG_ID_ { ++ BTIF_DISABLE_LOGGER = 0, ++ BTIF_ENABLE_LOGGER = BTIF_DISABLE_LOGGER + 1, ++ BTIF_DUMP_LOG = BTIF_ENABLE_LOGGER + 1, ++ BTIF_CLR_LOG = BTIF_DUMP_LOG + 1, ++ BTIF_DUMP_BTIF_REG = BTIF_CLR_LOG + 1, ++ BTIF_ENABLE_RT_LOG = BTIF_DUMP_BTIF_REG + 1, ++ BTIF_DISABLE_RT_LOG = BTIF_ENABLE_RT_LOG + 1, ++ BTIF_DBG_MAX, ++} ENUM_BTIF_DBG_ID; ++ ++typedef enum _ENUM_BTIF_OP_ERROR_CODE_ { ++ E_BTIF_AGAIN = 0, ++ E_BTIF_FAIL = -1, ++ E_BTIF_BAD_POINTER = -2, ++ E_BTIF_NO_SPACE = -3, ++ E_BTIF_INTR = -4, ++ E_BTIF_INVAL_PARAM = -5, ++ E_BTIF_ALREADY_OPEN = -6, ++ E_BTIF_NOT_OPEN = -7, ++ E_BTIF_INVAL_STATE = -8, ++} ENUM_BTIF_OP_ERROR_CODE; ++ ++/*--------------End of Enum Defination---------------*/ ++ ++/*--------------Type Definition---------------*/ ++ ++typedef int (*MTK_WCN_BTIF_RX_CB) (const unsigned char *p_buf, ++ unsigned int len); ++ ++/*--------------End of Type Definition---------------*/ ++ ++/*--------------Normal Mode API declearation---------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_open ++* DESCRIPTION ++* open BTIF interface, will do BTIF module HW and SW initialization ++* PARAMETERS ++* p_owner [IN] pointer to owner who call this API, ++* currently there are 2 owner ("stp" or "btif_tester") ++* may use this module ++* user's id string must be less than 32 bytes ++* for "stp", BTIF will call rx callback function to route rx data to STP module ++* for "stp_tester", BTIF will save rx data ++* and wait for native process to access ++* p_id [IN] BTIF's user id will be put to this address ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++* if open success, value p_id will be the only identifier for ++* user to access BTIF's other operations ++* including read/write/dpidle_ctrl/rx_cb_retister ++* this user id is only an identifier used for owner identification ++*****************************************************************************/ ++int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id); ++//EXPORT_SYMBOL(mtk_wcn_btif_open) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_close ++* DESCRIPTION ++* close BTIF interface, will do BTIF module HW and SW de-initialization ++* once this API is called, p_btif should never be used by BTIF's user again ++* PARAMETERS ++* u_id [IN] BTIF's user id ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_close(unsigned long u_id); ++//EXPORT_SYMBOL(mtk_wcn_btif_close) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_write ++* DESCRIPTION ++* send data throuth BTIF module ++* there's no internal buffer to cache STP data in BTIF driver, ++* if in DMA mode ++* btif driver will check if there's enough space ++* in vFIFO for data to send in DMA mode ++* if yes, put data to vFIFO and return corresponding data length to caller ++* if no, corresponding error code will be returned to called ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN] pointer to target data to send ++* len [IN] data length (should be less than 2014 bytes per STP package) ++* ++* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller ++* if btif driver detected that no space is available in Tx FIFO, ++* will return E_BTIF_NO_SPACE, ++* mostly something is wrong with BTIF or consys when this ++* return value is returned ++* RETURNS ++* int positive: data length send through BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++* E_BTIF_AGAIN (0) will be returned to caller if btif does not have ++* enough vFIFO to send data, when caller get 0, ++* he should wait for a moment (5~10ms maybe) and ++* try a few times (maybe 10~20) ++* if still get E_BTIF_AGAIN, should call BTIF's debug API and ++* dump BTIF driver and BTIF/DMA register information to kernel log ++* for debug ++* E_BTIF_BAD_POINTER will be returned to caller if btif is not ++* opened successfully before call this API ++* E_BTIF_INVAL_PARAM will be returned if parameter is not valid ++ ++*****************************************************************************/ ++int mtk_wcn_btif_write(unsigned long u_id, ++ const unsigned char *p_buf, unsigned int len); ++//EXPORT_SYMBOL(mtk_wcn_btif_write) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_read ++* DESCRIPTION ++* read data from BTIF module ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN/OUT] pointer to buffer where rx data will be put ++* max_len [IN] max buffer length ++* RETURNS ++* int positive: data length read from BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_read(unsigned long u_id, ++ unsigned char *p_buf, unsigned int max_len); ++//EXPORT_SYMBOL(mtk_wcn_btif_read) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_dpidle_ctrl ++* DESCRIPTION ++* control if BTIF module allow system enter deepidle state or not ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL ++* RETURNS ++* int always return 0 ++*****************************************************************************/ ++int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_rx_cb_register ++* DESCRIPTION ++* register rx callback function to BTIF module by btif user ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* rx_cb [IN] pointer to stp rx handler callback function, ++* should be comply with MTK_WCN_BTIF_RX_CB ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_wakeup_consys ++* DESCRIPTION ++* once sleep command is sent to con sys, ++* should call this API before send wakeup command to ++* make con sys aware host want to send data to consys ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_wakeup_consys(unsigned long u_id); ++ ++/*--------------End of Normal Mode API declearation----------------*/ ++ ++/*--------------Debug Purpose API declearation----------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_loopback_ctrl ++* DESCRIPTION ++* enable/disable BTIF internal loopback function, ++* when this function is enabled, ++* data send to btif will be received by btif itself ++* only for debug purpose, should never use this function in normal mode ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* enable [IN] loopback mode control flag, enable or disable, ++* shou be one of ENUM_BTIF_LPBK_MODE ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable); ++//EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_logger_ctrl ++* DESCRIPTION ++* control BTIF logger function's behavior ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* flag [IN] should be one of ENUM_BTIF_DBG_ID ++* BTIF_DISABLE_LOGGER - disable btif logger ++* BTIF_ENABLE_LOGGER - enable btif logger ++* BTIF_DUMP_LOG - dump log logged by btif ++* BTIF_CLR_LOG - clear btif log buffer ++* BTIF_DUMP_BTIF_REG - dump btif controller's register ++* BTIF_DUMP_DMA_REG - dump DMA controller's register ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag); ++//EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); ++/*-----------End of Debug Purpose API declearation------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_parser_wmt_evt ++* DESCRIPTION ++* parser wmt sleep/wakeup evt in btif bbs buffer for debug ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* sub_str [IN] the str to be parsered ++* str_len [IN] the length of sub_str ++* RETURNS ++* bool true = succeed; ++* false = fail; ++*****************************************************************************/ ++bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, ++ const char *sub_str, unsigned int str_len); ++ ++int mtk_btif_exp_open_test(void); ++int mtk_btif_exp_close_test(void); ++int mtk_btif_exp_write_test(void); ++int mtk_btif_exp_suspend_test(void); ++int mtk_btif_exp_resume_test(void); ++int mtk_btif_exp_enter_dpidle_test(void); ++int mtk_btif_exp_exit_dpidle_test(void); ++int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int loop); ++int mtk_btif_exp_log_debug_test(int flag); ++int mtk_btif_exp_restore_noirq_test(void); ++int btif_wakeup_consys_no_id(void); ++int mtk_btif_exp_clock_ctrl(int en); ++#if BTIF_RXD_BE_BLOCKED_DETECT ++int mtk_btif_rxd_be_blocked_flag_get(void); ++#endif ++void mtk_btif_read_cpu_sw_rst_debug_exp(void); ++#endif /*_MTK_BTIF_EXP_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/mtk_btif.c b/drivers/misc/mediatek/btif/common/mtk_btif.c +new file mode 100644 +index 000000000000..5deb64ef3e56 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/mtk_btif.c +@@ -0,0 +1,3472 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++/*-----------linux system header files----------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*#include */ ++/*-----------driver own header files----------------*/ ++#ifdef CONFIG_COMPAT ++#include ++#endif ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF" ++ ++#define BTIF_CDEV_SUPPORT 1 ++ ++#include "btif_pub.h" ++#include "btif_dma_pub.h" ++#include "mtk_btif_exp.h" ++#include "mtk_btif.h" ++ ++/*-----------static function declearation----------------*/ ++static int mtk_btif_probe(struct platform_device *pdev); ++static int mtk_btif_remove(struct platform_device *pdev); ++static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state); ++static int mtk_btif_resume(struct platform_device *pdev); ++static int mtk_btif_drv_resume(struct device *dev); ++static int mtk_btif_drv_suspend(struct device *pdev); ++ ++static int mtk_btif_restore_noirq(struct device *device); ++static int btif_file_open(struct inode *pinode, struct file *pfile); ++static int btif_file_release(struct inode *pinode, struct file *pfile); ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops); ++static unsigned int btif_poll(struct file *filp, poll_table *wait); ++static int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, ++ mtk_btif_irq_handler irq_handler, void *data); ++static int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data); ++static int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en); ++static int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en); ++static irqreturn_t btif_irq_handler(int irq, void *data); ++static unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++ ++static irqreturn_t btif_tx_dma_irq_handler(int irq, void *data); ++static irqreturn_t btif_rx_dma_irq_handler(int irq, void *data); ++ ++static unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++static int _btif_controller_tx_setup(p_mtk_btif p_btif); ++static int _btif_controller_tx_free(p_mtk_btif p_btif); ++static int _btif_controller_rx_setup(p_mtk_btif p_btif); ++static int _btif_controller_rx_free(p_mtk_btif p_btif); ++static int _btif_tx_pio_setup(p_mtk_btif p_btif); ++static int _btif_rx_pio_setup(p_mtk_btif p_btif); ++static int _btif_rx_dma_setup(p_mtk_btif p_btif); ++static int _btif_rx_dma_free(p_mtk_btif p_btif); ++static int _btif_tx_dma_setup(p_mtk_btif p_btif); ++static int _btif_tx_dma_free(p_mtk_btif p_btif); ++static int _btif_controller_setup(p_mtk_btif p_btif); ++static int _btif_controller_free(p_mtk_btif p_btif); ++ ++static int _btif_pio_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++static int _btif_dma_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++ ++static unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static unsigned int btif_bbs_read(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static unsigned int btif_bbs_write(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs); ++static int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len); ++static int _btif_rx_btm_deinit(p_mtk_btif p_btif); ++static int _btif_rx_btm_sched(p_mtk_btif p_btif); ++static int _btif_rx_btm_init(p_mtk_btif p_btif); ++static void btif_rx_tasklet(unsigned long func_data); ++static void btif_rx_worker(struct work_struct *p_work); ++static int btif_rx_thread(void *p_data); ++static int btif_rx_data_consummer(p_mtk_btif p_btif); ++ ++static int _btif_tx_ctx_init(p_mtk_btif p_btif); ++static int _btif_tx_ctx_deinit(p_mtk_btif p_btif); ++static void btif_tx_worker(struct work_struct *p_work); ++ ++static int _btif_state_deinit(p_mtk_btif p_btif); ++static int _btif_state_release(p_mtk_btif p_btif); ++static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif); ++static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state); ++static int _btif_state_hold(p_mtk_btif p_btif); ++static int _btif_state_init(p_mtk_btif p_btif); ++ ++static int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ++ ENUM_BTIF_DPIDLE_CTRL en_flag); ++static int _btif_enter_dpidle(p_mtk_btif p_btif); ++static int _btif_exit_dpidle(p_mtk_btif p_btif); ++static int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif); ++static int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif); ++static int _btif_enter_dpidle_from_on(p_mtk_btif p_btif); ++static int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif); ++ ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma); ++static int _btif_vfifo_init(p_mtk_btif_dma p_dma); ++#endif ++ ++static bool _btif_is_tx_complete(p_mtk_btif p_btif); ++static int _btif_init(p_mtk_btif p_btif); ++static int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); ++static int btif_rx_dma_mode_set(int en); ++static int btif_tx_dma_mode_set(int en); ++ ++static int _btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++ ++/*-----------end of static function declearation----------------*/ ++ ++static const char *g_state[B_S_MAX] = { ++ "OFF", ++ "SUSPEND", ++ "DPIDLE", ++ "ON", ++}; ++ ++/*-----------BTIF setting--------------*/ ++mtk_btif_setting g_btif_setting[BTIF_PORT_NR] = { ++ { ++ .tx_mode = BTIF_TX_MODE, ++ .rx_mode = BTIF_RX_MODE, ++ .rx_type = BTIF_RX_BTM_CTX, ++ .tx_type = BTIF_TX_CTX, ++ }, ++}; ++ ++mtk_btif g_btif[BTIF_PORT_NR] = { ++ { ++ .open_counter = 0, ++ .state = B_S_OFF, ++ .setting = &g_btif_setting[0], ++ .p_tx_dma = NULL, ++ .p_rx_dma = NULL, ++ .rx_cb = NULL, ++ .p_btif_info = NULL, ++ }, ++}; ++ ++mtk_btif_dma g_dma[BTIF_PORT_NR][BTIF_DIR_MAX] = { ++ { ++ { ++ .p_btif = NULL, ++ .dir = BTIF_TX, ++ .p_dma_info = NULL, ++ .entry = ATOMIC_INIT(0), ++ }, ++ { ++ .p_btif = NULL, ++ .dir = BTIF_RX, ++ .p_dma_info = NULL, ++ .entry = ATOMIC_INIT(0), ++ }, ++ }, ++}; ++ ++#define G_MAX_PKG_LEN (7 * 1024) ++static int g_max_pkg_len = G_MAX_PKG_LEN; /*DMA vFIFO is set to 8 * 1024, we set this to 7/8 * vFIFO size*/ ++static int g_max_pding_data_size = BTIF_RX_BUFFER_SIZE * 3 / 4; ++ ++ ++static int mtk_btif_dbg_lvl = BTIF_LOG_ERR; ++ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++static struct timeval btif_rxd_time_stamp[MAX_BTIF_RXD_TIME_REC]; ++#endif ++/*-----------Platform bus related structures----------------*/ ++#define DRV_NAME "mtk_btif" ++ ++#ifdef CONFIG_OF ++const struct of_device_id apbtif_of_ids[] = { ++ { .compatible = "mediatek,btif", }, ++ {} ++}; ++#endif ++ ++const struct dev_pm_ops mtk_btif_drv_pm_ops = { ++ .restore_noirq = mtk_btif_restore_noirq, ++ .suspend = mtk_btif_drv_suspend, ++ .resume = mtk_btif_drv_resume, ++}; ++ ++struct platform_driver mtk_btif_dev_drv = { ++ .probe = mtk_btif_probe, ++ .remove = mtk_btif_remove, ++#ifdef CONFIG_PM ++ .suspend = mtk_btif_suspend, ++ .resume = mtk_btif_resume, ++#endif ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &mtk_btif_drv_pm_ops, ++#endif ++#ifdef CONFIG_OF ++ .of_match_table = apbtif_of_ids, ++#endif ++ } ++}; ++ ++#define BTIF_STATE_RELEASE(x) _btif_state_release(x) ++ ++/*-----------End of Platform bus related structures----------------*/ ++ ++/*-----------platform bus related operation APIs----------------*/ ++ ++static int mtk_btif_probe(struct platform_device *pdev) ++{ ++/*Chaozhong: ToDo: to be implement*/ ++/*register IRQ for BTIF and Tx Rx DMA and disable them by default*/ ++ BTIF_INFO_FUNC("DO BTIF PROBE\n"); ++ platform_set_drvdata(pdev, &g_btif[0]); ++ g_btif[0].private_data = (struct device *)&pdev->dev; ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ hal_btif_clk_get_and_prepare(pdev); ++#endif ++ ++ return 0; ++} ++ ++static int mtk_btif_remove(struct platform_device *pdev) ++{ ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_INFO_FUNC("DO BTIF REMOVE\n"); ++ platform_set_drvdata(pdev, NULL); ++ g_btif[0].private_data = NULL; ++ return 0; ++} ++ ++int _btif_suspend(p_mtk_btif p_btif) ++{ ++ int i_ret; ++ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif != NULL) { ++ if (!(p_btif->enable)) ++ i_ret = 0; ++ else { ++ if (_btif_state_get(p_btif) == B_S_ON) { ++ BTIF_ERR_FUNC("BTIF in ON state,", ++ "there are data need to be send or recev,suspend fail\n"); ++ i_ret = -1; ++ } else { ++ /* ++ * before disable BTIF controller and DMA controller ++ * we need to set BTIF to ON state ++ */ ++ i_ret = _btif_exit_dpidle(p_btif); ++ if (i_ret == 0) { ++ i_ret += _btif_controller_free(p_btif); ++ i_ret = _btif_controller_tx_free(p_btif); ++ i_ret += _btif_controller_rx_free(p_btif); ++ } ++ if (i_ret != 0) { ++ BTIF_INFO_FUNC("failed\n"); ++ /*Chaozhong: what if failed*/ ++ } else { ++ BTIF_INFO_FUNC("succeed\n"); ++ i_ret = _btif_state_set(p_btif, B_S_SUSPEND); ++ if (i_ret && _btif_init(p_btif)) { ++ /*Chaozhong:BTIF re-init failed? what to do*/ ++ i_ret = _btif_state_set(p_btif, B_S_OFF); ++ } ++ } ++ } ++ } ++ } else ++ i_ret = -1; ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++ ++static int mtk_btif_drv_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ pm_message_t state = PMSG_SUSPEND; ++ ++ return mtk_btif_suspend(pdev, state); ++} ++ ++static int mtk_btif_drv_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ ++ return mtk_btif_resume(pdev); ++} ++ ++static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = NULL; ++ ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_DBG_FUNC("++\n"); ++ p_btif = platform_get_drvdata(pdev); ++ i_ret = _btif_suspend(p_btif); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int _btif_restore_noirq(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*BTIF IRQ restore no irq*/ ++ i_ret = hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF HW IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC("BTIF HW IRQ restore failed, i_ret:%d\n", i_ret); ++ return i_ret; ++ } ++/*BTIF DMA restore no irq*/ ++ if (p_btif->tx_mode & BTIF_MODE_DMA) { ++ i_ret = hal_dma_pm_ops(p_btif->p_tx_dma->p_dma_info, ++ BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF Tx DMA IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC ++ ("BTIF Tx DMA IRQ restore failed, i_ret:%d\n", ++ i_ret); ++ return i_ret; ++ } ++ } ++ if (p_btif->rx_mode & BTIF_MODE_DMA) { ++ i_ret = hal_dma_pm_ops(p_btif->p_rx_dma->p_dma_info, ++ BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF Rx DMA IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC ++ ("BTIF Rx DMA IRQ restore failed, i_ret:%d\n", ++ i_ret); ++ return i_ret; ++ } ++ } ++ return i_ret; ++} ++ ++static int mtk_btif_restore_noirq(struct device *dev) ++{ ++ int i_ret = 0; ++ struct platform_device *pdev = to_platform_device(dev); ++ p_mtk_btif p_btif = platform_get_drvdata(pdev); ++ ++ BTIF_INFO_FUNC("++\n"); ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif->enable) ++ BTIF_ERR_FUNC("!!!-----------------!BTIF is not closed before IPOH shutdown!!!---------------!\n"); ++ WARN_ON(p_btif->enable); ++ ++ i_ret = _btif_restore_noirq(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ BTIF_INFO_FUNC("--\n"); ++ return 0; ++} ++ ++int _btif_resume(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif != NULL) { ++ state = _btif_state_get(p_btif); ++ if (!(p_btif->enable)) ++ i_ret = 0; ++ else if (state == B_S_SUSPEND) ++ i_ret = _btif_enter_dpidle(p_btif); ++ else ++ BTIF_INFO_FUNC ++ ("BTIF state: %s before resume, do nothing\n", g_state[state]); ++ } else ++ i_ret = -1; ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++static int mtk_btif_resume(struct platform_device *pdev) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = NULL; ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_DBG_FUNC("++\n"); ++ p_btif = platform_get_drvdata(pdev); ++ i_ret = _btif_resume(p_btif); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return 0; ++} ++ ++/*-----------device node----------------*/ ++#if BTIF_CDEV_SUPPORT ++ ++dev_t btif_dev; ++struct class *p_btif_class; ++struct device *p_btif_dev; ++const char *p_btif_dev_name = "btif"; ++static struct semaphore wr_mtx; ++static struct semaphore rd_mtx; ++unsigned char wr_buf[2048]; ++unsigned char rd_buf[2048]; ++static int rx_notify_flag; ++static DECLARE_WAIT_QUEUE_HEAD(btif_wq); ++static int btif_file_open(struct inode *pinode, struct file *pfile); ++static int btif_file_release(struct inode *pinode, struct file *pfile); ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops); ++ ++static ssize_t btif_file_write(struct file *filp, ++ const char __user *buf, size_t count, loff_t *f_pos); ++static long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, ++ unsigned long arg); ++#ifdef CONFIG_COMPAT ++static long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); ++#endif ++static struct cdev btif_dev_c; ++static wait_queue_head_t btif_read_inq; /* read queues */ ++ ++const struct file_operations mtk_btif_fops = { ++ .owner = THIS_MODULE, ++ .open = btif_file_open, ++ .release = btif_file_release, ++ .read = btif_file_read, ++ .write = btif_file_write, ++ .unlocked_ioctl = btif_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = btif_compat_ioctl, ++#endif ++ .poll = btif_poll, ++}; ++ ++static int btif_chrdev_init(void) ++{ ++ int i_ret; ++ ++ int i_err; ++ ++ /* alloc device number dynamically */ ++ i_ret = alloc_chrdev_region(&btif_dev, 0, 1, p_btif_dev_name); ++ if (i_ret) { ++ BTIF_ERR_FUNC("devuce number allocation failed, i_ret:%d\n", ++ i_ret); ++ } else { ++ BTIF_INFO_FUNC("devuce number allocation succeed\n"); ++ } ++ cdev_init(&btif_dev_c, &mtk_btif_fops); ++ btif_dev_c.owner = THIS_MODULE; ++ i_err = cdev_add(&btif_dev_c, btif_dev, 1); ++ if (i_err) { ++ BTIF_ERR_FUNC("error add btif dev to kernel, error code:%d\n", ++ i_err); ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -1; ++ } ++ BTIF_INFO_FUNC("add btif dev to kernel succeed\n"); ++ ++ p_btif_class = class_create(THIS_MODULE, p_btif_dev_name); ++ if (IS_ERR(p_btif_class)) { ++ BTIF_ERR_FUNC("error happened when doing class_create\n"); ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -2; ++ } ++ BTIF_INFO_FUNC("create class for btif succeed\n"); ++ ++ p_btif_dev = device_create(p_btif_class, ++ NULL, btif_dev, 0, p_btif_dev_name); ++ if (IS_ERR(p_btif_dev)) { ++ BTIF_ERR_FUNC("error happened when doing device_create\n"); ++ class_destroy(p_btif_class); ++ p_btif_class = NULL; ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -3; ++ } ++ BTIF_INFO_FUNC("create device for btif succeed\n"); ++ ++ return 0; ++} ++ ++void btif_rx_notify_cb(void) ++{ ++ BTIF_DBG_FUNC("++\n"); ++ rx_notify_flag = 1; ++ wake_up(&btif_wq); ++ wake_up_interruptible(&btif_read_inq); ++ BTIF_DBG_FUNC("--\n"); ++} ++ ++unsigned int btif_poll(struct file *filp, poll_table *wait) ++{ ++ unsigned int mask = 0; ++ unsigned int ava_len = 0; ++/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ ++ unsigned int wr_idx = g_btif[0].btif_buf.wr_idx; ++ ++/* BTIF_Rx_IRQ_Disable(); */ ++ ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); ++ BTIF_INFO_FUNC("++\n"); ++ if (ava_len == 0) { ++ poll_wait(filp, &btif_read_inq, wait); ++ wr_idx = g_btif[0].btif_buf.wr_idx; ++ ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); ++/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ ++ if (ava_len) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ } else { ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ } ++/*make for writable*/ ++ mask |= POLLOUT | POLLWRNORM; /* writable */ ++ BTIF_INFO_FUNC("--, mask:%d\n", mask); ++ return mask; ++} ++ ++static int _btif_file_open(void) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_INFO_FUNC("++\n"); ++ ++/*Chaozhong: ToDo: to be implement*/ ++ i_ret = btif_open(p_btif); ++ if ((i_ret != 0) && (i_ret != E_BTIF_ALREADY_OPEN)) { ++ BTIF_ERR_FUNC("btif_open failed, error code:%d\n", i_ret); ++ } else { ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ i_ret = 0; ++ } ++/*semaphore for read and write operation init*/ ++ sema_init(&wr_mtx, 1); ++ sema_init(&rd_mtx, 1); ++ ++/*buffer for read and write init*/ ++ memset(wr_buf, 0, sizeof(wr_buf)); ++ memset(rd_buf, 0, sizeof(rd_buf)); ++ init_waitqueue_head(&(btif_read_inq)); ++ btif_rx_notify_reg(p_btif, btif_rx_notify_cb); ++ BTIF_INFO_FUNC("--\n"); ++ return i_ret; ++} ++ ++static int _btif_file_close(void) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("++\n"); ++/*Chaozhong: ToDo: to be implement*/ ++ i_ret = btif_close(&g_btif[0]); ++ if (i_ret != 0) ++ BTIF_ERR_FUNC("btif_close failed, error code:%d\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_close succeed\n"); ++ ++ BTIF_INFO_FUNC("--\n"); ++ return i_ret; ++} ++ ++static int btif_file_open(struct inode *pinode, struct file *pfile) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("pid:%d\n", current->pid); ++ i_ret = 0; ++ return i_ret; ++} ++ ++static int btif_file_release(struct inode *pinode, struct file *pfile) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("pid:%d\n", current->pid); ++ i_ret = 0; ++ return i_ret; ++} ++ ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops) ++{ ++ int i_ret = 0; ++ int rd_len = 0; ++ ++ BTIF_INFO_FUNC("++\n"); ++ down(&rd_mtx); ++ rd_len = btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); ++ while (rd_len == 0) { ++ if (pfile->f_flags & O_NONBLOCK) ++ break; ++ ++ wait_event(btif_wq, rx_notify_flag != 0); ++ rx_notify_flag = 0; ++ rd_len = ++ btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, ++ sizeof(rd_buf)); ++ } ++ ++ if (rd_len == 0) ++ i_ret = 0; ++ else if ((rd_len > 0) && (copy_to_user(buf, rd_buf, rd_len) == 0)) ++ i_ret = rd_len; ++ else ++ i_ret = -EFAULT; ++ ++ up(&rd_mtx); ++ BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++ssize_t btif_file_write(struct file *filp, ++ const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ int i_ret = 0; ++ int copy_size = 0; ++ ++ copy_size = count > sizeof(wr_buf) ? sizeof(wr_buf) : count; ++ ++ BTIF_INFO_FUNC("++\n"); ++ down(&wr_mtx); ++ if (copy_from_user(&wr_buf[0], &buf[0], copy_size)) ++ i_ret = -EFAULT; ++ else ++ i_ret = btif_send_data(&g_btif[0], wr_buf, copy_size); ++ ++ up(&wr_mtx); ++ BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); ++ ++ return i_ret; ++} ++#ifdef CONFIG_COMPAT ++long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ ++ BTIF_INFO_FUNC("cmd[0x%x]\n", cmd); ++ ret = btif_unlocked_ioctl(filp, cmd, arg); ++ return ret; ++} ++#endif ++long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++#define BTIF_IOC_MAGIC 0xb0 ++#define BTIF_IOCTL_OPEN _IOW(BTIF_IOC_MAGIC, 1, int) ++#define BTIF_IOCTL_CLOSE _IOW(BTIF_IOC_MAGIC, 2, int) ++#define BTIF_IOCTL_LPBK_CTRL _IOWR(BTIF_IOC_MAGIC, 3, int) ++#define BTIF_IOCTL_LOG_FUNC_CTRL _IOWR(BTIF_IOC_MAGIC, 4, int) ++#define BTIF_IOCTL_RT_LOG_CTRL _IOWR(BTIF_IOC_MAGIC, 5, int) ++#define BTIF_IOCTL_LOG_DUMP _IOWR(BTIF_IOC_MAGIC, 6, int) ++#define BTIF_IOCTL_REG_DUMP _IOWR(BTIF_IOC_MAGIC, 7, int) ++#define BTIF_IOCTL_DMA_CTRL _IOWR(BTIF_IOC_MAGIC, 8, int) ++ ++ long ret = 0; ++/* unsigned char p_buf[NAME_MAX + 1]; */ ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_INFO_FUNC("++\n"); ++ BTIF_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); ++ ++ switch (cmd) { ++ case BTIF_IOCTL_OPEN: ++ ret = _btif_file_open(); ++ break; ++ case BTIF_IOCTL_CLOSE: ++ ret = _btif_file_close(); ++ break; ++ case BTIF_IOCTL_LPBK_CTRL: ++ ret = btif_lpbk_ctrl(p_btif, arg == 0 ? 0 : 1); ++ break; ++ case BTIF_IOCTL_LOG_FUNC_CTRL: ++ if (arg == 0) { ++ ret += btif_log_buf_disable(&p_btif->tx_log); ++ ret += btif_log_buf_disable(&p_btif->rx_log); ++ } else { ++ ret += btif_log_buf_enable(&p_btif->tx_log); ++ ret += btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_IOCTL_RT_LOG_CTRL: ++ if (arg == 0) { ++ ret += btif_log_output_disable(&p_btif->tx_log); ++ ret += btif_log_output_disable(&p_btif->rx_log); ++ } else { ++ ret += btif_log_output_enable(&p_btif->tx_log); ++ ret += btif_log_output_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_IOCTL_LOG_DUMP: ++ ++ ret += btif_log_buf_dmp_out(&p_btif->tx_log); ++ ret += btif_log_buf_dmp_out(&p_btif->rx_log); ++ break; ++ case BTIF_IOCTL_REG_DUMP: ++ ret += btif_dump_reg(p_btif); ++ break; ++ case BTIF_IOCTL_DMA_CTRL: ++ if (arg == 0) { ++ ret += btif_tx_dma_mode_set(0); ++ ret += btif_rx_dma_mode_set(0); ++ } else { ++ ret += btif_tx_dma_mode_set(1); ++ ret += btif_rx_dma_mode_set(1); ++ } ++ break; ++ default: ++ BTIF_INFO_FUNC("unknown cmd(%d)\n", cmd); ++ ret = -2; ++ break; ++ } ++ BTIF_INFO_FUNC("--\n"); ++ return ret; ++} ++ ++#endif ++ ++/*-----------device property----------------*/ ++//static ssize_t driver_flag_read(struct device_driver *drv, char *buf) ++static ssize_t flag_show(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "btif driver debug level:%d\n", mtk_btif_dbg_lvl); ++} ++ ++//static ssize_t driver_flag_set(struct device_driver *drv, ++static ssize_t flag_store(struct device_driver *drv, ++ const char *buffer, size_t count) ++{ ++ char buf[256]; ++ char *p_buf; ++ unsigned long len = count; ++ long x = 0; ++ long y = 0; ++ long z = 0; ++ int result = 0; ++ char *p_token = NULL; ++ char *p_delimiter = " \t"; ++ ++ BTIF_INFO_FUNC("buffer = %s, count = %zd\n", buffer, count); ++ if (len >= sizeof(buf)) { ++ BTIF_ERR_FUNC("input handling fail!\n"); ++ len = sizeof(buf) - 1; ++ return -1; ++ } ++ ++ memcpy(buf, buffer, sizeof(buf)); ++ p_buf = buf; ++ ++ p_token = strsep(&p_buf, p_delimiter); ++ if (p_token != NULL) { ++ result = kstrtol(p_token, 16, &x); ++ BTIF_INFO_FUNC("x = 0x%08x\n\r", x); ++ } else ++ x = 0; ++/* x = (NULL != p_token) ? kstrtol(p_token, 16, NULL) : 0;*/ ++ ++ p_token = strsep(&p_buf, "\t\n "); ++ if (p_token != NULL) { ++ result = kstrtol(p_token, 16, &y); ++ BTIF_INFO_FUNC("y = 0x%08x\n\r", y); ++ } else ++ y = 0; ++ ++ p_token = strsep(&p_buf, "\t\n "); ++ if (p_token != NULL) ++ result = kstrtol(p_token, 16, &z); ++ else ++ z = 0; ++ ++ BTIF_INFO_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++ ++ switch (x) { ++ case 1: ++ mtk_btif_exp_open_test(); ++ break; ++ case 2: ++ mtk_btif_exp_close_test(); ++ break; ++ case 3: ++ mtk_btif_exp_write_test(); ++ break; ++ case 4: ++ mtk_btif_exp_enter_dpidle_test(); ++ break; ++ case 5: ++ mtk_btif_exp_exit_dpidle_test(); ++ break; ++ case 6: ++ mtk_btif_exp_suspend_test(); ++ break; ++ case 7: ++ mtk_btif_exp_resume_test(); ++ break; ++ case 8: ++ if (y > BTIF_LOG_LOUD) ++ mtk_btif_dbg_lvl = BTIF_LOG_LOUD; ++ else if (y < BTIF_LOG_ERR) ++ mtk_btif_dbg_lvl = BTIF_LOG_WARN; ++ else ++ mtk_btif_dbg_lvl = y; ++ BTIF_ERR_FUNC("mtk_btif_dbg_lvl set to %d\n", mtk_btif_dbg_lvl); ++ break; ++ case 9: ++ mtk_btif_exp_open_test(); ++ mtk_btif_exp_write_test(); ++ mtk_btif_exp_close_test(); ++ break; ++ case 0xa: ++ mtk_btif_exp_log_debug_test(y); ++ break; ++ case 0xb: ++ btif_tx_dma_mode_set(1); ++ btif_rx_dma_mode_set(1); ++ break; ++ case 0xc: ++ btif_tx_dma_mode_set(0); ++ btif_rx_dma_mode_set(0); ++ break; ++ case 0xd: ++ mtk_btif_exp_restore_noirq_test(); ++ break; ++ case 0xe: ++ btif_wakeup_consys_no_id(); ++ break; ++ case 0xf: ++ mtk_btif_exp_clock_ctrl(y); ++ break; ++ case 0x10: ++ y = y > G_MAX_PKG_LEN ? G_MAX_PKG_LEN : y; ++ y = y < 1024 ? 1024 : y; ++ BTIF_INFO_FUNC("g_max_pkg_len is set to %d\n", y); ++ g_max_pkg_len = y; ++ break; ++ case 0x11: ++ y = y > BTIF_RX_BUFFER_SIZE ? BTIF_RX_BUFFER_SIZE : y; ++ y = y < 1024 ? 1024 : y; ++ BTIF_INFO_FUNC("g_max_pding_data_size is set to %d\n", y); ++ g_max_pding_data_size = y; ++ break; ++ default: ++ mtk_btif_exp_open_test(); ++ mtk_btif_exp_write_stress_test(3030, 1); ++ mtk_btif_exp_close_test(); ++ BTIF_WARN_FUNC("not supported.\n"); ++ break; ++ } ++ ++ return count; ++} ++ ++//FWU: driver_ATTR dropped in 4.14 ++//static DRIVER_ATTR(flag, S_IRUGO | S_IWUSR, driver_flag_read, driver_flag_set); ++static DRIVER_ATTR_RW(flag); ++ ++/*-----------End of platform bus related operation APIs------------*/ ++ ++/*-----------------------platform driver ----------------*/ ++ ++int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, ++ mtk_btif_irq_handler irq_handler, void *data) ++{ ++ int i_ret = -1; ++ unsigned int irq_id; ++ unsigned int flag; ++ ++ if ((p_irq == NULL) || (irq_handler == NULL)) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (!(p_irq->is_irq_sup)) { ++ BTIF_WARN_FUNC("%s is not supported\n", p_irq->name); ++ return 0; ++ } ++ ++ irq_id = p_irq->irq_id; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; ++ else ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_FALLING; ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_LOW; ++ break; ++ default: ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_LOW; ++ break; ++ } ++#endif ++ ++ p_irq->p_irq_handler = irq_handler; ++ i_ret = request_irq(irq_id, ++ (irq_handler_t) irq_handler, ++ flag, p_irq->name, data); ++ if (i_ret) ++ return i_ret; ++ ++ p_irq->reg_flag = true; ++ return 0; ++} ++ ++int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data) ++{ ++ int i_ret = 0; ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if ((p_irq->is_irq_sup) && (p_irq->reg_flag)) { ++ _btif_irq_ctrl(p_irq, false); ++ free_irq(eint_num, data); ++ p_irq->reg_flag = false; ++ } ++/*do nothing for this operation*/ ++ return i_ret; ++} ++ ++int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en) ++{ ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if (en) ++ enable_irq(eint_num); ++ else ++ disable_irq_nosync(eint_num); ++ ++ return 0; ++} ++ ++int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en) ++{ ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if (en) ++ enable_irq(eint_num); ++ else ++ disable_irq(eint_num); ++ ++ return 0; ++} ++ ++ ++irqreturn_t btif_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++/*Chaozhong: do we need lock here?*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ ++ _btif_irq_ctrl(p_btif->p_btif_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_btif_irq_handler(p_btif->p_btif_info, NULL, 0); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_irq_ctrl(p_btif->p_btif_info->p_irq, true); ++ _btif_rx_btm_sched(p_btif); ++ ++ BTIF_DBG_FUNC("--\n"); ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t btif_tx_dma_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ p_mtk_btif_dma p_tx_dma = p_btif->p_tx_dma; ++ P_MTK_DMA_INFO_STR p_dma_info = p_tx_dma->p_dma_info; ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ _btif_irq_ctrl(p_dma_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_tx_dma_irq_handler(p_dma_info); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++#endif ++ _btif_irq_ctrl(p_dma_info->p_irq, true); ++ BTIF_DBG_FUNC("--\n"); ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t btif_rx_dma_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ p_mtk_btif_dma p_rx_dma = p_btif->p_rx_dma; ++ P_MTK_DMA_INFO_STR p_rx_dma_info = p_rx_dma->p_dma_info; ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ ++ _btif_irq_ctrl(p_rx_dma_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++ hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_rx_dma_irq_handler(p_rx_dma_info, NULL, 0); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_DISABLE); ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_irq_ctrl(p_rx_dma_info->p_irq, true); ++ ++ _btif_rx_btm_sched(p_btif); ++ ++ BTIF_DBG_FUNC("--\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len) ++{ ++ unsigned int index = 0; ++ p_mtk_btif p_btif = &(g_btif[index]); ++ ++#if 0 ++ _btif_dump_memory("", p_buf, buf_len); ++#endif ++ ++ btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); ++/*save DMA Rx packet here*/ ++ if (buf_len > 0) ++ btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); ++ ++ return 0; ++} ++ ++unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len) ++{ ++ unsigned int index = 0; ++ p_mtk_btif p_btif = &(g_btif[index]); ++ ++#if 0 ++ _btif_dump_memory("", p_buf, buf_len); ++#endif ++ btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); ++ ++/*save PIO Rx packet here*/ ++ if (buf_len > 0) ++ btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); ++ ++ return 0; ++} ++ ++bool btif_parser_wmt_evt(p_mtk_btif p_btif, ++ const char *sub_str, ++ unsigned int str_len) ++{ ++ unsigned int data_cnt = 0; ++ unsigned int copy_cnt = 0; ++ char *local_buf = NULL; ++ bool b_ret = false; ++ p_btif_buf_str p_bbs = &(p_btif->btif_buf); ++ unsigned int wr_idx = p_bbs->wr_idx; ++ unsigned int rd_idx = p_bbs->rd_idx; ++ ++ data_cnt = copy_cnt = BBS_COUNT(p_bbs); ++ ++ if (data_cnt < str_len) { ++ BTIF_WARN_FUNC("there is not enough data for parser,need(%d),have(%d)\n", str_len, data_cnt); ++ return false; ++ } ++ BTIF_INFO_FUNC("data count in bbs buffer:%d,wr_idx(%d),rd_idx(%d)\n", data_cnt, wr_idx, rd_idx); ++ local_buf = vmalloc((data_cnt + 3) & ~0x3UL); ++ if (!local_buf) { ++ BTIF_WARN_FUNC("vmalloc memory fail\n"); ++ return false; ++ } ++ ++ if (wr_idx >= rd_idx) { ++ memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), copy_cnt); ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - rd_idx; ++ ++ BTIF_INFO_FUNC("tail_Len(%d)\n", tail_len); ++ memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), tail_len); ++ memcpy(local_buf + tail_len, BBS_PTR(p_bbs, 0), copy_cnt - tail_len); ++ } ++ ++ do { ++ int i = 0; ++ int j = 0; ++ int k = 0; ++ int d = 0; ++ ++ BTIF_INFO_FUNC("sub_str_len:%d\n", str_len); ++ for (i = 0; i < copy_cnt; i++) { ++ BTIF_DBG_FUNC("i:%d\n", i); ++ k = i; ++ while (1) { ++ if ((j >= str_len) || (k >= copy_cnt) || (sub_str[j++] != local_buf[k++])) ++ break; ++ } ++ ++ if (j == str_len) { ++ for (d = i; d < (str_len + i); d++) ++ BTIF_INFO_FUNC("0x%2x", local_buf[d]); ++ BTIF_INFO_FUNC("find sub str index:%d\n", i); ++ b_ret = true; ++ break; ++ } ++ if (j < str_len) ++ j = 0; ++ } ++ ++ } while (0); ++ ++ vfree(local_buf); ++ return b_ret; ++} ++int _btif_controller_tx_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_tx_dma_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_setup failed,i_ret(%d),", ++ "set tx to PIO mode\n", i_ret); ++ i_ret = _btif_tx_pio_setup(p_btif); ++ } ++ } else ++/*enable Tx PIO mode*/ ++ i_ret = _btif_tx_pio_setup(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_controller_tx_free(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_tx_dma_free(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_free failed, i_ret(%d)\n", ++ i_ret); ++ } ++ } else { ++/*do nothing for Tx PIO mode*/ ++ } ++ return i_ret; ++} ++ ++int _btif_controller_rx_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_rx_dma_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_setup failed, i_ret(%d),", ++ "set tx to PIO mode\n", i_ret); ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } ++ } else { ++/*enable Tx PIO mode*/ ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } ++ return i_ret; ++} ++ ++int _btif_controller_rx_free(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_rx_dma_free(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_rx_dma_free failed, i_ret(%d)\n", ++ i_ret); ++ } ++ } else { ++/*do nothing for Rx PIO mode*/ ++ } ++ return i_ret; ++} ++ ++int _btif_tx_pio_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++/*set Tx to PIO mode*/ ++ p_btif->tx_mode = BTIF_MODE_PIO; ++/*enable Tx PIO mode*/ ++ i_ret = hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); ++ return i_ret; ++} ++ ++int _btif_rx_pio_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; ++ ++ p_btif->rx_mode = BTIF_MODE_PIO; ++/*Enable Rx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, true); ++/*enable Rx PIO mode*/ ++ i_ret = hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); ++ return i_ret; ++} ++ ++int _btif_rx_dma_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = NULL; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = NULL; ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; ++ ++ p_btif_info = p_btif->p_btif_info; ++ p_btif_irq = p_dma_info->p_irq; ++ ++/*vFIFO reset*/ ++ hal_btif_vfifo_reset(p_dma_info); ++ ++ i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d),", ++ "set rx to pio mode\n", i_ret); ++/*DMA control failed set Rx to PIO mode*/ ++ return _btif_rx_pio_setup(p_btif); ++ } ++/*hardware init*/ ++ hal_btif_dma_hw_init(p_dma_info); ++ ++ hal_btif_dma_rx_cb_reg(p_dma_info, ++ (dma_rx_buf_write) btif_dma_rx_data_receiver); ++ ++/*DMA controller enable*/ ++ i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", ++ "set rx to pio mode\n", i_ret); ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++/*DMA control failed set Rx to PIO mode*/ ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } else { ++/*enable Rx DMA mode*/ ++ hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); ++ ++/*DMA Rx IRQ register*/ ++ _btif_irq_reg(p_btif_irq, btif_rx_dma_irq_handler, p_btif); ++#if 0 ++/*Enable DMA Rx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, true); ++#endif ++ BTIF_DBG_FUNC("succeed\n"); ++ } ++ return i_ret; ++} ++ ++int _btif_rx_dma_free(p_mtk_btif p_btif) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_rx_dma->p_dma_info->p_irq; ++ ++ hal_btif_dma_rx_cb_reg(p_dma_info, (dma_rx_buf_write) NULL); ++ _btif_irq_free(p_irq, p_btif); ++/*disable BTIF Rx DMA channel*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); ++/*disable clock output*/ ++ return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++} ++ ++int _btif_tx_dma_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_dma_info->p_irq; ++ ++/*vFIFO reset*/ ++ hal_btif_vfifo_reset(p_dma_info); ++ ++ i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d)\n", ++ i_ret); ++ return i_ret; ++ } ++/*DMA controller setup*/ ++ hal_btif_dma_hw_init(p_dma_info); ++ ++/*DMA HW Enable*/ ++ i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", ++ "set tx to pio mode\n", i_ret); ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_tx_pio_setup(p_btif); ++ } else { ++ hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); ++/*DMA Tx IRQ register*/ ++ _btif_irq_reg(p_btif_irq, btif_tx_dma_irq_handler, p_btif); ++#if 0 ++/*disable DMA Tx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, false); ++#endif ++ ++ BTIF_DBG_FUNC("succeed\n"); ++ } ++ return i_ret; ++} ++ ++int _btif_tx_dma_free(p_mtk_btif p_btif) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_tx_dma->p_dma_info->p_irq; ++ ++ _btif_irq_free(p_irq, p_btif); ++/*disable BTIF Tx DMA channel*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); ++/*disable clock output*/ ++ return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++} ++ ++int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) ++{ ++ int i_ret = -1; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++#if 0 ++ state = _btif_state_get(p_btif); ++ if (p_btif->enable && B_S_ON == state) ++ i_ret = _btif_lpbk_ctrl(p_btif, flag); ++ else ++ i_ret = E_BTIF_INVAL_STATE; ++#endif ++ i_ret = _btif_exit_dpidle(p_btif); ++ if (i_ret == 0) ++ i_ret = _btif_lpbk_ctrl(p_btif, flag); ++ else ++ i_ret = E_BTIF_INVAL_STATE; ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) ++{ ++ int i_ret = -1; ++ ++ if (flag) { ++ i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, true); ++ BTIF_DBG_FUNC("loopback function enabled\n"); ++ } else { ++ i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, false); ++ BTIF_DBG_FUNC("loopback function disabled\n"); ++ } ++ if (i_ret == 0) ++ p_btif->lpbk_flag = flag; ++ ++ return i_ret; ++} ++ ++int btif_clock_ctrl(p_mtk_btif p_btif, int en) ++{ ++ int i_ret = 0; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ENUM_CLOCK_CTRL ctrl_flag = en == 0 ? CLK_OUT_DISABLE : CLK_OUT_ENABLE; ++ ++ i_ret = hal_btif_clk_ctrl(p_btif_info, ctrl_flag); ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ctrl_flag); ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ctrl_flag); ++ ++ return i_ret; ++} ++ ++int _btif_controller_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; ++ ++/*BTIF rx buffer init*/ ++/* memset(p_btif->rx_buf, 0, BTIF_RX_BUFFER_SIZE); */ ++ BBS_INIT(&(p_btif->btif_buf)); ++/************************************************/ ++ hal_btif_rx_cb_reg(p_btif_info, ++ (btif_rx_buf_write) btif_pio_rx_data_receiver); ++ ++ i_ret = hal_btif_clk_ctrl(p_btif_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_clk_ctrl failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++/*BTIF controller init*/ ++ i_ret = hal_btif_hw_init(p_btif_info); ++ if (i_ret) { ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++ BTIF_ERR_FUNC("hal_btif_hw_init failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++ _btif_lpbk_ctrl(p_btif, p_btif->lpbk_flag); ++/*BTIF IRQ register*/ ++ i_ret = _btif_irq_reg(p_btif_irq, btif_irq_handler, p_btif); ++ if (i_ret) { ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++ ++ BTIF_ERR_FUNC("_btif_irq_reg failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++ ++/*disable IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, false); ++ i_ret = 0; ++ BTIF_DBG_FUNC("succeed\n"); ++ return i_ret; ++} ++ ++int _btif_controller_free(p_mtk_btif p_btif) ++{ ++/*No need to set BTIF to PIO mode, only enable BTIF CG*/ ++ hal_btif_rx_cb_reg(p_btif->p_btif_info, (btif_rx_buf_write) NULL); ++ _btif_irq_free(p_btif->p_btif_info->p_irq, p_btif); ++ return hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++} ++ ++int _btif_init(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ i_ret = _btif_controller_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_init failed, i_ret(%d)\n", ++ i_ret); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ ++ i_ret = _btif_controller_tx_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", ++ i_ret); ++ _btif_controller_free(p_btif); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ ++ i_ret = _btif_controller_rx_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", ++ i_ret); ++ _btif_controller_tx_free(p_btif); ++ _btif_controller_free(p_btif); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ return i_ret; ++} ++ ++int btif_open(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->enable) ++ return E_BTIF_ALREADY_OPEN; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++/*disable deepidle*/ ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); ++ ++ i_ret = _btif_init(p_btif); ++ if (i_ret == 0) { ++ /*set BTIF's enable flag*/ ++ p_btif->enable = true; ++ _btif_state_set(p_btif, B_S_ON); ++ } else { ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ } ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ ++ BTIF_DBG_FUNC("BTIF's Tx Mode:%d, Rx Mode(%d)\n", ++ p_btif->tx_mode, p_btif->rx_mode); ++ return i_ret; ++} ++ ++int btif_close(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ if (!(p_btif->enable)) ++ return E_BTIF_NOT_OPEN; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++/*always set state back to B_S_ON before do close operation*/ ++ _btif_exit_dpidle(p_btif); ++/*set BTIF's state to disable state*/ ++ p_btif->enable = false; ++ ++ _btif_controller_free(p_btif); ++ _btif_controller_tx_free(p_btif); ++ _btif_controller_rx_free(p_btif); ++ ++/*reset BTIF's rx_cb function*/ ++ p_btif->rx_cb = NULL; ++ p_btif->rx_notify = NULL; ++ p_btif->lpbk_flag = false; ++ ++/*set state mechine to B_S_OFF*/ ++ _btif_state_set(p_btif, B_S_OFF); ++ ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_exit_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ state = _btif_state_get(p_btif); ++ switch (state) { ++ case B_S_DPIDLE: ++ i_ret = _btif_exit_dpidle_from_dpidle(p_btif); ++ break; ++ case B_S_SUSPEND: ++/*in suspend state, need to do reinit of btif*/ ++ i_ret = _btif_exit_dpidle_from_sus(p_btif); ++ break; ++ case B_S_OFF: ++ i_ret = _btif_init(p_btif); ++ break; ++ case B_S_ON: ++ i_ret = 0; /* for btif_close case */ ++ break; ++ default: ++ i_ret = E_BTIF_INVAL_PARAM; ++ BTIF_INFO_FUNC("invalid state change:%d->\n", state, B_S_ON); ++ break; ++ } ++ ++ if (i_ret == 0) ++ i_ret = _btif_state_set(p_btif, B_S_ON); ++ return i_ret; ++} ++ ++int btif_exit_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ i_ret = _btif_exit_dpidle(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_enter_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ state = _btif_state_get(p_btif); ++ if (state == B_S_ON) { ++ i_ret = _btif_enter_dpidle_from_on(p_btif); ++ } else if (state == B_S_SUSPEND) { ++ /*do reinit and enter deepidle*/ ++ i_ret = _btif_enter_dpidle_from_sus(p_btif); ++ } else if (state == B_S_DPIDLE) { ++ /*do nothing*/ ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("operation is not allowed, current state:%d\n", ++ state); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++/*anyway, set to B_S_DPIDLE state*/ ++ if (i_ret == 0) ++ i_ret = _btif_state_set(p_btif, B_S_DPIDLE); ++ return i_ret; ++} ++ ++int btif_enter_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ i_ret = _btif_enter_dpidle(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*in dpidle state, only need to open related clock*/ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*enable BTIF Tx DMA's clock*/ ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ++ CLK_OUT_ENABLE); ++ } ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ /*enable BTIF Rx DMA's clock*/ ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ++ CLK_OUT_ENABLE); ++ } ++/*enable BTIF's clock*/ ++ i_ret += hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++ ++ if (i_ret != 0) ++ BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif) ++{ ++/*in suspend state, need to do driver re-init*/ ++ ++ int i_ret = _btif_init(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif) ++{ ++/*do driiver reinit*/ ++ int i_ret = _btif_init(p_btif); ++ ++ if (i_ret == 0) ++ i_ret = _btif_enter_dpidle_from_on(p_btif); ++ return i_ret; ++} ++ ++int _btif_enter_dpidle_from_on(p_mtk_btif p_btif) ++{ ++#define MAX_WAIT_TIME_MS 5000 ++/* ++ * this max wait time cannot exceed 12s, ++ * because dpm will monitor each device's ++ * resume/suspend process by start up a watch dog timer of 12s ++ * incase of one driver's suspend/resume process block other device's suspend/resume ++ */ ++ int i_ret = 0; ++ unsigned int retry = 0; ++ unsigned int wait_period = 1; ++ unsigned int max_retry = MAX_WAIT_TIME_MS / wait_period; ++ struct timeval timer_start; ++ struct timeval timer_now; ++ ++ do_gettimeofday(&timer_start); ++ ++ while ((!_btif_is_tx_complete(p_btif)) && (retry < max_retry)) { ++ do_gettimeofday(&timer_now); ++ if ((MAX_WAIT_TIME_MS/1000) <= (timer_now.tv_sec - timer_start.tv_sec)) { ++ BTIF_WARN_FUNC("max retry timer expired, timer_start.tv_sec:%d, timer_now.tv_sec:%d,", ++ "retry:%d\n", timer_start.tv_sec, timer_now.tv_sec, retry); ++ break; ++ } ++ msleep(wait_period); ++ retry++; ++ } ++ ++ if (retry < max_retry) { ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*disable BTIF Tx DMA's clock*/ ++ i_ret += ++ hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ } ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ /*disable BTIF Rx DMA's clock*/ ++ i_ret += ++ hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ } ++/*disable BTIF's clock*/ ++ i_ret += ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++ ++ if (i_ret) ++ BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); ++ } else ++ i_ret = -1; ++ ++ return i_ret; ++} ++ ++int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++/*call WCP's API to control deepidle's enable/disable*/ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_DIS); ++ else ++ hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_EN); ++ ++ return 0; ++} ++ ++int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ if (p_btif->rx_cb) { ++ BTIF_WARN_FUNC ++ ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", ++ p_btif->rx_cb, rx_cb); ++ } ++ p_btif->rx_cb = rx_cb; ++ ++ return 0; ++} ++ ++int btif_raise_wak_signal(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++#endif ++ ++ i_ret = hal_btif_raise_wak_sig(p_btif_info); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++#endif ++ return i_ret; ++} ++ ++bool _btif_is_tx_complete(p_mtk_btif p_btif) ++{ ++ bool b_ret = false; ++ ENUM_BTIF_MODE tx_mode = p_btif->tx_mode; ++ ++/* ++ * make sure BTIF tx finished in PIO mode ++ * make sure BTIF tx finished and DMA tx finished in DMA mode ++ */ ++ if (tx_mode == BTIF_MODE_DMA) { ++ b_ret = hal_dma_is_tx_complete(p_btif->p_tx_dma->p_dma_info); ++ if (b_ret == false) { ++ BTIF_DBG_FUNC("Tx DMA is not finished\n"); ++ return b_ret; ++ } ++ } ++ ++ b_ret = hal_btif_is_tx_complete(p_btif->p_btif_info); ++ if (b_ret == false) { ++ BTIF_DBG_FUNC("BTIF Tx is not finished\n"); ++ return b_ret; ++ } ++ b_ret = true; ++ return b_ret; ++} ++ ++/*--------------------------------Functions-------------------------------------------*/ ++ ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_init(p_mtk_btif_dma p_dma) ++{ ++ P_DMA_VFIFO p_vfifo = NULL; ++ struct device *dev = NULL; ++ p_mtk_btif p_btif = NULL; ++ ++ if (p_dma == NULL) { ++ BTIF_ERR_FUNC("p_dma is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ p_btif = (p_mtk_btif)p_dma->p_btif; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ dev = (struct device *)p_btif->private_data; ++ if (dev == NULL) ++ BTIF_WARN_FUNC("Null dev pointer!!!!\n"); ++ ++ p_vfifo = p_dma->p_dma_info->p_vfifo; ++ if (p_vfifo->p_vir_addr != NULL) { ++ BTIF_ERR_FUNC ++ ("BTIF vFIFO memory already allocated, do nothing\n"); ++ return E_BTIF_BAD_POINTER; ++ } ++ ++/*vFIFO memory allocation*/ ++ p_vfifo->p_vir_addr = dma_zalloc_coherent(dev, ++ p_vfifo->vfifo_size, ++ &p_vfifo->phy_addr, GFP_DMA | GFP_DMA32); ++ if (p_vfifo->p_vir_addr == NULL) { ++ BTIF_ERR_FUNC("alloc vFIFO memory for BTIF failed\n"); ++ return E_BTIF_FAIL; ++ } ++ ++ if (sizeof(dma_addr_t) == sizeof(unsigned long long)) ++ BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch64,vir addr:0x%p,", ++ "phy addr:0x%llx\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ else ++ BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch32,vir addr:0x%p,", ++ "phy addr:0x%08x\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ ++ return 0; ++} ++#endif ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma) ++{ ++ P_DMA_VFIFO p_vfifo = NULL; ++ struct device *dev = NULL; ++ p_mtk_btif p_btif = NULL; ++ ++ if (p_dma == NULL) { ++ BTIF_ERR_FUNC("p_dma is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ ++ p_btif = (p_mtk_btif)p_dma->p_btif; ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ dev = (struct device *)p_btif->private_data; ++ if (dev == NULL) ++ BTIF_WARN_FUNC("Null dev pointer!!!!\n"); ++ ++ p_vfifo = p_dma->p_dma_info->p_vfifo; ++ ++/*free DMA memory if allocated successfully before*/ ++ if (p_vfifo->p_vir_addr != NULL) { ++ dma_free_coherent(dev, ++ p_vfifo->vfifo_size, ++ p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ p_vfifo->p_vir_addr = NULL; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int _btif_state_init(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ p_btif->state = B_S_OFF; ++ mutex_init(&(p_btif->state_mtx)); ++ ++ return 0; ++} ++ ++static int _btif_state_hold(p_mtk_btif p_btif) ++{ ++ return mutex_lock_killable(&(p_btif->state_mtx)); ++} ++ ++static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state) ++{ ++/*chaozhong: To do: need to finished state mechine here*/ ++ int i_ret = 0; ++ int ori_state = p_btif->state; ++ ++ if (ori_state == state) { ++ BTIF_INFO_FUNC("already in %s state\n", g_state[state]); ++ return i_ret; ++ } ++ if ((state >= B_S_OFF) && (state < B_S_MAX)) { ++ BTIF_DBG_FUNC("%s->%s request\n", g_state[ori_state], ++ g_state[state]); ++ if (state == B_S_ON) ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); ++ switch (ori_state) { ++ case B_S_ON: ++/*B_S_ON can only be switched to B_S_OFF, B_S_SUSPEND and B_S_DPIDLE*/ ++/*B_S_ON->B_S_OFF : do nothing here*/ ++/* ++ * B_S_ON->B_S_DPLE : disable clock backup ++ * BTIF and DMA controller's register if necessary ++ */ ++ if (state == B_S_DPIDLE) { ++ /*clock controlled id done in _btif_enter_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_OFF) { ++ /*clock controlled is done in btif_close*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_SUSPEND) { ++ /*clock controlled is done in btif_close*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ case B_S_DPIDLE: ++/*B_S_DPIDLE can only be switched to B_S_ON and B_S_SUSPEND*/ ++/*B_S_DPIDLE-> B_S_ON: do nothing for this moment*/ ++/* ++ * B_S_DPIDLE-> B_S_SUSPEND: ++ * disable clock backup BTIF and DMA controller's register if necessary ++ */ ++ if (state == B_S_ON) { ++ /*clock controlled id done in _btif_exit_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_SUSPEND) { ++ /*clock controlled is done in _btif_exit_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ ++ case B_S_SUSPEND: ++/*B_S_SUSPEND can be switched to B_S_IDLE and B_S_ON*/ ++/*reinit BTIF controller and DMA controller*/ ++ if (state == B_S_DPIDLE) { ++ /* ++ * system call resume API, do resume operation, ++ * change to deepidle state ++ */ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_ON) { ++ /* ++ * when stp want to send data before ++ * system do resume operation ++ */ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ ++ case B_S_OFF:{ ++/*B_S_OFF can only be switched to B_S_ON*/ ++ if (state == B_S_ON) { ++ /*clock controlled is done in btif_open*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ } ++ break; ++ default: ++/*no this possibility*/ ++ BTIF_ERR_FUNC ++ ("state change request is not allowed, this should never happen\n"); ++ break; ++ } ++ ++ if (state != B_S_ON) ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ ++ } else { ++ i_ret = E_BTIF_INVAL_PARAM; ++ BTIF_ERR_FUNC("invalid state:%d, do nothing\n", state); ++ } ++ return i_ret; ++} ++ ++static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif) ++{ ++ return p_btif->state; ++} ++ ++static int _btif_state_release(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ BTIF_MUTEX_UNLOCK(&(p_btif->state_mtx)); ++ return i_ret; ++} ++ ++static int _btif_state_deinit(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ p_btif->state = B_S_OFF; ++ mutex_destroy(&(p_btif->state_mtx)); ++ ++ return 0; ++} ++ ++static int btif_rx_data_consummer(p_mtk_btif p_btif) ++{ ++ unsigned int length = 0; ++ unsigned char *p_buf = NULL; ++/*get BTIF rx buffer's information*/ ++ p_btif_buf_str p_bbs = &(p_btif->btif_buf); ++/* ++ * wr_idx of btif_buf may be modified in IRQ handler, ++ * in order not to be effected by case in which irq interrupt this operation, ++ * we record wr_idx here ++ */ ++ unsigned int wr_idx = p_bbs->wr_idx; ++ ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ ++/*make sure length of rx buffer data > 0*/ ++ do { ++ if (length > 0) { ++ /* ++ * check if rx_cb empty or not, if registered , ++ * call user's rx callback to handle these data ++ */ ++ if (p_btif->rx_cb) { ++ if (p_bbs->rd_idx <= wr_idx) { ++ p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); ++ /* p_buf = &(p_bbs->buf[p_bbs->rd_idx]); */ ++ /* length = BBS_COUNT(p_bbs); */ ++ length = (wr_idx >= (p_bbs)->rd_idx) ? ++ (wr_idx - (p_bbs)->rd_idx) : ++ BBS_SIZE(p_bbs) - ++ ((p_bbs)->rd_idx - wr_idx); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, length); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ /*update rx data read index*/ ++ p_bbs->rd_idx = wr_idx; ++ } else { ++ unsigned int len_tail = ++ BBS_SIZE(p_bbs) - (p_bbs)->rd_idx; ++ /*p_buf = &(p_bbs->buf[p_bbs->->rd_idx]);*/ ++ p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, len_tail); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ length -= len_tail; ++ /*p_buf = &(p_bbs->buf[0]);*/ ++ p_buf = BBS_PTR(p_bbs, 0); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, length); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ /*update rx data read index*/ ++ p_bbs->rd_idx = wr_idx; ++ } ++ } else if (p_btif->rx_notify != NULL) { ++ (*p_btif->rx_notify) (); ++ } else { ++ BTIF_WARN_FUNC ++ ("p_btif:0x%p, both rx_notify and rx_cb are NULL\n", ++ p_btif); ++ break; ++ } ++ } else { ++ BTIF_DBG_FUNC("length:%d\n", length); ++ break; ++ } ++ wr_idx = p_bbs->wr_idx; ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ } while (1); ++ return length; ++} ++ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++static int mtk_btif_rxd_be_blocked_by_timer(void) ++{ ++ int ret = 0; ++ int counter = 0; ++ unsigned int i; ++ struct timeval now; ++ int time_gap[MAX_BTIF_RXD_TIME_REC]; ++ ++ do_gettimeofday(&now); ++ ++ for (i = 0; i < MAX_BTIF_RXD_TIME_REC; i++) { ++ BTIF_INFO_FUNC("btif_rxd_time_stamp[%d]=%d.%d\n", i, ++ btif_rxd_time_stamp[i].tv_sec, btif_rxd_time_stamp[i].tv_usec); ++ if (now.tv_sec >= btif_rxd_time_stamp[i].tv_sec) { ++ time_gap[i] = now.tv_sec - btif_rxd_time_stamp[i].tv_sec; ++ time_gap[i] *= 1000000; /*second*/ ++ if (now.tv_usec >= btif_rxd_time_stamp[i].tv_usec) ++ time_gap[i] += now.tv_usec - btif_rxd_time_stamp[i].tv_usec; ++ else ++ time_gap[i] += 1000000 - now.tv_usec + btif_rxd_time_stamp[i].tv_usec; ++ ++ if (time_gap[i] > 1000000) ++ counter++; ++ BTIF_INFO_FUNC("time_gap[%d]=%d,counter:%d\n", i, time_gap[i], counter); ++ } else { ++ time_gap[i] = 0; ++ BTIF_ERR_FUNC("abnormal case now:%d < time_stamp[%d]:%d\n", now.tv_sec, ++ i, btif_rxd_time_stamp[i].tv_usec); ++ } ++ } ++ if (counter > (MAX_BTIF_RXD_TIME_REC - 2)) ++ ret = 1; ++ return ret; ++} ++static int mtk_btif_rxd_be_blocked_by_data(void) ++{ ++ unsigned int out_index = 0; ++ unsigned int in_index = 0; ++ unsigned int dump_size = 0; ++ unsigned int len = 0; ++ unsigned long flags; ++ unsigned int sync_pkt_n = 0; ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ P_BTIF_LOG_QUEUE_T p_log_que = NULL; ++ p_mtk_btif p_btif = &(g_btif[0]); ++ ++ p_log_que = &p_btif->rx_log; ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ in_index = p_log_que->in; ++ dump_size = p_log_que->size; ++ out_index = p_log_que->size >= ++ BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - ++ p_log_que->size + ++ in_index) % BTIF_LOG_ENTRY_NUM; ++ if (dump_size != 0) { ++ while (dump_size--) { ++ p_log_buf = p_log_que->p_queue[0] + out_index; ++ len = p_log_buf->len; ++ if (len > BTIF_LOG_SZ) ++ len = BTIF_LOG_SZ; ++ if ((0x7f == *(p_log_buf->buffer)) && (0x7f == *(p_log_buf->buffer + 1))) { ++ sync_pkt_n++; ++ BTIF_INFO_FUNC("tx pkt_count:%d is sync pkt\n", out_index); ++ } ++ out_index++; ++ out_index %= BTIF_LOG_ENTRY_NUM; ++ } ++ } ++ if (sync_pkt_n == 0) ++ BTIF_ERR_FUNC("there is no sync pkt in BTIF buffer\n"); ++ else ++ BTIF_ERR_FUNC("there are %d sync pkt in BTIF buffer\n", sync_pkt_n); ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ return sync_pkt_n; ++} ++ ++int mtk_btif_rxd_be_blocked_flag_get(void) ++{ ++ int ret = 0; ++ int condition1 = 0, condition2 = 0; ++ ++ condition1 = mtk_btif_rxd_be_blocked_by_timer(); ++ condition2 = mtk_btif_rxd_be_blocked_by_data(); ++ if (condition1 && condition2) { ++ BTIF_ERR_FUNC("btif_rxd thread be blocked too long!\n"); ++ ret = 1; ++ } ++ return ret; ++} ++#endif ++static int btif_rx_thread(void *p_data) ++{ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++ unsigned int i = 0; ++#endif ++ p_mtk_btif p_btif = (p_mtk_btif)p_data; ++ ++ ++ while (1) { ++ wait_for_completion_interruptible(&p_btif->rx_comp); ++ ++ if (kthread_should_stop()) { ++ BTIF_WARN_FUNC("btif rx thread stoping ...\n"); ++ break; ++ } ++#ifdef BTIF_RXD_BE_BLOCKED_DETECT ++ do_gettimeofday(&btif_rxd_time_stamp[i]); ++ i++; ++ if (i >= MAX_BTIF_RXD_TIME_REC) ++ i = 0; ++#endif ++ btif_rx_data_consummer(p_btif); ++ } ++ return 0; ++} ++ ++static void btif_rx_worker(struct work_struct *p_work) ++{ ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = container_of(p_work, mtk_btif, rx_work); ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++/*lock rx_mutex*/ ++ ++ if (mutex_lock_killable(&(p_btif->rx_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return; ++ } ++ btif_rx_data_consummer(p_btif); ++ BTIF_MUTEX_UNLOCK(&(p_btif->rx_mtx)); ++} ++ ++static void btif_tx_worker(struct work_struct *p_work) ++{ ++ int i_ret = 0; ++ int leng_sent = 0; ++/*tx fifo out*/ ++ int how_much_get = 0; ++ unsigned char local_buf[384]; ++ ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = container_of(p_work, mtk_btif, tx_work); ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++ ++ if (mutex_lock_killable(&(p_btif->tx_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return; ++ } ++ how_much_get = ++ kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); ++ do { ++ while (leng_sent < how_much_get) { ++ i_ret = _btif_send_data(p_btif, ++ local_buf + leng_sent, ++ how_much_get - leng_sent); ++ if (i_ret > 0) { ++ leng_sent += i_ret; ++ } else if (i_ret == 0) { ++ BTIF_WARN_FUNC ++ ("_btif_send_data return 0, retry\n"); ++ } else { ++ BTIF_WARN_FUNC ++ ("btif send data fail,reset tx fifo, i_ret(%d)\n", ++ i_ret); ++ kfifo_reset(p_btif->p_tx_fifo); ++ break; ++ } ++ } ++ how_much_get = ++ kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); ++ leng_sent = 0; ++ } while (how_much_get > 0); ++ BTIF_MUTEX_UNLOCK(&(p_btif->tx_mtx)); ++} ++ ++static void btif_rx_tasklet(unsigned long func_data) ++{ ++ unsigned long flags; ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = (p_mtk_btif) func_data; ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++/*lock rx_spinlock*/ ++ spin_lock_irqsave(&p_btif->rx_tasklet_spinlock, flags); ++ btif_rx_data_consummer(p_btif); ++ spin_unlock_irqrestore(&p_btif->rx_tasklet_spinlock, flags); ++} ++ ++static int _btif_tx_ctx_init(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ p_btif->p_tx_wq = create_singlethread_workqueue("btif_txd"); ++ ++ if (!(p_btif->p_tx_wq)) { ++ BTIF_ERR_FUNC ++ ("create_singlethread_workqueue for tx thread fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ mutex_init(&(p_btif->tx_mtx)); ++/* init btif tx work */ ++ INIT_WORK(&(p_btif->tx_work), btif_tx_worker); ++ BTIF_INFO_FUNC("btif_tx_worker init succeed\n"); ++ ++ p_btif->p_tx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); ++ if (p_btif->p_tx_fifo == NULL) { ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); ++ goto btm_init_err; ++ } ++ ++ i_ret = kfifo_alloc(p_btif->p_tx_fifo, ++ BTIF_TX_FIFO_SIZE, GFP_ATOMIC); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ } else if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { ++ BTIF_INFO_FUNC ++ ("nothing is done when btif tx in user's thread\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported tx context type:%d\n", ++ p_btif->tx_ctx); ++ goto btm_init_err; ++ } ++ ++ BTIF_INFO_FUNC("succeed\n"); ++ ++ i_ret = 0; ++ return i_ret; ++btm_init_err: ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ if (p_btif->p_tx_wq) { ++ destroy_workqueue(p_btif->p_tx_wq); ++ p_btif->p_tx_wq = NULL; ++ BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); ++ } ++ kfree(p_btif->p_tx_fifo); ++ } ++ return i_ret; ++} ++ ++static int _btif_tx_ctx_deinit(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ if (p_btif->p_tx_wq) { ++ destroy_workqueue(p_btif->p_tx_wq); ++ p_btif->p_tx_wq = NULL; ++ BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); ++ } ++ if (p_btif->p_tx_fifo) { ++ kfifo_free(p_btif->p_tx_fifo); ++ kfree(p_btif->p_tx_fifo); ++ p_btif->p_tx_fifo = NULL; ++ } ++ } ++ return i_ret; ++} ++ ++static int _btif_rx_btm_init(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ init_completion(&p_btif->rx_comp); ++ ++ /*create kernel thread for later rx data handle*/ ++ p_btif->p_task = kthread_create(btif_rx_thread, p_btif, "btif_rxd"); ++ if (p_btif->p_task == NULL) { ++ BTIF_ERR_FUNC("kthread_create fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ ++#if ENABLE_BTIF_RX_THREAD_RT_SCHED ++ { ++ int i_ret = -1; ++ int policy = SCHED_FIFO; ++ struct sched_param param; ++ ++ param.sched_priority = MAX_RT_PRIO - 20; ++ i_ret = sched_setscheduler(p_btif->p_task, policy, ¶m); ++ if (i_ret != 0) ++ BTIF_WARN_FUNC("set RT to btif_rxd workqueue failed\n"); ++ else ++ BTIF_INFO_FUNC("set RT to btif_rxd workqueue succeed\n"); ++ } ++#endif ++ ++ wake_up_process(p_btif->p_task); ++ BTIF_INFO_FUNC("btif_rxd start to work!\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ p_btif->p_rx_wq = create_singlethread_workqueue("btif_rxwq"); ++ if (!(p_btif->p_rx_wq)) { ++ BTIF_ERR_FUNC("create_singlethread_workqueue fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ mutex_init(&(p_btif->rx_mtx)); ++ /* init btif rx work */ ++ INIT_WORK(&(p_btif->rx_work), btif_rx_worker); ++ BTIF_INFO_FUNC("btif_rx_worker init succeed\n"); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ /*init rx tasklet*/ ++ tasklet_init(&(p_btif->rx_tasklet), btif_rx_tasklet, ++ (unsigned long)p_btif); ++ spin_lock_init(&(p_btif->rx_tasklet_spinlock)); ++ BTIF_INFO_FUNC("btif_rx_tasklet init succeed\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++/*spinlock init*/ ++ spin_lock_init(&(p_btif->rx_irq_spinlock)); ++ BTIF_INFO_FUNC("rx_spin_lock init succeed\n"); ++ ++ i_ret = 0; ++ return i_ret; ++btm_init_err: ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ /*do nothing*/ ++ BTIF_INFO_FUNC("failed\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ if (p_btif->p_rx_wq) { ++ destroy_workqueue(p_btif->p_rx_wq); ++ p_btif->p_rx_wq = NULL; ++ BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); ++ } ++ } ++ return i_ret; ++} ++ ++static int _btif_rx_btm_sched(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ complete(&p_btif->rx_comp); ++ BTIF_DBG_FUNC("schedule btif_rx_thread\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ queue_work(p_btif->p_rx_wq, &(p_btif->rx_work)); ++ BTIF_DBG_FUNC("schedule btif_rx_worker\n"); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ /*schedule it!*/ ++ tasklet_schedule(&(p_btif->rx_tasklet)); ++ BTIF_DBG_FUNC("schedule btif_rx_tasklet\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++ return 0; ++} ++ ++static int _btif_rx_btm_deinit(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ if (p_btif->p_task != NULL) { ++ BTIF_INFO_FUNC("signaling btif rx thread to stop ...\n"); ++ kthread_stop(p_btif->p_task); ++ } ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ if (p_btif->p_rx_wq) { ++ cancel_work_sync(&(p_btif->rx_work)); ++ BTIF_INFO_FUNC("btif_rx_worker cancelled\n"); ++ destroy_workqueue(p_btif->p_rx_wq); ++ p_btif->p_rx_wq = NULL; ++ BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); ++ } ++ mutex_destroy(&(p_btif->rx_mtx)); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ tasklet_kill(&(p_btif->rx_tasklet)); ++ BTIF_INFO_FUNC("rx_tasklet killed\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++ spin_lock_init(&(p_btif->rx_irq_spinlock)); ++ ++ return 0; ++} ++ ++ ++void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs) ++{ ++ BTIF_INFO_FUNC ++ ("%s UBS:0x%p\n Size:0x%p\n read:0x%08x\n write:0x%08x\n", ++ p_str, p_bbs, p_bbs->size, p_bbs->rd_idx, p_bbs->wr_idx); ++} ++ ++unsigned int btif_bbs_write(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++/*in IRQ context, so read operation won't interrupt this operation*/ ++ ++ unsigned int wr_len = 0; ++ ++ unsigned int emp_len = BBS_LEFT(p_bbs); ++ unsigned int ava_len = emp_len - 1; ++ p_mtk_btif p_btif = container_of(p_bbs, mtk_btif, btif_buf); ++ ++ if (ava_len <= 0) { ++ BTIF_ERR_FUNC ++ ("no empty space left for write, (%d)ava_len, (%d)to write\n", ++ ava_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ return 0; ++ } ++ ++ if (ava_len < buf_len) { ++ BTIF_ERR_FUNC("BTIF overrun, (%d)empty, (%d)needed\n", ++ emp_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ } ++ ++ if (buf_len >= g_max_pkg_len) { ++ BTIF_WARN_FUNC("buf_len too long, (%d)ava_len, (%d)to write\n", ++ ava_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ } ++ ++ wr_len = min(buf_len, ava_len); ++ btif_bbs_wr_direct(p_bbs, p_buf, wr_len); ++ ++ if (BBS_COUNT(p_bbs) >= g_max_pding_data_size) { ++ BTIF_WARN_FUNC("Rx buf_len too long, size(%d)\n", ++ BBS_COUNT(p_bbs)); ++ btif_dump_bbs_str("Rx buffer tooo long", p_bbs); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ BBS_INIT(p_bbs); ++ } ++ ++ return wr_len; ++} ++ ++unsigned int btif_bbs_read(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int rd_len = 0; ++ unsigned int ava_len = 0; ++ unsigned int wr_idx = p_bbs->wr_idx; ++ ++ ava_len = BBS_COUNT_CUR(p_bbs, wr_idx); ++ if (ava_len >= 4096) { ++ BTIF_WARN_FUNC("ava_len too long, size(%d)\n", ava_len); ++ btif_dump_bbs_str("Rx buffer tooo long", p_bbs); ++ } ++ if (ava_len != 0) { ++ if (buf_len >= ava_len) { ++ rd_len = ava_len; ++ if (wr_idx >= (p_bbs)->rd_idx) { ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ ava_len); ++ (p_bbs)->rd_idx = wr_idx; ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - ++ (p_bbs)->rd_idx; ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ tail_len); ++ memcpy(p_buf + tail_len, BBS_PTR(p_bbs, ++ 0), ava_len - tail_len); ++ (p_bbs)->rd_idx = wr_idx; ++ } ++ } else { ++ rd_len = buf_len; ++ if (wr_idx >= (p_bbs)->rd_idx) { ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ rd_len); ++ (p_bbs)->rd_idx = (p_bbs)->rd_idx + rd_len; ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - ++ (p_bbs)->rd_idx; ++ if (tail_len >= rd_len) { ++ memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), ++ rd_len); ++ (p_bbs)->rd_idx = ++ ((p_bbs)->rd_idx + rd_len) & (BBS_MASK(p_bbs)); ++ } else { ++ memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), tail_len); ++ memcpy(p_buf + tail_len, ++ (p_bbs)->p_buf, rd_len - tail_len); ++ (p_bbs)->rd_idx = rd_len - tail_len; ++ } ++ } ++ } ++ } ++ mb(); ++ return rd_len; ++} ++ ++unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int tail_len = 0; ++ unsigned int l = 0; ++ unsigned int tmp_wr_idx = p_bbs->wr_idx; ++ ++ tail_len = BBS_SIZE(p_bbs) - (tmp_wr_idx & BBS_MASK(p_bbs)); ++ ++ l = min(tail_len, buf_len); ++ ++ memcpy((p_bbs->p_buf) + (tmp_wr_idx & BBS_MASK(p_bbs)), p_buf, l); ++ memcpy(p_bbs->p_buf, p_buf + l, buf_len - l); ++ ++ mb(); ++ ++ tmp_wr_idx += buf_len; ++ tmp_wr_idx &= BBS_MASK(p_bbs); ++ p_bbs->wr_idx = tmp_wr_idx; ++ ++ mb(); ++ return buf_len; ++} ++ ++int _btif_dma_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int i_ret = 0; ++ unsigned int retry = 0; ++ unsigned int max_tx_retry = 10; ++ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ ++ _btif_irq_ctrl_sync(p_dma_info->p_irq, false); ++ do { ++ /*wait until tx is allowed*/ ++ while (!hal_dma_is_tx_allow(p_dma_info) && ++ (retry < max_tx_retry)) { ++ retry++; ++ if (retry >= max_tx_retry) { ++ BTIF_ERR_FUNC("wait for tx allowed timeout\n"); ++ break; ++ } ++ } ++ if (retry >= max_tx_retry) ++ break; ++ ++ if (buf_len <= hal_dma_get_ava_room(p_dma_info)) ++ i_ret = hal_dma_send_data(p_dma_info, p_buf, buf_len); ++ else ++ i_ret = 0; ++ } while (0); ++ _btif_irq_ctrl_sync(p_dma_info->p_irq, true); ++ return i_ret; ++} ++ ++int _btif_pio_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int i_ret = 0; ++ unsigned int sent_len = 0; ++ unsigned int retry = 0; ++ unsigned int max_tx_retry = 10; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++ while ((sent_len < buf_len)) { ++ if (hal_btif_is_tx_allow(p_btif_info)) { ++ i_ret = hal_btif_send_data(p_btif_info, ++ p_buf + sent_len, ++ buf_len - sent_len); ++ if (i_ret > 0) { ++ sent_len += i_ret; ++ BTIF_DBG_FUNC("lent sent:%d, total sent:%d\n", ++ i_ret, sent_len); ++ retry = 0; ++ } ++ } ++ if ((++retry > max_tx_retry) || (i_ret < 0)) { ++ BTIF_INFO_FUNC("exceed retry times limit :%d\n", retry); ++ break; ++ } ++ } ++ i_ret = sent_len; ++ return i_ret; ++} ++ ++int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int idx = 0; ++ ++ pr_debug("%s:, length:%d\n", str, buf_len); ++ for (idx = 0; idx < buf_len;) { ++ pr_debug("%02x ", p_buf[idx]); ++ idx++; ++ if (idx % 8 == 0) ++ pr_debug("\n"); ++ } ++ return 0; ++} ++ ++int btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ int i_ret = 0; ++ ++ if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { ++ i_ret = _btif_send_data(p_btif, p_buf, buf_len); ++ } else if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ int length = 0; ++/*tx fifo in*/ ++ length = kfifo_in(p_btif->p_tx_fifo, ++ (unsigned char *)p_buf, buf_len); ++ if (length == buf_len) { ++ queue_work(p_btif->p_tx_wq, &(p_btif->tx_work)); ++ BTIF_DBG_FUNC("schedule btif_tx_worker\n"); ++ i_ret = length; ++ } else { ++ i_ret = 0; ++ BTIF_ERR_FUNC("fifo in failed, target len(%d),in len(%d),", ++ "don't schedule btif_tx_worker\n", buf_len, length); ++ } ++ } else { ++ BTIF_ERR_FUNC("invalid btif tx context:%d\n", p_btif->tx_ctx); ++ i_ret = 0; ++ } ++ ++ return i_ret; ++} ++ ++int _btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ int i_ret = 0; ++ unsigned int state = 0; ++ ++/*make sure BTIF in ON state before doing tx operation*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ state = _btif_state_get(p_btif); ++ ++ if (state != B_S_ON) ++ i_ret = _btif_exit_dpidle(p_btif); ++ ++ if (i_ret != 0) { ++ i_ret = E_BTIF_INVAL_STATE; ++ } else if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ ++ i_ret = _btif_dma_write(p_btif, p_buf, buf_len); ++ } else if (p_btif->tx_mode == BTIF_MODE_PIO) { ++ /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ ++ i_ret = _btif_pio_write(p_btif, p_buf, buf_len); ++ } else { ++ BTIF_ERR_FUNC("invalid tx mode:%d\n", p_btif->tx_mode); ++ i_ret = 0; ++ } ++ ++/*save Tx packet here*/ ++ if (i_ret > 0) ++ btif_log_buf_dmp_in(&p_btif->tx_log, p_buf, i_ret); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int btif_dump_reg(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ unsigned int ori_state = 0; ++ ++/*make sure BTIF in ON state before doing tx operation*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ ori_state = _btif_state_get(p_btif); ++ ++ if (ori_state == B_S_OFF) { ++ i_ret = E_BTIF_INVAL_STATE; ++ BTIF_ERR_FUNC ++ ("BTIF in OFF state, ", ++ "should no need to dump register, ", ++ "please check wmt's operation is okay or not.\n"); ++ goto dmp_reg_err; ++ } ++ ++ if ((ori_state != B_S_ON) && (ori_state < B_S_MAX)) { ++ BTIF_ERR_FUNC("BTIF's original state is %s, not B_S_ON\n", g_state[ori_state]); ++ BTIF_ERR_FUNC("!!!!---<<>>---!!!"); ++ i_ret = _btif_exit_dpidle(p_btif); ++ } ++ ++ if (i_ret != 0) { ++ i_ret = E_BTIF_INVAL_STATE; ++ BTIF_ERR_FUNC("switch to B_S_ON failed\n"); ++ goto dmp_reg_err; ++ } ++ ++/*dump BTIF register*/ ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ ++/*dump BTIF Tx DMA channel register if in DMA mode*/ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) ++ hal_dma_dump_reg(p_btif->p_tx_dma->p_dma_info, REG_TX_DMA_ALL); ++ else ++ BTIF_INFO_FUNC("BTIF Tx in PIO mode,no need to dump Tx DMA's register\n"); ++ ++/*dump BTIF Rx DMA channel register if in DMA mode*/ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ else ++ BTIF_INFO_FUNC("BTIF Rx in PIO mode,no need to dump Rx DMA's register\n"); ++ ++ switch (ori_state) { ++ case B_S_SUSPEND: ++/*return to dpidle state*/ ++/* break; */ ++ case B_S_DPIDLE: ++/*return to dpidle state*/ ++ _btif_enter_dpidle(p_btif); ++ break; ++ case B_S_ON: ++/*nothing needs to be done*/ ++ break; ++ default: ++ break; ++ } ++ ++dmp_reg_err: ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify) ++{ ++ if (p_btif->rx_notify) { ++ BTIF_WARN_FUNC ++ ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", ++ p_btif->rx_notify, rx_notify); ++ } ++ p_btif->rx_notify = rx_notify; ++ ++ return 0; ++} ++ ++int btif_dump_data(char *p_buf, int len) ++{ ++ unsigned int idx = 0; ++ unsigned char str[30]; ++ unsigned char *p_str; ++ ++ p_str = &str[0]; ++ for (idx = 0; idx < len; idx++, p_buf++) { ++ sprintf(p_str, "%02x ", *p_buf); ++ p_str += 3; ++ if (7 == (idx % 8)) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ p_str = &str[0]; ++ } ++ } ++ if (len % 8) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ } ++ return 0; ++} ++ ++int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, ++ int len) ++{ ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ char *dir = NULL; ++ struct timeval *p_timer = NULL; ++ unsigned long flags; ++ bool output_flag = false; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++ if ((p_log_que == NULL) || (p_buf == NULL) || (len == 0)) { ++ BTIF_ERR_FUNC("invalid parameter, p_log_que(0x%x), buf(0x%x), ", ++ "len(%d)\n", p_log_que, p_buf, len); ++ return 0; ++ } ++ if (!(p_log_que->enable)) ++ return 0; ++ ++ dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; ++ output_flag = p_log_que->output_flag; ++ ++ spin_lock_irqsave(&(p_log_que->lock), flags); ++ ++/*get next log buffer for record usage*/ ++ p_log_buf = p_log_que->p_queue[0] + p_log_que->in; ++ p_timer = &p_log_buf->timer; ++ ++/*log time stamp*/ ++ do_gettimeofday(p_timer); ++ ++/*record data information including length and content*/ ++ p_log_buf->len = len; ++ memcpy(p_log_buf->buffer, p_buf, len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len); ++ ++/*update log queue size information*/ ++ p_log_que->size++; ++ p_log_que->size = p_log_que->size > ++ BTIF_LOG_ENTRY_NUM ? BTIF_LOG_ENTRY_NUM : p_log_que->size; ++ ++/*update log queue index information*/ ++ p_log_que->in++; ++ p_log_que->in %= BTIF_LOG_ENTRY_NUM; ++ ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ ++/*check if log dynamic output function is enabled or not*/ ++ if (output_flag) { ++ pr_debug("BTIF-DBG, dir:%s, %d.%ds len:%d\n", ++ dir, (int)p_timer->tv_sec, (int)p_timer->tv_usec, len); ++/*output buffer content*/ ++ btif_dump_data((char *)p_buf, len); ++ } ++ BTIF_DBG_FUNC("--\n"); ++ ++ return 0; ++} ++ ++int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ unsigned int out_index = 0; ++ unsigned int in_index = 0; ++ unsigned int dump_size = 0; ++ unsigned char *p_buf = NULL; ++ unsigned int len = 0; ++ unsigned int pkt_count = 0; ++ unsigned char *p_dir = NULL; ++ struct timeval *p_timer = NULL; ++ unsigned long flags; ++ ++#if 0 /* no matter enable or not, we allowed output */ ++ if (!(p_log_que->enable)) ++ return; ++#endif ++ BTIF_DBG_FUNC("++\n"); ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ in_index = p_log_que->in; ++ dump_size = p_log_que->size; ++ out_index = p_log_que->size >= ++ BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - ++ p_log_que->size + ++ in_index) % BTIF_LOG_ENTRY_NUM; ++ p_dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; ++ ++ BTIF_INFO_FUNC("btif %s log buffer size:%d\n", p_dir, dump_size); ++ ++ if (dump_size != 0) { ++ while (dump_size--) { ++ p_log_buf = p_log_que->p_queue[0] + out_index; ++ ++ len = p_log_buf->len; ++ p_buf = p_log_buf->buffer; ++ p_timer = &p_log_buf->timer; ++ ++ len = len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len; ++ ++ BTIF_INFO_FUNC("dir:%s, pkt_count:%d, %d.%ds len:%d\n", ++ p_dir, ++ pkt_count++, ++ (int)p_timer->tv_sec, ++ (int)p_timer->tv_usec, len); ++/*output buffer content*/ ++ btif_dump_data(p_log_buf->buffer, len); ++ out_index++; ++ out_index %= BTIF_LOG_ENTRY_NUM; ++ } ++ } ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_DBG_FUNC("--\n"); ++ ++ return 0; ++} ++ ++int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->enable = true; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("enable %s log function\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->enable = false; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("disable %s log function\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->output_flag = true; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("%s log rt output enabled\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->output_flag = false; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("%s log rt output disabled\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ ++/*tx log buffer init*/ ++ p_log_que->in = 0; ++ p_log_que->out = 0; ++ p_log_que->size = 0; ++ p_log_que->enable = true; ++ memset((p_log_que->p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_DBG_FUNC("reset %s log buffer\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_init(p_mtk_btif p_btif) ++{ ++/*tx log buffer init*/ ++ p_btif->tx_log.dir = BTIF_TX; ++ p_btif->tx_log.in = 0; ++ p_btif->tx_log.out = 0; ++ p_btif->tx_log.size = 0; ++ p_btif->tx_log.output_flag = false; ++ p_btif->tx_log.enable = true; ++ spin_lock_init(&(p_btif->tx_log.lock)); ++ BTIF_DBG_FUNC("tx_log.p_queue:0x%p\n", p_btif->tx_log.p_queue[0]); ++ memset((p_btif->tx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++/*rx log buffer init*/ ++ p_btif->rx_log.dir = BTIF_RX; ++ p_btif->rx_log.in = 0; ++ p_btif->rx_log.out = 0; ++ p_btif->rx_log.size = 0; ++ p_btif->rx_log.output_flag = false; ++ p_btif->rx_log.enable = true; ++ spin_lock_init(&(p_btif->rx_log.lock)); ++ BTIF_DBG_FUNC("rx_log.p_queue:0x%p\n", p_btif->rx_log.p_queue[0]); ++ memset((p_btif->rx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++ return 0; ++} ++ ++int btif_tx_dma_mode_set(int en) ++{ ++ int index = 0; ++ ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ g_btif[index].tx_mode = mode; ++ ++ return 0; ++} ++ ++int btif_rx_dma_mode_set(int en) ++{ ++ int index = 0; ++ ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ g_btif[index].rx_mode = mode; ++ ++ return 0; ++} ++ ++static int BTIF_init(void) ++{ ++ int i_ret = -1; ++ int index = 0; ++ p_mtk_btif_dma p_tx_dma = NULL; ++ p_mtk_btif_dma p_rx_dma = NULL; ++ unsigned char *p_btif_buffer = NULL; ++ unsigned char *p_tx_queue = NULL; ++ unsigned char *p_rx_queue = NULL; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++/*Platform Driver initialization*/ ++ i_ret = platform_driver_register(&mtk_btif_dev_drv); ++ if (i_ret) { ++ BTIF_ERR_FUNC("BTIF platform driver registered failed, ret(%d)\n", i_ret); ++ goto err_exit1; ++ } ++ ++ i_ret = driver_create_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ if (i_ret) ++ BTIF_ERR_FUNC("BTIF pdriver_create_file failed, ret(%d)\n", i_ret); ++ ++/*SW init*/ ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ p_btif_buffer = kmalloc(BTIF_RX_BUFFER_SIZE, GFP_ATOMIC); ++ if (!p_btif_buffer) { ++ BTIF_ERR_FUNC("p_btif_buffer kmalloc memory fail\n"); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_btif_buffer get memory 0x%p\n", p_btif_buffer); ++ p_tx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); ++ if (!p_tx_queue) { ++ BTIF_ERR_FUNC("p_tx_queue kmalloc memory fail\n"); ++ kfree(p_btif_buffer); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_tx_queue get memory 0x%p\n", p_tx_queue); ++ p_rx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); ++ if (!p_rx_queue) { ++ BTIF_ERR_FUNC("p_rx_queue kmalloc memory fail\n"); ++ kfree(p_btif_buffer); ++ kfree(p_tx_queue); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_rx_queue get memory 0x%p\n", p_rx_queue); ++ ++ INIT_LIST_HEAD(&(g_btif[index].user_list)); ++ BBS_INIT(&(g_btif[index].btif_buf)); ++ g_btif[index].enable = false; ++ g_btif[index].open_counter = 0; ++ g_btif[index].setting = &g_btif_setting[index]; ++ g_btif[index].p_btif_info = hal_btif_info_get(); ++ g_btif[index].tx_mode = g_btif_setting[index].tx_mode; ++ g_btif[index].rx_mode = g_btif_setting[index].rx_mode; ++ g_btif[index].btm_type = g_btif_setting[index].rx_type; ++ g_btif[index].tx_ctx = g_btif_setting[index].tx_type; ++ g_btif[index].lpbk_flag = false; ++ g_btif[index].rx_cb = NULL; ++ g_btif[index].rx_notify = NULL; ++ g_btif[index].btif_buf.p_buf = p_btif_buffer; ++ g_btif[index].tx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_tx_queue; ++ g_btif[index].rx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_rx_queue; ++ btif_log_buf_init(&g_btif[index]); ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF clock gating by default*/ ++ i_ret = hal_btif_clk_ctrl(g_btif[index].p_btif_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF controller CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++/* ++ * viftual FIFO memory must be physical continious, ++ * because DMA will access it directly without MMU ++ */ ++#if ENABLE_BTIF_TX_DMA ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ g_btif[index].p_tx_dma = p_tx_dma; ++ p_tx_dma->dir = BTIF_TX; ++ p_tx_dma->p_btif = &(g_btif[index]); ++ ++/*DMA Tx vFIFO initialization*/ ++ p_tx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_TX); ++/*spinlock init*/ ++ spin_lock_init(&(p_tx_dma->iolock)); ++/*entry setup*/ ++ atomic_set(&(p_tx_dma->entry), 0); ++/*vFIFO initialization*/ ++ i_ret = _btif_vfifo_init(p_tx_dma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx vFIFO allocation failed\n"); ++ goto err_exit2; ++ } ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF Tx DMA channel's clock gating by default*/ ++ i_ret = hal_btif_dma_clk_ctrl(p_tx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx DMA's CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++#else ++ g_btif[index].p_tx_dma = NULL; ++/*force tx mode to DMA no matter what it is in default setting*/ ++ g_btif[index].tx_mode = BTIF_MODE_PIO; ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++ g_btif[index].p_rx_dma = p_rx_dma; ++ p_rx_dma->p_btif = &(g_btif[index]); ++ p_rx_dma->dir = BTIF_RX; ++ ++/*DMA Tx vFIFO initialization*/ ++ p_rx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_RX); ++/*spinlock init*/ ++ spin_lock_init(&(p_rx_dma->iolock)); ++/*entry setup*/ ++ atomic_set(&(p_rx_dma->entry), 0); ++/*vFIFO initialization*/ ++ i_ret = _btif_vfifo_init(p_rx_dma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx vFIFO allocation failed\n"); ++ goto err_exit2; ++ } ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF Tx DMA channel's clock gating by default*/ ++ i_ret = hal_btif_dma_clk_ctrl(p_rx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx DMA's CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++#else ++ g_btif[index].p_rx_dma = NULL; ++/*force rx mode to DMA no matter what it is in default setting*/ ++ g_btif[index].rx_mode = BTIF_MODE_PIO; ++ ++#endif ++/*PM state mechine initialization*/ ++ i_ret = _btif_state_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF state mechanism init failed\n"); ++ goto err_exit2; ++ } ++ ++/*Rx bottom half initialization*/ ++ i_ret = _btif_rx_btm_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx btm init failed\n"); ++ goto err_exit3; ++ } ++ i_ret = _btif_tx_ctx_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx context init failed\n"); ++ goto err_exit4; ++ } ++/*Character Device initialization*/ ++/*Chaozhong: ToDo: to be initialized*/ ++ ++ mutex_init(&g_btif[index].ops_mtx); ++ } ++ ++/*Debug purpose initialization*/ ++ ++#if BTIF_CDEV_SUPPORT ++ btif_chrdev_init(); ++#endif ++ ++ return 0; ++ ++err_exit4: ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ _btif_tx_ctx_deinit(&(g_btif[index])); ++ ++err_exit3: ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ _btif_rx_btm_deinit(&(g_btif[index])); ++ ++ _btif_state_deinit(&(g_btif[index])); ++ } ++ ++err_exit2: ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++#if ENABLE_BTIF_TX_DMA ++ _btif_vfifo_deinit(p_tx_dma); ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ _btif_vfifo_deinit(p_rx_dma); ++#endif ++ g_btif[index].open_counter = 0; ++ g_btif[index].enable = false; ++ } ++ driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ platform_driver_unregister(&mtk_btif_dev_drv); ++ ++err_exit1: ++ i_ret = -1; ++ BTIF_DBG_FUNC("--\n"); ++ return i_ret; ++} ++ ++static void BTIF_exit(void) ++{ ++ unsigned int index = 0; ++ p_mtk_btif_dma p_tx_dma = NULL; ++ p_mtk_btif_dma p_rx_dma = NULL; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ g_btif[index].open_counter = 0; ++ g_btif[index].enable = false; ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++#if ENABLE_BTIF_TX_DMA ++ _btif_vfifo_deinit(p_tx_dma); ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ _btif_vfifo_deinit(p_rx_dma); ++#endif ++ _btif_state_deinit(&(g_btif[index])); ++ ++ _btif_rx_btm_deinit(&(g_btif[index])); ++ ++ mutex_destroy(&g_btif[index].ops_mtx); ++ } ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ hal_btif_clk_unprepare(); ++#endif ++ ++ driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ platform_driver_unregister(&mtk_btif_dev_drv); ++ BTIF_DBG_FUNC("--\n"); ++} ++ ++int mtk_btif_hal_get_log_lvl(void) ++{ ++ return mtk_btif_dbg_lvl; ++} ++ ++void mtk_btif_read_cpu_sw_rst_debug(void) ++{ ++ mtk_btif_read_cpu_sw_rst_debug_plat(); ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++module_init(BTIF_init); ++module_exit(BTIF_exit); ++ ++/*---------------------------------------------------------------------------*/ ++ ++MODULE_AUTHOR("MBJ/WCN/SE/SS1/Chaozhong.Liang"); ++MODULE_DESCRIPTION("MTK BTIF Driver$1.0$"); ++MODULE_LICENSE("GPL"); ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/drivers/misc/mediatek/btif/common/mtk_btif_exp.c b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c +new file mode 100644 +index 000000000000..c0df44558357 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c +@@ -0,0 +1,786 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF-EXP" ++ ++/*#include "mtk_btif_exp.h"*/ ++#include "mtk_btif.h" ++ ++/*---------------------------------Function----------------------------------*/ ++ ++p_mtk_btif btif_exp_srh_id(unsigned long u_id) ++{ ++ int index = 0; ++ p_mtk_btif p_btif = NULL; ++ struct list_head *p_list = NULL; ++ struct list_head *tmp = NULL; ++ p_mtk_btif_user p_user = NULL; ++ ++ for (index = 0; (index < BTIF_PORT_NR) && (p_btif == NULL); index++) { ++ p_list = &(g_btif[index].user_list); ++ list_for_each(tmp, p_list) { ++ p_user = container_of(tmp, mtk_btif_user, entry); ++ if (u_id == p_user->u_id) { ++ p_btif = p_user->p_btif; ++ BTIF_DBG_FUNC ++ ("BTIF's user id(0x%p), p_btif(0x%p)\n", ++ p_user->u_id, p_btif); ++ break; ++ } ++ } ++ } ++ if (p_btif == NULL) { ++ BTIF_INFO_FUNC ++ ("no btif structure found for BTIF's user id(0x%lx)\n", ++ u_id); ++ } ++ return p_btif; ++} ++ ++/*-----Normal Mode API declearation-------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_open ++* DESCRIPTION ++* open BTIF interface, will do BTIF module HW and SW initialization ++* PARAMETERS ++* p_owner [IN] pointer to owner who call this API, ++* currently there are 2 owner ("stp" or "btif_tester") ++* may use this module ++* for "stp", BTIF will call rx callback function to route rx data to STP module ++* for "stp_tester", BTIF will save rx data and wait for native process to access ++* p_id [IN] BTIF's user id will be put to this address ++* RETURNS ++* int 0 = BTIF module initialization fail; negative = BTIF module initialization success ++* if open success, value p_id will be the only identifier ++* for user to access BTIF's other operations ++* including read/write/dpidle_ctrl/rx_cb_retister ++* this user id is only an identifier used for owner identification ++*****************************************************************************/ ++int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id) ++{ ++ int i_ret = -1; ++ unsigned int index = 0; ++ p_mtk_btif_user p_new_user = NULL; ++ p_mtk_btif p_btif = &g_btif[index]; ++ struct list_head *p_user_list = &(p_btif->user_list); ++ ++ BTIF_DBG_FUNC("++"); ++ BTIF_DBG_FUNC("p_btif(0x%p)\n", p_btif); ++ ++ if (mutex_lock_killable(&(p_btif->ops_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return E_BTIF_INTR; ++ } ++ if ((p_owner == NULL) || (p_id == NULL)) { ++ if (p_id) ++ *p_id = 0; ++ BTIF_ERR_FUNC("parameter invalid, p_owner(0x%p), p_id(0x%p)\n", ++ p_owner, p_id); ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++/*check if btif is already opened or not, if yes, just return fail*/ ++ if (!list_empty(p_user_list)) { ++ struct list_head *pos; ++ p_mtk_btif_user p_user; ++ ++ BTIF_ERR_FUNC("BTIF's user list is not empty\n"); ++ list_for_each(pos, p_user_list) { ++ p_user = container_of(pos, mtk_btif_user, entry); ++ BTIF_INFO_FUNC("BTIF's user id(0x%lx), name(%s)\n", ++ p_user->u_id, p_user->u_name); ++ } ++/*leave p_id alone*/ ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ return E_BTIF_ALREADY_OPEN; ++ } ++ p_new_user = vmalloc(sizeof(mtk_btif_user)); ++ ++ if (p_new_user != NULL) { ++ INIT_LIST_HEAD(&(p_new_user->entry)); ++ p_new_user->enable = false; ++ p_new_user->p_btif = p_btif; ++ p_new_user->u_id = (unsigned long)p_new_user; ++ strncpy(p_new_user->u_name, p_owner, sizeof(p_new_user->u_name) - 1); ++ p_new_user->u_name[sizeof(p_new_user->u_name) - 1] = '\0'; ++ BTIF_DBG_FUNC("owner name:%s, recorded name:%s\n", ++ p_owner, p_new_user->u_name); ++ ++ i_ret = btif_open(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); ++ *p_id = 0; ++/*free btif new user's structure*/ ++ vfree(p_new_user); ++ p_new_user = NULL; ++ } else { ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ *p_id = p_new_user->u_id; ++/*mark enable flag to true*/ ++ p_new_user->enable = true; ++/*add to uer lsit*/ ++ list_add_tail(&(p_new_user->entry), p_user_list); ++ } ++ } else { ++ *p_id = 0; ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("allocate memory for mtk_btif_user failed\n"); ++ } ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ BTIF_DBG_FUNC("--"); ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_open); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_close ++* DESCRIPTION ++* close BTIF interface, will do BTIF module HW and SW de-initialization ++* once this API is called, p_btif should never be used by BTIF's user again ++* PARAMETERS ++* u_id [IN] BTIF's user id ++* RETURNS ++* int 0 = succeed; ++* others = fail, ++* for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_close(unsigned long u_id) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ struct list_head *pos = NULL; ++ struct list_head *p_user_list = NULL; ++ ++ BTIF_DBG_FUNC("++"); ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (mutex_lock_killable(&(p_btif->ops_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return E_BTIF_INTR; ++ } ++ p_user_list = &(p_btif->user_list); ++ list_for_each(pos, p_user_list) { ++ p_mtk_btif_user p_user = ++ container_of(pos, mtk_btif_user, entry); ++ ++ if (p_user->u_id == u_id) { ++ BTIF_INFO_FUNC ++ ("user who's id is 0x%lx deleted from user list\n", ++ u_id); ++ list_del(pos); ++ vfree(p_user); ++ i_ret = btif_close(p_btif); ++ if (i_ret) ++ BTIF_WARN_FUNC("BTIF close failed"); ++ break; ++ } ++ } ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ BTIF_DBG_FUNC("--"); ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_close); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_write ++* DESCRIPTION ++* send data throuth BTIF module ++* there's no internal buffer to cache STP data in BTIF driver, ++* if in DMA mode ++* btif driver will check if there's enough space in vFIFO for data to send in DMA mode ++* if yes, put data to vFIFO and return corresponding data length to caller ++* if no, corresponding error code will be returned to called ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN] pointer to target data to send ++* len [IN] data length (should be less than 2014 bytes per STP package) ++* ++* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller ++* if btif driver detected that no space is available in Tx FIFO, ++* will return E_BTIF_NO_SPACE, mostly something is wrong with BTIF or ++* consys when this return value is returned ++* RETURNS ++* int positive: data length send through BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++* E_BTIF_AGAIN (0) will be returned to caller ++* if btif does not have enough vFIFO to send data, ++* when caller get 0, he should wait for a moment ++* (5~10ms maybe) and try a few times (maybe 10~20) ++* if still get E_BTIF_AGAIN, ++* should call BTIF's debug API and dump BTIF driver ++* and BTIF/DMA register information to kernel log for debug ++* E_BTIF_BAD_POINTER will be returned to caller ++* if btif is not opened successfully before call this API ++* E_BTIF_INVAL_PARAM will be returned if parameter is not valid ++ ++*****************************************************************************/ ++int mtk_wcn_btif_write(unsigned long u_id, ++ const unsigned char *p_buf, unsigned int len) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ BTIF_DBG_FUNC("++"); ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ if (p_buf == NULL) { ++ BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { ++ BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ i_ret = btif_send_data(p_btif, p_buf, len); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_write); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_read ++* DESCRIPTION ++* read data from BTIF module ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN/OUT] pointer to buffer where rx data will be put ++* max_len [IN] max buffer length ++* RETURNS ++* int positive: data length read from BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_read(unsigned long u_id, ++ unsigned char *p_buf, unsigned int max_len) ++{ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_dpidle_ctrl ++* DESCRIPTION ++* control if BTIF module allow system enter deepidle state or not ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL ++* RETURNS ++* int always return 0 ++*****************************************************************************/ ++int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ i_ret = btif_exit_dpidle(p_btif); ++ else ++ i_ret = btif_enter_dpidle(p_btif); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_dpidle_ctrl); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_rx_cb_register ++* DESCRIPTION ++* register rx callback function to BTIF module by btif user ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* rx_cb [IN] pointer to stp rx handler callback function, ++* should be comply with MTK_WCN_BTIF_RX_CB ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ i_ret = btif_rx_cb_reg(p_btif, rx_cb); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_rx_cb_register); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_wakeup_consys ++* DESCRIPTION ++* once sleep command is sent to con sys, ++* should call this API before send wakeup command ++* to make con sys aware host want to send data to consys ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_wakeup_consys(unsigned long u_id) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ ++ i_ret = btif_raise_wak_signal(p_btif); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_wakeup_consys); ++ ++ ++/***************End of Normal Mode API declearation**********/ ++ ++/***************Debug Purpose API declearation**********/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_loopback_ctrl ++* DESCRIPTION ++* enable/disable BTIF internal loopback function, ++* when this function is enabled data send to btif ++* will be received by btif itself ++* only for debug purpose, should never use this function in normal mode ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* enable [IN] loopback mode control flag, enable or disable, ++* shou be one of ENUM_BTIF_LPBK_MODE ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ i_ret = ++ btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_logger_ctrl ++* DESCRIPTION ++* control BTIF logger function's behavior ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* flag [IN] should be one of ENUM_BTIF_DBG_ID ++* BTIF_DISABLE_LOGGER - disable btif logger ++* BTIF_ENABLE_LOGGER - enable btif logger ++* BTIF_DUMP_LOG - dump log logged by btif ++* BTIF_CLR_LOG - clear btif log buffer ++* BTIF_DUMP_BTIF_REG - dump btif controller's register ++* BTIF_DUMP_DMA_REG - dump DMA controller's register ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ i_ret = 0; ++ switch (flag) { ++ case BTIF_DISABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("disable btif log function for both Tx and Rx\n"); ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_ENABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("enable btif log function for both Tx and Rx\n"); ++ btif_log_buf_enable(&p_btif->tx_log); ++ btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_LOG:{ ++ BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); ++ btif_log_buf_dmp_out(&p_btif->tx_log); ++ btif_log_buf_dmp_out(&p_btif->rx_log); ++ } ++ break; ++ ++ case BTIF_CLR_LOG:{ ++ BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_BTIF_REG: ++ /*TBD*/ btif_dump_reg(p_btif); ++ break; ++ case BTIF_ENABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("enable btif real time log for both Tx and Rx\n"); ++ btif_log_output_enable(&p_btif->tx_log); ++ btif_log_output_enable(&p_btif->rx_log); ++ break; ++ case BTIF_DISABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("disable btif real time log for both Tx and Rx\n"); ++ btif_log_output_disable(&p_btif->tx_log); ++ btif_log_output_disable(&p_btif->rx_log); ++ break; ++ default: ++ BTIF_INFO_FUNC("not supported flag:%d\n", flag); ++ i_ret = -2; ++ break; ++ } ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); ++ ++bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, ++ const char *sub_str, unsigned int str_len) ++{ ++ bool b_ret = false; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ b_ret = btif_parser_wmt_evt(p_btif, sub_str, str_len); ++ BTIF_INFO_FUNC("parser wmt evt %s\n", b_ret ? "ok" : "fail"); ++ ++ return b_ret; ++} ++ ++/**********End of Debug Purpose API declearation**********/ ++ ++int btif_open_no_id(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_open(p_btif); ++ ++ if (i_ret) ++ BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ ++ return i_ret; ++} ++ ++int btif_close_no_id(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_close(p_btif); ++ ++ if (i_ret) ++ BTIF_ERR_FUNC("btif_close failed, i_ret(%d)\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_close succeed\n"); ++ return i_ret; ++} ++ ++int btif_write_no_id(const unsigned char *p_buf, unsigned int len) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_DBG_FUNC("++"); ++ ++ if (p_buf == NULL) { ++ BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { ++ BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ i_ret = btif_send_data(p_btif, p_buf, len); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int btif_dpidle_ctrl_no_id(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ i_ret = btif_exit_dpidle(p_btif); ++ else ++ i_ret = btif_enter_dpidle(p_btif); ++ ++ return i_ret; ++} ++ ++int btif_wakeup_consys_no_id(void) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ ++ i_ret = btif_raise_wak_signal(p_btif); ++ ++ return i_ret; ++} ++ ++int btif_loopback_ctrl_no_id(ENUM_BTIF_LPBK_MODE enable) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = ++ btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); ++ ++ return i_ret; ++} ++ ++int btif_dbg_ctrl_no_id(ENUM_BTIF_DBG_ID flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = 0; ++ switch (flag) { ++ case BTIF_DISABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("disable btif log function for both Tx and Rx\n"); ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_ENABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("enable btif log function for both Tx and Rx\n"); ++ btif_log_buf_enable(&p_btif->tx_log); ++ btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_LOG:{ ++ BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); ++ btif_log_buf_dmp_out(&p_btif->tx_log); ++ btif_log_buf_dmp_out(&p_btif->rx_log); ++ } ++ break; ++ ++ case BTIF_CLR_LOG:{ ++ BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_BTIF_REG: ++ /*TBD*/ btif_dump_reg(p_btif); ++ break; ++ case BTIF_ENABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("enable btif real time log for both Tx and Rx\n"); ++ btif_log_output_enable(&p_btif->tx_log); ++ btif_log_output_enable(&p_btif->rx_log); ++ break; ++ case BTIF_DISABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("disable btif real time log for both Tx and Rx\n"); ++ btif_log_output_disable(&p_btif->tx_log); ++ btif_log_output_disable(&p_btif->rx_log); ++ break; ++ default: ++ BTIF_INFO_FUNC("not supported flag:%d\n", flag); ++ i_ret = -2; ++ break; ++ } ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_open_test(void) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_open_no_id(); ++ if (i_ret < 0) { ++ BTIF_INFO_FUNC("mtk_wcn_btif_open failed\n"); ++ return -1; ++ } ++ ++ BTIF_INFO_FUNC("mtk_wcn_btif_open succeed\n"); ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_close_test(void) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_close_no_id(); ++ if (i_ret < 0) { ++ BTIF_INFO_FUNC("mtk_wcn_btif_close failed\n"); ++ return -1; ++ } ++ ++ BTIF_INFO_FUNC("mtk_wcn_btif_close succeed\n"); ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_write_test(void) ++{ ++ return mtk_btif_exp_write_stress_test(100, 10); ++} ++ ++int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int max_loop) ++{ ++#define BUF_LEN 1024 ++ int i_ret = 0; ++ int idx = 0; ++ int buf_len = length > BUF_LEN ? BUF_LEN : length; ++ int loop = max_loop > 1000000 ? 1000000 : max_loop; ++ unsigned char *buffer; ++ ++ buffer = kmalloc(BUF_LEN, GFP_KERNEL); ++ if (!buffer) { ++ BTIF_ERR_FUNC("btif tester kmalloc failed\n"); ++ return -1; ++ } ++ ++ for (idx = 0; idx < buf_len; idx++) ++ /* btif_stress_test_buf[idx] = BUF_LEN -idx; */ ++ *(buffer + idx) = idx % 255; ++ i_ret = btif_loopback_ctrl_no_id(BTIF_LPBK_ENABLE); ++ BTIF_INFO_FUNC("mtk_wcn_btif_loopback_ctrl returned %d\n", i_ret); ++ while (loop--) { ++ i_ret = btif_write_no_id(buffer, buf_len); ++ BTIF_INFO_FUNC("mtk_wcn_btif_write left loop:%d, i_ret:%d\n", ++ loop, i_ret); ++ if (i_ret != buf_len) { ++ BTIF_INFO_FUNC ++ ("mtk_wcn_btif_write failed, target len %d, sent len: %d\n", ++ buf_len, i_ret); ++ break; ++ } ++ buf_len--; ++ if (buf_len <= 0) ++ buf_len = length > BUF_LEN ? BUF_LEN : length; ++ } ++ kfree(buffer); ++ return i_ret; ++} ++ ++int mtk_btif_exp_suspend_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_suspend(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_restore_noirq_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_restore_noirq(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_clock_ctrl(int en) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_clock_ctrl(p_btif, en); ++ return i_ret; ++} ++ ++int mtk_btif_exp_resume_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_resume(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_enter_dpidle_test(void) ++{ ++ return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_ENABLE); ++} ++ ++int mtk_btif_exp_exit_dpidle_test(void) ++{ ++ return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_DISABLE); ++} ++ ++int mtk_btif_exp_log_debug_test(int flag) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_dbg_ctrl_no_id(flag); ++ return i_ret; ++} ++ ++void mtk_btif_read_cpu_sw_rst_debug_exp(void) ++{ ++ mtk_btif_read_cpu_sw_rst_debug(); ++} ++ ++/************End of Function**********/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h +new file mode 100644 +index 000000000000..97756f684ab4 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_DMA_H_ ++#define __HAL_BTIF_DMA_H_ ++ ++#include ++#include "btif_dma_pub.h" ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(CONFIG_ARCH_MT6580) ++#define MTK_BTIF_APDMA_CLK_CG MT_CG_APDMA_SW_CG ++#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) ++#define MTK_BTIF_APDMA_CLK_CG MT_CG_PERI_APDMA ++#endif ++#else ++extern struct clk *clk_btif_apdma; /*btif apdma clock*/ ++#endif /* !defined(CONFIG_MTK_CLKMGR) */ ++ ++#define TX_DMA_VFF_SIZE (1024 * 8) /*Tx vFIFO Len must be 8 Byte allignment */ ++#define RX_DMA_VFF_SIZE (1024 * 8) /*Rx vFIFO Len must be 8 Byte allignment */ ++ ++#define DMA_TX_THRE(n) (n - 7) /*Tx Trigger Level */ ++#define DMA_RX_THRE(n) ((n) * 3 / 4) /*Rx Trigger Level */ ++ ++/**********************************Hardware related defination**************************/ ++#ifndef CONFIG_OF ++/*DMA channel's offset refer to AP_DMA's base address*/ ++#define BTIF_TX_DMA_OFFSET 0x880 ++#define BTIF_RX_DMA_OFFSET 0x900 ++#endif ++ ++/*Register Address Mapping*/ ++#define DMA_INT_FLAG_OFFSET 0x00 ++#define DMA_INT_EN_OFFSET 0x04 ++#define DMA_EN_OFFSET 0x08 ++#define DMA_RST_OFFSET 0x0C ++#define DMA_STOP_OFFSET 0x10 ++#define DMA_FLUSH_OFFSET 0x14 ++ ++#define DMA_BASE_OFFSET 0x1C ++#define DMA_LEN_OFFSET 0x24 ++ ++#define DMA_THRE_OFFSET 0x28 ++#define DMA_WPT_OFFSET 0x2C ++#define DMA_RPT_OFFSET 0x30 ++#define DMA_VALID_OFFSET 0x3C ++#define DMA_LEFT_OFFSET 0x40 ++#define DMA_VFF_BIT29_OFFSET 0x01 ++ ++#define TX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Tx Virtual FIFO Interrupt Flag Register */ ++#define TX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Tx Virtual FIFO Interrupt Enable Register */ ++#define TX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET)/*BTIF Tx Virtual FIFO Enable Register */ ++#define TX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET)/*BTIF Tx Virtual FIFO Reset Register */ ++#define TX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET)/*BTIF Tx Virtual FIFO STOP Register */ ++#define TX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET)/*BTIF Tx Virtual FIFO Flush Register */ ++#define TX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Tx Virtual FIFO Base Address Register */ ++#define TX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Tx Virtual FIFO Length Register */ ++#define TX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Tx Virtual FIFO Threshold Register */ ++#define TX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Tx Virtual FIFO Write Pointer Register */ ++#define TX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Tx Virtual FIFO Read Pointer Register */ ++#define TX_DMA_W_INT_BUF_SIZE(base) (unsigned long)(base + 0x34) ++/*BTIF Tx Virtual FIFO Internal Tx Write Buffer Size Register */ ++#define TX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) ++/*BTIF Tx Virtual FIFO Internal Tx Buffer Size Register */ ++ ++#define TX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Tx Virtual FIFO Valid Size Register */ ++#define TX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Tx Virtual FIFO Left Size Register */ ++#define TX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Tx Virtual FIFO Debug Status Register */ ++#define TX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Tx Virtual FIFO Base High Address Register */ ++ ++/*Rx Register Address Mapping*/ ++#define RX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Rx Virtual FIFO Interrupt Flag Register */ ++#define RX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Rx Virtual FIFO Interrupt Enable Register */ ++#define RX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET) /*BTIF Rx Virtual FIFO Enable Register */ ++#define RX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET) /*BTIF Rx Virtual FIFO Reset Register */ ++#define RX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET) /*BTIF Rx Virtual FIFO Stop Register */ ++#define RX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET) /*BTIF Rx Virtual FIFO Flush Register */ ++#define RX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Rx Virtual FIFO Base Address Register */ ++#define RX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Rx Virtual FIFO Length Register */ ++#define RX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Rx Virtual FIFO Threshold Register */ ++#define RX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Rx Virtual FIFO Write Pointer Register */ ++#define RX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Rx Virtual FIFO Read Pointer Register */ ++#define RX_DMA_FLOW_CTRL_THRE(base) (unsigned long)(base + 0x34) /*BTIF Rx Virtual FIFO Flow Control Register */ ++#define RX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) /*BTIF Rx Virtual FIFO Internal Buffer Register */ ++#define RX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Rx Virtual FIFO Valid Size Register */ ++#define RX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Rx Virtual FIFO Left Size Register */ ++#define RX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Rx Virtual FIFO Debug Status Register */ ++#define RX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Rx Virtual FIFO Base High Address Register */ ++ ++#define DMA_EN_BIT (0x1) ++#define DMA_STOP_BIT (0x1) ++#define DMA_RST_BIT (0x1) ++#define DMA_FLUSH_BIT (0x1) ++ ++#define DMA_WARM_RST (0x1 << 0) ++#define DMA_HARD_RST (0x1 << 1) ++ ++#define DMA_WPT_MASK (0x0000FFFF) ++#define DMA_WPT_WRAP (0x00010000) ++ ++#define DMA_RPT_MASK (0x0000FFFF) ++#define DMA_RPT_WRAP (0x00010000) ++ ++/*APDMA BTIF Tx Reg Ctrl Bit*/ ++#define TX_DMA_INT_FLAG_MASK (0x1) ++ ++#define TX_DMA_INTEN_BIT (0x1) ++ ++#define TX_DMA_ADDR_MASK (0xFFFFFFF8) ++#define TX_DMA_LEN_MASK (0x0000FFF8) ++ ++#define TX_DMA_THRE_MASK (0x0000FFFF) ++ ++#define TX_DMA_W_INT_BUF_MASK (0x000000FF) ++ ++#define TX_DMA_VFF_VALID_MASK (0x0000FFFF) ++#define TX_DMA_VFF_LEFT_MASK (0x0000FFFF) ++ ++/*APDMA BTIF Rx Reg Ctrl Bit*/ ++#define RX_DMA_INT_THRE (0x1 << 0) ++#define RX_DMA_INT_DONE (0x1 << 1) ++ ++#define RX_DMA_INT_THRE_EN (0x1 << 0) ++#define RX_DMA_INT_DONE_EN (0x1 << 1) ++ ++#define RX_DMA_ADDR_MASK (0xFFFFFFF8) ++#define RX_DMA_LEN_MASK (0x0000FFF8) ++ ++#define RX_DMA_THRE_MASK (0x0000FFFF) ++ ++#define RX_DMA_FLOW_CTRL_THRE_MASK (0x000000FF) ++ ++#define RX_DMA_INT_BUF_SIZE_MASK (0x0000001F) ++ ++#define RX_DMA_VFF_VALID_MASK (0x0000001F) ++ ++#define RX_DMA_VFF_LEFT_MASK (0x0000FFFF) ++ ++typedef struct _MTK_BTIF_DMA_VFIFO_ { ++ DMA_VFIFO vfifo; ++ unsigned int wpt; /*DMA's write pointer, which is maintained by SW for Tx DMA and HW for Rx DMA */ ++ unsigned int last_wpt_wrap; /*last wrap bit for wpt */ ++ unsigned int rpt; /*DMA's read pointer, which is maintained by HW for Tx DMA and SW for Rx DMA */ ++ unsigned int last_rpt_wrap; /*last wrap bit for rpt */ ++} MTK_BTIF_DMA_VFIFO, *P_MTK_BTIF_DMA_VFIFO; ++ ++/*for DMA debug purpose*/ ++typedef struct _MTK_BTIF_DMA_REG_DMP_DBG_ { ++ unsigned long reg_addr; ++ unsigned int reg_val; ++} MTK_BTIF_DMA_REG_DMP_DBG, *P_MTK_BTIF_DMA_REG_DMP_DBG; ++ ++#endif /*__HAL_BTIF_DMA_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h +new file mode 100644 +index 000000000000..0773f2ce387a +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIFD_DMA_PUB_H_ ++#define __HAL_BTIFD_DMA_PUB_H_ ++ ++#include ++ ++#include "plat_common.h" ++ ++typedef enum _ENUM_DMA_CTRL_ { ++ DMA_CTRL_DISABLE = 0, ++ DMA_CTRL_ENABLE = DMA_CTRL_DISABLE + 1, ++ DMA_CTRL_BOTH, ++} ENUM_DMA_CTRL; ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_info_get ++* DESCRIPTION ++* get btif tx dma channel's information ++* PARAMETERS ++* dma_dir [IN] DMA's direction ++* RETURNS ++* pointer to btif dma's information structure ++*****************************************************************************/ ++P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dma_hw_init ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ctrl ++* DESCRIPTION ++* enable/disable Tx DMA channel ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* ctrl_id [IN] enable/disable ID ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dma_rx_cb_reg ++* DESCRIPTION ++* register rx callback function to dma module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* rx_cb [IN] function pointer to btif ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ dma_rx_buf_write rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_vfifo_reset ++* DESCRIPTION ++* reset tx virtual fifo information, except memory information ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_send_data ++* DESCRIPTION ++* send data through btif in DMA mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, ++ const unsigned char *p_buf, const unsigned int buf_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_get_ava_room ++* DESCRIPTION ++* get tx available room ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* available room size ++*****************************************************************************/ ++int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_allow ++* DESCRIPTION ++* is tx operation allowed by DMA ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_rx_dma_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag); ++ ++int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid); ++ ++#endif /*__HAL_BTIFD_DMA_PUB_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h +new file mode 100644 +index 000000000000..51fe58a82b49 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_H_ ++#define __HAL_BTIF_H_ ++ ++#ifndef CONFIG_OF ++#define MTK_BTIF_REG_BASE BTIF_BASE ++#endif ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(CONFIG_ARCH_MT6580) ++#define MTK_BTIF_CG_BIT MT_CG_BTIF_SW_CG ++#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) ++#define MTK_BTIF_CG_BIT MT_CG_PERI_BTIF ++#endif ++#else ++struct clk *clk_btif_apdma; /*btif apdma clock*/ ++struct clk *clk_btif; /*btif clock*/ ++#endif /* !defined(CONFIG_MTK_CLKMGR) */ ++ ++#define BTIF_RBR(base) (unsigned long)(base + 0x0) /*RX Buffer Register: read only */ ++#define BTIF_THR(base) (unsigned long)(base + 0x0) /*Rx Holding Register: write only */ ++#define BTIF_IER(base) (unsigned long)(base + 0x4) /*Interrupt Enable Register: read/write */ ++#define BTIF_IIR(base) (unsigned long)(base + 0x8) /*Interrupt Identification Register: read only */ ++#define BTIF_FIFOCTRL(base) (unsigned long)(base + 0x8) /*FIFO Control Register: write only */ ++#define BTIF_FAKELCR(base) (unsigned long)(base + 0xC) /*FAKE LCR Register: read/write */ ++#define BTIF_LSR(base) (unsigned long)(base + 0x14) /*Line Status Register: read only */ ++#define BTIF_SLEEP_EN(base) (unsigned long)(base + 0x48) /*Sleep Enable Register: read/write */ ++#define BTIF_DMA_EN(base) (unsigned long)(base + 0x4C) /*DMA Enable Register: read/write */ ++#define BTIF_RTOCNT(base) (unsigned long)(base + 0x54) /*Rx Timeout Count Register: read/write */ ++#define BTIF_TRI_LVL(base) (unsigned long)(base + 0x60) /*Tx/Rx Trigger Level Control Register: read/write */ ++#define BTIF_WAK(base) (unsigned long)(base + 0x64) /*BTIF module wakeup Register: write only */ ++#define BTIF_WAT_TIME(base) (unsigned long)(base + 0x68) /*BTIF ASYNC Wait Time Control Register: read/write */ ++#define BTIF_HANDSHAKE(base) (unsigned long)(base + 0x6C) /*BTIF New Handshake Control Register: read/write */ ++ ++/*BTIF_IER bits*/ ++#define BTIF_IER_TXEEN (0x1 << 1) /*1: Tx holding register is empty */ ++#define BTIF_IER_RXFEN (0x1 << 0) /*1: Rx buffer contains data */ ++ ++/*BTIF_IIR bits*/ ++#define BTIF_IIR_NINT (0x1 << 0) /*No INT Pending */ ++#define BTIF_IIR_TX_EMPTY (0x1 << 1) /*Tx Holding Register empty */ ++#define BTIF_IIR_RX (0x1 << 2) /*Rx data received */ ++#define BTIF_IIR_RX_TIMEOUT (0x11 << 2) /*Rx data received */ ++ ++/*BTIF_LSR bits*/ ++#define BTIF_LSR_DR_BIT (0x1 << 0) ++#define BTIF_LSR_THRE_BIT (0x1 << 5) ++#define BTIF_LSR_TEMT_BIT (0x1 << 6) ++ ++/*BTIF_FIFOCTRL bits*/ ++#define BTIF_FIFOCTRL_CLR_TX (0x1 << 2) /*Clear Tx FIRO */ ++#define BTIF_FIFOCTRL_CLR_RX (0x1 << 1) /*Clear Rx FIRO */ ++ ++/*BTIF_FAKELCR bits*/ ++#define BTIF_FAKELCR_NORMAL_MODE 0x0 ++ ++/*BTIF_SLEEP_EN bits*/ ++#define BTIF_SLEEP_EN_BIT (0x1 << 0) /*enable Sleep mode */ ++#define BTIF_SLEEP_DIS_BIT (0x0) /*disable sleep mode */ ++ ++/*BTIF_DMA_EN bits*/ ++#define BTIF_DMA_EN_RX (0x1 << 0) /*Enable Rx DMA */ ++#define BTIF_DMA_EN_TX (0x1 << 1) /*Enable Tx DMA */ ++#define BTIF_DMA_EN_AUTORST_EN (0x1 << 2) /*1: timeout counter will be auto reset */ ++#define BTIF_DMA_EN_AUTORST_DIS (0x0 << 2) /* ++ * 0: after Rx timeout happens, ++ * SW shall reset the interrupt by reading BTIF 0x4C ++ */ ++ ++/*BTIF_TRI_LVL bits*/ ++#define BTIF_TRI_LVL_TX_MASK ((0xf) << 0) ++#define BTIF_TRI_LVL_RX_MASK ((0x7) << 4) ++ ++#define BTIF_TRI_LVL_TX(x) ((x & 0xf) << 0) ++#define BTIF_TRI_LVL_RX(x) ((x & 0x7) << 4) ++ ++#define BTIF_TRI_LOOP_EN (0x1 << 7) ++#define BTIF_TRI_LOOP_DIS (0x0 << 7) ++ ++/*BTIF_WAK bits*/ ++#define BTIF_WAK_BIT (0x1 << 0) ++ ++/*BTIF_HANDSHAKE bits*/ ++#define BTIF_HANDSHAKE_EN_HANDSHAKE 1 ++#define BTIF_HANDSHAKE_DIS_HANDSHAKE 0 ++ ++#define BTIF_TX_FIFO_SIZE 16 ++#define BTIF_RX_FIFO_SIZE 8 ++ ++#define BTIF_TX_FIFO_THRE (BTIF_TX_FIFO_SIZE / 2) ++#define BTIF_RX_FIFO_THRE 0x1 /* 0x5 */ ++ ++#endif /*__HAL_BTIF_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h +new file mode 100644 +index 000000000000..1555d5a50c38 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_PUB_H_ ++#define __HAL_BTIF_PUB_H_ ++ ++#include "plat_common.h" ++ ++/*Enum Defination*/ ++/*BTIF Mode Enum */ ++typedef enum _ENUM_BTIF_MODE_ { ++ BTIF_MODE_PIO = 0, ++ BTIF_MODE_DMA = BTIF_MODE_PIO + 1, ++ BTIF_MODE_MAX, ++} ENUM_BTIF_MODE; ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_info_get ++* DESCRIPTION ++* get btif's information included base address , irq related information ++* PARAMETERS ++* RETURNS ++* BTIF's information ++*****************************************************************************/ ++P_MTK_BTIF_INFO_STR hal_btif_info_get(void); ++ ++#if 0 /*included in hal_btif_info_get */ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_get_irq ++* DESCRIPTION ++* get BTIF module's IRQ information ++* PARAMETERS ++* RETURNS ++* pointer to BTIF's irq structure ++*****************************************************************************/ ++P_MTK_BTIF_IRQ_STR hal_btif_get_irq(void); ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_get_and_prepare ++* DESCRIPTION ++* get clock from device tree and prepare for enable/disable control ++* PARAMETERS ++* pdev device pointer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_get_and_prepare(struct platform_device *pdev); ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_unprepare ++* DESCRIPTION ++* unprepare btif clock and apdma clock ++* PARAMETERS ++* none ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_unprepare(void); ++#endif ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of BTIF module ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_hw_init ++* DESCRIPTION ++* BTIF module init, after this step, BTIF should enable to do tx/rx with PIO ++* mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_cb_reg ++* DESCRIPTION ++* BTIF rx callback register API ++* PARAMETERS ++* p_btif_info [IN] pointer to BTIF's information ++* rx_cb [IN] rx callback function ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, ++ btif_rx_buf_write rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_loopback_ctrl ++* DESCRIPTION ++* BTIF Tx/Rx loopback mode set, this operation can only be done ++* after set BTIF to normal mode ++* PARAMETERS ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_handler ++* DESCRIPTION ++* lower level interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success; negative means fail; positive means rx data length ++*****************************************************************************/ ++int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_mode_ctrl ++* DESCRIPTION ++* set BTIF tx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_mode_ctrl ++* DESCRIPTION ++* set BTIF rx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_send_data ++* DESCRIPTION ++* send data through btif in FIFO mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* positive means number of data sent; ++* 0 means no data put to FIFO; ++* negative means error happens ++*****************************************************************************/ ++int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, ++ const unsigned char *p_buf, const unsigned int buf_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_raise_wak_sig ++* DESCRIPTION ++* raise wakeup signal to counterpart ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_allow ++* DESCRIPTION ++* whether tx is allowed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); ++ ++int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif, MTK_BTIF_PM_OPID opid); ++ ++void mtk_btif_read_cpu_sw_rst_debug_plat(void); ++ ++#endif /*__HAL_BTIF_PUB_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h +new file mode 100644 +index 000000000000..2a1462cb32ff +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h +@@ -0,0 +1,307 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_PUB_H_ ++#define __HAL_PUB_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_OF ++#include ++#include ++#include ++#else ++#include ++#include ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++#include ++#else ++#include ++#include ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++#include ++ ++extern int mtk_btif_hal_get_log_lvl(void); ++ ++#define MTK_BTIF_MARK_UNUSED_API ++ ++typedef irq_handler_t mtk_btif_irq_handler; ++ ++#define MTK_BTIF_ENABLE_CLK_CTL 1 ++#define MTK_BTIF_ENABLE_CLK_REF_COUNTER 1 ++ ++#define DBG_LOG_STR_SIZE 256 ++ ++/*Log defination*/ ++static int hal_log_print(const char *str, ...) ++{ ++ va_list args; ++ char temp_sring[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(temp_sring, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_err("%s", temp_sring); ++ ++ return 0; ++} ++ ++#define BTIF_LOG_LOUD 4 ++#define BTIF_LOG_DBG 3 ++#define BTIF_LOG_INFO 2 ++#define BTIF_LOG_WARN 1 ++#define BTIF_LOG_ERR 0 ++ ++#ifndef DFT_TAG ++#define DFT_TAG "[BTIF-DFT]" ++#endif ++ ++#define BTIF_LOUD_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_LOUD) \ ++ hal_log_print(DFT_TAG "[L]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_INFO_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_INFO)\ ++ hal_log_print(DFT_TAG "[I]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_WARN_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_WARN)\ ++ hal_log_print(DFT_TAG "[W]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_ERR_FUNC(fmt, arg ...)\ ++do {\ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_ERR)\ ++ hal_log_print(DFT_TAG "[E]%s(%d):" fmt,\ ++ __func__, __LINE__, ## arg);\ ++} while (0) ++ ++#define BTIF_DBG_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ ++ hal_log_print(DFT_TAG "[D]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_TRC_FUNC(f) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ ++ hal_log_print(DFT_TAG "<%s> <%d>\n", \ ++ __func__, __LINE__); \ ++} while (0) ++ ++/*-----------------------------------Enum Defination--------------------------------*/ ++/*IRQ sensetive type */ ++typedef enum _ENUM_IRQ_SENS_TYPE_ { ++ IRQ_SENS_EDGE = 0, ++ IRQ_SENS_LVL = IRQ_SENS_EDGE + 1, ++ IRQ_SENS_TYPE_MAX ++} ENUM_IRQ_SENS_TYPE; ++ ++/*IRQ level trigger type */ ++typedef enum _ENUM_IRQ_LVL_TYPE_ { ++ IRQ_LVL_LOW = 0, ++ IRQ_LVL_HIGH = IRQ_LVL_LOW + 1, ++ IRQ_LVL_MAX ++} ENUM_IRQ_LVL; ++ ++/*IRQ edge trigger type */ ++typedef enum _ENUM_IRQ_EDGE_TYPE_ { ++ IRQ_EDGE_FALL = 0, ++ IRQ_EDGE_RAISE = IRQ_EDGE_FALL + 1, ++ IRQ_EDGE_BOTH = IRQ_EDGE_RAISE + 1, ++ IRQ_EDGE_MAX ++} ENUM_IRQ_EDGE; ++ ++typedef enum _ENUM_CLOCK_CTRL_ { ++ CLK_OUT_DISABLE = 0, ++ CLK_OUT_ENABLE = CLK_OUT_DISABLE + 1, ++ CLK_OUT_MAX ++} ENUM_CLOCK_CTRL; ++ ++/*Error No. table */ ++typedef enum _ENUM_ERROR_CODE_ { ++ ERR_NO_ERROR = 0, ++ ERR_INVALID_PAR = ERR_NO_ERROR - 1, ++ ERR_MAX = ERR_INVALID_PAR - 1, ++} ENUM_ERROR_CODE; ++ ++typedef enum _ENUM_BTIF_DIR_ { ++ BTIF_TX = 0, ++ BTIF_RX = BTIF_TX + 1, ++ BTIF_DIR_MAX, ++} ENUM_BTIF_DIR; ++ ++typedef enum _ENUM_DMA_DIR_ { ++ DMA_DIR_RX = 0, ++ DMA_DIR_TX = DMA_DIR_RX + 1, ++ DMA_DIR_BOTH, ++} ENUM_DMA_DIR; ++ ++typedef enum _ENUM_BTIF_REG_ID_ { ++ REG_IIR = 0, /*Interrupt Identification Register */ ++ REG_LSR = 1, /*Line Status Register */ ++ REG_FAKE_LCR = 2, /*Fake Lcr Regiseter */ ++ REG_FIFO_CTRL = 3, /*FIFO Control Register */ ++ REG_IER = 4, /*Interrupt Enable Register */ ++ REG_SLEEP_EN = 5, /*Sleep Enable Register */ ++ REG_RTO_COUNTER = 6, /*Rx Timeout Counter Register */ ++ REG_DMA_EN = 7, /*DMA Enalbe Register */ ++ REG_TRIG_LVL = 8, /*Tx/Rx Trigger Level Register */ ++ REG_WAT_TIME = 9, /*Async Wait Time Register */ ++ REG_HANDSHAKE = 10, /*New HandShake Mode Register */ ++ REG_SLP_WAK = 11, /*Sleep Wakeup Reigster */ ++ REG_BTIF_ALL = 12, /*all btif controller's registers */ ++ REG_TX_DMA_ALL = 13, ++ REG_RX_DMA_ALL = 14, ++ REG_MAX ++} ENUM_BTIF_REG_ID; ++ ++typedef enum _MTK_BTIF_PM_OPID_ { ++ BTIF_PM_DPIDLE_EN, ++ BTIF_PM_DPIDLE_DIS, ++ BTIF_PM_SUSPEND, ++ BTIF_PM_RESUME, ++ BTIF_PM_RESTORE_NOIRQ, ++} MTK_BTIF_PM_OPID; ++ ++#define BTIF_HAL_TX_FIFO_SIZE (1024 * 4) ++ ++/*-----------------------------------Enum Defination End--------------------------------*/ ++ ++/*****************************structure definition***************************/ ++/*IRQ related information*/ ++typedef struct _MTK_BTIF_IRQ_STR_ { ++ const char *name; ++ bool is_irq_sup; ++ unsigned int irq_id; ++#ifdef CONFIG_OF ++ unsigned int irq_flags; ++#else ++ ENUM_IRQ_SENS_TYPE sens_type; ++ union { ++ ENUM_IRQ_LVL lvl_type; ++ ENUM_IRQ_EDGE edge_type; ++ }; ++#endif ++ bool reg_flag; ++ irq_handler_t p_irq_handler; ++} MTK_BTIF_IRQ_STR, *P_MTK_BTIF_IRQ_STR; ++ ++typedef struct _DMA_VFIFO_ { ++ /*[Driver Access] vFIFO memory'svirtual address */ ++ unsigned char *p_vir_addr; ++ /*[HW Access] dma handle , physically address, set to DMA's HW Register */ ++ dma_addr_t phy_addr; ++ /*DMA's vFIFO size */ ++ unsigned int vfifo_size; ++ /*DMA's threshold value */ ++ unsigned int thre; ++} DMA_VFIFO, *P_DMA_VFIFO; ++ ++typedef unsigned int (*dma_rx_buf_write) (void *p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++typedef unsigned int (*btif_rx_buf_write) (void *p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++ ++/*DMA related information*/ ++typedef struct _MTK_DMA_INFO_STR_ { ++ unsigned long base; ++ ENUM_DMA_DIR dir; ++ P_MTK_BTIF_IRQ_STR p_irq; ++ dma_rx_buf_write rx_cb; ++ P_DMA_VFIFO p_vfifo; ++} MTK_DMA_INFO_STR, *P_MTK_DMA_INFO_STR; ++ ++/*DMA related information*/ ++typedef struct _MTK_BTIF_INFO_STR_ { ++ unsigned long base; /*base address */ ++ P_MTK_BTIF_IRQ_STR p_irq; /*irq related information */ ++ ++ unsigned int tx_fifo_size; /*BTIF tx FIFO size */ ++ unsigned int rx_fifo_size; /*BTIF rx FIFO size */ ++ ++ unsigned int tx_tri_lvl; /*BTIFtx trigger level in FIFO mode */ ++ unsigned int rx_tri_lvl; /*BTIFrx trigger level in FIFO mode */ ++ ++ unsigned int clk_gat_addr; /*clock gating address */ ++ unsigned int set_bit; /*enable clock gating bit */ ++ unsigned int clr_bit; /*clear clock gating bit */ ++ ++ unsigned int rx_data_len; /*rx data length */ ++ ++ btif_rx_buf_write rx_cb; ++ ++ struct kfifo *p_tx_fifo; /*tx fifo */ ++ spinlock_t tx_fifo_spinlock; /*tx fifo spinlock */ ++} MTK_BTIF_INFO_STR, *P_MTK_BTIF_INFO_STR; ++ ++/**********End of Structure Definition***********/ ++ ++/***********register operation***********/ ++#ifdef __KERNEL__ ++/*byte write <1 byte> */ ++#define btif_reg_sync_writeb(v, a) mt_reg_sync_writeb(v, a) ++/*word write <2 byte> */ ++#define btif_reg_sync_writew(v, a) mt_reg_sync_writew(v, a) ++/*long write <4 byte> */ ++#define btif_reg_sync_writel(v, a) mt_reg_sync_writel(v, a) ++#else ++/*byte write <1 byte> */ ++#define btif_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) ++/*word write <2 byte> */ ++#define btif_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) ++/*long write <4 byte> */ ++#define btif_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) ++#endif ++#define BTIF_READ8(REG) __raw_readb((unsigned char *)(REG)) ++#define BTIF_READ16(REG) __raw_readw((unsigned short *)(REG)) ++#define BTIF_READ32(REG) __raw_readl((unsigned int *)(REG)) ++ ++#define BTIF_SET_BIT(REG, BITVAL) do { \ ++*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL)); \ ++mb(); /**/ \ ++} \ ++while (0) ++#define BTIF_CLR_BIT(REG, BITVAL) do { \ ++(*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL)); \ ++mb(); /**/\ ++} \ ++while (0) ++ ++/***********end of register operation *********/ ++ ++#endif /*__HAL_PUB_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/Kconfig b/drivers/misc/mediatek/connectivity/Kconfig +new file mode 100644 +index 000000000000..aa4c3e6f71c9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/Kconfig +@@ -0,0 +1,298 @@ ++config MTK_COMBO ++ tristate "MediaTek Connectivity Combo Chip Support" ++ help ++ MTK connectivity combo chip driver for MT66xx ++ ++# ++# MTK Combo Chip Selection ++# ++ ++choice ++ prompt "Select Chip" ++ depends on MTK_COMBO ++ ++config MTK_COMBO_CHIP_MT6620 ++ bool "MT6620" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6620 ++ ++config MTK_COMBO_CHIP_MT6628 ++ bool "MT6628" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6628 ++ ++config MTK_COMBO_CHIP_MT6630 ++ bool "MT6630" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6630 ++ ++config MTK_COMBO_CHIP_CONSYS_6572 ++ bool "CONSYS_6572" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6572 ++ ++config MTK_COMBO_CHIP_CONSYS_6582 ++ bool "CONSYS_6582" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6582 ++ ++config MTK_COMBO_CHIP_CONSYS_8127 ++ bool "CONSYS_8127" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6572 ++ ++config MTK_COMBO_CHIP_CONSYS_7623 ++ bool "CONSYS_7623" ++ help ++ this config is used to decide SOC consys version ++ in current platform is MT7623 and prepare proper ++ system services like radio power on/off and firmware ++ download for the Bluetotoh and Wifi. ++ ++ ++config MTK_COMBO_CHIP_CONSYS_6752 ++ bool "CONSYS_6752" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6752 ++ ++config MTK_COMBO_CHIP_CONSYS_6592 ++ bool "CONSYS_6592" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6592 ++ ++config MTK_COMBO_CHIP_CONSYS_8163 ++ bool "CONSYS_8163" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT8163 ++ ++config MTK_COMBO_CHIP_CONSYS_6735 ++ bool "CONSYS_6735" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6735 ++ ++config MTK_COMBO_CHIP_CONSYS_6755 ++ bool "CONSYS_6755" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6755 ++ ++config MTK_COMBO_CHIP_CONSYS_6580 ++ bool "CONSYS_6580" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6580 ++ ++config MTK_COMBO_CHIP_CONSYS_6797 ++ bool "CONSYS_6797" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6797 ++endchoice ++ ++config MTK_COMBO_CHIP ++ string ++ default "MT6620" if MTK_COMBO_CHIP_MT6620 ++ default "MT6628" if MTK_COMBO_CHIP_MT6628 ++ default "MT6630" if MTK_COMBO_CHIP_MT6630 ++ default "CONSYS_6572" if MTK_COMBO_CHIP_CONSYS_6572 ++ default "CONSYS_6582" if MTK_COMBO_CHIP_CONSYS_6582 ++ default "CONSYS_8127" if MTK_COMBO_CHIP_CONSYS_8127 ++ default "CONSYS_7623" if MTK_COMBO_CHIP_CONSYS_7623 ++ default "CONSYS_6752" if MTK_COMBO_CHIP_CONSYS_6752 ++ default "CONSYS_6755" if MTK_COMBO_CHIP_CONSYS_6755 ++ default "CONSYS_6592" if MTK_COMBO_CHIP_CONSYS_6592 ++ default "CONSYS_8163" if MTK_COMBO_CHIP_CONSYS_8163 ++ default "CONSYS_6735" if MTK_COMBO_CHIP_CONSYS_6735 ++ default "CONSYS_6580" if MTK_COMBO_CHIP_CONSYS_6580 ++ default "CONSYS_6797" if MTK_COMBO_CHIP_CONSYS_6797 ++ help ++ this feature is used to identify combo chip version or SOC chip ++ consys version. ++ ++# ++# Target Platform Selection ++# ++config MTK_COMBO_PLAT_PATH ++ string "Platform folder name" ++ depends on MTK_COMBO ++ default "sample" if MTK_COMBO_PLAT_SAMPLE ++ help ++ Specify platform folder under common driver platform folder: ++ mtk_wcn_combo/common/platform/* ++ ++# ++# MTK COMBO Chip Configuration ++# ++config MTK_COMBO_COMM ++ depends on MTK_COMBO ++ tristate "MediaTek Combo Chip Common part driver" ++ help ++ MediaTek combo chip common part driver ++ ++#config MTK_COMBO_COMM_PS ++# depends on MTK_COMBO_COMM ++# bool "Enable PS support" ++# default n ++# help ++# Enable PS support of common UART interface ++ ++config MTK_COMBO_COMM_UART ++ depends on MTK_COMBO_COMM ++ tristate "Common interface UART" ++ help ++ Use UART for common part interface type ++ ++config MTK_COMBO_COMM_SDIO ++ depends on MTK_COMBO_COMM ++ tristate "Common interface SDIO" ++ help ++ Use SDIO for common part interface type ++ ++config MTK_COMBO_COMM_NPWR ++ depends on MTK_COMBO_COMM ++ bool "Enable NPWR support" ++ default n ++ help ++ Enable NPWR support of new power on swquence ++ ++config MTK_COMBO_COMM_APO ++ depends on MTK_COMBO_COMM ++ bool "Enable always power on support" ++ #default y ++ help ++ Enable chip will always power on ++ ++config MTK_COMBO_BT ++ tristate "MediaTek Combo Chip BT driver" ++ depends on MTK_COMBO ++ select MTK_BTIF ++ help ++ MTK BT /dev/stpbt driver for Bluedroid ++ ++config MTK_COMBO_BT_HCI ++ tristate "MediaTek Combo Chip BlueZ driver" ++ depends on BT && MTK_COMBO ++ select MTK_BTIF ++ help ++ MTK BT driver for BlueZ ++ ++config MTK_COMBO_WIFI ++ tristate "MediaTek combo chip Wi-Fi support" ++ depends on MTK_COMBO ++ select MTK_BTIF ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ ++config MTK_WAPI_SUPPORT ++ bool "MTK_WAPI_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ #default y ++ help ++ if it is set to TRUE: Support WAPI (WLAN Authentication and ++ Privacy Infrastructure) ++ ++config MTK_PASSPOINT_R1_SUPPORT ++ bool "MTK_PASSPOINT_R1_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ help ++ Support Passpoint R1 (Hotspot 2.0 R1) ++ ++config MTK_PASSPOINT_R2_SUPPORT ++ bool "MTK_PASSPOINT_R2_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ help ++ Support Passpoint R2 ++ ++config MTK_WIFI_MCC_SUPPORT ++ bool "MTK_WIFI_MCC_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ #default y ++ help ++ if it is set to TRUE, wlan will support Multi-Channel Concurrency, ++ otherwise, only support Single Channel Concurrency ++ ++config MTK_DHCPV6C_WIFI ++ bool "MTK_DHCPV6C_WIFI" ++ help ++ no: disable this feature ++ ++config MTK_CONN_LTE_IDC_SUPPORT ++ bool "MediaTek CONN LTE IDC support" ++ select MTK_CONN_MD ++ #default y ++ help ++ This option enables CONN LTE IDC support ++ ++menuconfig GPS ++ tristate "GPS drivers" ++ #default y ++ ---help--- ++ Say Y here for supporting GPS. ++ ++if GPS ++config MTK_GPS ++ tristate "MediaTek GPS driver" ++ #default y ++ ---help--- ++ MTK GPS driver ++ To switch gps nmea port driver. ++ Set "yes" to turn on. ++ Set "no" to turn off. ++endif # GPS ++ ++config MTK_GPS_SUPPORT ++ tristate "MediaTek GPS driver" ++ select MTK_GPS ++ help ++ to switch GPS feature on the platform. ++ Set "yes" to turn on and set "no" ++ (with MTK_AGPS_APP=no at the same time) ++ to turn off. ++ ++config MTK_GPS_REGISTER_SETTING ++ tristate "MediaTek GPS Register Setting" ++ depends on MTK_COMBO_GPS ++ help ++ GPS register settings. ++ ++config MTK_GPS_EMI ++ tristate "MediaTek GPS EMI Driver" ++ depends on MTK_COMBO_GPS ++ help ++ GPS EMI driver is for MNL OFFLOAD feature. +diff --git a/drivers/misc/mediatek/connectivity/Makefile b/drivers/misc/mediatek/connectivity/Makefile +new file mode 100644 +index 000000000000..0947788d189a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/Makefile +@@ -0,0 +1,41 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# Connectivity combo driver ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++subdir-ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE ++ifeq ($(CONFIG_ARM64), y) ++subdir-ccflags-y += -D CONFIG_MTK_WCN_ARM64 ++endif ++ ++ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) ++ subdir-ccflags-y += -D WMT_IDC_SUPPORT=1 ++else ++ subdir-ccflags-y += -D WMT_IDC_SUPPORT=0 ++endif ++ subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++ obj-y += common/ ++ obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/ ++ obj-n := dummy.o ++ ++# Otherwise we were called directly from the command line; ++# invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/Makefile b/drivers/misc/mediatek/connectivity/common/Makefile +new file mode 100644 +index 000000000000..622b74430e13 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/Makefile +@@ -0,0 +1,23 @@ ++subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include ++subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat ++ ++#ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) ++# obj-y += combo/ ++#endif ++#ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) ++# subdir-ccflags-y += -D MT6628 ++# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT ++# obj-y += combo/ ++#endif ++#ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++# subdir-ccflags-y += -D MT6630 ++#ifneq ($(CONFIG_ARCH_MT2601),y) ++# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT ++#endif ++# obj-y += combo/ ++#endif ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ obj-y += conn_soc/ ++endif ++ ++obj-y += common_detect/ +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile +new file mode 100644 +index 000000000000..8d7dc690affd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile +@@ -0,0 +1,47 @@ ++subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/$(ARCH_MTK_PROJECT)/dct/dct ++subdir-ccflags-y += -DWMT_PLAT_ALPS=1 ++ ++COMBO_CHIP_SUPPORT := false ++ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifeq ($(COMBO_CHIP_SUPPORT), true) ++ subdir-ccflags-y += -D MTK_WCN_COMBO_CHIP_SUPPORT ++ ccflags-y += -I$(src)/../combo/linux/include ++endif ++ ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ subdir-ccflags-y += -D MTK_WCN_SOC_CHIP_SUPPORT ++ ccflags-y += -I$(src)/../conn_soc/linux/include ++endif ++ ++ ++ifeq ($(CONFIG_MTK_COMBO),y) ++ ccflags-y += -I$(src)/drv_init/inc ++ obj-y += mtk_wcn_stub_alps.o ++ obj-y += wmt_stp_exp.o ++ obj-y += wmt_gpio.o ++ ++ obj-y += wmt_detect.o ++ obj-y += sdio_detect.o ++ obj-y += wmt_detect_pwr.o ++ ++ obj-y += drv_init/ ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO),m) ++ obj-y += mtk_wcn_stub_alps.o ++ obj-y += wmt_stp_exp.o ++ obj-y += wmt_gpio.o ++ ++ obj-$(CONFIG_MTK_COMBO) += mtk_wmt_detect.o ++ mtk_wmt_detect-objs := wmt_detect.o ++ mtk_wmt_detect-objs += sdio_detect.o ++ mtk_wmt_detect-objs += wmt_detect_pwr.o ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +new file mode 100644 +index 000000000000..bb84384b9a24 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +@@ -0,0 +1,22 @@ ++ifeq ($(CONFIG_MTK_COMBO),y) ++ ccflags-y += -I$(src)/inc/ ++ ccflags-y += -I$(src)/../ ++ ++ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN3 ++endif ++ifneq ($(filter "CONSYS_6797",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN3 ++else ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN2 ++endif ++ ++ obj-y += conn_drv_init.o ++ obj-y += common_drv_init.o ++ obj-y += bluetooth_drv_init.o ++ obj-y += gps_drv_init.o ++ obj-y += fm_drv_init.o ++ obj-y += wlan_drv_init.o ++ obj-($(CONFIG_MTK_COMBO_ANT)) += ant_drv_init.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c +new file mode 100644 +index 000000000000..aa453f9397a4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c +@@ -0,0 +1,38 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[ANT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "ant_drv_init.h" ++ ++int do_ant_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++ ++ WMT_DETECT_INFO_FUNC("start to do ANT driver init\n"); ++ switch (chip_id) { ++ case 0x6630: ++ case 0x6797: ++ i_ret = mtk_wcn_stpant_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish ANT driver init, i_ret:%d\n", i_ret); ++ break; ++ default: ++ WMT_DETECT_ERR_FUNC("chipid is not 6630,ANT is not supported!\n"); ++ } ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +new file mode 100644 +index 000000000000..47b055433443 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +@@ -0,0 +1,35 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[BT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "bluetooth_drv_init.h" ++ ++int do_bluetooth_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++ ++#if defined(CONFIG_MTK_COMBO_BT) || defined(CONFIG_MTK_COMBO_BT_HCI) ++ WMT_DETECT_INFO_FUNC("start to do bluetooth driver init\n"); ++ i_ret = mtk_wcn_stpbt_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish bluetooth driver init, i_ret:%d\n", i_ret); ++#else ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_BT is not defined\n"); ++#endif ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c +new file mode 100644 +index 000000000000..f9c332ea266b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c +@@ -0,0 +1,103 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "common_drv_init.h" ++ ++static int do_combo_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ int i_ret_tmp = 0; ++ ++ WMT_DETECT_DBG_FUNC("start to do combo driver init, chipid:0x%08x\n", chip_id); ++ ++ /* HIF-SDIO driver init */ ++ i_ret_tmp = mtk_wcn_hif_sdio_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("HIF-SDIO driver init, i_ret:%d\n", i_ret); ++ ++ /* WMT driver init */ ++ i_ret_tmp = mtk_wcn_combo_common_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); ++ ++ /* STP-UART driver init */ ++ i_ret_tmp = mtk_wcn_stp_uart_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("STP-UART driver init, i_ret:%d\n", i_ret); ++ ++ /* STP-SDIO driver init */ ++ i_ret_tmp = mtk_wcn_stp_sdio_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("STP-SDIO driver init, i_ret:%d\n", i_ret); ++ ++#else ++ i_ret = -1; ++ WMT_DETECT_ERR_FUNC("COMBO chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); ++#endif ++ WMT_DETECT_DBG_FUNC("finish combo driver init\n"); ++ return i_ret; ++} ++ ++static int do_soc_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++ int i_ret_tmp = 0; ++ ++ WMT_DETECT_DBG_FUNC("start to do soc common driver init, chipid:0x%08x\n", chip_id); ++ ++ /* WMT driver init */ ++ i_ret_tmp = mtk_wcn_soc_common_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); ++ ++#else ++ i_ret = -1; ++ WMT_DETECT_ERR_FUNC("SOC chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); ++#endif ++ ++ WMT_DETECT_DBG_FUNC("TBD........\n"); ++ return i_ret; ++} ++ ++int do_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++ WMT_DETECT_INFO_FUNC("start to do common driver init, chipid:0x%08x\n", chip_id); ++ ++ switch (chip_id) { ++ case 0x6620: ++ case 0x6628: ++ case 0x6630: ++ i_ret = do_combo_common_drv_init(chip_id); ++ break; ++ default: ++ i_ret = do_soc_common_drv_init(chip_id); ++ break; ++ } ++ ++ WMT_DETECT_INFO_FUNC("finish common driver init\n"); ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c +new file mode 100644 +index 000000000000..8112d2a1d95e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c +@@ -0,0 +1,80 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WCN-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "conn_drv_init.h" ++#include "common_drv_init.h" ++#include "fm_drv_init.h" ++#include "wlan_drv_init.h" ++#include "bluetooth_drv_init.h" ++#include "gps_drv_init.h" ++#include "ant_drv_init.h" ++ ++int __weak do_wlan_drv_init(int chip_id) ++{ ++ WMT_DETECT_ERR_FUNC("Can not find wlan module for chip: %d !\n", chip_id); ++ return 0; ++} ++ ++int __weak do_ant_drv_init(int chip_id) ++{ ++ WMT_DETECT_DBG_FUNC("Chip: %d can not support ANT !\n", chip_id); ++ return 0; ++} ++ ++int do_connectivity_driver_init(int chip_id) ++{ ++ int i_ret = 0; ++ int tmp_ret = 0; ++ ++ tmp_ret = do_common_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) { ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ WMT_DETECT_ERR_FUNC("abort connectivity driver init, because common part is not ready\n"); ++ return i_ret; ++ } ++ ++ tmp_ret = do_bluetooth_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_gps_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_fm_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do fm module init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_wlan_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do wlan module init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_ant_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do ANT module init failed, ret:%d\n", tmp_ret); ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c +new file mode 100644 +index 000000000000..069c1cf13bba +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c +@@ -0,0 +1,33 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[FM-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "fm_drv_init.h" ++ ++int do_fm_drv_init(int chip_id) ++{ ++ WMT_DETECT_INFO_FUNC("start to do fm module init\n"); ++ ++#ifdef CONFIG_MTK_FMRADIO ++ mtk_wcn_fm_init(); ++#endif ++ ++ WMT_DETECT_INFO_FUNC("finish fm module init\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c +new file mode 100644 +index 000000000000..6da1d70a3ca6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c +@@ -0,0 +1,35 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[GPS-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "gps_drv_init.h" ++ ++int do_gps_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++#ifdef CONFIG_MTK_COMBO_GPS ++ WMT_DETECT_INFO_FUNC("start to do gps driver init\n"); ++ i_ret = mtk_wcn_stpgps_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish gps driver init, i_ret:%d\n", i_ret); ++#else ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_GPS is not defined\n"); ++#endif ++ return i_ret; ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h +new file mode 100644 +index 000000000000..4a436a236290 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _ANT_DRIVER_INIT_H_ ++#define _ANT_DRIVER_INIT_H_ ++ ++extern int do_ant_drv_init(int chip_id); ++extern int mtk_wcn_stpant_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h +new file mode 100644 +index 000000000000..8a847d361fc8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _BLUETOOTH_DRIVER_INIT_H_ ++#define _BLUETOOTH_DRIVER_INIT_H_ ++ ++extern int do_bluetooth_drv_init(int chip_id); ++extern int mtk_wcn_stpbt_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h +new file mode 100644 +index 000000000000..ea01bd633c3c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h +@@ -0,0 +1,31 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _COMMON_DRV_INIT_H_ ++#define _COMMON_DRV_INIT_H_ ++extern int do_common_drv_init(int chip_id); ++ ++/*defined in common part driver*/ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++extern int mtk_wcn_combo_common_drv_init(void); ++extern int mtk_wcn_hif_sdio_drv_init(void); ++extern int mtk_wcn_stp_uart_drv_init(void); ++extern int mtk_wcn_stp_sdio_drv_init(void); ++#endif ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++extern int mtk_wcn_soc_common_drv_init(void); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h +new file mode 100644 +index 000000000000..971193eade9e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h +@@ -0,0 +1,18 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _CONNECTIVITY_DRV_INIT_H_ ++#define _CONNECTIVITY_DRV_INIT_H_ ++extern int do_connectivity_driver_init(int chip_id); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h +new file mode 100644 +index 000000000000..f6ea30addc5d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _FM_DRV_INIT_H_ ++#define _FM_DRV_INIT_H_ ++extern int do_fm_drv_init(int chip_id); ++extern int mtk_wcn_fm_init(void); ++extern void mtk_wcn_fm_exit(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h +new file mode 100644 +index 000000000000..006ce072c53b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h +@@ -0,0 +1,19 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _GPS_DRIVER_INIT_H_ ++#define _GPS_DRIVER_INIT_H_ ++extern int do_gps_drv_init(int chip_id); ++extern int mtk_wcn_stpgps_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h +new file mode 100644 +index 000000000000..cb71b50bf950 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h +@@ -0,0 +1,30 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WLAN_DRV_INIT_H_ ++#define _WLAN_DRV_INIT_H_ ++ ++ ++extern int do_wlan_drv_init(int chip_id); ++ ++extern int mtk_wcn_wmt_wifi_init(void); ++ ++#ifdef MTK_WCN_WLAN_GEN2 ++extern int mtk_wcn_wlan_gen2_init(void); ++#endif ++#ifdef MTK_WCN_WLAN_GEN3 ++extern int mtk_wcn_wlan_gen3_init(void); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +new file mode 100644 +index 000000000000..5b0d039a4a42 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WLAN-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "wlan_drv_init.h" ++ ++ ++int do_wlan_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef CONFIG_MTK_COMBO_WIFI ++ int ret = 0; ++ ++ WMT_DETECT_INFO_FUNC("start to do wlan module init 0x%x\n", chip_id); ++ ++ /* WMT-WIFI char dev init */ ++ ret = mtk_wcn_wmt_wifi_init(); ++ WMT_DETECT_INFO_FUNC("WMT-WIFI char dev init, ret:%d\n", ret); ++ i_ret += ret; ++ ++ switch (chip_id) { ++ case 0x6630: ++ case 0x6797: ++#ifdef MTK_WCN_WLAN_GEN3 ++ /* WLAN driver init */ ++ ret = mtk_wcn_wlan_gen3_init(); ++ WMT_DETECT_INFO_FUNC("WLAN-GEN3 driver init, ret:%d\n", ret); ++ i_ret += ret; ++#else ++ WMT_DETECT_ERR_FUNC("WLAN-GEN3 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); ++ i_ret = -1; ++#endif ++ break; ++ ++ default: ++#ifdef MTK_WCN_WLAN_GEN2 ++ /* WLAN driver init */ ++ ret = mtk_wcn_wlan_gen2_init(); ++ WMT_DETECT_INFO_FUNC("WLAN-GEN2 driver init, ret:%d\n", ret); ++ i_ret += ret; ++#else ++ WMT_DETECT_ERR_FUNC("WLAN-GEN2 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); ++ i_ret = -1; ++#endif ++ break; ++ } ++ ++ WMT_DETECT_INFO_FUNC("finish wlan module init\n"); ++ ++#else ++ ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_WIFI is not defined\n"); ++ ++#endif ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c +new file mode 100644 +index 000000000000..fa8d437686f2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c +@@ -0,0 +1,605 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CMB_STUB_DBG_LOG 3 ++#define CMB_STUB_INFO_LOG 2 ++#define CMB_STUB_WARN_LOG 1 ++ ++int gCmbStubLogLevel = CMB_STUB_INFO_LOG; ++ ++#define CMB_STUB_LOG_INFO(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_INFO_LOG) \ ++ pr_warn(fmt, ##arg); \ ++} while (0) ++#define CMB_STUB_LOG_WARN(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_WARN_LOG) \ ++ pr_warn(fmt, ##arg); \ ++} while (0) ++#define CMB_STUB_LOG_DBG(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_DBG_LOG) \ ++ pr_debug(fmt, ##arg); \ ++} while (0) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wmt_detect.h" ++ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 ++#endif ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++struct work_struct *g_sdio_1v_autok_wk = NULL; ++#endif ++int gConnectivityChipId = -1; ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++/* ++* current used uart port name, default is "ttyMT2", ++* will be changed when wmt driver init ++*/ ++char *wmt_uart_port_desc = "ttyMT2"; ++EXPORT_SYMBOL(wmt_uart_port_desc); ++#endif ++ ++static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data); ++static void mtk_wcn_cmb_sdio_enable_eirq(void); ++static void mtk_wcn_cmb_sdio_disable_eirq(void); ++static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data); ++ ++struct sdio_ops mt_sdio_ops[4] = { ++ {NULL, NULL, NULL, NULL}, ++ {NULL, NULL, NULL, NULL}, ++ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, ++ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}, ++ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, ++ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm} ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb; ++static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb; ++static wmt_thermal_query_cb cmb_stub_thermal_ctrl_cb; ++static CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0; ++static wmt_deep_idle_ctrl_cb cmb_stub_deep_idle_ctrl_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++static wmt_get_drv_status cmb_stub_drv_status_ctrl_cb; ++#endif ++static wmt_func_do_reset cmb_stub_do_reset_cb; ++/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X. ++ * This is used for ALPS backward compatible ONLY!!! Remove this table, related ++ * functions, and type definition after modifying other kernel built-in modules, ++ * such as AUDIO. [FixMe][GeorgeKuo] ++ */ ++#if 0 ++static CMB_STUB_AIF_X audio2aif[] = { ++ [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0, ++ [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1, ++ [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2, ++ [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3, ++}; ++#endif ++static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler; ++static atomic_t sdio_claim_irq_enable_flag; ++static atomic_t irq_enable_flag; ++static pm_callback_t mtk_wcn_cmb_sdio_pm_cb; ++static void *mtk_wcn_cmb_sdio_pm_data; ++static void *mtk_wcn_cmb_sdio_eirq_data; ++ ++static u32 wifi_irq = 0xffffffff; ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++static void mtk_wcn_cmb_stub_1v_autok_work(struct work_struct *work) ++{ ++ CMB_STUB_LOG_WARN("++enter++\n"); ++ mtk_wcn_cmb_stub_func_ctrl(11, 1); ++ mtk_wcn_cmb_stub_func_ctrl(11, 0); ++ CMB_STUB_LOG_WARN("--exit--\n"); ++} ++ ++/*! ++ * \brief A function for Getting current driver status:on/off ++ * ++ * \param driver type:0/bt,1/fm,2/gps,3/wifi,11/autok->run wmt turn on/off wifi flow ++ * ++ * \retval 0/off,2/on,-1/null pointer ++ */ ++static int mtk_wcn_cmb_stub_drv_status(unsigned int type) ++{ ++ int ret = -1; ++ ++ if (cmb_stub_drv_status_ctrl_cb) ++ ret = (*cmb_stub_drv_status_ctrl_cb) (type); ++ else ++ CMB_STUB_LOG_WARN("cmb_stub_drv_status_ctrl_cb is NULL\n"); ++ return ret; ++} ++ ++/*! ++ * \brief A 1v AutoK function for kernel DVFS driver calling when screen off ++ * ++ * \param void ++ * ++ * \retval int,mt6630 state:0/off,1/power on,2/func on, -1/null ++ */ ++int mtk_wcn_cmb_stub_1vautok_for_dvfs(void) ++{ ++ int wmt_status; ++ ++ CMB_STUB_LOG_WARN("DVFS driver call sdio 1v autok\n"); ++ ++ wmt_status = mtk_wcn_cmb_stub_drv_status(4); ++ CMB_STUB_LOG_WARN("current mt6630 status is %d\n", wmt_status); ++ if (0 == wmt_status) { ++ if (g_sdio_1v_autok_wk) ++ schedule_work(g_sdio_1v_autok_wk); ++ else ++ CMB_STUB_LOG_WARN("g_sdio_1v_autok_wk is NULL\n"); ++ } else if ((2 == wmt_status) || (1 == wmt_status)) { ++ CMB_STUB_LOG_WARN("mt6630 is on state,skip AUTOK\n"); ++ } else { ++ CMB_STUB_LOG_WARN("mt6630 is unknown state(%d)\n", wmt_status); ++ } ++ ++ return wmt_status; ++ ++} ++#endif ++/*! ++ * \brief A registration function for WMT-PLAT to register itself to CMB-STUB. ++ * ++ * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register ++ * itself and related callback functions when driver being loaded into kernel. ++ * ++ * \param p_stub_cb a pointer carrying CMB_STUB_CB information ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ */ ++int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb) ++{ ++ if ((!p_stub_cb) ++ || (p_stub_cb->size != sizeof(CMB_STUB_CB))) { ++ CMB_STUB_LOG_WARN("[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n", ++ p_stub_cb, (p_stub_cb) ? p_stub_cb->size : 0); ++ return -1; ++ } ++ ++ CMB_STUB_LOG_DBG("[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n", p_stub_cb, p_stub_cb->size); ++ ++ cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb; ++ cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb; ++ cmb_stub_thermal_ctrl_cb = p_stub_cb->thermal_query_cb; ++ cmb_stub_deep_idle_ctrl_cb = p_stub_cb->deep_idle_ctrl_cb; ++ cmb_stub_do_reset_cb = p_stub_cb->wmt_do_reset_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ cmb_stub_drv_status_ctrl_cb = p_stub_cb->get_drv_status_cb; ++ g_sdio_1v_autok_wk = vmalloc(sizeof(struct work_struct)); ++ if (!g_sdio_1v_autok_wk) ++ CMB_STUB_LOG_WARN("vmalloc work_struct(%zd) fail\n", sizeof(struct work_struct)); ++ else ++ INIT_WORK(g_sdio_1v_autok_wk, mtk_wcn_cmb_stub_1v_autok_work); ++ ++#endif ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg); ++/*! ++ * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB. ++ * ++ * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to ++ * unregister itself and clear callback function references. ++ * ++ * \retval 0 operation success ++ */ ++int mtk_wcn_cmb_stub_unreg(void) ++{ ++ cmb_stub_aif_ctrl_cb = NULL; ++ cmb_stub_func_ctrl_cb = NULL; ++ cmb_stub_thermal_ctrl_cb = NULL; ++ cmb_stub_deep_idle_ctrl_cb = NULL; ++ cmb_stub_do_reset_cb = NULL; ++ CMB_STUB_LOG_INFO("[cmb_stub] unregistered\n"); /* KERN_DEBUG */ ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ if (g_sdio_1v_autok_wk) { ++ vfree(g_sdio_1v_autok_wk); ++ g_sdio_1v_autok_wk = NULL; ++ } ++#endif ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg); ++ ++/* stub functions for kernel to control audio path pin mux */ ++int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) ++{ ++ int ret; ++ ++ if ((CMB_STUB_AIF_MAX <= state) ++ || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { ++ ++ CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n", state, ctrl); ++ return -1; ++ } ++ ++ /* avoid the early interrupt before we register the eirq_handler */ ++ if (cmb_stub_aif_ctrl_cb) { ++ ret = (*cmb_stub_aif_ctrl_cb) (state, ctrl); ++ CMB_STUB_LOG_INFO("[cmb_stub] aif_ctrl_cb state(%d->%d) ctrl(%d) ret(%d)\n", ++ cmb_stub_aif_stat, state, ctrl, ret); /* KERN_DEBUG */ ++ ++ cmb_stub_aif_stat = state; ++ } else { ++ CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl_cb null\n"); ++ ret = -2; ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl); ++ ++/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X ++ * for ALPS backward compatible ONLY!!! Remove this table, related functions, ++ * and type definition after modifying other kernel built-in modules, such as ++ * AUDIO. [FixMe][GeorgeKuo] ++ */ ++ ++void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on) ++{ ++ if (cmb_stub_func_ctrl_cb) ++ (*cmb_stub_func_ctrl_cb) (type, on); ++ else ++ CMB_STUB_LOG_WARN("[cmb_stub] func_ctrl_cb null\n"); ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl); ++ ++int mtk_wcn_cmb_stub_query_ctrl(void) ++{ ++ signed long temp = 0; ++ ++ if (cmb_stub_thermal_ctrl_cb) ++ temp = (*cmb_stub_thermal_ctrl_cb) (); ++ else ++ CMB_STUB_LOG_WARN("[cmb_stub] thermal_ctrl_cb null\n"); ++ ++ return temp; ++} ++ ++/*platform-related APIs*/ ++/* void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); */ ++/* void set_device_working_ability(UINT32 clockId, MT6573_STATE state); */ ++ ++static int _mt_combo_plt_do_deep_idle(COMBO_IF src, int enter) ++{ ++ int ret = -1; ++ ++#if 0 ++ if (src != COMBO_IF_UART && src != COMBO_IF_MSDC && src != COMBO_IF_BTIF) { ++ CMB_STUB_LOG_WARN("src = %d is error\n", src); ++ return ret; ++ } ++ if (src >= 0 && src < COMBO_IF_MAX) ++ CMB_STUB_LOG_INFO("src = %s, to enter deep idle? %d\n", combo_if_name[src], enter); ++#endif ++ /*TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI ++ to decide if the msdc will enter deep idle safely */ ++ ++ switch (src) { ++ case COMBO_IF_UART: ++ if (enter == 0) { ++ /* clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ ++ /* disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++#if 0 ++ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 0); ++ if (ret < 0) ++ CMB_STUB_LOG_WARN("[CMB] %s exit deep idle failed\n", wmt_uart_port_desc); ++#endif ++#endif ++ } else { ++ /* set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ ++ /* enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++#if 0 ++ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 1); ++ if (ret < 0) ++ CMB_STUB_LOG_WARN("[CMB] %s enter deep idle failed\n", wmt_uart_port_desc); ++#endif ++#endif ++ } ++ ret = 0; ++ break; ++ ++ case COMBO_IF_MSDC: ++ if (enter == 0) { ++ /* for common sdio hif */ ++ /* clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ ++ } else { ++ /* for common sdio hif */ ++ /* set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ ++ } ++ ret = 0; ++ break; ++ ++ case COMBO_IF_BTIF: ++ if (cmb_stub_deep_idle_ctrl_cb) ++ ret = (*cmb_stub_deep_idle_ctrl_cb) (enter); ++ else ++ CMB_STUB_LOG_WARN("NULL function pointer\n"); ++ ++ if (ret) ++ CMB_STUB_LOG_WARN("%s deep idle fail(%d)\n", enter == 1 ? "enter" : "exit", ret); ++ else ++ CMB_STUB_LOG_DBG("%s deep idle ok(%d)\n", enter == 1 ? "enter" : "exit", ret); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++int mt_combo_plt_enter_deep_idle(COMBO_IF src) ++{ ++ /* return 0; */ ++ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ ++ return _mt_combo_plt_do_deep_idle(src, 1); ++} ++EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle); ++ ++int mt_combo_plt_exit_deep_idle(COMBO_IF src) ++{ ++ /* return 0; */ ++ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ ++ return _mt_combo_plt_do_deep_idle(src, 0); ++} ++EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle); ++ ++int mtk_wcn_wmt_chipid_query(void) ++{ ++ return gConnectivityChipId; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query); ++ ++void mtk_wcn_wmt_set_chipid(int chipid) ++{ ++ CMB_STUB_LOG_INFO("set current consys chipid (0x%x)\n", chipid); ++ gConnectivityChipId = chipid; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_set_chipid); ++ ++int mtk_wcn_cmb_stub_do_reset(unsigned int type) ++{ ++ if (cmb_stub_do_reset_cb) ++ return (*cmb_stub_do_reset_cb) (type); ++ else ++ return -1; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_do_reset); ++ ++static void mtk_wcn_cmb_sdio_enable_eirq(void) ++{ ++ if (atomic_read(&irq_enable_flag)) ++ CMB_STUB_LOG_DBG("wifi eint has been enabled\n"); ++ else { ++ atomic_set(&irq_enable_flag, 1); ++ if (wifi_irq != 0xfffffff) { ++ enable_irq(wifi_irq); ++ CMB_STUB_LOG_DBG(" enable WIFI EINT irq %d !!\n", wifi_irq); ++ } ++ } ++} ++ ++static void mtk_wcn_cmb_sdio_disable_eirq(void) ++{ ++ if (!atomic_read(&irq_enable_flag)) ++ CMB_STUB_LOG_DBG("wifi eint has been disabled!\n"); ++ else { ++ if (wifi_irq != 0xfffffff) { ++ disable_irq_nosync(wifi_irq); ++ CMB_STUB_LOG_DBG("disable WIFI EINT irq %d !!\n", wifi_irq); ++ } ++ atomic_set(&irq_enable_flag, 0); ++ } ++} ++ ++irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data) ++{ ++ if ((NULL != mtk_wcn_cmb_sdio_eirq_handler)&&(0 != atomic_read(&sdio_claim_irq_enable_flag))) ++ mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data); ++ return IRQ_HANDLED; ++} ++ ++static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data) ++{ ++ struct device_node *node; ++ int ret = -EINVAL; ++#if 0 ++ unsigned int gpio_wifi_eint_pin; ++#endif ++ ++ CMB_STUB_LOG_INFO("enter %s\n", __func__); ++ mtk_wcn_sdio_irq_flag_set(0); ++ atomic_set(&irq_enable_flag, 0); ++ mtk_wcn_cmb_sdio_eirq_data = data; ++ mtk_wcn_cmb_sdio_eirq_handler = irq_handler; ++ ++ node = (struct device_node *)of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); ++ if (node) { ++#if 0 ++ gpio_wifi_eint_pin = of_get_gpio(node, 5); ++ CMB_STUB_LOG_INFO("WIFI EINT pin %d !!\n", gpio_wifi_eint_pin); ++ wifi_irq = gpio_to_irq(gpio_wifi_eint_pin); ++#else ++ wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */ ++#endif ++#if 1 ++ ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW, ++ "WIFI-eint", NULL); ++ CMB_STUB_LOG_DBG("WIFI EINT irq %d !!\n", wifi_irq); ++#endif ++ ++ if (ret) ++ CMB_STUB_LOG_WARN("WIFI EINT IRQ LINE NOT AVAILABLE!!\n"); ++ else ++ mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/ ++ } else ++ CMB_STUB_LOG_WARN("[%s] can't find connectivity compatible node\n", __func__); ++ ++ CMB_STUB_LOG_INFO("exit %s\n", __func__); ++} ++ ++static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data) ++{ ++ CMB_STUB_LOG_DBG("mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data); ++ /* register pm change callback */ ++ mtk_wcn_cmb_sdio_pm_cb = pm_cb; ++ mtk_wcn_cmb_sdio_pm_data = data; ++} ++ ++static void mtk_wcn_cmb_sdio_on(int sdio_port_num) ++{ ++ pm_message_t state = {.event = PM_EVENT_USER_RESUME }; ++ ++ CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_on (%d)\n", sdio_port_num); ++ ++ /* 1. disable sdio eirq */ ++ mtk_wcn_cmb_sdio_disable_eirq(); ++ ++ /* 2. call sd callback */ ++ if (mtk_wcn_cmb_sdio_pm_cb) { ++ /* pr_warn("mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p)\n", ++ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ ++ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); ++ } else ++ CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_on no sd callback!!\n"); ++} ++ ++static void mtk_wcn_cmb_sdio_off(int sdio_port_num) ++{ ++ pm_message_t state = {.event = PM_EVENT_USER_SUSPEND }; ++ ++ CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_off (%d)\n", sdio_port_num); ++ ++ /* 1. call sd callback */ ++ if (mtk_wcn_cmb_sdio_pm_cb) { ++ /* pr_warn("mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p)\n", ++ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ ++ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); ++ } else ++ CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_off no sd callback!!\n"); ++ ++ /* 2. disable sdio eirq */ ++ mtk_wcn_cmb_sdio_disable_eirq(); ++} ++ ++int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on) ++{ ++ CMB_STUB_LOG_DBG("mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", sdio_port_num, on); ++ if (on) { ++#if 1 ++ CMB_STUB_LOG_DBG("board_sdio_ctrl force off before on\n"); ++ mtk_wcn_cmb_sdio_off(sdio_port_num); ++#else ++ CMB_STUB_LOG_WARN("skip sdio off before on\n"); ++#endif ++ /* off -> on */ ++ mtk_wcn_cmb_sdio_on(sdio_port_num); ++ if (wifi_irq != 0xfffffff) ++ irq_set_irq_wake(wifi_irq, 1); ++ else ++ CMB_STUB_LOG_WARN("wifi_irq is not available\n"); ++ } else { ++ if (wifi_irq != 0xfffffff) ++ irq_set_irq_wake(wifi_irq, 0); ++ else ++ CMB_STUB_LOG_WARN("wifi_irq is not available\n"); ++ /* on -> off */ ++ mtk_wcn_cmb_sdio_off(sdio_port_num); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(board_sdio_ctrl); ++ ++int mtk_wcn_sdio_irq_flag_set(int flag) ++{ ++ if (0 != flag) ++ atomic_set(&sdio_claim_irq_enable_flag, 1); ++ else ++ atomic_set(&sdio_claim_irq_enable_flag, 0); ++ ++ CMB_STUB_LOG_DBG("sdio_claim_irq_enable_flag:%d\n", atomic_read(&sdio_claim_irq_enable_flag)); ++ ++ return atomic_read(&sdio_claim_irq_enable_flag); ++} ++EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set); +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c +new file mode 100644 +index 000000000000..7ac5ac73ef5d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c +@@ -0,0 +1,269 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[SDIO-DETECT]" ++ ++#include "wmt_detect.h" ++ ++#if MTK_HIF_SDIO_AUTOK_ENABLED ++#include ++#endif ++ ++unsigned int gComboChipId = -1; ++struct sdio_func *g_func = NULL; ++ ++MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = { ++ /* MT6620 *//* Not an SDIO standard class device */ ++ {{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620}, /* SDIO1:FUNC1:WIFI */ ++ {{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ {{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ ++ ++ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628}, ++ ++ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630}, ++ ++}; ++ ++/* Supported SDIO device table */ ++static const struct sdio_device_id mtk_sdio_id_tbl[] = { ++ /* MT6618 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */ ++ {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */ ++ {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ ++ ++ /* MT6619 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ ++ /* MT6620 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */ ++ {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ ++ ++ /* MT5921 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x5921)}, ++ ++ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {SDIO_DEVICE(0x037A, 0x6628)}, ++ ++ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {SDIO_DEVICE(0x037A, 0x6630)}, ++ { /* end: all zeroes */ }, ++}; ++ ++static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id); ++ ++static void sdio_detect_remove(struct sdio_func *func); ++ ++static struct sdio_driver mtk_sdio_client_drv = { ++ .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ ++ .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ ++ .probe = sdio_detect_probe, ++ .remove = sdio_detect_remove, ++}; ++ ++static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id); ++ ++int hif_sdio_is_chipid_valid(int chipId) ++{ ++ int index = -1; ++ ++ int left = 0; ++ int middle = 0; ++ int right = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]) - 1; ++ ++ if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId)) ++ return index; ++ ++ middle = (left + right) / 2; ++ ++ while (left <= right) { ++ if (chipId > gChipInfoArray[middle].chipId) { ++ left = middle + 1; ++ } else if (chipId < gChipInfoArray[middle].chipId) { ++ right = middle - 1; ++ } else { ++ index = middle; ++ break; ++ } ++ middle = (left + right) / 2; ++ } ++ ++ if (0 > index) ++ WMT_DETECT_ERR_FUNC("no supported chipid found\n"); ++ else ++ WMT_DETECT_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId); ++ ++ return index; ++} ++ ++int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id) ++{ ++ int maxIndex = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]); ++ int index = 0; ++ struct sdio_device_id *localId = NULL; ++ int chipId = -1; ++ ++ for (index = 0; index < maxIndex; index++) { ++ localId = &(gChipInfoArray[index].deviceId); ++ if ((localId->vendor == id->vendor) && (localId->device == id->device)) { ++ chipId = gChipInfoArray[index].chipId; ++ WMT_DETECT_INFO_FUNC ++ ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index, ++ localId->vendor, localId->device, chipId); ++ gComboChipId = chipId; ++ mtk_wcn_wmt_set_chipid(gComboChipId); ++ break; ++ } ++ } ++ if (0 > chipId) { ++ WMT_DETECT_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, ++ id->device); ++ } ++ ++ return chipId; ++} ++ ++int sdio_detect_query_chipid(int waitFlag) ++{ ++ unsigned int timeSlotMs = 200; ++ unsigned int maxTimeSlot = 15; ++ unsigned int counter = 0; ++ /* gComboChipId = 0x6628; */ ++ if (0 == waitFlag) ++ return gComboChipId; ++ if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) ++ return gComboChipId; ++ ++ while (counter < maxTimeSlot) { ++ if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) ++ break; ++ msleep(timeSlotMs); ++ counter++; ++ } ++ ++ return gComboChipId; ++} ++ ++int sdio_detect_do_autok(int chipId) ++{ ++ int i_ret = 0; ++ ++#if MTK_HIF_SDIO_AUTOK_ENABLED ++#if 0 ++ BOOTMODE boot_mode; ++ ++ boot_mode = get_boot_mode(); ++ ++ if (boot_mode == META_BOOT) { ++ WMT_DETECT_INFO_FUNC("omit autok in meta mode\n"); ++ return 0; ++ } ++#endif ++ if (0x6630 == chipId) { ++#ifdef CONFIG_SDIOAUTOK_SUPPORT ++ if (NULL != g_func) { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready++\n"); ++ i_ret = wait_sdio_autok_ready(g_func->card->host); ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready--\n"); ++ if (0 == i_ret) { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return success\n"); ++ } else { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return fail, i_ret:%d\n", i_ret); ++ gComboChipId = -1; ++ } ++ } else { ++ WMT_DETECT_INFO_FUNC("g_func NULL, omit autok\n"); ++ } ++#else ++ i_ret = 0; ++ WMT_DETECT_INFO_FUNC("MTK_SDIOAUTOK_SUPPORT not defined\n"); ++#endif ++ } else { ++ WMT_DETECT_INFO_FUNC("MT%x does not support SDIO3.0 autoK is not needed\n", chipId); ++ } ++#else ++ i_ret = 0; ++ WMT_DETECT_INFO_FUNC("MTK_HIF_SDIO_AUTOK_ENABLED is not defined\n"); ++#endif ++ return i_ret; ++} ++ ++/*! ++ * \brief hif_sdio probe function ++ * ++ * hif_sdio probe function called by mmc driver when any matched SDIO function ++ * is detected by it. ++ * ++ * \param func ++ * \param id ++ * ++ * \retval 0 register successfully ++ * \retval < 0 list error code here ++ */ ++static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id) ++{ ++ int chipId = 0; ++ ++ WMT_DETECT_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); ++ chipId = hif_sdio_match_chipid_by_dev_id(id); ++ ++ if ((0x6630 == chipId) && (1 == func->num)) { ++ int ret = 0; ++ ++ g_func = func; ++ WMT_DETECT_INFO_FUNC("autok function detected, func:0x%p\n", g_func); ++ ++ sdio_claim_host(func); ++ ret = sdio_enable_func(func); ++ sdio_release_host(func); ++ if (ret) ++ WMT_DETECT_ERR_FUNC("sdio_enable_func failed!\n"); ++ } ++ ++ return 0; ++} ++ ++static void sdio_detect_remove(struct sdio_func *func) ++{ ++ if (g_func == func) { ++ sdio_claim_host(func); ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ g_func = NULL; ++ } ++ WMT_DETECT_INFO_FUNC("do sdio remove\n"); ++} ++ ++int sdio_detect_init(void) ++{ ++ int ret = -1; ++ /* register to mmc driver */ ++ ret = sdio_register_driver(&mtk_sdio_client_drv); ++ WMT_DETECT_INFO_FUNC("sdio_register_driver() ret=%d\n", ret); ++ return 0; ++} ++ ++int sdio_detect_exit(void) ++{ ++ g_func = NULL; ++ /* register to mmc driver */ ++ sdio_unregister_driver(&mtk_sdio_client_drv); ++ WMT_DETECT_INFO_FUNC("sdio_unregister_driver\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h +new file mode 100644 +index 000000000000..3a0bff9def1b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h +@@ -0,0 +1,43 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _SDIO_DETECT_H_ ++#define _SDIO_DETECT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_SDIOAUTOK_SUPPORT ++#define MTK_HIF_SDIO_AUTOK_ENABLED 1 ++extern int wait_sdio_autok_ready(void *); ++#else ++#define MTK_HIF_SDIO_AUTOK_ENABLED 0 ++#endif ++ ++typedef struct _MTK_WCN_HIF_SDIO_CHIP_INFO_ { ++ struct sdio_device_id deviceId; ++ unsigned int chipId; ++} MTK_WCN_HIF_SDIO_CHIP_INFO, *P_MTK_WCN_HIF_SDIO_CHIP_INFO; ++ ++extern int sdio_detect_exit(void); ++extern int sdio_detect_init(void); ++extern int sdio_detect_query_chipid(int waitFlag); ++extern int hif_sdio_is_chipid_valid(int chipId); ++ ++extern int sdio_detect_do_autok(int chipId); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c +new file mode 100644 +index 000000000000..487852df8f20 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c +@@ -0,0 +1,380 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DETECT]" ++ ++#include "wmt_detect.h" ++#include "wmt_gpio.h" ++ ++#if MTK_WCN_REMOVE_KO ++#include "conn_drv_init.h" ++#endif ++#ifdef CONFIG_COMPAT ++#include ++#endif ++ ++#define WMT_DETECT_MAJOR 154 ++#define WMT_DETECT_DEV_NUM 1 ++#define WMT_DETECT_DRVIER_NAME "mtk_wcn_detect" ++#define WMT_DETECT_DEVICE_NAME "wmtdetect" ++ ++struct class *pDetectClass = NULL; ++struct device *pDetectDev = NULL; ++static int gWmtDetectMajor = WMT_DETECT_MAJOR; ++static struct cdev gWmtDetectCdev; ++unsigned int gWmtDetectDbgLvl = WMT_DETECT_LOG_INFO; ++ ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++inline unsigned int wmt_plat_get_soc_chipid(void) ++{ ++ WMT_DETECT_INFO_FUNC("no soc chip supported, due to MTK_WCN_SOC_CHIP_SUPPORT is not set.\n"); ++ return -1; ++} ++#endif ++ ++static int wmt_detect_open(struct inode *inode, struct file *file) ++{ ++ WMT_DETECT_INFO_FUNC("open major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static int wmt_detect_close(struct inode *inode, struct file *file) ++{ ++ WMT_DETECT_INFO_FUNC("close major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static ssize_t wmt_detect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_DETECT_INFO_FUNC(" ++\n"); ++ WMT_DETECT_INFO_FUNC(" --\n"); ++ ++ return 0; ++} ++ ++ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_DETECT_INFO_FUNC(" ++\n"); ++ WMT_DETECT_INFO_FUNC(" --\n"); ++ ++ return 0; ++} ++ ++static long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int retval = 0; ++ ++ WMT_DETECT_INFO_FUNC("cmd (%d),arg(%ld)\n", cmd, arg); ++ ++ switch (cmd) { ++ case COMBO_IOCTL_GET_CHIP_ID: ++ /*just get chipid from sdio-detect module */ ++ /*check if external combo chip exists or not */ ++ /*if yes, just return combo chip id */ ++ /*if no, get soc chipid */ ++ retval = mtk_wcn_wmt_chipid_query(); ++ break; ++ ++ case COMBO_IOCTL_SET_CHIP_ID: ++ mtk_wcn_wmt_set_chipid(arg); ++ ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_PWR_ON: ++ retval = wmt_detect_ext_chip_pwr_on(); ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_DETECT: ++ retval = wmt_detect_ext_chip_detect(); ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_PWR_OFF: ++ retval = wmt_detect_ext_chip_pwr_off(); ++ break; ++ ++ case COMBO_IOCTL_DO_SDIO_AUDOK: ++ retval = sdio_detect_do_autok(arg); ++ break; ++ ++ case COMBO_IOCTL_GET_SOC_CHIP_ID: ++ retval = wmt_plat_get_soc_chipid(); ++ /*get soc chipid by HAL interface */ ++ break; ++ ++ case COMBO_IOCTL_MODULE_CLEANUP: ++#if (MTK_WCN_REMOVE_KO) ++ /*deinit SDIO-DETECT module */ ++ retval = sdio_detect_exit(); ++#else ++ WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); ++#endif ++ break; ++ ++ case COMBO_IOCTL_DO_MODULE_INIT: ++#if (MTK_WCN_REMOVE_KO) ++ /*deinit SDIO-DETECT module */ ++ retval = do_connectivity_driver_init(arg); ++#else ++ WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); ++#endif ++ break; ++ ++ default: ++ WMT_DETECT_WARN_FUNC("unknown cmd (%d)\n", cmd); ++ retval = 0; ++ break; ++ } ++ return retval; ++} ++#ifdef CONFIG_COMPAT ++static long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ ++ WMT_DETECT_INFO_FUNC("cmd (%d)\n", cmd); ++ ret = wmt_detect_unlocked_ioctl(filp, cmd, arg); ++ return ret; ++} ++#endif ++const struct file_operations gWmtDetectFops = { ++ .open = wmt_detect_open, ++ .release = wmt_detect_close, ++ .read = wmt_detect_read, ++ .write = wmt_detect_write, ++ .unlocked_ioctl = wmt_detect_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = WMT_compat_detect_ioctl, ++#endif ++}; ++ ++int wmt_detect_ext_chip_pwr_on(void) ++{ ++ /*pre power on external chip */ ++ /* wmt_plat_pwr_ctrl(FUNC_ON); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ WMT_DETECT_INFO_FUNC("++\n"); ++ if (0 != wmt_detect_chip_pwr_ctrl(1)) ++ return -1; ++ if (0 != wmt_detect_sdio_pwr_ctrl(1)) ++ return -2; ++ return 0; ++#else ++ WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); ++ return -1; ++#endif ++} ++ ++int wmt_detect_ext_chip_pwr_off(void) ++{ ++ /*pre power off external chip */ ++ /* wmt_plat_pwr_ctrl(FUNC_OFF); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ WMT_DETECT_INFO_FUNC("--\n"); ++ wmt_detect_sdio_pwr_ctrl(0); ++ return wmt_detect_chip_pwr_ctrl(0); ++#else ++ WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); ++ return 0; ++#endif ++} ++ ++int wmt_detect_ext_chip_detect(void) ++{ ++ int iRet = -1; ++ unsigned int chipId = -1; ++ /*if there is no external combo chip, return -1 */ ++ int bgfEintStatus = -1; ++ ++ WMT_DETECT_INFO_FUNC("++\n"); ++ /*wait for a stable time */ ++ msleep(20); ++ ++ /*read BGF_EINT_PIN status */ ++ bgfEintStatus = wmt_detect_read_ext_cmb_status(); ++ ++ if (0 == bgfEintStatus) { ++ /*external chip does not exist */ ++ WMT_DETECT_INFO_FUNC("external combo chip not detected\n"); ++ } else if (1 == bgfEintStatus) { ++ /*combo chip exists */ ++ WMT_DETECT_INFO_FUNC("external combo chip detected\n"); ++ ++ /*detect chipid by sdio_detect module */ ++ chipId = sdio_detect_query_chipid(1); ++ if (0 <= hif_sdio_is_chipid_valid(chipId)) ++ WMT_DETECT_INFO_FUNC("valid external combo chip id (0x%x)\n", chipId); ++ else ++ WMT_DETECT_INFO_FUNC("invalid external combo chip id (0x%x)\n", chipId); ++ iRet = 0; ++ } else { ++ /*Error exists */ ++ WMT_DETECT_ERR_FUNC("error happens when detecting combo chip\n"); ++ } ++ WMT_DETECT_INFO_FUNC("--\n"); ++ /*return 0 */ ++ return iRet; ++ /*todo: if there is external combo chip, power on chip return 0 */ ++} ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++static int wmt_detect_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ WMT_DETECT_ERR_FUNC("platform name: %s\n", pdev->name); ++ ret = wmt_gpio_init(pdev); ++ if (-1 == ret) ++ WMT_DETECT_ERR_FUNC("gpio init fail ret:%d\n", ret); ++ return ret; ++} ++ ++static int wmt_detect_remove(struct platform_device *pdev) ++{ ++ wmt_gpio_deinit(); ++ return 0; ++} ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++static struct of_device_id wmt_detect_match[] = { ++ { .compatible = "mediatek,connectivity-combo", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, wmt_detect_match); ++ ++static struct platform_driver wmt_detect_driver = { ++ .probe = wmt_detect_probe, ++ .remove = wmt_detect_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "mediatek,connectivity-combo", ++ .of_match_table = wmt_detect_match, ++ }, ++}; ++#endif ++ ++/*module_platform_driver(wmt_detect_driver);*/ ++static int wmt_detect_driver_init(void) ++{ ++ dev_t devID = MKDEV(gWmtDetectMajor, 0); ++ int cdevErr = -1; ++ int ret = -1; ++ ++ ret = register_chrdev_region(devID, WMT_DETECT_DEV_NUM, WMT_DETECT_DRVIER_NAME); ++ if (ret) { ++ WMT_DETECT_ERR_FUNC("fail to register chrdev\n"); ++ return ret; ++ } ++ ++ cdev_init(&gWmtDetectCdev, &gWmtDetectFops); ++ gWmtDetectCdev.owner = THIS_MODULE; ++ ++ cdevErr = cdev_add(&gWmtDetectCdev, devID, WMT_DETECT_DEV_NUM); ++ if (cdevErr) { ++ WMT_DETECT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); ++ goto err1; ++ } ++ ++ pDetectClass = class_create(THIS_MODULE, WMT_DETECT_DEVICE_NAME); ++ if (IS_ERR(pDetectClass)) { ++ WMT_DETECT_ERR_FUNC("class create fail, error code(%ld)\n", PTR_ERR(pDetectClass)); ++ goto err1; ++ } ++ ++ pDetectDev = device_create(pDetectClass, NULL, devID, NULL, WMT_DETECT_DEVICE_NAME); ++ if (IS_ERR(pDetectDev)) { ++ WMT_DETECT_ERR_FUNC("device create fail, error code(%ld)\n", PTR_ERR(pDetectDev)); ++ goto err2; ++ } ++ ++ WMT_DETECT_INFO_FUNC("driver(major %d) installed success\n", gWmtDetectMajor); ++ ++ /*init SDIO-DETECT module */ ++ sdio_detect_init(); ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ ret = platform_driver_register(&wmt_detect_driver); ++ if (ret) ++ WMT_DETECT_ERR_FUNC("platform driver register fail ret:%d\n", ret); ++#endif ++ ++ return 0; ++ ++err2: ++ ++ if (pDetectClass) { ++ class_destroy(pDetectClass); ++ pDetectClass = NULL; ++ } ++ ++err1: ++ ++ if (cdevErr == 0) ++ cdev_del(&gWmtDetectCdev); ++ ++ if (ret == 0) { ++ unregister_chrdev_region(devID, WMT_DETECT_DEV_NUM); ++ gWmtDetectMajor = -1; ++ } ++ ++ WMT_DETECT_ERR_FUNC("fail\n"); ++ ++ return -1; ++} ++ ++static void wmt_detect_driver_exit(void) ++{ ++ dev_t dev = MKDEV(gWmtDetectMajor, 0); ++ ++ if (pDetectDev) { ++ device_destroy(pDetectClass, dev); ++ pDetectDev = NULL; ++ } ++ ++ if (pDetectClass) { ++ class_destroy(pDetectClass); ++ pDetectClass = NULL; ++ } ++ ++ cdev_del(&gWmtDetectCdev); ++ unregister_chrdev_region(dev, WMT_DETECT_DEV_NUM); ++ ++#if !(MTK_WCN_REMOVE_KO) ++/*deinit SDIO-DETECT module*/ ++ sdio_detect_exit(); ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ platform_driver_unregister(&wmt_detect_driver); ++#endif ++ ++ WMT_DETECT_INFO_FUNC("done\n"); ++} ++ ++module_init(wmt_detect_driver_init); ++module_exit(wmt_detect_driver_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Zhiguo.Niu & Chaozhong.Liang @ MBJ/WCNSE/SS1"); ++ ++module_param(gWmtDetectMajor, uint, 0); +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h +new file mode 100644 +index 000000000000..7e152bfd39ec +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h +@@ -0,0 +1,114 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_DETECT_H_ ++#define _WMT_DETECT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++#define MTK_WCN_REMOVE_KO 1 ++#else ++#define MTK_WCN_REMOVE_KO 0 ++#endif ++ ++#include "sdio_detect.h" ++#include "wmt_detect_pwr.h" ++#include ++ ++#define WMT_DETECT_LOG_LOUD 4 ++#define WMT_DETECT_LOG_DBG 3 ++#define WMT_DETECT_LOG_INFO 2 ++#define WMT_DETECT_LOG_WARN 1 ++#define WMT_DETECT_LOG_ERR 0 ++ ++extern unsigned int gWmtDetectDbgLvl; ++ ++#define WMT_DETECT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_LOUD) \ ++ pr_debug(DFT_TAG"[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_DBG) \ ++ pr_debug(DFT_TAG"[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_INFO) \ ++ pr_err(DFT_TAG"[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_WARN) \ ++ pr_warn(DFT_TAG"[W]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_DETECT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_ERR) \ ++ pr_err(DFT_TAG"[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++ ++#define WMT_IOC_MAGIC 'w' ++#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_IOC_MAGIC, 0, int) ++#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_IOC_MAGIC, 1, int) ++#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_IOC_MAGIC, 2, int) ++#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_IOC_MAGIC, 3, int) ++#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_IOC_MAGIC, 4, int) ++#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_IOC_MAGIC, 5, int) ++#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_IOC_MAGIC, 6, int) ++#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_IOC_MAGIC, 7, int) ++#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_IOC_MAGIC, 8, int) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++********************************************************************************/ ++extern int wmt_detect_ext_chip_detect(void); ++extern int wmt_detect_ext_chip_pwr_on(void); ++extern int wmt_detect_ext_chip_pwr_off(void); ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++extern unsigned int wmt_plat_get_soc_chipid(void); ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver ++ * ++ * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" ++ * @ enable - "1", enable deep idle; "0", disable deep idle ++ * ++ * Return 0 if success, else -1 ++ */ ++extern unsigned int mtk_uart_pdn_enable(char *port, int enable); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c +new file mode 100644 +index 000000000000..1dcb7ed358bc +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c +@@ -0,0 +1,232 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DETECT]" ++ ++#include "wmt_detect.h" ++#include "wmt_gpio.h" ++ ++#define INVALID_PIN_ID (0xFFFFFFFF) ++ ++/*copied form WMT module*/ ++static int wmt_detect_dump_pin_conf(void) ++{ ++ WMT_DETECT_DBG_FUNC("[WMT-DETECT]=>dump wmt pin configuration start<=\n"); ++ ++ WMT_DETECT_INFO_FUNC("LDO(GPIO%d), PMU(GPIO%d), PMUV28(GPIO%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num); ++ ++ WMT_DETECT_INFO_FUNC("RST(GPIO%d), BGF_EINT(GPIO%d), BGF_EINT_NUM(%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num, ++ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num)); ++ ++ WMT_DETECT_INFO_FUNC("WIFI_EINT(GPIO%d), WIFI_EINT_NUM(%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num, ++ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)); ++ ++ WMT_DETECT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration ends<=\n"); ++ ++ return 0; ++} ++ ++int _wmt_detect_output_low(unsigned int id) ++{ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 0); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); ++ } ++ ++ return 0; ++} ++ ++int _wmt_detect_output_high(unsigned int id) ++{ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 1); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); ++ } ++ ++ return 0; ++} ++ ++int _wmt_detect_read_gpio_input(unsigned int id) ++{ ++ int retval = 0; ++ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ retval = gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: get GPIO%d val%d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, retval); ++ } ++ ++ return retval; ++} ++ ++/*This power on sequence must support all combo chip's basic power on sequence ++ * 1. LDO control is a must, if external LDO exist ++ * 2. PMU control is a must ++ * 3. RST control is a must ++ * 4. WIFI_EINT pin control is a must, used for GPIO mode for EINT status checkup ++ * 5. RTC32k clock control is a must ++ * */ ++static int wmt_detect_chip_pwr_on(void) ++{ ++ int retval = -1; ++ /*setting validiation check*/ ++ if ((INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) || ++ (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) || ++ (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)) { ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: either PMU(%d) or RST(%d) or WIFI_EINT(%d) is not set\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num); ++ ++ return retval; ++ } ++ /*set LDO/PMU/RST to output 0, no pull*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]); ++ WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); ++ WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ _wmt_detect_output_low(GPIO_COMBO_RST_PIN); ++ ++#if 0 ++ _wmt_detect_output_high(GPIO_WIFI_EINT_PIN); ++#endif ++ ++ /*pull high LDO*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_high(GPIO_COMBO_LDO_EN_PIN); ++ /*sleep for LDO stable time*/ ++ msleep(MAX_LDO_STABLE_TIME); ++ ++ /*export RTC clock, sleep for RTC stable time*/ ++ rtc_gpio_enable_32k(RTC_GPIO_USER_GPS); ++ msleep(MAX_RTC_STABLE_TIME); ++ /*PMU output low, RST output low, to make chip power off completely*/ ++ /*always done*/ ++ /*sleep for power off stable time*/ ++ msleep(MAX_OFF_STABLE_TIME); ++ /*PMU output high, and sleep for reset stable time*/ ++ _wmt_detect_output_high(GPIO_COMBO_PMU_EN_PIN); ++#ifdef CONFIG_MTK_COMBO_COMM_NPWR ++ if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != INVALID_PIN_ID) && ++ (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != INVALID_PIN_ID)) { ++ msleep(20); ++ _wmt_detect_output_high(GPIO_PCM_DAISYNC_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_high(GPIO_COMBO_I2S_DAT_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_low(GPIO_COMBO_I2S_DAT_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_low(GPIO_PCM_DAISYNC_PIN); ++ ++ msleep(20); ++ } ++#endif ++ msleep(MAX_RST_STABLE_TIME); ++ /*RST output high, and sleep for power on stable time */ ++ _wmt_detect_output_high(GPIO_COMBO_RST_PIN); ++ msleep(MAX_ON_STABLE_TIME); ++ ++ retval = 0; ++ return retval; ++} ++ ++static int wmt_detect_chip_pwr_off(void) ++{ ++ ++ /*set RST pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); ++ /*set RST pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_RST_PIN); ++ /*set PMU pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); ++ return 0; ++} ++ ++int wmt_detect_read_ext_cmb_status(void) ++{ ++ int retval = 0; ++ /*read WIFI_EINT pin status*/ ++ if (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num) { ++ retval = 0; ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: no WIFI_EINT pin set\n"); ++ } else { ++ retval = _wmt_detect_read_gpio_input(GPIO_WIFI_EINT_PIN); ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: WIFI_EINT input status:%d\n", retval); ++ } ++ return retval; ++} ++ ++int wmt_detect_chip_pwr_ctrl(int on) ++{ ++ int retval = -1; ++ ++ if (0 == on) { ++ /*power off combo chip */ ++ retval = wmt_detect_chip_pwr_off(); ++ } else { ++ wmt_detect_dump_pin_conf(); ++ /*power on combo chip */ ++ retval = wmt_detect_chip_pwr_on(); ++ } ++ return retval; ++} ++ ++int wmt_detect_sdio_pwr_ctrl(int on) ++{ ++ int retval = -1; ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ if (0 == on) { ++ /*power off SDIO slot */ ++ retval = board_sdio_ctrl(1, 0); ++ } else { ++ /*power on SDIO slot */ ++ retval = board_sdio_ctrl(1, 1); ++ } ++#else ++ WMT_DETECT_WARN_FUNC("WMT-DETECT: MTK_WCN_COMBO_CHIP_SUPPORT is not set\n"); ++#endif ++ return retval; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h +new file mode 100644 +index 000000000000..32e661520fd0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h +@@ -0,0 +1,29 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef __WMT_DETECT_PWR_H_ ++#define __WMT_DETECT_PWR_H_ ++ ++#define MAX_RTC_STABLE_TIME 100 ++#define MAX_LDO_STABLE_TIME 100 ++#define MAX_RST_STABLE_TIME 30 ++#define MAX_OFF_STABLE_TIME 10 ++#define MAX_ON_STABLE_TIME 30 ++ ++extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); ++extern int wmt_detect_chip_pwr_ctrl(int on); ++extern int wmt_detect_sdio_pwr_ctrl(int on); ++extern int wmt_detect_read_ext_cmb_status(void); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c +new file mode 100644 +index 000000000000..3a79e1e9d15a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c +@@ -0,0 +1,371 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "wmt_gpio.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX] = {{"gpio_ldo_en_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_ldo_en_in_pulldown", ++ ""}, ++ {"gpio_pmuv28_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_pmuv28_in_pulldown", ++ ""}, ++ {"gpio_pmu_en_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_pmu_en_in_pulldown", ++ ""}, ++ {"gpio_rst_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_bgf_eint_in_pulldown", ++ "gpio_bgf_eint_in_pullup"}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_wifi_eint_in_pull_dis", ++ "", ++ "gpio_wifi_eint_in_pullup"}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_all_eint_in_pulldown", ++ "gpio_all_eint_in_pullup"}, ++ {"gpio_urxd_uart_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_urxd_gpio_in_pull_dis", ++ "", ++ "gpio_urxd_gpio_in_pullup"}, ++ {"gpio_utxd_uart_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daiclk_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daipcmin_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daipcmout_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daisync_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_ck_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_ws_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_dat_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_gps_sync_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_gps_lna_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""} ++}; ++ ++const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX] = {"gpio_combo_ldo_en_pin", ++ "gpio_combo_pmuv28_en_pin", ++ "gpio_combo_pmu_en_pin", ++ "gpio_combo_rst_pin", ++ "gpio_combo_bgf_eint_pin", ++ "gpio_wifi_eint_pin", ++ "gpio_all_eint_pin", ++ "gpio_combo_urxd_pin", ++ "gpio_combo_utxd_pin", ++ "gpio_pcm_daiclk_pin", ++ "gpio_pcm_daipcmin_pin", ++ "gpio_pcm_daipcmout_pin", ++ "gpio_pcm_daisync_pin", ++ "gpio_combo_i2s_ck_pin", ++ "gpio_combo_i2s_ws_pin", ++ "gpio_combo_i2s_dat_pin", ++ "gpio_gps_sync_pin", ++ "gpio_gps_lna_pin"}; ++ ++GPIO_CTRL_INFO gpio_ctrl_info; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_gpio_init(struct platform_device *pdev) ++{ ++ INT32 iret = 0; ++ UINT32 i, j; ++ struct device_node *node; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); ++ if (!node) { ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ pr_err("wmt_gpio:can't find device tree node!\n"); ++ iret = -1; ++ goto err; ++ } ++ ++ gpio_ctrl_info.pinctrl_info = devm_pinctrl_get(&pdev->dev); ++ if (gpio_ctrl_info.pinctrl_info) { ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = of_get_named_gpio(node, ++ gpio_pin_name[i], 0); ++ if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num < 0) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { ++ for (j = 0; j < GPIO_STATE_MAX; j++) { ++ if (0 != strlen(gpio_state_name[i][j])) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = ++ pinctrl_lookup_state(gpio_ctrl_info.pinctrl_info, ++ gpio_state_name[i][j]); ++ } else ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; ++ } ++ } ++ } ++ ++ pr_err("wmt_gpio: gpio init start!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ 0); ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN out to 0: %d!\n", ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); ++ } ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ 0); ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN out to 0: %d!\n", ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); ++ } ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); ++ pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ pr_err("wmt_gpio: gpio init done!\n"); ++ } else { ++ pr_err("wmt_gpio:can't find pinctrl dev!\n"); ++ iret = -1; ++ } ++err: ++ return iret; ++} ++ ++INT32 wmt_gpio_deinit(VOID) ++{ ++ INT32 iret = 0; ++ UINT32 i; ++ UINT32 j; ++ ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { ++ for (j = 0; j < GPIO_STATE_MAX; j++) { ++ if (0 != strlen(gpio_state_name[i][j])) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; ++ } ++ } ++ } ++ if (gpio_ctrl_info.pinctrl_info) { ++ devm_pinctrl_put(gpio_ctrl_info.pinctrl_info); ++ gpio_ctrl_info.pinctrl_info = NULL; ++ } ++ ++ return iret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h +new file mode 100644 +index 000000000000..cd935bfddd99 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h +@@ -0,0 +1,103 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_GPIO_H_ ++#define _WMT_GPIO_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "osal.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define DEFAULT_PIN_ID (0xffffffff) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_GPIO_PIN_ID { ++ GPIO_COMBO_LDO_EN_PIN = 0, ++ GPIO_COMBO_PMUV28_EN_PIN, ++ GPIO_COMBO_PMU_EN_PIN, ++ GPIO_COMBO_RST_PIN, ++ GPIO_COMBO_BGF_EINT_PIN, ++ GPIO_WIFI_EINT_PIN, ++ GPIO_COMBO_ALL_EINT_PIN, ++ GPIO_COMBO_URXD_PIN, ++ GPIO_COMBO_UTXD_PIN, ++ GPIO_PCM_DAICLK_PIN, ++ GPIO_PCM_DAIPCMIN_PIN, ++ GPIO_PCM_DAIPCMOUT_PIN, ++ GPIO_PCM_DAISYNC_PIN, ++ GPIO_COMBO_I2S_CK_PIN, ++ GPIO_COMBO_I2S_WS_PIN, ++ GPIO_COMBO_I2S_DAT_PIN, ++ GPIO_GPS_SYNC_PIN, ++ GPIO_GPS_LNA_PIN, ++ GPIO_PIN_ID_MAX ++} ENUM_GPIO_PIN_ID, *P_ENUM_GPIO_PIN_ID; ++ ++typedef enum _ENUM_GPIO_STATE_ID { ++ GPIO_PULL_DIS = 0, ++ GPIO_PULL_DOWN, ++ GPIO_PULL_UP, ++ GPIO_OUT_LOW, ++ GPIO_OUT_HIGH, ++ GPIO_IN_DIS, ++ GPIO_IN_EN, ++ GPIO_IN_PULL_DIS, ++ GPIO_IN_PULLDOWN, ++ GPIO_IN_PULLUP, ++ GPIO_STATE_MAX, ++} ENUM_GPIO_STATE_ID, *P_ENUM_GPIO_STATE_ID; ++ ++typedef struct _GPIO_CTRL_STATE { ++ INT32 gpio_num; ++ struct pinctrl_state *gpio_state[GPIO_STATE_MAX]; ++} GPIO_CTRL_STATE, *P_GPIO_CTRL_STATE; ++ ++typedef struct _GPIO_CTRL_INFO { ++ struct pinctrl *pinctrl_info; ++ GPIO_CTRL_STATE gpio_ctrl_state[GPIO_PIN_ID_MAX]; ++} GPIO_CTRL_INFO, *P_GPIO_CTRL_INFO; ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX]; ++extern const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX]; ++extern GPIO_CTRL_INFO gpio_ctrl_info; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_gpio_init(struct platform_device *pdev); ++ ++INT32 wmt_gpio_deinit(VOID); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c +new file mode 100644 +index 000000000000..4fc3144b3ba6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c +@@ -0,0 +1,480 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include "osal_typedef.h" ++#include "wmt_stp_exp.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-STP-EXP]" ++ ++#define WMT_STP_EXP_INFO_FUNC(fmt, arg...) pr_debug(DFT_TAG "[I]%s: " fmt, __func__ , ##arg) ++#define WMT_STP_EXP_WARN_FUNC(fmt, arg...) pr_warn(DFT_TAG "[W]%s: " fmt, __func__ , ##arg) ++#define WMT_STP_EXP_ERR_FUNC(fmt, arg...) pr_err(DFT_TAG "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++/*STP exp*/ ++MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_f = NULL; ++MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_raw_f = NULL; ++MTK_WCN_STP_PARSER_DATA mtk_wcn_stp_parser_data_f = NULL; ++MTK_WCN_STP_RECV_DATA mtk_wcn_stp_receive_data_f = NULL; ++MTK_WCN_STP_IS_RXQ_EMPTY mtk_wcn_stp_is_rxqueue_empty_f = NULL; ++MTK_WCN_STP_IS_RDY mtk_wcn_stp_is_ready_f = NULL; ++MTK_WCN_STP_SET_BLUEZ mtk_wcn_stp_set_bluez_f = NULL; ++MTK_WCN_STP_REG_IF_TX mtk_wcn_stp_if_tx_f = NULL; ++MTK_WCN_STP_REG_IF_RX mtk_wcn_stp_if_rx_f = NULL; ++MTK_WCN_STP_REG_EVENT_CB mtk_wcn_stp_reg_event_cb_f = NULL; ++MTK_WCN_STP_RGE_TX_EVENT_CB mtk_wcn_stp_reg_tx_event_cb_f = NULL; ++MTK_WCN_STP_COREDUMP_START_GET mtk_wcn_stp_coredump_start_get_f = NULL; ++ ++/*WMT exp*/ ++MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_on_f = NULL; ++MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_off_f = NULL; ++MTK_WCN_WMT_THERM_CTRL mtk_wcn_wmt_therm_ctrl_f = NULL; ++MTK_WCN_WMT_HWVER_GET mtk_wcn_wmt_hwver_get_f = NULL; ++MTK_WCN_WMT_DSNS_CTRL mtk_wcn_wmt_dsns_ctrl_f = NULL; ++MTK_WCN_WMT_MSGCB_REG mtk_wcn_wmt_msgcb_reg_f = NULL; ++MTK_WCN_WMT_MSGCB_UNREG mtk_wcn_wmt_msgcb_unreg_f = NULL; ++MTK_WCN_WMT_SDIO_OP_REG mtk_wcn_wmt_sdio_op_reg_f = NULL; ++MTK_WCN_WMT_SDIO_HOST_AWAKE mtk_wcn_wmt_sdio_host_awake_f = NULL; ++MTK_WCN_WMT_ASSERT mtk_wcn_wmt_assert_f = NULL; ++MTK_WCN_WMT_ASSERT_TIMEOUT mtk_wcn_wmt_assert_timeout_f = NULL; ++MTK_WCN_WMT_IC_INFO_GET mtk_wcn_wmt_ic_info_get_f = NULL; ++MTK_WCN_WMT_PSM_CTRL mtk_wcn_wmt_psm_ctrl_f = NULL; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb) ++{ ++ WMT_STP_EXP_INFO_FUNC("call stp exp cb reg\n"); ++ ++ mtk_wcn_stp_send_data_f = pStpExpCb->stp_send_data_cb; ++ mtk_wcn_stp_send_data_raw_f = pStpExpCb->stp_send_data_raw_cb; ++ mtk_wcn_stp_parser_data_f = pStpExpCb->stp_parser_data_cb; ++ mtk_wcn_stp_receive_data_f = pStpExpCb->stp_receive_data_cb; ++ mtk_wcn_stp_is_rxqueue_empty_f = pStpExpCb->stp_is_rxqueue_empty_cb; ++ mtk_wcn_stp_is_ready_f = pStpExpCb->stp_is_ready_cb; ++ mtk_wcn_stp_set_bluez_f = pStpExpCb->stp_set_bluez_cb; ++ mtk_wcn_stp_if_tx_f = pStpExpCb->stp_if_tx_cb; ++ mtk_wcn_stp_if_rx_f = pStpExpCb->stp_if_rx_cb; ++ mtk_wcn_stp_reg_event_cb_f = pStpExpCb->stp_reg_event_cb; ++ mtk_wcn_stp_reg_tx_event_cb_f = pStpExpCb->stp_reg_tx_event_cb; ++ mtk_wcn_stp_coredump_start_get_f = pStpExpCb->stp_coredump_start_get_cb; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_reg); ++ ++UINT32 mtk_wcn_stp_exp_cb_unreg(VOID) ++{ ++ WMT_STP_EXP_INFO_FUNC("call stp exp cb unreg\n"); ++ ++ mtk_wcn_stp_send_data_f = NULL; ++ mtk_wcn_stp_send_data_raw_f = NULL; ++ mtk_wcn_stp_parser_data_f = NULL; ++ mtk_wcn_stp_receive_data_f = NULL; ++ mtk_wcn_stp_is_rxqueue_empty_f = NULL; ++ mtk_wcn_stp_is_ready_f = NULL; ++ mtk_wcn_stp_set_bluez_f = NULL; ++ mtk_wcn_stp_if_tx_f = NULL; ++ mtk_wcn_stp_if_rx_f = NULL; ++ mtk_wcn_stp_reg_event_cb_f = NULL; ++ mtk_wcn_stp_reg_tx_event_cb_f = NULL; ++ mtk_wcn_stp_coredump_start_get_f = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_unreg); ++ ++INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_send_data_f) { ++ ret = (*mtk_wcn_stp_send_data_f) (buffer, length, type); ++ /* WMT_STP_EXP_INFO_FUNC("mtk_wcn_stp_send_data_f send data(%d)\n",ret); */ ++ } else { ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_f cb is null\n"); ++ } ++ ++ return ret; ++ ++} ++EXPORT_SYMBOL(mtk_wcn_stp_send_data); ++ ++INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_send_data_raw_f) ++ ret = (*mtk_wcn_stp_send_data_raw_f) (buffer, length, type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_raw_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); ++ ++INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_parser_data_f) ++ ret = (*mtk_wcn_stp_parser_data_f) (buffer, length); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_parser_data_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_parser_data); ++ ++INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_receive_data_f) ++ ret = (*mtk_wcn_stp_receive_data_f) (buffer, length, type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_receive_data_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_receive_data); ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_stp_is_rxqueue_empty_f) ++ ret = (*mtk_wcn_stp_is_rxqueue_empty_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_rxqueue_empty_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_stp_is_ready_f) ++ ret = (*mtk_wcn_stp_is_ready_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_ready_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_is_ready); ++ ++void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags) ++{ ++ ++ if (mtk_wcn_stp_set_bluez_f) ++ (*mtk_wcn_stp_set_bluez_f) (flags); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_set_bluez_f cb is null\n"); ++ ++} ++EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); ++ ++INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_if_tx_f) ++ ret = (*mtk_wcn_stp_if_tx_f) (stp_if, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_tx_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); ++ ++INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_if_rx_f) ++ ret = (*mtk_wcn_stp_if_rx_f) (func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_rx_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); ++ ++INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_reg_event_cb_f) ++ ret = (*mtk_wcn_stp_reg_event_cb_f) (type, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_event_cb_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); ++ ++INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_reg_tx_event_cb_f) ++ ret = (*mtk_wcn_stp_reg_tx_event_cb_f) (type, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_tx_event_cb_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); ++ ++INT32 mtk_wcn_stp_coredump_start_get(VOID) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_coredump_start_get_f) ++ ret = (*mtk_wcn_stp_coredump_start_get_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_coredump_start_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get); ++ ++UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb) ++{ ++ WMT_STP_EXP_INFO_FUNC("call wmt exp cb reg\n"); ++ ++ mtk_wcn_wmt_func_on_f = pWmtExpCb->wmt_func_on_cb; ++ mtk_wcn_wmt_func_off_f = pWmtExpCb->wmt_func_off_cb; ++ mtk_wcn_wmt_therm_ctrl_f = pWmtExpCb->wmt_therm_ctrl_cb; ++ mtk_wcn_wmt_hwver_get_f = pWmtExpCb->wmt_hwver_get_cb; ++ mtk_wcn_wmt_dsns_ctrl_f = pWmtExpCb->wmt_dsns_ctrl_cb; ++ mtk_wcn_wmt_msgcb_reg_f = pWmtExpCb->wmt_msgcb_reg_cb; ++ mtk_wcn_wmt_msgcb_unreg_f = pWmtExpCb->wmt_msgcb_unreg_cb; ++ mtk_wcn_wmt_sdio_op_reg_f = pWmtExpCb->wmt_sdio_op_reg_cb; ++ mtk_wcn_wmt_sdio_host_awake_f = pWmtExpCb->wmt_sdio_host_awake_cb; ++ mtk_wcn_wmt_assert_f = pWmtExpCb->wmt_assert_cb; ++ mtk_wcn_wmt_assert_timeout_f = pWmtExpCb->wmt_assert_timeout_cb; ++ mtk_wcn_wmt_ic_info_get_f = pWmtExpCb->wmt_ic_info_get_cb; ++ mtk_wcn_wmt_psm_ctrl_f = pWmtExpCb->wmt_psm_ctrl_cb; ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_reg); ++ ++UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID) ++{ ++ WMT_STP_EXP_INFO_FUNC("call wmt exp cb unreg\n"); ++ ++ mtk_wcn_wmt_func_on_f = NULL; ++ mtk_wcn_wmt_func_off_f = NULL; ++ mtk_wcn_wmt_therm_ctrl_f = NULL; ++ mtk_wcn_wmt_hwver_get_f = NULL; ++ mtk_wcn_wmt_dsns_ctrl_f = NULL; ++ mtk_wcn_wmt_msgcb_reg_f = NULL; ++ mtk_wcn_wmt_msgcb_unreg_f = NULL; ++ mtk_wcn_wmt_sdio_op_reg_f = NULL; ++ mtk_wcn_wmt_sdio_host_awake_f = NULL; ++ mtk_wcn_wmt_assert_f = NULL; ++ mtk_wcn_wmt_assert_timeout_f = NULL; ++ mtk_wcn_wmt_ic_info_get_f = NULL; ++ mtk_wcn_wmt_psm_ctrl_f = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_unreg); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_func_off_f) ++ ret = (*mtk_wcn_wmt_func_off_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_off_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_func_off); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_func_on_f) { ++ ret = (*mtk_wcn_wmt_func_on_f) (type); ++ WMT_STP_EXP_INFO_FUNC("mtk_wcn_wmt_func_on_f type(%d)\n", type); ++ } else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_on_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_func_on); ++ ++INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_therm_ctrl_f) ++ ret = (*mtk_wcn_wmt_therm_ctrl_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_therm_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); ++ ++ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) ++{ ++ ENUM_WMTHWVER_TYPE_T ret = WMTHWVER_INVALID; ++ ++ if (mtk_wcn_wmt_hwver_get_f) ++ ret = (*mtk_wcn_wmt_hwver_get_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_hwver_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_dsns_ctrl_f) ++ ret = (*mtk_wcn_wmt_dsns_ctrl_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_dsns_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); ++ ++INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++{ ++ INT32 ret = 0; ++ ++ if (mtk_wcn_wmt_msgcb_reg_f) ++ ret = (*mtk_wcn_wmt_msgcb_reg_f) (eType, pCb); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_reg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); ++ ++INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++{ ++ INT32 ret = 0; ++ ++ if (mtk_wcn_wmt_msgcb_unreg_f) ++ ret = (*mtk_wcn_wmt_msgcb_unreg_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_unreg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); ++ ++INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_sdio_op_reg_f) ++ ret = (*mtk_wcn_wmt_sdio_op_reg_f) (own_cb); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_op_reg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); ++ ++INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_sdio_host_awake_f) ++ ret = (*mtk_wcn_wmt_sdio_host_awake_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_host_awake_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_assert_f) ++ ret = (*mtk_wcn_wmt_assert_f) (type, reason); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_assert); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_assert_timeout_f) ++ ret = (*mtk_wcn_wmt_assert_timeout_f)(type, reason, timeout); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_timeout_f cb is null\n"); ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_assert_timeout); ++ ++UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type) ++{ ++ UINT32 ret = 0; ++ ++ if (mtk_wcn_wmt_ic_info_get_f) ++ ret = (*mtk_wcn_wmt_ic_info_get_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_ic_info_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get); ++ ++INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag) ++{ ++ UINT32 ret = 0; ++ ++ if (mtk_wcn_wmt_psm_ctrl_f) ++ ret = (*mtk_wcn_wmt_psm_ctrl_f)(flag); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_psm_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h +new file mode 100644 +index 000000000000..1c3dc8965298 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h +@@ -0,0 +1,610 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_STP_EXP_H_ ++#define _WMT_STP_EXP_H_ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "osal_typedef.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 ++#endif ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++#if (WMT_IDC_SUPPORT) ++#define CFG_WMT_LTE_COEX_HANDLING 1 ++#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0 ++#else ++#define CFG_WMT_LTE_COEX_HANDLING 0 ++#endif ++ ++/*from stp_exp.h*/ ++#define BT_TASK_INDX (0) ++#define FM_TASK_INDX (1) ++#define GPS_TASK_INDX (2) ++#define WIFI_TASK_INDX (3) ++#define WMT_TASK_INDX (4) ++#define STP_TASK_INDX (5) ++#define INFO_TASK_INDX (6) ++#define ANT_TASK_INDX (7) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define COEX_TASK_INDX (8) ++#define MTKSTP_MAX_TASK_NUM (9) ++#else ++#define MTKSTP_MAX_TASK_NUM (8) ++#endif ++ ++#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ ++/*end from stp_exp.h*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++********************************************************************************/ ++ ++/*moved from stp_exp.h*/ ++typedef void (*MTK_WCN_STP_EVENT_CB) (void); ++typedef INT32(*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); ++/* export for HIF driver */ ++typedef void (*MTK_WCN_STP_IF_RX) (const PUINT8 data, INT32 size); ++ ++typedef enum { ++ STP_UART_IF_TX = 0, ++ STP_SDIO_IF_TX = 1, ++ STP_BTIF_IF_TX = 2, ++ STP_MAX_IF_TX ++} ENUM_STP_TX_IF_TYPE; ++ ++/*end moved from stp_exp.h*/ ++ ++typedef INT32(*MTK_WCN_STP_SEND_DATA) (const PUINT8 buffer, const UINT32 length, const UINT8 type); ++typedef INT32(*MTK_WCN_STP_PARSER_DATA) (PUINT8 buffer, UINT32 length); ++typedef INT32(*MTK_WCN_STP_RECV_DATA) (PUINT8 buffer, UINT32 length, UINT8 type); ++typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RXQ_EMPTY) (UINT8 type); ++typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RDY) (VOID); ++typedef VOID(*MTK_WCN_STP_SET_BLUEZ) (MTK_WCN_BOOL flags); ++typedef INT32(*MTK_WCN_STP_REG_IF_TX) (ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++typedef INT32(*MTK_WCN_STP_REG_IF_RX) (MTK_WCN_STP_IF_RX func); ++typedef INT32(*MTK_WCN_STP_REG_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); ++typedef INT32(*MTK_WCN_STP_RGE_TX_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); ++typedef INT32(*MTK_WCN_STP_COREDUMP_START_GET)(VOID); ++ ++typedef struct _MTK_WCN_STP_EXP_CB_INFO_ { ++ MTK_WCN_STP_SEND_DATA stp_send_data_cb; ++ MTK_WCN_STP_SEND_DATA stp_send_data_raw_cb; ++ MTK_WCN_STP_PARSER_DATA stp_parser_data_cb; ++ MTK_WCN_STP_RECV_DATA stp_receive_data_cb; ++ MTK_WCN_STP_IS_RXQ_EMPTY stp_is_rxqueue_empty_cb; ++ MTK_WCN_STP_IS_RDY stp_is_ready_cb; ++ MTK_WCN_STP_SET_BLUEZ stp_set_bluez_cb; ++ MTK_WCN_STP_REG_IF_TX stp_if_tx_cb; ++ MTK_WCN_STP_REG_IF_RX stp_if_rx_cb; ++ MTK_WCN_STP_REG_EVENT_CB stp_reg_event_cb; ++ MTK_WCN_STP_RGE_TX_EVENT_CB stp_reg_tx_event_cb; ++ MTK_WCN_STP_COREDUMP_START_GET stp_coredump_start_get_cb; ++} MTK_WCN_STP_EXP_CB_INFO, *P_MTK_WCN_STP_EXP_CB_INFO; ++ ++/*moved from wmt_exp.h*/ ++ ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_ANT = 5, ++ WMTDRV_TYPE_STP = 6, ++ WMTDRV_TYPE_SDIO1 = 7, ++ WMTDRV_TYPE_SDIO2 = 8, ++ WMTDRV_TYPE_LPBK = 9, ++ WMTDRV_TYPE_COREDUMP = 10, ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ WMTDRV_TYPE_AUTOK = 11, ++#endif ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++typedef enum _ENUM_WMTDSNS_TYPE_T { ++ WMTDSNS_FM_DISABLE = 0, ++ WMTDSNS_FM_ENABLE = 1, ++ WMTDSNS_FM_GPS_DISABLE = 2, ++ WMTDSNS_FM_GPS_ENABLE = 3, ++ WMTDSNS_MAX ++} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; ++ ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_E1 = 0x0, ++ WMTHWVER_E2 = 0x1, ++ WMTHWVER_E3 = 0x2, ++ WMTHWVER_E4 = 0x3, ++ WMTHWVER_E5 = 0x4, ++ WMTHWVER_E6 = 0x5, ++ WMTHWVER_E7 = 0x6, ++ WMTHWVER_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++ ++typedef enum _ENUM_WMTTHERM_TYPE_T { ++ WMTTHERM_ZERO = 0, ++ WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, ++ WMTTHERM_READ = WMTTHERM_ENABLE + 1, ++ WMTTHERM_DISABLE = WMTTHERM_READ + 1, ++ WMTTHERM_MAX ++} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ UINT32 /* Buffer size in unit of byte */ ++); ++ ++typedef enum _SDIO_PS_OP { ++ OWN_SET = 0, ++ OWN_CLR = 1, ++ OWN_STATE = 2, ++} SDIO_PS_OP; ++ ++typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); ++ ++typedef enum _ENUM_WMTCHIN_TYPE_T { ++ WMTCHIN_CHIPID = 0x0, ++ WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, ++ WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, ++ WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, ++ WMTCHIN_MAX, ++ ++} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; ++ ++/*end moved from wmt_exp.h*/ ++ ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_FUNC_CTRL) (ENUM_WMTDRV_TYPE_T type); ++typedef INT8(*MTK_WCN_WMT_THERM_CTRL) (ENUM_WMTTHERM_TYPE_T eType); ++typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET) (VOID); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_DSNS_CTRL) (ENUM_WMTDSNS_TYPE_T eType); ++typedef INT32(*MTK_WCN_WMT_MSGCB_REG) (ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++typedef INT32(*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType); ++typedef INT32(*MTK_WCN_WMT_SDIO_OP_REG) (PF_WMT_SDIO_PSOP own_cb); ++typedef INT32(*MTK_WCN_WMT_SDIO_HOST_AWAKE) (VOID); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT) (ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT_TIMEOUT)(ENUM_WMTDRV_TYPE_T type, ++ UINT32 reason, INT32 timeout); ++typedef UINT32(*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type); ++typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag); ++ ++typedef struct _MTK_WCN_WMT_EXP_CB_INFO_ { ++ MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb; ++ MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb; ++ MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb; ++ MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb; ++ MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb; ++ MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb; ++ MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb; ++ MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb; ++ MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb; ++ MTK_WCN_WMT_ASSERT wmt_assert_cb; ++ MTK_WCN_WMT_ASSERT_TIMEOUT wmt_assert_timeout_cb; ++ MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb; ++ MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb; ++} MTK_WCN_WMT_EXP_CB_INFO, *P_MTK_WCN_WMT_EXP_CB_INFO; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*exp for WMT/STP register callback*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_reg ++* DESCRIPTION ++* stp driver reigster exp symbols ++* PARAMETERS ++* pStpExpCb [IN] stp callback structure pointer ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_unreg ++* DESCRIPTION ++* stp driver unreigster exp symbols ++* PARAMETERS ++* VOID ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_stp_exp_cb_unreg(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_exp_cb_reg ++* DESCRIPTION ++* WMT driver reigster exp symbols ++* PARAMETERS ++* pStpExpCb [IN] wmt callback structure pointer ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_unreg ++* DESCRIPTION ++* wmt driver unreigster exp symbols ++* PARAMETERS ++* VOID ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID); ++ ++/*stp exp symbols*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* subfunction send data through STP without seq/ack ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* Is STP ready? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:ready, FALSE:not ready ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); ++ ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_tx ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_rx ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_event_cb ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_tx_event_cb ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get coredump flag is set or not ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32: 0:coredump flag is not set , 1: coredump flag is set ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_get(VOID); ++ ++/*wmt exp symbols*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_func_off ++* DESCRIPTION ++* wmt turn off subsystem ++* PARAMETERS ++* type [IN] subsystem type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_func_on ++* DESCRIPTION ++* wmt turn on subsystem ++* PARAMETERS ++* type [IN] subsystem type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_therm_ctrl ++* DESCRIPTION ++* query chip temperature by WMT CMD ++* PARAMETERS ++* eType [IN] thermal ctrl type ++* RETURNS ++* >=0: chip temperature; 0xff:error ++*****************************************************************************/ ++extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_hwver_get ++* DESCRIPTION ++* get chip hardware version ++* PARAMETERS ++* VOID ++* RETURNS ++* >=0: chip hw version; 0xff:error ++*****************************************************************************/ ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_ic_info_get ++* DESCRIPTION ++* get chip hardware version or f/w version ++* PARAMETERS ++* type : which kind of information is needed ++* RETURNS ++* f/w version or hw version information ++*****************************************************************************/ ++extern UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_dsns_ctrl ++* DESCRIPTION ++* fm dsns cmd ctrl ++* PARAMETERS ++* eType [IN] fm dsns ctrl type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_msgcb_reg ++* DESCRIPTION ++* used for subsystem register chip reset callback for received wmt reset msg. ++* PARAMETERS ++* eType [IN] subsystem type ++* pCb [IN] rst callback ++* RETURNS ++* 1: OK; 0:error ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_msgcb_unreg ++* DESCRIPTION ++* used for subsystem unregister chip reset callback for received wmt reset msg. ++* PARAMETERS ++* eType [IN] subsystem type ++* RETURNS ++* 1: OK; 0:error ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wmt_sdio_op_reg ++* DESCRIPTION ++* used to register callback for set sdio ownership. ++* PARAMETERS ++* own_cb [IN] set owner ship callback ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wmt_sdio_host_awake ++* DESCRIPTION ++* handing host awake when link is stp sdio? ++* PARAMETERS ++* VOID ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_assert ++* DESCRIPTION ++* host trigger firmware assert ++* PARAMETERS ++* type [IN] subsystem driver type ++* reason [IN] trigger assert reason ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++/***************************************************************************** ++ * * FUNCTION ++ * * mtk_wcn_wmt_assert_timeout ++ * * DESCRIPTION ++ * * host trigger firmware assert ++ * * PARAMETERS ++ * * type [IN] subsystem driver type ++ * * reason [IN] trigger assert reason ++ * * timeout [IN] trigger assert timeout data ++ * * RETURNS ++ * * MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++ * *****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, ++ UINT32 reason, INT32 timeout); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_psm_ctrl ++* DESCRIPTION ++* disable/enable psm ++* PARAMETERS ++* flag [IN] disable:0, enable:1 ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag); ++ ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile +new file mode 100644 +index 000000000000..286bfd4bfed3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile +@@ -0,0 +1,65 @@ ++subdir-ccflags-y += \ ++ -I$(src)/linux/include \ ++ -I$(src)/linux/pri/include \ ++ -I$(src)/core/include \ ++ -I$(src)/include \ ++ -I$(src)/../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc ++ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM) ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs/ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include ++ ++EXT_FLAG=_soc ++COMMON_SRC_PATH := $(src) ++COMMON_OBJ_PATH := $(src) ++ ++ifeq ($(CONFIG_ARCH_MT6580), y) ++subdir-ccflags-y += -D CFG_WMT_READ_EFUSE_VCN33 ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO), m) ++# WMT DRIVER ++obj-$(CONFIG_MTK_COMBO) += mtk_stp_wmt$(EXT_FLAG).o ++# WMT DRIVER-core part ++mtk_stp_wmt$(EXT_FLAG)-objs := core/wmt_core.o core/wmt_ctrl.o core/wmt_func.o core/wmt_ic_soc.o core/wmt_lib.o core/wmt_conf.o ++ ++ ++# WMT DRIVER-linux private part ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/wmt_dev.o linux/pri/wmt_exp.o ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_btif.o ++ ++ ++# WMT DRIVER-OSAL ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pub/osal.o linux/pub/bgw_desense.o ++# WMT DRIVER-platform implementation ++# ccflags-y += -D WMT_PLAT_ALPS ++# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/wmt_plat_alps.o ++ ++# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/mtk_wcn_consys_hw.o ++ ++ ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_exp.o core/stp_core.o core/psm_core.o core/btm_core.o linux/pri/stp_dbg.o ++ ++# WMT stub part (built-in kernel image) ++# obj-y += platform/alps/mtk_wcn_consys_stub_alps.o ++ ++ ++ ++obj-$(CONFIG_MTK_COMBO_BT) += mtk_stp_bt$(EXT_FLAG).o ++mtk_stp_bt$(EXT_FLAG)-objs := linux/pub/stp_chrdev_bt.o ++ ++ ++obj-$(CONFIG_MTK_COMBO_WIFI) += mtk_wmt_wifi$(EXT_FLAG).o ++mtk_wmt_wifi$(EXT_FLAG)-objs := linux/pub/wmt_chrdev_wifi.o ++ ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO), y) ++# subdir-ccflags-y += -D WMT_PLAT_ALPS ++obj-y += core/ ++obj-y += linux/ ++#obj-y += $(subst ",,$(CONFIG_MTK_PLATFORM))/ ++obj-y += mt7623/ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile +new file mode 100644 +index 000000000000..9df71b9e163e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile +@@ -0,0 +1,22 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../linux/include \ ++ -I$(src)/../linux/pri/include \ ++ -I$(src)/../core/include \ ++ -I$(src)/../include \ ++ -I$(src)/../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ ++ ++obj-y += wmt_core.o \ ++ wmt_ctrl.o \ ++ wmt_func.o \ ++ wmt_ic_soc.o \ ++ wmt_lib.o \ ++ wmt_conf.o \ ++ btm_core.o \ ++ dbg_core.o \ ++ psm_core.o \ ++ stp_core.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c +new file mode 100644 +index 000000000000..4946b682d826 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c +@@ -0,0 +1,1376 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_dbg.h" ++#include "stp_core.h" ++#include "btm_core.h" ++#include "wmt_plat.h" ++ ++#define PFX_BTM "[STP-BTM] " ++#define STP_BTM_LOG_LOUD 4 ++#define STP_BTM_LOG_DBG 3 ++#define STP_BTM_LOG_INFO 2 ++#define STP_BTM_LOG_WARN 1 ++#define STP_BTM_LOG_ERR 0 ++ ++INT32 gBtmDbgLevel = STP_BTM_LOG_INFO; ++ ++#define STP_BTM_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_LOUD) \ ++ pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ ++ pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_INFO) \ ++ pr_debug(PFX_BTM "[I]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_WARN) \ ++ pr_warn(PFX_BTM "[W]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_ERR) \ ++ pr_err(PFX_BTM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define STP_BTM_TRC_FUNC(f) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ ++ pr_debug(PFX_BTM "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#define ASSERT(expr) ++ ++MTKSTP_BTM_T stp_btm_i; ++MTKSTP_BTM_T *stp_btm = &stp_btm_i; ++ ++const char *g_btm_op_name[] = { ++ "STP_OPID_BTM_RETRY", ++ "STP_OPID_BTM_RST", ++ "STP_OPID_BTM_DBG_DUMP", ++ "STP_OPID_BTM_DUMP_TIMEOUT", ++ "STP_OPID_BTM_POLL_CPUPCR", ++ "STP_OPID_BTM_PAGED_DUMP", ++ "STP_OPID_BTM_FULL_DUMP", ++ "STP_OPID_BTM_PAGED_TRACE", ++ "STP_OPID_BTM_FORCE_FW_ASSERT", ++#if CFG_WMT_LTE_COEX_HANDLING ++ "STP_OPID_BTM_WMT_LTE_COEX", ++#endif ++ "STP_OPID_BTM_EXIT" ++}; ++ ++#if 0 ++static char *_stp_pkt_type(int type) ++{ ++ ++ static char s[10]; ++ ++ switch (type) { ++ case WMT_TASK_INDX: ++ osal_memcpy(s, "WMT", strlen("WMT") + 1); ++ break; ++ case BT_TASK_INDX: ++ osal_memcpy(s, "BT", strlen("BT") + 1); ++ break; ++ case GPS_TASK_INDX: ++ osal_memcpy(s, "GPS", strlen("GPS") + 1); ++ break; ++ case FM_TASK_INDX: ++ osal_memcpy(s, "FM", strlen("FM") + 1); ++ break; ++ default: ++ osal_memcpy(s, "UNKNOWN", strlen("UNKNOWN") + 1); ++ break; ++ } ++ ++ return s; ++} ++#endif ++ ++static INT32 _stp_btm_put_dump_to_nl(void) ++{ ++#define NUM_FETCH_ENTRY 8 ++ ++ static UINT8 buf[2048]; ++ static UINT8 tmp[2048]; ++ ++ UINT32 buf_len; ++ STP_PACKET_T *pkt; ++ STP_DBG_HDR_T *hdr; ++ INT32 len; ++ INT32 remain = 0, index = 0; ++ INT32 retry = 0, rc = 0, nl_retry = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ index = 0; ++ tmp[index++] = '['; ++ tmp[index++] = 'M'; ++ tmp[index++] = ']'; ++ ++ do { ++ index = 3; ++ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); ++ if (buf_len > 0) { ++ pkt = (STP_PACKET_T *) buf; ++ hdr = &pkt->hdr; ++ len = pkt->hdr.len; ++ osal_memcpy(&tmp[index], &len, 2); ++ index += 2; ++ if (hdr->dbg_type == STP_DBG_FW_DMP) { ++ osal_memcpy(&tmp[index], pkt->raw, len); ++ ++ if (len <= 1500) { ++ /* pr_warn("\n%s\n+++\n", tmp); */ ++ /* pr_warn("send coredump len:%d\n", len); */ ++ /* pr_warn("send coredump:%s\n", tmp); */ ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); ++ ++ while (rc) { ++ nl_retry++; ++ if (nl_retry > 1000) ++ break; ++ STP_BTM_WARN_FUNC ++ ("**dump send fails, and retry again.**\n"); ++ osal_sleep_ms(3); ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); ++ if (!rc) ++ STP_BTM_WARN_FUNC("****retry again ok!**\n"); ++ } ++ /* schedule(); */ ++ } else { ++ STP_BTM_INFO_FUNC("dump entry length is over long\n"); ++ BUG_ON(0); ++ } ++ retry = 0; ++ } ++ } else { ++ retry++; ++ osal_sleep_ms(100); ++ } ++ } while ((remain > 0) || (retry < 2)); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return 0; ++} ++ ++#define SUB_PKT_SIZE 1024 ++#define SUB_PKT_HEADER 5 /*'[M]',3Bytes; len,2Bytes*/ ++ ++INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len) ++{ ++ static UINT8 tmp[SUB_PKT_SIZE + SUB_PKT_HEADER]; ++ ++ INT32 remain = dump_len, index = 0; ++ INT32 rc = 0, nl_retry = 0; ++ INT32 len; ++ INT32 offset = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ if (dump_len > 0) { ++ index = 0; ++ tmp[index++] = '['; ++ tmp[index++] = 'M'; ++ tmp[index++] = ']'; ++ ++ do { ++ index = 3; ++ if (remain >= SUB_PKT_SIZE) ++ len = SUB_PKT_SIZE; ++ else ++ len = remain; ++ remain -= len; ++ ++ osal_memcpy(&tmp[index], &len, 2); ++ index += 2; ++ osal_memcpy(&tmp[index], data_buf + offset, len); ++ offset += len; ++ STP_BTM_DBG_FUNC ++ ("send %d remain %d\n", len, remain); ++ ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); ++ while (rc) { ++ nl_retry++; ++ if (nl_retry > 1000) ++ break; ++ STP_BTM_WARN_FUNC ++ ("**dump send fails, and retry again.**\n"); ++ osal_sleep_ms(3); ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); ++ if (!rc) { ++ STP_BTM_WARN_FUNC ++ ("****retry again ok!**\n"); ++ } ++ } ++ /* schedule(); */ ++ } while (remain > 0); ++ } else ++ STP_BTM_INFO_FUNC("dump entry length is 0\n"); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return 0; ++} ++ ++static INT32 _stp_btm_put_dump_to_aee(void) ++{ ++ static UINT8 buf[2048]; ++ static UINT8 tmp[2048]; ++ ++ UINT32 buf_len; ++ STP_PACKET_T *pkt; ++ STP_DBG_HDR_T *hdr; ++ INT32 remain = 0; ++ INT32 retry = 0; ++ INT32 ret = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ do { ++ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); ++ if (buf_len > 0) { ++ pkt = (STP_PACKET_T *) buf; ++ hdr = &pkt->hdr; ++ if (hdr->dbg_type == STP_DBG_FW_DMP) { ++ memcpy(&tmp[0], pkt->raw, pkt->hdr.len); ++ ++ if (pkt->hdr.len <= 1500) { ++ tmp[pkt->hdr.len] = '\n'; ++ tmp[pkt->hdr.len + 1] = '\0'; ++ ++ ret = stp_dbg_aee_send(tmp, pkt->hdr.len, 0); ++ } else { ++ STP_BTM_INFO_FUNC("dump entry length is over long\n"); ++ BUG_ON(0); ++ } ++ retry = 0; ++ } ++ } else { ++ retry++; ++ msleep(100); ++ } ++ } while ((remain > 0) || (retry < 2)); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return ret; ++} ++ ++#if 0 ++INT32 _stp_trigger_firmware_assert_via_emi(VOID) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ INT32 status = -1; ++ INT32 i = 0, j = 0; ++ ++ do { ++ STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); ++ if (!p_virtual_addr) { ++ STP_BTM_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); ++ STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); ++#if 1 ++ /* wait for firmware assert */ ++ osal_sleep_ms(50); ++ /* if firmware is not assert self, host driver helps it. */ ++ do { ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ mtk_wcn_stp_wakeup_consys(); ++ STP_BTM_INFO_FUNC("[Force Assert] wakeup consys (%d)\n", i); ++ stp_dbg_poll_cpupcr(5, 1, 1); ++ osal_sleep_ms(5); ++ ++ i++; ++ if (i > 20) { ++ i = 0; ++ break; ++ } ++ } while (1); ++#endif ++ ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ j++; ++ if (j > 8) { ++ j = 0; ++ break; ++ } ++ } while (1); ++ ++ return status; ++} ++#else ++INT32 _stp_trigger_firmware_assert_via_emi(VOID) ++{ ++ INT32 status = -1; ++ INT32 j = 0; ++ ++ wmt_plat_force_trigger_assert(STP_FORCE_TRG_ASSERT_DEBUG_PIN); ++ ++ do { ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ stp_dbg_poll_cpupcr(5, 1, 1); ++ stp_dbg_poll_dmaregs(5, 1); ++ j++; ++ STP_BTM_INFO_FUNC("Wait for assert message (%d)\n", j); ++ osal_sleep_ms(20); ++ if (j > 49) { /* wait for 1 second */ ++ stp_dbg_set_fw_info("host trigger fw assert timeout", ++ osal_strlen("host trigger fw assert timeout"), ++ STP_HOST_TRIGGER_ASSERT_TIMEOUT); ++ wcn_core_dump_timeout(); /* trigger collect SYS_FTRACE */ ++ break; ++ } ++ } while (1); ++ ++ return status; ++} ++#endif ++ ++#define COMBO_DUMP2AEE ++#if 1 ++#define STP_DBG_PAGED_DUMP_BUFFER_SIZE (32*1024*sizeof(char)) ++UINT8 g_paged_dump_buffer[STP_DBG_PAGED_DUMP_BUFFER_SIZE] = { 0 }; ++ ++#define STP_DBG_PAGED_TRACE_SIZE (2048*sizeof(char)) ++UINT8 g_paged_trace_buffer[STP_DBG_PAGED_TRACE_SIZE] = { 0 }; ++ ++UINT32 g_paged_dump_len = 0; ++UINT32 g_paged_trace_len = 0; ++VOID _stp_dump_emi_dump_buffer(UINT8 *buffer, UINT32 len) ++{ ++ UINT32 i = 0; ++ ++ if (len > 16) ++ len = 16; ++ for (i = 0; i < len; i++) { ++ if (i % 16 == 0 && i != 0) ++ pr_cont("\n "); ++ ++ if (buffer[i] == ']' || buffer[i] == '[' || buffer[i] == ',') ++ pr_cont("%c", buffer[i]); ++ else ++ pr_cont("0x%02x ", buffer[i]); ++ } ++} ++#endif ++static INT32 _stp_btm_handler(MTKSTP_BTM_T *stp_btm, P_STP_BTM_OP pStpOp) ++{ ++ INT32 ret = -1; ++ INT32 dump_sink = 1; /* core dump target, 0: aee; 1: netlink */ ++ INT32 Ret = 0; ++ static UINT32 counter; ++ UINT32 full_dump_left = STP_FULL_DUMP_TIME; ++ UINT32 page_counter = 0; ++ UINT32 packet_num = STP_PAGED_DUMP_TIME_LIMIT/100; ++ UINT32 dump_num = 0; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ P_CONSYS_EMI_ADDR_INFO p_ecsi; ++ ++ p_ecsi = wmt_plat_get_emi_phy_add(); ++ osal_assert(p_ecsi); ++ if (NULL == pStpOp) ++ return -1; ++ ++ switch (pStpOp->opId) { ++ case STP_OPID_BTM_EXIT: ++ /* TODO: clean all up? */ ++ ret = 0; ++ break; ++ ++ /*tx timeout retry */ ++ case STP_OPID_BTM_RETRY: ++ stp_do_tx_timeout(); ++ ret = 0; ++ ++ break; ++ ++ /*whole chip reset */ ++ case STP_OPID_BTM_RST: ++ STP_BTM_INFO_FUNC("whole chip reset start!\n"); ++ STP_BTM_INFO_FUNC("....+\n"); ++ if (stp_btm->wmt_notify) { ++ stp_btm->wmt_notify(BTM_RST_OP); ++ ret = 0; ++ } else { ++ STP_BTM_ERR_FUNC("stp_btm->wmt_notify is NULL."); ++ ret = -1; ++ } ++ ++ STP_BTM_INFO_FUNC("whole chip reset end!\n"); ++ ++ break; ++ ++ case STP_OPID_BTM_DBG_DUMP: ++ /*Notify the wmt to get dump data */ ++ STP_BTM_DBG_FUNC("wmt dmp notification\n"); ++ dump_sink = ((stp_btm->wmt_notify(BTM_GET_AEE_SUPPORT_FLAG) == MTK_WCN_BOOL_TRUE) ? 0 : 1); ++ ++ if (dump_sink == 0) ++ _stp_btm_put_dump_to_aee(); ++ else if (dump_sink == 1) ++ _stp_btm_put_dump_to_nl(); ++ else ++ STP_BTM_ERR_FUNC("unknown sink %d\n", dump_sink); ++ ++ break; ++ ++ case STP_OPID_BTM_DUMP_TIMEOUT: ++ /* Flush dump data, and reset compressor */ ++ STP_BTM_INFO_FUNC("Flush dump data\n"); ++ wcn_core_dump_flush(0, MTK_WCN_BOOL_TRUE); ++ break; ++ ++ case STP_OPID_BTM_POLL_CPUPCR: ++ do { ++ UINT32 times; ++ UINT32 sleep; ++ ++ times = pStpOp->au4OpData[0]; ++ sleep = pStpOp->au4OpData[1]; ++ ++ ret = stp_dbg_poll_cpupcr(times, sleep, 0); ++ ret += stp_dbg_poll_dmaregs(times, sleep); ++ } while (0); ++ break; ++ ++ case STP_OPID_BTM_PAGED_DUMP: ++ g_paged_dump_len = 0; ++ issue_type = STP_FW_ASSERT_ISSUE; ++ /*packet number depend on dump_num get from register:0xf0080044 ,support jade*/ ++ wcn_core_dump_deinit_gcoredump(); ++ dump_num = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_page_dump_num); ++ if (dump_num != 0) { ++ packet_num = dump_num; ++ STP_BTM_WARN_FUNC("get consys dump num packet_num(%d)\n", packet_num); ++ } else { ++ STP_BTM_ERR_FUNC("can not get consys dump num and default num is 35\n"); ++ } ++ Ret = wcn_core_dump_init_gcoredump(packet_num, STP_CORE_DUMP_TIMEOUT); ++ if (Ret) { ++ STP_BTM_ERR_FUNC("core dump init fail\n"); ++ break; ++ } ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ page_counter = 0; ++ do { ++ UINT32 loop_cnt1 = 0; ++ UINT32 loop_cnt2 = 0; ++ ENUM_HOST_DUMP_STATE host_state; ++ ENUM_CHIP_DUMP_STATE chip_state; ++ UINT32 dump_phy_addr = 0; ++ UINT8 *dump_vir_addr = NULL; ++ UINT32 dump_len = 0; ++ UINT32 isEnd = 0; ++ ++ host_state = (ENUM_HOST_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_state); ++ if (STP_HOST_DUMP_NOT_START == host_state) { ++ counter++; ++ STP_BTM_INFO_FUNC("counter(%d)\n", counter); ++ osal_sleep_ms(100); ++ } else { ++ counter = 0; ++ } ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_PUT_DONE == chip_state) { ++ STP_BTM_INFO_FUNC("chip put done\n"); ++ break; ++ } ++ STP_BTM_INFO_FUNC("waiting chip put done\n"); ++ STP_BTM_INFO_FUNC("chip_state: %d\n", chip_state); ++ loop_cnt1++; ++ osal_sleep_ms(5); ++ ++ if (loop_cnt1 > 10) ++ goto paged_dump_end; ++ ++ } ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); ++ ++ dump_phy_addr = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); ++ ++ if (!dump_phy_addr) { ++ STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); ++ ret = -2; ++ break; ++ } ++ dump_len = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); ++ STP_BTM_INFO_FUNC("dump_phy_ddr(%08x),dump_vir_add(0x%p),dump_len(%d)\n", ++ dump_phy_addr, dump_vir_addr, dump_len); ++ ++ /*move dump info according to dump_addr & dump_len */ ++#if 1 ++ osal_memcpy(&g_paged_dump_buffer[0], dump_vir_addr, dump_len); ++ _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], dump_len); ++ ++ if (0 == page_counter) { /* do fw assert infor paser in first paged dump */ ++ if (1 == stp_dbg_get_host_trigger_assert()) ++ issue_type = STP_HOST_TRIGGER_FW_ASSERT; ++ ++ ret = stp_dbg_set_fw_info(&g_paged_dump_buffer[0], 512, issue_type); ++ if (ret) { ++ STP_BTM_ERR_FUNC("set fw issue infor fail(%d),maybe fw warm reset...\n", ret); ++ stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"), ++ STP_FW_WARM_RST_ISSUE); ++ } ++ } ++ ++ if (dump_len <= 32 * 1024) { ++ pr_err("g_coredump_mode: %d!\n", g_coredump_mode); ++ if (1 == g_coredump_mode) ++ ret = stp_dbg_aee_send(&g_paged_dump_buffer[0], dump_len, 0); ++ else if (2 == g_coredump_mode) ++ ret = _stp_btm_put_emi_dump_to_nl(&g_paged_dump_buffer[0], dump_len); ++ else{ ++ STP_BTM_INFO_FUNC("coredump is disabled!\n"); ++ return 0; ++ } ++ if (ret == 0) ++ STP_BTM_INFO_FUNC("aee send ok!\n"); ++ else if (ret == 1) ++ STP_BTM_INFO_FUNC("aee send fisish!\n"); ++ else ++ STP_BTM_ERR_FUNC("aee send error!\n"); ++ } else ++ STP_BTM_ERR_FUNC("dump len is over than 32K(%d)\n", dump_len); ++ ++ g_paged_dump_len += dump_len; ++ STP_BTM_INFO_FUNC("dump len update(%d)\n", g_paged_dump_len); ++#endif ++ wmt_plat_update_host_sync_num(); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); ++ ++ STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); ++ ++ page_counter++; ++ STP_BTM_INFO_FUNC("\n\n++ paged dump counter(%d) ++\n\n\n", page_counter); ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_END == chip_state) { ++ STP_BTM_INFO_FUNC("chip put end\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); ++ break; ++ } ++ STP_BTM_INFO_FUNC("waiting chip put end\n"); ++ ++ loop_cnt2++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt2 > 10) ++ goto paged_dump_end; ++ } ++ ++paged_dump_end: ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ ++ if (counter > packet_num) { ++ isEnd = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_paded_dump_end); ++ ++ if (isEnd) { ++ STP_BTM_INFO_FUNC("paged dump end\n"); ++ ++ STP_BTM_INFO_FUNC("\n\n paged dump print ++\n\n"); ++ _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], g_paged_dump_len); ++ STP_BTM_INFO_FUNC("\n\n paged dump print --\n\n"); ++ STP_BTM_INFO_FUNC("\n\n paged dump size = %d, paged dump page number = %d\n\n", ++ g_paged_dump_len, page_counter); ++ counter = 0; ++ ret = 0; ++ } else { ++ STP_BTM_ERR_FUNC("paged dump fail\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ stp_dbg_poll_cpupcr(5, 5, 0); ++ stp_dbg_poll_dmaregs(5, 1); ++ counter = 0; ++ ret = -1; ++ } ++ break; ++ } ++ ++ } while (1); ++ ++ break; ++ ++ case STP_OPID_BTM_FULL_DUMP: ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ do { ++ UINT32 loop_cnt1 = 0; ++ UINT32 loop_cnt2 = 0; ++ ENUM_CHIP_DUMP_STATE chip_state; ++ UINT32 dump_phy_addr = 0; ++ UINT8 *dump_vir_addr = NULL; ++ UINT32 dump_len = 0; ++ UINT32 isFail = 0; ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_PUT_DONE == chip_state) ++ break; ++ ++ loop_cnt1++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt1 > 10) { ++ isFail = 1; ++ goto full_dump_end; ++ } ++ } ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); ++ ++ dump_phy_addr = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); ++ if (!dump_phy_addr) { ++ STP_BTM_ERR_FUNC("get phy dump address fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get vir dump address fail\n"); ++ ret = -2; ++ break; ++ } ++ dump_len = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); ++ /*move dump info according to dump_addr & dump_len */ ++ wmt_plat_update_host_sync_num(); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); ++ ++ STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_END == chip_state) { ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); ++ break; ++ } ++ loop_cnt2++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt2 > 10) { ++ isFail = 1; ++ goto full_dump_end; ++ } ++ } ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++full_dump_end: ++ if (isFail) { ++ STP_BTM_ERR_FUNC("full dump fail\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ ret = -1; ++ break; ++ } ++ } while (--full_dump_left > 0); ++ if (0 == full_dump_left) { ++ STP_BTM_INFO_FUNC("full dump end\n"); ++ ret = 0; ++ } ++ break; ++ case STP_OPID_BTM_PAGED_TRACE: ++ g_paged_trace_len = 0; ++ do { ++ UINT32 ctrl_val = 0; ++ UINT32 loop_cnt1 = 0; ++ UINT32 buffer_start = 0; ++ UINT32 buffer_idx = 0; ++ UINT8 *dump_vir_addr = NULL; ++ ++ while (loop_cnt1 < 10) { ++ ctrl_val = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state); ++ if (0x8 == ctrl_val) ++ break; ++ osal_sleep_ms(10); ++ loop_cnt1++; ++ } ++ ++ if (loop_cnt1 >= 10) { ++ STP_BTM_ERR_FUNC("polling CTRL STATE fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ buffer_start = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_start); ++ buffer_idx = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_idx); ++ /* buffer_len = buffer_idx - buffer_start; */ ++ g_paged_trace_len = buffer_idx; ++ STP_BTM_INFO_FUNC("paged trace buffer addr(%08x),buffer_len(%d)\n", buffer_start, buffer_idx); ++ dump_vir_addr = wmt_plat_get_emi_virt_add(buffer_start - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get vir dump address fail\n"); ++ ret = -2; ++ break; ++ } ++ osal_memcpy(&g_paged_trace_buffer[0], dump_vir_addr, ++ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE); ++ /*moving paged trace according to buffer_start & buffer_len */ ++ do { ++ int i = 0; ++ int dump_len = 0; ++ ++ dump_len = ++ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE; ++ pr_warn("\n\n -- paged trace hex output --\n\n"); ++ for (i = 0; i < dump_len; i++) { ++ if (i % 16 == 0) ++ pr_cont("\n"); ++ ++ pr_cont("%02x ", g_paged_trace_buffer[i]); ++ } ++ pr_warn("\n\n -- paged trace ascii output --\n\n"); ++ for (i = 0; i < dump_len; i++) { ++ if (i % 64 == 0) ++ pr_cont("\n"); ++ pr_cont("%c", g_paged_trace_buffer[i]); ++ } ++ } while (0); ++ /*move parser fw assert infor to paged dump in the one paged dump */ ++ /* ret = stp_dbg_set_fw_info(&g_paged_trace_buffer[0],g_paged_trace_len,issue_type); */ ++ ret = 0; ++ ++ } while (0); ++ mtk_wcn_stp_ctx_restore(); ++ break; ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ case STP_OPID_BTM_WMT_LTE_COEX: ++ ret = wmt_idc_msg_to_lte_handing(); ++ break; ++#endif ++ default: ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ /* INT32 ret = 0; */ ++ ++ if (!pOpQ) { ++ STP_BTM_WARN_FUNC("!pOpQ\n"); ++ return NULL; ++ } ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ ++ if (!pOp) ++ STP_BTM_WARN_FUNC("RB_GET fail\n"); ++ ++ return pOp; ++} ++ ++static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 ret; ++ ++ if (!pOpQ || !pOp) { ++ STP_BTM_WARN_FUNC("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); ++ return 0; /* ;MTK_WCN_BOOL_FALSE; */ ++ } ++ ++ ret = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ ret = -1; ++ ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ ++ if (ret) { ++ STP_BTM_WARN_FUNC("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", ++ pOpQ, ++ RB_COUNT(pOpQ), ++ &stp_btm->rFreeOpQ, ++ &stp_btm->rActiveOpQ); ++ return 0; ++ } ++ /* STP_BTM_WARN_FUNC("RB_COUNT = %d\n",RB_COUNT(pOpQ)); */ ++ return 1; ++ ++} ++ ++P_OSAL_OP _stp_btm_get_free_op(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ ++ if (stp_btm) { ++ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, sizeof(pOp->op)); ++ ++ return pOp; ++ } else ++ return NULL; ++} ++ ++INT32 _stp_btm_put_act_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp) ++{ ++ INT32 bRet = 0; ++ INT32 bCleanup = 0; ++ long wait_ret = -1; ++ ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ if (!stp_btm || !pOp) { ++ STP_BTM_ERR_FUNC("Input NULL pointer\n"); ++ return bRet; ++ } ++ do { ++ pSignal = &pOp->signal; ++ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(&pOp->signal); ++ } ++ ++ /* put to active Q */ ++ bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp); ++ if (0 == bRet) { ++ STP_BTM_WARN_FUNC("put active queue fail\n"); ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ break; ++ } ++ ++ /* wake up wmtd */ ++ osal_trigger_event(&stp_btm->STPd_event); ++ ++ if (pSignal->timeoutValue == 0) { ++ bRet = 1; /* MTK_WCN_BOOL_TRUE; */ ++ /* clean it in wmtd */ ++ break; ++ } ++ ++ /* wait result, clean it here */ ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ ++ /* check result */ ++ wait_ret = osal_wait_for_signal_timeout(&pOp->signal); ++ ++ STP_BTM_DBG_FUNC("wait completion:%ld\n", wait_ret); ++ if (!wait_ret) { ++ STP_BTM_ERR_FUNC("wait completion timeout\n"); ++ /* TODO: how to handle it? retry? */ ++ } else { ++ if (pOp->result) ++ STP_BTM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); ++ ++ bRet = (pOp->result) ? 0 : 1; ++ } ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); ++ } ++ bRet = (pOp->result) ? 0 : 1; ++ return bRet; ++} ++ ++static INT32 _stp_btm_wait_for_msg(void *pvData) ++{ ++ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; ++ ++ return (!RB_EMPTY(&stp_btm->rActiveOpQ)) || osal_thread_should_stop(&stp_btm->BTMd); ++} ++ ++static INT32 _stp_btm_proc(void *pvData) ++{ ++ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; ++ P_OSAL_OP pOp; ++ INT32 id; ++ INT32 result; ++ ++ if (!stp_btm) { ++ STP_BTM_WARN_FUNC("!stp_btm\n"); ++ return -1; ++ } ++ ++ for (;;) { ++ pOp = NULL; ++ ++ osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (void *)stp_btm); ++ ++ if (osal_thread_should_stop(&stp_btm->BTMd)) { ++ STP_BTM_INFO_FUNC("should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); ++ ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_lxop activeQ fail\n"); ++ continue; ++ } ++ ++ id = osal_op_get_id(pOp); ++ ++ STP_BTM_DBG_FUNC("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", ++ id, (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), ++ RB_COUNT(&stp_btm->rActiveOpQ)); ++ ++ if (id >= STP_OPID_BTM_NUM) { ++ STP_BTM_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ result = -1; ++ goto handler_done; ++ } ++ ++ result = _stp_btm_handler(stp_btm, &pOp->op); ++ ++handler_done: ++ ++ if (result) { ++ STP_BTM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, ++ (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), ++ result); ++ } ++ ++ if (osal_op_is_wait_for_signal(pOp)) { ++ osal_op_raise_signal(pOp, result); ++ } else { ++ /* put Op back to freeQ */ ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); ++ } ++ ++ if (STP_OPID_BTM_EXIT == id) { ++ break; ++ } else if (STP_OPID_BTM_RST == id) { ++ /* prevent multi reset case */ ++ stp_btm_reset_btm_wq(stp_btm); ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ } ++ } ++ ++ STP_BTM_INFO_FUNC("exits\n"); ++ ++ return 0; ++}; ++ ++static inline INT32 _stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_RST; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_RETRY; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (!stp_btm) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_DUMP_TIMEOUT; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = opid; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ INT32 retval; ++#if 0 ++ UINT32 dump_type; ++ UINT8 *virtual_addr = NULL; ++#endif ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++#if 1 /* Paged dump */ ++ STP_BTM_INFO_FUNC("paged dump start++\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); ++ if (retval) ++ STP_BTM_ERR_FUNC("paged dump fail\n"); ++#else ++ virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_CHIP_SYNC_ADDR); ++ if (!virtual_addr) { ++ STP_BTM_ERR_FUNC("get dump type virtual addr fail\n"); ++ return -1; ++ } ++ dump_type = CONSYS_REG_READ(virtual_addr); ++ STP_BTM_INFO_FUNC("dump type:%08x\n", dump_type); ++ ++ if ((dump_type & 0xfffff) == (CONSYS_PAGED_DUMP_START_ADDR & 0xfffff)) { ++ STP_BTM_INFO_FUNC("do paged dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); ++ if (retval) { ++ STP_BTM_ERR_FUNC("paged dump fail,do full dump\n"); ++ _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); ++ } ++ } else if ((dump_type & 0xfffff) == (CONSYS_FULL_DUMP_START_ADDR & 0xfffff)) { ++ STP_BTM_INFO_FUNC("do full dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); ++ } else { ++ STP_BTM_INFO_FUNC("do normal dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DBG_DUMP); ++ } ++#endif ++ ++ return retval; ++} ++ ++static inline INT32 _stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_POLL_CPUPCR; ++ pOp->signal.timeoutValue = 0; ++ pOp->op.au4OpData[0] = times; ++ pOp->op.au4OpData[1] = sleep; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_PAGED_TRACE; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) ++{ ++ INT32 ret = -1; ++ ++ ret = _stp_trigger_firmware_assert_via_emi(); ++ ++ return ret; ++ ++} ++ ++INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_rst_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_stp_retry_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_coredump_timeout_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_dmp_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_trace_wq(stp_btm); ++} ++ ++INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) ++{ ++ return _stp_notify_btm_poll_cpupcr(stp_btm, times, sleep); ++} ++ ++INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en) ++{ ++ return stp_dbg_poll_cuppcr_ctrl(en); ++} ++ ++INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) ++{ ++ INT32 ret = -1; ++#if BTIF_RXD_BE_BLOCKED_DETECT ++ if (is_btif_rxd_be_blocked()) ++ ret = wcn_btif_rxd_blocked_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ else ++#endif ++ ret = _stp_btm_do_fw_assert_via_emi(stp_btm); ++ return ret; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++static inline INT32 _stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_WMT_LTE_COEX; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_notify_btm_handle_wmt_lte_coex(stp_btm); ++} ++ ++#endif ++MTKSTP_BTM_T *stp_btm_init(void) ++{ ++ INT32 i = 0x0; ++ INT32 ret = -1; ++ ++ osal_unsleepable_lock_init(&stp_btm->wq_spinlock); ++ osal_event_init(&stp_btm->STPd_event); ++ stp_btm->wmt_notify = wmt_lib_btm_cb; ++ ++ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); ++ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); ++ ++ /* Put all to free Q */ ++ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_btm->arQue[i].signal)); ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); ++ } ++ ++ /*Generate PSM thread, to servie STP-CORE for packet retrying and core dump receiving */ ++ stp_btm->BTMd.pThreadData = (VOID *) stp_btm; ++ stp_btm->BTMd.pThreadFunc = (VOID *) _stp_btm_proc; ++ osal_memcpy(stp_btm->BTMd.threadName, BTM_THREAD_NAME, osal_strlen(BTM_THREAD_NAME)); ++ ++ ret = osal_thread_create(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_create fail...\n"); ++ goto ERR_EXIT1; ++ } ++ ++ /* Start STPd thread */ ++ ret = osal_thread_run(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_run FAILS\n"); ++ goto ERR_EXIT1; ++ } ++ ++ return stp_btm; ++ ++ERR_EXIT1: ++ ++ return NULL; ++ ++} ++ ++INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ INT32 ret = -1; ++ ++ STP_BTM_INFO_FUNC("btm deinit\n"); ++ ++ if (!stp_btm) ++ return STP_BTM_OPERATION_FAIL; ++ ++ ret = osal_thread_destroy(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ return STP_BTM_OPERATION_FAIL; ++ } ++ ++ return STP_BTM_OPERATION_SUCCESS; ++} ++ ++INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ UINT32 i = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); ++ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* Put all to free Q */ ++ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_btm->arQue[i].signal)); ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); ++ } ++ ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c +new file mode 100644 +index 000000000000..246448b38b31 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c +@@ -0,0 +1,13 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h +new file mode 100644 +index 000000000000..9a429b4af1e3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h +@@ -0,0 +1,133 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _BTM_CORE_H ++#define _BTM_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_wmt.h" ++#include "wmt_plat.h" ++#include "wmt_idc.h" ++#include "mtk_btif_exp.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define STP_BTM_OPERATION_FAIL (-1) ++#define STP_BTM_OPERATION_SUCCESS (0) ++ ++#define STP_BTM_OP_BUF_SIZE (64) ++ ++#define BTM_THREAD_NAME "mtk_stp_btm" ++ ++#define STP_PAGED_DUMP_TIME_LIMIT 3500 ++#define STP_FULL_DUMP_TIME 3 ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_STP_BTM_OPID_T { ++ STP_OPID_BTM_RETRY = 0x0, ++ STP_OPID_BTM_RST = 0x1, ++ STP_OPID_BTM_DBG_DUMP = 0x2, ++ STP_OPID_BTM_DUMP_TIMEOUT = 0x3, ++ STP_OPID_BTM_POLL_CPUPCR = 0x4, ++ STP_OPID_BTM_PAGED_DUMP = 0x5, ++ STP_OPID_BTM_FULL_DUMP = 0x6, ++ STP_OPID_BTM_PAGED_TRACE = 0x7, ++ STP_OPID_BTM_FORCE_FW_ASSERT = 0x8, ++#if CFG_WMT_LTE_COEX_HANDLING ++ STP_OPID_BTM_WMT_LTE_COEX = 0x9, ++#endif ++ STP_OPID_BTM_EXIT, ++ STP_OPID_BTM_NUM ++} ENUM_STP_BTM_OPID_T, *P_ENUM_STP_BTM_OPID_T; ++ ++typedef OSAL_OP_DAT STP_BTM_OP; ++typedef P_OSAL_OP_DAT P_STP_BTM_OP; ++ ++typedef struct mtk_stp_btm { ++ OSAL_THREAD BTMd; /* main thread (wmtd) handle */ ++ OSAL_EVENT STPd_event; ++ OSAL_UNSLEEPABLE_LOCK wq_spinlock; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[STP_BTM_OP_BUF_SIZE]; /* real op instances */ ++ ++ /*wmt_notify */ ++ INT32 (*wmt_notify)(MTKSTP_BTM_WMT_OP_T); ++} MTKSTP_BTM_T; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep); ++INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en); ++INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm); ++INT32 wcn_psm_flag_trigger_collect_ftrace(void); ++#if BTIF_RXD_BE_BLOCKED_DETECT ++INT32 wcn_btif_rxd_blocked_collect_ftrace(void); ++MTK_WCN_BOOL is_btif_rxd_be_blocked(void); ++#endif ++MTKSTP_BTM_T *stp_btm_init(void); ++extern unsigned int g_coredump_mode; ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h +new file mode 100644 +index 000000000000..d8c6ebe9c4b0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h +@@ -0,0 +1,69 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _DBG_CORE_H ++#define _DBG_CORE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h +new file mode 100644 +index 000000000000..fe92f25e92c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h +@@ -0,0 +1,251 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _PSM_CORE_H ++#define _PSM_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_wmt.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define PFX_PSM "[STP-PSM] " ++#define STP_PSM_LOG_LOUD 4 ++#define STP_PSM_LOG_DBG 3 ++#define STP_PSM_LOG_INFO 2 ++#define STP_PSM_LOG_WARN 1 ++#define STP_PSM_LOG_ERR 0 ++ ++#define ASSERT(expr) ++#define STP_PSM_FIFO_SIZE 0x2000 /* 8kbytes */ ++#define STP_PSM_TX_SIZE 0x800 /* 2kbytes */ ++ ++#define STP_PSM_OPERATION_FAIL (-1) ++#define STP_PSM_OPERATION_SUCCESS (0) ++ ++#define STP_PSM_PACKET_SIZE_MAX (2000) ++ ++#define PSM_HANDLING 127 ++ ++#define STP_PSM_WMT_PS_TASK_HANDLING_TIME 30 /* 20 milli-seconds */ ++#define STP_PSM_IDLE_TIME_SLEEP 30 /* temporary for stress testing */ ++#define STP_PSM_IDLE_TIME_SLEEP_1000 1000 /* for high speed transmission e.g. BT OPP*/ ++#define STP_PSM_SDIO_IDLE_TIME_SLEEP 100 /* temporary for SDIO stress testing */ ++#define STP_PSM_WAIT_EVENT_TIMEOUT 6000 ++#if 0 ++#define STP_PSM_WMT_EVENT_SLEEP_EN (0x1UL << 0) ++#define STP_PSM_WMT_EVENT_WAKEUP_EN (0x1UL << 1) ++#define STP_PSM_BLOCK_DATA_EN (0x1UL << 2) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (0x1UL << 3) ++#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (0x1UL << 4) ++#define STP_PSM_RESET_EN (0x1UL << 5) ++#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (0x1UL << 6) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (0x1UL << 7) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (0x1UL << 8) ++#endif ++ ++#define STP_PSM_WMT_EVENT_SLEEP_EN (0) ++#define STP_PSM_WMT_EVENT_WAKEUP_EN (1) ++#define STP_PSM_BLOCK_DATA_EN (2) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (3) ++#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (4) ++#define STP_PSM_RESET_EN (5) ++#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (6) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (7) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (8) ++ ++#define STP_PSM_DBG_SIZE (16) ++ ++/* OP command ring buffer : must be power of 2 */ ++#define STP_OP_BUF_SIZE (16) ++ ++#define PSM_THREAD_NAME "mtk_stp_psm" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum { ++ ACT = 0, ++ ACT_INACT, ++ INACT, ++ INACT_ACT, ++ STP_PSM_MAX_STATE, ++} MTKSTP_PSM_STATE_T; ++ ++typedef enum _ENUM_STP_OPID_T { ++ STP_OPID_PSM_SLEEP = 0, ++ STP_OPID_PSM_WAKEUP, ++ STP_OPID_PSM_HOST_AWAKE, ++ STP_OPID_PSM_EXIT, ++ STP_OPID_PSM_NUM, ++ STP_OPID_PSM_INALID = STP_OPID_PSM_NUM, ++} ENUM_STP_OPID_T, *P_ENUM_STP_OPID_T; ++ ++typedef enum { ++ MON = 0, ++ UNMON, ++} MTKSTP_PSM_MONSTATE_T; ++ ++typedef INT32(*wmt_notify_t) (MTKSTP_PSM_ACTION_T action); ++typedef INT32(*stp_tx_cb_t) (unsigned char *buffer, UINT32 length, UINT8 type); ++ ++typedef OSAL_OP_DAT STP_OP; ++typedef P_OSAL_OP_DAT P_STP_OP; ++ ++typedef struct mtk_stp_psm { ++ OSAL_THREAD PSMd; /* main thread (wmtd) handle */ ++ OSAL_EVENT STPd_event; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[STP_OP_BUF_SIZE]; /* real op instances */ ++ ++ /* OSAL_OP current_active_op; */ ++ /* P_OSAL_OP current_active_op; */ ++ UINT32 last_active_opId; ++ MTKSTP_PSM_STATE_T work_state; /*working state */ ++ OSAL_BIT_OP_VAR flag; ++ ++ /* in normal cases, sleep op is always enabled; ++ * but in error cases, we can't execute sleep cmd, ++ * Eg: FW assert, core dump ++ */ ++ INT32 sleep_en; ++ ++/* OSAL_UNSLEEPABLE_LOCK flagSpinlock; */ ++ INT32 idle_time_to_sleep; ++ OSAL_WAKE_LOCK wake_lock; ++ OSAL_TIMER psm_timer; /*monitor if active */ ++ OSAL_EVENT wait_wmt_q; ++ OSAL_FIFO hold_fifo; ++ OSAL_SLEEPABLE_LOCK hold_fifo_spinlock_global; ++ OSAL_UNSLEEPABLE_LOCK wq_spinlock; ++ OSAL_SLEEPABLE_LOCK stp_psm_lock; ++ INT32 (*wmt_notify)(MTKSTP_PSM_ACTION_T action); ++ INT32 (*stp_tx_cb)(unsigned char *buffer, UINT32 length, UINT8 type); ++ ++ MTK_WCN_BOOL (*is_wmt_quick_ps_support)(VOID); ++ UINT8 out_buf[STP_PSM_TX_SIZE]; ++} MTKSTP_PSM_T; ++ ++typedef struct { ++ UINT32 prev_flag; ++ UINT32 cur_flag; ++ UINT32 line_num; ++ UINT32 package_no; ++ UINT32 sec; ++ UINT32 usec; ++ UINT32 pid; ++} STP_PSM_ENTRY_T; ++ ++typedef struct stp_psm_record { ++ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; ++ UINT32 in; ++ UINT32 out; ++ UINT32 size; ++ OSAL_UNSLEEPABLE_LOCK lock; ++} STP_PSM_RECORD_T; ++ ++typedef struct stp_psm_opid_record { ++ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; ++ UINT32 in; ++ UINT32 out; ++ UINT32 size; ++ OSAL_UNSLEEPABLE_LOCK lock; ++} STP_PSM_OPID_RECORD, *P_STP_PSM_OPID_RECORD; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#define PSM_USE_COUNT_PACKAGE 0 ++ ++#if PSM_USE_COUNT_PACKAGE ++#define MTK_COMBO_PSM_RX_TH_DEFAULT (1600) ++#define MTK_COMBO_PSM_TX_TH_DEFAULT (300) ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir); ++#else ++#define SAMPLE_DURATION 1 /*1 second */ ++#define RTX_SPEED_THRESHOLD 50000 /*50KB/s */ ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*stp-psm external function*/ ++INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); ++INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm); ++ ++INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type); ++INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep); ++struct mtk_stp_psm *stp_psm_init(void); ++INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm); ++MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel); ++INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state); ++MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID); ++ ++INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h +new file mode 100644 +index 000000000000..eaa5ce773e33 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h +@@ -0,0 +1,629 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_CORE_H ++#define _STP_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_exp.h" ++#include "psm_core.h" ++#include "btm_core.h" ++#include "stp_btif.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CFG_STP_CORE_CTX_SPIN_LOCK (0) ++ ++#define WMT_LTE_COEX_FLAG (0x16) ++ ++/*configure using SPINLOCK or just mutex for STP-CORE tx*/ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define CONFIG_POWER_SAVING_SUPPORT ++ ++#ifdef PFX ++#undef PFX ++#endif ++#define PFX "[STP] " ++ ++#define STP_LOG_DBG 4 ++#define STP_LOG_PKHEAD 3 ++#define STP_LOG_INFO 2 ++#define STP_LOG_WARN 1 ++#define STP_LOG_ERR 0 ++ ++extern unsigned int gStpDbgLvl; ++ ++#define STP_DBG_FUNC(fmt, arg...)\ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_INFO) \ ++ osal_dbg_print(PFX "%s:[I] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_WARN) \ ++ osal_warn_print(PFX "%s:[W] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_ERR) \ ++ osal_err_print(PFX "%s:[E] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_TRC_FUNC(f) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#define STP_DUMP_PACKET_HEAD(a, b, c) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_PKHEAD) \ ++ stp_dump_data(a, b, c); \ ++} while (0) ++#define STP_TRACE_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++ ++#define STP_MODE_BIT(x) (0x1UL << x) ++#define MTKSTP_UART_FULL_MODE STP_MODE_BIT(0) ++#define MTKSTP_UART_MAND_MODE STP_MODE_BIT(1) ++#define MTKSTP_BTIF_FULL_MODE STP_MODE_BIT(2) ++#define MTKSTP_BTIF_MAND_MODE STP_MODE_BIT(3) ++#define MTKSTP_SDIO_MODE STP_MODE_BIT(4) ++ ++#define MTKSTP_BUFFER_SIZE (16384) ++ ++/*To check function driver's status by the the interface*/ ++/*Operation definition*/ ++#define OP_FUNCTION_ACTIVE 0 ++ ++/*Driver's status*/ ++#define STATUS_OP_INVALID 0 ++#define STATUS_FUNCTION_INVALID 1 ++ ++#define STATUS_FUNCTION_ACTIVE 31 ++#define STATUS_FUNCTION_INACTIVE 32 ++ ++#define MTKSTP_CRC_SIZE (2) ++#define MTKSTP_HEADER_SIZE (4) ++#define MTKSTP_SEQ_SIZE (8) ++ ++/*#define MTKSTP_WINSIZE (4)*/ ++#define MTKSTP_WINSIZE (7) ++#define MTKSTP_TX_TIMEOUT (180) /*TODO: Baudrate to decide this */ ++#define MTKSTP_RETRY_LIMIT (10) ++ ++#define INDEX_INC(idx) \ ++{ \ ++ idx++; \ ++ idx &= 0x7; \ ++} ++ ++#define INDEX_DEC(idx) \ ++{ \ ++ idx--; \ ++ idx &= 0x7; \ ++} ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef INT32(*IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); ++/* event/signal */ ++typedef INT32(*EVENT_SET) (UINT8 function_type); ++typedef INT32(*EVENT_TX_RESUME) (UINT8 winspace); ++typedef INT32(*FUNCTION_STATUS) (UINT8 type, UINT8 op); ++typedef INT32(*WMT_NOTIFY_FUNC_T) (UINT32 action); ++typedef INT32(*BTM_NOTIFY_WMT_FUNC_T) (INT32); ++ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++typedef OSAL_UNSLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; ++#else ++typedef OSAL_SLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; ++#endif ++ ++typedef struct { ++ /* common interface */ ++ IF_TX cb_if_tx; ++ /* event/signal */ ++ EVENT_SET cb_event_set; ++ EVENT_TX_RESUME cb_event_tx_resume; ++ FUNCTION_STATUS cb_check_funciton_status; ++} mtkstp_callback; ++ ++typedef enum { ++ MTKSTP_SYNC = 0, ++ MTKSTP_SEQ, ++ MTKSTP_ACK, ++ MTKSTP_NAK, ++ MTKSTP_TYPE, ++ MTKSTP_LENGTH, ++ MTKSTP_CHECKSUM, ++ MTKSTP_DATA, ++ MTKSTP_CRC1, ++ MTKSTP_CRC2, ++ MTKSTP_RESYNC1, ++ MTKSTP_RESYNC2, ++ MTKSTP_RESYNC3, ++ MTKSTP_RESYNC4, ++ MTKSTP_FW_MSG, ++} mtkstp_parser_state; ++ ++typedef struct { ++ mtkstp_parser_state state; ++ UINT8 seq; ++ UINT8 ack; ++ UINT8 nak; ++ UINT8 type; ++ UINT16 length; ++ UINT8 checksum; ++ UINT16 crc; ++#if 1 ++ UINT8 wmtsubtype; ++#endif ++} mtkstp_parser_context_struct; ++ ++typedef struct { ++ UINT8 txseq; /* last tx pkt's seq + 1 */ ++ UINT8 txack; /* last tx pkt's ack */ ++ UINT8 rxack; /* last rx pkt's ack */ ++ UINT8 winspace; /* current sliding window size */ ++ UINT8 expected_rxseq; /* last rx pkt's seq + 1 */ ++ UINT8 retry_times; ++} mtkstp_sequence_context_struct; ++ ++typedef struct { ++ /* MTK_WCN_MUTEX mtx; */ ++ OSAL_UNSLEEPABLE_LOCK mtx; ++ UINT8 buffer[MTKSTP_BUFFER_SIZE]; ++ UINT32 read_p; ++ UINT32 write_p; ++} mtkstp_ring_buffer_struct; ++ ++typedef struct { ++ UINT8 inband_rst_set; ++ UINT32 rx_counter; /* size of current processing pkt in rx_buf[] */ ++ UINT8 rx_buf[MTKSTP_BUFFER_SIZE]; /* input buffer of STP, room for current processing pkt */ ++ UINT32 tx_read; /* read ptr of tx_buf[] */ ++ UINT32 tx_write; /* write ptr of tx_buf[] */ ++ UINT8 tx_buf[MTKSTP_BUFFER_SIZE]; /* output buffer of STP */ ++ UINT32 tx_start_addr[MTKSTP_SEQ_SIZE]; /* ptr of each pkt in tx_buf[] */ ++ UINT32 tx_length[MTKSTP_SEQ_SIZE]; /* length of each pkt in tx_buf[] */ ++ mtkstp_ring_buffer_struct ring[MTKSTP_MAX_TASK_NUM]; /* ring buffers for each function driver */ ++ mtkstp_parser_context_struct parser; /* current rx pkt's content */ ++ mtkstp_sequence_context_struct sequence; /* state machine's current status */ ++ /* MTK_WCN_MUTEX stp_mutex; */ ++ /* OSAL_UNSLEEPABLE_LOCK stp_mutex; */ ++ STP_CTX_LOCK stp_mutex; ++ /* MTK_WCN_TIMER tx_timer; // timer for tx timeout handling */ ++ OSAL_TIMER tx_timer; ++ ++ MTKSTP_PSM_T *psm; ++ MTKSTP_BTM_T *btm; ++ UINT8 f_enable; /* default disabled */ ++ UINT8 f_ready; /* default non-ready */ ++ UINT8 f_pending_type; ++ UINT8 f_coredump; /*block tx flag, for now, only when f/w assert happens, we will set this bit on */ ++ UINT8 en_coredump; ++ /* Flag to identify Blueztooth is Bluez/or MTK Stack */ ++ MTK_WCN_BOOL f_bluez; ++ MTK_WCN_BOOL f_dbg_en; ++ MTK_WCN_BOOL f_autorst_en; ++ ++ /* Flag to identify STP by SDIO or UART */ ++ UINT32 f_mode; ++ ++ /* Flag to indicate the last WMT CLOSE */ ++ UINT32 f_wmt_last_close; ++ ++ /* Flag to indicate evt err has triggered assert or not */ ++ UINT32 f_evt_err_assert; ++} mtkstp_context_struct; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_init ++* DESCRIPTION ++* init STP kernel ++* PARAMETERS ++* cb_func [IN] function pointers of system APIs ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_deinit ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_deinit(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_enable ++* DESCRIPTION ++* enable/disable STP ++* PARAMETERS ++* value [IN] 0 = disable, others = enable ++* RETURNS ++* INT32 0 = success, others = error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_enable(INT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_ready ++* DESCRIPTION ++* ready/non-ready STP ++* PARAMETERS ++* value [IN] 0 = non-ready, others = ready ++* RETURNS ++* INT32 0 = success, others = error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_ready(INT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_ctrl ++* DESCRIPTION ++* set f/w assert flag in STP context ++* PARAMETERS ++* value [IN] 0=assert end, others=assert begins ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get f/w assert flag in STP context ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0= f/w assert flag is not set, others=f/w assert flag is set ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_get(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* send raw data to common interface, bypass STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 length transmitted ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_set_sdio_mode ++* DESCRIPTION ++* Set stp for SDIO mode ++* PARAMETERS ++* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_mode(UINT32 sdio_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_fullset_mode ++* DESCRIPTION ++* Is stp use UART Fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:UART Fullset, FALSE:UART Fullset ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_mand_mode ++* DESCRIPTION ++* Is stp use UART Mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:UART Mandatory, FALSE:UART Mandatory ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void); ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_fullset_mode ++* DESCRIPTION ++* Is stp use BTIF Fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Fullset, FALSE:BTIF Fullset ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_mand_mode ++* DESCRIPTION ++* Is stp use BTIF Mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Mandatory, FALSE:BTIF Mandatory ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_sdio_mode ++* DESCRIPTION ++* Is stp use SDIO mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To sync to oringnal stp state with f/w stp ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_inband_reset(void); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To send testing command to chip ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_test_cmd(INT32 no); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To control STP debugging mechanism ++* PARAMETERS ++* func_no: function control, func_op: dumpping filer, func_param: dumpping parameter ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_debug_ctrl(INT32 func_no, INT32 func_op, INT32 func_param); ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush ++* DESCRIPTION ++* flush all stp context ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_flush_context(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_rx_queue ++* DESCRIPTION ++* flush all stp rx queue ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_flush_rx_queue(UINT32 type); ++ ++/***************************************************************************** ++* FUNCTION ++* set stp debugging mdoe ++* DESCRIPTION ++* set stp debugging mdoe ++* PARAMETERS ++* dbg_mode: switch to dbg mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode); ++ ++/***************************************************************************** ++* FUNCTION ++* set stp auto reset mdoe ++* DESCRIPTION ++* set stp auto reset mdoe ++* PARAMETERS ++* auto_rst: switch to auto reset mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst); ++ ++/*stp_psm support*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_notify_stp ++* DESCRIPTION ++* WMT notification to STP that power saving job is done or not ++* PARAMETERS ++* ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_notify_stp(const UINT32 action); ++ ++extern int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_enabla ++* DESCRIPTION ++* enable STP PSM ++* PARAMETERS ++* int idle_time_to_sleep: IDLE time to sleep ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_enable(int idle_time_to_sleep); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_disable ++* DESCRIPTION ++* disable STP PSM ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_disable(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_reset ++* DESCRIPTION ++* reset STP PSM (used on whole chip reset) ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_reset(void); ++extern void stp_do_tx_timeout(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_btm_get_dmp ++* DESCRIPTION ++* get stp dump related information ++* PARAMETERS ++* buffer: dump placement, len: dump size ++* RETURNS ++* 0: Success Negative Value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_btm_get_dmp(char *buf, int *len); ++ ++extern int mtk_wcn_stp_dbg_enable(void); ++ ++extern int mtk_wcn_stp_dbg_disable(void); ++ ++extern void mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type); ++ ++extern int mtk_wcn_sys_if_rx(UINT8 *data, INT32 size); ++ ++extern MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel); ++ ++extern INT32 mtk_wcn_stp_dbg_dump_package(VOID); ++ ++extern int stp_drv_init(void); ++ ++extern void stp_drv_exit(void); ++ ++extern INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on); ++ ++extern INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on); ++ ++extern INT32 mtk_wcn_stp_coredump_flag_get(VOID); ++extern INT32 mtk_wcn_stp_notify_sleep_for_thermal(void); ++ ++extern INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value); ++ ++/*stp btif API declared*/ ++extern INT32 mtk_wcn_stp_open_btif(VOID); ++extern INT32 mtk_wcn_stp_close_btif(VOID); ++extern INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb); ++extern INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len); ++extern INT32 mtk_wcn_stp_wakeup_consys(VOID); ++extern INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); ++extern INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); ++extern INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag); ++extern VOID mtk_wcn_stp_ctx_save(VOID); ++extern VOID mtk_wcn_stp_ctx_restore(VOID); ++extern INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(VOID); ++extern VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value); ++extern UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(VOID); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _STP_CORE_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h +new file mode 100644 +index 000000000000..94b3d8a597ac +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h +@@ -0,0 +1,89 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_WMT_H ++#define _STP_WMT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum { ++ BTM_RST_OP = 0, ++ BTM_DMP_OP = 1, ++ BTM_GET_AEE_SUPPORT_FLAG = 2, ++ BTM_MAX_OP, ++} MTKSTP_BTM_WMT_OP_T; ++ ++typedef enum { ++ SLEEP = 0, ++ HOST_AWAKE, ++ WAKEUP, ++ EIRQ, ++ ROLL_BACK, ++ STP_PSM_MAX_ACTION ++} MTKSTP_PSM_ACTION_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++extern MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op); ++ ++extern INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action); ++extern MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _STP_WMT_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h +new file mode 100644 +index 000000000000..4c64b6b5e65b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CONF_H_ ++#define _WMT_CONF_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CUST_CFG_WMT "WMT_SOC.cfg" ++#define CUST_CFG_WMT_PREFIX "/system/etc/firmware/" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_conf_read_file(VOID); ++P_WMT_GEN_CONF wmt_conf_get_cfg(VOID); ++INT32 wmt_conf_set_cfg_file(const char *name); ++ ++#endif /* _WMT_CONF_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h +new file mode 100644 +index 000000000000..cca52a15cc98 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h +@@ -0,0 +1,428 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CORE_H_ ++#define _WMT_CORE_H_ ++ ++#include "osal.h" ++#include "wmt_ctrl.h" ++#include "wmt_exp.h" ++#include "wmt_plat.h" ++/* TODO: [GeorgeKuo][FixMe] remove temporarily */ ++/* for AIF state definition */ ++/* #include "mtk_wcn_cmb_stub.h" */ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++#define CFG_CORE_MT6620_SUPPORT 0 /* whether MT6620 is supported or not */ ++ ++#define CFG_CORE_MT6628_SUPPORT 0 /* whether MT6628 is supported or not */ ++ ++#define CFG_CORE_SOC_SUPPORT 1 ++ ++/* TODO:[ChangeFeature][George] move this definition outside so that wmt_dev can remove wmt_core.h inclusion. */ ++#define defaultPatchName "mt66xx_patch_hdr.bin" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define BCNT_PATCH_BUF_HEADROOM (8) ++ ++#define DWCNT_HIF_CONF (4) ++#define DWCNT_STRAP_CONF (4) ++#define DWCNT_RESERVED (8) ++#define DWCNT_CTRL_DATA (16) ++ ++#if 0 /* TODO: [obsolete][GeorgeKuo]: remove ubsolete definitions */ ++#define WMT_SET (1) ++#define WMT_QUERY (0) ++#define WMT_PKT_FMT_RAW (1) ++#define WMT_PKT_FMT_STP (0) ++#endif ++ ++#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE) ++#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE) ++ ++#define WMT_HDR_LEN (4) /* header length */ ++#define WMT_STS_LEN (1) /* status length */ ++#define WMT_FLAG_LEN (1) ++#define WMT_HIF_UART_INFO_LEN (4) ++#define WMT_FUNC_CTRL_PARAM_LEN (1) ++ ++#define WMT_DEFAULT_BAUD_RATE (115200) ++ ++#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_WMT_FM_T { ++ WMT_FM_INVALID = 0, ++ WMT_FM_I2C = 1, ++ WMT_FM_COMM = 2, ++ WMT_FM_MAX ++} ENUM_WMT_FM_T, *P_ENUM_WMT_FM_T; ++ ++typedef enum _ENUM_WMT_HIF_T { ++ WMT_HIF_UART = 0, ++ WMT_HIF_SDIO = 1, ++ WMT_HIF_BTIF = 2, ++ WMT_HIF_MAX ++} ENUM_WMT_HIF_T, *P_ENUM_WMT_HIF_T; ++ ++#if 0 /* [George] moved to wmt_exp.h for hif_sdio's use */ ++typedef enum { ++ WMT_SDIO_SLOT_INVALID = 0, ++ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ ++ WMT_SDIO_SLOT_SDIO2 = 2, ++ WMT_SDIO_SLOT_MAX ++} WMT_SDIO_SLOT_NUM; ++ ++typedef enum { ++ WMT_SDIO_FUNC_STP = 0, ++ WMT_SDIO_FUNC_WIFI = 1, ++ WMT_SDIO_FUNC_MAX ++} WMT_SDIO_FUNC_TYPE; ++#endif ++ ++typedef enum _ENUM_WMT_OPID_T { ++ WMT_OPID_HIF_CONF = 0, ++ WMT_OPID_PWR_ON = 1, ++ WMT_OPID_PWR_OFF = 2, ++ WMT_OPID_FUNC_ON = 3, ++ WMT_OPID_FUNC_OFF = 4, ++ WMT_OPID_REG_RW = 5, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++ WMT_OPID_EXIT = 6, ++ WMT_OPID_PWR_SV = 7, ++ WMT_OPID_DSNS = 8, ++ WMT_OPID_LPBK = 9, ++ WMT_OPID_CMD_TEST = 10, ++ WMT_OPID_HW_RST = 11, ++ WMT_OPID_SW_RST = 12, ++ WMT_OPID_BAUD_RST = 13, ++ WMT_OPID_STP_RST = 14, ++ WMT_OPID_THERM_CTRL = 15, ++ WMT_OPID_EFUSE_RW = 16, ++ WMT_OPID_GPIO_CTRL = 17, ++ WMT_OPID_FW_COREDMP = 18, ++ WMT_OPID_GPIO_STATE = 19, ++ WMT_OPID_BGW_DS = 20, ++ WMT_OPID_SET_MCU_CLK = 21, ++ WMT_OPID_ADIE_LPBK_TEST = 22, ++#if CFG_WMT_LTE_COEX_HANDLING ++ WMT_OPID_IDC_MSG_HANDLING = 23, ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++ WMT_OPID_ANT_RAM_DOWN = 24, ++ WMT_OPID_ANT_RAM_STA_GET = 25, ++#endif ++ WMT_OPID_MAX ++} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T; ++ ++typedef OSAL_OP_DAT WMT_OP; ++typedef P_OSAL_OP_DAT P_WMT_OP; ++ ++typedef struct _WMT_HIF_CONF { ++ UINT32 hifType; /* HIF Type */ ++ UINT32 au4HifConf[DWCNT_HIF_CONF]; /* HIF Config */ ++ UINT32 au4StrapConf[DWCNT_STRAP_CONF]; /* Strap Config */ ++} WMT_HIF_CONF, *P_WMT_HIF_CONF; ++ ++typedef INT32(*WMT_OPID_FUNC) (P_WMT_OP); ++ ++typedef struct _WMT_GEN_CONF { ++ UINT8 cfgExist; ++ ++ UINT8 coex_wmt_ant_mode; ++ UINT8 coex_wmt_ext_component; ++ UINT8 coex_wmt_wifi_time_ctl; ++ UINT8 coex_wmt_ext_pta_dev_on; ++ /*mt6592 and LTE coex filter mode setting */ ++ UINT8 coex_wmt_filter_mode; ++ ++ UINT8 coex_bt_rssi_upper_limit; ++ UINT8 coex_bt_rssi_mid_limit; ++ UINT8 coex_bt_rssi_lower_limit; ++ UINT8 coex_bt_pwr_high; ++ UINT8 coex_bt_pwr_mid; ++ UINT8 coex_bt_pwr_low; ++ ++ UINT8 coex_wifi_rssi_upper_limit; ++ UINT8 coex_wifi_rssi_mid_limit; ++ UINT8 coex_wifi_rssi_lower_limit; ++ UINT8 coex_wifi_pwr_high; ++ UINT8 coex_wifi_pwr_mid; ++ UINT8 coex_wifi_pwr_low; ++ ++ UINT8 coex_ext_pta_hi_tx_tag; ++ UINT8 coex_ext_pta_hi_rx_tag; ++ UINT8 coex_ext_pta_lo_tx_tag; ++ UINT8 coex_ext_pta_lo_rx_tag; ++ UINT16 coex_ext_pta_sample_t1; ++ UINT16 coex_ext_pta_sample_t2; ++ UINT8 coex_ext_pta_wifi_bt_con_trx; ++ ++ UINT32 coex_misc_ext_pta_on; ++ UINT32 coex_misc_ext_feature_set; ++ /*GPS LNA setting */ ++ UINT8 wmt_gps_lna_pin; ++ UINT8 wmt_gps_lna_enable; ++ /*Power on sequence */ ++ UINT8 pwr_on_rtc_slot; ++ UINT8 pwr_on_ldo_slot; ++ UINT8 pwr_on_rst_slot; ++ UINT8 pwr_on_off_slot; ++ UINT8 pwr_on_on_slot; ++ UINT8 co_clock_flag; ++ ++ /* Combo chip side SDIO driving setting */ ++ UINT32 sdio_driving_cfg; ++ ++} WMT_GEN_CONF, *P_WMT_GEN_CONF; ++ ++typedef enum _ENUM_DRV_STS_ { ++#if 0 ++ DRV_STS_INVALID = 0, ++ DRV_STS_UNREG = 1, /* Initial State */ ++#endif ++ DRV_STS_POWER_OFF = 0, /* initial state */ ++ DRV_STS_POWER_ON = 1, /* powered on, only WMT */ ++ DRV_STS_FUNC_ON = 2, /* FUNC ON */ ++ DRV_STS_MAX ++} ENUM_DRV_STS, *P_ENUM_DRV_STS; ++ ++typedef enum _WMT_IC_PIN_ID_ { ++ WMT_IC_PIN_AUDIO = 0, ++ WMT_IC_PIN_EEDI = 1, ++ WMT_IC_PIN_EEDO = 2, ++ WMT_IC_PIN_GSYNC = 3, ++ WMT_IC_PIN_MAX ++} WMT_IC_PIN_ID, *P_WMT_IC_PIN_ID; ++ ++typedef enum _WMT_IC_PIN_STATE_ { ++ WMT_IC_PIN_EN = 0, ++ WMT_IC_PIN_DIS = 1, ++ WMT_IC_AIF_0 = 2, /* = CMB_STUB_AIF_0, */ ++ WMT_IC_AIF_1 = 3, /* = CMB_STUB_AIF_1, */ ++ WMT_IC_AIF_2 = 4, /* = CMB_STUB_AIF_2, */ ++ WMT_IC_AIF_3 = 5, /* = CMB_STUB_AIF_3, */ ++ WMT_IC_PIN_MUX = 6, ++ WMT_IC_PIN_GPIO = 7, ++ WMT_IC_PIN_GPIO_HIGH = 8, ++ WMT_IC_PIN_GPIO_LOW = 9, ++ WMT_IC_PIN_STATE_MAX ++} WMT_IC_PIN_STATE, *P_WMT_IC_PIN_STATE; ++ ++typedef enum _WMT_CO_CLOCK_ { ++ WMT_CO_CLOCK_DIS = 0, ++ WMT_CO_CLOCK_EN = 1, ++ WMT_CO_CLOCK_MAX ++} WMT_CO_CLOCK, *P_WMT_CO_CLOCK; ++ ++typedef INT32(*SW_INIT) (P_WMT_HIF_CONF pWmtHifConf); ++typedef INT32(*SW_DEINIT) (P_WMT_HIF_CONF pWmtHifConf); ++typedef INT32(*IC_PIN_CTRL) (WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); ++typedef INT32(*IC_VER_CHECK) (VOID); ++typedef INT32(*CO_CLOCK_CTRL) (WMT_CO_CLOCK on); ++typedef MTK_WCN_BOOL(*IS_QUICK_SLEEP_SUPPORT) (VOID); ++typedef MTK_WCN_BOOL(*IS_AEE_DUMP_SUPPORT) (VOID); ++ ++typedef struct _WMT_IC_OPS_ { ++ UINT32 icId; ++ SW_INIT sw_init; ++ SW_DEINIT sw_deinit; ++ IC_PIN_CTRL ic_pin_ctrl; ++ IC_VER_CHECK ic_ver_check; ++ CO_CLOCK_CTRL co_clock_ctrl; ++ IS_QUICK_SLEEP_SUPPORT is_quick_sleep; ++ IS_AEE_DUMP_SUPPORT is_aee_dump_support; ++} WMT_IC_OPS, *P_WMT_IC_OPS; ++ ++typedef struct _WMT_CTX_ { ++ ENUM_DRV_STS eDrvStatus[WMTDRV_TYPE_MAX]; /* Controlled driver status */ ++ UINT32 wmtInfoBit; /* valid info bit */ ++ WMT_HIF_CONF wmtHifConf; /* HIF information */ ++ ++ /* Pointer to WMT_IC_OPS. Shall be assigned to a correct table in stp_init ++ * if and only if getting chip id successfully. hwver and fwver are kept in ++ * WMT-IC module only. ++ */ ++ P_WMT_IC_OPS p_ic_ops; ++} WMT_CTX, *P_WMT_CTX; ++ ++/* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ ++/* Using this struct relies on compiler's implementation and pack() settings */ ++typedef struct _WMT_PKT_ { ++ UINT8 eType; /* PKT_TYPE_* */ ++ UINT8 eOpCode; /* OPCODE_* */ ++ UINT16 u2SduLen; /* 2 bytes length, little endian */ ++ UINT8 aucParam[32]; ++} WMT_PKT, *P_WMT_PKT; ++ ++/* WMT Packet Format */ ++typedef enum _ENUM_PKT_TYPE { ++ PKT_TYPE_INVALID = 0, ++ PKT_TYPE_CMD = 1, ++ PKT_TYPE_EVENT = 2, ++ _PKT_TYPE_MAX ++} ENUM_PKT_TYPE, *P_ENUM_PKT_TYPE; ++ ++typedef enum _ENUM_OPCODE { ++ OPCODE_INVALID = 0, ++ OPCODE_PATCH = 1, ++ OPCODE_TEST = 2, ++ OPCODE_WAKEUP = 3, ++ OPCODE_HIF = 4, ++ OPCODE_STRAP_CONF = 5, ++ OPCODE_FUNC_CTRL = 6, ++ OPCODE_RESET = 7, ++ OPCODE_INT = 8, ++ OPCODE_MAX ++} ENUM_OPCODE, *P_ENUM_OPCODE; ++ ++typedef enum { ++ WMT_STP_CONF_EN = 0, ++ WMT_STP_CONF_RDY = 1, ++ WMT_STP_CONF_MODE = 2, ++ WMT_STP_CONF_MAX ++} WMT_STP_CONF_TYPE; ++ ++struct init_script { ++ UINT8 *cmd; ++ UINT32 cmdSz; ++ UINT8 *evt; ++ UINT32 evtSz; ++ UINT8 *str; ++}; ++ ++typedef struct _WMT_PATCH { ++ UINT8 ucDateTime[16]; ++ UINT8 ucPLat[4]; ++ UINT16 u2HwVer; ++ UINT16 u2SwVer; ++ UINT32 u4PatchVer; ++} WMT_PATCH, *P_WMT_PATCH; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_CORE_MT6620_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_mt6620; ++#endif ++ ++#if CFG_CORE_MT6628_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_mt6628; ++#endif ++ ++#if CFG_CORE_SOC_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_soc; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern INT32 wmt_core_init(VOID); ++extern INT32 wmt_core_deinit(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmtd ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 wmt_core_opid(P_WMT_OP pWmtOp); ++ ++extern INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2); ++ ++extern INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn); ++ ++extern INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask); ++ ++extern VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len); ++ ++extern MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer); ++ ++extern INT32 wmt_core_init_script(struct init_script *script, INT32 count); ++ ++extern INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize); ++ ++extern INT32 wmt_core_tx(const PUINT8 pData, UINT32 size, PUINT32 writtenSize, MTK_WCN_BOOL bRawFlag); ++extern MTK_WCN_BOOL wmt_core_is_quick_ps_support(void); ++ ++extern MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void); ++ ++#if CFG_CORE_INTERNAL_TXRX ++extern INT32 wmt_core_lpbk_do_stp_init(void); ++extern INT32 wmt_core_lpbk_do_stp_deinit(void); ++#endif ++ ++extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state); ++#if CFG_WMT_LTE_COEX_HANDLING ++extern VOID wmt_core_set_flag_for_test(UINT32 enable); ++extern UINT32 wmt_core_get_flag_for_test(VOID); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static _osal_inline_ MTK_WCN_BOOL wmt_core_ic_ops_check(P_WMT_IC_OPS p_ops) ++{ ++ if (!p_ops) ++ return MTK_WCN_BOOL_FALSE; ++ ++ if ((NULL == p_ops->sw_init) ++ || (NULL == p_ops->sw_deinit) ++ || (NULL == p_ops->ic_ver_check) ++ || (NULL == p_ops->ic_pin_ctrl)) ++ return MTK_WCN_BOOL_FALSE; ++ else ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++#endif /* _WMT_CORE_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h +new file mode 100644 +index 000000000000..0ff3d6058c39 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h +@@ -0,0 +1,120 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CTRL_H_ ++#define _WMT_CTRL_H_ ++ ++#include "osal.h" ++#include "wmt_stp_exp.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define DWCNT_CTRL_DATA (16) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _WMT_CTRL_DATA_ { ++ SIZE_T ctrlId; ++ SIZE_T au4CtrlData[DWCNT_CTRL_DATA]; ++} WMT_CTRL_DATA, *P_WMT_CTRL_DATA; ++ ++typedef enum _ENUM_WMT_CTRL_T { ++ WMT_CTRL_HW_PWR_OFF = 0, /* whole chip power off */ ++ WMT_CTRL_HW_PWR_ON = 1, /* whole chip power on */ ++ WMT_CTRL_HW_RST = 2, /* whole chip rst */ ++ WMT_CTRL_STP_CLOSE = 3, ++ WMT_CTRL_STP_OPEN = 4, ++ WMT_CTRL_STP_CONF = 5, ++ WMT_CTRL_FREE_PATCH = 6, ++ WMT_CTRL_GET_PATCH = 7, ++ WMT_CTRL_GET_PATCH_NAME = 8, ++ WMT_CTRL_HWIDVER_SET = 9, /* TODO: rename this and add chip id information in addition to chip version */ ++ WMT_CTRL_STP_RST = 10, ++ WMT_CTRL_GET_WMT_CONF = 11, ++ WMT_CTRL_TX = 12, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ ++ WMT_CTRL_RX = 13, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ ++ WMT_CTRL_RX_FLUSH = 14, /* [FixMe][SeanWang]: to be removed by Sean's stp integration */ ++ WMT_CTRL_GPS_SYNC_SET = 15, ++ WMT_CTRL_GPS_LNA_SET = 16, ++ WMT_CTRL_PATCH_SEARCH = 17, ++ WMT_CTRL_CRYSTAL_TRIMING_GET = 18, ++ WMT_CTRL_CRYSTAL_TRIMING_PUT = 19, ++ WMT_CTRL_HW_STATE_DUMP = 20, ++ WMT_CTRL_GET_PATCH_NUM = 21, ++ WMT_CTRL_GET_PATCH_INFO = 22, ++ WMT_CTRL_SOC_PALDO_CTRL = 23, ++ WMT_CTRL_SOC_WAKEUP_CONSYS = 24, ++ WMT_CTRL_SET_STP_DBG_INFO = 25, ++ WMT_CTRL_BGW_DESENSE_CTRL = 26, ++ WMT_CTRL_EVT_ERR_TRG_ASSERT = 27, ++#if CFG_WMT_LTE_COEX_HANDLING ++ WMT_CTRL_GET_TDM_REQ_ANTSEL = 28, ++#endif ++ WMT_CTRL_EVT_PARSER = 29, ++ WMT_CTRL_MAX ++} ENUM_WMT_CTRL_T, *P_ENUM_WMT_CTRL_T; ++ ++typedef INT32(*WMT_CTRL_FUNC) (P_WMT_CTRL_DATA); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData); ++ ++extern INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_CTRL_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h +new file mode 100644 +index 000000000000..d586f442e7ef +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h +@@ -0,0 +1,140 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_FUNC_H_ ++#define _WMT_FUNC_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_core.h" ++#include "wmt_plat.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_HCI_DRIVER) || defined(CONFIG_MTK_COMBO_BT) */ ++#define CFG_FUNC_BT_SUPPORT 1 ++#else ++#define CFG_FUNC_BT_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_FM) */ ++#define CFG_FUNC_FM_SUPPORT 1 ++#else ++#define CFG_FUNC_FM_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_GPS) */ ++#define CFG_FUNC_GPS_SUPPORT 1 ++#else ++#define CFG_FUNC_GPS_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_WIFI) */ ++#define CFG_FUNC_WIFI_SUPPORT 1 ++#else ++#define CFG_FUNC_WIFI_SUPPORT 0 ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef INT32(*SUBSYS_FUNC_ON) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++typedef INT32(*SUBSYS_FUNC_OFF) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++typedef struct _WMT_FUNC_OPS_ { ++ SUBSYS_FUNC_ON func_on; ++ SUBSYS_FUNC_OFF func_off; ++} WMT_FUNC_OPS, *P_WMT_FUNC_OPS; ++ ++typedef struct _CMB_PIN_CTRL_REG_ { ++ UINT32 regAddr; ++ UINT32 regValue; ++ UINT32 regMask; ++ ++} CMB_PIN_CTRL_REG, *P_CMB_PIN_CTRL_REG; ++ ++typedef struct _CMB_PIN_CTRL_ { ++ UINT32 pinId; ++ UINT32 regNum; ++ P_CMB_PIN_CTRL_REG pFuncOnArray; ++ P_CMB_PIN_CTRL_REG pFuncOffArray; ++ ++} CMB_PIN_CTRL, *P_CMB_PIN_CTRL; ++ ++typedef enum _ENUM_CMP_PIN_ID_ { ++ CMB_PIN_EEDI_ID = 0, ++ CMB_PIN_EEDO_ID = 1, ++ CMB_PIN_GSYNC_ID = 2, ++} ENUM_CMP_PIN_ID, *P_ENUM_CMP_PIN_ID; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_BT_SUPPORT ++extern WMT_FUNC_OPS wmt_func_bt_ops; ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++extern WMT_FUNC_OPS wmt_func_fm_ops; ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++extern WMT_FUNC_OPS wmt_func_gps_ops; ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++extern WMT_FUNC_OPS wmt_func_wifi_ops; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_FUNC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h +new file mode 100644 +index 000000000000..901becfdb92f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h +@@ -0,0 +1,122 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_IC_H_ ++#define _WMT_IC_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "wmt_core.h" ++#include "wmt_exp.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define WMT_IC_NAME_MT6620 "MT6620" ++#define WMT_IC_NAME_MT6628 "MT6628" ++#define WMT_IC_NAME_DEFAULT "SOC_CONSYS" ++ ++#define WMT_IC_VER_E1 "E1" ++#define WMT_IC_VER_E2 "E2" ++#define WMT_IC_VER_E3 "E3" ++#define WMT_IC_VER_E4 "E4" ++#define WMT_IC_VER_E5 "E5" ++#define WMT_IC_VER_E6 "E6" ++ ++#define WMT_IC_PATCH_DUMMY_EXT "_ex" ++#define WMT_IC_PATCH_NO_EXT "" ++#define WMT_IC_PATCH_E1_EXT "_e1" ++#define WMT_IC_PATCH_E2_EXT "_e2" ++#define WMT_IC_PATCH_E3_EXT "_e3" ++#define WMT_IC_PATCH_E4_EXT "_e4" ++#define WMT_IC_PATCH_E5_EXT "_e5" ++#define WMT_IC_PATCH_E6_EXT "_e6" ++ ++#define WMT_IC_PATCH_TAIL "_hdr.bin" ++ ++#define WMT_IC_INVALID_CHIP_ID 0xFFFF ++ ++#define MAJORNUM(x) (x & 0x00F0) ++#define MINORNUM(x) (x & 0x000F) ++ ++/******************************************************************************* ++* R E G I S T E R M A P ++******************************************************************************** ++*/ ++/* General definition used for ALL/UNKNOWN CHIPS */ ++/* Now MT6620 uses these definitions */ ++#define GEN_CONFG_BASE (0x80000000UL) ++#define GEN_HVR (GEN_CONFG_BASE + 0x0UL) /* HW_VER */ ++#define GEN_FVR (GEN_CONFG_BASE + 0x4UL) /* FW_VER */ ++#define GEN_VER_MASK (0x0000FFFFUL) /* HW_VER and FW_VER valid bits mask */ ++#define GEN_HCR (GEN_CONFG_BASE + 0x8UL) /* HW_CODE, chip id */ ++#define GEN_HCR_MASK (0x0000FFFFUL) /* HW_CODE valid bits mask */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _WMT_IC_INFO_S { ++ UINT32 u4HwVer; /* u4HwId */ ++ PUINT8 cChipName; ++ PUINT8 cChipVersion; ++ PUINT8 cPatchNameExt; ++ MTK_WCN_BOOL bPsmSupport; ++ MTK_WCN_BOOL bWorkWithoutPatch; ++ ENUM_WMTHWVER_TYPE_T eWmtHwVer; ++} WMT_IC_INFO_S, *P_WMT_IC_INFO_S; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_IC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h +new file mode 100644 +index 000000000000..b0c05cf3a252 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h +@@ -0,0 +1,300 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_LIB_H_ ++#define _WMT_LIB_H_ ++ ++#include "osal.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++#include ++#include "stp_wmt.h" ++#include "wmt_plat.h" ++#include "wmt_idc.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define WMT_OP_BUF_SIZE (16) ++ ++typedef enum _ENUM_WMTRSTRET_TYPE_T { ++ WMTRSTRET_SUCCESS = 0x0, ++ WMTRSTRET_FAIL = 0x1, ++ WMTRSTRET_ONGOING = 0x2, ++ WMTRSTRET_MAX ++} ENUM_WMTRSTRET_TYPE_T, *P_ENUM_WMTRSTRET_TYPE_T; ++ ++/* ++3(retry times) * 180 (STP retry time out) +++ 10 (firmware process time) + ++10 (transmit time) + ++10 (uart process -> WMT response pool) + ++230 (others) ++*/ ++#define WMT_LIB_RX_TIMEOUT 20000 /*800-->cover v1.2phone BT function on time (~830ms) */ ++/* ++open wifi during wifi power on procedure ++(because wlan is insert to system after mtk_hif_sdio module, ++so wifi card is not registered to hif module ++when mtk_wcn_wmt_func_on is called by wifi through rfkill) ++*/ ++#define MAX_WIFI_ON_TIME 55000 ++ ++#define WMT_PWRON_RTY_DFT 2 ++#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT) ++#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY WMT_LIB_RX_TIMEOUT /*each WMT command */ ++#define MAX_FUNC_ON_TIME \ ++ (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT + MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3) ++ ++#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ ++#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4) ++ ++#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ ++ ++#define MAX_GPIO_CTRL_TIME (2000) /* [FixMe][GeorgeKuo] a temp value */ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* AIF FLAG definition */ ++/* bit(0): share pin or not */ ++#define WMT_LIB_AIF_FLAG_MASK (0x1UL) ++#define WMT_LIB_AIF_FLAG_SHARE (0x1UL << 0) ++#define WMT_LIB_AIF_FLAG_SEPARATE (0x0UL << 0) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* bit field offset definition */ ++typedef enum { ++ WMT_STAT_PWR = 0, /* is powered on */ ++ WMT_STAT_STP_REG = 1, /* is STP driver registered: */ ++ WMT_STAT_STP_OPEN = 2, /* is STP opened: default FALSE */ ++ WMT_STAT_STP_EN = 3, /* is STP enabled: default FALSE */ ++ WMT_STAT_STP_RDY = 4, /* is STP ready for client: default FALSE */ ++ WMT_STAT_RX = 5, /* is rx data available */ ++ WMT_STAT_CMD = 6, /* is cmd string to be read */ ++ WMT_STAT_RST_ON = 7, ++ WMT_STAT_MAX ++} WMT_STAT; ++ ++typedef enum _ENUM_WMTRSTSRC_TYPE_T { ++ WMTRSTSRC_RESET_BT = 0x0, ++ WMTRSTSRC_RESET_FM = 0x1, ++ WMTRSTSRC_RESET_GPS = 0x2, ++ WMTRSTSRC_RESET_WIFI = 0x3, ++ WMTRSTSRC_RESET_STP = 0x4, ++ WMTRSTSRC_RESET_TEST = 0x5, ++ WMTRSTSRC_RESET_MAX ++} ENUM_WMTRSTSRC_TYPE_T, *P_ENUM_WMTRSTSRC_TYPE_T; ++ ++typedef struct { ++ PF_WMT_CB fDrvRst[4]; ++} WMT_FDRV_CB, *P_WMT_FDRV_CB; ++ ++typedef struct { ++ UINT32 dowloadSeq; ++ UINT8 addRess[4]; ++ UINT8 patchName[256]; ++} WMT_PATCH_INFO, *P_WMT_PATCH_INFO; ++ ++/* OS independent wrapper for WMT_OP */ ++typedef struct _DEV_WMT_ { ++ ++ OSAL_SLEEPABLE_LOCK psm_lock; ++ OSAL_SLEEPABLE_LOCK idc_lock; ++ /* WMTd thread information */ ++ /* struct task_struct *pWmtd; */ ++ OSAL_THREAD thread; /* main thread (wmtd) handle */ ++ /* wait_queue_head_t rWmtdWq; */ ++ OSAL_EVENT rWmtdWq; /*WMTd command wait queue */ ++ /* ULONG state; */ ++ OSAL_BIT_OP_VAR state; /* bit field of WMT_STAT */ ++ ++ /* STP context information */ ++ /* wait_queue_head_t rWmtRxWq; */ ++ OSAL_EVENT rWmtRxWq; /* STP Rx wait queue */ ++ /* WMT_STP_FUNC rStpFunc; */ ++ WMT_FDRV_CB rFdrvCb; /* STP functions */ ++ ++ /* WMT Configurations */ ++ WMT_HIF_CONF rWmtHifConf; ++ WMT_GEN_CONF rWmtGenConf; ++ ++ /* Patch information */ ++ UINT8 cPatchName[NAME_MAX + 1]; ++ UINT8 cFullPatchName[NAME_MAX + 1]; ++ UINT32 patchNum; ++ ++ const osal_firmware *pPatch; ++ ++ UINT8 cWmtcfgName[NAME_MAX + 1]; ++ const osal_firmware *pWmtCfg; ++ ++ const osal_firmware *pNvram; ++ ++ /* Current used UART port description */ ++ INT8 cUartName[NAME_MAX + 1]; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[WMT_OP_BUF_SIZE]; /* real op instances */ ++ P_OSAL_OP pCurOP; /* current op */ ++ ++ /* cmd str buffer */ ++ UINT8 cCmd[NAME_MAX + 1]; ++ INT32 cmdResult; ++ /* struct completion cmd_comp; */ ++ /* wait_queue_head_t cmd_wq; */ ++ OSAL_SIGNAL cmdResp; /* read command queues */ ++ OSAL_EVENT cmdReq; ++ ++ /* WMT loopback Thread Information */ ++ /* WMT_CMB_VER combo_ver; */ ++ /* P_WMT_CMB_CHIP_INFO_S pChipInfo; */ ++ UINT32 chip_id; ++ UINT32 hw_ver; ++ UINT32 fw_ver; ++ /* TODO: [FixMe][GeorgeKuo] remove this translated version code in the */ ++ /* future. Just return the above 3 info to querist */ ++ ENUM_WMTHWVER_TYPE_T eWmtHwVer; ++ ++ P_WMT_PATCH_INFO pWmtPatchInfo; ++} DEV_WMT, *P_DEV_WMT; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern DEV_WMT gDevWmt; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++extern INT32 wmt_lib_init(VOID); ++extern INT32 wmt_lib_deinit(VOID); ++extern INT32 wmt_lib_tx(PUINT8 data, UINT32 size, PUINT32 writtenSize); ++extern INT32 wmt_lib_tx_raw(PUINT8 data, UINT32 size, PUINT32 writtenSize); ++extern INT32 wmt_lib_rx(PUINT8 buff, UINT32 buffLen, PUINT32 readSize); ++extern VOID wmt_lib_flush_rx(VOID); ++ ++#if CFG_WMT_PS_SUPPORT ++extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime); ++extern INT32 wmt_lib_ps_init(VOID); ++extern INT32 wmt_lib_ps_deinit(VOID); ++extern INT32 wmt_lib_ps_enable(VOID); ++extern INT32 wmt_lib_ps_ctrl(UINT32 state); ++ ++extern INT32 wmt_lib_ps_disable(VOID); ++extern VOID wmt_lib_ps_irq_cb(VOID); ++#endif ++extern VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb); ++ ++/* LXOP functions: */ ++extern P_OSAL_OP wmt_lib_get_free_op(VOID); ++extern INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp); ++extern MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp); ++ ++/* extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); */ ++extern UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T type); ++ ++extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID); ++extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID); ++extern INT32 wmt_lib_trigger_cmd_signal(INT32 result); ++extern PUINT8 wmt_lib_get_cmd(VOID); ++extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID); ++extern INT32 wmt_lib_set_patch_name(PUINT8 cPatchName); ++extern INT32 wmt_lib_set_hif(unsigned long hifconf); ++extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID); ++extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID); ++ ++/* GeorgeKuo: replace set_chip_gpio() with more specific ones */ ++#if 0 /* moved to wmt_exp.h */ ++extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ ++#endif ++extern INT32 wmt_lib_host_awake_get(VOID); ++extern INT32 wmt_lib_host_awake_put(VOID); ++extern UINT32 wmt_lib_dbg_level_set(UINT32 level); ++ ++extern INT32 wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++extern INT32 wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src); ++MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst); ++MTK_WCN_BOOL wmt_lib_hw_rst(VOID); ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); ++INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); ++ ++extern INT32 DISABLE_PSM_MONITOR(void); ++extern VOID ENABLE_PSM_MONITOR(void); ++extern INT32 wmt_lib_notify_stp_sleep(void); ++extern void wmt_lib_psm_lock_release(void); ++extern INT32 wmt_lib_psm_lock_aquire(void); ++extern VOID wmt_lib_idc_lock_release(VOID); ++extern INT32 wmt_lib_idc_lock_aquire(VOID); ++extern INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value); ++ ++extern VOID wmt_lib_set_patch_num(UINT32 num); ++extern VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo); ++extern INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp); ++extern P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev); ++extern PUINT8 wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, PUINT8 buff, UINT32 len); ++extern INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee); ++extern PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 len); ++extern INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl); ++extern UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en); ++extern INT8 wmt_lib_co_clock_get(VOID); ++extern UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver); ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++extern MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor); ++#endif ++#if CFG_WMT_PS_SUPPORT ++extern UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en); ++#endif ++#if CONSYS_ENALBE_SET_JTAG ++extern UINT32 wmt_lib_jtag_flag_set(UINT32 en); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_LIB_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c +new file mode 100644 +index 000000000000..f37da4761009 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c +@@ -0,0 +1,1889 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "psm_core.h" ++#include "stp_core.h" ++#include ++ ++INT32 gPsmDbgLevel = STP_PSM_LOG_INFO; ++MTKSTP_PSM_T stp_psm_i; ++MTKSTP_PSM_T *stp_psm = &stp_psm_i; ++ ++STP_PSM_RECORD_T *g_stp_psm_dbg = NULL; ++static UINT32 g_record_num; ++ ++P_STP_PSM_OPID_RECORD g_stp_psm_opid_dbg = NULL; ++static UINT32 g_opid_record_num; ++ ++#define STP_PSM_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) \ ++ pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ ++ pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_INFO) \ ++ pr_debug(PFX_PSM "[I]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_WARN) \ ++ pr_warn(PFX_PSM "[W]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_ERR) \ ++ pr_err(PFX_PSM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define STP_PSM_TRC_FUNC(f) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ ++ pr_debug(PFX_PSM "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); ++static INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); ++static INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); ++static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num); ++static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg); ++ ++static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num); ++static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg); ++ ++static const char *g_psm_state[STP_PSM_MAX_STATE] = { ++ "ACT", ++ "ACT_INACT", ++ "INACT", ++ "INACT_ACT" ++}; ++ ++static const char *g_psm_action[STP_PSM_MAX_ACTION] = { ++ "SLEEP", ++ "HOST_AWAKE", ++ "WAKEUP", ++ "EIRQ", ++ "ROLL_BACK" ++}; ++ ++static const char *g_psm_op_name[STP_OPID_PSM_NUM] = { ++ "STP_OPID_PSM_SLEEP", ++ "STP_OPID_PSM_WAKEUP", ++ "STP_OPID_PSM_HOST_AWAKE", ++ "STP_OPID_PSM_EXIT" ++}; ++ ++static int _stp_psm_release_data(MTKSTP_PSM_T *stp_psm); ++ ++static inline int _stp_psm_get_state(MTKSTP_PSM_T *stp_psm); ++ ++static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ); ++ ++static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ); ++static MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID); ++ ++MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel) ++{ ++ if (dbglevel <= 4) { ++ gPsmDbgLevel = dbglevel; ++ STP_PSM_INFO_FUNC("gPsmDbgLevel = %d\n", gPsmDbgLevel); ++ return true; ++ } ++ STP_PSM_INFO_FUNC("invalid psm debug level. gPsmDbgLevel = %d\n", gPsmDbgLevel); ++ ++ return false; ++} ++ ++static INT32 _stp_psm_handler(MTKSTP_PSM_T *stp_psm, P_STP_OP pStpOp) ++{ ++ INT32 ret = -1; ++ ++ /* if (NULL == pStpOp) */ ++ /* { */ ++ /* return -1; */ ++ /* } */ ++ ret = _stp_psm_thread_lock_aquire(stp_psm); ++ if (ret) { ++ STP_PSM_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ switch (pStpOp->opId) { ++ case STP_OPID_PSM_EXIT: ++ /* TODO: clean all up? */ ++ ret = 0; ++ break; ++ ++ case STP_OPID_PSM_SLEEP: ++ if (stp_psm_check_sleep_enable(stp_psm) > 0) ++ ret = _stp_psm_notify_wmt(stp_psm, SLEEP); ++ else ++ STP_PSM_INFO_FUNC("cancel sleep request\n"); ++ ++ break; ++ ++ case STP_OPID_PSM_WAKEUP: ++ ret = _stp_psm_notify_wmt(stp_psm, WAKEUP); ++ break; ++ ++ case STP_OPID_PSM_HOST_AWAKE: ++ ret = _stp_psm_notify_wmt(stp_psm, HOST_AWAKE); ++ break; ++ ++ default: ++ STP_PSM_ERR_FUNC("invalid operation id (%d)\n", pStpOp->opId); ++ ret = -1; ++ break; ++ } ++ _stp_psm_thread_lock_release(stp_psm); ++ return ret; ++} ++ ++static P_OSAL_OP _stp_psm_get_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ ++ if (!pOpQ) { ++ STP_PSM_WARN_FUNC("pOpQ == NULL\n"); ++ return NULL; ++ } ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) { ++ /* stp_psm->current_active_op = pOp; */ ++ stp_psm->last_active_opId = pOp->op.opId; ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) ++ STP_PSM_DBG_FUNC("last_active_opId(%d)\n", stp_psm->last_active_opId); ++ ++ if (!pOp) ++ STP_PSM_WARN_FUNC("RB_GET fail\n"); ++ ++ return pOp; ++} ++ ++static INT32 _stp_psm_dump_active_q(P_OSAL_OP_Q pOpQ) ++{ ++ UINT32 read_idx; ++ UINT32 write_idx; ++ UINT32 opId; ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ read_idx = stp_psm->rActiveOpQ.read; ++ write_idx = stp_psm->rActiveOpQ.write; ++ ++ STP_PSM_DBG_FUNC("Active op list:++\n"); ++ while ((read_idx & RB_MASK(pOpQ)) != (write_idx & RB_MASK(pOpQ))) { ++ opId = pOpQ->queue[read_idx & RB_MASK(pOpQ)]->op.opId; ++ if (opId < STP_OPID_PSM_NUM) ++ STP_PSM_DBG_FUNC("%s\n", g_psm_op_name[opId]); ++ else ++ STP_PSM_WARN_FUNC("Unknown OP Id\n"); ++ ++ ++read_idx; ++ } ++ STP_PSM_DBG_FUNC("Active op list:--\n"); ++ } else { ++ STP_PSM_DBG_FUNC("%s: not active queue, dont dump\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ) ++{ ++ unsigned int opId = 0; ++ unsigned int prev_opId = 0; ++ ++ /* if((pOpQ == &stp_psm->rActiveOpQ) && (NULL != stp_psm->current_active_op)) */ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (STP_OPID_PSM_INALID != stp_psm->last_active_opId)) { ++ opId = pOp->op.opId; ++ ++ if (opId == STP_OPID_PSM_SLEEP) { ++ if (RB_EMPTY(pOpQ)) { ++ /* prev_opId = stp_psm->current_active_op->op.opId; */ ++ prev_opId = stp_psm->last_active_opId; ++ } else { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ } ++ ++ if (prev_opId == STP_OPID_PSM_SLEEP) { ++ STP_PSM_DBG_FUNC("redundant sleep opId found\n"); ++ return 1; ++ } else { ++ return 0; ++ } ++ } else { ++ if (RB_EMPTY(pOpQ)) { ++ /* prev_opId = stp_psm->current_active_op->op.opId; */ ++ prev_opId = stp_psm->last_active_opId; ++ } else { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ } ++ ++ if (((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_WAKEUP)) || ++ ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_WAKEUP)) || ++ ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) || ++ ((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) ++ ) { ++ STP_PSM_DBG_FUNC("redundant opId found, opId(%d), preOpid(%d)\n", opId, prev_opId); ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++ } else { ++ return 0; ++ } ++ ++} ++ ++static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ) ++{ ++ unsigned int prev_opId = 0; ++ unsigned int prev_prev_opId = 0; ++ ++ P_OSAL_OP pOp; ++ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ /* sleep , wakeup | sleep, --> null | sleep (x) */ ++ /* wakeup , sleep , wakeup | sleep --> wakeup | sleep (v) */ ++ /* sleep , wakeup , sleep | wakeup --> sleep | wakeup (v) */ ++ /* xxx, sleep | sleep --> xxx, sleep (v) */ ++ /* xxx, wakeup | wakeup --> xxx, wakeup (v) */ ++ /* xxx, awake | awake --> xxx, awake (v) --> should never happen */ ++ while (RB_COUNT(pOpQ) > 2) { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ prev_prev_opId = pOpQ->queue[(pOpQ->write - 2) & RB_MASK(pOpQ)]->op.opId; ++ ++ if ((prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_WAKEUP) || ++ (prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE) || ++ (prev_opId == STP_OPID_PSM_WAKEUP && prev_prev_opId == STP_OPID_PSM_SLEEP) || ++ (prev_opId == STP_OPID_PSM_HOST_AWAKE && prev_prev_opId == STP_OPID_PSM_SLEEP) ++ ) { ++ RB_GET(pOpQ, pOp); ++ RB_PUT(pFreeOpQ, pOp); ++ RB_GET(pOpQ, pOp); ++ RB_PUT(pFreeOpQ, pOp); ++ } else if (prev_opId == prev_prev_opId) { ++ RB_GET(pOpQ, pOp); ++ STP_PSM_DBG_FUNC("redundant opId(%d) found, remove it\n", pOp->op.opId); ++ RB_PUT(pFreeOpQ, pOp); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static INT32 _stp_psm_put_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 ret; ++ ++ /* if (!pOpQ || !pOp) */ ++ /* { */ ++ /* STP_PSM_WARN_FUNC("pOpQ = 0x%p, pLxOp = 0x%p\n", pOpQ, pOp); */ ++ /* return 0; */ ++ /* } */ ++ ret = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* acquire lock success */ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ if (!_stp_psm_is_redundant_active_op(pOp, pOpQ)) { ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) { ++ RB_PUT(pOpQ, pOp); ++ STP_PSM_DBG_FUNC("opId(%d) enqueue\n", pOp->op.opId); ++ } else { ++ STP_PSM_INFO_FUNC("************ Active Queue Full ************\n"); ++ ret = -1; ++ } ++ ++ _stp_psm_clean_up_redundant_active_op(pOpQ); ++ } else { ++ /*redundant opId, mark ret as success */ ++ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; ++ ++ if (!RB_FULL(pFreeOpQ)) ++ RB_PUT(pFreeOpQ, pOp); ++ else ++ osal_assert(!RB_FULL(pFreeOpQ)); ++ ++ ret = 0; ++ } ++ } else { ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ ret = -1; ++ ++ } ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) ++ _stp_psm_dump_active_q(&stp_psm->rActiveOpQ); ++ ++ ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ STP_PSM_DBG_FUNC("stp_psm do unlock,active queue? (%s)\n", (pOpQ == &stp_psm->rActiveOpQ) ? "y" : "n"); ++ ++ if (ret) { ++ STP_PSM_WARN_FUNC("RB_FULL, RB_COUNT=%d , RB_SIZE=%d\n", RB_COUNT(pOpQ), RB_SIZE(pOpQ)); ++ return 0; ++ } else ++ return 1; ++ ++} ++ ++P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ ++ if (stp_psm) { ++ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, sizeof(pOp->op)); ++ ++ return pOp; ++ } else ++ return NULL; ++ ++} ++ ++INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp) ++{ ++ INT32 bRet = 0; /* MTK_WCN_BOOL_FALSE; */ ++ INT32 bCleanup = 0; /* MTK_WCN_BOOL_FALSE; */ ++ INT32 wait_ret = -1; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ do { ++ if (!stp_psm || !pOp) { ++ STP_PSM_ERR_FUNC("stp_psm = %p, pOp = %p\n", stp_psm, pOp); ++ break; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(&pOp->signal); ++ } ++ ++ /* put to active Q */ ++ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rActiveOpQ, pOp); ++ ++ if (0 == bRet) { ++ STP_PSM_WARN_FUNC("+++++++++++ Put op Active queue Fail\n"); ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ break; ++ } ++ _stp_psm_opid_dbg_dmp_in(g_stp_psm_opid_dbg, pOp->op.opId, __LINE__); ++ ++ /* wake up wmtd */ ++ osal_trigger_event(&stp_psm->STPd_event); ++ ++ if (pSignal->timeoutValue == 0) { ++ bRet = 1; /* MTK_WCN_BOOL_TRUE; */ ++ /* clean it in wmtd */ ++ break; ++ } ++ ++ /* wait result, clean it here */ ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ ++ /* check result */ ++ wait_ret = osal_wait_for_signal_timeout(&pOp->signal); ++ STP_PSM_DBG_FUNC("wait completion:%d\n", wait_ret); ++ if (!wait_ret) { ++ STP_PSM_ERR_FUNC("wait completion timeout\n"); ++ /* TODO: how to handle it? retry? */ ++ } else { ++ if (pOp->result) ++ STP_PSM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); ++ /* op completes, check result */ ++ bRet = (pOp->result) ? 0 : 1; ++ } ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp); ++ if (bRet == 0) ++ STP_PSM_WARN_FUNC("+++++++++++ Put op active free fail, maybe disable/enable psm\n"); ++ } ++ ++ return bRet; ++} ++ ++static INT32 _stp_psm_wait_for_msg(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ ++ STP_PSM_DBG_FUNC("%s: stp_psm->rActiveOpQ = %d\n", __func__, RB_COUNT(&stp_psm->rActiveOpQ)); ++ ++ return (!RB_EMPTY(&stp_psm->rActiveOpQ)) || osal_thread_should_stop(&stp_psm->PSMd); ++} ++ ++static INT32 _stp_psm_proc(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ P_OSAL_OP pOp; ++ UINT32 id; ++ INT32 result; ++ ++ if (!stp_psm) { ++ STP_PSM_WARN_FUNC("!stp_psm\n"); ++ return -1; ++ } ++/* STP_PSM_INFO_FUNC("wmtd starts running: pWmtDev(0x%p) [pol, rt_pri, n_pri, pri]=[%d, %d, %d, %d]\n", */ ++/* stp_psm, current->policy, current->rt_priority, current->normal_prio, current->prio); */ ++ ++ for (;;) { ++ ++ pOp = NULL; ++ ++ osal_wait_for_event(&stp_psm->STPd_event, _stp_psm_wait_for_msg, (void *)stp_psm); ++ ++ /* we set reset flag when calling stp_reset after cleanup all op. */ ++ if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_RESET_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ if (osal_thread_should_stop(&stp_psm->PSMd)) { ++ STP_PSM_INFO_FUNC("should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rActiveOpQ); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("+++++++++++ Get op from activeQ fail, maybe disable/enable psm\n"); ++ continue; ++ } ++ ++ id = osal_op_get_id(pOp); ++ ++ if (id >= STP_OPID_PSM_NUM) { ++ STP_PSM_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ result = -1; ++ goto handler_done; ++ } ++ ++ result = _stp_psm_handler(stp_psm, &pOp->op); ++ ++handler_done: ++ ++ if (result) { ++ STP_PSM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, ++ (id >= 4) ? ("???") : (g_psm_op_name[id]), result); ++ } ++ ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, result); ++ else { ++ /* put Op back to freeQ */ ++ if (_stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp) == 0) ++ STP_PSM_WARN_FUNC("+++++++++++ Put op to FreeOpQ fail, maybe disable/enable psm\n"); ++ } ++ ++ if (STP_OPID_PSM_EXIT == id) ++ break; ++ } ++ STP_PSM_INFO_FUNC("exits\n"); ++ ++ return 0; ++}; ++ ++static inline INT32 _stp_psm_get_time(void) ++{ ++ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) ++ osal_printtimeofday(">>>"); ++ ++ return 0; ++} ++ ++static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (stp_psm->work_state < STP_PSM_MAX_STATE) ++ return stp_psm->work_state; ++ STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); ++ ++ return STP_PSM_OPERATION_FAIL; ++} ++ ++static inline INT32 _stp_psm_set_state(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_STATE_T state) ++{ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (stp_psm->work_state < STP_PSM_MAX_STATE) { ++ _stp_psm_get_time(); ++ /* STP_PSM_INFO_FUNC("work_state = %s --> %s\n", ++ * g_psm_state[stp_psm->work_state], g_psm_state[state]); ++ */ ++ ++ stp_psm->work_state = state; ++ if (stp_psm->work_state != ACT) { ++ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ osal_set_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ } ++ } else ++ STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); ++ ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_DBG_FUNC("STP-PSM DISABLE, DONT restart monitor!\n\r"); ++ return STP_PSM_OPERATION_SUCCESS; ++ } ++ ++ STP_PSM_LOUD_FUNC("start monitor\n"); ++ osal_timer_modify(&stp_psm->psm_timer, stp_psm->idle_time_to_sleep); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_stop_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_DBG_FUNC("stop monitor\n"); ++ osal_timer_stop_sync(&stp_psm->psm_timer); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++INT32 _stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) ++{ ++ INT32 available_space = 0; ++ INT32 needed_space = 0; ++ UINT8 delimiter[] = { 0xbb, 0xbb }; ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ available_space = STP_PSM_FIFO_SIZE - osal_fifo_len(&stp_psm->hold_fifo); ++ needed_space = len + sizeof(UINT8) + sizeof(UINT32) + 2; ++ ++ /* STP_PSM_INFO_FUNC("*******FIFO Available(%d), Need(%d)\n", available_space, needed_space); */ ++ ++ if (available_space < needed_space) { ++ STP_PSM_ERR_FUNC("FIFO Available!! Reset FIFO\n"); ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ } ++ /* type */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); ++ /* length */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); ++ /* buffer */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) buffer, len); ++ /* delimiter */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); ++ ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ return len; ++ ++} ++ ++INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return osal_fifo_len(&stp_psm->hold_fifo); ++} ++ ++INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 i = 20; /*Max buffered packet number */ ++ INT32 ret = 0; ++ UINT8 type = 0; ++ UINT32 len = 0; ++ UINT8 delimiter[2]; ++ ++ /* STP_PSM_ERR_FUNC("++++++++++release data++len=%d\n", osal_fifo_len(&stp_psm->hold_fifo)); */ ++ while (osal_fifo_len(&stp_psm->hold_fifo) && i > 0) { ++ /* acquire spinlock */ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); ++ ++ if (len > STP_PSM_PACKET_SIZE_MAX) { ++ STP_PSM_ERR_FUNC("***psm packet's length too Long!****\n"); ++ STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); ++ } else { ++ osal_memset(stp_psm->out_buf, 0, STP_PSM_TX_SIZE); ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) stp_psm->out_buf, len); ++ } ++ ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); ++ ++ if (delimiter[0] == 0xbb && delimiter[1] == 0xbb) { ++ /* osal_buffer_dump(stp_psm->out_buf, "psm->out_buf", len, 32); */ ++ stp_send_data_no_ps(stp_psm->out_buf, len, type); ++ } else { ++ STP_PSM_ERR_FUNC("***psm packet fifo parsing fail****\n"); ++ STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); ++ ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ } ++ i--; ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ } ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_host_awake_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_HOST_AWAKE; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ ++ STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 0; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_wakeup_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_WAKEUP; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ if (0 == bRet) { ++ STP_PSM_WARN_FUNC("OPID(%d) type(%zd) bRet(%s)\n\n", ++ pOp->op.opId, pOp->op.au4OpData[0], "fail"); ++ } ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : (STP_PSM_OPERATION_SUCCESS); ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_sleep_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag)) ++ return 0; ++#if PSM_USE_COUNT_PACKAGE ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag)) ++ return 0; ++#endif ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) ++ return 0; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_SLEEP; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ ++ STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 1; ++ ++ return retval; ++} ++ ++/*internal function*/ ++ ++static inline INT32 _stp_psm_reset(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 i = 0; ++ P_OSAL_OP_Q pOpQ; ++ P_OSAL_OP pOp; ++ ++ STP_PSM_DBG_FUNC("PSM MODE RESET=============================>\n\r"); ++ ++ STP_PSM_DBG_FUNC("_stp_psm_reset\n"); ++ STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_unlock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ /* --> disable psm <--// */ ++ stp_psm->flag.data = 0; ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_stop_monitor(stp_psm); ++ ++ /* --> prepare the op list <--// */ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); ++ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); ++ ++ /* stp_psm->current_active_op = NULL; */ ++ stp_psm->last_active_opId = STP_OPID_PSM_INALID; ++ ++ pOpQ = &stp_psm->rFreeOpQ; ++ for (i = 0; i < STP_OP_BUF_SIZE; i++) { ++ if (!RB_FULL(pOpQ)) { ++ pOp = &stp_psm->arQue[i]; ++ RB_PUT(pOpQ, pOp); ++ } ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ /* --> clean up interal data structure<--// */ ++ _stp_psm_set_state(stp_psm, ACT); ++ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ /* --> stop psm thread wait <--// */ ++ osal_set_bit(STP_PSM_RESET_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ ++ STP_PSM_DBG_FUNC("PSM MODE RESET<============================\n\r"); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static INT32 _stp_psm_wait_wmt_event(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ ++ STP_PSM_DBG_FUNC("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data); ++ ++ return (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)); ++} ++ ++static inline INT32 _stp_psm_wait_wmt_event_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 retval = 0; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ osal_wait_for_event_timeout(&stp_psm->wait_wmt_q, _stp_psm_wait_wmt_event, (void *)stp_psm); ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ /* STP send data here: STP enqueue data to psm buffer. */ ++ _stp_psm_release_data(stp_psm); ++ /* STP send data here: STP enqueue data to psm buffer. We release packet by the next one. */ ++ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* STP send data here: STP sends data directly without PSM. */ ++ _stp_psm_set_state(stp_psm, ACT); ++/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ ++ if (stp_psm_is_quick_ps_support()) ++ stp_psm_notify_wmt_sleep(stp_psm); ++ else ++ _stp_psm_start_monitor(stp_psm); ++ } else if (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_set_state(stp_psm, INACT); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle++\n"); ++ mt_combo_plt_enter_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle--\n"); ++ ++ STP_PSM_DBG_FUNC("sleep-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_unlock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("sleep-wake_lock#(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ } else if (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ if (_stp_psm_get_state(stp_psm) == ACT_INACT) { ++ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ _stp_psm_release_data(stp_psm); ++ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_set_state(stp_psm, ACT); ++ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ } else if (_stp_psm_get_state(stp_psm) == INACT_ACT) { ++ _stp_psm_set_state(stp_psm, INACT); ++ STP_PSM_INFO_FUNC("[WARNING]PSM state rollback due too wakeup fail\n"); ++ } ++ } else if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } else { ++ STP_PSM_ERR_FUNC("flag = %ld<== Abnormal flag be set!!\n\r", stp_psm->flag.data); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ wcn_psm_flag_trigger_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ } ++ retval = STP_PSM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ ++ INT32 retval = 0; ++ ++ if (action == EIRQ) { ++ STP_PSM_DBG_FUNC("Call _stp_psm_notify_wmt_host_awake_wq\n\r"); ++ ++ _stp_psm_notify_wmt_host_awake_wq(stp_psm); ++ ++ return STP_PSM_OPERATION_FAIL; ++ } ++ ++ if ((_stp_psm_get_state(stp_psm) < STP_PSM_MAX_STATE) && (_stp_psm_get_state(stp_psm) >= 0)) { ++ STP_PSM_DBG_FUNC("state = %s, action=%s\n\r", g_psm_state[_stp_psm_get_state(stp_psm)], ++ g_psm_action[action]); ++ } ++ /* If STP trigger WAKEUP and SLEEP, to do the job below */ ++ switch (_stp_psm_get_state(stp_psm)) { ++ /* stp trigger */ ++ case ACT_INACT: ++ ++ if (action == SLEEP) { ++ STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, ready to INACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == ROLL_BACK) { ++ STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, back to ACT\n\r", g_psm_action[action]); ++ /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */ ++ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else { ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, ACT_INACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ } ++ break; ++ /* stp trigger */ ++ ++ case INACT_ACT: ++ ++ if (action == WAKEUP) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == HOST_AWAKE) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == ROLL_BACK) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, back to INACT\n\r", g_psm_action[action]); ++ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else { ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, INACT_ACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ } ++ break; ++ ++ case INACT: ++ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, INACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = -1; ++ ++ break; ++ ++ case ACT: ++ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, ACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ ++ default: ++ ++ /*invalid */ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, Invalid state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ } ++ ++ return retval; ++ ++} ++ ++static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ switch (_stp_psm_get_state(stp_psm)) { ++ case ACT: ++ ++ if (action == SLEEP) { ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_ERR_FUNC("psm monitor disabled, can't do sleep op\n"); ++ return STP_PSM_OPERATION_FAIL; ++ } ++ ++ _stp_psm_set_state(stp_psm, ACT_INACT); ++ ++ _stp_psm_release_data(stp_psm); ++ ++ if (stp_psm->wmt_notify) { ++ stp_psm->wmt_notify(SLEEP); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == WAKEUP || action == HOST_AWAKE) { ++ STP_PSM_INFO_FUNC("In ACT state, dont do WAKEUP/HOST_AWAKE again\n"); ++ _stp_psm_release_data(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ ++ } ++ ++ break; ++ ++ case INACT: ++ ++ if (action == WAKEUP) { ++ _stp_psm_set_state(stp_psm, INACT_ACT); ++ ++ if (stp_psm->wmt_notify) { ++ STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); ++ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); ++ ++ stp_psm->wmt_notify(WAKEUP); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == HOST_AWAKE) { ++ _stp_psm_set_state(stp_psm, INACT_ACT); ++ ++ if (stp_psm->wmt_notify) { ++ STP_PSM_DBG_FUNC("host awake +wake_lock(%d)\n", ++ osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("host awake +wake_lock(%d)#\n", ++ osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); ++ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); ++ ++ stp_psm->wmt_notify(HOST_AWAKE); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == SLEEP) { ++ STP_PSM_INFO_FUNC("In INACT state, dont do SLEEP again\n"); ++ } else { ++ STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ ++ break; ++ ++ default: ++ ++ /*invalid */ ++ STP_PSM_ERR_FUNC("invalid state, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ } ++ return ret; ++} ++ ++static inline void _stp_psm_stp_is_idle(unsigned long data) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) data; ++ ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_DBG_FUNC("STP-PSM DISABLE!\n"); ++ return; ++ } ++ ++ if (1 == _stp_psm_notify_wmt_sleep_wq(stp_psm)) ++ STP_PSM_INFO_FUNC("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep); ++} ++ ++static inline INT32 _stp_psm_init_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_INFO_FUNC("init monitor\n"); ++ ++ stp_psm->psm_timer.timeoutHandler = _stp_psm_stp_is_idle; ++ stp_psm->psm_timer.timeroutHandlerData = (unsigned long)stp_psm; ++ osal_timer_create(&stp_psm->psm_timer); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_deinit_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_INFO_FUNC("deinit monitor\n"); ++ ++ osal_timer_stop_sync(&stp_psm->psm_timer); ++ ++ return 0; ++} ++ ++static inline INT32 _stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 iRet = -1; ++ ++/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ ++ if (osal_test_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag)) ++ iRet = 1; ++ else ++ iRet = 0; ++ ++/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ return iRet; ++} ++ ++static inline INT32 _stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) ++ return 1; ++ else ++ return 0; ++} ++ ++static inline INT32 _stp_psm_do_wait(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) ++{ ++ ++#define POLL_WAIT 20 /* 200 */ ++#define POLL_WAIT_TIME 2000 ++ ++ INT32 i = 0; ++ INT32 limit = POLL_WAIT_TIME / POLL_WAIT; ++ ++ while (_stp_psm_get_state(stp_psm) != state && i < limit) { ++ osal_sleep_ms(POLL_WAIT); ++ i++; ++ STP_PSM_INFO_FUNC("STP is waiting state for %s, i=%d, state = %d\n", g_psm_state[state], i, ++ _stp_psm_get_state(stp_psm)); ++ } ++ ++ if (i == limit) { ++ STP_PSM_WARN_FUNC("-Wait for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); ++ _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg); ++ return STP_PSM_OPERATION_FAIL; ++ } ++ STP_PSM_DBG_FUNC("+Total waits for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); ++ /* _stp_psm_dbg_out_printk(g_stp_psm_opid_dbg); */ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 ret = 0; ++ INT32 retry = 10; ++ P_OSAL_OP_Q pOpQ; ++ P_OSAL_OP pOp; ++ ++ STP_PSM_LOUD_FUNC("*** Do Force Wakeup!***\n\r"); ++ ++ /* <1>If timer is active, we will stop it. */ ++ _stp_psm_stop_monitor(stp_psm); ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ pOpQ = &stp_psm->rFreeOpQ; ++ ++ while (!RB_EMPTY(&stp_psm->rActiveOpQ)) { ++ RB_GET(&stp_psm->rActiveOpQ, pOp); ++ if (NULL != pOp && !RB_FULL(pOpQ)) { ++ STP_PSM_DBG_FUNC("opid = %d\n", pOp->op.opId); ++ RB_PUT(pOpQ, pOp); ++ } else { ++ STP_PSM_ERR_FUNC("clear up active queue fail, freeQ full\n"); ++ } ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* <5>We issue wakeup request into op queue. and wait for active. */ ++ do { ++ ret = _stp_psm_notify_wmt_wakeup_wq(stp_psm); ++ ++ if (ret == STP_PSM_OPERATION_SUCCESS) { ++ ret = _stp_psm_do_wait(stp_psm, ACT); ++ ++ /* STP_PSM_INFO_FUNC("<< wait ret = %d, num of activeQ = %d\n", ++ * ret, RB_COUNT(&stp_psm->rActiveOpQ)); ++ */ ++ if (ret == STP_PSM_OPERATION_SUCCESS) ++ break; ++ } else ++ STP_PSM_ERR_FUNC("_stp_psm_notify_wmt_wakeup_wq fail!!\n"); ++ ++ /* STP_PSM_INFO_FUNC("retry = %d\n", retry); */ ++ retry--; ++ ++ if (retry == 0) ++ break; ++ } while (1); ++ ++ if (retry == 0) ++ return STP_PSM_OPERATION_FAIL; ++ else ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_DBG_FUNC("PSM Disable start\n\r"); ++ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ ret = _stp_psm_do_wakeup(stp_psm); ++ if (ret == STP_PSM_OPERATION_SUCCESS) ++ STP_PSM_DBG_FUNC("PSM Disable Success\n"); ++ else ++ STP_PSM_ERR_FUNC("***PSM Disable Fail***\n"); ++ ++ return ret; ++} ++ ++static inline INT32 _stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) ++{ ++ INT32 ret = STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_LOUD_FUNC("PSM Enable start\n\r"); ++ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ ++ ret = _stp_psm_do_wakeup(stp_psm); ++ if (ret == STP_PSM_OPERATION_SUCCESS) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm->idle_time_to_sleep = idle_time_to_sleep; ++ ++ if (osal_wake_lock_count(&stp_psm->wake_lock) == 0) { ++ STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ } ++ ++ _stp_psm_start_monitor(stp_psm); ++ ++ STP_PSM_DBG_FUNC("PSM Enable succeed\n\r"); ++ } else ++ STP_PSM_ERR_FUNC("***PSM Enable Fail***\n"); ++ ++ return ret; ++} ++ ++INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) ++{ ++ return osal_lock_sleepable_lock(&stp_psm->stp_psm_lock); ++} ++ ++INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) ++{ ++ osal_unlock_sleepable_lock(&stp_psm->stp_psm_lock); ++ return 0; ++} ++ ++MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID) ++{ ++ if (stp_psm->is_wmt_quick_ps_support) ++ return (*(stp_psm->is_wmt_quick_ps_support)) (); ++ ++ STP_PSM_DBG_FUNC("stp_psm->is_wmt_quick_ps_support is NULL, return false\n\r"); ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID) ++{ ++ return _stp_psm_is_quick_ps_support(); ++} ++ ++#if PSM_USE_COUNT_PACKAGE ++int stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, int dir) ++{ ++ ++ /* easy the variable maintain beween stp tx, rx thread. */ ++ /* so we create variable for tx, rx respectively. */ ++ ++ static int tx_cnt; ++ static int rx_cnt; ++ static int is_tx_first = 1; ++ static int is_rx_first = 1; ++ static unsigned long tx_end_time; ++ static unsigned long rx_end_time; ++ ++ /* */ ++ /* BT A2DP TX CNT = 220, RX CNT = 843 */ ++ /* BT FTP Transferring TX CNT = 574, RX CNT = 2233 (1228~1588) */ ++ /* BT FTP Receiving TX CNT = 204, RX CNT = 3301 (2072~2515) */ ++ /* BT OPP Tx TX_CNT= 330, RX CNT = 1300~1800 */ ++ /* BT OPP Rx TX_CNT= (109~157), RX CNT = 1681~2436 */ ++ if (dir == 0) { /* tx */ ++ ++ tx_cnt++; ++ ++ if (((long)jiffies - (long)tx_end_time >= 0) || (is_tx_first)) { ++ tx_end_time = jiffies + (3 * HZ); ++ STP_PSM_INFO_FUNC("tx cnt = %d in the previous 3 sec\n", tx_cnt); ++ /* if(tx_cnt > 400)//for high traffic , not to do sleep. */ ++ if (tx_cnt > 300) { ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ tx_cnt = 0; ++ if (is_tx_first) ++ is_tx_first = 0; ++ } ++ } else { ++ rx_cnt++; ++ ++ if (((long)jiffies - (long)rx_end_time >= 0) || (is_rx_first)) { ++ rx_end_time = jiffies + (3 * HZ); ++ STP_PSM_INFO_FUNC("rx cnt = %d in the previous 3 sec\n", rx_cnt); ++ ++ /* if(rx_cnt > 2000)//for high traffic , not to do sleep. */ ++ if (rx_cnt > 1200) { /* for high traffic , not to do sleep. */ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ rx_cnt = 0; ++ if (is_rx_first) ++ is_rx_first = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++#else ++static struct timeval tv_now, tv_end; ++static INT32 sample_start; ++static INT32 tx_sum_len; ++static INT32 rx_sum_len; ++ ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length) ++{ ++ if (sample_start) { ++ if (dir) ++ rx_sum_len += length; ++ else ++ tx_sum_len += length; ++ ++ do_gettimeofday(&tv_now); ++ /* STP_PSM_INFO_FUNC("tv_now:%d.%d tv_end:%d.%d\n", ++ * tv_now.tv_sec,tv_now.tv_usec,tv_end.tv_sec,tv_end.tv_usec); ++ */ ++ if (((tv_now.tv_sec == tv_end.tv_sec) && (tv_now.tv_usec > tv_end.tv_usec)) || ++ (tv_now.tv_sec > tv_end.tv_sec)) { ++ STP_PSM_INFO_FUNC("STP speed rx:%d tx:%d\n", rx_sum_len, tx_sum_len); ++ if ((rx_sum_len + tx_sum_len) > RTX_SPEED_THRESHOLD) { ++ /* STP_PSM_INFO_FUNC("High speed,Disable monitor\n"); */ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP_1000; ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ /* STP_PSM_INFO_FUNC("Low speed,Enable monitor\n"); */ ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ } ++ sample_start = 0; ++ rx_sum_len = 0; ++ tx_sum_len = 0; ++ } ++ } else { ++ sample_start = 1; ++ do_gettimeofday(&tv_now); ++ tv_end = tv_now; ++ tv_end.tv_sec += SAMPLE_DURATION; ++ } ++ ++ return 0; ++} ++#endif ++ ++/*external function for WMT module to do sleep/wakeup*/ ++INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) ++{ ++ return _stp_psm_set_state(stp_psm, state); ++} ++ ++INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_thread_lock_aquire(stp_psm); ++} ++ ++INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_thread_lock_release(stp_psm); ++} ++ ++INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_do_wakeup(stp_psm); ++} ++ ++INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ ++ return _stp_psm_notify_stp(stp_psm, action); ++} ++ ++INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_notify_wmt_wakeup_wq(stp_psm); ++} ++ ++int stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ return _stp_psm_notify_wmt_sleep_wq(stp_psm); ++} ++ ++INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_start_monitor(stp_psm); ++} ++ ++INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_is_to_block_traffic(stp_psm); ++} ++ ++INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_is_disable(stp_psm); ++} ++ ++INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_has_pending_data(stp_psm); ++} ++ ++INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_release_data(stp_psm); ++} ++ ++INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) ++{ ++ return _stp_psm_hold_data(stp_psm, buffer, len, type); ++} ++ ++INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_disable(stp_psm); ++} ++ ++INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) ++{ ++ return _stp_psm_enable(stp_psm, idle_time_to_sleep); ++} ++ ++INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm) ++{ ++ stp_psm_set_sleep_enable(stp_psm); ++ ++ return _stp_psm_reset(stp_psm); ++} ++ ++INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_notify_wmt_sleep_wq(stp_psm); ++} ++ ++INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ stp_psm->sleep_en = 1; ++ STP_PSM_DBG_FUNC("\n"); ++ ret = 0; ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ stp_psm->sleep_en = 0; ++ STP_PSM_DBG_FUNC("\n"); ++ ret = 0; ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++/* stp_psm_check_sleep_enable - to check if sleep cmd is enabled or not ++ * @ stp_psm - pointer of psm ++ * ++ * return 1 if sleep is enabled; else return 0 if disabled; else error code ++ */ ++INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ ret = stp_psm->sleep_en; ++ STP_PSM_DBG_FUNC("%s\n", ret ? "enabled" : "disabled"); ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num) ++{ ++ INT32 index = 0; ++ struct timeval now; ++ ++ if (stp_psm_dbg) { ++ osal_lock_unsleepable_lock(&stp_psm_dbg->lock); ++ do_gettimeofday(&now); ++ index = stp_psm_dbg->in - 1; ++ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; ++ STP_PSM_DBG_FUNC("index(%d)\n", index); ++ stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag = stp_psm_dbg->queue[index].cur_flag; ++ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag = flag; ++ stp_psm_dbg->queue[stp_psm_dbg->in].line_num = line_num; ++ stp_psm_dbg->queue[stp_psm_dbg->in].package_no = g_record_num++; ++ stp_psm_dbg->queue[stp_psm_dbg->in].sec = now.tv_sec; ++ stp_psm_dbg->queue[stp_psm_dbg->in].usec = now.tv_usec; ++ stp_psm_dbg->size++; ++ STP_PSM_DBG_FUNC("pre_Flag = %d, cur_flag = %d\n", stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag, ++ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag); ++ stp_psm_dbg->size = (stp_psm_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : stp_psm_dbg->size; ++ stp_psm_dbg->in = (stp_psm_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (stp_psm_dbg->in + 1); ++ STP_PSM_DBG_FUNC("record size = %d, in = %d num = %d\n", stp_psm_dbg->size, stp_psm_dbg->in, line_num); ++ ++ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); ++ } ++ return 0; ++} ++ ++static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg) ++{ ++ ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ if (!stp_psm_dbg) { ++ STP_PSM_ERR_FUNC("NULL g_stp_psm_dbg reference\n"); ++ return -1; ++ } ++ osal_lock_unsleepable_lock(&stp_psm_dbg->lock); ++ ++ inIndex = stp_psm_dbg->in; ++ dumpSize = stp_psm_dbg->size; ++ if (STP_PSM_DBG_SIZE == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; ++ ++ STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ ++ pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d)\n", ++ stp_psm_dbg->queue[outIndex].sec, ++ stp_psm_dbg->queue[outIndex].usec, ++ stp_psm_dbg->queue[outIndex].package_no, ++ stp_psm_dbg->queue[outIndex].prev_flag, ++ stp_psm_dbg->queue[outIndex].cur_flag, stp_psm_dbg->queue[outIndex].line_num); ++ ++ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); ++ ++ return 0; ++} ++ ++static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num) ++{ ++ INT32 index = 0; ++ struct timeval now; ++ ++ if (p_opid_dbg) { ++ osal_lock_unsleepable_lock(&p_opid_dbg->lock); ++ do_gettimeofday(&now); ++ index = p_opid_dbg->in - 1; ++ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; ++ STP_PSM_DBG_FUNC("index(%d)\n", index); ++ p_opid_dbg->queue[p_opid_dbg->in].prev_flag = p_opid_dbg->queue[index].cur_flag; ++ p_opid_dbg->queue[p_opid_dbg->in].cur_flag = opid; ++ p_opid_dbg->queue[p_opid_dbg->in].line_num = line_num; ++ p_opid_dbg->queue[p_opid_dbg->in].package_no = g_opid_record_num++; ++ p_opid_dbg->queue[p_opid_dbg->in].sec = now.tv_sec; ++ p_opid_dbg->queue[p_opid_dbg->in].usec = now.tv_usec; ++ p_opid_dbg->queue[p_opid_dbg->in].pid = current->pid; ++ p_opid_dbg->size++; ++ STP_PSM_DBG_FUNC("pre_opid = %d, cur_opid = %d\n", p_opid_dbg->queue[p_opid_dbg->in].prev_flag, ++ p_opid_dbg->queue[p_opid_dbg->in].cur_flag); ++ p_opid_dbg->size = (p_opid_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : p_opid_dbg->size; ++ p_opid_dbg->in = (p_opid_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (p_opid_dbg->in + 1); ++ STP_PSM_DBG_FUNC("opid record size = %d, in = %d num = %d\n", p_opid_dbg->size, p_opid_dbg->in, ++ line_num); ++ ++ osal_unlock_unsleepable_lock(&p_opid_dbg->lock); ++ } ++ return 0; ++ ++} ++ ++static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg) ++{ ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ if (!p_opid_dbg) { ++ STP_PSM_ERR_FUNC("NULL p_opid_dbg reference\n"); ++ return -1; ++ } ++ osal_lock_unsleepable_lock(&p_opid_dbg->lock); ++ ++ inIndex = p_opid_dbg->in; ++ dumpSize = p_opid_dbg->size; ++ if (STP_PSM_DBG_SIZE == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; ++ ++ STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ ++ pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d) pid(%d)\n", ++ p_opid_dbg->queue[outIndex].sec, ++ p_opid_dbg->queue[outIndex].usec, ++ p_opid_dbg->queue[outIndex].package_no, ++ p_opid_dbg->queue[outIndex].prev_flag, ++ p_opid_dbg->queue[outIndex].cur_flag, ++ p_opid_dbg->queue[outIndex].line_num, p_opid_dbg->queue[outIndex].pid); ++ ++ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ osal_unlock_unsleepable_lock(&p_opid_dbg->lock); ++ ++ return 0; ++ ++} ++ ++MTKSTP_PSM_T *stp_psm_init(void) ++{ ++ INT32 err = 0; ++ INT32 i = 0; ++ INT32 ret = -1; ++ ++ STP_PSM_INFO_FUNC("psm init\n"); ++ ++ stp_psm->work_state = ACT; ++ stp_psm->wmt_notify = wmt_lib_ps_stp_cb; ++ stp_psm->is_wmt_quick_ps_support = wmt_lib_is_quick_ps_support; ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; ++ stp_psm->flag.data = 0; ++ stp_psm->stp_tx_cb = NULL; ++ stp_psm_set_sleep_enable(stp_psm); ++ ++ ret = osal_fifo_init(&stp_psm->hold_fifo, NULL, STP_PSM_FIFO_SIZE); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("FIFO INIT FAILS\n"); ++ goto ERR_EXIT4; ++ } ++ ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ osal_sleepable_lock_init(&stp_psm->hold_fifo_spinlock_global); ++ osal_unsleepable_lock_init(&stp_psm->wq_spinlock); ++ osal_sleepable_lock_init(&stp_psm->stp_psm_lock); ++ ++/* osal_unsleepable_lock_init(&stp_psm->flagSpinlock); */ ++ ++ osal_memcpy(stp_psm->wake_lock.name, "MT662x", 6); ++ osal_wake_lock_init(&stp_psm->wake_lock); ++ ++ osal_event_init(&stp_psm->STPd_event); ++ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); ++ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); ++ /* Put all to free Q */ ++ for (i = 0; i < STP_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_psm->arQue[i].signal)); ++ _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, &(stp_psm->arQue[i])); ++ } ++ /* stp_psm->current_active_op = NULL; */ ++ stp_psm->last_active_opId = STP_OPID_PSM_INALID; ++ /*Generate BTM thread, to servie STP-CORE and WMT-CORE for sleeping, waking up and host awake */ ++ stp_psm->PSMd.pThreadData = (VOID *) stp_psm; ++ stp_psm->PSMd.pThreadFunc = (VOID *) _stp_psm_proc; ++ osal_memcpy(stp_psm->PSMd.threadName, PSM_THREAD_NAME, osal_strlen(PSM_THREAD_NAME)); ++ ++ ret = osal_thread_create(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_create fail...\n"); ++ goto ERR_EXIT5; ++ } ++ /* init_waitqueue_head(&stp_psm->wait_wmt_q); */ ++ stp_psm->wait_wmt_q.timeoutValue = STP_PSM_WAIT_EVENT_TIMEOUT; ++ osal_event_init(&stp_psm->wait_wmt_q); ++ ++ err = _stp_psm_init_monitor(stp_psm); ++ if (err) { ++ STP_PSM_ERR_FUNC("__stp_psm_init ERROR\n"); ++ goto ERR_EXIT6; ++ } ++ /* Start STPd thread */ ++ ret = osal_thread_run(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_run FAILS\n"); ++ goto ERR_EXIT6; ++ } ++ /* psm disable in default */ ++ _stp_psm_disable(stp_psm); ++ ++ g_stp_psm_dbg = (STP_PSM_RECORD_T *) osal_malloc(osal_sizeof(STP_PSM_RECORD_T)); ++ if (!g_stp_psm_dbg) { ++ STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); ++ return NULL; ++ } ++ osal_memset(g_stp_psm_dbg, 0, osal_sizeof(STP_PSM_RECORD_T)); ++ osal_unsleepable_lock_init(&g_stp_psm_dbg->lock); ++ ++ g_stp_psm_opid_dbg = (STP_PSM_OPID_RECORD *) osal_malloc(osal_sizeof(STP_PSM_OPID_RECORD)); ++ if (!g_stp_psm_opid_dbg) { ++ STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); ++ return NULL; ++ } ++ osal_memset(g_stp_psm_opid_dbg, 0, osal_sizeof(STP_PSM_OPID_RECORD)); ++ osal_unsleepable_lock_init(&g_stp_psm_opid_dbg->lock); ++ ++ return stp_psm; ++ ++ERR_EXIT6: ++ ++ ret = osal_thread_destroy(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ goto ERR_EXIT5; ++ } ++ERR_EXIT5: ++ osal_fifo_deinit(&stp_psm->hold_fifo); ++ERR_EXIT4: ++ ++ return NULL; ++} ++ ++INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = -1; ++ ++ STP_PSM_INFO_FUNC("psm deinit\n"); ++ ++ if (g_stp_psm_dbg) { ++ osal_unsleepable_lock_deinit(&g_stp_psm_dbg->lock); ++ osal_free(g_stp_psm_dbg); ++ g_stp_psm_dbg = NULL; ++ } ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ ret = osal_thread_destroy(&stp_psm->PSMd); ++ if (ret < 0) ++ STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ ++ ret = _stp_psm_deinit_monitor(stp_psm); ++ if (ret < 0) ++ STP_PSM_ERR_FUNC("_stp_psm_deinit_monitor ERROR\n"); ++ ++ osal_wake_lock_deinit(&stp_psm->wake_lock); ++ osal_fifo_deinit(&stp_psm->hold_fifo); ++ osal_sleepable_lock_deinit(&stp_psm->hold_fifo_spinlock_global); ++ osal_unsleepable_lock_deinit(&stp_psm->wq_spinlock); ++ osal_sleepable_lock_deinit(&stp_psm->stp_psm_lock); ++/* osal_unsleepable_lock_deinit(&stp_psm->flagSpinlock); */ ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c +new file mode 100644 +index 000000000000..046af2a58e69 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c +@@ -0,0 +1,3358 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "osal_typedef.h" ++#include "stp_core.h" ++#include "psm_core.h" ++#include "btm_core.h" ++#include "stp_dbg.h" ++#include "stp_btif.h" ++ ++#define PFX "[STP] " ++#define STP_LOG_DBG 4 ++#define STP_LOG_PKHEAD 3 ++#define STP_LOG_INFO 2 ++#define STP_LOG_WARN 1 ++#define STP_LOG_ERR 0 ++ ++#define STP_DEL_SIZE 2 /* STP delimiter length */ ++ ++UINT32 gStpDbgLvl = STP_LOG_INFO; ++unsigned int g_coredump_mode = 0; ++#define REMOVE_USELESS_LOG 1 ++ ++#define STP_POLL_CPUPCR_NUM 16 ++#define STP_POLL_CPUPCR_DELAY 10 ++#define STP_RETRY_OPTIMIZE 0 ++ ++/* global variables */ ++static const UINT8 stp_delimiter[STP_DEL_SIZE] = { 0x55, 0x55 }; ++ ++static INT32 fgEnableNak; /* 0=enable NAK; 1=disable NAK */ ++static INT32 fgEnableDelimiter; /* 0=disable Delimiter; 1=enable Delimiter */ ++#if STP_RETRY_OPTIMIZE ++static UINT32 g_retry_times; ++#endif ++/* common interface */ ++static IF_TX sys_if_tx; ++/* event/signal */ ++static EVENT_SET sys_event_set; ++static EVENT_TX_RESUME sys_event_tx_resume; ++static FUNCTION_STATUS sys_check_function_status; ++/* kernel lib */ ++/* int g_block_tx = 0; */ ++static mtkstp_context_struct stp_core_ctx = { 0 }; ++ ++#define STP_PSM_CORE(x) ((x).psm) ++#define STP_SET_PSM_CORE(x, v) ((x).psm = (v)) ++ ++#define STP_BTM_CORE(x) ((x).btm) ++#define STP_SET_BTM_CORE(x, v) ((x).btm = (v)) ++ ++#define STP_IS_ENABLE(x) ((x).f_enable != 0) ++#define STP_NOT_ENABLE(x) ((x).f_enable == 0) ++#define STP_SET_ENABLE(x, v) ((x).f_enable = (v)) ++ ++#define STP_IS_READY(x) ((x).f_ready != 0) ++#define STP_NOT_READY(x) ((x).f_ready == 0) ++#define STP_SET_READY(x, v) ((x).f_ready = (v)) ++ ++#define STP_PENDING_TYPE(x) ((x).f_pending_type) ++#define STP_SET_PENDING_TYPE(x, v) ((x).f_pending_type = (v)) ++ ++#define STP_BLUE_ANGEL (0) ++#define STP_BLUE_Z (1) ++#define STP_BT_STK(x) ((x).f_bluez) ++#define STP_BT_STK_IS_BLUEZ(x) ((x).f_bluez == (STP_BLUE_Z)) ++#define STP_SET_BT_STK(x, v) ((x).f_bluez = (v)) ++ ++#define STP_IS_ENABLE_DBG(x) ((x).f_dbg_en != 0) ++#define STP_NOT_ENABLE_DBG(x) ((x).f_dbg_en == 0) ++#define STP_SET_ENABLE_DBG(x, v) ((x).f_dbg_en = (v)) ++ ++#define STP_IS_ENABLE_RST(x) ((x).f_autorst_en != 0) ++#define STP_NOT_ENABLE_RST(x) ((x).f_autorst_en == 0) ++#define STP_SET_ENABLE_RST(x, v) ((x).f_autorst_en = (v)) ++ ++#define STP_SUPPORT_PROTOCOL(x) ((x).f_mode) ++#define STP_SET_SUPPORT_PROTOCOL(x, v) ((x).f_mode = (v)) ++ ++#define STP_FW_COREDUMP_FLAG(x) ((x).f_coredump) ++#define STP_SET_FW_COREDUMP_FLAG(x, v) ((x).f_coredump = (v)) ++#define STP_ENABLE_FW_COREDUMP(x, v) ((x).en_coredump = (v)) ++#define STP_ENABLE_FW_COREDUMP_FLAG(x) ((x).en_coredump) ++ ++#define STP_WMT_LAST_CLOSE(x) ((x).f_wmt_last_close) ++#define STP_SET_WMT_LAST_CLOSE(x, v) ((x).f_wmt_last_close = (v)) ++ ++#define STP_EVT_ERR_ASSERT(x) ((x).f_evt_err_assert) ++#define STP_SET_EVT_ERR_ASSERT(x, v) ((x).f_evt_err_assert = (v)) ++ ++/*[PatchNeed]Need to calculate the timeout value*/ ++static UINT32 mtkstp_tx_timeout = MTKSTP_TX_TIMEOUT; ++static mtkstp_parser_state prev_state = -1; ++ ++#define CONFIG_DEBUG_STP_TRAFFIC_SUPPORT ++#ifdef CONFIG_DEBUG_STP_TRAFFIC_SUPPORT ++static MTKSTP_DBG_T *g_mtkstp_dbg; ++#endif ++static VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len); ++static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc); ++static VOID stp_update_tx_queue(UINT32 txseq); ++static VOID stp_rest_ctx_state(VOID); ++static VOID stp_change_rx_state(mtkstp_parser_state next); ++static void stp_tx_timeout_handler(unsigned long data); ++static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len); ++static VOID stp_dump_tx_queue(UINT32 txseq); ++static INT32 stp_is_apply_powersaving(VOID); ++/*static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type);*/ ++static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length); ++static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length); ++static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type); ++static VOID stp_send_tx_queue(UINT32 txseq); ++static VOID stp_send_ack(UINT8 txAck, UINT8 nak); ++static INT32 stp_process_rxack(VOID); ++static VOID stp_process_packet(VOID); ++ ++/*private functions*/ ++ ++static INT32 stp_ctx_lock_init(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unsleepable_lock_init(&((pctx)->stp_mutex)); ++#else ++ osal_sleepable_lock_init(&((pctx)->stp_mutex)); ++ return 0; ++#endif ++} ++ ++static INT32 stp_ctx_lock_deinit(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unsleepable_lock_deinit(&((pctx)->stp_mutex)); ++#else ++ return osal_sleepable_lock_deinit(&((pctx)->stp_mutex)); ++#endif ++} ++ ++static INT32 stp_ctx_lock(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_lock_unsleepable_lock(&((pctx)->stp_mutex)); ++#else ++ return osal_lock_sleepable_lock(&((pctx)->stp_mutex)); ++#endif ++} ++ ++static INT32 stp_ctx_unlock(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unlock_unsleepable_lock(&((pctx)->stp_mutex)); ++#else ++ return osal_unlock_sleepable_lock(&((pctx)->stp_mutex)); ++#endif ++} ++ ++MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel) ++{ ++ if (dbglevel <= 4) { ++ gStpDbgLvl = dbglevel; ++ STP_INFO_FUNC("gStpDbgLvl = %d\n", gStpDbgLvl); ++ return MTK_WCN_BOOL_TRUE; ++ } ++ STP_INFO_FUNC("invalid stp debug level. gStpDbgLvl = %d\n", gStpDbgLvl); ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++#if !(REMOVE_USELESS_LOG) ++static UINT8 *stp_type_to_dbg_string(UINT32 type) ++{ ++ UINT8 *type_name = NULL; ++ ++ if (type == BT_TASK_INDX) ++ type_name = "< BT>"; ++ else if (type == GPS_TASK_INDX) ++ type_name = ""; ++ else if (type == WMT_TASK_INDX) ++ type_name = ""; ++ else if (type == FM_TASK_INDX) ++ type_name = "< FM>"; ++ else if (type == ANT_TASK_INDX) ++ type_name = ""; ++ ++ return type_name; ++} ++#endif ++#if 0 ++/***************************************************************************** ++* FUNCTION ++* crc16 ++* DESCRIPTION ++* Compute the CRC-16 for the data buffer ++* PARAMETERS ++* crc [IN] previous CRC value ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* the updated CRC value ++*****************************************************************************/ ++static UINT16 crc16(const UINT8 *buffer, const UINT32 length) ++{ ++ UINT32 crc, i; ++ ++ /* FIXME: Add STP checksum feature */ ++ crc = 0; ++ for (i = 0; i < length; i++, buffer++) ++ crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; ++ ++ return crc; ++} ++ ++#endif ++ ++VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len) ++{ ++ ++#ifndef CONFIG_LOG_STP_INTERNAL ++ return; ++#endif ++ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx)) { ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_PKT, type, /* type */ ++ txAck, /* ack */ ++ seq, /* seq */ ++ crc, /* crc */ ++ dir, /* dir */ ++ len, /* len */ ++ pBuf); /* body */ ++ } else { ++ STP_DBG_FUNC("stp_dbg not enabled"); ++ } ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_check_crc ++* DESCRIPTION ++* check the check sum of packet payload ++* PARAMETERS ++* pdata [IN] the data want to check ++* length [IN] the length of pdata ++* crc [IN] the crc of pdata ++* RETURNS ++* KAL_TRUE crc is ok ++* KAL_FALSE crc is wrong ++*****************************************************************************/ ++static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc) ++{ ++ /*----------------------------------------------------------------*/ ++ /* Local Variables */ ++ /*----------------------------------------------------------------*/ ++ UINT16 checksum; ++ ++ /*----------------------------------------------------------------*/ ++ /* Code Body */ ++ /*----------------------------------------------------------------*/ ++ ++ /* FIXME: Add STP feature: check or skip crc */ ++ ++ checksum = osal_crc16(buffer, length); ++ if (checksum == crc) ++ return MTK_WCN_BOOL_TRUE; ++ ++ STP_ERR_FUNC("CRC fail, length = %d, rx = %x, calc = %x \r\n", length, crc, checksum); ++ return MTK_WCN_BOOL_FALSE; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_update_tx_queue ++* DESCRIPTION ++* update packet's ACK field ++* PARAMETERS ++* txseq [IN] index of the tx packet which we want to update ++* RETURNS ++* void ++*****************************************************************************/ ++static void stp_update_tx_queue(UINT32 txseq) ++{ ++ INT32 tx_read, i; ++ UINT8 checksum = 0; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ stp_core_ctx.tx_buf[tx_read] &= 0xf8; ++ stp_core_ctx.tx_buf[tx_read] |= stp_core_ctx.sequence.txack; ++ ++ for (i = 0; i < 3; i++) { ++ checksum += stp_core_ctx.tx_buf[tx_read]; ++ tx_read++; ++ if (tx_read >= MTKSTP_BUFFER_SIZE) ++ tx_read -= MTKSTP_BUFFER_SIZE; ++ ++ } ++ ++ stp_core_ctx.tx_buf[tx_read] = checksum; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_rest_ctx_state ++* DESCRIPTION ++* Reset stp context state variables only. Mutex and timer resources are not touched. ++* ++* PARAMETERS ++* void ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_rest_ctx_state(VOID) ++{ ++ INT32 i; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ stp_core_ctx.rx_counter = 0; ++ ++ /*reset rx buffer pointer */ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) { ++ stp_core_ctx.ring[i].read_p = 0; ++ stp_core_ctx.ring[i].write_p = 0; ++ } ++ ++ /*reset tx buffer pointer */ ++ stp_core_ctx.tx_write = 0; ++ stp_core_ctx.tx_read = 0; ++ ++ /*reset STP protocol context */ ++ stp_core_ctx.parser.state = MTKSTP_SYNC; ++ stp_core_ctx.sequence.txseq = 0; ++ stp_core_ctx.sequence.txack = 7; ++ stp_core_ctx.sequence.rxack = 7; ++ stp_core_ctx.sequence.winspace = MTKSTP_WINSIZE; ++ stp_core_ctx.sequence.expected_rxseq = 0; ++ stp_core_ctx.sequence.retry_times = 0; ++ stp_core_ctx.inband_rst_set = 0; ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_change_rx_state ++* DESCRIPTION ++* change the rx fsm of STP to "next" ++* PARAMETERS ++* next [IN] the next state of rx fsm ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_change_rx_state(mtkstp_parser_state next) ++{ ++ prev_state = stp_core_ctx.parser.state; ++ stp_core_ctx.parser.state = next; ++ ++} ++ ++/* static void stp_tx_timeout_handler(void){ */ ++static void stp_tx_timeout_handler(unsigned long data) ++{ ++ STP_WARN_FUNC("call retry btm retry wq ...\n"); ++ /*shorten the softirq lattency */ ++ stp_btm_notify_stp_retry_wq(STP_BTM_CORE(stp_core_ctx)); ++ STP_WARN_FUNC("call retry btm retry wq ...#\n"); ++} ++ ++VOID stp_do_tx_timeout(VOID) ++{ ++ UINT32 seq; ++ UINT32 ret; ++ INT32 iRet; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ UINT8 resync[4]; ++ ++ STP_WARN_FUNC("==============================================================================\n"); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++#if STP_RETRY_OPTIMIZE ++ if ((g_retry_times != 0) && (stp_core_ctx.sequence.retry_times == 0)) { ++ STP_INFO_FUNC("STP TX timeout has been recoveryed by resend,record_retry_time(%d)\n", g_retry_times); ++ g_retry_times = 0; ++ stp_ctx_unlock(&stp_core_ctx); ++ return; ++ } ++#endif ++ if (stp_core_ctx.sequence.retry_times > (MTKSTP_RETRY_LIMIT)) { ++ STP_INFO_FUNC("STP retry times(%d) have reached retry limit,stop it\n", ++ stp_core_ctx.sequence.retry_times); ++ stp_ctx_unlock(&stp_core_ctx); ++ return; ++ } ++#if STP_RETRY_OPTIMIZE ++ else ++ STP_DBG_FUNC("current TX timeout package has not received ACK yet,retry_times(%d)\n", ++ g_retry_times); ++#endif ++ /*polling cpupcr when no ack occurs at first retry */ ++ stp_notify_btm_poll_cpupcr(STP_BTM_CORE(stp_core_ctx), STP_POLL_CPUPCR_NUM, STP_POLL_CPUPCR_DELAY); ++ ++ seq = stp_core_ctx.sequence.rxack; ++ INDEX_INC(seq); ++ ++ if (seq != stp_core_ctx.sequence.txseq) { ++ osal_memset(&resync[0], 127, 4); ++ (*sys_if_tx) (&resync[0], 4, &ret); ++ if (ret != 4) { ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: send resync fail\n"); ++ osal_assert(0); ++ } ++ ++ do { ++ STP_WARN_FUNC("[stp.ctx]*rxack (=last rx ack) = %d\n\r", stp_core_ctx.sequence.rxack); ++ STP_WARN_FUNC("[stp.ctx]txack (=last rx seq)= %d\n\r", stp_core_ctx.sequence.txack); ++ STP_WARN_FUNC("[stp.ctx]*txseq (=next tx seq)= %d\n\r", stp_core_ctx.sequence.txseq); ++ STP_WARN_FUNC("Resend STP packet from %d -> %d\n\r", seq, ++ (stp_core_ctx.sequence.txseq <= 0) ? (7) : (stp_core_ctx.sequence.txseq - 1)); ++ stp_dump_tx_queue(seq); ++ ++ stp_send_tx_queue(seq); ++ INDEX_INC(seq); ++ } while (seq != stp_core_ctx.sequence.txseq); ++ ++ } ++ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ ++ if (stp_core_ctx.sequence.winspace == MTKSTP_WINSIZE) { ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); ++ } else { ++ stp_core_ctx.sequence.retry_times++; ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler, retry = %d\n", stp_core_ctx.sequence.retry_times); ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = stp_core_ctx.sequence.retry_times; ++#endif ++ /*If retry too much, try to recover STP by return back to initializatin state */ ++ /*And not to retry again */ ++ if (stp_core_ctx.sequence.retry_times > MTKSTP_RETRY_LIMIT) { ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = 0; ++#endif ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ stp_ctx_unlock(&stp_core_ctx); ++ ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); ++ ++ STP_ERR_FUNC("TX retry limit = %d\n", MTKSTP_RETRY_LIMIT); ++ osal_assert(0); ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ /*Whole Chip Reset Procedure Invoke */ ++ /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ ++ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ stp_dbg_set_host_assert_info(4, 36, 1); ++ STP_INFO_FUNC("**STP NoAck trigger firmware assert**\n"); ++ iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ ++ if (iRet) { ++ STP_ERR_FUNC("host tigger fw assert fail(%d), do noack handle flow\n", iRet); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ issue_type = STP_FW_NOACK_ISSUE; ++ iRet = stp_dbg_set_fw_info("STP NoAck", osal_strlen("STP NoAck"), issue_type); ++ ++ osal_dbg_assert_aee("[SOC_CONNSYS]NoAck", ++ "**[WCN_ISSUE_INFO]STP Tx Timeout**\n F/W has NO any RESPONSE. Please check F/W status first\n"); ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ } else { ++ STP_INFO_FUNC("do trigger assert & chip reset in wmt\n"); ++ } ++ return; ++ } ++ } ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ STP_WARN_FUNC("==============================================================================#\n"); ++} ++ ++static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len) ++{ ++ osal_buffer_dump(buf, title, len, 32); ++} ++ ++/***************************************************************************** ++ * FUNCTION ++ * stp_tx_timeout_handler ++ * DESCRIPTION ++ * tx timeout handler, send resync & retransmitt ++ * PARAMETERS ++ * void ++ * RETURNS ++ * void ++ *****************************************************************************/ ++static VOID stp_dump_tx_queue(UINT32 txseq) ++{ ++ INT32 tx_read, tx_length, last_len; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ tx_length = stp_core_ctx.tx_length[txseq]; ++ ++ STP_ERR_FUNC("tx_seq=%d ..", txseq); ++ ++ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { ++ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q", (tx_length >= 8) ? (8) : (tx_length)); ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - tx_read; ++ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q_0", (last_len >= 8) ? (8) : (last_len)); ++ stp_dump_data(&stp_core_ctx.tx_buf[0], "tx_q_0", ++ ((tx_length - last_len) ? (8) : (tx_length - last_len))); ++ } ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_is_apply_powersaving ++* DESCRIPTION ++* Check if STP support power saving mode. ++* PARAMETERS ++* ++* RETURNS ++* True: support power saving False: not support power saving ++*****************************************************************************/ ++static INT32 stp_is_apply_powersaving(VOID) ++{ ++ ++ if (STP_IS_READY(stp_core_ctx) && !stp_psm_is_disable(STP_PSM_CORE(stp_core_ctx))) { ++ /* osal_dbg_print("apply power saving\n"); */ ++ return MTK_WCN_BOOL_TRUE; ++ } ++ if (mtk_wcn_stp_is_sdio_mode()) ++ return MTK_WCN_BOOL_FALSE; ++ ++ STP_DBG_FUNC("not apply power saving\n"); ++ return MTK_WCN_BOOL_FALSE; ++} ++#if 0 ++/***************************************************************************** ++* FUNCTION ++* stp_is_privileges_cmd ++* DESCRIPTION ++* Check if the data is privilege command ++* PARAMETERS ++* ++* RETURNS ++* True/False ++*****************************************************************************/ ++static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type) ++{ ++ typedef struct privileges_cmd { ++ UINT32 length; ++ UINT8 type; ++ UINT8 buf[7]; /* MAX length of target command is only 5 currently */ ++ } p_cmd_t; ++ ++ p_cmd_t p_cmd_table[] = { ++ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x01} }, /* sleep command */ ++ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x02} }, /* host_awake command */ ++ }; ++ ++ UINT32 i; ++ UINT32 size = sizeof(p_cmd_table) / sizeof(p_cmd_table[0]); ++ ++ for (i = 0; i < size; i++) { ++ if (type != p_cmd_table[i].type) ++ continue; ++ ++ if (length != p_cmd_table[i].length) ++ continue; ++ ++ if (osal_memcmp(p_cmd_table[i].buf, buffer, length)) ++ continue; ++ ++ /* matched entry is found */ ++ STP_DBG_FUNC("It's p_cmd_t\n"); ++ return MTK_WCN_BOOL_TRUE; ++ } ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++#endif ++/***************************************************************************** ++* FUNCTION ++* tx_queue_room_available ++* DESCRIPTION ++* check room if available, ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length) ++{ ++ UINT32 roomLeft; ++ ++ /* ++ Get available space of TX Queue ++ */ ++ if (stp_core_ctx.tx_read <= stp_core_ctx.tx_write) ++ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write + stp_core_ctx.tx_read - 1; ++ else ++ roomLeft = stp_core_ctx.tx_read - stp_core_ctx.tx_write - 1; ++ ++ if (roomLeft < length) { ++ STP_ERR_FUNC("%s: tx queue room shortage\n", __func__); ++ return MTK_WCN_BOOL_FALSE; ++ } else ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_add_to_tx_queue ++* DESCRIPTION ++* put data to tx queue ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length) ++{ ++ UINT32 last_len; ++ ++ /* Get available space of TX Queue */ ++ if (length + stp_core_ctx.tx_write < MTKSTP_BUFFER_SIZE) { ++ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, length); ++ stp_core_ctx.tx_write += length; ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write; ++ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, last_len); ++ osal_memcpy(stp_core_ctx.tx_buf, buffer + last_len, length - last_len); ++ ++ stp_core_ctx.tx_write = length - last_len; ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_add_to_rx_queue ++* DESCRIPTION ++* put data to corresponding task's rx queue and notify corresponding task ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] corresponding task index ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type) ++{ ++ UINT32 roomLeft, last_len; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if (stp_core_ctx.ring[type].read_p <= stp_core_ctx.ring[type].write_p) ++ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p + stp_core_ctx.ring[type].read_p - 1; ++ else ++ roomLeft = stp_core_ctx.ring[type].read_p - stp_core_ctx.ring[type].write_p - 1; ++ ++ if (roomLeft < length) { ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ STP_ERR_FUNC("Queue is full !!!, type = %d\n", type); ++ osal_assert(0); ++ return -1; ++ } ++ ++ if (length + stp_core_ctx.ring[type].write_p < MTKSTP_BUFFER_SIZE) { ++ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, length); ++ stp_core_ctx.ring[type].write_p += length; ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p; ++ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, last_len); ++ osal_memcpy(stp_core_ctx.ring[type].buffer, buffer + last_len, length - last_len); ++ stp_core_ctx.ring[type].write_p = length - last_len; ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_tx_queue ++* DESCRIPTION ++* send data in tx buffer to common interface ++* PARAMETERS ++* txseq [IN] sequence number of outgoing packet in tx buffer ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_send_tx_queue(UINT32 txseq) ++{ ++ UINT32 ret; ++ INT32 tx_read, tx_length, last_len; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ tx_length = stp_core_ctx.tx_length[txseq]; ++ ++ stp_update_tx_queue(txseq); ++ ++ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { ++ ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], tx_length, &ret); ++ ++ if (ret != tx_length) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length, ret); ++ osal_assert(0); ++ } ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - tx_read; ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], last_len, &ret); ++ ++ if (ret != last_len) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", last_len, ret); ++ osal_assert(0); ++ } ++ ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], tx_length - last_len, &ret); ++ ++ if (ret != tx_length - last_len) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length - last_len, ret); ++ osal_assert(0); ++ } ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_ack ++* DESCRIPTION ++* send ack packet to the peer ++* PARAMETERS ++* txAck [IN] Ack number ++* nak [IN] 0 = ack; !0 = NAK ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_send_ack(UINT8 txAck, UINT8 nak) ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE]; ++ UINT32 ret; ++ INT32 iStatus; ++ ++ mtkstp_header[0] = 0x80 + (0 << 3) + txAck; /* stp_core_ctx.sequence.txack; */ ++ ++ if (fgEnableNak == 0) ++ mtkstp_header[1] = 0x00; /* disable NAK */ ++ else ++ mtkstp_header[1] = ((nak == 0) ? 0x00 : 0x80); ++ ++ mtkstp_header[2] = 0; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ ++ stp_dbg_pkt_log(STP_TASK_INDX, txAck, 0, 0, PKT_DIR_TX, NULL, 0); ++ ++ if (fgEnableDelimiter == 1) { ++ iStatus = (*sys_if_tx) ((PUINT8) &stp_delimiter[0], STP_DEL_SIZE, &ret); ++ STP_DUMP_PACKET_HEAD((PUINT8) &stp_delimiter[0], "tx del", STP_DEL_SIZE); ++ if (ret != STP_DEL_SIZE) { ++ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", STP_DEL_SIZE, ret, iStatus); ++ osal_assert(0); ++ } ++ } ++ ++ iStatus = (*sys_if_tx) (&mtkstp_header[0], MTKSTP_HEADER_SIZE, &ret); ++ ++ if (ret != MTKSTP_HEADER_SIZE) { ++ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", MTKSTP_HEADER_SIZE, ret, iStatus); ++ osal_assert(0); ++ } ++ ++} ++ ++INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type) ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; ++ UINT8 *p_tx_buf = NULL; ++ UINT16 crc; ++ INT32 ret = 0; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*Only WMT can set raw data */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { ++ /* no op */ ++ /* NULL; */ ++ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { ++ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ ++ /* NULL; */ ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ osal_printtimeofday("[ STP][SDIO][ B][W]"); ++ ++ mtkstp_header[0] = 0x80; ++ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); ++ mtkstp_header[2] = (length) & 0xff; ++ mtkstp_header[3] = 0x00; ++ ++ p_tx_buf = &stp_core_ctx.tx_buf[0]; ++ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); ++ p_tx_buf += MTKSTP_HEADER_SIZE; ++ ++ osal_memcpy(p_tx_buf, buffer, length); ++ p_tx_buf += length; ++ ++ temp[0] = 0x00; ++ temp[1] = 0x00; ++ osal_memcpy(p_tx_buf, temp, 2); ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, 0, PKT_DIR_TX, buffer, length); ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); ++ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { ++ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); ++ osal_assert(0); ++ ret = 0; ++ } else { ++ ret = (INT32) length; ++ } ++ ++ osal_printtimeofday("[ STP][SDIO][ E][W]"); ++ } ++ /* STP over BTIF OR UART */ ++ else if ((mtk_wcn_stp_is_btif_fullset_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ if ((stp_core_ctx.sequence.winspace > 0) && ++ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { ++ mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; ++ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); ++ mtkstp_header[2] = length & 0xff; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ ++ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; ++ ++ if (fgEnableDelimiter == 1) { ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; ++ stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); ++ } ++ ++ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); ++ ++ /*Make Payload */ ++ stp_add_to_tx_queue(buffer, length); ++ ++ /*Make CRC */ ++ crc = osal_crc16(buffer, length); ++ temp[0] = crc & 0xff; ++ temp[1] = (crc & 0xff00) >> 8; ++ stp_add_to_tx_queue(temp, 2); ++ ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); ++ ++ /*Kick to UART */ ++ stp_send_tx_queue(stp_core_ctx.sequence.txseq); ++ INDEX_INC(stp_core_ctx.sequence.txseq); ++ stp_core_ctx.sequence.winspace--; ++ ++ /*Setup the Retry Timer */ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ else ++ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); ++ ++ ret = (INT32) length; ++ } else { ++ /* No winspace to send. Let caller retry */ ++ STP_ERR_FUNC("%s: There is no winspace/txqueue to send !!!\n", __func__); ++ ret = 0; ++ } ++ } ++ ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ ++ return ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_process_rxack ++* DESCRIPTION ++* process ack packet ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++static INT32 stp_process_rxack(VOID) ++{ ++ INT32 j, k; ++ UINT8 rxack; ++ INT32 fgResult = (-1); ++ ++ if (stp_core_ctx.sequence.rxack != stp_core_ctx.parser.ack) { ++ j = k = 0; ++ rxack = stp_core_ctx.sequence.rxack; ++ INDEX_INC(rxack); ++ while (rxack != stp_core_ctx.sequence.txseq) { ++ j++; ++ if (rxack == stp_core_ctx.parser.ack) { ++ k = 1; ++ break; ++ } ++ INDEX_INC(rxack); ++ } ++ if (k == 1) { ++ stp_core_ctx.sequence.rxack = stp_core_ctx.parser.ack; ++ stp_core_ctx.tx_read = stp_core_ctx.tx_start_addr[rxack] + stp_core_ctx.tx_length[rxack]; ++ if (stp_core_ctx.tx_read >= MTKSTP_BUFFER_SIZE) ++ stp_core_ctx.tx_read -= MTKSTP_BUFFER_SIZE; ++ ++ stp_core_ctx.sequence.winspace += j; ++ stp_core_ctx.sequence.retry_times = 0; ++ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ ++ fgResult = 0; ++ } ++ } ++ ++ return fgResult; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_process_packet ++* DESCRIPTION ++* process STP packet ++* PARAMETERS ++* void ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_process_packet(VOID) ++{ ++ INT32 fgTriggerResume = (-1); ++ UINT8 txAck = 0; ++ static INT32 fgRxOk; ++ MTK_WCN_BOOL b; ++ MTK_WCN_BOOL is_function_active = 0; ++ static INT32 stp_process_packet_fail_count; ++ INT32 iRet = -1; ++ ++ stp_dbg_pkt_log(stp_core_ctx.parser.type, ++ stp_core_ctx.parser.ack, ++ stp_core_ctx.parser.seq, ++ stp_core_ctx.parser.crc, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.parser.length); ++ /*Optimization */ ++ /*If bluez, direct send packet to hci_core not through RX buffer! */ ++ if ((stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) && ++ (stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { ++ /*Indicate packet to hci_stp */ ++ STP_DBG_FUNC("Send Packet to BT_SUBFUCTION, len = %d\n", stp_core_ctx.rx_counter); ++ ++ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if (b) ++ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ /*Process rx ack */ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ txAck = stp_core_ctx.sequence.txack; ++ ++ /*Send ack back */ ++ stp_send_ack(txAck, 0); ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ fgRxOk = 0; ++ } ++ /* sequence matches expected, enqueue packet */ ++ else if (stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) { ++ is_function_active = ++ ((*sys_check_function_status) (stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) == ++ STATUS_FUNCTION_ACTIVE); ++ /*If type is valid and function works, then try to enqueue */ ++ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && (is_function_active == MTK_WCN_BOOL_TRUE)) { ++ if (stp_core_ctx.parser.type == BT_TASK_INDX) { ++ static const UINT8 rst_buf[7] = { 0x04, 0x0e, 0x04, 0x01, 0x3, 0xc, 0x00 }; ++ ++ if (!osal_strncmp(stp_core_ctx.rx_buf, rst_buf, 7)) ++ osal_printtimeofday("############ BT Rest end <--"); ++ } ++ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ ++ /*Send tx ack */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 0); ++ ++ stp_ctx_unlock(&stp_core_ctx); ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, COEX_TASK_INDX); ++ } else { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ STP_WARN_FUNC("BT/WIFI & LTE coex in non-LTE projects,drop it...\n"); ++ } else { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ if (is_function_active == MTK_WCN_BOOL_FALSE) { ++ STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n", ++ stp_core_ctx.parser.type); ++ fgRxOk = 0; /*drop packet */ ++ } else { ++ STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n", ++ stp_core_ctx.parser.type); ++ fgRxOk = 0; /*drop packet */ ++ } ++ stp_ctx_lock(&stp_core_ctx); ++ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ ++ /*Send tx ack */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 0); ++ ++ stp_ctx_unlock(&stp_core_ctx); ++ } ++ ++ /* enqueue successfully */ ++ if (fgRxOk == 0) { ++ stp_process_packet_fail_count = 0; ++ /*notify corresponding subfunction of incoming data */ ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++#if 1 ++ STP_DBG_FUNC ++ ("WMT/LTE package:[0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x]\n", ++ stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], stp_core_ctx.rx_buf[2], ++ stp_core_ctx.rx_buf[3], stp_core_ctx.rx_buf[4], stp_core_ctx.rx_buf[5], ++ stp_core_ctx.rx_buf[6], stp_core_ctx.rx_buf[7]); ++#endif ++ stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ STP_WARN_FUNC("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); ++ } else { ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ stp_process_packet_fail_count++; ++ /*Queue is full */ ++ if (stp_core_ctx.parser.type == GPS_TASK_INDX) { ++ /*Clear Rx Queue if GPS */ ++ mtk_wcn_stp_flush_rx_queue(GPS_TASK_INDX); ++ } else { ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++ /*enqueue fail, don't send ack and wait for peer retry */ ++ STP_ERR_FUNC("Enqueue to Rx queue fail, maybe function %d queue is full\n", ++ stp_core_ctx.parser.type); ++ } ++ } ++ /*sequence not match && previous packet enqueue successfully, send the previous ACK */ ++ else if (fgRxOk == 0) { ++ STP_ERR_FUNC("mtkstp_process_packet: expected_rxseq = %d, parser.seq = %d\n", ++ stp_core_ctx.sequence.expected_rxseq, stp_core_ctx.parser.seq); ++ stp_process_packet_fail_count++; ++ ++ stp_ctx_lock(&stp_core_ctx); ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 1); ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ STP_ERR_FUNC ++ ("sequence not match && previous packet enqueue successfully, send the previous ACK (ack no =%d)\n", ++ txAck); ++ } ++ /*sequence not match && previous packet enqueue failed, do nothing, make the other side timeout */ ++ else { ++ stp_process_packet_fail_count++; ++ STP_ERR_FUNC ++ ("sequence not match && previous packet enqueue failed, do nothing, make the other side timeout\n"); ++ } ++ ++ if (fgTriggerResume == 0) { ++ /*[PatchNeed]Just Notificaiton, not blocking call */ ++ /* notify adaptation layer for possible tx resume mechanism */ ++ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); ++ } ++ ++ if (stp_process_packet_fail_count > MTKSTP_RETRY_LIMIT) { ++ stp_process_packet_fail_count = 0; ++ STP_ERR_FUNC("The process packet fail count > 10 lastly\n\r, whole chip reset\n\r"); ++ mtk_wcn_stp_dbg_dump_package(); ++ /*Whole Chip Reset Procedure Invoke */ ++ /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ stp_dbg_set_host_assert_info(4, 37, 1); ++ STP_INFO_FUNC("**Ack Miss trigger firmware assert**\n"); ++ iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ if (iRet) { ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ /* (*sys_dbg_assert_aee)("[MT662x]Ack Miss", "**STP Ack Miss**\n Ack Miss.\n"); */ ++ osal_dbg_assert_aee("[SOC_CONSYS]Ack Miss", ++ "**[WCN_ISSUE_INFO]STP Ack Miss**\n Ack Miss.\n"); ++ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ } ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_init ++* DESCRIPTION ++* init STP kernel ++* PARAMETERS ++* cb_func [IN] function pointers of system APIs ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func) ++{ ++ INT32 ret = 0; ++ INT32 i = 0; ++ ++ /* Function pointer to point to the currently used transmission interface ++ */ ++ sys_if_tx = cb_func->cb_if_tx; ++ ++ /* Used to inform the function driver has received the corresponding type of information */ ++ sys_event_set = cb_func->cb_event_set; ++ ++ /* Used to inform the function driver can continue to send information and ++ STP has resources to deal with ++ */ ++ sys_event_tx_resume = cb_func->cb_event_tx_resume; ++ ++ /* STP driver determines whether the function is enable. If not enable and ++ STP has received the kind of information, and STP have the right to put it away. ++ */ ++ sys_check_function_status = cb_func->cb_check_funciton_status; ++ ++ /* osal_unsleepable_lock_init(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock_init(&stp_core_ctx); ++ /* Setup timer to be used to check if f/w receive the data in the specific time ++ interval after being sent ++ */ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) ++ osal_unsleepable_lock_init(&stp_core_ctx.ring[i].mtx); ++ ++ stp_core_ctx.tx_timer.timeoutHandler = stp_tx_timeout_handler; ++ stp_core_ctx.tx_timer.timeroutHandlerData = 0; ++ osal_timer_create(&stp_core_ctx.tx_timer); ++ ++ STP_SET_BT_STK(stp_core_ctx, 0); ++ STP_SET_ENABLE(stp_core_ctx, 0); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 0); ++ STP_SET_ENABLE_RST(stp_core_ctx, 0); ++ STP_SET_PENDING_TYPE(stp_core_ctx, 0); ++ STP_SET_READY(stp_core_ctx, 0); ++ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, 0); ++ STP_SET_PSM_CORE(stp_core_ctx, stp_psm_init()); ++ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, 0); ++ STP_ENABLE_FW_COREDUMP(stp_core_ctx, 0); ++ STP_SET_WMT_LAST_CLOSE(stp_core_ctx, 0); ++ STP_SET_EVT_ERR_ASSERT(stp_core_ctx, 0); ++ ++ if (!STP_PSM_CORE(stp_core_ctx)) { ++ ret = (-3); ++ goto ERROR; ++ } ++ ++ STP_SET_BTM_CORE(stp_core_ctx, stp_btm_init()); ++ if (!STP_BTM_CORE(stp_core_ctx)) { ++ STP_ERR_FUNC("STP_BTM_CORE(stp_core_ctx) initialization fail!\n"); ++ ret = (-3); ++ goto ERROR; ++ } ++ ++ if (STP_BTM_CORE(stp_core_ctx) != NULL) ++ g_mtkstp_dbg = stp_dbg_init(STP_BTM_CORE(stp_core_ctx)); ++ else ++ g_mtkstp_dbg = stp_dbg_init(NULL); ++ ++ if (!g_mtkstp_dbg) { ++ STP_ERR_FUNC("g_mtkstp_dbg initialization fail!\n"); ++ ret = (-3); ++ goto ERROR; ++ } ++ STP_SET_ENABLE_RST(stp_core_ctx, 1); ++#ifdef CONFIG_LOG_STP_INTERNAL ++ mtk_wcn_stp_dbg_enable(); ++#else ++ mtk_wcn_stp_dbg_enable(); ++#endif ++ goto RETURN; ++ ++ERROR: ++ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); ++ ++RETURN: ++ return ret; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_deinit ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++INT32 mtk_wcn_stp_deinit(void) ++{ ++ UINT32 i = 0; ++ ++ sys_if_tx = NULL; ++ sys_event_set = NULL; ++ sys_event_tx_resume = NULL; ++ sys_check_function_status = NULL; ++ ++ stp_dbg_deinit(g_mtkstp_dbg); ++ stp_btm_deinit(STP_BTM_CORE(stp_core_ctx)); ++ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); ++ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) ++ osal_unsleepable_lock_deinit(&stp_core_ctx.ring[i].mtx); ++ ++ stp_ctx_lock_deinit(&stp_core_ctx); ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_btm_get_dmp ++* DESCRIPTION ++* get stp dump related information ++* PARAMETERS ++* buffer: dump placement, len: dump size ++* RETURNS ++* 0: Success Negative Value: Fail ++*****************************************************************************/ ++ ++int mtk_wcn_stp_btm_get_dmp(char *buf, int *len) ++{ ++ return stp_dbg_dmp_out(g_mtkstp_dbg, buf, len); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_notify_stp ++* DESCRIPTION ++* WMT notification to STP that power saving job is done or not ++* PARAMETERS ++* ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++int mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action) ++{ ++ return stp_psm_notify_stp(STP_PSM_CORE(stp_core_ctx), action); ++} ++ ++int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state) ++{ ++ return stp_psm_set_state(STP_PSM_CORE(stp_core_ctx), state); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_enable ++* DESCRIPTION ++* enable STP sleep/wakeup support ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep) ++{ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { ++ if (mtk_wcn_stp_is_ready()) ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_DBG_FUNC("PSM is not support under SDIO mode\n"); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ ++#else ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_DBG_FUNC("PSM is not support under SDIO mode\n"); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++#endif ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_disable ++* DESCRIPTION ++* disable STP sleep/wakeup support ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_psm_disable(VOID) ++{ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { ++ if (mtk_wcn_stp_is_ready()) ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ ++#else ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ return 0; ++ } ++ STP_DBG_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return 0; ++ ++#endif ++} ++ ++extern INT32 mtk_wcn_stp_psm_reset(VOID) ++{ ++ return stp_psm_reset(STP_PSM_CORE(stp_core_ctx)); ++} ++ ++extern INT32 mtk_wcn_stp_dbg_disable(VOID) ++{ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx)) { ++ STP_DBG_FUNC("STP dbg mode is turned off\n"); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 0); ++ stp_dbg_disable(g_mtkstp_dbg); ++ } else { ++ STP_WARN_FUNC("STP dbg mode has been turned off\n"); ++ } ++ ++ return 0; ++} ++ ++extern INT32 mtk_wcn_stp_dbg_enable(VOID) ++{ ++ if (STP_NOT_ENABLE_DBG(stp_core_ctx)) { ++ STP_DBG_FUNC("STP dbg mode is turned on\n"); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 1); ++ stp_dbg_enable(g_mtkstp_dbg); ++ } else { ++ STP_WARN_FUNC("STP dbg mode has been turned on\n"); ++ } ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on) ++{ ++ stp_dbg_log_ctrl(on); ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on) ++{ ++ STP_ENABLE_FW_COREDUMP(stp_core_ctx, on); ++ STP_INFO_FUNC("coredump function mode: %d.\n", on); ++ g_coredump_mode = on; ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_coredump_flag_get(VOID) ++{ ++ return STP_ENABLE_FW_COREDUMP_FLAG(stp_core_ctx); ++} ++ ++static INT32 stp_parser_data_in_mand_mode(UINT32 length, UINT8 *p_data) ++{ ++ UINT8 padding_len = 0; ++ INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ ++ MTK_WCN_BOOL is_function_active = 0; ++ INT32 i = length; ++ ++ while (i > 0) { ++ switch (stp_core_ctx.parser.state) { ++ case MTKSTP_SYNC: /* b'10 */ ++ /* if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) */ ++ /* if(*p_data == 0x80) */ ++ if ((*p_data & 0x80) == 0x80) { ++ /* STP_DBG_FUNC("[STP] STP Packet Start =========>\n"); */ ++ if (*p_data != 0x80) ++ STP_WARN_FUNC("SDIO not 0x80!!(0x%x)\n", *p_data); ++ ++ if (i >= 4) { ++#if !(REMOVE_USELESS_LOG) ++ /*print header, when get the full STP header */ ++ UINT32 type = (*(p_data + 1) & 0x70) >> 4; ++ UINT8 *type_name = ""; ++ ++ type_name = stp_type_to_dbg_string(type); ++ STP_DBG_FUNC( ++ "STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", ++ *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), ++ type_name, ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), ++ (*p_data & 0x38) >> 3, *p_data & 0x07); ++#endif ++ } else { ++ STP_WARN_FUNC("STP Rx: discard due to i < 4 (%d)\n", i); ++ } ++ ++ /* STP_DBG_FUNC("[STP] sync->nak\n"); */ ++ stp_change_rx_state(MTKSTP_NAK); ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("sync to sync!!(0x%x)\n", *p_data); ++ stp_change_rx_state(MTKSTP_SYNC); ++ } ++ break; ++ ++ case MTKSTP_NAK: ++ /* STP_DBG_FUNC("[STP] nak->length\n"); */ ++ stp_change_rx_state(MTKSTP_LENGTH); ++ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; ++ if (stp_core_ctx.parser.type <= MTKSTP_MAX_TASK_NUM) { ++ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("nak to sync\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ } ++ break; ++ ++ case MTKSTP_LENGTH: ++ /* STP_DBG_FUNC("[STP] length -> checksum\n"); */ ++ stp_change_rx_state(MTKSTP_CHECKSUM); ++ stp_core_ctx.parser.length += *p_data; ++ ++ /*Valid length checking */ ++ if (stp_core_ctx.parser.length < 2000) { ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("The length of STP packet is not valid !!! length = %d\n", ++ stp_core_ctx.parser.length); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ /* return -1; */ ++ } ++ ++ break; ++ ++ case MTKSTP_CHECKSUM: ++ ++ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || ++ (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_change_rx_state(MTKSTP_FW_MSG); ++ stp_core_ctx.rx_counter = 0; ++ i -= 1; ++ if (i != 0) ++ p_data += 1; ++ ++ continue; ++ } ++ ++ if (stp_core_ctx.parser.length == 0) { ++ STP_WARN_FUNC("checksum to sync\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ } else { ++ /* STP_DBG_FUNC("[STP] checksum->data\n"); */ ++ stp_change_rx_state(MTKSTP_DATA); ++ stp_core_ctx.rx_counter = 0; ++ } ++ break; ++ ++ case MTKSTP_DATA: ++ ++ /* block copy instead of byte copy */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ /*boundary checking */ ++ if (stp_core_ctx.rx_counter + remain_length >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC("Abnormal!! Memory operation over boundary!!\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_core_ctx.parser.state = MTKSTP_CRC1; ++ continue; ++ ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ /*boundary checking */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC("Abnormal!! Memory operation over boundary 2!!\n"); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++ break; ++ ++ case MTKSTP_CRC1: ++ stp_change_rx_state(MTKSTP_CRC2); ++ break; ++ ++ case MTKSTP_CRC2: ++#if 1 ++ if (stp_core_ctx.parser.type == WMT_TASK_INDX) { ++ stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; ++ STP_DBG_FUNC("wmt sub type (0x%x)\n", stp_core_ctx.parser.wmtsubtype); ++ } ++#endif ++ /*SDIO mode do it. */ ++ if (mtk_wcn_stp_is_sdio_mode()) { ++ /*STP packet 4-bytes alignment */ ++ /*Discard padding bytes , otherwise make parser state machine disorder */ ++ if (i <= 4) { ++ /*STP_DBG_FUNC("STP last block padding %d bytes\n", i-1); */ ++ p_data += (i - 1); ++ i -= (i - 1); ++ } else { ++ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; ++ p_data += padding_len; ++ i -= padding_len; ++ /*STP_DBG_FUNC("STP Agg padding %d bytes\n", padding_len); */ ++ } ++ } ++ stp_dbg_pkt_log(stp_core_ctx.parser.type, ++ 0, 0, 0, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if ((stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { ++ int b; ++ ++ /*Indicate packet to hci_stp */ ++ if (gStpDbgLvl >= STP_LOG_DBG) { ++ stp_dump_data(stp_core_ctx.rx_buf, "indicate_to_bt_core", ++ stp_core_ctx.rx_counter); ++ } ++ ++ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if (b) ++ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); ++ ++ } else { ++ ++ is_function_active = ( ++ (*sys_check_function_status)(stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) ++ == STATUS_FUNCTION_ACTIVE); ++ ++ /*check type and function if active? */ ++ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) ++ && (is_function_active == MTK_WCN_BOOL_TRUE)) { ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) ++ && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { ++ STP_INFO_FUNC("wmt/lte coex package!\n"); ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, COEX_TASK_INDX); ++ stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) ++ && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { ++ STP_WARN_FUNC ++ ("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); ++ } else { ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ if (is_function_active == MTK_WCN_BOOL_FALSE) { ++ STP_ERR_FUNC ++ ("function type = %d is inactive, so no en-queue to rx\n", ++ stp_core_ctx.parser.type); ++ } else { ++ STP_ERR_FUNC ++ ("mtkstp_process_packet: type = %x, the type is invalid\n", ++ stp_core_ctx.parser.type); ++ } ++ } ++ } ++ ++ /* STP_DBG_FUNC("[STP] crc2->sync\n"); */ ++ /* STP_DBG_FUNC("[STP] STP Packet End <=========\n"); */ ++ stp_core_ctx.rx_counter = 0; ++ stp_change_rx_state(MTKSTP_SYNC); ++ ++ break; ++ ++ case MTKSTP_FW_MSG: ++ ++ /*f/w assert and exception information */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ } ++ ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; ++ /*Trace32 Dump */ ++ if (stp_core_ctx.parser.type == STP_TASK_INDX) { ++ /* g_block_tx = 1; */ ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ pr_debug("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type, stp_core_ctx.rx_buf); ++ /*use paged dump or full dump */ ++ stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); ++#if 0 ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_DMP /*STP_DBG_FW_ASSERT */ , 5, ++ 0, 0, 0, 0, ++ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); ++#endif ++ } ++ ++ /*discard CRC */ ++ /* we will discard antoher CRC on the outer switch procedure. */ ++ if (i >= 1) { ++ STP_INFO_FUNC("crc discard.. i = %d\n", i); ++ i -= 1; ++ if (i > 0) ++ p_data += 1; ++ ++ } ++ ++ /*STP packet 4-bytes alignment */ ++ /*Discard padding bytes , otherwise make parser state machine disorder */ ++ if (i <= 4) { ++ STP_INFO_FUNC ++ ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", ++ i - 1); ++ p_data += (i - 1); ++ i -= (i - 1); ++ } else { ++ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; ++ p_data += padding_len; ++ i -= padding_len; ++ STP_INFO_FUNC ++ ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n", ++ padding_len); ++ } ++ stp_change_rx_state(MTKSTP_SYNC); ++ ++ } else { /* only copy by data length */ ++ ++ STP_ERR_FUNC("raw data doesn't contain full stp packet!!\n"); ++ } ++ break; ++ default: ++ break; ++ } ++ p_data++; ++ i--; ++ } ++ ++ return 0; ++} ++ ++static INT32 stp_parser_data_in_full_mode(UINT32 length, UINT8 *p_data) ++{ ++ INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ ++ INT32 i = length; ++ ++ while (i > 0) { ++ switch (stp_core_ctx.parser.state) { ++ ++ case MTKSTP_RESYNC1: /* RESYNC must be 4 _continuous_ 0x7f */ ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC2); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC2: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC3); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC3: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC4); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC4: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_SYNC); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_SYNC: /* b'10 */ ++ STP_DUMP_PACKET_HEAD(p_data, "rx (uart):", length > 4 ? 4 : length); ++ if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) { ++ stp_change_rx_state(MTKSTP_NAK); ++ stp_core_ctx.parser.seq = (*p_data & 0x38) >> 3; ++ stp_core_ctx.parser.ack = *p_data & 0x07; ++ stp_core_ctx.rx_buf[0] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /* stp_core_ctx.rx_counter++; */ ++ ++ if (i >= 4 && gStpDbgLvl >= STP_LOG_DBG) { ++ /*print header, when get the full STP header */ ++#if !(REMOVE_USELESS_LOG) ++ int type = (*(p_data + 1) & 0x70) >> 4; ++ char *type_name = ""; ++ ++ type_name = stp_type_to_dbg_string(type); ++ ++ STP_DBG_FUNC ++ ("STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", ++ *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), type_name, ++ ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), ++ (*p_data & 0x38) >> 3, *p_data & 0x07); ++#endif ++ } else { ++ STP_DBG_FUNC("STP Rx: discard due to i < 4\n"); ++ } ++ } else if ((*p_data == 0x7f) && (prev_state == MTKSTP_RESYNC4)) { ++ /* if this 0x7f is continuous to resync pattern */ ++ /* skip this continuous 0x7f, remain current & prev state */ ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: continuous resync pattern, buff = %x\n", *p_data); ++ } else if (*p_data == 0x7f) { /* a start of 0x7f, maybe this is resync pattern */ ++ stp_change_rx_state(MTKSTP_RESYNC2); ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: go to MTKSTP_RESYNC2, buff = %x\n", *p_data); ++ } else if (*p_data == 0x55) { /* STP delimiter */ ++ /* do nothing for delimiter */ ++ } else { /* unexpected, go to resync1 */ ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: unexpected data, buff = %x\n", *p_data); ++ } ++ break; ++ ++ case MTKSTP_NAK: ++ /* (*sys_dbg_print)("MTKSTP_NAK : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ if (fgEnableNak == 0) ++ stp_core_ctx.parser.nak = 0; /* disable NAK */ ++ else ++ stp_core_ctx.parser.nak = (*p_data & 0x80) >> 7; ++ ++ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; ++ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; ++ stp_core_ctx.rx_buf[1] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /*stp_core_ctx.rx_counter++; */ ++ if (stp_core_ctx.parser.nak) ++ STP_ERR_FUNC("MTKSTP_NAK TRUE: mtk_wcn_stp_parser_data, buff = %x\n", *p_data); ++ ++ if (stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) ++ stp_change_rx_state(MTKSTP_LENGTH); ++ else ++ stp_change_rx_state(MTKSTP_SYNC); ++ break; ++ ++ case MTKSTP_LENGTH: ++ /* (*sys_dbg_print)("MTKSTP_LENGTH : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ stp_change_rx_state(MTKSTP_CHECKSUM); ++ stp_core_ctx.parser.length += *p_data; ++ ++ /*Valid length checking */ ++ if (stp_core_ctx.parser.length > 2048) { ++ STP_ERR_FUNC("The length of STP packet is not valid !!! length = %d\n", ++ stp_core_ctx.parser.length); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ STP_TRACE_FUNC("--\n"); ++ return -1; ++ } ++ ++ stp_core_ctx.rx_buf[2] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /*stp_core_ctx.rx_counter++; */ ++ break; ++ ++ case MTKSTP_CHECKSUM: ++ /* (*sys_dbg_print)("MTKSTP_CHECKSUM : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || ++ (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_change_rx_state(MTKSTP_FW_MSG); ++ stp_core_ctx.rx_counter = 0; ++ i -= 1; ++ if (i != 0) ++ p_data += 1; ++ ++ continue; ++ } ++ ++ if (((stp_core_ctx.rx_buf[0] + ++ stp_core_ctx.rx_buf[1] + stp_core_ctx.rx_buf[2]) & 0xff) == *p_data) { ++ /* header only packet */ ++ if (stp_core_ctx.parser.length == 0) { ++ INT32 fgTriggerResume = (-1); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ if (stp_core_ctx.inband_rst_set == 0) { ++ stp_dbg_pkt_log(STP_TASK_INDX, ++ stp_core_ctx.parser.ack, ++ stp_core_ctx.parser.seq, ++ 5, /* STP type id */ ++ PKT_DIR_RX, ++ NULL, ++ 0); ++ fgTriggerResume = stp_process_rxack(); ++ } else { ++ STP_WARN_FUNC ++ ("Now it's inband reset process and drop ACK packet.\n"); ++ } ++ ++ if (fgTriggerResume == 0) { ++ /* notify adaptation layer for ++ * possible tx resume mechanism ++ */ ++ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); ++ } ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ } else { ++ stp_change_rx_state(MTKSTP_DATA); ++ stp_core_ctx.rx_counter = 0; ++ } ++ } else { ++ STP_ERR_FUNC("The checksum of header is error !!! %02x %02x %02x %02x\n", ++ stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], ++ stp_core_ctx.rx_buf[2], *p_data); ++ /* George FIXME: error handling mechanism shall be refined */ ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ ++ /* since checksum error is usually related to interface ++ * buffer overflow, so we just let timeout mechanism to ++ * handle such error. ++ */ ++ STP_TRACE_FUNC("--\n"); ++ /* return and purge COMM port */ ++ return -1; ++ /*stp_send_ack(1); NAK mechanism is removed */ ++ } ++ break; ++ ++ case MTKSTP_DATA: ++#if 0 ++ if (stp_core_ctx.rx_counter < stp_core_ctx.parser.length) { ++ stp_core_ctx.rx_buf[stp_core_ctx.rx_counter] = *p_data; ++ stp_core_ctx.rx_counter++; ++ } ++ if (stp_core_ctx.rx_counter == stp_core_ctx.parser.length) ++ stp_change_rx_state(MTKSTP_CRC1); ++#else ++ /* block copy instead of byte copy */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_core_ctx.parser.state = MTKSTP_CRC1; ++ continue; ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC ++ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ STP_TRACE_FUNC("--\n"); ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++#endif ++ break; ++ ++ case MTKSTP_CRC1: ++ stp_change_rx_state(MTKSTP_CRC2); ++ stp_core_ctx.parser.crc = *p_data; ++ break; ++ case MTKSTP_CRC2: ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.parser.crc += (*p_data) << 8; ++#if 1 ++ if (stp_core_ctx.parser.type == WMT_TASK_INDX) { ++ stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; ++ STP_DBG_FUNC("wmt sub type is (0x%x)\n", stp_core_ctx.parser.wmtsubtype); ++ } ++#endif ++ if (stp_check_crc(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, stp_core_ctx.parser.crc) ++ == MTK_WCN_BOOL_TRUE) { ++ if (stp_core_ctx.inband_rst_set == 0) ++ stp_process_packet(); ++ else ++ STP_WARN_FUNC("Now it's inband reset process and drop packet.\n"); ++ } else { ++ STP_ERR_FUNC("The CRC of packet is error !!!\n"); ++ /* George FIXME: error handling mechanism shall be refined */ ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ ++ /* since checksum error is usually related to interface ++ * buffer overflow, so we just let timeout mechanism to ++ * handle such error. ++ */ ++ STP_TRACE_FUNC("--\n"); ++ /* return and purge COMM port */ ++ return -1; ++ /*stp_send_ack(1); NAK mechanism is removed */ ++ } ++ break; ++ ++ case MTKSTP_FW_MSG: ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ if (STP_IS_READY(stp_core_ctx)) ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ STP_SET_READY(stp_core_ctx, 0); ++ /*stp inband reset */ ++ if (stp_core_ctx.parser.type == STP_TASK_INDX && ++ stp_core_ctx.parser.seq == 0 && ++ stp_core_ctx.parser.ack == 0 && ++ stp_core_ctx.parser.length == 0 && stp_core_ctx.inband_rst_set == 1) { ++ STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r"); ++ stp_rest_ctx_state(); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.inband_rst_set = 0; ++ /* STP_INFO_FUNC("Restart STP Timer\n\r"); */ ++ /* (*sys_timer_start)(stp_core_ctx.tx_timer, ++ * mtkstp_tx_timeout, ++ * (MTK_WCN_TIMER_CB)stp_tx_timeout_handler, ++ * NULL); ++ */ ++ STP_TRACE_FUNC("--\n"); ++ return 0; ++ } ++ ++ /*f/w assert and exception information */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_change_rx_state(MTKSTP_SYNC); ++ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; ++ /* STP_ERR_FUNC("%s [%d]\n", stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); */ ++#if 0 ++ if ((stp_core_ctx.rx_counter == 1) && (stp_core_ctx.rx_buf[0] == 0xFF)) { ++ /* For MT6620, enable/disable coredump function is controlled by ++ * firmware for the moment, we need to set coredump enable flag ++ * to be 1 after see firmware send a pariticallar character(0xff) ++ * before any coredump packet is sent ++ */ ++ mtk_wcn_stp_coredump_flag_ctrl(1); ++ } ++#endif ++ /*Trace32 Dump */ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx) && ++ (stp_core_ctx.parser.type == STP_TASK_INDX)) { ++ if (0 != stp_core_ctx.rx_counter) { ++ STP_SET_READY(stp_core_ctx, 0); ++ mtk_wcn_stp_ctx_save(); ++ STP_INFO_FUNC("++ start to read paged dump and paged trace ++\n"); ++ stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); ++ stp_btm_notify_wmt_trace_wq(stp_core_ctx.btm); ++ STP_INFO_FUNC("++ start to read paged dump and paged trace --\n"); ++ ++ } ++ STP_INFO_FUNC("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type, stp_core_ctx.rx_buf); ++ } ++ ++ /*Runtime FW Log */ ++ else if (STP_IS_ENABLE_DBG(stp_core_ctx) ++ && (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0, ++ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); ++ mtk_wcn_stp_dbg_dump_package(); ++ } ++ /*Normal mode: whole chip reset */ ++ else { ++ /*Aee Kernel Warning Message Shown First */ ++ /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */ ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf); ++ /*Whole Chip Reset Procedure Invoke */ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC ++ ("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ /*discard CRC */ ++ if (i >= 2) { ++ STP_DBG_FUNC("crc discard.. i = %d\n", i); ++ i -= 2; ++ if (i > 0) ++ p_data += 2; ++ } ++ continue; ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC ++ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++ ++ break; ++ default: ++ break; ++ } ++ p_data++; ++ i--; ++ } ++ ++ return 0; ++} ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* int 0 = success; -1 = crc/checksum error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++int _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) ++#else ++int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) ++#endif ++{ ++ /*----------------------------------------------------------------*/ ++ /* Local Variables */ ++ /*----------------------------------------------------------------*/ ++ INT32 i; ++ UINT8 *p_data; ++ INT32 ret = 0; ++#ifdef DEBUG_DUMP_PACKET_HEAD ++ static UINT32 counter; ++ ++ STP_TRACE_FUNC("++, rx (cnt=%d,len=%d)\n", ++counter, length); ++#endif ++ ++#if 0 ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ if (stp_is_apply_powersaving()) { ++ /* If now chip is awake, to restart monitor! */ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ STP_DBG_FUNC("To restart moinotr when rx\n\r"); ++ stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } ++#endif ++#endif ++ ++ /*----------------------------------------------------------------*/ ++ /* Code Body */ ++ /*----------------------------------------------------------------*/ ++ /* George FIXME: WHY or HOW can we reduct the locked region? */ ++ /*flags = (*sys_mutex_lock)(stp_core_ctx.stp_mutex); */ ++ i = length; ++ p_data = (UINT8 *) buffer; ++ ++/* stp_dump_data(buffer, "rx queue", length); */ ++ ++ /*STP is not enabled and only WMT can use Raw data path */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == STP_PENDING_TYPE(stp_core_ctx)) { ++ /* route to task who send command */ ++ stp_add_to_rx_queue(buffer, length, STP_PENDING_TYPE(stp_core_ctx)); ++ ++ /* mike: notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (STP_PENDING_TYPE(stp_core_ctx)); ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++#if !(REMOVE_USELESS_LOG) ++ if (gStpDbgLvl >= STP_LOG_DBG) ++ stp_dump_data(buffer, "sdio parser_in", length); ++#endif ++ /* STP_DBG_FUNC("sdio stp parser data length = %d\n", length); */ ++ ret = stp_parser_data_in_mand_mode(i, p_data); ++ } ++ /* STP over UART */ ++ else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) ++ ret = stp_parser_data_in_full_mode(i, p_data); ++ ++ /* George FIXME: WHY or HOW can we reduct the locked region? */ ++ /*(*sys_mutex_unlock)(stp_core_ctx.stp_mutex, flags); */ ++ STP_TRACE_FUNC("--\n"); ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_parser_data); ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_enable ++* DESCRIPTION ++* enable/disable STP ++* PARAMETERS ++* value [IN] 0=disable, others=enable ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_enable(INT32 value) ++{ ++ STP_DBG_FUNC("%s: set the current enable = (%d)\n", __func__, value); ++ ++ stp_rest_ctx_state(); ++ STP_SET_ENABLE(stp_core_ctx, value); ++ if (!value) { ++ mtk_wcn_stp_psm_reset(); ++ } else { ++/* g_block_tx = 0; */ ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ } ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_dbg_dump_package(VOID) ++{ ++ if (STP_NOT_ENABLE(stp_core_ctx)) { ++ STP_INFO_FUNC("STP dbg mode is off\n"); ++ ++ } else { ++ STP_INFO_FUNC("STP dbg mode is on\n"); ++ /* if (0 == g_block_tx) */ ++ if (0 == mtk_wcn_stp_coredump_start_get()) { ++ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); ++ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); ++ stp_dbg_dmp_printk(g_mtkstp_dbg); ++ } else { ++ STP_INFO_FUNC("assert start flag is set, disable packet dump function\n"); ++ } ++ } ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_ready ++* DESCRIPTION ++* ready/un-ready STP ++* PARAMETERS ++* value [IN] 0=un-ready, others=ready ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_ready(INT32 value) ++{ ++ STP_DBG_FUNC("set ready (%d)\n", value); ++ ++ STP_SET_READY(stp_core_ctx, value); ++ /*if whole chip reset, reset the debuggine mode */ ++#ifndef CONFIG_LOG_STP_INTERNAL ++ /* mtk_wcn_stp_dbg_disable(); */ ++#endif ++ ++ if (stp_is_apply_powersaving()) { ++ STP_INFO_FUNC("Restart the stp-psm monitor !!\n"); ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_ctrl ++* DESCRIPTION ++* set f/w assert flag in STP context ++* PARAMETERS ++* value [IN] 0=assert end, others=assert begins ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value) ++{ ++ STP_DBG_FUNC("set f/w assert (%d)\n", value); ++ ++ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, value); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get f/w assert flag in STP context ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0= f/w assert flag is not set, others=f/w assert flag is set ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_coredump_start_get(VOID) ++#else ++INT32 mtk_wcn_stp_coredump_start_get(VOID) ++#endif ++{ ++ return STP_FW_COREDUMP_FLAG(stp_core_ctx); ++} ++ ++/* mtk_wcn_stp_set_wmt_last_close -- set the state of link(UART or SDIO) ++ * @ value - 1, link already be closed; 0, link is open ++ * ++ * Return 0 if success; else error code ++ */ ++INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value) ++{ ++ STP_INFO_FUNC("set wmt_last_close flag (%d)\n", value); ++ ++ STP_SET_WMT_LAST_CLOSE(stp_core_ctx, value); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 > 0: length transmitted; = 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#else ++INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#endif ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; ++ UINT8 *p_tx_buf = NULL; ++ UINT16 crc; ++ INT32 ret = 0; ++ MTK_WCN_BOOL is_quick_enable = MTK_WCN_BOOL_TRUE; ++ ++ /* osal_buffer_dump(buffer,"tx", length, 32); */ ++ ++ if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { ++ STP_ERR_FUNC("WMT lats close,should not have tx request!\n"); ++ return length; ++ } ++ /* if(g_block_tx) */ ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ STP_ERR_FUNC("STP fw coredump start flag set...\n"); ++ return length; ++ } ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ is_quick_enable = stp_psm_is_quick_ps_support(); ++ STP_DBG_FUNC("is quick sleep enable:%s\n", is_quick_enable ? "yes" : "no"); ++ if (MTK_WCN_BOOL_TRUE == is_quick_enable) { ++ if (type != WMT_TASK_INDX) { ++#if PSM_USE_COUNT_PACKAGE ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0); ++#else ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0, length); ++#endif ++ } ++ /* if(stp_is_apply_powersaving()) */ ++ { ++ if (type == WMT_TASK_INDX) ++ goto DONT_MONITOR; ++ /*-----------------------------STP_PSM_Lock----------------------------------------*/ ++ ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { ++ STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); ++ stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } else { ++ ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); ++ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); ++ /*-----------------------------STP_PSM_UnLock----------------------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ return ret; ++ } ++ } ++ } else { ++ /* if(stp_is_apply_powersaving()) */ ++ { ++ if (type == WMT_TASK_INDX) ++ goto DONT_MONITOR; ++ /* If now chip is awake, to restart monitor! */ ++ /* STP_INFO_FUNC("check if block traffic !!\n"); */ ++ /*-----------------------------STP_PSM_Lock----------------------------------------*/ ++ ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ /* STP_INFO_FUNC("not to block !!\n"); */ ++ if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { ++ STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); ++ stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); ++ } ++ stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); ++ } else { ++ /* STP_INFO_FUNC("to block !!\n"); */ ++ ++ /* STP_INFO_FUNC("*****hold data in psm queue data length = %d\n", ++ * length); ++ */ ++ /* stp_dump_data(buffer, "Hold in psm queue", length); */ ++ /* hold datas */ ++ ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); ++ /* wmt notification */ ++ STP_INFO_FUNC("#####Type = %d, to inform WMT to wakeup chip, ret = %d:0x%2x,0x%2x\n", ++ type, ret, *buffer, *(buffer + 1)); ++ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); ++ /* STP_INFO_FUNC("*********Type = %d, to inform WMT to wakeup chip>end\n", type); */ ++ /*-----------------------------STP_PSM_UnLock----------------------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ return ret; ++ } ++ } ++ } ++DONT_MONITOR: ++#endif ++ if (type == BT_TASK_INDX) { ++ static const UINT8 rst_buf[4] = { 0x01, 0x03, 0x0c, 0x00 }; ++ ++ if (!osal_strncmp(buffer, rst_buf, 4)) ++ osal_printtimeofday("############ BT Rest start -->"); ++ } ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ /*Only WMT can set raw data */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { ++ /* no-op */ ++ /* NULL; */ ++ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { ++ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ ++ /* NULL; */ ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ /* osal_printtimeofday("[ STP][SDIO][ B][W]"); */ ++ ++ mtkstp_header[0] = 0x80; ++ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); ++ mtkstp_header[2] = (length) & 0xff; ++ mtkstp_header[3] = 0x00; ++ ++ /* HEADER */ ++ p_tx_buf = &stp_core_ctx.tx_buf[0]; ++ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); ++ p_tx_buf += MTKSTP_HEADER_SIZE; ++ ++ /* PAYLOAD */ ++ osal_memcpy(p_tx_buf, buffer, length); ++ p_tx_buf += length; ++ ++ /* CRC */ ++ temp[0] = 0x00; ++ temp[1] = 0x00; ++ osal_memcpy(p_tx_buf, temp, 2); ++ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length); ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); ++ ++ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { ++ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); ++ osal_assert(0); ++ ret = 0; ++ } else { ++ ret = (INT32) length; ++ } ++ ++ /* osal_printtimeofday("[ STP][SDIO][ E][W]"); */ ++ } ++ /* STP over UART */ ++ else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ /* osal_printtimeofday("[ STP][UART][ B][W]"); */ ++ /* STP_INFO_FUNC("Write byte %d\n", length); */ ++ ++ if ((stp_core_ctx.sequence.winspace > 0) && ++ (stp_core_ctx.inband_rst_set == 0) && ++ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { ++ /*Make Header */ ++ /* (*sys_dbg_print)("mtk_wcn_stp_send_data 1, txseq = %d, winspace = %d", ++ * stp_core_ctx.sequence.txseq, stp_core_ctx.sequence.winspace); ++ */ ++ mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; ++ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); ++ mtkstp_header[2] = length & 0xff; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; ++ if (fgEnableDelimiter == 1) { ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; ++ stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); ++ } ++ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); ++ ++ /*Make Payload */ ++ stp_add_to_tx_queue(buffer, length); ++ ++ /*Make CRC */ ++ crc = osal_crc16(buffer, length); ++ temp[0] = crc & 0xff; ++ temp[1] = (crc & 0xff00) >> 8; ++ stp_add_to_tx_queue(temp, 2); ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); ++ ++ /*Kick to UART */ ++ stp_send_tx_queue(stp_core_ctx.sequence.txseq); ++ ++ INDEX_INC(stp_core_ctx.sequence.txseq); ++ stp_core_ctx.sequence.winspace--; ++ ++ /*Setup the Retry Timer */ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ else ++ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); ++ ++ ret = (INT32) length; ++ } else { ++ /* ++ No winspace to send. Let caller retry ++ */ ++ if (stp_core_ctx.inband_rst_set == 1) ++ STP_WARN_FUNC("Now it's inband reset process and drop sent packet.\n"); ++ else ++ STP_ERR_FUNC("There is no winspace/txqueue to send !!!\n"); ++ ++ ret = 0; ++ } ++ ++ /* osal_printtimeofday("[ STP][UART][ E][W]"); */ ++ } ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ ++ if (MTK_WCN_BOOL_TRUE == is_quick_enable) { ++ if (type != WMT_TASK_INDX) { ++ stp_psm_notify_wmt_sleep(STP_PSM_CORE(stp_core_ctx)); ++ /*-----------------------STP_PSM_UnLock-------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } else { ++ /* if(stp_is_apply_powersaving()) */ ++ /* { */ ++ if (type != WMT_TASK_INDX) { ++ ++ /*--------------------STP_PSM_UnLock--------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ } ++ /* } */ ++ } ++#endif ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_send_data); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* send raw data to common interface, bypass STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#else ++INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#endif ++{ ++ UINT32 written = 0; ++ INT32 ret = 0; ++ ++ if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { ++ STP_ERR_FUNC("WMT lats close,should not have tx request!"); ++ return length; ++ } ++ ++ STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d, data = %x %x %x %x %x %x ", type, buffer[0], buffer[1], ++ buffer[2], buffer[3], buffer[4], buffer[5]); ++ STP_SET_PENDING_TYPE(stp_core_ctx, type); /* remember tx type, forward following rx to this type */ ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, 1); ++ (*sys_if_tx) (&buffer[0], length, &written); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ ++ if (written == 0) ++ stp_dump_data(&buffer[0], "tx raw failed:", length); ++ ++ if (written == length) ++ ret = (INT32) written; ++ else ++ ret = (-1); ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) ++#else ++INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) ++#endif ++{ ++ /* GeorgeKuo modify: reduce "if" branch */ ++ UINT16 copyLen = 0; ++ UINT16 tailLen = 0; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ while (stp_core_ctx.ring[type].read_p != stp_core_ctx.ring[type].write_p) { ++ /* GeorgeKuo modify: reduce if branch */ ++ if (stp_core_ctx.ring[type].write_p > stp_core_ctx.ring[type].read_p) { ++ copyLen = stp_core_ctx.ring[type].write_p - stp_core_ctx.ring[type].read_p; ++ if (copyLen > length) ++ copyLen = length; ++ ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, copyLen); ++ stp_core_ctx.ring[type].read_p += copyLen; ++ } else { ++ tailLen = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].read_p; ++ if (tailLen > length) { /* exclude equal case to skip wrap check */ ++ copyLen = length; ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, ++ copyLen); ++ stp_core_ctx.ring[type].read_p += copyLen; ++ } else { ++ /* part 1: copy tailLen */ ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, ++ tailLen); ++ ++ buffer += tailLen; /* update buffer offset */ ++ ++ /* part 2: check if head length is enough */ ++ copyLen = length - tailLen; ++ copyLen = ++ (stp_core_ctx.ring[type].write_p < ++ copyLen) ? stp_core_ctx.ring[type].write_p : copyLen; ++ ++ if (copyLen) ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + 0, copyLen); ++ ++ /* Update read_p final position */ ++ stp_core_ctx.ring[type].read_p = copyLen; ++ ++ /* update return length: head + tail */ ++ copyLen += tailLen; ++ } ++ } ++ break; ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if ((MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) && (type != WMT_TASK_INDX)) { ++#if PSM_USE_COUNT_PACKAGE ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1); ++#else ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1, copyLen); ++#endif ++ } ++ ++ return copyLen; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_receive_data); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++#else ++INT32 mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++#endif ++{ ++ INT32 ret; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if (stp_core_ctx.ring[type].read_p == stp_core_ctx.ring[type].write_p) ++ ret = 1; /* queue is empty */ ++ else ++ ret = 0; /* queue is not empty */ ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_set_sdio_mode ++* DESCRIPTION ++* Set stp for SDIO mode ++* PARAMETERS ++* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) ++* RETURNS ++* void ++*****************************************************************************/ ++ ++void mtk_wcn_stp_set_mode(UINT32 mode) ++{ ++ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, mode); ++ ++ STP_DBG_FUNC("STP_SUPPORT_PROTOCOL = %08x\n", STP_SUPPORT_PROTOCOL(stp_core_ctx)); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_fullset_mode ++* DESCRIPTION ++* Is stp use UART fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:Uart Fullset mode, FALSE:Not UART Fullset mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_FULL_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_mand_mode ++* DESCRIPTION ++* Is stp use UART mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:Uart Mandatory mode, FALSE:Not UART Mandotary mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_MAND_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_fullset_mode ++* DESCRIPTION ++* Is stp use BTIF fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Fullset mode, FALSE:Not BTIF Fullset mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void) ++{ ++ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_FULL_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_mand_mode ++* DESCRIPTION ++* Is stp use BTIF mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Mandatory mode, FALSE:Not BTIF Mandotary mode ++*****************************************************************************/ ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void) ++{ ++ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_MAND_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_sdio_mode ++* DESCRIPTION ++* Is stp use SDIO mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_SDIO_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To sync to oringnal stp state with f/w stp ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++void mtk_wcn_stp_inband_reset(void) ++{ ++ UINT8 inband_reset_packet[64]; ++ UINT32 txseq = 0; ++ UINT32 txack = 0; ++ UINT32 crc = 0; ++ UINT32 ret = 0; ++ UINT32 reset_payload_len = 0; ++ ++ /*512 bytes */ ++ UINT8 reset_payload[] = { ++ 0xc0, 0x01, 0xc0, 0xde, 0x3e, 0xd1, 0xa7, 0xef ++ }; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*RESYNC*/ inband_reset_packet[0] = 0x7f; ++ inband_reset_packet[1] = 0x7f; ++ inband_reset_packet[2] = 0x7f; ++ inband_reset_packet[3] = 0x7f; ++ inband_reset_packet[4] = 0x7f; ++ inband_reset_packet[5] = 0x7f; ++ inband_reset_packet[6] = 0x7f; ++ inband_reset_packet[7] = 0x7f; ++ ++ /*header */ ++ reset_payload_len = sizeof(reset_payload) / sizeof(reset_payload[0]); ++ inband_reset_packet[8] = 0x80 + (txseq << 3) + txack; ++ inband_reset_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); ++ inband_reset_packet[10] = reset_payload_len & 0xff; ++ inband_reset_packet[11] = (inband_reset_packet[8] + inband_reset_packet[9] + inband_reset_packet[10]) & 0xff; ++ ++ /*payload */ ++ osal_memcpy(&inband_reset_packet[12], reset_payload, reset_payload_len); ++ ++ /*crc */ ++ crc = osal_crc16(&reset_payload[0], reset_payload_len); ++ inband_reset_packet[12 + reset_payload_len] = crc & 0xff; ++ inband_reset_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; ++ ++ (*sys_if_tx) (&inband_reset_packet[0], 14 + reset_payload_len, &ret); ++ ++ if (ret != (14 + reset_payload_len)) ++ STP_ERR_FUNC("Inband sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, ret); ++ ++ stp_core_ctx.inband_rst_set = 1; ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++} ++ ++void mtk_wcn_stp_debug_ctrl(INT32 op, INT32 filter, INT32 filter_param) ++{ ++ /*nothing at now*/ ++} ++ ++void mtk_wcn_stp_test_cmd(INT32 cmd_no) ++{ ++ UINT8 test_packet[64]; ++ UINT32 txseq = 0; ++ UINT32 txack = 0; ++ UINT32 crc = 0; ++ UINT32 ret = 0; ++ UINT32 reset_payload_len = 0; ++ ++ UINT8 test_payload[] = { ++ 0xAA, 0xAA, 0xC0, 0xDE, 0x3E, 0xD1, 0xA7, 0xEF ++ }; ++/* */ ++/* select your test command by cmd_no */ ++/* */ ++ if (cmd_no == 0) { ++ /* to test new command to chip */ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*RESYNC*/ test_packet[0] = 0x7f; ++ test_packet[1] = 0x7f; ++ test_packet[2] = 0x7f; ++ test_packet[3] = 0x7f; ++ test_packet[4] = 0x7f; ++ test_packet[5] = 0x7f; ++ test_packet[6] = 0x7f; ++ test_packet[7] = 0x7f; ++ ++ /*header */ ++ reset_payload_len = sizeof(test_payload) / sizeof(test_payload[0]); ++ test_packet[8] = 0x80 + (txseq << 3) + txack; ++ test_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); ++ test_packet[10] = reset_payload_len & 0xff; ++ test_packet[11] = (test_packet[8] + test_packet[9] + test_packet[10]) & 0xff; ++ ++ /*payload */ ++ osal_memcpy(&test_packet[12], test_payload, reset_payload_len); ++ ++ /*crc */ ++ crc = osal_crc16(&test_payload[0], reset_payload_len); ++ test_packet[12 + reset_payload_len] = crc & 0xff; ++ test_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; ++ ++ (*sys_if_tx) (&test_packet[0], 14 + reset_payload_len, &ret); ++ if (ret != (14 + reset_payload_len)) { ++ STP_ERR_FUNC("stp test sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, ++ ret); ++ } ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush_context ++* DESCRIPTION ++* Flush STP Context ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++void mtk_wcn_stp_flush_context(void) ++{ ++ stp_rest_ctx_state(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush_rx_queue ++* DESCRIPTION ++* Flush STP Rx Queue ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++ ++void mtk_wcn_stp_flush_rx_queue(UINT32 type) ++{ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ if (type < MTKSTP_MAX_TASK_NUM) { ++ stp_core_ctx.ring[type].read_p = 0; ++ stp_core_ctx.ring[type].write_p = 0; ++ } ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* STP is ready? ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void) ++#else ++MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) ++#endif ++{ ++ return STP_IS_READY(stp_core_ctx); ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_is_ready); ++#endif ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) ++#else ++void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) ++#endif ++{ ++ /* g_mtkstp_bluez_flag = bluez_flag; */ ++ STP_SET_BT_STK(stp_core_ctx, bluez_flag); ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); ++#endif ++/***************************************************************************** ++* FUNCTION ++* set stp debugging mdoe ++* DESCRIPTION ++* set stp debugging mdoe ++* PARAMETERS ++* dbg_mode: switch to dbg mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode) ++{ ++ STP_SET_ENABLE_DBG(stp_core_ctx, dbg_mode); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* set stp auto reset mdoe ++* DESCRIPTION ++* set stp auto reset mdoe ++* PARAMETERS ++* auto_rst: switch to auto reset mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst) ++{ ++ STP_SET_ENABLE_RST(stp_core_ctx, auto_rst); ++} ++ ++INT32 mtk_wcn_stp_notify_sleep_for_thermal(void) ++{ ++ return stp_psm_sleep_for_thermal(STP_PSM_CORE(stp_core_ctx)); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_open_btif ++* DESCRIPTION ++* init btif hw & sw by owner stp ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_open_btif(VOID) ++{ ++ return mtk_wcn_consys_stp_btif_open(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_open_close ++* DESCRIPTION ++* close btif hw & sw by owner stp ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_close_btif(VOID) ++{ ++ return mtk_wcn_consys_stp_btif_close(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_rx_cb_register ++* DESCRIPTION ++* register stp rx cb to btif ++* PARAMETERS ++* MTK_WCN_BTIF_RX_CB stp rx handle function ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ return mtk_wcn_consys_stp_btif_rx_cb_register(rx_cb); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_tx ++* DESCRIPTION ++* send stp package by btif ++* PARAMETERS ++* pBuf:package buffer pointer,len:package length ++* written_len:package written length ++* RETURNS ++* INT32 package length-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len) ++{ ++ INT32 iRet = -1; ++ ++ iRet = mtk_wcn_consys_stp_btif_tx(pBuf, len, written_len); ++ return iRet; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wakeup_consys ++* DESCRIPTION ++* STP wakeup consys by btif ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_wakeup_consys(VOID) ++{ ++ /*log wakeup int for debug */ ++ stp_dbg_pkt_log(7, 0, 0, 0, PKT_DIR_TX, NULL, 0); ++ return mtk_wcn_consys_stp_btif_wakeup(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_dpidle_ctrl ++* DESCRIPTION ++* decide AP enter or exit deep idle ++* PARAMETERS ++* en_flag:1,enter,0,exit ++* RETURNS ++* always 0 ++*****************************************************************************/ ++INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ mtk_wcn_consys_stp_btif_dpidle_ctrl(en_flag); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_lpbk_ctrl ++* DESCRIPTION ++* enable stp internal lpbk test or not ++* PARAMETERS ++* mode:1,enable,0,disabel ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) ++{ ++ return mtk_wcn_consys_stp_btif_lpbk_ctrl(mode); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_logger_ctrl ++* DESCRIPTION ++* dump btif buffer or register status when No ACK or assert occurs ++* PARAMETERS ++* flag:see enum value in ENUM_BTIF_DBG_ID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag) ++{ ++ return mtk_wcn_consys_stp_btif_logger_ctrl(flag); ++} ++ ++VOID mtk_wcn_stp_ctx_save(void) ++{ ++ STP_INFO_FUNC("start ++\n"); ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ stp_psm_set_sleep_disable(stp_core_ctx.psm); ++ STP_INFO_FUNC("exit --\n"); ++} ++ ++VOID mtk_wcn_stp_ctx_restore(void) ++{ ++ STP_INFO_FUNC("start ++\n"); ++ stp_psm_set_sleep_enable(stp_core_ctx.psm); ++ stp_btm_reset_btm_wq(STP_BTM_CORE(stp_core_ctx)); ++ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ else ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = 0; ++#endif ++ STP_INFO_FUNC("exit --\n"); ++} ++ ++INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(void) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_coredump_start_get() != 0) { ++ STP_INFO_FUNC("firmware assert has been triggered\n"); ++ return 0; ++ } ++ ++ ret = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("evt err trigger assert fail,do chip reset to recovery\n"); ++ ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ else ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ ++ return ret; ++} ++ ++VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value) ++{ ++ STP_INFO_FUNC("set evt err tigger assert flag to %d\n", value); ++ STP_SET_EVT_ERR_ASSERT(stp_core_ctx, value); ++} ++ ++UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(void) ++{ ++ return STP_EVT_ERR_ASSERT(stp_core_ctx); ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c +new file mode 100644 +index 000000000000..3009bd26df41 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c +@@ -0,0 +1,529 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CONF]" ++ ++#include "osal_typedef.h" ++/* #include "osal.h" */ ++#include "wmt_lib.h" ++#include "wmt_dev.h" ++#include "wmt_conf.h" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++struct parse_data { ++ PINT8 name; ++ INT32 (*parser)(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 value); ++ PINT8 (*writer)(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ /*PINT8 param1, *param2, *param3; */ ++ /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */ ++ PINT8 param1; ++ PINT8 param2; ++ PINT8 param3; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal); ++ ++static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size); ++ ++#define OFFSET(v) ((void *) &((P_DEV_WMT) 0)->v) ++ ++#define CHAR(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_char, \ ++ wmt_conf_write_char, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define CHAR(f) _CHAR(f), NULL, NULL} */ ++ ++#define SHORT(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_short, \ ++ wmt_conf_write_short, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define SHORT(f) _SHORT(f), NULL, NULL */ ++ ++#define INT(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_int, \ ++ wmt_conf_write_int, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define INT(f) _INT(f), NULL, NULL */ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static const struct parse_data wmtcfg_fields[] = { ++ CHAR(coex_wmt_ant_mode), ++ CHAR(coex_wmt_ext_component), ++ CHAR(coex_wmt_wifi_time_ctl), ++ CHAR(coex_wmt_ext_pta_dev_on), ++ CHAR(coex_wmt_filter_mode), ++ ++ CHAR(coex_bt_rssi_upper_limit), ++ CHAR(coex_bt_rssi_mid_limit), ++ CHAR(coex_bt_rssi_lower_limit), ++ CHAR(coex_bt_pwr_high), ++ CHAR(coex_bt_pwr_mid), ++ CHAR(coex_bt_pwr_low), ++ ++ CHAR(coex_wifi_rssi_upper_limit), ++ CHAR(coex_wifi_rssi_mid_limit), ++ CHAR(coex_wifi_rssi_lower_limit), ++ CHAR(coex_wifi_pwr_high), ++ CHAR(coex_wifi_pwr_mid), ++ CHAR(coex_wifi_pwr_low), ++ ++ CHAR(coex_ext_pta_hi_tx_tag), ++ CHAR(coex_ext_pta_hi_rx_tag), ++ CHAR(coex_ext_pta_lo_tx_tag), ++ CHAR(coex_ext_pta_lo_rx_tag), ++ SHORT(coex_ext_pta_sample_t1), ++ SHORT(coex_ext_pta_sample_t2), ++ CHAR(coex_ext_pta_wifi_bt_con_trx), ++ ++ INT(coex_misc_ext_pta_on), ++ INT(coex_misc_ext_feature_set), ++ ++ CHAR(wmt_gps_lna_pin), ++ CHAR(wmt_gps_lna_enable), ++ ++ CHAR(pwr_on_rtc_slot), ++ CHAR(pwr_on_ldo_slot), ++ CHAR(pwr_on_rst_slot), ++ CHAR(pwr_on_off_slot), ++ CHAR(pwr_on_on_slot), ++ CHAR(co_clock_flag), ++ ++ INT(sdio_driving_cfg), ++ ++}; ++ ++#define NUM_WMTCFG_FIELDS (osal_sizeof(wmtcfg_fields) / osal_sizeof(wmtcfg_fields[0])) ++ ++static int wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PINT8 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT8 src; ++ INT32 res; ++ PINT8 value; ++ ++ src = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static int wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PUINT16 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT16 src; ++ INT32 res; ++ PINT8 value; ++ ++ /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */ ++ src = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static int wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PUINT32 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT32) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT32 src; ++ INT32 res; ++ PINT8 value; ++ ++ src = (PUINT32) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal) ++{ ++ int i = 0; ++ int ret = 0; ++ ++ /* WMT_INFO_FUNC( DBG_NAME "cfg(%s) val(%s)\n", pKey, pVal); */ ++ ++ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { ++ const struct parse_data *field = &wmtcfg_fields[i]; ++ ++ if (osal_strcmp(pKey, field->name) != 0) ++ continue; ++ if (field->parser(pWmtDev, field, pVal)) { ++ WMT_ERR_FUNC("failed to parse %s '%s'.\n", pKey, pVal); ++ ret = -1; ++ } ++ break; ++ } ++ if (i == NUM_WMTCFG_FIELDS) { ++ WMT_ERR_FUNC("unknown field '%s'.\n", pKey); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size) ++{ ++ PINT8 pch; ++ PINT8 pBuf; ++ PINT8 pLine; ++ PINT8 pKey; ++ PINT8 pVal; ++ PINT8 pPos; ++ INT32 ret = 0; ++ INT32 i = 0; ++ PINT8 pa = NULL; ++ ++ pBuf = osal_malloc(size); ++ if (!pBuf) ++ return -1; ++ ++ osal_memcpy(pBuf, pInBuf, size); ++ pBuf[size] = '\0'; ++ ++ pch = pBuf; ++ /* pch is to be updated by strsep(). Keep pBuf unchanged!! */ ++ ++#if 0 ++ { ++ PINT8 buf_ptr = pBuf; ++ INT32 k = 0; ++ ++ WMT_INFO_FUNC("%s len=%d", "wmcfg.content:", size); ++ for (k = 0; k < size; k++) { ++ /* if(k%16 == 0) WMT_INFO_FUNC("\n"); */ ++ WMT_INFO_FUNC("%c", buf_ptr[k]); ++ } ++ WMT_INFO_FUNC("--end\n"); ++ } ++#endif ++ ++ while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) { ++ /* pch is updated to the end of pLine by strsep() and updated to '\0' */ ++ /*WMT_INFO_FUNC("strsep offset(%d), char(%d, '%c' )\n", pLine-pBuf, *pLine, *pLine); */ ++ /* parse each line */ ++ ++ /* WMT_INFO_FUNC("==> Line = (%s)\n", pLine); */ ++ ++ if (!*pLine) ++ continue; ++ ++ pVal = osal_strchr(pLine, '='); ++ if (!pVal) { ++ WMT_WARN_FUNC("mal-format cfg string(%s)\n", pLine); ++ continue; ++ } ++ ++ /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */ ++ *pVal = '\0'; /* replace '=' with '\0' to get key */ ++ /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */ ++ pKey = pLine; ++ ++ if ((pVal - pBuf) < size) ++ pVal++; ++ ++ /*key handling */ ++ pPos = pKey; ++ /*skip space characeter */ ++ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*key head */ ++ pKey = pPos; ++ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*key tail */ ++ (*pPos) = '\0'; ++ ++ /*value handling */ ++ pPos = pVal; ++ /*skip space characeter */ ++ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*value head */ ++ pVal = pPos; ++ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*value tail */ ++ (*pPos) = '\0'; ++ ++ /* WMT_DBG_FUNC("parse (key: #%s#, value: #%s#)\n", pKey, pVal); */ ++ ret = wmt_conf_parse_pair(pWmtDev, pKey, pVal); ++ WMT_DBG_FUNC("parse (%s, %s, %d)\n", pKey, pVal, ret); ++ if (ret) ++ WMT_WARN_FUNC("parse fail (%s, %s, %d)\n", pKey, pVal, ret); ++ } ++ ++ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { ++ const struct parse_data *field = &wmtcfg_fields[i]; ++ ++ pa = field->writer(pWmtDev, field); ++ if (pa) { ++ WMT_DBG_FUNC("#%d(%s)=>%s\n", i, field->name, pa); ++ osal_free(pa); ++ } else { ++ WMT_ERR_FUNC("failed to parse '%s'.\n", field->name); ++ } ++ } ++ osal_free(pBuf); ++ return 0; ++} ++ ++INT32 wmt_conf_set_cfg_file(const char *name) ++{ ++ if (NULL == name) { ++ WMT_ERR_FUNC("name is NULL\n"); ++ return -1; ++ } ++ if (osal_strlen(name) >= osal_sizeof(gDevWmt.cWmtcfgName)) { ++ WMT_ERR_FUNC("name is too long, length=%d, expect to < %d\n", osal_strlen(name), ++ osal_sizeof(gDevWmt.cWmtcfgName)); ++ return -2; ++ } ++ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); ++ osal_strcpy(&(gDevWmt.cWmtcfgName[0]), name); ++ WMT_ERR_FUNC("WMT config file is set to (%s)\n", &(gDevWmt.cWmtcfgName[0])); ++ ++ return 0; ++} ++ ++INT32 wmt_conf_read_file(VOID) ++{ ++ INT32 ret = -1; ++ ++ osal_memset(&gDevWmt.rWmtGenConf, 0, osal_sizeof(gDevWmt.rWmtGenConf)); ++ osal_memset(&gDevWmt.pWmtCfg, 0, osal_sizeof(gDevWmt.pWmtCfg)); ++ ++#if 1 ++ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); ++ ++ osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT_PREFIX, osal_sizeof(CUST_CFG_WMT_PREFIX)); ++ osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT, osal_sizeof(CUST_CFG_WMT)); ++#endif ++ ++ if (!osal_strlen(&(gDevWmt.cWmtcfgName[0]))) { ++ WMT_ERR_FUNC("empty Wmtcfg name\n"); ++ osal_assert(0); ++ return ret; ++ } ++ WMT_DBG_FUNC("WMT config file:%s\n", &(gDevWmt.cWmtcfgName[0])); ++ if (0 == wmt_dev_patch_get(&gDevWmt.cWmtcfgName[0], (osal_firmware **) &gDevWmt.pWmtCfg, 0)) { ++ /*get full name patch success */ ++ WMT_DBG_FUNC("get full file name(%s) buf(0x%p) size(%d)\n", ++ &gDevWmt.cWmtcfgName[0], gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size); ++ ++ if (0 == wmt_conf_parse(&gDevWmt, (const PINT8)gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size)) { ++ /*config file exists */ ++ gDevWmt.rWmtGenConf.cfgExist = 1; ++ ++ WMT_DBG_FUNC("&gDevWmt.rWmtGenConf=%p\n", &gDevWmt.rWmtGenConf); ++ ret = 0; ++ } else { ++ WMT_ERR_FUNC("wmt conf parsing fail\n"); ++ osal_assert(0); ++ ret = -1; ++ } ++ wmt_dev_patch_put((osal_firmware **) &gDevWmt.pWmtCfg); ++/* ++ if (gDevWmt.pWmtCfg) ++ { ++ if (gDevWmt.pWmtCfg->data) ++ { ++ osal_free(gDevWmt.pWmtCfg->data); ++ } ++ osal_free(gDevWmt.pWmtCfg); ++ gDevWmt.pWmtCfg = 0; ++ } ++*/ ++ return ret; ++ } ++ WMT_ERR_FUNC("read %s file fails\n", &(gDevWmt.cWmtcfgName[0])); ++ osal_assert(0); ++ ++ gDevWmt.rWmtGenConf.cfgExist = 0; ++ return ret; ++} ++ ++P_WMT_GEN_CONF wmt_conf_get_cfg(VOID) ++{ ++ if (0 == gDevWmt.rWmtGenConf.cfgExist) ++ return NULL; ++ ++ return &gDevWmt.rWmtGenConf; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c +new file mode 100644 +index 000000000000..cca6729d53a0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c +@@ -0,0 +1,2521 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CORE]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_lib.h" ++#include "wmt_core.h" ++#include "wmt_ctrl.h" ++#include "wmt_ic.h" ++#include "wmt_conf.h" ++ ++#include "wmt_func.h" ++#include "stp_core.h" ++#include "psm_core.h" ++ ++ ++P_WMT_FUNC_OPS gpWmtFuncOps[4] = { ++#if CFG_FUNC_BT_SUPPORT ++ [0] = &wmt_func_bt_ops, ++#else ++ [0] = NULL, ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ [1] = &wmt_func_fm_ops, ++#else ++ [1] = NULL, ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ [2] = &wmt_func_gps_ops, ++#else ++ [2] = NULL, ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++ [3] = &wmt_func_wifi_ops, ++#else ++ [3] = NULL, ++#endif ++ ++}; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* TODO:[FixMe][GeorgeKuo]: is it an MT6620 only or general general setting? ++*move to wmt_ic_6620 temporarily. ++*/ ++/* BT Port 2 Feature. */ ++/* #define CFG_WMT_BT_PORT2 (1) */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++static WMT_CTX gMtkWmtCtx; ++static UINT8 gLpbkBuf[1024+5] = { 0 }; ++#ifdef CONFIG_MTK_COMBO_ANT ++static UINT8 gAntBuf[1024] = { 0 }; ++#define CFG_CHECK_WMT_RESULT (1) ++#endif ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp); ++static INT32 opfunc_func_on(P_WMT_OP pWmtOp); ++static INT32 opfunc_func_off(P_WMT_OP pWmtOp); ++static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp); ++static INT32 opfunc_exit(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp); ++static INT32 opfunc_dsns(P_WMT_OP pWmtOp); ++static INT32 opfunc_lpbk(P_WMT_OP pWmtOp); ++static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp); ++static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp); ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_pin_state(P_WMT_OP pWmtOp); ++static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp); ++static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp); ++static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp); ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp); ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++static INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp); ++static INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp); ++#endif ++static VOID wmt_core_dump_func_state(PINT8 pSource); ++static INT32 wmt_core_stp_init(VOID); ++static INT32 wmt_core_stp_deinit(VOID); ++static INT32 wmt_core_hw_check(VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static const UINT8 WMT_SLEEP_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x01 }; ++static const UINT8 WMT_SLEEP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; ++ ++static const UINT8 WMT_HOST_AWAKE_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x02 }; ++static const UINT8 WMT_HOST_AWAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; ++ ++static const UINT8 WMT_WAKEUP_CMD[] = { 0xFF }; ++static const UINT8 WMT_WAKEUP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++ ++static UINT8 WMT_THERM_CMD[] = { 0x01, 0x11, 0x01, 0x00, ++ 0x00 /*thermal sensor operation */ ++}; ++static UINT8 WMT_THERM_CTRL_EVT[] = { 0x02, 0x11, 0x01, 0x00, 0x00 }; ++static UINT8 WMT_THERM_READ_EVT[] = { 0x02, 0x11, 0x02, 0x00, 0x00, 0x00 }; ++ ++static UINT8 WMT_EFUSE_CMD[] = { 0x01, 0x0D, 0x08, 0x00, ++ 0x01, /*[4]operation, 0:init, 1:write 2:read */ ++ 0x01, /*[5]Number of register setting */ ++ 0xAA, 0xAA, /*[6-7]Address */ ++ 0xBB, 0xBB, 0xBB, 0xBB /*[8-11] Value */ ++}; ++ ++static UINT8 WMT_EFUSE_EVT[] = { 0x02, 0x0D, 0x08, 0x00, ++ 0xAA, /*[4]operation, 0:init, 1:write 2:read */ ++ 0xBB, /*[5]Number of register setting */ ++ 0xCC, 0xCC, /*[6-7]Address */ ++ 0xDD, 0xDD, 0xDD, 0xDD /*[8-11] Value */ ++}; ++ ++static UINT8 WMT_DSNS_CMD[] = { 0x01, 0x0E, 0x02, 0x00, 0x01, ++ 0x00 /*desnse type */ ++}; ++static UINT8 WMT_DSNS_EVT[] = { 0x02, 0x0E, 0x01, 0x00, 0x00 }; ++ ++/* TODO:[NewFeature][GeorgeKuo] Update register group in ONE CMD/EVT */ ++static UINT8 WMT_SET_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x00 /*op: w(1) & r(2) */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*res */ ++ , 0x01 /*1 register */ ++ , 0x00, 0x00, 0x00, 0x00 /* addr */ ++ , 0x00, 0x00, 0x00, 0x00 /* value */ ++ , 0xFF, 0xFF, 0xFF, 0xFF /*mask */ ++}; ++ ++static UINT8 WMT_SET_REG_WR_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 register */ ++ /* , 0x00, 0x00, 0x00, 0x00 */ /* addr */ ++ /* , 0x00, 0x00, 0x00, 0x00 */ /* value */ ++}; ++ ++static UINT8 WMT_SET_REG_RD_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 register */ ++ , 0x00, 0x00, 0x00, 0x00 /* addr */ ++ , 0x00, 0x00, 0x00, 0x00 /* value */ ++}; ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++static UINT8 WMT_ANT_RAM_STA_GET_CMD[] = { 0x01, 0x06, 0x02, 0x00, 0x05, 0x02 ++}; ++ ++static UINT8 WMT_ANT_RAM_STA_GET_EVT[] = { 0x02, 0x06, 0x03, 0x00 /*length */ ++ , 0x05, 0x02, 0x00 /*S: result */ ++}; ++ ++static UINT8 WMT_ANT_RAM_DWN_CMD[] = { 0x01, 0x15, 0x00, 0x00, 0x01 ++}; ++ ++static UINT8 WMT_ANT_RAM_DWN_EVT[] = { 0x02, 0x15, 0x01, 0x00 /*length */ ++ , 0x00 ++}; ++#endif ++ ++/* GeorgeKuo: Use designated initializers described in ++ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html ++ */ ++ ++static const WMT_OPID_FUNC wmt_core_opfunc[] = { ++ [WMT_OPID_HIF_CONF] = opfunc_hif_conf, ++ [WMT_OPID_PWR_ON] = opfunc_pwr_on, ++ [WMT_OPID_PWR_OFF] = opfunc_pwr_off, ++ [WMT_OPID_FUNC_ON] = opfunc_func_on, ++ [WMT_OPID_FUNC_OFF] = opfunc_func_off, ++ [WMT_OPID_REG_RW] = opfunc_reg_rw, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++ [WMT_OPID_EXIT] = opfunc_exit, ++ [WMT_OPID_PWR_SV] = opfunc_pwr_sv, ++ [WMT_OPID_DSNS] = opfunc_dsns, ++ [WMT_OPID_LPBK] = opfunc_lpbk, ++ [WMT_OPID_CMD_TEST] = opfunc_cmd_test, ++ [WMT_OPID_HW_RST] = opfunc_hw_rst, ++ [WMT_OPID_SW_RST] = opfunc_sw_rst, ++ [WMT_OPID_STP_RST] = opfunc_stp_rst, ++ [WMT_OPID_THERM_CTRL] = opfunc_therm_ctrl, ++ [WMT_OPID_EFUSE_RW] = opfunc_efuse_rw, ++ [WMT_OPID_GPIO_CTRL] = opfunc_gpio_ctrl, ++ [WMT_OPID_GPIO_STATE] = opfunc_pin_state, ++ [WMT_OPID_BGW_DS] = opfunc_bgw_ds, ++ [WMT_OPID_SET_MCU_CLK] = opfunc_set_mcu_clk, ++ [WMT_OPID_ADIE_LPBK_TEST] = opfunc_adie_lpbk_test, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [WMT_OPID_IDC_MSG_HANDLING] = opfunc_idc_msg_handling, ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++ [WMT_OPID_ANT_RAM_DOWN] = opfunc_ant_ram_down, ++ [WMT_OPID_ANT_RAM_STA_GET] = opfunc_ant_ram_stat_get, ++#endif ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_core_init(VOID) ++{ ++ INT32 i = 0; ++ ++ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); ++ /* gMtkWmtCtx.p_ops is cleared to NULL */ ++ ++ /* default FUNC_OFF state */ ++ for (i = 0; i < WMTDRV_TYPE_MAX; ++i) { ++ /* WinMo is default to DRV_STS_UNREG; */ ++ gMtkWmtCtx.eDrvStatus[i] = DRV_STS_POWER_OFF; ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_core_deinit(VOID) ++{ ++ /* return to init state */ ++ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); ++ /* gMtkWmtCtx.p_ops is cleared to NULL */ ++ return 0; ++} ++ ++/* TODO: [ChangeFeature][George] Is wmt_ctrl a good interface? maybe not...... */ ++/* parameters shall be copied in/from ctrl buffer, which is also a size-wasting buffer. */ ++INT32 wmt_core_tx(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) ++{ ++ INT32 iRet; ++#if 0 /* Test using direct function call instead of wmt_ctrl() interface */ ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_TX; ++ ctrlData.au4CtrlData[0] = (UINT32) pData; ++ ctrlData.au4CtrlData[1] = size; ++ ctrlData.au4CtrlData[2] = (UINT32) writtenSize; ++ ctrlData.au4CtrlData[3] = bRawFlag; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_TX, iRet:%d\n", iRet); ++ /* (*sys_dbg_assert)(0, __FILE__, __LINE__); */ ++ osal_assert(0); ++ } ++#endif ++ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++ if (0 == *writtenSize) { ++ INT32 retry_times = 0; ++ INT32 max_retry_times = 3; ++ INT32 retry_delay_ms = 360; ++ ++ WMT_WARN_FUNC("WMT-CORE: wmt_ctrl_tx_ex failed and written ret:%d, maybe no winspace in STP layer\n", ++ *writtenSize); ++ while ((0 == *writtenSize) && (retry_times < max_retry_times)) { ++ WMT_ERR_FUNC("WMT-CORE: retrying, wait for %d ms\n", retry_delay_ms); ++ osal_sleep_ms(retry_delay_ms); ++ ++ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++ retry_times++; ++ } ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize) ++{ ++ INT32 iRet; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_RX; ++ ctrlData.au4CtrlData[0] = (SIZE_T) pBuf; ++ ctrlData.au4CtrlData[1] = bufLen; ++ ctrlData.au4CtrlData[2] = (SIZE_T) readSize; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX, iRet:%d\n", iRet); ++ mtk_wcn_stp_dbg_dump_package(); ++ osal_assert(0); ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_rx_flush(UINT32 type) ++{ ++ INT32 iRet; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_RX_FLUSH; ++ ctrlData.au4CtrlData[0] = (UINT32) type; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX_FLUSH, iRet:%d\n", iRet); ++ osal_assert(0); ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn) ++{ ++ INT32 iRet = 0; ++ UINT32 u4WmtCmdPduLen; ++ UINT32 u4WmtEventPduLen; ++ UINT32 u4ReadSize; ++ UINT32 u4WrittenSize; ++ WMT_PKT rWmtPktCmd; ++ WMT_PKT rWmtPktEvent; ++ MTK_WCN_BOOL fgFail; ++ ++ /* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ ++ /* Using this struct relies on compiler's implementation and pack() settings */ ++ osal_memset(&rWmtPktCmd, 0, osal_sizeof(rWmtPktCmd)); ++ osal_memset(&rWmtPktEvent, 0, osal_sizeof(rWmtPktEvent)); ++ ++ rWmtPktCmd.eType = (UINT8) PKT_TYPE_CMD; ++ rWmtPktCmd.eOpCode = (UINT8) OPCODE_FUNC_CTRL; ++ ++ /* Flag field: driver type */ ++ rWmtPktCmd.aucParam[0] = (UINT8) type; ++ /* Parameter field: ON/OFF */ ++ rWmtPktCmd.aucParam[1] = (fgEn == WMT_FUNC_CTRL_ON) ? 1 : 0; ++ rWmtPktCmd.u2SduLen = WMT_FLAG_LEN + WMT_FUNC_CTRL_PARAM_LEN; /* (2) */ ++ ++ /* WMT Header + WMT SDU */ ++ u4WmtCmdPduLen = WMT_HDR_LEN + rWmtPktCmd.u2SduLen; /* (6) */ ++ u4WmtEventPduLen = WMT_HDR_LEN + WMT_STS_LEN; /* (5) */ ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++/* iRet = (*kal_stp_tx)((PUINT8)&rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize); */ ++ iRet = wmt_core_tx((PUINT8) &rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize, MTK_WCN_BOOL_FALSE); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_tx failed\n"); ++ break; ++ } ++ ++ iRet = wmt_core_rx((PUINT8) &rWmtPktEvent, u4WmtEventPduLen, &u4ReadSize); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_rx failed\n"); ++ break; ++ } ++ ++ /* Error Checking */ ++ if (PKT_TYPE_EVENT != rWmtPktEvent.eType) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd PKT_TYPE_EVENT != rWmtPktEvent.eType %d\n", ++ rWmtPktEvent.eType); ++ break; ++ } ++ ++ if (rWmtPktCmd.eOpCode != rWmtPktEvent.eOpCode) { ++ WMT_ERR_FUNC ++ ("WMT-CORE: wmt_func_ctrl_cmd rWmtPktCmd.eOpCode(0x%x) != rWmtPktEvent.eType(0x%x)\n", ++ rWmtPktCmd.eOpCode, rWmtPktEvent.eOpCode); ++ break; ++ } ++ ++ if (u4WmtEventPduLen != (rWmtPktEvent.u2SduLen + WMT_HDR_LEN)) { ++ WMT_ERR_FUNC ++ ("WMT-CORE: wmt_func_ctrl_cmd u4WmtEventPduLen(0x%x) != rWmtPktEvent.u2SduLen(0x%x)+4\n", ++ u4WmtEventPduLen, rWmtPktEvent.u2SduLen); ++ break; ++ } ++ /* Status field of event check */ ++ if (0 != rWmtPktEvent.aucParam[0]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd, 0 != status(%d)\n", rWmtPktEvent.aucParam[0]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ } while (0); ++ ++ if (MTK_WCN_BOOL_FALSE == fgFail) { ++ /* WMT_INFO_FUNC("WMT-CORE: wmt_func_ctrl_cmd OK!\n"); */ ++ return 0; ++ } ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd 0x%x FAIL\n", rWmtPktCmd.aucParam[0]); ++ return -3; ++} ++ ++INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp) ++{ ++ UINT32 opId; ++ INT32 ret; ++ ++ opId = pWmtOp->opId; ++ ++ if (wmt_core_opfunc[opId]) { ++ ret = (*(wmt_core_opfunc[opId])) (pWmtOp); /*wmtCoreOpidHandlerPack[].opHandler */ ++ return ret; ++ } ++ WMT_ERR_FUNC("WMT-CORE: null handler (%d)\n", pWmtOp->opId); ++ return -2; ++ ++} ++ ++INT32 wmt_core_opid(P_WMT_OP pWmtOp) ++{ ++ ++ /*sanity check */ ++ if (NULL == pWmtOp) { ++ WMT_ERR_FUNC("null pWmtOP\n"); ++ /*print some message with error info */ ++ return -1; ++ } ++ ++ if (WMT_OPID_MAX <= pWmtOp->opId) { ++ WMT_ERR_FUNC("WMT-CORE: invalid OPID(%d)\n", pWmtOp->opId); ++ return -2; ++ } ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ return wmt_core_opid_handler(pWmtOp); ++} ++ ++INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2) ++{ ++ INT32 iRet = -1; ++ WMT_CTRL_DATA ctrlData; ++ SIZE_T val1 = (pPa1) ? *pPa1 : 0; ++ SIZE_T val2 = (pPa2) ? *pPa2 : 0; ++ ++ ctrlData.ctrlId = (SIZE_T) ctrId; ++ ctrlData.au4CtrlData[0] = val1; ++ ctrlData.au4CtrlData[1] = val2; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: id(%d), type(%d), value(%d) iRet:(%d)\n", ctrId, val1, ++ val2, iRet); ++ osal_assert(0); ++ } else { ++ if (pPa1) ++ *pPa1 = ctrlData.au4CtrlData[0]; ++ if (pPa2) ++ *pPa2 = ctrlData.au4CtrlData[1]; ++ } ++ return iRet; ++} ++ ++VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len) ++{ ++ PUINT8 ptr = pData; ++ INT32 k = 0; ++ ++ WMT_INFO_FUNC("%s len=%d\n", pTitle, len); ++ for (k = 0; k < len; k++) { ++ if (k % 16 == 0) ++ WMT_INFO_FUNC("\n"); ++ WMT_INFO_FUNC("0x%02x ", *ptr); ++ ptr++; ++ } ++ WMT_INFO_FUNC("--end\n"); ++} ++ ++/*! ++ * \brief An WMT-CORE function to support read, write, and read after write to ++ * an internal register. ++ * ++ * Detailed description. ++ * ++ * \param isWrite 1 for write, 0 for read ++ * \param offset of register to be written or read ++ * \param pVal a pointer to the 32-bit value to be writtern or read ++ * \param mask a 32-bit mask to be applied for the read or write operation ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ * \retval -2 tx cmd fail ++ * \retval -3 rx event fail ++ * \retval -4 read check error ++ */ ++INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask) ++{ ++ INT32 iRet; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_SET_REG_CMD[4] = (isWrite) ? 0x1 : 0x2; /* w:1, r:2 */ ++ osal_memcpy(&WMT_SET_REG_CMD[8], &offset, 4); /* offset */ ++ osal_memcpy(&WMT_SET_REG_CMD[12], pVal, 4); /* [2] is var addr */ ++ osal_memcpy(&WMT_SET_REG_CMD[16], &mask, 4); /* mask */ ++ ++ /* send command */ ++ iRet = wmt_core_tx(WMT_SET_REG_CMD, sizeof(WMT_SET_REG_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if ((iRet) || (u4Res != sizeof(WMT_SET_REG_CMD))) { ++ WMT_ERR_FUNC("Tx REG_CMD fail!(%d) len (%d, %d)\n", iRet, u4Res, sizeof(WMT_SET_REG_CMD)); ++ return -2; ++ } ++ ++ /* receive event */ ++ evtLen = (isWrite) ? sizeof(WMT_SET_REG_WR_EVT) : sizeof(WMT_SET_REG_RD_EVT); ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if ((iRet) || (u4Res != evtLen)) { ++ WMT_ERR_FUNC("Rx REG_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ return -3; ++ } ++ ++ if (!isWrite) { ++ UINT32 rxEvtAddr; ++ UINT32 txCmdAddr; ++ ++ osal_memcpy(&txCmdAddr, &WMT_SET_REG_CMD[8], 4); ++ osal_memcpy(&rxEvtAddr, &evtBuf[8], 4); ++ ++ /* check read result */ ++ if (txCmdAddr != rxEvtAddr) { ++ WMT_ERR_FUNC("Check read addr fail (0x%08x, 0x%08x)\n", rxEvtAddr, txCmdAddr); ++ return -4; ++ } ++ WMT_DBG_FUNC("Check read addr(0x%08x) ok\n", rxEvtAddr); ++ ++ osal_memcpy(pVal, &evtBuf[12], 4); ++ } ++ ++ /* no error here just return 0 */ ++ return 0; ++} ++ ++INT32 wmt_core_init_script(struct init_script *script, INT32 count) ++{ ++ UINT8 evtBuf[256]; ++ UINT32 u4Res; ++ INT32 i = 0; ++ INT32 iRet; ++ ++ for (i = 0; i < count; i++) { ++ WMT_DBG_FUNC("WMT-CORE: init_script operation %s start\n", script[i].str); ++ /* CMD */ ++ /* iRet = (*kal_stp_tx)(script[i].cmd, script[i].cmdSz, &u4Res); */ ++ iRet = wmt_core_tx(script[i].cmd, script[i].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != script[i].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", script[i].str, iRet, u4Res, ++ script[i].cmdSz); ++ break; ++ } ++ /* EVENT BUF */ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ iRet = wmt_core_rx(evtBuf, script[i].evtSz, &u4Res); ++ if (iRet || (u4Res != script[i].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", script[i].str, iRet, ++ u4Res, script[i].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ break; ++ } ++ /* RESULT */ ++ if (0x14 != evtBuf[1]) { /* workaround RF calibration data EVT,do not care this EVT */ ++ if (osal_memcmp(evtBuf, script[i].evt, script[i].evtSz) != 0) { ++ WMT_ERR_FUNC("WMT-CORE:compare %s result error\n", script[i].str); ++ WMT_ERR_FUNC ++ ("WMT-CORE:rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], script[i].evtSz, ++ script[i].evt[0], script[i].evt[1], script[i].evt[2], script[i].evt[3], ++ script[i].evt[4]); ++ mtk_wcn_stp_dbg_dump_package(); ++ break; ++ } ++ } ++ WMT_DBG_FUNC("init_script operation %s ok\n", script[i].str); ++ } ++ ++ return (i == count) ? 0 : -1; ++} ++ ++static INT32 wmt_core_stp_init(VOID) ++{ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT8 co_clock_type; ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ P_WMT_GEN_CONF pWmtGenConf = NULL; ++ ++ wmt_conf_read_file(); ++ pWmtGenConf = wmt_conf_get_cfg(); ++ if (!(pctx->wmtInfoBit & WMT_OP_HIF_BIT)) { ++ WMT_ERR_FUNC("WMT-CORE: no hif info!\n"); ++ osal_assert(0); ++ return -1; ++ } ++ /* 4 <1> open stp */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -2; ++ } ++ /* 4 <1.5> disable and un-ready stp */ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ /* 4 <2> set mode and enable */ ++ if (WMT_HIF_BTIF == pctx->wmtHifConf.hifType) { ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_MAND_MODE; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ } ++ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); ++ return -3; ++ } ++ /* TODO: [ChangeFeature][GeorgeKuo] can we apply raise UART baud rate firstly for ALL supported chips??? */ ++ ++ iRet = wmt_core_hw_check(); ++ if (iRet) { ++ WMT_ERR_FUNC("hw_check fail:%d\n", iRet); ++ return -4; ++ } ++ /* mtkWmtCtx.p_ic_ops is identified and checked ok */ ++ if ((NULL != pctx->p_ic_ops->co_clock_ctrl) && (pWmtGenConf != NULL)) { ++ co_clock_type = (pWmtGenConf->co_clock_flag & 0x0f); ++ (*(pctx->p_ic_ops->co_clock_ctrl)) (co_clock_type == 0 ? WMT_CO_CLOCK_DIS : WMT_CO_CLOCK_EN); ++ } else { ++ WMT_WARN_FUNC("pctx->p_ic_ops->co_clock_ctrl(0x%x), pWmtGenConf(0x%x)\n", pctx->p_ic_ops->co_clock_ctrl, ++ pWmtGenConf); ++ } ++ osal_assert(NULL != pctx->p_ic_ops->sw_init); ++ if (NULL != pctx->p_ic_ops->sw_init) { ++ iRet = (*(pctx->p_ic_ops->sw_init)) (&pctx->wmtHifConf); ++ } else { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); ++ return -5; ++ } ++ if (iRet) { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init fail:%d\n", iRet); ++ return -6; ++ } ++ /* 4 <10> set stp ready */ ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 1; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ return iRet; ++} ++ ++static INT32 wmt_core_stp_deinit(VOID) ++{ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ WMT_DBG_FUNC(" start\n"); ++ ++ if (NULL == gMtkWmtCtx.p_ic_ops) { ++ WMT_WARN_FUNC("gMtkWmtCtx.p_ic_ops is NULL\n"); ++ goto deinit_ic_ops_done; ++ } ++ if (NULL != gMtkWmtCtx.p_ic_ops->sw_deinit) { ++ iRet = (*(gMtkWmtCtx.p_ic_ops->sw_deinit)) (&gMtkWmtCtx.wmtHifConf); ++ /* unbind WMT-IC */ ++ gMtkWmtCtx.p_ic_ops = NULL; ++ } else { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); ++ } ++ ++deinit_ic_ops_done: ++ ++ /* 4 <1> un-ready, disable, and close stp. */ ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ ++ if (iRet) ++ WMT_WARN_FUNC("end with fail:%d\n", iRet); ++ ++ return iRet; ++} ++ ++static VOID wmt_core_dump_func_state(PINT8 pSource) ++{ ++ WMT_WARN_FUNC("[%s]status(b:%d f:%d g:%d w:%d lpbk:%d coredump:%d wmt:%d stp:%d)\n", ++ (pSource == NULL ? (PINT8) "CORE" : pSource), ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] ++ ); ++ return; ++ ++} ++ ++MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer) ++{ ++ if (MAJORNUM(u4HwVer) != MAJORNUM(u4PatchVer)) { ++ /*major no. does not match */ ++ WMT_ERR_FUNC("WMT-CORE: chip version(0x%d) does not match patch version(0x%d)\n", u4HwVer, u4PatchVer); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++static INT32 wmt_core_hw_check(VOID) ++{ ++ UINT32 chipid; ++ P_WMT_IC_OPS p_ops; ++ INT32 iret; ++ ++ /* 1. get chip id */ ++ chipid = 0; ++ WMT_LOUD_FUNC("before read hwcode (chip id)\n"); ++ iret = wmt_core_reg_rw_raw(0, GEN_HCR, &chipid, GEN_HCR_MASK); /* read 0x80000008 */ ++ if (iret) { ++ WMT_ERR_FUNC("get hwcode (chip id) fail (%d)\n", iret); ++ return -2; ++ } ++ WMT_DBG_FUNC("get hwcode (chip id) (0x%x)\n", chipid); ++ ++ /* TODO:[ChangeFeature][George]: use a better way to select a correct ops table based on chip id */ ++ switch (chipid) { ++#if CFG_CORE_MT6620_SUPPORT ++ case 0x6620: ++ p_ops = &wmt_ic_ops_mt6620; ++ break; ++#endif ++#if CFG_CORE_MT6628_SUPPORT ++ case 0x6628: ++ p_ops = &wmt_ic_ops_mt6628; ++ break; ++#endif ++#if CFG_CORE_SOC_SUPPORT ++ case 0x6572: ++ case 0x6582: ++ case 0x6592: ++ case 0x8127: ++ case 0x6571: ++ case 0x6752: ++ case 0x0279: ++ case 0x0326: ++ case 0x0321: ++ case 0x0335: ++ case 0x0337: ++ case 0x8163: ++ case 0x6580: ++ p_ops = &wmt_ic_ops_soc; ++ break; ++#endif ++ default: ++ p_ops = (P_WMT_IC_OPS) NULL; ++#if CFG_CORE_SOC_SUPPORT ++ if (0x7f90 == chipid - 0x600) { ++ p_ops = &wmt_ic_ops_soc; ++ chipid -= 0xf6d; ++ } ++#endif ++ break; ++ } ++ ++ if (NULL == p_ops) { ++ WMT_ERR_FUNC("unsupported chip id (hw_code): 0x%x\n", chipid); ++ return -3; ++ } else if (MTK_WCN_BOOL_FALSE == wmt_core_ic_ops_check(p_ops)) { ++ WMT_ERR_FUNC ++ ("chip id(0x%x) with null operation fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", ++ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); ++ return -4; ++ } ++ WMT_DBG_FUNC("chip id(0x%x) fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", ++ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); ++ ++ wmt_ic_ops_soc.icId = chipid; ++ WMT_DBG_FUNC("wmt_ic_ops_soc.icId(0x%x)\n", wmt_ic_ops_soc.icId); ++ iret = p_ops->ic_ver_check(); ++ if (iret) { ++ WMT_ERR_FUNC("chip id(0x%x) ver_check error:%d\n", chipid, iret); ++ return -5; ++ } ++ ++ WMT_DBG_FUNC("chip id(0x%x) ver_check ok\n", chipid); ++ gMtkWmtCtx.p_ic_ops = p_ops; ++ return 0; ++} ++ ++static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp) ++{ ++ if (!(pWmtOp->u4InfoBit & WMT_OP_HIF_BIT)) { ++ WMT_ERR_FUNC("WMT-CORE: no HIF_BIT in WMT_OP!\n"); ++ return -1; ++ } ++ ++ if (gMtkWmtCtx.wmtInfoBit & WMT_OP_HIF_BIT) { ++ WMT_ERR_FUNC("WMT-CORE: WMT HIF already exist. overwrite! old (%d), new(%d))\n", ++ gMtkWmtCtx.wmtHifConf.hifType, pWmtOp->au4OpData[0]); ++ } else { ++ gMtkWmtCtx.wmtInfoBit |= WMT_OP_HIF_BIT; ++ WMT_ERR_FUNC("WMT-CORE: WMT HIF info added\n"); ++ } ++ ++ osal_memcpy(&gMtkWmtCtx.wmtHifConf, &pWmtOp->au4OpData[0], osal_sizeof(gMtkWmtCtx.wmtHifConf)); ++ return 0; ++ ++} ++ ++static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ INT32 retry = WMT_PWRON_RTY_DFT; ++ ++ if (DRV_STS_POWER_OFF != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: already powered on, WMT DRV_STS_[0x%x]\n", ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); ++ osal_assert(0); ++ return -1; ++ } ++ /* TODO: [FixMe][GeorgeKuo]: clarify the following is reqiured or not! */ ++ if (pWmtOp->u4InfoBit & WMT_OP_HIF_BIT) ++ opfunc_hif_conf(pWmtOp); ++ ++pwr_on_rty: ++ /* power on control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); ++ if (0 == retry--) { ++ WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); ++ goto pwr_on_rty; ++ } ++ return -1; ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* init stp */ ++ iRet = wmt_core_stp_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_init fail (%d)\n", iRet); ++ osal_assert(0); ++ ++ /* deinit stp */ ++ iRet = wmt_core_stp_deinit(); ++ iRet = opfunc_pwr_off(pWmtOp); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: opfunc_pwr_off fail during pwr_on retry\n"); ++ ++ if (0 < retry--) { ++ WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); ++ goto pwr_on_rty; ++ } ++ iRet = -2; ++ return iRet; ++ } ++ ++ WMT_DBG_FUNC("WMT-CORE: WMT [FUNC_ON]\n"); ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; ++ ++ /* What to do when state is changed from POWER_OFF to POWER_ON? ++ * 1. STP driver does s/w reset ++ * 2. UART does 0xFF wake up ++ * 3. SDIO does re-init command(changed to trigger by host) ++ */ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_WARN_FUNC("WMT-CORE: WMT already off, WMT DRV_STS_[0x%x]\n", ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); ++ osal_assert(0); ++ return -1; ++ } ++ if (MTK_WCN_BOOL_FALSE == g_pwr_off_flag) { ++ WMT_WARN_FUNC("CONNSYS power off be disabled, maybe need trigger core dump!\n"); ++ osal_assert(0); ++ return -2; ++ } ++ ++ /* wmt and stp are initialized successfully */ ++ if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ iRet = wmt_core_stp_deinit(); ++ if (iRet) { ++ WMT_WARN_FUNC("wmt_core_stp_deinit fail (%d)\n", iRet); ++ /*should let run to power down chip */ ++ } ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* power off control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_OFF, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_WARN_FUNC("HW_PWR_OFF fail (%d)\n", iRet); ++ WMT_WARN_FUNC("HW_PWR_OFF ok\n"); ++ ++ /*anyway, set to POWER_OFF state */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; ++ return iRet; ++ ++} ++ ++static INT32 opfunc_func_on(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ INT32 iPwrOffRet = -1; ++ UINT32 drvType; ++ ++ drvType = pWmtOp->au4OpData[0]; ++ ++ /* Check abnormal type */ ++ if (WMTDRV_TYPE_COREDUMP < drvType) { ++ WMT_ERR_FUNC("abnormal Fun(%d)\n", drvType); ++ osal_assert(0); ++ return -1; ++ } ++ ++ /* Check abnormal state */ ++ if ((DRV_STS_POWER_OFF > gMtkWmtCtx.eDrvStatus[drvType]) ++ || (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType])) { ++ WMT_ERR_FUNC("func(%d) status[0x%x] abnormal\n", drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ osal_assert(0); ++ return -2; ++ } ++ ++ /* check if func already on */ ++ if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_WARN_FUNC("func(%d) already on\n", drvType); ++ return 0; ++ } ++ /*enable power off flag, if flag=0, power off connsys will not be executed */ ++ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); ++ /* check if chip power on is needed */ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ iRet = opfunc_pwr_on(pWmtOp); ++ ++ if (iRet) { ++ WMT_ERR_FUNC("func(%d) pwr_on fail(%d)\n", drvType, iRet); ++ osal_assert(0); ++ ++ /* check all sub-func and do power off */ ++ return -3; ++ } ++ } ++ ++ if (WMTDRV_TYPE_WMT > drvType) { ++ if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_on) { ++ iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ if (0 != iRet) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ else ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ } else { ++ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); ++ iRet = -5; ++ } ++ } else { ++ if (WMTDRV_TYPE_LPBK == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ else if (WMTDRV_TYPE_COREDUMP == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ iRet = 0; ++ } ++ ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet); ++ osal_assert(0); ++ /* FIX-ME:[Chaozhong Liang], Error handling? check subsystem state and do pwr off if necessary? */ ++ /* check all sub-func and do power off */ ++ if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { ++ WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); ++ mtk_wcn_wmt_system_state_reset(); ++ ++ iPwrOffRet = opfunc_pwr_off(pWmtOp); ++ if (iPwrOffRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iPwrOffRet, ++ drvType); ++ osal_assert(0); ++ } ++ } ++ return iRet; ++ } ++ ++ wmt_core_dump_func_state("AF FUNC ON"); ++ ++ return 0; ++} ++ ++static INT32 opfunc_func_off(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 drvType; ++ ++ drvType = pWmtOp->au4OpData[0]; ++ /* Check abnormal type */ ++ if (WMTDRV_TYPE_COREDUMP < drvType) { ++ WMT_ERR_FUNC("WMT-CORE: abnormal Fun(%d) in wmt_func_off\n", drvType); ++ osal_assert(0); ++ return -1; ++ } ++ ++ /* Check abnormal state */ ++ if (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_ERR_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] abnormal in wmt_func_off\n", ++ drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ osal_assert(0); ++ return -2; ++ } ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_WARN_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n", ++ drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ /* needs to check 4 subsystem's state? */ ++ return 0; ++ } else if (WMTDRV_TYPE_WMT > drvType) { ++ if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_off) { ++ iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ } else { ++ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); ++ iRet = -3; ++ } ++ } else { ++ if (WMTDRV_TYPE_LPBK == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ else if (WMTDRV_TYPE_COREDUMP == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ iRet = 0; ++ } ++ ++ /* shall we put device state to POWER_OFF state when fail? */ ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet); ++ osal_assert(0); ++ /* no matter subsystem function control fail or not, ++ *chip should be powered off when no subsystem is active ++ */ ++ /* return iRet; */ ++ } ++ ++ /* check all sub-func and do power off */ ++ if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { ++ WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); ++ ++ iRet = opfunc_pwr_off(pWmtOp); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iRet, drvType); ++ osal_assert(0); ++ } ++ } ++ ++ wmt_core_dump_func_state("AF FUNC OFF"); ++ return iRet; ++} ++ ++/* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp) ++{ ++ INT32 iret; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("reg_rw when WMT is powered off\n"); ++ return -1; ++ } ++ iret = wmt_core_reg_rw_raw(pWmtOp->au4OpData[0], ++ pWmtOp->au4OpData[1], (PUINT32) pWmtOp->au4OpData[2], pWmtOp->au4OpData[3]); ++ ++ return iret; ++} ++ ++static INT32 opfunc_exit(P_WMT_OP pWmtOp) ++{ ++ /* TODO: [FixMe][George] is ok to leave this function empty??? */ ++ WMT_WARN_FUNC("EMPTY FUNCTION\n"); ++ return 0; ++} ++ ++static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp) ++{ ++ INT32 ret = -1; ++ UINT32 u4_result = 0; ++ UINT32 evt_len; ++ UINT8 evt_buf[16] = { 0 }; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ typedef INT32(*STP_PSM_CB) (INT32); ++ STP_PSM_CB psm_cb = NULL; ++ ++ if (SLEEP == pWmtOp->au4OpData[0]) { ++ WMT_DBG_FUNC("**** Send sleep command\n"); ++ /* mtk_wcn_stp_set_psm_state(ACT_INACT); */ ++ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ ++ ret = wmt_core_tx((PUINT8) &WMT_SLEEP_CMD[0], sizeof(WMT_SLEEP_CMD), &u4_result, 0); ++ if (ret || (u4_result != sizeof(WMT_SLEEP_CMD))) { ++ WMT_ERR_FUNC("wmt_core: SLEEP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_SLEEP_CMD)); ++ goto pwr_sv_done; ++ } ++ ++ evt_len = sizeof(WMT_SLEEP_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 33; ++ unsigned long ctrlpa = 1; ++ ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: read SLEEP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 38; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_SLEEP_EVT, sizeof(WMT_SLEEP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_SLEEP_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_SLEEP_EVT), ++ WMT_SLEEP_EVT[0], ++ WMT_SLEEP_EVT[1], ++ WMT_SLEEP_EVT[2], ++ WMT_SLEEP_EVT[3], ++ WMT_SLEEP_EVT[4], ++ WMT_SLEEP_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ goto pwr_sv_done; ++ } else { ++ WMT_DBG_FUNC("Send sleep command OK!\n"); ++ } ++ } else if (pWmtOp->au4OpData[0] == WAKEUP) { ++ WMT_DBG_FUNC("wakeup connsys by btif"); ++ ++ ret = wmt_core_ctrl(WMT_CTRL_SOC_WAKEUP_CONSYS, &ctrlPa1, &ctrlPa2); ++ if (ret) { ++ WMT_ERR_FUNC("wmt-core:WAKEUP_CONSYS by BTIF fail(%d)", ret); ++ goto pwr_sv_done; ++ } ++#if 0 ++ WMT_DBG_FUNC("**** Send wakeup command\n"); ++ ret = wmt_core_tx(WMT_WAKEUP_CMD, sizeof(WMT_WAKEUP_CMD), &u4_result, 1); ++ ++ if (ret || (u4_result != sizeof(WMT_WAKEUP_CMD))) { ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: WAKEUP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_WAKEUP_CMD)); ++ goto pwr_sv_done; ++ } ++#endif ++ evt_len = sizeof(WMT_WAKEUP_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 34; ++ unsigned long ctrlpa = 2; ++ ++ WMT_ERR_FUNC("wmt_core: read WAKEUP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 39; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_WAKEUP_EVT, sizeof(WMT_WAKEUP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_WAKEUP_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_WAKEUP_EVT), ++ WMT_WAKEUP_EVT[0], ++ WMT_WAKEUP_EVT[1], ++ WMT_WAKEUP_EVT[2], ++ WMT_WAKEUP_EVT[3], ++ WMT_WAKEUP_EVT[4], ++ WMT_WAKEUP_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ goto pwr_sv_done; ++ } else { ++ WMT_DBG_FUNC("Send wakeup command OK!\n"); ++ } ++ } else if (pWmtOp->au4OpData[0] == HOST_AWAKE) { ++ ++ WMT_DBG_FUNC("**** Send host awake command\n"); ++ ++ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; ++ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ ++ ret = wmt_core_tx((PUINT8) WMT_HOST_AWAKE_CMD, sizeof(WMT_HOST_AWAKE_CMD), &u4_result, 0); ++ if (ret || (u4_result != sizeof(WMT_HOST_AWAKE_CMD))) { ++ WMT_ERR_FUNC("wmt_core: HOST_AWAKE_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_HOST_AWAKE_CMD)); ++ goto pwr_sv_done; ++ } ++ ++ evt_len = sizeof(WMT_HOST_AWAKE_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 35; ++ unsigned long ctrlpa = 3; ++ ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: read HOST_AWAKE_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 40; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_HOST_AWAKE_EVT, sizeof(WMT_HOST_AWAKE_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_HOST_AWAKE_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_HOST_AWAKE_EVT), ++ WMT_HOST_AWAKE_EVT[0], ++ WMT_HOST_AWAKE_EVT[1], ++ WMT_HOST_AWAKE_EVT[2], ++ WMT_HOST_AWAKE_EVT[3], ++ WMT_HOST_AWAKE_EVT[4], ++ WMT_HOST_AWAKE_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ /* goto pwr_sv_done; */ ++ } else { ++ WMT_DBG_FUNC("Send host awake command OK!\n"); ++ } ++ } ++pwr_sv_done: ++ ++ if (pWmtOp->au4OpData[0] < STP_PSM_MAX_ACTION) { ++ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; ++ WMT_DBG_FUNC("Do STP-CB! %d %p / %p\n", pWmtOp->au4OpData[0], (PVOID) pWmtOp->au4OpData[1], ++ (PVOID) psm_cb); ++ if (NULL != psm_cb) { ++ psm_cb(pWmtOp->au4OpData[0]); ++ } else { ++ WMT_ERR_FUNC("fatal error !!!, psm_cb = %p, god, someone must have corrupted our memory.\n", ++ psm_cb); ++ } ++ } ++ ++ return ret; ++} ++ ++static INT32 opfunc_dsns(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_DSNS_CMD[4] = (UINT8) pWmtOp->au4OpData[0]; ++ WMT_DSNS_CMD[5] = (UINT8) pWmtOp->au4OpData[1]; ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_DSNS_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: DSNS_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_DSNS_CMD)); ++ return iRet; ++ } ++ ++ evtLen = osal_sizeof(WMT_DSNS_EVT); ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || (u4Res != evtLen)) { ++ WMT_ERR_FUNC("WMT-CORE: read DSNS_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ mtk_wcn_stp_dbg_dump_package(); ++ return iRet; ++ } ++ ++ if (osal_memcmp(evtBuf, WMT_DSNS_EVT, osal_sizeof(WMT_DSNS_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_DSNS_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], ++ osal_sizeof(WMT_DSNS_EVT), WMT_DSNS_EVT[0], WMT_DSNS_EVT[1], WMT_DSNS_EVT[2], ++ WMT_DSNS_EVT[3], WMT_DSNS_EVT[4]); ++ } else { ++ WMT_INFO_FUNC("Send WMT_DSNS_CMD command OK!\n"); ++ } ++ ++ return iRet; ++} ++ ++#if CFG_CORE_INTERNAL_TXRX ++INT32 wmt_core_lpbk_do_stp_init(void) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -1; ++ } ++ ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_MAND_MODE; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); ++ return -2; ++ } ++} ++ ++INT32 wmt_core_lpbk_do_stp_deinit(void) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++#endif ++static INT32 opfunc_lpbk(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT32 buf_length = 0; ++ UINT32 *pbuffer = NULL; ++ UINT16 len_in_cmd; ++ ++ /* UINT32 offset; */ ++ UINT8 WMT_TEST_LPBK_CMD[] = { 0x1, 0x2, 0x0, 0x0, 0x7 }; ++ UINT8 WMT_TEST_LPBK_EVT[] = { 0x2, 0x2, 0x0, 0x0, 0x0 }; ++ ++ /* UINT8 lpbk_buf[1024 + 5] = {0}; */ ++ MTK_WCN_BOOL fgFail; ++ ++ buf_length = pWmtOp->au4OpData[0]; /* packet length */ ++ pbuffer = (VOID *) pWmtOp->au4OpData[1]; /* packet buffer pointer */ ++ WMT_DBG_FUNC("WMT-CORE: -->wmt_do_lpbk\n"); ++ ++#if 0 ++ osal_memcpy(&WMT_TEST_LPBK_EVT[0], &WMT_TEST_LPBK_CMD[0], osal_sizeof(WMT_TEST_LPBK_CMD)); ++#endif ++#if !CFG_CORE_INTERNAL_TXRX ++ /*check if WMTDRV_TYPE_LPBK function is already on */ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] ++ || buf_length + osal_sizeof(WMT_TEST_LPBK_CMD) > osal_sizeof(gLpbkBuf)) { ++ WMT_ERR_FUNC("WMT-CORE: abnormal LPBK in wmt_do_lpbk\n"); ++ osal_assert(0); ++ return -2; ++ } ++#endif ++ /*package loopback for STP */ ++ ++ /* init buffer */ ++ osal_memset(gLpbkBuf, 0, osal_sizeof(gLpbkBuf)); ++ ++ len_in_cmd = buf_length + 1; /* add flag field */ ++ ++ osal_memcpy(&WMT_TEST_LPBK_CMD[2], &len_in_cmd, 2); ++ osal_memcpy(&WMT_TEST_LPBK_EVT[2], &len_in_cmd, 2); ++ ++ /* wmt cmd */ ++ osal_memcpy(gLpbkBuf, WMT_TEST_LPBK_CMD, osal_sizeof(WMT_TEST_LPBK_CMD)); ++ osal_memcpy(gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), pbuffer, buf_length); ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ /*send packet through STP */ ++ ++ /* iRet = (*kal_stp_tx)( ++ *(PUINT8)gLpbkBuf, ++ *osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length, ++ *&u4WrittenSize); ++ */ ++ iRet = wmt_core_tx((PUINT8) gLpbkBuf, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length), ++ &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet) { ++ WMT_ERR_FUNC("opfunc_lpbk wmt_core_tx failed\n"); ++ break; ++ } ++ WMT_INFO_FUNC("opfunc_lpbk wmt_core_tx OK\n"); ++ ++ /*receive firmware response from STP */ ++ iRet = wmt_core_rx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_EVT) + buf_length), &u4ReadSize); ++ if (iRet) { ++ WMT_ERR_FUNC("opfunc_lpbk wmt_core_rx failed\n"); ++ break; ++ } ++ WMT_INFO_FUNC("opfunc_lpbk wmt_core_rx OK\n"); ++ /*check if loopback response ok or not */ ++ if (u4ReadSize != (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)) { ++ WMT_ERR_FUNC("lpbk event read size wrong(%d, %d)\n", u4ReadSize, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); ++ break; ++ } ++ WMT_INFO_FUNC("lpbk event read size right(%d, %d)\n", u4ReadSize, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); ++ ++ if (osal_memcmp(WMT_TEST_LPBK_EVT, gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_EVT))) { ++ WMT_ERR_FUNC("WMT-CORE WMT_TEST_LPBK_EVT error! read len %d [%02x,%02x,%02x,%02x,%02x]\n", ++ (INT32) u4ReadSize, gLpbkBuf[0], gLpbkBuf[1], gLpbkBuf[2], gLpbkBuf[3], gLpbkBuf[4] ++ ); ++ break; ++ } ++ pWmtOp->au4OpData[0] = u4ReadSize - osal_sizeof(WMT_TEST_LPBK_EVT); ++ osal_memcpy((VOID *) pWmtOp->au4OpData[1], gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), buf_length); ++ fgFail = MTK_WCN_BOOL_FALSE; ++ } while (0); ++ /*return result */ ++ /* WMT_DBG_FUNC("WMT-CORE: <--wmt_do_lpbk, fgFail = %d\n", fgFail); */ ++ return fgFail; ++ ++} ++ ++static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = 0; ++ UINT32 cmdNo = 0; ++ UINT32 cmdNoPa = 0; ++ ++ UINT8 tstCmd[64]; ++ UINT8 tstEvt[64]; ++ UINT8 tstEvtTmp[64]; ++ UINT32 u4Res; ++ SIZE_T tstCmdSz = 0; ++ SIZE_T tstEvtSz = 0; ++ ++ UINT8 *pRes = NULL; ++ UINT32 resBufRoom = 0; ++ /*test command list */ ++ /*1 */ ++ UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; ++ UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_NOACK_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0A }; ++ UINT8 WMT_NOACK_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_WARNRST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0B }; ++ UINT8 WMT_WARNRST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_FWLOGTST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0C }; ++ UINT8 WMT_FWLOGTST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ ++ UINT8 WMT_EXCEPTION_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x09 }; ++ UINT8 WMT_EXCEPTION_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ /*2 */ ++ UINT8 WMT_COEXDBG_CMD[] = { 0x01, 0x10, 0x02, 0x00, ++ 0x08, ++ 0xAA /*Debugging Parameter */ ++ }; ++ UINT8 WMT_COEXDBG_1_EVT[] = { 0x02, 0x10, 0x05, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA /*event content */ ++ }; ++ UINT8 WMT_COEXDBG_2_EVT[] = { 0x02, 0x10, 0x07, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB /*event content */ ++ }; ++ UINT8 WMT_COEXDBG_3_EVT[] = { 0x02, 0x10, 0x0B, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB /*event content */ ++ }; ++ /*test command list -end */ ++ ++ cmdNo = pWmtOp->au4OpData[0]; ++ ++ WMT_INFO_FUNC("Send Test command %d!\n", cmdNo); ++ if (cmdNo == 0) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Assert command !\n"); ++ tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); ++ tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); ++ osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); ++ } else if (cmdNo == 1) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Exception command !\n"); ++ tstCmdSz = osal_sizeof(WMT_EXCEPTION_CMD); ++ tstEvtSz = osal_sizeof(WMT_EXCEPTION_EVT); ++ osal_memcpy(tstCmd, WMT_EXCEPTION_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_EXCEPTION_EVT, tstEvtSz); ++ } else if (cmdNo == 2) { ++ cmdNoPa = pWmtOp->au4OpData[1]; ++ pRes = (PUINT8) pWmtOp->au4OpData[2]; ++ resBufRoom = pWmtOp->au4OpData[3]; ++ if (cmdNoPa <= 0xf) { ++ WMT_INFO_FUNC("Send Coexistence Debug command [0x%x]!\n", cmdNoPa); ++ tstCmdSz = osal_sizeof(WMT_COEXDBG_CMD); ++ osal_memcpy(tstCmd, WMT_COEXDBG_CMD, tstCmdSz); ++ if (tstCmdSz > 5) ++ tstCmd[5] = cmdNoPa; ++ ++ /*setup the expected event length */ ++ if (cmdNoPa <= 0x4) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_1_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_1_EVT, tstEvtSz); ++ } else if (cmdNoPa == 0x5) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_2_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_2_EVT, tstEvtSz); ++ } else if (cmdNoPa >= 0x6 && cmdNoPa <= 0xf) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_3_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_3_EVT, tstEvtSz); ++ } else { ++ ++ } ++ } else { ++ WMT_ERR_FUNC("cmdNoPa is wrong\n"); ++ return iRet; ++ } ++ } else if (cmdNo == 3) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send No Ack command !\n"); ++ tstCmdSz = osal_sizeof(WMT_NOACK_CMD); ++ tstEvtSz = osal_sizeof(WMT_NOACK_EVT); ++ osal_memcpy(tstCmd, WMT_NOACK_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_NOACK_EVT, tstEvtSz); ++ } else if (cmdNo == 4) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Warm reset command !\n"); ++ tstCmdSz = osal_sizeof(WMT_WARNRST_CMD); ++ tstEvtSz = osal_sizeof(WMT_WARNRST_EVT); ++ osal_memcpy(tstCmd, WMT_WARNRST_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_WARNRST_EVT, tstEvtSz); ++ } else if (cmdNo == 5) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send f/w log test command !\n"); ++ tstCmdSz = osal_sizeof(WMT_FWLOGTST_CMD); ++ tstEvtSz = osal_sizeof(WMT_FWLOGTST_EVT); ++ osal_memcpy(tstCmd, WMT_FWLOGTST_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_FWLOGTST_EVT, tstEvtSz); ++ } ++ ++ else { ++ /*Placed youer test WMT command here, easiler to integrate and test with F/W side */ ++ } ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(tstCmd, tstCmdSz, &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != tstCmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, tstCmdSz); ++ return -1; ++ } ++ ++ if ((cmdNo == 0) || (cmdNo == 1) || cmdNo == 3) { ++ WMT_INFO_FUNC("WMT-CORE: not to rx event for assert command\n"); ++ return 0; ++ } ++ ++ iRet = wmt_core_rx(tstEvtTmp, tstEvtSz, &u4Res); ++ ++ /*Event Post Handling */ ++ if (cmdNo == 2) { ++ WMT_INFO_FUNC("#=========================================================#\n"); ++ WMT_INFO_FUNC("coext debugging id = %d", cmdNoPa); ++ if (tstEvtSz > 5) { ++ wmt_core_dump_data(&tstEvtTmp[5], "coex debugging ", tstEvtSz - 5); ++ } else { ++ /* error log */ ++ WMT_ERR_FUNC("error coex debugging event\n"); ++ } ++ /*put response to buffer for shell to read */ ++ if (pRes != NULL && resBufRoom > 0) { ++ pWmtOp->au4OpData[3] = resBufRoom < tstEvtSz - 5 ? resBufRoom : tstEvtSz - 5; ++ osal_memcpy(pRes, &tstEvtTmp[5], pWmtOp->au4OpData[3]); ++ } else ++ pWmtOp->au4OpData[3] = 0; ++ WMT_INFO_FUNC("#=========================================================#\n"); ++ } ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ wmt_core_dump_func_state("BE HW RST"); ++ /*-->Reset WMT data structure*/ ++ /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] = DRV_STS_POWER_OFF; ++ /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = DRV_STS_POWER_OFF; ++ /*enable power off flag, if flag=0, power off connsys will not be executed */ ++ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); ++ /* if wmt is poweroff, we need poweron chip first */ ++ /* Zhiguo : this action also needed in BTIF interface to avoid KE */ ++#if 1 ++ if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_WARN_FUNC("WMT-CORE: WMT is off, need re-poweron\n"); ++ /* power on control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); ++ return -1; ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ } ++#endif ++ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_FUNC_ON) { ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); ++ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; ++ } ++ ++ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_FUNC_ON) { ++ ++ if (NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI] && NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off) { ++ iRet = gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off(gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: turn off WIFI func fail (%d)\n", iRet); ++ ++ /* check all sub-func and do power off */ ++ } else { ++ WMT_INFO_FUNC("wmt core: turn off WIFI func ok!!\n"); ++ } ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; ++ } ++#if 0 ++ /*<4>Power off Combo chip */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF fail (%d)", iRet); ++ WMT_INFO_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF ok (%d)", iRet); ++#endif ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; ++ ++ /*-->PesetCombo chip*/ ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: -->[HW RST] fail iRet(%d)\n", iRet); ++ WMT_WARN_FUNC("WMT-CORE: -->[HW RST] ok\n"); ++ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* 4 close stp */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ if (iRet == -2) { ++ WMT_INFO_FUNC("WMT-CORE:stp should have be closed\n"); ++ return 0; ++ } ++ WMT_ERR_FUNC("WMT-CORE: wmt close stp failed\n"); ++ return -1; ++ } ++ ++ wmt_core_dump_func_state("AF HW RST"); ++ return iRet; ++ ++} ++ ++static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ ++ iRet = wmt_core_stp_init(); ++ if (!iRet) ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; ++ return iRet; ++} ++ ++static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp) ++{ ++ ++ return 0; ++} ++ ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_THERM_CMD[4] = pWmtOp->au4OpData[0]; /*CMD type, refer to ENUM_WMTTHERM_TYPE_T */ ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_THERM_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: THERM_CTRL_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_THERM_CMD)); ++ return iRet; ++ } ++ ++ evtLen = 16; ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || ((u4Res != osal_sizeof(WMT_THERM_CTRL_EVT)) && (u4Res != osal_sizeof(WMT_THERM_READ_EVT)))) { ++ WMT_ERR_FUNC("WMT-CORE: read THERM_CTRL_EVT/THERM_READ_EVENT fail(%d) len(%d, %d)\n", iRet, u4Res, ++ evtLen); ++ mtk_wcn_stp_dbg_dump_package(); ++ return iRet; ++ } ++ if (u4Res == osal_sizeof(WMT_THERM_CTRL_EVT)) { ++ if (osal_memcmp(evtBuf, WMT_THERM_CTRL_EVT, osal_sizeof(WMT_THERM_CTRL_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_CTRL_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], ++ osal_sizeof(WMT_THERM_CTRL_EVT), WMT_THERM_CTRL_EVT[0], WMT_THERM_CTRL_EVT[1], ++ WMT_THERM_CTRL_EVT[2], WMT_THERM_CTRL_EVT[3], WMT_THERM_CTRL_EVT[4]); ++ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_FALSE; /*will return to function driver */ ++ mtk_wcn_stp_dbg_dump_package(); ++ } else { ++ WMT_DBG_FUNC("Send WMT_THERM_CTRL_CMD command OK!\n"); ++ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_TRUE; /*will return to function driver */ ++ } ++ } else { ++ /*no need to judge the real thermal value */ ++ if (osal_memcmp(evtBuf, WMT_THERM_READ_EVT, osal_sizeof(WMT_THERM_READ_EVT) - 1) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_READ_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5], ++ osal_sizeof(WMT_THERM_READ_EVT), WMT_THERM_READ_EVT[0], WMT_THERM_READ_EVT[1], ++ WMT_THERM_READ_EVT[2], WMT_THERM_READ_EVT[3]); ++ pWmtOp->au4OpData[1] = 0xFF; /*will return to function driver */ ++ mtk_wcn_stp_dbg_dump_package(); ++ } else { ++ WMT_DBG_FUNC("Send WMT_THERM_READ_CMD command OK!\n"); ++ pWmtOp->au4OpData[1] = evtBuf[5]; /*will return to function driver */ ++ } ++ } ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_efuse_rw fail: chip is powered off\n"); ++ return -1; ++ } ++ ++ WMT_EFUSE_CMD[4] = (pWmtOp->au4OpData[0]) ? 0x1 : 0x2; /* w:2, r:1 */ ++ osal_memcpy(&WMT_EFUSE_CMD[6], (PUINT8) &pWmtOp->au4OpData[1], 2); /* address */ ++ osal_memcpy(&WMT_EFUSE_CMD[8], (PUINT32) pWmtOp->au4OpData[2], 4); /* value */ ++ ++ wmt_core_dump_data(&WMT_EFUSE_CMD[0], "efuse_cmd", osal_sizeof(WMT_EFUSE_CMD)); ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_EFUSE_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: EFUSE_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_EFUSE_CMD)); ++ return iRet; ++ } ++ ++ evtLen = (pWmtOp->au4OpData[0]) ? osal_sizeof(WMT_EFUSE_EVT) : osal_sizeof(WMT_EFUSE_EVT); ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || (u4Res != evtLen)) ++ WMT_ERR_FUNC("WMT-CORE: read REG_EVB fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ wmt_core_dump_data(&evtBuf[0], "efuse_evt", osal_sizeof(evtBuf)); ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ WMT_IC_PIN_ID id; ++ WMT_IC_PIN_STATE stat; ++ UINT32 flag; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_gpio_ctrl fail: chip is powered off\n"); ++ return -1; ++ } ++ ++ if (!gMtkWmtCtx.p_ic_ops->ic_pin_ctrl) { ++ WMT_ERR_FUNC("WMT-CORE: error, gMtkWmtCtx.p_ic_ops->ic_pin_ctrl(NULL)\n"); ++ return -1; ++ } ++ ++ id = pWmtOp->au4OpData[0]; ++ stat = pWmtOp->au4OpData[1]; ++ flag = pWmtOp->au4OpData[2]; ++ ++ WMT_INFO_FUNC("ic pin id:%d, stat:%d, flag:0x%x\n", id, stat, flag); ++ ++ iRet = (*(gMtkWmtCtx.p_ic_ops->ic_pin_ctrl)) (id, stat, flag); ++ ++ return iRet; ++} ++ ++MTK_WCN_BOOL wmt_core_is_quick_ps_support(void) ++{ ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ ++ if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_quick_sleep)) ++ return (*(pctx->p_ic_ops->is_quick_sleep)) (); ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ ++ if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_aee_dump_support)) ++ bRet = (*(pctx->p_ic_ops->is_aee_dump_support)) (); ++ else ++ bRet = MTK_WCN_BOOL_FALSE; ++ ++ return bRet; ++} ++ ++INT32 opfunc_pin_state(P_WMT_OP pWmtOp) ++{ ++ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ UINT32 iRet = 0; ++ ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_STATE_DUMP, &ctrlPa1, &ctrlPa2); ++ return iRet; ++} ++ ++static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT32 buf_len = 0; ++ UINT8 *buffer = NULL; ++ UINT8 evt_buffer[8] = { 0 }; ++ MTK_WCN_BOOL fgFail; ++ ++ UINT8 WMT_BGW_DESENSE_CMD[] = { ++ 0x01, 0x0e, 0x0f, 0x00, ++ 0x02, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00 ++ }; ++ UINT8 WMT_BGW_DESENSE_EVT[] = { 0x02, 0x0e, 0x01, 0x00, 0x00 }; ++ ++ buf_len = pWmtOp->au4OpData[0]; ++ buffer = (PUINT8) pWmtOp->au4OpData[1]; ++ ++ osal_memcpy(&WMT_BGW_DESENSE_CMD[5], buffer, buf_len); ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ iRet = ++ wmt_core_tx(&WMT_BGW_DESENSE_CMD[0], osal_sizeof(WMT_BGW_DESENSE_CMD), &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4WrittenSize != osal_sizeof(WMT_BGW_DESENSE_CMD))) { ++ WMT_ERR_FUNC("bgw desense tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); ++ break; ++ } ++ ++ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_BGW_DESENSE_EVT), &u4ReadSize); ++ if (iRet || (u4ReadSize != osal_sizeof(WMT_BGW_DESENSE_EVT))) { ++ WMT_ERR_FUNC("bgw desense rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize); ++ break; ++ } ++ ++ if (osal_memcmp(evt_buffer, WMT_BGW_DESENSE_EVT, osal_sizeof(WMT_BGW_DESENSE_EVT)) != 0) { ++ WMT_ERR_FUNC ++ ("bgw desense WMT_BGW_DESENSE_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", ++ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ return fgFail; ++} ++ ++static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp) ++{ ++ UINT32 kind = 0; ++ INT32 iRet = -1; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT8 evt_buffer[12] = { 0 }; ++ MTK_WCN_BOOL fgFail; ++ PUINT8 set_mcu_clk_str[] = { ++ "Enable MCU PLL", ++ "SET MCU CLK to 26M", ++ "SET MCU CLK to 37M", ++ "SET MCU CLK to 64M", ++ "SET MCU CLK to 69M", ++ "SET MCU CLK to 104M", ++ "SET MCU CLK to 118.857M", ++ "SET MCU CLK to 138.67M", ++ "Disable MCU PLL" ++ }; ++ UINT8 WMT_SET_MCU_CLK_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++ }; ++ UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++ UINT8 WMT_EN_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00 }; /* enable pll clk */ ++ UINT8 WMT_26_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x00, 0x4d, 0x84, 0x00 }; /* set 26M */ ++ UINT8 WMT_37_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1e, 0x4d, 0x84, 0x00 }; /* set 37.8M */ ++ UINT8 WMT_64_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1d, 0x4d, 0x84, 0x00 }; /* set 64M */ ++ UINT8 WMT_69_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1c, 0x4d, 0x84, 0x00 }; /* set 69M */ ++ UINT8 WMT_104_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5b, 0x4d, 0x84, 0x00 }; /* set 104M */ ++ UINT8 WMT_108_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5a, 0x4d, 0x84, 0x00 }; /* set 118.857M */ ++ UINT8 WMT_138_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x59, 0x4d, 0x84, 0x00 }; /* set 138.67M */ ++ UINT8 WMT_DIS_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 }; /* disable pll clk */ ++ ++ kind = pWmtOp->au4OpData[0]; ++ WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]); ++ ++ switch (kind) { ++ case 0: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_EN_MCU_CLK_CMD[0], osal_sizeof(WMT_EN_MCU_CLK_CMD)); ++ break; ++ case 1: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_26_MCU_CLK_CMD[0], osal_sizeof(WMT_26_MCU_CLK_CMD)); ++ break; ++ case 2: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_37_MCU_CLK_CMD[0], osal_sizeof(WMT_37_MCU_CLK_CMD)); ++ break; ++ case 3: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_64_MCU_CLK_CMD[0], osal_sizeof(WMT_64_MCU_CLK_CMD)); ++ break; ++ case 4: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_69_MCU_CLK_CMD[0], osal_sizeof(WMT_69_MCU_CLK_CMD)); ++ break; ++ case 5: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_104_MCU_CLK_CMD[0], osal_sizeof(WMT_104_MCU_CLK_CMD)); ++ break; ++ case 6: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_108_MCU_CLK_CMD[0], osal_sizeof(WMT_108_MCU_CLK_CMD)); ++ break; ++ case 7: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_138_MCU_CLK_CMD[0], osal_sizeof(WMT_138_MCU_CLK_CMD)); ++ break; ++ case 8: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_DIS_MCU_CLK_CMD[0], osal_sizeof(WMT_DIS_MCU_CLK_CMD)); ++ break; ++ default: ++ WMT_ERR_FUNC("unknown kind\n"); ++ break; ++ } ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ iRet = ++ wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); ++ break; ++ } ++ ++ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); ++ if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); ++ break; ++ } ++ ++ if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", ++ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4], ++ evt_buffer[5], evt_buffer[6], evt_buffer[7]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ if (MTK_WCN_BOOL_FALSE == fgFail) ++ WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]); ++ ++ WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]); ++ ++ return fgFail; ++} ++ ++static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp) ++{ ++ UINT8 *buffer = NULL; ++ MTK_WCN_BOOL fgFail; ++ UINT32 u4Res; ++ UINT32 aDieChipid = 0; ++ UINT8 soc_adie_chipid_cmd[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; ++ UINT8 soc_adie_chipid_evt[] = { 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ UINT8 evtbuf[20]; ++ INT32 iRet = -1; ++ ++ buffer = (PUINT8) pWmtOp->au4OpData[1]; ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ /* read A die chipid by wmt cmd */ ++ iRet = ++ wmt_core_tx((PUINT8) &soc_adie_chipid_cmd[0], osal_sizeof(soc_adie_chipid_cmd), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_cmd))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, osal_sizeof(soc_adie_chipid_evt), &u4Res); ++ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_evt))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); ++ osal_memcpy(buffer, &evtbuf[u4Res - 2], 2); ++ pWmtOp->au4OpData[0] = 2; ++ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ return fgFail; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp) ++{ ++ MTK_WCN_BOOL fgFail; ++ UINT32 u4Res; ++ UINT8 host_lte_btwf_coex_cmd[] = { 0x01, 0x10, 0x00, 0x00, 0x00 }; ++ UINT8 host_lte_btwf_coex_evt[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ UINT8 *pTxBuf = NULL; ++ UINT8 evtbuf[8] = { 0 }; ++ INT32 iRet = -1; ++ UINT16 msg_len = 0; ++ UINT32 total_len = 0; ++ UINT32 index = 0; ++ UINT8 *msg_local_buffer = NULL; ++ ++ msg_local_buffer = kmalloc(1300, GFP_KERNEL); ++ if (!msg_local_buffer) { ++ WMT_ERR_FUNC("msg_local_buffer kmalloc memory fail\n"); ++ return 0; ++ } ++ ++ pTxBuf = (UINT8 *) pWmtOp->au4OpData[0]; ++ if (NULL == pTxBuf) { ++ WMT_ERR_FUNC("idc msg buffer is NULL\n"); ++ return -1; ++ } ++ iRet = wmt_lib_idc_lock_aquire(); ++ if (iRet) { ++ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", iRet); ++ return iRet; ++ } ++ osal_memcpy(&msg_len, &pTxBuf[0], osal_sizeof(msg_len)); ++ if (msg_len > 1200) { ++ wmt_lib_idc_lock_release(); ++ WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len); ++ return -2; ++ } ++ msg_len += 1; /*flag byte */ ++ ++ osal_memcpy(&host_lte_btwf_coex_cmd[2], &msg_len, 2); ++ host_lte_btwf_coex_cmd[4] = (pWmtOp->au4OpData[1] & 0x00ff); ++ osal_memcpy(&msg_local_buffer[0], &host_lte_btwf_coex_cmd[0], osal_sizeof(host_lte_btwf_coex_cmd)); ++ osal_memcpy(&msg_local_buffer[osal_sizeof(host_lte_btwf_coex_cmd)], ++ &pTxBuf[osal_sizeof(msg_len)], msg_len - 1); ++ ++ wmt_lib_idc_lock_release(); ++ total_len = osal_sizeof(host_lte_btwf_coex_cmd) + msg_len - 1; ++ ++ WMT_DBG_FUNC("wmt_core:idc msg payload len form lte(%d),wmt msg total len(%d)\n", msg_len - 1, ++ total_len); ++ WMT_DBG_FUNC("wmt_core:idc msg payload:\n"); ++ ++ for (index = 0; index < total_len; index++) ++ WMT_DBG_FUNC("0x%02x ", msg_local_buffer[index]); ++ ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ /* read A die chipid by wmt cmd */ ++ iRet = wmt_core_tx((PUINT8) &msg_local_buffer[0], total_len, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != total_len)) { ++ WMT_ERR_FUNC("wmt_core:send lte idc msg to connsys fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, osal_sizeof(host_lte_btwf_coex_evt), &u4Res); ++ if (iRet || (u4Res != osal_sizeof(host_lte_btwf_coex_evt))) { ++ WMT_ERR_FUNC("wmt_core:recv host_lte_btwf_coex_evt fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ kfree(msg_local_buffer); ++ return fgFail; ++} ++#endif ++ ++VOID wmt_core_set_coredump_state(ENUM_DRV_STS state) ++{ ++ WMT_INFO_FUNC("wmt-core: set coredump state(%d)\n", state); ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = state; ++} ++#ifdef CONFIG_MTK_COMBO_ANT ++INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ size_t ctrlPa1 = pWmtOp->au4OpData[0]; ++ UINT32 ctrlPa2 = pWmtOp->au4OpData[1]; ++ PUINT8 pbuf = (PUINT8) ctrlPa1; ++ UINT32 fragSeq = 0; ++ UINT16 fragSize = 0; ++ UINT16 wmtCmdLen; ++ UINT16 wmtPktLen; ++ UINT32 u4Res = 0; ++ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_DWN_EVT)]; ++#if 1 ++ UINT32 ctrlPa3 = pWmtOp->au4OpData[2]; ++ ++ do { ++ fragSize = ctrlPa2; ++ fragSeq = ctrlPa3; ++ gAntBuf[5] = fragSeq; ++ ++ ++ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_DWN_CMD) + 1; ++ ++ /*WMT command length cal */ ++ wmtCmdLen = wmtPktLen - 4; ++#if 0 ++ WMT_ANT_RAM_DWN_CMD[2] = wmtCmdLen & 0xFF; ++ WMT_ANT_RAM_DWN_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; ++#else ++ osal_memcpy(&WMT_ANT_RAM_DWN_CMD[2], &wmtCmdLen, 2); ++#endif ++ ++ ++ ++ WMT_ANT_RAM_DWN_CMD[4] = 1; /*RAM CODE download */ ++ ++ osal_memcpy(gAntBuf, WMT_ANT_RAM_DWN_CMD, sizeof(WMT_ANT_RAM_DWN_CMD)); ++ ++ /*copy ram code content to global buffer */ ++ osal_memcpy(&gAntBuf[osal_sizeof(WMT_ANT_RAM_DWN_CMD) + 1], pbuf, fragSize); ++ ++ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, wmtPktLen, u4Res); ++ ++ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); ++ ++ WMT_ANT_RAM_DWN_EVT[4] = 0; /*download result; 0 */ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_DWN_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_DWN_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) fail(%d)\n", ++ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res, iRet); ++ iRet = -5; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_DWN_EVT, sizeof(WMT_ANT_RAM_DWN_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_DWN_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], ++ antEvtBuf[4], sizeof(WMT_ANT_RAM_DWN_EVT), WMT_ANT_RAM_DWN_EVT[0], ++ WMT_ANT_RAM_DWN_EVT[1], WMT_ANT_RAM_DWN_EVT[2], WMT_ANT_RAM_DWN_EVT[3], ++ WMT_ANT_RAM_DWN_EVT[4]); ++ iRet = -6; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) ok\n", ++ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res); ++ ++ } while (0); ++#else ++ UINT32 patchSize = ctrlPa2; ++ UINT32 patchSizePerFrag = 1000; ++ UINT32 offset; ++ UINT32 fragNum = 0; ++ /*cal patch fragNum */ ++ fragNum = (patchSize + patchSizePerFrag - 1) / patchSizePerFrag; ++ if (2 >= fragNum) { ++ WMT_WARN_FUNC("ANT ramcode size(%d) too short\n", patchSize); ++ return -1; ++ } ++ ++ while (fragSeq < fragNum) { ++ /*update fragNum */ ++ fragSeq++; ++ ++ if (1 == fragSeq) { ++ fragSize = patchSizePerFrag; ++ /*first package */ ++ gAntBuf[5] = 1; /*RAM CODE start */ ++ } else if (fragNum == fragSeq) { ++ /*last package */ ++ fragSize = patchSizePerFrag; ++ gAntBuf[5] = 3; /*RAM CODE end */ ++ } else { ++ /*middle package */ ++ fragSize = patchSize - ((fragNum - 1) * patchSizePerFrag); ++ gAntBuf[5] = 2; /*RAM CODE confinue */ ++ } ++ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_OP_CMD) + 1; ++ ++ /*WMT command length cal */ ++ wmtCmdLen = wmtPktLen - 4; ++ ++ WMT_ANT_RAM_OP_CMD[2] = wmtCmdLen & 0xFF; ++ WMT_ANT_RAM_OP_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; ++ ++ WMT_ANT_RAM_OP_CMD[4] = 1; /*RAM CODE download */ ++ ++ osal_memcpy(gAntBuf, WMT_ANT_RAM_OP_CMD, sizeof(WMT_ANT_RAM_OP_CMD)); ++ ++ /*copy ram code content to global buffer */ ++ osal_memcpy(&gAntBuf[6], pbuf, fragSize); ++ ++ /*update offset */ ++ offset += fragSize; ++ pbuf += offset; ++ ++ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, wmtPktLen, u4Res); ++ ++ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); ++ ++ WMT_SET_RAM_OP_EVT[4] = 0; /*download result; 0 */ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_SET_RAM_OP_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_SET_RAM_OP_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) fail(%d)\n", ++ sizeof(WMT_SET_RAM_OP_EVT), u4Res, iRet); ++ iRet = -5; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_SET_RAM_OP_EVT, sizeof(WMT_SET_RAM_OP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_SET_RAM_OP_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], ++ antEvtBuf[4], sizeof(WMT_SET_RAM_OP_EVT), WMT_SET_RAM_OP_EVT[0], ++ WMT_SET_RAM_OP_EVT[1], WMT_SET_RAM_OP_EVT[2], WMT_SET_RAM_OP_EVT[3], ++ WMT_SET_RAM_OP_EVT[4]); ++ iRet = -6; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) ok\n", ++ sizeof(WMT_SET_RAM_OP_EVT), u4Res); ++ ++ ++ } ++ if (fragSeq != fragNum) ++ iRet = -7; ++#endif ++ return iRet; ++} ++ ++ ++INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ UINT32 u4Res = 0; ++ UINT32 wmtPktLen = osal_sizeof(WMT_ANT_RAM_STA_GET_CMD); ++ UINT32 u4AntRamStatus = 0; ++ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_STA_GET_EVT)]; ++ ++ ++ iRet = wmt_core_tx(WMT_ANT_RAM_STA_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC ++ ("wmt_core: write wmt and ramcode status query command failed, (%d, %d), iRet(%d)\n", ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ return iRet; ++ } ++ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_STA_GET_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_STA_GET_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_STA_GET_EVT length(%zu, %d) fail(%d)\n", ++ sizeof(WMT_ANT_RAM_STA_GET_EVT), u4Res, iRet); ++ iRet = -5; ++ return iRet; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_STA_GET_EVT, sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1) != ++ 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_STA_GET_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], antEvtBuf[4], ++ sizeof(WMT_ANT_RAM_STA_GET_EVT), WMT_ANT_RAM_STA_GET_EVT[0], ++ WMT_ANT_RAM_STA_GET_EVT[1], WMT_ANT_RAM_STA_GET_EVT[2], ++ WMT_ANT_RAM_STA_GET_EVT[3], WMT_ANT_RAM_STA_GET_EVT[4]); ++ iRet = -6; ++ return iRet; ++ } ++#endif ++ if (0 == iRet) { ++ u4AntRamStatus = antEvtBuf[sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1]; ++ pWmtOp->au4OpData[2] = u4AntRamStatus; ++ WMT_INFO_FUNC("ANT ram code %s\n", ++ 1 == u4AntRamStatus ? "exist already" : "not exist"); ++ } ++ return iRet; ++} ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++/*TEST CODE*/ ++static UINT32 g_open_wmt_lte_flag; ++VOID wmt_core_set_flag_for_test(UINT32 enable) ++{ ++ WMT_INFO_FUNC("%s wmt_lte_flag\n", enable ? "enable" : "disable"); ++ g_open_wmt_lte_flag = enable; ++} ++ ++UINT32 wmt_core_get_flag_for_test(VOID) ++{ ++ return g_open_wmt_lte_flag; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c +new file mode 100644 +index 000000000000..fa603c208e59 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c +@@ -0,0 +1,1019 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CTRL]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++ ++#include "wmt_ctrl.h" ++#include "wmt_core.h" ++#include "wmt_ic.h" ++#include "wmt_lib.h" ++#include "wmt_dev.h" ++#include "wmt_plat.h" ++#include "stp_core.h" ++#include "stp_dbg.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* moved to wmt_ctrl.h */ ++/*static INT32 wmt_ctrl_tx_ex (UINT8 *pData, UINT32 size, UINT32 *writtenSize, MTK_WCN_BOOL bRawFlag);*/ ++ ++static INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value); ++ ++static INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA); ++#if 0 ++static INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA); ++#endif ++static INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_others(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData); ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA); ++#endif ++ ++static INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA); ++ ++static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData); ++ ++static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData); ++ ++static INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData); ++ ++/* TODO: [FixMe][GeorgeKuo]: remove unused function */ ++/*static INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA);*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* GeorgeKuo: Use designated initializers described in ++ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html ++ */ ++static const WMT_CTRL_FUNC wmt_ctrl_func[] = { ++ [WMT_CTRL_HW_PWR_OFF] = wmt_ctrl_hw_pwr_off, ++ [WMT_CTRL_HW_PWR_ON] = wmt_ctrl_hw_pwr_on, ++ [WMT_CTRL_HW_RST] = wmt_ctrl_hw_rst, ++ [WMT_CTRL_STP_CLOSE] = wmt_ctrl_stp_close, ++ [WMT_CTRL_STP_OPEN] = wmt_ctrl_stp_open, ++ [WMT_CTRL_STP_CONF] = wmt_ctrl_stp_conf, ++ [WMT_CTRL_FREE_PATCH] = wmt_ctrl_free_patch, ++ [WMT_CTRL_GET_PATCH] = wmt_ctrl_get_patch, ++ [WMT_CTRL_GET_PATCH_NAME] = wmt_ctrl_get_patch_name, ++ [WMT_CTRL_HWIDVER_SET] = wmt_ctrl_hwidver_set, ++ [WMT_CTRL_STP_RST] = wmt_ctrl_stp_rst, ++ [WMT_CTRL_GET_WMT_CONF] = wmt_ctrl_get_wmt_conf, ++ [WMT_CTRL_TX] = wmt_ctrl_tx, ++ [WMT_CTRL_RX] = wmt_ctrl_rx, ++ [WMT_CTRL_RX_FLUSH] = wmt_ctrl_rx_flush, ++ [WMT_CTRL_GPS_SYNC_SET] = wmt_ctrl_gps_sync_set, ++ [WMT_CTRL_GPS_LNA_SET] = wmt_ctrl_gps_lna_set, ++ [WMT_CTRL_PATCH_SEARCH] = wmt_ctrl_patch_search, ++ [WMT_CTRL_CRYSTAL_TRIMING_GET] = wmt_ctrl_crystal_triming_get, ++ [WMT_CTRL_CRYSTAL_TRIMING_PUT] = wmt_ctrl_crystal_triming_put, ++ [WMT_CTRL_HW_STATE_DUMP] = wmt_ctrl_hw_state_show, ++ [WMT_CTRL_GET_PATCH_NUM] = wmt_ctrl_get_patch_num, ++ [WMT_CTRL_GET_PATCH_INFO] = wmt_ctrl_get_patch_info, ++ [WMT_CTRL_SOC_PALDO_CTRL] = wmt_ctrl_soc_paldo_ctrl, ++ [WMT_CTRL_SOC_WAKEUP_CONSYS] = wmt_ctrl_soc_wakeup_consys, ++ [WMT_CTRL_SET_STP_DBG_INFO] = wmt_ctrl_set_stp_dbg_info, ++ [WMT_CTRL_BGW_DESENSE_CTRL] = wmt_ctrl_bgw_desense_ctrl, ++ [WMT_CTRL_EVT_ERR_TRG_ASSERT] = wmt_ctrl_evt_err_trg_assert, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [WMT_CTRL_GET_TDM_REQ_ANTSEL] = wmt_ctrl_get_tdm_req_antsel, ++#endif ++ [WMT_CTRL_EVT_PARSER] = wmt_ctrl_evt_parser, ++ [WMT_CTRL_MAX] = wmt_ctrl_others, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 ctrlId; ++ ++ if (NULL == pWmtCtrlData) { ++ osal_assert(0); ++ return -1; ++ } ++ ++ ctrlId = pWmtCtrlData->ctrlId; ++ /*1sanity check, including wmtCtrlId */ ++ if ((NULL == pWmtCtrlData) ++ || (WMT_CTRL_MAX <= ctrlId)) ++ /* || (ctrlId < WMT_CTRL_HW_PWR_OFF) ) [FixMe][GeorgeKuo]: useless comparison */ ++ { ++ osal_assert(NULL != pWmtCtrlData); ++ osal_assert(WMT_CTRL_MAX > ctrlId); ++ /* osal_assert(ctrlId >= WMT_CTRL_HW_PWR_OFF); [FixMe][GeorgeKuo]: useless comparison */ ++ return -2; ++ } ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ if (wmt_ctrl_func[ctrlId]) { ++ /*call servicd handling API */ ++ return (*(wmt_ctrl_func[ctrlId])) (pWmtCtrlData); /* serviceHandlerPack[ctrlId].serviceHandler */ ++ } ++ osal_assert(NULL != wmt_ctrl_func[ctrlId]); ++ return -3; ++ ++} ++ ++INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pData, UINT32 size, UINT32 *writtenSize */) ++{ ++ UINT8 *pData = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ UINT32 size = pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 writtenSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ MTK_WCN_BOOL bRawFlag = pWmtCtrlData->au4CtrlData[3]; ++ ++ return wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++} ++ ++INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pBuff, UINT32 buffLen, UINT32 *readSize */) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 readLen; ++ long waitRet = -1; ++ PUINT8 pBuff = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ UINT32 buffLen = pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 readSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ ++ if (readSize) ++ *readSize = 0; ++ ++ /* sanity check */ ++ if (!buffLen) { ++ WMT_WARN_FUNC("buffLen = 0\n"); ++ osal_assert(buffLen); ++ return 0; ++ } ++#if 0 ++ if (!pDev) { ++ WMT_WARN_FUNC("gpDevWmt = NULL\n"); ++ osal_assert(pDev); ++ return -1; ++ } ++#endif ++ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { ++ WMT_WARN_FUNC("state(0x%lx)\n", pDev->state); ++ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); ++ return -2; ++ } ++ ++ /* sanity ok, proceeding rx operation */ ++ /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ ++ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); ++ ++ while (readLen == 0) { /* got nothing, wait for STP's signal */ ++ WMT_LOUD_FUNC("before wmt_dev_rx_timeout\n"); ++ /* iRet = wait_event_interruptible(pdev->rWmtRxWq, osal_test_bit(WMT_STAT_RX, &pdev->state)); */ ++ /* waitRet = wait_event_interruptible_timeout( ++ * pDev->rWmtRxWq, ++ * osal_test_bit(WMT_STAT_RX, &pdev->state), ++ * msecs_to_jiffies(WMT_LIB_RX_TIMEOUT)); ++ */ ++ pDev->rWmtRxWq.timeoutValue = WMT_LIB_RX_TIMEOUT; ++ /* waitRet = osal_wait_for_event_bit_timeout(&pDev->rWmtRxWq, &pDev->state, WMT_STAT_RX); */ ++ waitRet = wmt_dev_rx_timeout(&pDev->rWmtRxWq); ++ ++ WMT_LOUD_FUNC("wmt_dev_rx_timeout returned\n"); ++ ++ if (0 == waitRet) { ++ WMT_ERR_FUNC("wmt_dev_rx_timeout: timeout,jiffies(%lu),timeoutvalue(%d)\n", ++ jiffies, pDev->rWmtRxWq.timeoutValue); ++ return -1; ++ } else if (waitRet < 0) { ++ WMT_WARN_FUNC("wmt_dev_rx_timeout: interrupted by signal (%ld)\n", waitRet); ++ return waitRet; ++ } ++ WMT_DBG_FUNC("wmt_dev_rx_timeout, iRet(%ld)\n", waitRet); ++ /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ ++ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); ++ ++ if (0 == readLen) ++ WMT_WARN_FUNC("wmt_ctrl_rx be signaled, but no rx data(%ld)\n", waitRet); ++ ++ } ++ ++ if (readSize) ++ *readSize = readLen; ++ ++ return 0; ++ ++} ++ ++INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ ++ if (NULL != writtenSize) ++ *writtenSize = 0; ++ ++ /* sanity check */ ++ if (0 == size) { ++ WMT_WARN_FUNC("size to tx is 0\n"); ++ osal_assert(size); ++ return -1; ++ } ++ ++ /* if STP is not enabled yet, can't use this function. Use tx_raw instead */ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state) || !osal_test_bit(WMT_STAT_STP_EN, &pDev->state)) { ++ WMT_ERR_FUNC("wmt state(0x%lx)\n", pDev->state); ++ osal_assert(osal_test_bit(WMT_STAT_STP_EN, &pDev->state)); ++ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); ++ return -2; ++ } ++ ++ /* sanity ok, proceeding tx operation */ ++ /*retval = mtk_wcn_stp_send_data(data, size, WMTDRV_TYPE_WMT); */ ++ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); ++ if (bRawFlag) ++ iRet = mtk_wcn_stp_send_data_raw(pData, size, WMT_TASK_INDX); ++ else ++ iRet = mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX); ++ ++ if (iRet != size) { ++ WMT_WARN_FUNC("write(%d) written(%d)\n", size, iRet); ++ osal_assert(iRet == size); ++ } ++ ++ if (writtenSize) ++ *writtenSize = iRet; ++ ++ return 0; ++ ++} ++ ++INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 type = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_INFO_FUNC("flush rx %d queue\n", type); ++ mtk_wcn_stp_flush_rx_queue(type); ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iret; ++ ++/*psm should be disabled before wmt_ic_deinit*/ ++ P_DEV_WMT pDev = &gDevWmt; ++ ++ if (osal_test_and_clear_bit(WMT_STAT_PWR, &pDev->state)) { ++ WMT_DBG_FUNC("on->off\n"); ++ iret = wmt_plat_pwr_ctrl(FUNC_OFF); ++ } else { ++ WMT_WARN_FUNC("already off\n"); ++ iret = 0; ++ } ++ ++ return iret; ++} ++ ++INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iret; ++ /*psm should be enabled right after wmt_ic_init */ ++ P_DEV_WMT pDev = &gDevWmt; ++ if (osal_test_and_set_bit(WMT_STAT_PWR, &pDev->state)) { ++ WMT_WARN_FUNC("already on\n"); ++ iret = 0; ++ } else { ++ WMT_DBG_FUNC("off->on\n"); ++ iret = wmt_plat_pwr_ctrl(FUNC_ON); ++ } ++ ++ return iret; ++} ++ ++INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const UINT8 *pCmdStr) ++{ ++ INT32 waitRet = -1; ++ P_OSAL_SIGNAL pCmdSignal; ++ P_OSAL_EVENT pCmdReq; ++ ++ if (osal_test_and_set_bit(WMT_STAT_CMD, &pWmtDev->state)) { ++ WMT_WARN_FUNC("cmd buf is occupied by (%s)\n", pWmtDev->cCmd); ++ return -1; ++ } ++ ++ /* indicate baud rate change to user space app */ ++#if 0 ++ INIT_COMPLETION(pWmtDev->cmd_comp); ++ pWmtDev->cmd_result = -1; ++ strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); ++ pWmtDev->cCmd[NAME_MAX] = '\0'; ++ wake_up_interruptible(&pWmtDev->cmd_wq); ++#endif ++ ++ pCmdSignal = &pWmtDev->cmdResp; ++ osal_signal_init(pCmdSignal); ++ pCmdSignal->timeoutValue = 2000; ++ osal_strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); ++ pWmtDev->cCmd[NAME_MAX] = '\0'; ++ ++ pCmdReq = &pWmtDev->cmdReq; ++ ++ osal_trigger_event(&pWmtDev->cmdReq); ++ WMT_DBG_FUNC("str(%s) request ok\n", pCmdStr); ++ ++/* waitRet = wait_for_completion_interruptible_timeout(&pWmtDev->cmd_comp, msecs_to_jiffies(2000)); */ ++ waitRet = osal_wait_for_signal_timeout(pCmdSignal); ++ WMT_LOUD_FUNC("wait signal iRet:%d\n", waitRet); ++ if (0 == waitRet) { ++ WMT_ERR_FUNC("wait signal timeout\n"); ++ return -2; ++ } ++ ++ WMT_DBG_FUNC("str(%s) result(%d)\n", pCmdStr, pWmtDev->cmdResult); ++ ++ return pWmtDev->cmdResult; ++} ++ ++INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ wmt_plat_pwr_ctrl(FUNC_RST); ++ return 0; ++} ++ ++INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ wmt_plat_pwr_ctrl(FUNC_STAT); ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet = 0; ++ /* un-register to STP-core for rx */ ++ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, NULL); /* mtk_wcn_stp_register_event_cb */ ++ if (iRet) { ++ WMT_WARN_FUNC("stp_reg cb unregister fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /*un-register rxcb to btif */ ++ iRet = mtk_wcn_stp_rxcb_register(NULL); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_unregister fail(%d)\n", iRet); ++ return -2; ++ } ++ ++ iRet = mtk_wcn_stp_close_btif(); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_close_btif fail(%d)\n", iRet); ++ return -3; ++ } ++ osal_clear_bit(WMT_STAT_STP_OPEN, &pDev->state); ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ ++ iRet = mtk_wcn_stp_open_btif(); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_open_btif fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /*register stp rx call back to btif */ ++ iRet = mtk_wcn_stp_rxcb_register((MTK_WCN_BTIF_RX_CB) mtk_wcn_stp_parser_data); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_register fail(%d)\n", iRet); ++ return -2; ++ } ++ /* register to STP-core for rx */ ++ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, wmt_dev_rx_event_cb); ++ if (iRet) { ++ WMT_WARN_FUNC("stp_reg cb fail(%d)\n", iRet); ++ return -3; ++ } ++ ++ osal_set_bit(WMT_STAT_STP_OPEN, &pDev->state); ++ ++#if 0 ++ iRet = mtk_wcn_stp_lpbk_ctrl(1); ++#endif ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ UINT8 cmdStr[NAME_MAX + 1] = { 0 }; ++ ++ osal_snprintf(cmdStr, NAME_MAX, "srh_patch"); ++ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); ++ if (iRet) { ++ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); ++ return -1; ++ } ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ pWmtCtrlData->au4CtrlData[0] = pDev->patchNum; ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ UINT32 downLoadSeq = 0; ++ P_WMT_PATCH_INFO pPatchinfo = NULL; ++ PUINT8 pNbuf = NULL; ++ PUINT8 pAbuf = NULL; ++ ++ downLoadSeq = pWmtCtrlData->au4CtrlData[0]; ++ WMT_DBG_FUNC("download seq is %d\n", downLoadSeq); ++ ++ pPatchinfo = pDev->pWmtPatchInfo + downLoadSeq - 1; ++ pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1]; ++ pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2]; ++ if (pPatchinfo) { ++ osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName)); ++ osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess)); ++ WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", pAbuf[0], pAbuf[1], pAbuf[2], pAbuf[3]); ++ } else { ++ WMT_ERR_FUNC("NULL patchinfo pointer\n"); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ ENUM_PALDO_TYPE ept = pWmtCtrlData->au4CtrlData[0]; ++ ENUM_PALDO_OP epo = pWmtCtrlData->au4CtrlData[1]; ++ ++ WMT_DBG_FUNC("ept(%d),epo(%d)\n", ept, epo); ++ iRet = wmt_plat_soc_paldo_ctrl(ept, epo); ++ if (iRet) { ++ if (PMIC_CHIPID_PALDO == ept) { ++ /* special handling for PMIC CHIPID */ ++ pWmtCtrlData->au4CtrlData[2] = iRet; ++ } else { ++ /* for other PA handling */ ++ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ ++ iRet = mtk_wcn_stp_wakeup_consys(); ++ if (iRet) ++ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value) ++{ ++ INT32 iRet = -1; ++ ++ switch (type) { ++ case WMT_STP_CONF_EN: ++ iRet = mtk_wcn_stp_enable(value); ++ break; ++ ++ case WMT_STP_CONF_RDY: ++ iRet = mtk_wcn_stp_ready(value); ++ break; ++ ++ case WMT_STP_CONF_MODE: ++ mtk_wcn_stp_set_mode(value); ++ iRet = 0; ++ break; ++ ++ default: ++ WMT_WARN_FUNC("invalid type(%d) value(%d)\n", type, value); ++ break; ++ } ++ return iRet; ++} ++ ++INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ UINT32 type; ++ UINT32 value; ++ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_STP_ENABLE but invalid Handle of WmtStp\n"); ++ return -1; ++ } ++ ++ type = pWmtCtrlData->au4CtrlData[0]; ++ value = pWmtCtrlData->au4CtrlData[1]; ++ iRet = wmt_ctrl_stp_conf_ex(type, value); ++ ++ if (!iRet) { ++ if (WMT_STP_CONF_EN == type) { ++ if (value) { ++ osal_set_bit(WMT_STAT_STP_EN, &pDev->state); ++ WMT_DBG_FUNC("enable STP\n"); ++ } else { ++ osal_clear_bit(WMT_STAT_STP_EN, &pDev->state); ++ WMT_DBG_FUNC("disable STP\n"); ++ } ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 patchSeq = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (NULL != gDevWmt.pPatch) ++ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pPatch)); ++ ++ WMT_DBG_FUNC("AF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (patchSeq == gDevWmt.patchNum) { ++ WMT_DBG_FUNC("the %d patch has been download\n", patchSeq); ++ wmt_dev_patch_info_free(); ++ } ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ PUINT8 pBuf = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ ++ osal_memcpy(pBuf, gDevWmt.cPatchName, osal_sizeof(gDevWmt.cPatchName)); ++ return 0; ++} ++ ++INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (NULL != gDevWmt.pNvram) ++ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pNvram)); ++ ++ WMT_DBG_FUNC("AF free patch, gDevWmt.pNvram(0x%08x)\n", gDevWmt.pNvram); ++ return 0; ++} ++ ++INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0x0; ++ PUINT8 pFileName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ ++ osal_firmware *pNvram = NULL; ++ ++ if ((NULL == pFileName) || (NULL == pSize)) { ++ WMT_ERR_FUNC("parameter error, pFileName(0x%08x), pSize(0x%08x)\n", pFileName, pSize); ++ iRet = -1; ++ return iRet; ++ } ++ if (0 == wmt_dev_patch_get(pFileName, &pNvram, 0)) { ++ *ppBuf = (PUINT8) (pNvram)->data; ++ *pSize = (pNvram)->size; ++ gDevWmt.pNvram = pNvram; ++ return 0; ++ } ++ return -1; ++ ++} ++ ++INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT8 *pFullPatchName = NULL; ++ UINT8 *pDefPatchName = NULL; ++ PUINT8 *ppBuf = (PUINT8 *) pWmtCtrlData->au4CtrlData[2]; ++ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[3]; ++ ++ osal_firmware *pPatch = NULL; ++ ++ pFullPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[1]; ++ WMT_DBG_FUNC("BF get patch, pPatch(0x%08x)\n", pPatch); ++ if ((NULL != pFullPatchName) ++ && (0 == wmt_dev_patch_get(pFullPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { ++ /*get full name patch success */ ++ WMT_DBG_FUNC("get full patch name(%s) buf(0x%p) size(%d)\n", ++ pFullPatchName, (pPatch)->data, (pPatch)->size); ++ WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); ++ *ppBuf = (PUINT8) (pPatch)->data; ++ *pSize = (pPatch)->size; ++ gDevWmt.pPatch = pPatch; ++ return 0; ++ } ++ ++ pDefPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ if ((NULL != pDefPatchName) ++ && (0 == wmt_dev_patch_get(pDefPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { ++ WMT_DBG_FUNC("get def patch name(%s) buf(0x%p) size(%d)\n", ++ pDefPatchName, (pPatch)->data, (pPatch)->size); ++ WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); ++ /*get full name patch success */ ++ *ppBuf = (PUINT8) (pPatch)->data; ++ *pSize = (pPatch)->size; ++ gDevWmt.pPatch = pPatch; ++ return 0; ++ } ++ return -1; ++ ++} ++ ++/*do not need contol uart because B/G/F send/receive data by BTIF*/ ++#if 0 ++INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ char cmdStr[NAME_MAX + 1] = { 0 }; ++ UINT32 u4Baudrate = pWmtCtrlData->au4CtrlData[0]; ++ UINT32 u4FlowCtrl = pWmtCtrlData->au4CtrlData[1]; ++ ++ WMT_DBG_FUNC("baud(%d), flowctrl(%d)\n", u4Baudrate, u4FlowCtrl); ++ ++ if (osal_test_bit(WMT_STAT_STP_OPEN, &gDevWmt.state)) { ++ osal_snprintf(cmdStr, NAME_MAX, "baud_%d_%d", u4Baudrate, u4FlowCtrl); ++ iRet = wmt_ctrl_ul_cmd(&gDevWmt, cmdStr); ++ if (iRet) { ++ WMT_WARN_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) fail(%d)\n", ++ u4Baudrate, pWmtCtrlData->au4CtrlData[1], iRet); ++ } else { ++ WMT_DBG_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) ok\n", u4Baudrate, u4FlowCtrl); ++ } ++ } else { ++ WMT_INFO_FUNC("CTRL_BAUDRATE but invalid Handle of WmtStp\n"); ++ } ++ return iRet; ++} ++#endif ++/*do not need control SDIO because wifi send/receive data by sdio*/ ++#if 0 ++INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ UINT32 statBit = WMT_STAT_SDIO1_ON; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ WMT_SDIO_SLOT_NUM sdioSlotNum = pWmtCtrlData->au4CtrlData[0]; ++ ENUM_FUNC_STATE funcState = pWmtCtrlData->au4CtrlData[1]; ++ ++ if ((WMT_SDIO_SLOT_INVALID == sdioSlotNum) ++ || (WMT_SDIO_SLOT_MAX <= sdioSlotNum)) { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT(%d) but invalid slot num\n", sdioSlotNum); ++ return -1; ++ } ++ ++ WMT_DBG_FUNC("WMT_CTRL_SDIO_HW (0x%x, %d)\n", sdioSlotNum, funcState); ++ ++ if (WMT_SDIO_SLOT_SDIO2 == sdioSlotNum) ++ statBit = WMT_STAT_SDIO2_ON; ++ ++ if (funcState) { ++ if (osal_test_and_set_bit(statBit, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already ON\n", sdioSlotNum); ++ /* still return 0 */ ++ iRet = 0; ++ } else { ++ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_ON); ++ } ++ } else { ++ if (osal_test_and_clear_bit(statBit, &pDev->state)) { ++ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_OFF); ++ } else { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already OFF\n", sdioSlotNum); ++ /* still return 0 */ ++ iRet = 0; ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ UINT32 statBit = WMT_STAT_SDIO_WIFI_ON; ++ INT32 retry = 10; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ WMT_SDIO_FUNC_TYPE sdioFuncType = pWmtCtrlData->au4CtrlData[0]; ++ UINT32 u4On = pWmtCtrlData->au4CtrlData[1]; ++ ++ if (WMT_SDIO_FUNC_MAX <= sdioFuncType) { ++ WMT_ERR_FUNC("CTRL_SDIO_FUNC, invalid func type (%d)\n", sdioFuncType); ++ return -1; ++ } ++ ++ if (WMT_SDIO_FUNC_STP == sdioFuncType) ++ statBit = WMT_STAT_SDIO_STP_ON; ++ ++ if (u4On) { ++ if (osal_test_bit(statBit, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already ON\n", sdioFuncType); ++ iRet = 0; ++ } else { ++ while (retry-- > 0 && iRet != 0) { ++ if (iRet) { ++ /* sleep 150ms before sdio slot ON ready */ ++ osal_sleep_ms(150); ++ } ++ iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_TRUE); ++ if (HIF_SDIO_ERR_NOT_PROBED == iRet) { ++ /* not probed case, retry */ ++ continue; ++ } else if (HIF_SDIO_ERR_CLT_NOT_REG == iRet) { ++ /* For WiFi, client not reg yet, no need to retry, ++ *WiFi function can work any time when wlan.ko ++ *is insert into system ++ */ ++ iRet = 0; ++ } else { ++ /* other fail cases, stop */ ++ break; ++ } ++ } ++ if (!retry || iRet) { ++ WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, TRUE) fail(%d) retry(%d)\n", ++ sdioFuncType, iRet, retry); ++ } else { ++ osal_set_bit(statBit, &pDev->state); ++ } ++ } ++ } else { ++ if (osal_test_bit(statBit, &pDev->state)) { ++ iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_FALSE); ++ if (iRet) ++ WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, FALSE) fail(%d)\n", sdioFuncType, iRet); ++ /*any way, set to OFF state */ ++ osal_clear_bit(statBit, &pDev->state); ++ } else { ++ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already OFF\n", sdioFuncType); ++ iRet = 0; ++ } ++ } ++ ++ return iRet; ++} ++#endif ++ ++ ++INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ /* input sanity check is done in wmt_ctrl() */ ++ pDev->chip_id = (pWmtCtrlData->au4CtrlData[0] & 0xFFFF0000) >> 16; ++ pDev->hw_ver = pWmtCtrlData->au4CtrlData[0] & 0x0000FFFF; ++ pDev->fw_ver = pWmtCtrlData->au4CtrlData[1] & 0x0000FFFF; ++ ++ /* TODO: [FixMe][GeorgeKuo] remove translated ENUM_WMTHWVER_TYPE_T in the future!!! */ ++ /* Only use hw_ver read from hw. */ ++ pDev->eWmtHwVer = (ENUM_WMTHWVER_TYPE_T) (pWmtCtrlData->au4CtrlData[1] & 0xFFFF0000) >> 16; ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT8 *pRomVer = NULL; ++ P_WMT_PATCH pPatch = NULL; ++ UINT32 chipID = 0; ++ ++ chipID = pWmtCtrlData->au4CtrlData[0]; ++ pRomVer = (PUINT8) (pWmtCtrlData->au4CtrlData[1]); ++ pPatch = (P_WMT_PATCH) (pWmtCtrlData->au4CtrlData[2]); ++ if (!pRomVer) { ++ WMT_ERR_FUNC("pRomVer null pointer\n"); ++ return -1; ++ } ++ if (!pPatch) { ++ WMT_ERR_FUNC("pPatch null pointer\n"); ++ return -2; ++ } ++ WMT_DBG_FUNC("chipid(0x%x),rom(%s),patch date(%s),patch plat(%s)\n", chipID, pRomVer, pPatch->ucDateTime, ++ pPatch->ucPLat); ++ return stp_dbg_set_version_info(chipID, pRomVer, &(pPatch->ucDateTime[0]), &(pPatch->ucPLat[0])); ++} ++ ++static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 cmd = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_INFO_FUNC("wmt-ctrl:send native cmd(%d)\n", cmd); ++ wmt_dev_send_cmd_to_daemon(cmd); ++ ++ return 0; ++} ++ ++static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ ++ ENUM_WMTDRV_TYPE_T drv_type; ++ UINT32 reason = 0; ++ ++ drv_type = pWmtCtrlData->au4CtrlData[0]; ++ reason = pWmtCtrlData->au4CtrlData[1]; ++ WMT_WARN_FUNC("wmt-ctrl:drv_type(%d),reason(%d)\n", drv_type, reason); ++ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ wmt_lib_set_host_assert_info(drv_type, reason, 1); ++ ++ iRet = mtk_wcn_stp_wmt_evt_err_trg_assert(); ++ if (iRet) ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ } else { ++ /* maybe assert triggered by stp noack*/ ++ WMT_INFO_FUNC("do trigger assert & chip reset in stp noack\n"); ++ } ++ return 0; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 antsel_index = wmt_plat_get_tdm_antsel_index(); ++ ++ if (0 <= antsel_index) ++ pWmtCtrlData->au4CtrlData[0] = antsel_index; ++ else ++ pWmtCtrlData->au4CtrlData[0] = 0xff; ++ ++ WMT_INFO_FUNC("get tdm req antsel index is %d\n", antsel_index); ++ ++ return 0; ++} ++#endif ++ ++static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 ret = -1; ++ UINT32 evt_idx = (UINT32) pWmtCtrlData->au4CtrlData[0]; ++ UINT8 *p_buf = NULL; ++ ++ static UINT8 sleep_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; ++ static UINT8 wakeup_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++ static UINT8 hostawake_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; ++ static UINT8 *evt_array[] = { sleep_evt, wakeup_evt, hostawake_evt }; ++ ++ p_buf = evt_array[evt_idx - 1]; ++ ++ WMT_INFO_FUNC("evt index:%d,p_buf:%p\n", evt_idx, p_buf); ++ ++ ret = mtk_wcn_consys_stp_btif_parser_wmt_evt(p_buf, 6); ++ if (ret == 1) { ++ WMT_INFO_FUNC("parser wmt evt from BTIF buf is OK\n"); ++ return 0; ++ } ++ WMT_ERR_FUNC("parser wmt evt from BTIF buf fail(%d)\n", ret); ++ return -1; ++} ++ ++static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData) ++{ ++ INT32 iret; ++ ++ WMT_INFO_FUNC("ctrl GPS_SYNC(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); ++ iret = wmt_plat_gpio_ctrl(PIN_GPS_SYNC, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); ++ ++ if (iret) { ++ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", ++ (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX, iret); ++ } ++ ++ return 0; ++} ++ ++static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData) ++{ ++ INT32 iret; ++ ++ WMT_INFO_FUNC("ctrl GPS_LNA(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); ++ iret = wmt_plat_gpio_ctrl(PIN_GPS_LNA, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); ++ ++ if (iret) { ++ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", ++ (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H, iret); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ pWmtCtrlData->au4CtrlData[0] = (SIZE_T) &pDev->rWmtGenConf; ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_others(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ WMT_ERR_FUNC("wmt_ctrl_others, invalid CTRL ID (%d)\n", pWmtCtrlData->ctrlId); ++ return -1; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c +new file mode 100644 +index 000000000000..d42d572c9292 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c +@@ -0,0 +1,713 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-FUNC]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_func.h" ++#include "wmt_lib.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_BT_SUPPORT ++ ++static INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_bt_ops = { ++ /* BT subsystem function on/off */ ++ .func_on = wmt_func_bt_on, ++ .func_off = wmt_func_bt_off ++}; ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ ++static INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_fm_ops = { ++ /* FM subsystem function on/off */ ++ .func_on = wmt_func_fm_on, ++ .func_off = wmt_func_fm_off ++}; ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ ++static INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_gps_ops = { ++ /* GPS subsystem function on/off */ ++ .func_on = wmt_func_gps_on, ++ .func_off = wmt_func_gps_off ++}; ++ ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++static INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_wifi_ops = { ++ /* Wi-Fi subsystem function on/off */ ++ .func_on = wmt_func_wifi_on, ++ .func_off = wmt_func_wifi_off ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_GPS_SUPPORT ++CMB_PIN_CTRL_REG eediPinOhRegs[] = { ++ { ++ /* pull down ctrl register */ ++ .regAddr = 0x80050020, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ }, ++ { ++ /* pull up ctrl register */ ++ .regAddr = 0x80050000, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020, ++ }, ++ { ++ /* iomode ctrl register */ ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 0, ++ .regMask = 0x00000007, ++ }, ++ { ++ /* output high/low ctrl register */ ++ .regAddr = 0x80050040, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG eediPinOlRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020UL, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 0, ++ .regMask = 0x00000007, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ } ++}; ++ ++CMB_PIN_CTRL_REG eedoPinOhRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080UL, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080UL, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 12, ++ .regMask = 0x00007000UL, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080, ++ } ++}; ++ ++CMB_PIN_CTRL_REG eedoPinOlRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 12, ++ .regMask = 0x00007000, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG gsyncPinOnRegs[] = { ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x3 << 20, ++ .regMask = 0x7 << 20, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG gsyncPinOffRegs[] = { ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x0 << 20, ++ .regMask = 0x7 << 20, ++ } ++}; ++ ++/* templete usage for GPIO control */ ++CMB_PIN_CTRL gCmbPinCtrl[3] = { ++ { ++ .pinId = CMB_PIN_EEDI_ID, ++ .regNum = 4, ++ .pFuncOnArray = eediPinOhRegs, ++ .pFuncOffArray = eediPinOlRegs, ++ }, ++ { ++ .pinId = CMB_PIN_EEDO_ID, ++ .regNum = 4, ++ .pFuncOnArray = eedoPinOhRegs, ++ .pFuncOffArray = eedoPinOlRegs, ++ }, ++ { ++ .pinId = CMB_PIN_GSYNC_ID, ++ .regNum = 1, ++ .pFuncOnArray = gsyncPinOnRegs, ++ .pFuncOffArray = gsyncPinOffRegs, ++ } ++}; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_FUNC_BT_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_bt_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*only need to send turn BT subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_bt_ctrl(FUNC_ON); */ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); ++ return -1; ++ } ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_on) failed(%d)\n", iRet); ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ /*do coredump when bt on fail */ ++ wmt_core_set_coredump_state(DRV_STS_FUNC_ON); ++ ctrlPa1 = WMTDRV_TYPE_BT; ++ ctrlPa2 = 32; ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); ++ return -2; ++ } ++ osal_set_bit(WMT_BT_ON, &gBtWifiGpsState); ++ if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ return 0; ++} ++ ++INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_bt_ctrl(FUNC_OFF); */ ++ INT32 iRet1 = -1; ++ INT32 iRet2 = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ iRet1 = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE); ++ if (iRet1) ++ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_off) failed(%d)\n", iRet1); ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet2 = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet2) ++ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl(bt_off) failed(%d)\n", iRet2); ++ ++ if (iRet1 + iRet2) { ++ /*do coredump when bt off fail */ ++ wmt_core_set_coredump_state(DRV_STS_FUNC_ON); ++ ctrlPa1 = WMTDRV_TYPE_BT; ++ ctrlPa2 = 32; ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); ++ return -1; ++ } ++ ++ osal_clear_bit(WMT_BT_ON, &gBtWifiGpsState); ++ if ((!osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stopping send de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ return 0; ++} ++ ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_gps_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*send turn GPS subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_GPS, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_gps_pre_ctrl(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf, ENUM_FUNC_STATE funcStatus) ++{ ++ UINT32 i = 0; ++ INT32 iRet = 0; ++ UINT32 regAddr = 0; ++ UINT32 regValue = 0; ++ UINT32 regMask = 0; ++ UINT32 regNum = 0; ++ P_CMB_PIN_CTRL_REG pReg; ++ P_CMB_PIN_CTRL pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; ++ WMT_CTRL_DATA ctrlData; ++ WMT_IC_PIN_ID wmtIcPinId = WMT_IC_PIN_MAX; ++ /* sanity check */ ++ if (FUNC_ON != funcStatus && FUNC_OFF != funcStatus) { ++ WMT_ERR_FUNC("invalid funcStatus(%d)\n", funcStatus); ++ return -1; ++ } ++ /* turn on GPS sync function on both side */ ++ ctrlData.ctrlId = WMT_CTRL_GPS_SYNC_SET; ++ ctrlData.au4CtrlData[0] = (FUNC_ON == funcStatus) ? 1 : 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /*we suppose this would never print */ ++ WMT_ERR_FUNC("ctrl GPS_SYNC_SET(%d) fail, ret(%d)\n", funcStatus, iRet); ++ /* TODO:[FixMe][George] error handling? */ ++ return -2; ++ } ++ WMT_INFO_FUNC("ctrl GPS_SYNC_SET(%d) ok\n", funcStatus); ++ ++ ++ if ((NULL == pOps->ic_pin_ctrl) || ++ (0 > pOps->ic_pin_ctrl( ++ WMT_IC_PIN_GSYNC, ++ FUNC_ON == funcStatus ? WMT_IC_PIN_MUX : WMT_IC_PIN_GPIO, ++ 1))) { /*WMT_IC_PIN_GSYNC */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; ++ regNum = pCmbPinCtrl->regNum; ++ for (i = 0; i < regNum; i++) { ++ if (FUNC_ON == funcStatus) ++ pReg = &pCmbPinCtrl->pFuncOnArray[i]; ++ else ++ pReg = &pCmbPinCtrl->pFuncOffArray[i]; ++ ++ regAddr = pReg->regAddr; ++ regValue = pReg->regValue; ++ regMask = pReg->regMask; ++ ++ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); ++ if (iRet) { ++ WMT_ERR_FUNC("set reg for GPS_SYNC function fail(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -2; ++ } ++ ++ } ++ } else { ++ WMT_INFO_FUNC("set reg for GPS_SYNC function okay by chip ic_pin_ctrl\n"); ++ } ++ WMT_INFO_FUNC("ctrl combo chip gps sync function succeed\n"); ++ /* turn on GPS lna ctrl function */ ++ if (NULL != pConf) { ++ if (0 == pConf->wmt_gps_lna_enable) { ++ ++ WMT_INFO_FUNC("host pin used for gps lna\n"); ++ /* host LNA ctrl pin needed */ ++ ctrlData.ctrlId = WMT_CTRL_GPS_LNA_SET; ++ ctrlData.au4CtrlData[0] = FUNC_ON == funcStatus ? 1 : 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /*we suppose this would never print */ ++ WMT_ERR_FUNC("ctrl host GPS_LNA output high fail, ret(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -3; ++ } ++ WMT_INFO_FUNC("ctrl host gps lna function succeed\n"); ++ } else { ++ WMT_INFO_FUNC("combo chip pin(%s) used for gps lna\n", ++ 0 == pConf->wmt_gps_lna_pin ? "EEDI" : "EEDO"); ++ wmtIcPinId = 0 == pConf->wmt_gps_lna_pin ? WMT_IC_PIN_EEDI : WMT_IC_PIN_EEDO; ++ if ((NULL == pOps->ic_pin_ctrl) || ++ (0 > pOps->ic_pin_ctrl( ++ wmtIcPinId, ++ FUNC_ON == funcStatus ? WMT_IC_PIN_GPIO_HIGH : WMT_IC_PIN_GPIO_LOW, ++ 1))) { /*WMT_IC_PIN_GSYNC */ ++ if (0 == pConf->wmt_gps_lna_pin) { ++ /* EEDI needed */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDI_ID]; ++ } else if (1 == pConf->wmt_gps_lna_pin) { ++ /* EEDO needed */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDO_ID]; ++ } ++ regNum = pCmbPinCtrl->regNum; ++ for (i = 0; i < regNum; i++) { ++ if (FUNC_ON == funcStatus) ++ pReg = &pCmbPinCtrl->pFuncOnArray[i]; ++ else ++ pReg = &pCmbPinCtrl->pFuncOffArray[i]; ++ regAddr = pReg->regAddr; ++ regValue = pReg->regValue; ++ regMask = pReg->regMask; ++ ++ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); ++ if (iRet) { ++ WMT_ERR_FUNC("set reg for GPS_LNA function fail(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -3; ++ } ++ } ++ WMT_INFO_FUNC("ctrl combo chip gps lna succeed\n"); ++ } else { ++ WMT_INFO_FUNC("set reg for GPS_LNA function okay by chip ic_pin_ctrl\n"); ++ } ++ } ++ } ++ return 0; ++ ++} ++ ++INT32 wmt_func_gps_pre_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_ON); ++} ++ ++INT32 wmt_func_gps_pre_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ ++ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_OFF); ++} ++ ++INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ ++ if (!osal_test_bit(WMT_FM_ON, &gGpsFmState)) { ++ ctrlPa1 = GPS_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_INFO_FUNC("LDO VCN28 has been turn on by FM\n"); ++ } ++ } ++ ++ iRet = wmt_func_gps_pre_on(pOps, pConf); ++ if (0 == iRet) { ++ iRet = wmt_func_gps_ctrl(FUNC_ON); ++ if (!iRet) { ++ osal_set_bit(WMT_GPS_ON, &gBtWifiGpsState); ++ if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) ++ || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) /* use SOC external LNA */ ++ osal_set_bit(WMT_GPS_ON, &gGpsFmState); ++ } ++ } ++ return iRet; ++} ++ ++INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ iRet = wmt_func_gps_pre_off(pOps, pConf); ++ if (0 == iRet) { ++ iRet = wmt_func_gps_ctrl(FUNC_OFF); ++ if (!iRet) { ++ osal_clear_bit(WMT_GPS_ON, &gBtWifiGpsState); ++ if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) ++ || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stop sending de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ } ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ ++ if (osal_test_bit(WMT_FM_ON, &gGpsFmState)) ++ WMT_INFO_FUNC("FM is still on, do not turn off LDO VCN28\n"); ++ else { ++ ctrlPa1 = GPS_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ osal_clear_bit(WMT_GPS_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++ ++} ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_fm_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*only need to send turn FM subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_fm_ctrl(FUNC_ON); */ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ INT32 iRet = -1; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ if (co_clock_type) { ++ if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { ++ ctrlPa1 = FM_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_INFO_FUNC("LDO VCN28 has been turn on by GPS\n"); ++ } ++ } ++ ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE); ++ if (!iRet) { ++ if (co_clock_type) ++ osal_set_bit(WMT_FM_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_fm_ctrl(FUNC_OFF); */ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ INT32 iRet = -1; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE); ++ ++ if (co_clock_type) { ++ if (osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { ++ WMT_INFO_FUNC("GPS is still on, do not turn off LDO VCN28\n"); ++ } else { ++ ctrlPa1 = FM_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ osal_clear_bit(WMT_FM_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++} ++ ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++ ++/*in soc, wmt turn on wifi directly, no not need operate SDIO*/ ++#if 0 ++INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = WMT_SDIO_FUNC_WIFI; ++ unsigned long ctrlPa2 = (FUNC_ON == funcState) ? 1 : 0; /* turn on Wi-Fi driver */ ++ ++ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: turn on WIFI function fail (%d)", iRet); ++ return -1; ++ } ++ return 0; ++} ++#endif ++ ++INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ int iRet = 0; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ if (NULL != mtk_wcn_wlan_probe) { ++ ++ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan probe\n"); ++ iRet = (*mtk_wcn_wlan_probe) (); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan probe fail(%d)\n", iRet); ++ iRet = -1; ++ } else { ++ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan probe ok\n"); ++ } ++ } else { ++ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_probe\n"); ++ gWifiProbed = 1; ++ iRet = -2; ++ } ++ ++ if (!iRet) { ++ osal_set_bit(WMT_WIFI_ON, &gBtWifiGpsState); ++ if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ return iRet; ++#if 0 ++ return wmt_func_wifi_ctrl(FUNC_ON); ++#endif ++} ++ ++INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ int iRet = 0; ++ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ if (NULL != mtk_wcn_wlan_remove) { ++ ++ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan remove\n"); ++ iRet = (*mtk_wcn_wlan_remove) (); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan remove fail(%d)\n", iRet); ++ iRet = -1; ++ } else { ++ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan remove ok\n"); ++ } ++ } else { ++ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_remove\n"); ++ iRet = -2; ++ } ++ ++ if (!iRet) { ++ osal_clear_bit(WMT_WIFI_ON, &gBtWifiGpsState); ++ if ((!osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stopping send de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ return iRet; ++#if 0 ++ return wmt_func_wifi_ctrl(FUNC_OFF); ++#endif ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c +new file mode 100644 +index 000000000000..c07052bce8e6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c +@@ -0,0 +1,2452 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-IC]" ++#define CFG_IC_SOC 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "wmt_ic.h" ++#include "wmt_core.h" ++#include "wmt_lib.h" ++#include "stp_core.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define DEFAULT_PATCH_FRAG_SIZE (1000) ++#define WMT_PATCH_FRAG_1ST (0x1) ++#define WMT_PATCH_FRAG_MID (0x2) ++#define WMT_PATCH_FRAG_LAST (0x3) ++ ++#define CFG_CHECK_WMT_RESULT (1) ++/* BT Port 2 Feature. this command does not need ++ * after coex command is downconfirmed by LC, ++ */ ++#define CFG_WMT_BT_PORT2 (0) ++ ++#define CFG_SET_OPT_REG (0) ++#define CFG_WMT_I2S_DBGUART_SUPPORT (0) ++#define CFG_SET_OPT_REG_SWLA (0) ++#define CFG_SET_OPT_REG_MCUCLK (0) ++#define CFG_SET_OPT_REG_MCUIRQ (0) ++ ++#define CFG_SUBSYS_COEX_NEED 0 ++ ++#define CFG_WMT_COREDUMP_ENABLE 0 ++ ++#define CFG_WMT_MULTI_PATCH (1) ++ ++#define CFG_WMT_CRYSTAL_TIMING_SET (0) ++ ++#define CFG_WMT_SDIO_DRIVING_SET (0) ++ ++#define CFG_WMT_UART_HIF_USE (0) ++ ++#define CFG_WMT_WIFI_5G_SUPPORT (1) ++ ++#define CFG_WMT_PATCH_DL_OPTM (1) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define CFG_WMT_FILTER_MODE_SETTING (1) ++#else ++#define CFG_WMT_FILTER_MODE_SETTING (0) ++#endif ++#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT (0) ++ ++#define CFG_WMT_POWER_ON_DLM (1) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static UINT8 gFullPatchName[NAME_MAX + 1]; ++static const WMT_IC_INFO_S *gp_soc_info; ++static WMT_PATCH gp_soc_patch_info; ++static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; ++#if 0 ++static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; ++ ++static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; ++static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; ++#endif ++ ++#if CFG_WMT_UART_HIF_USE ++static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; ++static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; ++static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; ++static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; ++static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; ++static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; ++static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++#endif ++static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_QUERY_STP_EVT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; ++static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; ++static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; ++ ++#if CFG_WMT_BT_PORT2 ++static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; ++static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++#endif ++ ++/*soc patial patch address cmd & evt need firmware owner provide*/ ++#if CFG_WMT_MULTI_PATCH ++static UINT8 WMT_PATCH_ADDRESS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x3c, 0x02, 0x09, 0x02, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0xc4, 0x04, 0x09, 0x02, ++ 0x00, 0x3f, 0x00, 0x01, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++#endif ++ ++/*coex cmd/evt++*/ ++static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; ++static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++#if CFG_SUBSYS_COEX_NEED ++static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, ++ 0x00, 0x02, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA ++}; ++static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, ++ 0x00, 0x03, ++ 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA ++}; ++static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, ++ 0x00, 0x04, ++ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE ++}; ++static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, ++ 0x00, 0x05, ++ 0xAA, 0xAA, 0xAA, 0xAA, ++ 0xBB, 0xBB, 0xBB, 0xBB ++}; ++static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++#endif ++ ++/*coex cmd/evt--*/ ++static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; ++static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; ++static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; ++static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; ++ ++#if 0 ++static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; ++static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; ++#endif ++ ++#if 0 ++/* to enable dump feature */ ++static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 }; ++static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get system stack dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get task and system stack dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get bt related memory dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A }; ++static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++#endif ++/* to get full dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; ++static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_CORE_START_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x1, 0x00, 0x01 }; ++static UINT8 WMT_CORE_START_RF_CALIBRATION_EVT[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x01 }; ++ ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */ ++ , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */ ++ , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */ ++ , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */ ++ , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */ ++ , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */ ++ , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++#endif ++ ++#if !(CFG_IC_SOC) /* For MT6628 no need to set ALLEINT registers, done in f/w */ ++/* enable all interrupt */ ++static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ ++ , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ ++ , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ ++}; ++ ++static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++#endif ++ ++#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ ++static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ ++ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ ++ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ ++ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ ++ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ ++ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ ++}; ++ ++static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++}; ++#endif ++ ++#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ ++static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ ++ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ ++ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ ++ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ ++ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ ++ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ ++ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ ++}; ++ ++static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++}; ++#endif ++ ++#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ ++static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ ++ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ ++ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ ++ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ ++ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ ++ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ ++}; ++ ++static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++}; ++#endif ++ ++#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ ++#if 1 /* Ray */ ++static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ ++ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ ++ /* cirq_int_n */ ++ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ ++ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ ++ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ ++ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ ++ /* 1. ARM irq_b, monitor flag 0 */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ ++ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ ++ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ ++}; ++ ++static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 5 registers */ ++}; ++#elif 0 /* KC */ ++static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x05 /* 5 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ ++ , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ ++ , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ ++ /* 1. ARM irq_b, monitor flag 0 */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ ++ , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ ++ , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ ++ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ ++ /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ ++ , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ ++ , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ ++ , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ ++ , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ ++ , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ ++ , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ ++}; ++ ++static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x05 /* 5 registers */ ++}; ++#endif ++#endif ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; ++static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; ++ ++static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; ++#endif ++ ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++static UINT8 WMT_GET_EFUSE_VCN33_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x04, 0x00 }; ++static UINT8 WMT_GET_EFUSE_VCN33_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x04, 0x00 }; ++#endif ++ ++/* set sdio driving */ ++#if CFG_WMT_SDIO_DRIVING_SET ++static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ ++ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ ++ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ ++}; ++ ++static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++#endif ++ ++#if CFG_WMT_WIFI_5G_SUPPORT ++static UINT8 WMT_GET_SOC_ADIE_CHIPID_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; ++static UINT8 WMT_GET_SOC_ADIE_CHIPID_EVT[] = { ++ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static UINT8 WMT_GET_SOC_6625_L_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x20, 0x01 }; ++static UINT8 WMT_GET_SOC_6625_L_EVT[] = { ++ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x20, ++ 0x01, 0x00, 0x00, 0x00, 0x00 ++}; ++#endif ++ ++#if CFG_WMT_PATCH_DL_OPTM ++static UINT8 WMT_SET_MCU_CLK_EN_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x34, 0x03, 0x00, 0x80, ++ 0x00, 0x00, 0x01, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_EN_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_138_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, ++ 0x59, 0x4d, 0x84, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_138_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_26_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, ++ 0x00, 0x4d, 0x84, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_26_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_DIS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x34, 0x03, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_DIS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++/*only for 6797,enable high clock frequency*/ ++/*CLK EN*/ ++static UINT8 WMT_SET_MCU_CLK_EN_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x10, ++ 0x00, 0x00, 0x00, 0x10 ++}; ++/*RATIO SET*/ ++static UINT8 WMT_SET_MCU_RATIO_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, ++ 0xc0, 0x00, 0x00, 0x00 ++}; ++/*DIV SET*/ ++static UINT8 WMT_SET_MCU_DIV_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x18, 0x11, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00, ++ 0x3f, 0x00, 0x00, 0x00 ++}; ++/*HCLK SET*/ ++static UINT8 WMT_SET_MCU_HCLK_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x11, 0x02, 0x81, 0x04, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x00 ++}; ++ ++/*Change clock to 26MHz*/ ++/*HCLK DIS*/ ++static UINT8 WMT_SET_MCU_HCLK_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x00 ++}; ++/*RATIO DIS*/ ++static UINT8 WMT_SET_MCU_RATIO_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, ++ 0xc0, 0x00, 0x00, 0x00 ++}; ++/*CLK DIS*/ ++static UINT8 WMT_SET_MCU_CLK_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10 ++}; ++ ++static UINT8 WMT_SET_MCU_CLK_EVT_6797[] = { ++ 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 ++}; ++ ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = {0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00}; ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, ++ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x00, 0x0a, 0x0c, 0x0e, ++ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xd4, ++ 0x09, 0xe3, 0x09, 0x5a, 0x0a, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x60, 0x09, 0xd3, 0x09, 0xe2, ++ 0x09, 0x59, 0x0a, 0x8B, 0x0a}; ++static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; ++static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; ++ ++#if 0 ++static UINT8 WMT_COEX_SPLIT_FILTER_CMD_TEST[] = { ++ 0x01, 0x10, 0x19, 0x00, 0x0F, 0x00, 0x00, 0x00, ++ 0x00, 0x6c, 0x09, 0x8a, 0x09, 0x8a, 0x09, 0x9e, ++ 0x09, 0x01, 0x07, 0x07, 0x0b, 0x07, 0x07, 0x00, ++ 0x32, 0x27, 0x4e, 0x27, 0x32 ++}; ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x07, 0x07, 0x07, 0x54, 0x54, 0x00, 0x00, ++ 0x00, 0x50, 0x50, 0x50, 0x54, 0x54, 0x39, 0x39, ++ 0x39, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, ++ 0x09, 0xf6, 0x09, 0x0f, 0xaf, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, ++ 0x09, 0x0d, 0x0a, 0x27, 0x0a ++}; ++static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; ++static UINT8 WMT_COEX_EXT_COMPONENT_CMD_TEST[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x7f, 0x03 }; ++#endif ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_0[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x63, 0x3c, 0x3c, 0x3c, ++ 0x3c, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, ++ 0x09, 0xf6, 0x09, 0x0f, 0x0a, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, ++ 0x09, 0x0d, 0x0a, 0x27, 0x0a ++}; ++static UINT8 WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x14, 0x00 }; ++static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; ++static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_6752[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, ++ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, ++ 0x01, 0x0E, 0x0E, 0x0E, 0x00, 0x0A, 0x0C, 0x0E, ++ 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xFC, 0x08, 0x15, ++ 0x09, 0x2E, 0x09, 0x47, 0x09, 0xC4, 0x09, 0xD4, ++ 0x09, 0xE3, 0x09, 0x5A, 0x0A, 0x14, 0x09, 0x2D, ++ 0x09, 0x46, 0x09, 0x60, 0x09, 0xD3, 0x09, 0xE2, ++ 0x09, 0x59, 0x0A, 0x8B, 0x0A ++}; ++#endif ++ ++#if CFG_WMT_POWER_ON_DLM ++static UINT8 WMT_POWER_CTRL_DLM_CMD1[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x0f, 0x00, 0x00 ++}; ++ ++static UINT8 WMT_POWER_CTRL_DLM_CMD2[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0x00, 0x00, 0x00 ++}; ++ ++static UINT8 WMT_POWER_CTRL_DLM_CMD3[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0x00 ++}; ++static UINT8 WMT_POWER_CTRL_DLM_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++#endif ++ ++#if (!CFG_IC_SOC) ++ ++/* stp sdio init scripts */ ++static struct init_script init_table_1_1[] = { ++ /* table_1_1 is only applied to common SDIO interface */ ++ INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), ++ /* applied to MT6628 ? */ ++ INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), ++}; ++ ++#endif ++ ++static struct init_script init_table_1_2[] = { ++ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), ++}; ++ ++#if CFG_WMT_UART_HIF_USE ++static struct init_script init_table_2[] = { ++ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), ++}; ++#endif ++ ++static struct init_script init_table_3[] = { ++ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), ++#if CFG_WMT_BT_PORT2 ++ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), ++#endif ++}; ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static struct init_script set_crystal_timing_script[] = { ++ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, "set crystal trim value"), ++}; ++ ++static struct init_script get_crystal_timing_script[] = { ++ INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, "get crystal trim value"), ++}; ++#endif ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++static struct init_script get_efuse_vcn33_script[] = { ++ INIT_CMD(WMT_GET_EFUSE_VCN33_CMD, WMT_GET_EFUSE_VCN33_EVT, "get efuse vcn33 value"), ++}; ++#endif ++ ++static struct init_script init_table_4[] = { ++ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), ++}; ++ ++static struct init_script init_table_5[] = { ++ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT, "query stp"), ++}; ++ ++static struct init_script init_table_5_1[] = { ++ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), ++}; ++ ++static struct init_script init_table_6[] = { ++ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), ++}; ++ ++static struct init_script calibration_table[] = { ++ INIT_CMD(WMT_CORE_START_RF_CALIBRATION_CMD, WMT_CORE_START_RF_CALIBRATION_EVT, "start RF calibration data"), ++}; ++ ++#if CFG_WMT_PATCH_DL_OPTM ++static struct init_script set_mcuclk_table_1[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_EN_CMD, WMT_SET_MCU_CLK_EN_EVT, "enable set mcu clk"), ++ INIT_CMD(WMT_SET_MCU_CLK_138_CMD, WMT_SET_MCU_CLK_138_EVT, "set mcu clk to 138.67MH"), ++}; ++ ++static struct init_script set_mcuclk_table_2[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_26_CMD, WMT_SET_MCU_CLK_26_EVT, "set mcu clk to 26MH"), ++ INIT_CMD(WMT_SET_MCU_CLK_DIS_CMD, WMT_SET_MCU_CLK_DIS_EVT, "disable set mcu clk"), ++}; ++ ++static struct init_script set_mcuclk_table_3[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_EN_6797, WMT_SET_MCU_CLK_EVT_6797, "enable set mcu clk"), ++ INIT_CMD(WMT_SET_MCU_RATIO_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu ratio set"), ++ INIT_CMD(WMT_SET_MCU_DIV_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu div set"), ++ INIT_CMD(WMT_SET_MCU_HCLK_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "set mcu clk to hclk"), ++}; ++static struct init_script set_mcuclk_table_4[] = { ++ INIT_CMD(WMT_SET_MCU_HCLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu hclk"), ++ INIT_CMD(WMT_SET_MCU_RATIO_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu ratio set"), ++ INIT_CMD(WMT_SET_MCU_CLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu clk set"), ++}; ++ ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static struct init_script set_wifi_lte_coex_table_1[] = { ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), ++ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"), ++}; ++ ++static struct init_script set_wifi_lte_coex_table_2[] = { ++ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), ++ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), ++ INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), ++}; ++ ++static struct init_script set_wifi_lte_coex_table_0[] = { ++#if 0 ++ INIT_CMD(WMT_COEX_SPLIT_FILTER_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex split filter"), ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), ++ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte channel unsafe"), ++ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi coex ext component"), ++#endif ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte freq idx"), ++}; ++ ++static struct init_script get_tdm_req_antsel_num_table[] = { ++ INIT_CMD(WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD, WMT_COEX_SPLIT_MODE_EVT, "get tdm req antsel num"), ++}; ++#endif ++ ++#if CFG_SET_OPT_REG ++static struct init_script set_registers[] = { ++ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ ++ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ ++#if CFG_WMT_I2S_DBGUART_SUPPORT ++ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), ++#endif ++#if CFG_SET_OPT_REG_SWLA ++ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), ++#endif ++#if CFG_SET_OPT_REG_MCUCLK ++ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), ++#endif ++#if CFG_SET_OPT_REG_MCUIRQ ++ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), ++#endif ++}; ++#endif ++ ++static struct init_script coex_table[] = { ++ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), ++ ++#if CFG_SUBSYS_COEX_NEED ++/* no need in MT6628 */ ++ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), ++ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), ++ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), ++ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), ++#endif ++}; ++ ++static struct init_script osc_type_table[] = { ++ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), ++}; ++ ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++static struct init_script merge_pcm_table[] = { ++ INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"), ++ INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"), ++ INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"), ++}; ++#endif ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static struct init_script sdio_driving_table[] = { ++ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), ++}; ++#endif ++ ++#if CFG_WMT_POWER_ON_DLM ++static struct init_script wmt_power_on_dlm_table[] = { ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD1, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd1"), ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD2, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd2"), ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD3, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd3") ++}; ++#endif ++ ++/* SOC Chip Version and Info Table */ ++static const WMT_IC_INFO_S mtk_wcn_soc_info_table[] = { ++ { ++ .u4HwVer = 0x8A00, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E1, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ /* need to refine? */ ++ .eWmtHwVer = WMTHWVER_E1, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ }, ++ { ++ .u4HwVer = 0x8A01, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E2, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ .eWmtHwVer = WMTHWVER_E2, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ }, ++ { ++ .u4HwVer = 0x8B01, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E3, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ .eWmtHwVer = WMTHWVER_E3, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ } ++}; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf); ++ ++static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); ++ ++static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); ++ ++static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); ++ ++static INT32 mtk_wcn_soc_ver_check(VOID); ++ ++static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver); ++ ++static INT32 wmt_stp_init_coex(VOID); ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static INT32 wmt_stp_wifi_lte_coex(VOID); ++#endif ++ ++#if CFG_WMT_MULTI_PATCH ++static INT32 mtk_wcn_soc_patch_dwn(UINT32 index); ++static INT32 mtk_wcn_soc_patch_info_prepare(VOID); ++#else ++static INT32 mtk_wcn_soc_patch_dwn(VOID); ++#endif ++ ++static INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on); ++static WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID); ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static INT32 mtk_wcn_soc_crystal_triming_set(VOID); ++#endif ++ ++static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID); ++ ++static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID); ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static INT32 mtk_wcn_soc_set_sdio_driving(void); ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* SOC Operation Function Table */ ++WMT_IC_OPS wmt_ic_ops_soc = { ++ .icId = 0x0000, /* soc may have mt6572/82/71/83,but they have the same sw init flow */ ++ .sw_init = mtk_wcn_soc_sw_init, ++ .sw_deinit = mtk_wcn_soc_sw_deinit, ++ .ic_pin_ctrl = mtk_wcn_soc_pin_ctrl, ++ .ic_ver_check = mtk_wcn_soc_ver_check, ++ .co_clock_ctrl = mtk_wcn_soc_co_clock_ctrl, ++ .is_quick_sleep = mtk_wcn_soc_quick_sleep_flag_get, ++ .is_aee_dump_support = mtk_wcn_soc_aee_dump_flag_get, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf) ++{ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT32 hw_ver; ++ WMT_CTRL_DATA ctrlData; ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++ UINT32 efuse_d3_vcn33 = 2; /*default voltage is 3.5V*/ ++#endif ++#if CFG_WMT_MULTI_PATCH ++ UINT32 patch_num = 0; ++ UINT32 patch_index = 0; ++#endif ++#if CFG_WMT_WIFI_5G_SUPPORT ++ UINT32 dDieChipid = 0; ++ UINT32 aDieChipid = 0; ++ UINT8 evtbuf[20]; ++ UINT32 u4Res; ++ UINT32 pmicChipid = 0; ++#endif ++ WMT_DBG_FUNC(" start\n"); ++ ++ osal_assert(NULL != gp_soc_info); ++ if ((NULL == gp_soc_info) ++ || (NULL == pWmtHifConf) ++ ) { ++ WMT_ERR_FUNC("null pointers: gp_soc_info(0x%p), pWmtHifConf(0x%p)\n", gp_soc_info, pWmtHifConf); ++ return -1; ++ } ++ ++ hw_ver = gp_soc_info->u4HwVer; ++ ++ /* 4 <3.2> start init for BTIF */ ++ if (WMT_HIF_BTIF == pWmtHifConf->hifType) { ++ /* 1. Query chip STP default options (TEST-ONLY) */ ++ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ ++ iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); ++ osal_assert(0); ++ return -2; ++ } ++ /* 2. Set chip STP options */ ++ iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); ++ return -3; ++ } ++ ++ /* 3. Enable host full mode */ ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_FULL_MODE; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("enable host STP-BTIF-FULL mode fail(%d)\n", iRet); ++ return -4; ++ } ++ WMT_DBG_FUNC("enable host STP-BTIF-FULL mode\n"); ++ /*4. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ ++ osal_sleep_ms(10); ++ /* 5. Query chip STP options (TEST-ONLY) */ ++ iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); ++ return -5; ++ } ++ } ++#if CFG_WMT_POWER_ON_DLM ++ iRet = wmt_core_init_script(wmt_power_on_dlm_table, osal_array_size(wmt_power_on_dlm_table)); ++ if (iRet) ++ WMT_ERR_FUNC("wmt_power_on_dlm_table fail(%d)\n", iRet); ++ WMT_DBG_FUNC("wmt_power_on_dlm_table ok\n"); ++#endif ++ /* 6. download patch */ ++#if CFG_WMT_MULTI_PATCH ++ /* 6.1 Let launcher to search patch info */ ++ iRet = mtk_wcn_soc_patch_info_prepare(); ++ if (iRet) { ++ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); ++ return -6; ++ } ++ ++ /* 6.2 Read patch number */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); ++ patch_num = ctrlPa1; ++ WMT_DBG_FUNC("patch total num = [%d]\n", patch_num); ++ ++#if CFG_WMT_PATCH_DL_OPTM ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ iRet = wmt_core_init_script(set_mcuclk_table_3, osal_array_size(set_mcuclk_table_3)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_3 fail(%d)\n", iRet); ++ } else { ++ iRet = wmt_core_init_script(set_mcuclk_table_1, osal_array_size(set_mcuclk_table_1)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_1 fail(%d)\n", iRet); ++ } ++#endif ++ /* 6.3 Multi-patch Patch download */ ++ for (patch_index = 0; patch_index < patch_num; patch_index++) { ++ iRet = mtk_wcn_soc_patch_dwn(patch_index); ++ if (iRet) { ++ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); ++ return -7; ++ } ++ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); ++ return -8; ++ } ++ } ++ ++#if CFG_WMT_PATCH_DL_OPTM ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ iRet = wmt_core_init_script(set_mcuclk_table_4, osal_array_size(set_mcuclk_table_4)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_4 fail(%d)\n", iRet); ++ } else { ++ iRet = wmt_core_init_script(set_mcuclk_table_2, osal_array_size(set_mcuclk_table_2)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_2 fail(%d)\n", iRet); ++ } ++#endif ++ ++#else ++ /* 6.3 Patch download */ ++ iRet = mtk_wcn_soc_patch_dwn(); ++ /* If patch download fail, we just ignore this error and let chip init process goes on */ ++ if (iRet) ++ WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); ++ ++ /* 6.4. WMT Reset command */ ++ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); ++ return -8; ++ } ++#endif ++ ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++ /*get CrystalTiming value before set it */ ++ iRet = wmt_core_tx(get_efuse_vcn33_script[0].cmd, get_efuse_vcn33_script[0].cmdSz, &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != get_efuse_vcn33_script[0].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", ++ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].cmdSz); ++ } ++ /* EVENT BUF */ ++ osal_memset(get_efuse_vcn33_script[0].evt, 0, get_efuse_vcn33_script[0].evtSz); ++ iRet = wmt_core_rx(get_efuse_vcn33_script[0].evt, get_efuse_vcn33_script[0].evtSz, &u4Res); ++ if (iRet || (u4Res != get_efuse_vcn33_script[0].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", ++ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ } ++ efuse_d3_vcn33 = WMT_GET_EFUSE_VCN33_EVT[5] & 0x03; ++ WMT_INFO_FUNC("Read efuse to set PMIC voltage:(%d)\n", efuse_d3_vcn33); ++ wmt_set_pmic_voltage(efuse_d3_vcn33); ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++ if ((0x6580 == wmt_ic_ops_soc.icId) || ++ (0x8163 == wmt_ic_ops_soc.icId) || ++ (0x6752 == wmt_ic_ops_soc.icId) || ++ (0x6582 == wmt_ic_ops_soc.icId) || ++ (0x6592 == wmt_ic_ops_soc.icId) || ++ (0x0279 == wmt_ic_ops_soc.icId) || ++ (0x0326 == wmt_ic_ops_soc.icId) || ++ (0x0321 == wmt_ic_ops_soc.icId) || (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { ++ wmt_stp_wifi_lte_coex(); ++ WMT_DBG_FUNC("wmt_stp_wifi_lte_coex done!\n"); ++ } ++ if ((0x6582 == wmt_ic_ops_soc.icId) || (0x6592 == wmt_ic_ops_soc.icId)) { ++ /*get gpio tdm req antsel number */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_GET_TDM_REQ_ANTSEL, &ctrlPa1, &ctrlPa2); ++ WMT_INFO_FUNC("get GPIO TDM REQ ANTSEL number(%d)\n", ctrlPa1); ++ /*set gpio tdm req antsel number to firmware */ ++ WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[5] = ctrlPa1; ++ iRet = wmt_core_init_script(get_tdm_req_antsel_num_table, ++ osal_array_size(get_tdm_req_antsel_num_table)); ++ if (iRet) ++ WMT_ERR_FUNC("get_tdm_req_antsel_num_table fail(%d)\n", iRet); ++ } ++#endif ++ /* 7. start RF calibration data */ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WIFI_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ iRet = wmt_core_init_script(calibration_table, osal_array_size(calibration_table)); ++ if (iRet) { ++ /* pwrap_read(0x0210,&ctrlPa1); */ ++ /* pwrap_read(0x0212,&ctrlPa2); */ ++ WMT_ERR_FUNC("power status: 210:(%d),212:(%d)!\n", ctrlPa1, ctrlPa2); ++ WMT_ERR_FUNC("calibration_table fail(%d)\n", iRet); ++ return -9; ++ } ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WIFI_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ iRet = wmt_stp_init_coex(); ++ if (iRet) { ++ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); ++ return -10; ++ } ++ WMT_DBG_FUNC("init_coex ok\n"); ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++ mtk_wcn_soc_crystal_triming_set(); ++#endif ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++ mtk_wcn_soc_set_sdio_driving(); ++#endif ++ ++ if (WMT_CO_CLOCK_EN == mtk_wcn_soc_co_clock_get()) { ++ WMT_INFO_FUNC("co-clock enabled.\n"); ++ ++ iRet = wmt_core_init_script(osc_type_table, osal_array_size(osc_type_table)); ++ if (iRet) { ++ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); ++ return -11; ++ } ++ } else { ++ WMT_WARN_FUNC("co-clock disabled.\n"); ++ } ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++ iRet = wmt_core_init_script(merge_pcm_table, osal_array_size(merge_pcm_table)); ++ if (iRet) { ++ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); ++ return -12; ++ } ++#endif ++ ++ /* 15. Set FM strap */ ++ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; ++ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; ++ iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", pWmtHifConf->au4StrapConf[0], iRet); ++ return -13; ++ } ++ WMT_DBG_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); ++ ++#if CFG_SET_OPT_REG /*set registers */ ++ iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); ++ if (iRet) { ++ WMT_ERR_FUNC("set_registers fail(%d)", iRet); ++ return -14; ++ } ++#endif ++ ++#if CFG_WMT_COREDUMP_ENABLE ++ /*Open Core Dump Function @QC begin */ ++ mtk_wcn_stp_coredump_flag_ctrl(1); ++#endif ++ if (0 != mtk_wcn_stp_coredump_flag_get()) { ++ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); ++ return -15; ++ } ++ WMT_DBG_FUNC("enable soc_consys firmware coredump\n"); ++ } else { ++ WMT_DBG_FUNC("disable soc_consys firmware coredump\n"); ++ } ++ ++#if CFG_WMT_WIFI_5G_SUPPORT ++ dDieChipid = wmt_ic_ops_soc.icId; ++ WMT_DBG_FUNC("current SOC chipid is 0x%x\n", dDieChipid); ++ if (0x6592 == dDieChipid) { ++ /* read A die chipid by wmt cmd */ ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_GET_SOC_ADIE_CHIPID_CMD[0], sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); ++ return -16; ++ } ++ osal_memset(evtbuf, 0, sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); ++ return -17; ++ } ++ ++ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); ++ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); ++ ++ if (0x6625 == aDieChipid) { ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_GET_SOC_6625_L_CMD[0], sizeof(WMT_GET_SOC_6625_L_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_CMD))) ++ WMT_ERR_FUNC("wmt_core:read A die efuse CMD fail(%d),size(%d)\n", iRet, u4Res); ++ osal_memset(evtbuf, 0, sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_6625_L_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_EVT))) ++ WMT_ERR_FUNC("wmt_core:read A die efuse EVT fail(%d),size(%d)\n", iRet, u4Res); ++ ++ WMT_INFO_FUNC("read SOC Adie Efuse(0x120) value:0x%2x,0x%2x,0x%2x,0x%2x -> %s\n", ++ evtbuf[u4Res - 4], evtbuf[u4Res - 3], evtbuf[u4Res - 2], evtbuf[u4Res - 1], ++ evtbuf[u4Res - 2] == 0x31 ? "MT6625L" : "MT6625"); ++ } ++ /* get PMIC chipid */ ++ ++ ctrlData.ctrlId = WMT_CTRL_SOC_PALDO_CTRL; ++ ctrlData.au4CtrlData[0] = PMIC_CHIPID_PALDO; ++ ctrlData.au4CtrlData[1] = 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet < 0) { ++ WMT_ERR_FUNC("wmt_core: read PMIC chipid fail(%d)\n", iRet); ++ return -18; ++ } ++ pmicChipid = ctrlData.au4CtrlData[2]; ++ WMT_INFO_FUNC("current PMIC chipid(0x%x)\n", pmicChipid); ++ ++ /* MT6625 & MT6322, write 1 to 0x0414[12] */ ++ /* MT6625 & MT6323, assert */ ++ /* MT6627 & (MT6322 or MT6323),write 0 to 0x0414[12] */ ++ ++ switch (aDieChipid) { ++ case 0x6625: ++ if (0x6322 == pmicChipid) { ++ WMT_INFO_FUNC("wmt-core:enable wifi 5G support\n"); ++ ctrlPa1 = WIFI_5G_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else if (0x6323 == pmicChipid) { ++ osal_assert(0); ++ } else { ++ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); ++ } ++ break; ++ case 0x6627: ++ if ((0x6322 == pmicChipid) || (0x6323 == pmicChipid)) { ++ WMT_INFO_FUNC("wmt-core: disable wifi 5G support\n"); ++ ctrlPa1 = WIFI_5G_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); ++ } ++ break; ++ default: ++ WMT_WARN_FUNC("wmt-core: unknown A die chipid(0x%x)\n", aDieChipid); ++ break; ++ } ++ } ++#endif ++ ++#if 1 ++ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; ++ ctrlData.au4CtrlData[0] = wmt_ic_ops_soc.icId; ++ ctrlData.au4CtrlData[1] = (SIZE_T) gp_soc_info->cChipVersion; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &gp_soc_patch_info; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); ++ return -19; ++ } ++#endif ++ ++#if CFG_WMT_PS_SUPPORT ++ osal_assert(NULL != gp_soc_info); ++ if (NULL != gp_soc_info) { ++ if (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport) ++ wmt_lib_ps_enable(); ++ else ++ wmt_lib_ps_disable(); ++ } ++#endif ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) ++{ ++ WMT_DBG_FUNC(" start\n"); ++ ++#if CFG_WMT_PS_SUPPORT ++ osal_assert(NULL != gp_soc_info); ++ if ((NULL != gp_soc_info) ++ && (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport)) { ++ wmt_lib_ps_disable(); ++ } ++#endif ++ ++ gp_soc_info = NULL; ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 ret = -1; ++ UINT32 val; ++ ++ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { ++ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); ++#if 0 ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ val = 0x00000770; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ val = 0x00000700; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x00000710; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#else ++ WMT_WARN_FUNC("TBD!!"); ++ ret = 0; ++#endif ++ } else { ++ /*PCM & I2S separate */ ++ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); ++#if 0 ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ val = 0x00000770; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ val = 0x00000700; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x00000070; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ ++ break; ++ case WMT_IC_AIF_3: ++ val = 0x00000000; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ ++ break; ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#else ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ ret = 0; ++ break; ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ ret = 0; ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x01110000; ++ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); ++ ++ break; ++ case WMT_IC_AIF_3: ++ ret = 0; ++ break; ++ ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#endif ++ } ++ ++ if (!ret) ++ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); ++ WMT_INFO_FUNC("new state(%d) ok\n", state); ++ ++ return ret; ++} ++ ++static INT32 mtk_wcn_soc_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 iRet = -1; ++ UINT32 uVal = 0; ++ ++ /* mt6797 can not access reg:0x80050078 and no need to do GPS SYNC */ ++ if (0x0279 != wmt_ic_ops_soc.icId) { ++ if (WMT_IC_PIN_MUX == state) ++ uVal = 0x1 << 28; ++ else ++ uVal = 0x5 << 28; ++ iRet = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28); ++ if (iRet) ++ WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet); ++ } else ++ WMT_INFO_FUNC("This chip no need to sync GPS and MODEM!\n"); ++ ++ /* anyway, we return 0 */ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 ret; ++ ++ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); ++ ++ ret = -1; ++ switch (id) { ++ case WMT_IC_PIN_AUDIO: ++ ret = mtk_wcn_soc_aif_ctrl(state, flag); ++ break; ++ ++ case WMT_IC_PIN_EEDI: ++ WMT_WARN_FUNC("TBD!!"); ++ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ ++ ret = 0; ++ break; ++ ++ case WMT_IC_PIN_EEDO: ++ WMT_WARN_FUNC("TBD!!"); ++ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ ++ ret = 0; ++ break; ++ case WMT_IC_PIN_GSYNC: ++ ret = mtk_wcn_soc_gps_sync_ctrl(state, flag); ++ break; ++ default: ++ break; ++ } ++ WMT_INFO_FUNC("ret = (%d)\n", ret); ++ ++ return ret; ++} ++ ++INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on) ++{ ++ INT32 iRet = 0; ++ ++ if ((WMT_CO_CLOCK_DIS <= on) && (WMT_CO_CLOCK_MAX > on)) { ++ gCoClockEn = on; ++ } else { ++ WMT_DBG_FUNC("0x%x: error parameter:%d\n", wmt_ic_ops_soc.icId, on); ++ iRet = -1; ++ } ++ WMT_DBG_FUNC("0x%x: Co-clock %s\n", wmt_ic_ops_soc.icId, ++ (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled"); ++ ++ return iRet; ++} ++ ++static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID) ++{ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID) ++{ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID) ++{ ++ return gCoClockEn; ++} ++ ++static INT32 mtk_wcn_soc_ver_check(VOID) ++{ ++ UINT32 hw_ver; ++ UINT32 fw_ver; ++ INT32 iret; ++ const WMT_IC_INFO_S *p_info; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ ++ WMT_LOUD_FUNC("0x%x: before read hw_ver (hw version)\n", wmt_ic_ops_soc.icId); ++ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); ++ if (iret) { ++ WMT_ERR_FUNC("0x%x: read hw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); ++ return -2; ++ } ++ WMT_WARN_FUNC("0x%x: read hw_ver (hw version) (0x%x)\n", wmt_ic_ops_soc.icId, hw_ver); ++ ++ WMT_LOUD_FUNC("0x%x: before fw_ver (rom version)\n", wmt_ic_ops_soc.icId); ++ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); ++ if (iret) { ++ WMT_ERR_FUNC("0x%x: read fw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); ++ return -2; ++ } ++ WMT_WARN_FUNC("0x%x: read fw_ver (rom version) (0x%x)\n", wmt_ic_ops_soc.icId, fw_ver); ++ ++ p_info = mtk_wcn_soc_find_wmt_ic_info(hw_ver); ++ if (NULL == p_info) { ++ WMT_ERR_FUNC("0x%x: hw_ver(0x%x) find wmt ic info fail\n", wmt_ic_ops_soc.icId); ++ return -3; ++ } ++ WMT_WARN_FUNC("0x%x: ic info: %s.%s (0x%x/0x%x, WMTHWVER:%d, patch_ext:%s)\n", ++ wmt_ic_ops_soc.icId, p_info->cChipName, p_info->cChipVersion, ++ hw_ver, fw_ver, p_info->eWmtHwVer, p_info->cPatchNameExt); ++ ++ /* hw id & version */ ++ ctrlPa1 = (wmt_ic_ops_soc.icId << 16) | (hw_ver & 0x0000FFFF); ++ /* translated hw version & fw rom version */ ++ ctrlPa2 = ((UINT32) (p_info->eWmtHwVer) << 16) | (fw_ver & 0x0000FFFF); ++ ++ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); ++ if (iret) ++ WMT_WARN_FUNC("0x%x: WMT_CTRL_HWIDVER_SET fail(%d)\n", wmt_ic_ops_soc.icId, iret); ++ ++ gp_soc_info = p_info; ++ return 0; ++} ++ ++static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver) ++{ ++ /* match chipversion with u4HwVer item in mtk_wcn_soc_info_table */ ++ const UINT32 size = osal_array_size(mtk_wcn_soc_info_table); ++ INT32 index = 0; ++ ++ /* George: reverse the search order to favor newer version products ++ * TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() ++ * is changed correctly in the future!! ++ * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. ++ */ ++ index = size - 1; ++ /* full match */ ++ while ((0 <= index) && (hw_ver != mtk_wcn_soc_info_table[index].u4HwVer)) ++ --index; ++ if (0 <= index) { ++ WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); ++ return &mtk_wcn_soc_info_table[index]; ++ } ++ ++ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); ++ ++ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR ++ * NUM only can help us support future minor hw ECO, or fab switch, etc. ++ * FULL matching eliminate such flexibility and software package have to be ++ * updated EACH TIME even when minor hw ECO or fab switch!!! ++ */ ++ /* George: reverse the search order to favor newer version products */ ++ index = size - 1; ++ /* major num match */ ++ while ((0 <= index) && ++ (MAJORNUM(hw_ver) != MAJORNUM(mtk_wcn_soc_info_table[index].u4HwVer))) { ++ --index; ++ } ++ if (0 <= index) { ++ WMT_DBG_FUNC("0x%x: found ic info for hw_ver(0x%x) by major num! index:%d\n", ++ wmt_ic_ops_soc.icId, hw_ver, index); ++ return &mtk_wcn_soc_info_table[index]; ++ } ++ ++ WMT_ERR_FUNC("0x%x: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", ++ wmt_ic_ops_soc.icId, hw_ver); ++ WMT_ERR_FUNC("Set default chip version: E1!\n"); ++ return &mtk_wcn_soc_info_table[0]; ++} ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static INT32 wmt_stp_wifi_lte_coex(VOID) ++{ ++ INT32 iRet; ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ ++ /*Get wmt config */ ++ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (iRet) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); ++ return -2; ++ } ++ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ osal_sleep_ms(5); ++ ++ if (pWmtGenConf->coex_wmt_filter_mode == 0) { ++ if ((0x6752 == wmt_ic_ops_soc.icId) || ++ (0x6580 == wmt_ic_ops_soc.icId) || ++ (0x8163 == wmt_ic_ops_soc.icId) || ++ (0x0326 == wmt_ic_ops_soc.icId) || ++ (0x0321 == wmt_ic_ops_soc.icId) || ++ (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_1, osal_array_size(set_wifi_lte_coex_table_1)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_1 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } else if (0x0279 == wmt_ic_ops_soc.icId) { ++ /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/ ++ if (pWmtGenConf->coex_wmt_ext_component) { ++ WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); ++ set_wifi_lte_coex_table_2[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; ++ } ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_2, osal_array_size(set_wifi_lte_coex_table_2)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_2 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } else { ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_0, osal_array_size(set_wifi_lte_coex_table_0)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } ++ } ++ ++ return iRet; ++} ++#endif ++ ++static INT32 wmt_stp_init_coex(VOID) ++{ ++ INT32 iRet; ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ ++#define COEX_WMT 0 ++ ++#if CFG_SUBSYS_COEX_NEED ++ /* no need for MT6628 */ ++#define COEX_BT 1 ++#define COEX_WIFI 2 ++#define COEX_PTA 3 ++#define COEX_MISC 4 ++#endif ++ /*Get wmt config */ ++ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (iRet) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); ++ return -2; ++ } ++ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ /*Dump the coex-related info */ ++ WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode); ++#if CFG_SUBSYS_COEX_NEED ++ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_bt_rssi_upper_limit, ++ pWmtGenConf->coex_bt_rssi_mid_limit, ++ pWmtGenConf->coex_bt_rssi_lower_limit, ++ pWmtGenConf->coex_bt_pwr_high, pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); ++ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_wifi_rssi_upper_limit, ++ pWmtGenConf->coex_wifi_rssi_mid_limit, ++ pWmtGenConf->coex_wifi_rssi_lower_limit, ++ pWmtGenConf->coex_wifi_pwr_high, pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); ++ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_ext_pta_hi_tx_tag, ++ pWmtGenConf->coex_ext_pta_hi_rx_tag, ++ pWmtGenConf->coex_ext_pta_lo_tx_tag, ++ pWmtGenConf->coex_ext_pta_lo_rx_tag, ++ pWmtGenConf->coex_ext_pta_sample_t1, ++ pWmtGenConf->coex_ext_pta_sample_t2, pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); ++ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); ++#endif ++ ++ /*command adjustion due to WMT.cfg */ ++ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); ++ ++#if CFG_SUBSYS_COEX_NEED ++ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; ++ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; ++ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; ++ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; ++ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; ++ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); ++ ++ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; ++ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; ++ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; ++ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; ++ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; ++ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], ++ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); ++ ++ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; ++ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; ++ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; ++ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; ++ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); ++ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); ++ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); ++ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); ++ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); ++ ++ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, ++ sizeof(pWmtGenConf->coex_misc_ext_pta_on)); ++ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, ++ sizeof(pWmtGenConf->coex_misc_ext_feature_set)); ++ ++ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, coex_table[COEX_MISC].cmdSz); ++#endif ++ ++ iRet = wmt_core_init_script(coex_table, sizeof(coex_table) / sizeof(coex_table[0])); ++ ++ return iRet; ++} ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static INT32 mtk_wcn_soc_set_sdio_driving(void) ++{ ++ INT32 ret = 0; ++ ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ UINT32 drv_val = 0; ++ ++ /*Get wmt config */ ++ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (ret) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); ++ return -1; ++ } ++ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ drv_val = pWmtGenConf->sdio_driving_cfg; ++ ++ /*Dump the sdio driving related info */ ++ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); ++ ++ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ ++ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ ++ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ ++ ++ ret = wmt_core_init_script(sdio_driving_table, sizeof(sdio_driving_table) / sizeof(sdio_driving_table[0])); ++ ++ return ret; ++} ++#endif ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static INT32 mtk_wcn_soc_crystal_triming_set(VOID) ++{ ++ INT32 iRet = 0; ++ PUINT8 pbuf = NULL; ++ UINT32 bufLen = 0; ++ WMT_CTRL_DATA ctrlData; ++ UINT32 uCryTimOffset = 0x6D; ++ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ INT8 cCrystalTimingOffset = 0x0; ++ UINT8 cCrystalTiming = 0x0; ++ INT32 iCrystalTiming = 0x0; ++ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ UINT32 u4Res; ++ ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ /**/ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; ++ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; ++ ctrlData.au4CtrlData[1] = (UINT32) &pbuf; ++ ctrlData.au4CtrlData[2] = (UINT32) &bufLen; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 != iRet) { ++ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", wmt_ic_ops_soc.icId, iRet); ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ cCrystalTimingOffset = 0x0; ++ cCrystalTiming = 0x0; ++ iRet = -1; ++ } else { ++ WMT_DBG_FUNC("0x%x: nvram pBuf(0x%08x), bufLen(%d)\n", wmt_ic_ops_soc.icId, pbuf, bufLen); ++ if (bufLen < (uCryTimOffset + 1)) { ++ WMT_ERR_FUNC("0x%x: nvram len(%d) too short, crystalTimging value offset(%d)\n", ++ wmt_ic_ops_soc.icId, bufLen, uCryTimOffset); ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ cCrystalTimingOffset = 0x0; ++ cCrystalTiming = 0x0; ++ } else { ++ bIsNvramExist = MTK_WCN_BOOL_TRUE; ++ cCrystalTimingOffset = *(pbuf + uCryTimOffset); ++ if (cCrystalTimingOffset & 0x80) { ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; ++ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; ++ } ++ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", cCrystalTimingOffset, ++ bIsCrysTrimEnabled); ++ } ++ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; ++ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 != iRet) { ++ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", wmt_ic_ops_soc.icId, iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n", wmt_ic_ops_soc.icId); ++ } ++ } ++ if ((MTK_WCN_BOOL_TRUE == bIsNvramExist) && (MTK_WCN_BOOL_TRUE == bIsCrysTrimEnabled)) { ++ /*get CrystalTiming value before set it */ ++ iRet = ++ wmt_core_tx(get_crystal_timing_script[0].cmd, get_crystal_timing_script[0].cmdSz, &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", ++ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].cmdSz); ++ iRet = -3; ++ goto done; ++ } ++ /* EVENT BUF */ ++ osal_memset(get_crystal_timing_script[0].evt, 0, get_crystal_timing_script[0].evtSz); ++ iRet = wmt_core_rx(get_crystal_timing_script[0].evt, get_crystal_timing_script[0].evtSz, &u4Res); ++ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", ++ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ iRet = -4; ++ goto done; ++ } ++ ++ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; ++ if (cCrystalTimingOffset & 0x40) { ++ /*nagative offset value */ ++ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; ++ } else { ++ iCrystalTiming += cCrystalTimingOffset; ++ } ++ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); ++ cCrystalTiming = iCrystalTiming > 0x7f ? 0x7f : iCrystalTiming; ++ cCrystalTiming = iCrystalTiming < 0 ? 0 : iCrystalTiming; ++ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); ++ /* set_crystal_timing_script */ ++ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; ++ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; ++ ++ iRet = wmt_core_init_script(set_crystal_timing_script, osal_array_size(set_crystal_timing_script)); ++ if (iRet) { ++ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); ++ iRet = -5; ++ } else { ++ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", WMT_SET_CRYSTAL_TRIMING_CMD[5]); ++ iRet = ++ wmt_core_init_script(get_crystal_timing_script, osal_array_size(get_crystal_timing_script)); ++ if (iRet) { ++ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); ++ iRet = -6; ++ } else { ++ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", ++ WMT_GET_CRYSTAL_TRIMING_EVT[5]); ++ iRet = 0x0; ++ } ++ } ++ } ++done: ++ return iRet; ++} ++#endif ++ ++#if CFG_WMT_MULTI_PATCH ++static INT32 mtk_wcn_soc_patch_info_prepare(VOID) ++{ ++ INT32 iRet = -1; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; ++ iRet = wmt_ctrl(&ctrlData); ++ ++ return iRet; ++} ++ ++static INT32 mtk_wcn_soc_patch_dwn(UINT32 index) ++{ ++ INT32 iRet = -1; ++ P_WMT_PATCH patchHdr; ++ PUINT8 pbuf; ++ UINT32 patchSize; ++ UINT32 fragSeq; ++ UINT32 fragNum; ++ UINT16 fragSize = 0; ++ UINT16 cmdLen; ++ UINT32 offset; ++ UINT32 u4Res; ++ UINT8 evtBuf[8]; ++ UINT8 addressevtBuf[12]; ++ UINT8 addressByte[4]; ++ PINT8 cDataTime = NULL; ++ /*PINT8 cPlat = NULL; */ ++ UINT16 u2HwVer = 0; ++ UINT16 u2SwVer = 0; ++ UINT32 u4PatchVer = 0; ++ UINT32 patchSizePerFrag = 0; ++ WMT_CTRL_DATA ctrlData; ++ ++ /*1.check hardware information */ ++ if (NULL == gp_soc_info) { ++ WMT_ERR_FUNC("null gp_soc_info!\n"); ++ return -1; ++ } ++ ++ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); ++ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; ++ ctrlData.au4CtrlData[0] = index + 1; ++ ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &addressByte; ++ iRet = wmt_ctrl(&ctrlData); ++ WMT_DBG_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); ++ ++ /* <2.2> read patch content */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH; ++ ctrlData.au4CtrlData[0] = (SIZE_T) NULL; ++ ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &pbuf; ++ ctrlData.au4CtrlData[3] = (SIZE_T) &patchSize; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); ++ iRet -= 1; ++ goto done; ++ } ++ ++ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ ++ pbuf += BCNT_PATCH_BUF_HEADROOM; ++ /* patch file with header: ++ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| ++ */ ++ patchHdr = (P_WMT_PATCH) pbuf; ++ /* check patch file information */ ++ ++ cDataTime = patchHdr->ucDateTime; ++ u2HwVer = patchHdr->u2HwVer; ++ u2SwVer = patchHdr->u2SwVer; ++ u4PatchVer = patchHdr->u4PatchVer; ++ /*cPlat = &patchHdr->ucPLat[0]; */ ++ ++ cDataTime[15] = '\0'; ++ if (index == 0) { ++ WMT_DBG_FUNC("===========================================\n"); ++ WMT_INFO_FUNC("[Patch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", ++ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), ++ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), ++ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); ++ WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], ++ patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("===========================================\n"); ++ } ++ ++ /* remove patch header: ++ * |<-patch body: X Bytes (X=patchSize)--->| ++ */ ++ patchSize -= sizeof(WMT_PATCH); ++ pbuf += sizeof(WMT_PATCH); ++ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; ++ /* reserve 1st patch cmd space before patch body ++ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| ++ */ ++ /* gp_soc_patch_info = patchHdr; */ ++ osal_memcpy(&gp_soc_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); ++ pbuf -= sizeof(WMT_PATCH_CMD); ++ ++ fragNum = patchSize / patchSizePerFrag; ++ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; ++ ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ ++ /*send wmt part patch address command */ ++ if (0x6752 == wmt_ic_ops_soc.icId || ++ 0x8127 == wmt_ic_ops_soc.icId || ++ 0x7623 == wmt_ic_ops_soc.icId || ++ 0x6571 == wmt_ic_ops_soc.icId || ++ 0x0326 == wmt_ic_ops_soc.icId || ++ 0x0321 == wmt_ic_ops_soc.icId || ++ 0x0335 == wmt_ic_ops_soc.icId || ++ 0x0337 == wmt_ic_ops_soc.icId || 0x8163 == wmt_ic_ops_soc.icId || 0x6580 == wmt_ic_ops_soc.icId) { ++ /* MT6571 patch RAM base */ ++ WMT_PATCH_ADDRESS_CMD[8] = 0x40; ++ WMT_PATCH_P_ADDRESS_CMD[8] = 0xc8; ++ } ++ /*send wmt part patch address command */ ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ /* MT6797 patch RAM base */ ++ WMT_PATCH_ADDRESS_CMD[8] = 0x08; ++ WMT_PATCH_ADDRESS_CMD[9] = 0x05; ++ WMT_PATCH_P_ADDRESS_CMD[8] = 0x2c; ++ WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b; ++ } ++ ++ /*send wmt part patch address command */ ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); ++ iRet -= 1; ++ goto done; ++ } ++ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); ++ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); ++ iRet -= 1; ++ goto done; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); ++ iRet -= 1; ++ goto done; ++ } ++#endif ++ ++ /*send part patch address command */ ++ osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); ++ WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", ++ WMT_PATCH_P_ADDRESS_CMD[12], ++ WMT_PATCH_P_ADDRESS_CMD[13], WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { ++ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); ++ iRet -= 1; ++ goto done; ++ } ++ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); ++ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); ++ iRet -= 1; ++ goto done; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", index); ++ iRet -= 1; ++ goto done; ++ } ++#endif ++ ++ /* send all fragments */ ++ offset = sizeof(WMT_PATCH_CMD); ++ fragSeq = 0; ++ while (fragSeq < fragNum) { ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ if (fragSeq == (fragNum - 1)) { ++ /* last fragment */ ++ fragSize = patchSize - fragSeq * patchSizePerFrag; ++ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; ++ } else { ++ fragSize = patchSizePerFrag; ++ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; ++ } ++ /* update length field in CMD:flag+frag */ ++ cmdLen = 1 + fragSize; ++ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); ++ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ ++ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); ++ ++ /* iRet = ++ *(*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ *&u4Res); ++ */ ++ iRet = ++ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); ++ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ ++ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), ++ u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, ++ evtBuf[0], ++ evtBuf[1], ++ evtBuf[2], ++ evtBuf[3], ++ evtBuf[4]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_PATCH_EVT), ++ WMT_PATCH_EVT[0], ++ WMT_PATCH_EVT[1], ++ WMT_PATCH_EVT[2], ++ WMT_PATCH_EVT[3], ++ WMT_PATCH_EVT[4]); ++ iRet -= 1; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); ++ offset += patchSizePerFrag; ++ ++fragSeq; ++ } ++ ++ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", ++ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); ++ ++ if (fragSeq != fragNum) ++ iRet -= 1; ++done: ++ /* WMT_CTRL_FREE_PATCH always return 0 */ ++ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ ++ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; ++ ctrlData.au4CtrlData[0] = index + 1; ++ wmt_ctrl(&ctrlData); ++ ++ return iRet; ++} ++ ++#else ++static INT32 mtk_wcn_soc_patch_dwn(VOID) ++{ ++ INT32 iRet = -1; ++ P_WMT_PATCH patchHdr; ++ PUINT8 pbuf; ++ UINT32 patchSize; ++ UINT32 fragSeq; ++ UINT32 fragNum; ++ UINT16 fragSize = 0; ++ UINT16 cmdLen; ++ UINT32 offset; ++ UINT32 u4Res; ++ UINT8 evtBuf[8]; ++ PINT8 cDataTime = NULL; ++ /*PINT8 cPlat = NULL; */ ++ UINT16 u2HwVer = 0; ++ UINT16 u2SwVer = 0; ++ UINT32 u4PatchVer = 0; ++ UINT32 patchSizePerFrag = 0; ++ WMT_CTRL_DATA ctrlData; ++ ++ /*1.check hardware information */ ++ if (NULL == gp_soc_info) { ++ WMT_ERR_FUNC("null gp_soc_info!\n"); ++ return -1; ++ } ++ /* <2> search patch and read patch content */ ++ /* <2.1> search patch */ ++ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 == iRet) { ++ /* patch with correct Hw Ver Major Num found */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; ++ ctrlData.au4CtrlData[0] = (UINT32) &gFullPatchName; ++ iRet = wmt_ctrl(&ctrlData); ++ ++ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); ++ /* <2.2> read patch content */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH; ++ ctrlData.au4CtrlData[0] = (UINT32) NULL; ++ ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName; ++ ++ } else { ++ iRet -= 1; ++ return iRet; ++ } ++ ctrlData.au4CtrlData[2] = (UINT32) &pbuf; ++ ctrlData.au4CtrlData[3] = (UINT32) &patchSize; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); ++ iRet -= 1; ++ goto done; ++ } ++ ++ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ ++ pbuf += BCNT_PATCH_BUF_HEADROOM; ++ /* patch file with header: ++ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| ++ */ ++ patchHdr = (P_WMT_PATCH) pbuf; ++ /* check patch file information */ ++ ++ cDataTime = patchHdr->ucDateTime; ++ u2HwVer = patchHdr->u2HwVer; ++ u2SwVer = patchHdr->u2SwVer; ++ u4PatchVer = patchHdr->u4PatchVer; ++ /*cPlat = &patchHdr->ucPLat[0]; */ ++ ++ cDataTime[15] = '\0'; ++ WMT_DBG_FUNC("===========================================\n"); ++ WMT_INFO_FUNC("[ConsysPatch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", ++ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), ++ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), ++ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); ++ WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], ++ patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("===========================================\n"); ++ ++ /* remove patch header: ++ * |<-patch body: X Bytes (X=patchSize)--->| ++ */ ++ patchSize -= sizeof(WMT_PATCH); ++ pbuf += sizeof(WMT_PATCH); ++ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; ++ /* reserve 1st patch cmd space before patch body ++ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| ++ */ ++ pbuf -= sizeof(WMT_PATCH_CMD); ++ ++ fragNum = patchSize / patchSizePerFrag; ++ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; ++ ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ ++ /* send all fragments */ ++ offset = sizeof(WMT_PATCH_CMD); ++ fragSeq = 0; ++ while (fragSeq < fragNum) { ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ if (fragSeq == (fragNum - 1)) { ++ /* last fragment */ ++ fragSize = patchSize - fragSeq * patchSizePerFrag; ++ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; ++ } else { ++ fragSize = patchSizePerFrag; ++ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; ++ } ++ /* update length field in CMD:flag+frag */ ++ cmdLen = 1 + fragSize; ++ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); ++ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ ++ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); ++ ++ /* iRet = ++ * (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ * &u4Res); ++ */ ++ iRet = ++ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); ++ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ ++ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), ++ u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, ++ evtBuf[0], ++ evtBuf[1], ++ evtBuf[2], ++ evtBuf[3], ++ evtBuf[4]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_PATCH_EVT), ++ WMT_PATCH_EVT[0], ++ WMT_PATCH_EVT[1], ++ WMT_PATCH_EVT[2], ++ WMT_PATCH_EVT[3], ++ WMT_PATCH_EVT[4]); ++ iRet -= 1; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); ++ offset += patchSizePerFrag; ++ ++fragSeq; ++ } ++ ++ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", ++ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); ++ ++ if (fragSeq != fragNum) ++ iRet -= 1; ++done: ++ /* WMT_CTRL_FREE_PATCH always return 0 */ ++ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); ++ ++ return iRet; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c +new file mode 100644 +index 000000000000..747ed64af2d2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c +@@ -0,0 +1,1938 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-LIB]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_dev.h" ++#include "wmt_lib.h" ++#include "wmt_conf.h" ++#include "wmt_core.h" ++#include "wmt_plat.h" ++ ++#include "stp_core.h" ++#include "btm_core.h" ++#include "psm_core.h" ++#include "stp_dbg.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* A table for translation: CMB_STUB_AIF_X=>WMT_IC_PIN_STATE */ ++static const WMT_IC_PIN_STATE cmb_aif2pin_stat[] = { ++ [CMB_STUB_AIF_0] = WMT_IC_AIF_0, ++ [CMB_STUB_AIF_1] = WMT_IC_AIF_1, ++ [CMB_STUB_AIF_2] = WMT_IC_AIF_2, ++ [CMB_STUB_AIF_3] = WMT_IC_AIF_3, ++}; ++ ++#if CFG_WMT_PS_SUPPORT ++static UINT32 gPsIdleTime = STP_PSM_IDLE_TIME_SLEEP; ++static UINT32 gPsEnable = 1; ++static PF_WMT_SDIO_PSOP sdio_own_ctrl; ++#endif ++ ++#define WMT_STP_CPUPCR_BUF_SIZE 6144 ++static UINT8 g_cpupcr_buf[WMT_STP_CPUPCR_BUF_SIZE] = { 0 }; ++ ++static UINT32 g_quick_sleep_ctrl = 1; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++DEV_WMT gDevWmt; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_WMT_PS_SUPPORT ++static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action); ++static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID); ++static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID); ++static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID); ++static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action); ++#endif ++ ++static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pLxOp); ++ ++static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ); ++ ++static INT32 wmtd_thread(PVOID pvData); ++ ++static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag); ++static MTK_WCN_BOOL wmt_lib_hw_state_show(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_lib_idc_lock_aquire(VOID) ++{ ++ return osal_lock_sleepable_lock(&gDevWmt.idc_lock); ++} ++ ++VOID wmt_lib_idc_lock_release(VOID) ++{ ++ osal_unlock_sleepable_lock(&gDevWmt.idc_lock); ++} ++INT32 wmt_lib_psm_lock_aquire(void) ++{ ++ return osal_lock_sleepable_lock(&gDevWmt.psm_lock); ++} ++ ++void wmt_lib_psm_lock_release(void) ++{ ++ osal_unlock_sleepable_lock(&gDevWmt.psm_lock); ++} ++ ++INT32 DISABLE_PSM_MONITOR(void) ++{ ++ INT32 ret = 0; ++ ++ /* osal_lock_sleepable_lock(&gDevWmt.psm_lock); */ ++ ret = wmt_lib_psm_lock_aquire(); ++ if (ret) { ++ WMT_ERR_FUNC("--->lock psm_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++#if CFG_WMT_PS_SUPPORT ++ ret = wmt_lib_ps_disable(); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_lib_ps_disable fail, ret=%d\n", ret); ++ wmt_lib_psm_lock_release(); ++ } ++#endif ++ ++ return ret; ++} ++ ++void ENABLE_PSM_MONITOR(void) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_enable(); ++#endif ++ /* osal_unlock_sleepable_lock(&gDevWmt.psm_lock); */ ++ wmt_lib_psm_lock_release(); ++} ++ ++INT32 wmt_lib_init(VOID) ++{ ++ INT32 iRet; ++ UINT32 i; ++ P_DEV_WMT pDevWmt; ++ P_OSAL_THREAD pThraed; ++ ++ /* create->init->start */ ++ /* 1. create: static allocation with zero initialization */ ++ pDevWmt = &gDevWmt; ++ osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); ++ ++ iRet = wmt_conf_read_file(); ++ if (iRet) { ++ WMT_ERR_FUNC("read wmt config file fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ pThraed = &gDevWmt.thread; ++ ++ /* Create mtk_wmtd thread */ ++ osal_strncpy(pThraed->threadName, "mtk_wmtd", sizeof(pThraed->threadName)); ++ pThraed->pThreadData = (VOID *) pDevWmt; ++ pThraed->pThreadFunc = (VOID *) wmtd_thread; ++ iRet = osal_thread_create(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThraed, iRet); ++ return -2; ++ } ++ ++ /* 2. initialize */ ++ /* Initialize wmt_core */ ++ ++ iRet = wmt_core_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core_init() fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /* Initialize WMTd Thread Information: Thread */ ++ osal_event_init(&pDevWmt->rWmtdWq); ++ osal_sleepable_lock_init(&pDevWmt->psm_lock); ++ osal_sleepable_lock_init(&pDevWmt->idc_lock); ++ osal_sleepable_lock_init(&pDevWmt->rActiveOpQ.sLock); ++ osal_sleepable_lock_init(&pDevWmt->rFreeOpQ.sLock); ++ pDevWmt->state.data = 0; ++ ++ /* Initialize op queue */ ++ RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); ++ RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); ++ /* Put all to free Q */ ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(pDevWmt->arQue[i].signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); ++ } ++ ++ /* initialize stp resources */ ++ osal_event_init(&pDevWmt->rWmtRxWq); ++ ++ /*function driver callback */ ++ for (i = 0; i < WMTDRV_TYPE_WIFI; i++) ++ pDevWmt->rFdrvCb.fDrvRst[i] = NULL; ++ ++ pDevWmt->hw_ver = WMTHWVER_MAX; ++ WMT_INFO_FUNC("***********Init, hw->ver = %x\n", pDevWmt->hw_ver); ++ ++ /* TODO:[FixMe][GeorgeKuo]: wmt_lib_conf_init */ ++ /* initialize default configurations */ ++ /* i4Result = wmt_lib_conf_init(VOID); */ ++ /* WMT_WARN_FUNC("wmt_drv_conf_init(%d)\n", i4Result); */ ++ ++ osal_signal_init(&pDevWmt->cmdResp); ++ osal_event_init(&pDevWmt->cmdReq); ++ ++ /* initialize platform resources */ ++ if (0 != gDevWmt.rWmtGenConf.cfgExist) ++ iRet = wmt_plat_init(gDevWmt.rWmtGenConf.co_clock_flag & 0x0f); ++ else ++ iRet = wmt_plat_init(0); ++ ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_plat_init() fail(%d)\n", iRet); ++ return -3; ++ } ++#if CFG_WMT_PS_SUPPORT ++ iRet = wmt_lib_ps_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_lib_ps_init() fail(%d)\n", iRet); ++ return -4; ++ } ++#endif ++ ++ /* 3. start: start running mtk_wmtd */ ++ iRet = osal_thread_run(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", pThraed, iRet); ++ return -5; ++ } ++ ++ /*4. register irq callback to WMT-PLAT */ ++ wmt_plat_irq_cb_reg(wmt_lib_ps_irq_cb); ++ ++ /*5. register audio if control callback to WMT-PLAT */ ++ wmt_plat_aif_cb_reg(wmt_lib_set_aif); ++ ++ /*6. register function control callback to WMT-PLAT */ ++ wmt_plat_func_ctrl_cb_reg(mtk_wcn_wmt_func_ctrl_for_plat); ++ ++ wmt_plat_deep_idle_ctrl_cb_reg(mtk_wcn_consys_stp_btif_dpidle_ctrl); ++ /*7 reset gps/bt state */ ++ ++ mtk_wcn_wmt_system_state_reset(); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_wmt_exp_init(); ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ wmt_idc_init(); ++#endif ++ WMT_DBG_FUNC("init success\n"); ++ return 0; ++} ++ ++INT32 wmt_lib_deinit(VOID) ++{ ++ INT32 iRet; ++ P_DEV_WMT pDevWmt; ++ P_OSAL_THREAD pThraed; ++ INT32 i; ++ INT32 iResult; ++ ++ pDevWmt = &gDevWmt; ++ pThraed = &gDevWmt.thread; ++ iResult = 0; ++ ++ /* stop->deinit->destroy */ ++ ++ /* 1. stop: stop running mtk_wmtd */ ++ iRet = osal_thread_stop(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); ++ iResult += 1; ++ } ++ ++ /* 2. deinit: */ ++ ++#if CFG_WMT_PS_SUPPORT ++ iRet = wmt_lib_ps_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_lib_ps_deinit fail(%d)\n", iRet); ++ iResult += 2; ++ } ++#endif ++ ++ iRet = wmt_plat_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_plat_deinit fail(%d)\n", iRet); ++ iResult += 4; ++ } ++ ++ osal_event_deinit(&pDevWmt->cmdReq); ++ osal_signal_deinit(&pDevWmt->cmdResp); ++ ++ /* de-initialize stp resources */ ++ osal_event_deinit(&pDevWmt->rWmtRxWq); ++ ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) ++ osal_signal_deinit(&(pDevWmt->arQue[i].signal)); ++ ++ ++ osal_sleepable_lock_deinit(&pDevWmt->rFreeOpQ.sLock); ++ osal_sleepable_lock_deinit(&pDevWmt->rActiveOpQ.sLock); ++ osal_sleepable_lock_deinit(&pDevWmt->idc_lock); ++ osal_sleepable_lock_deinit(&pDevWmt->psm_lock); ++ osal_event_deinit(&pDevWmt->rWmtdWq); ++ ++ iRet = wmt_core_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core_deinit fail(%d)\n", iRet); ++ iResult += 8; ++ } ++ ++ /* 3. destroy */ ++ iRet = osal_thread_destroy(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); ++ iResult += 16; ++ } ++ osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_wmt_exp_deinit(); ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ wmt_idc_deinit(); ++#endif ++ ++ return iResult; ++} ++ ++VOID wmt_lib_flush_rx(VOID) ++{ ++ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); ++} ++ ++INT32 wmt_lib_trigger_cmd_signal(INT32 result) ++{ ++ P_OSAL_SIGNAL pSignal = &gDevWmt.cmdResp; ++ ++ gDevWmt.cmdResult = result; ++ osal_raise_signal(pSignal); ++ WMT_DBG_FUNC("wakeup cmdResp\n"); ++ return 0; ++} ++ ++P_OSAL_EVENT wmt_lib_get_cmd_event(VOID) ++{ ++ return &gDevWmt.cmdReq; ++} ++ ++INT32 wmt_lib_set_patch_name(PUINT8 cPatchName) ++{ ++ osal_strncpy(gDevWmt.cPatchName, cPatchName, NAME_MAX); ++ return 0; ++} ++ ++INT32 wmt_lib_set_hif(unsigned long hifconf) ++{ ++ UINT32 val; ++ P_WMT_HIF_CONF pHif = &gDevWmt.rWmtHifConf; ++ ++ val = hifconf & 0xF; ++ if (STP_UART_FULL == val) { ++ pHif->hifType = WMT_HIF_UART; ++ val = (hifconf >> 8); ++ pHif->au4HifConf[0] = val; ++ pHif->au4HifConf[1] = val; ++ mtk_wcn_stp_set_if_tx_type(STP_UART_IF_TX); ++ } else if (STP_SDIO == val) { ++ pHif->hifType = WMT_HIF_SDIO; ++ mtk_wcn_stp_set_if_tx_type(STP_SDIO_IF_TX); ++ } else if (STP_BTIF_FULL == val) { ++ pHif->hifType = WMT_HIF_BTIF; ++ mtk_wcn_stp_set_if_tx_type(STP_BTIF_IF_TX); ++ } else { ++ WMT_WARN_FUNC("invalid stp mode: %u\n", val); ++ mtk_wcn_stp_set_if_tx_type(STP_MAX_IF_TX); ++ return -1; ++ } ++ ++ val = (hifconf & 0xF0) >> 4; ++ if (WMT_FM_COMM == val) { ++ pHif->au4StrapConf[0] = WMT_FM_COMM; ++ } else if (WMT_FM_I2C == val) { ++ pHif->au4StrapConf[0] = WMT_FM_I2C; ++ } else { ++ WMT_WARN_FUNC("invalid fm mode: %u\n", val); ++ return -2; ++ } ++ ++ WMT_WARN_FUNC("new hifType: %d, fm:%d\n", pHif->hifType, pHif->au4StrapConf[0]); ++ return 0; ++} ++ ++P_WMT_HIF_CONF wmt_lib_get_hif(VOID) ++{ ++ return &gDevWmt.rWmtHifConf; ++} ++ ++PUINT8 wmt_lib_get_cmd(VOID) ++{ ++ if (osal_test_and_clear_bit(WMT_STAT_CMD, &gDevWmt.state)) ++ return gDevWmt.cCmd; ++ ++ return NULL; ++} ++ ++MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID) ++{ ++ return osal_test_bit(WMT_STAT_CMD, &gDevWmt.state) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; ++} ++ ++#if CFG_WMT_PS_SUPPORT ++INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime) ++{ ++ gPsIdleTime = psIdleTime; ++ return gPsIdleTime; ++} ++ ++INT32 wmt_lib_ps_ctrl(UINT32 state) ++{ ++ if (0 == state) { ++ wmt_lib_ps_disable(); ++ gPsEnable = 0; ++ } else { ++ gPsEnable = 1; ++ wmt_lib_ps_enable(); ++ } ++ return 0; ++} ++ ++INT32 wmt_lib_ps_enable(VOID) ++{ ++ if (gPsEnable) ++ mtk_wcn_stp_psm_enable(gPsIdleTime); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_disable(VOID) ++{ ++ if (gPsEnable) ++ return mtk_wcn_stp_psm_disable(); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_init(VOID) ++{ ++ /* mtk_wcn_stp_psm_register_wmt_cb(wmt_lib_ps_stp_cb); */ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_deinit(VOID) ++{ ++ /* mtk_wcn_stp_psm_unregister_wmt_cb(); */ ++ return 0; ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action) ++{ ++ P_OSAL_OP lxop; ++ MTK_WCN_BOOL bRet; ++ UINT32 u4Wait; ++ P_OSAL_SIGNAL pSignal; ++ ++ lxop = wmt_lib_get_free_op(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ pSignal = &lxop->signal; ++ pSignal->timeoutValue = 0; ++ lxop->op.opId = WMT_OPID_PWR_SV; ++ lxop->op.au4OpData[0] = action; ++ lxop->op.au4OpData[1] = (SIZE_T) mtk_wcn_stp_psm_notify_stp; ++ u4Wait = 0; ++ bRet = wmt_lib_put_act_op(lxop); ++ return bRet; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor) ++{ ++ P_OSAL_OP lxop; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ INT32 ret = 0; ++ UINT16 msg_len = 0; ++ static UINT8 msg_local_buffer[1300]; ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++#endif ++ WMT_DBG_FUNC("idc_infor from conn_md is 0x%p\n", idc_infor); ++ ret = wmt_lib_idc_lock_aquire(); ++ if (ret) { ++ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", ret); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ msg_len = idc_infor->local_para_ptr->msg_len - osal_sizeof(local_para_struct); ++ osal_memcpy(&msg_local_buffer[0], &msg_len, osal_sizeof(msg_len)); ++ osal_memcpy(&msg_local_buffer[osal_sizeof(msg_len)], ++ &(idc_infor->local_para_ptr->data[0]), msg_len - 1); ++ wmt_lib_idc_lock_release(); ++ lxop = wmt_lib_get_free_op(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ pSignal = &lxop->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ lxop->op.opId = WMT_OPID_IDC_MSG_HANDLING; ++ lxop->op.au4OpData[0] = (size_t) msg_local_buffer; ++ /*msg opcode fill rule is still not clrear,need scott comment */ ++ /***********************************************************/ ++ WMT_DBG_FUNC("ilm msg id is (0x%08x)\n", idc_infor->msg_id); ++ ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ switch (idc_infor->msg_id) { ++ case IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_PARA; ++ break; ++ case IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_FREQ; ++ break; ++ case IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_WIFI_MAX_POWER; ++ break; ++ case IPC_MSG_ID_EL1_LTE_TX_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_INDICATION; ++ break; ++ case IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS; ++ break; ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ break; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(lxop); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(lxop); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); ++ else ++ WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", lxop->op.opId, lxop->op.au4OpData[1]); ++ } else { ++ bRet = MTK_WCN_BOOL_FALSE; ++ wmt_lib_put_op_to_free_queue(lxop); ++ WMT_ERR_FUNC("unknown msgid from LTE(%d)\n", idc_infor->msg_id); ++ } ++#else ++ if ((idc_infor->msg_id >= IPC_EL1_MSG_ID_BEGIN) ++ && (idc_infor->msg_id <= IPC_EL1_MSG_ID_BEGIN + IPC_EL1_MSG_ID_RANGE)) { ++ lxop->op.au4OpData[1] = idc_infor->msg_id - IPC_EL1_MSG_ID_BEGIN + LTE_MSG_ID_OFFSET - 1; ++ ++ WMT_DBG_FUNC("LTE->CONN:(0x%x->0x%zx)\n", idc_infor->msg_id, lxop->op.au4OpData[1]); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(lxop); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(lxop); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); ++ } else { ++ WMT_DBG_FUNC("wmt_lib_handle_idc_msg OPID(%d) type(%d) ok\n", ++ lxop->op.opId, lxop->op.au4OpData[1]); ++ } ++ } else { ++ wmt_lib_put_op_to_free_queue(lxop); ++ WMT_ERR_FUNC("msgid(%d) out of range,wmt drop it!\n", idc_infor->msg_id); ++ } ++#endif ++ ++ return bRet; ++} ++#endif ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID) ++{ ++ return wmt_lib_ps_action(SLEEP); ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID) ++{ ++ return wmt_lib_ps_action(WAKEUP); ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID) ++{ ++#if 1 ++ return wmt_lib_ps_action(WAKEUP); ++#else ++ return wmt_lib_ps_action(HOST_AWAKE); ++#endif ++} ++ ++/* extern int g_block_tx; */ ++static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action) ++{ ++ INT32 ret; ++ ++ ret = 0; /* TODO:[FixMe][George] initial value or compile warning? */ ++ /* if(g_block_tx && (action == SLEEP)) */ ++ if ((0 != mtk_wcn_stp_coredump_start_get()) && (action == SLEEP)) { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ return ret; ++ } ++ ++ /*MT662x Not Ready */ ++ if (!mtk_wcn_stp_is_ready()) { ++ WMT_DBG_FUNC("MT662x Not Ready, Dont Send Sleep/Wakeup Command\n"); ++ mtk_wcn_stp_psm_notify_stp(ROLL_BACK); ++ return 0; ++ } ++ ++ if (SLEEP == action) { ++ WMT_DBG_FUNC("send op-----------> sleep job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ ret = wmt_lib_ps_do_sleep(); ++ WMT_DBG_FUNC("enable host eirq\n"); ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_EN); ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ } else { ++ /* ret = mtk_wcn_stp_sdio_do_own_set(); */ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_SET); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ } else if (ret == -2) { ++ mtk_wcn_stp_psm_notify_stp(ROLL_BACK); ++ WMT_WARN_FUNC("===[SDIO-PS] rollback due to tx busy===%%\n"); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ WMT_ERR_FUNC("===[SDIO-PS] set own fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<---------- sleep job\n"); ++ } else if (WAKEUP == action) { ++ WMT_DBG_FUNC("send op --------> wake job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ ret = wmt_lib_ps_do_wakeup(); ++ } else { ++ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ ++ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_CLR); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(WAKEUP); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(WAKEUP); ++ WMT_ERR_FUNC("===[SDIO-PS] set own back fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<---------- wake job\n"); ++ } else if (HOST_AWAKE == action) { ++ WMT_DBG_FUNC("send op-----------> host awake job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++ /* IRQ already disabled */ ++ /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ ret = wmt_lib_ps_do_host_awake(); ++ } else { ++ WMT_DBG_FUNC("[SDIO-PS] SDIO host awake! ####\n"); ++ ++ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ ++ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_CLR); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ /* Here we set ret to 0 directly */ ++ ret = 0; ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); ++ WMT_ERR_FUNC("===[SDIO-PS]set own back fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<----------- host awake job\n"); ++ } else if (EIRQ == action) { ++ WMT_DBG_FUNC("send op -------------> eirq job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++ /* Disable interrupt */ ++ /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ ++ ret = mtk_wcn_stp_psm_notify_stp(EIRQ); ++ } else { ++ WMT_ERR_FUNC("[SDIO-PS]sdio own-back eirq!######\n"); ++ ret = mtk_wcn_stp_psm_notify_stp(EIRQ); ++ } ++ ++ WMT_DBG_FUNC("send op<----------- eirq job\n"); ++ } ++ ++ return ret; ++} ++#endif /* end of CFG_WMT_PS_SUPPORT */ ++ ++INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action) ++{ ++#if CFG_WMT_PS_SUPPORT ++ return wmt_lib_ps_handler(action); ++#else ++ WMT_WARN_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); ++ return 0; ++#endif ++} ++ ++MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID) ++{ ++ if ((g_quick_sleep_ctrl) && (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_TRUE)) ++ return wmt_core_is_quick_ps_support(); ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++VOID wmt_lib_ps_irq_cb(VOID) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_handler(EIRQ); ++#else ++ WMT_DBG_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); ++ return; ++#endif ++} ++ ++VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb) ++{ ++#if CFG_WMT_PS_SUPPORT ++ sdio_own_ctrl = own_cb; ++#endif ++} ++ ++UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread) ++{ ++ P_DEV_WMT pDevWmt; ++ ++ if (pThread) { ++ pDevWmt = (P_DEV_WMT) (pThread->pThreadData); ++ return !RB_EMPTY(&pDevWmt->rActiveOpQ); ++ } ++ WMT_ERR_FUNC("pThread(NULL)\n"); ++ return 0; ++} ++ ++static INT32 wmtd_thread(void *pvData) ++{ ++ P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData; ++ P_OSAL_EVENT pEvent = NULL; ++ P_OSAL_OP pOp; ++ INT32 iResult; ++ ++ if (NULL == pWmtDev) { ++ WMT_ERR_FUNC("pWmtDev(NULL)\n"); ++ return -1; ++ } ++ WMT_INFO_FUNC("wmtd thread starts\n"); ++ ++ pEvent = &(pWmtDev->rWmtdWq); ++ ++ for (;;) { ++ pOp = NULL; ++ pEvent->timeoutValue = 0; ++/* osal_thread_wait_for_event(&pWmtDev->thread, pEvent);*/ ++ osal_thread_wait_for_event(&pWmtDev->thread, pEvent, wmt_lib_wait_event_checker); ++ ++ if (osal_thread_should_stop(&pWmtDev->thread)) { ++ WMT_INFO_FUNC("wmtd thread should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = wmt_lib_get_op(&pWmtDev->rActiveOpQ); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_lxop activeQ fail\n"); ++ continue; ++ } ++#if 0 /* wmt_core_opid_handler will do sanity check on opId, so no usage here */ ++ id = lxop_get_opid(pLxOp); ++ if (id >= WMT_OPID_MAX) { ++ WMT_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ iResult = -1; ++ goto handlerDone; ++ } ++#endif ++ ++ if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) { ++ /* when whole chip reset, only HW RST and SW RST cmd can execute */ ++ if ((pOp->op.opId == WMT_OPID_HW_RST) || (pOp->op.opId == WMT_OPID_SW_RST) ++ || (pOp->op.opId == WMT_OPID_GPIO_STATE)) { ++ iResult = wmt_core_opid(&pOp->op); ++ } else { ++ iResult = -2; ++ WMT_WARN_FUNC("Whole chip resetting, opid (%d) failed, iRet(%d)\n", pOp->op.opId, ++ iResult); ++ } ++ } else { ++ wmt_lib_set_current_op(pWmtDev, pOp); ++ iResult = wmt_core_opid(&pOp->op); ++ wmt_lib_set_current_op(pWmtDev, NULL); ++ } ++ ++ if (iResult) ++ WMT_WARN_FUNC("opid (%d) failed, iRet(%d)\n", pOp->op.opId, iResult); ++ ++ if (osal_op_is_wait_for_signal(pOp)) { ++ osal_op_raise_signal(pOp, iResult); ++ } else { ++ /* put Op back to freeQ */ ++ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); ++ } ++ ++ if (WMT_OPID_EXIT == pOp->op.opId) { ++ WMT_INFO_FUNC("wmtd thread received exit signal\n"); ++ break; ++ } ++ } ++ ++ WMT_INFO_FUNC("wmtd thread exits succeed\n"); ++ ++ return 0; ++}; ++ ++static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 iRet; ++ ++ if (!pOpQ || !pOp) { ++ WMT_WARN_FUNC("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", pOpQ, pOp); ++ osal_assert(pOpQ); ++ osal_assert(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ iRet = osal_lock_sleepable_lock(&pOpQ->sLock); ++ if (iRet) { ++ WMT_WARN_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); ++ return MTK_WCN_BOOL_FALSE; ++ } ++#if 0 ++ if (pOpQ == &gDevWmt.rFreeOpQ) ++ WMT_INFO_FUNC("current wmt free queue count is(%d),opid(%d)\n", RB_COUNT(pOpQ), pOp->op.opId); ++#endif ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ iRet = -1; ++ ++ osal_unlock_sleepable_lock(&pOpQ->sLock); ++ ++ if (iRet) { ++ WMT_WARN_FUNC("RB_FULL(0x%p)\n", pOpQ); ++ return MTK_WCN_BOOL_FALSE; ++ } else { ++ return MTK_WCN_BOOL_TRUE; ++ } ++} ++ ++static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ INT32 iRet; ++ ++ if (NULL == pOpQ) { ++ WMT_ERR_FUNC("pOpQ = NULL\n"); ++ osal_assert(pOpQ); ++ return NULL; ++ } ++ ++ iRet = osal_lock_sleepable_lock(&pOpQ->sLock); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); ++ return NULL; ++ } ++ ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ osal_unlock_sleepable_lock(&pOpQ->sLock); ++ ++ if (NULL == pOp) { ++ WMT_WARN_FUNC("RB_GET return NULL\n"); ++ osal_assert(pOp); ++ } ++ ++ return pOp; ++} ++ ++INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (MTK_WCN_BOOL_FALSE == wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp)) ++ return -1; ++ else ++ return 0; ++} ++ ++P_OSAL_OP wmt_lib_get_free_op(VOID) ++{ ++ P_OSAL_OP pOp = NULL; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ ++ osal_assert(pDevWmt); ++ ++ pOp = wmt_lib_get_op(&pDevWmt->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, osal_sizeof(pOp->op)); ++ return pOp; ++} ++ ++MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ MTK_WCN_BOOL bCleanup = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal = NULL; ++ long waitRet = -1; ++ P_OSAL_THREAD pThread; ++ ++ osal_assert(pWmtDev); ++ osal_assert(pOp); ++ ++ do { ++ if (!pWmtDev || !pOp) { ++ WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp); ++ break; ++ } ++ if ((0 != mtk_wcn_stp_coredump_start_get()) && ++ (WMT_OPID_HW_RST != pOp->op.opId) && ++ (WMT_OPID_SW_RST != pOp->op.opId) && (WMT_OPID_GPIO_STATE != pOp->op.opId)) { ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ WMT_WARN_FUNC("block tx flag is set\n"); ++ break; ++ } ++ pSignal = &pOp->signal; ++/* pOp->u4WaitMs = u4WaitMs; */ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(pSignal); ++ } ++ ++ /* put to active Q */ ++ bRet = wmt_lib_put_op(&pWmtDev->rActiveOpQ, pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("put to active queue fail\n"); ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ break; ++ } ++ ++ /* wake up wmtd */ ++ /* wake_up_interruptible(&pWmtDev->rWmtdWq); */ ++ osal_trigger_event(&pWmtDev->rWmtdWq); ++ ++ if (0 == pSignal->timeoutValue) { ++ bRet = MTK_WCN_BOOL_TRUE; ++ /* clean it in wmtd */ ++ break; ++ } ++ /* wait result, clean it here */ ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ ++ /* check result */ ++ /* wait_ret = wait_for_completion_interruptible_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ ++ /* wait_ret = wait_for_completion_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ ++ waitRet = osal_wait_for_signal_timeout(pSignal); ++ WMT_DBG_FUNC("osal_wait_for_signal_timeout:%ld\n", waitRet); ++ ++ /* if (unlikely(!wait_ret)) { */ ++ if (0 == waitRet) { ++ pThread = &gDevWmt.thread; ++ WMT_ERR_FUNC ++ ("wait completion timeout, opId(%d), show wmtd_thread stack!\n", pOp->op.opId); ++ /* TODO: how to handle it? retry? */ ++ wcn_wmtd_timeout_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ osal_thread_show_stack(pThread); ++ } else { ++ if (pOp->result) ++ WMT_WARN_FUNC("opId(%d) result:%d\n", pOp->op.opId, pOp->result); ++ } ++ /* op completes, check result */ ++ bRet = (pOp->result) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); ++ } ++ ++ return bRet; ++} ++ ++/* TODO:[ChangeFeature][George] is this function obsoleted? */ ++#if 0 ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_WMT_LXOP lxop; ++ MTK_WCN_BOOL bRet; ++ PUINT32 plv = NULL; ++ UINT32 pbuf[2]; ++ P_OSAL_EVENT pSignal = NULL; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ lxop = wmt_lib_get_free_lxop(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ ++ return -1; ++ } ++ ++ plv = (PUINT32) (((UINT32) pbuf + 0x3) & ~0x3UL); ++ *plv = *pvalue; ++ pSignal = &lxop->signal; ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%d) offset(0x%x) value(0x%x) mask(0x%x)\n", isWrite, offset, *pvalue, mask); ++ ++ lxop->op.opId = WMT_OPID_REG_RW; ++ lxop->op.au4OpData[0] = isWrite; ++ lxop->op.au4OpData[1] = offset; ++ lxop->op.au4OpData[2] = (UINT32) plv; ++ lxop->op.au4OpData[3] = mask; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ DISABLE_PSM_MONITOR(); ++ bRet = wmt_lib_put_act_lxop(lxop); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, *plv, mask); ++ if (!isWrite) ++ *pvalue = *plv; ++ } else { ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, *plv, mask, bRet); ++ } ++ ++ return bRet; ++} ++#endif ++ ++/* TODO:[ChangeFeature][George] is this function obsoleted? */ ++#if 0 ++static VOID wmt_lib_clear_chip_id(VOID) ++{ ++/* ++ gDevWmt.pChipInfo = NULL; ++*/ ++ gDevWmt.hw_ver = WMTHWVER_INVALID; ++} ++#endif ++ ++/* TODO: [FixMe][GeorgeKuo]: change this API to report real chip id, hw_ver, and */ ++/* fw_ver instead of WMT-translated WMTHWVER */ ++ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver(VOID) ++{ ++/* ++ P_WMT_CMB_CHIP_INFO_S pChipInfo = NULL; ++ P_DEV_WMT pWmtDev = gpDevWmt; ++ pChipInfo = wmt_lib_get_chip_info(pWmtDev); ++ return pChipInfo != NULL ? pChipInfo->eHwVersion : WMTHWVER_INVALID; ++ */ ++ return gDevWmt.eWmtHwVer; ++} ++ ++UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T index) ++{ ++ if (WMTCHIN_CHIPID == index) ++ return gDevWmt.chip_id; ++ else if (WMTCHIN_HWVER == index) ++ return gDevWmt.hw_ver; ++ else if (WMTCHIN_MAPPINGHWVER == index) ++ return gDevWmt.eWmtHwVer; ++ else if (WMTCHIN_FWVER == index) ++ return gDevWmt.fw_ver; ++ ++ return 0; ++ ++} ++ ++PUINT8 wmt_lib_def_patch_name(VOID) ++{ ++ WMT_INFO_FUNC("wmt-lib: use default patch name (%s)\n", gDevWmt.cPatchName); ++ return gDevWmt.cPatchName; ++} ++ ++MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID) ++{ ++ MTK_WCN_BOOL bIsSupportTherm = MTK_WCN_BOOL_TRUE; ++ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ ++ if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) ++ || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { ++ WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); ++ bIsSupportTherm = MTK_WCN_BOOL_FALSE; ++ } ++ if (!mtk_wcn_stp_is_ready()) { ++ WMT_ERR_FUNC("thermal command can not be send: STP is not ready\n"); ++ bIsSupportTherm = MTK_WCN_BOOL_FALSE; ++ } ++ ++ return bIsSupportTherm; ++} ++ ++MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ ++ if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) ++ || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { ++ WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++/*! ++ * \brief Update combo chip pin settings (GPIO) ++ * ++ * An internal library function to support various settings for chip GPIO. It is ++ * updated in a grouping way: configure all required pins in a single call. ++ * ++ * \param id desired pin ID to be controlled ++ * \param stat desired pin states to be set ++ * \param flag supplementary options for this operation ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid id ++ * \retval -2 invalid stat ++ * \retval < 0 error for operation fail ++ */ ++static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /* input sanity check */ ++ if (WMT_IC_PIN_MAX <= id) { ++ WMT_ERR_FUNC("invalid ic pin id(%d)\n", id); ++ return -1; ++ } ++ if (WMT_IC_PIN_STATE_MAX <= stat) { ++ WMT_ERR_FUNC("invalid ic pin state (%d)\n", stat); ++ return -2; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_GPIO_CTRL (ic pin id:%d, stat:%d, flag:0x%x)\n", id, stat, flag); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_GPIO_CTRL; ++ pOp->op.au4OpData[0] = id; ++ pOp->op.au4OpData[1] = stat; ++ pOp->op.au4OpData[2] = flag; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("PIN_ID(%d) PIN_STATE(%d) flag(%d) fail\n", id, stat, flag); ++ else ++ WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 value; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ value = *pvalue; ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", isWrite, offset, *pvalue, mask); ++ pOp->op.opId = WMT_OPID_REG_RW; ++ pOp->op.au4OpData[0] = isWrite; ++ pOp->op.au4OpData[1] = offset; ++ pOp->op.au4OpData[2] = (SIZE_T)&value; ++ pOp->op.au4OpData[3] = mask; ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, value, mask); ++ if (!isWrite) ++ *pvalue = value; ++ ++ return 0; ++ } ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, value, mask, bRet); ++ return -1; ++} ++ ++INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 value; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ value = *pvalue; ++ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", ++ isWrite, offset, *pvalue, mask); ++ pOp->op.opId = WMT_OPID_EFUSE_RW; ++ pOp->op.au4OpData[0] = isWrite; ++ pOp->op.au4OpData[1] = offset; ++ pOp->op.au4OpData[2] = (SIZE_T)&value; ++ pOp->op.au4OpData[3] = mask; ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, value, mask); ++ if (!isWrite) ++ *pvalue = value; ++ ++ return 0; ++ } ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, value, mask, bRet); ++ return -1; ++ ++} ++ ++/*! ++ * \brief update combo chip AUDIO Interface (AIF) settings ++ * ++ * A library function to support updating chip AUDIO pin settings. A group of ++ * pins is updated as a whole. ++ * ++ * \param aif desired audio interface state to use ++ * \param flag whether audio pin is shared or not ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid aif ++ * \retval < 0 error for invalid parameters or operation fail ++ */ ++INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share) ++{ ++ if (CMB_STUB_AIF_MAX <= aif) { ++ WMT_ERR_FUNC("invalid aif (%d)\n", aif); ++ return -1; ++ } ++ WMT_DBG_FUNC("call pin_ctrl for aif:%d, share:%d\n", aif, (MTK_WCN_BOOL_TRUE == share) ? 1 : 0); ++ /* Translate CMB_STUB_AIF_X into WMT_IC_PIN_STATE by array */ ++ return wmt_lib_pin_ctrl(WMT_IC_PIN_AUDIO, ++ cmb_aif2pin_stat[aif], ++ (MTK_WCN_BOOL_TRUE == share) ? WMT_LIB_AIF_FLAG_SHARE : WMT_LIB_AIF_FLAG_SEPARATE); ++} ++ ++INT32 wmt_lib_host_awake_get(VOID) ++{ ++ return wmt_plat_wake_lock_ctrl(WL_OP_GET); ++} ++ ++INT32 wmt_lib_host_awake_put(VOID) ++{ ++ return wmt_plat_wake_lock_ctrl(WL_OP_PUT); ++} ++ ++MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (op == BTM_RST_OP) { ++ /* high priority, not to enqueue into the queue of wmtd */ ++ WMT_INFO_FUNC("Invoke whole chip reset from stp_btm!!!\n"); ++ wmt_lib_cmb_rst(WMTRSTSRC_RESET_STP); ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else if (op == BTM_DMP_OP) { ++ ++ WMT_WARN_FUNC("TBD!!!\n"); ++ } else if (op == BTM_GET_AEE_SUPPORT_FLAG) { ++ bRet = wmt_core_get_aee_dump_flag(); ++ } ++ return bRet; ++} ++ ++MTK_WCN_BOOL wmt_cdev_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg) ++{ ++ ++ INT32 i = 0; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ PUINT8 drv_name[] = { ++ "DRV_TYPE_BT", ++ "DRV_TYPE_FM", ++ "DRV_TYPE_GPS", ++ "DRV_TYPE_WIFI" ++ }; ++ ++ for (i = 0; i <= WMTDRV_TYPE_WIFI; i++) { ++ /* <1> check if reset callback is registered */ ++ if (pDevWmt->rFdrvCb.fDrvRst[i]) { ++ /* <2> send the msg to this subfucntion */ ++ /*src, dst, msg_type, msg_data, msg_size */ ++ pDevWmt->rFdrvCb.fDrvRst[i] (WMTDRV_TYPE_WMT, i, WMTMSG_TYPE_RESET, &msg, ++ sizeof(ENUM_WMTRSTMSG_TYPE_T)); ++ WMT_INFO_FUNC("type = %s, msg sent\n", drv_name[i]); ++ } else { ++ WMT_DBG_FUNC("type = %s, unregistered\n", drv_name[i]); ++ } ++ } ++ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++VOID wmt_lib_state_init(VOID) ++{ ++ /* UINT32 i = 0; */ ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ P_OSAL_OP pOp; ++ ++ /* Initialize op queue */ ++ /* RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); */ ++ /* RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); */ ++ ++ while (!RB_EMPTY(&pDevWmt->rActiveOpQ)) { ++#if 0 ++ osal_signal_init(&(pOp->signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); ++#endif ++ pOp = wmt_lib_get_op(&pDevWmt->rActiveOpQ); ++ if (pOp) { ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, -1); ++ else ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); ++ } ++ } ++ ++ /* Put all to free Q */ ++ /* ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(pDevWmt->arQue[i].signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); ++ } */ ++} ++ ++#if 0 ++INT32 wmt_lib_sdio_ctrl(UINT32 on) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_SDIO_CTRL\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_SDIO_CTRL; ++ pOp->op.au4OpData[0] = on; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_SDIO_CTRL failed\n"); ++ return -1; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_SDIO_CTRL)ok\n"); ++ ++ return 0; ++} ++#endif ++ ++MTK_WCN_BOOL wmt_lib_hw_state_show(VOID) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_HW_STATE_SHOW\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_GPIO_STATE; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_HW_STATE_SHOW failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_HW_STATE_SHOW)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++MTK_WCN_BOOL wmt_lib_hw_rst(VOID) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ ++ wmt_lib_state_init(); ++ ++ osal_clear_bit(WMT_STAT_STP_REG, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_OPEN, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_EN, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_RDY, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_RX, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_CMD, &pDevWmt->state); ++ ++ /*Before do hardware reset, we show GPIO state to check if others modified our pin state accidentially */ ++ wmt_lib_hw_state_show(); ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_HW_RST\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_HW_RST; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_HW_RST failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_HW_RST)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /* <1> wmt state reset */ ++ wmt_lib_state_init(); ++ ++ /* <2> Reset STP data structure */ ++ WMT_DBG_FUNC("Cleanup STP context\n"); ++ mtk_wcn_stp_flush_context(); ++ /* <3> Reset STP-PSM data structure */ ++ WMT_DBG_FUNC("Cleanup STP-PSM context\n"); ++ mtk_wcn_stp_psm_reset(); ++ ++ /* <4> do sw reset in wmt-core */ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_SW_RST\n"); ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_FUNC_ON_TIME; ++ ++ pOp->op.opId = WMT_OPID_SW_RST; ++ pOp->op.au4OpData[0] = baudRst; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_SW_RST failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_SW_RST)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src) ++{ ++#define RETRYTIMES 10 ++ MTK_WCN_BOOL bRet; ++ ENUM_WMTRSTRET_TYPE_T retval = WMTRSTRET_MAX; ++ ENUM_WMTRSTMSG_TYPE_T rstMsg = WMTRSTMSG_RESET_MAX; ++ INT32 retries = RETRYTIMES; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ P_OSAL_OP pOp; ++ PUINT8 srcName[] = { "WMTRSTSRC_RESET_BT", ++ "WMTRSTSRC_RESET_FM", ++ "WMTRSTSRC_RESET_GPS", ++ "WMTRSTSRC_RESET_WIFI", ++ "WMTRSTSRC_RESET_STP", ++ "WMTRSTSRC_RESET_TEST" ++ }; ++ ++ if (src < WMTRSTSRC_RESET_MAX) ++ WMT_INFO_FUNC("reset source = %s\n", srcName[src]); ++ ++ if (WMTRSTSRC_RESET_TEST == src) { ++ pOp = wmt_lib_get_current_op(pDevWmt); ++ if (pOp && ((WMT_OPID_FUNC_ON == pOp->op.opId) ++ || (WMT_OPID_FUNC_OFF == pOp->op.opId))) { ++ WMT_INFO_FUNC("can't do reset by test src when func on/off\n"); ++ return -1; ++ } ++ } ++ /* <1> Consider the multi-context combo_rst case. */ ++ if (osal_test_and_set_bit(WMT_STAT_RST_ON, &pDevWmt->state)) { ++ retval = WMTRSTRET_ONGOING; ++ goto rstDone; ++ } ++ /* <2> Block all STP request */ ++ mtk_wcn_stp_enable(0); ++ ++ /* <3> RESET_START notification */ ++ bRet = wmt_cdev_rstmsg_snd(WMTRSTMSG_RESET_START); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); ++ retval = WMTRSTRET_FAIL; ++ goto rstDone; ++ } ++ /* wakeup blocked opid */ ++ pOp = wmt_lib_get_current_op(pDevWmt); ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, -1); ++ ++ /* wakeup blocked cmd */ ++ wmt_dev_rx_event_cb(); ++ ++ /* <4> retry until reset flow successful */ ++ while (retries > 0) { ++ /* <4.1> reset combo hw */ ++ bRet = wmt_lib_hw_rst(); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_hw_rst!\n"); ++ retries--; ++ continue; ++ } ++ /* <4.2> reset driver/combo sw */ ++ bRet = wmt_lib_sw_rst(1); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_sw_rst!\n"); ++ retries--; ++ continue; ++ } ++ break; ++ } ++ ++ osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state); ++ ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ rstMsg = WMTRSTMSG_RESET_END_FAIL; ++ WMT_WARN_FUNC("[whole chip reset] fail! retries = %d\n", RETRYTIMES - retries); ++ } else { ++ rstMsg = WMTRSTMSG_RESET_END; ++ WMT_INFO_FUNC("[whole chip reset] ok! retries = %d\n", RETRYTIMES - retries); ++ } ++ ++ /* <5> RESET_END notification */ ++ bRet = wmt_cdev_rstmsg_snd(rstMsg); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); ++ retval = WMTRSTRET_FAIL; ++ } else { ++ retval = WMTRSTMSG_RESET_END == rstMsg ? WMTRSTRET_SUCCESS : WMTRSTRET_FAIL; ++ } ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++rstDone: ++ if (osal_test_and_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state)) ++ WMT_WARN_FUNC("[whole chip reset] retval = %d\n", retval); ++ ++ return retval; ++} ++ ++MTK_WCN_BOOL wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++{ ++ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { ++ WMT_DBG_FUNC("reg ok!\n"); ++ pWmtDev->rFdrvCb.fDrvRst[eType] = pCb; ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else { ++ WMT_WARN_FUNC("reg fail!\n"); ++ } ++ ++ return bRet; ++} ++ ++MTK_WCN_BOOL wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { ++ WMT_DBG_FUNC("unreg ok!\n"); ++ pWmtDev->rFdrvCb.fDrvRst[eType] = NULL; ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else { ++ WMT_WARN_FUNC("unreg fail!\n"); ++ } ++ ++ return bRet; ++} ++ ++UINT32 wmt_lib_dbg_level_set(UINT32 level) ++{ ++ gWmtDbgLvl = level > WMT_LOG_LOUD ? WMT_LOG_LOUD : level; ++ return 0; ++} ++ ++INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value) ++{ ++ return mtk_wcn_stp_set_wmt_last_close(value); ++} ++ ++INT32 wmt_lib_notify_stp_sleep(void) ++{ ++ INT32 iRet = 0x0; ++ ++ iRet = wmt_lib_psm_lock_aquire(); ++ if (iRet) { ++ WMT_ERR_FUNC("--->lock psm_lock failed, iRet=%d\n", iRet); ++ return iRet; ++ } ++ ++ iRet = mtk_wcn_stp_notify_sleep_for_thermal(); ++ wmt_lib_psm_lock_release(); ++ ++ return iRet; ++} ++ ++VOID wmt_lib_set_patch_num(UINT32 num) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ pWmtDev->patchNum = num; ++} ++ ++VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (pPatchinfo) ++ pWmtDev->pWmtPatchInfo = pPatchinfo; ++ ++} ++ ++INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp) ++{ ++ if (pWmtDev) { ++ pWmtDev->pCurOP = pOp; ++ WMT_DBG_FUNC("pOp=0x%p\n", pOp); ++ return 0; ++ } ++ WMT_ERR_FUNC("Invalid pointer\n"); ++ return -1; ++} ++ ++P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev) ++{ ++ if (pWmtDev) ++ return pWmtDev->pCurOP; ++ ++ WMT_ERR_FUNC("Invalid pointer\n"); ++ return NULL; ++} ++ ++UINT8 *wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, UINT8 *buf, UINT32 len) ++{ ++ UINT8 *pAddr = NULL; ++ UINT32 sublen1 = 0; ++ UINT32 sublen2 = 0; ++ P_CONSYS_EMI_ADDR_INFO p_consys_info; ++ ++ p_consys_info = wmt_plat_get_emi_phy_add(); ++ osal_assert(p_consys_info); ++ ++ if (section == 0) { ++ pAddr = wmt_plat_get_emi_virt_add(0x0); ++ if (len > 1024) ++ len = 1024; ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); ++ osal_memcpy(&buf[0], pAddr, len); ++ } ++ } else { ++ if (offset >= 0x7fff) ++ offset = 0x0; ++ ++ if (offset + len > 32768) { ++ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get part1 EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("part1 vir addr(0x%p)\n", pAddr); ++ sublen1 = 0x7fff - offset; ++ osal_memcpy(&buf[0], pAddr, sublen1); ++ } ++ pAddr = wmt_plat_get_emi_virt_add(p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get part2 EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("part2 vir addr(0x%p)\n", pAddr); ++ sublen2 = len - sublen1; ++ osal_memcpy(&buf[sublen1], pAddr, sublen2); ++ } ++ } else { ++ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); ++ osal_memcpy(&buf[0], pAddr, len); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee) ++{ ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ ++ issue_type = STP_DBG_PROC_TEST; ++ ++ stp_dbg_poll_cpupcr(count, sleep, 1); ++ ++ if (toAee) { ++ stp_dbg_set_fw_info("STP ProcTest", osal_strlen("STP ProcTest"), issue_type); ++ osal_dbg_assert_aee("[SOC_CONSYS]ProcTest", ++ "**[WCN_ISSUE_INFO]STP Tx Timeout**\n Polling CPUPCR for FW debug usage\n"); ++ } else { ++ WMT_INFO_FUNC("wmt_lib:do not pass cpupcr to AEE\n"); ++ } ++ return 0; ++} ++ ++UINT8 *wmt_lib_get_cpupcr_xml_format(UINT32 *len) ++{ ++ PUINT8 temp; ++ UINT32 i = 0; ++ ++ osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE); ++ temp = g_cpupcr_buf; ++ stp_dbg_cpupcr_infor_format(&temp, len); ++ ++ pr_debug("print xml buffer,len(%d):\n\n", *len); ++ for (i = 0; i < *len; i++) ++ pr_cont("%c", g_cpupcr_buf[i]); ++ ++ return &g_cpupcr_buf[0]; ++} ++ ++UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en) ++{ ++ return stp_dbg_set_host_assert_info(type, reason, en); ++} ++ ++INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl) ++{ ++ wmt_plat_thermal_ctrl_cb_reg(thermal_ctrl); ++ return 0; ++} ++ ++INT8 wmt_lib_co_clock_get(void) ++{ ++ if (gDevWmt.rWmtGenConf.cfgExist) ++ return gDevWmt.rWmtGenConf.co_clock_flag; ++ else ++ return -1; ++} ++ ++#if CFG_WMT_PS_SUPPORT ++UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en) ++{ ++ WMT_WARN_FUNC("%s quick sleep mode\n", en ? "enable" : "disable"); ++ g_quick_sleep_ctrl = en; ++ return 0; ++} ++#endif ++ ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_lib_jtag_flag_set(UINT32 en) ++{ ++ return wmt_plat_jtag_flag_ctrl(en); ++} ++#endif ++ ++UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver) ++{ ++ return stp_dbg_set_wifiver(wifiver); ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h +new file mode 100644 +index 000000000000..b1b5285638f9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h +@@ -0,0 +1,252 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_EXP_H_ ++#define _STP_EXP_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_stp_exp.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++#define BT_TASK_INDX (0) ++#define FM_TASK_INDX (1) ++#define GPS_TASK_INDX (2) ++#define WIFI_TASK_INDX (3) ++#define WMT_TASK_INDX (4) ++#define STP_TASK_INDX (5) ++#define INFO_TASK_INDX (6) ++#define ANT_TASK_INDX (7) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define COEX_TASK_INDX (8) ++#define MTKSTP_MAX_TASK_NUM (9) ++#else ++#define MTKSTP_MAX_TASK_NUM (8) ++#endif ++ ++#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ ++ ++#define STP_EXP_HID_API_EXPORT 0 ++ ++#else ++ ++#define STP_EXP_HID_API_EXPORT 1 ++ ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++typedef void (*MTK_WCN_STP_EVENT_CB) (void); ++typedef INT32 (*MTK_WCN_STP_IF_TX) (const UINT8 *data, const UINT32 size, UINT32 *written_size); ++/* export for HIF driver */ ++typedef void (*MTK_WCN_STP_IF_RX) (const UINT8 *data, INT32 size); ++ ++typedef enum { ++ STP_UART_IF_TX = 0, ++ STP_SDIO_IF_TX = 1, ++ STP_BTIF_IF_TX = 2, ++ STP_MAX_IF_TX ++} ENUM_STP_TX_IF_TYPE; ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* Is STP ready? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:ready, FALSE:not ready ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++extern int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); ++ ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_tx_event_cb ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_tx_event_cb(int type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_event_cb ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_event_cb(int type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_tx ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_rx ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#else ++extern INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); ++extern INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++extern INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++extern MTK_WCN_BOOL _mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++extern MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void); ++extern INT32 _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); ++extern void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); ++extern INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++extern INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++extern INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++extern INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++extern INT32 _mtk_wcn_stp_coredump_start_get(VOID); ++ ++#endif ++ ++#endif /* _WMT_EXP_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h +new file mode 100644 +index 000000000000..6d10c3ff2659 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h +@@ -0,0 +1,19 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _MTKWMT_H_ ++#define _MTKWMT_H_ ++#include "wmt_core.h" ++ ++#endif /*_MTKWMT_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h +new file mode 100644 +index 000000000000..06238e07879f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h +@@ -0,0 +1,329 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_EXP_H_ ++#define _WMT_EXP_H_ ++ ++#include ++#include "osal.h" ++#include "wmt_plat.h" ++#include "wmt_stp_exp.h" ++/* not to reference to internal wmt */ ++/* #include "wmt_core.h" */ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++#ifndef DFT_TAG ++#define DFT_TAG "[WMT-DFT]" ++#endif ++ ++#define WMT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_LOUD) \ ++ osal_dbg_print(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_INFO) \ ++ osal_dbg_print(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_WARN) \ ++ osal_warn_print(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_ERR) \ ++ osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_DBG) \ ++ osal_dbg_print(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_TRC_FUNC(f) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_DBG) \ ++ osal_dbg_print(DFT_TAG "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++extern UINT32 gWmtDbgLvl; ++#endif ++extern OSAL_BIT_OP_VAR gBtWifiGpsState; ++extern OSAL_BIT_OP_VAR gGpsFmState; ++extern UINT32 gWifiProbed; ++extern MTK_WCN_BOOL g_pwr_off_flag; ++extern UINT32 g_IsNeedDoChipReset; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++#define WMT_LOG_LOUD 4 ++#define WMT_LOG_DBG 3 ++#define WMT_LOG_INFO 2 ++#define WMT_LOG_WARN 1 ++#define WMT_LOG_ERR 0 ++#endif ++#define CFG_CORE_INTERNAL_TXRX 0 /*just do TX/RX in host side */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_STP = 5, ++ WMTDRV_TYPE_LPBK = 6, ++ WMTDRV_TYPE_COREDUMP = 7, ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++/* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ ++/* TODO: how do we extend for new chip and newer revision? */ ++/* TODO: This way is hard to extend */ ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_E1 = 0x0, ++ WMTHWVER_E2 = 0x1, ++ WMTHWVER_E3 = 0x2, ++ WMTHWVER_E4 = 0x3, ++ WMTHWVER_E5 = 0x4, ++ WMTHWVER_E6 = 0x5, ++ WMTHWVER_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++ ++typedef enum _ENUM_WMTDSNS_TYPE_T { ++ WMTDSNS_FM_DISABLE = 0, ++ WMTDSNS_FM_ENABLE = 1, ++ WMTDSNS_FM_GPS_DISABLE = 2, ++ WMTDSNS_FM_GPS_ENABLE = 3, ++ WMTDSNS_MAX ++} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; ++ ++typedef enum _ENUM_WMTTHERM_TYPE_T { ++ WMTTHERM_ZERO = 0, ++ WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, ++ WMTTHERM_READ = WMTTHERM_ENABLE + 1, ++ WMTTHERM_DISABLE = WMTTHERM_READ + 1, ++ WMTTHERM_MAX ++} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ UINT32 /* Buffer size in unit of byte */ ++); ++ ++typedef enum _SDIO_PS_OP { ++ OWN_SET = 0, ++ OWN_CLR = 1, ++ OWN_STATE = 2, ++} SDIO_PS_OP; ++ ++typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); ++ ++typedef enum _ENUM_WMTCHIN_TYPE_T { ++ WMTCHIN_CHIPID = 0x0, ++ WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, ++ WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, ++ WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, ++ WMTCHIN_MAX, ++ ++} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; ++ ++#endif ++ ++typedef enum _ENUM_WMTRSTMSG_TYPE_T { ++ WMTRSTMSG_RESET_START = 0x0, ++ WMTRSTMSG_RESET_END = 0x1, ++ WMTRSTMSG_RESET_END_FAIL = 0x2, ++ WMTRSTMSG_RESET_MAX, ++ WMTRSTMSG_RESET_INVALID = 0xff ++} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; ++ ++typedef enum _ENUM_BT_GPS_ONOFF_STATE_T { ++ WMT_BT_ON = 0, ++ WMT_GPS_ON = 1, ++ WMT_WIFI_ON = 2, ++ WMT_FM_ON = 3, ++ WMT_BT_GPS_STATE_MAX, ++ WMT_BT_GPS_STATE_INVALID = 0xff ++} ENUM_BT_GPS_ONOFF_STATE_T, *P_ENUM_BT_GPS_ONOFF_STATE_T; ++ ++#if 1 /* moved from wmt_core.h */ ++typedef enum { ++ WMT_SDIO_SLOT_INVALID = 0, ++ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ ++ WMT_SDIO_SLOT_SDIO2 = 2, ++ WMT_SDIO_SLOT_MAX ++} WMT_SDIO_SLOT_NUM; ++ ++typedef enum { ++ WMT_SDIO_FUNC_STP = 0, ++ WMT_SDIO_FUNC_WIFI = 1, ++ WMT_SDIO_FUNC_MAX ++} WMT_SDIO_FUNC_TYPE; ++#endif ++ ++typedef INT32(*wmt_wlan_probe_cb) (VOID); ++typedef INT32(*wmt_wlan_remove_cb) (VOID); ++typedef INT32(*wmt_wlan_bus_cnt_get_cb) (VOID); ++typedef INT32(*wmt_wlan_bus_cnt_clr_cb) (VOID); ++ ++typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { ++ wmt_wlan_probe_cb wlan_probe_cb; ++ wmt_wlan_remove_cb wlan_remove_cb; ++ wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; ++ wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; ++} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++typedef enum _ENUM_WMT_ANT_RAM_CTRL_T { ++ WMT_ANT_RAM_GET_STATUS = 0, ++ WMT_ANT_RAM_DOWNLOAD = WMT_ANT_RAM_GET_STATUS + 1, ++ WMT_ANT_RAM_CTRL_MAX ++} ENUM_WMT_ANT_RAM_CTRL, *P_ENUM_WMT_ANT_RAM_CTRL; ++ ++typedef enum _ENUM_WMT_ANT_RAM_SEQ_T { ++ WMT_ANT_RAM_START_PKT = 1, ++ WMT_ANT_RAM_CONTINUE_PKT = WMT_ANT_RAM_START_PKT + 1, ++ WMT_ANT_RAM_END_PKT = WMT_ANT_RAM_CONTINUE_PKT + 1, ++ WMT_ANT_RAM_SEQ_MAX ++} ENUM_WMT_ANT_RAM_SEQ, *P_ENUM_WMT_ANT_RAM_SEQ; ++ ++typedef enum _ENUM_WMT_ANT_RAM_STATUS_T { ++ WMT_ANT_RAM_NOT_EXIST = 0, ++ WMT_ANT_RAM_EXIST = WMT_ANT_RAM_NOT_EXIST + 1, ++ WMT_ANT_RAM_DOWN_OK = WMT_ANT_RAM_EXIST + 1, ++ WMT_ANT_RAM_DOWN_FAIL = WMT_ANT_RAM_DOWN_OK + 1, ++ WMT_ANT_RAM_PARA_ERR = WMT_ANT_RAM_DOWN_FAIL + 1, ++ WMT_ANT_RAM_OP_ERR = WMT_ANT_RAM_PARA_ERR + 1, ++ WMT_ANT_RAM_MAX ++} ENUM_WMT_ANT_RAM_STATUS, *P_ENUM_WMT_ANT_RAM_STATUS; ++#endif ++ ++extern INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); ++extern INT32 mtk_wcn_wmt_wlan_unreg(VOID); ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern wmt_wlan_probe_cb mtk_wcn_wlan_probe; ++extern wmt_wlan_remove_cb mtk_wcn_wlan_remove; ++extern wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt; ++extern wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*subsystem function ctrl APIs*/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++#define WMT_EXP_HID_API_EXPORT 0 ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ ++extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); ++ ++extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); ++/* ++return value: ++enable/disable thermal sensor function: true(1)/false(0) ++read thermal sensor function: thermal value ++ ++*/ ++extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); ++ ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++ ++#else ++#define WMT_EXP_HID_API_EXPORT 1 ++#endif ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++extern ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, ++ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq); ++#endif ++extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ ++extern VOID wmt_lib_ps_irq_cb(VOID); ++ ++extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type); ++ ++extern INT32 mtk_wcn_wmt_system_state_reset(VOID); ++extern MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value); ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++extern VOID mtk_wcn_wmt_exp_init(VOID); ++extern VOID mtk_wcn_wmt_exp_deinit(VOID); ++#endif ++extern INT8 mtk_wcn_wmt_co_clock_flag_get(VOID); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_EXP_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h +new file mode 100644 +index 000000000000..075496cac54f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h +@@ -0,0 +1,295 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_PLAT_H_ ++#define _WMT_PLAT_H_ ++#include "osal_typedef.h" ++#include "stp_exp.h" ++#include ++ ++/* #include "mtk_wcn_consys_hw.h" */ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if 1 /* moved from wmt_exp.h */ ++#ifndef DFT_TAG ++#define DFT_TAG "[WMT-DFT]" ++#endif ++ ++#define WMT_PLAT_LOG_LOUD 4 ++#define WMT_PLAT_LOG_DBG 3 ++#define WMT_PLAT_LOG_INFO 2 ++#define WMT_PLAT_LOG_WARN 1 ++#define WMT_PLAT_LOG_ERR 0 ++ ++extern UINT32 wmtPlatLogLvl; ++ ++#define WMT_PLAT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_LOUD) \ ++ pr_debug(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_INFO) \ ++ pr_debug(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_WARN) \ ++ pr_warn(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_ERR) \ ++ pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_PLAT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_DBG) \ ++ pr_debug(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++ ++#endif ++ ++#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_exp.h */ ++ ++#define CFG_WMT_DUMP_INT_STATUS 0 ++#define CONSYS_ENALBE_SET_JTAG 1 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_FUNC_STATE_ { ++ FUNC_ON = 0, ++ FUNC_OFF = 1, ++ FUNC_RST = 2, ++ FUNC_STAT = 3, ++ FUNC_CTRL_MAX, ++} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE; ++ ++typedef enum _ENUM_PIN_ID_ { ++ PIN_BGF_EINT = 0, ++ PIN_I2S_GRP = 1, ++ PIN_GPS_SYNC = 2, ++ PIN_GPS_LNA = 3, ++#if CFG_WMT_LTE_COEX_HANDLING ++ PIN_TDM_REQ = 4, ++#endif ++ PIN_ID_MAX ++} ENUM_PIN_ID, *P_ENUM_PIN_ID; ++ ++typedef enum _ENUM_PIN_STATE_ { ++ PIN_STA_INIT = 0, ++ PIN_STA_OUT_L = 1, ++ PIN_STA_OUT_H = 2, ++ PIN_STA_IN_L = 3, ++ PIN_STA_MUX = 4, ++ PIN_STA_EINT_EN = 5, ++ PIN_STA_EINT_DIS = 6, ++ PIN_STA_DEINIT = 7, ++ PIN_STA_SHOW = 8, ++ PIN_STA_MAX ++} ENUM_PIN_STATE, *P_ENUM_PIN_STATE; ++ ++typedef enum _CMB_IF_TYPE_ { ++ CMB_IF_UART = 0, ++ CMB_IF_WIFI_SDIO = 1, ++ CMB_IF_BGF_SDIO = 2, ++ CMB_IF_BGWF_SDIO = 3, ++ CMB_IF_TYPE_MAX ++} CMB_IF_TYPE, *P_CMB_IF_TYPE; ++ ++typedef INT32(*fp_set_pin) (ENUM_PIN_STATE); ++ ++typedef enum _ENUM_WL_OP_ { ++ WL_OP_GET = 0, ++ WL_OP_PUT = 1, ++ WL_OP_MAX ++} ENUM_WL_OP, *P_ENUM_WL_OP; ++ ++typedef enum _ENUM_PALDO_TYPE_ { ++ BT_PALDO = 0, ++ WIFI_PALDO = 1, ++ FM_PALDO = 2, ++ GPS_PALDO = 3, ++ PMIC_CHIPID_PALDO = 4, ++ WIFI_5G_PALDO = 5, ++ PALDO_TYPE_MAX ++} ENUM_PALDO_TYPE, *P_ENUM_PALDO_TYPE; ++ ++typedef enum _ENUM_PALDO_OP_ { ++ PALDO_OFF = 0, ++ PALDO_ON = 1, ++ PALDO_OP_MAX ++} ENUM_PALDO_OP, *P_ENUM_PALDO_OP; ++ ++typedef enum _ENUM_HOST_DUMP_STATE_T { ++ STP_HOST_DUMP_NOT_START = 0, ++ STP_HOST_DUMP_GET = 1, ++ STP_HOST_DUMP_GET_DONE = 2, ++ STP_HOST_DUMP_END = 3, ++ STP_HOST_DUMP_MAX ++} ENUM_HOST_DUMP_STATE, *P_ENUM_HOST_DUMP_STATE_T; ++ ++typedef enum _ENUM_FORCE_TRG_ASSERT_T { ++ STP_FORCE_TRG_ASSERT_EMI = 0, ++ STP_FORCE_TRG_ASSERT_DEBUG_PIN = 1, ++ STP_FORCE_TRG_ASSERT_MAX = 2 ++} ENUM_FORCE_TRG_ASSERT_T, *P_ENUM_FORCE_TRG_ASSERT_T; ++ ++typedef enum _ENUM_CHIP_DUMP_STATE_T { ++ STP_CHIP_DUMP_NOT_START = 0, ++ STP_CHIP_DUMP_PUT = 1, ++ STP_CHIP_DUMP_PUT_DONE = 2, ++ STP_CHIP_DUMP_END = 3, ++ STP_CHIP_DUMP_MAX ++} ENUM_CHIP_DUMP_STATE, *P_ENUM_CHIP_DUMP_STATE_T; ++ ++typedef struct _EMI_CTRL_STATE_OFFSET_ { ++ UINT32 emi_apmem_ctrl_state; ++ UINT32 emi_apmem_ctrl_host_sync_state; ++ UINT32 emi_apmem_ctrl_host_sync_num; ++ UINT32 emi_apmem_ctrl_chip_sync_state; ++ UINT32 emi_apmem_ctrl_chip_sync_num; ++ UINT32 emi_apmem_ctrl_chip_sync_addr; ++ UINT32 emi_apmem_ctrl_chip_sync_len; ++ UINT32 emi_apmem_ctrl_chip_print_buff_start; ++ UINT32 emi_apmem_ctrl_chip_print_buff_len; ++ UINT32 emi_apmem_ctrl_chip_print_buff_idx; ++ UINT32 emi_apmem_ctrl_chip_int_status; ++ UINT32 emi_apmem_ctrl_chip_paded_dump_end; ++ UINT32 emi_apmem_ctrl_host_outband_assert_w1; ++ UINT32 emi_apmem_ctrl_chip_page_dump_num; ++} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET; ++ ++typedef struct _BGF_IRQ_BALANCE_ { ++ UINT32 counter; ++ unsigned long flags; ++ spinlock_t lock; ++} BGF_IRQ_BALANCE, *P_BGF_IRQ_BALANCE; ++ ++typedef struct _CONSYS_EMI_ADDR_INFO_ { ++ UINT32 emi_phy_addr; ++ UINT32 paged_trace_off; ++ UINT32 paged_dump_off; ++ UINT32 full_dump_off; ++ P_EMI_CTRL_STATE_OFFSET p_ecso; ++} CONSYS_EMI_ADDR_INFO, *P_CONSYS_EMI_ADDR_INFO; ++ ++typedef struct _GPIO_TDM_REQ_INFO_ { ++ UINT32 ant_sel_index; ++ UINT32 gpio_number; ++ UINT32 cr_address; ++} GPIO_TDM_REQ_INFO, *P_GPIO_TDM_REQ_INFO; ++ ++typedef VOID(*irq_cb) (VOID); ++typedef INT32(*device_audio_if_cb) (CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); ++typedef VOID(*func_ctrl_cb) (UINT32 on, UINT32 type); ++typedef long (*thermal_query_ctrl_cb) (VOID); ++typedef INT32(*deep_idle_ctrl_cb) (UINT32); ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern UINT32 gWmtDbgLvl; ++extern struct device *wmt_dev; ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++extern INT32 wmt_set_pmic_voltage(UINT32 level); ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 wmt_plat_init(UINT32 co_clock_type); ++ ++INT32 wmt_plat_deinit(VOID); ++ ++INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state); ++ ++INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); ++ ++INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); ++ ++INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId); ++ ++INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); ++ ++VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb); ++VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb); ++VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl); ++VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl); ++VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl); ++ ++INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo); ++UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset); ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en); ++#endif ++#if CFG_WMT_DUMP_INT_STATUS ++VOID wmt_plat_BGF_irq_dump_status(VOID); ++MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID); ++#endif ++P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID); ++UINT32 wmt_plat_read_cpupcr(VOID); ++UINT32 wmt_plat_read_dmaregs(UINT32); ++INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state); ++UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type); ++INT32 wmt_plat_update_host_sync_num(VOID); ++INT32 wmt_plat_get_dump_info(UINT32 offset); ++UINT32 wmt_plat_get_soc_chipid(VOID); ++INT32 wmt_plat_set_dbg_mode(UINT32 flag); ++VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf); ++#if CFG_WMT_LTE_COEX_HANDLING ++INT32 wmt_plat_get_tdm_antsel_index(VOID); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_PLAT_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile +new file mode 100644 +index 000000000000..905207118938 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile +@@ -0,0 +1,6 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++obj-y += pub/ ++obj-y += pri/ ++ ++endif +\ No newline at end of file +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h +new file mode 100644 +index 000000000000..95d1ab02a9fa +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef __BGW_DESENSE_H_ ++#define __BGW_DESENSE_H_ ++ ++#ifdef MSG ++#undef MSG ++#endif ++ ++#ifdef ERR ++#undef ERR ++#endif ++ ++#define PFX1 "[BWG] " ++#define MSG(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) ++#define ERR(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) ++ ++#ifdef NETLINK_TEST ++#undef NETLINK_TEST ++#endif ++ ++#define NETLINK_TEST 17 ++ ++#ifdef MAX_NL_MSG_LEN ++#undef MAX_NL_MSG_LEN ++#endif ++ ++#define MAX_NL_MSG_LEN 1024 ++ ++ ++#ifdef ON ++#undef ON ++#endif ++#ifdef OFF ++#undef OFF ++#endif ++#ifdef ACK ++#undef ACK ++#endif ++ ++#define ON 1 ++#define OFF 0 ++#define ACK 2 ++ ++/* ++used send command to native process ++ ++parameter: command could be macro ON: enable co-exist; OFF: disable co-exist; ++ACK: after get native process init message send ACK ++ ++*/ ++extern void send_command_to_daemon(const int command); ++ ++/* ++before use kernel socket, please call init socket first ++return value: 0: ok; -1: fail ++*/ ++extern int bgw_init_socket(void); ++ ++extern void bgw_destroy_netlink_kernel(void); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h +new file mode 100644 +index 000000000000..493a4dd16f23 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h +@@ -0,0 +1,348 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _OSAL_H_ ++#define _OSAL_H_ ++ ++#include ++#include ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define OS_BIT_OPS_SUPPORT 1 ++ ++#define _osal_inline_ inline ++ ++#define MAX_THREAD_NAME_LEN 16 ++#define MAX_WAKE_LOCK_NAME_LEN 16 ++#define OSAL_OP_BUF_SIZE 64 ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) ++#define OSAL_OP_DATA_SIZE 8 ++#else ++#define OSAL_OP_DATA_SIZE 32 ++#endif ++ ++#define DBG_LOG_STR_SIZE 256 ++ ++#define osal_sizeof(x) sizeof(x) ++ ++#define osal_array_size(x) (sizeof(x)/sizeof(x[0])) ++ ++#ifndef NAME_MAX ++#define NAME_MAX 256 ++#endif ++ ++#define WMT_OP_BIT(x) (0x1UL << x) ++#define WMT_OP_HIF_BIT WMT_OP_BIT(0) ++ ++#define RB_SIZE(prb) ((prb)->size) ++#define RB_MASK(prb) (RB_SIZE(prb) - 1) ++#define RB_COUNT(prb) ((prb)->write - (prb)->read) ++#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) ++#define RB_EMPTY(prb) ((prb)->write == (prb)->read) ++ ++#define RB_INIT(prb, qsize) \ ++do { \ ++ (prb)->read = (prb)->write = 0; \ ++ (prb)->size = (qsize); \ ++} while (0) ++ ++#define RB_PUT(prb, value) \ ++do { \ ++ if (!RB_FULL(prb)) { \ ++ (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \ ++ ++((prb)->write); \ ++ } \ ++ else { \ ++ osal_assert(!RB_FULL(prb)); \ ++ } \ ++} while (0) ++ ++#define RB_GET(prb, value) \ ++do { \ ++ if (!RB_EMPTY(prb)) { \ ++ value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \ ++ ++((prb)->read); \ ++ if (RB_EMPTY(prb)) { \ ++ (prb)->read = (prb)->write = 0; \ ++ } \ ++ } \ ++ else { \ ++ value = NULL; \ ++ osal_assert(!RB_EMPTY(prb)); \ ++ } \ ++} while (0) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef VOID(*P_TIMEOUT_HANDLER) (unsigned long); ++typedef INT32(*P_COND) (VOID *); ++ ++typedef struct _OSAL_TIMER_ { ++ struct timer_list timer; ++ P_TIMEOUT_HANDLER timeoutHandler; ++ unsigned long timeroutHandlerData; ++} OSAL_TIMER, *P_OSAL_TIMER; ++ ++typedef struct _OSAL_UNSLEEPABLE_LOCK_ { ++ spinlock_t lock; ++ unsigned long flag; ++} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; ++ ++typedef struct _OSAL_SLEEPABLE_LOCK_ { ++ struct mutex lock; ++} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; ++ ++typedef struct _OSAL_SIGNAL_ { ++ struct completion comp; ++ UINT32 timeoutValue; ++} OSAL_SIGNAL, *P_OSAL_SIGNAL; ++ ++typedef struct _OSAL_EVENT_ { ++ wait_queue_head_t waitQueue; ++/* VOID *pWaitQueueData; */ ++ UINT32 timeoutValue; ++ INT32 waitFlag; ++ ++} OSAL_EVENT, *P_OSAL_EVENT; ++ ++typedef struct _OSAL_THREAD_ { ++ struct task_struct *pThread; ++ VOID *pThreadFunc; ++ VOID *pThreadData; ++ char threadName[MAX_THREAD_NAME_LEN]; ++} OSAL_THREAD, *P_OSAL_THREAD; ++ ++typedef struct _OSAL_FIFO_ { ++ /*fifo definition */ ++ VOID *pFifoBody; ++ spinlock_t fifoSpinlock; ++ /*fifo operations */ ++ INT32 (*FifoInit)(struct _OSAL_FIFO_ *pFifo, UINT8 *buf, UINT32); ++ INT32 (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoReset)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoSz)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoLen)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const VOID *buf, UINT32 len); ++ INT32 (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, void *buf, UINT32 len); ++} OSAL_FIFO, *P_OSAL_FIFO; ++ ++typedef struct firmware osal_firmware; ++ ++typedef struct _OSAL_OP_DAT { ++ UINT32 opId; /* Event ID */ ++ UINT32 u4InfoBit; /* Reserved */ ++ SIZE_T au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */ ++} OSAL_OP_DAT, *P_OSAL_OP_DAT; ++ ++typedef struct _OSAL_LXOP_ { ++ OSAL_OP_DAT op; ++ OSAL_SIGNAL signal; ++ INT32 result; ++} OSAL_OP, *P_OSAL_OP; ++ ++typedef struct _OSAL_LXOP_Q { ++ OSAL_SLEEPABLE_LOCK sLock; ++ UINT32 write; ++ UINT32 read; ++ UINT32 size; ++ P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; ++} OSAL_OP_Q, *P_OSAL_OP_Q; ++ ++typedef struct _OSAL_WAKE_LOCK_ { ++ #ifdef CONFIG_PM_WAKELOCKS ++ struct wakeup_source wake_lock; ++ #else ++ struct wake_lock wake_lock; ++ #endif ++ UINT8 name[MAX_WAKE_LOCK_NAME_LEN]; ++} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK; ++#if 1 ++typedef struct _OSAL_BIT_OP_VAR_ { ++ unsigned long data; ++ OSAL_UNSLEEPABLE_LOCK opLock; ++} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; ++#else ++#define OSAL_BIT_OP_VAR unsigned long ++#define P_OSAL_BIT_OP_VAR unsigned long * ++ ++#endif ++typedef UINT32(*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread); ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern UINT32 osal_strlen(const char *str); ++extern INT32 osal_strcmp(const char *dst, const char *src); ++extern INT32 osal_strncmp(const char *dst, const char *src, UINT32 len); ++extern char *osal_strcpy(char *dst, const char *src); ++extern char *osal_strncpy(char *dst, const char *src, UINT32 len); ++extern char *osal_strcat(char *dst, const char *src); ++extern char *osal_strncat(char *dst, const char *src, UINT32 len); ++extern char *osal_strchr(const char *str, UINT8 c); ++extern char *osal_strsep(char **str, const char *c); ++extern int osal_strtol(const char *str, UINT32 adecimal, long *res); ++extern INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...); ++extern char *osal_strstr(char *str1, const char *str2); ++ ++extern INT32 osal_err_print(const char *str, ...); ++extern INT32 osal_dbg_print(const char *str, ...); ++extern INT32 osal_warn_print(const char *str, ...); ++ ++extern INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line); ++extern INT32 osal_sprintf(char *str, const char *format, ...); ++extern VOID *osal_malloc(UINT32 size); ++extern VOID osal_free(const VOID *dst); ++extern VOID *osal_memset(VOID *buf, INT32 i, UINT32 len); ++extern VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len); ++extern INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len); ++ ++extern INT32 osal_sleep_ms(UINT32 ms); ++extern INT32 osal_udelay(UINT32 us); ++extern INT32 osal_timer_create(P_OSAL_TIMER); ++extern INT32 osal_timer_start(P_OSAL_TIMER, UINT32); ++extern INT32 osal_timer_stop(P_OSAL_TIMER); ++extern INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer); ++extern INT32 osal_timer_modify(P_OSAL_TIMER, UINT32); ++extern INT32 osal_timer_delete(P_OSAL_TIMER); ++ ++extern INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size); ++extern VOID osal_fifo_deinit(P_OSAL_FIFO pFifo); ++extern INT32 osal_fifo_reset(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); ++extern UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); ++extern UINT32 osal_fifo_len(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo); ++ ++extern INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock); ++ ++#if defined(CONFIG_PROVE_LOCKING) ++#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); } ++#else ++extern INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK); ++#endif ++extern INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); ++extern INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); ++extern INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK); ++ ++#if defined(CONFIG_PROVE_LOCKING) ++#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); } ++#else ++extern INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK); ++#endif ++extern INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); ++extern INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); ++extern INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK); ++ ++extern INT32 osal_signal_init(P_OSAL_SIGNAL); ++extern INT32 osal_wait_for_signal(P_OSAL_SIGNAL); ++extern INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL); ++extern INT32 osal_raise_signal(P_OSAL_SIGNAL); ++extern INT32 osal_signal_deinit(P_OSAL_SIGNAL); ++ ++extern INT32 osal_event_init(P_OSAL_EVENT); ++extern INT32 osal_wait_for_event(P_OSAL_EVENT, P_COND, void *); ++extern INT32 osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, void *); ++extern INT32 osal_trigger_event(P_OSAL_EVENT); ++ ++extern INT32 osal_event_deinit(P_OSAL_EVENT); ++ ++extern INT32 osal_thread_create(P_OSAL_THREAD); ++extern INT32 osal_thread_run(P_OSAL_THREAD); ++extern INT32 osal_thread_should_stop(P_OSAL_THREAD); ++extern INT32 osal_thread_stop(P_OSAL_THREAD); ++/*extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ ++extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); ++/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ ++extern INT32 osal_thread_destroy(P_OSAL_THREAD); ++ ++extern INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++ ++extern INT32 osal_dbg_assert_aee(const char *module, const char *detail_description); ++extern INT32 osal_gettimeofday(PINT32 sec, PINT32 usec); ++extern INT32 osal_printtimeofday(const PUINT8 prefix); ++ ++extern VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, UINT32 len, UINT32 limit); ++ ++extern UINT32 osal_op_get_id(P_OSAL_OP pOp); ++extern MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); ++extern VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result); ++extern VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result); ++extern UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length); ++extern VOID osal_thread_show_stack(P_OSAL_THREAD pThread); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#define osal_assert(condition) \ ++do { \ ++ if (!(condition)) \ ++ osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition); \ ++} while (0) ++ ++#endif /* _OSAL_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h +new file mode 100644 +index 000000000000..b3a9c57e062d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h +@@ -0,0 +1,90 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _OSAL_TYPEDEF_H_ ++#define _OSAL_TYPEDEF_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_EARLYSUSPEND ++#include ++#else ++#include ++#endif ++#include ++#include ++#ifdef WMT_PLAT_ALPS ++#include ++#endif ++#include ++#ifdef CONFIG_PM_WAKELOCKS ++#include ++#else ++#include ++#endif ++#include ++ ++#ifndef _TYPEDEFS_H /*fix redifine */ ++typedef char INT8; ++#endif ++ ++typedef void VOID, *PVOID, **PPVOID; ++typedef char *PINT8, **PPINT8; ++typedef short INT16, *PINT16, **PPINT16; ++typedef int INT32, *PINT32, **PPINT32; ++typedef long long INT64, *PINT64, **PPINT64; ++ ++typedef unsigned char UINT8, *PUINT8, **PPUINT8; ++typedef unsigned short UINT16, *PUINT16, **PPUINT16; ++typedef unsigned int UINT32, *PUINT32, **PPUINT32; ++typedef unsigned long long UINT64, *PUINT64, **PPUINT64; ++ ++typedef size_t SIZE_T; ++ ++typedef int MTK_WCN_BOOL; ++#ifndef MTK_WCN_BOOL_TRUE ++#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) ++#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) ++#endif ++ ++#endif /*_OSAL_TYPEDEF_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h +new file mode 100644 +index 000000000000..17be778484c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h +@@ -0,0 +1,97 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_IDC_H_ ++#define _WMT_IDC_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_stp_exp.h" ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++#include "wmt_stp_exp.h" ++#include "conn_md_exp.h" ++ ++#define LTE_IDC_BUFFER_MAX_SIZE 1024 ++/*comment from firmware owner,max pckage num is 5,but should not happened*/ ++#define WMT_IDC_RX_MAX_LEN 384 ++#define LTE_MSG_ID_OFFSET 0x30 ++ ++typedef enum { ++ WMT_IDC_TX_OPCODE_MIN = 0, ++ WMT_IDC_TX_OPCODE_LTE_PARA = 0x0a, ++ WMT_IDC_TX_OPCODE_LTE_FREQ = 0x0b, ++ WMT_IDC_TX_OPCODE_WIFI_MAX_POWER = 0x0c, ++ WMT_IDC_TX_OPCODE_DEBUG_MONITOR = 0x0e, ++ WMT_IDC_TX_OPCODE_SPLIT_FILTER = 0x0f, ++ WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS = 0x16, ++ WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION = 0x17, ++ WMT_IDC_TX_OPCODE_LTE_INDICATION = 0x20, ++ WMT_IDC_TX_OPCODE_MAX ++} WMT_IDC_TX_OPCODE; ++ ++typedef enum { ++ WMT_IDC_RX_OPCODE_BTWF_DEF_PARA = 0x0, ++ WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN = 0x1, ++ /* WMT_IDC_RX_OPCODE_TDM_REQ = 0x10, */ ++ WMT_IDC_RX_OPCODE_DEBUG_MONITOR = 0x02, ++ WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE = 0x03, ++ WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND = 0x04, ++ WMT_IDC_RX_OPCODE_UART_PIN_SEL = 0x05, ++ WMT_IDC_RX_OPCODE_MAX ++} WMT_IDC_RX_OPCODE; ++ ++#if (CFG_WMT_LTE_ENABLE_MSGID_MAPPING == 0) ++typedef enum { ++ IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN, ++ IPC_L4C_MSG_ID_END, ++ IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN, ++ /* below are EL1 IPC messages sent from AP */ ++ IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND, ++ IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND, ++ IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND, ++ IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND, ++ IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND, ++ ++ /* below are EL1 messages sent to AP */ ++ IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, ++ IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, ++ IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, ++ IPC_MSG_ID_EL1_LTE_TX_IND, ++ IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND, ++ IPC_MSG_ID_EL1_PIN_TYPE_IND, ++ IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND, ++ IPC_MSG_ID_EL1_DUMMY13_IND, ++ IPC_MSG_ID_EL1_DUMMY14_IND, ++ IPC_MSG_ID_EL1_DUMMY15_IND, ++ IPC_EL1_MSG_ID_END, ++} IPC_MSG_ID_CODE; ++#endif ++ ++typedef struct _MTK_WCN_WMT_IDC_INFO_ { ++ ipc_ilm_t iit; ++ CONN_MD_BRIDGE_OPS ops; ++ UINT8 buffer[LTE_IDC_BUFFER_MAX_SIZE]; ++} MTK_WCN_WMT_IDC_INFO, *P_MTK_WCN_WMT_IDC_INFO; ++ ++extern INT32 wmt_idc_init(VOID); ++extern INT32 wmt_idc_deinit(VOID); ++extern INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm); ++extern INT32 wmt_idc_msg_to_lte_handing(VOID); ++extern UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len); ++ ++#endif /* endif CFG_WMT_LTE_COEX_HANDLING */ ++ ++#endif /* _WMT_IDC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile +new file mode 100644 +index 000000000000..ff0f0b0aefda +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile +@@ -0,0 +1,21 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../../linux/include \ ++ -I$(src)/../../linux/pri/include \ ++ -I$(src)/../../core/include \ ++ -I$(src)/../../include \ ++ -I$(src)/../include \ ++ -I$(src)/../../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ ++ -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach ++ ++ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 ++ ++obj-y += stp_btif.o \ ++ stp_dbg.o \ ++ stp_exp.o \ ++ wmt_dev.o \ ++ wmt_exp.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h +new file mode 100644 +index 000000000000..3730fbba6928 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h +@@ -0,0 +1,31 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _STP_BTIF_H_ ++#define _STP_BTIF_H_ ++ ++#include "osal_typedef.h" ++#include "mtk_btif_exp.h" ++ ++extern INT32 mtk_wcn_consys_stp_btif_open(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_close(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb); ++extern INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len); ++extern INT32 mtk_wcn_consys_stp_btif_wakeup(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); ++extern INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); ++extern INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag); ++extern MTK_WCN_BOOL mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h +new file mode 100644 +index 000000000000..de5684a16853 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h +@@ -0,0 +1,316 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _STP_DEBUG_H_ ++#define _STP_DEBUG_H_ ++ ++#include ++#include "osal.h" ++ ++#define CONFIG_LOG_STP_INTERNAL ++ ++#if 1 /* #ifndef CONFIG_LOG_STP_INTERNAL */ ++#define STP_PKT_SZ 16 ++#define STP_DMP_SZ 2048 ++#define STP_PKT_NO 2048 ++ ++#define STP_DBG_LOG_ENTRY_NUM 60 ++#define STP_DBG_LOG_ENTRY_SZ 64 ++ ++#else ++ ++#define STP_PKT_SZ 16 ++#define STP_DMP_SZ 16 ++#define STP_PKT_NO 16 ++ ++#define STP_DBG_LOG_ENTRY_NUM 28 ++#define STP_DBG_LOG_ENTRY_SZ 64 ++ ++#endif ++ ++typedef enum { ++ STP_DBG_EN = 0, ++ STP_DBG_PKT = 1, ++ STP_DBG_DR = 2, ++ STP_DBG_FW_ASSERT = 3, ++ STP_DBG_FW_LOG = 4, ++ STP_DBG_FW_DMP = 5, ++ STP_DBG_MAX ++} STP_DBG_OP_T; ++ ++typedef enum { ++ STP_DBG_PKT_FIL_ALL = 0, ++ STP_DBG_PKT_FIL_BT = 1, ++ STP_DBG_PKT_FIL_GPS = 2, ++ STP_DBG_PKT_FIL_FM = 3, ++ STP_DBG_PKT_FIL_WMT = 4, ++ STP_DBG_PKT_FIL_MAX ++} STP_DBG_PKT_FIL_T; ++ ++static char *const gStpDbgType[] = { ++ "< BT>", ++ "< FM>", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "" ++}; ++ ++typedef enum { ++ STP_DBG_DR_MAX = 0, ++} STP_DBG_DR_FIL_T; ++ ++typedef enum { ++ STP_DBG_FW_MAX = 0, ++} STP_DBG_FW_FIL_T; ++ ++typedef enum { ++ PKT_DIR_RX = 0, ++ PKT_DIR_TX ++} STP_DBG_PKT_DIR_T; ++ ++/*simple log system ++*/ ++ ++typedef struct { ++ /*type: 0. pkt trace 1. fw info ++ * 2. assert info 3. trace32 dump . ++ * -1. linked to the the previous ++ */ ++ int id; ++ int len; ++ char buffer[STP_DBG_LOG_ENTRY_SZ]; ++} MTKSTP_LOG_ENTRY_T; ++ ++typedef struct log_sys { ++ MTKSTP_LOG_ENTRY_T queue[STP_DBG_LOG_ENTRY_NUM]; ++ unsigned int size; ++ unsigned int in; ++ unsigned int out; ++ spinlock_t lock; ++} MTKSTP_LOG_SYS_T; ++/*--*/ ++ ++typedef struct stp_dbg_pkt_hdr { ++ /* packet information */ ++ unsigned int sec; ++ unsigned int usec; ++ unsigned int dbg_type; ++ unsigned int dmy; ++ unsigned int no; ++ unsigned int dir; ++ ++ /* packet content */ ++ unsigned int type; ++ unsigned int len; ++ unsigned int ack; ++ unsigned int seq; ++ unsigned int chs; ++ unsigned int crc; ++} STP_DBG_HDR_T; ++ ++typedef struct stp_dbg_pkt { ++ struct stp_dbg_pkt_hdr hdr; ++ unsigned char raw[STP_DMP_SZ]; ++} STP_PACKET_T; ++ ++typedef struct mtkstp_dbg_t { ++ /*log_sys */ ++ int pkt_trace_no; ++ void *btm; ++ int is_enable; ++ MTKSTP_LOG_SYS_T *logsys; ++} MTKSTP_DBG_T; ++ ++/* extern void aed_combo_exception(const int *, int, const int *, int, const char *); */ ++ ++#define STP_CORE_DUMP_TIMEOUT (5*60*1000) /* default 5minutes */ ++#define STP_OJB_NAME_SZ 20 ++#define STP_CORE_DUMP_INFO_SZ 500 ++#define STP_CORE_DUMP_INIT_SIZE 1 ++typedef enum wcn_compress_algorithm_t { ++ GZIP = 0, ++ BZIP2 = 1, ++ RAR = 2, ++ LMA = 3, ++ MAX ++} WCN_COMPRESS_ALG_T; ++ ++typedef INT32 (*COMPRESS_HANDLER) (void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, ++ INT32 finish); ++typedef struct wcn_compressor_t { ++ /* current object name */ ++ UINT8 name[STP_OJB_NAME_SZ + 1]; ++ ++ /* buffer for raw data, named L1 */ ++ PUINT8 L1_buf; ++ INT32 L1_buf_sz; ++ INT32 L1_pos; ++ ++ /* target buffer, named L2 */ ++ PUINT8 L2_buf; ++ INT32 L2_buf_sz; ++ INT32 L2_pos; ++ ++ /* compress state */ ++ UINT8 f_done; ++ UINT16 reserved; ++ UINT32 uncomp_size; ++ UINT32 crc32; ++ ++ /* compress algorithm */ ++ UINT8 f_compress_en; ++ WCN_COMPRESS_ALG_T compress_type; ++ void *worker; ++ COMPRESS_HANDLER handler; ++} WCN_COMPRESSOR_T, *P_WCN_COMPRESSOR_T; ++ ++P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz); ++INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T compressor); ++INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T compressor, PUINT8 buf, INT32 len, INT32 finish); ++INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T compressor, PUINT8 *pbuf, PINT32 len); ++INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T compressor, UINT8 enable, WCN_COMPRESS_ALG_T type); ++ ++typedef enum core_dump_state_t { ++ CORE_DUMP_INIT = 0, ++ CORE_DUMP_DOING, ++ CORE_DUMP_TIMEOUT, ++ CORE_DUMP_DONE, ++ CORE_DUMP_MAX ++} CORE_DUMP_STA; ++ ++typedef struct core_dump_t { ++ /* compress dump data and buffered */ ++ P_WCN_COMPRESSOR_T compressor; ++ ++ /* timer for monitor timeout */ ++ OSAL_TIMER dmp_timer; ++ UINT32 timeout; ++ ++ OSAL_SLEEPABLE_LOCK dmp_lock; ++ ++ /* state machine for core dump flow */ ++ CORE_DUMP_STA sm; ++ ++ /* dump info */ ++ INT8 info[STP_CORE_DUMP_INFO_SZ + 1]; ++} WCN_CORE_DUMP_T, *P_WCN_CORE_DUMP_T; ++ ++typedef enum _ENUM_STP_FW_ISSUE_TYPE_ { ++ STP_FW_ISSUE_TYPE_INVALID = 0x0, ++ STP_FW_ASSERT_ISSUE = 0x1, ++ STP_FW_NOACK_ISSUE = 0x2, ++ STP_FW_WARM_RST_ISSUE = 0x3, ++ STP_DBG_PROC_TEST = 0x4, ++ STP_HOST_TRIGGER_FW_ASSERT = 0x5, ++ STP_HOST_TRIGGER_ASSERT_TIMEOUT = 0x6, ++ STP_FW_ISSUE_TYPE_MAX ++} ENUM_STP_FW_ISSUE_TYPE, *P_ENUM_STP_FW_ISSUE_TYPE; ++ ++/* this was added for support dmareg's issue */ ++typedef enum _ENUM_DMA_ISSUE_TYPE_ { ++ CONNSYS_CLK_GATE_STATUS = 0x00, ++ CONSYS_EMI_STATUS, ++ SYSRAM1, ++ SYSRAM2, ++ SYSRAM3, ++ DMA_REGS_MAX ++} ENUM_DMA_ISSUE_TYPE; ++#define STP_PATCH_TIME_SIZE 12 ++#define STP_DBG_CPUPCR_NUM 512 ++#define STP_DBG_DMAREGS_NUM 16 ++#define STP_PATCH_BRANCH_SZIE 8 ++#define STP_ASSERT_INFO_SIZE 64 ++#define STP_DBG_ROM_VER_SIZE 4 ++#define STP_ASSERT_TYPE_SIZE 32 ++ ++typedef struct stp_dbg_host_assert_t { ++ UINT32 drv_type; ++ UINT32 reason; ++ UINT32 assert_from_host; ++} STP_DBG_HOST_ASSERT_T, *P_STP_DBG_HOST_ASSERT_T; ++ ++typedef struct stp_dbg_cpupcr_t { ++ UINT32 chipId; ++ UINT8 romVer[STP_DBG_ROM_VER_SIZE]; ++ UINT8 patchVer[STP_PATCH_TIME_SIZE]; ++ UINT8 branchVer[STP_PATCH_BRANCH_SZIE]; ++ UINT32 wifiVer; ++ UINT32 count; ++ UINT32 stop_flag; ++ UINT32 buffer[STP_DBG_CPUPCR_NUM]; ++ UINT8 assert_info[STP_ASSERT_INFO_SIZE]; ++ UINT32 fwTaskId; ++ UINT32 fwRrq; ++ UINT32 fwIsr; ++ STP_DBG_HOST_ASSERT_T host_assert_info; ++ UINT8 assert_type[STP_ASSERT_TYPE_SIZE]; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ OSAL_SLEEPABLE_LOCK lock; ++} STP_DBG_CPUPCR_T, *P_STP_DBG_CPUPCR_T; ++ ++typedef struct stp_dbg_dmaregs_t { ++ UINT32 count; ++ UINT32 dmaIssue[DMA_REGS_MAX][STP_DBG_DMAREGS_NUM]; ++ OSAL_SLEEPABLE_LOCK lock; ++} STP_DBG_DMAREGS_T, *P_STP_DBG_DMAREGS_T; ++ ++typedef enum _ENUM_ASSERT_INFO_PARSER_TYPE_ { ++ STP_DBG_ASSERT_INFO = 0x0, ++ STP_DBG_FW_TASK_ID = 0x1, ++ STP_DBG_FW_ISR = 0x2, ++ STP_DBG_FW_IRQ = 0x3, ++ STP_DBG_ASSERT_TYPE = 0x4, ++ STP_DBG_PARSER_TYPE_MAX ++} ENUM_ASSERT_INFO_PARSER_TYPE, *P_ENUM_ASSERT_INFO_PARSER_TYPE; ++ ++P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout); ++INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp); ++INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len); ++INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 len); ++INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout); ++INT32 wcn_core_dump_timeout(void); ++INT32 wcn_wmtd_timeout_collect_ftrace(void); ++ ++extern INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout); ++extern INT32 wcn_core_dump_deinit_gcoredump(VOID); ++extern INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL is_coredump_timeout); ++extern int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg); ++extern int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg); ++extern MTKSTP_DBG_T *stp_dbg_init(void *); ++extern int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg); ++extern int stp_dbg_dmp_out_ex(char *buf, int *len); ++extern int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len); ++extern int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg); ++extern char stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len); ++ ++extern INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd); ++extern INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len); ++extern int ++stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, ++ int dbg_type, int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body); ++extern int stp_dbg_log_ctrl(unsigned int on); ++extern INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); ++extern INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep); ++extern INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en); ++extern INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, ++ PUINT8 pPatchBrh); ++extern INT32 stp_dbg_set_wifiver(UINT32 wifiver); ++extern INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 len); ++extern INT32 stp_dbg_set_fw_info(PUINT8 assert_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type); ++extern INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en); ++extern UINT32 stp_dbg_get_host_trigger_assert(VOID); ++#endif /* end of _STP_DEBUG_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h +new file mode 100644 +index 000000000000..5788eb355549 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h +@@ -0,0 +1,71 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_DEV_H_ ++#define _WMT_DEV_H_ ++ ++#include "osal.h" ++ ++#define STP_UART_FULL 0x01 ++#define STP_UART_MAND 0x02 ++#define STP_BTIF_FULL 0x03 ++#define STP_SDIO 0x04 ++ ++#define CFG_WMT_DBG_SUPPORT 1 /* support wmt_dbg or not */ ++#define CFG_WMT_PROC_FOR_AEE 1 ++ ++extern VOID wmt_dev_rx_event_cb(VOID); ++extern INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent); ++extern INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf); ++extern INT32 wmt_dev_patch_put(osal_firmware **ppPatch); ++extern VOID wmt_dev_patch_info_free(VOID); ++extern VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd); ++extern MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID); ++ ++#if CFG_WMT_DBG_SUPPORT ++typedef struct _COEX_BUF { ++ UINT8 buffer[128]; ++ INT32 availSize; ++} COEX_BUF, *P_COEX_BUF; ++ ++typedef enum _ENUM_CMD_TYPE_T { ++ WMTDRV_CMD_ASSERT = 0, ++ WMTDRV_CMD_EXCEPTION = 1, ++ WMTDRV_CMD_COEXDBG_00 = 2, ++ WMTDRV_CMD_COEXDBG_01 = 3, ++ WMTDRV_CMD_COEXDBG_02 = 4, ++ WMTDRV_CMD_COEXDBG_03 = 5, ++ WMTDRV_CMD_COEXDBG_04 = 6, ++ WMTDRV_CMD_COEXDBG_05 = 7, ++ WMTDRV_CMD_COEXDBG_06 = 8, ++ WMTDRV_CMD_COEXDBG_07 = 9, ++ WMTDRV_CMD_COEXDBG_08 = 10, ++ WMTDRV_CMD_COEXDBG_09 = 11, ++ WMTDRV_CMD_COEXDBG_10 = 12, ++ WMTDRV_CMD_COEXDBG_11 = 13, ++ WMTDRV_CMD_COEXDBG_12 = 14, ++ WMTDRV_CMD_COEXDBG_13 = 15, ++ WMTDRV_CMD_COEXDBG_14 = 16, ++ WMTDRV_CMD_COEXDBG_15 = 17, ++ WMTDRV_CMD_NOACK_TEST = 18, ++ WMTDRV_CMD_WARNRST_TEST = 19, ++ WMTDRV_CMD_FWTRACE_TEST = 20, ++ WMTDRV_CMD_MAX ++} ENUM_WMTDRV_CMD_T, *P_ENUM_WMTDRV_CMD_T; ++ ++#endif ++ ++typedef INT32(*WMT_DEV_DBG_FUNC) (INT32 par1, INT32 par2, INT32 par3); ++ ++#endif /*_WMT_DEV_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c +new file mode 100644 +index 000000000000..76debb4674f9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c +@@ -0,0 +1,279 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*file: stp_btif, mainly control stp & btif interaction*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[STP-BTIF]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "wmt_exp.h" ++#include "stp_exp.h" ++#include "stp_btif.h" ++ ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BTIF_OWNER_NAME "CONSYS_STP" ++ ++#define STP_MAX_PACKAGE_ALLOWED (2000) ++ ++#define STP_BTIF_TX_RTY_LMT (10) ++#define STP_BTIF_TX_RTY_DLY (5) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++unsigned long stpBtifId = 0; ++unsigned long *pBtifRef = &stpBtifId; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 mtk_wcn_consys_stp_btif_open(VOID) ++{ ++ INT32 iRet = -1; ++ ++ iRet = mtk_wcn_btif_open(BTIF_OWNER_NAME, pBtifRef); ++ if (iRet) { ++ WMT_WARN_FUNC("STP open btif fail(%d)\n", iRet); ++ return -1; ++ } ++ WMT_DBG_FUNC("STP open bitf OK\n"); ++ ++ mtk_wcn_stp_register_if_tx(STP_BTIF_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_consys_stp_btif_tx); ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_close(VOID) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_close(stpBtifId); ++ if (iRet) { ++ WMT_WARN_FUNC("STP close btif fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ stpBtifId = 0; ++ WMT_DBG_FUNC("STP close btif OK\n"); ++ } ++ } ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference\n!"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_rx_cb_register(stpBtifId, rx_cb); ++ if (iRet) { ++ WMT_WARN_FUNC("STP register rxcb to btif fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("STP register rxcb to btif OK\n"); ++ } ++ } ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len) ++{ ++ INT32 retry_left = STP_BTIF_TX_RTY_LMT; ++ INT32 wr_count = 0; ++ INT32 written = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ return -1; ++ } ++ ++ if (len == 0) { ++ *written_len = 0; ++ WMT_INFO_FUNC("special case for STP-CORE,pbuf(%p)\n", pBuf); ++ return 0; ++ } ++ ++ *written_len = 0; ++ ++ if (len > STP_MAX_PACKAGE_ALLOWED) { ++ WMT_WARN_FUNC("abnormal pacage length,len(%d),pid[%d/%s]\n", len, current->pid, current->comm); ++ return -2; ++ } ++ wr_count = mtk_wcn_btif_write(stpBtifId, pBuf, len); ++ ++ if (wr_count < 0) { ++ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)\n", wr_count); ++ *written_len = 0; ++ return -3; ++ } ++ if (wr_count == len) { ++ /*perfect case */ ++ *written_len = wr_count; ++ return wr_count; ++ } ++ ++ while ((retry_left--) && (wr_count < len)) { ++ osal_sleep_ms(STP_BTIF_TX_RTY_DLY); ++ written = mtk_wcn_btif_write(stpBtifId, pBuf + wr_count, len - wr_count); ++ if (written < 0) { ++ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)when do recovered\n", written); ++ break; ++ } ++ wr_count += written; ++ } ++ ++ if (wr_count == len) { ++ WMT_INFO_FUNC("recovered,len(%d),retry_left(%d)\n", len, retry_left); ++ /*recovered case */ ++ *written_len = wr_count; ++ return wr_count; ++ } ++ ++ WMT_ERR_FUNC("stp btif write fail,len(%d),written(%d),retry_left(%d),pid[%d/%s]\n", ++ len, wr_count, retry_left, current->pid, current->comm); ++ *written_len = 0; ++ return -wr_count; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_rx(UINT8 *pBuf, UINT32 len) ++{ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_wakeup(VOID) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_wakeup_consys(stpBtifId); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif wakeup consys fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("STP btif wakeup consys ok\n"); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ mtk_wcn_btif_dpidle_ctrl(stpBtifId, en_flag); ++ WMT_DBG_FUNC("stp btif dpidle ctrl done,en_flag(%d)\n", en_flag); ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_loopback_ctrl(stpBtifId, mode); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif lpbk ctrl fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_INFO_FUNC("stp btif lpbk ctrl ok,mode(%d)\n", mode); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_dbg_ctrl(stpBtifId, flag); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif log dbg ctrl fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_INFO_FUNC("stp btif log dbg ctrl ok,flag(%d)\n", flag); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len) ++{ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ return -1; ++ } else { ++ return (INT32) mtk_wcn_btif_parser_wmt_evt(stpBtifId, str, len); ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c +new file mode 100644 +index 000000000000..fd8e9a97a0b8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c +@@ -0,0 +1,2060 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include /* GFP_KERNEL */ ++#include /* init_timer, add_time, del_timer_sync */ ++#include /* gettimeofday */ ++#include ++#include /* kzalloc */ ++#include /* task's status */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "osal_typedef.h" ++#include "stp_dbg.h" ++/* #include "stp_btm.h" */ ++#include "btm_core.h" ++#include "wmt_plat.h" ++ ++#define PFX_STP_DBG "[STPDbg]" ++#define STP_DBG_LOG_LOUD 4 ++#define STP_DBG_LOG_DBG 3 ++#define STP_DBG_LOG_INFO 2 ++#define STP_DBG_LOG_WARN 1 ++#define STP_DBG_LOG_ERR 0 ++ ++unsigned int gStpDbgDbgLevel = STP_DBG_LOG_INFO; ++unsigned int gStpDbgLogOut = 0; ++ ++#define STP_DBG_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \ ++ pr_warn(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \ ++ pr_err(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_TRC_FUNC(f) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ ++ pr_debug(PFX_STP_DBG "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++MTKSTP_DBG_T *g_stp_dbg = NULL; ++ ++#define STP_DBG_FAMILY_NAME "STP_DBG" ++#define MAX_BIND_PROCESS (4) ++#ifdef WMT_PLAT_ALPS ++#define STP_DBG_AEE_EXP_API (1) ++#else ++#define STP_DBG_AEE_EXP_API (0) ++#endif ++enum { ++ __STP_DBG_ATTR_INVALID, ++ STP_DBG_ATTR_MSG, ++ __STP_DBG_ATTR_MAX, ++}; ++#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1) ++ ++enum { ++ __STP_DBG_COMMAND_INVALID, ++ STP_DBG_COMMAND_BIND, ++ STP_DBG_COMMAND_RESET, ++ __STP_DBG_COMMAND_MAX, ++}; ++#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1) ++ ++static struct genl_family stp_dbg_gnl_family = { ++ .id = GENL_ID_GENERATE, ++ .hdrsize = 0, ++ .name = STP_DBG_FAMILY_NAME, ++ .version = 1, ++ .maxattr = STP_DBG_ATTR_MAX, ++}; ++ ++static void stp_dbg_nl_init(void); ++static void stp_dbg_nl_deinit(void); ++static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info); ++static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info); ++ ++/* attribute policy */ ++static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = { ++ [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING}, ++}; ++ ++/* operation definition */ ++#if 0 ++static struct genl_ops stp_dbg_gnl_ops_bind = { ++ .cmd = STP_DBG_COMMAND_BIND, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_bind, ++ .dumpit = NULL, ++}; ++ ++static struct genl_ops stp_dbg_gnl_ops_reset = { ++ .cmd = STP_DBG_COMMAND_RESET, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_reset, ++ .dumpit = NULL, ++}; ++#endif ++static struct genl_ops stp_dbg_gnl_ops_array[] = { ++ { ++ .cmd = STP_DBG_COMMAND_BIND, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_bind, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = STP_DBG_COMMAND_RESET, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_reset, ++ .dumpit = NULL, ++ }, ++}; ++ ++#if 0 ++#define E2S(x) #x ++static char *dmaRegsStr[] = { ++ E2S(CONNSYS_CLK_GATE_STATUS), ++ E2S(CONSYS_EMI_STATUS), ++ E2S(SYSRAM1), ++ E2S(SYSRAM2), ++ E2S(SYSRAM3) ++}; ++#endif ++static unsigned int stp_dbg_seqnum; ++static int num_bind_process; ++static pid_t bind_pid[MAX_BIND_PROCESS]; ++ ++static P_WCN_CORE_DUMP_T g_core_dump; ++ ++static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr; ++ ++/* just show in log at present */ ++static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs; ++ ++/* core_dump_timeout_handler - handler of coredump timeout ++ * @ data - core dump object's pointer ++ * ++ * No return value ++ */ ++static void core_dump_timeout_handler(unsigned long data) ++{ ++ P_WCN_CORE_DUMP_T dmp = (P_WCN_CORE_DUMP_T) data; ++ ++ STP_DBG_INFO_FUNC(" start\n"); ++ ++ stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm); ++ ++ STP_DBG_INFO_FUNC(" end\n"); ++ ++ if (dmp) ++ dmp->sm = CORE_DUMP_TIMEOUT; ++} ++ ++/* wcn_core_dump_init - create core dump sys ++ * @ timeout - core dump time out value ++ * ++ * Return object pointer if success, else NULL ++ */ ++P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout) ++{ ++#define KBYTES (1024*sizeof(char)) ++#define L1_BUF_SIZE (32*KBYTES) ++ ++ P_WCN_CORE_DUMP_T core_dmp = NULL; ++ ++ core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T)); ++ if (!core_dmp) { ++ STP_DBG_ERR_FUNC("alloc mem failed!\n"); ++ goto fail; ++ } ++ ++ osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T)); ++ ++ core_dmp->compressor = wcn_compressor_init("core_dump_compressor", L1_BUF_SIZE, 18*packet_num*KBYTES); ++ if (!core_dmp->compressor) { ++ STP_DBG_ERR_FUNC("create compressor failed!\n"); ++ goto fail; ++ } ++ wcn_compressor_reset(core_dmp->compressor, 1, GZIP); ++ ++ core_dmp->dmp_timer.timeoutHandler = core_dump_timeout_handler; ++ core_dmp->dmp_timer.timeroutHandlerData = (unsigned long)core_dmp; ++ osal_timer_create(&core_dmp->dmp_timer); ++ core_dmp->timeout = timeout; ++ ++ osal_sleepable_lock_init(&core_dmp->dmp_lock); ++ ++ core_dmp->sm = CORE_DUMP_INIT; ++ STP_DBG_INFO_FUNC("create coredump object OK!\n"); ++ ++ return core_dmp; ++ ++fail: ++ if (core_dmp && core_dmp->compressor) { ++ wcn_compressor_deinit(core_dmp->compressor); ++ core_dmp->compressor = NULL; ++ } ++ if (core_dmp) ++ osal_free(core_dmp); ++ ++ return NULL; ++} ++INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout) ++{ ++ INT32 Ret = 0; ++ ++ g_core_dump = wcn_core_dump_init(packet_num, timeout); ++ if (g_core_dump == NULL) ++ Ret = -1; ++ return Ret; ++} ++ ++/* wcn_core_dump_deinit - destroy core dump object ++ * @ dmp - pointer of object ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp) ++{ ++ if (dmp && dmp->compressor) { ++ wcn_compressor_deinit(dmp->compressor); ++ dmp->compressor = NULL; ++ } ++ ++ if (dmp) { ++ osal_sleepable_lock_deinit(&dmp->dmp_lock); ++ osal_timer_stop(&dmp->dmp_timer); ++ osal_free(dmp); ++ } ++ ++ return 0; ++} ++ ++INT32 wcn_core_dump_deinit_gcoredump(VOID) ++{ ++ wcn_core_dump_deinit(g_core_dump); ++ return 0; ++} ++ ++static INT32 wcn_core_dump_check_end(PUINT8 buf, INT32 len) ++{ ++ if (strnstr(buf, "coredump end", len)) ++ return 1; ++ else ++ return 0; ++} ++ ++/* wcn_core_dump_in - add a packet to compressor buffer ++ * @ dmp - pointer of object ++ * @ buf - input buffer ++ * @ len - data length ++ * ++ * Retunr 0 if success; return 1 if find end string; else error code ++ */ ++INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) ++{ ++ INT32 ret = 0; ++ INT32 tmp; ++ ++#define INFO_HEAD ";SOC_CONSYS FW CORE, " ++ ++ if ((!dmp) || (!buf)) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ ret = osal_lock_sleepable_lock(&dmp->dmp_lock); ++ if (ret) { ++ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ switch (dmp->sm) { ++ case CORE_DUMP_INIT: ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); ++ ++ /* first package, copy to info buffer */ ++ osal_strcpy(&dmp->info[0], INFO_HEAD); ++ ++ if (NULL == (strnstr(buf, "", 32))) { ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...", ++ osal_strlen("Fw warm reset exception...")); ++ dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] = '\0'; ++ } else { ++ char *pStr = buf; ++ char *pDtr = NULL; ++ ++ pDtr = osal_strchr(pStr, '-'); ++ if (NULL != pDtr) { ++ tmp = pDtr - pStr; ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); ++ dmp->info[osal_strlen(dmp->info) + 1] = '\0'; ++ } else { ++ tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD); ++ tmp = (len > tmp) ? tmp : len; ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); ++ dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0'; ++ } ++ ++ } ++ /* show coredump start info on UI */ ++ /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */ ++#if STP_DBG_AEE_EXP_API ++ aee_kernel_dal_show("SOC_CONSYS coredump start ....\n"); ++#endif ++ /* parsing data, and check end srting */ ++ ret = wcn_core_dump_check_end(buf, len); ++ if (ret == 1) { ++ STP_DBG_INFO_FUNC("core dump end!\n"); ++ dmp->sm = CORE_DUMP_DONE; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } else { ++ dmp->sm = CORE_DUMP_DOING; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } ++ break; ++ ++ case CORE_DUMP_DOING: ++ /* parsing data, and check end srting */ ++ ret = wcn_core_dump_check_end(buf, len); ++ if (ret == 1) { ++ STP_DBG_INFO_FUNC("core dump end!\n"); ++ dmp->sm = CORE_DUMP_DONE; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } else { ++ dmp->sm = CORE_DUMP_DOING; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } ++ break; ++ ++ case CORE_DUMP_DONE: ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ dmp->sm = CORE_DUMP_DOING; ++ break; ++ ++ case CORE_DUMP_TIMEOUT: ++ break; ++ default: ++ break; ++ } ++ ++ osal_unlock_sleepable_lock(&dmp->dmp_lock); ++ ++ return ret; ++} ++ ++/* wcn_core_dump_out - get compressed data from compressor buffer ++ * @ dmp - pointer of object ++ * @ pbuf - target buffer's pointer ++ * @ len - data length ++ * ++ * Retunr 0 if success; else error code ++ */ ++INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 plen) ++{ ++ INT32 ret = 0; ++ ++ if ((!dmp) || (!pbuf) || (!plen)) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ ret = osal_lock_sleepable_lock(&dmp->dmp_lock); ++ if (ret) { ++ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ ret = wcn_compressor_out(dmp->compressor, pbuf, plen); ++ ++ osal_unlock_sleepable_lock(&dmp->dmp_lock); ++ ++ return ret; ++} ++ ++/* wcn_core_dump_reset - reset core dump sys ++ * @ dmp - pointer of object ++ * @ timeout - core dump time out value ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout) ++{ ++ if (!dmp) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ dmp->sm = CORE_DUMP_INIT; ++ dmp->timeout = timeout; ++ osal_timer_stop(&dmp->dmp_timer); ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1); ++ ++ wcn_core_dump_deinit(dmp); ++ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); ++ ++ return 0; ++} ++ ++/* wcn_wmtd_timeout_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define WMTD_TIMEOUT_INFO_HEAD "Wait wmtd complation timeout ,just collect SYS_FTRACE to DB" ++INT32 wcn_wmtd_timeout_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Wait wmtd complation timeout"; ++ len = osal_strlen("Wait wmtd complation timeout"); ++ osal_strcpy(&g_core_dump->info[0], WMTD_TIMEOUT_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++/* wcn_psm_flag_trigger_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define PSM_ABNORMAL_FLAG_INFO_HEAD "Abnormal PSM flag be set ,just collect SYS_FTRACE to DB" ++INT32 wcn_psm_flag_trigger_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Abnormal PSM flag be set"; ++ len = osal_strlen("Abnormal PSM flag be set"); ++ osal_strcpy(&g_core_dump->info[0], PSM_ABNORMAL_FLAG_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++#if BTIF_RXD_BE_BLOCKED_DETECT ++MTK_WCN_BOOL is_btif_rxd_be_blocked(void) ++{ ++ MTK_WCN_BOOL flag = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_btif_rxd_be_blocked_flag_get()) ++ flag = MTK_WCN_BOOL_TRUE; ++ return flag; ++} ++/* wcn_btif_rxd_blocked_collect_ftrace - btif rxd be blocked,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define BTIF_RXD_BLOCKED_INFO_HEAD "Btif_rxd thread be blocked too long,just collect SYS_FTRACE to DB" ++INT32 wcn_btif_rxd_blocked_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Btif_rxd thread be blocked too long"; ++ len = osal_strlen("Btif_rxd thread be blocked too long"); ++ osal_strcpy(&g_core_dump->info[0], BTIF_RXD_BLOCKED_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++#endif ++/* wcn_core_dump_timeout - wait for FW assert info timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define TIMEOUT_INFO_HEAD "Trigger assert timeout ,just collect SYS_FTRACE to DB" ++INT32 wcn_core_dump_timeout(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Trigger assert timeout"; ++ len = osal_strlen("Trigger assert timeout"); ++ osal_strcpy(&g_core_dump->info[0], TIMEOUT_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++ ++#define ENABLE_F_TRACE 0 ++/* wcn_core_dump_flush - Fulsh dump data and reset core dump sys ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout) ++{ ++ PUINT8 pbuf = NULL; ++ INT32 len = 0; ++ ++ if (!g_core_dump) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ wcn_core_dump_out(g_core_dump, &pbuf, &len); ++ STP_DBG_INFO_FUNC("buf 0x%zx, len %d\n", (SIZE_T) pbuf, len); ++#ifdef WMT_PLAT_ALPS ++ /* show coredump end info on UI */ ++ /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */ ++#if STP_DBG_AEE_EXP_API ++ if (coredump_is_timeout) ++ aee_kernel_dal_show("++ SOC_CONSYS coredump tiemout ,pass received coredump to AEE ++\n"); ++ else ++ aee_kernel_dal_show("++ SOC_CONSYS coredump get successfully ++\n"); ++ /* call AEE driver API */ ++#if ENABLE_F_TRACE ++ aed_combo_exception_api(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info, DB_OPT_FTRACE); ++#else ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ ++#endif ++ ++#endif // WMT_PLAT_ALPS ++ ++ /* reset */ ++ wcn_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT); ++ ++ return 0; ++} ++ ++static INT32 wcn_gzip_compressor(void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, ++ INT32 finish) ++{ ++ INT32 ret = 0; ++ z_stream *stream = NULL; ++ INT32 tmp = *out_sz; ++ ++ STP_DBG_INFO_FUNC("need to compressor :buf 0x%zx, size %d\n", (SIZE_T) in_buf, in_sz); ++ STP_DBG_INFO_FUNC("before compressor,avalible buf: 0x%zx, size %d\n", (SIZE_T) out_buf, tmp); ++ ++ stream = (z_stream *) worker; ++ if (!stream) { ++ STP_DBG_ERR_FUNC("invalid workspace!\n"); ++ return -1; ++ } ++ ++ if (in_sz > 0) { ++#if 0 ++ ret = zlib_deflateReset(stream); ++ if (ret != Z_OK) { ++ STP_DBG_ERR_FUNC("reset failed!\n"); ++ return -2; ++ } ++#endif ++ ++ stream->next_in = in_buf; ++ stream->avail_in = in_sz; ++ stream->next_out = out_buf; ++ stream->avail_out = tmp; ++ ++ zlib_deflate(stream, Z_FULL_FLUSH); ++ ++ if (finish) { ++ while (1) { ++ int val = zlib_deflate(stream, Z_FINISH); ++ ++ if (val == Z_OK) ++ continue; ++ else if (val == Z_STREAM_END) ++ break; ++ STP_DBG_ERR_FUNC("finish operation failed %d\n", val); ++ return -3; ++ } ++ } ++ ++ *out_sz = tmp - stream->avail_out; ++ } ++ ++ STP_DBG_INFO_FUNC("after compressor,avalible buf: 0x%zx, compress rate %d -> %d\n", (SIZE_T) out_buf, in_sz, ++ *out_sz); ++ ++ return ret; ++} ++ ++/* wcn_compressor_init - create a compressor and do init ++ * @ name - compressor's name ++ * @ L1_buf_sz - L1 buffer size ++ * @ L2_buf_sz - L2 buffer size ++ * ++ * Retunr object's pointer if success, else NULL ++ */ ++P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz) ++{ ++ z_stream *pstream = NULL; ++ P_WCN_COMPRESSOR_T compress = NULL; ++ ++ compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T)); ++ if (!compress) { ++ STP_DBG_ERR_FUNC("alloc compressor failed!\n"); ++ goto fail; ++ } ++ ++ osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T)); ++ osal_memcpy(compress->name, name, STP_OJB_NAME_SZ); ++ ++ compress->f_compress_en = 0; ++ compress->compress_type = GZIP; ++ ++ if (compress->compress_type == GZIP) { ++ compress->worker = osal_malloc(sizeof(z_stream)); ++ if (!compress->worker) { ++ STP_DBG_ERR_FUNC("alloc stream failed!\n"); ++ goto fail; ++ } ++ pstream = (z_stream *) compress->worker; ++ ++ pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); ++ if (!pstream->workspace) { ++ STP_DBG_ERR_FUNC("alloc workspace failed!\n"); ++ goto fail; ++ } ++ zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, ++ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); ++ } ++ ++ compress->handler = wcn_gzip_compressor; ++ compress->L1_buf_sz = L1_buf_sz; ++ compress->L2_buf_sz = L2_buf_sz; ++ compress->L1_pos = 0; ++ compress->L2_pos = 0; ++ compress->uncomp_size = 0; ++ compress->crc32 = 0xffffffffUL; ++ ++ compress->L1_buf = osal_malloc(compress->L1_buf_sz); ++ if (!compress->L1_buf) { ++ STP_DBG_ERR_FUNC("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz); ++ goto fail; ++ } ++ ++ compress->L2_buf = osal_malloc(compress->L2_buf_sz); ++ if (!compress->L2_buf) { ++ STP_DBG_ERR_FUNC("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz); ++ goto fail; ++ } ++ ++ STP_DBG_INFO_FUNC("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz); ++ return compress; ++ ++fail: ++ if (compress) { ++ if (compress->L2_buf) { ++ osal_free(compress->L2_buf); ++ compress->L2_buf = NULL; ++ } ++ ++ if (compress->L1_buf) { ++ osal_free(compress->L1_buf); ++ compress->L1_buf = NULL; ++ } ++ ++ if (compress->worker) { ++ pstream = (z_stream *) compress->worker; ++ if ((compress->compress_type == GZIP) && pstream->workspace) { ++ zlib_deflateEnd(pstream); ++ osal_free(pstream->workspace); ++ } ++ osal_free(compress->worker); ++ compress->worker = NULL; ++ } ++ ++ if (compress->worker) { ++ osal_free(compress->worker); ++ compress->worker = NULL; ++ } ++ ++ osal_free(compress); ++ compress = NULL; ++ } ++ ++ STP_DBG_ERR_FUNC("init failed!\n"); ++ ++ return NULL; ++} ++ ++/* wcn_compressor_deinit - distroy a compressor ++ * @ cprs - compressor's pointer ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T cprs) ++{ ++ z_stream *pstream = NULL; ++ ++ if (cprs) { ++ if (cprs->L2_buf) { ++ osal_free(cprs->L2_buf); ++ cprs->L2_buf = NULL; ++ } ++ ++ if (cprs->L1_buf) { ++ osal_free(cprs->L1_buf); ++ cprs->L1_buf = NULL; ++ } ++ ++ if (cprs->worker) { ++ pstream = (z_stream *) cprs->worker; ++ if ((cprs->compress_type == GZIP) && pstream->workspace) { ++ zlib_deflateEnd(pstream); ++ osal_free(pstream->workspace); ++ } ++ osal_free(cprs->worker); ++ cprs->worker = NULL; ++ } ++ ++ cprs->handler = NULL; ++ ++ osal_free(cprs); ++ } ++ ++ STP_DBG_INFO_FUNC("destroy OK\n"); ++ ++ return 0; ++} ++ ++/* wcn_compressor_in - put in a raw data, and compress L1 buffer if need ++ * @ cprs - compressor's pointer ++ * @ buf - raw data buffer ++ * @ len - raw data length ++ * @ finish - core dump finish or not, 1: finished; 0: not finish ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, INT32 finish) ++{ ++ INT32 tmp_len = 0; ++ INT32 ret = 0; ++ ++ if (!cprs) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ ++ cprs->uncomp_size += len; ++ ++ /* check L1 buf valid space */ ++ if (len > (cprs->L1_buf_sz - cprs->L1_pos)) { ++ STP_DBG_INFO_FUNC("L1 buffer full\n"); ++ ++ if (cprs->f_compress_en && cprs->handler) { ++ /* need compress */ ++ /* compress L1 buffer, and put result to L2 buffer */ ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ ret = ++ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], ++ &tmp_len, finish); ++ if (!ret) { ++ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); ++ cprs->L2_pos += tmp_len; ++ if (cprs->L2_pos > cprs->L2_buf_sz) ++ STP_DBG_ERR_FUNC("coredump size too large(%d), L2 buf overflow\n", ++ cprs->L2_pos); ++ ++ if (finish) { ++ /* Add 8 byte suffix ++ === ++ 32 bits UNCOMPRESS SIZE ++ 32 bits CRC ++ */ ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; ++ cprs->L2_pos += 8; ++ } ++ STP_DBG_INFO_FUNC("compress OK!\n"); ++ } else ++ STP_DBG_ERR_FUNC("compress error!\n"); ++ } else { ++ /* no need compress */ ++ /* Flush L1 buffer to L2 buffer */ ++ STP_DBG_INFO_FUNC("No need do compress, Put to L2 buf\n"); ++ ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; ++ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); ++ cprs->L2_pos += tmp_len; ++ } ++ ++ /* reset L1 buf pos */ ++ cprs->L1_pos = 0; ++ ++ /* put curren data to L1 buf */ ++ if (len > cprs->L1_buf_sz) { ++ STP_DBG_ERR_FUNC("len=%d, too long err!\n", len); ++ } else { ++ STP_DBG_INFO_FUNC("L1 Flushed, and Put %d bytes to L1 buf\n", len); ++ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); ++ cprs->L1_pos += len; ++ } ++ } else { ++ /* put to L1 buffer */ ++ STP_DBG_INFO_FUNC("Put %d bytes to L1 buf\n", len); ++ ++ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); ++ cprs->L1_pos += len; ++ } ++ ++ return ret; ++} ++ ++/* wcn_compressor_out - get the result data from L2 buffer ++ * @ cprs - compressor's pointer ++ * @ pbuf - point to L2 buffer ++ * @ plen - out len ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T cprs, PUINT8 *pbuf, PINT32 plen) ++{ ++ INT32 ret = 0; ++ INT32 tmp_len = 0; ++ ++ if ((!cprs) || (!pbuf) || (!plen)) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ /* check if there's L1 data need flush to L2 buffer */ ++ if (cprs->L1_pos > 0) { ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ ++ if (cprs->f_compress_en && cprs->handler) { ++ /* need compress */ ++ ret = ++ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], ++ &tmp_len, 1); ++ ++ if (!ret) { ++ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); ++ cprs->L2_pos += tmp_len; ++ ++ /* Add 8 byte suffix ++ === ++ 32 bits UNCOMPRESS SIZE ++ 32 bits CRC ++ */ ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; ++ cprs->L2_pos += 8; ++ ++ STP_DBG_INFO_FUNC("compress OK!\n"); ++ } else { ++ STP_DBG_ERR_FUNC("compress error!\n"); ++ } ++ } else { ++ /* no need compress */ ++ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; ++ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); ++ cprs->L2_pos += tmp_len; ++ } ++ ++ cprs->L1_pos = 0; ++ } ++ ++ *pbuf = cprs->L2_buf; ++ *plen = cprs->L2_pos; ++ ++ STP_DBG_INFO_FUNC("0x%zx, len %d\n", (SIZE_T)*pbuf, *plen); ++ ++ return 0; ++} ++ ++/* wcn_compressor_reset - reset compressor ++ * @ cprs - compressor's pointer ++ * @ enable - enable/disable compress ++ * @ type - compress algorithm ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type) ++{ ++ if (!cprs) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ ++ cprs->f_compress_en = enable; ++ /* cprs->f_compress_en = 0; // disable compress for test */ ++ cprs->compress_type = type; ++ cprs->L1_pos = 0; ++ cprs->L2_pos = 0; ++ cprs->uncomp_size = 0; ++ cprs->crc32 = 0xffffffffUL; ++ ++ /* zlib_deflateEnd((z_stream*)cprs->worker); */ ++ ++ STP_DBG_INFO_FUNC("OK! compress algorithm %d\n", type); ++ ++ return 0; ++} ++ ++static void stp_dbg_dump_data(unsigned char *pBuf, char *title, int len) ++{ ++ int k = 0; ++ ++ pr_debug(" %s-len:%d\n", title, len); ++ ++ for (k = 0; k < len; k++) { ++ if (k % 16 == 0 && k != 0) ++ pr_cont("\n "); ++ pr_cont("0x%02x ", pBuf[k]); ++ } ++ pr_debug("--end\n"); ++} ++ ++static int _stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ stp_dbg->pkt_trace_no = 0; ++ stp_dbg->is_enable = 1; ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++static int _stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ stp_dbg->pkt_trace_no = 0; ++ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); ++ stp_dbg->is_enable = 0; ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++static int _stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) ++{ ++ unsigned long flags; ++ STP_DBG_HDR_T *pHdr = NULL; ++ char *pBuf = NULL; ++ unsigned int length = 0; ++ unsigned int internalFlag = stp_dbg->logsys->size < STP_DBG_LOG_ENTRY_NUM; ++ /* #ifdef CONFIG_LOG_STP_INTERNAL */ ++ /* Here we record log in this circle buffer, if buffer is full , ++ select to overlap earlier log, logic should be okay */ ++ internalFlag = 1; ++ /* #endif */ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ ++ if (internalFlag) { ++ stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0; ++ stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len; ++ memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), ++ 0, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); ++ memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), ++ buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); ++ ++ stp_dbg->logsys->size++; ++ stp_dbg->logsys->size = ++ (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ? STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size; ++ ++ if (0 != gStpDbgLogOut) { ++ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]); ++ pBuf = (char *)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) + sizeof(STP_DBG_HDR_T); ++ length = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T); ++ pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", ++ pHdr->sec, ++ pHdr->usec, ++ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", ++ gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); ++ if (0 < length) ++ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", length); ++ } ++ stp_dbg->logsys->in = ++ (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1); ++ STP_DBG_DBG_FUNC("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in); ++ } else { ++ STP_DBG_WARN_FUNC("logsys FULL!\n"); ++ } ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++int stp_gdb_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg) ++{ ++ int retval = 0; ++/* #ifndef CONFIG_LOG_STP_INTERNAL */ ++ ++ if (stp_dbg->btm != NULL) ++ retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm); ++/* #endif */ ++ ++ return retval; ++} ++ ++int stp_dbg_log_ctrl(unsigned int on) ++{ ++ if (on != 0) { ++ gStpDbgLogOut = 1; ++ pr_debug("STP-DBG: enable pkt log dump out.\n"); ++ } else { ++ gStpDbgLogOut = 0; ++ pr_debug("STP-DBG: disable pkt log dump out.\n"); ++ } ++ return 0; ++} ++ ++int stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) ++{ ++ return _stp_dbg_dmp_in(stp_dbg, buf, len); ++} ++ ++int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg) ++{ ++#define MAX_DMP_NUM 80 ++ unsigned long flags; ++ char *pBuf = NULL; ++ int len = 0; ++ STP_DBG_HDR_T *pHdr = NULL; ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ /* Not to dequeue from loging system */ ++ inIndex = stp_dbg->logsys->in; ++ dumpSize = stp_dbg->logsys->size; ++ if (STP_DBG_LOG_ENTRY_NUM == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM; ++ ++ if (dumpSize > MAX_DMP_NUM) { ++ ++ outIndex += (dumpSize - MAX_DMP_NUM); ++ outIndex %= STP_DBG_LOG_ENTRY_NUM; ++ dumpSize = MAX_DMP_NUM; ++ ++ } ++ STP_DBG_INFO_FUNC("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[outIndex].buffer[0]); ++ pBuf = &(stp_dbg->logsys->queue[outIndex].buffer[0]) + sizeof(STP_DBG_HDR_T); ++ len = stp_dbg->logsys->queue[outIndex].len - sizeof(STP_DBG_HDR_T); ++ len = len > STP_PKT_SZ ? STP_PKT_SZ : len; ++ pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", ++ pHdr->sec, ++ pHdr->usec, ++ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", ++ gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); ++ ++ if (0 < len) ++ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len); ++ outIndex = (outIndex >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++int stp_dbg_dmp_out_ex(char *buf, int *len) ++{ ++ return stp_dbg_dmp_out(g_stp_dbg, buf, len); ++} ++ ++int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len) ++{ ++ ++ unsigned long flags; ++ int remaining = 0; ++ *len = 0; ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ ++ if (stp_dbg->logsys->size > 0) { ++ memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]), ++ stp_dbg->logsys->queue[stp_dbg->logsys->out].len); ++ ++ (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len; ++ stp_dbg->logsys->out = ++ (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->out + 1); ++ stp_dbg->logsys->size--; ++ ++ STP_DBG_DBG_FUNC("logsys size = %d, out = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->out); ++ } else { ++ STP_DBG_LOUD_FUNC("logsys EMPTY!\n"); ++ } ++ ++ remaining = (stp_dbg->logsys->size == 0) ? (0) : (1); ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return remaining; ++} ++ ++static int stp_dbg_fill_hdr(struct stp_dbg_pkt_hdr *hdr, int type, int ack, int seq, int crc, int dir, int len, ++ int dbg_type) ++{ ++ ++ struct timeval now; ++ ++ if (!hdr) { ++ STP_DBG_ERR_FUNC("function invalid\n"); ++ return -EINVAL; ++ } ++ do_gettimeofday(&now); ++ hdr->dbg_type = dbg_type; ++ hdr->ack = ack; ++ hdr->seq = seq; ++ hdr->sec = now.tv_sec; ++ hdr->usec = now.tv_usec; ++ hdr->crc = crc; ++ hdr->dir = dir; /* rx */ ++ hdr->dmy = 0xffffffff; ++ hdr->len = len; ++ hdr->type = type; ++ return 0; ++ ++} ++ ++static int stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, struct stp_dbg_pkt_hdr *hdr, const unsigned char *body) ++{ ++ /* fix the frame size large issues. */ ++ static struct stp_dbg_pkt stp_pkt; ++ uint32_t hdr_sz = sizeof(struct stp_dbg_pkt_hdr); ++ uint32_t body_sz = 0; ++ ++ BUG_ON(!stp_dbg); ++ ++ if (hdr->dbg_type == STP_DBG_PKT) ++ body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ); ++ else ++ body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ); ++ ++ hdr->no = stp_dbg->pkt_trace_no++; ++ memcpy((uint8_t *) &stp_pkt.hdr, (uint8_t *) hdr, hdr_sz); ++ if (body != NULL) ++ memcpy((uint8_t *) &stp_pkt.raw[0], body, body_sz); ++ ++ _stp_dbg_dmp_in(stp_dbg, (char *)&stp_pkt, hdr_sz + body_sz); ++ /* Only FW DMP MSG should inform BTM-CORE to dump packet to native process */ ++ if (hdr->dbg_type == STP_DBG_FW_DMP) ++ stp_gdb_notify_btm_dmp_wq(stp_dbg); ++ ++ return 0; ++} ++ ++int stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, int dbg_type, ++ int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body) ++{ ++ ++ struct stp_dbg_pkt_hdr hdr; ++ ++ if (stp_dbg->is_enable == 0) { ++ /*dbg is disable,and not to log */ ++ } else { ++ hdr.no = 0; ++ hdr.chs = 0; ++ stp_dbg_fill_hdr(&hdr, ++ (int)type, (int)ack_no, (int)seq_no, (int)crc, (int)dir, (int)len, (int)dbg_type); ++ ++ stp_dbg_add_pkt(stp_dbg, &hdr, body); ++ } ++ ++ return 0; ++} ++ ++int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) ++{ ++ return _stp_dbg_enable(stp_dbg); ++} ++ ++int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) ++{ ++ return _stp_dbg_disable(stp_dbg); ++} ++ ++static void stp_dbg_nl_init(void) ++{ ++#if 0 ++ if (genl_register_family(&stp_dbg_gnl_family) != 0) { ++ STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); ++ } else { ++ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0) ++ STP_DBG_ERR_FUNC("%s(): BIND operation registration fail\n", __func__); ++ ++ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0) ++ STP_DBG_ERR_FUNC("%s(): RESET operation registration fail\n", __func__); ++ ++ } ++#endif ++ if (genl_register_family_with_ops(&stp_dbg_gnl_family, stp_dbg_gnl_ops_array) != 0) ++ STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); ++} ++ ++static void stp_dbg_nl_deinit(void) ++{ ++ genl_unregister_family(&stp_dbg_gnl_family); ++} ++ ++static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct nlattr *na; ++ char *mydata; ++ ++ if (info == NULL) ++ goto out; ++ ++ STP_DBG_INFO_FUNC("%s():->\n", __func__); ++ ++ na = info->attrs[STP_DBG_ATTR_MSG]; ++ ++ if (na) ++ mydata = (char *)nla_data(na); ++ ++ if (num_bind_process < MAX_BIND_PROCESS) { ++ bind_pid[num_bind_process] = info->snd_portid; ++ num_bind_process++; ++ STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_portid); ++ } else { ++ STP_DBG_ERR_FUNC("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS); ++ } ++ ++out: ++ return 0; ++} ++ ++static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info) ++{ ++ STP_DBG_ERR_FUNC("%s(): should not be invoked\n", __func__); ++ ++ return 0; ++} ++ ++INT8 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len) ++{ ++ struct sk_buff *skb = NULL; ++ void *msg_head = NULL; ++ int rc = -1; ++ int i; ++ ++ if (num_bind_process == 0) { ++ /* no listening process */ ++ STP_DBG_ERR_FUNC("%s(): the process is not invoked\n", __func__); ++ return 0; ++ } ++ ++ for (i = 0; i < num_bind_process; i++) { ++ skb = genlmsg_new(2048, GFP_KERNEL); ++ ++ if (skb) { ++ msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd); ++ if (msg_head == NULL) { ++ nlmsg_free(skb); ++ STP_DBG_ERR_FUNC("%s(): genlmsg_put fail...\n", __func__); ++ return -1; ++ } ++ ++ rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg); ++ if (rc != 0) { ++ nlmsg_free(skb); ++ STP_DBG_ERR_FUNC("%s(): nla_put_string fail...%d\n", __func__, rc); ++ return -1; ++ } ++ ++ /* finalize the message */ ++ genlmsg_end(skb, msg_head); ++ ++ /* sending message */ ++ rc = genlmsg_unicast(&init_net, skb, bind_pid[i]); ++ if (rc != 0) { ++ STP_DBG_ERR_FUNC("%s(): genlmsg_unicast fail...\n", __func__); ++ return -1; ++ } ++ } else { ++ STP_DBG_ERR_FUNC("%s(): genlmsg_new fail...\n", __func__); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd) ++{ ++ INT32 ret = 0; ++ ++ /* buffered to compressor */ ++ ret = wcn_core_dump_in(g_core_dump, aucMsg, len); ++ if (ret == 1) ++ wcn_core_dump_flush(0, MTK_WCN_BOOL_FALSE); ++ ++ return ret; ++} ++ ++UINT8 *_stp_dbg_id_to_task(UINT32 id) ++{ ++ UINT8 *taskStr[] = { ++ "Task_WMT", ++ "Task_BT", ++ "Task_Wifi", ++ "Task_Tst", ++ "Task_FM", ++ "Task_Idle", ++ "Task_DrvStp", ++ "Task_DrvBtif", ++ "Task_NatBt" ++ }; ++ return taskStr[id]; ++} ++ ++INT32 _stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type) ++{ ++ char *pStr = NULL; ++ char *pDtr = NULL; ++ char *pTemp = NULL; ++ char *pTemp2 = NULL; ++ char tempBuf[64] = { 0 }; ++ UINT32 len = 0; ++ long res; ++ INT32 ret; ++ ++ PUINT8 parser_sub_string[] = { ++ " ", ++ "id=", ++ "isr=", ++ "irq=", ++ "rc=" ++ }; ++ ++ if (!str) { ++ STP_DBG_ERR_FUNC("NULL string source\n"); ++ return -1; ++ } ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -2; ++ } ++ ++ pStr = str; ++ STP_DBG_DBG_FUNC("source infor:%s\n", pStr); ++ switch (type) { ++ case STP_DBG_ASSERT_INFO: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ' '); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@")); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len); ++ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_'; ++ ++ pTemp = osal_strchr(pDtr, '#'); ++ pTemp += 1; ++ ++ pTemp2 = osal_strchr(pTemp, ' '); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp, pTemp2 - pTemp); ++ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0'; ++ STP_DBG_INFO_FUNC("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]); ++ break; ++ case STP_DBG_FW_TASK_ID: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ' '); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw task id :%x\n", (UINT32)res); ++ break; ++ case STP_DBG_FW_ISR: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw isr id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwIsr = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw isr str:%x\n", (UINT32)res); ++ break; ++ case STP_DBG_FW_IRQ: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw irq id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwRrq = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw irq value:%x\n", (UINT32)res); ++ break; ++ case STP_DBG_ASSERT_TYPE: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ++ if (0 == osal_memcmp(tempBuf, "*", len)) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert", osal_strlen("general assert")); ++ if (0 == osal_memcmp(tempBuf, "Watch Dog Timeout", len)) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt")); ++ if (0 == osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL"))) { ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len); ++ ++ pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL("); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen("RB_FULL("); ++ pTemp = osal_strchr(pDtr, ')'); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(RB_FULL()\n"); ++ return -4; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); ++ return -5; ++ } ++ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("update fw task id :%x\n", (UINT32)res); ++ } ++ ++ STP_DBG_INFO_FUNC("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type); ++ break; ++ default: ++ STP_DBG_ERR_FUNC("unknown parser type\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID) ++{ ++ P_STP_DBG_CPUPCR_T pSdCpupcr = NULL; ++ ++ pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T)); ++ if (!pSdCpupcr) { ++ STP_DBG_ERR_FUNC("stp dbg cpupcr allocate memory fail!\n"); ++ return NULL; ++ } ++ ++ osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T)); ++ ++ osal_sleepable_lock_init(&pSdCpupcr->lock); ++ ++ return pSdCpupcr; ++} ++ ++P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID) ++{ ++ P_STP_DBG_DMAREGS_T pDmaRegs = NULL; ++ ++ pDmaRegs = (P_STP_DBG_DMAREGS_T) osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T)); ++ if (!pDmaRegs) { ++ STP_DBG_ERR_FUNC("stp dbg dmareg allocate memory fail!\n"); ++ return NULL; ++ } ++ ++ osal_memset(pDmaRegs, 0, osal_sizeof(STP_DBG_DMAREGS_T)); ++ ++ osal_sleepable_lock_init(&pDmaRegs->lock); ++ ++ return pDmaRegs; ++} ++ ++VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr) ++{ ++ if (pCpupcr) { ++ osal_sleepable_lock_deinit(&pCpupcr->lock); ++ osal_free(pCpupcr); ++ pCpupcr = NULL; ++ } ++} ++ ++VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs) ++{ ++ if (pDmaRegs) { ++ osal_sleepable_lock_deinit(&pDmaRegs->lock); ++ osal_free(pDmaRegs); ++ pDmaRegs = NULL; ++ } ++} ++ ++INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd) ++{ ++ INT32 i = 0; ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL reference pointer\n"); ++ return -1; ++ } ++ ++ if (!cmd) { ++ if (g_stp_dbg_cpupcr->count + times > STP_DBG_CPUPCR_NUM) ++ times = STP_DBG_CPUPCR_NUM - g_stp_dbg_cpupcr->count; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ for (i = 0; i < times; i++) { ++ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); ++ /* osal_memcpy( ++ * &g_stp_dbg_cpupcr->buffer[i], ++ * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), ++ * osal_sizeof(UINT32)); ++ */ ++ g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count + i] = wmt_plat_read_cpupcr(); ++ osal_sleep_ms(sleep); ++ } ++ g_stp_dbg_cpupcr->count += times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_INFO_FUNC("stp-dbg: for proc test polling cpupcr\n"); ++ if (times > STP_DBG_CPUPCR_NUM) ++ times = STP_DBG_CPUPCR_NUM; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->count = 0; ++ for (i = 0; i < times; i++) { ++ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); ++ /* osal_memcpy( ++ * &g_stp_dbg_cpupcr->buffer[i], ++ * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), ++ * osal_sizeof(UINT32)); ++ */ ++ g_stp_dbg_cpupcr->buffer[i] = wmt_plat_read_cpupcr(); ++ osal_sleep_ms(sleep); ++ } ++ g_stp_dbg_cpupcr->count = times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ } ++ return 0; ++} ++ ++INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep) ++{ ++#if 0 ++ INT32 i = 0; ++ ++ if (!g_stp_dbg_dmaregs) { ++ STP_DBG_ERR_FUNC("NULL reference pointer\n"); ++ return -1; ++ } ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock); ++ ++ if (g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM) { ++ if (g_stp_dbg_dmaregs->count > STP_DBG_DMAREGS_NUM) { ++ STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count:%d must less than STP_DBG_DMAREGS_NUM:%d\n", ++ g_stp_dbg_dmaregs->count, STP_DBG_DMAREGS_NUM); ++ g_stp_dbg_dmaregs->count = 0; ++ STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count be set default value 0\n"); ++ } ++ times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count; ++ } ++ if (times > STP_DBG_DMAREGS_NUM) { ++ STP_DBG_ERR_FUNC("times overflow, set default value:0\n"); ++ times = 0; ++ } ++ STP_DBG_WARN_FUNC("---------Now Polling DMA relative Regs -------------\n"); ++ for (i = 0; i < times; i++) { ++ INT32 k = 0; ++ ++ for (; k < DMA_REGS_MAX; k++) { ++ STP_DBG_WARN_FUNC("times:%d,i:%d reg: %s, regs:%08x\n", times, i, dmaRegsStr[k], ++ wmt_plat_read_dmaregs(k)); ++ /* g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] = wmt_plat_read_dmaregs(k); */ ++ } ++ osal_sleep_ms(sleep); ++ } ++ STP_DBG_WARN_FUNC("---------Polling DMA relative Regs End-------------\n"); ++ g_stp_dbg_dmaregs->count += times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock); ++#else ++ return 0; ++#endif ++} ++ ++INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en) ++{ ++ ++ STP_DBG_INFO_FUNC("%s polling cpupcr\n", en == 0 ? "start" : "stop"); ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->stop_flag = en; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ return 0; ++} ++ ++INT32 stp_dbg_set_version_info(UINT32 chipid, UINT8 *pRomVer, UINT8 *pPatchVer, UINT8 *pPatchBrh) ++{ ++ if (g_stp_dbg_cpupcr) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->chipId = chipid; ++ ++ if (pRomVer) ++ osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2); ++ if (pPatchVer) ++ osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8); ++ if (pPatchBrh) ++ osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4); ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("chipid(0x%x),romver(%s),patchver(%s),branchver(%s)\n", g_stp_dbg_cpupcr->chipId, ++ &g_stp_dbg_cpupcr->romVer[0], &g_stp_dbg_cpupcr->patchVer[0], &g_stp_dbg_cpupcr->branchVer[0]); ++ return 0; ++} ++INT32 stp_dbg_set_wifiver(UINT32 wifiver) ++{ ++ if (g_stp_dbg_cpupcr) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->wifiVer = wifiver; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("wifiver(%x)\n", g_stp_dbg_cpupcr->wifiVer); ++ return 0; ++} ++ ++INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en) ++{ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en; ++ g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type; ++ g_stp_dbg_cpupcr->host_assert_info.reason = reason; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ return 0; ++} ++ ++UINT32 stp_dbg_get_host_trigger_assert(VOID) ++{ ++ return g_stp_dbg_cpupcr->host_assert_info.assert_from_host; ++} ++ ++INT32 stp_dbg_set_fw_info(UINT8 *issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type) ++{ ++ ENUM_ASSERT_INFO_PARSER_TYPE type_index; ++ PUINT8 tempbuf = NULL; ++ UINT32 i = 0; ++ INT32 iRet = 0; ++ ++ if (NULL == issue_info) { ++ STP_DBG_ERR_FUNC("null issue infor\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("issue type(%d)\n", issue_type); ++ g_stp_dbg_cpupcr->issue_type = issue_type; ++ osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE); ++ ++ /*print patch version when assert happened */ ++ STP_DBG_INFO_FUNC("=======================================\n"); ++ STP_DBG_INFO_FUNC("[consys patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer); ++ STP_DBG_INFO_FUNC("[consys patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer); ++ STP_DBG_INFO_FUNC("=======================================\n"); ++ ++ if ((STP_FW_ASSERT_ISSUE == issue_type) || ++ (STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { ++ if ((STP_FW_ASSERT_ISSUE == issue_type) || (STP_HOST_TRIGGER_FW_ASSERT == issue_type)) { ++ tempbuf = osal_malloc(len + 1); ++ if (!tempbuf) ++ return -2; ++ ++ osal_memcpy(&tempbuf[0], issue_info, len); ++ ++ for (i = 0; i < len; i++) { ++ if (tempbuf[i] == '\0') ++ tempbuf[i] = '?'; ++ } ++ ++ tempbuf[len] = '\0'; ++ ++ for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX; type_index++) ++ iRet += _stp_dbg_parser_assert_str(&tempbuf[0], type_index); ++ ++ if (iRet) ++ STP_DBG_ERR_FUNC("passert assert infor fail(%d)\n", iRet); ++ ++ } ++ if ((STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { ++ switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) { ++ case 0: ++ STP_DBG_INFO_FUNC("BT trigger assert\n"); ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ if (31 != g_stp_dbg_cpupcr->host_assert_info.reason) ++ /*BT firmware trigger assert */ ++ { ++ g_stp_dbg_cpupcr->fwTaskId = 1; ++ ++ } else ++ /*BT stack trigger assert */ ++ { ++ g_stp_dbg_cpupcr->fwTaskId = 8; ++ } ++ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; ++ /* g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; */ ++ /* g_stp_dbg_cpupcr->host_assert_info.reason = 0; */ ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ break; ++ case 4: ++ STP_DBG_INFO_FUNC("WMT trigger assert\n"); ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ if (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ ++ if ((38 == g_stp_dbg_cpupcr->host_assert_info.reason) || ++ (39 == g_stp_dbg_cpupcr->host_assert_info.reason) || ++ (40 == g_stp_dbg_cpupcr->host_assert_info.reason)) ++ g_stp_dbg_cpupcr->fwTaskId = 6; /* HOST schedule reason trigger */ ++ else ++ g_stp_dbg_cpupcr->fwTaskId = 0; /* Must be firmware reason */ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ break; ++ default: ++ break; ++ } ++ ++ } ++ osal_free(tempbuf); ++ } else if (STP_FW_NOACK_ISSUE == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 6; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else if (STP_DBG_PROC_TEST == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 0; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else if (STP_FW_WARM_RST_ISSUE == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 0; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("invalid issue type(%d)\n", issue_type); ++ return -3; ++ } ++ ++ return iRet; ++} ++ ++INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 str_len) ++{ ++ UINT32 len = 0; ++ UINT32 i = 0; ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ ++ /*format common information about issue */ ++ len = osal_sprintf(*buf, "
\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tMT%x\n\t\n\t", g_stp_dbg_cpupcr->chipId); ++ len += osal_sprintf(*buf + len, "\n\t\t"); ++ len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->romVer); ++ if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", strlen("ALPS")))) ++ len += osal_sprintf(*buf + len, "Internal Dev\n\t\t", g_stp_dbg_cpupcr->branchVer); ++ else ++ len += osal_sprintf(*buf + len, "W%sMP\n\t\t", g_stp_dbg_cpupcr->branchVer); ++ ++ len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->patchVer); ++ ++ if (0 == g_stp_dbg_cpupcr->wifiVer) ++ len += osal_sprintf(*buf + len, "NULL\n\t"); ++ else ++ len += osal_sprintf(*buf + len, "0x%X.%X\n\t", ++ (UINT8)((g_stp_dbg_cpupcr->wifiVer & 0xFF00)>>8), (UINT8)(g_stp_dbg_cpupcr->wifiVer & 0xFF)); ++ ++ len += osal_sprintf(*buf + len, "\n\t"); ++ ++ /*format issue information: no ack, assert */ ++ len += osal_sprintf(*buf + len, "\n\t\t\n\t\t\t"); ++ if ((STP_FW_NOACK_ISSUE == g_stp_dbg_cpupcr->issue_type) || ++ (STP_DBG_PROC_TEST == g_stp_dbg_cpupcr->issue_type) || ++ (STP_FW_WARM_RST_ISSUE == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", ++ g_stp_dbg_cpupcr->assert_info); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += ++ osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", ++ _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); ++ len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); ++ len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } else if ((STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", ++ g_stp_dbg_cpupcr->assert_info); ++ len += osal_sprintf(*buf + len, "%s\n\t\t\n\t\n\t", g_stp_dbg_cpupcr->assert_type); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += ++ osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", ++ _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); ++ if (32 == g_stp_dbg_cpupcr->host_assert_info.reason || 33 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 34 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 35 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 36 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 37 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 38 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 39 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 40 == g_stp_dbg_cpupcr->host_assert_info.reason) { ++ /*handling wmt turn on/off bt cmd has ack but no evt issue */ ++ /*one of both the irqx and irs is nULL, then use task to find MOF */ ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } else { ++ len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); ++ } ++ len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); ++ ++ if (STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) { ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } ++ ++ if ((STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%d\n\t\t\t", ++ g_stp_dbg_cpupcr->host_assert_info.drv_type); ++ len += ++ osal_sprintf(*buf + len, "%d\n\t\t\t", ++ g_stp_dbg_cpupcr->host_assert_info.reason); ++ } ++ } else { ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\t\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "\n\t\t\tNULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } ++ ++ len += osal_sprintf(*buf + len, ""); ++ STP_DBG_INFO_FUNC("stp-dbg:sub len1 for debug(%d)\n", len); ++ ++ if (!g_stp_dbg_cpupcr->count) ++ len += osal_sprintf(*buf + len, "NULL"); ++ else { ++ for (i = 0; i < g_stp_dbg_cpupcr->count; i++) ++ len += osal_sprintf(*buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]); ++ } ++ STP_DBG_INFO_FUNC("stp-dbg:sub len2 for debug(%d)\n", len); ++ len += osal_sprintf(*buf + len, "\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n
\n"); ++ STP_DBG_INFO_FUNC("buffer len[%d]\n", len); ++ /* STP_DBG_INFO_FUNC("Format infor:\n%s\n",*buf); */ ++ *str_len = len; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM); ++ g_stp_dbg_cpupcr->count = 0; ++ g_stp_dbg_cpupcr->host_assert_info.reason = 0; ++ g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ return 0; ++ ++} ++ ++MTKSTP_DBG_T *stp_dbg_init(void *btm_half) ++{ ++ ++ MTKSTP_DBG_T *stp_dbg = NULL; ++ ++ STP_DBG_INFO_FUNC("stp-dbg init\n"); ++ ++ stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL); ++ if (stp_dbg == NULL) ++ goto ERR_EXIT1; ++ if (IS_ERR(stp_dbg)) { ++ STP_DBG_ERR_FUNC("-ENOMEM\n"); ++ goto ERR_EXIT1; ++ } ++ ++ stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T)); ++ if (stp_dbg->logsys == NULL) ++ goto ERR_EXIT2; ++ if (IS_ERR(stp_dbg->logsys)) { ++ STP_DBG_ERR_FUNC("-ENOMEM stp_gdb->logsys\n"); ++ goto ERR_EXIT2; ++ } ++ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); ++ spin_lock_init(&(stp_dbg->logsys->lock)); ++ stp_dbg->pkt_trace_no = 0; ++ stp_dbg->is_enable = 0; ++ g_stp_dbg = stp_dbg; ++ ++ if (btm_half != NULL) ++ stp_dbg->btm = btm_half; ++ else ++ stp_dbg->btm = NULL; ++ ++ ++ /* bind to netlink */ ++ stp_dbg_nl_init(); ++ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); ++ g_stp_dbg_cpupcr = stp_dbg_cpupcr_init(); ++ g_stp_dbg_dmaregs = stp_dbg_dmaregs_init(); ++ ++ return stp_dbg; ++ ++ERR_EXIT2: ++ kfree(stp_dbg); ++ return NULL; ++ ++ERR_EXIT1: ++ kfree(stp_dbg); ++ return NULL; ++} ++ ++int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ STP_DBG_INFO_FUNC("stp-dbg deinit\n"); ++ ++ wcn_core_dump_deinit(g_core_dump); ++ ++ stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr); ++ stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs); ++ /* unbind with netlink */ ++ stp_dbg_nl_deinit(); ++ ++ if (stp_dbg->logsys) ++ vfree(stp_dbg->logsys); ++ ++ kfree(stp_dbg); ++ ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c +new file mode 100644 +index 000000000000..f7f4aff010d4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c +@@ -0,0 +1,279 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include /* udelay() */ ++ ++#include ++ ++ ++#include "osal_typedef.h" ++#include "stp_core.h" ++#include "stp_exp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static MTK_WCN_STP_IF_TX stp_uart_if_tx; ++static MTK_WCN_STP_IF_TX stp_sdio_if_tx; ++static MTK_WCN_STP_IF_TX stp_btif_if_tx; ++static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX; ++static MTK_WCN_STP_IF_RX stp_if_rx; ++static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; ++static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size) ++{ ++ if (stp_if_rx == 0x0) ++ return -1; ++ ++ (*stp_if_rx) (data, size); ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_if_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) ++{ ++ ++ if (STP_UART_IF_TX == g_stp_if_type) ++ return stp_uart_if_tx != NULL ? (*stp_uart_if_tx) (data, size, written_size) : -1; ++ else if (STP_SDIO_IF_TX == g_stp_if_type) ++ return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx) (data, size, written_size) : -1; ++ else if (STP_BTIF_IF_TX == g_stp_if_type) ++ return stp_btif_if_tx != NULL ? (*stp_btif_if_tx) (data, size, written_size) : -1; ++ /*if (g_stp_if_type >= STP_MAX_IF_TX) *//* George: remove ALWAYS TRUE condition */ ++ return -1; ++} ++ ++static INT32 mtk_wcn_sys_event_set(UINT8 function_type) ++{ ++ if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0)) { ++ (*event_callback_tbl[function_type]) (); ++ } else { ++ /* FIXME: error handling */ ++ pr_err("[%s] STP set event fail. It seems the function is not active.\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace) ++{ ++ int type = 0; ++ ++ for (type = 0; type < MTKSTP_MAX_TASK_NUM; type++) { ++ if (tx_event_callback_tbl[type]) ++ tx_event_callback_tbl[type] (); ++ } ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op) ++{ ++ ++ /* op == FUNCTION_ACTIVE, to check if funciton[type] is active ? */ ++ if (!(type < MTKSTP_MAX_TASK_NUM)) ++ return STATUS_FUNCTION_INVALID; ++ ++ if (op == OP_FUNCTION_ACTIVE) { ++ if (event_callback_tbl[type] != 0x0) ++ return STATUS_FUNCTION_ACTIVE; ++ else ++ return STATUS_FUNCTION_INACTIVE; ++ ++ } ++ /* you can define more operation here ..., to queury function's status/information */ ++ ++ return STATUS_OP_INVALID; ++} ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++#else ++INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++#endif ++{ ++ stp_if_rx = func; ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); ++#endif ++ ++VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type) ++{ ++ static const char * const ifType[] = { ++ "UART", ++ "SDIO", ++ "BTIF", ++ "UNKNOWN" ++ }; ++ g_stp_if_type = stp_if_type; ++ pr_debug("[%s] set STP_IF_TX to %s.\n", __func__, ifType[stp_if_type]); ++} ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++#else ++INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++#endif ++{ ++ if (STP_UART_IF_TX == stp_if) { ++ stp_uart_if_tx = func; ++ } else if (STP_SDIO_IF_TX == stp_if) { ++ stp_sdio_if_tx = func; ++ } else if (STP_BTIF_IF_TX == stp_if) { ++ stp_btif_if_tx = func; ++ } else { ++ pr_debug("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); ++ return -1; ++ } ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); ++#endif ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#else ++INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#endif ++{ ++ if (type < MTKSTP_MAX_TASK_NUM) { ++ event_callback_tbl[type] = func; ++ ++ /*clear rx queue */ ++ pr_debug("Flush type = %d Rx Queue\n", type); ++ mtk_wcn_stp_flush_rx_queue(type); ++ } ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); ++#endif ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#else ++INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#endif ++{ ++ if (type < MTKSTP_MAX_TASK_NUM) ++ tx_event_callback_tbl[type] = func; ++ else ++ BUG_ON(0); ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); ++#endif ++ ++INT32 stp_drv_init(VOID) ++{ ++ INT32 ret = 0; ++ ++ mtkstp_callback cb = { ++ .cb_if_tx = mtk_wcn_sys_if_tx, ++ .cb_event_set = mtk_wcn_sys_event_set, ++ .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume, ++ .cb_check_funciton_status = mtk_wcn_sys_check_function_status ++ }; ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ MTK_WCN_STP_EXP_CB_INFO stpExpCb = { ++ .stp_send_data_cb = _mtk_wcn_stp_send_data, ++ .stp_send_data_raw_cb = _mtk_wcn_stp_send_data_raw, ++ .stp_parser_data_cb = _mtk_wcn_stp_parser_data, ++ .stp_receive_data_cb = _mtk_wcn_stp_receive_data, ++ .stp_is_rxqueue_empty_cb = _mtk_wcn_stp_is_rxqueue_empty, ++ .stp_is_ready_cb = _mtk_wcn_stp_is_ready, ++ .stp_set_bluez_cb = _mtk_wcn_stp_set_bluez, ++ .stp_if_tx_cb = _mtk_wcn_stp_register_if_tx, ++ .stp_if_rx_cb = _mtk_wcn_stp_register_if_rx, ++ .stp_reg_event_cb = _mtk_wcn_stp_register_event_cb, ++ .stp_reg_tx_event_cb = _mtk_wcn_stp_register_tx_event_cb, ++ .stp_coredump_start_get_cb = _mtk_wcn_stp_coredump_start_get, ++ }; ++#endif ++ ++ ret = mtk_wcn_stp_init(&cb); ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_stp_exp_cb_reg(&stpExpCb); ++#endif ++ return ret; ++} ++ ++VOID stp_drv_exit(VOID) ++{ ++ mtk_wcn_stp_deinit(); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_stp_exp_cb_unreg(); ++#endif ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c +new file mode 100644 +index 000000000000..f70c88796f09 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c +@@ -0,0 +1,2566 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief brief description ++ ++ Detailed descriptions here. ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DEV]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_dev.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++#include "wmt_lib.h" ++#include "wmt_conf.h" ++#include "psm_core.h" ++#include "stp_core.h" ++#include "stp_exp.h" ++#include "bgw_desense.h" ++#include ++#include "wmt_idc.h" ++#ifdef CONFIG_COMPAT ++#include ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++#include ++#endif ++#define BUF_LEN_MAX 384 ++#include ++#ifdef CONFIG_COMPAT ++#define COMPAT_WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, compat_uptr_t) ++#endif ++ ++#define WMT_IOC_MAGIC 0xa0 ++#define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, char*) ++#define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC, 5, int) ++#define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC, 6, int) ++#define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC, 7, int) ++#define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, char*) ++#define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC, 12, int) ++#define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC, 13, int) ++#define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC, 14, int) ++#define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, char*) ++#define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*) ++#define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*) ++#define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int) ++#define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int) ++#define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int) ++#define WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, char*) ++#define WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, char*) ++#define WMT_IOCTL_FW_DBGLOG_CTRL _IOR(WMT_IOC_MAGIC, 29, int) ++#define WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, char*) ++ ++#define MTK_WMT_VERSION "SOC Consys WMT Driver - v1.0" ++#define MTK_WMT_DATE "2013/01/20" ++#define WMT_DEV_MAJOR 190 /* never used number */ ++#define WMT_DEV_NUM 1 ++#define WMT_DEV_INIT_TO_MS (2 * 1000) ++#define DYNAMIC_DUMP_BUF 109 ++ ++#if CFG_WMT_DBG_SUPPORT ++#define WMT_DBG_PROCNAME "driver/wmt_dbg" ++#endif ++ ++#define WMT_DRIVER_NAME "mtk_stp_wmt" ++ ++P_OSAL_EVENT gpRxEvent = NULL; ++ ++UINT32 u4RxFlag = 0x0; ++static atomic_t gRxCount = ATOMIC_INIT(0); ++ ++/* Linux UINT8 device */ ++static int gWmtMajor = WMT_DEV_MAJOR; ++static struct cdev gWmtCdev; ++static atomic_t gWmtRefCnt = ATOMIC_INIT(0); ++/* WMT driver information */ ++static UINT8 gLpbkBuf[1024+5] = { 0 }; ++ ++static UINT32 gLpbkBufLog; /* George LPBK debug */ ++static INT32 gWmtInitDone; ++static wait_queue_head_t gWmtInitWq; ++ ++P_WMT_PATCH_INFO pPatchInfo = NULL; ++UINT32 pAtchNum = 0; ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) ++#define WMT_EMI_DEBUG_BUF_SIZE (8*1024) ++#else ++#define WMT_EMI_DEBUG_BUF_SIZE (32*1024) ++#endif ++ ++static UINT8 gEmiBuf[WMT_EMI_DEBUG_BUF_SIZE]; ++UINT8 *buf_emi; ++ ++#if CFG_WMT_PROC_FOR_AEE ++static struct proc_dir_entry *gWmtAeeEntry; ++#define WMT_AEE_PROCNAME "driver/wmt_aee" ++#define WMT_PROC_AEE_SIZE 3072 ++static UINT32 g_buf_len; ++static UINT8 *pBuf; ++#endif ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *wmt_class = NULL; ++struct device *wmt_dev = NULL; ++#endif ++ ++#if CFG_WMT_DBG_SUPPORT ++static struct proc_dir_entry *gWmtDbgEntry; ++COEX_BUF gCoexBuf; ++ ++static INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd); ++static INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3); ++ ++#if CFG_CORE_INTERNAL_TXRX ++static INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3); ++#endif ++static INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3); ++#if CONSYS_ENALBE_SET_JTAG ++static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3); ++#endif ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3); ++#endif ++#endif ++static void wmt_dbg_fwinfor_print_buff(UINT32 len) ++{ ++ UINT32 i = 0; ++ UINT32 idx = 0; ++ ++ for (i = 0; i < len; i++) { ++ buf_emi[idx] = gEmiBuf[i]; ++ if (gEmiBuf[i] == '\n') { ++ pr_cont("%s", buf_emi); ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ idx = 0; ++ } else { ++ idx++; ++ } ++ if (idx == BUF_LEN_MAX-1) { ++ buf_emi[idx] = '\0'; ++ pr_cont("%s", buf_emi); ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ idx = 0; ++ } ++ } ++} ++ ++/*LCM on/off ctrl for wmt varabile*/ ++static struct work_struct gPwrOnOffWork; ++UINT32 g_es_lr_flag_for_quick_sleep = 1; /* for ctrl quick sleep flag */ ++UINT32 g_es_lr_flag_for_lpbk_onoff = 0; /* for ctrl lpbk on off */ ++OSAL_SLEEPABLE_LOCK g_es_lr_lock; ++ ++#ifdef CONFIG_EARLYSUSPEND ++ ++static void wmt_dev_early_suspend(struct early_suspend *h) ++{ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 1; ++ g_es_lr_flag_for_lpbk_onoff = 0; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter early suspend@@@@@@@@@@@@@@\n"); ++ ++ schedule_work(&gPwrOnOffWork); ++} ++ ++static void wmt_dev_late_resume(struct early_suspend *h) ++{ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 0; ++ g_es_lr_flag_for_lpbk_onoff = 1; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter late resume@@@@@@@@@@@@@@\n"); ++ ++ schedule_work(&gPwrOnOffWork); ++ ++} ++ ++struct early_suspend wmt_early_suspend_handler = { ++ .suspend = wmt_dev_early_suspend, ++ .resume = wmt_dev_late_resume, ++}; ++ ++#else ++ ++static struct notifier_block wmt_fb_notifier; ++static int wmt_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) ++{ ++ struct fb_event *evdata = data; ++ INT32 blank; ++ ++ WMT_DBG_FUNC("wmt_fb_notifier_callback\n"); ++ ++ /* If we aren't interested in this event, skip it immediately ... */ ++ if (event != FB_EVENT_BLANK) ++ return 0; ++ ++ blank = *(INT32 *)evdata->data; ++ WMT_DBG_FUNC("fb_notify(blank=%d)\n", blank); ++ ++ switch (blank) { ++ case FB_BLANK_UNBLANK: ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 0; ++ g_es_lr_flag_for_lpbk_onoff = 1; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter UNBLANK @@@@@@@@@@@@@@\n"); ++ schedule_work(&gPwrOnOffWork); ++ break; ++ case FB_BLANK_POWERDOWN: ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 1; ++ g_es_lr_flag_for_lpbk_onoff = 0; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter early POWERDOWN @@@@@@@@@@@@@@\n"); ++ schedule_work(&gPwrOnOffWork); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static void wmt_pwr_on_off_handler(struct work_struct *work) ++{ ++ INT32 retryCounter = 1; ++ ++ WMT_DBG_FUNC("wmt_pwr_on_off_handler start to run\n"); ++ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ ++ if (g_es_lr_flag_for_lpbk_onoff) { ++ do { ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK)) { ++ WMT_WARN_FUNC("WMT turn on LPBK fail, retrying, retryCounter left:%d!\n", retryCounter); ++ retryCounter--; ++ osal_sleep_ms(1000); ++ } else { ++ WMT_INFO_FUNC("WMT turn on LPBK suceed\n"); ++ break; ++ } ++ } while (retryCounter > 0); ++ } else { ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK)) ++ WMT_WARN_FUNC("WMT turn off LPBK fail\n"); ++ else ++ WMT_DBG_FUNC("WMT turn off LPBK suceed\n"); ++ ++ } ++ ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++} ++ ++ ++MTK_WCN_BOOL wmt_dev_get_early_suspend_state(void) ++{ ++ MTK_WCN_BOOL bRet = (0 == g_es_lr_flag_for_quick_sleep) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; ++ /* WMT_INFO_FUNC("bRet:%d\n", bRet); */ ++ return bRet; ++} ++ ++#if CFG_WMT_DBG_SUPPORT ++ ++static const WMT_DEV_DBG_FUNC wmt_dev_dbg_func[] = { ++ [0] = wmt_dbg_psm_ctrl, ++ [1] = wmt_dbg_quick_sleep_ctrl, ++ [2] = wmt_dbg_dsns_ctrl, ++ [3] = wmt_dbg_hwver_get, ++ [4] = wmt_dbg_assert_test, ++ [5] = wmt_dbg_inband_rst, ++ [6] = wmt_dbg_chip_rst, ++ [7] = wmt_dbg_func_ctrl, ++ [8] = wmt_dbg_raed_chipid, ++ [9] = wmt_dbg_wmt_dbg_level, ++ [0xa] = wmt_dbg_stp_dbg_level, ++ [0xb] = wmt_dbg_reg_read, ++ [0xc] = wmt_dbg_reg_write, ++ [0xd] = wmt_dbg_coex_test, ++ [0xe] = wmt_dbg_rst_ctrl, ++ [0xf] = wmt_dbg_ut_test, ++ [0x10] = wmt_dbg_efuse_read, ++ [0x11] = wmt_dbg_efuse_write, ++ [0x12] = wmt_dbg_sdio_ctrl, ++ [0x13] = wmt_dbg_stp_dbg_ctrl, ++ [0x14] = wmt_dbg_stp_dbg_log_ctrl, ++ [0x15] = wmt_dbg_wmt_assert_ctrl, ++ [0x16] = wmt_dbg_fwinfor_from_emi, ++ [0x17] = wmt_dbg_set_mcu_clock, ++ [0x18] = wmt_dbg_poll_cpupcr, ++ [0x19] = wmt_dbg_jtag_flag_ctrl, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [0x20] = wmt_dbg_lte_coex_test, ++#endif ++}; ++ ++INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++#if CFG_WMT_PS_SUPPORT ++ if (0 == par2) { ++ wmt_lib_ps_ctrl(0); ++ WMT_INFO_FUNC("disable PSM\n"); ++ } else { ++ par2 = (1 > par2 || 20000 < par2) ? STP_PSM_IDLE_TIME_SLEEP : par2; ++ wmt_lib_ps_set_idle_time(par2); ++ wmt_lib_ps_ctrl(1); ++ WMT_WARN_FUNC("enable PSM, idle to sleep time = %d ms\n", par2); ++ } ++#else ++ WMT_INFO_FUNC("WMT PS not supported\n"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++#if CFG_WMT_PS_SUPPORT ++ UINT32 en_flag = par2; ++ ++ wmt_lib_quick_sleep_ctrl(en_flag); ++#else ++ WMT_WARN_FUNC("WMT PS not supported\n"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (WMTDSNS_FM_DISABLE <= par2 && WMTDSNS_MAX > par2) { ++ WMT_INFO_FUNC("DSNS type (%d)\n", par2); ++ mtk_wcn_wmt_dsns_ctrl(par2); ++ } else { ++ WMT_WARN_FUNC("invalid DSNS type\n"); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("query chip version\n"); ++ mtk_wcn_wmt_hwver_get(); ++ return 0; ++} ++ ++INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par3) { ++ /* par2 = 0: send assert command */ ++ /* par2 != 0: send exception command */ ++ return wmt_dbg_cmd_test_api(0 == par2 ? 0 : 1); ++ } else if (1 == par3) { ++ /* send noack command */ ++ return wmt_dbg_cmd_test_api(18); ++ } else if (2 == par3) { ++ /* warn reset test */ ++ return wmt_dbg_cmd_test_api(19); ++ } else if (3 == par3) { ++ /* firmware trace test */ ++ return wmt_dbg_cmd_test_api(20); ++ } ++ { ++ INT32 sec = 8; ++ INT32 times = 0; ++ ++ times = par3; ++ do { ++ WMT_INFO_FUNC("Send Assert Command per 8 secs!!\n"); ++ wmt_dbg_cmd_test_api(0); ++ osal_sleep_ms(sec * 1000); ++ } while (--times); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd) ++{ ++ ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = WMT_OPID_CMD_TEST; ++ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*this test command should be run with usb cable connected, so no host awake is needed */ ++ /* wmt_lib_host_awake_get(); */ ++ switch (cmd) { ++ case WMTDRV_CMD_ASSERT: ++ pOp->op.au4OpData[0] = 0; ++ break; ++ case WMTDRV_CMD_EXCEPTION: ++ pOp->op.au4OpData[0] = 1; ++ break; ++ case WMTDRV_CMD_NOACK_TEST: ++ pOp->op.au4OpData[0] = 3; ++ break; ++ case WMTDRV_CMD_WARNRST_TEST: ++ pOp->op.au4OpData[0] = 4; ++ break; ++ case WMTDRV_CMD_FWTRACE_TEST: ++ pOp->op.au4OpData[0] = 5; ++ break; ++ default: ++ if (WMTDRV_CMD_COEXDBG_00 <= cmd && WMTDRV_CMD_COEXDBG_15 >= cmd) { ++ pOp->op.au4OpData[0] = 2; ++ pOp->op.au4OpData[1] = cmd - 2; ++ } else { ++ pOp->op.au4OpData[0] = 0xff; ++ pOp->op.au4OpData[1] = 0xff; ++ } ++ pOp->op.au4OpData[2] = (SIZE_T) gCoexBuf.buffer; ++ pOp->op.au4OpData[3] = osal_sizeof(gCoexBuf.buffer); ++ break; ++ } ++ WMT_INFO_FUNC("CMD_TEST, opid(%d), par(%d, %d)\n", pOp->op.opId, pOp->op.au4OpData[0], pOp->op.au4OpData[1]); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if ((cmd != WMTDRV_CMD_ASSERT) && ++ (cmd != WMTDRV_CMD_EXCEPTION) && ++ (cmd != WMTDRV_CMD_NOACK_TEST) && (cmd != WMTDRV_CMD_WARNRST_TEST) && (cmd != WMTDRV_CMD_FWTRACE_TEST)) { ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ gCoexBuf.availSize = 0; ++ } else { ++ gCoexBuf.availSize = pOp->op.au4OpData[3]; ++ WMT_INFO_FUNC("gCoexBuf.availSize = %d\n", gCoexBuf.availSize); ++ } ++ } ++ /* wmt_lib_host_awake_put(); */ ++ WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", ++ pOp->op.opId, ++ pOp->op.au4OpData[0], ++ pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par2) { ++ WMT_INFO_FUNC("inband reset test!!\n"); ++ mtk_wcn_stp_inband_reset(); ++ } else { ++ WMT_INFO_FUNC("STP context reset in host side!!\n"); ++ mtk_wcn_stp_flush_context(); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par2) { ++ if (mtk_wcn_stp_is_ready()) { ++ WMT_INFO_FUNC("whole chip reset test\n"); ++ wmt_lib_cmb_rst(WMTRSTSRC_RESET_TEST); ++ } else { ++ WMT_INFO_FUNC("STP not ready , not to launch whole chip reset test\n"); ++ } ++ } else if (1 == par2) { ++ WMT_INFO_FUNC("chip hardware reset test\n"); ++ wmt_lib_hw_rst(); ++ } else { ++ WMT_INFO_FUNC("chip software reset test\n"); ++ wmt_lib_sw_rst(1); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (WMTDRV_TYPE_WMT > par2 || WMTDRV_TYPE_LPBK == par2) { ++ if (0 == par3) { ++ WMT_INFO_FUNC("function off test, type(%d)\n", par2); ++ mtk_wcn_wmt_func_off(par2); ++ } else { ++ WMT_INFO_FUNC("function on test, type(%d)\n", par2); ++ mtk_wcn_wmt_func_on(par2); ++ } ++ } else { ++ WMT_INFO_FUNC("function ctrl test, invalid type(%d)\n", par2); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("chip version = %d\n", wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER)); ++ return 0; ++} ++ ++INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3) ++{ ++ par2 = (WMT_LOG_ERR <= par2 && WMT_LOG_LOUD >= par2) ? par2 : WMT_LOG_INFO; ++ wmt_lib_dbg_level_set(par2); ++ WMT_INFO_FUNC("set wmt log level to %d\n", par2); ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3) ++{ ++ par2 = (0 <= par2 && 4 >= par2) ? par2 : 2; ++ mtk_wcn_stp_dbg_level(par2); ++ WMT_INFO_FUNC("set stp log level to %d\n", par2); ++ return 0; ++ ++} ++ ++INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->register address */ ++ /* par3-->register mask */ ++ UINT32 value = 0x0; ++ UINT32 iRet = -1; ++#if 0 ++ DISABLE_PSM_MONITOR(); ++ iRet = wmt_core_reg_rw_raw(0, par2, &value, par3); ++ ENABLE_PSM_MONITOR(); ++#endif ++ iRet = wmt_lib_reg_rw(0, par2, &value, par3); ++ WMT_INFO_FUNC("read combo chip register (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); ++ return 0; ++} ++ ++INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->register address */ ++ /* par3-->value to set */ ++ UINT32 iRet = -1; ++#if 0 ++ DISABLE_PSM_MONITOR(); ++ iRet = wmt_core_reg_rw_raw(1, par2, &par3, 0xffffffff); ++ ENABLE_PSM_MONITOR(); ++#endif ++ iRet = wmt_lib_reg_rw(1, par2, &par3, 0xffffffff); ++ WMT_INFO_FUNC("write combo chip register (0x%08x) with value (0x%08x) %s\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed"); ++ return 0; ++} ++ ++INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->efuse address */ ++ /* par3-->register mask */ ++ UINT32 value = 0x0; ++ UINT32 iRet = -1; ++ ++ iRet = wmt_lib_efuse_rw(0, par2, &value, par3); ++ WMT_INFO_FUNC("read combo chip efuse (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); ++ return 0; ++} ++ ++INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->efuse address */ ++ /* par3-->value to set */ ++ UINT32 iRet = -1; ++ ++ iRet = wmt_lib_efuse_rw(1, par2, &par3, 0xffffffff); ++ WMT_INFO_FUNC("write combo chip efuse (0x%08x) with value (0x%08x) %s\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed"); ++ return 0; ++} ++ ++INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++/*remove sdio card detect/remove control because of btif is used*/ ++#if 0 ++ INT32 iRet = -1; ++ ++ iRet = wmt_lib_sdio_ctrl(0 != par2 ? 1 : 0); ++ WMT_INFO_FUNC("ctrl SDIO function %s\n", 0 == iRet ? "succeed" : "failed"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (1 < par2) { ++ mtk_wcn_stp_dbg_dump_package(); ++ return 0; ++ } ++ WMT_INFO_FUNC("%s stp debug function\n", 0 == par2 ? "disable" : "enable"); ++ if (0 == par2) ++ mtk_wcn_stp_dbg_disable(); ++ else if (1 == par2) ++ mtk_wcn_stp_dbg_enable(); ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ mtk_wcn_stp_dbg_log_ctrl(0 != par2 ? 1 : 0); ++ return 0; ++} ++ ++INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ mtk_wcn_stp_coredump_flag_ctrl(0 != par2 ? 1 : 0); ++ return 0; ++} ++ ++INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 offset = 0; ++ UINT32 len = 0; ++ UINT32 *pAddr = NULL; ++ UINT32 cur_idx_pagedtrace; ++ static UINT32 prev_idx_pagedtrace; ++ MTK_WCN_BOOL isBreak = MTK_WCN_BOOL_TRUE; ++ ++ offset = par2; ++ len = par3; ++ ++ buf_emi = kmalloc(sizeof(UINT8) * BUF_LEN_MAX, GFP_KERNEL); ++ if (!buf_emi) { ++ WMT_ERR_FUNC("buf kmalloc memory fail\n"); ++ return 0; ++ } ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); ++ wmt_lib_get_fwinfor_from_emi(0, offset, &gEmiBuf[0], 0x100); ++ ++ if (offset == 1) { ++ do { ++ pAddr = (PUINT32) wmt_plat_get_emi_virt_add(0x24); ++ cur_idx_pagedtrace = *pAddr; ++ ++ if (cur_idx_pagedtrace > prev_idx_pagedtrace) { ++ len = cur_idx_pagedtrace - prev_idx_pagedtrace; ++ wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); ++ wmt_dbg_fwinfor_print_buff(len); ++ prev_idx_pagedtrace = cur_idx_pagedtrace; ++ } ++ ++ if (cur_idx_pagedtrace < prev_idx_pagedtrace) { ++ if (prev_idx_pagedtrace >= 0x8000) { ++ pr_debug("++ prev_idx_pagedtrace invalid ...++\n\\n"); ++ prev_idx_pagedtrace = 0x8000 - 1; ++ continue; ++ } ++ ++ len = 0x8000 - prev_idx_pagedtrace - 1; ++ wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); ++ pr_debug("\n\n -- CONNSYS paged trace ascii output (cont...) --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ ++ len = cur_idx_pagedtrace; ++ wmt_lib_get_fwinfor_from_emi(1, 0x0, &gEmiBuf[0], len); ++ pr_debug("\n\n -- CONNSYS paged trace ascii output (end) --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ prev_idx_pagedtrace = cur_idx_pagedtrace; ++ } ++ msleep(100); ++ } while (isBreak); ++ } ++ ++ pr_debug("\n\n -- control word --\n\n"); ++ wmt_dbg_fwinfor_print_buff(256); ++ if (len > 1024 * 4) ++ len = 1024 * 4; ++ ++ WMT_WARN_FUNC("get fw infor from emi at offset(0x%x),len(0x%x)\n", offset, len); ++ osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); ++ wmt_lib_get_fwinfor_from_emi(1, offset, &gEmiBuf[0], len); ++ ++ pr_debug("\n\n -- paged trace hex output --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ pr_debug("\n\n -- paged trace ascii output --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ kfree(buf_emi); ++ return 0; ++} ++ ++INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("coexistance test cmd!!\n"); ++ return wmt_dbg_cmd_test_api(par2 + WMTDRV_CMD_COEXDBG_00); ++} ++ ++INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("%s audo rst\n", 0 == par2 ? "disable" : "enable"); ++ mtk_wcn_stp_set_auto_rst(0 == par2 ? 0 : 1); ++ return 0; ++} ++ ++INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ ++ INT32 i = 0; ++ INT32 j = 0; ++ INT32 iRet = 0; ++ ++ i = 20; ++ while ((i--) > 0) { ++ WMT_INFO_FUNC("#### UT WMT and STP Function On/Off .... %d\n", i); ++ j = 10; ++ while ((j--) > 0) { ++ WMT_INFO_FUNC("#### BT On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### GPS On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### FM On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### WIFI On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### BT Off .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### GPS Off ....(%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### FM Off .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### WIFI Off ....(%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ } ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ } ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ WMT_INFO_FUNC("#### UT FAIL!!\n"); ++ else ++ WMT_INFO_FUNC("#### UT PASS!!\n"); ++ ++ return iRet; ++} ++ ++#if CFG_CORE_INTERNAL_TXRX ++ ++struct lpbk_package { ++ long payload_length; ++ unsigned char out_payload[2048]; ++ unsigned char in_payload[2048]; ++}; ++ ++static INT32 wmt_internal_loopback(INT32 count, INT32 max) ++{ ++ int ret = 0; ++ int loop; ++ int offset; ++ struct lpbk_package lpbk_buffer; ++ P_OSAL_OP pOp; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ for (loop = 0; loop < count; loop++) { ++ /* <1> init buffer */ ++ osal_memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package)); ++ lpbk_buffer.payload_length = max; ++ for (offset = 0; offset < max; offset++) ++ lpbk_buffer.out_payload[offset] = (offset + 1) /*for test use: begin from 1 */ & 0xFF; ++ ++ ++ memcpy(&gLpbkBuf[0], &lpbk_buffer.out_payload[0], max); ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ ret = -1; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_LPBK; ++ pOp->op.au4OpData[0] = lpbk_buffer.payload_length; /* packet length */ ++ pOp->op.au4OpData[1] = (UINT32) &gLpbkBuf[0]; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ ret = -2; ++ } ++ ++ ret = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == ret) { ++ WMT_WARN_FUNC("OPID(%d) type(%d)fail\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ret = -3; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ memcpy(&lpbk_buffer.in_payload[0], &gLpbkBuf[0], max); ++ ++ ret = pOp->op.au4OpData[0]; ++ /*<3> compare result */ ++ if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) { ++ WMT_INFO_FUNC("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __func__); ++ ret = -4; ++ break; ++ } ++ WMT_ERR_FUNC("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld)\n", __func__, loop, ++ lpbk_buffer.payload_length); ++ ++ } ++ ++ if (loop != count) ++ WMT_ERR_FUNC("fail at loop(%d) buf_length(%d)\n", loop, max); ++ ++ ++ return ret; ++} ++ ++INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 count; ++ UINT32 length; ++ ++ count = par1; ++ length = par2; ++ ++ WMT_INFO_FUNC("count[%d],length[%d]\n", count, length); ++ ++ wmt_core_lpbk_do_stp_init(); ++ ++ wmt_internal_loopback(count, length); ++ ++ wmt_core_lpbk_do_stp_deinit(); ++ return 0; ++} ++#endif ++ ++static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3) ++{ ++ int ret = 0; ++ P_OSAL_OP pOp; ++ P_OSAL_SIGNAL pSignal = NULL; ++ UINT32 kind = 0; ++ ++ kind = par2; ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_SET_MCU_CLK; ++ pOp->op.au4OpData[0] = kind; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ WMT_INFO_FUNC("OPID(%d) kind(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) kind(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -2; ++ } ++ ++ ret = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == ret) { ++ WMT_WARN_FUNC("OPID(%d) kind(%d)fail(%d)\n", pOp->op.opId, pOp->op.au4OpData[0], ret); ++ return -3; ++ } ++ WMT_INFO_FUNC("OPID(%d) kind(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return ret; ++} ++ ++static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 count = 0; ++ UINT16 sleep = 0; ++ UINT16 toAee = 0; ++ ++ count = par2; ++ sleep = (par3 & 0xF0) >> 4; ++ toAee = (par3 & 0x0F); ++ ++ WMT_INFO_FUNC("polling count[%d],polling sleep[%d],toaee[%d]\n", count, sleep, toAee); ++ wmt_lib_poll_cpupcr(count, sleep, toAee); ++ ++ return 0; ++} ++ ++#if CONSYS_ENALBE_SET_JTAG ++static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 en_flag = par2; ++ ++ wmt_lib_jtag_flag_set(en_flag); ++ return 0; ++} ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_dbg_lte_to_wmt_test(UINT32 opcode, UINT32 msg_len) ++{ ++ ipc_ilm_t ilm; ++ local_para_struct *p_buf_str; ++ INT32 i = 0; ++ INT32 iRet = -1; ++ ++ WMT_INFO_FUNC("opcode(0x%02x),msg_len(%d)\n", opcode, msg_len); ++ p_buf_str = osal_malloc(osal_sizeof(local_para_struct) + msg_len); ++ if (NULL == p_buf_str) { ++ WMT_ERR_FUNC("kmalloc for local para ptr structure failed.\n"); ++ return -1; ++ } ++ p_buf_str->msg_len = msg_len; ++ for (i = 0; i < msg_len; i++) ++ p_buf_str->data[i] = i; ++ ++ ilm.local_para_ptr = p_buf_str; ++ ilm.msg_id = opcode; ++ ++ iRet = wmt_lib_handle_idc_msg(&ilm); ++ osal_free(p_buf_str); ++ return iRet; ++ ++} ++ ++static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT8 *local_buffer = NULL; ++ UINT32 handle_len; ++ INT32 iRet = -1; ++ static UINT8 wmt_to_lte_test_evt1[] = { 0x02, 0x16, 0x0d, 0x00, ++ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, ++ 0xa, 0xb ++ }; ++ static UINT8 wmt_to_lte_test_evt2[] = { 0x02, 0x16, 0x09, 0x00, ++ 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ++ }; ++ static UINT8 wmt_to_lte_test_evt3[] = { 0x02, 0x16, 0x02, 0x00, ++ 0x02, 0xff ++ }; ++ static UINT8 wmt_to_lte_test_evt4[] = { 0x02, 0x16, 0x0d, 0x00, ++ 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, ++ 0xa, 0xb ++ }; ++ ++ local_buffer = kmalloc(512, GFP_KERNEL); ++ if (!local_buffer) { ++ WMT_ERR_FUNC("local_buffer kmalloc memory fail\n"); ++ return 0; ++ } ++ ++ if (par2 == 1) { ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt1)) { ++ WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt1)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 2) { ++ osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], ++ &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); ++ ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], ++ osal_sizeof(wmt_to_lte_test_evt1) + ++ osal_sizeof(wmt_to_lte_test_evt2)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)) { ++ WMT_ERR_FUNC("par2=2,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 3) { ++ osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], ++ &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)], ++ &wmt_to_lte_test_evt3[0], osal_sizeof(wmt_to_lte_test_evt3)); ++ ++ handle_len = wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], osal_sizeof(wmt_to_lte_test_evt1) + ++ osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)); ++ if (handle_len != ++ osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)) { ++ WMT_ERR_FUNC("par2=3,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", handle_len, ++ osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)); ++ } else { ++ WMT_INFO_FUNC("par3=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 4) { ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt4[0], osal_sizeof(wmt_to_lte_test_evt4)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt4)) { ++ WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt4)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 5) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 6) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 7) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 8) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_TX_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_TX_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 9) { ++ if (par3 > 0) ++ wmt_core_set_flag_for_test(1); ++ else ++ wmt_core_set_flag_for_test(0); ++ } ++ return 0; ++ kfree(local_buffer); ++} ++#endif ++ ++static ssize_t wmt_dev_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ ++ INT32 retval = 0; ++ INT32 i_ret = 0; ++ PINT8 warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; ++ ++ if (*f_pos > 0) { ++ retval = 0; ++ } else { ++ /*len = sprintf(page, "%d\n", g_psm_enable); */ ++ if (gCoexBuf.availSize <= 0) { ++ WMT_INFO_FUNC("no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"); ++ retval = osal_strlen(warn_msg) + 1; ++ if (count < retval) ++ retval = count; ++ ++ i_ret = copy_to_user(buf, warn_msg, retval); ++ if (i_ret) { ++ WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } else { ++ INT32 i = 0; ++ INT32 len = 0; ++ INT8 msg_info[128]; ++ INT32 max_num = 0; ++ /*we do not check page buffer, because there are only ++ * 100 bytes in g_coex_buf, no reason page buffer is not ++ * enough, a bomb is placed here on unexpected condition ++ */ ++ ++ WMT_INFO_FUNC("%d bytes available\n", gCoexBuf.availSize); ++ max_num = ((osal_sizeof(msg_info) > count ? osal_sizeof(msg_info) : count) - 1) / 5; ++ ++ if (max_num > gCoexBuf.availSize) ++ max_num = gCoexBuf.availSize; ++ else ++ WMT_INFO_FUNC("round to %d bytes due to local buffer size limitation\n", max_num); ++ ++ ++ for (i = 0; i < max_num; i++) ++ len += osal_sprintf(msg_info + len, "0x%02x ", gCoexBuf.buffer[i]); ++ ++ ++ len += osal_sprintf(msg_info + len, "\n"); ++ retval = len; ++ ++ i_ret = copy_to_user(buf, msg_info, retval); ++ if (i_ret) { ++ WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ ++ } ++ } ++ gCoexBuf.availSize = 0; ++err_exit: ++ ++ return retval; ++} ++ ++static ssize_t wmt_dev_dbg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ INT8 buf[256]; ++ PINT8 pBuf; ++ ssize_t len = count; ++ INT32 x = 0, y = 0, z = 0; ++ PINT8 pToken = NULL; ++ PINT8 pDelimiter = " \t"; ++ long res; ++ INT32 ret; ++ ++ WMT_INFO_FUNC("write parameter len = %d\n\r", (INT32) len); ++ if (len >= osal_sizeof(buf)) { ++ WMT_ERR_FUNC("input handling fail!\n"); ++ len = osal_sizeof(buf) - 1; ++ return -1; ++ } ++ ++ if (copy_from_user(buf, buffer, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ WMT_INFO_FUNC("write parameter data = %s\n\r", buf); ++ ++ pBuf = buf; ++ pToken = osal_strsep(&pBuf, pDelimiter); ++ ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get x fail(%d)\n", ret); ++ x = 0; ++ } ++ x = res; ++ } else { ++ x = 0; ++ } ++ ++ pToken = osal_strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get y fail(%d)\n", ret); ++ y = 0; ++ } ++ y = res; ++ WMT_INFO_FUNC("y = 0x%08x\n\r", y); ++ } else { ++ y = 3000; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ y = 0x80000000; ++ ++ } ++ ++ pToken = osal_strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get z fail(%d)\n", ret); ++ z = 0; ++ } ++ z = res; ++ } else { ++ z = 10; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ z = 0xffffffff; ++ ++ } ++ ++ WMT_WARN_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++ ++ if (osal_array_size(wmt_dev_dbg_func) > x && NULL != wmt_dev_dbg_func[x]) ++ (*wmt_dev_dbg_func[x]) (x, y, z); ++ else ++ WMT_WARN_FUNC("no handler defined for command id(0x%08x)\n\r", x); ++ ++ return len; ++} ++ ++INT32 wmt_dev_dbg_setup(VOID) ++{ ++ static const struct file_operations wmt_dbg_fops = { ++ .owner = THIS_MODULE, ++ .read = wmt_dev_dbg_read, ++ .write = wmt_dev_dbg_write, ++ }; ++ gWmtDbgEntry = proc_create(WMT_DBG_PROCNAME, 0664, NULL, &wmt_dbg_fops); ++ if (gWmtDbgEntry == NULL) { ++ WMT_ERR_FUNC("Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ return 0; ++} ++ ++INT32 wmt_dev_dbg_remove(VOID) ++{ ++ if (NULL != gWmtDbgEntry) ++ remove_proc_entry(WMT_DBG_PROCNAME, NULL); ++ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_deinit(); ++#endif ++ return 0; ++} ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ ++static ssize_t wmt_dev_proc_for_aee_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = 0; ++ UINT32 len = 0; ++ ++ WMT_INFO_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos); ++ ++ if (0 == *f_pos) { ++ pBuf = wmt_lib_get_cpupcr_xml_format(&len); ++ g_buf_len = len; ++ WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len); ++ } ++ ++ if (g_buf_len >= count) { ++ ++ retval = copy_to_user(buf, pBuf, count); ++ if (retval) { ++ WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ ++ *f_pos += count; ++ g_buf_len -= count; ++ pBuf += count; ++ WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); ++ ++ retval = count; ++ } else if (0 != g_buf_len) { ++ ++ retval = copy_to_user(buf, pBuf, g_buf_len); ++ if (retval) { ++ WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ ++ *f_pos += g_buf_len; ++ len = g_buf_len; ++ g_buf_len = 0; ++ pBuf += len; ++ retval = len; ++ WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); ++ } else { ++ WMT_INFO_FUNC("wmt_dev: no data available for aee\n"); ++ retval = 0; ++ } ++err_exit: ++ return retval; ++} ++ ++static ssize_t wmt_dev_proc_for_aee_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_TRC_FUNC(); ++ return 0; ++} ++ ++INT32 wmt_dev_proc_for_aee_setup(VOID) ++{ ++ static const struct file_operations wmt_aee_fops = { ++ .owner = THIS_MODULE, ++ .read = wmt_dev_proc_for_aee_read, ++ .write = wmt_dev_proc_for_aee_write, ++ }; ++ ++ gWmtDbgEntry = proc_create(WMT_AEE_PROCNAME, 0664, NULL, &wmt_aee_fops); ++ if (gWmtDbgEntry == NULL) { ++ WMT_ERR_FUNC("Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_dev_proc_for_aee_remove(VOID) ++{ ++ if (NULL != gWmtAeeEntry) ++ remove_proc_entry(WMT_AEE_PROCNAME, NULL); ++ ++ return 0; ++} ++#endif ++ ++VOID wmt_dev_rx_event_cb(VOID) ++{ ++ u4RxFlag = 1; ++ atomic_inc(&gRxCount); ++ if (NULL != gpRxEvent) { ++ /* u4RxFlag = 1; */ ++ /* atomic_inc(&gRxCount); */ ++ wake_up_interruptible(&gpRxEvent->waitQueue); ++ } else { ++ /* WMT_ERR_FUNC("null gpRxEvent, flush rx!\n"); */ ++ /* wmt_lib_flush_rx(); */ ++ } ++} ++ ++INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent) ++{ ++ ++ UINT32 ms = pEvent->timeoutValue; ++ long lRet = 0; ++ ++ gpRxEvent = pEvent; ++ if (0 != ms) ++ lRet = wait_event_interruptible_timeout(gpRxEvent->waitQueue, 0 != u4RxFlag, msecs_to_jiffies(ms)); ++ else ++ lRet = wait_event_interruptible(gpRxEvent->waitQueue, u4RxFlag != 0); ++ ++ u4RxFlag = 0; ++/* gpRxEvent = NULL; */ ++ if (atomic_dec_return(&gRxCount)) { ++ WMT_ERR_FUNC("gRxCount != 0 (%d), reset it!\n", atomic_read(&gRxCount)); ++ atomic_set(&gRxCount, 0); ++ } ++ ++ return lRet; ++} ++ ++INT32 wmt_dev_read_file(PUINT8 pName, const PPUINT8 ppBufPtr, INT32 offset, INT32 padSzBuf) ++{ ++ INT32 iRet = -1; ++ struct file *fd; ++ /* ssize_t iRet; */ ++ INT32 file_len; ++ INT32 read_len; ++ PVOID pBuf; ++ mm_segment_t fs; ++ ++ /* struct cred *cred = get_task_cred(current); */ ++ //const struct cred *cred = get_current_cred(); ++ ++ if (!ppBufPtr) { ++ WMT_ERR_FUNC("invalid ppBufptr!\n"); ++ return -1; ++ } ++ *ppBufPtr = NULL; ++ ++ fd = filp_open(pName, O_RDONLY, 0); ++ if (IS_ERR(fd)) { ++ WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); ++ return -2; ++ } ++ ++ if(fd->f_op == NULL) { ++ printk(KERN_ERR "invalid file op \r\n"); ++ return -3; ++ } ++ ++#if 0 ++ if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { ++ WMT_ERR_FUNC("failed to open or read!(0x%p, %d, %d, %d)\n", fd, PTR_ERR(fd), cred->fsuid, cred->fsgid); ++ if (IS_ERR(fd)) ++ WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); ++ return -1; ++ } ++#endif ++ file_len = fd->f_path.dentry->d_inode->i_size; ++ file_len = fd->f_op->llseek(fd, 0, 2); ++ fd->f_op->llseek(fd, 0, 0); ++ pBuf = vmalloc((file_len + BCNT_PATCH_BUF_HEADROOM + 3) & ~0x3UL); ++ if (!pBuf) { ++ WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32) ((file_len + 3) & ~0x3UL)); ++ goto read_file_done; ++ } ++ ++ do { ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ WMT_ERR_FUNC("failed to seek!!\n"); ++ goto read_file_done; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ fs=get_fs(); ++ read_len = vfs_read(fd, pBuf + padSzBuf, file_len, &fd->f_pos); ++ set_fs(fs); ++ if (read_len != file_len) ++ WMT_WARN_FUNC("read abnormal: read_len(%d), file_len(%d)\n", read_len, file_len); ++ ++ } while (false); ++ ++ iRet = 0; ++ *ppBufPtr = pBuf; ++ ++read_file_done: ++ if (iRet) { ++ if (pBuf) ++ vfree(pBuf); ++ ++ } ++ ++ filp_close(fd, NULL); ++ ++ return (iRet) ? iRet : read_len; ++} ++ ++/* TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. */ ++INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf) ++{ ++ INT32 iRet = -1; ++ osal_firmware *pfw; ++ uid_t orig_uid; ++ gid_t orig_gid; ++ ++ /* struct cred *cred = get_task_cred(current); */ ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ mm_segment_t orig_fs = get_fs(); ++ ++ if (*ppPatch) { ++ WMT_WARN_FUNC("f/w patch already exists\n"); ++ if ((*ppPatch)->data) ++ vfree((*ppPatch)->data); ++ ++ kfree(*ppPatch); ++ *ppPatch = NULL; ++ } ++ ++ if (!osal_strlen(pPatchName)) { ++ WMT_ERR_FUNC("empty f/w name\n"); ++ osal_assert((osal_strlen(pPatchName) > 0)); ++ return -1; ++ } ++ ++ pfw = kzalloc(sizeof(osal_firmware), /*GFP_KERNEL */ GFP_ATOMIC); ++ if (!pfw) { ++ WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(osal_firmware)); ++ return -2; ++ } ++ ++ orig_uid = cred->fsuid.val; ++ orig_gid = cred->fsgid.val; ++ cred->fsuid.val = cred->fsgid.val = 0; ++ ++ set_fs(get_ds()); ++ ++ /* load patch file from fs */ ++ iRet = wmt_dev_read_file(pPatchName, (const PPUINT8)&pfw->data, 0, padSzBuf); ++ set_fs(orig_fs); ++ ++ cred->fsuid.val = orig_uid; ++ cred->fsgid.val = orig_gid; ++ ++ ++ if (iRet > 0) { ++ pfw->size = iRet; ++ *ppPatch = pfw; ++ WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName, pfw->data); ++ return 0; ++ } ++ kfree(pfw); ++ *ppPatch = NULL; ++ WMT_ERR_FUNC("load file (%s) fail, iRet(%d)\n", pPatchName, iRet); ++ return -1; ++} ++ ++INT32 wmt_dev_patch_put(osal_firmware **ppPatch) ++{ ++ if (NULL != *ppPatch) { ++ if ((*ppPatch)->data) ++ vfree((*ppPatch)->data); ++ ++ kfree(*ppPatch); ++ *ppPatch = NULL; ++ } ++ return 0; ++} ++ ++VOID wmt_dev_patch_info_free(VOID) ++{ ++ ++ kfree(pPatchInfo); ++ pPatchInfo = NULL; ++ ++} ++ ++MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName) ++{ ++ struct file *fd = NULL; ++ /* ssize_t iRet; */ ++ INT32 fileLen = -1; ++ const struct cred *cred = get_current_cred(); ++ ++ if (pFileName == NULL) { ++ WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) { ++ WMT_ERR_FUNC("invalid file name(%s)\n", pFileName); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ /* struct cred *cred = get_task_cred(current); */ ++ ++ fd = filp_open(pFileName, O_RDONLY, 0); ++ if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { ++ WMT_ERR_FUNC("failed to open or read(%s)!(0x%p, %d, %d)\n", pFileName, fd, cred->fsuid, cred->fsgid); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ fileLen = fd->f_path.dentry->d_inode->i_size; ++ filp_close(fd, NULL); ++ fd = NULL; ++ if (fileLen <= 0) { ++ WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName, fileLen); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName, fileLen); ++ return true; ++ ++} ++ ++/* static unsigned long count_last_access_sdio = 0; */ ++static unsigned long count_last_access_btif; ++static unsigned long jiffies_last_poll; ++ ++#if 0 ++static INT32 wmt_dev_tra_sdio_update(void) ++{ ++ count_last_access_sdio += 1; ++ /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */ ++ ++ return 0; ++} ++#endif ++ ++extern INT32 wmt_dev_tra_bitf_update(void) ++{ ++ count_last_access_btif += 1; ++ /* WMT_INFO_FUNC("jiffies_last_access_btif: jiffies = %ul\n", jiffies); */ ++ ++ return 0; ++} ++ ++static UINT32 wmt_dev_tra_ahb_poll(void) ++{ ++#define TIME_THRESHOLD_TO_TEMP_QUERY 3000 ++#define COUNT_THRESHOLD_TO_TEMP_QUERY 200 ++ ++ unsigned long ahb_during_count = 0; ++ unsigned long poll_during_time = 0; ++ ++ /* if (jiffies > jiffies_last_poll) */ ++ if (time_after(jiffies, jiffies_last_poll)) ++ poll_during_time = jiffies - jiffies_last_poll; ++ else ++ poll_during_time = 0xffffffff; ++ ++ ++ WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %lu\n", jiffies_to_msecs(0xffffffff)); ++ ++ if (jiffies_to_msecs(poll_during_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { ++ WMT_DBG_FUNC("**poll_during_time = %lu < %lu, not to query\n", ++ jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY); ++ return -1; ++ } ++ /* ahb_during_count = count_last_access_sdio; */ ++ if (NULL == mtk_wcn_wlan_bus_tx_cnt) { ++ WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt null pointer\n"); ++ return -1; ++ } ++ ahb_during_count = (*mtk_wcn_wlan_bus_tx_cnt) (); ++ ++ if (ahb_during_count < COUNT_THRESHOLD_TO_TEMP_QUERY) { ++ WMT_DBG_FUNC("**ahb_during_count = %lu < %lu, not to query\n", ++ ahb_during_count, COUNT_THRESHOLD_TO_TEMP_QUERY); ++ return -2; ++ } ++ ++ if (NULL == mtk_wcn_wlan_bus_tx_cnt_clr) { ++ WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt_clr null pointer\n"); ++ return -3; ++ } ++ (*mtk_wcn_wlan_bus_tx_cnt_clr) (); ++ /* count_last_access_sdio = 0; */ ++ jiffies_last_poll = jiffies; ++ ++ WMT_INFO_FUNC("**poll_during_time = %lu > %lu, ahb_during_count = %lu > %lu, query\n", ++ jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY, ++ jiffies_to_msecs(ahb_during_count), COUNT_THRESHOLD_TO_TEMP_QUERY); ++ ++ return 0; ++} ++ ++long wmt_dev_tm_temp_query(void) ++{ ++#define HISTORY_NUM 5 ++#define TEMP_THRESHOLD 65 ++#define REFRESH_TIME 300 /* sec */ ++ ++ static INT32 temp_table[HISTORY_NUM] = { 99 }; /* not query yet. */ ++ static INT32 idx_temp_table; ++ static struct timeval query_time, now_time; ++ ++ INT8 query_cond = 0; ++ INT32 current_temp = 0; ++ INT32 index = 0; ++ long return_temp = 0; ++ /* Query condition 1: */ ++ /* If we have the high temperature records on the past, we continue to query/monitor */ ++ /* the real temperature until cooling */ ++ for (index = 0; index < HISTORY_NUM; index++) { ++ if (temp_table[index] >= TEMP_THRESHOLD) { ++ query_cond = 1; ++ WMT_DBG_FUNC("temperature table is still initial value, we should query temp temperature..\n"); ++ } ++ } ++ ++ do_gettimeofday(&now_time); ++#if 1 ++ /* Query condition 2: */ ++ /* Moniter the ahb bus activity to decide if we have the need to query temperature. */ ++ if (!query_cond) { ++ if (wmt_dev_tra_ahb_poll() == 0) { ++ query_cond = 1; ++ WMT_INFO_FUNC("ahb traffic , we must query temperature..\n"); ++ } else { ++ WMT_DBG_FUNC("ahb idle traffic ....\n"); ++ } ++ ++ /* only WIFI tx power might make temperature varies largely */ ++#if 0 ++ if (!query_cond) { ++ last_access_time = wmt_dev_tra_uart_poll(); ++ if (jiffies_to_msecs(last_access_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { ++ query_cond = 1; ++ WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n"); ++ } else { ++ WMT_DBG_FUNC("uart still idle traffic , we don't query temp temperature..\n"); ++ } ++ } ++#endif ++ } ++#endif ++ /* Query condition 3: */ ++ /* If the query time exceeds the a certain of period, refresh temp table. */ ++ /* */ ++ if (!query_cond) { ++ /* time overflow, we refresh temp table again for simplicity! */ ++ if ((now_time.tv_sec < query_time.tv_sec) || ++ ((now_time.tv_sec > query_time.tv_sec) && (now_time.tv_sec - query_time.tv_sec) > REFRESH_TIME)) { ++ query_cond = 1; ++ ++ WMT_INFO_FUNC("It is long time (> %d sec) not to query, we must query temp temperature..\n", ++ REFRESH_TIME); ++ for (index = 0; index < HISTORY_NUM; index++) ++ temp_table[index] = 99; ++ ++ } ++ } ++ ++ if (query_cond) { ++ /* update the temperature record */ ++ mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE); ++ current_temp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ); ++ mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE); ++ idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; ++ temp_table[idx_temp_table] = current_temp; ++ do_gettimeofday(&query_time); ++ ++ WMT_INFO_FUNC("[Thermal] current_temp = 0x%x\n", (current_temp & 0xFF)); ++ } else { ++ current_temp = temp_table[idx_temp_table]; ++ idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; ++ temp_table[idx_temp_table] = current_temp; ++ } ++ ++ /* */ ++ /* Dump information */ ++ /* */ ++ WMT_DBG_FUNC("[Thermal] idx_temp_table = %d\n", idx_temp_table); ++ WMT_DBG_FUNC("[Thermal] now.time = %d, query.time = %d, REFRESH_TIME = %d\n", now_time.tv_sec, ++ query_time.tv_sec, REFRESH_TIME); ++ ++ WMT_DBG_FUNC("[0] = %d, [1] = %d, [2] = %d, [3] = %d, [4] = %d\n----\n", ++ temp_table[0], temp_table[1], temp_table[2], temp_table[3], temp_table[4]); ++ ++ return_temp = ((current_temp & 0x80) == 0x0) ? current_temp : (-1) * (current_temp & 0x7f); ++ ++ return return_temp; ++} ++ ++ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 iRet = 0; ++ UINT8 wrBuf[NAME_MAX + 1] = { 0 }; ++ INT32 copySize = (count < NAME_MAX) ? count : NAME_MAX; ++ ++ WMT_LOUD_FUNC("count:%d copySize:%d\n", count, copySize); ++ ++ if (copySize > 0) { ++ if (copy_from_user(wrBuf, buf, copySize)) { ++ iRet = -EFAULT; ++ goto write_done; ++ } ++ iRet = copySize; ++ wrBuf[NAME_MAX] = '\0'; ++ ++ if (!strncasecmp(wrBuf, "ok", NAME_MAX)) { ++ WMT_DBG_FUNC("resp str ok\n"); ++ /* pWmtDevCtx->cmd_result = 0; */ ++ wmt_lib_trigger_cmd_signal(0); ++ } else { ++ WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf); ++ /* pWmtDevCtx->cmd_result = -1; */ ++ wmt_lib_trigger_cmd_signal(-1); ++ } ++ /* complete(&pWmtDevCtx->cmd_comp); */ ++ ++ } ++ ++write_done: ++ return iRet; ++} ++ ++ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 iRet = 0; ++ PUINT8 pCmd = NULL; ++ UINT32 cmdLen = 0; ++ ++ pCmd = wmt_lib_get_cmd(); ++ ++ if (pCmd != NULL) { ++ cmdLen = osal_strlen(pCmd) < NAME_MAX ? osal_strlen(pCmd) : NAME_MAX; ++ WMT_DBG_FUNC("cmd str(%s)\n", pCmd); ++ if (copy_to_user(buf, pCmd, cmdLen)) ++ iRet = -EFAULT; ++ else ++ iRet = cmdLen; ++ ++ } ++#if 0 ++ if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { ++ iRet = osal_strlen(localBuf) < NAME_MAX ? osal_strlen(localBuf) : NAME_MAX; ++ /* we got something from STP driver */ ++ WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf); ++ if (copy_to_user(buf, localBuf, iRet)) { ++ iRet = -EFAULT; ++ goto read_done; ++ } ++ } ++#endif ++ return iRet; ++} ++ ++unsigned int WMT_poll(struct file *filp, poll_table *wait) ++{ ++ UINT32 mask = 0; ++ P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event(); ++ ++ poll_wait(filp, &pEvent->waitQueue, wait); ++ /* empty let select sleep */ ++ if (MTK_WCN_BOOL_TRUE == wmt_lib_get_cmd_status()) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ ++#if 0 ++ if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ ++#endif ++ mask |= POLLOUT | POLLWRNORM; /* writable */ ++ return mask; ++} ++ ++/* INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) */ ++long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ ++ INT32 iRet = 0; ++ UINT8 *pBuffer = NULL; ++ ++ WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); ++ switch (cmd) { ++ case WMT_IOCTL_SET_PATCH_NAME: /* patch location */ ++ { ++ ++ pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++ if (!pBuffer) { ++ WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); ++ return 0; ++ } ++ if (copy_from_user(pBuffer, (void *)arg, NAME_MAX)) { ++ iRet = -EFAULT; ++ kfree(pBuffer); ++ break; ++ } ++ pBuffer[NAME_MAX] = '\0'; ++ wmt_lib_set_patch_name(pBuffer); ++ kfree(pBuffer); ++ } ++ break; ++ ++ case WMT_IOCTL_SET_STP_MODE: /* stp/hif/fm mode */ ++ ++ /* set hif conf */ ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal = NULL; ++ P_WMT_HIF_CONF pHif = NULL; ++ ++ iRet = wmt_lib_set_hif(arg); ++ if (0 != iRet) { ++ WMT_INFO_FUNC("wmt_lib_set_hif fail\n"); ++ break; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_INFO_FUNC("get_free_lxop fail\n"); ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_HIF_CONF; ++ ++ pHif = wmt_lib_get_hif(); ++ ++ osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF)); ++ pOp->op.u4InfoBit = WMT_OP_HIF_BIT; ++ pSignal->timeoutValue = 0; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d)\n", bRet); ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_FUNC_ONOFF_CTRL: /* test turn on/off func */ ++ ++ do { ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (arg & 0x80000000) ++ bRet = mtk_wcn_wmt_func_on(arg & 0xF); ++ else ++ bRet = mtk_wcn_wmt_func_off(arg & 0xF); ++ ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_LPBK_POWER_CTRL: ++ /*switch Loopback function on/off ++ arg: bit0 = 1:turn loopback function on ++ bit0 = 0:turn loopback function off ++ */ ++ do { ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (arg & 0x01) ++ bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); ++ else ++ bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); ++ ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_LPBK_TEST: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 u4Wait; ++ /* UINT8 lpbk_buf[1024] = {0}; */ ++ UINT32 effectiveLen = 0; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ if (copy_from_user(&effectiveLen, (void *)arg, sizeof(effectiveLen))) { ++ iRet = -EFAULT; ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ break; ++ } ++ if (effectiveLen > sizeof(gLpbkBuf)) { ++ iRet = -EFAULT; ++ WMT_ERR_FUNC("length is too long\n"); ++ break; ++ } ++ WMT_DBG_FUNC("len = %d\n", effectiveLen); ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ u4Wait = 2000; ++ if (copy_from_user(&gLpbkBuf[0], (void *)arg + sizeof(unsigned long), effectiveLen)) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_LPBK; ++ pOp->op.au4OpData[0] = effectiveLen; /* packet length */ ++ pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; /* packet buffer pointer */ ++ memcpy(&gLpbkBufLog, &gLpbkBuf[((effectiveLen >= 4) ? effectiveLen - 4 : 0)], 4); ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", ++ pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n", ++ pOp->op.opId, pOp->op.au4OpData[0], gLpbkBufLog); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ if (copy_to_user((void *)arg + sizeof(SIZE_T) + sizeof(UINT8[2048]), gLpbkBuf, iRet)) { ++ iRet = -EFAULT; ++ break; ++ } ++ ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_ADIE_LPBK_TEST: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_ADIE_LPBK_TEST; ++ pOp->op.au4OpData[0] = 0; ++ pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d)abort\n", pOp->op.opId); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ if (copy_to_user((void *)arg + sizeof(SIZE_T), gLpbkBuf, iRet)) { ++ iRet = -EFAULT; ++ break; ++ } ++ ++ } while (0); ++ ++ break; ++ ++ case 10: ++ { ++ pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++ if (!pBuffer) { ++ WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); ++ return 0; ++ } ++ wmt_lib_host_awake_get(); ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ osal_strcpy(pBuffer, "MT662x f/w coredump start-"); ++ if (copy_from_user ++ (pBuffer + osal_strlen(pBuffer), (void *)arg, NAME_MAX - osal_strlen(pBuffer))) { ++ /* osal_strcpy(pBuffer, "MT662x f/w assert core dump start"); */ ++ WMT_ERR_FUNC("copy assert string failed\n"); ++ } ++ pBuffer[NAME_MAX] = '\0'; ++ osal_dbg_assert_aee(pBuffer, pBuffer); ++ kfree(pBuffer); ++ } ++ break; ++ case 11: ++ { ++ osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); ++ wmt_lib_host_awake_put(); ++ } ++ break; ++ ++ case WMT_IOCTL_GET_CHIP_INFO: ++ { ++ if (0 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_CHIPID); ++ else if (1 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_HWVER); ++ else if (2 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_FWVER); ++ ++ } ++ break; ++ ++ case WMT_IOCTL_SET_LAUNCHER_KILL:{ ++ if (1 == arg) { ++ WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n"); ++ wmt_lib_set_stp_wmt_last_close(1); ++ } else { ++ wmt_lib_set_stp_wmt_last_close(0); ++ } ++ ++ } ++ break; ++ ++ case WMT_IOCTL_SET_PATCH_NUM:{ ++ pAtchNum = arg; ++ WMT_DBG_FUNC(" get patch num from launcher = %d\n", pAtchNum); ++ wmt_lib_set_patch_num(pAtchNum); ++ pPatchInfo = kcalloc(pAtchNum, sizeof(WMT_PATCH_INFO), GFP_ATOMIC); ++ if (!pPatchInfo) { ++ WMT_ERR_FUNC("allocate memory fail!\n"); ++ break; ++ } ++ } ++ break; ++ ++ case WMT_IOCTL_SET_PATCH_INFO:{ ++ WMT_PATCH_INFO wMtPatchInfo; ++ P_WMT_PATCH_INFO pTemp = NULL; ++ UINT32 dWloadSeq; ++ static UINT32 counter; ++ ++ if (!pPatchInfo) { ++ WMT_ERR_FUNC("NULL patch info pointer\n"); ++ break; ++ } ++ ++ if (copy_from_user(&wMtPatchInfo, (void *)arg, sizeof(WMT_PATCH_INFO))) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ ++ dWloadSeq = wMtPatchInfo.dowloadSeq; ++ WMT_DBG_FUNC( ++ "patch dl seq %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n", ++ dWloadSeq, wMtPatchInfo.patchName, ++ wMtPatchInfo.addRess[0], ++ wMtPatchInfo.addRess[1], ++ wMtPatchInfo.addRess[2], ++ wMtPatchInfo.addRess[3]); ++ osal_memcpy(pPatchInfo + dWloadSeq - 1, &wMtPatchInfo, sizeof(WMT_PATCH_INFO)); ++ pTemp = pPatchInfo + dWloadSeq - 1; ++ if (++counter == pAtchNum) { ++ wmt_lib_set_patch_info(pPatchInfo); ++ counter = 0; ++ } ++ } ++ break; ++ ++ case WMT_IOCTL_WMT_COREDUMP_CTRL: ++ mtk_wcn_stp_coredump_flag_ctrl(arg); ++ break; ++ case WMT_IOCTL_WMT_QUERY_CHIPID: ++ { ++ iRet = mtk_wcn_wmt_chipid_query(); ++ WMT_WARN_FUNC("chipid = 0x%x\n", iRet); ++ } ++ break; ++ case WMT_IOCTL_SEND_BGW_DS_CMD: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT8 desense_buf[14] = { 0 }; ++ UINT32 effectiveLen = 14; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ if (copy_from_user(&desense_buf[0], (void *)arg, effectiveLen)) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_BGW_DS; ++ pOp->op.au4OpData[0] = effectiveLen; /* packet length */ ++ pOp->op.au4OpData[1] = (SIZE_T) &desense_buf[0]; /* packet buffer pointer */ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,opid(%d) abort\n", pOp->op.opId); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ ++ } while (0); ++ ++ break; ++ case WMT_IOCTL_FW_DBGLOG_CTRL: ++ { ++ iRet = wmt_plat_set_dbg_mode(arg); ++ if (iRet == 0) ++ wmt_dbg_fwinfor_from_emi(0, 1, 0); ++ } ++ break; ++ case WMT_IOCTL_DYNAMIC_DUMP_CTRL: ++ { ++ UINT32 i = 0, j = 0, k = 0; ++ UINT8 *pBuf = NULL; ++ UINT32 int_buf[10]; ++ char Buffer[10][11]; ++ ++ pBuf = kmalloc(DYNAMIC_DUMP_BUF + 1, GFP_KERNEL); ++ if (!pBuf) { ++ WMT_ERR_FUNC("pBuf kmalloc memory fail\n"); ++ return 0; ++ } ++ if (copy_from_user(pBuf, (void *)arg, DYNAMIC_DUMP_BUF)) { ++ iRet = -EFAULT; ++ kfree(pBuf); ++ break; ++ } ++ pBuf[DYNAMIC_DUMP_BUF] = '\0'; ++ WMT_INFO_FUNC("get dynamic dump data from property(%s)\n", pBuf); ++ memset(Buffer, 0, 10*11); ++ for (i = 0; i < DYNAMIC_DUMP_BUF; i++) { ++ if (pBuf[i] == '/') { ++ k = 0; ++ j++; ++ } else { ++ Buffer[j][k] = pBuf[i]; ++ k++; ++ } ++ } ++ for (j = 0; j < 10; j++) { ++ iRet = kstrtou32(Buffer[j], 0, &int_buf[j]); ++ if (iRet) { ++ WMT_ERR_FUNC("string convert fail(%d)\n", iRet); ++ break; ++ } ++ WMT_INFO_FUNC("dynamic dump data buf[%d]:(0x%x)\n", j, int_buf[j]); ++ } ++ wmt_plat_set_dynamic_dumpmem(int_buf); ++ kfree(pBuf); ++ } ++ break; ++ default: ++ iRet = -EINVAL; ++ WMT_WARN_FUNC("unknown cmd (%d)\n", cmd); ++ break; ++ } ++ ++ return iRet; ++} ++#ifdef CONFIG_COMPAT ++long WMT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ WMT_INFO_FUNC("cmd[0x%x]\n", cmd); ++ switch (cmd) { ++ case COMPAT_WMT_IOCTL_SET_PATCH_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_LPBK_TEST: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_LPBK_TEST, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_SET_PATCH_INFO: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_INFO, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_PORT_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_PORT_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_WMT_CFG_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_WMT_CFG_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SEND_BGW_DS_CMD, (unsigned long)compat_ptr(arg)); ++ break; ++ default: { ++ ret = WMT_unlocked_ioctl(filp, cmd, arg); ++ break; ++ } ++ } ++ return ret; ++} ++#endif ++static int WMT_open(struct inode *inode, struct file *file) ++{ ++ long ret; ++ ++ WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ret = wait_event_timeout(gWmtInitWq, gWmtInitDone != 0, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); ++ if (!ret) { ++ WMT_WARN_FUNC("wait_event_timeout (%d)ms,(%d)jiffies,return -EIO\n", ++ WMT_DEV_INIT_TO_MS, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); ++ return -EIO; ++ } ++ ++ if (atomic_inc_return(&gWmtRefCnt) == 1) ++ WMT_INFO_FUNC("1st call\n"); ++ ++ return 0; ++} ++ ++static int WMT_close(struct inode *inode, struct file *file) ++{ ++ WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ if (atomic_dec_return(&gWmtRefCnt) == 0) ++ WMT_INFO_FUNC("last call\n"); ++ ++ return 0; ++} ++ ++const struct file_operations gWmtFops = { ++ .open = WMT_open, ++ .release = WMT_close, ++ .read = WMT_read, ++ .write = WMT_write, ++/* .ioctl = WMT_ioctl, */ ++ .unlocked_ioctl = WMT_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = WMT_compat_ioctl, ++#endif ++ .poll = WMT_poll, ++}; ++ ++void wmt_dev_bgw_desense_init(VOID) ++{ ++ bgw_init_socket(); ++} ++ ++void wmt_dev_bgw_desense_deinit(VOID) ++{ ++ bgw_destroy_netlink_kernel(); ++} ++ ++void wmt_dev_send_cmd_to_daemon(UINT32 cmd) ++{ ++ send_command_to_daemon(cmd); ++} ++ ++static int WMT_init(void) ++{ ++ dev_t devID = MKDEV(gWmtMajor, 0); ++ INT32 cdevErr = -1; ++ INT32 ret = -1; ++ ++ WMT_INFO_FUNC("WMT Version= %s DATE=%s\n", MTK_WMT_VERSION, MTK_WMT_DATE); ++ /* Prepare a UINT8 device */ ++ /*static allocate chrdev */ ++ gWmtInitDone = 0; ++ init_waitqueue_head((wait_queue_head_t *) &gWmtInitWq); ++ stp_drv_init(); ++ ++ ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME); ++ if (ret) { ++ WMT_ERR_FUNC("fail to register chrdev\n"); ++ return ret; ++ } ++ cdev_init(&gWmtCdev, &gWmtFops); ++ gWmtCdev.owner = THIS_MODULE; ++ cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM); ++ if (cdevErr) { ++ WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); ++ goto error; ++ } ++ WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor); ++#if WMT_CREATE_NODE_DYNAMIC ++ wmt_class = class_create(THIS_MODULE, "stpwmt"); ++ if (IS_ERR(wmt_class)) ++ goto error; ++ wmt_dev = device_create(wmt_class, NULL, devID, NULL, "stpwmt"); ++ if (IS_ERR(wmt_dev)) ++ goto error; ++#endif ++ ++#if 0 ++ pWmtDevCtx = wmt_drv_create(); ++ if (!pWmtDevCtx) { ++ WMT_ERR_FUNC("wmt_drv_create() fails\n"); ++ goto error; ++ } ++ ret = wmt_drv_init(pWmtDevCtx); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret); ++ goto error; ++ } ++ WMT_INFO_FUNC("stp_btmcb_reg\n"); ++ wmt_cdev_btmcb_reg(); ++ ret = wmt_drv_start(pWmtDevCtx); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret); ++ goto error; ++ } ++#endif ++ ret = wmt_lib_init(); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret); ++ goto error; ++ } ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_setup(); ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ wmt_dev_proc_for_aee_setup(); ++#endif ++ ++ WMT_INFO_FUNC("wmt_dev register thermal cb\n"); ++ wmt_lib_register_thermal_ctrl_cb(wmt_dev_tm_temp_query); ++ wmt_dev_bgw_desense_init(); ++ gWmtInitDone = 1; ++ wake_up(&gWmtInitWq); ++ osal_sleepable_lock_init(&g_es_lr_lock); ++ INIT_WORK(&gPwrOnOffWork, wmt_pwr_on_off_handler); ++#ifdef CONFIG_EARLYSUSPEND ++ register_early_suspend(&wmt_early_suspend_handler); ++ WMT_INFO_FUNC("register_early_suspend finished\n"); ++#else ++ wmt_fb_notifier.notifier_call = wmt_fb_notifier_callback; ++ ret = fb_register_client(&wmt_fb_notifier); ++ if (ret) ++ WMT_ERR_FUNC("wmt register fb_notifier failed! ret(%d)\n", ret); ++ else ++ WMT_INFO_FUNC("wmt register fb_notifier OK!\n"); ++#endif ++ WMT_INFO_FUNC("success\n"); ++ return 0; ++ ++error: ++ wmt_lib_deinit(); ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_remove(); ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!(IS_ERR(wmt_dev))) ++ device_destroy(wmt_class, devID); ++ if (!(IS_ERR(wmt_class))) { ++ class_destroy(wmt_class); ++ wmt_class = NULL; ++ } ++#endif ++ ++ if (cdevErr == 0) ++ cdev_del(&gWmtCdev); ++ ++ if (ret == 0) { ++ unregister_chrdev_region(devID, WMT_DEV_NUM); ++ gWmtMajor = -1; ++ } ++ ++ WMT_ERR_FUNC("fail\n"); ++ ++ return -1; ++} ++ ++static void WMT_exit(void) ++{ ++ dev_t dev = MKDEV(gWmtMajor, 0); ++ ++ osal_sleepable_lock_deinit(&g_es_lr_lock); ++#ifdef CONFIG_EARLYSUSPEND ++ unregister_early_suspend(&wmt_early_suspend_handler); ++ WMT_INFO_FUNC("unregister_early_suspend finished\n"); ++#else ++ fb_unregister_client(&wmt_fb_notifier); ++#endif ++ ++ wmt_dev_bgw_desense_deinit(); ++ ++ wmt_lib_register_thermal_ctrl_cb(NULL); ++ ++ wmt_lib_deinit(); ++ ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_remove(); ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ wmt_dev_proc_for_aee_remove(); ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++ if (wmt_dev) { ++ device_destroy(wmt_class, dev); ++ wmt_dev = NULL; ++ } ++ if (wmt_class) { ++ class_destroy(wmt_class); ++ wmt_class = NULL; ++ } ++#endif ++ cdev_del(&gWmtCdev); ++ unregister_chrdev_region(dev, WMT_DEV_NUM); ++ gWmtMajor = -1; ++ ++ stp_drv_exit(); ++ ++ WMT_INFO_FUNC("done\n"); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++int mtk_wcn_soc_common_drv_init(void) ++{ ++ return WMT_init(); ++ ++} ++EXPORT_SYMBOL(mtk_wcn_soc_common_drv_init); ++void mtk_wcn_soc_common_drv_exit(void) ++{ ++ return WMT_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_soc_common_drv_exit); ++ ++#else ++module_init(WMT_init); ++module_exit(WMT_exit); ++#endif ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("MediaTek Inc WCN"); ++MODULE_DESCRIPTION("MTK WCN combo driver for WMT function"); ++ ++module_param(gWmtMajor, uint, 0); +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c +new file mode 100644 +index 000000000000..9f2192d9a3e5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c +@@ -0,0 +1,610 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-EXP]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include ++#include ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++wmt_wlan_probe_cb mtk_wcn_wlan_probe = NULL; ++wmt_wlan_remove_cb mtk_wcn_wlan_remove = NULL; ++wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt = NULL; ++wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr = NULL; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++OSAL_BIT_OP_VAR gBtWifiGpsState; ++OSAL_BIT_OP_VAR gGpsFmState; ++UINT32 gWifiProbed = 0; ++UINT32 gWmtDbgLvl = WMT_LOG_DBG; ++MTK_WCN_BOOL g_pwr_off_flag = MTK_WCN_BOOL_TRUE; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = opId; ++ pOp->op.au4OpData[0] = type; ++ if (WMTDRV_TYPE_WIFI == type) ++ pSignal->timeoutValue = 4000; ++ /*donot block system server/init/netd from longer than 5s, in case of ANR happens*/ ++ else ++ pSignal->timeoutValue = (WMT_OPID_FUNC_ON == pOp->op.opId) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ /*do not check return value, we will do this either way */ ++ wmt_lib_host_awake_get(); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ wmt_lib_host_awake_put(); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ wmt_lib_host_awake_put(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ else ++ WMT_WARN_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return bRet; ++} ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++#endif ++{ ++ MTK_WCN_BOOL ret; ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT OFF ====>"); ++ ++ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF); ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT OFF <===="); ++ ++ return ret; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_func_off); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++#endif ++{ ++ MTK_WCN_BOOL ret; ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT ON ====>"); ++ ++ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON); ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday(" ############BT ON <===="); ++ ++ return ret; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_func_on); ++#endif ++ ++VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type) ++{ ++ if (on) ++ mtk_wcn_wmt_func_on(type); ++ else ++ mtk_wcn_wmt_func_off(type); ++} ++ ++/* ++return value: ++enable/disable thermal sensor function: true(1)/false(0) ++read thermal sensor function:thermal value ++ ++*/ ++#if WMT_EXP_HID_API_EXPORT ++INT8 _mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++#else ++INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++#endif ++{ ++ P_OSAL_OP pOp; ++ P_WMT_OP pOpData; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /*parameter validation check */ ++ if (WMTTHERM_MAX < eType || WMTTHERM_ENABLE > eType) { ++ WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ /*check if chip support thermal control function or not */ ++ bRet = wmt_lib_is_therm_ctrl_support(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("thermal ctrl function not supported\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pOpData = &pOp->op; ++ pOpData->opId = WMT_OPID_THERM_CTRL; ++ /*parameter fill */ ++ pOpData->au4OpData[0] = eType; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ /*0xFF means read error occurs */ ++ /*will return to function driver */ ++ pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE; ++ } else { ++ WMT_INFO_FUNC("OPID(%d) type(%d) return(%d) ok\n\n", ++ pOpData->opId, pOpData->au4OpData[0], pOpData->au4OpData[1]); ++ } ++ /*return value will be put to lxop->op.au4OpData[1] */ ++ WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08x)\n", eType, pOpData->au4OpData[1]); ++ return (INT8) pOpData->au4OpData[1]; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++ENUM_WMTHWVER_TYPE_T _mtk_wcn_wmt_hwver_get(VOID) ++#else ++ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) ++#endif ++{ ++ /* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ ++ /* TODO: how do we extend for new chip and newer revision? */ ++ /* TODO: This way is hard to extend */ ++ return wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++#endif ++{ ++ P_OSAL_OP pOp; ++ P_WMT_OP pOpData; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (WMTDSNS_MAX <= eType) { ++ WMT_ERR_FUNC("invalid desense control command (%d)\n", eType); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ /*check if chip support thermal control function or not */ ++ bRet = wmt_lib_is_dsns_ctrl_support(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("thermal ctrl function not supported\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pOpData = &pOp->op; ++ pOpData->opId = WMT_OPID_DSNS; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*parameter fill */ ++ if ((WMTDSNS_FM_DISABLE <= eType) && (WMTDSNS_FM_GPS_ENABLE >= eType)) { ++ pOpData->au4OpData[0] = WMTDRV_TYPE_FM; ++ pOpData->au4OpData[1] = eType; ++ } ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ else ++ WMT_INFO_FUNC("OPID(%d) type(%d) ok\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ ++ return bRet; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++#else ++INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++#endif ++{ ++ return (INT32) wmt_lib_msgcb_reg(eType, pCb); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++#else ++INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++#endif ++{ ++ return (INT32) wmt_lib_msgcb_unreg(eType); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++#else ++INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++#endif ++{ ++ wmt_lib_ps_set_sdio_psop(own_cb); ++ return 0; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++#else ++INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++#endif ++{ ++ wmt_lib_ps_irq_cb(); ++ return 0; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++#endif ++{ ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ wmt_lib_set_host_assert_info(type, reason, 1); ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = WMT_OPID_CMD_TEST; ++ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*this test command should be run with usb cable connected, so no host awake is needed */ ++ /* wmt_lib_host_awake_get(); */ ++ pOp->op.au4OpData[0] = 0; ++ ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,assert flow abort\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ /* wmt_lib_host_awake_put(); */ ++ WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", ++ pOp->op.opId, ++ pOp->op.au4OpData[0], ++ pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ return bRet; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_assert); ++#endif ++ ++INT8 mtk_wcn_wmt_co_clock_flag_get(void) ++{ ++ return wmt_lib_co_clock_get(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_co_clock_flag_get); ++ ++INT32 mtk_wcn_wmt_system_state_reset(void) ++{ ++ osal_memset(&gBtWifiGpsState, 0, osal_sizeof(gBtWifiGpsState)); ++ osal_memset(&gGpsFmState, 0, osal_sizeof(gGpsFmState)); ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo) ++{ ++ INT32 iRet = -1; ++ ++ if (!pWmtWlanCbInfo) { ++ WMT_ERR_FUNC("wlan cb info in null!\n"); ++ return -1; ++ } ++ ++ WMT_INFO_FUNC("wmt wlan cb register\n"); ++ mtk_wcn_wlan_probe = pWmtWlanCbInfo->wlan_probe_cb; ++ mtk_wcn_wlan_remove = pWmtWlanCbInfo->wlan_remove_cb; ++ mtk_wcn_wlan_bus_tx_cnt = pWmtWlanCbInfo->wlan_bus_cnt_get_cb; ++ mtk_wcn_wlan_bus_tx_cnt_clr = pWmtWlanCbInfo->wlan_bus_cnt_clr_cb; ++ ++ if (gWifiProbed) { ++ WMT_INFO_FUNC("wlan has been done power on,call probe directly\n"); ++ iRet = (*mtk_wcn_wlan_probe) (); ++ if (!iRet) { ++ WMT_INFO_FUNC("call wlan probe OK when do wlan register to wmt\n"); ++ gWifiProbed = 0; ++ } else { ++ WMT_ERR_FUNC("call wlan probe fail(%d) when do wlan register to wmt\n", iRet); ++ return -2; ++ } ++ } ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wlan_reg); ++ ++INT32 mtk_wcn_wmt_wlan_unreg(void) ++{ ++ WMT_INFO_FUNC("wmt wlan cb unregister\n"); ++ mtk_wcn_wlan_probe = NULL; ++ mtk_wcn_wlan_remove = NULL; ++ mtk_wcn_wlan_bus_tx_cnt = NULL; ++ mtk_wcn_wlan_bus_tx_cnt_clr = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wlan_unreg); ++ ++MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value) ++{ ++ g_pwr_off_flag = value; ++ if (g_pwr_off_flag) ++ WMT_DBG_FUNC("enable connsys power off flag\n"); ++ else ++ WMT_INFO_FUNC("disable connsys power off, maybe need trigger coredump!\n"); ++ return g_pwr_off_flag; ++} ++EXPORT_SYMBOL(mtk_wcn_set_connsys_power_off_flag); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++VOID mtk_wcn_wmt_exp_init(void) ++{ ++ MTK_WCN_WMT_EXP_CB_INFO wmtExpCb = { ++ ++ .wmt_func_on_cb = _mtk_wcn_wmt_func_on, ++ .wmt_func_off_cb = _mtk_wcn_wmt_func_off, ++ .wmt_therm_ctrl_cb = _mtk_wcn_wmt_therm_ctrl, ++ .wmt_hwver_get_cb = _mtk_wcn_wmt_hwver_get, ++ .wmt_dsns_ctrl_cb = _mtk_wcn_wmt_dsns_ctrl, ++ .wmt_msgcb_reg_cb = _mtk_wcn_wmt_msgcb_reg, ++ .wmt_msgcb_unreg_cb = _mtk_wcn_wmt_msgcb_unreg, ++ .wmt_sdio_op_reg_cb = _mtk_wcn_stp_wmt_sdio_op_reg, ++ .wmt_sdio_host_awake_cb = _mtk_wcn_stp_wmt_sdio_host_awake, ++ .wmt_assert_cb = _mtk_wcn_wmt_assert ++ }; ++ ++ mtk_wcn_wmt_exp_cb_reg(&wmtExpCb); ++} ++ ++VOID mtk_wcn_wmt_exp_deinit(void) ++{ ++ mtk_wcn_wmt_exp_cb_unreg(); ++} ++#ifdef CONFIG_MTK_COMBO_ANT ++/* ++ ctrlId: get ram code status opId or ram code download opId ++ pBuf: pointer to ANT ram code ++ length: total length of ANT ram code ++*/ ++ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, ++ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq) ++{ ++ ENUM_WMT_ANT_RAM_STATUS eRet = 0; ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ /*1. parameter validation check */ ++ /*for WMT_ANT_RAM_GET_STATUS, ignore pBuf and length */ ++ /*for WMT_ANT_RAM_DOWNLOAD, ++ pBuf must not be NULL, kernel space memory pointer ++ length must be large than 0 */ ++ ++ if ((WMT_ANT_RAM_GET_STATUS > ctrlId) || (WMT_ANT_RAM_CTRL_MAX <= ctrlId)) { ++ WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); ++ eRet = WMT_ANT_RAM_PARA_ERR; ++ return eRet; ++ } ++ ++ if ((WMT_ANT_RAM_DOWNLOAD == ctrlId) && ++ ((NULL == pBuf) || ++ (0 >= length) || ++ (1000 < length) || (seq >= WMT_ANT_RAM_SEQ_MAX) || (seq < WMT_ANT_RAM_START_PKT))) { ++ eRet = WMT_ANT_RAM_PARA_ERR; ++ WMT_ERR_FUNC ++ ("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x),seq(%d) .\n", ++ ctrlId, pBuf, length, seq); ++ return eRet; ++ } ++ /*get WMT opId */ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_DBG_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = ++ (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD; ++ ++ pOp->op.opId = ++ (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? WMT_OPID_ANT_RAM_DOWN : WMT_OPID_ANT_RAM_STA_GET; ++ pOp->op.au4OpData[0] = (size_t) pBuf; ++ pOp->op.au4OpData[1] = length; ++ pOp->op.au4OpData[2] = seq; ++ ++ ++ /*disable PSM monitor */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ /*wakeup wmtd thread */ ++ bRet = wmt_lib_put_act_op(pOp); ++ ++ /*enable PSM monitor */ ++ ENABLE_PSM_MONITOR(); ++ ++ WMT_DBG_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n", ++ pOp->op.opId, ++ bRet, ++ pOp->op.au4OpData[2], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ /*check return value and return result */ ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ eRet = WMT_ANT_RAM_OP_ERR; ++ } else { ++ eRet = (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? ++ WMT_ANT_RAM_DOWN_OK : ++ ((1 == pOp->op.au4OpData[2]) ? WMT_ANT_RAM_EXIST : WMT_ANT_RAM_NOT_EXIST); ++ } ++ ++ return eRet; ++ ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_ant_ram_ctrl); ++#endif ++ ++#endif ++VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value) ++{ ++ wmt_lib_soc_set_wifiver(Value); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_set_wifi_ver); +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +new file mode 100644 +index 000000000000..eb37baf87b02 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +@@ -0,0 +1,27 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../../linux/include \ ++ -I$(src)/../../linux/pri/include \ ++ -I$(src)/../../core/include \ ++ -I$(src)/../../include \ ++ -I$(src)/../include \ ++ -I$(src)/../../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach \ ++ -DMTK_BT_HCI=1 ++ ++ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 ++ ++ifeq ($(CONFIG_MTK_TC1_FEATURE), y) ++ ccflags-y += -DCFG_TC1_FEATURE=1 ++else ++ ccflags-y += -DCFG_TC1_FEATURE=0 ++endif ++ ++obj-y += osal.o \ ++ bgw_desense.o \ ++ wmt_idc.o ++obj-$(CONFIG_MTK_COMBO_BT) += stp_chrdev_bt.o ++obj-$(CONFIG_MTK_COMBO_WIFI) += wmt_chrdev_wifi.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c +new file mode 100644 +index 000000000000..11e45aa13087 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c +@@ -0,0 +1,153 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include "bgw_desense.h" ++ ++static struct sock *g_nl_sk; ++/* static struct sockaddr_nl src_addr, des_addr; */ ++/* static struct iovec iov; */ ++static int pid; ++/* static struct msghdr msg; */ ++ ++void bgw_destroy_netlink_kernel(void) ++{ ++ if (g_nl_sk != NULL) { ++ /* sock_release(g_nl_sk->sk_socket); */ ++ netlink_kernel_release(g_nl_sk); ++ MSG("release socket\n"); ++ return; ++ } ++ ERR("no socket yet\n"); ++} ++ ++void send_command_to_daemon(const int command /*struct sk_buff *skb */) ++{ ++/* ++ struct iphdr *iph; ++ struct ethhdr *ehdr; ++ */ ++ struct nlmsghdr *nlh; ++ struct sk_buff *nl_skb; ++ int res; ++ ++ MSG("here we will send command to native daemon\n"); ++/* if(skb == NULL) ++ { ++ ERR("invalid sk_buff\n"); ++ return; ++ } ++*/ ++ if (!g_nl_sk) { ++ ERR("invalid socket\n"); ++ return; ++ } ++ if (pid == 0) { ++ ERR("invalid native process pid\n"); ++ return; ++ } ++ /*alloc data buffer for sending to native */ ++ /*malloc data space at least 1500 bytes, which is ethernet data length */ ++ nl_skb = alloc_skb(NLMSG_SPACE(MAX_NL_MSG_LEN), GFP_ATOMIC); ++ if (nl_skb == NULL) { ++ ERR("malloc skb error\n"); ++ return; ++ } ++ MSG("malloc data space done\n"); ++ /* ++ ehdr = eth_hdr(skb); ++ iph = ip_hdr(skb); ++ */ ++ ++/* nlh = NLMSG_PUT(nl_skb, 0, 0, 0, NLMSG_SPACE(1500)-sizeof(struct nlmsghdr)); */ ++ nlh = nlmsg_put(nl_skb, 0, 0, 0, MAX_NL_MSG_LEN, 0); ++ if (nlh == NULL) { ++ MSG("nlh is NULL\n"); ++ kfree_skb(nl_skb); ++ return; ++ } ++ NETLINK_CB(nl_skb).portid = 0; ++ ++/* memcpy(NLMSG_DATA(nlh), ACK, 5); */ ++ *(char *)NLMSG_DATA(nlh) = command; ++ res = netlink_unicast(g_nl_sk, nl_skb, pid, MSG_DONTWAIT); ++ if (res == 0) { ++ MSG("send to user space process error\n"); ++ return; ++ } ++ ERR("send to user space process done, data length = %d\n", res); ++} ++ ++static void nl_data_handler(struct sk_buff *__skb) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ int i; ++ int len; ++ char str[128]; ++ ++ MSG("we got netlink message\n"); ++ len = NLMSG_SPACE(MAX_NL_MSG_LEN); ++ skb = skb_get(__skb); ++ if (skb == NULL) ++ ERR("skb_get return NULL"); ++ if (skb->len >= NLMSG_SPACE(0)) { /*presume there is 5byte payload at leaset */ ++ MSG("length is enough\n"); ++ nlh = nlmsg_hdr(skb); /* point to data which include in skb */ ++ memcpy(str, NLMSG_DATA(nlh), sizeof(str)); ++ for (i = 0; i < 3; i++) ++ MSG("str[%d = %c]", i, str[i]); ++ MSG("str[0] = %d, str[1] = %d, str[2] = %d\n", str[0], str[1], str[2]); ++ if (str[0] == 'B' && str[1] == 'G' && str[2] == 'W') { ++ MSG("got native daemon init command, record it's pid\n"); ++ pid = nlh->nlmsg_pid; /*record the native process PID */ ++ MSG("native daemon pid is %d\n", pid); ++ } else { ++ ERR("this is not BGW message, ignore it\n"); ++ return; ++ } ++ } else { ++ ERR("not engouth data length\n"); ++ return; ++ } ++ ++ kfree_skb(skb); ++ ++ send_command_to_daemon(ACK); ++} ++ ++int bgw_init_socket(void) ++{ ++ struct netlink_kernel_cfg cfg; ++ ++ memset(&cfg, 0, sizeof(cfg)); ++ cfg.input = nl_data_handler; ++ ++ g_nl_sk = __netlink_kernel_create(&init_net, NETLINK_TEST, THIS_MODULE, &cfg); ++ ++ if (g_nl_sk == NULL) { ++ ERR("netlink_kernel_create error\n"); ++ return -1; ++ } ++ MSG("netlink_kernel_create ok\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c +new file mode 100644 +index 000000000000..4ebbd51c0259 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c +@@ -0,0 +1,1210 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ ++static UINT16 const crc16_table[256] = { ++ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, ++ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, ++ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, ++ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, ++ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, ++ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, ++ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, ++ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, ++ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, ++ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, ++ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, ++ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, ++ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, ++ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, ++ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, ++ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, ++ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, ++ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, ++ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, ++ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, ++ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, ++ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, ++ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, ++ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, ++ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, ++ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, ++ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, ++ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, ++ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, ++ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, ++ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, ++ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 ++}; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*string operations*/ ++_osal_inline_ UINT32 osal_strlen(const char *str) ++{ ++ return strlen(str); ++} ++ ++_osal_inline_ INT32 osal_strcmp(const char *dst, const char *src) ++{ ++ return strcmp(dst, src); ++} ++ ++_osal_inline_ INT32 osal_strncmp(const char *dst, const char *src, UINT32 len) ++{ ++ return strncmp(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strcpy(char *dst, const char *src) ++{ ++ return strcpy(dst, src); ++} ++ ++_osal_inline_ char *osal_strncpy(char *dst, const char *src, UINT32 len) ++{ ++ return strncpy(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strcat(char *dst, const char *src) ++{ ++ return strcat(dst, src); ++} ++ ++_osal_inline_ char *osal_strncat(char *dst, const char *src, UINT32 len) ++{ ++ return strncat(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strchr(const char *str, UINT8 c) ++{ ++ return strchr(str, c); ++} ++ ++_osal_inline_ char *osal_strsep(char **str, const char *c) ++{ ++ return strsep(str, c); ++} ++ ++_osal_inline_ int osal_strtol(const char *str, UINT32 adecimal, long *res) ++{ ++ return kstrtol(str, adecimal, res); ++} ++ ++_osal_inline_ char *osal_strstr(char *str1, const char *str2) ++{ ++ return strstr(str1, str2); ++} ++ ++INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...) ++{ ++ INT32 iRet = 0; ++ va_list args; ++ ++ /*va_start(args, fmt); */ ++ va_start(args, fmt); ++ /*iRet = snprintf(buf, len, fmt, args); */ ++ iRet = vsnprintf(buf, len, fmt, args); ++ va_end(args); ++ ++ return iRet; ++} ++ ++INT32 osal_err_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_err("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_dbg_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_debug("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_warn_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_warn("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line) ++{ ++ if (!expr) { ++ pr_warn("%s (%d)\n", file, line); ++ /*BUG_ON(!expr); */ ++#ifdef CFG_COMMON_GPIO_DBG_PIN ++/* package this part */ ++ mt_set_gpio_out(GPIO70, GPIO_OUT_ZERO); ++ pr_warn("toggle GPIO70\n"); ++ udelay(10); ++ mt_set_gpio_out(GPIO70, GPIO_OUT_ONE); ++#endif ++ return 1; ++ } ++ return 0; ++ ++} ++ ++INT32 osal_dbg_assert_aee(const char *module, const char *detail_description) ++{ ++ osal_err_print("[WMT-ASSERT]" "[E][Module]:%s, [INFO]%s\n", module, detail_description); ++ ++#ifdef WMT_PLAT_ALPS ++ /* aee_kernel_warning(module,detail_description); */ ++ aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_WCN_ISSUE_INFO, module, detail_description); ++#endif ++ return 0; ++} ++ ++INT32 osal_sprintf(char *str, const char *format, ...) ++{ ++ INT32 iRet = 0; ++ va_list args; ++ ++ va_start(args, format); ++ iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); ++ va_end(args); ++ ++ return iRet; ++} ++ ++_osal_inline_ VOID *osal_malloc(UINT32 size) ++{ ++ return vmalloc(size); ++} ++ ++_osal_inline_ VOID osal_free(const VOID *dst) ++{ ++ vfree(dst); ++} ++ ++_osal_inline_ VOID *osal_memset(VOID *buf, INT32 i, UINT32 len) ++{ ++ return memset(buf, i, len); ++} ++ ++_osal_inline_ VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len) ++{ ++#ifdef CONFIG_MTK_WCN_ARM64 ++ char *tmp; ++ const char *s; ++ size_t i; ++ ++ tmp = dst; ++ s = src; ++ for (i = 0; i < len; i++) ++ tmp[i] = s[i]; ++ ++ return dst; ++ ++#else ++ return memcpy(dst, src, len); ++#endif ++} ++ ++_osal_inline_ INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len) ++{ ++ return memcmp(buf1, buf2, len); ++} ++ ++_osal_inline_ UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length) ++{ ++ UINT16 crc = 0; ++ UINT32 i = 0; ++ ++ /* FIXME: Add STP checksum feature */ ++ crc = 0; ++ for (i = 0; i < length; i++, buffer++) ++ crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; ++ ++ return crc; ++} ++ ++_osal_inline_ VOID osal_thread_show_stack(P_OSAL_THREAD pThread) ++{ ++ return show_stack(pThread->pThread, NULL); ++} ++ ++/* ++ *OSAL layer Thread Opeartion related APIs ++ * ++ * ++*/ ++_osal_inline_ INT32 osal_thread_create(P_OSAL_THREAD pThread) ++{ ++ pThread->pThread = kthread_create(pThread->pThreadFunc, pThread->pThreadData, pThread->threadName); ++ if (NULL == pThread->pThread) ++ return -1; ++ ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_thread_run(P_OSAL_THREAD pThread) ++{ ++ if (pThread->pThread) { ++ wake_up_process(pThread->pThread); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_thread_stop(P_OSAL_THREAD pThread) ++{ ++ INT32 iRet; ++ ++ if ((pThread) && (pThread->pThread)) { ++ iRet = kthread_stop(pThread->pThread); ++ /* pThread->pThread = NULL; */ ++ return iRet; ++ } ++ return -1; ++} ++ ++_osal_inline_ INT32 osal_thread_should_stop(P_OSAL_THREAD pThread) ++{ ++ if ((pThread) && (pThread->pThread)) ++ return kthread_should_stop(); ++ else ++ return 1; ++ ++} ++ ++_osal_inline_ INT32 ++osal_thread_wait_for_event(P_OSAL_THREAD pThread, P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker) ++{ ++ /* P_DEV_WMT pDevWmt;*/ ++ ++ if ((pThread) && (pThread->pThread) && (pEvent) && (pChecker)) { ++ /* pDevWmt = (P_DEV_WMT)(pThread->pThreadData);*/ ++ return wait_event_interruptible(pEvent->waitQueue, (/*!RB_EMPTY(&pDevWmt->rActiveOpQ) || */ ++ osal_thread_should_stop(pThread) ++ || (*pChecker) (pThread))); ++ } ++ return -1; ++} ++ ++_osal_inline_ INT32 osal_thread_destroy(P_OSAL_THREAD pThread) ++{ ++ if (pThread && (pThread->pThread)) { ++ kthread_stop(pThread->pThread); ++ pThread->pThread = NULL; ++ } ++ return 0; ++} ++ ++/* ++ *OSAL layer Signal Opeartion related APIs ++ *initialization ++ *wait for signal ++ *wait for signal timerout ++ *raise signal ++ *destroy a signal ++ * ++*/ ++ ++_osal_inline_ INT32 osal_signal_init(P_OSAL_SIGNAL pSignal) ++{ ++ if (pSignal) { ++ init_completion(&pSignal->comp); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_wait_for_signal(P_OSAL_SIGNAL pSignal) ++{ ++ if (pSignal) { ++ wait_for_completion_interruptible(&pSignal->comp); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal) ++{ ++ /* return wait_for_completion_interruptible_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); */ ++ /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. ++ * Avoid using *interruptible" version in order to complete our jobs, such ++ * as function off gracefully. ++ */ ++ return wait_for_completion_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); ++} ++ ++_osal_inline_ INT32 osal_raise_signal(P_OSAL_SIGNAL pSignal) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ ++ complete(&pSignal->comp); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_signal_deinit(P_OSAL_SIGNAL pSignal) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ ++ pSignal->timeoutValue = 0; ++ return 0; ++} ++ ++/* ++ *OSAL layer Event Opeartion related APIs ++ *initialization ++ *wait for signal ++ *wait for signal timerout ++ *raise signal ++ *destroy a signal ++ * ++*/ ++ ++INT32 osal_event_init(P_OSAL_EVENT pEvent) ++{ ++ init_waitqueue_head(&pEvent->waitQueue); ++ ++ return 0; ++} ++ ++INT32 osal_wait_for_event(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) ++{ ++ return wait_event_interruptible(pEvent->waitQueue, condition(cond_pa)); ++} ++ ++INT32 osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) ++{ ++ return wait_event_interruptible_timeout(pEvent->waitQueue, condition(cond_pa), ++ msecs_to_jiffies(pEvent->timeoutValue)); ++} ++ ++INT32 osal_trigger_event(P_OSAL_EVENT pEvent) ++{ ++ INT32 ret = 0; ++ ++ wake_up_interruptible(&pEvent->waitQueue); ++ return ret; ++} ++ ++INT32 osal_event_deinit(P_OSAL_EVENT pEvent) ++{ ++ return 0; ++} ++ ++_osal_inline_ long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) ++{ ++ UINT32 ms = pEvent->timeoutValue; ++ ++ if (ms != 0) { ++ return wait_event_interruptible_timeout(pEvent->waitQueue, test_bit(bitOffset, pState), ++ msecs_to_jiffies(ms)); ++ } else { ++ return wait_event_interruptible(pEvent->waitQueue, test_bit(bitOffset, pState)); ++ } ++ ++} ++ ++_osal_inline_ long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) ++{ ++ UINT32 ms = pEvent->timeoutValue; ++ ++ if (ms != 0) { ++ return wait_event_interruptible_timeout(pEvent->waitQueue, !test_bit(bitOffset, pState), ++ msecs_to_jiffies(ms)); ++ } else { ++ return wait_event_interruptible(pEvent->waitQueue, !test_bit(bitOffset, pState)); ++ } ++ ++} ++ ++/* ++ *bit test and set/clear operations APIs ++ * ++ * ++*/ ++#if OS_BIT_OPS_SUPPORT ++#define osal_bit_op_lock(x) ++#define osal_bit_op_unlock(x) ++#else ++ ++_osal_inline_ INT32 osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) ++{ ++ ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) ++{ ++ ++ return 0; ++} ++#endif ++_osal_inline_ INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ osal_bit_op_lock(&(pData->opLock)); ++ clear_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ osal_bit_op_lock(&(pData->opLock)); ++ set_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++} ++ ++_osal_inline_ INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_and_clear_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++ ++} ++ ++_osal_inline_ INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_and_set_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++} ++ ++/* ++ *tiemr operations APIs ++ *create ++ *stop ++ * modify ++ *create ++ *delete ++ * ++*/ ++ ++INT32 osal_timer_create(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ init_timer(timer); ++ timer->function = pTimer->timeoutHandler; ++ timer->data = (unsigned long)pTimer->timeroutHandlerData; ++ return 0; ++} ++ ++INT32 osal_timer_start(P_OSAL_TIMER pTimer, UINT32 ms) ++{ ++ ++ struct timer_list *timer = &pTimer->timer; ++ ++ timer->expires = jiffies + (ms / (1000 / HZ)); ++ add_timer(timer); ++ return 0; ++} ++ ++INT32 osal_timer_stop(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ del_timer(timer); ++ return 0; ++} ++ ++INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ del_timer_sync(timer); ++ return 0; ++} ++ ++INT32 osal_timer_modify(P_OSAL_TIMER pTimer, UINT32 ms) ++{ ++ ++ mod_timer(&pTimer->timer, jiffies + (ms) / (1000 / HZ)); ++ return 0; ++} ++ ++INT32 _osal_fifo_init(OSAL_FIFO *pFifo, UINT8 *buf, UINT32 size) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = -1; ++ ++ if (!pFifo) { ++ pr_err("pFifo must be !NULL\n"); ++ return -1; ++ } ++ if (pFifo->pFifoBody) { ++ pr_err("pFifo->pFifoBody must be NULL\n"); ++ pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", pFifo, pFifo->pFifoBody); ++ return -1; ++ } ++ fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); ++ if (!buf) { ++ /*fifo's buffer is not ready, we allocate automatically */ ++ ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC); ++ } else { ++ if (is_power_of_2(size)) { ++ kfifo_init(fifo, buf, size); ++ ret = 0; ++ } else { ++ kfifo_free(fifo); ++ fifo = NULL; ++ ret = -1; ++ } ++ } ++ ++ pFifo->pFifoBody = fifo; ++ return (ret < 0) ? (-1) : (0); ++} ++ ++INT32 _osal_fifo_deinit(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ kfifo_free(fifo); ++ ++ return 0; ++} ++ ++INT32 _osal_fifo_size(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_size(fifo); ++ ++ return ret; ++} ++ ++/*returns unused bytes in fifo*/ ++INT32 _osal_fifo_avail_size(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_avail(fifo); ++ ++ return ret; ++} ++ ++/*returns used bytes in fifo*/ ++INT32 _osal_fifo_len(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_len(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_is_empty(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_is_empty(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_is_full(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_is_full(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_data_in(OSAL_FIFO *pFifo, const VOID *buf, UINT32 len) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) { ++ ret = kfifo_in(fifo, buf, len); ++ } else { ++ pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", ++ __func__, len, _osal_fifo_avail_size(pFifo), buf); ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, UINT32 len) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo && buf && (len <= _osal_fifo_len(pFifo))) { ++ ret = kfifo_out(fifo, buf, len); ++ } else { ++ pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", ++ __func__, len, _osal_fifo_len(pFifo), buf); ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_reset(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ kfifo_reset(fifo); ++ ++ return 0; ++} ++ ++INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size) ++{ ++ if (!pFifo) { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ pFifo->FifoInit = _osal_fifo_init; ++ pFifo->FifoDeInit = _osal_fifo_deinit; ++ pFifo->FifoSz = _osal_fifo_size; ++ pFifo->FifoAvailSz = _osal_fifo_avail_size; ++ pFifo->FifoLen = _osal_fifo_len; ++ pFifo->FifoIsEmpty = _osal_fifo_is_empty; ++ pFifo->FifoIsFull = _osal_fifo_is_full; ++ pFifo->FifoDataIn = _osal_fifo_data_in; ++ pFifo->FifoDataOut = _osal_fifo_data_out; ++ pFifo->FifoReset = _osal_fifo_reset; ++ ++ if (NULL != pFifo->pFifoBody) { ++ pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__); ++ pFifo->FifoDeInit(pFifo->pFifoBody); ++ pFifo->pFifoBody = NULL; ++ } ++ ++ pFifo->FifoInit(pFifo, buffer, size); ++ ++ return 0; ++} ++ ++VOID osal_fifo_deinit(P_OSAL_FIFO pFifo) ++{ ++ if (pFifo) ++ pFifo->FifoDeInit(pFifo); ++ else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ return; ++ } ++ kfree(pFifo->pFifoBody); ++} ++ ++INT32 osal_fifo_reset(P_OSAL_FIFO pFifo) ++{ ++ INT32 ret = -1; ++ ++ if (pFifo) { ++ ret = pFifo->FifoReset(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = -1; ++ } ++ return ret; ++} ++ ++UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoDataIn(pFifo, buffer, size); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoDataOut(pFifo, buffer, size); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_len(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoLen(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoSz(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoAvailSz(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoIsEmpty(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoIsFull(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ return ret; ++} ++ ++INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_init(&pLock->wake_lock, pLock->name); ++ #else ++ wake_lock_init(&pLock->wake_lock, WAKE_LOCK_SUSPEND, pLock->name); ++ #endif ++ return 0; ++} ++ ++INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_trash(&pLock->wake_lock); ++ #else ++ wake_lock_destroy(&pLock->wake_lock); ++ #endif ++ return 0; ++} ++ ++INT32 osal_wake_lock(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_stay_awake(&pLock->wake_lock); ++ #else ++ wake_lock(&pLock->wake_lock); ++ #endif ++ ++ return 0; ++} ++ ++INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_relax(&pLock->wake_lock); ++ #else ++ wake_unlock(&pLock->wake_lock); ++ #endif ++ ++ return 0; ++ ++} ++ ++INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock) ++{ ++ INT32 count = 0; ++ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ count = pLock->wake_lock.active; ++ #else ++ count = wake_lock_active(&pLock->wake_lock); ++ #endif ++ return count; ++} ++ ++/* ++ *sleepable lock operations APIs ++ *init ++ *lock ++ *unlock ++ *destroy ++ * ++*/ ++ ++#if !defined(CONFIG_PROVE_LOCKING) ++INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_lock_init(&(pUSL->lock)); ++ return 0; ++} ++#endif ++ ++INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_lock_irqsave(&(pUSL->lock), pUSL->flag); ++ return 0; ++} ++ ++INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); ++ return 0; ++} ++ ++INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ return 0; ++} ++ ++/* ++ *unsleepable operations APIs ++ *init ++ *lock ++ *unlock ++ *destroy ++ ++ * ++*/ ++ ++#if !defined(CONFIG_PROVE_LOCKING) ++INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_init(&pSL->lock); ++ return 0; ++} ++#endif ++ ++INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ return mutex_lock_killable(&pSL->lock); ++} ++ ++INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_unlock(&pSL->lock); ++ return 0; ++} ++ ++INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_destroy(&pSL->lock); ++ return 0; ++} ++ ++INT32 osal_sleep_ms(UINT32 ms) ++{ ++ msleep(ms); ++ return 0; ++} ++ ++INT32 osal_udelay(UINT32 us) ++{ ++ udelay(us); ++ return 0; ++} ++ ++INT32 osal_gettimeofday(PINT32 sec, PINT32 usec) ++{ ++ INT32 ret = 0; ++ struct timeval now; ++ ++ do_gettimeofday(&now); ++ ++ if (sec != NULL) ++ *sec = now.tv_sec; ++ else ++ ret = -1; ++ ++ if (usec != NULL) ++ *usec = now.tv_usec; ++ else ++ ret = -1; ++ ++ return ret; ++} ++ ++INT32 osal_printtimeofday(const PUINT8 prefix) ++{ ++ INT32 ret; ++ INT32 sec; ++ INT32 usec; ++ ++ ret = osal_gettimeofday(&sec, &usec); ++ ret += osal_dbg_print("%s>sec=%d, usec=%d\n", prefix, sec, usec); ++ ++ return ret; ++} ++ ++VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, const UINT32 len, const UINT32 limit) ++{ ++ INT32 k; ++ UINT32 dump_len; ++ ++ pr_warn("start of dump>[%s] len=%d, limit=%d,", title, len, limit); ++ ++ dump_len = ((0 != limit) && (len > limit)) ? limit : len; ++#if 0 ++ if (limit != 0) ++ len = (len > limit) ? (limit) : (len); ++ ++#endif ++ ++ for (k = 0; k < dump_len; k++) { ++ if ((k != 0) && (k % 16 == 0)) ++ pr_cont("\n"); ++ pr_cont("0x%02x ", buf[k]); ++ } ++ pr_warn("op.opId : 0xFFFFFFFF; ++} ++ ++MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) ++{ ++ return (pOp && pOp->signal.timeoutValue) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; ++} ++ ++VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result) ++{ ++ if (pOp) { ++ pOp->result = result; ++ osal_raise_signal(&pOp->signal); ++ } ++} ++ ++VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result) ++{ ++ if (pOp) ++ pOp->result = result; ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +new file mode 100644 +index 000000000000..190fa3944d80 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +@@ -0,0 +1,899 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if WMT_CREATE_NODE_DYNAMIC ++#include ++#endif ++#include ++ ++#include "osal_typedef.h" ++#include "stp_exp.h" ++#include "wmt_exp.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++#ifdef MTK_BT_HCI ++#define MTK_BT_DEBUG 0 ++#include ++#include ++#endif ++ ++ ++#define BT_DRIVER_NAME "mtk_stp_BT_chrdev" ++#define BT_DEV_MAJOR 192 /* Never used number */ ++ ++#define PFX "[MTK-BT] " ++#define BT_LOG_DBG 3 ++#define BT_LOG_INFO 2 ++#define BT_LOG_WARN 1 ++#define BT_LOG_ERR 0 ++ ++#define COMBO_IOC_MAGIC 0xb0 ++#define COMBO_IOCTL_FW_ASSERT _IOWR(COMBO_IOC_MAGIC, 0, int) ++#define COMBO_IOCTL_BT_IC_HW_VER _IOWR(COMBO_IOC_MAGIC, 1, void*) ++#define COMBO_IOCTL_BT_IC_FW_VER _IOWR(COMBO_IOC_MAGIC, 2, void*) ++#define COMBO_IOC_BT_HWVER _IOWR(COMBO_IOC_MAGIC, 3, void*) ++ ++static UINT32 gDbgLevel = BT_LOG_INFO; ++ ++#define BT_DBG_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_DBG) \ ++ pr_debug(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_INFO_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_INFO) \ ++ pr_warn(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_WARN_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_WARN) \ ++ pr_err(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_ERR_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_ERR) \ ++ pr_err(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++ ++#define VERSION "1.0" ++ ++#ifdef MTK_BT_HCI ++ ++#define NUM_REASSEMBLY 32 ++struct mtk_hci { ++ struct hci_dev *hdev; ++ struct work_struct work; ++ struct sk_buff_head txq; ++ struct sk_buff *reassembly[NUM_REASSEMBLY]; ++}; ++ ++static struct mtk_hci mtk_hci; ++ ++#endif ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *stpbt_class = NULL; ++struct device *stpbt_dev = NULL; ++#endif ++ ++static INT32 BT_devs = 1; /* Device count */ ++static INT32 BT_major = BT_DEV_MAJOR; /* Dynamic allocation */ ++module_param(BT_major, uint, 0); ++static struct cdev BT_cdev; ++ ++#define BT_BUFFER_SIZE 2048 ++static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer of read() */ ++static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer of write() */ ++ ++static struct semaphore wr_mtx, rd_mtx; ++/* Wait queue for poll and read */ ++static wait_queue_head_t inq; ++static DECLARE_WAIT_QUEUE_HEAD(BT_wq); ++static INT32 flag; ++/* Reset flag for whole chip reset senario */ ++static volatile INT32 rstflag; ++ ++#ifdef MTK_BT_HCI ++static int hci_reassembly(struct hci_dev *hdev, int type, void *data, ++ int count, __u8 index) ++{ ++ int len = 0; ++ int hlen = 0; ++ int offset = 0; ++ int remain = count; ++ struct sk_buff *skb; ++ struct bt_skb_cb *scb; ++ u16 opcode = 0; ++ unsigned char *pdata = data; ++ ++ struct mtk_hci *info = NULL; ++ struct hci_event_hdr *ehdr = NULL; ++ struct hci_ev_cmd_complete *ev = NULL; ++ struct hci_rp_read_local_ext_features *ext = NULL; ++ ++ info = hci_get_drvdata(hdev); ++ if ( NULL == info ) { ++ printk(KERN_ERR "mtk_bt_hci: invalid info point\n"); ++ return 0; ++ } ++ ++ if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || ++ index >= NUM_REASSEMBLY) ++ return -EILSEQ; ++ ++ skb = info->reassembly[index]; ++ ++ if (!skb) { ++ switch (type) { ++ case HCI_ACLDATA_PKT: ++ len = HCI_MAX_FRAME_SIZE; ++ hlen = HCI_ACL_HDR_SIZE; ++ break; ++ case HCI_EVENT_PKT: ++ len = HCI_MAX_EVENT_SIZE; ++ hlen = HCI_EVENT_HDR_SIZE; ++ break; ++ case HCI_SCODATA_PKT: ++ len = HCI_MAX_SCO_SIZE; ++ hlen = HCI_SCO_HDR_SIZE; ++ break; ++ } ++ ++ skb = bt_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) ++ return -ENOMEM; ++ ++ scb = (void *) skb->cb; ++ scb->expect = hlen; ++ scb->pkt_type = type; ++ ++ info->reassembly[index] = skb; ++ } ++ ++ while (count) { ++ scb = (void *) skb->cb; ++ len = min_t(uint, scb->expect, count); ++ ++ /* ++ * Workaround for MT7623+MT6625 BT: the max page in response of cmd READ_LOCAL_EXT_FEATURES ++ * should be 1, instead of 2, so changing it to 1 here ++ */ ++ ++ if (HCI_EVENT_PKT == type) ++ { ++ ehdr = (void *)pdata; ++ offset = sizeof(struct hci_event_hdr); ++ if ( HCI_EV_CMD_COMPLETE == ehdr->evt) ++ { ++ ev = (struct hci_ev_cmd_complete *)&pdata[offset]; ++ ++ offset += sizeof(struct hci_ev_cmd_complete); ++ ++ opcode = __le16_to_cpu(ev->opcode); ++ if(HCI_OP_READ_LOCAL_EXT_FEATURES == opcode) { ++ ext = (struct hci_rp_read_local_ext_features *) &pdata[offset]; ++ if( !ext->status && ext->max_page >= 2) { ++ pr_info("%s: this workaround is applied for mediatek BT\n", __func__); ++ ext->max_page = 1; ++ } ++ } ++ ++ } ++ } ++ ++ memcpy(skb_put(skb, len), data, len); ++ ++ count -= len; ++ data += len; ++ scb->expect -= len; ++ remain = count; ++ ++ switch (type) { ++ case HCI_EVENT_PKT: ++ if (skb->len == HCI_EVENT_HDR_SIZE) { ++ struct hci_event_hdr *h = hci_event_hdr(skb); ++ ++ scb->expect = h->plen; ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ if (skb->len == HCI_ACL_HDR_SIZE) { ++ struct hci_acl_hdr *h = hci_acl_hdr(skb); ++ ++ scb->expect = __le16_to_cpu(h->dlen); ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ break; ++ ++ case HCI_SCODATA_PKT: ++ if (skb->len == HCI_SCO_HDR_SIZE) { ++ struct hci_sco_hdr *h = hci_sco_hdr(skb); ++ ++ scb->expect = h->dlen; ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ break; ++ } ++ ++ if (scb->expect == 0) { ++ /* Complete frame */ ++ ++ bt_cb(skb)->pkt_type = type; ++ hci_recv_frame(hdev, skb); ++ ++ info->reassembly[index] = NULL; ++ return remain; ++ } ++ } ++ ++ return remain; ++} ++ ++int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) ++{ ++ int rem = 0; ++ ++ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ++ return -EILSEQ; ++ ++ while (count) { ++ rem = hci_reassembly(hdev, type, data, count, type - 1); ++ if (rem < 0) ++ return rem; ++ ++ data += (count - rem); ++ count = rem; ++ } ++ ++ return rem; ++} ++#endif ++ ++#ifdef MTK_BT_HCI ++void ++hex_dump(char *prefix, char *p, int len) ++{ ++ int i; ++ ++ pr_err("%s ", prefix); ++ for (i = 0; i < len; i++) ++ pr_err("%02x ", (*p++ & 0xff)); ++ pr_err("\n"); ++} ++ ++static int ++mtk_bt_hci_open(struct hci_dev *hdev) ++{ ++ int err = 0; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ err = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); ++ if (err != MTK_WCN_BOOL_TRUE) { ++ pr_err("%s func on failed with %d\n", __func__, err); ++ return -ENODEV; ++ } ++ ++ set_bit(HCI_RUNNING, &hdev->flags); ++ ++ mtk_wcn_stp_set_bluez(1); ++ ++ return 0; ++} ++ ++static int ++mtk_bt_hci_close(struct hci_dev *hdev) ++{ ++ int err = 0; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ mtk_wcn_stp_set_bluez(0); ++ ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ ++ err = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ if (err != MTK_WCN_BOOL_TRUE) { ++ pr_err("%s func off failed with %d\n", __func__, err); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void ++mtk_bt_hci_work(struct work_struct *work) ++{ ++ int err; ++ struct sk_buff *skb; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ while ((skb = skb_dequeue(&mtk_hci.txq))) { ++ skb_push(skb, 1); ++ skb->data[0] = bt_cb(skb)->pkt_type; ++ ++#if MTK_BT_DEBUG == 1 ++ hex_dump(">>", skb->data, skb->len); ++#endif ++ ++ err = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX); ++ if (err < 0) { ++ pr_err("%s err=%d\n", __func__, err); ++ mtk_hci.hdev->stat.err_tx++; ++ skb_queue_head(&mtk_hci.txq, skb); ++ break; ++ } ++ ++ mtk_hci.hdev->stat.byte_tx += skb->len; ++ kfree_skb(skb); ++ } ++} ++ ++static int ++mtk_bt_hci_send(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ if (mtk_hci.hdev && !test_bit(HCI_RUNNING, &mtk_hci.hdev->flags)) ++ return -EBUSY; ++ ++ switch (bt_cb(skb)->pkt_type) { ++ case HCI_COMMAND_PKT: ++ mtk_hci.hdev->stat.cmd_tx++; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ mtk_hci.hdev->stat.acl_tx++; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ mtk_hci.hdev->stat.sco_tx++; ++ break; ++ ++ default: ++ return -EILSEQ; ++ } ++ ++ skb_queue_tail(&mtk_hci.txq, skb); ++ schedule_work(&mtk_hci.work); ++ ++ return 0; ++} ++ ++static int ++mtk_bt_hci_flush(struct hci_dev *hdev) ++{ ++ pr_err("%s: todo\n", __func__); ++ ++ return 0; ++} ++ ++static void ++mtk_bt_hci_receive(const PUINT8 data, INT32 size) ++{ ++ int err; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++ hex_dump("<<", data, size); ++#endif ++ ++ err = hci_recv_fragment(mtk_hci.hdev, data[0], (void *)&data[1], size - 1); ++ if (err < 0) ++ pr_err("%s: hci_recv_fragment failed with %d\n", __func__, err); ++ ++ if (mtk_hci.hdev) ++ mtk_hci.hdev->stat.byte_rx += size - 1; ++} ++ ++static void ++mtk_bt_hci_notify(struct hci_dev *hdev, unsigned int evt) ++{ ++ static const char * const notify_str[] = { ++ "null", ++ "HCI_NOTIFY_CONN_ADD", ++ "HCI_NOTIFY_CONN_DEL", ++ "HCI_NOTIFY_VOICE_SETTING" ++ }; ++ ++ if (evt > HCI_NOTIFY_VOICE_SETTING) ++ pr_info("%s event=0x%x\n", __func__, evt); ++ else ++ pr_info("%s event(%d)=%s\n", __func__, evt, notify_str[evt]); ++} ++#endif ++ ++#ifdef MTK_BT_HCI ++ ++int mtk_bt_hci_init(void) ++{ ++ INT32 hci_err = 0; ++ ++ mtk_hci.hdev = hci_alloc_dev(); ++ if (!(mtk_hci.hdev)) { ++ mtk_hci.hdev = NULL; ++ BT_ERR_FUNC("%s hci_alloc_dev failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ mtk_hci.hdev->bus = HCI_SDIO; ++ mtk_hci.hdev->open = mtk_bt_hci_open; ++ mtk_hci.hdev->close = mtk_bt_hci_close; ++ mtk_hci.hdev->send = mtk_bt_hci_send; ++ mtk_hci.hdev->flush = mtk_bt_hci_flush; ++ mtk_hci.hdev->notify = mtk_bt_hci_notify; ++ SET_HCIDEV_DEV(mtk_hci.hdev, stpbt_dev); ++ ++ hci_set_drvdata(mtk_hci.hdev, &mtk_hci); ++ ++ mtk_wcn_stp_register_if_rx(mtk_bt_hci_receive); ++ ++ hci_err = hci_register_dev(mtk_hci.hdev); ++ if (hci_err) { ++ BT_ERR_FUNC("%s hci_register_dev failed with %d\n", __func__, hci_err); ++ hci_free_dev(mtk_hci.hdev); ++ mtk_hci.hdev = NULL; ++ return hci_err; ++ } ++ ++ skb_queue_head_init(&mtk_hci.txq); ++ INIT_WORK(&mtk_hci.work, mtk_bt_hci_work); ++ ++ return 0; ++} ++#endif ++ ++ ++static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, ++ ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz) ++{ ++ /* ++ Handle whole chip reset messages ++ */ ++ ENUM_WMTRSTMSG_TYPE_T rst_msg; ++ ++ if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { ++ memcpy((PINT8)&rst_msg, (PINT8)buf, sz); ++ BT_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, ++ dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); ++ if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) ++ && (type == WMTMSG_TYPE_RESET)) { ++ if (rst_msg == WMTRSTMSG_RESET_START) { ++ BT_INFO_FUNC("BT reset start!\n"); ++ rstflag = 1; ++ wake_up_interruptible(&inq); ++ ++ } else if (rst_msg == WMTRSTMSG_RESET_END) { ++ BT_INFO_FUNC("BT reset end!\n"); ++ rstflag = 2; ++ wake_up_interruptible(&inq); ++ } ++ } ++ } else { ++ /* Invalid message format */ ++ BT_WARN_FUNC("Invalid message format!\n"); ++ } ++} ++ ++VOID BT_event_cb(VOID) ++{ ++ BT_DBG_FUNC("BT_event_cb()\n"); ++ ++ flag = 1; ++ ++ /* ++ * Finally, wake up any reader blocked in poll or read ++ */ ++ wake_up_interruptible(&inq); ++ wake_up(&BT_wq); ++} ++ ++unsigned int BT_poll(struct file *filp, poll_table *wait) ++{ ++ UINT32 mask = 0; ++ ++/* down(&wr_mtx); */ ++ /* ++ * The buffer is circular; it is considered full ++ * if "wp" is right behind "rp". "left" is 0 if the ++ * buffer is empty, and it is "1" if it is completely full. ++ */ ++ if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) { ++ poll_wait(filp, &inq, wait); ++ ++ if (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) || rstflag) ++ /* BT Rx queue has valid data, or whole chip reset occurs */ ++ mask |= POLLIN | POLLRDNORM; /* Readable */ ++ } else { ++ mask |= POLLIN | POLLRDNORM; /* Readable */ ++ } ++ ++ /* Do we need condition here? */ ++ mask |= POLLOUT | POLLWRNORM; /* Writable */ ++/* up(&wr_mtx); */ ++ return mask; ++} ++ ++ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = 0; ++ INT32 write_size; ++ INT32 written = 0; ++ ++ down(&wr_mtx); ++ ++ BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); ++ if (rstflag) { ++ if (rstflag == 1) { /* Reset start */ ++ retval = -88; ++ BT_INFO_FUNC("%s: detect whole chip reset start\n", __func__); ++ } else if (rstflag == 2) { /* Reset end */ ++ retval = -99; ++ BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); ++ } ++ goto OUT; ++ } ++ ++ if (count > 0) { ++ if (count < BT_BUFFER_SIZE) { ++ write_size = count; ++ } else { ++ write_size = BT_BUFFER_SIZE; ++ BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); ++ } ++ ++ if (copy_from_user(&o_buf[0], &buf[0], write_size)) { ++ retval = -EFAULT; ++ goto OUT; ++ } ++ ++ written = mtk_wcn_stp_send_data(&o_buf[0], write_size, BT_TASK_INDX); ++ if (0 == written) { ++ retval = -ENOSPC; ++ /* No space is available, native program should not call BT_write with no delay */ ++ BT_ERR_FUNC ++ ("Packet length %zd, sent length %d, retval = %d\n", ++ count, written, retval); ++ } else { ++ retval = written; ++ } ++ ++ } else { ++ retval = -EFAULT; ++ BT_ERR_FUNC("Packet length %zd is not allowed, retval = %d\n", count, retval); ++ } ++ ++OUT: ++ up(&wr_mtx); ++ return retval; ++} ++ ++ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ static int chip_reset_count; ++ INT32 retval = 0; ++ ++ down(&rd_mtx); ++ ++ BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); ++ if (rstflag) { ++ if (rstflag == 1) { /* Reset start */ ++ retval = -88; ++ if ((chip_reset_count%500) == 0) ++ BT_INFO_FUNC("%s: detect whole chip reset start, %d\n", __func__, chip_reset_count); ++ chip_reset_count++; ++ } else if (rstflag == 2) { /* Reset end */ ++ retval = -99; ++ BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); ++ chip_reset_count = 0; ++ } ++ goto OUT; ++ } ++ ++ if (count > BT_BUFFER_SIZE) { ++ count = BT_BUFFER_SIZE; ++ BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); ++ } ++ ++ retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); ++ ++ while (retval == 0) { /* Got nothing, wait for STP's signal */ ++ /* ++ * If nonblocking mode, return directly. ++ * O_NONBLOCK is specified during open() ++ */ ++ if (filp->f_flags & O_NONBLOCK) { ++ BT_DBG_FUNC("Non-blocking BT_read\n"); ++ retval = -EAGAIN; ++ goto OUT; ++ } ++ ++ BT_DBG_FUNC("%s: wait_event 1\n", __func__); ++ wait_event(BT_wq, flag != 0); ++ BT_DBG_FUNC("%s: wait_event 2\n", __func__); ++ flag = 0; ++ retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); ++ BT_DBG_FUNC("%s: mtk_wcn_stp_receive_data returns %d\n", __func__, retval); ++ } ++ ++ /* Got something from STP driver */ ++ if (copy_to_user(buf, i_buf, retval)) { ++ retval = -EFAULT; ++ goto OUT; ++ } ++ ++OUT: ++ up(&rd_mtx); ++ BT_DBG_FUNC("%s: retval = %d\n", __func__, retval); ++ return retval; ++} ++ ++/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ ++long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ INT32 retval = 0; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; ++ ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; ++ ++ BT_DBG_FUNC("%s: cmd: 0x%x\n", __func__, cmd); ++ ++ switch (cmd) { ++ case COMBO_IOC_BT_HWVER: ++ /* Get combo HW version */ ++ hw_ver_sym = mtk_wcn_wmt_hwver_get(); ++ BT_INFO_FUNC("%s: HW version = %d, sizeof(hw_ver_sym) = %zd\n", ++ __func__, hw_ver_sym, sizeof(hw_ver_sym)); ++ if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) ++ retval = -EFAULT; ++ break; ++ ++ case COMBO_IOCTL_FW_ASSERT: ++ /* Trigger FW assert for debug */ ++ BT_INFO_FUNC("%s: Host trigger FW assert......, reason:%lu\n", __func__, arg); ++ bRet = mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, arg); ++ if (bRet == MTK_WCN_BOOL_TRUE) { ++ BT_INFO_FUNC("Host trigger FW assert succeed\n"); ++ retval = 0; ++ } else { ++ BT_ERR_FUNC("Host trigger FW assert Failed\n"); ++ retval = (-EBUSY); ++ } ++ break; ++ case COMBO_IOCTL_BT_IC_HW_VER: ++ retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); ++ break; ++ case COMBO_IOCTL_BT_IC_FW_VER: ++ retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); ++ break; ++ default: ++ retval = -EFAULT; ++ BT_ERR_FUNC("Unknown cmd (%d)\n", cmd); ++ break; ++ } ++ ++ return retval; ++} ++ ++long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ return BT_unlocked_ioctl(filp, cmd, arg); ++} ++ ++static int BT_open(struct inode *inode, struct file *file) ++{ ++ BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); ++ ++ /* Turn on BT */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { ++ BT_WARN_FUNC("WMT turn on BT fail!\n"); ++ return -ENODEV; ++ } ++ ++ BT_INFO_FUNC("WMT turn on BT OK!\n"); ++ rstflag = 0; ++ ++ if (mtk_wcn_stp_is_ready()) { ++ ++ mtk_wcn_stp_set_bluez(0); ++ ++ BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); ++ BT_INFO_FUNC("STP is ready!\n"); ++ ++ BT_DBG_FUNC("Register BT event callback!\n"); ++ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); ++ } else { ++ BT_ERR_FUNC("STP is not ready\n"); ++ mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ return -ENODEV; ++ } ++ ++ BT_DBG_FUNC("Register BT reset callback!\n"); ++ mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); ++ ++ /* init_MUTEX(&wr_mtx); */ ++ sema_init(&wr_mtx, 1); ++ /* init_MUTEX(&rd_mtx); */ ++ sema_init(&rd_mtx, 1); ++ BT_INFO_FUNC("%s: finish\n", __func__); ++ ++ return 0; ++} ++ ++static int BT_close(struct inode *inode, struct file *file) ++{ ++ BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); ++ rstflag = 0; ++ mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); ++ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { ++ BT_ERR_FUNC("WMT turn off BT fail!\n"); ++ return -EIO; /* Mostly, native program will not check this return value. */ ++ } ++ ++ BT_INFO_FUNC("WMT turn off BT OK!\n"); ++ ++ return 0; ++} ++ ++const struct file_operations BT_fops = { ++ .open = BT_open, ++ .release = BT_close, ++ .read = BT_read, ++ .write = BT_write, ++ /* .ioctl = BT_ioctl, */ ++ .unlocked_ioctl = BT_unlocked_ioctl, ++ .compat_ioctl = BT_compat_ioctl, ++ .poll = BT_poll ++}; ++ ++ ++ ++static int BT_init(void) ++{ ++ dev_t dev = MKDEV(BT_major, 0); ++ INT32 alloc_ret = 0; ++ INT32 cdev_err = 0; ++ ++ /* Static allocate char device */ ++ alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME); ++ if (alloc_ret) { ++ BT_ERR_FUNC("%s: Failed to register char device\n", __func__); ++ return alloc_ret; ++ } ++ ++ cdev_init(&BT_cdev, &BT_fops); ++ BT_cdev.owner = THIS_MODULE; ++ ++ cdev_err = cdev_add(&BT_cdev, dev, BT_devs); ++ if (cdev_err) ++ goto error; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ stpbt_class = class_create(THIS_MODULE, "stpbt"); ++ if (IS_ERR(stpbt_class)) ++ goto error; ++ stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt"); ++ if (IS_ERR(stpbt_dev)) ++ goto error; ++#endif ++ ++ BT_INFO_FUNC("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major); ++ ++ /* Init wait queue */ ++ init_waitqueue_head(&(inq)); ++ ++#ifdef MTK_BT_HCI ++ mtk_bt_hci_init(); ++#endif ++ ++ return 0; ++ ++error: ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!IS_ERR(stpbt_dev)) ++ device_destroy(stpbt_class, dev); ++ if (!IS_ERR(stpbt_class)) { ++ class_destroy(stpbt_class); ++ stpbt_class = NULL; ++ } ++#endif ++ if (cdev_err == 0) ++ cdev_del(&BT_cdev); ++ ++ if (alloc_ret == 0) ++ unregister_chrdev_region(dev, BT_devs); ++ ++ return -1; ++} ++ ++static void BT_exit(void) ++{ ++ dev_t dev = MKDEV(BT_major, 0); ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ if (stpbt_dev) { ++ device_destroy(stpbt_class, dev); ++ stpbt_dev = NULL; ++ } ++ if (stpbt_class) { ++ class_destroy(stpbt_class); ++ stpbt_class = NULL; ++ } ++#endif ++ ++ cdev_del(&BT_cdev); ++ unregister_chrdev_region(dev, BT_devs); ++ ++ BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++int mtk_wcn_stpbt_drv_init(void) ++{ ++ return BT_init(); ++} ++EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init); ++ ++void mtk_wcn_stpbt_drv_exit(void) ++{ ++ return BT_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit); ++ ++#else ++ ++module_init(BT_init); ++module_exit(BT_exit); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +new file mode 100644 +index 000000000000..c43bec5f7452 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -0,0 +1,668 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wmt_exp.h" ++#include "stp_exp.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++#define WIFI_DRIVER_NAME "mtk_wmt_WIFI_chrdev" ++#define WIFI_DEV_MAJOR 155 ++ ++#define PFX "[MTK-WIFI] " ++#define WIFI_LOG_DBG 3 ++#define WIFI_LOG_INFO 2 ++#define WIFI_LOG_WARN 1 ++#define WIFI_LOG_ERR 0 ++ ++UINT32 gDbgLevel = WIFI_LOG_DBG; ++ ++#define WIFI_DBG_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_INFO_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_INFO) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_WARN_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_WARN) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_ERR_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_ERR) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_TRC_FUNC(f)\ ++ do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "<%s> <%d>\n", __func__, __LINE__); } while (0) ++ ++#define VERSION "1.0" ++ ++#define WLAN_IFACE_NAME "wlan0" ++#if CFG_TC1_FEATURE ++#define LEGACY_IFACE_NAME "legacy0" ++#endif ++ ++enum { ++ WLAN_MODE_HALT, ++ WLAN_MODE_AP, ++ WLAN_MODE_STA_P2P, ++ WLAN_MODE_MAX ++}; ++static INT32 wlan_mode = WLAN_MODE_HALT; ++static INT32 powered; ++static INT8 *ifname = WLAN_IFACE_NAME; ++#if CFG_TC1_FEATURE ++volatile INT32 wlan_if_changed = 0; ++EXPORT_SYMBOL(wlan_if_changed); ++#endif ++ ++typedef enum _ENUM_RESET_STATUS_T { ++ RESET_FAIL, ++ RESET_SUCCESS ++} ENUM_RESET_STATUS_T; ++ ++/* ++ * enable = 1, mode = 0 => init P2P network ++ * enable = 1, mode = 1 => init Soft AP network ++ * enable = 0 => uninit P2P/AP network ++ */ ++typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { ++ UINT32 u4Enable; ++ UINT32 u4Mode; ++} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; ++typedef INT32(*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++ ++static set_p2p_mode pf_set_p2p_mode; ++VOID register_set_p2p_mode_handler(set_p2p_mode handler) ++{ ++ WIFI_INFO_FUNC("(pid %d) register set p2p mode handler %p\n", current->pid, handler); ++ pf_set_p2p_mode = handler; ++} ++EXPORT_SYMBOL(register_set_p2p_mode_handler); ++ ++/* For dynamical debug level setting */ ++/* copy of debug.h in wlan driver */ ++#define DBG_CLASS_ERROR BIT(0) ++#define DBG_CLASS_WARN BIT(1) ++#define DBG_CLASS_STATE BIT(2) ++#define DBG_CLASS_EVENT BIT(3) ++#define DBG_CLASS_TRACE BIT(4) ++#define DBG_CLASS_INFO BIT(5) ++#define DBG_CLASS_LOUD BIT(6) ++#define DBG_CLASS_TEMP BIT(7) ++#define DBG_CLASS_MASK BITS(0, 7) ++ ++typedef enum _ENUM_DBG_MODULE_T { ++ DBG_INIT_IDX = 0, /* For driver initial */ ++ DBG_HAL_IDX, /* For HAL(HW) Layer */ ++ DBG_INTR_IDX, /* For Interrupt */ ++ DBG_REQ_IDX, ++ DBG_TX_IDX, ++ DBG_RX_IDX, ++ DBG_RFTEST_IDX, /* For RF test mode */ ++ DBG_EMU_IDX, /* Developer specific */ ++ ++ DBG_SW1_IDX, /* Developer specific */ ++ DBG_SW2_IDX, /* Developer specific */ ++ DBG_SW3_IDX, /* Developer specific */ ++ DBG_SW4_IDX, /* Developer specific */ ++ ++ DBG_HEM_IDX, /* HEM */ ++ DBG_AIS_IDX, /* AIS */ ++ DBG_RLM_IDX, /* RLM */ ++ DBG_MEM_IDX, /* RLM */ ++ DBG_CNM_IDX, /* CNM */ ++ DBG_RSN_IDX, /* RSN */ ++ DBG_BSS_IDX, /* BSS */ ++ DBG_SCN_IDX, /* SCN */ ++ DBG_SAA_IDX, /* SAA */ ++ DBG_AAA_IDX, /* AAA */ ++ DBG_P2P_IDX, /* P2P */ ++ DBG_QM_IDX, /* QUE_MGT */ ++ DBG_SEC_IDX, /* SEC */ ++ DBG_BOW_IDX, /* BOW */ ++ DBG_WAPI_IDX, /* WAPI */ ++ DBG_ROAMING_IDX, /* ROAMING */ ++ ++ DBG_MODULE_NUM /* Notice the XLOG check */ ++} ENUM_DBG_MODULE_T; ++/* end */ ++typedef VOID(*set_dbg_level) (UINT8 modules[DBG_MODULE_NUM]); ++ ++UINT8 wlan_dbg_level[DBG_MODULE_NUM]; ++static set_dbg_level pf_set_dbg_level; ++VOID register_set_dbg_level_handler(set_dbg_level handler) ++{ ++ pf_set_dbg_level = handler; ++} ++EXPORT_SYMBOL(register_set_dbg_level_handler); ++ ++static INT32 WIFI_devs = 1; ++static INT32 WIFI_major = WIFI_DEV_MAJOR; ++module_param(WIFI_major, uint, 0); ++static struct cdev WIFI_cdev; ++volatile INT32 retflag = 0; ++static struct semaphore wr_mtx; ++ ++#define WMT_CHECK_DO_CHIP_RESET() \ ++do { \ ++ if (g_IsNeedDoChipReset) { \ ++ g_IsNeedDoChipReset = 0; \ ++ WIFI_ERR_FUNC("Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); \ ++ } \ ++} while (0) ++ ++/******************************************************************* ++ * WHOLE CHIP RESET PROCEDURE: ++ * ++ * WMTRSTMSG_RESET_START callback ++ * -> wlanRemove ++ * -> WMTRSTMSG_RESET_END callback ++ * ++ ******************************************************************* ++*/ ++/*-----------------------------------------------------------------*/ ++/* ++ * Receiving RESET_START message ++ */ ++/*-----------------------------------------------------------------*/ ++INT32 wifi_reset_start(VOID) ++{ ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ ++ down(&wr_mtx); ++ ++ if (powered == 1) { ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev == NULL) { ++ WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); ++ } else { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ ++ if (pf_set_p2p_mode) { ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ else ++ WIFI_INFO_FUNC("Turn off p2p/ap mode"); ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ } else { ++ /* WIFI is off before whole chip reset, do nothing */ ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(wifi_reset_start); ++ ++/*-----------------------------------------------------------------*/ ++/* ++ * Receiving RESET_END/RESET_END_FAIL message ++ */ ++/*-----------------------------------------------------------------*/ ++INT32 wifi_reset_end(ENUM_RESET_STATUS_T status) ++{ ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ INT32 wait_cnt = 0; ++ INT32 ret = -1; ++ ++ if (status == RESET_FAIL) { ++ /* whole chip reset fail, donot recover WIFI */ ++ ret = 0; ++ up(&wr_mtx); ++ } else if (status == RESET_SUCCESS) { ++ WIFI_WARN_FUNC("WIFI state recovering...\n"); ++ ++ if (powered == 1) { ++ /* WIFI is on before whole chip reset, reopen it now */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ } ++ ++ if (pf_set_p2p_mode == NULL) { ++ WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ while (netdev == NULL && wait_cnt < 10) { ++ WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); ++ msleep(300); ++ wait_cnt++; ++ netdev = dev_get_by_name(&init_net, ifname); ++ } ++ if (wait_cnt >= 10) { ++ WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); ++ goto done; ++ } ++ ++ if (wlan_mode == WLAN_MODE_STA_P2P) { ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_P2P); ++ ret = 0; ++ } ++ } else if (wlan_mode == WLAN_MODE_AP) { ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 1; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_AP); ++ ret = 0; ++ } ++ } ++done: ++ if (netdev != NULL) ++ dev_put(netdev); ++ } else { ++ /* WIFI is off before whole chip reset, do nothing */ ++ ret = 0; ++ } ++ up(&wr_mtx); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(wifi_reset_end); ++ ++static int WIFI_open(struct inode *inode, struct file *file) ++{ ++ WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static int WIFI_close(struct inode *inode, struct file *file) ++{ ++ WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); ++ retflag = 0; ++ ++ return 0; ++} ++ ++ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = -EIO; ++ INT8 local[12] = { 0 }; ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ INT32 wait_cnt = 0; ++ ++ down(&wr_mtx); ++ if (count <= 0) { ++ WIFI_ERR_FUNC("WIFI_write invalid param\n"); ++ goto done; ++ } ++ ++ if (0 == copy_from_user(local, buf, (count > sizeof(local)) ? sizeof(local) : count)) { ++ local[11] = 0; ++ WIFI_INFO_FUNC("WIFI_write %s\n", local); ++ ++ if (local[0] == '0') { ++ if (powered == 0) { ++ WIFI_INFO_FUNC("WIFI is already power off!\n"); ++ retval = count; ++ wlan_mode = WLAN_MODE_HALT; ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev == NULL) { ++ WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); ++ } else { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ ++ if (pf_set_p2p_mode) { ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ } else { ++ WIFI_INFO_FUNC("Turn off p2p/ap mode"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn off WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ } else { ++ WIFI_INFO_FUNC("WMT turn off WIFI OK!\n"); ++ powered = 0; ++ retval = count; ++ wlan_mode = WLAN_MODE_HALT; ++#if CFG_TC1_FEATURE ++ ifname = WLAN_IFACE_NAME; ++ wlan_if_changed = 0; ++#endif ++ } ++ } else if (local[0] == '1') { ++ if (powered == 1) { ++ WIFI_INFO_FUNC("WIFI is already power on!\n"); ++ retval = count; ++ goto done; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ } else { ++ powered = 1; ++ retval = count; ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } else if (local[0] == 'D') { ++ INT32 k = 0; ++ /* ++ * 0: no debug ++ * 1: common debug output ++ * 2: more detials ++ * 3: verbose ++ */ ++ switch (local[1]) { ++ case '0': ++ for (k = 0; k < DBG_MODULE_NUM; k++) ++ wlan_dbg_level[k] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '1': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; ++ } ++ wlan_dbg_level[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_INTR_IDX] = 0; ++ wlan_dbg_level[DBG_MEM_IDX] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '2': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; ++ } ++ wlan_dbg_level[DBG_INTR_IDX] = 0; ++ wlan_dbg_level[DBG_MEM_IDX] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '3': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | ++ DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO | DBG_CLASS_LOUD; ++ } ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ default: ++ break; ++ } ++ } else if (local[0] == 'S' || local[0] == 'P' || local[0] == 'A') { ++ if (powered == 0) { ++ /* If WIFI is off, turn on WIFI first */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ goto done; ++ } else { ++ powered = 1; ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } ++ ++ if (pf_set_p2p_mode == NULL) { ++ WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ while (netdev == NULL && wait_cnt < 10) { ++ WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); ++ msleep(300); ++ wait_cnt++; ++ netdev = dev_get_by_name(&init_net, ifname); ++ } ++ if (wait_cnt >= 10) { ++ WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); ++ goto done; ++ } ++ ++ if ((wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'S' || local[0] == 'P')) || ++ (wlan_mode == WLAN_MODE_AP && (local[0] == 'A'))) { ++ WIFI_INFO_FUNC("WIFI is already in mode %d!\n", wlan_mode); ++ retval = count; ++ goto done; ++ } ++ ++ if ((wlan_mode == WLAN_MODE_AP && (local[0] == 'S' || local[0] == 'P')) || ++ (wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'A'))) { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ goto done; ++ } ++ } ++ ++ if (local[0] == 'S' || local[0] == 'P') { ++#if CFG_TC1_FEATURE ++ /* Restore NIC name to wlan0 */ ++ rtnl_lock(); ++ if (strcmp(ifname, WLAN_IFACE_NAME) != 0) { ++ if (dev_change_name(netdev, WLAN_IFACE_NAME) != 0) { ++ WIFI_ERR_FUNC("netdev name change to %s fail\n", WLAN_IFACE_NAME); ++ rtnl_unlock(); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, ++ WLAN_IFACE_NAME); ++ ifname = WLAN_IFACE_NAME; ++ wlan_if_changed = 0; ++ } ++ } ++ rtnl_unlock(); ++#endif ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_STA_P2P); ++ wlan_mode = WLAN_MODE_STA_P2P; ++ retval = count; ++ } ++ } else if (local[0] == 'A') { ++#if CFG_TC1_FEATURE ++ /* Change NIC name to legacy0, since wlan0 is used for AP */ ++ rtnl_lock(); ++ if (strcmp(ifname, LEGACY_IFACE_NAME) != 0) { ++ if (dev_change_name(netdev, LEGACY_IFACE_NAME) != 0) { ++ WIFI_ERR_FUNC("netdev name change to %s fail\n", LEGACY_IFACE_NAME); ++ rtnl_unlock(); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, ++ LEGACY_IFACE_NAME); ++ ifname = LEGACY_IFACE_NAME; ++ wlan_if_changed = 1; ++ } ++ } ++ rtnl_unlock(); ++#endif ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 1; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_AP); ++ wlan_mode = WLAN_MODE_AP; ++ retval = count; ++ } ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ } ++done: ++ if (netdev != NULL) ++ dev_put(netdev); ++ ++ up(&wr_mtx); ++ return retval; ++} ++ ++const struct file_operations WIFI_fops = { ++ .open = WIFI_open, ++ .release = WIFI_close, ++ .write = WIFI_write, ++}; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *wmtwifi_class = NULL; ++#endif ++ ++static int WIFI_init(void) ++{ ++ dev_t dev = MKDEV(WIFI_major, 0); ++ INT32 alloc_ret = 0; ++ INT32 cdev_err = 0; ++#if WMT_CREATE_NODE_DYNAMIC ++ struct device *wmtwifi_dev = NULL; ++#endif ++ ++ /* static allocate chrdev */ ++ alloc_ret = register_chrdev_region(dev, 1, WIFI_DRIVER_NAME); ++ if (alloc_ret) { ++ WIFI_ERR_FUNC("Fail to register chrdev\n"); ++ return alloc_ret; ++ } ++ ++ cdev_init(&WIFI_cdev, &WIFI_fops); ++ WIFI_cdev.owner = THIS_MODULE; ++ ++ cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs); ++ if (cdev_err) ++ goto error; ++ ++#if WMT_CREATE_NODE_DYNAMIC /* mknod replace */ ++ wmtwifi_class = class_create(THIS_MODULE, "wmtWifi"); ++ if (IS_ERR(wmtwifi_class)) ++ goto error; ++ wmtwifi_dev = device_create(wmtwifi_class, NULL, dev, NULL, "wmtWifi"); ++ if (wmtwifi_dev == NULL) ++ goto error; ++ if (IS_ERR(wmtwifi_dev)) ++ goto error; ++#endif ++ ++ sema_init(&wr_mtx, 1); ++ ++ WIFI_INFO_FUNC("%s driver(major %d) installed.\n", WIFI_DRIVER_NAME, WIFI_major); ++ retflag = 0; ++ wlan_mode = WLAN_MODE_HALT; ++ pf_set_p2p_mode = NULL; ++ ++ return 0; ++ ++error: ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!IS_ERR(wmtwifi_dev)) ++ device_destroy(wmtwifi_class, dev); ++ if (!IS_ERR(wmtwifi_class)) { ++ class_destroy(wmtwifi_class); ++ wmtwifi_class = NULL; ++ } ++#endif ++ ++ if (cdev_err == 0) ++ cdev_del(&WIFI_cdev); ++ ++ if (alloc_ret == 0) ++ unregister_chrdev_region(dev, WIFI_devs); ++ ++ return -1; ++} ++ ++static void WIFI_exit(void) ++{ ++ dev_t dev = MKDEV(WIFI_major, 0); ++ ++ retflag = 0; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ device_destroy(wmtwifi_class, dev); ++ class_destroy(wmtwifi_class); ++ wmtwifi_class = NULL; ++#endif ++ ++ cdev_del(&WIFI_cdev); ++ unregister_chrdev_region(dev, WIFI_devs); ++ ++ WIFI_INFO_FUNC("%s driver removed.\n", WIFI_DRIVER_NAME); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++INT32 mtk_wcn_wmt_wifi_init(VOID) ++{ ++ return WIFI_init(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wifi_init); ++ ++VOID mtk_wcn_wmt_wifi_exit(VOID) ++{ ++ return WIFI_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wifi_exit); ++ ++#else ++ ++module_init(WIFI_init); ++module_exit(WIFI_exit); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c +new file mode 100644 +index 000000000000..641e516f603d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c +@@ -0,0 +1,307 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "osal_typedef.h" ++#include "wmt_idc.h" ++#include "wmt_lib.h" ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++MTK_WCN_WMT_IDC_INFO gWmtIdcInfo; ++ ++INT32 wmt_idc_init(VOID) ++{ ++ INT32 iRet; ++ ++ osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); ++ gWmtIdcInfo.iit.src_mod_id = AP_MOD_WMT; ++ gWmtIdcInfo.iit.dest_mod_id = MD_MOD_EL1; ++ gWmtIdcInfo.iit.sap_id = 0; ++ gWmtIdcInfo.ops.rx_cb = wmt_idc_msg_from_lte_handing; ++ ++ iRet = mtk_conn_md_bridge_reg(gWmtIdcInfo.iit.src_mod_id, &gWmtIdcInfo.ops); ++ if (iRet) { ++ WMT_ERR_FUNC("mtk_conn_md_bridge_reg fail(%d)\n", iRet); ++ return -1; ++ } ++ /* mtk_wcn_stp_flush_rx_queue(COEX_TASK_INDX); */ ++ return 0; ++ ++} ++ ++INT32 wmt_idc_deinit(VOID) ++{ ++ INT32 iRet; ++ ++ iRet = mtk_conn_md_bridge_unreg(gWmtIdcInfo.iit.src_mod_id); ++ if (iRet) ++ WMT_ERR_FUNC("mtk_conn_md_bridge_unreg fail(%d)\n", iRet); ++ ++ osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); ++ ++ return 0; ++} ++ ++INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm) ++{ ++ MTK_WCN_BOOL bRet; ++ ++ if (NULL == ilm) { ++ WMT_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready()) { ++ bRet = wmt_lib_handle_idc_msg(ilm); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("wmt handing idc msg fail\n"); ++ return -2; ++ } ++ } else { ++ WMT_INFO_FUNC("Received LTE msg,but STP is not ready,drop it!\n"); ++ } ++ return 0; ++} ++ ++VOID wmt_idc_dump_debug_msg(UINT8 *str, UINT8 *p_buf, UINT32 buf_len) ++{ ++ UINT32 idx = 0; ++ ++ WMT_DBG_FUNC("%s:, length:%d\n", str, buf_len); ++ ++ WMT_DBG_FUNC("ASCII output:\n"); ++ ++ for (idx = 0; idx < buf_len;) { ++ WMT_DBG_FUNC("%c", p_buf[idx]); ++ idx++; ++ if (0 == idx % 16) ++ WMT_DBG_FUNC("\n"); ++ } ++ ++ WMT_DBG_FUNC("HEX output:\n"); ++ ++ for (idx = 0; idx < buf_len;) { ++ WMT_DBG_FUNC("%02x ", p_buf[idx]); ++ idx++; ++ if (0 == idx % 16) ++ WMT_DBG_FUNC("\n"); ++ } ++} ++ ++INT32 wmt_idc_msg_to_lte_handing(VOID) ++{ ++ UINT32 readlen = 0; ++ local_para_struct *p_lps = NULL; ++ UINT8 *p_data = NULL; ++ UINT8 opcode = 0; ++ UINT16 msg_len = 0; ++ UINT32 handle_len = 0; ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++#endif ++ readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); ++ if (readlen == 0) { ++ osal_sleep_ms(5); ++ readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); ++ } ++ ++ if (readlen > 0) { ++ WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); ++ wmt_idc_dump_debug_msg("WMT->LTE from STP buffer", &gWmtIdcInfo.buffer[0], readlen); ++ p_data = &gWmtIdcInfo.buffer[0]; ++ ++ while (handle_len < readlen) { ++ p_data += 2; /*omit direction & opcode 2 bytes */ ++ osal_memcpy(&msg_len, p_data, 2); ++ msg_len -= 1; /*flag byte */ ++ WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); ++ ++ p_data += 2; /*length: 2 bytes */ ++ ++ /*how to handle flag(msg type) need to Scott comment */ ++ /************************************************/ ++ ++ if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) ++ /*do not need transfer to LTE */ ++ { ++ p_data += 1; /*flag : 1 byte */ ++ /*need to handle these debug message */ ++ wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); ++ } else ++ /*need to transfer to LTE */ ++ { ++ p_lps = ++ (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + ++ osal_sizeof(UINT8) * msg_len); ++ if (NULL == p_lps) { ++ WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); ++ return -1; ++ } ++ ++ p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); ++ ++ opcode = *p_data; ++ WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); ++ ++ p_data += 1; /*flag : 1 byte */ ++ osal_memcpy(p_lps->data, p_data, msg_len); ++ ++ gWmtIdcInfo.iit.local_para_ptr = p_lps; ++ ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ switch (opcode) { ++ case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_UART_PIN_SEL: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_PIN_TYPE_IND; ++ break; ++ /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ ++ /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ ++ /* break; */ ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); ++ break; ++ } ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ } ++#else ++ if (opcode >= LTE_MSG_ID_OFFSET) { ++ gWmtIdcInfo.iit.msg_id = opcode + IPC_EL1_MSG_ID_BEGIN - LTE_MSG_ID_OFFSET + 1; ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ WMT_DBG_FUNC("CONN->LTE: (0x%x->0x%x)\n", opcode, gWmtIdcInfo.iit.msg_id); ++ } else { ++ WMT_ERR_FUNC("opcode(%d)from connsys fw is out of range,drop it!\n", opcode); ++ } ++#endif ++ osal_free(p_lps); ++ } ++ ++ p_data += msg_len; /*point to next package header */ ++ ++ handle_len += (msg_len + 5); ++ } ++ ++ } else { ++ WMT_ERR_FUNC("there is no coex data in stp buffer\n"); ++ } ++ ++ osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); ++ ++ return 0; ++} ++ ++UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len) ++{ ++ UINT32 readlen = len; ++ local_para_struct *p_lps = NULL; ++ UINT8 *p_data = NULL; ++ UINT8 opcode = 0; ++ UINT16 msg_len = 0; ++ UINT32 handle_len = 0; ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++ ++ osal_memcpy(&gWmtIdcInfo.buffer[0], p_buf, len); ++ ++ if (readlen > 0) { ++ WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); ++ p_data = &gWmtIdcInfo.buffer[0]; ++ ++ while (handle_len < readlen) { ++ p_data += 2; /*omit direction & opcode 2 bytes */ ++ osal_memcpy(&msg_len, p_data, 2); ++ msg_len -= 1; /*flag byte */ ++ WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); ++ ++ p_data += 2; /*length: 2 bytes */ ++ ++ /*how to handle flag(msg type) need to Scott comment */ ++ /************************************************/ ++ ++ if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) ++ /*do not need transfer to LTE */ ++ { ++ p_data += 1; /*flag : 1 byte */ ++ /*need to handle these debug message */ ++ wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); ++ } else ++ /*need to transfer to LTE */ ++ { ++ p_lps = ++ (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + ++ osal_sizeof(UINT8) * msg_len); ++ if (NULL == p_lps) { ++ WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); ++ return -1; ++ } ++ ++ p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); ++ ++ opcode = *p_data; ++ WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); ++ ++ p_data += 1; /*flag : 1 byte */ ++ osal_memcpy(p_lps->data, p_data, msg_len); ++ ++ gWmtIdcInfo.iit.local_para_ptr = p_lps; ++ ++ switch (opcode) { ++ case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; ++ break; ++ /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ ++ /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ ++ /* break; */ ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); ++ break; ++ } ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ } ++ osal_free(p_lps); ++ } ++ ++ p_data += msg_len; /*point to next package header */ ++ ++ handle_len += (msg_len + 5); ++ } ++ ++ } else { ++ WMT_ERR_FUNC("there is no coex data in stp buffer\n"); ++ } ++ ++ osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); ++ ++ return handle_len; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile +new file mode 100644 +index 000000000000..c201e8291b8e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile +@@ -0,0 +1,25 @@ ++# WMT HAL driver for MT7623 ++ ++ccflags-y += \ ++ -I$(src)/include \ ++ -I$(src)/../linux/include \ ++ -I$(src)/../include \ ++ -I$(src)/../../common_detect ++ ++ ifeq ($(CONFIG_MTK_CLKMGR),y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach ++ endif ++ #ifeq ($(CONFIG_MTK_EMI_MPU),y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach ++ #endif ++ ++subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) ++ subdir-ccflags-y += -DWMT_IDC_SUPPORT=1 ++else ++ subdir-ccflags-y += -DWMT_IDC_SUPPORT=0 ++endif ++ ++obj-y += mtk_wcn_consys_hw.o ++obj-y += wmt_plat_alps.o +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h +new file mode 100644 +index 000000000000..94d6af9d0b3e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h +@@ -0,0 +1,287 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _MTK_WCN_CONSYS_HW_H_ ++#define _MTK_WCN_CONSYS_HW_H_ ++ ++#include ++/*#include */ ++#include "wmt_plat.h" ++ ++/*device tree mode*/ ++#ifdef CONFIG_OF ++/* #if 1 */ ++#include ++#include ++#include ++#include ++#endif ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CONSYS_BT_WIFI_SHARE_V33 0 ++#define CONSYS_PMIC_CTRL_ENABLE 1 ++#define CONSYS_PMIC_CTRL_UPMU 1 ++#define CONSYS_EMI_MPU_SETTING 0 ++#define CONSYS_AHB_CLK_MAGEMENT 1 ++#define CONSYS_USE_PLATFORM_WRITE 1 ++#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 ++#define CONSYS_CLOCK_BUF_CTRL 0 ++#if defined(CONFIG_MTK_LEGACY) ++#define CONFIG_MTK_PMIC_LEGACY 0 ++#endif ++#define CONFIG_RESET_CONTROL 1 ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*tag start:new platform need to make sure these define */ ++#define PLATFORM_SOC_CHIP 0x7623 ++/*tag end*/ ++ ++#ifdef CONFIG_OF ++ ++struct CONSYS_BASE_ADDRESS { ++ SIZE_T mcu_base; ++ SIZE_T ap_rgu_base; ++ SIZE_T topckgen_base; ++ SIZE_T spm_base; ++}; ++ ++/*TOPCKGEN_BASE*/ ++#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 ++#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 ++#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 ++#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000800 ++#define CONSYS_EMI_MAPPING_OFFSET 0x00000310 ++/*AP_RGU_BASE*/ ++#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 ++/*SPM_BASE*/ ++#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 ++#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000280 ++#define CONSYS_PWR_CONN_ACK_OFFSET 0x0000060c ++#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000610 ++/*CONN_MCU_CONFIG_BASE*/ ++#define CONSYS_CHIP_ID_OFFSET 0x00000008 ++#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 ++#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 ++#define CONSYS_CPUPCR_OFFSET 0x00000160 ++/*AXI bus*/ ++ ++#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 ++#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x0228 ++#endif ++ ++#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile UINT32*)(REG)) |= ((UINT32)(BITVAL))) ++#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile UINT32*)(REG)) &= ~((UINT32)(BITVAL))) ++#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ ++ UINT32 val = (*(volatile UINT32*)(REG)); \ ++ val &= ~((UINT32)(BITVAL)); \ ++ val |= ((UINT32)(KEY)); \ ++ (*(volatile UINT32*)(REG)) = val;\ ++} ++#define CONSYS_REG_READ(addr) (*((volatile UINT32*)(addr))) ++#if CONSYS_USE_PLATFORM_WRITE ++#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) ++#else ++#define CONSYS_REG_WRITE(addr, data) (*((volatile UINT32*)(addr)) = (UINT32)(data)) ++#endif ++ ++/*tag start: connsys register base address (hard code, no use) */ ++#define AP_RGU_BASE 0xF0007000 ++#define TOPCKGEN_BASE 0xF0000000 ++#define SPM_BASE 0xF0006000 ++#define CONN_MCU_CONFIG_BASE 0xF8070000 ++/*GIC Interrupt ID*/ ++#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 237 ++/*tag end*/ ++ ++/*connsys register offset define(hard code mode)*/ ++#if 1 ++ /*top clock gating control register */ ++#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) ++#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) ++#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) ++ ++ /*SPM clock gating control register */ ++#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) ++#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) ++#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) ++#endif ++ ++#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) ++#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x00000280) ++#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x0000060c) ++#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000610) ++ ++#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) ++#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) ++#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) ++#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) ++#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) ++#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) ++#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) ++#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) ++#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) ++#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) ++#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) ++ ++#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x0220) ++#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x0228) ++#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14) | (0x1<<15)) /* bit 13, 14, 15 */ ++/*CONSYS_CPU_SW_RST_REG*/ ++#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) ++#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) ++ ++/*CONSYS_TOP1_PWR_CTRL_REG*/ ++#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) ++#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) ++#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) ++#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) ++#define CONSYS_CLK_CTRL_BIT (0x1 << 4) ++#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) ++ ++/*CONSYS_PWR_CONN_ACK_REG*/ ++#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) ++ ++/*CONSYS_PWR_CONN_ACK_S_REG*/ ++#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) ++ ++/*CONSYS_WD_SYS_RST_REG*/ ++#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) ++#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) ++ ++/*CONSYS_MCU_CFG_ACR_REG*/ ++#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) ++ ++/* EMI part mapping & ctrl*/ ++#define KBYTE (1024*sizeof(char)) ++#define CONSYS_EMI_AP_PHY_OFFSET (0x80000) ++#define CONSYS_EMI_AP_PHY_BASE (0x80080000) ++#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) ++#define CONSYS_EMI_MEM_SIZE (343*KBYTE) /*coredump space , 343K is enough */ ++#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) ++#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) ++#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) ++ ++/*cpupcr*/ ++#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) ++/*emi mapping*/ ++#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + 0x1310) ++ ++/*control app2cnn_osc_en*/ ++#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) ++#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 16) ++#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 17) ++ ++/*paged dump address start*/ ++#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) ++#define CONSYS_PAGED_DUMP_SIZE (32*KBYTE) ++ ++/*full dump address start*/ ++#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) ++#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) ++#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) ++#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) ++#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) ++#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) ++ ++/*force fw assert pattern*/ ++#define EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1 (0x19b30bb1) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_EMI_CTRL_STATE_OFFSET_ { ++ EXP_APMEM_CTRL_STATE = 0x0, ++ EXP_APMEM_CTRL_HOST_SYNC_STATE = 0x4, ++ EXP_APMEM_CTRL_HOST_SYNC_NUM = 0x8, ++ EXP_APMEM_CTRL_CHIP_SYNC_STATE = 0xc, ++ EXP_APMEM_CTRL_CHIP_SYNC_NUM = 0x10, ++ EXP_APMEM_CTRL_CHIP_SYNC_ADDR = 0x14, ++ EXP_APMEM_CTRL_CHIP_SYNC_LEN = 0x18, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START = 0x1c, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN = 0x20, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX = 0x24, ++ EXP_APMEM_CTRL_CHIP_INT_STATUS = 0x28, ++ EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END = 0x2c, ++ EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 = 0x30, ++ EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP = 0x48, ++ EXP_APMEM_CTRL_MAX ++} ENUM_EMI_CTRL_STATE_OFFSET, *P_ENUM_EMI_CTRL_STATE_OFFSET; ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++typedef struct _BT_WIFI_V33_STATUS_ { ++ UINT32 counter; ++ UINT32 flags; ++ spinlock_t lock; ++} BT_WIFI_V33_STATUS; ++ ++#endif ++ ++typedef enum _CONSYS_GPS_CO_CLOCK_TYPE_ { ++ GPS_TCXO_TYPE = 0, ++ GPS_CO_TSX_TYPE = 1, ++ GPS_CO_DCXO_TYPE = 2, ++ GPS_CO_VCTCXO_TYPE = 3, ++ GPS_CO_CLOCK_TYPE_MAX ++} CONSYS_GPS_CO_CLOCK_TYPE, *P_CONSYS_GPS_CO_CLOCK_TYPE; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern struct CONSYS_BASE_ADDRESS conn_reg; ++#if CONSYS_BT_WIFI_SHARE_V33 ++extern BT_WIFI_V33_STATUS gBtWifiV33; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++extern INT32 mtk_wcn_consys_hw_init(VOID); ++extern INT32 mtk_wcn_consys_hw_deinit(VOID); ++extern INT32 mtk_wcn_consys_hw_pwr_off(VOID); ++extern INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type); ++extern INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type); ++extern INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_state_show(VOID); ++extern UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset); ++#if CONSYS_ENALBE_SET_JTAG ++extern UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en); ++#endif ++extern UINT32 mtk_wcn_consys_soc_chipid(VOID); ++#if !defined(CONFIG_MTK_GPIO_LEGACY) ++extern struct pinctrl *mtk_wcn_consys_get_pinctrl(VOID); ++#endif ++extern INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 buf); ++#endif /* _MTK_WCN_CMB_HW_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +new file mode 100644 +index 000000000000..191f7312f897 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +@@ -0,0 +1,737 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CONSYS-HW]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include "osal_typedef.h" ++#include "mtk_wcn_consys_hw.h" ++#include ++#include ++#include ++#if CONSYS_EMI_MPU_SETTING ++#include ++#endif ++ ++#include ++#ifdef CONFIG_MTK_HIBERNATION ++#include ++#endif ++ ++#include ++ ++#if CONSYS_CLOCK_BUF_CTRL ++#include ++#endif ++ ++#include ++#include ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static INT32 mtk_wmt_probe(struct platform_device *pdev); ++static INT32 mtk_wmt_remove(struct platform_device *pdev); ++ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++struct CONSYS_BASE_ADDRESS conn_reg; ++static phys_addr_t gConEmiPhyBase; ++static UINT8 __iomem *pEmibaseaddr; ++static struct clk *clk_infra_conn_main; /*ctrl infra_connmcu_bus clk */ ++static struct platform_device *my_pdev; ++static struct reset_control *rstc; ++static struct regulator *reg_VCN18; ++static struct regulator *reg_VCN28; ++static struct regulator *reg_VCN33_BT; ++static struct regulator *reg_VCN33_WIFI; ++static struct pinctrl *consys_pinctrl; ++static struct pinctrl *mt6625_spi_pinctrl; ++static struct pinctrl_state *mt6625_spi_default; ++static struct regmap *pmic_regmap; ++#define DYNAMIC_DUMP_GROUP_NUM 5 ++ ++static const struct of_device_id apwmt_of_ids[] = { ++ {.compatible = "mediatek,mt7623-consys",} ++}; ++MODULE_DEVICE_TABLE(of, apwmt_of_ids); ++ ++static struct platform_driver mtk_wmt_dev_drv = { ++ .probe = mtk_wmt_probe, ++ .remove = mtk_wmt_remove, ++ .driver = { ++ .name = "mt7623consys", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(apwmt_of_ids), ++ }, ++}; ++ ++static INT32 mtk_wmt_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct device_node *node = NULL; ++ ++ pm_runtime_enable(&pdev->dev); ++ my_pdev = pdev; ++ mt6625_spi_pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(mt6625_spi_pinctrl)) { ++ ret = PTR_ERR(mt6625_spi_pinctrl); ++ WMT_PLAT_ERR_FUNC("Wmt cannot find pinctrl!\n"); ++ goto set_pin_exit; ++ } ++ mt6625_spi_default = pinctrl_lookup_state(mt6625_spi_pinctrl, "consys_pins_default"); ++ if (IS_ERR(mt6625_spi_default)) { ++ ret = PTR_ERR(mt6625_spi_default); ++ WMT_PLAT_ERR_FUNC("Wmt Cannot find pinctrl default!\n"); ++ goto set_pin_exit; ++ } ++ pinctrl_select_state(mt6625_spi_pinctrl, mt6625_spi_default); ++set_pin_exit: ++ ++ node = of_parse_phandle(pdev->dev.of_node, "mediatek,pwrap-regmap", 0); ++ if (node) { ++ pmic_regmap = pwrap_node_to_regmap(node); ++ if (IS_ERR(pmic_regmap)) ++ goto set_pmic_wrap_exit; ++ } else { ++ WMT_PLAT_ERR_FUNC("Pwrap node has not register regmap.\n"); ++ goto set_pmic_wrap_exit; ++ } ++set_pmic_wrap_exit: ++ ++ clk_infra_conn_main = devm_clk_get(&pdev->dev, "consysbus"); ++ if (IS_ERR(clk_infra_conn_main)) { ++ WMT_PLAT_ERR_FUNC("sean debug [CCF]cannot get clk_infra_conn_main clock.\n"); ++ return PTR_ERR(clk_infra_conn_main); ++ } ++ WMT_PLAT_DBG_FUNC("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); ++ ++ reg_VCN18 = devm_regulator_get(&pdev->dev, "vcn18"); ++ if (IS_ERR(reg_VCN18)) { ++ ret = PTR_ERR(reg_VCN18); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN_1V8 fail, ret=%d\n", ret); ++ } ++ reg_VCN28 = devm_regulator_get(&pdev->dev, "vcn28"); ++ if (IS_ERR(reg_VCN28)) { ++ ret = PTR_ERR(reg_VCN28); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN_2V8 fail, ret=%d\n", ret); ++ } ++ reg_VCN33_BT = devm_regulator_get(&pdev->dev, "vcn33_bt"); ++ if (IS_ERR(reg_VCN33_BT)) { ++ ret = PTR_ERR(reg_VCN33_BT); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN33_BT fail, ret=%d\n", ret); ++ } ++ reg_VCN33_WIFI = devm_regulator_get(&pdev->dev, "vcn33_wifi"); ++ if (IS_ERR(reg_VCN33_WIFI)) { ++ ret = PTR_ERR(reg_VCN33_WIFI); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN33_WIFI fail, ret=%d\n", ret); ++ } ++ ++ rstc = devm_reset_control_get(&pdev->dev, "connsys"); ++ if (IS_ERR(rstc)) { ++ ret = PTR_ERR(rstc); ++ WMT_PLAT_ERR_FUNC("CanNot get consys reset. ret=%d\n", ret); ++ return PTR_ERR(rstc); ++ } ++ ++ consys_pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(consys_pinctrl)) { ++ ret = PTR_ERR(consys_pinctrl); ++ WMT_PLAT_ERR_FUNC("CanNot find consys pinctrl. ret=%d\n", ret); ++ return PTR_ERR(consys_pinctrl); ++ } ++ return 0; ++} ++ ++static INT32 mtk_wmt_remove(struct platform_device *pdev) ++{ ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++VOID mtk_wcn_consys_power_on(VOID) ++{ ++ INT32 iRet = -1; ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ iRet = pm_runtime_get_sync(&my_pdev->dev); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("pm_runtime_get_sync() fail(%d)\n", iRet); ++ else ++ WMT_PLAT_INFO_FUNC("pm_runtime_get_sync() CONSYS ok\n"); ++ ++ iRet = device_init_wakeup(&my_pdev->dev, true); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("device_init_wakeup(true) fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("device_init_wakeup(true) CONSYS ok\n"); ++} ++ ++VOID mtk_wcn_consys_power_off(VOID) ++{ ++ INT32 iRet = -1; ++ ++ iRet = pm_runtime_put_sync(&my_pdev->dev); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("pm_runtime_put_sync() fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("pm_runtime_put_sync() CONSYS ok\n"); ++ ++ iRet = device_init_wakeup(&my_pdev->dev, false); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("device_init_wakeup(false) fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("device_init_wakeup(false) CONSYS ok\n"); ++} ++ ++INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_type) ++{ ++ UINT32 retry = 10; ++ UINT32 consysHwChipId = 0; ++ ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),start\n", on); ++ if (on) { ++ WMT_PLAT_DBG_FUNC("++\n"); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /*need PMIC driver provide new API protocol */ ++ /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ ++ regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ ++ if (reg_VCN18) { ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ regulator_set_voltage(reg_VCN18, 1800000, 1800000); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (regulator_enable(reg_VCN18)) ++ WMT_PLAT_ERR_FUNC("enable VCN18 fail\n"); ++ else ++ WMT_PLAT_DBG_FUNC("enable VCN18 ok\n"); ++ } ++ udelay(150); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (co_clock_type) { ++ /*step0,clk buf ctrl */ ++ WMT_PLAT_INFO_FUNC("co clock type(%d),turn on clk buf\n", co_clock_type); ++#if CONSYS_CLOCK_BUF_CTRL ++ clk_buf_ctrl(CLK_BUF_CONN, 1); ++#endif ++ /*if co-clock mode: */ ++ /*2.set VCN28 to SW control mode (with PMIC_WRAP API) */ ++ /*turn on VCN28 LDO only when FMSYS is activated" */ ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ ++ } else { ++ /*if NOT co-clock: */ ++ /*2.1.switch VCN28 to HW control mode (with PMIC_WRAP API) */ ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x1 << 14);/*V28*/ ++ /*2.2.turn on VCN28 LDO (with PMIC_WRAP API)" */ ++ /*fix vcn28 not balance warning */ ++ if (reg_VCN28) { ++ regulator_set_voltage(reg_VCN28, 2800000, 2800000); ++ if (regulator_enable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("enable VCN_2V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("enable VCN_2V8 ok\n"); ++ } ++ } ++ ++ /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ reset_control_reset(rstc); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ mtk_wcn_consys_power_on(); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /*11.26M is ready now, delay 10us for mem_pd de-assert */ ++ udelay(10); ++ /*enable AP bus clock : connmcu_bus_pd API: enable_clock() ++?? */ ++ clk_prepare_enable(clk_infra_conn_main); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ WMT_PLAT_DBG_FUNC("[CCF]enable clk_infra_conn_main\n"); ++ /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ ++ while (retry-- > 0) { ++ consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET) - 0xf6d; ++ ++ if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { ++ WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); ++ break; ++ } ++ if ((consysHwChipId == 0x8163) || (consysHwChipId == 0x8127) || (consysHwChipId == 0x7623)) { ++ WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); ++ break; ++ } ++ ++ WMT_PLAT_ERR_FUNC("Read CONSYS chipId(0x%08x)", consysHwChipId); ++ msleep(20); ++ } ++ ++ if ((0 == retry) || (0 == consysHwChipId)) ++ WMT_PLAT_ERR_FUNC("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); ++ ++ msleep(40); ++ ++ } else { ++ ++ clk_disable_unprepare(clk_infra_conn_main); ++ WMT_PLAT_DBG_FUNC("[CCF] clk_disable_unprepare(clk_infra_conn_main) calling\n"); ++ mtk_wcn_consys_power_off(); ++ ++ if (co_clock_type) { ++ /*VCN28 has been turned off by GPS OR FM */ ++#if CONSYS_CLOCK_BUF_CTRL ++ clk_buf_ctrl(CLK_BUF_CONN, 0); ++#endif ++ } else { ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ ++ /*turn off VCN28 LDO (with PMIC_WRAP API)" */ ++ if (reg_VCN28) { ++ if (regulator_disable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("disable VCN_2V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("disable VCN_2V8 ok\n"); ++ } ++ } ++ ++ /*AP power off MT6625L VCN_1V8 LDO */ ++ regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); ++ if (reg_VCN18) { ++ if (regulator_disable(reg_VCN18)) ++ WMT_PLAT_ERR_FUNC("disable VCN_1V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("disable VCN_1V8 ok\n"); ++ } ++ ++ } ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),finish\n", on); ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_gpio_ctrl(UINT32 on) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), start\n", on); ++ ++ if (on) { ++ ++ /* TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok */ ++ /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); */ ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ registered and disabled\n"); ++ ++ } else { ++ ++ /* set bgf eint/all eint to deinit state, namely input low state */ ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); ++ WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ unregistered and disabled\n"); ++ /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); */ ++ } ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), finish\n", on); ++ return iRet; ++ ++} ++ ++INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, start\n"); ++ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); ++ iRet += mtk_wcn_consys_hw_gpio_ctrl(1); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, finish(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_pwr_off(VOID) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, start\n"); ++ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(0, 0); ++ iRet += mtk_wcn_consys_hw_gpio_ctrl(0); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, finish(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst start, eirq should be disabled before this step\n"); ++ ++ /*1. do whole hw power off flow */ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(0, co_clock_type); ++ ++ /*2. do whole hw power on flow */ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst finish, eirq should be enabled after this step\n"); ++ return iRet; ++} ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) ++{ ++ /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ ++ if (enable) { ++ if (1 == gBtWifiV33.counter) { ++ gBtWifiV33.counter++; ++ WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); ++ } else if (2 == gBtWifiV33.counter) { ++ WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); ++ } else { ++#if CONSYS_PMIC_CTRL_ENABLE ++ /*do BT PMIC on,depenency PMIC API ready */ ++ /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ ++ /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ ++ hwPowerOn(MT6323_POWER_LDO_VCN33, VOL_3300, "wcn_drv"); ++ upmu_set_vcn33_on_ctrl_bt(1); ++#endif ++ WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 on\n"); ++ gBtWifiV33.counter++; ++ } ++ ++ } else { ++ if (1 == gBtWifiV33.counter) { ++ /*do BT PMIC off */ ++ /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ ++#if CONSYS_PMIC_CTRL_ENABLE ++ upmu_set_vcn33_on_ctrl_bt(0); ++ hwPowerDown(MT6323_POWER_LDO_VCN33, "wcn_drv"); ++#endif ++ WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 off\n"); ++ gBtWifiV33.counter--; ++ } else if (2 == gBtWifiV33.counter) { ++ gBtWifiV33.counter--; ++ WMT_PLAT_DBG_FUNC("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); ++ } else { ++ WMT_PLAT_DBG_FUNC("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); ++ } ++ ++ } ++ /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) ++{ ++ mtk_wcn_consys_hw_bt_paldo_ctrl(enable); ++ return 0; ++} ++ ++#else ++INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) ++{ ++ ++ if (enable) { ++ /*do BT PMIC on,depenency PMIC API ready */ ++ /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ ++ if (reg_VCN33_BT) { ++ regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); ++ if (regulator_enable(reg_VCN33_BT)) ++ WMT_PLAT_ERR_FUNC("WMT do BT PMIC on fail!\n"); ++ } ++ regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x1 << 5);/*BT*/ ++ WMT_PLAT_INFO_FUNC("WMT do BT PMIC on\n"); ++ } else { ++ /*do BT PMIC off */ ++ /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ ++ regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x0 << 5);/*BT*/ ++ if (reg_VCN33_BT) ++ if (regulator_disable(reg_VCN33_BT)) ++ WMT_PLAT_ERR_FUNC("WMT do BT PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("WMT do BT PMIC off\n"); ++ } ++ ++ return 0; ++ ++} ++ ++INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) ++{ ++ ++ if (enable) { ++ /*do WIFI PMIC on,depenency PMIC API ready */ ++ /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ ++ if (reg_VCN33_WIFI) { ++ regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); ++ if (regulator_enable(reg_VCN33_WIFI)) ++ WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC on fail!\n"); ++ else ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on !\n"); ++ } ++ regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x1 << 14);/*WIFI*/ ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on\n"); ++ } else { ++ /*do WIFI PMIC off */ ++ /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ ++ regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x0 << 14);/*WIFI*/ ++ if (reg_VCN33_WIFI) ++ if (regulator_disable(reg_VCN33_WIFI)) ++ WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC off\n"); ++ } ++ ++ return 0; ++} ++ ++#endif ++INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) ++{ ++ if (enable) { ++ /*in co-clock mode,need to turn on vcn28 when fm on */ ++ if (reg_VCN28) { ++ regulator_set_voltage(reg_VCN28, 2800000, 2800000); ++ if (regulator_enable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC on fail!\n"); ++ } ++ WMT_PLAT_INFO_FUNC("turn on vcn28 for fm/gps usage in co-clock mode\n"); ++ } else { ++ /*in co-clock mode,need to turn off vcn28 when fm off */ ++ if (reg_VCN28) ++ if (regulator_disable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("turn off vcn28 for fm/gps usage in co-clock mode\n"); ++ } ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_state_show(VOID) ++{ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_restore(struct device *device) ++{ ++ UINT32 addrPhy = 0; ++ ++ if (gConEmiPhyBase) { ++ ++#if CONSYS_EMI_MPU_SETTING ++ /*set MPU for EMI share Memory */ ++ WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); ++ ++#if 0 ++ emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, ++ gConEmiPhyBase + SZ_1M, ++ 5, ++ SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); ++ ++ ++#else ++ WMT_PLAT_WARN_FUNC("not define platform config\n"); ++#endif ++ ++#endif ++ /*consys to ap emi remapping register:10001310, cal remapping address */ ++ addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; ++ ++ /*enable consys to ap emi remapping bit12 */ ++ addrPhy = addrPhy | 0x1000; ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); ++ ++#if 1 ++ pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); ++#else ++ pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); ++#endif ++ if (pEmibaseaddr) { ++ WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); ++ memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); ++ } else { ++ WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); ++ } ++ } else { ++ WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); ++ } ++ ++ return 0; ++} ++ ++/*Reserved memory by device tree!*/ ++int reserve_memory_consys_fn(struct reserved_mem *rmem) ++{ ++ WMT_PLAT_WARN_FUNC(" name: %s, base: 0x%llx, size: 0x%llx\n", rmem->name, ++ (unsigned long long)rmem->base, (unsigned long long)rmem->size); ++ gConEmiPhyBase = rmem->base; ++ return 0; ++} ++ ++RESERVEDMEM_OF_DECLARE(reserve_memory_test, "mediatek,consys-reserve-memory", reserve_memory_consys_fn); ++ ++ ++INT32 mtk_wcn_consys_hw_init(void) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 addrPhy = 0; ++ INT32 i = 0; ++ struct device_node *node = NULL; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); ++ if (node) { ++ /* registers base address */ ++ conn_reg.mcu_base = (SIZE_T) of_iomap(node, i); ++ WMT_PLAT_DBG_FUNC("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); ++ i++; ++ ++ conn_reg.topckgen_base = (SIZE_T) of_iomap(node, i); ++ WMT_PLAT_DBG_FUNC("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); ++ i++; ++ } else { ++ WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); ++ return iRet; ++ } ++ if (gConEmiPhyBase) { ++#if CONSYS_EMI_MPU_SETTING ++ /*set MPU for EMI share Memory */ ++ WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); ++ ++#if 0 ++ emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, ++ gConEmiPhyBase + SZ_1M, ++ 5, ++ SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); ++#else ++ WMT_PLAT_WARN_FUNC("not define platform config\n"); ++#endif ++ ++#endif ++ WMT_PLAT_DBG_FUNC("get consys start phy address(0x%zx)\n", (SIZE_T) gConEmiPhyBase); ++ ++ /*consys to ap emi remapping register:10001310, cal remapping address */ ++ addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; ++ ++ /*enable consys to ap emi remapping bit12 */ ++ addrPhy = addrPhy | 0x1000; ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump(0x%08x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); ++ ++#if 1 ++ pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); ++#else ++ pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); ++#endif ++ /* pEmibaseaddr = ioremap_nocache(0x80090400,270*KBYTE); */ ++ if (pEmibaseaddr) { ++ WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); ++ memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); ++ iRet = 0; ++ } else { ++ WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); ++ } ++ } else { ++ WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); ++ } ++#ifdef CONFIG_MTK_HIBERNATION ++ WMT_PLAT_INFO_FUNC("register connsys restore cb for complying with IPOH function\n"); ++ register_swsusp_restore_noirq_func(ID_M_CONNSYS, mtk_wcn_consys_hw_restore, NULL); ++#endif ++ iRet = platform_driver_register(&mtk_wmt_dev_drv); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("WMT platform driver registered failed(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_deinit(void) ++{ ++ if (pEmibaseaddr) { ++ iounmap(pEmibaseaddr); ++ pEmibaseaddr = NULL; ++ } ++#ifdef CONFIG_MTK_HIBERNATION ++ unregister_swsusp_restore_noirq_func(ID_M_CONNSYS); ++#endif ++ ++ platform_driver_unregister(&mtk_wmt_dev_drv); ++ return 0; ++} ++ ++UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset) ++{ ++ UINT8 *p_virtual_addr = NULL; ++ ++ if (!pEmibaseaddr) { ++ WMT_PLAT_ERR_FUNC("EMI base address is NULL\n"); ++ return NULL; ++ } ++ WMT_PLAT_DBG_FUNC("ctrl_state_offset(%08x)\n", ctrl_state_offset); ++ p_virtual_addr = pEmibaseaddr + ctrl_state_offset; ++ ++ return p_virtual_addr; ++} ++ ++UINT32 mtk_wcn_consys_soc_chipid(void) ++{ ++ return PLATFORM_SOC_CHIP; ++} ++ ++struct pinctrl *mtk_wcn_consys_get_pinctrl() ++{ ++ return consys_pinctrl; ++} ++INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 str_buf) ++{ ++ PUINT8 vir_addr = NULL; ++ ++ vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP); ++ if (!vir_addr) { ++ WMT_PLAT_ERR_FUNC("get vir address fail\n"); ++ return -2; ++ } ++ memcpy(vir_addr, str_buf, DYNAMIC_DUMP_GROUP_NUM*8); ++ WMT_PLAT_INFO_FUNC("dynamic dump register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c +new file mode 100644 +index 000000000000..3a3be8308f6a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c +@@ -0,0 +1,1071 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-PLAT]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++ ++/* ALPS header files */ ++/*#include */ ++/*#include */ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++#include ++#endif ++#include ++ ++/* MTK_WCN_COMBO header files */ ++#include "osal_typedef.h" ++#include "mtk_wcn_consys_hw.h" ++#include "stp_dbg.h" ++ ++#define CFG_WMT_WAKELOCK_SUPPORT 1 ++ ++#ifdef CONFIG_MTK_MT6306_SUPPORT ++#define MTK_WCN_MT6306_IS_READY 1 ++#else ++#define MTK_WCN_MT6306_IS_READY 0 ++#endif ++ ++#if MTK_WCN_MT6306_IS_READY ++#include ++ ++#ifdef GPIO_GPS_LNA_PIN ++#undef GPIO_GPS_LNA_PIN ++#endif ++ ++#define GPIO_GPS_LNA_PIN GPIO7 ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { ++ .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, ++ .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, ++ .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, ++ .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, ++ .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, ++ .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, ++ .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, ++ .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, ++ .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, ++ .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, ++ .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, ++ .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, ++ .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, ++}; ++ ++CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { ++ .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, ++ .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, ++ .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, ++ .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, ++ .p_ecso = &mtk_wcn_emi_state_off, ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static VOID wmt_plat_bgf_eirq_cb(VOID); ++ ++static INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state); ++ ++static INT32 wmt_plat_dump_pin_conf(VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++UINT32 gCoClockFlag = 0; ++BGF_IRQ_BALANCE gbgfIrqBle; ++UINT32 wmtPlatLogLvl = WMT_PLAT_LOG_DBG; ++#if CONSYS_BT_WIFI_SHARE_V33 ++BT_WIFI_V33_STATUS gBtWifiV33; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_WMT_WAKELOCK_SUPPORT ++static struct mutex gOsSLock; ++#ifdef CONFIG_PM_WAKELOCKS ++static struct wakeup_source wmtWakeLock; ++#else ++static struct wake_lock wmtWakeLock; ++#endif ++#endif ++ ++irq_cb wmt_plat_bgf_irq_cb = NULL; ++device_audio_if_cb wmt_plat_audio_if_cb = NULL; ++func_ctrl_cb wmt_plat_func_ctrl_cb = NULL; ++thermal_query_ctrl_cb wmt_plat_thermal_query_ctrl_cb = NULL; ++deep_idle_ctrl_cb wmt_plat_deep_idle_ctrl_cb = NULL; ++ ++static const fp_set_pin gfp_set_pin_table[] = { ++ [PIN_BGF_EINT] = wmt_plat_bgf_eint_ctrl, ++ [PIN_I2S_GRP] = wmt_plat_i2s_ctrl, ++ [PIN_GPS_SYNC] = wmt_plat_gps_sync_ctrl, ++ [PIN_GPS_LNA] = wmt_plat_gps_lna_ctrl, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*! ++ * \brief audio control callback function for CMB_STUB on ALPS ++ * ++ * A platform function required for dynamic binding with CMB_STUB on ALPS. ++ * ++ * \param state desired audio interface state to use ++ * \param flag audio interface control options ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ * \retval < 0 error for operation fail ++ */ ++INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) ++{ ++ INT32 iRet = 0; ++ UINT32 pinShare = 0; ++ ++ /* input sanity check */ ++ if ((CMB_STUB_AIF_MAX <= state) ++ || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { ++ return -1; ++ } ++ ++ iRet = 0; ++ ++ /* set host side first */ ++ switch (state) { ++ case CMB_STUB_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); ++ break; ++ ++ case CMB_STUB_AIF_1: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); ++ break; ++ ++ case CMB_STUB_AIF_2: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); ++ break; ++ ++ case CMB_STUB_AIF_3: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); ++ break; ++ ++ default: ++ /* FIXME: move to cust folder? */ ++ WMT_PLAT_ERR_FUNC("invalid state [%d]\n", state); ++ iRet = -1; ++ break; ++ } ++ ++ if (CMB_STUB_AIF_CTRL_EN == ctrl) { ++ WMT_PLAT_INFO_FUNC("call chip aif setting\n"); ++ /* need to control chip side GPIO */ ++ if (NULL != wmt_plat_audio_if_cb) { ++ iRet += (*wmt_plat_audio_if_cb) (state, (pinShare) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++ } else { ++ WMT_PLAT_WARN_FUNC("wmt_plat_audio_if_cb is not registered\n"); ++ iRet -= 1; ++ } ++ ++ } else { ++ WMT_PLAT_INFO_FUNC("skip chip aif setting\n"); ++ } ++ ++ return iRet; ++ ++} ++ ++static VOID wmt_plat_func_ctrl(UINT32 type, UINT32 on) ++{ ++ if (wmt_plat_func_ctrl_cb) ++ (*wmt_plat_func_ctrl_cb) (on, type); ++} ++ ++static long wmt_plat_thermal_ctrl(VOID) ++{ ++ long temp = 0; ++ ++ if (wmt_plat_thermal_query_ctrl_cb) ++ temp = (*wmt_plat_thermal_query_ctrl_cb) (); ++ ++ return temp; ++} ++ ++static INT32 wmt_plat_deep_idle_ctrl(UINT32 dpilde_ctrl) ++{ ++ INT32 iRet = -1; ++ ++ if (wmt_plat_deep_idle_ctrl_cb) ++ iRet = (*wmt_plat_deep_idle_ctrl_cb) (dpilde_ctrl); ++ ++ return iRet; ++} ++ ++static VOID wmt_plat_bgf_eirq_cb(VOID) ++{ ++#if CFG_WMT_PS_SUPPORT ++/* #error "need to disable EINT here" */ ++ /* wmt_lib_ps_irq_cb(); */ ++ if (NULL != wmt_plat_bgf_irq_cb) ++ (*(wmt_plat_bgf_irq_cb)) (); ++ else ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: wmt_plat_bgf_irq_cb not registered\n"); ++#else ++ return; ++#endif ++ ++} ++ ++irqreturn_t wmt_plat_bgf_irq_isr(INT32 i, VOID *arg) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ wmt_plat_bgf_eirq_cb(); ++#else ++ WMT_PLAT_INFO_FUNC("skip irq handing because psm is disable"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb) ++{ ++ wmt_plat_bgf_irq_cb = bgf_irq_cb; ++} ++EXPORT_SYMBOL(wmt_plat_irq_cb_reg); ++ ++VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb) ++{ ++ wmt_plat_audio_if_cb = aif_ctrl_cb; ++} ++EXPORT_SYMBOL(wmt_plat_aif_cb_reg); ++ ++VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl) ++{ ++ wmt_plat_func_ctrl_cb = subsys_func_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_func_ctrl_cb_reg); ++ ++VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl) ++{ ++ wmt_plat_thermal_query_ctrl_cb = thermal_query_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_thermal_ctrl_cb_reg); ++ ++VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl) ++{ ++ wmt_plat_deep_idle_ctrl_cb = deep_idle_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_deep_idle_ctrl_cb_reg); ++ ++UINT32 wmt_plat_soc_co_clock_flag_get(VOID) ++{ ++ return gCoClockFlag; ++} ++ ++static UINT32 wmt_plat_soc_co_clock_flag_set(UINT32 flag) ++{ ++ gCoClockFlag = flag; ++ return 0; ++} ++ ++INT32 wmt_plat_init(UINT32 co_clock_type) ++{ ++ CMB_STUB_CB stub_cb; ++ INT32 iret; ++ /*init wmt function ctrl wakelock if wake lock is supported by host platform */ ++ ++ wmt_plat_soc_co_clock_flag_set(co_clock_type); ++ ++ stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; ++ stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; ++ stub_cb.thermal_query_cb = wmt_plat_thermal_ctrl; ++ stub_cb.deep_idle_ctrl_cb = wmt_plat_deep_idle_ctrl; ++ stub_cb.size = sizeof(stub_cb); ++ ++ /* register to cmb_stub */ ++ iret = mtk_wcn_cmb_stub_reg(&stub_cb); ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++#ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_init(&wmtWakeLock, "wmtFuncCtrl"); ++#else ++ wake_lock_init(&wmtWakeLock, WAKE_LOCK_SUSPEND, "wmtFuncCtrl"); ++#endif ++ mutex_init(&gOsSLock); ++#endif ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++ gBtWifiV33.counter = 0; ++ spin_lock_init(&gBtWifiV33.lock); ++#endif ++ ++ iret += mtk_wcn_consys_hw_init(); ++ ++ spin_lock_init(&gbgfIrqBle.lock); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_init); ++ ++INT32 wmt_plat_deinit(VOID) ++{ ++ INT32 iret = 0; ++ /* 2. unreg to cmb_stub */ ++ iret = mtk_wcn_cmb_stub_unreg(); ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wmt wakelock deinit\n",__FUNCTION__,__LINE__); ++ /*3. wmt wakelock deinit */ ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++#ifdef CONFIG_PM_WAKELOCKS ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wakeup_source_trash\n",__FUNCTION__,__LINE__); ++ wakeup_source_trash(&wmtWakeLock); ++#else ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wake lock destroy %d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); ++//destroy calls wakeup_source_trash with &lock->ws ++printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock:%d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); ++printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock->ws: %d\n",__FUNCTION__,__LINE__,(int)&(wmtWakeLock.ws)); ++ wake_lock_destroy(&wmtWakeLock); ++#endif ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling mutex_destroy\n",__FUNCTION__,__LINE__); ++ mutex_destroy(&gOsSLock); ++ WMT_PLAT_DBG_FUNC("destroy wmtWakeLock\n"); ++#endif ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling consys hw deinit\n",__FUNCTION__,__LINE__); ++ ++ iret += mtk_wcn_consys_hw_deinit(); ++ ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_deinit); ++ ++static INT32 wmt_plat_dump_pin_conf(VOID) ++{ ++ WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration start<=\n"); ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#ifdef GPIO_COMBO_BGF_EINT_PIN ++ WMT_PLAT_DBG_FUNC("BGF_EINT(GPIO%d)\n", GPIO_COMBO_BGF_EINT_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("BGF_EINT(not defined)\n"); ++#endif ++ ++#ifdef CUST_EINT_COMBO_BGF_NUM ++ WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(%d)\n", CUST_EINT_COMBO_BGF_NUM); ++#else ++ WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(not defined)\n"); ++#endif ++ ++#ifdef GPIO_COMBO_URXD_PIN ++ WMT_PLAT_DBG_FUNC("UART_RX(GPIO%d)\n", GPIO_COMBO_URXD_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("UART_RX(not defined)\n"); ++#endif ++#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) ++#ifdef GPIO_COMBO_I2S_CK_PIN ++ WMT_PLAT_DBG_FUNC("I2S_CK(GPIO%d)\n", GPIO_COMBO_I2S_CK_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_CK(not defined)\n"); ++#endif ++#ifdef GPIO_COMBO_I2S_WS_PIN ++ WMT_PLAT_DBG_FUNC("I2S_WS(GPIO%d)\n", GPIO_COMBO_I2S_WS_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_WS(not defined)\n"); ++#endif ++#ifdef GPIO_COMBO_I2S_DAT_PIN ++ WMT_PLAT_DBG_FUNC("I2S_DAT(GPIO%d)\n", GPIO_COMBO_I2S_DAT_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_DAT(not defined)\n"); ++#endif ++#else /* FM_ANALOG_INPUT || FM_ANALOG_OUTPUT */ ++ WMT_PLAT_DBG_FUNC("FM digital mode is not set, no need for I2S GPIOs\n"); ++#endif ++#ifdef GPIO_GPS_SYNC_PIN ++ WMT_PLAT_DBG_FUNC("GPS_SYNC(GPIO%d)\n", GPIO_GPS_SYNC_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("GPS_SYNC(not defined)\n"); ++#endif ++ ++#ifdef GPIO_GPS_LNA_PIN ++ WMT_PLAT_INFO_FUNC("GPS_LNA(GPIO%d)\n", GPIO_GPS_LNA_PIN); ++#else ++ WMT_PLAT_INFO_FUNC("GPS_LNA(not defined)\n"); ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration emds<=\n"); ++ return 0; ++} ++ ++INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state) ++{ ++ INT32 ret = -1; ++ ++ switch (state) { ++ case FUNC_ON: ++ /* TODO:[ChangeFeature][George] always output this or by request throuth /proc or sysfs? */ ++ wmt_plat_dump_pin_conf(); ++ ret = mtk_wcn_consys_hw_pwr_on(gCoClockFlag); ++ break; ++ ++ case FUNC_OFF: ++ ret = mtk_wcn_consys_hw_pwr_off(); ++ break; ++ ++ case FUNC_RST: ++ ret = mtk_wcn_consys_hw_rst(gCoClockFlag); ++ break; ++ case FUNC_STAT: ++ ret = mtk_wcn_consys_hw_state_show(); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) in pwr_ctrl\n", state); ++ break; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(wmt_plat_pwr_ctrl); ++ ++INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) ++{ ++#ifdef CONFIG_OF ++ struct device_node *node; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++#endif ++ INT32 iret = -EINVAL; ++ static INT32 bgf_irq_num = -1; ++ static UINT32 bgf_irq_flag; ++ /* TODO: [ChangeFeature][GeorgeKuo]: use another function to handle this, as done in gpio_ctrls */ ++ ++ if ((PIN_STA_INIT != state) ++ && (PIN_STA_DEINIT != state) ++ && (PIN_STA_EINT_EN != state) ++ && (PIN_STA_EINT_DIS != state)) { ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:invalid PIN_STATE(%d) in eirq_ctrl for PIN(%d)\n", state, id); ++ return -1; ++ } ++ ++ switch (id) { ++ case PIN_BGF_EINT: ++ ++ if (PIN_STA_INIT == state) { ++#ifdef CONFIG_OF ++ node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); ++ if (node) { ++ bgf_irq_num = irq_of_parse_and_map(node, 0); ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ WMT_PLAT_ERR_FUNC("get irq flags from DTS fail!!\n"); ++ return iret; ++ } ++ bgf_irq_flag = irq_info[2]; ++ WMT_PLAT_INFO_FUNC("get irq id(%d) and irq trigger flag(%d) from DT\n", bgf_irq_num, ++ bgf_irq_flag); ++ } else { ++ WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); ++ return iret; ++ } ++#else ++ bgf_irq_num = MT_CONN2AP_BTIF_WAKEUP_IRQ_ID; ++ bgf_irq_flag = IRQF_TRIGGER_LOW; ++#endif ++ iret = request_irq(bgf_irq_num, wmt_plat_bgf_irq_isr, bgf_irq_flag, "BTIF_WAKEUP_IRQ", NULL); ++ if (iret) { ++ WMT_PLAT_ERR_FUNC("request_irq fail,irq_no(%d),iret(%d)\n", bgf_irq_num, iret); ++ return iret; ++ } ++ gbgfIrqBle.counter = 1; ++ ++ } else if (PIN_STA_EINT_EN == state) { ++ ++ spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ if (gbgfIrqBle.counter) { ++ WMT_PLAT_DBG_FUNC("BGF INT has been enabled,counter(%d)\n", gbgfIrqBle.counter); ++ } else { ++ enable_irq(bgf_irq_num); ++ gbgfIrqBle.counter++; ++ } ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (en)\n"); ++ spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ } else if (PIN_STA_EINT_DIS == state) { ++ spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ if (!gbgfIrqBle.counter) { ++ WMT_PLAT_INFO_FUNC("BGF INT has been disabled,counter(%d)\n", gbgfIrqBle.counter); ++ } else { ++ disable_irq_nosync(bgf_irq_num); ++ gbgfIrqBle.counter--; ++ } ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (dis)\n"); ++ spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ } else { ++ free_irq(bgf_irq_num, NULL); ++ /* de-init: nothing to do in ALPS, such as un-registration... */ ++ } ++ iret = 0; ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:unsupported EIRQ(PIN_ID:%d) in eirq_ctrl\n", id); ++ iret = -1; ++ break; ++ } ++ ++ return iret; ++} ++EXPORT_SYMBOL(wmt_plat_eirq_ctrl); ++ ++INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) ++{ ++ if ((PIN_ID_MAX > id) ++ && (PIN_STA_MAX > state)) { ++ ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ if (gfp_set_pin_table[id]) ++ return (*(gfp_set_pin_table[id])) (state); /* .handler */ ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: null fp for gpio_ctrl(%d)\n", id); ++ return -2; ++ } ++ return -1; ++} ++EXPORT_SYMBOL(wmt_plat_gpio_ctrl); ++ ++INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state) ++{ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++#ifdef GPIO_COMBO_BGF_EINT_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ /*set to gpio input low, pull down enable */ ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt init(in pd)\n"); ++ break; ++ ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_UP); ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_EINT); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt mux (eint)\n"); ++ break; ++ ++ case PIN_STA_IN_L: ++ case PIN_STA_DEINIT: ++ /*set to gpio input low, pull down enable */ ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt deinit(in pd)\n"); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on BGF EINT\n", state); ++ break; ++ } ++#else ++ WMT_PLAT_INFO_FUNC("WMT-PLAT:BGF EINT not defined\n"); ++#endif ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state) ++{ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#ifdef GPIO_GPS_SYNC_PIN ++#ifndef GPIO_GPS_SYNC_PIN_M_GPS_SYNC ++#ifdef GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC ++#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC ++#else ++#ifdef GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC ++#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC ++#endif ++#endif ++#endif ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_GPS_SYNC_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_GPS_SYNC_PIN, GPIO_OUT_ZERO); ++ break; ++ ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPS_SYNC); ++ break; ++ ++ default: ++ break; ++ } ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++#if MTK_WCN_MT6306_IS_READY ++/* MT6306 GPIO7 is GPIO_GPS_LNA_EN, for K2 common phone pin modification */ ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) ++{ ++#ifdef GPIO_GPS_LNA_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin ctrl %d!\n", state); ++ mt6306_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ case PIN_STA_OUT_H: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin output high!\n"); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); ++ break; ++ case PIN_STA_OUT_L: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin output low!\n"); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); ++ return 0; ++#endif ++} ++#else ++ ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) ++{ ++#if !defined(CONFIG_MTK_GPIO_LEGACY) ++ static struct pinctrl_state *gps_lna_init; ++ static struct pinctrl_state *gps_lna_oh; ++ static struct pinctrl_state *gps_lna_ol; ++ static struct pinctrl *consys_pinctrl; ++ ++ WMT_PLAT_DBG_FUNC("ENTER++\n"); ++ consys_pinctrl = mtk_wcn_consys_get_pinctrl(); ++ if (NULL == consys_pinctrl) { ++ WMT_PLAT_ERR_FUNC("get consys pinctrl fail\n"); ++ return -1; ++ } ++ ++ gps_lna_init = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_init"); ++ if (NULL == gps_lna_init) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin init state!\n"); ++ return -2; ++ } ++ ++ gps_lna_oh = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_oh"); ++ if (NULL == gps_lna_oh) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin oh state!\n"); ++ return -3; ++ } ++ ++ gps_lna_ol = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_ol"); ++ if (NULL == gps_lna_ol) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin ol state!\n"); ++ return -4; ++ } ++ ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ pinctrl_select_state(consys_pinctrl, gps_lna_init); ++ WMT_PLAT_INFO_FUNC("set gps lna to init\n"); ++ break; ++ case PIN_STA_OUT_H: ++ pinctrl_select_state(consys_pinctrl, gps_lna_oh); ++ WMT_PLAT_INFO_FUNC("set gps lna to oh\n"); ++ break; ++ case PIN_STA_OUT_L: ++ pinctrl_select_state(consys_pinctrl, gps_lna_ol); ++ WMT_PLAT_INFO_FUNC("set gps lna to ol\n"); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++#ifdef GPIO_GPS_LNA_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_pull_enable(GPIO_GPS_LNA_PIN, GPIO_PULL_DISABLE); ++ mt_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_mode(GPIO_GPS_LNA_PIN, GPIO_GPS_LNA_PIN_M_GPIO); ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ case PIN_STA_OUT_H: ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); ++ break; ++ case PIN_STA_OUT_L: ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); ++ return 0; ++#endif ++#endif /* !defined(CONFIG_MTK_GPIO_LEGACY) */ ++} ++#endif ++ ++INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state) ++{ ++ /* TODO: [NewFeature][GeorgeKuo]: GPIO_I2Sx is changed according to different project. */ ++ /* TODO: provide a translation table in board_custom.h for different ALPS project customization. */ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) ++#if defined(GPIO_COMBO_I2S_CK_PIN) ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_I2S0_CK); ++ mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_I2S0_WS); ++ mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_I2S0_DAT); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S init (I2S0 system)\n"); ++ break; ++ case PIN_STA_IN_L: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_CK_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_CK_PIN, GPIO_OUT_ZERO); ++ ++ mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_WS_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_WS_PIN, GPIO_OUT_ZERO); ++ ++ mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_DAT_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_DAT_PIN, GPIO_OUT_ZERO); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S deinit (out 0)\n"); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on I2S Group\n", state); ++ break; ++ } ++#else ++ WMT_PLAT_ERR_FUNC("[MT6620]Error:FM digital mode set, but no I2S GPIOs defined\n"); ++#endif ++#else ++ WMT_PLAT_INFO_FUNC ++ ("[MT6620]warnning:FM digital mode is not set, no I2S GPIO settings should be modified by combo driver\n"); ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId) ++{ ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++ static INT32 counter; ++ INT32 status; ++ INT32 ret = 0; ++ ++ ret = mutex_lock_killable(&gOsSLock); ++ if (ret) { ++ WMT_PLAT_ERR_FUNC("--->lock gOsSLock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (WL_OP_GET == opId) ++ ++counter; ++ else if (WL_OP_PUT == opId) ++ --counter; ++ ++ mutex_unlock(&gOsSLock); ++ if (WL_OP_GET == opId && counter == 1) { ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_stay_awake(&wmtWakeLock); ++ status = wmtWakeLock.active; ++ #else ++ wake_lock(&wmtWakeLock); ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_lock(%d), counter(%d)\n", status, counter); ++ ++ } else if (WL_OP_PUT == opId && counter == 0) { ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_relax(&wmtWakeLock); ++ status = wmtWakeLock.active; ++ #else ++ wake_unlock(&wmtWakeLock); ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_unlock(%d), counter(%d)\n", status, counter); ++ } else { ++ #ifdef CONFIG_PM_WAKELOCKS ++ status = wmtWakeLock.active; ++ #else ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: wakelock status(%d), counter(%d)\n", status, counter); ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: host awake function is not supported.\n"); ++ return 0; ++ ++#endif ++} ++EXPORT_SYMBOL(wmt_plat_wake_lock_ctrl); ++ ++INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo) ++{ ++ INT32 iRet = 0; ++ ++ switch (ePt) { ++ ++ case BT_PALDO: ++ iRet = mtk_wcn_consys_hw_bt_paldo_ctrl(ePo); ++ break; ++ case WIFI_PALDO: ++ iRet = mtk_wcn_consys_hw_wifi_paldo_ctrl(ePo); ++ break; ++ case FM_PALDO: ++ case GPS_PALDO: ++ iRet = mtk_wcn_consys_hw_vcn28_ctrl(ePo); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid type(%d) in palod_ctrl\n", ePt); ++ break; ++ } ++ return iRet; ++} ++EXPORT_SYMBOL(wmt_plat_soc_paldo_ctrl); ++ ++UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset) ++{ ++ return mtk_wcn_consys_emi_virt_addr_get(offset); ++} ++EXPORT_SYMBOL(wmt_plat_get_emi_virt_add); ++ ++P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID) ++{ ++ return &mtk_wcn_emi_addr_info; ++} ++EXPORT_SYMBOL(wmt_plat_get_emi_phy_add); ++ ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en) ++{ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_jtag_flag_ctrl); ++#endif ++ ++#if CFG_WMT_DUMP_INT_STATUS ++VOID wmt_plat_BGF_irq_dump_status(VOID) ++{ ++ WMT_PLAT_INFO_FUNC("this function is null in MT8127\n"); ++} ++EXPORT_SYMBOL(wmt_plat_BGF_irq_dump_status); ++ ++MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID) ++{ ++ return MTK_WCN_BOOL_FALSE; ++} ++EXPORT_SYMBOL(wmt_plat_dump_BGF_irq_status); ++#endif ++ ++UINT32 wmt_plat_read_cpupcr(void) ++{ ++ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); ++} ++EXPORT_SYMBOL(wmt_plat_read_cpupcr); ++ ++UINT32 wmt_plat_read_dmaregs(UINT32 type) ++{ ++ return 0; ++#if 0 ++ switch (type) { ++ case CONNSYS_CLK_GATE_STATUS: ++ return CONSYS_REG_READ(CONNSYS_CLK_GATE_STATUS_REG); ++ case CONSYS_EMI_STATUS: ++ return CONSYS_REG_READ(CONSYS_EMI_STATUS_REG); ++ case SYSRAM1: ++ return CONSYS_REG_READ(SYSRAM1_REG); ++ case SYSRAM2: ++ return CONSYS_REG_READ(SYSRAM2_REG); ++ case SYSRAM3: ++ return CONSYS_REG_READ(SYSRAM3_REG); ++ default: ++ return 0; ++ } ++#endif ++} ++ ++INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_STATE); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, state); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_set_host_dump_state); ++ ++UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ switch (type) { ++ case STP_FORCE_TRG_ASSERT_EMI: ++ ++ WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); ++ WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); ++ break; ++ case STP_FORCE_TRG_ASSERT_DEBUG_PIN: ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + ++ CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); ++ WMT_PLAT_INFO_FUNC("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); ++ usleep_range(64, 96); ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + ++ CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); ++ WMT_PLAT_INFO_FUNC("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); ++ ++ break; ++ default: ++ WMT_PLAT_ERR_FUNC("unknown force trigger assert type\n"); ++ break; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_force_trigger_assert); ++ ++INT32 wmt_plat_update_host_sync_num(VOID) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ UINT32 sync_num = 0; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_NUM); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ sync_num = CONSYS_REG_READ(p_virtual_addr); ++ CONSYS_REG_WRITE(p_virtual_addr, sync_num + 1); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_update_host_sync_num); ++ ++INT32 wmt_plat_get_dump_info(UINT32 offset) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(offset); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ WMT_PLAT_INFO_FUNC("connsys_reg_read (0x%x), (0x%p), (0x%x)\n", CONSYS_REG_READ(p_virtual_addr), p_virtual_addr, ++ offset); ++ return CONSYS_REG_READ(p_virtual_addr); ++} ++EXPORT_SYMBOL(wmt_plat_get_dump_info); ++ ++UINT32 wmt_plat_get_soc_chipid(void) ++{ ++ UINT32 chipId = mtk_wcn_consys_soc_chipid(); ++ ++ WMT_PLAT_INFO_FUNC("current SOC chip:0x%x\n", chipId); ++ return chipId; ++} ++EXPORT_SYMBOL(wmt_plat_get_soc_chipid); ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++INT32 wmt_plat_get_tdm_antsel_index(VOID) ++{ ++ WMT_PLAT_INFO_FUNC("not support LTE in this platform\n"); ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_get_tdm_antsel_index); ++#endif ++INT32 wmt_plat_set_dbg_mode(UINT32 flag) ++{ ++ return -1; ++} ++VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf) ++{ ++ mtk_wcn_consys_set_dynamic_dump(buf); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/Makefile b/drivers/misc/mediatek/connectivity/wlan/Makefile +new file mode 100644 +index 000000000000..36ce26810912 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/Makefile +@@ -0,0 +1,8 @@ ++ifeq ($(CONFIG_MTK_COMBO_WIFI),y) ++ subdir-ccflags-y += -D MTK_WCN_BUILT_IN_DRIVER ++endif ++ ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++$(warning include gen2) ++ obj-y += gen2/ ++endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile +new file mode 100644 +index 000000000000..09e4d66436a0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile +@@ -0,0 +1,237 @@ ++# --------------------------------------------------- ++# Compile Options ++# --------------------------------------------------- ++ccflags-y += -DLINUX -DMT6628 ++ ++ccflags-y += -DCFG_SUPPORT_AGPS_ASSIST=1 ++ccflags-y += -DCFG_SUPPORT_TSF_USING_BOOTTIME=1 ++ccflags-y += -DCFG_P2P_LEGACY_COEX_REVISE=1 ++ccflags-y += -DARP_MONITER_ENABLE=1 ++ ++ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_WAPI=1 ++else ++ ccflags-y += -DCFG_SUPPORT_WAPI=0 ++endif ++ ++ifeq ($(CONFIG_MTK_WIFI_MCC_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_MCC=1 ++else ++ ccflags-y += -DCFG_SUPPORT_MCC=0 ++endif ++ ++ifeq ($(CONFIG_HAVE_XLOG_FEATURE), y) ++ ccflags-y += -DCFG_SUPPORT_XLOG=1 ++else ++ ccflags-y += -DCFG_SUPPORT_XLOG=0 ++endif ++ ++ifeq ($(CONFIG_MTK_AEE_FEATURE), y) ++ ccflags-y += -DCFG_SUPPORT_AEE=1 ++else ++ ccflags-y += -DCFG_SUPPORT_AEE=0 ++endif ++ ++#ifeq ($(CONFIG_MTK_COMBO_WIFI_HIF_SDIO1), y) ++# ccflags-y += -D_HIF_SDIO=1 ++#endif ++ ++ifeq ($(CONFIG_MTK_PASSPOINT_R1_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=1 ++ ccflags-y += -DCFG_HS20_DEBUG=1 ++ ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=1 ++else ++ ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=0 ++ ccflags-y += -DCFG_HS20_DEBUG=0 ++ ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=0 ++endif ++ ++MTK_MET_PROFILING_SUPPORT = no ++ifeq ($(MTK_MET_PROFILING_SUPPORT), yes) ++ ccflags-y += -DCFG_SUPPORT_MET_PROFILING=1 ++else ++ ccflags-y += -DCFG_SUPPORT_MET_PROFILING=0 ++endif ++ ++ifeq ($(CONFIG_MTK_TC1_FEATURE), y) ++ifeq ($(CONFIG_MTK_GPT_SCHEME_SUPPORT), y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/gpt ++else ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/pmt ++endif ++ ccflags-y += -DCFG_TC1_FEATURE=1 ++ ccflags-y += -DCFG_SUPPORT_CFG_FILE=1 ++else ++ ccflags-y += -DCFG_TC1_FEATURE=0 ++endif ++ ++MTK_SRAM_SIZE_OPTION=0 ++ifeq ($(CONFIG_ARCH_MT6755), y) ++ MTK_SRAM_SIZE_OPTION=2 ++endif ++ifeq ($(CONFIG_ARCH_MT6735), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6735M), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6753), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6580), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT8163), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ccflags-y += -DCFG_SRAM_SIZE_OPTION=$(MTK_SRAM_SIZE_OPTION) ++ ++ifeq ($(strip $(TRUSTONIC_TEE_SUPPORT)),yes) ++ifeq ($(strip $(MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT)),yes) ++ ccflags-y += -DTRUSTONIC_TEE_SUPPORT ++ ccflags-y += -DMTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT ++endif ++endif ++ ++ccflags-y += -D_HIF_SDIO=1 ++ ++ccflags-y += -DDBG=0 ++ccflags-y += -I$(src)/os -I$(src)/os/linux/include -I$(src)/os/linux/hif/ahb/include ++ccflags-y += -I$(src)/include -I$(src)/include/nic -I$(src)/include/mgmt ++ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include ++ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/ ++ ++MODULE_NAME := wlan_gen2 ++obj-$(CONFIG_MTK_COMBO_WIFI) += $(MODULE_NAME).o ++#obj-m += $(MODULE_NAME).o if CONFIG_MTK_COMBO_WIFI=m ==> obj-m means ko module, not build in obj-y ++ ++# --------------------------------------------------- ++# Directory List ++# --------------------------------------------------- ++COMMON_DIR := common/ ++OS_DIR := os/linux/ ++HIF_DIR := os/linux/hif/ahb/ ++NIC_DIR := nic/ ++MGMT_DIR := mgmt/ ++DMA_DIR := ../../../../platform/$(call lc,$(MTK_PLATFORM))/kernel/drivers/wifi/ ++PLAT_DIR := os/linux/plat/$(MTK_PLATFORM)/ ++HIF_AHB_PDMA := $(HIF_DIR)$(MTK_PLATFORM)/ ++#$(call lc,$(MTK_PLATFORM)) ++ ++ ++# --------------------------------------------------- ++# Objects List ++# --------------------------------------------------- ++ ++COMMON_OBJS := $(COMMON_DIR)dump.o \ ++ $(COMMON_DIR)wlan_lib.o \ ++ $(COMMON_DIR)wlan_oid.o \ ++ $(COMMON_DIR)wlan_bow.o \ ++ $(COMMON_DIR)debug.o ++ ++NIC_OBJS := $(NIC_DIR)nic.o \ ++ $(NIC_DIR)nic_tx.o \ ++ $(NIC_DIR)nic_rx.o \ ++ $(NIC_DIR)nic_pwr_mgt.o \ ++ $(NIC_DIR)cmd_buf.o \ ++ $(NIC_DIR)que_mgt.o \ ++ $(NIC_DIR)nic_cmd_event.o ++ ++OS_OBJS := $(OS_DIR)gl_init.o \ ++ $(OS_DIR)gl_kal.o \ ++ $(OS_DIR)gl_bow.o \ ++ $(OS_DIR)gl_wext.o \ ++ $(OS_DIR)gl_wext_priv.o \ ++ $(OS_DIR)gl_rst.o \ ++ $(OS_DIR)gl_cfg80211.o \ ++ $(OS_DIR)gl_vendor.o \ ++ $(OS_DIR)platform.o \ ++ $(OS_DIR)gl_proc.o ++ ++MGMT_OBJS := $(MGMT_DIR)ais_fsm.o \ ++ $(MGMT_DIR)aaa_fsm.o \ ++ $(MGMT_DIR)assoc.o \ ++ $(MGMT_DIR)auth.o \ ++ $(MGMT_DIR)bss.o \ ++ $(MGMT_DIR)cnm.o \ ++ $(MGMT_DIR)cnm_timer.o \ ++ $(MGMT_DIR)cnm_mem.o \ ++ $(MGMT_DIR)hem_mbox.o \ ++ $(MGMT_DIR)mib.o \ ++ $(MGMT_DIR)privacy.o \ ++ $(MGMT_DIR)rate.o \ ++ $(MGMT_DIR)rlm.o \ ++ $(MGMT_DIR)rlm_domain.o \ ++ $(MGMT_DIR)rlm_obss.o \ ++ $(MGMT_DIR)rlm_protection.o \ ++ $(MGMT_DIR)rsn.o \ ++ $(MGMT_DIR)saa_fsm.o \ ++ $(MGMT_DIR)scan.o \ ++ $(MGMT_DIR)scan_fsm.o \ ++ $(MGMT_DIR)sec_fsm.o \ ++ $(MGMT_DIR)swcr.o \ ++ $(MGMT_DIR)swcr.o \ ++ $(MGMT_DIR)roaming_fsm.o \ ++ $(MGMT_DIR)hs20.o ++ ++# --------------------------------------------------- ++# TDLS Objects List ++# --------------------------------------------------- ++MGMT_OBJS += $(MGMT_DIR)tdls.o \ ++ $(MGMT_DIR)tdls_com.o ++ ++# --------------------------------------------------- ++# STATS Objects List ++# --------------------------------------------------- ++MGMT_OBJS += $(MGMT_DIR)stats.o ++ ++# --------------------------------------------------- ++# P2P Objects List ++# --------------------------------------------------- ++ ++COMMON_OBJS += $(COMMON_DIR)wlan_p2p.o ++ ++NIC_OBJS += $(NIC_DIR)p2p_nic.o ++ ++OS_OBJS += $(OS_DIR)gl_p2p.o \ ++ $(OS_DIR)gl_p2p_cfg80211.o \ ++ $(OS_DIR)gl_p2p_init.o \ ++ $(OS_DIR)gl_p2p_kal.o ++ ++MGMT_OBJS += $(MGMT_DIR)p2p_assoc.o \ ++ $(MGMT_DIR)p2p_bss.o \ ++ $(MGMT_DIR)p2p_fsm.o \ ++ $(MGMT_DIR)p2p_func.o \ ++ $(MGMT_DIR)p2p_rlm.o \ ++ $(MGMT_DIR)p2p_rlm_obss.o \ ++ $(MGMT_DIR)p2p_scan.o \ ++ $(MGMT_DIR)p2p_ie.o \ ++ $(MGMT_DIR)p2p_state.o ++ ++ ++ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) ++MGMT_OBJS += $(MGMT_DIR)wapi.o ++endif ++ ++ifeq ($(WLAN_PROC), y) ++OS_OBJS += gl_proc.o ++endif ++ ++$(warning $(CONFIG_MACH_MT7623)) ++ ++ifeq ($(CONFIG_MACH_MT7623), y) ++HIF_AHB_PDMA = $(HIF_DIR)mt8127/ ++endif ++HIF_OBJS := $(HIF_DIR)arm.o \ ++ $(HIF_DIR)ahb.o \ ++ $(HIF_AHB_PDMA)ahb_pdma.o ++ifeq ($(CONFIG_ARCH_MT6755), y) ++PLAT_OBJS := $(PLAT_DIR)plat_priv.o ++$(MODULE_NAME)-objs += $(PLAT_OBJS) ++endif ++$(MODULE_NAME)-objs += $(COMMON_OBJS) ++$(MODULE_NAME)-objs += $(NIC_OBJS) ++$(MODULE_NAME)-objs += $(OS_OBJS) ++$(MODULE_NAME)-objs += $(HIF_OBJS) ++$(MODULE_NAME)-objs += $(MGMT_OBJS) ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c +new file mode 100644 +index 000000000000..e31e0b86d231 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c +@@ -0,0 +1,165 @@ ++#include "precomp.h" ++#include "gl_kal.h" ++ ++struct COMMAND { ++ UINT_8 ucCID; ++ BOOLEAN fgSetQuery; ++ BOOLEAN fgNeedResp; ++ UINT_8 ucCmdSeqNum; ++}; ++ ++struct SECURITY_FRAME { ++ UINT_16 u2EthType; ++ UINT_16 u2Reserved; ++}; ++ ++struct MGMT_FRAME { ++ UINT_16 u2FrameCtl; ++ UINT_16 u2DurationID; ++}; ++ ++struct TC_RES_RELEASE_ENTRY { ++ UINT_64 u8RelaseTime; ++ UINT_32 u4RelCID; ++ UINT_8 ucTc4RelCnt; ++ UINT_8 ucAvailableTc4; ++}; ++ ++struct CMD_TRACE_ENTRY { ++ UINT_64 u8TxTime; ++ COMMAND_TYPE eCmdType; ++ union { ++ struct COMMAND rCmd; ++ struct SECURITY_FRAME rSecFrame; ++ struct MGMT_FRAME rMgmtFrame; ++ } u; ++}; ++ ++#define TC_RELEASE_TRACE_BUF_MAX_NUM 100 ++#define TXED_CMD_TRACE_BUF_MAX_NUM 100 ++ ++static struct TC_RES_RELEASE_ENTRY *gprTcReleaseTraceBuffer; ++static struct CMD_TRACE_ENTRY *gprCmdTraceEntry; ++VOID wlanDebugInit(VOID) ++{ ++ /* debug for command/tc4 resource begin */ ++ gprTcReleaseTraceBuffer = ++ kalMemAlloc(TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY), PHY_MEM_TYPE); ++ kalMemZero(gprTcReleaseTraceBuffer, TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); ++ gprCmdTraceEntry = kalMemAlloc(TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY), PHY_MEM_TYPE); ++ kalMemZero(gprCmdTraceEntry, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); ++ /* debug for command/tc4 resource end */ ++} ++ ++VOID wlanDebugUninit(VOID) ++{ ++ /* debug for command/tc4 resource begin */ ++ kalMemFree(gprTcReleaseTraceBuffer, PHY_MEM_TYPE, ++ TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); ++ kalMemFree(gprCmdTraceEntry, PHY_MEM_TYPE, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); ++ /* debug for command/tc4 resource end */ ++} ++ ++VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd) ++{ ++ static UINT_16 u2CurEntry; ++ struct CMD_TRACE_ENTRY *prCurCmd = &gprCmdTraceEntry[u2CurEntry]; ++ ++ prCurCmd->u8TxTime = sched_clock(); ++ prCurCmd->eCmdType = prCmd->eCmdType; ++ if (prCmd->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ P_WLAN_MAC_MGMT_HEADER_T prMgmt = (P_WLAN_MAC_MGMT_HEADER_T)((P_MSDU_INFO_T)prCmd->prPacket)->prPacket; ++ ++ prCurCmd->u.rMgmtFrame.u2FrameCtl = prMgmt->u2FrameCtrl; ++ prCurCmd->u.rMgmtFrame.u2DurationID = prMgmt->u2Duration; ++ } else if (prCmd->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ PUINT_8 pucPkt = (PUINT_8)((struct sk_buff *)prCmd->prPacket)->data; ++ ++ prCurCmd->u.rSecFrame.u2EthType = ++ (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ } else { ++ prCurCmd->u.rCmd.ucCID = prCmd->ucCID; ++ prCurCmd->u.rCmd.ucCmdSeqNum = prCmd->ucCmdSeqNum; ++ prCurCmd->u.rCmd.fgNeedResp = prCmd->fgNeedResp; ++ prCurCmd->u.rCmd.fgSetQuery = prCmd->fgSetQuery; ++ } ++ u2CurEntry++; ++ if (u2CurEntry == TC_RELEASE_TRACE_BUF_MAX_NUM) ++ u2CurEntry = 0; ++} ++ ++VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable) ++{ ++ static UINT_16 u2CurEntry; ++ struct TC_RES_RELEASE_ENTRY *prCurBuf = &gprTcReleaseTraceBuffer[u2CurEntry]; ++ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &prCurBuf->u4RelCID); ++ prCurBuf->u8RelaseTime = sched_clock(); ++ prCurBuf->ucTc4RelCnt = aucTxRlsCnt[TC4_INDEX]; ++ prCurBuf->ucAvailableTc4 = ucAvailable; ++ u2CurEntry++; ++ if (u2CurEntry == TXED_CMD_TRACE_BUF_MAX_NUM) ++ u2CurEntry = 0; ++} ++ ++VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen) ++{ ++ UINT_16 i = 0; ++ struct CMD_TRACE_ENTRY *prCmd = gprCmdTraceEntry; ++ struct TC_RES_RELEASE_ENTRY *prTcRel = gprTcReleaseTraceBuffer; ++ ++ if (pucBuf) { ++ int bufLen = 0; ++ ++ for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/2; i++) { ++ bufLen = snprintf(pucBuf, maxLen, ++ "%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", ++ i*2, prCmd[i*2].u8TxTime, prCmd[i*2].eCmdType, *(PUINT_32)(&prCmd[i*2].u.rCmd.ucCID), ++ i*2+1, prCmd[i*2+1].u8TxTime, prCmd[i*2+1].eCmdType, ++ *(PUINT_32)(&prCmd[i*2+1].u.rCmd.ucCID)); ++ if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) ++ break; ++ pucBuf += bufLen; ++ maxLen -= bufLen; ++ } ++ for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/2; i++) { ++ bufLen = snprintf(pucBuf, maxLen, ++ "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d CID %08x\n", ++ i*2, prTcRel[i*2].u8RelaseTime, prTcRel[i*2].ucTc4RelCnt, prTcRel[i*2].ucAvailableTc4, ++ prTcRel[i*2].u4RelCID, ++ i*2+1, prTcRel[i*2+1].u8RelaseTime, prTcRel[i*2+1].ucTc4RelCnt, ++ prTcRel[i*2+1].ucAvailableTc4, prTcRel[i*2+1].u4RelCID); ++ if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) ++ break; ++ pucBuf += bufLen; ++ maxLen -= bufLen; ++ } ++ return; ++ } ++ for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/4; i++) { ++ LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x; ", ++ i*4, prCmd[i*4].u8TxTime, prCmd[i*4].eCmdType, ++ *(PUINT_32)(&prCmd[i*4].u.rCmd.ucCID), ++ i*4+1, prCmd[i*4+1].u8TxTime, prCmd[i*4+1].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+1].u.rCmd.ucCID)); ++ LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", ++ i*4+2, prCmd[i*4+2].u8TxTime, prCmd[i*4+2].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+2].u.rCmd.ucCID), ++ i*4+3, prCmd[i*4+3].u8TxTime, prCmd[i*4+3].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+3].u.rCmd.ucCID)); ++ } ++ for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/4; i++) { ++ LOG_FUNC( ++ "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x;", ++ i*4, prTcRel[i*4].u8RelaseTime, prTcRel[i*4].ucTc4RelCnt, ++ prTcRel[i*4].ucAvailableTc4, prTcRel[i*4].u4RelCID, ++ i*4+1, prTcRel[i*4+1].u8RelaseTime, prTcRel[i*4+1].ucTc4RelCnt, ++ prTcRel[i*4+1].ucAvailableTc4, prTcRel[i*4+1].u4RelCID); ++ LOG_FUNC( ++ " %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x\n", ++ i*4+2, prTcRel[i*4+2].u8RelaseTime, prTcRel[i*4+2].ucTc4RelCnt, ++ prTcRel[i*4+2].ucAvailableTc4, prTcRel[i*4+2].u4RelCID, ++ i*4+3, prTcRel[i*4+3].u8RelaseTime, prTcRel[i*4+3].ucTc4RelCnt, ++ prTcRel[i*4+3].ucAvailableTc4, prTcRel[i*4+3].u4RelCID); ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c +new file mode 100644 +index 000000000000..486ba239f16a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c +@@ -0,0 +1,345 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/dump.c#1 ++*/ ++ ++/*! \file "dump.c" ++ \brief Provide memory dump function for debugging. ++ ++ Provide memory dump function for debugging. ++*/ ++ ++/* ++** Log: dump.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 19:58:51 GMT mtk01426 ++** Init develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump a segment of memory in bytes. ++* ++* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. ++* \param[in] u4Length Length of the memory to be dumped. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length) ++{ ++ ASSERT(pucStartAddr); ++ ++ LOG_FUNC("DUMP8 ADDRESS: %p, Length: %u\n", pucStartAddr, u4Length); ++ ++ while (u4Length > 0) { ++ if (u4Length >= 16) { ++ LOG_FUNC( ++ "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], pucStartAddr[8], ++ pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], pucStartAddr[12], pucStartAddr[13], ++ pucStartAddr[14], pucStartAddr[15]); ++ u4Length -= 16; ++ pucStartAddr += 16; ++ } else { ++ switch (u4Length) { ++ case 1: ++ LOG_FUNC("(%p) %02x\n", pucStartAddr, pucStartAddr[0]); ++ break; ++ case 2: ++ LOG_FUNC("(%p) %02x %02x\n", pucStartAddr, pucStartAddr[0], pucStartAddr[1]); ++ break; ++ case 3: ++ LOG_FUNC("(%p) %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2]); ++ break; ++ case 4: ++ LOG_FUNC("(%p) %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3]); ++ break; ++ case 5: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4]); ++ break; ++ case 6: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5]); ++ break; ++ case 7: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6]); ++ break; ++ case 8: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7]); ++ break; ++ case 9: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8]); ++ break; ++ case 10: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9]); ++ break; ++ case 11: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10]); ++ break; ++ case 12: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11]); ++ break; ++ case 13: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12]); ++ break; ++ case 14: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12], pucStartAddr[13]); ++ break; ++ case 15: ++ LOG_FUNC( ++ "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12], pucStartAddr[13], pucStartAddr[14]); ++ break; ++ /* ++ default: ++ break; ++ */ ++ } ++ u4Length = 0; ++ } ++ } ++ ++ LOG_FUNC("\n"); ++ ++} /* end of dumpMemory8() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump a segment of memory in double words. ++* ++* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. ++* \param[in] u4Length Length of the memory to be dumped. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length) ++{ ++ PUINT_8 pucAddr; ++ ++ ASSERT(pu4StartAddr); ++ ++ LOG_FUNC("DUMP32 ADDRESS: %p, Length: %u\n", pu4StartAddr, u4Length); ++ ++ if (IS_NOT_ALIGN_4((ULONG) pu4StartAddr)) { ++ UINT_32 u4ProtrudeLen = sizeof(UINT_32) - ((ULONG) pu4StartAddr % 4); ++ ++ u4ProtrudeLen = ((u4Length < u4ProtrudeLen) ? u4Length : u4ProtrudeLen); ++ LOG_FUNC("pu4StartAddr is not at DW boundary.\n"); ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ ++ switch (u4ProtrudeLen) { ++ case 1: ++ LOG_FUNC("(%p) %02x------\n", pu4StartAddr, pucAddr[0]); ++ break; ++ case 2: ++ LOG_FUNC("(%p) %02x%02x----\n", pu4StartAddr, pucAddr[1], pucAddr[0]); ++ break; ++ case 3: ++ LOG_FUNC("(%p) %02x%02x%02x--\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ default: ++ break; ++ } ++ ++ u4Length -= u4ProtrudeLen; ++ pu4StartAddr = (PUINT_32) ((ULONG) pu4StartAddr + u4ProtrudeLen); ++ } ++ ++ while (u4Length > 0) { ++ if (u4Length >= 16) { ++ LOG_FUNC("(%p) %08x %08x %08x %08x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pu4StartAddr[3]); ++ pu4StartAddr += 4; ++ u4Length -= 16; ++ } else { ++ switch (u4Length) { ++ case 1: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) ------%02x\n", pu4StartAddr, pucAddr[0]); ++ break; ++ case 2: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) ----%02x%02x\n", pu4StartAddr, pucAddr[1], pucAddr[0]); ++ break; ++ case 3: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) --%02x%02x%02x\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 4: ++ LOG_FUNC("(%p) %08x\n", pu4StartAddr, pu4StartAddr[0]); ++ break; ++ case 5: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x ------%02x\n", pu4StartAddr, pu4StartAddr[0], pucAddr[0]); ++ break; ++ case 6: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x ----%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pucAddr[1], pucAddr[0]); ++ break; ++ case 7: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x --%02x%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 8: ++ LOG_FUNC("(%p) %08x %08x\n", pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1]); ++ break; ++ case 9: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x ------%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[0]); ++ break; ++ case 10: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x ----%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[1], pucAddr[0]); ++ break; ++ case 11: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x --%02x%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 12: ++ LOG_FUNC("(%p) %08x %08x %08x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2]); ++ break; ++ case 13: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x ------%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[0]); ++ break; ++ case 14: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x ----%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 15: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x --%02x%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], ++ pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ /* ++ default: ++ break; ++ */ ++ } ++ u4Length = 0; ++ } ++ } ++ ++} /* end of dumpMemory32() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c +new file mode 100644 +index 000000000000..21bd849827e1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c +@@ -0,0 +1,3442 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_bow.c#1 ++*/ ++ ++/*! \file wlan_bow.c ++ \brief This file contains the 802.11 PAL commands processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_bow.c ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 01 09 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00110632] [Rose][LCA42][Cross Feature][Bluetooth]The "KE" pops up after the device reboots automatically.(once) ++ * ++ * Fix bow link disconnected event dereference. ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 07 06 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Improve BoW connection establishment speed. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 21 2011 terry.wu ++ * NULL ++ * Fix BoW KE. ++ * ++ * 06 20 2011 terry.wu ++ * NULL ++ * Add BoW Rate Limitation. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 07 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * aware more compile options. ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 23 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add some BoW error handling. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * . ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Only reply probe response to its peer or mached SSID for BoW AP. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW SAA retry and disable disconnect event when AAA fail . ++ * ++ * 05 21 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Protect BoW connection establishment. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting ++ * Send deauth while disconnecting BoW link. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix wrong StaRec state of BoW . ++ * ++ * 05 06 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix BoW Multiple Physical Link connect/disconnect issue. ++ * ++ * 05 03 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix prAssocRspSwRfb casting. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 12 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add WMM IE for BOW initiator data. ++ * ++ * 04 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 28 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Simplify link disconnected routine, remove link disconnected other routine. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add new feature - multiple physical link support. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000486] [MT6620 Wi-Fi][BOW] Fixed the bow send frame but not encrypted issue ++ * fixed the BOW packet sending without encrypted issue. ++ * ++ * 02 21 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BOW link disconnection bug. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting. ++ * ++ * 02 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW channel granted function. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW Activity Report structure and bug fix. ++ * ++ * 01 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW to support multiple physical link. ++ * ++ * 12 08 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support concurrent networks. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 11 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BoW timer assert issue. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix for event returnning Band. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix wrong BoW event size. ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 chinghwa.yu ++ * NULL ++ * Fix bowResponderScanDone error when prBssDesc is NULL. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 09 14 2010 cp.wu ++ * NULL ++ * indicate correct AIS network information for PAL. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Initialize nicActivateNetwork(prAdapter as soon as bow is starting.. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * 2) command sequence number is now increased atomically ++ * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++static UINT_32 g_u4LinkCount; ++static UINT_32 g_u4Beaconing; ++static BOW_TABLE_T arBowTable[CFG_BOW_PHYSICAL_LINK_NUM]; ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++const BOW_CMD_T arBowCmdTable[] = { ++ {BOW_CMD_ID_GET_MAC_STATUS, bowCmdGetMacStatus}, ++ {BOW_CMD_ID_SETUP_CONNECTION, bowCmdSetupConnection}, ++ {BOW_CMD_ID_DESTROY_CONNECTION, bowCmdDestroyConnection}, ++ {BOW_CMD_ID_SET_PTK, bowCmdSetPTK}, ++ {BOW_CMD_ID_READ_RSSI, bowCmdReadRSSI}, ++ {BOW_CMD_ID_READ_LINK_QUALITY, bowCmdReadLinkQuality}, ++ {BOW_CMD_ID_SHORT_RANGE_MODE, bowCmdShortRangeMode}, ++ {BOW_CMD_ID_GET_CHANNEL_LIST, bowCmdGetChannelList}, ++}; ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCID, ++ IN BOOLEAN fgSetQuery, ++ IN BOOLEAN fgNeedResp, ++ IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ IN UINT_32 u4SetQueryInfoLen, IN PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_BOW_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ prCmdInfo->u4PrivateData = (UINT_32) ucSeqNumber; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dispatch command coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ WLAN_STATUS retval = WLAN_STATUS_FAILURE; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < sizeof(arBowCmdTable) / sizeof(BOW_CMD_T); i++) { ++ if ((arBowCmdTable[i].uCmdID == prCmd->rHeader.ucCommandId) && arBowCmdTable[i].pfCmdHandle) { ++ retval = arBowCmdTable[i].pfCmdHandle(prAdapter, prCmd); ++ break; ++ } ++ } ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_GET_MAC_STATUS ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_MAC_STATUS prMacStatus; ++ UINT_8 idx = 0; ++ UINT_8 ucPrimaryChannel; ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eBssSCO; ++ UINT_8 ucNumOfChannel = 0; /* MAX_BOW_NUMBER_OF_CHANNEL; */ ++ ++ RF_CHANNEL_INFO_T aucChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; ++ ++ ASSERT(prAdapter); ++ ++ /* 3 <1> If LinkCount != 0 -> OK (optional) */ ++ ++ eBand = BAND_2G4; ++ eBssSCO = CHNL_EXT_SCN; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return WLAN_STATUS_FAILURE; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_MAC_STATUS; ++ prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_MAC_STATUS); ++ ++ /* fill event body */ ++ prMacStatus = (P_BOW_MAC_STATUS) (prEvent->aucPayload); ++ kalMemZero(prMacStatus, sizeof(BOW_MAC_STATUS)); ++ ++ /* 3 <2> Call CNM to decide if BOW available. */ ++ if (cnmBowIsPermitted(prAdapter)) ++ prMacStatus->ucAvailability = TRUE; ++ else ++ prMacStatus->ucAvailability = FALSE; ++ ++ memcpy(prMacStatus->aucMacAddr, prAdapter->rWifiVar.aucDeviceAddress, PARAM_MAC_ADDR_LEN); ++ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucPrimaryChannel, &eBssSCO)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "bowCmdGetMacStatus, Get preferred channel.\n"); ++#endif ++ ++ prMacStatus->ucNumOfChannel = 1; ++ prMacStatus->arChannelList[0].ucChannelBand = eBand; ++ prMacStatus->arChannelList[0].ucChannelNum = ucPrimaryChannel; ++ } else { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, ++ "bowCmdGetMacStatus, Get channel list. Current number of channel, %d.\n", ucNumOfChannel); ++#endif ++ ++ rlmDomainGetChnlList(prAdapter, BAND_2G4, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_2G4, ++ &ucNumOfChannel, aucChannelList); ++ ++ if (ucNumOfChannel > 0) { ++ for (idx = 0; idx < ucNumOfChannel; idx++) { ++ prMacStatus->arChannelList[idx].ucChannelBand = aucChannelList[idx].eBand; ++ prMacStatus->arChannelList[idx].ucChannelNum = aucChannelList[idx].ucChannelNum; ++ } ++ ++ prMacStatus->ucNumOfChannel = ucNumOfChannel; ++ } ++ ++ rlmDomainGetChnlList(prAdapter, BAND_5G, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_5G, ++ &ucNumOfChannel, aucChannelList); ++ ++ if (ucNumOfChannel > 0) { ++ for (idx = 0; idx < ucNumOfChannel; idx++) { ++ prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelBand = ++ aucChannelList[idx].eBand; ++ prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelNum = ++ aucChannelList[idx].ucChannelNum; ++ } ++ ++ prMacStatus->ucNumOfChannel = prMacStatus->ucNumOfChannel + ucNumOfChannel; ++ ++ } ++ } ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, ++ "ucNumOfChannel,eBand,aucChannelList,%x,%x,%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ ucNumOfChannel, aucChannelList[0].eBand, aucChannelList[0].ucChannelNum, aucChannelList[1].ucChannelNum, ++ aucChannelList[2].ucChannelNum, aucChannelList[3].ucChannelNum, aucChannelList[4].ucChannelNum, ++ aucChannelList[5].ucChannelNum, aucChannelList[6].ucChannelNum, aucChannelList[7].ucChannelNum, ++ aucChannelList[8].ucChannelNum, aucChannelList[9].ucChannelNum, aucChannelList[10].ucChannelNum, ++ aucChannelList[11].ucChannelNum, aucChannelList[12].ucChannelNum, aucChannelList[13].ucChannelNum, ++ aucChannelList[14].ucChannelNum, aucChannelList[15].ucChannelNum, aucChannelList[16].ucChannelNum, ++ aucChannelList[17].ucChannelNum)); ++ ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->ucNumOfChannel, eBand, %x, %x.\n", ++ prMacStatus->ucNumOfChannel, prMacStatus->arChannelList[0].ucChannelBand); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ prMacStatus->arChannelList[0].ucChannelNum, prMacStatus->arChannelList[1].ucChannelNum, ++ prMacStatus->arChannelList[2].ucChannelNum, prMacStatus->arChannelList[3].ucChannelNum, ++ prMacStatus->arChannelList[4].ucChannelNum, prMacStatus->arChannelList[5].ucChannelNum, ++ prMacStatus->arChannelList[6].ucChannelNum, prMacStatus->arChannelList[7].ucChannelNum, ++ prMacStatus->arChannelList[8].ucChannelNum, prMacStatus->arChannelList[9].ucChannelNum, ++ prMacStatus->arChannelList[10].ucChannelNum, prMacStatus->arChannelList[11].ucChannelNum, ++ prMacStatus->arChannelList[12].ucChannelNum, prMacStatus->arChannelList[13].ucChannelNum, ++ prMacStatus->arChannelList[14].ucChannelNum, prMacStatus->arChannelList[15].ucChannelNum, ++ prMacStatus->arChannelList[16].ucChannelNum, prMacStatus->arChannelList[17].ucChannelNum)); ++ ++ DBGLOG(BOW, TRACE, "prMacStatus->ucNumOfChannel, %x.\n", prMacStatus->ucNumOfChannel); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList[0].ucChannelBand, %x.\n", prMacStatus->arChannelList[0].ucChannelBand); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList[0].ucChannelNum, %x.\n", prMacStatus->arChannelList[0].ucChannelNum); ++ DBGLOG(BOW, TRACE, "prMacStatus->ucAvailability, %x.\n", prMacStatus->ucAvailability); ++ DBGLOG(BOW, TRACE, "prMacStatus->aucMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prMacStatus->aucMacAddr[0], ++ prMacStatus->aucMacAddr[1], ++ prMacStatus->aucMacAddr[2], ++ prMacStatus->aucMacAddr[3], prMacStatus->aucMacAddr[4], prMacStatus->aucMacAddr[5])); ++#endif ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS))); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SETUP_CONNECTION ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SETUP_CONNECTION prBowSetupConnection; ++ CMD_BT_OVER_WIFI rCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ BOW_TABLE_T rBowTable; ++ ++ UINT_8 ucBowTableIdx = 0; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowSetupConnection = (P_BOW_SETUP_CONNECTION) &(prCmd->aucPayload[0]); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SETUP_CONNECTION)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* 3 <1> If ucLinkCount >= 4 -> Fail. */ ++ if (g_u4LinkCount >= CFG_BOW_PHYSICAL_LINK_NUM) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* 3 <2> Call CNM, check if BOW is available. */ ++ if (!cnmBowIsPermitted(prAdapter)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* 3 <3> Lookup BOW Table, if Peer MAC address exist and valid -> Fail. */ ++ if (bowCheckBowTableIfVaild(prAdapter, prBowSetupConnection->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (EQUAL_MAC_ADDR(prBowSetupConnection->aucPeerAddress, prAdapter->rWifiVar.aucDeviceAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* fill CMD_BT_OVER_WIFI */ ++ rCmdBtOverWifi.ucAction = BOW_SETUP_CMD; ++ rCmdBtOverWifi.ucChannelNum = prBowSetupConnection->ucChannelNum; ++ COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowSetupConnection->aucPeerAddress); ++ rCmdBtOverWifi.u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; ++ rCmdBtOverWifi.ucTimeoutDiscovery = prBowSetupConnection->ucTimeoutDiscovery; ++ rCmdBtOverWifi.ucTimeoutInactivity = prBowSetupConnection->ucTimeoutInactivity; ++ rCmdBtOverWifi.ucRole = prBowSetupConnection->ucRole; ++ rCmdBtOverWifi.PAL_Capabilities = prBowSetupConnection->ucPAL_Capabilities; ++ rCmdBtOverWifi.cMaxTxPower = prBowSetupConnection->cMaxTxPower; ++ ++ if (prBowSetupConnection->ucChannelNum > 14) ++ rCmdBtOverWifi.ucChannelBand = BAND_5G; ++ else ++ rCmdBtOverWifi.ucChannelBand = BAND_2G4; ++ ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowSetupConnection->aucPeerAddress); ++ ++#if CFG_BOW_PHYSICAL_LINK_NUM > 1 ++ /*Channel check for supporting multiple physical link */ ++ if (g_u4LinkCount > 0) { ++ if (prBowSetupConnection->ucChannelNum != prBowFsmInfo->ucPrimaryChannel) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ } ++#endif ++ ++ prBowFsmInfo->ucPrimaryChannel = prBowSetupConnection->ucChannelNum; ++ prBowFsmInfo->eBand = rCmdBtOverWifi.ucChannelBand; ++ prBowFsmInfo->u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; ++ prBowFsmInfo->ucRole = prBowSetupConnection->ucRole; ++ ++ if (prBowSetupConnection->ucPAL_Capabilities > 0) ++ prBowFsmInfo->fgSupportQoS = TRUE; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdSetupConnection.\n"); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Channel Number - 0x%x.\n", rCmdBtOverWifi.ucChannelNum); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Peer address - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], ++ rCmdBtOverWifi.rPeerAddr[1], ++ rCmdBtOverWifi.rPeerAddr[2], ++ rCmdBtOverWifi.rPeerAddr[3], rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Beacon interval - 0x%x.\n", rCmdBtOverWifi.u2BeaconInterval); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout activity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutDiscovery); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout inactivity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutInactivity); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Role - 0x%x.\n", rCmdBtOverWifi.ucRole); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi PAL capability - 0x%x.\n", rCmdBtOverWifi.PAL_Capabilities); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Max Tx power - 0x%x.\n", rCmdBtOverWifi.cMaxTxPower); ++#endif ++ ++ /* 3 <4> Get a free BOW entry, mark as Valid, fill in Peer MAC address, LinkCount += 1, state == Starting. */ ++ if (!bowGetBowTableFreeEntry(prAdapter, &ucBowTableIdx)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ prBowFsmInfo->prTargetBssDesc = NULL; ++ ++ kalMemZero(&rBowTable, sizeof(BOW_TABLE_T)); ++ ++ COPY_MAC_ADDR(rBowTable.aucPeerAddress, prBowSetupConnection->aucPeerAddress); ++ /* owTable.eState = BOW_DEVICE_STATE_ACQUIRING_CHANNEL; */ ++ rBowTable.fgIsValid = TRUE; ++ rBowTable.ucAcquireID = prBowFsmInfo->ucSeqNumOfChReq; ++ /* rBowTable.ucRole = prBowSetupConnection->ucRole; */ ++ /* rBowTable.ucChannelNum = prBowSetupConnection->ucChannelNum; */ ++ bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); ++ ++ kalSetBowRole(prAdapter->prGlueInfo, rCmdBtOverWifi.ucRole, prBowSetupConnection->aucPeerAddress); ++ ++ GLUE_INC_REF_CNT(g_u4LinkCount); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ if (g_u4LinkCount == 1) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting, cnmTimerInitTimer.\n"); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo->u2BeaconInterval, %d.\n", prBowFsmInfo->u2BeaconInterval); ++#endif ++ cnmTimerInitTimer(prAdapter, ++ &prBowFsmInfo->rStartingBeaconTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) bowSendBeacon, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) bowChGrantedTimeout, (ULONG) NULL); ++ ++ /* Reset Global Variable */ ++ g_u4Beaconing = 0; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdSetupConnection, g_u4LinkCount, %x.\n", g_u4LinkCount); ++ DBGLOG(BOW, EVENT, "kalInitBowDevice, bow0\n"); ++#endif ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalInitBowDevice(prAdapter->prGlueInfo, BOWDEVNAME); ++#endif ++ ++ /*Active BoW Network */ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ } ++ ++ if (rCmdBtOverWifi.ucRole == BOW_INITIATOR) { ++ bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL); ++ bowRequestCh(prAdapter); ++ } else { ++ bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); ++ bowResponderScan(prAdapter); ++ } ++ ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_DESTROY_CONNECTION ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_DESTROY_CONNECTION prBowDestroyConnection; ++ CMD_BT_OVER_WIFI rCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++#if CFG_BOW_TEST ++ UINT_8 ucIdx; ++#endif ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* 3 <1> If LinkCount == 0 ->Fail (Optional) */ ++ if (g_u4LinkCount == 0) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_DESTROY_CONNECTION)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* 3 <2> Lookup BOW table, check if is not exist (Valid and Peer MAC address) -> Fail */ ++ prBowDestroyConnection = (P_BOW_DESTROY_CONNECTION) &(prCmd->aucPayload[0]); ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowDestroyConnection->aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdDestroyConnection, bowCheckIfVaild, not accepted.\n"); ++#endif ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowCmdDestroyConnection, destroy Peer address - %x:%x:%x:%x:%x:%x.\n", ++ prBowDestroyConnection->aucPeerAddress[0], prBowDestroyConnection->aucPeerAddress[1], ++ prBowDestroyConnection->aucPeerAddress[2], prBowDestroyConnection->aucPeerAddress[3], ++ prBowDestroyConnection->aucPeerAddress[4], prBowDestroyConnection->aucPeerAddress[5])); ++#endif ++ ++ /* fill CMD_BT_OVER_WIFI */ ++ rCmdBtOverWifi.ucAction = 2; ++ COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowDestroyConnection->aucPeerAddress); ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowDestroyConnection->aucPeerAddress); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowCmdDestroyConnection, rCmdBtOverWifi.rPeerAddr - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], ++ rCmdBtOverWifi.rPeerAddr[1], rCmdBtOverWifi.rPeerAddr[2], rCmdBtOverWifi.rPeerAddr[3], ++ rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); ++#endif ++ ++#if CFG_BOW_TEST ++ for (ucIdx = 0; ucIdx < 11; ucIdx++) { ++ DBGLOG(BOW, EVENT, ++ "BoW receiving PAL packet delta time vs packet number -- %d ms vs %x.\n", ucIdx, ++ g_arBowRevPalPacketTime[ucIdx]); ++ } ++#endif ++ ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, ++ sizeof(CMD_BT_OVER_WIFI), ++ (PUINT_8)&rCmdBtOverWifi, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SET_PTK ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SET_PTK prBowSetPTK; ++ CMD_802_11_KEY rCmdKey; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SET_PTK)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowSetPTK = (P_BOW_SET_PTK) &(prCmd->aucPayload[0]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowSetPTK->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowSetPTK->aucPeerAddress[0], ++ prBowSetPTK->aucPeerAddress[1], ++ prBowSetPTK->aucPeerAddress[2], ++ prBowSetPTK->aucPeerAddress[3], ++ prBowSetPTK->aucPeerAddress[4], prBowSetPTK->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "rCmdKey.ucIsAuthenticator, %x.\n", kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress)); ++#endif ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowSetPTK->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (bowGetBowTableState(prAdapter, prBowSetPTK->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* fill CMD_802_11_KEY */ ++ rCmdKey.ucAddRemove = 1; /* add */ ++ rCmdKey.ucTxKey = 1; ++ rCmdKey.ucKeyType = 1; ++ rCmdKey.ucIsAuthenticator = kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress); ++ COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prBowSetPTK->aucPeerAddress); ++ rCmdKey.ucNetType = NETWORK_TYPE_BOW_INDEX; /* BT Over Wi-Fi */ ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ ++ rCmdKey.ucKeyId = 0; ++ rCmdKey.ucKeyLen = 16; /* AES = 128bit */ ++ kalMemCopy(rCmdKey.aucKeyMaterial, prBowSetPTK->aucTemporalKey, 16); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowSetPTK->aucTemporalKey, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ prBowSetPTK->aucTemporalKey[0], ++ prBowSetPTK->aucTemporalKey[1], ++ prBowSetPTK->aucTemporalKey[2], ++ prBowSetPTK->aucTemporalKey[3], ++ prBowSetPTK->aucTemporalKey[4], ++ prBowSetPTK->aucTemporalKey[5], ++ prBowSetPTK->aucTemporalKey[6], ++ prBowSetPTK->aucTemporalKey[7], ++ prBowSetPTK->aucTemporalKey[8], ++ prBowSetPTK->aucTemporalKey[9], ++ prBowSetPTK->aucTemporalKey[10], ++ prBowSetPTK->aucTemporalKey[11], ++ prBowSetPTK->aucTemporalKey[12], ++ prBowSetPTK->aucTemporalKey[13], ++ prBowSetPTK->aucTemporalKey[14], prBowSetPTK->aucTemporalKey[15])); ++ ++ DBGLOG(BOW, EVENT, "rCmdKey.aucKeyMaterial, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ rCmdKey.aucKeyMaterial[0], ++ rCmdKey.aucKeyMaterial[1], ++ rCmdKey.aucKeyMaterial[2], ++ rCmdKey.aucKeyMaterial[3], ++ rCmdKey.aucKeyMaterial[4], ++ rCmdKey.aucKeyMaterial[5], ++ rCmdKey.aucKeyMaterial[6], ++ rCmdKey.aucKeyMaterial[7], ++ rCmdKey.aucKeyMaterial[8], ++ rCmdKey.aucKeyMaterial[9], ++ rCmdKey.aucKeyMaterial[10], ++ rCmdKey.aucKeyMaterial[11], ++ rCmdKey.aucKeyMaterial[12], ++ rCmdKey.aucKeyMaterial[13], rCmdKey.aucKeyMaterial[14], rCmdKey.aucKeyMaterial[15])); ++#endif ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventSetCommon, ++ wlanbowCmdTimeoutHandler, ++ sizeof(CMD_802_11_KEY), (PUINT_8)&rCmdKey, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_READ_RSSI ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_READ_RSSI prBowReadRSSI; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_READ_RSSI)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowReadRSSI = (P_BOW_READ_RSSI) &(prCmd->aucPayload[0]); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ wlanbowCmdEventReadRssi, ++ wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_READ_LINK_QUALITY ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_READ_LINK_QUALITY prBowReadLinkQuality; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(P_BOW_READ_LINK_QUALITY)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowReadLinkQuality = (P_BOW_READ_LINK_QUALITY) &(prCmd->aucPayload[0]); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ wlanbowCmdEventReadLinkQuality, ++ wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SHORT_RANGE_MODE ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SHORT_RANGE_MODE prBowShortRangeMode; ++ CMD_TX_PWR_T rTxPwrParam; ++ ++ ASSERT(prAdapter); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdShortRangeMode.\n"); ++#endif ++ ++ prBowShortRangeMode = (P_BOW_SHORT_RANGE_MODE) &(prCmd->aucPayload[0]); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SHORT_RANGE_MODE)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowShortRangeMode->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (bowGetBowTableState(prAdapter, prBowShortRangeMode->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowShortRangeMode->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowShortRangeMode->aucPeerAddress[0], ++ prBowShortRangeMode->aucPeerAddress[1], ++ prBowShortRangeMode->aucPeerAddress[2], ++ prBowShortRangeMode->aucPeerAddress[3], ++ prBowShortRangeMode->aucPeerAddress[4], prBowShortRangeMode->aucPeerAddress[5])); ++#endif ++ ++ rTxPwrParam.cTxPwr2G4Cck = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4OFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4OFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4HT20_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4HT40_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr5GOFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr5GHT20_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ if (nicUpdateTxPower(prAdapter, &rTxPwrParam) == WLAN_STATUS_SUCCESS) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdShortRangeMode, %x.\n", WLAN_STATUS_SUCCESS); ++#endif ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ return WLAN_STATUS_SUCCESS; ++ } ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_GET_CHANNEL_LIST ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ ASSERT(prAdapter); ++ ++ /* not supported yet */ ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is generic command done handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = ucEventBuf; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is generic command done handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_CONNECTED prBowLinkConnected; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); ++ ++ /* fill event body */ ++ prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prEvent->aucPayload); ++ kalMemZero(prBowLinkConnected, sizeof(BOW_LINK_CONNECTED)); ++ prBowLinkConnected->rChannel.ucChannelNum = prBssInfo->ucPrimaryChannel; ++ prBowLinkConnected->rChannel.ucChannelBand = prBssInfo->eBand; ++ COPY_MAC_ADDR(prBowLinkConnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); ++ DBGLOG(BOW, EVENT, ++ "prBowLinkConnected->rChannel.ucChannelNum, 0x%x\n", prBowLinkConnected->rChannel.ucChannelNum); ++ DBGLOG(BOW, EVENT, ++ "prBowLinkConnected->rChannel.ucChannelBand, 0x%x\n", prBowLinkConnected->rChannel.ucChannelBand); ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkConnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5]); ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkConnected, prBowLinkConnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowLinkConnected->aucPeerAddress[0], prBowLinkConnected->aucPeerAddress[1], ++ prBowLinkConnected->aucPeerAddress[2], prBowLinkConnected->aucPeerAddress[3], ++ prBowLinkConnected->aucPeerAddress[4], prBowLinkConnected->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkConnected, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Indicate Event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED))); ++ ++ /*Release channel if granted */ ++ if (prBowFsmInfo->fgIsChannelGranted) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ /* bowReleaseCh(prAdapter); */ ++ /*Requested, not granted yet */ ++ } else if (prBowFsmInfo->fgIsChannelRequested) { ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ } ++ ++ /* set to connected status */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTED); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ BOW_TABLE_T rBowTable; ++ UINT_8 ucBowTableIdx; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ BOOLEAN fgSendDeauth = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /*do nothing */ ++ return; ++ } ++ /*Cancel scan */ ++ else if (eFsmState == BOW_DEVICE_STATE_SCANNING && !(prBowFsmInfo->fgIsChannelRequested)) { ++ bowResponderCancelScan(prAdapter, FALSE); ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_DISCONNECTING); ++ return; ++ } ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; ++ if ((prCmdInfo->u4PrivateData)) ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ else ++ prEvent->rHeader.ucSeqNumber = 0; ++ ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); ++ ++ /* fill event body */ ++ prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prEvent->aucPayload); ++ kalMemZero(prBowLinkDisconnected, sizeof(BOW_LINK_DISCONNECTED)); ++ prBowLinkDisconnected->ucReason = 0x0; ++ COPY_MAC_ADDR(prBowLinkDisconnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); ++ ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkDisconnected, prBowLinkDisconnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowLinkDisconnected->aucPeerAddress[0], prBowLinkDisconnected->aucPeerAddress[1], ++ prBowLinkDisconnected->aucPeerAddress[2], prBowLinkDisconnected->aucPeerAddress[3], ++ prBowLinkDisconnected->aucPeerAddress[4], prBowLinkDisconnected->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Indicate BoW event to PAL */ ++#if 0 ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++#endif ++ ++ /* set to disconnected status */ ++ prBowFsmInfo->prTargetStaRec = ++ cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_BOW_INDEX, prBowLinkDisconnected->aucPeerAddress); ++ if (!(prBowFsmInfo->prTargetStaRec)) { ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ /*Release channel if granted */ ++ if (prBowFsmInfo->fgIsChannelGranted) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ bowReleaseCh(prAdapter); ++ /*Requested, not granted yet */ ++ } else if (prBowFsmInfo->fgIsChannelRequested) { ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ /* bowReleaseCh(prAdapter); */ ++ } ++#if 1 ++ /*Send Deauth to connected peer */ ++ if (eFsmState == BOW_DEVICE_STATE_CONNECTED && (prBowFsmInfo->prTargetStaRec->ucStaState == STA_STATE_3)) { ++ fgSendDeauth = TRUE; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkDisconnected, bowGetBowTableState, %x.\n", ++ bowGetBowTableState(prAdapter, prBowLinkDisconnected->aucPeerAddress)); ++#endif ++ authSendDeauthFrame(prAdapter, ++ prBowFsmInfo->prTargetStaRec, ++ (P_SW_RFB_T) NULL, ++ REASON_CODE_DEAUTH_LEAVING_BSS, (PFN_TX_DONE_HANDLER) bowDisconnectLink); ++ } ++#endif ++ ++#if 0 ++ /* 3 <3>Stop this link; flush Tx; ++ * send deAuthentication -> abort. SAA, AAA. need to check BOW table state == Connected. ++ */ ++ if (prAdapter->prGlueInfo->i4TxPendingFrameNum > 0) ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* flush pending security frames */ ++ if (prAdapter->prGlueInfo->i4TxPendingSecurityFrameNum > 0) ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++#endif ++ ++ /*Update BoW table */ ++ bowGetBowTableEntryByPeerAddress(prAdapter, prBowLinkDisconnected->aucPeerAddress, &ucBowTableIdx); ++ rBowTable.fgIsValid = FALSE; ++ rBowTable.eState = BOW_DEVICE_STATE_DISCONNECTED; ++ kalMemZero(rBowTable.aucPeerAddress, sizeof(rBowTable.aucPeerAddress)); ++ bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); ++ ++ /*Indicate BoW event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++ ++ /*Decrease link count */ ++ GLUE_DEC_REF_CNT(g_u4LinkCount); ++ ++ /*If no need to send deauth, DO disconnect now */ ++ /*If need to send deauth, DO disconnect at deauth Tx done */ ++ if (!fgSendDeauth) ++ bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_BT_OVER_WIFI prCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* restore original command for rPeerAddr */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prCmdBtOverWifi = (P_CMD_BT_OVER_WIFI) (prWifiCmd->aucBuffer); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; ++ ++ /*Indicate BoW event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++ ++ /* set to starting status */ ++ kalSetBowState(prAdapter->prGlueInfo, BOW_DEVICE_STATE_STARTING, prCmdBtOverWifi->rPeerAddr); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the command done handler for BOW_CMD_ID_READ_LINK_QUALITY ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_QUALITY prBowLinkQuality; ++ ++ ASSERT(prAdapter); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_QUALITY; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_QUALITY); ++ ++ /* fill event body */ ++ prBowLinkQuality = (P_BOW_LINK_QUALITY) (prEvent->aucPayload); ++ kalMemZero(prBowLinkQuality, sizeof(BOW_LINK_QUALITY)); ++ prBowLinkQuality->ucLinkQuality = (UINT_8) prLinkQuality->cLinkQuality; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the command done handler for BOW_CMD_ID_READ_RSSI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_AMPC_EVENT prEvent; ++ P_BOW_RSSI prBowRssi; ++ ++ ASSERT(prAdapter); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_RSSI; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_RSSI); ++ ++ /* fill event body */ ++ prBowRssi = (P_BOW_RSSI) (prEvent->aucPayload); ++ kalMemZero(prBowRssi, sizeof(BOW_RSSI)); ++ prBowRssi->cRssi = (INT_8) prLinkQuality->cRssi; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the default command timeout handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_TIMEOUT; /* timeout */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++ ++} ++ ++VOID bowStopping(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBowBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStoping.\n"); ++ DBGLOG(BOW, EVENT, "bowStoping, SSID %s.\n", prBowBssInfo->aucSSID); ++ DBGLOG(BOW, EVENT, "bowStoping, prBowBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", ++ prBowBssInfo->aucBSSID[0], ++ prBowBssInfo->aucBSSID[1], ++ prBowBssInfo->aucBSSID[2], ++ prBowBssInfo->aucBSSID[3], prBowBssInfo->aucBSSID[4], prBowBssInfo->aucBSSID[5])); ++ DBGLOG(BOW, EVENT, "bowStoping, prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prBowBssInfo->aucOwnMacAddr[0], ++ prBowBssInfo->aucOwnMacAddr[1], ++ prBowBssInfo->aucOwnMacAddr[2], ++ prBowBssInfo->aucOwnMacAddr[3], ++ prBowBssInfo->aucOwnMacAddr[4], prBowBssInfo->aucOwnMacAddr[5])); ++ DBGLOG(BOW, EVENT, "bowStoping, prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", ++ prAdapter->rWifiVar.aucDeviceAddress[0], ++ prAdapter->rWifiVar.aucDeviceAddress[1], ++ prAdapter->rWifiVar.aucDeviceAddress[2], ++ prAdapter->rWifiVar.aucDeviceAddress[3], ++ prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); ++ DBGLOG(BOW, EVENT, "bowStopping, g_u4LinkCount, %x.\n", g_u4LinkCount); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ kalPrint("BoW Stoping,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++#endif ++ ++ if (g_u4LinkCount == 0) { ++ /*Stop beaconing */ ++ GLUE_DEC_REF_CNT(g_u4Beaconing); ++ ++ /*Deactive BoW network */ ++ /* prBowBssInfo->fgIsNetActive = FALSE; */ ++ /* prBowBssInfo->fgIsBeaconActivated = FALSE; */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ /*temp solution for FW hal_pwr_mgt.c#3037 ASSERT */ ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ } ++ ++} ++ ++VOID bowStarting(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (g_u4LinkCount == 1) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "BoW Starting.\n"); ++ DBGLOG(BOW, EVENT, "BoW channel granted.\n"); ++#endif ++ ++#if 0 ++ /*Active BoW Network */ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#endif ++ ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBssInfo->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prBssInfo->eCurrentOPMode = OP_MODE_BOW; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucDeviceAddress); ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); ++ prBssInfo->ucSSIDLen = BOW_SSID_LEN; ++ bowAssignSsid(prBssInfo->aucSSID, prBssInfo->aucOwnMacAddr); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "SSID %s.\n", prBssInfo->aucSSID); ++ DBGLOG(BOW, EVENT, "prBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", ++ prBssInfo->aucBSSID[0], ++ prBssInfo->aucBSSID[1], ++ prBssInfo->aucBSSID[2], ++ prBssInfo->aucBSSID[3], prBssInfo->aucBSSID[4], prBssInfo->aucBSSID[5])); ++ DBGLOG(BOW, EVENT, "prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prBssInfo->aucOwnMacAddr[0], ++ prBssInfo->aucOwnMacAddr[1], ++ prBssInfo->aucOwnMacAddr[2], ++ prBssInfo->aucOwnMacAddr[3], ++ prBssInfo->aucOwnMacAddr[4], prBssInfo->aucOwnMacAddr[5])); ++ DBGLOG(BOW, EVENT, "prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", ++ prAdapter->rWifiVar.aucDeviceAddress[0], ++ prAdapter->rWifiVar.aucDeviceAddress[1], ++ prAdapter->rWifiVar.aucDeviceAddress[2], ++ prAdapter->rWifiVar.aucDeviceAddress[3], ++ prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); ++#endif ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.4> Setup Channel, Band and Phy Attributes */ ++ prBssInfo->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; ++ if (prBowFsmInfo->eBand == BAND_2G4) ++ prBssInfo->eBand = BAND_2G4; ++ else ++ prBssInfo->eBand = BAND_5G; ++ ++#if CFG_BOW_SUPPORT_11N ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ ++#else ++ if (prBssInfo->eBand == BAND_2G4) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ ++ /* RATE_SET_ERP; */ ++ prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; ++ prBssInfo->u2OperationalRateSet = RATE_SET_ERP; ++ prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else { ++ /* Depend on eBand */ ++ /* prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; */ ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ /* prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; */ ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11A; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; ++ ++ /* RATE_SET_ERP; */ ++ /* prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; */ ++ /* prBssInfo->u2OperationalRateSet = RATE_SET_ERP; */ ++ ++ /* RATE_SET_ERP; */ ++ prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_OFDM; ++ prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; ++ prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } ++ ++#endif ++ prBssInfo->fgErpProtectMode = FALSE; ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2BeaconInterval = prBowFsmInfo->u2BeaconInterval; ++ prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ prBssInfo->u2ATIMWindow = 0; ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ if (prBowFsmInfo->fgSupportQoS) { ++ prAdapter->rWifiVar.fgSupportQoS = TRUE; ++ prBssInfo->fgIsQBSS = TRUE; ++ } ++ /* 3 <2> Update BSS_INFO_T common part */ ++#if CFG_SUPPORT_AAA ++ bssInitForAP(prAdapter, prBssInfo, TRUE); ++ nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#endif /* CFG_SUPPORT_AAA */ ++ prBssInfo->fgIsNetActive = TRUE; ++ prBssInfo->fgIsBeaconActivated = TRUE; ++ ++ /* 3 <3> Set MAC HW */ ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BOW_BSS_INFO_INIT(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], ++ prBowFsmInfo->aucPeerAddress[5])); ++#endif ++ ++ /* 4 <3.1> use command packets to inform firmware */ ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /* 4 <3.2> Update AdHoc PM parameter */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /* 4 <3.1> Reset HW TSF Update Mode and Beacon Mode */ ++ ++ /* 4 <3.2> Setup BSSID */ ++ /* TODO: rxmSetRxFilterBSSID0 */ ++/* rxmSetRxFilterBSSID0(prBssInfo->ucHwBssidId, prBssInfo->aucBSSID); */ ++ ++ /* 4 <3.3> Setup RX Filter to accept Probe Request */ ++ /* TODO: f get/set RX filter. */ ++ ++#if 0 ++ { ++ UINT_32 u4RxFilter; ++ ++ if (halMacRxGetRxFilters(&u4RxFilter) == HAL_STATUS_SUCCESS) { ++ ++ u4RxFilter &= ~BIT(RXFILTER_DROP_PROBE_REQ); ++ ++ halMacRxSetRxFilters(u4RxFilter); ++ } ++ } ++#endif ++ } ++ ++ /*Update BoW Table */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_STARTING); ++ ++#if CFG_BOW_TEST ++ kalPrint("BoW Starting,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++ DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Start beaconing */ ++ if (g_u4Beaconing < 1) { ++ GLUE_INC_REF_CNT(g_u4Beaconing); ++ bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); ++ cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); ++ } ++#if 0 ++ /*Responder: Start to scan Initiator */ ++ if (prBowFsmInfo->ucRole == BOW_RESPONDER) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting responder, start scan result searching.\n"); ++#endif ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ bowReleaseCh(prAdapter); ++ bowResponderScan(prAdapter); ++ } ++ /*Initiator: Request channel, wait for responder */ ++ else { ++ /* Todo:: Nothing*/ ++ /* bowRequestCh(prAdapter); */ ++ } ++#endif ++ ++} ++ ++VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 puOwnMacAddr) ++{ ++ UINT_8 i; ++ UINT_8 aucSSID[] = BOW_WILDCARD_SSID; ++ ++ kalMemCopy(pucSsid, aucSSID, BOW_WILDCARD_SSID_LEN); ++ ++ for (i = 0; i < 6; i++) { ++ pucSsid[(3 * i) + 3] = 0x2D; ++ if ((*(puOwnMacAddr + i) >> 4) < 0xA) ++ *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x30; ++ else ++ *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x57; ++ ++ if ((*(puOwnMacAddr + i) & 0x0F) < 0xA) ++ pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x30; ++ else ++ pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x57; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ BOOLEAN fgReplyProbeResp = FALSE; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu4ControlFlags); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if 0 /* CFG_BOW_TEST */ ++ DBGLOG(BOW, EVENT, "bowValidateProbeReq.\n"); ++#endif ++ ++ /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions */ ++ /*If BoW AP is beaconing */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_BOW && g_u4Beaconing > 0) { ++ ++ /*Check the probe requset sender is our peer */ ++ if (bowCheckBowTableIfVaild(prAdapter, prMgtHdr->aucSrcAddr)) ++ fgReplyProbeResp = TRUE; ++ /*Check the probe request target SSID is our SSID */ ++ else if ((prIeSsid) && ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prIeSsid->aucSSID, prIeSsid->ucLength)) ++ fgReplyProbeResp = TRUE; ++ else ++ fgReplyProbeResp = FALSE; ++ } ++ ++ return fgReplyProbeResp; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if ((g_u4Beaconing != 0) && (g_u4LinkCount > 0) && (g_u4LinkCount < CFG_BOW_PHYSICAL_LINK_NUM)) { ++ /* Send beacon */ ++ bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); ++ cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); ++ } ++#if CFG_BOW_TEST ++ else ++ kalPrint("BoW Send Beacon,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderScan(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderScan.\n"); ++ kalPrint("BOW SCAN [REQ:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq + 1); ++#endif ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ ++ if (!prScanReqMsg) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ /*Fill scan message */ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfScanReq; ++ prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_BOW_INDEX; ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ prScanReqMsg->ucSSIDLength = BOW_SSID_LEN; ++ bowAssignSsid(prScanReqMsg->aucSSID, prBowFsmInfo->aucPeerAddress); ++ prScanReqMsg->ucChannelListNum = 1; ++ ++ if (prBowFsmInfo->eBand == BAND_2G4) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ prScanReqMsg->arChnlInfoList[0].eBand = BAND_2G4; ++ } else { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ prScanReqMsg->arChnlInfoList[0].eBand = BAND_5G; ++ } ++ ++ prScanReqMsg->arChnlInfoList[0].ucChannelNum = prBowFsmInfo->ucPrimaryChannel; ++ prScanReqMsg->u2IELen = 0; ++ ++ /*Send scan message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ ++ /*Change state to SCANNING */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); ++ ++ /* prBowFsmInfo->fgTryScan = FALSE; */ /* Will enable background sleep for infrastructure */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_DESC_T prBssDesc; ++ UINT_8 ucSeqNumOfCompMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ENUM_SCAN_STATUS eScanStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ ASSERT(prScanDoneMsg->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX); ++ ++ ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; ++ eScanStatus = prScanDoneMsg->eScanStatus; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderScanDone.\n"); ++ kalPrint("BOW SCAN [DONE:%d]\n", ucSeqNumOfCompMsg); ++#endif ++ ++ if (eScanStatus == SCAN_STATUS_CANCELLED) { ++#if CFG_BOW_TEST ++ kalPrint("BOW SCAN [CANCELLED:%d]\n", ucSeqNumOfCompMsg); ++#endif ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTING) { ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ } ++ return; ++ } else if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /* bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); */ ++ return; ++ } else if (ucSeqNumOfCompMsg != prBowFsmInfo->ucSeqNumOfScanReq) { ++ DBGLOG(BOW, EVENT, "Sequence no. of BOW Responder scan done is not matched.\n"); ++ return; ++ } ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prBowFsmInfo->aucPeerAddress); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "End scan result searching.\n"); ++#endif ++ ++ /* Initiator is FOUND */ ++ if (prBssDesc != NULL) { ++ /* (prBssDesc->aucBSSID != NULL)) */ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Search Bow Peer address - %x:%x:%x:%x:%x:%x.\n", prBssDesc->aucBSSID[0], ++ prBssDesc->aucBSSID[1], ++ prBssDesc->aucBSSID[2], ++ prBssDesc->aucBSSID[3], prBssDesc->aucBSSID[4], prBssDesc->aucBSSID[5]); ++ DBGLOG(BOW, EVENT, "Starting to join initiator.\n"); ++#endif ++ /*Set target BssDesc */ ++ prBowFsmInfo->prTargetBssDesc = prBssDesc; ++ /*Request channel to do JOIN */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL); ++ bowRequestCh(prAdapter); ++ } ++ /*Initiator is NOT FOUND */ ++ else { ++ /*Scan again, until PAL timeout */ ++ bowResponderScan(prAdapter); ++#if 0 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#endif ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Function for cancelling scan request. There is another option to extend channel privilige ++* for another purpose. ++* ++* @param fgIsChannelExtention - Keep the channel previlege, but can cancel scan timer. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention) ++{ ++ ++ P_MSG_SCN_SCAN_CANCEL prScanCancel = (P_MSG_SCN_SCAN_CANCEL) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo = (P_BOW_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("bowResponderCancelScan()"); ++ ++ do { ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (TRUE) { ++#if CFG_BOW_TEST ++ kalPrint("BOW SCAN [CANCEL:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq); ++#endif ++ /* There is a channel privilege on hand. */ ++ ++ DBGLOG(P2P, TRACE, "BOW Cancel Scan\n"); ++ ++ prScanCancel = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancel) { ++ /* Buffer not enough, can not cancel scan request. */ ++ DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanCancel->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_CANCEL; ++ prScanCancel->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prScanCancel->ucSeqNum = prBowFsmInfo->ucSeqNumOfScanReq; ++#if CFG_ENABLE_WIFI_DIRECT ++ prScanCancel->fgIsChannelExt = fgIsChannelExtention; ++#endif ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancel, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++ ++} /* bowResponderCancelScan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialization of JOIN STATE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ ASSERT(prBssDesc); ++ ASSERT(prAdapter); ++ ++ DBGLOG(BOW, EVENT, "Starting bowResponderJoin.\n"); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> We are going to connect to this BSS. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTING); ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ /*Support First JOIN and retry */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_BOW_AP, NETWORK_TYPE_BOW_INDEX, prBssDesc); ++ if (!prStaRec) ++ return; ++ ++ prBowFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ ++ prStaRec->fgIsReAssoc = FALSE; ++ prBowFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ ++ /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ ++ if (prBowFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(BOW, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ prBowFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <4.1> sync. to firmware domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy */ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prBssDesc->aucSSID); ++ DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prConnSettings->aucSSID); ++#endif ++ } ++ /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_BOW_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ prBssInfo->prStaRecOfAP = prStaRec; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prStaRec->eStaType, %x.\n", prStaRec->eStaType); ++ DBGLOG(BOW, INFO, "BoW trigger SAA [%pM]\n", prStaRec->aucMacAddr); ++#endif ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Join Complete Event from SAA FSM for BOW FSM ++* ++* @param[in] prMsgHdr Message of Join Complete of SAA FSM. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_JOIN_COMP_T prJoinCompMsg; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prAssocRspSwRfb; ++ P_BSS_INFO_T prBssInfo; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prStaRec = prJoinCompMsg->prStaRec; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete.\n"); ++ DBGLOG(BOW, EVENT, "bowfsmRunEventJoinComplete ptr check\n"); ++ DBGLOG(BOW, EVENT, "prMsgHdr %x\n", prMsgHdr); ++ DBGLOG(BOW, EVENT, "prAdapter %x\n", prAdapter); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo %x\n", prBowFsmInfo); ++ DBGLOG(BOW, EVENT, "prStaRec %x\n", prStaRec); ++#endif ++ ++ ASSERT(prStaRec); ++ ASSERT(prBowFsmInfo); ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prBowFsmInfo->ucSeqNumOfReqMsg) { ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); ++ ++ /* 4 <1> JOIN was successful */ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - ++ WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ prStaRec->eStaType = STA_TYPE_BOW_AP; ++ prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; ++#if CFG_BOW_RATE_LIMITATION ++ /* 4 <1.2>Update Rate Set */ ++ /*Limit Rate Set to 24M, 48M, 54M */ ++ prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); ++ /*If peer cannot support the above rate set, fix on the available highest rate */ ++ if (prStaRec->u2DesiredNonHTRateSet == 0) { ++ UINT_8 ucHighestRateIndex; ++ ++ if (rateGetHighestRateIndexFromRateSet ++ (prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) { ++ prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); ++ } ++ } ++#endif ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <1.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++#if CFG_BOW_SUPPORT_11N ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++#endif ++ ++ /* 4 <1.3> Update BSS_INFO_T */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Finish bowUpdateBssInfoForJOIN.\n"); ++#endif ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowFsmRunEventJoinComplete, qmActivateStaRec.\n"); ++#endif ++ ++ /* 4 <1.7> Set the Next State of BOW FSM */ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ } ++ /* 4 <2> JOIN was not successful */ ++ else { ++ /*Retry */ ++ bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); ++#if 0 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#endif ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete -- Join failed.\n"); ++ DBGLOG(BOW, INFO, "BoW trigger SAA REJOIN\n"); ++#endif ++ } ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Media State to HOST ++* ++* @param[in] eConnectionState Current Media State ++* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN BOOLEAN fgDelayIndication) ++{ ++ EVENT_CONNECTION_STATUS rEventConnStatus; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* NOTE(Kevin): Move following line to bowChangeMediaState() macro per CM's request. */ ++ /* prBowBssInfo->eConnectionState = eConnectionState; */ ++ ++ /* For indicating the Disconnect Event only if current media state is ++ * disconnected and we didn't do indication yet. ++ */ ++ if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ if (prBssInfo->eConnectionStateIndicated == eConnectionState) ++ return; ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <0> Cancel Delay Timer */ ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rIndicationOfDisconnectTimer); ++ ++ /* 4 <1> Fill EVENT_CONNECTION_STATUS */ ++ rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; ++ ++ if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_BOW) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; ++ rEventConnStatus.u2AID = prBssInfo->u2AssocId; ++ rEventConnStatus.u2ATIMWindow = 0; ++ } else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; ++ rEventConnStatus.u2AID = 0; ++ rEventConnStatus.u2ATIMWindow = prBssInfo->u2ATIMWindow; ++ } else { ++ ASSERT(0); ++ } ++ ++ COPY_SSID(rEventConnStatus.aucSsid, ++ rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ COPY_MAC_ADDR(rEventConnStatus.aucBssid, prBssInfo->aucBSSID); ++ ++ rEventConnStatus.u2BeaconPeriod = prBssInfo->u2BeaconInterval; ++ rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prBssInfo->ucPrimaryChannel); ++ ++ switch (prBssInfo->ucNonHTBasicPhyType) { ++ case PHY_TYPE_HR_DSSS_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PHY_TYPE_ERP_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PHY_TYPE_OFDM_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ default: ++ ASSERT(0); ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ } ++ } else { ++#if CFG_PRIVACY_MIGRATION ++ /* Clear the pmkid cache while media disconnect */ ++ secClearPmkid(prAdapter); ++#endif ++ ++ rEventConnStatus.ucReasonOfDisconnect = prBssInfo->ucReasonOfDisconnect; ++ ++ } ++ ++ /* 4 <2> Indication */ ++ nicMediaStateChange(prAdapter, NETWORK_TYPE_BOW_INDEX, &rEventConnStatus); ++ prBssInfo->eConnectionStateIndicated = eConnectionState; ++ } else { ++ /* NOTE: Only delay the Indication of Disconnect Event */ ++ ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ DBGLOG(BOW, INFO, "Postpone the indication of Disconnect for %d seconds\n", ++ prConnSettings->ucDelayTimeOfDisconnectEvent); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rIndicationOfDisconnectTimer, ++ SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Tx Fail of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowRunEventAAATxFail , bssRemoveStaRecFromClientList.\n"); ++ DBGLOG(BOW, INFO, "BoW AAA TxFail, target state %d\n", prStaRec->ucStaState + 1); ++#endif ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ ASSERT(prStaRec); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowRunEventAAAComplete, cnmStaRecChangeState, STA_STATE_3.\n"); ++ DBGLOG(BOW, INFO, "BoW AAA complete [%pM]\n", prStaRec->aucMacAddr); ++#endif ++ ++ /*Update BssInfo to connected */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /*Update StaRec to State3 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /*Connected */ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, FALSE, wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle RxDeauth ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBowBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if (!IS_STA_IN_BOW(prStaRec)) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ ++ eFsmState = bowGetBowTableState(prAdapter, prStaRec->aucMacAddr); ++ ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /*do nothing */ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (prStaRec->ucStaState > STA_STATE_1) { ++ ++ if (STA_STATE_3 == prStaRec->ucStaState) { ++ /* P_MSG_AIS_ABORT_T prAisAbortMsg; */ ++ ++ /* NOTE(Kevin): Change state immediately to avoid starvation of ++ * MSG buffer because of too many deauth frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); ++ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, wlanbowCmdEventLinkDisconnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handle BoW Link disconnect. ++* ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++* ++* \note after receive deauth frame, callback function call this ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /*Free target StaRec */ ++ if (prMsduInfo) ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ else ++ prStaRec = prBowFsmInfo->prTargetStaRec; ++ ++ if (prStaRec) ++ /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ kalPrint("bowDisconnectLink\n"); ++ /*No one connected */ ++ if (g_u4LinkCount == 0 && g_u4Beaconing != 0) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer); ++ bowStopping(prAdapter); ++ kalPrint("bowStopping\n"); ++ /*Restore TxPower from Short range mode */ ++#if CFG_SUPPORT_NVRAM && 0 ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ /*Uninit BoW Interface */ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalUninitBowDevice(prAdapter->prGlueInfo); ++#endif ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Assoc Req Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Assoc Resp ++* @retval FALSE Don't reply the Assoc Resp ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAssocResp = FALSE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; ++ OS_SYSTIME rCurrentTime; ++ static OS_SYSTIME rLastRejectAssocTime; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, prAssocReqFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", ++ prAssocReqFrame->aucSrcAddr[0], ++ prAssocReqFrame->aucSrcAddr[1], ++ prAssocReqFrame->aucSrcAddr[2], ++ prAssocReqFrame->aucSrcAddr[3], ++ prAssocReqFrame->aucSrcAddr[4], prAssocReqFrame->aucSrcAddr[5])); ++#endif ++ ++ /*Assoc Accept */ ++ while (EQUAL_MAC_ADDR(prAssocReqFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, return wlanbowCmdEventLinkConnected.\n"); ++#endif ++ /*Update StaRec */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (UINT_8) NETWORK_TYPE_BOW_INDEX, prAssocReqFrame->aucSrcAddr); ++ if (!prStaRec) ++ break; ++ prStaRec->eStaType = STA_TYPE_BOW_CLIENT; ++ prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; ++ ++#if CFG_BOW_RATE_LIMITATION ++ /*Limit Rate Set to 24M, 48M, 54M */ ++ prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); ++ /*If peer cannot support the above rate set, fix on the available highest rate */ ++ if (prStaRec->u2DesiredNonHTRateSet == 0) { ++ UINT_8 ucHighestRateIndex; ++ ++ if (rateGetHighestRateIndexFromRateSet(prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) ++ prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); ++ else { ++ /*If no available rate is found, DECLINE the association */ ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ } ++#endif ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ ++ /*Undpate BssInfo to FW */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /*reply successful */ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ fgReplyAssocResp = TRUE; ++ break; ++ } ++ ++ /*Reject Assoc */ ++ if (*pu2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ /*Reply Assoc with reject every 5s */ ++ rCurrentTime = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAssocTime, MSEC_TO_SYSTIME(5000)) || ++ rLastRejectAssocTime == 0) { ++ fgReplyAssocResp = TRUE; ++ rLastRejectAssocTime = rCurrentTime; ++ } ++ } ++ ++ return fgReplyAssocResp; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Auth Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Auth ++* @retval FALSE Don't reply the Auth ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++bowValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAuth = FALSE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; ++ OS_SYSTIME rCurrentTime; ++ static OS_SYSTIME rLastRejectAuthTime; ++ ++ /* TODO(Kevin): Call BoW functions to check .. ++ 1. Check we are BoW now. ++ 2. Check we can accept connection from thsi peer ++ 3. Check Black List here. ++ */ ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prAuthFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", ++ prAuthFrame->aucSrcAddr[0], ++ prAuthFrame->aucSrcAddr[1], ++ prAuthFrame->aucSrcAddr[2], ++ prAuthFrame->aucSrcAddr[3], prAuthFrame->aucSrcAddr[4], prAuthFrame->aucSrcAddr[5])); ++#endif ++ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX, prAuthFrame->aucSrcAddr); ++ if (!prStaRec) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecAlloc.\n"); ++#endif ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ if (!prStaRec) ++ return fgReplyAuth; ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ prBowBssInfo->prStaRecOfAP = prStaRec; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecChangeState.\n"); ++#endif ++ } else { ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucIndex, %x.\n", prStaRec->ucIndex); ++#endif ++ bssRemoveStaRecFromClientList(prAdapter, prBowBssInfo, prStaRec); ++ } ++ ++ if (EQUAL_MAC_ADDR(prAuthFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { ++ ++ prStaRec->eStaType = STA_TYPE_BOW_CLIENT; ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->eStaType, %x.\n", prStaRec->eStaType); ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucNetTypeIndex, %x.\n", prStaRec->ucNetTypeIndex); ++#endif ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->ucJoinFailureCount = 0; ++ *pprStaRec = prStaRec; ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ fgReplyAuth = TRUE; ++ } else { ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ /*Reply auth with reject every 5s */ ++ rCurrentTime = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAuthTime, MSEC_TO_SYSTIME(5000)) || ++ rLastRejectAuthTime == 0) { ++ fgReplyAuth = TRUE; ++ rLastRejectAuthTime = rCurrentTime; ++ } ++ } ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, fgReplyAuth, %x.\n", fgReplyAuth); ++#endif ++ return fgReplyAuth; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is invoked when CNM granted channel privilege ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prBowBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_GRANT_T prMsgChGrant; ++ UINT_8 ucTokenID; ++ UINT_32 u4GrantInterval; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ucTokenID = prMsgChGrant->ucTokenID; ++ u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ /* 1. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ prBowFsmInfo->fgIsChannelGranted = TRUE; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Entering bowRunEventChGrant.\n"); ++#endif ++ ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ /*Release channel */ ++ if ((!prBowFsmInfo->fgIsChannelRequested) || ++ (prBowFsmInfo->ucSeqNumOfChReq != ucTokenID) || ++ (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) || (eFsmState == BOW_DEVICE_STATE_DISCONNECTING)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [GIVE UP:%d]\n", ucTokenID); ++ DBGLOG(BOW, INFO, "[Requested:%d][ucSeqNumOfChReq:%d][eFsmState:%d]\n", ++ prBowFsmInfo->fgIsChannelRequested, prBowFsmInfo->ucSeqNumOfChReq, eFsmState); ++#endif ++ bowReleaseCh(prAdapter); ++ return; ++ } ++ ++ /* 2. channel privilege has been approved */ ++ prBowFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++#if 0 ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, ++ prBowFsmInfo->u4ChGrantedInterval - BOW_JOIN_CH_GRANT_THRESHOLD); ++#else ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, BOW_JOIN_CH_REQUEST_INTERVAL - BOW_JOIN_CH_GRANT_THRESHOLD); ++#endif ++ ++ /* 3.2 set local variable to indicate join timer is ticking */ ++ prBowFsmInfo->fgIsInfraChannelFinished = FALSE; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [GRANTED:%d].\n", ucTokenID); ++#endif ++ ++ if (eFsmState == BOW_DEVICE_STATE_ACQUIRING_CHANNEL) { ++ bowStarting(prAdapter); ++ bowReleaseCh(prAdapter); ++ if (prBowFsmInfo->ucRole == BOW_RESPONDER) ++ bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); ++ } else { ++ /*update bssinfo */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ bowReleaseCh(prAdapter); ++ } ++ ++} /* end of aisFsmRunEventChGrant() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM for channel privilege requesting ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRequestCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_REQ_T prMsgChReq; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (prBowFsmInfo->fgIsChannelGranted == FALSE) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW channel [REQUEST:%d], %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq + 1, ++ prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); ++#endif ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prMsgChReq->ucTokenID = ++prBowFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++#if 0 ++ prMsgChReq->u4MaxInterval = BOW_JOIN_CH_REQUEST_INTERVAL; ++#else ++ prMsgChReq->u4MaxInterval = 1; ++#endif ++ /* prBowFsmInfo->prTargetBssDesc->ucChannelNum; */ ++ prMsgChReq->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; ++ /* prBowFsmInfo->prTargetBssDesc->eSco; */ ++ prMsgChReq->eRfSco = CHNL_EXT_SCN; ++ /* prBowFsmInfo->prTargetBssDesc->eBand; */ ++ prMsgChReq->eRfBand = prBowFsmInfo->eBand; ++ COPY_MAC_ADDR(prMsgChReq->aucBSSID, prBowFsmInfo->aucPeerAddress); ++ ++ prBowFsmInfo->fgIsChannelRequested = TRUE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform BOW that channel privilege is granted ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowReleaseCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (prBowFsmInfo->fgIsChannelGranted != FALSE || prBowFsmInfo->fgIsChannelRequested != FALSE) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW channel [RELEASE:%d] %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq, ++ prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); ++#endif ++ ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ prBowFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChAbort) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ return; ++ } ++ ++ prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prMsgChAbort->ucTokenID = prBowFsmInfo->ucSeqNumOfChReq; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); ++ } ++ ++} /* end of aisFsmReleaseCh() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [TIMEOUT]\n"); ++#endif ++#if 1 ++ /* bowReleaseCh(prAdapter); */ ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ /*If connecting is not completed, request CH again */ ++ if ((eFsmState == BOW_DEVICE_STATE_CONNECTING) || (eFsmState == BOW_DEVICE_STATE_STARTING)) ++ bowRequestCh(prAdapter); ++#endif ++} ++ ++BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucBowTableIdx = 0; ++ CMD_INFO_T rCmdInfo; ++ ++ ASSERT(prAdapter); ++ ++ kalMemZero(&rCmdInfo, sizeof(CMD_INFO_T)); ++ ++ while (ucBowTableIdx < CFG_BOW_PHYSICAL_LINK_NUM) { ++ if (arBowTable[ucBowTableIdx].fgIsValid) { ++ COPY_MAC_ADDR(prAdapter->rWifiVar.rBowFsmInfo.aucPeerAddress, ++ arBowTable[ucBowTableIdx].aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowNotifyAllLinkDisconnected, arBowTable[%x].aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ ucBowTableIdx, arBowTable[ucBowTableIdx].aucPeerAddress[0], ++ arBowTable[ucBowTableIdx].aucPeerAddress[1], ++ arBowTable[ucBowTableIdx].aucPeerAddress[2], ++ arBowTable[ucBowTableIdx].aucPeerAddress[3], ++ arBowTable[ucBowTableIdx].aucPeerAddress[4], ++ arBowTable[ucBowTableIdx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "bowNotifyAllLinkDisconnected, arBowTable[%x].fgIsValid, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++#endif ++#if 1 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#else ++ wlanbowCmdEventLinkDisconnected(prAdapter, &rCmdInfo, NULL); ++#endif ++ } ++ ++ ucBowTableIdx += 1; ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++ ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ return FALSE; ++} ++ ++BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ if (arBowTable[ucBowTableIdx].fgIsValid) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowGetBowTableContent, arBowTable[idx].fgIsValid, %x, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++ DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[ucBowTableIdx].eState); ++#endif ++ prBowTable = &(arBowTable[ucBowTableIdx]); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return TRUE; ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ COPY_MAC_ADDR(arBowTable[ucBowTableIdx].aucPeerAddress, prBowTable->aucPeerAddress); ++ arBowTable[ucBowTableIdx].eState = prBowTable->eState; ++ arBowTable[ucBowTableIdx].fgIsValid = prBowTable->fgIsValid; ++ arBowTable[ucBowTableIdx].ucAcquireID = prBowTable->ucAcquireID; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ kalSetBowState(prAdapter->prGlueInfo, prBowTable->eState, prBowTable->aucPeerAddress); ++ /* kalSetBowRole(prAdapter->prGlueInfo, prBowTable->ucRole, prBowTable->aucPeerAddress); */ ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "SET State [%d]\n", arBowTable[ucBowTableIdx].eState); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[ucBowTableIdx].fgIsValid, %x, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++#endif ++ ++ return TRUE; ++ ++} ++ ++BOOLEAN ++bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ *pucBowTableIdx = idx; ++ ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (!arBowTable[idx].fgIsValid) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowGetBowTableFreeEntry, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++#endif ++ *pucBowTableIdx = idx; ++ arBowTable[idx].fgIsValid = TRUE; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowGetState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowGetState, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], ++ arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], ++ arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "bowGetState, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid); ++ DBGLOG(BOW, EVENT, ++ "bowGetState, arBowTable[idx].eState;, %x, %x.\n", idx, arBowTable[idx].eState); ++ DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[idx].eState); ++#endif ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return arBowTable[idx].eState; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState) ++{ ++ UINT_8 ucBowTableIdx; ++ ++ if (bowGetBowTableEntryByPeerAddress(prAdapter, aucPeerAddress, &ucBowTableIdx)) { ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ arBowTable[ucBowTableIdx].eState = eState; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "SET State [%d]\n", eState); ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ kalSetBowState(prAdapter->prGlueInfo, eState, aucPeerAddress); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c +new file mode 100644 +index 000000000000..1c59f861047e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c +@@ -0,0 +1,6240 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_lib.c#2 ++*/ ++/*! \file wlan_lib.c ++ \brief Internal driver stack will export the required procedures here for GLUE Layer. ++ ++ This file contains all routines which are exported from MediaTek 802.11 Wireless ++ LAN driver stack to GLUE Layer. ++*/ ++ ++/* ++** Log: wlan_lib.c ++** ++** 08 15 2012 eason.tsai ++** [ALPS00338170] [Need Patch] [Volunteer Patch] modify build warning ++** fix build waring for codechange ++ * ++ * 07 13 2012 cp.wu ++ * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for termination ++ * after SDIO error has happened ++ * [driver domain] add force reset by host-to-device interrupt mechanism ++ * ++ * 06 11 2012 cp.wu ++ * [WCXRP00001252] [MT6620 Wi-Fi][Driver] Add debug message while encountering firmware response timeout ++ * output message while timeout event occurs ++ * ++ * 06 11 2012 eason.tsai ++ * NULL ++ * change from binay to hex code ++ * ++ * 06 08 2012 eason.tsai ++ * NULL ++ * Nvram context covert from 6620 to 6628 for old 6620 meta tool ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 04 2012 eason.tsai ++ * NULL ++ * modify the cal fail report code. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band ++ * configuration with corresponding network configuration correct scan result removing policy. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with ++ * corresponding network configuration add wlanSetPreferBandByNetwork() for glue layer to invoke ++ * for setting preferred band configuration corresponding to network type. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment ++ * when returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 11 14 2011 cm.chang ++ * [WCXRP00001104] [All Wi-Fi][FW] Show init process by HW mail-box register ++ * Show FW initial ID when timeout to wait for ready bit ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 10 18 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * when powering off, always clear pending interrupts, then wait for RDY to be de-asserted ++ * ++ * 10 14 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * shorten the packet length for firmware download if no more than 2048 bytes. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 20 2011 cp.wu ++ * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized ++ * 1. always show error message for SDIO bus errors. ++ * 2. reset bus error flag when re-initialization ++ * ++ * 08 26 2011 cm.chang ++ * [WCXRP00000952] [MT5931 Wi-Fi][FW] Handshake with BWCS before DPD/TX power calibration ++ * Fix compiling error for WinXP MT5931 driver ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS Sync ready for WinXP. ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 19 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * escape from normal path if any error is occurred. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a ++ * disconnecting device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 24 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * if there is no valid address in chip, generate a new one from driver domain instead of firmware domain ++ * due to sufficient randomness ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * disable whole-chip resetting mechanism due to the need of further ECO to work as expected. ++ * ++ * 05 31 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * changed to use non-zero checking for valid bit in NVRAM content ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain ++ * pass PHY_PARAM in NVRAM from driver to firmware. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * correct assertion. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 05 11 2011 cm.chang ++ * [WCXRP00000717] [MT5931 Wi-Fi][Driver] Handle wrong NVRAM content about AP bandwidth setting ++ * . ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * change delay from 100ms to 120ms upon DE's suggestion. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 22 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space ++ * process for RESET_START and RESET_END events skip power-off handshaking when RESET indication is received. ++ * ++ * 04 22 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * . ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 04 15 2011 cp.wu ++ * [WCXRP00000654] [MT6620 Wi-Fi][Driver] Add loop termination criterion for wlanAdapterStop(). ++ * add loop termination criteria for wlanAdapterStop(). ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing ++ * frame dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure ++ * happend inside wlanAdapterStart invoke nicReleaseAdapterMemory() as failure handling in case ++ * wlanAdapterStart() failed unexpectedly ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error ++ * fixed the kclocwork error. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically ++ * continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 02 25 2011 cp.wu ++ * [WCXRP00000496] [MT5931][Driver] Apply host-triggered chip reset before initializing firmware download procedures ++ * apply host-triggered chip reset mechanism before initializing firmware download procedures. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 01 2011 george.huang ++ * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers ++ * init variable for CTIA. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the ++ * corresponding BSS is disconnected due to beacon timeout remove from scanning result when the BSS ++ * is disconnected due to beacon timeout. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ++ * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous ++ * and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * while being unloaded, clear all pending interrupt then set LP-own to firmware ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay ++ * to avoid blocking to system scheduling change to use msleep() and shorten waiting interval ++ * to reduce blocking to other task while Wi-Fi driver is being loaded ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 22 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Remove controling auto rate from initial setting. The initial setting is defined by FW code. ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * sync. with ALPS code by enabling interrupt just before leaving wlanAdapterStart() ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * Change Param name for invitation connection. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 03 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) use 8 buffers for MT5931 which is equipped with less memory ++ * 2) modify MT5931 debug level to TRACE when download is successful ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * for MT5931, adapter initialization is done *after* firmware is downloaded. ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * correct MT5931 firmware download procedure: ++ * MT5931 will download firmware first then acquire LP-OWN ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) update MT5931 firmware encryption tool. (using 64-bytes unit) ++ * 2) update MT5931 firmware download procedure ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying ++ * current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function ++ * for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add option for enable/disable TX PWR gain adjustment (default: off) ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 15 2010 cp.wu ++ * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A ++ * bugfix: always reset pointer to IEbuf to zero when keeping scanning result for the connected AP ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with ++ * AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * acquire & release power control in oid handing wrapper. ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * move IE to buffer head when the IE pointer is not pointed at head. ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 13 2010 cp.wu ++ * NULL ++ * correction issue: desired phy type not initialized as ABGN mode. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 10 2010 cm.chang ++ * NULL ++ * Support EEPROM read/write in RF test mode ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 13 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Reduce unnecessary type casting ++ * ++ * 07 13 2010 cp.wu ++ * ++ * use multiple queues to keep 1x/MMPDU/CMD's strict order even when there is incoming 1x frames. ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent ++ * network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * initialize mbox & ais_fsm in wlanAdapterStart() ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * simplify timer usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable interrupt then send power control command packet. ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when stopping adapter, wait til RDY bit has been cleaerd. ++ * 2) set TASK_OFFLOAD as driver-core OIDs ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * roll-back to rev.60. ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove redundant firmware image unloading ++ * 2) use compile-time macros to separate logic related to accquiring own ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always set fw-own before driver is unloaded. ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * 2) command sequence number is now increased atomically ++ * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * 2) add 2 kal API for later integration ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) eliminate unused definitions ++ * 2) ready bit will be polled for limited iteration ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * kalOidComplete is not necessary in linux ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use pass-in prRegInfo instead of accessing prGlueInfo directly ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding none-glue code portability ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding non-glue code portability ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve non-glue code portability ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * due to the different configurations on FPGA and ASIC ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * only send CMD_NIC_POWER_CTRL in wlanAdapterStop() when card is not removed and is not in D3 state ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++* 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when starting adapter, read local adminsitrated address from registry and send to firmware via CMD_BASIC_CONFIG. ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 03 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add command/event definitions for initial states ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for QM_TEST_MODE ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct function name .. ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * separate wlanProcesQueuePacket() into 2 APIs upon request ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct wlanAdapterStart ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * 2) firmware image length is now retrieved via NdisFileOpen ++ * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * 4) nicRxWaitResponse() revised ++ * 5) another set of TQ counter default value is added for fw-download state ++ * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * 2. follow MSDN defined behavior when associates to another AP ++ * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * wlanoidSetFrequency is now implemented by RF test command. ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * QueryRssi is no longer w/o hardware access, it is now implemented by command/event handling loop ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. clear prPendingCmdInfo properly ++ * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. ++ * ++ * 01 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * allow MCR read/write OIDs in RF test mode ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * 2. block TX/ordinary OID when RF test mode is engaged ++ * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * 4. correct some HAL implementation ++ * ++ * 01 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-12-10 16:54:36 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-12-09 20:04:59 GMT mtk02752 ++** only report as connected when CFG_HIF_EMULATION_TEST is set to 1 ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-12-08 17:39:41 GMT mtk02752 ++** wlanoidRftestQueryAutoTest could be executed without touching hardware ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-12-03 16:10:26 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-02 22:05:33 GMT mtk02752 ++** kalOidComplete() will decrease i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-01 23:02:36 GMT mtk02752 ++** remove unnecessary spinlock ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-01 22:50:38 GMT mtk02752 ++** use TC4 for command, maintein i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-27 12:45:34 GMT mtk02752 ++** prCmdInfo should be freed when invoking wlanReleasePendingOid() to clear pending oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-24 19:55:51 GMT mtk02752 ++** wlanSendPacket & wlanRetransmitOfPendingFrames is only used in old data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-23 17:59:55 GMT mtk02752 ++** clear prPendingOID inside wlanSendCommand() when the OID didn't need to be replied. ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-23 14:45:29 GMT mtk02752 ++** add another version of wlanSendCommand() for command-sending only without blocking for response ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-17 22:40:44 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 10:14:56 GMT mtk01084 ++** modify place to invoke wlanIst ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-10-30 18:17:07 GMT mtk01084 ++** fix compiler warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-10-29 19:46:15 GMT mtk01084 ++** invoke interrupt process routine ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-10-13 21:58:24 GMT mtk01084 ++** modify for new HW architecture ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-09-09 17:26:01 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-05-20 12:21:27 GMT mtk01461 ++** Add SeqNum check when process Event Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-05-19 10:38:44 GMT mtk01461 ++** Add wlanReleasePendingOid() for mpReset() if there is a pending OID and no available TX resource to send it. ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-04-29 15:41:34 GMT mtk01461 ++** Add handle of EVENT of CMD Result in wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-04-22 09:11:23 GMT mtk01461 ++** Fix wlanSendCommand() for Driver Domain CR ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-04-21 09:33:56 GMT mtk01461 ++** Update wlanSendCommand() for Driver Domain Response and handle Event Packet, ++** wlanQuery/SetInformation() for enqueue CMD_INFO_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-17 20:00:08 GMT mtk01461 ++** Update wlanImageSectionDownload for optimized CMD process ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-14 20:50:51 GMT mtk01426 ++** Fixed compile error ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-13 16:38:40 GMT mtk01084 ++** add wifi start function ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-13 14:26:44 GMT mtk01084 ++** modify a parameter about FW download length ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-10 21:53:42 GMT mtk01461 ++** Update wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-08 16:51:04 GMT mtk01084 ++** Update for the image download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-01 10:32:47 GMT mtk01461 ++** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-03-23 21:44:13 GMT mtk01461 ++** Refine TC assignment for WmmAssoc flag ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 16:51:57 GMT mtk01084 ++** modify the input argument of caller to RECLAIM_POWER_CONTROL_TO_PM() ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:27:13 GMT mtk01461 ++** Add reference code of FW Image Download ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:37 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:08 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 16:28:45 GMT mtk01426 ++** Init develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++#include "mgmt/ais_fsm.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */ ++/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to Traffic Class */ ++const UINT_8 aucPriorityParam2TC[] = { ++ TC1_INDEX, ++ TC0_INDEX, ++ TC0_INDEX, ++ TC1_INDEX, ++ TC2_INDEX, ++ TC2_INDEX, ++ TC3_INDEX, ++ TC3_INDEX ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _CODE_MAPPING_T { ++ UINT_32 u4RegisterValue; ++ INT_32 i4TxpowerOffset; ++} CODE_MAPPING_T, *P_CODE_MAPPING_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++BOOLEAN fgIsBusAccessFailed = FALSE; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SIGNED_EXTEND(n, _sValue) \ ++ (((_sValue) & BIT((n)-1)) ? ((_sValue) | BITS(n, 31)) : \ ++ ((_sValue) & ~BITS(n, 31))) ++ ++/* TODO: Check */ ++/* OID set handlers without the need to access HW register */ ++PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = { ++ wlanoidSetChannel, ++ wlanoidSetBeaconInterval, ++ wlanoidSetAtimWindow, ++ wlanoidSetFrequency, ++}; ++ ++/* TODO: Check */ ++/* OID query handlers without the need to access HW register */ ++PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = { ++ wlanoidQueryBssid, ++ wlanoidQuerySsid, ++ wlanoidQueryInfrastructureMode, ++ wlanoidQueryAuthMode, ++ wlanoidQueryEncryptionStatus, ++ wlanoidQueryPmkid, ++ wlanoidQueryNetworkTypeInUse, ++ wlanoidQueryBssidList, ++ wlanoidQueryAcpiDevicePowerState, ++ wlanoidQuerySupportedRates, ++ wlanoidQueryDesiredRates, ++ wlanoidQuery802dot11PowerSaveProfile, ++ wlanoidQueryBeaconInterval, ++ wlanoidQueryAtimWindow, ++ wlanoidQueryFrequency, ++}; ++ ++/* OID set handlers allowed in RF test mode */ ++PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = { ++ wlanoidRftestSetTestMode, ++ wlanoidRftestSetAbortTestMode, ++ wlanoidRftestSetAutoTest, ++ wlanoidSetMcrWrite, ++ wlanoidSetEepromWrite ++}; ++ ++/* OID query handlers allowed in RF test mode */ ++PFN_OID_HANDLER_FUNC apfnOidQueryHandlerAllowedInRFTest[] = { ++ wlanoidRftestQueryAutoTest, ++ wlanoidQueryMcrRead, ++ wlanoidQueryEepromRead ++} ++ ++; ++ ++PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = { ++ wlanoidRftestSetTestMode, ++ wlanoidRftestSetAbortTestMode, ++ wlanoidSetAcpiDevicePowerState, ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 /* no use */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is a private routine, which is used to check if HW access is needed ++* for the OID query/ set handlers. ++* ++* \param[IN] pfnOidHandler Pointer to the OID handler. ++* \param[IN] fgSetInfo It is a Set information handler. ++* ++* \retval TRUE This function needs HW access ++* \retval FALSE This function does not need HW access ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerWOHwAccess; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ if (fgSetInfo) { ++ apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess; ++ u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); ++ } else { ++ apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess; ++ u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); ++ } ++ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler) ++ return FALSE; ++ } ++ ++ return TRUE; ++} /* wlanIsHandlerNeedHwAccess */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set flag for later handling card ++* ejected event. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++* ++* \note When surprised removal happens, Glue layer should invoke this ++* function to notify WPDD not to do any hw access. ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanCardEjected(IN P_ADAPTER_T prAdapter) ++{ ++ DEBUGFUNC("wlanCardEjected"); ++ /* INITLOG(("\n")); */ ++ ++ ASSERT(prAdapter); ++ ++ /* mark that the card is being ejected, NDIS will shut us down soon */ ++ nicTxRelease(prAdapter); ++ ++} /* wlanCardEjected */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Create adapter object ++* ++* \param prAdapter This routine is call to allocate the driver software objects. ++* If fails, return NULL. ++* \retval NULL If it fails, NULL is returned. ++* \retval NOT NULL If the adapter was initialized successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_ADAPTER_T prAdpater = (P_ADAPTER_T) NULL; ++ ++ DEBUGFUNC("wlanAdapterCreate"); ++ ++ do { ++ prAdpater = (P_ADAPTER_T) kalMemAlloc(sizeof(ADAPTER_T), VIR_MEM_TYPE); ++ ++ if (!prAdpater) { ++ DBGLOG(INIT, ERROR, "Allocate ADAPTER memory ==> FAILED\n"); ++ break; ++ } ++ ++ kalMemZero(prAdpater, sizeof(ADAPTER_T)); ++ prAdpater->prGlueInfo = prGlueInfo; ++ ++ } while (FALSE); ++ ++ return prAdpater; ++} /* wlanAdapterCreate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Destroy adapter object ++* ++* \param prAdapter This routine is call to destroy the driver software objects. ++* If fails, return NULL. ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ ++ if (!prAdapter) ++ return; ++ ++ kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initialize the adapter. The sequence is ++* 1. Disable interrupt ++* 2. Read adapter configuration from EEPROM and registry, verify chip ID. ++* 3. Create NIC Tx/Rx resource. ++* 4. Initialize the chip ++* 5. Initialize the protocol ++* 6. Enable Interrupt ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanAdapterStart(IN P_ADAPTER_T prAdapter, ++ IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 i, u4Value = 0; ++ UINT_32 u4WHISR = 0; ++ UINT_8 aucTxCount[8]; ++#if CFG_ENABLE_FW_DOWNLOAD ++ UINT_32 u4FwLoadAddr, u4ImgSecSize; ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ UINT_32 j; ++ P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; ++ BOOLEAN fgValidHead; ++ const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); ++#endif ++#endif ++ enum Adapter_Start_Fail_Reason { ++ ALLOC_ADAPTER_MEM_FAIL, ++ DRIVER_OWN_FAIL, ++ INIT_ADAPTER_FAIL, ++ RAM_CODE_DOWNLOAD_FAIL, ++ WAIT_FIRMWARE_READY_FAIL, ++ FAIL_REASON_MAX ++ } eFailReason; ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanAdapterStart"); ++ ++ eFailReason = FAIL_REASON_MAX; ++ /* 4 <0> Reset variables in ADAPTER_T */ ++ prAdapter->fgIsFwOwn = TRUE; ++ prAdapter->fgIsEnterD3ReqIssued = FALSE; ++ ++ QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue)); ++ ++ /* Initialize rWlanInfo */ ++ kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); ++ ++ /* 4 <0.1> reset fgIsBusAccessFailed */ ++ fgIsBusAccessFailed = FALSE; ++ prAdapter->ulSuspendFlag = 0; ++ ++ do { ++ u4Status = nicAllocateAdapterMemory(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicAllocateAdapterMemory Error!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = ALLOC_ADAPTER_MEM_FAIL; ++ break; ++ } ++ ++ prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; ++ ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): Acquiring LP-OWN %d\n", fgIsResetting); ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++#if !CFG_ENABLE_FULL_PM ++ nicpmSetDriverOwn(prAdapter); ++#endif ++ ++ if (prAdapter->fgIsFwOwn == TRUE) { ++ DBGLOG(INIT, ERROR, "nicpmSetDriverOwn() failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = DRIVER_OWN_FAIL; ++ break; ++ } ++ /* 4 <1> Initialize the Adapter */ ++ u4Status = nicInitializeAdapter(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicInitializeAdapter failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = INIT_ADAPTER_FAIL; ++ break; ++ } ++ ++ /* init wake lock before interrupt enable and tx thread */ ++ KAL_WAKE_LOCK_INIT(prAdapter, &prAdapter->rTxThreadWakeLock, "WLAN TX THREAD"); ++ ++ /* 4 <2> Initialize System Service (MGMT Memory pool and STA_REC) */ ++ nicInitSystemService(prAdapter); ++ ++ /* 4 <3> Initialize Tx */ ++ nicTxInitialize(prAdapter); ++ wlanDefTxPowerCfg(prAdapter); ++ ++ /* 4 <4> Initialize Rx */ ++ nicRxInitialize(prAdapter); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ if (pvFwImageMapFile == NULL) { ++ DBGLOG(INIT, ERROR, "No Firmware found!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = RAM_CODE_DOWNLOAD_FAIL; ++ break; ++ } ++ ++ /* 1. disable interrupt, download is done by polling mode only */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 2. Initialize Tx Resource to fw download state */ ++ nicTxInitResetResource(prAdapter); ++ ++ /* 3. FW download here */ ++ u4FwLoadAddr = prRegInfo->u4LoadAddress; ++ ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ /* 3a. parse file header for decision of divided firmware download or not */ ++ prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; ++ ++ if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && ++ prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, ++ u4FwImageFileLength - u4CRCOffset)) { ++ fgValidHead = TRUE; ++ } else { ++ fgValidHead = FALSE; ++ } ++ ++ /* 3b. engage divided firmware downloading */ ++ if (fgValidHead == TRUE) { ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): fgValidHead == TRUE\n"); ++ ++ for (i = 0; i < prFwHead->u4NumOfEntries; i++) { ++ ++#if CFG_START_ADDRESS_IS_1ST_SECTION_ADDR ++ if (i == 0) { ++ prRegInfo->u4StartAddress = prFwHead->arSection[i].u4DestAddr; ++ DBGLOG(INIT, TRACE, ++ "wlanAdapterStart(): FW start address 0x%08x\n", ++ prRegInfo->u4StartAddress); ++ } ++#endif ++ ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ prFwHead->arSection[i].u4DestAddr, ++ prFwHead->arSection[i].u4Length, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = prFwHead->arSection[i].u4Length - j; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ prFwHead->arSection[i].u4DestAddr + j, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset + j) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, ++ "Firmware scatter download failed %d!\n", (int)i); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ /* escape from loop if any pending error occurs */ ++ if (u4Status == WLAN_STATUS_FAILURE) ++ break; ++ } ++ } else ++#endif ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ u4FwLoadAddr, ++ u4FwImageFileLength, ++ (PUINT_8) pvFwImageMapFile) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (i = 0; i < u4FwImageFileLength; i += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImageFileLength) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = u4FwImageFileLength - i; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ u4FwLoadAddr + i, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + i) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ eFailReason = RAM_CODE_DOWNLOAD_FAIL; ++ break; ++ } ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ ++ if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++#endif ++ ++ /* 4. send Wi-Fi Start command */ ++ DBGLOG(INIT, INFO, " send Wi-Fi Start command\n"); ++#if CFG_OVERRIDE_FW_START_ADDRESS ++ wlanConfigWifiFunc(prAdapter, TRUE, prRegInfo->u4StartAddress); ++#else ++ wlanConfigWifiFunc(prAdapter, FALSE, 0); ++#endif ++#endif ++ ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); ++ /* 4 <5> check Wi-Fi FW asserts ready bit */ ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ DBGLOG(INIT, TRACE, "Ready bit asserted\n"); ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ UINT_32 u4MailBox0; ++ ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ DBGLOG(INIT, ERROR, "Waiting for Ready bit: Timeout, ID=%u\n", ++ (u4MailBox0 & 0x0000FFFF)); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* 1. reset interrupt status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ ++ /* 2. reset TX Resource for normal operation */ ++ nicTxResetResource(prAdapter); ++ ++ /* 3. query for permanent address by polling */ ++ wlanQueryPermanentAddress(prAdapter); ++ ++#if (CFG_SUPPORT_NIC_CAPABILITY == 1) ++ /* 4. query for NIC capability */ ++ wlanQueryNicCapability(prAdapter); ++#endif ++ /* 4.1 query for compiler flags */ ++ wlanQueryCompileFlags(prAdapter); ++ ++ /* 5. Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++ /* 6. indicate disconnection as default status */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } ++ ++ /* OID timeout timer initialize */ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rOidTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) wlanReleasePendingOid, (ULONG) NULL); ++ ++ /* Return Indicated Rfb list timer */ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rReturnIndicatedRfbListTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) wlanReturnIndicatedPacketsTimeOut, (ULONG) NULL); ++ ++ /* Power state initialization */ ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ prAdapter->rAcpiState = ACPI_STATE_D0; ++ ++ /* Online scan option */ ++ if (prRegInfo->fgDisOnlineScan == 0) ++ prAdapter->fgEnOnlineScan = TRUE; ++ else ++ prAdapter->fgEnOnlineScan = FALSE; ++ ++ /* Beacon lost detection option */ ++ if (prRegInfo->fgDisBcnLostDetection != 0) ++ prAdapter->fgDisBcnLostDetection = TRUE; ++ ++ /* Load compile time constant */ ++ prAdapter->rWlanInfo.u2BeaconPeriod = CFG_INIT_ADHOC_BEACON_INTERVAL; ++ prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW; ++ ++#if 1 /* set PM parameters */ ++ prAdapter->fgEnArpFilter = prRegInfo->fgEnArpFilter; ++ prAdapter->u4PsCurrentMeasureEn = prRegInfo->u4PsCurrentMeasureEn; ++ ++ prAdapter->u4UapsdAcBmp = prRegInfo->u4UapsdAcBmp; ++ ++ prAdapter->u4MaxSpLen = prRegInfo->u4MaxSpLen; ++ ++ DBGLOG(INIT, TRACE, "[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x", ++ prAdapter->fgEnArpFilter, prAdapter->u4UapsdAcBmp, prAdapter->u4MaxSpLen); ++ ++ prAdapter->fgEnCtiaPowerMode = FALSE; ++ ++#if CFG_SUPPORT_DBG_POWERMODE ++ prAdapter->fgEnDbgPowerMode = FALSE; ++#endif ++ ++#endif ++ ++ /* MGMT Initialization */ ++ nicInitMGMT(prAdapter, prRegInfo); ++ ++ /* Enable WZC Disassociation */ ++ prAdapter->rWifiVar.fgSupportWZCDisassociation = TRUE; ++ ++ /* Apply Rate Setting */ ++ if ((ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate) < FIXED_RATE_NUM) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate); ++ else ++ prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; ++ ++ if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { ++ /* Enable Auto (Long/Short) Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; ++ } else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) ++ || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) { ++ /* Force Short Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; ++ } else { ++ /* Force Long Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; ++ } ++ ++ /* Disable Hidden SSID Join */ ++ prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = FALSE; ++ ++ /* Enable Short Slot Time */ ++ prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = TRUE; ++ ++ /* configure available PHY type set */ ++ nicSetAvailablePhyTypeSet(prAdapter); ++ ++#if 1 /* set PM parameters */ ++ { ++#if CFG_SUPPORT_PWR_MGT ++ prAdapter->u4PowerMode = prRegInfo->u4PowerMode; ++ prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucNetTypeIndex = ++ NETWORK_TYPE_P2P_INDEX; ++ prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile = ENUM_PSP_FAST_SWITCH; ++#else ++ prAdapter->u4PowerMode = ENUM_PSP_CONTINUOUS_ACTIVE; ++#endif ++ ++ nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, /* FIXIT */ ++ prAdapter->u4PowerMode, FALSE); ++ } ++ ++#endif ++ ++#if CFG_SUPPORT_NVRAM ++ /* load manufacture data */ ++ wlanLoadManufactureData(prAdapter, prRegInfo); ++#endif ++ ++#ifdef CONFIG_MTK_TC1_FEATURE /* 1 //keep alive packet time change from default 30secs to 20secs. //TC01// */ ++ { ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ ++ rCmdSwCtrl.u4Id = 0x90100000; ++ rCmdSwCtrl.u4Data = 30; ++ DBGLOG(INIT, TRACE, "wlanAdapterStart Keepaliveapcket 0x%x, %d\n", ++ rCmdSwCtrl.u4Id, rCmdSwCtrl.u4Data); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8) (&rCmdSwCtrl), NULL, 0); ++ } ++#endif ++ ++#if 0 ++ /* Update Auto rate parameters in FW */ ++ nicRlmArUpdateParms(prAdapter, ++ prRegInfo->u4ArSysParam0, ++ prRegInfo->u4ArSysParam1, prRegInfo->u4ArSysParam2, prRegInfo->u4ArSysParam3); ++#endif ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ /* clock gating workaround */ ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++#endif ++ ++ } while (FALSE); ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* restore to hardware default */ ++ HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter); ++ HAL_SET_MAILBOX_READ_CLEAR(prAdapter, FALSE); ++ ++ /* Enable interrupt */ ++ nicEnableInterrupt(prAdapter); ++ ++ } else { ++ /* release allocated memory */ ++ switch (eFailReason) { ++ case WAIT_FIRMWARE_READY_FAIL: ++ DBGLOG(INIT, ERROR, "Wait firmware ready fail, FailReason: %d\n", ++ eFailReason); ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Wait firmware ready fail!]", __func__); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ nicRxUninitialize(prAdapter); ++ nicTxRelease(prAdapter); ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case RAM_CODE_DOWNLOAD_FAIL: ++ DBGLOG(INIT, ERROR, "Ram code download fail, FailReason: %d\n", ++ eFailReason); ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Ram code download fail!]", __func__); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ nicRxUninitialize(prAdapter); ++ nicTxRelease(prAdapter); ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case INIT_ADAPTER_FAIL: ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case DRIVER_OWN_FAIL: ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case ALLOC_ADAPTER_MEM_FAIL: ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return u4Status; ++} /* wlanAdapterStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Uninitialize the adapter ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4Value = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ /* MGMT - unitialization */ ++ nicUninitMGMT(prAdapter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D0 && ++#if (CFG_CHIP_RESET_SUPPORT == 1) ++ kalIsResetting() == FALSE && ++#endif ++ kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { ++ ++ /* 0. Disable interrupt, this can be done without Driver own */ ++ nicDisableInterrupt(prAdapter); ++ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* 1. Set CMD to FW to tell WIFI to stop (enter power off state) */ ++ /* the command must be issue to firmware even in wlanRemove() */ ++ if (prAdapter->fgIsFwOwn == FALSE && wlanSendNicPowerCtrlCmd(prAdapter, 1) == WLAN_STATUS_SUCCESS) { ++ /* 2. Clear pending interrupt */ ++ i = 0; ++ while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ i++; ++ }; ++ ++ /* 3. Wait til RDY bit has been cleaerd */ ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if ((u4Value & WCIR_WLAN_READY) == 0) ++ break; ++ else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE ++ || fgIsBusAccessFailed == TRUE || i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Read WCIR_WLAN_READY fail!]", __func__); ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ } ++ ++ /* 4. Set Onwership to F/W */ ++ nicpmSetFWOwn(prAdapter, FALSE); ++ ++#if CFG_FORCE_RESET_UNDER_BUS_ERROR ++ if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == TRUE) { ++ /* force acquire firmware own */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ ++ /* delay for 10ms */ ++ kalMdelay(10); ++ ++ /* force firmware reset via software interrupt */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, WSICR_H2D_SW_INT_SET); ++ ++ /* force release firmware own */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ } ++#endif ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } ++ ++ nicRxUninitialize(prAdapter); ++ ++ nicTxRelease(prAdapter); ++ ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ ++ nicReleaseAdapterMemory(prAdapter); ++ ++#if defined(_HIF_SPI) ++ /* Note: restore the SPI Mode Select from 32 bit to default */ ++ nicRestoreSpiDefMode(prAdapter); ++#endif ++ ++ return u4Status; ++} /* wlanAdapterStop */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by ISR (interrupt). ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval TRUE: NIC's interrupt ++* \retval FALSE: Not NIC's interrupt ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl) ++{ ++ ASSERT(prAdapter); ++ ++ if (fgGlobalIntrCtrl) { ++ nicDisableInterrupt(prAdapter); ++ ++ /* wlanIST(prAdapter); */ ++ } ++ ++ return TRUE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by IST (task_let). ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanIST(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* wake up CONNSYS */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* handle interrupts */ ++ nicProcessIST(prAdapter); ++ ++ /* re-enable HIF interrupts */ ++ nicEnableInterrupt(prAdapter); ++ ++ /* CONNSYS can decide to sleep */ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will check command queue to find out if any could be dequeued ++* and/or send to HIF to MT6620 ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param prCmdQue Pointer of Command Queue (in Glue Layer) ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue) ++{ ++ WLAN_STATUS rStatus; ++ QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue; ++ P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue; ++ P_QUE_ENTRY_T prQueueEntry; ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(prCmdQue); ++ ++ /* init */ ++ prTempCmdQue = &rTempCmdQue; ++ prMergeCmdQue = &rMergeCmdQue; ++ prStandInCmdQue = &rStandInCmdQue; ++ ++ QUEUE_INITIALIZE(prTempCmdQue); ++ QUEUE_INITIALIZE(prMergeCmdQue); ++ QUEUE_INITIALIZE(prStandInCmdQue); ++ ++ /* 4 <1> Move whole list of CMD_INFO to the temp queue */ ++ /* copy all commands to prTempCmdQue and empty prCmdQue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ /* 4 <2> Dequeue from head and check it is able to be sent */ ++ /* remove the first one */ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ /* check how to handle the command: drop, queue, or tx */ ++ switch (prCmdInfo->eCmdType) { ++ case COMMAND_TYPE_GENERAL_IOCTL: ++ case COMMAND_TYPE_NETWORK_IOCTL: ++ /* command packet will be always sent */ ++ eFrameAction = FRAME_ACTION_TX_PKT; ++ break; ++ ++ case COMMAND_TYPE_SECURITY_FRAME: ++ /* inquire with QM */ ++ eFrameAction = qmGetFrameAction(prAdapter, ++ prCmdInfo->eNetworkType, ++ prCmdInfo->ucStaRecIndex, NULL, FRAME_TYPE_802_1X); ++ break; ++ ++ case COMMAND_TYPE_MANAGEMENT_FRAME: ++ /* inquire with QM */ ++ prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); ++ ++ eFrameAction = qmGetFrameAction(prAdapter, ++ prMsduInfo->ucNetworkType, ++ prMsduInfo->ucStaRecIndex, prMsduInfo, FRAME_TYPE_MMPDU); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ /* 4 <3> handling upon dequeue result */ ++ if (eFrameAction == FRAME_ACTION_DROP_PKT) { ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) ++ DBGLOG(TX, WARN, "Drop Security frame seqNo=%d\n", ++ prCmdInfo->ucCmdSeqNum); ++ wlanReleaseCommand(prAdapter, prCmdInfo); ++ } else if (eFrameAction == FRAME_ACTION_QUEUE_PKT) { ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) ++ DBGLOG(TX, INFO, "Queue Security frame seqNo=%d\n", ++ prCmdInfo->ucCmdSeqNum); ++ QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); ++ } else if (eFrameAction == FRAME_ACTION_TX_PKT) { ++ /* 4 <4> Send the command */ ++ rStatus = wlanSendCommand(prAdapter, prCmdInfo); ++ ++ if (rStatus == WLAN_STATUS_RESOURCES) { ++ /* no more TC4 resource for further transmission */ ++ QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); ++ DBGLOG(TX, EVENT, "No TC4 resource to send cmd, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", ++ prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, ++ prCmdInfo->eCmdType, prCmdInfo->fgIsOid); ++ break; ++ } else if (rStatus == WLAN_STATUS_PENDING) { ++ /* command packet which needs further handling upon response */ ++ /* i.e. we need to wait for FW's response */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), prQueueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ } else { ++ /* send success or fail */ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* send success */ ++ if (prCmdInfo->pfCmdDoneHandler) { ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, ++ prCmdInfo->pucInfoBuffer); ++ } ++ } else { ++ /* send fail */ ++ if (prCmdInfo->fgIsOid) { ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, rStatus); ++ } ++ DBGLOG(TX, WARN, "Send CMD, status=%u, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", ++ rStatus, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, ++ prCmdInfo->eCmdType, prCmdInfo->fgIsOid); ++ } ++ ++ /* free the command memory */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ } else { ++ ++ /* impossible, wrong eFrameAction */ ++ ASSERT(0); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ /* 4 <3> Merge back to original queue */ ++ /* 4 <3.1> Merge prMergeCmdQue & prTempCmdQue */ ++ QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue); ++ ++ /* 4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ due to incoming 802.1X frames */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ /* ??? here, prCmdQue shall be empty, why QUEUE_MOVE_ALL ??? */ ++ QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue); ++ ++ /* 4 <3.3> concatenate prStandInQue to prMergeCmdQue */ ++ QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue); ++ ++ /* 4 <3.4> then move prMergeCmdQue to prCmdQue */ ++ QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanProcessCommandQueue() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will take CMD_INFO_T which carry some information of ++* incoming OID and notify the NIC_TX to send CMD. ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param prCmdInfo Pointer of P_CMD_INFO_T ++* ++* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately. ++* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous ++* frame finishing their transmission. ++* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN pfgIsSecOrMgmt = FALSE; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* init */ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* DbgPrint("wlanSendCommand()\n"); */ ++ /* */ ++ /* */ ++#if DBG && 0 ++ LOG_FUNC("wlanSendCommand()\n"); ++ LOG_FUNC("CmdType %u NetworkType %u StaRecIndex %u Oid %u CID 0x%x SetQuery %u NeedResp %u CmdSeqNum %u\n", ++ prCmdInfo->eCmdType, ++ prCmdInfo->eNetworkType, ++ prCmdInfo->ucStaRecIndex, ++ prCmdInfo->fgIsOid, ++ prCmdInfo->ucCID, prCmdInfo->fgSetQuery, prCmdInfo->fgNeedResp, prCmdInfo->ucCmdSeqNum); ++#endif ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ do { ++ /* <0> card removal check */ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ rStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* <1> Normal case of sending CMD Packet */ ++ if (!prCmdInfo->fgDriverDomainMCR) { ++ /* <1.1> Assign Traffic Class(TC) = TC4. */ ++ ucTC = TC4_INDEX; ++ ++ if ((prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) || ++ (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME)) ++ pfgIsSecOrMgmt = TRUE; ++ ++ /* <1.2> Check if pending packet or resource was exhausted */ ++ rStatus = nicTxAcquireResource(prAdapter, ucTC, pfgIsSecOrMgmt); ++ if (rStatus == WLAN_STATUS_RESOURCES) { ++ DbgPrint("NO Resource:%d\n", ucTC); ++ break; ++ } ++ /* <1.3> Forward CMD_INFO_T to NIC Layer */ ++ rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC); ++ ++ /* <1.4> Set Pending in response to Query Command/Need Response */ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) ++ rStatus = WLAN_STATUS_PENDING; ++ } ++ } ++ /* <2> "Special case" for access Driver Domain MCR */ ++ else { ++ ++ P_CMD_ACCESS_REG prCmdAccessReg; ++ ++ prCmdAccessReg = (P_CMD_ACCESS_REG) (prCmdInfo->pucInfoBuffer + CMD_HDR_SIZE); ++ ++ if (prCmdInfo->fgSetQuery) { ++ /* address is in DWORD unit */ ++ HAL_MCR_WR(prAdapter, (prCmdAccessReg->u4Address & BITS(2, 31)), ++ prCmdAccessReg->u4Data); ++ } else { ++ P_CMD_ACCESS_REG prEventAccessReg; ++ UINT_32 u4Address; ++ ++ u4Address = prCmdAccessReg->u4Address; ++ prEventAccessReg = (P_CMD_ACCESS_REG) prCmdInfo->pucInfoBuffer; ++ prEventAccessReg->u4Address = u4Address; ++ /* address is in DWORD unit */ ++ HAL_MCR_RD(prAdapter, prEventAccessReg->u4Address & BITS(2, 31), ++ &prEventAccessReg->u4Data); ++ } ++ } ++ ++ } while (FALSE); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return rStatus; ++} /* end of wlanSendCommand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function will release thd CMD_INFO upon its attribution ++ * ++ * \param prAdapter Pointer of Adapter Data Structure ++ * \param prCmdInfo Pointer of CMD_INFO_T ++ * ++ * \return (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ switch (prCmdInfo->eCmdType) { ++ case COMMAND_TYPE_GENERAL_IOCTL: ++ case COMMAND_TYPE_NETWORK_IOCTL: ++ if (prCmdInfo->fgIsOid) { ++ /* for OID command, we need to do complete() to wake up kalIoctl() */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_FAILURE); ++ } ++ break; ++ ++ case COMMAND_TYPE_SECURITY_FRAME: ++ /* free packets in kalSecurityFrameSendComplete() */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); ++ break; ++ ++ case COMMAND_TYPE_MANAGEMENT_FRAME: ++ prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; ++ ++ /* invoke callbacks */ ++ if (prMsduInfo->pfTxDoneHandler != NULL) ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); ++ ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ break; ++ ++ default: ++ /* impossible, shall not be here */ ++ ASSERT(0); ++ break; ++ } ++ ++ /* free command buffer and return the command header to command pool */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++} /* end of wlanReleaseCommand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will search the CMD Queue to look for the pending OID and ++* compelete it immediately when system request a reset. ++* ++* \param prAdapter ointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("wlanReleasePendingOid"); ++ ++ ASSERT(prAdapter); ++ ++ DBGLOG(OID, ERROR, "OID Timeout! Releasing pending OIDs ..\n"); ++ ++ do { ++ /* 1: Handle OID commands in pending queue */ ++ /* Clear Pending OID in prAdapter->rPendingCmdQueue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ /* move all pending commands to prTempCmdQue and empty prCmdQue */ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ /* get first pending command */ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->fgIsOid) { ++ if (prCmdInfo->pfCmdTimeoutHandler) { ++ prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); ++ } else { ++ /* send complete() to wake up kalIoctl() */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++ } ++ ++ /* free command memory */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } else { ++ /* nothing to do so re-queue it to prCmdQue */ ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ /* 2: Clear pending OID staying in command queue */ ++ kalOidCmdClearance(prAdapter->prGlueInfo); ++ ++ /* 3: Do complete(), do we need this? because we have completed in kalOidComplete */ ++ kalOidClearance(prAdapter->prGlueInfo); ++ ++ } while (FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will search the CMD Queue to look for the pending CMD/OID for specific ++* NETWORK TYPE and compelete it immediately when system request a reset. ++* ++* \param prAdapter ointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* only free commands from the network interface, AIS, P2P, or BOW */ ++ ++ do { ++ /* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ DBGLOG(P2P, TRACE, "Pending CMD for Network Type:%d\n", prCmdInfo->eNetworkType); ++ ++ if (prCmdInfo->eNetworkType == eNetworkType) { ++ if (prCmdInfo->pfCmdTimeoutHandler) { ++ prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); ++ } else ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ } while (FALSE); ++ ++} /* wlanReleasePendingCMDbyNetwork */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the packet buffer and reallocate one to the RFB ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param pvPacket Pointer of returned packet ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("wlanReturnPacket"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* free the packet */ ++ if (pvPacket) { ++ kalPacketFree(prAdapter->prGlueInfo, pvPacket); ++ RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1); ++#if CFG_NATIVE_802_11 ++ if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) { ++ /*Todo:: nothing*/ ++ /*Todo:: nothing*/ ++ } ++#endif ++ } ++ ++ /* free the packet control block */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (!prSwRfb) { ++ ASSERT(0); ++ return; ++ } ++ ++ if (nicRxSetupRFB(prAdapter, prSwRfb)) { ++ ASSERT(0); ++ /* return; // Don't return here or it would lost SwRfb --kc */ ++ if (!timerPendingTimer(&prAdapter->rReturnIndicatedRfbListTimer)) { ++ DBGLOG(RX, WARN, ++ "wlanReturnPacket, Start ReturnIndicatedRfbList Timer (%ds)\n", ++ RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); ++ cnmTimerStartTimer(prAdapter, &prAdapter->rReturnIndicatedRfbListTimer, ++ SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); ++ } ++ } ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the indicated packet buffer and reallocate one to the RFB ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param pvPacket Pointer of returned packet ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_QUE_T prQueList; ++ ++ DEBUGFUNC("wlanReturnIndicatedPacketsTimeOut"); ++ DBGLOG(RX, WARN, "wlanReturnIndicatedPacketsTimeOut"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prQueList = &prRxCtrl->rIndicatedRfbList; ++ DBGLOG(RX, WARN, "IndicatedRfbList num = %u\n", (unsigned int)prQueList->u4NumElem); ++ ++ while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rIndicatedRfbList)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (nicRxSetupRFB(prAdapter, prSwRfb)) { ++ status = WLAN_STATUS_RESOURCES; ++ ASSERT(0); ++ } ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ if (status == WLAN_STATUS_RESOURCES) ++ break; ++ } ++ if (status == WLAN_STATUS_RESOURCES) { ++ DBGLOG(RX, WARN, "Start ReturnIndicatedRfbList Timer (%ds)\n", RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); ++ /* restart timer */ ++ cnmTimerStartTimer(prAdapter, ++ &prAdapter->rReturnIndicatedRfbListTimer, ++ SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a required function that returns information about ++* the capabilities and status of the driver and/or its network adapter. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] pfnOidQryHandler Function pointer for the OID query handler. ++* \param[IN] pvInfoBuf Points to a buffer for return the query information. ++* \param[IN] u4QueryBufferLen Specifies the number of bytes at pvInfoBuf. ++* \param[OUT] pu4QueryInfoLen Points to the number of bytes it written or is needed. ++* ++* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanQueryInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfnOidQryHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QryInfoLen); ++ ++ /* ignore any OID request after connected, under PS current measurement mode */ ++ /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for ++ * blocking OIDs during current measurement ++ */ ++ if (prAdapter->u4PsCurrentMeasureEn && ++ (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) ++ return WLAN_STATUS_SUCCESS; ++#if 1 ++ /* most OID handler will just queue a command packet */ ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++#else ++ if (wlanIsHandlerNeedHwAccess(pfnOidQryHandler, FALSE)) { ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } else ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++#endif ++ ++ return status; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a required function that allows bound protocol drivers, ++* or NDIS, to request changes in the state information that the miniport ++* maintains for particular object identifiers, such as changes in multicast ++* addresses. ++* ++* \param[IN] prAdapter Pointer to the Glue info structure. ++* \param[IN] pfnOidSetHandler Points to the OID set handlers. ++* \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data for the set. ++* \param[IN] u4InfoBufLen Specifies the number of bytes at prSetBuffer. ++* \param[OUT] pu4SetInfoLen Points to the number of bytes it read or is needed. ++* ++* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSetInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfnOidSetHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* ignore any OID request after connected, under PS current measurement mode */ ++ /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for blocking ++ * OIDs during current measurement ++ */ ++ if (prAdapter->u4PsCurrentMeasureEn && ++ (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) ++ return WLAN_STATUS_SUCCESS; ++#if 1 ++ /* most OID handler will just queue a command packet ++ * for power state transition OIDs, handler will acquire power control by itself ++ */ ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++#else ++ if (wlanIsHandlerNeedHwAccess(pfnOidSetHandler, TRUE)) { ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } else { ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++ } ++#endif ++ ++ return status; ++} ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a used to query driver's config wapi mode or not ++* ++* \param[IN] prAdapter Pointer to the Glue info structure. ++* ++* \retval TRUE for use wapi mode ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rWifiVar.rConnSettings.fgWapiMode; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to set RX filter to Promiscuous Mode. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode) ++{ ++ ASSERT(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to set RX filter to allow to receive ++* broadcast address packets. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to send out CMD_NIC_POWER_CTRL command packet ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] ucPowerMode refer to CMD/EVENT document ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode) ++{ ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucTC, ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* 1. Prepare CMD */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL))); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* 2.1 increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* 2.2 Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL); ++ ++ /* 2.3 Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL)); ++ ((P_CMD_NIC_POWER_CTRL) (prWifiCmd->aucBuffer))->ucPowerMode = ucPowerMode; ++ ++ /* 3. Issue CMD for entering specific power mode */ ++ ucTC = TC4_INDEX; ++ ++ while (1) { ++ /* 3.0 Removal check */ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* 3.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ ++ /* wait and poll tx resource */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ continue; ++ } ++ /* 3.2 Send CMD Info Packet */ ++ if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Fail to transmit CMD_NIC_POWER_CTRL command\n"); ++ status = WLAN_STATUS_FAILURE; ++ } ++ ++ break; ++ }; ++ ++ /* 4. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* 5. Add flag */ ++ if (ucPowerMode == 1) ++ prAdapter->fgIsEnterD3ReqIssued = TRUE; ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to check if it is RF test mode and ++* the OID is allowed to be called or not ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerAllowedInRFTest; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ if (fgSetInfo) { ++ apfnOidHandlerAllowedInRFTest = apfnOidSetHandlerAllowedInRFTest; ++ u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); ++ } else { ++ apfnOidHandlerAllowedInRFTest = apfnOidQueryHandlerAllowedInRFTest; ++ u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); ++ } ++ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to download FW image in an aggregated way ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) ++{ ++#if defined(MT6620) || defined(MT6628) ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 u4PktCnt, u4Offset, u4Length; ++ UINT_32 u4TotalLength; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucImgSecBuf); ++ ++ pucOutputBuf = prAdapter->rTxCtrl.pucTxCoalescingBufPtr; ++ ++ DEBUGFUNC("wlanImageSectionDownloadAggregated"); ++ ++ if (u4ImgSecSize == 0) ++ return WLAN_STATUS_SUCCESS; ++ /* 1. Allocate CMD Info Packet and Pre-fill Headers */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + ++ CMD_PKT_SIZE_FOR_IMAGE); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + CMD_PKT_SIZE_FOR_IMAGE; ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->ucEtherTypeOffset = 0; ++ prInitHifTxHeader->ucCSflags = 0; ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; ++ ++ /* 4. Setup CMD_DOWNLOAD_BUF */ ++ prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdDownloadBuf->u4DataMode = 0 ++#if CFG_ENABLE_FW_ENCRYPTION ++ | DOWNLOAD_BUF_ENCRYPTION_MODE ++#endif ++ ; ++ ++ /* 5.0 reset loop control variable */ ++ u4TotalLength = 0; ++ u4Offset = u4PktCnt = 0; ++ ++ /* 5.1 main loop for maximize transmission count per access */ ++ while (u4Offset < u4ImgSecSize) { ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_SUCCESS) { ++ /* 5.1.1 calculate u4Length */ ++ if (u4Offset + CMD_PKT_SIZE_FOR_IMAGE < u4ImgSecSize) ++ u4Length = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4Length = u4ImgSecSize - u4Offset; ++ ++ /* 5.1.1 increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5.1.2 update HIF TX hardware header */ ++ prInitHifTxHeader->u2TxByteCount = ++ ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4Length); ++ ++ /* 5.1.3 fill command header */ ++ prInitCmdDownloadBuf->u4Address = u4DestAddr + u4Offset; ++ prInitCmdDownloadBuf->u4Length = u4Length; ++ prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf + u4Offset, u4Length); ++ ++ /* 5.1.4.1 copy header to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength, ++ (PVOID) prCmdInfo->pucInfoBuffer, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF)); ++ ++ /* 5.1.4.2 copy payload to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength + sizeof(INIT_HIF_TX_HEADER_T) + ++ sizeof(INIT_CMD_DOWNLOAD_BUF), pucImgSecBuf + u4Offset, u4Length); ++ ++ /* 5.1.4.3 update length and other variables */ ++ u4TotalLength += ++ ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4Length); ++ u4Offset += u4Length; ++ u4PktCnt++; ++ ++ if (u4Offset < u4ImgSecSize) ++ continue; ++ } else if (u4PktCnt == 0) { ++ /* no resource, so get some back */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ } ++ ++ if (u4PktCnt != 0) { ++ /* start transmission */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ 0, ++ u4TotalLength, (PUINT_8) pucOutputBuf, prAdapter->u4CoalescingBufCachedSize); ++ ++ /* reset varaibles */ ++ u4PktCnt = 0; ++ u4TotalLength = 0; ++ } ++ } ++ ++ /* 8. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++ ++#else ++#error "Only MT6620/MT6628/MT6582 supports firmware download in an aggregated way" ++ ++ return WLAN_STATUS_FAILURE; ++ ++#endif ++} ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to download FW image. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucImgSecBuf); ++ ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); ++ ++ DEBUGFUNC("wlanImageSectionDownload"); ++ ++ if (u4ImgSecSize == 0) ++ return WLAN_STATUS_SUCCESS; ++ /* 1. Allocate CMD Info Packet and its Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4ImgSecSize); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4ImgSecSize; ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5. Setup CMD_DOWNLOAD_BUF */ ++ prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdDownloadBuf->u4Address = u4DestAddr; ++ prInitCmdDownloadBuf->u4Length = u4ImgSecSize; ++ prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf, u4ImgSecSize); ++ ++ prInitCmdDownloadBuf->u4DataMode = 0 ++#if CFG_ENABLE_FW_DOWNLOAD_ACK ++ | DOWNLOAD_BUF_ACK_OPTION /* ACK needed */ ++#endif ++#if CFG_ENABLE_FW_ENCRYPTION ++ | DOWNLOAD_BUF_ENCRYPTION_MODE ++#endif ++ ; ++ ++ kalMemCopy(prInitCmdDownloadBuf->aucBuffer, pucImgSecBuf, u4ImgSecSize); ++ ++ /* 6. Send FW_Download command */ ++ while (1) { ++ /* 6.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ continue; ++ } ++ /* 6.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); ++ } ++ ++ break; ++ }; ++ ++#if CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* 7. Wait for INIT_EVENT_ID_CMD_RESULT */ ++ u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum); ++#endif ++ ++ /* 8. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to confirm previously firmware download is done without error ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR)]; ++ UINT_32 u4RxPktLength; ++ P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; ++ P_INIT_EVENT_PENDING_ERROR prEventPendingError; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_8 ucTC, ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanImageQueryStatus"); ++ ++ /* 1. Allocate CMD Info Packet and it Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ kalMemZero(prCmdInfo, sizeof(INIT_HIF_TX_HEADER_T)); ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5. Send command */ ++ while (1) { ++ /* 5.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ continue; ++ } ++ /* 5.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); ++ } ++ ++ break; ++ }; ++ ++ /* 6. Wait for INIT_EVENT_ID_PENDING_ERROR */ ++ do { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (nicRxWaitResponse(prAdapter, ++ 0, ++ aucBuffer, ++ sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; ++ ++ /* EID / SeqNum check */ ++ if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PENDING_ERROR) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prEventPendingError = ++ (P_INIT_EVENT_PENDING_ERROR) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); ++ if (prEventPendingError->ucStatus != 0) { /* 0 for download success */ ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ } while (FALSE); ++ ++ /* 7. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++#else ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to confirm the status of ++* previously downloaded firmware scatter ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ucCmdSeqNum Sequence number of previous firmware scatter ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum) ++{ ++ UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)]; ++ P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; ++ P_INIT_EVENT_CMD_RESULT prEventCmdResult; ++ UINT_32 u4RxPktLength; ++ WLAN_STATUS u4Status; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ DBGLOG(INIT, ERROR, "kalIsCardRemoved or fgIsBusAccessFailed\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (nicRxWaitResponse(prAdapter, ++ 0, ++ aucBuffer, ++ sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT),/* 4B + 4B */ ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicRxWaitResponse fail\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; ++ ++ /* EID / SeqNum check */ ++ if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT) { ++ DBGLOG(INIT, ERROR, "rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Check EID error!]", __func__); ++ } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { ++ DBGLOG(INIT, ERROR, "rInitWifiEvent.ucSeqNum != ucCmdSeqNum\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Check SeqNum error!]", __func__); ++ } else { ++ prEventCmdResult = ++ (P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); ++ if (prEventCmdResult->ucStatus != 0) { /* 0 for download success */ ++ /* ++ 0: success ++ 1: rejected by invalid param ++ 2: rejected by incorrect CRC ++ 3: rejected by decryption failure ++ 4: unknown CMD ++ */ ++ DBGLOG(INIT, ERROR, "Read Response status error = %d\n", ++ prEventCmdResult->ucStatus); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to start FW normal operation. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_WIFI_START prInitCmdWifiStart; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanConfigWifiFunc"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START); ++ ++ /* 2. Always use TC0 */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_WIFI_START; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ prInitCmdWifiStart = (P_INIT_CMD_WIFI_START) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdWifiStart->u4Override = (fgEnable == TRUE ? 1 : 0); ++ prInitCmdWifiStart->u4Address = u4StartAddress; ++ ++ /* 5. Seend WIFI start command */ ++ while (1) { ++ /* 5.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ ++ /* wait and poll tx resource */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ ++ continue; ++ } ++ /* 5.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit WIFI start command\n"); ++ } ++ ++ break; ++ }; ++ ++ /* 6. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate CRC32 checksum ++* ++* @param buf Pointer to the data. ++* @param len data length ++* ++* @return crc32 value ++*/ ++/*----------------------------------------------------------------------------*/ ++static const UINT_32 crc32_ccitt_table[256] = { ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, ++ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, ++ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, ++ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, ++ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, ++ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, ++ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, ++ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, ++ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, ++ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, ++ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, ++ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, ++ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, ++ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, ++ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, ++ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, ++ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, ++ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, ++ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, ++ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, ++ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, ++ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, ++ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, ++ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, ++ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, ++ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, ++ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, ++ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, ++ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, ++ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, ++ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, ++ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, ++ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, ++ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, ++ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, ++ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, ++ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, ++ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, ++ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, ++ 0x2d02ef8d ++ }; ++ ++UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len) ++{ ++ UINT_32 i, crc32 = 0xFFFFFFFF; ++ ++ for (i = 0; i < len; i++) ++ crc32 = crc32_ccitt_table[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8); ++ ++ return ~crc32; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to process queued RX packets ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prSwRfbListHead Pointer to head of RX packets link list ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) ++{ ++ P_SW_RFB_T prSwRfb, prNextSwRfb; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfbListHead); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ prSwRfb = prSwRfbListHead; ++ ++ do { ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ ++ switch (prSwRfb->eDst) { ++ case RX_PKT_DESTINATION_HOST: ++ /* to host */ ++ nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_FORWARD: ++ /* need ot forward */ ++ nicRxProcessForwardPkt(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_HOST_WITH_FORWARD: ++ /* to host and forward */ ++ nicRxProcessGOBroadcastPkt(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_NULL: ++ /* free it */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ ++ default: ++ break; ++ } ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4DequeuedCnt++; ++#endif ++ ++ /* check next queued packet */ ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to purge queued TX packets ++* by indicating failure to OS and returned to free list ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prMsduInfoListHead Pointer to head of TX packets link list ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); ++ nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if the OID handler needs timeout ++* ++* @param prAdapter Pointer to the Adapter structure. ++* pfnOidHandler Pointer to the OID handler ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerWOTimeoutCheck; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ apfnOidHandlerWOTimeoutCheck = apfnOidWOTimeoutCheck; ++ u4NumOfElem = sizeof(apfnOidWOTimeoutCheck) / sizeof(PFN_OID_HANDLER_FUNC); ++ ++ /* skip some OID timeout checks ? */ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerWOTimeoutCheck[i] == pfnOidHandler) ++ return FALSE; ++ } ++ ++ /* set timer if need timeout check */ ++ /* cnmTimerStartTimer(prAdapter, */ ++ /* &(prAdapter->rOidTimeoutTimer), */ ++ /* 1000); */ ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rOidTimeoutTimer), 2000); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to clear any pending OID timeout check ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rOidTimeoutTimer)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update network address in firmware domain ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return WLAN_STATUS_FAILURE The request could not be processed ++* WLAN_STATUS_PENDING The request has been queued for later processing ++* WLAN_STATUS_SUCCESS The request has been processed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter) ++{ ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ PARAM_MAC_ADDRESS rMacAddr = {0}; ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_BASIC_CONFIG prCmdBasicConfig; ++ UINT_32 u4SysTime; ++ ++ DEBUGFUNC("wlanUpdateNetworkAddress"); ++ ++ ASSERT(prAdapter); ++ ++ if (kalRetrieveNetworkAddress(prAdapter->prGlueInfo, &rMacAddr) == FALSE || IS_BMCAST_MAC_ADDR(rMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, rMacAddr)) { ++ /* eFUSE has a valid address, don't do anything */ ++ if (prAdapter->fgIsEmbbededMacAddrValid == TRUE) { ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "Using embedded MAC address"); ++#endif ++ return WLAN_STATUS_SUCCESS; ++ } ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, TRACE, "Using dynamically generated MAC address"); ++#endif ++ /* dynamic generate */ ++ u4SysTime = kalGetTimeTick(); ++ ++ rMacAddr[0] = 0x00; ++ rMacAddr[1] = 0x08; ++ rMacAddr[2] = 0x22; ++ ++ kalMemCopy(&rMacAddr[3], &u4SysTime, 3); ++ } else { ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "Using host-supplied MAC address"); ++#endif ++ } ++ ++ /* allocate command memory */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* configure CMD_BASIC_CONFIG */ ++ prCmdBasicConfig = (P_CMD_BASIC_CONFIG) (prWifiCmd->aucBuffer); ++ kalMemCopy(&(prCmdBasicConfig->rMyMacAddr), &rMacAddr, PARAM_MAC_ADDR_LEN); ++ prCmdBasicConfig->ucNative80211 = 0; ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum = 0; ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum = 0; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(2); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(1); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(0); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(2); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(1); ++ ++ if (prAdapter->u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(0); ++#endif ++ ++ /* send the command to FW */ ++ if (wlanSendCommand(prAdapter, prCmdInfo) == WLAN_STATUS_RESOURCES) { ++ ++ /* backup the command to wait response */ ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryAddress; ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ return WLAN_STATUS_PENDING; ++ } ++ /* send ok without response */ ++ nicCmdEventQueryAddress(prAdapter, prCmdInfo, (PUINT_8) prCmdBasicConfig); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if the device is in RF test mode ++* ++* @param pfnOidHandler Pointer to the OID handler ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->fgTestMode; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to identify 802.1x and Bluetooth-over-Wi-Fi ++* security frames, and queued into command queue for strict ordering ++* due to 802.1x frames before add-key OIDs are not to be encrypted ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prPacket Pointer of native packet ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket) ++{ ++ UINT_8 ucPriorityParam; ++ UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; ++ BOOLEAN fgIs1x = FALSE; ++ BOOLEAN fgIsPAL = FALSE; ++ UINT_32 u4PacketLen; ++ ULONG u4SysTime; ++ UINT_8 ucNetworkType; ++ P_CMD_INFO_T prCmdInfo; ++ UINT_8 ucCmdSeqNo = 0; ++ ++ /* 1x data packets */ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prPacket); ++ ++ /* retrieve some information for packet classification */ ++ if (kalQoSFrameClassifierAndPacketInfo(prAdapter->prGlueInfo, ++ prPacket, ++ &ucPriorityParam, ++ &u4PacketLen, ++ aucEthDestAddr, ++ &fgIs1x, ++ &fgIsPAL, ++ &ucNetworkType, ++ &ucCmdSeqNo) == TRUE) { ++ /* almost TRUE except frame length < 14B */ ++ ++ if (fgIs1x == FALSE) ++ return FALSE; ++ ++ /* get a free command entry */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ P_STA_RECORD_T prStaRec; ++ ++ /* fill arrival time */ ++ u4SysTime = (OS_SYSTIME) kalGetTimeTick(); ++ GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); ++ ++ kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); ++ ++ prCmdInfo->eCmdType = COMMAND_TYPE_SECURITY_FRAME; ++ prCmdInfo->u2InfoBufLen = (UINT_16) u4PacketLen; ++ prCmdInfo->pucInfoBuffer = NULL; ++ prCmdInfo->prPacket = prPacket; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNo; ++#if 0 ++ prCmdInfo->ucStaRecIndex = qmGetStaRecIdx(prAdapter, ++ aucEthDestAddr, ++ (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType); ++#endif ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType, ++ aucEthDestAddr); ++ if (prStaRec) ++ prCmdInfo->ucStaRecIndex = prStaRec->ucIndex; ++ else ++ prCmdInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ ++ prCmdInfo->eNetworkType = (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType; ++ prCmdInfo->pfCmdDoneHandler = wlanSecurityFrameTxDone; ++ prCmdInfo->pfCmdTimeoutHandler = wlanSecurityFrameTxTimeout; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ ++ /* ++ queue the 1x packet and we will send the packet to CONNSYS by ++ using command queue ++ */ ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* TRUE: means we have already handled it in the function */ ++ return TRUE; ++ } ++ ++ /* no memory, why assert ? can skip the packet ? */ ++ ASSERT(0); ++ return FALSE; ++ } ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi ++* security frames has been sent to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prCmdInfo Pointer of CMD_INFO_T ++* @param pucEventBuf meaningless, only for API compatibility ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->eNetworkType == NETWORK_TYPE_AIS_INDEX && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) { ++ ++ /* AIS counter measure so change RSN FSM to SEND_DEAUTH state */ ++ P_STA_RECORD_T prSta = cnmGetStaRecByIndex(prAdapter, prCmdInfo->ucStaRecIndex); ++ ++ if (prSta) { ++ kalMsleep(10); ++ secFsmEventEapolTxDone(prAdapter, prSta, TX_RESULT_SUCCESS); ++ } ++ } ++ ++ /* free the packet */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_SUCCESS); ++ DBGLOG(TX, INFO, "Security frame tx done, SeqNum: %d\n", prCmdInfo->ucCmdSeqNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi ++* security frames has failed sending to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prCmdInfo Pointer of CMD_INFO_T ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* free the packet */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called before AIS is starting a new scan ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter) ++{ ++ BOOLEAN fgKeepCurrOne = FALSE; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* clear scanning result except current one */ ++ /* copy current one to prAdapter->rWlanInfo.arScanResult[0] */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { ++ fgKeepCurrOne = TRUE; ++ ++ if (i != 0) { ++ /* copy structure */ ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[0]), ++ &(prAdapter->rWlanInfo.arScanResult[i]), ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ } ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[i] != ++ &(prAdapter->rWlanInfo.aucScanIEBuf[0])) { ++ /* move IEs to head */ ++ kalMemCopy(prAdapter->rWlanInfo.aucScanIEBuf, ++ prAdapter->rWlanInfo.apucScanResultIEs[i], ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ } ++ /* modify IE pointer */ ++ prAdapter->rWlanInfo.apucScanResultIEs[0] = ++ &(prAdapter->rWlanInfo.aucScanIEBuf[0]); ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[0] = NULL; ++ } ++ ++ break; ++ } ++ } ++ } ++ ++ if (fgKeepCurrOne == TRUE) { ++ prAdapter->rWlanInfo.u4ScanResultNum = 1; ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage = ALIGN_4(prAdapter->rWlanInfo.arScanResult[0].u4IELength); ++ } else { ++ prAdapter->rWlanInfo.u4ScanResultNum = 0; ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage = 0; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when AIS received a beacon timeout event ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param arBSSID MAC address of the specified BSS ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID) ++{ ++ UINT_32 i, j, u4IELength = 0, u4IEMoveLength; ++ PUINT_8 pucIEPtr; ++ ++ ASSERT(prAdapter); ++ ++ /* clear the scanning result for arBSSID */ ++ i = 0; ++ while (1) { ++ if (i >= prAdapter->rWlanInfo.u4ScanResultNum) ++ break; ++ ++ if (EQUAL_MAC_ADDR(arBSSID, prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { ++ ++ /* backup current IE length */ ++ u4IELength = ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ pucIEPtr = prAdapter->rWlanInfo.apucScanResultIEs[i]; ++ ++ /* removed from middle */ ++ for (j = i + 1; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[j - 1]), ++ &(prAdapter->rWlanInfo.arScanResult[j]), ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[j - 1] = ++ prAdapter->rWlanInfo.apucScanResultIEs[j]; ++ } ++ ++ prAdapter->rWlanInfo.u4ScanResultNum--; ++ ++ /* remove IE buffer if needed := move rest of IE buffer */ ++ if (u4IELength > 0) { ++ u4IEMoveLength = prAdapter->rWlanInfo.u4ScanIEBufferUsage - ++ (((ULONG) pucIEPtr) + (ULONG) u4IELength - ++ ((ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])))); ++ ++ kalMemCopy(pucIEPtr, pucIEPtr + u4IELength, u4IEMoveLength); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4IELength; ++ ++ /* correction of pointers to IE buffer */ ++ for (j = 0; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[j] > pucIEPtr) { ++ prAdapter->rWlanInfo.apucScanResultIEs[j] = ++ (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[j]) - ++ u4IELength); ++ } ++ } ++ } ++ } ++ ++ i++; ++ } ++ ++} ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter) ++{ ++#if 0 ++ P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; ++ ++ prMsgFuncSwitch = ++ (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ if (!prMsgFuncSwitch) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prMsgFuncSwitch->fgIsFuncOn = TRUE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++} ++ ++VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter) ++{ ++ ++ P_MSG_P2P_CONNECTION_REQUEST_T prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ UINT_8 aucTargetDeviceID[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; ++ ++ prMsgConnReq = ++ (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ if (!prMsgConnReq) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prMsgConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ /*=====Param Modified for test=====*/ ++ COPY_MAC_ADDR(prMsgConnReq->aucDeviceID, aucTargetDeviceID); ++ prMsgConnReq->fgIsTobeGO = TRUE; ++ prMsgConnReq->fgIsPersistentGroup = FALSE; ++ ++ /*=====Param Modified for test=====*/ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgConnReq, MSG_SEND_METHOD_BUF); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve permanent address from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_EVENT_BASIC_CONFIG prEventBasicConfig; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryPermanentAddress"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* wait for response */ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG), /* 8B + 12B */ ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_BASIC_CONFIG) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (prEvent->aucBuffer); ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucPermanentAddress, &(prEventBasicConfig->rMyMacAddr)); ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, &(prEventBasicConfig->rMyMacAddr)); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve NIC capability from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_32 u4FwIDVersion = 0; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_EVENT_NIC_CAPABILITY prEventNicCapability; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryNicCapability"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* wait for FW response */ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_NIC_CAPABILITY) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventNicCapability = (P_EVENT_NIC_CAPABILITY) (prEvent->aucBuffer); ++ ++ prAdapter->rVerInfo.u2FwProductID = prEventNicCapability->u2ProductID; ++ prAdapter->rVerInfo.u2FwOwnVersion = prEventNicCapability->u2FwVersion; ++ prAdapter->rVerInfo.u2FwPeerVersion = prEventNicCapability->u2DriverVersion; ++ prAdapter->fgIsHw5GBandDisabled = (BOOLEAN) prEventNicCapability->ucHw5GBandDisabled; ++ prAdapter->fgIsEepromUsed = (BOOLEAN) prEventNicCapability->ucEepromUsed; ++ prAdapter->fgIsEfuseValid = (BOOLEAN) prEventNicCapability->ucEfuseValid; ++ prAdapter->fgIsEmbbededMacAddrValid = (BOOLEAN) prEventNicCapability->ucMacAddrValid; ++ ++ u4FwIDVersion = (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); ++ mtk_wcn_wmt_set_wifi_ver(u4FwIDVersion); ++#if (CFG_SUPPORT_TDLS == 1) ++ if (prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_TDLS)) ++ prAdapter->fgTdlsIsSup = TRUE; ++ DBGLOG(TDLS, TRACE, " support flag: 0x%x\n", prEventNicCapability->ucFeatureSet); ++#else ++ prAdapter->fgTdlsIsSup = 0; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ if (!(prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_5G_SUPPORT))) ++ prAdapter->fgEnable5GBand = FALSE; /* firmware does not support */ ++ ++#if CFG_ENABLE_CAL_LOG ++ DBGLOG(INIT, LOUD, " RF CAL FAIL = (%d),BB CAL FAIL = (%d)\n", ++ prEventNicCapability->ucRfCalFail, prEventNicCapability->ucBbCalFail); ++#endif ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve NIC capability from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryDebugCode"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE; ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_GET_DEBUG_CODE; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve compiler flag from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryCompileFlag(IN P_ADAPTER_T prAdapter, IN UINT_32 u4QueryID, OUT PUINT_32 pu4CompilerFlag) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_CMD_SW_DBG_CTRL_T prCmdNicCompileFlag, prEventNicCompileFlag; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC(__func__); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_SW_DBG_CTRL; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* Fill up SW CR */ ++ prCmdNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prWifiCmd->aucBuffer); ++ ++ prCmdNicCompileFlag->u4Id = u4QueryID; ++ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_SW_DBG_CTRL) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prEvent->aucBuffer); ++ ++ *pu4CompilerFlag = prEventNicCompileFlag->u4Data; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter) ++{ ++ wlanQueryCompileFlag(prAdapter, 0xA0240000, &prAdapter->u4FwCompileFlag0); ++ wlanQueryCompileFlag(prAdapter, 0xA0240001, &prAdapter->u4FwCompileFlag1); ++ ++ DBGLOG(INIT, TRACE, ++ "Compile Flags: 0x%08x 0x%08x\n", prAdapter->u4FwCompileFlag0, prAdapter->u4FwCompileFlag1); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if defined(MT6628) ++static INT_32 wlanChangeCodeWord(INT_32 au4Input) ++{ ++ ++ UINT_16 i; ++#if TXPWR_USE_PDSLOPE ++ CODE_MAPPING_T arCodeTable[] = { ++ {0X100, -40}, ++ {0X104, -35}, ++ {0X128, -30}, ++ {0X14C, -25}, ++ {0X170, -20}, ++ {0X194, -15}, ++ {0X1B8, -10}, ++ {0X1DC, -5}, ++ {0, 0}, ++ {0X24, 5}, ++ {0X48, 10}, ++ {0X6C, 15}, ++ {0X90, 20}, ++ {0XB4, 25}, ++ {0XD8, 30}, ++ {0XFC, 35}, ++ {0XFF, 40}, ++ ++ }; ++#else ++ CODE_MAPPING_T arCodeTable[] = { ++ {0X100, 0x80}, ++ {0X104, 0x80}, ++ {0X128, 0x80}, ++ {0X14C, 0x80}, ++ {0X170, 0x80}, ++ {0X194, 0x94}, ++ {0X1B8, 0XB8}, ++ {0X1DC, 0xDC}, ++ {0, 0}, ++ {0X24, 0x24}, ++ {0X48, 0x48}, ++ {0X6C, 0x6c}, ++ {0X90, 0x7F}, ++ {0XB4, 0x7F}, ++ {0XD8, 0x7F}, ++ {0XFC, 0x7F}, ++ {0XFF, 0x7F}, ++ ++ }; ++#endif ++ ++ for (i = 0; i < sizeof(arCodeTable) / sizeof(CODE_MAPPING_T); i++) { ++ ++ if (arCodeTable[i].u4RegisterValue == au4Input) ++ return arCodeTable[i].i4TxpowerOffset; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if TXPWR_USE_PDSLOPE ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_CMD_ACCESS_REG prCmdMcrQuery; ++ ++ ASSERT(prAdapter); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_ACCESS_REG; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_ACCESS_REG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ kalMemCopy(prWifiCmd->aucBuffer, prMcrRdInfo, sizeof(CMD_ACCESS_REG)); ++ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG), &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ ++ if (prEvent->ucEID != EVENT_ID_ACCESS_REG) ++ return WLAN_STATUS_FAILURE; ++ ++ prCmdMcrQuery = (P_CMD_ACCESS_REG) (prEvent->aucBuffer); ++ prMcrRdInfo->u4McrOffset = prCmdMcrQuery->u4Address; ++ prMcrRdInfo->u4McrData = prCmdMcrQuery->u4Data; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++static INT_32 wlanIntRound(INT_32 au4Input) ++{ ++ ++ if (au4Input >= 0) { ++ if ((au4Input % 10) == 5) { ++ au4Input = au4Input + 5; ++ return au4Input; ++ } ++ } ++ ++ if (au4Input < 0) { ++ if ((au4Input % 10) == -5) { ++ au4Input = au4Input - 5; ++ return au4Input; ++ } ++ } ++ ++ return au4Input; ++} ++ ++static INT_32 wlanCal6628EfuseForm(IN P_ADAPTER_T prAdapter, INT_32 au4Input) ++{ ++ ++ PARAM_MCR_RW_STRUCT_T rMcrRdInfo; ++ INT_32 au4PdSlope, au4TxPwrOffset, au4TxPwrOffset_Round; ++ INT_8 auTxPwrOffset_Round; ++ ++ rMcrRdInfo.u4McrOffset = 0x60205c68; ++ rMcrRdInfo.u4McrData = 0; ++ au4TxPwrOffset = au4Input; ++ wlanQueryPdMcr(prAdapter, &rMcrRdInfo); ++ ++ au4PdSlope = (rMcrRdInfo.u4McrData) & BITS(0, 6); ++ au4TxPwrOffset_Round = wlanIntRound((au4TxPwrOffset * au4PdSlope)) / 10; ++ ++ au4TxPwrOffset_Round = -au4TxPwrOffset_Round; ++ ++ if (au4TxPwrOffset_Round < -128) ++ au4TxPwrOffset_Round = 128; ++ else if (au4TxPwrOffset_Round < 0) ++ au4TxPwrOffset_Round += 256; ++ else if (au4TxPwrOffset_Round > 127) ++ au4TxPwrOffset_Round = 127; ++ ++ auTxPwrOffset_Round = (UINT8) au4TxPwrOffset_Round; ++ ++ return au4TxPwrOffset_Round; ++} ++ ++#endif ++ ++#if defined(MT6628) ++static VOID wlanChangeNvram6620to6628(PUINT_8 pucEFUSE) ++{ ++ ++#define EFUSE_CH_OFFSET1_L_MASK_6620 BITS(0, 8) ++#define EFUSE_CH_OFFSET1_L_SHIFT_6620 0 ++#define EFUSE_CH_OFFSET1_M_MASK_6620 BITS(9, 17) ++#define EFUSE_CH_OFFSET1_M_SHIFT_6620 9 ++#define EFUSE_CH_OFFSET1_H_MASK_6620 BITS(18, 26) ++#define EFUSE_CH_OFFSET1_H_SHIFT_6620 18 ++#define EFUSE_CH_OFFSET1_VLD_MASK_6620 BIT(27) ++#define EFUSE_CH_OFFSET1_VLD_SHIFT_6620 27 ++ ++#define EFUSE_CH_OFFSET1_L_MASK_5931 BITS(0, 7) ++#define EFUSE_CH_OFFSET1_L_SHIFT_5931 0 ++#define EFUSE_CH_OFFSET1_M_MASK_5931 BITS(8, 15) ++#define EFUSE_CH_OFFSET1_M_SHIFT_5931 8 ++#define EFUSE_CH_OFFSET1_H_MASK_5931 BITS(16, 23) ++#define EFUSE_CH_OFFSET1_H_SHIFT_5931 16 ++#define EFUSE_CH_OFFSET1_VLD_MASK_5931 BIT(24) ++#define EFUSE_CH_OFFSET1_VLD_SHIFT_5931 24 ++#define EFUSE_ALL_CH_OFFSET1_MASK_5931 BITS(25, 27) ++#define EFUSE_ALL_CH_OFFSET1_SHIFT_5931 25 ++ ++ INT_32 au4ChOffset; ++ INT_16 au2ChOffsetL, au2ChOffsetM, au2ChOffsetH; ++ ++ au4ChOffset = *(UINT_32 *) (pucEFUSE + 72); ++ ++ if ((au4ChOffset & EFUSE_CH_OFFSET1_VLD_MASK_6620) && ((*(UINT_32 *) (pucEFUSE + 28)) == 0)) { ++ ++ au2ChOffsetL = ((au4ChOffset & EFUSE_CH_OFFSET1_L_MASK_6620) >> EFUSE_CH_OFFSET1_L_SHIFT_6620); ++ ++ au2ChOffsetM = ((au4ChOffset & EFUSE_CH_OFFSET1_M_MASK_6620) >> EFUSE_CH_OFFSET1_M_SHIFT_6620); ++ ++ au2ChOffsetH = ((au4ChOffset & EFUSE_CH_OFFSET1_H_MASK_6620) >> EFUSE_CH_OFFSET1_H_SHIFT_6620); ++ ++ au2ChOffsetL = wlanChangeCodeWord(au2ChOffsetL); ++ au2ChOffsetM = wlanChangeCodeWord(au2ChOffsetM); ++ au2ChOffsetH = wlanChangeCodeWord(au2ChOffsetH); ++ ++ au4ChOffset = 0; ++ au4ChOffset |= *(UINT_32 *) (pucEFUSE + 72) ++ >> (EFUSE_CH_OFFSET1_VLD_SHIFT_6620 - ++ EFUSE_CH_OFFSET1_VLD_SHIFT_5931) & EFUSE_CH_OFFSET1_VLD_MASK_5931; ++ ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetL) << EFUSE_CH_OFFSET1_L_SHIFT_5931) & EFUSE_CH_OFFSET1_L_MASK_5931); ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetM) << EFUSE_CH_OFFSET1_M_SHIFT_5931) & EFUSE_CH_OFFSET1_M_MASK_5931); ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetH) << EFUSE_CH_OFFSET1_H_SHIFT_5931) & EFUSE_CH_OFFSET1_H_MASK_5931); ++ ++ *((INT_32 *) ((pucEFUSE + 28))) = au4ChOffset; ++ ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to load manufacture data from NVRAM ++* if available and valid ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prRegInfo Pointer of REG_INFO_T ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ CMD_RDD_CH_T rRddParam; ++#endif ++ ++ ASSERT(prAdapter); ++ ++ /* 1. Version Check */ ++ kalGetConfigurationVersion(prAdapter->prGlueInfo, ++ &(prAdapter->rVerInfo.u2Part1CfgOwnVersion), ++ &(prAdapter->rVerInfo.u2Part1CfgPeerVersion), ++ &(prAdapter->rVerInfo.u2Part2CfgOwnVersion), ++ &(prAdapter->rVerInfo.u2Part2CfgPeerVersion)); ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ if (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION) { ++ return WLAN_STATUS_FAILURE; ++ } ++#endif ++ ++ /* MT6620 E1/E2 would be ignored directly */ ++ if (prAdapter->rVerInfo.u2Part1CfgOwnVersion == 0x0001) { ++ prRegInfo->ucTxPwrValid = 1; ++ } else { ++ /* 2. Load TX power gain parameters if valid */ ++ if (prRegInfo->ucTxPwrValid != 0) { ++ /* send to F/W */ ++ nicUpdateTxPower(prAdapter, (P_CMD_TX_PWR_T) (&(prRegInfo->rTxPwr))); ++ } ++ } ++ ++ /* Workaround for supporting 5G */ ++ prRegInfo->ucEnable5GBand = 1; ++ prRegInfo->ucSupport5GBand = 1; ++ ++ /* 3. Check if needs to support 5GHz */ ++ /* if(prRegInfo->ucEnable5GBand) { // Frank workaround */ ++ if (1) { ++ /* check if it is disabled by hardware */ ++ if (prAdapter->fgIsHw5GBandDisabled || prRegInfo->ucSupport5GBand == 0) ++ prAdapter->fgEnable5GBand = FALSE; ++ else ++ prAdapter->fgEnable5GBand = TRUE; ++ } else ++ prAdapter->fgEnable5GBand = FALSE; ++ /* Workaround for supporting 5G */ ++ prAdapter->fgEnable5GBand = TRUE; ++/* ++ DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d)\n", ++ prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled); ++*/ ++ /* 4. Send EFUSE data */ ++#if defined(MT6628) ++ wlanChangeNvram6620to6628(prRegInfo->aucEFUSE); ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PHY_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_PHY_PARAM_T), (PUINT_8) (prRegInfo->aucEFUSE), NULL, 0); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ rRddParam.ucRddTestMode = (UINT_8) prRegInfo->u4RddTestMode; ++ rRddParam.ucRddShutCh = (UINT_8) prRegInfo->u4RddShutFreq; ++ rRddParam.ucRddStartCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStartFreq); ++ rRddParam.ucRddStopCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStopFreq); ++ rRddParam.ucRddDfs = (UINT_8) prRegInfo->u4RddDfs; ++ prAdapter->ucRddStatus = 0; ++ nicUpdateRddTestMode(prAdapter, (P_CMD_RDD_CH_T) (&rRddParam)); ++#endif ++ ++ /* 5. Get 16-bits Country Code and Bandwidth */ ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = ++ (((UINT_16) prRegInfo->au2CountryCode[0]) << 8) | (((UINT_16) prRegInfo->au2CountryCode[1]) & BITS(0, 7)); ++ ++ DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d) CountryCode(0x%x 0x%x)\n", ++ prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled, ++ prRegInfo->au2CountryCode[0], prRegInfo->au2CountryCode[1]); ++ ++#if 0 /* Bandwidth control will be controlled by GUI. 20110930 ++ * So ignore the setting from registry/NVRAM ++ */ ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = ++ prRegInfo->uc2G4BwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = ++ prRegInfo->uc5GBwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; ++#endif ++ ++ /* 6. Set domain and channel information to chip */ ++ rlmDomainSendCmd(prAdapter, FALSE); ++ /* Update supported channel list in channel table */ ++ wlanUpdateChannelTable(prAdapter->prGlueInfo); ++ ++ /* 7. Set band edge tx power if available */ ++ if (prRegInfo->fg2G4BandEdgePwrUsed) { ++ CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; ++ ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK = prRegInfo->cBandEdgeMaxPwrCCK; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 = prRegInfo->cBandEdgeMaxPwrOFDM20; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 = prRegInfo->cBandEdgeMaxPwrOFDM40; ++ ++ DBGLOG(INIT, TRACE, "NVRAM 2G Bandedge CCK(%d) HT20(%d)HT40(%d)\n", ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK, ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_EDGE_TXPWR_LIMIT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); ++ } ++ /* 8. set 5G band edge tx power if available (add for 6625) */ ++ if (prAdapter->fgEnable5GBand) { ++#define NVRAM_5G_TX_BANDEDGE_VALID_OFFSET 10 ++#define NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET 11 ++#define NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET 12 ++ ++ if (prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_VALID_OFFSET]) { ++ CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; ++ ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 ++ = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET]; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 ++ = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET]; ++ ++ DBGLOG(INIT, TRACE, "NVRAM 5G Bandedge HT20(%d)HT40(%d)\n", ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); ++ } ++ } ++ /* 9. set RSSI compensation */ ++ /* DBGLOG(INIT, INFO, ("[frank] RSSI valid(%d) 2G(%d) 5G(%d)", ++ prRegInfo->fgRssiCompensationValidbit, ++ prRegInfo->uc2GRssiCompensation, ++ prRegInfo->uc5GRssiCompensation)); */ ++ if (prRegInfo->fgRssiCompensationValidbit) { ++ CMD_RSSI_COMPENSATE_T rCmdRssiCompensate; ++ ++ rCmdRssiCompensate.uc2GRssiCompensation = prRegInfo->uc2GRssiCompensation; ++ rCmdRssiCompensate.uc5GRssiCompensation = prRegInfo->uc5GRssiCompensation; ++ ++ DBGLOG(INIT, LOUD, "NVRAM RSSI Comp. 2G(%d)5G(%d)\n", ++ rCmdRssiCompensate.uc2GRssiCompensation, rCmdRssiCompensate.uc5GRssiCompensation); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RSSI_COMPENSATE, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_RSSI_COMPENSATE_T), (PUINT_8)&rCmdRssiCompensate, NULL, 0); ++ } ++ /* 10. notify FW Band Support 5G */ ++ if (prAdapter->fgEnable5GBand) { ++ CMD_BAND_SUPPORT_T rCmdBandSupport; ++ ++ rCmdBandSupport.uc5GBandSupport = TRUE; ++ DBGLOG(INIT, TRACE, "NVRAM 5G BandSupport\n"); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BAND_SUPPORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_BAND_SUPPORT_T), (PUINT_8)&rCmdBandSupport, NULL, 0); ++ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check ++* Media Stream Mode is set to non-default value or not, ++* and clear to default value if above criteria is met ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return TRUE ++* The media stream mode was non-default value and has been reset ++* FALSE ++* The media stream mode is default value ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode != 0) { ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if any pending timer has expired ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* check timer status */ ++ cnmTimerDoTimeOutCheck(prAdapter); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if any pending mailbox message ++* to be handled ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { /* MBOX_ID_TOTAL_NUM = 1 */ ++ mboxRcvAllMsg(prAdapter, (ENUM_MBOX_ID_T) i); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to enqueue a single TX packet into CORE ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* prNativePacket Pointer of Native Packet ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_RESOURCES ++* WLAN_STATUS_INVALID_PACKET ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* get a free packet header */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo == NULL) ++ return WLAN_STATUS_RESOURCES; ++ ++ prMsduInfo->eSrc = TX_PACKET_OS; ++ ++ if (nicTxFillMsduInfo(prAdapter, prMsduInfo, prNativePacket) == FALSE) { ++ /* packet is not extractable */ ++ ++ /* fill fails */ ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_INVALID_PACKET); ++ ++ nicTxReturnMsduInfo(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_INVALID_PACKET; ++ } ++ /* enqueue to QM */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to flush pending TX packets in CORE ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return nicTxFlush(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function sends pending MSDU_INFO_T to MT6620 ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pfgHwAccess Pointer for tracking LP-OWN status ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ ASSERT(pfgHwAccess); ++ ++ /* <1> dequeue packets by txDequeuTxPackets() */ ++ /* Note: prMsduInfo is a packet list queue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prMsduInfo = qmDequeueTxPackets(prAdapter, &prTxCtrl->rTc); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prMsduInfo != NULL) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { ++ /* <2> Acquire LP-OWN if necessary */ ++ if (*pfgHwAccess == FALSE) { ++ *pfgHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prAdapter); ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ /* <3> send packet"s" to HIF */ ++ nicTxMsduInfoList(prAdapter, prMsduInfo); ++ ++ /* <4> update TC by txAdjustTcQuotas() */ ++ nicTxAdjustTcq(prAdapter); ++ } else ++ wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); /* free the packet */ ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to acquire power control from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* do driver own */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state *//* no use */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to release power control to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* do FW own */ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to report currently pending TX frames count ++* (command packets are not included) ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return number of pending TX frames ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ UINT_32 u4Num; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* number in prTxQueue + number in RX forward */ ++ u4Num = kalGetTxPendingFrameCount(prAdapter->prGlueInfo) + (UINT_32) (prTxCtrl->i4PendingFwdFrameCount); ++ ++ return u4Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to report current ACPI state ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return ACPI_STATE_D0 Normal Operation Mode ++* ACPI_STATE_D3 Suspend Mode ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rAcpiState; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to update current ACPI state only ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param ePowerState ACPI_STATE_D0 Normal Operation Mode ++* ACPI_STATE_D3 Suspend Mode ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState) ++{ ++ ASSERT(prAdapter); ++ ASSERT(ePowerState <= ACPI_STATE_D3); ++ ++ prAdapter->rAcpiState = ePowerState; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to query ECO version from HIFSYS CR ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return zero Unable to retrieve ECO version information ++* non-zero ECO version (1-based) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (nicVerifyChipID(prAdapter) == TRUE) ++ return prAdapter->ucRevID + 1; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to setting the default Tx Power configuration ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return zero Unable to retrieve ECO version information ++* non-zero ECO version (1-based) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 i; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ P_SET_TXPWR_CTRL_T prTxpwr; ++ ++ ASSERT(prGlueInfo); ++ ++ prTxpwr = &prGlueInfo->rTxPwr; ++ ++ prTxpwr->c2GLegacyStaPwrOffset = 0; ++ prTxpwr->c2GHotspotPwrOffset = 0; ++ prTxpwr->c2GP2pPwrOffset = 0; ++ prTxpwr->c2GBowPwrOffset = 0; ++ prTxpwr->c5GLegacyStaPwrOffset = 0; ++ prTxpwr->c5GHotspotPwrOffset = 0; ++ prTxpwr->c5GP2pPwrOffset = 0; ++ prTxpwr->c5GBowPwrOffset = 0; ++ prTxpwr->ucConcurrencePolicy = 0; ++ for (i = 0; i < 3; i++) ++ prTxpwr->acReserved1[i] = 0; ++ ++ for (i = 0; i < 14; i++) ++ prTxpwr->acTxPwrLimit2G[i] = 63; ++ ++ for (i = 0; i < 4; i++) ++ prTxpwr->acTxPwrLimit5G[i] = 63; ++ ++ for (i = 0; i < 2; i++) ++ prTxpwr->acReserved2[i] = 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* set preferred band configuration corresponding to network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eBand Given band ++* @param eNetTypeIndex Given Network Type ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eBand <= BAND_NUM); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ /* 1. set prefer band according to network type */ ++ prAdapter->aePreferBand[eNetTypeIndex] = eBand; ++ ++ /* 2. remove buffered BSS descriptors correspondingly */ ++ if (eBand == BAND_2G4) ++ scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_5G, eNetTypeIndex); ++ else if (eBand == BAND_5G) ++ scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_2G4, eNetTypeIndex); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* get channel information corresponding to specified network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eNetTypeIndex Given Network Type ++* ++* @return channel number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ return prBssInfo->ucPrimaryChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* get BSS descriptor information corresponding to specified network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eNetTypeIndex Given Network Type ++* ++* @return pointer to BSS_DESC_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ return prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; ++ ++ case NETWORK_TYPE_P2P_INDEX: ++ return NULL; ++ ++ case NETWORK_TYPE_BOW_INDEX: ++ return prAdapter->rWifiVar.rBowFsmInfo.prTargetBssDesc; ++ ++ default: ++ return NULL; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* check unconfigured system properties and generate related message on ++* scan list to notify users ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter) ++{ ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) || (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ const UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ BOOLEAN fgIsConfExist = TRUE; ++ BOOLEAN fgGenErrMsg = FALSE; ++ P_REG_INFO_T prRegInfo = NULL; ++ P_WLAN_BEACON_FRAME_T prBeacon = NULL; ++ P_IE_SSID_T prSsid = NULL; ++ UINT_32 u4ErrCode = 0; ++ UINT_8 aucErrMsg[32]; ++ PARAM_SSID_T rSsid; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ PARAM_RATES_EX rSupportedRates; ++#endif ++ ++ DEBUGFUNC("wlanCheckSystemConfiguration"); ++ ++ ASSERT(prAdapter); ++ ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) ++ if (kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) { ++ fgIsConfExist = FALSE; ++ fgGenErrMsg = TRUE; ++ } ++#endif ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ prRegInfo = kalGetConfiguration(prAdapter->prGlueInfo); ++ ++ if (fgIsConfExist == TRUE && (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion ++ || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ || prAdapter->fgIsPowerLimitTableValid == FALSE ++#endif ++ || (prAdapter->fgIsEmbbededMacAddrValid == FALSE && ++ (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) ++ || prRegInfo->ucTxPwrValid == 0)) ++ fgGenErrMsg = TRUE; ++#endif ++ ++ if (fgGenErrMsg == TRUE) { ++ prBeacon = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); ++ if (!prBeacon) { ++ ASSERT(FALSE); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* initialization */ ++ kalMemZero(prBeacon, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); ++ ++ /* prBeacon initialization */ ++ prBeacon->u2FrameCtrl = MAC_FRAME_BEACON; ++ COPY_MAC_ADDR(prBeacon->aucDestAddr, aucBCAddr); ++ COPY_MAC_ADDR(prBeacon->aucSrcAddr, aucZeroMacAddr); ++ COPY_MAC_ADDR(prBeacon->aucBSSID, aucZeroMacAddr); ++ prBeacon->u2BeaconInterval = 100; ++ prBeacon->u2CapInfo = CAP_INFO_ESS; ++ ++ /* prSSID initialization */ ++ prSsid = (P_IE_SSID_T) (&prBeacon->aucInfoElem[0]); ++ prSsid->ucId = ELEM_ID_SSID; ++ ++ /* rConfiguration initialization */ ++ rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ rConfiguration.u4BeaconPeriod = 100; ++ rConfiguration.u4ATIMWindow = 1; ++ rConfiguration.u4DSConfig = 2412; ++ rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ /* rSupportedRates initialization */ ++ kalMemZero(rSupportedRates, sizeof(PARAM_RATES_EX)); ++ } ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) ++#define NVRAM_ERR_MSG "NVRAM WARNING: Err = 0x01" ++ if ((kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) && (prBeacon) && (prSsid)) { ++ COPY_SSID(prSsid->aucSSID, prSsid->ucLength, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBeacon, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + prSsid->ucLength, ++ 1, 0); ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ nicAddScanResult(prAdapter, ++ prBeacon->aucBSSID, ++ &rSsid, ++ 0, ++ 0, ++ PARAM_NETWORK_TYPE_FH, ++ &rConfiguration, ++ NET_TYPE_INFRA, ++ rSupportedRates, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + prSsid->ucLength - ++ WLAN_MAC_MGMT_HEADER_LEN, (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); ++ } ++#endif ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++#define VER_ERR_MSG "NVRAM WARNING: Err = 0x%02X" ++ if ((fgIsConfExist == TRUE) && (prBeacon) && (prSsid)) { ++ if ((CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion ++ || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION)) ++ u4ErrCode |= NVRAM_ERROR_VERSION_MISMATCH; ++ ++ if (prRegInfo->ucTxPwrValid == 0) ++ u4ErrCode |= NVRAM_ERROR_INVALID_TXPWR; ++ ++ if (prAdapter->fgIsEmbbededMacAddrValid == FALSE && (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, ++ prRegInfo->aucMacAddr))) ++ u4ErrCode |= NVRAM_ERROR_INVALID_MAC_ADDR; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ if (prAdapter->fgIsPowerLimitTableValid == FALSE) ++ u4ErrCode |= NVRAM_POWER_LIMIT_TABLE_INVALID; ++#endif ++ if (u4ErrCode != 0) { ++ sprintf(aucErrMsg, VER_ERR_MSG, (unsigned int)u4ErrCode); ++ COPY_SSID(prSsid->aucSSID, prSsid->ucLength, aucErrMsg, strlen(aucErrMsg)); ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBeacon, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + ++ prSsid->ucLength, 1, 0); ++ ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ nicAddScanResult(prAdapter, ++ prBeacon->aucBSSID, ++ &rSsid, ++ 0, ++ 0, ++ PARAM_NETWORK_TYPE_FH, ++ &rConfiguration, ++ NET_TYPE_INFRA, ++ rSupportedRates, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + ++ prSsid->ucLength - WLAN_MAC_MGMT_HEADER_LEN, ++ (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); ++ } ++ } ++#endif ++ ++ if (fgGenErrMsg == TRUE) ++ cnmMemFree(prAdapter, prBeacon); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prStaRec, prTempStaRec; ++ P_PARAM_GET_STA_STATISTICS prQueryStaStatistics; ++ UINT_8 ucStaRecIdx; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ CMD_GET_STA_STATISTICS_T rQueryCmdStaStatistics; ++ UINT_8 ucIdx; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ do { ++ ASSERT(pvQueryBuffer); ++ ++ /* 4 1. Sanity test */ ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(PARAM_GET_STA_STA_STATISTICS)) { ++ *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ prQueryStaStatistics = (P_PARAM_GET_STA_STATISTICS) pvQueryBuffer; ++ *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ ++ /* 4 5. Get driver global QM counter */ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { ++ prQueryStaStatistics->au4TcAverageQueLen[ucIdx] = prQM->au4AverageQueLen[ucIdx]; ++ prQueryStaStatistics->au4TcCurrentQueLen[ucIdx] = prQM->au4CurrentTcResource[ucIdx]; ++ } ++ ++ /* 4 2. Get StaRec by MAC address */ ++ prStaRec = NULL; ++ ++ for (ucStaRecIdx = 0; ucStaRecIdx < CFG_NUM_OF_STA_RECORD; ucStaRecIdx++) { ++ prTempStaRec = &(prAdapter->arStaRec[ucStaRecIdx]); ++ if (prTempStaRec->fgIsValid && prTempStaRec->fgIsInUse) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prQueryStaStatistics->aucMacAddr)) { ++ prStaRec = prTempStaRec; ++ break; ++ } ++ } ++ } ++ ++ if (!prStaRec) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ prQueryStaStatistics->u4Flag |= BIT(0); ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ /* 4 3. Get driver statistics */ ++ DBGLOG(TX, INFO, "skbToDriver %lld, skbFreed: %lld\n", ++ prAdapter->prGlueInfo->u8SkbToDriver, ++ prAdapter->prGlueInfo->u8SkbFreed); ++ prAdapter->prGlueInfo->u8SkbFreed = 0; ++ prAdapter->prGlueInfo->u8SkbToDriver = 0; ++ ++ prQueryStaStatistics->u4TxTotalCount = prStaRec->u4TotalTxPktsNumber; ++ prQueryStaStatistics->u4TxExceedThresholdCount = prStaRec->u4ThresholdCounter; ++ prQueryStaStatistics->u4TxMaxTime = prStaRec->u4MaxTxPktsTime; ++ prQueryStaStatistics->u4TxMaxHifTime = prStaRec->u4MaxTxPktsHifTime; ++ if (prStaRec->u4TotalTxPktsNumber) { ++ prQueryStaStatistics->u4TxAverageProcessTime = ++ (prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber); ++ prQueryStaStatistics->u4TxAverageHifTime = ++ (prStaRec->u4TotalTxPktsHifTime / prStaRec->u4TotalTxPktsNumber); ++ } else ++ prQueryStaStatistics->u4TxAverageProcessTime = 0; ++ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { ++ prQueryStaStatistics->au4TcResourceEmptyCount[ucIdx] = ++ prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx]; ++ /* Reset */ ++ prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceBackCount[ucIdx] = ++ prQM->au4QmTcResourceBackCounter[ucIdx]; ++ prQM->au4QmTcResourceBackCounter[ucIdx] = 0; ++ ++ prQueryStaStatistics->au4DequeueNoTcResource[ucIdx] = ++ prQM->au4DequeueNoTcResourceCounter[ucIdx]; ++ prQM->au4DequeueNoTcResourceCounter[ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceUsedCount[ucIdx] = ++ prQM->au4ResourceUsedCounter[ucIdx]; ++ prQM->au4ResourceUsedCounter[ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceWantedCount[ucIdx] = ++ prQM->au4ResourceWantedCounter[ucIdx]; ++ prQM->au4ResourceWantedCounter[ucIdx] = 0; ++ } ++ ++ prQueryStaStatistics->u4EnqueueCounter = prQM->u4EnqeueuCounter; ++ prQueryStaStatistics->u4DequeueCounter = prQM->u4DequeueCounter; ++ prQueryStaStatistics->u4EnqueueStaCounter = prStaRec->u4EnqeueuCounter; ++ prQueryStaStatistics->u4DequeueStaCounter = prStaRec->u4DeqeueuCounter; ++ ++ prQueryStaStatistics->IsrCnt = prGlueInfo->IsrCnt - prGlueInfo->IsrPreCnt; ++ prQueryStaStatistics->IsrPassCnt = prGlueInfo->IsrPassCnt - prGlueInfo->IsrPrePassCnt; ++ prQueryStaStatistics->TaskIsrCnt = prGlueInfo->TaskIsrCnt - prGlueInfo->TaskPreIsrCnt; ++ ++ prQueryStaStatistics->IsrAbnormalCnt = prGlueInfo->IsrAbnormalCnt; ++ prQueryStaStatistics->IsrSoftWareCnt = prGlueInfo->IsrSoftWareCnt; ++ prQueryStaStatistics->IsrRxCnt = prGlueInfo->IsrRxCnt; ++ prQueryStaStatistics->IsrTxCnt = prGlueInfo->IsrTxCnt; ++ ++ /* 4 4.1 Reset statistics */ ++ prStaRec->u4ThresholdCounter = 0; ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsHifTime = 0; ++ ++ prStaRec->u4EnqeueuCounter = 0; ++ prStaRec->u4DeqeueuCounter = 0; ++ ++ prQM->u4EnqeueuCounter = 0; ++ prQM->u4DequeueCounter = 0; ++ ++ prGlueInfo->IsrPreCnt = prGlueInfo->IsrCnt; ++ prGlueInfo->IsrPrePassCnt = prGlueInfo->IsrPassCnt; ++ prGlueInfo->TaskPreIsrCnt = prGlueInfo->TaskIsrCnt; ++ prGlueInfo->IsrAbnormalCnt = 0; ++ prGlueInfo->IsrSoftWareCnt = 0; ++ prGlueInfo->IsrRxCnt = 0; ++ prGlueInfo->IsrTxCnt = 0; ++#endif ++ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) ++ prQueryStaStatistics->au4TcQueLen[ucIdx] = prStaRec->arTxQueue[ucIdx].u4NumElem; ++ ++ rResult = WLAN_STATUS_SUCCESS; ++ ++ /* 4 6. Ensure FW supports get station link status */ ++ if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { ++ ++ rQueryCmdStaStatistics.ucIndex = prStaRec->ucIndex; ++ COPY_MAC_ADDR(rQueryCmdStaStatistics.aucMacAddr, prQueryStaStatistics->aucMacAddr); ++ rQueryCmdStaStatistics.ucReadClear = TRUE; ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STA_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStaStatistics, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_STA_STATISTICS_T), ++ (PUINT_8)&rQueryCmdStaStatistics, ++ pvQueryBuffer, u4QueryBufferLen); ++ ++ prQueryStaStatistics->u4Flag |= BIT(1); ++ } else { ++ rResult = WLAN_STATUS_NOT_SUPPORTED; ++ } ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++WLAN_STATUS ++wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ /* P_PARAM_GET_CHN_LOAD prQueryChnLoad; */ ++ P_PARAM_GET_LTE_MODE prLteMode; ++ CMD_GET_LTE_SAFE_CHN_T rQuery_LTE_SAFE_CHN; ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]wlanoidQueryACSChannelList\n"); ++ do { ++ ASSERT(pvQueryBuffer); ++ ++ /* 4 1. Sanity test */ ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ prLteMode = (P_PARAM_GET_LTE_MODE) pvQueryBuffer; ++ ++ /* 4 3. Ensure FW supports get station link status */ ++#if 0 ++ if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ rCmdAccessReg.u4Address = 0xFFFFFFFF; ++ rCmdAccessReg.u4Data = ELEM_RM_TYPE_ACS_CHN; ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ TRUE, ++ TRUE, ++ /* The handler to receive firmware notification */ ++ nicCmdEventQueryChannelLoad, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8)&rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); ++ ++ prQueryChnLoad->u4Flag |= BIT(1); ++ } else { ++ rResult = WLAN_STATUS_NOT_SUPPORTED; ++ } ++#endif ++ /* 4 4.Avoid LTE Channels */ ++ prLteMode->u4Flags &= BIT(0); ++ /*if(prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) */ { ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LTE_CHN, ++ FALSE, ++ TRUE, ++ /* Query ID */ ++ TRUE, ++ /* The handler to receive firmware notification */ ++ nicCmdEventQueryLTESafeChn, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_LTE_SAFE_CHN_T), ++ (PUINT_8)&rQuery_LTE_SAFE_CHN, ++ pvQueryBuffer, u4QueryBufferLen); ++ ++ DBGLOG(P2P, INFO, "[Auto Channel] Get LTE Channels\n"); ++ prLteMode->u4Flags |= BIT(1); ++ } ++ ++ /* 4 5. Calc the value */ ++ ++ DBGLOG(P2P, INFO, "[Auto Channel] Candidated Channels\n"); ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++#endif ++#if CFG_SUPPORT_CFG_FILE ++ ++P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 i; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ASSERT(pucKey); ++ ++ prWlanCfgEntry = NULL; ++ ++ for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; ++ if (prWlanCfgEntry->aucKey[0] != '\0') { ++ DBGLOG(INIT, LOUD, "compare key %s saved key %s\n", pucKey, prWlanCfgEntry->aucKey); ++ if (kalStrniCmp(pucKey, prWlanCfgEntry->aucKey, WLAN_CFG_KEY_LEN_MAX - 1) == 0) ++ return prWlanCfgEntry; ++ } ++ } ++ ++ DBGLOG(INIT, LOUD, "wifi config there is no entry \'%s\'\n", pucKey); ++ return NULL; ++ ++} ++ ++WLAN_STATUS wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ASSERT(pucValue); ++ ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ kalStrnCpy(pucValue, prWlanCfgEntry->aucValue, WLAN_CFG_VALUE_LEN_MAX - 1); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (pucValueDef) ++ kalStrnCpy(pucValue, pucValueDef, WLAN_CFG_VALUE_LEN_MAX - 1); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef) ++{ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 u4Value; ++ INT_32 u4Ret; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ u4Value = u4ValueDef; ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ u4Ret = kalkStrtou32(prWlanCfgEntry->aucValue, 0, &u4Value); ++ if (u4Ret) ++ DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue u4Ret=%u\n", u4Ret); ++ /* u4Value = kalStrtoul(prWlanCfgEntry->aucValue, NULL, 0); */ ++ } ++ ++ return u4Value; ++} ++ ++INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef) ++{ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ INT_32 i4Value; ++ INT_32 i4Ret; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ i4Value = i4ValueDef; ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ i4Ret = kalkStrtos32(prWlanCfgEntry->aucValue, 0, &i4Value); ++ /* i4Ret = kalStrtol(prWlanCfgEntry->aucValue, NULL, 0); */ ++ if (i4Ret) ++ DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue i4Ret=%u\n\r", i4Ret); ++ } ++ ++ return i4Value; ++} ++ ++WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 u4EntryIndex; ++ UINT_32 i; ++ UINT_8 ucExist; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ASSERT(prWlanCfg); ++ ASSERT(pucKey); ++ ++ /* Find the exist */ ++ ucExist = 0; ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (!prWlanCfgEntry) { ++ /* Find the empty */ ++ for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; ++ if (prWlanCfgEntry->aucKey[0] == '\0') ++ break; ++ } ++ ++ u4EntryIndex = i; ++ if (u4EntryIndex < WLAN_CFG_ENTRY_NUM_MAX) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[u4EntryIndex]; ++ kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); ++ } else { ++ prWlanCfgEntry = NULL; ++ DBGLOG(INIT, ERROR, "wifi config there is no empty entry\n"); ++ } ++ } /* !prWlanCfgEntry */ ++ else ++ ucExist = 1; ++ ++ if (prWlanCfgEntry) { ++ if (ucExist == 0) { ++ kalStrnCpy(prWlanCfgEntry->aucKey, pucKey, WLAN_CFG_KEY_LEN_MAX - 1); ++ prWlanCfgEntry->aucKey[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; ++ } ++ ++ if (pucValue && pucValue[0] != '\0') { ++ kalStrnCpy(prWlanCfgEntry->aucValue, pucValue, WLAN_CFG_VALUE_LEN_MAX - 1); ++ prWlanCfgEntry->aucValue[WLAN_CFG_VALUE_LEN_MAX - 1] = '\0'; ++ ++ if (ucExist) { ++ if (prWlanCfgEntry->pfSetCb) ++ prWlanCfgEntry->pfSetCb(prAdapter, ++ prWlanCfgEntry->aucKey, ++ prWlanCfgEntry->aucValue, prWlanCfgEntry->pPrivate, 0); ++ } ++ } else { ++ /* Call the pfSetCb if value is empty ? */ ++ /* remove the entry if value is empty */ ++ kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); ++ } ++ ++ } ++ /* prWlanCfgEntry */ ++ if (prWlanCfgEntry) { ++ DBGLOG(INIT, LOUD, "Set wifi config exist %u \'%s\' \'%s\'\n", ++ ucExist, prWlanCfgEntry->aucKey, prWlanCfgEntry->aucValue); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (pucKey) ++ DBGLOG(INIT, ERROR, "Set wifi config error key \'%s\'\n", pucKey); ++ if (pucValue) ++ DBGLOG(INIT, ERROR, "Set wifi config error value \'%s\'\n", pucValue); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++WLAN_STATUS ++wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ASSERT(prWlanCfg); ++ ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ prWlanCfgEntry->pfSetCb = pfSetCb; ++ prWlanCfgEntry->pPrivate = pPrivate; ++ } ++ ++ if (prWlanCfgEntry) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value) ++{ ++ ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_8 aucBuf[WLAN_CFG_VALUE_LEN_MAX]; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ kalMemZero(aucBuf, sizeof(aucBuf)); ++ ++ kalSnprintf(aucBuf, WLAN_CFG_VALUE_LEN_MAX, "0x%x", (unsigned int)u4Value); ++ ++ return wlanCfgSet(prAdapter, pucKey, aucBuf, 0); ++} ++ ++enum { ++ STATE_EOF = 0, ++ STATE_TEXT = 1, ++ STATE_NEWLINE = 2 ++}; ++ ++struct WLAN_CFG_PARSE_STATE_S { ++ CHAR *ptr; ++ CHAR *text; ++ INT_32 nexttoken; ++ UINT_32 maxSize; ++}; ++ ++INT_32 wlanCfgFindNextToken(struct WLAN_CFG_PARSE_STATE_S *state) ++{ ++ CHAR *x = state->ptr; ++ CHAR *s; ++ ++ if (state->nexttoken) { ++ INT_32 t = state->nexttoken; ++ ++ state->nexttoken = 0; ++ return t; ++ } ++ ++ for (;;) { ++ switch (*x) { ++ case 0: ++ state->ptr = x; ++ return STATE_EOF; ++ case '\n': ++ x++; ++ state->ptr = x; ++ return STATE_NEWLINE; ++ case ' ': ++ case '\t': ++ case '\r': ++ x++; ++ continue; ++ case '#': ++ while (*x && (*x != '\n')) ++ x++; ++ if (*x == '\n') { ++ state->ptr = x + 1; ++ return STATE_NEWLINE; ++ } ++ state->ptr = x; ++ return STATE_EOF; ++ default: ++ goto text; ++ } ++ } ++ ++textdone: ++ state->ptr = x; ++ *s = 0; ++ return STATE_TEXT; ++text: ++ state->text = s = x; ++textresume: ++ for (;;) { ++ switch (*x) { ++ case 0: ++ goto textdone; ++ case ' ': ++ case '\t': ++ case '\r': ++ x++; ++ goto textdone; ++ case '\n': ++ state->nexttoken = STATE_NEWLINE; ++ x++; ++ goto textdone; ++ case '"': ++ x++; ++ for (;;) { ++ switch (*x) { ++ case 0: ++ /* unterminated quoted thing */ ++ state->ptr = x; ++ return STATE_EOF; ++ case '"': ++ x++; ++ goto textresume; ++ default: ++ *s++ = *x++; ++ } ++ } ++ break; ++ case '\\': ++ x++; ++ switch (*x) { ++ case 0: ++ goto textdone; ++ case 'n': ++ *s++ = '\n'; ++ break; ++ case 'r': ++ *s++ = '\r'; ++ break; ++ case 't': ++ *s++ = '\t'; ++ break; ++ case '\\': ++ *s++ = '\\'; ++ break; ++ case '\r': ++ /* \ -> line continuation */ ++ if (x[1] != '\n') { ++ x++; ++ continue; ++ } ++ case '\n': ++ /* \ -> line continuation */ ++ x++; ++ /* eat any extra whitespace */ ++ while ((*x == ' ') || (*x == '\t')) ++ x++; ++ continue; ++ default: ++ /* unknown escape -- just copy */ ++ *s++ = *x++; ++ } ++ continue; ++ default: ++ *s++ = *x++; ++ } ++ } ++ return STATE_EOF; ++} ++ ++WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]) ++{ ++ struct WLAN_CFG_PARSE_STATE_S state; ++ CHAR **args; ++ INT_32 nargs; ++ ++ if (cmdLine == NULL || argc == NULL || argv == NULL) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ args = argv; ++ nargs = 0; ++ state.ptr = cmdLine; ++ state.nexttoken = 0; ++ state.maxSize = 0; ++ ++ if (kalStrnLen(cmdLine, 512) >= 512) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ for (;;) { ++ switch (wlanCfgFindNextToken(&state)) { ++ case STATE_EOF: ++ goto exit; ++ case STATE_NEWLINE: ++ goto exit; ++ case STATE_TEXT: ++ if (nargs < WLAN_CFG_ARGV_MAX) ++ args[nargs++] = state.text; ++ break; ++ } ++ } ++ ++exit: ++ *argc = nargs; ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanCfgParseAddEntry(IN P_ADAPTER_T prAdapter, ++ PUINT_8 pucKeyHead, PUINT_8 pucKeyTail, PUINT_8 pucValueHead, PUINT_8 pucValueTail) ++{ ++ ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ UINT_32 u4Len; ++ ++ kalMemZero(aucKey, sizeof(aucKey)); ++ kalMemZero(aucValue, sizeof(aucValue)); ++ ++ if ((pucKeyHead == NULL) ++ || (pucValueHead == NULL) ++ ) ++ return WLAN_STATUS_FAILURE; ++ ++ if (pucKeyTail) { ++ if (pucKeyHead > pucKeyTail) ++ return WLAN_STATUS_FAILURE; ++ u4Len = pucKeyTail - pucKeyHead + 1; ++ } else ++ u4Len = kalStrnLen(pucKeyHead, WLAN_CFG_KEY_LEN_MAX - 1); ++ ++ if (u4Len >= WLAN_CFG_KEY_LEN_MAX) ++ u4Len = WLAN_CFG_KEY_LEN_MAX - 1; ++ ++ if (u4Len < WLAN_CFG_VALUE_LEN_MAX) ++ kalStrnCpy(aucKey, pucKeyHead, u4Len); ++ else ++ DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); ++ ++ if (pucValueTail) { ++ if (pucValueHead > pucValueTail) ++ return WLAN_STATUS_FAILURE; ++ u4Len = pucValueTail - pucValueHead + 1; ++ } else ++ u4Len = kalStrnLen(pucValueHead, WLAN_CFG_VALUE_LEN_MAX - 1); ++ ++ if (u4Len >= WLAN_CFG_VALUE_LEN_MAX) ++ u4Len = WLAN_CFG_VALUE_LEN_MAX - 1; ++ ++ if (u4Len < WLAN_CFG_VALUE_LEN_MAX) ++ kalStrnCpy(aucValue, pucValueHead, u4Len); ++ else ++ DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); ++ ++ return wlanCfgSet(prAdapter, aucKey, aucValue, 0); ++} ++ ++enum { ++ WAIT_KEY_HEAD = 0, ++ WAIT_KEY_TAIL, ++ WAIT_VALUE_HEAD, ++ WAIT_VALUE_TAIL, ++ WAIT_COMMENT_TAIL ++}; ++ ++WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen) ++{ ++ ++ struct WLAN_CFG_PARSE_STATE_S state; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; ++ CHAR **args; ++ INT_32 nargs; ++ ++ if (pucConfigBuf == NULL) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ if (kalStrnLen(pucConfigBuf, 4000) >= 4000) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ if (u4ConfigBufLen == 0) ++ return WLAN_STATUS_FAILURE; ++ args = apcArgv; ++ nargs = 0; ++ state.ptr = pucConfigBuf; ++ state.nexttoken = 0; ++ state.maxSize = u4ConfigBufLen; ++ ++ for (;;) { ++ switch (wlanCfgFindNextToken(&state)) { ++ case STATE_EOF: ++ if (nargs > 1) ++ wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); ++ goto exit; ++ case STATE_NEWLINE: ++ if (nargs > 1) ++ wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); ++ nargs = 0; ++ break; ++ case STATE_TEXT: ++ if (nargs < WLAN_CFG_ARGV_MAX) ++ args[nargs++] = state.text; ++ break; ++ } ++ } ++ ++exit: ++ return WLAN_STATUS_SUCCESS; ++ ++#if 0 ++ /* Old version */ ++ UINT_32 i; ++ UINT_8 c; ++ PUINT_8 pbuf; ++ UINT_8 ucState; ++ PUINT_8 pucKeyTail = NULL; ++ PUINT_8 pucKeyHead = NULL; ++ PUINT_8 pucValueHead = NULL; ++ PUINT_8 pucValueTail = NULL; ++ ++ ucState = WAIT_KEY_HEAD; ++ pbuf = pucConfigBuf; ++ ++ for (i = 0; i < u4ConfigBufLen; i++) { ++ c = pbuf[i]; ++ if (c == '\r' || c == '\n') { ++ ++ if (ucState == WAIT_VALUE_TAIL) { ++ /* Entry found */ ++ if (pucValueHead) ++ wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, ++ pucValueHead, pucValueTail); ++ } ++ ucState = WAIT_KEY_HEAD; ++ pucKeyTail = NULL; ++ pucKeyHead = NULL; ++ pucValueHead = NULL; ++ pucValueTail = NULL; ++ ++ } else if (c == '=') { ++ if (ucState == WAIT_KEY_TAIL) { ++ pucKeyTail = &pbuf[i - 1]; ++ ucState = WAIT_VALUE_HEAD; ++ } ++ } else if (c == ' ' || c == '\t') { ++ if (ucState == WAIT_KEY_HEAD) ++ ; ++ else if (ucState == WAIT_KEY_TAIL) { ++ pucKeyTail = &pbuf[i - 1]; ++ ucState = WAIT_VALUE_HEAD; ++ } ++ } else { ++ ++ if (c == '#') { ++ /* comments */ ++ if (ucState == WAIT_KEY_HEAD) ++ ucState = WAIT_COMMENT_TAIL; ++ else if (ucState == WAIT_VALUE_TAIL) ++ pucValueTail = &pbuf[i]; ++ ++ } else { ++ if (ucState == WAIT_KEY_HEAD) { ++ pucKeyHead = &pbuf[i]; ++ pucKeyTail = &pbuf[i]; ++ ucState = WAIT_KEY_TAIL; ++ } else if (ucState == WAIT_VALUE_HEAD) { ++ pucValueHead = &pbuf[i]; ++ pucValueTail = &pbuf[i]; ++ ucState = WAIT_VALUE_TAIL; ++ } else if (ucState == WAIT_VALUE_TAIL) ++ pucValueTail = &pbuf[i]; ++ } ++ } ++ ++ } /* for */ ++ ++ if (ucState == WAIT_VALUE_TAIL) { ++ /* Entry found */ ++ if (pucValueTail) ++ wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, pucValueHead, pucValueTail); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++#endif ++ ++#if CFG_SUPPORT_CFG_FILE ++WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags) ++{ ++ P_WLAN_CFG_T prWlanCfg; ++ /* P_WLAN_CFG_ENTRY_T prWlanCfgEntry; */ ++ prAdapter->prWlanCfg = &prAdapter->rWlanCfg; ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ kalMemZero(prWlanCfg, sizeof(WLAN_CFG_T)); ++ ASSERT(prWlanCfg); ++ prWlanCfg->u4WlanCfgEntryNumMax = WLAN_CFG_ENTRY_NUM_MAX; ++ prWlanCfg->u4WlanCfgKeyLenMax = WLAN_CFG_KEY_LEN_MAX; ++ prWlanCfg->u4WlanCfgValueLenMax = WLAN_CFG_VALUE_LEN_MAX; ++#if 0 ++ DBGLOG(INIT, INFO, "Init wifi config len %u max entry %u\n", u4ConfigBufLen, prWlanCfg->u4WlanCfgEntryNumMax); ++#endif ++ /* self test */ ++ wlanCfgSet(prAdapter, "ConfigValid", "0x123", 0); ++ if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 0x123) ++ DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); ++ wlanCfgSet(prAdapter, "ConfigValid", "1", 0); ++ if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 1) ++ DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); ++#if 0 /* soc chip didn't support these parameters now */ ++ /* Add initil config */ ++ /* use g,wlan,p2p,ap as prefix */ ++ /* Don't set cb here , overwrite by another api */ ++ wlanCfgSet(prAdapter, "TxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "RxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "RxBeamformee", "1", 0); ++ wlanCfgSet(prAdapter, "RoamTh1", "100", 0); ++ wlanCfgSet(prAdapter, "RoamTh2", "150", 0); ++ wlanCfgSet(prAdapter, "wlanRxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "apRxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "p2pRxLdpc", "1", 0); ++#endif ++ /* Parse the pucConfigBuff */ ++ ++ if (pucConfigBuf && (u4ConfigBufLen > 0)) ++ wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigBufLen); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to initialize WLAN feature options ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanCfgApply(IN P_ADAPTER_T prAdapter) ++{ ++#define STR2BYTE(s) (((((PUINT_8)s)[0]-'0')*10)+(((PUINT_8)s)[1]-'0')) ++ CHAR aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; ++ P_REG_INFO_T prRegInfo = &prAdapter->prGlueInfo->rRegInfo; ++ P_TX_PWR_PARAM_T prTxPwr = &prRegInfo->rTxPwr; ++ ++ kalMemZero(aucValue, sizeof(aucValue)); ++ DBGLOG(INIT, LOUD, "CFG_FILE: Apply Config File\n"); ++ /* Apply COUNTRY Config */ ++ if (wlanCfgGet(prAdapter, "country", aucValue, "", 0) == WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Found Country Key, Value=%s\n", aucValue); ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = ++ (((UINT_16) aucValue[0]) << 8) | ((UINT_16) aucValue[1]); ++ prRegInfo->au2CountryCode[0] = aucValue[0]; ++ prRegInfo->au2CountryCode[1] = aucValue[1]; ++ } ++ prWifiVar->ucApWpsMode = (UINT_8) wlanCfgGetUint32(prAdapter, "ApWpsMode", 0); ++ prWifiVar->ucCert11nMode = (UINT_8)wlanCfgGetUint32(prAdapter, "Cert11nMode", 0); ++ DBGLOG(INIT, LOUD, "CFG_FILE: ucApWpsMode = %u, ucCert11nMode = %u\n", ++ prWifiVar->ucApWpsMode, prWifiVar->ucCert11nMode); ++ if (prWifiVar->ucCert11nMode == 1) ++ nicWriteMcr(prAdapter, 0x11111115 , 1); ++ ++ if (wlanCfgGet(prAdapter, "5G_support", aucValue, "", 0) == WLAN_STATUS_SUCCESS) ++ prRegInfo->ucSupport5GBand = (*aucValue == 'y') ? 1 : 0; ++ if (wlanCfgGet(prAdapter, "TxPower2G4CCK", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 2) { ++ prTxPwr->cTxPwr2G4Cck = STR2BYTE(aucValue); ++ DBGLOG(INIT, LOUD, "2.4G cck=%d\n", prTxPwr->cTxPwr2G4Cck); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4OFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 10) { ++ prTxPwr->cTxPwr2G4OFDM_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4OFDM_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4OFDM_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4OFDM_48Mbps = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4OFDM_54Mbps = STR2BYTE(aucValue + 8); ++ DBGLOG(INIT, LOUD, "2.4G OFDM=%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4OFDM_BPSK, prTxPwr->cTxPwr2G4OFDM_QPSK, ++ prTxPwr->cTxPwr2G4OFDM_16QAM, prTxPwr->cTxPwr2G4OFDM_48Mbps, ++ prTxPwr->cTxPwr2G4OFDM_54Mbps); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4HT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr2G4HT20_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4HT20_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4HT20_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4HT20_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4HT20_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr2G4HT20_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "2.4G HT20=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4HT20_BPSK, prTxPwr->cTxPwr2G4HT20_QPSK, ++ prTxPwr->cTxPwr2G4HT20_16QAM, prTxPwr->cTxPwr2G4HT20_MCS5, ++ prTxPwr->cTxPwr2G4HT20_MCS6, prTxPwr->cTxPwr2G4HT20_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4HT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr2G4HT40_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4HT40_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4HT40_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4HT40_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4HT40_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr2G4HT40_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "2.4G HT40=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4HT40_BPSK, prTxPwr->cTxPwr2G4HT40_QPSK, ++ prTxPwr->cTxPwr2G4HT40_16QAM, prTxPwr->cTxPwr2G4HT40_MCS5, ++ prTxPwr->cTxPwr2G4HT40_MCS6, prTxPwr->cTxPwr2G4HT40_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GOFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 10) { ++ prTxPwr->cTxPwr5GOFDM_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GOFDM_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GOFDM_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GOFDM_48Mbps = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GOFDM_54Mbps = STR2BYTE(aucValue + 8); ++ DBGLOG(INIT, LOUD, "5G OFDM=%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GOFDM_BPSK, prTxPwr->cTxPwr5GOFDM_QPSK, ++ prTxPwr->cTxPwr5GOFDM_16QAM, prTxPwr->cTxPwr5GOFDM_48Mbps, ++ prTxPwr->cTxPwr5GOFDM_54Mbps); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GHT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr5GHT20_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GHT20_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GHT20_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GHT20_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GHT20_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr5GHT20_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "5G HT20=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GHT20_BPSK, prTxPwr->cTxPwr5GHT20_QPSK, ++ prTxPwr->cTxPwr5GHT20_16QAM, prTxPwr->cTxPwr5GHT20_MCS5, prTxPwr->cTxPwr5GHT20_MCS6, ++ prTxPwr->cTxPwr5GHT20_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GHT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr5GHT40_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GHT40_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GHT40_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GHT40_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GHT40_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr5GHT40_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "5G HT40=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GHT40_BPSK, prTxPwr->cTxPwr5GHT40_QPSK, ++ prTxPwr->cTxPwr5GHT40_16QAM, prTxPwr->cTxPwr5GHT40_MCS5, prTxPwr->cTxPwr5GHT40_MCS6, ++ prTxPwr->cTxPwr5GHT40_MCS7); ++ } ++ /* TODO: Apply other Config */ ++} ++#endif /* CFG_SUPPORT_CFG_FILE */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c +new file mode 100644 +index 000000000000..993ff061ed20 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c +@@ -0,0 +1,11050 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_oid.c#5 ++*/ ++ ++/*! \file wlanoid.c ++ \brief This file contains the WLAN OID processing routines of Windows driver for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_oid.c ++** ++** 09 05 2013 cp.wu ++** isolate logic regarding roaming & reassociation ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 09 02 2013 cp.wu ++** add path to handle reassociation request ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * using the wlanSendSetQueryCmd to set the tx power control cmd. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * change the set tx power cmd name. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 12 20 2011 cp.wu ++ * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information ++ * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO ++ * to expose version information ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to ++ * asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state ++ * without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 21 2011 cp.wu ++ * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing ++ * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer ++ * add more checking for such cases ++ * ++ * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. ++ * add some tweaking to protect such cases because that net device has become invalid. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 11 09 2011 george.huang ++ * [WCXRP00000871] [MT6620 Wi-Fi][FW] Include additional wakeup condition, which is by ++ * consequent DTIM unicast indication add XLOG for Set PS mode entry ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 11 02 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add RDD certification features. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 15 2011 tsaiyuan.hsu ++ * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA ++ * correct fifo full control from query to set operation for CTIA. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 17 2011 tsaiyuan.hsu ++ * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA ++ * add system config for CTIA. ++ * ++ * 08 15 2011 george.huang ++ * [MT6620 Wi-Fi][FW] handle TSF drift for connection detection ++ * . ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, ++ * for customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 05 02 2011 eddie.chen ++ * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control ++ * Fix compile warning. ++ * ++ * 04 29 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * . ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * add more debug message ++ * ++ * 04 26 2011 eddie.chen ++ * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control ++ * Add rx path profiling. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 31 2011 puff.wen ++ * NULL ++ * . ++ * ++ * 03 29 2011 puff.wen ++ * NULL ++ * Add chennel switch for stress test ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning ++ * surpress klock warning with code path rewritten ++ * ++ * 03 24 2011 wh.su ++ * [WCXRP00000595] [MT6620 Wi-Fi][Driver] at CTIA indicate disconnect to make the ps profile can apply ++ * use disconnect event instead of ais abort for CTIA testing. ++ * ++ * 03 23 2011 george.huang ++ * [WCXRP00000586] [MT6620 Wi-Fi][FW] Modify for blocking absence request right after connected ++ * revise for CTIA power mode setting ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 17 2011 yarco.yang ++ * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage ++ * . ++ * ++ * 03 15 2011 george.huang ++ * [WCXRP00000557] [MT6620 Wi-Fi] Support current consumption test mode commands ++ * Support current consumption measurement mode command ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 04 2011 cp.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * surpress compile warning occurred when compiled by GNU compiler collection. ++ * ++ * 03 03 2011 wh.su ++ * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue ++ * fixed the enter ctia test mode issue. ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Update sigma CAPI for U-APSD setting ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as ++ * initial RSSI right after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting ++ * Support CTIA power mode setting. ++ * ++ * 01 26 2011 wh.su ++ * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux ++ * adding the SW cmd ioctl support, use set/get structure ioctl. ++ * ++ * 01 25 2011 cp.wu ++ * [WCXRP00000394] [MT6620 Wi-Fi][Driver] Count space needed for generating error message in ++ * scanning list into buffer size checking ++ * when doing size prechecking, check illegal MAC address as well ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * check if allow to switch to IBSS mode via concurrent module before setting to IBSS mode ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000342] [MT6620 Wi-Fi][Driver] show error code in scanning list when MAC address is not ++ * correctly configured in NVRAM ++ * show error code 0x10 when MAC address in NVRAM is not configured correctly. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 28 2010 george.huang ++ * [WCXRP00000232] [MT5931 Wi-Fi][FW] Modifications for updated HW power on sequence and related design ++ * support WMM-PS U-APSD AC assignment. ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 16 2010 cp.wu ++ * [WCXRP00000268] [MT6620 Wi-Fi][Driver] correction for WHQL failed items ++ * correction for OID_802_11_NETWORK_TYPES_SUPPORTED handlers ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork ++ * suppress warning reported by Klockwork. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 30 2010 cp.wu ++ * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 ++ * . ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only ++ * with necessary data field checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available ++ * but extra scan result used to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 21 2010 wh.su ++ * [WCXRP00000192] [MT6620 Wi-Fi][Driver] Fixed fail trying to build connection with Security ++ * AP while enable WAPI message check ++ * Not set the wapi mode while the wapi assoc info set non-wapi ie. ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying ++ * current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 22 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * dos2unix conversion. ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android complete ++ * implementation of Android NVRAM access ++ * ++ * 10 06 2010 yuche.tsai ++ * NULL ++ * Update SLT 5G Test Channel Set. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 06 2010 yuche.tsai ++ * NULL ++ * Update For SLT 5G Test Channel Selection Rule. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form ++ * Query buffer size needs to be enlarged due to result is filled in 4-bytes alignment boundary ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and ++ * replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form ++ * Extend result length to multiples of 4-bytes ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Update SLT due to API change of SCAN module. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 yuche.tsai ++ * NULL ++ * Refine SLT IO control handler. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Modify the rescan condition. ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 27 2010 chinglan.wang ++ * NULL ++ * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * . ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * update params defined in CMD_SET_NETWORK_ADDRESS_LIST ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * fix for check build WHQL testing: ++ * 1) do not assert query buffer if indicated buffer length is zero ++ * 2) sdio.c has bugs which cause freeing same pointer twice ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * bypass u4FuncData for RF-Test query request as well. ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 26 2010 cp.wu ++ * ++ * re-commit code logic being overwriten. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one ++ * 2) refine disconnection behaviour when issued during BG-SCAN process ++ * ++ * 07 19 2010 wh.su ++ * ++ * modify the auth and encry status variable. ++ * ++ * 07 16 2010 cp.wu ++ * ++ * remove work-around in case SCN is not available. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. ++ * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add SCN compilation option. ++ * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement SCAN-REQUEST oid as mailbox message dispatching. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * adding the compiling flag for oid pmkid. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * simplify cmd packet sending for RF test and MCR access OIDs ++ * ++ * 05 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable radio even when STA is not associated. ++ * ++ * 05 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct 2 OID behaviour to meet WHQL requirement. ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct BSSID_LIST oid when radio if turned off. ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll ++ * 2) correct address list parsing ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable wlanoidSetNetworkAddress() temporally. ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * some OIDs should be DRIVER_CORE instead of GLUE_EXTENSION ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. ++ * 2) finish statistics OIDs ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct wlanoidSet802dot11PowerSaveProfile implementation. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) enable CMD/EVENT ver 0.9 definition. ++ * 2) abandon use of ENUM_MEDIA_STATE ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add dissassocation support for wpa supplicant ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct return value. ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * for disassociation, still use parameter with current setting. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * for disassociation, generate a WZC-compatible invalid SSID. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * associate to illegal SSID when handling OID_802_11_DISASSOCIATE ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * reserve field of privacy filter and RTS threshold setting. ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00003830]add OID_802_11_PRIVACY_FILTER support ++ * enable RX filter OID ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add ioctl of power management ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * 2) command sequence number is now increased atomically ++ * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_CONFIGURATION query for infrastructure mode. ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) remove unused spin lock declaration ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * are done in adapter layer. ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)improve none-glue code portability ++ * (2) disable set Multicast address during atomic context ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve glue code portability ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * the frequency is used for adhoc connection only ++ * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list ++ * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result ++ * ++ * 03 19 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * adding the check for pass WHQL test item. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++* 03 16 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * fixed some whql pre-test fail case. ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. ++ * ++ * 02 24 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Don't needed to check the auth mode, WHQL testing not specific at auth wpa2. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not check SSID validity anymore. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * 2. follow MSDN defined behavior when associates to another AP ++ * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move ucCmdSeqNum as instance variable ++ * ++ * 02 04 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when OID_CUSTOM_OID_INTERFACE_VERSION is queried, do modify connection states ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * 4. correct some HAL implementation ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * OID_802_11_RSSI, ++ * OID_802_11_RSSI_TRIGGER, ++ * OID_802_11_STATISTICS, ++ * OID_802_11_DISASSOCIATE, ++ * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not fill ucJoinOnly currently ++ * ++ * 01 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable to connect to ad-hoc network ++ * ++ * 01 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * .implement Set/Query BeaconInterval/AtimWindow ++ * ++ * 01 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * .Set/Get AT Info is not blocked even when driver is not in fg test mode ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * and result is retrieved by get ATInfo instead ++ * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 28 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate redundant variables for connection_state ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-16 22:13:36 GMT mtk02752 ++** change hard-coded MAC address to match with FW (temporally) ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-10 16:49:50 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-08 17:38:49 GMT mtk02752 ++** + add OID for RF test ++** * MCR RD/WR are modified to match with cmd/event definition ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-12-08 11:32:20 GMT mtk02752 ++** add skeleton for RF test implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-12-03 16:43:24 GMT mtk01461 ++** Modify query SCAN list oid by adding prEventScanResult ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-03 16:39:27 GMT mtk01461 ++** Sync CMD data structure in set ssid oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-03 16:28:22 GMT mtk01461 ++** Add invalid check of set SSID oid and fix query scan list oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-30 17:33:08 GMT mtk02752 ++** implement wlanoidSetInfrastructureMode/wlanoidQueryInfrastructureMode ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-30 10:53:49 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-30 09:22:48 GMT mtk02752 ++** correct wifi cmd length mismatch ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-25 21:34:33 GMT mtk02752 ++** sync EVENT_SCAN_RESULT_T with firmware ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 21:03:27 GMT mtk02752 ++** implement wlanoidQueryBssidList() ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-25 18:17:17 GMT mtk02752 ++** refine GL_WLAN_INFO_T for buffering scan result ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-23 20:28:51 GMT mtk02752 ++** some OID will be set to WLAN_STATUS_PENDING until it is sent via wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-23 17:56:36 GMT mtk02752 ++** implement wlanoidSetBssidListScan(), wlanoidSetBssid() and wlanoidSetSsid() ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-13 17:20:53 GMT mtk02752 ++** add Set BSSID/SSID path but disabled temporally due to FW is not ready yet ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 12:28:58 GMT mtk02752 ++** add wlanoidSetBssidListScan -> cmd_info path ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-09 22:48:07 GMT mtk01084 ++** modify test cases entry ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-04 14:10:58 GMT mtk01084 ++** add new test interfaces ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-30 18:17:10 GMT mtk01084 ++** fix compiler warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:46:26 GMT mtk01084 ++** add test functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:07:56 GMT mtk01084 ++** include new file ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:29 GMT mtk01084 ++** modify for new HW architecture ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-02 13:48:49 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-09-09 17:26:04 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-21 12:09:50 GMT mtk01461 ++** Update for MCR Write OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:35:18 GMT mtk01461 ++** Update wlanoidQueryMcrRead() for composing CMD_INFO_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 18:09:51 GMT mtk01426 ++** Remove kalIndicateStatusAndComplete() in wlanoidQueryOidInterfaceVersion() ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-14 15:51:50 GMT mtk01426 ++** Add MCR read/write support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:40 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:06:31 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++#include "mgmt/rsn.h" ++ ++#include ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++#if CFG_ENABLE_STATISTICS_BUFFERING ++static BOOLEAN IsBufferedStatisticsUsable(P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsStatValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rStatUpdateTime) <= CFG_STATISTICS_VALID_CYCLE) ++ return TRUE; ++ else ++ return FALSE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the supported physical layer network ++* type that can be used by the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ UINT_32 u4NumItem = 0; ++ ENUM_PARAM_NETWORK_TYPE_T eSupportedNetworks[PARAM_NETWORK_TYPE_NUM]; ++ PPARAM_NETWORK_TYPE_LIST prSupported; ++ ++ /* The array of all physical layer network subtypes that the driver supports. */ ++ ++ DEBUGFUNC("wlanoidQueryNetworkTypesSupported"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ /* Init. */ ++ for (u4NumItem = 0; u4NumItem < PARAM_NETWORK_TYPE_NUM; u4NumItem++) ++ eSupportedNetworks[u4NumItem] = 0; ++ ++ u4NumItem = 0; ++ ++ eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_DS; ++ u4NumItem++; ++ ++ eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_OFDM24; ++ u4NumItem++; ++ ++ *pu4QueryInfoLen = ++ (UINT_32) OFFSET_OF(PARAM_NETWORK_TYPE_LIST, eNetworkType) + ++ (u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prSupported = (PPARAM_NETWORK_TYPE_LIST) pvQueryBuffer; ++ prSupported->NumberOfItems = u4NumItem; ++ kalMemCopy(prSupported->eNetworkType, eSupportedNetworks, u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); ++ ++ DBGLOG(OID, TRACE, "NDIS supported network type list: %u\n", prSupported->NumberOfItems); ++ DBGLOG_MEM8(OID, TRACE, prSupported, *pu4QueryInfoLen); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryNetworkTypesSupported */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current physical layer network ++* type used by the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ /* TODO: need to check the OID handler content again!! */ ++ ++ ENUM_PARAM_NETWORK_TYPE_T rCurrentNetworkTypeInUse = PARAM_NETWORK_TYPE_OFDM24; ++ ++ DEBUGFUNC("wlanoidQueryNetworkTypeInUse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) ++ rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkType); ++ else ++ rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkTypeInUse); ++ ++ *(P_ENUM_PARAM_NETWORK_TYPE_T) pvQueryBuffer = rCurrentNetworkTypeInUse; ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ ++ DBGLOG(OID, TRACE, "Network type in use: %d\n", rCurrentNetworkTypeInUse); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryNetworkTypeInUse */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the physical layer network type used ++* by the driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns the ++* amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS The given network type is supported and accepted. ++* \retval WLAN_STATUS_INVALID_DATA The given network type is not in the ++* supported list. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ /* TODO: need to check the OID handler content again!! */ ++ ++ ENUM_PARAM_NETWORK_TYPE_T eNewNetworkType; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetNetworkTypeInUse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ eNewNetworkType = *(P_ENUM_PARAM_NETWORK_TYPE_T) pvSetBuffer; ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ ++ DBGLOG(OID, INFO, "New network type: %d mode\n", eNewNetworkType); ++ ++ switch (eNewNetworkType) { ++ ++ case PARAM_NETWORK_TYPE_DS: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PARAM_NETWORK_TYPE_OFDM5: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ case PARAM_NETWORK_TYPE_OFDM24: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PARAM_NETWORK_TYPE_AUTOMODE: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_AUTOMODE; ++ break; ++ ++ case PARAM_NETWORK_TYPE_FH: ++ DBGLOG(OID, INFO, "Not support network type: %d\n", eNewNetworkType); ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Unknown network type: %d\n", eNewNetworkType); ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ /* Verify if we support the new network type. */ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(OID, WARN, "Unknown network type: %d\n", eNewNetworkType); ++ ++ return rStatus; ++} /* wlanoidSetNetworkTypeInUse */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current BSSID. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidQueryBssid"); ++ ++ ASSERT(prAdapter); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) { ++ ASSERT(pu4QueryInfoLen); ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ ASSERT(u4QueryBufferLen >= MAC_ADDR_LEN); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) ++ kalMemCopy(pvQueryBuffer, prAdapter->rWlanInfo.rCurrBssId.arMacAddress, MAC_ADDR_LEN); ++ else if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS) { ++ PARAM_MAC_ADDRESS aucTemp; /*!< BSSID */ ++ ++ COPY_MAC_ADDR(aucTemp, prAdapter->rWlanInfo.rCurrBssId.arMacAddress); ++ aucTemp[0] &= ~BIT(0); ++ aucTemp[1] |= BIT(1); ++ COPY_MAC_ADDR(pvQueryBuffer, aucTemp); ++ } else ++ rStatus = WLAN_STATUS_ADAPTER_NOT_READY; ++ ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ return rStatus; ++} /* wlanoidQueryBssid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the list of all BSSIDs detected by ++* the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i, u4BssidListExLen; ++ P_PARAM_BSSID_LIST_EX_T prList; ++ P_PARAM_BSSID_EX_T prBssidEx; ++ PUINT_8 cp; ++ ++ DEBUGFUNC("wlanoidQueryBssidList"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) { ++ ASSERT(pvQueryBuffer); ++ ++ if (!pvQueryBuffer) ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in qeury BSSID list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ u4BssidListExLen = 0; ++ ++ if (prAdapter->fgIsRadioOff == FALSE) { ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) ++ u4BssidListExLen += ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4Length); ++ } ++ ++ if (u4BssidListExLen) ++ u4BssidListExLen += 4; /* u4NumberOfItems. */ ++ else ++ u4BssidListExLen = sizeof(PARAM_BSSID_LIST_EX_T); ++ ++ *pu4QueryInfoLen = u4BssidListExLen; ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Clear the buffer */ ++ kalMemZero(pvQueryBuffer, u4BssidListExLen); ++ ++ prList = (P_PARAM_BSSID_LIST_EX_T) pvQueryBuffer; ++ cp = (PUINT_8) &prList->arBssid[0]; ++ ++ if (prAdapter->fgIsRadioOff == FALSE && prAdapter->rWlanInfo.u4ScanResultNum > 0) { ++ /* fill up for each entry */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ prBssidEx = (P_PARAM_BSSID_EX_T) cp; ++ ++ /* copy structure */ ++ kalMemCopy(prBssidEx, ++ &(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /*For WHQL test, Rssi should be in range -10 ~ -200 dBm */ ++ if (prBssidEx->rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ prBssidEx->rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { ++ /* copy IEs */ ++ kalMemCopy(prBssidEx->aucIEs, ++ prAdapter->rWlanInfo.apucScanResultIEs[i], ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ } ++ /* 4-bytes alignement */ ++ prBssidEx->u4Length = ALIGN_4(prBssidEx->u4Length); ++ ++ cp += prBssidEx->u4Length; ++ prList->u4NumberOfItems++; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryBssidList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to perform ++* scanning. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SSID_T prSsid; ++ PARAM_SSID_T rSsid; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetBssidListScan()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(OID, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(OID, TRACE, "Scan\n"); ++ ++ if (pvSetBuffer != NULL && u4SetBufferLen != 0) { ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, pvSetBuffer, u4SetBufferLen); ++ prSsid = &rSsid; ++ } else { ++ prSsid = NULL; ++ } ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { ++ if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else ++#endif ++ { ++ if (prAdapter->fgEnOnlineScan == TRUE) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ return rStatus; ++} /* wlanoidSetBssidListScan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to perform ++* scanning with attaching information elements(IEs) specified from user space ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SCAN_REQUEST_EXT_T prScanRequest; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_PARAM_SSID_T prSsid; ++ PUINT_8 pucIe; ++ UINT_32 u4IeLength; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_8 ucScanTime = AIS_SCN_DONE_TIMEOUT_SEC; ++ ++ DEBUGFUNC("wlanoidSetBssidListScanExt()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, ERROR, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgTestMode) { ++ DBGLOG(OID, WARN, "didn't support Scan in test mode\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)) { ++ DBGLOG(OID, ERROR, "u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(OID, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(OID, TRACE, "ScanEx\n"); ++ ++ /* clear old scan backup results if exists */ ++ { ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); ++ prBssDesc->u2RawLength = 0; ++ } ++ } ++ } ++ ++ if (pvSetBuffer != NULL && u4SetBufferLen != 0) { ++ prScanRequest = (P_PARAM_SCAN_REQUEST_EXT_T) pvSetBuffer; ++ prSsid = &(prScanRequest->rSsid); ++ pucIe = prScanRequest->pucIE; ++ u4IeLength = prScanRequest->u4IELength; ++ } else { ++ prScanRequest = NULL; ++ prSsid = NULL; ++ pucIe = NULL; ++ u4IeLength = 0; ++ } ++ ++/* P_AIS_FSM_INFO_T prAisFsmInfo; */ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++/* #if CFG_SUPPORT_WFD */ ++#if 0 ++ if ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.ucWfdEnable) && ++ ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ DBGLOG(OID, TRACE, "Twice the Scan Time for WFD\n"); ++ ucScanTime *= 2; ++ } ++ } ++#endif /* CFG_SUPPORT_WFD */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer, SEC_TO_MSEC(ucScanTime)); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { ++ if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else ++#endif ++ { ++ if (prAdapter->fgEnOnlineScan == TRUE) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ DBGLOG(OID, WARN, "ScanEx fail %d!\n", prAdapter->fgEnOnlineScan); ++ } ++ } ++ ++ return rStatus; ++} /* wlanoidSetBssidListScanWithIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will initiate the join procedure to attempt to associate ++* with the specified BSSID. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_UINT_8 pAddr; ++ UINT_32 i; ++ INT_32 i4Idx = -1; ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ UINT_8 ucReasonOfDisconnect; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = MAC_ADDR_LEN; ++ if (u4SetBufferLen != MAC_ADDR_LEN) { ++ *pu4SetInfoLen = MAC_ADDR_LEN; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ pAddr = (P_UINT_8) pvSetBuffer; ++ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; ++ } else { ++ DBGLOG(OID, TRACE, "DisByBssid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ } else { ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ ++ /* check if any scanned result matchs with the BSSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { ++ i4Idx = (INT_32) i; ++ break; ++ } ++ } ++ ++ /* prepare message to AIS */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS ++ || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_BSSID; ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = ucReasonOfDisconnect; ++ ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAdapter->rWifiVar.rConnSettings.ucSSIDLen = 0; ++ prAdapter->rWifiVar.rConnSettings.aucSSID[0] = '\0'; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr); ++ ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ else ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(OID, INFO, "SetBssid\n"); ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetBssid() */ ++ ++WLAN_STATUS ++wlanoidSetConnect(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_CONNECT_T pParamConn; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_32 i; ++ /*INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN;*/ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ BOOLEAN fgIsValidSsid = TRUE; ++ BOOLEAN fgEqualSsid = FALSE; ++ BOOLEAN fgEqualBssid = FALSE; ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* MSDN: ++ * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE ++ */ ++ if (prAdapter->fgIsRadioOff == TRUE) ++ prAdapter->fgIsRadioOff = FALSE; ++ ++ if (u4SetBufferLen != sizeof(PARAM_CONNECT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ ++ pParamConn = (P_PARAM_CONNECT_T) pvSetBuffer; ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ ++ if (pParamConn->u4SsidLen > 32) { ++ cnmMemFree(prAdapter, prAisAbortMsg); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (!pParamConn->pucBssid && !pParamConn->pucSsid) { ++ cnmMemFree(prAdapter, prAisAbortMsg); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ kalMemZero(prConnSettings->aucSSID, sizeof(prConnSettings->aucSSID)); ++ kalMemZero(prConnSettings->aucBSSID, sizeof(prConnSettings->aucBSSID)); ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_ANY; ++ prConnSettings->fgIsConnByBssidIssued = FALSE; ++ ++ if (pParamConn->pucSsid) { ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ COPY_SSID(prConnSettings->aucSSID, ++ prConnSettings->ucSSIDLen, pParamConn->pucSsid, (UINT_8) pParamConn->u4SsidLen); ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, ++ pParamConn->pucSsid, pParamConn->u4SsidLen)) ++ fgEqualSsid = TRUE; ++ } ++ if (pParamConn->pucBssid) { ++ if (!EQUAL_MAC_ADDR(aucZeroMacAddr, pParamConn->pucBssid) && IS_UCAST_MAC_ADDR(pParamConn->pucBssid)) { ++ prConnSettings->eConnectionPolicy = CONNECT_BY_BSSID; ++ prConnSettings->fgIsConnByBssidIssued = TRUE; ++ COPY_MAC_ADDR(prConnSettings->aucBSSID, pParamConn->pucBssid); ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pParamConn->pucBssid)) ++ fgEqualBssid = TRUE; ++ } else ++ DBGLOG(OID, TRACE, "wrong bssid %pM to connect\n", pParamConn->pucBssid); ++ } else ++ DBGLOG(OID, TRACE, "No Bssid set\n"); ++ prConnSettings->u4FreqInKHz = pParamConn->u4CenterFreq; ++ ++ /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (fgEqualSsid) { ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_ROAMING; ++ if (fgEqualBssid) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; ++ } ++ } else { ++ DBGLOG(OID, TRACE, "DisBySsid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ } else ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++#if 0 ++ /* check if any scanned result matchs with the SSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; ++ UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; ++ INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ ++ if (EQUAL_SSID(aucSsid, ucSsidLength, pParamConn->pucSsid, pParamConn->u4SsidLen) && ++ i4RSSI >= i4MaxRSSI) { ++ i4Idx = (INT_32) i; ++ i4MaxRSSI = i4RSSI; ++ } ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { ++ i4Idx = (INT_32) i; ++ break; ++ } ++ } ++#endif ++ /* prepare message to AIS */ ++ if (prConnSettings->eOPMode == NET_TYPE_IBSS || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prConnSettings->u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prConnSettings->u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { ++ if (pParamConn->u4SsidLen == ELEM_MAX_LEN_SSID) { ++ fgIsValidSsid = FALSE; ++ ++ for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { ++ if (pParamConn->pucSsid) { ++ if (!((0 < pParamConn->pucSsid[i]) && (pParamConn->pucSsid[i] <= 0x1F))) { ++ fgIsValidSsid = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ if (fgIsValidSsid) ++ prConnSettings->fgIsConnReqIssued = TRUE; ++ else ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ ++ if (fgEqualSsid || fgEqualBssid) ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ else ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(OID, INFO, "ssid %s, bssid %pM, conn policy %d, disc reason %d\n", ++ prConnSettings->aucSSID, prConnSettings->aucBSSID, ++ prConnSettings->eConnectionPolicy, prAisAbortMsg->ucReasonOfDisconnect); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will initiate the join procedure to attempt ++* to associate with the new SSID. If the previous scanning ++* result is aged, we will scan the channels at first. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_SSID_T pParamSsid; ++ UINT_32 i; ++ INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN; ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ BOOLEAN fgIsValidSsid = TRUE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* MSDN: ++ * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE ++ */ ++ if (prAdapter->fgIsRadioOff == TRUE) ++ prAdapter->fgIsRadioOff = FALSE; ++ ++ if (u4SetBufferLen < sizeof(PARAM_SSID_T) || u4SetBufferLen > sizeof(PARAM_SSID_T)) { ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ pParamSsid = (P_PARAM_SSID_T) pvSetBuffer; ++ ++ if (pParamSsid->u4SsidLen > 32) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, ++ pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ } else { ++ DBGLOG(OID, TRACE, "DisBySsid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ } ++ /* check if any scanned result matchs with the SSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; ++ UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; ++ INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ ++ if (EQUAL_SSID(aucSsid, ucSsidLength, pParamSsid->aucSsid, pParamSsid->u4SsidLen) && ++ i4RSSI >= i4MaxRSSI) { ++ i4Idx = (INT_32) i; ++ i4MaxRSSI = i4RSSI; ++ } ++ } ++ ++ /* prepare message to AIS */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS ++ || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { ++ if (pParamSsid->u4SsidLen == ELEM_MAX_LEN_SSID) { ++ fgIsValidSsid = FALSE; ++ ++ for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { ++ if (!((0 < pParamSsid->aucSsid[i]) && (pParamSsid->aucSsid[i] <= 0x1F))) { ++ fgIsValidSsid = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ if (fgIsValidSsid) { ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; ++ ++ if (pParamSsid->u4SsidLen) { ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ } else { ++ /* wildcard SSID */ ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_ANY; ++ } ++ } else { ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ } ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ ++ COPY_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, ++ prAdapter->rWifiVar.rConnSettings.ucSSIDLen, pParamSsid->aucSsid, (UINT_8) pParamSsid->u4SsidLen); ++ ++ prAdapter->rWifiVar.rConnSettings.u4FreqInKHz = pParamSsid->u4CenterFreq; ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ } else { ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ } ++ DBGLOG(SCN, INFO, "SSID %s\n", prAdapter->rWifiVar.rConnSettings.aucSSID); ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidSetSsid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the currently associated SSID. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_SSID_T prAssociatedSsid; ++ ++ DEBUGFUNC("wlanoidQuerySsid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_SSID_T); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prAssociatedSsid = (P_PARAM_SSID_T) pvQueryBuffer; ++ ++ kalMemZero(prAssociatedSsid->aucSsid, sizeof(prAssociatedSsid->aucSsid)); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ prAssociatedSsid->u4SsidLen = prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen; ++ ++ if (prAssociatedSsid->u4SsidLen) { ++ kalMemCopy(prAssociatedSsid->aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, prAssociatedSsid->u4SsidLen); ++ } ++ } else { ++ prAssociatedSsid->u4SsidLen = 0; ++ ++ DBGLOG(OID, TRACE, "Null SSID\n"); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQuerySsid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 network type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryInfrastructureMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eOPMode; ++ ++ /* ++ ** According to OID_802_11_INFRASTRUCTURE_MODE ++ ** If there is no prior OID_802_11_INFRASTRUCTURE_MODE, ++ ** NDIS_STATUS_ADAPTER_NOT_READY shall be returned. ++ */ ++#if DBG ++ switch (*(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer) { ++ case NET_TYPE_IBSS: ++ DBGLOG(OID, INFO, "IBSS mode\n"); ++ break; ++ case NET_TYPE_INFRA: ++ DBGLOG(OID, INFO, "Infrastructure mode\n"); ++ break; ++ default: ++ DBGLOG(OID, INFO, "Automatic mode\n"); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryInfrastructureMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set mode to infrastructure or ++* IBSS, or automatic switch between the two. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid ++* length of the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ DEBUGFUNC("wlanoidSetInfrastructureMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set infrastructure mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ eOpMode = *(P_ENUM_PARAM_OP_MODE_T) pvSetBuffer; ++ /* Verify the new infrastructure mode. */ ++ if (eOpMode >= NET_TYPE_NUM) { ++ DBGLOG(OID, TRACE, "Invalid mode value %d\n", eOpMode); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* check if possible to switch to AdHoc mode */ ++ if (eOpMode == NET_TYPE_IBSS || eOpMode == NET_TYPE_DEDICATED_IBSS) { ++ if (cnmAisIbssIsPermitted(prAdapter) == FALSE) { ++ DBGLOG(OID, TRACE, "Mode value %d unallowed\n", eOpMode); ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ /* Save the new infrastructure mode setting. */ ++ prAdapter->rWifiVar.rConnSettings.eOPMode = eOpMode; ++ ++ /* Clean up the Tx key flag */ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++#if CFG_SUPPORT_WAPI ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz = 0; ++ kalMemZero(&prAdapter->prGlueInfo->aucWapiAssocInfoIEs, 42); ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled = FALSE; ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++ kalMemZero(&prAdapter->prGlueInfo->aucWSCAssocInfoIE, 200); ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INFRASTRUCTURE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, nicOidCmdTimeoutCommon, 0, NULL, pvSetBuffer, u4SetBufferLen); ++ ++} /* wlanoidSetInfrastructureMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 authentication ++* mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryAuthMode"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eAuthMode; ++ ++#if DBG ++ switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer) { ++ case AUTH_MODE_OPEN: ++ DBGLOG(OID, INFO, "Current auth mode: Open\n"); ++ break; ++ ++ case AUTH_MODE_SHARED: ++ DBGLOG(OID, INFO, "Current auth mode: Shared\n"); ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(OID, INFO, "Current auth mode: Auto-switch\n"); ++ break; ++ ++ case AUTH_MODE_WPA: ++ DBGLOG(OID, INFO, "Current auth mode: WPA\n"); ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ DBGLOG(OID, INFO, "Current auth mode: WPA PSK\n"); ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ DBGLOG(OID, INFO, "Current auth mode: WPA None\n"); ++ break; ++ ++ case AUTH_MODE_WPA2: ++ DBGLOG(OID, INFO, "Current auth mode: WPA2\n"); ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ DBGLOG(OID, INFO, "Current auth mode: WPA2 PSK\n"); ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); ++ break; ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryAuthMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the IEEE 802.11 authentication mode ++* to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i, u4AkmSuite; ++ P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; ++ ++ DEBUGFUNC("wlanoidSetAuthMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* RF Test */ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* Check if the new authentication mode is valid. */ ++ if (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer >= AUTH_MODE_NUM) { ++ DBGLOG(OID, TRACE, "Invalid auth mode %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer) { ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ /* infrastructure mode only */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_INFRA) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ /* ad hoc mode only */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_IBSS) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Save the new authentication mode. */ ++ prAdapter->rWifiVar.rConnSettings.eAuthMode = *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer; ++ ++#if DBG ++ switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { ++ case AUTH_MODE_OPEN: ++ DBGLOG(RSN, TRACE, "New auth mode: open\n"); ++ break; ++ ++ case AUTH_MODE_SHARED: ++ DBGLOG(RSN, TRACE, "New auth mode: shared\n"); ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(RSN, TRACE, "New auth mode: auto-switch\n"); ++ break; ++ ++ case AUTH_MODE_WPA: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA\n"); ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA PSK\n"); ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA None\n"); ++ break; ++ ++ case AUTH_MODE_WPA2: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA2\n"); ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA2 PSK\n"); ++ break; ++ ++ default: ++ DBGLOG(RSN, TRACE, "New auth mode: unknown (%d)\n", prAdapter->rWifiVar.rConnSettings.eAuthMode); ++ } ++#endif ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode >= AUTH_MODE_WPA) { ++ switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { ++ case AUTH_MODE_WPA: ++ u4AkmSuite = WPA_AKM_SUITE_802_1X; ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ u4AkmSuite = WPA_AKM_SUITE_PSK; ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ u4AkmSuite = WPA_AKM_SUITE_NONE; ++ break; ++ ++ case AUTH_MODE_WPA2: ++ u4AkmSuite = RSN_AKM_SUITE_802_1X; ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ u4AkmSuite = RSN_AKM_SUITE_PSK; ++ break; ++ ++ default: ++ u4AkmSuite = 0; ++ } ++ } else { ++ u4AkmSuite = 0; ++ } ++ ++ /* Enable the specific AKM suite only. */ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; ++ ++ if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = FALSE; ++#if CFG_SUPPORT_802_11W ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED) { ++ if ((u4AkmSuite == RSN_AKM_SUITE_PSK) && ++ prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_PSK_SHA256) { ++ DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_PSK_SHA256 AKM support\n"); ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ ++ } ++ if ((u4AkmSuite == RSN_AKM_SUITE_802_1X) && ++ prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_802_1X_SHA256) { ++ DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_802_1X_SHA256 AKM support\n"); ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ } ++ } ++#endif ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetAuthMode */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 privacy filter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryPrivacyFilter"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer = prAdapter->rWlanInfo.ePrivacyFilter; ++ ++#if DBG ++ switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer) { ++ case PRIVACY_FILTER_ACCEPT_ALL: ++ DBGLOG(OID, INFO, "Current privacy mode: open mode\n"); ++ break; ++ ++ case PRIVACY_FILTER_8021xWEP: ++ DBGLOG(OID, INFO, "Current privacy mode: filtering mode\n"); ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryPrivacyFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the IEEE 802.11 privacy filter ++* to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("wlanoidSetPrivacyFilter"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* Check if the new authentication mode is valid. */ ++ if (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer >= PRIVACY_FILTER_NUM) { ++ DBGLOG(OID, TRACE, "Invalid privacy filter %d\n", *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer) { ++ default: ++ break; ++ } ++ ++ /* Save the new authentication mode. */ ++ prAdapter->rWlanInfo.ePrivacyFilter = *(ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetPrivacyFilter */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to reload the available default settings for ++* the specified type field. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType; ++ UINT_32 u4Len; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetReloadDefaults"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = sizeof(PARAM_RELOAD_DEFAULTS); ++ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Reload default! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ /* Verify the available reload options and reload the settings. */ ++ switch (*(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer) { ++ case ENUM_RELOAD_WEP_KEYS: ++ /* Reload available default WEP keys from the permanent ++ storage. */ ++ prAdapter->rWifiVar.rConnSettings.eAuthMode = AUTH_MODE_OPEN; ++ /* ENUM_ENCRYPTION_DISABLED; */ ++ prAdapter->rWifiVar.rConnSettings.eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; ++ { ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 0; /* Remove */ ++ prCmdKey->ucKeyId = 0; /* (UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); */ ++ kalMemCopy(prCmdKey->aucPeerAddr, aucBCAddr, MAC_ADDR_LEN); ++ ++ ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); ++ ++ prCmdKey->ucKeyType = 0; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++ } ++ ++ break; ++ ++ default: ++ DBGLOG(OID, TRACE, "Invalid reload option %d\n", *(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer); ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* OID_802_11_RELOAD_DEFAULTS requiest to reset to auto mode */ ++ eNetworkType = PARAM_NETWORK_TYPE_AUTOMODE; ++ wlanoidSetNetworkTypeInUse(prAdapter, &eNetworkType, sizeof(eNetworkType), &u4Len); ++ ++ return rStatus; ++} /* wlanoidSetReloadDefaults */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a WEP key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++#ifdef LINUX ++UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; ++UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++#endif ++WLAN_STATUS ++wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#ifndef LINUX ++ UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++#endif ++ P_PARAM_WEP_T prNewWepKey; ++ P_PARAM_KEY_T prParamKey = (P_PARAM_KEY_T) keyBuffer; ++ UINT_32 u4KeyId, u4SetLen; ++ ++ DEBUGFUNC("wlanoidSetAddWep"); ++ ++ ASSERT(prAdapter); ++ ++ *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); ++ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)) { ++ ASSERT(pu4SetInfoLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewWepKey = (P_PARAM_WEP_T) pvSetBuffer; ++ ++ /* Verify the total buffer for minimum length. */ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + prNewWepKey->u4KeyLength) { ++ DBGLOG(OID, WARN, "Invalid total buffer length (%d) than minimum length (%d)\n", ++ (UINT_8) u4SetBufferLen, (UINT_8) OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)); ++ ++ *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Verify the key structure length. */ ++ if (prNewWepKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewWepKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Verify the key material length for maximum key material length:16 */ ++ if (prNewWepKey->u4KeyLength > 16 /* LEGACY_KEY_MAX_LEN */) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d) greater than maximum key material length (16)\n", ++ (UINT_8) prNewWepKey->u4KeyLength); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ u4KeyId = prNewWepKey->u4KeyIndex & BITS(0, 29) /* WEP_KEY_ID_FIELD */; ++ ++ /* Verify whether key index is valid or not, current version ++ driver support only 4 global WEP keys setting by this OID */ ++ if (u4KeyId > MAX_KEY_NUM - 1) { ++ DBGLOG(OID, ERROR, "Error, invalid WEP key ID: %d\n", (UINT_8) u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prParamKey->u4KeyIndex = u4KeyId; ++ ++ /* Transmit key */ ++ if (prNewWepKey->u4KeyIndex & IS_TRANSMIT_KEY) ++ prParamKey->u4KeyIndex |= IS_TRANSMIT_KEY; ++ ++ /* Per client key */ ++ if (prNewWepKey->u4KeyIndex & IS_UNICAST_KEY) ++ prParamKey->u4KeyIndex |= IS_UNICAST_KEY; ++ ++ prParamKey->u4KeyLength = prNewWepKey->u4KeyLength; ++ ++ kalMemCopy(prParamKey->arBSSID, aucBCAddr, MAC_ADDR_LEN); ++ ++ kalMemCopy(prParamKey->aucKeyMaterial, prNewWepKey->aucKeyMaterial, prNewWepKey->u4KeyLength); ++ ++ prParamKey->u4Length = OFFSET_OF(PARAM_KEY_T, aucKeyMaterial) + prNewWepKey->u4KeyLength; ++ ++ wlanoidSetAddKey(prAdapter, (PVOID) prParamKey, prParamKey->u4Length, &u4SetLen); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetAddWep */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to remove the WEP key ++* at the specified key index. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 u4KeyId, u4SetLen; ++ PARAM_REMOVE_KEY_T rRemoveKey; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ DEBUGFUNC("wlanoidSetRemoveWep"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_KEY_INDEX); ++ ++ if (u4SetBufferLen < sizeof(PARAM_KEY_INDEX)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ u4KeyId = *(PUINT_32) pvSetBuffer; ++ ++ /* Dump PARAM_WEP content. */ ++ DBGLOG(OID, INFO, "Set: Dump PARAM_KEY_INDEX content\n"); ++ DBGLOG(OID, INFO, "Index : 0x%08x\n", u4KeyId); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4KeyId & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "Invalid WEP key index: 0x%08x\n", u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ u4KeyId &= BITS(0, 7); ++ ++ /* Verify whether key index is valid or not. Current version ++ driver support only 4 global WEP keys. */ ++ if (u4KeyId > MAX_KEY_NUM - 1) { ++ DBGLOG(OID, ERROR, "invalid WEP key ID %u\n", u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ rRemoveKey.u4KeyIndex = *(PUINT_32) pvSetBuffer; ++ ++ kalMemCopy(rRemoveKey.arBSSID, aucBCAddr, MAC_ADDR_LEN); ++ ++ wlanoidSetRemoveKey(prAdapter, (PVOID)&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T), &u4SetLen); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetRemoveWep */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_KEY_T prNewKey; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 ucCmdSeqNum; ++ ++#if 0 ++ DEBUGFUNC("wlanoidSetAddKey"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++#endif ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++#if 0 ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ /* Verify the key material length for key material buffer */ ++ if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check */ ++ if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || ++ prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyIndex & 0xff) != 0) || ++ ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) ++ && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) ++ && (prNewKey->arBSSID[5] == 0xff))) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++#endif ++ ++ /* Dump PARAM_KEY content. */ ++ DBGLOG(OID, TRACE, "Set: PARAM_KEY Length: 0x%08x, Key Index: 0x%08x, Key Length: 0x%08x\n", ++ prNewKey->u4Length, prNewKey->u4KeyIndex, prNewKey->u4KeyLength); ++ DBGLOG(OID, TRACE, "BSSID:\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ DBGLOG(OID, TRACE, "Key RSC:\n"); ++ DBGLOG_MEM8(OID, TRACE, &prNewKey->rKeyRSC, sizeof(PARAM_KEY_RSC)); ++ DBGLOG(OID, TRACE, "Key Material:\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->aucKeyMaterial, prNewKey->u4KeyLength); ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { ++ /* Todo:: Store the legacy wep key for OID_802_11_RELOAD_DEFAULTS */ ++ /* Todo:: Nothing */ ++ } ++ ++ if (prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = TRUE; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(OID, TRACE, "ucCmdSeqNum = %d\n", ucCmdSeqNum); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 1; /* Add */ ++ ++ prCmdKey->ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; ++ prCmdKey->ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; ++ prCmdKey->ucIsAuthenticator = ((prNewKey->u4KeyIndex & IS_AUTHENTICATOR) == IS_AUTHENTICATOR) ? 1 : 0; ++ ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->arBSSID, MAC_ADDR_LEN); ++ ++ prCmdKey->ucNetType = 0; /* AIS */ ++ ++ prCmdKey->ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); ++ ++ /* Note: adjust the key length for WPA-None */ ++ prCmdKey->ucKeyLen = (UINT_8) prNewKey->u4KeyLength; ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, prCmdKey->ucKeyLen); ++ ++ if (prNewKey->u4KeyLength == 5) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP40; ++ } else if (prNewKey->u4KeyLength == 13) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP104; ++ } else if (prNewKey->u4KeyLength == 16) { ++ if ((ucAlgorithmId != CIPHER_SUITE_CCMP) && ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA)) ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP128; ++ else { ++#if CFG_SUPPORT_802_11W ++ if (prCmdKey->ucKeyId >= 4) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_BIP; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ prAisSpecBssInfo->fgBipKeyInstalled = TRUE; ++ } else ++#endif ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; ++ if (rsnCheckPmkidCandicate(prAdapter)) { ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ DBGLOG(RSN, TRACE, ++ "Add key: Prepare a timer to indicate candidate PMKID Candidate\n"); ++ cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++ } else if (prNewKey->u4KeyLength == 32) { ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; ++ else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; ++ prCmdKey->ucKeyLen = CCMP_KEY_LEN; ++ } ++ } else ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; ++ } ++ ++ DBGLOG(RSN, TRACE, "prCmdKey->ucAlgorithmId=%d, key len=%d\n", ++ prCmdKey->ucAlgorithmId, (UINT32) prNewKey->u4KeyLength); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS ++wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_KEY_T prNewKey; ++ ++ DEBUGFUNC("wlanoidSetAddKey"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ /* Verify the key material length for key material buffer */ ++ if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check */ ++ if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN) && ++ (prNewKey->u4KeyIndex & 0xff) != 0) || ++ EQUAL_MAC_ADDR(prNewKey->arBSSID, "\xff\xff\xff\xff\xff\xff")) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || ++ prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* ++ supplicant will set key before updating station & enabling the link so we need to ++ backup the key information and set key when link is enabled ++ */ ++ if (TdlsexKeyHandle(prAdapter, prNewKey) == TDLS_STATUS_SUCCESS) ++ return WLAN_STATUS_SUCCESS; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return _wlanoidSetAddKey(prAdapter, pvSetBuffer, u4SetBufferLen, TRUE, CIPHER_SUITE_NONE, pu4SetInfoLen); ++} /* wlanoidSetAddKey */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to remove the key at ++* the specified key index. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_REMOVE_KEY_T prRemovedKey; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetRemoveKey"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set remove key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; ++ ++ /* Dump PARAM_REMOVE_KEY content. */ ++ DBGLOG(OID, TRACE, "Set: Dump PARAM_REMOVE_KEY content\n"); ++ DBGLOG(OID, TRACE, "Length : 0x%08x\n", prRemovedKey->u4Length); ++ DBGLOG(OID, TRACE, "Key Index : 0x%08x\n", prRemovedKey->u4KeyIndex); ++ DBGLOG(OID, TRACE, "BSSID:\n"); ++ DBGLOG_MEM8(OID, TRACE, prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ ++ /* Check bit 31: this bit should always 0 */ ++ if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Check bits 8 ~ 29 should always be 0 */ ++ if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Clean up the Tx key flag */ ++ if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 0; /* Remove */ ++ prCmdKey->ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ ++#if CFG_SUPPORT_802_11W ++ ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM + 2); ++#else ++ /* ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); */ ++#endif ++ ++ if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) ++ prCmdKey->ucKeyType = 1; ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetRemoveKey */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current encryption status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ BOOLEAN fgTransmitKeyAvailable = TRUE; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus = 0; ++ ++ DEBUGFUNC("wlanoidQueryEncryptionStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); ++ ++ fgTransmitKeyAvailable = prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist; ++ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION3_ENABLED: ++ if (fgTransmitKeyAvailable) ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION3_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: ++ if (fgTransmitKeyAvailable) { ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ break; ++ } ++ eEncStatus = ENUM_ENCRYPTION2_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: ++ if (fgTransmitKeyAvailable) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION_DISABLED: ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ break; ++ ++ default: ++ DBGLOG(OID, ERROR, "Unknown Encryption Status Setting:%d\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++ ++#if DBG ++ DBGLOG(OID, INFO, ++ "Encryption status: %d Return:%d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, eEncStatus); ++#endif ++ ++ *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvQueryBuffer = eEncStatus; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryEncryptionStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the encryption status to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_SUPPORTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEewEncrypt; ++ ++ DEBUGFUNC("wlanoidSetEncryptionStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); ++ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set encryption status! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ eEewEncrypt = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; ++ DBGLOG(OID, TRACE, "ENCRYPTION_STATUS %d\n", eEewEncrypt); ++ ++ switch (eEewEncrypt) { ++ case ENUM_ENCRYPTION_DISABLED: /* Disable WEP, TKIP, AES */ ++ DBGLOG(RSN, TRACE, "Disable Encryption\n"); ++ secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: /* Enable WEP. Disable TKIP, AES */ ++ DBGLOG(RSN, TRACE, "Enable Encryption1\n"); ++ secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: /* Enable WEP, TKIP. Disable AES */ ++ secSetCipherSuite(prAdapter, ++ CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP); ++ DBGLOG(RSN, TRACE, "Enable Encryption2\n"); ++ break; ++ ++ case ENUM_ENCRYPTION3_ENABLED: /* Enable WEP, TKIP, AES */ ++ secSetCipherSuite(prAdapter, ++ CIPHER_FLAG_WEP40 | ++ CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP | CIPHER_FLAG_CCMP); ++ DBGLOG(RSN, TRACE, "Enable Encryption3\n"); ++ break; ++ ++ default: ++ DBGLOG(RSN, WARN, "Unacceptible encryption status: %d\n", ++ *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer); ++ ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ } ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* Save the new encryption status. */ ++ prAdapter->rWifiVar.rConnSettings.eEncStatus = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; ++ ++ DBGLOG(RSN, TRACE, "wlanoidSetEncryptionStatus to %d\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++ ++ return rStatus; ++} /* wlanoidSetEncryptionStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to test the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_802_11_TEST_T prTest; ++ PVOID pvTestData; ++ PVOID pvStatusBuffer; ++ UINT_32 u4StatusBufferSize; ++ ++ DEBUGFUNC("wlanoidSetTest"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prTest = (P_PARAM_802_11_TEST_T) pvSetBuffer; ++ ++ DBGLOG(OID, TRACE, "Test - Type %u\n", prTest->u4Type); ++ ++ switch (prTest->u4Type) { ++ case 1: /* Type 1: generate an authentication event */ ++ pvTestData = (PVOID) &prTest->u.AuthenticationEvent; ++ pvStatusBuffer = (PVOID) prAdapter->aucIndicationEventBuffer; ++ u4StatusBufferSize = prTest->u4Length - 8; ++ if (u4StatusBufferSize > sizeof(PARAM_AUTH_EVENT_T)) { ++ DBGLOG(OID, TRACE, "prTest->u4Length error %u\n", u4StatusBufferSize); ++ ASSERT(FALSE); ++ } ++ break; ++ ++ case 2: /* Type 2: generate an RSSI status indication */ ++ pvTestData = (PVOID) &prTest->u.RssiTrigger; ++ pvStatusBuffer = (PVOID) &prAdapter->rWlanInfo.rCurrBssId.rRssi; ++ u4StatusBufferSize = sizeof(PARAM_RSSI); ++ break; ++ ++ default: ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ASSERT(u4StatusBufferSize <= 180); ++ if (u4StatusBufferSize > 180) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Get the contents of the StatusBuffer from the test structure. */ ++ kalMemCopy(pvStatusBuffer, pvTestData, u4StatusBufferSize); ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, pvStatusBuffer, u4StatusBufferSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetTest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the driver's WPA2 status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CAPABILITY_T prCap; ++ P_PARAM_AUTH_ENCRYPTION_T prAuthenticationEncryptionSupported; ++ ++ DEBUGFUNC("wlanoidQueryCapability"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = 4 * sizeof(UINT_32) + 14 * sizeof(PARAM_AUTH_ENCRYPTION_T); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prCap = (P_PARAM_CAPABILITY_T) pvQueryBuffer; ++ ++ prCap->u4Length = *pu4QueryInfoLen; ++ prCap->u4Version = 2; /* WPA2 */ ++ prCap->u4NoOfPMKIDs = CFG_MAX_PMKID_CACHE; ++ prCap->u4NoOfAuthEncryptPairsSupported = 14; ++ ++ prAuthenticationEncryptionSupported = &prCap->arAuthenticationEncryptionSupported[0]; ++ ++ /* fill 14 entries of supported settings */ ++ prAuthenticationEncryptionSupported[0].eAuthModeSupported = AUTH_MODE_OPEN; ++ ++ prAuthenticationEncryptionSupported[0].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; ++ ++ prAuthenticationEncryptionSupported[1].eAuthModeSupported = AUTH_MODE_OPEN; ++ prAuthenticationEncryptionSupported[1].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; ++ ++ prAuthenticationEncryptionSupported[2].eAuthModeSupported = AUTH_MODE_SHARED; ++ prAuthenticationEncryptionSupported[2].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; ++ ++ prAuthenticationEncryptionSupported[3].eAuthModeSupported = AUTH_MODE_SHARED; ++ prAuthenticationEncryptionSupported[3].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; ++ ++ prAuthenticationEncryptionSupported[4].eAuthModeSupported = AUTH_MODE_WPA; ++ prAuthenticationEncryptionSupported[4].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[5].eAuthModeSupported = AUTH_MODE_WPA; ++ prAuthenticationEncryptionSupported[5].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[6].eAuthModeSupported = AUTH_MODE_WPA_PSK; ++ prAuthenticationEncryptionSupported[6].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[7].eAuthModeSupported = AUTH_MODE_WPA_PSK; ++ prAuthenticationEncryptionSupported[7].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[8].eAuthModeSupported = AUTH_MODE_WPA_NONE; ++ prAuthenticationEncryptionSupported[8].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[9].eAuthModeSupported = AUTH_MODE_WPA_NONE; ++ prAuthenticationEncryptionSupported[9].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[10].eAuthModeSupported = AUTH_MODE_WPA2; ++ prAuthenticationEncryptionSupported[10].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[11].eAuthModeSupported = AUTH_MODE_WPA2; ++ prAuthenticationEncryptionSupported[11].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[12].eAuthModeSupported = AUTH_MODE_WPA2_PSK; ++ prAuthenticationEncryptionSupported[12].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[13].eAuthModeSupported = AUTH_MODE_WPA2_PSK; ++ prAuthenticationEncryptionSupported[13].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryCapability */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the PMKID in the PMK cache. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ UINT_32 i; ++ P_PARAM_PMKID_T prPmkid; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("wlanoidQueryPmkid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ *pu4QueryInfoLen = OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo) + ++ prAisSpecBssInfo->u4PmkidCacheCount * sizeof(PARAM_BSSID_INFO_T); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prPmkid = (P_PARAM_PMKID_T) pvQueryBuffer; ++ ++ prPmkid->u4Length = *pu4QueryInfoLen; ++ prPmkid->u4BSSIDInfoCount = prAisSpecBssInfo->u4PmkidCacheCount; ++ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { ++ kalMemCopy(prPmkid->arBSSIDInfo[i].arBSSID, ++ prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ kalMemCopy(prPmkid->arBSSIDInfo[i].arPMKID, ++ prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryPmkid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the PMKID to the PMK cache in the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i, j; ++ P_PARAM_PMKID_T prPmkid; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("wlanoidSetPmkid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* It's possibble BSSIDInfoCount is zero, because OS wishes to clean PMKID */ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ ASSERT(pvSetBuffer); ++ prPmkid = (P_PARAM_PMKID_T) pvSetBuffer; ++ ++ if (u4SetBufferLen < ++ ((prPmkid->u4BSSIDInfoCount * sizeof(PARAM_BSSID_INFO_T)) + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo))) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ DBGLOG(OID, TRACE, "Count %u\n", prPmkid->u4BSSIDInfoCount); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* This OID replace everything in the PMKID cache. */ ++ if (prPmkid->u4BSSIDInfoCount == 0) { ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++ } ++ if ((prAisSpecBssInfo->u4PmkidCacheCount + prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE)) { ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++ } ++ ++ /* ++ The driver can only clear its PMKID cache whenever it make a media disconnect ++ indication. Otherwise, it must change the PMKID cache only when set through this OID. ++ */ ++#if CFG_RSN_MIGRATION ++ for (i = 0; i < prPmkid->u4BSSIDInfoCount; i++) { ++ /* Search for desired BSSID. If desired BSSID is found, ++ then set the PMKID */ ++ if (!rsnSearchPmkidEntry(prAdapter, (PUINT_8) prPmkid->arBSSIDInfo[i].arBSSID, &j)) { ++ /* No entry found for the specified BSSID, so add one entry */ ++ if (prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE - 1) { ++ j = prAisSpecBssInfo->u4PmkidCacheCount; ++ kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prPmkid->arBSSIDInfo[i].arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ prAisSpecBssInfo->u4PmkidCacheCount++; ++ } else { ++ j = CFG_MAX_PMKID_CACHE; ++ } ++ } ++ ++ if (j < CFG_MAX_PMKID_CACHE) { ++ kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID, ++ prPmkid->arBSSIDInfo[i].arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ DBGLOG(RSN, TRACE, "Add BSSID %pM idx=%d PMKID value %pM\n", ++ (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID), (UINT_32) j, ++ (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID)); ++ prAisSpecBssInfo->arPmkidCache[j].fgPmkidExist = TRUE; ++ } ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetPmkid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the set of supported data rates that ++* the radio is capable of running ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query ++* \param[in] u4QueryBufferLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number ++* of bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ PARAM_RATES eRate = { ++ /* BSSBasicRateSet for 802.11n Non-HT rates */ ++ 0x8C, /* 6M */ ++ 0x92, /* 9M */ ++ 0x98, /* 12M */ ++ 0xA4, /* 18M */ ++ 0xB0, /* 24M */ ++ 0xC8, /* 36M */ ++ 0xE0, /* 48M */ ++ 0xEC /* 54M */ ++ }; ++ ++ DEBUGFUNC("wlanoidQuerySupportedRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, (PVOID) &eRate, sizeof(PARAM_RATES)); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQuerySupportedRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current desired rates. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryDesiredRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, (PVOID) &(prAdapter->rWlanInfo.eDesiredRates), sizeof(PARAM_RATES)); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidQueryDesiredRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to Set the desired rates. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i; ++ ++ DEBUGFUNC("wlanoidSetDesiredRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(PARAM_RATES)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(PARAM_RATES); ++ ++ if (u4SetBufferLen < sizeof(PARAM_RATES)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ kalMemCopy((PVOID) &(prAdapter->rWlanInfo.eDesiredRates), pvSetBuffer, sizeof(PARAM_RATES)); ++ ++ prAdapter->rWlanInfo.eLinkAttr.ucDesiredRateLen = PARAM_MAX_LEN_RATES; ++ for (i = 0; i < PARAM_MAX_LEN_RATES; i++) ++ prAdapter->rWlanInfo.eLinkAttr.u2DesiredRate[i] = (UINT_16) (prAdapter->rWlanInfo.eDesiredRates[i]); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_LINK_ATTRIB, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_LINK_ATTRIB), ++ (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetDesiredRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the maximum frame size in bytes, ++* not including the header. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMaxFrameSize"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ - ETHERNET_HEADER_SZ; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryMaxFrameSize */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the maximum total packet length ++* in bytes. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMaxTotalSize"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryMaxTotalSize */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the vendor ID of the NIC. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#if DBG ++ PUINT_8 cp; ++#endif ++ DEBUGFUNC("wlanoidQueryVendorId"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, prAdapter->aucMacAddress, 3); ++ *((PUINT_8) pvQueryBuffer + 3) = 1; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++#if DBG ++ cp = (PUINT_8) pvQueryBuffer; ++ DBGLOG(OID, LOUD, "Vendor ID=%02x-%02x-%02x-%02x\n", cp[0], cp[1], cp[2], cp[3]); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryVendorId */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RSSI value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call failed due to invalid length of ++* the query buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRssi"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgIsLinkQualityValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ PARAM_RSSI rRssi; ++ ++ rRssi = (PARAM_RSSI) prAdapter->rLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ ++ kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); ++ return WLAN_STATUS_SUCCESS; ++ } ++#ifdef LINUX ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, ++ *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++#endif ++} /* end of wlanoidQueryRssi() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RSSI trigger value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call failed due to invalid length of ++* the query buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRssiTrigger"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_NONE) ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ *(PARAM_RSSI *) pvQueryBuffer = prAdapter->rWlanInfo.rRssiTriggerValue; ++ DBGLOG(OID, INFO, "RSSI trigger: %d dBm\n", *(PARAM_RSSI *) pvQueryBuffer); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryRssiTrigger */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a trigger value of the RSSI event. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns the ++* amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PARAM_RSSI rRssiTriggerValue; ++ ++ DEBUGFUNC("wlanoidSetRssiTrigger"); ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_RSSI); ++ rRssiTriggerValue = *(PARAM_RSSI *) pvSetBuffer; ++ ++ if (rRssiTriggerValue > PARAM_WHQL_RSSI_MAX_DBM || rRssiTriggerValue < PARAM_WHQL_RSSI_MIN_DBM) ++ return ++ /* Save the RSSI trigger value to the Adapter structure */ ++ prAdapter->rWlanInfo.rRssiTriggerValue = rRssiTriggerValue; ++ ++ /* If the RSSI trigger value is equal to the current RSSI value, the ++ * indication triggers immediately. We need to indicate the protocol ++ * that an RSSI status indication event triggers. */ ++ if (rRssiTriggerValue == (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) &prAdapter->rWlanInfo.rRssiTriggerValue, sizeof(PARAM_RSSI)); ++ } else if (rRssiTriggerValue < (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_GREATER; ++ else if (rRssiTriggerValue > (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_LESS; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetRssiTrigger */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a suggested value for the number of ++* bytes of received packet data that will be indicated to the protocol ++* driver. We just accept the set and ignore this value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ DEBUGFUNC("wlanoidSetCurrentLookahead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) { ++ *pu4SetInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetCurrentLookahead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames that the driver ++* receives but does not indicate to the protocols due to errors. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the number of frames that the NIC ++* cannot receive due to lack of NIC receive buffer space. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS If success; ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvNoBuffer"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) 0; /* @FIXME */ ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) 0; /* @FIXME */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvNoBuffer, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvNoBuffer */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the number of frames that the NIC ++* received and it is CRC error. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS If success; ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvCrcError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvCrcError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvCrcError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the current 802.11 statistics. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; ++ prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; ++ prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; ++ prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS_PL, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStatistics, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryStatistics */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the current 802.11 statistics. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryStatistics"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; ++ prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; ++ prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; ++ prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStatistics, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryStatistics */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query current media streaming status. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMediaStreamMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(P_ENUM_MEDIA_STREAM_MODE) pvQueryBuffer = ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryMediaStreamMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to enter media streaming mode or exit media streaming mode ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ENUM_MEDIA_STREAM_MODE eStreamMode; ++ ++ DEBUGFUNC("wlanoidSetMediaStreamMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(ENUM_MEDIA_STREAM_MODE)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); ++ ++ eStreamMode = *(P_ENUM_MEDIA_STREAM_MODE) pvSetBuffer; ++ ++ if (eStreamMode == ENUM_MEDIA_STREAM_OFF) ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; ++ else ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 1; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_LINK_ATTRIB, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetMediaStreamMode, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_LINK_ATTRIB), ++ (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); ++} /* wlanoidSetMediaStreamMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the permanent MAC address of the NIC. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryPermanentAddr"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucPermanentAddress); ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryPermanentAddr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_BASIC_CONFIG rCmdBasicConfig; ++ ++ DEBUGFUNC("wlanoidQueryCurrentAddr"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BASIC_CONFIG, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryAddress, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BASIC_CONFIG), ++ (PUINT_8) &rCmdBasicConfig, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryCurrentAddr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query NIC link speed. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryLinkSpeed"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgIsLinkRateValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ *(PUINT_32) pvQueryBuffer = prAdapter->rLinkQuality.u2LinkSpeed * 5000; /* change to unit of 100bps */ ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkSpeed, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ } ++} /* end of wlanoidQueryLinkSpeed() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query MCR value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ DEBUGFUNC("wlanoidQueryMcrRead"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvQueryBuffer; ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++#if CFG_SUPPORT_SWCR ++ if ((prMcrRdInfo->u4McrOffset >> 16) == 0x9F00) { ++ swCrReadWriteCmd(prAdapter, ++ SWCR_READ, ++ (UINT_16) (prMcrRdInfo->u4McrOffset & BITS(0, 15)), &prMcrRdInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ /* Check if access F/W Domain MCR (due to WiFiSYS is placed from 0x6000-0000 */ ++ if (prMcrRdInfo->u4McrOffset & 0xFFFF0000) { ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrRdInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = 0; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMcrRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); ++ } else { ++ HAL_MCR_RD(prAdapter, prMcrRdInfo->u4McrOffset & BITS(2, 31), /* address is in DWORD unit */ ++ &prMcrRdInfo->u4McrData); ++ ++ DBGLOG(OID, TRACE, "MCR Read: Offset = %#08x, Data = %#08x\n", ++ prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++} /* end of wlanoidQueryMcrRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write MCR and enable specific function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrWrInfo; ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++#if CFG_STRESS_TEST_SUPPORT ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); ++ P_STA_RECORD_T prStaRec = prBssInfo->prStaRecOfAP; ++ UINT_32 u4McrOffset, u4McrData; ++#endif ++ ++ DEBUGFUNC("wlanoidSetMcrWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvSetBuffer; ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++ /* -- Puff Stress Test Begin */ ++#if CFG_STRESS_TEST_SUPPORT ++ ++ /* 0xFFFFFFFE for Control Rate */ ++ if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFE) { ++ if (prMcrWrInfo->u4McrData < FIXED_RATE_NUM && prMcrWrInfo->u4McrData > 0) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prMcrWrInfo->u4McrData); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DEBUGFUNC("[Stress Test]Complete Rate is Changed...\n"); ++ DBGLOG(OID, TRACE, ++ "[Stress Test] Rate is Changed to index %d...\n", prAdapter->rWifiVar.eRateSetting); ++ } ++ /* 0xFFFFFFFD for Switch Channel */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFD) { ++ if (prMcrWrInfo->u4McrData <= 11 && prMcrWrInfo->u4McrData >= 1) ++ prBssInfo->ucPrimaryChannel = prMcrWrInfo->u4McrData; ++ nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); ++ DBGLOG(OID, TRACE, "[Stress Test] Channel is switched to %d ...\n", prBssInfo->ucPrimaryChannel); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 0xFFFFFFFFC for Control RF Band and SCO */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFC) { ++ /* Band */ ++ if (prMcrWrInfo->u4McrData & 0x80000000) { ++ /* prBssInfo->eBand = BAND_5G; */ ++ /* prBssInfo->ucPrimaryChannel = 52; // Bond to Channel 52 */ ++ } else { ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = 8; /* Bond to Channel 6 */ ++ } ++ ++ /* Bandwidth */ ++ if (prMcrWrInfo->u4McrData & 0x00010000) { ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ ++ if (prMcrWrInfo->u4McrData == 0x00010002) { ++ prBssInfo->eBssSCO = CHNL_EXT_SCB; /* U20 */ ++ prBssInfo->ucPrimaryChannel += 2; ++ } else if (prMcrWrInfo->u4McrData == 0x00010001) { ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* L20 */ ++ prBssInfo->ucPrimaryChannel -= 2; ++ } else { ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* 40 */ ++ } ++ } ++ ++ if (prMcrWrInfo->u4McrData & 0x00000000) { ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ } ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ } ++ /* 0xFFFFFFFB for HT Capability */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFB) { ++ /* Enable HT Capability */ ++ if (prMcrWrInfo->u4McrData & 0x00000001) { ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ DEBUGFUNC("[Stress Test]Enable HT capability...\n"); ++ } else { ++ prStaRec->u2HtCapInfo &= (~HT_CAP_INFO_HT_GF); ++ DEBUGFUNC("[Stress Test]Disable HT capability...\n"); ++ } ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ } ++ /* 0xFFFFFFFA for Enable Random Rx Reset */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFA) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_RANDOM_RX_RESET_EN, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF9 for Disable Random Rx Reset */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF9) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_RANDOM_RX_RESET_DE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF8 for Enable SAPP */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF8) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SAPP_EN, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF7 for Disable SAPP */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF7) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SAPP_DE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ ++ else ++#endif ++ /* -- Puff Stress Test End */ ++ ++ /* Check if access F/W Domain MCR */ ++ if (prMcrWrInfo->u4McrOffset & 0xFFFF0000) { ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++#if CFG_SUPPORT_SWCR ++ if ((prMcrWrInfo->u4McrOffset >> 16) == 0x9F00) { ++ swCrReadWriteCmd(prAdapter, ++ SWCR_WRITE, ++ (UINT_16) (prMcrWrInfo->u4McrOffset & BITS(0, 15)), &prMcrWrInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if 1 ++ /* low power test special command */ ++ if (prMcrWrInfo->u4McrOffset == 0x11111110) { ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ /* DbgPrint("Enter test mode\n"); */ ++ prAdapter->fgTestMode = TRUE; ++ return rStatus; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111111) { ++ /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ ++ ++ nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111112) { ++ ++ /* DbgPrint("LP enter sleep\n"); */ ++ ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++#endif ++ ++#if 1 ++ /* low power test special command */ ++ if (prMcrWrInfo->u4McrOffset == 0x11111110) { ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ /* DbgPrint("Enter test mode\n"); */ ++ prAdapter->fgTestMode = TRUE; ++ return rStatus; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111111) { ++ /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ ++ ++ nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111112) { ++ ++ /* DbgPrint("LP enter sleep\n"); */ ++ ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++#endif ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } else { ++ HAL_MCR_WR(prAdapter, (prMcrWrInfo->u4McrOffset & BITS(2, 31)), /* address is in DWORD unit */ ++ prMcrWrInfo->u4McrData); ++ ++ DBGLOG(OID, TRACE, "MCR Write: Offset = %#08x, Data = %#08x\n", ++ prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++} /* wlanoidSetMcrWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query SW CTRL ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ WLAN_STATUS rWlanStatus; ++ UINT_16 u2Id, u2SubId; ++ UINT_32 u4Data; ++ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ ++ DEBUGFUNC("wlanoidQuerySwCtrlRead"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvQueryBuffer; ++ ++ u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); ++ u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); ++ u4Data = 0; ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ switch (u2Id) { ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++#if CFG_SUPPORT_SWCR ++ case 0x9F00: ++ swCrReadWriteCmd(prAdapter, SWCR_READ /* Read */ , ++ (UINT_16) u2SubId, &u4Data); ++ break; ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ case 0xFFFF: ++ { ++ u4Data = 0x5AA56620; ++ } ++ break; ++ ++ case 0x9000: ++ default: ++ { ++ rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; ++ rCmdSwCtrl.u4Data = 0; ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQuerySwCtrlRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_SW_DBG_CTRL_T), ++ (PUINT_8) &rCmdSwCtrl, pvQueryBuffer, u4QueryBufferLen); ++ } ++ } /* switch(u2Id) */ ++ ++ prSwCtrlInfo->u4Data = u4Data; ++ ++ return rWlanStatus; ++ ++} ++ ++ /* end of wlanoidQuerySwCtrlRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write SW CTRL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ WLAN_STATUS rWlanStatus; ++ UINT_16 u2Id, u2SubId; ++ UINT_32 u4Data; ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ P_GLUE_INFO_T prGlueInfo; ++ CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; ++#endif ++ ++ DEBUGFUNC("wlanoidSetSwCtrlWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ prGlueInfo = prAdapter->prGlueInfo; ++#endif ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvSetBuffer; ++ ++ u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); ++ u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); ++ u4Data = prSwCtrlInfo->u4Data; ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ switch (u2Id) { ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++#if CFG_SUPPORT_SWCR ++ case 0x9F00: ++ swCrReadWriteCmd(prAdapter, SWCR_WRITE, (UINT_16) u2SubId, &u4Data); ++ break; ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ case 0x1000: ++ if (u2SubId == 0x8000) { ++ /* CTIA power save mode setting (code: 0x10008000) */ ++ prAdapter->u4CtiaPowerMode = u4Data; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ /* */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ if (prAdapter->u4CtiaPowerMode == 0) ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ else if (prAdapter->u4CtiaPowerMode == 1) ++ ePowerMode = Param_PowerModeMAX_PSP; ++ else ++ ePowerMode = Param_PowerModeFast_PSP; ++ ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); ++ } ++ } ++ break; ++ case 0x1001: ++ if (u2SubId == 0x0) ++ prAdapter->fgEnOnlineScan = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x1) ++ prAdapter->fgDisBcnLostDetection = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x2) ++ prAdapter->rWifiVar.fgSupportUAPSD = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x3) { ++ prAdapter->u4UapsdAcBmp = u4Data & BITS(0, 15); ++ prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpDeliveryAC = ++ (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpTriggerAC = ++ (UINT_8) prAdapter->u4UapsdAcBmp; ++ } else if (u2SubId == 0x4) ++ prAdapter->fgDisStaAgingTimeoutDetection = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x5) ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = (UINT_8) u4Data; ++ else if (u2SubId == 0x0100) ++ prAdapter->rWifiVar.u8SupportRxGf = (UINT_8) u4Data; ++ else if (u2SubId == 0x0101) { ++ prAdapter->rWifiVar.u8SupportRxSgi20 = (UINT_8) u4Data; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = (UINT_8) u4Data; ++ } else if (u2SubId == 0x0102) ++ prAdapter->rWifiVar.u8SupportRxSTBC = (UINT_8) u4Data; ++ break; ++ ++#if CFG_SUPPORT_SWCR ++ case 0x1002: ++ if (u2SubId == 0x0) { ++ if (u4Data) ++ u4Data = BIT(HIF_RX_PKT_TYPE_MANAGEMENT); ++ swCrFrameCheckEnable(prAdapter, u4Data); ++ } else if (u2SubId == 0x1) { ++ BOOLEAN fgIsEnable; ++ UINT_8 ucType; ++ UINT_32 u4Timeout; ++ ++ fgIsEnable = (BOOLEAN) (u4Data & 0xff); ++ ucType = 0; /* ((u4Data>>4) & 0xf); */ ++ u4Timeout = ((u4Data >> 8) & 0xff); ++ swCrDebugCheckEnable(prAdapter, fgIsEnable, ucType, u4Timeout); ++ } ++ break; ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ case 0x2000: ++ DBGLOG(RSN, TRACE, "802.11w test 0x%x\n", u2SubId); ++ if (u2SubId == 0x0) ++ rsnStartSaQuery(prAdapter); ++ if (u2SubId == 0x1) ++ rsnStopSaQuery(prAdapter); ++ if (u2SubId == 0x2) ++ rsnSaQueryRequest(prAdapter, NULL); ++ if (u2SubId == 0x3) { ++ P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); ++ ++ authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP, NULL, 7, NULL); ++ } ++ /* wext_set_mode */ ++ /* ++ if (u2SubId == 0x3) { ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_DISABLED; ++ } ++ if (u2SubId == 0x4) { ++ //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_OPTIONAL; ++ } ++ if (u2SubId == 0x5) { ++ //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_REQUIRED; ++ } ++ */ ++ break; ++#endif ++ case 0xFFFF: ++ { ++/* CMD_ACCESS_REG rCmdAccessReg; */ ++#if 1 /* CFG_MT6573_SMT_TEST */ ++ if (u2SubId == 0x0123) { ++ ++ DBGLOG(HAL, TRACE, "set smt fixed rate: %u\n", u4Data); ++ ++ if ((ENUM_REGISTRY_FIXED_RATE_T) (u4Data) < FIXED_RATE_NUM) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (u4Data); ++ else ++ prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; ++ ++ if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) ++ /* Enable Auto (Long/Short) Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; ++ else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) ++ || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) ++ /* Force Short Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; ++ else ++ /* Force Long Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; ++ ++ /* abort to re-connect */ ++#if 1 ++ DBGLOG(OID, TRACE, "DisBySwC\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++#else ++ aisBssBeaconTimeout(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++ ++ } else if (u2SubId == 0x1234) { ++ /* 1. Disable On-Lin Scan */ ++ /* 3. Disable FIFO FULL no ack */ ++ /* 4. Disable Roaming */ ++ /* Disalbe auto tx power */ ++ /* 2. Keep at CAM mode */ ++ /* 5. Disable Beacon Timeout Detection */ ++ rWlanStatus = nicEnterCtiaMode(prAdapter, TRUE, TRUE); ++ } else if (u2SubId == 0x1235) { ++ /* 1. Enaable On-Lin Scan */ ++ /* 3. Enable FIFO FULL no ack */ ++ /* 4. Enable Roaming */ ++ /* Enable auto tx power */ ++ /* 2. Keep at Fast PS */ ++ /* 5. Enable Beacon Timeout Detection */ ++ rWlanStatus = nicEnterCtiaMode(prAdapter, FALSE, TRUE); ++ } ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ else if (u2SubId == 0x1240) { ++ DBGLOG(P2P, TRACE, "Disable Hotspot Optimization!\n"); ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = FALSE; ++ arHotspotOptimizationCfg.u4Level = 0; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); ++ } else if (u2SubId == 0x1241) { ++ DBGLOG(P2P, TRACE, "Enable Hotspot Optimization!\n"); ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; ++ arHotspotOptimizationCfg.u4Level = 5; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); ++ } ++#endif /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ else if (u2SubId == 0x1250) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET DUAL BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_NULL; ++ } else if (u2SubId == 0x1251) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET 2.4G BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_2G4; ++ } else if (u2SubId == 0x1252) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET 5G BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_5G; ++ } ++#endif ++ } ++ break; ++ ++ case 0x9000: ++ default: ++ { ++ rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; ++ rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_SW_DBG_CTRL_T), ++ (PUINT_8) &rCmdSwCtrl, pvSetBuffer, u4SetBufferLen); ++ } ++ } /* switch(u2Id) */ ++ ++ return rWlanStatus; ++} ++ ++ /* wlanoidSetSwCtrlWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query EEPROM value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; ++ CMD_ACCESS_EEPROM rCmdAccessEeprom; ++ ++ DEBUGFUNC("wlanoidQueryEepromRead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvQueryBuffer; ++ ++ kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); ++ rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_EEPROM, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryEepromRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_EEPROM), ++ (PUINT_8) &rCmdAccessEeprom, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryEepromRead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write EEPROM value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; ++ CMD_ACCESS_EEPROM rCmdAccessEeprom; ++ ++ DEBUGFUNC("wlanoidSetEepromWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); ++ rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; ++ rCmdAccessEeprom.u2Data = prEepromRwInfo->u2EepromData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_EEPROM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_EEPROM), ++ (PUINT_8) &rCmdAccessEeprom, pvSetBuffer, u4SetBufferLen); ++ ++} /* wlanoidSetEepromWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of the successfully transmitted ++* packets. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitOk"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitOk, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitOk */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of the successfully received ++* packets. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvOk"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvOk, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvOk */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames that the driver ++* fails to transmit. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames successfully ++* transmitted after exactly one collision. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitOneCollision"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) ++ (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - ++ prAdapter->rStatStruct.rRetryCount.QuadPart); ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) ++ (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - ++ prAdapter->rStatStruct.rRetryCount.QuadPart); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitOneCollision, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitOneCollision */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames successfully ++* transmitted after more than one collision. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitMoreCollisions"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitMoreCollisions, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++} /* wlanoidQueryXmitMoreCollisions */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames ++* not transmitted due to excessive collisions. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitMaxCollisions"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitMaxCollisions, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++} /* wlanoidQueryXmitMaxCollisions */ ++ ++#define MTK_CUSTOM_OID_INTERFACE_VERSION 0x00006620 /* for WPDWifi DLL */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current the OID interface version, ++* which is the interface between the application and driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryOidInterfaceVersion"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *(PUINT_32) pvQueryBuffer = MTK_CUSTOM_OID_INTERFACE_VERSION; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ DBGLOG(OID, WARN, "Custom OID interface version: %#08X\n", *(PUINT_32) pvQueryBuffer); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryOidInterfaceVersion */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#ifndef LINUX ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_MAC_MCAST_ADDR, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMcastAddr, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return WLAN_STATUS_SUCCESS; ++#endif ++} /* end of wlanoidQueryMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_8 ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Caller should provide this information */ ++ CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* The data must be a multiple of the Ethernet address size. */ ++ if ((u4SetBufferLen % MAC_ADDR_LEN)) { ++ DBGLOG(OID, WARN, "Invalid MC list length %u\n", u4SetBufferLen); ++ ++ *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Verify if we can support so many multicast addresses. */ ++ if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { ++ DBGLOG(OID, WARN, "Too many MC addresses\n"); ++ ++ return WLAN_STATUS_MULTICAST_FULL; ++ } ++ ++ /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && ++ * pvSetBuffer == NULL to clear exist Multicast List. ++ */ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; ++ rCmdMacMcastAddr.ucNetTypeIndex = ucNetTypeIndex; ++ kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_MAC_MCAST_ADDR, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_MAC_MCAST_ADDR), ++ (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); ++} /* end of wlanoidSetMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Packet Filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 u4NewPacketFilter; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) { ++ *pu4SetInfoLen = sizeof(UINT_32); ++ DBGLOG(OID, INFO, "iput buffer is too small"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ASSERT(pvSetBuffer); ++ ++ /* Set the new packet filter. */ ++ u4NewPacketFilter = *(PUINT_32) pvSetBuffer; ++ ++ DBGLOG(OID, TRACE, "New packet filter: %#08x\n", u4NewPacketFilter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set current packet filter! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ do { ++ /* Verify the bits of the new packet filter. If any bits are set that ++ we don't support, leave. */ ++ if (u4NewPacketFilter & ~(PARAM_PACKET_FILTER_SUPPORTED)) { ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ break; ++ } ++#if DBG ++ /* Need to enable or disable promiscuous support depending on the new ++ filter. */ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_PROMISCUOUS) ++ DBGLOG(OID, TRACE, "Enable promiscuous mode\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable promiscuous mode\n"); ++ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) ++ DBGLOG(OID, TRACE, "Enable all-multicast mode\n"); ++ else if (u4NewPacketFilter & PARAM_PACKET_FILTER_MULTICAST) ++ DBGLOG(OID, TRACE, "Enable multicast\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable multicast\n"); ++ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_BROADCAST) ++ DBGLOG(OID, TRACE, "Enable Broadcast\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable Broadcast\n"); ++#endif ++ } while (FALSE); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* Store the packet filter */ ++ ++ prAdapter->u4OsPacketFilter &= PARAM_PACKET_FILTER_P2P_MASK; ++ prAdapter->u4OsPacketFilter |= u4NewPacketFilter; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, pvSetBuffer, u4SetBufferLen); ++ } else { ++ return rStatus; ++ } ++} /* wlanoidSetCurrentPacketFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current packet filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryCurrentPacketFilter"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen >= sizeof(UINT_32)) { ++ ASSERT(pvQueryBuffer); ++ *(PUINT_32) pvQueryBuffer = prAdapter->u4OsPacketFilter; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryCurrentPacketFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query ACPI device power state. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#if DBG ++ PPARAM_DEVICE_POWER_STATE prPowerState; ++#endif ++ ++ DEBUGFUNC("wlanoidQueryAcpiDevicePowerState"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); ++ ++#if DBG ++ prPowerState = (PPARAM_DEVICE_POWER_STATE) pvQueryBuffer; ++ switch (*prPowerState) { ++ case ParamDeviceStateD0: ++ DBGLOG(OID, INFO, "Query Power State: D0\n"); ++ break; ++ case ParamDeviceStateD1: ++ DBGLOG(OID, INFO, "Query Power State: D1\n"); ++ break; ++ case ParamDeviceStateD2: ++ DBGLOG(OID, INFO, "Query Power State: D2\n"); ++ break; ++ case ParamDeviceStateD3: ++ DBGLOG(OID, INFO, "Query Power State: D3\n"); ++ break; ++ default: ++ break; ++ } ++#endif ++ ++ /* Since we will disconnect the newwork, therefore we do not ++ need to check queue empty */ ++ *(PPARAM_DEVICE_POWER_STATE) pvQueryBuffer = ParamDeviceStateD3; ++ /* WARNLOG(("Ready to transition to D3\n")); */ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* pwrmgtQueryPower */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set ACPI device power state. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PPARAM_DEVICE_POWER_STATE prPowerState; ++ BOOLEAN fgRetValue = TRUE; ++ ++ DEBUGFUNC("wlanoidSetAcpiDevicePowerState"); ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); ++ ++ ASSERT(pvSetBuffer); ++ prPowerState = (PPARAM_DEVICE_POWER_STATE) pvSetBuffer; ++ switch (*prPowerState) { ++ case ParamDeviceStateD0: ++ DBGLOG(OID, INFO, "Set Power State: D0\n"); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD0); ++ fgRetValue = nicpmSetAcpiPowerD0(prAdapter); ++ break; ++ case ParamDeviceStateD1: ++ DBGLOG(OID, INFO, "Set Power State: D1\n"); ++ /* no break here */ ++ case ParamDeviceStateD2: ++ DBGLOG(OID, INFO, "Set Power State: D2\n"); ++ /* no break here */ ++ case ParamDeviceStateD3: ++ DBGLOG(OID, INFO, "Set Power State: D3\n"); ++ fgRetValue = nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ break; ++ default: ++ break; ++ } ++ ++ if (fgRetValue == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++} /* end of wlanoidSetAcpiDevicePowerState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current fragmentation threshold. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryFragThreshold"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ DBGLOG(OID, LOUD, "\n"); ++ ++#if CFG_TX_FRAGMENT ++ ++ return WLAN_STATUS_SUCCESS; ++ ++#else ++ ++ return WLAN_STATUS_NOT_SUPPORTED; ++#endif /* CFG_TX_FRAGMENT */ ++ ++} /* end of wlanoidQueryFragThreshold() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a new fragmentation threshold to the ++* driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if CFG_TX_FRAGMENT ++ ++ return WLAN_STATUS_SUCCESS; ++ ++#else ++ ++ return WLAN_STATUS_NOT_SUPPORTED; ++#endif /* CFG_TX_FRAGMENT */ ++ ++} /* end of wlanoidSetFragThreshold() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RTS threshold. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRtsThreshold"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ DBGLOG(OID, LOUD, "\n"); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { ++ *pu4QueryInfoLen = sizeof(PARAM_RTS_THRESHOLD); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ *((PARAM_RTS_THRESHOLD *) pvQueryBuffer) = prAdapter->rWlanInfo.eRtsThreshold; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryRtsThreshold */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a new RTS threshold to the driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PARAM_RTS_THRESHOLD *prRtsThreshold; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_RTS_THRESHOLD); ++ if (u4SetBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRtsThreshold = (PARAM_RTS_THRESHOLD *) pvSetBuffer; ++ *prRtsThreshold = prAdapter->rWlanInfo.eRtsThreshold; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetRtsThreshold */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to turn radio off. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ ++ DEBUGFUNC("wlanoidSetDisassociate"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set disassociate! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* prepare message to AIS */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ /* indicate for disconnection */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ DBGLOG(OID, INFO, "DisconnectByOid\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, NULL, 0); ++ } ++#if !defined(LINUX) ++ prAdapter->fgIsRadioOff = TRUE; ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetDisassociate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query the power save profile. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQuery802dot11PowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen != 0) { ++ ASSERT(pvQueryBuffer); ++ ++/* *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile); */ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = ++ (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_AIS_INDEX].ucPsProfile); ++ *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); ++ ++ /* hack for CTIA power mode setting function */ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ /* set to non-zero value (to prevent MMI query 0, before it intends to set 0, */ ++ /* which will skip its following state machine) */ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE) 2; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ PARAM_POWER_MODE ePowerMode; ++ ++ DEBUGFUNC("wlanoidSet802dot11PowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); ++ if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { ++ /* WARNLOG(("Invalid power mode %d\n", */ ++ /* *(PPARAM_POWER_MODE) pvSetBuffer)); */ ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; ++ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ if (ePowerMode == Param_PowerModeCAM) ++ ; ++ else { ++ /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ ++ ++ if (prAdapter->u4CtiaPowerMode == 0) ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ else if (prAdapter->u4CtiaPowerMode == 1) ++ ePowerMode = Param_PowerModeMAX_PSP; ++ else if (prAdapter->u4CtiaPowerMode == 2) ++ ePowerMode = Param_PowerModeFast_PSP; ++ } ++ } ++ ++ status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); ++ ++ switch (ePowerMode) { ++ case Param_PowerModeCAM: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to CAM (%d)\n", ePowerMode); ++ break; ++ case Param_PowerModeMAX_PSP: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to MAX PS (%d)\n", ePowerMode); ++ break; ++ case Param_PowerModeFast_PSP: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to FAST PS (%d)\n", ePowerMode); ++ break; ++ default: ++ DBGLOG(OID, INFO, "invalid Wi-Fi PS mode setting (%d)\n", ePowerMode); ++ break; ++ } ++ ++ return status; ++ ++} /* end of wlanoidSetAcpiDevicePowerStateMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current status of AdHoc Mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set AdHoc Mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query RF frequency. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryFrequency"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ *(PUINT_32) pvQueryBuffer = ++ nicChannelNum2Freq(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].ucPrimaryChannel); ++ } else { ++ *(PUINT_32) pvQueryBuffer = 0; ++ } ++ } else { ++ *(PUINT_32) pvQueryBuffer = nicChannelNum2Freq(prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryFrequency() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set RF frequency by User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4FreqInKHz; ++ ++ DEBUGFUNC("wlanoidSetFrequency"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4FreqInKHz = (PUINT_32) pvSetBuffer; ++ ++ prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(*pu4FreqInKHz); ++ prAdapter->rWifiVar.rConnSettings.eAdHocBand = *pu4FreqInKHz < 5000000 ? BAND_2G4 : BAND_5G; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetFrequency() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set 802.11 channel of the radio frequency. ++* This is a proprietary function call to Lunux currently. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetChannel(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(0); /* // */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the Beacon Interval from User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryBeaconInterval"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; ++ } else { ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = 0; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryBeaconInterval() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the Beacon Interval to User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4BeaconInterval; ++ ++ DEBUGFUNC("wlanoidSetBeaconInterval"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4BeaconInterval = (PUINT_32) pvSetBuffer; ++ ++ if ((*pu4BeaconInterval < DOT11_BEACON_PERIOD_MIN) || (*pu4BeaconInterval > DOT11_BEACON_PERIOD_MAX)) { ++ DBGLOG(OID, TRACE, "Invalid Beacon Interval = %u\n", *pu4BeaconInterval); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prAdapter->rWlanInfo.u2BeaconPeriod = (UINT_16) *pu4BeaconInterval; ++ ++ DBGLOG(OID, INFO, "Set beacon interval: %d\n", prAdapter->rWlanInfo.u2BeaconPeriod); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetBeaconInterval() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the ATIM window from User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryAtimWindow"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = 0; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2AtimWindow; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidQueryAtimWindow() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the ATIM window to User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4AtimWindow; ++ ++ DEBUGFUNC("wlanoidSetAtimWindow"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4AtimWindow = (PUINT_32) pvSetBuffer; ++ ++ prAdapter->rWlanInfo.u2AtimWindow = (UINT_16) *pu4AtimWindow; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetAtimWindow() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to Set the MAC address which is currently used by the NIC. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(0); /* // */ ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetCurrentAddr() */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the checksum offload function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i, u4CSUMFlags; ++ CMD_BASIC_CONFIG rCmdBasicConfig; ++ ++ DEBUGFUNC("wlanoidSetCSUMOffload"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ u4CSUMFlags = *(PUINT_32) pvSetBuffer; ++ ++ kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); ++ ++ for (i = 0; i < 6; i++) { /* set to broadcast address for not-specified */ ++ rCmdBasicConfig.rMyMacAddr[i] = 0xff; ++ } ++ ++ rCmdBasicConfig.ucNative80211 = 0; /* @FIXME: for Vista */ ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(2); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(1); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(0); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(2); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(1); ++ ++ if (u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(0); ++ ++ prAdapter->u4CSUMFlags = u4CSUMFlags; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BASIC_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BASIC_CONFIG), (PUINT_8) &rCmdBasicConfig, pvSetBuffer, u4SetBufferLen); ++} ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the IP address for pattern search function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ UINT_32 u4IpV4AddrListSize; ++ P_BSS_INFO_T prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++#endif ++ ++ DEBUGFUNC("wlanoidSetNetworkAddress"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ if (u4IpAddressCount == 0) ++ u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ u4IpV4AddrListSize = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + ++ (u4IpAddressCount * sizeof(IPV4_NETWORK_ADDRESS)); ++ if (prBssInfo->prIpV4NetAddrList) ++ FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); ++ prBssInfo->prIpV4NetAddrList = (P_IPV4_NETWORK_ADDRESS_LIST) kalMemAlloc(u4IpV4AddrListSize, VIR_MEM_TYPE); ++ if (prBssInfo->prIpV4NetAddrList == NULL) { ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return WLAN_STATUS_FAILURE; ++ } ++ prBssInfo->prIpV4NetAddrList->ucAddrCount = (UINT_8) u4IpAddressCount; ++#endif ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ /* only to set IP address to FW once ARP filter is enabled */ ++ if (prAdapter->fgEnArpFilter) { ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ ++ DBGLOG(OID, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); ++ ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ kalMemCopy(prBssInfo->prIpV4NetAddrList->arNetAddr[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++#endif ++ ++ j++; ++ ++ pucBuf = (PUINT_8) &prNetAddrIp->in_addr; ++ DBGLOG(OID, INFO, ++ "prNetAddrIp->in_addr:%d:%d:%d:%d\n", pucBuf[0], pucBuf[1], pucBuf[2], ++ pucBuf[3]); ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ } ++ ++ } else { ++ prCmdNetworkAddressList->ucAddressCount = 0; ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set driver to switch into RF test mode ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, ++* should be NULL ++* \param[in] u4SetBufferLen The length of the set buffer, should be 0 ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_DATA ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus; ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ DEBUGFUNC("wlanoidRftestSetTestMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen == 0) { ++ if (prAdapter->fgTestMode == FALSE) { ++ /* switch to RF Test mode */ ++ rCmdTestCtrl.ucAction = 0; /* Switch mode */ ++ rCmdTestCtrl.u.u4OpMode = 1; /* RF test mode */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ TRUE, ++ TRUE, ++ nicCmdEventEnterRfTest, ++ nicOidCmdEnterRFTestTimeout, ++ sizeof(CMD_TEST_CTRL_T), ++ (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); ++ } else { ++ /* already in test mode .. */ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } ++ } else { ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ DBGLOG(OID, INFO, "Enter TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", ++ u4SetBufferLen, prAdapter->fgTestMode, rStatus); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set driver to switch into normal operation mode from RF test mode ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* should be NULL ++* \param[in] u4SetBufferLen The length of the set buffer, should be 0 ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_DATA ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus; ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ DEBUGFUNC("wlanoidRftestSetTestMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen == 0) { ++ if (prAdapter->fgTestMode == TRUE) { ++ /* switch to normal mode */ ++ rCmdTestCtrl.ucAction = 0; /* Switch mode */ ++ rCmdTestCtrl.u.u4OpMode = 0; /* normal mode */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventLeaveRfTest, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_TEST_CTRL_T), ++ (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); ++ } else { ++ /* already in normal mode .. */ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } ++ } else { ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ DBGLOG(OID, INFO, "Abort TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", ++ u4SetBufferLen, prAdapter->fgTestMode, rStatus); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief query for RF test parameter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidRftestQueryAutoTest"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); ++ ++ if (u4QueryBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { ++ DBGLOG(OID, ERROR, "Invalid data. QueryBufferLen: %u.\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvQueryBuffer; ++ rStatus = rftestQueryATInfo(prAdapter, ++ prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData, pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set RF test parameter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidRftestSetAutoTest"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); ++ ++ if (u4SetBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { ++ DBGLOG(OID, ERROR, "Invalid data. SetBufferLen: %u.\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvSetBuffer; ++ rStatus = rftestSetATInfo(prAdapter, prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData); ++ ++ return rStatus; ++} ++ ++/* RF test OID set handler */ ++WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_TEST_CTRL_T pCmdTestCtrl; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_TEST_MODE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ ++ /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); ++ pCmdTestCtrl->ucAction = 1; /* Set ATInfo */ ++ pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; ++ pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS ++rftestQueryATInfo(IN P_ADAPTER_T prAdapter, ++ UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_TEST_CTRL_T pCmdTestCtrl; ++ UINT_8 ucCmdSeqNum; ++ P_EVENT_TEST_STATUS prTestStatus; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u4FuncIndex == RF_AT_FUNCID_FW_INFO) { ++ /* driver implementation */ ++ prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; ++ ++ prTestStatus->rATInfo.u4FuncData = ++ (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); ++ u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); ++ ++ return WLAN_STATUS_SUCCESS; ++ } else if (u4FuncIndex == RF_AT_FUNCID_DRV_INFO) { ++ /* driver implementation */ ++ prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; ++ ++ prTestStatus->rATInfo.u4FuncData = CFG_DRV_OWN_VERSION; ++ u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryRfTestATInfo; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_TEST_MODE; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pvInformationBuffer = pvQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4QueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); ++ pCmdTestCtrl->ucAction = 2; /* Get ATInfo */ ++ pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; ++ pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen) ++{ ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ ASSERT(prAdapter); ++ ++ rCmdTestCtrl.ucAction = 5; /* Set Channel Frequency */ ++ rCmdTestCtrl.u.u4ChannelFreq = u4FreqInKHz; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, sizeof(CMD_TEST_CTRL_T), (PUINT_8) &rCmdTestCtrl, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ DEBUGFUNC("wlanSendSetQueryCmd"); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(OID, TRACE, "ucCmdSeqNum =%d, ucCID =%d\n", ucCmdSeqNum, ucCID); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WAPI ui to set wapi mode, which is needed to info the the driver ++* to operation at WAPI mode while driver initialize. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ DEBUGFUNC("wlanoidSetWapiMode"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ /* Todo:: For support WAPI and Wi-Fi at same driver, use the set wapi assoc ie at the check point */ ++ /* The Adapter Connection setting fgUseWapi will cleat whil oid set mode (infra), */ ++ /* And set fgUseWapi True while set wapi assoc ie */ ++ /* policay selection, add key all depend on this flag, */ ++ /* The fgUseWapi may remove later */ ++ if (*(PUINT_32) pvSetBuffer) ++ prAdapter->fgUseWapi = TRUE; ++ else ++ prAdapter->fgUseWapi = FALSE; ++ ++#if 0 ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + 4)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + 4; ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_WAPI_MODE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ cp = (PUINT_8) (prWifiCmd->aucBuffer); ++ ++ kalMemCopy(cp, (PUINT_8) pvSetBuffer, 4); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++#else ++ return WLAN_STATUS_SUCCESS; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WAPI to set the assoc info, which is needed to add to ++* Association request frame while join WAPI AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_WAPI_INFO_ELEM_T prWapiInfo; ++ PUINT_8 cp; ++ UINT_16 u2AuthSuiteCount = 0; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_32 u4AuthKeyMgtSuite = 0; ++ UINT_32 u4PairSuite = 0; ++ UINT_32 u4GroupSuite = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetWapiAssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen < 20 /* From EID to Group cipher */) { ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++ DBGLOG(SEC, INFO, "fgWapiMode = FALSE due to u4SetBufferLen %u < 20!\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = TRUE; ++ ++ /* if (prWapiInfo->ucElemId != ELEM_ID_WAPI) */ ++ /* DBGLOG(SEC, TRACE, ("Not WAPI IE ?!\n")); */ ++ ++ /* if (prWapiInfo->ucLength < 18) */ ++ /* return WLAN_STATUS_INVALID_LENGTH; */ ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prWapiInfo = (P_WAPI_INFO_ELEM_T) pvSetBuffer; ++ ++ if (prWapiInfo->ucElemId != ELEM_ID_WAPI) { ++ DBGLOG(SEC, INFO, "Not WAPI IE ?! u4SetBufferLen = %u\n", u4SetBufferLen); ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prWapiInfo->ucLength < 18) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Skip Version check */ ++ cp = (PUINT_8) &prWapiInfo->u2AuthKeyMgtSuiteCount; ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ ++ if (u2AuthSuiteCount > 1) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ cp = (PUINT_8) &prWapiInfo->aucAuthKeyMgtSuite1[0]; ++ WLAN_GET_FIELD_32(cp, &u4AuthKeyMgtSuite); ++ ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info auth mgt suite [%d]: %02x-%02x-%02x-%02x\n", ++ u2AuthSuiteCount, ++ (UCHAR) (u4AuthKeyMgtSuite & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 16) & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 24) & 0x000000FF)); ++ ++ if (u4AuthKeyMgtSuite != WAPI_AKM_SUITE_802_1X && u4AuthKeyMgtSuite != WAPI_AKM_SUITE_PSK) ++ ASSERT(FALSE); ++ ++ cp += 4; ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ if (u2PairSuiteCount > 1) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ cp += 2; ++ WLAN_GET_FIELD_32(cp, &u4PairSuite); ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info pairwise cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ u2PairSuiteCount, ++ (UCHAR) (u4PairSuite & 0x000000FF), ++ (UCHAR) ((u4PairSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4PairSuite >> 16) & 0x000000FF), (UCHAR) ((u4PairSuite >> 24) & 0x000000FF)); ++ ++ if (u4PairSuite != WAPI_CIPHER_SUITE_WPI) ++ ASSERT(FALSE); ++ ++ cp += 4; ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info group cipher suite : %02x-%02x-%02x-%02x\n", ++ (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (u4GroupSuite != WAPI_CIPHER_SUITE_WPI) ++ ASSERT(FALSE); ++ ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite = u4AuthKeyMgtSuite; ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher = u4PairSuite; ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher = u4GroupSuite; ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucWapiAssocInfoIEs, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the wpi key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer P_PARAM_WPI_KEY, which is set by NDIS, is unpacked. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_WPI_KEY_T prNewKey; ++ P_CMD_802_11_KEY prCmdKey; ++ PUINT_8 pc; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetWapiKey"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\r\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewKey = (P_PARAM_WPI_KEY_T) pvSetBuffer; ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) pvSetBuffer, 560); ++ pc = (PUINT_8) pvSetBuffer; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Exception check */ ++ if (prNewKey->ucKeyID != 0x1 || prNewKey->ucKeyID != 0x0) { ++ prNewKey->ucKeyID = prNewKey->ucKeyID & BIT(0); ++ /* DBGLOG(SEC, INFO, ("Invalid WAPI key ID (%d)\r\n", prNewKey->ucKeyID)); */ ++ } ++ ++ /* Dump P_PARAM_WPI_KEY_T content. */ ++ DBGLOG(OID, TRACE, "Set: Dump P_PARAM_WPI_KEY_T content\r\n"); ++ DBGLOG(OID, TRACE, "TYPE : %d\r\n", prNewKey->eKeyType); ++ DBGLOG(OID, TRACE, "Direction : %d\r\n", prNewKey->eDirection); ++ DBGLOG(OID, TRACE, "KeyID : %d\r\n", prNewKey->ucKeyID); ++ DBGLOG(OID, TRACE, "AddressIndex:\r\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->aucAddrIndex, 12); ++ prNewKey->u4LenWPIEK = 16; ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPIEK, (UINT_8) prNewKey->u4LenWPIEK); ++ prNewKey->u4LenWPICK = 16; ++ ++ DBGLOG(OID, TRACE, "CK Key(%d):\r\n", (UINT_8) prNewKey->u4LenWPICK); ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPICK, (UINT_8) prNewKey->u4LenWPICK); ++ DBGLOG(OID, TRACE, "PN:\r\n"); ++ if (prNewKey->eKeyType == 0) { ++ prNewKey->aucPN[0] = 0x5c; ++ prNewKey->aucPN[1] = 0x36; ++ prNewKey->aucPN[2] = 0x5c; ++ prNewKey->aucPN[3] = 0x36; ++ prNewKey->aucPN[4] = 0x5c; ++ prNewKey->aucPN[5] = 0x36; ++ prNewKey->aucPN[6] = 0x5c; ++ prNewKey->aucPN[7] = 0x36; ++ prNewKey->aucPN[8] = 0x5c; ++ prNewKey->aucPN[9] = 0x36; ++ prNewKey->aucPN[10] = 0x5c; ++ prNewKey->aucPN[11] = 0x36; ++ prNewKey->aucPN[12] = 0x5c; ++ prNewKey->aucPN[13] = 0x36; ++ prNewKey->aucPN[14] = 0x5c; ++ prNewKey->aucPN[15] = 0x36; ++ } ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucPN, 16); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetBufferLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_ID_ADD_REMOVE_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 1; /* Add */ ++ ++ if (prNewKey->eKeyType == ENUM_WPI_PAIRWISE_KEY) { ++ prCmdKey->ucTxKey = 1; ++ prCmdKey->ucKeyType = 1; ++ } ++ ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->aucAddrIndex, MAC_ADDR_LEN); ++ ++ prCmdKey->ucNetType = 0; /* AIS */ ++ ++ prCmdKey->ucKeyId = prNewKey->ucKeyID; ++ ++ prCmdKey->ucKeyLen = 32; ++ ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WPI; ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucWPIEK, 16); ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial + 16, (PUINT_8) prNewKey->aucWPICK, 16); ++ ++ kalMemCopy(prCmdKey->aucKeyRsc, (PUINT_8) prNewKey->aucPN, 16); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetAddKey */ ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the assoc info, which is needed to add to ++* Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetWSCAssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucWSCAssocInfoIE, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++#endif ++ ++#if CFG_ENABLE_WAKEUP_ON_LAN ++WLAN_STATUS ++wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_PM_PACKET_PATTERN prPacketPattern; ++ ++ DEBUGFUNC("wlanoidSetAddWakeupPattern"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); ++ ++ if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; ++ ++ /* FIXME: ++ * Send the struct to firmware */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++ ++WLAN_STATUS ++wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_PM_PACKET_PATTERN prPacketPattern; ++ ++ DEBUGFUNC("wlanoidSetAddWakeupPattern"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); ++ ++ if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; ++ ++ /* FIXME: ++ * Send the struct to firmware */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++ ++WLAN_STATUS ++wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ PUINT_32 pu4WakeupEventEnable; ++ ++ DEBUGFUNC("wlanoidQueryEnableWakeup"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ pu4WakeupEventEnable = (PUINT_32) pvQueryBuffer; ++ ++ *pu4WakeupEventEnable = prAdapter->u4WakeupEventEnable; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4WakeupEventEnable; ++ ++ DEBUGFUNC("wlanoidSetEnableWakup"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ pu4WakeupEventEnable = (PUINT_32) pvSetBuffer; ++ prAdapter->u4WakeupEventEnable = *pu4WakeupEventEnable; ++ ++ /* FIXME: ++ * Send Command Event for setting wakeup-pattern / Magic Packet to firmware ++ * */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure PS related settings for WMM-PS test. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T prWmmPsTestInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_SET_WMM_PS_TEST_STRUCT_T rSetWmmPsTestParam; ++ UINT_16 u2CmdBufLen; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetWiFiWmmPsTest"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T); ++ ++ prWmmPsTestInfo = (P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T) pvSetBuffer; ++ ++ rSetWmmPsTestParam.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rSetWmmPsTestParam.bmfgApsdEnAc = prWmmPsTestInfo->bmfgApsdEnAc; ++ rSetWmmPsTestParam.ucIsEnterPsAtOnce = prWmmPsTestInfo->ucIsEnterPsAtOnce; ++ rSetWmmPsTestParam.ucIsDisableUcTrigger = prWmmPsTestInfo->ucIsDisableUcTrigger; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[rSetWmmPsTestParam.ucNetTypeIndex]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ prPmProfSetupInfo->ucBmpDeliveryAC = (rSetWmmPsTestParam.bmfgApsdEnAc >> 4) & BITS(0, 3); ++ prPmProfSetupInfo->ucBmpTriggerAC = rSetWmmPsTestParam.bmfgApsdEnAc & BITS(0, 3); ++ ++ u2CmdBufLen = sizeof(CMD_SET_WMM_PS_TEST_STRUCT_T); ++ ++#if 0 ++ /* it will apply the disable trig or not immediately */ ++ if (prPmInfo->ucWmmPsDisableUcPoll && prPmInfo->ucWmmPsConnWithTrig) ++ ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, TRUE); */ ++ else ++ ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, FALSE); */ ++#endif ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_WMM_PS_TEST_PARMS, TRUE, FALSE, TRUE, NULL, /* TODO? */ ++ NULL, u2CmdBufLen, (PUINT_8) &rSetWmmPsTestParam, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetWiFiWmmPsTest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure enable/disable TX A-MPDU feature. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_TX_AMPDU_T rTxAmpdu; ++ UINT_16 u2CmdBufLen; ++ PBOOLEAN pfgEnable; ++ ++ DEBUGFUNC("wlanoidSetTxAmpdu"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(BOOLEAN); ++ ++ pfgEnable = (PBOOLEAN) pvSetBuffer; ++ ++ rTxAmpdu.fgEnable = *pfgEnable; ++ ++ u2CmdBufLen = sizeof(CMD_TX_AMPDU_T); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TX_AMPDU, ++ TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rTxAmpdu, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetTxAmpdu */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure reject/accept ADDBA Request. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_ADDBA_REJECT_T rAddbaReject; ++ UINT_16 u2CmdBufLen; ++ PBOOLEAN pfgEnable; ++ ++ DEBUGFUNC("wlanoidSetAddbaReject"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(BOOLEAN); ++ ++ pfgEnable = (PBOOLEAN) pvSetBuffer; ++ ++ rAddbaReject.fgEnable = *pfgEnable; ++ ++ u2CmdBufLen = sizeof(CMD_ADDBA_REJECT_T); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ADDBA_REJECT, ++ TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rAddbaReject, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetAddbaReject */ ++ ++#if CFG_SLT_SUPPORT ++ ++WLAN_STATUS ++wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++ ++ DEBUGFUNC("wlanoidQuerySLTStatus"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvQueryBuffer); ++ ++ prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvQueryBuffer; ++ ++ prSltInfo = &(prAdapter->rWifiVar.rSltInfo); ++ ++ switch (prMtkSltInfo->rSltFuncIdx) { ++ case ENUM_MTK_SLT_FUNC_LP_SET: ++ { ++ P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); ++ ++ prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ prLpSetting->u4BcnRcvNum = prSltInfo->u4BeaconReceiveCnt; ++ } ++ break; ++ default: ++ /* TBD... */ ++ break; ++ } ++ ++ return rWlanStatus; ++} /* wlanoidQuerySLTStatus */ ++ ++WLAN_STATUS ++wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ ++ /* 1. Action: Update or Initial Set ++ * 2. Role. ++ * 3. Target MAC address. ++ * 4. RF BW & Rate Settings ++ */ ++ ++ DEBUGFUNC("wlanoidUpdateSLTMode"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvSetBuffer; ++ ++ prSltInfo = &(prAdapter->rWifiVar.rSltInfo); ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ switch (prMtkSltInfo->rSltFuncIdx) { ++ case ENUM_MTK_SLT_FUNC_INITIAL: /* Initialize */ ++ { ++ P_PARAM_MTK_SLT_INITIAL_STRUCT_T prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_INITIAL_STRUCT_T)); ++ ++ prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prSltInfo->prPseudoStaRec != NULL) { ++ /* The driver has been initialized. */ ++ prSltInfo->prPseudoStaRec = NULL; ++ } ++ ++ prSltInfo->prPseudoBssDesc = scanSearchExistingBssDesc(prAdapter, ++ BSS_TYPE_IBSS, ++ prMtkSltInit->aucTargetMacAddr, ++ prMtkSltInit->aucTargetMacAddr); ++ ++ prSltInfo->u2SiteID = prMtkSltInit->u2SiteID; ++ ++ /* Bandwidth 2.4G: Channel 1~14 ++ * Bandwidth 5G: *36, 40, 44, 48, 52, 56, 60, 64, ++ * *100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, ++ * 149, 153, *157, 161, ++ * 184, 188, 192, 196, 200, 204, 208, 212, *216 ++ */ ++ prSltInfo->ucChannel2G4 = 1 + (prSltInfo->u2SiteID % 4) * 5; ++ ++ switch (prSltInfo->ucChannel2G4) { ++ case 1: ++ prSltInfo->ucChannel5G = 36; ++ break; ++ case 6: ++ prSltInfo->ucChannel5G = 52; ++ break; ++ case 11: ++ prSltInfo->ucChannel5G = 104; ++ break; ++ case 16: ++ prSltInfo->ucChannel2G4 = 14; ++ prSltInfo->ucChannel5G = 161; ++ break; ++ default: ++ ASSERT(FALSE); ++ } ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ do { ++ prSltInfo->prPseudoBssDesc = scanAllocateBssDesc(prAdapter); ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ } while (FALSE); ++ } else { ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ } ++ ++ if (prBssDesc) { ++ prBssDesc->eBSSType = BSS_TYPE_IBSS; ++ ++ COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prMtkSltInit->aucTargetMacAddr); ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ ++ prBssDesc->u2BeaconInterval = 100; ++ prBssDesc->u2ATIMWindow = 0; ++ prBssDesc->ucDTIMPeriod = 1; ++ ++ prBssDesc->u2IELength = 0; ++ ++ prBssDesc->fgIsERPPresent = TRUE; ++ prBssDesc->fgIsHTPresent = TRUE; ++ ++ prBssDesc->u2OperationalRateSet = BIT(RATE_36M_INDEX); ++ prBssDesc->u2BSSBasicRateSet = BIT(RATE_36M_INDEX); ++ prBssDesc->fgIsUnknownBssBasicRate = FALSE; ++ ++ prBssDesc->fgIsLargerTSF = TRUE; ++ ++ prBssDesc->eBand = BAND_2G4; ++ ++ prBssDesc->ucChannelNum = prSltInfo->ucChannel2G4; ++ ++ prBssDesc->ucPhyTypeSet = PHY_TYPE_SET_802_11ABGN; ++ ++ GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); ++ } ++ } ++ break; ++ case ENUM_MTK_SLT_FUNC_RATE_SET: /* Update RF Settings. */ ++ if (prSltInfo->prPseudoStaRec == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ P_PARAM_MTK_SLT_TR_TEST_STRUCT_T prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_TR_TEST_STRUCT_T)); ++ ++ prStaRec = prSltInfo->prPseudoStaRec; ++ prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { ++ prBssInfo->eBand = BAND_5G; ++ prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel5G; ++ } ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM24) { ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel2G4; ++ } ++ ++ if ((prTRSetting->u4FixedRate & FIXED_BW_DL40) != 0) { ++ /* RF 40 */ ++ /* It would controls RFBW capability in WTBL. */ ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ /* This controls RF BW, RF BW would be 40 only if */ ++ /* 1. PHY_TYPE_BIT_HT is TRUE. */ ++ /* 2. SCO is SCA/SCB. */ ++ prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ ++ /* U20/L20 Control. */ ++ switch (prTRSetting->u4FixedRate & 0xC000) { ++ case FIXED_EXT_CHNL_U20: ++ prBssInfo->eBssSCO = CHNL_EXT_SCB; /* +2 */ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) ++ prBssInfo->ucPrimaryChannel += 2; ++ else { ++ /* For channel 1, testing L20 at channel 8. */ ++ if (prBssInfo->ucPrimaryChannel < 5) ++ prBssInfo->ucPrimaryChannel = 8; ++ } ++ break; ++ case FIXED_EXT_CHNL_L20: ++ default: /* 40M */ ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* -2 */ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { ++ prBssInfo->ucPrimaryChannel -= 2; ++ } else { ++ /* For channel 11 / 14. testing U20 at channel 3. */ ++ if (prBssInfo->ucPrimaryChannel > 10) ++ prBssInfo->ucPrimaryChannel = 3; ++ } ++ break; ++ } ++ } else { ++ /* RF 20 */ ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ } ++ ++ prBssInfo->fgErpProtectMode = FALSE; ++ prBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; ++ prBssInfo->eGfOperationMode = GF_MODE_NORMAL; ++ ++ nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); ++ ++ prStaRec->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ switch (prTRSetting->u4FixedRate & 0xFF) { ++ case RATE_OFDM_54M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_54M_INDEX); ++ break; ++ case RATE_OFDM_48M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_48M_INDEX); ++ break; ++ case RATE_OFDM_36M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); ++ break; ++ case RATE_OFDM_24M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_24M_INDEX); ++ break; ++ case RATE_OFDM_6M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_6M_INDEX); ++ break; ++ case RATE_CCK_11M_LONG: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_11M_INDEX); ++ break; ++ case RATE_CCK_1M_LONG: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_1M_INDEX); ++ break; ++ case RATE_GF_MCS_0: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ break; ++ case RATE_MM_MCS_7: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; ++#if 0 /* Only for Current Measurement Mode. */ ++ prStaRec->u2HtCapInfo |= (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++#endif ++ break; ++ case RATE_GF_MCS_7: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ break; ++ default: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); ++ break; ++ } ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ break; ++ case ENUM_MTK_SLT_FUNC_LP_SET: /* Reset LP Test Result. */ ++ { ++ P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); ++ ++ prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ /* Please initial SLT Mode first. */ ++ break; ++ } ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ ++ switch (prLpSetting->rLpTestMode) { ++ case ENUM_MTK_LP_TEST_NORMAL: ++ /* In normal mode, we would use target MAC address to be the BSSID. */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ prSltInfo->fgIsDUT = FALSE; ++ break; ++ case ENUM_MTK_LP_TEST_GOLDEN_SAMPLE: ++ /* 1. Lower AIFS of BCN queue. ++ * 2. Fixed Random Number tobe 0. ++ */ ++ prSltInfo->fgIsDUT = FALSE; ++ /* In LP test mode, we would use MAC address of Golden Sample to be the BSSID. */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ break; ++ case ENUM_MTK_LP_TEST_DUT: ++ /* 1. Enter Sleep Mode. ++ * 2. Fix random number a large value & enlarge AIFN of BCN queue. ++ */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssDesc->aucSrcAddr); ++ prSltInfo->u4BeaconReceiveCnt = 0; ++ prSltInfo->fgIsDUT = TRUE; ++ break; ++ } ++ ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ return WLAN_STATUS_FAILURE; ++ ++ return rWlanStatus; ++} /* wlanoidUpdateSLTMode */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query NVRAM value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; ++ UINT_16 u2Data; ++ BOOLEAN fgStatus; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidQueryNvramRead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvQueryBuffer; ++ ++ if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_READ) { ++ /* change to byte offset */ ++ fgStatus = kalCfgDataRead16(prAdapter->prGlueInfo, ++ prNvramRwInfo->ucEepromIndex << 1, ++ &u2Data); ++ ++ if (fgStatus) { ++ prNvramRwInfo->u2EepromData = u2Data; ++ DBGLOG(OID, INFO, "NVRAM Read: index=%#X, data=%#02X\r\n", ++ prNvramRwInfo->ucEepromIndex, u2Data); ++ } else { ++ DBGLOG(OID, ERROR, "NVRAM Read Failed: index=%#x.\r\n", prNvramRwInfo->ucEepromIndex); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_GETSIZE) { ++ prNvramRwInfo->u2EepromData = CFG_FILE_WIFI_REC_SIZE; ++ DBGLOG(OID, INFO, "EEPROM size =%d\r\n", prNvramRwInfo->u2EepromData); ++ } ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ return rStatus; ++} /* wlanoidQueryNvramRead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write NVRAM value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; ++ BOOLEAN fgStatus; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetNvramWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvSetBuffer; ++ ++ /* change to byte offset */ ++ fgStatus = kalCfgDataWrite16(prAdapter->prGlueInfo, ++ prNvramRwInfo->ucEepromIndex << 1, ++ prNvramRwInfo->u2EepromData); ++ ++ if (fgStatus == FALSE) { ++ DBGLOG(OID, ERROR, "NVRAM Write Failed.\r\n"); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ ++ return rStatus; ++} /* wlanoidSetNvramWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_CFG_SRC_TYPE_T); ++ ++ if (kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE) ++ *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_NVRAM; ++ else ++ *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_EEPROM; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ *pu4QueryInfoLen = sizeof(P_ENUM_EEPROM_TYPE_T); ++ ++#if CFG_SUPPORT_NIC_CAPABILITY ++ if (prAdapter->fgIsEepromUsed == TRUE) ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_PRESENT; ++ else ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; ++#else ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_8 pucCountry; ++ UINT_16 u2CountryCode; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(u4SetBufferLen == 2); ++ ++ *pu4SetInfoLen = 2; ++ ++ pucCountry = pvSetBuffer; ++ u2CountryCode = (((UINT_16) pucCountry[0]) << 8) | ((UINT_16) pucCountry[1]); ++ ++ /* previous country code == FF : ignore country code, current country code == FE : resume */ ++ if (prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup == COUNTRY_CODE_FF) { ++ if (u2CountryCode != COUNTRY_CODE_FE) { ++ DBGLOG(OID, INFO, "Skip country code cmd (0x%04x)\n", u2CountryCode); ++ return WLAN_STATUS_SUCCESS; ++ } ++ DBGLOG(OID, INFO, "Resume handle country code cmd (0x%04x)\n", u2CountryCode); ++ } ++ ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = u2CountryCode; ++ prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ DBGLOG(OID, LOUD, "u2CountryCodeBakup=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup); ++ ++ /* Force to re-search country code in country domains */ ++ prAdapter->prDomainInfo = NULL; ++ rlmDomainSendCmd(prAdapter, TRUE); ++ ++ /* Update supported channel list in channel table based on current country domain */ ++ wlanUpdateChannelTable(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if 0 ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; ++ CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; ++ ++ DEBUGFUNC("wlanoidSetNoaParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); ++ rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; ++ rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; ++ rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++} ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; ++ CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; ++ ++ DEBUGFUNC("wlanoidSetOppPsParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_OPPPS_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++} ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; ++ CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetUApsdParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; ++ prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; ++ ++ rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; ++ rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; ++ rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; ++ rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; ++ prPmProfSetupInfo->ucBmpDeliveryAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ prPmProfSetupInfo->ucBmpTriggerAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ ++ rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; ++ prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set BT profile or BT information and the ++* driver will set the built-in PTA configuration into chip. ++* ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ++ P_PTA_IPC_T prPtaIpc; ++ ++ DEBUGFUNC("wlanoidSetBT.\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PTA_IPC_T); ++ if (u4SetBufferLen != sizeof(PTA_IPC_T)) { ++ WARNLOG(("Invalid length %u\n", u4SetBufferLen)); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set BT profile because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ prPtaIpc = (P_PTA_IPC_T) pvSetBuffer; ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(OID, INFO, ++ "BCM BWCS CMD: BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", ++ prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], ++ prPtaIpc->u.aucBTPParams[3]; ++ ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BWCS, ++ TRUE, FALSE, FALSE, NULL, NULL, sizeof(PTA_IPC_T), (PUINT_8) prPtaIpc, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current BT profile and BTCR values ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBT(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++/* P_PARAM_PTA_IPC_T prPtaIpc; */ ++/* UINT_32 u4QueryBuffLen; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PTA_IPC_T); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(PTA_IPC_T)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++/* prPtaIpc = (P_PTA_IPC_T)pvQueryBuffer; */ ++/* prPtaIpc->ucCmd = BT_CMD_PROFILE; */ ++/* prPtaIpc->ucLen = sizeof(prPtaIpc->u); */ ++/* nicPtaGetProfile(prAdapter, (PUINT_8)&prPtaIpc->u, &u4QueryBuffLen); */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if 0 ++WLAN_STATUS ++wlanoidQueryBtSingleAntenna(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PTA_INFO_T prPtaInfo; ++ PUINT_32 pu4SingleAntenna; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(UINT_32)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ pu4SingleAntenna = (PUINT_32) pvQueryBuffer; ++ ++ if (prPtaInfo->fgSingleAntenna) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 1\r\n")); */ ++ *pu4SingleAntenna = 1; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 0\r\n")); */ ++ *pu4SingleAntenna = 0; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetBtSingleAntenna(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ++ PUINT_32 pu4SingleAntenna; ++ UINT_32 u4SingleAntenna; ++ P_PTA_INFO_T prPtaInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen != sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (IS_ARB_IN_RFTEST_STATE(prAdapter)) ++ return WLAN_STATUS_SUCCESS; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set antenna because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ pu4SingleAntenna = (PUINT_32) pvSetBuffer; ++ u4SingleAntenna = *pu4SingleAntenna; ++ ++ if (u4SingleAntenna == 0) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 0\r\n")); */ ++ prPtaInfo->fgSingleAntenna = FALSE; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 1\r\n")); */ ++ prPtaInfo->fgSingleAntenna = TRUE; ++ } ++ ptaFsmRunEventSetConfig(prAdapter, &prPtaInfo->rPtaParam); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++WLAN_STATUS ++wlanoidQueryPta(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PTA_INFO_T prPtaInfo; ++ PUINT_32 pu4Pta; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(UINT_32)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ pu4Pta = (PUINT_32) pvQueryBuffer; ++ ++ if (prPtaInfo->fgEnabled) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 1\r\n")); */ ++ *pu4Pta = 1; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 0\r\n")); */ ++ *pu4Pta = 0; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetPta(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4PtaCtrl; ++ UINT_32 u4PtaCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen != sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (IS_ARB_IN_RFTEST_STATE(prAdapter)) ++ return WLAN_STATUS_SUCCESS; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set BT setting because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ pu4PtaCtrl = (PUINT_32) pvSetBuffer; ++ u4PtaCtrl = *pu4PtaCtrl; ++ ++ if (u4PtaCtrl == 0) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 0\r\n")); */ ++ nicPtaSetFunc(prAdapter, FALSE); ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 1\r\n")); */ ++ nicPtaSetFunc(prAdapter, TRUE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++#endif ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Tx power profile. ++* ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ /* P_SET_TXPWR_CTRL_T pTxPwr = (P_SET_TXPWR_CTRL_T)pvSetBuffer; */ ++ /* UINT_32 i; */ ++ WLAN_STATUS rStatus; ++ ++ DEBUGFUNC("wlanoidSetTxPower"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ++#if 0 ++ DBGLOG(OID, INFO, "c2GLegacyStaPwrOffset=%d\n", pTxPwr->c2GLegacyStaPwrOffset); ++ DBGLOG(OID, INFO, "c2GHotspotPwrOffset=%d\n", pTxPwr->c2GHotspotPwrOffset); ++ DBGLOG(OID, INFO, "c2GP2pPwrOffset=%d\n", pTxPwr->c2GP2pPwrOffset); ++ DBGLOG(OID, INFO, "c2GBowPwrOffset=%d\n", pTxPwr->c2GBowPwrOffset); ++ DBGLOG(OID, INFO, "c5GLegacyStaPwrOffset=%d\n", pTxPwr->c5GLegacyStaPwrOffset); ++ DBGLOG(OID, INFO, "c5GHotspotPwrOffset=%d\n", pTxPwr->c5GHotspotPwrOffset); ++ DBGLOG(OID, INFO, "c5GP2pPwrOffset=%d\n", pTxPwr->c5GP2pPwrOffset); ++ DBGLOG(OID, INFO, "c5GBowPwrOffset=%d\n", pTxPwr->c5GBowPwrOffset); ++ DBGLOG(OID, INFO, "ucConcurrencePolicy=%d\n", pTxPwr->ucConcurrencePolicy); ++ ++ for (i = 0; i < 14; i++) ++ DBGLOG(OID, INFO, "acTxPwrLimit2G[%d]=%d\n", i, pTxPwr->acTxPwrLimit2G[i]); ++ ++ for (i = 0; i < 4; i++) ++ DBGLOG(OID, INFO, "acTxPwrLimit5G[%d]=%d\n", i, pTxPwr->acTxPwrLimit5G[i]); ++#endif ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_TXPWR_CTRL, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ TRUE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ u4SetBufferLen, /* u4SetQueryInfoLen */ ++ (PUINT_8) pvSetBuffer, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ return rStatus; ++ ++} ++ ++WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) ++{ ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ P_CMD_DUMP_MEM prCmdDumpMem; ++ CMD_DUMP_MEM rCmdDumpMem; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4MemSize = PARAM_MEM_DUMP_MAX_SIZE; ++ ++ UINT_32 u4RemainLeng = 0; ++ UINT_32 u4CurAddr = 0; ++ UINT_8 ucFragNum = 0; ++ ++ prCmdDumpMem = &rCmdDumpMem; ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; ++ ++ u4RemainLeng = prMemDumpInfo->u4RemainLength; ++ u4CurAddr = prMemDumpInfo->u4Address + prMemDumpInfo->u4Length; ++ ucFragNum = prMemDumpInfo->ucFragNum + 1; ++ ++ /* Query. If request length is larger than max length, do it as ping pong. ++ * Send a command and wait for a event. Send next command while the event is received. ++ * ++ */ ++ do { ++ UINT_32 u4CurLeng = 0; ++ ++ if (u4RemainLeng > u4MemSize) { ++ u4CurLeng = u4MemSize; ++ u4RemainLeng -= u4MemSize; ++ } else { ++ u4CurLeng = u4RemainLeng; ++ u4RemainLeng = 0; ++ } ++ ++ prCmdDumpMem->u4Address = u4CurAddr; ++ prCmdDumpMem->u4Length = u4CurLeng; ++ prCmdDumpMem->u4RemainLength = u4RemainLeng; ++ prCmdDumpMem->ucFragNum = ucFragNum; ++ ++ DBGLOG(OID, TRACE, "[%d] 0x%X, len %u, remain len %u\n", ++ ucFragNum, ++ prCmdDumpMem->u4Address, prCmdDumpMem->u4Length, prCmdDumpMem->u4RemainLength); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_DUMP_MEM, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMemDump, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_DUMP_MEM), ++ (PUINT_8) prCmdDumpMem, pvQueryBuffer, u4QueryBufferLen); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump memory. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ ++ DEBUGFUNC("wlanoidQueryMemDump"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; ++ DBGLOG(OID, TRACE, "Dump 0x%X, len %u\n", prMemDumpInfo->u4Address, prMemDumpInfo->u4Length); ++ ++ prMemDumpInfo->u4RemainLength = prMemDumpInfo->u4Length; ++ prMemDumpInfo->u4Length = 0; ++ prMemDumpInfo->ucFragNum = 0; ++ ++ return wlanSendMemDumpCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* end of wlanoidQueryMcrRead() */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the p2p mode. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_PARAM_CUSTOM_P2P_SET_STRUCT_T prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) NULL; ++ /* P_MSG_P2P_NETDEV_REGISTER_T prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T)NULL; */ ++ DEBUGFUNC("wlanoidSetP2pMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T); ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) pvSetBuffer; ++ ++ DBGLOG(P2P, INFO, "Set P2P enable %p [%u] mode[%u]\n", prSetP2P, prSetP2P->u4Enable, prSetP2P->u4Mode); ++ ++ /* ++ * enable = 1, mode = 0 => init P2P network ++ * enable = 1, mode = 1 => init Soft AP network ++ * enable = 0 => uninit P2P/AP network ++ */ ++ ++ if (prSetP2P->u4Enable) { ++ p2pSetMode((prSetP2P->u4Mode == 1) ? TRUE : FALSE); ++ ++ if (p2pLaunch(prAdapter->prGlueInfo)) ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ } else { ++ DBGLOG(P2P, TRACE, "prAdapter->fgIsP2PRegistered = %d\n", prAdapter->fgIsP2PRegistered); ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ DBGLOG(P2P, INFO, "p2pRemove\n"); ++ p2pRemove(prAdapter->prGlueInfo); ++ } ++ ++ } ++ ++#if 0 ++ prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_NETDEV_REGISTER_T))); ++ ++ if (prP2pNetdevRegMsg == NULL) { ++ ASSERT(FALSE); ++ status = WLAN_STATUS_RESOURCES; ++ return status; ++ } ++ ++ prP2pNetdevRegMsg->rMsgHdr.eMsgId = MID_MNY_P2P_NET_DEV_REGISTER; ++ prP2pNetdevRegMsg->fgIsEnable = (prSetP2P->u4Enable == 1) ? TRUE : FALSE; ++ prP2pNetdevRegMsg->ucMode = (UINT_8) prSetP2P->u4Mode; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pNetdevRegMsg, MSG_SEND_METHOD_BUF); ++#endif ++ ++ return status; ++} ++#endif ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query build date code information from firmware ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_GET_BUILD_DATE_CODE rCmdGetBuildDateCode; ++ ++ DEBUGFUNC("wlanoidQueryBuildDateCode"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_8) * 16; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8) * 16) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BUILD_DATE_CODE, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventBuildDateCode, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_BUILD_DATE_CODE), ++ (PUINT_8) &rCmdGetBuildDateCode, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* end of wlanoidQueryBuildDateCode() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query BSS info from firmware ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ EVENT_AIS_BSS_INFO_T rCmdBSSInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); ++ ++ if (u4QueryBufferLen < sizeof(EVENT_AIS_BSS_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ kalMemZero(&rCmdBSSInfo, sizeof(EVENT_AIS_BSS_INFO_T)); ++ /* ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BSS_INFO, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventGetBSSInfo, ++ nicOidCmdTimeoutCommon, ++ sizeof(P_EVENT_AIS_BSS_INFO_T), ++ (PUINT_8) &rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); ++ */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BSS_INFO, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventGetBSSInfo, ++ nicOidCmdTimeoutCommon, ++ sizeof(EVENT_AIS_BSS_INFO_T), ++ (PUINT_8) & rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} /* wlanoidSetWiFiWmmPsTest */ ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++#define CMD_WLS_BATCHING "WLS_BATCHING" ++ ++#define BATCHING_SET "SET" ++#define BATCHING_GET "GET" ++#define BATCHING_STOP "STOP" ++ ++#define PARAM_SCANFREQ "SCANFREQ" ++#define PARAM_MSCAN "MSCAN" ++#define PARAM_BESTN "BESTN" ++#define PARAM_CHANNEL "CHANNEL" ++#define PARAM_RTT "RTT" ++ ++WLAN_STATUS ++batchSetCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4WritenLen) ++{ ++ P_CHANNEL_INFO_T prRfChannelInfo; ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ PCHAR head, p, p2; ++ UINT_32 tokens; ++ INT_32 scanfreq, mscan, bestn, rtt; ++ ++ DBGLOG(SCN, TRACE, "[BATCH] command=%s, len=%u\n", (PCHAR) pvSetBuffer, (UINT_32) u4SetBufferLen); ++ ++ if (!pu4WritenLen) ++ return -EINVAL; ++ *pu4WritenLen = 0; ++ ++ if (u4SetBufferLen < kalStrLen(CMD_WLS_BATCHING)) { ++ DBGLOG(SCN, TRACE, "[BATCH] invalid len %u\n", (UINT_32) u4SetBufferLen); ++ return -EINVAL; ++ } ++ ++ head = pvSetBuffer + kalStrLen(CMD_WLS_BATCHING) + 1; ++ kalMemSet(&rCmdBatchReq, 0, sizeof(CMD_BATCH_REQ_T)); ++ ++ if (!kalStrnCmp(head, BATCHING_SET, kalStrLen(BATCHING_SET))) { ++ ++ DBGLOG(SCN, TRACE, "XXX Start Batch Scan XXX\n"); ++ ++ head += kalStrLen(BATCHING_SET) + 1; ++ ++ /* SCANFREQ, MSCAN, BESTN */ ++ tokens = kalSScanf(head, "SCANFREQ=%d MSCAN=%d BESTN=%d", &scanfreq, &mscan, &bestn); ++ if (tokens != 3) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, SCANFREQ=%d MSCAN=%d BESTN=%d\n", ++ (UINT_32) tokens, scanfreq, mscan, bestn); ++ return -EINVAL; ++ } ++ /* RTT */ ++ p = kalStrStr(head, PARAM_RTT); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse RTT fail. head=%s\n", head); ++ return -EINVAL; ++ } ++ tokens = kalSScanf(p, "RTT=%d", &rtt); ++ if (tokens != 1) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, rtt=%d\n", (UINT_32) tokens, rtt); ++ return -EINVAL; ++ } ++ /* CHANNEL */ ++ p = kalStrStr(head, PARAM_CHANNEL); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(1)\n"); ++ return -EINVAL; ++ } ++ head = p; ++ p = kalStrChr(head, '>'); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(2)\n"); ++ return -EINVAL; ++ } ++ /* else { ++ *p = '.'; // remove '>' because sscanf can not parse <%s> ++ }*/ ++ /*tokens = kalSScanf(head, "CHANNEL=<%s", c_channel); ++ if (tokens != 1) { ++ DBGLOG(SCN, TRACE, ("[BATCH] Parse fail: tokens=%d, CHANNEL=<%s>\n", ++ tokens, c_channel)); ++ return -EINVAL; ++ } */ ++ rCmdBatchReq.ucChannelType = SCAN_CHANNEL_SPECIFIED; ++ rCmdBatchReq.ucChannelListNum = 0; ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ p = head + kalStrLen(PARAM_CHANNEL) + 2; /* c_channel; */ ++ while ((p2 = kalStrSep((char **)&p, ",")) != NULL) { ++ if (p2 == NULL || *p2 == 0) ++ break; ++ if (*p2 == '\0') ++ continue; ++ if (*p2 == 'A') { ++ rCmdBatchReq.ucChannelType = ++ rCmdBatchReq.ucChannelType == ++ SCAN_CHANNEL_2G4 ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_5G; ++ } else if (*p2 == 'B') { ++ rCmdBatchReq.ucChannelType = ++ rCmdBatchReq.ucChannelType == ++ SCAN_CHANNEL_5G ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_2G4; ++ } else { ++ ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo->ucChannelNum = kalStrtol(p2, NULL, 0); ++ DBGLOG(SCN, TRACE, "Scanning Channel:%u, freq: %d\n", ++ (UINT_32) prRfChannelInfo->ucChannelNum, ++ (UINT_32) nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); ++ prRfChannelInfo->ucBand = prRfChannelInfo->ucChannelNum < 15 ? BAND_2G4 : BAND_5G; ++ ++ rCmdBatchReq.ucChannelListNum++; ++ if (rCmdBatchReq.ucChannelListNum >= 32) ++ break; ++ prRfChannelInfo++; ++ } ++ } ++ ++ /* set channel for test */ ++#if 0 ++ rCmdBatchReq.ucChannelType = 4; /* SCAN_CHANNEL_SPECIFIED; */ ++ rCmdBatchReq.ucChannelListNum = 0; ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ for (i = 1; i <= 14; i++) { ++ ++ /* filter out some */ ++ if (i == 1 || i == 5 || i == 11) ++ continue; ++ ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo->ucChannelNum = i; ++ DBGLOG(SCN, TRACE, "Scanning Channel:%d, freq: %d\n", ++ prRfChannelInfo->ucChannelNum, ++ nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); ++ prRfChannelInfo->ucBand = BAND_2G4; ++ ++ rCmdBatchReq.ucChannelListNum++; ++ prRfChannelInfo++; ++ } ++#endif ++#if 0 ++ rCmdBatchReq.ucChannelType = 0; /* SCAN_CHANNEL_FULL; */ ++#endif ++ ++ rCmdBatchReq.u4Scanfreq = scanfreq; ++ rCmdBatchReq.ucMScan = mscan > CFG_BATCH_MAX_MSCAN ? CFG_BATCH_MAX_MSCAN : mscan; ++ rCmdBatchReq.ucBestn = bestn; ++ rCmdBatchReq.ucRtt = rtt; ++ DBGLOG(SCN, TRACE, "[BATCH] SCANFREQ=%u MSCAN=%u BESTN=%u RTT=%u\n", ++ (UINT_32) rCmdBatchReq.u4Scanfreq, ++ (UINT_32) rCmdBatchReq.ucMScan, ++ (UINT_32) rCmdBatchReq.ucBestn, (UINT_32) rCmdBatchReq.ucRtt; ++ ++ if (rCmdBatchReq.ucChannelType != SCAN_CHANNEL_SPECIFIED) { ++ DBGLOG(SCN, TRACE, "[BATCH] CHANNELS = %s\n", ++ rCmdBatchReq.ucChannelType == SCAN_CHANNEL_FULL ? "FULL" : ++ rCmdBatchReq.ucChannelType == SCAN_CHANNEL_2G4 ? "2.4G all" : "5G all"); ++ } else { ++ DBGLOG(SCN, TRACE, "[BATCH] CHANNEL list\n"); ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ for (tokens = 0; tokens < rCmdBatchReq.ucChannelListNum; tokens++) { ++ DBGLOG(SCN, TRACE, "[BATCH] %s, %d\n", ++ prRfChannelInfo->ucBand == BAND_2G4 ? "2.4G" : "5G", ++ prRfChannelInfo->ucChannelNum); ++ prRfChannelInfo++; ++ } ++ } ++ ++ rCmdBatchReq.ucSeqNum = 1; ++ rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_START; ++ ++ *pu4WritenLen = kalSnprintf(pvSetBuffer, 3, "%d", rCmdBatchReq.ucMScan); ++ ++ } else if (!kalStrnCmp(head, BATCHING_STOP, kalStrLen(BATCHING_STOP))) { ++ ++ DBGLOG(SCN, TRACE, "XXX Stop Batch Scan XXX\n"); ++ ++ rCmdBatchReq.ucSeqNum = 1; ++ rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_STOP; ++ } else { ++ return -EINVAL; ++ } ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BATCH_REQ, ++ TRUE, FALSE, TRUE, NULL, NULL, sizeof(CMD_BATCH_REQ_T), (PUINT_8) &rCmdBatchReq, NULL, 0); ++ ++ /* kalMemSet(pvSetBuffer, 0, u4SetBufferLen); */ ++ /* rStatus = kalSnprintf(pvSetBuffer, 2, "%s", "OK"); */ ++ ++ return rStatus; ++} ++ ++WLAN_STATUS ++batchGetCmd(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_EVENT_BATCH_RESULT_T prEventBatchResult; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pvQueryBuffer; ++ ++ DBGLOG(SCN, TRACE, "XXX Get Batch Scan Result (%u) XXX\n", (UINT_32) prEventBatchResult->ucScanCount); ++ ++ *pu4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); ++ ++ rCmdBatchReq.ucSeqNum = 2; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_RESULT; ++ rCmdBatchReq.ucMScan = prEventBatchResult->ucScanCount; /* Get which round result */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BATCH_REQ, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventBatchScanResult, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BATCH_REQ_T), ++ (PUINT_8) &rCmdBatchReq, (PVOID) pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ return batchSetCmd(prAdapter, pvSetBuffer, u4SetBufferLen, pu4SetInfoLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ return batchGetCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen, pu4QueryInfoLen); ++ ++} /* end of wlanoidQueryBatchScanResult() */ ++ ++#endif /* CFG_SUPPORT_BATCH_SCAN */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request starting of schedule scan ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; ++ ++ DEBUGFUNC("wlanoidSetStartSchedScan()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set scheduled scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen != sizeof(PARAM_SCHED_SCAN_REQUEST)) { ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ return WLAN_STATUS_INVALID_DATA; ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED && ++ prAdapter->fgEnOnlineScan == FALSE) { ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) pvSetBuffer; ++ ++ if (scnFsmSchedScanRequest(prAdapter, ++ (UINT_8) (prSchedScanRequest->u4SsidNum), ++ prSchedScanRequest->arSsid, ++ prSchedScanRequest->u4IELength, ++ prSchedScanRequest->pucIE, prSchedScanRequest->u2ScanInterval) == TRUE) { ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request termination of schedule scan ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ /* ask SCN module to stop scan request */ ++ if (scnFsmSchedScanStopRequest(prAdapter) == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a periodically scan action ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_CMD_SET_PSCAN_ENABLE prCmdPscnAction; ++ P_SCAN_INFO_T prScanInfo; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ DBGLOG(SCN, TRACE, "wlanoidSetGSCNAction\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4SetBufferLen != sizeof(CMD_SET_PSCAN_ENABLE)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ else if (pvSetBuffer == NULL) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prCmdPscnAction = (P_CMD_SET_PSCAN_ENABLE) pvSetBuffer; ++ ++ if (prCmdPscnAction->ucPscanAct == ENABLE) { ++#if 0 ++ DBGLOG(OID, INFO, "set PCSN ENABLE\n"); ++ if (scnFsmPSCNAction(prAdapter, (UINT_8) (prCmdPscnAction->ucPscanAct)) == TRUE) { ++ ++ DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); ++ return WLAN_STATUS_PENDING; ++ } ++ DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); ++ return WLAN_STATUS_FAILURE; ++ ++#endif ++ scnPSCNFsm(prAdapter, PSCN_SCANNING, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, TRUE); ++ } else if (prCmdPscnAction->ucPscanAct == DISABLE) { ++#if 0 ++ DBGLOG(OID, INFO, "disable PCSN\n"); ++ scnFsmPSCNAction(prAdapter, (UINT_8) DISABLE); ++ ++ DBGLOG(OID, TRACE, "set new PCSN\n"); ++ scnCombineParamsIntoPSCN(prAdapter, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE); ++ ++ DBGLOG(OID, INFO, "ENABLE or disable PCSN\n"); ++ if (!prScanInfo->fgPscnOnnning) { ++ DBGLOG(OID, INFO, "ENABLE PCSN\n"); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ } else { ++ DBGLOG(OID, INFO, "All PCSN is disabled...\n"); ++ } ++#endif ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE, FALSE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a periodically scan action ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam; ++ /*UINT_8 i, j = 0;*/ ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam v1\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(P_PARAM_WIFI_GSCAN_CMD_PARAMS))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prCmdGscnParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; ++ /* KC-XXX memcpy(prCmdGscnParam, */ ++ /* (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer, */ ++ /* sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS) ); */ ++ DBGLOG(SCN, INFO, ++ "prCmdGscnParam : base_period[%u], max_ap_per_scan[%u] num_buckets[%u], report_threshold[%u]\n", ++ prCmdGscnParam->base_period, prCmdGscnParam->max_ap_per_scan, prCmdGscnParam->num_buckets, ++ prCmdGscnParam->report_threshold); ++#if 0 ++ for (i = 0; i < prCmdGscnParam->num_buckets; i++) { ++ ++ DBGLOG(OID, INFO, ++ "prCmdGscnParam->buckets : band[%u], bucket[%u] num_buckets[%u], period[%u] report_events[%u]\n", ++ prCmdGscnParam->buckets[i].band, prCmdGscnParam->buckets[i].bucket, ++ prCmdGscnParam->buckets[i].num_channels, prCmdGscnParam->buckets[i].period, ++ prCmdGscnParam->buckets[i].report_events)); ++ DBGLOG(OID, INFO, "prCmdGscnParam->buckets[%d] has channel: ", i); ++ for (j = 0; j < prCmdGscnParam->buckets[i].num_channels; j++) ++ DBGLOG(OID, INFO, " %d, ", prCmdGscnParam->buckets[i].channels[j].channel); ++ DBGLOG(OID, INFO, "\n"); ++ } ++#endif ++ if (scnSetGSCNParam(prAdapter, prCmdGscnParam) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set configure gscan PARAMs ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnScnConfigParam; ++ CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; ++ ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAConfig v1\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer\n"); ++ prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; ++ memcpy(prCmdGscnScnConfigParam, (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer, ++ sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam assign prCmdGscnScnConfig\n"); ++ rCmdGscnScnConfig.u4BufferThreshold = prCmdGscnScnConfigParam->report_threshold; ++ rCmdGscnScnConfig.ucNumApPerScn = prCmdGscnScnConfigParam->max_ap_per_scan; ++ rCmdGscnScnConfig.u4NumScnToCache = prCmdGscnScnConfigParam->num_scans; ++ DBGLOG(SCN, INFO, " report_threshold %d report_threshold %d num_scans %d\n", ++ rCmdGscnScnConfig.u4BufferThreshold, ++ rCmdGscnScnConfig.ucNumApPerScn, rCmdGscnScnConfig.u4NumScnToCache); ++ if (scnFsmSetGSCNConfig(prAdapter, &rCmdGscnScnConfig) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get a gscan result ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS prGetGscnScnResultParm; ++ CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; ++ ++ DEBUGFUNC("wlanoidGetGSCNResult()"); ++ DBGLOG(SCN, INFO, "wlanoidGetGSCNResult v1\n"); ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prGetGscnScnResultParm = (P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) pvSetBuffer; ++ /* memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultParm, sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) ); */ ++ ++ rGetGscnScnResultCmd.u4Num = prGetGscnScnResultParm->get_num; ++ rGetGscnScnResultCmd.ucFlush = prGetGscnScnResultParm->flush; ++ rGetGscnScnResultCmd.ucVersion = PSCAN_VERSION; ++ kalMemZero(rGetGscnScnResultCmd.aucReserved, sizeof(rGetGscnScnResultCmd.aucReserved)); ++ ++ if (scnFsmGetGSCNResult(prAdapter, &rGetGscnScnResultCmd) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidGetGSCNResult --->scnFsmGetGSCNResult\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++ ++} ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by HS2.0 to set the assoc info, which is needed to add to ++* Association request frame while join HS2.0 AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_IE_HS20_INDICATION_T prHS20IndicationIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetHS20AssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pvSetBuffer; ++ ++ prAdapter->prGlueInfo->ucHotspotConfig = prHS20IndicationIe->ucHotspotConfig; ++ prAdapter->prGlueInfo->fgConnectHS20AP = TRUE; ++ ++ DBGLOG(SEC, TRACE, "HS20 IE sz %u\n", u4SetBufferLen); ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucHS20AssocInfoIE, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2HS20AssocInfoIELen = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "HS20 Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the assoc info, which is needed to add to ++* Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if 0 ++ P_HS20_INFO_T prHS20Info = NULL; ++ P_IE_INTERWORKING_T prInterWorkingIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ DEBUGFUNC("wlanoidSetInterworkingInfo"); ++ DBGLOG(OID, TRACE, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ prInterWorkingIe = (P_IE_INTERWORKING_T) pvSetBuffer; ++ ++ prHS20Info->ucAccessNetworkOptions = prInterWorkingIe->ucAccNetOpt; ++ prHS20Info->ucVenueGroup = prInterWorkingIe->ucVenueGroup; ++ prHS20Info->ucVenueType = prInterWorkingIe->ucVenueType; ++ COPY_MAC_ADDR(prHS20Info->aucHESSID, prInterWorkingIe->aucHESSID); ++ ++ DBGLOG(SEC, TRACE, "IW IE sz %ld\n", u4SetBufferLen); ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the Roaming Consortium IE info, which is needed to ++* add to Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if 0 ++ P_HS20_INFO_T prHS20Info = NULL; ++ P_PARAM_HS20_ROAMING_CONSORTIUM_INFO prRCInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ /* DEBUGFUNC("wlanoidSetRoamingConsortiumInfo"); */ ++ /* DBGLOG(HS2, TRACE, ("\r\n")); */ ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ prRCInfo = (P_PARAM_HS20_ROAMING_CONSORTIUM_INFO) pvSetBuffer; ++ ++ kalMemCopy(&(prHS20Info->rRCInfo), prRCInfo, sizeof(PARAM_HS20_ROAMING_CONSORTIUM_INFO)); ++ ++ /* DBGLOG(HS2, TRACE, ("RoamingConsortium IE sz %ld\n", u4SetBufferLen)); */ ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set_bssid_pool ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_HS20_SET_BSSID_POOL)) { ++ *pu4SetInfoLen = sizeof(PARAM_HS20_SET_BSSID_POOL); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ rWlanStatus = hs20SetBssidPool(prAdapter, pvSetBuffer, NETWORK_TYPE_AIS_INDEX); ++ ++ return rWlanStatus; ++} /* end of wlanoidSendHS20GASRequest() */ ++ ++#endif ++ ++#if CFG_SUPPORT_ROAMING_ENC ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_ROAMING_INFO_T *prCmdRoamingInfo; ++ ++ DEBUGFUNC("wlanoidSetRoamingInfo"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_ROAMING_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_ROAMING_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdRoamingInfo = (CMD_ROAMING_INFO_T *) pvSetBuffer; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_ROAMING_INFO, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ROAMING_INFO_T), (PUINT_8) prCmdRoamingInfo, NULL, 0); ++} ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set chip ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; ++ CMD_CHIP_CONFIG_T rCmdChipConfig; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(prChipConfigInfo->aucCmd) == CHIP_CONFIG_RESP_SIZE); ++ DEBUGFUNC("wlanoidSetChipConfig"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prChipConfigInfo = (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T) pvSetBuffer; ++ kalMemZero(&rCmdChipConfig, sizeof(rCmdChipConfig)); ++ ++ rCmdChipConfig.u2Id = prChipConfigInfo->u2Id; ++ rCmdChipConfig.ucType = prChipConfigInfo->ucType; ++ rCmdChipConfig.ucRespType = prChipConfigInfo->ucRespType; ++ rCmdChipConfig.u2MsgSize = prChipConfigInfo->u2MsgSize; ++ if (rCmdChipConfig.u2MsgSize > CHIP_CONFIG_RESP_SIZE) { ++ DBGLOG(OID, INFO, "Chip config Msg Size %u is not valid (set)\n", rCmdChipConfig.u2MsgSize); ++ rCmdChipConfig.u2MsgSize = CHIP_CONFIG_RESP_SIZE; ++ } ++ kalMemCopy(rCmdChipConfig.aucCmd, prChipConfigInfo->aucCmd, rCmdChipConfig.u2MsgSize); ++ ++ DBGLOG(OID, TRACE, "rCmdChipConfig.aucCmd=%s\n", rCmdChipConfig.aucCmd); ++#if 1 ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_CHIP_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CHIP_CONFIG_T), ++ (PUINT_8) &rCmdChipConfig, pvSetBuffer, u4SetBufferLen); ++#endif ++ return rWlanStatus; ++} /* wlanoidSetChipConfig */ ++ ++WLAN_STATUS ++wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_CMD_WFD_DEBUG_MODE_INFO_T prCmdWfdDebugModeInfo; ++ ++ DEBUGFUNC("wlanoidSetWFDDebugMode"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_WFD_DEBUG_MODE_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_WFD_DEBUG_MODE_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdWfdDebugModeInfo = (CMD_WFD_DEBUG_MODE_INFO_T *) pvSetBuffer; ++ ++ DBGLOG(OID, INFO, "New WFD Debug: %d mode and period=0x%x\n", prCmdWfdDebugModeInfo->ucDebugMode, ++ prCmdWfdDebugModeInfo->u2PeriodInteval); ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode = (UINT_8) prCmdWfdDebugModeInfo->ucDebugMode; ++ prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.u2WfdSNShowPeiroid = ++ (UINT_16) prCmdWfdDebugModeInfo->u2PeriodInteval; ++ ++ return WLAN_STATUS_SUCCESS; ++} /*wlanoidSetWfdDebugMode */ ++ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxRateInfo( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_RLM_INFO_T *prCmdTxRInfo; ++ ++ DEBUGFUNC("wlanoidSetTxRateInfo"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_RLM_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_RLM_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdTxRInfo = (CMD_RLM_INFO_T *)pvSetBuffer; ++ ++ DBGLOG(OID, INFO, " command = %u %u %u %u %d %u %u\n", ++ prCmdTxRInfo->u4Version, ++ prCmdTxRInfo->fgIsErrRatioEnhanceApplied, ++ prCmdTxRInfo->ucErrRatio2LimitMinRate, ++ prCmdTxRInfo->ucMinLegacyRateIdx, ++ prCmdTxRInfo->cMinRssiThreshold, ++ prCmdTxRInfo->fgIsRtsApplied, ++ prCmdTxRInfo->ucRecoverTime)); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TX_AR_ERR_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_RLM_INFO_T), ++ (PUINT_8)prCmdTxRInfo, ++ NULL, ++ 0 ++ ); ++} ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++WLAN_STATUS ++wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WIFI_SYSTEM_SUSPEND_CMD_T rSuspendCmd; ++ ++ if (!prAdapter || !pvSetBuffer) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ rSuspendCmd.fgIsSystemSuspend = *(PBOOLEAN)pvSetBuffer; ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_SYSTEM_SUSPEND, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(BOOLEAN), ++ (PUINT_8)&rSuspendCmd, ++ NULL, ++ 0); ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c +new file mode 100644 +index 000000000000..7ca7ee48922e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c +@@ -0,0 +1,1654 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/common/wlan_p2p.c#8 ++*/ ++ ++/*! \file wlan_bow.c ++ \brief This file contains the Wi-Fi Direct commands processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_p2p.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 24 2011 yuche.tsai ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support ++ * for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix Multicast Issue of P2P. ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 wh.su ++ * [WCXRP00000571] [MT6620 Wi-Fi] [Driver] Not check the p2p role during set key ++ * Skip the p2p role for adding broadcast key issue. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * fixed compiling error while enable dbg. ++ * ++ * 03 08 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format ++ * issue[WCXRP00000509] [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix SD Request Query Length issue. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Service Discovery Request. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Wlan OID related function. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ioctl implementations for P2P Service Discovery ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ++ * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous ++ * and physically-continuous type to ease slab system pressure ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * . ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * support wlanoidSetP2pPowerSaveProfile() in P2P ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * Support wlanoidSetNetworkAddress() for P2P ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++#include "gl_p2p_ioctl.h" ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ DEBUGFUNC("wlanoidSendSetQueryP2PCmd"); ++ DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(P2P, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_P2P_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a key to Wi-Fi Direct driver ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_802_11_KEY rCmdKey; ++ P_PARAM_KEY_T prNewKey; ++ ++ DEBUGFUNC("wlanoidSetAddP2PKey"); ++ DBGLOG(REQ, INFO, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(REQ, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* Verify the key material length for key material buffer */ ++ else if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(REQ, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ /* Exception check */ ++ else if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) { ++ return WLAN_STATUS_INVALID_DATA; ++ } else if (!(prNewKey->u4KeyLength == CCMP_KEY_LEN) && !(prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyIndex & 0xff) != 0) || ++ ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) ++ && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) ++ && (prNewKey->arBSSID[5] == 0xff))) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* fill CMD_802_11_KEY */ ++ kalMemZero(&rCmdKey, sizeof(CMD_802_11_KEY)); ++ rCmdKey.ucAddRemove = 1; /* add */ ++ rCmdKey.ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; ++ rCmdKey.ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ ++ rCmdKey.ucIsAuthenticator = 0; ++ } else { /* group owner */ ++ rCmdKey.ucIsAuthenticator = 1; ++ } ++ COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prNewKey->arBSSID); ++ rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; ++ if (prNewKey->u4KeyLength == CCMP_KEY_LEN) ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ ++ else if (prNewKey->u4KeyLength == TKIP_KEY_LEN) ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_TKIP; /* TKIP */ ++ rCmdKey.ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); ++ rCmdKey.ucKeyLen = (UINT_8) prNewKey->u4KeyLength; ++ kalMemCopy(rCmdKey.aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, rCmdKey.ucKeyLen); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ NULL, ++ sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request Wi-Fi Direct driver to remove keys ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_802_11_KEY rCmdKey; ++ P_PARAM_REMOVE_KEY_T prRemovedKey; ++ ++ DEBUGFUNC("wlanoidSetRemoveP2PKey"); ++ ASSERT(prAdapter); ++ ++ if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; ++ ++ /* Check bit 31: this bit should always 0 */ ++ if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Check bits 8 ~ 29 should always be 0 */ ++ if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { ++ /* Bit 31 should not be set */ ++ DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* There should not be any key operation for P2P Device */ ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 0) ++ ; /* return WLAN_STATUS_NOT_ACCEPTED; */ ++ ++ kalMemZero((PUINT_8) &rCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ rCmdKey.ucAddRemove = 0; /* remove */ ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ ++ rCmdKey.ucIsAuthenticator = 0; ++ } else { /* group owner */ ++ rCmdKey.ucIsAuthenticator = 1; ++ } ++ kalMemCopy(rCmdKey.aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; ++ rCmdKey.ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ NULL, ++ sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the IP address for pattern search function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ ++ DEBUGFUNC("wlanoidSetP2pNetworkAddress"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++ j++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query the power save profile. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryP2pPowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen != 0) { ++ ASSERT(pvQueryBuffer); ++ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = ++ (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile); ++ *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ PARAM_POWER_MODE ePowerMode; ++ ++ DEBUGFUNC("wlanoidSetP2pPowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); ++ if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { ++ DBGLOG(REQ, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { ++ WARNLOG(("Invalid power mode %d\n", *(PPARAM_POWER_MODE) pvSetBuffer)); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; ++ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ if (ePowerMode == Param_PowerModeCAM) { ++ /*Todo:: Nothing*/ ++ /*Todo:: Nothing*/ ++ } else { ++ /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ ++ ++ if (prAdapter->u4CtiaPowerMode == 0) { ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ } else if (prAdapter->u4CtiaPowerMode == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (prAdapter->u4CtiaPowerMode == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } ++ } ++ } ++ ++ status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_P2P_INDEX, ePowerMode, TRUE); ++ return status; ++} /* end of wlanoidSetP2pPowerSaveProfile() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; ++ ++ DEBUGFUNC("wlanoidSetP2pSetNetworkAddress"); ++ DBGLOG(P2P, TRACE, "\n"); ++ DBGLOG(P2P, INFO, "wlanoidSetP2pSetNetworkAddress (%d)\n", (INT_16) u4SetBufferLen); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ ++ if (u4IpAddressCount == 0) ++ u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ ++ /* only to set IP address to FW once ARP filter is enabled */ ++ if (prAdapter->fgEnArpFilter) { ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ ++ DBGLOG(P2P, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++ j++; ++ ++ pucBuf = (PUINT_8) &prNetAddrIp->in_addr; ++ DBGLOG(P2P, INFO, "prNetAddrIp->in_addr:%d:%d:%d:%d\n", ++ (UINT_8) pucBuf[0], (UINT_8) pucBuf[1], ++ (UINT_8) pucBuf[2], (UINT_8) pucBuf[3]); ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ } ++ ++ } else { ++ prCmdNetworkAddressList->ucAddressCount = 0; ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} /* end of wlanoidSetP2pSetNetworkAddress() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* The data must be a multiple of the Ethernet address size. */ ++ if ((u4SetBufferLen % MAC_ADDR_LEN)) { ++ DBGLOG(REQ, WARN, "Invalid MC list length %u\n", u4SetBufferLen); ++ ++ *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Verify if we can support so many multicast addresses. */ ++ if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { ++ DBGLOG(REQ, WARN, "Too many MC addresses\n"); ++ ++ return WLAN_STATUS_MULTICAST_FULL; ++ } ++ ++ /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && ++ * pvSetBuffer == NULL to clear exist Multicast List. ++ */ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(REQ, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; ++ rCmdMacMcastAddr.ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); ++ ++ /* This CMD response is no need to complete the OID. Or the event would unsync. */ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, CMD_ID_MAC_MCAST_ADDR, TRUE, FALSE, FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_MAC_MCAST_ADDR), ++ (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetP2PMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send GAS frame for P2P Service Discovery Request ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_REQUEST)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_REQUEST); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++/* rWlanStatus = p2pFsmRunEventSDRequest(prAdapter, (P_PARAM_P2P_SEND_SD_REQUEST)pvSetBuffer); */ ++ ++ return rWlanStatus; ++} /* end of wlanoidSendP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send GAS frame for P2P Service Discovery Response ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_RESPONSE)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_RESPONSE); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++/* rWlanStatus = p2pFsmRunEventSDResponse(prAdapter, (P_PARAM_P2P_SEND_SD_RESPONSE)pvSetBuffer); */ ++ ++ return rWlanStatus; ++} /* end of wlanoidGetP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get GAS frame for P2P Service Discovery Request ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /*PUINT_8 pucPacketBuffer = NULL, pucTA = NULL;*/ ++/* PUINT_8 pucChannelNum = NULL; */ ++ /*PUINT_16 pu2PacketLength = NULL;*/ ++ /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ ++ /*UINT_8 ucVersionNum = 0;*/ ++/* UINT_8 ucChannelNum = 0, ucSeqNum = 0; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_REQUEST)) { ++ *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_REQUEST); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ DBGLOG(P2P, TRACE, "Get Service Discovery Request\n"); ++#if 0 ++ ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); ++ if (ucVersionNum == 0) { ++ P_PARAM_P2P_GET_SD_REQUEST prP2pGetSdReq = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ ++ pucPacketBuffer = prP2pGetSdReq->aucPacketContent; ++ pu2PacketLength = &prP2pGetSdReq->u2PacketLength; ++ pucTA = &prP2pGetSdReq->rTransmitterAddr; ++ } else { ++ P_PARAM_P2P_GET_SD_REQUEST_EX prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST_EX) NULL; ++ ++ prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ pucPacketBuffer = prP2pGetSdReqEx->aucPacketContent; ++ pu2PacketLength = &prP2pGetSdReqEx->u2PacketLength; ++ pucTA = &prP2pGetSdReqEx->rTransmitterAddr; ++ pucChannelNum = &prP2pGetSdReqEx->ucChannelNum; ++ ucSeqNum = prP2pGetSdReqEx->ucSeqNum; ++ } ++ ++ rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, ++ pucPacketBuffer, ++ (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_REQUEST)), ++ (PUINT_32) pu2PacketLength, pucChannelNum, ucSeqNum); ++#else ++ *pu4QueryInfoLen = 0; ++ return rWlanStatus; ++#endif ++ /* ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketBuffer; ++ ++ kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); ++ ++ if (pu4QueryInfoLen) { ++ if (ucVersionNum == 0) ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST) + (*pu2PacketLength)); ++ else ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST_EX) + (*pu2PacketLength)); ++ ++ } ++ ++ return rWlanStatus; ++ */ ++} /* end of wlanoidGetP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get GAS frame for P2P Service Discovery Response ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ ++ /* UINT_8 ucSeqNum = 0, */ ++ /*UINT_8 ucVersionNum = 0;*/ ++ /*PUINT_8 pucPacketContent = (PUINT_8) NULL, pucTA = (PUINT_8) NULL;*/ ++ /*PUINT_16 pu2PacketLength = (PUINT_16) NULL;*/ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_RESPONSE)) { ++ *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_RESPONSE); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ DBGLOG(P2P, TRACE, "Get Service Discovery Response\n"); ++ ++#if 0 ++ ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); ++ if (ucVersionNum == 0) { ++ P_PARAM_P2P_GET_SD_RESPONSE prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_RESPONSE) NULL; ++ ++ prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ pucPacketContent = prP2pGetSdRsp->aucPacketContent; ++ pucTA = &prP2pGetSdRsp->rTransmitterAddr; ++ pu2PacketLength = &prP2pGetSdRsp->u2PacketLength; ++ } else { ++ P_PARAM_P2P_GET_SD_RESPONSE_EX prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) NULL; ++ ++ prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) pvQueryBuffer; ++ pucPacketContent = prP2pGetSdRspEx->aucPacketContent; ++ pucTA = &prP2pGetSdRspEx->rTransmitterAddr; ++ pu2PacketLength = &prP2pGetSdRspEx->u2PacketLength; ++ ucSeqNum = prP2pGetSdRspEx->ucSeqNum; ++ } ++ ++/* rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, */ ++/* pucPacketContent, */ ++/* (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_RESPONSE)), */ ++/* (PUINT_32)pu2PacketLength, */ ++/* NULL, */ ++/* ucSeqNum); */ ++#else ++ *pu4QueryInfoLen = 0; ++ return rWlanStatus; ++#endif ++ /* ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketContent; ++ ++ kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); ++ ++ if (pu4QueryInfoLen) { ++ if (ucVersionNum == 0) ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE) + *pu2PacketLength); ++ else ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE_EX) + *pu2PacketLength); ++ } ++ ++ return rWlanStatus; ++ */ ++} /* end of wlanoidGetP2PSDResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to terminate P2P Service Discovery Phase ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_P2P_TERMINATE_SD_PHASE prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) NULL; ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ ++ do { ++ if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) ++ break; ++ ++ if ((u4SetBufferLen) && (pvSetBuffer == NULL)) ++ break; ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_TERMINATE_SD_PHASE)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_TERMINATE_SD_PHASE); ++ rWlanStatus = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) pvSetBuffer; ++ ++ if (EQUAL_MAC_ADDR(prP2pTerminateSD->rPeerAddr, aucNullAddr)) { ++ DBGLOG(P2P, TRACE, "Service Discovery Version 2.0\n"); ++/* p2pFuncSetVersionNumOfSD(prAdapter, 2); */ ++ } ++ /* rWlanStatus = p2pFsmRunEventSDAbort(prAdapter); */ ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* end of wlanoidSetP2PTerminateSDPhase() */ ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SEC_CHECK, ++ FALSE, ++ TRUE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ u4SetBufferLen, (PUINT_8) pvSetBuffer, pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetSecCheckRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /* P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; */ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen > 256) ++ u4QueryBufferLen = 256; ++ ++ *pu4QueryInfoLen = u4QueryBufferLen; ++ ++#if DBG ++ DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); ++#endif ++ kalMemCopy((PUINT_8) (pvQueryBuffer + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer)), ++ prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); ++ ++ return rWlanStatus; ++} /* end of wlanoidGetSecCheckResponse() */ ++#endif ++ ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; ++ CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; ++ ++ DEBUGFUNC("wlanoidSetNoaParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); ++ rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; ++ rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; ++ rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++ ++} ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; ++ CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; ++ ++ DEBUGFUNC("wlanoidSetOppPsParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_OPPPS_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++ ++} ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; ++ CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetUApsdParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; ++ prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; ++ ++ rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; ++ rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; ++ rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; ++ rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; ++ prPmProfSetupInfo->ucBmpDeliveryAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ prPmProfSetupInfo->ucBmpTriggerAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ ++ rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; ++ prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++} ++ ++WLAN_STATUS ++wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++/* PUINT_8 pucOpChnl = (PUINT_8)pvQueryBuffer; */ ++ ++ do { ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8)) { ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++#if 0 ++ if (!p2pFuncGetCurrentOpChnl(prAdapter, pucOpChnl)) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++#else ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++#endif ++ /* ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_SUCCESS; ++ */ ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pOpChannel */ ++ ++WLAN_STATUS ++wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++/* PUINT_8 pucVersionNum = (PUINT_8)pvQueryBuffer; */ ++ ++ do { ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8)) { ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++ ++WLAN_STATUS ++wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ UINT_8 ucVersionNum; ++ ++ do { ++ if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { ++ ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ *pu4SetInfoLen = sizeof(UINT_8); ++ ++ if (u4SetBufferLen < sizeof(UINT_8)) { ++ rResult = WLAN_STATUS_INVALID_LENGTH; ++ break; ++ } ++ ++ ucVersionNum = *((PUINT_8) pvSetBuffer); ++ ++ rResult = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidSetP2pSupplicantVersion */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the WPS mode. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ UINT_32 u4IsWPSmode = 0; ++ ++ DEBUGFUNC("wlanoidSetP2pWPSmode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (pvSetBuffer) ++ u4IsWPSmode = *(PUINT_32) pvSetBuffer; ++ else ++ u4IsWPSmode = 0; ++ ++ if (u4IsWPSmode) ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 1; ++ else ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 0; ++ ++ status = nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ return status; ++} /* end of wlanoidSetP2pWPSmode() */ ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++WLAN_STATUS ++wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryP2pRssi"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(REQ, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (prAdapter->fgIsP2pLinkQualityValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ PARAM_RSSI rRssi; ++ ++ rRssi = (PARAM_RSSI) prAdapter->rP2pLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ ++ kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); ++ return WLAN_STATUS_SUCCESS; ++ } ++#ifdef LINUX ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, ++ *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++#endif ++} /* wlanoidQueryP2pRssi */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h +new file mode 100644 +index 000000000000..89de18c89c1c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h +@@ -0,0 +1,238 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/CFG_Wifi_File.h#1 ++*/ ++ ++/*! \file CFG_Wifi_File.h ++ \brief Collection of NVRAM structure used for YuSu project ++ ++ In this file we collect all compiler flags and detail the driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++/* ++** Log: CFG_Wifi_File.h ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 09 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * update NVRAM data structure definition. ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition ++ * follow-up for CMD_5G_PWR_OFFSET_T definition change ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++*/ ++ ++#ifndef _CFG_WIFI_FILE_H ++#define _CFG_WIFI_FILE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/* duplicated from nic_cmd_event.h to avoid header dependency */ ++typedef struct _TX_PWR_PARAM_T { ++ INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ ++ INT_8 acReserved[3]; /* form MT6628 acReserved[0]=cTxPwr2G4Dsss */ ++ INT_8 cTxPwr2G4OFDM_BPSK; ++ INT_8 cTxPwr2G4OFDM_QPSK; ++ INT_8 cTxPwr2G4OFDM_16QAM; ++ INT_8 cTxPwr2G4OFDM_Reserved; ++ INT_8 cTxPwr2G4OFDM_48Mbps; ++ INT_8 cTxPwr2G4OFDM_54Mbps; ++ ++ INT_8 cTxPwr2G4HT20_BPSK; ++ INT_8 cTxPwr2G4HT20_QPSK; ++ INT_8 cTxPwr2G4HT20_16QAM; ++ INT_8 cTxPwr2G4HT20_MCS5; ++ INT_8 cTxPwr2G4HT20_MCS6; ++ INT_8 cTxPwr2G4HT20_MCS7; ++ ++ INT_8 cTxPwr2G4HT40_BPSK; ++ INT_8 cTxPwr2G4HT40_QPSK; ++ INT_8 cTxPwr2G4HT40_16QAM; ++ INT_8 cTxPwr2G4HT40_MCS5; ++ INT_8 cTxPwr2G4HT40_MCS6; ++ INT_8 cTxPwr2G4HT40_MCS7; ++ ++ INT_8 cTxPwr5GOFDM_BPSK; ++ INT_8 cTxPwr5GOFDM_QPSK; ++ INT_8 cTxPwr5GOFDM_16QAM; ++ INT_8 cTxPwr5GOFDM_Reserved; ++ INT_8 cTxPwr5GOFDM_48Mbps; ++ INT_8 cTxPwr5GOFDM_54Mbps; ++ ++ INT_8 cTxPwr5GHT20_BPSK; ++ INT_8 cTxPwr5GHT20_QPSK; ++ INT_8 cTxPwr5GHT20_16QAM; ++ INT_8 cTxPwr5GHT20_MCS5; ++ INT_8 cTxPwr5GHT20_MCS6; ++ INT_8 cTxPwr5GHT20_MCS7; ++ ++ INT_8 cTxPwr5GHT40_BPSK; ++ INT_8 cTxPwr5GHT40_QPSK; ++ INT_8 cTxPwr5GHT40_16QAM; ++ INT_8 cTxPwr5GHT40_MCS5; ++ INT_8 cTxPwr5GHT40_MCS6; ++ INT_8 cTxPwr5GHT40_MCS7; ++} TX_PWR_PARAM_T, *P_TX_PWR_PARAM_T; ++ ++typedef struct _PWR_5G_OFFSET_T { ++ INT_8 cOffsetBand0; /* 4.915-4.980G */ ++ INT_8 cOffsetBand1; /* 5.000-5.080G */ ++ INT_8 cOffsetBand2; /* 5.160-5.180G */ ++ INT_8 cOffsetBand3; /* 5.200-5.280G */ ++ INT_8 cOffsetBand4; /* 5.300-5.340G */ ++ INT_8 cOffsetBand5; /* 5.500-5.580G */ ++ INT_8 cOffsetBand6; /* 5.600-5.680G */ ++ INT_8 cOffsetBand7; /* 5.700-5.825G */ ++} PWR_5G_OFFSET_T, *P_PWR_5G_OFFSET_T; ++ ++typedef struct _PWR_PARAM_T { ++ UINT_32 au4Data[28]; ++ UINT_32 u4RefValue1; ++ UINT_32 u4RefValue2; ++} PWR_PARAM_T, *P_PWR_PARAM_T; ++ ++typedef struct _MT6620_CFG_PARAM_STRUCT { ++ /* 256 bytes of MP data */ ++ UINT_16 u2Part1OwnVersion; ++ UINT_16 u2Part1PeerVersion; ++ UINT_8 aucMacAddress[6]; ++ UINT_8 aucCountryCode[2]; ++ TX_PWR_PARAM_T rTxPwr; ++ UINT_8 aucEFUSE[144]; ++ UINT_8 ucTxPwrValid; ++ UINT_8 ucSupport5GBand; ++ UINT_8 fg2G4BandEdgePwrUsed; ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ ++ UINT_8 ucRegChannelListMap; ++ UINT_8 ucRegChannelListIndex; ++ UINT_8 aucRegSubbandInfo[36]; ++ ++ UINT_8 aucReserved2[256 - 240]; ++ ++ /* 256 bytes of function data */ ++ UINT_16 u2Part2OwnVersion; ++ UINT_16 u2Part2PeerVersion; ++ UINT_8 uc2G4BwFixed20M; ++ UINT_8 uc5GBwFixed20M; ++ UINT_8 ucEnable5GBand; ++ UINT_8 aucPreTailReserved; ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 fgRssiCompensationValidbit; ++ UINT_8 ucRxAntennanumber; ++ UINT_8 aucTailReserved[256 - 12]; ++} MT6620_CFG_PARAM_STRUCT, *P_MT6620_CFG_PARAM_STRUCT, WIFI_CFG_PARAM_STRUCT, *P_WIFI_CFG_PARAM_STRUCT; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef DATA_STRUCT_INSPECTING_ASSERT ++#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ ++{ \ ++ switch (0) {case 0: case (expr): default:; } \ ++} ++#endif ++ ++#define CFG_FILE_WIFI_REC_SIZE sizeof(WIFI_CFG_PARAM_STRUCT) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* We don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this to guarantee the same member order in different structures ++ * to simply handling effort in some functions. ++ */ ++static inline VOID nvramOffsetCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion) == 256); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(WIFI_CFG_PARAM_STRUCT) == 512); ++ ++ DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) & 0x0001) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) & 0x0001) == 0); ++} ++#endif ++ ++#endif /* _CFG_WIFI_FILE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h +new file mode 100644 +index 000000000000..a52053d5752d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h +@@ -0,0 +1,1628 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/config.h#2 ++*/ ++ ++/*! \file "config.h" ++ \brief This file includes the various configurable parameters for customers ++ ++ This file ncludes the configurable parameters except the parameters indicate the turning-on/off of some features ++*/ ++ ++/* ++** Log: config.h ++ * ++ * 07 13 2012 cp.wu ++ * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for ++ * termination after SDIO error has happened ++ * [driver domain] add force reset by host-to-device interrupt mechanism ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 06 05 2012 tsaiyuan.hsu ++ * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" ++ * resolve build waring for "WNM_UNIT_TEST not defined".. ++ * ++ * 06 04 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * discussed with WH, privacy bit in associate response is not necessary to be checked, ++ * and identified as association failure when mismatching with beacon/probe response ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 23 2011 cp.wu ++ * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection ++ * add compile option to disable beacon content change detection. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 10 28 2011 cp.wu ++ * [MT6620 Wi-Fi][Win32 Driver] Enable 5GHz support as default ++ * enable 5GHz as default for DaVinci trunk and V2.1 driver release . ++ * ++ * 10 18 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * surpress compiler warning for MT6628 build ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * enable divided firmware downloading. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 28 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * enlarge window size only by 4. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 12 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. ++ * ++ * 08 09 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS definition for MT6620. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Refine compile flag. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 06 24 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * increase RX buffer number to have a 2:1 ping-pong ratio ++ * ++ * 06 23 2011 eddie.chen ++ * [WCXRP00000810] [MT5931][DRV/FW] Adjust TxRx Buffer number and Rx buffer size ++ * 1. Different TX RX buffer ++ * 2. Enlarge RX buffer and increase the number 8->11 ++ * 3. Separate the WINSZIE and RX buffer number ++ * 4. Fix RX maximum size in MAC ++ * ++ * 06 20 2011 terry.wu ++ * NULL ++ * Add BoW Rate Limitation. ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * . ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add compile flag for persistent group support. ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Limit AIS to fixed channel same with BOW ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * Enable RX STBC capability ++ * ++ * 04 11 2011 george.huang ++ * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF ++ * . ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. correction: RX aggregation is not limited to SDIO but for all host interface options ++ * 2. add forward declarations for DBG-only symbols ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port ++ * 2. update perm_addr as well for MAC address ++ * 3. not calling check_mem_region() anymore for eHPI ++ * 4. correct MSC_CS macro for 0-based notation ++ * ++ * 04 01 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface ++ * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR ++ * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with ++ * user space process for RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 18 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the Anti_piracy check at driver . ++ * ++ * 03 17 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * enable roaming feature. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one ++ * to reduce physically continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 03 01 2011 george.huang ++ * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames ++ * Fix compile issue ++ * ++ * 02 25 2011 george.huang ++ * [WCXRP00000497] [MT6620 Wi-Fi][FW] Change default UAPSD AC assignment ++ * Assign all AC default to be U-APSD enabled. ++ * ++ * 02 14 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * Let the privacy check at hotspot mode default enable. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 02 08 2011 cp.wu ++ * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number ++ * change version number to v1.2.0.0 for preparing v1.2 software package release. ++ * ++ * 02 01 2011 yarco.yang ++ * [WCXRP00000417] [MT6620 Driver] Change CFG_HANDLE_IST_IN_SDIO_CALLBACK from 1 to 0 for Interoperability ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 19 2011 wh.su ++ * [WCXRP00000370] [MT6620 Wi-Fi][Driver] Disable Rx RDG for workaround pre-N ccmp issue ++ * Not announce support Rx RDG for wokaround pre-N ccmp construct AAD issue.. ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause ++ * hardware header translation needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW only for Linux. ++ * ++ * 01 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Enable BOW and 4 physical links. ++ * ++ * 01 08 2011 yuche.tsai ++ * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, ++ * but the SSID length is still invalid. ++ * Modify CFG_SLT_SUPPORT default value. ++ * ++ * 01 08 2011 yuche.tsai ++ * [WCXRP00000341] [MT6620][SLT] Create Branch for SLT SW. ++ * Update configure flag. ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 15 2010 yuche.tsai ++ * NULL ++ * Update SLT Descriptor number configure in driver. ++ * ++ * 12 13 2010 chinglan.wang ++ * NULL ++ * Add WPS 1.0 feature flag to enable the WPS 1.0 function. ++ * ++ * 11 23 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Enable PM function by default ++ * ++ * 11 15 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * use config.mk WAPI config define. ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * use the config.mk define. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add option for enable/disable TX PWR gain adjustment (default: off) ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * enable the WAPI compiling flag as default ++ * ++ * 10 19 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * Add a define CFG_TEST_ANDROID_DIRECT_GO compiling flag ++ * ++ * 10 08 2010 cm.chang ++ * NULL ++ * Remove unused compiling flags (TX_RDG and TX_SGI) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 05 2010 yarco.yang ++ * [WCXRP00000082] [MT6620 Wi-Fi][Driver]High throughput performance tuning ++ * Change CFG_IST_LOOP_COUNT from 2 to 1 to reduce unnecessary SDIO bus access ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 20 2010 cm.chang ++ * NULL ++ * Disable RX STBC by BB HEC based on MT6620E1_PHY_BUG v05.docx ++ * ++ * 09 17 2010 chinglan.wang ++ * NULL ++ * Add performance test option ++ * ++ * 09 10 2010 chinglan.wang ++ * NULL ++ * Modify for Software Migration Phase 2.10 for E2 FPGA ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a CFG for max common IE buffer size. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * restore configuration as before. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Enable the MT6620_FPGA_BWCS value. ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Disable the FW encryption. ++ * ++ * 08 27 2010 chinglan.wang ++ * NULL ++ * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add option for enabling AIS 5GHz scan ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Disable BOW Test. ++ * ++ * 08 23 2010 jeffrey.chang ++ * NULL ++ * fix config.h typo ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 21 2010 jeffrey.chang ++ * NULL ++ * 1) add sdio two setting ++ * 2) bug fix of sdio glue ++ * ++ * 08 09 2010 wh.su ++ * NULL ++ * let the firmware download default enabled. ++ * ++ * 08 07 2010 wh.su ++ * NULL ++ * adding the privacy related code for P2P network ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add a configure flag for P2P unitest. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) enable Ad-Hoc ++ * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Add for SLT support. ++ * ++ * 07 16 2010 cp.wu ++ * ++ * remove work-around in case SCN is not available. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor ++ * underflow under concurrent network operation ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * for first connection, if connecting failed do not enter into scan state. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add SCN compilation option. ++ * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * set default compiling flag for security disable. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add config option for cfg80211. ++ * ++ * 05 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * set ATIMwindow default value to zero. ++ * ++ * 05 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add option for FPGA_BWCS & FPGA_V5 ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) enable CMD/EVENT ver 0.9 definition. ++ * 2) abandon use of ENUM_MEDIA_STATE ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change firmware name to WIFI_RAM_CODE. ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * disable bt-over-wifi configuration, turn it on after firmware finished implementation ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * re-enable power management ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable TCP/IP checksum offloading by default. ++ * ++ * 04 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * set CFG_ENABLE_FULL_PM to 1 as default to ++ * 1) acquire own before hardware access ++ * 2) set own back after hardware access ++ * ++ * 04 15 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * change firmware name ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * disable RX-enhanced response temporally, it seems the CQ is not resolved yet. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * re-enable RX enhanced mode as WPD00003827 is resolved. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * turn off RX_ENHANCE mode by default. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) eliminate unused definitions ++ * * 2) ready bit will be polled for limited iteration ++ * ++ * 04 02 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * firmware download: Linux uses different firmware path ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * * due to the different configurations on FPGA and ASIC ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add options for full PM support. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * turn on FW-DOWNLOAD as default for release. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 05 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * change CFG_NUM_OF_QM_RX_PKT_NUM to 120 ++ * ++ * 03 04 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * . ++ * ++ * 03 04 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * increase RX buffer number to avoid RX buffer starvation. ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed the number of STA_RECs to 20 ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * and result is retrieved by get ATInfo instead ++ * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-16 22:12:28 GMT mtk02752 ++** enable interrupt enhanced response, TX/RX Aggregation as default ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:38:43 GMT mtk02752 ++** eliminate compile options which are obsolete or for emulation purpose ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 13:56:26 GMT MTK02468 ++** Added RX buffer reordering configurations ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-12-04 12:09:09 GMT mtk02752 ++** once enhanced intr/rx response is taken, RX must be access in aggregated basis ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 17:54:50 GMT mtk02752 ++** correct a typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:47 GMT mtk01084 ++** add defines ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:33:37 GMT mtk02752 ++** add coalescing buffer definition for SD1_SD3_DATAPATH_INTEGRATION ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 20:32:40 GMT mtk02752 ++** add CFG_TX_MAX_PKT_NUM for limiting queued TX packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 13:34:44 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION define for source control ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 13:54:11 GMT mtk01084 ++** enable INT enhance mode by default ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-30 18:17:14 GMT mtk01084 ++** add new define ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-10-29 19:47:36 GMT mtk01084 ++** not use HIF loopback mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-13 21:58:33 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-09-09 17:26:08 GMT mtk01084 ++** add CFG_TEST_WITH_MT5921 ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:02:30 GMT mtk01426 ++** Update CFG_RX_COALESCING_BUFFER_SIZE ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-21 09:35:51 GMT mtk01461 ++** Add CFG_TX_DBG_MGT_BUF to debug MGMT Buffer depth ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:52:21 GMT mtk01426 ++** Add OOB_DATA_PRE_FIXED_LEN define ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-08 16:51:08 GMT mtk01084 ++** update for FW download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:33:37 GMT mtk01461 ++** Add SW pre test flag CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 00:29:18 GMT mtk01461 ++** Fix CFG_COALESCING_BUFFER_SIZE if enable the CFG_TX_FRAGMENT ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-18 20:58:34 GMT mtk01426 ++** Add CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-17 20:17:36 GMT mtk01426 ++** Add CMD/Response related configure ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:21 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:21 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _CONFIG_H ++#define _CONFIG_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#ifdef MT6620 ++#undef MT6620 ++#endif ++ ++#ifndef MT6628 ++#define MT6628 ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 2 Flags for OS capability */ ++ ++#define MTK_WCN_SINGLE_MODULE 0 /* 1: without WMT */ ++ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define MTK_WCN_HIF_SDIO 0 ++#else ++#define MTK_WCN_HIF_SDIO 0 /* samp */ ++#endif ++#else ++#define MTK_WCN_HIF_SDIO 0 ++#endif ++ ++#if (CFG_SUPPORT_AEE == 1) ++#define CFG_ENABLE_AEE_MSG 1 ++#else ++#define CFG_ENABLE_AEE_MSG 0 ++#endif ++ ++#if CFG_ENABLE_AEE_MSG ++#include ++#endif ++ ++/* 2 Flags for Driver Features */ ++#define CFG_TX_FRAGMENT 1 /*!< 1: Enable TX fragmentation ++ 0: Disable */ ++#define CFG_SUPPORT_PERFORMANCE_TEST 0 /*Only for performance Test */ ++ ++#define CFG_COUNTRY_CODE NULL /* "US" */ ++ ++#ifndef LINUX ++#define CFG_FW_FILENAME L"WIFI_RAM_CODE" ++#define CFG_FW_FILENAME_E6 L"WIFI_RAM_CODE_E6" ++#else ++#define CFG_FW_FILENAME "WIFI_RAM_CODE" ++#endif ++#ifndef LINUX ++#define CFG_SUPPORT_CFG_FILE 0 ++#else ++#define CFG_SUPPORT_CFG_FILE 1 ++#endif ++ ++#define CFG_SUPPORT_CE_FCC_TXPWR_LIMIT 0 /* Support CE FCC Tx Power limit */ ++ ++#define CFG_SUPPORT_802_11D 1 /*!< 1(default): Enable 802.11d ++ 0: Disable */ ++ ++#define CFG_SUPPORT_RRM 0 /* Radio Reasource Measurement (802.11k) */ ++#define CFG_SUPPORT_DFS 1 /* DFS (802.11h) */ ++ ++#if (CFG_SUPPORT_DFS == 1) /* Add by Enlai */ ++#define CFG_SUPPORT_QUIET 1 /* Quiet (802.11h) */ ++#define CFG_SUPPORT_SPEC_MGMT 1 /* Spectrum Management (802.11h): TPC and DFS */ ++#else ++#define CFG_SUPPORT_QUIET 0 /* Quiet (802.11h) */ ++#define CFG_SUPPORT_SPEC_MGMT 0 /* Spectrum Management (802.11h): TPC and DFS */ ++#endif ++ ++#define CFG_SUPPORT_RX_RDG 0 /* 11n feature. RX RDG capability */ ++#define CFG_SUPPORT_MFB 0 /* 802.11n MCS Feedback responder */ ++#define CFG_SUPPORT_RX_STBC 1 /* 802.11n RX STBC (1SS) */ ++#define CFG_SUPPORT_RX_SGI 1 /* 802.11n RX short GI for both 20M and 40M BW */ ++#define CFG_SUPPORT_RX_HT_GF 1 /* 802.11n RX HT green-field capability */ ++ ++#define CFG_SUPPORT_ROAMING_ENC 0 /* enahnced roaming */ ++ ++#define CFG_SUPPORT_TDLS 1 /* IEEE802.11z TDLS */ ++#define CFG_SUPPORT_TDLS_DBG 0 /* TDLS debug */ ++#define CFG_SUPPORT_STATISTICS 1 ++#define CFG_SUPPORT_DBG_POWERMODE 1 /* for debugging power always active mode */ ++ ++#define CFG_SUPPORT_GSCN 1 ++ ++#define CFG_SUPPORT_TXR_ENC 0 /* enhanced tx rate switch */ ++ ++#define CFG_SUPPORT_PERSIST_NETDEV 0 /* create NETDEV when system bootup */ ++ ++#define CFG_FORCE_USE_20BW 1 ++/*------------------------------------------------------------------------------ ++ * SLT Option ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SLT_SUPPORT 0 ++ ++#define MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE 0 ++ ++#if defined(MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE) ++#define CFG_AUTO_CHANNEL_SEL_SUPPORT 1 ++#else ++#define CFG_AUTO_CHANNEL_SEL_SUPPORT 0 ++#endif ++ ++#ifdef NDIS60_MINIPORT ++#define CFG_NATIVE_802_11 1 ++ ++#define CFG_TX_MAX_PKT_SIZE 2304 ++#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 /* !< 1: Enable TCP/IP header checksum offload ++ 0: Disable */ ++#define CFG_TCP_IP_CHKSUM_OFFLOAD 0 ++#define CFG_WHQL_DOT11_STATISTICS 1 ++#define CFG_WHQL_ADD_REMOVE_KEY 1 ++#define CFG_WHQL_CUSTOM_IE 1 ++#define CFG_WHQL_SAFE_MODE_ENABLED 1 ++ ++#else ++#define CFG_TCP_IP_CHKSUM_OFFLOAD 1 /* !< 1: Enable TCP/IP header checksum offload ++ 0: Disable */ ++#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 ++#define CFG_TX_MAX_PKT_SIZE 1600 ++#define CFG_NATIVE_802_11 0 ++#endif ++ ++/* 2 Flags for Driver Parameters */ ++/*------------------------------------------------------------------------------ ++ * Flags for EHPI Interface in Colibri Platform ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_EHPI_FASTER_BUS_TIMING 0 /*!< 1: Do workaround for faster bus timing ++ 0(default): Disable */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags for HIFSYS Interface ++ *------------------------------------------------------------------------------ ++ */ ++#ifdef _lint ++#define _HIF_SDIO 0 /* samp */ ++#endif ++ ++#define CFG_SDIO_INTR_ENHANCE 1 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode ++ 0: Disable */ ++#define CFG_SDIO_RX_ENHANCE 0 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode ++ 0: Disable */ ++#define CFG_SDIO_TX_AGG 1 /*!< 1: Enable SDIO TX enhance ++ mode(Multiple frames in single BLOCK CMD) ++ 0(default): Disable */ ++ ++#define CFG_SDIO_RX_AGG 1 /*!< 1: Enable SDIO RX enhance ++ mode(Multiple frames in single BLOCK CMD) ++ 0(default): Disable */ ++ ++#if (CFG_SDIO_RX_AGG == 1) && (CFG_SDIO_INTR_ENHANCE == 0) ++#error "CFG_SDIO_INTR_ENHANCE should be 1 once CFG_SDIO_RX_AGG equals to 1" ++#elif (CFG_SDIO_INTR_ENHANCE == 1 || CFG_SDIO_RX_ENHANCE == 1) && (CFG_SDIO_RX_AGG == 0) ++#error "CFG_SDIO_RX_AGG should be 1 once CFG_SDIO_INTR_ENHANCE and/or CFG_SDIO_RX_ENHANCE equals to 1" ++#endif ++ ++#define CFG_SDIO_MAX_RX_AGG_NUM 0 /*!< 1: Setting the maximum RX aggregation number ++ 0(default): no limited */ ++ ++#ifdef WINDOWS_CE ++#define CFG_SDIO_PATHRU_MODE 1 /*!< 1: Support pass through (PATHRU) mode ++ 0: Disable */ ++#else ++#define CFG_SDIO_PATHRU_MODE 0 /*!< 0: Always disable if WINDOWS_CE is not defined */ ++#endif ++ ++#define CFG_MAX_RX_ENHANCE_LOOP_COUNT 3 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Integration ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(MT6620) ++#define MT6620_FPGA_BWCS 0 ++#define MT6620_FPGA_V5 0 ++ ++#if (MT6620_FPGA_BWCS == 1) && (MT6620_FPGA_V5 == 1) ++#error ++#endif ++ ++#if (MTK_WCN_HIF_SDIO == 1) ++#define CFG_MULTI_ECOVER_SUPPORT 1 ++#elif !defined(LINUX) ++#define CFG_MULTI_ECOVER_SUPPORT 1 ++#else ++#define CFG_MULTI_ECOVER_SUPPORT 0 ++#endif ++ ++#define CFG_ENABLE_CAL_LOG 0 ++#define CFG_REPORT_RFBB_VERSION 0 ++ ++#elif defined(MT6628) ++ ++#define CFG_MULTI_ECOVER_SUPPORT 0 ++ ++#define CFG_ENABLE_CAL_LOG 1 ++#define CFG_REPORT_RFBB_VERSION 1 ++ ++#endif ++ ++#define CFG_CHIP_RESET_SUPPORT 1 ++ ++#if defined(MT6628) ++#define CFG_EMBED_FIRMWARE_BUILD_DATE_CODE 1 ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * Flags for workaround ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(MT6620) && (MT6620_FPGA_BWCS == 0) && (MT6620_FPGA_V5 == 0) ++#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 ++#else ++#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 ++#endif ++ ++/* SPM issue: suspend current is higher than deep idle */ ++#define CFG_SPM_WORKAROUND_FOR_HOTSPOT 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for driver version ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_DRV_OWN_VERSION \ ++ ((UINT_16)((NIC_DRIVER_MAJOR_VERSION << 8) | (NIC_DRIVER_MINOR_VERSION))) ++#define CFG_DRV_PEER_VERSION ((UINT_16)0x0000) ++ ++/*------------------------------------------------------------------------------ ++ * Flags for TX path which are OS dependent ++ *------------------------------------------------------------------------------ ++ */ ++/*! NOTE(Kevin): If the Network buffer is non-scatter-gather like structure(without ++ * NETIF_F_FRAGLIST in LINUX), then we can set CFG_TX_BUFFER_IS_SCATTER_LIST to "0" ++ * for zero copy TX packets. ++ * For scatter-gather like structure, we set "1", driver will do copy frame to ++ * internal coalescing buffer before write it to FIFO. ++ */ ++#if defined(LINUX) ++#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 /*!< 1: Do frame copy before write to TX FIFO. ++ Used when Network buffer is scatter-gather. ++ 0(default): Do not copy frame */ ++#else /* WINDOWS/WINCE */ ++#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 ++#endif /* LINUX */ ++ ++#if CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST ++#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE * NIC_TX_BUFF_SUM) ++#else ++#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE) ++#endif /* CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for TX path ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*! Maximum number of SW TX packet queue */ ++#define CFG_TX_MAX_PKT_NUM 512 /* 256 must >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD * 2; ++ or wmm will fail when queue is full */ ++ ++/*! Maximum number of SW TX CMD packet buffer */ ++#define CFG_TX_MAX_CMD_PKT_NUM 32 ++ ++/*! Maximum number of associated STAs */ ++#define CFG_NUM_OF_STA_RECORD 20 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for RX path ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*! Max. descriptor number - sync. with firmware */ ++#if CFG_SLT_SUPPORT ++#define CFG_NUM_OF_RX0_HIF_DESC 42 ++#else ++#define CFG_NUM_OF_RX0_HIF_DESC 16 ++#endif ++#define CFG_NUM_OF_RX1_HIF_DESC 2 ++ ++/*! Max. buffer hold by QM */ ++#define CFG_NUM_OF_QM_RX_PKT_NUM 120 ++ ++/*! Maximum number of SW RX packet buffer */ ++#define CFG_RX_MAX_PKT_NUM ((CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC) * 3 \ ++ + CFG_NUM_OF_QM_RX_PKT_NUM) ++ ++#define CFG_RX_REORDER_Q_THRESHOLD 8 ++ ++#ifndef LINUX ++#define CFG_RX_RETAINED_PKT_THRESHOLD \ ++ (CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC + CFG_NUM_OF_QM_RX_PKT_NUM) ++#else ++#define CFG_RX_RETAINED_PKT_THRESHOLD 0 ++#endif ++ ++/*! Maximum RX packet size, if exceed this value, drop incoming packet */ ++/* 7.2.3 Maganement frames */ ++#define CFG_RX_MAX_PKT_SIZE (28 + 2312 + 12 /*HIF_RX_HEADER_T*/) /* TODO: it should be ++ 4096 under emulation mode */ ++ ++/*! Minimum RX packet size, if lower than this value, drop incoming packet */ ++#define CFG_RX_MIN_PKT_SIZE 10 /*!< 802.11 Control Frame is 10 bytes */ ++ ++#if CFG_SDIO_RX_AGG ++ /* extra size for CS_STATUS and enhanced response */ ++#define CFG_RX_COALESCING_BUFFER_SIZE ((CFG_NUM_OF_RX0_HIF_DESC + 1) \ ++ * CFG_RX_MAX_PKT_SIZE) ++#else ++#define CFG_RX_COALESCING_BUFFER_SIZE (CFG_RX_MAX_PKT_SIZE) ++#endif ++ ++/*! RX BA capability */ ++#define CFG_NUM_OF_RX_BA_AGREEMENTS 8 ++#define CFG_RX_BA_MAX_WINSIZE 16 ++#define CFG_RX_BA_INC_SIZE 4 ++#define CFG_RX_MAX_BA_TID_NUM 8 ++#define CFG_RX_REORDERING_ENABLED 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for CMD/RESPONSE ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_RESPONSE_POLLING_TIMEOUT 512 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Protocol Stack ++ *------------------------------------------------------------------------------ ++ */ ++/*! Maximum number of BSS in the SCAN list */ ++#define CFG_MAX_NUM_BSS_LIST 64 ++ ++#define CFG_MAX_COMMON_IE_BUF_LEN ((1500 * CFG_MAX_NUM_BSS_LIST) / 3) ++ ++/*! Maximum size of Header buffer of each SCAN record */ ++#define CFG_RAW_BUFFER_SIZE 1024 ++ ++/*! Maximum size of IE buffer of each SCAN record */ ++#define CFG_IE_BUFFER_SIZE 512 ++ ++/*! Maximum number of STA records */ ++#define CFG_MAX_NUM_STA_RECORD 32 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Power management ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FULL_PM 1 ++#define CFG_ENABLE_WAKEUP_ON_LAN 0 ++#if defined(CONFIG_ARCH_MT6755) || defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || \ ++ defined(CONFIG_ARCH_MT6753) || defined(CONFIG_ARCH_MT6580) ++#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 1 /* debug which packet wake up host */ ++#else ++#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 0 /* debug which packet wake up host */ ++#endif ++#define CFG_INIT_POWER_SAVE_PROF ENUM_PSP_FAST_SWITCH ++ ++#define CFG_INIT_ENABLE_PATTERN_FILTER_ARP 0 ++ ++#define CFG_INIT_UAPSD_AC_BMP 0 /* (BIT(3) | BIT(2) | BIT(1) | BIT(0)) */ ++ ++/* #define CFG_SUPPORT_WAPI 0 */ ++#define CFG_SUPPORT_WPS 1 ++#define CFG_SUPPORT_WPS2 1 ++ ++/*------------------------------------------------------------------------------ ++ * 802.11i RSN Pre-authentication PMKID cahce maximun number ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_MAX_PMKID_CACHE 16 /*!< max number of PMKID cache ++ 16(default) : The Max PMKID cache */ ++/*------------------------------------------------------------------------------ ++ * Auto Channel Selection Maximun Channel Number ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define MAX_AUTO_CHAL_NUM 23 /* Ch1~Ch14,Ch36,Ch40,Ch44, ++ Ch48,Ch149,Ch153,Ch157,Ch161 */ ++/*------------------------------------------------------------------------------ ++ * FAST SCAN ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FAST_SCAN 0 ++#define CFG_CN_SUPPORT_CLASS121 0 /* Add Class 121, 5470-5725MHz, support for China domain */ ++#if CFG_ENABLE_FAST_SCAN ++ #define CFG_FAST_SCAN_DWELL_TIME 40 ++ #define CFG_FAST_SCAN_REG_DOMAIN_DEF_IDX 10 ++#endif ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Ad-Hoc ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_INIT_ADHOC_FREQ (2462000) ++#define CFG_INIT_ADHOC_MODE AD_HOC_MODE_MIXED_11BG ++#define CFG_INIT_ADHOC_BEACON_INTERVAL (100) ++#define CFG_INIT_ADHOC_ATIM_WINDOW (0) ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Maximum Scan SSID number ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SCAN_SSID_MAX_NUM (4) ++#define CFG_SCAN_SSID_MATCH_MAX_NUM (16) ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Load Setup Default ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags for enable 802.11A Band setting ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Interrupt Process ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(_HIF_SDIO) && defined(WINDOWS_CE) ++#define CFG_IST_LOOP_COUNT 8 ++#else ++#define CFG_IST_LOOP_COUNT 8 ++#endif /* _HIF_SDIO */ ++ ++#define CFG_INT_WRITE_CLEAR 0 ++ ++#if defined(LINUX) ++#define CFG_DBG_GPIO_PINS 0 /* if 1, use MT6516 GPIO pin to log TX behavior */ ++#endif ++ ++/* 2 Flags for Driver Debug Options */ ++/*------------------------------------------------------------------------------ ++ * Flags of TX Debug Option. NOTE(Kevin): Confirm with SA before modifying following flags. ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_DBG_MGT_BUF 1 /*!< 1: Debug statistics usage of MGMT Buffer ++ 0: Disable */ ++ ++#define CFG_HIF_STATISTICS 0 ++ ++#define CFG_HIF_RX_STARVATION_WARNING 0 ++ ++#define CFG_STARTUP_DEBUG 0 ++ ++#define CFG_RX_PKTS_DUMP 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Firmware Download Option. ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FW_DOWNLOAD 1 ++ ++#define CFG_ENABLE_FW_DOWNLOAD_ACK 1 ++#define CFG_ENABLE_FW_ENCRYPTION 1 ++ ++#if defined(MT6628) ++#define CFG_ENABLE_FW_DOWNLOAD_AGGREGATION 0 ++#define CFG_ENABLE_FW_DIVIDED_DOWNLOAD 1 ++#endif ++ ++#if defined(MT6620) ++#if MT6620_FPGA_BWCS ++#define CFG_FW_LOAD_ADDRESS 0x10014000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10014001 ++#elif MT6620_FPGA_V5 ++#define CFG_FW_LOAD_ADDRESS 0x10008000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10008001 ++#else ++#define CFG_FW_LOAD_ADDRESS 0x10008000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10008001 ++#endif ++#elif defined(MT6628) ++#define CFG_FW_LOAD_ADDRESS 0x00060000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 1 ++#define CFG_FW_START_ADDRESS 0x00060000 ++#define CFG_START_ADDRESS_IS_1ST_SECTION_ADDR 1 ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Bluetooth-over-WiFi (BT 3.0 + HS) support ++ *------------------------------------------------------------------------------ ++ */ ++ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define CFG_ENABLE_BT_OVER_WIFI 0 ++#else ++#define CFG_ENABLE_BT_OVER_WIFI 1 ++#endif ++#else ++#define CFG_ENABLE_BT_OVER_WIFI 0 ++#endif ++ ++#define CFG_BOW_SEPARATE_DATA_PATH 1 ++ ++#define CFG_BOW_PHYSICAL_LINK_NUM 4 ++ ++#define CFG_BOW_TEST 0 ++ ++#define CFG_BOW_LIMIT_AIS_CHNL 1 ++ ++#define CFG_BOW_SUPPORT_11N 0 ++ ++#define CFG_BOW_RATE_LIMITATION 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Wi-Fi Direct support ++ *------------------------------------------------------------------------------ ++ */ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define CFG_ENABLE_WIFI_DIRECT 0 ++#define CFG_SUPPORT_802_11W 0 ++#else ++#define CFG_ENABLE_WIFI_DIRECT 1 ++#define CFG_SUPPORT_802_11W 0 /*!< 0(default): Disable 802.11W */ ++#endif ++#else ++#define CFG_ENABLE_WIFI_DIRECT 0 ++#define CFG_SUPPORT_802_11W 0 /* Not support at WinXP */ ++#endif ++ ++#define CFG_SUPPORT_PERSISTENT_GROUP 0 ++ ++#define CFG_TEST_WIFI_DIRECT_GO 0 ++ ++#define CFG_TEST_ANDROID_DIRECT_GO 0 ++ ++#define CFG_UNITEST_P2P 0 ++ ++/* ++ * Enable cfg80211 option after Android 2.2(Froyo) is suggested, ++ * cfg80211 on linux 2.6.29 is not mature yet ++ */ ++#define CFG_ENABLE_WIFI_DIRECT_CFG_80211 1 ++ ++#define CFG_SUPPORT_HOTSPOT_OPTIMIZATION 1 ++#define CFG_HOTSPOT_OPTIMIZATION_BEACON_INTERVAL 300 ++#define CFG_HOTSPOT_OPTIMIZATION_DTIM 1 ++ ++/*------------------------------------------------------------------------------ ++ * Configuration Flags (Linux Only) ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_EXT_CONFIG 0 ++ ++/*------------------------------------------------------------------------------ ++ * Statistics Buffering Mechanism ++ *------------------------------------------------------------------------------ ++ */ ++#if CFG_SUPPORT_PERFORMANCE_TEST ++#define CFG_ENABLE_STATISTICS_BUFFERING 1 ++#else ++#define CFG_ENABLE_STATISTICS_BUFFERING 0 ++#endif ++#define CFG_STATISTICS_VALID_CYCLE 2000 ++#define CFG_LINK_QUALITY_VALID_PERIOD 5000 ++ ++/*------------------------------------------------------------------------------ ++ * Migration Option ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_ADHOC 0 ++#define CFG_SUPPORT_AAA 1 ++ ++#define CFG_SUPPORT_BCM 0 ++#define CFG_SUPPORT_BCM_BWCS 0 ++#define CFG_SUPPORT_BCM_BWCS_DEBUG 0 ++ ++#define CFG_SUPPORT_RDD_TEST_MODE 0 ++ ++#define CFG_SUPPORT_PWR_MGT 1 ++ ++#define CFG_RSN_MIGRATION 1 ++ ++#define CFG_PRIVACY_MIGRATION 1 ++ ++#define CFG_ENABLE_HOTSPOT_PRIVACY_CHECK 1 ++ ++#define CFG_MGMT_FRAME_HANDLING 1 ++ ++#define CFG_MGMT_HW_ACCESS_REPLACEMENT 0 ++ ++#if CFG_SUPPORT_PERFORMANCE_TEST ++ ++#else ++ ++#endif ++ ++#define CFG_SUPPORT_AIS_5GHZ 1 ++#define CFG_SUPPORT_BEACON_CHANGE_DETECTION 0 ++ ++/*------------------------------------------------------------------------------ ++ * Option for NVRAM and Version Checking ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_NVRAM 1 ++#define CFG_NVRAM_EXISTENCE_CHECK 1 ++#define CFG_SW_NVRAM_VERSION_CHECK 1 ++#define CFG_SUPPORT_NIC_CAPABILITY 1 ++ ++/*------------------------------------------------------------------------------ ++ * CONFIG_TITLE : Stress Test Option ++ * OWNER : Puff Wen ++ * Description : For stress test only. DO NOT enable it while normal operation ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_STRESS_TEST_SUPPORT 0 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for LINT ++ *------------------------------------------------------------------------------ ++ */ ++#define LINT_SAVE_AND_DISABLE /*lint -save -e* */ ++ ++#define LINT_RESTORE /*lint -restore */ ++ ++#define LINT_EXT_HEADER_BEGIN LINT_SAVE_AND_DISABLE ++ ++#define LINT_EXT_HEADER_END LINT_RESTORE ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Features ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define CFG_SUPPORT_QOS 1 /* Enable/disable QoS TX, AMPDU */ ++#define CFG_SUPPORT_AMPDU_TX 1 ++#define CFG_SUPPORT_AMPDU_RX 1 ++#define CFG_SUPPORT_TSPEC 0 /* Enable/disable TS-related Action frames handling */ ++#define CFG_SUPPORT_UAPSD 1 ++#define CFG_SUPPORT_UL_PSMP 0 ++ ++#define CFG_SUPPORT_ROAMING 1 /* Roaming System */ ++#define CFG_SUPPORT_SWCR 1 ++ ++#define CFG_SUPPORT_ANTI_PIRACY 1 ++ ++#define CFG_SUPPORT_OSC_SETTING 1 ++ ++#define CFG_SUPPORT_P2P_RSSI_QUERY 0 ++ ++#define CFG_SHOW_MACADDR_SOURCE 1 ++ ++#define CFG_SUPPORT_802_11V 0 /* Support 802.11v Wireless Network Management */ ++#define CFG_SUPPORT_802_11V_TIMING_MEASUREMENT 0 ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (CFG_SUPPORT_802_11V == 0) ++#error "CFG_SUPPORT_802_11V should be 1 once CFG_SUPPORT_802_11V_TIMING_MEASUREMENT equals to 1" ++#endif ++#if (CFG_SUPPORT_802_11V == 0) ++#define WNM_UNIT_TEST 0 ++#endif ++ ++#define CFG_DRIVER_COMPOSE_ASSOC_REQ 1 ++ ++#define CFG_STRICT_CHECK_CAPINFO_PRIVACY 0 ++ ++#define CFG_SUPPORT_WFD 1 ++ ++#define CFG_SUPPORT_WFD_COMPOSE_IE 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Packet Lifetime Profiling Mechanism ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_PKT_LIFETIME_PROFILE 1 ++ ++#define CFG_ENABLE_PER_STA_STATISTICS 1 ++ ++#define CFG_PRINT_RTP_PROFILE 0 /* If want to enable WFD Debug, please change it to 1. */ ++#define CFG_PRINT_RTP_SN_SKIP 0 ++ ++#define CFG_SUPPORT_PWR_LIMIT_COUNTRY 1 ++/*------------------------------------------------------------------------------ ++ * Flags of bus error tolerance ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_FORCE_RESET_UNDER_BUS_ERROR 0 ++ ++/*------------------------------------------------------------------------------ ++ * Build Date Code Integration ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_BUILD_DATE_CODE 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for prepare the FW compile flag ++ *------------------------------------------------------------------------------ ++ */ ++#define COMPILE_FLAG0_GET_STA_LINK_STATUS (1<<0) ++#define COMPILE_FLAG0_WFD_ENHANCEMENT_PROTECT (1<<1) ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Batch Scan SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_BATCH_SCAN 0 ++#define CFG_BATCH_MAX_MSCAN 2 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Channel Environment SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_GET_CH_ENV 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of THERMO_THROTTLING SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define CFG_SUPPORT_THERMO_THROTTLING 1 ++#define WLAN_INCLUDE_PROC 1 ++ ++#define CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE 1 ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _CONFIG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h +new file mode 100644 +index 000000000000..af586063c21a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h +@@ -0,0 +1,466 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/debug.h#1 ++*/ ++ ++/*! \file debug.h ++ \brief Definition of SW debugging level. ++ ++ In this file, it describes the definition of various SW debugging levels and ++ assert functions. ++*/ ++ ++/* ++** Log: debug.h ++ * ++ * 12 16 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * fixed the Windows DDK free build compiling error. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 07 2011 wh.su ++ * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * . ++ * ++ * 09 23 2010 cp.wu ++ * NULL ++ * add BOW index for debugging message and passing compilation ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add one more debug moduel for P2P. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add debug module index for cnm and ais. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-29 19:47:50 GMT mtk01084 ++** add emu category ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-17 18:12:04 GMT mtk01426 ++** Don't use dynamic memory allocate for debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:29 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _DEBUG_H ++#define _DEBUG_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#ifndef BUILD_QA_DBG ++#define BUILD_QA_DBG 0 ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++extern UINT_8 aucDebugModule[]; ++extern UINT_32 u4DebugModule; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Define debug category (class): ++ * (1) ERROR (2) WARN (3) STATE (4) EVENT (5) TRACE (6) INFO (7) LOUD (8) TEMP ++ */ ++#define DBG_CLASS_ERROR BIT(0) ++#define DBG_CLASS_WARN BIT(1) ++#define DBG_CLASS_STATE BIT(2) ++#define DBG_CLASS_EVENT BIT(3) ++#define DBG_CLASS_TRACE BIT(4) ++#define DBG_CLASS_INFO BIT(5) ++#define DBG_CLASS_LOUD BIT(6) ++#define DBG_CLASS_TEMP BIT(7) ++#define DBG_CLASS_MASK BITS(0, 7) ++ ++#if defined(LINUX) ++#define DBG_PRINTF_64BIT_DEC "lld" ++ ++#else /* Windows */ ++#define DBG_PRINTF_64BIT_DEC "I64d" ++ ++#endif ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Define debug module index */ ++typedef enum _ENUM_DBG_MODULE_T { ++ DBG_INIT_IDX = 0, /* For driver initial */ ++ DBG_HAL_IDX, /* For HAL(HW) Layer */ ++ DBG_INTR_IDX, /* For Interrupt */ ++ DBG_REQ_IDX, ++ DBG_TX_IDX, ++ DBG_RX_IDX, ++ DBG_RFTEST_IDX, /* For RF test mode */ ++ DBG_EMU_IDX, /* Developer specific */ ++ ++ DBG_SW1_IDX, /* Developer specific */ ++ DBG_SW2_IDX, /* Developer specific */ ++ DBG_SW3_IDX, /* Developer specific */ ++ DBG_SW4_IDX, /* Developer specific */ ++ ++ DBG_HEM_IDX, /* HEM */ ++ DBG_AIS_IDX, /* AIS */ ++ DBG_RLM_IDX, /* RLM */ ++ DBG_MEM_IDX, /* RLM */ ++ DBG_CNM_IDX, /* CNM */ ++ DBG_RSN_IDX, /* RSN */ ++ DBG_BSS_IDX, /* BSS */ ++ DBG_SCN_IDX, /* SCN */ ++ DBG_SAA_IDX, /* SAA */ ++ DBG_AAA_IDX, /* AAA */ ++ DBG_P2P_IDX, /* P2P */ ++ DBG_QM_IDX, /* QUE_MGT */ ++ DBG_SEC_IDX, /* SEC */ ++ DBG_BOW_IDX, /* BOW */ ++ DBG_WAPI_IDX, /* WAPI */ ++ DBG_ROAMING_IDX, /* ROAMING */ ++ DBG_TDLS_IDX, /* TDLS *//* CFG_SUPPORT_TDLS */ ++ DBG_OID_IDX, ++ DBG_NIC_IDX, ++ ++ DBG_MODULE_NUM /* Notice the XLOG check */ ++} ENUM_DBG_MODULE_T; ++ ++/* XLOG */ ++/* #define XLOG_DBG_MODULE_IDX 28 */ /* DBG_MODULE_NUM */ ++/* #if (XLOG_DBG_MODULE_IDX != XLOG_DBG_MODULE_IDX) */ ++/* #error "Please modify the DBG_MODULE_NUM and make sure this include at XLOG" */ ++/* #endif */ ++ ++/* Define who owns developer specific index */ ++#define DBG_YARCO_IDX DBG_SW1_IDX ++#define DBG_KEVIN_IDX DBG_SW2_IDX ++#define DBG_CMC_IDX DBG_SW3_IDX ++#define DBG_GEORGE_IDX DBG_SW4_IDX ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Debug print format string for the OS system time */ ++#define OS_SYSTIME_DBG_FORMAT "0x%08x" ++ ++/* Debug print argument for the OS system time */ ++#define OS_SYSTIME_DBG_ARGUMENT(systime) (systime) ++ ++/* Debug print format string for the MAC Address */ ++#define MACSTR "%pM" ++/* "%02x:%02x:%02x:%02x:%02x:%02x" */ ++ ++/* Debug print argument for the MAC Address */ ++#define MAC2STR(a) a ++/* ((PUINT_8)a)[0], ((PUINT_8)a)[1], ((PUINT_8)a)[2], ((PUINT_8)a)[3], ((PUINT_8)a)[4], ((PUINT_8)a)[5] */ ++ ++/* The pre-defined format to dump the value of a varaible with its name shown. */ ++#define DUMPVAR(variable, format) (#variable " = " format "\n", variable) ++ ++/* The pre-defined format to dump the MAC type value with its name shown. */ ++#define DUMPMACADDR(addr) (#addr " = %pM\n", (addr)) ++ ++/* Basiclly, we just do renaming of KAL functions although they should ++ * be defined as "Nothing to do" if DBG=0. But in some compiler, the macro ++ * syntax does not support #define LOG_FUNC(x,...) ++ * ++ * A caller shall not invoke these three macros when DBG=0. ++ */ ++ ++/*LOG_FUNC("[wlan]%s:(" #_Module " " #_Class ") "_Fmt, __func__, ##__VA_ARGS__);*/ ++ ++#define LOG_FUNC kalPrint ++ ++#if defined(LINUX) ++#define DBGLOG(_Module, _Class, _Fmt, ...) \ ++ do { \ ++ if ((aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) == 0) \ ++ break; \ ++ LOG_FUNC("%s:(" #_Module " " #_Class ")"_Fmt, __func__, ##__VA_ARGS__); \ ++ } while (0) ++#else ++#define DBGLOG(_Module, _Class, _Fmt) ++#endif ++ ++#if DBG ++ ++#define TMP_BUF_LEN 256 ++#define TMP_WBUF_LEN (TMP_BUF_LEN * 2) ++ ++extern PINT_16 g_wbuf_p; ++extern PINT_8 g_buf_p; ++ ++ /* If __FUNCTION__ is already defined by compiler, we just use it. */ ++#if defined(__func__) ++#define DEBUGFUNC(_Func) ++#else ++#define DEBUGFUNC(_Func) \ ++ static const char __func__[] = _Func ++#endif ++ ++#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ ++ { \ ++ if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ ++ LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ ++ dumpMemory8((PUINT_8) (_StartAddr), (UINT_32) (_Length)); \ ++ } \ ++ } ++ ++#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) \ ++ { \ ++ if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ ++ LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ ++ dumpMemory32((PUINT_32) (_StartAddr), (UINT_32) (_Length)); \ ++ } \ ++ } ++ /*lint -restore */ ++ ++ /*lint -save -e961 use of '#undef' is discouraged */ ++#undef ASSERT ++ /*lint -restore */ ++ ++#ifdef _lint ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp)) { \ ++ do {} while (1); \ ++ } \ ++ } ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#endif /* _lint */ ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define DISP_STRING(_str) _str ++ ++#else /* !DBG */ ++ ++#define DEBUGFUNC(_Func) ++#define INITLOG(_Fmt) ++#define ERRORLOG(_Fmt) ++#define WARNLOG(_Fmt) ++ ++#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) ++#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) ++ ++#undef ASSERT ++ ++#if BUILD_QA_DBG ++#if defined(LINUX) /* For debugging in Linux w/o GDB */ ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#else ++#ifdef WINDOWS_CE ++#define UNICODE_TEXT(_msg) TEXT(_msg) ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ TCHAR rUbuf[256]; \ ++ kalBreakPoint(); \ ++ _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ ++ UNICODE_TEXT(__FILE__), \ ++ __LINE__, \ ++ UNICODE_TEXT(#_exp)); \ ++ MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ TCHAR rUbuf[256]; \ ++ kalBreakPoint(); \ ++ _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ ++ UNICODE_TEXT(__FILE__), \ ++ __LINE__, \ ++ UNICODE_TEXT(#_exp)); \ ++ MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ ++ } \ ++ } ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#endif /* WINDOWS_CE */ ++#endif /* LINUX */ ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ } \ ++ } ++#endif /* BUILD_QA_DBG */ ++ ++#define DISP_STRING(_str) "" ++ ++#endif /* DBG */ ++ ++#if CFG_STARTUP_DEBUG ++#if defined(LINUX) ++#define DBGPRINTF kalPrint ++#else ++#define DBGPRINTF DbgPrint ++#endif ++#else ++#define DBGPRINTF(...) ++#endif ++ ++/* The following macro is used for debugging packed structures. */ ++#ifndef DATA_STRUCT_INSPECTING_ASSERT ++#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ ++{ \ ++ switch (0) {case 0: case (expr): default:; } \ ++} ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length); ++ ++VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length); ++ ++VOID wlanDebugInit(VOID); ++VOID wlanDebugUninit(VOID); ++VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable); ++VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd); ++VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _DEBUG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h +new file mode 100644 +index 000000000000..108860c80e2d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h +@@ -0,0 +1,368 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/link.h#1 ++*/ ++ ++/*! \file link.h ++ \brief Definition for simple doubly linked list operations. ++ ++ In this file we define the simple doubly linked list data structure and its ++ operation MACROs and INLINE functions. ++*/ ++ ++/* ++** Log: link.h ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify a MACRO of LINK_FOR_EACH_SAFE for compile error. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833] [MT6620 and MT5931] Driver migration ++ * . ++ * ++ * ++ * ++ * ++ * May 4 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * add WIFI to BORA source control ++** \main\maintrunk.MT5921\8 2008-10-16 15:57:11 GMT mtk01461 ++** Update driver to fix lint warning ++** \main\maintrunk.MT5921\7 2008-08-10 18:47:53 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\6 2007-12-11 00:09:00 GMT mtk01461 ++** Add macro for checking valid list ++** \main\maintrunk.MT5921\5 2007-11-13 14:27:01 GMT mtk01461 ++** Add LINK_IS_INVALID macro ++** Revision 1.1.1.1 2007/06/22 08:09:05 MTK01461 ++** no message ++** ++*/ ++ ++#ifndef _LINK_H ++#define _LINK_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* May cause page fault & unalignment issue (data abort) */ ++#define INVALID_LINK_POISON1 ((VOID *) 0x00100101) ++/* Used to verify that nonbody uses non-initialized link entries. */ ++#define INVALID_LINK_POISON2 ((VOID *) 0x00100201) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Simple Doubly Linked List Structures - Entry Part */ ++typedef struct _LINK_ENTRY_T { ++ struct _LINK_ENTRY_T *prNext, *prPrev; ++} LINK_ENTRY_T, *P_LINK_ENTRY_T; ++ ++/* Simple Doubly Linked List Structures - List Part */ ++typedef struct _LINK_T { ++ P_LINK_ENTRY_T prNext; ++ P_LINK_ENTRY_T prPrev; ++ UINT_32 u4NumElem; ++} LINK_T, *P_LINK_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#if 0 /* No one use it, temporarily mark it for [Lint - Info 773] */ ++#define LINK_ADDR(rLink) { (P_LINK_ENTRY_T)(&(rLink)), (P_LINK_ENTRY_T)(&(rLink)), 0 } ++ ++#define LINK_DECLARATION(rLink) \ ++ struct _LINK_T rLink = LINK_ADDR(rLink) ++#endif ++ ++#define LINK_INITIALIZE(prLink) \ ++ do { \ ++ ((P_LINK_T)(prLink))->prNext = (P_LINK_ENTRY_T)(prLink); \ ++ ((P_LINK_T)(prLink))->prPrev = (P_LINK_ENTRY_T)(prLink); \ ++ ((P_LINK_T)(prLink))->u4NumElem = 0; \ ++ } while (0) ++ ++#define LINK_ENTRY_INITIALIZE(prEntry) \ ++ do { \ ++ ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)NULL; \ ++ ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)NULL; \ ++ } while (0) ++ ++#define LINK_ENTRY_INVALID(prEntry) \ ++ do { \ ++ ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)INVALID_LINK_POISON1; \ ++ ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)INVALID_LINK_POISON2; \ ++ } while (0) ++ ++#define LINK_IS_EMPTY(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)(prLink)) ++ ++/* NOTE: We should do memory zero before any LINK been initiated, so we can check ++ * if it is valid before parsing the LINK. ++ */ ++#define LINK_IS_INVALID(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)NULL) ++ ++#define LINK_IS_VALID(prLink) (((P_LINK_T)(prLink))->prNext != (P_LINK_ENTRY_T)NULL) ++ ++#define LINK_ENTRY(ptr, type, member) ENTRY_OF(ptr, type, member) ++ ++/* Insert an entry into a link list's head */ ++#define LINK_INSERT_HEAD(prLink, prEntry) \ ++ { \ ++ linkAdd(prEntry, prLink); \ ++ ((prLink)->u4NumElem)++; \ ++ } ++ ++/* Append an entry into a link list's tail */ ++#define LINK_INSERT_TAIL(prLink, prEntry) \ ++ { \ ++ linkAddTail(prEntry, prLink); \ ++ ((prLink)->u4NumElem)++; \ ++ } ++ ++/* Peek head entry, but keep still in link list */ ++#define LINK_PEEK_HEAD(prLink, _type, _member) \ ++ ( \ ++ LINK_IS_EMPTY(prLink) ? \ ++ NULL : LINK_ENTRY((prLink)->prNext, _type, _member) \ ++ ) ++ ++/* Peek tail entry, but keep still in link list */ ++#define LINK_PEEK_TAIL(prLink, _type, _member) \ ++ ( \ ++ LINK_IS_EMPTY(prLink) ? \ ++ NULL : LINK_ENTRY((prLink)->prPrev, _type, _member) \ ++ ) ++ ++/* Get first entry from a link list */ ++/* NOTE: We assume the link entry located at the beginning of "prEntry Type", ++ * so that we can cast the link entry to other data type without doubts. ++ * And this macro also decrease the total entry count at the same time. ++ */ ++#define LINK_REMOVE_HEAD(prLink, prEntry, _P_TYPE) \ ++ { \ ++ ASSERT(prLink); \ ++ if (LINK_IS_EMPTY(prLink)) { \ ++ prEntry = (_P_TYPE)NULL; \ ++ } \ ++ else { \ ++ prEntry = (_P_TYPE)(((P_LINK_T)(prLink))->prNext); \ ++ linkDel((P_LINK_ENTRY_T)prEntry); \ ++ ((prLink)->u4NumElem)--; \ ++ } \ ++ } ++ ++/* Assume the link entry located at the beginning of prEntry Type. ++ * And also decrease the total entry count. ++ */ ++#define LINK_REMOVE_KNOWN_ENTRY(prLink, prEntry) \ ++ { \ ++ ASSERT(prLink); \ ++ ASSERT(prEntry); \ ++ linkDel((P_LINK_ENTRY_T)prEntry); \ ++ ((prLink)->u4NumElem)--; \ ++ } ++ ++/* Iterate over a link list */ ++#define LINK_FOR_EACH(prEntry, prLink) \ ++ for (prEntry = (prLink)->prNext; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = (P_LINK_ENTRY_T)prEntry->prNext) ++ ++/* Iterate over a link list backwards */ ++#define LINK_FOR_EACH_PREV(prEntry, prLink) \ ++ for (prEntry = (prLink)->prPrev; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = (P_LINK_ENTRY_T)prEntry->prPrev) ++ ++/* Iterate over a link list safe against removal of link entry */ ++#define LINK_FOR_EACH_SAFE(prEntry, prNextEntry, prLink) \ ++ for (prEntry = (prLink)->prNext, prNextEntry = prEntry->prNext; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = prNextEntry, prNextEntry = prEntry->prNext) ++ ++/* Iterate over a link list of given type */ ++#define LINK_FOR_EACH_ENTRY(prObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember)) ++ ++/* Iterate backwards over a link list of given type */ ++#define LINK_FOR_EACH_ENTRY_PREV(prObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prPrev, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = LINK_ENTRY(prObj->rMember.prPrev, _TYPE, rMember)) ++ ++/* Iterate over a link list of given type safe against removal of link entry */ ++#define LINK_FOR_EACH_ENTRY_SAFE(prObj, prNextObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember), \ ++ prNextObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = prNextObj, \ ++ prNextObj = LINK_ENTRY(prNextObj->rMember.prNext, _TYPE, rMember)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is only for internal link list manipulation. ++* ++* \param[in] prNew Pointer of new link head ++* \param[in] prPrev Pointer of previous link head ++* \param[in] prNext Pointer of next link head ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID __linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) ++{ ++ prNext->prPrev = prNew; ++ prNew->prNext = prNext; ++ prNew->prPrev = prPrev; ++ prPrev->prNext = prNew; ++ ++} /* end of __linkAdd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will add a new entry after the specified link head. ++* ++* \param[in] prNew New entry to be added ++* \param[in] prHead Specified link head to add it after ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) ++{ ++ __linkAdd(prNew, (P_LINK_ENTRY_T) prLink, prLink->prNext); ++ ++} /* end of linkAdd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will add a new entry before the specified link head. ++* ++* \param[in] prNew New entry to be added ++* \param[in] prHead Specified link head to add it before ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkAddTail(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) ++{ ++ __linkAdd(prNew, prLink->prPrev, (P_LINK_ENTRY_T) prLink); ++ ++} /* end of linkAddTail() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is only for internal link list manipulation. ++* ++* \param[in] prPrev Pointer of previous link head ++* \param[in] prNext Pointer of next link head ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID __linkDel(IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) ++{ ++ prNext->prPrev = prPrev; ++ prPrev->prNext = prNext; ++ ++} /* end of __linkDel() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list. ++* NOTE: the entry is in an initial state. ++* ++* \param prEntry Specified link head(entry) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkDel(IN P_LINK_ENTRY_T prEntry) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ ++ LINK_ENTRY_INITIALIZE(prEntry); ++ ++} /* end of linkDel() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list and then add it ++* after the specified link head. ++* ++* \param[in] prEntry Specified link head(entry) ++* \param[in] prOtherHead Another link head to add it after ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkMove(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ linkAdd(prEntry, prLink); ++ ++} /* end of linkMove() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list and then add it ++* before the specified link head. ++* ++* \param[in] prEntry Specified link head(entry) ++* \param[in] prOtherHead Another link head to add it before ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkMoveTail(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ linkAddTail(prEntry, prLink); ++ ++} /* end of linkMoveTail() */ ++ ++#endif /* _LINK_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h +new file mode 100644 +index 000000000000..fd83c79ffe10 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h +@@ -0,0 +1,188 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/aa_fsm.h#1 ++*/ ++ ++/*! \file aa_fsm.h ++ \brief Declaration of functions and finite state machine for SAA/AAA Module. ++ ++ Declaration of functions and finite state machine for SAA/AAA Module. ++*/ ++ ++/* ++** Log: aa_fsm.h ++ * ++ * 10 13 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS ++ * 1. short join failure count limit to 2 ++ * 2. treat join timeout as kind of join failure as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _AA_FSM_H ++#define _AA_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Retry interval for retransmiting authentication-request MMPDU. */ ++#define TX_AUTHENTICATION_RETRY_TIMEOUT_TU 100 /* TU. */ ++ ++/* Retry interval for retransmiting association-request MMPDU. */ ++#define TX_ASSOCIATION_RETRY_TIMEOUT_TU 100 /* TU. */ ++ ++/* Wait for a response to a transmitted authentication-request MMPDU. */ ++#define DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ ++ ++/* Wait for a response to a transmitted association-request MMPDU. */ ++#define DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ ++ ++/* The maximum time to wait for JOIN process complete. */ ++#define JOIN_FAILURE_TIMEOUT_BEACON_INTERVAL 20 /* Beacon Interval, 20 * 100TU = 2 sec. */ ++ ++/* Retry interval for next JOIN request. */ ++#define JOIN_RETRY_INTERVAL_SEC 10 /* Seconds */ ++ ++/* Maximum Retry Count for accept a JOIN request. */ ++#define JOIN_MAX_RETRY_FAILURE_COUNT 2 /* Times */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_AA_STATE_T { ++ AA_STATE_IDLE = 0, ++ SAA_STATE_SEND_AUTH1, ++ SAA_STATE_WAIT_AUTH2, ++ SAA_STATE_SEND_AUTH3, ++ SAA_STATE_WAIT_AUTH4, ++ SAA_STATE_SEND_ASSOC1, ++ SAA_STATE_WAIT_ASSOC2, ++ AAA_STATE_SEND_AUTH2, ++ AAA_STATE_SEND_AUTH4, /* We may not use, because P2P GO didn't support WEP and 11r */ ++ AAA_STATE_SEND_ASSOC2, ++ AA_STATE_RESOURCE, /* A state for debugging the case of out of msg buffer. */ ++ AA_STATE_NUM ++} ENUM_AA_STATE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in saa_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++saaFsmSteps(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb); ++ ++WLAN_STATUS ++saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, ++ WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb); ++ ++VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS ++saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in aaa_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AA_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h +new file mode 100644 +index 000000000000..b771bdacf2c6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h +@@ -0,0 +1,573 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/ais_fsm.h#1 ++*/ ++ ++/*! \file ais_fsm.h ++ \brief Declaration of functions and finite state machine for AIS Module. ++ ++ Declaration of functions and finite state machine for AIS Module. ++*/ ++ ++/* ++** Log: ais_fsm.h ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition ++ * from synchronous to asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS ++ * is in Normal TR state without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 04 25 2011 cp.wu ++ * [WCXRP00000676] [MT6620 Wi-Fi][Driver] AIS to reduce request channel period from 5 seconds to 2 seconds ++ * channel interval for joining is shortened to 2 seconds to avoid interruption of concurrent operating network. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 02 22 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with ++ * a queue-based approach to improve response time for scanning request ++ * handle SCAN and RECONNECT with a FIFO approach. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 14 2011 cp.wu ++ * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent ++ * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. ++ * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, RLM/CNM will handle ++ * the channel switching when BSS information is updated ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, ++ * just pend it til 5-sec. period finishes ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * separate AIS-FSM states into different cases of channel request. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Refine AIS-FSM by divided into more states ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 23 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * reduce the background ssid idle time min and max value ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * and will send Null frame to diagnose connection ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Support dynamic channel selection ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Media disconnect indication and related postpone functions ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmRunEventJoinComplete() ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Virtual CMD & RESP for testing CMD PATH ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * add aisFsmInitializeConnectionSettings() ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_MGMT_FSM for aisFsmTest() ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function prototype of aisFsmInit() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _AIS_FSM_H ++#define _AIS_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define AIS_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ ++#define AIS_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ ++ ++#define AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4 2 /* 2.4G scan need about 0.5s, so delay 2s to reconnect is enough */ ++#define AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND 5 /* 2.4G scan need about 3.3s, so delay 5s to reconnect is enough */ ++ ++#define AIS_IBSS_ALONE_TIMEOUT_SEC 20 /* seconds */ ++ ++#define AIS_BEACON_TIMEOUT_COUNT_ADHOC 30 ++#define AIS_BEACON_TIMEOUT_COUNT_INFRA 10 ++#define AIS_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ ++ ++#define AIS_BEACON_MAX_TIMEOUT_TU 100 ++#define AIS_BEACON_MIN_TIMEOUT_TU 5 ++#define AIS_BEACON_MAX_TIMEOUT_VALID TRUE ++#define AIS_BEACON_MIN_TIMEOUT_VALID TRUE ++ ++#define AIS_BMC_MAX_TIMEOUT_TU 100 ++#define AIS_BMC_MIN_TIMEOUT_TU 5 ++#define AIS_BMC_MAX_TIMEOUT_VALID TRUE ++#define AIS_BMC_MIN_TIMEOUT_VALID TRUE ++ ++#define AIS_JOIN_CH_GRANT_THRESHOLD 10 ++#define AIS_JOIN_CH_REQUEST_INTERVAL 3000 ++ ++#define AIS_SCN_DONE_TIMEOUT_SEC 30 /* 15 for 2.4G + 5G */ /* 5 */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_AIS_STATE_T { ++ AIS_STATE_IDLE = 0, ++ AIS_STATE_SEARCH, ++ AIS_STATE_SCAN, ++ AIS_STATE_ONLINE_SCAN, ++ AIS_STATE_LOOKING_FOR, ++ AIS_STATE_WAIT_FOR_NEXT_SCAN, ++ AIS_STATE_REQ_CHANNEL_JOIN, ++ AIS_STATE_JOIN, ++ AIS_STATE_IBSS_ALONE, ++ AIS_STATE_IBSS_MERGE, ++ AIS_STATE_NORMAL_TR, ++ AIS_STATE_DISCONNECTING, ++ AIS_STATE_REQ_REMAIN_ON_CHANNEL, ++ AIS_STATE_REMAIN_ON_CHANNEL, ++ AIS_STATE_NUM ++} ENUM_AIS_STATE_T; ++ ++typedef struct _MSG_AIS_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucReasonOfDisconnect; ++ BOOLEAN fgDelayIndication; ++} MSG_AIS_ABORT_T, *P_MSG_AIS_ABORT_T; ++ ++typedef struct _MSG_AIS_IBSS_PEER_FOUND_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ BOOLEAN fgIsMergeIn; /* TRUE: Merge In, FALSE: Merge Out */ ++ P_STA_RECORD_T prStaRec; ++} MSG_AIS_IBSS_PEER_FOUND_T, *P_MSG_AIS_IBSS_PEER_FOUND_T; ++ ++typedef enum _ENUM_AIS_REQUEST_TYPE_T { ++ AIS_REQUEST_SCAN, ++ AIS_REQUEST_RECONNECT, ++ AIS_REQUEST_ROAMING_SEARCH, ++ AIS_REQUEST_ROAMING_CONNECT, ++ AIS_REQUEST_REMAIN_ON_CHANNEL, ++ AIS_REQUEST_NUM ++} ENUM_AIS_REQUEST_TYPE_T; ++ ++typedef struct _AIS_REQ_HDR_T { ++ LINK_ENTRY_T rLinkEntry; ++ ENUM_AIS_REQUEST_TYPE_T eReqType; ++} AIS_REQ_HDR_T, *P_AIS_REQ_HDR_T; ++ ++typedef struct _AIS_REQ_CHNL_INFO { ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eSco; ++ UINT_8 ucChannelNum; ++ UINT_32 u4DurationMs; ++ UINT_64 u8Cookie; ++} AIS_REQ_CHNL_INFO, *P_AIS_REQ_CHNL_INFO; ++ ++typedef struct _AIS_MGMT_TX_REQ_INFO_T { ++ BOOLEAN fgIsMgmtTxRequested; ++ P_MSDU_INFO_T prMgmtTxMsdu; ++ UINT_64 u8Cookie; ++} AIS_MGMT_TX_REQ_INFO_T, *P_AIS_MGMT_TX_REQ_INFO_T; ++ ++typedef struct _AIS_FSM_INFO_T { ++ ENUM_AIS_STATE_T ePreviousState; ++ ENUM_AIS_STATE_T eCurrentState; ++ ++ BOOLEAN fgTryScan; ++ ++ BOOLEAN fgIsInfraChannelFinished; ++ BOOLEAN fgIsChannelRequested; ++ BOOLEAN fgIsChannelGranted; ++ ++#if CFG_SUPPORT_ROAMING ++ BOOLEAN fgIsRoamingScanPending; ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++ P_BSS_DESC_T prTargetBssDesc; /* For destination */ ++ ++ P_STA_RECORD_T prTargetStaRec; /* For JOIN Abort */ ++ ++ UINT_32 u4SleepInterval; ++ ++ TIMER_T rBGScanTimer; ++ ++ TIMER_T rIbssAloneTimer; ++ ++ TIMER_T rIndicationOfDisconnectTimer; ++ ++ TIMER_T rJoinTimeoutTimer; ++ ++ TIMER_T rChannelTimeoutTimer; ++ ++ TIMER_T rScanDoneTimer; ++ ++ TIMER_T rDeauthDoneTimer; ++ ++ UINT_8 ucSeqNumOfReqMsg; ++ UINT_8 ucSeqNumOfChReq; ++ UINT_8 ucSeqNumOfScanReq; ++ ++ UINT_32 u4ChGrantedInterval; ++ ++ UINT_8 ucConnTrialCount; ++ ++ UINT_8 ucScanSSIDLen; ++ UINT_8 aucScanSSID[ELEM_MAX_LEN_SSID]; ++ ++ UINT_32 u4ScanIELength; ++ UINT_8 aucScanIEBuf[MAX_IE_LENGTH]; ++ ++ /* Pending Request List */ ++ LINK_T rPendingReqList; ++ ++ /* Join Request Timestamp */ ++ OS_SYSTIME rJoinReqTime; ++ ++ /* for cfg80211 REMAIN_ON_CHANNEL support */ ++ AIS_REQ_CHNL_INFO rChReqInfo; ++ ++ /* Mgmt tx related. */ ++ AIS_MGMT_TX_REQ_INFO_T rMgmtTxInfo; ++ ++ /* Packet filter for AIS module. */ ++ UINT_32 u4AisPacketFilter; ++ ++} AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define aisChangeMediaState(_prAdapter, _eNewMediaState) \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState = (_eNewMediaState)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++VOID aisFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication); ++ ++VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter); ++#if 0 ++VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState); ++#endif ++VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Handling for Ad-Hoc Network */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++/*----------------------------------------------------------------------------*/ ++/* Handling of Incoming Mailbox Message from CNM */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Generating Outgoing Mailbox Message to CNM */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Event Indication */ ++/*----------------------------------------------------------------------------*/ ++VOID ++aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); ++ ++VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb); ++ ++VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter); ++ ++VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++WLAN_STATUS ++aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Disconnection Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication); ++ ++/*----------------------------------------------------------------------------*/ ++/* Event Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter); ++ ++VOID aisBssSecurityChanged(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if CFG_SUPPORT_ROAMING ++VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan); ++ ++ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec); ++ ++VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++#endif /*CFG_SUPPORT_ROAMING */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Timeout Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength); ++ ++/*----------------------------------------------------------------------------*/ ++/* Internal State Checking */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove); ++ ++P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType); ++ ++VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); ++ ++VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) ++VOID aisTest(VOID); ++#endif /* CFG_TEST_MGMT_FSM */ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AIS_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h +new file mode 100644 +index 000000000000..70b32bca102b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h +@@ -0,0 +1,112 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/assoc.h#1 ++*/ ++ ++/*! \file assoc.h ++ \brief This file contains the ASSOC REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: assoc.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add assocCheckTxReAssocRespFrame() proto type for P2P usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _ASSOC_H ++#define _ASSOC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in assoc.c */ ++/*----------------------------------------------------------------------------*/ ++UINT_16 assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++WLAN_STATUS ++assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode); ++ ++WLAN_STATUS ++assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); ++ ++WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ASSOC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h +new file mode 100644 +index 000000000000..4f76f03324dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h +@@ -0,0 +1,125 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/auth.h#1 ++*/ ++ ++/*! \file auth.h ++ \brief This file contains the authentication REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: auth.h ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _AUTH_H ++#define _AUTH_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in auth.c */ ++/*----------------------------------------------------------------------------*/ ++VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo); ++ ++#if !CFG_SUPPORT_AAA ++WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum); ++#else ++WLAN_STATUS ++authSendAuthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode); ++#endif /* CFG_SUPPORT_AAA */ ++ ++WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum); ++ ++WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode); ++ ++VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr); ++ ++WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++authSendDeauthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); ++ ++WLAN_STATUS ++authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN UINT_8 aucExpectedBSSID[], ++ IN UINT_16 u2ExpectedAuthAlgNum, ++ IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AUTH_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h +new file mode 100644 +index 000000000000..5995d133a6cd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h +@@ -0,0 +1,184 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/bow_fsm.h#1 ++*/ ++ ++/*! \file bow_fsm.h ++ \brief Declaration of functions and finite state machine for BOW Module. ++ ++ Declaration of functions and finite state machine for BOW Module. ++*/ ++ ++/* ++** Log: bow_fsm.h ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Submit missing BoW header files. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add channel previledge into _BOW_FSM_INFO_T. ++ * ++ * 09 16 2010 chinghwa.yu ++ * NULL ++ * update bowChangeMediaState. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ */ ++ ++#ifndef _BOW_FSM_H ++#define _BOW_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define BOW_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ ++#define BOW_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ ++ ++#define BOW_DELAY_TIME_OF_DISCONNECT_SEC 10 ++ ++#define BOW_BEACON_TIMEOUT_COUNT_STARTING 10 ++#define BOW_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ ++ ++#define BOW_BEACON_MAX_TIMEOUT_TU 100 ++#define BOW_BEACON_MIN_TIMEOUT_TU 5 ++#define BOW_BEACON_MAX_TIMEOUT_VALID TRUE ++#define BOW_BEACON_MIN_TIMEOUT_VALID TRUE ++ ++#define BOW_BMC_MAX_TIMEOUT_TU 100 ++#define BOW_BMC_MIN_TIMEOUT_TU 5 ++#define BOW_BMC_MAX_TIMEOUT_VALID TRUE ++#define BOW_BMC_MIN_TIMEOUT_VALID TRUE ++ ++#define BOW_JOIN_CH_GRANT_THRESHOLD 10 ++#define BOW_JOIN_CH_REQUEST_INTERVAL 2000 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_BOW_STATE_T { ++ BOW_STATE_IDLE = 0, ++ BOW_STATE_SEARCH, ++ BOW_STATE_SCAN, ++ BOW_STATE_ONLINE_SCAN, ++ BOW_STATE_LOOKING_FOR, ++ BOW_STATE_WAIT_FOR_NEXT_SCAN, ++ BOW_STATE_REQ_CHANNEL_JOIN, ++ BOW_STATE_REQ_CHANNEL_ALONE, ++ BOW_STATE_REQ_CHANNEL_MERGE, ++ BOW_STATE_JOIN, ++ BOW_STATE_IBSS_ALONE, ++ BOW_STATE_IBSS_MERGE, ++ BOW_STATE_NORMAL_TR, ++ BOW_STATE_NUM ++} ENUM_BOW_STATE_T; ++ ++typedef struct _BOW_FSM_INFO_T { ++ ENUM_BOW_STATE_T ePreviousState; ++ ENUM_BOW_STATE_T eCurrentState; ++ ++ BOOLEAN fgTryScan; ++ ++ /* Channel Privilege */ ++ ++ BOOLEAN fgIsInfraChannelFinished; ++ BOOLEAN fgIsChannelRequested; ++ BOOLEAN fgIsChannelGranted; ++ BOOLEAN fgIsScanPending; ++ UINT_32 u4ChGrantedInterval; ++ ++ UINT_8 ucPrimaryChannel; ++ ENUM_BAND_T eBand; ++ UINT_16 u2BeaconInterval; ++ ++ ENUM_BOW_STATE_T eReturnState; /* Return state after current activity finished or abort. */ ++ ENUM_BOW_STATE_T eForwardState; /* Step to next state if ACTION frame is TX successfully. */ ++ ++ P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ ++ ++ P_STA_RECORD_T prTargetStaRec; ++ P_BSS_DESC_T prTargetBssDesc; /* For destination */ ++ ++ UINT_8 aucPeerAddress[6]; ++ ++ UINT_8 ucRole; ++ ++ BOOLEAN fgSupportQoS; ++ ++ BOOLEAN fgIsRsponseProbe; /* Indicate if BOW can response probe request frame. */ ++ ++ /* Sequence number of requested message. */ ++ UINT_8 ucSeqNumOfChReq; ++ UINT_8 ucSeqNumOfReqMsg; ++ UINT_8 ucSeqNumOfScnMsg; ++ UINT_8 ucSeqNumOfScanReq; ++ ++ UINT_8 ucSeqNumOfCancelMsg; ++ ++ UINT_8 ucDialogToken; ++ ++ /* Timer */ ++ TIMER_T rStartingBeaconTimer; /* For device discovery time of each discovery request from user. */ ++ TIMER_T rStartingDiscoveryTimer; ++ TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ ++ TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ ++ TIMER_T rIndicationOfDisconnectTimer; ++ TIMER_T rChGrantedTimer; ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++} BOW_FSM_INFO_T, *P_BOW_FSM_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define bowChangeMediaState(_prAdapter, _eNewMediaState) \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].eConnectionState = (_eNewMediaState)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h +new file mode 100644 +index 000000000000..0597132b970e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h +@@ -0,0 +1,265 @@ ++/* ++** Id: @(#) bss.h ++*/ ++ ++/*! \file "bss.h" ++ \brief In this file we define the function prototype used in BSS/IBSS. ++ ++ The file contains the function declarations and defines for used in BSS/IBSS. ++*/ ++ ++/* ++** Log: bss.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 02 23 2011 eddie.chen ++ * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap ++ * Fix parsing WMM INFO and bmp delivery bitmap definition. ++ * ++ * 01 31 2011 george.huang ++ * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers ++ * Extend TIM PVB, from 2 to 3 octets. ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Update bssProcessProbeRequest() and bssSendBeaconProbeResponse() declarations ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add CTRL FLAGS for Probe Response. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Remove unused typedef. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix file merge error ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * and will send Null frame to diagnose connection ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add DTIM count update while TX Beacon ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++#ifndef _BSS_H ++#define _BSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* NOTE(Kevin): change define for george */ ++/* #define MAX_LEN_TIM_PARTIAL_BMP (((MAX_ASSOC_ID + 1) + 7) / 8) */ /* Required bits = (MAX_ASSOC_ID + 1) */ ++#define MAX_LEN_TIM_PARTIAL_BMP ((CFG_STA_REC_NUM + 7) / 8) ++/* reserve length greater than maximum size of STA_REC */ /* obsoleted: Assume we only use AID:1~15 */ ++ ++/* CTRL FLAGS for Probe Response */ ++#define BSS_PROBE_RESP_USE_P2P_DEV_ADDR BIT(0) ++#define BSS_PROBE_RESP_INCLUDE_P2P_IE BIT(1) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define bssAssignAssocID(_prStaRec) ((_prStaRec)->ucIndex + 1) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines for all Operation Modes */ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T ++bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_STA_TYPE_T eStaType, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc); ++ ++VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec); ++ ++VOID ++bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP); ++ ++WLAN_STATUS ++bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++WLAN_STATUS ++bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for both IBSS(AdHoc) and BSS(AP) */ ++/*----------------------------------------------------------------------------*/ ++VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr); ++ ++VOID ++bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN PUINT_8 pucDestAddr, ++ IN PUINT_8 pucOwnMACAddress, ++ IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo); ++ ++WLAN_STATUS ++bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags); ++ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); ++ ++VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for IBSS(AdHoc) only */ ++/*----------------------------------------------------------------------------*/ ++VOID ++ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI); ++ ++WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for BSS(AP) only */ ++/*----------------------------------------------------------------------------*/ ++VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate); ++ ++VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId); ++ ++P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr); ++ ++/*link function to p2p module for txBcnIETable*/ ++ ++/* WMM-2.2.2 WMM ACI to AC coding */ ++typedef enum _ENUM_ACI_T { ++ ACI_BE = 0, ++ ACI_BK = 1, ++ ACI_VI = 2, ++ ACI_VO = 3, ++ ACI_NUM ++} ENUM_ACI_T, *P_ENUM_ACI_T; ++ ++typedef enum _ENUM_AC_PRIORITY_T { ++ AC_BK_PRIORITY = 0, ++ AC_BE_PRIORITY, ++ AC_VI_PRIORITY, ++ AC_VO_PRIORITY ++} ENUM_AC_PRIORITY_T, *P_ENUM_AC_PRIORITY_T; ++ ++#endif /* _BSS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h +new file mode 100644 +index 000000000000..81b16b588867 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h +@@ -0,0 +1,258 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm.h#1 ++*/ ++ ++/*! \file "cnm.h" ++ \brief ++*/ ++ ++/* ++** Log: cnm.h ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Provide function to decide if BSS can be activated or not ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 13 2010 cm.chang ++ * ++ * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Need bandwidth info when requesting channel privilege ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add a new function to send abort message ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support partial part about cmd basic configuration ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add prototype of cnmFsmEventInit() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_H ++#define _CNM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_CH_REQ_TYPE_T { ++ CH_REQ_TYPE_JOIN, ++ CH_REQ_TYPE_P2P_LISTEN, ++ ++ CH_REQ_TYPE_NUM ++} ENUM_CH_REQ_TYPE_T, *P_ENUM_CH_REQ_TYPE_T; ++ ++typedef struct _MSG_CH_REQ_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++ UINT_32 u4MaxInterval; /* In unit of ms */ ++ UINT_8 aucBSSID[6]; ++ UINT_8 aucReserved[2]; ++} MSG_CH_REQ_T, *P_MSG_CH_REQ_T; ++ ++typedef struct _MSG_CH_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++} MSG_CH_ABORT_T, *P_MSG_CH_ABORT_T; ++ ++typedef struct _MSG_CH_GRANT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++ UINT_32 u4GrantInterval; /* In unit of ms */ ++} MSG_CH_GRANT_T, *P_MSG_CH_GRANT_T; ++ ++typedef struct _MSG_CH_REOCVER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++} MSG_CH_RECOVER_T, *P_MSG_CH_RECOVER_T; ++ ++typedef struct _CNM_INFO_T { ++ UINT_32 u4Reserved; ++} CNM_INFO_T, *P_CNM_INFO_T; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/* Moved from p2p_fsm.h */ ++typedef struct _DEVICE_TYPE_T { ++ UINT_16 u2CategoryId; /* Category ID */ ++ UINT_8 aucOui[4]; /* OUI */ ++ UINT_16 u2SubCategoryId; /* Sub Category ID */ ++} __KAL_ATTRIB_PACKED__ DEVICE_TYPE_T, *P_DEVICE_TYPE_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cnmInit(P_ADAPTER_T prAdapter); ++ ++VOID cnmUninit(P_ADAPTER_T prAdapter); ++ ++VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent); ++ ++BOOLEAN ++cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO); ++ ++BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); ++ ++VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); ++#if CFG_P2P_LEGACY_COEX_REVISE ++BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* We don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this to guarantee the same member order in different structures ++ * to simply handling effort in some functions. ++ */ ++static inline VOID cnmMsgDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == OFFSET_OF(MSG_CH_RECOVER_T, rMsgHdr)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucNetTypeIndex) == ++ OFFSET_OF(MSG_CH_RECOVER_T, ucNetTypeIndex)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucTokenID) == OFFSET_OF(MSG_CH_RECOVER_T, ucTokenID)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucPrimaryChannel) == ++ OFFSET_OF(MSG_CH_RECOVER_T, ucPrimaryChannel)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfSco) == OFFSET_OF(MSG_CH_RECOVER_T, eRfSco)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfBand) == OFFSET_OF(MSG_CH_RECOVER_T, eRfBand)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eReqType) == OFFSET_OF(MSG_CH_RECOVER_T, eReqType)); ++ ++} ++#endif /* _lint */ ++ ++#endif /* _CNM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h +new file mode 100644 +index 000000000000..c8f25b1b29a9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h +@@ -0,0 +1,1164 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_mem.h#1 ++*/ ++ ++/*! \file "cnm_mem.h" ++ \brief In this file we define the structure of the control unit of ++ packet buffer and MGT/MSG Memory Buffer. ++*/ ++ ++/* ++** Log: cnm_mem.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Resize the Secondary Device Type array when WiFi Direct is enabled. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add per STA flow control when STA is in PS mode ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 12 2010 cp.wu ++ * ++ * SAA will take a record for tracking request sequence number. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error for P2P related defination. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related fields. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [BORA00000678] [MT6620]WiFi LP integration ++ * 1. add u8TimeStamp in MSDU_INFO ++ * 2. move fgIsRxTSFUpdated/fgIsTxTSFUpdated from static to BSS_INFO ++ * 3. add new member for supporting PM in STA_RECORD, which is for AP PS mode ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support checking of duplicated buffer free ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 19 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fixed MAC RX Desc be overwritten issue ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 10 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support Rx header translation for A-MSDU subframe ++ * ++ * 05 07 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * add more sanity check about setting timer ++ * ++ * 04 29 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * modify the compiling flag for RAM usage ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Modified some MQM-related data structures (SN counter, TX/RX BA table) ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Added new TX/RX BA tables in STA_REC ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 09 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * [BORA00000644] WiFi phase 4 integration ++ * Added per-TID SN cache in STA_REC ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support power control ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 11 2010 yuche.tsai ++ * [BORA00000343][MT6620] Emulation For TX ++ * . ++ * ++ * 03 05 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove Emulation definition ++ * ++ * 03 04 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * eliminate HIF_EMULATION in cnm_mem.h ++ * ++ * 03 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add cnmStaRecChangeState() declaration. ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning for some emulation flags ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * To store field AMPDU Parameters in STA_REC ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsWmmSupported in STA_RECORD_T. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsUapsdSupported in STA_RECORD_T ++ * ++ * 02 13 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added arTspecTable in STA_REC for TSPEC management ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable mgmt buffer debug by default ++ * ++ * 02 12 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added BUFFER_SOURCE_BCN ++ * ++ * 02 10 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Renamed MSDU_INFO.ucFixedRateIndex as MSDU_INFO.ucFixedRateCode ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 02 02 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added SN info in MSDU_INFO_T ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h ++ * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem ++ * 3) use cnmMemAlloc() instead to allocate SRAM buffer ++ * ++ * 12 31 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) surpress debug message emitted from hal_hif.c ++ * 2) add two set of field for recording buffer process time ++ * ++ * 12 31 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1. move wifi task initialization from wifi_task.c(rom) to wifi_init.c (TCM) for integrating F/W download later ++ * * * * * 2. WIFI_Event_Dispatcher() prototype changed to return to suspend mode from normal operation mode ++ * * * * * 2. HIF emulation logic revised ++ * ++ * 12 29 2009 yuche.tsai ++ * [BORA00000343][MT6620] Emulation For TX ++ * .Using global buffer declaring by SD1 instead of using another one. ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * MQM: BA handling ++ * * TXM: Macros updates ++ * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 24 2009 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 23 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * allocating SRAM for emulation purpose by ruducing MEM_BANK3_BUF_SZ ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove individual DATA_BUF_BLOCK_NUM definition for emulation compiling flagsu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support several data buffer banks. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * .For new FPGA memory size ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 17 2009 george.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 17 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Modified the DATA_BLOCK_SIZE from 1620 to 2048 ++ * ++ * Dec 16 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_SEC_EMULATION flag ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add HT cap to sta record ++ * ++ * Dec 9 2009 mtk02752 ++ * [BORA00000368] Integrate HIF part into BORA ++ * add cnmDataPktFree() for emulation loopback purpose ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the buffer for key handshake 1x and cmd key order issue ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * move the tx call back function proto type to typedef.h ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add cnmGetStaRecByAddress() and modify variable in STA_RECORD_T ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the port block flag ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add variables to STA_RECORD_T for assoc/auth ++ * ++ * Nov 23 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed the value of STA_WAIT_QUEUE_NUM (from 7 to 5) ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed u2FrameLength from SW_RFB ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed indenting ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Updated MSDU_INFO and SW_RFB ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * update the variable for security ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove the variable to make the compiler ok ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the variable for security module ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo in define of MSG_BUF_BLOCK_SIZE ++ * ++ * Nov 13 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Let typedef STA_REC_T precede typedef MSDU_INFO_T and SW_RFB_T ++ * ++ * Nov 13 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Modified MSDU_INFO and STA_REC for TXM and MQM ++ * ++ * Nov 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename STA_REC_T to STA_RECORD_T and add ucIndex member ++ * ++ * Nov 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Make sure ucBufferSource the same offset in MSDU_INFO and SW_RFB ++ * ++ * Nov 6 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Nov 5 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comment ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add draft content of MSDU_INFO_T and SW_RFB_T ++ * ++ * Oct 30 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 21 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_RX_EMULATION flag ++ * ++ * Oct 20 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 9 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added field ucTC to MSDU_INFO_T and field pucHifRxPacket to SW_RFB_T ++ * ++ * Oct 8 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_MEM_H ++#define _CNM_MEM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#ifndef POWER_OF_2 ++#define POWER_OF_2(n) BIT(n) ++#endif ++ ++/* Size of a basic management buffer block in power of 2 */ ++#define MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2 7 /* 7 to the power of 2 = 128 */ ++#define MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2 5 /* 5 to the power of 2 = 32 */ ++ ++/* Size of a basic management buffer block */ ++#define MGT_BUF_BLOCK_SIZE POWER_OF_2(MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++#define MSG_BUF_BLOCK_SIZE POWER_OF_2(MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++ ++/* Total size of (n) basic management buffer blocks */ ++#define MGT_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++#define MSG_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++ ++/* Number of management buffer block */ ++#define MAX_NUM_OF_BUF_BLOCKS 32 /* Range: 1~32 */ ++ ++/* Size of overall management frame buffer */ ++#define MGT_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MGT_BUF_BLOCK_SIZE) ++#define MSG_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MSG_BUF_BLOCK_SIZE) ++ ++/* STA_REC related definitions */ ++#define STA_REC_INDEX_BMCAST 0xFF ++#define STA_REC_INDEX_NOT_FOUND 0xFE ++#define STA_WAIT_QUEUE_NUM 5 /* Number of SW queues in each STA_REC: AC0~AC4 */ ++#define SC_CACHE_INDEX_NUM 5 /* Number of SC caches in each STA_REC: AC0~AC4 */ ++ ++/* P2P related definitions */ ++#ifdef CFG_ENABLE_WIFI_DIRECT ++/* Moved from p2p_fsm.h */ ++#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ ++#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if ((MAX_NUM_OF_BUF_BLOCKS > 32) || (MAX_NUM_OF_BUF_BLOCKS <= 0)) ++#error > #define MAX_NUM_OF_MGT_BUF_BLOCKS : Out of boundary ! ++#elif MAX_NUM_OF_BUF_BLOCKS > 16 ++typedef UINT_32 BUF_BITMAP; ++#elif MAX_NUM_OF_BUF_BLOCKS > 8 ++typedef UINT_16 BUF_BITMAP; ++#else ++typedef UINT_8 BUF_BITMAP; ++#endif /* MAX_NUM_OF_MGT_BUF_BLOCKS */ ++ ++/* Control variable of TX management memory pool */ ++typedef struct _BUF_INFO_T { ++ PUINT_8 pucBuf; ++ ++#if CFG_DBG_MGT_BUF ++ UINT_32 u4AllocCount; ++ UINT_32 u4FreeCount; ++ UINT_32 u4AllocNullCount; ++#endif /* CFG_DBG_MGT_BUF */ ++ ++ BUF_BITMAP rFreeBlocksBitmap; ++ UINT_8 aucAllocatedBlockNum[MAX_NUM_OF_BUF_BLOCKS]; ++} BUF_INFO_T, *P_BUF_INFO_T; ++ ++/* Wi-Fi divides RAM into three types ++ * MSG: Mailbox message (Small size) ++ * BUF: HW DMA buffers (HIF/MAC) ++ */ ++typedef enum _ENUM_RAM_TYPE_T { ++ RAM_TYPE_MSG = 0, ++ RAM_TYPE_BUF ++} ENUM_RAM_TYPE_T, P_ENUM_RAM_TYPE_T; ++ ++typedef enum _ENUM_BUFFER_SOURCE_T { ++ BUFFER_SOURCE_HIF_TX0 = 0, ++ BUFFER_SOURCE_HIF_TX1, ++ BUFFER_SOURCE_MAC_RX, ++ BUFFER_SOURCE_MNG, ++ BUFFER_SOURCE_BCN, ++ BUFFER_SOURCE_NUM ++} ENUM_BUFFER_SOURCE_T, *P_ENUM_BUFFER_SOURCE_T; ++ ++typedef enum _ENUM_SEC_STATE_T { ++ SEC_STATE_INIT, ++ SEC_STATE_INITIATOR_PORT_BLOCKED, ++ SEC_STATE_RESPONDER_PORT_BLOCKED, ++ SEC_STATE_CHECK_OK, ++ SEC_STATE_SEND_EAPOL, ++ SEC_STATE_SEND_DEAUTH, ++ SEC_STATE_COUNTERMEASURE, ++ SEC_STATE_NUM ++} ENUM_SEC_STATE_T; ++ ++typedef struct _TSPEC_ENTRY_T { ++ UINT_8 ucStatus; ++ UINT_8 ucToken; /* Dialog Token in ADDTS_REQ or ADDTS_RSP */ ++ UINT_16 u2MediumTime; ++ UINT_32 u4TsInfo; ++ /* PARAM_QOS_TS_INFO rParamTsInfo; */ ++ /* Add other retained QoS parameters below */ ++} TSPEC_ENTRY_T, *P_TSPEC_ENTRY_T, TSPEC_TABLE_ENTRY_T, *P_TSPEC_TABLE_ENTRY_T; ++ ++typedef struct _SEC_INFO_T { ++ ++ ENUM_SEC_STATE_T ePreviousState; ++ ENUM_SEC_STATE_T eCurrentState; ++ ++ BOOLEAN fg2nd1xSend; ++ BOOLEAN fgKeyStored; ++ ++ UINT_8 aucStoredKey[64]; ++ ++ BOOLEAN fgAllowOnly1x; ++} SEC_INFO_T, *P_SEC_INFO_T; ++ ++#define MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS 3 ++ ++#define UPDATE_BSS_RSSI_INTERVAL_SEC 3 /* Seconds */ ++ ++/* Fragment information structure */ ++typedef struct _FRAG_INFO_T { ++ UINT_16 u2NextFragSeqCtrl; ++ PUINT_8 pucNextFragStart; ++ P_SW_RFB_T pr1stFrag; ++ OS_SYSTIME rReceiveLifetimeLimit; /* The receive time of 1st fragment */ ++} FRAG_INFO_T, *P_FRAG_INFO_T; ++ ++typedef struct _STAT_CNT_INFO_FW_T { ++ UINT32 u4NumOfTx; /* number of packets sent from host */ ++ UINT32 u4NumOfTxOK; /* number of packets sent to air OK */ ++ UINT32 u4NumOfTxRetry; /* number of packets sent to air RETRY */ ++ UINT32 u4TxDoneAirTimeMax; /* maximum tx done air time */ ++ ++ UINT32 u4NumOfPtiRspTxOk; /* number of PTI RSP sent to air OK */ ++ UINT32 u4NumOfPtiRspTxErr; /* number of PTI RSP sent to air ERROR */ ++ ++ UINT32 u4NumOfTxErr; /* number of packets sent to air ERROR */ ++ ++ UINT32 u4NumOfRx; /* number of received packets */ ++ UINT32 u4NumOfPtiRspRx; /* number of PTI RSP rcv */ ++ ++#define STAT_CNT_INFO_TX_ERR_FLUSHED 0x00000001 ++#define STAT_CNT_INFO_TX_ERR_AGE_TIMEOUT 0x00000002 ++#define STAT_CNT_INFO_TX_ERR_MPDU 0x00000004 ++#define STAT_CNT_INFO_TX_ERR_RTS 0x00000010 ++#define STAT_CNT_INFO_TX_ERR_LIFETIME 0x00000020 ++#define STAT_CNT_INFO_TX_ERR_UNKNOWN 0x80000000 ++ UINT32 u4TxErrBitmap; /* TX error type */ ++ ++#define STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM 10 /* TX OK history */ ++ UINT8 aucTxRateOkHis[STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM][2]; ++ UINT32 u4TxRateOkHisId; ++ ++#define STAT_CNT_INFO_MAX_RATE_ID (32) /* MCS0 ~ MCS31 */ ++ UINT32 aucTxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; ++ UINT32 aucRxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; ++ ++ UINT8 aucStateHis[100][3]; /* State history */ ++ UINT32 u4StateHisId; /* history ID */ ++} STAT_CNT_INFO_FW_T; ++ ++typedef struct _STAT_CNT_INFO_DRV_T { ++ ++ UINT32 u4NumOfTxFromOs; /* number of packets sent from OS */ ++ UINT32 u4NumOfTxQueFull; /* number of packets dropped due to queue full */ ++ UINT32 u4NumOfTxToFw; /* number of packets sent to firmware */ ++ ++ STAT_CNT_INFO_FW_T rFw; ++} STAT_CNT_INFO_DRV_T; ++ ++/* Define STA record structure */ ++struct _STA_RECORD_T { ++ LINK_ENTRY_T rLinkEntry; ++ UINT_8 ucIndex; /* Not modify it except initializing */ ++ ++ BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; /* MAC address */ ++ ++ /* SAA/AAA */ ++ ENUM_AA_STATE_T eAuthAssocState; /* Store STATE Value used in SAA/AAA */ ++ UINT_8 ucAuthAssocReqSeqNum; ++ ++ ENUM_STA_TYPE_T eStaType; /* Indicate the role of this STA in ++ * the network (for example, P2P GO) ++ */ ++ ++ UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ ++ ++ UINT_8 ucStaState; /* STATE_1,2,3 */ ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer ++ * (may deduced from received BSS_DESC_T) ++ */ ++ UINT_8 ucDesiredPhyTypeSet; /* The match result by AND operation of peer's ++ * PhyTypeSet and ours. ++ */ ++ BOOLEAN fgHasBasicPhyType; /* A flag to indicate a Basic Phy Type which ++ * is used to generate some Phy Attribute IE ++ * (e.g. capability, MIB) during association. ++ */ ++ UINT_8 ucNonHTBasicPhyType; /* The Basic Phy Type chosen among the ++ * ucDesiredPhyTypeSet. ++ */ ++ ++ UINT_16 u2CapInfo; /* For Infra Mode, to store Capability Info. from Association Resp(SAA). ++ * For AP Mode, to store Capability Info. from Association Req(AAA). ++ */ ++ UINT_16 u2AssocId; /* For Infra Mode, to store AID from Association Resp(SAA). ++ * For AP Mode, to store the Assigned AID(AAA). ++ */ ++ ++ UINT_16 u2ListenInterval; /* Listen Interval from STA(AAA) */ ++ ++ UINT_16 u2DesiredNonHTRateSet; /* Our Current Desired Rate Set after ++ * match with STA's Operational Rate Set ++ */ ++ ++ UINT_16 u2OperationalRateSet; /* Operational Rate Set of peer BSS */ ++ UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of peer BSS */ ++ ++ BOOLEAN fgIsMerging; /* For IBSS Mode, to indicate that Merge is ongoing */ ++ ++ BOOLEAN fgDiagnoseConnection; /* For Infra/AP Mode, to diagnose the Connection with ++ * this peer by sending ProbeReq/Null frame */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* 802.11n HT capabilities when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) is true */ ++ /* They have the same definition with fields of information element */ ++ /*------------------------------------------------------------------------------------------*/ ++ UINT_8 ucMcsSet; /* MCS0~7 rate set of peer BSS */ ++ BOOLEAN fgSupMcs32; /* MCS32 is supported by peer BSS */ ++ UINT_16 u2HtCapInfo; /* HT cap info field by HT cap IE */ ++ UINT_8 ucAmpduParam; /* Field A-MPDU Parameters in HT cap IE */ ++ UINT_16 u2HtExtendedCap; /* HT extended cap field by HT cap IE */ ++ UINT_32 u4TxBeamformingCap; /* TX beamforming cap field by HT cap IE */ ++ UINT_8 ucAselCap; /* ASEL cap field by HT cap IE */ ++ ++ UINT_8 ucRCPI; /* RCPI of peer */ ++ ++ UINT_8 ucDTIMPeriod; /* Target BSS's DTIM Period, we use this ++ * value for setup Listen Interval ++ * TODO(Kevin): TBD ++ */ ++ UINT_8 ucAuthAlgNum; /* For Infra/AP Mode, the Auth Algorithm Num used in Authentication(SAA/AAA) */ ++ BOOLEAN fgIsReAssoc; /* For Infra/AP Mode, to indicate ReAssoc Frame was in used(SAA/AAA) */ ++ ++ UINT_8 ucTxAuthAssocRetryCount; /* For Infra Mode, the Retry Count of TX Auth/Assod Frame(SAA) */ ++ UINT_8 ucTxAuthAssocRetryLimit; /* For Infra Mode, the Retry Limit of TX Auth/Assod Frame(SAA) */ ++ ++ UINT_16 u2StatusCode; /* Status of Auth/Assoc Req */ ++ UINT_16 u2ReasonCode; /* Reason that been Deauth/Disassoc */ ++ ++ P_IE_CHALLENGE_TEXT_T prChallengeText; /* Point to an allocated buffer for storing Challenge Text ++ * for Shared Key Authentication ++ */ ++ ++ TIMER_T rTxReqDoneOrRxRespTimer; /* For Infra Mode, a timer used to send a timeout event ++ * while waiting for TX request done or RX response. ++ */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* Power Management related fields (for STA/ AP/ P2P/ BOW power saving mode) */ ++ /*------------------------------------------------------------------------------------------*/ ++ BOOLEAN fgSetPwrMgtBit; /* For Infra Mode, to indicate that outgoing frame need toggle ++ * the Pwr Mgt Bit in its Frame Control Field. ++ */ ++ ++ BOOLEAN fgIsInPS; /* For AP Mode, to indicate the client PS state(PM). ++ * TRUE: In PS Mode; FALSE: In Active Mode. */ ++ ++ BOOLEAN fgIsInPsPollSP; /* For Infra Mode, to indicate we've sent a PS POLL to AP and start ++ * the PS_POLL Service Period(LP) ++ */ ++ ++ BOOLEAN fgIsInTriggerSP; /* For Infra Mode, to indicate we've sent a Trigger Frame to AP and start ++ * the Delivery Service Period(LP) ++ */ ++ ++ UINT_8 ucBmpDeliveryAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ ++ ++ UINT_8 ucBmpTriggerAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ ++ ++ UINT_8 ucUapsdSp; /* Max SP length */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ ++ BOOLEAN fgIsRtsEnabled; ++ ++ OS_SYSTIME rUpdateTime; /* (4) System Timestamp of Successful TX and RX */ ++ ++ OS_SYSTIME rLastJoinTime; /* (4) System Timestamp of latest JOIN process */ ++ ++ UINT_8 ucJoinFailureCount; /* Retry Count of JOIN process */ ++ ++ LINK_T arStaWaitQueue[STA_WAIT_QUEUE_NUM]; /* For TXM to defer pkt forwarding to MAC TX DMA */ ++ ++ UINT_16 au2CachedSeqCtrl[TID_NUM + 1]; /* Duplicate removal for HT STA on a per-TID basis ++ * ("+1" is for MMPDU and non-QoS) ++ */ ++ ++#if 0 ++ /* RXM */ ++ P_RX_BA_ENTRY_T aprRxBaTable[TID_NUM]; ++ ++ /* TXM */ ++ P_TX_BA_ENTRY_T aprTxBaTable[TID_NUM]; ++#endif ++ ++ FRAG_INFO_T rFragInfo[MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS]; ++ ++ SEC_INFO_T rSecInfo; /* The security state machine */ ++ ++ BOOLEAN fgPortBlock; /* The 802.1x Port Control flag */ ++ ++ BOOLEAN fgTransmitKeyExist; /* Unicast key exist for this STA */ ++ ++ UINT_8 ucWTEntry; ++ ++ BOOLEAN fgTxAmpduEn; /* Enable TX AMPDU for this Peer */ ++ BOOLEAN fgRxAmpduEn; /* Enable RX AMPDU for this Peer */ ++ ++ PUINT_8 pucAssocReqIe; ++ UINT_16 u2AssocReqIeLen; ++ /*------------------------------------------------------------------------------------------*/ ++ /* WMM/QoS related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++ BOOLEAN fgIsQoS; /* If the STA is associated as a QSTA or QAP (for TX/RX) */ ++ BOOLEAN fgIsWmmSupported; /* If the peer supports WMM, set to TRUE (for association) */ ++ BOOLEAN fgIsUapsdSupported; /* Set according to the scan result (for association) */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* P2P related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 u2DevNameLen; ++ UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; ++ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ ++ UINT_16 u2ConfigMethods; ++ ++ UINT_8 ucDeviceCap; ++ ++ UINT_8 ucSecondaryDevTypeCount; ++ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; ++ ++ DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT]; ++#endif /* CFG_SUPPORT_P2P */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* QM related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++ ++ UINT_8 ucFreeQuota; /* Per Sta flow controal. Valid when fgIsInPS is TRUE. ++ Change it for per Queue flow control */ ++ /* UINT_8 aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]; */ /* used in future */ ++ UINT_8 ucFreeQuotaForDelivery; ++ UINT_8 ucFreeQuotaForNonDelivery; ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE && CFG_ENABLE_PER_STA_STATISTICS ++ UINT_32 u4TotalTxPktsNumber; ++ UINT_32 u4TotalTxPktsTime; ++ UINT_32 u4TotalTxPktsHifTime; ++ ++ UINT_32 u4MaxTxPktsTime; ++ UINT_32 u4MaxTxPktsHifTime; ++ ++ UINT_32 u4ThresholdCounter; ++ UINT_32 u4EnqeueuCounter; ++ UINT_32 u4DeqeueuCounter; ++ UINT_32 u4PrevIntCount; ++ UINT_32 u4ThisIntCount; ++ UINT_32 u4NoTcResource; ++#endif ++ ++#if 1 ++ /*------------------------------------------------------------------------------------------*/ ++ /* To be removed, this is to make que_mgt compilation success only */ ++ /*------------------------------------------------------------------------------------------*/ ++ /* When this STA_REC is in use, set to TRUE. */ ++ BOOLEAN fgIsValid; ++ ++ /* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ ++ QUE_T arTxQueue[NUM_OF_PER_STA_TX_QUEUES]; ++ ++ /* When this STA is in PS Mode, set to TRUE. */ ++ /* BOOLEAN fgIsPS; */ ++ ++ /* When this STA enters Power-Saving, FW will notify the driver with a Session ID */ ++ UINT_8 ucPsSessionID; ++ ++ BOOLEAN fgIsAp; ++ ++ /* Reorder Parameter reference table */ ++ P_RX_BA_ENTRY_T aprRxReorderParamRefTbl[CFG_RX_MAX_BA_TID_NUM]; ++#endif ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ TIMINGMSMT_PARAM_T rWNMTimingMsmt; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ ++ BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ ++ ++ BOOLEAN flgTdlsIsInitiator; /* TRUE: the peer is the initiator */ ++ IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ ++ BOOLEAN fgTdlsInSecurityMode; /* TRUE: security mode */ ++ PARAM_KEY_T rTdlsKeyTemp; /* temp to queue the key information */ ++ ++#define TDLS_SETUP_TIMEOUT_SEC 5 /* unit: second */ ++ OS_SYSTIME rTdlsSetupStartTime; /* time when link setup is started */ ++ ++ OS_SYSTIME rTdlsTxQuotaEmptyTime; /* time when TX quota is 0 */ ++ ++ STAT_CNT_INFO_DRV_T rTdlsStatistics; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++#define STATS_ENV_TIMEOUT_SEC 10 /* unit: second */ ++ OS_SYSTIME rStatsEnvTxPeriodLastTime; ++ ++#define STATS_ENV_TX_CNT_REPORT_TRIGGER 2500 /* 6Mbps */ ++#define STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC 5 /* unit: second */ ++ OS_SYSTIME rStatsEnvTxLastTime; ++ UINT32 u4StatsEnvTxCnt; ++ ++ UINT32 u4NumOfNoTxQuota; ++ ++ UINT32 u4RxReorderFallAheadCnt; ++ UINT32 u4RxReorderFallBehindCnt; ++ UINT32 u4RxReorderHoleCnt; ++ UINT32 u4RxReorderHoleTimeoutCnt; ++ ++ UINT32 u4StatsRxPassToOsCnt; ++ ++ /* delay from HIF to pass to OS: us */ ++#define STATS_STAY_INT_BYTE_THRESHOLD 500 ++ UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; ++ ++ UINT8 ucStatsGenDisplayCnt; ++#endif /* CFG_SUPPORT_STATISTICS */ ++}; ++ ++#if 0 ++/* use nic_tx.h instead */ ++/* MSDU_INFO and SW_RFB structure */ ++typedef struct _MSDU_INFO_T { ++ ++ /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ ++ ++ LINK_ENTRY_T rLinkEntry; ++ PUINT_8 pucBuffer; /* Pointer to the associated buffer */ ++ ++ UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ ++ UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ ++ UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ ++ UINT_8 ucTID; /* Traffic Identification */ ++ ++ BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ ++ UINT_8 ucMacHeaderLength; ++ UINT_16 u2PayloadLength; ++ PUINT_8 pucMacHeader; /* 802.11 header */ ++ PUINT_8 pucPayload; /* 802.11 payload */ ++ ++ OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ ++ P_STA_RECORD_T prStaRec; ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; ++ UINT_32 rActivityTime[2]; ++#endif ++#if DBG && CFG_BUFFER_FREE_CHK ++ BOOLEAN fgBufferInSource; ++#endif ++ ++ UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ ++ ++ /* 4 -----------------------Non-Common ------------------------- */ ++ /* TODO: move flags to ucControlFlag */ ++ ++ BOOLEAN fgIs1xFrame; /* Set to TRUE for 802.1x frame */ ++ ++ /* TXM: For TX Done handling, callback function & parameter (5) */ ++ BOOLEAN fgIsTxFailed; /* Set to TRUE if transmission failure */ ++ ++ PFN_TX_DONE_HANDLER pfTxDoneHandler; ++ ++ UINT_64 u8TimeStamp; /* record the TX timestamp */ ++ ++ /* TXM: For PS forwarding control (per-STA flow control) */ ++ UINT_8 ucPsForwardingType; /* Delivery-enabled, non-delivery-enabled, non-PS */ ++ UINT_8 ucPsSessionID; /* The Power Save session id for PS forwarding control */ ++ ++ /* TXM: For MAC TX DMA operations */ ++ UINT_8 ucMacTxQueIdx; /* MAC TX queue: AC0-AC6, BCM, or BCN */ ++ BOOLEAN fgNoAck; /* Set to true if Ack is not required for this packet */ ++ BOOLEAN fgBIP; /* Set to true if BIP is used for this packet */ ++ UINT_8 ucFragTotalCount; ++ UINT_8 ucFragFinishedCount; ++ UINT_16 u2FragThreshold; /* Fragmentation threshold without WLAN Header & FCS */ ++ BOOLEAN fgFixedRate; /* If a fixed rate is used, set to TRUE. */ ++ UINT_8 ucFixedRateCode; /* The rate code copied to MAC TX Desc */ ++ UINT_8 ucFixedRateRetryLimit; /* The retry limit when a fixed rate is used */ ++ BOOLEAN fgIsBmcQueueEnd; /* Set to true if this packet is the end of BMC */ ++ ++ /* TXM: For flushing ACL frames */ ++ UINT_16 u2PalLLH; /* 802.11 PAL LLH */ ++ /* UINT_16 u2LLH; */ ++ UINT_16 u2ACLSeq; /* u2LLH+u2ACLSeq for AM HCI flush ACL frame */ ++ ++ /* TXM for retransmitting a flushed packet */ ++ BOOLEAN fgIsSnAssigned; ++ UINT_16 u2SequenceNumber; /* To remember the Sequence Control field of this MPDU */ ++ ++} MSDU_INFO_T, *P_MSDU_INFO_T; ++#endif ++ ++#if 0 ++/* nic_rx.h */ ++typedef struct _SW_RFB_T { ++ ++ /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ ++ ++ LINK_ENTRY_T rLinkEntry; ++ PUINT_8 pucBuffer; /* Pointer to the associated buffer */ ++ ++ UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ ++ UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ ++ UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ ++ UINT_8 ucTID; /* Traffic Identification */ ++ ++ BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ ++ UINT_8 ucMacHeaderLength; ++ UINT_16 u2PayloadLength; ++ PUINT_8 pucMacHeader; /* 802.11 header */ ++ PUINT_8 pucPayload; /* 802.11 payload */ ++ ++ OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ ++ P_STA_RECORD_T prStaRec; ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; ++ UINT_32 rActivityTime[2]; ++#endif ++#if DBG && CFG_BUFFER_FREE_CHK ++ BOOLEAN fgBufferInSource; ++#endif ++ ++ UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ ++ ++ /* 4 -----------------------Non-Common ------------------------- */ ++ ++ /* For composing the HIF RX Header (TODO: move flags to ucControlFlag) */ ++ PUINT_8 pucHifRxPacket; /* Pointer to the Response packet to HIF RX0 or RX1 */ ++ UINT_16 u2HifRxPacketLength; ++ UINT_8 ucHeaderOffset; ++ UINT_8 ucHifRxPortIndex; ++ ++ UINT_16 u2SequenceControl; ++ BOOLEAN fgIsA4Frame; /* (For MAC RX packet parsing) set to TRUE if 4 addresses are present */ ++ BOOLEAN fgIsBAR; ++ BOOLEAN fgIsQoSData; ++ BOOLEAN fgIsAmsduSubframe; /* Set to TRUE for A-MSDU Subframe */ ++ ++ /* For HIF RX DMA Desc */ ++ BOOLEAN fgTUChecksumCheckRequired; ++ BOOLEAN fgIPChecksumCheckRequired; ++ UINT_8 ucEtherTypeOffset; ++ ++} SW_RFB_T, *P_SW_RFB_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++P_MSDU_INFO_T cnmMgtPktAlloc(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); ++ ++VOID cnmMgtPktFree(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID cnmMemInit(IN P_ADAPTER_T prAdapter); ++ ++PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length); ++ ++VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory); ++ ++VOID cnmStaRecInit(IN P_ADAPTER_T prAdapter); ++ ++VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter); ++ ++P_STA_RECORD_T cnmStaRecAlloc(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex); ++ ++VOID cnmStaRecFree(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSyncToChip); ++ ++VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip); ++ ++P_STA_RECORD_T cnmGetStaRecByIndex(IN P_ADAPTER_T prAdapter, IN UINT_8 ucIndex); ++ ++P_STA_RECORD_T cnmGetStaRecByAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex, IN UINT_8 aucPeerMACAddress[]); ++ ++VOID cnmStaRecResetStatus(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++VOID cnmStaRecChangeState(IN P_ADAPTER_T prAdapter, IN OUT P_STA_RECORD_T prStaRec, IN UINT_8 ucNewState); ++ ++P_STA_RECORD_T ++cnmStaTheTypeGet(P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID cnmMemDataTypeCheck(VOID) ++{ ++#if 0 ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == OFFSET_OF(SW_RFB_T, rLinkEntry)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucBuffer) == OFFSET_OF(SW_RFB_T, pucBuffer)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucBufferSource) == OFFSET_OF(SW_RFB_T, ucBufferSource)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucMacHeader) == OFFSET_OF(SW_RFB_T, pucMacHeader)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucMacHeaderLength) == ++ OFFSET_OF(SW_RFB_T, ucMacHeaderLength)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucPayload) == OFFSET_OF(SW_RFB_T, pucPayload)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, u2PayloadLength) == OFFSET_OF(SW_RFB_T, u2PayloadLength)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, prStaRec) == OFFSET_OF(SW_RFB_T, prStaRec)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucNetworkTypeIndex) == ++ OFFSET_OF(SW_RFB_T, ucNetworkTypeIndex)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTID) == OFFSET_OF(SW_RFB_T, ucTID)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgIs802_11Frame) == OFFSET_OF(SW_RFB_T, fgIs802_11Frame)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucControlFlag) == OFFSET_OF(SW_RFB_T, ucControlFlag)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rArrivalTime) == OFFSET_OF(SW_RFB_T, rArrivalTime)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTC) == OFFSET_OF(SW_RFB_T, ucTC)); ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, eActivity[0]) == OFFSET_OF(SW_RFB_T, eActivity[0])); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rActivityTime[0]) == ++ OFFSET_OF(SW_RFB_T, rActivityTime[0])); ++#endif ++ ++#if DBG && CFG_BUFFER_FREE_CHK ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgBufferInSource) == ++ OFFSET_OF(SW_RFB_T, fgBufferInSource)); ++#endif ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(STA_RECORD_T, rLinkEntry) == 0); ++ ++ return; ++#endif ++} ++#endif /* _lint */ ++ ++#endif /* _CNM_MEM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h +new file mode 100644 +index 000000000000..cc5d0fa1adfc +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h +@@ -0,0 +1,169 @@ ++/* ++** Id: @(#) ++*/ ++ ++/*! \file "cnm_scan.h" ++ \brief ++ ++*/ ++ ++/* ++** Log: cnm_scan.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * remove unused definitions. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function prototype of cnmScanInit() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_SCAN_H ++#define _CNM_SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define SCN_CHANNEL_DWELL_TIME_MIN_MSEC 12 ++#define SCN_CHANNEL_DWELL_TIME_EXT_MSEC 98 ++ ++#define SCN_TOTAL_PROBEREQ_NUM_FOR_FULL 3 ++#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_FULL 1 ++ ++#define SCN_TOTAL_PROBEREQ_NUM_FOR_PARTIAL 2 ++#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_PARTIAL 1 ++ ++#define SCN_INTERLACED_CHANNEL_GROUPS_NUM 3 /* Used by partial scan */ ++ ++#define SCN_PARTIAL_SCAN_NUM 3 ++ ++#define SCN_PARTIAL_SCAN_IDLE_MSEC 100 ++ ++#define MAXIMUM_OPERATION_CHANNEL_LIST 46 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* The type of Scan Source */ ++typedef enum _ENUM_SCN_REQ_SOURCE_T { ++ SCN_REQ_SOURCE_HEM = 0, ++ SCN_REQ_SOURCE_NET_FSM, ++ SCN_REQ_SOURCE_ROAMING, /* ROAMING Module is independent of AIS FSM */ ++ SCN_REQ_SOURCE_OBSS, /* 2.4G OBSS scan */ ++ SCN_REQ_SOURCE_NUM ++} ENUM_SCN_REQ_SOURCE_T, *P_ENUM_SCN_REQ_SOURCE_T; ++ ++typedef enum _ENUM_SCAN_PROFILE_T { ++ SCAN_PROFILE_FULL = 0, ++ SCAN_PROFILE_PARTIAL, ++ SCAN_PROFILE_VOIP, ++ SCAN_PROFILE_FULL_2G4, ++ SCAN_PROFILE_NUM ++} ENUM_SCAN_PROFILE_T, *P_ENUM_SCAN_PROFILE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 ++VOID cnmScanInit(VOID); ++ ++VOID cnmScanRunEventScanRequest(IN P_MSG_HDR_T prMsgHdr); ++ ++BOOLEAN cnmScanRunEventScanAbort(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanProfileSelection(VOID); ++ ++VOID cnmScanProcessStart(VOID); ++ ++VOID cnmScanProcessStop(VOID); ++ ++VOID cnmScanRunEventReqAISAbsDone(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanRunEventCancelAISAbsDone(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanPartialScanTimeout(UINT_32 u4Param); ++ ++VOID cnmScanRunEventScnFsmComplete(IN P_MSG_HDR_T prMsgHdr); ++#endif ++ ++#endif /* _CNM_SCAN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h +new file mode 100644 +index 000000000000..a2ed9cd02fed +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h +@@ -0,0 +1,235 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_timer.h#1 ++*/ ++ ++/*! \file cnm_timer.h ++ \brief Declaration of timer obj and related timer macro for setup time out ++ event. ++ ++ In this file we declare the timer object and provide several macro for ++ Protocol functional blocks to setup their own time out event. ++*/ ++ ++/* ++** Log: cnm_timer.h ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Return timer token back to COS when entering wait off state ++ * ++ * 01 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 01 06 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix system time is 32KHz instead of 1ms ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the copy time function ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix LINT warnning ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_TIMER_H ++#define _CNM_TIMER_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#undef MSEC_PER_SEC ++#define MSEC_PER_SEC 1000 ++#undef USEC_PER_MSEC ++#define USEC_PER_MSEC 1000 ++#define USEC_PER_TU 1024 /* microsecond */ ++ ++#define MSEC_PER_MIN (60 * MSEC_PER_SEC) ++ ++#define MGMT_MAX_TIMEOUT_INTERVAL ((UINT_32)0x7fffffff) ++ ++#define WAKE_LOCK_MAX_TIME 5 /* Unit: sec */ ++ ++/* If WAKE_LOCK_MAX_TIME is too large, the whole system may always keep awake ++ * because of periodic timer of OBSS scanning ++ */ ++#if (WAKE_LOCK_MAX_TIME >= OBSS_SCAN_MIN_INTERVAL) ++#error WAKE_LOCK_MAX_TIME is too large ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef VOID(*PFN_MGMT_TIMEOUT_FUNC) (P_ADAPTER_T, ULONG); ++ ++typedef struct _TIMER_T { ++ LINK_ENTRY_T rLinkEntry; ++ OS_SYSTIME rExpiredSysTime; ++ UINT_16 u2Minutes; ++ UINT_16 u2Reserved; ++ ULONG ulData; ++ PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; ++} TIMER_T, *P_TIMER_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Check if time "a" is before time "b" */ ++/* In 32-bit variable, 0x00000001~0x7fffffff -> positive number, ++ * 0x80000000~0xffffffff -> negative number ++ */ ++#define TIME_BEFORE_64bit(a, b) (a < b) ++ ++#define TIME_BEFORE(a, b) ((UINT_32)((UINT_32)(a) - (UINT_32)(b)) > 0x7fffffff) ++ ++/* #define TIME_BEFORE(a,b) ((INT_32)((INT_32)(b) - (INT_32)(a)) > 0) ++ * may cause UNexpect result between Free build and Check build for WinCE ++ */ ++ ++#define TIME_AFTER(a, b) TIME_BEFORE(b, a) ++ ++#define SYSTIME_TO_SEC(_systime) ((_systime) / KAL_HZ) ++#define SEC_TO_SYSTIME(_sec) ((_sec) * KAL_HZ) ++ ++/* The macros to convert second & millisecond */ ++#define MSEC_TO_SEC(_msec) ((_msec) / MSEC_PER_SEC) ++#define SEC_TO_MSEC(_sec) ((UINT_32)(_sec) * MSEC_PER_SEC) ++ ++/* The macros to convert millisecond & microsecond */ ++#define USEC_TO_MSEC(_usec) ((_usec) / USEC_PER_MSEC) ++#define MSEC_TO_USEC(_msec) ((UINT_32)(_msec) * USEC_PER_MSEC) ++ ++/* The macros to convert TU & microsecond, TU & millisecond */ ++#define TU_TO_USEC(_tu) ((_tu) * USEC_PER_TU) ++#define TU_TO_MSEC(_tu) USEC_TO_MSEC(TU_TO_USEC(_tu)) ++ ++/* The macros to convert TU & & OS system time, round up by 0.5 */ ++#define TU_TO_SYSTIME(_tu) MSEC_TO_SYSTIME(TU_TO_MSEC(_tu)) ++#define SYSTIME_TO_TU(_systime) \ ++ ((SYSTIME_TO_USEC(_systime) + ((USEC_PER_TU / 2) - 1)) / USEC_PER_TU) ++ ++/* The macros to convert OS system time & microsecond */ ++#define SYSTIME_TO_USEC(_systime) (SYSTIME_TO_MSEC(_systime) * USEC_PER_MSEC) ++ ++/* The macro to get the current OS system time */ ++#define GET_CURRENT_SYSTIME(_systime_p) {*(_systime_p) = kalGetTimeTick(); } ++ ++/* The macro to copy the system time */ ++#define COPY_SYSTIME(_destTime, _srcTime) {(_destTime) = (_srcTime); } ++ ++/* The macro to get the system time difference between t1 and t2 (t1 - t2) */ ++/* #define GET_SYSTIME_DIFFERENCE(_time1, _time2, _diffTime) \ ++ (_diffTime) = (_time1) - (_time2) */ ++ ++/* The macro to check for the expiration, if TRUE means _currentTime >= _expirationTime */ ++#define CHECK_FOR_EXPIRATION(_currentTime, _expirationTime) \ ++ (((UINT_32)(_currentTime) - (UINT_32)(_expirationTime)) <= 0x7fffffffUL) ++ ++/* The macro to check for the timeout */ ++#define CHECK_FOR_TIMEOUT(_currentTime, _timeoutStartingTime, _timeout) \ ++ CHECK_FOR_EXPIRATION((_currentTime), ((_timeoutStartingTime) + (_timeout))) ++ ++/* The macro to set the expiration time with a specified timeout *//* Watch out for round up. */ ++#define SET_EXPIRATION_TIME(_expirationTime, _timeout) \ ++ { \ ++ GET_CURRENT_SYSTIME(&(_expirationTime)); \ ++ (_expirationTime) += (OS_SYSTIME)(_timeout); \ ++ } ++ ++#define timerRenewTimer(adapter, tmr, interval) \ ++ timerStartTimer(adapter, tmr, interval, (tmr)->function, (tmr)->data) ++ ++#define MGMT_INIT_TIMER(_adapter_p, _timer, _callbackFunc) \ ++ timerInitTimer(_adapter_p, &(_timer), (ULONG)(_callbackFunc)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID ++cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData); ++ ++VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer); ++ ++VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs); ++ ++VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++static inline INT_32 timerPendingTimer(IN P_TIMER_T prTimer) ++{ ++ ASSERT(prTimer); ++ ++ return prTimer->rLinkEntry.prNext != NULL; ++} ++ ++#endif /* _CNM_TIMER_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h +new file mode 100644 +index 000000000000..868de4a6c40a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h +@@ -0,0 +1,446 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/hem_mbox.h#2 ++*/ ++ ++/*! \file hem_mbox.h ++ \brief ++ ++*/ ++ ++/* ++** Log: hem_mbox.h ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for ++ * more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. ++ * cnm_timer[WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add invitation support. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Remove unused message ID ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some message ID for P2P FSM under provisioning phase. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add Message Event ID for P2P Module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * remove unused mailbox message definitions. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * message table should not be commented out by compilation option without modifying header file ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Develop partial DPD code ++ * ++ * 02 11 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added MID_RXM_MQM_QOS_ACTION_FRAME for RXM to indicate QoS Action frames to MQM ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename the parameter of mboxDummy() ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove Dummy MSG ID ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add JOIN REQ related MSG ID ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add AIS ABORT MSG ID ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add SCN MSG IDs ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _HEM_MBOX_H ++#define _HEM_MBOX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Message IDs */ ++typedef enum _ENUM_MSG_ID_T { ++ MID_MNY_CNM_CH_REQ, /* MANY notify CNM to obtain channel privilege */ ++ MID_MNY_CNM_CH_ABORT, /* MANY notify CNM to abort/release channel privilege */ ++ ++ MID_CNM_AIS_CH_GRANT, /* CNM notify AIS for indicating channel granted */ ++ MID_CNM_P2P_CH_GRANT, /* CNM notify P2P for indicating channel granted */ ++ MID_CNM_BOW_CH_GRANT, /* CNM notify BOW for indicating channel granted */ ++ ++ /*--------------------------------------------------*/ ++ /* SCN Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_AIS_SCN_SCAN_REQ, /* AIS notify SCN for starting scan */ ++ MID_AIS_SCN_SCAN_REQ_V2, /* AIS notify SCN for starting scan with multiple SSID support */ ++ MID_AIS_SCN_SCAN_CANCEL, /* AIS notify SCN for cancelling scan */ ++ MID_P2P_SCN_SCAN_REQ, /* P2P notify SCN for starting scan */ ++ MID_P2P_SCN_SCAN_REQ_V2, /* P2P notify SCN for starting scan with multiple SSID support */ ++ MID_P2P_SCN_SCAN_CANCEL, /* P2P notify SCN for cancelling scan */ ++ MID_BOW_SCN_SCAN_REQ, /* BOW notify SCN for starting scan */ ++ MID_BOW_SCN_SCAN_REQ_V2, /* BOW notify SCN for starting scan with multiple SSID support */ ++ MID_BOW_SCN_SCAN_CANCEL, /* BOW notify SCN for cancelling scan */ ++ MID_RLM_SCN_SCAN_REQ, /* RLM notify SCN for starting scan (OBSS-SCAN) */ ++ MID_RLM_SCN_SCAN_REQ_V2, /* RLM notify SCN for starting scan (OBSS-SCAN) with multiple SSID support */ ++ MID_RLM_SCN_SCAN_CANCEL, /* RLM notify SCN for cancelling scan (OBSS-SCAN) */ ++ MID_SCN_AIS_SCAN_DONE, /* SCN notify AIS for scan completion */ ++ MID_SCN_P2P_SCAN_DONE, /* SCN notify P2P for scan completion */ ++ MID_SCN_BOW_SCAN_DONE, /* SCN notify BOW for scan completion */ ++ MID_SCN_RLM_SCAN_DONE, /* SCN notify RLM for scan completion (OBSS-SCAN) */ ++ ++ /*--------------------------------------------------*/ ++ /* AIS Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_OID_AIS_FSM_JOIN_REQ, /* OID/IOCTL notify AIS for join */ ++ MID_OID_AIS_FSM_ABORT, /* OID/IOCTL notify AIS for abort */ ++ MID_AIS_SAA_FSM_START, /* AIS notify SAA for Starting authentication/association fsm */ ++ MID_AIS_SAA_FSM_ABORT, /* AIS notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_AIS_JOIN_COMPLETE, /* SAA notify AIS for indicating join complete */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /*--------------------------------------------------*/ ++ /* BOW Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_BOW_SAA_FSM_START, /* BOW notify SAA for Starting authentication/association fsm */ ++ MID_BOW_SAA_FSM_ABORT, /* BOW notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_BOW_JOIN_COMPLETE, /* SAA notify BOW for indicating join complete */ ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*--------------------------------------------------*/ ++ /* P2P Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_P2P_SAA_FSM_START, /* P2P notify SAA for Starting authentication/association fsm */ ++ MID_P2P_SAA_FSM_ABORT, /* P2P notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_P2P_JOIN_COMPLETE, /* SAA notify P2P for indicating join complete */ ++ ++ MID_MNY_P2P_FUN_SWITCH, /* Enable P2P FSM. */ ++ MID_MNY_P2P_DEVICE_DISCOVERY, /* Start device discovery. */ ++ MID_MNY_P2P_CONNECTION_REQ, /* Connection request. */ ++ MID_MNY_P2P_CONNECTION_ABORT, /* Abort connection request, P2P FSM return to IDLE. */ ++ MID_MNY_P2P_BEACON_UPDATE, ++ MID_MNY_P2P_STOP_AP, ++ MID_MNY_P2P_CHNL_REQ, ++ MID_MNY_P2P_CHNL_ABORT, ++ MID_MNY_P2P_MGMT_TX, ++ MID_MNY_P2P_GROUP_DISSOLVE, ++ MID_MNY_P2P_MGMT_FRAME_REGISTER, ++ MID_MNY_P2P_NET_DEV_REGISTER, ++ MID_MNY_P2P_START_AP, ++ MID_MNY_P2P_MGMT_FRAME_UPDATE, ++ MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, ++#if CFG_SUPPORT_WFD ++ MID_MNY_P2P_WFD_CFG_UPDATE, ++#endif ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ MID_SCN_AIS_FOUND_IBSS, /* SCN notify AIS that an IBSS Peer has been found and can merge into */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ MID_SAA_AIS_FSM_ABORT, /* SAA notify AIS for indicating deauthentication/disassociation */ ++ ++ /*--------------------------------------------------*/ ++ /* AIS MGMT-TX Support */ ++ /*--------------------------------------------------*/ ++ MID_MNY_AIS_REMAIN_ON_CHANNEL, ++ MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, ++ MID_MNY_AIS_MGMT_TX, ++ ++ MID_TOTAL_NUM ++} ENUM_MSG_ID_T, *P_ENUM_MSG_ID_T; ++ ++/* Message header of inter-components */ ++struct _MSG_HDR_T { ++ LINK_ENTRY_T rLinkEntry; ++ ENUM_MSG_ID_T eMsgId; ++}; ++ ++typedef VOID(*PFN_MSG_HNDL_FUNC) (P_ADAPTER_T, P_MSG_HDR_T); ++ ++typedef struct _MSG_HNDL_ENTRY { ++ ENUM_MSG_ID_T eMsgId; ++ PFN_MSG_HNDL_FUNC pfMsgHndl; ++} MSG_HNDL_ENTRY_T, *P_MSG_HNDL_ENTRY_T; ++ ++typedef enum _EUNM_MSG_SEND_METHOD_T { ++ MSG_SEND_METHOD_BUF = 0, /* Message is put in the queue and will be ++ executed when mailbox is checked. */ ++ MSG_SEND_METHOD_UNBUF /* The handler function is called immediately ++ in the same context of the sender */ ++} EUNM_MSG_SEND_METHOD_T, *P_EUNM_MSG_SEND_METHOD_T; ++ ++typedef enum _ENUM_MBOX_ID_T { ++ MBOX_ID_0 = 0, ++ MBOX_ID_TOTAL_NUM ++} ENUM_MBOX_ID_T, *P_ENUM_MBOX_ID_T; ++ ++/* Define Mailbox structure */ ++typedef struct _MBOX_T { ++ LINK_T rLinkHead; ++} MBOX_T, *P_MBOX_T; ++ ++typedef struct _MSG_SAA_FSM_START_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ P_STA_RECORD_T prStaRec; ++} MSG_SAA_FSM_START_T, *P_MSG_SAA_FSM_START_T; ++ ++typedef struct _MSG_SAA_FSM_COMP_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ WLAN_STATUS rJoinStatus; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prSwRfb; ++} MSG_SAA_FSM_COMP_T, *P_MSG_SAA_FSM_COMP_T; ++ ++typedef struct _MSG_SAA_FSM_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ P_STA_RECORD_T prStaRec; ++} MSG_SAA_FSM_ABORT_T, *P_MSG_SAA_FSM_ABORT_T; ++ ++typedef struct _MSG_CONNECTION_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++} MSG_CONNECTION_ABORT_T, *P_MSG_CONNECTION_ABORT_T; ++ ++typedef struct _MSG_REMAIN_ON_CHANNEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eSco; ++ UINT_8 ucChannelNum; ++ UINT_32 u4DurationMs; ++ UINT_64 u8Cookie; ++} MSG_REMAIN_ON_CHANNEL_T, *P_MSG_REMAIN_ON_CHANNEL_T; ++ ++typedef struct _MSG_CANCEL_REMAIN_ON_CHANNEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++} MSG_CANCEL_REMAIN_ON_CHANNEL_T, *P_MSG_CANCEL_REMAIN_ON_CHANNEL_T; ++ ++typedef struct _MSG_MGMT_TX_REQUEST_T { ++ MSG_HDR_T rMsgHdr; ++ P_MSDU_INFO_T prMgmtMsduInfo; ++ UINT_64 u8Cookie; /* For indication. */ ++ BOOLEAN fgNoneCckRate; ++ BOOLEAN fgIsWaitRsp; ++} MSG_MGMT_TX_REQUEST_T, *P_MSG_MGMT_TX_REQUEST_T; ++ ++/* specific message data types */ ++typedef MSG_SAA_FSM_START_T MSG_JOIN_REQ_T, *P_MSG_JOIN_REQ_T; ++typedef MSG_SAA_FSM_COMP_T MSG_JOIN_COMP_T, *P_MSG_JOIN_COMP_T; ++typedef MSG_SAA_FSM_ABORT_T MSG_JOIN_ABORT_T, *P_MSG_JOIN_ABORT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); ++ ++VOID ++mboxSendMsg(IN P_ADAPTER_T prAdapter, ++ IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod); ++ ++VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); ++ ++VOID mboxInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID mboxDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID mboxDummy(IN P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _HEM_MBOX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h +new file mode 100644 +index 000000000000..88b99222133f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h +@@ -0,0 +1,148 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/include/mgmt/hs20.h#2 ++*/ ++ ++/*! \file hs20.h ++ \brief This file contains the function declaration for hs20.c. ++*/ ++ ++/* ++** Log: ++ * ++ */ ++ ++#ifndef _HS20_H ++#define _HS20_H ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BSSID_POOL_MAX_SIZE 8 ++#define HS20_SIGMA_SCAN_RESULT_TIMEOUT 30 /* sec */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++/*For GTK Frame Filter*/ ++typedef struct _IPV4_NETWORK_ADDRESS_LIST { ++ UINT_8 ucAddrCount; ++ IPV4_NETWORK_ADDRESS arNetAddr[1]; ++} IPV4_NETWORK_ADDRESS_LIST, *P_IPV4_NETWORK_ADDRESS_LIST; ++#endif ++ ++/* Entry of BSSID Pool - For SIGMA Test */ ++typedef struct _BSSID_ENTRY_T { ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++} BSSID_ENTRY_T, P_HS20_BSSID_POOL_ENTRY_T; ++ ++struct _HS20_INFO_T { ++ ++ /*Hotspot 2.0 Information */ ++ UINT_8 aucHESSID[MAC_ADDR_LEN]; ++ UINT_8 ucAccessNetworkOptions; ++ UINT_8 ucVenueGroup; /* VenueInfo - Group */ ++ UINT_8 ucVenueType; ++ UINT_8 ucHotspotConfig; ++ ++ /*Roaming Consortium Information */ ++ /* PARAM_HS20_ROAMING_CONSORTIUM_INFO rRCInfo; */ ++ ++ /*Hotspot 2.0 dummy AP Info */ ++ ++ /*Time Advertisement Information */ ++ /* UINT_32 u4UTCOffsetTime; */ ++ /* UINT_8 aucTimeZone[ELEM_MAX_LEN_TIME_ZONE]; */ ++ /* UINT_8 ucLenTimeZone; */ ++ ++ /* For SIGMA Test */ ++ /* BSSID Pool */ ++ BSSID_ENTRY_T arBssidPool[BSSID_POOL_MAX_SIZE]; ++ UINT_8 ucNumBssidPoolEntry; ++ BOOLEAN fgIsHS2SigmaMode; ++ ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*For GTK Frame Filter*/ ++#if DBG ++#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ ++ { \ ++ UINT_32 u4Size = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + \ ++ (((_prAddrList)->ucAddrCount) * sizeof(IPV4_NETWORK_ADDRESS)); \ ++ kalMemFree((_prAddrList), VIR_MEM_TYPE, u4Size); \ ++ (_prAddrList) = NULL; \ ++ } ++#else ++#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ ++ { \ ++ kalMemFree((_prAddrList), VIR_MEM_TYPE, 0); \ ++ (_prAddrList) = NULL; \ ++ } ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); ++ ++VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); ++ ++UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID); ++ ++WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE); ++ ++BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); ++ ++BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); ++#endif ++ ++BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); ++ ++BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); ++ ++#endif ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h +new file mode 100644 +index 000000000000..cb89fd8793ee +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h +@@ -0,0 +1,153 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/mib.h#1 ++*/ ++ ++/*! \file mib.h ++ \brief This file contains the IEEE 802.11 family related MIB definition ++ for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: mib.h ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _MIB_H ++#define _MIB_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Entry in SMT AuthenticationAlgorithms Table: dot11AuthenticationAlgorithmsEntry */ ++typedef struct _DOT11_AUTHENTICATION_ALGORITHMS_ENTRY { ++ BOOLEAN dot11AuthenticationAlgorithmsEnable; /* dot11AuthenticationAlgorithmsEntry 3 */ ++} DOT11_AUTHENTICATION_ALGORITHMS_ENTRY, *P_DOT11_AUTHENTICATION_ALGORITHMS_ENTRY; ++ ++/* Entry in SMT dot11RSNAConfigPairwiseCiphersTalbe Table: dot11RSNAConfigPairwiseCiphersEntry */ ++typedef struct _DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY { ++ UINT_32 dot11RSNAConfigPairwiseCipher; /* dot11RSNAConfigPairwiseCiphersEntry 2 */ ++ BOOLEAN dot11RSNAConfigPairwiseCipherEnabled; /* dot11RSNAConfigPairwiseCiphersEntry 3 */ ++} DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY, *P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY; ++ ++/* Entry in SMT dot11RSNAConfigAuthenticationSuitesTalbe Table: dot11RSNAConfigAuthenticationSuitesEntry */ ++typedef struct _DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY { ++ UINT_32 dot11RSNAConfigAuthenticationSuite; /* dot11RSNAConfigAuthenticationSuitesEntry 2 */ ++ BOOLEAN dot11RSNAConfigAuthenticationSuiteEnabled; /* dot11RSNAConfigAuthenticationSuitesEntry 3 */ ++} DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY, *P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY; ++ ++/* ----- IEEE 802.11 MIB Major sections ----- */ ++typedef struct _IEEE_802_11_MIB_T { ++ /* dot11PrivacyTable (dot11smt 5) */ ++ UINT_8 dot11WEPDefaultKeyID; /* dot11PrivacyEntry 2 */ ++ BOOLEAN dot11TranmitKeyAvailable; ++ UINT_32 dot11WEPICVErrorCount; /* dot11PrivacyEntry 5 */ ++ UINT_32 dot11WEPExcludedCount; /* dot11PrivacyEntry 6 */ ++ ++ /* dot11RSNAConfigTable (dot11smt 8) */ ++ UINT_32 dot11RSNAConfigGroupCipher; /* dot11RSNAConfigEntry 4 */ ++ ++ /* dot11RSNAConfigPairwiseCiphersTable (dot11smt 9) */ ++ DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY dot11RSNAConfigPairwiseCiphersTable[MAX_NUM_SUPPORTED_CIPHER_SUITES]; ++ ++ /* dot11RSNAConfigAuthenticationSuitesTable (dot11smt 10) */ ++ DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY ++ dot11RSNAConfigAuthenticationSuitesTable[MAX_NUM_SUPPORTED_AKM_SUITES]; ++ ++#if 0 /* SUPPORT_WAPI */ ++ BOOLEAN fgWapiKeyInstalled; ++ PARAM_WPI_KEY_T rWapiPairwiseKey[2]; ++ BOOLEAN fgPairwiseKeyUsed[2]; ++ UINT_8 ucWpiActivedPWKey; /* Must be 0 or 1, by wapi spec */ ++ PARAM_WPI_KEY_T rWapiGroupKey[2]; ++ BOOLEAN fgGroupKeyUsed[2]; ++#endif ++} IEEE_802_11_MIB_T, *P_IEEE_802_11_MIB_T; ++ ++/* ------------------ IEEE 802.11 non HT PHY characteristics ---------------- */ ++typedef const struct _NON_HT_PHY_ATTRIBUTE_T { ++ UINT_16 u2SupportedRateSet; ++ ++ BOOLEAN fgIsShortPreambleOptionImplemented; ++ ++ BOOLEAN fgIsShortSlotTimeOptionImplemented; ++ ++} NON_HT_PHY_ATTRIBUTE_T, *P_NON_HT_PHY_ATTRIBUTE_T; ++ ++typedef const struct _NON_HT_ADHOC_MODE_ATTRIBUTE_T { ++ ++ ENUM_PHY_TYPE_INDEX_T ePhyTypeIndex; ++ ++ UINT_16 u2BSSBasicRateSet; ++ ++} NON_HT_ADHOC_MODE_ATTRIBUTE_T, *P_NON_HT_ADHOC_MODE_ATTRIBUTE_T; ++ ++typedef NON_HT_ADHOC_MODE_ATTRIBUTE_T NON_HT_AP_MODE_ATTRIBUTE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[]; ++extern NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[]; ++extern NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[]; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MIB_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h +new file mode 100644 +index 000000000000..11145c31dbfa +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h +@@ -0,0 +1,55 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_assoc.h#1 ++*/ ++ ++/*! \file p2p_assoc.h ++ \brief This file contains the Wi-Fi Direct ASSOC REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++#ifndef _P2P_ASSOC_H ++#define _P2P_ASSOC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h +new file mode 100644 +index 000000000000..869d7bf0ee61 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h +@@ -0,0 +1,56 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_bss.h#2 ++*/ ++ ++/*! \file "p2p_bss.h" ++ \brief In this file we define the function prototype used in p2p BSS/IBSS. ++ ++ The file contains the function declarations and defines for used in BSS/IBSS. ++*/ ++ ++#ifndef _P2P_BSS_H ++#define _P2P_BSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++UINT_32 p2pGetTxProbRspIeTableSize(VOID); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h +new file mode 100644 +index 000000000000..2541e1d2883e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h +@@ -0,0 +1,2190 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_fsm.h#23 ++*/ ++ ++/*! \file p2p_fsm.h ++ \brief Declaration of functions and finite state machine for P2P Module. ++ ++ Declaration of functions and finite state machine for P2P Module. ++*/ ++ ++/* ++** Log: p2p_fsm.h ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix compile error. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 18 2012 yuche.tsai ++ * NULL ++ * add one file. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve class 3 error issue under AP mode. ++ * ++ * data frame may TX before Assoc Response TX. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix default device name issue. ++ * ++ * 11 09 2011 yuche.tsai ++ * [WCXRP00001093] [Need Patch][Volunteer Patch] Service Discovery 2.0 state transition issue. ++ * Fix SD2.0 issue which may cause KE. (Monkey test) ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version ++ * query & set support for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 09 01 2011 yuche.tsai ++ * NULL ++ * Fix channel stay interval. ++ * Sync channel stay interval & channel request interval under AP mode.. ++ * ++ * 08 30 2011 yuche.tsai ++ * [WCXRP00000953] [Volunteer Patch][Driver] Hot Spot Channel ASSERT issue. ++ * Fix hot spot FW assert issue when under concurrent case. (DBG enable only) ++ * ++ * 08 16 2011 cp.wu ++ * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence ++ * auto channel decision for 2.4GHz hot spot mode ++ * ++ * 08 16 2011 yuche.tsai ++ * NULL ++ * Fix scan policy for Active LISTEN scan. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, ++ * TX deauth to a disconnecting device issue. ++ * Support TX Deauth Issue. ++ * ++ * 07 26 2011 yuche.tsai ++ * [WCXRP00000875] [Volunteer Patch][WiFi Direct][Driver] MT6620 IOT issue with realtek test bed solution. ++ * Turn off persistent group support for V2.0 release. ++ * ++ * 07 18 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Fix compile error. ++ * ++ * 07 18 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Fix MT6620 WiFi Direct IOT Issue with BCM solution. ++ * ++ * 07 11 2011 yuche.tsai ++ * [WCXRP00000845] [Volunteer Patch][WiFi Direct] WiFi Direct Device Connection Robustness ++ * Enhance Connection Robustness. ++ * ++ * 07 08 2011 yuche.tsai ++ * [WCXRP00000841] [Volunteer Patch][WiFi Direct] Group Owner Setting. ++ * Update GO configure parameter. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Disable enhancement II for debugging. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Refine compile flag. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix connection indication twice issue. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 05 04 2011 yuche.tsai ++ * NULL ++ * Support partial persistent group function. ++ * ++ * 04 20 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1.Shorten the LISTEN interval. ++ * 2. Fix IF address issue when we are GO ++ * 3. Fix LISTEN channel issue. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Change P2P Connection Request Flow. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 07 2011 yuche.tsai ++ * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the ioctl setting that index not map to spec defined config method. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC IE BE format issue. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 11 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add two function prototype. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Support Disassoc & Deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++ ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++ ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 25 2011 terry.wu ++ * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter ++ * Add a new module parameter to indicate current runnig mode, P2P or AP. ++ * ++ * 01 19 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Null NOA attribute setting when no related parameters. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify some behavior of AP mode. ++ * ++ * 12 22 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Compile Error. ++ * ++ * 12 15 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Refine Connection Flow. ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. ++ * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client ++ * by checking the P2P IE in assoc req frame. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation & Provision Discovery. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ ++ * ++ * 11 29 2010 yuche.tsai ++ * NULL ++ * Update P2P related function for INVITATION & PROVISION DISCOVERY. ++ * ++ * 11 26 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Update P2P PS for NOA function. ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update Code for Invitation Related Function. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] ++ * Set the Tx lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at WinXP. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add connection abort message event prototype. ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix P2P Intended Interface Address Bug. ++ * Extend GO Nego Timeout Time. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Extend Listen Interval default value & remove deprecated variable. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add function prototype for join complete. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some function proto type for P2P FSM under provisioning phase.. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Change P2P data structure for supporting ++ * 1. P2P Device discovery. ++ * 2. P2P Group Negotiation. ++ * 3. P2P JOIN ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Update P2P FSM header file. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * P2P/RSN/WAPI IEs need to be declared with compact structure. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Update P2P FSM header file. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix some P2P function prototype. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename CFG flag for P2P ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify parameter of p2pStartGO ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add Wi-Fi Direct SSID and P2P GO Test Mode ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++#ifndef _P2P_FSM_H ++#define _P2P_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CID52_53_54 0 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_P2P_STATE_T { ++ P2P_STATE_IDLE = 0, ++ P2P_STATE_SCAN, ++ P2P_STATE_AP_CHANNEL_DETECT, ++ P2P_STATE_REQING_CHANNEL, ++ P2P_STATE_CHNL_ON_HAND, /* Requesting Channel to Send Specific Frame. */ ++ P2P_STATE_GC_JOIN, /* Sending Specific Frame. May extending channel by other event. */ ++ P2P_STATE_NUM ++} ENUM_P2P_STATE_T, *P_ENUM_P2P_STATE_T; ++ ++enum _ENUM_P2P_DEV_EXT_LISTEN_T { ++ P2P_DEV_NOT_EXT_LISTEN, ++ P2P_DEV_EXT_LISTEN_ING, ++ P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT, ++ P2P_DEV_EXT_LISTEN_NUM ++}; ++ ++typedef enum _ENUM_CHANNEL_REQ_TYPE_T { ++ CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL, ++ CHANNEL_REQ_TYPE_GC_JOIN_REQ, ++ CHANNEL_REQ_TYPE_GO_START_BSS ++} ENUM_CHANNEL_REQ_TYPE_T, *P_ENUM_CHANNEL_REQ_TYPE_T; ++ ++typedef enum _ENUM_BUFFER_TYPE_T { ++ ENUM_FRAME_TYPE_EXTRA_IE_BEACON, ++ ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP, ++ ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP, ++ ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE, ++ ENUM_FRAME_TYPE_BEACON_TEMPLATE, ++ ENUM_FRAME_IE_NUM ++} ENUM_BUFFER_TYPE_T, *P_ENUM_BUFFER_TYPE_T; ++ ++typedef enum _ENUM_HIDDEN_SSID_TYPE_T { ++ ENUM_HIDDEN_SSID_NONE, ++ ENUM_HIDDEN_SSID_LEN, ++ ENUM_HIDDEN_SSID_ZERO_CONTENT, ++ ENUM_HIDDEN_SSID_NUM ++} ENUM_HIDDEN_SSID_TYPE_T, *P_ENUM_HIDDEN_SSID_TYPE_T; ++ ++typedef struct _P2P_SSID_STRUCT_T { ++ UINT_8 aucSsid[32]; ++ UINT_8 ucSsidLen; ++} P2P_SSID_STRUCT_T, *P_P2P_SSID_STRUCT_T; ++ ++typedef struct _P2P_STATION_INFO_T { ++ UINT_32 u4InactiveTime; ++ UINT_32 u4RxBytes; /* TODO: */ ++ UINT_32 u4TxBytes; /* TODO: */ ++ UINT_32 u4RxPackets; /* TODO: */ ++ UINT_32 u4TxPackets; /* TODO: */ ++ /* TODO: Add more for requirement. */ ++} P2P_STATION_INFO_T, *P_P2P_STATION_INFO_T; ++ ++typedef struct _AP_CRYPTO_SETTINGS_T { ++ UINT_32 u4WpaVersion; ++ UINT_32 u4CipherGroup; ++ INT_32 i4NumOfCiphers; ++ UINT_32 aucCiphersPairwise[5]; ++ INT_32 i4NumOfAkmSuites; ++ UINT_32 aucAkmSuites[2]; ++ BOOLEAN fgIsControlPort; ++ UINT_16 u2ControlPortBE; ++ BOOLEAN fgIsControlPortEncrypt; ++} AP_CRYPTO_SETTINGS_T, *P_AP_CRYPTO_SETTINGS_T; ++ ++/*-------------------- P2P FSM ACTION STRUCT ---------------------*/ ++typedef struct _P2P_CHNL_REQ_INFO_T { ++ BOOLEAN fgIsChannelRequested; ++ UINT_8 ucSeqNumOfChReq; ++ UINT_64 u8Cookie; ++ UINT_8 ucReqChnlNum; ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eChnlSco; ++ UINT_32 u4MaxInterval; ++ ENUM_CHANNEL_REQ_TYPE_T eChannelReqType; ++ ++ UINT_8 ucOriChnlNum; ++ ENUM_BAND_T eOriBand; ++ ENUM_CHNL_EXT_T eOriChnlSco; ++ UINT_32 NFC_BEAM; /*NFC Beam + Indication */ ++} P2P_CHNL_REQ_INFO_T, *P_P2P_CHNL_REQ_INFO_T; ++ ++typedef struct _P2P_SCAN_REQ_INFO_T { ++ ENUM_SCAN_TYPE_T eScanType; ++ ENUM_SCAN_CHANNEL eChannelSet; ++ UINT_16 u2PassiveDewellTime; ++ UINT_8 ucSeqNumOfScnMsg; ++ BOOLEAN fgIsAbort; ++ BOOLEAN fgIsScanRequest; ++ UINT_8 ucNumChannelList; ++ RF_CHANNEL_INFO_T arScanChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++ P2P_SSID_STRUCT_T rSsidStruct; /* Currently we can only take one SSID scan request */ ++ BOOLEAN fgIsGOInitialDone; ++} P2P_SCAN_REQ_INFO_T, *P_P2P_SCAN_REQ_INFO_T; ++ ++typedef struct _P2P_CONNECTION_REQ_INFO_T { ++ ++ BOOLEAN fgIsConnRequest; ++ P2P_SSID_STRUCT_T rSsidStruct; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ /* For ASSOC Req. */ ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++} P2P_CONNECTION_REQ_INFO_T, *P_P2P_CONNECTION_REQ_INFO_T; ++ ++typedef struct _P2P_MGMT_TX_REQ_INFO_T { ++ BOOLEAN fgIsMgmtTxRequested; ++ P_MSDU_INFO_T prMgmtTxMsdu; ++ UINT_64 u8Cookie; ++} P2P_MGMT_TX_REQ_INFO_T, *P_P2P_MGMT_TX_REQ_INFO_T; ++ ++struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 wait; /* interval supplicant expected to stay in listen interval */ ++}; ++ ++typedef struct _P2P_BEACON_UPDATE_INFO_T { ++ PUINT_8 pucBcnHdr; ++ UINT_32 u4BcnHdrLen; ++ PUINT_8 pucBcnBody; ++ UINT_32 u4BcnBodyLen; ++} P2P_BEACON_UPDATE_INFO_T, *P_P2P_BEACON_UPDATE_INFO_T; ++ ++typedef struct _P2P_PROBE_RSP_UPDATE_INFO_T { ++ P_MSDU_INFO_T prProbeRspMsduTemplate; ++} P2P_PROBE_RSP_UPDATE_INFO_T, *P_P2P_PROBE_RSP_UPDATE_INFO_T; ++ ++typedef struct _P2P_ASSOC_RSP_UPDATE_INFO_T { ++ PUINT_8 pucAssocRspExtIE; ++ UINT_16 u2AssocIELen; ++} P2P_ASSOC_RSP_UPDATE_INFO_T, *P_P2P_ASSOC_RSP_UPDATE_INFO_T; ++ ++typedef struct _P2P_JOIN_INFO_T { ++ UINT_32 ucSeqNumOfReqMsg; ++ UINT_8 ucAvailableAuthTypes; ++ P_STA_RECORD_T prTargetStaRec; ++ P2P_SSID_STRUCT_T rSsidStruct; ++ BOOLEAN fgIsJoinComplete; ++ /* For ASSOC Rsp. */ ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++} P2P_JOIN_INFO_T, *P_P2P_JOIN_INFO_T; ++ ++#if CFG_SUPPORT_WFD ++ ++#define WFD_FLAGS_DEV_INFO_VALID BIT(0) /* 1. WFD_DEV_INFO, 2. WFD_CTRL_PORT, 3. WFD_MAT_TP. */ ++#define WFD_FLAGS_SINK_INFO_VALID BIT(1) /* 1. WFD_SINK_STATUS, 2. WFD_SINK_MAC. */ ++#define WFD_FLAGS_ASSOC_MAC_VALID BIT(2) /* 1. WFD_ASSOC_MAC. */ ++#define WFD_FLAGS_EXT_CAPABILITY_VALID BIT(3) /* 1. WFD_EXTEND_CAPABILITY. */ ++ ++struct _WFD_CFG_SETTINGS_T { ++ UINT_32 u4WfdCmdType; ++ UINT_8 ucWfdEnable; ++ UINT_8 ucWfdCoupleSinkStatus; ++ UINT_8 ucWfdSessionAvailable; /* 0: NA 1:Set 2:Clear */ ++ UINT_8 ucWfdSigmaMode; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2WfdControlPort; ++ UINT_16 u2WfdMaximumTp; ++ UINT_16 u2WfdExtendCap; ++ UINT_8 aucWfdCoupleSinkAddress[MAC_ADDR_LEN]; ++ UINT_8 aucWfdAssociatedBssid[MAC_ADDR_LEN]; ++ UINT_8 aucWfdVideoIp[4]; ++ UINT_8 aucWfdAudioIp[4]; ++ UINT_16 u2WfdVideoPort; ++ UINT_16 u2WfdAudioPort; ++ UINT_32 u4WfdFlag; ++ UINT_32 u4WfdPolicy; ++ UINT_32 u4WfdState; ++ UINT_8 aucWfdSessionInformationIE[24 * 8]; ++ UINT_16 u2WfdSessionInformationIELen; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; ++ UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; ++ UINT_32 u4WfdAdvancedFlag; ++ /* Group 1 64 bytes */ ++ UINT_8 aucWfdLocalIp[4]; ++ UINT_16 u2WfdLifetimeAc2; /* Unit is 2 TU */ ++ UINT_16 u2WfdLifetimeAc3; /* Unit is 2 TU */ ++ UINT_16 u2WfdCounterThreshold; /* Unit is ms */ ++ UINT_8 aucReverved2[54]; ++ /* Group 2 64 bytes */ ++ UINT_8 aucReverved3[64]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReverved4[64]; ++ ++}; ++ ++struct _WFD_DBG_CFG_SETTINGS_T { ++ UINT_8 ucWfdDebugMode; ++ UINT_16 u2WfdSNShowPeiroid; ++ UINT_8 Reserved; ++ ++}; ++ ++#endif ++ ++struct _P2P_FSM_INFO_T { ++ /* State related. */ ++ ENUM_P2P_STATE_T ePreviousState; ++ ENUM_P2P_STATE_T eCurrentState; ++ ++ /* Channel related. */ ++ P2P_CHNL_REQ_INFO_T rChnlReqInfo; ++ ++ /* Scan related. */ ++ P2P_SCAN_REQ_INFO_T rScanReqInfo; ++ ++ /* Connection related. */ ++ P2P_CONNECTION_REQ_INFO_T rConnReqInfo; ++ ++ /* Mgmt tx related. */ ++ P2P_MGMT_TX_REQ_INFO_T rMgmtTxInfo; ++ ++ /* Beacon related. */ ++ P2P_BEACON_UPDATE_INFO_T rBcnContentInfo; ++ ++ /* Probe Response related. */ ++ P2P_PROBE_RSP_UPDATE_INFO_T rProbeRspContentInfo; ++ ++ /* Assoc Rsp related. */ ++ P2P_ASSOC_RSP_UPDATE_INFO_T rAssocRspContentInfo; ++ ++ /* GC Join related. */ ++ P2P_JOIN_INFO_T rJoinInfo; ++ ++ /* FSM Timer */ ++/* TIMER_T rP2pFsmTimeoutTimer; */ ++ ++ /* GC Target BSS. */ ++ P_BSS_DESC_T prTargetBss; ++ ++ /* GC Connection Request. */ ++ BOOLEAN fgIsConnectionRequested; ++ ++ BOOLEAN fgIsApMode; ++ ++ /* Channel grant interval. */ ++ UINT_32 u4GrantInterval; ++ ++ /* Packet filter for P2P module. */ ++ UINT_32 u4P2pPacketFilter; ++ ++ /* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Prepare for use vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ ++ /* Msg event queue. */ ++ LINK_T rMsgEventQueue; ++ ++#if CFG_SUPPORT_WFD ++ WFD_CFG_SETTINGS_T rWfdConfigureSettings; ++ WFD_DBG_CFG_SETTINGS_T rWfdDebugSetting; ++#endif ++ ++ BOOLEAN fgIsWPSMode; ++ ++ enum _ENUM_P2P_DEV_EXT_LISTEN_T eListenExted; ++}; ++ ++/*---------------- Messages -------------------*/ ++typedef struct _MSG_P2P_SCAN_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P_P2P_SSID_STRUCT_T prSSID; ++ INT_32 i4SsidNum; ++ UINT_32 u4NumChannel; ++ PUINT_8 pucIEBuf; ++ UINT_32 u4IELen; ++ BOOLEAN fgIsAbort; ++ RF_CHANNEL_INFO_T arChannelListInfo[1]; ++} MSG_P2P_SCAN_REQUEST_T, *P_MSG_P2P_SCAN_REQUEST_T; ++ ++typedef struct _MSG_P2P_CHNL_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++ UINT_32 u4Duration; ++ ENUM_CHNL_EXT_T eChnlSco; ++ RF_CHANNEL_INFO_T rChannelInfo; ++} MSG_P2P_CHNL_REQUEST_T, *P_MSG_P2P_CHNL_REQUEST_T; ++ ++typedef struct _MSG_P2P_CHNL_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++} MSG_P2P_CHNL_ABORT_T, *P_MSG_P2P_CHNL_ABORT_T; ++ ++typedef struct _MSG_P2P_CONNECTION_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P2P_SSID_STRUCT_T rSsid; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ ENUM_CHNL_EXT_T eChnlSco; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ UINT_32 u4IELen; ++ UINT_8 aucIEBuf[1]; ++ /* TODO: Auth Type, OPEN, SHARED, FT, EAP... */ ++} MSG_P2P_CONNECTION_REQUEST_T, *P_MSG_P2P_CONNECTION_REQUEST_T; ++ ++typedef struct _MSG_P2P_CONNECTION_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member. */ ++ UINT_8 aucTargetID[MAC_ADDR_LEN]; ++ UINT_16 u2ReasonCode; ++ BOOLEAN fgSendDeauth; ++} MSG_P2P_CONNECTION_ABORT_T, *P_MSG_P2P_CONNECTION_ABORT_T; ++ ++typedef struct _MSG_P2P_MGMT_TX_REQUEST_T { ++ MSG_HDR_T rMsgHdr; ++ P_MSDU_INFO_T prMgmtMsduInfo; ++ UINT_64 u8Cookie; /* For indication. */ ++ BOOLEAN fgNoneCckRate; ++ BOOLEAN fgIsWaitRsp; ++} MSG_P2P_MGMT_TX_REQUEST_T, *P_MSG_P2P_MGMT_TX_REQUEST_T; ++ ++typedef struct _MSG_P2P_START_AP_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 u4DtimPeriod; ++ UINT_32 u4BcnInterval; ++ UINT_8 aucSsid[32]; ++ UINT_16 u2SsidLen; ++ UINT_8 ucHiddenSsidType; ++ BOOLEAN fgIsPrivacy; ++ AP_CRYPTO_SETTINGS_T rEncryptionSettings; ++ INT_32 i4InactiveTimeout; ++} MSG_P2P_START_AP_T, *P_MSG_P2P_START_AP_T; ++ ++typedef struct _MSG_P2P_BEACON_UPDATE_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 u4BcnHdrLen; ++ UINT_32 u4BcnBodyLen; ++ PUINT_8 pucBcnHdr; ++ PUINT_8 pucBcnBody; ++ UINT_8 aucBuffer[1]; /* Header & Body are put here. */ ++} MSG_P2P_BEACON_UPDATE_T, *P_MSG_P2P_BEACON_UPDATE_T; ++ ++typedef struct _MSG_P2P_MGMT_FRAME_UPDATE_T { ++ MSG_HDR_T rMsgHdr; ++ ENUM_BUFFER_TYPE_T eBufferType; ++ UINT_32 u4BufferLen; ++ UINT_8 aucBuffer[1]; ++} MSG_P2P_MGMT_FRAME_UPDATE_T, *P_MSG_P2P_MGMT_FRAME_UPDATE_T; ++ ++typedef struct _MSG_P2P_SWITCH_OP_MODE_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ ENUM_OP_MODE_T eOpMode; ++} MSG_P2P_SWITCH_OP_MODE_T, *P_MSG_P2P_SWITCH_OP_MODE_T; ++ ++typedef struct _MSG_P2P_MGMT_FRAME_REGISTER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_16 u2FrameType; ++ BOOLEAN fgIsRegister; ++} MSG_P2P_MGMT_FRAME_REGISTER_T, *P_MSG_P2P_MGMT_FRAME_REGISTER_T; ++ ++typedef struct _MSG_P2P_NETDEV_REGISTER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ BOOLEAN fgIsEnable; ++ UINT_8 ucMode; ++} MSG_P2P_NETDEV_REGISTER_T, *P_MSG_P2P_NETDEV_REGISTER_T; ++ ++#if CFG_SUPPORT_WFD ++typedef struct _MSG_WFD_CONFIG_SETTINGS_CHANGED_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings; ++} MSG_WFD_CONFIG_SETTINGS_CHANGED_T, *P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS ++p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++#if CFG_SUPPORT_WFD ++VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++#endif ++ ++#if 0 ++/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ ++#endif ++ ++/* 3 --------------- WFA P2P DEFAULT PARAMETERS --------------- */ ++#define P2P_WILDCARD_SSID "DIRECT-" ++#define P2P_WILDCARD_SSID_LEN 7 ++#define P2P_GROUP_ID_LEN 9 ++ ++#define P2P_DRIVER_VERSION 2 /* Update when needed. */ ++ ++#define P2P_DEFAULT_DEV_NAME "Wireless Client" ++#define P2P_DEFAULT_DEV_NAME_LEN 15 ++#define P2P_DEFAULT_PRIMARY_CATEGORY_ID 10 ++#define P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID 5 ++#define P2P_DEFAULT_CONFIG_METHOD \ ++ (WPS_ATTRI_CFG_METHOD_PUSH_BUTTON | WPS_ATTRI_CFG_METHOD_KEYPAD | WPS_ATTRI_CFG_METHOD_DISPLAY) ++#define P2P_DEFAULT_LISTEN_CHANNEL 1 ++ ++#define P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT 0 /* NOTE(Kevin): Shall <= 16 */ ++#define P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT 13 ++ ++#define P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE 51 /* Contains 6 sub-band. */ ++ ++#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ ++ ++#define P2P_MAXIMUM_CLIENT_COUNT 8 ++#define P2P_MAXIMUM_NOA_COUNT 8 ++ ++#define P2P_MAXIMUM_ATTRIBUTE_LEN 251 ++ ++#define P2P_CTWINDOW_DEFAULT 25 /* in TU=(1024usec) */ ++ ++#define P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE 768 ++ ++/* P2P 3.1.2.1.3 - Find Phase */ ++#define P2P_MAX_DISCOVERABLE_INTERVAL 8 /* 3 */ ++#define P2P_MIN_DISCOVERABLE_INTERVAL 5 /* 1 */ ++ ++#define P2P_LISTEN_SCAN_UNIT 100 /* MS */ ++ ++/* FSM Time Related constrain. */ ++#define P2P_SERACH_STATE_PERIOD_MS 1000 /* Deprecated. */ ++ ++#define P2P_GO_CHANNEL_STAY_INTERVAL 1000 ++ ++#define P2P_GO_NEGO_TIMEOUT_MS 500 ++#define P2P_CONNECTION_TIMEOUT_SEC 120 ++ ++#define P2P_INVITAION_TIMEOUT_MS 500 /* Timeout Wait Invitation Resonse. */ ++#define P2P_PROVISION_DISCOVERY_TIMEOUT_MS 500 /* Timeout Wait Provision Discovery Resonse. */ ++ ++/* 3 --------------- WFA P2P IE --------------- */ ++/* P2P 4.1.1 - P2P IE format */ ++#define P2P_OUI_TYPE_LEN 4 ++#define P2P_IE_OUI_HDR (ELEM_HDR_LEN + P2P_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, ++ aucP2PAttributes[0]) */ ++ ++/* P2P 4.1.1 - General P2P Attribute */ ++#define P2P_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ ++#define P2P_ATTRI_LEN_NOTICE_OF_ABSENCE (P2P_ATTRI_HDR_LEN + 2) /* 5 */ ++ ++/* P2P 4.1.1 - P2P Attribute ID definitions */ ++#define P2P_ATTRI_ID_STATUS 0 ++#define P2P_ATTRI_ID_REASON_CODE 1 ++#define P2P_ATTRI_ID_P2P_CAPABILITY 2 ++#define P2P_ATTRI_ID_P2P_DEV_ID 3 ++#define P2P_ATTRI_ID_GO_INTENT 4 ++#define P2P_ATTRI_ID_CFG_TIMEOUT 5 ++#define P2P_ATTRI_ID_LISTEN_CHANNEL 6 ++#define P2P_ATTRI_ID_P2P_GROUP_BSSID 7 ++#define P2P_ATTRI_ID_EXT_LISTEN_TIMING 8 ++#define P2P_ATTRI_ID_INTENDED_P2P_IF_ADDR 9 ++#define P2P_ATTRI_ID_P2P_MANAGEABILITY 10 ++#define P2P_ATTRI_ID_CHANNEL_LIST 11 ++#define P2P_ATTRI_ID_NOTICE_OF_ABSENCE 12 ++#define P2P_ATTRI_ID_P2P_DEV_INFO 13 ++#define P2P_ATTRI_ID_P2P_GROUP_INFO 14 ++#define P2P_ATTRI_ID_P2P_GROUP_ID 15 ++#define P2P_ATTRI_ID_P2P_INTERFACE 16 ++#define P2P_ATTRI_ID_OPERATING_CHANNEL 17 ++#define P2P_ATTRI_ID_INVITATION_FLAG 18 ++#define P2P_ATTRI_ID_VENDOR_SPECIFIC 221 ++ ++/* Maximum Length of P2P Attributes */ ++#define P2P_ATTRI_MAX_LEN_STATUS 1 /* 0 */ ++#define P2P_ATTRI_MAX_LEN_REASON_CODE 1 /* 1 */ ++#define P2P_ATTRI_MAX_LEN_P2P_CAPABILITY 2 /* 2 */ ++#define P2P_ATTRI_MAX_LEN_P2P_DEV_ID 6 /* 3 */ ++#define P2P_ATTRI_MAX_LEN_GO_INTENT 1 /* 4 */ ++#define P2P_ATTRI_MAX_LEN_CFG_TIMEOUT 2 /* 5 */ ++#if CID52_53_54 ++#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ ++#else ++#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ ++#endif ++#define P2P_ATTRI_MAX_LEN_P2P_GROUP_BSSID 6 /* 7 */ ++#define P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING 4 /* 8 */ ++#define P2P_ATTRI_MAX_LEN_INTENDED_P2P_IF_ADDR 6 /* 9 */ ++#define P2P_ATTRI_MAX_LEN_P2P_MANAGEABILITY 1 /* 10 */ ++/* #define P2P_ATTRI_MAX_LEN_CHANNEL_LIST 3 + (n* (2 + num_of_ch)) */ /* 11 */ ++#define P2P_ATTRI_LEN_CHANNEL_LIST 3 /* 11 */ ++#define P2P_ATTRI_LEN_CHANNEL_ENTRY 2 /* 11 */ ++ ++/* #define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE 2 + (n* (13)) */ /* 12 */ ++#define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE (2 + (P2P_MAXIMUM_NOA_COUNT*(13))) /* 12 */ ++ ++#define P2P_ATTRI_MAX_LEN_P2P_DEV_INFO (17 + (8 * (8)) + 36) /* 13 */ ++/* #define P2P_ATTRI_MAX_LEN_P2P_GROUP_INFO n* (25 + (m* (8)) + 32) */ /* 14 */ ++#define P2P_ATTRI_MAX_LEN_P2P_GROUP_ID 38 /* 15 */ ++#define P2P_ATTRI_MAX_LEN_P2P_INTERFACE 253 /* 7 + 6* [0~41] */ /* 16 */ ++#if CID52_53_54 ++#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ ++#else ++#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ ++#endif ++#define P2P_ATTRI_MAX_LEN_INVITATION_FLAGS 1 /* 18 */ ++ ++/* P2P 4.1.2 - P2P Status definitions */ ++#define P2P_STATUS_SUCCESS 0 ++#define P2P_STATUS_FAIL_INFO_IS_CURRENTLY_UNAVAILABLE 1 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 2 ++#define P2P_STATUS_FAIL_LIMIT_REACHED 3 ++#define P2P_STATUS_FAIL_INVALID_PARAM 4 ++#define P2P_STATUS_FAIL_UNABLE_ACCOMMODATE_REQ 5 ++#define P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR 6 ++#define P2P_STATUS_FAIL_NO_COMMON_CHANNELS 7 ++#define P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP 8 ++#define P2P_STATUS_FAIL_SAME_INTENT_VALUE_15 9 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVISION_METHOD 10 ++#define P2P_STATUS_FAIL_REJECTED_BY_USER 11 ++ ++/* P2P 4.1.3 - P2P Minor Reason Code definitions */ ++#define P2P_REASON_SUCCESS 0 ++#define P2P_REASON_DISASSOCIATED_DUE_CROSS_CONNECTION 1 ++#define P2P_REASON_DISASSOCIATED_DUE_UNMANAGEABLE 2 ++#define P2P_REASON_DISASSOCIATED_DUE_NO_P2P_COEXIST_PARAM 3 ++#define P2P_REASON_DISASSOCIATED_DUE_MANAGEABLE 4 ++ ++/* P2P 4.1.4 - Device Capability Bitmap definitions */ ++#define P2P_DEV_CAPABILITY_SERVICE_DISCOVERY BIT(0) ++#define P2P_DEV_CAPABILITY_CLIENT_DISCOVERABILITY BIT(1) ++#define P2P_DEV_CAPABILITY_CONCURRENT_OPERATION BIT(2) ++#define P2P_DEV_CAPABILITY_P2P_INFRA_MANAGED BIT(3) ++#define P2P_DEV_CAPABILITY_P2P_DEVICE_LIMIT BIT(4) ++#define P2P_DEV_CAPABILITY_P2P_INVITATION_PROCEDURE BIT(5) ++ ++/* P2P 4.1.4 - Group Capability Bitmap definitions */ ++#define P2P_GROUP_CAPABILITY_P2P_GROUP_OWNER BIT(0) ++#define P2P_GROUP_CAPABILITY_PERSISTENT_P2P_GROUP BIT(1) ++#define P2P_GROUP_CAPABILITY_P2P_GROUP_LIMIT BIT(2) ++#define P2P_GROUP_CAPABILITY_INTRA_BSS_DISTRIBUTION BIT(3) ++#define P2P_GROUP_CAPABILITY_CROSS_CONNECTION BIT(4) ++#define P2P_GROUP_CAPABILITY_PERSISTENT_RECONNECT BIT(5) ++#define P2P_GROUP_CAPABILITY_GROUP_FORMATION BIT(6) ++ ++/* P2P 4.1.6 - GO Intent field definitions */ ++#define P2P_GO_INTENT_TIE_BREAKER_FIELD BIT(0) ++#define P2P_GO_INTENT_VALUE_MASK BITS(1, 7) ++#define P2P_GO_INTENT_VALUE_OFFSET 1 ++ ++/* P2P 4.1.12 - Manageability Bitmap definitions */ ++#define P2P_DEVICE_MANAGEMENT BIT(0) ++ ++/* P2P 4.1.14 - CTWindow and OppPS Parameters definitions */ ++#define P2P_CTW_OPPPS_PARAM_OPPPS_FIELD BIT(7) ++#define P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK BITS(0, 6) ++ ++#define ELEM_MAX_LEN_P2P_FOR_PROBE_REQ \ ++ (P2P_OUI_TYPE_LEN + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_ID) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL)) ++ ++#define ELEM_MAX_LEN_P2P_FOR_ASSOC_REQ \ ++ (P2P_OUI_TYPE_LEN + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_INFO)) ++ ++/* P2P 4.1.16 - P2P Client Infor Descriptor */ ++#define P2P_CLIENT_INFO_DESC_HDR_LEN 1 /* Length(1 octets) */ ++ ++/* P2P 4.1.20 - P2P Invitation Flags Attribute*/ ++#define P2P_INVITATION_FLAGS_INVITATION_TYPE BIT(0) ++#define P2P_INVITATION_TYPE_INVITATION 0 ++#define P2P_INVITATION_TYPE_REINVOKE 1 ++/* 3 --------------- WPS Data Element Definitions --------------- */ ++/* P2P 4.2.2 - General WSC Attribute */ ++#define WSC_ATTRI_HDR_LEN 4 /* ID(2 octet) + Length(2 octets) */ ++#define WSC_ATTRI_MAX_LEN_VERSION 1 ++#define WSC_ATTRI_MAX_LEN_DEVICE_PASSWORD_ID 2 ++#define WSC_ATTRI_LEN_CONFIG_METHOD 2 ++ ++/* WPS 11 - Data Element Definitions */ ++#define WPS_ATTRI_ID_VERSION 0x104A ++#define WPS_ATTRI_ID_CONFIGURATION_METHODS 0x1008 ++#define WPS_ATTRI_ID_DEVICE_PASSWORD 0x1012 ++#define WPS_ATTRI_ID_DEVICE_NAME 0x1011 ++#define WPS_ATTRI_ID_PRI_DEVICE_TYPE 0x1054 ++#define WPS_ATTRI_ID_SEC_DEVICE_TYPE 0x1055 ++ ++#define WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE 300 ++ ++#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ ++ ++#define WPS_ATTRI_CFG_METHOD_USBA BIT(0) ++#define WPS_ATTRI_CFG_METHOD_ETHERNET BIT(1) ++#define WPS_ATTRI_CFG_METHOD_LABEL BIT(2) ++#define WPS_ATTRI_CFG_METHOD_DISPLAY BIT(3) ++#define WPS_ATTRI_CFG_METHOD_EXT_NFC BIT(4) ++#define WPS_ATTRI_CFG_METHOD_INT_NFC BIT(5) ++#define WPS_ATTRI_CFG_METHOD_NFC_IF BIT(6) ++#define WPS_ATTRI_CFG_METHOD_PUSH_BUTTON BIT(7) ++#define WPS_ATTRI_CFG_METHOD_KEYPAD BIT(8) ++ ++#define P2P_FLAGS_PROVISION_COMPLETE 0x00000001 ++#define P2P_FLAGS_PROVISION_DISCOVERY_COMPLETE 0x00000002 ++#define P2P_FLAGS_PROVISION_DISCOVERY_WAIT_RESPONSE 0x00000004 ++#define P2P_FLAGS_PROVISION_DISCOVERY_RESPONSE_WAIT 0x00000008 ++#define P2P_FLAGS_MASK_PROVISION 0x00000017 ++#define P2P_FLAGS_MASK_PROVISION_COMPLETE 0x00000015 ++#define P2P_FLAGS_PROVISION_DISCOVERY_INDICATED 0x00000010 ++#define P2P_FLAGS_INVITATION_TOBE_GO 0x00000100 ++#define P2P_FLAGS_INVITATION_TOBE_GC 0x00000200 ++#define P2P_FLAGS_INVITATION_SUCCESS 0x00000400 ++#define P2P_FLAGS_INVITATION_WAITING_TARGET 0x00000800 ++#define P2P_FLAGS_MASK_INVITATION 0x00000F00 ++#define P2P_FLAGS_FORMATION_ON_GOING 0x00010000 ++#define P2P_FLAGS_FORMATION_LOCAL_PWID_RDY 0x00020000 ++#define P2P_FLAGS_FORMATION_TARGET_PWID_RDY 0x00040000 ++#define P2P_FLAGS_FORMATION_COMPLETE 0x00080000 ++#define P2P_FLAGS_MASK_FORMATION 0x000F0000 ++#define P2P_FLAGS_DEVICE_DISCOVER_REQ 0x00100000 ++#define P2P_FLAGS_DEVICE_DISCOVER_DONE 0x00200000 ++#define P2P_FLAGS_DEVICE_INVITATION_WAIT 0x00400000 ++#define P2P_FLAGS_DEVICE_SERVICE_DISCOVER_WAIT 0x00800000 ++#define P2P_FLAGS_MASK_DEVICE_DISCOVER 0x00F00000 ++ ++#define P2P_FLAGS_DEVICE_FORMATION_REQUEST 0x01000000 ++ ++/* MACRO for flag operation */ ++#define SET_FLAGS(_FlagsVar, _BitsToSet) \ ++ {(_FlagsVar) = ((_FlagsVar) | (_BitsToSet))} ++ ++#define TEST_FLAGS(_FlagsVar, _BitsToCheck) \ ++ (((_FlagsVar) & (_BitsToCheck)) == (_BitsToCheck)) ++ ++#define CLEAR_FLAGS(_FlagsVar, _BitsToClear) \ ++ {(_FlagsVar) &= ~(_BitsToClear)} ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_I 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_II 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_III 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_IV 0 ++ ++#define CFG_DISABLE_DELAY_PROVISION_DISCOVERY 0 ++ ++#define CFG_CONNECTION_POLICY_2_0 0 ++ ++/* Device Password ID */ ++enum wps_dev_password_id { ++ DEV_PW_DEFAULT = 0x0000, ++ DEV_PW_USER_SPECIFIED = 0x0001, ++ DEV_PW_MACHINE_SPECIFIED = 0x0002, ++ DEV_PW_REKEY = 0x0003, ++ DEV_PW_PUSHBUTTON = 0x0004, ++ DEV_PW_REGISTRAR_SPECIFIED = 0x0005 ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack(1) ++#endif ++ ++/* 3 --------------- WFA P2P IE and Attributes --------------- */ ++ ++/* P2P 4.1.1 - P2P Information Element */ ++typedef struct _IE_P2P_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 aucP2PAttributes[1]; /* P2P Attributes */ ++} __KAL_ATTRIB_PACKED__ IE_P2P_T, *P_IE_P2P_T; ++ ++/* P2P 4.1.1 - General P2P Attribute */ ++typedef struct _P2P_ATTRIBUTE_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRIBUTE_T, ATTRIBUTE_HDR_T, *P_P2P_ATTRIBUTE_T, *P_ATTRIBUTE_HDR_T; ++ ++/* P2P 4.1.2 - P2P Status Attribute */ ++typedef struct _P2P_ATTRI_STATUS_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucStatusCode; /* Status Code */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_STATUS_T, *P_P2P_ATTRI_STATUS_T; ++ ++/* P2P 4.1.3 - P2P Minor Reason Code Attribute */ ++typedef struct _P2P_ATTRI_REASON_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucMinorReasonCode; /* Minor Reason Code */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_REASON_T, *P_P2P_ATTRI_REASON_T; ++ ++/* P2P 4.1.4 - P2P Capability Attribute */ ++typedef struct _P2P_ATTRI_CAPABILITY_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucDeviceCap; /* Device Capability Bitmap */ ++ UINT_8 ucGroupCap; /* Group Capability Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CAPABILITY_T, *P_P2P_ATTRI_CAPABILITY_T; ++ ++/* P2P 4.1.5 - P2P Device ID Attribute */ ++typedef struct _P2P_ATTRI_DEV_ID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_ID_T, *P_P2P_ATTRI_DEV_ID_T; ++ ++/* P2P 4.1.6 - Group Owner Intent Attribute */ ++typedef struct _P2P_ATTRI_GO_INTENT_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucGOIntent; /* Group Owner Intent */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GO_INTENT_T, *P_P2P_ATTRI_GO_INTENT_T; ++ ++/* P2P 4.1.7 - Configuration Timeout Attribute */ ++typedef struct _P2P_ATTRI_CFG_TIMEOUT_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucGOCfgTimeout; /* GO Configuration Timeout */ ++ UINT_8 ucClientCfgTimeout; /* Client Configuration Timeout */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CFG_TIMEOUT_T, *P_P2P_ATTRI_CFG_TIMEOUT_T; ++ ++/* P2P 4.1.8 - Listen Channel Attribute */ ++typedef struct _P2P_ATTRI_LISTEN_CHANNEL_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ ++ UINT_8 ucChannelNumber; /* Channel Number */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_LISTEN_CHANNEL_T, *P_P2P_ATTRI_LISTEN_CHANNEL_T; ++ ++/* P2P 4.1.9 - P2P Group BSSID Attribute */ ++typedef struct _P2P_ATTRI_GROUP_BSSID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBssid[MAC_ADDR_LEN]; /* P2P Group BSSID */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_BSSID_T, *P_P2P_ATTRI_GROUP_BSSID_T; ++ ++/* P2P 4.1.10 - Extended Listen Timing Attribute */ ++typedef struct _P2P_ATTRI_EXT_LISTEN_TIMING_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2AvailPeriod; /* Availability Period */ ++ UINT_16 u2AvailInterval; /* Availability Interval */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_EXT_LISTEN_TIMING_T, *P_P2P_ATTRI_EXT_LISTEN_TIMING_T; ++ ++/* P2P 4.1.11 - Intended P2P Interface Address Attribute */ ++typedef struct _P2P_ATTRI_INTENDED_IF_ADDR_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTENDED_IF_ADDR_T, *P_P2P_ATTRI_INTENDED_IF_ADDR_T; ++ ++/* P2P 4.1.12 - P2P Manageability Attribute */ ++typedef struct _P2P_ATTRI_MANAGEABILITY_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucManageability; /* P2P Manageability Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_MANAGEABILITY_T, *P_P2P_ATTRI_MANAGEABILITY_T; ++ ++/* P2P 4.1.13 - Channel List Attribute */ ++typedef struct _P2P_ATTRI_CHANNEL_LIST_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 aucChannelEntry[1]; /* Channel Entry List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CHANNEL_T, *P_P2P_ATTRI_CHANNEL_T; ++ ++typedef struct _CHANNEL_ENTRY_FIELD_T { ++ UINT_8 ucRegulatoryClass; /* Regulatory Class */ ++ UINT_8 ucNumberOfChannels; /* Number Of Channels */ ++ UINT_8 aucChannelList[1]; /* Channel List */ ++} __KAL_ATTRIB_PACKED__ CHANNEL_ENTRY_FIELD_T, *P_CHANNEL_ENTRY_FIELD_T; ++ ++/* P2P 4.1.14 - Notice of Absence Attribute */ ++typedef struct _P2P_ATTRI_NOA_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucIndex; /* Index */ ++ UINT_8 ucCTWOppPSParam; /* CTWindow and OppPS Parameters */ ++ UINT_8 aucNoADesc[1]; /* NoA Descriptor */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_NOA_T, *P_P2P_ATTRI_NOA_T; ++ ++typedef struct _NOA_DESCRIPTOR_T { ++ UINT_8 ucCountType; /* Count/Type */ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} __KAL_ATTRIB_PACKED__ NOA_DESCRIPTOR_T, *P_NOA_DESCRIPTOR_T; ++ ++typedef struct _P2P_ATTRI_DEV_INFO_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_16 u2ConfigMethodsBE; /* Config Method */ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ ++ UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ ++ DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_INFO_T, *P_P2P_ATTRI_DEV_INFO_T; ++ ++/* WPS 7.1 & 11 WPS TLV Data Format - Device Name */ ++typedef struct _DEVICE_NAME_TLV_T { ++ UINT_16 u2Id; /* WPS Attribute Type */ ++ UINT_16 u2Length; /* Data Length */ ++ UINT_8 aucName[32]; /* Device Name */ /* TODO: Fixme */ ++} __KAL_ATTRIB_PACKED__ DEVICE_NAME_TLV_T, *P_DEVICE_NAME_TLV_T; ++ ++/* P2P 4.1.16 - P2P Group Info Attribute */ ++typedef struct _P2P_CLIENT_INFO_DESC_T { ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ ++ UINT_8 ucDeviceCap; /* Device Capability Bitmap */ ++ UINT_16 u2ConfigMethodsBE; /* Config Method */ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ ++ UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ ++ DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ ++} __KAL_ATTRIB_PACKED__ P2P_CLIENT_INFO_DESC_T, *P_P2P_CLIENT_INFO_DESC_T; ++ ++typedef struct _P2P_ATTRI_GROUP_INFO_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ P2P_CLIENT_INFO_DESC_T arClientDesc[1]; /* P2P Client Info Descriptors */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_INFO_T, *P_P2P_ATTRI_GROUP_INFO_T; ++ ++/* P2P 4.1.17 - P2P Group ID Attribute */ ++typedef struct _P2P_ATTRI_GROUP_ID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_ID_T, *P_P2P_ATTRI_GROUP_ID_T; ++ ++/* P2P 4.1.18 - P2P Interface Attribute */ ++typedef struct _P2P_ATTRI_INTERFACE_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 ucIfAddrCount; /* P2P Interface Address Count */ ++ UINT_8 aucIfAddrList[MAC_ADDR_LEN]; /* P2P Interface Address List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTERFACE_T, *P_P2P_ATTRI_INTERFACE_T; ++ ++/* P2P 4.1.19 - Operating Channel Attribute */ ++typedef struct _P2P_ATTRI_OPERATING_CHANNEL_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ ++ UINT_8 ucChannelNumber; /* Channel Number */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_OPERATING_CHANNEL_T, *P_P2P_ATTRI_OPERATING_CHANNEL_T; ++ ++/* P2P 4.1.20 - Invitation Flags Attribute */ ++typedef struct _P2P_ATTRI_INVITATION_FLAG_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucInviteFlagsBitmap; /* Invitation Flags Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INVITATION_FLAG_T, *P_P2P_ATTRI_INVITATION_FLAG_T; ++ ++/* P2P 4.1.1 - General WSC Attribute */ ++typedef struct _WSC_ATTRIBUTE_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRIBUTE_T, *P_WSC_ATTRIBUTE_T; ++ ++/* WSC 1.0 Table 28 */ ++typedef struct _WSC_ATTRI_VERSION_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucVersion; /* Version 1.0 or 1.1 */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_VERSION_T, *P_WSC_ATTRI_VERSION_T; ++ ++typedef struct _WSC_ATTRI_DEVICE_PASSWORD_ID_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2DevPasswordId; /* Device Password ID */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_DEVICE_PASSWORD_ID_T, *P_WSC_ATTRI_DEVICE_PASSWORD_ID_T; ++ ++typedef struct _WSC_ATTRI_CONFIGURATION_METHOD_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2ConfigMethods; /* Configure Methods */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_CONFIGURATION_METHOD_T, *P_WSC_ATTRI_CONFIGURATION_METHOD_T; ++ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack() ++#endif ++ ++/* 3 --------------- WFA P2P Attributes Handler prototype --------------- */ ++typedef UINT_32(*PFN_APPEND_ATTRI_FUNC) (P_ADAPTER_T, BOOLEAN, PUINT_16, PUINT_8, UINT_16); ++ ++typedef VOID(*PFN_HANDLE_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T); ++ ++typedef VOID(*PFN_VERIFY_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T, PUINT_16); ++ ++typedef UINT_32(*PFN_CALCULATE_VAR_ATTRI_LEN_FUNC) (P_ADAPTER_T, P_STA_RECORD_T); ++ ++typedef struct _APPEND_VAR_ATTRI_ENTRY_T { ++ UINT_16 u2EstimatedFixedAttriLen; /* For fixed length */ ++ PFN_CALCULATE_VAR_ATTRI_LEN_FUNC pfnCalculateVariableAttriLen; ++ PFN_APPEND_ATTRI_FUNC pfnAppendAttri; ++} APPEND_VAR_ATTRI_ENTRY_T, *P_APPEND_VAR_ATTRI_ENTRY_T; ++ ++typedef enum _ENUM_CONFIG_METHOD_SEL { ++ ENUM_CONFIG_METHOD_SEL_AUTO, ++ ENUM_CONFIG_METHOD_SEL_USER, ++ ENUM_CONFIG_METHOD_SEL_NUM ++} ENUM_CONFIG_METHOD_SEL, *P_ENUM_CONFIG_METHOD_SEL; ++ ++typedef enum _ENUM_P2P_FORMATION_POLICY { ++ ENUM_P2P_FORMATION_POLICY_AUTO = 0, ++ ENUM_P2P_FORMATION_POLICY_PASSIVE, /* Device would wait GO NEGO REQ instead of sending it actively. */ ++ ENUM_P2P_FORMATION_POLICY_NUM ++} ENUM_P2P_FORMATION_POLICY, P_ENUM_P2P_FORMATION_POLICY; ++ ++typedef enum _ENUM_P2P_INVITATION_POLICY { ++ ENUM_P2P_INVITATION_POLICY_USER = 0, ++ ENUM_P2P_INVITATION_POLICY_ACCEPT_FIRST, ++ ENUM_P2P_INVITATION_POLICY_DENY_ALL, ++ ENUM_P2P_INVITATION_POLICY_NUM ++} ENUM_P2P_INVITATION_POLICY, P_ENUM_P2P_INVITATION_POLICY; ++ ++/* 3 --------------- Data Structure for P2P Operation --------------- */ ++/* 3 Session for CONNECTION SETTINGS of P2P */ ++struct _P2P_CONNECTION_SETTINGS_T { ++ UINT_8 ucDevNameLen; ++ UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; ++ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; ++ ++ ENUM_P2P_FORMATION_POLICY eFormationPolicy; /* Formation Policy. */ ++ ++ /*------------WSC Related Param---------------*/ ++ UINT_16 u2ConfigMethodsSupport; /* Preferred configure method. ++ * Some device may not have keypad. ++ */ ++ ENUM_CONFIG_METHOD_SEL eConfigMethodSelType; ++ UINT_16 u2TargetConfigMethod; /* Configure method selected by user or auto. */ ++ UINT_16 u2LocalConfigMethod; /* Configure method of target. */ ++ BOOLEAN fgIsPasswordIDRdy; ++ /*------------WSC Related Param---------------*/ ++ ++ UINT_8 ucClientConfigTimeout; ++ UINT_8 ucGoConfigTimeout; ++ ++ UINT_8 ucSecondaryDevTypeCount; ++#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT ++ DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT]; ++#endif ++ ++#if 0 ++ UINT_8 ucRfChannelListCount; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT ++ UINT_8 aucChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering ++ depends on 802.11mb Annex J. */ ++ ++#endif ++#else ++ UINT_8 ucRfChannelListSize; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE ++ UINT_8 aucChannelEntriesField[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE]; ++#endif ++#endif ++ ++ /* Go Intent */ ++ UINT_8 ucTieBreaker; ++ UINT_8 ucGoIntent; ++ ++ /* For Device Capability */ ++ BOOLEAN fgSupportServiceDiscovery; ++ BOOLEAN fgSupportClientDiscoverability; ++ BOOLEAN fgSupportConcurrentOperation; ++ BOOLEAN fgSupportInfraManaged; ++ BOOLEAN fgSupportInvitationProcedure; ++ ++ /* For Group Capability */ ++ BOOLEAN fgSupportPersistentP2PGroup; ++ BOOLEAN fgSupportIntraBSSDistribution; ++ BOOLEAN fgSupportCrossConnection; ++ BOOLEAN fgSupportPersistentReconnect; ++ ++ BOOLEAN fgP2pGroupLimit; ++ ++ BOOLEAN fgSupportOppPS; ++ UINT_16 u2CTWindow; ++ ++ BOOLEAN fgIsScanReqIssued; ++ BOOLEAN fgIsServiceDiscoverIssued; ++ ++ /*============ Target Device Connection Settings ============*/ ++ ++ /* Discover Target Device Info. */ ++ BOOLEAN fgIsDevId; ++ BOOLEAN fgIsDevType; ++ ++ /* Encryption mode of Target Device */ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ /* SSID ++ * 1. AP Mode, this is the desired SSID user specified. ++ * 2. Client Mode, this is the target SSID to be connected to. ++ */ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ ++ /* Operating channel requested. */ ++ UINT_8 ucOperatingChnl; ++ ENUM_BAND_T eBand; ++ ++ /* Linten channel requested. */ ++ UINT_8 ucListenChnl; ++ ++ /* For device discover address/type. */ ++ UINT_8 aucTargetDevAddr[MAC_ADDR_LEN]; /* P2P Device Address, for P2P Device Discovery & P2P Connection. */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_DEVICE_DESC_T prTargetP2pDesc; ++#endif ++ ++ UINT_8 ucLastStatus; /* P2P FSM would append status attribute according to this field. */ ++ ++#if !CFG_DISABLE_DELAY_PROVISION_DISCOVERY ++ UINT_8 ucLastDialogToken; ++ UINT_8 aucIndicateDevAddr[MAC_ADDR_LEN]; ++#endif ++ ++#if 0 ++ UINT_8 ucTargetRfChannelListCount; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT ++ UINT_8 aucTargetChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering ++ depends on 802.11mb Annex J. */ ++#endif ++#endif ++ ++}; ++ ++typedef struct _NOA_TIMING_T { ++ BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 ucCount; /* Count */ ++ ++ UINT_8 aucReserved[2]; ++ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} NOA_TIMING_T, *P_NOA_TIMING_T; ++ ++typedef enum _ENUM_P2P_IOCTL_T { ++ P2P_IOCTL_IDLE = 0, ++ P2P_IOCTL_DEV_DISCOVER, ++ P2P_IOCTL_INVITATION_REQ, ++ P2P_IOCTL_SERV_DISCOVER, ++ P2P_IOCTL_WAITING, ++ P2P_IOCTL_NUM ++} ENUM_P2P_IOCTL_T; ++ ++/*---------------- Service Discovery Related -------------------*/ ++typedef enum _ENUM_SERVICE_TX_TYPE_T { ++ ENUM_SERVICE_TX_TYPE_BY_DA, ++ ENUM_SERVICE_TX_TYPE_BY_CHNL, ++ ENUM_SERVICE_TX_TYPE_NUM ++} ENUM_SERVICE_TX_TYPE_T; ++ ++typedef struct _SERVICE_DISCOVERY_FRAME_DATA_T { ++ QUE_ENTRY_T rQueueEntry; ++ P_MSDU_INFO_T prSDFrame; ++ ENUM_SERVICE_TX_TYPE_T eServiceType; ++ UINT_8 ucSeqNum; ++ union { ++ ++ UINT_8 ucChannelNum; ++ UINT_8 aucPeerAddr[MAC_ADDR_LEN]; ++ } uTypeData; ++ BOOLEAN fgIsTxDoneIndicate; ++} SERVICE_DISCOVERY_FRAME_DATA_T, *P_SERVICE_DISCOVERY_FRAME_DATA_T; ++ ++struct _P2P_FSM_INFO_T_DEPRECATED { ++ /* P2P FSM State */ ++ ENUM_P2P_STATE_T eCurrentState; ++ ++ /* Channel */ ++ BOOLEAN fgIsChannelRequested; ++ ++ ENUM_P2P_STATE_T ePreviousState; ++ ++ ENUM_P2P_STATE_T eReturnState; /* Return state after current activity finished or abort. */ ++ ++ UINT_8 aucTargetIfAddr[PARAM_MAC_ADDR_LEN]; ++ P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ ++ ++ P_STA_RECORD_T prTargetStaRec; ++ ++ BOOLEAN fgIsRsponseProbe; /* Indicate if P2P FSM can response probe request frame. */ ++ ++ /* Sequence number of requested message. */ ++ UINT_8 ucSeqNumOfReqMsg; /* Used for SAA FSM request message. */ ++ ++ /* Channel Privilege */ ++ UINT_8 ucSeqNumOfChReq; /* Used for Channel Request message. */ ++ ++ UINT_8 ucSeqNumOfScnMsg; /* Used for SCAN FSM request message. */ ++ UINT_8 ucSeqNumOfCancelMsg; ++ ++ UINT_8 ucDialogToken; ++ UINT_8 ucRxDialogToken; ++ ++ /* Timer */ ++ TIMER_T rDeviceDiscoverTimer; /* For device discovery time of each discovery request from user. */ ++ TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ ++ TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ ++ ++ TIMER_T rRejoinTimer; /* A timer used for Action frame timeout usage. */ ++ ++ /* Flag to indicate Provisioning */ ++ BOOLEAN fgIsConnectionRequested; ++ ++ /* Current IOCTL. */ ++ ENUM_P2P_IOCTL_T eP2pIOCTL; ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++ /*--------SERVICE DISCOVERY--------*/ ++ QUE_T rQueueGASRx; /* Input Request/Response. */ ++ QUE_T rQueueGASTx; /* Output Response. */ ++ P_SERVICE_DISCOVERY_FRAME_DATA_T prSDRequest; ++ UINT_8 ucVersionNum; /* GAS packet sequence number for...Action Frame? */ ++ UINT_8 ucGlobalSeqNum; /* Sequence Number of RX SD packet. */ ++ /*--------Service DISCOVERY--------*/ ++ ++ /*--------DEVICE DISCOVERY---------*/ ++ UINT_8 aucTargetGroupID[PARAM_MAC_ADDR_LEN]; ++ UINT_16 u2TargetGroupSsidLen; ++ UINT_8 aucTargetSsid[32]; ++ UINT_8 aucSearchingP2pDevice[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucDLToken; ++ /*----------------------------------*/ ++ ++ /* Indicating Peer Status. */ ++ UINT_32 u4Flags; ++ ++ /*Indicating current running mode. */ ++ BOOLEAN fgIsApMode; ++ ++ /*------------INVITATION------------*/ ++ ENUM_P2P_INVITATION_POLICY eInvitationRspPolicy; ++ /*----------------------------------*/ ++ ++}; ++ ++struct _P2P_SPECIFIC_BSS_INFO_T { ++ /* For GO(AP) Mode - Compose TIM IE */ ++ UINT_16 u2SmallestAID; ++ UINT_16 u2LargestAID; ++ UINT_8 ucBitmapCtrl; ++ /* UINT_8 aucPartialVirtualBitmap[MAX_LEN_TIM_PARTIAL_BMP]; */ ++ ++ /* For GC/GO OppPS */ ++ BOOLEAN fgEnableOppPS; ++ UINT_16 u2CTWindow; ++ ++ /* For GC/GO NOA */ ++ UINT_8 ucNoAIndex; ++ UINT_8 ucNoATimingCount; /* Number of NoA Timing */ ++ NOA_TIMING_T arNoATiming[P2P_MAXIMUM_NOA_COUNT]; ++ ++ BOOLEAN fgIsNoaAttrExisted; ++ ++ /* For P2P Device */ ++ UINT_8 ucRegClass; /* Regulatory Class for channel. */ ++ UINT_8 ucListenChannel; /* Linten Channel only on channels 1, 6 and 11 in the 2.4 GHz. */ ++ ++ UINT_8 ucPreferredChannel; /* Operating Channel, should be one of channel list ++ in p2p connection settings. */ ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ++ /* Extended Listen Timing. */ ++ UINT_16 u2AvailabilityPeriod; ++ UINT_16 u2AvailabilityInterval; ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++ UINT_16 u2IELenForBCN; ++ UINT_8 aucBeaconIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++/* UINT_16 u2IELenForProbeRsp; */ ++/* UINT_8 aucProbeRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; */ ++ ++ UINT_16 u2IELenForAssocRsp; ++ UINT_8 aucAssocRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++#else ++ UINT_16 u2AttributeLen; ++ UINT_8 aucAttributesCache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++ UINT_16 u2WscAttributeLen; ++ UINT_8 aucWscAttributesCache[WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++#endif ++ UINT_8 aucGroupID[MAC_ADDR_LEN]; ++ UINT_16 u2GroupSsidLen; ++ UINT_8 aucGroupSsid[ELEM_MAX_LEN_SSID]; ++ ++ PARAM_CUSTOM_NOA_PARAM_STRUCT_T rNoaParam; ++ PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T rOppPsParam; ++ ++ UINT_16 u2WpaIeLen; ++ UINT_8 aucWpaIeBuffer[ELEM_HDR_LEN + ELEM_MAX_LEN_WPA]; ++}; ++ ++typedef struct _MSG_P2P_DEVICE_DISCOVER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_32 u4DevDiscoverTime; /* 0: Infinite, 1~X: in unit of MS. */ ++ BOOLEAN fgIsSpecificType; ++#if CFG_ENABLE_WIFI_DIRECT ++ P2P_DEVICE_TYPE_T rTargetDeviceType; ++#endif ++ UINT_8 aucTargetDeviceID[MAC_ADDR_LEN]; ++} MSG_P2P_DEVICE_DISCOVER_T, *P_MSG_P2P_DEVICE_DISCOVER_T; ++ ++typedef struct _MSG_P2P_INVITATION_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 aucDeviceID[MAC_ADDR_LEN]; /* Target Device ID to be invited. */ ++} MSG_P2P_INVITATION_REQUEST_T, *P_MSG_P2P_INVITATION_REQUEST_T; ++ ++typedef struct _MSG_P2P_FUNCTION_SWITCH_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ BOOLEAN fgIsFuncOn; ++} MSG_P2P_FUNCTION_SWITCH_T, *P_MSG_P2P_FUNCTION_SWITCH_T; ++ ++typedef struct _MSG_P2P_SERVICE_DISCOVERY_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 aucDeviceID[MAC_ADDR_LEN]; ++ BOOLEAN fgNeedTxDoneIndicate; ++ UINT_8 ucSeqNum; ++} MSG_P2P_SERVICE_DISCOVERY_REQUEST_T, *P_MSG_P2P_SERVICE_DISCOVERY_REQUEST_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define p2pChangeMediaState(_prAdapter, _eNewMediaState) \ ++do { \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState = (_eNewMediaState));\ ++ wfdChangeMediaState((_prAdapter), NETWORK_TYPE_P2P_INDEX, (_eNewMediaState)); \ ++} while (0) ++ ++#define ATTRI_ID(_fp) (((P_P2P_ATTRIBUTE_T) _fp)->ucId) ++#define ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[0]) | \ ++ ((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[1] << 8)) ++ ++#define ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + ATTRI_LEN(_fp)) ++ ++#define P2P_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += ATTRI_SIZE(_pucAttriBuf))) ++ ++#define P2P_IE(_fp) ((P_IE_P2P_T) _fp) ++ ++#define WSC_ATTRI_ID(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[1])) ++ ++#define WSC_ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[1])) ++ ++#define WSC_ATTRI_SIZE(_fp) (WSC_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) ++ ++#define WSC_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += WSC_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WSC_ATTRI_SIZE(_pucAttriBuf))) ++ ++#define WSC_IE(_fp) ((P_IE_P2P_T) _fp) ++ ++#define WFD_ATTRI_ID(_fp) (((P_WFD_ATTRIBUTE_T) _fp)->ucElemID) ++ ++#define WFD_ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[1])) ++ ++#define WFD_ATTRI_SIZE(_fp) (WFD_ATTRI_HDR_LEN + WFD_ATTRI_LEN(_fp)) ++ ++#define WFD_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += WFD_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WFD_ATTRI_SIZE(_pucAttriBuf))) ++ ++#if DBG ++#define ASSERT_BREAK(_exp) \ ++ { \ ++ if (!(_exp)) { \ ++ ASSERT(FALSE); \ ++ break; \ ++ } \ ++ } ++ ++#else ++#define ASSERT_BREAK(_exp) ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*======P2P State======*/ ++VOID ++p2pStateInit_LISTEN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prSP2pBssInfo, IN UINT_8 ucListenChannel); ++ ++VOID p2pStateAbort_LISTEN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); ++ ++VOID p2pStateAbort_SEARCH_SCAN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); ++ ++VOID p2pStateAbort_GO_OPERATION(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateAbort_GC_OPERATION(IN P_ADAPTER_T prAdapter); ++ ++VOID ++p2pStateInit_CONFIGURATION(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecBssInfo); ++ ++VOID p2pStateAbort_CONFIGURATION(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateInit_JOIN(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateAbort_JOIN(IN P_ADAPTER_T prAdapter); ++ ++/*====== P2P Functions ======*/ ++ ++VOID p2pFuncInitGO(IN P_ADAPTER_T prAdapter); ++ ++VOID ++p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++VOID ++p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW); ++ ++VOID p2pFuncRunEventProvisioningComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS p2pFuncSetGroupID(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucGroupID, IN PUINT_8 pucSsid, IN UINT_8 ucSsidLen); ++ ++WLAN_STATUS ++p2pFuncSendDeviceDiscoverabilityReqFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); ++ ++WLAN_STATUS ++p2pFuncSendDeviceDiscoverabilityRspFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); ++ ++UINT_8 p2pFuncGetVersionNumOfSD(IN P_ADAPTER_T prAdapter); ++ ++/*====== P2P FSM ======*/ ++VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDeviceDiscoveryRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDeviceDiscoveryAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventRxGroupNegotiationReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationResponseTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationConfirmTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventProvisionDiscoveryRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventProvisionDiscoveryResponseTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventInvitationRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if 1 ++#endif ++ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/*======Mail Box Event Message=====*/ ++ ++VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventConnectionTrigger(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventP2PFunctionSwitch(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventConnectionPause(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID ++p2pIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN UINT_8 aucTargetAddr[]); ++ ++VOID p2pUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++ ++/*======Mail Box Event Message=====*/ ++ ++VOID p2pFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStartGO(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); ++ ++VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventIOReqTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); ++ ++VOID p2pFsmRunEventSearchPeriodTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); ++ ++VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG u4Param); ++ ++VOID p2pFsmRunEventRejoinTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Parm); ++ ++/*=============== P2P Function Related ================*/ ++ ++/*=============== P2P Function Related ================*/ ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID p2pTest(IN P_ADAPTER_T prAdapter); ++#endif /* CFG_TEST_WIFI_DIRECT_GO */ ++ ++VOID p2pGenerateP2P_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID p2pGenerateP2P_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pCalculateP2P_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pCalculateP2P_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pGenerateWSC_IEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++p2pGenerateWSC_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_16 p2pCalculateWSC_IELenForProbeReq(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++UINT_32 ++p2pCalculateWSC_IELenForProbeResp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriStatus(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriGoIntent(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriCfgTimeout(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriGroupBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForBeacon(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForDeviceDiscoveryReq(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriListenChannel(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriIntendP2pIfAddr(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriChannelList(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenChannelList(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriNoA(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenDeviceInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriGroupInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenGroupInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriP2pGroupID(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriOperatingChannel(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriInvitationFlag(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++VOID ++p2pGenerateWscIE(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++UINT_32 ++p2pAppendAttriWSCConfigMethod(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCVersion(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCGONegReqDevPasswordId(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCGONegRspDevPasswordId(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++WLAN_STATUS ++p2pGetWscAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++WLAN_STATUS ++p2pGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pSendProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN p2pFsmRunEventRxProbeRequestFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc); ++ ++WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxGroupNegotiationRspFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxGroupNegotiationCfmFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#if 0 /* frog */ ++BOOLEAN scanMatchFilterOfP2P(IN P_SW_RFB_T prSWRfb, IN PP_BSS_DESC_T pprBssDesc); ++#endif /* frog */ ++ ++VOID ++p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); ++ ++VOID p2pFuncCompleteIOCTL(IN P_ADAPTER_T prAdapter, IN WLAN_STATUS rWlanStatus); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID p2pDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(IE_P2P_T) == (2 + 4 + 1)); /* all UINT_8 */ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRIBUTE_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_STATUS_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_REASON_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CAPABILITY_T) == (3 + 2)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_ID_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GO_INTENT_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CFG_TIMEOUT_T) == (3 + 2)); ++#if CID52_53_54 ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); ++#else ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); ++#endif ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_BSSID_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_EXT_LISTEN_TIMING_T) == (3 + 4)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTENDED_IF_ADDR_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_MANAGEABILITY_T) == (3 + 1)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CHANNEL_T) == (3 + 4)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(CHANNEL_ENTRY_FIELD_T) == 3); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_NOA_T) == (3 + 3)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(NOA_DESCRIPTOR_T) == 13); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_TYPE_T) == 8); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_INFO_T) == (3 + 6 + 2 + 8 + 1 + 8)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_NAME_TLV_T) == (4 + 32)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_CLIENT_INFO_DESC_T) == (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_INFO_T) == (3 + (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8))); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_ID_T) == (3 + 38)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTERFACE_T) == (3 + 13)); ++#if CID52_53_54 ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); ++#else ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); ++#endif ++ ++} ++#endif /* _lint */ ++ ++#endif /* _P2P_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h +new file mode 100644 +index 000000000000..1ac1770debca +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h +@@ -0,0 +1,155 @@ ++#ifndef _P2P_FUNC_H ++#define _P2P_FUNC_H ++ ++#define P2P_EXT_LISTEN_TIME_MS 600 ++#define P2P_OFF_CHNL_TX_DEFAULT_TIME_MS 1000 ++ ++VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID ++p2pFuncStartGO(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, ++ IN PUINT_8 pucSsidBuf, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP); ++ ++VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo); ++ ++BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo); ++ ++VOID ++p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++ ++WLAN_STATUS ++p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); ++ ++WLAN_STATUS ++p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, ++ IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, ++ IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen); ++ ++BOOLEAN ++p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings); ++ ++BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); ++ ++BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen); ++ ++P_BSS_DESC_T ++p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, ++ IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID ++p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, ++ IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter); ++ ++VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter); ++ ++VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo); ++ ++BOOLEAN ++p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu); ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++UINT_32 ++p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#else ++UINT_32 ++p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++#endif ++UINT_32 ++p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_STA_RECORD_T prStaRec, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++VOID ++p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++UINT_32 ++p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++VOID ++p2pFuncDissolve(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++P_IE_HDR_T ++p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore); ++ ++P_ATTRIBUTE_HDR_T ++p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID); ++ ++WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h +new file mode 100644 +index 000000000000..efb75855695f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h +@@ -0,0 +1,156 @@ ++#ifndef _P2P_IE_H ++#define _P2P_IE_H ++ ++#if CFG_SUPPORT_WFD ++ ++#define ELEM_MAX_LEN_WFD 62 /* TODO: Move to appropriate place */ ++ ++/*---------------- WFD Data Element Definitions ----------------*/ ++/* WFD 4.1.1 - WFD IE format */ ++#define WFD_OUI_TYPE_LEN 4 ++#define WFD_IE_OUI_HDR (ELEM_HDR_LEN + WFD_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, ++ aucP2PAttributes[0]) */ ++ ++/* WFD 4.1.1 - General WFD Attribute */ ++#define WFD_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ ++ ++/* WFD Attribute Code */ ++#define WFD_ATTRI_ID_DEV_INFO 0 ++#define WFD_ATTRI_ID_ASSOC_BSSID 1 ++#define WFD_ATTRI_ID_COUPLED_SINK_INFO 6 ++#define WFD_ATTRI_ID_EXT_CAPABILITY 7 ++#define WFD_ATTRI_ID_SESSION_INFO 9 ++#define WFD_ATTRI_ID_ALTER_MAC_ADDRESS 10 ++ ++/* Maximum Length of WFD Attributes */ ++#define WFD_ATTRI_MAX_LEN_DEV_INFO 6 /* 0 */ ++#define WFD_ATTRI_MAX_LEN_ASSOC_BSSID 6 /* 1 */ ++#define WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO 7 /* 6 */ ++#define WFD_ATTRI_MAX_LEN_EXT_CAPABILITY 2 /* 7 */ ++#define WFD_ATTRI_MAX_LEN_SESSION_INFO 0 /* 9 */ /* 24 * #Clients */ ++#define WFD_ATTRI_MAX_LEN_ALTER_MAC_ADDRESS 6 /* 10 */ ++ ++/* WFD 1.10 5.1.1 */ ++typedef struct _IE_WFD_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 aucWFDAttributes[1]; /* WFD Subelement */ ++} __KAL_ATTRIB_PACKED__ IE_WFD_T, *P_IE_WFD_T; ++ ++typedef struct _WFD_ATTRIBUTE_T { ++ UINT_8 ucElemID; /* Subelement ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ WFD_ATTRIBUTE_T, *P_WFD_ATTRIBUTE_T; ++ ++typedef struct _WFD_DEVICE_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2SessionMgmtCtrlPort; ++ UINT_16 u2WfdDevMaxSpeed; ++} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_IE_T, *P_WFD_DEVICE_INFORMATION_IE_T; ++ ++typedef struct _WFD_ASSOCIATED_BSSID_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_8 aucAssocBssid[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_ASSOCIATED_BSSID_IE_T, *P_WFD_ASSOCIATED_BSSID_IE_T; ++ ++typedef struct _WFD_COUPLE_SINK_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_8 ucCoupleSinkStatusBp; ++ UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_COUPLE_SINK_INFORMATION_IE_T, *P_WFD_COUPLE_SINK_INFORMATION_IE_T; ++ ++typedef struct _WFD_EXTENDED_CAPABILITY_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_16 u2WfdExtCapabilityBp; ++} __KAL_ATTRIB_PACKED__ WFD_EXTENDED_CAPABILITY_IE_T, *P_WFD_EXTENDED_CAPABILITY_IE_T; ++ ++typedef struct _WFD_SESSION_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ PUINT_8 pucWfdDevInfoDesc[1]; ++} __KAL_ATTRIB_PACKED__ WFD_SESSION_INFORMATION_IE_T, *P_WFD_SESSION_INFORMATION_IE_T; ++ ++typedef struct _WFD_DEVICE_INFORMATION_DESCRIPTOR_T { ++ UINT_8 ucLength; ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; ++ UINT_8 aucAssocBssid[MAC_ADDR_LEN]; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2WfdDevMaxSpeed; ++ UINT_8 ucCoupleSinkStatusBp; ++ UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_DESCRIPTOR_T, *P_WFD_DEVICE_INFORMATION_DESCRIPTOR_T; ++ ++#endif ++ ++UINT_32 ++p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#if CFG_SUPPORT_WFD ++ ++UINT_32 ++wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForProbeResp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#endif ++ ++UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h +new file mode 100644 +index 000000000000..32bc14c10959 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h +@@ -0,0 +1,74 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm.h#1 ++*/ ++ ++/*! \file "rlm.h" ++ \brief ++*/ ++ ++#ifndef _P2P_RLM_H ++#define _P2P_RLM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); ++ ++VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter); ++ ++VOID ++rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, ++ IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize); ++ ++UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum); ++ ++BOOLEAN ++rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCheckChnl, ++ IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel); ++ ++ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h +new file mode 100644 +index 000000000000..5b6e756f48dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h +@@ -0,0 +1,64 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm_obss.h#1 ++*/ ++ ++/*! \file "rlm_obss.h" ++ \brief ++*/ ++ ++#ifndef _P2P_RLM_OBSS_H ++#define _P2P_RLM_OBSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); ++ ++UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h +new file mode 100644 +index 000000000000..8db6aa5c31e0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h +@@ -0,0 +1,81 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_scan.h#1 ++*/ ++ ++/*! \file "scan.h" ++ \brief ++ ++*/ ++ ++#ifndef _P2P_SCAN_H ++#define _P2P_SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); ++ ++P_P2P_DEVICE_DESC_T ++scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc); ++ ++P_P2P_DEVICE_DESC_T ++scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, ++ IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound); ++ ++P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum); ++ ++BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ++scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); ++ ++VOID scanRemoveAllP2pBssDesc(P_ADAPTER_T prAdapter); ++ ++VOID scanRemoveP2pBssDesc(P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++P_BSS_DESC_T ++scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h +new file mode 100644 +index 000000000000..8f0c4c1564a8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h +@@ -0,0 +1,43 @@ ++#ifndef _P2P_STATE_H ++#define _P2P_STATE_H ++ ++BOOLEAN ++p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState); ++ ++VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ++p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h +new file mode 100644 +index 000000000000..c80430ae4eb5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h +@@ -0,0 +1,230 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/privacy.h#1 ++*/ ++ ++/*! \file privacy.h ++ \brief This file contains the function declaration for privacy.c. ++*/ ++ ++/* ++** Log: privacy.h ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * For support the WHQL test, do the remove key code refine. ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the cmd return type ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for auth mode and encryption status setting from build connection command ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for wapi ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the tx done callback handle function ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for mac header privacy bit setting ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the structure for parsing the EAPoL frame ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the class error function parameter ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security function declaration ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the ap selection structure ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++#ifndef _PRIVACY_H ++#define _PRIVACY_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_KEY_NUM 4 ++#define WEP_40_LEN 5 ++#define WEP_104_LEN 13 ++#define LEGACY_KEY_MAX_LEN 16 ++#define CCMP_KEY_LEN 16 ++#define TKIP_KEY_LEN 32 ++#define MAX_KEY_LEN 32 ++#define MIC_RX_KEY_OFFSET 16 ++#define MIC_TX_KEY_OFFSET 24 ++#define MIC_KEY_LEN 8 ++ ++#define WEP_KEY_ID_FIELD BITS(0, 29) ++#define KEY_ID_FIELD BITS(0, 7) ++ ++#define IS_TRANSMIT_KEY BIT(31) ++#define IS_UNICAST_KEY BIT(30) ++#define IS_AUTHENTICATOR BIT(28) ++ ++#define CIPHER_SUITE_NONE 0 ++#define CIPHER_SUITE_WEP40 1 ++#define CIPHER_SUITE_TKIP 2 ++#define CIPHER_SUITE_TKIP_WO_MIC 3 ++#define CIPHER_SUITE_CCMP 4 ++#define CIPHER_SUITE_WEP104 5 ++#define CIPHER_SUITE_BIP 6 ++#define CIPHER_SUITE_WEP128 7 ++#define CIPHER_SUITE_WPI 8 ++ ++#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ ++#define WPA_KEY_INFO_MIC BIT(8) ++#define WPA_KEY_INFO_SECURE BIT(9) ++ ++#define MASK_2ND_EAPOL (WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _IEEE_802_1X_HDR { ++ UINT_8 ucVersion; ++ UINT_8 ucType; ++ UINT_16 u2Length; ++ /* followed by length octets of data */ ++} IEEE_802_1X_HDR, *P_IEEE_802_1X_HDR; ++ ++typedef struct _EAPOL_KEY { ++ UINT_8 ucType; ++ /* Note: key_info, key_length, and key_data_length are unaligned */ ++ UINT_8 aucKeyInfo[2]; /* big endian */ ++ UINT_8 aucKeyLength[2]; /* big endian */ ++ UINT_8 aucReplayCounter[8]; ++ UINT_8 aucKeyNonce[16]; ++ UINT_8 aucKeyIv[16]; ++ UINT_8 aucKeyRsc[8]; ++ UINT_8 aucKeyId[8]; /* Reserved in IEEE 802.11i/RSN */ ++ UINT_8 aucKeyMic[16]; ++ UINT_8 aucKeyDataLength[2]; /* big endian */ ++ /* followed by key_data_length bytes of key_data */ ++} EAPOL_KEY, *P_EAPOL_KEY; ++ ++/* WPA2 PMKID candicate structure */ ++typedef struct _PMKID_CANDICATE_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_32 u4PreAuthFlags; ++} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; ++ ++#if 0 ++/* WPA2 PMKID cache structure */ ++typedef struct _PMKID_ENTRY_T { ++ PARAM_BSSID_INFO_T rBssidInfo; ++ BOOLEAN fgPmkidExist; ++} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx); ++ ++VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPort); ++ ++BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); ++ ++VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags); ++ ++BOOLEAN ++secProcessEAPOL(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen); ++ ++VOID ++secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T pMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus); ++ ++BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec); ++ ++VOID secClearPmkid(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PRIVACY_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h +new file mode 100644 +index 000000000000..123dbebdacaf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h +@@ -0,0 +1,93 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rate.h#1 ++*/ ++ ++/*! \file rate.h ++ \brief This file contains the rate utility function of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: rate.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _RATE_H ++#define _RATE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in rate.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, ++ IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, ++ OUT PUINT_16 pu2OperationalRateSet, ++ OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate); ++ ++VOID ++rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen); ++ ++BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex); ++ ++BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RATE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h +new file mode 100644 +index 000000000000..1af3841ecec2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h +@@ -0,0 +1,396 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm.h#2 ++*/ ++ ++/*! \file "rlm.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Use SCO of BSS_INFO to replace user-defined setting variables ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 18 2010 cm.chang ++ * [WCXRP00000114] [MT6620 Wi-Fi] [Driver] Fix compiling warning in Linux about RLM network index checking ++ * Enum member cannot be used as compiling option decision in Linux ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX HT GF compiling option ++ * ++ * 06 02 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Roll back to remove CFG_SUPPORT_BCM_TEST. ++ * ++ * 06 01 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Update BCM Test and RW configuration. ++ * ++ * 05 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some compiling options to control 11n functions ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 17 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * MT6620 does not support L-SIG TXOP ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Move default value of HT capability to rlm.h ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * ++ * Modify the prototype of rlmRecAssocRspHtInfo() ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add several function prototypes for HT operation ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++#ifndef _RLM_H ++#define _RLM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define ELEM_EXT_CAP_DEFAULT_VAL \ ++ (ELEM_EXT_CAP_20_40_COEXIST_SUPPORT /*| ELEM_EXT_CAP_PSMP_CAP*/) ++ ++#if CFG_SUPPORT_RX_STBC ++#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_1_SS ++#else ++#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_NO_SUPPORTED ++#endif ++ ++#if CFG_SUPPORT_RX_SGI ++#define FIELD_HT_CAP_INFO_SGI_20M HT_CAP_INFO_SHORT_GI_20M ++#define FIELD_HT_CAP_INFO_SGI_40M HT_CAP_INFO_SHORT_GI_40M ++#else ++#define FIELD_HT_CAP_INFO_SGI_20M 0 ++#define FIELD_HT_CAP_INFO_SGI_40M 0 ++#endif ++ ++#if CFG_SUPPORT_RX_HT_GF ++#define FIELD_HT_CAP_INFO_HT_GF HT_CAP_INFO_HT_GF ++#else ++#define FIELD_HT_CAP_INFO_HT_GF 0 ++#endif ++ ++#define HT_CAP_INFO_DEFAULT_VAL \ ++ (HT_CAP_INFO_SUP_CHNL_WIDTH | FIELD_HT_CAP_INFO_HT_GF | \ ++ FIELD_HT_CAP_INFO_SGI_20M | FIELD_HT_CAP_INFO_SGI_40M | \ ++ FIELD_HT_CAP_INFO_RX_STBC | HT_CAP_INFO_DSSS_CCK_IN_40M) ++ ++#define AMPDU_PARAM_DEFAULT_VAL \ ++ (AMPDU_PARAM_MAX_AMPDU_LEN_64K | AMPDU_PARAM_MSS_NO_RESTRICIT) ++ ++#define SUP_MCS_TX_DEFAULT_VAL \ ++ SUP_MCS_TX_SET_DEFINED /* TX defined and TX/RX equal (TBD) */ ++ ++#if CFG_SUPPORT_MFB ++#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_BOTH ++#else ++#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_NO_FB ++#endif ++ ++#if CFG_SUPPORT_RX_RDG ++#define FIELD_HT_EXT_CAP_RDR HT_EXT_CAP_RD_RESPONDER ++#else ++#define FIELD_HT_EXT_CAP_RDR 0 ++#endif ++ ++#if CFG_SUPPORT_MFB || CFG_SUPPORT_RX_RDG ++#define FIELD_HT_EXT_CAP_HTC HT_EXT_CAP_HTC_SUPPORT ++#else ++#define FIELD_HT_EXT_CAP_HTC 0 ++#endif ++ ++#define HT_EXT_CAP_DEFAULT_VAL \ ++ (HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE | \ ++ FIELD_HT_EXT_CAP_MFB | FIELD_HT_EXT_CAP_HTC | \ ++ FIELD_HT_EXT_CAP_RDR) ++ ++#define TX_BEAMFORMING_CAP_DEFAULT_VAL 0 ++#define ASEL_CAP_DEFAULT_VAL 0 ++ ++/* Define bandwidth from user setting */ ++#define CONFIG_BW_20_40M 0 ++#define CONFIG_BW_20M 1 /* 20MHz only */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* It is used for RLM module to judge if specific network is valid ++ * Note: Ad-hoc mode of AIS is not included now. (TBD) ++ */ ++#define RLM_NET_PARAM_VALID(_prBssInfo) \ ++ (IS_BSS_ACTIVE(_prBssInfo) && \ ++ ((_prBssInfo)->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || \ ++ (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT || \ ++ (_prBssInfo)->eCurrentOPMode == OP_MODE_IBSS || \ ++ RLM_NET_IS_BOW(_prBssInfo)) \ ++ ) ++ ++#define RLM_NET_IS_11N(_prBssInfo) \ ++ ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11N) ++#define RLM_NET_IS_11GN(_prBssInfo) \ ++ ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11GN) ++ ++/* This macro is used to sweep all 3 networks */ ++#define RLM_NET_FOR_EACH(_ucNetIdx) \ ++ for ((_ucNetIdx) = 0; \ ++ (_ucNetIdx) < NETWORK_TYPE_INDEX_NUM; \ ++ (_ucNetIdx)++) ++ ++/* This macro is used to sweep all networks excluding BOW */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /* Note: value of enum NETWORK_TYPE_BOW_INDEX is validated in ++ * rlmStuctureCheck(). ++ */ ++#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) \ ++ for ((_ucNetIdx) = 0; \ ++ (_ucNetIdx) < NETWORK_TYPE_BOW_INDEX; \ ++ (_ucNetIdx)++) ++ ++#define RLM_NET_IS_BOW(_prBssInfo) \ ++ ((_prBssInfo)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ ++#else ++#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) RLM_NET_FOR_EACH(_ucNetIdx) ++#define RLM_NET_IS_BOW(_prBssInfo) (FALSE) ++ ++#endif /* end of CFG_ENABLE_BT_OVER_WIFI */ ++ ++/* The bandwidth modes are not used anymore. They represent if AP ++ * can use 20/40 bandwidth, not all modes. (20110411) ++ */ ++#define RLM_AP_IS_BW_40_ALLOWED(_prAdapter, _prBssInfo) \ ++ (((_prBssInfo)->eBand == BAND_2G4 && \ ++ (_prAdapter)->rWifiVar.rConnSettings.uc2G4BandwidthMode \ ++ == CONFIG_BW_20_40M) || \ ++ ((_prBssInfo)->eBand == BAND_5G && \ ++ (_prAdapter)->rWifiVar.rConnSettings.uc5GBandwidthMode \ ++ == CONFIG_BW_20_40M)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID rlmFsmEventInit(P_ADAPTER_T prAdapter); ++ ++VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter); ++ ++VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++UINT32 ++rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, ++ BOOLEAN fgShortGIDisabled, ++ UINT_8 u8SupportRxSgi20, ++ UINT_8 u8SupportRxSgi40, ++ UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf); ++ ++UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme); ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE); ++#endif ++ ++VOID ++rlmTxRateEnhanceConfig( ++ P_ADAPTER_T prAdapter ++ ); ++ ++VOID ++rlmCmd( ++ P_GLUE_INFO_T prGlueInfo, ++ UINT_8 *prInBuf, ++ UINT_32 u4InBufLen ++ ); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#ifndef _lint ++static inline VOID rlmDataTypeCheck(VOID) ++{ ++#if CFG_ENABLE_BT_OVER_WIFI ++ DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_AIS_INDEX < NETWORK_TYPE_BOW_INDEX); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_P2P_INDEX < NETWORK_TYPE_BOW_INDEX); ++#endif ++#endif ++ ++} ++#endif /* _lint */ ++ ++#endif /* _RLM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h +new file mode 100644 +index 000000000000..65e907041a28 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h +@@ -0,0 +1,557 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_domain.h#1 ++*/ ++ ++/*! \file "rlm_domain.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_domain.h ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Provide legal channel function based on domain ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 01 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide query function about full channel list. ++ * ++ * Dec 1 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Declare public rDomainInfo ++ * ++** ++*/ ++ ++#ifndef _RLM_DOMAIN_H ++#define _RLM_DOMAIN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_SUBBAND_NUM 6 ++#define MAX_SUBBAND_NUM_5G 8 ++ ++#define COUNTRY_CODE_NULL ((UINT_16)0x0) ++ ++/* ISO/IEC 3166-1 two-character country codes */ ++ ++#define COUNTRY_CODE_AD (((UINT_16) 'A' << 8) | (UINT_16) 'D') /* Andorra */ ++#define COUNTRY_CODE_AE (((UINT_16) 'A' << 8) | (UINT_16) 'E') /* UAE */ ++#define COUNTRY_CODE_AF (((UINT_16) 'A' << 8) | (UINT_16) 'F') /* Afghanistan */ ++#define COUNTRY_CODE_AG (((UINT_16) 'A' << 8) | (UINT_16) 'G') /* Antigua & Barbuda */ ++#define COUNTRY_CODE_AI (((UINT_16) 'A' << 8) | (UINT_16) 'I') /* Anguilla */ ++#define COUNTRY_CODE_AL (((UINT_16) 'A' << 8) | (UINT_16) 'L') /* Albania */ ++#define COUNTRY_CODE_AM (((UINT_16) 'A' << 8) | (UINT_16) 'M') /* Armenia */ ++#define COUNTRY_CODE_AN (((UINT_16) 'A' << 8) | (UINT_16) 'N') /* Netherlands Antilles */ ++#define COUNTRY_CODE_AO (((UINT_16) 'A' << 8) | (UINT_16) 'O') /* Angola */ ++#define COUNTRY_CODE_AR (((UINT_16) 'A' << 8) | (UINT_16) 'R') /* Argentina */ ++#define COUNTRY_CODE_AS (((UINT_16) 'A' << 8) | (UINT_16) 'S') /* American Samoa (USA) */ ++#define COUNTRY_CODE_AT (((UINT_16) 'A' << 8) | (UINT_16) 'T') /* Austria */ ++#define COUNTRY_CODE_AU (((UINT_16) 'A' << 8) | (UINT_16) 'U') /* Australia */ ++#define COUNTRY_CODE_AW (((UINT_16) 'A' << 8) | (UINT_16) 'W') /* Aruba */ ++#define COUNTRY_CODE_AZ (((UINT_16) 'A' << 8) | (UINT_16) 'Z') /* Azerbaijan */ ++#define COUNTRY_CODE_BA (((UINT_16) 'B' << 8) | (UINT_16) 'A') /* Bosnia and Herzegovina */ ++#define COUNTRY_CODE_BB (((UINT_16) 'B' << 8) | (UINT_16) 'B') /* Barbados */ ++#define COUNTRY_CODE_BD (((UINT_16) 'B' << 8) | (UINT_16) 'D') /* Bangladesh */ ++#define COUNTRY_CODE_BE (((UINT_16) 'B' << 8) | (UINT_16) 'E') /* Belgium */ ++#define COUNTRY_CODE_BF (((UINT_16) 'B' << 8) | (UINT_16) 'F') /* Burkina Faso */ ++#define COUNTRY_CODE_BG (((UINT_16) 'B' << 8) | (UINT_16) 'G') /* Bulgaria */ ++#define COUNTRY_CODE_BH (((UINT_16) 'B' << 8) | (UINT_16) 'H') /* Bahrain */ ++#define COUNTRY_CODE_BI (((UINT_16) 'B' << 8) | (UINT_16) 'I') /* Burundi */ ++#define COUNTRY_CODE_BJ (((UINT_16) 'B' << 8) | (UINT_16) 'J') /* Benin */ ++#define COUNTRY_CODE_BM (((UINT_16) 'B' << 8) | (UINT_16) 'M') /* Bermuda */ ++#define COUNTRY_CODE_BN (((UINT_16) 'B' << 8) | (UINT_16) 'N') /* Brunei */ ++#define COUNTRY_CODE_BO (((UINT_16) 'B' << 8) | (UINT_16) 'O') /* Bolivia */ ++#define COUNTRY_CODE_BR (((UINT_16) 'B' << 8) | (UINT_16) 'R') /* Brazil */ ++#define COUNTRY_CODE_BS (((UINT_16) 'B' << 8) | (UINT_16) 'S') /* Bahamas */ ++#define COUNTRY_CODE_BT (((UINT_16) 'B' << 8) | (UINT_16) 'T') /* Bhutan */ ++#define COUNTRY_CODE_BW (((UINT_16) 'B' << 8) | (UINT_16) 'W') /* Botswana */ ++#define COUNTRY_CODE_BY (((UINT_16) 'B' << 8) | (UINT_16) 'Y') /* Belarus */ ++#define COUNTRY_CODE_BZ (((UINT_16) 'B' << 8) | (UINT_16) 'Z') /* Belize */ ++#define COUNTRY_CODE_CA (((UINT_16) 'C' << 8) | (UINT_16) 'A') /* Canada */ ++#define COUNTRY_CODE_CD (((UINT_16) 'C' << 8) | (UINT_16) 'D') /* Congo. Democratic Republic of the */ ++#define COUNTRY_CODE_CF (((UINT_16) 'C' << 8) | (UINT_16) 'F') /* Central African Republic */ ++#define COUNTRY_CODE_CG (((UINT_16) 'C' << 8) | (UINT_16) 'G') /* Congo. Republic of the */ ++#define COUNTRY_CODE_CH (((UINT_16) 'C' << 8) | (UINT_16) 'H') /* Switzerland */ ++#define COUNTRY_CODE_CI (((UINT_16) 'C' << 8) | (UINT_16) 'I') /* Cote d'lvoire */ ++#define COUNTRY_CODE_CK (((UINT_16) 'C' << 8) | (UINT_16) 'K') /* Cook Island */ ++#define COUNTRY_CODE_CL (((UINT_16) 'C' << 8) | (UINT_16) 'L') /* Chile */ ++#define COUNTRY_CODE_CM (((UINT_16) 'C' << 8) | (UINT_16) 'M') /* Cameroon */ ++#define COUNTRY_CODE_CN (((UINT_16) 'C' << 8) | (UINT_16) 'N') /* China */ ++#define COUNTRY_CODE_CO (((UINT_16) 'C' << 8) | (UINT_16) 'O') /* Columbia */ ++#define COUNTRY_CODE_CR (((UINT_16) 'C' << 8) | (UINT_16) 'R') /* Costa Rica */ ++#define COUNTRY_CODE_CU (((UINT_16) 'C' << 8) | (UINT_16) 'U') /* Cuba */ ++#define COUNTRY_CODE_CV (((UINT_16) 'C' << 8) | (UINT_16) 'V') /* Cape Verde */ ++#define COUNTRY_CODE_CX (((UINT_16) 'C' << 8) | (UINT_16) 'X') /* "Christmas Island(Australia) */ ++#define COUNTRY_CODE_CY (((UINT_16) 'C' << 8) | (UINT_16) 'Y') /* Cyprus */ ++#define COUNTRY_CODE_CZ (((UINT_16) 'C' << 8) | (UINT_16) 'Z') /* Czech */ ++#define COUNTRY_CODE_DE (((UINT_16) 'D' << 8) | (UINT_16) 'E') /* Germany */ ++#define COUNTRY_CODE_DJ (((UINT_16) 'D' << 8) | (UINT_16) 'J') /* Djibouti */ ++#define COUNTRY_CODE_DK (((UINT_16) 'D' << 8) | (UINT_16) 'K') /* Denmark */ ++#define COUNTRY_CODE_DM (((UINT_16) 'D' << 8) | (UINT_16) 'M') /* Dominica */ ++#define COUNTRY_CODE_DO (((UINT_16) 'D' << 8) | (UINT_16) 'O') /* Dominican Republic */ ++#define COUNTRY_CODE_DZ (((UINT_16) 'D' << 8) | (UINT_16) 'Z') /* Algeria */ ++#define COUNTRY_CODE_EC (((UINT_16) 'E' << 8) | (UINT_16) 'C') /* Ecuador */ ++#define COUNTRY_CODE_EE (((UINT_16) 'E' << 8) | (UINT_16) 'E') /* Estonia */ ++#define COUNTRY_CODE_EG (((UINT_16) 'E' << 8) | (UINT_16) 'G') /* Egypt */ ++#define COUNTRY_CODE_EH (((UINT_16) 'E' << 8) | (UINT_16) 'H') /* Western Sahara (Morocco) */ ++#define COUNTRY_CODE_ER (((UINT_16) 'E' << 8) | (UINT_16) 'R') /* Eritrea */ ++#define COUNTRY_CODE_ES (((UINT_16) 'E' << 8) | (UINT_16) 'S') /* Spain */ ++#define COUNTRY_CODE_ET (((UINT_16) 'E' << 8) | (UINT_16) 'T') /* Ethiopia */ ++#define COUNTRY_CODE_EU (((UINT_16) 'E' << 8) | (UINT_16) 'U') /* Europe */ ++#define COUNTRY_CODE_FI (((UINT_16) 'F' << 8) | (UINT_16) 'I') /* Finland */ ++#define COUNTRY_CODE_FJ (((UINT_16) 'F' << 8) | (UINT_16) 'J') /* Fiji */ ++#define COUNTRY_CODE_FK (((UINT_16) 'F' << 8) | (UINT_16) 'K') /* Falkland Island */ ++#define COUNTRY_CODE_FM (((UINT_16) 'F' << 8) | (UINT_16) 'M') /* Micronesia */ ++#define COUNTRY_CODE_FO (((UINT_16) 'F' << 8) | (UINT_16) 'O') /* Faroe Island */ ++#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* France */ ++#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* Wallis and Futuna (France) */ ++#define COUNTRY_CODE_GA (((UINT_16) 'G' << 8) | (UINT_16) 'A') /* Gabon */ ++#define COUNTRY_CODE_GB (((UINT_16) 'G' << 8) | (UINT_16) 'B') /* United Kingdom */ ++#define COUNTRY_CODE_GD (((UINT_16) 'G' << 8) | (UINT_16) 'D') /* Grenada */ ++#define COUNTRY_CODE_GE (((UINT_16) 'G' << 8) | (UINT_16) 'E') /* Georgia */ ++#define COUNTRY_CODE_GF (((UINT_16) 'G' << 8) | (UINT_16) 'F') /* French Guiana */ ++#define COUNTRY_CODE_GG (((UINT_16) 'G' << 8) | (UINT_16) 'G') /* Guernsey */ ++#define COUNTRY_CODE_GH (((UINT_16) 'G' << 8) | (UINT_16) 'H') /* Ghana */ ++#define COUNTRY_CODE_GI (((UINT_16) 'G' << 8) | (UINT_16) 'I') /* Gibraltar */ ++#define COUNTRY_CODE_GM (((UINT_16) 'G' << 8) | (UINT_16) 'M') /* Gambia */ ++#define COUNTRY_CODE_GN (((UINT_16) 'G' << 8) | (UINT_16) 'N') /* Guinea */ ++#define COUNTRY_CODE_GP (((UINT_16) 'G' << 8) | (UINT_16) 'P') /* Guadeloupe */ ++#define COUNTRY_CODE_GQ (((UINT_16) 'G' << 8) | (UINT_16) 'Q') /* Equatorial Guinea */ ++#define COUNTRY_CODE_GR (((UINT_16) 'G' << 8) | (UINT_16) 'R') /* Greece */ ++#define COUNTRY_CODE_GT (((UINT_16) 'G' << 8) | (UINT_16) 'T') /* Guatemala */ ++#define COUNTRY_CODE_GU (((UINT_16) 'G' << 8) | (UINT_16) 'U') /* Guam */ ++#define COUNTRY_CODE_GW (((UINT_16) 'G' << 8) | (UINT_16) 'W') /* Guinea-Bissau */ ++#define COUNTRY_CODE_GY (((UINT_16) 'G' << 8) | (UINT_16) 'Y') /* Guyana */ ++#define COUNTRY_CODE_HK (((UINT_16) 'H' << 8) | (UINT_16) 'K') /* Hong Kong */ ++#define COUNTRY_CODE_HN (((UINT_16) 'H' << 8) | (UINT_16) 'N') /* Honduras */ ++#define COUNTRY_CODE_HR (((UINT_16) 'H' << 8) | (UINT_16) 'R') /* Croatia */ ++#define COUNTRY_CODE_HT (((UINT_16) 'H' << 8) | (UINT_16) 'T') /* Haiti */ ++#define COUNTRY_CODE_HU (((UINT_16) 'H' << 8) | (UINT_16) 'U') /* Hungary */ ++#define COUNTRY_CODE_ID (((UINT_16) 'I' << 8) | (UINT_16) 'D') /* Indonesia */ ++#define COUNTRY_CODE_IE (((UINT_16) 'I' << 8) | (UINT_16) 'E') /* Ireland */ ++#define COUNTRY_CODE_IL (((UINT_16) 'I' << 8) | (UINT_16) 'L') /* Israel */ ++#define COUNTRY_CODE_IM (((UINT_16) 'I' << 8) | (UINT_16) 'M') /* Isle of Man */ ++#define COUNTRY_CODE_IN (((UINT_16) 'I' << 8) | (UINT_16) 'N') /* India */ ++#define COUNTRY_CODE_IQ (((UINT_16) 'I' << 8) | (UINT_16) 'Q') /* Iraq */ ++#define COUNTRY_CODE_IR (((UINT_16) 'I' << 8) | (UINT_16) 'R') /* Iran */ ++#define COUNTRY_CODE_IS (((UINT_16) 'I' << 8) | (UINT_16) 'S') /* Iceland */ ++#define COUNTRY_CODE_IT (((UINT_16) 'I' << 8) | (UINT_16) 'T') /* Italy */ ++#define COUNTRY_CODE_JE (((UINT_16) 'J' << 8) | (UINT_16) 'E') /* Jersey */ ++#define COUNTRY_CODE_JM (((UINT_16) 'J' << 8) | (UINT_16) 'M') /* Jameica */ ++#define COUNTRY_CODE_JO (((UINT_16) 'J' << 8) | (UINT_16) 'O') /* Jordan */ ++#define COUNTRY_CODE_JP (((UINT_16) 'J' << 8) | (UINT_16) 'P') /* Japan */ ++#define COUNTRY_CODE_KE (((UINT_16) 'K' << 8) | (UINT_16) 'E') /* Kenya */ ++#define COUNTRY_CODE_KG (((UINT_16) 'K' << 8) | (UINT_16) 'G') /* Kyrgyzstan */ ++#define COUNTRY_CODE_KH (((UINT_16) 'K' << 8) | (UINT_16) 'H') /* Cambodia */ ++#define COUNTRY_CODE_KI (((UINT_16) 'K' << 8) | (UINT_16) 'I') /* Kiribati */ ++#define COUNTRY_CODE_KM (((UINT_16) 'K' << 8) | (UINT_16) 'M') /* Comoros */ ++#define COUNTRY_CODE_KN (((UINT_16) 'K' << 8) | (UINT_16) 'N') /* Saint Kitts and Nevis */ ++#define COUNTRY_CODE_KP (((UINT_16) 'K' << 8) | (UINT_16) 'P') /* North Korea */ ++#define COUNTRY_CODE_KR (((UINT_16) 'K' << 8) | (UINT_16) 'R') /* South Korea */ ++#define COUNTRY_CODE_KW (((UINT_16) 'K' << 8) | (UINT_16) 'W') /* Kuwait */ ++#define COUNTRY_CODE_KY (((UINT_16) 'K' << 8) | (UINT_16) 'Y') /* Cayman Islands */ ++#define COUNTRY_CODE_KZ (((UINT_16) 'K' << 8) | (UINT_16) 'Z') /* Kazakhstan */ ++#define COUNTRY_CODE_LA (((UINT_16) 'L' << 8) | (UINT_16) 'A') /* Laos */ ++#define COUNTRY_CODE_LB (((UINT_16) 'L' << 8) | (UINT_16) 'B') /* Lebanon */ ++#define COUNTRY_CODE_LC (((UINT_16) 'L' << 8) | (UINT_16) 'C') /* Saint Lucia */ ++#define COUNTRY_CODE_LI (((UINT_16) 'L' << 8) | (UINT_16) 'I') /* Liechtenstein */ ++#define COUNTRY_CODE_LK (((UINT_16) 'L' << 8) | (UINT_16) 'K') /* Sri Lanka */ ++#define COUNTRY_CODE_LR (((UINT_16) 'L' << 8) | (UINT_16) 'R') /* Liberia */ ++#define COUNTRY_CODE_LS (((UINT_16) 'L' << 8) | (UINT_16) 'S') /* Lesotho */ ++#define COUNTRY_CODE_LT (((UINT_16) 'L' << 8) | (UINT_16) 'T') /* Lithuania */ ++#define COUNTRY_CODE_LU (((UINT_16) 'L' << 8) | (UINT_16) 'U') /* Luxemburg */ ++#define COUNTRY_CODE_LV (((UINT_16) 'L' << 8) | (UINT_16) 'V') /* Latvia */ ++#define COUNTRY_CODE_LY (((UINT_16) 'L' << 8) | (UINT_16) 'Y') /* Libya */ ++#define COUNTRY_CODE_MA (((UINT_16) 'M' << 8) | (UINT_16) 'A') /* Morocco */ ++#define COUNTRY_CODE_MC (((UINT_16) 'M' << 8) | (UINT_16) 'C') /* Monaco */ ++#define COUNTRY_CODE_MD (((UINT_16) 'M' << 8) | (UINT_16) 'D') /* Moldova */ ++#define COUNTRY_CODE_ME (((UINT_16) 'M' << 8) | (UINT_16) 'E') /* Montenegro */ ++#define COUNTRY_CODE_MF (((UINT_16) 'M' << 8) | (UINT_16) 'F') /* Saint Martin / Sint Marteen ++ (Added on window's list) */ ++#define COUNTRY_CODE_MG (((UINT_16) 'M' << 8) | (UINT_16) 'G') /* Madagascar */ ++#define COUNTRY_CODE_MH (((UINT_16) 'M' << 8) | (UINT_16) 'H') /* Marshall Islands */ ++#define COUNTRY_CODE_MK (((UINT_16) 'M' << 8) | (UINT_16) 'K') /* Macedonia */ ++#define COUNTRY_CODE_ML (((UINT_16) 'M' << 8) | (UINT_16) 'L') /* Mali */ ++#define COUNTRY_CODE_MM (((UINT_16) 'M' << 8) | (UINT_16) 'M') /* Myanmar */ ++#define COUNTRY_CODE_MN (((UINT_16) 'M' << 8) | (UINT_16) 'N') /* Mongolia */ ++#define COUNTRY_CODE_MO (((UINT_16) 'M' << 8) | (UINT_16) 'O') /* Macao */ ++#define COUNTRY_CODE_MP (((UINT_16) 'M' << 8) | (UINT_16) 'P') /* Northern Mariana Islands (Rota Island. ++ Saipan and Tinian Island) */ ++#define COUNTRY_CODE_MQ (((UINT_16) 'M' << 8) | (UINT_16) 'Q') /* Martinique (France) */ ++#define COUNTRY_CODE_MR (((UINT_16) 'M' << 8) | (UINT_16) 'R') /* Mauritania */ ++#define COUNTRY_CODE_MS (((UINT_16) 'M' << 8) | (UINT_16) 'S') /* Montserrat (UK) */ ++#define COUNTRY_CODE_MT (((UINT_16) 'M' << 8) | (UINT_16) 'T') /* Malta */ ++#define COUNTRY_CODE_MU (((UINT_16) 'M' << 8) | (UINT_16) 'U') /* Mauritius */ ++#define COUNTRY_CODE_MV (((UINT_16) 'M' << 8) | (UINT_16) 'V') /* Maldives */ ++#define COUNTRY_CODE_MW (((UINT_16) 'M' << 8) | (UINT_16) 'W') /* Malawi */ ++#define COUNTRY_CODE_MX (((UINT_16) 'M' << 8) | (UINT_16) 'X') /* Mexico */ ++#define COUNTRY_CODE_MY (((UINT_16) 'M' << 8) | (UINT_16) 'Y') /* Malaysia */ ++#define COUNTRY_CODE_MZ (((UINT_16) 'M' << 8) | (UINT_16) 'Z') /* Mozambique */ ++#define COUNTRY_CODE_NA (((UINT_16) 'N' << 8) | (UINT_16) 'A') /* Namibia */ ++#define COUNTRY_CODE_NC (((UINT_16) 'N' << 8) | (UINT_16) 'C') /* New Caledonia */ ++#define COUNTRY_CODE_NE (((UINT_16) 'N' << 8) | (UINT_16) 'E') /* Niger */ ++#define COUNTRY_CODE_NF (((UINT_16) 'N' << 8) | (UINT_16) 'F') /* Norfolk Island */ ++#define COUNTRY_CODE_NG (((UINT_16) 'N' << 8) | (UINT_16) 'G') /* Nigeria */ ++#define COUNTRY_CODE_NI (((UINT_16) 'N' << 8) | (UINT_16) 'I') /* Nicaragua */ ++#define COUNTRY_CODE_NL (((UINT_16) 'N' << 8) | (UINT_16) 'L') /* Netherlands */ ++#define COUNTRY_CODE_NO (((UINT_16) 'N' << 8) | (UINT_16) 'O') /* Norway */ ++#define COUNTRY_CODE_NP (((UINT_16) 'N' << 8) | (UINT_16) 'P') /* Nepal */ ++#define COUNTRY_CODE_NR (((UINT_16) 'N' << 8) | (UINT_16) 'R') /* Nauru */ ++#define COUNTRY_CODE_NU (((UINT_16) 'N' << 8) | (UINT_16) 'U') /* Niue */ ++#define COUNTRY_CODE_NZ (((UINT_16) 'N' << 8) | (UINT_16) 'Z') /* New Zealand */ ++#define COUNTRY_CODE_OM (((UINT_16) 'O' << 8) | (UINT_16) 'M') /* Oman */ ++#define COUNTRY_CODE_PA (((UINT_16) 'P' << 8) | (UINT_16) 'A') /* Panama */ ++#define COUNTRY_CODE_PE (((UINT_16) 'P' << 8) | (UINT_16) 'E') /* Peru */ ++#define COUNTRY_CODE_PF (((UINT_16) 'P' << 8) | (UINT_16) 'F') /* "French Polynesia */ ++#define COUNTRY_CODE_PG (((UINT_16) 'P' << 8) | (UINT_16) 'G') /* Papua New Guinea */ ++#define COUNTRY_CODE_PH (((UINT_16) 'P' << 8) | (UINT_16) 'H') /* Philippines */ ++#define COUNTRY_CODE_PK (((UINT_16) 'P' << 8) | (UINT_16) 'K') /* Pakistan */ ++#define COUNTRY_CODE_PL (((UINT_16) 'P' << 8) | (UINT_16) 'L') /* Poland */ ++#define COUNTRY_CODE_PM (((UINT_16) 'P' << 8) | (UINT_16) 'M') /* Saint Pierre and Miquelon */ ++#define COUNTRY_CODE_PN (((UINT_16) 'P' << 8) | (UINT_16) 'N') /* Pitcairn Islands */ ++#define COUNTRY_CODE_PR (((UINT_16) 'P' << 8) | (UINT_16) 'R') /* Puerto Rico (USA) */ ++#define COUNTRY_CODE_PS (((UINT_16) 'P' << 8) | (UINT_16) 'S') /* Palestinian Authority */ ++#define COUNTRY_CODE_PT (((UINT_16) 'P' << 8) | (UINT_16) 'T') /* Portugal */ ++#define COUNTRY_CODE_PW (((UINT_16) 'P' << 8) | (UINT_16) 'W') /* Palau */ ++#define COUNTRY_CODE_PY (((UINT_16) 'P' << 8) | (UINT_16) 'Y') /* Paraguay */ ++#define COUNTRY_CODE_QA (((UINT_16) 'Q' << 8) | (UINT_16) 'A') /* Qatar */ ++#define COUNTRY_CODE_RE (((UINT_16) 'R' << 8) | (UINT_16) 'E') /* Reunion (France) */ ++#define COUNTRY_CODE_RKS (((UINT_16) 'R' << 8) | (UINT_16) 'K') /* Kosvo (Added on window's list) */ ++#define COUNTRY_CODE_RO (((UINT_16) 'R' << 8) | (UINT_16) 'O') /* Romania */ ++#define COUNTRY_CODE_RS (((UINT_16) 'R' << 8) | (UINT_16) 'S') /* Serbia */ ++#define COUNTRY_CODE_RU (((UINT_16) 'R' << 8) | (UINT_16) 'U') /* Russia */ ++#define COUNTRY_CODE_RW (((UINT_16) 'R' << 8) | (UINT_16) 'W') /* Rwanda */ ++#define COUNTRY_CODE_SA (((UINT_16) 'S' << 8) | (UINT_16) 'A') /* Saudi Arabia */ ++#define COUNTRY_CODE_SB (((UINT_16) 'S' << 8) | (UINT_16) 'B') /* Solomon Islands */ ++#define COUNTRY_CODE_SC (((UINT_16) 'S' << 8) | (UINT_16) 'C') /* Seychelles */ ++#define COUNTRY_CODE_SD (((UINT_16) 'S' << 8) | (UINT_16) 'D') /* Sudan */ ++#define COUNTRY_CODE_SE (((UINT_16) 'S' << 8) | (UINT_16) 'E') /* Sweden */ ++#define COUNTRY_CODE_SG (((UINT_16) 'S' << 8) | (UINT_16) 'G') /* Singapole */ ++#define COUNTRY_CODE_SI (((UINT_16) 'S' << 8) | (UINT_16) 'I') /* Slovenia */ ++#define COUNTRY_CODE_SK (((UINT_16) 'S' << 8) | (UINT_16) 'K') /* Slovakia */ ++#define COUNTRY_CODE_SL (((UINT_16) 'S' << 8) | (UINT_16) 'L') /* Sierra Leone */ ++#define COUNTRY_CODE_SM (((UINT_16) 'S' << 8) | (UINT_16) 'M') /* San Marino */ ++#define COUNTRY_CODE_SN (((UINT_16) 'S' << 8) | (UINT_16) 'N') /* Senegal */ ++#define COUNTRY_CODE_SO (((UINT_16) 'S' << 8) | (UINT_16) 'O') /* Somalia */ ++#define COUNTRY_CODE_SR (((UINT_16) 'S' << 8) | (UINT_16) 'R') /* Suriname */ ++#define COUNTRY_CODE_SS (((UINT_16) 'S' << 8) | (UINT_16) 'S') /* South_Sudan */ ++#define COUNTRY_CODE_ST (((UINT_16) 'S' << 8) | (UINT_16) 'T') /* Sao Tome and Principe */ ++#define COUNTRY_CODE_SV (((UINT_16) 'S' << 8) | (UINT_16) 'V') /* El Salvador */ ++#define COUNTRY_CODE_SY (((UINT_16) 'S' << 8) | (UINT_16) 'Y') /* Syria */ ++#define COUNTRY_CODE_SZ (((UINT_16) 'S' << 8) | (UINT_16) 'Z') /* Swaziland */ ++#define COUNTRY_CODE_TC (((UINT_16) 'T' << 8) | (UINT_16) 'C') /* Turks and Caicos Islands (UK) */ ++#define COUNTRY_CODE_TD (((UINT_16) 'T' << 8) | (UINT_16) 'D') /* Chad */ ++#define COUNTRY_CODE_TF (((UINT_16) 'T' << 8) | (UINT_16) 'F') /* French Southern and Antarctic Lands */ ++#define COUNTRY_CODE_TG (((UINT_16) 'T' << 8) | (UINT_16) 'G') /* Togo */ ++#define COUNTRY_CODE_TH (((UINT_16) 'T' << 8) | (UINT_16) 'H') /* Thailand */ ++#define COUNTRY_CODE_TJ (((UINT_16) 'T' << 8) | (UINT_16) 'J') /* Tajikistan */ ++#define COUNTRY_CODE_TL (((UINT_16) 'T' << 8) | (UINT_16) 'L') /* East Timor */ ++#define COUNTRY_CODE_TM (((UINT_16) 'T' << 8) | (UINT_16) 'M') /* Turkmenistan */ ++#define COUNTRY_CODE_TN (((UINT_16) 'T' << 8) | (UINT_16) 'N') /* Tunisia */ ++#define COUNTRY_CODE_TO (((UINT_16) 'T' << 8) | (UINT_16) 'O') /* Tonga */ ++#define COUNTRY_CODE_TR (((UINT_16) 'T' << 8) | (UINT_16) 'R') /* Turkey */ ++#define COUNTRY_CODE_TT (((UINT_16) 'T' << 8) | (UINT_16) 'T') /* Trinidad and Tobago */ ++#define COUNTRY_CODE_TV (((UINT_16) 'T' << 8) | (UINT_16) 'V') /* Tuvalu */ ++#define COUNTRY_CODE_TW (((UINT_16) 'T' << 8) | (UINT_16) 'W') /* Taiwan */ ++#define COUNTRY_CODE_TZ (((UINT_16) 'T' << 8) | (UINT_16) 'Z') /* Tanzania */ ++#define COUNTRY_CODE_UA (((UINT_16) 'U' << 8) | (UINT_16) 'A') /* Ukraine */ ++#define COUNTRY_CODE_UG (((UINT_16) 'U' << 8) | (UINT_16) 'G') /* Ugnada */ ++#define COUNTRY_CODE_US (((UINT_16) 'U' << 8) | (UINT_16) 'S') /* US */ ++#define COUNTRY_CODE_UY (((UINT_16) 'U' << 8) | (UINT_16) 'Y') /* Uruguay */ ++#define COUNTRY_CODE_UZ (((UINT_16) 'U' << 8) | (UINT_16) 'Z') /* Uzbekistan */ ++#define COUNTRY_CODE_VA (((UINT_16) 'V' << 8) | (UINT_16) 'A') /* Vatican (Holy See) */ ++#define COUNTRY_CODE_VC (((UINT_16) 'V' << 8) | (UINT_16) 'C') /* Saint Vincent and the Grenadines */ ++#define COUNTRY_CODE_VE (((UINT_16) 'V' << 8) | (UINT_16) 'E') /* Venezuela */ ++#define COUNTRY_CODE_VG (((UINT_16) 'V' << 8) | (UINT_16) 'G') /* British Virgin Islands */ ++#define COUNTRY_CODE_VI (((UINT_16) 'V' << 8) | (UINT_16) 'I') /* US Virgin Islands */ ++#define COUNTRY_CODE_VN (((UINT_16) 'V' << 8) | (UINT_16) 'N') /* Vietnam */ ++#define COUNTRY_CODE_VU (((UINT_16) 'V' << 8) | (UINT_16) 'U') /* Vanuatu */ ++#define COUNTRY_CODE_WS (((UINT_16) 'W' << 8) | (UINT_16) 'S') /* Samoa */ ++#define COUNTRY_CODE_YE (((UINT_16) 'Y' << 8) | (UINT_16) 'E') /* Yemen */ ++#define COUNTRY_CODE_YT (((UINT_16) 'Y' << 8) | (UINT_16) 'T') /* Mayotte (France) */ ++#define COUNTRY_CODE_ZA (((UINT_16) 'Z' << 8) | (UINT_16) 'A') /* South Africa */ ++#define COUNTRY_CODE_ZM (((UINT_16) 'Z' << 8) | (UINT_16) 'M') /* Zambia */ ++#define COUNTRY_CODE_ZW (((UINT_16) 'Z' << 8) | (UINT_16) 'W') /* Zimbabwe */ ++ ++#define COUNTRY_CODE_DF (((UINT_16) 'D' << 8) | (UINT_16) 'F') /* Default country domain */ ++#define COUNTRY_CODE_UDF (((UINT_16) 'U' << 8) | (UINT_16) 'D') /* User defined supported channel list ++ and passive scan channel list */ ++ ++#define COUNTRY_CODE_FF (((UINT_16) 'F' << 8) | (UINT_16) 'F') /* enable open for all channel for Certification */ ++#define COUNTRY_CODE_FE (((UINT_16) 'F' << 8) | (UINT_16) 'E') /* disable open for all channel for Certification */ ++ ++/* dot11RegDomainsSupportValue */ ++#define MIB_REG_DOMAIN_FCC 0x10 /* FCC (US) */ ++#define MIB_REG_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ ++#define MIB_REG_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ ++#define MIB_REG_DOMAIN_SPAIN 0x31 /* Spain */ ++#define MIB_REG_DOMAIN_FRANCE 0x32 /* France */ ++#define MIB_REG_DOMAIN_JAPAN 0x40 /* MPHPT (Japan) */ ++#define MIB_REG_DOMAIN_OTHER 0x00 /* other */ ++ ++/*2.4G*/ ++#define BAND_2G4_LOWER_BOUND 1 ++#define BAND_2G4_UPPER_BOUND 14 ++/*5G SubBand FCC spec*/ ++#define UNII1_LOWER_BOUND 36 ++#define UNII1_UPPER_BOUND 48 ++#define UNII2A_LOWER_BOUND 52 ++#define UNII2A_UPPER_BOUND 64 ++#define UNII2C_LOWER_BOUND 100 ++#define UNII2C_UPPER_BOUND 144 ++#define UNII3_LOWER_BOUND 149 ++#define UNII3_UPPER_BOUND 173 ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++#define POWER_LIMIT_TABLE_NULL 0xFFFF ++#define MAX_TX_POWER 63 ++#define MIN_TX_POWER -64 ++#define MAX_CMD_SUPPORT_CHANNEL_NUM 64 ++ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++typedef enum _ENUM_POWER_LIMIT_T { ++ PWR_LIMIT_CCK, ++ PWR_LIMIT_20M, ++ PWR_LIMIT_40M, ++ PWR_LIMIT_80M, ++ PWR_LIMIT_160M, ++ PWR_LIMIT_NUM ++} ENUM_POWER_LIMIT_T, *P_ENUM_POWER_LIMIT_T; ++ ++#endif ++ ++typedef enum _ENUM_POWER_LIMIT_SUBBAND_T { ++ POWER_LIMIT_2G4, ++ POWER_LIMIT_UNII1, ++ POWER_LIMIT_UNII2A, ++ POWER_LIMIT_UNII2C, ++ POWER_LIMIT_UNII3, ++ POWER_LIMIT_SUBAND_NUM ++} ENUM_POWER_LIMIT_SUBBAND_T, *P_ENUM_POWER_LIMIT_SUBBAND_T; ++ ++/* Define channel offset in unit of 5MHz bandwidth */ ++typedef enum _ENUM_CHNL_SPAN_T { ++ CHNL_SPAN_5 = 1, ++ CHNL_SPAN_10 = 2, ++ CHNL_SPAN_20 = 4, ++ CHNL_SPAN_40 = 8 ++} ENUM_CHNL_SPAN_T, *P_ENUM_CHNL_SPAN_T; ++ ++/* Define BSS operating bandwidth */ ++typedef enum _ENUM_CHNL_BW_T { ++ CHNL_BW_20, ++ CHNL_BW_20_40, ++ CHNL_BW_10, ++ CHNL_BW_5 ++} ENUM_CHNL_BW_T, *P_ENUM_CHNL_BW_T; ++ ++/* In all bands, the first channel will be SCA and the second channel is SCB, ++ * then iteratively. ++ * Note the final channel will not be SCA. ++ */ ++typedef struct _DOMAIN_SUBBAND_INFO { ++ /* Note1: regulation class depends on operation bandwidth and RF band. ++ * For example: 2.4GHz, 1~13, 20MHz ==> regulation class = 81 ++ * 2.4GHz, 1~13, SCA ==> regulation class = 83 ++ * 2.4GHz, 1~13, SCB ==> regulation class = 84 ++ * Note2: TX power limit is not specified here because path loss is unknown ++ */ ++ UINT_8 ucRegClass; /* Regulation class for 20MHz */ ++ UINT_8 ucBand; /* Type: ENUM_BAND_T */ ++ UINT_8 ucChannelSpan; /* Type: ENUM_CHNL_SPAN_T */ ++ UINT_8 ucFirstChannelNum; ++ UINT_8 ucNumChannels; ++ UINT_8 fgDfs; /* Type: BOOLEAN */ ++} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; ++ ++/* Use it as all available channel list for STA */ ++typedef struct _DOMAIN_INFO_ENTRY { ++ PUINT_16 pu2CountryGroup; ++ UINT_32 u4CountryNum; ++ ++ /* If different attributes, put them into different rSubBands. ++ * For example, DFS shall be used or not. ++ */ ++ DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; ++} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; ++ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++typedef struct _CHANNEL_POWER_LIMIT { ++ UINT_8 ucCentralCh; ++ INT_8 cPwrLimitCCK; ++ INT_8 cPwrLimit20; ++ INT_8 cPwrLimit40; ++ INT_8 cPwrLimit80; ++ INT_8 cPwrLimit160; ++ UINT_8 ucFlag; ++ UINT_8 aucReserved[1]; ++} CHANNEL_POWER_LIMIT, *P_CHANNEL_POWER_LIMIT; ++ ++typedef struct _COUNTRY_CHANNEL_POWER_LIMIT { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 ucCountryFlag; ++ UINT_8 ucChannelNum; ++ UINT_8 aucReserved[4]; ++ CHANNEL_POWER_LIMIT rChannelPowerLimit[80]; ++} COUNTRY_CHANNEL_POWER_LIMIT, *P_COUNTRY_CHANNEL_POWER_LIMIT; ++ ++#define CHANNEL_PWR_LIMIT(_channel, _pwrLimit_cck, _pwrLimit_bw20, \ ++ _pwrLimit_bw40, _pwrLimit_bw80, _pwrLimit_bw160, _ucFlag) \ ++ { \ ++ .ucCentralCh = (_channel), \ ++ .cPwrLimitCCK = (_pwrLimit_cck), \ ++ .cPwrLimit20 = (_pwrLimit_bw20), \ ++ .cPwrLimit40 = (_pwrLimit_bw40), \ ++ .cPwrLimit80 = (_pwrLimit_bw80), \ ++ .cPwrLimit160 = (_pwrLimit_bw160), \ ++ .ucFlag = (_ucFlag), \ ++ .aucReserved = {0} \ ++} ++ ++typedef struct _COUNTRY_POWER_LIMIT_TABLE_DEFAULT { ++ UINT_8 aucCountryCode[2]; ++ /* 0: ch 1 ~14 , 1: ch 36 ~48, 2: ch 52 ~64, 3: ch 100 ~144, 4: ch 149 ~165 */ ++ INT_8 aucPwrLimitSubBand[POWER_LIMIT_SUBAND_NUM]; ++ /* bit0: cPwrLimit2G4, bit1: cPwrLimitUnii1; bit2: cPwrLimitUnii2A; ++ * bit3: cPwrLimitUnii2C; bit4: cPwrLimitUnii3; mW: 0, mW\MHz : 1 */ ++ UINT_8 ucPwrUnit; ++} COUNTRY_POWER_LIMIT_TABLE_DEFAULT, *P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT; ++ ++typedef struct _COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 ucCentralCh; ++ INT_8 aucPwrLimit[PWR_LIMIT_NUM]; ++} COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION, *P_COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION; ++ ++typedef struct _SUBBAND_CHANNEL_T { ++ UINT_8 ucStartCh; ++ UINT_8 ucEndCh; ++ UINT_8 ucInterval; ++ UINT_8 ucReserved; ++} SUBBAND_CHANNEL_T, *P_SUBBAND_CHANNEL_T; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CAL_CH_OFFSET_80M(_PRIMARY_CH, _CENTRAL_CH) \ ++ (((_PRIMARY_CH - _CENTRAL_CH) + 6) >> 2) ++ ++#define CAL_CH_OFFSET_160M(_PRIMARY_CH, _CENTRAL_CH) \ ++ (((_PRIMARY_CH - _CENTRAL_CH) + 14) >> 2) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter); ++ ++VOID ++rlmDomainGetChnlList(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, ++ UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList); ++ ++VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel); ++ ++UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf); ++ ++BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh); ++ ++UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++BOOLEAN rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, ++ UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend, ++ ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2); ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++BOOLEAN ++rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, ++ COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, ++ UINT_8 ucPwrLimitNum); ++ ++VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter); ++ ++UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode); ++ ++VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_DOMAIN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h +new file mode 100644 +index 000000000000..7f29dba4ce06 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h +@@ -0,0 +1,150 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_obss.h#1 ++*/ ++ ++/*! \file "rlm_obss.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_obss.h ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ++ * ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++#ifndef _RLM_OBSS_H ++#define _RLM_OBSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define CHNL_LIST_SZ_2G 14 ++#define CHNL_LIST_SZ_5G 14 ++ ++#define CHNL_LEVEL0 0 ++#define CHNL_LEVEL1 1 ++#define CHNL_LEVEL2 2 ++ ++#define AFFECTED_CHNL_OFFSET 5 ++ ++#define OBSS_SCAN_MIN_INTERVAL 10 /* In unit of sec */ ++ ++#define PUBLIC_ACTION_MAX_LEN 200 /* In unit of byte */ ++ ++/* P2P GO only */ ++/* Define default OBSS Scan parameters (from MIB in spec.) */ ++#define dot11OBSSScanPassiveDwell 20 ++#define dot11OBSSScanActiveDwell 10 ++#define dot11OBSSScanPassiveTotalPerChannel 200 ++#define dot11OBSSScanActiveTotalPerChannel 20 ++#define dot11BSSWidthTriggerScanInterval 300 /* Unit: sec */ ++#define dot11BSSWidthChannelTransitionDelayFactor 5 ++#define dot11OBSSScanActivityThreshold 25 ++ ++#define OBSS_20_40M_TIMEOUT (dot11BSSWidthTriggerScanInterval + 10) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* Control MAC PCO function */ ++typedef enum _ENUM_SYS_PCO_PHASE_T { ++ SYS_PCO_PHASE_DISABLED = 0, ++ SYS_PCO_PHASE_20M, ++ SYS_PCO_PHASE_40M ++} ENUM_SYS_PCO_PHASE_T, *P_ENUM_SYS_PCO_PHASE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID rlmObssInit(P_ADAPTER_T prAdapter); ++ ++VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_OBSS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h +new file mode 100644 +index 000000000000..8665e48569ba +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h +@@ -0,0 +1,122 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_protection.h#1 ++*/ ++ ++/*! \file "rlm_protection.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_protection.h ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++#ifndef _RLM_PROTECTION_H ++#define _RLM_PROTECTION_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SYS_PROTECT_MODE_T { ++ SYS_PROTECT_MODE_NONE = 0, /* Mode 0 */ ++ SYS_PROTECT_MODE_ERP, /* Mode 1 */ ++ SYS_PROTECT_MODE_NON_HT, /* Mode 2 */ ++ SYS_PROTECT_MODE_20M, /* Mode 3 */ ++ ++ SYS_PROTECT_MODE_NUM ++} ENUM_SYS_PROTECT_MODE_T, *P_ENUM_SYS_PROTECT_MODE_T; ++ ++/* This definition follows HT Protection field of HT Operation IE */ ++typedef enum _ENUM_HT_PROTECT_MODE_T { ++ HT_PROTECT_MODE_NONE = 0, ++ HT_PROTECT_MODE_NON_MEMBER, ++ HT_PROTECT_MODE_20M, ++ HT_PROTECT_MODE_NON_HT, ++ ++ HT_PROTECT_MODE_NUM ++} ENUM_HT_PROTECT_MODE_T, *P_ENUM_HT_PROTECT_MODE_T; ++ ++typedef enum _ENUM_GF_MODE_T { ++ GF_MODE_NORMAL = 0, ++ GF_MODE_PROTECT, ++ GF_MODE_DISALLOWED, ++ ++ GF_MODE_NUM ++} ENUM_GF_MODE_T, *P_ENUM_GF_MODE_T; ++ ++typedef enum _ENUM_RIFS_MODE_T { ++ RIFS_MODE_NORMAL = 0, ++ RIFS_MODE_DISALLOWED, ++ ++ RIFS_MODE_NUM ++} ENUM_RIFS_MODE_T, *P_ENUM_RIFS_MODE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_PROTECTION_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h +new file mode 100644 +index 000000000000..d01c6e01e83f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h +@@ -0,0 +1,1213 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_txpwr_init.h#1 ++*/ ++ ++/*! \file "rlm_txpwr_init.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_txpwr_init.h ++*/ ++ ++ ++#ifndef _RLM_TXPWR_INIT_H ++#define _RLM_TXPWR_INIT_H ++ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*Support Tx Power Range : 63~ -64 (unit : 0.5dBm)*/ ++ ++#define PWR_LIMIT_2G4_IN_MW_MHZ BIT(0) ++#define PWR_LIMIT_UNII1_IN_MW_MHZ BIT(1) ++#define PWR_LIMIT_UNII2A_IN_MW_MHZ BIT(2) ++#define PWR_LIMIT_UNII2C_IN_MW_MHZ BIT(3) ++#define PWR_LIMIT_UNII3_IN_MW_MHZ BIT(4) ++ ++#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT ++#define CE_FCC_TXPWR_LIMIT_CCK 30 /* 15 dBm */ ++#define CE_FCC_TXPWR_LIMIT_OFDM 20 /* 10 dBm */ ++#define CE_FCC_TXPWR_LIMIT_HT40 18 /* 9 dBm */ ++#endif ++ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++COUNTRY_POWER_LIMIT_TABLE_DEFAULT g_rRlmPowerLimitDefault[] = { ++ ++ {{'A', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'Z'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'T'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'I'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'F'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'D'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'D'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'I'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'D', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'Q'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'E', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'F', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'A'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'N'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'W'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'R', 'K'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'L', 'Y'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'L'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'C'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'T'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'C'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'L'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'B'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'Z'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'V'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'V', 'U'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'Y', 'E'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'A', 'S'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'A', 'I'} ++ , {60, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'B', 'M'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'C', 'A'} ++ , {60, 46, 48, 48, 60} ++ , 0} ++ , ++ {{'K', 'Y'} ++ , {60, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'G', 'U'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'F', 'M'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'P', 'R'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'U', 'S'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'V', 'I'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'A', 'R'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'A', 'U'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'Z'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'B', 'W'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'K', 'H'} ++ , {40, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'C', 'X'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'O'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'C', 'R'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'E', 'C'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'G', 'D'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'G', 'T'} ++ , {40, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'H', 'K'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'I'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'B'} ++ , {40, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'L', 'R'} ++ , {60, 46, 60, 63, 63} ++ , 0} ++ , ++ {{'M', 'N'} ++ , {46, 32, 46, 46, 58} ++ , 0} ++ , ++ {{'A', 'N'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'N', 'Z'} ++ , {63, 46, 60, 48, 63} ++ , 0} ++ , ++ {{'N', 'I'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'P', 'W'} ++ , {60, 60, 60, 60, 60} ++ , 0} ++ , ++ {{'P', 'Y'} ++ , {60, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'P', 'E'} ++ , {54, 46, 48, 42, 48} ++ , 0} ++ , ++ {{'P', 'H'} ++ , {40, 46, 46, 48, 48} ++ , 0} ++ , ++ {{'W', 'S'} ++ , {40, 40, 40, 40, 60} ++ , 0} ++ , ++ {{'S', 'G'} ++ , {46, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'L', 'K'} ++ , {46, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'T', 'H'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'T', 'T'} ++ , {60, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'U', 'Y'} ++ , {63, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'V', 'N'} ++ , {46, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'A', 'W'} ++ , {60, 46, 60, 60, 63} ++ , 0} ++ , ++ {{'L', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'A'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'A', 'E'} ++ , {40, 46, 46, 60, 46} ++ , 0} ++ , ++ {{'U', 'G'} ++ , {40, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'M', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'Z'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'D'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'Y'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'V', 'G'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'G'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'V'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'H', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'Y'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'Z'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'T'} ++ , {40, 40, 40, 40, 63} ++ , 0} ++ , ++ {{'F', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'F', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'H'} ++ , {40, 34, 48, 60, 63} ++ , 0} ++ , ++ {{'G', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'P'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'H', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'Q'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'V'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'Q'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'R'} ++ , {40, 46, 46, 46, 63} ++ , 0} ++ , ++ {{'M', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'Y', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'D'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'C'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'N', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'N', 'O'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'O', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'R', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'R', 'O'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'N'} ++ , {40, 40, 40, 60, 63} ++ , 0} ++ , ++ {{'R', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'Z', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'H'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'C'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'B'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'V', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'M'} ++ , {40, 40, 40, 63, 63} ++ , 0} ++ , ++ {{'I', 'L'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'K', 'W'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'M', 'A'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'N', 'E'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'T', 'N'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'E', 'H'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'N', 'P'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'A', 'F'} ++ , {40, 46, 63, 63, 63} ++ , 0} ++ , ++ {{'A', 'G'} ++ , {40, 46, 48, 63, 54} ++ , 0} ++ , ++ {{'B', 'S'} ++ , {63, 46, 60, 63, 63} ++ , 0} ++ , ++ {{'B', 'H'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'B', 'B'} ++ , {40, 46, 48, 63, 54} ++ , 0} ++ , ++ {{'B', 'N'} ++ , {46, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'C', 'L'} ++ , {40, 44, 44, 63, 44} ++ , 0} ++ , ++ {{'C', 'N'} ++ , {40, 46, 46, 63, 54} ++ , 0} ++ , ++ {{'E', 'G'} ++ , {40, 46, 46, 63, 46} ++ , 0} ++ , ++ {{'S', 'V'} ++ , {60, 34, 48, 63, 60} ++ , 0} ++ , ++ {{'I', 'N'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'M', 'Y'} ++ , {54, 60, 60, 63, 60} ++ , 0} ++ , ++ {{'M', 'V'} ++ , {40, 46, 46, 63, 40} ++ , 0} ++ , ++ {{'P', 'A'} ++ , {60, 34, 48, 63, 60} ++ , 0} ++ , ++ {{'V', 'E'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'Z', 'M'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'J', 'O'} ++ , {40, 46, 63, 63, 46} ++ , 0} ++ , ++ {{'P', 'G'} ++ , {40, 46, 63, 63, 60} ++ , 0} ++ , ++ {{'B', 'F'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'G', 'Y'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'H', 'T'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'H', 'N'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'J', 'M'} ++ , {54, 63, 63, 63, 57} ++ , 0} ++ , ++ {{'M', 'O'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'M', 'W'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'P', 'K'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'Q', 'A'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'R', 'W'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'K', 'N'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'T', 'Z'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'I', 'D'} ++ , {46, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'N', 'G'} ++ , {40, 63, 46, 63, 60} ++ , 0} ++ , ++ {{'B', 'D'} ++ , {40, 46, 46, 60, 28} ++ , 0} ++ , ++ {{'B', 'R'} ++ , {52, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'D', 'M'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'D', 'O'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'F', 'K'} ++ , {40, 46, 46, 60, 28} ++ , 0} ++ , ++ {{'K', 'Z'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'M', 'X'} ++ , {60, 34, 48, 60, 63} ++ , 0} ++ , ++ {{'M', 'Z'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'N', 'A'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'R', 'U'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'L', 'C'} ++ , {40, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'V', 'C'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'U', 'A'} ++ , {40, 46, 46, 46, 48} ++ , 0} ++ , ++ {{'U', 'Z'} ++ , {40, 48, 48, 48, 60} ++ , 0} ++ , ++ {{'Z', 'W'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'M', 'P'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'T', 'W'} ++ , {60, 63, 34, 48, 60} ++ , 0} ++ , ++ {{'C', 'K'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'U'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'L'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'F', 'O'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'I'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'G'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'I', 'R'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'I', 'M'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'J', 'E'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'P'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'H'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'U'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'F'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'S'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'N'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'M'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'S'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'D'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'Y'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'J', 'P'} ++ , {46, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'R'} ++ , {46, 34, 46, 46, 46} ++ , PWR_LIMIT_UNII1_IN_MW_MHZ} ++ , ++ ++/*Default*/ ++ {{0, 0} ++ , {63, 63, 63, 63, 63} ++ , 0} ++}; ++ ++COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION g_rRlmPowerLimitConfiguration[] = { ++ ++ {{'A', 'I'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'A', 'Z'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'B', 'W'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'G', 'D'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'L', 'B'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'L', 'R'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'W', 'S'} ++ , 165, {40, 40, 40, 40, 40} ++ } ++ , ++ {{'V', 'N'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 1, {38, 30, 60, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 3, {60, 60, 26, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 9, {60, 60, 26, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 11, {38, 30, 60, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 36, {34, 34, 34, 34, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 38, {34, 34, 34, 34, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 42, {34, 34, 34, 31, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 58, {48, 48, 48, 31, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 62, {48, 48, 34, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 64, {37, 37, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 100, {37, 37, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 102, {48, 48, 34, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 106, {48, 48, 48, 31, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 155, {60, 60, 60, 31, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 159, {60, 60, 34, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 165, {37, 37, 60, 60, 60} ++ } ++ , ++ ++/*Default*/ ++ {{0, 0} ++ , 165, {63, 63, 63, 63, 63} ++ } ++}; ++ ++#if 0 ++COUNTRY_CHANNEL_POWER_LIMIT g_rRlmCountryPowerLimitTable[] = { ++ { ++ {'A', 'O'} ++ , 0, 0, {0, 0, 0, 0} ++ , ++ { ++ CHANNEL_PWR_LIMIT(1, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(2, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(3, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(4, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(5, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(6, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(7, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(8, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(9, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(10, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(11, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(12, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(13, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(14, 40, 40, 40, 40, 40, 0), ++ ++ CHANNEL_PWR_LIMIT(36, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(38, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(40, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(42, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(44, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(46, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(48, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(52, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(54, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(56, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(58, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(60, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(62, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(64, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(100, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(102, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(104, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(106, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(108, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(110, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(112, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(114, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(116, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(118, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(120, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(122, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(124, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(126, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(128, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(130, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(132, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(134, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(136, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(138, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(140, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(142, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(144, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(149, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(151, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(153, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(155, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(157, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(159, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(161, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(163, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(165, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(167, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(169, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(171, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(173, 63, 63, 63, 63, 63, 0) ++ } ++ } ++ , ++ { ++ /*Used to check the end of country entry */ ++ {0, 0} ++ , 0, 0, {0, 0, 0, 0} ++ , ++ { ++ /*Used to check the end of channel power limit */ ++ CHANNEL_PWR_LIMIT(ENDCH, 0, 0, 0, 0, 0, 0) ++ } ++ } /*end of CountryTable */ ++}; ++#endif ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_TXPWR_INIT_H */ ++ ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h +new file mode 100644 +index 000000000000..0df4ec3e0828 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h +@@ -0,0 +1,171 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "roaming_fsm.h" ++ \brief This file defines the FSM for Roaming MODULE. ++ ++ This file defines the FSM for Roaming MODULE. ++*/ ++ ++/* ++** Log: roaming_fsm.h ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++*/ ++ ++#ifndef _ROAMING_FSM_H ++#define _ROAMING_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Roaming Discovery interval, SCAN result need to be updated */ ++#define ROAMING_DISCOVERY_TIMEOUT_SEC 5 /* Seconds. */ ++ ++/* #define ROAMING_NO_SWING_RCPI_STEP 5 //rcpi */ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_ROAMING_FAIL_REASON_T { ++ ROAMING_FAIL_REASON_CONNLIMIT = 0, ++ ROAMING_FAIL_REASON_NOCANDIDATE, ++ ROAMING_FAIL_REASON_NUM ++} ENUM_ROAMING_FAIL_REASON_T; ++ ++/* events of roaming between driver and firmware */ ++typedef enum _ENUM_ROAMING_EVENT_T { ++ ROAMING_EVENT_START = 0, ++ ROAMING_EVENT_DISCOVERY, ++ ROAMING_EVENT_ROAM, ++ ROAMING_EVENT_FAIL, ++ ROAMING_EVENT_ABORT, ++ ROAMING_EVENT_NUM ++} ENUM_ROAMING_EVENT_T; ++ ++#define ROAMING_EVENT_REASON_TX_ERR BIT(0) ++#define ROAMING_EVENT_REASON_RCPI BIT(1) ++ ++typedef struct _ROAMING_PARAM_T { ++ UINT_16 u2Event; ++ UINT_16 u2Data; ++ UINT_16 u2Reason; ++} ROAMING_PARAM_T, *P_ROAMING_PARAM_T; ++ ++ /**/ typedef enum _ENUM_ROAMING_STATE_T { ++ ROAMING_STATE_IDLE = 0, ++ ROAMING_STATE_DECISION, ++ ROAMING_STATE_DISCOVERY, ++ ROAMING_STATE_ROAM, ++ ROAMING_STATE_NUM ++} ENUM_ROAMING_STATE_T; ++ ++typedef struct _ROAMING_INFO_T { ++ BOOLEAN fgIsEnableRoaming; ++ ++ ENUM_ROAMING_STATE_T eCurrentState; ++ ++ OS_SYSTIME rRoamingDiscoveryUpdateTime; ++ ++#define ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX 2 ++ UINT_32 RoamingEntryTimeoutSkipCount; ++ ++} ROAMING_INFO_T, *P_ROAMING_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if CFG_SUPPORT_ROAMING ++#define IS_ROAMING_ACTIVE(prAdapter) \ ++ (prAdapter->rWifiVar.rRoamingInfo.eCurrentState == ROAMING_STATE_ROAM) ++#else ++#define IS_ROAMING_ACTIVE(prAdapter) FALSE ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID roamingFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState); ++ ++VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Reason); ++ ++VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ROAMING_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h +new file mode 100644 +index 000000000000..20ab14251f65 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h +@@ -0,0 +1,271 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rsn.h#1 ++*/ ++ ++/*! \file rsn.h ++ \brief The wpa/rsn related define, macro and structure are described here. ++*/ ++ ++/* ++** Log: rsn.h ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h ++ * and let the sw structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 wh.su ++ * NULL ++ * remove non-used code. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, and modify ++ * the security related callback function prototype. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function prototype for generate wap/rsn ie ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function input parameter ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some event function declaration ++ * ++ * Nov 26 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * move the internal data structure for pmkid to rsn.h ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the port control and class error function ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the pmkid candidate ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++#ifndef _RSN_H ++#define _RSN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* ----- Definitions for Cipher Suite Selectors ----- */ ++#define RSN_CIPHER_SUITE_USE_GROUP_KEY 0x00AC0F00 ++#define RSN_CIPHER_SUITE_WEP40 0x01AC0F00 ++#define RSN_CIPHER_SUITE_TKIP 0x02AC0F00 ++#define RSN_CIPHER_SUITE_CCMP 0x04AC0F00 ++#define RSN_CIPHER_SUITE_WEP104 0x05AC0F00 ++#if CFG_SUPPORT_802_11W ++#define RSN_CIPHER_SUITE_AES_128_CMAC 0x06AC0F00 ++#endif ++ ++#define WPA_CIPHER_SUITE_NONE 0x00F25000 ++#define WPA_CIPHER_SUITE_WEP40 0x01F25000 ++#define WPA_CIPHER_SUITE_TKIP 0x02F25000 ++#define WPA_CIPHER_SUITE_CCMP 0x04F25000 ++#define WPA_CIPHER_SUITE_WEP104 0x05F25000 ++ ++/* ----- Definitions for Authentication and Key Management Suite Selectors ----- */ ++#define RSN_AKM_SUITE_NONE 0x00AC0F00 ++#define RSN_AKM_SUITE_802_1X 0x01AC0F00 ++#define RSN_AKM_SUITE_PSK 0x02AC0F00 ++#if CFG_SUPPORT_802_11W ++#define RSN_AKM_SUITE_802_1X_SHA256 0x05AC0F00 ++#define RSN_AKM_SUITE_PSK_SHA256 0x06AC0F00 ++#endif ++ ++#define WPA_AKM_SUITE_NONE 0x00F25000 ++#define WPA_AKM_SUITE_802_1X 0x01F25000 ++#define WPA_AKM_SUITE_PSK 0x02F25000 ++ ++#define ELEM_ID_RSN_LEN_FIXED 20 /* The RSN IE len for associate request */ ++ ++#define ELEM_ID_WPA_LEN_FIXED 22 /* The RSN IE len for associate request */ ++ ++#define MASK_RSNIE_CAP_PREAUTH BIT(0) ++ ++#define GET_SELECTOR_TYPE(x) ((UINT_8)(((x) >> 24) & 0x000000FF)) ++#define SET_SELECTOR_TYPE(x, y) {x = (((x) & 0x00FFFFFF) | (((UINT_32)(y) << 24) & 0xFF000000))} ++ ++#define AUTH_CIPHER_CCMP 0x00000008 ++ ++/* Cihpher suite flags */ ++#define CIPHER_FLAG_NONE 0x00000000 ++#define CIPHER_FLAG_WEP40 0x00000001 /* BIT 1 */ ++#define CIPHER_FLAG_TKIP 0x00000002 /* BIT 2 */ ++#define CIPHER_FLAG_CCMP 0x00000008 /* BIT 4 */ ++#define CIPHER_FLAG_WEP104 0x00000010 /* BIT 5 */ ++#define CIPHER_FLAG_WEP128 0x00000020 /* BIT 6 */ ++ ++#define WAIT_TIME_IND_PMKID_CANDICATE_SEC 6 /* seconds */ ++#define TKIP_COUNTERMEASURE_SEC 60 /* seconds */ ++ ++#if CFG_SUPPORT_802_11W ++#define RSN_AUTH_MFP_DISABLED 0 /* MFP disabled */ ++#define RSN_AUTH_MFP_OPTIONAL 1 /* MFP optional */ ++#define RSN_AUTH_MFP_REQUIRED 2 /* MFP required */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* Flags for PMKID Candidate list structure */ ++#define EVENT_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++ ++#define CONTROL_FLAG_UC_MGMT_NO_ENC BIT(5) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define RSN_IE(fp) ((P_RSN_INFO_ELEM_T) fp) ++#define WPA_IE(fp) ((P_WPA_INFO_ELEM_T) fp) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo); ++ ++BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo); ++ ++BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index); ++ ++BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index); ++ ++BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++BOOLEAN ++rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion); ++ ++BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo); ++ ++#if CFG_SUPPORT_AAA ++void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode); ++#endif ++ ++VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType); ++ ++VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex); ++ ++BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter); ++ ++VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter); ++ ++VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++#if CFG_SUPPORT_WPS2 ++VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++#endif ++ ++#if CFG_SUPPORT_802_11W ++UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter); ++ ++void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter); ++ ++void rsnStartSaQuery(IN P_ADAPTER_T prAdapter); ++ ++void rsnStopSaQuery(IN P_ADAPTER_T prAdapter); ++ ++void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype); ++#endif ++BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RSN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h +new file mode 100644 +index 000000000000..c08b2244be6c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h +@@ -0,0 +1,988 @@ ++/* ++** Id: @(#) ++*/ ++ ++/*! \file "scan.h" ++ \brief ++ ++*/ ++ ++/* ++** Log: scan.h ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting ++ * preferred band configuration corresponding to network type. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID ++ * in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings ++ * to work around some tricky AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module ++ * with structure miss-align pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix compile error. ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add a functio prototype to find p2p descriptor of a bss descriptor directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add function prototype for return channel. ++ * modify data structure for scan specific device ID or TYPE. (Move from P2P Connection Settings to Scan Param) ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add a option for channel time extension in scan abort command. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Scan status "FIND" is used for P2P FSM find state. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, other request ++ * will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related field in SCAN_PARAM_T. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * ++ * Add new HW CH macro support ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify scanBuildProbeReqFrameCommonIEs() to support P2P SCAN ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver ++ * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Simplify the process of Beacon during SCAN and remove redundant variable in PRE_BSS_DESC_T ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding variable for wapi ap ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove non-used secuirty variavle ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Refine data structure of BSS_DESC_T and PRE_BSS_DESC_T ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add eNetType to rScanParam and revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add ucAvailablePhyTypeSet to BSS_DESC_T ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aucSrcAddress to SCAN_PARAM_T for P2P's Device Address ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security related variable ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security ie filed for scan parsing ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scanSearchBssDescByPolicy() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function declarations of scan_fsm.c ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scan.h to source control ++** ++*/ ++ ++#ifndef _SCAN_H ++#define _SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_vendor.h" ++ ++/* TDLS test purpose */ ++extern BOOLEAN flgTdlsTestExtCapElm; ++extern UINT8 aucTdlsTestExtCapElm[]; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*! Maximum buffer size of SCAN list */ ++#define SCN_MAX_BUFFER_SIZE (CFG_MAX_NUM_BSS_LIST * ALIGN_4(sizeof(BSS_DESC_T))) ++ ++#define SCN_RM_POLICY_EXCLUDE_CONNECTED BIT(0) /* Remove SCAN result except the connected one. */ ++#define SCN_RM_POLICY_TIMEOUT BIT(1) /* Remove the timeout one */ ++#define SCN_RM_POLICY_OLDEST_HIDDEN BIT(2) /* Remove the oldest one with hidden ssid */ ++#define SCN_RM_POLICY_SMART_WEAKEST BIT(3) /* If there are more than half BSS which has the ++ * same ssid as connection setting, remove the ++ * weakest one from them ++ * Else remove the weakest one. ++ */ ++#define SCN_RM_POLICY_ENTIRE BIT(4) /* Remove entire SCAN result */ ++ ++#define SCN_BSS_DESC_SAME_SSID_THRESHOLD 3 /* This is used by POLICY SMART WEAKEST, ++ * If exceed this value, remove weakest BSS_DESC_T ++ * with same SSID first in large network. ++ */ ++ ++/* the scan time in WFD mode + 2.4G/5G is about 9s so we need to enlarge the value */ ++#define SCN_BSS_DESC_REMOVE_TIMEOUT_SEC 15 /* Second. */ ++ /* This is used by POLICY TIMEOUT, ++ * If exceed this value, remove timeout BSS_DESC_T. ++ */ ++ ++#define SCN_PROBE_DELAY_MSEC 0 ++ ++#define SCN_ADHOC_BSS_DESC_TIMEOUT_SEC 5 /* Second. */ ++ ++#define SCN_NLO_NETWORK_CHANNEL_NUM (4) ++ ++/*----------------------------------------------------------------------------*/ ++/* MSG_SCN_SCAN_REQ */ ++/*----------------------------------------------------------------------------*/ ++#define SCAN_REQ_SSID_WILDCARD BIT(0) ++#define SCAN_REQ_SSID_P2P_WILDCARD BIT(1) ++#define SCAN_REQ_SSID_SPECIFIED BIT(2) ++ ++/*----------------------------------------------------------------------------*/ ++/* Support Multiple SSID SCAN */ ++/*----------------------------------------------------------------------------*/ ++#define SCN_SSID_MAX_NUM CFG_SCAN_SSID_MAX_NUM ++#define SCN_SSID_MATCH_MAX_NUM CFG_SCAN_SSID_MATCH_MAX_NUM ++ ++#define SWC_NUM_BSSID_THRESHOLD_DEFAULT 8 ++#define SWC_RSSI_WINDSIZE_DEFAULT 8 ++#define LOST_AP_WINDOW 16 ++#define MAX_CHANNEL_NUM_PER_BUCKETS 8 ++ ++#define SCN_BSS_JOIN_FAIL_THRESOLD 4 ++#define SCN_BSS_JOIN_FAIL_CNT_RESET_SEC 15 ++#define SCN_BSS_JOIN_FAIL_RESET_STEP 2 ++ ++#if CFG_SUPPORT_BATCH_SCAN ++/*----------------------------------------------------------------------------*/ ++/* SCAN_BATCH_REQ */ ++/*----------------------------------------------------------------------------*/ ++#define SCAN_BATCH_REQ_START BIT(0) ++#define SCAN_BATCH_REQ_STOP BIT(1) ++#define SCAN_BATCH_REQ_RESULT BIT(2) ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SCAN_TYPE_T { ++ SCAN_TYPE_PASSIVE_SCAN = 0, ++ SCAN_TYPE_ACTIVE_SCAN, ++ SCAN_TYPE_NUM ++} ENUM_SCAN_TYPE_T, *P_ENUM_SCAN_TYPE_T; ++ ++typedef enum _ENUM_SCAN_STATE_T { ++ SCAN_STATE_IDLE = 0, ++ SCAN_STATE_SCANNING, ++ SCAN_STATE_NUM ++} ENUM_SCAN_STATE_T; ++ ++typedef enum _ENUM_SCAN_CHANNEL_T { ++ SCAN_CHANNEL_FULL = 0, ++ SCAN_CHANNEL_2G4, ++ SCAN_CHANNEL_5G, ++ SCAN_CHANNEL_P2P_SOCIAL, ++ SCAN_CHANNEL_SPECIFIED, ++ SCAN_CHANNEL_NUM ++} ENUM_SCAN_CHANNEL, *P_ENUM_SCAN_CHANNEL; ++ ++typedef struct _MSG_SCN_FSM_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_32 u4Dummy; ++} MSG_SCN_FSM_T, *P_MSG_SCN_FSM_T; ++ ++typedef enum _ENUM_PSCAN_STATE_T { ++ PSCN_IDLE = 1, ++ PSCN_SCANNING, ++ PSCN_RESET, ++ PSCAN_STATE_T_NUM ++} ENUM_PSCAN_STATE_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* BSS Descriptors */ ++/*----------------------------------------------------------------------------*/ ++struct _BSS_DESC_T { ++ LINK_ENTRY_T rLinkEntry; ++ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ ++ ++ BOOLEAN fgIsConnecting; /* If we are going to connect to this BSS ++ * (JOIN or ROAMING to another BSS), don't ++ * remove this record from BSS List. ++ */ ++ BOOLEAN fgIsConnected; /* If we have connected to this BSS (NORMAL_TR), ++ * don't removed this record from BSS list. ++ */ ++ ++ BOOLEAN fgIsHiddenSSID; /* When this flag is TRUE, means the SSID ++ * of this BSS is not known yet. ++ */ ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ ++ OS_SYSTIME rUpdateTime; ++ ++ ENUM_BSS_TYPE_T eBSSType; ++ ++ UINT_16 u2CapInfo; ++ ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2ATIMWindow; ++ ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ BOOLEAN fgIsERPPresent; ++ BOOLEAN fgIsHTPresent; ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this BSS */ ++ ++ UINT_8 ucChannelNum; ++ ++ ENUM_CHNL_EXT_T eSco; /* Record bandwidth for association process ++ Some AP will send association resp by 40MHz BW */ ++ ENUM_BAND_T eBand; ++ ++ UINT_8 ucDTIMPeriod; ++ ++ BOOLEAN fgIsLargerTSF; /* This BSS's TimeStamp is larger than us(TCL == 1 in RX_STATUS_T) */ ++ ++ UINT_8 ucRCPI; ++ ++ UINT_8 ucWmmFlag; /* A flag to indicate this BSS's WMM capability */ ++ ++ /*! \brief The srbiter Search State will matched the scan result, ++ and saved the selected cipher and akm, and report the score, ++ for arbiter join state, join module will carry this target BSS ++ to rsn generate ie function, for gen wpa/rsn ie */ ++ UINT_32 u4RsnSelectedGroupCipher; ++ UINT_32 u4RsnSelectedPairwiseCipher; ++ UINT_32 u4RsnSelectedAKMSuite; ++ ++ UINT_16 u2RsnCap; ++ ++ RSN_INFO_T rRSNInfo; ++ RSN_INFO_T rWPAInfo; ++#if 1 /* CFG_SUPPORT_WAPI */ ++ WAPI_INFO_T rIEWAPI; ++ BOOLEAN fgIEWAPI; ++#endif ++ BOOLEAN fgIERSN; ++ BOOLEAN fgIEWPA; ++ ++ /*! \brief RSN parameters selected for connection */ ++ /*! \brief The Select score for final AP selection, ++ 0, no sec, 1,2,3 group cipher is WEP, TKIP, CCMP */ ++ UINT_8 ucEncLevel; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2PPresent; ++ BOOLEAN fgIsP2PReport; /* TRUE: report to upper layer */ ++ P_P2P_DEVICE_DESC_T prP2pDesc; ++ ++ UINT_8 aucIntendIfAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ ++/* UINT_8 ucDevCapabilityBitmap; */ /* Device Capability Attribute. (P2P_DEV_CAPABILITY_XXXX) */ ++/* UINT_8 ucGroupCapabilityBitmap; */ /* Group Capability Attribute. (P2P_GROUP_CAPABILITY_XXXX) */ ++ ++ LINK_T rP2pDeviceList; ++ ++/* P_LINK_T prP2pDeviceList; */ ++ ++ /* For ++ * 1. P2P Capability. ++ * 2. P2P Device ID. ( in aucSrcAddr[] ) ++ * 3. NOA (TODO:) ++ * 4. Extend Listen Timing. (Probe Rsp) (TODO:) ++ * 5. P2P Device Info. (Probe Rsp) ++ * 6. P2P Group Info. (Probe Rsp) ++ */ ++#endif ++ ++ BOOLEAN fgIsIEOverflow; /* The received IE length exceed the maximum IE buffer size */ ++ UINT_16 u2RawLength; /* The byte count of aucRawBuf[] */ ++ UINT_16 u2IELength; /* The byte count of aucIEBuf[] */ ++ ++ ULARGE_INTEGER u8TimeStamp; /* Place u8TimeStamp before aucIEBuf[1] to force DW align */ ++ UINT_8 aucRawBuf[CFG_RAW_BUFFER_SIZE]; ++ UINT_8 aucIEBuf[CFG_IE_BUFFER_SIZE]; ++ UINT_8 ucJoinFailureCount; ++ OS_SYSTIME rJoinFailTime; ++}; ++ ++typedef struct _SCAN_PARAM_T { /* Used by SCAN FSM */ ++ /* Active or Passive */ ++ ENUM_SCAN_TYPE_T eScanType; ++ ++ /* Network Type */ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ ++ /* Specified SSID Type */ ++ UINT_8 ucSSIDType; ++ UINT_8 ucSSIDNum; ++ ++ /* Length of Specified SSID */ ++ UINT_8 ucSpecifiedSSIDLen[SCN_SSID_MAX_NUM]; ++ ++ /* Specified SSID */ ++ UINT_8 aucSpecifiedSSID[SCN_SSID_MAX_NUM][ELEM_MAX_LEN_SSID]; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgFindSpecificDev; /* P2P: Discovery Protocol */ ++ UINT_8 aucDiscoverDevAddr[MAC_ADDR_LEN]; ++ BOOLEAN fgIsDevType; ++ P2P_DEVICE_TYPE_T rDiscoverDevType; ++ ++ UINT_16 u2PassiveListenInterval; ++ /* TODO: Find Specific Device Type. */ ++#endif /* CFG_SUPPORT_P2P */ ++ ++ BOOLEAN fgIsObssScan; ++ BOOLEAN fgIsScanV2; ++ ++ /* Run time flags */ ++ UINT_16 u2ProbeDelayTime; ++ ++ /* channel information */ ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ ++ /* Feedback information */ ++ UINT_8 ucSeqNum; ++ ++ /* Information Element */ ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++ ++} SCAN_PARAM_T, *P_SCAN_PARAM_T; ++ ++typedef struct _NLO_PARAM_T { /* Used by SCAN FSM */ ++ SCAN_PARAM_T rScanParam; ++ ++ /* NLO */ ++ BOOLEAN fgStopAfterIndication; ++ UINT_8 ucFastScanIteration; ++ UINT_16 u2FastScanPeriod; ++ UINT_16 u2SlowScanPeriod; ++ ++ /* Match SSID */ ++ UINT_8 ucMatchSSIDNum; ++ UINT_8 ucMatchSSIDLen[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_8 aucMatchSSID[SCN_SSID_MATCH_MAX_NUM][ELEM_MAX_LEN_SSID]; ++ ++ UINT_8 aucCipherAlgo[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_16 au2AuthAlgo[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_8 aucChannelHint[SCN_SSID_MATCH_MAX_NUM][SCN_NLO_NETWORK_CHANNEL_NUM]; ++ P_BSS_DESC_T aprPendingBssDescToInd[SCN_SSID_MATCH_MAX_NUM]; ++} NLO_PARAM_T, *P_NLO_PARAM_T; ++ ++#if 1 ++ ++typedef struct _GSCN_CHANNEL_INFO_T { ++ UINT_8 ucBand; ++ UINT_8 ucChannel; /* frequency */ ++ UINT_8 ucPassive; /* 0 => active, 1 => passive scan; ignored for DFS */ ++ UINT_8 aucReserved[1]; ++ ++ UINT_32 u4DwellTimeMs; /* dwell time hint */ ++ /* Add channel class */ ++} GSCN_CHANNEL_INFO_T, *P_GSCN_CHANNEL_INFO_T; ++ ++typedef struct _GSCAN_CHANNEL_BUCKET_T { ++ ++ UINT_16 u2BucketIndex; /* bucket index, 0 based */ ++ UINT_8 ucBucketFreqMultiple; /* desired period, in millisecond; ++ * if this is too low, the firmware should choose to generate ++ * results as fast as it can instead of failing the command */ ++ /* report_events semantics - ++ * 0 => report only when scan history is % full ++ * 1 => same as 0 + report a scan completion event after scanning this bucket ++ * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL ++ * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to ++ supplicant as well (optional) . */ ++ UINT_8 ucReportFlag; ++ UINT_8 ucNumChannels; ++ UINT_8 aucReserved[3]; ++ WIFI_BAND eBand; /* when UNSPECIFIED, use channel list */ ++ GSCN_CHANNEL_INFO_T arChannelList[GSCAN_MAX_CHANNELS]; /* channels to scan; these may include DFS channels */ ++} GSCAN_CHANNEL_BUCKET_T, *P_GSCAN_CHANNEL_BUCKET_T; ++ ++typedef struct _CMD_GSCN_REQ_T { ++ UINT_8 ucFlags; ++ UINT_8 ucNumScnToCache; ++ UINT_8 aucReserved[2]; ++ UINT_32 u4BufferThreshold; ++ UINT_32 u4BasePeriod; /* base timer period in ms */ ++ UINT_32 u4NumBuckets; ++ UINT_32 u4MaxApPerScan; /* number of APs to store in each scan in the */ ++ /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ ++ ++ GSCAN_CHANNEL_BUCKET_T arChannelBucket[GSCAN_MAX_BUCKETS]; ++} CMD_GSCN_REQ_T, *P_CMD_GSCN_REQ_T; ++ ++#endif ++ ++typedef struct _CMD_GSCN_SCN_COFIG_T { ++ UINT_8 ucNumApPerScn; /* GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN */ ++ UINT_32 u4NumScnToCache; /* GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE */ ++ UINT_32 u4BufferThreshold; /* GSCAN_ATTRIBUTE_REPORT_THRESHOLD */ ++} CMD_GSCN_SCN_COFIG_T, *P_CMD_GSCN_SCN_COFIG_T; ++ ++typedef struct _CMD_GET_GSCAN_RESULT { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[2]; ++ UINT_8 ucFlush; ++ UINT_32 u4Num; ++} CMD_GET_GSCAN_RESULT_T, *P_CMD_GET_GSCAN_RESULT_T; ++ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd like ++ approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++typedef struct _PSCN_PARAM_T { ++ UINT_8 ucVersion; ++ CMD_NLO_REQ rCurrentCmdNloReq; ++ CMD_BATCH_REQ_T rCurrentCmdBatchReq; ++ CMD_GSCN_REQ_T rCurrentCmdGscnReq; ++ BOOLEAN fgNLOScnEnable; ++ BOOLEAN fgBatchScnEnable; ++ BOOLEAN fgGScnEnable; ++ UINT_32 u4BasePeriod; /* GSCAN_ATTRIBUTE_BASE_PERIOD */ ++} PSCN_PARAM_T, *P_PSCN_PARAM_T; ++ ++typedef struct _SCAN_INFO_T { ++ ENUM_SCAN_STATE_T eCurrentState; /* Store the STATE variable of SCAN FSM */ ++ ++ OS_SYSTIME rLastScanCompletedTime; ++ ++ SCAN_PARAM_T rScanParam; ++ NLO_PARAM_T rNloParam; ++ ++ UINT_32 u4NumOfBssDesc; ++ ++ UINT_8 aucScanBuffer[SCN_MAX_BUFFER_SIZE]; ++ ++ LINK_T rBSSDescList; ++ ++ LINK_T rFreeBSSDescList; ++ ++ LINK_T rPendingMsgList; ++ ++ /* Sparse Channel Detection */ ++ BOOLEAN fgIsSparseChannelValid; ++ RF_CHANNEL_INFO_T rSparseChannel; ++ ++ /* NLO scanning state tracking */ ++ BOOLEAN fgNloScanning; ++ BOOLEAN fgPscnOnnning; ++ BOOLEAN fgGScnConfigSet; ++ BOOLEAN fgGScnParamSet; ++ P_PSCN_PARAM_T prPscnParam; ++ ENUM_PSCAN_STATE_T eCurrentPSCNState; ++ ++} SCAN_INFO_T, *P_SCAN_INFO_T; ++ ++/* Incoming Mailbox Messages */ ++typedef struct _MSG_SCN_SCAN_REQ_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_TYPE_T eScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucSSID[PARAM_MAX_LEN_SSID]; ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ ++#endif ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} MSG_SCN_SCAN_REQ, *P_MSG_SCN_SCAN_REQ; ++ ++typedef struct _MSG_SCN_SCAN_REQ_V2_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_TYPE_T eScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDNum; ++ P_PARAM_SSID_T prSsid; ++ UINT_16 u2ProbeDelay; ++ UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} MSG_SCN_SCAN_REQ_V2, *P_MSG_SCN_SCAN_REQ_V2; ++ ++typedef struct _MSG_SCN_SCAN_CANCEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsChannelExt; ++#endif ++} MSG_SCN_SCAN_CANCEL, *P_MSG_SCN_SCAN_CANCEL; ++ ++/* Outgoing Mailbox Messages */ ++typedef enum _ENUM_SCAN_STATUS_T { ++ SCAN_STATUS_DONE = 0, ++ SCAN_STATUS_CANCELLED, ++ SCAN_STATUS_FAIL, ++ SCAN_STATUS_BUSY, ++ SCAN_STATUS_NUM ++} ENUM_SCAN_STATUS, *P_ENUM_SCAN_STATUS; ++ ++typedef struct _MSG_SCN_SCAN_DONE_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_STATUS eScanStatus; ++} MSG_SCN_SCAN_DONE, *P_MSG_SCN_SCAN_DONE; ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++typedef enum { ++ AGPS_PHY_A, ++ AGPS_PHY_B, ++ AGPS_PHY_G, ++} AP_PHY_TYPE; ++ ++typedef struct _AGPS_AP_INFO_T { ++ UINT_8 aucBSSID[6]; ++ INT_16 i2ApRssi; /* -127..128 */ ++ UINT_16 u2Channel; /* 0..256 */ ++ AP_PHY_TYPE ePhyType; ++} AGPS_AP_INFO_T, *P_AGPS_AP_INFO_T; ++ ++typedef struct _AGPS_AP_LIST_T { ++ UINT_8 ucNum; ++ AGPS_AP_INFO_T arApInfo[32]; ++} AGPS_AP_LIST_T, *P_AGPS_AP_LIST_T; ++#endif ++ ++typedef struct _CMD_SET_PSCAN_PARAM { ++ UINT_8 ucVersion; ++ CMD_NLO_REQ rCmdNloReq; ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ CMD_GSCN_REQ_T rCmdGscnReq; ++ BOOLEAN fgNLOScnEnable; ++ BOOLEAN fgBatchScnEnable; ++ BOOLEAN fgGScnEnable; ++ UINT_32 u4BasePeriod; ++} CMD_SET_PSCAN_PARAM, *P_CMD_SET_PSCAN_PARAM; ++ ++typedef struct _CMD_SET_PSCAN_ADD_HOTLIST_BSSID { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucFlags; ++ UINT_8 aucReserved[5]; ++} CMD_SET_PSCAN_ADD_HOTLIST_BSSID, *P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID; ++ ++typedef struct _CMD_SET_PSCAN_ADD_SWC_BSSID { ++ INT_32 i4RssiLowThreshold; ++ INT_32 i4RssiHighThreshold; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucReserved[6]; ++} CMD_SET_PSCAN_ADD_SWC_BSSID, *P_CMD_SET_PSCAN_ADD_SWC_BSSID; ++ ++typedef struct _CMD_SET_PSCAN_MAC_ADDR { ++ UINT_8 ucVersion; ++ UINT_8 ucFlags; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucReserved[8]; ++} CMD_SET_PSCAN_MAC_ADDR, *P_CMD_SET_PSCAN_MAC_ADDR; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in scan.c */ ++/*----------------------------------------------------------------------------*/ ++VOID scnInit(IN P_ADAPTER_T prAdapter); ++ ++VOID scnUninit(IN P_ADAPTER_T prAdapter); ++ ++/* BSS-DESC Search */ ++P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++P_BSS_DESC_T ++scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]); ++ ++P_BSS_DESC_T ++scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++#endif ++ ++/* BSS-DESC Search - Alternative */ ++P_BSS_DESC_T ++scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]); ++ ++P_BSS_DESC_T ++scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, ++ IN UINT_8 aucBSSID[], ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++/* BSS-DESC Allocation */ ++P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter); ++ ++/* BSS-DESC Removal */ ++VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy); ++ ++VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++VOID ++scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/* BSS-DESC State Change */ ++VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++#if 0 ++/* BSS-DESC Insertion */ ++P_BSS_DESC_T scanAddToInternalScanResult(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb, IN P_BSS_DESC_T prBssDesc); ++#endif ++ ++/* BSS-DESC Insertion - ALTERNATIVE */ ++P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); ++ ++VOID ++scanBuildProbeReqFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, ++ IN PUINT_8 pucDesiredSsid, IN UINT_32 u4DesiredSsidLen, IN UINT_16 u2SupportedRateSet); ++ ++WLAN_STATUS scanSendProbeReqFrames(IN P_ADAPTER_T prAdapter, IN P_SCAN_PARAM_T prScanParam); ++ ++VOID scanUpdateBssDescForSearch(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); ++ ++VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in scan_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState); ++ ++/*----------------------------------------------------------------------------*/ ++/* Command Routines */ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReq(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* RX Event Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone); ++ ++VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg); ++ ++VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg); ++ ++VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Generation */ ++/*----------------------------------------------------------------------------*/ ++VOID ++scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Query for sparse channel */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSsidNum, ++ IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval); ++ ++BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct); ++ ++BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++ ++BOOLEAN scnFsmGSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++ ++#if 0 ++ ++BOOLEAN scnFsmGSCNSetRssiSignificatn(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++#endif ++ ++BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId); ++ ++BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr); ++ ++#if 1 /* CFG_SUPPORT_GSCN_NONSYNC_BROADCOM */ ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam); ++ ++#else ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_REQ_T prCmdGscnParam); ++ ++#endif ++ ++BOOLEAN ++scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN); ++ ++BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig); ++ ++BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd); ++ ++VOID ++scnPSCNFsm(IN P_ADAPTER_T prAdapter, ++ ENUM_PSCAN_STATE_T eNextPSCNState, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN); ++ ++#endif /* _SCAN_H */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h +new file mode 100644 +index 000000000000..c6c468e06c4a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h +@@ -0,0 +1,233 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/sec_fsm.h#1 ++*/ ++ ++/*! \file sec_fsm.h ++ \brief Declaration of functions and finite state machine for SECURITY Module. ++ ++ Function declaration for privacy.c and SEC_STATE for SECURITY FSM. ++*/ ++ ++/* ++** Log: sec_fsm.h ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 03 04 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Code refine, and remove non-used code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, and modify the security ++ * related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * fixed the deauth Tx done callback parameter ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the reference function declaration ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * delete non-used code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function prototype ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function declaration ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security variable ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** \main\maintrunk.MT5921\14 2009-04-06 15:35:47 GMT mtk01088 ++** add the variable to set the disable AP selection for privacy check, for wps open networking. ++** \main\maintrunk.MT5921\13 2008-11-19 11:46:01 GMT mtk01088 ++** rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\12 2008-08-28 20:37:11 GMT mtk01088 ++** remove non-used code ++** ++** \main\maintrunk.MT5921\11 2008-03-18 09:51:52 GMT mtk01088 ++** Add function declaration for timer to indicate pmkid candidate ++** \main\maintrunk.MT5921\10 2008-02-29 15:12:08 GMT mtk01088 ++** add variable for sw port control ++** \main\maintrunk.MT5921\9 2008-02-29 12:37:30 GMT mtk01088 ++** rename the security related function declaration ++** \main\maintrunk.MT5921\8 2007-12-27 13:59:08 GMT mtk01088 ++** adjust the wlan table and sec fsm init timing ++** \main\maintrunk.MT5921\7 2007-11-20 10:39:49 GMT mtk01088 ++** add function timer for wait EAPoL Error timeout ++** \main\maintrunk.MT5921\6 2007-11-06 20:39:08 GMT mtk01088 ++** rename the counter measure timer ++** \main\maintrunk.MT5921\5 2007-11-06 20:14:31 GMT mtk01088 ++** add a abort function ++** Revision 1.5 2007/07/16 02:33:42 MTK01088 ++** change the ENUM declaration structure prefix from r to e ++** ++** Revision 1.4 2007/07/09 06:23:10 MTK01088 ++** update ++** ++** Revision 1.3 2007/07/04 10:09:04 MTK01088 ++** adjust the state for security fsm ++** change function name ++** ++** Revision 1.2 2007/07/03 08:13:22 MTK01088 ++** change the sec fsm state ++** add the event for sec fsm ++** ++** Revision 1.1 2007/06/27 06:20:35 MTK01088 ++** add the sec fsm header file ++** ++** ++*/ ++#ifndef _SEC_FSM_H ++#define _SEC_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* TKIP CounterMeasure interval for Rejoin to Network. */ ++#define COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC 60 ++ ++/* Timeout to wait the EAPoL Error Report frame Send out. */ ++#define EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef UINT_32 SEC_STATUS, *P_SEC_STATUS; ++ ++#if 0 ++/* WPA2 PMKID candicate structure */ ++typedef struct _PMKID_CANDICATE_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; /* MAC address */ ++ UINT_32 u4PreAuthFlags; ++} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; ++#endif ++ ++typedef SEC_STATUS(*PFN_SEC_FSM_STATE_HANDLER) (VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SEC_STATE_TRANSITION_FLAG fgIsTransition ++#define SEC_NEXT_STATE_VAR eNextState ++ ++#define SEC_STATE_TRANSITION(prAdapter, prSta, eFromState, eToState) \ ++ { secFsmTrans_ ## eFromState ## _to_ ## eToState(prAdapter, prSta); \ ++ SEC_NEXT_STATE_VAR = SEC_STATE_ ## eToState; \ ++ SEC_STATE_TRANSITION_FLAG = (BOOLEAN)TRUE; \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle the sec check */ ++/*--------------------------------------------------------------*/ ++/***** Routines in sec_fsm.c *****/ ++VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID ++secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++ ++VOID ++secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _SEC_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h +new file mode 100644 +index 000000000000..1c0f9a76e119 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h +@@ -0,0 +1,368 @@ ++/* ++** Id: stats.h#1 ++*/ ++ ++/*! \file stats.h ++ \brief This file includes statistics support. ++*/ ++ ++/* ++** Log: stats.h ++ * ++ * 07 17 2014 samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++extern UINT_64 u8DrvOwnStart, u8DrvOwnEnd; ++extern UINT32 u4DrvOwnMax; ++extern BOOLEAN fgIsUnderSuspend; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* Command to TDLS core module */ ++typedef enum _STATS_CMD_CORE_ID { ++ STATS_CORE_CMD_ENV_REQUEST = 0x00 ++} STATS_CMD_CORE_ID; ++ ++typedef enum _STATS_EVENT_HOST_ID { ++ STATS_HOST_EVENT_ENV_REPORT = 0x00, ++ STATS_HOST_EVENT_RX_DROP ++} STATS_EVENT_HOST_ID; ++ ++#define CFG_ARP BIT(0) ++#define CFG_DNS BIT(1) ++#define CFG_TCP BIT(2) ++#define CFG_UDP BIT(3) ++#define CFG_EAPOL BIT(4) ++#define CFG_DHCP BIT(5) ++#define CFG_ICMP BIT(6) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _STATS_CMD_CORE_T { ++ ++ UINT32 u4Command; /* STATS_CMD_CORE_ID */ ++ ++ UINT8 ucStaRecIdx; ++ UINT8 ucReserved[3]; ++ ++ UINT32 u4Reserved[4]; ++ ++#define STATS_CMD_CORE_RESERVED_SIZE 50 ++ union { ++ UINT8 Reserved[STATS_CMD_CORE_RESERVED_SIZE]; ++ } Content; ++ ++} STATS_CMD_CORE_T; ++ ++typedef struct _STATS_INFO_ENV_T { ++ ++ BOOLEAN fgIsUsed; /* TRUE: used */ ++ ++ /* ------------------- TX ------------------- */ ++ BOOLEAN fgTxIsRtsUsed; /* TRUE: we use RTS/CTS currently */ ++ BOOLEAN fgTxIsRtsEverUsed; /* TRUE: we ever use RTS/CTS */ ++ BOOLEAN fgTxIsCtsSelfUsed; /* TRUE: we use CTS-self */ ++ ++#define STATS_INFO_TX_PARAM_HW_BW40_OFFSET 0 ++#define STATS_INFO_TX_PARAM_HW_SHORT_GI20_OFFSET 1 ++#define STATS_INFO_TX_PARAM_HW_SHORT_GI40_OFFSET 2 ++#define STATS_INFO_TX_PARAM_USE_BW40_OFFSET 3 ++#define STATS_INFO_TX_PARAM_USE_SHORT_GI_OFFSET 4 ++#define STATS_INFO_TX_PARAM_NO_ACK_OFFSET 5 ++ UINT_8 ucTxParam; ++ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucReserved1[2]; ++ ++ UINT32 u4TxDataCntAll; /* total tx count from host */ ++ UINT32 u4TxDataCntOK; /* total tx ok count to air */ ++ UINT32 u4TxDataCntErr; /* total tx err count to air */ ++ ++ /* WLAN_STATUS_BUFFER_RETAINED ~ WLAN_STATUS_PACKET_LIFETIME_ERROR */ ++ UINT32 u4TxDataCntErrType[6]; /* total tx err count for different type to air */ ++ ++ UINT_8 ucTxRate1NonHTMax; ++ UINT_8 ucTxRate1HTMax; ++ UINT32 u4TxRateCntNonHT[16]; /* tx done rate */ ++ UINT32 u4TxRateCntHT[16]; /* tx done rate */ ++ ++ UINT_8 ucTxAggBitmap; /* TX BA sessions TID0 ~ TID7 */ ++ UINT_8 ucTxPeerAggMaxSize; ++ ++ /* ------------------- RX ------------------- */ ++ BOOLEAN fgRxIsRtsUsed; /* TRUE: peer uses RTS/CTS currently */ ++ BOOLEAN fgRxIsRtsEverUsed; /* TRUE: peer ever uses RTS/CTS */ ++ ++ UINT_8 ucRcvRcpi; ++ UINT_8 ucHwChanNum; ++ BOOLEAN fgRxIsShortGI; ++ UINT_8 ucReserved2[1]; ++ ++ UINT32 u4RxDataCntAll; /* total rx count from peer */ ++ UINT32 u4RxDataCntErr; /* total rx err count */ ++ UINT32 u4RxRateCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ ++ ++ UINT_8 ucRxAggBitmap; /* RX BA sessions TID0 ~ TID7 */ ++ UINT_8 ucRxAggMaxSize; ++ ++#define STATS_INFO_PHY_MODE_CCK 0 ++#define STATS_INFO_PHY_MODE_OFDM 1 ++#define STATS_INFO_PHY_MODE_HT 2 ++#define STATS_INFO_PHY_MODE_VHT 3 ++ UINT_8 ucBssSupPhyMode; /* CCK, OFDM, HT, or VHT BSS */ ++ ++ UINT_8 ucVersion; /* the version of statistics info environment */ ++ ++ /* ------------------- Delay ------------------- */ ++#define STATS_AIR_DELAY_INT 500 /* 500 byte */ ++ ++ /* delay in firmware from host to MAC */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxH2M[3], u4StayIntMinH2M[3], u4StayIntAvgH2M[3]; ++ ++ /* delay in firmware from MAC to TX done */ ++ /* unit: 32us, for 500B, 1000B, max */ ++ UINT32 u4AirDelayMax[3], u4AirDelayMin[3], u4AirDelayAvg[3]; ++ ++ /* delay in firmware from host to TX done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMax[3], u4StayIntMin[3], u4StayIntAvg[3]; ++ UINT32 u4StayIntMaxSysTime[3]; ++ ++ /* delay in firmware from driver to TX done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxD2T[3], u4StayIntMinD2T[3], u4StayIntAvgD2T[3]; ++ ++ /* delay count in firmware from host to TX done */ ++ /* u4StayIntByConst: divide 4 fix partitions to count each delay in firmware */ ++#define STATS_STAY_INT_CONST 1 /* 1ms */ ++#define STATS_STAY_INT_CONST_2 5 ++#define STATS_STAY_INT_CONST_3 10 ++#define STATS_STAY_INT_CONST_4 15 ++#define STATS_STAY_INT_CONST_NUM 4 ++ UINT32 u4StayIntByConst[STATS_STAY_INT_CONST_NUM]; ++ ++ /* ++ u4StayIntMaxPast: past maximum delay in firmware ++ u4StayIntCnt[]: divide 4 partitions to count each delay in firmware ++ */ ++#define STATS_STAY_INT_NUM 4 ++ UINT32 u4StayIntMaxPast; ++ UINT32 u4StayIntCnt[STATS_STAY_INT_NUM + 1]; ++ ++ /* delay count in firmware from driver to HIF */ ++ /* u4StayIntD2HByConst: divide 4 fix partitions to count each delay in firmware */ ++#define STATS_STAY_INT_D2H_CONST 10 /* 10ms */ ++#define STATS_STAY_INT_D2H_CONST_2 20 ++#define STATS_STAY_INT_D2H_CONST_3 30 ++#define STATS_STAY_INT_D2H_CONST_4 40 ++#define STATS_STAY_INT_D2H_CONST_NUM 4 ++ UINT32 u4StayIntD2HByConst[STATS_STAY_INT_D2H_CONST_NUM]; ++ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; ++ ++ /* ------------------- Others ------------------- */ ++ UINT32 u4NumOfChanChange; /* total channel change count */ ++ UINT32 u4NumOfRetryCnt; /* total TX retry count */ ++ UINT32 u4RxFifoFullCnt; /* counter of the number of the packets which ++ pass RFCR but are dropped due to FIFO full. */ ++ UINT32 u4PsIntMax; /* maximum time from ps to active */ ++ UINT_8 ucNumOfPsChange; /* peer power save change count */ ++ UINT_8 ucReserved3[3]; ++ ++ UINT32 u4ReportSysTime; /* firmware system time */ ++ UINT32 u4RxDataCntOk; /* total rx count to hif */ ++ ++ /* V4 */ ++ UINT32 u4RxRateRetryCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ ++ UINT32 au4ChanIdleCnt[10]; /* past Channel idle count in unit of slot */ ++ ++ /* V5 */ ++ UINT32 u4BtContUseTime; /* the air time that BT continuous occypy */ ++ ++ /* V6 */ ++ UINT32 u4LastTxOkTime; /* last time we tx ok to the station */ ++ ++ /* V7 */ ++ UINT_8 ucBtWfCoexGrantCnt[8]; /* [0]:WF Rx Grant Cnt[1]: WF Tx Grant Cnt[2]: WF Grant with Priority1 */ ++ /* [4]:BT Rx Grant Cnt[5]: BT Tx Grant Cnt[6]: BT Grant with Priority1 */ ++ ++ /* V8 */ ++ UINT_32 u4RxMacFreeDescCnt[6]; ++ UINT_32 u4RxHifFreeDescCnt[6]; ++ ++ /* V9 */ ++#define STATS_MAX_RX_DROP_TYPE 20 ++ UINT32 u4NumOfRxDrop[STATS_MAX_RX_DROP_TYPE]; ++ ++ /* V10 */ ++ UINT_32 u4NumOfTxDone; /* number of all packets (data/man/ctrl) tx done */ ++ UINT_32 u4NumOfTxDoneFixRate; /* number of done rate = 0 */ ++ UINT_32 u4NumOfTxDoneErrRate; /* number of error done rate */ ++ UINT_32 u4NumOfNullTxDone; /* number of null tx done */ ++ UINT_32 u4NumOfQoSNullTxDone; /* number of QoS-null tx done */ ++ ++ /* V11 */ ++ /* delay in firmware from HIF RX to HIF RX Done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxHR2HRD[3], u4StayIntMinHR2HRD[3], u4StayIntAvgHR2HRD[3]; ++ ++ /* V12 */ ++ UINT32 u4AirDelayTotal; /* agg all the air delay */ ++ ++ /* V13 */ ++ UINT32 u4CurrChnlInfo; /* add current channel information */ ++ ++ UINT_8 ucReserved_rate[4]; /* the field must be the last one */ ++} STATS_INFO_ENV_T; ++ ++/******************************************************************************* ++* M A C R O D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#if (CFG_SUPPORT_STATISTICS == 1) ++ ++#define STATS_ENV_REPORT_DETECT statsEnvReportDetect ++ ++#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderFallAheadCnt++; \ ++} ++ ++#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderFallBehindCnt++; \ ++} ++ ++#define STATS_RX_REORDER_HOLE_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderHoleCnt++; \ ++} ++ ++#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) \ ++{ \ ++ if ((__IsTimeout__) == TRUE) \ ++ (__StaRec__)->u4RxReorderHoleTimeoutCnt++; \ ++} ++ ++#define STATS_RX_ARRIVE_TIME_RECORD(__SwRfb__) \ ++{ \ ++ (__SwRfb__)->rRxTime = StatsEnvTimeGet(); \ ++} ++ ++#define STATS_RX_PASS2OS_INC StatsEnvRxDone ++ ++#define STATS_RX_PKT_INFO_DISPLAY StatsRxPktInfoDisplay ++ ++#define STATS_TX_TIME_ARRIVE(__Skb__) \ ++do { \ ++ UINT_64 __SysTime; \ ++ __SysTime = StatsEnvTimeGet(); /* us */ \ ++ GLUE_SET_PKT_XTIME(__Skb__, __SysTime); \ ++} while (FALSE) ++ ++#define STATS_TX_TIME_TO_HIF StatsEnvTxTime2Hif ++ ++#define STATS_TX_PKT_CALLBACK StatsTxPktCallBack ++#define STATS_TX_PKT_DONE_INFO_DISPLAY StatsTxPktDoneInfoDisplay ++ ++#define STATS_DRIVER_OWN_RESET() \ ++{ \ ++ u4DrvOwnMax = 0; \ ++} ++#define STATS_DRIVER_OWN_START_RECORD() \ ++{ \ ++ u8DrvOwnStart = StatsEnvTimeGet(); \ ++} ++#define STATS_DRIVER_OWN_END_RECORD() \ ++{ \ ++ u8DrvOwnEnd = StatsEnvTimeGet(); \ ++} ++#define STATS_DRIVER_OWN_STOP() \ ++do { \ ++ UINT32 __Diff; \ ++ __Diff = (UINT32)(u8DrvOwnEnd - u8DrvOwnStart); \ ++ if (__Diff > u4DrvOwnMax) \ ++ u4DrvOwnMax = __Diff; \ ++} while (FALSE) ++ ++#else ++ ++#define STATS_ENV_REPORT_DETECT(__Adapter__, __StaRecIndex__) ++ ++#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) ++#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) ++#define STATS_RX_REORDER_HOLE_INC(__StaRec__) ++#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) ++#define STATS_RX_PASS2OS_INC(__StaRec__, __SwRfb__) ++#define STATS_RX_PKT_INFO_DISPLAY(__Pkt__) ++ ++#define STATS_TX_TIME_ARRIVE(__Skb__) ++#define STATS_TX_TIME_TO_HIF(__MsduInfo__, __HwTxHeader__) ++#define STATS_TX_PKT_CALLBACK(__Pkt__, __fgIsNeedAck__) ++#define STATS_TX_PKT_DONE_INFO_DISPLAY(__Adapter__, __Event__) ++ ++#define STATS_DRIVER_OWN_RESET() ++#define STATS_DRIVER_OWN_START_RECORD() ++#define STATS_DRIVER_OWN_END_RECORD() ++#define STATS_DRIVER_OWN_STOP() ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex); ++ ++VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb); ++ ++UINT_64 StatsEnvTimeGet(VOID); ++ ++VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader); ++ ++VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++VOID StatsRxPktInfoDisplay(UINT_8 *pPkt); ++ ++VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo); ++ ++VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf); ++ ++VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet); ++ ++UINT_16 StatsGetCfgTxDone(VOID); ++ ++/* End of stats.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h +new file mode 100644 +index 000000000000..50c4b558c2cd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h +@@ -0,0 +1,187 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/swcr.h#1 ++*/ ++ ++/*! \file "swcr.h" ++ \brief ++*/ ++ ++/* ++ * ++ */ ++ ++#ifndef _SWCR_H ++#define _SWCR_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "nic_cmd_event.h" ++ ++#if 0 ++extern SWCR_MAP_ENTRY_T g_arRlmArSwCrMap[]; ++#endif ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define SWCR_VAR(x) ((VOID *)&x) ++#define SWCR_FUNC(x) ((VOID *)x) ++ ++#define SWCR_T_FUNC BIT(7) ++ ++#define SWCR_L_32 3 ++#define SWCR_L_16 2 ++#define SWCR_L_8 1 ++ ++#define SWCR_READ 0 ++#define SWCR_WRITE 1 ++ ++#define SWCR_MAP_NUM(x) (sizeof(x)/sizeof(x[0])) ++ ++#define SWCR_CR_NUM 7 ++ ++#define SWCR_GET_RW_INDEX(action, rw, index) \ ++do { \ ++ index = action & 0x7F; \ ++ rw = action >> 7; \ ++} while (0) ++ ++extern UINT_32 g_au4SwCr[]; /*: 0: command other: data */ ++ ++typedef VOID(*PFN_SWCR_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++typedef VOID(*PFN_CMD_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++ ++typedef struct _SWCR_MAP_ENTRY_T { ++ UINT_16 u2Type; ++ PVOID u4Addr; ++} SWCR_MAP_ENTRY_T, *P_SWCR_MAP_ENTRY_T; ++ ++typedef struct _SWCR_MOD_MAP_ENTRY_T { ++ UINT_8 ucMapNum; ++ P_SWCR_MAP_ENTRY_T prSwCrMap; ++} SWCR_MOD_MAP_ENTRY_T, *P_SWCR_MOD_MAP_ENTRY_T; ++ ++typedef enum _ENUM_SWCR_DBG_TYPE_T { ++ SWCR_DBG_TYPE_ALL = 0, ++ SWCR_DBG_TYPE_TXRX, ++ SWCR_DBG_TYPE_RX_RATES, ++ SWCR_DBG_TYPE_PS, ++ SWCR_DBG_TYPE_NUM ++} ENUM_SWCR_DBG_TYPE_T; ++ ++typedef enum _ENUM_SWCR_DBG_ALL_T { ++ SWCR_DBG_ALL_TX_CNT = 0, ++ SWCR_DBG_ALL_TX_BCN_CNT, ++ SWCR_DBG_ALL_TX_FAILED_CNT, ++ SWCR_DBG_ALL_TX_RETRY_CNT, ++ SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT, ++ SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT, ++ SWCR_DBG_ALL_TX_MGNT_DROP_CNT, ++ SWCR_DBG_ALL_TX_ERROR_CNT, ++ ++ SWCR_DBG_ALL_RX_CNT, ++ SWCR_DBG_ALL_RX_DROP_CNT, ++ SWCR_DBG_ALL_RX_DUP_DROP_CNT, ++ SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT, ++ ++ SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT, ++ ++ SWCR_DBG_ALL_RX_FCSERR_CNT, ++ SWCR_DBG_ALL_RX_FIFOFULL_CNT, ++ SWCR_DBG_ALL_RX_PFDROP_CNT, ++ ++ SWCR_DBG_ALL_PWR_PS_POLL_CNT, ++ SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT, ++ SWCR_DBG_ALL_PWR_BCN_IND_CNT, ++ SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT, ++ SWCR_DBG_ALL_PWR_PM_STATE0, ++ SWCR_DBG_ALL_PWR_PM_STATE1, ++ SWCR_DBG_ALL_PWR_CUR_PS_PROF0, ++ SWCR_DBG_ALL_PWR_CUR_PS_PROF1, ++ ++ SWCR_DBG_ALL_AR_STA0_RATE, ++ SWCR_DBG_ALL_AR_STA0_BWGI, ++ SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI, ++ ++ SWCR_DBG_ALL_ROAMING_ENABLE, ++ SWCR_DBG_ALL_ROAMING_ROAM_CNT, ++ SWCR_DBG_ALL_ROAMING_INT_CNT, ++ ++ SWCR_DBG_ALL_BB_RX_MDRDY_CNT, ++ SWCR_DBG_ALL_BB_RX_FCSERR_CNT, ++ SWCR_DBG_ALL_BB_CCK_PD_CNT, ++ SWCR_DBG_ALL_BB_OFDM_PD_CNT, ++ SWCR_DBG_ALL_BB_CCK_SFDERR_CNT, ++ SWCR_DBG_ALL_BB_CCK_SIGERR_CNT, ++ SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT, ++ SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT, ++ ++ SWCR_DBG_ALL_NUM ++} ENUM_SWCR_DBG_ALL_T; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++void testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++ ++/* Support Debug */ ++VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl); ++VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++ ++/* Debug Support */ ++VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType); ++VOID swCrDebugInit(P_ADAPTER_T prAdapter); ++VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout); ++VOID swCrDebugUninit(P_ADAPTER_T prAdapter); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h +new file mode 100644 +index 000000000000..3b6991131d05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h +@@ -0,0 +1,262 @@ ++/* ++** Id: include/tdls.h#1 ++*/ ++ ++/*! \file "tdls.h" ++ \brief This file contains the internal used in TDLS modules ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: tdls.h ++ * ++ * 11 18 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ * ++ ** ++ */ ++ ++#ifndef _TDLS_H ++#define _TDLS_H ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define TDLS_CFG_CMD_TEST 1 ++#define TDLS_CFG_HT_SUP 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); ++extern BOOLEAN flgTdlsTestExtCapElm; ++extern UINT8 aucTdlsTestExtCapElm[]; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++typedef struct _TDLS_LINK_HIS_OTHERS_T { ++ BOOLEAN fgIsHt; /* TRUE: HT device */ ++ ++} TDLS_LINK_HIS_OTHERS_T; ++ ++/* command */ ++typedef enum _TDLS_CMD_ID { ++ TDLS_CMD_TEST_TX_FRAME = 0x00, ++ TDLS_CMD_TEST_RCV_FRAME = 0x01, ++ TDLS_CMD_TEST_PEER_ADD = 0x02, ++ TDLS_CMD_TEST_PEER_UPDATE = 0x03, ++ TDLS_CMD_TEST_DATA_FRAME = 0x04, ++ TDLS_CMD_TEST_RCV_NULL = 0x05, ++ TDLS_CMD_MIB_UPDATE = 0x06, ++ TDLS_CMD_TEST_SKIP_TX_FAIL = 0x07, ++ TDLS_CMD_UAPSD_CONF = 0x08, ++ TDLS_CMD_CH_SW_CONF = 0x09, ++ TDLS_CMD_TEST_SKIP_KEEP_ALIVE = 0x0a, ++ TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT = 0x0b, ++ TDLS_CMD_TEST_TX_TDLS_FRAME = 0x0c, ++ TDLS_CMD_TEST_PROHIBIT_SET_IN_AP = 0x0d, ++ TDLS_CMD_TEST_SCAN_DISABLE = 0x0e, ++ TDLS_CMD_TEST_DATA_FRAME_CONT = 0x0f, ++ TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP = 0x10, ++ TDLS_CMD_SETUP_CONF = 0x11, ++ TDLS_CMD_INFO = 0x12, ++ TDLS_CMD_TEST_DELAY = 0x13, ++ TDLS_CMD_KEY_INFO = 0x14, ++ TDLS_CMD_TEST_PTI_TX_FAIL = 0x15 ++} TDLS_CMD_ID; ++ ++typedef enum _TDLS_EVENT_HOST_ID { ++ TDLS_HOST_EVENT_TEAR_DOWN = 0x00, /* TDLS_EVENT_HOST_SUBID_TEAR_DOWN */ ++ TDLS_HOST_EVENT_TX_DONE, ++ TDLS_HOST_EVENT_FME_STATUS, /* TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME */ ++ TDLS_HOST_EVENT_STATISTICS ++} TDLS_EVENT_HOST_ID; ++ ++typedef enum _TDLS_EVENT_HOST_SUBID_TEAR_DOWN { ++ TDLS_HOST_EVENT_TD_PTI_TIMEOUT = 0x00, ++ TDLS_HOST_EVENT_TD_AGE_TIMEOUT, ++ TDLS_HOST_EVENT_TD_PTI_SEND_FAIL, ++ TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL, ++ TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX, ++ TDLS_HOST_EVENT_TD_NON_STATE3, ++ TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN ++} TDLS_EVENT_HOST_SUBID_TEAR_DOWN; ++ ++typedef enum _TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME { ++ TDLS_HOST_EVENT_SF_BA, ++ TDLS_HOST_EVENT_SF_BA_OK, ++ TDLS_HOST_EVENT_SF_BA_DECLINE, ++ TDLS_HOST_EVENT_SF_BA_PEER, ++ TDLS_HOST_EVENT_SF_BA_RSP_OK, ++ TDLS_HOST_EVENT_SF_BA_RSP_DECLINE ++} TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME; ++ ++/* payload specific type in the LLC/SNAP header */ ++#define TDLS_FRM_PAYLOAD_TYPE 2 ++ ++#define TDLS_FRM_CATEGORY 12 ++ ++typedef enum _TDLS_FRM_ACTION_ID { ++ TDLS_FRM_ACTION_SETUP_REQ = 0x00, ++ TDLS_FRM_ACTION_SETUP_RSP, ++ TDLS_FRM_ACTION_CONFIRM, ++ TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_FRM_ACTION_PTI, ++ TDLS_FRM_ACTION_CHAN_SWITCH_REQ, ++ TDLS_FRM_ACTION_CHAN_SWITCH_RSP, ++ TDLS_FRM_ACTION_PEER_PSM_REQ, ++ TDLS_FRM_ACTION_PEER_PSM_RSP, ++ TDLS_FRM_ACTION_PTI_RSP, /* 0x09 */ ++ TDLS_FRM_ACTION_DISCOVERY_REQ, ++ ++ TDLS_FRM_ACTION_EVENT_TEAR_DOWN_TO_SUPPLICANT = 0x30, ++ ++ TDLS_FRM_DATA_TEST_DATA = 0x80 ++} TDLS_FRM_ACTION_ID; ++ ++#define TDLS_FRM_ACTION_DISCOVERY_RESPONSE 14 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* 7.3.2.62 Link Identifier element */ ++#define ELEM_ID_LINK_IDENTIFIER 101 ++#define ELEM_LEN_LINK_IDENTIFIER 18 ++ ++typedef struct _IE_LINK_IDENTIFIER_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aBSSID[6]; ++ UINT_8 aInitiator[6]; ++ UINT_8 aResponder[6]; ++} __KAL_ATTRIB_PACKED__ IE_LINK_IDENTIFIER_T; ++ ++#define TDLS_LINK_IDENTIFIER_IE(__ie__) ((IE_LINK_IDENTIFIER_T *)(__ie__)) ++ ++/* test command use */ ++typedef struct _PARAM_CUSTOM_TDLS_CMD_STRUCT_T { ++ ++ UINT_8 ucFmeType; /* TDLS_FRM_ACTION_ID */ ++ ++ UINT_8 ucToken; ++ UINT_16 u2Cap; ++ ++ /* bit0: TDLS, bit1: Peer U-APSD Buffer, bit2: Channel Switching */ ++#define TDLS_EX_CAP_PEER_UAPSD BIT(0) ++#define TDLS_EX_CAP_CHAN_SWITCH BIT(1) ++#define TDLS_EX_CAP_TDLS BIT(2) ++ UINT_8 ucExCap; ++ ++ UINT_8 arSupRate[4]; ++ UINT_8 arSupChan[4]; ++ ++ UINT_32 u4Timeout; ++ ++#define TDLS_FME_MAC_ADDR_LEN 6 ++ UINT_8 arRspAddr[TDLS_FME_MAC_ADDR_LEN]; ++ UINT_8 arBssid[TDLS_FME_MAC_ADDR_LEN]; ++ ++/* ++ Linux Kernel-3.10 ++ struct station_parameters { ++ const u8 *supported_rates; ++ struct net_device *vlan; ++ u32 sta_flags_mask, sta_flags_set; ++ u32 sta_modify_mask; ++ int listen_interval; ++ u16 aid; ++ u8 supported_rates_len; ++ u8 plink_action; ++ u8 plink_state; ++ const struct ieee80211_ht_cap *ht_capa; ++ const struct ieee80211_vht_cap *vht_capa; ++ u8 uapsd_queues; ++ u8 max_sp; ++ enum nl80211_mesh_power_mode local_pm; ++ u16 capability; ++ const u8 *ext_capab; ++ u8 ext_capab_len; ++ }; ++*/ ++ struct ieee80211_ht_cap rHtCapa; ++ struct ieee80211_vht_cap rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ struct station_parameters rPeerInfo; ++ ++} PARAM_CUSTOM_TDLS_CMD_STRUCT_T; ++ ++typedef struct _TDLS_MGMT_TX_INFO { ++ UINT8 aucPeer[6]; ++ UINT8 ucActionCode; ++ UINT8 ucDialogToken; ++ UINT16 u2StatusCode; ++ UINT32 u4SecBufLen; ++ UINT8 aucSecBuf[1000]; ++} TDLS_MGMT_TX_INFO; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* check any TDLS link */ ++#define TDLS_IS_NO_LINK_GOING(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt == 0) ++ ++/* increase TDLS link count */ ++#define TDLS_LINK_INCREASE(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt++) ++ ++/* decrease TDLS link count */ ++#define TDLS_LINK_DECREASE(__GlueInfo__) \ ++do { \ ++ if ((__GlueInfo__)->rTdlsLink.cLinkCnt > 0) \ ++ (__GlueInfo__)->rTdlsLink.cLinkCnt--; \ ++} while (0) ++ ++/* get TDLS link count */ ++#define TDLS_LINK_COUNT(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt) ++ ++/* reset TDLS link count */ ++#define TDLS_LINK_COUNT_RESET(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt = 0) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* Note: these functions are used only in tdls module, not other modules */ ++UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt); ++ ++TDLS_STATUS ++TdlsDataFrameSend(ADAPTER_T *prAdapter, ++ STA_RECORD_T *prStaRec, ++ UINT_8 *pPeerMac, ++ UINT_8 ucActionCode, ++ UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#endif /* _TDLS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h +new file mode 100644 +index 000000000000..12c9359f2e8f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h +@@ -0,0 +1,104 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wapi.h#1 ++*/ ++ ++/*! \file wapi.h ++ \brief The wapi related define, macro and structure are described here. ++*/ ++ ++/* ++** Log: wapi.h ++ * ++ * 07 20 2010 wh.su ++ * ++ * . ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the wapi function name and adding the generate wapi ie function ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some wapi structure define ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** \main\maintrunk.MT5921\1 2009-10-09 17:06:29 GMT mtk01088 ++** ++*/ ++ ++#ifndef _WAPI_H ++#define _WAPI_H ++ ++#if CFG_SUPPORT_WAPI ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define WAPI_CIPHER_SUITE_WPI 0x01721400 /* WPI_SMS4 */ ++#define WAPI_AKM_SUITE_802_1X 0x01721400 /* WAI */ ++#define WAPI_AKM_SUITE_PSK 0x02721400 /* WAI_PSK */ ++ ++#define ELEM_ID_WAPI 68 /* WAPI IE */ ++ ++#define WAPI_IE(fp) ((P_WAPI_INFO_ELEM_T) fp) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo); ++ ++BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++/* BOOLEAN */ ++/* wapiUpdateTxKeyIdx ( */ ++/* IN P_STA_RECORD_T prStaRec, */ ++/* IN UINT_8 ucWlanIdx */ ++/* ); */ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif ++#endif /* _WAPI_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h +new file mode 100644 +index 000000000000..5dc969f1cc05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h +@@ -0,0 +1,87 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wlan_typedef.h#1 ++*/ ++ ++/*! \file wlan_typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to all MGMT Protocol Stack. ++*/ ++ ++/* ++** Log: wlan_typedef.h ++*/ ++ ++#ifndef _WLAN_TYPEDEF_H ++#define _WLAN_TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for BSS_INFO_T structure, to describe the attributes used in a ++ * common BSS. ++ */ ++typedef struct _BSS_INFO_T BSS_INFO_T, *P_BSS_INFO_T; ++ ++typedef BSS_INFO_T AIS_BSS_INFO_T, *P_AIS_BSS_INFO_T; ++typedef BSS_INFO_T P2P_BSS_INFO_T, *P_P2P_BSS_INFO_T; ++typedef BSS_INFO_T BOW_BSS_INFO_T, *P_BOW_BSS_INFO_T; ++ ++typedef struct _AIS_SPECIFIC_BSS_INFO_T AIS_SPECIFIC_BSS_INFO_T, *P_AIS_SPECIFIC_BSS_INFO_T; ++typedef struct _P2P_SPECIFIC_BSS_INFO_T P2P_SPECIFIC_BSS_INFO_T, *P_P2P_SPECIFIC_BSS_INFO_T; ++typedef struct _BOW_SPECIFIC_BSS_INFO_T BOW_SPECIFIC_BSS_INFO_T, *P_BOW_SPECIFIC_BSS_INFO_T; ++/* CFG_SUPPORT_WFD */ ++typedef struct _WFD_CFG_SETTINGS_T WFD_CFG_SETTINGS_T, *P_WFD_CFG_SETTINGS_T; ++ ++typedef struct _WFD_DBG_CFG_SETTINGS_T WFD_DBG_CFG_SETTINGS_T, *P_WFD_DBG_CFG_SETTINGS_T; ++ ++/* BSS related structures */ ++/* Type definition for BSS_DESC_T structure, to describe parameter sets of a particular BSS */ ++typedef struct _BSS_DESC_T BSS_DESC_T, *P_BSS_DESC_T, **PP_BSS_DESC_T; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++typedef struct _HS20_INFO_T HS20_INFO_T, *P_HS20_INFO_T; ++#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _WLAN_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h +new file mode 100644 +index 000000000000..09bc0b5d5151 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h +@@ -0,0 +1,95 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/mgmt/wnm.h#1 ++*/ ++ ++/*! \file wnm.h ++ \brief This file contains the IEEE 802.11 family related 802.11v network management ++ for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wnm.h ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * ++*/ ++ ++#ifndef _WNM_H ++#define _WNM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _TIMINGMSMT_PARAM_T { ++ BOOLEAN fgInitiator; ++ UINT_8 ucTrigger; ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ ++ UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ ++ UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ ++} TIMINGMSMT_PARAM_T, *P_TIMINGMSMT_PARAM_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++WLAN_STATUS ++wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID ++wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA); ++ ++#define WNM_UNIT_TEST 1 ++ ++#if WNM_UNIT_TEST ++VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WNM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h +new file mode 100644 +index 000000000000..d34f2c9c36a8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h +@@ -0,0 +1,1506 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/adapter.h#3 ++*/ ++ ++/*! \file adapter.h ++ \brief Definition of internal data structure for driver manipulation. ++ ++ In this file we define the internal data structure - ADAPTER_T which stands ++ for MiniPort ADAPTER(From Windows point of view) or stands for Network ADAPTER. ++*/ ++ ++/* ++** Log: adapter.h ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have ++** connected to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration ++ * corresponding to network type. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve inorder issue under AP mode. ++ * ++ * data frame may TX before assoc response frame. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Remove ERP member in adapter structure ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * Action frame callback for GO Device Discoverability Req. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically ++ * continuous memory shortage after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce ++ * physically continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 yuche.tsai ++ * [WCXRP00000533] [Volunteer Patch][MT6620][Driver] Provide a P2P function API for Legacy WiFi to query AP mode. ++ * Provide an API for Legacy WiFi to query the operation mode.. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as ++ * initial RSSI right after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid ++ * using a uninitialized MAC-RX RCPI. ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module ++ * with structure miss-align pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to ++ * target station for AAA module. ++ * Provide disconnect function for AAA module. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting ++ * Support CTIA power mode setting. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add CWMin CWMax for AP to generate IE. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a common IE buffer in P2P INFO structure. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * restore configuration as before. ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add an intend mode for BSS info. ++ * It is used to let P2P BSS Info to know which OP Mode it is going to become. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Remove BSS info which is redonedent in Wifi Var.. ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P FSM Info in adapter. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related field, additional include p2p_fsm.h if p2p is enabled. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * reserve field of privacy filter and RTS threshold setting. ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move ucCmdSeqNum as instance variable ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * 4. correct some HAL implementation ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * and result is retrieved by get ATInfo instead ++ * * * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 28 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate redundant variables for connection_state ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-16 18:02:03 GMT mtk02752 ++** add external reference to avoid compilation error ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:40:26 GMT mtk02752 ++** eliminate unused member ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-08 17:36:08 GMT mtk02752 ++** add RF test data members into P_ADAPTER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:45 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-28 10:29:57 GMT mtk01461 ++** Add read WTSR for SDIO_STATUS_ENHANCE mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:37:35 GMT mtk01461 ++** Add prPendingCmdInfoOfOID for temporarily saving the CMD_INFO_T before en-queue to rCmdQueue ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:57:51 GMT mtk01461 ++** Add MGMT Buffer Info ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:34:12 GMT mtk01461 ++** Add SW pre test CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:41:48 GMT mtk01461 ++** Add fgIsWmmAssoc flag for TC assignment ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:51 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:51:52 GMT mtk01426 ++** Add #if CFG_SDIO_RX_ENHANCE related data structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:17 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _ADAPTER_H ++#define _ADAPTER_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#include "hs20.h" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _ENHANCE_MODE_DATA_STRUCT_T SDIO_CTRL_T, *P_SDIO_CTRL_T; ++ ++typedef struct _WLAN_INFO_T { ++ PARAM_BSSID_EX_T rCurrBssId; ++ ++ /* Scan Result */ ++ PARAM_BSSID_EX_T arScanResult[CFG_MAX_NUM_BSS_LIST]; ++ PUINT_8 apucScanResultIEs[CFG_MAX_NUM_BSS_LIST]; ++ UINT_32 u4ScanResultNum; ++ ++ /* IE pool for Scanning Result */ ++ UINT_8 aucScanIEBuf[CFG_MAX_COMMON_IE_BUF_LEN]; ++ UINT_32 u4ScanIEBufferUsage; ++ ++ OS_SYSTIME u4SysTime; ++ ++ /* connection parameter (for Ad-Hoc) */ ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2AtimWindow; ++ ++ PARAM_RATES eDesiredRates; ++ CMD_LINK_ATTRIB eLinkAttr; ++/* CMD_PS_PROFILE_T ePowerSaveMode; */ ++ CMD_PS_PROFILE_T arPowerSaveMode[NETWORK_TYPE_INDEX_NUM]; ++ ++ /* trigger parameter */ ++ ENUM_RSSI_TRIGGER_TYPE eRssiTriggerType; ++ PARAM_RSSI rRssiTriggerValue; ++ ++ /* Privacy Filter */ ++ ENUM_PARAM_PRIVACY_FILTER_T ePrivacyFilter; ++ ++ /* RTS Threshold */ ++ PARAM_RTS_THRESHOLD eRtsThreshold; ++ ++ /* Network Type */ ++ UINT_8 ucNetworkType; ++ ++ /* Network Type In Use */ ++ UINT_8 ucNetworkTypeInUse; ++ ++} WLAN_INFO_T, *P_WLAN_INFO_T; ++ ++/* Session for CONNECTION SETTINGS */ ++typedef struct _CONNECTION_SETTINGS_T { ++ ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ ++ UINT_8 ucDelayTimeOfDisconnectEvent; ++ ++ BOOLEAN fgIsConnByBssidIssued; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ ++ BOOLEAN fgIsConnReqIssued; ++ BOOLEAN fgIsDisconnectedByNonRequest; ++ ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ ++ ENUM_PARAM_OP_MODE_T eOPMode; ++ ++ ENUM_PARAM_CONNECTION_POLICY_T eConnectionPolicy; ++ ++ ENUM_PARAM_AD_HOC_MODE_T eAdHocMode; ++ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ++ BOOLEAN fgIsScanReqIssued; ++ ++ /* MIB attributes */ ++ UINT_16 u2BeaconPeriod; ++ ++ UINT_16 u2RTSThreshold; /* User desired setting */ ++ ++ UINT_16 u2DesiredNonHTRateSet; /* User desired setting */ ++ ++ UINT_8 ucAdHocChannelNum; /* For AdHoc */ ++ ++ ENUM_BAND_T eAdHocBand; /* For AdHoc */ ++ ++ UINT_32 u4FreqInKHz; /* Center frequency */ ++ ++ /* ATIM windows using for IBSS power saving function */ ++ UINT_16 u2AtimWindow; ++ ++ /* Features */ ++ BOOLEAN fgIsEnableRoaming; ++ ++ BOOLEAN fgIsAdHocQoSEnable; ++ ++ ENUM_PARAM_PHY_CONFIG_T eDesiredPhyConfig; ++ ++ /* Used for AP mode for desired channel and bandwidth */ ++ UINT_16 u2CountryCode; ++ UINT_16 u2CountryCodeBakup; ++ UINT_8 uc2G4BandwidthMode; /* 20/40M or 20M only */ ++ UINT_8 uc5GBandwidthMode; /* 20/40M or 20M only */ ++ ++ BOOLEAN fgTxShortGIDisabled; ++ BOOLEAN fgRxShortGIDisabled; ++ ++#if CFG_SUPPORT_802_11D ++ BOOLEAN fgMultiDomainCapabilityEnabled; ++#endif /* CFG_SUPPORT_802_11D */ ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ BOOLEAN fgWapiMode; ++ UINT_32 u4WapiSelectedGroupCipher; ++ UINT_32 u4WapiSelectedPairwiseCipher; ++ UINT_32 u4WapiSelectedAKMSuite; ++#endif ++ ++ /* CR1486, CR1640 */ ++ /* for WPS, disable the privacy check for AP selection policy */ ++ BOOLEAN fgPrivacyCheckDisable; ++ ++ /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 bmfgApsdEnAc; ++ ++ /* for RSN info store, when upper layer set rsn info */ ++ RSN_INFO_T rRsnInfo; ++ ++} CONNECTION_SETTINGS_T, *P_CONNECTION_SETTINGS_T; ++ ++struct _BSS_INFO_T { ++ ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ ++ ENUM_PARAM_MEDIA_STATE_T eConnectionStateIndicated; /* The Media State that report to HOST */ ++ ++ ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ ++#if CFG_ENABLE_WIFI_DIRECT ++ ENUM_OP_MODE_T eIntendOPMode; ++#endif ++ ++ BOOLEAN fgIsNetActive; /* TRUE if this network has been activated */ ++ ++ UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ ++ ++ UINT_8 ucReasonOfDisconnect; /* Used by media state indication */ ++ ++ UINT_8 ucSSIDLen; /* Length of SSID */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ENUM_HIDDEN_SSID_TYPE_T eHiddenSsidType; /* For Hidden SSID usage. */ ++#endif ++ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID used in this BSS */ ++ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* The BSSID of the associated BSS */ ++ ++ UINT_8 aucOwnMacAddr[MAC_ADDR_LEN]; /* Owned MAC Address used in this BSS */ ++ ++ P_STA_RECORD_T prStaRecOfAP; /* For Infra Mode, and valid only if ++ * eConnectionState == MEDIA_STATE_CONNECTED ++ */ ++ LINK_T rStaRecOfClientList; /* For IBSS/AP Mode, all known STAs in current BSS */ ++ ++ UINT_16 u2CapInfo; /* Change Detection */ ++ ++ UINT_16 u2BeaconInterval; /* The Beacon Interval of this BSS */ ++ ++ UINT_16 u2ATIMWindow; /* For IBSS Mode */ ++ ++ UINT_16 u2AssocId; /* For Infra Mode, it is the Assoc ID assigned by AP. ++ */ ++ ++ UINT_8 ucDTIMPeriod; /* For Infra/AP Mode */ ++ ++ UINT_8 ucDTIMCount; /* For AP Mode, it is the DTIM value we should carried in ++ * the Beacon of next TBTT. ++ */ ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer ++ * (This is deduced from received BSS_DESC_T) ++ */ ++ ++ UINT_8 ucNonHTBasicPhyType; /* The Basic PHY Type Index, used to setup Phy Capability */ ++ ++ UINT_8 ucConfigAdHocAPMode; /* The configuration of AdHoc/AP Mode. e.g. 11g or 11b */ ++ ++ UINT_8 ucBeaconTimeoutCount; /* For Infra/AP Mode, it is a threshold of Beacon Lost Count to ++ confirm connection was lost */ ++ ++ BOOLEAN fgHoldSameBssidForIBSS; /* For IBSS Mode, to keep use same BSSID to extend the life cycle of an IBSS */ ++ ++ BOOLEAN fgIsBeaconActivated; /* For AP/IBSS Mode, it is used to indicate that Beacon is sending */ ++ ++ P_MSDU_INFO_T prBeacon; /* For AP/IBSS Mode - Beacon Frame */ ++ ++ BOOLEAN fgIsIBSSMaster; /* For IBSS Mode - To indicate that we can reply ProbeResp Frame. ++ In current TBTT interval */ ++ ++ BOOLEAN fgIsShortPreambleAllowed; /* From Capability Info. of AssocResp Frame ++ AND of Beacon/ProbeResp Frame */ ++ BOOLEAN fgUseShortPreamble; /* Short Preamble is enabled in current BSS. */ ++ BOOLEAN fgUseShortSlotTime; /* Short Slot Time is enabled in current BSS. */ ++ ++ UINT_16 u2OperationalRateSet; /* Operational Rate Set of current BSS */ ++ UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of current BSS */ ++ ++ UINT_8 ucAllSupportedRatesLen; /* Used for composing Beacon Frame in AdHoc or AP Mode */ ++ UINT_8 aucAllSupportedRates[RATE_NUM]; ++ ++ UINT_8 ucAssocClientCnt; /* TODO(Kevin): Number of associated clients */ ++ ++ BOOLEAN fgIsProtection; ++ BOOLEAN fgIsQBSS; /* fgIsWmmBSS; *//* For Infra/AP/IBSS Mode, it is used to indicate if we support WMM in ++ * current BSS. */ ++ BOOLEAN fgIsNetAbsent; /* TRUE: BSS is absent, FALSE: BSS is present */ ++ ++ UINT_32 u4RsnSelectedGroupCipher; ++ UINT_32 u4RsnSelectedPairwiseCipher; ++ UINT_32 u4RsnSelectedAKMSuite; ++ UINT_16 u2RsnSelectedCapInfo; ++ ++ /*------------------------------------------------------------------------*/ ++ /* Power Management related information */ ++ /*------------------------------------------------------------------------*/ ++ PM_PROFILE_SETUP_INFO_T rPmProfSetupInfo; ++ ++ /*------------------------------------------------------------------------*/ ++ /* WMM/QoS related information */ ++ /*------------------------------------------------------------------------*/ ++ UINT_8 ucWmmParamSetCount; /* Used to detect the change of EDCA parameters. For AP mode, ++ the value is used in WMM IE */ ++ ++ AC_QUE_PARMS_T arACQueParms[WMM_AC_INDEX_NUM]; ++ ++ UINT_8 aucCWminLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWminLog2 */ ++ UINT_8 aucCWmaxLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWmaxLog2 */ ++ AC_QUE_PARMS_T arACQueParmsForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the value */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* 802.11n HT operation IE when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) */ ++ /* is true. They have the same definition with fields of */ ++ /* information element (CM) */ ++ /*------------------------------------------------------------------------*/ ++ ENUM_BAND_T eBand; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucHtOpInfo1; ++ UINT_16 u2HtOpInfo2; ++ UINT_16 u2HtOpInfo3; ++ ++ /*------------------------------------------------------------------------*/ ++ /* Required protection modes (CM) */ ++ /*------------------------------------------------------------------------*/ ++ BOOLEAN fgErpProtectMode; ++ ENUM_HT_PROTECT_MODE_T eHtProtectMode; ++ ENUM_GF_MODE_T eGfOperationMode; ++ ENUM_RIFS_MODE_T eRifsOperationMode; ++ ++ BOOLEAN fgObssErpProtectMode; /* GO only */ ++ ENUM_HT_PROTECT_MODE_T eObssHtProtectMode; /* GO only */ ++ ENUM_GF_MODE_T eObssGfOperationMode; /* GO only */ ++ BOOLEAN fgObssRifsOperationMode; /* GO only */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* OBSS to decide if 20/40M bandwidth is permitted. */ ++ /* The first member indicates the following channel list length. */ ++ /*------------------------------------------------------------------------*/ ++ BOOLEAN fgAssoc40mBwAllowed; ++ BOOLEAN fg40mBwAllowed; ++ ENUM_CHNL_EXT_T eBssSCO; /* Real setting for HW ++ * 20/40M AP mode will always set 40M, ++ * but its OP IE can be changed. ++ */ ++ UINT_8 auc2G_20mReqChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_NonHtChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_PriChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_SecChnlList[CHNL_LIST_SZ_2G + 1]; ++ ++ UINT_8 auc5G_20mReqChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_NonHtChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_PriChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_SecChnlList[CHNL_LIST_SZ_5G + 1]; ++ ++ TIMER_T rObssScanTimer; ++ UINT_16 u2ObssScanInterval; /* in unit of sec */ ++ ++ BOOLEAN fgObssActionForcedTo20M; /* GO only */ ++ BOOLEAN fgObssBeaconForcedTo20M; /* GO only */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* HW Related Fields (Kevin) */ ++ /*------------------------------------------------------------------------*/ ++ UINT_8 ucHwDefaultFixedRateCode; /* The default rate code copied to MAC TX Desc */ ++ UINT_16 u2HwLPWakeupGuardTimeUsec; ++ ++ UINT_8 ucBssFreeQuota; /* The value is updated from FW */ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ P_IPV4_NETWORK_ADDRESS_LIST prIpV4NetAddrList; ++#endif ++ UINT_16 u2DeauthReason; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ ++ BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ ++#endif /* CFG_SUPPORT_TDLS */ ++}; ++ ++struct _AIS_SPECIFIC_BSS_INFO_T { ++ UINT_8 ucRoamingAuthTypes; /* This value indicate the roaming type used in AIS_JOIN */ ++ ++ BOOLEAN fgIsIBSSActive; ++ ++ /*! \brief Global flag to let arbiter stay at standby and not connect to any network */ ++ BOOLEAN fgCounterMeasure; ++ UINT_8 ucWEPDefaultKeyID; ++ BOOLEAN fgTransmitKeyExist; /* Legacy wep Transmit key exist or not */ ++ ++ /* While Do CounterMeasure procedure, check the EAPoL Error report have send out */ ++ BOOLEAN fgCheckEAPoLTxDone; ++ ++ UINT_32 u4RsnaLastMICFailTime; ++ ++ /* Stored the current bss wpa rsn cap filed, used for roaming policy */ ++ /* UINT_16 u2RsnCap; */ ++ TIMER_T rPreauthenticationTimer; ++ ++ /* By the flow chart of 802.11i, ++ wait 60 sec before associating to same AP ++ or roaming to a new AP ++ or sending data in IBSS, ++ keep a timer for handle the 60 sec counterMeasure */ ++ TIMER_T rRsnaBlockTrafficTimer; ++ TIMER_T rRsnaEAPoLReportTimeoutTimer; ++ ++ /* For Keep the Tx/Rx Mic key for TKIP SW Calculate Mic */ ++ /* This is only one for AIS/AP */ ++ UINT_8 aucTxMicKey[8]; ++ UINT_8 aucRxMicKey[8]; ++ ++ /* Buffer for WPA2 PMKID */ ++ /* The PMKID cache lifetime is expire by media_disconnect_indication */ ++ UINT_32 u4PmkidCandicateCount; ++ PMKID_CANDICATE_T arPmkidCandicate[CFG_MAX_PMKID_CACHE]; ++ UINT_32 u4PmkidCacheCount; ++ PMKID_ENTRY_T arPmkidCache[CFG_MAX_PMKID_CACHE]; ++ BOOLEAN fgIndicatePMKID; ++#if CFG_SUPPORT_802_11W ++ BOOLEAN fgMgmtProtection; ++ UINT_32 u4SaQueryStart; ++ UINT_32 u4SaQueryCount; ++ UINT_8 ucSaQueryTimedOut; ++ PUINT_8 pucSaQueryTransId; ++ TIMER_T rSaQueryTimer; ++ BOOLEAN fgBipKeyInstalled; ++#endif ++}; ++ ++struct _BOW_SPECIFIC_BSS_INFO_T { ++ UINT_16 u2Reserved; /* Reserved for Data Type Check */ ++}; ++ ++#if CFG_SLT_SUPPORT ++typedef struct _SLT_INFO_T { ++ ++ P_BSS_DESC_T prPseudoBssDesc; ++ UINT_16 u2SiteID; ++ UINT_8 ucChannel2G4; ++ UINT_8 ucChannel5G; ++ BOOLEAN fgIsDUT; ++ UINT_32 u4BeaconReceiveCnt; ++ /* ///////Deprecated///////// */ ++ P_STA_RECORD_T prPseudoStaRec; ++} SLT_INFO_T, *P_SLT_INFO_T; ++#endif ++ ++/* Major member variables for WiFi FW operation. ++ Variables within this region will be ready for access after WIFI function is enabled. ++*/ ++typedef struct _WIFI_VAR_T { ++ BOOLEAN fgIsRadioOff; ++ ++ BOOLEAN fgIsEnterD3ReqIssued; ++ ++ BOOLEAN fgDebugCmdResp; ++ ++ CONNECTION_SETTINGS_T rConnSettings; ++ ++ SCAN_INFO_T rScanInfo; ++ ++#if CFG_SUPPORT_ROAMING ++ ROAMING_INFO_T rRoamingInfo; ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ AIS_FSM_INFO_T rAisFsmInfo; ++ ++ ENUM_PWR_STATE_T aePwrState[NETWORK_TYPE_INDEX_NUM]; ++ ++ BSS_INFO_T arBssInfo[NETWORK_TYPE_INDEX_NUM]; ++ ++ AIS_SPECIFIC_BSS_INFO_T rAisSpecificBssInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings; ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo; ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ BOW_SPECIFIC_BSS_INFO_T rBowSpecificBssInfo; ++ BOW_FSM_INFO_T rBowFsmInfo; ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ DEAUTH_INFO_T arDeauthInfo[MAX_DEAUTH_INFO_COUNT]; ++ ++ /* Current Wi-Fi Settings and Flags */ ++ UINT_8 aucPermanentAddress[MAC_ADDR_LEN]; ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ UINT_8 aucDeviceAddress[MAC_ADDR_LEN]; ++ UINT_8 aucInterfaceAddress[MAC_ADDR_LEN]; ++ ++ UINT_8 ucAvailablePhyTypeSet; ++ ++ ENUM_PHY_TYPE_INDEX_T eNonHTBasicPhyType2G4; /* Basic Phy Type used by SCN according ++ * to the set of Available PHY Types ++ */ ++ ++ ENUM_PARAM_PREAMBLE_TYPE_T ePreambleType; ++ ENUM_REGISTRY_FIXED_RATE_T eRateSetting; ++ ++ BOOLEAN fgIsShortSlotTimeOptionEnable; ++ /* User desired setting, but will honor the capability of AP */ ++ ++ BOOLEAN fgEnableJoinToHiddenSSID; ++ BOOLEAN fgSupportWZCDisassociation; ++ ++ BOOLEAN fgSupportQoS; ++ BOOLEAN fgSupportAmpduTx; ++ BOOLEAN fgSupportAmpduRx; ++ BOOLEAN fgSupportTspec; ++ BOOLEAN fgSupportUAPSD; ++ BOOLEAN fgSupportULPSMP; ++ UINT_8 u8SupportRxSgi20; /* 0: default 1: enable 2:disble */ ++ UINT_8 u8SupportRxSgi40; ++ UINT_8 u8SupportRxGf; ++ UINT_8 u8SupportRxSTBC; ++#if CFG_SUPPORT_CFG_FILE ++ UINT_8 ucApWpsMode; ++ UINT_8 ucCert11nMode; ++#endif ++#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT ++ UINT_8 ucCeFccTxPwrLimit; ++ UINT_8 ucCeFccTxPwrLimitCck; ++ UINT_8 ucCeFccTxPwrLimitOfdmHt20; ++ UINT_8 ucCeFccTxPwrLimitHt40; ++#endif ++ ++#if CFG_SLT_SUPPORT ++ SLT_INFO_T rSltInfo; ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ HS20_INFO_T rHS20Info; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ PARAM_GET_CHN_LOAD rChnLoadInfo; ++#endif ++ ++} WIFI_VAR_T, *P_WIFI_VAR_T; /* end of _WIFI_VAR_T */ ++ ++/* cnm_timer module */ ++typedef struct { ++ LINK_T rLinkHead; ++ OS_SYSTIME rNextExpiredSysTime; ++ KAL_WAKE_LOCK_T rWakeLock; ++ BOOLEAN fgWakeLocked; ++} ROOT_TIMER, *P_ROOT_TIMER; ++ ++/* FW/DRV/NVRAM version information */ ++typedef struct { ++ ++ /* NVRAM or Registry */ ++ UINT_16 u2Part1CfgOwnVersion; ++ UINT_16 u2Part1CfgPeerVersion; ++ UINT_16 u2Part2CfgOwnVersion; ++ UINT_16 u2Part2CfgPeerVersion; ++ ++ /* Firmware */ ++ UINT_16 u2FwProductID; ++ UINT_16 u2FwOwnVersion; ++ UINT_16 u2FwPeerVersion; ++ ++} WIFI_VER_INFO_T, *P_WIFI_VER_INFO_T; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/* ++* p2p function pointer structure ++*/ ++ ++typedef struct _P2P_FUNCTION_LINKER { ++ P2P_REMOVE prP2pRemove; ++/* NIC_P2P_MEDIA_STATE_CHANGE prNicP2pMediaStateChange; */ ++/* SCAN_UPDATE_P2P_DEVICE_DESC prScanUpdateP2pDeviceDesc; */ ++/* P2P_FSM_RUN_EVENT_RX_PROBE_RESPONSE_FRAME prP2pFsmRunEventRxProbeResponseFrame; */ ++ P2P_GENERATE_P2P_IE prP2pGenerateWSC_IEForBeacon; ++/* P2P_CALCULATE_WSC_IE_LEN_FOR_PROBE_RSP prP2pCalculateWSC_IELenForProbeRsp; */ ++/* P2P_GENERATE_WSC_IE_FOR_PROBE_RSP prP2pGenerateWSC_IEForProbeRsp; */ ++/* SCAN_REMOVE_P2P_BSS_DESC prScanRemoveP2pBssDesc; */ ++/* P2P_HANDLE_SEC_CHECK_RSP prP2pHandleSecCheckRsp; */ ++ P2P_NET_REGISTER prP2pNetRegister; ++ P2P_NET_UNREGISTER prP2pNetUnregister; ++ P2P_CALCULATE_P2P_IE_LEN prP2pCalculateP2p_IELenForAssocReq; /* All IEs generated from supplicant. */ ++ P2P_GENERATE_P2P_IE prP2pGenerateP2p_IEForAssocReq; /* All IEs generated from supplicant. */ ++} P2P_FUNCTION_LINKER, *P_P2P_FUNCTION_LINKER; ++ ++#endif ++ ++/* ++ *State Machine: ++ *-->STOP: Turn on/off WiFi ++ *-->DISABLE: Screen was off (wlanHandleSystemSuspend) ++ *-->ENABLE: Screen was on (wlanHandleSystemResume) ++ *----->clear DISABLE ++ *-->RUNNING: Screen was on && Tx/Rx was ongoing (wlanHardStartXmit/kalRxIndicatePkts) ++*/ ++struct GL_PER_MON_T { ++ TIMER_T rPerfMonTimer; ++ ULONG ulPerfMonFlag; ++ ULONG ulLastTxBytes; ++ ULONG ulLastRxBytes; ++ ULONG ulP2PLastTxBytes; ++ ULONG ulP2PLastRxBytes; ++ /*in bps*/ ++ ULONG ulThroughput; ++ /*in ms*/ ++ UINT32 u4UpdatePeriod; ++ UINT32 u4TarPerfLevel; ++ UINT32 u4CurrPerfLevel; ++}; ++ ++/* ++ * Major ADAPTER structure ++ * Major data structure for driver operation ++ */ ++struct _ADAPTER_T { ++ UINT_8 ucRevID; ++ ++ UINT_16 u2NicOpChnlNum; ++ ++ BOOLEAN fgIsEnableWMM; ++ BOOLEAN fgIsWmmAssoc; /* This flag is used to indicate that WMM is enable in current BSS */ ++ ++ UINT_32 u4OsPacketFilter; /* packet filter used by OS */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ UINT_32 u4CSUMFlags; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ ENUM_BAND_T aePreferBand[NETWORK_TYPE_INDEX_NUM]; ++ ++ /* ADAPTER flags */ ++ UINT_32 u4Flags; ++ UINT_32 u4HwFlags; ++ ++ BOOLEAN fgIsRadioOff; ++ ++ BOOLEAN fgIsEnterD3ReqIssued; ++ ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ ++ ENUM_PHY_TYPE_INDEX_T eCurrentPhyType; /* Current selection basing on the set of Available PHY Types */ ++ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ UINT_32 u4CoalescingBufCachedSize; ++ PUINT_8 pucCoalescingBufCached; ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* Buffer for CMD_INFO_T, Mgt packet and mailbox message */ ++ BUF_INFO_T rMgtBufInfo; ++ BUF_INFO_T rMsgBufInfo; ++ PUINT_8 pucMgtBufCached; ++ UINT_32 u4MgtBufCachedSize; ++ UINT_8 aucMsgBuf[MSG_BUFFER_SIZE]; ++#if CFG_DBG_MGT_BUF ++ UINT_32 u4MemAllocDynamicCount; /* Debug only */ ++ UINT_32 u4MemFreeDynamicCount; /* Debug only */ ++#endif ++ ++ STA_RECORD_T arStaRec[CFG_STA_REC_NUM]; ++ ++ /* Element for TX PATH */ ++ TX_CTRL_T rTxCtrl; ++ QUE_T rFreeCmdList; ++ CMD_INFO_T arHifCmdDesc[CFG_TX_MAX_CMD_PKT_NUM]; ++ ++ /* Element for RX PATH */ ++ RX_CTRL_T rRxCtrl; ++ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ /* Element for MT6620 E1 HIFSYS workaround */ ++ BOOLEAN fgIsClockGatingEnabled; ++#endif ++ ++ /* Buffer for Authentication Event */ ++ /* Move to glue layer and refine the kal function */ ++ /* Reference to rsnGeneratePmkidIndication function at rsn.c */ ++ UINT_8 aucIndicationEventBuffer[(CFG_MAX_PMKID_CACHE * 20) + 8]; ++ ++ UINT_32 u4IntStatus; ++ ++ ENUM_ACPI_STATE_T rAcpiState; ++ ++ BOOLEAN fgIsIntEnable; ++ BOOLEAN fgIsIntEnableWithLPOwnSet; ++ ++ BOOLEAN fgIsFwOwn; ++ BOOLEAN fgWiFiInSleepyState; ++ ++ UINT_32 u4PwrCtrlBlockCnt; ++ ++ QUE_T rPendingCmdQueue; ++ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ UINT_8 ucCmdSeqNum; ++ UINT_8 ucTxSeqNum; ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ BOOLEAN fgUseWapi; ++#endif ++ ++ /* RF Test flags */ ++ BOOLEAN fgTestMode; ++ ++ /* WLAN Info for DRIVER_CORE OID query */ ++ WLAN_INFO_T rWlanInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2PRegistered; ++ ENUM_NET_REG_STATE_T rP2PNetRegState; ++ BOOLEAN fgIsWlanLaunched; ++ P_P2P_INFO_T prP2pInfo; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ OS_SYSTIME rP2pLinkQualityUpdateTime; ++ BOOLEAN fgIsP2pLinkQualityValid; ++ EVENT_LINK_QUALITY rP2pLinkQuality; ++#endif ++ ++ /* FSM Timer */ ++ TIMER_T rP2pFsmTimeoutTimer; ++#endif ++ ++ /* Online Scan Option */ ++ BOOLEAN fgEnOnlineScan; ++ ++ /* Online Scan Option */ ++ BOOLEAN fgDisBcnLostDetection; ++ ++ /* MAC address */ ++ PARAM_MAC_ADDRESS rMyMacAddr; ++ ++ /* Wake-up Event for WOL */ ++ UINT_32 u4WakeupEventEnable; ++ ++ /* Event Buffering */ ++ EVENT_STATISTICS rStatStruct; ++ OS_SYSTIME rStatUpdateTime; ++ BOOLEAN fgIsStatValid; ++ ++ EVENT_LINK_QUALITY rLinkQuality; ++ OS_SYSTIME rLinkQualityUpdateTime; ++ BOOLEAN fgIsLinkQualityValid; ++ OS_SYSTIME rLinkRateUpdateTime; ++ BOOLEAN fgIsLinkRateValid; ++ ++ /* WIFI_VAR_T */ ++ WIFI_VAR_T rWifiVar; ++ ++ /* MTK WLAN NIC driver IEEE 802.11 MIB */ ++ IEEE_802_11_MIB_T rMib; ++ ++ /* Mailboxs for inter-module communication */ ++ MBOX_T arMbox[MBOX_ID_TOTAL_NUM]; ++ ++ /* Timers for OID Pending Handling */ ++ TIMER_T rOidTimeoutTimer; ++ ++ TIMER_T rReturnIndicatedRfbListTimer; ++ ++ /* Root Timer for cnm_timer module */ ++ ROOT_TIMER rRootTimer; ++ ++ /* RLM maintenance */ ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_SYS_PROTECT_MODE_T eSysProtectMode; ++ ENUM_GF_MODE_T eSysHtGfMode; ++ ENUM_RIFS_MODE_T eSysTxRifsMode; ++ ENUM_SYS_PCO_PHASE_T eSysPcoPhase; ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ /* QM */ ++ QUE_MGT_T rQM; ++ ++ CNM_INFO_T rCnmInfo; ++ ++ UINT_32 u4PowerMode; ++ ++ UINT_32 u4CtiaPowerMode; ++ BOOLEAN fgEnCtiaPowerMode; ++ ++ UINT_32 fgEnArpFilter; ++ ++ UINT_32 u4UapsdAcBmp; ++ ++ UINT_32 u4MaxSpLen; ++ ++ UINT_32 u4PsCurrentMeasureEn; ++ ++ /* Version Information */ ++ WIFI_VER_INFO_T rVerInfo; ++ ++ /* 5GHz support (from F/W) */ ++ BOOLEAN fgIsHw5GBandDisabled; ++ BOOLEAN fgEnable5GBand; ++ BOOLEAN fgIsEepromUsed; ++ BOOLEAN fgIsEfuseValid; ++ BOOLEAN fgIsEmbbededMacAddrValid; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ BOOLEAN fgIsPowerLimitTableValid; ++#endif ++ ++ /* Packet Forwarding Tracking */ ++ INT_32 i4PendingFwdFrameCount; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ UINT_8 ucRddStatus; ++#endif ++ ++ BOOLEAN fgDisStaAgingTimeoutDetection; ++#if CFG_SUPPORT_CFG_FILE ++ P_WLAN_CFG_T prWlanCfg; ++ WLAN_CFG_T rWlanCfg; ++#endif ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ KAL_WAKE_LOCK_T rApWakeLock; ++#endif ++ UINT_32 u4FwCompileFlag0; ++ UINT_32 u4FwCompileFlag1; ++ KAL_WAKE_LOCK_T rTxThreadWakeLock; ++ KAL_WAKE_LOCK_T rAhbIsrWakeLock; ++ ++#if CFG_SUPPORT_ROAMING_ENC ++ BOOLEAN fgIsRoamingEncEnabled; ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsSup; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ UINT_8 ucScanTime; ++ ++#if CFG_SUPPORT_DBG_POWERMODE ++ BOOLEAN fgEnDbgPowerMode; /* dbg privilege power mode, always keep in active */ ++#endif ++ ++ UINT_32 u4AirDelayTotal; /* dbg privilege power mode, always keep in active */ ++ ULONG ulSuspendFlag; ++ struct GL_PER_MON_T rPerMonitor; ++}; /* end of _ADAPTER_T */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SUSPEND_FLAG_FOR_WAKEUP_REASON (0) ++#define SUSPEND_FLAG_CLEAR_WHEN_RESUME (1) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for BSS_INFO_T - Flag of Net Active */ ++/*----------------------------------------------------------------------------*/ ++#define IS_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive) ++#define IS_BSS_ACTIVE(_prBssInfo) ((_prBssInfo)->fgIsNetActive) ++ ++#define IS_AIS_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_AIS_INDEX) ++#define IS_P2P_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_P2P_INDEX) ++#define IS_BOW_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_BOW_INDEX) ++ ++#define SET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = TRUE; } ++ ++#define UNSET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = FALSE; } ++ ++#define BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ ++ { UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; \ ++ P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ ++ \ ++ _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; \ ++ _prBssInfo->fgIsNetActive = FALSE; \ ++ _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ ++ _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ ++ COPY_MAC_ADDR(_prBssInfo->aucBSSID, _aucZeroMacAddr); \ ++ LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ ++ _prBssInfo->fgIsBeaconActivated = FALSE; \ ++ _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ ++ _prBssInfo->fgIsNetAbsent = FALSE; \ ++ } ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#define BOW_BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ ++ { \ ++ P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ ++ \ ++ _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eCurrentOPMode = OP_MODE_BOW; \ ++ _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ ++ _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ ++ LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ ++ _prBssInfo->fgIsBeaconActivated = TRUE; \ ++ _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ ++ _prBssInfo->fgIsNetAbsent = FALSE; \ ++ } ++#endif ++ ++#define PERF_MON_DISABLE_BIT_OFF (0) ++#define PERF_MON_STOP_BIT_OFF (1) ++#define PERF_MON_RUNNING_BIT_OFF (2) ++ ++#define THROUGHPUT_L1_THRESHOLD (20*1024*1024) ++#define THROUGHPUT_L2_THRESHOLD (60*1024*1024) ++#define THROUGHPUT_L3_THRESHOLD (135*1024*1024) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for Power State */ ++/*----------------------------------------------------------------------------*/ ++#define SET_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_IDLE; } ++ ++#define SET_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_ACTIVE; } ++ ++#define SET_NET_PWR_STATE_PS(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_PS; } ++ ++#define IS_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_ACTIVE) ++ ++#define IS_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_IDLE) ++ ++#define IS_SCN_PWR_STATE_ACTIVE(_prAdapter) \ ++ (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_ACTIVE) ++ ++#define IS_SCN_PWR_STATE_IDLE(_prAdapter) \ ++ (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_IDLE) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ADAPTER_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h +new file mode 100644 +index 000000000000..6c4c1b76622b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h +@@ -0,0 +1,322 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/bow.h#1 ++*/ ++ ++/* ++** Log: bow.h ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Submit missing BoW header files. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW structure. ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add Activity Report definition. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix wrong BoW event size. ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * basic implementation for EVENT_BT_OVER_WIFI ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * sync. with design document for interface change. ++ * ++ * 04 02 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * Wi-Fi driver no longer needs to implement 802.11 PAL, thus replaced by wrapping command/event definitions ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * correct typo. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * update for all command/event needed to be supported by 802.11 PAL. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++*/ ++ ++#ifndef _BOW_H_ ++#define _BOW_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define BOWDEVNAME "bow0" ++ ++#define MAX_BOW_NUMBER_OF_CHANNEL_2G4 14 ++#define MAX_BOW_NUMBER_OF_CHANNEL_5G 4 ++/* (MAX_BOW_NUMBER_OF_CHANNEL_2G4 + MAX_BOW_NUMBER_OF_CHANNEL_5G) */ ++#define MAX_BOW_NUMBER_OF_CHANNEL 18 ++ ++#define MAX_ACTIVITY_REPORT 2 ++#define MAX_ACTIVITY_REPROT_TIME 660 ++ ++#define ACTIVITY_REPORT_STATUS_SUCCESS 0 ++#define ACTIVITY_REPORT_STATUS_FAILURE 1 ++#define ACTIVITY_REPORT_STATUS_TIME_INVALID 2 ++#define ACTIVITY_REPORT_STATUS_OTHERS 3 ++ ++#define ACTIVITY_REPORT_SCHEDULE_UNKNOWN 0 /* Does not know the schedule of the interference */ ++#define ACTIVITY_REPORT_SCHEDULE_KNOWN 1 ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _BT_OVER_WIFI_COMMAND_HEADER_T { ++ UINT_8 ucCommandId; ++ UINT_8 ucSeqNumber; ++ UINT_16 u2PayloadLength; ++} AMPC_COMMAND_HEADER_T, *P_AMPC_COMMAND_HEADER_T; ++ ++typedef struct _BT_OVER_WIFI_COMMAND { ++ AMPC_COMMAND_HEADER_T rHeader; ++ UINT_8 aucPayload[0]; ++} AMPC_COMMAND, *P_AMPC_COMMAND; ++ ++typedef struct _BT_OVER_WIFI_EVENT_HEADER_T { ++ UINT_8 ucEventId; ++ UINT_8 ucSeqNumber; ++ UINT_16 u2PayloadLength; ++} AMPC_EVENT_HEADER_T, *P_AMPC_EVENT_HEADER_T; ++ ++typedef struct _BT_OVER_WIFI_EVENT { ++ AMPC_EVENT_HEADER_T rHeader; ++ UINT_8 aucPayload[0]; ++} AMPC_EVENT, *P_AMPC_EVENT; ++ ++typedef struct _CHANNEL_DESC_T { ++ UINT_8 ucChannelBand; ++ UINT_8 ucChannelNum; ++} CHANNEL_DESC, P_CHANNEL_DESC; ++ ++/* Command Structures */ ++typedef struct _BOW_SETUP_CONNECTION { ++/* Fixed to 2.4G */ ++ UINT_8 ucChannelNum; ++ UINT_8 ucReserved1; ++ UINT_8 aucPeerAddress[6]; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 ucPAL_Capabilities; ++ INT_8 cMaxTxPower; ++ UINT_8 ucReserved2; ++ ++/* Pending, for future BOW 5G supporting. */ ++/* UINT_8 aucPeerAddress[6]; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 ucPAL_Capabilities; ++ INT_8 cMaxTxPower; ++ UINT_8 ucChannelListNum; ++ CHANNEL_DESC arChannelList[1]; ++*/ ++} BOW_SETUP_CONNECTION, *P_BOW_SETUP_CONNECTION; ++ ++typedef struct _BOW_DESTROY_CONNECTION { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_DESTROY_CONNECTION, *P_BOW_DESTROY_CONNECTION; ++ ++typedef struct _BOW_SET_PTK { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++ UINT_8 aucTemporalKey[16]; ++} BOW_SET_PTK, *P_BOW_SET_PTK; ++ ++typedef struct _BOW_READ_RSSI { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_READ_RSSI, *P_BOW_READ_RSSI; ++ ++typedef struct _BOW_READ_LINK_QUALITY { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_READ_LINK_QUALITY, *P_BOW_READ_LINK_QUALITY; ++ ++typedef struct _BOW_SHORT_RANGE_MODE { ++ UINT_8 aucPeerAddress[6]; ++ INT_8 cTxPower; ++ UINT_8 ucReserved; ++} BOW_SHORT_RANGE_MODE, *P_BOW_SHORT_RANGE_MODE; ++ ++/* Event Structures */ ++typedef struct _BOW_COMMAND_STATUS { ++ UINT_8 ucStatus; ++ UINT_8 ucReserved[3]; ++} BOW_COMMAND_STATUS, *P_BOW_COMMAND_STATUS; ++ ++typedef struct _BOW_MAC_STATUS { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucAvailability; ++ UINT_8 ucNumOfChannel; ++ CHANNEL_DESC arChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; ++} BOW_MAC_STATUS, *P_BOW_MAC_STATUS; ++ ++typedef struct _BOW_LINK_CONNECTED { ++ CHANNEL_DESC rChannel; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_LINK_CONNECTED, *P_BOW_LINK_CONNECTED; ++ ++typedef struct _BOW_LINK_DISCONNECTED { ++ UINT_8 ucReason; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_LINK_DISCONNECTED, *P_BOW_LINK_DISCONNECTED; ++ ++typedef struct _BOW_RSSI { ++ INT_8 cRssi; ++ UINT_8 aucReserved[3]; ++} BOW_RSSI, *P_BOW_RSSI; ++ ++typedef struct _BOW_LINK_QUALITY { ++ UINT_8 ucLinkQuality; ++ UINT_8 aucReserved[3]; ++} BOW_LINK_QUALITY, *P_BOW_LINK_QUALITY; ++ ++typedef enum _ENUM_BOW_CMD_ID_T { ++ BOW_CMD_ID_GET_MAC_STATUS = 1, ++ BOW_CMD_ID_SETUP_CONNECTION, ++ BOW_CMD_ID_DESTROY_CONNECTION, ++ BOW_CMD_ID_SET_PTK, ++ BOW_CMD_ID_READ_RSSI, ++ BOW_CMD_ID_READ_LINK_QUALITY, ++ BOW_CMD_ID_SHORT_RANGE_MODE, ++ BOW_CMD_ID_GET_CHANNEL_LIST, ++} ENUM_BOW_CMD_ID_T, *P_ENUM_BOW_CMD_ID_T; ++ ++typedef enum _ENUM_BOW_EVENT_ID_T { ++ BOW_EVENT_ID_COMMAND_STATUS = 1, ++ BOW_EVENT_ID_MAC_STATUS, ++ BOW_EVENT_ID_LINK_CONNECTED, ++ BOW_EVENT_ID_LINK_DISCONNECTED, ++ BOW_EVENT_ID_RSSI, ++ BOW_EVENT_ID_LINK_QUALITY, ++ BOW_EVENT_ID_CHANNEL_LIST, ++ BOW_EVENT_ID_CHANNEL_SELECTED, ++} ENUM_BOW_EVENT_ID_T, *P_ENUM_BOW_EVENT_ID_T; ++ ++typedef enum _ENUM_BOW_DEVICE_STATE { ++ BOW_DEVICE_STATE_DISCONNECTED = 0, ++ BOW_DEVICE_STATE_DISCONNECTING, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL, ++ BOW_DEVICE_STATE_STARTING, ++ BOW_DEVICE_STATE_SCANNING, ++ BOW_DEVICE_STATE_CONNECTING, ++ BOW_DEVICE_STATE_CONNECTED, ++ BOW_DEVICE_STATE_NUM ++} ENUM_BOW_DEVICE_STATE, *P_ENUM_BOW_DEVICE_STATE; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_BOW_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h +new file mode 100644 +index 000000000000..c1ecb303b877 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h +@@ -0,0 +1,150 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "cmd_buf.h" ++ \brief In this file we define the structure for Command Packet. ++ ++ In this file we define the structure for Command Packet and the control unit ++ of MGMT Memory Pool. ++*/ ++ ++/* ++** Log: cmd_buf.h ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow ++ * under concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Enable change log ++*/ ++ ++#ifndef _CMD_BUF_H ++#define _CMD_BUF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _COMMAND_TYPE { ++ COMMAND_TYPE_GENERAL_IOCTL, ++ COMMAND_TYPE_NETWORK_IOCTL, ++ COMMAND_TYPE_SECURITY_FRAME, ++ COMMAND_TYPE_MANAGEMENT_FRAME, ++ COMMAND_TYPE_NUM ++} COMMAND_TYPE, *P_COMMAND_TYPE; ++ ++typedef VOID(*PFN_CMD_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++typedef VOID(*PFN_CMD_TIMEOUT_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++struct _CMD_INFO_T { ++ QUE_ENTRY_T rQueEntry; ++ ++ COMMAND_TYPE eCmdType; ++ ++ UINT_16 u2InfoBufLen; /* This is actual CMD buffer length */ ++ PUINT_8 pucInfoBuffer; /* May pointer to structure in prAdapter */ ++ P_NATIVE_PACKET prPacket; /* only valid when it's a security frame */ ++ ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkType; ++ UINT_8 ucStaRecIndex; /* only valid when it's a security frame */ ++ ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler; ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler; ++ ++ BOOLEAN fgIsOid; /* Used to check if we need indicate */ ++ ++ UINT_8 ucCID; ++ BOOLEAN fgSetQuery; ++ BOOLEAN fgNeedResp; ++ BOOLEAN fgDriverDomainMCR; /* Access Driver Domain MCR, for CMD_ID_ACCESS_REG only */ ++ UINT_8 ucCmdSeqNum; ++ UINT_32 u4SetInfoLen; /* Indicate how many byte we read for Set OID */ ++ ++ /* information indicating by OID/ioctl */ ++ PVOID pvInformationBuffer; ++ UINT_32 u4InformationBufferLength; ++ ++ /* private data */ ++ UINT_32 u4PrivateData; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter); ++ ++P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); ++ ++VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for CMDs */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); ++VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _CMD_BUF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h +new file mode 100644 +index 000000000000..0fdb9dcadeef +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h +@@ -0,0 +1,618 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hal.h#1 ++*/ ++ ++/*! \file "hal.h" ++ \brief The declaration of hal functions ++ ++ N/A ++*/ ++ ++/* ++** Log: hal.h ++ * ++ * 04 01 2011 tsaiyuan.hsu ++ * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues ++ * fix the klocwork issues, 57500, 57501, 57502 and 57503. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change zero-padding for TX port access to HAL. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * 4. correct some HAL implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-16 18:02:26 GMT mtk02752 ++** include precomp.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:16 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 13:54:15 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-11 10:36:01 GMT mtk01084 ++** modify HAL functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-09 22:56:28 GMT mtk01084 ++** modify HW access routines ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:50:09 GMT mtk01084 ++** add new macro HAL_TX_PORT_WR ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:08:10 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:50 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-05-18 14:28:10 GMT mtk01084 ++** fix issue in HAL_DRIVER_OWN_BY_SDIO_CMD52() ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-11 17:26:33 GMT mtk01084 ++** modify the bit definition to check driver own status ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:30:22 GMT mtk01461 ++** Fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:50:34 GMT mtk01461 ++** Redefine HAL_PORT_RD/WR macro for SW pre test ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-24 09:46:49 GMT mtk01084 ++** fix LINT error ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 16:53:38 GMT mtk01084 ++** add HAL_DRIVER_OWN_BY_SDIO_CMD52() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:53:13 GMT mtk01426 ++** Fixed lint warn ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:20 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _HAL_H ++#define _HAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* Macros for flag operations for the Adapter structure */ ++#define HAL_SET_FLAG(_M, _F) ((_M)->u4HwFlags |= (_F)) ++#define HAL_CLEAR_FLAG(_M, _F) ((_M)->u4HwFlags &= ~(_F)) ++#define HAL_TEST_FLAG(_M, _F) ((_M)->u4HwFlags & (_F)) ++#define HAL_TEST_FLAGS(_M, _F) (((_M)->u4HwFlags & (_F)) == (_F)) ++ ++#if defined(_HIF_SDIO) ++#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ ++do { \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ /* DBGLOG(HAL, ERROR, ("HAL_MCR_RD access fail! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)*_pu4Value)); */ \ ++ } \ ++ } else { \ ++ /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_RD access! 0x%x\n", (UINT32)_u4Offset)); */ \ ++ } \ ++} while (0) ++ ++#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ ++do { \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ /* DBGLOG(HAL, ERROR, ("HAL_MCR_WR access fail! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ ++ } \ ++ } else { \ ++ /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_WR access! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ ++ } \ ++} while (0) ++ ++#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ /*fgResult = FALSE; */\ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_PORT_RD access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /*fgResult = TRUE;*/ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_PORT_RD access! 0x%x\n", _u4Port); \ ++ } \ ++} ++ ++#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ /*fgResult = FALSE; */\ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_PORT_WR access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /*fgResult = TRUE;*/ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_PORT_WR access! 0x%x\n", _u4Port); \ ++ } \ ++} ++ ++#if 0 /* only for SDIO */ ++#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_BYTE_WR access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /* Todo:: Nothing*/ \ ++ } \ ++ } \ ++ else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_BYTE_WR access! 0x%x\n", _u4Port); \ ++ } \ ++} ++#endif ++ ++#define HAL_DRIVER_OWN_BY_SDIO_CMD52(_prAdapter, _pfgDriverIsOwnReady) \ ++{ \ ++ UINT_8 ucBuf = BIT(1); \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevReadAfterWriteWithSdioCmd52(_prAdapter->prGlueInfo, MCR_WHLPCR_BYTE1, &ucBuf, 1) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "kalDevReadAfterWriteWithSdioCmd52 access fail!\n"); \ ++ } \ ++ else { \ ++ *_pfgDriverIsOwnReady = (ucBuf & BIT(0)) ? TRUE : FALSE; \ ++ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_DRIVER_OWN_BY_SDIO_CMD52 access!\n"); \ ++ } \ ++} ++ ++#else /* #if defined(_HIF_SDIO) */ ++#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#if 0 /* only for SDIO */ ++#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf); \ ++} ++#endif ++ ++#endif /* #if defined(_HIF_SDIO) */ ++ ++#define HAL_READ_RX_PORT(prAdapter, u4PortId, u4Len, pvBuf, _u4ValidBufSize) \ ++{ \ ++ ASSERT(u4PortId < 2); \ ++ HAL_PORT_RD(prAdapter, \ ++ ((u4PortId == 0) ? MCR_WRDR0 : MCR_WRDR1), \ ++ u4Len, \ ++ pvBuf, \ ++ _u4ValidBufSize/*temp!!*//*4Kbyte*/); \ ++} ++ ++#define HAL_WRITE_TX_PORT(_prAdapter, _ucTxPortIdx, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ ASSERT(_ucTxPortIdx < 2); \ ++ if ((_u4ValidBufSize - _u4Len) >= sizeof(UINT_32)) { \ ++ /* fill with single dword of zero as TX-aggregation termination */ \ ++ *(PUINT_32) (&((_pucBuf)[ALIGN_4(_u4Len)])) = 0; \ ++ } \ ++ HAL_PORT_WR(_prAdapter, \ ++ (_ucTxPortIdx == 0) ? MCR_WTDR0 : MCR_WTDR1, \ ++ _u4Len, \ ++ _pucBuf, \ ++ _u4ValidBufSize/*temp!!*//*4KByte*/); \ ++} ++ ++/* The macro to read the given MCR several times to check if the wait ++ condition come true. */ ++#define HAL_MCR_RD_AND_WAIT(_pAdapter, _offset, _pReadValue, _waitCondition, _waitDelay, _waitCount, _status) \ ++{ \ ++ UINT_32 count; \ ++ (_status) = FALSE; \ ++ for (count = 0; count < (_waitCount); count++) { \ ++ HAL_MCR_RD((_pAdapter), (_offset), (_pReadValue)); \ ++ if ((_waitCondition)) { \ ++ (_status) = TRUE; \ ++ break; \ ++ } \ ++ kalUdelay((_waitDelay)); \ ++ } \ ++} ++ ++/* The macro to write 1 to a R/S bit and read it several times to check if the ++ command is done */ ++#define HAL_MCR_WR_AND_WAIT(_pAdapter, _offset, _writeValue, _busyMask, _waitDelay, _waitCount, _status) \ ++{ \ ++ UINT_32 u4Temp; \ ++ UINT_32 u4Count = _waitCount; \ ++ (_status) = FALSE; \ ++ HAL_MCR_WR((_pAdapter), (_offset), (_writeValue)); \ ++ do { \ ++ kalUdelay((_waitDelay)); \ ++ HAL_MCR_RD((_pAdapter), (_offset), &u4Temp); \ ++ if (!(u4Temp & (_busyMask))) { \ ++ (_status) = TRUE; \ ++ break; \ ++ } \ ++ u4Count--; \ ++ } while (u4Count); \ ++} ++ ++#define HAL_GET_CHIP_ID_VER(_prAdapter, pu2ChipId, pu2Version) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WCIR, \ ++ &u4Value); \ ++ *pu2ChipId = (UINT_16)(u4Value & WCIR_CHIP_ID); \ ++ *pu2Version = (UINT_16)(u4Value & WCIR_REVISION_ID) >> 16; \ ++} ++ ++#define HAL_WAIT_WIFI_FUNC_READY(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ UINT_32 i; \ ++ for (i = 0; i < 100; i++) { \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WCIR, \ ++ &u4Value); \ ++ if (u4Value & WCIR_WLAN_READY) { \ ++ break; \ ++ } \ ++ NdisMSleep(10); \ ++ } \ ++} ++ ++#define HAL_INTR_DISABLE(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_INT_EN_CLR) ++ ++#define HAL_INTR_ENABLE(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_INT_EN_SET) ++ ++#define HAL_INTR_ENABLE_AND_LP_OWN_SET(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ (WHLPCR_INT_EN_SET | WHLPCR_FW_OWN_REQ_SET)) ++ ++#define HAL_LP_OWN_SET(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_FW_OWN_REQ_SET) ++ ++#define HAL_LP_OWN_CLR_OK(_prAdapter, _pfgResult) \ ++{ \ ++ UINT_32 i; \ ++ UINT_32 u4RegValue; \ ++ UINT_32 u4LoopCnt = 2048 / 8; \ ++ *_pfgResult = TRUE; \ ++ /* Software get LP ownership */ \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_FW_OWN_REQ_CLR) \ ++ for (i = 0; i < u4LoopCnt; i++) { \ ++ HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ ++ if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ ++ break; \ ++ } \ ++ else { \ ++ kalUdelay(8); \ ++ } \ ++ } \ ++ if (i == u4LoopCnt) { \ ++ *_pfgResult = FALSE; \ ++ /*ERRORLOG(("LP cannot be own back (%ld)", u4LoopCnt));*/ \ ++ /* check the time of LP instructions need to perform from Sleep to On */ \ ++ /*ASSERT(0); */ \ ++ } \ ++} ++ ++#define HAL_GET_ABNORMAL_INTERRUPT_REASON_CODE(_prAdapter, pu4AbnormalReason) \ ++{ \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WASR, \ ++ pu4AbnormalReason); \ ++} ++ ++#define HAL_DISABLE_RX_ENHANCE_MODE(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value & ~WHCR_RX_ENHANCE_MODE_EN); \ ++} ++ ++#define HAL_ENABLE_RX_ENHANCE_MODE(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value | WHCR_RX_ENHANCE_MODE_EN); \ ++} ++ ++#define HAL_CFG_MAX_HIF_RX_LEN_NUM(_prAdapter, _ucNumOfRxLen) \ ++{ \ ++ UINT_32 u4Value, ucNum; \ ++ ucNum = ((_ucNumOfRxLen >= 16) ? 0 : _ucNumOfRxLen); \ ++ u4Value = 0; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ u4Value &= ~WHCR_MAX_HIF_RX_LEN_NUM; \ ++ u4Value |= ((((UINT_32)ucNum) << 4) & WHCR_MAX_HIF_RX_LEN_NUM); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value); \ ++} ++ ++#define HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(prAdapter, \ ++ MCR_WHCR, \ ++ u4Value & ~WHCR_W_INT_CLR_CTRL); \ ++ prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = TRUE;\ ++} ++ ++#define HAL_SET_INTR_STATUS_WRITE_1_CLEAR(prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(prAdapter, \ ++ MCR_WHCR, \ ++ u4Value | WHCR_W_INT_CLR_CTRL); \ ++ prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = FALSE;\ ++} ++ ++/* Note: enhance mode structure may also carried inside the buffer, ++ if the length of the buffer is long enough */ ++#define HAL_READ_INTR_STATUS(prAdapter, length, pvBuf) \ ++ HAL_PORT_RD(prAdapter, \ ++ MCR_WHISR, \ ++ length, \ ++ pvBuf, \ ++ length) ++ ++#define HAL_READ_TX_RELEASED_COUNT(_prAdapter, aucTxReleaseCount) \ ++{ \ ++ PUINT_32 pu4Value = (PUINT_32)aucTxReleaseCount; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WTSR0, \ ++ &pu4Value[0]); \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WTSR1, \ ++ &pu4Value[1]); \ ++} ++ ++#define HAL_READ_RX_LENGTH(prAdapter, pu2Rx0Len, pu2Rx1Len) \ ++{ \ ++ UINT_32 u4Value; \ ++ u4Value = 0; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WRPLR, \ ++ &u4Value); \ ++ *pu2Rx0Len = (UINT_16)u4Value; \ ++ *pu2Rx1Len = (UINT_16)(u4Value >> 16); \ ++} ++ ++#define HAL_GET_INTR_STATUS_FROM_ENHANCE_MODE_STRUCT(pvBuf, u2Len, pu4Status) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvBuf; \ ++ *pu4Status = pu4Buf[0]; \ ++} ++ ++#define HAL_GET_TX_STATUS_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4BufOut, u4LenBufOut) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ ASSERT(u4LenBufOut >= 8); \ ++ pu4BufOut[0] = pu4Buf[1]; \ ++ pu4BufOut[1] = pu4Buf[2]; \ ++} ++ ++#define HAL_GET_RX_LENGTH_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu2Rx0Num, au2Rx0Len, pu2Rx1Num, au2Rx1Len) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ ASSERT((sizeof(au2Rx0Len) / sizeof(UINT_16)) >= 16); \ ++ ASSERT((sizeof(au2Rx1Len) / sizeof(UINT_16)) >= 16); \ ++ *pu2Rx0Num = (UINT_16)pu4Buf[3]; \ ++ *pu2Rx1Num = (UINT_16)(pu4Buf[3] >> 16); \ ++ kalMemCopy(au2Rx0Len, &pu4Buf[4], 8); \ ++ kalMemCopy(au2Rx1Len, &pu4Buf[12], 8); \ ++} ++ ++#define HAL_GET_MAILBOX_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4Mailbox0, pu4Mailbox1) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ *pu4Mailbox0 = (UINT_16)pu4Buf[21]; \ ++ *pu4Mailbox1 = (UINT_16)pu4Buf[22]; \ ++} ++ ++#define HAL_IS_TX_DONE_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_TX_DONE_INT) ? TRUE : FALSE) ++ ++#define HAL_IS_RX_DONE_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)) ? TRUE : FALSE) ++ ++#define HAL_IS_ABNORMAL_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_ABNORMAL_INT) ? TRUE : FALSE) ++ ++#define HAL_IS_FW_OWNBACK_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_FW_OWN_BACK_INT) ? TRUE : FALSE) ++ ++#define HAL_PUT_MAILBOX(prAdapter, u4MboxId, u4Data) \ ++{ \ ++ ASSERT(u4MboxId < 2); \ ++ HAL_MCR_WR(prAdapter, \ ++ ((u4MboxId == 0) ? MCR_H2DSM0R : MCR_H2DSM1R), \ ++ u4Data); \ ++} ++ ++#define HAL_GET_MAILBOX(prAdapter, u4MboxId, pu4Data) \ ++{ \ ++ ASSERT(u4MboxId < 2); \ ++ HAL_MCR_RD(prAdapter, \ ++ ((u4MboxId == 0) ? MCR_D2HRM0R : MCR_D2HRM1R), \ ++ pu4Data); \ ++} ++ ++#define HAL_SET_MAILBOX_READ_CLEAR(prAdapter, fgEnableReadClear) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value);\ ++ HAL_MCR_WR(prAdapter, MCR_WHCR, \ ++ (fgEnableReadClear) ? \ ++ (u4Value | WHCR_W_MAILBOX_RD_CLR_EN) : \ ++ (u4Value & ~WHCR_W_MAILBOX_RD_CLR_EN)); \ ++ prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear = fgEnableReadClear;\ ++} ++ ++#define HAL_GET_MAILBOX_READ_CLEAR(prAdapter) (prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _HAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h +new file mode 100644 +index 000000000000..b9aa154b097e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h +@@ -0,0 +1,220 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_rx.h#1 ++*/ ++ ++/*! \file "hif_rx.h" ++ \brief Provide HIF RX Header Information between F/W and Driver ++ ++ N/A ++*/ ++ ++/* ++** Log: hif_rx.h ++ * ++ * 09 01 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * follow-ups for HIF_RX_HEADER_T update: ++ * 1) add TCL ++ * 2) add RCPI ++ * 3) add ChannelNumber ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:44:00 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-09 13:59:20 GMT MTK02468 ++** Added HIF_RX_HDR parsing macros ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 19:54:54 GMT mtk02752 ++** adopt HIF_RX_HEADER_T in new data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-29 19:51:19 GMT mtk01084 ++** modify FW/ driver interface ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:33:58 GMT mtk01461 ++** Add define of HW_APPENED_LEN ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:51:02 GMT mtk01461 ++** Rename ENUM_HIF_RX_PKT_TYPE_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 12:05:03 GMT mtk01426 ++** Remove __KAL_ATTRIB_PACKED__ and add hifDataTypeCheck() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:18:52 GMT mtk01426 ++** Add comment to HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:23 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _HIF_RX_H ++#define _HIF_RX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*! HIF_RX_HEADER_T */ ++/* DW 0, Byte 1 */ ++#define HIF_RX_HDR_PACKET_TYPE_MASK BITS(0, 1) ++#define HIF_RX_HDR_SEC_MODE_MASK BITS(2, 5) ++#define HIF_RX_HDR_SEC_MODE_OFFSET 2 ++ ++/* DW 1, Byte 0 */ ++#define HIF_RX_HDR_HEADER_LEN BITS(2, 7) ++#define HIF_RX_HDR_HEADER_LEN_OFFSET 2 ++#define HIF_RX_HDR_HEADER_OFFSET_MASK BITS(0, 1) ++ ++/* DW 1, Byte 1 */ ++#define HIF_RX_HDR_80211_HEADER_FORMAT BIT(0) ++#define HIF_RX_HDR_DO_REORDER BIT(1) ++#define HIF_RX_HDR_PAL BIT(2) ++#define HIF_RX_HDR_TCL BIT(3) ++#define HIF_RX_HDR_NETWORK_IDX_MASK BITS(4, 7) ++#define HIF_RX_HDR_NETWORK_IDX_OFFSET 4 ++ ++/* DW 1, Byte 2, 3 */ ++#define HIF_RX_HDR_SEQ_NO_MASK BITS(0, 11) ++#define HIF_RX_HDR_TID_MASK BITS(12, 14) ++#define HIF_RX_HDR_TID_OFFSET 12 ++#define HIF_RX_HDR_BAR_FRAME BIT(15) ++ ++#define HIF_RX_HDR_FLAG_AMP_WDS BIT(0) ++#define HIF_RX_HDR_FLAG_802_11_FORMAT BIT(1) ++#define HIF_RX_HDR_FLAG_BAR_FRAME BIT(2) ++#define HIF_RX_HDR_FLAG_DO_REORDERING BIT(3) ++#define HIF_RX_HDR_FLAG_CTRL_WARPPER_FRAME BIT(4) ++ ++#define HIF_RX_HW_APPENDED_LEN 4 ++ ++/* For DW 2, Byte 3 - ucHwChannelNum */ ++#define HW_CHNL_NUM_MAX_2G4 14 ++#define HW_CHNL_NUM_MAX_4G_5G (255 - HW_CHNL_NUM_MAX_2G4) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _HIF_RX_HEADER_T { ++ UINT_16 u2PacketLen; ++ UINT_16 u2PacketType; ++ UINT_8 ucHerderLenOffset; ++ UINT_8 uc80211_Reorder_PAL_TCL; ++ UINT_16 u2SeqNoTid; ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucRcpi; ++ UINT_8 ucHwChannelNum; ++ UINT_8 ucReserved; ++} HIF_RX_HEADER_T, *P_HIF_RX_HEADER_T; ++ ++typedef enum _ENUM_HIF_RX_PKT_TYPE_T { ++ HIF_RX_PKT_TYPE_DATA = 0, ++ HIF_RX_PKT_TYPE_EVENT, ++ HIF_RX_PKT_TYPE_TX_LOOPBACK, ++ HIF_RX_PKT_TYPE_MANAGEMENT, ++ HIF_RX_PKT_TYPE_NUM ++} ENUM_HIF_RX_PKT_TYPE_T, *P_ENUM_HIF_RX_PKT_TYPE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define HIF_RX_HDR_SIZE sizeof(HIF_RX_HEADER_T) ++ ++#define HIF_RX_HDR_GET_80211_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_80211_HEADER_FORMAT) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_REORDER_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_DO_REORDER) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_PAL_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_PAL) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_TCL_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_TCL) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_NETWORK_IDX(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_NETWORK_IDX_MASK)\ ++ >> HIF_RX_HDR_NETWORK_IDX_OFFSET) ++ ++#define HIF_RX_HDR_GET_SEC_MODE(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->u2PacketType) & HIF_RX_HDR_SEC_MODE_MASK) >> HIF_RX_HDR_SEC_MODE_OFFSET) ++ ++#define HIF_RX_HDR_GET_TID(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_TID_MASK)\ ++ >> HIF_RX_HDR_TID_OFFSET) ++#define HIF_RX_HDR_GET_SN(_prHifRxHdr) \ ++ (((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_SEQ_NO_MASK) ++#define HIF_RX_HDR_GET_BAR_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_BAR_FRAME) ? TRUE : FALSE)) ++ ++#define HIF_RX_HDR_GET_CHNL_NUM(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->ucHwChannelNum) > HW_CHNL_NUM_MAX_4G_5G) ? \ ++ (((_prHifRxHdr)->ucHwChannelNum) - HW_CHNL_NUM_MAX_4G_5G) : \ ++ ((_prHifRxHdr)->ucHwChannelNum)) ++ ++/* To do: support more bands other than 2.4G and 5G */ ++#define HIF_RX_HDR_GET_RF_BAND(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->ucHwChannelNum) <= HW_CHNL_NUM_MAX_2G4) ? \ ++ BAND_2G4 : BAND_5G) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static inline VOID hifDataTypeCheck(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID hifDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_RX_HEADER_T) == 12); ++ ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h +new file mode 100644 +index 000000000000..17252f2c7760 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h +@@ -0,0 +1,214 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_tx.h#1 ++*/ ++ ++/* ++** Log: hif_tx.h ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill extra information for revised HIF_TX_HEADER. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate ++ * 2) add packet type for indicating management frames ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 01 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:40 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-24 19:55:11 GMT mtk02752 ++** adopt HIF_TX_HEADER_T in new data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-23 17:54:13 GMT mtk02752 ++** CMD_HDR_SIZE = (sizeof(WIFI_CMD_T)) to follow up CM's CMD/EVENT documentation ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-17 22:41:10 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-17 17:34:07 GMT mtk02752 ++** remove HIF_TX_BUFF_COUNT_TC0 (move to nic_tx.h) ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-17 12:14:12 GMT mtk02752 ++** add initial value for HIF_TX_BUFF_COUNT_TC5 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-13 13:54:18 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-04 14:11:14 GMT mtk01084 ++** modify SW TX data format ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-29 19:51:53 GMT mtk01084 ++** modify FW/ driver interface ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-20 12:22:46 GMT mtk01461 ++** Add SeqNum field to CMD Header ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:40:52 GMT mtk01461 ++** Update the Log Sign ++*/ ++ ++#ifndef _HIF_TX_H ++#define _HIF_TX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Maximum buffer size for individual HIF TCQ Buffer */ ++#define HIF_TX_BUFF_MAX_SIZE 1552 /* Reserved field was not included */ ++ ++/* Maximum buffer count for individual HIF TCQ */ ++#define HIF_TX_BUFF_COUNT_TC0 3 ++#define HIF_TX_BUFF_COUNT_TC1 3 ++#define HIF_TX_BUFF_COUNT_TC2 3 ++#define HIF_TX_BUFF_COUNT_TC3 3 ++#define HIF_TX_BUFF_COUNT_TC4 2 ++ ++#define TX_HDR_SIZE sizeof(HIF_TX_HEADER_T) ++ ++#define CMD_HDR_SIZE sizeof(WIFI_CMD_T) ++ ++#define CMD_PKT_SIZE_FOR_IMAGE 2048 /* !< 2048 Bytes CMD payload buffer */ ++ ++/*! NIC_HIF_TX_HEADER_T */ ++/* DW 0, Byte 0,1 */ ++#define HIF_TX_HDR_TX_BYTE_COUNT_MASK BITS(0, 11) ++#define HIF_TX_HDR_USER_PRIORITY_OFFSET 12 ++ ++/* DW 0, Byte 2 */ ++#define HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK BITS(0, 7) ++ ++/* DW 0, Byte 3 */ ++#define HIF_TX_HDR_IP_CSUM BIT(0) ++#define HIF_TX_HDR_TCP_CSUM BIT(1) ++#define HIF_TX_HDR_RESOURCE_MASK BITS(2, 5) ++#define HIF_TX_HDR_RESOURCE_OFFSET 2 ++#define HIF_TX_HDR_PACKET_TYPE_MASK BITS(6, 7) ++#define HIF_TX_HDR_PACKET_TYPE_OFFSET 6 ++ ++/* DW 1, Byte 0 */ ++#define HIF_TX_HDR_WLAN_HEADER_LEN_MASK BITS(0, 5) ++ ++/* DW 1, Byte 1 */ ++#define HIF_TX_HDR_FORMAT_ID_MASK BITS(0, 2) ++#define HIF_TX_HDR_NETWORK_TYPE_MASK BITS(4, 5) ++#define HIF_TX_HDR_NETWORK_TYPE_OFFSET 4 ++#define HIF_TX_HDR_FLAG_1X_FRAME_MASK BIT(6) ++#define HIF_TX_HDR_FLAG_1X_FRAME_OFFSET 6 ++#define HIF_TX_HDR_FLAG_802_11_FORMAT_MASK BIT(7) ++#define HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET 7 ++ ++/* DW2, Byte 3 */ ++#define HIF_TX_HDR_PS_FORWARDING_TYPE_MASK BITS(0, 1) ++#define HIF_TX_HDR_PS_SESSION_ID_MASK BITS(2, 4) ++#define HIF_TX_HDR_PS_SESSION_ID_OFFSET 2 ++#define HIF_TX_HDR_BURST_END_MASK BIT(5) ++#define HIF_TX_HDR_BURST_END_OFFSET 5 ++ ++/* DW3, Byte 1 */ ++#define HIF_TX_HDR_NEED_ACK BIT(0) ++#define HIF_TX_HDR_BIP BIT(1) ++#define HIF_TX_HDR_BASIC_RATE BIT(2) ++#define HIF_TX_HDR_NEED_TX_DONE_STATUS BIT(3) ++#define HIF_TX_HDR_RTS BIT(4) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _HIF_HW_TX_HEADER_T { ++ UINT_16 u2TxByteCount; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucCSflags; ++ UINT_8 aucBuffer[0]; ++} HIF_HW_TX_HEADER_T, *P_HIF_HW_TX_HEADER_T; ++ ++typedef struct _HIF_TX_HEADER_T { ++ UINT_16 u2TxByteCount_UserPriority; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucResource_PktType_CSflags; ++ UINT_8 ucWlanHeaderLength; ++ UINT_8 ucPktFormtId_Flags; ++ UINT_16 u2LLH; /* for BOW */ ++ UINT_16 u2SeqNo; /* for BOW */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucForwardingType_SessionID_Reserved; ++ UINT_8 ucPacketSeqNo; ++ UINT_8 ucAck_BIP_BasicRate; ++ UINT_8 aucReserved[2]; ++} HIF_TX_HEADER_T, *P_HIF_TX_HEADER_T; ++ ++typedef enum _ENUM_HIF_TX_PKT_TYPE_T { ++ HIF_TX_PKT_TYPE_DATA = 0, ++ HIF_TX_PKT_TYPE_CMD, ++ HIF_TX_PKT_TYPE_HIF_LOOPBACK, ++ HIF_TX_PKT_TYPE_MANAGEMENT, ++ HIF_TX_PKT_TYPE_NUM ++} ENUM_HIF_TX_PKT_TYPE_T, *P_ENUM_HIF_TX_PKT_TYPE_T; ++ ++typedef enum _ENUM_HIF_OOB_CTRL_PKT_TYPE_T { ++ HIF_OOB_CTRL_PKT_TYPE_LOOPBACK = 1, ++ HIF_OOB_CTRL_PKT_TYP_NUM ++} ENUM_HIF_OOB_CTRL_PKT_TYPE_T, *P_ENUM_HIF_OOB_CTRL_PKT_TYPE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define TFCB_FRAME_PAD_TO_DW(u2Length) ALIGN_4(u2Length) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ */ ++static inline VOID hif_txDataTypeCheck(VOID); ++ ++static inline VOID hif_txDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_TX_HEADER_T) == 16); ++ ++} ++ ++#endif /*_HIF_TX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h +new file mode 100644 +index 000000000000..ff38d30c3cf2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h +@@ -0,0 +1,2323 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/mac.h#1 ++*/ ++ ++/*! \file "mac.h" ++ \brief Brief description. ++ ++ Detail description. ++*/ ++ ++/* ++** Log: mac.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h ++ * and let the sw structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 05 06 2011 wh.su ++ * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send ++ * the wrong beacon make driver got incorrect support rate set ++ * Add the length check before access the ie length filed. ++ * ++ * 05 06 2011 wh.su ++ * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send ++ * the wrong beacon make driver got incorrect support rate set ++ * adding the length check before processing next ie.. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discover ability support. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Some action frame define is not belong to P2P. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Add some service discovery MAC define, phase I. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork ++ * suppress warning reported by Klockwork. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * revert to previous revision. (this file is not necessary to be changed) ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * 1. Add P2P MAC define. ++ * 2. Add scan device found event ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add WFA specific OUI. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P IE ID & Vendor OUI TYPE for P2P. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge MAC.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added OFFSET_BAR_SSC_SN ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:00:24 GMT MTK02468 ++** Added offsets and masks for the BA Parameter Set filed ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:26 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _MAC_H ++#define _MAC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 3 --------------- Constants for Ethernet/802.11 MAC --------------- */ ++/* MAC Address */ ++#define MAC_ADDR_LEN 6 ++ ++#define MAC_ADDR_LOCAL_ADMIN BIT(1) ++ ++#define ETH_P_IPV4 0x0800 ++#define ETH_P_IPX 0x8137 /* Novell IPX */ ++#define ETH_P_AARP 0x80F3 /* AppleTalk Address Resolution Protocol (AARP) */ ++#define ETH_P_IPV6 0x86DD ++ ++#define IP_VERSION_4 4 ++#define IP_VERSION_6 6 ++ ++#define IP_PROTOCOL_TCP 6 ++#define IP_PROTOCOL_UDP 17 ++ ++#define IPV4_HDR_IP_IDENTIFICATION_OFFSET 4 ++#define IPV4_HDR_IP_PROTOCOL_OFFSET 9 ++#define IPV4_HDR_IP_CSUM_OFFSET 10 ++#define IPV4_HDR_IP_SRC_ADDR_OFFSET 12 ++#define IPV4_HDR_IP_DST_ADDR_OFFSET 16 ++ ++#define IPV6_HDR_IP_PROTOCOL_OFFSET 6 ++#define IPV6_HDR_IP_SRC_ADDR_OFFSET 8 ++#define IPV6_HDR_IP_DST_ADDR_OFFSET 24 ++#define IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET 32 ++#define IPV6_HDR_IP_DST_ADDR_MAC_LOW_OFFSET 37 ++#define IPV6_PROTOCOL_ICMPV6 0x3A ++#define IPV6_ADDR_LEN 16 ++#define IPV6_HDR_LEN 40 ++ ++#define ARP_OPERATION_OFFSET 6 ++#define ARP_SNEDER_MAC_OFFSET 8 ++#define ARP_SENDER_IP_OFFSET 14 ++#define ARP_TARGET_MAC_OFFSET 18 ++#define ARP_TARGET_IP_OFFSET 24 ++#define ARP_OPERATION_REQUEST 0x0001 ++#define ARP_OPERATION_RESPONSE 0x0002 ++ ++#define ICMPV6_TYPE_OFFSET 0 ++#define ICMPV6_FLAG_OFFSET 4 ++#define ICMPV6_TARGET_ADDR_OFFSET 8 ++#define ICMPV6_TARGET_LL_ADDR_TYPE_OFFSET 24 ++#define ICMPV6_TARGET_LL_ADDR_LEN_OFFSET 25 ++#define ICMPV6_TARGET_LL_ADDR_TA_OFFSET 26 ++ ++#define ICMPV6_FLAG_ROUTER_BIT BIT(7) ++#define ICMPV6_FLAG_SOLICITED_BIT BIT(6) ++#define ICMPV6_FLAG_OVERWRITE_BIT BIT(5) ++#define ICMPV6_TYPE_NEIGHBOR_SOLICITATION 0x87 ++#define ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT 0x88 ++ ++#define TCP_HDR_TCP_CSUM_OFFSET 16 ++#define UDP_HDR_UDP_CSUM_OFFSET 6 ++ ++#define LLC_LEN 8 /* LLC(3) + SNAP(3) + EtherType(2) */ ++ ++#define NULL_MAC_ADDR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ++#define BC_MAC_ADDR {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} ++ ++/* Ethernet Frame Field Size, in byte */ ++#define ETHER_HEADER_LEN 14 ++#define ETHER_TYPE_LEN 2 ++#define ETHER_MIN_PKT_SZ 60 ++#define ETHER_MAX_PKT_SZ 1514 ++ ++/* IEEE 802.11 WLAN Frame Field Size, in byte */ ++#define WLAN_MAC_HEADER_LEN 24 /* Address 4 excluded */ ++#define WLAN_MAC_HEADER_A4_LEN 30 /* Address 4 included */ ++#define WLAN_MAC_HEADER_QOS_LEN 26 /* QoS Control included */ ++#define WLAN_MAC_HEADER_QOS_HTC_LEN 30 /* QoS Control and HTC included */ ++#define WLAN_MAC_HEADER_A4_QOS_LEN 32 /* Address 4 and QoS Control included */ ++#define WLAN_MAC_HEADER_A4_QOS_HTC_LEN 36 /* Address 4, QoS Control and HTC included */ ++#define WLAN_MAC_MGMT_HEADER_LEN 24 /* Address 4 excluded */ ++#define WLAN_MAC_MGMT_HEADER_HTC_LEN 28 /* HTC included */ ++ ++#define QOS_CTRL_LEN 2 ++#define HT_CTRL_LEN 4 ++ ++#define WLAN_MAC_CTS_ACK_LEN (WLAN_MAC_CTS_ACK_FRAME_HEADER_LEN + FCS_LEN) ++ ++/* 6.2.1.1.2 Semantics of the service primitive */ ++#define MSDU_MAX_LENGTH 2304 ++ ++/* 7.1.3.3.3 Broadcast BSSID */ ++#define BC_BSSID BC_MAC_ADDR ++ ++/* 7.1.3.7 FCS field */ ++#define FCS_LEN 4 ++ ++/* 7.3.1.6 Listen Interval field */ ++#define DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD 2 /* In unit of AP's DTIM interval, */ ++#define DEFAULT_LISTEN_INTERVAL 10 ++ ++/* 7.3.2.1 Broadcast(Wildcard) SSID */ ++#define BC_SSID "" ++#define BC_SSID_LEN 0 ++ ++/* 7.3.2.2 Data Rate Value */ ++#define RATE_1M 2 /* 1M in unit of 500kb/s */ ++#define RATE_2M 4 /* 2M */ ++#define RATE_5_5M 11 /* 5.5M */ ++#define RATE_11M 22 /* 11M */ ++#define RATE_22M 44 /* 22M */ ++#define RATE_33M 66 /* 33M */ ++#define RATE_6M 12 /* 6M */ ++#define RATE_9M 18 /* 9M */ ++#define RATE_12M 24 /* 12M */ ++#define RATE_18M 36 /* 18M */ ++#define RATE_24M 48 /* 24M */ ++#define RATE_36M 72 /* 36M */ ++#define RATE_48M 96 /* 48M */ ++#define RATE_54M 108 /* 54M */ ++/* 7.3.2.14 BSS membership selector */ ++#define RATE_HT_PHY 127 /* BSS Selector - Clause 20. HT PHY */ ++#define RATE_MASK BITS(0, 6) /* mask bits for the rate */ ++#define RATE_BASIC_BIT BIT(7) /* mask bit for the rate belonging to the BSSBasicRateSet */ ++ ++/* 8.3.2.2 TKIP MPDU formats */ ++#define TKIP_MIC_LEN 8 ++ ++/* 9.2.10 DIFS */ ++#define DIFS 2 /* 2 x aSlotTime */ ++ ++/* 11.3 STA Authentication and Association */ ++#define STA_STATE_1 0 /* Accept Class 1 frames */ ++#define STA_STATE_2 1 /* Accept Class 1 & 2 frames */ ++#define STA_STATE_3 2 /* Accept Class 1,2 & 3 frames */ ++ ++/* 15.4.8.5 802.11k RCPI-dBm mapping*/ ++#define NDBM_LOW_BOUND_FOR_RCPI 110 ++#define RCPI_LOW_BOUND 0 ++#define RCPI_HIGH_BOUND 220 ++#define RCPI_MEASUREMENT_NOT_AVAILABLE 255 ++ ++/* PHY characteristics */ ++/* 17.4.4/18.3.3/19.8.4 Slot Time (aSlotTime) */ ++#define SLOT_TIME_LONG 20 /* Long Slot Time */ ++#define SLOT_TIME_SHORT 9 /* Short Slot Time */ ++ ++#define SLOT_TIME_HR_DSSS SLOT_TIME_LONG /* 802.11b aSlotTime */ ++#define SLOT_TIME_OFDM SLOT_TIME_SHORT /* 802.11a aSlotTime(20M Spacing) */ ++#define SLOT_TIME_OFDM_10M_SPACING 13 /* 802.11a aSlotTime(10M Spacing) */ ++#define SLOT_TIME_ERP_LONG SLOT_TIME_LONG /* 802.11g aSlotTime(Long) */ ++#define SLOT_TIME_ERP_SHORT SLOT_TIME_SHORT /* 802.11g aSlotTime(Short) */ ++ ++/* 17.4.4/18.3.3/19.8.4 Contention Window (aCWmin & aCWmax) */ ++#define CWMIN_OFDM 15 /* 802.11a aCWmin */ ++#define CWMAX_OFDM 1023 /* 802.11a aCWmax */ ++ ++#define CWMIN_HR_DSSS 31 /* 802.11b aCWmin */ ++#define CWMAX_HR_DSSS 1023 /* 802.11b aCWmax */ ++ ++#define CWMIN_ERP_0 31 /* 802.11g aCWmin(0) - for only have 1/2/5/11Mbps Rates */ ++#define CWMIN_ERP_1 15 /* 802.11g aCWmin(1) */ ++#define CWMAX_ERP 1023 /* 802.11g aCWmax */ ++ ++/* Short Inter-Frame Space (aSIFSTime) */ ++/* 15.3.3 802.11b aSIFSTime */ ++#define SIFS_TIME_HR_DSSS 10 ++/* 17.4.4 802.11a aSIFSTime */ ++#define SIFS_TIME_OFDM 16 ++/* 19.8.4 802.11g aSIFSTime */ ++#define SIFS_TIME_ERP 10 ++ ++/* 15.4.6.2 Number of operating channels */ ++#define CH_1 0x1 ++#define CH_2 0x2 ++#define CH_3 0x3 ++#define CH_4 0x4 ++#define CH_5 0x5 ++#define CH_6 0x6 ++#define CH_7 0x7 ++#define CH_8 0x8 ++#define CH_9 0x9 ++#define CH_10 0xa ++#define CH_11 0xb ++#define CH_12 0xc ++#define CH_13 0xd ++#define CH_14 0xe ++ ++#define MAXIMUM_OPERATION_CHANNEL_LIST 46 ++ ++/* 3 --------------- IEEE 802.11 PICS --------------- */ ++/* Annex D - dot11OperationEntry 2 */ ++#define DOT11_RTS_THRESHOLD_MIN 0 ++#define DOT11_RTS_THRESHOLD_MAX 2347 /* from Windows DDK */ ++/* #define DOT11_RTS_THRESHOLD_MAX 3000 // from Annex D */ ++ ++#define DOT11_RTS_THRESHOLD_DEFAULT \ ++ DOT11_RTS_THRESHOLD_MAX ++ ++/* Annex D - dot11OperationEntry 5 */ ++#define DOT11_FRAGMENTATION_THRESHOLD_MIN 256 ++#define DOT11_FRAGMENTATION_THRESHOLD_MAX 2346 /* from Windows DDK */ ++/* #define DOT11_FRAGMENTATION_THRESHOLD_MAX 3000 // from Annex D */ ++ ++#define DOT11_FRAGMENTATION_THRESHOLD_DEFAULT \ ++ DOT11_FRAGMENTATION_THRESHOLD_MAX ++ ++/* Annex D - dot11OperationEntry 6 */ ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MIN 1 ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MAX 0xFFFFffff ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_DEFAULT 4095 /* 802.11 define 512 */ ++ /* MT5921 only aceept N <= 4095 */ ++ ++/* Annex D - dot11OperationEntry 7 */ ++#define DOT11_RECEIVE_LIFETIME_TU_MIN 1 ++#define DOT11_RECEIVE_LIFETIME_TU_MAX 0xFFFFffff ++#define DOT11_RECEIVE_LIFETIME_TU_DEFAULT 4096 /* 802.11 define 512 */ ++ ++/* Annex D - dot11StationConfigEntry 12 */ ++#define DOT11_BEACON_PERIOD_MIN 1 /* TU. */ ++#define DOT11_BEACON_PERIOD_MAX 0xffff /* TU. */ ++#define DOT11_BEACON_PERIOD_DEFAULT 100 /* TU. */ ++ ++/* Annex D - dot11StationConfigEntry 13 */ ++#define DOT11_DTIM_PERIOD_MIN 1 /* TU. */ ++#define DOT11_DTIM_PERIOD_MAX 255 /* TU. */ ++#define DOT11_DTIM_PERIOD_DEFAULT 1 /* TU. */ ++ ++/* Annex D - dot11RegDomainsSupportValue */ ++#define REGULATION_DOMAIN_FCC 0x10 /* FCC (US) */ ++#define REGULATION_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ ++#define REGULATION_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ ++#define REGULATION_DOMAIN_SPAIN 0x31 /* Spain */ ++#define REGULATION_DOMAIN_FRANCE 0x32 /* France */ ++#define REGULATION_DOMAIN_JAPAN 0x40 /* MKK (Japan) */ ++#define REGULATION_DOMAIN_CHINA 0x50 /* China */ ++#define REGULATION_DOMAIN_OTHER 0x00 /* Other */ ++ ++/* 3 --------------- IEEE 802.11 MAC header fields --------------- */ ++/* 7.1.3.1 Masks for the subfields in the Frame Control field */ ++#define MASK_FC_PROTOCOL_VER BITS(0, 1) ++#define MASK_FC_TYPE BITS(2, 3) ++#define MASK_FC_SUBTYPE BITS(4, 7) ++#define MASK_FC_SUBTYPE_QOS_DATA BIT(7) ++#define MASK_FC_TO_DS BIT(8) ++#define MASK_FC_FROM_DS BIT(9) ++#define MASK_FC_MORE_FRAG BIT(10) ++#define MASK_FC_RETRY BIT(11) ++#define MASK_FC_PWR_MGT BIT(12) ++#define MASK_FC_MORE_DATA BIT(13) ++#define MASK_FC_PROTECTED_FRAME BIT(14) ++#define MASK_FC_ORDER BIT(15) ++ ++#define MASK_FRAME_TYPE (MASK_FC_TYPE | MASK_FC_SUBTYPE) ++#define MASK_TO_DS_FROM_DS (MASK_FC_TO_DS | MASK_FC_FROM_DS) ++ ++#define MAX_NUM_OF_FC_SUBTYPES 16 ++#define OFFSET_OF_FC_SUBTYPE 4 ++ ++/* 7.1.3.1.2 MAC frame types and subtypes */ ++#define MAC_FRAME_TYPE_MGT 0 ++#define MAC_FRAME_TYPE_CTRL BIT(2) ++#define MAC_FRAME_TYPE_DATA BIT(3) ++#define MAC_FRAME_TYPE_QOS_DATA (MAC_FRAME_TYPE_DATA | MASK_FC_SUBTYPE_QOS_DATA) ++ ++#define MAC_FRAME_ASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0000) ++#define MAC_FRAME_ASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0010) ++#define MAC_FRAME_REASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0020) ++#define MAC_FRAME_REASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0030) ++#define MAC_FRAME_PROBE_REQ (MAC_FRAME_TYPE_MGT | 0x0040) ++#define MAC_FRAME_PROBE_RSP (MAC_FRAME_TYPE_MGT | 0x0050) ++#define MAC_FRAME_BEACON (MAC_FRAME_TYPE_MGT | 0x0080) ++#define MAC_FRAME_ATIM (MAC_FRAME_TYPE_MGT | 0x0090) ++#define MAC_FRAME_DISASSOC (MAC_FRAME_TYPE_MGT | 0x00A0) ++#define MAC_FRAME_AUTH (MAC_FRAME_TYPE_MGT | 0x00B0) ++#define MAC_FRAME_DEAUTH (MAC_FRAME_TYPE_MGT | 0x00C0) ++#define MAC_FRAME_ACTION (MAC_FRAME_TYPE_MGT | 0x00D0) ++#define MAC_FRAME_ACTION_NO_ACK (MAC_FRAME_TYPE_MGT | 0x00E0) ++ ++#define MAC_FRAME_CONTRL_WRAPPER (MAC_FRAME_TYPE_CTRL | 0x0070) ++#define MAC_FRAME_BLOCK_ACK_REQ (MAC_FRAME_TYPE_CTRL | 0x0080) ++#define MAC_FRAME_BLOCK_ACK (MAC_FRAME_TYPE_CTRL | 0x0090) ++#define MAC_FRAME_PS_POLL (MAC_FRAME_TYPE_CTRL | 0x00A0) ++#define MAC_FRAME_RTS (MAC_FRAME_TYPE_CTRL | 0x00B0) ++#define MAC_FRAME_CTS (MAC_FRAME_TYPE_CTRL | 0x00C0) ++#define MAC_FRAME_ACK (MAC_FRAME_TYPE_CTRL | 0x00D0) ++#define MAC_FRAME_CF_END (MAC_FRAME_TYPE_CTRL | 0x00E0) ++#define MAC_FRAME_CF_END_CF_ACK (MAC_FRAME_TYPE_CTRL | 0x00F0) ++ ++#define MAC_FRAME_DATA (MAC_FRAME_TYPE_DATA | 0x0000) ++#define MAC_FRAME_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0010) ++#define MAC_FRAME_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0020) ++#define MAC_FRAME_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0030) ++#define MAC_FRAME_NULL (MAC_FRAME_TYPE_DATA | 0x0040) ++#define MAC_FRAME_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0050) ++#define MAC_FRAME_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0060) ++#define MAC_FRAME_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0070) ++#define MAC_FRAME_QOS_DATA (MAC_FRAME_TYPE_DATA | 0x0080) ++#define MAC_FRAME_QOS_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0090) ++#define MAC_FRAME_QOS_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00A0) ++#define MAC_FRAME_QOS_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00B0) ++#define MAC_FRAME_QOS_NULL (MAC_FRAME_TYPE_DATA | 0x00C0) ++#define MAC_FRAME_QOS_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00E0) ++#define MAC_FRAME_QOS_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00F0) ++ ++/* 7.1.3.2 Mask for the AID value in the Duration/ID field */ ++#define MASK_DI_DURATION BITS(0, 14) ++#define MASK_DI_AID BITS(0, 13) ++#define MASK_DI_AID_MSB BITS(14, 15) ++#define MASK_DI_CFP_FIXED_VALUE BIT(15) ++ ++/* 7.1.3.4 Masks for the subfields in the Sequence Control field */ ++#define MASK_SC_SEQ_NUM BITS(4, 15) ++#define MASK_SC_SEQ_NUM_OFFSET 4 ++#define MASK_SC_FRAG_NUM BITS(0, 3) ++#define INVALID_SEQ_CTRL_NUM 0x000F /* According to 6.2.1.1.2 ++ * FRAG_NUM won't equal to 15 ++ */ ++ ++/* 7.1.3.5 QoS Control field */ ++#define TID_NUM 16 ++#define TID_MASK BITS(0, 3) ++#define EOSP BIT(4) ++#define ACK_POLICY BITS(5, 6) ++#define A_MSDU_PRESENT BIT(7) ++ ++#define MASK_QC_TID BITS(0, 3) ++#define MASK_QC_EOSP BIT(4) ++#define MASK_QC_EOSP_OFFSET 4 ++#define MASK_QC_ACK_POLICY BITS(5, 6) ++#define MASK_QC_ACK_POLICY_OFFSET 5 ++#define MASK_QC_A_MSDU_PRESENT BIT(7) ++ ++/* 7.1.3.5a HT Control field */ ++#define HT_CTRL_LINK_ADAPTATION_CTRL BITS(0, 15) ++#define HT_CTRL_CALIBRATION_POSITION BITS(16, 17) ++#define HT_CTRL_CALIBRATION_SEQUENCE BITS(18, 19) ++#define HT_CTRL_CSI_STEERING BITS(22, 23) ++#define HT_CTRL_NDP_ANNOUNCEMENT BIT(24) ++#define HT_CTRL_AC_CONSTRAINT BIT(30) ++#define HT_CTRL_RDG_MORE_PPDU BIT(31) ++ ++#define LINK_ADAPTATION_CTRL_TRQ BIT(1) ++#define LINK_ADAPTATION_CTRL_MAI_MRQ BIT(2) ++#define LINK_ADAPTATION_CTRL_MAI_MSI BITS(3, 5) ++#define LINK_ADAPTATION_CTRL_MFSI BITS(6, 8) ++#define LINK_ADAPTATION_CTRL_MFB_ASELC_CMD BITS(9, 11) ++#define LINK_ADAPTATION_CTRL_MFB_ASELC_DATA BITS(12, 15) ++ ++/* 7.1.3.5.3 Ack Policy subfield*/ ++#define ACK_POLICY_NORMAL_ACK_IMPLICIT_BA_REQ 0 ++#define ACK_POLICY_NO_ACK 1 ++#define ACK_POLICY_NO_EXPLICIT_ACK_PSMP_ACK 2 ++#define ACK_POLICY_BA 3 ++ ++/* 7.1.3.7 FCS field */ ++#define FCS_LEN 4 ++ ++/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ ++#define PSPOLL_FRAME_LEN 16 /* w/o FCS */ ++ ++/* 7.2.7.1 BAR */ ++#define OFFSET_BAR_SSC_SN 4 ++ ++/* 8.3.2.2 TKIP MPDU formats */ ++#define TKIP_MIC_LEN 8 ++ ++/* 2009.11.30 mtk02468: Moved these definitions to the right place */ ++#if 0 ++/* Block Ack Parameter Set field */ ++#define BA_PARM_BA_POLICY BIT(1) ++#define BA_PARM_TID BITS(2, 5) ++#define BA_PARM_BUFFER_SIZE BITS(6, 15) ++#endif ++ ++#define BA_POLICY_IMMEDIATE BIT(1) ++ ++/* Block Ack Starting Sequence Control field */ ++#define BA_START_SEQ_CTL_FRAG_NUM BITS(0, 3) ++#define BA_START_SEQ_CTL_SSN BITS(4, 15) ++ ++/* BAR Control field */ ++#define BAR_CONTROL_NO_ACK_POLICY BIT(0) ++#define BAR_CONTROL_MULTI_TID BIT(1) ++#define BAR_CONTROL_COMPRESSED_BA BIT(2) ++#define BAR_CONTROL_TID_INFO BITS(12, 15) ++#define BAR_CONTROL_TID_INFO_OFFSET 12 ++ ++/* TID Value */ ++#define BAR_INFO_TID_VALUE BITS(12, 15) ++ ++#define BAR_COMPRESSED_VARIANT_FRAME_LEN (16 + 4) ++ ++/* 3 --------------- IEEE 802.11 frame body fields --------------- */ ++/* 3 Management frame body components (I): Fixed Fields. */ ++/* 7.3.1.1 Authentication Algorithm Number field */ ++#define AUTH_ALGORITHM_NUM_FIELD_LEN 2 ++ ++#define AUTH_ALGORITHM_NUM_OPEN_SYSTEM 0 /* Open System */ ++#define AUTH_ALGORITHM_NUM_SHARED_KEY 1 /* Shared Key */ ++#define AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION 2 /* Fast BSS Transition */ ++ ++/* 7.3.1.2 Authentication Transaction Sequence Number field */ ++#define AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN 2 ++#define AUTH_TRANSACTION_SEQ_1 1 ++#define AUTH_TRANSACTION_SEQ_2 2 ++#define AUTH_TRANSACTION_SEQ_3 3 ++#define AUTH_TRANSACTION_SEQ_4 4 ++ ++/* 7.3.1.3 Beacon Interval field */ ++#define BEACON_INTERVAL_FIELD_LEN 2 ++ ++/* 7.3.1.4 Capability Information field */ ++#define CAP_INFO_FIELD_LEN 2 ++#define CAP_INFO_ESS BIT(0) ++#define CAP_INFO_IBSS BIT(1) ++#define CAP_INFO_BSS_TYPE (CAP_INFO_ESS | CAP_INFO_IBSS) ++#define CAP_INFO_CF_POLLABLE BIT(2) ++#define CAP_INFO_CF_POLL_REQ BIT(3) ++#define CAP_INFO_CF (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) ++#define CAP_INFO_PRIVACY BIT(4) ++#define CAP_INFO_SHORT_PREAMBLE BIT(5) ++#define CAP_INFO_PBCC BIT(6) ++#define CAP_INFO_CH_AGILITY BIT(7) ++#define CAP_INFO_SPEC_MGT BIT(8) ++#define CAP_INFO_QOS BIT(9) ++#define CAP_INFO_SHORT_SLOT_TIME BIT(10) ++#define CAP_INFO_APSD BIT(11) ++#define CAP_INFO_RESERVED BIT(12) ++#define CAP_INFO_DSSS_OFDM BIT(13) ++#define CAP_INFO_DELAYED_BLOCK_ACK BIT(14) ++#define CAP_INFO_IMM_BLOCK_ACK BIT(15) ++/* STA usage of CF-Pollable and CF-Poll Request subfields */ ++/* STA: not CF-Pollable */ ++#define CAP_CF_STA_NOT_POLLABLE 0x0000 ++/* STA: CF-Pollable, not requesting on the CF-Polling list */ ++#define CAP_CF_STA_NOT_ON_LIST CAP_INFO_CF_POLL_REQ ++/* STA: CF-Pollable, requesting on the CF-Polling list */ ++#define CAP_CF_STA_ON_LIST CAP_INFO_CF_POLLABLE ++/* STA: CF-Pollable, requesting never to be polled */ ++#define CAP_CF_STA_NEVER_POLLED (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) ++ ++/* AP usage of CF-Pollable and CF-Poll Request subfields */ ++/* AP: No point coordinator (PC) */ ++#define CAP_CF_AP_NO_PC 0x0000 ++/* AP: PC at AP for delivery only (no polling) */ ++#define CAP_CF_AP_DELIVERY_ONLY CAP_INFO_CF_POLL_REQ ++/* AP: PC at AP for delivery and polling */ ++#define CAP_CF_AP_DELIVERY_POLLING CAP_INFO_CF_POLLABLE ++ ++/* 7.3.1.5 Current AP Address field */ ++#define CURR_AP_ADDR_FIELD_LEN MAC_ADDR_LEN ++ ++/* 7.3.1.6 Listen Interval field */ ++#define LISTEN_INTERVAL_FIELD_LEN 2 ++ ++/* 7.3.1.7 Reason Code field */ ++#define REASON_CODE_FIELD_LEN 2 ++ ++#define REASON_CODE_RESERVED 0 /* Reseved */ ++#define REASON_CODE_UNSPECIFIED 1 /* Unspecified reason */ ++#define REASON_CODE_PREV_AUTH_INVALID 2 /* Previous auth no longer valid */ ++#define REASON_CODE_DEAUTH_LEAVING_BSS 3 /* Deauth because sending STA is leaving BSS */ ++#define REASON_CODE_DISASSOC_INACTIVITY 4 /* Disassoc due to inactivity */ ++#define REASON_CODE_DISASSOC_AP_OVERLOAD 5 /* Disassoc because AP is unable to handle all assoc STAs */ ++#define REASON_CODE_CLASS_2_ERR 6 /* Class 2 frame rx from nonauth STA */ ++#define REASON_CODE_CLASS_3_ERR 7 /* Class 3 frame rx from nonassoc STA */ ++#define REASON_CODE_DISASSOC_LEAVING_BSS 8 /* Disassoc because sending STA is leaving BSS */ ++#define REASON_CODE_ASSOC_BEFORE_AUTH 9 /* STA requesting (re)assoc is not auth with responding STA */ ++#define REASON_CODE_DISASSOC_PWR_CAP_UNACCEPTABLE 10 /* Disassoc because the info in Power Capability is ++ unacceptable */ ++#define REASON_CODE_DISASSOC_SUP_CHS_UNACCEPTABLE 11 /* Disassoc because the info in Supported Channels is ++ unacceptable */ ++#define REASON_CODE_INVALID_INFO_ELEM 13 /* Invalid information element */ ++#define REASON_CODE_MIC_FAILURE 14 /* MIC failure */ ++#define REASON_CODE_4_WAY_HANDSHAKE_TIMEOUT 15 /* 4-way handshake timeout */ ++#define REASON_CODE_GROUP_KEY_UPDATE_TIMEOUT 16 /* Group key update timeout */ ++#define REASON_CODE_DIFFERENT_INFO_ELEM 17 /* Info element in 4-way handshake different from ++ (Re-)associate request/Probe response/Beacon */ ++#define REASON_CODE_MULTICAST_CIPHER_NOT_VALID 18 /* Multicast Cipher is not valid */ ++#define REASON_CODE_UNICAST_CIPHER_NOT_VALID 19 /* Unicast Cipher is not valid */ ++#define REASON_CODE_AKMP_NOT_VALID 20 /* AKMP is not valid */ ++#define REASON_CODE_UNSUPPORTED_RSNE_VERSION 21 /* Unsupported RSNE version */ ++#define REASON_CODE_INVALID_RSNE_CAPABILITIES 22 /* Invalid RSNE Capabilities */ ++#define REASON_CODE_IEEE_802_1X_AUTH_FAILED 23 /* IEEE 802.1X Authentication failed */ ++#define REASON_CODE_CIPHER_REJECT_SEC_POLICY 24 /* Cipher suite rejected because of the security policy */ ++#define REASON_CODE_DISASSOC_UNSPECIFIED_QOS 32 /* Disassoc for unspecified, QoS-related reason */ ++#define REASON_CODE_DISASSOC_LACK_OF_BANDWIDTH 33 /* Disassoc because QAP lacks sufficient bandwidth ++ for this QSTA */ ++#define REASON_CODE_DISASSOC_ACK_LOST_POOR_CHANNEL 34 /* Disassoc because of too many ACKs lost for AP transmissions ++ and/or poor channel conditions */ ++#define REASON_CODE_DISASSOC_TX_OUTSIDE_TXOP_LIMIT 35 /* Disassoc because QSTA is transmitting outside the limits of ++ its TXOPs */ ++#define REASON_CODE_PEER_WHILE_LEAVING 36 /* QSTA is leaving the QBSS or resetting */ ++#define REASON_CODE_PEER_REFUSE_DLP 37 /* Peer does not want to use this mechanism */ ++#define REASON_CODE_PEER_SETUP_REQUIRED 38 /* Frames received but a setup is reqired */ ++#define REASON_CODE_PEER_TIME_OUT 39 /* Time out */ ++#define REASON_CODE_PEER_CIPHER_UNSUPPORTED 45 /* Peer does not support the requested cipher suite */ ++#define REASON_CODE_BEACON_TIMEOUT 100 /* for beacon timeout, defined by mediatek */ ++#define REASON_CODE_BSS_SECURITY_CHANGE 101 /* for BSS security change, defined by mediatek */ ++/* 7.3.1.8 AID field */ ++#define AID_FIELD_LEN 2 ++#define AID_MASK BITS(0, 13) ++#define AID_MSB BITS(14, 15) ++#define AID_MIN_VALUE 1 ++#define AID_MAX_VALUE 2007 ++ ++/* 7.3.1.9 Status Code field */ ++#define STATUS_CODE_FIELD_LEN 2 ++ ++#define STATUS_CODE_RESERVED 0 /* Reserved - Used by TX Auth */ ++#define STATUS_CODE_SUCCESSFUL 0 /* Successful */ ++#define STATUS_CODE_UNSPECIFIED_FAILURE 1 /* Unspecified failure */ ++#define STATUS_CODE_CAP_NOT_SUPPORTED 10 /* Cannot support all requested cap in the Cap Info field */ ++#define STATUS_CODE_REASSOC_DENIED_WITHOUT_ASSOC 11 /* Reassoc denied due to inability to confirm that ++ assoc exists */ ++#define STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD 12 /* Assoc denied due to reason outside the scope of this std. */ ++#define STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED 13 /* Responding STA does not support the specified ++ auth algorithm */ ++#define STATUS_CODE_AUTH_OUT_OF_SEQ 14 /* Rx an auth frame with auth transaction seq num ++ out of expected seq */ ++#define STATUS_CODE_AUTH_REJECTED_CHAL_FAIL 15 /* Auth rejected because of challenge failure */ ++#define STATUS_CODE_AUTH_REJECTED_TIMEOUT 16 /* Auth rejected due to timeout waiting for next frame ++ in sequence */ ++#define STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD 17 /* Assoc denied because AP is unable to handle additional ++ assoc STAs */ ++#define STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED 18 /* Assoc denied due to requesting STA not supporting ++ all of basic rates */ ++#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_PREAMBLE 19 /* Assoc denied due to requesting STA not supporting short ++ preamble */ ++#define STATUS_CODE_ASSOC_DENIED_NO_PBCC 20 /* Assoc denied due to requesting STA not supporting PBCC */ ++#define STATUS_CODE_ASSOC_DENIED_NO_CH_AGILITY 21 /* Assoc denied due to requesting STA not supporting channel ++ agility */ ++#define STATUS_CODE_ASSOC_REJECTED_NO_SPEC_MGT 22 /* Assoc rejected because Spectrum Mgt capability is required */ ++#define STATUS_CODE_ASSOC_REJECTED_PWR_CAP 23 /* Assoc rejected because the info in Power Capability ++ is unacceptable */ ++#define STATUS_CODE_ASSOC_REJECTED_SUP_CHS 24 /* Assoc rejected because the info in Supported Channels ++ is unacceptable */ ++#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 /* Assoc denied due to requesting STA not supporting ++ short slot time */ ++#define STATUS_CODE_ASSOC_DENIED_NO_DSSS_OFDM 26 /* Assoc denied due to requesting STA not supporting ++ DSSS-OFDM */ ++#if CFG_SUPPORT_802_11W ++#define STATUS_CODE_ASSOC_REJECTED_TEMPORARILY 30 /* IEEE 802.11w, Assoc denied due to the SA query */ ++#define STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 /* IEEE 802.11w, Assoc denied due to the MFP select ++ policy */ ++#endif ++#define STATUS_CODE_UNSPECIFIED_QOS_FAILURE 32 /* Unspecified, QoS-related failure */ ++#define STATUS_CODE_ASSOC_DENIED_BANDWIDTH 33 /* Assoc denied due to insufficient bandwidth to handle another ++ QSTA */ ++#define STATUS_CODE_ASSOC_DENIED_POOR_CHANNEL 34 /* Assoc denied due to excessive frame loss rates and/or poor ++ channel conditions */ ++#define STATUS_CODE_ASSOC_DENIED_NO_QOS_FACILITY 35 /* Assoc denied due to requesting STA not supporting QoS ++ facility */ ++#define STATUS_CODE_REQ_DECLINED 37 /* Request has been declined */ ++#define STATUS_CODE_REQ_INVALID_PARAMETER_VALUE 38 /* Request has not been successful as one or more parameters ++ have invalid values */ ++#define STATUS_CODE_REQ_NOT_HONORED_TSPEC 39 /* TS not created because request cannot be honored. ++ Suggested TSPEC provided. */ ++#define STATUS_CODE_INVALID_INFO_ELEMENT 40 /* Invalid information element */ ++#define STATUS_CODE_INVALID_GROUP_CIPHER 41 /* Invalid group cipher */ ++#define STATUS_CODE_INVALID_PAIRWISE_CIPHER 42 /* Invalid pairwise cipher */ ++#define STATUS_CODE_INVALID_AKMP 43 /* Invalid AKMP */ ++#define STATUS_CODE_UNSUPPORTED_RSN_IE_VERSION 44 /* Unsupported RSN information element version */ ++#define STATUS_CODE_INVALID_RSN_IE_CAP 45 /* Invalid RSN information element capabilities */ ++#define STATUS_CODE_CIPHER_SUITE_REJECTED 46 /* Cipher suite rejected because of security policy */ ++#define STATUS_CODE_REQ_NOT_HONORED_TS_DELAY 47 /* TS not created because request cannot be honored. ++ Attempt to create a TS later. */ ++#define STATUS_CODE_DIRECT_LINK_NOT_ALLOWED 48 /* Direct Link is not allowed in the BSS by policy */ ++#define STATUS_CODE_DESTINATION_STA_NOT_PRESENT 49 /* Destination STA is not present within this QBSS */ ++#define STATUS_CODE_DESTINATION_STA_NOT_QSTA 50 /* Destination STA is not a QSTA */ ++#define STATUS_CODE_ASSOC_DENIED_LARGE_LIS_INTERVAL 51 /* Association denied because the ListenInterval is too large */ ++ ++/* proprietary definition of reserved field of Status Code */ ++#define STATUS_CODE_JOIN_FAILURE 0xFFF0 /* Join failure */ ++#define STATUS_CODE_JOIN_TIMEOUT 0xFFF1 /* Join timeout */ ++#define STATUS_CODE_AUTH_TIMEOUT 0xFFF2 /* Authentication timeout */ ++#define STATUS_CODE_ASSOC_TIMEOUT 0xFFF3 /* (Re)Association timeout */ ++#define STATUS_CODE_CCX_CCKM_REASSOC_FAILURE 0xFFF4 /* CCX CCKM reassociation failure */ ++ ++/* 7.3.1.10 Timestamp field */ ++#define TIMESTAMP_FIELD_LEN 8 ++ ++/* 7.3.1.11 Category of Action field */ ++#define CATEGORY_SPEC_MGT 0 ++#define CATEGORY_QOS_ACTION 1 /* QoS action */ ++#define CATEGORY_DLS_ACTION 2 /* Direct Link Protocol (DLP) action */ ++#define CATEGORY_BLOCK_ACK_ACTION 3 /* Block ack action */ ++#define CATEGORY_PUBLIC_ACTION 4 /* Public action */ ++#define CATEGORY_RM_ACTION 5 /* Radio measurement action */ ++#define CATEGORY_HT_ACTION 7 ++#if CFG_SUPPORT_802_11W ++#define CATEGORY_SA_QUERT_ACTION 8 ++#endif ++#define CATEGORY_WNM_ACTION 10 /* 802.11v Wireless Network Management */ ++#define CATEGORY_UNPROTECTED_WNM_ACTION 11 /* 802.11v Wireless Network Management */ ++#define CATEGORY_WME_MGT_NOTIFICATION 17 /* WME management notification */ ++#define CATEGORY_VENDOR_SPECIFIC_ACTION 127 ++ ++/* 7.3.1.14 Block Ack Parameter Set field */ ++#define BA_PARAM_SET_ACK_POLICY_MASK BIT(1) ++#define BA_PARAM_SET_ACK_POLICY_MASK_OFFSET 1 ++#define BA_PARAM_SET_TID_MASK BITS(2, 5) ++#define BA_PARAM_SET_TID_MASK_OFFSET 2 ++#define BA_PARAM_SET_BUFFER_SIZE_MASK BITS(6, 15) ++#define BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET 6 ++ ++#define BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA 1 ++#define BA_PARAM_SET_ACK_POLICY_DELAYED_BA 0 ++ ++/* 3 Management frame body components (II): Information Elements. */ ++/* 7.3.2 Element IDs of information elements */ ++#define ELEM_HDR_LEN 2 ++ ++#define ELEM_ID_SSID 0 /* SSID */ ++#define ELEM_ID_SUP_RATES 1 /* Supported rates */ ++#define ELEM_ID_FH_PARAM_SET 2 /* FH parameter set */ ++#define ELEM_ID_DS_PARAM_SET 3 /* DS parameter set */ ++#define ELEM_ID_CF_PARAM_SET 4 /* CF parameter set */ ++#define ELEM_ID_TIM 5 /* TIM */ ++#define ELEM_ID_IBSS_PARAM_SET 6 /* IBSS parameter set */ ++#define ELEM_ID_COUNTRY_INFO 7 /* Country information */ ++#define ELEM_ID_HOPPING_PATTERN_PARAM 8 /* Hopping pattern parameters */ ++#define ELEM_ID_HOPPING_PATTERN_TABLE 9 /* Hopping pattern table */ ++#define ELEM_ID_REQUEST 10 /* Request */ ++#define ELEM_ID_BSS_LOAD 11 /* BSS load */ ++#define ELEM_ID_EDCA_PARAM_SET 12 /* EDCA parameter set */ ++#define ELEM_ID_TSPEC 13 /* Traffic specification (TSPEC) */ ++#define ELEM_ID_TCLAS 14 /* Traffic classification (TCLAS) */ ++#define ELEM_ID_SCHEDULE 15 /* Schedule */ ++#define ELEM_ID_CHALLENGE_TEXT 16 /* Challenge text */ ++ ++#define ELEM_ID_PWR_CONSTRAINT 32 /* Power constraint */ ++#define ELEM_ID_PWR_CAP 33 /* Power capability */ ++#define ELEM_ID_TPC_REQ 34 /* TPC request */ ++#define ELEM_ID_TPC_REPORT 35 /* TPC report */ ++#define ELEM_ID_SUP_CHS 36 /* Supported channels */ ++#define ELEM_ID_CH_SW_ANNOUNCEMENT 37 /* Channel switch announcement */ ++#define ELEM_ID_MEASUREMENT_REQ 38 /* Measurement request */ ++#define ELEM_ID_MEASUREMENT_REPORT 39 /* Measurement report */ ++#define ELEM_ID_QUIET 40 /* Quiet */ ++#define ELEM_ID_IBSS_DFS 41 /* IBSS DFS */ ++#define ELEM_ID_ERP_INFO 42 /* ERP information */ ++#define ELEM_ID_TS_DELAY 43 /* TS delay */ ++#define ELEM_ID_TCLAS_PROCESSING 44 /* TCLAS processing */ ++#define ELEM_ID_HT_CAP 45 /* HT Capabilities subelement */ ++#define ELEM_ID_QOS_CAP 46 /* QoS capability */ ++#define ELEM_ID_RSN 48 /* RSN IE */ ++#define ELEM_ID_EXTENDED_SUP_RATES 50 /* Extended supported rates */ ++#define ELEM_ID_TIMEOUT_INTERVAL 56 /* 802.11w SA Timeout interval */ ++#define ELEM_ID_SUP_OPERATING_CLASS 59 /* Supported Operating Classes */ ++#define ELEM_ID_HT_OP 61 /* HT Operation */ ++#define ELEM_ID_SCO 62 /* Secondary Channel Offset */ ++#define ELEM_ID_RRM_ENABLED_CAP 70 /* Radio Resource Management Enabled Capabilities */ ++#define ELEM_ID_20_40_BSS_COEXISTENCE 72 /* 20/40 BSS Coexistence */ ++#define ELEM_ID_20_40_INTOLERANT_CHNL_REPORT 73 /* 20/40 BSS Intolerant Channel Report */ ++#define ELEM_ID_OBSS_SCAN_PARAMS 74 /* Overlapping BSS Scan Parameters */ ++#define ELEM_ID_INTERWORKING 107 /* Interworking with External Network */ ++#define ELEM_ID_ADVERTISEMENT_PROTOCOL 108 /* Advertisement Protocol */ ++#define ELEM_ID_ROAMING_CONSORTIUM 111 /* Roaming Consortium */ ++#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ ++ ++#define ELEM_ID_VENDOR 221 /* Vendor specific IE */ ++#define ELEM_ID_WPA ELEM_ID_VENDOR /* WPA IE */ ++#define ELEM_ID_WMM ELEM_ID_VENDOR /* WMM IE */ ++#define ELEM_ID_P2P ELEM_ID_VENDOR /* WiFi Direct */ ++#define ELEM_ID_WFD ELEM_ID_VENDOR /* WiFi Direct */ ++#define ELEM_ID_WSC ELEM_ID_VENDOR /* WSC IE */ ++ ++#define ELEM_ID_RESERVED 255 /* Reserved */ ++ ++/* 7.3.2.1 SSID element */ ++#define ELEM_MAX_LEN_SSID 32 ++ ++/* 7.3.2.2 Supported Rates */ ++#define ELEM_MAX_LEN_SUP_RATES 8 ++ ++/* 7.3.2.4 DS Parameter Set */ ++#define ELEM_MAX_LEN_DS_PARAMETER_SET 1 ++ ++/* 7.3.2.5 CF Parameter Set */ ++#define ELEM_CF_PARM_LEN 8 ++ ++/* 7.3.2.6 TIM */ ++#define ELEM_MIX_LEN_TIM 4 ++#define ELEM_MAX_LEN_TIM 254 ++ ++/* 7.3.2.7 IBSS Parameter Set element */ ++#define ELEM_MAX_LEN_IBSS_PARAMETER_SET 2 ++ ++/* 7.3.2.8 Challenge Text element */ ++#define ELEM_MIN_LEN_CHALLENGE_TEXT 1 ++#define ELEM_MAX_LEN_CHALLENGE_TEXT 253 ++ ++/* 7.3.2.9 Country Information element */ ++/* Country IE should contain at least 3-bytes country code string and one subband triplet. */ ++#define ELEM_MIN_LEN_COUNTRY_INFO 6 ++ ++#define ELEM_ID_COUNTRY_INFO_TRIPLET_LEN_FIXED 3 ++#define ELEM_ID_COUNTRY_INFO_SUBBAND_TRIPLET_LEN_FIXED 3 ++#define ELEM_ID_COUNTRY_INFO_REGULATORY_TRIPLET_LEN_FIXED 3 ++ ++/* 7.3.2.13 ERP Information element */ ++#define ELEM_MAX_LEN_ERP 1 ++/* -- bits in the ERP Information element */ ++#define ERP_INFO_NON_ERP_PRESENT BIT(0) /* NonERP_Present bit */ ++#define ERP_INFO_USE_PROTECTION BIT(1) /* Use_Protection bit */ ++#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) /* Barker_Preamble_Mode bit */ ++ ++/* 7.3.2.14 Extended Supported Rates */ ++#define ELEM_MAX_LEN_EXTENDED_SUP_RATES 255 ++ ++#if CFG_SUPPORT_DFS ++/* 7.3.2.19 Supported Channels element */ ++#define ELEM_MAX_LEN_SUPPORTED_CHANNELS 7 ++#endif ++ ++/* 7.3.2.21 Measurement Request element */ ++#define ELEM_RM_TYPE_BASIC_REQ 0 ++#define ELEM_RM_TYPE_CCA_REQ 1 ++#define ELEM_RM_TYPE_RPI_HISTOGRAM_REQ 2 ++#define ELEM_RM_TYPE_CHNL_LOAD_REQ 3 ++#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REQ 4 ++#define ELEM_RM_TYPE_BEACON_REQ 5 ++#define ELEM_RM_TYPE_FRAME_REQ 6 ++#define ELEM_RM_TYPE_STA_STATISTICS_REQ 7 ++#define ELEM_RM_TYPE_LCI_REQ 8 ++#define ELEM_RM_TYPE_TS_REQ 9 ++#define ELEM_RM_TYPE_MEASURE_PAUSE_REQ 255 ++ ++/* 7.3.2.22 Measurement Report element */ ++#define ELEM_RM_TYPE_BASIC_REPORT 0 ++#define ELEM_RM_TYPE_CCA_REPORT 1 ++#define ELEM_RM_TYPE_RPI_HISTOGRAM_REPORT 2 ++#define ELEM_RM_TYPE_CHNL_LOAD_REPORT 3 ++#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REPORT 4 ++#define ELEM_RM_TYPE_BEACON_REPORT 5 ++#define ELEM_RM_TYPE_FRAME_REPORT 6 ++#define ELEM_RM_TYPE_STA_STATISTICS_REPORT 7 ++#define ELEM_RM_TYPE_LCI_REPORT 8 ++#define ELEM_RM_TYPE_TS_REPORT 9 ++/*Auto Channel Selection*/ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++#define ELEM_RM_TYPE_ACS_CHN 1 ++#define ELEM_RM_TYPE_LTE_CHN 2 ++#endif ++ ++/* 7.3.2.25 RSN information element */ ++#define ELEM_MAX_LEN_WPA 34 /* one pairwise, one AKM suite, one PMKID */ ++#define ELEM_MAX_LEN_RSN 38 /* one pairwise, one AKM suite, one PMKID */ ++#define ELEM_MAX_LEN_WAPI 38 /* one pairwise, one AKM suite, one BKID */ ++#define ELEM_MAX_LEN_WSC 200 /* one pairwise, one AKM suite, one BKID */ ++ ++#if CFG_SUPPORT_802_11W ++#define ELEM_WPA_CAP_MFPR BIT(6) ++#define ELEM_WPA_CAP_MFPC BIT(7) ++#endif ++ ++/* 7.3.2.27 Extended Capabilities information element */ ++#define ELEM_EXT_CAP_20_40_COEXIST_SUPPORT BIT(0) ++#define ELEM_EXT_CAP_PSMP_CAP BIT(4) ++#define ELEM_EXT_CAP_SERVICE_INTERVAL_GRANULARITY BIT(5) ++#define ELEM_EXT_CAP_SCHEDULE_PSMP BIT(6) ++ ++#define ELEM_EXT_CAP_BSS_TRANSITION_BIT 19 ++#define ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT 27 ++#define ELEM_EXT_CAP_INTERWORKING_BIT 31 ++#define ELEM_EXT_CAP_WNM_NOTIFICATION_BIT 46 ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#define ELEM_MAX_LEN_EXT_CAP (6) ++#else ++#define ELEM_MAX_LEN_EXT_CAP (3 - ELEM_HDR_LEN) ++#endif ++ ++/* 7.3.2.30 TSPEC element */ ++#define TS_INFO_TRAFFIC_TYPE_MASK BIT(0) /* WMM: 0 (Asynchronous TS of low-duty cycles) */ ++#define TS_INFO_TID_OFFSET 1 ++#define TS_INFO_TID_MASK BITS(1, 4) ++#define TS_INFO_DIRECTION_OFFSET 5 ++#define TS_INFO_DIRECTION_MASK BITS(5, 6) ++#define TS_INFO_ACCESS_POLICY_OFFSET 7 ++#define TS_INFO_ACCESS_POLICY_MASK BITS(7, 8) ++#define TS_INFO_AGGREGATION_MASK BIT(9) /* WMM: 0 */ ++#define TS_INFO_APSD_MASK BIT(10) ++#define TS_INFO_UP_OFFSET 11 ++#define TS_INFO_UP_MASK BITS(11, 13) ++#define TS_INFO_ACK_POLICY_OFFSET 14 ++#define TS_INFO_ACK_POLICY_MASK BITS(14, 15) ++#define TS_INFO_SCHEDULE_MASK 16 ++ ++/* 7.3.2.56 HT capabilities element */ ++#define ELEM_MAX_LEN_HT_CAP (28 - ELEM_HDR_LEN) /* sizeof(IE_HT_CAP_T)-2 */ ++ ++/* 7.3.2.56.2 HT capabilities Info field */ ++#define HT_CAP_INFO_LDPC_CAP BIT(0) ++#define HT_CAP_INFO_SUP_CHNL_WIDTH BIT(1) ++#define HT_CAP_INFO_SM_POWER_SAVE BITS(2, 3) ++#define HT_CAP_INFO_HT_GF BIT(4) ++#define HT_CAP_INFO_SHORT_GI_20M BIT(5) ++#define HT_CAP_INFO_SHORT_GI_40M BIT(6) ++#define HT_CAP_INFO_TX_STBC BIT(7) ++#define HT_CAP_INFO_RX_STBC BITS(8, 9) ++#define HT_CAP_INFO_HT_DELAYED_BA BIT(10) ++#define HT_CAP_INFO_MAX_AMSDU_LEN BIT(11) ++#define HT_CAP_INFO_DSSS_CCK_IN_40M BIT(12) ++#define HT_CAP_INFO_40M_INTOLERANT BIT(14) ++#define HT_CAP_INFO_LSIG_TXOP_SUPPORT BIT(15) ++ ++#define HT_CAP_INFO_RX_STBC_NO_SUPPORTED 0 ++#define HT_CAP_INFO_RX_STBC_1_SS BIT(8) ++#define HT_CAP_INFO_RX_STBC_2_SS BIT(9) ++#define HT_CAP_INFO_RX_STBC_3_SS HT_CAP_INFO_RX_STBC ++ ++/* 7.3.2.56.3 A-MPDU Parameters field */ ++#define AMPDU_PARAM_MAX_AMPDU_LEN_EXP BITS(0, 1) ++#define AMPDU_PARAM_MIN_START_SPACING BITS(2, 4) ++ ++#define AMPDU_PARAM_MAX_AMPDU_LEN_8K 0 ++#define AMPDU_PARAM_MAX_AMPDU_LEN_16K BIT(0) ++#define AMPDU_PARAM_MAX_AMPDU_LEN_32K BIT(1) ++#define AMPDU_PARAM_MAX_AMPDU_LEN_64K BITS(0, 1) ++ ++#define AMPDU_PARAM_MSS_NO_RESTRICIT 0 ++#define AMPDU_PARAM_MSS_1_4_US BIT(2) ++#define AMPDU_PARAM_MSS_1_2_US BIT(3) ++#define AMPDU_PARAM_MSS_1_US BITS(2, 3) ++#define AMPDU_PARAM_MSS_2_US BIT(4) ++#define AMPDU_PARAM_MSS_4_US (BIT(4) | BIT(2)) ++#define AMPDU_PARAM_MSS_8_US (BIT(4) | BIT(3)) ++#define AMPDU_PARAM_MSS_16_US BITS(2, 4) ++ ++/* 7.3.2.56.4 Supported MCS Set field (TX rate: octects 12~15) */ ++#define SUP_MCS_TX_SET_DEFINED BIT(0) ++#define SUP_MCS_TX_RX_SET_NOT_EQUAL BIT(1) ++#define SUP_MCS_TX_MAX_NUM_SS BITS(2, 3) ++#define SUP_MCS_TX_UNEQUAL_MODULATION BIT(4) ++ ++#define SUP_MCS_TX_MAX_NUM_1_SS 0 ++#define SUP_MCS_TX_MAX_NUM_2_SS BIT(2) ++#define SUP_MCS_TX_MAX_NUM_3_SS BIT(3) ++#define SUP_MCS_TX_MAX_NUM_4_SS BITS(2, 3) ++ ++#define SUP_MCS_RX_BITMASK_OCTET_NUM 10 ++#define SUP_MCS_RX_DEFAULT_HIGHEST_RATE 0 /* Not specify */ ++ ++/* 7.3.2.56.5 HT Extended Capabilities field */ ++#define HT_EXT_CAP_PCO BIT(0) ++#define HT_EXT_CAP_PCO_TRANSITION_TIME BITS(1, 2) ++#define HT_EXT_CAP_MCS_FEEDBACK BITS(8, 9) ++#define HT_EXT_CAP_HTC_SUPPORT BIT(10) ++#define HT_EXT_CAP_RD_RESPONDER BIT(11) ++ ++#define HT_EXT_CAP_PCO_TRANS_TIME_NONE 0 ++#define HT_EXT_CAP_PCO_TRANS_TIME_400US BIT(1) ++#define HT_EXT_CAP_PCO_TRANS_TIME_1_5MS BIT(2) ++#define HT_EXT_CAP_PCO_TRANS_TIME_5MS BITS(1, 2) ++ ++#define HT_EXT_CAP_MCS_FEEDBACK_NO_FB 0 ++#define HT_EXT_CAP_MCS_FEEDBACK_UNSOLICITED BIT(9) ++#define HT_EXT_CAP_MCS_FEEDBACK_BOTH BITS(8, 9) ++ ++/* 7.3.2.56.6 Transmit Beamforming Capabilities field */ ++ ++/* 7.3.2.56.7 Antenna Selection Capability field */ ++#define ASEL_CAP_CAPABLE BIT(0) ++#define ASEL_CAP_CSI_FB_BY_TX_ASEL_CAPABLE BIT(1) ++#define ASEL_CAP_ANT_INDICES_FB_BY_TX_ASEL_CAPABLE BIT(2) ++#define ASEL_CAP_EXPLICIT_CSI_FB_CAPABLE BIT(3) ++#define ASEL_CAP_ANT_INDICES_CAPABLE BIT(4) ++#define ASEL_CAP_RX_ASEL_CAPABLE BIT(5) ++#define ASEL_CAP_TX_SOUNDING_CAPABLE BIT(6) ++ ++/* 7.3.2.57 HT Operation element */ ++#define ELEM_MAX_LEN_HT_OP (24 - ELEM_HDR_LEN) /* sizeof(IE_HT_OP_T)-2 */ ++ ++#define HT_OP_INFO1_SCO BITS(0, 1) ++#define HT_OP_INFO1_STA_CHNL_WIDTH BIT(2) ++#define HT_OP_INFO1_RIFS_MODE BIT(3) ++ ++#define HT_OP_INFO2_HT_PROTECTION BITS(0, 1) ++#define HT_OP_INFO2_NON_GF_HT_STA_PRESENT BIT(2) ++#define HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT BIT(4) ++ ++#define HT_OP_INFO3_DUAL_BEACON BIT(6) ++#define HT_OP_INFO3_DUAL_CTS_PROTECTION BIT(7) ++#define HT_OP_INFO3_STBC_BEACON BIT(8) ++#define HT_OP_INFO3_LSIG_TXOP_FULL_SUPPORT BIT(9) ++#define HT_OP_INFO3_PCO_ACTIVE BIT(10) ++#define HT_OP_INFO3_PCO_PHASE BIT(11) ++ ++/* 7.3.2.59 OBSS Scan Parameter element */ ++#define ELEM_MAX_LEN_OBSS_SCAN (16 - ELEM_HDR_LEN) ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++#define ELEM_MAX_LEN_20_40_BSS_COEXIST (3 - ELEM_HDR_LEN) ++ ++#define BSS_COEXIST_INFO_REQ BIT(0) ++#define BSS_COEXIST_40M_INTOLERANT BIT(1) ++#define BSS_COEXIST_20M_REQ BIT(2) ++#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ BIT(3) ++#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_GRANT BIT(4) ++ ++/* 802.11u 7.3.2.92 Interworking IE */ ++#define ELEM_MAX_LEN_INTERWORKING (11 - ELEM_HDR_LEN) ++ ++/* 802.11u 7.3.2.93 Advertisement Protocol IE */ ++#define ELEM_MAX_LEN_ADV_PROTOCOL (4 - ELEM_HDR_LEN) ++ ++/* 802.11u 7.3.2.96 Roaming Consortium IE */ ++#define ELEM_MAX_LEN_ROAMING_CONSORTIUM (19 - ELEM_HDR_LEN) ++ ++#define IW_IE_LENGTH_ANO 1 ++#define IW_IE_LENGTH_ANO_VENUE 3 ++#define IW_IE_LENGTH_ANO_HESSID 7 ++#define IW_IE_LENGTH_ANO_VENUE_HESSID 9 ++ ++/* 3 Management frame body components (III): 7.4 Action frame format details. */ ++/* 7.4.1 Spectrum Measurement Action frame details */ ++#define ACTION_MEASUREMENT_REQ 0 /* Spectrum measurement request */ ++#define ACTION_MEASUREMENT_REPORT 1 /* Spectrum measurement report */ ++#define ACTION_TPC_REQ 2 /* TPC request */ ++#define ACTION_TPC_REPORT 3 /* TPC report */ ++#define ACTION_CHNL_SWITCH 4 /* Channel Switch Announcement */ ++ ++/* 7.4.2 QoS Action frame details */ ++#define ACTION_ADDTS_REQ 0 /* ADDTS request */ ++#define ACTION_ADDTS_RSP 1 /* ADDTS response */ ++#define ACTION_DELTS 2 /* DELTS */ ++#define ACTION_SCHEDULE 3 /* Schedule */ ++ ++#define ACTION_ADDTS_REQ_FRAME_LEN (24+3+63) /* WMM TSPEC IE: 63 */ ++#define ACTION_ADDTS_RSP_FRAME_LEN (24+4+63) /* WMM Status Code: 1; WMM TSPEC IE: 63 */ ++ ++/* 7.4.3 DLS Action frame details */ ++#define ACTION_DLS_REQ 0 /* DLS request */ ++#define ACTION_DLS_RSP 1 /* DLS response */ ++#define ACTION_DLS_TEARDOWN 2 /* DLS teardown */ ++ ++/* 7.4.4 Block ack Action frame details */ ++#define ACTION_ADDBA_REQ 0 /* ADDBA request */ ++#define ACTION_ADDBA_RSP 1 /* ADDBA response */ ++#define ACTION_DELBA 2 /* DELBA */ ++ ++#define ACTION_ADDBA_REQ_FRAME_LEN (24+9) ++#define ACTION_ADDBA_RSP_FRAME_LEN (24+9) ++ ++#define ACTION_DELBA_INITIATOR_MASK BIT(11) ++#define ACTION_DELBA_TID_MASK BITS(12, 15) ++#define ACTION_DELBA_TID_OFFSET 12 ++#define ACTION_DELBA_FRAME_LEN (24+6) ++ ++/* 7.4.6 Radio Measurement Action frame details */ ++#define ACTION_RM_REQ 0 /* Radio measurement request */ ++#define ACTION_RM_REPORT 1 /* Radio measurement report */ ++#define ACTION_LM_REQ 2 /* Link measurement request */ ++#define ACTION_LM_REPORT 3 /* Link measurement report */ ++#define ACTION_NEIGHBOR_REPORT_REQ 4 /* Neighbor report request */ ++#define ACTION_NEIGHBOR_REPORT_RSP 5 /* Neighbor report response */ ++ ++/* 7.4.7 Public Action frame details */ ++#define ACTION_PUBLIC_20_40_COEXIST 0 /* 20/40 BSS coexistence */ ++ ++#if CFG_SUPPORT_802_11W ++/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ ++#define ACTION_SA_QUERY_REQUEST 0 ++#define ACTION_SA_QUERY_RESPONSE 1 ++ ++#define ACTION_SA_QUERY_TR_ID_LEN 2 ++ ++/* Timeout Interval Type */ ++#define ACTION_SA_TIMEOUT_REASSOC_DEADLINE 1 ++#define ACTION_SA_TIMEOUT_KEY_LIFETIME 2 ++#define ACTION_SA_TIMEOUT_ASSOC_COMEBACK 3 ++#endif ++ ++/* 7.4.10.1 HT action frame details */ ++#define ACTION_HT_NOTIFY_CHANNEL_WIDTH 0 /* Notify Channel Width */ ++#define ACTION_HT_SM_POWER_SAVE 1 /* SM Power Save */ ++#define ACTION_HT_PSMP 2 /* PSMP */ ++#define ACTION_HT_SET_PCO_PHASE 3 /* Set PCO Phase */ ++#define ACTION_HT_CSI 4 /* CSI */ ++#define ACTION_HT_NON_COMPRESSED_BEAMFORM 5 /* Non-compressed Beamforming */ ++#define ACTION_HT_COMPRESSED_BEAMFORM 6 /* Compressed Beamforming */ ++#define ACTION_HT_ANT_SEL_INDICES_FB 7 /* Antenna Selection Indices Feedback */ ++ ++/* 802.11v Wireless Network Management */ ++#define ACTION_WNM_TIMING_MEASUREMENT_REQUEST 27 ++ ++#define ACTION_UNPROTECTED_WNM_TIM 0 ++#define ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT 1 ++ ++#define ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN 12 ++ ++/* 3 --------------- WFA frame body fields --------------- */ ++#define VENDOR_OUI_WFA { 0x00, 0x50, 0xF2 } ++#define VENDOR_OUI_WFA_SPECIFIC { 0x50, 0x6F, 0x9A } ++#define VENDOR_OUI_TYPE_WPA 1 ++#define VENDOR_OUI_TYPE_WMM 2 ++#define VENDOR_OUI_TYPE_WPS 4 ++#define VENDOR_OUI_TYPE_P2P 9 ++#define VENDOR_OUI_TYPE_WFD 10 ++#define VENDOR_OUI_TYPE_HS20 16 ++ ++#define VENDOR_OUI_TYPE_LEN 4 /* Length of OUI and Type */ ++ ++/* VERSION(2 octets for WPA) / SUBTYPE(1 octet)-VERSION(1 octet) fields for WMM in WFA IE */ ++#define VERSION_WPA 0x0001 /* Little Endian Format */ ++#define VENDOR_OUI_SUBTYPE_VERSION_WMM_INFO 0x0100 ++#define VENDOR_OUI_SUBTYPE_VERSION_WMM_PARAM 0x0101 ++ ++/* SUBTYPE(1 octet) for WMM */ ++#define VENDOR_OUI_SUBTYPE_WMM_INFO 0x00 /* WMM Spec version 1.1 */ ++#define VENDOR_OUI_SUBTYPE_WMM_PARAM 0x01 ++#define VENDOR_OUI_SUBTYPE_WMM_TSPEC 0x02 ++ ++/* VERSION(1 octet) for WMM */ ++#define VERSION_WMM 0x01 /* WMM Spec version 1.1 */ ++ ++/* WMM-2.1.6 QoS Control Field */ ++#define WMM_QC_UP_MASK BITS(0, 2) ++#define WMM_QC_EOSP BIT(4) ++#define WMM_QC_ACK_POLICY_MASK BITS(5, 6) ++#define WMM_QC_ACK_POLICY_OFFSET 5 ++#define WMM_QC_ACK_POLICY_ACKNOWLEDGE 0 ++#define WMM_QC_ACK_POLICY_NOT_ACKNOWLEDGE (1 << WMM_QC_ACK_POLICY_OFFSET) ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE 6 ++ ++/* HOTSPOT 2.0 Indication IE*/ ++#define ELEM_MAX_LEN_HS20_INDICATION 5 ++#define ELEM_MIN_LEN_HS20_INDICATION 4 ++ ++/* Hotspot Configuration*/ ++#define ELEM_HS_CONFIG_DGAF_DISABLED_MASK BIT(0) /* Downstream Group-Addressed Forwarding */ ++ ++/* 3 Control frame body */ ++/* 7.2.1.7 BlockAckReq */ ++#define CTRL_BAR_BAR_CONTROL_OFFSET 16 ++#define CTRL_BAR_BAR_INFORMATION_OFFSET 18 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack(1) ++#endif ++ ++typedef struct _LLC_SNAP_HEADER_T { ++ UINT_8 ucDSAP; ++ UINT_8 ucSSAP; ++ UINT_8 ucControl; ++ UINT_8 aucCode[3]; ++ UINT_16 u2Type; ++} __KAL_ATTRIB_PACKED__ LLC_SNAP_HEADER_T, *P_LLC_SNAP_HEADER_T; ++ ++/* 3 MAC Header. */ ++/* Ethernet Frame Header */ ++typedef struct _ETH_FRAME_HEADER_T { ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_16 u2TypeLen; ++} __KAL_ATTRIB_PACKED__ ETH_FRAME_HEADER_T, *P_ETH_FRAME_HEADER_T; ++ ++/* Ethernet Frame Structure */ ++typedef struct _ETH_FRAME_T { ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_16 u2TypeLen; ++ UINT_8 aucData[1]; ++} __KAL_ATTRIB_PACKED__ ETH_FRAME_T, *P_ETH_FRAME_T; ++ ++/* IEEE 802.11 WLAN Frame Structure */ ++/* WLAN MAC Header (without Address 4 and QoS Control fields) */ ++typedef struct _WLAN_MAC_HEADER_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_T, *P_WLAN_MAC_HEADER_T; ++ ++/* WLAN MAC Header (QoS Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_QOS_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_16 u2QosCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_QOS_T, *P_WLAN_MAC_HEADER_QOS_T; ++ ++/* WLAN MAC Header (HT Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_16 u2QosCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_HT_T, *P_WLAN_MAC_HEADER_HT_T; ++ ++/* WLAN MAC Header (Address 4 included) */ ++typedef struct _WLAN_MAC_HEADER_A4_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_T, *P_WLAN_MAC_HEADER_A4_T; ++ ++/* WLAN MAC Header (Address 4 and QoS Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_A4_QOS_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++ UINT_16 u2QosCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_QOS_T, *P_WLAN_MAC_HEADER_A4_QOS_T; ++ ++typedef struct _WLAN_MAC_HEADER_A4_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++ UINT_16 u2QosCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_HT_T, *P_WLAN_MAC_HEADER_A4_HT_T; ++ ++/* 7.2.3 WLAN MAC Header for Management Frame - MMPDU */ ++typedef struct _WLAN_MAC_MGMT_HEADER_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2Duration; ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_T, *P_WLAN_MAC_MGMT_HEADER_T; ++ ++/* WLAN MAC Header for Management Frame (HT Control fields included) */ ++typedef struct _WLAN_MAC_MGMT_HEADER_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_HT_T, *P_WLAN_MAC_MGMT_HEADER_HT_T; ++ ++/* 3 WLAN CONTROL Frame */ ++/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ ++typedef struct _CTRL_PSPOLL_FRAME_T { ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2AID; /* AID */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_8 aucTA[MAC_ADDR_LEN]; /* TA */ ++} __KAL_ATTRIB_PACKED__ CTRL_PSPOLL_FRAME_T, *P_CTRL_PSPOLL_FRAME_T; ++ ++/* BAR */ ++typedef struct _CTRL_BAR_FRAME_T { ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* RA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* TA */ ++ UINT_16 u2BarControl; ++ UINT_8 aucBarInfo[2]; /* Variable size */ ++} __KAL_ATTRIB_PACKED__ CTRL_BAR_FRAME_T, *P_CTRL_BAR_FRAME_T; ++ ++/* 3 WLAN Management Frame. */ ++/* 7.2.3.1 WLAN Management Frame - Beacon Frame */ ++typedef struct _WLAN_BEACON_FRAME_T { ++ /* Beacon header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ ++} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_T, *P_WLAN_BEACON_FRAME_T; ++ ++typedef struct _WLAN_BEACON_FRAME_BODY_T { ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ ++} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_BODY_T, *P_WLAN_BEACON_FRAME_BODY_T; ++ ++/* 7.2.3.3 WLAN Management Frame - Disassociation Frame */ ++typedef struct _WLAN_DISASSOC_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Disassociation frame body */ ++ UINT_16 u2ReasonCode; /* Reason code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ ++} __KAL_ATTRIB_PACKED__ WLAN_DISASSOC_FRAME_T, *P_WLAN_DISASSOC_FRAME_T; ++ ++/* 7.2.3.4 WLAN Management Frame - Association Request frame */ ++typedef struct _WLAN_ASSOC_REQ_FRAME_T { ++ /* Association Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Association Request frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2ListenInterval; /* Listen interval */ ++ UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ ++} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_REQ_FRAME_T, *P_WLAN_ASSOC_REQ_FRAME_T; ++ ++/* 7.2.3.5 WLAN Management Frame - Association Response frame */ ++typedef struct _WLAN_ASSOC_RSP_FRAME_T { ++ /* Association Response MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Association Response frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2StatusCode; /* Status code */ ++ UINT_16 u2AssocId; /* Association ID */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ supported rates, and etc. */ ++} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_RSP_FRAME_T, *P_WLAN_ASSOC_RSP_FRAME_T; ++ ++/* 7.2.3.6 WLAN Management Frame - Reassociation Request frame */ ++typedef struct _WLAN_REASSOC_REQ_FRAME_T { ++ /* Reassociation Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Reassociation Request frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2ListenInterval; /* Listen interval */ ++ UINT_8 aucCurrentAPAddr[MAC_ADDR_LEN]; /* Current AP address */ ++ UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ ++} __KAL_ATTRIB_PACKED__ WLAN_REASSOC_REQ_FRAME_T, *P_WLAN_REASSOC_REQ_FRAME_T; ++ ++/* 7.2.3.7 WLAN Management Frame - Reassociation Response frame ++ (the same as Association Response frame) */ ++typedef WLAN_ASSOC_RSP_FRAME_T WLAN_REASSOC_RSP_FRAME_T, *P_WLAN_REASSOC_RSP_FRAME_T; ++ ++/* 7.2.3.9 WLAN Management Frame - Probe Response Frame */ ++typedef WLAN_BEACON_FRAME_T WLAN_PROBE_RSP_FRAME_T, *P_WLAN_PROBE_RSP_FRAME_T; ++ ++/* 7.2.3.10 WLAN Management Frame - Authentication Frame */ ++typedef struct _WLAN_AUTH_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Authentication frame body */ ++ UINT_16 u2AuthAlgNum; /* Authentication algorithm number */ ++ UINT_16 u2AuthTransSeqNo; /* Authentication transaction sequence number */ ++ UINT_16 u2StatusCode; /* Status code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs for Fast BSS Transition */ ++} __KAL_ATTRIB_PACKED__ WLAN_AUTH_FRAME_T, *P_WLAN_AUTH_FRAME_T; ++ ++/* 7.2.3.11 WLAN Management Frame - Deauthentication Frame */ ++typedef struct _WLAN_DEAUTH_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Deauthentication frame body */ ++ UINT_16 u2ReasonCode; /* Reason code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ ++} __KAL_ATTRIB_PACKED__ WLAN_DEAUTH_FRAME_T, *P_WLAN_DEAUTH_FRAME_T; ++ ++/* 3 Information Elements. */ ++/* 7.3.2 Generic element format */ ++typedef struct _IE_HDR_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucInfo[1]; ++} __KAL_ATTRIB_PACKED__ IE_HDR_T, *P_IE_HDR_T; ++ ++/* 7.3.2.1 SSID element */ ++typedef struct _IE_SSID_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++} __KAL_ATTRIB_PACKED__ IE_SSID_T, *P_IE_SSID_T; ++ ++/* 7.3.2.2 Supported Rates element */ ++typedef struct _IE_SUPPORTED_RATE_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES]; ++} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_T, *P_IE_SUPPORTED_RATE_T; ++ ++/* 7.3.2.4 DS Parameter Set element */ ++typedef struct _IE_DS_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCurrChnl; ++} __KAL_ATTRIB_PACKED__ IE_DS_PARAM_SET_T, *P_IE_DS_PARAM_SET_T; ++ ++/* 7.3.2.5 CF Parameter Set element */ ++typedef struct _IE_CF_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCFPCount; ++ UINT_8 ucCFPPeriod; ++ UINT_16 u2CFPMaxDur; ++ UINT_16 u2DurRemaining; ++} __KAL_ATTRIB_PACKED__ IE_CF_PARAM_SET_T, *P_IE_CF_PARAM_SET_T; ++ ++/* 7.3.2.6 TIM */ ++typedef struct _IE_TIM_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucDTIMCount; ++ UINT_8 ucDTIMPeriod; ++ UINT_8 ucBitmapControl; ++ UINT_8 aucPartialVirtualMap[1]; ++} __KAL_ATTRIB_PACKED__ IE_TIM_T, *P_IE_TIM_T; ++ ++/* 7.3.2.7 IBSS Parameter Set element */ ++typedef struct _IE_IBSS_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2ATIMWindow; ++} __KAL_ATTRIB_PACKED__ IE_IBSS_PARAM_SET_T, *P_IE_IBSS_PARAM_SET_T; ++ ++/* 7.3.2.8 Challenge Text element */ ++typedef struct _IE_CHALLENGE_TEXT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucChallengeText[ELEM_MAX_LEN_CHALLENGE_TEXT]; ++} __KAL_ATTRIB_PACKED__ IE_CHALLENGE_TEXT_T, *P_IE_CHALLENGE_TEXT_T; ++ ++/* 7.3.2.9 Country information element */ ++#if CFG_SUPPORT_802_11D ++/*! \brief COUNTRY_INFO_TRIPLET is defined for the COUNTRY_INFO_ELEM structure. */ ++typedef struct _COUNTRY_INFO_TRIPLET_T { ++ UINT_8 ucParam1; /*!< If param1 >= 201, this triplet is referred to as ++ Regulatory Triplet in 802_11J. */ ++ UINT_8 ucParam2; ++ UINT_8 ucParam3; ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_TRIPLET_T, *P_COUNTRY_INFO_TRIPLET_T; ++ ++typedef struct _COUNTRY_INFO_SUBBAND_TRIPLET_T { ++ UINT_8 ucFirstChnlNum; /*!< First Channel Number */ ++ UINT_8 ucNumOfChnl; /*!< Number of Channels */ ++ INT_8 cMaxTxPwrLv; /*!< Maximum Transmit Power Level */ ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_SUBBAND_TRIPLET_T, *P_COUNTRY_INFO_SUBBAND_TRIPLET_T; ++ ++typedef struct _COUNTRY_INFO_REGULATORY_TRIPLET_T { ++ UINT_8 ucRegExtId; /*!< Regulatory Extension Identifier, should ++ be greater than or equal to 201 */ ++ UINT_8 ucRegClass; /*!< Regulatory Class */ ++ UINT_8 ucCoverageClass; /*!< Coverage Class, unsigned 1-octet value 0~31 ++ , 32~255 reserved */ ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_REGULATORY_TRIPLET_T, *P_COUNTRY_INFO_REGULATORY_TRIPLET_T; ++ ++typedef struct _IE_COUNTRY_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCountryStr[3]; ++ COUNTRY_INFO_SUBBAND_TRIPLET_T arCountryStr[1]; ++} __KAL_ATTRIB_PACKED__ IE_COUNTRY_T, *P_IE_COUNTRY_T; ++#endif /* CFG_SUPPORT_802_11D */ ++ ++/* 7.3.2.13 ERP element */ ++typedef struct _IE_ERP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucERP; ++} __KAL_ATTRIB_PACKED__ IE_ERP_T, *P_IE_ERP_T; ++ ++/* 7.3.2.14 Extended Supported Rates element */ ++typedef struct _IE_EXT_SUPPORTED_RATE_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucExtSupportedRates[ELEM_MAX_LEN_EXTENDED_SUP_RATES]; ++} __KAL_ATTRIB_PACKED__ IE_EXT_SUPPORTED_RATE_T, *P_IE_EXT_SUPPORTED_RATE_T; ++ ++/* 7.3.2.15 Power Constraint element */ ++typedef struct _IE_POWER_CONSTRAINT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucLocalPowerConstraint; /* Unit: dBm */ ++} __KAL_ATTRIB_PACKED__ IE_POWER_CONSTRAINT_T, *P_IE_POWER_CONSTRAINT_T; ++ ++/* 7.3.2.16 Power Capability element */ ++typedef struct _IE_POWER_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ INT_8 cMinTxPowerCap; /* Unit: dBm */ ++ INT_8 cMaxTxPowerCap; /* Unit: dBm */ ++} __KAL_ATTRIB_PACKED__ IE_POWER_CAP_T, *P_IE_POWER_CAP_T; ++ ++/* 7.3.2.17 TPC request element */ ++typedef struct _IE_TPC_REQ_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++} __KAL_ATTRIB_PACKED__ IE_TPC_REQ_T, *P_IE_TPC_REQ_T; ++ ++/* 7.3.2.18 TPC report element */ ++typedef struct _IE_TPC_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ INT_8 cTxPower; /* Unit: dBm */ ++ INT_8 cLinkMargin; /* Unit: dB */ ++} __KAL_ATTRIB_PACKED__ IE_TPC_REPORT_T, *P_IE_TPC_REPORT_T; ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++/* 7.3.2.19 Supported Channels element*/ ++typedef struct _IE_SUPPORTED_CHANNELS_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucChannelNum[ELEM_MAX_LEN_SUPPORTED_CHANNELS * 2]; ++} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_CHANNELS_T, *P_IE_SUPPORTED_CHANNELS_T; ++ ++/* 7.3.2.20 Channel Switch Announcement element*/ ++typedef struct _IE_CHANNEL_SWITCH_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucChannelSwitchMode; ++ UINT_8 ucNewChannelNum; ++ UINT_8 ucChannelSwitchCount; ++} __KAL_ATTRIB_PACKED__ IE_CHANNEL_SWITCH_T, *P_IE_CHANNEL_SWITCH_T; ++#endif ++ ++/* 7.3.2.21 Measurement Request element */ ++typedef struct _IE_MEASUREMENT_REQ_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucToken; ++ UINT_8 ucRequestMode; ++ UINT_8 ucMeasurementType; ++ UINT_8 aucRequestFields[1]; ++} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REQ_T, *P_IE_MEASUREMENT_REQ_T; ++ ++typedef struct _SM_BASIC_REQ_T { ++ UINT_8 ucChannel; ++ UINT_32 au4StartTime[2]; ++ UINT_16 u2Duration; ++} __KAL_ATTRIB_PACKED__ SM_BASIC_REQ_T, *P_SM_BASIC_REQ_T; ++ ++/* SM_COMMON_REQ_T is not specified in Spec. Use it as common structure of SM */ ++typedef SM_BASIC_REQ_T SM_REQ_COMMON_T, *P_SM_REQ_COMMON_T; ++typedef SM_BASIC_REQ_T SM_CCA_REQ_T, *P_SM_CCA_REQ_T; ++typedef SM_BASIC_REQ_T SM_RPI_HISTOGRAM_REQ_T, *P_SM_RPI_HISTOGRAM_REQ_T; ++ ++typedef struct _RM_CHNL_LOAD_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REQ_T, *P_RM_CHNL_LOAD_REQ_T; ++ ++typedef RM_CHNL_LOAD_REQ_T RM_NOISE_HISTOGRAM_REQ_T, *P_RM_NOISE_HISTOGRAM_REQ_T; ++ ++typedef struct _RM_BCN_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucMeasurementMode; ++ UINT_8 aucBssid[6]; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_BCN_REQ_T, *P_RM_BCN_REQ_T; ++ ++typedef struct _RM_FRAME_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucFrameReqType; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_FRAME_REQ_T, *P_RM_FRAME_REQ_T; ++ ++typedef struct _RM_STA_STATS_REQ_T { ++ UINT_8 aucPeerMacAddr[6]; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucGroupID; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_STA_STATS_REQ_T, *P_RM_STA_STATS_REQ_T; ++ ++typedef struct _RM_LCI_REQ_T { ++ UINT_8 ucLocationSubject; ++ UINT_8 ucLatitudeResolution; ++ UINT_8 ucLongitudeResolution; ++ UINT_8 ucAltitudeResolution; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_LCI_REQ_T, *P_RM_LCI_REQ_T; ++ ++typedef struct _RM_TS_MEASURE_REQ_T { ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 aucPeerStaAddr[6]; ++ UINT_8 ucTrafficID; ++ UINT_8 ucBin0Range; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_TS_MEASURE_REQ_T, *P_RM_TS_MEASURE_REQ_T; ++ ++typedef struct _RM_MEASURE_PAUSE_REQ_T { ++ UINT_16 u2PauseTime; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_MEASURE_PAUSE_REQ_T, *P_RM_MEASURE_PAUSE_REQ_T; ++ ++/* 7.3.2.22 Measurement Report element */ ++typedef struct _IE_MEASUREMENT_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucToken; ++ UINT_8 ucReportMode; ++ UINT_8 ucMeasurementType; ++ UINT_8 aucReportFields[1]; ++} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REPORT_T, *P_IE_MEASUREMENT_REPORT_T; ++ ++typedef struct _SM_BASIC_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucMap; ++} __KAL_ATTRIB_PACKED__ SM_BASIC_REPORT_T, *P_SM_BASIC_REPORT_T; ++ ++typedef struct _SM_CCA_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucCcaBusyFraction; ++} __KAL_ATTRIB_PACKED__ SM_CCA_REPORT_T, *P_SM_CCA_REPORT_T; ++ ++typedef struct _SM_RPI_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 aucRPI[8]; ++} __KAL_ATTRIB_PACKED__ SM_RPI_REPORT_T, *P_SM_RPI_REPORT_T; ++ ++typedef struct _RM_CHNL_LOAD_REPORT_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucChnlLoad; ++} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REPORT_T, *P_RM_CHNL_LOAD_REPORT_T; ++ ++typedef struct _RM_IPI_REPORT_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucAntennaId; ++ INT_8 cANPI; ++ UINT_8 aucIPI[11]; ++} __KAL_ATTRIB_PACKED__ RM_IPI_REPORT_T, *P_RM_IPI_REPORT_T; ++ ++/* 7.3.2.23 Quiet element */ ++typedef struct _IE_QUIET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCount; ++ UINT_8 ucPeriod; ++ UINT_16 u2Duration; ++ UINT_16 u2Offset; ++} __KAL_ATTRIB_PACKED__ IE_QUIET_T, *P_IE_QUIET_T; ++ ++/* 7.3.2.27 Extended Capabilities element */ ++typedef struct _IE_EXT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCapabilities[5]; ++} __KAL_ATTRIB_PACKED__ IE_EXT_CAP_T, *P_EXT_CAP_T; ++ ++/* 7.3.2.27 hs20 Extended Capabilities element */ ++typedef struct _IE_HS20_EXT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCapabilities[6]; ++} __KAL_ATTRIB_PACKED__ IE_HS20_EXT_CAP_T, *P_HS20_EXT_CAP_T; ++ ++ ++/* 7.3.2.27 Extended Capabilities element */ ++typedef struct _IE_RRM_ENABLED_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCap[5]; ++} __KAL_ATTRIB_PACKED__ IE_RRM_ENABLED_CAP_T, *P_IE_RRM_ENABLED_CAP_T; ++ ++/* 7.3.2.51 Timeout Interval element (TIE) */ ++typedef struct _IE_TIMEOUT_INTERVAL_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++#define IE_TIMEOUT_INTERVAL_TYPE_RESERVED 0 ++#define IE_TIMEOUT_INTERVAL_TYPE_REASSOC 1 ++#define IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME 2 ++#define IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK 3 ++ UINT_8 ucType; ++ UINT_32 u4Value; ++} __KAL_ATTRIB_PACKED__ IE_TIMEOUT_INTERVAL_T; ++ ++/* 7.3.2.56 HT Capabilities element */ ++typedef struct _SUP_MCS_SET_FIELD { ++ UINT_8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; ++ UINT_16 u2RxHighestSupportedRate; ++ UINT_32 u4TxRateInfo; ++} __KAL_ATTRIB_PACKED__ SUP_MCS_SET_FIELD, *P_SUP_MCS_SET_FIELD; ++ ++typedef struct _IE_HT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2HtCapInfo; ++ UINT_8 ucAmpduParam; ++ SUP_MCS_SET_FIELD rSupMcsSet; ++ UINT_16 u2HtExtendedCap; ++ UINT_32 u4TxBeamformingCap; ++ UINT_8 ucAselCap; ++} __KAL_ATTRIB_PACKED__ IE_HT_CAP_T, *P_IE_HT_CAP_T; ++ ++/* 7.3.2.57 HT Operation element */ ++typedef struct _IE_HT_OP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucInfo1; ++ UINT_16 u2Info2; ++ UINT_16 u2Info3; ++ UINT_8 aucBasicMcsSet[16]; ++} __KAL_ATTRIB_PACKED__ IE_HT_OP_T, *P_IE_HT_OP_T; ++ ++/* 7.3.2.25 RSN Information element format */ ++typedef struct _RSN_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2PairwiseKeyCipherSuiteCount; ++ UCHAR aucPairwiseKeyCipherSuite1[4]; ++} __KAL_ATTRIB_PACKED__ RSN_INFO_ELEM_T, *P_RSN_INFO_ELEM_T; ++ ++/* 7.3.2.26 WPA Information element format */ ++typedef struct _WPA_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UCHAR aucOui[3]; ++ UCHAR ucOuiType; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2PairwiseKeyCipherSuiteCount; ++ UCHAR aucPairwiseKeyCipherSuite1[4]; ++} __KAL_ATTRIB_PACKED__ WPA_INFO_ELEM_T, *P_WPA_INFO_ELEM_T; ++ ++/* 7.3.2.58 20/40 BSS Intolerant Channel Report element */ ++typedef struct _IE_INTOLERANT_CHNL_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucRegulatoryClass; ++ UINT_8 aucChannelList[1]; ++} __KAL_ATTRIB_PACKED__ IE_INTOLERANT_CHNL_REPORT_T, *P_IE_INTOLERANT_CHNL_REPORT_T; ++ ++/* 7.3.2.59 OBSS Scan Parameters element */ ++typedef struct _IE_OBSS_SCAN_PARAM_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2ScanPassiveDwell; ++ UINT_16 u2ScanActiveDwell; ++ UINT_16 u2TriggerScanInterval; ++ UINT_16 u2ScanPassiveTotalPerChnl; ++ UINT_16 u2ScanActiveTotalPerChnl; ++ UINT_16 u2WidthTransDelayFactor; ++ UINT_16 u2ScanActivityThres; ++} __KAL_ATTRIB_PACKED__ IE_OBSS_SCAN_PARAM_T, *P_IE_OBSS_SCAN_PARAM_T; ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++typedef struct _IE_20_40_COEXIST_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucData; ++} __KAL_ATTRIB_PACKED__ IE_20_40_COEXIST_T, *P_IE_20_40_COEXIST_T; ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++typedef struct _IE_SUP_OPERATING_CLASS_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCur; ++ UINT_8 ucSup[255]; ++} __KAL_ATTRIB_PACKED__ IE_SUP_OPERATING_CLASS_T, *P_IE_SUP_OPERATING_CLASS_T; ++ ++/* 3 7.4 Action Frame. */ ++/* 7.4 Action frame format */ ++typedef struct _WLAN_ACTION_FRAME { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucActionDetails[1]; /* Action details */ ++} __KAL_ATTRIB_PACKED__ WLAN_ACTION_FRAME, *P_WLAN_ACTION_FRAME; ++ ++/* 7.4.1.1 Spectrum Measurement Request frame format */ ++typedef struct _ACTION_SM_REQ_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Information elements */ ++} __KAL_ATTRIB_PACKED__ ACTION_SM_REQ_FRAME, *P_ACTION_SM_REQ_FRAME; ++ ++/* 7.4.1.2 Spectrum Measurement Report frame format */ ++typedef ACTION_SM_REQ_FRAME ACTION_SM_REPORT_FRAME, *P_ACTION_SM_REPORT_FRAME; ++ ++/* 7.4.1.5 Channel Switch Announcement frame format */ ++typedef struct _ACTION_CHANNEL_SWITCH_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 aucInfoElem[5]; /* Information elements */ ++} __KAL_ATTRIB_PACKED__ _ACTION_CHANNEL_SWITCH_FRAME, *P_ACTION_CHANNEL_SWITCH_FRAME; ++ ++/* 7.4.2.1 ADDTS Request frame format */ ++typedef struct _ACTION_ADDTS_REQ_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ TS Delay, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_REQ_FRAME, *P_ACTION_ADDTS_REQ_FRAME; ++ ++/* 7.4.2.2 ADDTS Response frame format */ ++typedef struct _ACTION_ADDTS_RSP_FRAME { ++ /* ADDTS Response MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Response frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucStatusCode; /* WMM Status Code is of one byte */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ TS Delay, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_RSP_FRAME, *P_ACTION_ADDTS_RSP_FRAME; ++ ++/* 7.4.2.3 DELTS frame format */ ++typedef struct _ACTION_DELTS_FRAME { ++ /* DELTS MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* DELTS frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 aucTsInfo[3]; /* TS Info */ ++} __KAL_ATTRIB_PACKED__ ACTION_DELTS_FRAME, *P_ACTION_DELTS_FRAME; ++ ++/* 7.4.4.1 ADDBA Request frame format */ ++typedef struct _ACTION_ADDBA_REQ_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ ++ UINT_8 aucBATimeoutValue[2]; ++ UINT_8 aucBAStartSeqCtrl[2]; /* SSN */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_FRAME_T, *P_ACTION_ADDBA_REQ_FRAME_T; ++ ++typedef struct _ACTION_ADDBA_REQ_BODY_T { ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++ UINT_16 u2BAStartSeqCtrl; /* SSN */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_BODY_T, *P_ACTION_ADDBA_REQ_BODY_T; ++ ++/* 7.4.4.2 ADDBA Response frame format */ ++typedef struct _ACTION_ADDBA_RSP_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_8 aucStatusCode[2]; ++ UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ ++ UINT_8 aucBATimeoutValue[2]; ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_FRAME_T, *P_ACTION_ADDBA_RSP_FRAME_T; ++ ++typedef struct _ACTION_ADDBA_RSP_BODY_T { ++ UINT_16 u2StatusCode; ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_BODY_T, *P_ACTION_ADDBA_RSP_BODY_T; ++ ++/* 7.4.4.3 DELBA frame format */ ++typedef struct _ACTION_DELBA_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_16 u2DelBaParameterSet; /* Bit 11 Initiator, Bits 12-15 TID */ ++ UINT_16 u2ReasonCode; /* 7.3.1.7 */ ++} __KAL_ATTRIB_PACKED__ ACTION_DELBA_FRAME_T, *P_ACTION_DELBA_FRAME_T; ++ ++/* 7.4.6.1 Radio Measurement Request frame format */ ++typedef struct _ACTION_RM_REQ_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Radio Measurement Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_16 u2Repetitions; /* Number of repetitions */ ++ UINT_8 aucInfoElem[1]; /* Measurement Request elements, such as ++ channel load request, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_RM_REQ_FRAME, *P_ACTION_RM_REQ_FRAME; ++ ++/* 7.4.6.2 Radio Measurement Report frame format */ ++typedef struct _ACTION_RM_REPORT_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Radio Measurement Report frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Measurement Report elements, such as ++ channel load report, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_RM_REPORT_FRAME, *P_ACTION_RM_REPORT_FRAME; ++ ++/* 7.4.7.1a 20/40 BSS Coexistence Management frame format */ ++typedef struct _ACTION_20_40_COEXIST_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ ++ IE_20_40_COEXIST_T rBssCoexist; /* 20/40 BSS coexistence element */ ++ IE_INTOLERANT_CHNL_REPORT_T rChnlReport; /* Intolerant channel report */ ++ ++} __KAL_ATTRIB_PACKED__ ACTION_20_40_COEXIST_FRAME, *P_ACTION_20_40_COEXIST_FRAME; ++ ++#if CFG_SUPPORT_802_11W ++/* 7.4.9 SA Query Management frame format */ ++typedef struct _ACTION_SA_QUERY_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ ++ UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; /* Transaction id */ ++ ++} __KAL_ATTRIB_PACKED__ ACTION_SA_QUERY_FRAME, *P_ACTION_SA_QUERY_FRAME; ++#endif ++ ++/* 7.4.10 Notify Channel Width Management frame format */ ++typedef struct _ACTION_NOTIFY_CHNL_WIDTH_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucChannelWidth; /* Channel Width */ ++} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHNL_WIDTH_FRAME, *P_ACTION_NOTIFY_CHNL_WIDTH_FRAME; ++ ++/* 802.11v Wireless Network Management: Timing Measurement Request */ ++typedef struct _ACTION_WNM_TIMING_MEAS_REQ_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Timing Measurement Request Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucTrigger; /* Trigger */ ++} __KAL_ATTRIB_PACKED__ ACTION_WNM_TIMING_MEAS_REQ_FRAME, *P_ACTION_WNM_TIMING_MEAS_REQ_FRAME; ++ ++/* 802.11v Wireless Network Management: Timing Measurement */ ++typedef struct _ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Timing Measurement Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ ++ UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ ++ UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ ++ UINT_8 ucMaxToDErr; /* Maximum of ToD Error [10ns] */ ++ UINT_8 ucMaxToAErr; /* Maximum of ToA Error [10ns] */ ++} __KAL_ATTRIB_PACKED__ ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME, *P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME; ++ ++/* 3 Information Elements from WFA. */ ++typedef struct _IE_WFA_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucOui[3]; ++ UINT_8 ucOuiType; ++ UINT_8 aucOuiSubTypeVersion[2]; ++ /*!< Please be noted. WPA defines a 16 bit field version ++ instead of one subtype field and one version field */ ++} __KAL_ATTRIB_PACKED__ IE_WFA_T, *P_IE_WFA_T; ++ ++/* HS20 3.1 - HS 2.0 Indication Information Element */ ++typedef struct _IE_HS20_INDICATION_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucType; /* Type */ ++ UINT_8 ucHotspotConfig; /* Hotspot Configuration */ ++} __KAL_ATTRIB_PACKED__ IE_HS20_INDICATION_T, *P_IE_HS20_INDICATION_T; ++ ++/* WAPI Information element format */ ++typedef struct _WAPI_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_16 u2AuthKeyMgtSuiteCount; ++ UCHAR aucAuthKeyMgtSuite1[4]; ++} __KAL_ATTRIB_PACKED__ WAPI_INFO_ELEM_T, *P_WAPI_INFO_ELEM_T; ++ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack() ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Convert the ECWmin(max) to CWmin(max) */ ++#define ECW_TO_CW(_ECW) ((1 << (_ECW)) - 1) ++ ++/* Convert the RCPI to dBm */ ++#define RCPI_TO_dBm(_rcpi) \ ++ ((PARAM_RSSI)(((_rcpi) > RCPI_HIGH_BOUND ? RCPI_HIGH_BOUND : (_rcpi)) >> 1) - NDBM_LOW_BOUND_FOR_RCPI) ++ ++/* Convert the dBm to RCPI */ ++#define dBm_TO_RCPI(_dbm) \ ++ (RCPI)(((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) > RCPI_HIGH_BOUND) ? RCPI_HIGH_BOUND : \ ++ ((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) < RCPI_LOW_BOUND ? RCPI_LOW_BOUND : \ ++ (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1))) ++ ++/* Convert an unsigned char pointer to an information element pointer */ ++#define IE_ID(fp) (((P_IE_HDR_T) fp)->ucId) ++#define IE_LEN(fp) (((P_IE_HDR_T) fp)->ucLength) ++#define IE_SIZE(fp) (ELEM_HDR_LEN + IE_LEN(fp)) ++ ++#define SSID_IE(fp) ((P_IE_SSID_T) fp) ++ ++#define SUP_RATES_IE(fp) ((P_IE_SUPPORTED_RATE_T) fp) ++ ++#define DS_PARAM_IE(fp) ((P_IE_DS_PARAM_SET_T) fp) ++ ++#define TIM_IE(fp) ((P_IE_TIM_T) fp) ++ ++#define IBSS_PARAM_IE(fp) ((P_IE_IBSS_PARAM_SET_T) fp) ++ ++#define ERP_INFO_IE(fp) ((P_IE_ERP_T) fp) ++ ++#define EXT_SUP_RATES_IE(fp) ((P_IE_EXT_SUPPORTED_RATE_T) fp) ++ ++#define WFA_IE(fp) ((P_IE_WFA_T) fp) ++ ++#if CFG_SUPPORT_802_11D ++#define COUNTRY_IE(fp) ((P_IE_COUNTRY_T) fp) ++#endif ++ ++#define EXT_CAP_IE(fp) ((P_EXT_CAP_T) fp) ++ ++#define HT_CAP_IE(fp) ((P_IE_HT_CAP_T) fp) ++ ++#define HT_OP_IE(fp) ((P_IE_HT_OP_T) fp) ++ ++#define OBSS_SCAN_PARAM_IE(fp) ((P_IE_OBSS_SCAN_PARAM_T) fp) ++ ++#define BSS_20_40_COEXIST_IE(fp) ((P_IE_20_40_COEXIST_T) fp) ++ ++#define SUP_OPERATING_CLASS_IE(fp) ((P_IE_SUP_OPERATING_CLASS_T) fp) ++ ++#define QUIET_IE(fp) ((P_IE_QUIET_T) fp) ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++#define SUPPORTED_CHANNELS_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp) ++#endif ++ ++#define TIMEOUT_INTERVAL_IE(fp) ((IE_TIMEOUT_INTERVAL_T *)fp) ++ ++/* The macro to check if the MAC address is B/MCAST Address */ ++#define IS_BMCAST_MAC_ADDR(_pucDestAddr) \ ++ ((BOOLEAN) (((PUINT_8)(_pucDestAddr))[0] & BIT(0))) ++ ++/* The macro to check if the MAC address is UCAST Address */ ++#define IS_UCAST_MAC_ADDR(_pucDestAddr) \ ++ ((BOOLEAN) !(((PUINT_8)(_pucDestAddr))[0] & BIT(0))) ++ ++/* The macro to copy the MAC address */ ++#define COPY_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ kalMemCopy(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN) ++ ++/* The macro to check if two MAC addresses are equal */ ++#define EQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ (!kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) ++ ++/* The macro to check if two MAC addresses are not equal */ ++#define UNEQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ (kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) ++ ++/* The macro to check whether two SSIDs are equal */ ++#define EQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ ++ ((ucSsidLen1 <= ELEM_MAX_LEN_SSID) && \ ++ (ucSsidLen2 <= ELEM_MAX_LEN_SSID) && \ ++ ((ucSsidLen1) == (ucSsidLen2)) && \ ++ !kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) ++ ++/* The macro to check whether two SSIDs are equal */ ++#define UNEQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ ++ ((ucSsidLen1 > ELEM_MAX_LEN_SSID) || \ ++ (ucSsidLen2 > ELEM_MAX_LEN_SSID) || \ ++ ((ucSsidLen1) != (ucSsidLen2)) || \ ++ kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) ++ ++/* The macro to copy the SSID, the length of pucDestSsid should have at least 32 bytes */ ++#define COPY_SSID(pucDestSsid, ucDestSsidLen, pucSrcSsid, ucSrcSsidLen) \ ++ do { \ ++ ucDestSsidLen = ucSrcSsidLen; \ ++ if (ucSrcSsidLen) { \ ++ ASSERT(ucSrcSsidLen <= ELEM_MAX_LEN_SSID); \ ++ kalMemCopy(pucDestSsid, \ ++ pucSrcSsid, \ ++ ((ucSrcSsidLen > ELEM_MAX_LEN_SSID) ? ELEM_MAX_LEN_SSID : ucSrcSsidLen)); \ ++ } \ ++ } while (FALSE) ++ ++/* The macro to copy the IE */ ++#define COPY_IE(pucDestIE, pucSrcIE) \ ++ do { \ ++ kalMemCopy((PUINT_8)pucDestIE, \ ++ (PUINT_8)pucSrcIE,\ ++ IE_SIZE(pucSrcIE)); \ ++ } while (FALSE) ++ ++#define IE_FOR_EACH(_pucIEsBuf, _u2IEsBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0;\ ++ ((((_u2Offset) + 2) <= (_u2IEsBufLen)) && (((_u2Offset) + IE_SIZE(_pucIEsBuf)) <= (_u2IEsBufLen))); \ ++ (_u2Offset) += IE_SIZE(_pucIEsBuf), (_pucIEsBuf) += IE_SIZE(_pucIEsBuf)) ++ ++#define SET_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ ++ do { \ ++ if ((_ucBit) < ((_ucFieldLength) * 8)) { \ ++ PUINT_8 aucExtCap = (PUINT_8)(_aucField); \ ++ ((aucExtCap)[(_ucBit) / 8]) |= BIT((_ucBit) % 8); \ ++ } \ ++ } while (FALSE) ++ ++#define TEST_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ ++ ((((_ucFieldLength) * 8) > (_ucBit)) && (((_aucField)[(_ucBit) / 8]) & BIT((_ucBit) % 8))) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MAC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h +new file mode 100644 +index 000000000000..583923aed010 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h +@@ -0,0 +1,272 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/nic/mtreg.h#2 ++*/ ++ ++/*! \file "mtreg.h" ++ \brief The common register definition of mt5931 ++ ++ N/A ++*/ ++ ++/* ++** Log: mtreg.h ++ * ++ * 01 28 2013 samp.lin ++ * [WCXRP00000851] [MT6582 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6582-specific definitions. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 07 13 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add initial version for MT6628 driver support. ++ * ++*/ ++ ++#ifndef _MTREG_H ++#define _MTREG_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* 1 MT6628 MCR Definition */ ++ ++/* 2 Host Interface */ ++ ++/* 4 CHIP ID Register */ ++#define MCR_WCIR 0x0000 ++ ++/* 4 HIF Low Power Control Register */ ++#define MCR_WHLPCR 0x0004 ++ ++/* 4 Control Status Register */ ++#define MCR_WSDIOCSR 0x0008 ++#define MCR_WSPICSR 0x0008 ++ ++/* 4 HIF Control Register */ ++#define MCR_WHCR 0x000C ++ ++/* 4 HIF Interrupt Status Register */ ++#define MCR_WHISR 0x0010 ++ ++/* 4 HIF Interrupt Enable Register */ ++#define MCR_WHIER 0x0014 ++ ++/* 4 Abnormal Status Register */ ++#define MCR_WASR 0x0018 ++ ++/* 4 WLAN Software Interrupt Control Register */ ++#define MCR_WSICR 0x001C ++ ++/* 4 WLAN TX Status Register */ ++#define MCR_WTSR0 0x0020 ++ ++/* 4 WLAN TX Status Register */ ++#define MCR_WTSR1 0x0024 ++ ++/* 4 WLAN TX Data Register 0 */ ++#define MCR_WTDR0 0x0028 ++ ++/* 4 WLAN TX Data Register 1 */ ++#define MCR_WTDR1 0x002C ++ ++/* 4 WLAN RX Data Register 0 */ ++#define MCR_WRDR0 0x0030 ++ ++/* 4 WLAN RX Data Register 1 */ ++#define MCR_WRDR1 0x0034 ++ ++/* 4 Host to Device Send Mailbox 0 Register */ ++#define MCR_H2DSM0R 0x0038 ++ ++/* 4 Host to Device Send Mailbox 1 Register */ ++#define MCR_H2DSM1R 0x003c ++ ++/* 4 Device to Host Receive Mailbox 0 Register */ ++#define MCR_D2HRM0R 0x0040 ++ ++/* 4 Device to Host Receive Mailbox 1 Register */ ++#define MCR_D2HRM1R 0x0044 ++ ++/* 4 Device to Host Receive Mailbox 2 Register */ ++#define MCR_D2HRM2R 0x0048 ++ ++/* 4 WLAN RX Packet Length Register */ ++#define MCR_WRPLR 0x0050 ++ ++/* 4 HSIF Transaction Count Register */ ++#define MCR_HSTCR 0x0058 ++ ++/* #if CFG_SDIO_INTR_ENHANCE */ ++typedef struct _ENHANCE_MODE_DATA_STRUCT_T { ++ UINT_32 u4WHISR; ++ union { ++ struct { ++ UINT_8 ucTQ0Cnt; ++ UINT_8 ucTQ1Cnt; ++ UINT_8 ucTQ2Cnt; ++ UINT_8 ucTQ3Cnt; ++ UINT_8 ucTQ4Cnt; ++ UINT_8 ucTQ5Cnt; ++ UINT_16 u2Rsrv; ++ } u; ++ UINT_32 au4WTSR[2]; ++ } rTxInfo; ++ union { ++ struct { ++ UINT_16 u2NumValidRx0Len; ++ UINT_16 u2NumValidRx1Len; ++ UINT_16 au2Rx0Len[16]; ++ UINT_16 au2Rx1Len[16]; ++ } u; ++ UINT_32 au4RxStatusRaw[17]; ++ } rRxInfo; ++ UINT_32 u4RcvMailbox0; ++ UINT_32 u4RcvMailbox1; ++} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; ++/* #endif */ /* ENHANCE_MODE_DATA_STRUCT_T */ ++ ++/* 2 Definition in each register */ ++/* 3 WCIR 0x0000 */ ++#define WCIR_WLAN_READY BIT(21) ++#define WCIR_POR_INDICATOR BIT(20) ++#define WCIR_REVISION_ID BITS(16, 19) ++#define WCIR_CHIP_ID BITS(0, 15) ++ ++#define MTK_CHIP_REV_72 0x00006572 ++#define MTK_CHIP_REV_82 0x00006582 ++#define MTK_CHIP_REV_92 0x00006592 ++#define MTK_CHIP_MP_REVERSION_ID 0x0 ++ ++/* 3 WHLPCR 0x0004 */ ++#define WHLPCR_FW_OWN_REQ_CLR BIT(9) ++#define WHLPCR_FW_OWN_REQ_SET BIT(8) ++#define WHLPCR_IS_DRIVER_OWN BIT(8) ++#define WHLPCR_INT_EN_CLR BIT(1) ++#define WHLPCR_INT_EN_SET BIT(0) ++ ++/* 3 WSDIOCSR 0x0008 */ ++#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) ++ ++/* 3 WSPICSR 0x0008 */ ++#define WCSR_SPI_MODE_SEL BITS(3, 4) ++#define WCSR_SPI_ENDIAN_BIG BIT(2) ++#define WCSR_SPI_INT_OUT_MODE BIT(1) ++#define WCSR_SPI_DATA_OUT_MODE BIT(0) ++ ++/* 3 WHCR 0x000C */ ++#define WHCR_RX_ENHANCE_MODE_EN BIT(16) ++#define WHCR_MAX_HIF_RX_LEN_NUM BITS(4, 7) ++#define WHCR_W_MAILBOX_RD_CLR_EN BIT(2) ++#define WHCR_W_INT_CLR_CTRL BIT(1) ++#define WHCR_MCU_DBG_EN BIT(0) ++#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 4 ++ ++/* 3 WHISR 0x0010 */ ++#define WHISR_D2H_SW_INT BITS(8, 31) ++#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) ++#define WHISR_FW_OWN_BACK_INT BIT(4) ++#define WHISR_ABNORMAL_INT BIT(3) ++#define WHISR_RX1_DONE_INT BIT(2) ++#define WHISR_RX0_DONE_INT BIT(1) ++#define WHISR_TX_DONE_INT BIT(0) ++ ++/* 3 WHIER 0x0014 */ ++#define WHIER_D2H_SW_INT BITS(8, 31) ++#define WHIER_FW_OWN_BACK_INT_EN BIT(4) ++#define WHIER_ABNORMAL_INT_EN BIT(3) ++#define WHIER_RX1_DONE_INT_EN BIT(2) ++#define WHIER_RX0_DONE_INT_EN BIT(1) ++#define WHIER_TX_DONE_INT_EN BIT(0) ++#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ ++ WHIER_RX1_DONE_INT_EN | \ ++ WHIER_TX_DONE_INT_EN | \ ++ WHIER_ABNORMAL_INT_EN | \ ++ WHIER_D2H_SW_INT \ ++ ) ++ ++/* 3 WASR 0x0018 */ ++#define WASR_FW_OWN_INVALID_ACCESS BIT(4) ++#define WASR_RX1_UNDER_FLOW BIT(3) ++#define WASR_RX0_UNDER_FLOW BIT(2) ++#define WASR_TX1_OVER_FLOW BIT(1) ++#define WASR_TX0_OVER_FLOW BIT(0) ++ ++/* 3 WSICR 0x001C */ ++#define WSICR_H2D_SW_INT_SET BITS(16, 31) ++ ++/* 3 WRPLR 0x0050 */ ++#define WRPLR_RX1_PACKET_LENGTH BITS(16, 31) ++#define WRPLR_RX0_PACKET_LENGTH BITS(0, 15) ++ ++/* 3 HSTCR 0x0058 */ ++#define HSTCR_AFF_BURST_LEN BITS(24, 25) ++#define HSTCR_AFF_BURST_LEN_OFFSET 24 ++#define HSTCR_TRANS_TARGET BITS(20, 22) ++#define HSTCR_TRANS_TARGET_OFFSET 20 ++#define HSTCR_HSIF_TRANS_CNT BITS(2, 19) ++#define HSTCR_HSIF_TRANS_CNT_OFFSET 2 ++ ++/* HSTCR_TRANS_TARGET */ ++typedef enum _eTransTarget { ++ TRANS_TARGET_TXD0 = 0, ++ TRANS_TARGET_TXD1, ++ TRANS_TARGET_RXD0, ++ TRANS_TARGET_RXD1, ++ TRANS_TARGET_WHISR, ++ NUM_TRANS_TARGET ++} E_TRANS_TARGET_T; ++ ++typedef enum _E_AFF_BURST_LEN { ++ BURST_1_DW = 0, ++ BURST_4_DW, ++ BURST_8_DW, ++ BURST_RSV, ++ NUM_AFF_BURST_LEN ++} E_AFF_BURST_LEN; ++ ++#endif /* _MTREG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h +new file mode 100644 +index 000000000000..c059b707aee8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h +@@ -0,0 +1,498 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic.h#1 ++*/ ++ ++/*! \file "nic.h" ++ \brief The declaration of nic functions ++ ++ Detail description. ++*/ ++ ++/* ++** Log: nic.h ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS ++ * cannot do the 4-way handshake to connect to the AP.. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right ++ * after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test ++ * with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always process TX interrupt first then RX interrupt. ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-10-13 21:58:58 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-24 21:12:55 GMT mtk01104 ++** Add function prototype nicRestoreSpiDefMode() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:54 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:32 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_H ++#define _NIC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++struct _REG_ENTRY_T { ++ UINT_32 u4Offset; ++ UINT_32 u4Value; ++}; ++ ++struct _TABLE_ENTRY_T { ++ P_REG_ENTRY_T pu4TablePtr; ++ UINT_16 u2Size; ++}; ++ ++/*! INT status to event map */ ++typedef struct _INT_EVENT_MAP_T { ++ UINT_32 u4Int; ++ UINT_32 u4Event; ++} INT_EVENT_MAP_T, *P_INT_EVENT_MAP_T; ++ ++enum ENUM_INT_EVENT_T { ++ INT_EVENT_ABNORMAL, ++ INT_EVENT_SW_INT, ++ INT_EVENT_TX, ++ INT_EVENT_RX, ++ INT_EVENT_NUM ++}; ++ ++typedef enum _ENUM_IE_UPD_METHOD_T { ++ IE_UPD_METHOD_UPDATE_RANDOM, ++ IE_UPD_METHOD_UPDATE_ALL, ++ IE_UPD_METHOD_DELETE_ALL, ++} ENUM_IE_UPD_METHOD_T, *P_ENUM_IE_UPD_METHOD_T; ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern BOOLEAN fgIsResetting; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in nic.c */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter); ++ ++VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter); ++ ++VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus); ++ ++WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter); ++ ++VOID nicMCRInit(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_SDIO_INTR_ENHANCE ++VOID nicSDIOInit(IN P_ADAPTER_T prAdapter); ++ ++VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus); ++#endif ++ ++BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter); ++ ++VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt); ++ ++BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter); ++ ++#if defined(_HIF_SPI) ++void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data); ++ ++VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data); ++ ++VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap); ++ ++P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); ++ ++P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); ++ ++P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx); ++ ++VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter); ++ ++UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter); ++ ++/* Media State Change */ ++WLAN_STATUS ++nicMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); ++ ++/* Utility function for channel number conversion */ ++UINT_32 nicChannelNum2Freq(IN UINT_32 u4ChannelNum); ++ ++UINT_32 nicFreq2ChannelNum(IN UINT_32 u4FreqInKHz); ++ ++/* firmware command wrapper */ ++ /* NETWORK (WIFISYS) */ ++WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* BSS-INFO */ ++WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* BSS-INFO Indication (PM) */ ++WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* Beacon Template Update */ ++WLAN_STATUS ++nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, ++ IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen); ++ ++WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam); ++ ++/*----------------------------------------------------------------------------*/ ++/* Calibration Control */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam); ++ ++WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset); ++ ++WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult); ++ ++/*----------------------------------------------------------------------------*/ ++/* PHY configuration */ ++/*----------------------------------------------------------------------------*/ ++VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* MGMT and System Service Control */ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicResetSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent); ++ ++WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent); ++/*----------------------------------------------------------------------------*/ ++/* Scan Result Processing */ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicAddScanResult(IN P_ADAPTER_T prAdapter, ++ IN PARAM_MAC_ADDRESS rMacAddr, ++ IN P_PARAM_SSID_T prSsid, ++ IN UINT_32 u4Privacy, ++ IN PARAM_RSSI rRssi, ++ IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, ++ IN P_PARAM_802_11_CONFIG_T prConfiguration, ++ IN ENUM_PARAM_OP_MODE_T eOpMode, ++ IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf); ++ ++VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++/*----------------------------------------------------------------------------*/ ++/* Workaround Control */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Fixed Rate Hacking */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateRateParams(IN P_ADAPTER_T prAdapter, ++ IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, ++ IN PUINT_8 pucDesiredPhyTypeSet, ++ IN PUINT_16 pu2DesiredNonHTRateSet, ++ IN PUINT_16 pu2BSSBasicRateSet, ++ IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 u2HtCapInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Write registers */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value); ++ ++/*----------------------------------------------------------------------------*/ ++/* Update auto rate */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4ArSysParam0, ++ IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3); ++ ++/*----------------------------------------------------------------------------*/ ++/* Enable/Disable Roaming */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming); ++ ++VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Link Quality Updating */ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality); ++ ++VOID ++nicUpdateRSSI(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); ++ ++VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam); ++#endif ++ ++#endif /* _NIC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h +new file mode 100644 +index 000000000000..86e2c84b07ff +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h +@@ -0,0 +1,420 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_rx.h#1 ++*/ ++ ++/*! \file "nic_rx.h" ++ \brief The declaration of the nic rx functions ++ ++*/ ++ ++/* ++** Log: nic_rx.h ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode ++ * and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Change prototype of API of adding P2P device to scan result. ++ * Additional IE buffer is saved. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify data structure for P2P Scan result. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * newly added P2P API should be declared in header file. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * 4) nicRxWaitResponse() revised ++ * * 5) another set of TQ counter default value is added for fw-download state ++ * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * and result is retrieved by get ATInfo instead ++ * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:49:09 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 14:02:37 GMT MTK02468 ++** Added ucStaRecIdx in SW_RFB_T and HALF_SEQ_NO_COUNT definition (to replace HALF_SEQ_NO_CNOUT) ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-27 11:07:54 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 18:18:09 GMT mtk02752 ++** modify nicRxAddScanResult() ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-24 22:42:22 GMT mtk02752 ++** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-24 19:57:06 GMT mtk02752 ++** adopt P_HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 21:43:04 GMT mtk02752 ++** correct ENUM_RX_PKT_DESTINATION_T definitions ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 15:28:25 GMT mtk02752 ++** add ucQueuedPacketNum for indicating how many packet are queued by RX reordering buffer/forwarding path ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 15:05:01 GMT mtk02752 ++** add eTC for SW_RFB_T and structure RX_MAILBOX ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 21:16:57 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-13 16:59:30 GMT mtk02752 ++** add handler for event packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-13 13:45:50 GMT mtk02752 ++** add port param for nicRxEnhanceReadBuffer() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-11 10:12:31 GMT mtk02752 ++** nicSDIOReadIntStatus() always read sizeof(ENHANCE_MODE_DATA_STRUCT_T) for int response, ++** thus the number should be set to 0(:=16) instead of 10 ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-29 19:53:32 GMT mtk01084 ++** modify structure naming ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-23 16:08:23 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:01 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-20 12:23:33 GMT mtk01461 ++** Add u4MaxEventBufferLen parameter to nicRxWaitResponse() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-18 21:00:48 GMT mtk01426 ++** Update SDIO_MAXIMUM_RX_STATUS value ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:36:15 GMT mtk01461 ++** Remove unused define - SDIO_MAXIMUM_TX_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:17 GMT mtk01461 ++** Add function for HIF_LOOPBACK_PRE_TEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:56:19 GMT mtk01426 ++** Add to support CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:19:56 GMT mtk01426 ++** Add nicRxWaitResponse function proto type ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:35 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_RX_H ++#define _NIC_RX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern P_SW_RFB_T g_arGscnResultsTempBuffer[]; ++extern UINT_8 g_GscanResultsTempBufferIndex; ++extern UINT_8 g_arGscanResultsIndicateNumber[]; ++extern UINT_8 g_GetResultsBufferedCnt; ++extern UINT_8 g_GetResultsCmdCnt; ++extern void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_SEQ_NO 4095 ++#define MAX_SEQ_NO_COUNT 4096 ++#define HALF_SEQ_NO_CNOUT 2048 ++ ++#define HALF_SEQ_NO_COUNT 2048 ++ ++#define MT6620_FIXED_WIN_SIZE 64 ++#define CFG_RX_MAX_BA_ENTRY 4 ++#define CFG_RX_MAX_BA_TID_NUM 8 ++ ++#define RX_STATUS_FLAG_MORE_PACKET BIT(30) ++#define RX_STATUS_CHKSUM_MASK BITS(0, 10) ++ ++#define RX_RFB_LEN_FIELD_LEN 4 ++#define RX_HEADER_OFFSET 2 ++ ++#define RX_RETURN_INDICATED_RFB_TIMEOUT_SEC 3 ++ ++#if defined(_HIF_SDIO) && defined(WINDOWS_DDK) ++/*! On XP, maximum Tx+Rx Statue <= 64-4(HISR)*/ ++#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ ++#else ++#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_RX_STATISTIC_COUNTER_T { ++ RX_MPDU_TOTAL_COUNT = 0, ++ RX_SIZE_ERR_DROP_COUNT, ++ ++ RX_DATA_INDICATION_COUNT, ++ RX_DATA_RETURNED_COUNT, ++ RX_DATA_RETAINED_COUNT, ++ ++ RX_DROP_TOTAL_COUNT, ++ RX_TYPE_ERR_DROP_COUNT, ++ RX_CLASS_ERR_DROP_COUNT, ++ RX_DST_NULL_DROP_COUNT, ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ RX_CSUM_TCP_FAILED_COUNT, ++ RX_CSUM_UDP_FAILED_COUNT, ++ RX_CSUM_IP_FAILED_COUNT, ++ RX_CSUM_TCP_SUCCESS_COUNT, ++ RX_CSUM_UDP_SUCCESS_COUNT, ++ RX_CSUM_IP_SUCCESS_COUNT, ++ RX_CSUM_UNKNOWN_L4_PKT_COUNT, ++ RX_CSUM_UNKNOWN_L3_PKT_COUNT, ++ RX_IP_V6_PKT_CCOUNT, ++#endif ++ RX_STATISTIC_COUNTER_NUM ++} ENUM_RX_STATISTIC_COUNTER_T; ++ ++typedef enum _ENUM_RX_PKT_DESTINATION_T { ++ RX_PKT_DESTINATION_HOST, /* to OS */ ++ RX_PKT_DESTINATION_FORWARD, /* to TX queue for forward, AP mode */ ++ RX_PKT_DESTINATION_HOST_WITH_FORWARD, /* to both TX and OS, AP mode broadcast packet */ ++ RX_PKT_DESTINATION_NULL, /* packet to be freed */ ++ RX_PKT_DESTINATION_NUM ++} ENUM_RX_PKT_DESTINATION_T; ++ ++struct _SW_RFB_T { ++ QUE_ENTRY_T rQueEntry; ++ PVOID pvPacket; /*!< ptr to rx Packet Descriptor */ ++ PUINT_8 pucRecvBuff; /*!< ptr to receive data buffer */ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4HifRxHdrFlag; ++ PVOID pvHeader; ++ UINT_16 u2PacketLen; ++ UINT_16 u2HeaderLen; ++ UINT_16 u2SSN; ++ UINT_8 ucTid; ++ UINT_8 ucWlanIdx; ++ UINT_8 ucPacketType; ++ UINT_8 ucStaRecIdx; ++ ++ ENUM_CSUM_RESULT_T aeCSUM[CSUM_TYPE_NUM]; ++ ENUM_RX_PKT_DESTINATION_T eDst; ++ ENUM_TRAFFIC_CLASS_INDEX_T eTC; /* only valid when eDst == FORWARD */ ++ ++ UINT_64 rRxTime; ++}; ++ ++/*! RX configuration type structure */ ++typedef struct _RX_CTRL_T { ++ UINT_32 u4RxCachedSize; ++ PUINT_8 pucRxCached; ++ QUE_T rFreeSwRfbList; ++ QUE_T rReceivedRfbList; ++ QUE_T rIndicatedRfbList; ++ ++#if CFG_SDIO_RX_AGG ++ PUINT_8 pucRxCoalescingBufPtr; ++#endif ++ ++ PVOID apvIndPacket[CFG_RX_MAX_PKT_NUM]; ++ PVOID apvRetainedPacket[CFG_RX_MAX_PKT_NUM]; ++ ++ UINT_8 ucNumIndPacket; ++ UINT_8 ucNumRetainedPacket; ++ UINT_64 au8Statistics[RX_STATISTIC_COUNTER_NUM]; /*!< RX Counters */ ++ ++#if CFG_HIF_STATISTICS ++ UINT_32 u4TotalRxAccessNum; ++ UINT_32 u4TotalRxPacketNum; ++#endif ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ UINT_32 u4QueuedCnt; ++ UINT_32 u4DequeuedCnt; ++#endif ++ ++#if CFG_RX_PKTS_DUMP ++ UINT_32 u4RxPktsDumpTypeMask; ++#endif ++ ++} RX_CTRL_T, *P_RX_CTRL_T; ++ ++typedef struct _RX_MAILBOX_T { ++ UINT_32 u4RxMailbox[2]; /* for Device-to-Host Mailbox */ ++} RX_MAILBOX_T, *P_RX_MAILBOX_T; ++ ++typedef WLAN_STATUS(*PROCESS_RX_MGT_FUNCTION) (P_ADAPTER_T, P_SW_RFB_T); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define RX_INC_CNT(prRxCtrl, eCounter) \ ++ {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]++; } ++ ++#define RX_ADD_CNT(prRxCtrl, eCounter, u8Amount) \ ++ {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] += (UINT_64)u8Amount; } ++ ++#define RX_GET_CNT(prRxCtrl, eCounter) \ ++ (((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]) ++ ++#define RX_RESET_ALL_CNTS(prRxCtrl) \ ++ {kalMemZero(&prRxCtrl->au8Statistics[0], sizeof(prRxCtrl->au8Statistics)); } ++ ++#define RX_STATUS_TEST_MORE_FLAG(flag) \ ++ ((BOOLEAN)((flag & RX_STATUS_FLAG_MORE_PACKET) ? TRUE : FALSE)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID nicRxInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter); ++ ++#if !CFG_SDIO_INTR_ENHANCE ++VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++#else ++VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++#if CFG_SDIO_RX_AGG ++VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter); ++#endif ++ ++WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); ++ ++VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); ++ ++VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus); ++ ++VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); ++ ++VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); ++ ++WLAN_STATUS ++nicRxWaitResponse(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length); ++ ++VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#endif /* _NIC_RX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h +new file mode 100644 +index 000000000000..e516468fcb16 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h +@@ -0,0 +1,642 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_tx.h#1 ++*/ ++ ++/*! \file nic_tx.h ++ \brief Functions that provide TX operation in NIC's point of view. ++ ++ This file provides TX functions which are responsible for both Hardware and ++ Software Resource Management and keep their Synchronization. ++ ++*/ ++ ++/* ++** Log: nic_tx.h ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add log counter for tx ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add TX_DONE status detail information. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing ++ * frame dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 02 16 2011 cp.wu ++ * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking ++ * available count and modify behavior ++ * 1. add new API: nicTxGetFreeCmdCount() ++ * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 12 15 2010 yuche.tsai ++ * NULL ++ * Update SLT Descriptor number configure in driver. ++ * ++ * 11 16 2010 yarco.yang ++ * [WCXRP00000177] [MT5931 F/W] Performance tuning for 1st connection ++ * Update TX buffer count ++ * ++ * 11 03 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) use 8 buffers for MT5931 which is equipped with less memory ++ * 2) modify MT5931 debug level to TRACE when download is successful ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 07 26 2010 cp.wu ++ * ++ * change TC4 initial value from 2 to 4. ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under ++ * concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add MGMT Packet type for HIF_TX_HEADER ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate ++ * 2) add packet type for indicating management frames ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add TX_PACKET_MGMT to indicate the frame is coming from management modules ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 02 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Redistributed the initial TC resources for normal operation ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * 4) nicRxWaitResponse() revised ++ * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * 4. correct some HAL implementation ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * and result is retrieved by get ATInfo instead ++ * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:53:28 GMT mtk02752 ++** remove unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-27 11:08:00 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-24 19:56:49 GMT mtk02752 ++** remove redundant eTC ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 22:01:08 GMT mtk02468 ++** Added MSDU_INFO fields for composing HIF TX header ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:51 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:35:05 GMT mtk02752 ++** + nicTxMsduInfoList() for sending MsduInfoList ++** + NIC_TX_BUFF_COUNT_TC[0~5] ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-17 11:07:00 GMT mtk02752 ++** add nicTxAdjustTcq() API ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 22:28:30 GMT mtk02752 ++** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 21:44:50 GMT mtk02752 ++** + nicTxReturnMsduInfo() ++** + nicTxFillMsduInfo() ++** + rFreeMsduInfoList field in TX_CTRL ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-16 18:00:43 GMT mtk02752 ++** use P_PACKET_INFO_T for prPacket to avoid inventing another new structure for packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-16 15:28:49 GMT mtk02752 ++** add ucQueuedPacketNum for indicating how many packets are queued by per STA/AC queue ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-16 10:52:01 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-14 23:39:24 GMT mtk02752 ++** interface structure redefine ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-13 21:17:03 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-29 19:53:10 GMT mtk01084 ++** remove strange code by Frog ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:04 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-02 13:53:03 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:36:50 GMT mtk01461 ++** Add declaration of nicTxReleaseResource() ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:58:39 GMT mtk01461 ++** Move CMD_INFO_T related define and function to cmd_buf.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:53 GMT mtk01461 ++** Add function for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:33:27 GMT mtk01461 ++** Define constants for TX PATH and add nicTxPollingResource ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:32 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:38 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_TX_H ++#define _NIC_TX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define NIC_TX_RESOURCE_POLLING_TIMEOUT 256 ++#define NIC_TX_RESOURCE_POLLING_DELAY_MSEC 50 ++ ++/* Maximum buffer count for individual HIF TCQ */ ++ ++#if defined(MT6620) ++#if CFG_SLT_SUPPORT ++ /* 20101215 mtk01725 Redistributed the initial TC resources for SLT operation */ ++#define NIC_TX_BUFF_COUNT_TC0 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 16 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 0 /* First connection: 0 */ ++#else ++ /* 20100302 mtk02468 Redistributed the initial TC resources for normal operation */ ++#define NIC_TX_BUFF_COUNT_TC0 6 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 8 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 8 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 8 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 2 /* First connection: 0 */ ++#endif ++#elif defined(MT6628) ++#if (CFG_SRAM_SIZE_OPTION == 0) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 20 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#elif (CFG_SRAM_SIZE_OPTION == 1) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 36 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#elif (CFG_SRAM_SIZE_OPTION == 2) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 48 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#else ++#error "> Set TX_BUFF_COUNT_TC error!" ++#endif ++#endif ++ ++#define NIC_TX_BUFF_SUM (NIC_TX_BUFF_COUNT_TC0 + \ ++ NIC_TX_BUFF_COUNT_TC1 + \ ++ NIC_TX_BUFF_COUNT_TC2 + \ ++ NIC_TX_BUFF_COUNT_TC3 + \ ++ NIC_TX_BUFF_COUNT_TC4 + \ ++ NIC_TX_BUFF_COUNT_TC5) ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++#define NIC_TX_INIT_BUFF_COUNT_TC0 8 ++#define NIC_TX_INIT_BUFF_COUNT_TC1 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC2 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC3 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC4 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC5 0 ++ ++#define NIC_TX_INIT_BUFF_SUM (NIC_TX_INIT_BUFF_COUNT_TC0 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC1 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC2 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC3 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC4 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC5) ++ ++#endif ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#define NIC_TX_TIME_THRESHOLD 100 /* in unit of ms */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* 3 Session for TX QUEUES */ ++/* The definition in this ENUM is used to categorize packet's Traffic Class according ++ * to the their TID(User Priority). ++ * In order to achieve QoS goal, a particular TC should not block the process of ++ * another packet with different TC. ++ * In current design we will have 5 categories(TCs) of SW resource. ++ */ ++typedef enum _ENUM_TRAFFIC_CLASS_INDEX_T { ++ TC0_INDEX = 0, /* HIF TX0: AC0 packets */ ++ TC1_INDEX, /* HIF TX0: AC1 packets & non-QoS packets */ ++ TC2_INDEX, /* HIF TX0: AC2 packets */ ++ TC3_INDEX, /* HIF TX0: AC3 packets */ ++ TC4_INDEX, /* HIF TX1: Command packets or 802.1x packets */ ++ TC5_INDEX, /* HIF TX0: BMCAST packets */ ++ TC_NUM /* Maximum number of Traffic Classes. */ ++} ENUM_TRAFFIC_CLASS_INDEX_T; ++ ++typedef enum _ENUM_TX_STATISTIC_COUNTER_T { ++ TX_MPDU_TOTAL_COUNT = 0, ++ TX_INACTIVE_BSS_DROP, ++ TX_INACTIVE_STA_DROP, ++ TX_FORWARD_OVERFLOW_DROP, ++ TX_AP_BORADCAST_DROP, ++ TX_STATISTIC_COUNTER_NUM ++} ENUM_TX_STATISTIC_COUNTER_T; ++ ++typedef struct _TX_TCQ_STATUS_T { ++ UINT_8 aucFreeBufferCount[TC_NUM]; ++ UINT_8 aucMaxNumOfBuffer[TC_NUM]; ++} TX_TCQ_STATUS_T, *P_TX_TCQ_STATUS_T; ++ ++typedef struct _TX_TCQ_ADJUST_T { ++ INT_8 acVariation[TC_NUM]; ++} TX_TCQ_ADJUST_T, *P_TX_TCQ_ADJUST_T; ++ ++typedef struct _TX_CTRL_T { ++ UINT_32 u4TxCachedSize; ++ PUINT_8 pucTxCached; ++ ++/* Elements below is classified according to TC (Traffic Class) value. */ ++ ++ TX_TCQ_STATUS_T rTc; ++ ++ PUINT_8 pucTxCoalescingBufPtr; ++ ++ QUE_T rFreeMsduInfoList; ++ ++ /* Management Frame Tracking */ ++ /* number of management frames to be sent */ ++ INT_32 i4TxMgmtPendingNum; ++ ++ /* to tracking management frames need TX done callback */ ++ QUE_T rTxMgmtTxingQueue; ++ ++#if CFG_HIF_STATISTICS ++ UINT_32 u4TotalTxAccessNum; ++ UINT_32 u4TotalTxPacketNum; ++#endif ++ UINT_32 au4Statistics[TX_STATISTIC_COUNTER_NUM]; ++ ++ /* Number to track forwarding frames */ ++ INT_32 i4PendingFwdFrameCount; ++ ++} TX_CTRL_T, *P_TX_CTRL_T; ++ ++typedef enum _ENUM_TX_PACKET_SRC_T { ++ TX_PACKET_OS, ++ TX_PACKET_OS_OID, ++ TX_PACKET_FORWARDING, ++ TX_PACKET_MGMT, ++ TX_PACKET_NUM ++} ENUM_TX_PACKET_SRC_T; ++ ++typedef enum _ENUM_HIF_TX_PACKET_TYPE_T { ++ HIF_TX_PACKET_TYPE_DATA = 0, ++ HIF_TX_PACKET_TYPE_COMMAND, ++ HIF_TX_PACKET_TYPE_HIF_LB, ++ HIF_TX_PACKET_TYPE_MGMT ++} ENUM_HIF_TX_PACKET_TYPE_T, *P_ENUM_HIF_TX_PACKET_TYPE_T; ++ ++typedef enum _ENUM_TX_RESULT_CODE_T { ++ TX_RESULT_SUCCESS = 0, ++ TX_RESULT_LIFE_TIMEOUT, ++ TX_RESULT_RTS_ERROR, ++ TX_RESULT_MPDU_ERROR, ++ TX_RESULT_AGING_TIMEOUT, ++ TX_RESULT_FLUSHED, ++ TX_RESULT_DROPPED_IN_DRIVER = 32, ++ TX_RESULT_NUM ++} ENUM_TX_RESULT_CODE_T, *P_ENUM_TX_RESULT_CODE_T; ++ ++struct _WLAN_CFG_ENTRY_T { ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ WLAN_CFG_SET_CB pfSetCb; ++ PVOID pPrivate; ++ UINT_32 u4Flags; ++}; ++ ++struct _WLAN_CFG_T { ++ UINT_32 u4WlanCfgEntryNumMax; ++ UINT_32 u4WlanCfgKeyLenMax; ++ UINT_32 u4WlanCfgValueLenMax; ++ WLAN_CFG_ENTRY_T arWlanCfgBuf[WLAN_CFG_ENTRY_NUM_MAX]; ++}; ++ ++/* TX Call Back Function */ ++typedef WLAN_STATUS(*PFN_TX_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++typedef struct _PKT_PROFILE_T { ++ BOOLEAN fgIsValid; ++#if CFG_PRINT_RTP_PROFILE ++ BOOLEAN fgIsPrinted; ++ UINT_16 u2IpSn; ++ UINT_16 u2RtpSn; ++ UINT_8 ucTcxFreeCount; ++#endif ++ OS_SYSTIME rHardXmitArrivalTimestamp; ++ OS_SYSTIME rEnqueueTimestamp; ++ OS_SYSTIME rDequeueTimestamp; ++ OS_SYSTIME rHifTxDoneTimestamp; ++} PKT_PROFILE_T, *P_PKT_PROFILE_T; ++#endif ++ ++/* TX transactions could be divided into 4 kinds: ++ * ++ * 1) 802.1X / Bluetooth-over-Wi-Fi Security Frames ++ * [CMD_INFO_T] - [prPacket] - in skb or NDIS_PACKET form ++ * ++ * 2) MMPDU ++ * [CMD_INFO_T] - [prPacket] - [MSDU_INFO_T] - [prPacket] - direct buffer for frame body ++ * ++ * 3) Command Packets ++ * [CMD_INFO_T] - [pucInfoBuffer] - direct buffer for content of command packet ++ * ++ * 4) Normal data frame ++ * [MSDU_INFO_T] - [prPacket] - in skb or NDIS_PACKET form ++ */ ++ ++/* PS_FORWARDING_TYPE_NON_PS means that the receiving STA is in Active Mode ++* from the perspective of host driver (maybe not synchronized with FW --> SN is needed) ++*/ ++ ++struct _MSDU_INFO_T { ++ QUE_ENTRY_T rQueEntry; ++ P_NATIVE_PACKET prPacket; ++ ++ ENUM_TX_PACKET_SRC_T eSrc; /* specify OS/FORWARD packet */ ++ UINT_8 ucUserPriority; ++ ++ /* For composing HIF TX header */ ++ UINT_8 ucTC; /* Traffic Class: 0~4 (HIF TX0), 5 (HIF TX1) */ ++ UINT_8 ucPacketType; /* 0: Data, 1: Command, 2: HIF Loopback 3: Management Frame */ ++ UINT_8 ucStaRecIndex; ++ UINT_8 ucNetworkType; /* See ENUM_NETWORK_TYPE_T */ ++ UINT_8 ucFormatID; /* 0: MAUI, Linux, Windows NDIS 5.1 */ ++ BOOLEAN fgIs802_1x; /* TRUE: 802.1x frame */ ++ BOOLEAN fgIs802_11; /* TRUE: 802.11 header is present */ ++ UINT_16 u2PalLLH; /* PAL Logical Link Header (for BOW network) */ ++ UINT_16 u2AclSN; /* ACL Sequence Number (for BOW network) */ ++ UINT_8 ucPsForwardingType; /* See ENUM_PS_FORWARDING_TYPE_T */ ++ UINT_8 ucPsSessionID; /* PS Session ID specified by the FW for the STA */ ++ BOOLEAN fgIsBurstEnd; /* TRUE means this is the last packet of the burst for (STA, TID) */ ++ BOOLEAN fgIsBIP; /* Management Frame Protection */ ++ BOOLEAN fgIsBasicRate; /* Force Basic Rate Transmission */ ++ ++ /* flattened from PACKET_INFO_T */ ++ UINT_8 ucMacHeaderLength; ++ UINT_8 ucLlcLength; /* w/o EtherType */ ++ UINT_16 u2FrameLength; ++ UINT_8 aucEthDestAddr[MAC_ADDR_LEN]; /* Ethernet Destination Address */ ++ ++ /* for TX done tracking */ ++ UINT_8 ucTxSeqNum; ++ PFN_TX_DONE_HANDLER pfTxDoneHandler; ++ BOOLEAN fgNeedTxDoneStatus; ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ PKT_PROFILE_T rPktProfile; ++#endif ++ COMMAND_TYPE eCmdType; ++ UINT_8 ucCID; ++ UINT_32 u4InqueTime; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define TX_INC_CNT(prTxCtrl, eCounter) \ ++ {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]++; } ++ ++#define TX_ADD_CNT(prTxCtrl, eCounter, u8Amount) \ ++ {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter] += (UINT_32)u8Amount; } ++ ++#define TX_GET_CNT(prTxCtrl, eCounter) \ ++ (((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]) ++ ++#define TX_RESET_ALL_CNTS(prTxCtrl) \ ++ {kalMemZero(&prTxCtrl->au4Statistics[0], sizeof(prTxCtrl->au4Statistics)); } ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#define PRINT_PKT_PROFILE(_pkt_profile, _note) \ ++{ \ ++ if (!(_pkt_profile)->fgIsPrinted) { \ ++ DBGLOG(TX, TRACE, "X[%u] E[%u] D[%u] HD[%u] B[%d] RTP[%d] %s\n", \ ++ (UINT_32)((_pkt_profile)->rHardXmitArrivalTimestamp), \ ++ (UINT_32)((_pkt_profile)->rEnqueueTimestamp), \ ++ (UINT_32)((_pkt_profile)->rDequeueTimestamp), \ ++ (UINT_32)((_pkt_profile)->rHifTxDoneTimestamp), \ ++ (UINT_8)((_pkt_profile)->ucTcxFreeCount), \ ++ (UINT_16)((_pkt_profile)->u2RtpSn), \ ++ (_note)); \ ++ (_pkt_profile)->fgIsPrinted = TRUE; \ ++ } \ ++} ++ ++#define CHK_PROFILES_DELTA(_pkt1, _pkt2, _delta) \ ++ (CHECK_FOR_TIMEOUT((_pkt1)->rHardXmitArrivalTimestamp, (_pkt2)->rHardXmitArrivalTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rEnqueueTimestamp, (_pkt2)->rEnqueueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rDequeueTimestamp, (_pkt2)->rDequeueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rHifTxDoneTimestamp, (_pkt2)->rHifTxDoneTimestamp, (_delta))) ++ ++#define CHK_PROFILE_DELTA(_pkt, _delta) \ ++ (CHECK_FOR_TIMEOUT((_pkt)->rEnqueueTimestamp, (_pkt)->rHardXmitArrivalTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt)->rDequeueTimestamp, (_pkt)->rEnqueueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt)->rHifTxDoneTimestamp, (_pkt)->rDequeueTimestamp, (_delta))) ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID nicTxInitialize(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt); ++ ++WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); ++ ++BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN UINT_8 *aucTxRlsCnt); ++ ++WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter); ++ ++UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); ++ ++WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue); ++ ++WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); ++ ++VOID nicTxRelease(IN P_ADAPTER_T prAdapter); ++ ++VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prNdisPacket); ++ ++WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); ++ ++WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter); ++#endif ++ ++WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_TX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h +new file mode 100644 +index 000000000000..d518aaf10eb5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h +@@ -0,0 +1,192 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p.h#3 ++*/ ++ ++/* ++** Log: p2p.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * p2p interface revised to be sync. with HAL ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add parameter to control: ++ * 1) auto group owner ++ * 2) P2P-PS parameter (CTWindow, NoA descriptors) ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * correct WPS Device Password ID definition. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * ++*/ ++ ++#ifndef _P2P_H ++#define _P2P_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* refer to 'Config Methods' in WPS */ ++#define WPS_CONFIG_USBA 0x0001 ++#define WPS_CONFIG_ETHERNET 0x0002 ++#define WPS_CONFIG_LABEL 0x0004 ++#define WPS_CONFIG_DISPLAY 0x0008 ++#define WPS_CONFIG_EXT_NFC 0x0010 ++#define WPS_CONFIG_INT_NFC 0x0020 ++#define WPS_CONFIG_NFC 0x0040 ++#define WPS_CONFIG_PBC 0x0080 ++#define WPS_CONFIG_KEYPAD 0x0100 ++ ++/* refer to 'Device Password ID' in WPS */ ++#define WPS_DEV_PASSWORD_ID_PIN 0x0000 ++#define WPS_DEV_PASSWORD_ID_USER 0x0001 ++#define WPS_DEV_PASSWORD_ID_MACHINE 0x0002 ++#define WPS_DEV_PASSWORD_ID_REKEY 0x0003 ++#define WPS_DEV_PASSWORD_ID_PUSHBUTTON 0x0004 ++#define WPS_DEV_PASSWORD_ID_REGISTRAR 0x0005 ++ ++#define P2P_DEVICE_TYPE_NUM 2 ++#define P2P_DEVICE_NAME_LENGTH 32 ++#define P2P_NETWORK_NUM 8 ++#define P2P_MEMBER_NUM 8 ++ ++#define P2P_WILDCARD_SSID "DIRECT-" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++struct _P2P_INFO_T { ++ UINT_32 u4DeviceNum; ++ EVENT_P2P_DEV_DISCOVER_RESULT_T arP2pDiscoverResult[CFG_MAX_NUM_BSS_LIST]; ++ PUINT_8 pucCurrIePtr; ++ UINT_8 aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]; /* A common pool for IE of all scan results. */ ++}; ++ ++typedef enum { ++ ENUM_P2P_PEER_GROUP, ++ ENUM_P2P_PEER_DEVICE, ++ ENUM_P2P_PEER_NUM ++} ENUM_P2P_PEER_TYPE, *P_ENUM_P2P_PEER_TYPE; ++ ++typedef struct _P2P_DEVICE_INFO { ++ UINT_8 aucDevAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_8 aucIfAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucDevCapabilityBitmap; ++ INT_32 i4ConfigMethod; ++ UINT_8 aucPrimaryDeviceType[8]; ++ UINT_8 aucSecondaryDeviceType[8]; ++ UINT_8 aucDeviceName[P2P_DEVICE_NAME_LENGTH]; ++} P2P_DEVICE_INFO, *P_P2P_DEVICE_INFO; ++ ++typedef struct _P2P_GROUP_INFO { ++ PARAM_SSID_T rGroupID; ++ P2P_DEVICE_INFO rGroupOwnerInfo; ++ UINT_8 ucMemberNum; ++ P2P_DEVICE_INFO arMemberInfo[P2P_MEMBER_NUM]; ++} P2P_GROUP_INFO, *P_P2P_GROUP_INFO; ++ ++typedef struct _P2P_NETWORK_INFO { ++ ENUM_P2P_PEER_TYPE eNodeType; ++ ++ union { ++ P2P_GROUP_INFO rGroupInfo; ++ P2P_DEVICE_INFO rDeviceInfo; ++ } node; ++ ++} P2P_NETWORK_INFO, *P_P2P_NETWORK_INFO; ++ ++typedef struct _P2P_NETWORK_LIST { ++ UINT_8 ucNetworkNum; ++ P2P_NETWORK_INFO rP2PNetworkInfo[P2P_NETWORK_NUM]; ++} P2P_NETWORK_LIST, *P_P2P_NETWORK_LIST; ++ ++typedef struct _P2P_DISCONNECT_INFO { ++ UINT_8 ucRole; ++ UINT_8 ucRsv[3]; ++} P2P_DISCONNECT_INFO, *P_P2P_DISCONNECT_INFO; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_P2P_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h +new file mode 100644 +index 000000000000..7f7a92584c7c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h +@@ -0,0 +1,83 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "p2p_cmd_buf.h" ++ \brief In this file we define the structure for Command Packet. ++ ++ In this file we define the structure for Command Packet and the control unit ++ of MGMT Memory Pool. ++*/ ++ ++/* ++** Log: p2p_cmd_buf.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++*/ ++ ++#ifndef _P2P_CMD_BUF_H ++#define _P2P_CMD_BUF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Firmware Command Packer */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); ++ ++#endif /* _P2P_CMD_BUF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h +new file mode 100644 +index 000000000000..76115dabe1a1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h +@@ -0,0 +1,207 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_mac.h#2 ++*/ ++ ++/*! \file "p2p_mac.h" ++ \brief Brief description. ++ ++ Detail description. ++*/ ++ ++#ifndef _P2P_MAC_H ++#define _P2P_MAC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define ACTION_PUBLIC_WIFI_DIRECT 9 ++#define ACTION_GAS_INITIAL_REQUEST 10 ++#define ACTION_GAS_INITIAL_RESPONSE 11 ++#define ACTION_GAS_COMEBACK_REQUEST 12 ++#define ACTION_GAS_COMEBACK_RESPONSE 13 ++ ++/* P2P 4.2.8.1 - P2P Public Action Frame Type. */ ++#define P2P_PUBLIC_ACTION_GO_NEGO_REQ 0 ++#define P2P_PUBLIC_ACTION_GO_NEGO_RSP 1 ++#define P2P_PUBLIC_ACTION_GO_NEGO_CFM 2 ++#define P2P_PUBLIC_ACTION_INVITATION_REQ 3 ++#define P2P_PUBLIC_ACTION_INVITATION_RSP 4 ++#define P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ 5 ++#define P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP 6 ++#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ 7 ++#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP 8 ++ ++/* P2P 4.2.9.1 - P2P Action Frame Type */ ++#define P2P_ACTION_NOTICE_OF_ABSENCE 0 ++#define P2P_ACTION_P2P_PRESENCE_REQ 1 ++#define P2P_ACTION_P2P_PRESENCE_RSP 2 ++#define P2P_ACTION_GO_DISCOVER_REQ 3 ++ ++#define P2P_PUBLIC_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+8) ++#define P2P_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+7) ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/* P2P 4.2.8.2 P2P Public Action Frame Format */ ++typedef struct _P2P_PUBLIC_ACTION_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ ++ UINT_8 ucOuiType; /* 0x09 */ ++ UINT_8 ucOuiSubtype; /* GO Nego Req/Rsp/Cfm, P2P Invittion Req/Rsp, Device Discoverability Req/Rsp */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_8 aucInfoElem[1]; /* P2P IE, WSC IE. */ ++} __KAL_ATTRIB_PACKED__ P2P_PUBLIC_ACTION_FRAME_T, *P_P2P_PUBLIC_ACTION_FRAME_T; ++ ++/* P2P 4.2.9.1 - General Action Frame Format. */ ++typedef struct _P2P_ACTION_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Action Frame Body */ ++ UINT_8 ucCategory; /* 0x7F */ ++ UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ ++ UINT_8 ucOuiType; /* 0x09 */ ++ UINT_8 ucOuiSubtype; /* */ ++ UINT_8 ucDialogToken; ++ UINT_8 aucInfoElem[1]; ++} __KAL_ATTRIB_PACKED__ P2P_ACTION_FRAME_T, *P_P2P_ACTION_FRAME_T; ++ ++/* P2P C.1 GAS Public Action Initial Request Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T; ++ ++/* P2P C.2 GAS Public Action Initial Response Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_16 u2StatusCode; /* Initial Response. */ ++ UINT_16 u2ComebackDelay; /* Initial Response. *//* In unit of TU. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T; ++ ++/* P2P C.3-1 GAS Public Action Comeback Request Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T; ++ ++/* P2P C.3-2 GAS Public Action Comeback Response Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_16 u2StatusCode; /* Comeback Response. */ ++ UINT_8 ucFragmentID; /*Comeback Response. */ ++ UINT_16 u2ComebackDelay; /* Comeback Response. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T; ++ ++typedef struct _P2P_SD_VENDER_SPECIFIC_CONTENT_T { ++ /* Service Discovery Vendor-specific Content. */ ++ UINT_8 ucOuiSubtype; /* 0x09 */ ++ UINT_16 u2ServiceUpdateIndicator; ++ UINT_8 aucServiceTLV[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SD_VENDER_SPECIFIC_CONTENT_T, *P_P2P_SD_VENDER_SPECIFIC_CONTENT_T; ++ ++typedef struct _P2P_SERVICE_REQUEST_TLV_T { ++ UINT_16 u2Length; ++ UINT_8 ucServiceProtocolType; ++ UINT_8 ucServiceTransID; ++ UINT_8 aucQueryData[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SERVICE_REQUEST_TLV_T, *P_P2P_SERVICE_REQUEST_TLV_T; ++ ++typedef struct _P2P_SERVICE_RESPONSE_TLV_T { ++ UINT_16 u2Length; ++ UINT_8 ucServiceProtocolType; ++ UINT_8 ucServiceTransID; ++ UINT_8 ucStatusCode; ++ UINT_8 aucResponseData[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SERVICE_RESPONSE_TLV_T, *P_P2P_SERVICE_RESPONSE_TLV_T; ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h +new file mode 100644 +index 000000000000..0a87bd457a92 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h +@@ -0,0 +1,62 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic.h#1 ++*/ ++ ++/*! \file "p2p_nic.h" ++ \brief The declaration of nic functions ++ ++ Detail description. ++*/ ++ ++#ifndef _P2P_NIC_H ++#define _P2P_NIC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID ++nicP2pMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); ++ ++VOID ++nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, ++ IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h +new file mode 100644 +index 000000000000..cea77414ce35 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h +@@ -0,0 +1,70 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic_cmd_event.h#1 ++*/ ++ ++/*! \file p2p_nic_cmd_event.h ++ \brief ++*/ ++ ++#ifndef _P2P_NIC_CMD_EVENT_H ++#define _P2P_NIC_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++typedef struct _EVENT_P2P_DEV_DISCOVER_RESULT_T { ++/* UINT_8 aucCommunicateAddr[MAC_ADDR_LEN]; // Deprecated. */ ++ UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 ucDeviceCapabilityBitmap; ++ UINT_8 ucGroupCapabilityBitmap; ++ UINT_16 u2ConfigMethod; /* Configure Method. */ ++ P2P_DEVICE_TYPE_T rPriDevType; ++ UINT_8 ucSecDevTypeNum; ++ P2P_DEVICE_TYPE_T arSecDevType[2]; ++ UINT_16 u2NameLength; ++ UINT_8 aucName[32]; ++ PUINT_8 pucIeBuf; ++ UINT_16 u2IELength; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ /* TODO: Service Information or PasswordID valid? */ ++} EVENT_P2P_DEV_DISCOVER_RESULT_T, *P_EVENT_P2P_DEV_DISCOVER_RESULT_T; ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h +new file mode 100644 +index 000000000000..dbfb90d94ee4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h +@@ -0,0 +1,971 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/que_mgt.h#1 ++*/ ++ ++/*! \file "que_mgt.h" ++ \brief TX/RX queues management header file ++ ++ The main tasks of queue management include TC-based HIF TX flow control, ++ adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save ++ forwarding control, RX packet reordering, and RX BA agreement management. ++*/ ++ ++/* ++** Log: que_mgt.h ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 07 26 2011 eddie.chen ++ * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter ++ * API for query the RX reorder queued packets counter. ++ * ++ * 06 14 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Change the parameter for WMM pass. ++ * ++ * 05 31 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Fix the QM quota in MT5931. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW ++ * Fix wmm parameters in beacon for BOW. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) Check Bss if support QoS before adding WMMIE ++ * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 07 22 2010 george.huang ++ * ++ * Update fgIsQoS information in BSS INFO by CMD ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 yarco.yang ++ * ++ * [WPD00003849] ++ * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled adaptive TC resource control ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 19 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * By default enabling dynamic STA_REC activation and decactivation ++ * ++ * 03 17 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) ++ * ++ * 03 11 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed buffer leak when processing BAR frames ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled multi-STA TX path with fairness ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled dynamically activating and deactivating STA_RECs ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for dynamic activating and deactivating STA_RECs. ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:04:53 GMT MTK02468 ++** Added RX buffer reordering function prototypes ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-02 22:08:44 GMT MTK02468 ++** Added macro QM_INIT_STA_REC for initialize a STA_REC ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 21:58:43 GMT mtk02468 ++** Initial version ++** ++*/ ++ ++#ifndef _QUE_MGT_H ++#define _QUE_MGT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* Queue Manager Features */ ++/* 1: Indicate the last TX packet to the FW for each burst */ ++#define QM_BURST_END_INFO_ENABLED 1 ++/* 1: To fairly share TX resource among active STAs */ ++#define QM_FORWARDING_FAIRNESS 1 ++/* 1: To adaptively adjust resource for each TC */ ++#define QM_ADAPTIVE_TC_RESOURCE_CTRL 1 ++/* 1: To print TC resource adjustment results */ ++#define QM_PRINT_TC_RESOURCE_CTRL 0 ++/* 1: If pkt with SSN is missing, auto advance the RX reordering window */ ++#define QM_RX_WIN_SSN_AUTO_ADVANCING 1 ++/* 1: Indicate the packets falling behind to OS before the frame with SSN is received */ ++#define QM_RX_INIT_FALL_BEHIND_PASS 1 ++/* 1: Count times of TC resource empty happened */ ++#define QM_TC_RESOURCE_EMPTY_COUNTER 1 ++/* Parameters */ ++ ++/* ++ In TDLS or AP mode, peer maybe enter "sleep mode". ++ ++ If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, ++ we need to wait 60 * u4TimeToAdjustTcResource = 180 packets ++ u4TimeToAdjustTcResource = 3, ++ then we will adjust TC resouce for VI or VO. ++ ++ But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, ++ we will to wait about 12 seconds to collect 180 packets. ++ but the test time is only 20 seconds. ++*/ ++#define QM_INIT_TIME_TO_UPDATE_QUE_LEN 60 /* p: Update queue lengths when p TX packets are enqueued */ ++#define QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN 5 ++ ++#define QM_INIT_TIME_TO_ADJUST_TC_RSC 3 /* s: Adjust the TC resource every s updates of queue lengths */ ++#define QM_QUE_LEN_MOVING_AVE_FACTOR 3 /* Factor for Que Len averaging */ ++ ++#define QM_MIN_RESERVED_TC0_RESOURCE 1 ++#define QM_MIN_RESERVED_TC1_RESOURCE 1 ++#define QM_MIN_RESERVED_TC2_RESOURCE 1 ++#define QM_MIN_RESERVED_TC3_RESOURCE 1 ++#define QM_MIN_RESERVED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_MIN_RESERVED_TC5_RESOURCE 1 ++ ++#if defined(MT6620) ++ ++#define QM_GUARANTEED_TC0_RESOURCE 4 ++#define QM_GUARANTEED_TC1_RESOURCE 4 ++#define QM_GUARANTEED_TC2_RESOURCE 9 ++#define QM_GUARANTEED_TC3_RESOURCE 11 ++#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_GUARANTEED_TC5_RESOURCE 4 ++ ++#elif defined(MT6628) ++ ++#define QM_GUARANTEED_TC0_RESOURCE 4 ++#define QM_GUARANTEED_TC1_RESOURCE 4 ++#define QM_GUARANTEED_TC2_RESOURCE 6 ++#define QM_GUARANTEED_TC3_RESOURCE 6 ++#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_GUARANTEED_TC5_RESOURCE 4 ++ ++#else ++#error ++#endif ++ ++#define QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY 0 ++ ++#define QM_TOTAL_TC_RESOURCE (\ ++ NIC_TX_BUFF_COUNT_TC0 + NIC_TX_BUFF_COUNT_TC1 +\ ++ NIC_TX_BUFF_COUNT_TC2 + NIC_TX_BUFF_COUNT_TC3 +\ ++ NIC_TX_BUFF_COUNT_TC5) ++#define QM_AVERAGE_TC_RESOURCE 6 ++ ++/* Note: QM_INITIAL_RESIDUAL_TC_RESOURCE shall not be less than 0 */ ++/* for 6628: QM_TOTAL_TC_RESOURCE = 28, RESIDUAL = 4 4 6 6 2 4 = 26 */ ++#define QM_INITIAL_RESIDUAL_TC_RESOURCE (QM_TOTAL_TC_RESOURCE - \ ++ (QM_GUARANTEED_TC0_RESOURCE +\ ++ QM_GUARANTEED_TC1_RESOURCE +\ ++ QM_GUARANTEED_TC2_RESOURCE +\ ++ QM_GUARANTEED_TC3_RESOURCE +\ ++ QM_GUARANTEED_TC5_RESOURCE \ ++ )) ++ ++/* Hard-coded network type for Phase 3: NETWORK_TYPE_AIS/P2P/BOW */ ++#define QM_OPERATING_NETWORK_TYPE NETWORK_TYPE_AIS ++ ++#define QM_TEST_MODE 0 ++#define QM_TEST_TRIGGER_TX_COUNT 50 ++#define QM_TEST_STA_REC_DETERMINATION 0 ++#define QM_TEST_STA_REC_DEACTIVATION 0 ++#define QM_TEST_FAIR_FORWARDING 0 ++ ++#define QM_DEBUG_COUNTER 0 ++ ++/* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ ++/* Per-Type Queues: [0] BMCAST */ ++#define NUM_OF_PER_STA_TX_QUEUES 5 ++#define NUM_OF_PER_TYPE_TX_QUEUES 1 ++ ++/* These two constants are also used for FW to verify the STA_REC index */ ++#define STA_REC_INDEX_BMCAST 0xFF ++#define STA_REC_INDEX_NOT_FOUND 0xFE ++ ++/* TX Queue Index */ ++#define TX_QUEUE_INDEX_BMCAST 0 ++#define TX_QUEUE_INDEX_NO_STA_REC 0 ++#define TX_QUEUE_INDEX_AC0 0 ++#define TX_QUEUE_INDEX_AC1 1 ++#define TX_QUEUE_INDEX_AC2 2 ++#define TX_QUEUE_INDEX_AC3 3 ++#define TX_QUEUE_INDEX_802_1X 4 ++#define TX_QUEUE_INDEX_NON_QOS 1 ++ ++/* 1 WMM-related */ ++/* WMM FLAGS */ ++#define WMM_FLAG_SUPPORT_WMM BIT(0) ++#define WMM_FLAG_SUPPORT_WMMSA BIT(1) ++#define WMM_FLAG_AC_PARAM_PRESENT BIT(2) ++#define WMM_FLAG_SUPPORT_UAPSD BIT(3) ++ ++/* WMM Admission Control Mandatory FLAGS */ ++#define ACM_FLAG_ADM_NOT_REQUIRED 0 ++#define ACM_FLAG_ADM_GRANTED BIT(0) ++#define ACM_FLAG_ADM_REQUIRED BIT(1) ++ ++/* WMM Power Saving FLAGS */ ++#define AC_FLAG_TRIGGER_ENABLED BIT(1) ++#define AC_FLAG_DELIVERY_ENABLED BIT(2) ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MAX_LEN_WMM_INFO 7 ++ ++/* WMM-2.2.2 WMM Parameter Element */ ++#define ELEM_MAX_LEN_WMM_PARAM 24 ++ ++/* WMM-2.2.1 WMM QoS Info field */ ++#define WMM_QOS_INFO_PARAM_SET_CNT BITS(0, 3) /* Sent by AP */ ++#define WMM_QOS_INFO_UAPSD BIT(7) ++ ++#define WMM_QOS_INFO_VO_UAPSD BIT(0) /* Sent by non-AP STA */ ++#define WMM_QOS_INFO_VI_UAPSD BIT(1) ++#define WMM_QOS_INFO_BK_UAPSD BIT(2) ++#define WMM_QOS_INFO_BE_UAPSD BIT(3) ++#define WMM_QOS_INFO_MAX_SP_LEN_MASK BITS(5, 6) ++#define WMM_QOS_INFO_MAX_SP_ALL 0 ++#define WMM_QOS_INFO_MAX_SP_2 BIT(5) ++#define WMM_QOS_INFO_MAX_SP_4 BIT(6) ++#define WMM_QOS_INFO_MAX_SP_6 BITS(5, 6) ++ ++/* -- definitions for Max SP length field */ ++#define WMM_MAX_SP_LENGTH_ALL 0 ++#define WMM_MAX_SP_LENGTH_2 2 ++#define WMM_MAX_SP_LENGTH_4 4 ++#define WMM_MAX_SP_LENGTH_6 6 ++ ++/* WMM-2.2.2 WMM ACI/AIFSN field */ ++/* -- subfields in the ACI/AIFSN field */ ++#define WMM_ACIAIFSN_AIFSN BITS(0, 3) ++#define WMM_ACIAIFSN_ACM BIT(4) ++#define WMM_ACIAIFSN_ACI BITS(5, 6) ++#define WMM_ACIAIFSN_ACI_OFFSET 5 ++ ++/* -- definitions for ACI field */ ++#define WMM_ACI_AC_BE 0 ++#define WMM_ACI_AC_BK BIT(5) ++#define WMM_ACI_AC_VI BIT(6) ++#define WMM_ACI_AC_VO BITS(5, 6) ++ ++#define WMM_ACI(_AC) (_AC << WMM_ACIAIFSN_ACI_OFFSET) ++ ++/* -- definitions for ECWmin/ECWmax field */ ++#define WMM_ECW_WMIN_MASK BITS(0, 3) ++#define WMM_ECW_WMAX_MASK BITS(4, 7) ++#define WMM_ECW_WMAX_OFFSET 4 ++ ++#define TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME 0 /* Unit: 64 us */ ++ ++#define QM_RX_BA_ENTRY_MISS_TIMEOUT_MS (1000) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++enum { ++ QM_DBG_CNT_00 = 0, ++ QM_DBG_CNT_01, ++ QM_DBG_CNT_02, ++ QM_DBG_CNT_03, ++ QM_DBG_CNT_04, ++ QM_DBG_CNT_05, ++ QM_DBG_CNT_06, ++ QM_DBG_CNT_07, ++ QM_DBG_CNT_08, ++ QM_DBG_CNT_09, ++ QM_DBG_CNT_10, ++ QM_DBG_CNT_11, ++ QM_DBG_CNT_12, ++ QM_DBG_CNT_13, ++ QM_DBG_CNT_14, ++ QM_DBG_CNT_15, ++ QM_DBG_CNT_16, ++ QM_DBG_CNT_17, ++ QM_DBG_CNT_18, ++ QM_DBG_CNT_19, ++ QM_DBG_CNT_20, ++ QM_DBG_CNT_21, ++ QM_DBG_CNT_22, ++ QM_DBG_CNT_23, ++ QM_DBG_CNT_24, ++ QM_DBG_CNT_25, ++ QM_DBG_CNT_26, ++ QM_DBG_CNT_27, ++ QM_DBG_CNT_28, ++ QM_DBG_CNT_29, ++ QM_DBG_CNT_30, ++ QM_DBG_CNT_31, ++ QM_DBG_CNT_NUM ++}; ++ ++/* Used for MAC TX */ ++typedef enum _ENUM_MAC_TX_QUEUE_INDEX_T { ++ MAC_TX_QUEUE_AC0_INDEX = 0, ++ MAC_TX_QUEUE_AC1_INDEX, ++ MAC_TX_QUEUE_AC2_INDEX, ++ MAC_TX_QUEUE_AC3_INDEX, ++ MAC_TX_QUEUE_AC4_INDEX, ++ MAC_TX_QUEUE_AC5_INDEX, ++ MAC_TX_QUEUE_AC6_INDEX, ++ MAC_TX_QUEUE_BCN_INDEX, ++ MAC_TX_QUEUE_BMC_INDEX, ++ MAC_TX_QUEUE_NUM ++} ENUM_MAC_TX_QUEUE_INDEX_T; ++ ++typedef struct _RX_BA_ENTRY_T { ++ BOOLEAN fgIsValid; ++ QUE_T rReOrderQue; ++ UINT_16 u2WinStart; ++ UINT_16 u2WinEnd; ++ UINT_16 u2WinSize; ++ ++ /* For identifying the RX BA agreement */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucTid; ++ ++ BOOLEAN fgIsWaitingForPktWithSsn; ++ ++ /* UINT_8 ucTxBufferSize; */ ++ /* BOOL fgIsAcConstrain; */ ++ /* BOOL fgIsBaEnabled; */ ++} RX_BA_ENTRY_T, *P_RX_BA_ENTRY_T; ++ ++/* The mailbox message (could be used for Host-To-Device or Device-To-Host Mailbox) */ ++typedef struct _MAILBOX_MSG_T { ++ UINT_32 u4Msg[2]; /* [0]: D2HRM0R or H2DRM0R, [1]: D2HRM1R or H2DRM1R */ ++} MAILBOX_MSG_T, *P_MAILBOX_MSG_T; ++ ++/* Used for adaptively adjusting TC resources */ ++typedef struct _TC_RESOURCE_CTRL_T { ++ /* TC0, TC1, TC2, TC3, TC5 */ ++ UINT_32 au4AverageQueLen[TC_NUM - 1]; ++} TC_RESOURCE_CTRL_T, *P_TC_RESOURCE_CTRL_T; ++ ++typedef struct _QUE_MGT_T { /* Queue Management Control Info */ ++ ++ /* Per-Type Queues: [0] BMCAST or UNKNOWN-STA packets */ ++ QUE_T arTxQueue[NUM_OF_PER_TYPE_TX_QUEUES]; ++ ++#if 0 ++ /* For TX Scheduling */ ++ UINT_8 arRemainingTxOppt[NUM_OF_PER_STA_TX_QUEUES]; ++ UINT_8 arCurrentTxStaIndex[NUM_OF_PER_STA_TX_QUEUES]; ++ ++#endif ++ ++ /* Reordering Queue Parameters */ ++ RX_BA_ENTRY_T arRxBaTable[CFG_NUM_OF_RX_BA_AGREEMENTS]; ++ ++ /* Current number of activated RX BA agreements <= CFG_NUM_OF_RX_BA_AGREEMENTS */ ++ UINT_8 ucRxBaCount; ++ ++#if QM_TEST_MODE ++ UINT_32 u4PktCount; ++ P_ADAPTER_T prAdapter; ++ ++#if QM_TEST_FAIR_FORWARDING ++ UINT_32 u4CurrentStaRecIndexToEnqueue; ++#endif ++ ++#endif ++ ++#if QM_FORWARDING_FAIRNESS ++ /* The current TX count for a STA with respect to a TC index */ ++ UINT_32 au4ForwardCount[NUM_OF_PER_STA_TX_QUEUES]; ++ ++ /* The current serving STA with respect to a TC index */ ++ UINT_32 au4HeadStaRecIndex[NUM_OF_PER_STA_TX_QUEUES]; ++#endif ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ UINT_32 au4AverageQueLen[TC_NUM]; ++ UINT_32 au4CurrentTcResource[TC_NUM]; ++ UINT_32 au4MinReservedTcResource[TC_NUM]; /* The minimum amount of resource no matter busy or idle */ ++ UINT_32 au4GuaranteedTcResource[TC_NUM]; /* The minimum amount of resource when extremely busy */ ++ ++ UINT_32 u4TimeToAdjustTcResource; ++ UINT_32 u4TimeToUpdateQueLen; ++ UINT_32 u4TxNumOfVi, u4TxNumOfVo; /* number of VI/VO packets */ ++ ++ /* Set to TRUE if the last TC adjustment has not been completely applied (i.e., waiting more TX-Done events ++ to align the TC quotas to the TC resource assignment) */ ++ BOOLEAN fgTcResourcePostAnnealing; ++ ++#endif ++ ++#if QM_DEBUG_COUNTER ++ UINT_32 au4QmDebugCounters[QM_DBG_CNT_NUM]; ++#endif ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ UINT_32 au4QmTcResourceEmptyCounter[NET_TYPE_NUM][TC_NUM]; ++ UINT_32 au4QmTcResourceBackCounter[TC_NUM]; ++ UINT_32 au4DequeueNoTcResourceCounter[TC_NUM]; ++ ++ UINT_32 au4ResourceUsedCounter[TC_NUM]; ++ ++ UINT_32 au4ResourceWantedCounter[TC_NUM]; ++ ++ UINT_32 u4EnqeueuCounter; ++ UINT_32 u4DequeueCounter; ++#endif ++} QUE_MGT_T, *P_QUE_MGT_T; ++ ++typedef struct _EVENT_RX_ADDBA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Fields not present in the received ADDBA_REQ */ ++ UINT_8 ucStaRecIdx; ++ ++ /* Fields that are present in the received ADDBA_REQ */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++ UINT_16 u2BAStartSeqCtrl; /* SSN */ ++ ++} EVENT_RX_ADDBA_T, *P_EVENT_RX_ADDBA_T; ++ ++typedef struct _EVENT_RX_DELBA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Fields not present in the received ADDBA_REQ */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucTid; ++} EVENT_RX_DELBA_T, *P_EVENT_RX_DELBA_T; ++ ++typedef struct _EVENT_BSS_ABSENCE_PRESENCE_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucNetTypeIdx; ++ BOOLEAN fgIsAbsent; ++ UINT_8 ucBssFreeQuota; ++ UINT_8 aucReserved[1]; ++} EVENT_BSS_ABSENCE_PRESENCE_T, *P_EVENT_BSS_ABSENCE_PRESENCE_T; ++ ++typedef struct _EVENT_STA_CHANGE_PS_MODE_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucStaRecIdx; ++ BOOLEAN fgIsInPs; ++ UINT_8 ucUpdateMode; ++ UINT_8 ucFreeQuota; ++} EVENT_STA_CHANGE_PS_MODE_T, *P_EVENT_STA_CHANGE_PS_MODE_T; ++ ++/* The free quota is used by PS only now */ ++/* The event may be used by per STA flow conttrol in general */ ++typedef struct _EVENT_STA_UPDATE_FREE_QUOTA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucUpdateMode; ++ UINT_8 ucFreeQuota; ++ UINT_8 aucReserved[1]; ++} EVENT_STA_UPDATE_FREE_QUOTA_T, *P_EVENT_STA_UPDATE_FREE_QUOTA_T; ++ ++/* WMM-2.2.1 WMM Information Element */ ++typedef struct _IE_WMM_INFO_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ UINT_8 ucQosInfo; /* QoS Info field */ ++ UINT_8 ucDummy[3]; /* Dummy for pack */ ++} IE_WMM_INFO_T, *P_IE_WMM_INFO_T; ++ ++/* WMM-2.2.2 WMM Parameter Element */ ++typedef struct _IE_WMM_PARAM_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ ++ /* IE Body */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ ++ /* WMM IE Body */ ++ UINT_8 ucQosInfo; /* QoS Info field */ ++ UINT_8 ucReserved; ++ ++ /* AC Parameters */ ++ UINT_8 ucAciAifsn_BE; ++ UINT_8 ucEcw_BE; ++ UINT_8 aucTxopLimit_BE[2]; ++ ++ UINT_8 ucAciAifsn_BG; ++ UINT_8 ucEcw_BG; ++ UINT_8 aucTxopLimit_BG[2]; ++ ++ UINT_8 ucAciAifsn_VI; ++ UINT_8 ucEcw_VI; ++ UINT_8 aucTxopLimit_VI[2]; ++ ++ UINT_8 ucAciAifsn_VO; ++ UINT_8 ucEcw_VO; ++ UINT_8 aucTxopLimit_VO[2]; ++ ++} IE_WMM_PARAM_T, *P_IE_WMM_PARAM_T; ++ ++typedef struct _IE_WMM_TSPEC_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ /* WMM TSPEC body */ ++ UINT_8 aucTsInfo[3]; /* TS Info */ ++ UINT_8 aucTspecBodyPart[1]; /* Note: Utilize PARAM_QOS_TSPEC to fill (memory copy) */ ++} IE_WMM_TSPEC_T, *P_IE_WMM_TSPEC_T; ++ ++typedef struct _IE_WMM_HDR_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ UINT_8 aucBody[1]; /* IE body */ ++} IE_WMM_HDR_T, *P_IE_WMM_HDR_T; ++ ++typedef struct _AC_QUE_PARMS_T { ++ UINT_16 u2CWmin; /*!< CWmin */ ++ UINT_16 u2CWmax; /*!< CWmax */ ++ UINT_16 u2TxopLimit; /*!< TXOP limit */ ++ UINT_16 u2Aifsn; /*!< AIFSN */ ++ UINT_8 ucGuradTime; /*!< GuardTime for STOP/FLUSH. */ ++ BOOLEAN fgIsACMSet; ++} AC_QUE_PARMS_T, *P_AC_QUE_PARMS_T; ++ ++/* WMM ACI (AC index) */ ++typedef enum _ENUM_WMM_ACI_T { ++ WMM_AC_BE_INDEX = 0, ++ WMM_AC_BK_INDEX, ++ WMM_AC_VI_INDEX, ++ WMM_AC_VO_INDEX, ++ WMM_AC_INDEX_NUM ++} ENUM_WMM_ACI_T, *P_ENUM_WMM_ACI_T; ++ ++/* Used for CMD Queue Operation */ ++typedef enum _ENUM_FRAME_ACTION_T { ++ FRAME_ACTION_DROP_PKT = 0, ++ FRAME_ACTION_QUEUE_PKT, ++ FRAME_ACTION_TX_PKT, ++ FRAME_ACTION_NUM ++} ENUM_FRAME_ACTION_T; ++ ++typedef enum _ENUM_FRAME_TYPE_IN_CMD_Q_T { ++ FRAME_TYPE_802_1X = 0, ++ FRAME_TYPE_MMPDU, ++ FRAME_TYPE_NUM ++} ENUM_FRAME_TYPE_IN_CMD_Q_T; ++ ++typedef enum _ENUM_FREE_QUOTA_MODET_T { ++ FREE_QUOTA_UPDATE_MODE_INIT = 0, ++ FREE_QUOTA_UPDATE_MODE_OVERWRITE, ++ FREE_QUOTA_UPDATE_MODE_INCREASE, ++ FREE_QUOTA_UPDATE_MODE_DECREASE ++} ENUM_FREE_QUOTA_MODET_T, *P_ENUM_FREE_QUOTA_MODET_T; ++ ++typedef struct _CMD_UPDATE_WMM_PARMS_T { ++ AC_QUE_PARMS_T arACQueParms[AC_NUM]; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 fgIsQBSS; ++ UINT_8 aucReserved[2]; ++} CMD_UPDATE_WMM_PARMS_T, *P_CMD_UPDATE_WMM_PARMS_T; ++ ++typedef struct _CMD_TX_AMPDU_T { ++ BOOLEAN fgEnable; ++ UINT_8 aucReserved[3]; ++} CMD_TX_AMPDU_T, *P_CMD_TX_AMPDU_T; ++ ++typedef struct _CMD_ADDBA_REJECT { ++ BOOLEAN fgEnable; ++ UINT_8 aucReserved[3]; ++} CMD_ADDBA_REJECT_T, *P_CMD_ADDBA_REJECT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define QM_TX_SET_NEXT_MSDU_INFO(_prMsduInfoPreceding, _prMsduInfoNext) \ ++ ((((_prMsduInfoPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prMsduInfoNext)) ++ ++#define QM_TX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ ++ ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) ++ ++#define QM_TX_GET_NEXT_MSDU_INFO(_prMsduInfo) \ ++ ((P_MSDU_INFO_T)(((_prMsduInfo)->rQueEntry).prNext)) ++ ++#define QM_RX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ ++ ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) ++ ++#define QM_RX_GET_NEXT_SW_RFB(_prSwRfb) \ ++ ((P_SW_RFB_T)(((_prSwRfb)->rQueEntry).prNext)) ++ ++#if 0 ++#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ ++ ((((_ucIndex) != STA_REC_INDEX_BMCAST) && ((_ucIndex) != STA_REC_INDEX_NOT_FOUND)) ?\ ++ &(_prAdapter->arStaRec[_ucIndex]) : NULL) ++#endif ++ ++#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ ++ cnmGetStaRecByIndex(_prAdapter, _ucIndex) ++ ++#define QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(\ ++ _prMsduInfo,\ ++ _ucTC,\ ++ _ucPacketType,\ ++ _ucFormatID,\ ++ _fgIs802_1x,\ ++ _fgIs802_11,\ ++ _u2PalLLH,\ ++ _u2AclSN,\ ++ _ucPsForwardingType,\ ++ _ucPsSessionID\ ++ ) \ ++{\ ++ ASSERT(_prMsduInfo);\ ++ (_prMsduInfo)->ucTC = (_ucTC);\ ++ (_prMsduInfo)->ucPacketType = (_ucPacketType);\ ++ (_prMsduInfo)->ucFormatID = (_ucFormatID);\ ++ (_prMsduInfo)->fgIs802_1x = (_fgIs802_1x);\ ++ (_prMsduInfo)->fgIs802_11 = (_fgIs802_11);\ ++ (_prMsduInfo)->u2PalLLH = (_u2PalLLH);\ ++ (_prMsduInfo)->u2AclSN = (_u2AclSN);\ ++ (_prMsduInfo)->ucPsForwardingType = (_ucPsForwardingType);\ ++ (_prMsduInfo)->ucPsSessionID = (_ucPsSessionID);\ ++ (_prMsduInfo)->fgIsBurstEnd = (FALSE);\ ++} ++ ++#define QM_INIT_STA_REC(\ ++ _prStaRec,\ ++ _fgIsValid,\ ++ _fgIsQoS,\ ++ _pucMacAddr\ ++ )\ ++{\ ++ ASSERT(_prStaRec);\ ++ (_prStaRec)->fgIsValid = (_fgIsValid);\ ++ (_prStaRec)->fgIsQoS = (_fgIsQoS);\ ++ (_prStaRec)->fgIsInPS = FALSE; \ ++ (_prStaRec)->ucPsSessionID = 0xFF;\ ++ COPY_MAC_ADDR((_prStaRec)->aucMacAddr, (_pucMacAddr));\ ++} ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++#define QM_GET_TX_QUEUE_LEN(_prAdapter, _u4QueIdx) \ ++ ((_prAdapter->rQM.au4AverageQueLen[(_u4QueIdx)] >> QM_QUE_LEN_MOVING_AVE_FACTOR)) ++#endif ++ ++#define WMM_IE_OUI_TYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiType) ++#define WMM_IE_OUI_SUBTYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiSubtype) ++#define WMM_IE_OUI(fp) (((P_IE_WMM_HDR_T)(fp))->aucOui) ++ ++#if QM_DEBUG_COUNTER ++#define QM_DBG_CNT_INC(_prQM, _index) { (_prQM)->au4QmDebugCounters[(_index)]++; } ++#else ++#define QM_DBG_CNT_INC(_prQM, _index) {} ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Queue Management and STA_REC Initialization */ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmInit(IN P_ADAPTER_T prAdapter); ++ ++#if QM_TEST_MODE ++VOID qmTestCases(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++ ++P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); ++ ++P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus); ++ ++VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter); ++ ++VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* RX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); ++ ++VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); ++ ++VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); ++ ++VOID ++qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++BOOLEAN ++qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout); ++ ++VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg); ++ ++BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater); ++ ++VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid); ++ ++BOOLEAN ++qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize); ++ ++VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost); ++ ++VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); ++ ++VOID ++mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride); ++ ++VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams); ++ ++VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec); ++ ++/* Utility function: for deciding STA-REC index */ ++UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++UINT_32 ++mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, ++ UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf); ++ ++VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode); ++ ++VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++ENUM_FRAME_ACTION_T ++qmGetFrameAction(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, ++ IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType); ++ ++VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); ++ ++VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID ++qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone); ++ ++VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter); ++ ++#if ARP_MONITER_ENABLE ++VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++VOID qmResetArpDetect(VOID); ++VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _QUE_MGT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h +new file mode 100644 +index 000000000000..2804b0387f5f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h +@@ -0,0 +1,1010 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/wlan_def.h#1 ++*/ ++ ++/*! \file "wlan_def.h" ++ \brief This file includes the basic definition of WLAN ++ ++*/ ++ ++/* ++** Log: wlan_def.h ++** ++** 09 02 2013 cp.wu ++** add path to handle reassociation request ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw ++ * structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Resize the Secondary Device Type array when WiFi Direct is enabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Add new station type MACRO. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 11 2010 kevin.huang ++ * [WCXRP00000068] [MT6620 Wi-Fi][Driver][FW] Fix STA RECORD sync issue and remove unused code ++ * Update ENUM_STA_ROLE_INDEX_T by using a fixed base value ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Update OP_MODE_BOW and include bow_fsm.h. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Change P2P Descriptor List to a pointer and allocate it dynamically to avoid structure corrupt by BssDescriptor free. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add a pointer in BSS Descriptor for P2P Descriptor. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add an Interface in BSS Descriptor. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify data structure for P2P Scan result. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add an operation mode for P2P device. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * P2P/RSN/WAPI IEs need to be declared with compact structure. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly ++ * dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P present boolean flag in BSS & Pre-BSS descriptor. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * move bss related data types to wlan_def.h to avoid recursive dependency. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:40 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_DEF_H ++#define _WLAN_DEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* disconnect reason */ ++#define DISCONNECT_REASON_CODE_RESERVED 0 ++#define DISCONNECT_REASON_CODE_RADIO_LOST 1 ++#define DISCONNECT_REASON_CODE_DEAUTHENTICATED 2 ++#define DISCONNECT_REASON_CODE_DISASSOCIATED 3 ++#define DISCONNECT_REASON_CODE_NEW_CONNECTION 4 ++#define DISCONNECT_REASON_CODE_REASSOCIATION 5 ++#define DISCONNECT_REASON_CODE_ROAMING 6 ++ ++/* The rate definitions */ ++#define TX_MODE_CCK 0x00 ++#define TX_MODE_OFDM 0x40 ++#define TX_MODE_HT_MM 0x80 ++#define TX_MODE_HT_GF 0xC0 ++ ++#define RATE_CCK_SHORT_PREAMBLE 0x10 ++#define RATE_OFDM 0x20 ++ ++#define PHY_RATE_1M 0x0 ++#define PHY_RATE_2M 0x1 ++#define PHY_RATE_5_5M 0x2 ++#define PHY_RATE_11M 0x3 ++#define PHY_RATE_6M 0xB ++#define PHY_RATE_9M 0xF ++#define PHY_RATE_12M 0xA ++#define PHY_RATE_18M 0xE ++#define PHY_RATE_24M 0x9 ++#define PHY_RATE_36M 0xD ++#define PHY_RATE_48M 0x8 ++#define PHY_RATE_54M 0xC ++#define PHY_RATE_MCS0 0x0 ++#define PHY_RATE_MCS1 0x1 ++#define PHY_RATE_MCS2 0x2 ++#define PHY_RATE_MCS3 0x3 ++#define PHY_RATE_MCS4 0x4 ++#define PHY_RATE_MCS5 0x5 ++#define PHY_RATE_MCS6 0x6 ++#define PHY_RATE_MCS7 0x7 ++#define PHY_RATE_MCS32 0x20 ++ ++#define RATE_CCK_1M_LONG (TX_MODE_CCK | PHY_RATE_1M) ++#define RATE_CCK_2M_LONG (TX_MODE_CCK | PHY_RATE_2M) ++#define RATE_CCK_5_5M_LONG (TX_MODE_CCK | PHY_RATE_5_5M) ++#define RATE_CCK_11M_LONG (TX_MODE_CCK | PHY_RATE_11M) ++#define RATE_CCK_2M_SHORT (TX_MODE_CCK | PHY_RATE_2M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_CCK_5_5M_SHORT (TX_MODE_CCK | PHY_RATE_5_5M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_CCK_11M_SHORT (TX_MODE_CCK | PHY_RATE_11M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_OFDM_6M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_6M) ++#define RATE_OFDM_9M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_9M) ++#define RATE_OFDM_12M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_12M) ++#define RATE_OFDM_18M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_18M) ++#define RATE_OFDM_24M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_24M) ++#define RATE_OFDM_36M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_36M) ++#define RATE_OFDM_48M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_48M) ++#define RATE_OFDM_54M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_54M) ++ ++#define RATE_MM_MCS_0 (TX_MODE_HT_MM | PHY_RATE_MCS0) ++#define RATE_MM_MCS_1 (TX_MODE_HT_MM | PHY_RATE_MCS1) ++#define RATE_MM_MCS_2 (TX_MODE_HT_MM | PHY_RATE_MCS2) ++#define RATE_MM_MCS_3 (TX_MODE_HT_MM | PHY_RATE_MCS3) ++#define RATE_MM_MCS_4 (TX_MODE_HT_MM | PHY_RATE_MCS4) ++#define RATE_MM_MCS_5 (TX_MODE_HT_MM | PHY_RATE_MCS5) ++#define RATE_MM_MCS_6 (TX_MODE_HT_MM | PHY_RATE_MCS6) ++#define RATE_MM_MCS_7 (TX_MODE_HT_MM | PHY_RATE_MCS7) ++#define RATE_MM_MCS_32 (TX_MODE_HT_MM | PHY_RATE_MCS32) ++ ++#define RATE_GF_MCS_0 (TX_MODE_HT_GF | PHY_RATE_MCS0) ++#define RATE_GF_MCS_1 (TX_MODE_HT_GF | PHY_RATE_MCS1) ++#define RATE_GF_MCS_2 (TX_MODE_HT_GF | PHY_RATE_MCS2) ++#define RATE_GF_MCS_3 (TX_MODE_HT_GF | PHY_RATE_MCS3) ++#define RATE_GF_MCS_4 (TX_MODE_HT_GF | PHY_RATE_MCS4) ++#define RATE_GF_MCS_5 (TX_MODE_HT_GF | PHY_RATE_MCS5) ++#define RATE_GF_MCS_6 (TX_MODE_HT_GF | PHY_RATE_MCS6) ++#define RATE_GF_MCS_7 (TX_MODE_HT_GF | PHY_RATE_MCS7) ++#define RATE_GF_MCS_32 (TX_MODE_HT_GF | PHY_RATE_MCS32) ++ ++#define RATE_TX_MODE_MASK BITS(6, 7) ++#define RATE_TX_MODE_OFFSET 6 ++#define RATE_CODE_GET_TX_MODE(_ucRateCode) ((_ucRateCode & RATE_TX_MODE_MASK) >> RATE_TX_MODE_OFFSET) ++#define RATE_PHY_RATE_MASK BITS(0, 5) ++#define RATE_PHY_RATE_OFFSET 0 ++#define RATE_CODE_GET_PHY_RATE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_MASK) >> RATE_PHY_RATE_OFFSET) ++#define RATE_PHY_RATE_SHORT_PREAMBLE BIT(4) ++#define RATE_CODE_IS_SHORT_PREAMBLE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_SHORT_PREAMBLE)?TRUE:FALSE) ++ ++#define CHNL_LIST_SZ_2G 14 ++#define CHNL_LIST_SZ_5G 14 ++ ++/*! CNM(STA_RECORD_T) related definition */ ++#define CFG_STA_REC_NUM 20 ++ ++/* PHY TYPE bit definitions */ ++#define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) /* HR/DSSS PHY (clause 18) */ ++#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) /* ERP PHY (clause 19) */ ++#define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) /* OFDM 5 GHz PHY (clause 17) */ ++#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) /* HT PHY (clause 20) */ ++ ++/* PHY TYPE set definitions */ ++#define PHY_TYPE_SET_802_11ABGN (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11BGN (PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11GN (PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11AN (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11ABG (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11BG (PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11A (PHY_TYPE_BIT_OFDM) ++ ++#define PHY_TYPE_SET_802_11G (PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11B (PHY_TYPE_BIT_HR_DSSS) ++ ++#define PHY_TYPE_SET_802_11N (PHY_TYPE_BIT_HT) ++ ++/* Rate set bit definitions */ ++#define RATE_SET_BIT_1M BIT(RATE_1M_INDEX) /* Bit 0: 1M */ ++#define RATE_SET_BIT_2M BIT(RATE_2M_INDEX) /* Bit 1: 2M */ ++#define RATE_SET_BIT_5_5M BIT(RATE_5_5M_INDEX) /* Bit 2: 5.5M */ ++#define RATE_SET_BIT_11M BIT(RATE_11M_INDEX) /* Bit 3: 11M */ ++#define RATE_SET_BIT_22M BIT(RATE_22M_INDEX) /* Bit 4: 22M */ ++#define RATE_SET_BIT_33M BIT(RATE_33M_INDEX) /* Bit 5: 33M */ ++#define RATE_SET_BIT_6M BIT(RATE_6M_INDEX) /* Bit 6: 6M */ ++#define RATE_SET_BIT_9M BIT(RATE_9M_INDEX) /* Bit 7: 9M */ ++#define RATE_SET_BIT_12M BIT(RATE_12M_INDEX) /* Bit 8: 12M */ ++#define RATE_SET_BIT_18M BIT(RATE_18M_INDEX) /* Bit 9: 18M */ ++#define RATE_SET_BIT_24M BIT(RATE_24M_INDEX) /* Bit 10: 24M */ ++#define RATE_SET_BIT_36M BIT(RATE_36M_INDEX) /* Bit 11: 36M */ ++#define RATE_SET_BIT_48M BIT(RATE_48M_INDEX) /* Bit 12: 48M */ ++#define RATE_SET_BIT_54M BIT(RATE_54M_INDEX) /* Bit 13: 54M */ ++#define RATE_SET_BIT_HT_PHY BIT(RATE_HT_PHY_INDEX) /* Bit 14: BSS Selector */ ++ ++/* Rate set definitions */ ++#define RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M) ++ ++#define RATE_SET_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_OFDM (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_HT (RATE_SET_ERP) ++/* #define RATE_SET_HT (RATE_SET_ERP | RATE_SET_BIT_HT_PHY) *//* NOTE(Kevin): TBD */ ++ ++#define RATE_SET_ALL_ABG RATE_SET_ERP ++ ++#define BASIC_RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M) ++ ++#define BASIC_RATE_SET_HR_DSSS_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M) ++ ++#define BASIC_RATE_SET_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define BASIC_RATE_SET_OFDM (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define BASIC_RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define INITIAL_RATE_SET_RCPI_100 RATE_SET_ALL_ABG ++ ++#define INITIAL_RATE_SET_RCPI_80 (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define INITIAL_RATE_SET_RCPI_60 (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M) ++ ++#define INITIAL_RATE_SET(_rcpi) (INITIAL_RATE_SET_ ## _rcpi) ++ ++#define RCPI_100 100 /* -60 dBm */ ++#define RCPI_80 80 /* -70 dBm */ ++#define RCPI_60 60 /* -80 dBm */ ++ ++/* The number of RCPI records used to calculate their average value */ ++#define MAX_NUM_RCPI_RECORDS 10 ++ ++/* The number of RCPI records used to calculate their average value */ ++#define NO_RCPI_RECORDS -128 ++#define MAX_RCPI_DBM 0 ++#define MIN_RCPI_DBM -100 ++ ++#define MAC_TX_RESERVED_FIELD 0 /* NOTE(Kevin): Should defined in tx.h */ ++ ++#define MAX_ASSOC_ID (CFG_STA_REC_NUM) /* Available AID: 1 ~ 20(STA_REC_NUM) */ ++ ++#define MAX_DEAUTH_INFO_COUNT 4 /* NOTE(Kevin): Used in auth.c */ ++#define MIN_DEAUTH_INTERVAL_MSEC 500 /* The minimum interval if continuously send Deauth Frame */ ++ ++/* Authentication Type */ ++#define AUTH_TYPE_OPEN_SYSTEM BIT(AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++#define AUTH_TYPE_SHARED_KEY BIT(AUTH_ALGORITHM_NUM_SHARED_KEY) ++#define AUTH_TYPE_FAST_BSS_TRANSITION BIT(AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION) ++ ++/* Authentication Retry Limit */ ++#define TX_AUTH_ASSOCI_RETRY_LIMIT 2 ++#define TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING 1 ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MAX_LEN_WMM_INFO 7 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_16 PHY_TYPE, *P_PHY_TYPE; ++typedef UINT_8 RCPI, *P_RCPI; ++typedef UINT_8 ALC_VAL, *P_ALC_VAL; ++ ++typedef enum _ENUM_HW_BSSID_T { ++ BSSID_0 = 0, ++ BSSID_1, ++ BSSID_NUM ++} ENUM_HW_BSSID_T; ++ ++typedef enum _ENUM_HW_MAC_ADDR_T { ++ MAC_ADDR_0 = 0, ++ MAC_ADDR_1, ++ MAC_ADDR_NUM ++} ENUM_HW_MAC_ADDR_T; ++ ++typedef enum _ENUM_HW_OP_MODE_T { ++ HW_OP_MODE_STA = 0, ++ HW_OP_MODE_AP, ++ HW_OP_MODE_ADHOC, ++ HW_OP_MODE_NUM ++} ENUM_HW_OP_MODE_T; ++ ++typedef enum _ENUM_TSF_T { ++ ENUM_LOCAL_TSF_0, ++ ENUM_LOCAL_TSF_1, ++ ENUM_LOCAL_TSF_NUM ++} ENUM_LOCAL_TSF_T, *P_ENUM_LOCAL_TSF_T; ++ ++typedef enum _HAL_TS_HW_UPDATE_MODE { ++ HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME, ++ HAL_TSF_HW_UPDATE_BY_TICK_ONLY, ++ HAL_TSF_HW_UPDATE_BY_RECEIVED_FRAME_ONLY, ++ HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME_AD_HOC ++} HAL_TSF_HW_UPDATE_MODE; ++ ++typedef enum _ENUM_AC_T { ++ AC0 = 0, ++ AC1, ++ AC2, ++ AC3, ++ AC_NUM ++} ENUM_AC_T, *P_ENUM_AC_T; ++ ++/* The Type of Network been activated */ ++typedef enum _ENUM_NETWORK_TYPE_INDEX_T { ++ NETWORK_TYPE_AIS_INDEX = 0, ++ NETWORK_TYPE_P2P_INDEX, ++ NETWORK_TYPE_BOW_INDEX, ++ NETWORK_TYPE_INDEX_NUM ++} ENUM_NETWORK_TYPE_INDEX_T; ++ ++/* The Type of STA Type. */ ++typedef enum _ENUM_STA_TYPE_INDEX_T { ++ STA_TYPE_LEGACY_INDEX = 0, ++ STA_TYPE_P2P_INDEX, ++ STA_TYPE_BOW_INDEX, ++ STA_TYPE_INDEX_NUM ++} ENUM_STA_TYPE_INDEX_T; ++ ++#define STA_ROLE_BASE_INDEX 4 ++ ++typedef enum _ENUM_STA_ROLE_INDEX_T { ++ STA_ROLE_ADHOC_INDEX = STA_ROLE_BASE_INDEX, /* 4 */ ++ STA_ROLE_CLIENT_INDEX, ++ STA_ROLE_AP_INDEX, ++ STA_ROLE_TDLS_INDEX, ++ STA_ROLE_DLS_INDEX /* Note: need to extend P_CMD_UPDATE_STA_RECORD_T */ ++} ENUM_STA_ROLE_INDEX_T; ++ ++/* The Power State of a specific Network */ ++typedef enum _ENUM_PWR_STATE_T { ++ PWR_STATE_IDLE = 0, ++ PWR_STATE_ACTIVE, ++ PWR_STATE_PS, ++ PWR_STATE_NUM ++} ENUM_PWR_STATE_T; ++ ++typedef enum _ENUM_PHY_TYPE_INDEX_T { ++ /* PHY_TYPE_DSSS_INDEX, *//* DSSS PHY (clause 15) -- Not used anymore */ ++ PHY_TYPE_HR_DSSS_INDEX = 0, /* HR/DSSS PHY (clause 18) */ ++ PHY_TYPE_ERP_INDEX, /* ERP PHY (clause 19) */ ++ PHY_TYPE_ERP_P2P_INDEX, /* ERP PHY (clause 19) w/o HR/DSSS */ ++ PHY_TYPE_OFDM_INDEX, /* OFDM 5 GHz PHY (clause 17) */ ++ PHY_TYPE_HT_INDEX, /* HT PHY (clause 20) */ ++ PHY_TYPE_INDEX_NUM /* 5 */ ++} ENUM_PHY_TYPE_INDEX_T, *P_ENUM_PHY_TYPE_INDEX_T; ++ ++typedef enum _ENUM_ACPI_STATE_T { ++ ACPI_STATE_D0 = 0, ++ ACPI_STATE_D1, ++ ACPI_STATE_D2, ++ ACPI_STATE_D3 ++} ENUM_ACPI_STATE_T; ++ ++/* The operation mode of a specific Network */ ++typedef enum _ENUM_OP_MODE_T { ++ OP_MODE_INFRASTRUCTURE = 0, /* Infrastructure/GC */ ++ OP_MODE_IBSS, /* AdHoc */ ++ OP_MODE_ACCESS_POINT, /* For GO */ ++ OP_MODE_P2P_DEVICE, /* P2P Device */ ++ OP_MODE_BOW, ++ OP_MODE_NUM ++} ENUM_OP_MODE_T, *P_ENUM_OP_MODE_T; ++ ++typedef enum _ENUM_CHNL_EXT_T { ++ CHNL_EXT_SCN = 0, ++ CHNL_EXT_SCA = 1, ++ CHNL_EXT_RES = 2, ++ CHNL_EXT_SCB = 3 ++} ENUM_CHNL_EXT_T, *P_ENUM_CHNL_EXT_T; ++ ++/* This starting freq of the band is unit of kHz */ ++typedef enum _ENUM_BAND_T { ++ BAND_NULL, ++ BAND_2G4, ++ BAND_5G, ++ BAND_NUM ++} ENUM_BAND_T, *P_ENUM_BAND_T; ++ ++/* Provide supported channel list to other components in array format */ ++typedef struct _RF_CHANNEL_INFO_T { ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannelNum; ++} RF_CHANNEL_INFO_T, *P_RF_CHANNEL_INFO_T; ++ ++typedef enum _ENUM_RATE_INDEX_T { ++ RATE_1M_INDEX = 0, /* 1M */ ++ RATE_2M_INDEX, /* 2M */ ++ RATE_5_5M_INDEX, /* 5.5M */ ++ RATE_11M_INDEX, /* 11M */ ++ RATE_22M_INDEX, /* 22M */ ++ RATE_33M_INDEX, /* 33M */ ++ RATE_6M_INDEX, /* 6M */ ++ RATE_9M_INDEX, /* 9M */ ++ RATE_12M_INDEX, /* 12M */ ++ RATE_18M_INDEX, /* 18M */ ++ RATE_24M_INDEX, /* 24M */ ++ RATE_36M_INDEX, /* 36M */ ++ RATE_48M_INDEX, /* 48M */ ++ RATE_54M_INDEX, /* 54M */ ++ RATE_HT_PHY_INDEX, /* BSS Selector - HT PHY */ ++ RATE_NUM /* 15 */ ++} ENUM_RATE_INDEX_T, *P_ENUM_RATE_INDEX_T; ++ ++typedef enum _ENUM_HT_RATE_INDEX_T { ++ HT_RATE_MCS0_INDEX = 0, ++ HT_RATE_MCS1_INDEX, ++ HT_RATE_MCS2_INDEX, ++ HT_RATE_MCS3_INDEX, ++ HT_RATE_MCS4_INDEX, ++ HT_RATE_MCS5_INDEX, ++ HT_RATE_MCS6_INDEX, ++ HT_RATE_MCS7_INDEX, ++ HT_RATE_MCS32_INDEX, ++ HT_RATE_NUM /* 9 */ ++} ENUM_HT_RATE_INDEX_T, *P_ENUM_HT_RATE_INDEX_T; ++ ++typedef enum _ENUM_PREMABLE_OPTION_T { ++ PREAMBLE_DEFAULT_LONG_NONE = 0, /* LONG for PHY_TYPE_HR_DSSS, NONE for PHY_TYPE_OFDM */ ++ PREAMBLE_OPTION_SHORT, /* SHORT mandatory for PHY_TYPE_ERP, SHORT option for PHY_TYPE_HR_DSSS */ ++ PREAMBLE_HT_MIXED_MODE, ++ PREAMBLE_HT_GREEN_FIELD, ++ PREAMBLE_OPTION_NUM ++} ENUM_PREMABLE_OPTION_T, *P_ENUM_PREMABLE_OPTION_T; ++ ++typedef enum _ENUM_CHANNEL_WIDTH_T { ++ CW_20_40MHZ = 0, ++ CW_80MHZ = 1, ++ CW_160MHZ = 2, ++ CW_80P80MHZ = 3 ++} ENUM_CHANNEL_WIDTH_T, *P_ENUM_CHANNEL_WIDTH_P; ++ ++typedef enum _ENUM_MODULATION_SYSTEM_T { ++ MODULATION_SYSTEM_CCK = 0, ++ MODULATION_SYSTEM_OFDM, ++ MODULATION_SYSTEM_HT20, ++ MODULATION_SYSTEM_HT40, ++ MODULATION_SYSTEM_NUM ++} ENUM_MODULATION_SYSTEM_T, *P_ENUM_MODULATION_SYSTEM_T; ++ ++typedef enum _ENUM_MODULATION_TYPE_T { ++ MODULATION_TYPE_CCK_BPSK = 0, ++ MODULATION_TYPE_QPSK, ++ MODULATION_TYPE_16QAM, ++ MODULATION_TYPE_64QAM, ++ MODULATION_TYPE_NUM ++} ENUM_MODULATION_TYPE_T, *P_ENUM_MODULATION_TYPE_T; ++ ++typedef enum _ENUM_PS_FORWARDING_TYPE_T { ++ PS_FORWARDING_TYPE_NON_PS = 0, ++ PS_FORWARDING_TYPE_DELIVERY_ENABLED, ++ PS_FORWARDING_TYPE_NON_DELIVERY_ENABLED, ++ PS_FORWARDING_MORE_DATA_ENABLED, ++ PS_FORWARDING_TYPE_NUM ++} ENUM_PS_FORWARDING_TYPE_T, *P_ENUM_PS_FORWARDING_TYPE_T; ++ ++typedef struct _DEAUTH_INFO_T { ++ UINT_8 aucRxAddr[MAC_ADDR_LEN]; ++ OS_SYSTIME rLastSendTime; ++} DEAUTH_INFO_T, *P_DEAUTH_INFO_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* Information Element (IE) handlers */ ++/*----------------------------------------------------------------------------*/ ++typedef VOID(*PFN_APPEND_IE_FUNC) (P_ADAPTER_T, P_MSDU_INFO_T); ++typedef VOID(*PFN_HANDLE_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T); ++typedef VOID(*PFN_VERIFY_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T, PUINT_16); ++typedef UINT_32(*PFN_CALCULATE_VAR_IE_LEN_FUNC) (P_ADAPTER_T, ENUM_NETWORK_TYPE_INDEX_T, P_STA_RECORD_T); ++ ++typedef struct _APPEND_IE_ENTRY_T { ++ UINT_16 u2EstimatedIELen; ++ PFN_APPEND_IE_FUNC pfnAppendIE; ++} APPEND_IE_ENTRY_T, *P_APPEND_IE_ENTRY_T; ++ ++typedef struct _APPEND_VAR_IE_ENTRY_T { ++ UINT_16 u2EstimatedFixedIELen; /* For Fixed Length */ ++ PFN_CALCULATE_VAR_IE_LEN_FUNC pfnCalculateVariableIELen; ++ PFN_APPEND_IE_FUNC pfnAppendIE; ++} APPEND_VAR_IE_ENTRY_T, *P_APPEND_VAR_IE_ENTRY_T; ++ ++typedef struct _HANDLE_IE_ENTRY_T { ++ UINT_8 ucElemID; ++ PFN_HANDLE_IE_FUNC pfnHandleIE; ++} HANDLE_IE_ENTRY_T, *P_HANDLE_IE_ENTRY_T; ++ ++typedef struct _VERIFY_IE_ENTRY_T { ++ UINT_8 ucElemID; ++ PFN_VERIFY_IE_FUNC pfnVarifyIE; ++} VERIFY_IE_ENTRY_T, *P_VERIFY_IE_ENTRY_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* Parameters of User Configuration */ ++/*----------------------------------------------------------------------------*/ ++typedef enum _ENUM_PARAM_CONNECTION_POLICY_T { ++ CONNECT_BY_SSID_BEST_RSSI = 0, ++ CONNECT_BY_SSID_GOOD_RSSI_MIN_CH_LOAD, ++ CONNECT_BY_SSID_ANY, /* NOTE(Kevin): Needed by WHQL */ ++ CONNECT_BY_BSSID, ++ CONNECT_BY_CUSTOMIZED_RULE /* NOTE(Kevin): TBD */ ++} ENUM_PARAM_CONNECTION_POLICY_T, *P_ENUM_PARAM_CONNECTION_POLICY_T; ++ ++typedef enum _ENUM_PARAM_PREAMBLE_TYPE_T { ++ PREAMBLE_TYPE_LONG = 0, ++ PREAMBLE_TYPE_SHORT, ++ PREAMBLE_TYPE_AUTO /*!< Try preamble short first, if fail tray preamble long. */ ++} ENUM_PARAM_PREAMBLE_TYPE_T, *P_ENUM_PARAM_PREAMBLE_TYPE_T; ++ ++/* This is enum defined for user to select a phy config listed in combo box */ ++typedef enum _ENUM_PARAM_PHY_CONFIG_T { ++ /*!< Can associated with 802.11abg AP but without n capability, Scan dual band. */ ++ PHY_CONFIG_802_11ABG = 0, ++ PHY_CONFIG_802_11BG, /*!< Can associated with 802_11bg AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11G, /*!< Can associated with 802_11g only AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11A, /*!< Can associated with 802_11a only AP, Scan single band and not report 2.4G BSSs. */ ++ PHY_CONFIG_802_11B, /*!< Can associated with 802_11b only AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11ABGN, /*!< Can associated with 802.11abgn AP, Scan dual band. */ ++ PHY_CONFIG_802_11BGN, /*!< Can associated with 802_11bgn AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11AN, /*!< Can associated with 802_11an AP, Scan single band and not report 2.4G BSSs. */ ++ PHY_CONFIG_802_11GN, /*!< Can associated with 802_11gn AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_NUM /* 9 */ ++} ENUM_PARAM_PHY_CONFIG_T, *P_ENUM_PARAM_PHY_CONFIG_T; ++ ++/* This is enum defined for user to select an AP Mode */ ++typedef enum _ENUM_PARAM_AP_MODE_T { ++ AP_MODE_11B = 0, /*!< Create 11b BSS if we support 802.11abg/802.11bg. */ ++ AP_MODE_MIXED_11BG, /*!< Create 11bg mixed BSS if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11G, /*!< Create 11g only BSS if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11G_P2P, /*!< Create 11g only BSS for P2P if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11A, /*!< Create 11a only BSS if we support 802.11abg. */ ++ AP_MODE_NUM /* 4 */ ++} ENUM_PARAM_AP_MODE_T, *P_ENUM_PARAM_AP_MODE_T; ++ ++/* Masks for determining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ ++#define NETWORK_TYPE_AIS_MASK BIT(NETWORK_TYPE_AIS_INDEX) ++#define NETWORK_TYPE_P2P_MASK BIT(NETWORK_TYPE_P2P_INDEX) ++#define NETWORK_TYPE_BOW_MASK BIT(NETWORK_TYPE_BOW_INDEX) ++#define STA_TYPE_LEGACY_MASK BIT(STA_TYPE_LEGACY_INDEX) ++#define STA_TYPE_P2P_MASK BIT(STA_TYPE_P2P_INDEX) ++#define STA_TYPE_BOW_MASK BIT(STA_TYPE_BOW_INDEX) ++#define STA_TYPE_ADHOC_MASK BIT(STA_ROLE_ADHOC_INDEX) ++#define STA_TYPE_CLIENT_MASK BIT(STA_ROLE_CLIENT_INDEX) ++#define STA_TYPE_AP_MASK BIT(STA_ROLE_AP_INDEX) ++#define STA_TYPE_DLS_MASK BIT(STA_ROLE_DLS_INDEX) ++#define STA_TYPE_TDLS_MASK BIT(STA_ROLE_TDLS_INDEX) ++ ++/* Macros for obtaining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ ++#define IS_STA_IN_AIS(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++#define IS_STA_IN_P2P(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++#define IS_STA_IN_BOW(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++#define IS_STA_LEGACY_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_LEGACY_MASK) ++#define IS_STA_P2P_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_P2P_MASK) ++#define IS_STA_BOW_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_BOW_MASK) ++#define IS_ADHOC_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_ADHOC_MASK) ++#define IS_CLIENT_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_CLIENT_MASK) ++#define IS_AP_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_AP_MASK) ++#define IS_DLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_DLS_MASK) ++#define IS_TDLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_TDLS_MASK) ++ ++/* The ENUM_STA_TYPE_T accounts for ENUM_NETWORK_TYPE_T and ENUM_STA_ROLE_INDEX_T. ++ * * It is a merged version of Network Type and STA Role. ++ * */ ++typedef enum _ENUM_STA_TYPE_T { ++ STA_TYPE_LEGACY_AP = (STA_TYPE_LEGACY_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_LEGACY_CLIENT = (STA_TYPE_LEGACY_MASK | STA_TYPE_CLIENT_MASK), ++ STA_TYPE_ADHOC_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_ADHOC_MASK), ++#if CFG_ENABLE_WIFI_DIRECT ++ STA_TYPE_P2P_GO = (STA_TYPE_P2P_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_P2P_GC = (STA_TYPE_P2P_MASK | STA_TYPE_CLIENT_MASK), ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ STA_TYPE_BOW_AP = (STA_TYPE_BOW_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_BOW_CLIENT = (STA_TYPE_BOW_MASK | STA_TYPE_CLIENT_MASK), ++#endif ++ STA_TYPE_DLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_DLS_MASK), ++ STA_TYPE_TDLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_TDLS_MASK) ++} ENUM_STA_TYPE_T, *P_ENUM_STA_TYPE_T; ++ ++/* The type of BSS we discovered */ ++typedef enum _ENUM_BSS_TYPE_T { ++ BSS_TYPE_INFRASTRUCTURE = 1, ++ BSS_TYPE_IBSS, ++ BSS_TYPE_P2P_DEVICE, ++ BSS_TYPE_BOW_DEVICE, ++ BSS_TYPE_NUM ++} ENUM_BSS_TYPE_T, *P_ENUM_BSS_TYPE_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* RSN structures */ ++/*----------------------------------------------------------------------------*/ ++/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ ++/* #pragma pack(1) */ ++/* #endif */ ++ ++#define MAX_NUM_SUPPORTED_CIPHER_SUITES 8 /* max number of supported cipher suites */ ++#if CFG_SUPPORT_802_11W ++#define MAX_NUM_SUPPORTED_AKM_SUITES 8 /* max number of supported AKM suites */ ++#else ++#define MAX_NUM_SUPPORTED_AKM_SUITES 6 /* max number of supported AKM suites */ ++#endif ++ ++/* Structure of RSN Information */ ++typedef struct _RSN_INFO_T { ++ UINT_8 ucElemId; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_32 u4PairwiseKeyCipherSuiteCount; ++ UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_CIPHER_SUITES]; ++ UINT_32 u4AuthKeyMgtSuiteCount; ++ UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_AKM_SUITES]; ++ UINT_16 u2RsnCap; ++ BOOLEAN fgRsnCapPresent; ++} /*__KAL_ATTRIB_PACKED__*/ RSN_INFO_T, *P_RSN_INFO_T; ++ ++#define MAX_NUM_SUPPORTED_WAPI_AKM_SUITES 1 /* max number of supported AKM suites */ ++#define MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES 1 /* max number of supported cipher suites */ ++ ++/* Structure of WAPI Information */ ++typedef struct _WAPI_INFO_T { ++ UINT_8 ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_32 u4AuthKeyMgtSuiteCount; ++ UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_WAPI_AKM_SUITES]; ++ UINT_32 u4PairwiseKeyCipherSuiteCount; ++ UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES]; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2WapiCap; ++ UINT_16 u2Bkid; ++ UINT_8 aucBkid[1][16]; ++} /* __KAL_ATTRIB_PACKED__ */ WAPI_INFO_T, *P_WAPI_INFO_T; ++ ++/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ ++/* #pragma pack() */ ++/* #endif */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++typedef struct _P2P_DEVICE_TYPE_T { ++ UINT_16 u2CategoryID; ++ UINT_16 u2SubCategoryID; ++} P2P_DEVICE_TYPE_T, *P_P2P_DEVICE_TYPE_T; ++ ++typedef struct _P2P_DEVICE_DESC_T { ++ LINK_ENTRY_T rLinkEntry; ++ BOOLEAN fgDevInfoValid; ++ UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Interface Address. */ ++ UINT_8 ucDeviceCapabilityBitmap; ++ UINT_8 ucGroupCapabilityBitmap; ++ UINT_16 u2ConfigMethod; /* Configure Method support. */ ++ P2P_DEVICE_TYPE_T rPriDevType; ++ UINT_8 ucSecDevTypeNum; ++ P2P_DEVICE_TYPE_T arSecDevType[8]; /* Reference to P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT */ ++ UINT_16 u2NameLength; ++ UINT_8 aucName[32]; /* Reference to WPS_ATTRI_MAX_LEN_DEVICE_NAME */ ++ /* TODO: Service Information or PasswordID valid? */ ++} P2P_DEVICE_DESC_T, *P_P2P_DEVICE_DESC_T; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static const UINT_8 aucRateIndex2RateCode[PREAMBLE_OPTION_NUM][RATE_NUM] = { ++ { /* Long Preamble */ ++ RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ ++ RATE_CCK_2M_LONG, /* RATE_2M_INDEX */ ++ RATE_CCK_5_5M_LONG, /* RATE_5_5M_INDEX */ ++ RATE_CCK_11M_LONG, /* RATE_11M_INDEX */ ++ RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ ++ RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ ++ RATE_OFDM_6M, /* RATE_6M_INDEX */ ++ RATE_OFDM_9M, /* RATE_9M_INDEX */ ++ RATE_OFDM_12M, /* RATE_12M_INDEX */ ++ RATE_OFDM_18M, /* RATE_18M_INDEX */ ++ RATE_OFDM_24M, /* RATE_24M_INDEX */ ++ RATE_OFDM_36M, /* RATE_36M_INDEX */ ++ RATE_OFDM_48M, /* RATE_48M_INDEX */ ++ RATE_OFDM_54M, /* RATE_54M_INDEX */ ++ }, ++ { /* Short Preamble */ ++ RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ ++ RATE_CCK_2M_SHORT, /* RATE_2M_INDEX */ ++ RATE_CCK_5_5M_SHORT, /* RATE_5_5M_INDEX */ ++ RATE_CCK_11M_SHORT, /* RATE_11M_INDEX */ ++ RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ ++ RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ ++ RATE_OFDM_6M, /* RATE_6M_INDEX */ ++ RATE_OFDM_9M, /* RATE_9M_INDEX */ ++ RATE_OFDM_12M, /* RATE_12M_INDEX */ ++ RATE_OFDM_18M, /* RATE_18M_INDEX */ ++ RATE_OFDM_24M, /* RATE_24M_INDEX */ ++ RATE_OFDM_36M, /* RATE_36M_INDEX */ ++ RATE_OFDM_48M, /* RATE_48M_INDEX */ ++ RATE_OFDM_54M, /* RATE_54M_INDEX */ ++ }, ++ { /* Mixed Mode(Option) */ ++ RATE_MM_MCS_0, /* RATE_MCS0_INDEX, */ ++ RATE_MM_MCS_1, /* RATE_MCS1_INDEX, */ ++ RATE_MM_MCS_2, /* RATE_MCS2_INDEX, */ ++ RATE_MM_MCS_3, /* RATE_MCS3_INDEX, */ ++ RATE_MM_MCS_4, /* RATE_MCS4_INDEX, */ ++ RATE_MM_MCS_5, /* RATE_MCS5_INDEX, */ ++ RATE_MM_MCS_6, /* RATE_MCS6_INDEX, */ ++ RATE_MM_MCS_7, /* RATE_MCS7_INDEX, */ ++ RATE_MM_MCS_32 /* RATE_MCS32_INDEX, */ ++ }, ++ { /* Green Field(Option) */ ++ RATE_GF_MCS_0, /* RATE_MCS0_INDEX, */ ++ RATE_GF_MCS_1, /* RATE_MCS1_INDEX, */ ++ RATE_GF_MCS_2, /* RATE_MCS2_INDEX, */ ++ RATE_GF_MCS_3, /* RATE_MCS3_INDEX, */ ++ RATE_GF_MCS_4, /* RATE_MCS4_INDEX, */ ++ RATE_GF_MCS_5, /* RATE_MCS5_INDEX, */ ++ RATE_GF_MCS_6, /* RATE_MCS6_INDEX, */ ++ RATE_GF_MCS_7, /* RATE_MCS7_INDEX, */ ++ RATE_GF_MCS_32 /* RATE_MCS32_INDEX, */ ++ } ++}; ++ ++static const UINT_8 aucRateTableSize[PREAMBLE_OPTION_NUM] = { ++ RATE_HT_PHY_INDEX, ++ RATE_HT_PHY_INDEX, ++ HT_RATE_NUM, ++ HT_RATE_NUM ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Macros to get and set the wireless LAN frame fields those are 16/32 bits in ++ length. */ ++#define WLAN_GET_FIELD_16(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_16)(_value_p) = ((UINT_16) __cp[0]) | ((UINT_16) __cp[1] << 8); \ ++ } ++ ++#define WLAN_GET_FIELD_BE16(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_16)(_value_p) = ((UINT_16) __cp[0] << 8) | ((UINT_16) __cp[1]); \ ++ } ++ ++#define WLAN_GET_FIELD_32(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_32)(_value_p) = ((UINT_32) __cp[0]) | ((UINT_32) __cp[1] << 8) | \ ++ ((UINT_32) __cp[2] << 16) | ((UINT_32) __cp[3] << 24); \ ++ } ++ ++#define WLAN_GET_FIELD_64(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_64)(_value_p) = \ ++ ((UINT_64) __cp[0]) | ((UINT_64) __cp[1] << 8) | \ ++ ((UINT_64) __cp[2] << 16) | ((UINT_64) __cp[3] << 24) | \ ++ ((UINT_64) __cp[4] << 32) | ((UINT_64) __cp[5] << 40) | \ ++ ((UINT_64) __cp[6] << 48) | ((UINT_64) __cp[7] << 56); \ ++ } ++ ++#define WLAN_SET_FIELD_16(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) (_value); \ ++ __cp[1] = (UINT_8) ((_value) >> 8); \ ++ } ++ ++#define WLAN_SET_FIELD_BE16(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) ((_value) >> 8); \ ++ __cp[1] = (UINT_8) (_value); \ ++ } ++ ++#define WLAN_SET_FIELD_32(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) (_value); \ ++ __cp[1] = (UINT_8) ((_value) >> 8); \ ++ __cp[2] = (UINT_8) ((_value) >> 16); \ ++ __cp[3] = (UINT_8) ((_value) >> 24); \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WLAN_DEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h +new file mode 100644 +index 000000000000..aba2e040c194 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h +@@ -0,0 +1,2290 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_cmd_event.h#1 ++*/ ++ ++/*! \file "nic_cmd_event.h" ++ \brief This file contains the declairation file of the WLAN OID processing routines ++ of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: nic_cmd_event.h ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 04 2012 eason.tsai ++ * NULL ++ * modify the cal fail report code. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * redefine the CMD_ID_SET_TXPWR_CTRL value. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 11 30 2011 cm.chang ++ * [WCXRP00001128] [MT5931 Wi-Fi][FW] Update BB/RF setting based on RF doc v0.7 for LGE spec ++ * 1. Add a new CMD for driver to set device mode ++ * 2. Update calibration parameters ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add TX_DONE status detail information. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 10 26 2011 cp.wu ++ * [WCXRP00001065] [MT6620 Wi-Fi][MT5931][FW][DRV] Adding parameter for controlling ++ * minimum channel dwell time for scanning ++ * add interface for control minimum channel dwell time for scanning. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * New CMD definition about RLM parameters ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 09 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * add osc stable time command structure ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than ++ * one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 31 2011 chinglan.wang ++ * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. ++ * . ++ * ++ * 03 18 2011 cm.chang ++ * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command ++ * As CR title ++ * ++ * 03 17 2011 yarco.yang ++ * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 10 2011 cp.wu ++ * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers ++ * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Update cmd format of BSS INFO, always sync OwnMac to FW no matter P2P is enabled or not.. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Sync HT operation element information from host to FW ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition ++ * follow-up for CMD_5G_PWR_OFFSET_T definition change ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 15 2010 cm.chang ++ * NULL ++ * Add new CMD for TX power, 5G power offset and power parameters ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a pointer in P2P SCAN RESULT structure. This pointer ++ * is pointed to a IE buffer for this P2p device. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add new CMD ID definition ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add a field in BSS INFO cmd to change interface address for P2P. (switching between Device Addr & Interface Addr) ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add interface address indication when indicate connection status. ++ * It is requested by supplicant to do 4 way handshake. ++ * ++ * 08 07 2010 wh.su ++ * NULL ++ * adding the privacy related code for P2P network ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Change data structure for P2P Device scan result, all channel time for scan command. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add P2P Device Found Event. ++ * Channel extension option in scan abort command. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 george.huang ++ * ++ * DWORD align for the CMD data structure ++ * ++ * 07 20 2010 cp.wu ++ * ++ * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 09 2010 cp.wu ++ * ++ * reorder members of CMD_SET_BSS_INFO. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * update prStaRecOfAP with BSS-INFO. ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add BSS/STA_REC commands for integration. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add TX Done Event handle entry ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sync statistics data structure definition with firmware implementation ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * the frequency is used for adhoc connection only ++ * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list ++ * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 15 2010 kevin.huang ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Add event for activate STA_RECORD_T ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c ++ * 'cause it involves OS dependent data structure handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * 4. correct some HAL implementation ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * OID_802_11_RSSI, ++ * * * OID_802_11_RSSI_TRIGGER, ++ * * * OID_802_11_STATISTICS, ++ * * * OID_802_11_DISASSOCIATE, ++ * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-12-11 18:35:07 GMT mtk02752 ++** add CMD added in CMD/EVEN document v0.8 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-12-10 16:39:37 GMT mtk02752 ++** eliminate unused definitions ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-12-10 09:55:11 GMT mtk02752 ++** command ID/event ID revised ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-09 13:57:37 GMT MTK02468 ++** Added event ids (EVENT_ID_RX_ADDBA and EVENT_ID_RX_DELBA) ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-08 17:35:39 GMT mtk02752 ++** + add event ID for EVENT_ID_TEST_STATUS (rf test) ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-12-07 23:01:09 GMT mtk02752 ++** add data structure for RF_TEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-12-03 16:22:56 GMT mtk01461 ++** Modify the element - i4RSSI in EVENT of SCAN RESULT ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-30 10:54:44 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T, while 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-26 10:16:58 GMT mtk02752 ++** resync EVENT_CONNECTION_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-25 21:34:01 GMT mtk02752 ++** sync. EVENT_SCAN_RESULT_T with firmware ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-25 21:03:48 GMT mtk02752 ++** refine MGMT_FRAME ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-25 18:17:47 GMT mtk02752 ++** refine GL_WLAN_INFO_T for buffering scan result and presume max. ie length = 600 bytes ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 22:41:20 GMT mtk02752 ++** add EVENT_SCAN_RESULT_T definition ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-11-23 20:29:16 GMT mtk02752 ++** fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-11-23 14:46:01 GMT mtk02752 ++** add new command/event structure upon CM@SD1's documentation ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-13 15:13:40 GMT mtk02752 ++** add command definition for CMD_BUILD_CONNECTION and EVENT_CONNECTION_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-20 12:22:22 GMT mtk01461 ++** Add SeqNum field to Event Header ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:11 GMT mtk01461 ++** Update structure of HIF_EVENT_HEADER_T and EVENT_HDR_SIZE ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 12:10:36 GMT mtk01461 ++** Add Common Set CMD Callback for MCR Write and other Set OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:17 GMT mtk01461 ++** Command Done Handler ++*/ ++#ifndef _NIC_CMD_EVENT_H ++#define _NIC_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define CMD_STATUS_SUCCESS 0 ++#define CMD_STATUS_REJECTED 1 ++#define CMD_STATUS_UNKNOWN 2 ++ ++#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) ++ ++#define MAX_IE_LENGTH (600) ++#define MAX_WSC_IE_LENGTH (400) ++ ++/* Action field in structure CMD_CH_PRIVILEGE_T */ ++#define CMD_CH_ACTION_REQ 0 ++#define CMD_CH_ACTION_ABORT 1 ++ ++/* Status field in structure EVENT_CH_PRIVILEGE_T */ ++#define EVENT_CH_STATUS_GRANT 0 ++ ++#define SCN_PSCAN_SWC_RSSI_WIN_MAX 75 ++#define SCN_PSCAN_SWC_MAX_NUM 8 ++#define SCN_PSCAN_HOTLIST_REPORT_MAX_NUM 8 ++ ++typedef enum _ENUM_CMD_ID_T { ++ CMD_ID_TEST_MODE = 1, /* 0x01 (Set) */ ++ CMD_ID_RESET_REQUEST, /* 0x02 (Set) */ ++ CMD_ID_BUILD_CONNECTION, /* 0x03 (Set) */ ++ CMD_ID_SCAN_REQ_V2, /* 0x04 (Set) */ ++ CMD_ID_NIC_POWER_CTRL, /* 0x05 (Set) */ ++ CMD_ID_POWER_SAVE_MODE, /* 0x06 (Set) */ ++ CMD_ID_LINK_ATTRIB, /* 0x07 (Set) */ ++ CMD_ID_ADD_REMOVE_KEY, /* 0x08 (Set) */ ++ CMD_ID_DEFAULT_KEY_ID, /* 0x09 (Set) */ ++ CMD_ID_INFRASTRUCTURE, /* 0x0a (Set) */ ++ CMD_ID_SET_RX_FILTER, /* 0x0b (Set) */ ++ CMD_ID_DOWNLOAD_BUF, /* 0x0c (Set) */ ++ CMD_ID_WIFI_START, /* 0x0d (Set) */ ++ CMD_ID_CMD_BT_OVER_WIFI, /* 0x0e (Set) */ ++ CMD_ID_SET_MEDIA_CHANGE_DELAY_TIME, /* 0x0f (Set) */ ++ CMD_ID_SEND_ADDBA_RSP, /* 0x10 (Set) */ ++ CMD_ID_WAPI_MODE, /* 0x11 (Set) (obsolete) */ ++ CMD_ID_WAPI_ASSOC_INFO, /* 0x12 (Set) (obsolete) */ ++ CMD_ID_SET_DOMAIN_INFO, /* 0x13 (Set) */ ++ CMD_ID_SET_IP_ADDRESS, /* 0x14 (Set) */ ++ CMD_ID_BSS_ACTIVATE_CTRL, /* 0x15 (Set) */ ++ CMD_ID_SET_BSS_INFO, /* 0x16 (Set) */ ++ CMD_ID_UPDATE_STA_RECORD, /* 0x17 (Set) */ ++ CMD_ID_REMOVE_STA_RECORD, /* 0x18 (Set) */ ++ CMD_ID_INDICATE_PM_BSS_CREATED, /* 0x19 (Set) */ ++ CMD_ID_INDICATE_PM_BSS_CONNECTED, /* 0x1a (Set) */ ++ CMD_ID_INDICATE_PM_BSS_ABORT, /* 0x1b (Set) */ ++ CMD_ID_UPDATE_BEACON_CONTENT, /* 0x1c (Set) */ ++ CMD_ID_SET_BSS_RLM_PARAM, /* 0x1d (Set) */ ++ CMD_ID_SCAN_REQ, /* 0x1e (Set) */ ++ CMD_ID_SCAN_CANCEL, /* 0x1f (Set) */ ++ CMD_ID_CH_PRIVILEGE, /* 0x20 (Set) */ ++ CMD_ID_UPDATE_WMM_PARMS, /* 0x21 (Set) */ ++ CMD_ID_SET_WMM_PS_TEST_PARMS, /* 0x22 (Set) */ ++ CMD_ID_TX_AMPDU, /* 0x23 (Set) */ ++ CMD_ID_ADDBA_REJECT, /* 0x24 (Set) */ ++ CMD_ID_SET_PS_PROFILE_ADV, /* 0x25 (Set) */ ++ CMD_ID_SET_RAW_PATTERN, /* 0x26 (Set) */ ++ CMD_ID_CONFIG_PATTERN_FUNC, /* 0x27 (Set) */ ++ CMD_ID_SET_TX_PWR, /* 0x28 (Set) */ ++ CMD_ID_SET_5G_PWR_OFFSET, /* 0x29 (Set) */ ++ CMD_ID_SET_PWR_PARAM, /* 0x2A (Set) */ ++ CMD_ID_P2P_ABORT, /* 0x2B (Set) */ ++#if CFG_STRESS_TEST_SUPPORT ++ CMD_ID_RANDOM_RX_RESET_EN = 0x2C, /* 0x2C (Set ) */ ++ CMD_ID_RANDOM_RX_RESET_DE = 0x2D, /* 0x2D (Set ) */ ++ CMD_ID_SAPP_EN = 0x2E, /* 0x2E (Set ) */ ++ CMD_ID_SAPP_DE = 0x2F, /* 0x2F (Set ) */ ++#endif ++ CMD_ID_ROAMING_TRANSIT = 0x30, /* 0x30 (Set) */ ++ CMD_ID_SET_PHY_PARAM, /* 0x31 (Set) */ ++ CMD_ID_SET_NOA_PARAM, /* 0x32 (Set) */ ++ CMD_ID_SET_OPPPS_PARAM, /* 0x33 (Set) */ ++ CMD_ID_SET_UAPSD_PARAM, /* 0x34 (Set) */ ++ CMD_ID_SET_SIGMA_STA_SLEEP, /* 0x35 (Set) */ ++ CMD_ID_SET_EDGE_TXPWR_LIMIT, /* 0x36 (Set) */ ++ CMD_ID_SET_DEVICE_MODE, /* 0x37 (Set) */ ++ CMD_ID_SET_TXPWR_CTRL, /* 0x38 (Set) */ ++ CMD_ID_SET_AUTOPWR_CTRL, /* 0x39 (Set) */ ++ CMD_ID_SET_WFD_CTRL, /* 0x3A (Set) */ ++ CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, /* 0x3B (Set) */ ++ CMD_ID_SET_RSSI_COMPENSATE, /* 0x3C (Set) */ ++ CMD_ID_SET_BAND_SUPPORT = 0x3D, /* 0x3D (Set) */ ++ CMD_ID_SET_NLO_REQ, /* 0x3E (Set) */ ++ CMD_ID_SET_NLO_CANCEL, /* 0x3F (Set) */ ++ CMD_ID_SET_BATCH_REQ, /* 0x40 (Set) */ ++ CMD_ID_SET_WOWLAN, /* 0x41 (Set) */ /*CFG_SUPPORT_WOWLAN */ ++ CMD_ID_GET_PSCAN_CAPABILITY = 0x42, /* 0x42 (Set) */ ++ CMD_ID_SET_PSCN_ENABLE = 0x43, /* 0x43 (Set) */ ++ CMD_ID_SET_PSCAN_PARAM = 0x44, /* 0x44 (Set) */ ++ CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID = 0x45, /* 0x45 (Set) */ ++ CMD_ID_SET_PSCN_ADD_SW_BSSID = 0x46, /* 0x46 (Set) */ ++ CMD_ID_SET_PSCN_MAC_ADDR = 0x47, /* 0x47 (Set) */ ++ CMD_ID_GET_GSCN_SCN_RESULT = 0x48, /* 0x48 (Get) */ ++ CMD_ID_SET_COUNTRY_POWER_LIMIT = 0x4A, /* 0x4A (Set) */ ++ CMD_ID_SET_SYSTEM_SUSPEND = 0x60, /* 0x60 (Set) */ ++ CMD_ID_GET_NIC_CAPABILITY = 0x80, /* 0x80 (Query) */ ++ CMD_ID_GET_LINK_QUALITY, /* 0x81 (Query) */ ++ CMD_ID_GET_STATISTICS, /* 0x82 (Query) */ ++ CMD_ID_GET_CONNECTION_STATUS, /* 0x83 (Query) */ ++ CMD_ID_GET_ASSOC_INFO, /* 0x84 (Query) (obsolete) */ ++ CMD_ID_GET_STA_STATISTICS = 0x85, /* 0x85 (Query) */ ++ CMD_ID_GET_DEBUG_CODE = 0x86, /* 0x86 (Query) */ ++ CMD_ID_GET_LTE_CHN = 0x87, /* 0x87 (Query) */ ++ CMD_ID_GET_CHN_LOADING = 0x88, /* 0x88 (Query) */ ++ CMD_ID_GET_STATISTICS_PL = 0x89, /* 0x87 (Query) */ ++ CMD_ID_BASIC_CONFIG = 0xc1, /* 0xc1 (Set / Query) */ ++ CMD_ID_ACCESS_REG, /* 0xc2 (Set / Query) */ ++ CMD_ID_MAC_MCAST_ADDR, /* 0xc3 (Set / Query) */ ++ CMD_ID_802_11_PMKID, /* 0xc4 (Set / Query) */ ++ CMD_ID_ACCESS_EEPROM, /* 0xc5 (Set / Query) */ ++ CMD_ID_SW_DBG_CTRL, /* 0xc6 (Set / Query) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ CMD_ID_SEC_CHECK, /* 0xc7 (Set / Query) */ ++#endif ++ CMD_ID_DUMP_MEM, /* 0xc8 (Query) */ ++ ++ CMD_ID_CHIP_CONFIG = 0xCA, /* 0xca (Set / Query) */ ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ CMD_ID_SET_RDD_CH = 0xE1, ++#endif ++ ++ CMD_ID_SET_BWCS = 0xF1, ++ CMD_ID_SET_ROAMING_INFO = 0xF3, ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++ CMD_ID_GET_BUILD_DATE_CODE = 0xF8, ++#endif ++ CMD_ID_GET_BSS_INFO = 0xF9, ++#if 1 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION = 0xFA, /* 0xFA (Set) */ ++#endif ++ ++ CMD_ID_TDLS_CORE = 0xFC, ++ CMD_ID_STATS = 0xFD, ++ CMD_ID_TX_AR_ERR_CONFIG = 0xFF ++} ENUM_CMD_ID_T, *P_ENUM_CMD_ID_T; ++ ++typedef enum _ENUM_EVENT_ID_T { ++ EVENT_ID_CMD_RESULT = 1, /* 0x01 (Query) */ ++ EVENT_ID_NIC_CAPABILITY, /* 0x02 (Query) */ ++ EVENT_ID_CONNECTION_STATUS, /* 0x03 (Query / Unsolicited) (obsolete) */ ++ EVENT_ID_SCAN_RESULT, /* 0x04 (Query / Unsolicited) (obselete) */ ++ EVENT_ID_LINK_QUALITY, /* 0x05 (Query / Unsolicited) */ ++ EVENT_ID_STATISTICS, /* 0x06 (Query) */ ++ EVENT_ID_MIC_ERR_INFO, /* 0x07 (Unsolicited) */ ++ EVENT_ID_ASSOC_INFO, /* 0x08 (Query - CMD_ID_GET_ASSOC_INFO) */ ++ EVENT_ID_BASIC_CONFIG, /* 0x09 (Query - CMD_ID_BASIC_CONFIG) */ ++ EVENT_ID_ACCESS_REG, /* 0x0a (Query - CMD_ID_ACCESS_REG) */ ++ EVENT_ID_MAC_MCAST_ADDR, /* 0x0b (Query - CMD_ID_MAC_MCAST_ADDR) */ ++ EVENT_ID_802_11_PMKID, /* 0x0c (Query - CMD_ID_802_11_PMKID) */ ++ EVENT_ID_ACCESS_EEPROM, /* 0x0d (Query - CMD_ID_ACCESS_EEPROM) */ ++ EVENT_ID_SLEEPY_NOTIFY, /* 0x0e (Query) */ ++ EVENT_ID_BT_OVER_WIFI, /* 0x0f (Unsolicited) */ ++ EVENT_ID_TEST_STATUS, /* 0x10 (Query - CMD_ID_TEST_MODE) */ ++ EVENT_ID_RX_ADDBA, /* 0x11 (Unsolicited) (obsolete) */ ++ EVENT_ID_RX_DELBA, /* 0x12 (Unsolicited) (obsolete) */ ++ EVENT_ID_ACTIVATE_STA_REC_T, /* 0x13 (Unsolicited) */ ++ EVENT_ID_DEACTIVATE_STA_REC_T, /* 0x14 (Unsolicited) */ ++ EVENT_ID_SCAN_DONE, /* 0x15 (Unsoiicited) */ ++ EVENT_ID_RX_FLUSH, /* 0x16 (Unsolicited) */ ++ EVENT_ID_TX_DONE, /* 0x17 (Unsolicited) */ ++ EVENT_ID_CH_PRIVILEGE, /* 0x18 (Unsolicited) */ ++ EVENT_ID_BSS_ABSENCE_PRESENCE = 0x19, /* 0x19 (Unsolicited) */ ++ EVENT_ID_STA_CHANGE_PS_MODE, /* 0x1A (Unsolicited) */ ++ EVENT_ID_BSS_BEACON_TIMEOUT, /* 0x1B (Unsolicited) */ ++ EVENT_ID_UPDATE_NOA_PARAMS, /* 0x1C (Unsolicited) */ ++ EVENT_ID_AP_OBSS_STATUS, /* 0x1D (Unsolicited) */ ++ EVENT_ID_STA_UPDATE_FREE_QUOTA, /* 0x1E (Unsolicited) */ ++ EVENT_ID_SW_DBG_CTRL, /* 0x1F (Query - CMD_ID_SW_DBG_CTRL) */ ++ EVENT_ID_ROAMING_STATUS, /* 0x20 (Unsolicited) */ ++ EVENT_ID_STA_AGING_TIMEOUT, /* 0x21 (Unsolicited) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ EVENT_ID_SEC_CHECK_RSP, /* 0x22 (Unsolicited) */ ++#endif ++ EVENT_ID_SEND_DEAUTH, /* 0x23 (Unsolicited) */ ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ EVENT_ID_UPDATE_RDD_STATUS, /* 0x24 (Unsolicited) */ ++#endif ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ EVENT_ID_UPDATE_BWCS_STATUS = 0x25, /* 0x25 (Unsolicited) */ ++ EVENT_ID_UPDATE_BCM_DEBUG, /* 0x26 (Unsolicited) */ ++#endif ++ EVENT_ID_RX_ERR, ++ EVENT_ID_DUMP_MEM, ++ EVENT_ID_STA_STATISTICS = 0x29, /* 0x29 (Query ) */ ++ EVENT_ID_STA_STATISTICS_UPDATE, /* 0x2A (Unsolicited) */ ++ EVENT_ID_NLO_DONE = 0x2b, ++ ++ EVENT_ID_GSCAN_CAPABILITY = 0x30, ++ EVENT_ID_GSCAN_SCAN_COMPLETE = 0x31, ++ EVENT_ID_GSCAN_FULL_RESULT = 0x32, ++ EVENT_ID_GSCAN_SIGNIFICANT_CHANGE = 0x33, ++ EVENT_ID_GSCAN_GEOFENCE_FOUND = 0x34, ++ EVENT_ID_GSCAN_SCAN_AVAILABLE = 0x35, ++ EVENT_ID_GSCAN_RESULT = 0x36, ++ EVENT_ID_BATCH_RESULT = 0x37, ++ ++ EVENT_ID_TDLS = 0x80, ++ EVENT_ID_STATS_ENV = 0x81, ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++ EVENT_ID_BUILD_DATE_CODE = 0xF8, ++#endif ++ EVENT_ID_GET_AIS_BSS_INFO = 0xF9, ++ EVENT_ID_DEBUG_CODE = 0xFB, ++ EVENT_ID_RFTEST_READY = 0xFC, /* 0xFC */ ++ EVENT_ID_TX_DONE_STATUS = 0xFD, ++ EVENT_ID_FW_LOG_ENV = 0xFE, /* 0xFE, FW real time debug log */ ++} ENUM_EVENT_ID_T, *P_ENUM_EVENT_ID_T; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef LINUX ++typedef UINT_8 CMD_STATUS; ++#endif ++ ++typedef struct _EVENT_TX_DONE_STATUS_T { ++ UINT_8 ucPacketSeq; ++ UINT_8 ucStatus; ++ UINT_16 u2SequenceNumber; ++ UINT_32 au4Reserved1; ++ UINT_32 au4Reserved2; ++ UINT_32 au4Reserved3; ++ UINT_32 u4PktBufInfo; ++ UINT_8 aucPktBuf[200]; ++} EVENT_TX_DONE_STATUS_T, *P_EVENT_TX_DONE_STATUS_T; ++ ++/* for Event Packet (via HIF-RX) */ ++ /* following CM's documentation v0.7 */ ++typedef struct _WIFI_CMD_T { ++ UINT_16 u2TxByteCount_UserPriority; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucResource_PktType_CSflags; ++ UINT_8 ucCID; ++ UINT_8 ucSetQuery; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2; ++ ++ UINT_8 aucBuffer[0]; ++} WIFI_CMD_T, *P_WIFI_CMD_T; ++ ++/* for Command Packet (via HIF-TX) */ ++ /* following CM's documentation v0.7 */ ++typedef struct _WIFI_EVENT_T { ++ UINT_16 u2PacketLen; ++ UINT_16 u2PacketType; ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ UINT_8 aucBuffer[0]; ++} WIFI_EVENT_T, *P_WIFI_EVENT_T; ++ ++/* CMD_ID_TEST_MODE */ ++typedef struct _CMD_TEST_CTRL_T { ++ UINT_8 ucAction; ++ UINT_8 aucReserved[3]; ++ union { ++ UINT_32 u4OpMode; ++ UINT_32 u4ChannelFreq; ++ PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; ++ } u; ++} CMD_TEST_CTRL_T, *P_CMD_TEST_CTRL_T; ++ ++/* EVENT_TEST_STATUS */ ++typedef struct _PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T { ++ UINT_32 u4PktSentStatus; ++ UINT_32 u4PktSentCount; ++ UINT_16 u2AvgAlc; ++ UINT_8 ucCckGainControl; ++ UINT_8 ucOfdmGainControl; ++} PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T { ++ UINT_32 u4IntRxOk; /*!< number of packets that Rx ok from interrupt */ ++ UINT_32 u4IntCrcErr; /*!< number of packets that CRC error from interrupt */ ++ UINT_32 u4IntShort; /*!< number of packets that is short preamble from interrupt */ ++ UINT_32 u4IntLong; /*!< number of packets that is long preamble from interrupt */ ++ UINT_32 u4PauRxPktCount; /*!< number of packets that Rx ok from PAU */ ++ UINT_32 u4PauCrcErrCount; /*!< number of packets that CRC error from PAU */ ++ UINT_32 u4PauRxFifoFullCount; /*!< number of packets that is short preamble from PAU */ ++ UINT_32 u4PauCCACount; /*!< CCA rising edge count */ ++} PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T; ++ ++typedef union _EVENT_TEST_STATUS { ++ PARAM_MTK_WIFI_TEST_STRUCT_T rATInfo; ++/* PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T rTxStatus; */ ++/* PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T rRxStatus; */ ++} EVENT_TEST_STATUS, *P_EVENT_TEST_STATUS; ++ ++/* CMD_BUILD_CONNECTION */ ++typedef struct _CMD_BUILD_CONNECTION { ++ UINT_8 ucInfraMode; ++ UINT_8 ucAuthMode; ++ UINT_8 ucEncryptStatus; ++ UINT_8 ucSsidLen; ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; ++ ++ /* Ad-hoc mode */ ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2ATIMWindow; ++ UINT_8 ucJoinOnly; ++ UINT_8 ucReserved; ++ UINT_32 u4FreqInKHz; ++ ++ /* for faster connection */ ++ UINT_8 aucScanResult[0]; ++} CMD_BUILD_CONNECTION, *P_CMD_BUILD_CONNECTION; ++ ++/* CMD_ADD_REMOVE_KEY */ ++typedef struct _CMD_802_11_KEY { ++ UINT_8 ucAddRemove; ++ UINT_8 ucTxKey; ++ UINT_8 ucKeyType; ++ UINT_8 ucIsAuthenticator; ++ UINT_8 aucPeerAddr[6]; ++ UINT_8 ucNetType; ++ UINT_8 ucAlgorithmId; ++ UINT_8 ucKeyId; ++ UINT_8 ucKeyLen; ++ UINT_8 aucReverved[2]; ++ UINT_8 aucKeyMaterial[32]; ++ UINT_8 aucKeyRsc[16]; ++} CMD_802_11_KEY, *P_CMD_802_11_KEY; ++ ++/* WPA2 PMKID cache structure */ ++typedef struct _PMKID_ENTRY_T { ++ PARAM_BSSID_INFO_T rBssidInfo; ++ BOOLEAN fgPmkidExist; ++} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; ++ ++typedef struct _CMD_802_11_PMKID { ++ ULONG u4BSSIDInfoCount; ++ P_PMKID_ENTRY_T arPMKIDInfo[1]; ++} CMD_802_11_PMKID, *P_CMD_802_11_PMKID; ++ ++/* CMD_BASIC_CONFIG */ ++typedef struct _CMD_CSUM_OFFLOAD { ++ UINT_16 u2RxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ ++ UINT_16 u2TxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ ++} CMD_CSUM_OFFLOAD, *P_CMD_CSUM_OFFLOAD; ++ ++typedef struct _CMD_BASIC_CONFIG { ++ PARAM_MAC_ADDRESS rMyMacAddr; ++ UINT_8 ucNative80211; ++ UINT_8 aucReserved[1]; ++ ++ CMD_CSUM_OFFLOAD rCsumOffload; ++} CMD_BASIC_CONFIG, *P_CMD_BASIC_CONFIG, EVENT_BASIC_CONFIG, *P_EVENT_BASIC_CONFIG; ++ ++/* CMD_MAC_MCAST_ADDR */ ++typedef struct _CMD_MAC_MCAST_ADDR { ++ UINT_32 u4NumOfGroupAddr; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[3]; ++ PARAM_MAC_ADDRESS arAddress[MAX_NUM_GROUP_ADDR]; ++} CMD_MAC_MCAST_ADDR, *P_CMD_MAC_MCAST_ADDR, EVENT_MAC_MCAST_ADDR, *P_EVENT_MAC_MCAST_ADDR; ++ ++/* CMD_ACCESS_EEPROM */ ++typedef struct _CMD_ACCESS_EEPROM { ++ UINT_16 u2Offset; ++ UINT_16 u2Data; ++} CMD_ACCESS_EEPROM, *P_CMD_ACCESS_EEPROM, EVENT_ACCESS_EEPROM, *P_EVENT_ACCESS_EEPROM; ++ ++typedef struct _CMD_CUSTOM_NOA_PARAM_STRUCT_T { ++ UINT_32 u4NoaDurationMs; ++ UINT_32 u4NoaIntervalMs; ++ UINT_32 u4NoaCount; ++} CMD_CUSTOM_NOA_PARAM_STRUCT_T, *P_CMD_CUSTOM_NOA_PARAM_STRUCT_T; ++ ++typedef struct _CMD_CUSTOM_OPPPS_PARAM_STRUCT_T { ++ UINT_32 u4CTwindowMs; ++} CMD_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_CMD_CUSTOM_OPPPS_PARAM_STRUCT_T; ++ ++typedef struct _CMD_CUSTOM_UAPSD_PARAM_STRUCT_T { ++ UINT_8 fgEnAPSD; ++ UINT_8 fgEnAPSD_AcBe; ++ UINT_8 fgEnAPSD_AcBk; ++ UINT_8 fgEnAPSD_AcVo; ++ UINT_8 fgEnAPSD_AcVi; ++ UINT_8 ucMaxSpLen; ++ UINT_8 aucResv[2]; ++} CMD_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_CMD_CUSTOM_UAPSD_PARAM_STRUCT_T; ++ ++/* EVENT_CONNECTION_STATUS */ ++typedef struct _EVENT_CONNECTION_STATUS { ++ UINT_8 ucMediaStatus; ++ UINT_8 ucReasonOfDisconnect; ++ ++ UINT_8 ucInfraMode; ++ UINT_8 ucSsidLen; ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucAuthenMode; ++ UINT_8 ucEncryptStatus; ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2AID; ++ UINT_16 u2ATIMWindow; ++ UINT_8 ucNetworkType; ++ UINT_8 aucReserved[1]; ++ UINT_32 u4FreqInKHz; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 aucInterfaceAddr[PARAM_MAC_ADDR_LEN]; ++#endif ++ ++} EVENT_CONNECTION_STATUS, *P_EVENT_CONNECTION_STATUS; ++ ++/* EVENT_NIC_CAPABILITY */ ++typedef struct _EVENT_NIC_CAPABILITY { ++ UINT_16 u2ProductID; ++ UINT_16 u2FwVersion; ++ UINT_16 u2DriverVersion; ++ UINT_8 ucHw5GBandDisabled; ++ UINT_8 ucEepromUsed; ++ UINT_8 ucEfuseValid; ++ UINT_8 ucMacAddrValid; ++#if CFG_REPORT_RFBB_VERSION ++ UINT_8 ucRfVersion; ++ UINT_8 ucPhyVersion; ++#endif ++#if CFG_ENABLE_CAL_LOG ++ UINT_8 ucRfCalFail; ++ UINT_8 ucBbCalFail; ++#endif ++ ++#define FEATURE_SET_OFFSET_TDLS 0 ++#define FEATURE_SET_OFFSET_5G_SUPPORT 1 ++ UINT_8 ucFeatureSet; /* bit0: TDLS */ ++ ++ UINT_8 aucReserved[1]; ++#if CFG_EMBED_FIRMWARE_BUILD_DATE_CODE ++ UINT_8 aucDateCode[16]; ++#endif ++} EVENT_NIC_CAPABILITY, *P_EVENT_NIC_CAPABILITY; ++ ++/* modified version of WLAN_BEACON_FRAME_BODY_T for simplier buffering */ ++typedef struct _WLAN_BEACON_FRAME_BODY_T_LOCAL { ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[MAX_IE_LENGTH]; /* Various IEs, start from SSID */ ++ UINT_16 u2IELength; /* This field is *NOT* carried by F/W but caculated by nic_rx */ ++} WLAN_BEACON_FRAME_BODY_T_LOCAL, *P_WLAN_BEACON_FRAME_BODY_T_LOCAL; ++ ++/* EVENT_SCAN_RESULT */ ++typedef struct _EVENT_SCAN_RESULT_T { ++ INT_32 i4RSSI; ++ UINT_32 u4LinkQuality; ++ UINT_32 u4DSConfig; /* Center frequency */ ++ UINT_32 u4DomainInfo; /* Require CM opinion */ ++ UINT_32 u4Reserved; ++ UINT_8 ucNetworkType; ++ UINT_8 ucOpMode; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; ++ WLAN_BEACON_FRAME_BODY_T_LOCAL rBeaconFrameBody; ++} EVENT_SCAN_RESULT_T, *P_EVENT_SCAN_RESULT_T; ++ ++/* event of tkip mic error */ ++typedef struct _EVENT_MIC_ERR_INFO { ++ UINT_32 u4Flags; ++} EVENT_MIC_ERR_INFO, *P_EVENT_MIC_ERR_INFO; ++ ++typedef struct _EVENT_PMKID_CANDIDATE_LIST_T { ++ UINT_32 u4Version; /*!< Version */ ++ UINT_32 u4NumCandidates; /*!< How many candidates follow */ ++ PARAM_PMKID_CANDIDATE_T arCandidateList[1]; ++} EVENT_PMKID_CANDIDATE_LIST_T, *P_EVENT_PMKID_CANDIDATE_LIST_T; ++ ++typedef struct _EVENT_CMD_RESULT { ++ UINT_8 ucCmdID; ++ UINT_8 ucStatus; ++ UINT_8 aucReserved[2]; ++} EVENT_CMD_RESULT, *P_EVENT_CMD_RESULT; ++ ++/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ ++typedef struct _CMD_ACCESS_REG { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} CMD_ACCESS_REG, *P_CMD_ACCESS_REG; ++ ++/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++typedef struct _CMD_ACCESS_CHN_LOAD { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++ UINT_16 u2Channel; ++ UINT_8 aucReserved[2]; ++} CMD_ACCESS_CHN_LOAD, *P_ACCESS_CHN_LOAD; ++ ++#endif ++/* CMD_DUMP_MEMORY */ ++typedef struct _CMD_DUMP_MEM { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++} CMD_DUMP_MEM, *P_CMD_DUMP_MEM; ++ ++typedef struct _EVENT_DUMP_MEM_T { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++ UINT_8 aucBuffer[1]; ++} EVENT_DUMP_MEM_T, *P_EVENT_DUMP_MEM_T; ++ ++typedef struct _CMD_SW_DBG_CTRL_T { ++ UINT_32 u4Id; ++ UINT_32 u4Data; ++ /* Debug Support */ ++ UINT_32 u4DebugCnt[64]; ++} CMD_SW_DBG_CTRL_T, *P_CMD_SW_DBG_CTRL_T; ++ ++/* CMD_ID_LINK_ATTRIB */ ++typedef struct _CMD_LINK_ATTRIB { ++ INT_8 cRssiTrigger; ++ UINT_8 ucDesiredRateLen; ++ UINT_16 u2DesiredRate[32]; ++ UINT_8 ucMediaStreamMode; ++ UINT_8 aucReserved[1]; ++} CMD_LINK_ATTRIB, *P_CMD_LINK_ATTRIB; ++ ++/* CMD_ID_NIC_POWER_CTRL */ ++typedef struct _CMD_NIC_POWER_CTRL { ++ UINT_8 ucPowerMode; ++ UINT_8 aucReserved[3]; ++} CMD_NIC_POWER_CTRL, *P_CMD_NIC_POWER_CTRL; ++ ++/* CMD_ID_POWER_SAVE_MODE */ ++typedef struct _CMD_PS_PROFILE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucPsProfile; ++ UINT_8 aucReserved[2]; ++} CMD_PS_PROFILE_T, *P_CMD_PS_PROFILE_T; ++ ++/* EVENT_LINK_QUALITY */ ++typedef struct _EVENT_LINK_QUALITY { ++ INT_8 cRssi; ++ INT_8 cLinkQuality; ++ UINT_16 u2LinkSpeed; ++ UINT_8 ucMediumBusyPercentage; ++} EVENT_LINK_QUALITY, *P_EVENT_LINK_QUALITY; ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++/* EVENT_LINK_QUALITY */ ++typedef struct _EVENT_LINK_QUALITY_EX { ++ INT_8 cRssi; ++ INT_8 cLinkQuality; ++ UINT_16 u2LinkSpeed; ++ UINT_8 ucMediumBusyPercentage; ++ UINT_8 ucIsLQ0Rdy; ++ INT_8 cRssiP2P; /* For P2P Network. */ ++ INT_8 cLinkQualityP2P; ++ UINT_16 u2LinkSpeedP2P; ++ UINT_8 ucMediumBusyPercentageP2P; ++ UINT_8 ucIsLQ1Rdy; ++} EVENT_LINK_QUALITY_EX, *P_EVENT_LINK_QUALITY_EX; ++#endif ++ ++/* EVENT_ID_STATISTICS */ ++typedef struct _EVENT_STATISTICS { ++ LARGE_INTEGER rTransmittedFragmentCount; ++ LARGE_INTEGER rMulticastTransmittedFrameCount; ++ LARGE_INTEGER rFailedCount; ++ LARGE_INTEGER rRetryCount; ++ LARGE_INTEGER rMultipleRetryCount; ++ LARGE_INTEGER rRTSSuccessCount; ++ LARGE_INTEGER rRTSFailureCount; ++ LARGE_INTEGER rACKFailureCount; ++ LARGE_INTEGER rFrameDuplicateCount; ++ LARGE_INTEGER rReceivedFragmentCount; ++ LARGE_INTEGER rMulticastReceivedFrameCount; ++ LARGE_INTEGER rFCSErrorCount; ++} EVENT_STATISTICS, *P_EVENT_STATISTICS; ++ ++/* EVENT_ID_FW_SLEEPY_NOTIFY */ ++typedef struct _EVENT_SLEEPY_NOTIFY { ++ UINT_8 ucSleepyState; ++ UINT_8 aucReserved[3]; ++} EVENT_SLEEPY_NOTIFY, *P_EVENT_SLEEPY_NOTIFY; ++ ++typedef struct _EVENT_ACTIVATE_STA_REC_T { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucNetworkTypeIndex; ++ BOOLEAN fgIsQoS; ++ BOOLEAN fgIsAP; ++ UINT_8 aucReserved[2]; ++} EVENT_ACTIVATE_STA_REC_T, *P_EVENT_ACTIVATE_STA_REC_T; ++ ++typedef struct _EVENT_DEACTIVATE_STA_REC_T { ++ UINT_8 ucStaRecIdx; ++ UINT_8 aucReserved[3]; ++} EVENT_DEACTIVATE_STA_REC_T, *P_EVENT_DEACTIVATE_STA_REC_T; ++ ++/* CMD_BT_OVER_WIFI */ ++typedef struct _CMD_BT_OVER_WIFI { ++ UINT_8 ucAction; /* 0: query, 1: setup, 2: destroy */ ++ UINT_8 ucChannelNum; ++ PARAM_MAC_ADDRESS rPeerAddr; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 PAL_Capabilities; ++ UINT_8 cMaxTxPower; ++ UINT_8 ucChannelBand; ++ UINT_8 ucReserved[1]; ++} CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI; ++ ++/* EVENT_BT_OVER_WIFI */ ++typedef struct _EVENT_BT_OVER_WIFI { ++ UINT_8 ucLinkStatus; ++ UINT_8 ucSelectedChannel; ++ INT_8 cRSSI; ++ UINT_8 ucReserved[1]; ++} EVENT_BT_OVER_WIFI, *P_EVENT_BT_OVER_WIFI; ++ ++/* Same with DOMAIN_SUBBAND_INFO */ ++typedef struct _CMD_SUBBAND_INFO { ++ UINT_8 ucRegClass; ++ UINT_8 ucBand; ++ UINT_8 ucChannelSpan; ++ UINT_8 ucFirstChannelNum; ++ UINT_8 ucNumChannels; ++ UINT_8 aucReserved[3]; ++} CMD_SUBBAND_INFO, *P_CMD_SUBBAND_INFO; ++ ++/* CMD_SET_DOMAIN_INFO */ ++typedef struct _CMD_SET_DOMAIN_INFO_T { ++ UINT_16 u2CountryCode; ++ UINT_16 u2IsSetPassiveScan; /* 0: set channel domain; 1: set passive scan channel domain */ ++ CMD_SUBBAND_INFO rSubBand[6]; ++ ++ UINT_8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ ++ UINT_8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ ++ UINT_8 aucReserved[2]; ++} CMD_SET_DOMAIN_INFO_T, *P_CMD_SET_DOMAIN_INFO_T; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++/* CMD_SET_PWR_LIMIT_TABLE */ ++typedef struct _CMD_CHANNEL_POWER_LIMIT { ++ UINT_8 ucCentralCh; ++ INT_8 cPwrLimitCCK; ++ INT_8 cPwrLimit20; ++ INT_8 cPwrLimit40; ++ INT_8 cPwrLimit80; ++ INT_8 cPwrLimit160; ++ UINT_8 ucFlag; ++ UINT_8 aucReserved[1]; ++} CMD_CHANNEL_POWER_LIMIT, *P_CMD_CHANNEL_POWER_LIMIT; ++ ++typedef struct _CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T { ++ UINT_16 u2CountryCode; ++ UINT_8 ucCountryFlag; ++ UINT_8 ucNum; ++ UINT_8 aucReserved[4]; ++ CMD_CHANNEL_POWER_LIMIT rChannelPowerLimit[1]; ++} CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T, *P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T; ++ ++#endif ++ ++/* CMD_SET_IP_ADDRESS */ ++typedef struct _IPV4_NETWORK_ADDRESS { ++ UINT_8 aucIpAddr[4]; ++} IPV4_NETWORK_ADDRESS, *P_IPV4_NETWORK_ADDRESS; ++ ++typedef struct _CMD_SET_NETWORK_ADDRESS_LIST { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucAddressCount; ++ UINT_8 ucReserved[2]; ++ IPV4_NETWORK_ADDRESS arNetAddress[1]; ++} CMD_SET_NETWORK_ADDRESS_LIST, *P_CMD_SET_NETWORK_ADDRESS_LIST; ++ ++typedef struct _PATTERN_DESCRIPTION { ++ UINT_8 fgCheckBcA1; ++ UINT_8 fgCheckMcA1; ++ UINT_8 ePatternHeader; ++ UINT_8 fgAndOp; ++ UINT_8 fgNotOp; ++ UINT_8 ucPatternMask; ++ UINT_16 ucPatternOffset; ++ UINT_8 aucPattern[8]; ++} PATTERN_DESCRIPTION, *P_PATTERN_DESCRIPTION; ++ ++typedef struct _CMD_RAW_PATTERN_CONFIGURATION_T { ++ PATTERN_DESCRIPTION arPatternDesc[4]; ++} CMD_RAW_PATTERN_CONFIGURATION_T, *P_CMD_RAW_PATTERN_CONFIGURATION_T; ++ ++typedef struct _CMD_PATTERN_FUNC_CONFIG { ++ BOOLEAN fgBcA1En; ++ BOOLEAN fgMcA1En; ++ BOOLEAN fgBcA1MatchDrop; ++ BOOLEAN fgMcA1MatchDrop; ++} CMD_PATTERN_FUNC_CONFIG, *P_CMD_PATTERN_FUNC_CONFIG; ++ ++typedef struct _EVENT_TX_DONE_T { ++ UINT_8 ucPacketSeq; ++ UINT_8 ucStatus; ++ UINT_16 u2SequenceNumber; ++ UINT_32 au4Reserved1; ++ UINT_32 au4Reserved2; ++ UINT_32 au4Reserved3; ++} EVENT_TX_DONE_T, *P_EVENT_TX_DONE_T; ++ ++typedef struct _CMD_BSS_ACTIVATE_CTRL { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucActive; ++ UINT_8 aucReserved[2]; ++} CMD_BSS_ACTIVATE_CTRL, *P_CMD_BSS_ACTIVATE_CTRL; ++ ++typedef struct _CMD_SET_BSS_RLM_PARAM_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucRfBand; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucErpProtectMode; ++ UINT_8 ucHtProtectMode; ++ UINT_8 ucGfOperationMode; ++ UINT_8 ucTxRifsMode; ++ UINT_16 u2HtOpInfo3; ++ UINT_16 u2HtOpInfo2; ++ UINT_8 ucHtOpInfo1; ++ UINT_8 ucUseShortPreamble; ++ UINT_8 ucUseShortSlotTime; ++ UINT_8 ucCheckId; /* Fixed value: 0x72 */ ++} CMD_SET_BSS_RLM_PARAM_T, *P_CMD_SET_BSS_RLM_PARAM_T; ++ ++typedef struct _CMD_SET_BSS_INFO { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucConnectionState; ++ UINT_8 ucCurrentOPMode; ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[32]; ++ UINT_8 aucBSSID[6]; ++ UINT_8 ucIsQBSS; ++ UINT_8 ucReserved1; ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ UINT_8 ucStaRecIdxOfAP; ++ UINT_8 ucReserved2; ++ UINT_8 ucReserved3; ++ UINT_8 ucNonHTBasicPhyType; /* For Slot Time and CWmin */ ++ UINT_8 ucAuthMode; ++ UINT_8 ucEncStatus; ++ UINT_8 ucPhyTypeSet; ++ UINT_8 aucOwnMac[6]; ++ UINT_8 fgWapiMode; ++ UINT_8 fgIsApMode; ++ UINT_8 fgHiddenSsidMode; ++ CMD_SET_BSS_RLM_PARAM_T rBssRlmParam; ++} CMD_SET_BSS_INFO, *P_CMD_SET_BSS_INFO; ++ ++typedef struct _CMD_UPDATE_STA_RECORD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucStaType; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_16 u2AssocId; ++ UINT_16 u2ListenInterval; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDesiredPhyTypeSet; ++ UINT_16 u2DesiredNonHTRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ UINT_8 ucIsQoS; ++ UINT_8 ucIsUapsdSupported; ++ UINT_8 ucStaState; ++ UINT_8 ucMcsSet; ++ UINT_8 ucSupMcs32; ++ UINT_8 ucAmpduParam; ++ UINT_16 u2HtCapInfo; ++ UINT_16 u2HtExtendedCap; ++ UINT_32 u4TxBeamformingCap; ++ UINT_8 ucAselCap; ++ UINT_8 ucRCPI; ++ UINT_8 ucNeedResp; ++ UINT_8 ucUapsdAc; /* b0~3: Trigger enabled, b4~7: Delivery enabled */ ++ UINT_8 ucUapsdSp; /* 0: all, 1: max 2, 2: max 4, 3: max 6 */ ++ UINT_8 aucReserved[3]; ++ /* TBD */ ++} CMD_UPDATE_STA_RECORD_T, *P_CMD_UPDATE_STA_RECORD_T; ++ ++typedef struct _CMD_REMOVE_STA_RECORD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucReserved; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++} CMD_REMOVE_STA_RECORD_T, *P_CMD_REMOVE_STA_RECORD_T; ++ ++typedef struct _CMD_INDICATE_PM_BSS_CREATED_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDtimPeriod; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2AtimWindow; ++ UINT_8 aucReserved[2]; ++} CMD_INDICATE_PM_BSS_CREATED, *P_CMD_INDICATE_PM_BSS_CREATED; ++ ++typedef struct _CMD_INDICATE_PM_BSS_CONNECTED_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDtimPeriod; ++ UINT_16 u2AssocId; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2AtimWindow; ++ UINT_8 fgIsUapsdConnection; ++ UINT_8 ucBmpDeliveryAC; ++ UINT_8 ucBmpTriggerAC; ++ UINT_8 aucReserved[1]; ++} CMD_INDICATE_PM_BSS_CONNECTED, *P_CMD_INDICATE_PM_BSS_CONNECTED; ++ ++typedef struct _CMD_INDICATE_PM_BSS_ABORT { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[3]; ++} CMD_INDICATE_PM_BSS_ABORT, *P_CMD_INDICATE_PM_BSS_ABORT; ++ ++typedef struct _CMD_BEACON_TEMPLATE_UPDATE { ++ UINT_8 ucUpdateMethod; /* 0: update randomly, ++ * 1: update all, ++ * 2: delete all (1 and 2 will update directly without search) ++ */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_16 u2Capability; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_BEACON_TEMPLATE_UPDATE, *P_CMD_BEACON_TEMPLATE_UPDATE; ++ ++typedef struct _CMD_SET_WMM_PS_TEST_STRUCT_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ ++ UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ ++} CMD_SET_WMM_PS_TEST_STRUCT_T, *P_CMD_SET_WMM_PS_TEST_STRUCT_T; ++ ++/* Definition for CHANNEL_INFO.ucBand: ++ * 0: Reserved ++ * 1: BAND_2G4 ++ * 2: BAND_5G ++ * Others: Reserved ++ */ ++typedef struct _CHANNEL_INFO_T { ++ UINT_8 ucBand; ++ UINT_8 ucChannelNum; ++} CHANNEL_INFO_T, *P_CHANNEL_INFO_T; ++ ++typedef struct _CMD_SCAN_REQ_EXT_CH_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucReserved[1]; ++ UINT_16 u2ChannelMinDwellTime; ++ UINT_8 aucSSID[32]; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_EXT_CH, *P_CMD_SCAN_REQ_EXT_CH; ++ ++typedef struct _CMD_SCAN_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucReserved[1]; ++ UINT_16 u2ChannelMinDwellTime; ++ UINT_8 aucSSID[32]; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[32]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ, *P_CMD_SCAN_REQ; ++ ++typedef struct _CMD_SCAN_REQ_V2_EXT_CH_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; ++ PARAM_SSID_T arSSID[4]; ++ UINT_16 u2ProbeDelayTime; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_V2_EXT_CH, *P_CMD_SCAN_REQ_V2_EXT_CH; ++ ++typedef struct _CMD_SCAN_REQ_V2_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; ++ PARAM_SSID_T arSSID[4]; ++ UINT_16 u2ProbeDelayTime; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[32]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_V2, *P_CMD_SCAN_REQ_V2; ++ ++typedef struct _CMD_SCAN_CANCEL_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucIsExtChannel; /* For P2P channel extension. */ ++ UINT_8 aucReserved[2]; ++} CMD_SCAN_CANCEL, *P_CMD_SCAN_CANCEL; ++ ++typedef struct _EVENT_SCAN_DONE_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucSparseChannelValid; ++ CHANNEL_INFO_T rSparseChannel; ++} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; ++ ++#if CFG_SUPPORT_GET_CH_ENV ++typedef struct _CH_ENV_T { ++ UINT_8 ucChNum; ++ UINT_8 ucApNum; ++} CH_ENV_T, *P_CH_ENV_T; ++#endif ++ ++#if 0 /* CFG_SUPPORT_BATCH_SCAN */ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd ++ like approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++typedef struct _EVENT_BATCH_RESULT_ENTRY_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ INT_8 cRssi; ++ UINT_32 ucFreq; ++ UINT_32 u4Age; ++ UINT_32 u4Dist; ++ UINT_32 u4Distsd; ++} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; ++ ++typedef struct _EVENT_BATCH_RESULT_T { ++ UINT_8 ucScanCount; ++ UINT_8 aucReserved[3]; ++ EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ ++} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; ++#endif ++ ++typedef struct _CMD_CH_PRIVILEGE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucAction; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucRfBand; ++ UINT_8 ucReqType; ++ UINT_8 ucReserved; ++ UINT_32 u4MaxInterval; /* In unit of ms */ ++ UINT_8 aucBSSID[6]; ++ UINT_8 aucReserved[2]; ++} CMD_CH_PRIVILEGE_T, *P_CMD_CH_PRIVILEGE_T; ++ ++typedef struct _CMD_TX_PWR_T { ++ INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ ++#if defined(MT6620) ++ INT_8 acReserved[3]; ++#elif defined(MT6628) ++ INT_8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ ++ INT_8 acReserved[2]; ++#else ++#error "No valid definition!" ++#endif ++ ++ INT_8 cTxPwr2G4OFDM_BPSK; ++ INT_8 cTxPwr2G4OFDM_QPSK; ++ INT_8 cTxPwr2G4OFDM_16QAM; ++ INT_8 cTxPwr2G4OFDM_Reserved; ++ INT_8 cTxPwr2G4OFDM_48Mbps; ++ INT_8 cTxPwr2G4OFDM_54Mbps; ++ ++ INT_8 cTxPwr2G4HT20_BPSK; ++ INT_8 cTxPwr2G4HT20_QPSK; ++ INT_8 cTxPwr2G4HT20_16QAM; ++ INT_8 cTxPwr2G4HT20_MCS5; ++ INT_8 cTxPwr2G4HT20_MCS6; ++ INT_8 cTxPwr2G4HT20_MCS7; ++ ++ INT_8 cTxPwr2G4HT40_BPSK; ++ INT_8 cTxPwr2G4HT40_QPSK; ++ INT_8 cTxPwr2G4HT40_16QAM; ++ INT_8 cTxPwr2G4HT40_MCS5; ++ INT_8 cTxPwr2G4HT40_MCS6; ++ INT_8 cTxPwr2G4HT40_MCS7; ++ ++ INT_8 cTxPwr5GOFDM_BPSK; ++ INT_8 cTxPwr5GOFDM_QPSK; ++ INT_8 cTxPwr5GOFDM_16QAM; ++ INT_8 cTxPwr5GOFDM_Reserved; ++ INT_8 cTxPwr5GOFDM_48Mbps; ++ INT_8 cTxPwr5GOFDM_54Mbps; ++ ++ INT_8 cTxPwr5GHT20_BPSK; ++ INT_8 cTxPwr5GHT20_QPSK; ++ INT_8 cTxPwr5GHT20_16QAM; ++ INT_8 cTxPwr5GHT20_MCS5; ++ INT_8 cTxPwr5GHT20_MCS6; ++ INT_8 cTxPwr5GHT20_MCS7; ++ ++ INT_8 cTxPwr5GHT40_BPSK; ++ INT_8 cTxPwr5GHT40_QPSK; ++ INT_8 cTxPwr5GHT40_16QAM; ++ INT_8 cTxPwr5GHT40_MCS5; ++ INT_8 cTxPwr5GHT40_MCS6; ++ INT_8 cTxPwr5GHT40_MCS7; ++} CMD_TX_PWR_T, *P_CMD_TX_PWR_T; ++ ++typedef struct _CMD_5G_PWR_OFFSET_T { ++ INT_8 cOffsetBand0; /* 4.915-4.980G */ ++ INT_8 cOffsetBand1; /* 5.000-5.080G */ ++ INT_8 cOffsetBand2; /* 5.160-5.180G */ ++ INT_8 cOffsetBand3; /* 5.200-5.280G */ ++ INT_8 cOffsetBand4; /* 5.300-5.340G */ ++ INT_8 cOffsetBand5; /* 5.500-5.580G */ ++ INT_8 cOffsetBand6; /* 5.600-5.680G */ ++ INT_8 cOffsetBand7; /* 5.700-5.825G */ ++} CMD_5G_PWR_OFFSET_T, *P_CMD_5G_PWR_OFFSET_T; ++ ++typedef struct _CMD_PWR_PARAM_T { ++ UINT_32 au4Data[28]; ++ UINT_32 u4RefValue1; ++ UINT_32 u4RefValue2; ++} CMD_PWR_PARAM_T, *P_CMD_PWR_PARAM_T; ++ ++typedef struct _CMD_PHY_PARAM_T { ++ UINT_8 aucData[144]; /* eFuse content */ ++} CMD_PHY_PARAM_T, *P_CMD_PHY_PARAM_T; ++ ++typedef struct _CMD_AUTO_POWER_PARAM_T { ++ UINT_8 ucType; /* 0: Disable 1: Enalbe 0x10: Change parameters */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_8 aucLevelRcpiTh[3]; ++ UINT_8 aucReserved2[1]; ++ INT_8 aicLevelPowerOffset[3]; /* signed, in unit of 0.5dBm */ ++ UINT_8 aucReserved3[1]; ++ UINT_8 aucReserved4[8]; ++} CMD_AUTO_POWER_PARAM_T, *P_CMD_AUTO_POWER_PARAM_T; ++ ++typedef struct _EVENT_CH_PRIVILEGE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucStatus; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucRfBand; ++ UINT_8 ucReqType; ++ UINT_8 ucReserved; ++ UINT_32 u4GrantInterval; /* In unit of ms */ ++} EVENT_CH_PRIVILEGE_T, *P_EVENT_CH_PRIVILEGE_T; ++ ++typedef enum _ENUM_BEACON_TIMEOUT_TYPE_T { ++ BEACON_TIMEOUT_LOST_BEACON = 0, ++ BEACON_TIMEOUT_AGE, ++ BEACON_TIMEOUT_CONNECT, ++ BEACON_TIMEOUT_BEACON_INTERVAL, ++ BEACON_TIMEOUT_ABORT, ++ BEACON_TIMEOUT_TX_ERROR, ++ BEACON_TIMEOUT_TYPE_NUM ++} ENUM_BEACON_TIMEOUT_TYPE_T, *P_ENUM_BEACON_TIMEOUT_TYPE_T; ++ ++typedef struct _EVENT_BSS_BEACON_TIMEOUT_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucReason; /* ENUM_BEACON_TIMEOUT_TYPE_T */ ++ UINT_8 aucReserved[2]; ++} EVENT_BSS_BEACON_TIMEOUT_T, *P_EVENT_BSS_BEACON_TIMEOUT_T; ++ ++typedef struct _EVENT_STA_AGING_TIMEOUT_T { ++ UINT_8 ucStaRecIdx; ++ UINT_8 aucReserved[3]; ++} EVENT_STA_AGING_TIMEOUT_T, *P_EVENT_STA_AGING_TIMEOUT_T; ++ ++typedef struct _EVENT_NOA_TIMING_T { ++ UINT_8 fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 ucCount; /* Count */ ++ UINT_8 aucReserved[2]; ++ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} EVENT_NOA_TIMING_T, *P_EVENT_NOA_TIMING_T; ++ ++typedef struct _EVENT_UPDATE_NOA_PARAMS_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_8 fgEnableOppPS; ++ UINT_16 u2CTWindow; ++ ++ UINT_8 ucNoAIndex; ++ UINT_8 ucNoATimingCount; /* Number of NoA Timing */ ++ EVENT_NOA_TIMING_T arEventNoaTiming[8 /*P2P_MAXIMUM_NOA_COUNT */]; ++} EVENT_UPDATE_NOA_PARAMS_T, *P_EVENT_UPDATE_NOA_PARAMS_T; ++ ++typedef struct _EVENT_AP_OBSS_STATUS_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucObssErpProtectMode; ++ UINT_8 ucObssHtProtectMode; ++ UINT_8 ucObssGfOperationMode; ++ UINT_8 ucObssRifsOperationMode; ++ UINT_8 ucObssBeaconForcedTo20M; ++ UINT_8 aucReserved[2]; ++} EVENT_AP_OBSS_STATUS_T, *P_EVENT_AP_OBSS_STATUS_T; ++ ++typedef struct _CMD_EDGE_TXPWR_LIMIT_T { ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ INT_8 cReserved; ++} CMD_EDGE_TXPWR_LIMIT_T, *P_CMD_EDGE_TXPWR_LIMIT_T; ++ ++typedef struct _CMD_RSSI_COMPENSATE_T { ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 ucRssiCompensationValidbit; ++ UINT_8 cReserved; ++} CMD_RSSI_COMPENSATE_T, *P_CMD_RSSI_COMPENSATE_T; ++ ++typedef struct _CMD_BAND_SUPPORT_T { ++ UINT_8 uc5GBandSupport; ++ UINT_8 cReserved[3]; ++} CMD_BAND_SUPPORT_T, *P_CMD_BAND_SUPPORT_T; ++ ++typedef struct _CMD_TX_PWR_CE_T { ++ INT_8 cTxPwrCckLmt; /* signed, in unit of 0.5dBm */ ++ INT_8 cTxPwrOfdmLmt; /* signed, in unit of 0.5dBm */ ++ INT_8 cTxPwrHt20Lmt; ++ INT_8 cTxPwrHt40Lmt; ++} CMD_TX_PWR_CE_T, *P_CMD_TX_PWR_CE_T; ++ ++typedef struct _CMD_SET_DEVICE_MODE_T { ++ UINT_16 u2ChipID; ++ UINT_16 u2Mode; ++} CMD_SET_DEVICE_MODE_T, *P_CMD_SET_DEVICE_MODE_T; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++typedef struct _CMD_RDD_CH_T { ++ UINT_8 ucRddTestMode; ++ UINT_8 ucRddShutCh; ++ UINT_8 ucRddStartCh; ++ UINT_8 ucRddStopCh; ++ UINT_8 ucRddDfs; ++ UINT_8 ucReserved; ++ UINT_8 ucReserved1; ++ UINT_8 ucReserved2; ++} CMD_RDD_CH_T, *P_CMD_RDD_CH_T; ++ ++typedef struct _EVENT_RDD_STATUS_T { ++ UINT_8 ucRddStatus; ++ UINT_8 aucReserved[3]; ++} EVENT_RDD_STATUS_T, *P_EVENT_RDD_STATUS_T; ++#endif ++ ++typedef struct _EVENT_AIS_BSS_INFO_T { ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ ++ ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ ++ BOOLEAN fgIsNetActive; /* TRUE if this network has been actived */ ++ UINT_8 ucReserved[3]; ++} EVENT_AIS_BSS_INFO_T, *P_EVENT_AIS_BSS_INFO_T; ++ ++typedef struct _CMD_SET_TXPWR_CTRL_T { ++ INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c2GHotspotPwrOffset; ++ INT_8 c2GP2pPwrOffset; ++ INT_8 c2GBowPwrOffset; ++ INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c5GHotspotPwrOffset; ++ INT_8 c5GP2pPwrOffset; ++ INT_8 c5GBowPwrOffset; ++ UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence ++ in the same channel ++ 0: Highest power has priority ++ 1: Lowest power has priority */ ++ INT_8 acReserved1[3]; /* Must be zero */ ++ ++ /* Power limit by channel for all data rates */ ++ INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ ++ INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ ++ INT_8 acReserved2[2]; /* Must be zero */ ++} CMD_SET_TXPWR_CTRL_T, *P_CMD_SET_TXPWR_CTRL_T; ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++typedef struct _CMD_GET_BUILD_DATE_CODE { ++ UINT_8 aucReserved[4]; ++} CMD_GET_BUILD_DATE_CODE, *P_CMD_GET_BUILD_DATE_CODE; ++ ++typedef struct _EVENT_BUILD_DATE_CODE { ++ UINT_8 aucDateCode[16]; ++} EVENT_BUILD_DATE_CODE, *P_EVENT_BUILD_DATE_CODE; ++#endif ++ ++typedef struct _CMD_GET_STA_STATISTICS_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 ucReadClear; ++ UINT_8 aucReserved0[1]; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucReserved2[16]; ++} CMD_GET_STA_STATISTICS_T, *P_CMD_GET_STA_STATISTICS_T; ++ ++/* CFG_SUPPORT_WFD */ ++typedef struct _EVENT_STA_STATISTICS_T { ++ /* Event header */ ++ /* UINT_16 u2Length; */ ++ /* UINT_16 u2Reserved1; *//* Must be filled with 0x0001 (EVENT Packet) */ ++ /* UINT_8 ucEID; */ ++ /* UINT_8 ucSeqNum; */ ++ /* UINT_8 aucReserved2[2]; */ ++ ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucNetworkTypeIndex; ++ UINT_8 ucWTEntry; ++ UINT_8 aucReserved4[1]; ++ ++ UINT_8 ucMacAddr[MAC_ADDR_LEN]; ++ UINT_8 ucPer; /* base: 128 */ ++ UINT_8 ucRcpi; ++ ++ UINT_32 u4PhyMode; /* SGI BW */ ++ UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ ++ UINT_8 ucLinkQuality; ++ UINT_8 ucLinkReserved; ++ ++ UINT_32 u4TxCount; ++ UINT_32 u4TxFailCount; ++ UINT_32 u4TxLifeTimeoutCount; ++ UINT_32 u4TxDoneAirTime; ++ ++ UINT_8 aucReserved[64]; ++} EVENT_STA_STATISTICS_T, *P_EVENT_STA_STATISTICS_T; ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++typedef struct _CMD_HOTSPOT_OPTIMIZATION_CONFIG { ++ UINT_32 fgHotspotOptimizationEn; ++ UINT_32 u4Level; ++} CMD_HOTSPOT_OPTIMIZATION_CONFIG, *P_HOTSPOT_OPTIMIZATION_CONFIG; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++ ++typedef struct _CMD_GET_CHN_LOAD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 ucReadClear; ++ UINT_8 aucReserved0[1]; ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 aucReserved1[1]; ++ UINT_8 aucReserved2[16]; ++} CMD_GET_CHN_LOAD_T, *P_CMD_GET_CHN_LOAD_T; ++/* 4 Auto Channel Selection */ ++ ++typedef struct _EVENT_CHN_LOAD_T { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 aucReserved4[1]; ++ ++ UINT_8 aucReserved[64]; ++ ++} EVENT_CHN_LOAD_T, *P_EVENT_CHN_LOAD_T; ++typedef struct _CMD_GET_LTE_SAFE_CHN_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 aucReserved0[2]; ++ ++ UINT_8 aucReserved2[16]; ++} CMD_GET_LTE_SAFE_CHN_T, *P_CMD_GET_LTE_SAFE_CHN_T; ++ ++typedef struct _EVENT_LTE_MODE_T { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ LTE_SAFE_CH_INFO_T rLteSafeChn; ++ UINT_8 aucReserved4[3]; ++ ++ UINT_8 aucReserved[4]; ++ ++} EVENT_LTE_MODE_T, *P_EVENT_LTE_MODE_T; ++#endif ++typedef struct _CMD_ROAMING_INFO_T { ++ UINT_32 fgIsFastRoamingApplied; ++ UINT_32 Reserved[9]; ++} CMD_ROAMING_INFO_T; ++ ++typedef struct _CMD_WFD_DEBUG_MODE_INFO_T { ++ UINT_8 ucDebugMode; ++ UINT_16 u2PeriodInteval; ++ UINT_8 Reserved; ++} CMD_WFD_DEBUG_MODE_INFO_T, *P_CMD_WFD_DEBUG_MODE_INFO_T; ++ ++typedef struct _EVENT_FW_LOG_T { ++ UINT_8 fileName[64]; ++ UINT_32 lineNo; ++ UINT_32 WifiUpTime; ++ UINT_8 log[896]; /* total size is aucBuffer in WIFI_EVENT_T */ ++} EVENT_FW_LOG_T, *P_EVENT_FW_LOG_T; ++ ++typedef enum _ENUM_NLO_CIPHER_ALGORITHM { ++ NLO_CIPHER_ALGO_NONE = 0x00, ++ NLO_CIPHER_ALGO_WEP40 = 0x01, ++ NLO_CIPHER_ALGO_TKIP = 0x02, ++ NLO_CIPHER_ALGO_CCMP = 0x04, ++ NLO_CIPHER_ALGO_WEP104 = 0x05, ++ NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, ++ NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, ++ NLO_CIPHER_ALGO_WEP = 0x101, ++} ENUM_NLO_CIPHER_ALGORITHM, *P_ENUM_NLO_CIPHER_ALGORITHM; ++ ++typedef enum _ENUM_NLO_AUTH_ALGORITHM { ++ NLO_AUTH_ALGO_80211_OPEN = 1, ++ NLO_AUTH_ALGO_80211_SHARED_KEY = 2, ++ NLO_AUTH_ALGO_WPA = 3, ++ NLO_AUTH_ALGO_WPA_PSK = 4, ++ NLO_AUTH_ALGO_WPA_NONE = 5, ++ NLO_AUTH_ALGO_RSNA = 6, ++ NLO_AUTH_ALGO_RSNA_PSK = 7, ++} ENUM_NLO_AUTH_ALGORITHM, *P_ENUM_NLO_AUTH_ALGORITHM; ++ ++typedef struct _NLO_NETWORK { ++ UINT_8 ucNumChannelHint[4]; ++ UINT_8 ucSSIDLength; ++ UINT_8 ucCipherAlgo; ++ UINT_16 u2AuthAlgo; ++ UINT_8 aucSSID[32]; ++} NLO_NETWORK, *P_NLO_NETWORK; ++ ++typedef struct _CMD_NLO_REQ { ++ UINT_8 ucSeqNum; ++ UINT_8 ucBssIndex; ++ UINT_8 ucNetworkType; ++ UINT_8 fgStopAfterIndication; ++ UINT_8 ucFastScanIteration; ++ UINT_16 u2FastScanPeriod; ++ UINT_16 u2SlowScanPeriod; ++ UINT_8 ucEntryNum; ++ UINT_8 ucReserved; ++ UINT_16 u2IELen; ++ NLO_NETWORK arNetworkList[16]; ++ UINT_8 aucIE[0]; ++ UINT_8 ucScanType; ++} CMD_NLO_REQ, *P_CMD_NLO_REQ; ++ ++typedef struct _CMD_NLO_CANCEL_T { ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved[3]; ++} CMD_NLO_CANCEL, *P_CMD_NLO_CANCEL; ++ ++typedef struct _EVENT_NLO_DONE_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucStatus; ++ UINT_8 aucReserved[2]; ++} EVENT_NLO_DONE_T, *P_EVENT_NLO_DONE_T; ++ ++typedef struct _EVENT_GSCAN_CAPABILITY_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4MaxScanCacheSize; ++ UINT_32 u4MaxScanBuckets; ++ UINT_32 u4MaxApCachePerScan; ++ UINT_32 u4MaxRssiSampleSize; ++ UINT_32 u4MaxScanReportingThreshold; ++ UINT_32 u4MaxHotlistAps; ++ UINT_32 u4MaxSignificantWifiChangeAps; ++ UINT_32 au4Reserved[4]; ++} EVENT_GSCAN_CAPABILITY_T, *P_EVENT_GSCAN_CAPABILITY_T; ++ ++typedef struct _EVENT_GSCAN_SCAN_AVAILABLE_T { ++ UINT_16 u2Num; ++ UINT_8 aucReserved[2]; ++} EVENT_GSCAN_SCAN_AVAILABLE_T, *P_EVENT_GSCAN_SCAN_AVAILABLE_T; ++ ++typedef struct _EVENT_GSCAN_SCAN_COMPLETE_T { ++ UINT_8 ucScanState; ++ UINT_8 aucReserved[3]; ++} EVENT_GSCAN_SCAN_COMPLETE_T, *P_EVENT_GSCAN_SCAN_COMPLETE_T; ++ ++typedef struct WIFI_GSCAN_RESULT { ++ UINT_64 u8Ts; /* Time of discovery */ ++ UINT_8 arSsid[ELEM_MAX_LEN_SSID + 1]; /* null terminated */ ++ UINT_8 arMacAddr[6]; /* BSSID */ ++ UINT_32 u4Channel; /* channel frequency in MHz */ ++ INT_32 i4Rssi; /* in db */ ++ UINT_64 u8Rtt; /* in nanoseconds */ ++ UINT_64 u8RttSd; /* standard deviation in rtt */ ++ UINT_16 u2BeaconPeriod; /* units are Kusec */ ++ UINT_16 u2Capability; /* Capability information */ ++ UINT_32 u4IeLength; /* byte length of Information Elements */ ++ UINT_8 ucIeData[1]; /* IE data to follow */ ++} WIFI_GSCAN_RESULT_T, *P_WIFI_GSCAN_RESULT_T; ++ ++typedef struct _EVENT_GSCAN_RESULT_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ UINT_16 u2ScanId; ++ UINT_16 u2ScanFlags; ++ UINT_16 u2NumOfResults; ++ WIFI_GSCAN_RESULT_T rResult[1]; ++} EVENT_GSCAN_RESULT_T, *P_EVENT_GSCAN_RESULT_T; ++ ++typedef struct _EVENT_GSCAN_FULL_RESULT_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ WIFI_GSCAN_RESULT_T rResult; ++} EVENT_GSCAN_FULL_RESULT_T, *P_EVENT_GSCAN_FULL_RESULT_T; ++ ++typedef struct GSCAN_SWC_NET { ++ UINT_16 u2Flags; ++ UINT_16 u2Channel; ++ UINT_8 arBssid[6]; ++ INT_8 aicRssi[SCN_PSCAN_SWC_RSSI_WIN_MAX]; ++} GSCAN_SWC_NET_T, P_GSCAN_SWC_NET_T; ++ ++typedef struct _EVENT_GSCAN_SIGNIFICANT_CHANGE_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ GSCAN_SWC_NET_T arNet[SCN_PSCAN_SWC_MAX_NUM]; ++} EVENT_GSCAN_SIGNIFICANT_CHANGE_T, *P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T; ++ ++typedef struct _EVENT_GSCAN_GEOFENCE_FOUND_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ WIFI_GSCAN_RESULT_T rResult[SCN_PSCAN_HOTLIST_REPORT_MAX_NUM]; ++} EVENT_GSCAN_GEOFENCE_FOUND_T, *P_EVENT_GSCAN_GEOFENCE_FOUND_T; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++#if 0 /* !CFG_SUPPORT_GSCN */ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which ++ we'd like approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++#endif ++ ++typedef struct _EVENT_BATCH_RESULT_ENTRY_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ INT_8 cRssi; ++ UINT_32 ucFreq; ++ UINT_32 u4Age; ++ UINT_32 u4Dist; ++ UINT_32 u4Distsd; ++} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; ++ ++typedef struct _EVENT_BATCH_RESULT_T { ++ UINT_8 ucScanCount; ++ UINT_8 aucReserved[3]; ++ EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ ++} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; ++#endif ++ ++typedef struct _CMD_RLM_INFO_T { ++ UINT_32 u4Version; ++ UINT_32 fgIsErrRatioEnhanceApplied; ++ UINT_8 ucErrRatio2LimitMinRate; ++ /* ++ 0:1M, 1:2M, 2:5.5M, 3:11M, 6:6M, 7:9M, 8:12M, 9:18M, 10:24M, 11:36M, 12:48M, 13:54M ++ */ ++ UINT_8 ucMinLegacyRateIdx; ++ INT_8 cMinRssiThreshold; ++ BOOLEAN fgIsRtsApplied; ++ UINT_8 ucRecoverTime; ++ ++ UINT_32 u4Reserved[0]; ++} CMD_RLM_INFO_T; ++ ++typedef struct _WIFI_SYSTEM_SUSPEND_CMD_T { ++ BOOLEAN fgIsSystemSuspend; ++ UINT_8 reserved[3]; ++} WIFI_SYSTEM_SUSPEND_CMD_T, *P_WIFI_SYSTEM_SUSPEND_CMD_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/* Statistics responder */ ++VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/* for timeout check */ ++VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++/* 4 Auto Channel Selection */ ++VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++#if CFG_SUPPORT_BATCH_SCAN ++VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_CMD_EVENT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h +new file mode 100644 +index 000000000000..994c589190de +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h +@@ -0,0 +1,177 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_init_cmd_event.h#1 ++*/ ++ ++/*! \file "nic_init_cmd_event.h" ++ \brief This file contains the declairation file of the WLAN initialization routines ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: nic_init_cmd_event.h ++ * ++ * 09 26 2011 cp.wu ++ * [WCXRP00001011] [MT6628 Wi-Fi] Firmware Download Agent: make CRC validation as an optional feature ++ * add definition for disabling CRC32 validation (for MT6628 only) ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add command/event definitions for initial states ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++*/ ++#ifndef _NIC_INIT_CMD_EVENT_H ++#define _NIC_INIT_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define INIT_CMD_STATUS_SUCCESS 0 ++#define INIT_CMD_STATUS_REJECTED_INVALID_PARAMS 1 ++#define INIT_CMD_STATUS_REJECTED_CRC_ERROR 2 ++#define INIT_CMD_STATUS_REJECTED_DECRYPT_FAIL 3 ++#define INIT_CMD_STATUS_UNKNOWN 4 ++ ++#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) ++ ++typedef enum _ENUM_INIT_CMD_ID { ++ INIT_CMD_ID_DOWNLOAD_BUF = 1, ++ INIT_CMD_ID_WIFI_START, ++ INIT_CMD_ID_ACCESS_REG, ++ INIT_CMD_ID_QUERY_PENDING_ERROR ++} ENUM_INIT_CMD_ID, *P_ENUM_INIT_CMD_ID; ++ ++typedef enum _ENUM_INIT_EVENT_ID { ++ INIT_EVENT_ID_CMD_RESULT = 1, ++ INIT_EVENT_ID_ACCESS_REG, ++ INIT_EVENT_ID_PENDING_ERROR ++} ENUM_INIT_EVENT_ID, *P_ENUM_INIT_EVENT_ID; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_8 CMD_STATUS; ++ ++/* commands */ ++typedef struct _INIT_WIFI_CMD_T { ++ UINT_8 ucCID; ++ UINT_8 ucSeqNum; ++ UINT_16 u2Reserved; ++ UINT_8 aucBuffer[0]; ++} INIT_WIFI_CMD_T, *P_INIT_WIFI_CMD_T; ++ ++typedef struct _INIT_HIF_TX_HEADER_T { ++ UINT_16 u2TxByteCount; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucCSflags; ++ INIT_WIFI_CMD_T rInitWifiCmd; ++} INIT_HIF_TX_HEADER_T, *P_INIT_HIF_TX_HEADER_T; ++ ++#define DOWNLOAD_BUF_ENCRYPTION_MODE BIT(0) ++#define DOWNLOAD_BUF_NO_CRC_CHECKING BIT(30) ++#define DOWNLOAD_BUF_ACK_OPTION BIT(31) ++typedef struct _INIT_CMD_DOWNLOAD_BUF { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4CRC32; ++ UINT_32 u4DataMode; ++ UINT_8 aucBuffer[0]; ++} INIT_CMD_DOWNLOAD_BUF, *P_INIT_CMD_DOWNLOAD_BUF; ++ ++typedef struct _INIT_CMD_WIFI_START { ++ UINT_32 u4Override; ++ UINT_32 u4Address; ++} INIT_CMD_WIFI_START, *P_INIT_CMD_WIFI_START; ++ ++typedef struct _INIT_CMD_ACCESS_REG { ++ UINT_8 ucSetQuery; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} INIT_CMD_ACCESS_REG, *P_INIT_CMD_ACCESS_REG; ++ ++/* Events */ ++typedef struct _INIT_WIFI_EVENT_T { ++ UINT_16 u2RxByteCount; ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucBuffer[0]; ++} INIT_WIFI_EVENT_T, *P_INIT_WIFI_EVENT_T; ++ ++typedef struct _INIT_HIF_RX_HEADER_T { ++ INIT_WIFI_EVENT_T rInitWifiEvent; ++} INIT_HIF_RX_HEADER_T, *P_INIT_HIF_RX_HEADER_T; ++ ++typedef struct _INIT_EVENT_CMD_RESULT { ++ UINT_8 ucStatus; /* 0: success */ ++ /* 1: rejected by invalid param */ ++ /* 2: rejected by incorrect CRC */ ++ /* 3: rejected by decryption failure */ ++ /* 4: unknown CMD */ ++ UINT_8 aucReserved[3]; ++} INIT_EVENT_CMD_RESULT, *P_INIT_EVENT_CMD_RESULT, INIT_EVENT_PENDING_ERROR, *P_INIT_EVENT_PENDING_ERROR; ++ ++typedef struct _INIT_EVENT_ACCESS_REG { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} INIT_EVENT_ACCESS_REG, *P_INIT_EVENT_ACCESS_REG; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_INIT_CMD_EVENT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h +new file mode 100644 +index 000000000000..85af819f4e62 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h +@@ -0,0 +1,201 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/p2p_precomp.h#1 ++*/ ++ ++/*! \file p2p_precomp.h ++ \brief Collection of most compiler flags for p2p driver are described here. ++ ++ In this file we collect all compiler flags and detail the p2p driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++#ifndef _P2P_PRECOMP_H ++#define _P2P_PRECOMP_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" /* Include "config.h" */ ++ ++#include "gl_p2p_os.h" ++ ++#include "debug.h" ++ ++#include "link.h" ++#include "queue.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++#include "wlan_typedef.h" ++ ++#include "mac.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "wlan_def.h" ++ ++#include "roaming_fsm.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\nic ++ *------------------------------------------------------------------------------ ++ */ ++/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ ++#include "cmd_buf.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "nic_cmd_event.h" ++ ++/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ ++#include "nic.h" ++ ++#include "nic_init_cmd_event.h" ++ ++#include "hif_rx.h" ++#include "hif_tx.h" ++ ++#include "nic_tx.h" ++ ++/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ ++#include "nic_rx.h" ++ ++#include "que_mgt.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_typedef.h" ++#include "p2p_cmd_buf.h" ++#include "p2p_nic_cmd_event.h" ++#include "p2p_mac.h" ++#include "p2p_nic.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++ ++#include "hem_mbox.h" ++ ++#include "scan.h" ++#include "bss.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_bow.h" ++ ++#include "wlan_p2p.h" ++ ++#include "hal.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#endif ++ ++#include "rlm.h" ++#include "rlm_domain.h" ++#include "rlm_protection.h" ++#include "rlm_obss.h" ++#include "rate.h" ++ ++#include "aa_fsm.h" ++ ++#include "cnm_timer.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "bow.h" ++#include "bow_fsm.h" ++#endif ++ ++#include "pwr_mgt.h" ++ ++#include "cnm.h" ++/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ ++#include "cnm_mem.h" ++#include "cnm_scan.h" ++ ++#include "p2p_rlm_obss.h" ++#include "p2p_bss.h" ++#include "p2p.h" ++/* Dependency: cnm_timer.h (TIMER_T) */ ++#include "p2p_fsm.h" ++#include "p2p_scan.h" ++#include "p2p_state.h" ++#include "p2p_func.h" ++#include "p2p_rlm.h" ++#include "p2p_assoc.h" ++#include "p2p_ie.h" ++ ++#include "privacy.h" ++ ++#include "mib.h" ++ ++#include "auth.h" ++#include "assoc.h" ++ ++#include "ais_fsm.h" ++ ++#include "adapter.h" ++ ++#include "que_mgt.h" ++#include "rftest.h" ++ ++#if CFG_RSN_MIGRATION ++#include "rsn.h" ++#include "sec_fsm.h" ++#endif ++ ++#if CFG_SUPPORT_WAPI ++#include "wapi.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * NVRAM structure ++ *------------------------------------------------------------------------------ ++ */ ++#include "CFG_Wifi_File.h" ++ ++#include "gl_p2p_kal.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_P2P_PRECOMP_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h +new file mode 100644 +index 000000000000..a02d391d3643 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h +@@ -0,0 +1,165 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/p2p_typedef.h#1 ++*/ ++ ++/*! \file p2p_typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to all MGMT Protocol Stack. ++*/ ++ ++#ifndef _P2P_TYPEDEF_H ++#define _P2P_TYPEDEF_H ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* ++* type definition of pointer to p2p structure ++*/ ++/* typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; */ ++typedef struct _P2P_INFO_T P2P_INFO_T, *P_P2P_INFO_T; ++ ++typedef struct _P2P_FSM_INFO_T P2P_FSM_INFO_T, *P_P2P_FSM_INFO_T; ++ ++typedef struct _P2P_CONNECTION_SETTINGS_T P2P_CONNECTION_SETTINGS_T, *P_P2P_CONNECTION_SETTINGS_T; ++ ++/* Type definition for function pointer to p2p function*/ ++typedef BOOLEAN(*P2P_LAUNCH) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*P2P_REMOVE) (P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsWlanLaunched); ++ ++typedef BOOLEAN(*KAL_P2P_GET_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_TKIP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_CCMP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_WSC_MODE) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef struct net_device *(*KAL_P2P_GET_DEV_HDLR) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*KAL_P2P_SET_MULTICAST_WORK_ITEM) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*P2P_NET_REGISTER) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*P2P_NET_UNREGISTER) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*KAL_P2P_UPDATE_ASSOC_INFO) (IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, ++ IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++typedef BOOLEAN(*P2P_VALIDATE_AUTH) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++typedef BOOLEAN(*P2P_VALIDATE_ASSOC_REQ) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu4ControlFlags); ++ ++typedef VOID(*P2P_RUN_EVENT_AAA_TX_FAIL) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++typedef BOOLEAN(*P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM) (IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); ++ ++typedef WLAN_STATUS(*P2P_RUN_EVENT_AAA_COMPLETE) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++typedef VOID(*P2P_PROCESS_EVENT_UPDATE_NOA_PARAM) (IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, ++ P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); ++ ++typedef VOID(*SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, ++ IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); ++ ++typedef VOID(*P2P_RX_PUBLIC_ACTION_FRAME) (P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_RSP_GENERATE_OBSS_SCAN_IE) (P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++typedef VOID(*RLM_UPDATE_BW_BY_CH_LIST_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++typedef VOID(*RLM_PROCESS_PUBLIC_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_PROCESS_HT_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_UPDATE_PARAMS_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); ++ ++typedef VOID(*RLM_HANDLE_OBSS_STATUS_EVENT_PKT) (P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); ++ ++typedef BOOLEAN(*P2P_FUNC_VALIDATE_PROBE_REQ) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++typedef VOID(*RLM_BSS_INIT_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++typedef UINT_32(*P2P_GET_PROB_RSP_IE_TABLE_SIZE) (VOID); ++ ++typedef PUINT_8(*P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES) (IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); ++ ++typedef VOID(*P2P_FUNC_DISCONNECT) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_RX_DEAUTH) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_RX_DISASSOC) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++typedef BOOLEAN(*P2P_FUN_IS_AP_MODE) (IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_BEACON_TIMEOUT) (IN P_ADAPTER_T prAdapter); ++ ++typedef VOID(*P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER) (IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*P2P_GENERATE_P2P_IE) (IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++typedef UINT_32(*P2P_CALCULATE_P2P_IE_LEN) (IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /*CFG_ENABLE_WIFI_DIRECT */ ++ ++#endif /* _P2P_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h +new file mode 100644 +index 000000000000..1b7e7ede66e1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h +@@ -0,0 +1,388 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/precomp.h#2 ++*/ ++ ++/*! \file precomp.h ++ \brief Collection of most compiler flags are described here. ++ ++ In this file we collect all compiler flags and detail the driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++/* ++** Log: precomp.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Fix BOW_FSM_INFO_T dependence. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 11:30:58 GMT mtk02752 ++** add rftest.h for implementing RF test mode in driver land ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-23 22:02:00 GMT mtk02468 ++** Added que_mgt.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-13 21:58:36 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:40:11 GMT mtk01461 ++** Add nic_cmd_event.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 20:00:26 GMT mtk01461 ++** Add cmd_buf.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:44 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:25 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:38 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _PRECOMP_H ++#define _PRECOMP_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" /* Include "config.h" */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_os.h" ++#endif ++ ++#include "debug.h" ++ ++#include "link.h" ++#include "queue.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++#include "wlan_typedef.h" ++ ++#include "mac.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "wlan_def.h" ++ ++#if CFG_SUPPORT_SWCR ++#include "swcr.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\nic ++ *------------------------------------------------------------------------------ ++ */ ++/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ ++#include "cmd_buf.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "nic_cmd_event.h" ++ ++/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ ++#include "nic.h" ++ ++#include "nic_init_cmd_event.h" ++ ++#include "hif_rx.h" ++#include "hif_tx.h" ++ ++#include "nic_tx.h" ++ ++/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ ++#include "nic_rx.h" ++ ++#include "que_mgt.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_typedef.h" ++#include "p2p_cmd_buf.h" ++#include "p2p_nic_cmd_event.h" ++#include "p2p_mac.h" ++#include "p2p_nic.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++ ++#include "hem_mbox.h" ++ ++#include "scan.h" ++#include "bss.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_bow.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "wlan_p2p.h" ++#endif ++ ++#include "hal.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#elif defined(MT6628) ++/* #include "mt6628_reg.h" */ ++#include "mtreg.h" ++#endif ++ ++#include "rlm.h" ++#include "rlm_domain.h" ++#include "rlm_protection.h" ++#include "rlm_obss.h" ++#include "rate.h" ++#if CFG_SUPPORT_802_11V ++#include "wnm.h" ++#endif ++ ++#include "aa_fsm.h" ++ ++#include "cnm_timer.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "bow.h" ++#include "bow_fsm.h" ++#endif ++ ++#include "pwr_mgt.h" ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++#include "stats.h" ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++#include "cnm.h" ++/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ ++#include "cnm_mem.h" ++#include "cnm_scan.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_rlm_obss.h" ++#include "p2p_bss.h" ++#include "p2p.h" ++#include "p2p_fsm.h" ++#include "p2p_scan.h" ++#include "p2p_state.h" ++#include "p2p_func.h" ++#include "p2p_rlm.h" ++#include "p2p_assoc.h" ++#include "p2p_ie.h" ++#endif ++ ++#include "privacy.h" ++ ++#include "mib.h" ++ ++#include "auth.h" ++#include "assoc.h" ++ ++#if CFG_SUPPORT_ROAMING ++#include "roaming_fsm.h" ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++#include "ais_fsm.h" ++ ++#include "adapter.h" ++ ++#include "que_mgt.h" ++#include "rftest.h" ++ ++#if CFG_RSN_MIGRATION ++#include "rsn.h" ++#include "sec_fsm.h" ++#endif ++ ++#if CFG_SUPPORT_WAPI ++#include "wapi.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * NVRAM structure ++ *------------------------------------------------------------------------------ ++ */ ++#include "CFG_Wifi_File.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_kal.h" ++#endif ++ ++typedef int (*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++typedef void (*set_dbg_level) (unsigned char modules[DBG_MODULE_NUM]); ++ ++extern void wlanRegisterNotifier(void); ++extern void wlanUnregisterNotifier(void); ++extern void register_set_p2p_mode_handler(set_p2p_mode handler); ++extern void register_set_dbg_level_handler(set_dbg_level handler); ++ ++#if CFG_TC1_FEATURE ++#define NIC_INF_NAME_IN_AP_MODE "legacy%d" ++extern volatile int wlan_if_changed; ++#endif ++extern BOOLEAN fgIsResetting; ++ ++extern UINT_8 g_aucBufIpAddr[32]; ++extern UINT_8 aucDebugModule[]; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PRECOMP_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h +new file mode 100644 +index 000000000000..40f52dcc9d68 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h +@@ -0,0 +1,141 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/pwr_mgt.h#1 ++*/ ++ ++/*! \file "pwr_mgt.h" ++ \brief In this file we define the STATE and EVENT for Power Management FSM. ++ ++ The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter ++ ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail ++ description. ++*/ ++ ++/* ++** Log: pwr_mgt.h ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL ++ * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. ++ ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * * * due to the different configurations on FPGA and ASIC ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-10 16:39:10 GMT mtk02752 ++** disable PM macros temporally ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-29 19:48:37 GMT mtk01084 ++** temp remove power management macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-08 16:51:11 GMT mtk01084 ++** update for power management control macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-03 14:59:58 GMT mtk01426 ++** Add #if CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:53:10 GMT mtk01084 ++** modify ACQUIRE_POWER_CONTROL_FROM_PM() and RECLAIM_POWER_CONTROL_TO_PM() macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:32:47 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:20 GMT mtk01084 ++** Initial version ++** ++*/ ++ ++#ifndef _PWR_MGT_H ++#define _PWR_MGT_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define PM_UAPSD_AC0 (BIT(0)) ++#define PM_UAPSD_AC1 (BIT(1)) ++#define PM_UAPSD_AC2 (BIT(2)) ++#define PM_UAPSD_AC3 (BIT(3)) ++ ++#define PM_UAPSD_ALL (PM_UAPSD_AC0 | PM_UAPSD_AC1 | PM_UAPSD_AC2 | PM_UAPSD_AC3) ++#define PM_UAPSD_NONE 0 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _PM_PROFILE_SETUP_INFO_T { ++ /* Profile setup */ ++ UINT_8 ucBmpDeliveryAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ ++ UINT_8 ucBmpTriggerAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ ++ ++ UINT_8 ucUapsdSp; /* Number of triggered packets in UAPSD */ ++ ++} PM_PROFILE_SETUP_INFO_T, *P_PM_PROFILE_SETUP_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if !CFG_ENABLE_FULL_PM ++#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) ++#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) ++#else ++#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) \ ++ { \ ++ if (_prAdapter->fgIsFwOwn) { \ ++ nicpmSetDriverOwn(_prAdapter); \ ++ } \ ++ /* Increase Block to Enter Low Power Semaphore count */ \ ++ GLUE_INC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ ++ } ++ ++#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) \ ++ { \ ++ ASSERT(_prAdapter->u4PwrCtrlBlockCnt != 0); \ ++ /* Decrease Block to Enter Low Power Semaphore count */ \ ++ GLUE_DEC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ ++ if (_prAdapter->fgWiFiInSleepyState && (_prAdapter->u4PwrCtrlBlockCnt == 0)) { \ ++ nicpmSetFWOwn(_prAdapter, _fgEnableGINT_in_IST); \ ++ } \ ++ } ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PWR_MGT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h +new file mode 100644 +index 000000000000..a9e74b58a8c9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h +@@ -0,0 +1,195 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/queue.h#1 ++*/ ++ ++/*! \file queue.h ++ \brief Definition for singly queue operations. ++ ++ In this file we define the singly queue data structure and its ++ queue operation MACROs. ++*/ ++ ++/* ++** Log: queue.h ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:46 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _QUEUE_H ++#define _QUEUE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Singly Queue Structures - Entry Part */ ++typedef struct _QUE_ENTRY_T { ++ struct _QUE_ENTRY_T *prNext; ++ struct _QUE_ENTRY_T *prPrev; /* For Rx buffer reordering used only */ ++} QUE_ENTRY_T, *P_QUE_ENTRY_T; ++ ++/* Singly Queue Structures - Queue Part */ ++typedef struct _QUE_T { ++ P_QUE_ENTRY_T prHead; ++ P_QUE_ENTRY_T prTail; ++ UINT_32 u4NumElem; ++} QUE_T, *P_QUE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* ++ * To resolve compiler warning of address check -Waddress ++ * Redefine a ASSERT dedicate for queue operation ++ */ ++#if DBG ++#define QUE_ASSERT ASSERT ++#else ++#define QUE_ASSERT(_exp) ++#endif ++ ++#define QUEUE_INITIALIZE(prQueue) \ ++ { \ ++ (prQueue)->prHead = (P_QUE_ENTRY_T)NULL; \ ++ (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ ++ (prQueue)->u4NumElem = 0; \ ++ } ++ ++#define QUEUE_IS_EMPTY(prQueue) (((P_QUE_T)(prQueue))->prHead == (P_QUE_ENTRY_T)NULL) ++ ++#define QUEUE_IS_NOT_EMPTY(prQueue) ((prQueue)->u4NumElem > 0) ++ ++#define QUEUE_GET_HEAD(prQueue) ((prQueue)->prHead) ++ ++#define QUEUE_GET_TAIL(prQueue) ((prQueue)->prTail) ++ ++#define QUEUE_GET_NEXT_ENTRY(prQueueEntry) ((prQueueEntry)->prNext) ++ ++#define QUEUE_INSERT_HEAD(prQueue, prQueueEntry) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ QUE_ASSERT(prQueueEntry); \ ++ (prQueueEntry)->prNext = (prQueue)->prHead; \ ++ (prQueue)->prHead = (prQueueEntry); \ ++ if ((prQueue)->prTail == (P_QUE_ENTRY_T)NULL) { \ ++ (prQueue)->prTail = (prQueueEntry); \ ++ } \ ++ ((prQueue)->u4NumElem)++; \ ++ } ++ ++#define QUEUE_INSERT_TAIL(prQueue, prQueueEntry) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ QUE_ASSERT(prQueueEntry); \ ++ (prQueueEntry)->prNext = (P_QUE_ENTRY_T)NULL; \ ++ if ((prQueue)->prTail) { \ ++ ((prQueue)->prTail)->prNext = (prQueueEntry); \ ++ } else { \ ++ (prQueue)->prHead = (prQueueEntry); \ ++ } \ ++ (prQueue)->prTail = (prQueueEntry); \ ++ ((prQueue)->u4NumElem)++; \ ++ } ++ ++/* NOTE: We assume the queue entry located at the beginning of "prQueueEntry Type", ++ * so that we can cast the queue entry to other data type without doubts. ++ * And this macro also decrease the total entry count at the same time. ++ */ ++#define QUEUE_REMOVE_HEAD(prQueue, prQueueEntry, _P_TYPE) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ prQueueEntry = (_P_TYPE)((prQueue)->prHead); \ ++ if (prQueueEntry) { \ ++ (prQueue)->prHead = ((P_QUE_ENTRY_T)(prQueueEntry))->prNext; \ ++ if ((prQueue)->prHead == (P_QUE_ENTRY_T)NULL) { \ ++ (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ ++ } \ ++ ((P_QUE_ENTRY_T)(prQueueEntry))->prNext = (P_QUE_ENTRY_T)NULL; \ ++ ((prQueue)->u4NumElem)--; \ ++ } \ ++ } ++ ++#define QUEUE_MOVE_ALL(prDestQueue, prSrcQueue) \ ++ { \ ++ QUE_ASSERT(prDestQueue); \ ++ QUE_ASSERT(prSrcQueue); \ ++ *(P_QUE_T)prDestQueue = *(P_QUE_T)prSrcQueue; \ ++ QUEUE_INITIALIZE(prSrcQueue); \ ++ } ++ ++#define QUEUE_CONCATENATE_QUEUES(prDestQueue, prSrcQueue) \ ++ { \ ++ QUE_ASSERT(prDestQueue); \ ++ QUE_ASSERT(prSrcQueue); \ ++ if (prSrcQueue->u4NumElem > 0) { \ ++ if ((prDestQueue)->prTail) { \ ++ ((prDestQueue)->prTail)->prNext = (prSrcQueue)->prHead; \ ++ } else { \ ++ (prDestQueue)->prHead = (prSrcQueue)->prHead; \ ++ } \ ++ (prDestQueue)->prTail = (prSrcQueue)->prTail; \ ++ ((prDestQueue)->u4NumElem) += ((prSrcQueue)->u4NumElem); \ ++ QUEUE_INITIALIZE(prSrcQueue); \ ++ } \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _QUEUE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h +new file mode 100644 +index 000000000000..4489e5601302 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h +@@ -0,0 +1,294 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/rftest.h#1 ++*/ ++ ++/*! \file "rftest.h" ++ \brief definitions for RF Productino test ++ ++*/ ++ ++/* ++** Log: rftest.h ++ * ++ * 12 20 2011 cp.wu ++ * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information ++ * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO ++ * to expose version information ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-08 17:35:11 GMT mtk02752 ++** * comment out RF test which is not supported on MT6620 ++** + API decalre for rftest ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-12-08 11:29:07 GMT mtk02752 ++** definitions for RF test mode ++** ++*/ ++#ifndef _RFTEST_H ++#define _RFTEST_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Table Version */ ++#define RF_AUTO_TEST_FUNCTION_TABLE_VERSION 0x01000001 ++ ++/* Power */ ++#define RF_AT_PARAM_POWER_MASK BITS(0, 7) ++#define RF_AT_PARAM_POWER_MAX RF_AT_PARAM_POWER_MASK ++ ++/* Rate */ ++#define RF_AT_PARAM_RATE_MCS_MASK BIT(31) ++#define RF_AT_PARAM_RATE_MASK BITS(0, 7) ++#define RF_AT_PARAM_RATE_CCK_MAX 3 ++#define RF_AT_PARAM_RATE_1M 0 ++#define RF_AT_PARAM_RATE_2M 1 ++#define RF_AT_PARAM_RATE_5_5M 2 ++#define RF_AT_PARAM_RATE_11M 3 ++#define RF_AT_PARAM_RATE_6M 4 ++#define RF_AT_PARAM_RATE_9M 5 ++#define RF_AT_PARAM_RATE_12M 6 ++#define RF_AT_PARAM_RATE_18M 7 ++#define RF_AT_PARAM_RATE_24M 8 ++#define RF_AT_PARAM_RATE_36M 9 ++#define RF_AT_PARAM_RATE_48M 10 ++#define RF_AT_PARAM_RATE_54M 11 ++ ++/* Antenna */ ++#define RF_AT_PARAM_ANTENNA_ID_MASK BITS(0, 7) ++#define RF_AT_PARAM_ANTENNA_ID_MAX 1 ++ ++/* Packet Length */ ++#define RF_AT_PARAM_TX_80211HDR_BYTE_MAX (32) ++#define RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX (2048) ++ ++#define RF_AT_PARAM_TX_PKTLEN_BYTE_DEFAULT 1024 ++#define RF_AT_PARAM_TX_PKTLEN_BYTE_MAX \ ++ ((UINT_16)(RF_AT_PARAM_TX_80211HDR_BYTE_MAX + RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX)) ++ ++/* Packet Count */ ++#define RF_AT_PARAM_TX_PKTCNT_DEFAULT 1000 ++#define RF_AT_PARAM_TX_PKTCNT_UNLIMITED 0 ++ ++/* Packet Interval */ ++#define RF_AT_PARAM_TX_PKT_INTERVAL_US_DEFAULT 50 ++ ++/* ALC */ ++#define RF_AT_PARAM_ALC_DISABLE 0 ++#define RF_AT_PARAM_ALC_ENABLE 1 ++ ++/* TXOP */ ++#define RF_AT_PARAM_TXOP_DEFAULT 0 ++#define RF_AT_PARAM_TXOPQUE_QMASK BITS(16, 31) ++#define RF_AT_PARAM_TXOPQUE_TMASK BITS(0, 15) ++#define RF_AT_PARAM_TXOPQUE_AC0 (0<<16) ++#define RF_AT_PARAM_TXOPQUE_AC1 (1<<16) ++#define RF_AT_PARAM_TXOPQUE_AC2 (2<<16) ++#define RF_AT_PARAM_TXOPQUE_AC3 (3<<16) ++#define RF_AT_PARAM_TXOPQUE_AC4 (4<<16) ++#define RF_AT_PARAM_TXOPQUE_QOFFSET 16 ++ ++/* Retry Limit */ ++#define RF_AT_PARAM_TX_RETRY_DEFAULT 0 ++#define RF_AT_PARAM_TX_RETRY_MAX 6 ++ ++/* QoS Queue */ ++#define RF_AT_PARAM_QOSQUE_AC0 0 ++#define RF_AT_PARAM_QOSQUE_AC1 1 ++#define RF_AT_PARAM_QOSQUE_AC2 2 ++#define RF_AT_PARAM_QOSQUE_AC3 3 ++#define RF_AT_PARAM_QOSQUE_AC4 4 ++#define RF_AT_PARAM_QOSQUE_DEFAULT RF_AT_PARAM_QOSQUE_AC0 ++ ++/* Bandwidth */ ++#define RF_AT_PARAM_BANDWIDTH_20MHZ 0 ++#define RF_AT_PARAM_BANDWIDTH_40MHZ 1 ++#define RF_AT_PARAM_BANDWIDTH_U20_IN_40MHZ 2 ++#define RF_AT_PARAM_BANDWIDTH_D20_IN_40MHZ 3 ++#define RF_AT_PARAM_BANDWIDTH_DEFAULT RF_AT_PARAM_BANDWIDTH_20MHZ ++ ++/* GI (Guard Interval) */ ++#define RF_AT_PARAM_GI_800NS 0 ++#define RF_AT_PARAM_GI_400NS 1 ++#define RF_AT_PARAM_GI_DEFAULT RF_AT_PARAM_GI_800NS ++ ++/* STBC */ ++#define RF_AT_PARAM_STBC_DISABLE 0 ++#define RF_AT_PARAM_STBC_ENABLE 1 ++ ++/* RIFS */ ++#define RF_AT_PARAM_RIFS_DISABLE 0 ++#define RF_AT_PARAM_RIFS_ENABLE 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Function ID List */ ++typedef enum _ENUM_RF_AT_FUNCID_T { ++ RF_AT_FUNCID_VERSION = 0, ++ RF_AT_FUNCID_COMMAND, ++ RF_AT_FUNCID_POWER, ++ RF_AT_FUNCID_RATE, ++ RF_AT_FUNCID_PREAMBLE, ++ RF_AT_FUNCID_ANTENNA, ++ RF_AT_FUNCID_PKTLEN, ++ RF_AT_FUNCID_PKTCNT, ++ RF_AT_FUNCID_PKTINTERVAL, ++ RF_AT_FUNCID_TEMP_COMPEN, ++ RF_AT_FUNCID_TXOPLIMIT, ++ RF_AT_FUNCID_ACKPOLICY, ++ RF_AT_FUNCID_PKTCONTENT, ++ RF_AT_FUNCID_RETRYLIMIT, ++ RF_AT_FUNCID_QUEUE, ++ RF_AT_FUNCID_BANDWIDTH, ++ RF_AT_FUNCID_GI, ++ RF_AT_FUNCID_STBC, ++ RF_AT_FUNCID_CHNL_FREQ, ++ RF_AT_FUNCID_RIFS, ++ RF_AT_FUNCID_TRSW_TYPE, ++ RF_AT_FUNCID_RF_SX_SHUTDOWN, ++ RF_AT_FUNCID_PLL_SHUTDOWN, ++ RF_AT_FUNCID_SLOW_CLK_MODE, ++ RF_AT_FUNCID_ADC_CLK_MODE, ++ RF_AT_FUNCID_MEASURE_MODE, ++ RF_AT_FUNCID_VOLT_COMPEN, ++ RF_AT_FUNCID_DPD_TX_GAIN, ++ RF_AT_FUNCID_DPD_MODE, ++ RF_AT_FUNCID_TSSI_MODE, ++ RF_AT_FUNCID_TX_GAIN_CODE, ++ RF_AT_FUNCID_TX_PWR_MODE, ++ ++ /* Query command */ ++ RF_AT_FUNCID_TXED_COUNT = 32, ++ RF_AT_FUNCID_TXOK_COUNT, ++ RF_AT_FUNCID_RXOK_COUNT, ++ RF_AT_FUNCID_RXERROR_COUNT, ++ RF_AT_FUNCID_RESULT_INFO, ++ RF_AT_FUNCID_TRX_IQ_RESULT, ++ RF_AT_FUNCID_TSSI_RESULT, ++ RF_AT_FUNCID_DPD_RESULT, ++ RF_AT_FUNCID_RXV_DUMP, ++ RF_AT_FUNCID_RX_PHY_STATIS, ++ RF_AT_FUNCID_MEASURE_RESULT, ++ RF_AT_FUNCID_TEMP_SENSOR, ++ RF_AT_FUNCID_VOLT_SENSOR, ++ RF_AT_FUNCID_READ_EFUSE, ++ RF_AT_FUNCID_RX_RSSI, ++ RF_AT_FUNCID_FW_INFO, ++ RF_AT_FUNCID_DRV_INFO, ++ ++ /* Set command */ ++ RF_AT_FUNCID_SET_DPD_RESULT = 64, ++ RF_AT_FUNCID_SET_CW_MODE, ++ RF_AT_FUNCID_SET_JAPAN_CH14_FILTER, ++ RF_AT_FUNCID_WRITE_EFUSE, ++ RF_AT_FUNCID_SET_MAC_ADDRESS ++} ENUM_RF_AT_FUNCID_T; ++ ++/* Command */ ++typedef enum _ENUM_RF_AT_COMMAND_T { ++ RF_AT_COMMAND_STOPTEST = 0, ++ RF_AT_COMMAND_STARTTX, ++ RF_AT_COMMAND_STARTRX, ++ RF_AT_COMMAND_RESET, ++ RF_AT_COMMAND_OUTPUT_POWER, /* Payload */ ++ RF_AT_COMMAND_LO_LEAKAGE, /* Local freq is renamed to Local leakage */ ++ RF_AT_COMMAND_CARRIER_SUPPR, /* OFDM (LTF/STF), CCK (PI,PI/2) */ ++ RF_AT_COMMAND_TRX_IQ_CAL, ++ RF_AT_COMMAND_TSSI_CAL, ++ RF_AT_COMMAND_DPD_CAL, ++ RF_AT_COMMAND_CW, ++ RF_AT_COMMAND_NUM ++} ENUM_RF_AT_COMMAND_T; ++ ++/* Preamble */ ++typedef enum _ENUM_RF_AT_PREAMBLE_T { ++ RF_AT_PREAMBLE_NORMAL = 0, ++ RF_AT_PREAMBLE_CCK_SHORT, ++ RF_AT_PREAMBLE_11N_MM, ++ RF_AT_PREAMBLE_11N_GF, ++ RF_AT_PREAMBLE_NUM ++} ENUM_RF_AT_PREAMBLE_T; ++ ++/* Ack Policy */ ++typedef enum _ENUM_RF_AT_ACK_POLICY_T { ++ RF_AT_ACK_POLICY_NORMAL = 0, ++ RF_AT_ACK_POLICY_NOACK, ++ RF_AT_ACK_POLICY_NOEXPLICTACK, ++ RF_AT_ACK_POLICY_BLOCKACK, ++ RF_AT_ACK_POLICY_NUM ++} ENUM_RF_AT_ACK_POLICY_T; ++ ++typedef enum _ENUM_RF_AUTOTEST_STATE_T { ++ RF_AUTOTEST_STATE_STANDBY = 0, ++ RF_AUTOTEST_STATE_TX, ++ RF_AUTOTEST_STATE_RX, ++ RF_AUTOTEST_STATE_RESET, ++ RF_AUTOTEST_STATE_OUTPUT_POWER, ++ RF_AUTOTEST_STATE_LOCA_FREQUENCY, ++ RF_AUTOTEST_STATE_CARRIER_SUPRRESION, ++ RF_AUTOTEST_STATE_NUM ++} ENUM_RF_AUTOTEST_STATE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData); ++ ++WLAN_STATUS ++rftestQueryATInfo(IN P_ADAPTER_T prAdapter, ++ UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); ++ ++WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen); ++ ++#endif /* _RFTEST_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h +new file mode 100644 +index 000000000000..8ee184591fc2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h +@@ -0,0 +1,427 @@ ++/* ++** Id: include/tdls_extr.h#1 ++*/ ++ ++/*! \file "tdls_extr.h" ++ \brief This file contains the external used in other modules ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: tdls_extr.h ++ * ++ * 11 18 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ * ++ ** ++ */ ++ ++#ifndef _TDLS_EXTR_H ++#define _TDLS_EXTR_H ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#define TDLS_TX_QUOTA_EMPTY_TIMEOUT 10 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* protocol */ ++#define TDLS_FRM_PROT_TYPE 0x890d ++ ++/* TDLS uses Ethertype 89-0d frames. The UP shall be AC_VI, unless otherwise specified. */ ++#define USER_PRIORITY_TDLS 5 ++ ++/* Status code */ ++#define TDLS_STATUS WLAN_STATUS ++ ++#define TDLS_STATUS_SUCCESS WLAN_STATUS_SUCCESS ++#define TDLS_STATUS_FAILURE WLAN_STATUS_FAILURE ++#define TDLS_STATUS_INVALID_LENGTH WLAN_STATUS_INVALID_LENGTH ++#define TDLS_STATUS_RESOURCES WLAN_STATUS_RESOURCES ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#define TDLS_U32 UINT32 ++#define TDLS_U16 UINT16 ++#define TDLS_U8 UINT8 ++ ++typedef enum _TDLS_REASON_CODE { ++ TDLS_REASON_CODE_UNREACHABLE = 25, ++ TDLS_REASON_CODE_UNSPECIFIED = 26, ++ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN = 0x80, /* 128 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WIFI_OFF = 0x81, /* 129 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING = 0x82, /* 130 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT = 0x83, /* 131 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT = 0x84, /* 132 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY = 0x85, /* 133 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL = 0x86, /* 134 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL = 0x87, /* 135 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX = 0x88, /* 136 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3 = 0x89, /* 137 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY = 0x8a, /* 138 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN = 0x8b /* 139 */ ++} TDLS_REASON_CODE; ++ ++/* TDLS FSM */ ++typedef struct _TDLS_CMD_PEER_ADD_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ ++#if 0 ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ UINT_16 u2CapInfo; ++ ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ UINT_8 ucPhyTypeSet; ++#endif ++} TDLS_CMD_PEER_ADD_T; ++ ++typedef struct _TDLS_CMD_LINK_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ BOOLEAN fgIsEnabled; ++} TDLS_CMD_LINK_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T { ++ TDLS_U8 arRxMask[10]; ++ TDLS_U16 u2RxHighest; ++ TDLS_U8 ucTxParams; ++ TDLS_U8 Reserved[3]; ++} TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_T { ++ TDLS_U16 u2CapInfo; ++ TDLS_U8 ucAmpduParamsInfo; ++ ++ /* 16 bytes MCS information */ ++ TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T rMCS; ++ ++ TDLS_U16 u2ExtHtCapInfo; ++ TDLS_U32 u4TxBfCapInfo; ++ TDLS_U8 ucAntennaSelInfo; ++} TDLS_CMD_PEER_UPDATE_HT_CAP_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ ++#define TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX 50 ++ TDLS_U8 aucSupChan[TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX]; ++ ++ TDLS_U16 u2StatusCode; ++ ++#define TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX 50 ++ TDLS_U8 aucSupRate[TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX]; ++ TDLS_U16 u2SupRateLen; ++ ++ TDLS_U8 UapsdBitmap; ++ TDLS_U8 UapsdMaxSp; /* MAX_SP */ ++ ++ TDLS_U16 u2Capability; ++#define TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN 5 ++ TDLS_U8 aucExtCap[TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN]; ++ TDLS_U16 u2ExtCapLen; ++ ++ TDLS_CMD_PEER_UPDATE_HT_CAP_T rHtCap; ++ BOOLEAN fgIsSupHt; ++ ++} TDLS_CMD_PEER_UPDATE_T; ++ ++/* Command to TDLS core module */ ++typedef enum _TDLS_CMD_CORE_ID { ++ TDLS_CORE_CMD_TEST_NULL_RCV = 0x00, ++ TDLS_CORE_CMD_TEST_PTI_RSP = 0x01, ++ TDLS_CORE_CMD_MIB_UPDATE = 0x02, ++ TDLS_CORE_CMD_TEST_TX_FAIL_SKIP = 0x03, ++ TDLS_CORE_CMD_UAPSD_CONF = 0x04, ++ TDLS_CORE_CMD_TEST_DATA_RCV = 0x05, ++ TDLS_CORE_CMD_TEST_PTI_REQ = 0x06, ++ TDLS_CORE_CMD_TEST_CHSW_REQ = 0x07, ++ TDLS_CORE_CMD_CHSW_CONF = 0x08, ++ TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP = 0x09, ++ TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP = 0x0a, ++ TDLS_CORE_CMD_TEST_CHSW_RSP = 0x0b, ++ TDLS_CORE_CMD_TEST_SCAN_SKIP = 0x0c, ++ TDLS_CORE_CMD_SETUP_CONF = 0x0d, ++ TDLS_CORE_CMD_TEST_TEAR_DOWN = 0x0e, ++ TDLS_CORE_CMD_KEY_INFO = 0x0f, ++ TDLS_CORE_CMD_TEST_PTI_TX_FAIL = 0x10 ++} TDLS_CMD_CORE_ID; ++ ++typedef struct _TDLS_CMD_CORE_TEST_NULL_RCV_T { ++ ++ TDLS_U32 u4PM; ++} TDLS_CMD_CORE_TEST_NULL_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T { ++ ++ TDLS_U32 u4DialogToken; ++} TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T { ++ ++ TDLS_U32 u4DialogToken; ++ TDLS_U32 u4PM; ++} TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T { ++ ++ TDLS_U32 u4ReasonCode; ++} TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T { ++ ++ TDLS_U32 u4Chan; ++ TDLS_U32 u4RegClass; ++ TDLS_U32 u4SecChanOff; ++ TDLS_U32 u4SwitchTime; ++ TDLS_U32 u4SwitchTimeout; ++} TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T { ++ ++ TDLS_U32 u4Chan; ++ TDLS_U32 u4SwitchTime; ++ TDLS_U32 u4SwitchTimeout; ++ TDLS_U32 u4StatusCode; ++} TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_DATA_RCV_T { ++ ++ TDLS_U32 u4PM; ++ TDLS_U32 u4UP; ++ TDLS_U32 u4EOSP; ++ TDLS_U32 u4IsNull; ++} TDLS_CMD_CORE_TEST_DATA_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_MIB_PARAM_UPDATE_T { ++ ++ BOOLEAN Tdlsdot11TunneledDirectLinkSetupImplemented; ++ BOOLEAN Tdlsdot11TDLSPeerUAPSDBufferSTAActivated; ++ BOOLEAN Tdlsdot11TDLSPeerPSMActivated; ++ TDLS_U16 Tdlsdot11TDLSPeerUAPSDIndicationWindow; ++ BOOLEAN Tdlsdot11TDLSChannelSwitchingActivated; ++ TDLS_U8 Tdlsdot11TDLSPeerSTAMissingAckRetryLimit; ++ TDLS_U8 Tdlsdot11TDLSResponseTimeout; ++ TDLS_U16 Tdlsdot11TDLSProbeDelay; ++ TDLS_U8 Tdlsdot11TDLSDiscoveryRequestWindow; ++ TDLS_U8 Tdlsdot11TDLSACDeterminationInterval; ++} TDLS_CMD_CORE_MIB_PARAM_UPDATE_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_UAPSD_CONFIG_T { ++ ++ BOOLEAN fgIsSpTimeoutSkip; ++ BOOLEAN fgIsPtiTimeoutSkip; ++} TDLS_CMD_CORE_UAPSD_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_SETUP_CONFIG_T { ++ ++ BOOLEAN fgIs2040Supported; ++} TDLS_CMD_CORE_SETUP_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_CHSW_CONFIG_T { ++ ++ TDLS_U8 ucNetTypeIndex; ++ BOOLEAN fgIsChSwEnabled; ++ BOOLEAN fgIsChSwStarted; ++ TDLS_U8 ucRegClass; ++ TDLS_U8 ucTargetChan; ++ TDLS_U8 ucSecChanOff; ++ BOOLEAN fgIsChSwRegular; ++} TDLS_CMD_CORE_CHSW_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PROHIBIT_T { ++ ++ BOOLEAN fgIsEnable; ++ BOOLEAN fgIsSet; ++} TDLS_CMD_CORE_TEST_PROHIBIT_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_SCAN_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_SCAN_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_INFO_DISPLAY_T { ++ ++ BOOLEAN fgIsToClearAllHistory; ++} TDLS_CMD_CORE_INFO_DISPLAY_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T; ++ ++typedef struct _TDLS_CMD_CORE_T { ++ ++ TDLS_U32 u4Command; /* TDLS_CMD_CORE_ID */ ++ ++ TDLS_U8 aucPeerMac[6]; ++ TDLS_U8 ucNetTypeIndex; ++ ++#define TDLS_CMD_CORE_RESERVED_SIZE 50 ++ union { ++ TDLS_CMD_CORE_TEST_NULL_RCV_T rCmdNullRcv; ++ TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T rCmdPtiReqRcv; ++ TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T rCmdPtiRspRcv; ++ TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T rCmdTearDownRcv; ++ TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T rCmdChStReqRcv; ++ TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T rCmdChStRspRcv; ++ TDLS_CMD_CORE_TEST_DATA_RCV_T rCmdDatRcv; ++ TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T rCmdTxFailSkip; ++ TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T rCmdKeepAliveSkip; ++ TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T rCmdChSwTimeoutSkip; ++ TDLS_CMD_CORE_TEST_PROHIBIT_T rCmdProhibit; ++ TDLS_CMD_CORE_TEST_SCAN_SKIP_T rCmdScanSkip; ++ TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T rCmdPtiTxFail; ++ ++ TDLS_CMD_CORE_MIB_PARAM_UPDATE_T rCmdMibUpdate; ++ TDLS_CMD_CORE_UAPSD_CONFIG_T rCmdUapsdConf; ++ TDLS_CMD_CORE_CHSW_CONFIG_T rCmdChSwConf; ++ TDLS_CMD_CORE_SETUP_CONFIG_T rCmdSetupConf; ++ TDLS_CMD_CORE_INFO_DISPLAY_T rCmdInfoDisplay; ++ TDLS_U8 Reserved[TDLS_CMD_CORE_RESERVED_SIZE]; ++ } Content; ++} TDLS_CMD_CORE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* ++ assign station record idx for the packet only when STA_STATE_3 ++ Or we will try to send data frame when the TDLS peer's state is STA_STATE_1 ++ EX: ++ 1. mtk_cfg80211_add_station: First create the STA_RECORD_T; ++ 2. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. ++ 3. mtk_cfg80211_add_station: Change state to STA_STATE_1. ++ 4. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. ++*/ ++#define TDLSEX_STA_REC_IDX_GET(__prAdapter__, __MsduInfo__) \ ++{ \ ++ STA_RECORD_T *__StaRec__; \ ++ __MsduInfo__->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; \ ++ __StaRec__ = cnmGetStaRecByAddress(__prAdapter__, \ ++ (UINT_8) NETWORK_TYPE_AIS_INDEX, \ ++ __MsduInfo__->aucEthDestAddr); \ ++ if ((__StaRec__ != NULL) && \ ++ ((__StaRec__)->ucStaState == STA_STATE_3) && \ ++ (IS_TDLS_STA(__StaRec__))) { \ ++ __MsduInfo__->ucStaRecIndex = __StaRec__->ucIndex; \ ++ } \ ++} ++ ++/* fill wiphy flag */ ++#define TDLSEX_WIPHY_FLAGS_INIT(__fgFlag__)\ ++{ \ ++ __fgFlag__ |= (WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP);\ ++} ++ ++/* assign user priority of a TDLS action frame */ ++/* ++ According to 802.11z: Setup req/resp are sent in AC_BK, otherwise we should default ++ to AC_VI. ++*/ ++#define TDLSEX_UP_ASSIGN(__UserPriority__) \ ++{ \ ++ __UserPriority__ = USER_PRIORITY_TDLS; \ ++} ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++int ++TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *buf, size_t len); ++ ++int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, enum nl80211_tdls_operation oper); ++ ++VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE); ++ ++VOID TdlsexEventHandle(P_GLUE_INFO_T prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey); ++ ++VOID TdlsexInit(ADAPTER_T *prAdapter); ++ ++BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter); ++ ++TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++VOID ++TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode); ++ ++TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++TDLS_STATUS TdlsexPeerAdd(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); ++ ++TDLS_STATUS TdlsexPeerUpdate(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); ++ ++BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt); ++ ++VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen); ++ ++TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo); ++ ++VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota); ++ ++VOID TdlsexUninit(ADAPTER_T *prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#endif /* _TDLS_EXTR_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h +new file mode 100644 +index 000000000000..7ab62dae8813 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h +@@ -0,0 +1,244 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/typedef.h#1 ++*/ ++ ++/*! \file typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to the GLUE Layer. ++*/ ++ ++/* ++** Log: typedef.h ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add Ethernet destination address information in packet info for TX ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:41:37 GMT mtk01461 ++** Update PACKET_INFO_INIT for TX Path ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:30:17 GMT mtk01461 ++** Add parameter in PACKET_INFO_T for HIF Loopback ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:22 GMT mtk01461 ++** Fix LINT warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:28 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:54 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _TYPEDEF_H ++#define _TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* ieee80211.h of linux has duplicated definitions */ ++#if defined(WLAN_STATUS_SUCCESS) ++#undef WLAN_STATUS_SUCCESS ++#endif ++ ++#define WLAN_STATUS_SUCCESS ((WLAN_STATUS) 0x00000000L) ++#define WLAN_STATUS_PENDING ((WLAN_STATUS) 0x00000103L) ++#define WLAN_STATUS_NOT_ACCEPTED ((WLAN_STATUS) 0x00010003L) ++ ++#define WLAN_STATUS_MEDIA_CONNECT ((WLAN_STATUS) 0x4001000BL) ++#define WLAN_STATUS_MEDIA_DISCONNECT ((WLAN_STATUS) 0x4001000CL) ++#define WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ((WLAN_STATUS) 0x4001000DL) ++ ++#define WLAN_STATUS_MEDIA_SPECIFIC_INDICATION ((WLAN_STATUS) 0x40010012L) ++ ++#define WLAN_STATUS_SCAN_COMPLETE ((WLAN_STATUS) 0x60010001L) ++#define WLAN_STATUS_MSDU_OK ((WLAN_STATUS) 0x60010002L) ++ ++/* TODO(Kevin): double check if 0x60010001 & 0x60010002 is proprietary */ ++#define WLAN_STATUS_ROAM_OUT_FIND_BEST ((WLAN_STATUS) 0x60010101L) ++#define WLAN_STATUS_ROAM_DISCOVERY ((WLAN_STATUS) 0x60010102L) ++ ++#define WLAN_STATUS_FAILURE ((WLAN_STATUS) 0xC0000001L) ++#define WLAN_STATUS_RESOURCES ((WLAN_STATUS) 0xC000009AL) ++#define WLAN_STATUS_NOT_SUPPORTED ((WLAN_STATUS) 0xC00000BBL) ++ ++#define WLAN_STATUS_MULTICAST_FULL ((WLAN_STATUS) 0xC0010009L) ++#define WLAN_STATUS_INVALID_PACKET ((WLAN_STATUS) 0xC001000FL) ++#define WLAN_STATUS_ADAPTER_NOT_READY ((WLAN_STATUS) 0xC0010011L) ++#define WLAN_STATUS_NOT_INDICATING ((WLAN_STATUS) 0xC0010013L) ++#define WLAN_STATUS_INVALID_LENGTH ((WLAN_STATUS) 0xC0010014L) ++#define WLAN_STATUS_INVALID_DATA ((WLAN_STATUS) 0xC0010015L) ++#define WLAN_STATUS_BUFFER_TOO_SHORT ((WLAN_STATUS) 0xC0010016L) ++ ++#define WLAN_STATUS_BWCS_UPDATE ((WLAN_STATUS) 0xC0010017L) ++ ++#define WLAN_STATUS_CONNECT_INDICATION ((WLAN_STATUS) 0xC0010018L) ++ ++/* NIC status flags */ ++#define ADAPTER_FLAG_HW_ERR 0x00400000 ++ ++/* Type Length */ ++#define TL_IPV4 0x0008 ++#define TL_IPV6 0xDD86 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for GLUE_INFO structure */ ++typedef struct _GLUE_INFO_T GLUE_INFO_T, *P_GLUE_INFO_T; ++ ++/* Type definition for WLAN STATUS */ ++typedef UINT_32 WLAN_STATUS, *P_WLAN_STATUS; ++ ++/* Type definition for ADAPTER structure */ ++typedef struct _ADAPTER_T ADAPTER_T, *P_ADAPTER_T; ++ ++/* Type definition for MESSAGE HEADER structure */ ++typedef struct _MSG_HDR_T MSG_HDR_T, *P_MSG_HDR_T; ++ ++/* Type definition for WLAN configuration */ ++typedef struct _WLAN_CFG_T WLAN_CFG_T, *P_WLAN_CFG_T; ++ ++/* Type definition for WLAN configuration entry */ ++typedef struct _WLAN_CFG_ENTRY_T WLAN_CFG_ENTRY_T, *P_WLAN_CFG_ENTRY_T; ++ ++/* Type definition for WLAN configuration callback */ ++typedef WLAN_STATUS(*WLAN_CFG_SET_CB) (P_ADAPTER_T prAdapter, ++ PUINT_8 pucKey, PUINT_8 pucValue, PVOID pPrivate, UINT_32 u4Flags); ++ ++/* Type definition for Pointer to OS Native Packet */ ++typedef void *P_NATIVE_PACKET; ++ ++/* Type definition for STA_RECORD_T structure to handle the connectivity and packet reception ++ * for a particular STA. ++ */ ++typedef struct _STA_RECORD_T STA_RECORD_T, *P_STA_RECORD_T, **PP_STA_RECORD_T; ++ ++/* CMD_INFO_T is used by Glue Layer to send a cluster of Command(OID) information to ++ * the TX Path to reduce the parameters of a function call. ++ */ ++typedef struct _CMD_INFO_T CMD_INFO_T, *P_CMD_INFO_T; ++ ++/* Following typedef should be removed later, because Glue Layer should not ++ * be aware of following data type. ++ */ ++typedef struct _SW_RFB_T SW_RFB_T, *P_SW_RFB_T, **PP_SW_RFB_T; ++ ++typedef struct _MSDU_INFO_T MSDU_INFO_T, *P_MSDU_INFO_T; ++ ++typedef struct _REG_ENTRY_T REG_ENTRY_T, *P_REG_ENTRY_T; ++ ++/* IST handler definition */ ++typedef VOID(*IST_EVENT_FUNCTION) (P_ADAPTER_T); ++ ++/* Type definition for function pointer of timer handler */ ++typedef VOID(*PFN_TIMER_CALLBACK) (IN P_GLUE_INFO_T); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h +new file mode 100644 +index 000000000000..e8937166dc4f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h +@@ -0,0 +1,352 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_bow.h#1 ++*/ ++ ++/*! \file "wlan_bow.h" ++ \brief This file contains the declairations of 802.11 PAL ++ command processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_bow.h ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 23 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add some BoW error handling. ++ * ++ * 05 21 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Protect BoW connection establishment. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting ++ * Send deauth while disconnecting BoW link. ++ * ++ * 05 06 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix BoW Multiple Physical Link connect/disconnect issue. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW table. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update bowString and channel grant. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW Activity Report structure and bug fix. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++#ifndef _WLAN_BOW_H ++#define _WLAN_BOW_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "nic/bow.h" ++#include "nic/cmd_buf.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++#if CFG_BOW_TEST ++extern UINT_32 g_arBowRevPalPacketTime[32]; ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BOWCMD_STATUS_SUCCESS 0 ++#define BOWCMD_STATUS_FAILURE 1 ++#define BOWCMD_STATUS_UNACCEPTED 2 ++#define BOWCMD_STATUS_INVALID 3 ++#define BOWCMD_STATUS_TIMEOUT 4 ++ ++#define BOW_WILDCARD_SSID "AMP" ++#define BOW_WILDCARD_SSID_LEN 3 ++#define BOW_SSID_LEN 21 ++ ++ /* 0: query, 1: setup, 2: destroy */ ++#define BOW_QUERY_CMD 0 ++#define BOW_SETUP_CMD 1 ++#define BOW_DESTROY_CMD 2 ++ ++#define BOW_INITIATOR 0 ++#define BOW_RESPONDER 1 ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++typedef struct _BOW_TABLE_T { ++ UINT_8 ucAcquireID; ++ BOOLEAN fgIsValid; ++ ENUM_BOW_DEVICE_STATE eState; ++ UINT_8 aucPeerAddress[6]; ++ /* UINT_8 ucRole; */ ++ /* UINT_8 ucChannelNum; */ ++ UINT_16 u2Reserved; ++} BOW_TABLE_T, *P_BOW_TABLE_T; ++ ++typedef WLAN_STATUS(*PFN_BOW_CMD_HANDLE) (P_ADAPTER_T, P_AMPC_COMMAND); ++ ++typedef struct _BOW_CMD_T { ++ UINT_8 uCmdID; ++ PFN_BOW_CMD_HANDLE pfCmdHandle; ++} BOW_CMD_T, *P_BOW_CMD_T; ++ ++typedef struct _BOW_EVENT_ACTIVITY_REPORT_T { ++ UINT_8 ucReason; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_EVENT_ACTIVITY_REPORT_T, *P_BOW_EVENT_ACTIVITY_REPORT_T; ++ ++/* ++ucReason: 0: success ++ 1: general failure ++ 2: too much time (> 2/3 second totally) requested for scheduling. ++ Others: reserved. ++*/ ++ ++typedef struct _BOW_EVENT_SYNC_TSF_T { ++ UINT_64 u4TsfTime; ++ UINT_32 u4TsfSysTime; ++ UINT_32 u4ScoTime; ++ UINT_32 u4ScoSysTime; ++} BOW_EVENT_SYNC_TSF_T, *P_BOW_EVENT_SYNC_TSF_T; ++ ++typedef struct _BOW_ACTIVITY_REPORT_BODY_T { ++ UINT_32 u4StartTime; ++ UINT_32 u4Duration; ++ UINT_32 u4Periodicity; ++} BOW_ACTIVITY_REPORT_BODY_T, *P_BOW_ACTIVITY_REPORT_BODY_T; ++ ++typedef struct _BOW_ACTIVITY_REPORT_T { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 ucScheduleKnown; ++ UINT_8 ucNumReports; ++ BOW_ACTIVITY_REPORT_BODY_T arBowActivityReportBody[MAX_ACTIVITY_REPORT]; ++} BOW_ACTIVITY_REPORT_T, *P_BOW_ACTIVITY_REPORT_T; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*--------------------------------------------------------------*/ ++/* Firmware Command Packer */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber); ++ ++/*--------------------------------------------------------------*/ ++/* Command Dispatcher */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle command */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf); ++ ++/*--------------------------------------------------------------*/ ++/* Callbacks for event indication */ ++/*--------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID bowStopping(IN P_ADAPTER_T prAdapter); ++ ++VOID bowStarting(IN P_ADAPTER_T prAdapter); ++ ++VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); ++ ++BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID bowResponderScan(IN P_ADAPTER_T prAdapter); ++ ++VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention); ++ ++VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID ++bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); ++ ++VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++BOOLEAN ++bowValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID bowRequestCh(IN P_ADAPTER_T prAdapter); ++ ++VOID bowReleaseCh(IN P_ADAPTER_T prAdapter); ++ ++VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam); ++ ++BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); ++ ++BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable); ++ ++BOOLEAN ++bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx); ++ ++BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx); ++ ++ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); ++ ++BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState); ++ ++BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif ++#endif /* _WLAN_BOW_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h +new file mode 100644 +index 000000000000..87259397a93d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h +@@ -0,0 +1,1001 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_lib.h#1 ++*/ ++ ++/*! \file "wlan_lib.h" ++ \brief The declaration of the functions of the wlanAdpater objects ++ ++ Detail description. ++*/ ++ ++/* ++** Log: wlan_lib.h ++ * ++ * 06 08 2012 eason.tsai ++ * NULL ++ * Nvram context covert from 6620 to 6628 for old 6620 meta tool ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for ++ * preferred band configuration with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for ++ * setting preferred band configuration corresponding to network type. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * eliminate win32 native data types. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 20 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * change window registry of driver for roaming. ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, ++ * TX deauth to a disconnecting device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result ++ * in OID handling layer when the corresponding BSS is disconnected due to beacon timeout ++ * remove from scanning result when the BSS is disconnected due to beacon timeout. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to ++ * disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * . ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid ++ * descriptor underflow under concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * simplify timer usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add extra 64 adjustable parameters for CoEX scenario. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * 2) add 2 kal API for later integration ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * separate wlanProcesQueuePacket() into 2 APIs upon request ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * * * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * 4) nicRxWaitResponse() revised ++ * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * 4. correct some HAL implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:39:55 GMT mtk02752 ++** eliminate unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:58:41 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-19 10:43:06 GMT mtk01461 ++** Add wlanReleasePendingOid() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-13 16:38:44 GMT mtk01084 ++** add WIFI start function ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-08 16:51:14 GMT mtk01084 ++** Update for the image download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:57:38 GMT mtk01461 ++** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:31:02 GMT mtk01461 ++** Add declaration of FW Image download reference code ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:31 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:04 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_LIB_H ++#define _WLAN_LIB_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "CFG_Wifi_File.h" ++#include "rlm_domain.h" ++#include "wlan_typedef.h" ++ ++ ++extern BOOLEAN fgIsResetting; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define MAX_NUM_GROUP_ADDR 32 /* max number of group addresses */ ++ ++#define TX_CS_TCP_UDP_GEN BIT(1) ++#define TX_CS_IP_GEN BIT(0) ++ ++#define CSUM_OFFLOAD_EN_TX_TCP BIT(0) ++#define CSUM_OFFLOAD_EN_TX_UDP BIT(1) ++#define CSUM_OFFLOAD_EN_TX_IP BIT(2) ++#define CSUM_OFFLOAD_EN_RX_TCP BIT(3) ++#define CSUM_OFFLOAD_EN_RX_UDP BIT(4) ++#define CSUM_OFFLOAD_EN_RX_IPv4 BIT(5) ++#define CSUM_OFFLOAD_EN_RX_IPv6 BIT(6) ++#define CSUM_OFFLOAD_EN_TX_MASK BITS(0, 2) ++#define CSUM_OFFLOAD_EN_ALL BITS(0, 6) ++ ++/* TCP, UDP, IP Checksum */ ++#define RX_CS_TYPE_UDP BIT(7) ++#define RX_CS_TYPE_TCP BIT(6) ++#define RX_CS_TYPE_IPv6 BIT(5) ++#define RX_CS_TYPE_IPv4 BIT(4) ++ ++#define RX_CS_STATUS_UDP BIT(3) ++#define RX_CS_STATUS_TCP BIT(2) ++#define RX_CS_STATUS_IP BIT(0) ++ ++#define CSUM_NOT_SUPPORTED 0x0 ++ ++#define TXPWR_USE_PDSLOPE 0 ++ ++/* NVRAM error code definitions */ ++#define NVRAM_ERROR_VERSION_MISMATCH BIT(1) ++#define NVRAM_ERROR_INVALID_TXPWR BIT(2) ++#define NVRAM_ERROR_INVALID_DPD BIT(3) ++#define NVRAM_ERROR_INVALID_MAC_ADDR BIT(4) ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++#define NVRAM_POWER_LIMIT_TABLE_INVALID BIT(5) ++#endif ++ ++#define NUM_TC_RESOURCE_TO_STATISTICS 4 ++ ++#define WLAN_CFG_ARGV_MAX 8 ++#define WLAN_CFG_ENTRY_NUM_MAX 128 ++#define WLAN_CFG_KEY_LEN_MAX 32 /* include \x00 EOL */ ++#define WLAN_CFG_VALUE_LEN_MAX 32 /* include \x00 EOL */ ++#define WLAN_CFG_FLAG_SKIP_CB BIT(0) ++#define WLAN_CFG_FILE_BUF_SIZE 2048 ++ ++#define WLAN_CFG_SET_CHIP_LEN_MAX 10 ++#define WLAN_CFG_SET_DEBUG_LEVEL_LEN_MAX 10 ++#define WLAN_CFG_SET_SW_CTRL_LEN_MAX 10 ++ ++#define WLAN_OID_TIMEOUT_THRESHOLD 2000 /* OID timeout (in ms) */ ++#define WLAN_OID_TIMEOUT_THRESHOLD_IN_RESETTING 300 /* OID timeout during chip-resetting (in ms) */ ++ ++#define WLAN_OID_NO_ACK_THRESHOLD 3 ++ ++#define WLAN_TX_THREAD_TASK_PRIORITY 0 /* If not setting the priority, 0 is the default */ ++#define WLAN_TX_THREAD_TASK_NICE (-10) /* If not setting the nice, -10 is the default */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC) (IN P_ADAPTER_T prAdapter, ++ IN PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); ++ ++typedef enum _ENUM_CSUM_TYPE_T { ++ CSUM_TYPE_IPV4, ++ CSUM_TYPE_IPV6, ++ CSUM_TYPE_TCP, ++ CSUM_TYPE_UDP, ++ CSUM_TYPE_NUM ++} ENUM_CSUM_TYPE_T, *P_ENUM_CSUM_TYPE_T; ++ ++typedef enum _ENUM_CSUM_RESULT_T { ++ CSUM_RES_NONE, ++ CSUM_RES_SUCCESS, ++ CSUM_RES_FAILED, ++ CSUM_RES_NUM ++} ENUM_CSUM_RESULT_T, *P_ENUM_CSUM_RESULT_T; ++ ++typedef enum _ENUM_PHY_MODE_T { ++ ENUM_PHY_2G4_CCK, ++ ENUM_PHY_2G4_OFDM_BPSK, ++ ENUM_PHY_2G4_OFDM_QPSK, ++ ENUM_PHY_2G4_OFDM_16QAM, ++ ENUM_PHY_2G4_OFDM_48M, ++ ENUM_PHY_2G4_OFDM_54M, ++ ENUM_PHY_2G4_HT20_BPSK, ++ ENUM_PHY_2G4_HT20_QPSK, ++ ENUM_PHY_2G4_HT20_16QAM, ++ ENUM_PHY_2G4_HT20_MCS5, ++ ENUM_PHY_2G4_HT20_MCS6, ++ ENUM_PHY_2G4_HT20_MCS7, ++ ENUM_PHY_2G4_HT40_BPSK, ++ ENUM_PHY_2G4_HT40_QPSK, ++ ENUM_PHY_2G4_HT40_16QAM, ++ ENUM_PHY_2G4_HT40_MCS5, ++ ENUM_PHY_2G4_HT40_MCS6, ++ ENUM_PHY_2G4_HT40_MCS7, ++ ENUM_PHY_5G_OFDM_BPSK, ++ ENUM_PHY_5G_OFDM_QPSK, ++ ENUM_PHY_5G_OFDM_16QAM, ++ ENUM_PHY_5G_OFDM_48M, ++ ENUM_PHY_5G_OFDM_54M, ++ ENUM_PHY_5G_HT20_BPSK, ++ ENUM_PHY_5G_HT20_QPSK, ++ ENUM_PHY_5G_HT20_16QAM, ++ ENUM_PHY_5G_HT20_MCS5, ++ ENUM_PHY_5G_HT20_MCS6, ++ ENUM_PHY_5G_HT20_MCS7, ++ ENUM_PHY_5G_HT40_BPSK, ++ ENUM_PHY_5G_HT40_QPSK, ++ ENUM_PHY_5G_HT40_16QAM, ++ ENUM_PHY_5G_HT40_MCS5, ++ ENUM_PHY_5G_HT40_MCS6, ++ ENUM_PHY_5G_HT40_MCS7, ++ ENUM_PHY_MODE_NUM ++} ENUM_PHY_MODE_T, *P_ENUM_PHY_MODE_T; ++ ++typedef enum _ENUM_POWER_SAVE_POLL_MODE_T { ++ ENUM_POWER_SAVE_POLL_DISABLE, ++ ENUM_POWER_SAVE_POLL_LEGACY_NULL, ++ ENUM_POWER_SAVE_POLL_QOS_NULL, ++ ENUM_POWER_SAVE_POLL_NUM ++} ENUM_POWER_SAVE_POLL_MODE_T, *P_ENUM_POWER_SAVE_POLL_MODE_T; ++ ++typedef enum _ENUM_AC_TYPE_T { ++ ENUM_AC_TYPE_AC0, ++ ENUM_AC_TYPE_AC1, ++ ENUM_AC_TYPE_AC2, ++ ENUM_AC_TYPE_AC3, ++ ENUM_AC_TYPE_AC4, ++ ENUM_AC_TYPE_AC5, ++ ENUM_AC_TYPE_AC6, ++ ENUM_AC_TYPE_BMC, ++ ENUM_AC_TYPE_NUM ++} ENUM_AC_TYPE_T, *P_ENUM_AC_TYPE_T; ++ ++typedef enum _ENUM_ADV_AC_TYPE_T { ++ ENUM_ADV_AC_TYPE_RX_NSW, ++ ENUM_ADV_AC_TYPE_RX_PTA, ++ ENUM_ADV_AC_TYPE_RX_SP, ++ ENUM_ADV_AC_TYPE_TX_PTA, ++ ENUM_ADV_AC_TYPE_TX_RSP, ++ ENUM_ADV_AC_TYPE_NUM ++} ENUM_ADV_AC_TYPE_T, *P_ENUM_ADV_AC_TYPE_T; ++ ++typedef enum _ENUM_REG_CH_MAP_T { ++ REG_CH_MAP_COUNTRY_CODE, ++ REG_CH_MAP_TBL_IDX, ++ REG_CH_MAP_CUSTOMIZED, ++ REG_CH_MAP_NUM ++} ENUM_REG_CH_MAP_T, *P_ENUM_REG_CH_MAP_T; ++ ++#define CHIP_CONFIG_RESP_SIZE 320 ++enum { ++ CHIP_CONFIG_TYPE_WO_RESPONSE = 0x00, ++ CHIP_CONFIG_TYPE_MEM8 = 0x01, ++ CHIP_CONFIG_TYPE_MEM32 = 0x02, ++ CHIP_CONFIG_TYPE_ASCII = 0x03, ++ CHIP_CONFIG_TYPE_BINARY = 0x04, ++ CHIP_CONFIG_TYPE_DRV_PASSTHROUGH = 0x05, ++ CHIP_CONFIG_TYPE_END ++}; ++ ++typedef struct _SET_TXPWR_CTRL_T { ++ INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c2GHotspotPwrOffset; ++ INT_8 c2GP2pPwrOffset; ++ INT_8 c2GBowPwrOffset; ++ INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c5GHotspotPwrOffset; ++ INT_8 c5GP2pPwrOffset; ++ INT_8 c5GBowPwrOffset; ++ UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence ++ in the same channel ++ 0: Highest power has priority ++ 1: Lowest power has priority */ ++ INT_8 acReserved1[3]; /* Must be zero */ ++ ++ /* Power limit by channel for all data rates */ ++ INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ ++ INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ ++ INT_8 acReserved2[2]; /* Must be zero */ ++} SET_TXPWR_CTRL_T, *P_SET_TXPWR_CTRL_T; ++ ++/* For storing driver initialization value from glue layer */ ++typedef struct _REG_INFO_T { ++ UINT_32 u4SdBlockSize; /* SDIO block size */ ++ UINT_32 u4SdBusWidth; /* SDIO bus width. 1 or 4 */ ++ UINT_32 u4SdClockRate; /* SDIO clock rate. (in unit of HZ) */ ++ UINT_32 u4StartAddress; /* Starting address of Wi-Fi Firmware */ ++ UINT_32 u4LoadAddress; /* Load address of Wi-Fi Firmware */ ++ UINT_16 aucFwImgFilename[65]; /* Firmware filename */ ++ UINT_16 aucFwImgFilenameE6[65]; /* Firmware filename for E6 */ ++ UINT_32 u4StartFreq; /* Start Frequency for Ad-Hoc network : in unit of KHz */ ++ UINT_32 u4AdhocMode; /* Default mode for Ad-Hoc network : ENUM_PARAM_AD_HOC_MODE_T */ ++ UINT_32 u4RddStartFreq; ++ UINT_32 u4RddStopFreq; ++ UINT_32 u4RddTestMode; ++ UINT_32 u4RddShutFreq; ++ UINT_32 u4RddDfs; ++ INT_32 i4HighRssiThreshold; ++ INT_32 i4MediumRssiThreshold; ++ INT_32 i4LowRssiThreshold; ++ INT_32 au4TxPriorityTag[ENUM_AC_TYPE_NUM]; ++ INT_32 au4RxPriorityTag[ENUM_AC_TYPE_NUM]; ++ INT_32 au4AdvPriorityTag[ENUM_ADV_AC_TYPE_NUM]; ++ UINT_32 u4FastPSPoll; ++ UINT_32 u4PTA; /* 0: disable, 1: enable */ ++ UINT_32 u4TXLimit; /* 0: disable, 1: enable */ ++ UINT_32 u4SilenceWindow; /* range: 100 - 625, unit: us */ ++ UINT_32 u4TXLimitThreshold; /* range: 250 - 1250, unit: us */ ++ UINT_32 u4PowerMode; ++ UINT_32 fgEnArpFilter; ++ UINT_32 u4PsCurrentMeasureEn; ++ UINT_32 u4UapsdAcBmp; ++ UINT_32 u4MaxSpLen; ++ UINT_32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online scan */ ++ UINT_32 fgDisBcnLostDetection; /* 0: enable online scan, non-zero: disable online scan */ ++ UINT_32 u4FixedRate; /* 0: automatic, non-zero: fixed rate */ ++ UINT_32 u4ArSysParam0; ++ UINT_32 u4ArSysParam1; ++ UINT_32 u4ArSysParam2; ++ UINT_32 u4ArSysParam3; ++ UINT_32 fgDisRoaming; /* 0:enable roaming 1:disable */ ++ ++ /* NVRAM - MP Data -START- */ ++ UINT_8 aucMacAddr[6]; ++ UINT_16 au2CountryCode[4]; /* Country code (in ISO 3166-1 expression, ex: "US", "TW") */ ++ TX_PWR_PARAM_T rTxPwr; ++ UINT_8 aucEFUSE[144]; ++ UINT_8 ucTxPwrValid; ++ UINT_8 ucSupport5GBand; ++ UINT_8 fg2G4BandEdgePwrUsed; ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ ENUM_REG_CH_MAP_T eRegChannelListMap; ++ UINT_8 ucRegChannelListIndex; ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ /* NVRAM - MP Data -END- */ ++ ++ /* NVRAM - Functional Data -START- */ ++ UINT_8 uc2G4BwFixed20M; ++ UINT_8 uc5GBwFixed20M; ++ UINT_8 ucEnable5GBand; ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 fgRssiCompensationValidbit; ++ UINT_8 ucRxAntennanumber; ++ /* NVRAM - Functional Data -END- */ ++ ++} REG_INFO_T, *P_REG_INFO_T; ++ ++/* for divided firmware loading */ ++typedef struct _FWDL_SECTION_INFO_T { ++ UINT_32 u4Offset; ++ UINT_32 u4Reserved; ++ UINT_32 u4Length; ++ UINT_32 u4DestAddr; ++} FWDL_SECTION_INFO_T, *P_FWDL_SECTION_INFO_T; ++ ++typedef struct _FIRMWARE_DIVIDED_DOWNLOAD_T { ++ UINT_32 u4Signature; ++ UINT_32 u4CRC; /* CRC calculated without first 8 bytes included */ ++ UINT_32 u4NumOfEntries; ++ UINT_32 u4Reserved; ++ FWDL_SECTION_INFO_T arSection[]; ++} FIRMWARE_DIVIDED_DOWNLOAD_T, *P_FIRMWARE_DIVIDED_DOWNLOAD_T; ++ ++typedef struct _PARAM_MCR_RW_STRUCT_T { ++ UINT_32 u4McrOffset; ++ UINT_32 u4McrData; ++} PARAM_MCR_RW_STRUCT_T, *P_PARAM_MCR_RW_STRUCT_T; ++ ++typedef struct _PARAM_GET_STA_STATISTICS { ++ UINT_8 ucInvalid; ++ UINT_8 ucVersion; ++ /* Per-STA statistic */ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_32 u4LinkScore; ++ UINT_32 u4Flag; ++ ++ /* From FW */ ++ UINT_8 ucPer; /* base: 128 */ ++ UINT_8 ucRcpi; ++ UINT_32 u4PhyMode; ++ UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ ++ ++ UINT_32 u4TxFailCount; ++ UINT_32 u4TxLifeTimeoutCount; ++ UINT_32 u4TxAverageAirTime; ++ ++ /* From driver */ ++ UINT_32 u4TxTotalCount; ++ UINT_32 u4TxExceedThresholdCount; ++ UINT_32 u4TxAverageProcessTime; ++ ++ UINT_32 u4TxMaxTime; ++ UINT_32 u4TxMaxHifTime; ++ UINT_32 u4TxAverageHifTime; ++ ++ /* ++ * How many packages Enqueue/Deqeue during statistics interval ++ */ ++ UINT_32 u4EnqueueCounter; ++ UINT_32 u4DequeueCounter; ++ ++ UINT_32 u4EnqueueStaCounter; ++ UINT_32 u4DequeueStaCounter; ++ ++ UINT_32 IsrCnt; ++ UINT_32 IsrPassCnt; ++ UINT_32 TaskIsrCnt; ++ ++ UINT_32 IsrAbnormalCnt; ++ UINT_32 IsrSoftWareCnt; ++ UINT_32 IsrRxCnt; ++ UINT_32 IsrTxCnt; ++ ++ UINT_32 au4TcResourceEmptyCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4DequeueNoTcResource[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcResourceBackCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ UINT_32 au4TcResourceUsedCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcResourceWantedCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ UINT_32 au4TcQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ /* Global queue management statistic */ ++ UINT_32 au4TcAverageQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcCurrentQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ /* Reserved fields */ ++ UINT_8 au4Reserved[32]; ++} PARAM_GET_STA_STA_STATISTICS, *P_PARAM_GET_STA_STATISTICS; ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR { ++ NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, ++ NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ ++ NL80211_TESTMODE_AVAILABLE_CHAN_NUM, ++} ENUM_TESTMODE_AVAILABLE_CHAN_ATTR; ++ ++typedef struct _LTE_SAFE_CH_INFO_T { ++ UINT_32 au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1]; ++} LTE_SAFE_CH_INFO_T, *P_CMD_LTE_SAFE_CH_INFO_T; ++ ++ /* Record Each CH Load */ ++typedef struct _PARAM_CHN_LOAD_INFO { ++ /* Per-CHN Load */ ++ UINT_32 u4Flag; ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 au4Reserved[1]; ++ ++ UINT_16 u2APNum; ++ UINT_16 u2APNumTmpCountingBuf; ++ ++ /* Reserved fields */ ++ UINT_8 au4Reserved1[8]; ++} PARAM_CHN_LOAD_INFO, *P_PARAM_CHN_LOAD_INFO; ++ ++typedef struct _PARAM_GET_CHN_LOAD { ++ LTE_SAFE_CH_INFO_T rLteSafeChnList; ++ PARAM_CHN_LOAD_INFO rEachChnLoad[MAX_AUTO_CHAL_NUM]; ++ BOOLEAN fgDataReadyBit; ++ UINT_8 au4Reserved1[3]; ++} PARAM_GET_CHN_LOAD, *P_PARAM_GET_CHN_LOAD; ++ ++typedef struct _PARAM_PREFER_CHN_INFO { ++ ++ UINT_8 ucChannel; ++ UINT_16 u2APNum; ++ UINT_8 au4Reserved1[1]; ++} PARAM_PREFER_CHN_INFO, *P_PARAM_PREFER_CHN_INFO; ++ ++typedef struct _PARAM_GET_LTE_MODE { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ LTE_SAFE_CH_INFO_T LTE_MODE; ++ UINT_8 aucReserved4[3]; ++ ++ UINT_8 aucReserved[4]; ++ ++} PARAM_GET_LTE_MODE, *P_PARAM_GET_LTE_MODE; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ ++ ((UINT_32)(UINT_8)(ch0) | ((UINT_32)(UINT_8)(ch1) << 8) | \ ++ ((UINT_32)(UINT_8)(ch2) << 16) | ((UINT_32)(UINT_8)(ch3) << 24)) ++ ++#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanCardEjected(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanIST(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl); ++ ++WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue); ++ ++WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData); ++ ++VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket); ++ ++VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData); ++ ++WLAN_STATUS ++wlanQueryInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfOidQryHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen); ++ ++WLAN_STATUS ++wlanSetInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfOidSetHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanAdapterStart(IN P_ADAPTER_T prAdapter, ++ IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength); ++ ++WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_SUPPORT_WAPI ++BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID wlanReturnRxPacket(IN PVOID pvAdapter, IN PVOID pvPacket); ++ ++VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast); ++ ++BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); ++ ++VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++WLAN_STATUS ++wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); ++#endif ++ ++WLAN_STATUS ++wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); ++ ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter); ++#else ++WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum); ++#endif ++ ++WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress); ++ ++UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len); ++ ++#endif ++ ++WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode); ++ ++BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); ++ ++WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); ++ ++WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler); ++ ++VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter); ++ ++/* Security Frame Handling */ ++BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket); ++ ++VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID); ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Address Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* NIC Capability Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* NIC Capability Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Compiler Flags Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* PD MCR Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, IN P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo); ++/*----------------------------------------------------------------------------*/ ++/* Loading Manufacture Data */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Media Stream Mode */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Timer Timeout Check (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Check (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX Pending Packets Handling (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket); ++ ++WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess); ++ ++/*----------------------------------------------------------------------------*/ ++/* Low Power Acquire/Release (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Pending Packets Number Reporting (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* ACPI state inquiry (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState); ++ ++VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* get ECO version from Revision ID register (for Win32) */ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* set preferred band configuration corresponding to network type */ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* get currently operating channel information */ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* get BSS Descriptor information */ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* check for system configuration to generate message on scan list */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* query sta statistics information from driver and firmware */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]); ++ ++P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey); ++ ++WLAN_STATUS ++wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags); ++ ++UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef); ++ ++INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef); ++ ++WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value); ++ ++WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags); ++ ++WLAN_STATUS ++wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags); ++ ++#if CFG_SUPPORT_CFG_FILE ++WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags); ++ ++VOID wlanCfgApply(IN P_ADAPTER_T prAdapter); ++#endif /* CFG_SUPPORT_CFG_FILE */ ++ ++extern VOID mtk_wcn_wmt_set_wifi_ver(UINT_32 Value); ++ ++#endif /* _WLAN_LIB_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h +new file mode 100644 +index 000000000000..45919df996e9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h +@@ -0,0 +1,1715 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_oid.h#2 ++*/ ++ ++/*! \file "wlan_oid.h" ++ \brief This file contains the declairation file of the WLAN OID processing routines ++ of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_oid.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. ++ * ++ ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00003830]add OID_802_11_PRIVACY_FILTER support ++ * enable RX filter OID ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * OID_802_11_RSSI, ++ * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * OID_802_11_STATISTICS, ++ * * * * OID_802_11_DISASSOCIATE, ++ * * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-08 11:38:11 GMT mtk02752 ++** add declares for RF test related APIs ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-24 22:41:53 GMT mtk02752 ++** remove u4SysTime, MSDN 10-second will be implemented in FW side ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 20:30:13 GMT mtk02752 ++** add u4SysTime field in PARAM_BSSID_EX_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-12 19:48:35 GMT mtk02752 ++** allow upper layer to set a packet filter with PROMISCUOUS mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:12 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_OID_H ++#define _WLAN_OID_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if DBG ++extern UINT_8 aucDebugModule[DBG_MODULE_NUM]; ++extern UINT_32 u4DebugModule; ++UINT_32 u4DebugModuleTemp; ++#endif /* DBG */ ++extern int sprintf(char *buf, const char *fmt, ...); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define PARAM_MAX_LEN_SSID 32 ++ ++#define PARAM_MAC_ADDR_LEN 6 ++ ++#define ETHERNET_HEADER_SZ 14 ++#define ETHERNET_MIN_PKT_SZ 60 ++#define ETHERNET_MAX_PKT_SZ 1514 ++ ++#define PARAM_MAX_LEN_RATES 8 ++#define PARAM_MAX_LEN_RATES_EX 16 ++ ++#define PARAM_AUTH_REQUEST_REAUTH 0x01 ++#define PARAM_AUTH_REQUEST_KEYUPDATE 0x02 ++#define PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++#define PARAM_EEPROM_READ_METHOD_READ 1 ++#define PARAM_EEPROM_READ_METHOD_GETSIZE 0 ++ ++#define PARAM_WHQL_RSSI_MAX_DBM (-10) ++#define PARAM_WHQL_RSSI_MIN_DBM (-200) ++ ++#define PARAM_DEVICE_WAKE_UP_ENABLE 0x00000001 ++#define PARAM_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 ++#define PARAM_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 ++ ++#define PARAM_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define PARAM_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define PARAM_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++/* Packet filter bit definitioin (UINT_32 bit-wise definition) */ ++#define PARAM_PACKET_FILTER_DIRECTED 0x00000001 ++#define PARAM_PACKET_FILTER_MULTICAST 0x00000002 ++#define PARAM_PACKET_FILTER_ALL_MULTICAST 0x00000004 ++#define PARAM_PACKET_FILTER_BROADCAST 0x00000008 ++#define PARAM_PACKET_FILTER_PROMISCUOUS 0x00000020 ++#define PARAM_PACKET_FILTER_ALL_LOCAL 0x00000080 ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#define PARAM_PACKET_FILTER_P2P_MASK 0xC0000000 ++#define PARAM_PACKET_FILTER_PROBE_REQ 0x80000000 ++#define PARAM_PACKET_FILTER_ACTION_FRAME 0x40000000 ++#endif ++ ++#if CFG_SLT_SUPPORT ++#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ ++ PARAM_PACKET_FILTER_MULTICAST | \ ++ PARAM_PACKET_FILTER_BROADCAST | \ ++ PARAM_PACKET_FILTER_ALL_MULTICAST) ++#else ++#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ ++ PARAM_PACKET_FILTER_MULTICAST | \ ++ PARAM_PACKET_FILTER_BROADCAST) ++#endif ++ ++#define PARAM_MEM_DUMP_MAX_SIZE 2048 ++ ++#define BT_PROFILE_PARAM_LEN 8 ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Parameters of User Configuration which match to NDIS5.1 */ ++/*----------------------------------------------------------------------------*/ ++/* NDIS_802_11_AUTHENTICATION_MODE */ ++typedef enum _ENUM_PARAM_AUTH_MODE_T { ++ AUTH_MODE_OPEN, /*!< Open system */ ++ AUTH_MODE_SHARED, /*!< Shared key */ ++ AUTH_MODE_AUTO_SWITCH, /*!< Either open system or shared key */ ++ AUTH_MODE_WPA, ++ AUTH_MODE_WPA_PSK, ++ AUTH_MODE_WPA_NONE, /*!< For Ad hoc */ ++ AUTH_MODE_WPA2, ++ AUTH_MODE_WPA2_PSK, ++ AUTH_MODE_NUM /*!< Upper bound, not real case */ ++} ENUM_PARAM_AUTH_MODE_T, *P_ENUM_PARAM_AUTH_MODE_T; ++ ++/* NDIS_802_11_ENCRYPTION_STATUS *//* Encryption types */ ++typedef enum _ENUM_WEP_STATUS_T { ++ ENUM_WEP_ENABLED, ++ ENUM_ENCRYPTION1_ENABLED = ENUM_WEP_ENABLED, ++ ENUM_WEP_DISABLED, ++ ENUM_ENCRYPTION_DISABLED = ENUM_WEP_DISABLED, ++ ENUM_WEP_KEY_ABSENT, ++ ENUM_ENCRYPTION1_KEY_ABSENT = ENUM_WEP_KEY_ABSENT, ++ ENUM_WEP_NOT_SUPPORTED, ++ ENUM_ENCRYPTION_NOT_SUPPORTED = ENUM_WEP_NOT_SUPPORTED, ++ ENUM_ENCRYPTION2_ENABLED, ++ ENUM_ENCRYPTION2_KEY_ABSENT, ++ ENUM_ENCRYPTION3_ENABLED, ++ ENUM_ENCRYPTION3_KEY_ABSENT ++} ENUM_PARAM_ENCRYPTION_STATUS_T, *P_ENUM_PARAM_ENCRYPTION_STATUS_T; ++ ++typedef UINT_8 PARAM_MAC_ADDRESS[PARAM_MAC_ADDR_LEN]; ++ ++typedef UINT_32 PARAM_KEY_INDEX; ++typedef UINT_64 PARAM_KEY_RSC; ++typedef INT_32 PARAM_RSSI; ++ ++typedef UINT_32 PARAM_FRAGMENTATION_THRESHOLD; ++typedef UINT_32 PARAM_RTS_THRESHOLD; ++ ++typedef UINT_8 PARAM_RATES[PARAM_MAX_LEN_RATES]; ++typedef UINT_8 PARAM_RATES_EX[PARAM_MAX_LEN_RATES_EX]; ++ ++typedef enum _ENUM_PARAM_PHY_TYPE_T { ++ PHY_TYPE_802_11ABG = 0, /*!< Can associated with 802.11abg AP, ++ Scan dual band. */ ++ PHY_TYPE_802_11BG, /*!< Can associated with 802_11bg AP, ++ Scan single band and not report 802_11a BSSs. */ ++ PHY_TYPE_802_11G, /*!< Can associated with 802_11g only AP, ++ Scan single band and not report 802_11ab BSSs. */ ++ PHY_TYPE_802_11A, /*!< Can associated with 802_11a only AP, ++ Scan single band and not report 802_11bg BSSs. */ ++ PHY_TYPE_802_11B, /*!< Can associated with 802_11b only AP, ++ Scan single band and not report 802_11ag BSSs. */ ++ PHY_TYPE_NUM /* 5 */ ++} ENUM_PARAM_PHY_TYPE_T, *P_ENUM_PARAM_PHY_TYPE_T; ++ ++typedef enum _ENUM_PARAM_OP_MODE_T { ++ NET_TYPE_IBSS = 0, /*!< Try to merge/establish an AdHoc, do periodic SCAN for merging. */ ++ NET_TYPE_INFRA, /*!< Try to join an Infrastructure, do periodic SCAN for joining. */ ++ NET_TYPE_AUTO_SWITCH, /*!< Try to join an Infrastructure, if fail then try to merge or ++ establish an AdHoc, do periodic SCAN for joining or merging. */ ++ NET_TYPE_DEDICATED_IBSS, /*!< Try to merge an AdHoc first, ++ if fail then establish AdHoc permanently, no more SCAN. */ ++ NET_TYPE_NUM /* 4 */ ++} ENUM_PARAM_OP_MODE_T, *P_ENUM_PARAM_OP_MODE_T; ++ ++typedef struct _PARAM_SSID_T { ++ UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_32 u4CenterFreq; ++} PARAM_SSID_T, *P_PARAM_SSID_T; ++ ++typedef struct _PARAM_CONNECT_T { ++ UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ ++ UINT_8 *pucSsid; ++ UINT_8 *pucBssid; ++ UINT_32 u4CenterFreq; ++} PARAM_CONNECT_T, *P_PARAM_CONNECT_T; ++ ++/* This is enum defined for user to select an AdHoc Mode */ ++typedef enum _ENUM_PARAM_AD_HOC_MODE_T { ++ AD_HOC_MODE_11B = 0, /*!< Create 11b IBSS if we support 802.11abg/802.11bg. */ ++ AD_HOC_MODE_MIXED_11BG, /*!< Create 11bg mixed IBSS if we support 802.11abg/802.11bg/802.11g. */ ++ AD_HOC_MODE_11G, /*!< Create 11g only IBSS if we support 802.11abg/802.11bg/802.11g. */ ++ AD_HOC_MODE_11A, /*!< Create 11a only IBSS if we support 802.11abg. */ ++ AD_HOC_MODE_NUM /* 4 */ ++} ENUM_PARAM_AD_HOC_MODE_T, *P_ENUM_PARAM_AD_HOC_MODE_T; ++ ++typedef enum _ENUM_PARAM_MEDIA_STATE_T { ++ PARAM_MEDIA_STATE_CONNECTED, ++ PARAM_MEDIA_STATE_DISCONNECTED, ++ PARAM_MEDIA_STATE_TO_BE_INDICATED /* for following MSDN re-association behavior */ ++} ENUM_PARAM_MEDIA_STATE_T, *P_ENUM_PARAM_MEDIA_STATE_T; ++ ++typedef enum _ENUM_PARAM_NETWORK_TYPE_T { ++ PARAM_NETWORK_TYPE_FH, ++ PARAM_NETWORK_TYPE_DS, ++ PARAM_NETWORK_TYPE_OFDM5, ++ PARAM_NETWORK_TYPE_OFDM24, ++ PARAM_NETWORK_TYPE_AUTOMODE, ++ PARAM_NETWORK_TYPE_NUM /*!< Upper bound, not real case */ ++} ENUM_PARAM_NETWORK_TYPE_T, *P_ENUM_PARAM_NETWORK_TYPE_T; ++ ++typedef struct _PARAM_NETWORK_TYPE_LIST { ++ UINT_32 NumberOfItems; /*!< At least 1 */ ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType[1]; ++} PARAM_NETWORK_TYPE_LIST, *PPARAM_NETWORK_TYPE_LIST; ++ ++typedef enum _ENUM_PARAM_PRIVACY_FILTER_T { ++ PRIVACY_FILTER_ACCEPT_ALL, ++ PRIVACY_FILTER_8021xWEP, ++ PRIVACY_FILTER_NUM ++} ENUM_PARAM_PRIVACY_FILTER_T, *P_ENUM_PARAM_PRIVACY_FILTER_T; ++ ++typedef enum _ENUM_RELOAD_DEFAULTS { ++ ENUM_RELOAD_WEP_KEYS ++} PARAM_RELOAD_DEFAULTS, *P_PARAM_RELOAD_DEFAULTS; ++ ++typedef struct _PARAM_PM_PACKET_PATTERN { ++ UINT_32 Priority; /* Importance of the given pattern. */ ++ UINT_32 Reserved; /* Context information for transports. */ ++ UINT_32 MaskSize; /* Size in bytes of the pattern mask. */ ++ UINT_32 PatternOffset; /* Offset from beginning of this */ ++ /* structure to the pattern bytes. */ ++ UINT_32 PatternSize; /* Size in bytes of the pattern. */ ++ UINT_32 PatternFlags; /* Flags (TBD). */ ++} PARAM_PM_PACKET_PATTERN, *P_PARAM_PM_PACKET_PATTERN; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Struct definition to indicate specific event. */ ++/*--------------------------------------------------------------*/ ++typedef enum _ENUM_STATUS_TYPE_T { ++ ENUM_STATUS_TYPE_AUTHENTICATION, ++ ENUM_STATUS_TYPE_MEDIA_STREAM_MODE, ++ ENUM_STATUS_TYPE_CANDIDATE_LIST, ++ ENUM_STATUS_TYPE_NUM /*!< Upper bound, not real case */ ++} ENUM_STATUS_TYPE_T, *P_ENUM_STATUS_TYPE_T; ++ ++typedef struct _PARAM_802_11_CONFIG_FH_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4HopPattern; /*!< Defined as 802.11 */ ++ UINT_32 u4HopSet; /*!< to one if non-802.11 */ ++ UINT_32 u4DwellTime; /*!< In unit of Kusec */ ++} PARAM_802_11_CONFIG_FH_T, *P_PARAM_802_11_CONFIG_FH_T; ++ ++typedef struct _PARAM_802_11_CONFIG_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4BeaconPeriod; /*!< In unit of Kusec */ ++ UINT_32 u4ATIMWindow; /*!< In unit of Kusec */ ++ UINT_32 u4DSConfig; /*!< Channel frequency in unit of kHz */ ++ PARAM_802_11_CONFIG_FH_T rFHConfig; ++} PARAM_802_11_CONFIG_T, *P_PARAM_802_11_CONFIG_T; ++ ++typedef struct _PARAM_STATUS_INDICATION_T { ++ ENUM_STATUS_TYPE_T eStatusType; ++} PARAM_STATUS_INDICATION_T, *P_PARAM_STATUS_INDICATION_T; ++ ++typedef struct _PARAM_AUTH_REQUEST_T { ++ UINT_32 u4Length; /*!< Length of this struct */ ++ PARAM_MAC_ADDRESS arBssid; ++ UINT_32 u4Flags; /*!< Definitions are as follows */ ++} PARAM_AUTH_REQUEST_T, *P_PARAM_AUTH_REQUEST_T; ++ ++typedef struct _PARAM_AUTH_EVENT_T { ++ PARAM_STATUS_INDICATION_T rStatus; ++ PARAM_AUTH_REQUEST_T arRequest[1]; ++} PARAM_AUTH_EVENT_T, *P_PARAM_AUTH_EVENT_T; ++ ++/*! \brief Capabilities, privacy, rssi and IEs of each BSSID */ ++typedef struct _PARAM_BSSID_EX_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ PARAM_MAC_ADDRESS arMacAddress; /*!< BSSID */ ++ UINT_8 Reserved[2]; ++ PARAM_SSID_T rSsid; /*!< SSID */ ++ UINT_32 u4Privacy; /*!< Need WEP encryption */ ++ PARAM_RSSI rRssi; /*!< in dBm */ ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkTypeInUse; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ PARAM_RATES_EX rSupportedRates; ++ UINT_32 u4IELength; ++ UINT_8 aucIEs[1]; ++} PARAM_BSSID_EX_T, *P_PARAM_BSSID_EX_T; ++ ++typedef struct _PARAM_BSSID_LIST_EX { ++ UINT_32 u4NumberOfItems; /*!< at least 1 */ ++ PARAM_BSSID_EX_T arBssid[1]; ++} PARAM_BSSID_LIST_EX_T, *P_PARAM_BSSID_LIST_EX_T; ++ ++typedef struct _PARAM_WEP_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< 0: pairwise key, others group keys */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} PARAM_WEP_T, *P_PARAM_WEP_T; ++ ++/*! \brief Key mapping of BSSID */ ++typedef struct _PARAM_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++ PARAM_KEY_RSC rKeyRSC; ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} PARAM_KEY_T, *P_PARAM_KEY_T; ++ ++typedef struct _PARAM_REMOVE_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++} PARAM_REMOVE_KEY_T, *P_PARAM_REMOVE_KEY_T; ++ ++#if CFG_SUPPORT_WAPI ++typedef enum _ENUM_KEY_TYPE { ++ ENUM_WPI_PAIRWISE_KEY = 0, ++ ENUM_WPI_GROUP_KEY ++} ENUM_KEY_TYPE; ++ ++typedef enum _ENUM_WPI_PROTECT_TYPE { ++ ENUM_WPI_NONE, ++ ENUM_WPI_RX, ++ ENUM_WPI_TX, ++ ENUM_WPI_RX_TX ++} ENUM_WPI_PROTECT_TYPE; ++ ++typedef struct _PARAM_WPI_KEY_T { ++ ENUM_KEY_TYPE eKeyType; ++ ENUM_WPI_PROTECT_TYPE eDirection; ++ UINT_8 ucKeyID; ++ UINT_8 aucRsv[3]; ++ UINT_8 aucAddrIndex[12]; ++ UINT_32 u4LenWPIEK; ++ UINT_8 aucWPIEK[256]; ++ UINT_32 u4LenWPICK; ++ UINT_8 aucWPICK[256]; ++ UINT_8 aucPN[16]; ++} PARAM_WPI_KEY_T, *P_PARAM_WPI_KEY_T; ++#endif ++ ++typedef enum _PARAM_POWER_MODE { ++ Param_PowerModeCAM, ++ Param_PowerModeMAX_PSP, ++ Param_PowerModeFast_PSP, ++#if CFG_SUPPORT_DBG_POWERMODE ++ Param_PowerModeKeepActiveOn, /* privilege mode, always active */ ++ Param_PowerModeKeepActiveOff, /* to leave privilege mode */ ++#endif ++ Param_PowerModeMax /* Upper bound, not real case */ ++} PARAM_POWER_MODE, *PPARAM_POWER_MODE; ++ ++typedef enum _PARAM_DEVICE_POWER_STATE { ++ ParamDeviceStateUnspecified = 0, ++ ParamDeviceStateD0, ++ ParamDeviceStateD1, ++ ParamDeviceStateD2, ++ ParamDeviceStateD3, ++ ParamDeviceStateMaximum ++} PARAM_DEVICE_POWER_STATE, *PPARAM_DEVICE_POWER_STATE; ++ ++#if CFG_SUPPORT_802_11D ++ ++/*! \brief The enumeration definitions for OID_IPN_MULTI_DOMAIN_CAPABILITY */ ++typedef enum _PARAM_MULTI_DOMAIN_CAPABILITY { ++ ParamMultiDomainCapDisabled, ++ ParamMultiDomainCapEnabled ++} PARAM_MULTI_DOMAIN_CAPABILITY, *P_PARAM_MULTI_DOMAIN_CAPABILITY; ++#endif ++ ++typedef struct _COUNTRY_STRING_ENTRY { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 aucEnvironmentCode[2]; ++} COUNTRY_STRING_ENTRY, *P_COUNTRY_STRING_ENTRY; ++ ++/* Power management related definition and enumerations */ ++#define UAPSD_NONE 0 ++#define UAPSD_AC0 (BIT(0) | BIT(4)) ++#define UAPSD_AC1 (BIT(1) | BIT(5)) ++#define UAPSD_AC2 (BIT(2) | BIT(6)) ++#define UAPSD_AC3 (BIT(3) | BIT(7)) ++#define UAPSD_ALL (UAPSD_AC0 | UAPSD_AC1 | UAPSD_AC2 | UAPSD_AC3) ++ ++typedef enum _ENUM_POWER_SAVE_PROFILE_T { ++ ENUM_PSP_CONTINUOUS_ACTIVE = 0, ++ ENUM_PSP_CONTINUOUS_POWER_SAVE, ++ ENUM_PSP_FAST_SWITCH, ++ ENUM_PSP_NUM ++} ENUM_POWER_SAVE_PROFILE_T, *PENUM_POWER_SAVE_PROFILE_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Set/Query testing type. */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_802_11_TEST_T { ++ UINT_32 u4Length; ++ UINT_32 u4Type; ++ union { ++ PARAM_AUTH_EVENT_T AuthenticationEvent; ++ PARAM_RSSI RssiTrigger; ++ } u; ++} PARAM_802_11_TEST_T, *P_PARAM_802_11_TEST_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Set/Query authentication and encryption capability. */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_AUTH_ENCRYPTION_T { ++ ENUM_PARAM_AUTH_MODE_T eAuthModeSupported; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncryptStatusSupported; ++} PARAM_AUTH_ENCRYPTION_T, *P_PARAM_AUTH_ENCRYPTION_T; ++ ++typedef struct _PARAM_CAPABILITY_T { ++ UINT_32 u4Length; ++ UINT_32 u4Version; ++ UINT_32 u4NoOfPMKIDs; ++ UINT_32 u4NoOfAuthEncryptPairsSupported; ++ PARAM_AUTH_ENCRYPTION_T arAuthenticationEncryptionSupported[1]; ++} PARAM_CAPABILITY_T, *P_PARAM_CAPABILITY_T; ++ ++typedef UINT_8 PARAM_PMKID_VALUE[16]; ++ ++typedef struct _PARAM_BSSID_INFO_T { ++ PARAM_MAC_ADDRESS arBSSID; ++ PARAM_PMKID_VALUE arPMKID; ++} PARAM_BSSID_INFO_T, *P_PARAM_BSSID_INFO_T; ++ ++typedef struct _PARAM_PMKID_T { ++ UINT_32 u4Length; ++ UINT_32 u4BSSIDInfoCount; ++ PARAM_BSSID_INFO_T arBSSIDInfo[1]; ++} PARAM_PMKID_T, *P_PARAM_PMKID_T; ++ ++/*! \brief PMKID candidate lists. */ ++typedef struct _PARAM_PMKID_CANDIDATE_T { ++ PARAM_MAC_ADDRESS arBSSID; ++ UINT_32 u4Flags; ++} PARAM_PMKID_CANDIDATE_T, *P_PARAM_PMKID_CANDIDATE_T; ++ ++/* #ifdef LINUX */ ++typedef struct _PARAM_PMKID_CANDIDATE_LIST_T { ++ UINT_32 u4Version; /*!< Version */ ++ UINT_32 u4NumCandidates; /*!< How many candidates follow */ ++ PARAM_PMKID_CANDIDATE_T arCandidateList[1]; ++} PARAM_PMKID_CANDIDATE_LIST_T, *P_PARAM_PMKID_CANDIDATE_LIST_T; ++/* #endif */ ++ ++typedef struct _PARAM_CUSTOM_MCR_RW_STRUCT_T { ++ UINT_32 u4McrOffset; ++ UINT_32 u4McrData; ++} PARAM_CUSTOM_MCR_RW_STRUCT_T, *P_PARAM_CUSTOM_MCR_RW_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_MEM_DUMP_STRUCT_T { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++} PARAM_CUSTOM_MEM_DUMP_STRUCT_T, *P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_SW_CTRL_STRUCT_T { ++ UINT_32 u4Id; ++ UINT_32 u4Data; ++} PARAM_CUSTOM_SW_CTRL_STRUCT_T, *P_PARAM_CUSTOM_SW_CTRL_STRUCT_T; ++ ++typedef struct _CMD_CHIP_CONFIG_T { ++ UINT_16 u2Id; ++ UINT_8 ucType; ++ UINT_8 ucRespType; ++ UINT_16 u2MsgSize; ++ UINT_8 aucReserved0[2]; ++ UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; ++} CMD_CHIP_CONFIG_T, *P_CMD_CHIP_CONFIG_T; ++ ++typedef struct _PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T { ++ UINT_16 u2Id; ++ UINT_8 ucType; ++ UINT_8 ucRespType; ++ UINT_16 u2MsgSize; ++ UINT_8 aucReserved0[2]; ++ UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; ++} PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T, *P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_KEY_CFG_STRUCT_T { ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++} PARAM_CUSTOM_KEY_CFG_STRUCT_T, *P_PARAM_CUSTOM_KEY_CFG_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_EEPROM_RW_STRUCT_T { ++ UINT_8 ucEepromMethod; /* For read only read: 1, query size: 0 */ ++ UINT_8 ucEepromIndex; ++ UINT_8 reserved; ++ UINT_16 u2EepromData; ++} PARAM_CUSTOM_EEPROM_RW_STRUCT_T, *P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T, ++PARAM_CUSTOM_NVRAM_RW_STRUCT_T, *P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T { ++ UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ ++ UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ ++ UINT_8 reserved; ++} PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T, *P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_NOA_PARAM_STRUCT_T { ++ UINT_32 u4NoaDurationMs; ++ UINT_32 u4NoaIntervalMs; ++ UINT_32 u4NoaCount; ++} PARAM_CUSTOM_NOA_PARAM_STRUCT_T, *P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T { ++ UINT_32 u4CTwindowMs; ++} PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T { ++ UINT_8 fgEnAPSD; ++ UINT_8 fgEnAPSD_AcBe; ++ UINT_8 fgEnAPSD_AcBk; ++ UINT_8 fgEnAPSD_AcVo; ++ UINT_8 fgEnAPSD_AcVi; ++ UINT_8 ucMaxSpLen; ++ UINT_8 aucResv[2]; ++} PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { ++ UINT_32 u4Enable; ++ UINT_32 u4Mode; ++} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; ++ ++typedef enum _ENUM_CFG_SRC_TYPE_T { ++ CFG_SRC_TYPE_EEPROM, ++ CFG_SRC_TYPE_NVRAM, ++ CFG_SRC_TYPE_UNKNOWN, ++ CFG_SRC_TYPE_NUM ++} ENUM_CFG_SRC_TYPE_T, *P_ENUM_CFG_SRC_TYPE_T; ++ ++typedef enum _ENUM_EEPROM_TYPE_T { ++ EEPROM_TYPE_NO, ++ EEPROM_TYPE_PRESENT, ++ EEPROM_TYPE_NUM ++} ENUM_EEPROM_TYPE_T, *P_ENUM_EEPROM_TYPE_T; ++ ++typedef struct _PARAM_QOS_TSINFO { ++ UINT_8 ucTrafficType; /* Traffic Type: 1 for isochronous 0 for asynchronous */ ++ UINT_8 ucTid; /* TSID: must be between 8 ~ 15 */ ++ UINT_8 ucDirection; /* direction */ ++ UINT_8 ucAccessPolicy; /* access policy */ ++ UINT_8 ucAggregation; /* aggregation */ ++ UINT_8 ucApsd; /* APSD */ ++ UINT_8 ucuserPriority; /* user priority */ ++ UINT_8 ucTsInfoAckPolicy; /* TSINFO ACK policy */ ++ UINT_8 ucSchedule; /* Schedule */ ++} PARAM_QOS_TSINFO, *P_PARAM_QOS_TSINFO; ++ ++typedef struct _PARAM_QOS_TSPEC { ++ PARAM_QOS_TSINFO rTsInfo; /* TS info field */ ++ UINT_16 u2NominalMSDUSize; /* nominal MSDU size */ ++ UINT_16 u2MaxMSDUsize; /* maximum MSDU size */ ++ UINT_32 u4MinSvcIntv; /* minimum service interval */ ++ UINT_32 u4MaxSvcIntv; /* maximum service interval */ ++ UINT_32 u4InactIntv; /* inactivity interval */ ++ UINT_32 u4SpsIntv; /* suspension interval */ ++ UINT_32 u4SvcStartTime; /* service start time */ ++ UINT_32 u4MinDataRate; /* minimum Data rate */ ++ UINT_32 u4MeanDataRate; /* mean data rate */ ++ UINT_32 u4PeakDataRate; /* peak data rate */ ++ UINT_32 u4MaxBurstSize; /* maximum burst size */ ++ UINT_32 u4DelayBound; /* delay bound */ ++ UINT_32 u4MinPHYRate; /* minimum PHY rate */ ++ UINT_16 u2Sba; /* surplus bandwidth allowance */ ++ UINT_16 u2MediumTime; /* medium time */ ++} PARAM_QOS_TSPEC, *P_PARAM_QOS_TSPEC; ++ ++typedef struct _PARAM_QOS_ADDTS_REQ_INFO { ++ PARAM_QOS_TSPEC rTspec; ++} PARAM_QOS_ADDTS_REQ_INFO, *P_PARAM_QOS_ADDTS_REQ_INFO; ++ ++typedef struct _PARAM_VOIP_CONFIG { ++ UINT_32 u4VoipTrafficInterval; /* 0: disable VOIP configuration */ ++} PARAM_VOIP_CONFIG, *P_PARAM_VOIP_CONFIG; ++ ++/*802.11 Statistics Struct*/ ++typedef struct _PARAM_802_11_STATISTICS_STRUCT_T { ++ UINT_32 u4Length; /* Length of structure */ ++ LARGE_INTEGER rTransmittedFragmentCount; ++ LARGE_INTEGER rMulticastTransmittedFrameCount; ++ LARGE_INTEGER rFailedCount; ++ LARGE_INTEGER rRetryCount; ++ LARGE_INTEGER rMultipleRetryCount; ++ LARGE_INTEGER rRTSSuccessCount; ++ LARGE_INTEGER rRTSFailureCount; ++ LARGE_INTEGER rACKFailureCount; ++ LARGE_INTEGER rFrameDuplicateCount; ++ LARGE_INTEGER rReceivedFragmentCount; ++ LARGE_INTEGER rMulticastReceivedFrameCount; ++ LARGE_INTEGER rFCSErrorCount; ++ LARGE_INTEGER rTKIPLocalMICFailures; ++ LARGE_INTEGER rTKIPICVErrors; ++ LARGE_INTEGER rTKIPCounterMeasuresInvoked; ++ LARGE_INTEGER rTKIPReplays; ++ LARGE_INTEGER rCCMPFormatErrors; ++ LARGE_INTEGER rCCMPReplays; ++ LARGE_INTEGER rCCMPDecryptErrors; ++ LARGE_INTEGER rFourWayHandshakeFailures; ++ LARGE_INTEGER rWEPUndecryptableCount; ++ LARGE_INTEGER rWEPICVErrorCount; ++ LARGE_INTEGER rDecryptSuccessCount; ++ LARGE_INTEGER rDecryptFailureCount; ++} PARAM_802_11_STATISTICS_STRUCT_T, *P_PARAM_802_11_STATISTICS_STRUCT_T; ++ ++/* Linux Network Device Statistics Struct */ ++typedef struct _PARAM_LINUX_NETDEV_STATISTICS_T { ++ UINT_32 u4RxPackets; ++ UINT_32 u4TxPackets; ++ UINT_32 u4RxBytes; ++ UINT_32 u4TxBytes; ++ UINT_32 u4RxErrors; ++ UINT_32 u4TxErrors; ++ UINT_32 u4Multicast; ++} PARAM_LINUX_NETDEV_STATISTICS_T, *P_PARAM_LINUX_NETDEV_STATISTICS_T; ++ ++typedef struct _PARAM_MTK_WIFI_TEST_STRUCT_T { ++ UINT_32 u4FuncIndex; ++ UINT_32 u4FuncData; ++} PARAM_MTK_WIFI_TEST_STRUCT_T, *P_PARAM_MTK_WIFI_TEST_STRUCT_T; ++ ++/* 802.11 Media stream constraints */ ++typedef enum _ENUM_MEDIA_STREAM_MODE { ++ ENUM_MEDIA_STREAM_OFF, ++ ENUM_MEDIA_STREAM_ON ++} ENUM_MEDIA_STREAM_MODE, *P_ENUM_MEDIA_STREAM_MODE; ++ ++/* for NDIS 5.1 Media Streaming Change */ ++typedef struct _PARAM_MEDIA_STREAMING_INDICATION { ++ PARAM_STATUS_INDICATION_T rStatus; ++ ENUM_MEDIA_STREAM_MODE eMediaStreamMode; ++} PARAM_MEDIA_STREAMING_INDICATION, *P_PARAM_MEDIA_STREAMING_INDICATION; ++ ++#define PARAM_PROTOCOL_ID_DEFAULT 0x00 ++#define PARAM_PROTOCOL_ID_TCP_IP 0x02 ++#define PARAM_PROTOCOL_ID_IPX 0x06 ++#define PARAM_PROTOCOL_ID_NBF 0x07 ++#define PARAM_PROTOCOL_ID_MAX 0x0F ++#define PARAM_PROTOCOL_ID_MASK 0x0F ++ ++/* for NDIS OID_GEN_NETWORK_LAYER_ADDRESSES */ ++typedef struct _PARAM_NETWORK_ADDRESS_IP { ++ UINT_16 sin_port; ++ UINT_32 in_addr; ++ UINT_8 sin_zero[8]; ++} PARAM_NETWORK_ADDRESS_IP, *P_PARAM_NETWORK_ADDRESS_IP; ++ ++typedef struct _PARAM_NETWORK_ADDRESS { ++ UINT_16 u2AddressLength; /* length in bytes of Address[] in this */ ++ UINT_16 u2AddressType; /* type of this address (PARAM_PROTOCOL_ID_XXX above) */ ++ UINT_8 aucAddress[1]; /* actually AddressLength bytes long */ ++} PARAM_NETWORK_ADDRESS, *P_PARAM_NETWORK_ADDRESS; ++ ++/* The following is used with OID_GEN_NETWORK_LAYER_ADDRESSES to set network layer addresses on an interface */ ++ ++typedef struct _PARAM_NETWORK_ADDRESS_LIST { ++ UINT_32 u4AddressCount; /* number of addresses following */ ++ UINT_16 u2AddressType; /* type of this address (NDIS_PROTOCOL_ID_XXX above) */ ++ PARAM_NETWORK_ADDRESS arAddress[1]; /* actually AddressCount elements long */ ++} PARAM_NETWORK_ADDRESS_LIST, *P_PARAM_NETWORK_ADDRESS_LIST; ++ ++#if CFG_SLT_SUPPORT ++ ++#define FIXED_BW_LG20 0x0000 ++#define FIXED_BW_UL20 0x2000 ++#define FIXED_BW_DL40 0x3000 ++ ++#define FIXED_EXT_CHNL_U20 0x4000 /* For AGG register. */ ++#define FIXED_EXT_CHNL_L20 0xC000 /* For AGG regsiter. */ ++ ++typedef enum _ENUM_MTK_LP_TEST_MODE_T { ++ ENUM_MTK_LP_TEST_NORMAL, ++ ENUM_MTK_LP_TEST_GOLDEN_SAMPLE, ++ ENUM_MTK_LP_TEST_DUT, ++ ENUM_MTK_LP_TEST_MODE_NUM ++} ENUM_MTK_LP_TEST_MODE_T, *P_ENUM_MTK_LP_TEST_MODE_T; ++ ++typedef enum _ENUM_MTK_SLT_FUNC_IDX_T { ++ ENUM_MTK_SLT_FUNC_DO_NOTHING, ++ ENUM_MTK_SLT_FUNC_INITIAL, ++ ENUM_MTK_SLT_FUNC_RATE_SET, ++ ENUM_MTK_SLT_FUNC_LP_SET, ++ ENUM_MTK_SLT_FUNC_NUM ++} ENUM_MTK_SLT_FUNC_IDX_T, *P_ENUM_MTK_SLT_FUNC_IDX_T; ++ ++typedef struct _PARAM_MTK_SLT_LP_TEST_STRUCT_T { ++ ENUM_MTK_LP_TEST_MODE_T rLpTestMode; ++ UINT_32 u4BcnRcvNum; ++} PARAM_MTK_SLT_LP_TEST_STRUCT_T, *P_PARAM_MTK_SLT_LP_TEST_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_TR_TEST_STRUCT_T { ++ ENUM_PARAM_NETWORK_TYPE_T rNetworkType; /* Network Type OFDM5G or OFDM2.4G */ ++ UINT_32 u4FixedRate; /* Fixed Rate including BW */ ++} PARAM_MTK_SLT_TR_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TR_TEST_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_INITIAL_STRUCT_T { ++ UINT_8 aucTargetMacAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_16 u2SiteID; ++} PARAM_MTK_SLT_INITIAL_STRUCT_T, *P_PARAM_MTK_SLT_INITIAL_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_TEST_STRUCT_T { ++ ENUM_MTK_SLT_FUNC_IDX_T rSltFuncIdx; ++ UINT_32 u4Length; /* Length of structure, ++ including myself */ ++ UINT_32 u4FuncInfoLen; /* Include following content ++ field and myself */ ++ union { ++ PARAM_MTK_SLT_INITIAL_STRUCT_T rMtkInitTest; ++ PARAM_MTK_SLT_LP_TEST_STRUCT_T rMtkLpTest; ++ PARAM_MTK_SLT_TR_TEST_STRUCT_T rMtkTRTest; ++ } unFuncInfoContent; ++ ++} PARAM_MTK_SLT_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TEST_STRUCT_T; ++ ++#endif ++ ++/*--------------------------------------------------------------*/ ++/*! \brief For Fixed Rate Configuration (Registry) */ ++/*--------------------------------------------------------------*/ ++typedef enum _ENUM_REGISTRY_FIXED_RATE_T { ++ FIXED_RATE_NONE, ++ FIXED_RATE_1M, ++ FIXED_RATE_2M, ++ FIXED_RATE_5_5M, ++ FIXED_RATE_11M, ++ FIXED_RATE_6M, ++ FIXED_RATE_9M, ++ FIXED_RATE_12M, ++ FIXED_RATE_18M, ++ FIXED_RATE_24M, ++ FIXED_RATE_36M, ++ FIXED_RATE_48M, ++ FIXED_RATE_54M, ++ FIXED_RATE_MCS0_20M_800NS, ++ FIXED_RATE_MCS1_20M_800NS, ++ FIXED_RATE_MCS2_20M_800NS, ++ FIXED_RATE_MCS3_20M_800NS, ++ FIXED_RATE_MCS4_20M_800NS, ++ FIXED_RATE_MCS5_20M_800NS, ++ FIXED_RATE_MCS6_20M_800NS, ++ FIXED_RATE_MCS7_20M_800NS, ++ FIXED_RATE_MCS0_20M_400NS, ++ FIXED_RATE_MCS1_20M_400NS, ++ FIXED_RATE_MCS2_20M_400NS, ++ FIXED_RATE_MCS3_20M_400NS, ++ FIXED_RATE_MCS4_20M_400NS, ++ FIXED_RATE_MCS5_20M_400NS, ++ FIXED_RATE_MCS6_20M_400NS, ++ FIXED_RATE_MCS7_20M_400NS, ++ FIXED_RATE_MCS0_40M_800NS, ++ FIXED_RATE_MCS1_40M_800NS, ++ FIXED_RATE_MCS2_40M_800NS, ++ FIXED_RATE_MCS3_40M_800NS, ++ FIXED_RATE_MCS4_40M_800NS, ++ FIXED_RATE_MCS5_40M_800NS, ++ FIXED_RATE_MCS6_40M_800NS, ++ FIXED_RATE_MCS7_40M_800NS, ++ FIXED_RATE_MCS32_800NS, ++ FIXED_RATE_MCS0_40M_400NS, ++ FIXED_RATE_MCS1_40M_400NS, ++ FIXED_RATE_MCS2_40M_400NS, ++ FIXED_RATE_MCS3_40M_400NS, ++ FIXED_RATE_MCS4_40M_400NS, ++ FIXED_RATE_MCS5_40M_400NS, ++ FIXED_RATE_MCS6_40M_400NS, ++ FIXED_RATE_MCS7_40M_400NS, ++ FIXED_RATE_MCS32_400NS, ++ FIXED_RATE_NUM ++} ENUM_REGISTRY_FIXED_RATE_T, *P_ENUM_REGISTRY_FIXED_RATE_T; ++ ++typedef enum _ENUM_BT_CMD_T { ++ BT_CMD_PROFILE = 0, ++ BT_CMD_UPDATE, ++ BT_CMD_NUM ++} ENUM_BT_CMD_T; ++ ++typedef enum _ENUM_BT_PROFILE_T { ++ BT_PROFILE_CUSTOM = 0, ++ BT_PROFILE_SCO, ++ BT_PROFILE_ACL, ++ BT_PROFILE_MIXED, ++ BT_PROFILE_NO_CONNECTION, ++ BT_PROFILE_NUM ++} ENUM_BT_PROFILE_T; ++ ++typedef struct _PTA_PROFILE_T { ++ ENUM_BT_PROFILE_T eBtProfile; ++ union { ++ UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; ++ /* 0: sco reserved slot time, ++ 1: sco idle slot time, ++ 2: acl throughput, ++ 3: bt tx power, ++ 4: bt rssi ++ 5: VoIP interval ++ 6: BIT(0) Use this field, BIT(1) 0 apply single/ 1 dual PTA setting. ++ */ ++ UINT_32 au4Btcr[4]; ++ } u; ++} PTA_PROFILE_T, *P_PTA_PROFILE_T; ++ ++typedef struct _PTA_IPC_T { ++ UINT_8 ucCmd; ++ UINT_8 ucLen; ++ union { ++ PTA_PROFILE_T rProfile; ++ UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; ++ } u; ++} PARAM_PTA_IPC_T, *P_PARAM_PTA_IPC_T, PTA_IPC_T, *P_PTA_IPC_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief CFG80211 Scan Request Container */ ++/*--------------------------------------------------------------*/ ++ ++typedef struct _PARAM_SCAN_REQUEST_EXT_T { ++ PARAM_SSID_T rSsid; ++ UINT_32 u4IELength; ++ PUINT_8 pucIE; ++} PARAM_SCAN_REQUEST_EXT_T, *P_PARAM_SCAN_REQUEST_EXT_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief CFG80211 Scheduled Scan Request Container */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_SCHED_SCAN_REQUEST_T { ++ UINT_32 u4SsidNum; ++ PARAM_SSID_T arSsid[CFG_SCAN_SSID_MATCH_MAX_NUM]; ++ UINT_32 u4IELength; ++ PUINT_8 pucIE; ++ UINT_16 u2ScanInterval; /* in milliseconds */ ++} PARAM_SCHED_SCAN_REQUEST, *P_PARAM_SCHED_SCAN_REQUEST; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++typedef struct _PARAM_HS20_SET_BSSID_POOL { ++ BOOLEAN fgIsEnable; ++ UINT_8 ucNumBssidPool; ++ PARAM_MAC_ADDRESS arBSSID[8]; ++} PARAM_HS20_SET_BSSID_POOL, *P_PARAM_HS20_SET_BSSID_POOL; ++ ++#endif ++ ++typedef struct _PARAM_CUSTOM_WFD_DEBUG_STRUCT_T { ++ UINT_8 ucWFDDebugMode; /* 0: Disable ++ 1:Enable but only show inqueue skb ether SN ++ 2.show skb ether SN and the statistics of skb inqueue time */ ++ UINT_16 u2SNPeriod; /* The Ether SN Period */ ++ ++ UINT_8 reserved; ++} PARAM_CUSTOM_WFD_DEBUG_STRUCT_T, *P_PARAM_CUSTOM_WFD_DEBUG_STRUCT_T; ++ ++typedef struct _CMD_GET_PSCAN_CAPABILITY { ++/* TBD */ ++} CMD_GET_GSCAN_CAPABILITY, *P_CMD_GET_GSCAN_CAPABILITY; ++ ++typedef struct _CMD_SET_PSCAN_ENABLE { ++ UINT_8 ucPscanAct; ++ UINT_8 aucReserved[3]; ++} CMD_SET_PSCAN_ENABLE, *P_CMD_SET_PSCAN_ENABLE; ++ ++typedef enum _ENUM_PSCAN_ACT_T { ++ ENABLE, ++ DISABLE, ++ SUSPEND, ++ CLEAR ++} ENUM_PSCAN_ACT_T, *P_ENUM_PSCAN_ACT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*--------------------------------------------------------------*/ ++/* Routines to set parameters or query information. */ ++/*--------------------------------------------------------------*/ ++/***** Routines in wlan_oid.c *****/ ++WLAN_STATUS ++wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetConnect(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if 0 ++WLAN_STATUS ++wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID prSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRfTestRxStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRfTestTxStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++WLAN_STATUS ++wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#ifdef LINUX ++ ++WLAN_STATUS ++wlanoidQueryStatisticsForLinux(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#endif ++ ++WLAN_STATUS ++wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++WLAN_STATUS ++wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/* RF Test related APIs */ ++WLAN_STATUS ++wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_SUPPORT_WAPI ++WLAN_STATUS ++wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++WLAN_STATUS ++wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_ENABLE_WAKEUP_ON_LAN ++WLAN_STATUS ++wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 u4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); ++ ++#if CFG_SLT_SUPPORT ++ ++WLAN_STATUS ++wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#endif ++ ++#if 0 ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBT(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++WLAN_STATUS ++wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#endif ++ ++/* ++WLAN_STATUS ++wlanoidQueryBtSingleAntenna ( ++ IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, ++ IN UINT_32 u4QueryBufferLen, ++ OUT PUINT_32 pu4QueryInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidSetBtSingleAntenna ( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidSetPta ( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidQueryPta ( ++ IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, ++ IN UINT_32 u4QueryBufferLen, ++ OUT PUINT_32 pu4QueryInfoLen ++ ); ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++WLAN_STATUS ++wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_SUPPORT_BATCH_SCAN ++WLAN_STATUS ++wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++WLAN_STATUS ++wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxRateInfo( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS ++wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++WLAN_STATUS ++wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen); ++ ++#endif /* _WLAN_OID_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h +new file mode 100644 +index 000000000000..0b558d64034d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h +@@ -0,0 +1,307 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/wlan_p2p.h#3 ++*/ ++ ++/*! \file "wlan_p2p.h" ++ \brief This file contains the declairations of Wi-Fi Direct command ++ processing routines for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_p2p.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version ++ * query & set support for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * support wlanoidSetP2pPowerSaveProfile() in P2P ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * Support wlanoidSetNetworkAddress() for P2P ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. ++ * ++ ++ * ++** ++*/ ++ ++#ifndef _WLAN_P2P_H ++#define _WLAN_P2P_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* Service Discovery */ ++typedef struct _PARAM_P2P_SEND_SD_RESPONSE { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucChannelNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_SEND_SD_RESPONSE, *P_PARAM_P2P_SEND_SD_RESPONSE; ++ ++typedef struct _PARAM_P2P_GET_SD_REQUEST { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_REQUEST, *P_PARAM_P2P_GET_SD_REQUEST; ++ ++typedef struct _PARAM_P2P_GET_SD_REQUEST_EX { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 ucChannelNum; /* Channel Number Where SD Request is received. */ ++ UINT_8 ucSeqNum; /* Get SD Request by sequence number. */ ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_REQUEST_EX, *P_PARAM_P2P_GET_SD_REQUEST_EX; ++ ++typedef struct _PARAM_P2P_SEND_SD_REQUEST { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucVersionNum; /* Indicate the Service Discovery Supplicant Version. */ ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_SEND_SD_REQUEST, *P_PARAM_P2P_SEND_SD_REQUEST; ++ ++/* Service Discovery 1.0. */ ++typedef struct _PARAM_P2P_GET_SD_RESPONSE { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_RESPONSE, *P_PARAM_P2P_GET_SD_RESPONSE; ++ ++/* Service Discovery 2.0. */ ++typedef struct _PARAM_P2P_GET_SD_RESPONSE_EX { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 ucSeqNum; /* Get SD Response by sequence number. */ ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_RESPONSE_EX, *P_PARAM_P2P_GET_SD_RESPONSE_EX; ++ ++typedef struct _PARAM_P2P_TERMINATE_SD_PHASE { ++ PARAM_MAC_ADDRESS rPeerAddr; ++} PARAM_P2P_TERMINATE_SD_PHASE, *P_PARAM_P2P_TERMINATE_SD_PHASE; ++ ++/*! \brief Key mapping of BSSID */ ++typedef struct _P2P_PARAM_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++ PARAM_KEY_RSC rKeyRSC; ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} P2P_PARAM_KEY_T, *P_P2P_PARAM_KEY_T; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle command */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/*--------------------------------------------------------------*/ ++/* Service Discovery Subroutines */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 puQueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++WLAN_STATUS ++wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++WLAN_STATUS ++wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++/*--------------------------------------------------------------*/ ++/* Callbacks for event indication */ ++/*--------------------------------------------------------------*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif ++#endif /* _WLAN_P2P_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c +new file mode 100644 +index 000000000000..f2324f13280e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c +@@ -0,0 +1,1303 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/aaa_fsm.c#2 ++*/ ++ ++/*! \file "aaa_fsm.c" ++ \brief This file defines the FSM for AAA MODULE. ++ ++ This file defines the FSM for AAA MODULE. ++*/ ++ ++/* ++** Log: aaa_fsm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 22 2012 yuche.tsai ++ * NULL ++ * Solve sigma test 5.1.3 issue, assoc response should have P2P IE. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve inorder issue under AP mode. ++ * ++ * data frame may TX before assoc response frame. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 02 2011 eddie.chen ++ * [WCXRP00000759] [MT6620 Wi-Fi][DRV] Update RCPI in AAA ++ * Update RCPI when receiving Assoc request. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 09 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * Skip to call p2pRunEventAAAComplete to avoid indicate STA connect twice. ++ * ++ * 03 04 2011 terry.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * Remove unused variable. ++ * ++ * 02 16 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Add more check after RX assoc frame under Hot-Spot mode. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * [On behalf of Frog] Add CFG_ENABLE_WIFI_DIRECT to p2pRunEventAAAComplete ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify AAA flow according to CM's comment. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Fix Compile warning, type cast from UINT_32 to UINT_16. ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * In P2P AT GO test mode under WinXP, we would not indicate connected event to host. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix bug while enabling P2P GO. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * modify due to P2P functino call prototype change. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 04 02 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify CFG flags ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * add support of Driver STA_RECORD_T activation ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Event to AIS/BOW/P2P ++* ++* @param[in] rJoinStatus To indicate JOIN success or failure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prSwRfb Pointer to the SW_RFB_T ++ ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS aaaFsmSendEventJoinComplete(WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb) ++{ ++ P_MSG_SAA_JOIN_COMP_T prJoinCompMsg; ++ ++ ASSERT(prStaRec); ++ ++ prJoinCompMsg = cnmMemAlloc(RAM_TYPE_TCM, sizeof(MSG_SAA_JOIN_COMP_T)); ++ if (!prJoinCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ if (IS_STA_IN_AIS(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; ++ else if (IS_STA_IN_P2P(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; ++ else if (IS_STA_IN_BOW(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; ++ else ++ ASSERT(0); ++ ++ prJoinCompMsg->rJoinStatus = rJoinStatus; ++ prJoinCompMsg->prStaRec = prStaRec; ++ prJoinCompMsg->prSwRfb = prSwRfb; ++ ++ mboxSendMsg(MBOX_ID_0, (P_MSG_HDR_T) prJoinCompMsg, MSG_SEND_METHOD_BUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of saaFsmSendEventJoinComplete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Start Event to AAA FSM. ++* ++* @param[in] prMsgHdr Message of Join Request for a particular STA. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventStart(IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_JOIN_REQ_T prJoinReqMsg; ++ P_STA_RECORD_T prStaRec; ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prMsgHdr); ++ ++ prJoinReqMsg = (P_MSG_SAA_JOIN_REQ_T) prMsgHdr; ++ prStaRec = prJoinReqMsg->prStaRec; ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM\n"); ++ ++ cnmMemFree(prMsgHdr); ++ ++ /* 4 <1> Validation of SAA Start Event */ ++ if (!IS_AP_STA(prStaRec->eStaType)) { ++ ++ DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); ++ ++ /* Ignore the return value because don't care the prSwRfb */ ++ saaFsmSendEventJoinComplete(WLAN_STATUS_FAILURE, prStaRec, NULL); ++ ++ return; ++ } ++ /* 4 <2> The previous JOIN process is not completed ? */ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ } ++ /* 4 <3> Reset Status Code and Time */ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); ++ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ cnmTimerStopTimer(&prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ prStaRec->ucStaState = STA_STATE_1; ++ ++ /* Trigger SAA MODULE */ ++ saaFsmSteps(prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventStart() */ ++#endif ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Auth Request Frame and then ++* trigger AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ UINT_16 u2StatusCode; ++ BOOLEAN fgReplyAuth = FALSE; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ ++ /* 4 <1> Check P2P network conditions */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prBssInfo->fgIsNetActive) { ++ ++ /* 4 <1.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ if (WLAN_STATUS_SUCCESS == ++ authProcessRxAuth1Frame(prAdapter, ++ prSwRfb, ++ prBssInfo->aucBSSID, ++ AUTH_ALGORITHM_NUM_OPEN_SYSTEM, ++ AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ /* 4 <1.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAuth = p2pFuncValidateAuth(prAdapter, ++ prSwRfb, &prStaRec, &u2StatusCode); ++ } else { ++ fgReplyAuth = TRUE; ++ } ++ eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* 4 <2> Check BOW network conditions */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { ++ ++ /* 4 <2.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ authProcessRxAuth1Frame(prAdapter, ++ prSwRfb, ++ prBssInfo->aucBSSID, ++ AUTH_ALGORITHM_NUM_OPEN_SYSTEM, ++ AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ ++ /* 4 <2.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAuth = ++ bowValidateAuth(prAdapter, prSwRfb, &prStaRec, &u2StatusCode); ++ ++ } else { ++ ++ fgReplyAuth = TRUE; ++ } ++ eNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ return; ++ } while (FALSE); ++ ++ if (prStaRec) { ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ } ++ /* 4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame */ ++ if (fgReplyAuth) { ++ ++ if (prStaRec) { ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(AAA, WARN, "Previous AuthAssocState (%d) != IDLE.\n", ++ prStaRec->eAuthAssocState); ++ } ++ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ } else { ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_1 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else { ++ /* NOTE(Kevin): We should have STA_RECORD_T if the status code was successful */ ++ ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL)); ++ } ++ ++ /* NOTE: Ignore the return status for AAA */ ++ /* 4 <4> Reply Auth */ ++ authSendAuthFrame(prAdapter, prStaRec, eNetTypeIndex, prSwRfb, AUTH_TRANSACTION_SEQ_2, u2StatusCode); ++ ++ } ++ ++} /* end of aaaFsmRunEventRxAuth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx (Re)Association Request Frame and then ++* trigger AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ UINT_16 u2StatusCode = STATUS_CODE_RESERVED; ++ BOOLEAN fgReplyAssocResp = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ ++ /* 4 <1> Check if we have the STA_RECORD_T for incoming Assoc Req */ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) { ++ ASSERT(0); /* Only for debug phase */ ++ break; ++ } ++ ++ if (!IS_CLIENT_STA(prStaRec)) ++ break; ++ ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ /* Do Reassocation */ ++ } else if ((prStaRec->ucStaState == STA_STATE_2) && ++ (prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2)) { ++ /* Normal case */ ++ } else { ++ DBGLOG(AAA, INFO, "Previous AuthAssocState (%d) != SEND_AUTH2, ucStaState:%d.\n", ++ prStaRec->eAuthAssocState, ++ prStaRec->ucStaState); ++ /* TODO: Why assoc req event is faster than tx done of auth */ ++ if (prStaRec->eAuthAssocState != AAA_STATE_SEND_AUTH2) ++ break; ++ } ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ /* 4 <2> Check P2P network conditions */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prBssInfo->fgIsNetActive) { ++ ++ /* 4 <2.1> Validate Assoc Req Frame and get Status Code */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ /* 4 <2.2> Validate Assoc Req Frame for Network Specific Conditions */ ++ fgReplyAssocResp = p2pFuncValidateAssocReq(prAdapter, ++ prSwRfb, ++ (PUINT_16)&u2StatusCode); ++ } else { ++ fgReplyAssocResp = TRUE; ++ } ++ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* 4 <3> Check BOW network conditions */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { ++ ++ /* 4 <3.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ ++ /* 4 <3.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAssocResp = ++ bowValidateAssocReq(prAdapter, prSwRfb, &u2StatusCode); ++ ++ } else { ++ ++ fgReplyAssocResp = TRUE; ++ } ++ ++ /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ return WLAN_STATUS_SUCCESS; /* To release the SW_RFB_T */ ++ } while (FALSE); ++ ++ /* 4 <4> Update STA_RECORD_T and reply Assoc Resp Frame */ ++ if (fgReplyAssocResp) { ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ if ((((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->u2FrameCtrl & MASK_FRAME_TYPE) == ++ MAC_FRAME_REASSOC_REQ) { ++ ++ u2IELength = prSwRfb->u2PacketLen - ++ (UINT_16) OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); ++ ++ pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } else { ++ u2IELength = prSwRfb->u2PacketLen - (UINT_16) OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); ++ ++ pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } ++ ++ rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.1> Assign Association ID */ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ if (p2pRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ /* prStaRec->eAuthAssocState = AA_STATE_IDLE; */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2;/* NOTE(Kevin): for TX done */ ++ ++ /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ ++ /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ } else { ++ /* Client List FULL. */ ++ u2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if ((IS_STA_IN_BOW(prStaRec))) { ++ /* if (bowRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { */ ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; /* NOTE(Kevin): for TX done */ ++ ++ /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ ++ /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ } ++#if 0 ++ else { ++ /* Client List FULL. */ ++ u2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ } ++#endif ++#endif ++ } else { ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ /* NOTE: Ignore the return status for AAA */ ++ /* 4 <4.2> Reply Assoc Resp */ ++ assocSendReAssocRespFrame(prAdapter, prStaRec); ++ ++} ++ ++return WLAN_STATUS_SUCCESS; ++ ++} /* end of aaaFsmRunEventRxAssoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ DBGLOG(AAA, LOUD, "EVENT-TX DONE: Current Time = %lu\n", (unsigned long)kalGetTimeTick()); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) { ++ DBGLOG(AAA, INFO, "EVENT-TX DONE: Invalid StaRec"); ++ return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ ++ } ++ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ DBGLOG(AAA, INFO, "TX DONE status: %d, AuthAssocState: %d, SeqNo: %d\n", ++ rTxDoneStatus, prStaRec->eAuthAssocState, ++ prMsduInfo->ucTxSeqNum); ++ ++ switch (prStaRec->eAuthAssocState) { ++ case AAA_STATE_SEND_AUTH2: ++ { ++ /* Strictly check the outgoing frame is matched with current AA STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_2) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { ++ if (TX_RESULT_SUCCESS == rTxDoneStatus) { ++ ++ /* NOTE(Kevin): Change to STATE_2 at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } else { ++ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_1 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ } ++ ++ } ++ /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ ++ ++ } ++ break; ++ ++ case AAA_STATE_SEND_ASSOC2: ++ { ++ /* Strictly check the outgoing frame is matched with current SAA STATE */ ++ if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { ++ if (TX_RESULT_SUCCESS == rTxDoneStatus) { ++ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_3 at TX Done */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAASuccess(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAAComplete(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ } else { ++ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Change to STATE_2 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ } ++ } ++ /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of aaaFsmRunEventTxDone() */ ++#endif /* CFG_SUPPORT_AAA */ ++ ++#if 0 /* TODO(Kevin): for abort event, just reset the STA_RECORD_T. */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send ABORT Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventAbort(IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventAbort"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: ABORT\n"); ++ ++ /* NOTE(Kevin): when reach here, the ARB_STATE should be in ARB_STATE_JOIN. */ ++ ASSERT(prJoinInfo->prBssDesc); ++ ++ /* 4 <1> Update Flags and Elements of JOIN Module. */ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel all JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rJoinTimer); ++ ++ /* 4 <2> Update the associated STA_RECORD_T during JOIN. */ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ if (prStaRec) ++ prStaRec->ucStaState = STA_STATE_1; /* Update Station Record - Class 1 Flag */ ++#if DBG ++ else ++ ASSERT(0); /* Shouldn't happened, because we already add this STA_RECORD_T at JOIN_STATE_INIT */ ++#endif /* DBG */ ++ ++ /* 4 <3> Pull back to IDLE. */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ /* 4 <4> If we are in Roaming, recover the settings of previous BSS. */ ++ /* NOTE: JOIN FAIL - ++ * Restore original setting from current BSS_INFO_T. ++ */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++} /* end of joinFsmRunEventAbort() */ ++#endif ++ ++/* TODO(Kevin): following code will be modified and move to AIS FSM */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send Join Timeout Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventJoinTimeOut"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); ++ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ ++ /* We have renew this Sta Record when in JOIN_STATE_INIT */ ++ ASSERT(prStaRec); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel other JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ /* Restore original setting from current BSS_INFO_T */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++ /* Pull back to IDLE */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ return WLAN_STATUS_FAILURE; ++ ++} /* end of joinFsmRunEventJoinTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from Peer BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ DEBUGFUNC("joinAdoptParametersFromPeerBss"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ ++ /* 4 <1> Adopt Peer BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssDesc->ePhyType; ++ ++ DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", ++ prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); ++ ++ /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); ++ ++ prJoinInfo->fgIsParameterAdopted = TRUE; ++ ++} /* end of joinAdoptParametersFromPeerBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from current associated BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) ++{ ++ /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ prBssInfo = &prAdapter->rBssInfo; ++ ++ /* 4 <1> Adopt current BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssInfo->ePhyType; ++ ++ /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); ++ ++} /* end of joinAdoptParametersFromCurrentBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will update all the SW variables and HW MCR registers after ++* the association with target BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinComplete(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ P_PEER_BSS_INFO_T prPeerBssInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_802_11D ++ P_IE_COUNTRY_T prIECountry; ++#endif ++ ++ DEBUGFUNC("joinComplete"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ prPeerBssInfo = &prAdapter->rPeerBssInfo; ++ prBssInfo = &prAdapter->rBssInfo; ++ prConnSettings = &prAdapter->rConnSettings; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ ++ /* Remove previous AP's Connection Flags if have */ ++ scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); ++ ++ prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ ++ ++ if (prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't ++ * broadcast SSID on its Beacon Frame. ++ */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); ++ ++ if (prBssDesc->ucSSIDLen) ++ prBssDesc->fgIsHiddenSSID = FALSE; ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++ DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); ++ } ++/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ ++ /* 4 <2.A> PHY Type */ ++ prBssInfo->ePhyType = prBssDesc->ePhyType; ++ ++ /* 4 <2.B> BSS Type */ ++ prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ /* 4 <2.C> BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); ++ ++ /* 4 <2.D> SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ /* 4 <2.E> Channel / Band information. */ ++ prBssInfo->eBand = prBssDesc->eBand; ++ prBssInfo->ucChnl = prBssDesc->ucChannelNum; ++ ++ /* 4 <2.F> RSN/WPA information. */ ++ secFsmRunEventStart(prAdapter); ++ prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; ++ prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ if (secRsnKeyHandshakeEnabled()) ++ prBssInfo->fgIsWPAorWPA2Enabled = TRUE; ++ else ++ prBssInfo->fgIsWPAorWPA2Enabled = FALSE; ++ ++ /* 4 <2.G> Beacon interval. */ ++ prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ ++ /* 4 <2.H> DTIM period. */ ++ prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* 4 <2.I> ERP Information */ ++ if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ ++ (prBssDesc->fgIsERPPresent)) { ++ ++ prBssInfo->fgIsERPPresent = TRUE; ++ prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ ++ } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ ++ prBssInfo->fgIsERPPresent = FALSE; ++ prBssInfo->ucERP = 0; ++ } ++ ++#if CFG_SUPPORT_802_11D ++ /* 4 <2.J> Country inforamtion of the associated AP */ ++ if (prConnSettings->fgMultiDomainCapabilityEnabled) { ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ ++ if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { ++ if (prBssDesc->prIECountry) { ++ prIECountry = prBssDesc->prIECountry; ++ ++ domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); ++ ++ /* use the domain get from the BSS info */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); ++ } else { ++ /* use the domain get from the scan result */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); ++ } ++ } ++ } ++#endif ++ ++ /* 4 <2.K> Signal Power of the associated AP */ ++ prBssInfo->rRcpi = prBssDesc->rRcpi; ++ prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); ++ GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); ++ ++ /* 4 <2.L> Capability Field of the associated AP */ ++ prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", ++ prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); ++ ++/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ ++ /* 4 <3.A> Association ID */ ++ prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; ++ ++ /* 4 <3.B> WMM Information */ ++ if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { ++ ++ prBssInfo->fgIsWmmAssoc = TRUE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC3; ++ ++ qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); ++ ++ if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { ++ kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } else { ++ kalMemCopy(&prBssInfo->rWmmInfo, ++ &prPeerBssInfo->rWmmInfo, ++ sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); ++ } ++ } else { ++ prBssInfo->fgIsWmmAssoc = FALSE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC1; ++ ++ kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } ++ ++ /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ ++ prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; ++ prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; ++ ++ /* 4 <3.D> Short Preamble */ ++ if (prBssInfo->fgIsERPPresent) { ++ ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE FALSE(shouldn't have such case, ++ * use the AssocResp) ++ * TRUE FALSE TRUE FALSE ++ * FALSE FALSE FALSE FALSE(shouldn't have such case, ++ * use the AssocResp) ++ * FALSE FALSE TRUE FALSE ++ * TRUE TRUE FALSE TRUE(follow ERP) ++ * TRUE TRUE TRUE FALSE(follow ERP) ++ * FALSE TRUE FALSE FALSE(shouldn't have such case, ++ * and we should set to FALSE) ++ * FALSE TRUE TRUE FALSE(we should set to FALSE) ++ */ ++ if ((prPeerBssInfo->fgIsShortPreambleAllowed) && ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ ++ if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ else ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ } else { ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE ++ * FALSE FALSE FALSE ++ * TRUE TRUE TRUE ++ * FALSE TRUE(status success) TRUE ++ * --> Honor the result of prPeerBssInfo. ++ */ ++ ++ prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = ++ prPeerBssInfo->fgIsShortPreambleAllowed; ++ } ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); ++ ++ /* 4 <3.E> Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); ++ ++ nicSetSlotTime(prAdapter, ++ prBssInfo->ePhyType, ++ ((prConnSettings->fgIsShortSlotTimeOptionEnable && ++ prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); ++ ++ /* 4 <3.F> Update Tx Rate for Control Frame */ ++ bssUpdateTxRateForControlFrame(prAdapter); ++ ++ /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ ++ /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ ++ { ++ ++ if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; ++ else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; ++ ++ prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; ++ ++ /* Set the stable time of the associated BSS. We won't do roaming decision ++ * during the stable time. ++ */ ++ SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, ++ SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); ++ } ++ ++ /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ ++#if CFG_TX_FRAGMENT ++ txFragInfoUpdate(prAdapter); ++#endif /* CFG_TX_FRAGMENT */ ++ ++/* 4 <4> Update STA_RECORD_T */ ++ /* Get a Station Record if possible */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); ++ ++ if (prStaRec) { ++ UINT_16 u2OperationalRateSet, u2DesiredRateSet; ++ ++ /* 4 <4.A> Desired Rate Set */ ++ u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & ++ prBssInfo->u2OperationalRateSet); ++ ++ u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); ++ if (u2DesiredRateSet) { ++ prStaRec->u2DesiredRateSet = u2DesiredRateSet; ++ } else { ++ /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ ++ prStaRec->u2DesiredRateSet = u2OperationalRateSet; ++ } ++ ++ /* Try to set the best initial rate for this entry */ ++ if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, ++ prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { ++ ++ if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) ++ ASSERT(0); ++ } ++ ++ DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); ++ ++ /* 4 <4.B> Preamble Mode */ ++ prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; ++ ++ /* 4 <4.C> QoS Flag */ ++ prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; ++ } ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++/* 4 <5> Update NIC */ ++ /* 4 <5.A> Update BSSID & Operation Mode */ ++ nicSetupBSS(prAdapter, prBssInfo); ++ ++ /* 4 <5.B> Update WLAN Table. */ ++ if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) ++ ASSERT(FALSE); ++ /* 4 <5.C> Update Desired Rate Set for BT. */ ++#if CFG_TX_FRAGMENT ++ if (prConnSettings->fgIsEnableTxAutoFragmentForBT) ++ txRateSetInitForBT(prAdapter, prStaRec); ++#endif /* CFG_TX_FRAGMENT */ ++ ++ /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ ++ if (prBssInfo->fgIsWmmAssoc) { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, FALSE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); ++ } else { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, TRUE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); ++ ++ nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); ++ } ++ ++#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN ++ { ++ prTxCtrl->fgBlockTxDuringJoin = FALSE; ++ ++#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ ++ nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxRetransmitOfSendWaitQue(prAdapter); ++ ++ if (prTxCtrl->fgIsPacketInOsSendQueue) ++ nicTxRetransmitOfOsSendQue(prAdapter); ++#if CFG_SDIO_TX_ENHANCE ++ halTxLeftClusteredMpdu(prAdapter); ++#endif /* CFG_SDIO_TX_ENHANCE */ ++ ++ } ++#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ ++ ++/* 4 <6> Setup CONNECTION flag. */ ++ prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; ++ prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; ++ ++ if (prJoinInfo->fgIsReAssoc) ++ prAdapter->fgBypassPortCtrlForRoaming = TRUE; ++ else ++ prAdapter->fgBypassPortCtrlForRoaming = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); ++ ++} /* end of joinComplete() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c +new file mode 100644 +index 000000000000..7b5a49a5ba63 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c +@@ -0,0 +1,5039 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/ais_fsm.c#1 ++*/ ++ ++/*! \file "aa_fsm.c" ++ \brief This file defines the FSM for SAA and AAA MODULE. ++ ++ This file defines the FSM for SAA and AAA MODULE. ++*/ ++ ++/* ++** Log: ais_fsm.c ++** ++** 09 06 2013 cp.wu ++** always paste SSID information to SAA-FSM ++** ++** 09 06 2013 cp.wu ++** add error handling when reassociation request failed to locate bss descriptor ++** ++** 09 05 2013 cp.wu ++** isolate logic regarding roaming & reassociation ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with ++ * corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration ++ * corresponding to network type. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous ++ * to asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state ++ * without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED ++ * cases as an explicit trigger for Android framework ++ * correct reference to BSSID field in Association-Response frame. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED ++ * cases as an explicit trigger for Android framework ++ * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. ++ * 2. (Android only) when reassociation-and-non-roaming cases happened, indicate an extra DISCONNECT ++ * indication to Android Wi-Fi framework ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 10 26 2011 tsaiyuan.hsu ++ * [WCXRP00001064] [MT6620 Wi-Fi][DRV]] add code with roaming awareness when disconnecting AIS network ++ * be aware roaming when disconnecting AIS network. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * STA_REC shall be NULL for Beacon's MSDU ++ * ++ * 10 13 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS ++ * 1. short join failure count limit to 2 ++ * 2. treat join timeout as kind of join failure as well ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 20 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * change window registry of driver for roaming. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Handle client mode about preamble type and slot time ++ * ++ * 09 08 2011 tsaiyuan.hsu ++ * [WCXRP00000972] [MT6620 Wi-Fi][DRV]] check if roaming occurs after join failure to avoid state incosistence. ++ * check if roaming occurs after join failure to avoid deactivation of network. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 16 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * EnableRoaming in registry is deprecated. ++ * ++ * 08 16 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * use registry to enable or disable roaming. ++ * ++ * 07 07 2011 cp.wu ++ * [WCXRP00000840] [MT6620 Wi-Fi][Driver][AIS] Stop timer for joining when channel is released ++ * due to join failure count exceeding limit ++ * stop timer when joining operation is failed due to try count exceeds limitation ++ * ++ * 06 28 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work ++ * around some tricky AP which use space character as hidden SSID ++ * do not handle SCAN request immediately after connected to increase the probability of receiving 1st beacon frame. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * ensure DEAUTH is always sent before establish a new connection ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * typo fix: a right brace is missed. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * When RECONNECT request is identified as disconnected, it is necessary to check for pending scan request. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels ++ * mark fgIsTransition as TRUE for state rolling. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * always check for pending scan after switched into NORMAL_TR state. ++ * ++ * 06 14 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * always treat connection request at higher priority over scanning request ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state ++ * when DEAUTH frame is dropped due to bss disconnection ++ * change SCAN handling behavior when followed by a CONNECT/DISCONNECT requests by pending instead of dropping. ++ * ++ * 05 17 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state ++ * when DEAUTH frame is dropped due to bss disconnection ++ * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 13 2011 george.huang ++ * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF ++ * remove assert ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000575] [MT6620 Wi-Fi][Driver][AIS] reduce memory usage when generating mailbox message for scan request ++ * when there is no IE needed for probe request, then request a smaller memory for mailbox message ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 03 11 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel ++ * ++ * 03 09 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * avoid clearing fgIsScanReqIssued so as to add scan results. ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 04 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * reset retry conter of attemp to connect to ap after completion of join. ++ * ++ * 03 04 2011 cp.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * surpress compile warning occurred when compiled by GNU compiler collection. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right ++ * after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 02 23 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to ++ * improve response time for scanning request ++ * when handling reconnect request, set fgTryScan as TRUE ++ * ++ * 02 22 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach ++ * to improve response time for scanning request ++ * handle SCAN and RECONNECT with a FIFO approach. ++ * ++ * 02 09 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * Check if prRegInfo is null or not before initializing roaming parameters. ++ * ++ * 02 01 2011 cp.wu ++ * [WCXRP00000416] [MT6620 Wi-Fi][Driver] treat "unable to find BSS" as connection trial ++ * to prevent infinite reconnection trials ++ * treat "unable to find BSS" as connection trial to prevent infinite reconnection trials. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 14 2011 cp.wu ++ * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent ++ * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. ++ * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. ++ * ++ * 01 11 2011 cp.wu ++ * [WCXRP00000307] [MT6620 Wi-Fi][SQA]WHQL test .2c_wlan_adhoc case fail. ++ * [IBSS] when merged in, the bss state should be updated to firmware to pass WHQL adhoc failed item ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer ++ * when the corresponding BSS is disconnected due to beacon timeout ++ * remove from scanning result when the BSS is disconnected due to beacon timeout. ++ * ++ * 01 03 2011 cp.wu ++ * [WCXRP00000337] [MT6620 Wi-FI][Driver] AIS-FSM not to invoke cnmStaRecResetStatus ++ * directly 'cause it frees all belonging STA-RECs ++ * do not invoke cnmStaRecResetStatus() directly, nicUpdateBss will do the things after bss is disconnected ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * do not need to manipulate prStaRec after indicating BSS disconnection to firmware, ++ * 'cause all STA-RECs belongs to BSS has been freed already ++ * ++ * 12 27 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * add DEBUGFUNC() macro invoking for more detailed debugging information ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 17 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update SLT Function for QoS Support and not be affected by fixed rate function. ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with ++ * Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate ++ * from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000097] [MT6620 Wi-Fi] [Driver] Fixed the P2P not setting the fgIsChannelExt value make scan not abort ++ * initial the fgIsChannelExt value. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. ++ * correct erroneous logic: specifying eBand with incompatible eSco ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000049] [MT6620 Wi-Fi][Driver] Adhoc cannot be created successfully. ++ * keep IBSS-ALONE state retrying until further instruction is received ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 09 2010 yuche.tsai ++ * NULL ++ * Fix NULL IE Beacon issue. Sync Beacon Content to FW before enable beacon. ++ * Both in IBSS Create & IBSS Merge ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * frequency is in unit of KHz thus no need to divide 1000 once more. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add option for enabling AIS 5GHz scan ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, ++ * RLM/CNM will handle the channel switching when BSS information is updated ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * check-in missed files. ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 09 2010 cp.wu ++ * NULL ++ * reset fgIsScanReqIssued when abort request is received right after join completion. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * allocate on MGMT packet for IBSS beaconing. ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * [AIS-FSM] fix: when join failed, release channel privilege as well ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * reuse join-abort sub-procedure to reduce code size. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, ++ * just pend it til 5-sec. period finishes ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 26 2010 cp.wu ++ * ++ * re-commit code logic being overwriten. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) enable Ad-Hoc ++ * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * indicate scan done for linux wireless extension ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 21 2010 cp.wu ++ * ++ * separate AIS-FSM states into different cases of channel request. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one ++ * 2) refine disconnection behaviour when issued during BG-SCAN process ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) bugfix: do not stop timer for join after switched into normal_tr state, ++ * for providing chance for DHCP handshasking ++ * 2) modify rsnPerformPolicySelection() invoking ++ * ++ * 07 19 2010 cp.wu ++ * ++ * 1) init AIS_BSS_INFO as channel number = 1 with band = 2.4GHz ++ * 2) correct typo ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * for AIS scanning, driver specifies no extra IE for probe request ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * Remove CFG_MQM_MIGRATION ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Refine AIS-FSM by divided into more states ++ * ++ * 07 13 2010 cm.chang ++ * ++ * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * for first connection, if connecting failed do not enter into scan state. ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * once STA-REC is allocated and updated, invoke cnmStaRecChangeState() to sync. with firmware. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * remove unused definitions. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * RSN/PRIVACY compilation flag awareness correction ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change to enqueue TX frame infinitely. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 01 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add conditionial compiling flag to choose default available bandwidth ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile error if CFG_CMD_EVENT_VER_009 == 0 for prEventConnStatus->ucNetworkType. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 17 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Call pmAbort() and add ucNetworkType field in EVENT_CONNECTION_STATUS ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile warning - define of MQM_WMM_PARSING was removed ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed the use of compiling flag MQM_WMM_PARSING ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * ++ * Fix typo ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the protected bit at cap info for ad-hoc. ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add new HW CH macro support ++ * ++ * 04 07 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Add TX Power Control RCPI function. ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * move the wlan table alloc / free to change state function. ++ * ++ * 03 25 2010 wh.su ++ * [BORA00000676][MT6620] Support the frequency setting and query at build connection / connection event ++ * modify the build connection and status event structure bu CMD_EVENT doc 0.09 draft, default is disable. ++ * ++ * 03 24 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * fixed some WHQL testing error. ++ * ++ * 03 24 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Set / Unset POWER STATE in AIS Network ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 03 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add PHY_CONFIG to change Phy Type ++ * ++ * 03 03 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Use bcmWiFiNotify to replace wifi_send_msg to pass information to BCM module. ++ * ++ * 03 03 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Remove wmt_task definition and add PTA function. ++ * ++ * 03 02 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Init TXM and MQM testing procedures in aisFsmRunEventJoinComplete() ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Modified aisUpdateBssInfo() to call TXM's functions for setting WTBL TX parameters ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * clear the pmkid cache while indicate media disconnect. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * . ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Enabled MQM parsing WMM IEs for non-AP mode ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * use the Rx0 dor event indicate. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Support dynamic channel selection ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000621][MT6620 Wi-Fi] Add the RSSI indicate to avoid XP stalled for query rssi value ++ * Adding the RSSI event support, ++ * using the HAL function to get the rcpi value and tranlsate to RSSI and indicate to driver ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Set max AMDPU size supported by the peer to 64 KB, ++ * removed mqmInit() and mqmTxSendAddBaReq() function calls in aisUpdateBssInfo() ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 20 2010 kevin.huang ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags ++ * ++ * 01 15 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Configured the AMPDU factor to 3 for the APu1rwduu`wvpghlqg|q`mpdkb+ilp ++ * ++ * 01 14 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Add WiFi BCM module for the 1st time. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Refine JOIN Complete and separate the function of Media State indication ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the sample code to update the wlan table rate, ++ * ++ * Dec 10 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Different function prototype of wifi_send_msg() ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call rlm related function to process HT info when join complete ++ * ++ * Dec 9 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * default the acquired wlan table entry code off ++ * ++ * Dec 9 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to acquired the wlan table entry, and a sample code to update the BA bit at table ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix the problem of prSwRfb overwrited by event packet in aisFsmRunEventJoinComplete() ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to integrate the security related code ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove redundant declaration ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add code for JOIN init and JOIN complete ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename u4RSSI to i4RSSI ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise ENUM_MEDIA_STATE to ENUM_PARAM_MEDIA_STATE ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add fgIsScanReqIssued to CONNECTION_SETTINGS_T ++ * ++ * Nov 26 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise Virtual CMD handler due to structure changed ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Virtual CMD & RESP for testing CMD PATH ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmInitializeConnectionSettings() ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_MGMT_FSM flag for aisFsmTest() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define AIS_ROAMING_CONNECTION_TRIAL_LIMIT 2 ++#define AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME 80 ++ ++#define CTIA_MAGIC_SSID "ctia_test_only_*#*#3646633#*#*" ++#define CTIA_MAGIC_SSID_LEN 30 ++ ++#define AIS_JOIN_TIMEOUT 7 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugAisState[AIS_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("AIS_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_SEARCH"), ++ (PUINT_8) DISP_STRING("AIS_STATE_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_ONLINE_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_LOOKING_FOR"), ++ (PUINT_8) DISP_STRING("AIS_STATE_WAIT_FOR_NEXT_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REQ_CHANNEL_JOIN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_JOIN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_IBSS_ALONE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_IBSS_MERGE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_NORMAL_TR"), ++ (PUINT_8) DISP_STRING("AIS_STATE_DISCONNECTING"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REQ_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REMAIN_ON_CHANNEL") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to initialize the value of the connection settings for ++* AIS network ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucAnyBSSID[] = BC_BSSID; ++ UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ int i = 0; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* Setup default values for operation */ ++ COPY_MAC_ADDR(prConnSettings->aucMacAddress, aucZeroMacAddr); ++ ++ if (prRegInfo) ++ prConnSettings->ucDelayTimeOfDisconnectEvent = ++ (!prAdapter->fgIsHw5GBandDisabled && prRegInfo->ucSupport5GBand) ? ++ AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND : AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; ++ else ++ prConnSettings->ucDelayTimeOfDisconnectEvent = AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; ++ ++ COPY_MAC_ADDR(prConnSettings->aucBSSID, aucAnyBSSID); ++ prConnSettings->fgIsConnByBssidIssued = FALSE; ++ ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ prConnSettings->fgIsDisconnectedByNonRequest = FALSE; ++ ++ prConnSettings->ucSSIDLen = 0; ++ ++ prConnSettings->eOPMode = NET_TYPE_INFRA; ++ ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ ++ if (prRegInfo) { ++ prConnSettings->ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4StartFreq); ++ prConnSettings->eAdHocBand = prRegInfo->u4StartFreq < 5000000 ? BAND_2G4 : BAND_5G; ++ prConnSettings->eAdHocMode = (ENUM_PARAM_AD_HOC_MODE_T) (prRegInfo->u4AdhocMode); ++ } ++ ++ prConnSettings->eAuthMode = AUTH_MODE_OPEN; ++ ++ prConnSettings->eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* MIB attributes */ ++ prConnSettings->u2BeaconPeriod = DOT11_BEACON_PERIOD_DEFAULT; ++ ++ prConnSettings->u2RTSThreshold = DOT11_RTS_THRESHOLD_DEFAULT; ++ ++ prConnSettings->u2DesiredNonHTRateSet = RATE_SET_ALL_ABG; ++ ++ /* prConnSettings->u4FreqInKHz; */ /* Center frequency */ ++ ++ /* Set U-APSD AC */ ++ prConnSettings->bmfgApsdEnAc = PM_UAPSD_NONE; ++ ++ secInit(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* Features */ ++ prConnSettings->fgIsEnableRoaming = FALSE; ++#if CFG_SUPPORT_ROAMING ++ if (prRegInfo) ++ prConnSettings->fgIsEnableRoaming = ((prRegInfo->fgDisRoaming > 0) ? (FALSE) : (TRUE)); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ prConnSettings->fgIsAdHocQoSEnable = FALSE; ++ ++ prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGN; ++ ++ /* Set default bandwidth modes */ ++ prConnSettings->uc2G4BandwidthMode = CONFIG_BW_20M; ++ prConnSettings->uc5GBandwidthMode = CONFIG_BW_20_40M; ++ ++ prConnSettings->rRsnInfo.ucElemId = 0x30; ++ prConnSettings->rRsnInfo.u2Version = 0x0001; ++ prConnSettings->rRsnInfo.u4GroupKeyCipherSuite = 0; ++ prConnSettings->rRsnInfo.u4PairwiseKeyCipherSuiteCount = 0; ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prConnSettings->rRsnInfo.au4PairwiseKeyCipherSuite[i] = 0; ++ prConnSettings->rRsnInfo.u4AuthKeyMgtSuiteCount = 0; ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) ++ prConnSettings->rRsnInfo.au4AuthKeyMgtSuite[i] = 0; ++ prConnSettings->rRsnInfo.u2RsnCap = 0; ++ prConnSettings->rRsnInfo.fgRsnCapPresent = FALSE; ++ ++} /* end of aisFsmInitializeConnectionSettings() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to initialize the value in AIS_FSM_INFO_T for ++* AIS FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ucScanTimeoutTimes = 0; ++VOID aisFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ ++ DEBUGFUNC("aisFsmInit()"); ++ DBGLOG(SW1, TRACE, "->aisFsmInit()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ /* 4 <1> Initiate FSM */ ++ prAisFsmInfo->ePreviousState = AIS_STATE_IDLE; ++ prAisFsmInfo->eCurrentState = AIS_STATE_IDLE; ++ ++ prAisFsmInfo->ucAvailableAuthTypes = 0; ++ ++ prAisFsmInfo->prTargetBssDesc = (P_BSS_DESC_T) NULL; ++ ++ prAisFsmInfo->ucSeqNumOfReqMsg = 0; ++ prAisFsmInfo->ucSeqNumOfChReq = 0; ++ prAisFsmInfo->ucSeqNumOfScanReq = 0; ++ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++#if CFG_SUPPORT_ROAMING ++ prAisFsmInfo->fgIsRoamingScanPending = FALSE; ++#endif /* CFG_SUPPORT_ROAMING */ ++ prAisFsmInfo->fgIsChannelRequested = FALSE; ++ prAisFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 4 <1.1> Initiate FSM - Timer INIT */ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rBGScanTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventBGSleepTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rIbssAloneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventIbssAloneTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rIndicationOfDisconnectTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisPostponedEventOfDisconnTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rJoinTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventJoinTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rScanDoneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventScanDoneTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rChannelTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventChannelTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rDeauthDoneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventDeauthTimeout, (ULONG) NULL); ++ ++ /* 4 <1.2> Initiate PWR STATE */ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ COPY_MAC_ADDR(prAisBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); ++ ++ /* 4 <3> Initiate BSS_INFO_T - private part */ ++ /* TODO */ ++ prAisBssInfo->eBand = BAND_2G4; ++ prAisBssInfo->ucPrimaryChannel = 1; ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ ++ /* 4 <4> Allocate MSDU_INFO_T for Beacon */ ++ prAisBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prAisBssInfo->prBeacon) { ++ prAisBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prAisBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ ++ } else { ++ ASSERT(0); ++ } ++ ++#if 0 ++ prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++#else ++ if (prAdapter->u4UapsdAcBmp == 0) { ++ prAdapter->u4UapsdAcBmp = CFG_INIT_UAPSD_AC_BMP; ++ /* ASSERT(prAdapter->u4UapsdAcBmp); */ ++ } ++ prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; ++#endif ++ ++ /* request list initialization */ ++ LINK_INITIALIZE(&prAisFsmInfo->rPendingReqList); ++ ++ /* DBGPRINTF("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucUapsdSp); */ ++ ++ /*reset ucScanTimeoutTimes value*/ ++ ucScanTimeoutTimes = 0; ++ ++} /* end of aisFsmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to uninitialize the value in AIS_FSM_INFO_T for ++* AIS FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ ++ DEBUGFUNC("aisFsmUninit()"); ++ DBGLOG(SW1, INFO, "->aisFsmUninit()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ /* 4 <1> Stop all timers */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); /* Add by Enlai */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ /* 4 <2> flush pending request */ ++ aisFsmFlushRequest(prAdapter); ++ ++ /* 4 <3> Reset driver-domain BSS-INFO */ ++ if (prAisBssInfo->prBeacon) { ++ cnmMgtPktFree(prAdapter, prAisBssInfo->prBeacon); ++ prAisBssInfo->prBeacon = NULL; ++ } ++#if CFG_SUPPORT_802_11W ++ rsnStopSaQuery(prAdapter); ++#endif ++ ++} /* end of aisFsmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialization of JOIN STATE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ DEBUGFUNC("aisFsmStateInit_JOIN()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> We are going to connect to this BSS. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_LEGACY_AP, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ if (prStaRec == NULL) { ++ DBGLOG(AIS, WARN, "Create station record fail\n"); ++ return; ++ } ++ ++ prAisFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <2.1> sync. to firmware domain */ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ switch (prConnSettings->eAuthMode) { ++ case AUTH_MODE_OPEN: /* Note: Omit break here. */ ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ break; ++ ++ case AUTH_MODE_SHARED: ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(AIS, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | AUTH_TYPE_SHARED_KEY); ++ break; ++ ++ default: ++ ASSERT(!(prConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); ++ DBGLOG(AIS, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", ++ prConnSettings->eAuthMode); ++ /* TODO(Kevin): error handling ? */ ++ return; ++ } ++ ++ /* TODO(tyhsu): Assume that Roaming Auth Type is equal to ConnSettings eAuthMode */ ++ prAisSpecificBssInfo->ucRoamingAuthTypes = prAisFsmInfo->ucAvailableAuthTypes; ++ ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ ++ } else { ++ ASSERT(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE); ++ ASSERT(!prBssDesc->fgIsConnected); ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: AUTH TYPE = %d for Roaming\n", ++ prAisSpecificBssInfo->ucRoamingAuthTypes); ++ ++ prStaRec->fgIsReAssoc = TRUE; /* We do roaming while the medium is connected */ ++ ++ /* TODO(Kevin): We may call a sub function to acquire the Roaming Auth Type */ ++ prAisFsmInfo->ucAvailableAuthTypes = prAisSpecificBssInfo->ucRoamingAuthTypes; ++ ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING; ++ } ++ ++ /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ ++ if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ ++ if (prBssDesc->ucSSIDLen) ++ COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ if (1) { ++ int j; ++ P_FRAG_INFO_T prFragInfo; ++ ++ for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { ++ prFragInfo = &prStaRec->rFragInfo[j]; ++ ++ if (prFragInfo->pr1stFrag) { ++ /* nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); */ ++ prFragInfo->pr1stFrag = (P_SW_RFB_T) NULL; ++ } ++ } ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++} /* end of aisFsmInit_JOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval TRUE We will retry JOIN ++* @retval FALSE We will not retry JOIN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ DEBUGFUNC("aisFsmStateInit_RetryJOIN()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* Retry other AuthType if possible */ ++ if (!prAisFsmInfo->ucAvailableAuthTypes) ++ return FALSE; ++ ++ if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(AIS, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else { ++ DBGLOG(AIS, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); ++ ASSERT(0); ++ } ++ ++ prAisFsmInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ ++ ++ /* Trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return FALSE; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ return TRUE; ++ ++} /* end of aisFsmRetryJOIN() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief State Initialization of AIS_STATE_IBSS_ALONE ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Check if IBSS was created before ? */ ++ if (prAisBssInfo->fgIsBeaconActivated) { ++ ++ /* 4 <2> Start IBSS Alone Timer for periodic SCAN and then SEARCH */ ++#if !CFG_SLT_SUPPORT ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); ++#endif ++ } ++ ++ aisFsmCreateIBSS(prAdapter); ++ ++} /* end of aisFsmStateInit_IBSS_ALONE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief State Initialization of AIS_STATE_IBSS_MERGE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the IBSS we will try to merge with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ ASSERT(prBssDesc); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> We will merge with to this BSS immediately. */ ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ if (prStaRec == NULL) { ++ DBGLOG(AIS, WARN, "Create station record fail\n"); ++ return; ++ } ++ ++ prStaRec->fgIsMerging = TRUE; ++ ++ prAisFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <2.1> sync. to firmware domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* 4 <3> IBSS-Merge */ ++ aisFsmMergeIBSS(prAdapter, prStaRec); ++ ++} /* end of aisFsmStateInit_IBSS_MERGE() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of JOIN Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_JOIN_ABORT_T prJoinAbortMsg; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* 1. Abort JOIN process */ ++ prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); ++ if (!prJoinAbortMsg) { ++ ++ ASSERT(0); /* Can't abort SAA FSM */ ++ return; ++ } ++ ++ prJoinAbortMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_ABORT; ++ prJoinAbortMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinAbortMsg->prStaRec = prAisFsmInfo->prTargetStaRec; ++ ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ /* 2. Return channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 3.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 3.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++} /* end of aisFsmAbortJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of SCAN Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* Abort JOIN process. */ ++ prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ ++ ASSERT(0); /* Can't abort SCN FSM */ ++ return; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfScanReq; ++ prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ prScanCancelMsg->fgIsChannelExt = FALSE; ++#endif ++ ++ /* unbuffered message to guarantee scan is cancelled in sequence */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_UNBUF); ++ ++} /* end of aisFsmAbortSCAN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of NORMAL_TR Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ DBGLOG(AIS, TRACE, "aisFsmStateAbort_NORMAL_TR\n"); ++ ++ /* TODO(Kevin): Do abort other MGMT func */ ++ ++ /* 1. Release channel to CNM */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 2.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++} /* end of aisFsmAbortNORMAL_TR() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of NORMAL_TR Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* reset BSS-DESC */ ++ if (prAisFsmInfo->prTargetStaRec) { ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); ++ ++ if (prBssDesc) { ++ prBssDesc->fgIsConnected = FALSE; ++ prBssDesc->fgIsConnecting = FALSE; ++ } ++ } ++ /* release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++} ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of AIS(Ad-hoc, Infra STA) ++* ++* @param[in] eNextState Enum value of next AIS STATE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc; ++ P_MSG_CH_REQ_T prMsgChReq; ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ P_AIS_REQ_HDR_T prAisReq; ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannel; ++ UINT_16 u2ScanIELen; ++ ENUM_AIS_STATE_T eOriPreState; ++ ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("aisFsmSteps()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ eOriPreState = prAisFsmInfo->ePreviousState; ++ ++ do { ++ ++ /* Do entering Next State */ ++ prAisFsmInfo->ePreviousState = prAisFsmInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(AIS, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugAisState[prAisFsmInfo->eCurrentState], apucDebugAisState[eNextState]); ++#else ++ DBGLOG(AIS, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_AIS_IDX, prAisFsmInfo->eCurrentState, eNextState); ++#endif ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ prAisFsmInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ /* Do tasks of the State that we just entered */ ++ switch (prAisFsmInfo->eCurrentState) { ++ /* NOTE(Kevin): we don't have to rearrange the sequence of following ++ * switch case. Instead I would like to use a common lookup table of array ++ * of function pointer to speed up state search. ++ */ ++ case AIS_STATE_IDLE: ++ ++ prAisReq = aisFsmGetNextRequest(prAdapter); ++ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ ++ if (prAisReq == NULL || prAisReq->eReqType == AIS_REQUEST_RECONNECT) { ++ if (prConnSettings->fgIsConnReqIssued == TRUE && ++ prConnSettings->fgIsDisconnectedByNonRequest == FALSE) { ++ ++ prAisFsmInfo->fgTryScan = TRUE; ++ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* reset trial count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ eNextState = AIS_STATE_SEARCH; ++ fgIsTransition = TRUE; ++ } else { ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* check for other pending request */ ++ if (prAisReq && ++ (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE)) { ++ ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_SCAN; ++ ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ if (prAisReq) { ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } ++ } else if (prAisReq->eReqType == AIS_REQUEST_SCAN) { ++#if CFG_SUPPORT_ROAMING ++ prAisFsmInfo->fgIsRoamingScanPending = FALSE; ++#endif /* CFG_SUPPORT_ROAMING */ ++ wlanClearScanningResult(prAdapter); ++ ++ eNextState = AIS_STATE_SCAN; ++ fgIsTransition = TRUE; ++ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } else if (prAisReq->eReqType == AIS_REQUEST_ROAMING_CONNECT ++ || prAisReq->eReqType == AIS_REQUEST_ROAMING_SEARCH) { ++ /* ignore */ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } else if (prAisReq->eReqType == AIS_REQUEST_REMAIN_ON_CHANNEL) { ++ eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; ++ fgIsTransition = TRUE; ++ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } ++ ++ prAisFsmInfo->u4SleepInterval = AIS_BG_SCAN_INTERVAL_MIN_SEC; ++ ++ break; ++ ++ case AIS_STATE_SEARCH: ++ /* 4 <1> Search for a matched candidate and save it to prTargetBssDesc. */ ++#if CFG_SLT_SUPPORT ++ prBssDesc = prAdapter->rWifiVar.rSltInfo.prPseudoBssDesc; ++#else ++ prBssDesc = scanSearchBssDescByPolicy(prAdapter, NETWORK_TYPE_AIS_INDEX); ++#endif ++ /* every time BSS join failure count is integral multiples of SCN_BSS_JOIN_FAIL_THRESOLD, ++ we need to scan again to find if a new BSS is here in the ESS, ++ this can also avoid too frequency to retry the rejected AP */ ++ if (prAisFsmInfo->ePreviousState == AIS_STATE_LOOKING_FOR || ++ ((eOriPreState == AIS_STATE_ONLINE_SCAN || ++ eOriPreState == AIS_STATE_SCAN) && prAisFsmInfo->ePreviousState != eOriPreState)) { ++ /* if previous state is scan/online scan/looking for, don't try to scan again */ ++ } else if (prBssDesc && prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD && ++ ((prBssDesc->ucJoinFailureCount - SCN_BSS_JOIN_FAIL_THRESOLD) % ++ SCN_BSS_JOIN_FAIL_THRESOLD) == 0) ++ prBssDesc = NULL; ++ ++ /* we are under Roaming Condition. */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ if (prAisFsmInfo->ucConnTrialCount > AIS_ROAMING_CONNECTION_TRIAL_LIMIT) { ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_CONNLIMIT); ++#endif /* CFG_SUPPORT_ROAMING */ ++ /* reset retry count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ /* abort connection trial */ ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ ++ eNextState = AIS_STATE_NORMAL_TR; ++ fgIsTransition = TRUE; ++ ++ break; ++ } ++ } ++ /* 4 <2> We are not under Roaming Condition. */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ /* 4 <2.a> If we have the matched one */ ++ if (prBssDesc) { ++ ++ /* 4 Stored the Selected BSS security cipher. ++ For later asoc req compose IE */ ++ prAisBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prAisBssInfo->u4RsnSelectedPairwiseCipher = ++ prBssDesc->u4RsnSelectedPairwiseCipher; ++ prAisBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ /* 4 Do STATE transition and update current Operation Mode. */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* Transit to channel acquire */ ++ eNextState = AIS_STATE_REQ_CHANNEL_JOIN; ++ fgIsTransition = TRUE; ++ ++ /* increase connection trial count */ ++ prAisFsmInfo->ucConnTrialCount++; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } ++ /* 4 <2.b> If we don't have the matched one */ ++ else { ++ ++ /* increase connection trial count for infrastructure connection */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) ++ prAisFsmInfo->ucConnTrialCount++; ++ /* 4 Try to SCAN */ ++ if (prAisFsmInfo->fgTryScan) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ fgIsTransition = TRUE; ++ break; ++ } ++ /* 4 We've do SCAN already, now wait in some STATE. */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) { ++ ++ /* issue reconnect request, ++ * and retreat to idle state for scheduling */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) ++ || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) ++ || (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ prAisFsmInfo->prTargetBssDesc = NULL; ++ ++ eNextState = AIS_STATE_IBSS_ALONE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } ++ } ++ /* 4 <3> We are under Roaming Condition. */ ++ else { /* prAdapter->eConnectionState == MEDIA_STATE_CONNECTED. */ ++ ++ /* 4 <3.a> This BSS_DESC_T is our AP. */ ++ /* NOTE(Kevin 2008/05/16): Following cases will go back to NORMAL_TR. ++ * CASE I: During Roaming, APP(WZC/NDISTEST) change the connection ++ * settings. That make we can NOT match the original AP, so the ++ * prBssDesc is NULL. ++ * CASE II: The same reason as CASE I. Because APP change the ++ * eOPMode to other network type in connection setting ++ * (e.g. NET_TYPE_IBSS), so the BssDesc become the IBSS node. ++ * (For CASE I/II, before WZC/NDISTEST set the OID_SSID, it will change ++ * other parameters in connection setting first. So if we do roaming ++ * at the same time, it will hit these cases.) ++ * ++ * CASE III: Normal case, we can't find other candidate to roam ++ * out, so only the current AP will be matched. ++ * ++ * CASE IV: Timestamp of the current AP might be reset ++ */ ++ if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION && ++ ((!prBssDesc) || /* CASE I */ ++ (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) || /* CASE II */ ++ (prBssDesc->fgIsConnected) || /* CASE III */ ++ (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID))) /* CASE IV */) { ++#if DBG ++ if ((prBssDesc) && (prBssDesc->fgIsConnected)) ++ ASSERT(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); ++#endif /* DBG */ ++ /* We already associated with it, go back to NORMAL_TR */ ++ /* TODO(Kevin): Roaming Fail */ ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* Retreat to NORMAL_TR state */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ fgIsTransition = TRUE; ++ break; ++ } ++ ++ /* 4 <3.b> Try to roam out for JOIN this BSS_DESC_T. */ ++ if (prBssDesc == NULL) { ++ /* increase connection trial count for infrastructure connection */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) ++ prAisFsmInfo->ucConnTrialCount++; ++ /* 4 Try to SCAN */ ++ if (prAisFsmInfo->fgTryScan) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ fgIsTransition = TRUE; ++ break; ++ } ++ ++ /* 4 We've do SCAN already, now wait in some STATE. */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) { ++ ++ /* issue reconnect request, and retreat to idle state ++ * for scheduling */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) ++ || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) ++ || (prConnSettings->eOPMode == ++ NET_TYPE_DEDICATED_IBSS)) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ prAisFsmInfo->prTargetBssDesc = NULL; ++ ++ eNextState = AIS_STATE_IBSS_ALONE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } else { ++#if DBG ++ if (prAisBssInfo->ucReasonOfDisconnect != ++ DISCONNECT_REASON_CODE_REASSOCIATION) { ++ ASSERT(UNEQUAL_MAC_ADDR ++ (prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); ++ } ++#endif /* DBG */ ++ ++ /* 4 Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* tyhsu: increase connection trial count */ ++ prAisFsmInfo->ucConnTrialCount++; ++ ++ /* Transit to channel acquire */ ++ eNextState = AIS_STATE_REQ_CHANNEL_JOIN; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ break; ++ ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ ++ DBGLOG(AIS, LOUD, "SCAN: Idle Begin - Current Time = %u\n", kalGetTimeTick()); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rBGScanTimer, SEC_TO_MSEC(prAisFsmInfo->u4SleepInterval)); ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prAisFsmInfo->u4SleepInterval < AIS_BG_SCAN_INTERVAL_MAX_SEC) ++ prAisFsmInfo->u4SleepInterval <<= 1; ++ break; ++ ++ case AIS_STATE_SCAN: ++ case AIS_STATE_ONLINE_SCAN: ++ case AIS_STATE_LOOKING_FOR: ++ ++ if (!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) { ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ ++ /* IE length decision */ ++ if (prAisFsmInfo->u4ScanIELength > 0) { ++ u2ScanIELen = (UINT_16) prAisFsmInfo->u4ScanIELength; ++ } else { ++#if CFG_SUPPORT_WPS2 ++ u2ScanIELen = prAdapter->prGlueInfo->u2WSCIELen; ++#else ++ u2ScanIELen = 0; ++#endif ++ } ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ OFFSET_OF(MSG_SCN_SCAN_REQ, ++ aucIE) + u2ScanIELen); ++ if (!prScanReqMsg) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfScanReq; ++ prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; ++#else ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++#endif ++ ++#if CFG_SUPPORT_ROAMING_ENC ++ if (prAdapter->fgIsRoamingEncEnabled == TRUE) { ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR && ++ prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ prScanReqMsg->u2ChannelDwellTime = AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME; ++ } ++ } ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_SCAN ++ || prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { ++ if (prAisFsmInfo->ucScanSSIDLen == 0) { ++ /* Scan for all available SSID */ ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; ++ } else { ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ COPY_SSID(prScanReqMsg->aucSSID, ++ prScanReqMsg->ucSSIDLength, ++ prAisFsmInfo->aucScanSSID, prAisFsmInfo->ucScanSSIDLen); ++ } ++ } else { ++ /* Scan for determined SSID */ ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ COPY_SSID(prScanReqMsg->aucSSID, ++ prScanReqMsg->ucSSIDLength, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ } ++ ++ /* check if tethering is running and need to fix on specific channel */ ++ if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ prScanReqMsg->ucChannelListNum = 1; ++ prScanReqMsg->arChnlInfoList[0].eBand = eBand; ++ prScanReqMsg->arChnlInfoList[0].ucChannelNum = ucChannel; ++ } else { ++#if 0 ++ aisFsmSetChannelInfo(prAdapter, prScanReqMsg, prAisFsmInfo->eCurrentState); ++#endif ++ if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_NULL) { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ else ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_2G4) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_5G) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ } else { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ ASSERT(0); ++ } ++ ++ } ++ ++ if (prAisFsmInfo->u4ScanIELength > 0) { ++ kalMemCopy(prScanReqMsg->aucIE, prAisFsmInfo->aucScanIEBuf, ++ prAisFsmInfo->u4ScanIELength); ++ } else { ++#if CFG_SUPPORT_WPS2 ++ if (prAdapter->prGlueInfo->u2WSCIELen > 0) { ++ kalMemCopy(prScanReqMsg->aucIE, &prAdapter->prGlueInfo->aucWSCIE, ++ prAdapter->prGlueInfo->u2WSCIELen); ++ } ++ } ++#endif ++ ++ prScanReqMsg->u2IELen = u2ScanIELen; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ DBGLOG(AIS, TRACE, "SendSR%d\n", prScanReqMsg->ucSeqNum); ++ prAisFsmInfo->fgTryScan = FALSE; /* Will enable background sleep for infrastructure */ ++ ++ prAdapter->ucScanTime++; ++ break; ++ ++ case AIS_STATE_REQ_CHANNEL_JOIN: ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ prMsgChReq->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ ++ if (prAisFsmInfo->prTargetBssDesc != NULL) { ++ prMsgChReq->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; ++ prMsgChReq->eRfSco = prAisFsmInfo->prTargetBssDesc->eSco; ++ prMsgChReq->eRfBand = prAisFsmInfo->prTargetBssDesc->eBand; ++ COPY_MAC_ADDR(prMsgChReq->aucBSSID, prAisFsmInfo->prTargetBssDesc->aucBSSID); ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prAisFsmInfo->fgIsChannelRequested = TRUE; ++ break; ++ ++ case AIS_STATE_JOIN: ++ aisFsmStateInit_JOIN(prAdapter, prAisFsmInfo->prTargetBssDesc); ++ break; ++ ++#if CFG_SUPPORT_ADHOC ++ case AIS_STATE_IBSS_ALONE: ++ aisFsmStateInit_IBSS_ALONE(prAdapter); ++ break; ++ ++ case AIS_STATE_IBSS_MERGE: ++ aisFsmStateInit_IBSS_MERGE(prAdapter, prAisFsmInfo->prTargetBssDesc); ++ break; ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ case AIS_STATE_NORMAL_TR: ++ if (prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { ++ /* Don't do anything when rJoinTimeoutTimer is still ticking */ ++ } else { ++ /* 1. Process for pending scan */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_ONLINE_SCAN; ++ fgIsTransition = TRUE; ++ } ++ /* 2. Process for pending roaming scan */ ++ else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE) == TRUE) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ fgIsTransition = TRUE; ++ } ++ /* 3. Process for pending roaming scan */ ++ else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE) == TRUE) { ++ eNextState = AIS_STATE_SEARCH; ++ fgIsTransition = TRUE; ++ } else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE) == ++ TRUE) { ++ eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ break; ++ ++ case AIS_STATE_DISCONNECTING: ++ /* send for deauth frame for disconnection */ ++ authSendDeauthFrame(prAdapter, ++ prAisBssInfo->prStaRecOfAP, ++ (P_SW_RFB_T) NULL, REASON_CODE_DEAUTH_LEAVING_BSS, aisDeauthXmitComplete); ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer, 100); ++ break; ++ ++ case AIS_STATE_REQ_REMAIN_ON_CHANNEL: ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ /* zero-ize */ ++ kalMemZero(prMsgChReq, sizeof(MSG_CH_REQ_T)); ++ ++ /* filling */ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ prMsgChReq->u4MaxInterval = prAisFsmInfo->rChReqInfo.u4DurationMs; ++ prMsgChReq->ucPrimaryChannel = prAisFsmInfo->rChReqInfo.ucChannelNum; ++ prMsgChReq->eRfSco = prAisFsmInfo->rChReqInfo.eSco; ++ prMsgChReq->eRfBand = prAisFsmInfo->rChReqInfo.eBand; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prAisFsmInfo->fgIsChannelRequested = TRUE; ++ ++ break; ++ ++ case AIS_STATE_REMAIN_ON_CHANNEL: ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ break; ++ ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ break; ++ ++ } ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of aisFsmSteps() */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState) ++{ ++ /*get scan channel infro from prAdapter->prGlueInfo->prScanRequest*/ ++ struct cfg80211_scan_request *scan_req_t = NULL; ++ struct ieee80211_channel *channel_tmp = NULL; ++ int i = 0; ++ int j = 0; ++ UINT_8 channel_num = 0; ++ UINT_8 channel_counts = 0; ++ ++ if ((prAdapter == NULL) || (ScanReqMsg == NULL)) ++ return; ++ if ((CurrentState == AIS_STATE_SCAN) || (CurrentState == AIS_STATE_ONLINE_SCAN)) { ++ if (prAdapter->prGlueInfo->prScanRequest != NULL) { ++ scan_req_t = prAdapter->prGlueInfo->prScanRequest; ++ if ((scan_req_t != NULL) && (scan_req_t->n_channels != 0) && ++ (scan_req_t->channels != NULL)) { ++ channel_counts = scan_req_t->n_channels; ++ DBGLOG(AIS, TRACE, "channel_counts=%d\n", channel_counts); ++ ++ while (j < channel_counts) { ++ channel_tmp = scan_req_t->channels[j]; ++ if (channel_tmp == NULL) ++ break; ++ ++ DBGLOG(AIS, TRACE, "set channel band=%d\n", channel_tmp->band); ++ if (channel_tmp->band >= IEEE80211_BAND_60GHZ) { ++ j++; ++ continue; ++ } ++ if (i >= MAXIMUM_OPERATION_CHANNEL_LIST) ++ break; ++ if (channel_tmp->band == IEEE80211_BAND_2GHZ) ++ ScanReqMsg->arChnlInfoList[i].eBand = BAND_2G4; ++ else if (channel_tmp->band == IEEE80211_BAND_5GHZ) ++ ScanReqMsg->arChnlInfoList[i].eBand = BAND_5G; ++ ++ DBGLOG(AIS, TRACE, "set channel channel_rer =%d\n", ++ channel_tmp->center_freq); ++ ++ channel_num = (UINT_8)nicFreq2ChannelNum( ++ channel_tmp->center_freq * 1000); ++ ++ DBGLOG(AIS, TRACE, "set channel channel_num=%d\n", ++ channel_num); ++ ScanReqMsg->arChnlInfoList[i].ucChannelNum = channel_num; ++ ++ j++; ++ i++; ++ } ++ } ++ } ++ } ++ ++ DBGLOG(AIS, INFO, "set channel i=%d\n", i); ++ if (i > 0) { ++ ScanReqMsg->ucChannelListNum = i; ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ ++ return; ++ } ++ ++ if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_NULL) { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ else ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_2G4) { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_5G) { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ } else { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ ASSERT(0); ++ } ++ ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ UINT_8 ucSeqNumOfCompMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventScanDone()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ ucScanTimeoutTimes = 0; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ ASSERT(prScanDoneMsg->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ if (ucSeqNumOfCompMsg != prAisFsmInfo->ucSeqNumOfScanReq) { ++ DBGLOG(AIS, WARN, "SEQ NO of AIS SCN DONE MSG is not matched %d %d.\n", ++ ucSeqNumOfCompMsg, prAisFsmInfo->ucSeqNumOfScanReq); ++ } else { ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_SCAN: ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++ ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++ eNextState = AIS_STATE_IDLE; ++#if CFG_SUPPORT_AGPS_ASSIST ++ scanReportScanResultToAgps(prAdapter); ++#endif ++ break; ++ ++ case AIS_STATE_ONLINE_SCAN: ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++ ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_NORMAL_TR; ++#endif /* CFG_SUPPORT_ROAMING */ ++#if CFG_SUPPORT_AGPS_ASSIST ++ scanReportScanResultToAgps(prAdapter); ++#endif ++ break; ++ ++ case AIS_STATE_LOOKING_FOR: ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ scanReportBss2Cfg80211(prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_SEARCH; ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ ++ default: ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ break; ++ ++ } ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventScanDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ UINT_8 ucReasonOfDisconnect; ++ BOOLEAN fgDelayIndication; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventAbort()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Extract information of Abort Message and then free memory. */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) prMsgHdr; ++ ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; ++ fgDelayIndication = prAisAbortMsg->fgDelayIndication; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if DBG ++ DBGLOG(AIS, STATE, "EVENT-ABORT: Current State %s %d\n", ++ apucDebugAisState[prAisFsmInfo->eCurrentState], ucReasonOfDisconnect); ++#else ++ DBGLOG(AIS, STATE, "[%d] EVENT-ABORT: Current State [%d %d]\n", ++ DBG_AIS_IDX, prAisFsmInfo->eCurrentState, ucReasonOfDisconnect); ++#endif ++ ++ GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); ++ ++ /* 4 <2> clear previous pending connection request and insert new one */ ++ if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DEAUTHENTICATED ++ || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DISASSOCIATED) { ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++ } else { ++ prConnSettings->fgIsDisconnectedByNonRequest = FALSE; ++ } ++ /* to support user space triggered roaming */ ++ if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_ROAMING && ++ prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && ++ prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { ++ aisFsmSteps(prAdapter, AIS_STATE_SEARCH); ++ } else { ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_ROAMING_CONNECT); ++ } ++ return; ++ } ++ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ if (prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { ++ /* 4 <3> invoke abort handler */ ++ aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, fgDelayIndication); ++ } ++ ++} /* end of aisFsmRunEventAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handles AIS-FSM abort event/command ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ucReasonOfDisconnect Reason for disonnection ++* fgDelayIndication Option to delay disconnection indication ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ BOOLEAN fgIsCheckConnected; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ fgIsCheckConnected = FALSE; ++ ++ /* 4 <1> Save information of Abort Message and then free memory. */ ++ prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; ++ ++ /* 4 <2> Abort current job. */ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IDLE: ++ case AIS_STATE_SEARCH: ++ break; ++ ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ /* Do cancel timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_SCAN: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* queue for later handling */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ ++ break; ++ ++ case AIS_STATE_LOOKING_FOR: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_REQ_CHANNEL_JOIN: ++ /* Release channel to CNM */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_JOIN: ++ /* Do abort JOIN */ ++ aisFsmStateAbort_JOIN(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++#if CFG_SUPPORT_ADHOC ++ case AIS_STATE_IBSS_ALONE: ++ case AIS_STATE_IBSS_MERGE: ++ aisFsmStateAbort_IBSS(prAdapter); ++ break; ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ case AIS_STATE_ONLINE_SCAN: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* queue for later handling */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_DISCONNECTING: ++ /* Do abort NORMAL_TR */ ++ aisFsmStateAbort_NORMAL_TR(prAdapter); ++ ++ break; ++ ++ case AIS_STATE_REQ_REMAIN_ON_CHANNEL: ++ /* release channel */ ++ aisFsmReleaseCh(prAdapter); ++ break; ++ ++ case AIS_STATE_REMAIN_ON_CHANNEL: ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2. stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (fgIsCheckConnected && (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState)) { ++ ++ /* switch into DISCONNECTING state for sending DEAUTH if necessary */ ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && ++ prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_NEW_CONNECTION && ++ prAisBssInfo->prStaRecOfAP && prAisBssInfo->prStaRecOfAP->fgIsInUse) { ++ aisFsmSteps(prAdapter, AIS_STATE_DISCONNECTING); ++ ++ return; ++ } ++ /* Do abort NORMAL_TR */ ++ aisFsmStateAbort_NORMAL_TR(prAdapter); ++ ++ } ++ ++ aisFsmDisconnect(prAdapter, fgDelayIndication); ++ ++ ++} /* end of aisFsmStateAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Join Complete Event from SAA FSM for AIS FSM ++* ++* @param[in] prMsgHdr Message of Join Complete of SAA FSM. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_JOIN_COMP_T prJoinCompMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prAssocRspSwRfb; ++ P_BSS_INFO_T prAisBssInfo; ++ UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; ++ OS_SYSTIME rCurrentTime; ++ ++ DEBUGFUNC("aisFsmRunEventJoinComplete()"); ++ ++ ASSERT(prMsgHdr); ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prStaRec = prJoinCompMsg->prStaRec; ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ DBGLOG(AIS, TRACE, "AISOK\n"); ++ ++ /* Check State and SEQ NUM */ ++ do { ++ if (prAisFsmInfo->eCurrentState != AIS_STATE_JOIN) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prAisFsmInfo->ucSeqNumOfReqMsg) { ++ ++ /* 4 <1> JOIN was successful */ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ ++ /* 1. Reset retry count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ /* Completion of roaming */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ ++#if CFG_SUPPORT_ROAMING ++ /* 2. Deactivate previous BSS */ ++ aisFsmRoamingDisconnectPrevAP(prAdapter, prStaRec); ++ ++ /* 3. Update bss based on roaming staRec */ ++ aisUpdateBssInfoForRoamingAP(prAdapter, prStaRec, prAssocRspSwRfb); ++#endif /* CFG_SUPPORT_ROAMING */ ++ } else { ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prAisBssInfo->prStaRecOfAP) && ++ (prAisBssInfo->prStaRecOfAP != prStaRec) && ++ (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { ++ ++ cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, ++ STA_STATE_1); ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /* 4 <1.5> Update RSSI if necessary */ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_AIS_INDEX, ++ (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. */ ++ /* from AIS_BSS_INFO_T */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, ++ FALSE); ++ ++ /* add for ctia mode */ ++ if (EQUAL_SSID ++ (aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen)) { ++ nicEnterCtiaMode(prAdapter, TRUE, FALSE); ++ } ++ } ++ ++#if CFG_SUPPORT_ROAMING ++ /* if bssid is given, it means we no need fw roaming */ ++ if (prAdapter->rWifiVar.rConnSettings.eConnectionPolicy != CONNECT_BY_BSSID) ++ roamingFsmRunEventStart(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* 4 <1.7> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ } ++ /* 4 <2> JOIN was not successful */ ++ else { ++ /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ ++ if (aisFsmStateInit_RetryJOIN(prAdapter, prStaRec) == FALSE) { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* 1. Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* 2. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 3.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 3.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prStaRec->aucMacAddr); ++ ++ if (prBssDesc == NULL) { ++ /* it maybe NULL when wlanRemove */ ++ /* ++ (1) UI does wifi off during SAA does auth/assoc procedure. ++ (2) We will do LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ in nicUninitMGMT(). ++ (3) We will handle prMsduInfo->pfTxDoneHandler ++ in nicTxRelease(). ++ (4) prMsduInfo->pfTxDoneHandler will point to ++ saaFsmRunEventTxDone(). ++ (5) Then jump to saaFsmSteps() -> saaFsmSendEventJoinComplete() ++ (6) Finally mboxSendMsg() -> aisFsmRunEventJoinComplete(). ++ (7) In aisFsmRunEventJoinComplete(), we will check ++ "prBssDesc = scanSearchBssDescByBssid(prAdapter, ++ prStaRec->aucMacAddr);" ++ (8) And prBssDesc will be NULL and hangs in ++ "ASSERT(prBssDesc->fgIsConnecting);" when DBG=0. ++ ASSERT(prBssDesc); ++ ASSERT(prBssDesc->fgIsConnecting); ++ */ ++ break; ++ } ++ /* ASSERT(prBssDesc); */ ++ /* ASSERT(prBssDesc->fgIsConnecting); */ ++ prBssDesc->ucJoinFailureCount++; ++ if (prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { ++ GET_CURRENT_SYSTIME(&prBssDesc->rJoinFailTime); ++ DBGLOG(AIS, INFO, ++ "Bss %pM join fail %d times,temp disable it at time:%u\n", ++ prBssDesc->aucBSSID, ++ SCN_BSS_JOIN_FAIL_THRESOLD, prBssDesc->rJoinFailTime); ++ } ++ ++ if (prBssDesc) ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ /* 3.3 Free STA-REC */ ++ if (prStaRec != prAisBssInfo->prStaRecOfAP) ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++#if CFG_SUPPORT_ROAMING ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++#endif /* CFG_SUPPORT_ROAMING */ ++ } else if (CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, ++ SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { ++ /* abort connection trial */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_CONNECT_INDICATION, NULL, 0); ++ ++ eNextState = AIS_STATE_IDLE; ++ } else { ++ /* 4.b send reconnect request */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ } ++ } ++ } ++ } ++#if DBG ++ else ++ DBGLOG(AIS, WARN, "SEQ NO of AIS JOIN COMP MSG is not matched.\n"); ++#endif /* DBG */ ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ } while (FALSE); ++ ++ if (prAssocRspSwRfb) ++ nicRxReturnRFB(prAdapter, prAssocRspSwRfb); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of aisFsmRunEventJoinComplete() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Grant Msg of IBSS Create which was sent by ++* CNM to indicate that channel was changed for creating IBSS. ++* ++* @param[in] prAdapter Pointer of ADAPTER_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ do { ++ /* Check State */ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_IBSS_ALONE) ++ aisUpdateBssInfoForCreateIBSS(prAdapter); ++ } while (FALSE); ++ ++} /* end of aisFsmCreateIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Grant Msg of IBSS Merge which was sent by ++* CNM to indicate that channel was changed for merging IBSS. ++* ++* @param[in] prAdapter Pointer of ADAPTER_T ++* @param[in] prStaRec Pointer of STA_RECORD_T for merge ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ do { ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_MERGE: ++ { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous Peers' STA_RECORD_T in Driver if have. */ ++ bssClearClientList(prAdapter, prAisBssInfo); ++ ++ /* 4 <1.3> Unmark connection flag of previous BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = FALSE; ++ } ++ /* 4 <1.4> Update BSS_INFO_T */ ++ aisUpdateBssInfoForMergeIBSS(prAdapter, prStaRec); ++ ++ /* 4 <1.5> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++ /* 4 <1.6> Activate current Peer's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ /* 4 <1.7> Enable other features */ ++ ++ /* 4 <1.8> Indicate Connected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++ /* 4 <1.9> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ ++ /* 4 <1.10> Release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++#if CFG_SLT_SUPPORT ++ prAdapter->rWifiVar.rSltInfo.prPseudoStaRec = prStaRec; ++#endif ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++ } while (FALSE); ++ ++} /* end of aisFsmMergeIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Notification of existing IBSS was found ++* from SCN. ++* ++* @param[in] prMsgHdr Message of Notification of an IBSS was present. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prAisBssInfo; ++ P_BSS_DESC_T prBssDesc; ++ BOOLEAN fgIsMergeIn; ++ ++ ASSERT(prMsgHdr); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) prMsgHdr; ++ ++ ASSERT(prAisIbssPeerFoundMsg->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX); ++ ++ prStaRec = prAisIbssPeerFoundMsg->prStaRec; ++ ASSERT(prStaRec); ++ ++ fgIsMergeIn = prAisIbssPeerFoundMsg->fgIsMergeIn; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_ALONE: ++ { ++ /* 4 <1> An IBSS Peer 'merged in'. */ ++ if (fgIsMergeIn) { ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++#if CFG_SLT_SUPPORT ++ /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ } else { ++ ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ ++ } ++ ++ /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ ++#else ++ /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ } else { ++ ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ ++ } ++ ++ /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ ++ ++#endif ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ /* 4 <1.6> sync. to firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <1.7> Indicate Connected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++ /* 4 <1.8> indicate PM for connected */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <1.9> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ ++ /* 4 <1.10> Release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ } ++ /* 4 <2> We need 'merge out' to this IBSS */ ++ else { ++ ++ /* 4 <2.1> Get corresponding BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* 4 <2.2> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ } ++ } ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ { ++ ++ /* 4 <3> An IBSS Peer 'merged in'. */ ++ if (fgIsMergeIn) { ++ ++ /* 4 <3.1> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++#if CFG_SLT_SUPPORT ++ /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ ++#else ++ /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ ++#endif ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ } ++ /* 4 <4> We need 'merge out' to this IBSS */ ++ else { ++ ++ /* 4 <4.1> Get corresponding BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* 4 <4.2> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventFoundIBSSPeer() */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Media State to HOST ++* ++* @param[in] eConnectionState Current Media State ++* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication) ++{ ++ EVENT_CONNECTION_STATUS rEventConnStatus; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ DEBUGFUNC("aisIndicationOfMediaStateToHost()"); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* NOTE(Kevin): Move following line to aisChangeMediaState() macro per CM's request. */ ++ /* prAisBssInfo->eConnectionState = eConnectionState; */ ++ ++ /* For indicating the Disconnect Event only if current media state is ++ * disconnected and we didn't do indication yet. ++ */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ if (prAisBssInfo->eConnectionStateIndicated == eConnectionState) ++ return; ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <0> Cancel Delay Timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); ++ ++ /* 4 <1> Fill EVENT_CONNECTION_STATUS */ ++ rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; ++ ++ if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; ++ rEventConnStatus.u2AID = prAisBssInfo->u2AssocId; ++ rEventConnStatus.u2ATIMWindow = 0; ++ } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; ++ rEventConnStatus.u2AID = 0; ++ rEventConnStatus.u2ATIMWindow = prAisBssInfo->u2ATIMWindow; ++ } else { ++ ASSERT(0); ++ } ++ ++ COPY_SSID(rEventConnStatus.aucSsid, ++ rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ COPY_MAC_ADDR(rEventConnStatus.aucBssid, prAisBssInfo->aucBSSID); ++ ++ rEventConnStatus.u2BeaconPeriod = prAisBssInfo->u2BeaconInterval; ++ rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prAisBssInfo->ucPrimaryChannel); ++ ++ switch (prAisBssInfo->ucNonHTBasicPhyType) { ++ case PHY_TYPE_HR_DSSS_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PHY_TYPE_ERP_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PHY_TYPE_OFDM_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ default: ++ ASSERT(0); ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ } ++ } else { ++ /* Deactivate previous Peers' STA_RECORD_T in Driver if have. */ ++ bssClearClientList(prAdapter, prAisBssInfo); ++ ++#if CFG_PRIVACY_MIGRATION ++ /* Clear the pmkid cache while media disconnect */ ++ secClearPmkid(prAdapter); ++#endif ++ ++ rEventConnStatus.ucReasonOfDisconnect = prAisBssInfo->ucReasonOfDisconnect; ++ } ++ ++ /* 4 <2> Indication */ ++ nicMediaStateChange(prAdapter, NETWORK_TYPE_AIS_INDEX, &rEventConnStatus); ++ prAisBssInfo->eConnectionStateIndicated = eConnectionState; ++ } else { ++ /* NOTE: Only delay the Indication of Disconnect Event */ ++ ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ DBGLOG(AIS, INFO, "Postpone the indication of Disconnect for %d seconds\n", ++ prConnSettings->ucDelayTimeOfDisconnectEvent); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rIndicationOfDisconnectTimer, ++ SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); ++ } ++ ++} /* end of aisIndicationOfMediaStateToHost() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if (prAisBssInfo->prStaRecOfAP) { ++ /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ ++ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ } ++ /* 4 <2> Remove pending connection request */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++ prAisBssInfo->u2DeauthReason = REASON_CODE_BEACON_TIMEOUT; ++ /* 4 <3> Indicate Disconnected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, FALSE); ++ ++} /* end of aisPostponedEventOfDisconnTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the association was completed. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ P_BSS_DESC_T prBssDesc; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ DEBUGFUNC("aisUpdateBssInfoForJOIN()"); ++ ++ ASSERT(prStaRec); ++ ASSERT(prAssocRspSwRfb); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ ++ DBGLOG(AIS, TRACE, "Update AIS_BSS_INFO_T and apply settings to MAC\n"); ++ ++ /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Setup Channel, Band */ ++ prAisBssInfo->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; ++ prAisBssInfo->eBand = prAisFsmInfo->prTargetBssDesc->eBand; ++ ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = prStaRec; ++ prAisBssInfo->u2AssocId = prStaRec->u2AssocId; ++ ++ /* 4 <2.2> Setup Capability */ ++ prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) ++ prAisBssInfo->fgIsShortPreambleAllowed = TRUE; ++ else ++ prAisBssInfo->fgIsShortPreambleAllowed = FALSE; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* init the TDLS flags */ ++ prAisBssInfo->fgTdlsIsProhibited = prStaRec->fgTdlsIsProhibited; ++ prAisBssInfo->fgTdlsIsChSwProhibited = prStaRec->fgTdlsIsChSwProhibited; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ /* 4 <3.1> Setup BSSID */ ++ COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ /* 4 <3.2> Parse WMM and setup QBSS flag */ ++ /* Parse WMM related IEs and configure HW CRs accordingly */ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ prAisBssInfo->fgIsQBSS = prStaRec->fgIsQoS; ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAssocRspFrame->aucBSSID); ++ if (prBssDesc) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ prBssDesc->ucJoinFailureCount = 0; ++ ++ /* 4 <4.1> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ } else { ++ /* should never happen */ ++ ASSERT(0); ++ } ++ ++ /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = 0; ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; ++ ++ /* 4 <4.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.3> Sync with firmware for BSS-INFO */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ ++ /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ ++ ++} /* end of aisUpdateBssInfoForJOIN() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will create an Ad-Hoc network and start sending Beacon Frames. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (prAisBssInfo->fgIsBeaconActivated) ++ return; ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prAisBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.4> Setup Channel, Band and Phy Attributes */ ++ prAisBssInfo->ucPrimaryChannel = prConnSettings->ucAdHocChannelNum; ++ prAisBssInfo->eBand = prConnSettings->eAdHocBand; ++ ++ if (prAisBssInfo->eBand == BAND_2G4) { ++ /* Depend on eBand */ ++ prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_MIXED_11BG; ++ } else { ++ /* Depend on eBand */ ++ prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_11A; ++ } ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prConnSettings->u2BeaconPeriod; ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = prConnSettings->u2AtimWindow; ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; ++ ++#if CFG_PRIVACY_MIGRATION ++ if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED || ++ prConnSettings->eEncStatus == ENUM_ENCRYPTION2_ENABLED || ++ prConnSettings->eEncStatus == ENUM_ENCRYPTION3_ENABLED) { ++ prAisBssInfo->fgIsProtection = TRUE; ++ } else { ++ prAisBssInfo->fgIsProtection = FALSE; ++ } ++#else ++ prAisBssInfo->fgIsProtection = FALSE; ++#endif ++ ++ /* 3 <2> Update BSS_INFO_T common part */ ++ ibssInitForAdHoc(prAdapter, prAisBssInfo); ++ ++ /* 3 <3> Set MAC HW */ ++ /* 4 <3.1> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); ++ ++ /* 4 <3.2> use command packets to inform firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <3.3> enable beaconing */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <3.4> Update AdHoc PM parameter */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 3 <4> Set ACTIVE flag. */ ++ prAisBssInfo->fgIsBeaconActivated = TRUE; ++ prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; ++ ++ /* 3 <5> Start IBSS Alone Timer */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); ++ ++ return; ++ ++} /* end of aisCreateIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the existing IBSS was found. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc; ++ /* UINT_16 u2IELength; */ ++ /* PUINT_8 pucIE; */ ++ ++ ASSERT(prStaRec); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); ++ ++ if (!prAisBssInfo->fgIsBeaconActivated) { ++ ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prAisBssInfo->u2AssocId = 0; ++ } ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Setup Capability */ ++ prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use Peer's Cap Info as IBSS Cap Info */ ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { ++ prAisBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prAisBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prAisBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prAisBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ ++ prAisBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ ++ prAisBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_PRIVACY) ++ prAisBssInfo->fgIsProtection = TRUE; ++ else ++ prAisBssInfo->fgIsProtection = FALSE; ++ ++ /* 4 <2.2> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ rateGetDataRatesFromRateSet(prAisBssInfo->u2OperationalRateSet, ++ prAisBssInfo->u2BSSBasicRateSet, ++ prAisBssInfo->aucAllSupportedRates, &prAisBssInfo->ucAllSupportedRatesLen); ++ ++ /* 3 <3> X Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ if (prBssDesc) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <4.1> Setup BSSID */ ++ COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ /* 4 <4.2> Setup Channel, Band */ ++ prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; ++ prAisBssInfo->eBand = prBssDesc->eBand; ++ ++ /* 4 <4.3> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = 0; /* TBD(Kevin) */ ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; ++ } else { ++ /* should never happen */ ++ ASSERT(0); ++ } ++ ++ /* 3 <5> Set MAC HW */ ++ /* 4 <5.1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ { ++ UINT_8 ucLowestBasicRateIndex; ++ ++ if (!rateGetLowestRateIndexFromRateSet(prAisBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex)) { ++ ++ if (prAisBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_OFDM) ++ ucLowestBasicRateIndex = RATE_6M_INDEX; ++ else ++ ucLowestBasicRateIndex = RATE_1M_INDEX; ++ } ++ ++ prAisBssInfo->ucHwDefaultFixedRateCode = ++ aucRateIndex2RateCode[prAisBssInfo->fgUseShortPreamble][ucLowestBasicRateIndex]; ++ } ++ ++ /* 4 <5.2> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); ++ ++ /* 4 <5.3> use command packets to inform firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <5.4> enable beaconing */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <5.5> Update AdHoc PM parameter */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 3 <6> Set ACTIVE flag. */ ++ prAisBssInfo->fgIsBeaconActivated = TRUE; ++ prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; ++ ++} /* end of aisUpdateBssInfoForMergeIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ BOOLEAN fgReplyProbeResp = FALSE; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu4ControlFlags); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) prSwRfb->pvHeader + prSwRfb->u2HeaderLen; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions */ ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ ++ if ((prIeSsid) && ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, /* CURRENT SSID */ ++ prIeSsid->aucSSID, prIeSsid->ucLength))) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++ ++ return fgReplyProbeResp; ++ ++} /* end of aisValidateProbeReq() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will modify and update necessary information to firmware ++* for disconnection handling ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++#if CFG_SUPPORT_ADHOC ++ if (prAisBssInfo->fgIsBeaconActivated) { ++ nicUpdateBeaconIETemplate(prAdapter, IE_UPD_METHOD_DELETE_ALL, NETWORK_TYPE_AIS_INDEX, 0, NULL, 0); ++ ++ prAisBssInfo->fgIsBeaconActivated = FALSE; ++ } ++#endif ++ ++ rlmBssAborted(prAdapter, prAisBssInfo); ++ ++ /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { ++ /* add for ctia mode */ ++ { ++ UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; ++ ++ if (EQUAL_SSID(aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) ++ nicEnterCtiaMode(prAdapter, FALSE, FALSE); ++ } ++ ++ if (prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_RADIO_LOST) { ++ scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* remove from scanning results as well */ ++ wlanClearBssInScanningResult(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* trials for re-association */ ++ if (fgDelayIndication) { ++ DBGLOG(AIS, INFO, "try to do re-association due to radio lost!\n"); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ } ++ } else { ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ } ++ ++ if (fgDelayIndication) { ++ if (OP_MODE_IBSS != prAisBssInfo->eCurrentOPMode) ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } else { ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } ++ } else { ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } ++ ++ /* 4 <4> Change Media State immediately. */ ++ if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION) { ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ /* 4 <4.1> sync. with firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <5> Deactivate previous AP's STA_RECORD_T or all Clients in Driver if have. */ ++ if (prAisBssInfo->prStaRecOfAP) { ++ /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ ++ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ } ++ } ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventAbort(prAdapter); ++ ++ /* clear pending roaming connection request */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* 4 <6> Indicate Disconnected Event to Host */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, fgDelayIndication); ++ ++ /* 4 <7> Trigger AIS FSM */ ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ ++} /* end of aisFsmDisconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of Scan done Time-Out to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 IsrCnt = 0, IsrPassCnt = 0, TaskIsrCnt = 0; ++VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++#define SCAN_DONE_TIMEOUT_TIMES_LIMIT 20 ++ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4FwCnt; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("aisFsmRunEventScanDoneTimeOut()"); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ ++ DBGLOG(AIS, WARN, "aisFsmRunEventScanDoneTimeOut Current[%d], ucScanTimeoutTimes=%d\n", ++ prAisFsmInfo->eCurrentState, ucScanTimeoutTimes); ++ DBGLOG(AIS, WARN, "Isr/task %u %u %u (0x%x)\n", prGlueInfo->IsrCnt, prGlueInfo->IsrPassCnt, ++ prGlueInfo->TaskIsrCnt, prAdapter->fgIsIntEnable); ++ ++ /* dump firmware program counter */ ++ DBGLOG(AIS, WARN, "CONNSYS FW CPUINFO:\n"); ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(AIS, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ ++ ucScanTimeoutTimes++; ++ if (ucScanTimeoutTimes > SCAN_DONE_TIMEOUT_TIMES_LIMIT) { ++ kalSendAeeWarning("[Scan done timeout more than 20 times!]", __func__); ++ glDoChipReset(); ++ } ++#if 0 /* ALPS02018734: remove trigger assert */ ++ if (prAdapter->fgTestMode == FALSE) { ++ /* Titus - xxx */ ++ /* assert if and only if in normal mode */ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); ++ } ++#endif ++ /* report all scanned frames to upper layer to avoid scanned frame is timeout */ ++ /* must be put before kalScanDone */ ++/* scanReportBss2Cfg80211(prAdapter,BSS_TYPE_INFRASTRUCTURE,NULL); */ ++ ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_SCAN: ++ prAisFsmInfo->u4ScanIELength = 0; ++ eNextState = AIS_STATE_IDLE; ++ break; ++ case AIS_STATE_ONLINE_SCAN: ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_NORMAL_TR; ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ default: ++ break; ++ } ++ ++ /* try to stop scan in CONNSYS */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* wlanQueryDebugCode(prAdapter); */ /* display current SCAN FSM in FW, debug use */ ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmBGSleepTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Background Scan Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DEBUGFUNC("aisFsmRunEventBGSleepTimeOut()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ DBGLOG(AIS, LOUD, "EVENT - SCAN TIMER: Idle End - Current Time = %u\n", kalGetTimeTick()); ++ ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmBGSleepTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "IBSS ALONE Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DEBUGFUNC("aisFsmRunEventIbssAloneTimeOut()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_ALONE: ++ ++ /* There is no one participate in our AdHoc during this TIMEOUT Interval ++ * so go back to search for a valid IBSS again. ++ */ ++ ++ DBGLOG(AIS, LOUD, "EVENT-IBSS ALONE TIMER: Start pairing\n"); ++ ++ prAisFsmInfo->fgTryScan = TRUE; ++ ++ /* abort timer */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* Pull back to SEARCH to find candidate again */ ++ eNextState = AIS_STATE_SEARCH; ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisIbssAloneTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Join Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ OS_SYSTIME rCurrentTime; ++ ++ DEBUGFUNC("aisFsmRunEventJoinTimeout()"); ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_JOIN: ++ DBGLOG(AIS, LOUD, "EVENT- JOIN TIMEOUT\n"); ++ ++ /* 1. Do abort JOIN */ ++ aisFsmStateAbort_JOIN(prAdapter); ++ ++ /* 2. Increase Join Failure Count */ ++ prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount++; ++/* For JB nl802.11 */ ++ if (prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) { ++ /* 3.1 Retreat to AIS_STATE_SEARCH state for next try */ ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* 3.2 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ } else if (!CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, ++ SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { ++ /* 3.3 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ } else { ++ /* 3.4 Retreat to AIS_STATE_JOIN_FAILURE to terminate join operation */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_CONNECT_INDICATION, NULL, 0); ++ eNextState = AIS_STATE_IDLE; ++ } ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++ /* 2. process if there is pending scan */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_ONLINE_SCAN; ++ } ++ ++ break; ++ ++ default: ++ /* release channel */ ++ aisFsmReleaseCh(prAdapter); ++ break; ++ ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventJoinTimeout() */ ++ ++VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ aisDeauthXmitComplete(prAdapter, NULL, TX_RESULT_LIFE_TIMEOUT); ++} ++ ++#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisTest(VOID) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucSSID[] = "pci-11n"; ++ UINT_8 ucSSIDLen = 7; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* Set Connection Request Issued Flag */ ++ prConnSettings->fgIsConnReqIssued = TRUE; ++ prConnSettings->ucSSIDLen = ucSSIDLen; ++ kalMemCopy(prConnSettings->aucSSID, aucSSID, ucSSIDLen); ++ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_HEM_AIS_FSM_ABORT; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ wifi_send_msg(INDX_WIFI, MSG_ID_WIFI_IST, 0); ++ ++} ++#endif /* CFG_TEST_MGMT_FSM */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] prSsid Pointer of SSID_T if specified ++* \param[in] pucIe Pointer to buffer of extra information elements to be attached ++* \param[in] u4IeLength Length of information elements ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ DEBUGFUNC("aisFsmScanRequest()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(u4IeLength <= MAX_IE_LENGTH); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (!prConnSettings->fgIsScanReqIssued) { ++ prConnSettings->fgIsScanReqIssued = TRUE; ++ ++ if (prSsid == NULL) { ++ prAisFsmInfo->ucScanSSIDLen = 0; ++ } else { ++ COPY_SSID(prAisFsmInfo->aucScanSSID, ++ prAisFsmInfo->ucScanSSIDLen, prSsid->aucSsid, (UINT_8) prSsid->u4SsidLen); ++ } ++ ++ if (u4IeLength > 0 && u4IeLength <= MAX_IE_LENGTH) { ++ prAisFsmInfo->u4ScanIELength = u4IeLength; ++ kalMemCopy(prAisFsmInfo->aucScanIEBuf, pucIe, u4IeLength); ++ } else { ++ prAisFsmInfo->u4ScanIELength = 0; ++ } ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE ++ && prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { ++ /* 802.1x might not finished yet, pend it for later handling .. */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ } else { ++ if (prAisFsmInfo->fgIsChannelGranted == TRUE) { ++ DBGLOG(AIS, WARN, ++ "Scan Request with channel granted for join operation: %d, %d", ++ prAisFsmInfo->fgIsChannelGranted, prAisFsmInfo->fgIsChannelRequested); ++ } ++ ++ /* start online scan */ ++ wlanClearScanningResult(prAdapter); ++ aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); ++ } ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { ++ wlanClearScanningResult(prAdapter); ++ aisFsmSteps(prAdapter, AIS_STATE_SCAN); ++ } else { ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ } ++ } else { ++ DBGLOG(AIS, WARN, "Scan Request dropped. (state: %d)\n", prAisFsmInfo->eCurrentState); ++ } ++ ++} /* end of aisFsmScanRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is invoked when CNM granted channel privilege ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_CH_GRANT_T prMsgChGrant; ++ UINT_8 ucTokenID; ++ UINT_32 u4GrantInterval; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ++ ucTokenID = prMsgChGrant->ucTokenID; ++ u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ /* 1. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN && prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { ++ /* 2. channel privilege has been approved */ ++ prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++ /* 3. state transition to join/ibss-alone/ibss-merge */ ++ /* 3.1 set timeout timer in cases join could not be completed */ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rJoinTimeoutTimer, ++ prAisFsmInfo->u4ChGrantedInterval - AIS_JOIN_CH_GRANT_THRESHOLD); ++ /* 3.2 set local variable to indicate join timer is ticking */ ++ prAisFsmInfo->fgIsInfraChannelFinished = FALSE; ++ ++ /* 3.3 switch to join state */ ++ aisFsmSteps(prAdapter, AIS_STATE_JOIN); ++ ++ prAisFsmInfo->fgIsChannelGranted = TRUE; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL && ++ prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { ++ /* 2. channel privilege has been approved */ ++ prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++ /* 3.1 set timeout timer in cases upper layer cancel_remain_on_channel never comes */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer, prAisFsmInfo->u4ChGrantedInterval); ++ ++ /* 3.2 switch to remain_on_channel state */ ++ aisFsmSteps(prAdapter, AIS_STATE_REMAIN_ON_CHANNEL); ++ ++ /* 3.3. indicate upper layer for channel ready */ ++ kalReadyOnChannel(prAdapter->prGlueInfo, ++ prAisFsmInfo->rChReqInfo.u8Cookie, ++ prAisFsmInfo->rChReqInfo.eBand, ++ prAisFsmInfo->rChReqInfo.eSco, ++ prAisFsmInfo->rChReqInfo.ucChannelNum, prAisFsmInfo->rChReqInfo.u4DurationMs); ++ ++ prAisFsmInfo->fgIsChannelGranted = TRUE; ++ } else { /* mismatched grant */ ++ /* 2. return channel privilege to CNM immediately */ ++ aisFsmReleaseCh(prAdapter); ++ } ++ ++} /* end of aisFsmRunEventChGrant() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM that channel privilege ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (prAisFsmInfo->fgIsChannelGranted == TRUE || prAisFsmInfo->fgIsChannelRequested == TRUE) { ++ ++ prAisFsmInfo->fgIsChannelRequested = FALSE; ++ prAisFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChAbort) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ return; ++ } ++ ++ prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChAbort->ucTokenID = prAisFsmInfo->ucSeqNumOfChReq; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); ++ } ++ ++} /* end of aisFsmReleaseCh() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform AIS that corresponding beacon has not ++* been received for a while and probing is not successful ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ BOOLEAN fgDoAbortIndication = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Diagnose Connection for Beacon Timeout Event */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { ++ if (OP_MODE_INFRASTRUCTURE == prAisBssInfo->eCurrentOPMode) { ++ P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; ++ ++ if (prStaRec) ++ fgDoAbortIndication = TRUE; ++ } else if (OP_MODE_IBSS == prAisBssInfo->eCurrentOPMode) { ++ fgDoAbortIndication = TRUE; ++ } ++ } ++ /* 4 <2> invoke abort handler */ ++ if (fgDoAbortIndication) { ++#if 0 ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++#endif ++ ++ DBGLOG(AIS, INFO, "Beacon Timeout, Remove BSS [%pM]\n", prAisBssInfo->aucBSSID); ++ scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* ++ Note: Cannot change TRUE to FALSE; or you will suffer the problem in ++ ALPS01270257/ ALPS01804173 ++ */ ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, TRUE); ++ } ++ ++} /* end of aisBssBeaconTimeout() */ ++ ++VOID aisBssSecurityChanged(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prAdapter->rWifiVar.rConnSettings.fgIsDisconnectedByNonRequest = TRUE; ++ prAisBssInfo->u2DeauthReason = REASON_CODE_BSS_SECURITY_CHANGE; ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_DEAUTHENTICATED, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform AIS that DEAUTH frame has been ++* sent and thus state machine could go ahead ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] prMsduInfo Pointer of MSDU_INFO_T for DEAUTH frame ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { ++ if (rTxDoneStatus != TX_RESULT_DROPPED_IN_DRIVER) ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_NEW_CONNECTION, FALSE); ++ } else { ++ DBGLOG(AIS, WARN, "DEAUTH frame transmitted without further handling"); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of aisDeauthXmitComplete() */ ++ ++#if CFG_SUPPORT_ROAMING ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Looking for a candidate due to weak signal" to AIS FSM. ++* ++* @param[in] u4ReqScan Requesting Scan or not ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ENUM_AIS_REQUEST_TYPE_T eAisRequest; ++ ++ DBGLOG(AIS, LOUD, "aisFsmRunEventRoamingDiscovery()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* search candidates by best rssi */ ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ ++#if CFG_SUPPORT_WFD ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ /* Check WFD is running */ ++ P_BSS_INFO_T prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered && ++ IS_BSS_ACTIVE(prP2pBssInfo) && ++ (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || ++ prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)) { ++ DBGLOG(ROAMING, INFO, "Handle roaming when P2P is GC or GO.\n"); ++ if (prAdapter->rWifiVar.prP2pFsmInfo) { ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ if ((prWfdCfgSettings->ucWfdEnable == 1) && ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ DBGLOG(ROAMING, INFO, "WFD is running. Stop roaming.\n"); ++ roamingFsmRunEventRoam(prAdapter); ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); ++ return; ++ } ++ } else { ++ ASSERT(0); ++ } ++ } /* fgIsP2PRegistered */ ++ } ++#endif ++#endif ++ ++ /* results are still new */ ++ if (!u4ReqScan) { ++ roamingFsmRunEventRoam(prAdapter); ++ eAisRequest = AIS_REQUEST_ROAMING_CONNECT; ++ } else { ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN ++ || prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { ++ eAisRequest = AIS_REQUEST_ROAMING_CONNECT; ++ } else { ++ eAisRequest = AIS_REQUEST_ROAMING_SEARCH; ++ } ++ } ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { ++ if (eAisRequest == AIS_REQUEST_ROAMING_SEARCH) ++ aisFsmSteps(prAdapter, AIS_STATE_LOOKING_FOR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_SEARCH); ++ } else { ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++ ++ aisFsmInsertRequest(prAdapter, eAisRequest); ++ } ++ ++} /* end of aisFsmRunEventRoamingDiscovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the time of ScanDone for roaming and transit to Roam state. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DBGLOG(AIS, LOUD, "->aisFsmRoamingScanResultsUpdate()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ roamingFsmScanResultsUpdate(prAdapter); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ if (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) { ++ roamingFsmRunEventRoam(prAdapter); ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { ++ eNextState = AIS_STATE_NORMAL_TR; ++ } ++ ++ return eNextState; ++} /* end of aisFsmRoamingScanResultsUpdate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will modify and update necessary information to firmware ++* for disconnection of last AP before switching to roaming bss. ++* ++* @param IN prAdapter Pointer to the Adapter structure. ++* prTargetStaRec Target of StaRec of roaming ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DBGLOG(AIS, LOUD, "aisFsmRoamingDisconnectPrevAP()"); ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* Not invoke rlmBssAborted() here to avoid prAisBssInfo->fg40mBwAllowed ++ * to be reset. RLM related parameters will be reset again when handling ++ * association response in rlmProcessAssocRsp(). 20110413 ++ */ ++ /* rlmBssAborted(prAdapter, prAisBssInfo); */ ++ ++ /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ /* 4 <4> Change Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ /* 4 <4.1> sync. with firmware */ ++ prTargetStaRec->ucNetTypeIndex = 0xff; /* Virtial NetType */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ prTargetStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Virtial NetType */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, prAisBssInfo->aucBSSID, ++ TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} /* end of aisFsmRoamingDisconnectPrevAP() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the roaming was completed. ++* ++* @param IN prAdapter Pointer to the Adapter structure. ++* prStaRec StaRec of roaming AP ++* prAssocRspSwRfb ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DBGLOG(AIS, LOUD, "aisUpdateBssInfoForRoamingAP()"); ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prAisBssInfo->prStaRecOfAP) && ++ (prAisBssInfo->prStaRecOfAP != prStaRec) && (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { ++ cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++} /* end of aisFsmRoamingUpdateBss() */ ++ ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Check if there is any pending request and remove it (optional) ++* ++* @param prAdapter ++* eReqType ++* bRemove ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_REQ_HDR_T prPendingReqHdr, prPendingReqHdrNext; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* traverse through pending request list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prPendingReqHdr, ++ prPendingReqHdrNext, &(prAisFsmInfo->rPendingReqList), rLinkEntry, AIS_REQ_HDR_T) { ++ /* check for specified type */ ++ if (prPendingReqHdr->eReqType == eReqType) { ++ /* check if need to remove */ ++ if (bRemove == TRUE) { ++ LINK_REMOVE_KNOWN_ENTRY(&(prAisFsmInfo->rPendingReqList), ++ &(prPendingReqHdr->rLinkEntry)); ++ ++ cnmMemFree(prAdapter, prPendingReqHdr); ++ } ++ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get next pending request ++* ++* @param prAdapter ++* ++* @return P_AIS_REQ_HDR_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_REQ_HDR_T prPendingReqHdr; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ LINK_REMOVE_HEAD(&(prAisFsmInfo->rPendingReqList), prPendingReqHdr, P_AIS_REQ_HDR_T); ++ ++ return prPendingReqHdr; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Insert a new request ++* ++* @param prAdapter ++* eReqType ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType) ++{ ++ P_AIS_REQ_HDR_T prAisReq; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ prAisReq = (P_AIS_REQ_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(AIS_REQ_HDR_T)); ++ ++ if (!prAisReq) { ++ ASSERT(0); /* Can't generate new message */ ++ return FALSE; ++ } ++ ++ prAisReq->eReqType = eReqType; ++ ++ /* attach request into pending request list */ ++ LINK_INSERT_TAIL(&prAisFsmInfo->rPendingReqList, &prAisReq->rLinkEntry); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Flush all pending requests ++* ++* @param prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_REQ_HDR_T prAisReq; ++ ++ ASSERT(prAdapter); ++ ++ while ((prAisReq = aisFsmGetNextRequest(prAdapter)) != NULL) ++ cnmMemFree(prAdapter, prAisReq); ++ ++} ++ ++VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_REMAIN_ON_CHANNEL_T prRemainOnChannel; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prRemainOnChannel = (P_MSG_REMAIN_ON_CHANNEL_T) prMsgHdr; ++ ++ /* record parameters */ ++ prAisFsmInfo->rChReqInfo.eBand = prRemainOnChannel->eBand; ++ prAisFsmInfo->rChReqInfo.eSco = prRemainOnChannel->eSco; ++ prAisFsmInfo->rChReqInfo.ucChannelNum = prRemainOnChannel->ucChannelNum; ++ prAisFsmInfo->rChReqInfo.u4DurationMs = prRemainOnChannel->u4DurationMs; ++ prAisFsmInfo->rChReqInfo.u8Cookie = prRemainOnChannel->u8Cookie; ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE || prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { ++ /* transit to next state */ ++ aisFsmSteps(prAdapter, AIS_STATE_REQ_REMAIN_ON_CHANNEL); ++ } else { ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL); ++ } ++ ++ /* free messages */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prCancelRemainOnChannel; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prCancelRemainOnChannel = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) prMsgHdr; ++ ++ /* 1. Check the cookie first */ ++ if (prCancelRemainOnChannel->u8Cookie == prAisFsmInfo->rChReqInfo.u8Cookie) { ++ ++ /* 2. release channel privilege/request */ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL) { ++ /* 2.1 elease channel */ ++ aisFsmReleaseCh(prAdapter); ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { ++ /* 2.1 release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2.2 stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ } ++ ++ /* 3. clear pending request of remain_on_channel */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE); ++ ++ /* 4. decide which state to retreat */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ } ++ ++ /* 5. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ /* prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); */ ++ ++ if (prAisFsmInfo == NULL) ++ break; ++ prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) prMsgHdr; ++ ++ aisFuncTxMgmtFrame(prAdapter, ++ &prAisFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* aisFsmRunEventMgmtFrameTx */ ++ ++VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2. stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ /* 3. expiration indication to upper layer */ ++ kalRemainOnChannelExpired(prAdapter->prGlueInfo, ++ prAisFsmInfo->rChReqInfo.u8Cookie, ++ prAisFsmInfo->rChReqInfo.eBand, ++ prAisFsmInfo->rChReqInfo.eSco, prAisFsmInfo->rChReqInfo.ucChannelNum); ++ ++ /* 4. decide which state to retreat */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ } else { ++ DBGLOG(AIS, WARN, "Unexpected remain_on_channel timeout event\n"); ++#if DBG ++ DBGLOG(AIS, STATE, "CURRENT State: [%s]\n", apucDebugAisState[prAisFsmInfo->eCurrentState]); ++#else ++ DBGLOG(AIS, STATE, "[%d] CURRENT State: [%d]\n", DBG_AIS_IDX, prAisFsmInfo->eCurrentState); ++#endif ++ } ++ ++} ++ ++WLAN_STATUS ++aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_AIS_MGMT_TX_REQ_INFO_T) NULL; ++ BOOLEAN fgIsSuccess = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prMgmtTxReqInfo = &(prAisFsmInfo->rMgmtTxInfo); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(AIS, ERROR, "Mgmt Frame TX Fail, Status:%d.\n", rTxDoneStatus); ++ } else { ++ fgIsSuccess = TRUE; ++ /* printk("Mgmt Frame TX Done.\n"); */ ++ } ++ ++ if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { ++ kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ fgIsSuccess, prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); ++ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* aisFsmRunEventMgmtFrameTxDone */ ++ ++WLAN_STATUS ++aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); ++ ++ if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { ++ ++ /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ ++ /* Packet on driver, not done yet, drop it. */ ++ prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; ++ if (prTxMsduInfo != NULL) { ++ ++ kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ FALSE, ++ prTxMsduInfo->prPacket, (UINT_32) prTxMsduInfo->u2FrameLength); ++ ++ /* Leave it to TX Done handler. */ ++ /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ ++ /* Packet transmitted, wait tx done. (cookie issue) */ ++ } ++ ++ ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanHdr->aucAddr1); ++ prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ ++ prMgmtTxReqInfo->u8Cookie = u8Cookie; ++ prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; ++ prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; ++ ++ prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; ++ prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); ++ if (prStaRec != NULL) { ++ /* Do nothing */ ++ /* printk("Mgmt with station record: %pM .\n", prStaRec->aucMacAddr); */ ++ } ++ ++ prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ ++ prMgmtTxMsdu->fgIs802_1x = FALSE; ++ prMgmtTxMsdu->fgIs802_11 = TRUE; ++ prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMgmtTxMsdu->pfTxDoneHandler = aisFsmRunEventMgmtFrameTxDone; ++ prMgmtTxMsdu->fgIsBasicRate = TRUE; ++ DBGLOG(AIS, TRACE, "Mgmt seq NO. %d .\n", prMgmtTxMsdu->ucTxSeqNum); ++ ++ nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* aisFuncTxMgmtFrame */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Action Frame and indicate to uppoer layer ++* if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("aisFuncValidateRxActionFrame"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (1 /* prAisFsmInfo->u4AisPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME */) { ++ /* Leave the action frame to wpa_supplicant. */ ++ kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* aisFuncValidateRxActionFrame */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c +new file mode 100644 +index 000000000000..f02d7c3bb5b2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c +@@ -0,0 +1,1932 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/assoc.c#3 ++*/ ++ ++/*! \file "assoc.c" ++ \brief This file includes the association-related functions. ++ ++ This file includes the association-related functions. ++*/ ++ ++/*\ ++** Log: assoc.c ++** ++** 07 27 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Fix wifi direct connection issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 06 08 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * add a pair of brace for compilation success. ++ * ++ * 06 04 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * discussed with WH, privacy bit in associate response is not necessary to be checked, ++ * and identified as association failure when mismatching with beacon/probe response ++ * ++ * 03 14 2012 wh.su ++ * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting ++ * Add code from 2.2 ++ * ++ * 03 09 2012 terry.wu ++ * NULL ++ * Fix build error. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 yuche.tsai ++ * NULL ++ * Update Driver for wifi driect gc join IE update issue. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Fix PhyTypeSet in STA_REC in AP mode ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 19 2011 yuche.tsai ++ * NULL ++ * Fix KE when enable hot-spot & any one client connect to this hot-spot. ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 07 15 2011 terry.wu ++ * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment ++ * Update workaround for Kingnet AP. ++ * ++ * 07 15 2011 terry.wu ++ * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment ++ * Workaround for Kingnet 710 AP wrong AID assignment. ++ * ++ * 05 02 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning[WCXRP00000672] [MT6620 Wi-Fi][FW] ++ * Fix the PS event allocation ++ * Check STA when rx assoc. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 03 14 2011 wh.su ++ * [WCXRP00000545] [MT6620 Wi-Fi] [Driver] Fixed the p2p not enable, received a assoc rsp ++ * cause the rx assoc execute a null function ++ * Modify file for avoid assert at BOW receive a assoc response frame but no p2p function. ++ * ++ * 03 08 2011 terry.wu ++ * [WCXRP00000524] [MT6620 Wi-Fi][Driver] Fix p2p assoc request containing wrong IE format ++ * Fix p2p assoc request containing wrong IE format. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix RX disassoc issue under Hot-spot mode. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Phy Type Set. When legacy client is connected, it can use 11b rate, ++ * but if the P2P device is connected, 11b rate is not allowed. ++ * ++ * 01 11 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Desired Non-HT Rate Set. ++ * ++ * 12 30 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Recover the code that was coverwritted.. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add SSID IE in assoc req frame which is sent by P2P GC. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RSN IE generation by CFG_RSN_MIGRATION compilation flag. ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * revised. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update assocProcessRxAssocReqFrame() to avoid redundant SSID IE {0,0} for IOT. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile warning - macro > 10 line, initial value of an array ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * * * * * * and will send Null frame to diagnose connection ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 03 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 28 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * fixed the compiling warning.u1rwduu`wvpghlqg|rm+vp ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update Assoc ID for PS ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Use new constant definition ELEM_MAX_LEN_EXT_CAP ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Modify assoc req IE talbe for HT cap IE ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * update the assocComposeReAssocReqFrameHeader() and fix the u2EstimatedFrameLen in assocSendReAssocReqFrame() ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove some space line ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the sending disassoc frame function ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the txassocReq IE table, adding for WPA/RSN ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix eNetType not init in send AssocReq function ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Integrate the send Assoc with TXM ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to indicate the assoc request and assoc response (now disable) ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove unused variables ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++APPEND_VAR_IE_ENTRY_T txAssocReqIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmReqGenerateHtCapIE} ++ , /* 45 */ ++#if CFG_SUPPORT_WPS2 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WSC), NULL, rsnGenerateWSCIE} ++ , /* 221 */ ++#endif ++#if CFG_RSN_MIGRATION ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} ++ , /* 48 */ ++#endif ++#if CFG_SUPPORT_WAPI ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WAPI), NULL, wapiGenerateWAPIIE} ++ , /* 68 */ ++#endif ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_INTERWORKING), NULL, hs20GenerateInterworkingIE} ++ , /* 107 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ROAMING_CONSORTIUM), NULL, hs20GenerateRoamingConsortiumIE} ++ , /* 111 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmReqGenerateExtCapIE} ++ , /* 127 */ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HS20_INDICATION), NULL, hs20GenerateHS20IE} ++ , /* 221 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO), NULL, mqmGenerateWmmInfoIE} ++ , /* 221 */ ++#if CFG_RSN_MIGRATION ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE} ++ , /* 221 */ ++#endif ++}; ++ ++#if CFG_SUPPORT_AAA ++VERIFY_IE_ENTRY_T rxAssocReqIETable[] = { ++ {ELEM_ID_RESERVED, NULL} /* 255 */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txAssocRespIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} ++ , /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} ++ , /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} ++ , /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} ++ , /* 74 */ ++ {(0), p2pFuncCalculateP2p_IELenForAssocRsp, p2pFuncGenerateP2p_IEForAssocRsp} ++ , /* 221 */ ++#if CFG_SUPPORT_WFD ++ {(0), wfdFuncCalculateWfdIELenForAssocRsp, wfdFuncGenerateWfdIEForAssocRsp} ++ , /* 221 */ ++#endif ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} ++ , /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} ++ , /* 221 */ ++ ++ {(0), p2pFuncCalculateWSC_IELenForAssocRsp, p2pFuncGenerateWSC_IEForAssocRsp} /* 221 */ ++ ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose the Capability Info Field. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval Capability Info Field ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 ++assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ UINT_32 u4NonHTPhyType; ++ UINT_16 u2CapInfo; ++ ++ /* Set up our requested capabilities. */ ++ u2CapInfo = CAP_INFO_ESS; ++ u2CapInfo |= CAP_CF_STA_NOT_POLLABLE; ++ ++ if (prStaRec == NULL) ++ u2CapInfo |= CAP_INFO_PRIVACY; ++ else { ++ if (prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ++ u2CapInfo |= CAP_INFO_PRIVACY; ++ } ++ ++ /* 7.3.1.4 */ ++ if (prStaRec == NULL) { ++ if ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) ||/* ShortPreambleOptionEnable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO)) ++ u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ if (prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) ++ u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ } else if (prStaRec->fgHasBasicPhyType) { ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ if ((rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortPreambleOptionImplemented) && ++ /* Short Preamble Option Enable is TRUE */ ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ /* Case I: Implemented == TRUE and Short Preamble Option Enable == TRUE. ++ * Case II: Implemented == TRUE and Short Preamble == AUTO (depends on ++ * BSS_DESC_T's capability) ++ */ ++ u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ } ++#if CFG_SUPPORT_SPEC_MGMT /*Add by Enlai */ ++ /* Support 802.11h */ ++ if (prStaRec->u2CapInfo & CAP_INFO_SPEC_MGT) { ++ /* ++ 1. The Power Capability element shall be present if ++ dot11SpectrumManagementRequired is true. ++ ++ 2. A STA shall set dot11SpectrumManagementRequired to TRUE before ++ associating with a BSS or IBSS in which the Spectrum Management ++ bit is set to 1 in the Capability Information field in Beacon frames ++ and Probe Response frames received from the BSS or IBSS. ++ */ ++ if (prAdapter->fgEnable5GBand == TRUE) ++ u2CapInfo |= CAP_INFO_SPEC_MGT; ++ } ++#endif ++ ++ if (rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortSlotTimeOptionImplemented && ++ prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) { ++ u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ } ++ } ++ ++ if (prStaRec) { ++ DBGLOG(SAA, LOUD, "ASSOC REQ: Compose Capability = 0x%04x for Target BSS [%pM].\n", ++ u2CapInfo, prStaRec->aucMacAddr); ++ } ++ ++ return u2CapInfo; ++ ++} /* end of assocBuildCapabilityInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Association ++* Request Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID assocBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ PUINT_8 pucBuffer; ++ UINT_16 u2SupportedRateSet; ++ UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; ++ UINT_8 ucAllSupportedRatesLen; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (IS_STA_IN_AIS(prStaRec)) { ++ ++ /* Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ pucBuffer = p2pBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo, pucBuffer); ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) { ++ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++#endif ++ else { ++ /* Do nothing */ ++ /* TODO(Kevin): For other network */ ++ } ++ ++ /* NOTE(Kevin 2008/12/19): 16.3.6.3 MLME-ASSOCIATE.indication - ++ * SupportedRates - The set of data rates that are supported by the STA ++ * that is requesting association. ++ * Original(Portable Driver): Only send the Rates that we'll support. ++ * New: Send the Phy Rates if the result of following & operation == NULL. ++ */ ++ /* rateGetDataRatesFromRateSet((prBssDesc->u2OperationalRateSet & */ ++ /* rPhyAttributes[prBssDesc->ePhyType].u2SupportedRateSet), */ ++ ++ if (prStaRec->fgHasBasicPhyType) { ++ UINT_32 u4NonHTPhyType; ++ ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ u2SupportedRateSet = (prStaRec->u2OperationalRateSet & ++ rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet); ++ ++ ASSERT(u2SupportedRateSet); ++ ++ if (!u2SupportedRateSet) ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ ++ /* TODO(Kevin): For P2P, we shouldn't send support rate set which contains 11b rate */ ++ ++ rateGetDataRatesFromRateSet(u2SupportedRateSet, 0, aucAllSupportedRates, &ucAllSupportedRatesLen); ++ ++ ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? ++ ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); ++ ++ ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; ++ ++ /* Fill the Supported Rates element. */ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* 7.3.2.19 Supported Channels element */ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ if (prAdapter->fgEnable5GBand == TRUE) { ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucId = ELEM_ID_SUP_CHS; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucLength = 8; ++ ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[0] = 36; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[1] = 4; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[2] = 52; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[3] = 4; ++/* Not China --- Start */ ++ /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 100; */ ++ /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 11; */ ++/* Not China --- End */ ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 149; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 4; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[6] = 165; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[7] = 1; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++#endif ++ } ++ ++} /* end of assocBuildReAssocReqFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the (Re)Association Request frame header and ++* its fixed fields ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in out] pu2PayloadLen Return the length of the composed fixed fields ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeReAssocReqFrameHeaderAndFF(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN OUT PUINT_16 pu2PayloadLen) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ BOOLEAN fgIsReAssoc; ++ ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2CapInfo; ++ UINT_16 u2ListenInterval; ++ ++ ASSERT(prStaRec); ++ ASSERT(pucBuffer); ++ ASSERT(aucMACAddress); ++ ASSERT(pu2PayloadLen); ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) pucBuffer; ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ ++ /* Fill the Frame Control field. */ ++ if (fgIsReAssoc) ++ u2FrameCtrl = MAC_FRAME_REASSOC_REQ; ++ else ++ u2FrameCtrl = MAC_FRAME_ASSOC_REQ; ++ WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prAssocFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prAssocFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prAssocFrame->aucBSSID, prStaRec->aucMacAddr); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prAssocFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); ++ ++ /* Fill the Capability Information field. */ ++ WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); ++ ++ /* Calculate the listen interval for the maximum power mode. Currently, we ++ set it to the value 2 times DTIM period. */ ++ if (prStaRec->ucDTIMPeriod) { ++ u2ListenInterval = prStaRec->ucDTIMPeriod * DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD; ++ } else { ++ DBGLOG(SAA, TRACE, "Use default listen interval\n"); ++ u2ListenInterval = DEFAULT_LISTEN_INTERVAL; ++ } ++ prStaRec->u2ListenInterval = u2ListenInterval; ++ ++ /* Fill the Listen Interval field. */ ++ WLAN_SET_FIELD_16(&prAssocFrame->u2ListenInterval, u2ListenInterval); ++ ++ /* 4 <3> Compose the Current AP Address field for ReAssociation Request frame. */ ++ /* Fill the Current AP Address field. */ ++ if (prStaRec->fgIsReAssoc) { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ ++ P_AIS_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ P_WLAN_REASSOC_REQ_FRAME_T prReAssocFrame = (P_WLAN_REASSOC_REQ_FRAME_T) prAssocFrame; ++ ++ COPY_MAC_ADDR(prReAssocFrame->aucCurrentAPAddr, prAisBssInfo->aucBSSID); ++ } else { ++ ASSERT(0); /* We don't support ReAssociation for other network */ ++ } ++ ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + CURR_AP_ADDR_FIELD_LEN); ++ } else { ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN); ++ } ++ ++} /* end of assocComposeReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the (Re)Association Request frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ BOOLEAN fgIsReAssoc; ++ UINT_32 i; ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ ++ if (fgIsReAssoc) { ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ LISTEN_INTERVAL_FIELD_LEN + ++ CURR_AP_ADDR_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ } else { ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ LISTEN_INTERVAL_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ } ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ u2EstimatedExtraIELen = p2pCalculate_IEForAssocReq(prAdapter, ++ prStaRec->ucNetTypeIndex, prStaRec); ++ } else { ++ DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); ++ ASSERT(FALSE); ++ } ++ } else { ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; ++ } else { ++ u2EstimatedExtraIELen += ++ (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ } ++ } ++#else ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; ++ } else { ++ u2EstimatedExtraIELen += (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ } ++#endif ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Request.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeReAssocReqFrameHeaderAndFF(prAdapter, ++ prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prBssInfo->aucOwnMacAddr, &u2PayloadLen); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ ++ assocBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ p2pGenerate_IEForAssocReq(prAdapter, prMsduInfo); ++ } else { ++ DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); ++ ASSERT(FALSE); ++ } ++ } else { ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].pfnAppendIE) ++ txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ } ++#else ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].pfnAppendIE) ++ txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++#endif ++ ++ /* 4 <6> Update the (Re)association request information */ ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++#if CFG_RSN_MIGRATION ++ kalUpdateReAssocReqInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocFrame->u2CapInfo, ++ prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), ++ fgIsReAssoc); ++#endif ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocFrame->u2CapInfo, ++ prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), ++ fgIsReAssoc); ++ } ++#endif ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ ++ DBGLOG(SAA, INFO, "Sending (Re)Assoc Request, network: %d seqNo: %d\n", ++ prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of assocSendReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX (Re)Association Request frame for ++* SAA event handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAssocReqFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2TxFrameCtrl != MAC_FRAME_REASSOC_REQ) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2TxFrameCtrl != MAC_FRAME_ASSOC_REQ) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckTxReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX (Re)Association Response frame for ++* AAA event handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAssocRspFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAssocFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2TxFrameCtrl != MAC_FRAME_REASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2TxFrameCtrl != MAC_FRAME_ASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckTxReAssocRespFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the incoming (Re)Association Frame and take out ++* the status code. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ UINT_16 u2RxFrameCtrl; ++ UINT_16 u2RxCapInfo; ++ UINT_16 u2RxStatusCode; ++ UINT_16 u2RxAssocId; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN + AID_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ DBGLOG(SAA, LOUD, "prSwRfb->u2PayloadLength = %d\n", prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* 4 <1> locate the (Re)Association Resp Frame. */ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of (Re)Association Resp Frame. */ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2RxFrameCtrl != MAC_FRAME_REASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2RxFrameCtrl != MAC_FRAME_ASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* 4 <3> Parse the Fixed Fields of (Re)Association Resp Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2CapInfo, &u2RxCapInfo); */ ++ u2RxCapInfo = prAssocRspFrame->u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2StatusCode, &u2RxStatusCode); */ ++ u2RxStatusCode = prAssocRspFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* 4 <4> Check CAP_INFO */ ++ /* NOTE(Kevin): CM suggest to add MGMT workaround for those APs didn't check ++ * the CAP Privacy Bit to overcome a corner case that the Privacy Bit ++ * of our SCAN result didn't consist with AP's Association Resp. ++ */ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { ++ /* WAPI AP allow the customer use WZC to join mode, the privacy bit is 0 */ ++ /* even at WAI & WAPI_PSK mode, but the assoc respose set the privacy bit set 1 */ ++ DBGLOG(SEC, TRACE, "Workaround the WAPI AP allow the customer to use WZC to join\n"); ++ } else ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && 1) { ++ /* Todo:: Fixed this */ ++ } else ++#endif ++ { ++ } ++ ++#if CFG_STRICT_CHECK_CAPINFO_PRIVACY ++ if ((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ^ (u2RxCapInfo & CAP_INFO_PRIVACY)) ++ u2RxStatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; ++#endif ++ } ++ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++#if CFG_RSN_MIGRATION ++ /* Update the information in the structure used to query and set ++ OID_802_11_ASSOCIATION_INFORMATION. */ ++ kalUpdateReAssocRspInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocRspFrame->u2CapInfo, (UINT_32) (prSwRfb->u2PacketLen)); ++#endif ++ } ++ /* 4 <5> Update CAP_INFO and ASSOC_ID */ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++ prStaRec->u2CapInfo = u2RxCapInfo; ++ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2AssocId, &u2RxAssocId); */ ++ u2RxAssocId = prAssocRspFrame->u2AssocId; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* 20110715 Workaround for Kingnet 710 AP (Realtek 8186) ++ * This AP raises the bit 6&7 not bit 14&15 in AID field. ++ * It cause wrong AID assignment. ++ * For AID = 2 ++ * Normal case: 0xC002(1100 0000 0000 0010) => 2 ++ * Kingnet 710: 0x00C2(0000 0000 1100 0010) => 194 ++ * workaround: mask bit 6&7 for this AP ++ */ ++ if ((u2RxAssocId & BIT(6)) && (u2RxAssocId & BIT(7)) && !(u2RxAssocId & BITS(8, 15))) { ++ prStaRec->u2AssocId = u2RxAssocId & ~BITS(6, 7); ++ } else { ++ prStaRec->u2AssocId = u2RxAssocId & ~AID_MSB; ++#if CFG_SUPPORT_802_11W ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ prBssSpecInfo->ucSaQueryTimedOut = 0; ++ } ++#endif ++ } ++ } ++#if CFG_SUPPORT_802_11W ++ if (u2RxStatusCode == STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED) { ++ DBGLOG(SAA, INFO, "AP rejected due the authentication algorithm not support\n"); ++ } else if (u2RxStatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { ++ PUINT_8 pucIE, pucTime; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_TIMEOUT_INTERVAL == IE_ID(pucIE) && IE_LEN(pucIE) == 5) { ++ pucTime = ((P_IE_HDR_T) pucIE)->aucInfo; ++ if (pucTime[0] == ACTION_SA_TIMEOUT_ASSOC_COMEBACK) { ++ UINT_32 tu; ++ ++ WLAN_GET_FIELD_32(pucTime + 1, &tu); ++ DBGLOG(SAA, INFO, ++ "AP rejected association temporarily;comeback duration %u TU (%u ms)\n", ++ tu, TU_TO_MSEC(tu)); ++ if (tu > TX_ASSOCIATION_RETRY_TIMEOUT_TU) { ++ DBGLOG(SAA, INFO, "Update timer based on comeback duration\n"); ++ /* ieee80211_reschedule_timer(wpa_s, ms); */ ++ } ++ } ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ } ++#endif ++ *pu2StatusCode = u2RxStatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckRxReAssocRspFrameStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will compose the Disassociation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2ReasonCode The reason code of disassociation ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeDisassocFrame(IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN UINT_16 u2ReasonCode) ++{ ++ P_WLAN_DISASSOC_FRAME_T prDisAssocFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(pucBuffer); ++ ASSERT(aucMACAddress); ++ ++ prDisAssocFrame = (P_WLAN_DISASSOC_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the DisAssociation frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_DISASSOC; ++ ++ WLAN_SET_FIELD_16(&prDisAssocFrame->u2FrameCtrl, u2FrameCtrl); ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucBSSID, prStaRec->aucMacAddr); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prDisAssocFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Disassociation frame. */ ++ /* Fill the Reason Code field. */ ++ WLAN_SET_FIELD_16(&prDisAssocFrame->u2ReasonCode, u2ReasonCode); ++ ++} /* end of assocComposeDisassocFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Disassociation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2ReasonCode The reason code of disassociation ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode) ++{ ++ PUINT_8 pucMacAddress; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ /* UINT_32 u4Status = WLAN_STATUS_SUCCESS; */ ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Disassociation Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending DisAssoc.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Disassociation frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ pucMacAddress = prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].aucOwnMacAddr; ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeDisassocFrame(prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucMacAddress, u2ReasonCode); ++ ++#if CFG_SUPPORT_802_11W ++ if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ ++ prDisassocFrame = ++ (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ DBGLOG(TX, WARN, "assocSendDisAssocFrame with protection\n"); ++ } ++#endif ++ ++ u2PayloadLen = REASON_CODE_FIELD_LEN; ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Enqueue the frame to send this (Re)Association request frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of assocSendDisAssocFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Disassociation frame ++* if the given BSSID is matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucBSSID Given BSSID ++* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) ++{ ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ UINT_16 u2RxReasonCode; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucBSSID); ++ ASSERT(pu2ReasonCode); ++ ++ /* 4 <1> locate the Disassociation Frame. */ ++ prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Disassociation Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Check if this Disassoc Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prDisassocFrame->aucBSSID, aucBSSID)) { ++ DBGLOG(SAA, LOUD, "Ignore Disassoc Frame from other BSS [ %pM ]\n", ++ prDisassocFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ ++ WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode); ++ *pu2ReasonCode = u2RxReasonCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocProcessRxDisassocFrame() */ ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Association Req frame ++* and return a Status Code. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode Pointer to store the Status Code for carried in Association Response. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_RSN_INFO_ELEM_T prIeRsn = (P_RSN_INFO_ELEM_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ PUINT_8 pucIE, pucIEStart; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ UINT_16 u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ UINT_16 u2RxFrameCtrl; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ /* 4 <1> locate the Association Req Frame. */ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Association Req Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Check if this Disassoc Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prAssocReqFrame->aucBSSID, prBssInfo->aucBSSID)) ++ return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ ++ /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (MAC_FRAME_REASSOC_REQ == u2RxFrameCtrl) { ++ prStaRec->fgIsReAssoc = TRUE; ++ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); ++ ++ pucIEStart = pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } else { ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); ++ ++ pucIEStart = pucIE = prAssocReqFrame->aucInfoElem; ++ } ++ ++ /* 4 <3> Parse the Fixed Fields of Assoc Req Frame Body. */ ++ prStaRec->u2CapInfo = prAssocReqFrame->u2CapInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ if (((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) && !kalP2PGetCipher(prAdapter->prGlueInfo))) { ++ u2StatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; ++ DBGLOG(RSN, TRACE, "STA Assoc req privacy bit check fail\n"); ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++#endif ++ ++ prStaRec->u2ListenInterval = prAssocReqFrame->u2ListenInterval; ++ prStaRec->ucPhyTypeSet = 0; ++ ++ /* Might be legacy client or p2p gc. */ ++ prStaRec->eStaType = STA_TYPE_LEGACY_CLIENT; ++ ++ /* 4 <4> Parse the IE of Assoc Req Frame Body. */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && /* NOTE(Kevin): Get SSID once */ ++ (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ } ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ if (!prIeExtSupportedRate) ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ case ELEM_ID_HT_CAP: ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ kalMemCopy(&prStaRec->u2HtCapInfo, &(HT_CAP_IE(pucIE)->u2HtCapInfo), 2); ++ break; ++ case ELEM_ID_RSN: ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ prIeRsn = RSN_IE(pucIE); ++ rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, &u2StatusCode); ++ if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ *pu2StatusCode = u2StatusCode; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++#endif ++ break; ++ case ELEM_ID_VENDOR: ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ UINT_8 ucOuiType = 0; ++ ++ p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType); ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ DBGLOG(P2P, TRACE, "Target Client is a P2P group client\n"); ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ } ++ } ++ } ++#endif ++ break; ++ default: ++ for (i = 0; i < (sizeof(rxAssocReqIETable) / sizeof(VERIFY_IE_ENTRY_T)); i++) { ++ ++ if ((IE_ID(pucIE)) == rxAssocReqIETable[i].ucElemID) { ++ rxAssocReqIETable[i].pfnVarifyIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIE, ++ &u2StatusCode); ++ ++ if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ *pu2StatusCode = u2StatusCode; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* parsing for WMM related information (2010/12/21) */ ++ mqmProcessAssocReq(prAdapter, prSwRfb, pucIEStart, u2IELength); ++ ++ do { ++ if (prIeSsid) { ++ if (UNEQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ ++ u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; ++ break; ++ } ++ } else { ++ u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; ++ break; ++ } ++ ++ prStaRec->u2OperationalRateSet = 0; ++ prStaRec->u2BSSBasicRateSet = 0; ++ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, &prStaRec->u2OperationalRateSet, ++ &u2BSSBasicRateSet, /* Ignore any Basic Bit */ ++ &fgIsUnknownBssBasicRate); ++ ++ if ((prBssInfo->u2BSSBasicRateSet & prStaRec->u2OperationalRateSet) != ++ prBssInfo->u2BSSBasicRateSet) { ++ ++ u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ ++ /* Accpet the Sta, update BSSBasicRateSet from Bss */ ++ ++ prStaRec->u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; ++ ++ prStaRec->u2DesiredNonHTRateSet = (prStaRec->u2OperationalRateSet & RATE_SET_ALL_ABG); ++ ++ if (BAND_2G4 == HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr)) { ++#if 0 /* Marked by CMC 20111024 */ ++ /* check if support 11n */ ++ if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ ++ if ((!(u2BSSBasicRateSet & RATE_SET_OFDM)) && ++ (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS)) { ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++ ++ } ++ ++ } ++#else ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++#endif ++ } else { /* (BAND_5G == prBssDesc->eBande) */ ++#if 0 /* Marked by CMC 20111024 */ ++ if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++ ASSERT((prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) == 0); ++#else ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++#endif ++ } ++ ++ } else { ++ ASSERT(0); ++ u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ if (prIeRsn) { ++ if (!kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ u2StatusCode = STATUS_CODE_CIPHER_SUITE_REJECTED; ++ break; ++ } ++ } else { ++ prStaRec->rSecInfo.fgAllowOnly1x = FALSE; ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ /* Only Allow 1x */ ++ prStaRec->rSecInfo.fgAllowOnly1x = TRUE; ++ break; ++ } ++ } ++ } ++#endif ++ ++ } while (FALSE); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++#if 1 /* ICS */ ++ { ++ PUINT_8 cp = (PUINT_8) &prAssocReqFrame->u2CapInfo; ++ P_UINT_8 prNewAssocReqIe = NULL; ++ ++ if (u2IELength) { ++ prNewAssocReqIe = kalMemAlloc(u2IELength, VIR_MEM_TYPE); ++ if (NULL == prNewAssocReqIe) { ++ DBGLOG(AIS, WARN, "allocate memory for (Re)assocReqIe fail!\n"); ++ u2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ if (prStaRec->fgIsReAssoc) ++ cp += 10; ++ else ++ cp += 4; ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ } ++ prStaRec->u2AssocReqIeLen = u2IELength; ++ if (u2IELength) { ++ prStaRec->pucAssocReqIe = prNewAssocReqIe; /* kalMemAlloc(u2IELength, VIR_MEM_TYPE); */ ++ kalMemCopy(prStaRec->pucAssocReqIe, cp, u2IELength); ++ } ++ } ++#endif ++ kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, (PUINT_8) &prAssocReqFrame->u2CapInfo, ++ u2IELength + (prStaRec->fgIsReAssoc ? 10 : 4), prStaRec->fgIsReAssoc); ++ } ++#endif ++ ++ *pu2StatusCode = u2StatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocProcessRxAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Association ++* Response Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocBuildReAssocRespFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo) ++{ ++ PUINT_8 pucBuffer; ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { ++ ++ ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; ++ ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; ++ } else { ++ ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; ++ ucExtSupRatesLen = 0; ++ } ++ ++ /* Fill the Supported Rates element. */ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &prBssInfo->aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* end of assocBuildReAssocRespFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the (Re)Association Response frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucBssid Given BSSID. ++* @param[in] u2CapInfo Capability Field of current BSS. ++* @param[in out] pu2PayloadLen Return the length of the composed fixed fields ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeReAssocRespFrameHeaderAndFF(IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, ++ IN UINT_8 aucBSSID[], IN UINT_16 u2CapInfo, IN OUT PUINT_16 pu2PayloadLen) ++{ ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ BOOLEAN fgIsReAssoc; ++ ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(prStaRec); ++ ASSERT(pucBuffer); ++ ASSERT(aucBSSID); ++ ASSERT(pu2PayloadLen); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) pucBuffer; ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ ++ /* Fill the Frame Control field. */ ++ if (fgIsReAssoc) ++ u2FrameCtrl = MAC_FRAME_REASSOC_RSP; ++ else ++ u2FrameCtrl = MAC_FRAME_ASSOC_RSP; ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prAssocRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target MAC Address. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with current BSSID. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucSrcAddr, aucBSSID); ++ ++ /* Fill the BSSID field with current BSSID. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucBSSID, aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prAssocRspFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ ++ /* Fill the Capability Information field. */ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); */ ++ prAssocRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2StatusCode, prStaRec->u2StatusCode); */ ++ prAssocRspFrame->u2StatusCode = prStaRec->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2AssocId, ((prStaRec->u2AssocId & AID_MASK) | AID_MSB)); */ ++ prAssocRspFrame->u2AssocId = ((prStaRec->u2AssocId & AID_MASK) | AID_MSB); /* NOTE(Kevin): Optimized for ARM */ ++ ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); ++ ++} /* end of assocComposeReAssocRespFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the (Re)Association Resp frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ BOOLEAN fgIsReAssoc; ++ UINT_32 i; ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN + ++ AID_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocRespIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocRespIETable[i].u2EstimatedFixedIELen; ++ } else if (txAssocRespIETable[i].pfnCalculateVariableIELen != NULL) { ++ u2EstimatedExtraIELen += (UINT_16) txAssocRespIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ ++ } ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(AAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Response.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex != NETWORK_TYPE_AIS_INDEX); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeReAssocRespFrameHeaderAndFF(prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prBssInfo->aucBSSID, prBssInfo->u2CapInfo, &u2PayloadLen); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = aaaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ ++ assocBuildReAssocRespFrameCommonIEs(prAdapter, prMsduInfo, prBssInfo); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocRespIETable[i].pfnAppendIE) ++ txAssocRespIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ ++ DBGLOG(SAA, INFO, "Sending (Re)Assoc Response, network: %d seqNo: %d\n", ++ prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocSendReAssocRespFrame() */ ++#endif /* CFG_SUPPORT_AAA */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c +new file mode 100644 +index 000000000000..43b91d72bd43 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c +@@ -0,0 +1,1211 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/auth.c#1 ++*/ ++ ++/*! \file "auth.c" ++ \brief This file includes the authentication-related functions. ++ ++ This file includes the authentication-related functions. ++*/ ++ ++/* ++** Log: auth.c ++ * ++ * 02 13 2012 cp.wu ++ * NULL ++ * show error message only instead of raise assertion when ++ * received authentication frame is carrying illegal parameters. ++ * ++ * 11 09 2011 yuche.tsai ++ * NULL ++ * Fix a network index & station record index issue when TX deauth frame. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 yuche.tsai ++ * NULL ++ * Fix coding error. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000796] [Volunteer Patch][MT6620][Driver] Add BC deauth frame TX feature. ++ * BC deauth support. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * 1. Fix Service Disocvery Logical issue. ++ * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 21 2011 terry.wu ++ * [WCXRP00000381] [MT6620 Wi-Fi][Driver] Kernel panic when replying unaccept Auth in AP mode ++ * In AP mode, use STA_REC_INDEX_NOT_FOUND(0xFE) instead of StaRec index when replying an unaccept Auth frame. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update authSendDeauthFrame() for correct the value of eNetTypeIndex in MSDU_INFO_T ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Check Net is active before sending Deauth frame. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Fix compile warning ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add debug message for abnormal authentication frame from AP ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Fix the Debug Label ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update the authComposeAuthFrameHeader() ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the send deauth frame function ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Integrate send Auth with TXM ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++APPEND_IE_ENTRY_T txAuthIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_CHALLENGE_TEXT), authAddIEChallengeText} ++}; ++ ++HANDLE_IE_ENTRY_T rxAuthIETable[] = { ++ {ELEM_ID_CHALLENGE_TEXT, authHandleIEChallengeText} ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Authentication frame header and fixed fields. ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucPeerMACAddress Given Peer MAC Address. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2AuthAlgNum Authentication Algorithm Number ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* @param[in] u2StatusCode Status Code ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++authComposeAuthFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN UINT_8 aucPeerMACAddress[], ++ IN UINT_8 aucMACAddress[], ++ IN UINT_16 u2AuthAlgNum, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(aucPeerMACAddress); ++ ASSERT(aucMACAddress); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Authentication frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_AUTH; ++ ++ /* If this frame is the third frame in the shared key authentication ++ * sequence, it shall be encrypted. ++ */ ++ if ((u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) ++ u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; /* HW will also detect this bit for applying encryption */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prAuthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucDestAddr, aucPeerMACAddress); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prAuthFrame->aucSrcAddr, aucMACAddress); ++ ++ switch (u2TransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucPeerMACAddress); ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ ++ /* Fill the BSSID field with Current BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ /* Clear the SEQ/FRAG_NO field. */ ++ prAuthFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ ++ /* Fill the Authentication Algorithm Number field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthAlgNum, u2AuthAlgNum); */ ++ prAuthFrame->u2AuthAlgNum = u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Authentication Transaction Sequence Number field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, u2TransactionSeqNum); */ ++ prAuthFrame->u2AuthTransSeqNo = u2TransactionSeqNum; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Status Code field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2StatusCode, u2StatusCode); */ ++ prAuthFrame->u2StatusCode = u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of authComposeAuthFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will append Challenge Text IE to the Authentication frame ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TransactionSeqNum; ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) ++ return; ++ ++ ASSERT(prStaRec); ++ ++ /* For Management, frame header and payload are in a continuous buffer */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prMsduInfo->prPacket; ++ ++ WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) ++ ++ /* Only consider SEQ_3 for Challenge Text */ ++ if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3) && ++ (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (prStaRec->prChallengeText != NULL)) { ++ ++ COPY_IE(((ULONG) (prMsduInfo->prPacket) + prMsduInfo->u2FrameLength), (prStaRec->prChallengeText)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prStaRec->prChallengeText); ++ } ++ ++ return; ++ ++} /* end of authAddIEChallengeText() */ ++ ++#if !CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Authenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ UINT_16 u2PayloadLen; ++ UINT_32 i; ++ ++ DBGLOG(SAA, LOUD, "Send Auth Frame\n"); ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) ++ u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and some Fixed Fields */ ++ authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec->aucMacAddr, ++ prBssInfo->aucOwnMacAddr, ++ prStaRec->ucAuthAlgNum, u2TransactionSeqNum, STATUS_CODE_RESERVED); ++ ++ u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { ++ if (txAuthIETable[i].pfnAppendIE) ++ txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Authentication frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendAuthFrame() */ ++ ++#else ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Authenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authSendAuthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) ++{ ++ PUINT_8 pucReceiveAddr; ++ PUINT_8 pucTransmitAddr; ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ /*get from input parameter */ ++ /* ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; */ ++ PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ UINT_16 u2PayloadLen; ++ UINT_16 ucAuthAlgNum; ++ UINT_32 i; ++ ++ DBGLOG(SAA, LOUD, "Send Auth Frame %d, Status Code = %d\n", u2TransactionSeqNum, u2StatusCode); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) ++ u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ ++ if (prStaRec) { ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucReceiveAddr = prStaRec->aucMacAddr; ++ ++ ucAuthAlgNum = prStaRec->ucAuthAlgNum; ++ ++ switch (u2TransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++ pfTxDoneHandler = saaFsmRunEventTxDone; ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ pfTxDoneHandler = aaaFsmRunEventTxDone; ++ break; ++ } ++ ++ } else { /* For Error Status Code */ ++ P_WLAN_AUTH_FRAME_T prFalseAuthFrame; ++ ++ ASSERT(prFalseAuthSwRfb); ++ prFalseAuthFrame = (P_WLAN_AUTH_FRAME_T) prFalseAuthSwRfb->pvHeader; ++ ++ ASSERT(u2StatusCode != STATUS_CODE_SUCCESSFUL); ++ ++ pucTransmitAddr = prFalseAuthFrame->aucDestAddr; ++ ++ pucReceiveAddr = prFalseAuthFrame->aucSrcAddr; ++ ++ ucAuthAlgNum = prFalseAuthFrame->u2AuthAlgNum; ++ ++ u2TransactionSeqNum = (prFalseAuthFrame->u2AuthTransSeqNo + 1); ++ } ++ ++ /* Compose Header and some Fixed Fields */ ++ authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucReceiveAddr, ++ pucTransmitAddr, ucAuthAlgNum, u2TransactionSeqNum, u2StatusCode); ++ ++ u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ if (prStaRec) ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ else ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; /* false Auth frame */ ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { ++ if (txAuthIETable[i].pfnAppendIE) ++ txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Authentication frame. */ ++ DBGLOG(SAA, INFO, "network: %d Send Auth Frame %d, Status Code = %d seq num %d\n", ++ eNetTypeIndex, u2TransactionSeqNum, u2StatusCode, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendAuthFrame() */ ++ ++#endif /* CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX Authentication frame for SAA/AAA event ++* handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ UINT_16 u2TxAuthAlgNum; ++ UINT_16 u2TxTransactionSeqNum; ++ ++ ASSERT(prMsduInfo); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAuthFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAuthFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (u2TxFrameCtrl != MAC_FRAME_AUTH) ++ return WLAN_STATUS_FAILURE; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2TxAuthAlgNum) */ ++ u2TxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2TxAuthAlgNum != (UINT_16) (prStaRec->ucAuthAlgNum)) ++ return WLAN_STATUS_FAILURE; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TxTransactionSeqNum) */ ++ u2TxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2TxTransactionSeqNum != u2TransactionSeqNum) ++ return WLAN_STATUS_FAILURE; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckTxAuthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Auth Frame's Transaction Sequence ++* Number before delivering it to the corresponding SAA or AAA Module. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain authentication frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2RxTransactionSeqNum; ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Authentication Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 4 <3> Parse the Fixed Fields of Authentication Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ ++ u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ switch (u2RxTransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ saaFsmRunEventRxAuth(prAdapter, prSwRfb); ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAuth(prAdapter, prSwRfb); ++#endif /* CFG_SUPPORT_AAA */ ++ break; ++ ++ default: ++ DBGLOG(SAA, WARN, "Strange Authentication Packet: Auth Trans Seq No = %d, Error Status Code = %d\n", ++ u2RxTransactionSeqNum, prAuthFrame->u2StatusCode); ++ break; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckRxAuthFrameTransSeq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the incoming Authentication Frame and take ++* the status code out. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2RxAuthAlgNum; ++ UINT_16 u2RxTransactionSeqNum; ++ /* UINT_16 u2RxStatusCode; // NOTE(Kevin): Optimized for ARM */ ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Fixed Fields of Authentication Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2RxAuthAlgNum); */ ++ u2RxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2RxAuthAlgNum != (UINT_16) prStaRec->ucAuthAlgNum) { ++ DBGLOG(SAA, WARN, "Discard Auth frame with auth type = %d, current = %d\n", ++ u2RxAuthAlgNum, prStaRec->ucAuthAlgNum); ++ *pu2StatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ ++ u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2RxTransactionSeqNum != u2TransactionSeqNum) { ++ DBGLOG(SAA, WARN, "Discard Auth frame with Transaction Seq No = %d\n", u2RxTransactionSeqNum); ++ *pu2StatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 4 <3> Get the Status code */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2StatusCode, &u2RxStatusCode); */ ++ /* *pu2StatusCode = u2RxStatusCode; */ ++ *pu2StatusCode = prAuthFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckRxAuthFrameStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Challenge Text IE from the Authentication frame ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] prIEHdr Pointer to start address of IE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TransactionSeqNum; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prIEHdr); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ /* For Management, frame header and payload are in a continuous buffer */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) */ ++ u2TransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Only consider SEQ_2 for Challenge Text */ ++ if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_2) && ++ (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY)) { ++ ++ /* Free previous allocated TCM memory */ ++ if (prStaRec->prChallengeText) { ++ ASSERT(0); ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ prStaRec->prChallengeText = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, IE_SIZE(prIEHdr)); ++ if (prStaRec->prChallengeText == NULL) ++ return; ++ ++ /* Save the Challenge Text from Auth Seq 2 Frame, before sending Auth Seq 3 Frame */ ++ COPY_IE(prStaRec->prChallengeText, prIEHdr); ++ } ++ ++ return; ++ ++} /* end of authAddIEChallengeText() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Authentication frame. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ PUINT_8 pucIEsBuffer; ++ UINT_16 u2IEsLen; ++ UINT_16 u2Offset; ++ UINT_8 ucIEID; ++ UINT_32 i; ++ ++ ASSERT(prSwRfb); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ pucIEsBuffer = &prAuthFrame->aucInfoElem[0]; ++ u2IEsLen = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ IE_FOR_EACH(pucIEsBuffer, u2IEsLen, u2Offset) { ++ ucIEID = IE_ID(pucIEsBuffer); ++ ++ for (i = 0; i < (sizeof(rxAuthIETable) / sizeof(HANDLE_IE_ENTRY_T)); i++) { ++ ++ if (ucIEID == rxAuthIETable[i].ucElemID) ++ rxAuthIETable[i].pfnHandleIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIEsBuffer); ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxAuth2_Auth4Frame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Deauthentication frame ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucPeerMACAddress Given Peer MAC Address. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2StatusCode Status Code ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++authComposeDeauthFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN UINT_8 aucPeerMACAddress[], ++ IN UINT_8 aucMACAddress[], IN UINT_8 aucBssid[], IN UINT_16 u2ReasonCode) ++{ ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(aucPeerMACAddress); ++ ASSERT(aucMACAddress); ++ ASSERT(aucBssid); ++ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Deauthentication frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_DEAUTH; ++ ++ /* WLAN_SET_FIELD_16(&prDeauthFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prDeauthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucDestAddr, aucPeerMACAddress); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucBSSID, aucBssid); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prDeauthFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ ++ /* Fill the Status Code field. */ ++ /* WLAN_SET_FIELD_16(&prDeauthFrame->u2ReasonCode, u2ReasonCode); */ ++ prDeauthFrame->u2ReasonCode = u2ReasonCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of authComposeDeauthFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Deauthenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prClassErrSwRfb Pointer to the SW_RFB_T which is Class Error. ++* @param[in] u2ReasonCode A reason code to indicate why to leave BSS. ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++* @retval WLAN_STATUS_FAILURE Didn't send Deauth frame for various reasons. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authSendDeauthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_WLAN_MAC_HEADER_A4_T prWlanMacHeader = NULL; ++ PUINT_8 pucReceiveAddr; ++ PUINT_8 pucTransmitAddr; ++ PUINT_8 pucBssid = NULL; ++ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2RxFrameCtrl; ++ P_BSS_INFO_T prBssInfo; ++ ++ P_DEAUTH_INFO_T prDeauthInfo; ++ OS_SYSTIME rCurrentTime; ++ INT_32 i4NewEntryIndex, i; ++ UINT_8 ucStaRecIdx = STA_REC_INDEX_NOT_FOUND; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 aucBMC[] = BC_MAC_ADDR; ++#endif ++ ++ /* NOTE(Kevin): The best way to reply the Deauth is according to the incoming data ++ * frame ++ */ ++ /* 4 <1> Find the Receiver Address first. */ ++ if (prClassErrSwRfb) { ++ BOOLEAN fgIsAbleToSendDeauth = FALSE; ++ ++ prWlanMacHeader = (P_WLAN_MAC_HEADER_A4_T) prClassErrSwRfb->pvHeader; ++ ++ /* WLAN_GET_FIELD_16(&prWlanMacHeader->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prWlanMacHeader->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* TODO(Kevin): Currently we won't send Deauth for IBSS node. How about DLS ? */ ++ if ((prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) == 0) ++ return WLAN_STATUS_FAILURE; ++ ++ /* Check if corresponding BSS is able to send Deauth */ ++ for (i = NETWORK_TYPE_AIS_INDEX; i < NETWORK_TYPE_INDEX_NUM; i++) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[i]); ++ ++ if (IS_NET_ACTIVE(prAdapter, i) && ++ (EQUAL_MAC_ADDR(prWlanMacHeader->aucAddr1, prBssInfo->aucOwnMacAddr))) { ++ { ++ fgIsAbleToSendDeauth = TRUE; ++ eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) i; ++ break; ++ } ++ } ++ } ++ ++ if (!fgIsAbleToSendDeauth) ++ return WLAN_STATUS_FAILURE; ++ ++ pucReceiveAddr = prWlanMacHeader->aucAddr2; ++ ++ } else if (prStaRec) { ++ ++ pucReceiveAddr = prStaRec->aucMacAddr; ++ } else { ++#if CFG_ENABLE_WIFI_DIRECT ++ pucReceiveAddr = aucBMC; ++#else ++ return WLAN_STATUS_FAILURE; ++#endif ++ } ++ ++ /* 4 <2> Check if already send a Deauth frame in MIN_DEAUTH_INTERVAL_MSEC */ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ i4NewEntryIndex = -1; ++ for (i = 0; i < MAX_DEAUTH_INFO_COUNT; i++) { ++ prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i]); ++ ++ /* For continuously sending Deauth frame, the minimum interval is ++ * MIN_DEAUTH_INTERVAL_MSEC. ++ */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, ++ prDeauthInfo->rLastSendTime, MSEC_TO_SYSTIME(MIN_DEAUTH_INTERVAL_MSEC))) { ++ ++ i4NewEntryIndex = i; ++ } else if (EQUAL_MAC_ADDR(pucReceiveAddr, prDeauthInfo->aucRxAddr) && (!pfTxDoneHandler)) { ++ ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ /* 4 <3> Update information. */ ++ if (i4NewEntryIndex > 0) { ++ ++ prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i4NewEntryIndex]); ++ ++ COPY_MAC_ADDR(prDeauthInfo->aucRxAddr, pucReceiveAddr); ++ prDeauthInfo->rLastSendTime = rCurrentTime; ++ } else { ++ /* NOTE(Kevin): for the case of AP mode, we may encounter this case ++ * if deauth all the associated clients. ++ */ ++ DBGLOG(SAA, WARN, "No unused DEAUTH_INFO_T !\n"); ++ } ++ ++ /* 4 <4> Allocate a PKT_INFO_T for Deauthentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Deauth Request.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <5> Find the Transmitter Address and BSSID. */ ++ if (prClassErrSwRfb) { ++ ++ /* The TA of Deauth is the A1 of RX frame */ ++ pucTransmitAddr = prWlanMacHeader->aucAddr1; ++ ++ switch (prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) { ++ ++ case MASK_FC_FROM_DS: ++ /* The BSSID of Deauth is the A2 of RX frame */ ++ pucBssid = prWlanMacHeader->aucAddr2; ++ break; ++ ++ case MASK_FC_TO_DS: ++ /* The BSSID of Deauth is the A1 of RX frame */ ++ pucBssid = prWlanMacHeader->aucAddr1; ++ break; ++ ++ case MASK_TO_DS_FROM_DS: ++ /* TODO(Kevin): Consider BOW, now we set the BSSID of Deauth ++ * to the A2 of RX frame for temporary solution. ++ */ ++ pucBssid = prWlanMacHeader->aucAddr2; ++ break; ++ ++ /* No Default */ ++ } ++ ++ } else if (prStaRec) { ++ eNetTypeIndex = prStaRec->ucNetTypeIndex; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucBssid = prBssInfo->aucBSSID; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else { ++ if (prAdapter->fgIsP2PRegistered) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ ucStaRecIdx = STA_REC_INDEX_BMCAST; ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucBssid = prBssInfo->aucBSSID; ++ ++ eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ } else { ++ /* 20130122: free packet by samplin */ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++#endif ++ ++ /* 4 <6> compose Deauthentication frame header and some fixed fields */ ++ authComposeDeauthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucReceiveAddr, pucTransmitAddr, pucBssid, u2ReasonCode); ++ ++#if CFG_SUPPORT_802_11W ++ if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ ++ prDeauthFrame = ++ (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ DBGLOG(TX, WARN, "authSendDeauthFrame with protection\n"); ++ } ++#endif ++ ++ /* 4 <7> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = ((prStaRec == NULL) ? ucStaRecIdx : prStaRec->ucIndex); ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ DBGLOG(SAA, INFO, "Sending Deauth, network: %d, seqNo %d\n", ++ eNetTypeIndex, prMsduInfo->ucTxSeqNum); ++ ++ /* 4 <8> Inform TXM to send this Deauthentication frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendDeauthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Deauthentication frame ++* if the given BSSID is matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucBSSID Given BSSID ++* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) ++{ ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ UINT_16 u2RxReasonCode; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucBSSID); ++ ASSERT(pu2ReasonCode); ++ ++ /* 4 <1> locate the Deauthentication Frame. */ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Deauthentication Frame. */ ++#if 0 /* Kevin: Seems redundant */ ++ WLAN_GET_FIELD_16(&prDeauthFrame->u2FrameCtrl, &u2RxFrameCtrl) ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (u2RxFrameCtrl != MAC_FRAME_DEAUTH) ++ return WLAN_STATUS_FAILURE; ++#endif ++ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Check if this Deauth Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prDeauthFrame->aucBSSID, aucBSSID)) { ++ DBGLOG(SAA, LOUD, "Ignore Deauth Frame from other BSS [ %pM ]\n", ++ prDeauthFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ ++ WLAN_GET_FIELD_16(&prDeauthFrame->u2ReasonCode, &u2RxReasonCode); ++ *pu2ReasonCode = u2RxReasonCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxDeauthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Authentication frame. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucExpectedBSSID Given Expected BSSID. ++* @param[in] u2ExpectedAuthAlgNum Given Expected Authentication Algorithm Number ++* @param[in] u2ExpectedTransSeqNum Given Expected Transaction Sequence Number. ++* @param[out] pu2ReturnStatusCode Return Status Code. ++* ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++* @retval WLAN_STATUS_FAILURE The frame we will ignore. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN UINT_8 aucExpectedBSSID[], ++ IN UINT_16 u2ExpectedAuthAlgNum, ++ IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2ReturnStatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucExpectedBSSID); ++ ASSERT(pu2ReturnStatusCode); ++ ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Check the BSSID */ ++ if (UNEQUAL_MAC_ADDR(prAuthFrame->aucBSSID, aucExpectedBSSID)) ++ return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ ++ /* 4 <3> Check the SA, which should not be MC/BC */ ++ if (prAuthFrame->aucSrcAddr[0] & BIT(0)) { ++ DBGLOG(P2P, WARN, "Invalid STA MAC with MC/BC bit set: %pM\n", ++ prAuthFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <4> Parse the Fixed Fields of Authentication Frame Body. */ ++ if (prAuthFrame->u2AuthAlgNum != u2ExpectedAuthAlgNum) ++ u2ReturnStatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; ++ ++ if (prAuthFrame->u2AuthTransSeqNo != u2ExpectedTransSeqNum) ++ u2ReturnStatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; ++ ++ *pu2ReturnStatusCode = u2ReturnStatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxAuth1Frame() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c +new file mode 100644 +index 000000000000..160779583655 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c +@@ -0,0 +1,2521 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/bss.c#3 ++*/ ++ ++/*! \file "bss.c" ++ \brief This file contains the functions for creating BSS(AP)/IBSS(AdHoc). ++ ++ This file contains the functions for BSS(AP)/IBSS(AdHoc). We may create a BSS/IBSS ++ network, or merge with exist IBSS network and sending Beacon Frame or reply ++ the Probe Response Frame for received Probe Request Frame. ++*/ ++ ++/* ++** Log: bss.c ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 14 2012 chinglan.wang ++ * NULL ++ * Fix the losing of the HT IE in assoc request.. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 08 2012 yuche.tsai ++ * NULL ++ * Fix FW assert when start Hot-Spot. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 20 2012 chinglan.wang ++ * 03 02 2012 terry.wu ++ * NULL ++ * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug. ++ * ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 15 2012 yuche.tsai ++ * NULL ++ * Fix wrong basic rate issue. ++ * ++ * 01 13 2012 yuche.tsai ++ * NULL ++ * WiFi Hot Spot Tethering for ICS ALPHA testing version. ++ * ++ * 11 03 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Always set short slot time to TRUE initially in AP mode ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 29 2011 eddie.chen ++ * [WCXRP00000608] [MT6620 Wi-Fi][DRV] Change wmm parameters in beacon ++ * Change wmm parameters in beacon. ++ * ++ * 03 29 2011 yuche.tsai ++ * [WCXRP00000607] [Volunteer Patch][MT6620][Driver] Coding Style Fix for klocwork scan. ++ * Fix klocwork issue. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 11 2011 chinglan.wang ++ * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. ++ * . ++ * ++ * 03 03 2011 george.huang ++ * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated ++ * . ++ * ++ * 03 03 2011 george.huang ++ * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated ++ * modify to handle if beacon MSDU been released when BSS deactivated ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 12 2011 yuche.tsai ++ * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. ++ * bss should create station record type according to callers input. ++ * ++ * 02 11 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * In p2p link function, check networktype before calling p2p function. ++ * ++ * 02 11 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Modify p2p link function to avoid assert. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 25 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Fix the compile error in windows. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 24 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * .Fix typo and missing entry ++ * ++ * 12 30 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Fix prBssInfo->aucCWminLog to prBssInfo->aucCWminLogForBcast ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Before composing Beacon IE, assign network type index for msdu info, ++ * this information is needed by RLM module while composing some RLM related IE field. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Fix undefined pucDestAddr in bssUpdateBeaconContent() ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add support to RX probe response for P2P. ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) bugfix: do not stop timer for join after switched into normal_tr state, for providing chance for DHCP handshasking ++ * 2) modify rsnPerformPolicySelection() invoking ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error while enable WIFI_DIRECT support. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct when ADHOC support is turned on. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fix compilation error when WIFI_DIRECT is turned on ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update bssProcessProbeRequest() to avoid redundant SSID IE {0,0} for IOT. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Use TX MGMT Frame API for sending PS NULL frame to avoid the TX Burst Mechanism in TX FW Frame API ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Separate Beacon and ProbeResp IE array ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed the use of compiling flag MQM_WMM_PARSING ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 20 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Fix restart Beacon Timeout Func after connection diagnosis ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the protected bit at cap info for ad-hoc. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename the CFG flags ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Update outgoing beacon's TX data rate ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add DTIM count update while TX Beacon ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify code due to define - BAND_24G and specific BSS_INFO_T was changed ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++APPEND_VAR_IE_ENTRY_T txBcnIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE}, /* 221 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++ {0, p2pFuncCalculateExtra_IELenForBeacon, p2pFuncGenerateExtra_IEForBeacon}, /* 221 */ ++#else ++ {0, p2pFuncCalculateP2p_IELenForBeacon, p2pFuncGenerateP2p_IEForBeacon}, /* 221 */ ++ {0, p2pFuncCalculateWSC_IELenForBeacon, p2pFuncGenerateWSC_IEForBeacon}, /* 221 */ ++ {0, p2pFuncCalculateP2P_IE_NoA, p2pFuncGenerateP2P_IE_NoA}, /* 221 */ ++#endif ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txProbRspIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ ++}; ++ ++#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines for all Operation Modes */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will create or reset a STA_RECORD_T by given BSS_DESC_T for ++* Infrastructure or AdHoc Mode. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eStaType Assign STA Type for this STA_RECORD_T ++* @param[in] eNetTypeIndex Assign Net Type Index for this STA_RECORD_T ++* @param[in] prBssDesc Received Beacon/ProbeResp from this STA ++* ++* @retval Pointer to STA_RECORD_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T ++bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_STA_TYPE_T eStaType, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucNonHTPhyTypeSet; ++ ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> Get a valid STA_RECORD_T */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); ++ if (!prStaRec) { ++ ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) eNetTypeIndex); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ ++ if (!prStaRec) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ ASSERT(prStaRec); ++ ++ prStaRec->ucStaState = STA_STATE_1; ++ prStaRec->ucJoinFailureCount = 0; ++ /* TODO(Kevin): If this is an old entry, we may also reset the ucJoinFailureCount to 0. ++ */ ++ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prBssDesc->aucSrcAddr); ++ } ++ /* 4 <2> Setup STA TYPE and NETWORK */ ++ prStaRec->eStaType = eStaType; ++ ++ prStaRec->ucNetTypeIndex = eNetTypeIndex; ++ ++ /* 4 <3> Update information from BSS_DESC_T to current P_STA_RECORD_T */ ++ prStaRec->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ prStaRec->u2OperationalRateSet = prBssDesc->u2OperationalRateSet; ++ prStaRec->u2BSSBasicRateSet = prBssDesc->u2BSSBasicRateSet; ++ ++ prStaRec->ucPhyTypeSet = prBssDesc->ucPhyTypeSet; ++ if (IS_STA_IN_AIS(prStaRec)) { ++ if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) || ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_KEY_ABSENT) || ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION_DISABLED) || ++ (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) || (prAdapter->prGlueInfo->u2WapiAssocInfoIESz))) { ++ DBGLOG(BSS, TRACE, "Ignore the HT Bit for TKIP as pairwise cipher configured!\n"); ++ prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; ++ } ++ } else { ++ DBGLOG(BSS, TRACE, "P2P skip TKIP limitation for HT Hit!\n"); ++ } ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ ++ ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; ++ ++ /* Check for Target BSS's non HT Phy Types */ ++ if (ucNonHTPhyTypeSet) { ++ ++ if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = TRUE; ++ } else { ++ /* Use mandatory for 11N only BSS */ ++ ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); ++ ++ { ++ /* TODO(Kevin): which value should we set for 11n ? ERP ? */ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = FALSE; ++ } ++ ++ /* Update non HT Desired Rate Set */ ++ { ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prStaRec->u2DesiredNonHTRateSet = ++ (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); ++ } ++ ++ /* 4 <4> Update information from BSS_DESC_T to current P_STA_RECORD_T */ ++ if (IS_AP_STA(prStaRec)) { ++ /* do not need to parse IE for DTIM, ++ * which have been parsed before inserting into BSS_DESC_T ++ */ ++ if (prBssDesc->ucDTIMPeriod) ++ prStaRec->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ else ++ prStaRec->ucDTIMPeriod = 0; /* Means that TIM was not parsed. */ ++ } ++ /* 4 <5> Update default value */ ++ prStaRec->fgDiagnoseConnection = FALSE; ++ ++ /* 4 <6> Update default value for other Modules */ ++ /* Determine fgIsWmmSupported and fgIsUapsdSupported in STA_REC */ ++ mqmProcessScanResult(prAdapter, prBssDesc, prStaRec); ++ ++ return prStaRec; ++ ++} /* end of bssCreateStaRecFromBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Null Data frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec) ++{ ++ P_WLAN_MAC_HEADER_T prNullFrame; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo); ++ ++ prNullFrame = (P_WLAN_MAC_HEADER_T) pucBuffer; ++ ++ /* 4 <1> Decide the Frame Control Field */ ++ u2FrameCtrl = MAC_FRAME_NULL; ++ ++ if (IS_AP_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_TO_DS; ++ ++ if (prStaRec->fgSetPwrMgtBit) ++ u2FrameCtrl |= MASK_FC_PWR_MGT; ++ } else if (IS_CLIENT_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_FROM_DS; ++ } else if (IS_DLS_STA(prStaRec)) { ++ /* TODO(Kevin) */ ++ } else { ++ /* NOTE(Kevin): We won't send Null frame for IBSS */ ++ ASSERT(0); ++ return; ++ } ++ ++ /* 4 <2> Compose the Null frame */ ++ /* Fill the Frame Control field. */ ++ /* WLAN_SET_FIELD_16(&prNullFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Address 1 field with Target Peer Address. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr1, prStaRec->aucMacAddr); ++ ++ /* Fill the Address 2 field with our MAC Address. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); ++ ++ /* Fill the Address 3 field with Target BSSID. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr3, prBssInfo->aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prNullFrame->u2SeqCtrl = 0; ++ ++ return; ++ ++} /* end of bssComposeNullFrameHeader() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the QoS Null Data frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* @param[in] ucUP User Priority. ++* @param[in] fgSetEOSP Set the EOSP bit. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP) ++{ ++ P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2QosControl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo); ++ ++ prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) pucBuffer; ++ ++ /* 4 <1> Decide the Frame Control Field */ ++ u2FrameCtrl = MAC_FRAME_QOS_NULL; ++ ++ if (IS_AP_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_TO_DS; ++ ++ if (prStaRec->fgSetPwrMgtBit) ++ u2FrameCtrl |= MASK_FC_PWR_MGT; ++ } else if (IS_CLIENT_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_FROM_DS; ++ } else if (IS_DLS_STA(prStaRec)) { ++ /* TODO(Kevin) */ ++ } else { ++ /* NOTE(Kevin): We won't send QoS Null frame for IBSS */ ++ ASSERT(0); ++ return; ++ } ++ ++ /* 4 <2> Compose the QoS Null frame */ ++ /* Fill the Frame Control field. */ ++ /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prQoSNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Address 1 field with Target Peer Address. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr1, prStaRec->aucMacAddr); ++ ++ /* Fill the Address 2 field with our MAC Address. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); ++ ++ /* Fill the Address 3 field with Target BSSID. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr3, prBssInfo->aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prQoSNullFrame->u2SeqCtrl = 0; ++ ++ u2QosControl = (UINT_16) (ucUP & WMM_QC_UP_MASK); ++ ++ if (fgSetEOSP) ++ u2QosControl |= WMM_QC_EOSP; ++ /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2QosCtrl, u2QosControl); */ ++ prQoSNullFrame->u2QosCtrl = u2QosControl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ return; ++ ++} /* end of bssComposeQoSNullFrameHeader() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the Null Frame ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Succe]ss. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeNullFrame(prAdapter, (PUINT_8) ((ULONG) prMsduInfo->prPacket + MAC_TX_RESERVED_FIELD), prStaRec); ++#if 0 ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ TXM_SET_DATA_PACKET( ++ /* STA_REC ptr */ prStaRec, ++ /* MSDU_INFO ptr */ prMsduInfo, ++ /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), ++ /* MAC HDR length */ WLAN_MAC_HEADER_LEN, ++ /* PAYLOAD ptr */ ++ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN), ++ /* PAYLOAD length */ 0, ++ /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, ++ /* TID */ 0 /* BE: AC1 */ , ++ /* Flag 802.11 */ TRUE, ++ /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , ++ /* Resource TC */ 0 /* Irrelevant */ , ++ /* Flag 802.1x */ FALSE, ++ /* TX-done callback */ pfTxDoneHandler, ++ /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, ++ /* PS Session ID */ 0 /* Irrelevant */ , ++ /* Flag fixed rate */ TRUE, ++ /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, ++ /* Fixed-rate retry */ BSS_DEFAULT_CONN_TEST_NULL_FRAME_RETRY_LIMIT, ++ /* PAL LLH */ 0 /* Irrelevant */ , ++ /* ACL SN */ 0 /* Irrelevant */ , ++ /* Flag No Ack */ FALSE ++ ); ++ ++ /* Terminate with a NULL pointer */ ++ NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* Indicate the packet to TXM */ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ txmSendFwDataPackets(prMsduInfo); ++#endif ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendNullFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the QoS Null Frame ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeQoSNullFrame(prAdapter, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec, ucUP, FALSE); ++#if 0 ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ TXM_SET_DATA_PACKET( ++ /* STA_REC ptr */ prStaRec, ++ /* MSDU_INFO ptr */ prMsduInfo, ++ /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), ++ /* MAC HDR length */ WLAN_MAC_HEADER_QOS_LEN, ++ /* PAYLOAD ptr */ ++ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN), ++ /* PAYLOAD length */ 0, ++ /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, ++ /* TID */ 0 /* BE: AC1 */ , ++ /* Flag 802.11 */ TRUE, ++ /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , ++ /* Resource TC */ 0 /* Irrelevant */ , ++ /* Flag 802.1x */ FALSE, ++ /* TX-done callback */ pfTxDoneHandler, ++ /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, ++ /* PS Session ID */ 0 /* Irrelevant */ , ++ /* Flag fixed rate */ TRUE, ++ /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, ++ /* Fixed-rate retry */ TXM_DEFAULT_DATA_FRAME_RETRY_LIMIT, ++ /* PAL LLH */ 0 /* Irrelevant */ , ++ /* ACL SN */ 0 /* Irrelevant */ , ++ /* Flag No Ack */ FALSE ++ ); ++ ++ /* Terminate with a NULL pointer */ ++ NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* Indicate the packet to TXM */ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ txmSendFwDataPackets(prMsduInfo); ++#endif ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendQoSNullFrame() */ ++ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++/*----------------------------------------------------------------------------*/ ++/* Routines for both IBSS(AdHoc) and BSS(AP) */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate Information Elements of Extended ++* Support Rate ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ PUINT_8 pucBuffer; ++ UINT_8 ucExtSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); ++ ASSERT(prBssInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ++ ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; ++ else ++ ucExtSupRatesLen = 0; ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &prBssInfo->aucAllSupportedRates[ELEM_MAX_LEN_SUP_RATES], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* end of bssGenerateExtSuppRate_IE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Beacon ++* or Probe Response Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr) ++{ ++ PUINT_8 pucBuffer; ++ UINT_8 ucSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prBssInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ /* Compose the frame body of the Probe Response frame. */ ++ /* 4 <1> Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ if (prBssInfo->eHiddenSsidType == ENUM_HIDDEN_SSID_LEN) { ++ if ((!pucDestAddr) && /* For Beacon only */ ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ SSID_IE(pucBuffer)->ucLength = 0; ++ } else { /* Probe response */ ++ SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; ++ if (prBssInfo->ucSSIDLen) ++ kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ } ++ } else { ++ SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; ++ if (prBssInfo->ucSSIDLen) ++ kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ } ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ /* 4 <2> Fill the Supported Rates element. */ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ++ ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; ++ else ++ ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; ++ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <3> Fill the DS Parameter Set element. */ ++ if (prBssInfo->eBand == BAND_2G4) { ++ DS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_DS_PARAM_SET; ++ DS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_DS_PARAMETER_SET; ++ DS_PARAM_IE(pucBuffer)->ucCurrChnl = prBssInfo->ucPrimaryChannel; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <4> IBSS Parameter Set element, ID: 6 */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ IBSS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_IBSS_PARAM_SET; ++ IBSS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_IBSS_PARAMETER_SET; ++ WLAN_SET_FIELD_16(&(IBSS_PARAM_IE(pucBuffer)->u2ATIMWindow), prBssInfo->u2ATIMWindow); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <5> TIM element, ID: 5 */ ++ if ((!pucDestAddr) && /* For Beacon only. */ ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*no fgIsP2PRegistered protect */ ++ if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++#if 0 ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ UINT_8 ucBitmapControl = 0; ++ UINT_32 u4N1, u4N2; ++ ++ prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); ++ ++ /* Clear existing value. */ ++ prP2pSpecificBssInfo->ucBitmapCtrl = 0; ++ kalMemZero(prP2pSpecificBssInfo->aucPartialVirtualBitmap, ++ sizeof(prP2pSpecificBssInfo->aucPartialVirtualBitmap)); ++ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucDTIMCount = prBssInfo->ucDTIMCount; ++ TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; ++ ++ /* Setup DTIM Count for next TBTT. */ ++ if (prBssInfo->ucDTIMCount == 0) { ++ /*Do nothing*/ ++ /* 3 *** pmQueryBufferedBCAST(); */ ++ } ++ /* 3 *** pmQueryBufferedPSNode(); */ ++ /* TODO(Kevin): Call PM Module here to loop all STA_RECORD_Ts and it ++ * will call bssSetTIMBitmap to toggle the Bitmap. ++ */ ++ ++ /* Set Virtual Bitmap for UCAST */ ++ u4N1 = (prP2pSpecificBssInfo->u2SmallestAID >> 4) << 1; /* Find the largest even number. */ ++ u4N2 = prP2pSpecificBssInfo->u2LargestAID >> 3; /* Find the smallest number. */ ++ ++ ASSERT(u4N2 >= u4N1); ++ ++ kalMemCopy(TIM_IE(pucBuffer)->aucPartialVirtualMap, ++ &prP2pSpecificBssInfo->aucPartialVirtualBitmap[u4N1], ((u4N2 - u4N1) + 1)); ++ ++ /* Set Virtual Bitmap for BMCAST */ ++ /* BMC bit only indicated when DTIM count == 0. */ ++ if (prBssInfo->ucDTIMCount == 0) ++ ucBitmapControl = prP2pSpecificBssInfo->ucBitmapCtrl; ++ TIM_IE(pucBuffer)->ucBitmapControl = ucBitmapControl | (UINT_8) u4N1; ++ ++ TIM_IE(pucBuffer)->ucLength = ((u4N2 - u4N1) + 4); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++#else ++ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP); /*((u4N2 - u4N1) + 4) */ ++ /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0; /*prBssInfo->ucDTIMCount */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; ++ /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucBitmapControl = 0; /*ucBitmapControl | (UINT_8)u4N1 */ ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ ++#endif ++ ++ } else ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ { ++ /* NOTE(Kevin): 1. AIS - Didn't Support AP Mode. ++ * 2. BOW - Didn't Support BCAST and PS. ++ */ ++ } ++ ++ } ++ ++} /* end of bssBuildBeaconProbeRespFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Beacon/Probe Response frame header and ++* its fixed fields. ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. ++* @param[in] pucOwnMACAddress Given Our MAC Address. ++* @param[in] pucBSSID Given BSSID of the BSS. ++* @param[in] u2BeaconInterval Given Beacon Interval. ++* @param[in] u2CapInfo Given Capability Info. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN PUINT_8 pucDestAddr, ++ IN PUINT_8 pucOwnMACAddress, ++ IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo) ++{ ++ P_WLAN_BEACON_FRAME_T prBcnProbRspFrame; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ UINT_16 u2FrameCtrl; ++ ++ DEBUGFUNC("bssComposeBeaconProbeRespFrameHeaderAndFF"); ++ /* DBGLOG(INIT, LOUD, ("\n")); */ ++ ++ ASSERT(pucBuffer); ++ ASSERT(pucOwnMACAddress); ++ ASSERT(pucBSSID); ++ ++ prBcnProbRspFrame = (P_WLAN_BEACON_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Beacon /ProbeResp frame. */ ++ /* Fill the Frame Control field. */ ++ if (pucDestAddr) { ++ u2FrameCtrl = MAC_FRAME_PROBE_RSP; ++ } else { ++ u2FrameCtrl = MAC_FRAME_BEACON; ++ pucDestAddr = aucBCAddr; ++ } ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prBcnProbRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with BCAST MAC ADDR or TA of ProbeReq. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucDestAddr, pucDestAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucSrcAddr, pucOwnMACAddress); ++ ++ /* Fill the BSSID field with current BSSID. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucBSSID, pucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prBcnProbRspFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the Beacon /ProbeResp frame. */ ++ /* MAC will update TimeStamp field */ ++ ++ /* Fill the Beacon Interval field. */ ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2BeaconInterval, u2BeaconInterval); */ ++ prBcnProbRspFrame->u2BeaconInterval = u2BeaconInterval; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Capability Information field. */ ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2CapInfo, u2CapInfo); */ ++ prBcnProbRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of bssComposeBeaconProbeRespFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the Beacon Frame Template to FW for AIS AdHoc and P2P GO. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eNetTypeIndex Specify which network reply the Probe Response. ++* ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_WLAN_BEACON_FRAME_T prBcnFrame; ++ UINT_32 i; ++ ++ DEBUGFUNC("bssUpdateBeaconContent"); ++ DBGLOG(BSS, LOUD, "\n"); ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Beacon Frame */ ++ /* Allocate a MSDU_INFO_T */ ++ /* For Beacon */ ++ prMsduInfo = prBssInfo->prBeacon; ++ ++ /* beacon prMsduInfo will be NULLify once BSS deactivated, so skip if it is */ ++ if (prMsduInfo == NULL) ++ return WLAN_STATUS_SUCCESS; ++ /* 4 <2> Compose header */ ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ NULL, ++ prBssInfo->aucOwnMacAddr, ++ prBssInfo->aucBSSID, ++ prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); ++ ++ prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); ++ ++ prMsduInfo->ucNetworkType = eNetTypeIndex; ++ ++ /* 4 <3> Compose the frame body's Common IEs of the Beacon frame. */ ++ bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, NULL); ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE for Beacon */ ++ for (i = 0; i < sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txBcnIETable[i].pfnAppendIE) ++ txBcnIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; ++ ++ return nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ eNetTypeIndex, ++ prBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); ++ ++} /* end of bssUpdateBeaconContent() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the Beacon Frame(for BOW) or Probe Response Frame according to the given ++* Destination Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eNetTypeIndex Specify which network reply the Probe Response. ++* @param[in] pucDestAddr Pointer to the Destination Address to reply ++* @param[in] u4ControlFlags Control flags for information on Probe Response. ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedFixedIELen; ++ UINT_16 u2EstimatedExtraIELen; ++ P_APPEND_VAR_IE_ENTRY_T prIeArray = NULL; ++ UINT_32 u4IeArraySize = 0; ++ UINT_32 i; ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (!pucDestAddr) { /* For Beacon */ ++ prIeArray = &txBcnIETable[0]; ++ u4IeArraySize = sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ } else { ++ prIeArray = &txProbRspIETable[0]; ++ u4IeArraySize = sizeof(txProbRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ } ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Beacon /Probe Response Frame */ ++ /* Allocate a MSDU_INFO_T */ ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Fields */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + ++ BEACON_INTERVAL_FIELD_LEN + ++ CAP_INFO_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_IBSS_PARAMETER_SET) + (ELEM_HDR_LEN + (3 + MAX_LEN_TIM_PARTIAL_BMP)); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < u4IeArraySize; i++) { ++ u2EstimatedFixedIELen = prIeArray[i].u2EstimatedFixedIELen; ++ ++ if (u2EstimatedFixedIELen) { ++ u2EstimatedExtraIELen += u2EstimatedFixedIELen; ++ } else { ++ ASSERT(prIeArray[i].pfnCalculateVariableIELen); ++ ++ u2EstimatedExtraIELen += (UINT_16) ++ prIeArray[i].pfnCalculateVariableIELen(prAdapter, eNetTypeIndex, NULL); ++ } ++ } ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending %s.\n", ((!pucDestAddr) ? "Beacon" : "Probe Response")); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Beacon/Probe Response frame header and fixed fields in MSDU_INfO_T. */ ++ /* Compose Header and Fixed Field */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (u4ControlFlags & BSS_PROBE_RESP_USE_P2P_DEV_ADDR) { ++ if (prAdapter->fgIsP2PRegistered) { ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prMsduInfo->prPacket) + ++ MAC_TX_RESERVED_FIELD), pucDestAddr, ++ prAdapter->rWifiVar.aucDeviceAddress, ++ prAdapter->rWifiVar.aucDeviceAddress, ++ DOT11_BEACON_PERIOD_DEFAULT, ++ (prBssInfo->u2CapInfo & ++ ~(CAP_INFO_ESS | CAP_INFO_IBSS))); ++ } ++ } else ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ { ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucDestAddr, prBssInfo->aucOwnMacAddr, prBssInfo->aucBSSID, ++ prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); ++ } ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = 0xFF; ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's Common IEs of the Beacon/ProbeResp frame. */ ++ bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, pucDestAddr); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE */ ++ for (i = 0; i < u4IeArraySize; i++) { ++ if (prIeArray[i].pfnAppendIE) ++ prIeArray[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Beacon /Probe Response frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendBeaconProbeResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Probe Request Frame and then send ++* back the corresponding Probe Response Frame if the specified conditions ++* were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ BOOLEAN fgIsBcBssid; ++ BOOLEAN fgReplyProbeResp; ++ UINT_32 u4CtrlFlagsForProbeResp = 0; ++ ENUM_BAND_T eBand; ++ UINT_8 ucHwChannelNum; ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> Parse Probe Req and Get BSSID */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ if (EQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID)) ++ fgIsBcBssid = TRUE; ++ else ++ fgIsBcBssid = FALSE; ++ ++ /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ ++ for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { ++ ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ continue; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if ((!fgIsBcBssid) && UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) ++ continue; ++ ++ eBand = HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr); ++ ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); ++ ++ if (prBssInfo->eBand != eBand) ++ continue; ++ ++ if (prBssInfo->ucPrimaryChannel != ucHwChannelNum) ++ continue; ++ ++ fgReplyProbeResp = FALSE; ++ ++ if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { ++ ++#if CFG_SUPPORT_ADHOC ++ fgReplyProbeResp = aisValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++#endif ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex)) { ++ if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { ++ /* Resource margin is enough */ ++ fgReplyProbeResp = ++ p2pFuncValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++ } ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) ++ fgReplyProbeResp = bowValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++#endif ++ ++ if (fgReplyProbeResp) { ++ if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { ++ /* Resource margin is enough */ ++ bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr, ++ u4CtrlFlagsForProbeResp); ++ } ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssProcessProbeRequest() */ ++ ++#if 0 /* NOTE(Kevin): condition check should move to P2P_FSM.c */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Probe Request Frame and then send ++* back the corresponding Probe Response Frame if the specified conditions ++* were matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ BOOLEAN fgReplyProbeResp; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgP2PTargetDeviceFound; ++ UINT_8 aucP2PWildcardSSID[] = P2P_WILDCARD_SSID; ++#endif ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> Parse Probe Req and Get SSID IE ptr */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((UINT_32) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ prIeSsid = (P_IE_SSID_T) NULL; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SUP_RATES) { */ ++ if (IE_LEN(pucIE) <= RATE_NUM) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* TODO: P2P IE & WCS IE parsing for P2P. */ ++ case ELEM_ID_P2P: ++ ++ break; ++#endif ++ ++ /* no default */ ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ ++ for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { ++ ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ continue; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (UNEQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID) && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { ++ /* BSSID not Wildcard BSSID. */ ++ continue; ++ } ++ ++ fgReplyProbeResp = FALSE; ++ ++ if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ ++ /* TODO(Kevin): Check if we are IBSS Master. */ ++ if (TRUE && prIeSsid) { ++ if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex) { ++ ++ /* TODO(Kevin): Move following lines to p2p_fsm.c */ ++ ++ if ((prIeSsid) && ++ ((prIeSsid->ucLength == BC_SSID_LEN) || ++ (EQUAL_SSID(aucP2PWildcardSSID, ++ P2P_WILDCARD_SSID_LEN, prIeSsid->aucSSID, prIeSsid->ucLength)))) { ++ /* if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prMgtHdr->aucSrcAddr, ++ pucIE, u2IELength)) { */ ++ if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prSwRfb)) { ++ /* Extand channel request time & cancel scan request. */ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ /* TODO: RX probe request may not caused by LISTEN state. */ ++ /* TODO: It can be GO. */ ++ /* Generally speaking, cancel a non-exist scan request is fine. ++ * We can check P2P FSM here for only LISTEN state. ++ */ ++ ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ /* Abort JOIN process. */ ++ prScanCancelMsg = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ ASSERT(0); /* Can't abort SCN FSM */ ++ continue; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucSeqNum = prP2pFsmInfo->ucSeqNumOfScnMsg; ++ prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ prScanCancelMsg->fgIsChannelExt = TRUE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); ++ } ++ } else { ++ /* 1. Probe Request without SSID. ++ * 2. Probe Request with SSID not Wildcard SSID & not P2P Wildcard SSID. ++ */ ++ continue; ++ } ++ ++#if 0 /* Frog */ ++ if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_LISTEN) { ++ /* P2P 2.4.1 - P2P Devices shall not respond to Probe Request frames ++ which only contain 11b rates only. */ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ UINT_16 u2OperationalRateSet, u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, ++ &u2OperationalRateSet, ++ &u2BSSBasicRateSet, /* Ignore any Basic Bit */ ++ &fgIsUnknownBssBasicRate); ++ ++ if (u2OperationalRateSet & ~RATE_SET_HR_DSSS) ++ continue; ++ } ++ } ++ /* TODO: Check channel time before first check point to: */ ++ /* If Target device is selected: ++ * 1. Send XXXX request frame. ++ * else ++ * 1. Send Probe Response frame. ++ */ ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* TODO(Kevin): During PROVISION state, can we reply Probe Response ? */ ++ ++ /* TODO(Kevin): ++ * If we are GO, accept legacy client --> accept Wildcard SSID ++ * If we are in Listen State, accept only P2P Device --> check P2P IE and WPS IE ++ */ ++ if (TRUE /* We are GO */ && prIeSsid) { ++ UINT_8 aucSSID[] = P2P_WILDCARD_SSID; ++ ++ if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength) || ++ EQUAL_SSID(aucSSID, P2P_WILDCARD_SSID_LEN, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++/* else if (FALSE) { */ /* We are in Listen State */ ++/* } */ ++ ++ /* TODO(Kevin): Check P2P IE and WPS IE */ ++ } ++#endif ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) { ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* Do nothing */ ++ /* TODO(Kevin): TBD */ ++ } ++ } ++#endif ++ else ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ if (fgReplyProbeResp) ++ bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr); ++ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssProcessProbeRequest() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to clear the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prPeerStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prPeerStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ cnmStaRecChangeState(prAdapter, prPeerStaRec, STA_STATE_1); ++ } ++ ++ LINK_INITIALIZE(prStaRecOfClientList); ++ } ++ ++} /* end of bssClearClientList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to Add a STA_RECORD_T to the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ ++ if (prCurrStaRec == prStaRec) { ++ DBGLOG(BSS, WARN, ++ "Current Client List already contains that STA_RECORD_T[%pM]\n", ++ prStaRec->aucMacAddr); ++ return; ++ } ++ } ++ } ++ ++ LINK_INSERT_TAIL(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ ++} /* end of bssAddStaRecToClientList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to Remove a STA_RECORD_T from the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++#if 0 ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ ++ if (prCurrStaRec == prStaRec) { ++ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ ++ return; ++ } ++ } ++ } ++#endif ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ return; ++ } ++ } ++ } ++ ++ DBGLOG(BSS, INFO, "Current Client List didn't contain that STA_RECORD_T[%pM] before removing.\n", ++ prStaRec->aucMacAddr); ++ ++} /* end of bssRemoveStaRecFromClientList() */ ++#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get station record by Address for AP mode ++* ++* @param[in] prBssInfo Pointer to BSS_INFO_T. ++* @param[in] pucMacAddr Pointer to target mac address ++* ++* @return pointer of STA_RECORD_T if found, otherwise, return NULL ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ASSERT(pucMacAddr); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, pucMacAddr)) ++ return prCurrStaRec; ++ } ++ } ++ return NULL; ++} ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/* Routines for IBSS(AdHoc) only */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to process Beacons from current Ad-Hoc network peers. ++* We also process Beacons from other Ad-Hoc network during SCAN. If it has ++* the same SSID and we'll decide to merge into it if it has a larger TSF. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] prBSSDesc Pointer to the BSS Descriptor. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI) ++{ ++ P_STA_RECORD_T prStaRec = NULL; ++ ++ BOOLEAN fgIsCheckCapability = FALSE; ++ BOOLEAN fgIsCheckTSF = FALSE; ++ BOOLEAN fgIsGoingMerging = FALSE; ++ BOOLEAN fgIsSameBSSID; ++ ++ ASSERT(prBssInfo); ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> Process IBSS Beacon only after we create or merge with other IBSS. */ ++ if (!prBssInfo->fgIsBeaconActivated) ++ return; ++ /* 4 <2> Get the STA_RECORD_T of TA. */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prBssDesc->aucSrcAddr); ++ ++ fgIsSameBSSID = UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID) ? FALSE : TRUE; ++ ++ /* 4 <3> IBSS Merge Decision Flow for Processing Beacon. */ ++ if (fgIsSameBSSID) { ++ ++ /* Same BSSID: ++ * Case I. This is a new TA and it has decide to merged with us. ++ * a) If fgIsMerging == FALSE - we will send msg to notify AIS. ++ * b) If fgIsMerging == TRUE - already notify AIS. ++ * Case II. This is an old TA and we've already merged together. ++ */ ++ if (!prStaRec) { ++ ++ /* For Case I - Check this IBSS's capability first before adding this Sta Record. */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, then we perform merging with this new IBSS */ ++ fgIsGoingMerging = TRUE; ++ ++ } else { ++ ++ ASSERT((prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) && IS_ADHOC_STA(prStaRec)); ++ ++ if (prStaRec->ucStaState != STA_STATE_3) { ++ ++ if (!prStaRec->fgIsMerging) { ++ ++ /* For Case I - Check this IBSS's capability first ++ * before adding this Sta Record. */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, then we perform merging with this new IBSS */ ++ fgIsGoingMerging = TRUE; ++ } else { ++ /* For Case II - Update rExpirationTime of Sta Record */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ } ++ } else { ++ /* For Case II - Update rExpirationTime of Sta Record */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ } ++ ++ } ++ } else { ++ ++ /* Unequal BSSID: ++ * Case III. This is a new TA and we need to compare the TSF and get the winner. ++ * Case IV. This is an old TA and it merge into a new IBSS before we do the same thing. ++ * We need to compare the TSF to get the winner. ++ * Case V. This is an old TA and it restart a new IBSS. We also need to ++ * compare the TSF to get the winner. ++ */ ++ ++ /* For Case III, IV & V - We'll always check this new IBSS's capability first ++ * before merging into new IBSS. ++ */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, we need to perform TSF check to decide the major BSSID */ ++ fgIsCheckTSF = TRUE; ++ ++ /* For Case IV & V - We won't update rExpirationTime of Sta Record */ ++ } ++ ++ /* 4 <7> Check this BSS_DESC_T's capability. */ ++ if (fgIsCheckCapability) { ++ BOOLEAN fgIsCapabilityMatched = FALSE; ++ ++ do { ++ if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Unsupported Phy.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ if (prBssDesc->fgIsUnknownBssBasicRate) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Unknown Basic Rate.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ fgIsCapabilityMatched = TRUE; ++ } while (FALSE); ++ ++ if (!fgIsCapabilityMatched) { ++ ++ if (prStaRec) { ++ /* For Case II - We merge this STA_RECORD in RX Path. ++ * Case IV & V - They change their BSSID after we merge with them. ++ */ ++ ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", ++ prBssDesc->aucSrcAddr); ++ } ++ ++ return; ++ } ++ ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Peer MAC: %pM - Check capability was passed.\n", ++ prBssDesc->aucSrcAddr); ++ } ++ ++ if (fgIsCheckTSF) { ++#if CFG_SLT_SUPPORT ++ fgIsGoingMerging = TRUE; ++#else ++ if (prBssDesc->fgIsLargerTSF) ++ fgIsGoingMerging = TRUE; ++ else ++ return; ++#endif ++ } ++ ++ if (fgIsGoingMerging) { ++ P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; ++ ++ /* 4 <1> We will merge with to this BSS immediately. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ prBssDesc->fgIsConnected = FALSE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, ++ STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ ++ if (!prStaRec) { ++ /* no memory ? */ ++ return; ++ } ++ ++ prStaRec->fgIsMerging = TRUE; ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = ucRCPI; ++ ++ /* 4 <3> Send Merge Msg to CNM to obtain the channel privilege. */ ++ prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_IBSS_PEER_FOUND_T)); ++ ++ if (!prAisIbssPeerFoundMsg) { ++ ++ ASSERT(0); /* Can't send Merge Msg */ ++ return; ++ } ++ ++ prAisIbssPeerFoundMsg->rMsgHdr.eMsgId = MID_SCN_AIS_FOUND_IBSS; ++ prAisIbssPeerFoundMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ prAisIbssPeerFoundMsg->prStaRec = prStaRec; ++ ++ /* Inform AIS to do STATE TRANSITION ++ * For Case I - If AIS in IBSS_ALONE, let it jump to NORMAL_TR after we know the new member. ++ * For Case III, IV - Now this new BSSID wins the TSF, follow it. ++ */ ++ if (fgIsSameBSSID) { ++ prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; ++ } else { ++#if CFG_SLT_SUPPORT ++ prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; ++#else ++ prAisIbssPeerFoundMsg->fgIsMergeIn = (prBssDesc->fgIsLargerTSF) ? FALSE : TRUE; ++#endif ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisIbssPeerFoundMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++} /* end of ibssProcessMatchedBeacon() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the Capability for Ad-Hoc to decide if we are ++* able to merge with(same capability). ++* ++* @param[in] prBSSDesc Pointer to the BSS Descriptor. ++* ++* @retval WLAN_STATUS_FAILURE Can't pass the check of Capability. ++* @retval WLAN_STATUS_SUCCESS Pass the check of Capability. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prBssDesc); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ do { ++ /* 4 <1> Check the BSS Basic Rate Set for current AdHoc Mode */ ++ if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11B) && ++ (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_HR_DSSS)) { ++ break; ++ } else if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11A) && ++ (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_OFDM)) { ++ break; ++ } ++ /* 4 <2> Check the Short Slot Time. */ ++#if 0 /* Do not check ShortSlotTime until Wi-Fi define such policy */ ++ if (prConnSettings->eAdHocMode == AD_HOC_MODE_11G) { ++ if (((prConnSettings->fgIsShortSlotTimeOptionEnable) && ++ !(prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) || ++ (!(prConnSettings->fgIsShortSlotTimeOptionEnable) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))) { ++ break; ++ } ++ } ++#endif ++ ++ /* 4 <3> Check the ATIM window setting. */ ++ if (prBssDesc->u2ATIMWindow) { ++ DBGLOG(BSS, INFO, "AdHoc PS was not supported(ATIM Window: %d)\n", prBssDesc->u2ATIMWindow); ++ break; ++ } ++#if CFG_RSN_MIGRATION ++ /* 4 <4> Check the Security setting. */ ++ if (!rsnPerformPolicySelection(prAdapter, prBssDesc)) ++ break; ++#endif ++ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rStatus; ++ ++} /* end of ibssCheckCapabilityForAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial the BSS_INFO_T for IBSS Mode. ++* ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++ UINT_8 ucLowestBasicRateIndex; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ PUINT_16 pu2BSSID = (PUINT_16) &aucBSSID[0]; ++ UINT_32 i; ++ ++ ASSERT(prBssInfo); ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_IBSS); ++ ++ /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ ++ /* 4 <2> Setup BSSID */ ++ if (!prBssInfo->fgHoldSameBssidForIBSS) { ++ ++ for (i = 0; i < sizeof(aucBSSID) / sizeof(UINT_16); i++) ++ pu2BSSID[i] = (UINT_16) (kalRandomNumber() & 0xFFFF); ++ ++ aucBSSID[0] &= ~0x01; /* 7.1.3.3.3 - The individual/group bit of the address is set to 0. */ ++ aucBSSID[0] |= 0x02; /* 7.1.3.3.3 - The universal/local bit of the address is set to 1. */ ++ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, aucBSSID); ++ } ++ /* 4 <3> Setup Capability - Short Preamble */ ++ if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 4 <4> Setup Capability - Short Slot Time */ ++ /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ ++ prBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ ++ ++ /* 4 <5> Compoase Capability */ ++ prBssInfo->u2CapInfo = CAP_INFO_IBSS; ++ ++ if (prBssInfo->fgIsProtection) ++ prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; ++ ++ if (prBssInfo->fgIsShortPreambleAllowed) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ ++ if (prBssInfo->fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); ++ ++ prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; ++ ++} /* end of ibssInitForAdHoc() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++#if CFG_SUPPORT_AAA ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for BSS(AP) only */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial the BSS_INFO_T for AP Mode. ++* ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate) ++{ ++ UINT_8 ucLowestBasicRateIndex; ++ ++ P_AC_QUE_PARMS_T prACQueParms; ++ ++ ENUM_WMM_ACI_T eAci; ++ ++ UINT_8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; ++ UINT_8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3 }; ++ UINT_8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; ++ UINT_8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ ++ ++ UINT_8 auCWminLog2[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; ++ UINT_8 auCWmaxLog2[WMM_AC_INDEX_NUM] = { 7, 10, 4, 3 }; ++ UINT_8 auAifs[WMM_AC_INDEX_NUM] = { 3, 7, 1, 1 }; ++ UINT_8 auTxop[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ ++ ++ DEBUGFUNC("bssInitForAP"); ++ DBGLOG(BSS, LOUD, "\n"); ++ ++ ASSERT(prBssInfo); ++ ASSERT((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || (prBssInfo->eCurrentOPMode == OP_MODE_BOW)); ++ ++#if 0 ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = CONFIG_BW_20M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = CONFIG_BW_20M; ++#endif ++ ++ /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ if (fgIsRateUpdate) { ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ } ++ /* 4 <2> Setup BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssInfo->aucOwnMacAddr); ++ ++ /* 4 <3> Setup Capability - Short Preamble */ ++ if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 4 <4> Setup Capability - Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = TRUE; ++ ++ /* 4 <5> Compoase Capability */ ++ prBssInfo->u2CapInfo = CAP_INFO_ESS; ++ ++ if (prBssInfo->fgIsProtection) ++ prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; ++ ++ if (prBssInfo->fgIsShortPreambleAllowed) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ ++ if (prBssInfo->fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); ++ ++ prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; ++ ++ /* 4 <7> Fill the EDCA */ ++ ++ prACQueParms = prBssInfo->arACQueParmsForBcast; ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prACQueParms[eAci].fgIsACMSet = FALSE; ++ prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; ++ prACQueParms[eAci].u2CWmin = BIT(auCWminLog2ForBcast[eAci]) - 1; ++ prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2ForBcast[eAci]) - 1; ++ prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; ++ ++ prBssInfo->aucCWminLog2ForBcast[eAci] = auCWminLog2ForBcast[eAci]; /* used to send WMM IE */ ++ prBssInfo->aucCWmaxLog2ForBcast[eAci] = auCWmaxLog2ForBcast[eAci]; ++ ++ DBGLOG(BSS, INFO, "Bcast: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prACQueParms[eAci].fgIsACMSet, ++ prACQueParms[eAci].u2Aifsn, ++ prACQueParms[eAci].u2CWmin, ++ prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); ++ ++ } ++ ++ prACQueParms = prBssInfo->arACQueParms; ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prACQueParms[eAci].fgIsACMSet = FALSE; ++ prACQueParms[eAci].u2Aifsn = auAifs[eAci]; ++ prACQueParms[eAci].u2CWmin = BIT(auCWminLog2[eAci]) - 1; ++ prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2[eAci]) - 1; ++ prACQueParms[eAci].u2TxopLimit = auTxop[eAci]; ++ ++ DBGLOG(BSS, INFO, "eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prACQueParms[eAci].fgIsACMSet, ++ prACQueParms[eAci].u2Aifsn, ++ prACQueParms[eAci].u2CWmin, ++ prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); ++ } ++ ++ /* Note: Caller should update the EDCA setting to HW by nicQmUpdateWmmParms() it there is no AIS network */ ++ /* Note: In E2, only 4 HW queues. The the Edca parameters should be folow by AIS network */ ++ /* Note: In E3, 8 HW queues. the Wmm parameters should be updated to right queues according to BSS */ ++ ++} /* end of bssInitForAP() */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update DTIM Count ++* ++* @param[in] eNetTypeIndex Specify which network to update ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ ++ /* Setup DTIM Count for next TBTT. */ ++ if (prBssInfo->ucDTIMCount > 0) { ++ prBssInfo->ucDTIMCount--; ++ } else { ++ ++ ASSERT(prBssInfo->ucDTIMPeriod > 0); ++ ++ prBssInfo->ucDTIMCount = prBssInfo->ucDTIMPeriod - 1; ++ } ++ } ++ ++} /* end of bssUpdateDTIMIE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to set the Virtual Bitmap in TIM Information Elements ++* ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] u2AssocId The association id to set in Virtual Bitmap. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId) ++{ ++ ++ ASSERT(prBssInfo); ++ ++ if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); ++ ++ /* Use Association ID == 0 for BMCAST indication */ ++ if (u2AssocId == 0) { ++ ++ prP2pSpecificBssInfo->ucBitmapCtrl |= (UINT_8) BIT(0); ++ } else { ++ PUINT_8 pucPartialVirtualBitmap; ++ UINT_8 ucBitmapToSet; ++ ++ /* (u2AssocId / 8) */ ++ pucPartialVirtualBitmap = &prP2pSpecificBssInfo->aucPartialVirtualBitmap[(u2AssocId >> 3)]; ++ ucBitmapToSet = (UINT_8) BIT((u2AssocId % 8)); ++ ++ if (*pucPartialVirtualBitmap & ucBitmapToSet) { ++ /* The virtual bitmap has been set */ ++ return; ++ } ++ ++ *pucPartialVirtualBitmap |= ucBitmapToSet; ++ ++ /* Update u2SmallestAID and u2LargestAID */ ++ if ((u2AssocId < prP2pSpecificBssInfo->u2SmallestAID) || ++ (prP2pSpecificBssInfo->u2SmallestAID == 0)) { ++ prP2pSpecificBssInfo->u2SmallestAID = u2AssocId; ++ } ++ ++ if ((u2AssocId > prP2pSpecificBssInfo->u2LargestAID) || ++ (prP2pSpecificBssInfo->u2LargestAID == 0)) { ++ prP2pSpecificBssInfo->u2LargestAID = u2AssocId; ++ } ++ } ++ } ++ ++} /* end of bssSetTIMBitmap() */ ++#endif ++ ++#endif /* CFG_SUPPORT_AAA */ ++ ++VOID bssCreateStaRecFromAuth(IN P_ADAPTER_T prAdapter) ++{ ++ ++} ++ ++VOID bssUpdateStaRecFromAssocReq(IN P_ADAPTER_T prAdapter) ++{ ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c +new file mode 100644 +index 000000000000..39af02df2af2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c +@@ -0,0 +1,738 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm.c#2 ++*/ ++ ++/*! \file "cnm.c" ++ \brief Module of Concurrent Network Management ++ ++ Module of Concurrent Network Management ++*/ ++ ++/* ++** Log: cnm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix possible wrong message when P2P is unregistered ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Fix large network type index assert in FW issue. ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 01 2011 cm.chang ++ * [WCXRP00001077] [All Wi-Fi][Driver] Fix wrong preferred channel for AP and BOW ++ * Only check AIS channel for P2P and BOW ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Extension channel of some 5G AP will not follow regulation requirement ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 01 2011 cm.chang ++ * [WCXRP00000937] [MT6620 Wi-Fi][Driver][FW] cnm.c line #848 assert when doing monkey test ++ * Print message only in Linux platform for monkey testing ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Limit AIS to fixed channel same with BOW ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Check if P2P network index is Tethering AP ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 02 17 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * When P2P registried, invoke BOW deactivate function ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Provide function to decide if BSS can be activated or not ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 10 13 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when cmd buffer is not available ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Fix wrong message ID for channel grant to requester ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set 20/40M bandwidth of AP HT OP before association process ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 21 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support TCP/UDP/IP Checksum offload feature ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add a new function to send abort message ++ * ++ * 04 27 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * BMC mac address shall be ignored in basic config command ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support change of MAC address by host command ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix bug for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * use the Rx0 dor event indicate. ++ * ++ * 02 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support partial part about cmd basic configuration ++ * ++ * Dec 10 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove conditional compiling FPGA_V5 ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function cnmFsmEventInit() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in CNM_INFO_T. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmInit(P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of cnmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in CNM_INFO_T. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmUninit(P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of cnmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Before handle the message from other module, it need to obtain ++* the Channel privilege from Channel Manager ++* ++* @param[in] prMsgHdr The message need to be handled. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_CH_REQ_T prMsgChReq; ++ P_CMD_CH_PRIVILEGE_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prMsgChReq = (P_MSG_CH_REQ_T) prMsgHdr; ++ ++ prCmdBody = (P_CMD_CH_PRIVILEGE_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(CNM, ERROR, "ChReq: fail to get buf (net=%d, token=%d)\n", ++ prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChReq net=%d token=%d b=%d c=%d s=%d\n", ++ prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID, ++ prMsgChReq->eRfBand, prMsgChReq->ucPrimaryChannel, prMsgChReq->eRfSco); ++ ++ prCmdBody->ucNetTypeIndex = prMsgChReq->ucNetTypeIndex; ++ prCmdBody->ucTokenID = prMsgChReq->ucTokenID; ++ prCmdBody->ucAction = CMD_CH_ACTION_REQ; /* Request */ ++ prCmdBody->ucPrimaryChannel = prMsgChReq->ucPrimaryChannel; ++ prCmdBody->ucRfSco = (UINT_8) prMsgChReq->eRfSco; ++ prCmdBody->ucRfBand = (UINT_8) prMsgChReq->eRfBand; ++ prCmdBody->ucReqType = (UINT_8) prMsgChReq->eReqType; ++ prCmdBody->ucReserved = 0; ++ prCmdBody->u4MaxInterval = prMsgChReq->u4MaxInterval; ++ COPY_MAC_ADDR(prCmdBody->aucBSSID, prMsgChReq->aucBSSID); ++ ++ ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ /* For monkey testing 20110901 */ ++ if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) ++ DBGLOG(CNM, ERROR, "CNM: ChReq with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_CH_PRIVILEGE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of cnmChMngrRequestPrivilege() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Before deliver the message to other module, it need to release ++* the Channel privilege to Channel Manager. ++* ++* @param[in] prMsgHdr The message need to be delivered ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ P_CMD_CH_PRIVILEGE_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) prMsgHdr; ++ ++ prCmdBody = (P_CMD_CH_PRIVILEGE_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(CNM, ERROR, "ChAbort: fail to get buf (net=%d, token=%d)\n", ++ prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChAbort net=%d token=%d\n", prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); ++ ++ prCmdBody->ucNetTypeIndex = prMsgChAbort->ucNetTypeIndex; ++ prCmdBody->ucTokenID = prMsgChAbort->ucTokenID; ++ prCmdBody->ucAction = CMD_CH_ACTION_ABORT; /* Abort */ ++ ++ ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ /* For monkey testing 20110901 */ ++ if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) ++ DBGLOG(CNM, ERROR, "CNM: ChAbort with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_CH_PRIVILEGE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of cnmChMngrAbortPrivilege() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_CH_PRIVILEGE_T prEventBody; ++ P_MSG_CH_GRANT_T prChResp; ++ ++ ASSERT(prAdapter); ++ ASSERT(prEvent); ++ ++ prEventBody = (P_EVENT_CH_PRIVILEGE_T) (prEvent->aucBuffer); ++ prChResp = (P_MSG_CH_GRANT_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_GRANT_T)); ++ ASSERT(prChResp); ++ ++ /* To do: exception handle */ ++ if (!prChResp) { ++ DBGLOG(CNM, ERROR, "ChGrant: fail to get buf (net=%d, token=%d)\n", ++ prEventBody->ucNetTypeIndex, prEventBody->ucTokenID); ++ ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChGrant net=%d token=%d ch=%d sco=%d\n", ++ prEventBody->ucNetTypeIndex, prEventBody->ucTokenID, ++ prEventBody->ucPrimaryChannel, prEventBody->ucRfSco); ++ ++ ASSERT(prEventBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ASSERT(prEventBody->ucStatus == EVENT_CH_STATUS_GRANT); ++ ++ /* Decide message ID based on network and response status */ ++ if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_AIS_CH_GRANT; ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (prEventBody->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_P2P_CH_GRANT; ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_BOW_CH_GRANT; ++#endif ++ else { ++ cnmMemFree(prAdapter, prChResp); ++ return; ++ } ++ ++ prChResp->ucNetTypeIndex = prEventBody->ucNetTypeIndex; ++ prChResp->ucTokenID = prEventBody->ucTokenID; ++ prChResp->ucPrimaryChannel = prEventBody->ucPrimaryChannel; ++ prChResp->eRfSco = (ENUM_CHNL_EXT_T) prEventBody->ucRfSco; ++ prChResp->eRfBand = (ENUM_BAND_T) prEventBody->ucRfBand; ++ prChResp->eReqType = (ENUM_CH_REQ_TYPE_T) prEventBody->ucReqType; ++ prChResp->u4GrantInterval = prEventBody->u4GrantInterval; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prChResp, MSG_SEND_METHOD_BUF); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked for P2P or BOW networks ++* ++* @param (none) ++* ++* @return TRUE: suggest to adopt the returned preferred channel ++* FALSE: No suggestion. Caller should adopt its preference ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBand); ++ ASSERT(pucPrimaryChannel); ++ ASSERT(prBssSCO); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (RLM_NET_PARAM_VALID(prBssInfo)) { ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ *prBssSCO = prBssInfo->eBssSCO; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: available channel is limited to return value ++* FALSE: no limited ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) ++{ ++#if CFG_ENABLE_WIFI_DIRECT || (CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL) ++ P_BSS_INFO_T prBssInfo; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { ++ ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ ++ return TRUE; ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ ++ return TRUE; ++ } ++#endif ++ ++ return FALSE; ++} ++ ++#if CFG_P2P_LEGACY_COEX_REVISE ++BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) ++{ ++ P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; ++ P_BSS_INFO_T prP2PBssInfo = &prWifiVar->arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && ++ (prP2PBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || ++ (prP2PBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && prP2PBssInfo->eIntendOPMode == OP_MODE_NUM))) { ++ *prBand = prP2PBssInfo->eBand; ++ *pucPrimaryChannel = prP2PBssInfo->ucPrimaryChannel; ++#if CFG_SUPPORT_MCC ++ if (nicFreq2ChannelNum(prWifiVar->rConnSettings.u4FreqInKHz * 1000) != *pucPrimaryChannel) { ++ DBGLOG(CNM, INFO, "p2p is running on Channel %d, but supplicant try to run as MCC\n", ++ *pucPrimaryChannel); ++ return FALSE; ++ } ++#endif ++ DBGLOG(CNM, INFO, "p2p is running on Channel %d, supplicant try to run as SCC\n", ++ *pucPrimaryChannel); ++ return TRUE; ++ } ++#endif ++ return FALSE; ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter) ++{ ++#if CFG_ENABLE_BT_OVER_WIFI ++ P_BSS_INFO_T prAisBssInfo, prBowBssInfo; ++ ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prBowBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ if (RLM_NET_PARAM_VALID(prAisBssInfo) && RLM_NET_PARAM_VALID(prBowBssInfo)) { ++ if (prAisBssInfo->eBand != prBowBssInfo->eBand || ++ prAisBssInfo->ucPrimaryChannel != prBowBssInfo->ucPrimaryChannel) { ++ ++ /* Notify BOW to do deactivation */ ++ bowNotifyAllLinkDisconnected(prAdapter); ++ } ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter) ++{ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) ++ return FALSE; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) ++ return FALSE; ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) ++ return FALSE; ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { ++ /* Notify BOW to do deactivation */ ++ bowNotifyAllLinkDisconnected(prAdapter); ++ } ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) ++ return FALSE; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) ++ return FALSE; ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 i; ++ P_BSS_DESC_T prBssDesc = NULL; ++ ++ /* Note: To support real-time decision instead of current activated-time, ++ * the STA roaming case shall be considered about synchronization ++ * problem. Another variable fgAssoc40mBwAllowed is added to ++ * represent HT capability when association ++ */ ++ for (i = 0; i < NETWORK_TYPE_INDEX_NUM; i++) { ++ if (i != (UINT_8) eNetTypeIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[i]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && (prBssInfo->fg40mBwAllowed || prBssInfo->fgAssoc40mBwAllowed)) ++ return FALSE; ++ } ++ } ++ ++ if (eNetTypeIdx == NETWORK_TYPE_AIS_INDEX) ++ prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; ++ else if ((eNetTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->rWifiVar.prP2pFsmInfo)) ++ prBssDesc = prAdapter->rWifiVar.prP2pFsmInfo->prTargetBss; ++ if (prBssDesc) { ++#if (CFG_FORCE_USE_20BW == 1) ++ if (prBssDesc->eBand == BAND_2G4) ++ return FALSE; ++#endif ++ if (prBssDesc->eSco == CHNL_EXT_SCN) ++ return FALSE; ++ } ++ ++ return TRUE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c +new file mode 100644 +index 000000000000..05bd0ff35f7a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c +@@ -0,0 +1,1236 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_mem.c#2 ++*/ ++ ++/*! \file "cnm_mem.c" ++ \brief This file contain the management function of packet buffers and ++ generic memory alloc/free functioin for mailbox message. ++ ++ A data packet has a fixed size of buffer, but a management ++ packet can be equipped with a variable size of buffer. ++*/ ++ ++/* ++** Log: cnm_mem.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 14 2012 wh.su ++ * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting ++ * Add code from 2.2 ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * initialize fgNeedResp. ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update SLT Function for QoS Support and not be affected by fixed rate function. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete ++ * and might leads to BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 10 13 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when cmd buffer is not available ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 05 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Fix correct structure size in cnmStaSendDeactivateCmd() ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * spin lock target revised ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change inner loop index from i to k. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support checking of duplicated buffer free ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Modified some MQM-related data structures (SN counter, TX/RX BA table) ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Added new TX/RX BA tables in STA_REC ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Notify MQM, TXM, and RXM upon disconnection . ++ * ++ * 04 26 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Call mqm, txm, rxm functions upon disconnection ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * * * * * * * * and will send Null frame to diagnose connection ++ * ++ * 04 09 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * [BORA00000644] WiFi phase 4 integration ++ * * Added per-TID SN cache in STA_REC ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * move the wlan table alloc / free to change state function. ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support power control ++ * ++ * 03 03 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Initialize StaRec->arStaWaitQueue ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add debug message when no available pkt buffer ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Fixed STA_REC initialization bug: prStaRec->au2CachedSeqCtrl[k] ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsWmmSupported in STA_RECORD_T. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsUapsdSupported in STA_RECORD_T ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * add support of Driver STA_RECORD_T activation ++ * ++ * 02 13 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added arTspecTable in STA_REC for TSPEC management ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable mgmt buffer debug by default ++ * ++ * 02 12 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added BUFFER_SOURCE_BCN ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h ++ * * * * * * * * * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem ++ * * * * * * * * * 3) use cnmMemAlloc() instead to allocate SRAM buffer ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * * * * * * MQM: BA handling ++ * * * * * * * TXM: Macros updates ++ * * * * * * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 24 2009 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support several data buffer banks. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * .For new FPGA memory size ++ * ++ * Dec 9 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed DBGPRINT ++ * ++ * Dec 9 2009 mtk02752 ++ * [BORA00000368] Integrate HIF part into BORA ++ * add cnmDataPktFree() for emulation loopback purpose ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix warning of null pointer ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add cnmGetStaRecByAddress() and add fgIsInUse flag in STA_RECORD_T ++ * ++ * Nov 23 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Assign ucBufferSource in function cnmMgtPktAlloc() ++ * ++ * Nov 23 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added packet redispatch function calls ++ * ++ * Nov 13 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * enable packet re-usable in current emulation driver ++ * ++ * Nov 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * 1. Add new function cnmGetStaRecByIndex() ++ * 2. Rename STA_REC_T to STA_RECORD_T ++ * ++ * Nov 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call cnmDataPktDispatch() in cnmPktFree() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove definition of pragma section code ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Oct 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 8 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf); ++ ++static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp); ++ ++static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T cnmMgtPktAlloc(P_ADAPTER_T prAdapter, UINT_32 u4Length) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_QUE_T prQueList; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; ++ ++ /* Get a free MSDU_INFO_T */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(prQueList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo) { ++ prMsduInfo->prPacket = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ ++ if (prMsduInfo->prPacket == NULL) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo = NULL; ++ } ++ if (prMsduInfo) { ++ prMsduInfo->eCmdType = COMMAND_TYPE_NUM; ++ prMsduInfo->ucCID = 0xff; ++ prMsduInfo->u4InqueTime = 0; ++ prMsduInfo->ucPacketType = TX_PACKET_NUM; ++ } ++ } else { ++ P_QUE_T prTxingQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_TX_TCQ_STATUS_T pTc = (P_TX_TCQ_STATUS_T) NULL; ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ pTc = &(prAdapter->rTxCtrl.rTc); ++ ++ DBGLOG(MEM, LOUD, "++dump TxPendingMsdu=%u, Tc0=%d Tc1=%d Tc2=%d Tc3=%d, Tc4=%d Tc5=%d\n", ++ prTxingQue->u4NumElem, pTc->aucFreeBufferCount[TC0_INDEX], ++ pTc->aucFreeBufferCount[TC1_INDEX], pTc->aucFreeBufferCount[TC2_INDEX], ++ pTc->aucFreeBufferCount[TC3_INDEX], pTc->aucFreeBufferCount[TC4_INDEX], ++ pTc->aucFreeBufferCount[TC5_INDEX]); ++ ++ prQueueEntry = QUEUE_GET_HEAD(prTxingQue); ++ ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ DBGLOG(MEM, LOUD, ++ "msdu type=%u, ucid=%u, type=%d, time=%u, seq=%u, sta=%u\n", ++ prMsduInfo->ucPacketType, ++ prMsduInfo->ucCID, ++ prMsduInfo->eCmdType, ++ prMsduInfo->u4InqueTime, prMsduInfo->ucTxSeqNum, prMsduInfo->ucStaRecIndex); ++ prQueueEntry = QUEUE_GET_NEXT_ENTRY(prQueueEntry); ++ } ++ DBGLOG(MEM, LOUD, "--end dump\n"); ++ } ++ ++#if DBG ++ if (prMsduInfo == NULL) { ++ DBGLOG(MEM, WARN, "MgtDesc#=%u\n", prQueList->u4NumElem); ++ ++#if CFG_DBG_MGT_BUF ++ DBGLOG(MEM, WARN, "rMgtBufInfo: alloc#=%u, free#=%u, null#=%u\n", ++ prAdapter->rMgtBufInfo.u4AllocCount, ++ prAdapter->rMgtBufInfo.u4FreeCount, prAdapter->rMgtBufInfo.u4AllocNullCount); ++#endif ++ ++ DBGLOG(MEM, WARN, "\n"); ++ } ++#endif ++ ++ return prMsduInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMgtPktFree(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_QUE_T prQueList; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; ++ ++ ASSERT(prMsduInfo->prPacket); ++ if (prMsduInfo->prPacket) { ++ cnmMemFree(prAdapter, prMsduInfo->prPacket); ++ prMsduInfo->prPacket = NULL; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo->fgIsBasicRate = FALSE; ++ QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry) ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to initial the MGMT/MSG memory pool. ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMemInit(P_ADAPTER_T prAdapter) ++{ ++ P_BUF_INFO_T prBufInfo; ++ ++ /* Initialize Management buffer pool */ ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ kalMemZero(prBufInfo, sizeof(prAdapter->rMgtBufInfo)); ++ prBufInfo->pucBuf = prAdapter->pucMgtBufCached; ++ ++ /* Setup available memory blocks. 1 indicates FREE */ ++ prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); ++ ++ /* Initialize Message buffer pool */ ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ kalMemZero(prBufInfo, sizeof(prAdapter->rMsgBufInfo)); ++ prBufInfo->pucBuf = &prAdapter->aucMsgBuf[0]; ++ ++ /* Setup available memory blocks. 1 indicates FREE */ ++ prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); ++ ++ return; ++ ++} /* end of cnmMemInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate MGMT/MSG memory pool. ++* ++* \param[in] eRamType Target RAM type. ++* TCM blk_sz= 16bytes, BUF blk_sz= 256bytes ++* \param[in] u4Length Length of the buffer to allocate. ++* ++* \retval !NULL Pointer to the start address of allocated memory. ++* \retval NULL Fail to allocat memory ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4MemAllocCnt = 0, u4MemFreeCnt = 0; ++PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length) ++{ ++ P_BUF_INFO_T prBufInfo; ++ BUF_BITMAP rRequiredBitmap; ++ UINT_32 u4BlockNum; ++ UINT_32 i, u4BlkSzInPower; ++ PVOID pvMemory; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(u4Length); ++ ++ u4MemAllocCnt++; ++ ++ if (eRamType == RAM_TYPE_MSG && u4Length <= 256) { ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ u4BlkSzInPower = MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ u4Length += (MSG_BUF_BLOCK_SIZE - 1); ++ u4BlockNum = u4Length >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); ++ } else { ++ eRamType = RAM_TYPE_BUF; ++ ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ u4BlkSzInPower = MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ u4Length += (MGT_BUF_BLOCK_SIZE - 1); ++ u4BlockNum = u4Length >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); ++ } ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4AllocCount++; ++#endif ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ if ((u4BlockNum > 0) && (u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS)) { ++ ++ /* Convert number of block into bit cluster */ ++ rRequiredBitmap = BITS(0, u4BlockNum - 1); ++ ++ for (i = 0; i <= (MAX_NUM_OF_BUF_BLOCKS - u4BlockNum); i++) { ++ ++ /* Have available memory blocks */ ++ if ((prBufInfo->rFreeBlocksBitmap & rRequiredBitmap) ++ == rRequiredBitmap) { ++ ++ /* Clear corresponding bits of allocated memory blocks */ ++ prBufInfo->rFreeBlocksBitmap &= ~rRequiredBitmap; ++ ++ /* Store how many blocks be allocated */ ++ prBufInfo->aucAllocatedBlockNum[i] = (UINT_8) u4BlockNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, ++ eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ /* Return the start address of allocated memory */ ++ return (PVOID) (prBufInfo->pucBuf + (i << u4BlkSzInPower)); ++ ++ } ++ ++ rRequiredBitmap <<= 1; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ /* cannot move the allocation between spin_lock_irqsave and spin_unlock_irqrestore */ ++#ifdef LINUX ++ pvMemory = (PVOID) kalMemAlloc(u4Length, VIR_MEM_TYPE); ++ if (pvMemory) ++ kalMemZero(pvMemory, u4Length); ++#else ++ pvMemory = (PVOID) NULL; ++#endif ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4AllocNullCount++; ++ ++ if (pvMemory) ++ prAdapter->u4MemAllocDynamicCount++; ++#endif ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ return pvMemory; ++ ++} /* end of cnmMemAlloc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release memory to MGT/MSG memory pool. ++* ++* \param pucMemory Start address of previous allocated memory ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory) ++{ ++ P_BUF_INFO_T prBufInfo; ++ UINT_32 u4BlockIndex; ++ BUF_BITMAP rAllocatedBlocksBitmap; ++ ENUM_RAM_TYPE_T eRamType; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvMemory); ++ if (!pvMemory) ++ return; ++ ++ u4MemFreeCnt++; ++ ++ /* Judge it belongs to which RAM type */ ++ if (((ULONG) pvMemory >= (ULONG)&prAdapter->aucMsgBuf[0]) && ++ ((ULONG) pvMemory <= (ULONG)&prAdapter->aucMsgBuf[MSG_BUFFER_SIZE - 1])) { ++ ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) ++ >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); ++ eRamType = RAM_TYPE_MSG; ++ } else if (((ULONG) pvMemory >= (ULONG) prAdapter->pucMgtBufCached) && ++ ((ULONG) pvMemory <= ((ULONG) prAdapter->pucMgtBufCached + MGT_BUFFER_SIZE - 1))) { ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) ++ >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); ++ eRamType = RAM_TYPE_BUF; ++ } else { ++#ifdef LINUX ++ /* For Linux, it is supported because size is not needed */ ++ kalMemFree(pvMemory, VIR_MEM_TYPE, 0); ++#else ++ /* For Windows, it is not supported because of no size argument */ ++ ASSERT(0); ++#endif ++ ++#if CFG_DBG_MGT_BUF ++ prAdapter->u4MemFreeDynamicCount++; ++#endif ++ return; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4FreeCount++; ++#endif ++ ++ /* Convert number of block into bit cluster */ ++ ASSERT(prBufInfo->aucAllocatedBlockNum[u4BlockIndex] > 0); ++ ++ rAllocatedBlocksBitmap = BITS(0, prBufInfo->aucAllocatedBlockNum[u4BlockIndex] - 1); ++ rAllocatedBlocksBitmap <<= u4BlockIndex; ++ ++ /* Clear saved block count for this memory segment */ ++ prBufInfo->aucAllocatedBlockNum[u4BlockIndex] = 0; ++ ++ /* Set corresponding bit of released memory block */ ++ prBufInfo->rFreeBlocksBitmap |= rAllocatedBlocksBitmap; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ return; ++ ++} /* end of cnmMemFree() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecInit(P_ADAPTER_T prAdapter) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ prStaRec->ucIndex = (UINT_8) i; ++ prStaRec->fgIsInUse = FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse) ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmStaRecAlloc(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i, k; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (!prStaRec->fgIsInUse) { ++ /*---- Initialize STA_REC_T here ----*/ ++ kalMemZero(prStaRec, sizeof(STA_RECORD_T)); ++ prStaRec->ucIndex = (UINT_8) i; ++ prStaRec->ucNetTypeIndex = ucNetTypeIndex; ++ prStaRec->fgIsInUse = TRUE; ++ ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ prStaRec->u2AssocReqIeLen = 0; ++ } ++ ++ /* Initialize the SN caches for duplicate detection */ ++ for (k = 0; k < TID_NUM + 1; k++) ++ prStaRec->au2CachedSeqCtrl[k] = 0xFFFF; ++ ++ /* Initialize SW TX queues in STA_REC */ ++ for (k = 0; k < STA_WAIT_QUEUE_NUM; k++) ++ LINK_INITIALIZE(&prStaRec->arStaWaitQueue[k]); ++ ++ /* Default enable TX/RX AMPDU */ ++ prStaRec->fgTxAmpduEn = TRUE; ++ prStaRec->fgRxAmpduEn = TRUE; ++ ++#if CFG_ENABLE_PER_STA_STATISTICS && CFG_ENABLE_PKT_LIFETIME_PROFILE ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++#endif ++ ++ for (k = 0; k < NUM_OF_PER_STA_TX_QUEUES; k++) ++ QUEUE_INITIALIZE(&prStaRec->arTxQueue[k]); ++ ++ break; ++ } ++ } ++ ++ return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecFree(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgSyncToChip) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ /* To do: free related resources, e.g. timers, buffers, etc */ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ prStaRec->fgTransmitKeyExist = FALSE; ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ prStaRec->u2AssocReqIeLen = 0; ++ } ++ ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ ++ if (fgSyncToChip) ++ cnmStaSendRemoveCmd(prAdapter, prStaRec); ++ ++ prStaRec->fgIsInUse = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex) ++ cnmStaRecFree(prAdapter, prStaRec, fgSyncToChip); ++ } /* end of for loop */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmGetStaRecByIndex(P_ADAPTER_T prAdapter, UINT_8 ucIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ++ prStaRec = (ucIndex < CFG_STA_REC_NUM) ? &prAdapter->arStaRec[ucIndex] : NULL; ++ ++ if (prStaRec && prStaRec->fgIsInUse == FALSE) ++ prStaRec = NULL; ++ ++ return prStaRec; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). ++* ++* @param[in] pucPeerMacAddr Given Peer MAC Address. ++* ++* @retval Pointer to STA_RECORD_T, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmGetStaRecByAddress(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex, PUINT_8 pucPeerMacAddr) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucPeerMacAddr); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && ++ prStaRec->ucNetTypeIndex == ucNetTypeIndex && ++ EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { ++ break; ++ } ++ } ++ ++ return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Reset the Status and Reason Code Field to 0 of all Station Records for ++* the specified Network Type ++* ++* @param[in] eNetType Specify Network Type ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecResetStatus(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetTypeIndex, FALSE); ++ ++#if 0 ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse) { ++ if ((NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) && IS_STA_IN_AIS(prStaRec->eStaType)) { ++ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->u2ReasonCode = REASON_CODE_RESERVED; ++ prStaRec->ucJoinFailureCount = 0; ++ prStaRec->fgTransmitKeyExist = FALSE; ++ ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ } ++ ++ /* TODO(Kevin): For P2P and BOW */ ++ } ++ } ++ ++ return; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will change the ucStaState of STA_RECORD_T and also do ++* event indication to HOST to sync the STA_RECORD_T in driver. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u4NewState New STATE to change. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecChangeState(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, UINT_8 ucNewState) ++{ ++ BOOLEAN fgNeedResp; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->fgIsInUse); ++ ++ /* Do nothing when following state transitions happen, ++ * other 6 conditions should be sync to FW, including 1-->1, 3-->3 ++ */ ++ if ((ucNewState == STA_STATE_2 && prStaRec->ucStaState != STA_STATE_3) || ++ (ucNewState == STA_STATE_1 && prStaRec->ucStaState == STA_STATE_2)) { ++ prStaRec->ucStaState = ucNewState; ++ return; ++ } ++ ++ fgNeedResp = FALSE; ++ if (ucNewState == STA_STATE_3) { ++ secFsmEventStart(prAdapter, prStaRec); ++ if (ucNewState != prStaRec->ucStaState) ++ fgNeedResp = TRUE; ++ } else { ++ if (ucNewState != prStaRec->ucStaState && prStaRec->ucStaState == STA_STATE_3) ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ fgNeedResp = FALSE; ++ } ++ prStaRec->ucStaState = ucNewState; ++ ++ cnmStaSendUpdateCmd(prAdapter, prStaRec, fgNeedResp); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* To do: Confirm if it is invoked here or other location, but it should ++ * be invoked after state sync of STA_REC ++ * Update system operation parameters for AP mode ++ */ ++ if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); ++ } ++#endif ++} ++ ++P_STA_RECORD_T ++cnmStaTheTypeGet(P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx) ++{ ++ P_STA_RECORD_T prStaRec = NULL; ++ UINT_16 i; ++ ++ for (i = *pu4StartIdx; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && ++ prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex && prStaRec->eStaType == eStaType) { ++ i++; ++ break; ++ } ++ ++ prStaRec = NULL; /* reset */ ++ } /* end of for loop */ ++ ++ *pu4StartIdx = i; ++ return prStaRec; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf) ++{ ++ P_EVENT_ACTIVATE_STA_REC_T prEventContent; ++ P_STA_RECORD_T prStaRec; ++ ++ prEventContent = (P_EVENT_ACTIVATE_STA_REC_T) pucEventBuf; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prEventContent->ucStaRecIdx); ++ ++ if (prStaRec && prStaRec->ucStaState == STA_STATE_3 && ++ !kalMemCmp(&prStaRec->aucMacAddr[0], &prEventContent->aucMacAddr[0], MAC_ADDR_LEN)) { ++ ++ qmActivateStaRec(prAdapter, prStaRec); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp) ++{ ++ P_CMD_UPDATE_STA_RECORD_T prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->fgIsInUse); ++ ++ /* To do: come out a mechanism to limit one STA_REC sync once for AP mode ++ * to avoid buffer empty case when many STAs are associated ++ * simultaneously. ++ */ ++ ++ /* To do: how to avoid 2 times of allocated memory. Use Stack? ++ * One is here, the other is in wlanSendQueryCmd() ++ */ ++ prCmdContent = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_UPDATE_STA_RECORD_T)); ++ ASSERT(prCmdContent); ++ ++ /* To do: exception handle */ ++ if (!prCmdContent) ++ return; ++ ++ prCmdContent->ucIndex = prStaRec->ucIndex; ++ prCmdContent->ucStaType = (UINT_8) prStaRec->eStaType; ++ kalMemCopy(&prCmdContent->aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); ++ prCmdContent->u2AssocId = prStaRec->u2AssocId; ++ prCmdContent->u2ListenInterval = prStaRec->u2ListenInterval; ++ prCmdContent->ucNetTypeIndex = prStaRec->ucNetTypeIndex; ++ ++ prCmdContent->ucDesiredPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ prCmdContent->u2DesiredNonHTRateSet = prStaRec->u2DesiredNonHTRateSet; ++ prCmdContent->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ prCmdContent->ucMcsSet = prStaRec->ucMcsSet; ++ prCmdContent->ucSupMcs32 = (UINT_8) prStaRec->fgSupMcs32; ++ prCmdContent->u2HtCapInfo = prStaRec->u2HtCapInfo; ++ prCmdContent->ucNeedResp = (UINT_8) fgNeedResp; ++ ++#if !CFG_SLT_SUPPORT ++ if (prAdapter->rWifiVar.eRateSetting != FIXED_RATE_NONE) { ++ /* override rate configuration */ ++ nicUpdateRateParams(prAdapter, ++ prAdapter->rWifiVar.eRateSetting, ++ &(prCmdContent->ucDesiredPhyTypeSet), ++ &(prCmdContent->u2DesiredNonHTRateSet), ++ &(prCmdContent->u2BSSBasicRateSet), ++ &(prCmdContent->ucMcsSet), ++ &(prCmdContent->ucSupMcs32), &(prCmdContent->u2HtCapInfo)); ++ } ++#endif ++ ++ prCmdContent->ucIsQoS = prStaRec->fgIsQoS; ++ prCmdContent->ucIsUapsdSupported = prStaRec->fgIsUapsdSupported; ++ prCmdContent->ucStaState = prStaRec->ucStaState; ++ ++ prCmdContent->ucAmpduParam = prStaRec->ucAmpduParam; ++ prCmdContent->u2HtExtendedCap = prStaRec->u2HtExtendedCap; ++ prCmdContent->u4TxBeamformingCap = prStaRec->u4TxBeamformingCap; ++ prCmdContent->ucAselCap = prStaRec->ucAselCap; ++ prCmdContent->ucRCPI = prStaRec->ucRCPI; ++ ++ prCmdContent->ucUapsdAc = prStaRec->ucBmpTriggerAC | (prStaRec->ucBmpDeliveryAC << 4); ++ prCmdContent->ucUapsdSp = prStaRec->ucUapsdSp; ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_UPDATE_STA_RECORD, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ fgNeedResp, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ fgNeedResp ? cnmStaRecHandleEventPkt : NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_UPDATE_STA_RECORD_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdContent); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ CMD_REMOVE_STA_RECORD_T rCmdContent; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ rCmdContent.ucIndex = prStaRec->ucIndex; ++ kalMemCopy(&rCmdContent.aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_REMOVE_STA_RECORD, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_REMOVE_STA_RECORD_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) &rCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c +new file mode 100644 +index 000000000000..8cc9ef9078fe +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c +@@ -0,0 +1,482 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1 ++*/ ++ ++/*! \file "cnm_timer.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: cnm_timer.c ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation ++ * because NdisMSleep() won't sleep long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support sleep notification to host ++ * ++ * 05 19 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some checking assertions ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Return timer token back to COS when entering wait off state ++ * ++ * 01 11 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning ++ * ++ * 01 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 01 06 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix system time is 32KHz instead of 1ms ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer ++ * ++ * Oct 30 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * In cnmTimerInitialize(), just stop timer if it was already created. ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Move the external reference for Lint to precomp.h ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the time to do the time out check. ++* ++* \param[in] rTimeout Time out interval from current time. ++* ++* \retval TRUE Success. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout) ++{ ++ P_ROOT_TIMER prRootTimer; ++ BOOLEAN fgNeedWakeLock; ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ kalSetTimer(prAdapter->prGlueInfo, rTimeout); ++ ++ if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) { ++ fgNeedWakeLock = TRUE; ++ ++ if (!prRootTimer->fgWakeLocked) { ++ KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = TRUE; ++ } ++ } else { ++ fgNeedWakeLock = FALSE; ++ } ++ ++ return fgNeedWakeLock; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to initialize a root timer. ++* ++* \param[in] prAdapter ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ /* Note: glue layer have configured timer */ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ LINK_INITIALIZE(&prRootTimer->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer"); ++ prRootTimer->fgWakeLocked = FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to destroy a root timer. ++* When WIFI is off, the token shall be returned back to system. ++* ++* \param[in] ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ if (prRootTimer->fgWakeLocked) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ LINK_INITIALIZE(&prRootTimer->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ /* Note: glue layer will be responsible for timer destruction */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to initialize a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* \param[in] pfnFunc Pointer to the call back function. ++* \param[in] u4Data Parameter for call back function. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData) ++{ ++ ASSERT(prAdapter); ++ ++ ASSERT(prTimer); ++ ++#if DBG ++ /* Note: NULL function pointer is permitted for HEM POWER */ ++ if (pfFunc == NULL) ++ DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n"); ++#endif ++ ++#if DBG ++ ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); ++ { ++ P_LINK_T prTimerList; ++ P_LINK_ENTRY_T prLinkEntry; ++ P_TIMER_T prPendingTimer; ++ ++ prTimerList = &(prAdapter->rRootTimer.rLinkHead); ++ ++ LINK_FOR_EACH(prLinkEntry, prTimerList) { ++ prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); ++ ASSERT(prPendingTimer); ++ ASSERT(prPendingTimer != prTimer); ++ } ++ } ++#endif ++ ++ LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); ++ ++ prTimer->pfMgmtTimeOutFunc = pfFunc; ++ prTimer->ulData = ulData; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to stop a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ if (fgAcquireSpinlock) ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ if (timerPendingTimer(prTimer)) { ++ LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry); ++ ++ /* Reduce dummy timeout for power saving, especially HIF activity. ++ * If two or more timers exist and being removed timer is smallest, ++ * this dummy timeout will still happen, but it is OK. ++ */ ++ if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { ++ kalCancelTimer(prAdapter->prGlueInfo); ++ ++ if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ } ++ } ++ ++ if (fgAcquireSpinlock) ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to stop a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to start a timer with wake_lock. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* \param[in] u4TimeoutMs Timeout to issue the timer and call back function ++* (unit: ms). ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs) ++{ ++ P_ROOT_TIMER prRootTimer; ++ P_LINK_T prTimerList; ++ OS_SYSTIME rExpiredSysTime, rTimeoutSystime; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ prTimerList = &prRootTimer->rLinkHead; ++ ++ /* If timeout interval is larger than 1 minute, the mod value is set ++ * to the timeout value first, then per minutue. ++ */ ++ if (u4TimeoutMs > MSEC_PER_MIN) { ++ ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN)); ++ ++ prTimer->u2Minutes = (UINT_16) (u4TimeoutMs / MSEC_PER_MIN); ++ u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN); ++ if (u4TimeoutMs == 0) { ++ u4TimeoutMs = MSEC_PER_MIN; ++ prTimer->u2Minutes--; ++ } ++ } else { ++ prTimer->u2Minutes = 0; ++ } ++ ++ /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */ ++ ASSERT(u4TimeoutMs < (((UINT_32) 0x80000000 - MSEC_PER_SEC) / KAL_HZ)); ++ rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs); ++ rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime; ++ ++ /* If no timer pending or the fast time interval is used. */ ++ if (LINK_IS_EMPTY(prTimerList) || TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { ++ ++ prRootTimer->rNextExpiredSysTime = rExpiredSysTime; ++ cnmTimerSetTimer(prAdapter, rTimeoutSystime); ++ } ++ ++ /* Add this timer to checking list */ ++ prTimer->rExpiredSysTime = rExpiredSysTime; ++ ++ if (!timerPendingTimer(prTimer)) ++ LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to check the timer list. ++* ++* \param[in] ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ P_LINK_T prTimerList; ++ P_LINK_ENTRY_T prLinkEntry; ++ P_TIMER_T prTimer; ++ OS_SYSTIME rCurSysTime; ++ PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; ++ ULONG ulTimeoutData; ++ BOOLEAN fgNeedWakeLock; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* acquire spin lock */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ prTimerList = &prRootTimer->rLinkHead; ++ ++ rCurSysTime = kalGetTimeTick(); ++ ++ /* Set the permitted max timeout value for new one */ ++ prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; ++ ++ LINK_FOR_EACH(prLinkEntry, prTimerList) { ++ prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); ++ ASSERT(prTimer); ++ ++ /* Check if this entry is timeout. */ ++ if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { ++ cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE); ++ ++ pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; ++ ulTimeoutData = prTimer->ulData; ++ ++ if (prTimer->u2Minutes > 0) { ++ prTimer->u2Minutes--; ++ prTimer->rExpiredSysTime = rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN); ++ LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); ++ } else if (pfMgmtTimeOutFunc) { ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ (pfMgmtTimeOutFunc) (prAdapter, ulTimeoutData); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ } ++ ++ /* Search entire list again because of nest del and add timers ++ * and current MGMT_TIMER could be volatile after stopped ++ */ ++ prLinkEntry = (P_LINK_ENTRY_T) prTimerList; ++ ++ prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; ++ } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { ++ prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime; ++ } ++ } /* end of for loop */ ++ ++ /* Setup the prNext timeout event. It is possible the timer was already ++ * set in the above timeout callback function. ++ */ ++ fgNeedWakeLock = FALSE; ++ if (!LINK_IS_EMPTY(prTimerList)) { ++ ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime)); ++ ++ fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME) ++ ((INT_32) prRootTimer->rNextExpiredSysTime - (INT_32) rCurSysTime)); ++ } ++ ++ if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ ++ /* release spin lock */ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c +new file mode 100644 +index 000000000000..c7a23eb018b6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c +@@ -0,0 +1,816 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/hem_mbox.c#3 ++*/ ++ ++/*! \file "hem_mbox.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: hem_mbox.c ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device ++** have connected to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 05 03 2012 cp.wu ++ * [WCXRP00001231] [MT6620 Wi-Fi][MT5931][Driver] Correct SCAN_V2 related debugging facilities within hem_mbox.c ++ * correct for debug message string table by adding missed scan_v2 related definitions. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 17 2012 yuche.tsai ++ * NULL ++ * Update mgmt frame filter setting. ++ * Please also update FW 2.1 ++ * ++ * 01 13 2012 yuche.tsai ++ * NULL ++ * WiFi Hot Spot Tethering for ICS ALPHA testing version. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Add exception handle for NULL function pointer of mailbox message ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support ++ * as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add invitation support. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation ++ * because NdisMSleep() won't sleep long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update bowString and channel grant. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 12 08 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support concurrent networks. ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Remove unused message ID ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add P2P Connection Abort Event Message handler. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 yarco.yang ++ * NULL ++ * Fixed Driver ASSERT at mboxInitMsgMap() ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. ++ * Update saa_fsm for BOW. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Add CFG_ENABLE_BT_OVER_WIFI. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add debug message for newly add P2P message. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some function entry for P2P FSM under provisioning phase.. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some events to P2P Module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add message box event for P2P device switch on & device discovery. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * remove unused mailbox message definitions. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * message table should not be commented out by compilation option without modifying header file ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Add wifi direct scan done callback. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * change handler of MID_MNY_CNM_CONNECTION_ABORT from NULL to mboxDummy. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable currently migrated message call-backs. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix file merge error ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Develop partial DPD code ++ * ++ * 02 11 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Updated arMsgMapTable for MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Dec 9 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add hemRunEventScanDone() to arMsgMapTable[] ++ * ++ * Dec 4 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix mboxDummy() didn't free prMsgHdr ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add saaAisJoinComplete event handler ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed the handler function name in arMsgMapTable for MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added MID_RXM_MQM_BA_ACTION_FRAME to MsgMapTable ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MSG Handler (remove dummy and add for SAA) ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmRunEventAbort() event handler ++ * ++ * Nov 11 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Nov 10 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add more MSG_HNDL_ENTRY_T to avoid ASSERT() in mboxInitMsgMap() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add SCN message and function entry to arMsgMapTable[] ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix sorting algorithm in mboxInitMsgMap() ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugMsg[] = { ++ (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_ABORT"), ++ (PUINT_8) DISP_STRING("MID_CNM_AIS_CH_GRANT"), ++ (PUINT_8) DISP_STRING("MID_CNM_P2P_CH_GRANT"), ++ (PUINT_8) DISP_STRING("MID_CNM_BOW_CH_GRANT"), ++ ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_SCN_AIS_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_P2P_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_BOW_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_RLM_SCAN_DONE"), ++ ++ (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_JOIN_REQ"), ++ (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_AIS_JOIN_COMPLETE"), ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_BOW_JOIN_COMPLETE"), ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_P2P_JOIN_COMPLETE"), ++ ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_FUN_SWITCH"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_DEVICE_DISCOVERY"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_BEACON_UPDATE"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_STOP_AP"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_TX"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_GROUP_DISSOLVE"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_FRAME_REGISTER"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_NET_DEV_REGISTER"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_START_AP"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_UPDATE_IE_BUF"), ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ /* (PUINT_8)DISP_STRING("MID_AIS_CNM_CREATE_IBSS_REQ"), */ ++ /* (PUINT_8)DISP_STRING("MID_CNM_AIS_CREATE_IBSS_GRANT"), */ ++ /* (PUINT_8)DISP_STRING("MID_AIS_CNM_MERGE_IBSS_REQ"), */ ++ /* (PUINT_8)DISP_STRING("MID_CNM_AIS_MERGE_IBSS_GRANT"), */ ++ (PUINT_8) DISP_STRING("MID_SCN_AIS_FOUND_IBSS"), ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ (PUINT_8) DISP_STRING("MID_SAA_AIS_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_MGMT_TX") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/* This message entry will be re-ordered based on the message ID order ++ * by invoking mboxInitMsgMap() ++ */ ++static MSG_HNDL_ENTRY_T arMsgMapTable[] = { ++ {MID_MNY_CNM_CH_REQ, cnmChMngrRequestPrivilege}, ++ {MID_MNY_CNM_CH_ABORT, cnmChMngrAbortPrivilege}, ++ {MID_CNM_AIS_CH_GRANT, aisFsmRunEventChGrant}, ++#if CFG_ENABLE_WIFI_DIRECT ++ {MID_CNM_P2P_CH_GRANT, p2pFsmRunEventChGrant}, /*set in gl_p2p_init.c */ ++#else ++ {MID_CNM_P2P_CH_GRANT, mboxDummy}, ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ {MID_CNM_BOW_CH_GRANT, bowRunEventChGrant}, ++#else ++ {MID_CNM_BOW_CH_GRANT, mboxDummy}, ++#endif ++ ++ /*--------------------------------------------------*/ ++ /* SCN Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_AIS_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_AIS_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_AIS_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_P2P_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_P2P_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_P2P_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_BOW_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_BOW_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_BOW_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_RLM_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_RLM_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_RLM_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_SCN_AIS_SCAN_DONE, aisFsmRunEventScanDone}, ++#if CFG_ENABLE_WIFI_DIRECT ++ {MID_SCN_P2P_SCAN_DONE, p2pFsmRunEventScanDone}, /*set in gl_p2p_init.c */ ++#else ++ {MID_SCN_P2P_SCAN_DONE, mboxDummy}, ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ {MID_SCN_BOW_SCAN_DONE, bowResponderScanDone}, ++#else ++ {MID_SCN_BOW_SCAN_DONE, mboxDummy}, ++#endif ++ {MID_SCN_RLM_SCAN_DONE, rlmObssScanDone}, ++ ++ /*--------------------------------------------------*/ ++ /* AIS Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_OID_AIS_FSM_JOIN_REQ, aisFsmRunEventAbort}, ++ {MID_OID_AIS_FSM_ABORT, aisFsmRunEventAbort}, ++ {MID_AIS_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_AIS_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_AIS_JOIN_COMPLETE, aisFsmRunEventJoinComplete}, ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /*--------------------------------------------------*/ ++ /* BOW Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_BOW_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_BOW_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_BOW_JOIN_COMPLETE, bowFsmRunEventJoinComplete}, ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT /*set in gl_p2p_init.c */ ++ {MID_P2P_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_P2P_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_P2P_JOIN_COMPLETE, p2pFsmRunEventJoinComplete}, /* TODO: p2pFsmRunEventJoinComplete */ ++ ++ {MID_MNY_P2P_FUN_SWITCH, p2pFsmRunEventSwitchOPMode}, ++ {MID_MNY_P2P_DEVICE_DISCOVERY, p2pFsmRunEventScanRequest}, ++ {MID_MNY_P2P_CONNECTION_REQ, p2pFsmRunEventConnectionRequest}, ++ {MID_MNY_P2P_CONNECTION_ABORT, p2pFsmRunEventConnectionAbort}, ++ {MID_MNY_P2P_BEACON_UPDATE, p2pFsmRunEventBeaconUpdate}, ++ {MID_MNY_P2P_STOP_AP, p2pFsmRunEventStopAP}, ++ {MID_MNY_P2P_CHNL_REQ, p2pFsmRunEventChannelRequest}, ++ {MID_MNY_P2P_CHNL_ABORT, p2pFsmRunEventChannelAbort}, ++ {MID_MNY_P2P_MGMT_TX, p2pFsmRunEventMgmtFrameTx}, ++ {MID_MNY_P2P_GROUP_DISSOLVE, p2pFsmRunEventDissolve}, ++ {MID_MNY_P2P_MGMT_FRAME_REGISTER, p2pFsmRunEventMgmtFrameRegister}, ++ {MID_MNY_P2P_NET_DEV_REGISTER, p2pFsmRunEventNetDeviceRegister}, ++ {MID_MNY_P2P_START_AP, p2pFsmRunEventStartAP}, ++ {MID_MNY_P2P_MGMT_FRAME_UPDATE, p2pFsmRunEventUpdateMgmtFrame}, ++ {MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, p2pFsmRunEventExtendListen}, ++#if CFG_SUPPORT_WFD ++ {MID_MNY_P2P_WFD_CFG_UPDATE, p2pFsmRunEventWfdSettingUpdate}, ++#endif ++ ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ {MID_SCN_AIS_FOUND_IBSS, aisFsmRunEventFoundIBSSPeer}, ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ {MID_SAA_AIS_FSM_ABORT, aisFsmRunEventAbort}, ++ {MID_MNY_AIS_REMAIN_ON_CHANNEL, aisFsmRunEventRemainOnChannel}, ++ {MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, aisFsmRunEventCancelRemainOnChannel}, ++ {MID_MNY_AIS_MGMT_TX, aisFsmRunEventMgmtFrameTx} ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if DBG ++#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ ++ ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ ++ if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ ++ DBGLOG(CNM, LOUD, "DO MSG [%d: %s]\n", prMsg->eMsgId, apucDebugMsg[prMsg->eMsgId]); \ ++ arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ ++ } \ ++ else { \ ++ DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ ++ cnmMemFree(prAdapter, prMsg); \ ++ } \ ++} while (0) ++#else ++#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ ++ ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ ++ if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ ++ DBGLOG(CNM, LOUD, "DO MSG [%d]\n", prMsg->eMsgId); \ ++ arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ ++ } \ ++ else { \ ++ DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ ++ cnmMemFree(prAdapter, prMsg); \ ++ } \ ++} while (0) ++#endif ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxInitMsgMap(VOID) ++{ ++ UINT_32 i, idx; ++ MSG_HNDL_ENTRY_T rTempEntry; ++ ++ ASSERT((sizeof(arMsgMapTable) / sizeof(MSG_HNDL_ENTRY_T)) == MID_TOTAL_NUM); ++ ++ for (i = 0; i < MID_TOTAL_NUM; i++) { ++ if (arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i) ++ continue; ++ for (idx = i + 1; idx < MID_TOTAL_NUM; idx++) { ++ if (arMsgMapTable[idx].eMsgId == (ENUM_MSG_ID_T) i) ++ break; ++ } ++ ASSERT(idx < MID_TOTAL_NUM); ++ if (idx >= MID_TOTAL_NUM) ++ continue; ++ ++ /* Swap target entry and current entry */ ++ rTempEntry.eMsgId = arMsgMapTable[idx].eMsgId; ++ rTempEntry.pfMsgHndl = arMsgMapTable[idx].pfMsgHndl; ++ ++ arMsgMapTable[idx].eMsgId = arMsgMapTable[i].eMsgId; ++ arMsgMapTable[idx].pfMsgHndl = arMsgMapTable[i].pfMsgHndl; ++ ++ arMsgMapTable[i].eMsgId = rTempEntry.eMsgId; ++ arMsgMapTable[i].pfMsgHndl = rTempEntry.pfMsgHndl; ++ } ++ ++ /* Verify the correctness of final message map */ ++ for (i = 0; i < MID_TOTAL_NUM; i++) { ++ ASSERT(arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i); ++ while (arMsgMapTable[i].eMsgId != (ENUM_MSG_ID_T) i) ++ ; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId) ++{ ++ P_MBOX_T prMbox; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_INITIALIZE(&prMbox->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++mboxSendMsg(IN P_ADAPTER_T prAdapter, ++ IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod) ++{ ++ P_MBOX_T prMbox; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prMsg); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ switch (eMethod) { ++ case MSG_SEND_METHOD_BUF: ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_INSERT_TAIL(&prMbox->rLinkHead, &prMsg->rLinkEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ /* to wake up main service thread */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ break; ++ ++ case MSG_SEND_METHOD_UNBUF: ++ MBOX_HNDL_MSG(prAdapter, prMsg); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, ENUM_MBOX_ID_T eMboxId) ++{ ++ P_MBOX_T prMbox; ++ P_MSG_HDR_T prMsg; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ ASSERT(prMsg); ++ MBOX_HNDL_MSG(prAdapter, prMsg); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* Initialize Mailbox */ ++ mboxInitMsgMap(); ++ ++ /* Setup/initialize each mailbox */ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) ++ mboxSetup(prAdapter, i); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ P_MBOX_T prMbox; ++ P_MSG_HDR_T prMsg; ++ UINT_8 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { ++ prMbox = &(prAdapter->arMbox[i]); ++ ++ while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ ASSERT(prMsg); ++ cnmMemFree(prAdapter, prMsg); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is dummy function to prevent empty arMsgMapTable[] for compiling. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxDummy(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ASSERT(prAdapter); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c +new file mode 100644 +index 000000000000..7fb71a199ccf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c +@@ -0,0 +1,498 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/mgmt/hs20.c#2 ++*/ ++ ++/*! \file "hs20.c" ++ \brief This file including the hotspot 2.0 related function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer hotspot 2.0 related function. ++ ++*/ ++ ++/* ++** Log: hs20.c ++ * ++ */ ++ ++ /******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate Interworking IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate Roaming Consortium IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate HS2.0 IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 221 :0xDD */ ++ if (prAdapter->prGlueInfo->u2HS20AssocInfoIELen) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucHS20AssocInfoIE, ++ prAdapter->prGlueInfo->u2HS20AssocInfoIELen); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2HS20AssocInfoIELen; ++ } ++ ++} ++ ++VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_HS20_EXT_CAP_T prExtCap; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_HS20_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ kalPrint("IE_SIZE(prExtCap) = %d, %d %d\n", IE_SIZE(prExtCap), ELEM_HDR_LEN, ELEM_MAX_LEN_EXT_CAP); ++ ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to fill up the content of Ext Cap IE bit 31. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] pucIE Pointer of the IE buffer ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) ++{ ++ P_HS20_EXT_CAP_T prExtCap; ++ ++ ASSERT(prAdapter); ++ ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_HS20_EXT_CAP_T) pucIE; ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to fill up the content of HS2.0 IE. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] pucIE Pointer of the IE buffer ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) ++{ ++ P_IE_HS20_INDICATION_T prHS20IndicationIe; ++ /* P_HS20_INFO_T prHS20Info; */ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ /* prHS20Info = &(prAdapter->rWifiVar.rHS20Info); */ ++ ++ prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pucIE; ++ ++ prHS20IndicationIe->ucId = ELEM_ID_VENDOR; ++ prHS20IndicationIe->ucLength = sizeof(IE_HS20_INDICATION_T) - ELEM_HDR_LEN; ++ prHS20IndicationIe->aucOui[0] = aucWfaOui[0]; ++ prHS20IndicationIe->aucOui[1] = aucWfaOui[1]; ++ prHS20IndicationIe->aucOui[2] = aucWfaOui[2]; ++ prHS20IndicationIe->ucType = VENDOR_OUI_TYPE_HS20; ++ prHS20IndicationIe->ucHotspotConfig = 0x00; /* prHS20Info->ucHotspotConfig; */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called while calculating length of hotspot 2.0 indication IE for Probe Request. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] pucTargetBSSID Pointer of target HESSID ++* ++* \return the length of composed HS20 IE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID) ++{ ++ UINT_32 u4IeLength; ++ ++ if (0) /* Todo:: Not HS20 STA */ ++ return 0; ++ ++ u4IeLength = ++ sizeof(IE_HS20_INDICATION_T) + /* sizeof(IE_INTERWORKING_T) */ + (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP); ++ ++ if (!pucTargetBSSID) { ++ /* Do nothing */ ++ /* u4IeLength -= MAC_ADDR_LEN; */ ++ } ++ ++ return u4IeLength; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called while composing hotspot 2.0 indication IE for Probe Request. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] pucTargetBSSID Pointer of target HESSID ++* \param[out] prIE Pointer of the IE buffer ++* ++* \return the wlan status ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE) ++{ ++ if (0) /* Todo:: Not HS20 STA */ ++ return 0; ++#if 0 ++ P_HS20_INFO_T prHS20Info; ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ /* ++ * Generate 802.11u Interworking IE (107) ++ */ ++ hs20FillInterworkingIE(prAdapter, ++ prHS20Info->ucAccessNetworkOptions, ++ prHS20Info->ucVenueGroup, prHS20Info->ucVenueType, pucTargetBSSID, prIE); ++ prIE += IE_SIZE(prIE); ++#endif ++ /* ++ * Generate Ext Cap IE (127) ++ */ ++ hs20FillProreqExtCapIE(prAdapter, prIE); ++ prIE += IE_SIZE(prIE); ++ ++ /* ++ * Generate HS2.0 Indication IE (221) ++ */ ++ hs20FillHS20IE(prAdapter, prIE); ++ prIE += IE_SIZE(prIE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_8 pucSenderIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SENDER_IP_OFFSET; ++ PUINT_8 pucTargetIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_IP_OFFSET; ++ PUINT_8 pucSenderMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SNEDER_MAC_OFFSET); ++#if CFG_HS20_DEBUG && 0 ++/* UINT_8 aucIpAllZero[4] = {0,0,0,0}; */ ++/* UINT_8 aucMACAllZero[MAC_ADDR_LEN] = {0,0,0,0,0,0}; */ ++ PUINT_8 pucTargetMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_MAC_OFFSET); ++#endif ++ ++#if CFG_HS20_DEBUG && 0 ++ PUINT_16 pu2ArpOper = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_OPERATION_OFFSET); ++ ++ kalPrint("Recv ARP 0x%04X\n", htons(*pu2ArpOper)); ++ kalPrint("SENDER[ %pM ] [%pI4]\n", pucSenderMac, pucSenderIP); ++ kalPrint("TARGET[ %pM ] [%pI4]\n", pucTargetMac, pucTargetIP); ++#endif ++ ++ /* IsGratuitousArp */ ++ if (!kalMemCmp(pucSenderIP, pucTargetIP, 4)) { ++ kalPrint("Drop Gratuitous ARP from [ %pM ] [%pI4]\n", pucSenderMac, pucTargetIP); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_8 pucIpv6Protocol = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_PROTOCOL_OFFSET); ++ ++ /* kalPrint("pucIpv6Protocol [%02X:%02X]\n", *pucIpv6Protocol, IPV6_PROTOCOL_ICMPV6); */ ++ if (*pucIpv6Protocol == IPV6_PROTOCOL_ICMPV6) { ++ PUINT_8 pucICMPv6Type = ++ ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_TYPE_OFFSET); ++ /* kalPrint("pucICMPv6Type [%02X:%02X]\n", *pucICMPv6Type, ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT); */ ++ if (*pucICMPv6Type == ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT) { ++ PUINT_8 pucICMPv6Flag = ++ ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_FLAG_OFFSET); ++ PUINT_8 pucSrcMAC = ((PUINT_8) prCurrSwRfb->pvHeader + MAC_ADDR_LEN); ++ ++#if CFG_HS20_DEBUG ++ kalPrint("NAdv Flag [%02X] [R(%d)\\S(%d)\\O(%d)]\n", ++ *pucICMPv6Flag, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_ROUTER_BIT) >> 7, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT) >> 6, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_OVERWRITE_BIT) >> 5); ++#endif ++ if (!(*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT)) { ++ kalPrint("Drop Unsolicited Neighbor Advertisement from [%pM]\n", pucSrcMAC); ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ /* ++ P_CONNECTION_SETTINGS_T prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ PUINT_8 pucEthDestAddr = prCurrSwRfb->pvHeader; ++ */ ++ /* 3 TODO: Need to verify this function before enable it */ ++ return FALSE; ++ /* ++ if ((prConnSettings->eEncStatus != ENUM_ENCRYPTION_DISABLED) && IS_BMCAST_MAC_ADDR(pucEthDestAddr)) { ++ UINT_8 ucIdx = 0; ++ PUINT_32 prIpAddr, prPacketDA; ++ PUINT_16 pu2PktIpVer = ++ (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); ++ ++ if (*pu2PktIpVer == htons(ETH_P_IPV4)) { ++ if (!prBssInfo->prIpV4NetAddrList) ++ return FALSE; ++ for (ucIdx = 0; ucIdx < prBssInfo->prIpV4NetAddrList->ucAddrCount; ucIdx++) { ++ prIpAddr = (PUINT_32) &prBssInfo->prIpV4NetAddrList->arNetAddr[ucIdx].aucIpAddr[0]; ++ prPacketDA = ++ (PUINT_32) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ++ IPV4_HDR_IP_DST_ADDR_OFFSET); ++ ++ if (kalMemCmp(prIpAddr, prPacketDA, 4) == 0) { ++ kalPrint("Drop FORGED IPv4 packet\n"); ++ return TRUE; ++ } ++ } ++ } ++#ifdef CONFIG_IPV6 ++ else if (*pu2PktIpVer == htons(ETH_P_IPV6)) { ++ UINT_8 aucIPv6Mac[MAC_ADDR_LEN]; ++ PUINT_8 pucIdx = ++ prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET; ++ ++ kalMemCopy(&aucIPv6Mac[0], pucIdx, 3); ++ pucIdx += 5; ++ kalMemCopy(&aucIPv6Mac[3], pucIdx, 3); ++ kalPrint("Get IPv6 frame Dst IP MAC part %pM\n", aucIPv6Mac); ++ if (EQUAL_MAC_ADDR(aucIPv6Mac, prBssInfo->aucOwnMacAddr)) { ++ kalPrint("Drop FORGED IPv6 packet\n"); ++ return TRUE; ++ } ++ } ++#endif ++ } ++ ++ return FALSE; ++ */ ++} ++#endif ++ ++BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_16 pu2PktIpVer = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); ++ ++ /* kalPrint("IPVER 0x%4X\n", htons(*pu2PktIpVer)); */ ++#if CFG_HS20_DEBUG & 0 ++ UINT_8 i = 0; ++ ++ kalPrint("==============================================="); ++ for (i = 0; i < 96; i++) { ++ if (!(i % 16)) ++ kalPrint("\n"); ++ kalPrint("%02X ", *((PUINT_8) prCurrSwRfb->pvHeader + i)); ++ } ++ kalPrint("\n"); ++#endif ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ if (hs20IsForgedGTKFrame(prAdapter, prBssInfo, prCurrSwRfb)) ++ return TRUE; ++ ++#endif ++ if (*pu2PktIpVer == htons(ETH_P_ARP)) ++ return hs20IsGratuitousArp(prAdapter, prCurrSwRfb); ++ else if (*pu2PktIpVer == htons(ETH_P_IPV6)) ++ return hs20IsUnsolicitedNeighborAdv(prAdapter, prCurrSwRfb); ++ ++ return FALSE; ++} ++ ++BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++#if 1 ++ if (prAdapter->prGlueInfo->fgConnectHS20AP) ++ return TRUE; ++#else ++ PARAM_SSID_T rParamSsid; ++ P_BSS_DESC_T prBssDesc; ++ ++ rParamSsid.u4SsidLen = prBssInfo->ucSSIDLen; ++ COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ ++ prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, prBssInfo->aucBSSID, TRUE, &rParamSsid); ++ if (!prBssDesc) ++ return FALSE; ++ ++ if (prBssDesc->fgIsSupportHS20) { ++ if (!(prBssDesc->ucHotspotConfig & ELEM_HS_CONFIG_DGAF_DISABLED_MASK)) ++ return TRUE; ++ ++ /* Disable frame filter only if DGAF == 1 */ ++ return FALSE; ++ ++ } ++#endif ++ ++ /* For Now, always return true to run hs20 check even for legacy AP */ ++ return TRUE; ++} ++ ++WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) ++{ ++ P_PARAM_HS20_SET_BSSID_POOL prParamBssidPool = (P_PARAM_HS20_SET_BSSID_POOL) pvBuffer; ++ P_HS20_INFO_T prHS20Info; ++ UINT_8 ucIdx; ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ kalPrint("[%s]Set Bssid Pool! enable[%d] num[%d]\n", __func__, prParamBssidPool->fgIsEnable, ++ prParamBssidPool->ucNumBssidPool); ++ for (ucIdx = 0; ucIdx < prParamBssidPool->ucNumBssidPool; ucIdx++) { ++ COPY_MAC_ADDR(prHS20Info->arBssidPool[ucIdx].aucBSSID, &prParamBssidPool->arBSSID[ucIdx]); ++ kalPrint("[%s][%d][ %pM ]\n", __func__, ucIdx, (prHS20Info->arBssidPool[ucIdx].aucBSSID)); ++ } ++ prHS20Info->fgIsHS2SigmaMode = prParamBssidPool->fgIsEnable; ++ prHS20Info->ucNumBssidPoolEntry = prParamBssidPool->ucNumBssidPool; ++ ++#if 0 ++ wlanClearScanningResult(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c +new file mode 100644 +index 000000000000..469a48ebe9c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c +@@ -0,0 +1,111 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/mib.c#1 ++*/ ++ ++/*! \file "mib.c" ++ \brief This file includes the mib default vale and functions. ++*/ ++ ++/* ++** Log: mib.c ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add mib.c. ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[] = { ++ {RATE_SET_HR_DSSS, TRUE, FALSE} ++ , /* For PHY_TYPE_HR_DSSS_INDEX(0) */ ++ {RATE_SET_ERP, TRUE, TRUE} ++ , /* For PHY_TYPE_ERP_INDEX(1) */ ++ {RATE_SET_ERP_P2P, TRUE, TRUE} ++ , /* For PHY_TYPE_ERP_P2P_INDEX(2) */ ++ {RATE_SET_OFDM, FALSE, FALSE} ++ , /* For PHY_TYPE_OFDM_INDEX(3) */ ++}; ++ ++NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[AD_HOC_MODE_NUM] = { ++ {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} ++ , /* For AD_HOC_MODE_11B(0) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} ++ , /* For AD_HOC_MODE_MIXED_11BG(1) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} ++ , /* For AD_HOC_MODE_11G(2) */ ++ {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} ++ , /* For AD_HOC_MODE_11A(3) */ ++}; ++ ++NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[AP_MODE_NUM] = { ++ {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} ++ , /* For AP_MODE_11B(0) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} ++ , /* For AP_MODE_MIXED_11BG(1) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} ++ , /* For AP_MODE_11G(2) */ ++ {PHY_TYPE_ERP_P2P_INDEX, BASIC_RATE_SET_ERP_P2P} ++ , /* For AP_MODE_11G_P2P(3) */ ++ {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} ++ , /* For AP_MODE_11A(4) */ ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c +new file mode 100644 +index 000000000000..cb5fbebedd49 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c +@@ -0,0 +1,87 @@ ++/* ++** Id: @(#) p2p_assoc.c@@ ++*/ ++ ++/*! \file "p2p_assoc.c" ++ \brief This file includes the Wi-Fi Direct association-related functions. ++ ++ This file includes the association-related functions. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for P2P Association ++* Request Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ /* Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ return pucBuffer; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c +new file mode 100644 +index 000000000000..72a20a322cee +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c +@@ -0,0 +1,58 @@ ++/* ++** Id: @(#) p2p_bss.c@@ ++*/ ++ ++/*! \file "p2p_bss.c" ++ \brief This file contains the functions for creating p2p BSS(AP). ++ ++ This file contains the functions for BSS(AP). We may create a BSS ++ network, or merge with exist IBSS network and sending Beacon Frame or reply ++ the Probe Response Frame for received Probe Request Frame. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c +new file mode 100644 +index 000000000000..f8c09e2aa9de +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c +@@ -0,0 +1,3139 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/mgmt/p2p_fsm.c#61 ++*/ ++ ++/*! \file "p2p_fsm.c" ++ \brief This file defines the FSM for P2P Module. ++ ++ This file defines the FSM for P2P Module. ++*/ ++ ++/* ++** Log: p2p_fsm.c ++** ++** 12 20 2012 yuche.tsai ++** [ALPS00410124] [Rose][Free Test][KE][rlmUpdateParamsForAP]The device reboot automatically ++** and then "Fatal/Kernel" pops up during use data service.(Once) ++** Fix possible NULL station record cause KE under AP mode. ++** May due to variable uninitial. ++** Review: http://mtksap20:8080/go?page=NewReview&reviewid=49970 ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected ++**to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 08 21 2012 yuche.tsai ++** NULL ++** fix disconnect indication. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix p2p bug find on ALPS.JB trunk. ++** ++** 07 27 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update for driver unload KE issue. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Fix the compile flag of enhancement. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000808] [Volunteer Patch][MT6620][Driver/FW] Device discoverability issue fix ++ * Change device discoverability methodology. From driver SCAN to FW lock channel. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000833] [Volunteer Patch][WiFi Direct][Driver] Service Discovery Frame RX Indicate Issue ++ * Fix Service Discovery Race Condition Issue. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 21 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix an issue of accepting connection of GO. ++ * ++ * 06 21 2011 yuche.tsai ++ * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability ++ * Drop GAS frame when SD is not enabled. ++ * ++ * 06 20 2011 yuche.tsai ++ * NULL ++ * Fix compile error. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix connection indication twice issue. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000795] [Volunteer Patch][MT6620][Driver] GO can not connect second device issue ++ * Solve P2P GO can not formation with second device issue. ++ * ++ * 06 14 2011 yuche.tsai ++ * NULL ++ * Change disconnect feature. ++ * ++ * 06 10 2011 yuche.tsai ++ * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability[WCXRP00000776] ++ * [Need Patch][MT6620][Driver] MT6620 response probe request of P2P device with P2P IE under Hot Spot mode. ++ * 1. Dynamic enable SD capability after P2P supplicant ready. ++ * 2. Avoid response probe respone with p2p IE when under hot spot mode. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 05 26 2011 yuche.tsai ++ * [WCXRP00000745] Support accepting connection after one Group Connection Lost. ++ ++After Group Formation & lost connection, if MT6620 behave as: ++ ++1. GO: It would keep under GO state until been dissolved by supplicant. ++ ++ At this time, other P2P device can use join method to join this group. ++ ++2. GC: It would keep on searching target GO or target device until been dissolved by supplicant. ++ ++At this time, it would ignore other P2P device formation request. ++ ++-- ++ ++Modification: Make driver to accept GO NEGO REQ at this time, to let user decide to accept new connection or not. ++ ++ * [Volunteer Patch][MT6620][Driver] ++ * Driver would indicate connection request, if password ID is not ready but connection request is issued. ++ * ++ * 05 18 2011 yuche.tsai ++ * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. ++ * A solution for both connection request & IO control. ++ * ++ * 05 16 2011 yuche.tsai ++ * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. ++ * Fix SD request can not send out issue. ++ * ++ * 05 09 2011 terry.wu ++ * [WCXRP00000711] [MT6620 Wi-Fi][Driver] Set Initial value of StaType in StaRec for Hotspot Client ++ * Set initial value of StaType in StaRec for hotspot client. ++ * ++ * 05 04 2011 yuche.tsai ++ * [WCXRP00000697] [Volunteer Patch][MT6620][Driver] ++ * Bug fix for p2p descriptor is NULL if BSS descriptor is found first. ++ * ++ * 05 04 2011 yuche.tsai ++ * NULL ++ * Support partial persistent group function. ++ * ++ * 05 02 2011 yuche.tsai ++ * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. ++ * Clear formation flag after formation timeout. ++ * ++ * 04 20 2011 yuche.tsai ++ * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition ++ * when add scan & query scan result at the same time. ++ * Fix side effect while starting ATGO. ++ * ++ * 04 20 2011 yuche.tsai ++ * NULL ++ * Fix ASSERT issue in FW, side effect of last change. ++ * ++ * 04 19 2011 yuche.tsai ++ * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition ++ * when add scan & query scan result at the same time. ++ * Workaround for multiple device connection, before invitation ready. ++ * ++ * 04 19 2011 yuche.tsai ++ * [WCXRP00000665] [Wifi Direct][MT6620 E4] When use Ralink's dongle to establish wifi direct connection with PBC. ++ * But 6573 always not pop accept option to establish connection. ++ * Support connection indication when GO NEGO REQ doesn't have configure method, instead it has PasswordID. ++ * ++ * 04 18 2011 yuche.tsai ++ * NULL ++ * Fix error. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Fix a connection issue. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Fix the channel issue of AP mode. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Connection flow refine for Sigma test. ++ * ++ * 04 09 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix Device discoverability related issue. ++ * ++ * 04 09 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix bug for Device Discoverability. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix compile error. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 03 28 2011 yuche.tsai ++ * NULL ++ * Fix a possible issue for retry join when media status connected. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 24 2011 yuche.tsai ++ * NULL ++ * Assign AID before change STA_REC state to state 3. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix Response Rate Issue when TX Auth Rsp Frame under P2P Mode. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix issue of connection to one GC. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix ASSERT issue when starting Hot-spot. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * When Target Information is not available, change to passive mode. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Fix one connection issue while using Keypad to connect a GO. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1. Fix two issues that may cause kernel panic. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Fix GC connect to other device issue. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1.Shorten the LISTEN interval. ++ * 2. Fix IF address issue when we are GO ++ * 3. Fix LISTEN channel issue. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Modify formation policy setting. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Solve Listen State doesn't response probe response issue. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Change P2P Connection Request Flow. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue ++ * Indicate the correct Group SSID when join on Group. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue ++ * Support the third P2P device to join GO/GC group. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000578] [Volunteer Patch][MT6620][Driver] Separate Connection Request from general IOCTL ++ * Separate connection request from general IOCTL. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * When AIS is connect to an AP, Hot Spot would be enabled under fixed same channel. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Solve the Group Info IE in Probe Response incorrect issue. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Release Channel after Join Complete. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix local configure method issue. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 14 2011 yuche.tsai ++ * NULL ++ * . ++ * ++ * 03 14 2011 yuche.tsai ++ * NULL ++ * Fix password ID issue. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 08 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue[WCXRP00000509] ++ * [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. ++ * . ++ * ++ * 03 07 2011 yuche.tsai ++ * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 04 2011 wh.su ++ * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue ++ * fixed the p2p action frame type check for device request indication. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Service Discovery RX packet buffer pointer. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 21 2011 yuche.tsai ++ * [WCXRP00000481] [Volunteer Patch][MT6620][FW] Scan hang under concurrent case. ++ * Fix all BE issue of WSC or P2P IE. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the wsc config method mapping to driver used config method issue. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000479] [Volunteer Patch][MT6620][Driver] Probe Response of P2P using 11b rate. ++ * Update basic rate to FW, after P2P is initialed. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame during search ++ * phase do not contain P2P wildcard SSID. ++ * Use P2P Wildcard SSID when scan type of P2P_WILDCARD_SSID is set. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC IE BE format issue. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 16 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * fixed the probe request send out without WSC IE issue (at P2P). ++ * ++ * 02 16 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * If two station connected to the Hot-Spot and one disconnect, FW would get into an infinite loop ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix re-connection issue after RX deauthentication. ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix conneciton issue after disconnect with AP. ++ * ++ * 02 12 2011 yuche.tsai ++ * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. ++ * P2P Create Station Type according to Target BSS capability. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Support Disassoc & Deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect ++ * to target station for AAA module. ++ * Disconnect every station client when disolve on P2P group. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * 1. Fix Service Disocvery Logical issue. ++ * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect ++ * to target station for AAA module. ++ * Workaround of disable P2P network. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue ++ * 1. Fixed SSID wrong length issue. ++ * 2. Under Hot Spot configuration, there won't be any P2P IE. ++ * 3. Under Hot Spot configuration, P2P FSM won't get into LISTEN state first. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Modify Start GO flow. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix desire phy type set issue. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Add desire phy type set phase I. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix P2P Disconnect Issue. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix compile error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type Definition. ++ * ++ * 01 19 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Add P2P QoS Support. ++ * ++ * 01 19 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Null NOA attribute setting when no related parameters. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify AAA flow according to CM's comment. ++ * ++ * 01 13 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Resolve Channel ZERO issue. (Uninitialized default channel) ++ * ++ * 01 13 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Update P2P State Debug Message. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Fix bug when allocating message buffer. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Phy Type Set. When legacy client is connected, it can use 11b rate, ++ * but if the P2P device is connected, 11b rate is not allowed. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. ++ * 2. Call cnmP2pIsPermit() before active P2P network. ++ * 3. Add channel selection support for AP mode. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix Bug of reference to NULL pointer. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify some behavior of AP mode. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix bug of wrong pointer check. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix Compile Error. ++ * ++ * 01 11 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Add station record into client list before change it state from STATE_2 to STATE_3. ++ * ++ * 01 05 2011 yuche.tsai ++ * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, ++ * but the SSID length is still invalid. ++ * Specify SSID Type when issue a scan request. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * correct typo ++ * ++ * 01 05 2011 george.huang ++ * [WCXRP00000343] [MT6620 Wi-Fi] Add TSF reset path for concurrent operation ++ * modify NOA update path for preventing assertion false alarm. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 01 03 2011 wh.su ++ * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * let the p2p ap mode acept a legacy device join. ++ * ++ * 12 22 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Compile Error. ++ * ++ * 12 15 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Refine Connection Flow. ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. ++ * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client ++ * by checking the P2P IE in assoc req frame. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * The order of invoking nicUpdateBss() and rlm functions ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation & Provision Discovery. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update RCIP value when RX assoc request frame. ++ * ++ * 11 29 2010 yuche.tsai ++ * NULL ++ * Update P2P related function for INVITATION & PROVISION DISCOVERY. ++ * ++ * 11 26 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Update P2P PS for NOA function. ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update Code for Invitation Related Function. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] ++ * Set the Tx lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * fixed the p2p role code error. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * fixed the ASSERT check error ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 19 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state ++ * machine[WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * fixed the compiling error. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * adding a code to support Direct GO with a compiling flag . ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. ++ * correct erroneous logic: specifying eBand with incompatible eSco ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * fixed the compiling error. ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at WinXP. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Reset Common IE Buffer of P2P INFO when scan request is issued. ++ * If an action frame other than public action frame is received, return direcly. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add P2P Connection Abort Event Message handler. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 yuche.tsai ++ * NULL ++ * 1. Fix Interface Address from GO Nego Req/Rsp is not correct. ++ * 2. Fix GO mode does not change media state after station connected. ++ * 3. Fix STA don't response probe request when there is a connection request. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Add Glue Layer indication. ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix compile warning under Linux. ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix some P2P FSM bug. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add random Interface Address Generation support. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix some P2P FSM bug. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM code for GO Nego. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Join complete indication. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add two boolean in connection request. ++ * Based on these two boolean value, P2P FSM should ++ * decide to do invitation or group formation or start a GO directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM, currently P2P Device Discovery is verified. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM for group formation. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * limit build always needs spin-lock declaration. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add P2P FSM code check in. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Update P2P FSM. ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error while enable WIFI_DIRECT support. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Update P2P Function call. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename CFG flag for P2P ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add code to test P2P GO ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add Wi-Fi Direct SSID and P2P GO Test Mode ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify code due to BAND_24G define was changed ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugP2pState[P2P_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("P2P_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("P2P_STATE_SCAN"), ++ (PUINT_8) DISP_STRING("P2P_STATE_AP_CHANNEL_DETECT"), ++ (PUINT_8) DISP_STRING("P2P_STATE_REQING_CHANNEL"), ++ (PUINT_8) DISP_STRING("P2P_STATE_CHNL_ON_HAND"), ++ (PUINT_8) DISP_STRING("P2P_STATE_GC_JOIN") ++}; ++ ++/*lint -restore */ ++#else ++static UINT_8 apucDebugP2pState[P2P_STATE_NUM] = { ++ P2P_STATE_IDLE, ++ P2P_STATE_SCAN, ++ P2P_STATE_AP_CHANNEL_DETECT, ++ P2P_STATE_REQING_CHANNEL, ++ P2P_STATE_CHNL_ON_HAND, ++ P2P_STATE_GC_JOIN ++}; ++ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* p2pStateXXX : Processing P2P FSM related action. ++ * p2pFSMXXX : Control P2P FSM flow. ++ * p2pFuncXXX : Function for doing one thing. ++ */ ++VOID p2pFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ ASSERT_BREAK(prP2pFsmInfo != NULL); ++ ++ LINK_INITIALIZE(&(prP2pFsmInfo->rMsgEventQueue)); ++ LINK_INITIALIZE(&(prP2pBssInfo->rStaRecOfClientList)); ++ ++ prP2pFsmInfo->eCurrentState = prP2pFsmInfo->ePreviousState = P2P_STATE_IDLE; ++ prP2pFsmInfo->prTargetBss = NULL; ++ prP2pFsmInfo->fgIsWPSMode = 0; ++ ++ cnmTimerInitTimer(prAdapter, ++ &(prAdapter->rP2pFsmTimeoutTimer), ++ (PFN_MGMT_TIMEOUT_FUNC) p2pFsmRunEventFsmTimeout, (ULONG) prP2pFsmInfo); ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <2.1> Initiate BSS_INFO_T - Setup HW ID */ ++ prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; ++ prP2pBssInfo->ucHwDefaultFixedRateCode = RATE_OFDM_6M; ++ ++ prP2pBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prP2pBssInfo->u2BSSBasicRateSet = ++ rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prP2pBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prP2pBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prP2pBssInfo->u2OperationalRateSet, ++ prP2pBssInfo->u2BSSBasicRateSet, ++ prP2pBssInfo->aucAllSupportedRates, &prP2pBssInfo->ucAllSupportedRatesLen); ++ ++ prP2pBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prP2pBssInfo->prBeacon) { ++ prP2pBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prP2pBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ ++ prP2pBssInfo->prBeacon->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } else { ++ /* Out of memory. */ ++ ASSERT(FALSE); ++ } ++ ++ prP2pBssInfo->eCurrentOPMode = OP_MODE_NUM; ++ ++ prP2pBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prP2pBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prP2pBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++ prP2pBssInfo->ucPrimaryChannel = P2P_DEFAULT_LISTEN_CHANNEL; ++ prP2pBssInfo->eBand = BAND_2G4; ++ prP2pBssInfo->eBssSCO = CHNL_EXT_SCN; ++ ++ if (prAdapter->rWifiVar.fgSupportQoS) ++ prP2pBssInfo->fgIsQBSS = TRUE; ++ else ++ prP2pBssInfo->fgIsQBSS = FALSE; ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } while (FALSE); ++ ++} /* p2pFsmInit */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function is used to uninitialize the value in P2P_FSM_INFO_T for ++* P2P FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ DEBUGFUNC("p2pFsmUninit()"); ++ DBGLOG(P2P, INFO, "->p2pFsmUninit()\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, OP_MODE_P2P_DEVICE, TRUE); ++ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, P2P_STATE_NUM); ++ ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ wlanAcquirePowerControl(prAdapter); ++ ++ /* Release all pending CMD queue. */ ++ DBGLOG(P2P, TRACE, "p2pFsmUninit: wlanProcessCommandQueue, num of element:%d\n", ++ (UINT_32) prAdapter->prGlueInfo->rCmdQueue.u4NumElem); ++ wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); ++ ++ wlanReleasePowerControl(prAdapter); ++ ++ /* Release pending mgmt frame, ++ * mgmt frame may be pending by CMD without resource. ++ */ ++ kalClearMgmtFramesByNetType(prAdapter->prGlueInfo, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Clear PendingCmdQue */ ++ wlanReleasePendingCMDbyNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ if (prP2pBssInfo->prBeacon) { ++ cnmMgtPktFree(prAdapter, prP2pBssInfo->prBeacon); ++ prP2pBssInfo->prBeacon = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* end of p2pFsmUninit() */ ++ ++VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ BOOLEAN fgIsTransOut = (BOOLEAN) FALSE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (!IS_BSS_ACTIVE(prP2pBssInfo)) { ++ if (!cnmP2PIsPermitted(prAdapter)) ++ return; ++ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ fgIsTransOut = fgIsTransOut ? FALSE : TRUE; ++ ++ if (!fgIsTransOut) { ++#if DBG ++ DBGLOG(P2P, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugP2pState[prP2pFsmInfo->eCurrentState], ++ apucDebugP2pState[eNextState]); ++#else ++ DBGLOG(P2P, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_P2P_IDX, apucDebugP2pState[prP2pFsmInfo->eCurrentState], ++ apucDebugP2pState[eNextState]); ++#endif ++ ++ /* Transition into current state. */ ++ prP2pFsmInfo->ePreviousState = prP2pFsmInfo->eCurrentState; ++ prP2pFsmInfo->eCurrentState = eNextState; ++ } ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_IDLE: ++ if (fgIsTransOut) ++ p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, eNextState); ++ else ++ fgIsTransOut = p2pStateInit_IDLE(prAdapter, prP2pFsmInfo, prP2pBssInfo, &eNextState); ++ break; ++ case P2P_STATE_SCAN: ++ if (fgIsTransOut) { ++ /* Scan done / scan canceled. */ ++ p2pStateAbort_SCAN(prAdapter, prP2pFsmInfo, eNextState); ++ } else { ++ /* Initial scan request. */ ++ p2pStateInit_SCAN(prAdapter, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_AP_CHANNEL_DETECT: ++ if (fgIsTransOut) { ++ /* Scan done */ ++ /* Get sparse channel result. */ ++ p2pStateAbort_AP_CHANNEL_DETECT(prAdapter, ++ prP2pFsmInfo, prP2pSpecificBssInfo, eNextState); ++ } ++ ++ else { ++ /* Initial passive scan request. */ ++ p2pStateInit_AP_CHANNEL_DETECT(prAdapter, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_REQING_CHANNEL: ++ if (fgIsTransOut) { ++ /* Channel on hand / Channel canceled. */ ++ p2pStateAbort_REQING_CHANNEL(prAdapter, prP2pFsmInfo, eNextState); ++ } else { ++ /* Initial channel request. */ ++ p2pFuncAcquireCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ break; ++ case P2P_STATE_CHNL_ON_HAND: ++ if (fgIsTransOut) { ++ p2pStateAbort_CHNL_ON_HAND(prAdapter, prP2pFsmInfo, prP2pBssInfo, eNextState); ++ } else { ++ /* Initial channel ready. */ ++ /* Send channel ready event. */ ++ /* Start a FSM timer. */ ++ p2pStateInit_CHNL_ON_HAND(prAdapter, prP2pBssInfo, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_GC_JOIN: ++ if (fgIsTransOut) { ++ /* Join complete / join canceled. */ ++ p2pStateAbort_GC_JOIN(prAdapter, prP2pFsmInfo, &(prP2pFsmInfo->rJoinInfo), eNextState); ++ } else { ++ if (prP2pFsmInfo->prTargetBss == NULL) { ++ ASSERT(FALSE); ++ } else { ++ /* Send request to SAA module. */ ++ p2pStateInit_GC_JOIN(prAdapter, ++ prP2pFsmInfo, ++ prP2pBssInfo, ++ &(prP2pFsmInfo->rJoinInfo), prP2pFsmInfo->prTargetBss); ++ } ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ } while (fgIsTransOut); ++ ++} /* p2pFsmStateTransition */ ++ ++VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prSwitchOpMode = (P_MSG_P2P_SWITCH_OP_MODE_T) prMsgHdr; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwitchOpMode != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventSwitchOPMode\n"); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prSwitchOpMode->eOpMode >= OP_MODE_NUM) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ /* P2P Device / GC. */ ++ p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, prSwitchOpMode->eOpMode, TRUE); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventSwitchOPMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle scan done event during Device Discovery. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) NULL; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ /* This scan done event is either for "SCAN" phase or "SEARCH" state or "LISTEN" state. ++ * The scan done for SCAN phase & SEARCH state doesn't imply Device ++ * Discovery over. ++ */ ++ DBGLOG(P2P, TRACE, "P2P Scan Done Event\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ ++ if (prScanDoneMsg->ucSeqNum != prScanReqInfo->ucSeqNumOfScnMsg) { ++ /* Scan Done message sequence number mismatch. ++ * Ignore this event. (P2P FSM issue two scan events.) ++ */ ++ /* The scan request has been cancelled. ++ * Ignore this message. It is possible. ++ */ ++ DBGLOG(P2P, TRACE, "P2P Scan Don SeqNum:%d <-> P2P Fsm SCAN Msg:%d\n", ++ prScanDoneMsg->ucSeqNum, prScanReqInfo->ucSeqNumOfScnMsg); ++ ++ break; ++ } ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_SCAN: ++ { ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ prScanReqInfo->fgIsAbort = FALSE; ++ ++ if (prConnReqInfo->fgIsConnRequest) { ++ prP2pFsmInfo->prTargetBss = p2pFuncKeepOnConnection(prAdapter, ++ &prP2pFsmInfo->rConnReqInfo, ++ &prP2pFsmInfo->rChnlReqInfo, ++ &prP2pFsmInfo->rScanReqInfo); ++ if (prP2pFsmInfo->prTargetBss == NULL) ++ eNextState = P2P_STATE_SCAN; ++ else ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ } else { ++ eNextState = P2P_STATE_IDLE; ++ } ++ ++ } ++ break; ++ case P2P_STATE_AP_CHANNEL_DETECT: ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ break; ++ default: ++ /* Unexpected channel scan done event without being chanceled. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanReqInfo->fgIsScanRequest = FALSE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when channel is granted by CNM module from FW. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T) NULL; ++ UINT_8 ucTokenID = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "P2P Run Event Channel Grant\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ucTokenID = prMsgChGrant->ucTokenID; ++ prP2pFsmInfo->u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ if (ucTokenID == prChnlReqInfo->ucSeqNumOfChReq) { ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_REQING_CHANNEL: ++ switch (prChnlReqInfo->eChannelReqType) { ++ case CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL: ++ eNextState = P2P_STATE_CHNL_ON_HAND; ++ break; ++ case CHANNEL_REQ_TYPE_GC_JOIN_REQ: ++ eNextState = P2P_STATE_GC_JOIN; ++ break; ++ case CHANNEL_REQ_TYPE_GO_START_BSS: ++ eNextState = P2P_STATE_IDLE; ++ break; ++ default: ++ break; ++ } ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ break; ++ default: ++ /* Channel is granted under unexpected state. ++ * Driver should cancel channel privileagea before leaving the states. ++ */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } else { ++ /* Channel requsted, but released. */ ++ /* ASSERT(!prChnlReqInfo->fgIsChannelRequested); */ ++ DBGLOG(P2P, TRACE, "Channel requsted, but released\n"); ++ } ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventChGrant */ ++ ++VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_P2P_CHNL_REQUEST_T prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) prMsgHdr; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelRequest\n"); ++ ++ /* Special case of time renewing for same frequency. */ ++ if ((prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) && ++ (prChnlReqInfo->ucReqChnlNum == prP2pChnlReqMsg->rChannelInfo.ucChannelNum) && ++ (prChnlReqInfo->eBand == prP2pChnlReqMsg->rChannelInfo.eBand) && ++ (prChnlReqInfo->eChnlSco == prP2pChnlReqMsg->eChnlSco)) { ++ ++ ASSERT(prChnlReqInfo->fgIsChannelRequested == TRUE); ++ ASSERT(prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL); ++ ++ prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; ++ prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; ++ ++ /* Re-enter the state. */ ++ eNextState = P2P_STATE_CHNL_ON_HAND; ++ } else { ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ /* Cookie can only be assign after abort.(for indication) */ ++ prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; ++ prChnlReqInfo->ucReqChnlNum = prP2pChnlReqMsg->rChannelInfo.ucChannelNum; ++ prChnlReqInfo->eBand = prP2pChnlReqMsg->rChannelInfo.eBand; ++ prChnlReqInfo->eChnlSco = prP2pChnlReqMsg->eChnlSco; ++ prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL; ++ ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ } ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventChannelRequest */ ++ ++VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_CHNL_ABORT_T prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) prMsgHdr; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelAbort\n"); ++ ++ if ((prChnlAbortMsg->u8Cookie == prChnlReqInfo->u8Cookie) && (prChnlReqInfo->fgIsChannelRequested)) { ++ ++ ASSERT((prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL || ++ (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND))); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventChannelAbort */ ++ ++VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) NULL; ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ UINT_32 u4ChnlListSize = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) prMsgHdr; ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventScanRequest\n"); ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ ASSERT(prScanReqInfo->fgIsScanRequest == FALSE); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; ++ ++ /* Channel List */ ++ prScanReqInfo->ucNumChannelList = prP2pScanReqMsg->u4NumChannel; ++ DBGLOG(P2P, TRACE, "Scan Request Channel List Number: %d\n", prScanReqInfo->ucNumChannelList); ++ if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { ++ DBGLOG(P2P, TRACE, "Channel List Number Overloaded: %d, change to: %d\n", ++ prScanReqInfo->ucNumChannelList, MAXIMUM_OPERATION_CHANNEL_LIST); ++ prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; ++ } ++ ++ u4ChnlListSize = sizeof(RF_CHANNEL_INFO_T) * prScanReqInfo->ucNumChannelList; ++ kalMemCopy(prScanReqInfo->arScanChannelList, prP2pScanReqMsg->arChannelListInfo, u4ChnlListSize); ++ ++ /* TODO: I only take the first SSID. Multiple SSID may be needed in the future. */ ++ /* SSID */ ++ if (prP2pScanReqMsg->i4SsidNum >= 1) ++ kalMemCopy(&(prScanReqInfo->rSsidStruct), prP2pScanReqMsg->prSSID, sizeof(P2P_SSID_STRUCT_T)); ++ else ++ prScanReqInfo->rSsidStruct.ucSsidLen = 0; ++ ++ /* IE Buffer */ ++ kalMemCopy(prScanReqInfo->aucIEBuf, prP2pScanReqMsg->pucIEBuf, prP2pScanReqMsg->u4IELen); ++ ++ prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanRequest */ ++ ++VOID p2pFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventScanAbort\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanAbort */ ++ ++VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventAbort\n"); ++ ++ if (prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { ++ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ } else if (prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL) { ++ /* 2012/08/06: frog ++ * Prevent Start GO. ++ */ ++ prP2pBssInfo->eIntendOPMode = OP_MODE_NUM; ++ } ++ /* For other state, is there any special action that should be take before leaving? */ ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } else { ++ /* P2P State IDLE. */ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ if (prChnlReqInfo->fgIsChannelRequested) ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventAbort */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle FSM Timeout. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) ulParam; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ DBGLOG(P2P, TRACE, "P2P FSM Timeout Event\n"); ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_IDLE: ++ { ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ } else if (IS_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } ++ break; ++ ++/* case P2P_STATE_SCAN: */ ++/* break; */ ++/* case P2P_STATE_AP_CHANNEL_DETECT: */ ++/* break; */ ++/* case P2P_STATE_REQING_CHANNEL: */ ++/* break; */ ++ case P2P_STATE_CHNL_ON_HAND: ++ switch (prP2pFsmInfo->eListenExted) { ++ case P2P_DEV_NOT_EXT_LISTEN: ++ case P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT: ++ DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", ++ prP2pFsmInfo->eListenExted); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ break; ++ case P2P_DEV_EXT_LISTEN_ING: ++ DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", ++ prP2pFsmInfo->eListenExted); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_CHNL_ON_HAND); ++ prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT; ++ break; ++ default: ++ ASSERT(FALSE); ++ DBGLOG(P2P, ERROR, ++ "Current P2P State %d is unexpected for FSM timeout event.\n", ++ prP2pFsmInfo->eCurrentState); ++ } ++ break; ++/* case P2P_STATE_GC_JOIN: */ ++/* break; */ ++ default: ++ break; ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventFsmTimeout */ ++ ++VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventMgmtFrameTx\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) prMsgHdr; ++ ++ p2pFuncTxMgmtFrame(prAdapter, ++ &prP2pFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventMgmtTx */ ++ ++VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventStartAP\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) prMsgHdr; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (prP2pStartAPMsg->u4BcnInterval) { ++ DBGLOG(P2P, TRACE, "Beacon interval updated to :%u\n", prP2pStartAPMsg->u4BcnInterval); ++ prP2pBssInfo->u2BeaconInterval = (UINT_16) prP2pStartAPMsg->u4BcnInterval; ++ } else if (prP2pBssInfo->u2BeaconInterval == 0) { ++ prP2pBssInfo->u2BeaconInterval = DOT11_BEACON_PERIOD_DEFAULT; ++ } ++ ++ if (prP2pStartAPMsg->u4DtimPeriod) { ++ DBGLOG(P2P, TRACE, "DTIM interval updated to :%u\n", prP2pStartAPMsg->u4DtimPeriod); ++ prP2pBssInfo->ucDTIMPeriod = (UINT_8) prP2pStartAPMsg->u4DtimPeriod; ++ } else if (prP2pBssInfo->ucDTIMPeriod == 0) { ++ prP2pBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ } ++ ++ if (prP2pStartAPMsg->u2SsidLen != 0) { ++ kalMemCopy(prP2pBssInfo->aucSSID, prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen); ++ kalMemCopy(prP2pSpecificBssInfo->aucGroupSsid, prP2pStartAPMsg->aucSsid, ++ prP2pStartAPMsg->u2SsidLen); ++ prP2pBssInfo->ucSSIDLen = prP2pSpecificBssInfo->u2GroupSsidLen = prP2pStartAPMsg->u2SsidLen; ++ } ++ ++ prP2pBssInfo->eHiddenSsidType = prP2pStartAPMsg->ucHiddenSsidType; ++ ++ /* TODO: JB */ ++ /* Privacy & inactive timeout. */ ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { ++ UINT_8 ucPreferedChnl = 0; ++ ENUM_BAND_T eBand = BAND_NULL; ++ ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_SCAN; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prP2pFsmInfo->eCurrentState != P2P_STATE_SCAN && ++ prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ } ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; ++ DBGLOG(P2P, INFO, ++ "NFC:p2pFsmRunEventStartAP,fgIsGOInitialDone[%d]\n", ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); ++ ++ /* 20120118: Moved to p2pFuncSwitchOPMode(). */ ++ /* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Leave IDLE state. */ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* sync with firmware */ ++ /* DBGLOG(P2P, INFO, ("Activate P2P Network.\n")); */ ++ /* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Key to trigger P2P FSM to allocate channel for AP mode. */ ++ prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; ++ ++ /* Sparse Channel to decide which channel to use. */ ++ if ((cnmPreferredChannel(prAdapter, ++ &eBand, ++ &ucPreferedChnl, ++ &eSco) == FALSE) && (prP2pConnSettings->ucOperatingChnl == 0)) { ++ /* Sparse Channel Detection using passive mode. */ ++ eNextState = P2P_STATE_AP_CHANNEL_DETECT; ++ } else { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = ++ prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++#if 1 ++ /* 2012-01-27: frog - Channel set from upper layer is the first priority. */ ++ /* Because the channel & beacon is decided by p2p_supplicant. */ ++ if (prP2pConnSettings->ucOperatingChnl != 0) { ++ prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; ++ prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; ++ } ++ ++ else { ++ ASSERT(ucPreferedChnl != 0); ++ prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prP2pSpecificBssInfo->eRfBand = eBand; ++ } ++#else ++ if (ucPreferedChnl) { ++ prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prP2pSpecificBssInfo->eRfBand = eBand; ++ } else { ++ ASSERT(prP2pConnSettings->ucOperatingChnl != 0); ++ prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; ++ prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; ++ } ++ ++#endif ++ prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel; ++ prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventStartAP GO Scan\n"); ++ } ++ ++ /* If channel is specified, use active scan to shorten the scan time. */ ++ p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, eNextState); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventStartAP */ ++ ++VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_NETDEV_REGISTER_T prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventNetDeviceRegister\n"); ++ ++ prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) prMsgHdr; ++ ++ if (prNetDevRegisterMsg->fgIsEnable) { ++ p2pSetMode((prNetDevRegisterMsg->ucMode == 1) ? TRUE : FALSE); ++ ++ if (p2pLaunch(prAdapter->prGlueInfo)) ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ } else { ++ if (prAdapter->fgIsP2PRegistered) ++ p2pRemove(prAdapter->prGlueInfo); ++ ++ } ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventNetDeviceRegister */ ++ ++VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_MGMT_FRAME_UPDATE_T prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventUpdateMgmtFrame\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) prMsgHdr; ++ ++ switch (prP2pMgmtFrameUpdateMsg->eBufferType) { ++ case ENUM_FRAME_TYPE_EXTRA_IE_BEACON: ++ break; ++ case ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP: ++ break; ++ case ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP: ++ break; ++ case ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE: ++ break; ++ case ENUM_FRAME_TYPE_BEACON_TEMPLATE: ++ break; ++ default: ++ break; ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventUpdateMgmtFrame */ ++ ++VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_BEACON_UPDATE_T prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconUpdate\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) prMsgHdr; ++ ++ p2pFuncBeaconUpdate(prAdapter, ++ prP2pBssInfo, ++ &prP2pFsmInfo->rBcnContentInfo, ++ prBcnUpdateMsg->pucBcnHdr, ++ prBcnUpdateMsg->u4BcnHdrLen, ++ prBcnUpdateMsg->pucBcnBody, prBcnUpdateMsg->u4BcnBodyLen); ++ ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && ++ (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { ++ /* AP is created, Beacon Update. */ ++ /* nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventBeaconUpdate */ ++ ++VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventStopAP\n"); ++ ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ && (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { ++ /* AP is created, Beacon Update. */ ++ ++ p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); ++ ++ DBGLOG(P2P, TRACE, "Stop Beaconing\n"); ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Reset RLM related field of BSSINFO. */ ++ rlmBssAborted(prAdapter, prP2pBssInfo); ++ } ++ /* 20120118: Moved to p2pFuncSwitchOPMode(). */ ++ /* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Enter IDLE state. */ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ DBGLOG(P2P, INFO, "Re activate P2P Network.\n"); ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++#if CFG_SUPPORT_WFD ++ p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); ++#endif ++ ++ /* p2pFsmRunEventAbort(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo); */ ++ p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventStopAP */ ++ ++VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) prMsgHdr; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionRequest\n"); ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ break; ++ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ /* Update connection request information. */ ++ prConnReqInfo->fgIsConnRequest = TRUE; ++ COPY_MAC_ADDR(prConnReqInfo->aucBssid, prConnReqMsg->aucBssid); ++ kalMemCopy(&(prConnReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); ++ kalMemCopy(prConnReqInfo->aucIEBuf, prConnReqMsg->aucIEBuf, prConnReqMsg->u4IELen); ++ prConnReqInfo->u4BufLength = prConnReqMsg->u4IELen; ++ ++ /* Find BSS Descriptor first. */ ++ prP2pFsmInfo->prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); ++ ++ if (prP2pFsmInfo->prTargetBss == NULL) { ++ /* Update scan parameter... to scan target device. */ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest,Trigger New Scan\n"); ++ ++ prScanReqInfo->ucNumChannelList = 1; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; ++ prScanReqInfo->arScanChannelList[0].ucChannelNum = prConnReqMsg->rChannelInfo.ucChannelNum; ++ kalMemCopy(&(prScanReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); ++ prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ } else { ++ prChnlReqInfo->u8Cookie = 0; ++ prChnlReqInfo->ucReqChnlNum = prConnReqMsg->rChannelInfo.ucChannelNum; ++ prChnlReqInfo->eBand = prConnReqMsg->rChannelInfo.eBand; ++ prChnlReqInfo->eChnlSco = prConnReqMsg->eChnlSco; ++ prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; ++ DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest, Report the Connecting BSS Again.\n"); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_REQING_CHANNEL); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventConnectionRequest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle Connection Request from Supplicant. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ /* P_STA_RECORD_T prTargetStaRec = (P_STA_RECORD_T)NULL; */ ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionAbort: Connection Abort.\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) prMsgHdr; ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ { ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ ++ if (!prP2pBssInfo->prStaRecOfAP) { ++ DBGLOG(P2P, TRACE, "GO's StaRec is NULL\n"); ++ break; ++ } ++ if (UNEQUAL_MAC_ADDR(prP2pBssInfo->prStaRecOfAP->aucMacAddr, prDisconnMsg->aucTargetID) ++ && UNEQUAL_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCBSSID)) { ++ DBGLOG(P2P, TRACE, ++ "Unequal MAC ADDR [ %pM : %pM ]\n", ++ prP2pBssInfo->prStaRecOfAP->aucMacAddr, ++ prDisconnMsg->aucTargetID); ++ break; ++ } ++ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, 0, ++ WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); ++ ++ /* Stop rejoin timer if it is started. */ ++ /* TODO: If it has. */ ++ ++ p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, prDisconnMsg->fgSendDeauth, ++ prDisconnMsg->u2ReasonCode); ++ ++ /* prTargetStaRec = prP2pBssInfo->prStaRecOfAP; */ ++ ++ /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). */ ++ /* hit prStaRecOfAP == NULL. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ /* Search specific client device, and disconnect. */ ++ /* 1. Send deauthentication frame. */ ++ /* 2. Indication: Device disconnect. */ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ DBGLOG(P2P, TRACE, ++ "Disconnecting with Target ID: %pM\n", ++ prDisconnMsg->aucTargetID); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prDisconnMsg->aucTargetID)) { ++ ++ DBGLOG(P2P, TRACE, ++ "Disconnecting: %pM\n", ++ prCurrStaRec->aucMacAddr); ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Glue layer indication. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ ++ ++ /* Send deauth & do indication. */ ++ p2pFuncDisconnect(prAdapter, prCurrStaRec, prDisconnMsg->fgSendDeauth, ++ prDisconnMsg->u2ReasonCode); ++ ++ /* prTargetStaRec = prCurrStaRec; */ ++ ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } while (FALSE); ++ ++ /* 20120830 moved into p2pFuncDisconnect() */ ++ /* if ((!prDisconnMsg->fgSendDeauth) && (prTargetStaRec)) { */ ++ /* cnmStaRecFree(prAdapter, prTargetStaRec, TRUE); */ ++ /* } */ ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventConnectionAbort */ ++ ++VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ /* TODO: */ ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventDissolve\n"); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++WLAN_STATUS ++p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ DBGLOG(P2P, INFO, "Deauth TX Done Status: %d, seqNo %d\n", ++ rTxDoneStatus, prMsduInfo->ucTxSeqNum); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec == NULL) { ++ DBGLOG(P2P, TRACE, "Station Record NULL, Index:%d\n", prMsduInfo->ucStaRecIndex); ++ break; ++ } ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ eOriMediaStatus = prP2pBssInfo->eConnectionState; ++ /* Change station state. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* Reset Station Record Status. */ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ /**/ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { ++ DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ } ++ ++ /* Because the eConnectionState is changed before Deauth TxDone. Dont Check eConnectionState */ ++ /* if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { */ ++ /* Update Disconnected state to FW. */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ /* } */ ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* p2pFsmRunEventDeauthTxDone */ ++ ++WLAN_STATUS ++p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_P2P_MGMT_TX_REQ_INFO_T) NULL; ++ BOOLEAN fgIsSuccess = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prMgmtTxReqInfo = &(prP2pFsmInfo->rMgmtTxInfo); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(P2P, INFO, "Mgmt Frame TX Fail, Status: %d, seq NO. %d, Cookie: 0x%llx\n", ++ rTxDoneStatus, prMsduInfo->ucTxSeqNum, prMgmtTxReqInfo->u8Cookie); ++ } else { ++ fgIsSuccess = TRUE; ++ DBGLOG(P2P, TRACE, "Mgmt Frame TX Done.\n"); ++ } ++ ++ if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { ++ kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ fgIsSuccess, ++ prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); ++ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* p2pFsmRunEventMgmtFrameTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called when JOIN complete message event is received from SAA. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; ++ P_MSG_JOIN_COMP_T prJoinCompMsg = (P_MSG_JOIN_COMP_T) NULL; ++ P_SW_RFB_T prAssocRspSwRfb = (P_SW_RFB_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ DBGLOG(P2P, TRACE, "P2P Join Complete\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ if (prP2pFsmInfo == NULL) { ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ prJoinInfo = &(prP2pFsmInfo->rJoinInfo); ++ if (prMsgHdr == NULL) ++ return; ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRec = prJoinCompMsg->prStaRec; ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prJoinInfo->ucSeqNumOfReqMsg) { ++ ASSERT(prStaRec == prJoinInfo->prTargetStaRec); ++ prJoinInfo->fgIsJoinComplete = TRUE; ++ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prP2pBssInfo->prStaRecOfAP) && (prP2pBssInfo->prStaRecOfAP != prStaRec)) { ++ cnmStaRecChangeState(prAdapter, prP2pBssInfo->prStaRecOfAP, ++ STA_STATE_1); ++ ++ cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ p2pFuncUpdateBssInfoForJOIN(prAdapter, prP2pFsmInfo->prTargetBss, prStaRec, ++ prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DBGLOG(P2P, INFO, "P2P GC Join Success\n"); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ /* <1.5> Update RSSI if necessary */ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, ++ (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); ++#endif ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ ++ /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, */ ++ /* prStaRec->aucMacAddr); */ ++ if (prP2pFsmInfo->prTargetBss) ++ scanReportBss2Cfg80211(prAdapter, OP_MODE_P2P_DEVICE, ++ prP2pFsmInfo->prTargetBss); ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ &prP2pFsmInfo->rConnReqInfo, ++ prJoinInfo->aucIEBuf, prJoinInfo->u4BufLength, ++ prStaRec->u2StatusCode, ++ WLAN_STATUS_MEDIA_CONNECT); ++ ++ } else { ++ /* Join Fail */ ++ /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ ++ if (p2pFuncRetryJOIN(prAdapter, prStaRec, prJoinInfo) == FALSE) { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ prBssDesc = prP2pFsmInfo->prTargetBss; ++ ++ ASSERT(prBssDesc); ++ ASSERT(prBssDesc->fgIsConnecting); ++ ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ if (prStaRec->ucJoinFailureCount >= 3) { ++ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ &prP2pFsmInfo->rConnReqInfo, ++ prJoinInfo->aucIEBuf, ++ prJoinInfo->u4BufLength, ++ prStaRec->u2StatusCode, ++ WLAN_STATUS_MEDIA_CONNECT); ++ } else { ++ /* Sometime the GO is not ready to response auth. */ ++ /* Connect it again */ ++ prP2pFsmInfo->prTargetBss = NULL; ++ } ++ DBGLOG(P2P, INFO, "P2P GC Join Failed\n"); ++ ++ } ++ ++ } ++ } ++ } ++ ++ if (prAssocRspSwRfb) ++ nicRxReturnRFB(prAdapter, prAssocRspSwRfb); ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_GC_JOIN) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ /* Return to IDLE state. */ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } else { ++ /* p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); */ ++ /* one more scan */ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ } ++ } ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventJoinComplete */ ++ ++VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) prMsgHdr; ++ ++ p2pFuncMgmtFrameRegister(prAdapter, ++ prMgmtFrameRegister->u2FrameType, ++ prMgmtFrameRegister->fgIsRegister, &prP2pFsmInfo->u4P2pPacketFilter); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventMgmtFrameRegister */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when RX deauthentication frame from the AIR. ++* If we are under STA mode, we would go back to P2P Device. ++* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ UINT_16 u2ReasonCode = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ if (prStaRec == NULL) ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ if (!prStaRec) ++ break; ++ ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ break; ++ ++ DBGLOG(P2P, TRACE, "RX Deauth\n"); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prStaRec->aucMacAddr, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ UINT_16 u2IELength = 0; ++ ++ if (prP2pBssInfo->prStaRecOfAP != prStaRec) ++ break; ++ ++ prStaRec->u2ReasonCode = u2ReasonCode; ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); ++ ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, ++ prDeauthFrame->aucInfoElem, u2IELength, u2ReasonCode, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ DBGLOG(P2P, INFO, "GC RX Deauth Reason: %d\n", u2ReasonCode); ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Delete client from client list. */ ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ ++ ++ /* Indicate disconnect to Host. */ ++ DBGLOG(P2P, INFO, "GO RX Deauth Reason: %d\n", u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ ++ break; ++ } ++ } ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ /* Findout why someone sent deauthentication frame to us. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "Deauth Reason:%d\n", u2ReasonCode); ++ ++ } while (FALSE); ++} /* p2pFsmRunEventRxDeauthentication */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when RX deauthentication frame from the AIR. ++* If we are under STA mode, we would go back to P2P Device. ++* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ UINT_16 u2ReasonCode = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ if (prStaRec == NULL) { ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ break; ++ } ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ break; ++ ++ DBGLOG(P2P, TRACE, "RX Disassoc\n"); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ UINT_16 u2IELength = 0; ++ ++ ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); ++ ++ if (prP2pBssInfo->prStaRecOfAP != prStaRec) ++ break; ++ ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, ++ prDisassocFrame->aucInfoElem, ++ u2IELength, prStaRec->u2ReasonCode, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ DBGLOG(P2P, INFO, "GC RX Disassoc Reason %d\n", prStaRec->u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, prStaRec->u2ReasonCode); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Delete client from client list. */ ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ ++ ++ /* Indicate disconnect to Host. */ ++ DBGLOG(P2P, INFO, "GO RX Disassoc Reason %d\n", u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ ++ break; ++ } ++ } ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } while (FALSE); ++} /* p2pFsmRunEventRxDisassociation */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called when a probe request frame is received. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is accepted & need cancel scan request. ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (prBssDesc != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ /* There is a connection request. */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventRxProbeResponseFrame */ ++ ++VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconTimeout: Beacon Timeout\n"); ++ ++ /* Only client mode would have beacon lost event. */ ++ ASSERT(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); ++ ++ if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, REASON_CODE_DISASSOC_INACTIVITY, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ if (prP2pBssInfo->prStaRecOfAP != NULL) { ++ P_STA_RECORD_T prStaRec = prP2pBssInfo->prStaRecOfAP; ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_DISASSOC_LEAVING_BSS); ++ ++ /* 20120830 moved into p2pFuncDisconnect() */ ++ /* cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ } ++ } while (FALSE); ++ ++} /* p2pFsmRunEventBeaconTimeout */ ++ ++VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = NULL; ++ struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prExtListenMsg = NULL; ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prExtListenMsg = (struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *) prMsgHdr; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ASSERT_BREAK(prP2pFsmInfo); ++ ++ if (!prExtListenMsg->wait) { ++ DBGLOG(P2P, INFO, "reset listen interval\n"); ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ if (prP2pFsmInfo && (prP2pFsmInfo->eListenExted == P2P_DEV_NOT_EXT_LISTEN)) { ++ DBGLOG(P2P, INFO, "try to ext listen, p2p state: %d\n", prP2pFsmInfo->eCurrentState); ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) { ++ DBGLOG(P2P, INFO, "here to ext listen interval\n"); ++ prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_ING; ++ } ++ } ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++} /* p2pFsmRunEventUpdateMgmtFrame */ ++ ++#if CFG_SUPPORT_WFD ++VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ WLAN_STATUS rStatus; ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventWfdSettingUpdate\n"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL)); ++ ++ if (prMsgHdr != NULL) { ++ prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) prMsgHdr; ++ prWfdCfgSettings = prMsgWfdCfgSettings->prWfdCfgSettings; ++ } else { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ } ++ ++ DBGLOG(P2P, INFO, "WFD Enalbe %x info %x state %x flag %x adv %x\n", ++ prWfdCfgSettings->ucWfdEnable, ++ prWfdCfgSettings->u2WfdDevInfo, ++ (UINT_32) prWfdCfgSettings->u4WfdState, ++ (UINT_32) prWfdCfgSettings->u4WfdFlag, ++ (UINT_32) prWfdCfgSettings->u4WfdAdvancedFlag); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_WFD_CTRL, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(WFD_CFG_SETTINGS_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prWfdCfgSettings, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ } while (FALSE); ++ ++ return; ++ ++} ++ ++/* p2pFsmRunEventWfdSettingUpdate */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec != NULL) { ++ if (IS_STA_P2P_TYPE(prStaRec)) { ++ /* Do nothing */ ++ /* TODO: */ ++ } ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* end of p2pGenerateP2P_IEForAssocReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Probe Request frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ /* TODO: */ ++ ++ return; ++ ++} /* end of p2pGenerateP2P_IEForProbReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate P2P IE length for Beacon frame. ++* ++* @param[in] eNetTypeIndex Specify which network ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of P2P IE added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ++p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ /* TODO: */ ++ ++ return 0; ++ ++} /* end of p2pCalculateP2P_IELenForProbeReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Tx Fail of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_UNSPECIFIED); ++ ++ /* 20120830 moved into p2puUncDisconnect. */ ++ /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ ++ ++} /* p2pRunEventAAATxFail */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaState; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ eOriMediaState = prP2pBssInfo->eConnectionState; ++ ++ if (prStaRec != NULL) ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ else ++ break; ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ rStatus = WLAN_STATUS_RESOURCES; ++ break; ++ } ++ ++ bssAddStaRecToClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ rStatus = WLAN_STATUS_RESOURCES; ++ break; ++ } ++ DBGLOG(P2P, INFO, "P2P GO Join Complete\n"); ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* Update Connected state to FW. */ ++ if (eOriMediaState != prP2pBssInfo->eConnectionState) ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} /* p2pRunEventAAAComplete */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ /* Glue layer indication. */ ++ kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, TRUE); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} /* p2pRunEventAAASuccess */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_P2P_PUBLIC_ACTION_FRAME_T prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prAdapter); ++ ++ prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) prSwRfb->pvHeader; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ DBGLOG(P2P, TRACE, "RX Public Action Frame Token:%d.\n", prPublicActionFrame->ucDialogToken); ++ ++ if (prPublicActionFrame->ucCategory != CATEGORY_PUBLIC_ACTION) ++ return rWlanStatus; ++ ++ switch (prPublicActionFrame->ucAction) { ++ case ACTION_PUBLIC_WIFI_DIRECT: ++ break; ++ case ACTION_GAS_INITIAL_REQUEST: ++ case ACTION_GAS_INITIAL_RESPONSE: ++ case ACTION_GAS_COMEBACK_REQUEST: ++ case ACTION_GAS_COMEBACK_RESPONSE: ++ break; ++ default: ++ break; ++ } ++ ++ return rWlanStatus; ++} /* p2pRxPublicActionFrame */ ++ ++WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_P2P_ACTION_FRAME_T prP2pActionFrame = (P_P2P_ACTION_FRAME_T) NULL; ++ UINT_8 aucOui[3] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pActionFrame = (P_P2P_ACTION_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prP2pActionFrame->ucCategory != CATEGORY_VENDOR_SPECIFIC_ACTION) { ++ DBGLOG(P2P, TRACE, "RX Action Frame but not vendor specific.\n"); ++ break; ++ } ++ ++ if ((prP2pActionFrame->ucOuiType != VENDOR_OUI_TYPE_P2P) || ++ (prP2pActionFrame->aucOui[0] != aucOui[0]) || ++ (prP2pActionFrame->aucOui[1] != aucOui[1]) || (prP2pActionFrame->aucOui[2] != aucOui[2])) { ++ DBGLOG(P2P, TRACE, "RX Vendor Specific Action Frame but not P2P Type or not WFA OUI.\n"); ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pRxActionFrame */ ++ ++VOID ++p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam) ++{ ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ UINT_32 i; ++ BOOLEAN fgNoaAttrExisted = FALSE; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIndex]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ prP2pSpecificBssInfo->fgEnableOppPS = prEventUpdateNoaParam->fgEnableOppPS; ++ prP2pSpecificBssInfo->u2CTWindow = prEventUpdateNoaParam->u2CTWindow; ++ prP2pSpecificBssInfo->ucNoAIndex = prEventUpdateNoaParam->ucNoAIndex; ++ prP2pSpecificBssInfo->ucNoATimingCount = prEventUpdateNoaParam->ucNoATimingCount; ++ ++ fgNoaAttrExisted |= prP2pSpecificBssInfo->fgEnableOppPS; ++ ++ DBGLOG(P2P, INFO, "Update NoA Count=%d.\n", prEventUpdateNoaParam->ucNoATimingCount); ++ ++ ASSERT(prP2pSpecificBssInfo->ucNoATimingCount <= P2P_MAXIMUM_NOA_COUNT); ++ ++ for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { ++ /* in used */ ++ prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse = prEventUpdateNoaParam->arEventNoaTiming[i].fgIsInUse; ++ /* count */ ++ prP2pSpecificBssInfo->arNoATiming[i].ucCount = prEventUpdateNoaParam->arEventNoaTiming[i].ucCount; ++ /* duration */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4Duration = prEventUpdateNoaParam->arEventNoaTiming[i].u4Duration; ++ /* interval */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4Interval = prEventUpdateNoaParam->arEventNoaTiming[i].u4Interval; ++ /* start time */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4StartTime = ++ prEventUpdateNoaParam->arEventNoaTiming[i].u4StartTime; ++ ++ fgNoaAttrExisted |= prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse; ++ } ++ ++ prP2pSpecificBssInfo->fgIsNoaAttrExisted = fgNoaAttrExisted; ++ ++ /* update beacon content by the change */ ++ bssUpdateBeaconContent(prAdapter, ucNetTypeIndex); ++} ++ ++#endif /* CFG_ENABLE_WIFI_DIRECT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c +new file mode 100644 +index 000000000000..586a74721b3b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c +@@ -0,0 +1,3796 @@ ++#include "precomp.h" ++#include ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocRspAttributesTable[] = { ++ {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS), NULL, p2pFuncAppendAttriStatusForAssocRsp} /* 0 */ ++ , {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING), NULL, p2pFuncAppendAttriExtListenTiming} /* 8 */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txProbeRspIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE} /* 50 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} /* 42 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} /* 45 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} /* 61 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} /* 48 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} /* 74 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} /* 127 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE} /* 221 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Function for requesting scan. There is an option to do ACTIVE or PASSIVE scan. ++* ++* @param eScanType - Specify the scan type of the scan request. It can be an ACTIVE/PASSIVE ++* Scan. ++* eChannelSet - Specify the preferred channel set. ++* A FULL scan would request a legacy full channel normal scan.(usually ACTIVE). ++* A P2P_SOCIAL scan would scan 1+6+11 channels.(usually ACTIVE) ++* A SPECIFIC scan would only 1/6/11 channels scan. (Passive Listen/Specific Search) ++* ucChannelNum - A specific channel number. (Only when channel is specified) ++* eBand - A specific band. (Only when channel is specified) ++* ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) ++{ ++ ++ P_MSG_SCN_SCAN_REQ prScanReq = (P_MSG_SCN_SCAN_REQ) NULL; ++ /*NFC Beam + Indication */ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsPureAP = FALSE; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++ ++ DEBUGFUNC("p2pFuncRequestScan()"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); ++ ++ if (prScanReqInfo->eChannelSet == SCAN_CHANNEL_SPECIFIED) { ++ ASSERT_BREAK(prScanReqInfo->ucNumChannelList > 0); ++ DBGLOG(P2P, LOUD, ++ "P2P Scan Request Channel:%d\n", prScanReqInfo->arScanChannelList[0].ucChannelNum); ++ } ++ ++ prScanReq = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ if (!prScanReq) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ break; ++ } ++ ++ prScanReq->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_REQ; ++ prScanReq->ucSeqNum = ++prScanReqInfo->ucSeqNumOfScnMsg; ++ prScanReq->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ prScanReq->eScanType = prScanReqInfo->eScanType; ++ prScanReq->eScanChannel = prScanReqInfo->eChannelSet; ++ prScanReq->u2IELen = 0; ++ ++ /* Copy IE for Probe Request. */ ++ if (prScanReqInfo->u4BufLength > MAX_IE_LENGTH) ++ prScanReqInfo->u4BufLength = MAX_IE_LENGTH; ++ kalMemCopy(prScanReq->aucIE, prScanReqInfo->aucIEBuf, prScanReqInfo->u4BufLength); ++ prScanReq->u2IELen = (UINT_16) prScanReqInfo->u4BufLength; ++ ++ prScanReq->u2ChannelDwellTime = prScanReqInfo->u2PassiveDewellTime; ++ ++ switch (prScanReqInfo->eChannelSet) { ++ case SCAN_CHANNEL_SPECIFIED: ++ { ++ UINT_32 u4Idx = 0; ++ P_RF_CHANNEL_INFO_T prDomainInfo = ++ (P_RF_CHANNEL_INFO_T) prScanReqInfo->arScanChannelList; ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ ++ if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ for (u4Idx = 0; u4Idx < prScanReqInfo->ucNumChannelList; u4Idx++) { ++ prScanReq->arChnlInfoList[u4Idx].ucChannelNum = prDomainInfo->ucChannelNum; ++ prScanReq->arChnlInfoList[u4Idx].eBand = prDomainInfo->eBand; ++ prDomainInfo++; ++ } ++ ++ prScanReq->ucChannelListNum = prScanReqInfo->ucNumChannelList; ++ ++ /*NFC Beam + Indication */ ++ prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ if (prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_GO_START_BSS && ++ prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && ++ !fgIsPureAP) { ++ prScanReq->ucChannelListNum = 1; ++ prScanReq->arChnlInfoList[0].ucChannelNum = prChnlReqInfo->ucReqChnlNum; ++ prScanReq->arChnlInfoList[0].eBand = prChnlReqInfo->eBand; ++ ++ DBGLOG(P2P, INFO, ++ "NFC:GO Skip Scan and Only Froce on %s[%d]\n", ++ prChnlReqInfo->eBand == 1 ? "2.4G" : "5G", ++ prChnlReqInfo->ucReqChnlNum); ++ } ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ ++ } ++ break; ++ ++ case SCAN_CHANNEL_FULL: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ ++ case SCAN_CHANNEL_2G4: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ ++ case SCAN_CHANNEL_P2P_SOCIAL: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ default: ++ /* Currently there is no other scan channel set. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReq, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pFuncRequestScan */ ++ ++VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanInfo) ++{ ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prScanInfo != NULL)); ++ ++ if (!prScanInfo->fgIsScanRequest) ++ break; ++ ++ if (prScanInfo->ucSeqNumOfScnMsg) { ++ /* There is a channel privilege on hand. */ ++ DBGLOG(P2P, TRACE, "P2P Cancel Scan\n"); ++ ++ prScanCancelMsg = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ /* Buffer not enough, can not cancel scan request. */ ++ DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prScanCancelMsg->ucSeqNum = prScanInfo->ucSeqNumOfScnMsg++; ++ prScanCancelMsg->fgIsChannelExt = FALSE; ++ prScanInfo->fgIsScanRequest = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncCancelScan */ ++ ++VOID ++p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW) ++{ ++ if (!prAdapter) ++ return; ++ if (!prAdapter->prGlueInfo) ++ return; ++ if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) ++ return; ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (eOpMode < OP_MODE_NUM)); ++ ++ if (prP2pBssInfo->eCurrentOPMode != eOpMode) { ++ DBGLOG(P2P, TRACE, ++ "p2pFuncSwitchOPMode: Switch to from %d, to %d.\n", prP2pBssInfo->eCurrentOPMode, ++ eOpMode); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); ++ ++ p2pFsmRunEventStopAP(prAdapter, NULL); ++ break; ++ default: ++ break; ++ } ++ ++ prP2pBssInfo->eIntendOPMode = eOpMode; ++ prP2pBssInfo->eCurrentOPMode = eOpMode; ++ switch (eOpMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to Client.\n"); ++ case OP_MODE_ACCESS_POINT: ++/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ++ /* Change interface address. */ ++ if (eOpMode == OP_MODE_ACCESS_POINT) { ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to AP.\n"); ++ prP2pBssInfo->ucSSIDLen = 0; ++ } ++ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucInterfaceAddress); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucInterfaceAddress); ++ ++ break; ++ case OP_MODE_P2P_DEVICE: ++ { ++ /* Change device address. */ ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch back to P2P Device.\n"); ++ ++/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); ++ ++ } ++ break; ++ default: ++/* if (IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++/* nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ if (1) { ++ P2P_DISCONNECT_INFO rP2PDisInfo; ++ ++ rP2PDisInfo.ucRole = 2; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_P2P_ABORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(P2P_DISCONNECT_INFO), (PUINT_8)&rP2PDisInfo, NULL, 0); ++ } ++ ++ DBGLOG(P2P, TRACE, ++ "The device address is changed to %pM\n", ++ prP2pBssInfo->aucOwnMacAddr); ++ DBGLOG(P2P, TRACE, "The BSSID is changed to %pM\n", prP2pBssInfo->aucBSSID); ++ ++ /* Update BSS INFO to FW. */ ++ if ((fgSyncToFW) && (eOpMode != OP_MODE_ACCESS_POINT)) ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncSwitchOPMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will start a P2P Group Owner and send Beacon Frames. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncStartGO(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, ++ IN PUINT_8 pucSsidBuf, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP) ++{ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL)); ++ ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 1; ++ DBGLOG(P2P, INFO, ++ "p2pFuncStartGO:NFC Done[%d]\n", ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); ++ /* AP mode started. */ ++ p2pFuncSwitchOPMode(prAdapter, prBssInfo, prBssInfo->eIntendOPMode, FALSE); ++ ++ prBssInfo->eIntendOPMode = OP_MODE_NUM; ++ ++ /* 4 <1.1> Assign SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, pucSsidBuf, ucSsidLen); ++ ++ DBGLOG(P2P, TRACE, "GO SSID:%s\n", prBssInfo->aucSSID); ++ ++ /* 4 <1.2> Clear current AP's STA_RECORD_T and current AID */ ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.3> Setup Channel, Band and Phy Attributes */ ++ prBssInfo->ucPrimaryChannel = ucChannelNum; ++ prBssInfo->eBand = eBand; ++ prBssInfo->eBssSCO = eSco; ++ ++ DBGLOG(P2P, TRACE, "GO Channel:%d\n", ucChannelNum); ++ ++ if (prBssInfo->eBand == BAND_5G) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; ++ } else if (fgIsPureAP) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ } else { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11GN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; ++ } ++ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ prBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ if (prBssInfo->ucAllSupportedRatesLen == 0) { ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, ++ &prBssInfo->ucAllSupportedRatesLen); ++ } ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2ATIMWindow = 0; ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ ++ /* 3 <2> Update BSS_INFO_T common part */ ++#if CFG_SUPPORT_AAA ++ if (!fgIsPureAP) { ++ prBssInfo->fgIsProtection = TRUE; /* Always enable protection at P2P GO */ ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); ++ } else { ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) ++ prBssInfo->fgIsProtection = TRUE; ++ } ++ ++ /* 20120106 frog: I want separate OP_Mode & Beacon TX Function. */ ++ /* p2pFuncSwitchOPMode(prAdapter, prBssInfo, OP_MODE_ACCESS_POINT, FALSE); */ ++ ++ bssInitForAP(prAdapter, prBssInfo, FALSE); ++ ++ nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_P2P_INDEX); ++#endif /* CFG_SUPPORT_AAA */ ++ ++ /* 3 <3> Set MAC HW */ ++ /* 4 <3.1> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ ++ /* 4 <3.2> Reset HW TSF Update Mode and Beacon Mode */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <3.3> Update Beacon again for network phy type confirmed. */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++#if 0 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ { ++ CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; ++ arHotspotOptimizationCfg.u4Level = (0x3) << 8 | 0x5; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8)&arHotspotOptimizationCfg, NULL, 0); ++ } ++#endif ++ ++ /* 4 <3.4> Setup BSSID */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ } while (FALSE); ++ ++} /* p2pFuncStartGO() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM that channel privilege ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ P_MSG_CH_ABORT_T prMsgChRelease = (P_MSG_CH_ABORT_T) NULL; ++ ++ DEBUGFUNC("p2pFuncReleaseCh()"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); ++ ++ if (!prChnlReqInfo->fgIsChannelRequested) ++ break; ++ ++ DBGLOG(P2P, TRACE, "P2P Release Channel\n"); ++ prChnlReqInfo->fgIsChannelRequested = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChRelease = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChRelease) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ break; ++ } ++ ++ prMsgChRelease->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChRelease->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prMsgChRelease->ucTokenID = prChnlReqInfo->ucSeqNumOfChReq++; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChRelease, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pFuncReleaseCh */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of CHANNEL_REQ_JOIN Initial. Enter CHANNEL_REQ_JOIN State. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ P_MSG_CH_REQ_T prMsgChReq = (P_MSG_CH_REQ_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); ++ ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ break; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prMsgChReq->ucTokenID = ++prChnlReqInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ if (prChnlReqInfo->u4MaxInterval < P2P_EXT_LISTEN_TIME_MS) ++ prMsgChReq->u4MaxInterval = P2P_EXT_LISTEN_TIME_MS; ++ else ++ prMsgChReq->u4MaxInterval = prChnlReqInfo->u4MaxInterval; ++ ++ prMsgChReq->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; ++ prMsgChReq->eRfSco = prChnlReqInfo->eChnlSco; ++ prMsgChReq->eRfBand = prChnlReqInfo->eBand; ++ ++ kalMemZero(prMsgChReq->aucBSSID, MAC_ADDR_LEN); ++ ++ /* Channel request join BSSID. */ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prChnlReqInfo->fgIsChannelRequested = TRUE; ++ ++ } while (FALSE); ++ ++} /* p2pFuncAcquireCh */ ++ ++#if 0 ++WLAN_STATUS ++p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBcnHdr, ++ IN UINT_32 u4HdrLen, ++ IN PUINT_8 pucBcnBody, IN UINT_32 u4BodyLen, IN UINT_32 u4DtimPeriod, IN UINT_32 u4BcnInterval) ++{ ++ WLAN_STATUS rResultStatus = WLAN_STATUS_INVALID_DATA; ++ P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucTIMBody = (PUINT_8) NULL; ++ UINT_16 u2FrameLength = 0, UINT_16 u2OldBodyLen = 0; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prBcnMsduInfo = prP2pBssInfo->prBeacon ASSERT_BREAK(prBcnMsduInfo != NULL); ++ ++ /* TODO: Find TIM IE pointer. */ ++ prBcnFrame = prBcnMsduInfo->prPacket; ++ ++ ASSERT_BREAK(prBcnFrame != NULL); ++ ++ do { ++ /* Ori header. */ ++ UINT_16 u2IELength = 0, u2Offset = 0; ++ PUINT_8 pucIEBuf = prBcnFrame->aucInfoElem; ++ ++ u2IELength = prBcnMsduInfo->u2FrameLength - prBcnMsduInfo->ucMacHeaderLength; ++ ++ IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { ++ if ((IE_ID(pucIEBuf) == ELEM_ID_TIM) || ((IE_ID(pucIEBuf) > ELEM_ID_IBSS_PARAM_SET))) { ++ pucTIMBody = pucIEBuf; ++ break; ++ } ++ u2FrameLength += IE_SIZE(pucIEBuf); ++ } ++ ++ if (pucTIMBody == NULL) ++ pucTIMBody = pucIEBuf; ++ ++ /* Body not change. */ ++ u2OldBodyLen = (UINT_16) ((UINT_32) pucTIMBody - (UINT_32) prBcnFrame->aucInfoElem); ++ /* Move body. */ ++ kalMemCmp(aucIEBuf, pucTIMBody, u2OldBodyLen); ++ } while (FALSE); ++ ++ if (pucBcnHdr) { ++ kalMemCopy(prBcnMsduInfo->prPacket, pucBcnHdr, u4HdrLen); ++ pucTIMBody = (PUINT_8) ((UINT_32) prBcnMsduInfo->prPacket + u4HdrLen); ++ prBcnMsduInfo->ucMacHeaderLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); ++ u2FrameLength = u4HdrLen; /* Header + Partial Body. */ ++ } else { ++ /* Header not change. */ ++ u2FrameLength += prBcnMsduInfo->ucMacHeaderLength; ++ } ++ ++ if (pucBcnBody) { ++ kalMemCopy(pucTIMBody, pucBcnBody, u4BodyLen); ++ u2FrameLength += (UINT_16) u4BodyLen; ++ } else { ++ kalMemCopy(pucTIMBody, aucIEBuf, u2OldBodyLen); ++ u2FrameLength += u2OldBodyLen; ++ } ++ ++ /* Frame Length */ ++ prBcnMsduInfo->u2FrameLength = u2FrameLength; ++ prBcnMsduInfo->fgIs802_11 = TRUE; ++ prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ prP2pBssInfo->u2BeaconInterval = (UINT_16) u4BcnInterval; ++ prP2pBssInfo->ucDTIMPeriod = (UINT_8) u4DtimPeriod; ++ prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; ++ prBcnMsduInfo->ucPacketType = 3; ++ rResultStatus = nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prP2pBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prBcnMsduInfo->u2FrameLength - ++ OFFSET_OF(WLAN_BEACON_FRAME_T, ++ aucInfoElem)); ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* AP is created, Beacon Update. */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } while (FALSE); ++ return rResultStatus; ++} /* p2pFuncBeaconUpdate */ ++ ++#else ++WLAN_STATUS ++ p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, ++ IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, ++ IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen) ++{ ++WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; ++PUINT_8 pucIEBuf = (PUINT_8) NULL; ++PUINT_8 paucIEBuf = (PUINT_8) NULL;/*[MAX_IE_LENGTH]; aucIEBuf*/ ++ ++do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (prBcnUpdateInfo != NULL)); ++ ++ prBcnMsduInfo = prP2pBssInfo->prBeacon; ++ ++#if DBG ++ if (prBcnUpdateInfo->pucBcnHdr != NULL) { ++ ASSERT((UINT_32) prBcnUpdateInfo->pucBcnHdr == ++ ((UINT_32) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD)); ++ } ++ ++ if (prBcnUpdateInfo->pucBcnBody != NULL) { ++ ASSERT((UINT_32) prBcnUpdateInfo->pucBcnBody == ++ ((UINT_32) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen)); ++ } ++#endif ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) ((ULONG) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ if (!pucNewBcnBody) { ++ /* Old body. */ ++ pucNewBcnBody = prBcnUpdateInfo->pucBcnBody; ++ ASSERT(u4NewBodyLen == 0); ++ u4NewBodyLen = prBcnUpdateInfo->u4BcnBodyLen; ++ } else { ++ prBcnUpdateInfo->u4BcnBodyLen = u4NewBodyLen; ++ } ++ ++ paucIEBuf = kalMemAlloc(MAX_IE_LENGTH, VIR_MEM_TYPE); ++ if (paucIEBuf == NULL) { ++ DBGLOG(P2P, TRACE, "p2p alloc paucIEBuf fail\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Temp buffer body part. */ ++ kalMemCopy(paucIEBuf, pucNewBcnBody, u4NewBodyLen); ++ ++ if (pucNewBcnHdr) { ++ kalMemCopy(prBcnFrame, pucNewBcnHdr, u4NewHdrLen); ++ prBcnUpdateInfo->pucBcnHdr = (PUINT_8) prBcnFrame; ++ prBcnUpdateInfo->u4BcnHdrLen = u4NewHdrLen; ++ } ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen); ++ kalMemCopy(pucIEBuf, paucIEBuf, u4NewBodyLen); ++ kalMemFree(paucIEBuf, VIR_MEM_TYPE, MAX_IE_LENGTH); ++ prBcnUpdateInfo->pucBcnBody = pucIEBuf; ++ ++ /* Frame Length */ ++ prBcnMsduInfo->u2FrameLength = (UINT_16) (prBcnUpdateInfo->u4BcnHdrLen + prBcnUpdateInfo->u4BcnBodyLen); ++ ++ prBcnMsduInfo->ucPacketType = 3; ++ prBcnMsduInfo->fgIs802_11 = TRUE; ++ prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++ /* Update BSS INFO related information. */ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prBcnFrame->aucSrcAddr); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prBcnFrame->aucBSSID); ++ prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; ++ ++ p2pFuncParseBeaconContent(prAdapter, ++ prP2pBssInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); ++ ++#if 1 ++ /* bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++#else ++ nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prBcnFrame->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); ++#endif ++} while (FALSE); ++ ++return rWlanStatus; ++} /* p2pFuncBeaconUpdate */ ++ ++#endif ++ ++/* TODO: We do not apply IE in deauth frame set from upper layer now. */ ++WLAN_STATUS ++p2pFuncDeauth(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucPeerMacAddr, ++ IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDeauth) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsStaFound = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); ++ fgIsStaFound = TRUE; ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_INFRASTRUCTURE: ++ ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); ++ if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) ++ break; ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ fgIsStaFound = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgIsStaFound) ++ p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDeauth, u2ReasonCode); ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncDeauth */ ++ ++/* TODO: We do not apply IE in disassoc frame set from upper layer now. */ ++WLAN_STATUS ++p2pFuncDisassoc(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucPeerMacAddr, ++ IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDisassoc) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsStaFound = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); ++ fgIsStaFound = TRUE; ++ /* p2pFuncDisconnect(prAdapter, prCliStaRec, ++ * fgSendDisassoc, u2ReasonCode); */ ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_INFRASTRUCTURE: ++ ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); ++ if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) ++ break; ++ /* p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); */ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ fgIsStaFound = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgIsStaFound) { ++ ++ p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); ++ /* 20120830 moved into p2pFuncDisconnect(). */ ++ /* cnmStaRecFree(prAdapter, prCliStaRec, TRUE); */ ++ ++ } ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncDisassoc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) ++* 1. GC: Disconnect from AP. (Send Deauth) ++* 2. GO: Disconnect all STA ++* ++* @param[in] prAdapter Pointer to the adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncDissolve(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) ++{ ++ DEBUGFUNC("p2pFuncDissolve()"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ /* Reset station record status. */ ++ if (prP2pBssInfo->prStaRecOfAP) { ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, REASON_CODE_DEAUTH_LEAVING_BSS, ++ WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); ++ ++ /* 2012/02/14 frog: After formation before join group, prStaRecOfAP is NULL. */ ++ p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, fgSendDeauth, u2ReasonCode); ++ } ++ ++ /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). ++ * hit prStaRecOfAP == NULL. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Under AP mode, we would net send deauthentication frame to each STA. ++ * We only stop the Beacon & let all stations timeout. ++ */ ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ ++ /* Send deauth. */ ++ authSendDeauthFrame(prAdapter, ++ NULL, (P_SW_RFB_T) NULL, u2ReasonCode, (PFN_TX_DONE_HANDLER) NULL); ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ while (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_REMOVE_HEAD(prStaRecOfClientList, prCurrStaRec, P_STA_RECORD_T); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ ++ ++ p2pFuncDisconnect(prAdapter, prCurrStaRec, TRUE, u2ReasonCode); ++ ++ } ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; ++ } ++ ++ break; ++ default: ++ return; /* 20110420 -- alreay in Device Mode. */ ++ } ++ ++ /* Make the deauth frame send to FW ASAP. */ ++ wlanAcquirePowerControl(prAdapter); ++ wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); ++ wlanReleasePowerControl(prAdapter); ++ ++ kalMdelay(100); ++ ++ /* Change Connection Status. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ } while (FALSE); ++ ++} /* p2pFuncDissolve */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) ++* 1. GC: Disconnect from AP. (Send Deauth) ++* 2. GO: Disconnect all STA ++* ++* @param[in] prAdapter Pointer to the adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ eOriMediaStatus = prP2pBssInfo->eConnectionState; ++ ++ /* Indicate disconnect. */ ++ /* TODO: */ ++ /* kalP2PGOStationUpdate */ ++ /* kalP2PGCIndicateConnectionStatus */ ++ /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, prStaRec->aucMacAddr); */ ++ DBGLOG(P2P, INFO, "p2pFuncDisconnect, eCurrentOPMode: %d, sendDeauth: %s\n", ++ prP2pBssInfo->eCurrentOPMode, fgSendDeauth ? "True" : "False"); ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); ++ ++ if (fgSendDeauth) { ++ /* Send deauth. */ ++ authSendDeauthFrame(prAdapter, ++ prStaRec, ++ (P_SW_RFB_T) NULL, ++ u2ReasonCode, (PFN_TX_DONE_HANDLER) p2pFsmRunEventDeauthTxDone); ++ } else { ++ /* Change station state. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* Reset Station Record Status. */ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { ++ DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ } ++ ++ if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { ++ /* Update Disconnected state to FW. */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { ++ /* GO: It would stop Beacon TX. GC: Stop all BSS related PS function. */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Reset RLM related field of BSSINFO. */ ++ rlmBssAborted(prAdapter, prP2pBssInfo); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncDisconnect */ ++ ++/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ ++#define WLAN_ACTION_SPECTRUM_MGMT 0 ++#define WLAN_ACTION_QOS 1 ++#define WLAN_ACTION_DLS 2 ++#define WLAN_ACTION_BLOCK_ACK 3 ++#define WLAN_ACTION_PUBLIC 4 ++#define WLAN_ACTION_RADIO_MEASUREMENT 5 ++#define WLAN_ACTION_FT 6 ++#define WLAN_ACTION_HT 7 ++#define WLAN_ACTION_SA_QUERY 8 ++#define WLAN_ACTION_PROTECTED_DUAL 9 ++#define WLAN_ACTION_WNM 10 ++#define WLAN_ACTION_UNPROTECTED_WNM 11 ++#define WLAN_ACTION_TDLS 12 ++#define WLAN_ACTION_SELF_PROTECTED 15 ++#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ ++#define WLAN_ACTION_VENDOR_SPECIFIC 127 ++ ++/* Public action codes */ ++#define WLAN_PA_20_40_BSS_COEX 0 ++#define WLAN_PA_VENDOR_SPECIFIC 9 ++#define WLAN_PA_GAS_INITIAL_REQ 10 ++#define WLAN_PA_GAS_INITIAL_RESP 11 ++#define WLAN_PA_GAS_COMEBACK_REQ 12 ++#define WLAN_PA_GAS_COMEBACK_RESP 13 ++#define WLAN_TDLS_DISCOVERY_RESPONSE 14 ++ ++/* P2P public action frames */ ++enum p2p_action_frame_type { ++ P2P_GO_NEG_REQ = 0, ++ P2P_GO_NEG_RESP = 1, ++ P2P_GO_NEG_CONF = 2, ++ P2P_INVITATION_REQ = 3, ++ P2P_INVITATION_RESP = 4, ++ P2P_DEV_DISC_REQ = 5, ++ P2P_DEV_DISC_RESP = 6, ++ P2P_PROV_DISC_REQ = 7, ++ P2P_PROV_DISC_RESP = 8 ++}; ++ ++const char *p2p_to_string(enum p2p_action_frame_type p2p_action) ++{ ++ switch (p2p_action) { ++ case P2P_GO_NEG_REQ: ++ return "GO_NEG_REQ"; ++ case P2P_GO_NEG_RESP: ++ return "GO_NEG_RESP"; ++ case P2P_GO_NEG_CONF: ++ return "GO_NEG_CONF"; ++ case P2P_INVITATION_REQ: ++ return "INVITATION_REQ"; ++ case P2P_INVITATION_RESP: ++ return "INVITATION_RESP"; ++ case P2P_DEV_DISC_REQ: ++ return "DEV_DISC_REQ"; ++ case P2P_DEV_DISC_RESP: ++ return "DEV_DISC_RESP"; ++ case P2P_PROV_DISC_REQ: ++ return "PROV_DISC_REQ"; ++ case P2P_PROV_DISC_RESP: ++ return "PROV_DISC_RESP"; ++ } ++ ++ return "UNKNOWN P2P Public Action"; ++} ++const char *pa_to_string(int pa_action) ++{ ++ switch (pa_action) { ++ case WLAN_PA_20_40_BSS_COEX: ++ return "PA_20_40_BSS_COEX"; ++ case WLAN_PA_VENDOR_SPECIFIC: ++ return "PA_VENDOR_SPECIFIC"; ++ case WLAN_PA_GAS_INITIAL_REQ: ++ return "PA_GAS_INITIAL_REQ"; ++ case WLAN_PA_GAS_INITIAL_RESP: ++ return "PA_GAS_INITIAL_RESP"; ++ case WLAN_PA_GAS_COMEBACK_REQ: ++ return "PA_GAS_COMEBACK_REQ"; ++ case WLAN_PA_GAS_COMEBACK_RESP: ++ return "PA_GAS_COMEBACK_RESP"; ++ case WLAN_TDLS_DISCOVERY_RESPONSE: ++ return "TDLS_DISCOVERY_RESPONSE"; ++ } ++ ++ return "UNKNOWN Public Action"; ++} ++ ++const char *action_to_string(int wlan_action) ++{ ++ switch (wlan_action) { ++ case WLAN_ACTION_SPECTRUM_MGMT: ++ return "SPECTRUM_MGMT"; ++ case WLAN_ACTION_QOS: ++ return "QOS"; ++ case WLAN_ACTION_DLS: ++ return "DLS"; ++ case WLAN_ACTION_BLOCK_ACK: ++ return "BLOCK_ACK"; ++ case WLAN_ACTION_PUBLIC: ++ return "PUBLIC"; ++ case WLAN_ACTION_RADIO_MEASUREMENT: ++ return "RADIO_MEASUREMENT"; ++ case WLAN_ACTION_FT: ++ return "FT"; ++ case WLAN_ACTION_HT: ++ return "HT"; ++ case WLAN_ACTION_SA_QUERY: ++ return "SA_QUERY"; ++ case WLAN_ACTION_PROTECTED_DUAL: ++ return "PROTECTED_DUAL"; ++ case WLAN_ACTION_WNM: ++ return "WNM"; ++ case WLAN_ACTION_UNPROTECTED_WNM: ++ return "UNPROTECTED_WNM"; ++ case WLAN_ACTION_TDLS: ++ return "TDLS"; ++ case WLAN_ACTION_SELF_PROTECTED: ++ return "SELF_PROTECTED"; ++ case WLAN_ACTION_WMM: ++ return "WMM"; ++ case WLAN_ACTION_VENDOR_SPECIFIC: ++ return "VENDOR_SPECIFIC"; ++ } ++ ++ return "UNKNOWN Action Frame"; ++} ++ ++VOID p2pFuncTagActionActionP2PFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ IN P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucP2pAction, IN UINT_64 u8Cookie) ++{ ++ DBGLOG(P2P, INFO, "Found P2P_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNO: %d\n", ++ p2p_to_string(ucP2pAction), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++} ++ ++VOID p2pFuncTagActionActionFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ IN P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucAction, IN UINT_64 u8Cookie) ++{ ++ PUINT_8 pucVendor = NULL; ++ ++ DBGLOG(P2P, INFO, "Found WLAN_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNo: %d\n", ++ pa_to_string(ucAction), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ if (ucAction == WLAN_PA_VENDOR_SPECIFIC) { ++ pucVendor = (PUINT_8)prActFrame + 26; ++ if (*(pucVendor + 0) == 0x50 && ++ *(pucVendor + 1) == 0x6f && ++ *(pucVendor + 2) == 0x9a) { ++ if (*(pucVendor + 3) == 0x09) ++ /* found p2p IE */ ++ p2pFuncTagActionActionP2PFrame(prMgmtTxMsdu, ++ prActFrame, *(pucVendor + 4), u8Cookie); ++ else if (*(pucVendor + 3) == 0x0a) ++ /* found WFD IE */ ++ DBGLOG(P2P, INFO, "Found WFD IE, SA: %pM - DA: %pM\n", ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr); ++ else ++ DBGLOG(P2P, INFO, "Found Other vendor 0x%x, SA: %pM - DA: %pM\n", ++ *(pucVendor + 3), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr); ++ } ++ } ++} ++ ++VOID p2pFuncTagActionCategoryFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucCategory, ++ IN UINT_64 u8Cookie) ++{ ++ ++ UINT_8 ucAction = 0; ++ ++ DBGLOG(P2P, INFO, "Found WLAN_ACTION_%s, SA: %pM - DA: %pM, u8Cookie: 0x%llx, SeqNO: %d\n", ++ action_to_string(ucCategory), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ if (ucCategory == WLAN_ACTION_PUBLIC) { ++ ucAction = prActFrame->ucAction; ++ p2pFuncTagActionActionFrame(prMgmtTxMsdu, prActFrame, ucAction, u8Cookie); ++ ++ } ++} ++ ++/* ++ * used to debug p2p mgmt frame: ++ * GO Nego Req ++ * GO Nego Res ++ * GO Nego Confirm ++ * GO Invite Req ++ * GO Invite Res ++ * Device Discoverability Req ++ * Device Discoverability Res ++ * Provision Discovery Req ++ * Provision Discovery Res ++ */ ++ ++VOID ++p2pFuncTagMgmtFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ /* P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; */ ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_WLAN_PROBE_RSP_FRAME_T prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T)NULL; ++ UINT_16 u2TxFrameCtrl; ++ P_WLAN_ACTION_FRAME prActFrame; ++ UINT_8 ucCategory; ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ /* ++ * mgmt frame MASK_FC_TYPE = 0 ++ * use MASK_FRAME_TYPE is oK for frame type/subtype judge ++ */ ++ u2TxFrameCtrl = prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE; ++ ++ switch (u2TxFrameCtrl) { ++ case MAC_FRAME_PROBE_RSP: ++ ++ prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T) prWlanHdr; ++ DBGLOG(P2P, INFO, "TX Probe Response Frame, SA: %pM - DA: %pM, cookie: 0x%llx, seqNo: %d\n", ++ prProbRspHdr->aucSrcAddr, prProbRspHdr->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ break; ++ ++ case MAC_FRAME_ACTION: ++ ++ prActFrame = (P_WLAN_ACTION_FRAME)prWlanHdr; ++ ucCategory = prActFrame->ucCategory; ++ p2pFuncTagActionCategoryFrame(prMgmtTxMsdu, prActFrame, ++ ucCategory, u8Cookie); ++ ++ break; ++ default: ++ DBGLOG(P2P, INFO, "MGMT:, un-tagged frame type: 0x%x, A1: %pM, A2: %pM, A3: %pM seqNo: %d\n", ++ u2TxFrameCtrl, ++ prWlanHdr->aucAddr1, ++ prWlanHdr->aucAddr2, ++ prWlanHdr->aucAddr3, ++ prMgmtTxMsdu->ucTxSeqNum); ++ break; ++ } ++} ++ ++WLAN_STATUS ++p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ BOOLEAN fgIsProbrsp = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); ++ ++ if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { ++ ++ /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ ++ /* Packet on driver, not done yet, drop it. */ ++ prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; ++ if (prTxMsduInfo != NULL) { ++ ++ kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ FALSE, ++ prTxMsduInfo->prPacket, ++ (UINT_32) prTxMsduInfo->u2FrameLength); ++ ++ /* Leave it to TX Done handler. */ ++ /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ DBGLOG(P2P, INFO, "p2pFuncTxMgmtFrame: Drop MGMT cookie: 0x%llx\n", ++ prMgmtTxReqInfo->u8Cookie); ++ } ++ /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ ++ /* Packet transmitted, wait tx done. (cookie issue) */ ++ /* 20120105 frog - use another u8cookie to store this value. */ ++ } ++ ++ ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, prWlanHdr->aucAddr1); ++ prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ ++ switch (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) { ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(P2P, TRACE, "p2pFuncTxMgmtFrame: TX MAC_FRAME_PROBE_RSP\n"); ++ fgIsProbrsp = TRUE; ++ prMgmtTxMsdu = p2pFuncProcessP2pProbeRsp(prAdapter, prMgmtTxMsdu); ++ break; ++ default: ++ break; ++ } ++ ++ prMgmtTxReqInfo->u8Cookie = u8Cookie; ++ prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; ++ prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; ++ ++ prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; ++ prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); ++ if (prStaRec != NULL) ++ DBGLOG(P2P, TRACE, "Mgmt with station record: %pM.\n", prStaRec->aucMacAddr); ++ ++ prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ ++ prMgmtTxMsdu->fgIs802_1x = FALSE; ++ prMgmtTxMsdu->fgIs802_11 = TRUE; ++ prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMgmtTxMsdu->pfTxDoneHandler = p2pFsmRunEventMgmtFrameTxDone; ++ prMgmtTxMsdu->fgIsBasicRate = TRUE; ++ ++ p2pFuncTagMgmtFrame(prMgmtTxMsdu, u8Cookie); ++ ++ nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncTxMgmtFrame */ ++ ++VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prRfChannelInfo != NULL)); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prP2pConnSettings->ucOperatingChnl = prRfChannelInfo->ucChannelNum; ++ prP2pConnSettings->eBand = prRfChannelInfo->eBand; ++ ++ } while (FALSE); ++ ++} ++ ++/* p2pFuncSetChannel */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval TRUE We will retry JOIN ++* @retval FALSE We will not retry JOIN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo) ++{ ++ P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; ++ BOOLEAN fgRetValue = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && (prJoinInfo != NULL)); ++ ++ /* Retry other AuthType if possible */ ++ if (!prJoinInfo->ucAvailableAuthTypes) ++ break; ++ ++ if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(P2P, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else { ++ DBGLOG(P2P, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ prJoinInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ ++ ++ /* Trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ break; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ fgRetValue = TRUE; ++ } while (FALSE); ++ ++ return fgRetValue; ++ ++} /* end of p2pFuncRetryJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the association was completed. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ DEBUGFUNC("p2pUpdateBssInfoForJOIN()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prAssocRspSwRfb); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ ++ DBGLOG(P2P, INFO, "Update P2P_BSS_INFO_T and apply settings to MAC\n"); ++ ++ /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prP2pBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); ++ ++ if (prBssDesc == NULL) { ++ /* Target BSS NULL. */ ++ DBGLOG(P2P, TRACE, "Target BSS NULL\n"); ++ return; ++ } ++ ++ if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAssocRspFrame->aucBSSID)) ++ ASSERT(FALSE); ++ /* 4 <1.3> Setup Channel, Band */ ++ prP2pBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; ++ prP2pBssInfo->eBand = prBssDesc->eBand; ++ ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ ++ prP2pBssInfo->prStaRecOfAP = prStaRec; ++ prP2pBssInfo->u2AssocId = prStaRec->u2AssocId; ++ ++ /* 4 <2.2> Setup Capability */ ++ prP2pBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ ++ ++ if (prP2pBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) ++ prP2pBssInfo->fgIsShortPreambleAllowed = TRUE; ++ else ++ prP2pBssInfo->fgIsShortPreambleAllowed = FALSE; ++ ++ /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prP2pBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prP2pBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prP2pBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prP2pBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ /* 4 <3.1> Setup BSSID */ ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ /* 4 <3.2> Parse WMM and setup QBSS flag */ ++ /* Parse WMM related IEs and configure HW CRs accordingly */ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ prP2pBssInfo->fgIsQBSS = prStaRec->fgIsQoS; ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ ASSERT(prBssDesc); ++ ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <4.1> Setup MIB for current BSS */ ++ prP2pBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ ++ prP2pBssInfo->ucDTIMPeriod = 0; ++ prP2pBssInfo->u2ATIMWindow = 0; ++ ++ prP2pBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; ++ ++ /* 4 <4.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.3> Sync with firmware for BSS-INFO */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ ++ /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ ++ ++} /* end of p2pUpdateBssInfoForJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Auth Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Auth ++* @retval FALSE Don't reply the Auth ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAuth = TRUE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; ++ ++ DBGLOG(P2P, INFO, "p2pValidate Authentication Frame\n"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prSwRfb != NULL) && (pprStaRec != NULL) && (pu2StatusCode != NULL)); ++ ++ /* P2P 3.2.8 */ ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ || (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { ++ /* We are not under AP Mode yet. */ ++ fgReplyAuth = FALSE; ++ DBGLOG(P2P, WARN, ++ "Current OP mode is not under AP mode. (%d)\n", prP2pBssInfo->eCurrentOPMode); ++ break; ++ } ++ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX, prAuthFrame->aucSrcAddr); ++ ++ if (!prStaRec) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ /* Sent a message event to clean un-used STA_RECORD_T. */ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ DBGLOG(AAA, INFO, "Station Limit Full. Decline a new Authentication.\n"); ++ break; ++ } ++ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); ++ ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ ++ prStaRec->u2BSSBasicRateSet = prP2pBssInfo->u2BSSBasicRateSet; ++ ++ prStaRec->u2DesiredNonHTRateSet = RATE_SET_ERP_P2P; ++ ++ prStaRec->u2OperationalRateSet = RATE_SET_ERP_P2P; ++ prStaRec->ucPhyTypeSet = PHY_TYPE_SET_802_11GN; ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } else { ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ ++ if ((prStaRec->ucStaState > STA_STATE_1) && (IS_STA_IN_P2P(prStaRec))) { ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ } ++ ++ } ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ /* GROUP limit full. */ ++ /* P2P 3.2.8 */ ++ DBGLOG(P2P, WARN, ++ "Group Limit Full. (%d)\n", (INT_16) prP2pBssInfo->rStaRecOfClientList.u4NumElem); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ fgReplyAuth = TRUE; ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD; ++ break; ++ } ++ /* Hotspot Blacklist */ ++ if (prAuthFrame->aucSrcAddr) { ++ if (kalP2PCmpBlackList(prAdapter->prGlueInfo, prAuthFrame->aucSrcAddr)) { ++ fgReplyAuth = TRUE; ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD; ++ return fgReplyAuth; ++ } ++ } ++ ++ /* prStaRec->eStaType = STA_TYPE_INFRA_CLIENT; */ ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ prStaRec->ucJoinFailureCount = 0; ++ ++ *pprStaRec = prStaRec; ++ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ } while (FALSE); ++ ++ return fgReplyAuth; ++ ++} /* p2pFuncValidateAuth */ ++ ++VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ do { ++ if ((prAdapter == NULL) || (prStaRec == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->u2ReasonCode = REASON_CODE_RESERVED; ++ prStaRec->ucJoinFailureCount = 0; ++ prStaRec->fgTransmitKeyExist = FALSE; ++ ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ ++ } while (FALSE); ++ ++} /* p2pFuncResetStaRecStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function is used to initialize the value of the connection settings for ++* P2P network ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings) ++{ ++ P_DEVICE_TYPE_T prDevType; ++ UINT_8 aucDefaultDevName[] = P2P_DEFAULT_DEV_NAME; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++#if CFG_SUPPORT_CFG_FILE ++ P_WIFI_VAR_T prWifiVar = NULL; ++#endif ++ ++ ASSERT(prP2PConnSettings); ++#if CFG_SUPPORT_CFG_FILE ++ prWifiVar = &(prAdapter->rWifiVar); ++ ASSERT(prWifiVar); ++#endif ++ ++ /* Setup Default Device Name */ ++ prP2PConnSettings->ucDevNameLen = P2P_DEFAULT_DEV_NAME_LEN; ++ kalMemCopy(prP2PConnSettings->aucDevName, aucDefaultDevName, sizeof(aucDefaultDevName)); ++ ++ /* Setup Primary Device Type (Big-Endian) */ ++ prDevType = &prP2PConnSettings->rPrimaryDevTypeBE; ++ ++ prDevType->u2CategoryId = HTONS(P2P_DEFAULT_PRIMARY_CATEGORY_ID); ++ prDevType->u2SubCategoryId = HTONS(P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID); ++ ++ prDevType->aucOui[0] = aucWfaOui[0]; ++ prDevType->aucOui[1] = aucWfaOui[1]; ++ prDevType->aucOui[2] = aucWfaOui[2]; ++ prDevType->aucOui[3] = VENDOR_OUI_TYPE_WPS; ++ ++ /* Setup Secondary Device Type */ ++ prP2PConnSettings->ucSecondaryDevTypeCount = 0; ++ ++ /* Setup Default Config Method */ ++ prP2PConnSettings->eConfigMethodSelType = ENUM_CONFIG_METHOD_SEL_AUTO; ++ prP2PConnSettings->u2ConfigMethodsSupport = P2P_DEFAULT_CONFIG_METHOD; ++ prP2PConnSettings->u2TargetConfigMethod = 0; ++ prP2PConnSettings->u2LocalConfigMethod = 0; ++ prP2PConnSettings->fgIsPasswordIDRdy = FALSE; ++ ++ /* For Device Capability */ ++ prP2PConnSettings->fgSupportServiceDiscovery = FALSE; ++ prP2PConnSettings->fgSupportClientDiscoverability = TRUE; ++ prP2PConnSettings->fgSupportConcurrentOperation = TRUE; ++ prP2PConnSettings->fgSupportInfraManaged = FALSE; ++ prP2PConnSettings->fgSupportInvitationProcedure = FALSE; ++ ++ /* For Group Capability */ ++#if CFG_SUPPORT_PERSISTENT_GROUP ++ prP2PConnSettings->fgSupportPersistentP2PGroup = TRUE; ++#else ++ prP2PConnSettings->fgSupportPersistentP2PGroup = FALSE; ++#endif ++ prP2PConnSettings->fgSupportIntraBSSDistribution = TRUE; ++ prP2PConnSettings->fgSupportCrossConnection = TRUE; ++ prP2PConnSettings->fgSupportPersistentReconnect = FALSE; ++ ++ prP2PConnSettings->fgSupportOppPS = FALSE; ++ prP2PConnSettings->u2CTWindow = P2P_CTWINDOW_DEFAULT; ++ ++ /* For Connection Settings. */ ++ prP2PConnSettings->eAuthMode = AUTH_MODE_OPEN; ++ ++ prP2PConnSettings->prTargetP2pDesc = NULL; ++ prP2PConnSettings->ucSSIDLen = 0; ++ ++ /* Misc */ ++ prP2PConnSettings->fgIsScanReqIssued = FALSE; ++ prP2PConnSettings->fgIsServiceDiscoverIssued = FALSE; ++ prP2PConnSettings->fgP2pGroupLimit = FALSE; ++ prP2PConnSettings->ucOperatingChnl = 0; ++ prP2PConnSettings->ucListenChnl = 0; ++ prP2PConnSettings->ucTieBreaker = (UINT_8) (kalRandomNumber() & 0x1); ++ ++ prP2PConnSettings->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; ++#if CFG_SUPPORT_CFG_FILE ++ /* prP2PConnSettings->fgIsWPSMode = prWifiVar->ucApWpsMode; */ ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = prWifiVar->ucApWpsMode; ++#endif ++} /* p2pFuncInitConnectionSettings */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Assoc Req Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Assoc Resp ++* @retval FALSE Don't reply the Assoc Resp ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAssocResp = TRUE; ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_WFD_ATTRIBUTE_T prWfdAttribute = (P_WFD_ATTRIBUTE_T) NULL; ++ BOOLEAN fgNeedFree = FALSE; ++#endif ++ /* UINT_16 u2AttriListLen = 0; */ ++ UINT_16 u2WfdDevInfo = 0; ++ P_WFD_DEVICE_INFORMATION_IE_T prAttriWfdDevInfo; ++ ++ /* TODO(Kevin): Call P2P functions to check .. ++ 2. Check we can accept connection from thsi peer ++ a. If we are in PROVISION state, only accept the peer we do the GO formation previously. ++ b. If we are in OPERATION state, only accept the other peer when P2P_GROUP_LIMIT is 0. ++ 3. Check Black List here. ++ */ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (pu2StatusCode != NULL)); ++ ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec == NULL) { ++ /* Station record should be ready while RX AUTH frame. */ ++ fgReplyAssocResp = FALSE; ++ ASSERT(FALSE); ++ break; ++ } ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ prStaRec->u2DesiredNonHTRateSet &= prP2pBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prP2pBssInfo->ucPhyTypeSet; ++ ++ if (prStaRec->ucDesiredPhyTypeSet == 0) { ++ /* The station only support 11B rate. */ ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++#if CFG_SUPPORT_WFD && 1 ++ /* LOG_FUNC("Skip check WFD IE because some API is not ready\n"); */ ++ if (!prAdapter->rWifiVar.prP2pFsmInfo) { ++ fgReplyAssocResp = FALSE; ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ DBGLOG(P2P, INFO, "AssocReq, wfd_en %u wfd_info 0x%x wfd_policy 0x%x wfd_flag 0x%x\n", ++ prWfdCfgSettings->ucWfdEnable, prWfdCfgSettings->u2WfdDevInfo, ++ prWfdCfgSettings->u4WfdPolicy, prWfdCfgSettings->u4WfdFlag); /* Eddie */ ++ if (prWfdCfgSettings->ucWfdEnable) { ++ if (prWfdCfgSettings->u4WfdPolicy & BIT(6)) { ++ /* Rejected all. */ ++ break; ++ } ++ ++ /* fgNeedFree = p2pFuncGetAttriList(prAdapter, */ ++ /* VENDOR_OUI_TYPE_WFD, */ ++ /* (PUINT_8)prAssocReqFrame->aucInfoElem, */ ++ /* (prSwRfb->u2PacketLen - OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), */ ++ /* (PPUINT_8)&prWfdAttribute, */ ++ /* &u2AttriListLen); */ ++ ++ prAttriWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) ++ p2pFuncGetSpecAttri(prAdapter, ++ VENDOR_OUI_TYPE_WFD, ++ (PUINT_8) prAssocReqFrame->aucInfoElem, ++ (prSwRfb->u2PacketLen - ++ OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), ++ WFD_ATTRI_ID_DEV_INFO); ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(5)) && (prAttriWfdDevInfo != NULL)) { ++ /* Rejected with WFD IE. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(0)) && (prAttriWfdDevInfo == NULL)) { ++ /* Rejected without WFD IE. */ ++ break; ++ } ++ ++ if (prAttriWfdDevInfo == NULL) { ++ /* ++ * Without WFD IE. ++ * Do nothing. Accept the connection request. ++ */ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ break; ++ } ++ ++ /* prAttriWfdDevInfo = */ ++ /* (P_WFD_DEVICE_INFORMATION_IE_T)p2pFuncGetSpecAttri(prAdapter, */ ++ /* VENDOR_OUI_TYPE_WFD, */ ++ /* (PUINT_8)prWfdAttribute, */ ++ /* u2AttriListLen, */ ++ /* WFD_ATTRI_ID_DEV_INFO); */ ++ /* if (prAttriWfdDevInfo == NULL) { */ ++ /* No such attribute. */ ++ /* break; */ ++ /* } */ ++ ++ WLAN_GET_FIELD_BE16(&prAttriWfdDevInfo->u2WfdDevInfo, &u2WfdDevInfo); ++ DBGLOG(P2P, INFO, "RX Assoc Req WFD Info:0x%x.\n", u2WfdDevInfo); ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(1)) && ((u2WfdDevInfo & 0x3) == 0x0)) { ++ /* Rejected because of SOURCE. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(2)) && ((u2WfdDevInfo & 0x3) == 0x1)) { ++ /* Rejected because of Primary Sink. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(3)) && ((u2WfdDevInfo & 0x3) == 0x2)) { ++ /* Rejected because of Secondary Sink. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(4)) && ((u2WfdDevInfo & 0x3) == 0x3)) { ++ /* Rejected because of Source & Primary Sink. */ ++ break; ++ } ++ ++ /* Check role */ ++ ++ if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) && ++ ((prWfdCfgSettings->u2WfdDevInfo & BITS(0, 1)) == 0x3)) { ++ /* P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = ++ * (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)NULL; */ ++ UINT_16 u2DevInfo = prWfdCfgSettings->u2WfdDevInfo; ++ ++ /* We may change role here if we are dual role */ ++ ++ if ((u2WfdDevInfo & BITS(0, 1)) == 0x00 /* Peer is Source */) { ++ DBGLOG(P2P, INFO, "WFD: Switch role to primary sink\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ prWfdCfgSettings->u2WfdDevInfo |= 0x1; ++ ++ /* event to annonce the role is chanaged to P-Sink */ ++ ++ } else if ((u2WfdDevInfo & BITS(0, 1)) == 0x01 /* Peer is P-Sink */) { ++ DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ /* event to annonce the role is chanaged to Source */ ++ } else { ++ DBGLOG(P2P, INFO, "WFD: Peer role is wrong type(dev 0x%x)\n", ++ (u2DevInfo)); ++ DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ /* event to annonce the role is chanaged to Source */ ++ } ++ ++ p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); ++ ++ } /* Dual role p2p->wfd_params->WfdDevInfo */ ++ ++ /* WFD_FLAG_DEV_INFO_VALID */ ++ } ++ /* ucWfdEnable */ ++#endif ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ } while (FALSE); ++ ++#if CFG_SUPPORT_WFD ++ if ((prWfdAttribute) && (fgNeedFree)) ++ kalMemFree(prWfdAttribute, VIR_MEM_TYPE, WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE); ++#endif ++ ++ return fgReplyAssocResp; ++ ++} /* p2pFuncValidateAssocReq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to check the P2P IE ++* ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType) ++{ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ P_IE_WFA_T prWfaIE = (P_IE_WFA_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pucOuiType != NULL)); ++ ++ prWfaIE = (P_IE_WFA_T) pucBuf; ++ ++ if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { ++ break; ++ } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || ++ prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { ++ break; ++ } ++ ++ *pucOuiType = prWfaIE->ucOuiType; ++ ++ return TRUE; ++ } while (FALSE); ++ ++ return FALSE; ++} /* p2pFuncParseCheckForP2PInfoElem */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ BOOLEAN fgIsReplyProbeRsp = FALSE; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("p2pFuncValidateProbeReq"); ++ DBGLOG(P2P, TRACE, "p2pFuncValidateProbeReq\n"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ) { ++ ++ DBGLOG(P2P, TRACE, "report probe req to OS\n"); ++ /* Leave the probe response to p2p_supplicant. */ ++ kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return fgIsReplyProbeRsp; ++ ++} /* end of p2pFuncValidateProbeReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("p2pFuncValidateProbeReq"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME) { ++ /* Leave the probe response to p2p_supplicant. */ ++ kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncValidateRxMgmtFrame */ ++ ++BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ if (prP2pFsmInfo) { ++ if (prP2pFsmInfo->fgIsWPSMode == 1) ++ return FALSE; ++ return prP2pFsmInfo->fgIsApMode; ++ } else { ++ return FALSE; ++ } ++} ++ ++/* p2pFuncIsAPMode */ ++ ++VOID ++p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen) ++{ ++ PUINT_8 pucIE = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ BOOLEAN ucNewSecMode = FALSE; ++ BOOLEAN ucOldSecMode = FALSE; ++ UINT_8 ucOuiType; ++ UINT_16 u2SubTypeVersion; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); ++ ++ if (u4IELen == 0) ++ break; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pSpecificBssInfo->u2AttributeLen = 0; ++ ++ ASSERT_BREAK(pucIEInfo != NULL); ++ ++ pucIE = pucIEInfo; ++ ++ ucOldSecMode = kalP2PGetCipher(prAdapter->prGlueInfo); ++ ++ IE_FOR_EACH(pucIE, u4IELen, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ { ++ /* 0 */ /* V */ /* Done */ ++ /* DBGLOG(P2P, TRACE, ("SSID update\n")); */ ++ /* SSID is saved when start AP/GO */ ++ /* SSID IE set in beacon from supplicant will not always be */ ++ /* the true since hidden SSID case */ ++ /* ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, ++ SSID_IE(pucIE)->aucSSID, ++ SSID_IE(pucIE)->ucLength); ++ ++ COPY_SSID(prP2pSpecificBssInfo->aucGroupSsid, ++ prP2pSpecificBssInfo->u2GroupSsidLen, ++ SSID_IE(pucIE)->aucSSID, ++ SSID_IE(pucIE)->ucLength); ++ */ ++ } ++ break; ++ case ELEM_ID_SUP_RATES: ++ { ++ /* 1 */ /* V */ /* Done */ ++ DBGLOG(P2P, TRACE, "Support Rate IE\n"); ++ kalMemCopy(prP2pBssInfo->aucAllSupportedRates, ++ SUP_RATES_IE(pucIE)->aucSupportedRates, ++ SUP_RATES_IE(pucIE)->ucLength); ++ ++ prP2pBssInfo->ucAllSupportedRatesLen = SUP_RATES_IE(pucIE)->ucLength; ++ ++ DBGLOG_MEM8(P2P, TRACE, SUP_RATES_IE(pucIE)->aucSupportedRates, ++ SUP_RATES_IE(pucIE)->ucLength); ++ } ++ break; ++ case ELEM_ID_DS_PARAM_SET: ++ { ++ /* 3 */ /* V */ /* Done */ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = ++ prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "DS PARAM IE\n"); ++ ++ ASSERT(prP2pConnSettings->ucOperatingChnl == DS_PARAM_IE(pucIE)->ucCurrChnl); ++ ++ if (prP2pConnSettings->eBand != BAND_2G4) { ++ ASSERT(FALSE); ++ break; ++ } ++ /* prP2pBssInfo->ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; */ ++ ++ /* prP2pBssInfo->eBand = BAND_2G4; */ ++ } ++ break; ++ case ELEM_ID_TIM: /* 5 */ /* V */ ++ DBGLOG(P2P, TRACE, "TIM IE\n"); ++ TIM_IE(pucIE)->ucDTIMPeriod = prP2pBssInfo->ucDTIMPeriod; ++ break; ++ case ELEM_ID_ERP_INFO: /* 42 */ /* V */ ++ { ++#if 1 ++ /* This IE would dynamic change due to FW detection change is required. */ ++ DBGLOG(P2P, TRACE, "ERP IE will be over write by driver\n"); ++ DBGLOG(P2P, TRACE, " ucERP: %x.\n", ERP_INFO_IE(pucIE)->ucERP); ++ ++#else ++ /* This IE would dynamic change due to FW detection change is required. */ ++ DBGLOG(P2P, TRACE, "ERP IE.\n"); ++ ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11GN; ++ ++ ASSERT(prP2pBssInfo->eBand == BAND_2G4); ++ ++ prP2pBssInfo->fgObssErpProtectMode = ++ ((ERP_INFO_IE(pucIE)->ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE); ++ ++ prP2pBssInfo->fgErpProtectMode = ++ ((ERP_INFO_IE(pucIE)->ucERP & ++ (ERP_INFO_USE_PROTECTION | ERP_INFO_NON_ERP_PRESENT)) ? TRUE : FALSE); ++#endif ++ ++ } ++ break; ++ case ELEM_ID_HT_CAP: /* 45 */ /* V */ ++ { ++#if 1 ++ DBGLOG(P2P, TRACE, "HT CAP IE would be overwritten by driver\n"); ++ ++ DBGLOG(P2P, TRACE, ++ "HT Cap Info:%x, AMPDU Param:%x\n", HT_CAP_IE(pucIE)->u2HtCapInfo, ++ HT_CAP_IE(pucIE)->ucAmpduParam); ++ ++ DBGLOG(P2P, TRACE, ++ "HT Extended Cap Info%x,TX Beamforming Cap Info%x,Ant Selection Cap Info%x\n", ++ HT_CAP_IE(pucIE)->u2HtExtendedCap, HT_CAP_IE(pucIE)->u4TxBeamformingCap, ++ HT_CAP_IE(pucIE)->ucAselCap); ++#else ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ ++ /* u2HtCapInfo */ ++ if ((HT_CAP_IE(pucIE)->u2HtCapInfo & ++ (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | ++ HT_CAP_INFO_DSSS_CCK_IN_40M)) == 0) { ++ prP2pBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } else { ++ prP2pBssInfo->fgAssoc40mBwAllowed = TRUE; ++ } ++ ++ if ((HT_CAP_IE(pucIE)->u2HtCapInfo & ++ (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M)) == 0) { ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; ++ } else { ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = FALSE; ++ } ++ ++ /* ucAmpduParam */ ++ DBGLOG(P2P, TRACE, ++ "AMPDU setting from supplicant:0x%x, & default value:0x%x\n", ++ (UINT_8) HT_CAP_IE(pucIE)->ucAmpduParam, ++ (UINT_8) AMPDU_PARAM_DEFAULT_VAL); ++ ++ /* rSupMcsSet */ ++ /* Can do nothing. the field is default value from other configuration. */ ++ /* HT_CAP_IE(pucIE)->rSupMcsSet; */ ++ ++ /* u2HtExtendedCap */ ++ ASSERT(HT_CAP_IE(pucIE)->u2HtExtendedCap == ++ (HT_EXT_CAP_DEFAULT_VAL & ++ ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE))); ++ ++ /* u4TxBeamformingCap */ ++ ASSERT(HT_CAP_IE(pucIE)->u4TxBeamformingCap == TX_BEAMFORMING_CAP_DEFAULT_VAL); ++ ++ /* ucAselCap */ ++ ASSERT(HT_CAP_IE(pucIE)->ucAselCap == ASEL_CAP_DEFAULT_VAL); ++#endif ++ } ++ break; ++ case ELEM_ID_RSN: /* 48 */ /* V */ ++ { ++ RSN_INFO_T rRsnIe; ++ ++ DBGLOG(P2P, TRACE, "RSN IE\n"); ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); ++ ucNewSecMode = TRUE; ++ ++ if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) { ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++ prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap; ++ } ++ } ++ break; ++ case ELEM_ID_EXTENDED_SUP_RATES: /* 50 */ /* V */ ++ /* Be attention, ++ * ELEM_ID_SUP_RATES should be placed before ELEM_ID_EXTENDED_SUP_RATES. */ ++ DBGLOG(P2P, TRACE, "Ex Support Rate IE\n"); ++ kalMemCopy(&(prP2pBssInfo->aucAllSupportedRates[prP2pBssInfo->ucAllSupportedRatesLen]), ++ EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, ++ EXT_SUP_RATES_IE(pucIE)->ucLength); ++ ++ DBGLOG_MEM8(P2P, TRACE, EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, ++ EXT_SUP_RATES_IE(pucIE)->ucLength); ++ ++ prP2pBssInfo->ucAllSupportedRatesLen += EXT_SUP_RATES_IE(pucIE)->ucLength; ++ break; ++ case ELEM_ID_HT_OP: ++ { ++ /* 61 */ /* V */ /* TODO: */ ++#if 1 ++ DBGLOG(P2P, TRACE, "HT OP IE would be overwritten by driver\n"); ++ ++ DBGLOG(P2P, TRACE, ++ " Primary Channel: %x, Info1: %x, Info2: %x, Info3: %x\n", ++ HT_OP_IE(pucIE)->ucPrimaryChannel, HT_OP_IE(pucIE)->ucInfo1, ++ HT_OP_IE(pucIE)->u2Info2, HT_OP_IE(pucIE)->u2Info3); ++#else ++ UINT_16 u2Info2 = 0; ++ ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ ++ DBGLOG(P2P, TRACE, "HT OP IE\n"); ++ ++ /* ucPrimaryChannel. */ ++ ASSERT(HT_OP_IE(pucIE)->ucPrimaryChannel == prP2pBssInfo->ucPrimaryChannel); ++ ++ /* ucInfo1 */ ++ prP2pBssInfo->ucHtOpInfo1 = HT_OP_IE(pucIE)->ucInfo1; ++ ++ /* u2Info2 */ ++ u2Info2 = HT_OP_IE(pucIE)->u2Info2; ++ ++ if (u2Info2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { ++ ASSERT(prP2pBssInfo->eGfOperationMode != GF_MODE_NORMAL); ++ u2Info2 &= ~HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (u2Info2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) { ++ prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; ++ u2Info2 &= ~HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ switch (u2Info2 & HT_OP_INFO2_HT_PROTECTION) { ++ case HT_PROTECT_MODE_NON_HT: ++ prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NON_HT; ++ break; ++ case HT_PROTECT_MODE_NON_MEMBER: ++ prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; ++ prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; ++ break; ++ default: ++ prP2pBssInfo->eHtProtectMode = HT_OP_IE(pucIE)->u2Info2; ++ break; ++ } ++ ++ /* u2Info3 */ ++ prP2pBssInfo->u2HtOpInfo3 = HT_OP_IE(pucIE)->u2Info3; ++ ++ /* aucBasicMcsSet */ ++ DBGLOG_MEM8(P2P, TRACE, HT_OP_IE(pucIE)->aucBasicMcsSet, 16); ++#endif ++ } ++ break; ++ case ELEM_ID_OBSS_SCAN_PARAMS: /* 74 */ /* V */ ++ { ++ DBGLOG(P2P, TRACE, ++ "ELEM_ID_OBSS_SCAN_PARAMS IE would be replaced by driver\n"); ++ } ++ break; ++ case ELEM_ID_EXTENDED_CAP: /* 127 */ /* V */ ++ { ++ DBGLOG(P2P, TRACE, "ELEM_ID_EXTENDED_CAP IE would be replaced by driver\n"); ++ } ++ break; ++ case ELEM_ID_VENDOR: /* 221 */ /* V */ ++ DBGLOG(P2P, TRACE, "Vender Specific IE\n"); ++ if (rsnParseCheckForWFAInfoElem ++ (prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { ++ if ((ucOuiType == VENDOR_OUI_TYPE_WPA) ++ && (u2SubTypeVersion == VERSION_WPA)) { ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_TKIP); ++ ucNewSecMode = TRUE; ++ kalMemCopy(prP2pSpecificBssInfo->aucWpaIeBuffer, pucIE, ++ IE_SIZE(pucIE)); ++ prP2pSpecificBssInfo->u2WpaIeLen = IE_SIZE(pucIE); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 0, pucIE, ++ IE_SIZE(pucIE)); ++ } ++ /* WMM here. */ ++ } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { ++ /* TODO Store the whole P2P IE & generate later. */ ++ /* Be aware that there may be one or more P2P IE. */ ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ } ++ } else { ++ ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ DBGLOG(P2P, TRACE, "Driver unprocessed Vender Specific IE\n"); ++ ASSERT(FALSE); ++ } ++ ++ /* TODO: Store other Vender IE except for WMM Param. */ ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Unprocessed element ID:%d\n", IE_ID(pucIE)); ++ break; ++ } ++ } ++ ++ if (!ucNewSecMode && ucOldSecMode) ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_NONE); ++ ++ } while (FALSE); ++ ++} /* p2pFuncParseBeaconContent */ ++ ++P_BSS_DESC_T ++p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, ++ IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) ++{ ++ P_BSS_DESC_T prTargetBss = (P_BSS_DESC_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prConnReqInfo != NULL) && (prChnlReqInfo != NULL) && (prScanReqInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ break; ++ /* Update connection request information. */ ++ ASSERT(prConnReqInfo->fgIsConnRequest == TRUE); ++ ++ /* Find BSS Descriptor first. */ ++ prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); ++ ++ if (prTargetBss == NULL) { ++ /* Update scan parameter... to scan target device. */ ++ prScanReqInfo->ucNumChannelList = 1; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; ++ prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ } else { ++ prChnlReqInfo->u8Cookie = 0; ++ prChnlReqInfo->ucReqChnlNum = prTargetBss->ucChannelNum; ++ prChnlReqInfo->eBand = prTargetBss->eBand; ++ prChnlReqInfo->eChnlSco = prTargetBss->eSco; ++ prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; ++ } ++ ++ } while (FALSE); ++ ++ return prTargetBss; ++} /* p2pFuncKeepOnConnection */ ++ ++/* Currently Only for ASSOC Response Frame. */ ++VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ INT_16 i2IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prAssocRspFrame->u2FrameCtrl != MAC_FRAME_ASSOC_RSP) ++ break; ++ ++ i2IELen = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); ++ ++ if (i2IELen <= 0) ++ break; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prJoinInfo = &(prP2pFsmInfo->rJoinInfo); ++ prJoinInfo->u4BufLength = (UINT_32) i2IELen; ++ ++ kalMemCopy(prJoinInfo->aucIEBuf, prAssocRspFrame->aucInfoElem, prJoinInfo->u4BufLength); ++ ++ } while (FALSE); ++ ++} /* p2pFuncStoreAssocRspIEBuffer */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Packet Filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, ++ IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter) ++{ ++ UINT_32 u4NewPacketFilter = 0; ++ ++ DEBUGFUNC("p2pFuncMgmtFrameRegister"); ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ if (pu4P2pPacketFilter) ++ u4NewPacketFilter = *pu4P2pPacketFilter; ++ ++ switch (u2FrameType) { ++ case MAC_FRAME_PROBE_REQ: ++ if (fgIsRegistered) { ++ u4NewPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); ++ } else { ++ u4NewPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (fgIsRegistered) { ++ u4NewPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); ++ } else { ++ u4NewPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Ask frog to add code for mgmt:%x\n", u2FrameType); ++ break; ++ } ++ ++ if (pu4P2pPacketFilter) ++ *pu4P2pPacketFilter = u4NewPacketFilter; ++ ++ /* u4NewPacketFilter |= prAdapter->u4OsPacketFilter; */ ++ ++ prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; ++ prAdapter->u4OsPacketFilter |= u4NewPacketFilter; ++ ++ DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, ++ &u4NewPacketFilter, sizeof(u4NewPacketFilter) ++ ); ++ ++ } while (FALSE); ++ ++} /* p2pFuncMgmtFrameRegister */ ++ ++VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter) ++{ ++ ++ do { ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->u4P2pPacketFilter = u4OsFilter; ++ ++ if ((prAdapter->u4OsPacketFilter & PARAM_PACKET_FILTER_P2P_MASK) ^ u4OsFilter) { ++ ++ prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; ++ ++ prAdapter->u4OsPacketFilter |= (u4OsFilter & PARAM_PACKET_FILTER_P2P_MASK); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, &u4OsFilter, sizeof(u4OsFilter) ++ ); ++ DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncUpdateMgmtFrameRegister */ ++ ++VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo) ++{ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucMacAddr != NULL) && (prStaInfo != NULL)); ++ ++ prStaInfo->u4InactiveTime = 0; ++ prStaInfo->u4RxBytes = 0; ++ prStaInfo->u4TxBytes = 0; ++ prStaInfo->u4RxPackets = 0; ++ prStaInfo->u4TxPackets = 0; ++ /* TODO: */ ++ ++ } while (FALSE); ++ ++} /* p2pFuncGetStationInfo */ ++ ++BOOLEAN ++p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen) ++{ ++ BOOLEAN fgIsAllocMem = FALSE; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_16 u2Offset = 0; ++ P_IE_P2P_T prIe = (P_IE_P2P_T) NULL; ++ PUINT_8 pucAttriListStart = (PUINT_8) NULL; ++ UINT_16 u2AttriListLen = 0, u2BufferSize = 0; ++ BOOLEAN fgBackupAttributes = FALSE; ++ UINT_16 u2CopyLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucIE); ++ ASSERT(ppucAttriList); ++ ASSERT(pu2AttriListLen); ++ ++ if (ppucAttriList) ++ *ppucAttriList = NULL; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = 0; ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ aucWfaOui[0] = 0x00; ++ aucWfaOui[1] = 0x50; ++ aucWfaOui[2] = 0xF2; ++ } else if ((ucOuiType != VENDOR_OUI_TYPE_P2P) ++#if CFG_SUPPORT_WFD ++ && (ucOuiType != VENDOR_OUI_TYPE_WFD) ++#endif ++ ) { ++ DBGLOG(P2P, INFO, "Not supported OUI Type to parsing 0x%x\n", ucOuiType); ++ return fgIsAllocMem; ++ } ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_VENDOR != IE_ID(pucIE)) ++ continue; ++ ++ prIe = (P_IE_P2P_T) pucIE; ++ ++ if (prIe->ucLength <= P2P_OUI_TYPE_LEN) ++ continue; ++ ++ if ((prIe->aucOui[0] == aucWfaOui[0]) && ++ (prIe->aucOui[1] == aucWfaOui[1]) && ++ (prIe->aucOui[2] == aucWfaOui[2]) && (ucOuiType == prIe->ucOuiType)) { ++ ++ if (!pucAttriListStart) { ++ pucAttriListStart = &prIe->aucP2PAttributes[0]; ++ if (prIe->ucLength > P2P_OUI_TYPE_LEN) ++ u2AttriListLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); ++ else ++ ASSERT(FALSE); ++ continue; ++ } ++/* More than 2 attributes. */ ++ ++ if (FALSE == fgBackupAttributes) { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = ++ prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ fgBackupAttributes = TRUE; ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache[0], ++ pucAttriListStart, u2AttriListLen); ++ ++ pucAttriListStart = ++ &prP2pSpecificBssInfo->aucAttributesCache[0]; ++ ++ u2BufferSize = P2P_MAXIMUM_ATTRIBUTE_LEN; ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucWscAttributesCache ++ [0], pucAttriListStart, u2AttriListLen); ++ pucAttriListStart = ++ &prP2pSpecificBssInfo->aucWscAttributesCache[0]; ++ ++ u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; ++ } ++#if CFG_SUPPORT_WFD ++ else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ PUINT_8 pucTmpBuf = (PUINT_8) NULL; ++ ++ pucTmpBuf = (PUINT_8) ++ kalMemAlloc(WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE, ++ VIR_MEM_TYPE); ++ ++ if (pucTmpBuf != NULL) { ++ fgIsAllocMem = TRUE; ++ } else { ++ /* Can't alloca memory for WFD IE relocate. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ kalMemCopy(pucTmpBuf, ++ pucAttriListStart, u2AttriListLen); ++ ++ pucAttriListStart = pucTmpBuf; ++ ++ u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; ++ } ++#endif ++ else ++ fgBackupAttributes = FALSE; ++ } ++ ++ u2CopyLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); ++ ++ if ((u2AttriListLen + u2CopyLen) > u2BufferSize) { ++ u2CopyLen = u2BufferSize - u2AttriListLen; ++ DBGLOG(P2P, WARN, ++ "Length of received P2P attributes > maximum cache size.\n"); ++ } ++ ++ if (u2CopyLen) { ++ kalMemCopy((PUINT_8) ++ ((ULONG) pucAttriListStart + ++ (UINT_32) u2AttriListLen), ++ &prIe->aucP2PAttributes[0], u2CopyLen); ++ ++ u2AttriListLen += u2CopyLen; ++ } ++ } /* prIe->aucOui */ ++ } /* IE_FOR_EACH */ ++ ++ if (pucAttriListStart) { ++ PUINT_8 pucAttribute = pucAttriListStart; ++ ++ DBGLOG(P2P, LOUD, "Checking Attribute Length.\n"); ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ P2P_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ /* Do nothing */ ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ /* Big Endian: WSC, WFD. */ ++ WSC_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset) { ++ DBGLOG(P2P, LOUD, "Attribute ID:%d, Length:%d.\n", ++ WSC_ATTRI_ID(pucAttribute), WSC_ATTRI_LEN(pucAttribute)); ++ } ++ } else { ++ } ++ ++ ASSERT(u2Offset == u2AttriListLen); ++ ++ if (ppucAttriList) ++ *ppucAttriList = pucAttriListStart; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = u2AttriListLen; ++ ++ } else { ++ if (ppucAttriList) ++ *ppucAttriList = (PUINT_8) NULL; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = 0; ++ } ++ ++ return fgIsAllocMem; ++} /* p2pFuncGetAttriList */ ++ ++P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu) ++{ ++ P_MSDU_INFO_T prRetMsduInfo = prMgmtTxMsdu; ++ P_WLAN_PROBE_RSP_FRAME_T prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0, u2IELength = 0, u2ProbeRspHdrLen = 0; ++ BOOLEAN fgIsP2PIE = FALSE, fgIsWSCIE = FALSE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ UINT_16 u2EstimateSize = 0, u2EstimatedExtraIELen = 0; ++ UINT_32 u4IeArraySize = 0, u4Idx = 0; ++ UINT_8 ucOuiType = 0; ++ UINT_16 u2SubTypeVersion = 0; ++ ++ BOOLEAN fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxMsdu != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ /* 3 Make sure this is probe response frame. */ ++ prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ ASSERT_BREAK((prProbeRspFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_PROBE_RSP); ++ ++ if (prP2pBssInfo->u2BeaconInterval) ++ prProbeRspFrame->u2BeaconInterval = prP2pBssInfo->u2BeaconInterval; ++ ++ /* 3 Get the importent P2P IE. */ ++ u2ProbeRspHdrLen = ++ (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ pucIEBuf = prProbeRspFrame->aucInfoElem; ++ u2IELength = prMgmtTxMsdu->u2FrameLength - u2ProbeRspHdrLen; ++ ++#if CFG_SUPPORT_WFD ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen = 0; ++#endif ++ ++ IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { ++ switch (IE_ID(pucIEBuf)) { ++ case ELEM_ID_SSID: ++ { ++ ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, ++ SSID_IE(pucIEBuf)->aucSSID, SSID_IE(pucIEBuf)->ucLength); ++ } ++ break; ++ case ELEM_ID_VENDOR: ++#if !CFG_SUPPORT_WFD ++ if (rsnParseCheckForWFAInfoElem(prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 2, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ fgIsWSCIE = TRUE; ++ } ++ ++ } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIEBuf, &ucOuiType)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ /* 2 Note(frog): I use WSC IE buffer for Probe Request to ++ * store the P2P IE for Probe Response. */ ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 1, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ fgIsP2PIE = TRUE; ++ } ++ ++ } else { ++ if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + ++ IE_SIZE(pucIEBuf)) < 512) { ++ kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, ++ pucIEBuf, IE_SIZE(pucIEBuf)); ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += ++ IE_SIZE(pucIEBuf); ++ } ++ } ++#else ++ /* Eddie May be WFD */ ++ if (rsnParseCheckForWFAInfoElem ++ (prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_WMM) ++ break; ++ ++ } ++ if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + IE_SIZE(pucIEBuf)) < ++ 1024) { ++ kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE + ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += IE_SIZE(pucIEBuf); ++ } ++#endif ++ break; ++ default: ++ break; ++ } ++ ++ } ++ ++ /* 3 Check the total size & current frame. */ ++ u2EstimateSize = WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + ++ BEACON_INTERVAL_FIELD_LEN + ++ CAP_INFO_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET); ++ ++ u2EstimatedExtraIELen = 0; ++ ++ u4IeArraySize = sizeof(txProbeRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { ++ if (txProbeRspIETable[u4Idx].u2EstimatedFixedIELen) { ++ u2EstimatedExtraIELen += txProbeRspIETable[u4Idx].u2EstimatedFixedIELen; ++ } ++ ++ else { ++ ASSERT(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen); ++ ++ u2EstimatedExtraIELen += ++ (UINT_16) (txProbeRspIETable[u4Idx].pfnCalculateVariableIELen ++ (prAdapter, NETWORK_TYPE_P2P_INDEX, NULL)); ++ } ++ ++ } ++ ++ if (fgIsWSCIE) ++ u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); ++ ++ if (fgIsP2PIE) { ++ u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); ++ u2EstimatedExtraIELen += p2pFuncCalculateP2P_IE_NoA(prAdapter, 0, NULL); ++ } ++#if CFG_SUPPORT_WFD ++ u2EstimatedExtraIELen += prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; ++#endif ++ ++ u2EstimateSize += u2EstimatedExtraIELen; ++ if (u2EstimateSize > (prRetMsduInfo->u2FrameLength)) { ++ prRetMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimateSize); ++ ++ if (prRetMsduInfo == NULL) { ++ DBGLOG(P2P, WARN, "No packet for sending new probe response, use original one\n"); ++ prRetMsduInfo = prMgmtTxMsdu; ++ break; ++ } ++ ++ prRetMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } ++ /* 3 Compose / Re-compose probe response frame. */ ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prRetMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prProbeRspFrame->aucDestAddr, prProbeRspFrame->aucSrcAddr, ++ prProbeRspFrame->aucBSSID, prProbeRspFrame->u2BeaconInterval, ++ fgIsPureAP ? prP2pBssInfo-> ++ u2CapInfo : prProbeRspFrame->u2CapInfo); ++ ++ prRetMsduInfo->u2FrameLength = ++ (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ ++ bssBuildBeaconProbeRespFrameCommonIEs(prRetMsduInfo, prP2pBssInfo, prProbeRspFrame->aucDestAddr); ++ ++ for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { ++ if (txProbeRspIETable[u4Idx].pfnAppendIE) ++ txProbeRspIETable[u4Idx].pfnAppendIE(prAdapter, prRetMsduInfo); ++ ++ } ++ ++ if (fgIsWSCIE) { ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, ++ 2, ++ (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + ++ (UINT_32) prRetMsduInfo->u2FrameLength)); ++ ++ prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); ++ } ++ ++ if (fgIsP2PIE) { ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, ++ 1, ++ (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + ++ (UINT_32) prRetMsduInfo->u2FrameLength)); ++ ++ prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); ++ p2pFuncGenerateP2P_IE_NoA(prAdapter, prRetMsduInfo); ++ } ++#if CFG_SUPPORT_WFD ++ if (prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen > 0) { ++ kalMemCopy((PUINT_8) ((ULONG) prRetMsduInfo->prPacket + (UINT_32) prRetMsduInfo->u2FrameLength), ++ prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen); ++ prRetMsduInfo->u2FrameLength += (UINT_16) prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; ++ } ++#endif ++ ++ } while (FALSE); ++ ++ if (prRetMsduInfo != prMgmtTxMsdu) ++ cnmMgtPktFree(prAdapter, prMgmtTxMsdu); ++ ++ return prRetMsduInfo; ++} /* p2pFuncProcessP2pProbeRsp */ ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++UINT_32 ++p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ UINT_32 u4IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4IELen = prP2pSpeBssInfo->u2IELenForBCN; ++ ++ } while (FALSE); ++ ++ return u4IELen; ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ pucIEBuf = (PUINT_8) ((UINT_32) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucBeaconIECache, prP2pSpeBssInfo->u2IELenForBCN); ++ ++ prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2IELenForBCN; ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateExtra_IEForBeacon */ ++ ++#else ++UINT_32 ++p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ UINT_32 u4IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); ++ ++ if (!prAdapter->fgIsP2PRegistered) ++ break; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4IELen = prP2pSpeBssInfo->u2AttributeLen; ++ ++ } while (FALSE); ++ ++ return u4IELen; ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ if (!prAdapter->fgIsP2PRegistered) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucAttributesCache, prP2pSpeBssInfo->u2AttributeLen); ++ ++ prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2AttributeLen; ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateP2p_IEForBeacon */ ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ UINT_16 u2IELen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) ++ return; ++ ++ u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* TODO: Check P2P FSM State. */ ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); ++ ++ prMsduInfo->u2FrameLength += u2IELen; ++ ++} /* p2pFuncGenerateP2p_IEForBeacon */ ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate P2P IE length for Beacon frame. ++* ++* @param[in] eNetTypeIndex Specify which network ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of P2P IE added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ++p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return p2pFuncCalculateP2P_IELen(prAdapter, ++ eNetTypeIndex, ++ prStaRec, ++ txAssocRspAttributesTable, ++ sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ ++} /* p2pFuncCalculateP2p_IELenForAssocRsp */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ if (!prStaRec) ++ break; ++ ++ if (IS_STA_P2P_TYPE(prStaRec)) { ++ DBGLOG(P2P, TRACE, "Generate NULL P2P IE for Assoc Rsp.\n"); ++ ++ p2pFuncGenerateP2P_IE(prAdapter, ++ TRUE, ++ &prMsduInfo->u2FrameLength, ++ prMsduInfo->prPacket, ++ 1500, ++ txAssocRspAttributesTable, ++ sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ } else { ++ ++ DBGLOG(P2P, TRACE, "Legacy device, no P2P IE.\n"); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncGenerateP2p_IEForAssocRsp */ ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ DBGLOG(P2P, TRACE, "p2pFuncCalculateWSC_IELenForAssocRsp\n"); ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++} /* p2pFuncCalculateP2p_IELenForAssocRsp */ ++ ++VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ UINT_16 u2IELen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) ++ return; ++ DBGLOG(P2P, TRACE, "p2pFuncGenerateWSC_IEForAssocRsp\n"); ++ ++ u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* TODO: Check P2P FSM State. */ ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); ++ ++ prMsduInfo->u2FrameLength += u2IELen; ++ ++} ++ ++/* p2pFuncGenerateP2p_IEForAssocRsp */ ++ ++UINT_32 ++p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_STA_RECORD_T prStaRec, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ ++ UINT_32 u4OverallAttriLen, u4Dummy; ++ UINT_16 u2EstimatedFixedAttriLen; ++ UINT_32 i; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ u2EstimatedFixedAttriLen = arAppendAttriTable[i].u2EstimatedFixedAttriLen; ++ ++ if (u2EstimatedFixedAttriLen) { ++ u4OverallAttriLen += u2EstimatedFixedAttriLen; ++ } else { ++ ASSERT(arAppendAttriTable[i].pfnCalculateVariableAttriLen); ++ ++ u4OverallAttriLen += arAppendAttriTable[i].pfnCalculateVariableAttriLen(prAdapter, prStaRec); ++ } ++ } ++ ++ u4Dummy = u4OverallAttriLen; ++ u4OverallAttriLen += P2P_IE_OUI_HDR; ++ ++ for (; (u4Dummy > P2P_MAXIMUM_ATTRIBUTE_LEN);) { ++ u4OverallAttriLen += P2P_IE_OUI_HDR; ++ u4Dummy -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ } ++ ++ return u4OverallAttriLen; ++} /* p2pFuncCalculateP2P_IELen */ ++ ++VOID ++p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ P_IE_P2P_T prIeP2P = (P_IE_P2P_T) NULL; ++ UINT_32 u4OverallAttriLen; ++ UINT_32 u4AttriLen; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; ++ UINT_32 i; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ /* Check buffer length is still enough. */ ++ ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= P2P_IE_OUI_HDR); ++ ++ prIeP2P = (P_IE_P2P_T) pucBuffer; ++ ++ prIeP2P->ucId = ELEM_ID_P2P; ++ ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ (*pu2Offset) += P2P_IE_OUI_HDR; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ ++ if (arAppendAttriTable[i].pfnAppendAttri) { ++ u4AttriLen = ++ arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, ++ u2BufSize); ++ ++ u4OverallAttriLen += u4AttriLen; ++ ++ if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { ++ u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ ++ prIeP2P->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); ++ ++ pucBuffer = ++ (PUINT_8) ((ULONG) prIeP2P + ++ (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ prIeP2P = (P_IE_P2P_T) ((ULONG) prIeP2P + ++ (ELEM_HDR_LEN + ++ (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN))); ++ ++ kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); ++ ++ prIeP2P->ucId = ELEM_ID_P2P; ++ ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ kalMemCopy(prIeP2P->aucP2PAttributes, aucTempBuffer, u4OverallAttriLen); ++ (*pu2Offset) += P2P_IE_OUI_HDR; ++ } ++ ++ } ++ ++ } ++ ++ prIeP2P->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateP2P_IE */ ++ ++UINT_32 ++p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ PUINT_8 pucBuffer; ++ P_P2P_ATTRI_STATUS_T prAttriStatus; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 u4AttriLen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (fgIsAssocFrame) ++ return u4AttriLen; ++ /* TODO: For assoc request P2P IE check in driver & return status in P2P IE. */ ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT(pucBuffer); ++ prAttriStatus = (P_P2P_ATTRI_STATUS_T) pucBuffer; ++ ++ ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); ++ ++ prAttriStatus->ucId = P2P_ATTRI_ID_STATUS; ++ WLAN_SET_FIELD_16(&prAttriStatus->u2Length, P2P_ATTRI_MAX_LEN_STATUS); ++ ++ prAttriStatus->ucStatusCode = P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR; ++ ++ u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} /* p2pFuncAppendAttriStatusForAssocRsp */ ++ ++UINT_32 ++p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ P_P2P_ATTRI_EXT_LISTEN_TIMING_T prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucBuffer = NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ if (fgIsAssocFrame) ++ return u4AttriLen; ++ /* TODO: For extend listen timing. */ ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); ++ ++ ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT(pucBuffer); ++ ++ prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) pucBuffer; ++ ++ prP2pExtListenTiming->ucId = P2P_ATTRI_ID_EXT_LISTEN_TIMING; ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2Length, P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailInterval, prP2pSpecificBssInfo->u2AvailabilityInterval); ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailPeriod, prP2pSpecificBssInfo->u2AvailabilityPeriod); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} /* p2pFuncAppendAttriExtListenTiming */ ++ ++P_IE_HDR_T ++p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore) ++{ ++ P_IE_HDR_T prTargetIE = (P_IE_HDR_T) NULL; ++ PUINT_8 pucIE = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0; ++ ++ if (pfgIsMore) ++ *pfgIsMore = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) ++ && (pucIEBuf != NULL)); ++ ++ pucIE = pucIEBuf; ++ ++ IE_FOR_EACH(pucIE, u2BufferLen, u2Offset) { ++ if (IE_ID(pucIE) == ucElemID) { ++ if ((prTargetIE) && (pfgIsMore)) { ++ ++ *pfgIsMore = TRUE; ++ break; ++ } ++ prTargetIE = (P_IE_HDR_T) pucIE; ++ ++ if (pfgIsMore == NULL) ++ break; ++ ++ } ++ } ++ ++ } while (FALSE); ++ ++ return prTargetIE; ++} /* p2pFuncGetSpecIE */ ++ ++P_ATTRIBUTE_HDR_T ++p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID) ++{ ++ P_IE_P2P_T prP2pIE = (P_IE_P2P_T) NULL; ++ P_ATTRIBUTE_HDR_T prTargetAttri = (P_ATTRIBUTE_HDR_T) NULL; ++ BOOLEAN fgIsMore = FALSE; ++ PUINT_8 pucIE = (PUINT_8) NULL, pucAttri = (PUINT_8) NULL; ++ UINT_16 u2OffsetAttri = 0; ++ UINT_16 u2BufferLenLeft = 0; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ DBGLOG(P2P, INFO, "Check AssocReq Oui type %u attri %u for len %u\n", ucOuiType, u2AttriID, u2BufferLen); ++ ++ ASSERT(prAdapter); ++ ASSERT(pucIEBuf); ++ ++ u2BufferLenLeft = u2BufferLen; ++ pucIE = pucIEBuf; ++ do { ++ fgIsMore = FALSE; ++ prP2pIE = (P_IE_P2P_T) p2pFuncGetSpecIE(prAdapter, ++ pucIE, u2BufferLenLeft, ELEM_ID_VENDOR, &fgIsMore); ++ if (prP2pIE == NULL) ++ continue; ++ ++ ASSERT((ULONG) prP2pIE >= (ULONG) pucIE); ++ ++ u2BufferLenLeft = u2BufferLen - (UINT_16) (((ULONG) prP2pIE) - ((ULONG) pucIEBuf)); ++ ++ DBGLOG(P2P, INFO, "Find vendor id %u len %u oui %u more %u LeftLen %u\n", ++ IE_ID(prP2pIE), IE_LEN(prP2pIE), prP2pIE->ucOuiType, fgIsMore, ++ u2BufferLenLeft); ++ ++ if ((IE_LEN(prP2pIE) > P2P_OUI_TYPE_LEN) && (prP2pIE->ucOuiType == ucOuiType)) { ++ switch (ucOuiType) { ++ case VENDOR_OUI_TYPE_WPS: ++ aucWfaOui[0] = 0x00; ++ aucWfaOui[1] = 0x50; ++ aucWfaOui[2] = 0xF2; ++ break; ++ case VENDOR_OUI_TYPE_P2P: ++ break; ++ case VENDOR_OUI_TYPE_WPA: ++ case VENDOR_OUI_TYPE_WMM: ++ case VENDOR_OUI_TYPE_WFD: ++ default: ++ break; ++ } ++ ++ if ((prP2pIE->aucOui[0] != aucWfaOui[0]) ++ || (prP2pIE->aucOui[1] != aucWfaOui[1]) ++ || (prP2pIE->aucOui[2] != aucWfaOui[2])) ++ continue; ++ ++ u2OffsetAttri = 0; ++ pucAttri = prP2pIE->aucP2PAttributes; ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ WSC_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* LOG_FUNC("WSC: attri id=%u len=%u\n", ++ * WSC_ATTRI_ID(pucAttri), ++ * WSC_ATTRI_LEN(pucAttri)); */ ++ if (WSC_ATTRI_ID(pucAttri) == u2AttriID) { ++ prTargetAttri = ++ (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ ++ } else if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ P2P_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* LOG_FUNC("P2P: attri id=%u len=%u\n", ++ * ATTRI_ID(pucAttri), ATTRI_LEN(pucAttri)); */ ++ if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { ++ prTargetAttri = (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ } ++#if CFG_SUPPORT_WFD ++ else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ WFD_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* DBGLOG(P2P, INFO, ("WFD: attri id=%u ++ * len=%u\n",WFD_ATTRI_ID(pucAttri), ++ * WFD_ATTRI_LEN(pucAttri))); */ ++ if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { ++ prTargetAttri = ++ (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ } ++#endif ++ /* Do nothing */ ++ /* Possible or else. */ ++ } /* ucOuiType */ ++ /* P2P_OUI_TYPE_LEN */ ++ pucIE = (PUINT_8) (((ULONG) prP2pIE) + IE_SIZE(prP2pIE)); ++ /* prP2pIE */ ++ } while (prP2pIE && fgIsMore && u2BufferLenLeft); ++ ++ return prTargetAttri; ++} ++ ++/* p2pFuncGetSpecAttri */ ++ ++WLAN_STATUS ++p2pFuncGenerateBeaconProbeRsp(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_MSDU_INFO_T prMsduInfo, IN BOOLEAN fgIsProbeRsp) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++/* P_APPEND_VAR_IE_ENTRY_T prAppendIeTable = (P_APPEND_VAR_IE_ENTRY_T)NULL; */ ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL) && (prMsduInfo != NULL)); ++ ++/* txBcnIETable */ ++ ++/* txProbeRspIETable */ ++ ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; ++ ++ return nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, ++ aucInfoElem)); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncGenerateBeaconProbeRsp */ ++ ++WLAN_STATUS ++p2pFuncComposeBeaconProbeRspTemplate(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBcnBuffer, ++ IN UINT_32 u4BcnBufLen, ++ IN BOOLEAN fgIsProbeRsp, ++ IN P_P2P_PROBE_RSP_UPDATE_INFO_T prP2pProbeRspInfo, IN BOOLEAN fgSynToFW) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBcnBuffer != NULL)); ++ ++ prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) pucBcnBuffer; ++ ++ if ((prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_BEACON) && (!fgIsProbeRsp)) { ++ rWlanStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ else if (prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_PROBE_RSP) { ++ rWlanStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (fgIsProbeRsp) { ++ ASSERT_BREAK(prP2pProbeRspInfo != NULL); ++ ++ if (prP2pProbeRspInfo->prProbeRspMsduTemplate) ++ cnmMgtPktFree(prAdapter, prP2pProbeRspInfo->prProbeRspMsduTemplate); ++ ++ prP2pProbeRspInfo->prProbeRspMsduTemplate = cnmMgtPktAlloc(prAdapter, u4BcnBufLen); ++ ++ prMsduInfo = prP2pProbeRspInfo->prProbeRspMsduTemplate; ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucStaRecIndex = 0xFF; ++ prMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++ } else { ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prMsduInfo = prP2pBssInfo->prBeacon; ++ ++ if (prMsduInfo == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ if (u4BcnBufLen > (OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH)) { ++ /* Unexpected error, buffer overflow. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucBuffer, pucBcnBuffer, u4BcnBufLen); ++ ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = (UINT_16) u4BcnBufLen; ++ ++ if (fgSynToFW && prP2pBssInfo) ++ rWlanStatus = p2pFuncGenerateBeaconProbeRsp(prAdapter, prP2pBssInfo, prMsduInfo, fgIsProbeRsp); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++ ++} /* p2pFuncComposeBeaconTemplate */ ++ ++#if CFG_SUPPORT_WFD ++WLAN_STATUS wfdAdjustResource(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) ++{ ++#if 1 ++ /* The API shall be called in tx_thread */ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); ++ if (fgEnable) { ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ if (QM_GUARANTEED_TC0_RESOURCE > 2) { ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE - 2; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; ++ } ++ if (QM_GUARANTEED_TC1_RESOURCE > 2) { ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE - 2; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; ++ } ++ } else { ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS wfdAdjustThread(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) ++{ ++#define WFD_TX_THREAD_PRIORITY 70 ++ DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); ++ if (prAdapter->prGlueInfo->main_thread != NULL) { ++ if (fgEnable) { ++#ifdef LINUX ++ /* TODO the change schedule API shall be provided by OS glue layer */ ++ /* Or the API shall be put in os glue layer */ ++ struct sched_param param = {.sched_priority = WFD_TX_THREAD_PRIORITY }; ++ ++ sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_RR, ¶m); ++#endif ++ } else { ++#ifdef LINUX ++ /* TODO the change schedule API shall be provided by OS glue layer */ ++ struct sched_param param = {.sched_priority = 0 }; ++ ++ sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_NORMAL, ¶m); ++#endif ++ } ++ } else { ++ ++ DBGLOG(P2P, WARN, "main_thread is null, please check if the wlanRemove is called in advance\n"); ++ } ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif /* CFG_SUPPORT_WFD */ ++ ++WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, ENUM_PARAM_MEDIA_STATE_T eConnectionState) ++{ ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered == FALSE) ++ return WLAN_STATUS_SUCCESS; ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ ++ if ((prWfdCfgSettings->ucWfdEnable) && ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ wfdAdjustResource(prAdapter, TRUE); ++ wfdAdjustThread(prAdapter, TRUE); ++ } else { ++ wfdAdjustResource(prAdapter, FALSE); ++ wfdAdjustThread(prAdapter, FALSE); ++ } ++ ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c +new file mode 100644 +index 000000000000..991861f73608 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c +@@ -0,0 +1,612 @@ ++#include "p2p_precomp.h" ++ ++#if CFG_SUPPORT_WFD ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++#if 0 ++APPEND_VAR_ATTRI_ENTRY_T txProbeRspWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_EXT_CAPABILITY), NULL, wfdFuncAppendAttriExtCapability} /* 7 */ ++ , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ ++}; ++ ++APPEND_VAR_ATTRI_ENTRY_T txBeaconWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++}; ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocReqWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++}; ++#endif ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocRspWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++ , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ ++ ++}; ++ ++#endif ++ ++UINT_32 ++p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ UINT_32 u4RetValue = 0; ++ ++ do { ++ ASSERT_BREAK((eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) && (prAdapter != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ u4RetValue = prConnReqInfo->u4BufLength; ++ ++ /* ADD HT Capability */ ++ u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP); ++ ++ /* ADD WMM Information Element */ ++ u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO); ++ ++ } while (FALSE); ++ ++ return u4RetValue; ++} /* p2pCalculate_IEForAssocReq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prConnReqInfo->aucIEBuf, prConnReqInfo->u4BufLength); ++ ++ prMsduInfo->u2FrameLength += prConnReqInfo->u4BufLength; ++ ++ rlmReqGenerateHtCapIE(prAdapter, prMsduInfo); ++ mqmGenerateWmmInfoIE(prAdapter, prMsduInfo); ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pGenerate_IEForAssocReq */ ++ ++UINT_32 ++wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_DEVICE_INFORMATION_IE_T prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdDevInfo->ucElemID = WFD_ATTRI_ID_DEV_INFO; ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevInfo, prWfdCfgSettings->u2WfdDevInfo); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2SessionMgmtCtrlPort, prWfdCfgSettings->u2WfdControlPort); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevMaxSpeed, prWfdCfgSettings->u2WfdMaximumTp); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2Length, WFD_ATTRI_MAX_LEN_DEV_INFO); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_DEV_INFO + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriDevInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_ASSOCIATED_BSSID_IE_T prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_BSS_INFO_T prAisBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ ++ /* AIS network. */ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if ((!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) || ++ (prAisBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) pucBuffer; ++ ++ prWfdAssocBssid->ucElemID = WFD_ATTRI_ID_ASSOC_BSSID; ++ ++ WLAN_SET_FIELD_BE16(&prWfdAssocBssid->u2Length, WFD_ATTRI_MAX_LEN_ASSOC_BSSID); ++ ++ COPY_MAC_ADDR(prWfdAssocBssid->aucAssocBssid, prAisBssInfo->aucBSSID); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_ASSOC_BSSID + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriAssocBssid */ ++ ++UINT_32 ++wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_COUPLE_SINK_INFORMATION_IE_T prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_SINK_INFO_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdCoupleSinkInfo->ucElemID = WFD_ATTRI_ID_COUPLED_SINK_INFO; ++ ++ WLAN_SET_FIELD_BE16(&prWfdCoupleSinkInfo->u2Length, WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO); ++ ++ COPY_MAC_ADDR(prWfdCoupleSinkInfo->aucCoupleSinkMac, prWfdCfgSettings->aucWfdCoupleSinkAddress); ++ ++ prWfdCoupleSinkInfo->ucCoupleSinkStatusBp = prWfdCfgSettings->ucWfdCoupleSinkStatus; ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriCoupledSinkInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_EXTENDED_CAPABILITY_IE_T prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_EXT_CAPABILITY_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) pucBuffer; ++ ++ prWfdExtCapability->ucElemID = WFD_ATTRI_ID_EXT_CAPABILITY; ++ ++ WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2Length, WFD_ATTRI_MAX_LEN_EXT_CAPABILITY); ++ ++ WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2WfdExtCapabilityBp, prWfdCfgSettings->u2WfdExtendCap); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_EXT_CAPABILITY + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriExtCapability */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate length of Channel List Attribute ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of Attribute added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ UINT_16 u2AttriLen = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ ++ u2AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ return (UINT_32) u2AttriLen; ++ ++} /* wfdFuncCalculateAttriLenSessionInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_SESSION_INFORMATION_IE_T prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || (prWfdCfgSettings->u2WfdSessionInformationIELen == 0)) ++ break; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdSessionInfo->ucElemID = WFD_ATTRI_ID_SESSION_INFO; ++ ++ /* TODO: Check endian issue? */ ++ kalMemCopy(prWfdSessionInfo->pucWfdDevInfoDesc, prWfdCfgSettings->aucWfdSessionInformationIE, ++ prWfdCfgSettings->u2WfdSessionInformationIELen); ++ ++ WLAN_SET_FIELD_16(&prWfdSessionInfo->u2Length, prWfdCfgSettings->u2WfdSessionInformationIELen); ++ ++ u4AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriSessionInfo */ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++VOID ++wfdFuncGenerateWfd_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ P_IE_WFD_T prIeWFD = (P_IE_WFD_T) NULL; ++ UINT_32 u4OverallAttriLen; ++ UINT_32 u4AttriLen; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; ++ UINT_32 i; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ /* Check buffer length is still enough. */ ++ ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= WFD_IE_OUI_HDR); ++ ++ prIeWFD = (P_IE_WFD_T) pucBuffer; ++ ++ prIeWFD->ucId = ELEM_ID_WFD; ++ ++ prIeWFD->aucOui[0] = aucWfaOui[0]; ++ prIeWFD->aucOui[1] = aucWfaOui[1]; ++ prIeWFD->aucOui[2] = aucWfaOui[2]; ++ prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; ++ ++ (*pu2Offset) += WFD_IE_OUI_HDR; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ ++ if (arAppendAttriTable[i].pfnAppendAttri) { ++ u4AttriLen = ++ arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, ++ u2BufSize); ++ ++ u4OverallAttriLen += u4AttriLen; ++ ++ if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { ++ u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ ++ prIeWFD->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); ++ ++ pucBuffer = ++ (PUINT_8) ((ULONG) prIeWFD + (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ prIeWFD = ++ (P_IE_WFD_T) ((ULONG) prIeWFD + ++ (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); ++ ++ prIeWFD->ucId = ELEM_ID_WFD; ++ ++ prIeWFD->aucOui[0] = aucWfaOui[0]; ++ prIeWFD->aucOui[1] = aucWfaOui[1]; ++ prIeWFD->aucOui[2] = aucWfaOui[2]; ++ prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; ++ ++ kalMemCopy(prIeWFD->aucWFDAttributes, aucTempBuffer, u4OverallAttriLen); ++ (*pu2Offset) += WFD_IE_OUI_HDR; ++ } ++ ++ } ++ ++ } ++ ++ prIeWFD->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); ++ ++ } while (FALSE); ++ ++} /* wfdFuncGenerateWfd_IE */ ++ ++#endif /* CFG_SUPPORT_WFD_COMPOSE_IE */ ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ if (!IS_STA_P2P_TYPE(prStaRec) || (prWfdCfgSettings->ucWfdEnable == 0)) ++ return 0; ++ ++ return p2pFuncCalculateP2P_IELen(prAdapter, ++ eNetTypeIndex, ++ prStaRec, ++ txAssocRspWFDAttributesTable, ++ sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ ++#else ++ return 0; ++#endif ++} /* wfdFuncCalculateWfdIELenForAssocRsp */ ++ ++VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_STA_RECORD_T prStaRec; ++ ++ do { ++ ASSERT_BREAK((prMsduInfo != NULL) && (prAdapter != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ ASSERT(FALSE); ++ } else if (IS_STA_P2P_TYPE(prStaRec)) { ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0) ++ break; ++ ++ wfdFuncGenerateWfd_IE(prAdapter, ++ FALSE, ++ &prMsduInfo->u2FrameLength, ++ prMsduInfo->prPacket, ++ 1500, ++ txAssocRspWFDAttributesTable, ++ sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ } ++ } while (FALSE); ++ ++ return; ++#else ++ ++ return; ++#endif ++} /* wfdFuncGenerateWfdIEForAssocRsp */ ++ ++VOID p2pFuncComposeNoaAttribute(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ ++ P_IE_P2P_T prIeP2P; ++ P_P2P_ATTRI_NOA_T prNoaAttr = NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; ++ P_NOA_DESCRIPTOR_T prNoaDesc = NULL; ++ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_32 u4AttributeLen; ++ UINT_32 u4NumOfNoaDesc = 0; ++ UINT_32 i = 0; ++ /*P2P IE format */ ++ prIeP2P = (P_IE_P2P_T) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ prIeP2P->ucId = ELEM_ID_P2P; ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ /*P2P Attribute--NoA */ ++ prNoaAttr = (P_P2P_ATTRI_NOA_T) prIeP2P->aucP2PAttributes; ++ ++ prNoaAttr->ucId = P2P_ATTRI_ID_NOTICE_OF_ABSENCE; ++ prNoaAttr->ucIndex = prP2pSpecificBssInfo->ucNoAIndex; ++ /*OPP*/ if (prP2pSpecificBssInfo->fgEnableOppPS) { ++ prNoaAttr->ucCTWOppPSParam = P2P_CTW_OPPPS_PARAM_OPPPS_FIELD | ++ (prP2pSpecificBssInfo->u2CTWindow & P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK); ++ } else { ++ prNoaAttr->ucCTWOppPSParam = 0; ++ } ++ /*NoA Description */ ++ DBGLOG(P2P, INFO, "Compose NoA count=%d.\n", prP2pSpecificBssInfo->ucNoATimingCount); ++ for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { ++ if (prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse) { ++ ++ prNoaDesc = (P_NOA_DESCRIPTOR_T) &prNoaAttr->aucNoADesc[u4NumOfNoaDesc]; ++ ++ prNoaDesc->ucCountType = prP2pSpecificBssInfo->arNoATiming[i].ucCount; ++ prNoaDesc->u4Duration = prP2pSpecificBssInfo->arNoATiming[i].u4Duration; ++ prNoaDesc->u4Interval = prP2pSpecificBssInfo->arNoATiming[i].u4Interval; ++ prNoaDesc->u4StartTime = prP2pSpecificBssInfo->arNoATiming[i].u4StartTime; ++ ++ u4NumOfNoaDesc++; ++ } ++ } ++ ++ /* include "index" + "OppPs Params" + "NOA descriptors" */ ++ prNoaAttr->u2Length = 2 + u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T); ++ u4NumOfNoaDesc++; ++ ++ /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ ++ u4AttributeLen = P2P_ATTRI_HDR_LEN + prNoaAttr->u2Length; ++ ++ prIeP2P->ucLength = VENDOR_OUI_TYPE_LEN + u4AttributeLen; ++ prMsduInfo->u2FrameLength += (ELEM_HDR_LEN + prIeP2P->ucLength); ++ ++} ++ ++UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; ++ UINT_8 ucIdx; ++ UINT_32 u4NumOfNoaDesc = 0; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ return 0; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ for (ucIdx = 0; ucIdx < prP2pSpecificBssInfo->ucNoATimingCount; ucIdx++) { ++ if (prP2pSpecificBssInfo->arNoATiming[ucIdx].fgIsInUse) ++ u4NumOfNoaDesc++; ++ } ++ ++ /* include "index" + "OppPs Params" + "NOA descriptors" */ ++ /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ ++ ++ return P2P_ATTRI_LEN_NOTICE_OF_ABSENCE + (u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T)); ++} ++ ++VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { /* Hotspot */ ++ return; ++ } ++ ++ /* Compose NoA attribute */ ++ p2pFuncComposeNoaAttribute(prAdapter, ++ prMsduInfo /*prMsduInfo->ucBssIndex, prIeP2P->aucP2PAttributes, &u4AttributeLen */); ++ ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c +new file mode 100644 +index 000000000000..f25df82d9ca7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c +@@ -0,0 +1,905 @@ ++/* ++** Id: @(#) p2p_rlm.c@@ ++*/ ++ ++/*! \file "p2p_rlm.c" ++ \brief ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init AP Bss ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannel; ++ ENUM_CHNL_EXT_T eSCO; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ return; ++ ++ /* Operation band, channel shall be ready before invoking this function. ++ * Bandwidth may be ready if other network is connected ++ */ ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ ++ if (RLM_AP_IS_BW_40_ALLOWED(prAdapter, prBssInfo)) { ++ /* In this case, the first BSS's SCO is 40MHz and known, so AP can ++ * apply 40MHz bandwidth, but the first BSS's SCO may be changed ++ * later if its Beacon lost timeout occurs ++ */ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) && ++ eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel && eBand == prBssInfo->eBand) { ++ prBssInfo->eBssSCO = eSCO; ++ } else if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex)) { ++ prBssInfo->eBssSCO = rlmDecideScoForAP(prAdapter, prBssInfo); ++ } ++ ++ if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ prBssInfo->fg40mBwAllowed = TRUE; ++ prBssInfo->fgAssoc40mBwAllowed = TRUE; ++ ++ prBssInfo->ucHtOpInfo1 = (UINT_8) ++ (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); ++ ++ rlmUpdateBwByChListForAP(prAdapter, prBssInfo); ++ } ++ } ++ ++ DBGLOG(RLM, INFO, "WLAN AP SCO=%d\n", prBssInfo->eBssSCO); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_IE_OBSS_SCAN_PARAM_T prObssScanIe; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && !RLM_NET_IS_BOW(prBssInfo) && ++ prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) && ++ prBssInfo->eBand == BAND_2G4 && prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ ++ prObssScanIe = (P_IE_OBSS_SCAN_PARAM_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add 20/40 BSS coexistence IE */ ++ prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS; ++ prObssScanIe->ucLength = sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN; ++ ++ prObssScanIe->u2ScanPassiveDwell = dot11OBSSScanPassiveDwell; ++ prObssScanIe->u2ScanActiveDwell = dot11OBSSScanActiveDwell; ++ prObssScanIe->u2TriggerScanInterval = dot11BSSWidthTriggerScanInterval; ++ prObssScanIe->u2ScanPassiveTotalPerChnl = dot11OBSSScanPassiveTotalPerChannel; ++ prObssScanIe->u2ScanActiveTotalPerChnl = dot11OBSSScanActiveTotalPerChannel; ++ prObssScanIe->u2WidthTransDelayFactor = dot11BSSWidthChannelTransitionDelayFactor; ++ prObssScanIe->u2ScanActivityThres = dot11OBSSScanActivityThreshold; ++ ++ ASSERT(IE_SIZE(prObssScanIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P GO. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ UINT_8 ucLevel; ++ BOOLEAN fgBwChange; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ fgBwChange = FALSE; ++ ++ if (prBssInfo->eBssSCO == CHNL_EXT_SCN) ++ return fgBwChange; ++ ++ ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO); ++ ++ if (ucLevel == CHNL_LEVEL0) { ++ /* Forced to 20MHz, so extended channel is SCN and STA width is zero */ ++ prBssInfo->fgObssActionForcedTo20M = TRUE; ++ ++ if (prBssInfo->ucHtOpInfo1 != (UINT_8) CHNL_EXT_SCN) { ++ prBssInfo->ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; ++ fgBwChange = TRUE; ++ } ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, OBSS_20_40M_TIMEOUT * MSEC_PER_SEC); ++ } ++ ++ /* Clear up all channel lists */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ prBssInfo->auc2G_PriChnlList[0] = 0; ++ prBssInfo->auc2G_SecChnlList[0] = 0; ++ prBssInfo->auc5G_20mReqChnlList[0] = 0; ++ prBssInfo->auc5G_NonHtChnlList[0] = 0; ++ prBssInfo->auc5G_PriChnlList[0] = 0; ++ prBssInfo->auc5G_SecChnlList[0] = 0; ++ ++ return fgBwChange; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_20_40_COEXIST_FRAME prRxFrame; ++ P_IE_20_40_COEXIST_T prCoexist; ++ P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport; ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength, u2Offset; ++ UINT_8 i, j; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || ++ !prStaRec || prStaRec->ucStaState != STA_STATE_3 || ++ prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || ++ HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != NETWORK_TYPE_P2P_INDEX) { ++ return; ++ } ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ASSERT(prBssInfo); ++ ++ if (!IS_BSS_ACTIVE(prBssInfo) || ++ prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || prBssInfo->eBssSCO == CHNL_EXT_SCN) { ++ return; ++ } ++ ++ prCoexist = &prRxFrame->rBssCoexist; ++ if (prCoexist->ucData & (BSS_COEXIST_40M_INTOLERANT | BSS_COEXIST_20M_REQ)) { ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_20mReqChnlList[i] == prBssInfo->ucPrimaryChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_20mReqChnlList[i] = prBssInfo->ucPrimaryChannel; ++ prBssInfo->auc2G_20mReqChnlList[0]++; ++ } ++ } ++ ++ /* Process intolerant channel report IE */ ++ pucIE = (PUINT_8) &prRxFrame->rChnlReport; ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT: ++ prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T) pucIE; ++ ++ if (prChnlReport->ucLength <= 1) ++ break; ++ ++ /* To do: process regulatory class. Now we assume 2.4G band */ ++ ++ for (j = 0; j < prChnlReport->ucLength - 1; j++) { ++ /* Update non-HT channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_NonHtChnlList[i] == prChnlReport->aucChannelList[j]) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_NonHtChnlList[i] = prChnlReport->aucChannelList[j]; ++ prBssInfo->auc2G_NonHtChnlList[0]++; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) { ++ bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ } ++ ++ /* Check if OBSS scan exemption response should be sent */ ++ if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ) ++ rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_NOTIFY_CHNL_WIDTH_FRAME prRxFrame; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_ACTION_NOTIFY_CHNL_WIDTH_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prRxFrame->ucAction != ACTION_HT_NOTIFY_CHANNEL_WIDTH || ++ !prStaRec || prStaRec->ucStaState != STA_STATE_3 || ++ prSwRfb->u2PacketLen < sizeof(ACTION_NOTIFY_CHNL_WIDTH_FRAME)) { ++ return; ++ } ++ ++ /* To do: depending regulation class 13 and 14 based on spec ++ * Note: (ucChannelWidth==1) shall restored back to original capability, ++ * not current setting to 40MHz BW here ++ */ ++ if (prRxFrame->ucChannelWidth == 0) ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ else if (prRxFrame->ucChannelWidth == 1) ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prObssStatus); ++ ASSERT(prObssStatus->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prObssStatus->ucNetTypeIndex]; ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); ++ ++ prBssInfo->fgObssErpProtectMode = (BOOLEAN) prObssStatus->ucObssErpProtectMode; ++ prBssInfo->eObssHtProtectMode = (ENUM_HT_PROTECT_MODE_T) prObssStatus->ucObssHtProtectMode; ++ prBssInfo->eObssGfOperationMode = (ENUM_GF_MODE_T) prObssStatus->ucObssGfOperationMode; ++ prBssInfo->fgObssRifsOperationMode = (BOOLEAN) prObssStatus->ucObssRifsOperationMode; ++ prBssInfo->fgObssBeaconForcedTo20M = (BOOLEAN) prObssStatus->ucObssBeaconForcedTo20M; ++ ++ /* Check if Beacon content need to be updated */ ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, TRUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon) ++{ ++ P_LINK_T prStaList; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fgErpProtectMode, fgSta40mIntolerant; ++ BOOLEAN fgUseShortPreamble, fgUseShortSlotTime; ++ ENUM_HT_PROTECT_MODE_T eHtProtectMode; ++ ENUM_GF_MODE_T eGfOperationMode; ++ UINT_8 ucHtOpInfo1; ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ P_GLUE_INFO_T prGlueInfo; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ if (!IS_BSS_ACTIVE(prBssInfo) || prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ return; ++ ++ fgErpProtectMode = FALSE; ++ eHtProtectMode = HT_PROTECT_MODE_NONE; ++ eGfOperationMode = GF_MODE_NORMAL; ++ fgSta40mIntolerant = FALSE; ++ fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; ++ fgUseShortSlotTime = TRUE; ++ ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; ++ ++ prStaList = &prBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) { ++ /* ASSERT(prStaRec); */ ++ if (!prStaRec) { ++ DBGLOG(P2P, TRACE, "prStaRec is NULL in rlmUpdateParamsForAP()\n"); ++ break; ++ } ++ if (prStaRec->fgIsInUse && prStaRec->ucStaState == STA_STATE_3 && ++ prStaRec->ucNetTypeIndex == prBssInfo->ucNetTypeIndex) { ++ if (!(prStaRec->ucPhyTypeSet & (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) { ++ /* B-only mode, so mode 1 (ERP protection) */ ++ fgErpProtectMode = TRUE; ++ } ++ ++ if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ /* BG-only or A-only */ ++ eHtProtectMode = HT_PROTECT_MODE_NON_HT; ++ } else if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { ++ /* 20MHz-only */ ++ /* ++ The HT Protection field may be set to 20 MHz protection ++ mode only if the following are true: ++ \A1X All STAs detected (by any means) in the primary channel ++ and all STAs detected (by any means) in the secondary ++ channel are HT STAs and all STAs that are members of ++ this BSS are HT STAs, and ++ \A1X This BSS is a 20/40 MHz BSS, and ++ \A1X There is at least one 20 MHz HT STA associated with this BSS. ++ */ ++ if (eHtProtectMode == HT_PROTECT_MODE_NONE && prBssInfo->fgAssoc40mBwAllowed) ++ eHtProtectMode = HT_PROTECT_MODE_20M; ++ } ++ ++ if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF)) ++ eGfOperationMode = GF_MODE_PROTECT; ++ ++ if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) ++ fgUseShortPreamble = FALSE; ++ ++ if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) ++ fgUseShortSlotTime = FALSE; ++ ++ if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) ++ fgSta40mIntolerant = TRUE; ++ } ++ } /* end of LINK_FOR_EACH_ENTRY */ ++ ++ /* Check if HT operation IE about 20/40M bandwidth shall be updated */ ++ if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ if (/*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant && ++ !prBssInfo->fgObssActionForcedTo20M && !prBssInfo->fgObssBeaconForcedTo20M) { ++ ++ ucHtOpInfo1 = (UINT_8) ++ (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); ++ } ++ } ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ prGlueInfo = prAdapter->prGlueInfo; ++ if (prGlueInfo->prP2PInfo->u4PsLevel & BITS(8, 15)) ++ fgErpProtectMode = TRUE; ++#endif ++ ++ /* Check if any new parameter may be updated */ ++ if (prBssInfo->fgErpProtectMode != fgErpProtectMode || ++ prBssInfo->eHtProtectMode != eHtProtectMode || ++ prBssInfo->eGfOperationMode != eGfOperationMode || ++ prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 || ++ prBssInfo->fgUseShortPreamble != fgUseShortPreamble || ++ prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) { ++ ++ prBssInfo->fgErpProtectMode = fgErpProtectMode; ++ prBssInfo->eHtProtectMode = eHtProtectMode; ++ prBssInfo->eGfOperationMode = eGfOperationMode; ++ prBssInfo->ucHtOpInfo1 = ucHtOpInfo1; ++ prBssInfo->fgUseShortPreamble = fgUseShortPreamble; ++ prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime; ++ ++ if (fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ else ++ prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; ++ ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ fgUpdateBeacon = TRUE; ++ } ++ ++ /* Update Beacon content if related IE content is changed */ ++ if (fgUpdateBeacon) ++ bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initial the channel list from the domain information. ++* This function is called after P2P initial and Domain information changed. ++* Make sure the device is disconnected while changing domain information. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_DOMAIN_INFO_ENTRY prDomainInfoEntry = (P_DOMAIN_INFO_ENTRY) NULL; ++ P_DOMAIN_SUBBAND_INFO prDomainSubBand = (P_DOMAIN_SUBBAND_INFO) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_32 u4Idx = 0, u4IdxII = 0; ++ UINT_8 ucBufferSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE; ++#if 0 ++ UINT_8 ucSocialChnlSupport = 0, ucAutoChnl = 0; ++#endif ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++#if 0 ++ ucAutoChnl = prP2pConnSetting->ucOperatingChnl; ++#endif ++ ++ prDomainInfoEntry = rlmDomainGetDomainInfo(prAdapter); ++ ++ ASSERT_BREAK((prDomainInfoEntry != NULL) && (prP2pConnSetting != NULL)); ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ for (u4Idx = 0; u4Idx < MAX_SUBBAND_NUM; u4Idx++) { ++ prDomainSubBand = &prDomainInfoEntry->rSubBand[u4Idx]; ++ ++ if (((prDomainSubBand->ucBand == BAND_5G) && (!prAdapter->fgEnable5GBand)) || ++ (prDomainSubBand->ucBand == BAND_NULL)) { ++ continue; ++ } ++ ++ if (ucBufferSize < (P2P_ATTRI_LEN_CHANNEL_ENTRY + prDomainSubBand->ucNumChannels)) { ++ /* Buffer is not enough to include all supported channels. */ ++ break; /* for */ ++ } ++ ++ prChannelEntryField->ucRegulatoryClass = prDomainSubBand->ucRegClass; ++ prChannelEntryField->ucNumberOfChannels = prDomainSubBand->ucNumChannels; ++ ++ for (u4IdxII = 0; u4IdxII < prDomainSubBand->ucNumChannels; u4IdxII++) { ++ prChannelEntryField->aucChannelList[u4IdxII] = prDomainSubBand->ucFirstChannelNum + ++ (u4IdxII * prDomainSubBand->ucChannelSpan); ++ ++#if 0 ++ switch (prChannelEntryField->aucChannelList[u4IdxII]) { ++ case 1: ++ ucSocialChnlSupport = 1; ++ break; ++ case 6: ++ ucSocialChnlSupport = 6; ++ break; ++ case 11: ++ ucSocialChnlSupport = 11; ++ break; ++ default: ++ break; ++ } ++ ++#endif ++ } ++ ++ if (ucBufferSize >= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels)) ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ else ++ break; ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) ++ prChannelEntryField->ucNumberOfChannels); ++ ++ } ++ ++#if 0 ++ if (prP2pConnSetting->ucListenChnl == 0) { ++ prP2pConnSetting->ucListenChnl = P2P_DEFAULT_LISTEN_CHANNEL; ++ ++ if (ucSocialChnlSupport != 0) { ++ /* 1. User Not Set LISTEN channel. ++ * 2. Social channel is not empty. ++ */ ++ prP2pConnSetting->ucListenChnl = ucSocialChnlSupport; ++ } ++ } ++#endif ++ ++ /* TODO: 20110921 frog - */ ++ /* If LISTEN channel is not set, ++ * a random supported channel would be set. ++ * If no social channel is supported, DEFAULT channel would be set. ++ */ ++ ++ prP2pConnSetting->ucRfChannelListSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE - ucBufferSize; ++ ++#if 0 ++ if (prP2pConnSetting->ucOperatingChnl == 0) { /* User not set OPERATE channel. */ ++ ++ if (scnQuerySparseChannel(prAdapter, NULL, &ucAutoChnl)) ++ break; /* while */ ++ ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while (ucBufferSize != 0) { ++ if (prChannelEntryField->ucNumberOfChannels != 0) { ++ ucAutoChnl = prChannelEntryField->aucChannelList[0]; ++ break; /* while */ ++ } ++ ++ else { ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((UINT_32) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (UINT_32)prChannelEntryField->ucNumberOfChannels); ++ ++ ucBufferSize -= ++ (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ } ++ ++ } ++ ++ } ++#endif ++ /* We assume user would not set a channel not in the channel list. ++ * If so, the operating channel still depends on target device supporting capability. ++ */ ++ ++ /* TODO: 20110921 frog - */ ++ /* If the Operating channel is not set, a channel from supported channel list is set automatically. ++ * If there is no supported channel in channel list, a DEFAULT channel is set. ++ */ ++ ++ } while (FALSE); ++ ++#if 0 ++ prP2pConnSetting->ucOperatingChnl = ucAutoChnl; ++#endif ++ ++} /* rlmFuncInitialChannelList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find a common channel list from the local channel list info & target channel list info. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, ++ IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) NULL, prChannelEntryIII = ++ (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_8 aucCommonChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE] = {0}; ++ UINT_8 ucOriChnlSize = 0, ucNewChnlSize = 0; ++ ++ do { ++ ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) aucCommonChannelList; ++ ++ while (ucChannelListSize > 0) { ++ ++ prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ucOriChnlSize = prP2pConnSetting->ucRfChannelListSize; ++ ++ while (ucOriChnlSize > 0) { ++ if (prChannelEntryI->ucRegulatoryClass == prChannelEntryII->ucRegulatoryClass) { ++ prChannelEntryIII->ucRegulatoryClass = prChannelEntryI->ucRegulatoryClass; ++ /* TODO: Currently we assume that the regulatory class the same, ++ * the channels are the same. */ ++ kalMemCopy(prChannelEntryIII->aucChannelList, prChannelEntryII->aucChannelList, ++ prChannelEntryII->ucNumberOfChannels); ++ prChannelEntryIII->ucNumberOfChannels = prChannelEntryII->ucNumberOfChannels; ++ ++ ucNewChnlSize += ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryIII->ucNumberOfChannels; ++ ++ prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryIII + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG)prChannelEntryIII->ucNumberOfChannels); ++ } ++ ++ ucOriChnlSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryI->ucNumberOfChannels); ++ ++ prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryI + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) ++ prChannelEntryI->ucNumberOfChannels); ++ ++ } ++ ++ ucChannelListSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryII->ucNumberOfChannels); ++ ++ prChannelEntryII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryII + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) prChannelEntryII->ucNumberOfChannels); ++ ++ } ++ ++ kalMemCopy(prP2pConnSetting->aucChannelEntriesField, aucCommonChannelList, ucNewChnlSize); ++ prP2pConnSetting->ucRfChannelListSize = ucNewChnlSize; ++ ++ } while (FALSE); ++ ++} /* rlmFuncCommonChannelList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum) ++{ ++ UINT_8 ucRegulatoryClass = 0, ucBufferSize = 0; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_32 u4Idx = 0; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while (ucBufferSize != 0) { ++ ++ for (u4Idx = 0; u4Idx < prChannelEntryField->ucNumberOfChannels; u4Idx++) { ++ if (prChannelEntryField->aucChannelList[u4Idx] == ucChannelNum) { ++ ucRegulatoryClass = prChannelEntryField->ucRegulatoryClass; ++ break; ++ } ++ ++ } ++ ++ if (ucRegulatoryClass != 0) ++ break; /* while */ ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG)prChannelEntryField->ucNumberOfChannels); ++ ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ ++ } ++ ++ } while (FALSE); ++ ++ return ucRegulatoryClass; ++} /* rlmFuncFindOperatingClass */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCheckChnl, ++ IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel) ++{ ++ BOOLEAN fgIsResultAvailable = FALSE; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_8 ucBufferSize = 0, ucIdx = 0, ucChannelSelected = 0; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ if (fgIsDefaultChannel) ++ ucChannelSelected = P2P_DEFAULT_LISTEN_CHANNEL; ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while ((ucBufferSize != 0) && (!fgIsResultAvailable)) { ++ ++ for (ucIdx = 0; ucIdx < prChannelEntry->ucNumberOfChannels; ucIdx++) { ++ if ((!fgIsSocialChannel) || ++ (prChannelEntry->aucChannelList[ucIdx] == 1) || ++ (prChannelEntry->aucChannelList[ucIdx] == 6) || ++ (prChannelEntry->aucChannelList[ucIdx] == 11)) { ++ ++ if (prChannelEntry->aucChannelList[ucIdx] <= 11) { ++ /* 2.4G. */ ++ ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; ++ } else if ((prChannelEntry->aucChannelList[ucIdx] < 52) && ++ (prChannelEntry->aucChannelList[ucIdx] > 14)) { ++ /* 2.4G + 5G. */ ++ ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; ++ } ++ ++ if (ucChannelSelected == ucCheckChnl) { ++ fgIsResultAvailable = TRUE; ++ break; ++ } ++ } ++ ++ } ++ ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntry->ucNumberOfChannels); ++ ++ prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntry + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) prChannelEntry->ucNumberOfChannels); ++ ++ } ++ ++ if ((!fgIsResultAvailable) && (pucSuggestChannel != NULL)) { ++ DBGLOG(P2P, TRACE, ++ "The request channel %d is not available, sugguested channel:%d\n", ucCheckChnl, ++ ucChannelSelected); ++ /* Given a suggested channel. */ ++ *pucSuggestChannel = ucChannelSelected; ++ } ++ ++ } while (FALSE); ++ ++ return fgIsResultAvailable; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ UINT_8 ucSecondChannel, i, j; ++ ENUM_CHNL_EXT_T eSCO; ++ ++ eSCO = CHNL_EXT_SCN; ++ ++ if (prBssInfo->eBand == BAND_2G4) { ++ if (prBssInfo->ucPrimaryChannel != 14) ++ eSCO = (prBssInfo->ucPrimaryChannel > 7) ? CHNL_EXT_SCB : CHNL_EXT_SCA; ++ } else { ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ if (prSubband->ucBand == prBssInfo->eBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) ++ == prBssInfo->ucPrimaryChannel) { ++ eSCO = (j & 1) ? CHNL_EXT_SCB : CHNL_EXT_SCA; ++ break; ++ } ++ } ++ ++ if (j < prSubband->ucNumChannels) ++ break; /* Found */ ++ } ++ } ++ } ++ ++ /* Check if it is boundary channel and 40MHz BW is permitted */ ++ if (eSCO != CHNL_EXT_SCN) { ++ ucSecondChannel = (eSCO == CHNL_EXT_SCA) ? ++ (prBssInfo->ucPrimaryChannel + 4) : (prBssInfo->ucPrimaryChannel - 4); ++ ++ if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel)) ++ eSCO = CHNL_EXT_SCN; ++ } ++ ++ return eSCO; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c +new file mode 100644 +index 000000000000..154f1e5db0f7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c +@@ -0,0 +1,313 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_cfg80211.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ using cfg80211 interface ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Different concurrent network has itself channel lists, and ++* concurrent networks should have been recorded in channel lists. ++* If role of active P2P is GO, assume associated AP of AIS will ++* record our Beacon for P2P GO because of same channel. ++* ++* Note: If we have scenario of different channel in the future, ++* the internal FW communication channel shall be established. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 ucChannelLevel; ++ ++ ASSERT(prBssInfo); ++ ++ if (eBand == BAND_2G4) { ++ ucChannelLevel = rlmObssChnlLevelIn2G4(prBssInfo, ucPriChannel, eExtend); ++ ++ /* (TBD) If concurrent networks permit different channel, extra ++ * channel judgement should be added. Please refer to ++ * previous version of this file. ++ */ ++ } else if (eBand == BAND_5G) { ++ ucChannelLevel = rlmObssChnlLevelIn5G(prBssInfo, ucPriChannel, eExtend); ++ ++ /* (TBD) If concurrent networks permit different channel, extra ++ * channel judgement should be added. Please refer to ++ * previous version of this file. ++ */ ++ } else { ++ ucChannelLevel = CHNL_LEVEL0; ++ } ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 i, ucChannelLevel; ++ UINT_8 ucSecChannel, ucCenterChannel; ++ UINT_8 ucAffectedChnl_L, ucAffectedChnl_H; ++ ++ ASSERT(prBssInfo); ++ ++ ucChannelLevel = CHNL_LEVEL2; ++ ++ /* Calculate center channel for 2.4G band */ ++ if (eExtend == CHNL_EXT_SCA) { ++ ucCenterChannel = ucPriChannel + 2; ++ ucSecChannel = ucPriChannel + 4; ++ } else if (eExtend == CHNL_EXT_SCB) { ++ ucCenterChannel = ucPriChannel - 2; ++ ucSecChannel = ucPriChannel - 4; ++ } else { ++ return CHNL_LEVEL0; ++ } ++ ASSERT(ucCenterChannel >= 1 && ucCenterChannel <= 14); ++ ++ /* Calculated low/upper channels in affected freq range */ ++ ucAffectedChnl_L = (ucCenterChannel <= AFFECTED_CHNL_OFFSET) ? 1 : (ucCenterChannel - AFFECTED_CHNL_OFFSET); ++ ++ ucAffectedChnl_H = (ucCenterChannel >= (14 - AFFECTED_CHNL_OFFSET)) ? ++ 14 : (ucCenterChannel + AFFECTED_CHNL_OFFSET); ++ ++ /* Check intolerant (Non-HT) channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_NonHtChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_NonHtChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_NonHtChnlList[i] != ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 20M BW request channel list */ ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_20mReqChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_20mReqChnlList[i] <= ucAffectedChnl_H)) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 2.4G primary channel list */ ++ ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_PriChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_PriChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_PriChnlList[i] != ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 2.4G secondary channel list */ ++ ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_SecChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_SecChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_SecChnlList[i] != ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++L_2G4_level_end: ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 i, ucChannelLevel; ++ UINT_8 ucSecChannel; ++ ++ ASSERT(prBssInfo); ++ ++ ucChannelLevel = CHNL_LEVEL2; ++ ++ /* Calculate center channel for 2.4G band */ ++ if (eExtend == CHNL_EXT_SCA) ++ ucSecChannel = ucPriChannel + 4; ++ else if (eExtend == CHNL_EXT_SCB) ++ ucSecChannel = ucPriChannel - 4; ++ else ++ return CHNL_LEVEL0; ++ ASSERT(ucSecChannel >= 36); ++ ++ /* Check 5G primary channel list */ ++ ASSERT(prBssInfo->auc5G_PriChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_PriChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_PriChnlList[i] == ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } else if (prBssInfo->auc5G_PriChnlList[i] == ucPriChannel) { ++ ucChannelLevel = CHNL_LEVEL1; ++ } ++ } ++ ++ /* Check non-HT channel list */ ++ ASSERT(prBssInfo->auc5G_NonHtChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_NonHtChnlList[i] == ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } else if (prBssInfo->auc5G_NonHtChnlList[i] == ucPriChannel) { ++ ucChannelLevel = CHNL_LEVEL1; ++ } ++ } ++ ++ /* Check secondary channel list */ ++ ASSERT(prBssInfo->auc5G_SecChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_SecChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_SecChnlList[i] == ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } ++ } ++ ++L_5G_level_end: ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_20_40_COEXIST_FRAME prTxFrame; ++ ++ /* To do: need an algorithm to do judgement. Now always reject request */ ++ ++ prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); ++ if (prMsduInfo == NULL) ++ return; ++ ++ DBGLOG(RLM, INFO, "Send 20/40 coexistence rsp frame!\n"); ++ ++ prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) prMsduInfo->prPacket; ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, ((P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader)->aucSrcAddr); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; ++ prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; ++ ++ /* To do: find correct algorithm */ ++ prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ prTxFrame->rBssCoexist.ucLength = 1; ++ prTxFrame->rBssCoexist.ucData = 0; ++ ++ ASSERT((WLAN_MAC_HEADER_LEN + 5) <= PUBLIC_ACTION_MAX_LEN); ++ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prSwRfb->ucStaRecIdx; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_HTC_LEN + 5; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* Send them to HW queue */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c +new file mode 100644 +index 000000000000..b5bd23965fe3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c +@@ -0,0 +1,756 @@ ++/* ++** Id: @(#) p2p_scan.c@@ ++*/ ++ ++/*! \file "p2p_scan.c" ++ \brief This file defines the p2p scan profile and the processing function of ++ scan result for SCAN Module. ++ ++ The SCAN Profile selection is part of SCAN MODULE and responsible for defining ++ SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. ++ In this file we also define the process of SCAN Result including adding, searching ++ and removing SCAN record from the list. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++P_P2P_DEVICE_DESC_T ++scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucDeviceID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* 4 <1> The outer loop to search for a candidate. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ /* Loop for each prBssDesc */ ++ prTargetP2pDesc = scanFindP2pDeviceDesc(prAdapter, prBssDesc, aucDeviceID, TRUE, FALSE); ++ ++ if (prTargetP2pDesc != NULL) ++ break; ++ } ++ ++ if ((pprBssDesc) && (prTargetP2pDesc != NULL)) { ++ /* Only valid if prTargetP2pDesc is not NULL. */ ++ *pprBssDesc = prBssDesc; ++ } ++ ++ return prTargetP2pDesc; ++} /* scanSearchTargetP2pDesc */ ++ ++VOID scanInvalidAllP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (prTargetDesc->fgDevInfoValid) ++ prTargetDesc->fgDevInfoValid = FALSE; ++ } ++ ++} /* scanRenewP2pClientDevice */ ++ ++VOID scanRemoveInvalidP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL, prNexEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ LINK_FOR_EACH_SAFE(prLinkEntry, prNexEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (!prTargetDesc->fgDevInfoValid) { ++ LINK_REMOVE_KNOWN_ENTRY(&prBssDesc->rP2pDeviceList, prLinkEntry); ++ if ((prP2pConnSettings) && (prP2pConnSettings->prTargetP2pDesc == prTargetDesc)) ++ prP2pConnSettings->prTargetP2pDesc = NULL; ++ kalMemFree(prTargetDesc, VIR_MEM_TYPE, sizeof(P2P_DEVICE_DESC_T)); ++ } ++ } ++ ++} /* scanRenewP2pClientDevice */ ++ ++P_P2P_DEVICE_DESC_T ++scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, ++ IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prBssDesc != NULL) && (aucMacAddr != NULL)); ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (fgIsDeviceAddr) { ++ if (EQUAL_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr)) ++ break; ++ } else { ++ if (EQUAL_MAC_ADDR(prTargetDesc->aucInterfaceAddr, aucMacAddr)) ++ break; ++ } ++ ++ prTargetDesc = NULL; ++ } ++ ++ if ((fgAddIfNoFound) && (prTargetDesc == NULL)) { ++ /* Target Not Found. */ ++ /* TODO: Use memory pool in the future. */ ++ prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); ++ ++ if (prTargetDesc) { ++ kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); ++ LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); ++ COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr); ++ LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); ++ prTargetDesc->fgDevInfoValid = TRUE; ++ } else { ++ ASSERT(FALSE); ++ } ++ } ++ ++ } while (FALSE); ++ ++ return prTargetDesc; ++} /* scanFindP2pDeviceDesc */ ++ ++P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssDesc); ++ ++ if (prBssDesc->prP2pDesc == NULL) { ++ ++ prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); ++ ++ if (prTargetDesc) { ++ kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); ++ LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); ++ LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); ++ prTargetDesc->fgDevInfoValid = TRUE; ++ prBssDesc->prP2pDesc = prTargetDesc; ++ /* We are not sure the SrcAddr is Device Address or Interface Address. */ ++ COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, prBssDesc->aucSrcAddr); ++ COPY_MAC_ADDR(prTargetDesc->aucInterfaceAddr, prBssDesc->aucSrcAddr); ++ } else { ++ ++ ASSERT(FALSE); ++ } ++ } else { ++ prTargetDesc = prBssDesc->prP2pDesc; ++ } ++ ++ return prTargetDesc; ++ ++} /* scanFindP2pDeviceDesc */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_P2P_DEVICE_DESC_T prP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; ++ UINT_16 u2AttributeLen = 0; ++ UINT_32 u4Idx = 0; ++ BOOLEAN fgUpdateDevInfo = FALSE; ++ ++ P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; ++ P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; ++ ++ ASSERT(prAdapter); ++ ++ prP2pDesc = scanGetP2pDeviceDesc(prAdapter, prBssDesc); ++ ++ if (!prP2pDesc) { ++ ASSERT(FALSE); ++ return fgUpdateDevInfo; ++ } ++ ++ p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, ++ &u2AttributeLen); ++ ++ while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { ++ switch (prP2pAttribute->ucId) { ++ case P2P_ATTRI_ID_P2P_CAPABILITY: /* Beacon, Probe Response */ ++ { ++ P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; ++ ++ prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; ++ ASSERT(prP2pAttriCapability->u2Length == 2); ++ ++ prP2pDesc->ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; ++ prP2pDesc->ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_ID: /* Beacon */ ++ { ++ P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; ++ ++ prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; ++ ASSERT(prP2pAttriDevID->u2Length == P2P_ATTRI_MAX_LEN_P2P_DEV_ID); ++ ++ kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_INFO: /* Probe Response */ ++ { ++ P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ UINT_16 u2NameLen = 0, u2Id = 0; ++ ++ fgUpdateDevInfo = TRUE; ++ ++ prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; ++ ++ kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevInfo->aucDevAddr, MAC_ADDR_LEN); ++ ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); ++ ++ prP2pDevType = &prP2pDesc->rPriDevType; ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ ++ ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= ++ P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ prP2pDesc->ucSecDevTypeNum = 0; ++ for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { ++ if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { ++ prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> ++ arSecondaryDevTypeListBE[u4Idx].u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> ++ arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ prP2pDesc->ucSecDevTypeNum++; ++ } ++ ++ } ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) ((PUINT_8) prP2pAttriDevInfo->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &u2NameLen); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Id, &u2Id); ++ ASSERT(u2Id == WPS_ATTRI_ID_DEVICE_NAME); ++ if (u2NameLen > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ u2NameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ prP2pDesc->u2NameLength = u2NameLen; ++ kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_GROUP_INFO: /* Probe Response */ ++ prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; ++ break; ++ case P2P_ATTRI_ID_NOTICE_OF_ABSENCE: ++ break; ++ case P2P_ATTRI_ID_EXT_LISTEN_TIMING: ++ /* TODO: Not implement yet. */ ++ /* ASSERT(FALSE); */ ++ break; ++ default: ++ break; ++ } ++ ++ u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); ++ ++ prP2pAttribute = ++ (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); ++ ++ } ++ ++ if (prP2pAttriGroupInfo != NULL) { ++ P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ scanInvalidAllP2pClientDevice(prAdapter, prBssDesc); ++ ++ /* GO/Device itself. */ ++ prP2pDesc->fgDevInfoValid = TRUE; ++ ++ prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) prP2pAttriGroupInfo->arClientDesc; ++ u2AttributeLen = prP2pAttriGroupInfo->u2Length; ++ ++ while (u2AttributeLen > 0) { ++ prP2pDesc = ++ scanFindP2pDeviceDesc(prAdapter, prBssDesc, prClientInfoDesc->aucDevAddr, TRUE, TRUE); ++ ++ if (!prP2pDesc) { ++ ASSERT(FALSE); ++ break; /* while */ ++ } ++ ++ prP2pDesc->fgDevInfoValid = TRUE; ++ ++ /* Basic size for P2P client info descriptor. */ ++ ASSERT(u2AttributeLen >= 25); ++ if (u2AttributeLen < 25) { ++ DBGLOG(P2P, WARN, "Length incorrect warning.\n"); ++ break; ++ } ++ COPY_MAC_ADDR(prP2pDesc->aucInterfaceAddr, prClientInfoDesc->aucIfAddr); ++ ++ prP2pDesc->ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; ++ ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); ++ ++ prP2pDevType = &(prP2pDesc->rPriDevType); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ ++ ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); ++ prP2pDesc->ucSecDevTypeNum = 0; ++ for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { ++ if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { ++ prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc-> ++ arSecondaryDevTypeListBE[u4Idx].u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc-> ++ arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ prP2pDesc->ucSecDevTypeNum++; ++ } ++ ++ } ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &prP2pDesc->u2NameLength); ++ if (prP2pDesc->u2NameLength > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ prP2pDesc->u2NameLength = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ ++ kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); ++ ++ u2AttributeLen -= (prClientInfoDesc->ucLength + P2P_CLIENT_INFO_DESC_HDR_LEN); ++ prClientInfoDesc = ++ (P_P2P_CLIENT_INFO_DESC_T) ((UINT_32) prClientInfoDesc + ++ (UINT_32) prClientInfoDesc->ucLength + ++ P2P_CLIENT_INFO_DESC_HDR_LEN); ++ } ++ ++ scanRemoveInvalidP2pClientDevice(prAdapter, prBssDesc); ++ } ++ ++ return fgUpdateDevInfo; ++} /* end of scanAddP2pDeviceInfo() */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) ++{ ++ EVENT_P2P_DEV_DISCOVER_RESULT_T rEventDevInfo; ++#if 1 ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ COPY_MAC_ADDR(rEventDevInfo.aucDeviceAddr, prTargetDesc->aucDeviceAddr); ++ COPY_MAC_ADDR(rEventDevInfo.aucInterfaceAddr, prTargetDesc->aucInterfaceAddr); ++ ++ rEventDevInfo.ucDeviceCapabilityBitmap = prTargetDesc->ucDeviceCapabilityBitmap; ++ rEventDevInfo.ucGroupCapabilityBitmap = prTargetDesc->ucGroupCapabilityBitmap; ++ rEventDevInfo.u2ConfigMethod = prTargetDesc->u2ConfigMethod; ++ ++ kalMemCopy(&rEventDevInfo.rPriDevType, &prTargetDesc->rPriDevType, sizeof(P2P_DEVICE_TYPE_T)); ++ ++ kalMemCopy(rEventDevInfo.arSecDevType, ++ prTargetDesc->arSecDevType, (prTargetDesc->ucSecDevTypeNum * sizeof(P2P_DEVICE_TYPE_T))); ++ ++ rEventDevInfo.ucSecDevTypeNum = prTargetDesc->ucSecDevTypeNum; ++ ++ rEventDevInfo.u2NameLength = prTargetDesc->u2NameLength; ++ kalMemCopy(rEventDevInfo.aucName, prTargetDesc->aucName, prTargetDesc->u2NameLength); ++ ++ COPY_MAC_ADDR(rEventDevInfo.aucBSSID, prBssDesc->aucBSSID); ++ ++ if (prTargetDesc == prBssDesc->prP2pDesc) ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo, prBssDesc->aucIEBuf, prBssDesc->u2IELength); ++ else ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo, NULL, 0); ++ } ++ ++ kalP2PIndicateFound(prAdapter->prGlueInfo); ++ ++#else ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; ++ UINT_16 u2AttributeLen = 0; ++ UINT_32 u4Idx = 0; ++ P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; ++ P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; ++ ++ ASSERT(prAdapter); ++ ++ prP2pSpecificBssInfo = &prAdapter->rWifiVar.rP2pSpecificBssInfo; ++ ++#if 1 ++ p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, ++ &u2AttributeLen); ++#else ++ prP2pAttribute = (P_P2P_ATTRIBUTE_T) &prP2pSpecificBssInfo->aucAttributesCache[0]; ++ u2AttributeLen = prP2pSpecificBssInfo->u2AttributeLen; ++#endif ++ rEventDevInfo.fgDevInfoValid = FALSE; ++ ++ while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { ++ switch (prP2pAttribute->ucId) { ++ case P2P_ATTRI_ID_P2P_CAPABILITY: ++ { ++ P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; ++ ++ prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; ++ ASSERT(prP2pAttriCapability->u2Length == 2); ++ rEventDevInfo.ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; ++ rEventDevInfo.ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_ID: ++ { ++ P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; ++ ++ prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; ++ ASSERT(prP2pAttriDevID->u2Length == 6); ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_INFO: ++ { ++ P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; ++ rEventDevInfo.fgDevInfoValid = TRUE; ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevInfo->aucDevAddr, ++ MAC_ADDR_LEN); ++ rEventDevInfo.u2ConfigMethod = prP2pAttriDevInfo->u2ConfigMethodsBE; ++ ++ prP2pDevType = &rEventDevInfo.rPriDevType; ++ prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; ++ ++ ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= 2); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { ++ /* TODO: Current sub device type can only support 2. */ ++ prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; ++ prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = ++ prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; ++ } ++ ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prP2pAttriDevInfo->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ ASSERT(prP2pDevName->u2Id == 0x1011); ++ ASSERT(prP2pDevName->u2Length <= 32); ++ /* TODO: Fixme if device name length is longer than 32 bytes. */ ++ kalMemCopy(rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_GROUP_INFO: ++ prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; ++ break; ++ } ++ ++ u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); ++ ++ prP2pAttribute = ++ (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); ++ ++ } ++ ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo); ++ ++ if (prP2pAttriGroupInfo != NULL) { ++ P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ prClientInfoDesc = prP2pAttriGroupInfo->arClientDesc; ++ u2AttributeLen = prP2pAttriGroupInfo->u2Length; ++ ++ while (u2AttributeLen > 0) { ++ /* Basic size for P2P client info descriptor. */ ++ ASSERT(u2AttributeLen >= 25); ++ rEventDevInfo.fgDevInfoValid = TRUE; ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prClientInfoDesc->aucIfAddr, MAC_ADDR_LEN); ++ rEventDevInfo.ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; ++ rEventDevInfo.u2ConfigMethod = prClientInfoDesc->u2ConfigMethodsBE; ++ ++ prP2pDevType = &rEventDevInfo.rPriDevType; ++ prP2pDevType->u2CategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId; ++ ++ ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= 2); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { ++ /* TODO: Current sub device type can only support 2. */ ++ prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; ++ prP2pDevType->u2CategoryID = ++ prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2CategoryId; ++ prP2pDevType->u2SubCategoryID = ++ prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId; ++ } ++ ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ ASSERT(prP2pDevName->u2Id == 0x1011); ++ ASSERT(prP2pDevName->u2Length <= 32); ++ /* TODO: Fixme if device name length is longer than 32 bytes. */ ++ kalMemCopy(&rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); ++ ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo); ++ ++ u2AttributeLen -= prP2pAttriGroupInfo->u2Length; ++ prP2pAttriGroupInfo = prP2pAttriGroupInfo + prP2pAttriGroupInfo->u2Length + 1; ++ } ++ ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* scanSendDeviceDiscoverEvent */ ++ ++VOID ++scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame) ++{ ++ BOOLEAN fgIsSkipThisBeacon; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ fgIsSkipThisBeacon = FALSE; ++ if (prBssDesc->fgIsP2PPresent) { ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && /* P2P GC */ ++ (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && /* Connected */ ++ ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { /* TX Beacon */ ++ ++ fgIsSkipThisBeacon = TRUE; ++ } ++ ++ if ((!prP2pBssInfo->ucDTIMPeriod) && /* First time. */ ++ fgIsSkipThisBeacon && (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen))) { /* SSID Match */ ++ prP2pBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ do { ++ RF_CHANNEL_INFO_T rChannelInfo; ++ ++ ASSERT_BREAK((prSwRfb != NULL) && (prBssDesc != NULL)); ++ ++ if (((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) != MAC_FRAME_PROBE_RSP)) { ++ /* Only report Probe Response frame to supplicant. */ ++ /* Probe response collect much more information. */ ++ ++ if (fgIsSkipThisBeacon || prBssDesc->eBand == BAND_2G4) ++ break; ++ } ++ ++ rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; ++ rChannelInfo.eBand = prBssDesc->eBand; ++ prBssDesc->fgIsP2PReport = TRUE; ++ ++ DBGLOG(P2P, INFO, "indicate %s [%d]\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, ++ &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ } while (FALSE); ++ } ++} ++ ++VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum) ++{ ++ ++ CMD_SCAN_CANCEL rCmdScanCancel; ++ ++ /* send cancel message to firmware domain */ ++ rCmdScanCancel.ucSeqNum = ucScnSeqNum; ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_CANCEL, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8)&rCmdScanCancel, NULL, 0); ++ ++} /* scnEventReturnChannel */ ++ ++VOID scanRemoveAllP2pBssDesc(IN P_ADAPTER_T prAdapter) ++{ ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prBSSDescNext; ++ ++ ASSERT(prAdapter); ++ ++ prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ scanRemoveP2pBssDesc(prAdapter, prBssDesc); ++ } ++} /* scanRemoveAllP2pBssDesc */ ++ ++VOID scanRemoveP2pBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ ++ ++} /* scanRemoveP2pBssDesc */ ++ ++P_BSS_DESC_T ++scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo) ++{ ++ P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL, prBssDesc = (P_BSS_DESC_T) NULL; ++ P_LINK_T prBssDescList = (P_LINK_T) NULL; ++ ++ do { ++ if ((prAdapter == NULL) || (prP2pBssInfo == NULL) || (prConnReqInfo == NULL)) ++ break; ++ ++ prBssDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); ++ ++ DBGLOG(P2P, LOUD, "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); ++ DBGLOG(P2P, LOUD, "Connecting to SSID:%s, length:%d\n", ++ prConnReqInfo->rSsidStruct.aucSsid, prConnReqInfo->rSsidStruct.ucSsidLen); ++ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBssDescList, rLinkEntry, BSS_DESC_T) { ++ DBGLOG(P2P, LOUD, "Checking BSS: %pM\n", prBssDesc->aucBSSID); ++ ++ if (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) { ++ DBGLOG(P2P, LOUD, "Ignore mismatch BSS type.\n"); ++ continue; ++ } ++ ++ if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnReqInfo->aucBssid)) { ++ DBGLOG(P2P, LOUD, "Ignore mismatch BSSID.\n"); ++ continue; ++ } ++ ++ /* SSID should be the same? SSID is vary for each connection. so... */ ++ if (UNEQUAL_SSID(prConnReqInfo->rSsidStruct.aucSsid, ++ prConnReqInfo->rSsidStruct.ucSsidLen, ++ prBssDesc->aucSSID, prBssDesc->ucSSIDLen)) { ++ ++ DBGLOG(P2P, TRACE, ++ "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); ++ DBGLOG(P2P, TRACE, ++ "Connecting to SSID:%s, length:%d\n", prConnReqInfo->rSsidStruct.aucSsid, ++ prConnReqInfo->rSsidStruct.ucSsidLen); ++ DBGLOG(P2P, TRACE, ++ "Checking SSID:%s, length:%d\n", prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ DBGLOG(P2P, TRACE, "Ignore mismatch SSID, (But BSSID match).\n"); ++ ASSERT(FALSE); ++ continue; ++ } ++ ++ if (!prBssDesc->fgIsP2PPresent) { ++ DBGLOG(P2P, ERROR, "SSID, BSSID, BSSTYPE match, but no P2P IE present.\n"); ++ continue; ++ } ++ ++ /* Final decision. */ ++ prCandidateBssDesc = prBssDesc; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return prCandidateBssDesc; ++} /* scanP2pSearchDesc */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c +new file mode 100644 +index 000000000000..befb9978f473 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c +@@ -0,0 +1,466 @@ ++#include "p2p_precomp.h" ++ ++BOOLEAN ++p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState) ++{ ++ BOOLEAN fgIsTransOut = FALSE; ++/* P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; */ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prP2pFsmInfo != NULL) && (prP2pBssInfo != NULL) && (peNextState != NULL)); ++ ++ if ((prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) ++ && IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ fgIsTransOut = TRUE; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pStateInit_IDLE GO Scan\n"); ++ *peNextState = P2P_STATE_REQING_CHANNEL; ++ ++ } else { ++#if 0 ++ else ++ if (IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ ++ ASSERT((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)); ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ /* Start a timer for return channel. */ ++ DBGLOG(P2P, TRACE, "start a GO channel timer.\n"); ++ } ++ ++ } ++#endif ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), 5000); ++ } ++ ++ } while (FALSE); ++ ++ return fgIsTransOut; ++} /* p2pStateInit_IDLE */ ++ ++VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ /* Release channel before timeout. */ ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ } ++ ++ /* Stop timer for leaving this state. */ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ } while (FALSE); ++ ++} /* p2pStateAbort_IDLE */ ++ ++VOID p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Store the original channel info. */ ++ prChnlReqInfo->ucOriChnlNum = prP2pBssInfo->ucPrimaryChannel; ++ prChnlReqInfo->eOriBand = prP2pBssInfo->eBand; ++ prChnlReqInfo->eOriChnlSco = prP2pBssInfo->eBssSCO; ++ ++ /* RX Probe Request would check primary channel. */ ++ prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; ++ prP2pBssInfo->eBand = prChnlReqInfo->eBand; ++ prP2pBssInfo->eBssSCO = prChnlReqInfo->eChnlSco; ++ ++ DBGLOG(P2P, TRACE, "start a channel on hand timer.\n"); ++ if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING) { ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), ++ prChnlReqInfo->u4MaxInterval); ++ ++ kalP2PIndicateChannelReady(prAdapter->prGlueInfo, ++ prChnlReqInfo->u8Cookie, ++ prChnlReqInfo->ucReqChnlNum, ++ prChnlReqInfo->eBand, prChnlReqInfo->eChnlSco, prChnlReqInfo->u4MaxInterval); ++ } else ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), ++ (P2P_EXT_LISTEN_TIME_MS - prChnlReqInfo->u4MaxInterval)); ++ } while (FALSE); ++ ++} /* p2pStateInit_CHNL_ON_HAND */ ++ ++VOID ++p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ /* Restore the original channel info. */ ++ prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucOriChnlNum; ++ prP2pBssInfo->eBand = prChnlReqInfo->eOriBand; ++ prP2pBssInfo->eBssSCO = prChnlReqInfo->eOriChnlSco; ++ ++ DBGLOG(P2P, INFO, "p2p state trans abort chann on hand, eListenExted: %d, eNextState: %d\n", ++ prP2pFsmInfo->eListenExted, eNextState); ++ if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING || ++ eNextState != P2P_STATE_CHNL_ON_HAND) { ++ /* Here maybe have a bug, when it's extlistening, a new remain_on_channel ++ was sent to driver? need to verify */ ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ /* Indicate channel return. */ ++ kalP2PIndicateChannelExpired(prAdapter->prGlueInfo, &prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Return Channel. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ } while (FALSE); ++} /* p2pStateAbort_CHNL_ON_HAND */ ++ ++VOID ++p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (eNextState < P2P_STATE_NUM)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (eNextState == P2P_STATE_IDLE) { ++ if (prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) { ++ /* Intend to be AP. */ ++ /* Setup for AP mode. */ ++ p2pFuncStartGO(prAdapter, ++ prP2pBssInfo, ++ prP2pSpecificBssInfo->aucGroupSsid, ++ prP2pSpecificBssInfo->u2GroupSsidLen, ++ prP2pSpecificBssInfo->ucPreferredChannel, ++ prP2pSpecificBssInfo->eRfBand, ++ prP2pSpecificBssInfo->eRfSco, prP2pFsmInfo->fgIsApMode); ++ ++ } else { ++ /* Return Channel. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ } ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_AP_CHANNEL_DETECT */ ++ ++VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->eScanType = SCAN_TYPE_PASSIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_2G4; ++ prScanReqInfo->u2PassiveDewellTime = 50; /* 50ms for passive channel load detection */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ prScanReqInfo->fgIsScanRequest = TRUE; ++ prScanReqInfo->ucNumChannelList = 0; ++ prScanReqInfo->u4BufLength = 0; ++ prScanReqInfo->rSsidStruct.ucSsidLen = 0; ++ ++ p2pFuncRequestScan(prAdapter, prScanReqInfo); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_AP_CHANNEL_DETECT */ ++ ++VOID ++p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ++ if (eNextState == P2P_STATE_REQING_CHANNEL) { ++ UINT_8 ucPreferedChnl = 0; ++ ENUM_BAND_T eBand = BAND_NULL; ++ ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Determine the channel for AP. */ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucPreferedChnl, &eSco) == FALSE) { ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ucPreferedChnl = prP2pConnSettings->ucOperatingChnl; ++ if (ucPreferedChnl == 0) { ++ ++ if (scnQuerySparseChannel(prAdapter, &eBand, &ucPreferedChnl) == FALSE) { ++ ++ /* What to do? */ ++ ASSERT(FALSE); ++ /* TODO: Pick up a valid channel from channel list. */ ++ ucPreferedChnl = 1; ++ eBand = BAND_2G4; ++ } ++ } ++ } ++ ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pStateAbort_AP_CHANNEL_DETECT GO Scan\n"); ++ prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand = eBand; ++ prChnlReqInfo->eChnlSco = prP2pSpecificBssInfo->eRfSco = eSco; ++ } else { ++ p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pStateAbort_AP_CHANNEL_DETECT */ ++ ++VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prScanReqInfo = &prP2pFsmInfo->rScanReqInfo; ++ ++ prScanReqInfo->fgIsScanRequest = TRUE; ++ ++ p2pFuncRequestScan(prAdapter, prScanReqInfo); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_SCAN */ ++ ++VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ /* 1. Scan cancel. (Make sure the scan request is invalid. */ ++ p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); ++ ++ /* Scan done indication. */ ++ kalP2PIndicateScanDone(prAdapter->prGlueInfo, prP2pFsmInfo->rScanReqInfo.fgIsAbort); ++ } while (FALSE); ++ ++} /* p2pStateAbort_SCAN */ ++ ++VOID ++p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prP2pFsmInfo != NULL) && ++ (prP2pBssInfo != NULL) && (prJoinInfo != NULL) && (prBssDesc != NULL)); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prP2pConnSettings->aucSSID, ++ prP2pConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ } ++ /* Setup a join timer. */ ++ DBGLOG(P2P, TRACE, "Start a join init timer\n"); ++ cnmTimerStartTimer(prAdapter, ++ &(prAdapter->rP2pFsmTimeoutTimer), ++ (prP2pFsmInfo->u4GrantInterval - AIS_JOIN_CH_GRANT_THRESHOLD)); ++ ++ /* 2 <1> We are goin to connect to this BSS */ ++ prBssDesc->fgIsConnecting = TRUE; ++ ++ /* 2 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, ++ (prBssDesc->fgIsP2PPresent ? (STA_TYPE_P2P_GO) ++ : (STA_TYPE_LEGACY_AP)), NETWORK_TYPE_P2P_INDEX, prBssDesc); ++ ++ if (prStaRec == NULL) { ++ DBGLOG(P2P, TRACE, "Create station record fail\n"); ++ break; ++ } ++ ++ prJoinInfo->prTargetStaRec = prStaRec; ++ prJoinInfo->fgIsJoinComplete = FALSE; ++ prJoinInfo->u4BufLength = 0; ++ ++ /* 2 <2.1> Sync. to FW domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ switch (prP2pConnSettings->eAuthMode) { ++ case AUTH_MODE_OPEN: /* Note: Omit break here. */ ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ break; ++ case AUTH_MODE_SHARED: ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; ++ break; ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(P2P, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | ++ AUTH_TYPE_SHARED_KEY); ++ break; ++ default: ++ ASSERT(!(prP2pConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); ++ DBGLOG(P2P, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", ++ prP2pConnSettings->eAuthMode); ++ /* TODO(Kevin): error handling ? */ ++ return; ++ } ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ } else { ++ ASSERT(FALSE); ++ /* TODO: Shall we considering ROAMIN case for P2P Device?. */ ++ } ++ ++ /* 2 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes. */ ++ if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { ++ ++ DBGLOG(P2P, TRACE, ++ "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prJoinInfo->rSsidStruct.aucSsid, ++ prJoinInfo->rSsidStruct.ucSsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ } ++ /* 2 <5> Backup desired channel. */ ++ ++ /* 2 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ ++ if (!prJoinReqMsg) { ++ DBGLOG(P2P, TRACE, "Allocation Join Message Fail\n"); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ /* TODO: Consider fragmentation info in station record. */ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_GC_JOIN */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of JOIN Abort. Leave JOIN State & Abort JOIN. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_MSG_JOIN_ABORT_T prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (prJoinInfo != NULL)); ++ ++ if (prJoinInfo->fgIsJoinComplete == FALSE) { ++ ++ prJoinAbortMsg = ++ (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); ++ if (!prJoinAbortMsg) { ++ DBGLOG(P2P, TRACE, "Fail to allocate join abort message buffer\n"); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prJoinAbortMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_ABORT; ++ prJoinAbortMsg->ucSeqNum = prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinAbortMsg->prStaRec = prJoinInfo->prTargetStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ /* Stop Join Timer. */ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ /* Release channel requested. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pStateAbort_GC_JOIN */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c +new file mode 100644 +index 000000000000..72fa52e761da +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c +@@ -0,0 +1,915 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/privacy.c#1 ++*/ ++ ++/*! \file "privacy.c" ++ \brief This file including the protocol layer privacy function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer security setting from rsn.c and nic_privacy.c ++ ++*/ ++ ++/* ++** Log: privacy.c ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 20 2011 terry.wu ++ * NULL ++ * Fix Hotspot deauth send failed. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 28 2011 tsaiyuan.hsu ++ * [WCXRP00000819] [MT6620 Wi-Fi][Driver] check if staRec is NULL or not in secCheckClassError ++ * check if staRec is NULL or not in secCheckClassError. ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * adding the compiling flag for migration. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 04 22 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the wpi same key id rx issue and fixed the remove wep key issue. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * remove the assert code for allow ad-hoc pkt. ++ * ++ * 04 13 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the Klocwork error and refine the class error message. ++ * ++ * 03 04 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Code refine, and remove non-used code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 26 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * change the waning message shown level, and clear the global transmit flag for CMD INFRASTRUCTURE. ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * For support the WHQL test, do the remove key code refine. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * * * * * * * * MQM: BA handling ++ * * * * * * * * * TXM: Macros updates ++ * * * * * * * * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 11 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * modify the cmd with result return ++ * ++ * Dec 11 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * fixed the value not initialize issue ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the cmd return type ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function to update the auth mode and encryption status for cmd build connection ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some code for wapi mode ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the call to check the 4th and eapol error report frame ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the function name ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code for parsing the EAPoL frame, and do some code refine ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the class error check ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the cmd_802_11_pmkid code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * doing some function rename, and adding the code for cmd CMD_ADD_REMOVE_KEY ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the clear pmkid function ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix eStaType check for AIS ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the ap selection related code ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_PRIVACY_MIGRATION ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to initialize the privacy-related ++* parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] ucNetTypeIdx Pointer to netowrk type index ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx) ++{ ++ UINT_8 i; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("secInit"); ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = 0; ++ prBssInfo->u4RsnSelectedPairwiseCipher = 0; ++ prBssInfo->u4RsnSelectedAKMSuite = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++#endif ++ ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[0].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP40; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[1].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_TKIP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[2].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_CCMP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[3].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP104; ++ ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[4].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP40; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[5].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_TKIP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[6].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[7].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP104; ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[0].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_NONE; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[1].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_802_1X; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[2].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_PSK; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[3].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_NONE; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[4].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_802_1X; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[5].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_PSK; ++ ++#if CFG_SUPPORT_802_11W ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[6].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_802_1X_SHA256; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[7].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_PSK_SHA256; ++#endif ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i].dot11RSNAConfigAuthenticationSuiteEnabled = ++ FALSE; ++ } ++ ++ secClearPmkid(prAdapter); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisSpecBssInfo->rPreauthenticationTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) rsnIndicatePmkidCand, (ULONG) NULL); ++ ++#if CFG_SUPPORT_802_11W ++ cnmTimerInitTimer(prAdapter, ++ &prAisSpecBssInfo->rSaQueryTimer, (PFN_MGMT_TIMEOUT_FUNC) rsnStartSaQueryTimer, (ULONG) NULL); ++#endif ++ ++ prAisSpecBssInfo->fgCounterMeasure = FALSE; ++ prAisSpecBssInfo->ucWEPDefaultKeyID = 0; ++ ++#if 0 ++ for (i = 0; i < WTBL_SIZE; i++) { ++ g_prWifiVar->arWtbl[i].fgUsed = FALSE; ++ g_prWifiVar->arWtbl[i].prSta = NULL; ++ g_prWifiVar->arWtbl[i].ucNetTypeIdx = NETWORK_TYPE_INDEX_NUM; ++ ++ } ++ nicPrivacyInitialize((UINT_8) NETWORK_TYPE_INDEX_NUM); ++#endif ++} /* secInit */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Rx Class Error" to SEC_FSM for ++* JOIN Module. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSwRfb Pointer to the SW RFB. ++* ++* \return FALSE Class Error ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec) ++{ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (!prStaRec) ++ return FALSE; ++ ++ eNetTypeIndex = prStaRec->ucNetTypeIndex; ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ return FALSE; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]; ++ if ((STA_STATE_3 != prStaRec->ucStaState) && prBssInfo->fgIsNetAbsent == FALSE) { ++ /*(IS_AP_STA(prStaRec) || IS_CLIENT_STA(prStaRec))) { */ ++ ++#if 0 /* by scott's suggestions, do not put work-around in JB2,we need to find the root cause */ ++ /* work-around for CR ALPS00816361 */ ++ if (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ DBGLOG(RSN, INFO, ++ "p2p> skip to send Deauth to MAC:[%pM] for Rx Class 3.\n", ++ prStaRec->aucMacAddr); ++ return TRUE; ++ } ++#endif ++ ++ if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, ++ prStaRec, ++ NULL, ++ REASON_CODE_CLASS_3_ERR, ++ (PFN_TX_DONE_HANDLER) NULL)) ++ ++ DBGLOG(RSN, INFO, "Send Deauth to [ %pM ] for Rx Class 3 Error.\n", ++ prStaRec->aucMacAddr); ++ else ++ DBGLOG(RSN, INFO, "Host sends Deauth to [ %pM ] for Rx Class 3 fail.\n", ++ prStaRec->aucMacAddr); ++ return FALSE; ++ } ++ ++ return secRxPortControlCheck(prAdapter, prSwRfb); ++} /* end of secCheckClassError() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to setting the sta port status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer to the sta ++* \param[in] fgPortBlock The port status ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPortBlock) ++{ ++ if (prSta == NULL) ++ return; ++ ++ prSta->fgPortBlock = fgPortBlock; ++ ++ DBGLOG(RSN, TRACE, ++ "The STA %pM port %s\n", prSta->aucMacAddr, fgPortBlock == TRUE ? "BLOCK" : " OPEN"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to report the sta port status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer to the sta ++* \param[out] fgPortBlock The port status ++* ++* \return TRUE sta exist, FALSE sta not exist ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secGetPortStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, OUT PBOOLEAN pfgPortStatus) ++{ ++ if (prSta == NULL) ++ return FALSE; ++ ++ *pfgPortStatus = prSta->fgPortBlock; ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle Peer device Tx Security process MSDU. ++* ++* \param[in] prMsduInfo pointer to the packet info pointer ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port blocked ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN /* ENUM_PORT_CONTROL_RESULT */ ++secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ ++ /* Todo:: */ ++ if (prMsduInfo->fgIs802_1x) ++ return TRUE; ++ ++ if (prStaRec->fgPortBlock == TRUE) { ++ DBGLOG(SEC, TRACE, "Drop Tx packet due Port Control!\n"); ++ return FALSE; ++ } ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) ++ return TRUE; ++#endif ++ if (IS_STA_IN_AIS(prStaRec)) { ++ if (!prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist && ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED)) { ++ DBGLOG(SEC, TRACE, "Drop Tx packet due the key is removed!!!\n"); ++ return FALSE; ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle The Rx Security process MSDU. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSWRfb SW rfb pinter ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port control ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb) ++{ ++ ASSERT(prSWRfb); ++ ++#if 0 ++ /* whsu:Todo: Process MGMT and DATA */ ++ if (prSWRfb->prStaRec) { ++ if (prSWRfb->prStaRec->fgPortBlock == TRUE) { ++ if (1 /* prSWRfb->fgIsDataFrame and not 1x */ && ++ (g_prWifiVar->rConnSettings.eAuthMode >= AUTH_MODE_WPA)) { ++ /* DBGLOG(SEC, WARN, ("Drop Rx data due port control !\r\n")); */ ++ return TRUE; /* Todo: whsu FALSE; */ ++ } ++ /* if (!RX_STATUS_IS_PROTECT(prSWRfb->prRxStatus)) { */ ++ /* DBGLOG(RSN, WARN, ("Drop rcv non-encrypted data frame!\n")); */ ++ /* return FALSE; */ ++ /* } */ ++ } ++ } else { ++ } ++#endif ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will enable/disable the cipher suite ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] u4CipherSuitesFlags flag for cipher suite ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags) ++{ ++ UINT_32 i; ++ P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; ++ P_IEEE_802_11_MIB_T prMib; ++ ++ ASSERT(prAdapter); ++ ++ prMib = &prAdapter->rMib; ++ ++ ASSERT(prMib); ++ ++ if (u4CipherSuitesFlags == CIPHER_FLAG_NONE) { ++ /* Disable all the pairwise cipher suites. */ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prMib->dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ ++ /* Update the group cipher suite. */ ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; ++ ++ return; ++ } ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { ++ prEntry = &prMib->dot11RSNAConfigPairwiseCiphersTable[i]; ++ ++ switch (prEntry->dot11RSNAConfigPairwiseCipher) { ++ case WPA_CIPHER_SUITE_WEP40: ++ case RSN_CIPHER_SUITE_WEP40: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_WEP40) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_TKIP: ++ case RSN_CIPHER_SUITE_TKIP: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_TKIP) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_CCMP: ++ case RSN_CIPHER_SUITE_CCMP: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_CCMP) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_WEP104: ++ case RSN_CIPHER_SUITE_WEP104: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_WEP104) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Update the group cipher suite. */ ++ if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_CCMP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_TKIP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP104; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP40; ++ else ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; ++ ++} /* secSetCipherSuite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle The 2nd Tx EAPoL Frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prMsduInfo pointer to the packet info pointer ++* \param[in] pucPayload pointer to the 1x hdr ++* \param[in] u2PayloadLen the 1x payload length ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port control ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++secProcessEAPOL(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen) ++{ ++ P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; ++ P_IEEE_802_1X_HDR pr1xHdr; ++ UINT_16 u2KeyInfo; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prStaRec); ++ ++ /* prStaRec = &(g_arStaRec[prMsduInfo->ucStaRecIndex]); */ ++ ASSERT(prStaRec); ++ ++ if (prStaRec && IS_AP_STA(prStaRec)) { ++ pr1xHdr = (P_IEEE_802_1X_HDR) pucPayload; ++ if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { ++ prEapol = (P_EAPOL_KEY) ((PUINT_32) (pucPayload + 4)); ++ WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); ++ if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { ++ if (u2KeyInfo & WPA_KEY_INFO_SECURE) { ++ /* 4th EAPoL check at secHandleTxDoneCallback() */ ++ /* DBGLOG(RSN, TRACE, ("Tx 4th EAPoL frame\r\n")); */ ++ } else if (u2PayloadLen == 123 /* Not include LLC */) { ++ DBGLOG(RSN, INFO, "Tx 2nd EAPoL frame\r\n"); ++ secFsmEvent2ndEapolTx(prAdapter, prStaRec); ++ } ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will handle the 4th EAPoL Tx done and mic Error Report frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus) ++{ ++ PUINT_8 pucPayload; ++ P_IEEE_802_1X_HDR pr1xHdr = (P_IEEE_802_1X_HDR) NULL; ++ P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; ++ UINT_16 u2KeyInfo; ++ UINT_16 u2PayloadLen; ++ ++ DEBUGFUNC("secHandleTxDoneCallback"); ++ ++ ASSERT(prMsduInfo); ++ /* Todo:: Notice if using the TX free immediate after send to firmware, the payload may not correcttly!!!! */ ++ ++ ASSERT(prStaRec); ++ ++ /* Todo:: This call back may not need because the order of set key and send 4th 1x can be make sure */ ++ /* Todo:: Notice the LLC offset */ ++#if 1 ++ pucPayload = (PUINT_8) prMsduInfo->prPacket; ++ ASSERT(pucPayload); ++ ++ u2PayloadLen = prMsduInfo->u2FrameLength; ++ ++ if (0 /* prMsduInfo->fgIs1xFrame */) { ++ ++ if (prStaRec && IS_AP_STA(prStaRec)) { ++ pr1xHdr = (P_IEEE_802_1X_HDR) (PUINT_32) (pucPayload + 8); ++ if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { ++ prEapol = (P_EAPOL_KEY) (PUINT_32) (pucPayload + 12); ++ WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); ++ if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { ++ if (prStaRec->rSecInfo.fg2nd1xSend == TRUE ++ && u2PayloadLen == ++ 107 /* include LLC *//* u2KeyInfo & WPA_KEY_INFO_SECURE */) { ++ DBGLOG(RSN, INFO, "Tx 4th EAPoL frame\r\n"); ++ secFsmEvent4ndEapolTxDone(prAdapter, prStaRec); ++ } else if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone) { ++ DBGLOG(RSN, INFO, "Tx EAPoL Error report frame\r\n"); ++ /* secFsmEventEapolTxDone(prAdapter, (UINT_32)prMsduInfo->prStaRec); */ ++ } ++ } ++ } ++ } ++ ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to initialize the pmkid parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secClearPmkid(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("secClearPmkid"); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ DBGLOG(RSN, TRACE, "secClearPmkid\n"); ++ prAisSpecBssInfo->u4PmkidCandicateCount = 0; ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCandicate, sizeof(PMKID_CANDICATE_T) * CFG_MAX_PMKID_CACHE); ++ kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether WPA, or WPA2 but not WPA-None is enabled. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ ++ ASSERT(prConnSettings); ++ ++ ASSERT(prConnSettings->eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); ++ ++ if (prConnSettings->eEncStatus == ENUM_ENCRYPTION_DISABLED) ++ return FALSE; ++ ++ ASSERT(prConnSettings->eAuthMode < AUTH_MODE_NUM); ++ if ((prConnSettings->eAuthMode >= AUTH_MODE_WPA) && (prConnSettings->eAuthMode != AUTH_MODE_WPA_NONE)) ++ return TRUE; ++ ++ return FALSE; ++} /* secRsnKeyHandshakeEnabled */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return whether the transmit key alread installed. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer the sta record ++* ++* \retval TRUE Default key or Transmit key installed ++* FALSE Default key or Transmit key not installed ++* ++* \note: ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ASSERT(prSta); ++ ++ if (prSta->fgTransmitKeyExist) ++ return TRUE; ++ else ++ return FALSE; ++} /* secTransmitKeyExist */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether 802.11 privacy is enabled. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter) ++{ ++ DEBUGFUNC("secEnabled"); ++ ++ ASSERT(prAdapter->rWifiVar.rConnSettings.eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); ++ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION_DISABLED: ++ return FALSE; ++ case ENUM_ENCRYPTION1_ENABLED: ++ case ENUM_ENCRYPTION2_ENABLED: ++ case ENUM_ENCRYPTION3_ENABLED: ++ return TRUE; ++ default: ++ DBGLOG(RSN, TRACE, "Unknown encryption setting %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ break; ++ } ++ return FALSE; ++} /* secEnabled */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the privacy bit at mac header for TxM ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prMsdu the msdu for known the sta record ++* ++* \return TRUE the privacy need to set ++* FALSE the privacy no need to set ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prAdapter); ++ ++ ASSERT(prMsdu); ++ ++ ASSERT(prStaRec); ++ /* prStaRec = &(g_arStaRec[prMsdu->ucStaRecIndex]); */ ++ ++ if (prStaRec == NULL) { ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) ++ return TRUE; ++ return FALSE; /* No privacy bit */ ++ } ++ ++ /* Todo:: */ ++ if (0 /* prMsdu->fgIs1xFrame */) { ++ if (IS_STA_IN_AIS(prStaRec) && prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { ++ DBGLOG(RSN, LOUD, "For AIS Legacy 1x, always not encryped\n"); ++ return FALSE; ++ } else if (!prStaRec->fgTransmitKeyExist) { ++ DBGLOG(RSN, LOUD, "1x Not Protected.\n"); ++ return FALSE; ++ } else if (prStaRec->rSecInfo.fgKeyStored) { ++ DBGLOG(RSN, LOUD, "1x not Protected due key stored!\n"); ++ return FALSE; ++ } ++ DBGLOG(RSN, LOUD, "1x Protected.\n"); ++ return TRUE; ++ } ++ if (!prStaRec->fgTransmitKeyExist) { ++ /* whsu , check for AIS only */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) { ++ DBGLOG(RSN, LOUD, "Protected\n"); ++ return TRUE; ++ } ++ } else { ++ DBGLOG(RSN, LOUD, "Protected.\n"); ++ return TRUE; ++ } ++ ++ /* No sec or key is removed!!! */ ++ return FALSE; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c +new file mode 100644 +index 000000000000..fd0a8772a666 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c +@@ -0,0 +1,497 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rate.c#1 ++*/ ++ ++/*! \file "rate.c" ++ \brief This file contains the transmission rate handling routines. ++ ++ This file contains the transmission rate handling routines for setting up ++ ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do ++ conversion between Rate Set and Data Rates. ++*/ ++ ++/* ++** Log: rate.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add rate.c. ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comments ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix DBGLOG ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** \main\maintrunk.MT5921\12 2008-12-19 17:19:32 GMT mtk01461 ++** Fix the problem that do not ASSERT the length of Supported Rate IE == 8 ++** \main\maintrunk.MT5921\11 2008-12-01 18:17:42 GMT mtk01088 ++** fixed the lint "possible using null pointer" warning ++** \main\maintrunk.MT5921\10 2008-08-20 00:16:36 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\9 2008-04-13 21:17:13 GMT mtk01461 ++** Revise GEN Link Speed OID ++** \main\maintrunk.MT5921\8 2008-03-28 10:40:13 GMT mtk01461 ++** Add rateGetRateSetFromDataRates() for set desired rate OID ++** \main\maintrunk.MT5921\7 2008-03-26 09:16:20 GMT mtk01461 ++** Add adopt operational rate as ACK rate if BasicRateSet was not found ++** Add comments ++** \main\maintrunk.MT5921\6 2008-02-21 15:01:39 GMT mtk01461 ++** Add initial rate according rx signal quality support ++** \main\maintrunk.MT5921\5 2008-01-07 15:06:44 GMT mtk01461 ++** Fix typo of rate adaptation of CtrlResp Frame ++** \main\maintrunk.MT5921\4 2007-10-25 18:05:12 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* The list of valid data rates. */ ++const UINT_8 aucDataRate[] = { ++ RATE_1M, /* RATE_1M_INDEX = 0 */ ++ RATE_2M, /* RATE_2M_INDEX */ ++ RATE_5_5M, /* RATE_5_5M_INDEX */ ++ RATE_11M, /* RATE_11M_INDEX */ ++ RATE_22M, /* RATE_22M_INDEX */ ++ RATE_33M, /* RATE_33M_INDEX */ ++ RATE_6M, /* RATE_6M_INDEX */ ++ RATE_9M, /* RATE_9M_INDEX */ ++ RATE_12M, /* RATE_12M_INDEX */ ++ RATE_18M, /* RATE_18M_INDEX */ ++ RATE_24M, /* RATE_24M_INDEX */ ++ RATE_36M, /* RATE_36M_INDEX */ ++ RATE_48M, /* RATE_48M_INDEX */ ++ RATE_54M, /* RATE_54M_INDEX */ ++ RATE_HT_PHY /* RATE_HT_PHY_INDEX */ ++}; ++ ++static const UINT_8 aucDefaultAckCtsRateIndex[RATE_NUM] = { ++ RATE_1M_INDEX, /* RATE_1M_INDEX = 0 */ ++ RATE_2M_INDEX, /* RATE_2M_INDEX */ ++ RATE_5_5M_INDEX, /* RATE_5_5M_INDEX */ ++ RATE_11M_INDEX, /* RATE_11M_INDEX */ ++ RATE_1M_INDEX, /* RATE_22M_INDEX - Not supported */ ++ RATE_1M_INDEX, /* RATE_33M_INDEX - Not supported */ ++ RATE_6M_INDEX, /* RATE_6M_INDEX */ ++ RATE_6M_INDEX, /* RATE_9M_INDEX */ ++ RATE_12M_INDEX, /* RATE_12M_INDEX */ ++ RATE_12M_INDEX, /* RATE_18M_INDEX */ ++ RATE_24M_INDEX, /* RATE_24M_INDEX */ ++ RATE_24M_INDEX, /* RATE_36M_INDEX */ ++ RATE_24M_INDEX, /* RATE_48M_INDEX */ ++ RATE_24M_INDEX /* RATE_54M_INDEX */ ++}; ++ ++const BOOLEAN afgIsOFDMRate[RATE_NUM] = { ++ FALSE, /* RATE_1M_INDEX = 0 */ ++ FALSE, /* RATE_2M_INDEX */ ++ FALSE, /* RATE_5_5M_INDEX */ ++ FALSE, /* RATE_11M_INDEX */ ++ FALSE, /* RATE_22M_INDEX - Not supported */ ++ FALSE, /* RATE_33M_INDEX - Not supported */ ++ TRUE, /* RATE_6M_INDEX */ ++ TRUE, /* RATE_9M_INDEX */ ++ TRUE, /* RATE_12M_INDEX */ ++ TRUE, /* RATE_18M_INDEX */ ++ TRUE, /* RATE_24M_INDEX */ ++ TRUE, /* RATE_36M_INDEX */ ++ TRUE, /* RATE_48M_INDEX */ ++ TRUE /* RATE_54M_INDEX */ ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the given Supported Rate & Extended Supported Rate IE to the ++* Operational Rate Set and Basic Rate Set, and also check if any Basic ++* Rate Code is unknown by driver. ++* ++* @param[in] prIeSupportedRate Pointer to the Supported Rate IE ++* @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE ++* @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set ++* @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set ++* @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that Basic ++* Rate Set has unknown Rate Code ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, ++ IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, ++ OUT PUINT_16 pu2OperationalRateSet, ++ OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate) ++{ ++ UINT_16 u2OperationalRateSet = 0; ++ UINT_16 u2BSSBasicRateSet = 0; ++ BOOLEAN fgIsUnknownBSSBasicRate = FALSE; ++ UINT_8 ucRate; ++ UINT_32 i, j; ++ ++ ASSERT(pu2OperationalRateSet); ++ ASSERT(pu2BSSBasicRateSet); ++ ASSERT(pfgIsUnknownBSSBasicRate); ++ ++ if (prIeSupportedRate) { ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* ASSERT(prIeSupportedRate->ucLength <= ELEM_MAX_LEN_SUP_RATES); */ ++ ASSERT(prIeSupportedRate->ucLength <= RATE_NUM); ++ ++ for (i = 0; i < prIeSupportedRate->ucLength; i++) { ++ ucRate = prIeSupportedRate->aucSupportedRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2OperationalRateSet |= BIT(j); ++ ++ if (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT) ++ u2BSSBasicRateSet |= BIT(j); ++ ++ break; ++ } ++ } ++ ++ if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && ++ (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)) { ++ fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ ++ } ++ } ++ } ++ ++ if (prIeExtSupportedRate) { ++ /* ASSERT(prIeExtSupportedRate->ucLength <= ELEM_MAX_LEN_EXTENDED_SUP_RATES); */ ++ ++ for (i = 0; i < prIeExtSupportedRate->ucLength; i++) { ++ ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2OperationalRateSet |= BIT(j); ++ ++ if (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT) ++ u2BSSBasicRateSet |= BIT(j); ++ ++ break; ++ } ++ } ++ ++ if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && ++ (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)) { ++ fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ ++ } ++ } ++ } ++ ++ *pu2OperationalRateSet = u2OperationalRateSet; ++ *pu2BSSBasicRateSet = u2BSSBasicRateSet; ++ *pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate; ++ ++ return; ++ ++} /* end of rateGetRateSetFromIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate Code ++* Format for used in (Ext)Supportec Rate IE. ++* ++* @param[in] u2OperationalRateSet Operational Rate Set ++* @param[in] u2BSSBasicRateSet Basic Rate Set ++* @param[out] pucDataRates Pointer to the Data Rate Buffer ++* @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen) ++{ ++ UINT_32 i, j; ++ ++ ASSERT(pucDataRates); ++ ASSERT(pucDataRatesLen); ++ ++ ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); ++ ++ for (i = RATE_1M_INDEX, j = 0; i < RATE_NUM; i++) { ++ if (u2OperationalRateSet & BIT(i)) { ++ ++ *(pucDataRates + j) = aucDataRate[i]; ++ ++ if (u2BSSBasicRateSet & BIT(i)) ++ *(pucDataRates + j) |= RATE_BASIC_BIT; ++ ++ j++; ++ } ++ } ++ ++ *pucDataRatesLen = (UINT_8) j; ++ ++ return; ++ ++} /* end of rateGetDataRatesFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the highest rate from given Rate Set. ++* ++* \param[in] u2RateSet Rate Set ++* \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index ++* ++* \retval TRUE Highest Rate Index was found ++* \retval FALSE Highest Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex) ++{ ++ INT_32 i; ++ ++ ASSERT(pucHighestRateIndex); ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2RateSet & BIT(i)) { ++ *pucHighestRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetHighestRateIndexFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the lowest rate from given Rate Set. ++* ++* \param[in] u2RateSet Rate Set ++* \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index ++* ++* \retval TRUE Lowest Rate Index was found ++* \retval FALSE Lowest Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex) ++{ ++ UINT_32 i; ++ ++ ASSERT(pucLowestRateIndex); ++ ++ for (i = RATE_1M_INDEX; i <= RATE_54M_INDEX; i++) { ++ if (u2RateSet & BIT(i)) { ++ *pucLowestRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetLowestRateIndexFromRateSet() */ ++ ++#if 0 /* NOTE(Kevin): For reference */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Convert the given Data Rates to the Rate Set. ++* ++* \param[in] pucDataRates Pointer to the Data Rates ++* \param[in] ucDataRatesLen Length of given Data Rates ++* \param[out] pu2RateSet Pointer to the Rate Set ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rateGetRateSetFromDataRates(IN PUINT_8 pucDataRates, IN UINT_8 ucDataRatesLen, OUT PUINT_16 pu2RateSet) ++{ ++ UINT_16 u2RateSet = 0; ++ UINT_8 ucRate; ++ UINT_32 i, j; ++ ++ ASSERT(pucDataRates); ++ ASSERT(pu2RateSet); ++ ++ if (pucDataRates) { ++ for (i = 0; i < ucDataRatesLen; i++) { ++ ucRate = pucDataRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2RateSet |= BIT(j); ++ break; ++ } ++ } ++ } ++ } ++ ++ *pu2RateSet = u2RateSet; ++ ++ return; ++ ++} /* end of rateGetRateSetFromDataRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the Operational Rate Set and Basic Rate Set to get the corresponding ++* ACK/CTS(Respnose) TX Rates. ++* ++* \param[in] u2OperationalRateSet Operational Rate Set ++* \param[in] u2BSSBasicRateSet Basic Rate Set ++* \param[out] aucAckCtsRateIndex Pointer to the Ack/Cts Data Rate Buffer ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateSetAckCtsDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, IN OUT UINT_8 aucAckCtsRateIndex[]) ++{ ++ INT_32 i, j; ++ ++ ASSERT(aucAckCtsRateIndex); ++ ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); ++ ++ /* Setup default ACK/CTS response rate */ ++ kalMemCopy(aucAckCtsRateIndex, (PVOID) aucDefaultAckCtsRateIndex, sizeof(aucDefaultAckCtsRateIndex)); ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2OperationalRateSet & BIT(i)) { ++ for (j = i; j >= RATE_1M_INDEX; j--) { ++ if (u2BSSBasicRateSet & BIT(j)) { ++ /* Reply ACK Frame at the same Modulation Scheme. */ ++ if ((afgIsOFDMRate[i] && afgIsOFDMRate[j]) || ++ (!afgIsOFDMRate[i] && !afgIsOFDMRate[j])) ++ aucAckCtsRateIndex[i] = (UINT_8) j; ++ break; ++ } ++ } ++ ++ /* NOTE(Kevin 2008/03/25): Following code is used for those AP which has ++ * NULL BasicRateSet. ++ * e.g. If input Operational Rate Set = [18M 12M 9M], Basic Rate Set = NULL. ++ * Originally we'll get Ack Rate for [18M 12M 9M] is [12M 12M "6M"]. ++ * Now we'll get Ack Rate for [18M 12M 9M] is [12M 12M 9M], ++ * The Ack Rate for Tx Rates which are not list in Operational Rate Set is still ++ * use highest mandatory rate as default. ++ */ ++ if (j < RATE_1M_INDEX) { /* The ACK/CTS rate was not found in BasicRateSet */ ++ if (!(BIT(aucAckCtsRateIndex[i]) & u2OperationalRateSet)) ++ aucAckCtsRateIndex[i] = (UINT_8) i; ++ } ++ } ++ } ++ ++ return; ++ ++} /* end of rateSetAckCtsDataRatesFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the proper initial rate from Rate Set according to given RCPI value ++* ++* \param[in] u2RateSet Rate Set ++* \param[in] rRcpi RCPI value from AP or Peer STA ++* \param[out] pucInitialRateIndex Pointer to buffer of the initial Rate Index ++* ++* \retval TRUE Initial Rate Index was found ++* \retval FALSE Initial Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetBestInitialRateIndex(IN UINT_16 u2RateSet, IN RCPI rRcpi, OUT PUINT_8 pucInitialRateIndex) ++{ ++ UINT_16 u2InitRateSet; ++ INT_32 i; ++ ++ ASSERT(pucInitialRateIndex); ++ ++ DBGLOG(MGT, TRACE, "rRcpi = %d\n", rRcpi); ++ ++ if (rRcpi >= RCPI_100) { /* Best Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_100); ++ } else if (rRcpi >= RCPI_80) { /* Better Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_80); ++ } else if (rRcpi >= RCPI_60) { /* Good Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_60); ++ } else { /* Worse Signal */ ++ /* NOTE(Kevin): If return FALSE, we should assign the BSS Basic Rate Index ++ * (prBssInfo->ucBasicRateIndex) to the initial rate. It was determined in ++ * function - bssUpdateTxRateForControlFrame(). ++ */ ++ return FALSE; ++ } ++ ++ u2RateSet &= u2InitRateSet; ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2RateSet & BIT(i)) { ++ *pucInitialRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetBestInitialRateIndex() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c +new file mode 100644 +index 000000000000..244346983f40 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c +@@ -0,0 +1,1858 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm.c#2 ++*/ ++ ++/*! \file "rlm.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Check length HT cap IE about RX associate request frame ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 03 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Fix preamble type of STA mode ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Not send ERP IE if peer STA is 802.11b-only ++ * ++ * 10 11 2011 cm.chang ++ * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter ++ * Ignore HT OP IE if its length field is not valid ++ * ++ * 09 28 2011 cm.chang ++ * NULL ++ * Add length check to reduce possibility to adopt wrong IE ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Handle client mode about preamble type and slot time ++ * ++ * 09 01 2011 cm.chang ++ * [WCXRP00000971] [MT6620 Wi-Fi][Driver][FW] Not set Beacon timeout interval when CPTT ++ * Final channel number only adopts the field from assoc response ++ * ++ * 06 10 2011 cm.chang ++ * [WCXRP00000773] [MT6620 Wi-Fi][Driver] Workaround some AP fill primary channel field with its secondary channel ++ * If DS IE exists, ignore the primary channel field in HT OP IE ++ * ++ * 05 03 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Fix compiling error ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Refine range of valid channel number ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Check if channel is valided before record ing BSS channel ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode ++ * and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 15 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when no mgmt buffer in free build ++ * ++ * 10 08 2010 cm.chang ++ * NULL ++ * When 20M only setting, ignore OBSS IE ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Temporary add rlmUpdateParamByStaForBow() and rlmBssInitForBow(). ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Add CFG_ENABLE_BT_OVER_WIFI. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Fix compile error while enabling WiFi Direct function. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix channel ID definition in RFB status to primary channel instead of center channel ++ * ++ * 06 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add TX short GI compiling option ++ * ++ * 06 02 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Roll back to remove CFG_SUPPORT_BCM_TEST. ++ * ++ * 06 01 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Update BCM Test and RW configuration. ++ * ++ * 05 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some compiling options to control 11n functions ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set RTS threshold of 2K bytes initially ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Utilize status of swRfb to know channel number and band ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 04 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process Beacon only ready for infra STA now ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 24 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * fixed some WHQL testing error. ++ * ++ * 03 15 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide draft measurement and quiet functions ++ * ++ * 03 09 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * If bss is not 11n network, zero WTBL HT parameters ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 03 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Generate HT IE only depending on own phyTypeSet ++ * ++ * 03 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not fill HT related IE if BssInfo does not include 11n phySet ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * To store field AMPDU Parameters in STA_REC ++ * ++ * 02 26 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable RDG RX, but disable RDG TX for IOT and LongNAV ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Modify the parameter of rlmRecAssocRspHtInfo function ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix prBssInfo->ucPrimaryChannel handle for assoc resp ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add some function to process HT operation ++ * ++ * Nov 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call rlmStatisticsInit() to handle MIB counters ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static BOOLEAN ++rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static BOOLEAN ++rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFsmEventInit(P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* Note: assume TIMER_T structures are reset to zero or stopped ++ * before invoking this function. ++ */ ++ ++ /* Initialize OBSS FSM */ ++ rlmObssInit(prAdapter); ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ rlmDomainCheckCountryPowerLimitTable(prAdapter); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 ucNetIdx; ++ ++ ASSERT(prAdapter); ++ ++ RLM_NET_FOR_EACH(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ /* Note: all RLM timers will also be stopped. ++ * Now only one OBSS scan timer. ++ */ ++ rlmBssReset(prAdapter, prBssInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe request, association request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe request, association request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ else if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ hs20FillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtOpIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ P_IE_ERP_T prErpIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11GN(prBssInfo) && prBssInfo->eBand == BAND_2G4 && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11GN))) { ++ prErpIe = (P_IE_ERP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add ERP IE */ ++ prErpIe->ucId = ELEM_ID_ERP_INFO; ++ prErpIe->ucLength = 1; ++ ++ prErpIe->ucERP = prBssInfo->fgObssErpProtectMode ? ERP_INFO_USE_PROTECTION : 0; ++ ++ if (prBssInfo->fgErpProtectMode) ++ prErpIe->ucERP |= (ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION); ++ ++ /* Handle barker preamble */ ++ if (!prBssInfo->fgUseShortPreamble) ++ prErpIe->ucERP |= ERP_INFO_BARKER_PREAMBLE_MODE; ++ ++ ASSERT(IE_SIZE(prErpIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prErpIe); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT32 ++rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, ++ BOOLEAN fgShortGIDisabled, ++ UINT_8 u8SupportRxSgi20, ++ UINT_8 u8SupportRxSgi40, ++ UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf) ++{ ++ P_IE_HT_CAP_T prHtCap; ++ P_SUP_MCS_SET_FIELD prSupMcsSet; ++ ++ ASSERT(pOutBuf); ++ ++ prHtCap = (P_IE_HT_CAP_T) pOutBuf; ++ ++ /* Add HT capabilities IE */ ++ prHtCap->ucId = ELEM_ID_HT_CAP; ++ prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; ++ ++ prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; ++ if (!fg40mAllowed) { ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | ++ HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); ++ } ++ if (fgShortGIDisabled) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ if (u8SupportRxSgi20 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); ++ if (u8SupportRxSgi40 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); ++ if (u8SupportRxGf == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); ++ if (u8SupportRxSTBC == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_RX_STBC_1_SS); ++ prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; ++ ++ prSupMcsSet = &prHtCap->rSupMcsSet; ++ kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); ++ ++ prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); ++ ++ if (fg40mAllowed) ++ prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ ++ prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; ++ prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; ++ ++ prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; ++ if (!fg40mAllowed || eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); ++ ++ prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; ++ ++ prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; ++ ++ ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); ++ ++ return IE_SIZE(prHtCap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_HT_CAP_T prHtCap; ++/* P_SUP_MCS_SET_FIELD prSupMcsSet; */ ++ BOOLEAN fg40mAllowed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(prMsduInfo); ++ ++ fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ ++ prHtCap = (P_IE_HT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ /* Add HT capabilities IE */ ++ prHtCap->ucId = ELEM_ID_HT_CAP; ++ prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; ++ ++ prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; ++ if (!fg40mAllowed) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | ++ HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); ++ if (prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ if (prAdapter->rWifiVar.u8SupportRxSgi20 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); ++ if (prAdapter->rWifiVar.u8SupportRxSgi40 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); ++ if (prAdapter->rWifiVar.u8SupportRxGf == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); ++ ++ prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; ++ ++ prSupMcsSet = &prHtCap->rSupMcsSet; ++ kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); ++ ++ prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); ++ ++ if (fg40mAllowed) ++ prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ ++ prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; ++ prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; ++ ++ prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; ++ if (!fg40mAllowed || prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); ++ ++ prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; ++ ++ prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; ++ ++ ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHtCap); ++#else ++ ++ prMsduInfo->u2FrameLength += rlmFillHtCapIEByParams(fg40mAllowed, ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, ++ prAdapter->rWifiVar.u8SupportRxSgi20, ++ prAdapter->rWifiVar.u8SupportRxSgi40, ++ prAdapter->rWifiVar.u8SupportRxGf, ++ prAdapter->rWifiVar.u8SupportRxSTBC, ++ prBssInfo->eCurrentOPMode, (UINT_8 *) prHtCap); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ P_HS20_EXT_CAP_T prHsExtCap; ++#else ++ P_EXT_CAP_T prExtCap; ++#endif ++ BOOLEAN fg40mAllowed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ prHsExtCap = (P_HS20_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ prHsExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prHsExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prHsExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prHsExtCap->aucCapabilities, sizeof(prHsExtCap->aucCapabilities)); ++ ++ prHsExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (!fg40mAllowed) ++ prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ ++ ASSERT(IE_SIZE(prHsExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHsExtCap); ++ ++#else ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ kalMemZero(prExtCap->aucCapabilities, sizeof(prExtCap->aucCapabilities)); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (!fg40mAllowed) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme) ++{ ++ P_IE_HT_OP_T prHtOp; ++ UINT_16 i; ++ ++ prHtOp = (P_IE_HT_OP_T) pFme; ++ ++ /* Add HT operation IE */ ++ prHtOp->ucId = ELEM_ID_HT_OP; ++ prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; ++ ++ /* RIFS and 20/40 bandwidth operations are included */ ++ prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; ++ ++ /* Decide HT protection mode field */ ++ if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; ++ else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; ++ else { ++ /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ ++ prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; ++ } ++ ++ if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { ++ /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED ++ * Note: it will also be set in ad-hoc network ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (0 /* Regulatory class 16 */ && ++ prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { ++ /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection ++ * although it is possible to have no protection by spec. ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ ++ ++ /* No basic MCSx are needed temporarily */ ++ for (i = 0; i < 16; i++) ++ prHtOp->aucBasicMcsSet[i] = 0; ++ ++ return sizeof(IE_HT_OP_T); ++} ++ ++static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++/* P_IE_HT_OP_T prHtOp; */ ++/* UINT_16 i; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(prMsduInfo); ++ ++ prMsduInfo->u2FrameLength += rlmFillHtOpIeBody(prBssInfo, ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength)); ++#if 0 ++ prHtOp = (P_IE_HT_OP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add HT operation IE */ ++ prHtOp->ucId = ELEM_ID_HT_OP; ++ prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; ++ ++ /* RIFS and 20/40 bandwidth operations are included */ ++ prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; ++ ++ /* Decide HT protection mode field */ ++ if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; ++ else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; ++ else { ++ /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ ++ prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; ++ } ++ ++ if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { ++ /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED ++ * Note: it will also be set in ad-hoc network ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (0 /* Regulatory class 16 */ && ++ prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { ++ /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection ++ * although it is possible to have no protection by spec. ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ ++ ++ /* No basic MCSx are needed temporarily */ ++ for (i = 0; i < 16; i++) ++ prHtOp->aucBasicMcsSet[i] = 0; ++ ++ ASSERT(IE_SIZE(prHtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHtOp); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked to update parameters of associated AP. ++* (Association response and Beacon) ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ UINT_16 u2Offset; ++ P_STA_RECORD_T prStaRec; ++ P_IE_HT_CAP_T prHtCap; ++ P_IE_HT_OP_T prHtOp; ++ P_IE_OBSS_SCAN_PARAM_T prObssScnParam; ++ UINT_8 ucERP, ucPrimaryChannel; ++#if CFG_SUPPORT_QUIET && 0 ++ BOOLEAN fgHasQuietIE = FALSE; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(pucIE); ++ ++ prStaRec = prBssInfo->prStaRecOfAP; ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return 0; ++ ++ prBssInfo->fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; ++ ucPrimaryChannel = 0; ++ prObssScnParam = NULL; ++ ++ /* Note: HT-related members in staRec may not be zero before, so ++ * if following IE does not exist, they are still not zero. ++ * These HT-related parameters are valid only when the corresponding ++ * BssInfo supports 802.11n, i.e., RLM_NET_IS_11N() ++ */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ break; ++ ++ case ELEM_ID_HT_OP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ prHtOp = (P_IE_HT_OP_T) pucIE; ++ /* Workaround that some APs fill primary channel field by its ++ * secondary channel, but its DS IE is correct 20110610 ++ */ ++ if (ucPrimaryChannel == 0) ++ ucPrimaryChannel = prHtOp->ucPrimaryChannel; ++ prBssInfo->ucHtOpInfo1 = prHtOp->ucInfo1; ++ prBssInfo->u2HtOpInfo2 = prHtOp->u2Info2; ++ prBssInfo->u2HtOpInfo3 = prHtOp->u2Info3; ++ ++ if (!prBssInfo->fg40mBwAllowed) ++ prBssInfo->ucHtOpInfo1 &= ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); ++ ++ if ((prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) ++ prBssInfo->eBssSCO = (ENUM_CHNL_EXT_T)(prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO); ++ ++ prBssInfo->eHtProtectMode = (ENUM_HT_PROTECT_MODE_T) ++ (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_HT_PROTECTION); ++ ++ /* To do: process regulatory class 16 */ ++ if ((prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) ++ && 0 /* && regulatory class is 16 */) ++ prBssInfo->eGfOperationMode = GF_MODE_DISALLOWED; ++ else if (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) ++ prBssInfo->eGfOperationMode = GF_MODE_PROTECT; ++ else ++ prBssInfo->eGfOperationMode = GF_MODE_NORMAL; ++ ++ prBssInfo->eRifsOperationMode = ++ (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_RIFS_MODE) ? RIFS_MODE_NORMAL : RIFS_MODE_DISALLOWED; ++ ++ break; ++ ++ case ELEM_ID_20_40_BSS_COEXISTENCE: ++ if (!RLM_NET_IS_11N(prBssInfo)) ++ break; ++ /* To do: store if scanning exemption grant to BssInfo */ ++ break; ++ ++ case ELEM_ID_OBSS_SCAN_PARAMS: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_OBSS_SCAN_PARAM_T) - 2)) ++ break; ++ /* Store OBSS parameters to BssInfo */ ++ prObssScnParam = (P_IE_OBSS_SCAN_PARAM_T) pucIE; ++ break; ++ ++ case ELEM_ID_EXTENDED_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo)) ++ break; ++ /* To do: store extended capability (PSMP, coexist) to BssInfo */ ++ break; ++ ++ case ELEM_ID_ERP_INFO: ++ if (IE_LEN(pucIE) != (sizeof(IE_ERP_T) - 2) || prBssInfo->eBand != BAND_2G4) ++ break; ++ ucERP = ERP_INFO_IE(pucIE)->ucERP; ++ prBssInfo->fgErpProtectMode = (ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE; ++ ++ if (ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ break; ++ ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) ++ ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ case ELEM_ID_CH_SW_ANNOUNCEMENT: ++ { ++ rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) pucIE); ++ } ++ break; ++ ++#if CFG_SUPPORT_QUIET && 0 ++ /* Note: RRM code should be moved to independent RRM function by ++ * component design rule. But we attach it to RLM temporarily ++ */ ++ case ELEM_ID_QUIET: ++ rrmQuietHandleQuietIE(prBssInfo, (P_IE_QUIET_T) pucIE); ++ fgHasQuietIE = TRUE; ++ break; ++#endif ++#endif ++ ++ default: ++ break; ++ } /* end of switch */ ++ } /* end of IE_FOR_EACH */ ++ ++ /* Some AP will have wrong channel number (255) when running time. ++ * Check if correct channel number information. 20110501 ++ */ ++ if ((prBssInfo->eBand == BAND_2G4 && ucPrimaryChannel > 14) || ++ (prBssInfo->eBand != BAND_2G4 && (ucPrimaryChannel >= 200 || ucPrimaryChannel <= 14))) ++ ucPrimaryChannel = 0; ++#if CFG_SUPPORT_QUIET && 0 ++ if (!fgHasQuietIE) ++ rrmQuietIeNotExist(prAdapter, prBssInfo); ++#endif ++ ++ /* Check if OBSS scan process will launch */ ++ if (!prAdapter->fgEnOnlineScan || !prObssScnParam || ++ !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH) || ++ prBssInfo->eBand != BAND_2G4 || !prBssInfo->fg40mBwAllowed) { ++ ++ /* Note: it is ok not to stop rObssScanTimer() here */ ++ prBssInfo->u2ObssScanInterval = 0; ++ } else { ++ if (prObssScnParam->u2TriggerScanInterval < OBSS_SCAN_MIN_INTERVAL) ++ prObssScnParam->u2TriggerScanInterval = OBSS_SCAN_MIN_INTERVAL; ++ if (prBssInfo->u2ObssScanInterval != prObssScnParam->u2TriggerScanInterval) { ++ ++ prBssInfo->u2ObssScanInterval = prObssScnParam->u2TriggerScanInterval; ++ ++ /* Start timer to trigger OBSS scanning */ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, ++ prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ } ++ } ++ ++ return ucPrimaryChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief AIS or P2P GC. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN ++rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ UINT_16 u2Offset, i; ++ UINT_8 ucPriChannel, ucSecChannel; ++ ENUM_CHNL_EXT_T eSCO; ++ BOOLEAN fgHtBss, fg20mReq; ++ ++ if ((prAdapter == NULL) ++ || (pucIE == NULL) ++ || (prBssInfo == NULL) ++ || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ /* Record it to channel list to change 20/40 bandwidth */ ++ ucPriChannel = 0; ++ eSCO = CHNL_EXT_SCN; ++ ++ fgHtBss = FALSE; ++ fg20mReq = FALSE; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ { ++ P_IE_HT_CAP_T prHtCap; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ if (prHtCap->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) ++ fg20mReq = TRUE; ++ fgHtBss = TRUE; ++ break; ++ } ++ case ELEM_ID_HT_OP: ++ { ++ P_IE_HT_OP_T prHtOp; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ ++ prHtOp = (P_IE_HT_OP_T) pucIE; ++ /* Workaround that some APs fill primary channel field by its ++ * secondary channel, but its DS IE is correct 20110610 ++ */ ++ if (ucPriChannel == 0) ++ ucPriChannel = prHtOp->ucPrimaryChannel; ++ ++ if ((prHtOp->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) ++ eSCO = (ENUM_CHNL_EXT_T) (prHtOp->ucInfo1 & HT_OP_INFO1_SCO); ++ break; ++ } ++ case ELEM_ID_20_40_BSS_COEXISTENCE: ++ { ++ P_IE_20_40_COEXIST_T prCoexist; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_20_40_COEXIST_T) - 2)) ++ break; ++ ++ prCoexist = (P_IE_20_40_COEXIST_T) pucIE; ++ if (prCoexist->ucData & BSS_COEXIST_40M_INTOLERANT) ++ fg20mReq = TRUE; ++ break; ++ } ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) != (sizeof(IE_DS_PARAM_SET_T) - 2)) ++ break; ++ ucPriChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ /* To do: Update channel list and 5G band. All channel lists have the same ++ * update procedure. We should give it the entry pointer of desired ++ * channel list. ++ */ ++ if (HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr) != BAND_2G4) ++ return FALSE; ++ ++ if (ucPriChannel == 0 || ucPriChannel > 14) ++ ucPriChannel = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); ++ ++ if (fgHtBss) { ++ ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_PriChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_PriChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_PriChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_PriChnlList[0]++; ++ } ++ ++ /* Update secondary channel */ ++ if (eSCO != CHNL_EXT_SCN) { ++ ucSecChannel = (eSCO == CHNL_EXT_SCA) ? (ucPriChannel + 4) : (ucPriChannel - 4); ++ ++ ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_SecChnlList[i] == ucSecChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_SecChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_SecChnlList[i] = ucSecChannel; ++ prBssInfo->auc2G_SecChnlList[0]++; ++ } ++ } ++ ++ /* Update 20M bandwidth request channels */ ++ if (fg20mReq) { ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_20mReqChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_20mReqChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_20mReqChnlList[0]++; ++ } ++ } ++ } else { ++ /* Update non-HT channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_NonHtChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_NonHtChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_NonHtChnlList[0]++; ++ } ++ ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief AIS or P2P GC. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN ++rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ if ((prAdapter == NULL) ++ || (pucIE == NULL) ++ || (prBssInfo == NULL) ++ || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++#if 0 /* SW migration 2010/8/20 */ ++ /* Note: we shall not update parameters when scanning, otherwise ++ * channel and bandwidth will not be correct or asserted failure ++ * during scanning. ++ * Note: remove channel checking. All received Beacons should be processed ++ * if measurement or other actions are executed in adjacent channels ++ * and Beacon content checking mechanism is not disabled. ++ */ ++ if (IS_SCAN_ACTIVE() ++ /* || prBssInfo->ucPrimaryChannel != CHNL_NUM_BY_SWRFB(prSwRfb) */ ++ ) { ++ return FALSE; ++ } ++#endif ++ ++ /* Handle change of slot time */ ++ prBssInfo->u2CapInfo = ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->u2CapInfo; ++ prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; ++ ++ rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgNewParameter; ++ UINT_8 ucNetIdx; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ fgNewParameter = FALSE; ++ ++ /* When concurrent networks exist, GO shall have the same handle as ++ * the other BSS, so the Beacon shall be processed for bandwidth and ++ * protection mechanism. ++ * Note1: we do not have 2 AP (GO) cases simultaneously now. ++ * Note2: If we are GO, concurrent AIS AP should detect it and reflect ++ * action in its Beacon, so AIS STA just follows Beacon from AP. ++ */ ++ RLM_NET_FOR_EACH_NO_BOW(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ if (IS_BSS_ACTIVE(prBssInfo)) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && ++ prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* P2P client or AIS infra STA */ ++ if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID, ((P_WLAN_MAC_MGMT_HEADER_T) ++ (prSwRfb->pvHeader))->aucBSSID)) { ++ ++ fgNewParameter = rlmRecBcnInfoForClient(prAdapter, ++ prBssInfo, prSwRfb, pucIE, u2IELength); ++ } else { ++ fgNewParameter = rlmRecBcnFromNeighborForClient(prAdapter, ++ prBssInfo, prSwRfb, pucIE, ++ u2IELength); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || ++ prBssInfo->eCurrentOPMode == OP_MODE_P2P_DEVICE)) { ++ /* AP scan to check if 20/40M bandwidth is permitted */ ++ rlmRecBcnFromNeighborForClient(prAdapter, prBssInfo, prSwRfb, pucIE, u2IELength); ++ } ++#endif ++ else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ /* Do nothing */ ++ /* To do: Ad-hoc */ ++ } ++ ++ /* Appy new parameters if necessary */ ++ if (fgNewParameter) { ++ DBGLOG(RLM, TRACE, "rlmProcessBcn\n"); ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ fgNewParameter = FALSE; ++ } ++ } /* end of IS_BSS_ACTIVE() */ ++ } /* end of RLM_NET_FOR_EACH_NO_BOW */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucPriChannel; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prStaRec == prBssInfo->prStaRecOfAP); ++ ++ /* To do: the invoked function is used to clear all members. It may be ++ * done by center mechanism in invoker. ++ */ ++ rlmBssReset(prAdapter, prBssInfo); ++ ++ prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; ++ ++ ucPriChannel = rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); ++ if (ucPriChannel > 0) ++ prBssInfo->ucPrimaryChannel = ucPriChannel; ++ ++ if (!RLM_NET_IS_11N(prBssInfo) || !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) ++ prBssInfo->fg40mBwAllowed = FALSE; ++ ++ /* Note: Update its capabilities to WTBL by cnmStaRecChangeState(), which ++ * shall be invoked afterwards. ++ * Update channel, bandwidth and protection mode by nicUpdateBss() ++ */ ++#if 1 ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ ++ DBGLOG(P2P, WARN, "Force P2P BW to 20\n"); ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prCmdBody && prBssInfo); ++ if (!prCmdBody || !prBssInfo) ++ return; ++ ++ prCmdBody->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; ++ prCmdBody->ucRfBand = (UINT_8) prBssInfo->eBand; ++ prCmdBody->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prCmdBody->ucRfSco = (UINT_8) prBssInfo->eBssSCO; ++ prCmdBody->ucErpProtectMode = (UINT_8) prBssInfo->fgErpProtectMode; ++ prCmdBody->ucHtProtectMode = (UINT_8) prBssInfo->eHtProtectMode; ++ prCmdBody->ucGfOperationMode = (UINT_8) prBssInfo->eGfOperationMode; ++ prCmdBody->ucTxRifsMode = (UINT_8) prBssInfo->eRifsOperationMode; ++ prCmdBody->u2HtOpInfo3 = prBssInfo->u2HtOpInfo3; ++ prCmdBody->u2HtOpInfo2 = prBssInfo->u2HtOpInfo2; ++ prCmdBody->ucHtOpInfo1 = prBssInfo->ucHtOpInfo1; ++ prCmdBody->ucUseShortPreamble = prBssInfo->fgUseShortPreamble; ++ prCmdBody->ucUseShortSlotTime = prBssInfo->fgUseShortSlotTime; ++ prCmdBody->ucCheckId = 0x72; ++ ++ if (RLM_NET_PARAM_VALID(prBssInfo)) { ++ DBGLOG(RLM, INFO, "N=%d b=%d c=%d s=%d e=%d h=%d I=0x%02x l=%d p=%d\n", ++ prCmdBody->ucNetTypeIndex, prCmdBody->ucRfBand, ++ prCmdBody->ucPrimaryChannel, prCmdBody->ucRfSco, ++ prCmdBody->ucErpProtectMode, prCmdBody->ucHtProtectMode, ++ prCmdBody->ucHtOpInfo1, prCmdBody->ucUseShortSlotTime, ++ prCmdBody->ucUseShortPreamble); ++ } else { ++ DBGLOG(RLM, TRACE, "N=%d closed\n", prCmdBody->ucNetTypeIndex); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will operation parameters based on situations of ++* concurrent networks. Channel, bandwidth, protection mode, supported ++* rate will be modified. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_CMD_SET_BSS_RLM_PARAM_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ prCmdBody = (P_CMD_SET_BSS_RLM_PARAM_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_BSS_RLM_PARAM_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(RLM, WARN, "No buf for sync RLM params (Net=%d)\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ rlmFillSyncCmdParam(prCmdBody, prBssInfo); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_BSS_RLM_PARAM, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_BSS_RLM_PARAM_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++} ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ P_IE_HT_CAP_T prHtCap; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ break; ++ ++ default: ++ break; ++ } /* end of switch */ ++ } /* end of IE_FOR_EACH */ ++} ++#endif /* CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is for both STA and AP modes ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ rlmBssInitForAP(prAdapter, prBssInfo); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is for both STA and AP modes ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ rlmBssReset(prAdapter, prBssInfo); ++ ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ ++ /* Assume FW state is updated by CMD_ID_SET_BSS_INFO, so ++ * the sync CMD is not needed here. ++ */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief All RLM timers will also be stopped. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ /* HT related parameters */ ++ prBssInfo->ucHtOpInfo1 = 0; /* RIFS disabled. 20MHz */ ++ prBssInfo->u2HtOpInfo2 = 0; ++ prBssInfo->u2HtOpInfo3 = 0; ++ ++ prBssInfo->eBssSCO = 0; ++ prBssInfo->fgErpProtectMode = 0; ++ prBssInfo->eHtProtectMode = 0; ++ prBssInfo->eGfOperationMode = 0; ++ prBssInfo->eRifsOperationMode = 0; ++ ++ /* OBSS related parameters */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ prBssInfo->auc2G_PriChnlList[0] = 0; ++ prBssInfo->auc2G_SecChnlList[0] = 0; ++ prBssInfo->auc5G_20mReqChnlList[0] = 0; ++ prBssInfo->auc5G_NonHtChnlList[0] = 0; ++ prBssInfo->auc5G_PriChnlList[0] = 0; ++ prBssInfo->auc5G_SecChnlList[0] = 0; ++ ++ /* All RLM timers will also be stopped */ ++ cnmTimerStopTimer(prAdapter, &prBssInfo->rObssScanTimer); ++ prBssInfo->u2ObssScanInterval = 0; ++ ++ prBssInfo->fgObssErpProtectMode = 0; /* GO only */ ++ prBssInfo->eObssHtProtectMode = 0; /* GO only */ ++ prBssInfo->eObssGfOperationMode = 0; /* GO only */ ++ prBssInfo->fgObssRifsOperationMode = 0; /* GO only */ ++ prBssInfo->fgObssActionForcedTo20M = 0; /* GO only */ ++ prBssInfo->fgObssBeaconForcedTo20M = 0; /* GO only */ ++} ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handle spectrum management action frame ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_CHANNEL_SWITCH_FRAME prRxFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ DBGLOG(RLM, INFO, "[5G DFS]rlmProcessSpecMgtAction \r\n"); ++ ++ prRxFrame = (P_ACTION_CHANNEL_SWITCH_FRAME) prSwRfb->pvHeader; ++ DBGLOG(RLM, INFO, "[5G DFS]prRxFrame->ucAction[%d] \r\n", prRxFrame->ucAction); ++ if (prRxFrame->ucAction == ACTION_CHNL_SWITCH) ++ rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) prRxFrame->aucInfoElem); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function process Channel Switch IE ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prChannelSwitchIE); ++ ++ DBGLOG(RLM, INFO, "[5G DFS] rlmProcessChannelSwitchIE \r\n"); ++ DBGLOG(RLM, INFO, "[5G DFS] ucChannelSwitchMode[%d], ucChannelSwitchCount[%d], ucNewChannelNum[%d] \r\n", ++ prChannelSwitchIE->ucChannelSwitchMode, ++ prChannelSwitchIE->ucChannelSwitchCount, prChannelSwitchIE->ucNewChannelNum); ++ if (prChannelSwitchIE->ucChannelSwitchMode == 1) { ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ DBGLOG(RLM, INFO, "[5G DFS] switch channel [%d]->[%d] \r\n", prAisBssInfo->ucPrimaryChannel, ++ prChannelSwitchIE->ucNewChannelNum); ++ prAisBssInfo->ucPrimaryChannel = prChannelSwitchIE->ucNewChannelNum; ++ nicUpdateBss(prAdapter, prAisBssInfo->ucNetTypeIndex); ++ } ++ ++} ++ ++#endif ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++VOID ++rlmTxRateEnhanceConfig( ++ P_ADAPTER_T prAdapter ++ ) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_RLM_INFO_T rTxRInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* suggestion from Tsaiyuan.Hsu */ ++ kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); ++ rTxRInfo.fgIsErrRatioEnhanceApplied = TRUE; ++ rTxRInfo.ucErrRatio2LimitMinRate = 3; ++ rTxRInfo.ucMinLegacyRateIdx = 2; ++ rTxRInfo.cMinRssiThreshold = -60; ++ rTxRInfo.fgIsRtsApplied = TRUE; ++ rTxRInfo.ucRecoverTime = 60; ++ ++ DBGLOG(RLM, INFO, "Enable tx rate enhance function\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxRateInfo, ++ &rTxRInfo, ++ sizeof(rTxRInfo), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(RLM, WARN, "set tx rate advance info fail 0x%lx\n", rStatus); ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TX Auto Rate module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT_32 u4Subcmd; ++ ++ ++ /* parse TAR sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(RLM, INFO, " sub command = %u\n", (UINT32)u4Subcmd); ++ ++ /* handle different sub-command */ ++ switch (u4Subcmd) { ++ case 0x00: /* configure */ ++ /* iwpriv wlan0 set_str_cmd 1_0_0_1_3_2_60_1_60 */ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_RLM_INFO_T rTxRInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); ++ rTxRInfo.u4Version = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.fgIsErrRatioEnhanceApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucErrRatio2LimitMinRate = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucMinLegacyRateIdx = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.cMinRssiThreshold = 0 - CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.fgIsRtsApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucRecoverTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(RLM, INFO, " rlmCmd = %u %u %u %u %d %u %u\n", ++ rTxRInfo.u4Version, ++ rTxRInfo.fgIsErrRatioEnhanceApplied, ++ rTxRInfo.ucErrRatio2LimitMinRate, ++ rTxRInfo.ucMinLegacyRateIdx, ++ rTxRInfo.cMinRssiThreshold, ++ rTxRInfo.fgIsRtsApplied, ++ rTxRInfo.ucRecoverTime)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxRateInfo, ++ &rTxRInfo, ++ sizeof(rTxRInfo), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ break; ++ ++ default: ++ break; ++ } ++} ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c +new file mode 100644 +index 000000000000..5e127488ea49 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c +@@ -0,0 +1,1791 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_domain.c#1 ++*/ ++ ++/*! \file "rlm_domain.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_domain.c ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 09 23 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Let channel number to zero if band is illegal ++ * ++ * 09 22 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Exclude channel list with illegal band ++ * ++ * 09 15 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use defined country group to have a change to add new group ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Provide legal channel function based on domain ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 02 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Export rlmDomainGetDomainInfo for p2p driver. ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 03 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Filter out not supported RF freq when reporting available chnl list ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide query function about full channel list. ++ * ++ * Dec 1 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++#include "rlm_txpwr_init.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* The following country or domain shall be set from host driver. ++ * And host driver should pass specified DOMAIN_INFO_ENTRY to MT6620 as ++ * the channel list of being a STA to do scanning/searching AP or being an ++ * AP to choose an adequate channel if auto-channel is set. ++ */ ++ ++/* Define mapping tables between country code and its channel set ++ */ ++static const UINT_16 g_u2CountryGroup0[] = { ++ COUNTRY_CODE_AO, COUNTRY_CODE_BZ, COUNTRY_CODE_BJ, COUNTRY_CODE_BT, ++ COUNTRY_CODE_BO, COUNTRY_CODE_BI, COUNTRY_CODE_CM, COUNTRY_CODE_CF, ++ COUNTRY_CODE_TD, COUNTRY_CODE_KM, COUNTRY_CODE_CD, COUNTRY_CODE_CG, ++ COUNTRY_CODE_CI, COUNTRY_CODE_DJ, COUNTRY_CODE_GQ, COUNTRY_CODE_ER, ++ COUNTRY_CODE_FJ, COUNTRY_CODE_GA, COUNTRY_CODE_GM, COUNTRY_CODE_GN, ++ COUNTRY_CODE_GW, COUNTRY_CODE_RKS, COUNTRY_CODE_KG, COUNTRY_CODE_LY, ++ COUNTRY_CODE_MG, COUNTRY_CODE_ML, COUNTRY_CODE_NR, COUNTRY_CODE_NC, ++ COUNTRY_CODE_ST, COUNTRY_CODE_SC, COUNTRY_CODE_SL, COUNTRY_CODE_SB, ++ COUNTRY_CODE_SO, COUNTRY_CODE_SR, COUNTRY_CODE_SZ, COUNTRY_CODE_TJ, ++ COUNTRY_CODE_TG, COUNTRY_CODE_TO, COUNTRY_CODE_TM, COUNTRY_CODE_TV, ++ COUNTRY_CODE_VU, COUNTRY_CODE_YE ++}; ++ ++static const UINT_16 g_u2CountryGroup1[] = { ++ COUNTRY_CODE_AS, COUNTRY_CODE_AI, COUNTRY_CODE_BM, COUNTRY_CODE_CA, ++ COUNTRY_CODE_KY, COUNTRY_CODE_GU, COUNTRY_CODE_FM, COUNTRY_CODE_PR, ++ COUNTRY_CODE_US, COUNTRY_CODE_VI ++}; ++ ++static const UINT_16 g_u2CountryGroup2[] = { ++ COUNTRY_CODE_AR, COUNTRY_CODE_AU, COUNTRY_CODE_AZ, COUNTRY_CODE_BW, ++ COUNTRY_CODE_KH, COUNTRY_CODE_CX, COUNTRY_CODE_CO, COUNTRY_CODE_CR, ++#if (CFG_CN_SUPPORT_CLASS121 == 1) ++ COUNTRY_CODE_CN, ++#endif ++ COUNTRY_CODE_EC, COUNTRY_CODE_GD, COUNTRY_CODE_GT, COUNTRY_CODE_HK, ++ COUNTRY_CODE_KI, COUNTRY_CODE_LB, COUNTRY_CODE_LR, COUNTRY_CODE_MN, ++ COUNTRY_CODE_AN, COUNTRY_CODE_NZ, COUNTRY_CODE_NI, COUNTRY_CODE_PW, ++ COUNTRY_CODE_PY, COUNTRY_CODE_PE, COUNTRY_CODE_PH, COUNTRY_CODE_WS, ++ COUNTRY_CODE_SG, COUNTRY_CODE_LK, COUNTRY_CODE_TH, COUNTRY_CODE_TT, ++ COUNTRY_CODE_UY, COUNTRY_CODE_VN ++}; ++ ++static const UINT_16 g_u2CountryGroup3[] = { ++ COUNTRY_CODE_AW, COUNTRY_CODE_LA, COUNTRY_CODE_SA, COUNTRY_CODE_AE, ++ COUNTRY_CODE_UG ++}; ++ ++static const UINT_16 g_u2CountryGroup4[] = { COUNTRY_CODE_MM }; ++ ++static const UINT_16 g_u2CountryGroup5[] = { ++ COUNTRY_CODE_AL, COUNTRY_CODE_DZ, COUNTRY_CODE_AD, COUNTRY_CODE_AT, ++ COUNTRY_CODE_BY, COUNTRY_CODE_BE, COUNTRY_CODE_BA, COUNTRY_CODE_VG, ++ COUNTRY_CODE_BG, COUNTRY_CODE_CV, COUNTRY_CODE_HR, COUNTRY_CODE_CY, ++ COUNTRY_CODE_CZ, COUNTRY_CODE_DK, COUNTRY_CODE_EE, COUNTRY_CODE_ET, ++ COUNTRY_CODE_FI, COUNTRY_CODE_FR, COUNTRY_CODE_GF, COUNTRY_CODE_PF, ++ COUNTRY_CODE_TF, COUNTRY_CODE_GE, COUNTRY_CODE_DE, COUNTRY_CODE_GH, ++ COUNTRY_CODE_GR, COUNTRY_CODE_GP, COUNTRY_CODE_HU, COUNTRY_CODE_IS, ++ COUNTRY_CODE_IQ, COUNTRY_CODE_IE, COUNTRY_CODE_IT, COUNTRY_CODE_KE, ++ COUNTRY_CODE_LV, COUNTRY_CODE_LS, COUNTRY_CODE_LI, COUNTRY_CODE_LT, ++ COUNTRY_CODE_LU, COUNTRY_CODE_MK, COUNTRY_CODE_MT, COUNTRY_CODE_MQ, ++ COUNTRY_CODE_MR, COUNTRY_CODE_MU, COUNTRY_CODE_YT, COUNTRY_CODE_MD, ++ COUNTRY_CODE_MC, COUNTRY_CODE_ME, COUNTRY_CODE_MS, COUNTRY_CODE_NL, ++ COUNTRY_CODE_NO, COUNTRY_CODE_OM, COUNTRY_CODE_PL, COUNTRY_CODE_PT, ++ COUNTRY_CODE_RE, COUNTRY_CODE_RO, COUNTRY_CODE_MF, COUNTRY_CODE_SM, ++ COUNTRY_CODE_SN, COUNTRY_CODE_RS, COUNTRY_CODE_SK, COUNTRY_CODE_SI, ++ COUNTRY_CODE_ZA, COUNTRY_CODE_ES, COUNTRY_CODE_SE, COUNTRY_CODE_CH, ++ COUNTRY_CODE_TR, COUNTRY_CODE_TC, COUNTRY_CODE_GB, COUNTRY_CODE_VA, ++ COUNTRY_CODE_EU ++}; ++ ++static const UINT_16 g_u2CountryGroup6[] = { COUNTRY_CODE_JP }; ++ ++static const UINT_16 g_u2CountryGroup7[] = { ++ COUNTRY_CODE_AM, COUNTRY_CODE_IL, COUNTRY_CODE_KW, COUNTRY_CODE_MA, ++ COUNTRY_CODE_NE, COUNTRY_CODE_TN, COUNTRY_CODE_MA ++}; ++ ++static const UINT_16 g_u2CountryGroup8[] = { COUNTRY_CODE_NP }; ++ ++static const UINT_16 g_u2CountryGroup9[] = { COUNTRY_CODE_AF }; ++ ++static const UINT_16 g_u2CountryGroup10[] = { ++ COUNTRY_CODE_AG, COUNTRY_CODE_BS, COUNTRY_CODE_BH, COUNTRY_CODE_BB, ++ COUNTRY_CODE_BN, COUNTRY_CODE_CL, COUNTRY_CODE_EG, ++#if (CFG_CN_SUPPORT_CLASS121 == 0) ++ COUNTRY_CODE_CN, ++#endif ++ COUNTRY_CODE_SV, COUNTRY_CODE_IN, COUNTRY_CODE_MY, COUNTRY_CODE_MV, ++ COUNTRY_CODE_PA, COUNTRY_CODE_VE, COUNTRY_CODE_ZM ++}; ++ ++static const UINT_16 g_u2CountryGroup11[] = { COUNTRY_CODE_JO, COUNTRY_CODE_PG }; ++ ++static const UINT_16 g_u2CountryGroup12[] = { ++ COUNTRY_CODE_BF, COUNTRY_CODE_GY, COUNTRY_CODE_HT, COUNTRY_CODE_HN, ++ COUNTRY_CODE_JM, COUNTRY_CODE_MO, COUNTRY_CODE_MW, COUNTRY_CODE_PK, ++ COUNTRY_CODE_QA, COUNTRY_CODE_RW, COUNTRY_CODE_KN, COUNTRY_CODE_TZ ++}; ++ ++static const UINT_16 g_u2CountryGroup13[] = { COUNTRY_CODE_ID }; ++ ++static const UINT_16 g_u2CountryGroup14[] = { COUNTRY_CODE_KR }; ++ ++static const UINT_16 g_u2CountryGroup15[] = { COUNTRY_CODE_NG }; ++ ++static const UINT_16 g_u2CountryGroup16[] = { ++ COUNTRY_CODE_BD, COUNTRY_CODE_BR, COUNTRY_CODE_DM, COUNTRY_CODE_DO, ++ COUNTRY_CODE_FK, COUNTRY_CODE_KZ, COUNTRY_CODE_MX, COUNTRY_CODE_MZ, ++ COUNTRY_CODE_NA, COUNTRY_CODE_RU, COUNTRY_CODE_LC, COUNTRY_CODE_VC, ++ COUNTRY_CODE_UA, COUNTRY_CODE_UZ, COUNTRY_CODE_ZW ++}; ++ ++static const UINT_16 g_u2CountryGroup17[] = { COUNTRY_CODE_MP }; ++ ++static const UINT_16 g_u2CountryGroup18[] = { COUNTRY_CODE_TW }; ++ ++static const UINT_16 g_u2CountryGroup19[] = { ++ COUNTRY_CODE_CK, COUNTRY_CODE_CU, COUNTRY_CODE_TL, COUNTRY_CODE_FO, ++ COUNTRY_CODE_GI, COUNTRY_CODE_GG, COUNTRY_CODE_IR, COUNTRY_CODE_IM, ++ COUNTRY_CODE_JE, COUNTRY_CODE_KP, COUNTRY_CODE_MH, COUNTRY_CODE_NU, ++ COUNTRY_CODE_NF, COUNTRY_CODE_PS, COUNTRY_CODE_PN, COUNTRY_CODE_PM, ++ COUNTRY_CODE_SS, COUNTRY_CODE_SD, COUNTRY_CODE_SY ++}; ++ ++static const UINT_16 g_u2CountryGroup20[] = { ++ COUNTRY_CODE_DF, COUNTRY_CODE_FF ++ /* When country code is not found and no matched NVRAM setting, ++ * this domain info will be used. ++ */ ++}; ++ ++static const UINT_16 g_u2CountryGroup21[] = { ++ COUNTRY_CODE_UDF ++}; ++ ++DOMAIN_INFO_ENTRY arSupportedRegDomains[] = { ++ { ++ (PUINT_16) g_u2CountryGroup0, sizeof(g_u2CountryGroup0) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup1, sizeof(g_u2CountryGroup1) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup2, sizeof(g_u2CountryGroup2) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup3, sizeof(g_u2CountryGroup3) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup4, sizeof(g_u2CountryGroup4) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup5, sizeof(g_u2CountryGroup5) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup6, sizeof(g_u2CountryGroup6) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 14, 1, FALSE} ++ , /* CH_SET_2G4_14_14 */ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup7, sizeof(g_u2CountryGroup7) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup8, sizeof(g_u2CountryGroup8) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup9, sizeof(g_u2CountryGroup9) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup10, sizeof(g_u2CountryGroup10) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup11, sizeof(g_u2CountryGroup11) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup12, sizeof(g_u2CountryGroup12) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup13, sizeof(g_u2CountryGroup13) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup14, sizeof(g_u2CountryGroup14) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 8, FALSE} ++ , /* CH_SET_UNII_WW_100_128 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup15, sizeof(g_u2CountryGroup15) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup16, sizeof(g_u2CountryGroup16) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup17, sizeof(g_u2CountryGroup17) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup18, sizeof(g_u2CountryGroup18) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup19, sizeof(g_u2CountryGroup19) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ /* Note: Default group if no matched country code */ ++ (PUINT_16) g_u2CountryGroup20, sizeof(g_u2CountryGroup20) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ /* Note: for customer configured their own scanning list and passive scan list */ ++ (PUINT_16) g_u2CountryGroup21, sizeof(g_u2CountryGroup21) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 12, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, FALSE} ++ , ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, FALSE} ++ , ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, FALSE} ++ , ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, FALSE} ++ , ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++}; ++ ++static UINT_16 g_u2CountryGroup0_Passive[] = { ++ COUNTRY_CODE_UDF ++}; ++ ++DOMAIN_INFO_ENTRY arSupportedRegDomains_Passive[] = { ++ { ++ /* Default passive scan channel table is empty */ ++ COUNTRY_CODE_NULL, 0, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 11, 0, 0}, /* CH_SET_2G4_1_14 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ ++ } ++ }, ++ { ++ /* User Defined passive scan channel table */ ++ g_u2CountryGroup0_Passive, 0, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 12, 1, 0}, /* CH_SET_2G4_1_14 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ ++ } ++ } ++}; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++SUBBAND_CHANNEL_T g_rRlmSubBand[] = { ++ ++ {BAND_2G4_LOWER_BOUND, BAND_2G4_UPPER_BOUND, 1, 0} ++ , /* 2.4G */ ++ {UNII1_LOWER_BOUND, UNII1_UPPER_BOUND, 2, 0} ++ , /* ch36,38,40,..,48 */ ++ {UNII2A_LOWER_BOUND, UNII2A_UPPER_BOUND, 2, 0} ++ , /* ch52,54,56,..,64 */ ++ {UNII2C_LOWER_BOUND, UNII2C_UPPER_BOUND, 2, 0} ++ , /* ch100,102,104,...,144 */ ++ {UNII3_LOWER_BOUND, UNII3_UPPER_BOUND, 2, 0} ++ /* ch149,151,153,....,173 */ ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter) ++{ ++#define REG_DOMAIN_DEF_IDX 20 /* Default country domain */ ++#define REG_DOMAIN_GROUP_NUM \ ++ (sizeof(arSupportedRegDomains) / sizeof(DOMAIN_INFO_ENTRY)) ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_REG_INFO_T prRegInfo; ++ UINT_16 u2TargetCountryCode; ++ UINT_16 i, j; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->prDomainInfo) ++ return prAdapter->prDomainInfo; ++ ++ prRegInfo = &prAdapter->prGlueInfo->rRegInfo; ++ ++ DBGLOG(RLM, TRACE, "eRegChannelListMap=%d, u2CountryCode=0x%04x\n", ++ prRegInfo->eRegChannelListMap, ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ /* ++ * Domain info can be specified by given idx of arSupportedRegDomains table, ++ * customized, or searched by country code, ++ * only one is set among these three methods in NVRAM. ++ */ ++ if (prRegInfo->eRegChannelListMap == REG_CH_MAP_TBL_IDX && ++ prRegInfo->ucRegChannelListIndex < REG_DOMAIN_GROUP_NUM) { ++ /* by given table idx */ ++ DBGLOG(RLM, TRACE, "ucRegChannelListIndex=%d\n", prRegInfo->ucRegChannelListIndex); ++ prDomainInfo = &arSupportedRegDomains[prRegInfo->ucRegChannelListIndex]; ++ } else if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { ++ /* by customized */ ++ prDomainInfo = &prRegInfo->rDomainInfo; ++ } else { ++ /* by country code */ ++ u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ ++ for (i = 0; i < REG_DOMAIN_GROUP_NUM; i++) { ++ prDomainInfo = &arSupportedRegDomains[i]; ++ ++ if ((prDomainInfo->u4CountryNum && prDomainInfo->pu2CountryGroup) || ++ prDomainInfo->u4CountryNum == 0) { ++ for (j = 0; j < prDomainInfo->u4CountryNum; j++) { ++ if (prDomainInfo->pu2CountryGroup[j] == u2TargetCountryCode) ++ break; ++ } ++ if (j < prDomainInfo->u4CountryNum) ++ break; /* Found */ ++ } ++ } ++ ++ /* If no matched country code, use the default country domain */ ++ if (i >= REG_DOMAIN_GROUP_NUM) { ++ DBGLOG(RLM, INFO, "No matched country code, use the default country domain\n"); ++ prDomainInfo = &arSupportedRegDomains[REG_DOMAIN_DEF_IDX]; ++ } ++ } ++ ++ prAdapter->prDomainInfo = prDomainInfo; ++ return prDomainInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] The input variable pointed by pucNumOfChannel is the max ++* arrary size. The return value indciates meaning list size. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmDomainGetChnlList(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, ++ UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ UINT_8 i, j, ucNum; ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(paucChannelList); ++ ASSERT(pucNumOfChannel); ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ ucNum = 0; ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ ++ if (prSubband->ucBand == BAND_NULL || prSubband->ucBand >= BAND_NUM || ++ (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand)) ++ continue; ++ ++ if (fgNoDfs == TRUE && prSubband->fgDfs == TRUE) ++ continue; ++ ++ if (eSpecificBand == BAND_NULL || prSubband->ucBand == eSpecificBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if (ucNum >= ucMaxChannelNum) ++ break; ++ paucChannelList[ucNum].eBand = prSubband->ucBand; ++ paucChannelList[ucNum].ucChannelNum = ++ prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan; ++ ucNum++; ++ } ++ } ++ } ++ ++ *pucNumOfChannel = ucNum; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++ rlmDomainSendDomainInfoCmd(prAdapter, fgIsOid); ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ rlmDomainSendPwrLimitCmd(prAdapter); ++#endif ++ rlmDomainSendPassiveScanInfoCmd(prAdapter, fgIsOid); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_CMD_SET_DOMAIN_INFO_T prCmd; ++ P_DOMAIN_SUBBAND_INFO prSubBand; ++ UINT_8 i; ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); ++ return; ++ } ++ kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ ++ prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ prCmd->u2IsSetPassiveScan = 0; ++ prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; ++ prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; ++ prCmd->aucReserved[0] = 0; ++ prCmd->aucReserved[1] = 0; ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubBand = &prDomainInfo->rSubBand[i]; ++ ++ prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; ++ prCmd->rSubBand[i].ucBand = prSubBand->ucBand; ++ ++ if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { ++ prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; ++ prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; ++ prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; ++ } ++ } ++ ++ /* Set domain info to chip */ ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_DOMAIN_INFO, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ fgIsOid, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ ++ (PUINT_8)prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ cnmMemFree(prAdapter, prCmd); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++#define REG_DOMAIN_PASSIVE_DEF_IDX 0 ++#define REG_DOMAIN_PASSIVE_UDF_IDX 1 ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_CMD_SET_DOMAIN_INFO_T prCmd; ++ P_DOMAIN_SUBBAND_INFO prSubBand; ++ UINT_8 i; ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); ++ return; ++ } ++ kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ ++ prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ prCmd->u2IsSetPassiveScan = 1; ++ prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; ++ prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; ++ prCmd->aucReserved[0] = 0; ++ prCmd->aucReserved[1] = 0; ++ ++ DBGLOG(RLM, TRACE, "u2CountryCode=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ if (prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_UDF) ++ prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_UDF_IDX]; ++ else ++ prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_DEF_IDX]; ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubBand = &prDomainInfo->rSubBand[i]; ++ ++ prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; ++ prCmd->rSubBand[i].ucBand = prSubBand->ucBand; ++ ++ if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { ++ prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; ++ prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; ++ prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; ++ } ++ } ++ ++ /* Set passive scan channel info to chip */ ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_DOMAIN_INFO, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ fgIsOid, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ cnmMemFree(prAdapter, prCmd); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return TRUE Legal channel ++* FALSE Illegal channel for current regulatory domain ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel) ++{ ++ UINT_8 i, j; ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ ++ if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) ++ continue; ++ ++ if (prSubband->ucBand == eBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) ++ == ucChannel) { ++ return TRUE; ++ } ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf) ++{ ++ /* ++ The Country element should only be included for Status Code 0 (Successful). ++ */ ++ UINT_32 u4IeLen; ++ UINT_8 aucClass[12] = { 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, ++ 0x1c, 0x1e, 0x20, 0x21 ++ }; ++ ++ /* ++ The Supported Operating Classes element is used by a STA to advertise the ++ operating classes that it is capable of operating with in this country. ++ ++ The Country element (see 8.4.2.10) allows a STA to configure its PHY and MAC ++ for operation when the operating triplet of Operating Extension Identifier, ++ Operating Class, and Coverage Class fields is present. ++ */ ++ SUP_OPERATING_CLASS_IE(pBuf)->ucId = ELEM_ID_SUP_OPERATING_CLASS; ++ SUP_OPERATING_CLASS_IE(pBuf)->ucLength = 1 + sizeof(aucClass); ++ SUP_OPERATING_CLASS_IE(pBuf)->ucCur = 0x0c; /* 0x51 */ ++ kalMemCopy(SUP_OPERATING_CLASS_IE(pBuf)->ucSup, aucClass, sizeof(aucClass)); ++ u4IeLen = (SUP_OPERATING_CLASS_IE(pBuf)->ucLength + 2); ++ pBuf += u4IeLen; ++ ++ COUNTRY_IE(pBuf)->ucId = ELEM_ID_COUNTRY_INFO; ++ COUNTRY_IE(pBuf)->ucLength = 6; ++ COUNTRY_IE(pBuf)->aucCountryStr[0] = 0x55; ++ COUNTRY_IE(pBuf)->aucCountryStr[1] = 0x53; ++ COUNTRY_IE(pBuf)->aucCountryStr[2] = 0x20; ++ COUNTRY_IE(pBuf)->arCountryStr[0].ucFirstChnlNum = 1; ++ COUNTRY_IE(pBuf)->arCountryStr[0].ucNumOfChnl = 11; ++ COUNTRY_IE(pBuf)->arCountryStr[0].cMaxTxPwrLv = 0x1e; ++ u4IeLen += (COUNTRY_IE(pBuf)->ucLength + 2); ++ ++ return u4IeLen; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (fgValid) : 0 -> inValid, 1 -> Valid ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh) ++{ ++ BOOLEAN fgValid = FALSE; ++ UINT_8 ucTemp = 0; ++ UINT_8 i; ++ /*Check Power limit table channel efficient or not */ ++ ++ for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { ++ if ((ucCentralCh >= g_rRlmSubBand[i].ucStartCh) && (ucCentralCh <= g_rRlmSubBand[i].ucEndCh)) ++ ucTemp = (ucCentralCh - g_rRlmSubBand[i].ucStartCh) % g_rRlmSubBand[i].ucInterval; ++ } ++ ++#if 0 ++ /*2.4G, ex 1, 2, 3 */ ++ if (ucCentralCh >= BAND_2G4_LOWER_BOUND && ucCentralCh <= BAND_2G4_UPPER_BOUND) ++ ucTemp = 0; ++ /*FCC- Spec : Band UNII-1, ex 36, 38, 40.... */ ++ else if (ucCentralCh >= UNII1_LOWER_BOUND && ucCentralCh <= UNII1_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII1_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-2A, ex 52, 54, 56.... */ ++ else if (ucCentralCh >= UNII2A_LOWER_BOUND && ucCentralCh <= UNII2A_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII2A_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-2C, ex 100, 102, 104.... */ ++ else if (ucCentralCh >= UNII2C_LOWER_BOUND && ucCentralCh <= UNII2C_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII2C_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-3, ex 149, 151, 153... */ ++ else if (ucCentralCh >= UNII3_LOWER_BOUND && ucCentralCh <= UNII3_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII3_LOWER_BOUND) % 2; ++#endif ++ if (ucTemp == 0) ++ fgValid = TRUE; ++ return fgValid; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 ucCenterChannel; ++ ++ if (eExtend == CHNL_EXT_SCA) ++ ucCenterChannel = ucPriChannel + 2; ++ else if (eExtend == CHNL_EXT_SCB) ++ ucCenterChannel = ucPriChannel - 2; ++ else ++ ucCenterChannel = ucPriChannel; ++ ++ return ucCenterChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eBand, ++ UINT_8 ucPriChannel, ++ ENUM_CHNL_EXT_T eExtend, ++ ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2) ++{ ++ UINT_8 ucCenterChannel; ++ BOOLEAN fgValidChannel = TRUE; ++ BOOLEAN fgValidBW = TRUE; ++ BOOLEAN fgValidRfSetting = TRUE; ++ UINT_32 u4PrimaryOffset; ++ ++ /*DBG msg for Channel InValid */ ++ if (eChannelWidth == CW_20_40MHZ) { ++ ucCenterChannel = rlmDomainGetCenterChannel(eBand, ucPriChannel, eExtend); ++ ++ /* Check Central Channel Valid or Not */ ++ fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); ++ if (fgValidChannel == FALSE) ++ DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); ++ } else if (eChannelWidth == CW_80MHZ) { ++ ucCenterChannel = ucChannelS1; ++ ++ /* Check Central Channel Valid or Not */ ++ fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); ++ if (fgValidChannel == FALSE) ++ DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); ++ } else if (eChannelWidth == CW_160MHZ) { ++ ucCenterChannel = ucChannelS2; ++ ++ /* Check Central Channel Valid or Not */ ++ /*TODo */ ++ } ++ ++ /* Check BW Setting Correct or Not */ ++ if (eBand == BAND_2G4) { ++ if (eChannelWidth != CW_20_40MHZ) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: B=%d, W=%d\n", eBand, eChannelWidth); ++ } ++ } else { ++ if (eChannelWidth == CW_80MHZ) { ++ u4PrimaryOffset = CAL_CH_OFFSET_80M(ucPriChannel, ucCenterChannel); ++ if (u4PrimaryOffset > 4) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); ++ } ++ } else if (eChannelWidth == CW_160MHZ) { ++ u4PrimaryOffset = CAL_CH_OFFSET_160M(ucPriChannel, ucCenterChannel); ++ if (u4PrimaryOffset > 8) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); ++ } ++ } ++ } ++ ++ if ((fgValidBW == FALSE) || (fgValidChannel == FALSE)) ++ fgValidRfSetting = FALSE; ++ ++ return fgValidRfSetting; ++ ++} ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (fgValid) : 0 -> inValid, 1 -> Valid ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, ++ COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, ++ UINT_8 ucPwrLimitNum) ++{ ++ UINT_8 i; ++ BOOLEAN fgValid = TRUE; ++ PINT_8 prPwrLimit; ++ ++ prPwrLimit = &rPowerLimitTableConfiguration.aucPwrLimit[0]; ++ ++ for (i = 0; i < ucPwrLimitNum; i++, prPwrLimit++) { ++ if (*prPwrLimit > MAX_TX_POWER || *prPwrLimit < MIN_TX_POWER) { ++ fgValid = FALSE; ++ break; /*Find out Wrong Power limit */ ++ } ++ } ++ return fgValid; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter) ++{ ++ UINT_8 i, j; ++ UINT_16 u2CountryCodeTable, u2CountryCodeCheck; ++ BOOLEAN fgChannelValid = FALSE; ++ BOOLEAN fgPowerLimitValid = FALSE; ++ BOOLEAN fgEntryRepetetion = FALSE; ++ BOOLEAN fgTableValid = TRUE; ++ ++ /*Configuration Table Check */ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { ++ /*Table Country Code */ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ /*Repetition Entry Check */ ++ for (j = i + 1; ++ j < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); ++ j++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[j].aucCountryCode[0], &u2CountryCodeCheck); ++ if (((g_rRlmPowerLimitConfiguration[i].ucCentralCh) == ++ g_rRlmPowerLimitConfiguration[j].ucCentralCh) ++ && (u2CountryCodeTable == u2CountryCodeCheck)) { ++ fgEntryRepetetion = TRUE; ++ DBGLOG(RLM, LOUD, "Domain: Configuration Repetition CC=%c%c, Ch=%d\n", ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ } ++ } ++ ++ /*Channel Number Check */ ++ fgChannelValid = ++ rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ ++ /*Power Limit Check */ ++ fgPowerLimitValid = ++ rlmDomainCheckPowerLimitValid(prAdapter, g_rRlmPowerLimitConfiguration[i], PWR_LIMIT_NUM); ++ ++ if (fgChannelValid == FALSE || fgPowerLimitValid == FALSE) { ++ fgTableValid = FALSE; ++ DBGLOG(RLM, LOUD, "Domain: CC=%c%c, Ch=%d, Limit: %d,%d,%d,%d,%d\n", ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh, ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]); ++ } ++ ++ if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ DBGLOG(RLM, LOUD, "Domain: Full search down\n"); ++ break; /*End of country table entry */ ++ } ++ ++ } ++ ++ if (fgEntryRepetetion == FALSE) ++ DBGLOG(RLM, TRACE, "Domain: Configuration Table no Repetiton.\n"); ++ ++ /*Configuration Table no error */ ++ if (fgTableValid == TRUE) ++ prAdapter->fgIsPowerLimitTableValid = TRUE; ++ else ++ prAdapter->fgIsPowerLimitTableValid = FALSE; ++ ++ /*Default Table Check */ ++ fgEntryRepetetion = FALSE; ++ for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ for (j = i + 1; j < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); j++) { ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[j].aucCountryCode[0], &u2CountryCodeCheck); ++ if (u2CountryCodeTable == u2CountryCodeCheck) { ++ fgEntryRepetetion = TRUE; ++ DBGLOG(RLM, LOUD, ++ "Domain: Default Repetition CC=%c%c\n", ++ g_rRlmPowerLimitDefault[j].aucCountryCode[0], ++ g_rRlmPowerLimitDefault[j].aucCountryCode[1]); ++ } ++ } ++ } ++ if (fgEntryRepetetion == FALSE) ++ DBGLOG(RLM, TRACE, "Domain: Default Table no Repetiton.\n"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (u2TableIndex) : if 0xFFFF -> No Table Match ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode) ++{ ++ ++ UINT_16 i; ++ UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; ++ UINT_16 u2TableIndex = POWER_LIMIT_TABLE_NULL; /* No Table Match */ ++ ++ /*Default Table Index */ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ if (u2CountryCodeTable == u2CountryCode) { ++ u2TableIndex = i; ++ break; /*match country code */ ++ } else if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ u2TableIndex = i; ++ break; /*find last one country- Default */ ++ } ++ } ++ ++ DBGLOG(RLM, TRACE, "Domain: Default Table Index = %d\n", u2TableIndex); ++ ++ return u2TableIndex; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainBuildCmdByDefaultTable(P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd, UINT_16 u2DefaultTableIndex) ++{ ++ UINT_8 i, k; ++ P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT prPwrLimitSubBand; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; ++ ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ prPwrLimitSubBand = &g_rRlmPowerLimitDefault[u2DefaultTableIndex]; ++ ++ /*Build power limit cmd by default table information */ ++ ++ for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[i] < MAX_TX_POWER) { ++ for (k = g_rRlmSubBand[i].ucStartCh; k <= g_rRlmSubBand[i].ucEndCh; ++ k += g_rRlmSubBand[i].ucInterval) { ++ if ((prPwrLimitSubBand->ucPwrUnit & BIT(i)) == 0) { ++ prCmdPwrLimit->ucCentralCh = k; ++ prCmdPwrLimit->cPwrLimitCCK = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit20 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit40 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit80 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit160 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ ++ } else { ++ /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 ++ * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ ++ prCmdPwrLimit->ucCentralCh = k; ++ prCmdPwrLimit->cPwrLimitCCK = prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit20 = prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit40 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 6; ++ if (prCmdPwrLimit->cPwrLimit40 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit40 = MAX_TX_POWER; ++ prCmdPwrLimit->cPwrLimit80 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 12; ++ if (prCmdPwrLimit->cPwrLimit80 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit80 = MAX_TX_POWER; ++ prCmdPwrLimit->cPwrLimit160 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 18; ++ if (prCmdPwrLimit->cPwrLimit160 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit160 = MAX_TX_POWER; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ } ++ } ++ ++#if 0 ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4] < MAX_TX_POWER) { ++ for (i = BAND_2G4_LOWER_BOUND; i <= BAND_2G4_UPPER_BOUND; i++) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4], ++ PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1] < MAX_TX_POWER) { ++ if (prCmd->u2CountryCode != COUNTRY_CODE_KR) { ++ for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } else { ++ for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { ++ /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 ++ * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ ++ prCmdPwrLimit->ucCentralCh = i; ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 6; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 12; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 18; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A] < MAX_TX_POWER) { ++ for (i = UNII2A_LOWER_BOUND; i <= UNII2A_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C] < MAX_TX_POWER) { ++ for (i = UNII2C_LOWER_BOUND; i <= UNII2C_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3] < MAX_TX_POWER) { ++ for (i = UNII3_LOWER_BOUND; i <= UNII3_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainBuildCmdByConfigTable(P_ADAPTER_T prAdapter, P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd) ++{ ++ UINT_8 i, k; ++ UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; ++ BOOLEAN fgChannelValid; ++ ++ /*Build power limit cmd by configuration table information */ ++ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ fgChannelValid = ++ rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ ++ if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ DBGLOG(RLM, TRACE, "Domain: full search configuration table done.\n"); ++ break; /*end of configuration table */ ++ } else if ((u2CountryCodeTable == prCmd->u2CountryCode) && (fgChannelValid == TRUE)) { ++ ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ ++ if (prCmd->ucNum != 0) { ++ for (k = 0; k < prCmd->ucNum; k++) { ++ if (prCmdPwrLimit->ucCentralCh == ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh) { ++ ++ /*Cmd setting (Default table information) and ++ Configuration table has repetition channel entry, ++ ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, ++ Configuration table (ex: ch1, limit = 22dBm) --> ch 1 = 22 dBm ++ Cmd final setting --> ch1 = 22dBm, ch12~14 = 20dBm ++ */ ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ ++ DBGLOG(RLM, LOUD, ++ "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, ++ prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, ++ prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ ++ break; ++ } ++ prCmdPwrLimit++; ++ } ++ if (k == prCmd->ucNum) { ++ ++ /*Full search cmd (Default table setting) no match channey, ++ ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, ++ Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm ++ Cmd final setting --> ch1~14 = 20dBm, ch36= 22dBm ++ */ ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ prCmd->ucNum++; ++ ++ DBGLOG(RLM, LOUD, ++ "Domain: Full CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), (prCmd->u2CountryCode & 0x00ff), ++ prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, ++ prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, ++ prCmdPwrLimit->ucFlag); ++ ++ } ++ } else { ++ ++ /*Default table power limit value are 63--> cmd table no channel entry ++ ex : Default table (ex: 2.4G, limit = 63Bm) --> no channel entry in cmd, ++ Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm ++ Cmd final setting --> ch36= 22dBm ++ */ ++ prCmdPwrLimit->ucCentralCh = g_rRlmPowerLimitConfiguration[i].ucCentralCh; ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ prCmd->ucNum++; ++ ++ DBGLOG(RLM, LOUD, "Domain: Default table power limit value are 63.\n"); ++ DBGLOG(RLM, LOUD, "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, ++ prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, ++ prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter) ++{ ++ P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd; ++ UINT_8 i; ++ UINT_16 u2DefaultTableIndex; ++ UINT_32 u4SetCmdTableMaxSize; ++ UINT_32 u4SetQueryInfoLen; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; /* for print usage */ ++ ++ u4SetCmdTableMaxSize = ++ sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + ++ MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); ++ ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); ++ return; ++ } ++ kalMemZero(prCmd, u4SetCmdTableMaxSize); ++ ++ u2DefaultTableIndex = ++ rlmDomainPwrLimitDefaultTableDecision(prAdapter, prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ if (u2DefaultTableIndex != POWER_LIMIT_TABLE_NULL) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[u2DefaultTableIndex].aucCountryCode[0], ++ &prCmd->u2CountryCode); ++ ++ prCmd->ucNum = 0; ++ ++ if (prCmd->u2CountryCode != COUNTRY_CODE_NULL) { ++ /*Command - default table information */ ++ rlmDomainBuildCmdByDefaultTable(prCmd, u2DefaultTableIndex); ++ ++ /*Command - configuration table information */ ++ rlmDomainBuildCmdByConfigTable(prAdapter, prCmd); ++ } ++ } ++#if 0 ++ u4SetCmdTableMaxSize = ++ sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + ++ MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); ++ ASSERT(prCmd); ++ ++ /* To do: exception handle */ ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); ++ return; ++ } ++ kalMemZero(prCmd, u4SetCmdTableMaxSize); /* TODO memzero */ ++ ++ if (u2TableIndex != POWER_LIMIT_TABLE_NULL && u2TableIndex < MAX_DEFAULT_TABLE_COUNTRY_NUM) { ++ ++ prCmd->u2CountryCode = (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[0]) << 8) | ++ (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[1]) & BITS(0, 7)); ++ prChPwrLimit = &g_rRlmCountryPowerLimitTable[u2TableIndex].rChannelPowerLimit[0]; ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ prCmd->ucNum = 0; ++ for (i = 0; i < MAX_CMD_SUPPORT_CHANNEL_NUM; i++) { ++ ++ if (prChPwrLimit->ucCentralCh != ENDCH) { ++ ++ /*Check Power limit table channel efficient or not */ ++ fgChannelValid = rlmDomainCheckChannelEntryValid(prAdapter, prChPwrLimit->ucCentralCh); ++ ++ /*Cmd set up */ ++ if (fgChannelValid) { ++ kalMemCopy(prCmdPwrLimit, prChPwrLimit, sizeof(CMD_CHANNEL_POWER_LIMIT)); ++ DBGLOG(RLM, INFO, ++ "Domain: ValidCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, ++ prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, ++ prCmdPwrLimit->ucFlag); ++ prCmd->ucNum++; ++ prCmdPwrLimit++; ++ } else { ++ DBGLOG(RLM, INFO, ++ "Domain: Non-Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ prChPwrLimit->ucCentralCh, prChPwrLimit->cPwrLimitCCK, ++ prChPwrLimit->cPwrLimit20, prChPwrLimit->cPwrLimit40, ++ prChPwrLimit->cPwrLimit80, prChPwrLimit->cPwrLimit160, ++ prChPwrLimit->ucFlag); ++ } ++ prChPwrLimit++; ++ } else { ++ /*End of the chanel entry */ ++ break; ++ } ++ }; ++ } ++#endif ++ ++ if (prCmd->u2CountryCode != 0) { ++ DBGLOG(RLM, INFO, ++ "Domain: ValidCC =%c%c, ChNum=%d\n", ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmd->ucNum); ++ } else { ++ DBGLOG(RLM, INFO, "Domain: ValidCC =0x%04x, ucNum=%d\n", prCmd->u2CountryCode, prCmd->ucNum); ++ } ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ ++ for (i = 0; i < prCmd->ucNum; i++) { ++ DBGLOG(RLM, TRACE, "Domain: Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ prCmdPwrLimit++; ++ } ++ ++ u4SetQueryInfoLen = ++ (sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + (prCmd->ucNum) * sizeof(CMD_CHANNEL_POWER_LIMIT)); ++ ++ /* Update domain info to chip */ ++ if (prCmd->ucNum <= MAX_CMD_SUPPORT_CHANNEL_NUM) { ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_COUNTRY_POWER_LIMIT, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ u4SetQueryInfoLen, /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ } else ++ DBGLOG(RLM, ERROR, "Domain: illegal power limit table"); ++ ++ cnmMemFree(prAdapter, prCmd); ++ ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c +new file mode 100644 +index 000000000000..8450124a3f38 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c +@@ -0,0 +1,436 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_obss.c#2 ++*/ ++ ++/*! \file "rlm_obss.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_obss.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Avoid possible OBSS scan when BSS is switched ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Regulation class is changed to 81 in 20_40_coexistence action frame ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame ++ * in AP mode and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Use SCO of BSS_INFO to replace user-defined setting variables ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Fix compile error while enabling WiFi Direct function. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add more ASSERT to check exception ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssInit(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 ucNetIdx; ++ ++ RLM_NET_FOR_EACH(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ cnmTimerInitTimer(prAdapter, &prBssInfo->rObssScanTimer, rlmObssScanTimeout, (ULONG) prBssInfo); ++ } /* end of RLM_NET_FOR_EACH */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmObssUpdateChnlLists(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_20_40_COEXIST_FRAME prTxFrame; ++ UINT_16 i, u2PayloadLen; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prScanDoneMsg->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ DBGLOG(RLM, INFO, "OBSS Scan Done (NetIdx=%d, Mode=%d)\n", ++ prScanDoneMsg->ucNetTypeIndex, prBssInfo->eCurrentOPMode); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* AP mode */ ++ if ((prAdapter->fgIsP2PRegistered) && ++ (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex)) && ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ return; ++ } ++#endif ++ ++ /* STA mode */ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || ++ !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { ++ DBGLOG(RLM, WARN, "OBSS Scan Done (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ /* To do: check 2.4G channel list to decide if obss mgmt should be ++ * sent to associated AP. Note: how to handle concurrent network? ++ * To do: invoke rlmObssChnlLevel() to decide if 20/40 BSS coexistence ++ * management frame is needed. ++ */ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ if ((prBssInfo->auc2G_20mReqChnlList[0] > 0 || prBssInfo->auc2G_NonHtChnlList[0] > 0) && prMsduInfo != NULL) { ++ DBGLOG(RLM, INFO, "Send 20/40 coexistence mgmt(20mReq=%d, NonHt=%d)\n", ++ prBssInfo->auc2G_20mReqChnlList[0], prBssInfo->auc2G_NonHtChnlList[0]); ++ ++ prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; ++ prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; ++ ++ /* To do: find correct algorithm */ ++ prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ prTxFrame->rBssCoexist.ucLength = 1; ++ prTxFrame->rBssCoexist.ucData = (prBssInfo->auc2G_20mReqChnlList[0] > 0) ? BSS_COEXIST_20M_REQ : 0; ++ ++ u2PayloadLen = 2 + 3; ++ ++ if (prBssInfo->auc2G_NonHtChnlList[0] > 0) { ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ ++ prTxFrame->rChnlReport.ucId = ELEM_ID_20_40_INTOLERANT_CHNL_REPORT; ++ prTxFrame->rChnlReport.ucLength = prBssInfo->auc2G_NonHtChnlList[0] + 1; ++ prTxFrame->rChnlReport.ucRegulatoryClass = 81; /* 2.4GHz, ch1~13 */ ++ for (i = 0; i < prBssInfo->auc2G_NonHtChnlList[0] && i < CHNL_LIST_SZ_2G; i++) ++ prTxFrame->rChnlReport.aucChannelList[i] = prBssInfo->auc2G_NonHtChnlList[i + 1]; ++ ++ u2PayloadLen += IE_SIZE(&prTxFrame->rChnlReport); ++ } ++ ASSERT((WLAN_MAC_HEADER_LEN + u2PayloadLen) <= PUBLIC_ACTION_MAX_LEN); ++ ++ /* Clear up channel lists in 2.4G band */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ } ++ /* end of prMsduInfo != NULL */ ++ if (prBssInfo->u2ObssScanInterval > 0) { ++ DBGLOG(RLM, INFO, "Set OBSS timer (NetIdx=%d, %d sec)\n", ++ prBssInfo->ucNetTypeIndex, prBssInfo->u2ObssScanInterval); ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = (P_BSS_INFO_T) ulData; ++ ASSERT(prBssInfo); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex))) { ++ ++ /* AP mode */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ ++ prBssInfo->fgObssActionForcedTo20M = FALSE; ++ ++ /* Check if Beacon content need to be updated */ ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); ++ ++ return; ++ } ++#if CFG_SUPPORT_WFD ++ /* WFD streaming */ ++ else { ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = ++ &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ P_BSS_INFO_T prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ /* If WFD is enabled & connected */ ++ if (prWfdCfgSettings->ucWfdEnable && ++ (prWfdCfgSettings->u4WfdFlag & BIT(0)) && RLM_NET_PARAM_VALID(prP2pBssInfo)) { ++ ++ /* Skip OBSS scan */ ++ prBssInfo->u2ObssScanInterval = 0; ++ ++ DBGLOG(RLM, INFO, "WFD is running. Stop net[%u] OBSS scan.\n", ++ (UINT_32) prBssInfo->ucNetTypeIndex); ++ ++ return; ++ } ++ } ++#endif ++ } ++#endif /* end of CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* STA mode */ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || ++ !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { ++ DBGLOG(RLM, WARN, "OBSS Scan timeout (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ rlmObssTriggerScan(prAdapter, prBssInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ ++ ASSERT(prBssInfo); ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ ASSERT(prScanReqMsg); ++ ++ if (!prScanReqMsg) { ++ DBGLOG(RLM, WARN, "No buf for OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ return; ++ } ++ ++ /* It is ok that ucSeqNum is set to fixed value because the same network ++ * OBSS scan interval is limited to OBSS_SCAN_MIN_INTERVAL (min 10 sec) ++ * and scan module don't care seqNum of OBSS scanning ++ */ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_RLM_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = 0x33; ++ prScanReqMsg->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; ++ prScanReqMsg->ucSSIDLength = 0; ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ prScanReqMsg->u2IELen = 0; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(RLM, INFO, "Timeout to trigger OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c +new file mode 100644 +index 000000000000..d3c513397095 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c +@@ -0,0 +1,105 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_protection.c#1 ++*/ ++ ++/*! \file "rlm_protection.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_protection.c ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set RTS threshold of 2K bytes initially ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 03 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable RTS threshold temporarily for AMPDU ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c +new file mode 100644 +index 000000000000..3f088c283993 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c +@@ -0,0 +1,539 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "roaming_fsm.c" ++ \brief This file defines the FSM for Roaming MODULE. ++ ++ This file defines the FSM for Roaming MODULE. ++*/ ++ ++/* ++** Log: roaming_fsm.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_ROAMING ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugRoamingState[ROAMING_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("ROAMING_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_DECISION"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_DISCOVERY"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_ROAM") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* ++#define ROAMING_ENABLE_CHECK(_roam) \ ++{ \ ++ if (!(_roam->fgIsEnableRoaming)) \ ++ return; \ ++} ++*/ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the value in ROAMING_FSM_INFO_T for ROAMING FSM operation ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmInit(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Initiate FSM */ ++ prRoamingFsmInfo->fgIsEnableRoaming = prConnSettings->fgIsEnableRoaming; ++ prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; ++ prRoamingFsmInfo->rRoamingDiscoveryUpdateTime = 0; ++ ++} /* end of roamingFsmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Uninitialize the value in AIS_FSM_INFO_T for AIS FSM operation ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmUninit(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; ++ ++} /* end of roamingFsmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send commands to firmware ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN P_ROAMING_PARAM_T] prParam ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ WLAN_STATUS rStatus; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmSendCmd(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_ROAMING_TRANSIT, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(ROAMING_PARAM_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prParam, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++} /* end of roamingFsmSendCmd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the recent time when ScanDone occurred ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmScanResultsUpdate(): Current Time = %u", kalGetTimeTick()); ++ ++ GET_CURRENT_SYSTIME(&prRoamingFsmInfo->rRoamingDiscoveryUpdateTime); ++ ++} /* end of roamingFsmScanResultsUpdate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of ROAMING for AIS Infra. ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN ENUM_ROAMING_STATE_T] eNextState Enum value of next AIS STATE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T ePreviousState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ do { ++ ++ /* Do entering Next State */ ++#if DBG ++ DBGLOG(ROAMING, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugRoamingState[prRoamingFsmInfo->eCurrentState], ++ apucDebugRoamingState[eNextState]); ++#else ++ DBGLOG(ROAMING, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_ROAMING_IDX, prRoamingFsmInfo->eCurrentState, eNextState); ++#endif ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ ePreviousState = prRoamingFsmInfo->eCurrentState; ++ prRoamingFsmInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ /* Do tasks of the State that we just entered */ ++ switch (prRoamingFsmInfo->eCurrentState) { ++ /* NOTE(Kevin): we don't have to rearrange the sequence of following ++ * switch case. Instead I would like to use a common lookup table of array ++ * of function pointer to speed up state search. ++ */ ++ case ROAMING_STATE_IDLE: ++ case ROAMING_STATE_DECISION: ++ break; ++ ++ case ROAMING_STATE_DISCOVERY: ++ { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prRoamingFsmInfo->rRoamingDiscoveryUpdateTime, ++ SEC_TO_SYSTIME(ROAMING_DISCOVERY_TIMEOUT_SEC))) { ++ DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Timeout"); ++ aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); ++ } else { ++ DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Updated"); ++#if CFG_SUPPORT_ROAMING_ENC ++ if (prAdapter->fgIsRoamingEncEnabled == TRUE) ++ aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); ++ else ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ aisFsmRunEventRoamingDiscovery(prAdapter, FALSE); ++ } ++ } ++ break; ++ ++ case ROAMING_STATE_ROAM: ++ break; ++ ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ } ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of roamingFsmSteps() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Decision state after join completion ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ P_BSS_INFO_T prAisBssInfo; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prAisBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING START: Current Time = %u\n", kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as DECISION, DISCOVERY -> DECISION */ ++ if (!(prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE || ++ prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) ++ return; ++ ++ eNextState = ROAMING_STATE_DECISION; ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_START; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventStart() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Discovery state when deciding to find a candidate ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING DISCOVERY: Current Time = %u Reason = %u\n", ++ kalGetTimeTick(), prParam->u2Reason); ++ ++ /* DECISION -> DISCOVERY */ ++ /* Errors as IDLE, DISCOVERY, ROAM -> DISCOVERY */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DECISION) ++ return; ++#if CFG_SUPPORT_ROAMING_ENC ++ prRoamingFsmInfo->RoamingEntryTimeoutSkipCount = 0; ++#endif ++ ++ eNextState = ROAMING_STATE_DISCOVERY; ++ /* DECISION -> DISCOVERY */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ P_BSS_INFO_T prAisBssInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ /* sync. rcpi with firmware */ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc) ++ prBssDesc->ucRCPI = (UINT_8) (prParam->u2Data & 0xff); ++ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventDiscovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Roam state after Scan Done ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ROAM: Current Time = %u\n", kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as IDLE, DECISION, ROAM -> ROAM */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DISCOVERY) ++ return; ++ ++ eNextState = ROAMING_STATE_ROAM; ++ /* DISCOVERY -> ROAM */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_ROAM; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventRoam() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Decision state as being failed to find out any candidate ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING FAIL: reason %x Current Time = %u\n", u4Param, kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as IDLE, DECISION, DISCOVERY -> DECISION */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_ROAM) ++ return; ++ ++ eNextState = ROAMING_STATE_DECISION; ++ /* ROAM -> DECISION */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_FAIL; ++ rParam.u2Data = (UINT_16) (u4Param & 0xffff); ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventFail() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Idle state as beging aborted by other moduels, AIS ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ABORT: Current Time = %u\n", kalGetTimeTick()); ++ ++ eNextState = ROAMING_STATE_IDLE; ++ /* IDLE, DECISION, DISCOVERY, ROAM -> IDLE */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_ABORT; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process events from firmware ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN P_ROAMING_PARAM_T] prParam ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ DBGLOG(ROAMING, LOUD, "ROAMING Process Events: Current Time = %u\n", kalGetTimeTick()); ++ ++ if (ROAMING_EVENT_DISCOVERY == prParam->u2Event) ++ roamingFsmRunEventDiscovery(prAdapter, prParam); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c +new file mode 100644 +index 000000000000..eedd8d12f2fd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c +@@ -0,0 +1,2533 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rsn.c#2 ++*/ ++ ++/*! \file "rsn.c" ++ \brief This file including the 802.11i, wpa and wpa2(rsn) related function. ++ ++ This file provided the macros and functions library support the wpa/rsn ie parsing, ++ cipher and AKM check to help the AP seleced deciding, tkip mic error handler and rsn PMKID support. ++*/ ++ ++/* ++** Log: rsn.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 09 2012 chinglan.wang ++ * NULL ++ * Fix the condition error. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 12 24 2010 chinglan.wang ++ * NULL ++ * [MT6620][Wi-Fi] Modify the key management in the driver for WPS function. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 11 03 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Refine the HT rate disallow TKIP pairwise cipher . ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 29 2010 yuche.tsai ++ * NULL ++ * Fix compile error, remove unused pointer in rsnGenerateRSNIE(). ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 08 30 2010 wh.su ++ * NULL ++ * remove non-used code. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * [WPD00003840] [MT6620 5931] Security migration ++ * migration from firmware. ++ * ++ * 05 27 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * not indicate pmkid candidate while no new one scanned. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the name ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * using the Rx0 port to indicate event ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine the code for generate the WPA/RSN IE for assoc req ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust code for pmkid event ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code for event (mic error and pmkid indicate) and do some function rename ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security function ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security feature, including pmkid ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_RSN_MIGRATION ++ ++/* extern PHY_ATTRIBUTE_T rPhyAttributes[]; */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse RSN IE. ++* ++* \param[in] prInfoElem Pointer to the RSN IE ++* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the ++** RSN information from the given RSN IE ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainRsnIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUINT_8 pucPairSuite = NULL; ++ PUINT_8 pucAuthSuite = NULL; ++ PUINT_8 cp; ++ ++ DEBUGFUNC("rsnParseRsnIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prRsnInfo); ++ ++ /* Verify the length of the RSN IE. */ ++ if (prInfoElem->ucLength < 2) { ++ DBGLOG(RSN, TRACE, "RSN IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check RSN version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(RSN, TRACE, "Unsupported RSN IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) & prInfoElem->u4GroupKeyCipherSuite; ++ u4RemainRsnIeLen = (INT_32) prInfoElem->ucLength - 2; ++ ++ do { ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainRsnIeLen < 4) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainRsnIeLen -= 4; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainRsnIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainRsnIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainRsnIeLen -= (INT_32) i; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainRsnIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainRsnIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainRsnIeLen -= (INT_32) i; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the RSN u2Capabilities field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ } while (FALSE); ++ ++ /* Save the RSN information for the BSS. */ ++ prRsnInfo->ucElemId = ELEM_ID_RSN; ++ ++ prRsnInfo->u2Version = u2Version; ++ ++ prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(RSN, LOUD, "RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; ++ ++ prRsnInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prRsnInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for RSN: CCMP. */ ++ prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP; ++ ++ DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; ++ ++ prRsnInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for RSN. */ ++ prRsnInfo->u4AuthKeyMgtSuiteCount = 1; ++ prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X; ++ ++ DBGLOG(RSN, LOUD, "RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ prRsnInfo->u2RsnCap = u2Cap; ++#if CFG_SUPPORT_802_11W ++ prRsnInfo->fgRsnCapPresent = TRUE; ++#endif ++ DBGLOG(RSN, LOUD, "RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap); ++ ++ return TRUE; ++} /* rsnParseRsnIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse WPA IE. ++* ++* \param[in] prInfoElem Pointer to the WPA IE. ++* \param[out] prWpaInfo Pointer to the BSSDescription structure to store the ++* WPA information from the given WPA IE. ++* ++* \retval TRUE Succeeded. ++* \retval FALSE Failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainWpaIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUCHAR pucPairSuite = NULL; ++ PUCHAR pucAuthSuite = NULL; ++ PUCHAR cp; ++ BOOLEAN fgCapPresent = FALSE; ++ ++ DEBUGFUNC("rsnParseWpaIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prWpaInfo); ++ ++ /* Verify the length of the WPA IE. */ ++ if (prInfoElem->ucLength < 6) { ++ DBGLOG(RSN, TRACE, "WPA IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check WPA version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(RSN, TRACE, "Unsupported WPA IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite; ++ u4RemainWpaIeLen = (INT_32) prInfoElem->ucLength - 6; ++ ++ do { ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* WPA_OUI : 4 ++ Version : 2 ++ GroupSuite : 4 ++ PairwiseCount: 2 ++ PairwiseSuite: 4 * pairSuiteCount ++ AuthCount : 2 ++ AuthSuite : 4 * authSuiteCount ++ Cap : 2 */ ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainWpaIeLen < 4) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainWpaIeLen -= 4; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainWpaIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainWpaIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainWpaIeLen -= (INT_32) i; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count ++ field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainWpaIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainWpaIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainWpaIeLen -= (INT_32) i; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the WPA u2Capabilities field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ fgCapPresent = TRUE; ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ u4RemainWpaIeLen -= 2; ++ } while (FALSE); ++ ++ /* Save the WPA information for the BSS. */ ++ ++ prWpaInfo->ucElemId = ELEM_ID_WPA; ++ ++ prWpaInfo->u2Version = u2Version; ++ ++ prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(RSN, LOUD, "WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; ++ ++ prWpaInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prWpaInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for WPA: TKIP. */ ++ prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP; ++ ++ DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; ++ ++ prWpaInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for WPA. */ ++ prWpaInfo->u4AuthKeyMgtSuiteCount = 1; ++ prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X; ++ ++ DBGLOG(RSN, LOUD, "WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (fgCapPresent) { ++ prWpaInfo->fgRsnCapPresent = TRUE; ++ prWpaInfo->u2RsnCap = u2Cap; ++ DBGLOG(RSN, LOUD, "WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap); ++ } else { ++ prWpaInfo->fgRsnCapPresent = FALSE; ++ prWpaInfo->u2RsnCap = 0; ++ } ++ ++ return TRUE; ++} /* rsnParseWpaIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search the desired pairwise ++* cipher suite from the MIB Pairwise Cipher Suite ++* configuration table. ++* ++* \param[in] u4Cipher The desired pairwise cipher suite to be searched ++* \param[out] pu4Index Pointer to the index of the desired pairwise cipher in ++* the table ++* ++* \retval TRUE - The desired pairwise cipher suite is found in the table. ++* \retval FALSE - The desired pairwise cipher suite is not found in the ++* table. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index) ++{ ++ UINT_8 i; ++ P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; ++ ++ DEBUGFUNC("rsnSearchSupportedCipher"); ++ ++ ASSERT(pu4Index); ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i]; ++ if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher && ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled) { ++ *pu4Index = i; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} /* rsnSearchSupportedCipher */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether BSS RSN is matched from upper layer set. ++* ++* \param[in] prAdapter Pointer to the Adapter structure, BSS RSN Information ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo) ++{ ++ UINT_8 i = 0; ++ ++ DEBUGFUNC("rsnIsSuitableBSS"); ++ ++ do { ++ ++ if ((prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite)) { ++ DBGLOG(RSN, TRACE, "Break by GroupKeyCipherSuite\n"); ++ break; ++ } ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])) ++ && (i == prBssRsnInfo->u4PairwiseKeyCipherSuiteCount - 1)) { ++ DBGLOG(RSN, TRACE, "Break by PairwiseKeyCipherSuite\n"); ++ break; ++ } ++ } ++ for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { ++ if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4AuthKeyMgtSuite[0])) ++ && (i == prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1)) { ++ DBGLOG(RSN, TRACE, "Break by AuthKeyMgtSuite\n"); ++ break; ++ } ++ } ++ return TRUE; ++ } while (FALSE); ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to search the desired ++* authentication and key management (AKM) suite from the ++* MIB Authentication and Key Management Suites table. ++* ++* \param[in] u4AkmSuite The desired AKM suite to be searched ++* \param[out] pu4Index Pointer to the index of the desired AKM suite in the ++* table ++* ++* \retval TRUE The desired AKM suite is found in the table. ++* \retval FALSE The desired AKM suite is not found in the table. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index) ++{ ++ UINT_8 i; ++ P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; ++ ++ DEBUGFUNC("rsnSearchAKMSuite"); ++ ++ ASSERT(pu4Index); ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; ++ if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite && ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) { ++ *pu4Index = i; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} /* rsnSearchAKMSuite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to perform RSNA or TSN policy ++* selection for a given BSS. ++* ++* \param[in] prBss Pointer to the BSS description ++* ++* \retval TRUE - The RSNA/TSN policy selection for the given BSS is ++* successful. The selected pairwise and group cipher suites ++* are returned in the BSS description. ++* \retval FALSE - The RSNA/TSN policy selection for the given BSS is failed. ++* The driver shall not attempt to join the given BSS. ++* ++* \note The Encrypt status matched score will save to bss for final ap select. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++#if CFG_SUPPORT_802_11W ++ INT_32 i; ++ UINT_32 j; ++#else ++ UINT_32 i, j; ++#endif ++ BOOLEAN fgSuiteSupported; ++ UINT_32 u4PairwiseCipher = 0; ++ UINT_32 u4GroupCipher = 0; ++ UINT_32 u4AkmSuite = 0; ++ P_RSN_INFO_T prBssRsnInfo; ++ ENUM_NETWORK_TYPE_INDEX_T eNetwotkType; ++ BOOLEAN fgIsWpsActive = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("rsnPerformPolicySelection"); ++ ++ ASSERT(prBss); ++ ++ DBGLOG(RSN, TRACE, "rsnPerformPolicySelection\n"); ++ /* Todo:: */ ++ eNetwotkType = NETWORK_TYPE_AIS_INDEX; ++ ++ prBss->u4RsnSelectedPairwiseCipher = 0; ++ prBss->u4RsnSelectedGroupCipher = 0; ++ prBss->u4RsnSelectedAKMSuite = 0; ++ prBss->ucEncLevel = 0; ++ ++#if CFG_SUPPORT_WPS ++ fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo); ++ ++ /* CR1640, disable the AP select privacy check */ ++ if (fgIsWpsActive && ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) && ++ (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) { ++ DBGLOG(RSN, TRACE, "-- Skip the Protected BSS check\n"); ++ return TRUE; ++ } ++#endif ++ ++ /* Protection is not required in this BSS. */ ++ if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0) { ++ ++ if (secEnabledInAis(prAdapter) == FALSE) { ++ DBGLOG(RSN, TRACE, "-- No Protected BSS\n"); ++ return TRUE; ++ } ++ DBGLOG(RSN, TRACE, "-- Protected BSS\n"); ++ return FALSE; ++ ++ } ++ ++ /* Protection is required in this BSS. */ ++ if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) { ++ if (secEnabledInAis(prAdapter) == FALSE) { ++ DBGLOG(RSN, TRACE, "-- Protected BSS\n"); ++ return FALSE; ++ } ++ } ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { ++ ++ if (prBss->fgIEWPA) { ++ prBssRsnInfo = &prBss->rWPAInfo; ++ } else { ++ DBGLOG(RSN, TRACE, "WPA Information Element does not exist.\n"); ++ return FALSE; ++ } ++ } else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) { ++ ++ if (prBss->fgIERSN) { ++ prBssRsnInfo = &prBss->rRSNInfo; ++ } else { ++ DBGLOG(RSN, TRACE, "RSN Information Element does not exist.\n"); ++ return FALSE; ++ } ++ } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != ENUM_ENCRYPTION1_ENABLED) { ++ /* If the driver is configured to use WEP only, ignore this BSS. */ ++ DBGLOG(RSN, TRACE, "-- Not WEP-only legacy BSS %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ return FALSE; ++ } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) { ++ /* If the driver is configured to use WEP only, use this BSS. */ ++ DBGLOG(RSN, TRACE, "-- WEP-only legacy BSS, fgIERSN %d, fgIEWPA %d\n", ++ prBss->fgIERSN, prBss->fgIEWPA); ++ /* if this BSS was configured to WPA/WPA2, don't select this AP */ ++ return (prBss->fgIERSN || prBss->fgIEWPA) ? FALSE : TRUE; ++ } ++ ++ if (!rsnIsSuitableBSS(prAdapter, prBssRsnInfo)) { ++ DBGLOG(RSN, TRACE, "RSN info check no matched\n"); ++ return FALSE; ++ } ++ ++ if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 && ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == CIPHER_SUITE_NONE) { ++ /* Since the pairwise cipher use the same cipher suite as the group ++ cipher in the BSS, we check the group cipher suite against the ++ current encryption status. */ ++ fgSuiteSupported = FALSE; ++ ++ switch (prBssRsnInfo->u4GroupKeyCipherSuite) { ++ case WPA_CIPHER_SUITE_CCMP: ++ case RSN_CIPHER_SUITE_CCMP: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ ++ case WPA_CIPHER_SUITE_TKIP: ++ case RSN_CIPHER_SUITE_TKIP: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ ++ case WPA_CIPHER_SUITE_WEP40: ++ case WPA_CIPHER_SUITE_WEP104: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ } ++ ++ if (fgSuiteSupported) { ++ u4PairwiseCipher = WPA_CIPHER_SUITE_NONE; ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ } ++#if DBG ++ else { ++ DBGLOG(RSN, TRACE, "Inproper encryption status %d for group-key-only BSS\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++#endif ++ } else { ++ fgSuiteSupported = FALSE; ++ ++ DBGLOG(RSN, TRACE, "eEncStatus %d %d 0x%x\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, ++ (UINT_32) prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, ++ (UINT_32) prBssRsnInfo->au4PairwiseKeyCipherSuite[0]); ++ /* Select pairwise/group ciphers */ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION3_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_CCMP) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_TKIP) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_CCMP) ++ DBGLOG(RSN, TRACE, "Cannot join CCMP BSS\n"); ++ else ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_WEP40 || ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_WEP104) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == ++ CIPHER_SUITE_CCMP || ++ GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_TKIP) { ++ DBGLOG(RSN, TRACE, "Cannot join CCMP/TKIP BSS\n"); ++ } else { ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ /* Exception handler */ ++ /* If we cannot find proper pairwise and group cipher suites to join the ++ BSS, do not check the supported AKM suites. */ ++ if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { ++ DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (eNetwotkType == NETWORK_TYPE_P2P_INDEX)) { ++ if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || ++ u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { ++ DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher for P2P network (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (eNetwotkType == NETWORK_TYPE_BOW_INDEX) { ++ if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || ++ u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { ++ /* Do nothing */ ++ } ++ DBGLOG(RSN, TRACE, ++ "Failed to select pairwise/group cipher for BT over Wi-Fi network (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++#endif ++ ++ /* Verify if selected pairwisse cipher is supported */ ++ fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i); ++ ++ /* Verify if selected group cipher is supported */ ++ if (fgSuiteSupported) ++ fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i); ++ ++ if (!fgSuiteSupported) { ++ DBGLOG(RSN, TRACE, "Failed to support selected pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ ++ /* Select AKM */ ++ /* If the driver cannot support any authentication suites advertised in ++ the given BSS, we fail to perform RSNA policy selection. */ ++ /* Attempt to find any overlapping supported AKM suite. */ ++#if CFG_SUPPORT_802_11W ++ if (i != 0) ++ for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) { ++#else ++ for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { ++#endif ++ if (rsnSearchAKMSuite(prAdapter, prBssRsnInfo->au4AuthKeyMgtSuite[i], &j)) { ++ u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i]; ++ break; ++ } ++ } ++ ++ if (u4AkmSuite == 0) { ++ DBGLOG(RSN, TRACE, "Cannot support any AKM suites\n"); ++ return FALSE; ++ } ++ ++ DBGLOG(RSN, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4PairwiseCipher & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), ++ (UINT_8) (u4GroupCipher & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); ++ ++ DBGLOG(RSN, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4AkmSuite & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); ++ ++#if CFG_SUPPORT_802_11W ++ DBGLOG(RSN, TRACE, "MFP setting = %d\n ", kalGetMfpSetting(prAdapter->prGlueInfo)); ++ ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { ++ if (!prBssRsnInfo->fgRsnCapPresent) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability.\n"); ++ return FALSE; ++ } else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required\n"); ++ return FALSE; ++ } ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ } else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) { ++ if (prBssRsnInfo->u2RsnCap && ((prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR) || ++ (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC))) { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ } else { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ } ++ } else { ++ if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability\n"); ++ return FALSE; ++ } ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ } ++ DBGLOG(RSN, TRACE, "fgMgmtProtection = %d\n ", prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection); ++#endif ++ ++ if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP) { ++ prBss->ucEncLevel = 3; ++ } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP) { ++ prBss->ucEncLevel = 2; ++ } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 || ++ GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) { ++ prBss->ucEncLevel = 1; ++ } else { ++ ASSERT(FALSE); ++ } ++ prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher; ++ prBss->u4RsnSelectedGroupCipher = u4GroupCipher; ++ prBss->u4RsnSelectedAKMSuite = u4AkmSuite; ++ ++ return TRUE; ++ ++} /* rsnPerformPolicySelection */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate WPA IE for beacon frame. ++* ++* \param[in] pucIeStartAddr Pointer to put the generated WPA IE. ++* ++* \return The append WPA-None IE length ++* \note ++* Called by: JOIN module, compose beacon IE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 i; ++ P_WPA_INFO_ELEM_T prWpaIE; ++ UINT_32 u4Suite; ++ UINT_16 u2SuiteCount; ++ PUINT_8 cp, cp2; ++ UINT_8 ucExpendedLen = 0; ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ ++ DEBUGFUNC("rsnGenerateWpaNoneIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE) ++ return; ++ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ ++ if (eNetworkId != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ prWpaIE = (P_WPA_INFO_ELEM_T) (pucBuffer); ++ ++ /* Start to construct a WPA IE. */ ++ /* Fill the Element ID field. */ ++ prWpaIE->ucElemId = ELEM_ID_WPA; ++ ++ /* Fill the OUI and OUI Type fields. */ ++ prWpaIE->aucOui[0] = 0x00; ++ prWpaIE->aucOui[1] = 0x50; ++ prWpaIE->aucOui[2] = 0xF2; ++ prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA; ++ ++ /* Fill the Version field. */ ++ WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */ ++ ucExpendedLen = 6; ++ ++ /* Fill the Pairwise Key Cipher Suite List field. */ ++ u2SuiteCount = 0; ++ cp = (PUINT_8) &prWpaIE->aucPairwiseKeyCipherSuite1[0]; ++ ++ if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) ++ u4Suite = WPA_CIPHER_SUITE_CCMP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) ++ u4Suite = WPA_CIPHER_SUITE_TKIP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) ++ u4Suite = WPA_CIPHER_SUITE_WEP104; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) ++ u4Suite = WPA_CIPHER_SUITE_WEP40; ++ else ++ u4Suite = WPA_CIPHER_SUITE_TKIP; ++ ++ WLAN_SET_FIELD_32(cp, u4Suite); ++ u2SuiteCount++; ++ ucExpendedLen += 4; ++ cp += 4; ++ ++ /* Fill the Group Key Cipher Suite field as the same in pair-wise key. */ ++ WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite); ++ ucExpendedLen += 4; ++ ++ /* Fill the Pairwise Key Cipher Suite Count field. */ ++ WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount); ++ ucExpendedLen += 2; ++ ++ cp2 = cp; ++ ++ /* Fill the Authentication and Key Management Suite List field. */ ++ u2SuiteCount = 0; ++ cp += 2; ++ ++ if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i)) ++ u4Suite = WPA_AKM_SUITE_802_1X; ++ else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i)) ++ u4Suite = WPA_AKM_SUITE_PSK; ++ else ++ u4Suite = WPA_AKM_SUITE_NONE; ++ ++ /* This shall be the only available value for current implementation */ ++ ASSERT(u4Suite == WPA_AKM_SUITE_NONE); ++ ++ WLAN_SET_FIELD_32(cp, u4Suite); ++ u2SuiteCount++; ++ ucExpendedLen += 4; ++ cp += 4; ++ ++ /* Fill the Authentication and Key Management Suite Count field. */ ++ WLAN_SET_FIELD_16(cp2, u2SuiteCount); ++ ucExpendedLen += 2; ++ ++ /* Fill the Length field. */ ++ prWpaIE->ucLength = (UINT_8) ucExpendedLen; ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ ++} /* rsnGenerateWpaNoneIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WPA IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WPA IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUCHAR cp; ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ DEBUGFUNC("rsnGenerateWPAIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ /* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */ ++ /* return; */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((1 /* prCurrentBss->fgIEWPA */ && ++ ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkId == NETWORK_TYPE_P2P_INDEX) && ++ (kalP2PGetTkipCipher(prAdapter->prGlueInfo)))) || ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) { ++#else ++ if ((1 /* prCurrentBss->fgIEWPA */ && ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK)))) { ++#endif ++ if (prP2pSpecificBssInfo->u2WpaIeLen != 0) { ++ kalMemCopy(pucBuffer, prP2pSpecificBssInfo->aucWpaIeBuffer, prP2pSpecificBssInfo->u2WpaIeLen); ++ prMsduInfo->u2FrameLength += prP2pSpecificBssInfo->u2WpaIeLen; ++ return; ++ } ++ ++ /* Construct a WPA IE for association request frame. */ ++ WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA; ++ WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; ++ WPA_IE(pucBuffer)->aucOui[0] = 0x00; ++ WPA_IE(pucBuffer)->aucOui[1] = 0x50; ++ WPA_IE(pucBuffer)->aucOui[2] = 0xF2; ++ WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA; ++ WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, WPA_CIPHER_SUITE_TKIP); ++ } else ++#endif ++ WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, ++ prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedGroupCipher); ++ ++ cp = (PUCHAR) &WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; ++ ++ WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP); ++ } else ++#endif ++ WLAN_SET_FIELD_32(cp, ++ prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedPairwiseCipher); ++ cp += 4; ++ ++ WLAN_SET_FIELD_16(cp, 1); ++ cp += 2; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK); ++ } else ++#endif ++ WLAN_SET_FIELD_32(cp, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedAKMSuite); ++ cp += 4; ++ ++ WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* rsnGenerateWPAIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate RSN IE for ++* associate request frame. ++* ++* \param[in] prMsduInfo The Selected BSS description ++* ++* \retval The append RSN IE length ++* ++* \note ++* Called by: AIS module, P2P module, BOW module Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 u4Entry; ++ PUCHAR cp; ++ /* UINT_8 ucExpendedLen = 0; */ ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("rsnGenerateRSNIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* Todo:: network id */ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ ++ if ( ++#if CFG_ENABLE_WIFI_DIRECT ++ ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkId == NETWORK_TYPE_P2P_INDEX) && (kalP2PGetCcmpCipher(prAdapter->prGlueInfo))) || ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ (eNetworkId == NETWORK_TYPE_BOW_INDEX) || ++#endif ++ (eNetworkId == NETWORK_TYPE_AIS_INDEX /* prCurrentBss->fgIERSN */ && ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK)))) { ++ /* Construct a RSN IE for association request frame. */ ++ RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN; ++ RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED; ++ WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); /* Version */ ++ WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite, ++ prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedGroupCipher); /* Group key suite */ ++ cp = (PUCHAR) &RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; ++ WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); ++ WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedPairwiseCipher); ++ cp += 4; ++ WLAN_SET_FIELD_16(cp, 1); /* AKM suite count */ ++ cp += 2; ++ WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedAKMSuite); /* AKM suite */ ++ cp += 4; ++ WLAN_SET_FIELD_16(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u2RsnSelectedCapInfo);/* Capabilities */ ++#if CFG_SUPPORT_802_11W ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection) { ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) ++ WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); /* Capabilities */ ++ else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) ++ WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); /* Capabilities */ ++ } ++#endif ++ cp += 2; ++ ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX) { ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ if (!prStaRec) { ++ DBGLOG(RSN, TRACE, "rsnGenerateRSNIE: prStaRec is NULL\n"); ++ return; ++ } ++ } ++ ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX && ++ rsnSearchPmkidEntry(prAdapter, prStaRec->aucMacAddr, &u4Entry)) { ++ /* DBGLOG(RSN, TRACE, ("Add Pmk at assoc req\n")); */ ++ /* DBGLOG(RSN, TRACE, ("addr %pM PMKID %pM\n", */ ++ /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arBSSID),*/ ++ /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID))); */ ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].fgPmkidExist) { ++ RSN_IE(pucBuffer)->ucLength = 38; ++ WLAN_SET_FIELD_16(cp, 1); /* PMKID count */ ++ cp += 2; ++ DBGLOG(RSN, TRACE, ++ "BSSID %pM ind=%d\n", prStaRec->aucMacAddr, (UINT_32) u4Entry); ++ DBGLOG(RSN, TRACE, "use PMKID %pM\n", ++ (prAdapter->rWifiVar.rAisSpecificBssInfo. ++ arPmkidCache[u4Entry].rBssidInfo.arPMKID)); ++ kalMemCopy(cp, ++ (PVOID) prAdapter->rWifiVar.rAisSpecificBssInfo. ++ arPmkidCache[u4Entry].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ /* ucExpendedLen = 40; */ ++ } else { ++ WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ ++ /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ ++#if CFG_SUPPORT_802_11W ++ cp += 2; ++ RSN_IE(pucBuffer)->ucLength += 2; ++#endif ++ } ++ } else { ++ WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ ++ /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ ++#if CFG_SUPPORT_802_11W ++ cp += 2; ++ RSN_IE(pucBuffer)->ucLength += 2; ++#endif ++ } ++ ++#if CFG_SUPPORT_802_11W ++ if ((eNetworkId == NETWORK_TYPE_AIS_INDEX) ++ && (kalGetMfpSetting(prAdapter->prGlueInfo) != ++ RSN_AUTH_MFP_DISABLED) /* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */) { ++ WLAN_SET_FIELD_32(cp, RSN_CIPHER_SUITE_AES_128_CMAC); ++ cp += 4; ++ RSN_IE(pucBuffer)->ucLength += 4; ++ } ++#endif ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* rsnGenerateRSNIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the given IE buffer and check if it is WFA IE and return Type and ++* SubType for further process. ++* ++* \param[in] pucBuf Pointer to the buffer of WFA Information Element. ++* \param[out] pucOuiType Pointer to the storage of OUI Type. ++* \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and Version. ++ ++* \retval TRUE Parse IE ok ++* \retval FALSE Parse IE fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion) ++{ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_IE_WFA_T prWfaIE; ++ ++ ASSERT(pucBuf); ++ ASSERT(pucOuiType); ++ ASSERT(pu2SubTypeVersion); ++ prWfaIE = (P_IE_WFA_T) pucBuf; ++ ++ do { ++ if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { ++ break; ++ } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || ++ prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { ++ break; ++ } ++ ++ *pucOuiType = prWfaIE->ucOuiType; ++ WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion); ++ ++ return TRUE; ++ } while (FALSE); ++ ++ return FALSE; ++ ++} /* end of rsnParseCheckForWFAInfoElem() */ ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK ++* ++* \param[in] prAdapter Pointer to Adapter ++* \param[in] prSwRfb Pointer to the rx buffer ++* \param[in] pIE Pointer rthe buffer of Information Element. ++* \param[out] prStatusCode Pointer to the return status code. ++ ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode) ++{ ++ ++ RSN_INFO_T rRsnIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(prIe); ++ ASSERT(pu2StatusCode); ++ ++ *pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; ++ ++ if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) { ++ if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1) ++ || (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) { ++ *pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER; ++ return; ++ } ++ if (rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP) { ++ *pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER; ++ return; ++ } ++ if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1) || (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) { ++ *pu2StatusCode = STATUS_CODE_INVALID_AKMP; ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n"); ++ *pu2StatusCode = WLAN_STATUS_SUCCESS; ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate an authentication event to NDIS. ++* ++* \param[in] u4Flags Authentication event: \n ++* PARAM_AUTH_REQUEST_REAUTH 0x01 \n ++* PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n ++* PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n ++* PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgFlags) ++{ ++ P_PARAM_AUTH_EVENT_T prAuthEvent; ++ ++ DEBUGFUNC("rsnGenMicErrorEvent"); ++ ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: Authentication Event */ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; ++ ++ /* Authentication request */ ++ prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); ++ kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, ++ (PVOID) prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucBSSID, MAC_ADDR_LEN); ++ ++ if (fgFlags == TRUE) ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; ++ else ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); ++ ++} /* rsnGenMicErrorEvent */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle TKIP MIC failures. ++* ++* \param[in] adapter_p Pointer to the adapter object data area. ++* \param[in] prSta Pointer to the STA which occur MIC Error ++* \param[in] fgErrorKeyType type of error key ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType) ++{ ++ /* UINT_32 u4RsnaCurrentMICFailTime; */ ++ /* P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; */ ++ ++ DEBUGFUNC("rsnTkipHandleMICFailure"); ++ ++ ASSERT(prAdapter); ++#if 1 ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ ++ nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, Param_PowerModeCAM, FALSE); ++ ++ /* Generate authentication request event. */ ++ DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); ++#else ++ ASSERT(prSta); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* Record the MIC error occur time. */ ++ GET_CURRENT_SYSTIME(&u4RsnaCurrentMICFailTime); ++ ++ /* Generate authentication request event. */ ++ DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); ++ ++ /* If less than 60 seconds have passed since a previous TKIP MIC failure, ++ disassociate from the AP and wait for 60 seconds before (re)associating ++ with the same AP. */ ++ if (prAisSpecBssInfo->u4RsnaLastMICFailTime != 0 && ++ !CHECK_FOR_TIMEOUT(u4RsnaCurrentMICFailTime, ++ prAisSpecBssInfo->u4RsnaLastMICFailTime, SEC_TO_SYSTIME(TKIP_COUNTERMEASURE_SEC))) { ++ /* If less than 60 seconds expired since last MIC error, we have to ++ block traffic. */ ++ ++ DBGLOG(RSN, INFO, "Start blocking traffic!\n"); ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ ++ secFsmEventStartCounterMeasure(prAdapter, prSta); ++ } else { ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ DBGLOG(RSN, INFO, "First TKIP MIC error!\n"); ++ } ++ ++ COPY_SYSTIME(prAisSpecBssInfo->u4RsnaLastMICFailTime, u4RsnaCurrentMICFailTime); ++#endif ++} /* rsnTkipHandleMICFailure */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to select a list of BSSID from ++* the scan results for PMKID candidate list. ++* ++* \param[in] prBssDesc the BSS Desc at scan result list ++* \param[out] pu4CandidateCount Pointer to the number of selected candidates. ++* It is set to zero if no BSSID matches our requirement. ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("rsnSelectPmkidCandidateList"); ++ ++ ASSERT(prBssDesc); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ /* Search a BSS with the same SSID from the given BSS description set. */ ++ /* DBGLOG(RSN, TRACE, ("Check scan result [%pM]\n", */ ++ /* prBssDesc->aucBSSID)); */ ++ ++ if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ DBGLOG(RSN, TRACE, "-- SSID not matched\n"); ++ return; ++ } ++#if 0 ++ if ((prBssDesc->u2BSSBasicRateSet & ++ ~(rPhyAttributes[prAisBssInfo->ePhyType].u2SupportedRateSet)) || prBssDesc->fgIsUnknownBssBasicRate) { ++ DBGLOG(RSN, TRACE, "-- Rate set not matched\n"); ++ return; ++ } ++ ++ if (/* prBssDesc->u4RsnSelectedPairwiseCipher != prAisBssInfo->u4RsnSelectedPairwiseCipher || */ ++ prBssDesc->u4RsnSelectedGroupCipher != prAisBssInfo->u4RsnSelectedGroupCipher /*|| ++ prBssDesc->u4RsnSelectedAKMSuite != prAisBssInfo->u4RsnSelectedAKMSuite */) { ++ DBGLOG(RSN, TRACE, "-- Encrypt status not matched for PMKID\n"); ++ return; ++ } ++#endif ++ ++ rsnUpdatePmkidCandidateList(prAdapter, prBssDesc); ++ ++} /* rsnSelectPmkidCandidateList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to select a list of BSSID from ++* the scan results for PMKID candidate list. ++* ++* \param[in] prBssDesc the BSS DESC at scan result list ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ UINT_32 i; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("rsnUpdatePmkidCandidateList"); ++ ++ ASSERT(prBssDesc); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ DBGLOG(RSN, TRACE, "-- SSID not matched\n"); ++ return; ++ } ++ ++ for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) { ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)) ++ return; ++ } ++ ++ /* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16), ++ then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache */ ++ if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE) ++ prAisSpecBssInfo->u4PmkidCandicateCount--; ++ ++ i = prAisSpecBssInfo->u4PmkidCandicateCount; ++ ++ COPY_MAC_ADDR((PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, (PVOID) prBssDesc->aucBSSID); ++ ++ if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) { ++ prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1; ++ DBGLOG(RSN, TRACE, "Add %pM with pre-auth to candidate list\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ } else { ++ prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0; ++ DBGLOG(RSN, TRACE, "Add %pM without pre-auth to candidate list\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ } ++ ++ prAisSpecBssInfo->u4PmkidCandicateCount++; ++ ++} /* rsnUpdatePmkidCandidateList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search the desired entry in ++* PMKID cache according to the BSSID ++* ++* \param[in] pucBssid Pointer to the BSSID ++* \param[out] pu4EntryIndex Pointer to place the found entry index ++* ++* \retval TRUE, if found one entry for specified BSSID ++* \retval FALSE, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex) ++{ ++ UINT_32 i; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("rsnSearchPmkidEntry"); ++ ++ ASSERT(pucBssid); ++ ASSERT(pu4EntryIndex); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE) ++ return FALSE; ++ ++ ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE); ++ ++ /* Search for desired BSSID */ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { ++ if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, pucBssid, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ /* If desired BSSID is found, then set the PMKID */ ++ if (i < prAisSpecBssInfo->u4PmkidCacheCount) { ++ *pu4EntryIndex = i; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} /* rsnSearchPmkidEntry */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check if there is difference ++* between PMKID candicate list and PMKID cache. If there ++* is new candicate that no cache entry is available, then ++* add a new entry for the new candicate in the PMKID cache ++* and set the PMKID indication flag to TRUE. ++* ++* \retval TRUE, if new member in the PMKID candicate list ++* \retval FALSe, if no new member in the PMKID candicate list ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ UINT_32 i; /* Index for PMKID candicate */ ++ UINT_32 j; /* Indix for PMKID cache */ ++ BOOLEAN status = FALSE; ++ ++ DEBUGFUNC("rsnCheckPmkidCandicate"); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* Check for each candicate */ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) { ++ for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) { ++ if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN)) { ++ /* DBGLOG(RSN, TRACE, ("%pM at PMKID cache!!\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); */ ++ break; ++ } ++ } ++ ++ /* No entry found in PMKID cache for the candicate, add new one */ ++ if (j == prAisSpecBssInfo->u4PmkidCacheCount ++ && prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) { ++ DBGLOG(RSN, TRACE, ++ "Add %pM to PMKID cache!!\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ kalMemCopy((PVOID) prAisSpecBssInfo-> ++ arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.arBSSID, ++ (PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN); ++ prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].fgPmkidExist = FALSE; ++ prAisSpecBssInfo->u4PmkidCacheCount++; ++ ++ status = TRUE; ++ } ++ } ++ ++ return status; ++} /* rsnCheckPmkidCandicate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to wait a duration to indicate the pre-auth AP candicate ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) ++{ ++ DBGLOG(RSN, EVENT, "Security - Time to indicate the PMKID cand.\n"); ++ ++ /* If the authentication mode is WPA2 and indication PMKID flag ++ is available, then we indicate the PMKID candidate list to NDIS and ++ clear the flag, indicatePMKID */ ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED && ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnGeneratePmkidIndication(prAdapter); ++ } ++ ++} /* end of rsnIndicatePmkidCand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check the BSS Desc at scan result ++* with pre-auth cap at wpa2 mode. If there ++* is candicate that no cache entry is available, then ++* add a new entry for the new candicate in the PMKID cache ++* and set the PMKID indication flag to TRUE. ++* ++* \param[in] prBss The BSS Desc at scan result ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("rsnCheckPmkidCandicate"); ++ ++ ASSERT(prBss); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && ++ (prConnSettings->eAuthMode == AUTH_MODE_WPA2)) { ++ rsnSelectPmkidCandidateList(prAdapter, prBss); ++ ++ /* Set indication flag of PMKID to TRUE, and then connHandleNetworkConnection() ++ will indicate this later */ ++ if (rsnCheckPmkidCandicate(prAdapter)) { ++ DBGLOG(RSN, TRACE, "Prepare a timer to indicate candidate PMKID Candidate\n"); ++ cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate an PMKID candidate list ++* indication to NDIS. ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] u4Flags PMKID candidate list event: ++* PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter) ++{ ++ P_PARAM_STATUS_INDICATION_T prStatusEvent; ++ P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ UINT_8 i, j = 0, count = 0; ++ UINT_32 u4LenOfUsedBuffer; ++ ++ DEBUGFUNC("rsnGeneratePmkidIndication"); ++ ++ ASSERT(prAdapter); ++ ++ prStatusEvent = (P_PARAM_STATUS_INDICATION_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: PMKID Candidatelist Event */ ++ prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; ++ ASSERT(prStatusEvent); ++ ++ prPmkidEvent = (P_PARAM_PMKID_CANDIDATE_LIST_T) (&prStatusEvent->eStatusType + 1); ++ ASSERT(prPmkidEvent); ++ ++ prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prAisSpecificBssInfo); ++ ++ for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) { ++ for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) { ++ if (EQUAL_MAC_ADDR(prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) && ++ (prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == TRUE)) { ++ break; ++ } ++ } ++ if (count >= CFG_MAX_PMKID_CACHE) ++ break; ++ ++ if (j == prAisSpecificBssInfo->u4PmkidCacheCount) { ++ kalMemCopy((PVOID) prPmkidEvent->arCandidateList[count].arBSSID, ++ (PVOID) prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, PARAM_MAC_ADDR_LEN); ++ prPmkidEvent->arCandidateList[count].u4Flags = ++ prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags; ++ DBGLOG(RSN, TRACE, "%pM %d\n", (prPmkidEvent->arCandidateList[count].arBSSID), ++ (UINT_32) prPmkidEvent->arCandidateList[count].u4Flags); ++ count++; ++ } ++ } ++ ++ /* PMKID Candidate List */ ++ prPmkidEvent->u4Version = 1; ++ prPmkidEvent->u4NumCandidates = count; ++ DBGLOG(RSN, TRACE, "rsnGeneratePmkidIndication #%d\n", (UINT_32) prPmkidEvent->u4NumCandidates); ++ u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(UINT_32)) + ++ (count * sizeof(PARAM_PMKID_CANDIDATE_T)); ++ /* dumpMemory8((PUINT_8)prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); */ ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); ++ ++} /* rsnGeneratePmkidIndication */ ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WSC IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WSC IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 221 :0xDD */ ++ if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE, ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen; ++ } ++ ++} ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the Bip Key installed or not ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ if (prStaRec && prStaRec->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX) ++ return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to check the Sa query timeout. ++* ++* ++* \note ++* Called by: AIS module, Handle by Sa Quert timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ UINT_32 now; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ GET_CURRENT_SYSTIME(&now); ++ ++ if (CHECK_FOR_TIMEOUT(now, prBssSpecInfo->u4SaQueryStart, TU_TO_MSEC(1000))) { ++ LOG_FUNC("association SA Query timed out\n"); ++ ++ prBssSpecInfo->ucSaQueryTimedOut = 1; ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ prBssSpecInfo->pucSaQueryTransId = NULL; ++ prBssSpecInfo->u4SaQueryCount = 0; ++ cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); ++ /* Re-connect */ ++ DBGLOG(RSN, TRACE, "DisBy11w\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to start the 802.11w sa query timer. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_SA_QUERY_FRAME prTxFrame; ++ UINT_16 u2PayloadLen; ++ PUINT_8 pucTmp = NULL; ++ UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ASSERT(prBssInfo); ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ LOG_FUNC("MFP: Start Sa Query\n"); ++ ++ if (prBssSpecInfo->u4SaQueryCount > 0 && rsnCheckSaQueryTimeout(prAdapter)) { ++ LOG_FUNC("MFP: u4SaQueryCount count =%d\n", prBssSpecInfo->u4SaQueryCount); ++ return; ++ } ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_SA_QUERY_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; ++ prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; ++ ++ if (prBssSpecInfo->u4SaQueryCount == 0) ++ GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart); ++ ++ if (prBssSpecInfo->u4SaQueryCount) { ++ pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); ++ if (!pucTmp) { ++ DBGLOG(RSN, ERROR, "MFP: Fail to alloc tmp buffer for backup sa query id\n"); ++ return; ++ } ++ kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ } ++ ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ ++ ucTransId[0] = (UINT_8) (kalRandomNumber() & 0xFF); ++ ucTransId[1] = (UINT_8) (kalRandomNumber() & 0xFF); ++ ++ kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ prBssSpecInfo->u4SaQueryCount++; ++ ++ prBssSpecInfo->pucSaQueryTransId = ++ kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); ++ if (!prBssSpecInfo->pucSaQueryTransId) { ++ DBGLOG(RSN, ERROR, "MFP: Fail to alloc buffer for sa query id list\n"); ++ return; ++ } ++ ++ if (pucTmp) { ++ kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp, ++ (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); ++ kalMemCopy(&prBssSpecInfo->pucSaQueryTransId ++ [(prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN], ucTransId, ++ ACTION_SA_QUERY_TR_ID_LEN); ++ kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); ++ } else { ++ kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ } ++ ++ u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ DBGLOG(RSN, TRACE, ++ "Set SA Query timer %d (%d sec)\n", prBssSpecInfo->u4SaQueryCount, prBssInfo->u2ObssScanInterval); ++ ++ cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, TU_TO_MSEC(201)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to start the 802.11w sa query. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStartSaQuery(IN P_ADAPTER_T prAdapter) ++{ ++ rsnStartSaQueryTimer(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to stop the 802.11w sa query. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStopSaQuery(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ prBssSpecInfo->pucSaQueryTransId = NULL; ++ prBssSpecInfo->u4SaQueryCount = 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w sa query action frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; ++ UINT_16 u2PayloadLen; ++ P_STA_RECORD_T prStaRec; ++ P_ACTION_SA_QUERY_FRAME prTxFrame; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ASSERT(prBssInfo); ++ ++ prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; ++ if (!prRxFrame) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Request from %pM\n", prStaRec->aucMacAddr); ++ ++ DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Ignore SA Query Request from unassociated STA %pM\n", ++ prStaRec->aucMacAddr); ++ return; ++ } ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Sending SA Query Response to %pM\n", prStaRec->aucMacAddr); ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_SA_QUERY_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ /* SA Query always with protected */ ++ prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; ++ prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; ++ ++ kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w sa query action frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ P_ACTION_SA_QUERY_FRAME prRxFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_32 i; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Too short SA Query Action frame (len=%u)\n", ++ prSwRfb->u2PacketLen); ++ return; ++ } ++ ++ if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { ++ rsnSaQueryRequest(prAdapter, prSwRfb); ++ return; ++ } ++ ++ if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Unexpected SA Query " "Action %d\n", prRxFrame->ucAction); ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Response from %pM\n", prStaRec->aucMacAddr); ++ ++ DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ /* MLME-SAQuery.confirm */ ++ ++ for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) { ++ if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId + ++ i * ACTION_SA_QUERY_TR_ID_LEN, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) ++ break; ++ } ++ ++ if (i >= prBssSpecInfo->u4SaQueryCount) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: No matching SA Query " "transaction identifier found\n"); ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "Reply to pending SA Query received\n"); ++ ++ rsnStopSaQuery(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w mgmt frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype) ++{ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ BOOLEAN fgUnicast = TRUE; ++ BOOLEAN fgRobustAction = FALSE; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { ++ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prAssocReqFrame->aucDestAddr[0] & BIT(0)) ++ fgUnicast = FALSE; ++ ++ LOG_FUNC("QM RX MGT: rsnCheckRxMgmt = %d 0x%x %d ucSubtype=%x\n", fgUnicast, prHifRxHdr->ucReserved, ++ (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC), ucSubtype); ++ ++ if (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC) { ++ /* "Dropped unprotected Robust Action frame from an MFP STA" */ ++ /* exclude Public Action */ ++ if (ucSubtype == 13 /* 0x1011: MAC_FRAME_ACTION */) { ++ UINT_8 ucAction = *prSwRfb->pucRecvBuff; ++ ++ if (ucAction != CATEGORY_PUBLIC_ACTION && ucAction != CATEGORY_HT_ACTION) { ++#if DBG && CFG_RX_PKTS_DUMP ++ LOG_FUNC("QM RX MGT: UnProtected Robust Action frame = %d\n", ucAction); ++#endif ++ fgRobustAction = TRUE; ++ return TRUE; ++ } ++ } ++ if (fgUnicast && ((ucSubtype == 10 /* 0x1010: MAC_FRAME_DISASSOC */) ++ || (ucSubtype == 12 /* 0x1100: MAC_FRAME_DEAUTH */))) { ++ LOG_FUNC("QM RX MGT: rsnStartSaQuery\n"); ++ /* MFP test plan 5.3.3.5 */ ++ rsnStartSaQuery(prAdapter); ++ return TRUE; ++ } ++ } ++#if 0 ++ else { ++ if (fgUnicast && ((ucSubtype == MAC_FRAME_DISASSOC) || (ucSubtype == MAC_FRAME_DEAUTH))) { ++ /* This done by function handler */ ++ /* kalIndicateStatusAndComplete(prAdapter->prGlueInfo, */ ++ /* WLAN_STATUS_MEDIA_DISCONNECT, */ ++ /* NULL, */ ++ /* 0); */ ++ } ++ } ++#endif ++ } ++ return FALSE; ++} ++#endif ++ ++#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE ++static BOOLEAN rsnCheckWpaRsnInfo(P_BSS_INFO_T prBss, P_RSN_INFO_T prWpaRsnInfo) ++{ ++ UINT_32 i = 0; ++ ++ if (prWpaRsnInfo->u4GroupKeyCipherSuite != prBss->u4RsnSelectedGroupCipher) { ++ DBGLOG(RSN, INFO, "GroupCipherSuite change, old=0x%04x, new=0x%04x\n", ++ prBss->u4RsnSelectedGroupCipher, prWpaRsnInfo->u4GroupKeyCipherSuite); ++ return TRUE; ++ } ++ for (; i < prWpaRsnInfo->u4AuthKeyMgtSuiteCount; i++) ++ if (prBss->u4RsnSelectedAKMSuite == prWpaRsnInfo->au4AuthKeyMgtSuite[i]) ++ break; ++ if (i == prWpaRsnInfo->u4AuthKeyMgtSuiteCount) { ++ DBGLOG(RSN, INFO, "KeyMgmt change, not find 0x%04x in new beacon\n", prBss->u4RsnSelectedAKMSuite); ++ return TRUE; ++ } ++ ++ for (i = 0; i < prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) ++ if (prBss->u4RsnSelectedPairwiseCipher == prWpaRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ break; ++ if (i == prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount) { ++ DBGLOG(RSN, INFO, "Pairwise Cipher change, not find 0x%04x in new beacon\n", ++ prBss->u4RsnSelectedPairwiseCipher); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc) ++{ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode = prAdapter->rWifiVar.rConnSettings.eAuthMode; ++ ++ switch (eAuthMode) { ++ case AUTH_MODE_OPEN: /* original is open system */ ++ if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) && !prAdapter->prGlueInfo->rWpaInfo.fgPrivacyInvoke) { ++ DBGLOG(RSN, INFO, "security change, open->privacy\n"); ++ return TRUE; ++ } ++ break; ++ case AUTH_MODE_SHARED: /* original is WEP */ ++ case AUTH_MODE_AUTO_SWITCH: ++ if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) == 0) { ++ DBGLOG(RSN, INFO, "security change, WEP->open\n"); ++ return TRUE; ++ } else if (prBssDesc->fgIERSN || prBssDesc->fgIEWPA) { ++ DBGLOG(RSN, INFO, "security change, WEP->WPA/WPA2\n"); ++ return TRUE; ++ } ++ break; ++ case AUTH_MODE_WPA: /*original is WPA */ ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA_NONE: ++ if (prBssDesc->fgIEWPA) ++ return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rWPAInfo); ++ DBGLOG(RSN, INFO, "security change, WPA->%s\n", ++ prBssDesc->fgIERSN ? "WPA2" : ++ (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); ++ return TRUE; ++ case AUTH_MODE_WPA2: /*original is WPA2 */ ++ case AUTH_MODE_WPA2_PSK: ++ if (prBssDesc->fgIERSN) ++ return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rRSNInfo); ++ DBGLOG(RSN, INFO, "security change, WPA2->%s\n", ++ prBssDesc->fgIEWPA ? "WPA" : ++ (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); ++ return TRUE; ++ default: ++ DBGLOG(RSN, WARN, "unknowned eAuthMode=%d\n", eAuthMode); ++ break; ++ } ++ /*DBGLOG(RSN, INFO, ("rsnCheckSecurityModeChanged, eAuthMode=%d, u2CapInfo=0x%02x, fgIEWPA=%d, fgIERSN=%d\n", ++ eAuthMode, prBssDesc->u2CapInfo, prBssDesc->fgIEWPA, prBssDesc->fgIERSN)); */ ++ return FALSE; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c +new file mode 100644 +index 000000000000..596ede60d788 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c +@@ -0,0 +1,1788 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/saa_fsm.c#2 ++*/ ++ ++/*! \file "saa_fsm.c" ++ \brief This file defines the FSM for SAA MODULE. ++ ++ This file defines the FSM for SAA MODULE. ++*/ ++ ++/* ++** Log: saa_fsm.c ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT ++ * for REASSOCIATED cases as an explicit trigger for Android framework ++ * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. ++ * 2. (Android only) when reassociation-and-non-roaming cases happened, ++ * indicate an extra DISCONNECT indication to Android Wi-Fi framework ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * Add debug message about 40MHz bandwidth allowed ++ * ++ * 05 12 2011 cp.wu ++ * [WCXRP00000720] [MT6620 Wi-Fi][Driver] Do not do any further operation in case STA-REC ++ * has been invalidated before SAA-FSM starts to roll ++ * check for valid STA-REC before SAA-FSM starts to roll. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 31 2011 puff.wen ++ * NULL ++ * . ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix compile error of after Station Type Macro modification. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete ++ * and might leads to BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. ++ * Update saa_fsm for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * Add support for P2P join event start. ++ * ++ * 07 12 2010 cp.wu ++ * ++ * SAA will take a record for tracking request sequence number. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with main branch for resetting to state 1 when associating with another AP ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error when enable WiFi Direct function. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * ++ * * * Add Connection Policy - Any and Rx Burst Deauth Support for WHQL ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support of Driver STA_RECORD_T activation ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 12 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix compile warning due to declared but not used ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Refine Debug Label ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comment ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the function ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugAAState[AA_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("AA_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH1"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH2"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH3"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH4"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_ASSOC1"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_ASSOC2"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH2"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH4"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_ASSOC2"), ++ (PUINT_8) DISP_STRING("AA_STATE_RESOURCE") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of SAA Module. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] eNextState The value of Next State ++* @param[in] prRetainedSwRfb Pointer to the retained SW_RFB_T for JOIN Success ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++saaFsmSteps(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb) ++{ ++ ENUM_AA_STATE_T ePreviousState; ++ BOOLEAN fgIsTransition; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ return; ++ } ++ ++ do { ++ ++#if DBG ++ DBGLOG(SAA, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugAAState[prStaRec->eAuthAssocState], apucDebugAAState[eNextState]); ++#else ++ DBGLOG(SAA, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_SAA_IDX, prStaRec->eAuthAssocState, eNextState); ++#endif ++ ePreviousState = prStaRec->eAuthAssocState; ++ ++ /* NOTE(Kevin): This is the only place to change the eAuthAssocState(except initial) */ ++ prStaRec->eAuthAssocState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ switch (prStaRec->eAuthAssocState) { ++ case AA_STATE_IDLE: ++ if (ePreviousState != prStaRec->eAuthAssocState) { /* Only trigger this event once */ ++ ++ if (prRetainedSwRfb) { ++ if (saaFsmSendEventJoinComplete(prAdapter, ++ WLAN_STATUS_SUCCESS, ++ prStaRec, ++ prRetainedSwRfb) == WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ } else { ++ eNextState = AA_STATE_RESOURCE; ++ fgIsTransition = TRUE; ++ } ++ } else { ++ if (saaFsmSendEventJoinComplete(prAdapter, ++ WLAN_STATUS_FAILURE, ++ prStaRec, ++ NULL) == WLAN_STATUS_RESOURCES) { ++ eNextState = AA_STATE_RESOURCE; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ } ++ ++ /* Free allocated TCM memory */ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH1: ++ { ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++ /* Update Station Record - Class 1 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++#if !CFG_SUPPORT_AAA ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) { ++#else ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, ++ prStaRec->ucNetTypeIndex, ++ NULL, ++ AUTH_TRANSACTION_SEQ_1, ++ STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { ++#endif /* CFG_SUPPORT_AAA */ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ } ++ break; ++ ++ case SAA_STATE_WAIT_AUTH2: ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ { ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++#if !CFG_SUPPORT_AAA ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) { ++#else ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, ++ prStaRec->ucNetTypeIndex, ++ NULL, ++ AUTH_TRANSACTION_SEQ_3, ++ STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { ++#endif /* CFG_SUPPORT_AAA */ ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ } ++ break; ++ ++ case SAA_STATE_WAIT_AUTH4: ++ break; ++ ++ case SAA_STATE_SEND_ASSOC1: ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++ if (assocSendReAssocReqFrame(prAdapter, prStaRec) != WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_ASSOCIATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ ++ break; ++ ++ case SAA_STATE_WAIT_ASSOC2: ++ break; ++ ++ case AA_STATE_RESOURCE: ++ /* TODO(Kevin) Can setup a timer and send message later */ ++ break; ++ ++ default: ++ DBGLOG(SAA, ERROR, "Unknown AA STATE\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of saaFsmSteps() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Event to AIS/BOW/P2P ++* ++* @param[in] rJoinStatus To indicate JOIN success or failure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prSwRfb Pointer to the SW_RFB_T ++ ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, ++ IN WLAN_STATUS rJoinStatus, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ ++ /* Store limitation about 40Mhz bandwidth capability during association */ ++ if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if (rJoinStatus == WLAN_STATUS_SUCCESS) ++ prBssInfo->fg40mBwAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { ++ /* @TODO: BOW handler */ ++ ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ else { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++} /* end of saaFsmSendEventJoinComplete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Start Event to SAA FSM. ++* ++* @param[in] prMsgHdr Message of Join Request for a particular STA. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_FSM_START_T prSaaFsmStartMsg; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prSaaFsmStartMsg = (P_MSG_SAA_FSM_START_T) prMsgHdr; ++ prStaRec = prSaaFsmStartMsg->prStaRec; ++ ++ if ((!prStaRec) || (prStaRec->fgIsInUse == FALSE)) { ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM.\n"); ++ ++ /* record sequence number of request message */ ++ prStaRec->ucAuthAssocReqSeqNum = prSaaFsmStartMsg->ucSeqNum; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ /* 4 <1> Validation of SAA Start Event */ ++ if (!IS_AP_STA(prStaRec)) { ++ ++ DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); ++ ++ /* Ignore the return value because don't care the prSwRfb */ ++ saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, prStaRec, NULL); ++ ++ return; ++ } ++ /* 4 <2> The previous JOIN process is not completed ? */ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ } ++ /* 4 <3> Reset Status Code and Time */ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); ++ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++#if CFG_PRIVACY_MIGRATION ++ /* 4 <4> Init the sec fsm */ ++ secFsmInit(prAdapter, prStaRec); ++#endif ++ ++ /* 4 <5> Reset the STA STATE */ ++ /* Update Station Record - Class 1 Flag */ ++ /* NOTE(Kevin): Moved to AIS FSM for Reconnect issue - ++ * We won't deactivate the same STA_RECORD_T and then activate it again for the ++ * case of reconnection. ++ */ ++ /* cnmStaRecChangeState(prStaRec, STA_STATE_1); */ ++ ++ /* 4 <6> Decide if this BSS 20/40M bandwidth is allowed */ ++ if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) ++ && (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ prBssInfo->fgAssoc40mBwAllowed = cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex); ++ } else { ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ DBGLOG(RLM, INFO, "STA 40mAllowed=%d\n", prBssInfo->fgAssoc40mBwAllowed); ++ } ++ /* 4 <7> Trigger SAA FSM */ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); ++ else if (prStaRec->ucStaState == STA_STATE_2 || prStaRec->ucStaState == STA_STATE_3) ++ saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_ASSOC1, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventStart() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(Auth1/Auth3/AssocReq) Event of SAA FSM. ++* ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ ENUM_AA_STATE_T eNextState; ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ DBGLOG(SAA, INFO, "EVENT-TX DONE: Status %d, Invalid StaRec\n", rTxDoneStatus); ++ return WLAN_STATUS_INVALID_PACKET; ++ } ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, INFO, "EVENT-TX DONE: Status: %d, eAuthAssocState: %d , SeqNO: %d ", ++ rTxDoneStatus, prStaRec->eAuthAssocState, ++ prMsduInfo->ucTxSeqNum); ++ ++ eNextState = prStaRec->eAuthAssocState; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ { ++ /* Strictly check the outgoing frame is matched with current AA STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_AUTH2; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); ++ } ++ ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ { ++ /* Strictly check the outgoing frame is matched with current JOIN STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_AUTH4; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); ++ } ++ ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_ASSOC1: ++ { ++ /* Strictly check the outgoing frame is matched with current SAA STATE */ ++ if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_ASSOC2; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &(prStaRec->rTxReqDoneOrRxRespTimer), ++ TU_TO_MSEC(DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU)); ++ } ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of saaFsmRunEventTxDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Tx Request Timeout Event to SAA FSM. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ++ DBGLOG(SAA, LOUD, "EVENT-TIMER: TX REQ TIMEOUT, Current Time = %u\n", kalGetTimeTick()); ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ case SAA_STATE_SEND_AUTH3: ++ case SAA_STATE_SEND_ASSOC1: ++ saaFsmSteps(prAdapter, prStaRec, prStaRec->eAuthAssocState, (P_SW_RFB_T) NULL); ++ break; ++ ++ default: ++ return; ++ } ++ ++} /* end of saaFsmRunEventTxReqTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Rx Response Timeout Event to SAA FSM. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ENUM_AA_STATE_T eNextState; ++ ++ DBGLOG(SAA, LOUD, "EVENT-TIMER: RX RESP TIMEOUT, Current Time = %u\n", kalGetTimeTick()); ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ++ eNextState = prStaRec->eAuthAssocState; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_WAIT_AUTH2: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_AUTH1; ++ break; ++ ++ case SAA_STATE_WAIT_AUTH4: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_AUTH3; ++ break; ++ ++ case SAA_STATE_WAIT_ASSOC2: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ if (eNextState != prStaRec->eAuthAssocState) ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventRxRespTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Auth Response Frame and then ++* trigger SAA FSM. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2StatusCode; ++ ENUM_AA_STATE_T eNextState; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if (!prStaRec) { ++ /* Peter: we can handle the packet without station record */ ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ if (!IS_AP_STA(prStaRec)) ++ return; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ case SAA_STATE_WAIT_AUTH2: ++ /* Check if the incoming frame is what we are waiting for */ ++ if (authCheckRxAuthFrameStatus(prAdapter, ++ prSwRfb, AUTH_TRANSACTION_SEQ_2, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); ++ ++ if (prStaRec->ucAuthAlgNum == (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY) { ++ ++ eNextState = SAA_STATE_SEND_AUTH3; ++ } else { ++ /* Update Station Record - Class 2 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ } ++ } else { ++ DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ ++ eNextState = AA_STATE_IDLE; ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ case SAA_STATE_WAIT_AUTH4: ++ /* Check if the incoming frame is what we are waiting for */ ++ if (authCheckRxAuthFrameStatus(prAdapter, ++ prSwRfb, AUTH_TRANSACTION_SEQ_4, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); /* Add for 802.11r handling */ ++ ++ /* Update Station Record - Class 2 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ } else { ++ DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ ++ eNextState = AA_STATE_IDLE; ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++} /* end of saaFsmRunEventRxAuth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx (Re)Association Response Frame and then ++* trigger SAA FSM. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS if the status code was not success ++* @retval WLAN_STATUS_BUFFER_RETAINED if the status code was success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2StatusCode; ++ ENUM_AA_STATE_T eNextState; ++ P_SW_RFB_T prRetainedSwRfb = (P_SW_RFB_T) NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if (!prStaRec) { ++ ASSERT(0); ++ return rStatus; ++ } ++ ++ if (!IS_AP_STA(prStaRec)) ++ return rStatus; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_ASSOC1: ++ case SAA_STATE_WAIT_ASSOC2: ++ /* TRUE if the incoming frame is what we are waiting for */ ++ if (assocCheckRxReAssocRspFrameStatus(prAdapter, prSwRfb, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ /* Update Station Record - Class 3 Flag */ ++ /* NOTE(Kevin): Moved to AIS FSM for roaming issue - ++ * We should deactivate the STA_RECORD_T of previous AP before ++ * activate new one in Driver. ++ */ ++ /* cnmStaRecChangeState(prStaRec, STA_STATE_3); */ ++ ++ prStaRec->ucJoinFailureCount = 0; /* Clear history. */ ++ ++ prRetainedSwRfb = prSwRfb; ++ rStatus = WLAN_STATUS_PENDING; ++ } else { ++ DBGLOG(SAA, INFO, "Assoc Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ eNextState = AA_STATE_IDLE; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, prRetainedSwRfb); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return rStatus; ++ ++} /* end of saaFsmRunEventRxAssoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Deauth Frame. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain deauthentication frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ DBGLOG(SAA, INFO, "Rx Deauth frame from BSSID=[ %pM ].\n", prDeauthFrame->aucBSSID); ++ ++ do { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ if (!IS_AP_STA(prStaRec)) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prStaRec->ucStaState <= STA_STATE_1) ++ break; ++ ++ /* Check if this is the AP we are associated or associating with */ ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ ++ DBGLOG(SAA, INFO, "Deauth reason = %d\n", prStaRec->u2ReasonCode); ++ ++ if (STA_STATE_2 <= prStaRec->ucStaState) { ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ ++ /* NOTE(Kevin): Change state immediately to avoid starvation of ++ * MSG buffer because of too many deauth frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ prAisAbortMsg = ++ (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) ++ break; ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; ++ prAisAbortMsg->ucReasonOfDisconnect = ++ DISCONNECT_REASON_CODE_DEAUTHENTICATED; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, ++ (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ } else { ++ ++ /* TODO(Kevin): Joining Abort */ ++ } ++ prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; ++ ++ } ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ /* TODO(Kevin) */ ++ p2pFsmRunEventRxDeauthentication(prAdapter, prStaRec, prSwRfb); ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventRxDeAuth(prAdapter, prStaRec, prSwRfb); ++#endif ++ else ++ ASSERT(0); ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of saaFsmRunEventRxDeauth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Disassociation Frame. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain disassociation frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ DBGLOG(SAA, INFO, "Rx Disassoc frame from BSSID=[ %pM ].\n", (prDisassocFrame->aucBSSID)); ++ ++ do { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ if (!IS_AP_STA(prStaRec)) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prStaRec->ucStaState <= STA_STATE_1) ++ break; ++ ++ /* Check if this is the AP we are associated or associating with */ ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ ++ DBGLOG(SAA, INFO, "Disassoc reason = %d\n", prStaRec->u2ReasonCode); ++ ++ if (STA_STATE_3 <= prStaRec->ucStaState) { ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ /* NOTE(Chaozhong): Change state immediately to avoid starvation of ++ * MSG buffer because of too many disassoc frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ prAisAbortMsg = ++ (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) ++ break; ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; ++ prAisAbortMsg->ucReasonOfDisconnect = ++ DISCONNECT_REASON_CODE_DISASSOCIATED; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, ++ (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ } else { ++ ++ /* TODO(Kevin): Joining Abort */ ++ } ++ prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; ++ ++ } ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ /* TODO(Kevin) */ ++ p2pFsmRunEventRxDisassociation(prAdapter, prStaRec, prSwRfb); ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) { ++ /* Do nothing */ ++ /* TODO(Kevin) */ ++ } ++#endif ++ else ++ ASSERT(0); ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of saaFsmRunEventRxDisassoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Abort Event to SAA FSM. ++* ++* @param[in] prMsgHdr Message of Abort Request for a particular STA. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_FSM_ABORT_T prSaaFsmAbortMsg; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prMsgHdr); ++ ++ prSaaFsmAbortMsg = (P_MSG_SAA_FSM_ABORT_T) prMsgHdr; ++ prStaRec = prSaaFsmAbortMsg->prStaRec; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Stop SAA FSM.\n"); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel JOIN relative Timer */ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++#if DBG ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %s.\n", ++ apucDebugAAState[prStaRec->eAuthAssocState]); ++#else ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %d.\n", prStaRec->eAuthAssocState); ++#endif ++ } ++#if 0 ++ /* For the Auth/Assoc State to IDLE */ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++#else ++ /* Free this StaRec */ ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++#endif ++ ++} /* end of saaFsmRunEventAbort() */ ++ ++/* TODO(Kevin): following code will be modified and move to AIS FSM */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send Join Timeout Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventJoinTimeOut"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); ++ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ ++ /* We have renew this Sta Record when in JOIN_STATE_INIT */ ++ ASSERT(prStaRec); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel other JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ /* Restore original setting from current BSS_INFO_T */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++ /* Pull back to IDLE */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ return WLAN_STATUS_FAILURE; ++ ++} /* end of joinFsmRunEventJoinTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from Peer BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ DEBUGFUNC("joinAdoptParametersFromPeerBss"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ ++ /* 4 <1> Adopt Peer BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssDesc->ePhyType; ++ ++ DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", ++ prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); ++ ++ /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); ++ ++ prJoinInfo->fgIsParameterAdopted = TRUE; ++ ++} /* end of joinAdoptParametersFromPeerBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from current associated BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) ++{ ++ /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ prBssInfo = &prAdapter->rBssInfo; ++ ++ /* 4 <1> Adopt current BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssInfo->ePhyType; ++ ++ /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); ++} /* end of joinAdoptParametersFromCurrentBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will update all the SW variables and HW MCR registers after ++* the association with target BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinComplete(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ P_PEER_BSS_INFO_T prPeerBssInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_802_11D ++ P_IE_COUNTRY_T prIECountry; ++#endif ++ ++ DEBUGFUNC("joinComplete"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ prPeerBssInfo = &prAdapter->rPeerBssInfo; ++ prBssInfo = &prAdapter->rBssInfo; ++ prConnSettings = &prAdapter->rConnSettings; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ ++ /* Remove previous AP's Connection Flags if have */ ++ scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); ++ ++ prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ ++ ++ if (prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't ++ * broadcast SSID on its Beacon Frame. ++ */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); ++ ++ if (prBssDesc->ucSSIDLen) ++ prBssDesc->fgIsHiddenSSID = FALSE; ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++ DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); ++ } ++/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ ++ /* 4 <2.A> PHY Type */ ++ prBssInfo->ePhyType = prBssDesc->ePhyType; ++ ++ /* 4 <2.B> BSS Type */ ++ prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ /* 4 <2.C> BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); ++ ++ /* 4 <2.D> SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ /* 4 <2.E> Channel / Band information. */ ++ prBssInfo->eBand = prBssDesc->eBand; ++ prBssInfo->ucChnl = prBssDesc->ucChannelNum; ++ ++ /* 4 <2.F> RSN/WPA information. */ ++ secFsmRunEventStart(prAdapter); ++ prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; ++ prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ if (secRsnKeyHandshakeEnabled()) ++ prBssInfo->fgIsWPAorWPA2Enabled = TRUE; ++ else ++ prBssInfo->fgIsWPAorWPA2Enabled = FALSE; ++ ++ /* 4 <2.G> Beacon interval. */ ++ prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ ++ /* 4 <2.H> DTIM period. */ ++ prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* 4 <2.I> ERP Information */ ++ if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ ++ (prBssDesc->fgIsERPPresent)) { ++ ++ prBssInfo->fgIsERPPresent = TRUE; ++ prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ ++ } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ ++ prBssInfo->fgIsERPPresent = FALSE; ++ prBssInfo->ucERP = 0; ++ } ++ ++#if CFG_SUPPORT_802_11D ++ /* 4 <2.J> Country inforamtion of the associated AP */ ++ if (prConnSettings->fgMultiDomainCapabilityEnabled) { ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ ++ if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { ++ if (prBssDesc->prIECountry) { ++ prIECountry = prBssDesc->prIECountry; ++ ++ domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); ++ ++ /* use the domain get from the BSS info */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); ++ } else { ++ /* use the domain get from the scan result */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); ++ } ++ } ++ } ++#endif ++ ++ /* 4 <2.K> Signal Power of the associated AP */ ++ prBssInfo->rRcpi = prBssDesc->rRcpi; ++ prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); ++ GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); ++ ++ /* 4 <2.L> Capability Field of the associated AP */ ++ prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", ++ prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); ++ ++/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ ++ /* 4 <3.A> Association ID */ ++ prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; ++ ++ /* 4 <3.B> WMM Information */ ++ if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { ++ ++ prBssInfo->fgIsWmmAssoc = TRUE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC3; ++ ++ qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); ++ ++ if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { ++ kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } else { ++ kalMemCopy(&prBssInfo->rWmmInfo, ++ &prPeerBssInfo->rWmmInfo, ++ sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); ++ } ++ } else { ++ prBssInfo->fgIsWmmAssoc = FALSE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC1; ++ ++ kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } ++ ++ /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ ++ prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; ++ prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; ++ ++ /* 4 <3.D> Short Preamble */ ++ if (prBssInfo->fgIsERPPresent) { ++ ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) ++ * TRUE FALSE TRUE FALSE ++ * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) ++ * FALSE FALSE TRUE FALSE ++ * TRUE TRUE FALSE TRUE(follow ERP) ++ * TRUE TRUE TRUE FALSE(follow ERP) ++ * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) ++ * FALSE TRUE TRUE FALSE(we should set to FALSE) ++ */ ++ if ((prPeerBssInfo->fgIsShortPreambleAllowed) && ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ ++ if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ else ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ } else { ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE ++ * FALSE FALSE FALSE ++ * TRUE TRUE TRUE ++ * FALSE TRUE(status success) TRUE ++ * --> Honor the result of prPeerBssInfo. ++ */ ++ ++ prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = ++ prPeerBssInfo->fgIsShortPreambleAllowed; ++ } ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); ++ ++ /* 4 <3.E> Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); ++ ++ nicSetSlotTime(prAdapter, ++ prBssInfo->ePhyType, ++ ((prConnSettings->fgIsShortSlotTimeOptionEnable && ++ prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); ++ ++ /* 4 <3.F> Update Tx Rate for Control Frame */ ++ bssUpdateTxRateForControlFrame(prAdapter); ++ ++ /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ ++ /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ ++ { ++ ++ if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; ++ else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; ++ ++ prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; ++ ++ /* Set the stable time of the associated BSS. We won't do roaming decision ++ * during the stable time. ++ */ ++ SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, ++ SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); ++ } ++ ++ /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ ++#if CFG_TX_FRAGMENT ++ txFragInfoUpdate(prAdapter); ++#endif /* CFG_TX_FRAGMENT */ ++ ++/* 4 <4> Update STA_RECORD_T */ ++ /* Get a Station Record if possible */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); ++ ++ if (prStaRec) { ++ UINT_16 u2OperationalRateSet, u2DesiredRateSet; ++ ++ /* 4 <4.A> Desired Rate Set */ ++ u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & ++ prBssInfo->u2OperationalRateSet); ++ ++ u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); ++ if (u2DesiredRateSet) { ++ prStaRec->u2DesiredRateSet = u2DesiredRateSet; ++ } else { ++ /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ ++ prStaRec->u2DesiredRateSet = u2OperationalRateSet; ++ } ++ ++ /* Try to set the best initial rate for this entry */ ++ if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, ++ prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { ++ ++ if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) ++ ASSERT(0); ++ } ++ ++ DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); ++ ++ /* 4 <4.B> Preamble Mode */ ++ prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; ++ ++ /* 4 <4.C> QoS Flag */ ++ prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; ++ } ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++/* 4 <5> Update NIC */ ++ /* 4 <5.A> Update BSSID & Operation Mode */ ++ nicSetupBSS(prAdapter, prBssInfo); ++ ++ /* 4 <5.B> Update WLAN Table. */ ++ if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) ++ ASSERT(FALSE); ++ /* 4 <5.C> Update Desired Rate Set for BT. */ ++#if CFG_TX_FRAGMENT ++ if (prConnSettings->fgIsEnableTxAutoFragmentForBT) ++ txRateSetInitForBT(prAdapter, prStaRec); ++#endif /* CFG_TX_FRAGMENT */ ++ ++ /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ ++ if (prBssInfo->fgIsWmmAssoc) { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, FALSE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); ++ } else { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, TRUE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); ++ ++ nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); ++ } ++ ++#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN ++ { ++ prTxCtrl->fgBlockTxDuringJoin = FALSE; ++ ++#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ ++ nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxRetransmitOfSendWaitQue(prAdapter); ++ ++ if (prTxCtrl->fgIsPacketInOsSendQueue) ++ nicTxRetransmitOfOsSendQue(prAdapter); ++#if CFG_SDIO_TX_ENHANCE ++ halTxLeftClusteredMpdu(prAdapter); ++#endif /* CFG_SDIO_TX_ENHANCE */ ++ ++ } ++#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ ++ ++/* 4 <6> Setup CONNECTION flag. */ ++ prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; ++ prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; ++ ++ if (prJoinInfo->fgIsReAssoc) ++ prAdapter->fgBypassPortCtrlForRoaming = TRUE; ++ else ++ prAdapter->fgBypassPortCtrlForRoaming = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); ++ ++} /* end of joinComplete() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c +new file mode 100644 +index 000000000000..2c9ccbe82dd1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c +@@ -0,0 +1,3103 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan.c#3 ++*/ ++ ++/*! \file "scan.c" ++ \brief This file defines the scan profile and the processing function of ++ scan result for SCAN Module. ++ ++ The SCAN Profile selection is part of SCAN MODULE and responsible for defining ++ SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. ++ In this file we also define the process of SCAN Result including adding, searching ++ and removing SCAN record from the list. ++*/ ++ ++/* ++** Log: scan.c ++** ++** 01 30 2013 yuche.tsai ++** [ALPS00451578] [JB2][WFD][Case Fail][JE][MR1]?????????[Java (JE),660,-1361051648,99, ++** /data/core/,0,system_server_crash,system_server]JE happens when try to connect WFD.(4/5) ++** Fix possible old scan result indicate to supplicant after formation. ++** ++** 01 16 2013 yuche.tsai ++** [ALPS00431980] [WFD]Aupus one ?play game 10 minitues?wfd connection automaticlly disconnect ++** Fix possible FW assert issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 25 2012 cp.wu ++ * [WCXRP00001258] [MT6620][MT5931][MT6628][Driver] Do not use stale scan result for deciding connection target ++ * drop off scan result which is older than 5 seconds when choosing which BSS to join ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band ++ * configuration with corresponding network configuration ++ * correct typo. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred ++ * band configuration corresponding to network type. ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 11 23 2011 cp.wu ++ * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection ++ * add compile option to disable beacon content change detection. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001085] [MT6628 Wi-Fi][Driver] deprecate old BSS-DESC if timestamp ++ * is reset with received beacon/probe response frames ++ * deprecate old BSS-DESC when timestamp in received beacon/probe response frames showed a smaller value than before ++ * ++ * 10 11 2011 cm.chang ++ * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter ++ * Ignore HT OP IE if its length field is not valid ++ * ++ * 09 30 2011 cp.wu ++ * [WCXRP00001021] [MT5931][Driver] Correct scan result generation for conversion between BSS type and operation mode ++ * correct type casting issue. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 10 2011 cp.wu ++ * [WCXRP00000922] [MT6620 Wi-Fi][Driver] traverse whole BSS-DESC list for removing ++ * traverse whole BSS-DESC list because BSSID is not unique anymore. ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * for multiple BSS descriptior detecting issue: ++ * 1) check BSSID for infrastructure network ++ * 2) check SSID for AdHoc network ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * check for BSSID for beacons used to update DTIM ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * do not check BSS descriptor for connected flag due to linksys's hidden ++ * SSID will use another BSS descriptor and never connected ++ * ++ * 07 11 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * just pass beacons with the same BSSID. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define ++ * for make sure the value is initialize, for customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 28 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * Do not check for SSID as beacon content change due to the existence of ++ * single BSSID with multiple SSID AP configuration ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * 1. correct logic ++ * 2. replace only BSS-DESC which doesn't have a valid SSID. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID ++ * settings to work around some tricky AP which use space character as hidden SSID ++ * remove unused temporal variable reference. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID ++ * settings to work around some tricky AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels ++ * filter out BSS in disallowed channel by ++ * 1. do not add to scan result array if BSS is at disallowed channel ++ * 2. do not allow to search for BSS-DESC in disallowed channels ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Refine range of valid channel number ++ * ++ * 05 02 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Take parsed result for channel information instead of ++ * hardware channel number passed from firmware domain ++ * take parsed result for generating scanning result with channel information. ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Check if channel is valided before record ing BSS channel ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Always update Bss Type, for Bss Type for P2P Network is changing every time. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix concurrent issue when AIS scan result would overwrite p2p scan result. ++ * ++ * 03 14 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * filtering out other BSS coming from adjacent channels ++ * ++ * 03 11 2011 chinglan.wang ++ * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. ++ * . ++ * ++ * 03 11 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() ++ * won't sleep long enough for specified interval such as 500ms ++ * implement beacon change detection by checking SSID and supported rate. ++ * ++ * 02 22 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC big endian issue. ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix scan channel extension issue when p2p module is not registered. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 21 2011 cp.wu ++ * [WCXRP00000380] [MT6620 Wi-Fi][Driver] SSID information should come from buffered ++ * BSS_DESC_T rather than using beacon-carried information ++ * SSID should come from buffered prBssDesc rather than beacon-carried information ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix compile error. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Memfree for P2P Descriptor & P2P Descriptor List. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Free P2P Descriptor List & Descriptor under BSS Descriptor. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc ++ * and vmalloc implementations to ease physically continuous memory demands ++ * 1) correct typo in scan.c ++ * 2) TX descriptors, RX descriptos and management buffer should use virtually ++ * continuous buffer instead of physically continuous one ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc ++ * and vmalloc implementations to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * while being unloaded, clear all pending interrupt then set LP-own to firmware ++ * ++ * 12 21 2010 cp.wu ++ * [WCXRP00000280] [MT6620 Wi-Fi][Driver] Enable BSS selection with best RCPI policy in SCN module ++ * SCN: enable BEST RSSI selection policy support ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 11 03 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Refine the HT rate disallow TKIP pairwise cipher . ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out ++ * beacons which is received on the folding frequency ++ * trust HT IE if available for 5GHz band ++ * ++ * 10 11 2010 cp.wu ++ * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out ++ * beacons which is received on the folding frequency ++ * add timing and strenght constraint for filtering out beacons with same SSID/TA but received on different channels ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 10 01 2010 yuche.tsai ++ * NULL ++ * [MT6620 P2P] Fix Big Endian Issue when parse P2P device name TLV. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * When indicate scan result, append IE buffer information in the scan result. ++ * ++ * 09 03 2010 yuche.tsai ++ * NULL ++ * 1. Update Beacon RX count when running SLT. ++ * 2. Ignore Beacon when running SLT, would not update information from Beacon. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * 1. Fix P2P Descriptor List to be a link list, to avoid link corrupt after Bss Descriptor Free. ++ * 2.. Fix P2P Device Name Length BE issue. ++ * ++ * 08 23 2010 yuche.tsai ++ * NULL ++ * Add P2P Device Found Indication to supplicant ++ * ++ * 08 20 2010 cp.wu ++ * NULL ++ * reset BSS_DESC_T variables before parsing IE due to peer might have been reconfigured. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Workaround for P2P Descriptor Infinite loop issue. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Modify code of processing Probe Resonse frame for P2P. ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add function to get P2P descriptor of BSS descriptor directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Modify Scan result processing for P2P module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update P2P Device Discovery result add function. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add support for Probe Request & Response parsing. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Fix compile error for SCAN module while disabling P2P feature. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct BSS_DESC_T initialization after allocated. ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * if beacon/probe-resp is received in 2.4GHz bands and there is ELEM_ID_DS_PARAM_SET IE available, ++ * trust IE instead of RMAC information ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Update P2P Function call. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * RSN/PRIVACY compilation flag awareness correction ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error when enable P2P function. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct when ADHOC support is turned on. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the TKIP disallow join a HT AP code. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add more chance of JOIN retry for BG_SCAN ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add new HW CH macro support ++ * ++ * 04 06 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the firmware return the broadcast frame at wrong tc. ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * let the rsn wapi IE always parsing. ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Solve the compile warning for 'return non-void' function ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Fix No PKT_INFO_T issue ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Update outgoing ProbeRequest Frame's TX data rate ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver ++ * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 20 2010 kevin.huang ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * ++ * Refine Beacon processing, add read RF channel from RX Status ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Modify u2EstimatedExtraIELen for probe request ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add HT cap IE to probe request ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update the process of SCAN Result by adding more Phy Attributes ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function and code for meet the new define ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename u4RSSI to i4RSSI ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Report event of scan result to host ++ * ++ * Nov 26 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix SCAN Record update ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status and Integrate with TXM ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add (Ext)Support Rate Set IE to ProbeReq ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed the use of SW_RFB->u2FrameLength ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix uninitial aucMacAddress[] for ProbeReq ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scanSearchBssDescByPolicy() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Send Probe Request Frame ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define REPLICATED_BEACON_TIME_THRESHOLD (3000) ++#define REPLICATED_BEACON_FRESH_PERIOD (10000) ++#define REPLICATED_BEACON_STRENGTH_THRESHOLD (32) ++ ++#define ROAMING_NO_SWING_RCPI_STEP (10) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used by SCN to initialize its variables ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_BSS_DESC_T prBSSDesc; ++ PUINT_8 pucBSSBuff; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ pucBSSBuff = &prScanInfo->aucScanBuffer[0]; ++ ++ DBGLOG(SCN, INFO, "->scnInit()\n"); ++ ++ /* 4 <1> Reset STATE and Message List */ ++ prScanInfo->eCurrentState = SCAN_STATE_IDLE; ++ ++ prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; ++ ++ LINK_INITIALIZE(&prScanInfo->rPendingMsgList); ++ ++ /* 4 <2> Reset link list of BSS_DESC_T */ ++ kalMemZero((PVOID) pucBSSBuff, SCN_MAX_BUFFER_SIZE); ++ ++ LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); ++ LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ ++ for (i = 0; i < CFG_MAX_NUM_BSS_LIST; i++) { ++ ++ prBSSDesc = (P_BSS_DESC_T) pucBSSBuff; ++ ++ LINK_INSERT_TAIL(&prScanInfo->rFreeBSSDescList, &prBSSDesc->rLinkEntry); ++ ++ pucBSSBuff += ALIGN_4(sizeof(BSS_DESC_T)); ++ } ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT(((ULONG) pucBSSBuff - (ULONG)&prScanInfo->aucScanBuffer[0]) == SCN_MAX_BUFFER_SIZE); ++ ++ /* reset freest channel information */ ++ prScanInfo->fgIsSparseChannelValid = FALSE; ++ ++ /* reset NLO state */ ++ prScanInfo->fgNloScanning = FALSE; ++ prScanInfo->fgPscnOnnning = FALSE; ++ ++ prScanInfo->prPscnParam = kalMemAlloc(sizeof(PSCN_PARAM_T), VIR_MEM_TYPE); ++ if (prScanInfo->prPscnParam) ++ kalMemZero(prScanInfo->prPscnParam, sizeof(PSCN_PARAM_T)); ++ ++} /* end of scnInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used by SCN to uninitialize its variables ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ DBGLOG(SCN, INFO, "->scnUninit()\n"); ++ ++ /* 4 <1> Reset STATE and Message List */ ++ prScanInfo->eCurrentState = SCAN_STATE_IDLE; ++ ++ prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; ++ ++ /* NOTE(Kevin): Check rPendingMsgList ? */ ++ ++ /* 4 <2> Reset link list of BSS_DESC_T */ ++ LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); ++ LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ ++ kalMemFree(prScanInfo->prPscnParam, VIR_MEM_TYPE, sizeof(PSCN_PARAM_T)); ++ ++} /* end of scnUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ return scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ if (fgCheckSsid == FALSE || prSsid == NULL) ++ return prBssDesc; ++ ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { ++ return prBssDesc; ++ } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { ++ prDstBssDesc = prBssDesc; ++ } else { ++ /* 20120206 frog: Equal BSSID but not SSID, SSID not hidden, ++ * SSID must be updated. */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen); ++ return prBssDesc; ++ } ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucSrcAddr Given Source Address(TA). ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]) ++{ ++ return scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucSrcAddr Given Source Address(TA). ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucSrcAddr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucSrcAddr, aucSrcAddr)) { ++ if (fgCheckSsid == FALSE || prSsid == NULL) ++ return prBssDesc; ++ ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { ++ return prBssDesc; ++ } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { ++ prDstBssDesc = prBssDesc; ++ } ++ ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByTA() */ ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ OS_SYSTIME rLatestUpdateTime = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ if (!rLatestUpdateTime || CHECK_FOR_EXPIRATION(prBssDesc->rUpdateTime, rLatestUpdateTime)) { ++ prDstBssDesc = prBssDesc; ++ COPY_SYSTIME(rLatestUpdateTime, prBssDesc->rUpdateTime); ++ } ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByBssid() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to ++* given eBSSType, BSSID and Transmitter Address ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. ++* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. ++* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]) ++{ ++ return scanSearchExistingBssDescWithSsid(prAdapter, eBSSType, aucBSSID, aucSrcAddr, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to ++* given eBSSType, BSSID and Transmitter Address ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. ++* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. ++* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, ++ IN UINT_8 aucBSSID[], ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_BSS_DESC_T prBssDesc, prIBSSBssDesc; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ ++ ++ ASSERT(prAdapter); ++ ASSERT(aucSrcAddr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ switch (eBSSType) { ++ case BSS_TYPE_P2P_DEVICE: ++ fgCheckSsid = FALSE; ++ case BSS_TYPE_INFRASTRUCTURE: ++ case BSS_TYPE_BOW_DEVICE: ++ { ++ prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); ++ ++ /* if (eBSSType == prBssDesc->eBSSType) */ ++ ++ return prBssDesc; ++ } ++ ++ case BSS_TYPE_IBSS: ++ { ++ prIBSSBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); ++ prBssDesc = scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, fgCheckSsid, prSsid); ++ ++ /* NOTE(Kevin): ++ * Rules to maintain the SCAN Result: ++ * For AdHoc - ++ * CASE I We have TA1(BSSID1), but it change its BSSID to BSSID2 ++ * -> Update TA1 entry's BSSID. ++ * CASE II We have TA1(BSSID1), and get TA1(BSSID1) again ++ * -> Update TA1 entry's contain. ++ * CASE III We have a SCAN result TA1(BSSID1), and TA2(BSSID2). Sooner or ++ * later, TA2 merge into TA1, we get TA2(BSSID1) ++ * -> Remove TA2 first and then replace TA1 entry's TA with TA2, ++ * Still have only one entry of BSSID. ++ * CASE IV We have a SCAN result TA1(BSSID1), and another TA2 also merge into BSSID1. ++ * -> Replace TA1 entry's TA with TA2, Still have only one entry. ++ * CASE V New IBSS ++ * -> Add this one to SCAN result. ++ */ ++ if (prBssDesc) { ++ if ((!prIBSSBssDesc) || /* CASE I */ ++ (prBssDesc == prIBSSBssDesc)) { /* CASE II */ ++ ++ return prBssDesc; ++ } /* CASE III */ ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ ++ return prIBSSBssDesc; ++ } ++ ++ if (prIBSSBssDesc) { /* CASE IV */ ++ ++ return prIBSSBssDesc; ++ } ++ /* CASE V */ ++ break; /* Return NULL; */ ++ } ++ ++ default: ++ break; ++ } ++ ++ return (P_BSS_DESC_T) NULL; ++ ++} /* end of scanSearchExistingBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given Remove Policy. ++* ++* @param[in] u4RemovePolicy Remove Policy. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* DBGLOG(SCN, TRACE, ("Before Remove - Number Of SCAN Result = %ld\n", */ ++ /* prBSSDescList->u4NumElem)); */ ++ ++ if (u4RemovePolicy & SCN_RM_POLICY_TIMEOUT) { ++ P_BSS_DESC_T prBSSDescNext; ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove TIMEOUT BSS DESC(%#x): ++ * MAC: %pM, Current Time = %08lx, Update Time = %08lx\n", */ ++ /* prBssDesc, prBssDesc->aucBSSID, rCurrentTime, prBssDesc->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_OLDEST_HIDDEN) { ++ P_BSS_DESC_T prBssDescOldest = (P_BSS_DESC_T) NULL; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if (!prBssDesc->fgIsHiddenSSID) ++ continue; ++ ++ if (!prBssDescOldest) { /* 1st element */ ++ prBssDescOldest = prBssDesc; ++ continue; ++ } ++ ++ if (TIME_BEFORE(prBssDesc->rUpdateTime, prBssDescOldest->rUpdateTime)) ++ prBssDescOldest = prBssDesc; ++ } ++ ++ if (prBssDescOldest) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove OLDEST HIDDEN BSS DESC(%#x): ++ * MAC: %pM, Update Time = %08lx\n", */ ++ /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescOldest); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescOldest->rLinkEntry); ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_SMART_WEAKEST) { ++ P_BSS_DESC_T prBssDescWeakest = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBssDescWeakestSameSSID = (P_BSS_DESC_T) NULL; ++ UINT_32 u4SameSSIDCount = 0; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if ((!prBssDesc->fgIsHiddenSSID) && ++ (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen))) { ++ ++ u4SameSSIDCount++; ++ ++ if (!prBssDescWeakestSameSSID) ++ prBssDescWeakestSameSSID = prBssDesc; ++ else if (prBssDesc->ucRCPI < prBssDescWeakestSameSSID->ucRCPI) ++ prBssDescWeakestSameSSID = prBssDesc; ++ } ++ ++ if (!prBssDescWeakest) { /* 1st element */ ++ prBssDescWeakest = prBssDesc; ++ continue; ++ } ++ ++ if (prBssDesc->ucRCPI < prBssDescWeakest->ucRCPI) ++ prBssDescWeakest = prBssDesc; ++ ++ } ++ ++ if ((u4SameSSIDCount >= SCN_BSS_DESC_SAME_SSID_THRESHOLD) && (prBssDescWeakestSameSSID)) ++ prBssDescWeakest = prBssDescWeakestSameSSID; ++ ++ if (prBssDescWeakest) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove WEAKEST BSS DESC(%#x): MAC: %pM, Update Time = %08lx\n", */ ++ /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescWeakest); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescWeakest->rLinkEntry); ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_ENTIRE) { ++ P_BSS_DESC_T prBSSDescNext; ++ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ ++ } ++ ++ return; ++ ++} /* end of scanRemoveBssDescsByPolicy() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given BSSID. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBSSDescNext; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* Check if such BSS Descriptor exists in a valid list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ ++ /* BSSID is not unique, so need to traverse whols link-list */ ++ } ++ } ++ ++} /* end of scanRemoveBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given band configuration ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBand Given band ++* @param[in] eNetTypeIndex AIS - Remove IBSS/Infrastructure BSS ++* BOW - Remove BOW BSS ++* P2P - Remove P2P BSS ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBSSDescNext; ++ BOOLEAN fgToRemove; ++ ++ ASSERT(prAdapter); ++ ASSERT(eBand <= BAND_NUM); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ if (eBand == BAND_NULL) ++ return; /* no need to do anything, keep all scan result */ ++ ++ /* Check if such BSS Descriptor exists in a valid list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ fgToRemove = FALSE; ++ ++ if (prBssDesc->eBand == eBand) { ++ switch (eNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS)) { ++ fgToRemove = TRUE; ++ } ++ break; ++ ++ case NETWORK_TYPE_P2P_INDEX: ++ if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) ++ fgToRemove = TRUE; ++ break; ++ ++ case NETWORK_TYPE_BOW_INDEX: ++ if (prBssDesc->eBSSType == BSS_TYPE_BOW_DEVICE) ++ fgToRemove = TRUE; ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ if (fgToRemove == TRUE) { ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ } ++ ++} /* end of scanRemoveBssDescByBand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Clear the CONNECTION FLAG of a specified BSS Descriptor. ++* ++* @param[in] aucBSSID Given BSSID. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ prBssDesc->fgIsConnected = FALSE; ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ /* BSSID is not unique, so need to traverse whols link-list */ ++ } ++ } ++ ++ return; ++ ++} /* end of scanRemoveConnectionFlagOfBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Allocate new BSS_DESC_T ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* ++* @return Pointer to BSS Descriptor, if has free space. NULL, if has no space. ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ LINK_REMOVE_HEAD(prFreeBSSDescList, prBssDesc, P_BSS_DESC_T); ++ ++ if (prBssDesc) { ++ P_LINK_T prBSSDescList; ++ ++ kalMemZero(prBssDesc, sizeof(BSS_DESC_T)); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ LINK_INITIALIZE(&(prBssDesc->rP2pDeviceList)); ++ prBssDesc->fgIsP2PPresent = FALSE; ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* NOTE(Kevin): In current design, this new empty BSS_DESC_T will be ++ * inserted to BSSDescList immediately. ++ */ ++ LINK_INSERT_TAIL(prBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ ++ return prBssDesc; ++ ++} /* end of scanAllocateBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This API parses Beacon/ProbeResp frame and insert extracted BSS_DESC_T ++* with IEs into prAdapter->rWifiVar.rScanInfo.aucScanBuffer ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the receiving frame buffer. ++* ++* @return Pointer to BSS Descriptor ++* NULL if the Beacon/ProbeResp frame is invalid ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_DESC_T prBssDesc = NULL; ++ UINT_16 u2CapInfo; ++ ENUM_BSS_TYPE_T eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_8 ucHwChannelNum = 0; ++ UINT_8 ucIeDsChannelNum = 0; ++ UINT_8 ucIeHtChannelNum = 0; ++ BOOLEAN fgIsValidSsid = FALSE, fgEscape = FALSE; ++ PARAM_SSID_T rSsid; ++ UINT_64 u8Timestamp; ++ BOOLEAN fgIsNewBssDesc = FALSE; ++ ++ UINT_32 i; ++ UINT_8 ucSSIDChar; ++ ++ UINT_8 ucOuiType; ++ UINT_16 u2SubTypeVersion; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ ++ WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2CapInfo, &u2CapInfo); ++ WLAN_GET_FIELD_64(&prWlanBeaconFrame->au4Timestamp[0], &u8Timestamp); ++ ++ /* decide BSS type */ ++ switch (u2CapInfo & CAP_INFO_BSS_TYPE) { ++ case CAP_INFO_ESS: ++ /* It can also be Group Owner of P2P Group. */ ++ eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ break; ++ ++ case CAP_INFO_IBSS: ++ eBSSType = BSS_TYPE_IBSS; ++ break; ++ case 0: ++ /* The P2P Device shall set the ESS bit of the Capabilities field ++ * in the Probe Response fame to 0 and IBSS bit to 0. (3.1.2.1.1) */ ++ eBSSType = BSS_TYPE_P2P_DEVICE; ++ break; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /* @TODO: add rule to identify BOW beacons */ ++#endif ++ ++ default: ++ DBGLOG(SCN, ERROR, "wrong bss type %d\n", (INT_32)(u2CapInfo & CAP_INFO_BSS_TYPE)); ++ return NULL; ++ } ++ ++ /* 4 <1.1> Pre-parse SSID IE */ ++ pucIE = prWlanBeaconFrame->aucInfoElem; ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); ++ ++ if (u2IELength > CFG_IE_BUFFER_SIZE) ++ u2IELength = CFG_IE_BUFFER_SIZE; ++ kalMemZero(&rSsid, sizeof(rSsid)); ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID) { ++ ucSSIDChar = '\0'; ++ ++ /* D-Link DWL-900AP+ */ ++ if (IE_LEN(pucIE) == 0) ++ fgIsValidSsid = FALSE; ++ /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ ++ /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && ++ * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ ++ else { ++ for (i = 0; i < IE_LEN(pucIE); i++) ++ ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; ++ ++ if (ucSSIDChar) ++ fgIsValidSsid = TRUE; ++ } ++ ++ /* Update SSID to BSS Descriptor only if SSID is not hidden. */ ++ if (fgIsValidSsid == TRUE) { ++ COPY_SSID(rSsid.aucSsid, ++ rSsid.u4SsidLen, SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); ++ } ++ } ++ fgEscape = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgEscape == TRUE) ++ break; ++ } ++ if (fgIsValidSsid) ++ DBGLOG(SCN, EVENT, "%s %pM channel %d\n", rSsid.aucSsid, prWlanBeaconFrame->aucBSSID, ++ HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); ++ else ++ DBGLOG(SCN, EVENT, "hidden ssid, %pM channel %d\n", prWlanBeaconFrame->aucBSSID, ++ HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); ++ /* 4 <1.2> Replace existing BSS_DESC_T or allocate a new one */ ++ prBssDesc = scanSearchExistingBssDescWithSsid(prAdapter, ++ eBSSType, ++ (PUINT_8) prWlanBeaconFrame->aucBSSID, ++ (PUINT_8) prWlanBeaconFrame->aucSrcAddr, ++ fgIsValidSsid, fgIsValidSsid == TRUE ? &rSsid : NULL); ++ ++ if (prBssDesc == (P_BSS_DESC_T) NULL) { ++ fgIsNewBssDesc = TRUE; ++ ++ do { ++ /* 4 <1.2.1> First trial of allocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.2> Hidden is useless, remove the oldest hidden ssid. (for passive scan) */ ++ scanRemoveBssDescsByPolicy(prAdapter, ++ (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_OLDEST_HIDDEN)); ++ ++ /* 4 <1.2.3> Second tail of allocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.4> Remove the weakest one */ ++ /* If there are more than half of BSS which has the same ssid as connection ++ * setting, remove the weakest one from them. ++ * Else remove the weakest one. ++ */ ++ scanRemoveBssDescsByPolicy(prAdapter, ++ (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_SMART_WEAKEST)); ++ ++ /* 4 <1.2.5> reallocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.6> no space, should not happen */ ++ DBGLOG(SCN, ERROR, "no bss desc available after remove policy\n"); ++ return NULL; ++ ++ } while (FALSE); ++ ++ } else { ++ OS_SYSTIME rCurrentTime; ++ ++ /* WCXRP00000091 */ ++ /* if the received strength is much weaker than the original one, */ ++ /* ignore it due to it might be received on the folding frequency */ ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ if (prBssDesc->eBSSType != eBSSType) { ++ prBssDesc->eBSSType = eBSSType; ++ } else if (HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr) != prBssDesc->ucChannelNum && ++ prBssDesc->ucRCPI > prSwRfb->prHifRxHdr->ucRcpi) { ++ /* for signal strength is too much weaker and previous beacon is not stale */ ++ if ((prBssDesc->ucRCPI - prSwRfb->prHifRxHdr->ucRcpi) >= REPLICATED_BEACON_STRENGTH_THRESHOLD && ++ (rCurrentTime - prBssDesc->rUpdateTime) <= REPLICATED_BEACON_FRESH_PERIOD) { ++ DBGLOG(SCN, EVENT, "rssi is too much weaker and previous one is fresh\n"); ++ return prBssDesc; ++ } ++ /* for received beacons too close in time domain */ ++ else if (rCurrentTime - prBssDesc->rUpdateTime <= REPLICATED_BEACON_TIME_THRESHOLD) { ++ DBGLOG(SCN, EVENT, "receive beacon/probe reponses too close\n"); ++ return prBssDesc; ++ } ++ } ++ ++ /* if Timestamp has been reset, re-generate BSS DESC 'cause AP should have reset itself */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && u8Timestamp < prBssDesc->u8TimeStamp.QuadPart) { ++ BOOLEAN fgIsConnected, fgIsConnecting; ++ ++ /* set flag for indicating this is a new BSS-DESC */ ++ fgIsNewBssDesc = TRUE; ++ ++ /* backup 2 flags for APs which reset timestamp unexpectedly */ ++ fgIsConnected = prBssDesc->fgIsConnected; ++ fgIsConnecting = prBssDesc->fgIsConnecting; ++ scanRemoveBssDescByBssid(prAdapter, prBssDesc->aucBSSID); ++ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (!prBssDesc) ++ return NULL; ++ ++ /* restore */ ++ prBssDesc->fgIsConnected = fgIsConnected; ++ prBssDesc->fgIsConnecting = fgIsConnecting; ++ } ++ } ++#if 1 ++ ++ prBssDesc->u2RawLength = prSwRfb->u2PacketLen; ++ if (prBssDesc->u2RawLength > CFG_RAW_BUFFER_SIZE) ++ prBssDesc->u2RawLength = CFG_RAW_BUFFER_SIZE; ++ kalMemCopy(prBssDesc->aucRawBuf, prWlanBeaconFrame, prBssDesc->u2RawLength); ++#endif ++ ++ /* NOTE: Keep consistency of Scan Record during JOIN process */ ++ if ((fgIsNewBssDesc == FALSE) && prBssDesc->fgIsConnecting) { ++ DBGLOG(SCN, INFO, "we're connecting this BSS(%pM) now, don't update it\n", ++ prBssDesc->aucBSSID); ++ return prBssDesc; ++ } ++ /* 4 <2> Get information from Fixed Fields */ ++ prBssDesc->eBSSType = eBSSType; /* Update the latest BSS type information. */ ++ ++ COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prWlanBeaconFrame->aucSrcAddr); ++ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prWlanBeaconFrame->aucBSSID); ++ ++ prBssDesc->u8TimeStamp.QuadPart = u8Timestamp; ++ ++ WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2BeaconInterval, &prBssDesc->u2BeaconInterval); ++ ++ prBssDesc->u2CapInfo = u2CapInfo; ++ ++ /* 4 <2.1> Retrieve IEs for later parsing */ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); ++ ++ if (u2IELength > CFG_IE_BUFFER_SIZE) { ++ u2IELength = CFG_IE_BUFFER_SIZE; ++ prBssDesc->fgIsIEOverflow = TRUE; ++ } else { ++ prBssDesc->fgIsIEOverflow = FALSE; ++ } ++ prBssDesc->u2IELength = u2IELength; ++ ++ kalMemCopy(prBssDesc->aucIEBuf, prWlanBeaconFrame->aucInfoElem, u2IELength); ++ ++ /* 4 <2.2> reset prBssDesc variables in case that AP has been reconfigured */ ++ prBssDesc->fgIsERPPresent = FALSE; ++ prBssDesc->fgIsHTPresent = FALSE; ++ prBssDesc->eSco = CHNL_EXT_SCN; ++ prBssDesc->fgIEWAPI = FALSE; ++#if CFG_RSN_MIGRATION ++ prBssDesc->fgIERSN = FALSE; ++#endif ++#if CFG_PRIVACY_MIGRATION ++ prBssDesc->fgIEWPA = FALSE; ++#endif ++ ++ /* 4 <3.1> Full IE parsing on SW_RFB_T */ ++ pucIE = prWlanBeaconFrame->aucInfoElem; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && /* NOTE(Kevin): for Atheros IOT #1 */ ++ (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { ++ BOOLEAN fgIsHiddenSSID = FALSE; ++ ++ ucSSIDChar = '\0'; ++ ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ ++ /* D-Link DWL-900AP+ */ ++ if (IE_LEN(pucIE) == 0) ++ fgIsHiddenSSID = TRUE; ++ /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ ++ /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && ++ * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ ++ else { ++ for (i = 0; i < IE_LEN(pucIE); i++) ++ ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; ++ ++ if (!ucSSIDChar) ++ fgIsHiddenSSID = TRUE; ++ } ++ ++ /* Update SSID to BSS Descriptor only if SSID is not hidden. */ ++ if (!fgIsHiddenSSID) { ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); ++ } ++#if 0 ++ /* ++ After we connect to a hidden SSID, prBssDesc->aucSSID[] will ++ not be empty and prBssDesc->ucSSIDLen will not be 0, ++ so maybe we need to empty prBssDesc->aucSSID[] and set ++ prBssDesc->ucSSIDLen to 0 in prBssDesc to avoid that ++ UI still displays hidden SSID AP in scan list after ++ we disconnect the hidden SSID AP. ++ */ ++ else { ++ prBssDesc->aucSSID[0] = '\0'; ++ prBssDesc->ucSSIDLen = 0; ++ } ++#endif ++ ++ } ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* TP-LINK will set extra and incorrect ie with ELEM_ID_SUP_RATES */ ++ if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) ++ ucIeDsChannelNum = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++ case ELEM_ID_TIM: ++ if (IE_LEN(pucIE) <= ELEM_MAX_LEN_TIM) ++ prBssDesc->ucDTIMPeriod = TIM_IE(pucIE)->ucDTIMPeriod; ++ break; ++ ++ case ELEM_ID_IBSS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_IBSS_PARAMETER_SET) ++ prBssDesc->u2ATIMWindow = IBSS_PARAM_IE(pucIE)->u2ATIMWindow; ++ break; ++ ++#if 0 /* CFG_SUPPORT_802_11D */ ++ case ELEM_ID_COUNTRY_INFO: ++ prBssDesc->prIECountry = (P_IE_COUNTRY_T) pucIE; ++ break; ++#endif ++ ++ case ELEM_ID_ERP_INFO: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_ERP) ++ prBssDesc->fgIsERPPresent = TRUE; ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ if (!prIeExtSupportedRate) ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ ++#if CFG_RSN_MIGRATION ++ case ELEM_ID_RSN: ++ if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &prBssDesc->rRSNInfo)) { ++ prBssDesc->fgIERSN = TRUE; ++ prBssDesc->u2RsnCap = prBssDesc->rRSNInfo.u2RsnCap; ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) ++ rsnCheckPmkidCache(prAdapter, prBssDesc); ++ } ++ break; ++#endif ++ ++ case ELEM_ID_HT_CAP: ++ prBssDesc->fgIsHTPresent = TRUE; ++ break; ++ ++ case ELEM_ID_HT_OP: ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ ++ if ((((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { ++ prBssDesc->eSco = (ENUM_CHNL_EXT_T) ++ (((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO); ++ } ++ ucIeHtChannelNum = ((P_IE_HT_OP_T) pucIE)->ucPrimaryChannel; ++ ++ break; ++ ++#if CFG_SUPPORT_WAPI ++ case ELEM_ID_WAPI: ++ if (wapiParseWapiIE(WAPI_IE(pucIE), &prBssDesc->rIEWAPI)) ++ prBssDesc->fgIEWAPI = TRUE; ++ break; ++#endif ++ ++ case ELEM_ID_VENDOR: /* ELEM_ID_P2P, ELEM_ID_WMM */ ++#if CFG_PRIVACY_MIGRATION ++ if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { ++ if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && (u2SubTypeVersion == VERSION_WPA)) { ++ ++ if (rsnParseWpaIE(prAdapter, WPA_IE(pucIE), &prBssDesc->rWPAInfo)) ++ prBssDesc->fgIEWPA = TRUE; ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) ++ prBssDesc->fgIsP2PPresent = TRUE; ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ break; ++ ++ /* no default */ ++ } ++ } ++ ++ /* 4 <3.2> Save information from IEs - SSID */ ++ /* Update Flag of Hidden SSID for used in SEARCH STATE. */ ++ ++ /* NOTE(Kevin): in current driver, the ucSSIDLen == 0 represent ++ * all cases of hidden SSID. ++ * If the fgIsHiddenSSID == TRUE, it means we didn't get the ProbeResp with ++ * valid SSID. ++ */ ++ if (prBssDesc->ucSSIDLen == 0) ++ prBssDesc->fgIsHiddenSSID = TRUE; ++ else ++ prBssDesc->fgIsHiddenSSID = FALSE; ++ ++ /* 4 <3.3> Check rate information in related IEs. */ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ rateGetRateSetFromIEs(prIeSupportedRate, ++ prIeExtSupportedRate, ++ &prBssDesc->u2OperationalRateSet, ++ &prBssDesc->u2BSSBasicRateSet, &prBssDesc->fgIsUnknownBssBasicRate); ++ } ++ /* 4 <4> Update information from HIF RX Header */ ++ { ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ ASSERT(prHifRxHdr); ++ ++ /* 4 <4.1> Get TSF comparison result */ ++ prBssDesc->fgIsLargerTSF = HIF_RX_HDR_GET_TCL_FLAG(prHifRxHdr); ++ ++ /* 4 <4.2> Get Band information */ ++ prBssDesc->eBand = HIF_RX_HDR_GET_RF_BAND(prHifRxHdr); ++ ++ /* 4 <4.2> Get channel and RCPI information */ ++ ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prHifRxHdr); ++ ++ if (BAND_2G4 == prBssDesc->eBand) { ++ ++ /* Update RCPI if in right channel */ ++ if (ucIeDsChannelNum >= 1 && ucIeDsChannelNum <= 14) { ++ ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeDsChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeDsChannelNum; ++ } else if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum <= 14) { ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeHtChannelNum; ++ } else { ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ ++ prBssDesc->ucChannelNum = ucHwChannelNum; ++ } ++ } ++ /* 5G Band */ ++ else { ++ if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum < 200) { ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeHtChannelNum; ++ } else { ++ /* Always update RCPI */ ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ ++ prBssDesc->ucChannelNum = ucHwChannelNum; ++ } ++ } ++ } ++ ++ /* 4 <5> PHY type setting */ ++ prBssDesc->ucPhyTypeSet = 0; ++ ++ if (BAND_2G4 == prBssDesc->eBand) { ++ /* check if support 11n */ ++ if (prBssDesc->fgIsHTPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ ++ /* if not 11n only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ /* check if support 11g */ ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || prBssDesc->fgIsERPPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ ++ /* if not 11g only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)) { ++ /* check if support 11b */ ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++ } ++ } ++ } else { /* (BAND_5G == prBssDesc->eBande) */ ++ /* check if support 11n */ ++ if (prBssDesc->fgIsHTPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ ++ /* if not 11n only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ /* Support 11a definitely */ ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++ ++ ASSERT(!(prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)); ++ } ++ } ++ ++ /* 4 <6> Update BSS_DESC_T's Last Update TimeStamp. */ ++ GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); ++ ++ return prBssDesc; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to scan result for query ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame; ++ PARAM_MAC_ADDRESS rMacAddr; ++ PARAM_SSID_T rSsid; ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ UINT_8 ucRateLen = 0; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prBssDesc->eBand == BAND_2G4) { ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) ++ || prBssDesc->fgIsERPPresent) { ++ eNetworkType = PARAM_NETWORK_TYPE_OFDM24; ++ } else { ++ eNetworkType = PARAM_NETWORK_TYPE_DS; ++ } ++ } else { ++ ASSERT(prBssDesc->eBand == BAND_5G); ++ eNetworkType = PARAM_NETWORK_TYPE_OFDM5; ++ } ++ ++ if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { ++ /* NOTE(Kevin): Not supported by WZC(TBD) */ ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ COPY_MAC_ADDR(rMacAddr, prWlanBeaconFrame->aucBSSID); ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ rConfiguration.u4BeaconPeriod = (UINT_32) prWlanBeaconFrame->u2BeaconInterval; ++ rConfiguration.u4ATIMWindow = prBssDesc->u2ATIMWindow; ++ rConfiguration.u4DSConfig = nicChannelNum2Freq(prBssDesc->ucChannelNum); ++ rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ rateGetDataRatesFromRateSet(prBssDesc->u2OperationalRateSet, 0, aucRatesEx, &ucRateLen); ++ ++ /* NOTE(Kevin): Set unused entries, if any, at the end of the array to 0. ++ * from OID_802_11_BSSID_LIST ++ */ ++ for (i = ucRateLen; i < sizeof(aucRatesEx) / sizeof(aucRatesEx[0]); i++) ++ aucRatesEx[i] = 0; ++ ++ switch (prBssDesc->eBSSType) { ++ case BSS_TYPE_IBSS: ++ eOpMode = NET_TYPE_IBSS; ++ break; ++ ++ case BSS_TYPE_INFRASTRUCTURE: ++ case BSS_TYPE_P2P_DEVICE: ++ case BSS_TYPE_BOW_DEVICE: ++ default: ++ eOpMode = NET_TYPE_INFRA; ++ break; ++ } ++ ++ DBGLOG(SCN, TRACE, "ind %s %d\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ { ++ if (flgTdlsTestExtCapElm == TRUE) { ++ /* only for RALINK AP */ ++ UINT8 *pucElm = (UINT8 *) (prSwRfb->pvHeader + prSwRfb->u2PacketLen); ++ ++ kalMemCopy(pucElm - 9, aucTdlsTestExtCapElm, 7); ++ prSwRfb->u2PacketLen -= 2; ++/* prSwRfb->u2PacketLen += 7; */ ++ ++ DBGLOG(TDLS, INFO, ++ " %s: append ext cap element to %pM\n", ++ __func__, prBssDesc->aucBSSID); ++ } ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ if (prAdapter->rWifiVar.rScanInfo.fgNloScanning && ++ test_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag)) { ++ UINT_8 i = 0; ++ P_BSS_DESC_T *pprPendBssDesc = &prScanInfo->rNloParam.aprPendingBssDescToInd[0]; ++ ++ for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { ++ if (pprPendBssDesc[i]) ++ continue; ++ DBGLOG(SCN, INFO, ++ "indicate bss[%pM] before wiphy resume, need to indicate again after wiphy resume\n", ++ prBssDesc->aucBSSID); ++ pprPendBssDesc[i] = prBssDesc; ++ break; ++ } ++ } ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prSwRfb->pvHeader, ++ prSwRfb->u2PacketLen, prBssDesc->ucChannelNum, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ nicAddScanResult(prAdapter, ++ rMacAddr, ++ &rSsid, ++ prWlanBeaconFrame->u2CapInfo & CAP_INFO_PRIVACY ? 1 : 0, ++ RCPI_TO_dBm(prBssDesc->ucRCPI), ++ eNetworkType, ++ &rConfiguration, ++ eOpMode, ++ aucRatesEx, ++ prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen, ++ (PUINT_8) ((ULONG) (prSwRfb->pvHeader) + WLAN_MAC_MGMT_HEADER_LEN)); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of scanAddScanResult() */ ++ ++#if 1 ++ ++BOOLEAN scanCheckBssIsLegal(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ BOOLEAN fgAddToScanResult = FALSE; ++ ENUM_BAND_T eBand = 0; ++ UINT_8 ucChannel = 0; ++ ++ ASSERT(prAdapter); ++ /* check the channel is in the legal doamin */ ++ if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == TRUE) { ++ /* check ucChannelNum/eBand for adjacement channel filtering */ ++ if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE && ++ (eBand != prBssDesc->eBand || ucChannel != prBssDesc->ucChannelNum)) { ++ fgAddToScanResult = FALSE; ++ } else { ++ fgAddToScanResult = TRUE; ++ } ++ } ++ return fgAddToScanResult; ++ ++} ++ ++VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc) ++{ ++ P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; ++ P_LINK_T prBSSDescList = (P_LINK_T) NULL; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ DBGLOG(SCN, TRACE, "scanReportBss2Cfg80211\n"); ++ ++ if (SpecificprBssDesc) { ++ { ++ /* check BSSID is legal channel */ ++ if (!scanCheckBssIsLegal(prAdapter, SpecificprBssDesc)) { ++ DBGLOG(SCN, TRACE, "Remove specific SSID[%s %d]\n", ++ SpecificprBssDesc->aucSSID, SpecificprBssDesc->ucChannelNum); ++ return; ++ } ++ ++ DBGLOG(SCN, TRACE, "Report Specific SSID[%s]\n", SpecificprBssDesc->aucSSID); ++ if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) SpecificprBssDesc->aucRawBuf, ++ SpecificprBssDesc->u2RawLength, ++ SpecificprBssDesc->ucChannelNum, ++ RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); ++ } else { ++ ++ rChannelInfo.ucChannelNum = SpecificprBssDesc->ucChannelNum; ++ rChannelInfo.eBand = SpecificprBssDesc->eBand; ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) SpecificprBssDesc->aucRawBuf, ++ SpecificprBssDesc->u2RawLength, ++ &rChannelInfo, RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); ++ ++ } ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ SpecificprBssDesc->fgIsP2PReport = FALSE; ++#endif ++ } ++ } else { ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ /* 4 Auto Channel Selection:Record the AP Number */ ++ P_PARAM_CHN_LOAD_INFO prChnLoad; ++ UINT_8 ucIdx = 0; ++ ++ if (((prBssDesc->ucChannelNum > 0) && (prBssDesc->ucChannelNum <= 48)) ++ || (prBssDesc->ucChannelNum >= 147) /*non-DFS Channel */) { ++ if (prBssDesc->ucChannelNum <= HW_CHNL_NUM_MAX_2G4) { ++ ucIdx = prBssDesc->ucChannelNum - 1; ++ } else if (prBssDesc->ucChannelNum <= 48) { ++ ucIdx = (UINT_8) (HW_CHNL_NUM_MAX_2G4 + (prBssDesc->ucChannelNum - 34) / 4); ++ } else { ++ ucIdx = ++ (UINT_8) (HW_CHNL_NUM_MAX_2G4 + 4 + (prBssDesc->ucChannelNum - 149) / 4); ++ } ++ ++ if (ucIdx < MAX_AUTO_CHAL_NUM) { ++ prChnLoad = (P_PARAM_CHN_LOAD_INFO) & ++ (prAdapter->rWifiVar.rChnLoadInfo.rEachChnLoad[ucIdx]); ++ prChnLoad->ucChannel = prBssDesc->ucChannelNum; ++ prChnLoad->u2APNum++; ++ } else { ++ DBGLOG(SCN, WARN, "ACS: ChIdx > MAX_AUTO_CHAL_NUM\n"); ++ } ++ ++ } ++#endif ++ /* check BSSID is legal channel */ ++ if (!scanCheckBssIsLegal(prAdapter, prBssDesc)) { ++ DBGLOG(SCN, TRACE, "Remove SSID[%s %d]\n", ++ prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ continue; ++ } ++ ++ if ((prBssDesc->eBSSType == eBSSType) ++#if CFG_ENABLE_WIFI_DIRECT ++ || ((eBSSType == BSS_TYPE_P2P_DEVICE) && (prBssDesc->fgIsP2PReport == TRUE)) ++#endif ++ ) { ++ ++ DBGLOG(SCN, TRACE, "Report ALL SSID[%s %d]\n", ++ prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ if (prBssDesc->u2RawLength != 0) { ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBssDesc->aucRawBuf, ++ prBssDesc->u2RawLength, ++ prBssDesc->ucChannelNum, ++ RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); ++ prBssDesc->u2RawLength = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssDesc->fgIsP2PReport = FALSE; ++#endif ++ } ++ } else { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssDesc->fgIsP2PReport == TRUE) { ++#endif ++ rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; ++ rChannelInfo.eBand = prBssDesc->eBand; ++ ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBssDesc->aucRawBuf, ++ prBssDesc->u2RawLength, ++ &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ /* do not clear it then we can pass the bss in Specific report */ ++ /* kalMemZero(prBssDesc->aucRawBuf,CFG_RAW_BUFFER_SIZE); */ ++ ++ /* ++ the BSS entry will not be cleared after scan done. ++ So if we dont receive the BSS in next scan, we cannot ++ pass it. We use u2RawLength for the purpose. ++ */ ++ /* prBssDesc->u2RawLength=0; */ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssDesc->fgIsP2PReport = FALSE; ++ } ++#endif ++ } ++ } ++ ++ } ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = TRUE; ++#endif ++ ++ } ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse the content of given Beacon or ProbeResp Frame. ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS if not report this SW_RFB_T to host ++* @retval WLAN_STATUS_PENDING if report this SW_RFB_T to host as scan result ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_BSS_INFO_T prAisBssInfo; ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++#if CFG_SLT_SUPPORT ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ /* 4 <0> Ignore invalid Beacon Frame */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)) { ++ /* to debug beacon length too small issue */ ++ UINT_32 u4MailBox0; ++ ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ DBGLOG(SCN, WARN, "if conn sys also get less length (0x5a means yes) %x\n", (UINT_32) u4MailBox0); ++ DBGLOG(SCN, WARN, "u2PacketLen %d, u2HeaderLen %d, payloadLen %d\n", ++ prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen, ++ prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); ++ /* dumpMemory8(prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ ++#ifndef _lint ++ ASSERT(0); ++#endif /* _lint */ ++ return rStatus; ++ } ++#if CFG_SLT_SUPPORT ++ prSltInfo = &prAdapter->rWifiVar.rSltInfo; ++ ++ if (prSltInfo->fgIsDUT) { ++ DBGLOG(SCN, INFO, "\n\rBCN: RX\n"); ++ prSltInfo->u4BeaconReceiveCnt++; ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ ++ /*ALPS01475157: don't show SSID on scan list for multicast MAC AP */ ++ if (IS_BMCAST_MAC_ADDR(prWlanBeaconFrame->aucSrcAddr)) { ++ DBGLOG(SCN, WARN, "received beacon/probe response from multicast AP\n"); ++ return rStatus; ++ } ++ ++ /* 4 <1> Parse and add into BSS_DESC_T */ ++ prBssDesc = scanAddToBssDesc(prAdapter, prSwRfb); ++ ++ if (prBssDesc) { ++ /* 4 <1.1> Beacon Change Detection for Connected BSS */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED && ++ ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA)) && ++ EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && ++ EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen)) { ++ BOOLEAN fgNeedDisconnect = FALSE; ++ ++#if CFG_SUPPORT_BEACON_CHANGE_DETECTION ++ /* <1.1.2> check if supported rate differs */ ++ if (prAisBssInfo->u2OperationalRateSet != prBssDesc->u2OperationalRateSet) ++ fgNeedDisconnect = TRUE; ++#endif ++#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE ++ if ( ++#if CFG_SUPPORT_WAPI ++ (prAdapter->rWifiVar.rConnSettings.fgWapiMode == TRUE && ++ !wapiPerformPolicySelection(prAdapter, prBssDesc)) || ++#endif ++ rsnCheckSecurityModeChanged(prAdapter, prAisBssInfo, prBssDesc)) { ++ DBGLOG(SCN, INFO, "Beacon security mode change detected\n"); ++ fgNeedDisconnect = FALSE; ++ aisBssSecurityChanged(prAdapter); ++ } ++#endif ++ ++ /* <1.1.3> beacon content change detected, disconnect immediately */ ++ if (fgNeedDisconnect == TRUE) ++ aisBssBeaconTimeout(prAdapter); ++ } ++ /* 4 <1.1> Update AIS_BSS_INFO */ ++ if (((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA))) { ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* *not* checking prBssDesc->fgIsConnected anymore, ++ * due to Linksys AP uses " " as hidden SSID, and would have different BSS descriptor */ ++ if ((!prAisBssInfo->ucDTIMPeriod) && ++ EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && ++ (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && ++ ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { ++ ++ prAisBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* sync with firmware for beacon information */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ } ++#if CFG_SUPPORT_ADHOC ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, ++ prConnSettings->ucSSIDLen) && ++ (prBssDesc->eBSSType == BSS_TYPE_IBSS) && (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { ++ ibssProcessMatchedBeacon(prAdapter, prAisBssInfo, prBssDesc, ++ prSwRfb->prHifRxHdr->ucRcpi); ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ } ++ ++ rlmProcessBcn(prAdapter, ++ prSwRfb, ++ ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem, ++ (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); ++ ++ /* 4 <3> Send SW_RFB_T to HIF when we perform SCAN for HOST */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE || prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ /* for AIS, send to host */ ++ if (prConnSettings->fgIsScanReqIssued || prAdapter->rWifiVar.rScanInfo.fgNloScanning) { ++ BOOLEAN fgAddToScanResult; ++ ++ fgAddToScanResult = scanCheckBssIsLegal(prAdapter, prBssDesc); ++ ++ if (fgAddToScanResult == TRUE) ++ rStatus = scanAddScanResult(prAdapter, prBssDesc, prSwRfb); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ scanP2pProcessBeaconAndProbeResp(prAdapter, prSwRfb, &rStatus, prBssDesc, prWlanBeaconFrame); ++#endif ++ } ++ ++ return rStatus; ++ ++} /* end of scanProcessBeaconAndProbeResp() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Search the Candidate of BSS Descriptor for JOIN(Infrastructure) or ++* MERGE(AdHoc) according to current Connection Policy. ++* ++* \return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ P_SCAN_INFO_T prScanInfo; ++ ++ P_LINK_T prBSSDescList; ++ ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prPrimaryBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL; ++ ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_STA_RECORD_T prPrimaryStaRec; ++ P_STA_RECORD_T prCandidateStaRec = (P_STA_RECORD_T) NULL; ++ ++ OS_SYSTIME rCurrentTime; ++ ++ /* The first one reach the check point will be our candidate */ ++ BOOLEAN fgIsFindFirst = (BOOLEAN) FALSE; ++ ++ BOOLEAN fgIsFindBestRSSI = (BOOLEAN) FALSE; ++ BOOLEAN fgIsFindBestEncryptionLevel = (BOOLEAN) FALSE; ++ /* BOOLEAN fgIsFindMinChannelLoad = (BOOLEAN)FALSE; */ ++ ++ /* TODO(Kevin): Support Min Channel Load */ ++ /* UINT_8 aucChannelLoad[CHANNEL_NUM] = {0}; */ ++ ++ BOOLEAN fgIsFixedChannel; ++ ENUM_BAND_T eBand = 0; ++ UINT_8 ucChannel = 0; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ /* check for fixed channel operation */ ++ if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++#if CFG_P2P_LEGACY_COEX_REVISE ++ fgIsFixedChannel = cnmAisDetectP2PChannel(prAdapter, &eBand, &ucChannel); ++#else ++ fgIsFixedChannel = cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel); ++#endif ++ } else { ++ fgIsFixedChannel = FALSE; ++ } ++ ++#if DBG ++ if (prConnSettings->ucSSIDLen < ELEM_MAX_LEN_SSID) ++ prConnSettings->aucSSID[prConnSettings->ucSSIDLen] = '\0'; ++#endif ++ ++ DBGLOG(SCN, INFO, "SEARCH: Bss Num: %d, Look for SSID: %s, %pM Band=%d, channel=%d\n", ++ (UINT_32) prBSSDescList->u4NumElem, prConnSettings->aucSSID, ++ (prConnSettings->aucBSSID), eBand, ucChannel); ++ ++ /* 4 <1> The outer loop to search for a candidate. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ /* TODO(Kevin): Update Minimum Channel Load Information here */ ++ ++ DBGLOG(SCN, TRACE, "SEARCH: [ %pM ], SSID:%s\n", ++ prBssDesc->aucBSSID, prBssDesc->aucSSID); ++ ++ /* 4 <2> Check PHY Type and attributes */ ++ /* 4 <2.1> Check Unsupported BSS PHY Type */ ++ if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { ++ DBGLOG(SCN, TRACE, "SEARCH: Ignore unsupported ucPhyTypeSet = %x\n", prBssDesc->ucPhyTypeSet); ++ continue; ++ } ++ /* 4 <2.2> Check if has unknown NonHT BSS Basic Rate Set. */ ++ if (prBssDesc->fgIsUnknownBssBasicRate) ++ continue; ++ /* 4 <2.3> Check if fixed operation cases should be aware */ ++ if (fgIsFixedChannel == TRUE && (prBssDesc->eBand != eBand || prBssDesc->ucChannelNum != ucChannel)) ++ continue; ++ /* 4 <2.4> Check if the channel is legal under regulatory domain */ ++ if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == FALSE) ++ continue; ++ /* 4 <2.5> Check if this BSS_DESC_T is stale */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { ++ ++ BOOLEAN fgIsNeedToCheckTimeout = TRUE; ++ ++#if CFG_SUPPORT_ROAMING ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ if ((prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) || ++ (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) { ++ if (++prRoamingFsmInfo->RoamingEntryTimeoutSkipCount < ++ ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX) { ++ fgIsNeedToCheckTimeout = FALSE; ++ DBGLOG(SCN, INFO, "SEARCH: Romaing skip SCN_BSS_DESC_REMOVE_TIMEOUT_SEC\n"); ++ } ++ } ++#endif ++ ++ if (fgIsNeedToCheckTimeout == TRUE) { ++ DBGLOG(SCN, TRACE, "Ignore stale bss %pM\n", prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ /* 4 <3> Check if reach the excessive join retry limit */ ++ /* NOTE(Kevin): STA_RECORD_T is recorded by TA. */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); ++ ++ if (prStaRec) { ++ /* NOTE(Kevin): ++ * The Status Code is the result of a Previous Connection Request, ++ * we use this as SCORE for choosing a proper ++ * candidate (Also used for compare see <6>) ++ * The Reason Code is an indication of the reason why AP reject us, ++ * we use this Code for "Reject" ++ * a SCAN result to become our candidate(Like a blacklist). ++ */ ++#if 0 /* TODO(Kevin): */ ++ if (prStaRec->u2ReasonCode != REASON_CODE_RESERVED) { ++ DBGLOG(SCN, INFO, "SEARCH: Ignore BSS with previous Reason Code = %d\n", ++ prStaRec->u2ReasonCode); ++ continue; ++ } else ++#endif ++ if (prStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ /* NOTE(Kevin): greedy association - after timeout, we'll still ++ * try to associate to the AP whose STATUS of conection attempt ++ * was not success. ++ * We may also use (ucJoinFailureCount x JOIN_RETRY_INTERVAL_SEC) for ++ * time bound. ++ */ ++ if ((prStaRec->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) || ++ (CHECK_FOR_TIMEOUT(rCurrentTime, ++ prStaRec->rLastJoinTime, ++ SEC_TO_SYSTIME(JOIN_RETRY_INTERVAL_SEC)))) { ++ ++ /* NOTE(Kevin): Every JOIN_RETRY_INTERVAL_SEC interval, we can retry ++ * JOIN_MAX_RETRY_FAILURE_COUNT times. ++ */ ++ if (prStaRec->ucJoinFailureCount >= JOIN_MAX_RETRY_FAILURE_COUNT) ++ prStaRec->ucJoinFailureCount = 0; ++ DBGLOG(SCN, INFO, ++ "SEARCH: Try to join BSS again,Status Code=%d (Curr=%u/Last Join=%u)\n", ++ prStaRec->u2StatusCode, rCurrentTime, prStaRec->rLastJoinTime); ++ } else { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Ignore BSS which reach maximum Join Retry Count = %d\n", ++ JOIN_MAX_RETRY_FAILURE_COUNT); ++ continue; ++ } ++ ++ } ++ } ++ /* 4 <4> Check for various NETWORK conditions */ ++ if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ ++ /* 4 <4.1> Check BSS Type for the corresponding Operation Mode in Connection Setting */ ++ /* NOTE(Kevin): For NET_TYPE_AUTO_SWITCH, we will always pass following check. */ ++ if (((prConnSettings->eOPMode == NET_TYPE_INFRA) && ++ (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE)) ++#if CFG_SUPPORT_ADHOC ++ || ((prConnSettings->eOPMode == NET_TYPE_IBSS ++ || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) ++ && (prBssDesc->eBSSType != BSS_TYPE_IBSS)) ++#endif ++ ) { ++ ++ DBGLOG(SCN, TRACE, "Cur OPMode %d, Ignore eBSSType = %d\n", ++ prConnSettings->eOPMode, prBssDesc->eBSSType); ++ continue; ++ } ++ /* 4 <4.2> Check AP's BSSID if OID_802_11_BSSID has been set. */ ++ if ((prConnSettings->fgIsConnByBssidIssued) && ++ (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE)) { ++ ++ if (UNEQUAL_MAC_ADDR(prConnSettings->aucBSSID, prBssDesc->aucBSSID)) { ++ ++ DBGLOG(SCN, TRACE, "SEARCH: Ignore due to BSSID was not matched!\n"); ++ continue; ++ } ++ } ++#if CFG_SUPPORT_ADHOC ++ /* 4 <4.3> Check for AdHoc Mode */ ++ if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ OS_SYSTIME rCurrentTime; ++ ++ /* 4 <4.3.1> Check if this SCAN record has been updated recently for IBSS. */ ++ /* NOTE(Kevin): Because some STA may change its BSSID frequently after it ++ * create the IBSS - e.g. IPN2220, so we need to make sure we get the new one. ++ * For BSS, if the old record was matched, however it won't be able to pass ++ * the Join Process later. ++ */ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_ADHOC_BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCN, LOUD, ++ "SEARCH: Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ /* 4 <4.3.2> Check Peer's capability */ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { ++ ++ if (prPrimaryBssDesc) ++ DBGLOG(SCN, INFO, ++ "SEARCH: BSS DESC MAC: %pM, not supported AdHoc Mode.\n", ++ prPrimaryBssDesc->aucBSSID); ++ ++ continue; ++ } ++ /* 4 <4.3.3> Compare TSF */ ++ if (prBssInfo->fgIsBeaconActivated && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID)) { ++ ++ DBGLOG(SCN, LOUD, ++ "SEARCH: prBssDesc->fgIsLargerTSF = %d\n", prBssDesc->fgIsLargerTSF); ++ ++ if (!prBssDesc->fgIsLargerTSF) { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Ignore BSS DESC MAC: [ %pM ], Smaller TSF\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ } ++#if 0 /* TODO(Kevin): For IBSS */ ++ /* 4 <2.c> Check if this SCAN record has been updated recently for IBSS. */ ++ /* NOTE(Kevin): Because some STA may change its BSSID frequently after it ++ * create the IBSS, so we need to make sure we get the new one. ++ * For BSS, if the old record was matched, however it won't be able to pass ++ * the Join Process later. ++ */ ++ if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ ++ if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) && ++ (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED)) { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ (prBssDesc->aucBSSID)); ++ continue; ++ } ++ } ++ /* 4 <4B> Check for IBSS AdHoc Mode. */ ++ /* Skip if one or more BSS Basic Rate are not supported by current AdHocMode */ ++ if (prPrimaryBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ /* 4 <4B.1> Check if match the Capability of current IBSS AdHoc Mode. */ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prPrimaryBssDesc) == WLAN_STATUS_FAILURE) { ++ ++ DBGLOG(SCAN, TRACE, ++ "Ignore BSS DESC MAC: %pM, Capability not supported for AdHoc Mode.\n", ++ prPrimaryBssDesc->aucBSSID); ++ ++ continue; ++ } ++ /* 4 <4B.2> IBSS Merge Decision Flow for SEARCH STATE. */ ++ if (prAdapter->fgIsIBSSActive && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prPrimaryBssDesc->aucBSSID)) { ++ ++ if (!fgIsLocalTSFRead) { ++ NIC_GET_CURRENT_TSF(prAdapter, &rCurrentTsf); ++ ++ DBGLOG(SCAN, TRACE, ++ "\n\nCurrent TSF : %08lx-%08lx\n\n", ++ rCurrentTsf.u.HighPart, rCurrentTsf.u.LowPart); ++ } ++ ++ if (rCurrentTsf.QuadPart > prPrimaryBssDesc->u8TimeStamp.QuadPart) { ++ DBGLOG(SCAN, TRACE, ++ "Ignore BSS DESC MAC: [%pM], Current BSSID: [%pM].\n", ++ prPrimaryBssDesc->aucBSSID, prBssInfo->aucBSSID); ++ ++ DBGLOG(SCAN, TRACE, ++ "\n\nBSS's TSF : %08lx-%08lx\n\n", ++ prPrimaryBssDesc->u8TimeStamp.u.HighPart, ++ prPrimaryBssDesc->u8TimeStamp.u.LowPart); ++ ++ prPrimaryBssDesc->fgIsLargerTSF = FALSE; ++ continue; ++ } else { ++ prPrimaryBssDesc->fgIsLargerTSF = TRUE; ++ } ++ ++ } ++ } ++ /* 4 <5> Check the Encryption Status. */ ++ if (rsnPerformPolicySelection(prPrimaryBssDesc)) { ++ ++ if (prPrimaryBssDesc->ucEncLevel > 0) { ++ fgIsFindBestEncryptionLevel = TRUE; ++ ++ fgIsFindFirst = FALSE; ++ } ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ continue; ++ } ++ ++ /* For RSN Pre-authentication, update the PMKID canidate list for ++ same SSID and encrypt status */ ++ /* Update PMKID candicate list. */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnUpdatePmkidCandidateList(prPrimaryBssDesc); ++ if (prAdapter->rWifiVar.rAisBssInfo.u4PmkidCandicateCount) ++ prAdapter->rWifiVar.rAisBssInfo.fgIndicatePMKID = rsnCheckPmkidCandicate(); ++ } ++#endif ++ ++ prPrimaryBssDesc = (P_BSS_DESC_T) NULL; ++ ++ /* 4 <6> Check current Connection Policy. */ ++ switch (prConnSettings->eConnectionPolicy) { ++ case CONNECT_BY_SSID_BEST_RSSI: ++ /* Choose Hidden SSID to join only if the `fgIsEnableJoin...` is TRUE */ ++ if (prAdapter->rWifiVar.fgEnableJoinToHiddenSSID && prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): following if () statement means that ++ * If Target is hidden, then we won't connect when user specify SSID_ANY policy. ++ */ ++ if (prConnSettings->ucSSIDLen) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindBestRSSI = TRUE; ++ } ++ ++ } else if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindBestRSSI = TRUE; ++ ++ DBGLOG(SCN, TRACE, "SEARCH: fgIsFindBestRSSI=TRUE, %d, prPrimaryBssDesc=[ %pM ]\n", ++ prBssDesc->ucRCPI, prPrimaryBssDesc->aucBSSID); ++ } ++ break; ++ ++ case CONNECT_BY_SSID_ANY: ++ /* NOTE(Kevin): In this policy, we don't know the desired ++ * SSID from user, so we should exclude the Hidden SSID from scan list. ++ * And because we refuse to connect to Hidden SSID node at the beginning, so ++ * when the JOIN Module deal with a BSS_DESC_T which has fgIsHiddenSSID == TRUE, ++ * then the Connection Settings must be valid without doubt. ++ */ ++ if (!prBssDesc->fgIsHiddenSSID) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindFirst = TRUE; ++ } ++ break; ++ ++ case CONNECT_BY_BSSID: ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnSettings->aucBSSID)) ++ prPrimaryBssDesc = prBssDesc; ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Primary Candidate was not found */ ++ if (prPrimaryBssDesc == NULL) ++ continue; ++ /* 4 <7> Check the Encryption Status. */ ++ if (prPrimaryBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { ++ DBGLOG(SCN, TRACE, "SEARCH: fgWapiMode == 1\n"); ++ ++ if (wapiPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { ++ fgIsFindFirst = TRUE; ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ DBGLOG(SCN, TRACE, "SEARCH: WAPI cannot pass the Encryption Status Check!\n"); ++ continue; ++ } ++ } else ++#endif ++#if CFG_RSN_MIGRATION ++ if (rsnPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { ++ if (prAisSpecBssInfo->fgCounterMeasure) { ++ DBGLOG(RSN, INFO, "Skip while at counter measure period!!!\n"); ++ continue; ++ } ++ ++ if (prPrimaryBssDesc->ucEncLevel > 0) { ++ fgIsFindBestEncryptionLevel = TRUE; ++ fgIsFindFirst = FALSE; ++ } ++#if 0 ++ /* Update PMKID candicate list. */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnUpdatePmkidCandidateList(prPrimaryBssDesc); ++ if (prAisSpecBssInfo->u4PmkidCandicateCount) { ++ if (rsnCheckPmkidCandicate()) { ++ DBGLOG(RSN, WARN, ++ "Prepare a timer to indicate candidate %pM\n", ++ (prAisSpecBssInfo->arPmkidCache ++ [prAisSpecBssInfo->u4PmkidCacheCount]. ++ rBssidInfo.aucBssid))); ++ cnmTimerStopTimer(&prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(&prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC ++ (WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++ } ++#endif ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ continue; ++ } ++#endif ++ } else { ++ /* Todo:: P2P and BOW Policy Selection */ ++ } ++ ++ prPrimaryStaRec = prStaRec; ++ ++ /* 4 <8> Compare the Candidate and the Primary Scan Record. */ ++ if (!prCandidateBssDesc) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ ++ /* 4 <8.1> Condition - Get the first matched one. */ ++ if (fgIsFindFirst) ++ break; ++ } else { ++#if 0 /* TODO(Kevin): For security(TBD) */ ++ /* 4 <6B> Condition - Choose the one with best Encryption Score. */ ++ if (fgIsFindBestEncryptionLevel) { ++ if (prCandidateBssDesc->ucEncLevel < prPrimaryBssDesc->ucEncLevel) { ++ ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ ++ /* If reach here, that means they have the same Encryption Score. ++ */ ++ ++ /* 4 <6C> Condition - Give opportunity to the one we didn't connect before. */ ++ /* For roaming, only compare the candidates other than current associated BSSID. */ ++ if (!prCandidateBssDesc->fgIsConnected && !prPrimaryBssDesc->fgIsConnected) { ++ if ((prCandidateStaRec != (P_STA_RECORD_T) NULL) && ++ (prCandidateStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { ++ ++ DBGLOG(SCAN, TRACE, ++ "So far -BSS DESC MAC: %pM has nonzero Status Code = %d\n", ++ prCandidateBssDesc->aucBSSID, ++ prCandidateStaRec->u2StatusCode); ++ ++ if (prPrimaryStaRec != (P_STA_RECORD_T) NULL) { ++ if (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ ++ /* Give opportunity to the one with smaller rLastJoinTime */ ++ if (TIME_BEFORE(prCandidateStaRec->rLastJoinTime, ++ prPrimaryStaRec->rLastJoinTime)) { ++ continue; ++ } ++ /* We've connect to CANDIDATE recently, ++ * let us try PRIMARY now */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ /* PRIMARY's u2StatusCode = 0 */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ /* PRIMARY has no StaRec - We didn't connet to PRIMARY before */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else { ++ if ((prPrimaryStaRec != (P_STA_RECORD_T) NULL) && ++ (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { ++ continue; ++ } ++ } ++ } ++#endif ++ ++ /* 4 <6D> Condition - Visible SSID win Hidden SSID. */ ++ if (prCandidateBssDesc->fgIsHiddenSSID) { ++ if (!prPrimaryBssDesc->fgIsHiddenSSID) { ++ prCandidateBssDesc = prPrimaryBssDesc; /* The non Hidden SSID win. */ ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else { ++ if (prPrimaryBssDesc->fgIsHiddenSSID) ++ continue; ++ } ++ ++ /* 4 <6E> Condition - Choose the one with better RCPI(RSSI). */ ++ if (fgIsFindBestRSSI) { ++ /* TODO(Kevin): We shouldn't compare the actual value, we should ++ * allow some acceptable tolerance of some RSSI percentage here. ++ */ ++ DBGLOG(SCN, TRACE, ++ "Candidate [%pM]: RCPI = %d, joinFailCnt=%d, Primary [%pM]: RCPI = %d, joinFailCnt=%d\n", ++ prCandidateBssDesc->aucBSSID, ++ prCandidateBssDesc->ucRCPI, prCandidateBssDesc->ucJoinFailureCount, ++ prPrimaryBssDesc->aucBSSID, ++ prPrimaryBssDesc->ucRCPI, prPrimaryBssDesc->ucJoinFailureCount); ++ ++ ASSERT(!(prCandidateBssDesc->fgIsConnected && prPrimaryBssDesc->fgIsConnected)); ++ if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { ++ /* give a chance to do join if join fail before ++ * SCN_BSS_DECRASE_JOIN_FAIL_CNT_SEC seconds ++ */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rJoinFailTime, ++ SEC_TO_SYSTIME(SCN_BSS_JOIN_FAIL_CNT_RESET_SEC))) { ++ prBssDesc->ucJoinFailureCount = SCN_BSS_JOIN_FAIL_THRESOLD - ++ SCN_BSS_JOIN_FAIL_RESET_STEP; ++ DBGLOG(SCN, INFO, ++ "decrease join fail count for Bss %pM to %u, timeout second %d\n", ++ prBssDesc->aucBSSID, prBssDesc->ucJoinFailureCount, ++ SCN_BSS_JOIN_FAIL_CNT_RESET_SEC); ++ } ++ } ++ ++ /* NOTE: To prevent SWING, ++ * we do roaming only if target AP has at least 5dBm larger than us. */ ++ if (prCandidateBssDesc->fgIsConnected) { ++ if (prCandidateBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP <= ++ prPrimaryBssDesc->ucRCPI && ++ prPrimaryBssDesc->ucJoinFailureCount < SCN_BSS_JOIN_FAIL_THRESOLD) { ++ ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else if (prPrimaryBssDesc->fgIsConnected) { ++ if (prCandidateBssDesc->ucRCPI < ++ (prPrimaryBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP) || ++ (prCandidateBssDesc->ucJoinFailureCount >= ++ SCN_BSS_JOIN_FAIL_THRESOLD)) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) ++ continue; ++ else if (prCandidateBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD || ++ prCandidateBssDesc->ucRCPI < prPrimaryBssDesc->ucRCPI) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++#if 0 ++ /* If reach here, that means they have the same Encryption Score, and ++ * both RSSI value are close too. ++ */ ++ /* 4 <6F> Seek the minimum Channel Load for less interference. */ ++ if (fgIsFindMinChannelLoad) { ++ /* Do nothing */ ++ /* TODO(Kevin): Check which one has minimum channel load in its channel */ ++ } ++#endif ++ } ++ } ++ ++ ++ if (prCandidateBssDesc != NULL) { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Candidate BSS: %pM\n", prCandidateBssDesc->aucBSSID); ++ } ++ ++ return prCandidateBssDesc; ++ ++} /* end of scanSearchBssDescByPolicy() */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter) ++{ ++ P_LINK_T prBSSDescList = &prAdapter->rWifiVar.rScanInfo.rBSSDescList; ++ P_BSS_DESC_T prBssDesc = NULL; ++ P_AGPS_AP_LIST_T prAgpsApList; ++ P_AGPS_AP_INFO_T prAgpsInfo; ++ P_SCAN_INFO_T prScanInfo = &prAdapter->rWifiVar.rScanInfo; ++ UINT_8 ucIndex = 0; ++ ++ prAgpsApList = kalMemAlloc(sizeof(AGPS_AP_LIST_T), VIR_MEM_TYPE); ++ if (!prAgpsApList) ++ return; ++ ++ prAgpsInfo = &prAgpsApList->arApInfo[0]; ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->rUpdateTime < prScanInfo->rLastScanCompletedTime) ++ continue; ++ COPY_MAC_ADDR(prAgpsInfo->aucBSSID, prBssDesc->aucBSSID); ++ prAgpsInfo->ePhyType = AGPS_PHY_G; ++ prAgpsInfo->u2Channel = prBssDesc->ucChannelNum; ++ prAgpsInfo->i2ApRssi = RCPI_TO_dBm(prBssDesc->ucRCPI); ++ prAgpsInfo++; ++ ucIndex++; ++ if (ucIndex == 32) ++ break; ++ } ++ prAgpsApList->ucNum = ucIndex; ++ GET_CURRENT_SYSTIME(&prScanInfo->rLastScanCompletedTime); ++ /* DBGLOG(SCN, INFO, ("num of scan list:%d\n", ucIndex)); */ ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_AP_LIST, (PUINT_8) prAgpsApList, sizeof(AGPS_AP_LIST_T)); ++ kalMemFree(prAgpsApList, VIR_MEM_TYPE, sizeof(AGPS_AP_LIST_T)); ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c +new file mode 100644 +index 000000000000..fac9f94428dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c +@@ -0,0 +1,2136 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan_fsm.c#1 ++*/ ++ ++/*! \file "scan_fsm.c" ++ \brief This file defines the state transition function for SCAN FSM. ++ ++ The SCAN FSM is part of SCAN MODULE and responsible for performing basic SCAN ++ behavior as metioned in IEEE 802.11 2007 11.1.3.1 & 11.1.3.2 . ++*/ ++ ++/* ++** Log: scan_fsm.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001095] [Volunteer Patch][Driver] Always Scan before enable Hot-Spot. ++ * Fix bug when unregister P2P network.. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * free mailbox message afte parsing is completed. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support ++ * as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning ++ * surpress klock warning with code path rewritten ++ * ++ * 03 18 2011 cm.chang ++ * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command ++ * As CR title ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame ++ * during search phase do not contain P2P wildcard SSID. ++ * Take P2P wildcard SSID into consideration. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix scan channel extension issue when p2p module is not registered. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix bug for processing queued scan request. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add a function for returning channel. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update SCAN FSM for support P2P Device discovery scan. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add option of channel extension while cancelling scan request. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 cp.wu ++ * ++ * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * due to FW/DRV won't be sync. precisely, some strict assertions should be eased. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * when returning to SCAN_IDLE state, send a correct message to source FSM. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine the order of Stop TX Queue and Switch Channel ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update pause/resume/flush API to new Bitmap API ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Ignore the PROBE_DELAY state if the value of Probe Delay == 0 ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add set RX Filter to receive BCN from different BSSID during SCAN ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove flag of CFG_TEST_MGMT_FSM ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Change parameter of scanSendProbeReqFrames() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update scnFsmSteps() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugScanState[SCAN_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("SCAN_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("SCAN_STATE_SCANNING"), ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++#define CURRENT_PSCN_VERSION 1 ++#define RSSI_MARGIN_DEFAULT 5 ++#define MAX_PERIOD 200000 ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_HDR_T prMsgHdr; ++ ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ do { ++ ++#if DBG ++ DBGLOG(SCN, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugScanState[prScanInfo->eCurrentState], apucDebugScanState[eNextState]); ++#else ++ DBGLOG(SCN, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_SCN_IDX, prScanInfo->eCurrentState, eNextState); ++#endif ++ ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ prScanInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ switch (prScanInfo->eCurrentState) { ++ case SCAN_STATE_IDLE: ++ /* check for pending scanning requests */ ++ if (!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { ++ /* load next message from pending list as scan parameters */ ++ LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, P_MSG_HDR_T); ++ ++ if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); ++ } else { ++ scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); ++ } ++ ++ /* switch to next state */ ++ eNextState = SCAN_STATE_SCANNING; ++ fgIsTransition = TRUE; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ } ++ break; ++ ++ case SCAN_STATE_SCANNING: ++ if (prScanParam->fgIsScanV2 == FALSE) ++ scnSendScanReq(prAdapter); ++ else ++ scnSendScanReqV2(prAdapter); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ ++ } ++ } while (fgIsTransition); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_EXT_CH rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_EXT_CH prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_EXT_CH), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) ++ return; ++ ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_EXT_CH)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ if (prScanParam->ucSSIDNum == 1) { ++ COPY_SSID(prCmdScanReq->aucSSID, ++ prCmdScanReq->ucSSIDLength, ++ prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); ++ } ++ ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_EXT_CH, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ else if (prCmdScanReq->ucSSIDLength > 32) ++ kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_EXT_CH)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReq(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ rCmdScanReq;*/ ++ P_CMD_SCAN_REQ prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanParam->ucChannelListNum > 32) { ++ scnSendScanReqExtCh(prAdapter); ++ } else { ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdScanReq fail"); ++ return; ++ } ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ if (prScanParam->ucSSIDNum == 1) { ++ COPY_SSID(prCmdScanReq->aucSSID, ++ prCmdScanReq->ucSSIDLength, ++ prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); ++ } ++ ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. ++ * (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++#if CFG_ENABLE_FAST_SCAN ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = CFG_FAST_SCAN_DWELL_TIME; ++#endif ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ else if (prCmdScanReq->ucSSIDLength > 32) ++ kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ_V2 command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_V2_EXT_CH rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_V2_EXT_CH prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2_EXT_CH), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) ++ return; ++ ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ for (i = 0; i < prScanParam->ucSSIDNum; i++) { ++ COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, ++ prCmdScanReq->arSSID[i].u4SsidLen, ++ prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); ++ } ++ ++ prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ_V2, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_V2_EXT_CH, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ_V2 command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_V2 rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_V2 prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanParam->ucChannelListNum > 32) { ++ scnSendScanReqV2ExtCh(prAdapter); ++ } else { ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdScanReq v2 fail"); ++ return; ++ } ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ for (i = 0; i < prScanParam->ucSSIDNum; i++) { ++ COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, ++ prCmdScanReq->arSSID[i].u4SsidLen, ++ prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); ++ } ++ ++ prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. ++ * (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ_V2, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_V2, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanInfo->eCurrentState == SCAN_STATE_IDLE) { ++ if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); ++ } else if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { ++ scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); ++ } else { ++ /* should not deliver to this function */ ++ ASSERT(0); ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ scnFsmSteps(prAdapter, SCAN_STATE_SCANNING); ++ } else { ++ LINK_INSERT_TAIL(&prScanInfo->rPendingMsgList, &prMsgHdr->rLinkEntry); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_CANCEL prScanCancel; ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ CMD_SCAN_CANCEL rCmdScanCancel; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanCancel = (P_MSG_SCN_SCAN_CANCEL) prMsgHdr; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanInfo->eCurrentState != SCAN_STATE_IDLE) { ++ if (prScanCancel->ucSeqNum == prScanParam->ucSeqNum && ++ prScanCancel->ucNetTypeIndex == (UINT_8) prScanParam->eNetTypeIndex) { ++ /* send cancel message to firmware domain */ ++ rCmdScanCancel.ucSeqNum = prScanParam->ucSeqNum; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) prScanCancel->fgIsChannelExt; ++ else ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_CANCEL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8) &rCmdScanCancel, NULL, 0); ++ ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ++ prScanParam->ucSeqNum, ++ (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_CANCELLED); ++ ++ /* switch to next pending scan */ ++ scnFsmSteps(prAdapter, SCAN_STATE_IDLE); ++ } else { ++ scnFsmRemovePendingMsg(prAdapter, prScanCancel->ucSeqNum, prScanCancel->ucNetTypeIndex); ++ } ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Scan Message Parsing (Legacy) ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prScanReqMsg); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prScanParam->eScanType = prScanReqMsg->eScanType; ++ prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; ++ prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; ++ if (prScanParam->ucSSIDType & (SCAN_REQ_SSID_SPECIFIED | SCAN_REQ_SSID_P2P_WILDCARD)) { ++ prScanParam->ucSSIDNum = 1; ++ ++ COPY_SSID(prScanParam->aucSpecifiedSSID[0], ++ prScanParam->ucSpecifiedSSIDLen[0], prScanReqMsg->aucSSID, prScanReqMsg->ucSSIDLength); ++ ++ /* reset SSID length to zero for rest array entries */ ++ for (i = 1; i < SCN_SSID_MAX_NUM; i++) ++ prScanParam->ucSpecifiedSSIDLen[i] = 0; ++ } else { ++ prScanParam->ucSSIDNum = 0; ++ ++ for (i = 0; i < SCN_SSID_MAX_NUM; i++) ++ prScanParam->ucSpecifiedSSIDLen[i] = 0; ++ } ++ ++ prScanParam->u2ProbeDelayTime = 0; ++ prScanParam->eScanChannel = prScanReqMsg->eScanChannel; ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; ++ else ++ prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ kalMemCopy(prScanParam->arChnlInfoList, ++ prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); ++ } ++ ++ if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) ++ prScanParam->u2IELen = prScanReqMsg->u2IELen; ++ else ++ prScanParam->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; ++#endif ++ prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; ++ ++ if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) ++ prScanParam->fgIsObssScan = TRUE; ++ else ++ prScanParam->fgIsObssScan = FALSE; ++ ++ prScanParam->fgIsScanV2 = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Scan Message Parsing - V2 with multiple SSID support ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prScanReqMsg); ++ ASSERT(prScanReqMsg->ucSSIDNum <= SCN_SSID_MAX_NUM); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prScanParam->eScanType = prScanReqMsg->eScanType; ++ prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; ++ prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; ++ prScanParam->ucSSIDNum = prScanReqMsg->ucSSIDNum; ++ ++ for (i = 0; i < prScanReqMsg->ucSSIDNum; i++) { ++ COPY_SSID(prScanParam->aucSpecifiedSSID[i], ++ prScanParam->ucSpecifiedSSIDLen[i], ++ prScanReqMsg->prSsid[i].aucSsid, (UINT_8) prScanReqMsg->prSsid[i].u4SsidLen); ++ } ++ ++ prScanParam->u2ProbeDelayTime = prScanReqMsg->u2ProbeDelay; ++ prScanParam->eScanChannel = prScanReqMsg->eScanChannel; ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; ++ else ++ prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ kalMemCopy(prScanParam->arChnlInfoList, ++ prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); ++ } ++ ++ if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) ++ prScanParam->u2IELen = prScanReqMsg->u2IELen; ++ else ++ prScanParam->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; ++#endif ++ prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; ++ ++ if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) ++ prScanParam->fgIsObssScan = TRUE; ++ else ++ prScanParam->fgIsObssScan = FALSE; ++ ++ prScanParam->fgIsScanV2 = TRUE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Remove pending scan request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_HDR_T prPendingMsgHdr, prPendingMsgHdrNext, prRemoveMsgHdr = NULL; ++ P_LINK_ENTRY_T prRemoveLinkEntry = NULL; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ /* traverse through rPendingMsgList for removal */ ++ LINK_FOR_EACH_ENTRY_SAFE(prPendingMsgHdr, ++ prPendingMsgHdrNext, &(prScanInfo->rPendingMsgList), rLinkEntry, MSG_HDR_T) { ++ if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ P_MSG_SCN_SCAN_REQ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) prPendingMsgHdr; ++ ++ if (ucSeqNum == prScanReqMsg->ucSeqNum && ucNetTypeIndex == prScanReqMsg->ucNetTypeIndex) { ++ prRemoveLinkEntry = &(prScanReqMsg->rMsgHdr.rLinkEntry); ++ prRemoveMsgHdr = prPendingMsgHdr; ++ } ++ } else if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { ++ P_MSG_SCN_SCAN_REQ_V2 prScanReqMsgV2 = (P_MSG_SCN_SCAN_REQ_V2) prPendingMsgHdr; ++ ++ if (ucSeqNum == prScanReqMsgV2->ucSeqNum && ucNetTypeIndex == prScanReqMsgV2->ucNetTypeIndex) { ++ prRemoveLinkEntry = &(prScanReqMsgV2->rMsgHdr.rLinkEntry); ++ prRemoveMsgHdr = prPendingMsgHdr; ++ } ++ } ++ ++ if (prRemoveLinkEntry) { ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ucSeqNum, ucNetTypeIndex, SCAN_STATUS_CANCELLED); ++ ++ /* remove from pending list */ ++ LINK_REMOVE_KNOWN_ENTRY(&(prScanInfo->rPendingMsgList), prRemoveLinkEntry); ++ cnmMemFree(prAdapter, prRemoveMsgHdr); ++ ++ break; ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ /* buffer empty channel information */ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_FULL || prScanParam->eScanChannel == SCAN_CHANNEL_2G4) { ++ if (prScanDone->ucSparseChannelValid) { ++ prScanInfo->fgIsSparseChannelValid = TRUE; ++ prScanInfo->rSparseChannel.eBand = (ENUM_BAND_T) prScanDone->rSparseChannel.ucBand; ++ prScanInfo->rSparseChannel.ucChannelNum = prScanDone->rSparseChannel.ucChannelNum; ++ } else { ++ prScanInfo->fgIsSparseChannelValid = FALSE; ++ } ++ } ++ ++ if (prScanInfo->eCurrentState == SCAN_STATE_SCANNING && prScanDone->ucSeqNum == prScanParam->ucSeqNum) { ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ++ prScanParam->ucSeqNum, (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_DONE); ++ ++ /* switch to next pending scan */ ++ scnFsmSteps(prAdapter, SCAN_STATE_IDLE); ++ } else { ++ DBGLOG(SCN, WARN, "Unexpected SCAN-DONE event: SeqNum = %d, Current State = %d\n", ++ prScanDone->ucSeqNum, prScanInfo->eCurrentState); ++ } ++ ++} /* end of scnEventScanDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ DBGLOG(SCN, INFO, "Rcv Scan Done, NetIdx %d, Obss %d, Status %d, Seq %d\n", ++ ucNetTypeIndex, prScanParam->fgIsObssScan, eScanStatus, ucSeqNum); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_DONE)); ++ if (!prScanDoneMsg) { ++ ASSERT(0); /* Can't indicate SCAN FSM Complete */ ++ return; ++ } ++ ++ if (prScanParam->fgIsObssScan == TRUE) { ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_RLM_SCAN_DONE; ++ } else { ++ switch ((ENUM_NETWORK_TYPE_INDEX_T) ucNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_AIS_SCAN_DONE; ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case NETWORK_TYPE_P2P_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_P2P_SCAN_DONE; ++ break; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ case NETWORK_TYPE_BOW_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_BOW_SCAN_DONE; ++ break; ++#endif ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ prScanDoneMsg->ucSeqNum = ucSeqNum; ++ prScanDoneMsg->ucNetTypeIndex = ucNetTypeIndex; ++ prScanDoneMsg->eScanStatus = eScanStatus; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanDoneMsg, MSG_SEND_METHOD_BUF); ++ ++} /* end of scnFsmGenerateScanDoneMsg() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Query for most sparse channel ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prScanInfo->fgIsSparseChannelValid == TRUE) { ++ if (prSparseBand) ++ *prSparseBand = prScanInfo->rSparseChannel.eBand; ++ ++ if (pucSparseChannel) ++ *pucSparseChannel = prScanInfo->rSparseChannel.ucChannelNum; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Event handler for NLO done event ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ if (prScanInfo->fgNloScanning == TRUE) { ++ DBGLOG(SCN, INFO, "scnEventNloDone Current State = %d\n", prScanInfo->eCurrentState); ++ ++ kalSchedScanResults(prAdapter->prGlueInfo); ++ ++ if (prNloParam->fgStopAfterIndication == TRUE) ++ prScanInfo->fgNloScanning = FALSE; ++ ++ kalMemZero(&prNloParam->aprPendingBssDescToInd[0], ++ CFG_SCAN_SSID_MATCH_MAX_NUM * sizeof(P_BSS_DESC_T)); ++ } else { ++ DBGLOG(SCN, INFO, "Unexpected NLO-DONE event\n"); ++ } ++ ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for starting scheduled scan ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSsidNum, ++ IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ P_CMD_NLO_REQ prCmdNloReq; ++ UINT_32 i, j; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ if (prScanInfo->fgNloScanning) { ++ DBGLOG(SCN, INFO, "prScanInfo->fgNloScanning == TRUE already scanning\n"); ++ return TRUE; ++ } ++ ++ prScanInfo->fgNloScanning = TRUE; ++ ++ /* 1. load parameters */ ++ prScanParam->ucSeqNum++; ++ /* prScanParam->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; */ ++ ++ prNloParam->fgStopAfterIndication = TRUE; ++ prNloParam->ucFastScanIteration = 0; ++ prNloParam->u2FastScanPeriod = u2Interval; ++ prNloParam->u2SlowScanPeriod = u2Interval; ++ ++ if (prScanParam->ucSSIDNum > CFG_SCAN_SSID_MAX_NUM) ++ prScanParam->ucSSIDNum = CFG_SCAN_SSID_MAX_NUM; ++ else ++ prScanParam->ucSSIDNum = ucSsidNum; ++ ++ if (prNloParam->ucMatchSSIDNum > CFG_SCAN_SSID_MATCH_MAX_NUM) ++ prNloParam->ucMatchSSIDNum = CFG_SCAN_SSID_MATCH_MAX_NUM; ++ else ++ prNloParam->ucMatchSSIDNum = ucSsidNum; ++ ++ for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { ++ if (i < CFG_SCAN_SSID_MAX_NUM) { ++ COPY_SSID(prScanParam->aucSpecifiedSSID[i], ++ prScanParam->ucSpecifiedSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); ++ } ++ ++ COPY_SSID(prNloParam->aucMatchSSID[i], ++ prNloParam->ucMatchSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); ++ ++ prNloParam->aucCipherAlgo[i] = 0; ++ prNloParam->au2AuthAlgo[i] = 0; ++ ++ for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) ++ prNloParam->aucChannelHint[i][j] = 0; ++ } ++ ++ /* 2. prepare command for sending */ ++ prCmdNloReq = (P_CMD_NLO_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_NLO_REQ) + prScanParam->u2IELen); ++ ++ if (!prCmdNloReq) { ++ ASSERT(0); /* Can't initiate NLO operation */ ++ return FALSE; ++ } ++ ++ /* 3. send command packet for NLO operation */ ++ kalMemZero(prCmdNloReq, sizeof(CMD_NLO_REQ)); ++ ++ prCmdNloReq->ucSeqNum = prScanParam->ucSeqNum; ++ /* prCmdNloReq->ucBssIndex = prScanParam->ucBssIndex; */ ++ ++ prCmdNloReq->ucNetworkType = prScanParam->eNetTypeIndex; ++ prCmdNloReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ ++ prCmdNloReq->fgStopAfterIndication = prNloParam->fgStopAfterIndication; ++ prCmdNloReq->ucFastScanIteration = prNloParam->ucFastScanIteration; ++ prCmdNloReq->u2FastScanPeriod = prNloParam->u2FastScanPeriod; ++ prCmdNloReq->u2SlowScanPeriod = prNloParam->u2SlowScanPeriod; ++ prCmdNloReq->ucEntryNum = prNloParam->ucMatchSSIDNum; ++ for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { ++ COPY_SSID(prCmdNloReq->arNetworkList[i].aucSSID, ++ prCmdNloReq->arNetworkList[i].ucSSIDLength, ++ prNloParam->aucMatchSSID[i], prNloParam->ucMatchSSIDLen[i]); ++ ++ prCmdNloReq->arNetworkList[i].ucCipherAlgo = prNloParam->aucCipherAlgo[i]; ++ prCmdNloReq->arNetworkList[i].u2AuthAlgo = prNloParam->au2AuthAlgo[i]; ++ ++ for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) ++ prCmdNloReq->arNetworkList[i].ucNumChannelHint[j] = prNloParam->aucChannelHint[i][j]; ++ } ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdNloReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdNloReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdNloReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdNloReq->u2IELen); ++#if !CFG_SUPPORT_GSCN ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NLO_REQ, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_NLO_REQ) + prCmdNloReq->u2IELen, (PUINT_8) prCmdNloReq, NULL, 0); ++ ++#else ++ scnPSCNFsm(prAdapter, PSCN_RESET, prCmdNloReq, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE); ++#endif ++ cnmMemFree(prAdapter, (PVOID) prCmdNloReq); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for stopping scheduled scan ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ CMD_NLO_CANCEL rCmdNloCancel; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ /* send cancel message to firmware domain */ ++ rCmdNloCancel.ucSeqNum = prScanParam->ucSeqNum; ++ ++#if !CFG_SUPPORT_GSCN ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NLO_CANCEL, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetStopSchedScan, ++ nicOidCmdTimeoutCommon, sizeof(CMD_NLO_CANCEL), (PUINT_8)(&rCmdNloCancel), NULL, 0); ++#else ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, TRUE, FALSE, FALSE, FALSE); ++#endif ++ ++ prScanInfo->fgNloScanning = FALSE; ++ ++ return TRUE; ++} ++ ++#if CFG_SUPPORT_GSCN ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set PSCN action ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct) ++{ ++ CMD_SET_PSCAN_ENABLE rCmdPscnAction; ++ P_SCAN_INFO_T prScanInfo; ++ ++ DBGLOG(SCN, TRACE, "scnFsmPSCNAction Act = %d\n", ucPscanAct); ++ ++ rCmdPscnAction.ucPscanAct = ucPscanAct; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (ucPscanAct == DISABLE) ++ prScanInfo->fgPscnOnnning = FALSE; ++ if (ucPscanAct == ENABLE) ++ prScanInfo->fgPscnOnnning = TRUE; ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ENABLE, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_ENABLE), (PUINT_8) &rCmdPscnAction, NULL, 0); ++ ++ DBGLOG(SCN, INFO, "scnFsmPSCNAction Act = %d is Set to FW\n", ucPscanAct); ++ return TRUE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set PSCN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ UINT_8 i, j; ++ ++ i = 0; ++ j = 0; ++ ++ ASSERT(prAdapter); ++ /*prCmdPscnParam->u4BasePeriod = prCmdPscnParam->u4BasePeriod;*/ ++#if 0 ++ DBGLOG(SCN, TRACE, ++ "rCmdPscnParam: Period[%u],NumCache[%u],Threshold[%u],NumBkts[%u],fgGSCN[%d] fgNLO[%d] fgBatch[%d]\n", ++ prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, ++ prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, prCmdPscnParam->fgBatchScnEnable)); ++ ++ for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { ++ DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); ++ DBGLOG(SCN, TRACE, ++ "band[%u], Index[%u] NumChannels[%u], ucBktFreqMultiple[%u] Flag[%u]\n", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); ++ for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) ++ DBGLOG(SCN, TRACE, ++ " %d, ", prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); ++ DBGLOG(SCN, TRACE, "\n"); ++ } ++#endif ++ ++ if (1 /*prScanInfo->fgPscnOnnning == FALSE */) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCAN_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_PARAM), (PUINT_8) prCmdPscnParam, NULL, 0); ++ ++ DBGLOG(SCN, TRACE, "CMD_ID_SET_PSCAN_PARAM is set to FW !!!!!!!!!!\n"); ++ return TRUE; ++ } ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set hotlist ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID prCmdPscnAddHotlist) ++{ ++ CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ memcpy(&rCmdPscnAddHotlist.aucMacAddr, &(prCmdPscnAddHotlist->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ /* rCmdPscnAddHotlist.aucMacAddr = prCmdPscnAddHotlist->aucMacAddr; */ ++ rCmdPscnAddHotlist.ucFlags = prCmdPscnAddHotlist->ucFlags; ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_SET_PSCAN_ADD_HOTLIST_BSSID), (PUINT_8) &rCmdPscnAddHotlist, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_ADD_SW_BSSID ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId) ++{ ++ CMD_SET_PSCAN_ADD_SWC_BSSID rCmdPscnAddSWCBssId; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ memcpy(&rCmdPscnAddSWCBssId.aucMacAddr, &(prCmdPscnAddSWCBssId->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ /* rCmdPscnAddSWCBssId.aucMacAddr = prCmdPscnAddSWCBssId->aucMacAddr; */ ++ rCmdPscnAddSWCBssId.i4RssiHighThreshold = prCmdPscnAddSWCBssId->i4RssiHighThreshold; ++ rCmdPscnAddSWCBssId.i4RssiLowThreshold = prCmdPscnAddSWCBssId->i4RssiLowThreshold; ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ADD_SW_BSSID, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_SET_PSCAN_ADD_SWC_BSSID), (PUINT_8) &rCmdPscnAddSWCBssId, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr) ++{ ++ CMD_SET_PSCAN_MAC_ADDR rCmdPscnSetMacAddr; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ /* rCmdPscnSetMacAddr.aucMacAddr = prCmdPscnSetMacAddr->aucMacAddr; */ ++ memcpy(&rCmdPscnSetMacAddr.aucMacAddr, &(prCmdPscnSetMacAddr->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ rCmdPscnSetMacAddr.ucFlags = prCmdPscnSetMacAddr->ucFlags; ++ rCmdPscnSetMacAddr.ucVersion = prCmdPscnSetMacAddr->ucVersion; ++ ++ if (1 /* (prScanInfo->fgPscnOnnning == TRUE */) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_MAC_ADDR, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_SET_PSCAN_MAC_ADDR), (PUINT_8) &rCmdPscnSetMacAddr, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set GSCN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam) ++{ ++ /*CMD_GSCN_REQ_T rCmdGscnParam;*/ ++ P_CMD_GSCN_REQ_T rCmdGscnParamp; ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 ucChannelBuckIndex; ++ UINT_8 i; ++ ++ ASSERT(prAdapter); ++ rCmdGscnParamp = kalMemAlloc(sizeof(CMD_GSCN_REQ_T), VIR_MEM_TYPE); ++ if (rCmdGscnParamp == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdGscnParam fail\n"); ++ return TRUE; ++ } ++ kalMemZero(rCmdGscnParamp, sizeof(CMD_GSCN_REQ_T)); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ rCmdGscnParamp->u4NumBuckets = prCmdGscnParam->num_buckets; ++ rCmdGscnParamp->u4BasePeriod = prCmdGscnParam->base_period; ++ DBGLOG(SCN, INFO, ++ "u4BasePeriod[%d], u4NumBuckets[%d]\n", rCmdGscnParamp->u4BasePeriod, rCmdGscnParamp->u4NumBuckets); ++ for (ucChannelBuckIndex = 0; ucChannelBuckIndex < prCmdGscnParam->num_buckets; ucChannelBuckIndex++) { ++ DBGLOG(SCN, TRACE, "assign channels to bucket[%d]\n", ucChannelBuckIndex); ++ for (i = 0; i < prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; i++) { ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel = ++ (UINT_8) nicFreq2ChannelNum(prCmdGscnParam->buckets[ucChannelBuckIndex]. ++ channels[i].channel * 1000); ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive = ++ (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].passive; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs = ++ (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].dwellTimeMs; ++ ++ DBGLOG(SCN, TRACE, "[ucChannel %d, ucPassive %d, u4DwellTimeMs %d\n", ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel, ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive, ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs); ++ ++ } ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].u2BucketIndex = ++ (UINT_16) prCmdGscnParam->buckets[ucChannelBuckIndex].bucket; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].eBand = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].band; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucBucketFreqMultiple = ++ (prCmdGscnParam->buckets[ucChannelBuckIndex].period / prCmdGscnParam->base_period); ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucNumChannels = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucReportFlag = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].report_events; ++ ++ /* printk("\n"); */ ++ } ++ ++ DBGLOG(SCN, INFO, "scnSetGSCNParam ---> scnPSCNFsm PSCN_RESET\n"); ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, rCmdGscnParamp, NULL, FALSE, FALSE, FALSE, FALSE); ++ kalMemFree(rCmdGscnParamp, VIR_MEM_TYPE, sizeof(CMD_GSCN_REQ_T)); ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine PNO Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineNLOtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prNewCmdNloReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prNewCmdNloReq) { ++ prCmdPscnParam->fgNLOScnEnable = TRUE; ++ memcpy(&prCmdPscnParam->rCmdNloReq, prNewCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } else if (prScanInfo->prPscnParam->fgNLOScnEnable) { ++ memcpy(&prCmdPscnParam->rCmdNloReq, &prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } else ++ prCmdPscnParam->fgNLOScnEnable = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine Batcht Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineBatchSCNtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prNewCmdBatchReq) { ++ prCmdPscnParam->fgBatchScnEnable = TRUE; ++ memcpy(&prCmdPscnParam->rCmdBatchReq, prNewCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ } else if (prScanInfo->prPscnParam->fgBatchScnEnable) { ++ memcpy(&prCmdPscnParam->rCmdBatchReq, &prScanInfo->prPscnParam->rCurrentCmdBatchReq, ++ sizeof(CMD_BATCH_REQ_T)); ++ } else ++ prCmdPscnParam->fgBatchScnEnable = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineGSCNtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_32 ucPeriodMin = MAX_PERIOD; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prCmdPscnParam->fgGScnEnable = FALSE; ++ ++ DBGLOG(SCN, TRACE, "scnSubCombineGSCNtoPSCN fgGScnParamSet %d fgGScnConfigSet %d\n", ++ prScanInfo->fgGScnParamSet, prScanInfo->fgGScnConfigSet); ++ ++ if (prNewCmdGscnReq) { ++ DBGLOG(SCN, INFO, "setup prNewCmdGscnReq\n"); ++ prScanInfo->fgGScnParamSet = TRUE; ++ memcpy(&prCmdPscnParam->rCmdGscnReq, prNewCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ if (ucPeriodMin > prNewCmdGscnReq->u4BasePeriod) ++ prCmdPscnParam->u4BasePeriod = prNewCmdGscnReq->u4BasePeriod; ++ } else if (prScanInfo->fgGScnParamSet) { ++ DBGLOG(SCN, INFO, "no new prNewCmdGscnReq but there is a old one\n"); ++ memcpy(&prCmdPscnParam->rCmdGscnReq, &prScanInfo->prPscnParam->rCurrentCmdGscnReq, ++ sizeof(CMD_GSCN_REQ_T)); ++ prCmdPscnParam->u4BasePeriod = prScanInfo->prPscnParam->u4BasePeriod; ++ } else ++ prScanInfo->fgGScnParamSet = FALSE; ++ ++ if (prNewCmdGscnConfig) { ++ DBGLOG(SCN, INFO, "set up prNewCmdGscnConfig\n"); ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prScanInfo->fgGScnConfigSet = TRUE; ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = prNewCmdGscnConfig->u4BufferThreshold; ++ prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = (UINT_8) prNewCmdGscnConfig->u4NumScnToCache; ++ } else if (prScanInfo->fgGScnConfigSet) { ++ DBGLOG(SCN, INFO, "no new prNewCmdGscnConfig but there is a old one\n"); ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = ++ prScanInfo->prPscnParam->rCurrentCmdGscnReq.u4BufferThreshold; ++ prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = ++ (UINT_8) prScanInfo->prPscnParam->rCurrentCmdGscnReq.ucNumScnToCache; ++ } else ++ prScanInfo->fgGScnConfigSet = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnRemoveFromPSCN(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, ++ IN BOOLEAN fgRemoveGSCNfromPSCN, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 ucPscanAct = DISABLE; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ { ++ DBGLOG(SCN, INFO, "remove NLO or Batch or GSCN from PSCN--->NLO=%d, BSN=%d, GSN=%d\n", ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); ++ ++ if (fgRemoveNLOfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgNLOScnEnable = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdNloReq, sizeof(CMD_NLO_REQ)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } ++ if (fgRemoveBatchSCNfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgBatchScnEnable = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ } ++ if (fgRemoveGSCNfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgGScnEnable = FALSE; ++ prScanInfo->fgGScnParamSet = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ } ++ ++ if (!fgRemoveNLOfromPSCN && !fgRemoveBatchSCNfromPSCN && !fgRemoveGSCNfromPSCN) { ++ /* prCmdPscnParam->fgIsPeriodicallyScn = FALSE; */ ++ prScanInfo->fgPscnOnnning = FALSE; ++ scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); ++ scnFsmPSCNAction(prAdapter, ucPscanAct); ++ } else { ++ /* prCmdPscnParam->fgIsPeriodicallyScn = TRUE; */ ++ scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); ++ DBGLOG(SCN, INFO, " disable NLO or GSCN or Batch but fgIsPeriodicallyScn = TRUE <-----\n"); ++ } ++ } ++ ++} ++ ++#if 1 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN , Batch, PNO Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN ++scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prNewCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ /* CMD_SET_PSCAN_PARAM rCmdPscnParam; */ ++ P_CMD_SET_PSCAN_PARAM prCmdPscnParam; ++ /* UINT_8 i, j = 0; */ ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prCmdPscnParam = (P_CMD_SET_PSCAN_PARAM) kalMemAlloc(sizeof(CMD_SET_PSCAN_PARAM), VIR_MEM_TYPE); ++ if (!prCmdPscnParam) { ++ DBGLOG(SCN, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); ++ return -ENOMEM; ++ } ++ kalMemZero(prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ ++ prCmdPscnParam->ucVersion = CURRENT_PSCN_VERSION; ++ ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ scnRemoveFromPSCN(prAdapter, ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN, prCmdPscnParam); ++ } else { ++ DBGLOG(SCN, INFO, "combine GSCN or Batch or NLO to PSCN --->\n"); ++ ++ scnSubCombineNLOtoPSCN(prAdapter, prNewCmdNloReq, prCmdPscnParam); ++ scnSubCombineBatchSCNtoPSCN(prAdapter, prNewCmdBatchReq, prCmdPscnParam); ++ if (prNewCmdGscnReq) ++ scnSubCombineGSCNtoPSCN(prAdapter, prNewCmdGscnReq, NULL, prCmdPscnParam); ++ if (prNewCmdGscnConfig) ++ scnSubCombineGSCNtoPSCN(prAdapter, NULL, prNewCmdGscnConfig, prCmdPscnParam); ++ /* scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); */ ++ ++#if 0 ++ DBGLOG(SCN, TRACE, "combine GSCN or Batch or NLO to PSCN <--- rCmdPscnParam\n"); ++ DBGLOG(SCN, TRACE, ++ "Period[%u], NumCache[%u], Threshold[%u], NumBuckets[%u],GSCNEn[%d] NLOEn[%d] BatchEn[%d]\n", ++ prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, ++ prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, ++ prCmdPscnParam->fgBatchScnEnable)); ++ ++ for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { ++ DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); ++ DBGLOG(SCN, TRACE, ++ "band[%u], ChnBkt[%u] NumChns[%u], BktFreqMltpl[%u] Flag[%u]\n", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); ++ for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) { ++ DBGLOG(SCN, TRACE, " %d, ", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); ++ } ++ DBGLOG(SCN, TRACE, "\n"); ++ } ++#endif ++ } ++ ++ memcpy(prScanInfo->prPscnParam, prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ kalMemFree(prCmdPscnParam, VIR_MEM_TYPE, sizeof(CMD_SET_PSCAN_PARAM)); ++ return TRUE; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig) ++{ ++ CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; ++ ++ ASSERT(prAdapter); ++ memcpy(&rCmdGscnScnConfig, prCmdGscnScnConfig, sizeof(CMD_GSCN_SCN_COFIG_T)); ++ DBGLOG(SCN, TRACE, "rCmdGscnScnConfig: u4BufferThreshold; [%d] ucNumApPerScn [%d] ucNumScnToCache [%d]\n", ++ rCmdGscnScnConfig.u4BufferThreshold, ++ rCmdGscnScnConfig.ucNumApPerScn, ++ rCmdGscnScnConfig.u4NumScnToCache); ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, &rCmdGscnScnConfig, FALSE, FALSE, FALSE, FALSE); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd) ++{ ++ CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultCmd, sizeof(CMD_GET_GSCAN_RESULT_T)); ++ DBGLOG(SCN, INFO, "rGetGscnScnResultCmd: ucGetNum [%d] fgFlush [%d]\n", ++ rGetGscnScnResultCmd.u4Num, rGetGscnScnResultCmd.ucFlush); ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_GSCN_SCN_RESULT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_GET_GSCAN_RESULT_T), (PUINT_8) &rGetGscnScnResultCmd, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN GSCN ongoing ??? */ ++ return FALSE; ++ ++} ++ ++VOID ++scnPSCNFsm(IN P_ADAPTER_T prAdapter, ++ ENUM_PSCAN_STATE_T eNextPSCNState, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ BOOLEAN fgTransitionState = FALSE; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ do { ++ fgTransitionState = FALSE; ++ ++ DBGLOG(SCN, STATE, "eCurrentPSCNState=%d, eNextPSCNState=%d\n", ++ prScanInfo->eCurrentPSCNState, eNextPSCNState); ++ ++ switch (prScanInfo->eCurrentPSCNState) { ++ case PSCN_IDLE: ++ if (eNextPSCNState == PSCN_RESET) { ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ DBGLOG(SCN, TRACE, "Unexpected remove NLO/BATCH/GSCN request\n"); ++ eNextPSCNState = PSCN_IDLE; ++ break; ++ } ++ ++ if (prCmdNloReq || prCmdBatchReq) { ++ DBGLOG(SCN, TRACE, "PSCN_IDLE->PSCN_RESET,.... scnFsmPSCNActionDISABLE\n"); ++ /*TBD check PSCAN is ongoing */ ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ } else if (eNextPSCNState == PSCN_SCANNING) { ++ if (fgEnableGSCN) { ++ if (prScanInfo->fgPscnOnnning) ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ if (prScanInfo->fgGScnParamSet) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_IDLE->PSCN_SCANNING,.... scnFsmPSCNActionENABLE\n"); ++ prScanInfo->prPscnParam->fgGScnEnable = TRUE; ++ scnFsmPSCNSetParam(prAdapter, ++ (P_CMD_SET_PSCAN_PARAM)prScanInfo->prPscnParam); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ eNextPSCNState = PSCN_SCANNING; ++ } ++ } ++ } ++ break; ++ ++ case PSCN_RESET: ++ scnCombineParamsIntoPSCN(prAdapter, ++ prCmdNloReq, ++ prCmdBatchReq, ++ prCmdGscnReq, ++ prNewCmdGscnConfig, ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); ++ ++ if (!prScanInfo->prPscnParam->fgNLOScnEnable && !prScanInfo->prPscnParam->fgBatchScnEnable ++ && !prScanInfo->prPscnParam->fgGScnEnable) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_RESET->PSCN_IDLE,.... fgNLOScnEnable/fgBatchScnEnable/fgGScnEnable false\n"); ++ eNextPSCNState = PSCN_IDLE; ++ } else { ++ if (prScanInfo->prPscnParam->fgNLOScnEnable ++ || prScanInfo->prPscnParam->fgBatchScnEnable) { ++ scnFsmPSCNSetParam(prAdapter, (P_CMD_SET_PSCAN_PARAM) prScanInfo->prPscnParam); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ eNextPSCNState = PSCN_SCANNING; ++ DBGLOG(SCN, TRACE, ++ "PSCN_RESET->PSCN_SCANNING,.... fgNLOScnEnable/fgBatchScnEnable ENABLE\n"); ++ } ++ } ++ break; ++ ++ case PSCN_SCANNING: ++ if (eNextPSCNState == PSCN_RESET) { ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_RESET,.... fgRemoveNLOfromPSCN/fgRemoveBatchSCNfromPSCN/fgRemoveGSCNfromPSCN\n"); ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ if (prCmdNloReq || prCmdBatchReq || prCmdGscnReq || prNewCmdGscnConfig) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_RESET,.... prCmdNloReq/prCmdBatchReq/prCmdGscnReq/prNewCmdGscnConfig\n"); ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ } else if (eNextPSCNState == PSCN_SCANNING) { ++ if (fgEnableGSCN) { ++ if (prScanInfo->prPscnParam->fgGScnEnable && (!prScanInfo->fgPscnOnnning)) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); ++ /* scnFsmPSCNAction(prAdapter, ENABLE); */ ++ eNextPSCNState = PSCN_SCANNING; ++ } else { ++ ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); ++ } ++ } ++ } ++ eNextPSCNState = PSCN_SCANNING; ++ break; ++ ++ default: ++ DBGLOG(SCN, WARN, "Unexpected state\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ DBGLOG(SCN, STATE, "eCurrentState %d , eNextPSCNState %d\n", ++ prScanInfo->eCurrentPSCNState, eNextPSCNState); ++ if (prScanInfo->eCurrentPSCNState != eNextPSCNState) ++ fgTransitionState = TRUE; ++ ++ prScanInfo->eCurrentPSCNState = eNextPSCNState; ++ } while (fgTransitionState); ++ ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c +new file mode 100644 +index 000000000000..29eb8d4e7d92 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c +@@ -0,0 +1,1112 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/sec_fsm.c#1 ++*/ ++ ++/*! \file "sec_fsm.c" ++ \brief This is the file implement security check state machine. ++ ++ In security module, do the port control check after success join to an AP, ++ and the path to NORMAL TR, the state machine handle these state transition. ++*/ ++ ++/* ++** Log: sec_fsm.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error ++ * fixed the kclocwork error. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 19 2010 wh.su ++ * ++ * fixed the compilng error at debug mode. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 13 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the Klocwork error and refine the class error message. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 13 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * fixed the compiling warning ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine some code ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine the code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * code refine ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function name ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the state machine, to meet the firmware security design v1.1 ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_RSN_MIGRATION ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugSecState[SEC_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("SEC_STATE_INIT"), ++ (PUINT_8) DISP_STRING("SEC_STATE_INITIATOR_PORT_BLOCKED"), ++ (PUINT_8) DISP_STRING("SEC_STATE_RESPONDER_PORT_BLOCKED"), ++ (PUINT_8) DISP_STRING("SEC_STATE_CHECK_OK"), ++ (PUINT_8) DISP_STRING("SEC_STATE_SEND_EAPOL"), ++ (PUINT_8) DISP_STRING("SEC_STATE_SEND_DEAUTH"), ++ (PUINT_8) DISP_STRING("SEC_STATE_COUNTERMEASURE"), ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do initialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the STA record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++#if 1 /* MT6620 */ ++ /* At MT5921, is ok, but at MT6620, firmware base ASIC, the firmware */ ++ /* will lost these data, thus, driver have to keep the wep material and */ ++ /* setting to firmware while awake from D3. */ ++#endif ++ ++ prSecInfo->eCurrentState = SEC_STATE_INIT; ++ ++ prSecInfo->fg2nd1xSend = FALSE; ++ prSecInfo->fgKeyStored = FALSE; ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ prAisSpecBssInfo->u4RsnaLastMICFailTime = 0; ++ prAisSpecBssInfo->fgCheckEAPoLTxDone = FALSE; ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEapolTxTimeout, (ULONG) prSta); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEndOfCounterMeasure, (ULONG) prSta); ++ ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do uninitialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the STA record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID /* whsu:Todo: */ ++secFsmUnInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++ prSecInfo->fg2nd1xSend = FALSE; ++ prSecInfo->fgKeyStored = FALSE; ++ ++ /* nicPrivacyRemoveWlanTable(prSta->ucWTEntry); */ ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); ++ cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* STANDBY to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INIT to INITIATOR_PORT_BLOCKED. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_INITIATOR_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INIT to RESPONDER_PORT_BLOCKED. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_RESPONDER_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INITIATOR_PORT_BLOCKED to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INITIATOR_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* RESPONDER_PORT_BLOCKED to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_RESPONDER_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* CHECK_OK to SEND_EAPOL ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_CHECK_OK_to_SEND_EAPOL(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(prSta); ++ ++ prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ ASSERT(prAisBssInfo); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prAisBssInfo->fgCheckEAPoLTxDone = TRUE; ++ ++ /* cnmTimerStartTimer(prAdapter, */ ++ /* &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer, */ ++ /* SEC_TO_MSEC(EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC)); */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_EAPOL to SEND_DEAUTH. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_SEND_EAPOL_to_SEND_DEAUTH(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Compose deauth frame to AP, a call back function for tx done */ ++ if (authSendDeauthFrame(prAdapter, ++ prSta, ++ (P_SW_RFB_T) NULL, ++ REASON_CODE_MIC_FAILURE, ++ (PFN_TX_DONE_HANDLER) secFsmEventDeauthTxDone) != WLAN_STATUS_SUCCESS) { ++ ASSERT(FALSE); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_DEAUTH to COUNTERMEASURE. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_SEND_DEAUTH_to_COUNTERMEASURE(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ /* Start the 60 sec timer */ ++ cnmTimerStartTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, ++ SEC_TO_MSEC(COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_DEAUTH to COUNTERMEASURE. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_COUNTERMEASURE_to_INIT(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ /* Clear the counter measure flag */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The Core FSM engine of security module. ++* ++* \param[in] prSta Pointer to the Sta record ++* \param[in] eNextState Enum value of next sec STATE ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmSteps(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN ENUM_SEC_STATE_T eNextState) ++{ ++ P_SEC_INFO_T prSecInfo; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ASSERT(prSecInfo); ++ ++ DEBUGFUNC("secFsmSteps"); ++ do { ++ /* Do entering Next State */ ++ prSecInfo->ePreviousState = prSecInfo->eCurrentState; ++ ++ /* Do entering Next State */ ++#if DBG ++ DBGLOG(RSN, STATE, "\n %pM TRANSITION: [%s] -> [%s]\n\n", ++ prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState], apucDebugSecState[eNextState]); ++#else ++ DBGLOG(RSN, STATE, "\n %pM [%d] TRANSITION: [%d] -> [%d]\n\n", ++ prSta->aucMacAddr, DBG_RSN_IDX, prSecInfo->eCurrentState, eNextState); ++#endif ++ prSecInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++#if 0 ++ /* Do tasks of the State that we just entered */ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INIT: ++ break; ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ break; ++ case SEC_STATE_RESPONDER_PORT_BLOCKED: ++ break; ++ case SEC_STATE_CHECK_OK: ++ break; ++ case SEC_STATE_SEND_EAPOL: ++ break; ++ case SEC_STATE_SEND_DEAUTH: ++ break; ++ case SEC_STATE_COUNTERMEASURE: ++ break; ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ break; ++ } ++#endif ++ } while (fgIsTransition); ++ ++ return; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do initialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ENUM_SEC_STATE_T eNextState; ++ ++ DBGLOG(RSN, TRACE, "secFsmRunEventStart\n"); ++ ++ ASSERT(prSta); ++ ++ if (!prSta) ++ return; ++ ++ if (!IS_STA_IN_AIS(prSta)) ++ return; ++ ++ DBGLOG(RSN, TRACE, "secFsmRunEventStart for sta %pM network %d\n", ++ prSta->aucMacAddr, prSta->ucNetTypeIndex); ++ ++ prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++ secSetPortBlocked(prAdapter, prSta, TRUE); ++ ++ /* prSta->fgTransmitKeyExist = FALSE; */ ++ /* whsu:: nicPrivacySetStaDefaultWTIdx(prSta); */ ++ ++#if 1 /* Since the 1x and key can set to firmware in order, always enter the check ok state */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); ++#else ++ if (IS_STA_IN_AIS(prSta->eStaType)) { ++ if (secRsnKeyHandshakeEnabled(prAdapter) == TRUE ++#if CFG_SUPPORT_WAPI ++ || (prAdapter->rWifiVar.rConnSettings.fgWapiMode) ++#endif ++ ) { ++ prSta->fgTransmitKeyExist = FALSE; ++ /* nicPrivacyInitialize(prSta->ucNetTypeIndex); */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); ++ } else { ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT || CFG_ENABLE_BT_OVER_WIFI ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_BT_OVER_WIFI ++ else if ((prSta->eStaType == STA_TYPE_BOW_CLIENT) || (prSta->eStaType == STA_TYPE_P2P_GC)) { ++#elif CFG_ENABLE_WIFI_DIRECT ++ else if (prSta->eStaType == STA_TYPE_P2P_GC) { ++#elif CFG_ENABLE_BT_OVER_WIFI ++ else if (prSta->eStaType == STA_TYPE_BOW_CLIENT) { ++#endif ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, RESPONDER_PORT_BLOCKED); ++ } ++#endif ++ else ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); ++#endif ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++} /* secFsmRunEventStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function called by reset procedure to force the sec fsm enter ++* idle state ++* ++* \param[in] ucNetTypeIdx The Specific Network type index ++* \param[in] prSta Pointer to the Sta record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ++ DBGLOG(RSN, TRACE, "secFsmEventAbort for sta %pM network %d\n", ++ prSta->aucMacAddr, prSta->ucNetTypeIndex); ++ ++ ASSERT(prSta); ++ ++ if (!prSta) ++ return; ++ ++ if (!IS_STA_IN_AIS(prSta)) ++ return; ++ ++ prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; ++ ++ prSta->fgTransmitKeyExist = FALSE; ++ ++ secSetPortBlocked(prAdapter, prSta, TRUE); ++ ++ if (prSecInfo == NULL) ++ return; ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ if (prSecInfo->eCurrentState == SEC_STATE_SEND_EAPOL) { ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone == FALSE) { ++ DBGLOG(RSN, TRACE, "EAPOL STATE not match the flag\n"); ++ /* cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar. ++ * rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); */ ++ } ++ } ++ } ++ prSecInfo->eCurrentState = SEC_STATE_INIT; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "2nd EAPoL Tx is sending" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ /* BOOLEAN fgIsTransition = (BOOLEAN)FALSE; */ ++ ++ DEBUGFUNC("secFsmRunEvent2ndEapolTx"); ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ case SEC_STATE_CHECK_OK: ++ prSecInfo->fg2nd1xSend = TRUE; ++ break; ++ default: ++#if DBG ++ DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at [%d]\n", prSecInfo->eCurrentState); ++#endif ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEvent2ndEapolTx */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "4th EAPoL Tx is Tx done" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ P_CMD_802_11_KEY prStoredKey; ++ ++ DEBUGFUNC("secFsmRunEvent4ndEapolTx"); ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ case SEC_STATE_CHECK_OK: ++ prSecInfo->fg2nd1xSend = FALSE; ++ if (prSecInfo->fgKeyStored) { ++ prStoredKey = (P_CMD_802_11_KEY) prSecInfo->aucStoredKey; ++ ++ /* prSta = rxmLookupStaRecIndexFromTA(prStoredKey->aucPeerAddr); */ ++ /* if (nicPrivacySetKeyEntry(prStoredKey, prSta->ucWTEntry) == FALSE) */ ++ /* DBGLOG(RSN, WARN, ("nicPrivacySetKeyEntry() fail,..\n")); */ ++ ++ /* key update */ ++ prSecInfo->fgKeyStored = FALSE; ++ prSta->fgTransmitKeyExist = TRUE; ++ } ++ if (prSecInfo->eCurrentState == SEC_STATE_INITIATOR_PORT_BLOCKED) ++ SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); ++ break; ++ default: ++ ++#if DBG ++ DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at [%d]\n", prSecInfo->eCurrentState); ++#endif ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEvent4ndEapolTx */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Pairwise key installed" to SEC FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \retval TRUE The key can be installed to HW ++* \retval FALSE The kay conflict with the current key, abort it ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgStatus = TRUE; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ if (prSecInfo == NULL) ++ return TRUE; /* Not PTK */ ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAdd), ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INIT: ++ /* Legacy wep, wpa-none */ ++ break; ++ ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ if (prSecInfo->fg2nd1xSend) ++ ; ++ else ++ SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); ++ break; ++ ++ case SEC_STATE_RESPONDER_PORT_BLOCKED: ++ SEC_STATE_TRANSITION(prAdapter, prSta, RESPONDER_PORT_BLOCKED, CHECK_OK); ++ break; ++ ++ case SEC_STATE_CHECK_OK: ++ break; ++ ++ default: ++ fgStatus = FALSE; ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return fgStatus; ++ ++} /* end of secFsmRunEventPTKInstalled() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Counter Measure" to SEC FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventStartCounterMeasure"); ++ ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.u4RsnaLastMICFailTime = 0; ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_CHECK_OK: ++ { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = TRUE; ++ ++ /* dls port control */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, CHECK_OK, SEND_EAPOL); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call arbFsmSteps() when we are going to change ARB STATE */ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEventStartCounterMeasure */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "802.1x EAPoL Tx Done" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("secFsmRunEventEapolTxDone"); ++ ++ ASSERT(prStaRec); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(RSN, INFO, "Error EAPoL fram fail to send!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ if (!IS_STA_IN_AIS(prStaRec)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ ASSERT(prAisBssInfo); ++ ++ prSecInfo = &prStaRec->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_EAPOL: ++ if (prAisBssInfo->fgCheckEAPoLTxDone == FALSE) ++ ASSERT(0); ++ ++ prAisBssInfo->fgCheckEAPoLTxDone = FALSE; ++ /* cnmTimerStopTimer(prAdapter, &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer); */ ++ ++ SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_EAPOL, SEND_DEAUTH); ++ break; ++ default: ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prStaRec, eNextState); ++ ++ return; ++ ++} /* secFsmRunEventEapolTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Deauth frame Tx Done" to Sec FSM. ++* ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++* ++* \note after receive deauth frame, callback function call this ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventDeauthTxDone"); ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ if (!IS_STA_IN_AIS(prStaRec)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = (P_SEC_INFO_T) &prStaRec->rSecInfo; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_DEAUTH: ++ ++ DBGLOG(RSN, TRACE, "Set timer %d\n", COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC); ++ ++ SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_DEAUTH, COUNTERMEASURE); ++ ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++} /* secFsmRunEventDeauthTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will check the eapol error frame fail to send issue. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("secFsmRunEventEapolTxTimeout"); ++ ++ prStaRec = (P_STA_RECORD_T) ulParm; ++ ++ ASSERT(prStaRec); ++ ++ /* Todo:: How to handle the Eapol Error fail to send case? */ ++ ASSERT(0); ++ ++ return; ++ ++} /* secFsmEventEapolTxTimeout */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will stop the counterMeasure duration. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, ULONG ulParm) ++{ ++ P_STA_RECORD_T prSta; ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventEndOfCounterMeasure"); ++ ++ prSta = (P_STA_RECORD_T) ulParm; ++ ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_DEAUTH: ++ { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = FALSE; ++ ++ SEC_STATE_TRANSITION(prAdapter, prSta, COUNTERMEASURE, INIT); ++ } ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ /* Call arbFsmSteps() when we are going to change ARB STATE */ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++} /* end of secFsmRunEventEndOfCounterMeasure */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c +new file mode 100644 +index 000000000000..ab3fcc028375 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c +@@ -0,0 +1,1342 @@ ++/* ++** Id: stats.c#1 ++*/ ++ ++/*! \file stats.c ++ \brief This file includes statistics support. ++*/ ++ ++/* ++** Log: stats.c ++ * ++ * 07 17 2014 samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++#include "precomp.h" ++ ++enum EVENT_TYPE { ++ EVENT_RX, ++ EVENT_TX, ++ EVENT_TX_DONE ++}; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++static WLAN_STATUS ++statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++UINT_64 u8DrvOwnStart, u8DrvOwnEnd; ++UINT32 u4DrvOwnMax = 0; ++#define CFG_USER_LOAD 0 ++static UINT_16 su2TxDoneCfg = CFG_DHCP | CFG_ICMP | CFG_EAPOL; ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display all environment log. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4NumOfInfo, u4InfoId; ++ UINT32 u4RxErrBitmap; ++ STATS_INFO_ENV_T *prInfo; ++ UINT32 u4Total, u4RateId; ++ ++/* ++[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 ++[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) ++ TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, ++ bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) ++ RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) ++ BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) ++ OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) ++ ERR (1st: total number of tx err, 2nd ~ 7st: total number of ++ WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, ++ WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) ++ TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) ++ RX (1st: latest RCPI, 2nd: chan num) ++ BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) ++ OK (number of rx packets without error, number of rx packets to OS) ++ ERR (number of rx packets with error) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ CCK MODE (1 2 5.5 11M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) ++ MIXED MODE (number of rx packets with MCS0 ~ MCS15) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) ++ delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) ++ delay from MAC start TX to MAC TX done ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) ++ delay from HIF to MAC TX done (min, avg, max_system time for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) ++ delay from driver to MAC TX done (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) ++ delay from MAC to HIF (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) ++ delay from HIF to Driver OS (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) ++ delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) ++ delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) ++ delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) ++ Channel idle time, scan count, channel change count, empty tx quota count, ++ power save change count from active to PS, maximum delay from PS to active ++*/ ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ /*prInfo = &rStatsInfoEnv;*/ ++ prInfo = kalMemAlloc(sizeof(STATS_INFO_ENV_T), VIR_MEM_TYPE); ++ if (prInfo == NULL) { ++ DBGLOG(RX, INFO, "prInfo alloc fail"); ++ return; ++ } ++ ++ kalMemZero(prInfo, sizeof(STATS_INFO_ENV_T)); ++ ++ if (u4InBufLen > sizeof(STATS_INFO_ENV_T)) ++ u4InBufLen = sizeof(STATS_INFO_ENV_T); ++ ++ /* parse */ ++ u4NumOfInfo = *(UINT32 *) prInBuf; ++ u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); ++ ++ /* print */ ++ for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { ++ /* ++ use u4InBufLen, not sizeof(rStatsInfoEnv) ++ because the firmware version maybe not equal to driver version ++ */ ++ kalMemCopy(prInfo, prInBuf + 8, u4InBufLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prInfo->ucStaRecIdx); ++ if (prStaRec == NULL) ++ continue; ++ ++ DBGLOG(RX, INFO, " Display stats for [%pM]: %uB\n", ++ prStaRec->aucMacAddr, (UINT32) sizeof(STATS_INFO_ENV_T)); ++ ++ if (prStaRec->ucStatsGenDisplayCnt++ > 10) { ++ /* display general statistics information every 10 * (5 or 10s) */ ++ DBGLOG(RX, INFO, " TBA(0x%x %u) RBA(0x%x %u)\n", ++ prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, ++ prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize); ++ prStaRec->ucStatsGenDisplayCnt = 0; ++ } ++ ++ if (prInfo->u4TxDataCntErr == 0) { ++ DBGLOG(RX, INFO, " TOS(%u) OK(%u %u)\n", ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK); ++ } else { ++ DBGLOG(RX, INFO, " TOS(%u) OK(%u %u) ERR(%u)\n", ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, prInfo->u4TxDataCntErr); ++ DBGLOG(RX, INFO, " ERR type(%u %u %u %u %u %u)\n", ++ prInfo->u4TxDataCntErrType[0], prInfo->u4TxDataCntErrType[1], ++ prInfo->u4TxDataCntErrType[2], prInfo->u4TxDataCntErrType[3], ++ prInfo->u4TxDataCntErrType[4], prInfo->u4TxDataCntErrType[5]); ++ } ++ ++ for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4TxRateCntNonHT[u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " non-HT TRATE (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], ++ prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], ++ prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], ++ prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], ++ prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], ++ prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], ++ prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], ++ prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15]); ++ } ++ if (prInfo->u4TxRateCntNonHT[0] > 0) { ++ DBGLOG(RX, INFO, " HT TRATE (1M %u) (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); ++ } else { ++ DBGLOG(RX, INFO, " HT TRATE (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); ++ } ++ ++ if ((prStaRec->u4RxReorderFallAheadCnt != 0) || ++ (prStaRec->u4RxReorderFallBehindCnt != 0) || (prStaRec->u4RxReorderHoleCnt != 0)) { ++ DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", ++ prStaRec->u4RxReorderFallAheadCnt, ++ prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); ++ } ++ ++ if (prInfo->u4RxDataCntErr == 0) { ++ DBGLOG(RX, INFO, " ROK(%u %u)\n", ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt); ++ } else { ++ DBGLOG(RX, INFO, " ROK(%u %u) ERR(%u)\n", ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, ++ prInfo->u4RxDataCntErr); ++ } ++ ++ for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[0][u4RateId] + prInfo->u4RxRateRetryCnt[0][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[0][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, ++ " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], ++ prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15]); ++ } else { ++ DBGLOG(RX, INFO, " RCCK (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateCnt[0][15]); ++ } ++ } else { ++ if ((prInfo->u4RxRateCnt[0][0] + prInfo->u4RxRateRetryCnt[0][0]) > 0) { ++ DBGLOG(RX, INFO, " RCCK (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0]); ++ } ++ } ++ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[1][u4RateId] + prInfo->u4RxRateRetryCnt[1][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[1][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, ++ " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], ++ prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15]); ++ } else { ++ DBGLOG(RX, INFO, " ROFDM (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateCnt[1][15]); ++ } ++ } ++ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[2][u4RateId] + prInfo->u4RxRateRetryCnt[2][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[2][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " RHT\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], ++ prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7]); ++ } else { ++ DBGLOG(RX, INFO, " RHT (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateCnt[2][7]); ++ } ++ } ++ ++ /* RX drop counts */ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 20; u4RateId++) ++ u4Total += prInfo->u4NumOfRxDrop[u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " RX Drop Count: (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n" ++ " (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", ++ prInfo->u4NumOfRxDrop[0], prInfo->u4NumOfRxDrop[1], ++ prInfo->u4NumOfRxDrop[2], prInfo->u4NumOfRxDrop[3], ++ prInfo->u4NumOfRxDrop[4], prInfo->u4NumOfRxDrop[5], ++ prInfo->u4NumOfRxDrop[6], prInfo->u4NumOfRxDrop[7], ++ prInfo->u4NumOfRxDrop[8], prInfo->u4NumOfRxDrop[9], ++ prInfo->u4NumOfRxDrop[10], prInfo->u4NumOfRxDrop[11], ++ prInfo->u4NumOfRxDrop[12], prInfo->u4NumOfRxDrop[13], ++ prInfo->u4NumOfRxDrop[14], prInfo->u4NumOfRxDrop[15], ++ prInfo->u4NumOfRxDrop[16], prInfo->u4NumOfRxDrop[17], ++ prInfo->u4NumOfRxDrop[18], prInfo->u4NumOfRxDrop[19]); ++ } ++ ++ /* delay from HIF RX to HIF RX Done */ ++ if (((prInfo->u4StayIntMinHR2HRD[1] + prInfo->u4StayIntAvgHR2HRD[1] + ++ prInfo->u4StayIntMaxHR2HRD[1]) > 0) || ++ ((prInfo->u4StayIntMinHR2HRD[2] + prInfo->u4StayIntAvgHR2HRD[2] + ++ prInfo->u4StayIntMaxHR2HRD[2]) > 0)) { ++ DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], ++ prInfo->u4StayIntMaxHR2HRD[0], ++ prInfo->u4StayIntMinHR2HRD[1], prInfo->u4StayIntAvgHR2HRD[1], ++ prInfo->u4StayIntMaxHR2HRD[1], ++ prInfo->u4StayIntMinHR2HRD[2], prInfo->u4StayIntAvgHR2HRD[2], ++ prInfo->u4StayIntMaxHR2HRD[2]); ++ } else { ++ DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u)\n", ++ prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], ++ prInfo->u4StayIntMaxHR2HRD[0]); ++ } ++ ++ /* others */ ++ DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%x)\n", ++ prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, ++ prInfo->u4NumOfChanChange, prInfo->u4CurrChnlInfo); ++#if CFG_SUPPORT_THERMO_THROTTLING ++ prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; ++#endif ++ /* reset */ ++ kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); ++ kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); ++ kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); ++ prStaRec->u4StatsRxPassToOsCnt = 0; ++ prStaRec->u4RxReorderFallAheadCnt = 0; ++ prStaRec->u4RxReorderFallBehindCnt = 0; ++ prStaRec->u4RxReorderHoleCnt = 0; ++ } ++ ++ STATS_DRIVER_OWN_RESET(); ++ kalMemFree(prInfo, VIR_MEM_TYPE, sizeof(STATS_INFO_ENV_T)); ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display all environment log. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4NumOfInfo, u4InfoId; ++ UINT32 u4RxErrBitmap; ++ STATS_INFO_ENV_T rStatsInfoEnv, *prInfo; ++ ++/* ++[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 ++[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) ++ TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, ++ bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) ++ RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) ++ BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) ++ OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) ++ ERR (1st: total number of tx err, 2nd ~ 7st: total number of ++ WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, ++ WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) ++ TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) ++ RX (1st: latest RCPI, 2nd: chan num) ++ BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) ++ OK (number of rx packets without error, number of rx packets to OS) ++ ERR (number of rx packets with error) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ CCK MODE (1 2 5.5 11M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) ++ MIXED MODE (number of rx packets with MCS0 ~ MCS15) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) ++ delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) ++ delay from MAC start TX to MAC TX done ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) ++ delay from HIF to MAC TX done (min, avg, max_system time for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) ++ delay from driver to MAC TX done (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) ++ delay from MAC to HIF (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) ++ delay from HIF to Driver OS (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) ++ delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) ++ delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) ++ delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) ++ Channel idle time, scan count, channel change count, empty tx quota count, ++ power save change count from active to PS, maximum delay from PS to active ++*/ ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ prInfo = &rStatsInfoEnv; ++ kalMemZero(&rStatsInfoEnv, sizeof(rStatsInfoEnv)); ++ ++ if (u4InBufLen > sizeof(rStatsInfoEnv)) ++ u4InBufLen = sizeof(rStatsInfoEnv); ++ ++ /* parse */ ++ u4NumOfInfo = *(UINT32 *) prInBuf; ++ u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); ++ ++ /* print */ ++ for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { ++ /* ++ use u4InBufLen, not sizeof(rStatsInfoEnv) ++ because the firmware version maybe not equal to driver version ++ */ ++ kalMemCopy(&rStatsInfoEnv, prInBuf + 8, u4InBufLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, rStatsInfoEnv.ucStaRecIdx); ++ if (prStaRec == NULL) ++ continue; ++ ++ DBGLOG(RX, INFO, " Display stats V%d.%d for [%pM]: %uB %ums\n", ++ prInfo->ucFwVer[0], prInfo->ucFwVer[1], ++ (prStaRec->aucMacAddr), (UINT32) sizeof(STATS_INFO_ENV_T), ++ prInfo->u4ReportSysTime); ++ DBGLOG(RX, INFO, "TPAM(0x%x)RTS(%u %u)BA(0x%x %u)OS(%u)OK(%u %u)ERR(%u %u %u %u %u %u %u)\n", ++ prInfo->ucTxParam, ++ prInfo->fgTxIsRtsUsed, prInfo->fgTxIsRtsEverUsed, ++ prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, ++ prInfo->u4TxDataCntErr, prInfo->u4TxDataCntErrType[0], ++ prInfo->u4TxDataCntErrType[1], prInfo->u4TxDataCntErrType[2], ++ prInfo->u4TxDataCntErrType[3], prInfo->u4TxDataCntErrType[4], ++ prInfo->u4TxDataCntErrType[5])); ++ ++ DBGLOG(RX, INFO, "TRATE(%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], ++ prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], ++ prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], ++ prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], ++ prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], ++ prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], ++ prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], ++ prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15], ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7])); ++ ++ DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", ++ prStaRec->u4RxReorderFallAheadCnt, ++ prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); ++ ++ DBGLOG(RX, INFO, " RX(%u %u %u) BA(0x%x %u) OK(%u %u) ERR(%u)\n", ++ prInfo->ucRcvRcpi, prInfo->ucHwChanNum, prInfo->fgRxIsShortGI, ++ prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize, ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, prInfo->u4RxDataCntErr); ++ ++ DBGLOG(RX, INFO, " RX Free MAC DESC(%u %u %u %u %u %u) Free HIF DESC(%u %u %u %u %u %u)\n", ++ prInfo->u4RxMacFreeDescCnt[0], prInfo->u4RxMacFreeDescCnt[1], ++ prInfo->u4RxMacFreeDescCnt[2], prInfo->u4RxMacFreeDescCnt[3], ++ prInfo->u4RxMacFreeDescCnt[4], prInfo->u4RxMacFreeDescCnt[5], ++ prInfo->u4RxHifFreeDescCnt[0], prInfo->u4RxHifFreeDescCnt[1], ++ prInfo->u4RxHifFreeDescCnt[2], prInfo->u4RxHifFreeDescCnt[3], ++ prInfo->u4RxHifFreeDescCnt[4], prInfo->u4RxHifFreeDescCnt[5])); ++ ++ DBGLOG(RX, INFO, " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], ++ prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15])); ++ DBGLOG(RX, INFO, " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], ++ prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15])); ++ DBGLOG(RX, INFO, " RHT (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], ++ prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7], ++ prInfo->u4RxRateCnt[2][8], prInfo->u4RxRateRetryCnt[2][8], ++ prInfo->u4RxRateCnt[2][9], prInfo->u4RxRateRetryCnt[2][9], ++ prInfo->u4RxRateCnt[2][10], prInfo->u4RxRateRetryCnt[2][10], ++ prInfo->u4RxRateCnt[2][11], prInfo->u4RxRateRetryCnt[2][11], ++ prInfo->u4RxRateCnt[2][12], prInfo->u4RxRateRetryCnt[2][12], ++ prInfo->u4RxRateCnt[2][13], prInfo->u4RxRateRetryCnt[2][13], ++ prInfo->u4RxRateCnt[2][14], prInfo->u4RxRateRetryCnt[2][14], ++ prInfo->u4RxRateCnt[2][15], prInfo->u4RxRateRetryCnt[2][15])); ++ ++ /* delay from HIF to MAC */ ++ DBGLOG(RX, INFO, " StayIntH2M us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinH2M[0], prInfo->u4StayIntAvgH2M[0], ++ prInfo->u4StayIntMaxH2M[0], ++ prInfo->u4StayIntMinH2M[1], prInfo->u4StayIntAvgH2M[1], ++ prInfo->u4StayIntMaxH2M[1], ++ prInfo->u4StayIntMinH2M[2], prInfo->u4StayIntAvgH2M[2], ++ prInfo->u4StayIntMaxH2M[2])); ++ /* delay from MAC to TXDONE */ ++ DBGLOG(RX, INFO, " AirTime us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4AirDelayMin[0] << 5, prInfo->u4AirDelayAvg[0] << 5, ++ prInfo->u4AirDelayMax[0] << 5, ++ prInfo->u4AirDelayMin[1] << 5, prInfo->u4AirDelayAvg[1] << 5, ++ prInfo->u4AirDelayMax[1] << 5, ++ prInfo->u4TxDataCntAll, (prInfo->u4AirDelayAvg[2] << 5) / (prInfo->u4TxDataCntAll), ++ (prInfo->u4AirDelayAvg[2] << 5) / 400000)); ++ prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; ++ /* delay from HIF to TXDONE */ ++ DBGLOG(RX, INFO, " StayInt us (%u %u %u_%u) (%u %u %u_%u) (%u %u %u_%u)\n", ++ prInfo->u4StayIntMin[0], prInfo->u4StayIntAvg[0], ++ prInfo->u4StayIntMax[0], prInfo->u4StayIntMaxSysTime[0], ++ prInfo->u4StayIntMin[1], prInfo->u4StayIntAvg[1], ++ prInfo->u4StayIntMax[1], prInfo->u4StayIntMaxSysTime[1], ++ prInfo->u4StayIntMin[2], prInfo->u4StayIntAvg[2], ++ prInfo->u4StayIntMax[2], prInfo->u4StayIntMaxSysTime[2])); ++ /* delay from Driver to TXDONE */ ++ DBGLOG(RX, INFO, " StayIntD2T us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinD2T[0], prInfo->u4StayIntAvgD2T[0], ++ prInfo->u4StayIntMaxD2T[0], ++ prInfo->u4StayIntMinD2T[1], prInfo->u4StayIntAvgD2T[1], ++ prInfo->u4StayIntMaxD2T[1], ++ prInfo->u4StayIntMinD2T[2], prInfo->u4StayIntAvgD2T[2], ++ prInfo->u4StayIntMaxD2T[2])); ++ ++ /* delay from RXDONE to HIF */ ++ DBGLOG(RX, INFO, " StayIntR_M2H us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinRx[0], prInfo->u4StayIntAvgRx[0], ++ prInfo->u4StayIntMaxRx[0], ++ prInfo->u4StayIntMinRx[1], prInfo->u4StayIntAvgRx[1], ++ prInfo->u4StayIntMaxRx[1], ++ prInfo->u4StayIntMinRx[2], prInfo->u4StayIntAvgRx[2], prInfo->u4StayIntMaxRx[2])); ++ /* delay from HIF to OS */ ++ DBGLOG(RX, INFO, " StayIntR_H2D us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prStaRec->u4StayIntMinRx[0], prStaRec->u4StayIntAvgRx[0], ++ prStaRec->u4StayIntMaxRx[0], ++ prStaRec->u4StayIntMinRx[1], prStaRec->u4StayIntAvgRx[1], ++ prStaRec->u4StayIntMaxRx[1], ++ prStaRec->u4StayIntMinRx[2], prStaRec->u4StayIntAvgRx[2], ++ prStaRec->u4StayIntMaxRx[2])); ++ ++ /* count based on delay from OS to HIF */ ++ DBGLOG(RX, INFO, " StayCntD2H unit:%dms (%d %d %d %d)\n", ++ STATS_STAY_INT_D2H_CONST, ++ prInfo->u4StayIntD2HByConst[0], prInfo->u4StayIntD2HByConst[1], ++ prInfo->u4StayIntD2HByConst[2], prInfo->u4StayIntD2HByConst[3]); ++ ++ /* count based on different delay from HIF to TX DONE */ ++ DBGLOG(RX, INFO, " StayCnt unit:%dms (%d %d %d %d)\n", ++ STATS_STAY_INT_CONST, ++ prInfo->u4StayIntByConst[0], prInfo->u4StayIntByConst[1], ++ prInfo->u4StayIntByConst[2], prInfo->u4StayIntByConst[3]); ++ DBGLOG(RX, INFO, " StayCnt (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~:%d)\n", ++ 0, prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntCnt[0], ++ prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntCnt[1], ++ prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntMaxPast * 3 / 4, ++ prInfo->u4StayIntCnt[2], prInfo->u4StayIntMaxPast * 3 / 4, prInfo->u4StayIntMaxPast, ++ prInfo->u4StayIntCnt[3], prInfo->u4StayIntMaxPast, prInfo->u4StayIntCnt[4])); ++ ++ /* channel idle time */ ++ DBGLOG(RX, INFO, " Idle Time (slot): (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", ++ prInfo->au4ChanIdleCnt[0], prInfo->au4ChanIdleCnt[1], ++ prInfo->au4ChanIdleCnt[2], prInfo->au4ChanIdleCnt[3], ++ prInfo->au4ChanIdleCnt[4], prInfo->au4ChanIdleCnt[5], ++ prInfo->au4ChanIdleCnt[6], prInfo->au4ChanIdleCnt[7], ++ prInfo->au4ChanIdleCnt[8], prInfo->au4ChanIdleCnt[9])); ++ ++ /* BT coex */ ++ DBGLOG(RX, INFO, " BT coex (0x%x)\n", prInfo->u4BtContUseTime); ++ ++ /* others */ ++ DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%u) (%u) (%ums) (%uus)\n", ++ prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, ++ prInfo->u4NumOfChanChange, prStaRec->u4NumOfNoTxQuota, ++ prInfo->ucNumOfPsChange, prInfo->u4PsIntMax, u4DrvOwnMax / 1000); ++ ++ /* reset */ ++ kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); ++ kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); ++ kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); ++ prStaRec->u4StatsRxPassToOsCnt = 0; ++ prStaRec->u4RxReorderFallAheadCnt = 0; ++ prStaRec->u4RxReorderFallBehindCnt = 0; ++ prStaRec->u4RxReorderHoleCnt = 0; ++ } ++ ++ STATS_DRIVER_OWN_RESET(); ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to request firmware to feedback statistics. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ STATS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* sanity check */ ++ if (fgIsUnderSuspend == true) ++ return WLAN_STATUS_SUCCESS; /* do not request stats after early suspend */ ++ ++ /* init command buffer */ ++ prCmdContent = (STATS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = STATS_CORE_CMD_ENV_REQUEST; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_STATS, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(STATS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(RX, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return WLAN_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(RX, INFO, "%s cmd ok.\n", __func__); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle any statistics event. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ UINT32 u4EventId; ++ ++ /* sanity check */ ++/* DBGLOG(RX, INFO, */ ++/* (" %s: Rcv a event\n", __FUNCTION__)); */ ++ ++ if ((prGlueInfo == NULL) || (prInBuf == NULL)) ++ return; /* shall not be here */ ++ ++ /* handle */ ++ u4EventId = *(UINT32 *) prInBuf; ++ u4InBufLen -= 4; ++ ++/* DBGLOG(RX, INFO, */ ++/* (" %s: Rcv a event: %d\n", __FUNCTION__, u4EventId)); */ ++ ++ switch (u4EventId) { ++ case STATS_HOST_EVENT_ENV_REPORT: ++ statsInfoEnvDisplay(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to detect if we can request firmware to feedback statistics. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] ucStaRecIndex The station index ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex) ++{ ++ STA_RECORD_T *prStaRec; ++ OS_SYSTIME rCurTime; ++ STATS_CMD_CORE_T rCmd; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->u4StatsEnvTxCnt++; ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (prStaRec->rStatsEnvTxPeriodLastTime == 0) { ++ prStaRec->rStatsEnvTxLastTime = rCurTime; ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ return; ++ } ++ ++ if (prStaRec->u4StatsEnvTxCnt > STATS_ENV_TX_CNT_REPORT_TRIGGER) { ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxLastTime, ++ SEC_TO_SYSTIME(STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC))) { ++ rCmd.ucStaRecIdx = ucStaRecIndex; ++ statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); ++ ++ prStaRec->rStatsEnvTxLastTime = rCurTime; ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ prStaRec->u4StatsEnvTxCnt = 0; ++ return; ++ } ++ } ++ ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxPeriodLastTime, SEC_TO_SYSTIME(STATS_ENV_TIMEOUT_SEC))) { ++ rCmd.ucStaRecIdx = ucStaRecIndex; ++ statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); ++ ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure ++* \param[in] prSwRfb Pointer to the received packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb) ++{ ++ UINT32 u4LenId; ++ UINT32 u4CurTime, u4DifTime; ++ ++ /* sanity check */ ++ if (prStaRec == NULL) ++ return; ++ ++ /* stats: rx done count */ ++ prStaRec->u4StatsRxPassToOsCnt++; ++ ++ /* get length partition ID */ ++ u4LenId = 0; ++ if (prSwRfb->u2PacketLen < STATS_STAY_INT_BYTE_THRESHOLD) { ++ u4LenId = 0; ++ } else { ++ if ((STATS_STAY_INT_BYTE_THRESHOLD <= prSwRfb->u2PacketLen) && ++ (prSwRfb->u2PacketLen < (STATS_STAY_INT_BYTE_THRESHOLD << 1))) { ++ u4LenId = 1; ++ } else ++ u4LenId = 2; ++ } ++ ++ /* stats: rx delay */ ++ u4CurTime = kalGetTimeTick(); ++ ++ if ((u4CurTime > prSwRfb->rRxTime) && (prSwRfb->rRxTime != 0)) { ++ u4DifTime = u4CurTime - prSwRfb->rRxTime; ++ ++ if (prStaRec->u4StayIntMinRx[u4LenId] == 0) /* impossible */ ++ prStaRec->u4StayIntMinRx[u4LenId] = 0xffffffff; ++ ++ if (u4DifTime > prStaRec->u4StayIntMaxRx[u4LenId]) ++ prStaRec->u4StayIntMaxRx[u4LenId] = u4DifTime; ++ else if (u4DifTime < prStaRec->u4StayIntMinRx[u4LenId]) ++ prStaRec->u4StayIntMinRx[u4LenId] = u4DifTime; ++ ++ prStaRec->u4StayIntAvgRx[u4LenId] += u4DifTime; ++ if (prStaRec->u4StayIntAvgRx[u4LenId] != u4DifTime) ++ prStaRec->u4StayIntAvgRx[u4LenId] >>= 1; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_64 StatsEnvTimeGet(VOID) ++{ ++ /* TODO: use better API to get time to save time, jiffies unit is 10ms, too large */ ++ ++/* struct timeval tv; */ ++ ++/* do_gettimeofday(&tv); */ ++/* return tv.tv_usec + tv.tv_sec * (UINT_64)1000000; */ ++ ++ UINT_64 u8Clk; ++/* UINT32 *pClk = &u8Clk; */ ++ ++ u8Clk = sched_clock(); /* unit: naro seconds */ ++/* printk(" sched_clock() = %x %x %u\n", pClk[0], pClk[1], sizeof(jiffies)); */ ++ ++ return (UINT_64) u8Clk; /* sched_clock *//* jiffies size = 4B */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader) ++{ ++ UINT_64 u8SysTime, u8SysTimeIn; ++ UINT32 u4TimeDiff; ++ ++ u8SysTime = StatsEnvTimeGet(); ++ u8SysTimeIn = GLUE_GET_PKT_XTIME(prMsduInfo->prPacket); ++ ++/* printk(" hif: 0x%x %u %u %u\n", */ ++/* prMsduInfo->prPacket, StatsEnvTimeGet(), u8SysTime, GLUE_GET_PKT_XTIME(prMsduInfo->prPacket)); */ ++ ++ if ((u8SysTimeIn > 0) && (u8SysTime > u8SysTimeIn)) { ++ u8SysTime = u8SysTime - u8SysTimeIn; ++ u4TimeDiff = (UINT32) u8SysTime; ++ u4TimeDiff = u4TimeDiff / 1000; /* ns to us */ ++ ++ /* pass the delay between OS to us and we to HIF */ ++ if (u4TimeDiff > 0xFFFF) ++ *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) 0xFFFF; /* 65535 us */ ++ else ++ *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) u4TimeDiff; ++ ++/* printk(" u4TimeDiff: %u\n", u4TimeDiff); */ ++ } else { ++ prHwTxHeader->aucReserved[0] = 0; ++ prHwTxHeader->aucReserved[1] = 0; ++ } ++} ++ ++static VOID statsParsePktInfo(PUINT_8 pucPkt, UINT_8 status, UINT_8 eventType, P_MSDU_INFO_T prMsduInfo) ++{ ++ /* get ethernet protocol */ ++ UINT_16 u2EtherType = (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ PUINT_8 pucEthBody = &pucPkt[ETH_HLEN]; ++ ++ switch (u2EtherType) { ++ case ETH_P_ARP: ++ { ++ UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; ++ if (eventType == EVENT_TX) ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ if ((su2TxDoneCfg & CFG_ARP) == 0) ++ break; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(RX, INFO, " Arp Req From IP: %d.%d.%d.%d\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(RX, INFO, " Arp Rsp from IP: %d.%d.%d.%d\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ break; ++ case EVENT_TX: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", status, ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", status, ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ break; ++ } ++ break; ++ } ++ case ETH_P_IP: ++ { ++ UINT_8 ucIpProto = pucEthBody[9]; /* IP header without options */ ++ UINT_8 ucIpVersion = (pucEthBody[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ UINT_16 u2IpId = pucEthBody[4]<<8 | pucEthBody[5]; ++ ++ if (ucIpVersion != IPVERSION) ++ break; ++ ++ switch (ucIpProto) { ++ case IP_PRO_ICMP: ++ { ++ /* the number of ICMP packets is seldom so we print log here */ ++ UINT_8 ucIcmpType; ++ UINT_16 u2IcmpId, u2IcmpSeq; ++ PUINT_8 pucIcmp = &pucEthBody[20]; ++ ++ ucIcmpType = pucIcmp[0]; ++ /* don't log network unreachable packet */ ++ if (((su2TxDoneCfg & CFG_ICMP) == 0) || ucIcmpType == 3) ++ break; ++ u2IcmpId = *(UINT_16 *) &pucIcmp[4]; ++ u2IcmpSeq = *(UINT_16 *) &pucIcmp[6]; ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " ICMP: Type %d, Id BE 0x%04x, Seq BE 0x%04x\n", ++ ucIcmpType, u2IcmpId, u2IcmpSeq); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " ICMP: Type %d, Id 0x04%x, Seq BE 0x%04x\n", ++ ucIcmpType, u2IcmpId, u2IcmpSeq); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " Type %d, Id 0x%04x, Seq 0x%04x\n", ++ status, ucIcmpType, u2IcmpId, u2IcmpSeq); ++ break; ++ } ++ break; ++ } ++ case IP_PRO_UDP: ++ { ++ /* the number of DHCP packets is seldom so we print log here */ ++ PUINT_8 pucUdp = &pucEthBody[20]; ++ PUINT_8 pucUdpPayload = &pucUdp[8]; ++ UINT_16 u2UdpDstPort; ++ UINT_16 u2UdpSrcPort; ++ ++ u2UdpDstPort = (pucUdp[2] << 8) | pucUdp[3]; ++ u2UdpSrcPort = (pucUdp[0] << 8) | pucUdp[1]; ++ /* dhcp */ ++ if ((u2UdpDstPort == UDP_PORT_DHCPS) || (u2UdpDstPort == UDP_PORT_DHCPC)) { ++ UINT_32 u4TransID = pucUdpPayload[4]<<24 | pucUdpPayload[5]<<16 | ++ pucUdpPayload[6]<<8 | pucUdpPayload[7]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ u2IpId, pucUdpPayload[0], u4TransID); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ u2IpId, pucUdpPayload[0], u4TransID); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, ++ " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ status, u2IpId, pucUdpPayload[0], u4TransID); ++ break; ++ } ++ } else if (u2UdpDstPort == UDP_PORT_DNS) { /* tx dns */ ++ UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; ++ if (eventType == EVENT_TX) ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ if ((su2TxDoneCfg & CFG_DNS) == 0) ++ break; ++ if (eventType == EVENT_TX) { ++ DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ } else if (eventType == EVENT_TX_DONE) ++ DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", ++ status, u2IpId, u2TransId); ++ } else if (u2UdpSrcPort == UDP_PORT_DNS && eventType == EVENT_RX) { /* rx dns */ ++ UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; ++ ++ if ((su2TxDoneCfg & CFG_DNS) == 0) ++ break; ++ DBGLOG(RX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); ++ } else if ((su2TxDoneCfg & CFG_UDP) != 0) { ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " UDP: IPID 0x%04x\n", u2IpId); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", u2IpId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", status, u2IpId); ++ break; ++ } ++ } ++ break; ++ } ++ case IP_PRO_TCP: ++ if ((su2TxDoneCfg & CFG_TCP) == 0) ++ break; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " TCP: IPID 0x%04x\n", u2IpId); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", u2IpId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", status, u2IpId); ++ break; ++ } ++ break; ++ } ++ break; ++ } ++ case ETH_P_PRE_1X: ++ DBGLOG(RX, INFO, "pre-1x\n"); ++ case ETH_P_1X: ++ { ++ PUINT_8 pucEapol = pucEthBody; ++ UINT_8 ucEapolType = pucEapol[1]; ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ status, pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ } ++ break; ++ case 1: /* eapol start */ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " EAPOL: start\n"); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " EAPOL: start\n"); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " EAPOL: start\n", status); ++ break; ++ } ++ break; ++ case 3: /* key */ ++ { ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ u2KeyInfo, ++ pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ status, u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], ++ pucEapol[20], pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ } ++ ++ break; ++ } ++ } ++ break; ++ } ++ case ETH_WPI_1X: ++ { ++ UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ ++ UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; ++ UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ status, ucSubType, u2Length, u2Seq); ++ break; ++ } ++ break; ++ } ++ } ++} ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display rx packet information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsRxPktInfoDisplay(UINT_8 *pPkt) ++{ ++ statsParsePktInfo(pPkt, 0, EVENT_RX, NULL); ++#if 0 /* carefully! too many ARP */ ++ if (pucIpHdr[0] == 0x00) { /* ARP */ ++ UINT_8 *pucDstIp = (UINT_8 *) pucIpHdr; ++ ++ if (pucDstIp[7] == ARP_PRO_REQ) { ++ DBGLOG(RX, TRACE, " OS rx a arp req from %d.%d.%d.%d\n", ++ pucDstIp[14], pucDstIp[15], pucDstIp[16], pucDstIp[17]); ++ } else if (pucDstIp[7] == ARP_PRO_RSP) { ++ DBGLOG(RX, TRACE, " OS rx a arp rsp from %d.%d.%d.%d\n", ++ pucDstIp[24], pucDstIp[25], pucDstIp[26], pucDstIp[27]); ++ } ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display tx packet information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_16 u2EtherTypeLen; ++ ++ u2EtherTypeLen = (pPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ statsParsePktInfo(pPkt, 0, EVENT_TX, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle display tx packet tx done information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf) ++{ ++ EVENT_TX_DONE_STATUS_T *prTxDone; ++ ++ prTxDone = (EVENT_TX_DONE_STATUS_T *) pucEvtBuf; ++ /* ++ * Why 65 Bytes: ++ * 8B + wlanheader(40B) + hif_tx_header(16B) + 6B + 6B(LLC) - 12B ++ */ ++ statsParsePktInfo(&prTxDone->aucPktBuf[64], prTxDone->ucStatus, EVENT_TX_DONE, NULL); ++} ++ ++VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet) ++{ ++ if (fgSet) ++ su2TxDoneCfg |= u2Cfg; ++ else ++ su2TxDoneCfg &= ~u2Cfg; ++} ++ ++UINT_16 StatsGetCfgTxDone(VOID) ++{ ++ return su2TxDoneCfg; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c +new file mode 100644 +index 000000000000..67eccbda9fa8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c +@@ -0,0 +1,1170 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/swcr.c#1 ++*/ ++ ++/*! \file "swcr.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: swcr.c ++ * ++ * 06 04 2012 tsaiyuan.hsu ++ * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" ++ * resolve build waring for "WNM_UNIT_TEST not defined". ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 22 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * keep debug counter setting after wake up. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * fix debug counters of rx in driver. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters, eCurPsProf, for PS. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Fix Klockwork warning. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add swcr for test. ++ * ++* ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_SWCR ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if 0 ++SWCR_MOD_MAP_ENTRY_T g_arSwCrAllMaps[] = { ++ {SWCR_MAP_NUM(g_arRlmArSwCrMap), g_arRlmArSwCrMap}, /* 0x00nn */ ++ {0, NULL} ++}; ++#endif ++ ++UINT_32 g_au4SwCr[SWCR_CR_NUM]; /*: 0: command other: data */ ++ ++/* JB mDNS Filter*/ ++UINT_32 g_u4mDNSRXFilter = 0; /* [31] 0: stop 1: start, [3] IPv6 [2] IPv4 */ ++ ++static TIMER_T g_rSwcrDebugTimer; ++static BOOLEAN g_fgSwcrDebugTimer = FALSE; ++static UINT_32 g_u4SwcrDebugCheckTimeout; ++static ENUM_SWCR_DBG_TYPE_T g_ucSwcrDebugCheckType; ++static UINT_32 g_u4SwcrDebugFrameDumpType; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#define TEST_PS 1 ++ ++static const PFN_CMD_RW_T g_arSwCtrlCmd[] = { ++ swCtrlCmdCategory0, ++ swCtrlCmdCategory1 ++#if TEST_PS ++ , testPsCmdCategory0, testPsCmdCategory1 ++#endif ++#if CFG_SUPPORT_802_11V ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) ++ , testWNMCmdCategory0 ++#endif ++#endif ++}; ++ ++const PFN_SWCR_RW_T g_arSwCrModHandle[] = { ++ swCtrlSwCr, ++ NULL ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++enum { ++ SWCTRL_MAGIC, ++ SWCTRL_DEBUG, ++ SWCTRL_WIFI_VAR, ++ SWCTRL_ENABLE_INT, ++ SWCTRL_DISABLE_INT, ++ SWCTRL_TXM_INFO, ++ SWCTRL_RXM_INFO, ++ SWCTRL_DUMP_BSS, ++ SWCTRL_QM_INFO, ++ SWCTRL_DUMP_ALL_QUEUE_LEN, ++ SWCTRL_DUMP_MEM, ++ SWCTRL_TX_CTRL_INFO, ++ SWCTRL_DUMP_QUEUE, ++ SWCTRL_DUMP_QM_DBG_CNT, ++ SWCTRL_QM_DBG_CNT, ++ SWCTRL_RX_PKTS_DUMP, ++ SWCTRL_RX_MDNS_FILTER, ++ SWCTRL_CATA0_INDEX_NUM ++}; ++ ++enum { ++ SWCTRL_STA_INFO, ++ SWCTRL_DUMP_STA, ++ SWCTRL_STA_QUE_INFO, ++ SWCTRL_CATA1_INDEX_NUM ++}; ++ ++/* JB mDNS Filter*/ ++#define RX_MDNS_FILTER_START (1<<31) ++#define RX_MDNS_FILTER_IPV4 (1<<2) ++#define RX_MDNS_FILTER_IPV6 (1<<3) ++typedef enum _ENUM_SWCR_RX_MDNS_FILTER_CMD_T { ++ SWCR_RX_MDNS_FILTER_CMD_STOP = 0, ++ SWCR_RX_MDNS_FILTER_CMD_START, ++ SWCR_RX_MDNS_FILTER_CMD_ADD, ++ SWCR_RX_MDNS_FILTER_CMD_REMOVE, ++ SWCR_RX_MDNS_FILTER_NUM ++} ENUM_SWCR_RX_MDNS_FILTER_CMD_T; ++ ++#if TEST_PS ++enum { ++ TEST_PS_MAGIC, ++ TEST_PS_SETUP_BSS, ++ TEST_PS_ENABLE_BEACON, ++ TEST_PS_TRIGGER_BMC, ++ TEST_PS_SEND_NULL, ++ TEST_PS_BUFFER_BMC, ++ TEST_PS_UPDATE_BEACON, ++ TEST_PS_CATA0_INDEX_NUM ++}; ++ ++enum { ++ TEST_PS_STA_PS, ++ TEST_PS_STA_ENTER_PS, ++ TEST_PS_STA_EXIT_PS, ++ TEST_PS_STA_TRIGGER_PSPOLL, ++ TEST_PS_STA_TRIGGER_FRAME, ++ TEST_PS_CATA1_INDEX_NUM ++}; ++#endif ++ ++#if CFG_SUPPORT_802_11V ++#if WNM_UNIT_TEST ++enum { ++ TEST_WNM_TIMING_MEAS, ++ TEST_WNM_CATA0_INDEX_NUM ++}; ++#endif ++#endif ++ ++#define _SWCTRL_MAGIC 0x66201642 ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++void dumpQueue(P_ADAPTER_T prAdapter) ++{ ++ ++ P_TX_CTRL_T prTxCtrl; ++ P_QUE_MGT_T prQM; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i; ++ UINT_32 j; ++ ++ DEBUGFUNC("dumpQueue"); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prQM = &prAdapter->rQM; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ for (i = TC0_INDEX; i <= TC5_INDEX; i++) { ++ DBGLOG(SW4, INFO, "TC %u\n", i); ++ DBGLOG(SW4, INFO, "Max %u Free %u\n", ++ prTxCtrl->rTc.aucMaxNumOfBuffer[i], prTxCtrl->rTc.aucFreeBufferCount[i]); ++ ++ DBGLOG(SW4, INFO, "Average %u minReserved %u CurrentTcResource %u GuaranteedTcResource %u\n", ++ QM_GET_TX_QUEUE_LEN(prAdapter, i), ++ prQM->au4MinReservedTcResource[i], ++ prQM->au4CurrentTcResource[i], prQM->au4GuaranteedTcResource[i]); ++ ++ } ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { ++ DBGLOG(SW4, INFO, ++ "TC %u HeadStaIdx %u ForwardCount %u\n", i, prQM->au4HeadStaRecIndex[i], ++ prQM->au4ForwardCount[i]); ++ } ++ ++ DBGLOG(SW4, INFO, "BMC or unknown TxQueue Len %u\n", prQM->arTxQueue[0].u4NumElem); ++ DBGLOG(SW4, INFO, "Pending %d\n", prGlueInfo->i4TxPendingFrameNum); ++ DBGLOG(SW4, INFO, "Pending Security %d\n", prGlueInfo->i4TxPendingSecurityFrameNum); ++#if defined(LINUX) ++ for (i = 0; i < 4; i++) { ++ for (j = 0; j < CFG_MAX_TXQ_NUM; j++) { ++ DBGLOG(SW4, INFO, ++ "Pending Q[%u][%u] %d\n", i, j, prGlueInfo->ai4TxPendingFrameNumPerQueue[i][j]); ++ } ++ } ++#endif ++ ++ DBGLOG(SW4, INFO, " rFreeSwRfbList %u\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " rReceivedRfbList %u\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " rIndicatedRfbList %u\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " ucNumIndPacket %u\n", prAdapter->rRxCtrl.ucNumIndPacket); ++ DBGLOG(SW4, INFO, " ucNumRetainedPacket %u\n", prAdapter->rRxCtrl.ucNumRetainedPacket); ++ ++} ++ ++void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ UINT_8 ucWTEntry; ++ UINT_32 i; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("dumpSTA"); ++ ++ ASSERT(prStaRec); ++ ucWTEntry = prStaRec->ucWTEntry; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ DBGLOG(SW4, INFO, "Mac address: %pM Rcpi %u" "\n", prStaRec->aucMacAddr, prStaRec->ucRCPI); ++ ++ DBGLOG(SW4, INFO, "Idx %u Wtbl %u Used %u State %u Bss Phy 0x%x Sta DesiredPhy 0x%x\n", ++ prStaRec->ucIndex, ucWTEntry, ++ prStaRec->fgIsInUse, prStaRec->ucStaState, ++ prBssInfo->ucPhyTypeSet, prStaRec->ucDesiredPhyTypeSet); ++ ++ DBGLOG(SW4, INFO, "Sta Operation 0x%x DesiredNontHtRateSet 0x%x Mcs 0x%x u2HtCapInfo 0x%x\n", ++ prStaRec->u2OperationalRateSet, prStaRec->u2DesiredNonHTRateSet, prStaRec->ucMcsSet, ++ prStaRec->u2HtCapInfo); ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) ++ DBGLOG(SW4, INFO, "TC %u Queue Len %u\n", i, prStaRec->arTxQueue[i].u4NumElem); ++ ++ DBGLOG(SW4, INFO, "BmpDeliveryAC %x\n", prStaRec->ucBmpDeliveryAC); ++ DBGLOG(SW4, INFO, "BmpTriggerAC %x\n", prStaRec->ucBmpTriggerAC); ++ DBGLOG(SW4, INFO, "UapsdSpSupproted %u\n", prStaRec->fgIsUapsdSupported); ++ DBGLOG(SW4, INFO, "IsQoS %u\n", prStaRec->fgIsQoS); ++ DBGLOG(SW4, INFO, "AssocId %u\n", prStaRec->u2AssocId); ++ ++ DBGLOG(SW4, INFO, "fgIsInPS %u\n", prStaRec->fgIsInPS); ++ DBGLOG(SW4, INFO, "ucFreeQuota %u\n", prStaRec->ucFreeQuota); ++ DBGLOG(SW4, INFO, "ucFreeQuotaForDelivery %u\n", prStaRec->ucFreeQuotaForDelivery); ++ DBGLOG(SW4, INFO, "ucFreeQuotaForNonDelivery %u\n", prStaRec->ucFreeQuotaForNonDelivery); ++ ++#if 0 ++ DBGLOG(SW4, INFO, "IsQmmSup %u\n", prStaRec->fgIsWmmSupported); ++ DBGLOG(SW4, INFO, "IsUapsdSup %u\n", prStaRec->fgIsUapsdSupported); ++ DBGLOG(SW4, INFO, "AvailabaleDeliverPkts %u\n", prStaRec->ucAvailableDeliverPkts); ++ DBGLOG(SW4, INFO, "BmpDeliverPktsAC %u\n", prStaRec->u4BmpDeliverPktsAC); ++ DBGLOG(SW4, INFO, "BmpBufferAC %u\n", prStaRec->u4BmpBufferAC); ++ DBGLOG(SW4, INFO, "BmpNonDeliverPktsAC %u\n", prStaRec->u4BmpNonDeliverPktsAC); ++#endif ++ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { ++ if (prStaRec->aprRxReorderParamRefTbl[i]) { ++ DBGLOG(SW4, INFO, ++ "RxReorder fgIsValid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid); ++ DBGLOG(SW4, INFO, "RxReorder Tid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->ucTid); ++ DBGLOG(SW4, INFO, ++ "RxReorder rReOrderQue Len: %u\n", ++ prStaRec->aprRxReorderParamRefTbl[i]->rReOrderQue.u4NumElem); ++ DBGLOG(SW4, INFO, ++ "RxReorder WinStart: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart); ++ DBGLOG(SW4, INFO, "RxReorder WinEnd: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd); ++ DBGLOG(SW4, INFO, "RxReorder WinSize: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize); ++ } ++ } ++ ++} ++ ++VOID dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ++ DBGLOG(SW4, INFO, "SSID %s\n", prBssInfo->aucSSID); ++ DBGLOG(SW4, INFO, "OWN %pM\n", prBssInfo->aucOwnMacAddr); ++ DBGLOG(SW4, INFO, "BSSID %pM\n", prBssInfo->aucBSSID); ++ DBGLOG(SW4, INFO, "ucNetTypeIndex %u\n", prBssInfo->ucNetTypeIndex); ++ DBGLOG(SW4, INFO, "eConnectionState %u\n", prBssInfo->eConnectionState); ++ DBGLOG(SW4, INFO, "eCurrentOPMode %u\n", prBssInfo->eCurrentOPMode); ++ DBGLOG(SW4, INFO, "fgIsQBSS %u\n", prBssInfo->fgIsQBSS); ++ DBGLOG(SW4, INFO, "fgIsShortPreambleAllowed %u\n", prBssInfo->fgIsShortPreambleAllowed); ++ DBGLOG(SW4, INFO, "fgUseShortPreamble %u\n", prBssInfo->fgUseShortPreamble); ++ DBGLOG(SW4, INFO, "fgUseShortSlotTime %u\n", prBssInfo->fgUseShortSlotTime); ++ DBGLOG(SW4, INFO, "ucNonHTBasicPhyType %x\n", prBssInfo->ucNonHTBasicPhyType); ++ DBGLOG(SW4, INFO, "u2OperationalRateSet %x\n", prBssInfo->u2OperationalRateSet); ++ DBGLOG(SW4, INFO, "u2BSSBasicRateSet %x\n", prBssInfo->u2BSSBasicRateSet); ++ DBGLOG(SW4, INFO, "ucPhyTypeSet %x\n", prBssInfo->ucPhyTypeSet); ++ DBGLOG(SW4, INFO, "rStaRecOfClientList %d\n", prBssInfo->rStaRecOfClientList.u4NumElem); ++ DBGLOG(SW4, INFO, "u2CapInfo %x\n", prBssInfo->u2CapInfo); ++ DBGLOG(SW4, INFO, "u2ATIMWindow %x\n", prBssInfo->u2ATIMWindow); ++ DBGLOG(SW4, INFO, "u2AssocId %x\n", prBssInfo->u2AssocId); ++ DBGLOG(SW4, INFO, "ucDTIMPeriod %x\n", prBssInfo->ucDTIMPeriod); ++ DBGLOG(SW4, INFO, "ucDTIMCount %x\n", prBssInfo->ucDTIMCount); ++ DBGLOG(SW4, INFO, "fgIsNetAbsent %x\n", prBssInfo->fgIsNetAbsent); ++ DBGLOG(SW4, INFO, "eBand %d\n", prBssInfo->eBand); ++ DBGLOG(SW4, INFO, "ucPrimaryChannel %d\n", prBssInfo->ucPrimaryChannel); ++ DBGLOG(SW4, INFO, "ucHtOpInfo1 %d\n", prBssInfo->ucHtOpInfo1); ++ DBGLOG(SW4, INFO, "ucHtOpInfo2 %d\n", prBssInfo->u2HtOpInfo2); ++ DBGLOG(SW4, INFO, "ucHtOpInfo3 %d\n", prBssInfo->u2HtOpInfo3); ++ DBGLOG(SW4, INFO, "fgErpProtectMode %d\n", prBssInfo->fgErpProtectMode); ++ DBGLOG(SW4, INFO, "eHtProtectMode %d\n", prBssInfo->eHtProtectMode); ++ DBGLOG(SW4, INFO, "eGfOperationMode %d\n", prBssInfo->eGfOperationMode); ++ DBGLOG(SW4, INFO, "eRifsOperationMode %d\n", prBssInfo->eRifsOperationMode); ++ DBGLOG(SW4, INFO, "fgObssErpProtectMode %d\n", prBssInfo->fgObssErpProtectMode); ++ DBGLOG(SW4, INFO, "eObssHtProtectMode %d\n", prBssInfo->eObssHtProtectMode); ++ DBGLOG(SW4, INFO, "eObssGfProtectMode %d\n", prBssInfo->eObssGfOperationMode); ++ DBGLOG(SW4, INFO, "fgObssRifsOperationMode %d\n", prBssInfo->fgObssRifsOperationMode); ++ DBGLOG(SW4, INFO, "fgAssoc40mBwAllowed %d\n", prBssInfo->fgAssoc40mBwAllowed); ++ DBGLOG(SW4, INFO, "fg40mBwAllowed %d\n", prBssInfo->fg40mBwAllowed); ++ DBGLOG(SW4, INFO, "eBssSCO %d\n", prBssInfo->eBssSCO); ++ ++} ++ ++VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_32 i; ++ ++ DEBUGFUNC("swCtrlCmdCategory0"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ i = 0; ++ ++ if (ucIndex >= SWCTRL_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case SWCTRL_DEBUG: ++#if DBG ++ aucDebugModule[ucOpt0] = (UINT_8) g_au4SwCr[1]; ++#endif ++ break; ++ case SWCTRL_WIFI_VAR: ++ break; ++ ++#if QM_DEBUG_COUNTER ++ case SWCTRL_DUMP_QM_DBG_CNT: ++ for (i = 0; i < QM_DBG_CNT_NUM; i++) ++ prAdapter->rQM.au4QmDebugCounters[i] = 0; ++ break; ++ case SWCTRL_QM_DBG_CNT: ++ prAdapter->rQM.au4QmDebugCounters[ucOpt0] = g_au4SwCr[1]; ++ ++ break; ++#endif ++#if CFG_RX_PKTS_DUMP ++ case SWCTRL_RX_PKTS_DUMP: ++ /* DBGLOG(SW4, INFO,("SWCTRL_RX_PKTS_DUMP: mask %x\n", g_au4SwCr[1])); */ ++ prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = g_au4SwCr[1]; ++ break; ++#endif ++ case SWCTRL_RX_MDNS_FILTER: ++ { ++ UINT_32 u4rxfilter; ++ BOOLEAN fgUpdate = FALSE; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_STOP) { ++ g_u4mDNSRXFilter &= ~(RX_MDNS_FILTER_START); ++ ++ u4rxfilter = prAdapter->u4OsPacketFilter; ++ fgUpdate = TRUE; ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_START) { ++ g_u4mDNSRXFilter |= (RX_MDNS_FILTER_START); ++ ++ u4rxfilter = prAdapter->u4OsPacketFilter; ++ if ((g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV4) || ++ (g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV6)) { ++ u4rxfilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } ++ fgUpdate = TRUE; ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_ADD) { ++ if (ucOpt1 < 31) ++ g_u4mDNSRXFilter |= (1 << ucOpt1); ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_REMOVE) { ++ if (ucOpt1 < 31) ++ g_u4mDNSRXFilter &= ~(1 << ucOpt1); ++ } ++ ++ if (fgUpdate == TRUE) { ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_RX_FILTER, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(UINT_32), /* u4SetQueryInfoLen */ ++ (PUINT_8)&u4rxfilter, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* un4SetQueryBufferLen */ ++ ); ++ } ++/* DBGLOG(SW4, INFO,("SWCTRL_RX_MDNS_FILTER: g_u4mDNSRXFilter %x ucOpt0 %x ucOpt1 %x fgUpdate %x u4rxfilter %x, */ ++/* rStatus %x\n", g_u4mDNSRXFilter, ucOpt0, ucOpt1, fgUpdate, u4rxfilter, rStatus)); */ ++ } ++ break; ++ default: ++ break; ++ } ++ } else { ++ switch (ucIndex) { ++ case SWCTRL_DEBUG: ++#if DBG ++ g_au4SwCr[1] = aucDebugModule[ucOpt0]; ++#endif ++ break; ++ case SWCTRL_MAGIC: ++ g_au4SwCr[1] = _SWCTRL_MAGIC; ++ /* DBGLOG(SW4, INFO, "BUILD TIME: %s %s\n", __DATE__, __TIME__); */ ++ break; ++ case SWCTRL_QM_INFO: ++ { ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ switch (ucOpt0) { ++ case 0: ++ g_au4SwCr[1] = (QM_GET_TX_QUEUE_LEN(prAdapter, ucOpt1)); ++ g_au4SwCr[2] = prQM->au4MinReservedTcResource[ucOpt1]; ++ g_au4SwCr[3] = prQM->au4CurrentTcResource[ucOpt1]; ++ g_au4SwCr[4] = prQM->au4GuaranteedTcResource[ucOpt1]; ++ break; ++ ++ case 1: ++ g_au4SwCr[1] = prQM->au4ForwardCount[ucOpt1]; ++ g_au4SwCr[2] = prQM->au4HeadStaRecIndex[ucOpt1]; ++ break; ++ ++ case 2: ++ g_au4SwCr[1] = prQM->arTxQueue[ucOpt1].u4NumElem; /* only one */ ++ ++ break; ++ } ++ ++ } ++ break; ++ case SWCTRL_TX_CTRL_INFO: ++ { ++ P_TX_CTRL_T prTxCtrl; ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ switch (ucOpt0) { ++ case 0: ++ g_au4SwCr[1] = prAdapter->rTxCtrl.rTc.aucFreeBufferCount[ucOpt1]; ++ g_au4SwCr[2] = prAdapter->rTxCtrl.rTc.aucMaxNumOfBuffer[ucOpt1]; ++ break; ++ } ++ ++ } ++ break; ++ case SWCTRL_DUMP_QUEUE: ++ dumpQueue(prAdapter); ++ ++ break; ++#if QM_DEBUG_COUNTER ++ case SWCTRL_DUMP_QM_DBG_CNT: ++ for (i = 0; i < QM_DBG_CNT_NUM; i++) ++ DBGLOG(SW4, INFO, "QM:DBG %u %u\n", i, prAdapter->rQM.au4QmDebugCounters[i]); ++ break; ++ ++ case SWCTRL_QM_DBG_CNT: ++ g_au4SwCr[1] = prAdapter->rQM.au4QmDebugCounters[ucOpt0]; ++ break; ++#endif ++ case SWCTRL_DUMP_BSS: ++ { ++ dumpBss(prAdapter, &(prAdapter->rWifiVar.arBssInfo[ucOpt0])); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ } ++} ++ ++VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_8 ucWTEntry; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("swCtrlCmdCategory1"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ if (ucOpt0 >= CFG_STA_REC_NUM) ++ return; ++ ++ /* prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); */ ++ prStaRec = &prAdapter->arStaRec[ucOpt0]; ++ ucWTEntry = prStaRec->ucWTEntry; ++ if (ucRead == SWCR_WRITE) { ++ /* Do nothing */ ++ } else { ++ /* Read */ ++ switch (ucIndex) { ++ case SWCTRL_STA_QUE_INFO: ++ { ++ g_au4SwCr[1] = prStaRec->arTxQueue[ucOpt1].u4NumElem; ++ } ++ break; ++ case SWCTRL_STA_INFO: ++ switch (ucOpt1) { ++ case 0: ++ g_au4SwCr[1] = prStaRec->fgIsInPS; ++ break; ++ } ++ ++ break; ++ ++ case SWCTRL_DUMP_STA: ++ { ++ dumpSTA(prAdapter, prStaRec); ++ } ++ break; ++ ++ default: ++ ++ break; ++ } ++ } ++ ++} ++ ++#if TEST_PS ++ ++VOID ++testPsSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN UINT_8 ucUP, ++ IN UINT_8 ucNetTypeIndex, ++ IN BOOLEAN fgBMC, ++ IN BOOLEAN fgIsBurstEnd, IN BOOLEAN ucPacketType, IN BOOLEAN ucPsSessionID, IN BOOLEAN fgSetEOSP) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; ++ ++ DEBUGFUNC("testPsSendQoSNullFrame"); ++ DBGLOG(SW4, LOUD, "\n"); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SW4, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeQoSNullFrame(prAdapter, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec, ucUP, fgSetEOSP); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ /* prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; */ ++ prMsduInfo->ucPacketType = ucPacketType; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ prMsduInfo->fgIsBurstEnd = fgIsBurstEnd; ++ prMsduInfo->ucUserPriority = ucUP; ++ prMsduInfo->ucPsSessionID = ucPsSessionID /* 0~7 Test 7 means NOACK */; ++ ++ prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) (((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD)); ++ ++ if (fgBMC) ++ prQoSNullFrame->aucAddr1[0] = 0xfd; ++ else ++ prQoSNullFrame->aucAddr1[5] = 0xdd; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++} ++ ++VOID testPsSetupBss(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetworkTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; ++ ++ DEBUGFUNC("testPsSetupBss()"); ++ DBGLOG(SW4, INFO, "index %d\n", ucNetworkTypeIndex); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetworkTypeIndex]); ++ ++ /* 4 <1.2> Initiate PWR STATE */ ++ /* SET_NET_PWR_STATE_IDLE(prAdapter, ucNetworkTypeIndex); */ ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, ucNetworkTypeIndex); ++ ++ prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; ++ prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ prBssInfo->eCurrentOPMode = OP_MODE_ACCESS_POINT; ++ prBssInfo->fgIsNetActive = TRUE; ++ prBssInfo->ucNetTypeIndex = (ucNetworkTypeIndex); ++ prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->u2BSSBasicRateSet = RATE_SET_ERP; ++ prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; ++ prBssInfo->fgErpProtectMode = FALSE; ++ prBssInfo->fgIsQBSS = TRUE; ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2BeaconInterval = 100; ++ prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ prBssInfo->u2ATIMWindow = 0; ++ ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ ++ bssInitForAP(prAdapter, prBssInfo, TRUE); ++ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, _aucZeroMacAddr); ++ LINK_INITIALIZE(&prBssInfo->rStaRecOfClientList); ++ prBssInfo->fgIsBeaconActivated = TRUE; ++ prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; ++ ++ COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); ++ ++ /* 4 <3> Initiate BSS_INFO_T - private part */ ++ /* TODO */ ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = 1; ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ ++ /* prBssInfo->fgErpProtectMode = eErpProectMode; */ ++ /* prBssInfo->eHtProtectMode = eHtProtectMode; */ ++ /* prBssInfo->eGfOperationMode = eGfOperationMode; */ ++ ++ /* 4 <4> Allocate MSDU_INFO_T for Beacon */ ++ prBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prBssInfo->prBeacon) { ++ prBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prBssInfo->prBeacon->ucNetworkType = ucNetworkTypeIndex; ++ } else { ++ DBGLOG(SW4, INFO, "prBeacon allocation fail\n"); ++ } ++ ++#if 0 ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++#else ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; ++#endif ++ ++#if 0 ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prBssInfo->arACQueParms[eAci].fgIsACMSet = FALSE; ++ prBssInfo->arACQueParms[eAci].u2Aifsn = (UINT_16) eAci; ++ prBssInfo->arACQueParms[eAci].u2CWmin = 7; ++ prBssInfo->arACQueParms[eAci].u2CWmax = 31; ++ prBssInfo->arACQueParms[eAci].u2TxopLimit = eAci + 1; ++ DBGLOG(SW4, INFO, "MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prBssInfo->arACQueParms[eAci].fgIsACMSet, ++ prBssInfo->arACQueParms[eAci].u2Aifsn, ++ prBssInfo->arACQueParms[eAci].u2CWmin, ++ prBssInfo->arACQueParms[eAci].u2CWmax, prBssInfo->arACQueParms[eAci].u2TxopLimit)); ++ ++ } ++#endif ++ ++ DBGLOG(SW4, INFO, "[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, prBssInfo->rPmProfSetupInfo.ucUapsdSp); ++ ++} ++ ++VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testPsCmdCategory0"); ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ DBGLOG(SW4, LOUD, "Read %u Index %u\n", ucRead, ucIndex); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, 0); ++ ++ if (ucIndex >= TEST_PS_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case TEST_PS_SETUP_BSS: ++ testPsSetupBss(prAdapter, ucOpt0); ++ break; ++ ++ case TEST_PS_ENABLE_BEACON: ++ break; ++ ++ case TEST_PS_TRIGGER_BMC: ++ /* txmForwardQueuedBmcPkts (ucOpt0); */ ++ break; ++ case TEST_PS_SEND_NULL: ++ { ++ ++ testPsSendQoSNullFrame(prAdapter, prStaRec, (UINT_8) (g_au4SwCr[1] & 0xFF), /* UP */ ++ ucOpt0, (BOOLEAN) ((g_au4SwCr[1] >> 8) & 0xFF), /* BMC */ ++ (BOOLEAN) ((g_au4SwCr[1] >> 16) & 0xFF), /* BurstEnd */ ++ (BOOLEAN) ((g_au4SwCr[1] >> 24) & 0xFF), /* Packet type */ ++ (UINT_8) ((g_au4SwCr[2]) & 0xFF), /* PS sesson ID 7: NOACK */ ++ FALSE /* EOSP */ ++ ); ++ } ++ break; ++ case TEST_PS_BUFFER_BMC: ++ /* g_aprBssInfo[ucOpt0]->fgApToBufferBMC = (g_au4SwCr[1] & 0xFF); */ ++ break; ++ case TEST_PS_UPDATE_BEACON: ++ bssUpdateBeaconContent(prAdapter, ucOpt0 /*networktype */); ++ break; ++ ++ default: ++ break; ++ } ++ } else { ++ switch (ucIndex) { ++ ++ case TEST_PS_MAGIC: ++ g_au4SwCr[1] = 0x88660011; ++ break; ++ ++ } ++ } ++} ++ ++#endif /* TEST_PS */ ++ ++#if TEST_PS ++ ++VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_8 ucWTEntry; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testPsCmdCategory1"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ if (ucOpt0 >= CFG_STA_REC_NUM) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucOpt0); ++ if (!prStaRec) ++ return; ++ ucWTEntry = prStaRec->ucWTEntry; ++ if (ucRead == SWCR_WRITE) { ++ ++ switch (ucIndex) { ++ case TEST_PS_STA_PS: ++ prStaRec->fgIsInPS = (BOOLEAN) (g_au4SwCr[1] & 0x1); ++ prStaRec->fgIsQoS = (BOOLEAN) (g_au4SwCr[1] >> 8 & 0xFF); ++ prStaRec->fgIsUapsdSupported = (BOOLEAN) (g_au4SwCr[1] >> 16 & 0xFF); ++ prStaRec->ucBmpDeliveryAC = (BOOLEAN) (g_au4SwCr[1] >> 24 & 0xFF); ++ break; ++ ++ } ++ ++ } else { ++ /* Read */ ++ switch (ucIndex) { ++ default: ++ break; ++ } ++ } ++ ++} ++ ++#endif /* TEST_PS */ ++ ++#if CFG_SUPPORT_802_11V ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) ++VOID testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testWNMCmdCategory0"); ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ DBGLOG(SW4, INFO, "Read %u Index %u\n", ucRead, ucIndex); ++ ++ if (ucIndex >= TEST_WNM_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case TEST_WNM_TIMING_MEAS: ++ wnmTimingMeasUnitTest1(prAdapter, ucOpt0); ++ break; ++ ++ default: ++ break; ++ } ++ } ++} ++#endif /* TEST_WNM */ ++#endif /* CFG_SUPPORT_802_11V */ ++ ++VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) ++{ ++ /* According other register STAIDX */ ++ UINT_8 ucOffset; ++ ++ ucOffset = (u2Addr >> 2) & 0x3F; ++ ++ if (ucOffset >= SWCR_CR_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ g_au4SwCr[ucOffset] = *pu4Data; ++ if (ucOffset == 0x0) { ++ /* Commmand [31:24]: Category */ ++ /* Commmand [23:23]: 1(W) 0(R) */ ++ /* Commmand [22:16]: Index */ ++ /* Commmand [15:08]: Option0 */ ++ /* Commmand [07:00]: Option1 */ ++ UINT_8 ucCate; ++ UINT_32 u4Cmd; ++ ++ u4Cmd = g_au4SwCr[0]; ++ ucCate = (UINT_8) (u4Cmd >> 24); ++ if (ucCate < sizeof(g_arSwCtrlCmd) / sizeof(g_arSwCtrlCmd[0])) { ++ if (g_arSwCtrlCmd[ucCate] != NULL) { ++ g_arSwCtrlCmd[ucCate] (prAdapter, ucCate, (UINT_8) (u4Cmd >> 16 & 0xFF), ++ (UINT_8) ((u4Cmd >> 8) & 0xFF), (UINT_8) (u4Cmd & 0xFF)); ++ } ++ } ++ } ++ } else { ++ *pu4Data = g_au4SwCr[ucOffset]; ++ } ++} ++ ++VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) ++{ ++ UINT_8 ucMod; ++ ++ ucMod = u2Addr >> 8; ++ /* Address [15:8] MOD ID */ ++ /* Address [7:0] OFFSET */ ++ ++ DEBUGFUNC("swCrReadWriteCmd"); ++ DBGLOG(SW4, TRACE, "%u addr 0x%x data 0x%x\n", ucRead, u2Addr, *pu4Data); ++ ++ if (ucMod < (sizeof(g_arSwCrModHandle) / sizeof(g_arSwCrModHandle[0]))) { ++ ++ if (g_arSwCrModHandle[ucMod] != NULL) ++ g_arSwCrModHandle[ucMod] (prAdapter, ucRead, u2Addr, pu4Data); ++ } /* ucMod */ ++} ++ ++/* Debug Support */ ++VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType) ++{ ++ g_u4SwcrDebugFrameDumpType = u4DumpType; ++ prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = u4DumpType; ++} ++ ++VOID swCrDebugInit(P_ADAPTER_T prAdapter) ++{ ++ /* frame dump */ ++ if (g_u4SwcrDebugFrameDumpType) ++ swCrFrameCheckEnable(prAdapter, g_u4SwcrDebugFrameDumpType); ++ /* debug counter */ ++ g_fgSwcrDebugTimer = FALSE; ++ ++ cnmTimerInitTimer(prAdapter, &g_rSwcrDebugTimer, (PFN_MGMT_TIMEOUT_FUNC) swCrDebugCheckTimeout, (ULONG) NULL); ++ ++ if (g_u4SwcrDebugCheckTimeout) ++ swCrDebugCheckEnable(prAdapter, TRUE, g_ucSwcrDebugCheckType, g_u4SwcrDebugCheckTimeout); ++} ++ ++VOID swCrDebugUninit(P_ADAPTER_T prAdapter) ++{ ++ cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); ++ ++ g_fgSwcrDebugTimer = FALSE; ++} ++ ++VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout) ++{ ++ if (fgIsEnable) { ++ g_ucSwcrDebugCheckType = ucType; ++ g_u4SwcrDebugCheckTimeout = u4Timeout; ++ if (g_fgSwcrDebugTimer == FALSE) ++ swCrDebugCheckTimeout(prAdapter, 0); ++ } else { ++ cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); ++ g_u4SwcrDebugCheckTimeout = 0; ++ } ++ ++ g_fgSwcrDebugTimer = fgIsEnable; ++} ++ ++VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* dump counters */ ++ if (prCmdSwCtrl) { ++ if (prCmdSwCtrl->u4Data == SWCR_DBG_TYPE_ALL) { ++ ++ /* TX Counter from fw */ ++ DBGLOG(SW4, INFO, "TX0\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_BCN_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_FAILED_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_RETRY_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_MGNT_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_ERROR_CNT]); ++#if 1 ++ /* TX Counter from drv */ ++ DBGLOG(SW4, INFO, "TX1\n" ++ "%08x %08x %08x %08x\n", ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_BSS_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_STA_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_FORWARD_OVERFLOW_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_AP_BORADCAST_DROP)); ++#endif ++ ++ /* RX Counter */ ++ DBGLOG(SW4, INFO, "RX0\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DUP_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FCSERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FIFOFULL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_PFDROP_CNT]); ++ ++ DBGLOG(SW4, INFO, "RX1\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT)); ++ ++ DBGLOG(SW4, INFO, "PWR\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PS_POLL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_IND_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE0], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE1], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF0], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF1]); ++ ++ DBGLOG(SW4, INFO, "ARM\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RATE], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_BWGI], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ENABLE], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ROAM_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_INT_CNT]); ++ ++ DBGLOG(SW4, INFO, "BB\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_MDRDY_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_FCSERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_PD_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_PD_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SFDERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SIGERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT]); ++ ++ } ++ } ++ /* start the next check */ ++ if (g_u4SwcrDebugCheckTimeout) ++ cnmTimerStartTimer(prAdapter, &g_rSwcrDebugTimer, g_u4SwcrDebugCheckTimeout * MSEC_PER_SEC); ++} ++ ++VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ WLAN_STATUS rStatus; ++ ++ rCmdSwCtrl.u4Id = (0xb000 << 16) + g_ucSwcrDebugCheckType; ++ rCmdSwCtrl.u4Data = 0; ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SW_DBG_CTRL, /* ucCID */ ++ FALSE, /* fgSetQuery */ ++ TRUE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ swCrDebugQuery, /* pfCmdDoneHandler */ ++ swCrDebugQueryTimeout, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SW_DBG_CTRL_T), /* u4SetQueryInfoLen */ ++ (PUINT_8)&rCmdSwCtrl, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++} ++ ++VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ++ swCrDebugCheck(prAdapter, (P_CMD_SW_DBG_CTRL_T) (pucEventBuf)); ++} ++ ++VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ swCrDebugCheck(prAdapter, NULL); ++} ++ ++#endif /* CFG_SUPPORT_SWCR */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c +new file mode 100644 +index 000000000000..96293c57e2b0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c +@@ -0,0 +1,5199 @@ ++/* ++** Id: tdls.c#1 ++*/ ++ ++/*! \file tdls.c ++ \brief This file includes IEEE802.11z TDLS support. ++*/ ++ ++/* ++** Log: tdls.c ++ * ++ * 11 13 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++#include "precomp.h" ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "gl_wext.h" ++#include "tdls.h" ++#include "gl_cfg80211.h" ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb); ++ ++#if TDLS_CFG_CMD_TEST ++static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static TDLS_STATUS ++TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd); ++ ++static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param); ++ ++static TDLS_STATUS ++TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static TDLS_STATUS ++TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static VOID ++TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, ++ UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers); ++ ++static VOID ++TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, ++ UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo); ++ ++static TDLS_STATUS ++TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static BOOLEAN fgIsPtiTimeoutSkip = FALSE; ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to indicate packets to upper layer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prSkb A pointer to the received packet ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb) ++{ ++ struct net_device *prNetDev; ++ ++ /* init */ ++ prNetDev = prGlueInfo->prDevHandler; ++ prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.rx_packets++; ++ ++ /* pass to upper layer */ ++ //prNetDev->last_rx = jiffies; ++ prSkb->protocol = eth_type_trans(prSkb, prNetDev); ++ prSkb->dev = prNetDev; ++ ++ if (!in_interrupt()) ++ netif_rx_ni(prSkb); /* only in non-interrupt context */ ++ else ++ netif_rx(prSkb); ++} ++ ++#if TDLS_CFG_CMD_TEST ++ ++#define LR_TDLS_FME_FIELD_FILL(__Len) \ ++do { \ ++ pPkt += __Len; \ ++ u4PktLen += __Len; \ ++} while (0) ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to add a TDLS peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_2_[Responder MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_2_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ struct wireless_dev *prWdev; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ /* init */ ++ rCmd.rPeerInfo.supported_rates = NULL; ++ rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; ++ rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); ++ ++ /* send command to wifi task to handle */ ++ prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; ++ mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_16_[Enable/Disable]_[Set/Clear] ++ ++ iwpriv wlan0 set_str_cmd 0_16_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ TDLS_CMD_CORE_T rCmd; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); ++ ++ /* command to do this */ ++ flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; ++ ++ aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; ++ aucTdlsTestExtCapElm[1] = 5; ++ aucTdlsTestExtCapElm[2] = 0; ++ aucTdlsTestExtCapElm[3] = 0; ++ aucTdlsTestExtCapElm[4] = 0; ++ aucTdlsTestExtCapElm[5] = 0; ++ aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 7); /* bit39 */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a channel switch request from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_5_[TDLS Peer MAC]_[Chan]_[RegulatoryClass]_ ++ [SecondaryChannelOffset]_[SwitchTime]_[SwitchTimeout] ++ ++ iwpriv wlan0 set_str_cmd 0_1_5_00:11:22:33:44:01_1_255_0_15000_30000 ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChStReqRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4RegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s:[%pM]u4Chan=%u u4RegClass=%u u4SecChanOff=%u u4SwitchTime=%u u4SwitchTimeout=%u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4Chan, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4RegClass, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SecChanOff, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTime, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestChStReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a channel switch response from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_6_[TDLS Peer MAC]_[Chan]_ ++ [SwitchTime]_[SwitchTimeout]_[StatusCode] ++ ++ iwpriv wlan0 set_str_cmd 0_1_6_00:11:22:33:44:01_11_15000_30000_0 ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChStRspRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4StatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [ %pM ] u4Chan=%u u4SwitchTime=%u u4SwitchTimeout=%u u4StatusCode=%u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4Chan, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTime, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4StatusCode); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestChStRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip channel switch timeout function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_11_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestChSwTimeoutSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer periodically. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TIMER_T rTdlsTimerTestDataSend; ++static UINT_8 aucTdlsTestDataSPeerMac[6]; ++static UINT_16 u2TdlsTestDataSInterval; ++ ++static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ BOOLEAN fgIsEnabled; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucTdlsTestDataSPeerMac); ++ u2TdlsTestDataSInterval = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ fgIsEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); ++ ++ if (fgIsEnabled == FALSE) { ++ /* stop test timer */ ++ return; ++ } ++ ++ /* re-init test timer */ ++ cnmTimerInitTimer(prAdapter, ++ &rTdlsTimerTestDataSend, (PFN_MGMT_TIMEOUT_FUNC) TdlsTimerTestDataContSend, (ULONG) NULL); ++ ++ cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a data frame from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_x80_[TDLS Peer MAC]_[PM]_[UP]_[EOSP]_[IsNull] ++ ++ iwpriv wlan0 set_str_cmd 0_1_x80_00:11:22:33:44:01_0_0_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.Content.rCmdDatRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4UP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4EOSP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4IsNull = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: [%pM] PM(%u) UP(%u) EOSP(%u) NULL(%u)\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4PM, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4UP, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4EOSP, (UINT32) rCmd.Content.rCmdDatRcv.u4IsNull); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestDataRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_4_[Responder MAC]_[tx status] ++ ++ iwpriv wlan0 set_str_cmd 0_4_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *prPkt; ++ UINT_8 MAC[6]; ++ UINT_8 ucTxStatus; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, MAC); ++ ucTxStatus = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ /* allocate a data frame */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); ++ return; ++ } ++ ++ /* init dev */ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* init packet */ ++ prMsduInfo->len = 1000; ++ kalMemZero(prMsduInfo->data, 100); /* for QoS field */ ++ kalMemCopy(prMsduInfo->data, MAC, 6); ++ kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); ++ *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; ++ ++ /* simulate OS to send the packet */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_16_[mili seconds] ++ ++ iwpriv wlan0 set_str_cmd 0_19_1000 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT32 u4Delay; ++ ++ u4Delay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, "%s: Delay = %d\n", __func__, u4Delay); ++ ++ kalMdelay(u4Delay); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test discovery request frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_10_[DialogToken]_[Peer MAC]_[BSSID] ++ ++ iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01 ++ iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01_00:22:33:44:11:22 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ kalMemZero(aucBSSID, sizeof(aucBSSID)); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_DISCOVERY_REQ; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; ++ ++ if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ else ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip keep alive function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_10_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_10_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestKeepAliveSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable]_[Set/Clear] ++ ++ iwpriv wlan0 set_str_cmd 0_13_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ TDLS_CMD_CORE_T rCmd; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); ++ ++ /* command to do this */ ++ flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; ++ ++ aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; ++ aucTdlsTestExtCapElm[1] = 5; ++ aucTdlsTestExtCapElm[2] = 0; ++ aucTdlsTestExtCapElm[3] = 0; ++ aucTdlsTestExtCapElm[4] = 0; ++ aucTdlsTestExtCapElm[5] = 0; ++ aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 6); /* bit38 */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI request from the AP. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_4_[TDLS Peer MAC]_[Dialog Token] ++ ++ iwpriv wlan0 set_str_cmd 0_1_4_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [ %pM ] u4DialogToken = %u\n", ++ __func__, rCmd.aucPeerMac, (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI response from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_9_[TDLS Peer MAC]_[Dialog Token]_[PM] ++ ++ iwpriv wlan0 set_str_cmd 0_1_9_00:11:22:33:44:01_0_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdPtiRspRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [%pM] u4DialogToken = %u %u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken, ++ (UINT32) rCmd.Content.rCmdPtiRspRcv.u4PM); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to simulate PTI tx done fail case. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_21_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_21_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdPtiTxFail.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdPtiTxFail.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiTxFail, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test frame. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++/* PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; */ ++/* TDLS_STATUS u4Status; */ ++ UINT_32 u4Subcmd; ++/* UINT_32 u4BufLen; */ ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test rv frame sub command = %u\n", (UINT32) u4Subcmd); ++ ++ /* parse command arguments */ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ /* simulate to receive a setup request frame */ ++ TdlsCmdTestSetupReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ /* simulate to receive a setup response frame */ ++ TdlsCmdTestSetupRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CONFIRM: ++ /* simulate to receive a setup confirm frame */ ++ TdlsCmdTestSetupConfirmRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_TEARDOWN: ++ /* simulate to receive a tear down frame */ ++ TdlsCmdTestTearDownRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_PTI: ++ /* simulate to receive a PTI request frame */ ++ TdlsCmdTestPtiReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_PTI_RSP: ++ /* simulate to receive a PTI response frame */ ++ TdlsCmdTestPtiRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_DATA_TEST_DATA: ++ /* simulate to receive a DATA frame */ ++ TdlsCmdTestDataRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CHAN_SWITCH_REQ: ++ /* simulate to receive a channel switch request frame */ ++ TdlsCmdTestChSwReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CHAN_SWITCH_RSP: ++ /* simulate to receive a channel switch response frame */ ++ TdlsCmdTestChSwRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_DISCOVERY_REQ: ++ /* simulate to receive a discovery request frame */ ++ TdlsCmdTestDiscoveryReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test rv frame sub command\n"); ++ return; ++ } ++ ++/* if (u4Status != TDLS_STATUS_SUCCESS) */ ++ { ++/* DBGLOG(TDLS, ERROR, (" command parse fail\n")); */ ++/* return; */ ++ } ++ ++ /* send command to wifi task to handle */ ++#if 0 ++ kalIoctl(prGlueInfo, ++ TdlsTestFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup confirm frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_2_[DialogToken]_[StatusCode]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_1_2_1_0_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d StatusCode=%d from %pM\n", ++ __func__, ucDialogToken, ucStatusCode, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_CONFIRM; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Status Code */ ++ *pPkt = ucStatusCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (4) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (17) WMM Information element */ ++ if (prAdapter->rWifiVar.fgSupportQoS) { ++ u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup request frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_0_[DialogToken]_[Peer MAC]_[BSSID] ++ ++ iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01 ++ iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01_00:22:33:44:11:22 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; ++ UINT_16 u2CapInfo; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ kalMemZero(aucBSSID, sizeof(aucBSSID)); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_SETUP_REQ; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (4) Capability */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* TDLS_EX_CAP_PEER_UAPSD */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* TDLS_EX_CAP_CHAN_SWITCH */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* TDLS_EX_CAP_TDLS */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; ++ ++ if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ else ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup response frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_1_[DialogToken]_[StatusCode]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_1_1_1_0_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; ++ UINT_16 u2CapInfo; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d StatusCode=%d from %pM\n", ++ __func__, ucDialogToken, ucStatusCode, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_SETUP_RSP; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Status Code */ ++ *pPkt = ucStatusCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (4) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (5) Capability */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* TDLS_EX_CAP_PEER_UAPSD */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* TDLS_EX_CAP_CHAN_SWITCH */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* TDLS_EX_CAP_TDLS */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip channel switch timeout function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_14_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_14_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdScanSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdScanSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestScanSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test tear down frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_3_[IsInitiator]_[ReasonCode]_[Peer MAC]_[Where] ++ ++ Where 0 (From driver) or 1 (From FW) ++ ++ iwpriv wlan0 set_str_cmd 0_1_3_1_26_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ BOOLEAN fgIsInitiator; ++ UINT_8 ucReasonCode, aucPeerMac[6]; ++ BOOLEAN fgIsFromWhich; ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ fgIsInitiator = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucReasonCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ fgIsFromWhich = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: ReasonCode=%d from %pM %d\n", ++ __func__, ucReasonCode, aucPeerMac, fgIsFromWhich); ++ ++ if (fgIsFromWhich == 0) { ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_TEARDOWN; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Reason Code */ ++ *pPkt = ucReasonCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ if (fgIsInitiator == 1) { ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ } else { ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); ++ } ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++ } else { ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ kalMemCopy(rCmd.aucPeerMac, aucPeerMac, 6); ++ rCmd.Content.rCmdTearDownRcv.u4ReasonCode = (UINT32) ucReasonCode; ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestTearDownRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip tx fail case. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_7_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_7_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdTxFailSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdTxFailSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestTxFailSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a test frame command to wifi task. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_2_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_2_0_1_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ UINT32 u4Subcmd; ++ UINT_32 u4BufLen; ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test tx tdls frame sub command = %u\n", u4Subcmd); ++ ++ /* parse command arguments */ ++ rCmd.ucFmeType = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); ++ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ rCmd.ucToken = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ DBGLOG(TDLS, INFO, " setup FmeType=%d Token=%d to [%pM]\n", ++ rCmd.ucFmeType, rCmd.ucToken, rCmd.arRspAddr); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); ++ return; ++ } ++ ++ /* send command to wifi task to handle */ ++ kalIoctl(prGlueInfo, ++ TdlsTestTdlsFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a test frame command to wifi task. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ ++ [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ ++ [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ ++ [Timeout]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ TDLS_STATUS u4Status; ++ UINT_32 u4Subcmd; ++ UINT_32 u4BufLen; ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test tx frame sub command = %u\n", (UINT32) u4Subcmd); ++ ++ /* parse command arguments */ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ u4Status = TdlsCmdTestTxFmeSetupReqBufTranslate(prInBuf, u4InBufLen, &rCmd); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); ++ return; ++ } ++ ++ if (u4Status != TDLS_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, " command parse fail\n"); ++ return; ++ } ++ ++ /* send command to wifi task to handle */ ++ kalIoctl(prGlueInfo, ++ TdlsTestFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse the TDLS test frame command, setup request ++* ++* @param CmdBuf Pointer to the buffer. ++* @param BufLen Record buffer length. ++* @param CmdTspec Pointer to the structure. ++* ++* @retval WLAN_STATUS_SUCCESS: Translate OK. ++* @retval WLAN_STATUS_FAILURE: Translate fail. ++* @usage iwpriv wlan0 set_str_cmd [tdls]_[command] ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ ++ [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ ++ [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ ++ [Timeout]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd) ++{ ++/* dumpMemory8(ANDROID_LOG_INFO, pCmdBuf, u4BufLen); */ ++ ++ prCmd->ucFmeType = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->ucToken = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->u2Cap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->ucExCap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->u4Timeout = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ CmdStringMacParse(pCmdBuf, &pCmdBuf, &u4BufLen, prCmd->arRspAddr); ++ ++ DBGLOG(TDLS, INFO, " command content =\n"); ++ DBGLOG(TDLS, INFO, "\tPeer MAC = %pM\n", (prCmd->arRspAddr)); ++ DBGLOG(TDLS, INFO, "\tToken = %u, Cap = 0x%x, ExCap = 0x%x, Timeout = %us FrameType = %u\n", ++ (UINT32) prCmd->ucToken, prCmd->u2Cap, prCmd->ucExCap, ++ (UINT32) prCmd->u4Timeout, (UINT32) prCmd->ucFmeType); ++ DBGLOG(TDLS, INFO, "\tSupRate = 0x%x %x %x %x\n", ++ prCmd->arSupRate[0], prCmd->arSupRate[1], prCmd->arSupRate[2], prCmd->arSupRate[3]); ++ DBGLOG(TDLS, INFO, "\tSupChan = %d %d %d %d\n", ++ prCmd->arSupChan[0], prCmd->arSupChan[1], prCmd->arSupChan[2], prCmd->arSupChan[3]); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update a TDLS peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_3_[Responder MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_3_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ struct wireless_dev *prWdev; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ /* init */ ++ rCmd.rPeerInfo.supported_rates = rCmd.arSupRate; ++ rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; ++ rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); ++ rCmd.rPeerInfo.uapsd_queues = 0xf; /* all AC */ ++ rCmd.rPeerInfo.max_sp = 0; /* delivery all packets */ ++ ++ /* send command to wifi task to handle */ ++ prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; ++ mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); ++ ++ /* update */ ++ TdlsexCfg80211TdlsOper(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, NL80211_TDLS_ENABLE_LINK); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Null frame from the peer. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* EX: iwpriv wlan0 set_str_cmd 0_5_[Responder MAC]_[PM bit] ++ ++ iwpriv wlan0 set_str_cmd 0_5_00:11:22:33:44:01_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.Content.rCmdNullRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [%pM] u4PM = %u\n", ++ __func__, (rCmd.aucPeerMac), (UINT32) rCmd.Content.rCmdNullRcv.u4PM); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestNullRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer periodically. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] u4Param no use ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_15_[Responder MAC]_[Interval: ms]_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_15_00:11:22:33:44:01_5000_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *prPkt; ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* allocate a data frame */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); ++ return; ++ } ++ ++ /* init dev */ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* init packet */ ++ prMsduInfo->len = 1000; ++ kalMemCopy(prMsduInfo->data, aucTdlsTestDataSPeerMac, 6); ++ kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); ++ *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; ++ ++ DBGLOG(TDLS, INFO, " %s try to send a data frame to %pM\n", ++ __func__, aucTdlsTestDataSPeerMac); ++ ++ /* simulate OS to send the packet */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ ++ /* restart test timer */ ++ cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Channel Switch Request frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_REQ; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Channel Switch Response frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_RSP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a test frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if (u4SetBufferLen == 0) ++ return TDLS_STATUS_INVALID_LENGTH; ++ ++ /* allocate/init packet */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ *pu4SetInfoLen = u4SetBufferLen; ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prCmd->arRspAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = prCmd->ucFmeType; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = prCmd->ucToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (4) Capability */ ++ WLAN_SET_FIELD_16(pPkt, prCmd->u2Cap); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */ ++ TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; ++ TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; ++ ++ TIMEOUT_INTERVAL_IE(pPkt)->ucType = IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; ++ TIMEOUT_INTERVAL_IE(pPkt)->u4Value = htonl(prCmd->u4Timeout); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prCmd->arRspAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* 5. send the data frame */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a NULL frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_NULL_RCV; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_REQ; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI response frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_RSP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Tear Down frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TEAR_DOWN; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a data frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_DATA_RCV; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip PTI tx fail status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_TX_FAIL; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a TDLS action frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; ++ struct wireless_dev *prWdev; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if (u4SetBufferLen == 0) ++ return TDLS_STATUS_INVALID_LENGTH; ++ ++ /* allocate/init packet */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; ++ prWdev = (struct wireless_dev *)prGlueInfo->prDevHandler->ieee80211_ptr; ++ ++ TdlsexCfg80211TdlsMgmt(prWdev->wiphy, NULL, ++ prCmd->arRspAddr, prCmd->ucFmeType, 1, ++ 0, 0, /* open/none */ ++ FALSE, NULL, 0); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip tx fail status. So always success in tx done in firmware. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TX_FAIL_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip to do keep alive function in firmware. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip channel switch timeout. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip scan request. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_SCAN_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure channel switch parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_CHSW_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update channel switch parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_9_[TDLS Peer MAC]_ ++ [NetworkTypeIndex]_[1 (Enable) or (0) Disable]_[1 (Start) or 0 (Stop)]_ ++ [RegClass]_[Chan]_[SecChanOff]_[1 (Reqular) or (0) One Shot] ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++ iwpriv wlan0 set_str_cmd 0_9_00:11:22:33:44:01_0_1_0_0_1_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwStarted = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucRegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucTargetChan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucSecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwRegular = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: %pM ucNetTypeIndex=%d, fgIsChSwEnabled=%d, fgIsChSwStarted=%d", ++ __func__, (rCmd.aucPeerMac), ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex, ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled, ++ rCmd.Content.rCmdChSwConf.fgIsChSwStarted); ++ DBGLOG(TDLS, INFO, " RegClass=%d, TargetChan=%d, SecChanOff=%d, Regular=%d\n", ++ rCmd.Content.rCmdChSwConf.ucRegClass, ++ rCmd.Content.rCmdChSwConf.ucTargetChan, ++ rCmd.Content.rCmdChSwConf.ucSecChanOff, rCmd.Content.rCmdChSwConf.fgIsChSwRegular); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsChSwConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display TDLS related information. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_18_[Peer MAC]_[Network Interface ID]_[IsClear] ++ ++ Network Interface ID: reference to ENUM_NETWORK_TYPE_INDEX_T ++ ++ typedef enum _ENUM_NETWORK_TYPE_INDEX_T { ++ NETWORK_TYPE_AIS_INDEX = 0, ++ NETWORK_TYPE_P2P_INDEX, ++ NETWORK_TYPE_BOW_INDEX, ++ NETWORK_TYPE_INDEX_NUM ++ } ENUM_NETWORK_TYPE_INDEX_T; ++ ++ iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdInfoDisplay.fgIsToClearAllHistory = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, " %s: Command PeerMac=%pM in BSS%u\n", ++ __func__, (rCmd.aucPeerMac), rCmd.ucNetTypeIndex); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display key related information. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_20 ++ ++ iwpriv wlan0 set_str_cmd 0_20 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsKeyInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update MIB parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_6_[TdlsEn]_[UapsdEn]_[PsmEn]_[PtiWin]_[CWCap]_ ++ [AckMisRetry]_[RspTimeout]_[CWPbDelay]_[DRWin]_[LowestAcInt] ++ ++ iwpriv wlan0 set_str_cmd 0_6_1_1_0_1_1_3_5_1000_2_1 ++ ++ reference to TDLS_CMD_CORE_MIB_PARAM_UPDATE_T ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, " MIB param = %d %d %d %d %d %d %d %d %d %d\n", ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsMibParamUpdate, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update setup parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_17_[20/40 Support] ++ ++ iwpriv wlan0 set_str_cmd 0_17_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ ++ rCmd.Content.rCmdSetupConf.fgIs2040Supported = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: rCmdSetupConf=%d\n", __func__, rCmd.Content.rCmdSetupConf.fgIs2040Supported); ++ ++ /* command to do this */ ++ prGlueInfo->rTdlsLink.fgIs2040Sup = rCmd.Content.rCmdSetupConf.fgIs2040Supported; ++ ++ rStatus = kalIoctl(prGlueInfo, TdlsSetupConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update UAPSD parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_8_[SP timeout skip]_[PTI timeout skip] ++ ++ iwpriv wlan0 set_str_cmd 0_8_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ ++ /* UAPSD Service Period */ ++ rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ /* PTI Service Period */ ++ fgIsPtiTimeoutSkip = rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip; ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsSpTimeoutSkip=%d, fgIsPtiTimeoutSkip=%d\n", ++ __func__, rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip, fgIsPtiTimeoutSkip); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsUapsdConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display TDLS all information. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_CORE_T *prCmdContent; ++ STA_RECORD_T *prStaRec; ++ TDLS_INFO_LINK_T *prLink; ++ UINT32 u4StartIdx; ++ UINT32 u4PeerNum; ++ BOOLEAN fgIsListAll; ++ UINT8 ucMacZero[6]; ++ UINT32 u4HisIdx; ++ UINT8 ucNetTypeIndex; ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ u4StartIdx = 0; ++ u4PeerNum = 1; ++ fgIsListAll = TRUE; ++ kalMemZero(ucMacZero, sizeof(ucMacZero)); ++ ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ /* display common information */ ++ DBGLOG(TDLS, TRACE, "TDLS common:\n"); ++ DBGLOG(TDLS, TRACE, "\t\trFreeSwRfbList=%u\n", (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ DBGLOG(TDLS, TRACE, "\t\tjiffies=%u %ums (HZ=%d)\n", (UINT32) jiffies, (UINT32) kalGetTimeTick(), HZ); ++ ++ /* display disconnection history information */ ++ DBGLOG(TDLS, TRACE, "TDLS link history: %d\n", prGlueInfo->rTdlsLink.u4LinkIdx); ++ ++ for (u4HisIdx = prGlueInfo->rTdlsLink.u4LinkIdx + 1; u4HisIdx < TDLS_LINK_HISTORY_MAX; u4HisIdx++) { ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; ++ ++ if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) ++ continue; /* skip all zero */ ++ ++ DBGLOG(TDLS, TRACE, ++ "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", ++ u4HisIdx, prLink->aucPeerMac, ++ prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), ++ prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), ++ prLink->ucReasonCode, ++ prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); ++ ++ if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { ++ DBGLOG(TDLS, TRACE, ++ "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", ++ prLink->ucHtBa[0], prLink->ucHtBa[1], ++ prLink->ucHtBa[2], prLink->ucHtBa[3], ++ prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); ++ } ++ } ++ for (u4HisIdx = 0; u4HisIdx <= prGlueInfo->rTdlsLink.u4LinkIdx; u4HisIdx++) { ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; ++ ++ if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) ++ continue; /* skip all zero, use continue, not break */ ++ ++ DBGLOG(TDLS, TRACE, ++ "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", ++ u4HisIdx, (prLink->aucPeerMac), ++ prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), ++ prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), ++ prLink->ucReasonCode, ++ prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); ++ ++ if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { ++ DBGLOG(TDLS, TRACE, ++ "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", ++ prLink->ucHtBa[0], prLink->ucHtBa[1], ++ prLink->ucHtBa[2], prLink->ucHtBa[3], ++ prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); ++ } ++ } ++ DBGLOG(TDLS, TRACE, "\n"); ++ ++ /* display link information */ ++ if (prCmdContent != NULL) { ++ if (kalMemCmp(prCmdContent->aucPeerMac, ucMacZero, 6) != 0) { ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ prCmdContent->ucNetTypeIndex, prCmdContent->aucPeerMac); ++ if (prStaRec == NULL) ++ fgIsListAll = TRUE; ++ } ++ ++ ucNetTypeIndex = prCmdContent->ucNetTypeIndex; ++ } ++ ++ while (1) { ++ if (fgIsListAll == TRUE) { ++ /* list all TDLS peers */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, ucNetTypeIndex, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ if (prStaRec == NULL) ++ break; ++ } ++ ++ DBGLOG(TDLS, TRACE, "-------- TDLS %d: 0x %pM\n", u4PeerNum, (prStaRec->aucMacAddr)); ++ DBGLOG(TDLS, TRACE, "\t\t\t State %d, PM %d, Cap 0x%x\n", ++ prStaRec->ucStaState, prStaRec->fgIsInPS, prStaRec->u2CapInfo); ++ DBGLOG(TDLS, TRACE, "\t\t\t SetupDisable %d, ChSwDisable %d\n", ++ prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); ++ ++ if (fgIsListAll == FALSE) ++ break; /* only list one */ ++ } ++ ++ /* check if we need to clear all histories */ ++ if ((prCmdContent != NULL) && (prCmdContent->Content.rCmdInfoDisplay.fgIsToClearAllHistory == TRUE)) { ++ kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); ++ prGlueInfo->rTdlsLink.u4LinkIdx = TDLS_LINK_HISTORY_MAX - 1; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display key information. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_KEY_INFO; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to record a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] fgIsTearDown TRUE: the link is torn down ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] fgIsFromUs TRUE: tear down is from us ++* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, ++ UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers) ++{ ++ TDLS_INFO_LINK_T *prLink; ++ ++ DBGLOG(TDLS, INFO, ++ " %s: record history for %pM %d %d %d %d\n", ++ __func__, pucPeerMac, prGlueInfo->rTdlsLink.u4LinkIdx, ++ fgIsTearDown, fgIsFromUs, u2ReasonCode); ++ ++ /* check duplicate one */ ++ if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) { ++ DBGLOG(TDLS, ERROR, " %s: u4LinkIdx >= TDLS_LINK_HISTORY_MAX\n", __func__); ++ ++ /* reset to 0 */ ++ prGlueInfo->rTdlsLink.u4LinkIdx = 0; ++ } ++ ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; ++ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) == 0) { ++ if ((prLink->ucReasonCode == u2ReasonCode) && (prLink->fgIsFromUs == fgIsFromUs)) { ++ /* same Peer MAC, Reason Code, Trigger source */ ++ if (fgIsTearDown == TRUE) { ++ if (prLink->jiffies_end != 0) { ++ /* already torn down */ ++ prLink->ucDupCount++; ++ return; ++ } ++ } else { ++ /* already built */ ++ prLink->ucDupCount++; ++ return; ++ } ++ } ++ } ++ ++ /* search old entry */ ++ if (fgIsTearDown == TRUE) { ++ /* TODO: need to search all entries to find it if we support multiple TDLS link design */ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { ++ /* error! can not find the link entry */ ++ DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); ++ return; ++ } ++ ++ prLink->jiffies_end = jiffies; ++ prLink->ucReasonCode = (UINT8) u2ReasonCode; ++ prLink->fgIsFromUs = fgIsFromUs; ++ } else { ++ /* record new one */ ++ prGlueInfo->rTdlsLink.u4LinkIdx++; ++ if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) ++ prGlueInfo->rTdlsLink.u4LinkIdx = 0; ++ ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; ++ ++ prLink->jiffies_start = jiffies; ++ prLink->jiffies_end = 0; ++ kalMemCopy(&prLink->aucPeerMac, pucPeerMac, 6); ++ prLink->ucReasonCode = 0; ++ prLink->fgIsFromUs = (UINT8) fgIsFromUs; ++ prLink->ucDupCount = 0; ++ ++ if (prOthers != NULL) { ++ /* record other parameters */ ++ TDLS_LINK_HIS_OTHERS_T *prHisOthers; ++ ++ prHisOthers = (TDLS_LINK_HIS_OTHERS_T *) prOthers; ++ if (prHisOthers->fgIsHt == TRUE) ++ prLink->ucHtCap |= TDLS_INFO_LINK_HT_CAP_SUP; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] eFmeStatus TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME ++* \param[in] pInfo other information ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, ++ UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo) ++{ ++ TDLS_INFO_LINK_T *prLink; ++ UINT32 u4LinkIdx; ++ UINT32 u4Tid; ++ ++ /* sanity check */ ++ if ((eFmeStatus < TDLS_HOST_EVENT_SF_BA) || (eFmeStatus > TDLS_HOST_EVENT_SF_BA_RSP_DECLINE)) { ++ /* do not care these frames */ ++ return; ++ } ++ ++ DBGLOG(TDLS, INFO, ++ " %s: update history for %pM %d %d\n", ++ __func__, (pucPeerMac), prGlueInfo->rTdlsLink.u4LinkIdx, eFmeStatus); ++ ++ /* init */ ++ u4LinkIdx = prGlueInfo->rTdlsLink.u4LinkIdx; ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4LinkIdx]; ++ ++ /* TODO: need to search all entries to find it if we support multiple TDLS link design */ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { ++ /* error! can not find the link entry */ ++ DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); ++ return; ++ } ++ ++ /* update */ ++ u4Tid = *(UINT32 *) pInfo; ++ switch (eFmeStatus) { ++ case TDLS_HOST_EVENT_SF_BA: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_OK: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_OK; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_DECLINE: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_DECLINE; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_PEER: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_PEER; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_RSP_OK: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_OK; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_RSP_DECLINE: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_DECLINE; ++ break; ++ } ++ ++ /* display TDLS link history */ ++ TdlsInfoDisplay(prGlueInfo->prAdapter, NULL, 0, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure TDLS MIB parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_MIB_UPDATE; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure TDLS SETUP parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_SETUP_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure UAPSD parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_UAPSD_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update frame status. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventFmeStatus(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4Tid; ++ ++ /* init */ ++ u4Tid = *(UINT32 *) prInBuf; ++ prInBuf += 4; /* skip u4EventSubId */ ++ ++ /* sanity check */ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); ++ if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) ++ return; ++ prInBuf++; ++ ++ /* update status */ ++ eFmeStatus = *prInBuf; ++ TdlsLinkHistoryRecordUpdate(prGlueInfo, prStaRec->aucMacAddr, eFmeStatus, &u4Tid); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to collect TDLS statistics from firmware. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ STA_RECORD_T *prStaRec; ++ STAT_CNT_INFO_FW_T *prStat; ++ UINT32 u4RateId; ++ ++ /* init */ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); ++ if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) ++ return; ++ ++ prInBuf += 4; /* skip prStaRec->ucIndex */ ++ ++ /* update statistics */ ++ kalMemCopy(&prStaRec->rTdlsStatistics.rFw, prInBuf, sizeof(prStaRec->rTdlsStatistics.rFw)); ++ ++ /* display statistics */ ++ prStat = &prStaRec->rTdlsStatistics.rFw; ++ ++ DBGLOG(TDLS, TRACE, " peer [%pM] statistics:\n", (prStaRec->aucMacAddr)); ++ DBGLOG(TDLS, TRACE, "\t\tT%d %d %d (P%d %d) (%dus) - E%d 0x%x - R%d (P%d)\n", ++ prStat->u4NumOfTx, prStat->u4NumOfTxOK, prStat->u4NumOfTxRetry, ++ prStat->u4NumOfPtiRspTxOk, prStat->u4NumOfPtiRspTxErr, ++ prStat->u4TxDoneAirTimeMax, ++ prStat->u4NumOfTxErr, prStat->u4TxErrBitmap, prStat->u4NumOfRx, prStat->u4NumOfPtiRspRx); ++ ++ DBGLOG(TDLS, TRACE, "\t\t"); ++ ++ for (u4RateId = prStat->u4TxRateOkHisId; u4RateId < STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM; u4RateId++) ++ DBGLOG(TDLS, TRACE, ++ "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); ++ for (u4RateId = 0; u4RateId < prStat->u4TxRateOkHisId; u4RateId++) ++ DBGLOG(TDLS, TRACE, ++ "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); ++ ++ DBGLOG(TDLS, TRACE, "\n\n"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to do tear down. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ STA_RECORD_T *prStaRec; ++ UINT16 u2ReasonCode; ++ UINT32 u4TearDownSubId; ++ UINT8 *pMac, aucZeroMac[6]; ++ ++ /* init */ ++ u4TearDownSubId = *(UINT32 *) prInBuf; ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ pMac = aucZeroMac; ++ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *(prInBuf + 4)); ++ if (prStaRec != NULL) ++ pMac = prStaRec->aucMacAddr; ++ ++ /* handle */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=PTI timeout\n", ++ __func__, pMac); ++ } else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=AGE timeout\n", ++ __func__, pMac); ++ } else { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=%d\n", ++ __func__, pMac, u4TearDownSubId); ++ } ++ ++ /* sanity check */ ++ if (prStaRec == NULL) ++ return; ++ ++ if (fgIsPtiTimeoutSkip == TRUE) { ++ /* skip PTI timeout event */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: skip PTI timeout\n", __func__); ++ return; ++ } ++ } ++ ++ /* record history */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_FAIL) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_NON_STATE3) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN; ++ else { ++ /* shall not be here */ ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN; ++ } ++ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, TRUE, u2ReasonCode, NULL); ++ ++ /* correct correct reason code for PTI or AGE timeout to supplicant */ ++ if ((u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT) || ++ (u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT)) { ++ u2ReasonCode = TDLS_REASON_CODE_UNREACHABLE; ++ } ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, NL80211_TDLS_TEARDOWN, u2ReasonCode, GFP_ATOMIC); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to do tx down. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventTxDone(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ /* UINT32 u4FmeIdx; */ ++ UINT8 *pucFmeHdr; ++ UINT8 ucErrStatus; ++ ++ ucErrStatus = *(UINT32 *) prInBuf; ++ ++ pucFmeHdr = prInBuf + 4; /* skip ucErrStatus */ ++ ++ if (ucErrStatus == 0) ++ DBGLOG(TDLS, TRACE, " %s: OK to tx a TDLS action:", __func__); ++ else ++ DBGLOG(TDLS, TRACE, " %s: fail to tx a TDLS action (err=0x%x):", __func__, ucErrStatus); ++ #if 0 ++ /* dump TX packet content from wlan header */ ++ for (u4FmeIdx = 0; u4FmeIdx < (u4InBufLen - 4); u4FmeIdx++) { ++ if ((u4FmeIdx % 16) == 0) ++ DBGLOG(TDLS, TRACE, "\n"); ++ ++ DBGLOG(TDLS, TRACE, "%02x ", *pucFmeHdr++); ++ } ++ DBGLOG(TDLS, TRACE, "\n\n"); ++ #endif ++} ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to parse TDLS Extended Capabilities element. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE) ++{ ++ UINT_8 *pucIeExtCap; ++ ++ /* sanity check */ ++ if ((prStaRec == NULL) || (pucIE == NULL)) ++ return; ++ ++ if (IE_ID(pucIE) != ELEM_ID_EXTENDED_CAP) ++ return; ++ ++ /* ++ from bit0 ~ ++ ++ bit 38: TDLS Prohibited ++ The TDLS Prohibited subfield indicates whether the use of TDLS is prohibited. The ++ field is set to 1 to indicate that TDLS is prohibited and to 0 to indicate that TDLS is ++ allowed. ++ */ ++ if (IE_LEN(pucIE) < 5) ++ return; /* we need 39/8 = 5 bytes */ ++ ++ /* init */ ++ prStaRec->fgTdlsIsProhibited = FALSE; ++ prStaRec->fgTdlsIsChSwProhibited = FALSE; ++ ++ /* parse */ ++ pucIeExtCap = pucIE + 2; ++ pucIeExtCap += 4; /* shift to the byte we care about */ ++ ++ if ((*pucIeExtCap) & BIT(38 - 32)) ++ prStaRec->fgTdlsIsProhibited = TRUE; ++ if ((*pucIeExtCap) & BIT(39 - 32)) ++ prStaRec->fgTdlsIsChSwProhibited = TRUE; ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: AP [%pM] tdls prohibit bit=%d %d\n", ++ __func__, ++ prStaRec->aucMacAddr, prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to transmit a TDLS data frame from nl80211. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] ++* \param[in] ++* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *buf, size_t len) ++{ ++ ADAPTER_T *prAdapter; ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prAisBssInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ TDLS_MGMT_TX_INFO *prMgmtTxInfo; ++ ++ /* ++ Have correct behavior for STAUT receiving TDLS Setup Request after sending TDLS ++ Set Request and before receiving TDLS Setup Response: ++ -- Source Address of received Request is higher than own MAC address ++ -- Source Address of received Request is lower than own MAC address ++ ++ ==> STA with larger MAC address will send the response frame. ++ ++ Supplicant will do this in wpa_tdls_process_tpk_m1(). ++ */ ++ ++ /* sanity check */ ++ if ((wiphy == NULL) || (peer == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: wrong 0x%p 0x%p!\n", __func__, wiphy, peer); ++ return -EINVAL; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] %d %d %d 0x%p %u\n", ++ __func__, peer, action_code, dialog_token, status_code, buf, (UINT32) len); ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); ++ return -EINVAL; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ if (prAdapter->fgTdlsIsSup == FALSE) { ++ DBGLOG(TDLS, ERROR, " %s: firmware TDLS is not supported!\n", __func__); ++ return -EBUSY; ++ } ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prAisBssInfo->fgTdlsIsProhibited == TRUE) { ++ /* do not send anything if TDLS is prohibited in the BSS */ ++ return 0; ++ } ++ ++ prMgmtTxInfo = kalMemAlloc(sizeof(TDLS_MGMT_TX_INFO), VIR_MEM_TYPE); ++ if (prMgmtTxInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate fail!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); ++ ++ if (peer != NULL) ++ kalMemCopy(prMgmtTxInfo->aucPeer, peer, 6); ++ prMgmtTxInfo->ucActionCode = action_code; ++ prMgmtTxInfo->ucDialogToken = dialog_token; ++ prMgmtTxInfo->u2StatusCode = status_code; ++ ++ if (buf != NULL) { ++ if (len > sizeof(prMgmtTxInfo->aucSecBuf)) { ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return -EINVAL; ++ } ++ prMgmtTxInfo->u4SecBufLen = len; ++ kalMemCopy(prMgmtTxInfo->aucSecBuf, buf, len); ++ } ++ ++ /* send the TDLS action data frame */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexMgmtCtrl, ++ prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* ++ clear all content to avoid any bug if we dont yet execute TdlsexMgmtCtrl() ++ then kalIoctl finishes ++ */ ++ kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return -EINVAL; ++ } ++ ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to enable or disable TDLS link from upper layer. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] ++* \param[in] ++* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, enum nl80211_tdls_operation oper) ++{ ++ ADAPTER_T *prAdapter; ++ GLUE_INFO_T *prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ TDLS_CMD_LINK_T rCmdLink; ++ ++ /* sanity check */ ++ if (peer == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: peer == NULL!\n", __func__); ++ return -EINVAL; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] %d %d\n", ++ __func__, peer, oper, (wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)); ++ ++ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) ++ return -ENOTSUPP; ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); ++ return -EINVAL; ++ } ++ prAdapter = prGlueInfo->prAdapter; ++ kalMemCopy(rCmdLink.aucPeerMac, peer, sizeof(rCmdLink.aucPeerMac)); ++ rCmdLink.fgIsEnabled = FALSE; ++ ++ /* ++ enum nl80211_tdls_operation { ++ NL80211_TDLS_DISCOVERY_REQ, ++ NL80211_TDLS_SETUP, ++ NL80211_TDLS_TEARDOWN, ++ NL80211_TDLS_ENABLE_LINK, ++ NL80211_TDLS_DISABLE_LINK, ++ }; ++ */ ++ ++ switch (oper) { ++ case NL80211_TDLS_ENABLE_LINK: ++ rCmdLink.fgIsEnabled = TRUE; ++ break; ++ ++ case NL80211_TDLS_DISABLE_LINK: ++ rCmdLink.fgIsEnabled = FALSE; ++ break; ++ ++ case NL80211_TDLS_TEARDOWN: ++ case NL80211_TDLS_SETUP: ++ case NL80211_TDLS_DISCOVERY_REQ: ++ /* we do not support setup/teardown/discovery from driver */ ++ return -ENOTSUPP; ++ ++ default: ++ return -ENOTSUPP; ++ } ++ ++ /* enable or disable TDLS link */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexLinkCtrl, &rCmdLink, sizeof(TDLS_CMD_LINK_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TDLS module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT_32 u4Subcmd; ++ static void (*TdlsCmdTestFunc)(P_GLUE_INFO_T, UINT_8 *, UINT_32); ++ ++ /* parse TDLS sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " sub command = %u\n", (UINT32) u4Subcmd); ++ TdlsCmdTestFunc = NULL; ++ ++ /* handle different sub-command */ ++ switch (u4Subcmd) { ++#if TDLS_CFG_CMD_TEST /* only for unit test */ ++ case TDLS_CMD_TEST_TX_FRAME: ++ /* simulate to send a TDLS frame */ ++ /* TdlsCmdTestTxFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxFrame; ++ break; ++ ++ case TDLS_CMD_TEST_TX_TDLS_FRAME: ++ /* simulate to send a TDLS frame from supplicant */ ++ /* TdlsCmdTestTxTdlsFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxTdlsFrame; ++ break; ++ ++ case TDLS_CMD_TEST_RCV_FRAME: ++ /* simulate to receive a TDLS frame */ ++ /* TdlsCmdTestRvFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestRvFrame; ++ break; ++ ++ case TDLS_CMD_TEST_PEER_ADD: ++ /* simulate to add a TDLS peer */ ++ /* TdlsCmdTestAddPeer(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestAddPeer; ++ break; ++ ++ case TDLS_CMD_TEST_PEER_UPDATE: ++ /* simulate to update a TDLS peer */ ++ /* TdlsCmdTestUpdatePeer(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestUpdatePeer; ++ break; ++ ++ case TDLS_CMD_TEST_DATA_FRAME: ++ /* simulate to send a data frame to the peer */ ++ /* TdlsCmdTestDataSend(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDataSend; ++ break; ++ ++ case TDLS_CMD_TEST_RCV_NULL: ++ /* simulate to receive a QoS null frame from the peer */ ++ /* TdlsCmdTestNullRecv(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestNullRecv; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_TX_FAIL: ++ /* command firmware to skip tx fail case */ ++ /* TdlsCmdTestTxFailSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxFailSkip; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_KEEP_ALIVE: ++ /* command firmware to skip keep alive function */ ++ /* TdlsCmdTestKeepAliveSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestKeepAliveSkip; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT: ++ /* command firmware to skip channel switch timeout function */ ++ /* TdlsCmdTestChSwTimeoutSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestChSwTimeoutSkip; ++ break; ++ ++ case TDLS_CMD_TEST_PROHIBIT_SET_IN_AP: ++ /* simulate to set Prohibited Bit in AP */ ++ /* TdlsCmdTestProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestProhibitedBitSet; ++ break; ++ ++ case TDLS_CMD_TEST_SCAN_DISABLE: ++ /* command to disable scan request to do channel switch */ ++ /* TdlsCmdTestScanCtrl(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestScanCtrl; ++ break; ++ ++ case TDLS_CMD_TEST_DATA_FRAME_CONT: ++ /* simulate to send a data frame to the peer periodically */ ++ /* TdlsCmdTestDataContSend(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDataContSend; ++ break; ++ ++ case TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP: ++ /* simulate to set channel switch Prohibited Bit in AP */ ++ /* TdlsCmdTestChSwProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestChSwProhibitedBitSet; ++ break; ++ ++ case TDLS_CMD_TEST_DELAY: ++ /* delay a where */ ++ /* TdlsCmdTestDelay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDelay; ++ break; ++ ++ case TDLS_CMD_TEST_PTI_TX_FAIL: ++ /* simulate the tx done fail for PTI */ ++ /* TdlsCmdTestPtiTxDoneFail(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestPtiTxDoneFail; ++ break; ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++ case TDLS_CMD_MIB_UPDATE: ++ /* update MIB parameters */ ++ /* TdlsCmdMibParamUpdate(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdMibParamUpdate; ++ break; ++ ++ case TDLS_CMD_UAPSD_CONF: ++ /* config UAPSD parameters */ ++ /* TdlsCmdUapsdConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdUapsdConf; ++ break; ++ ++ case TDLS_CMD_CH_SW_CONF: ++ /* enable or disable or start or stop channel switch function */ ++ /* TdlsCmdChSwConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdChSwConf; ++ break; ++ ++ case TDLS_CMD_SETUP_CONF: ++ /* config setup parameters */ ++ /* TdlsCmdSetupConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdSetupConf; ++ break; ++ ++ case TDLS_CMD_INFO: ++ /* display all TDLS information */ ++ /* TdlsCmdInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdInfoDisplay; ++ break; ++ ++ case TDLS_CMD_KEY_INFO: ++ /* display key information */ ++ /* TdlsCmdKeyInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdKeyInfoDisplay; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (TdlsCmdTestFunc != NULL) ++ TdlsCmdTestFunc(prGlueInfo, prInBuf, u4InBufLen); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to record a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] fgIsTearDown TRUE: tear down ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] fgIsFromUs TRUE: tear down is from us ++* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode) ++{ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (pucPeerMac == NULL)) ++ return; ++ ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a inform from %pM %d %d\n", ++ __func__, pucPeerMac, fgIsFromUs, u2ReasonCode); ++ ++ /* record */ ++ TdlsLinkHistoryRecord(prGlueInfo, fgIsTearDown, pucPeerMac, fgIsFromUs, u2ReasonCode, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TDLS module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ UINT32 u4EventId; ++ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (prInBuf == NULL)) ++ return; /* shall not be here */ ++ ++ /* handle */ ++ u4EventId = *(UINT32 *) prInBuf; ++ u4InBufLen -= 4; ++ ++ DBGLOG(TDLS, INFO, " %s: Rcv a event: %d\n", __func__, u4EventId); ++ ++ switch (u4EventId) { ++ case TDLS_HOST_EVENT_TEAR_DOWN: ++ TdlsEventTearDown(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_TX_DONE: ++ TdlsEventTxDone(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_FME_STATUS: ++ TdlsEventFmeStatus(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_STATISTICS: ++ TdlsEventStatistics(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return TDLS_STATUS_SUCCESS: do not set key and key infor. is queued ++ TDLS_STATUS_FAILURE: set key ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey) ++{ ++ STA_RECORD_T *prStaRec; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (prNewKey == NULL)) ++ return TDLS_STATUS_FAILURE; ++ ++ /* ++ supplicant will set key before updating station & enabling the link so we need to ++ backup the key information and set key when link is enabled ++ */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prNewKey->arBSSID); ++ if ((prStaRec != NULL) && IS_TDLS_STA(prStaRec)) { ++ DBGLOG(TDLS, TRACE, " %s: [%pM] queue key (len=%d) until link is enabled\n", ++ __func__, prNewKey->arBSSID, (UINT32) prNewKey->u4KeyLength); ++ ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ DBGLOG(TDLS, TRACE, " %s: [%pM] tear down the link due to STA_STATE_3\n", ++ __func__, prNewKey->arBSSID); ++ ++ /* re-key */ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, ++ prStaRec->aucMacAddr, TRUE, ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ /* backup the key */ ++ kalMemCopy(&prStaRec->rTdlsKeyTemp, prNewKey, sizeof(prStaRec->rTdlsKeyTemp)); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ return TDLS_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexInit(ADAPTER_T *prAdapter) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ ++ /* reset */ ++ kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get any peer is in power save. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval TRUE (at least one peer is in power save) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter) ++{ ++ STA_RECORD_T *prStaRec; ++ UINT32 u4StaId, u4StartIdx; ++ ++ for (u4StaId = 0, u4StartIdx = 0; u4StaId < CFG_STA_REC_NUM; u4StaId++) { ++ /* list all TDLS peers */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ if (prStaRec == NULL) ++ break; ++ ++ if (prStaRec->fgIsInPS == TRUE) { ++ DBGLOG(TDLS, TRACE, " yes, at least one peer is in ps\n"); ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to enable or disable a TDLS link. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_LINK_T *prCmd; ++ BSS_INFO_T *prBssInfo; ++ STA_RECORD_T *prStaRec; ++ TDLS_LINK_HIS_OTHERS_T rHisOthers; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_LINK_T); ++ prCmd = (TDLS_CMD_LINK_T *) pvSetBuffer; ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ if (prStaRec == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer! %pM\n", ++ __func__, prCmd->aucPeerMac); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ if (prCmd->fgIsEnabled == TRUE) { ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_ENABLE_LINK\n", __func__); ++ ++ /* update key information after cnmStaRecChangeState(STA_STATE_3) */ ++ prStaRec->fgTdlsInSecurityMode = FALSE; ++ ++ if (prStaRec->rTdlsKeyTemp.u4Length > 0) { ++ UINT_32 u4BufLen; /* no use */ ++ ++ DBGLOG(TDLS, INFO, " %s: key len=%d\n", ++ __func__, (UINT32) prStaRec->rTdlsKeyTemp.u4Length); ++ ++ /* ++ reminder the function that we are CIPHER_SUITE_CCMP, ++ do not change cipher type to CIPHER_SUITE_WEP128 ++ */ ++ _wlanoidSetAddKey(prAdapter, &prStaRec->rTdlsKeyTemp, ++ prStaRec->rTdlsKeyTemp.u4Length, FALSE, CIPHER_SUITE_CCMP, &u4BufLen); ++ ++ /* clear the temp key */ ++ prStaRec->fgTdlsInSecurityMode = TRUE; ++ kalMemZero(&prStaRec->rTdlsKeyTemp, sizeof(prStaRec->rTdlsKeyTemp)); ++ } ++ ++ /* check if we need to disable channel switch function */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ if (prBssInfo->fgTdlsIsChSwProhibited == TRUE) { ++ TDLS_CMD_CORE_T rCmd; ++ ++ kalMemZero(&rCmd, sizeof(TDLS_CMD_CORE_T)); ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex = prStaRec->ucNetTypeIndex; ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = FALSE; ++ kalMemCopy(rCmd.aucPeerMac, prStaRec->aucMacAddr, 6); ++ TdlsChSwConf(prAdapter, &rCmd, 0, 0); ++ ++ DBGLOG(TDLS, INFO, " %s: disable channel switch\n", __func__); ++ } ++ ++ TDLS_LINK_INCREASE(prGlueInfo); ++ ++ /* record link */ ++ if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) ++ rHisOthers.fgIsHt = TRUE; ++ else ++ rHisOthers.fgIsHt = FALSE; ++ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, FALSE, ++ prStaRec->aucMacAddr, !prStaRec->flgTdlsIsInitiator, 0, &rHisOthers); ++ } else { ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); /* release to other TDLS peers */ ++ DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_DISABLE_LINK\n", __func__); ++ ++ TDLS_LINK_DECREASE(prGlueInfo); ++/* while(1); //sample debug */ ++ } ++ ++ /* work-around link count */ ++ if ((TDLS_LINK_COUNT(prGlueInfo) < 0) || (TDLS_LINK_COUNT(prGlueInfo) > 1)) { ++ /* ERROR case: work-around to recount by searching all station records */ ++ UINT32 u4Idx; ++ ++ TDLS_LINK_COUNT_RESET(prGlueInfo); ++ ++ for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { ++ prStaRec = &prAdapter->arStaRec[u4Idx]; ++ ++ if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) ++ TDLS_LINK_INCREASE(prGlueInfo); ++ } ++ ++ if (TDLS_LINK_COUNT(prGlueInfo) > 1) { ++ /* number of links is still > 1 */ ++ DBGLOG(TDLS, INFO, " %s: cTdlsLinkCnt %d > 1?\n", ++ __func__, TDLS_LINK_COUNT(prGlueInfo)); ++ ++ TDLS_LINK_COUNT_RESET(prGlueInfo); ++ ++ /* free all TDLS links */ ++ for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { ++ prStaRec = &prAdapter->arStaRec[u4Idx]; ++ ++ if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ } ++ ++ /* maybe inform supplicant ? */ ++ } ++ } ++ ++ /* display TDLS link history */ ++ TdlsInfoDisplay(prAdapter, NULL, 0, NULL); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a TDLS action data frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_MGMT_TX_INFO *prMgmtTxInfo; ++ STA_RECORD_T *prStaRec; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_MGMT_TX_INFO); ++ prMgmtTxInfo = (TDLS_MGMT_TX_INFO *) pvSetBuffer; ++ ++ switch (prMgmtTxInfo->ucActionCode) { ++ case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: ++ prStaRec = NULL; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); ++ if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3)) { ++ /* rekey? we reject re-setup link currently */ ++ /* TODO: Still can setup link during rekey */ ++ ++ /* ++ return success to avoid supplicant clear TDLS entry; ++ Or we cannot send out any TDLS tear down frame to the peer ++ */ ++ DBGLOG(TDLS, TRACE, " %s: skip new setup on the exist link!\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ prStaRec = NULL; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ case TDLS_FRM_ACTION_TEARDOWN: ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); ++#if 0 /* in some cases, the prStaRec is still NULL */ ++ /* ++ EX: if a peer sends us a TDLS setup request with wrong BSSID, ++ supplicant will not call TdlsexPeerAdd() to create prStaRec and ++ supplicant will send a TDLS setup response with status code 7. ++ ++ So in the case, prStaRec will be NULL. ++ */ ++ if (prStaRec == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); ++ return -EINVAL; ++ } ++#endif ++ break; ++ ++ /* ++ TODO: Discovery response frame ++ Note that the TDLS Discovery Response frame is not a TDLS frame but a 11 ++ Public Action frame. ++ In WiFi TDLS Tech Minutes June 8 2010.doc, ++ a public action frame (i.e. it is no longer an encapsulated data frame) ++ */ ++ ++ default: ++ DBGLOG(TDLS, ERROR, ++ " %s: wrong action_code %d!\n", __func__, prMgmtTxInfo->ucActionCode); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* send the TDLS data frame */ ++ if (prStaRec != NULL) { ++ DBGLOG(TDLS, INFO, " %s: [%pM] ps=%d status=%d\n", ++ __func__, prStaRec->aucMacAddr, ++ prStaRec->fgIsInPS, prMgmtTxInfo->u2StatusCode); ++ ++ if (prMgmtTxInfo->ucActionCode == TDLS_FRM_ACTION_TEARDOWN) { ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prMgmtTxInfo->aucPeer, ++ TRUE, prMgmtTxInfo->u2StatusCode, NULL); ++ } ++ } ++ ++ return TdlsDataFrameSend(prAdapter, ++ prStaRec, ++ prMgmtTxInfo->aucPeer, ++ prMgmtTxInfo->ucActionCode, ++ prMgmtTxInfo->ucDialogToken, ++ prMgmtTxInfo->u2StatusCode, ++ (UINT_8 *) prMgmtTxInfo->aucSecBuf, prMgmtTxInfo->u4SecBufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to add a peer record. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexPeerAdd(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_PEER_ADD_T *prCmd; ++ BSS_INFO_T *prAisBssInfo; ++ STA_RECORD_T *prStaRec; ++ UINT_8 ucNonHTPhyTypeSet; ++ UINT32 u4StartIdx; ++ OS_SYSTIME rCurTime; ++ ++ /* sanity check */ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); ++ prCmd = (TDLS_CMD_PEER_ADD_T *) pvSetBuffer; ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4StartIdx = 0; ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ ++ /* check if any TDLS link exists because we only support one TDLS link currently */ ++ if (prStaRec == NULL) { ++ /* the MAC is new peer */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ ++ if (prStaRec != NULL) { ++ /* a building TDLS link exists */ ++ DBGLOG(TDLS, ERROR, ++ " %s: one TDLS link setup [%pM] is going...\n", ++ __func__, prStaRec->aucMacAddr); ++ ++ if (prStaRec->ucStaState != STA_STATE_3) { ++ /* check timeout */ ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsSetupStartTime, ++ SEC_TO_SYSTIME(TDLS_SETUP_TIMEOUT_SEC))) { ++ /* free the StaRec */ ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ DBGLOG(TDLS, ERROR, ++ " %s: free going TDLS link setup [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ /* handle new setup */ ++ prStaRec = NULL; ++ } else ++ return TDLS_STATUS_FAILURE; ++ } else { ++ /* the TDLS is built and works fine, reject new one */ ++ return TDLS_STATUS_FAILURE; ++ } ++ } ++ } else { ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ /* the peer exists, maybe TPK lifetime expired, supplicant wants to renew key */ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, ++ prStaRec->aucMacAddr, TRUE, ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: re-setup link for [%pM] maybe re-key?\n", ++ __func__, (prStaRec->aucMacAddr)); ++ return TDLS_STATUS_FAILURE; ++ } ++ } ++ ++ /* ++ create new entry if not exist ++ ++ 1. we are initiator ++ (1) send TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) got TDLS setup response and send TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ ++ 2. we are responder ++ (1) got TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) send TDLS setup response ++ (3) got TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ */ ++ if (prStaRec == NULL) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ if (prStaRec == NULL) { ++ /* shall not be here */ ++ DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ /* init the prStaRec */ ++ /* prStaRec will be zero first in cnmStaRecAlloc() */ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prCmd->aucPeerMac); ++ ++/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); */ ++ } else { ++#if 0 ++ if ((prStaRec->ucStaState > STA_STATE_1) && (IS_TDLS_STA(prStaRec))) { ++ /* ++ test plan: The STAUT should locally tear down existing TDLS direct link and ++ respond with Set up Response frame. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++#endif ++ } ++ ++ /* reference to bssCreateStaRecFromBssDesc() and use our best capability */ ++ /* reference to assocBuildReAssocReqFrameCommonIEs() to fill elements */ ++ ++ /* prStaRec->u2CapInfo */ ++ /* TODO: Need to parse elements from setup request frame */ ++ prStaRec->u2OperationalRateSet = prAisBssInfo->u2OperationalRateSet; ++ prStaRec->u2BSSBasicRateSet = prAisBssInfo->u2BSSBasicRateSet; ++ prStaRec->u2DesiredNonHTRateSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ prStaRec->ucPhyTypeSet = prAisBssInfo->ucPhyTypeSet; ++ prStaRec->eStaType = STA_TYPE_TDLS_PEER; ++ ++ prStaRec->ucDesiredPhyTypeSet = /*prStaRec->ucPhyTypeSet & */ ++ prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; ++ ++ /* check for Target BSS's non HT Phy Types */ ++ if (ucNonHTPhyTypeSet) { ++ if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = TRUE; ++ } else { ++ /* use mandatory for 11N only BSS */ ++/* ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ prStaRec->fgHasBasicPhyType = FALSE; ++ } ++ ++ /* update non HT Desired Rate Set */ ++ { ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prStaRec->u2DesiredNonHTRateSet = ++ (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); ++ } ++ ++#if 0 /* TdlsexPeerAdd() will be called before we receive setup rsp in TdlsexRxFrameHandle() */ ++ /* check if the add is from the same peer in the 1st unhandled setup request frame */ ++ DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", ++ __func__, prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac); ++ ++ if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { ++ /* copy the HT capability from its setup request */ ++ kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); ++ ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); ++ ++ /* reset backup */ ++ kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); ++ kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); ++ ++ DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); ++ } ++#endif ++ ++ /* update WMM: must support due to UAPSD in TDLS link */ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = TRUE; ++ ++ /* update station record to firmware */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* update time */ ++ GET_CURRENT_SYSTIME(&prStaRec->rTdlsSetupStartTime); ++ ++ DBGLOG(TDLS, INFO, " %s: create a peer [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to update a peer record. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexPeerUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_PEER_UPDATE_T *prCmd; ++ BSS_INFO_T *prAisBssInfo; ++ STA_RECORD_T *prStaRec; ++ IE_HT_CAP_T *prHtCap; ++ ++ /* sanity check */ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); ++ prCmd = (TDLS_CMD_PEER_UPDATE_T *) pvSetBuffer; ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ ++ /* ++ create new entry if not exist ++ ++ 1. we are initiator ++ (1) send TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) got TDLS setup response and send TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ ++ 2. we are responder ++ (1) got TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) send TDLS setup response ++ (3) got TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ */ ++ if ((prStaRec == NULL) || (prStaRec->fgIsInUse == 0)) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: update a peer [%pM] %d -> %d, 0x%x\n", ++ __func__, (prStaRec->aucMacAddr), ++ prStaRec->ucStaState, STA_STATE_3, prStaRec->eStaType); ++ ++ if (!IS_TDLS_STA(prStaRec)) { ++ DBGLOG(TDLS, ERROR, " %s: peer is not TDLS one!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* check if the add is from the same peer in the 1st unhandled setup request frame */ ++ DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", ++ __func__, (prGlueInfo->aucTdlsHtPeerMac), (prCmd->aucPeerMac)); ++ ++ if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { ++ /* copy the HT capability from its setup request */ ++ kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); ++ ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); ++ ++ /* reset backup */ ++ kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); ++ kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); ++ ++ DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); ++ } ++ ++ /* update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = prCmd->u2StatusCode; ++ ++ /* prStaRec->ucStaState shall be STA_STATE_1 */ ++ ++ prStaRec->u2CapInfo = prCmd->u2Capability; ++/* prStaRec->u2OperationalRateSet */ ++ prStaRec->u2AssocId = 0; /* no use */ ++ prStaRec->u2ListenInterval = 0; /* unknown */ ++/* prStaRec->ucDesiredPhyTypeSet */ ++/* prStaRec->u2DesiredNonHTRateSet */ ++/* prStaRec->u2BSSBasicRateSet */ ++/* prStaRec->ucMcsSet */ ++/* prStaRec->fgSupMcs32 */ ++/* prStaRec->u2HtCapInfo */ ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsUapsdSupported = (prCmd->UapsdBitmap == 0) ? FALSE : TRUE; ++/* prStaRec->ucAmpduParam */ ++/* prStaRec->u2HtExtendedCap */ ++ prStaRec->u4TxBeamformingCap = 0; /* no use */ ++ prStaRec->ucAselCap = 0; /* no use */ ++ prStaRec->ucRCPI = 0; ++ prStaRec->ucBmpTriggerAC = prCmd->UapsdBitmap; ++ prStaRec->ucBmpDeliveryAC = prCmd->UapsdBitmap; ++ prStaRec->ucUapsdSp = prCmd->UapsdMaxSp; ++ ++ /* update HT */ ++#if (TDLS_CFG_HT_SUP == 1) ++ if (prCmd->fgIsSupHt == FALSE) { ++ /* no HT IE is from supplicant so we use the backup */ ++ prHtCap = (IE_HT_CAP_T *) &prStaRec->rTdlsHtCap; ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] update ht ie 0x%x\n", ++ __func__, (prStaRec->aucMacAddr), prHtCap->ucId); ++ ++ if (prHtCap->ucId == ELEM_ID_HT_CAP) { ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ prStaRec->ucDesiredPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ } ++ } else { ++ /* TODO: use the HT IE from supplicant */ ++ } ++#endif /* TDLS_CFG_HT_SUP */ ++ ++ DBGLOG(TDLS, INFO, " %s: UAPSD 0x%x %d MCS=0x%x\n", ++ __func__, prCmd->UapsdBitmap, prCmd->UapsdMaxSp, prStaRec->ucMcsSet); ++ ++/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ ++ DBGLOG(TDLS, INFO, " %s: update a peer [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check if we need to drop a TDLS action frame. ++* ++* \param[in] *pPkt Pointer to the struct sk_buff->data. ++* \param[in] ++* \param[in] ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt) ++{ ++ ADAPTER_T *prAdapter; ++ UINT8 ucActionId; ++ ++ /* sanity check */ ++ if ((pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) ++ return FALSE; /* not TDLS data frame htons(0x890d) */ ++ ++#if 0 /* supplicant handles this check */ ++ if (prStaRec == NULL) ++ return FALSE; /* shall not be here */ ++ ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a TDLS action frame (id=%d) %d %d\n", ++ __func__, *(pPkt + 13 + 4), prStaRec->fgTdlsIsProhibited, fgIsPtiTimeoutSkip); ++ ++ /* check if TDLS Prohibited bit is set in AP's beacon */ ++ if (prStaRec->fgTdlsIsProhibited == TRUE) ++ return TRUE; ++#endif ++ ++ ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ ++ ++ if (fgIsPtiTimeoutSkip == TRUE) { ++ /* also skip any tear down frame from the peer */ ++ if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) ++ return TRUE; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a TDLS action frame %d (%u)\n", ++ __func__, ucActionId, (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ ++ if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) { ++ DBGLOG(TDLS, WARN, " %s: Rcv a TDLS tear down frame %d, will DISABLE link\n", ++ __func__, *(pPkt + 13 + 4)); /* reason code */ ++ ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, pPkt + 6, FALSE, *(pPkt + 13 + 4), NULL); ++ ++ /* inform tear down to supplicant only in OPEN/NONE mode */ ++ /* ++ we need to tear down the link manually; or supplicant will display ++ "No FTIE in TDLS Teardown" and it will not tear down the link ++ */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ pPkt + 6, TDLS_FRM_ACTION_TEARDOWN, *(pPkt + 13 + 4), GFP_ATOMIC); ++ } ++#if 0 /* pass all to supplicant except same thing is handled in supplicant */ ++ if (((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_REQ) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_RSP) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI_RSP)) { ++ return TRUE; ++ } ++#endif ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to parse some IEs in the setup frame from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] pPkt Pointer to the ethernet packet ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen) ++{ ++ ADAPTER_T *prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT8 ucActionId; ++ UINT8 *pucPeerMac, ucElmId, ucElmLen; ++ INT16 s2FmeLen; ++ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) ++ return; ++ ++ ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ ++ ++ if ((ucActionId != TDLS_FRM_ACTION_SETUP_REQ) && (ucActionId != TDLS_FRM_ACTION_SETUP_RSP)) ++ return; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ pucPeerMac = pPkt + 6; ++ s2FmeLen = (INT16) u2PktLen; ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: get a setup frame %d from %pM\n", ++ __func__, ucActionId, (pucPeerMac)); ++ ++ if (ucActionId == TDLS_FRM_ACTION_SETUP_REQ) ++ pPkt += 12 + 2 + 2 + 1 + 1 + 2; /* skip action, dialog token, capability */ ++ else ++ pPkt += 12 + 2 + 2 + 1 + 2 + 1 + 2; /* skip action, status code, dialog token, capability */ ++ ++ /* check station record */ ++ prStaRec = cnmGetStaRecByAddress(prGlueInfo->prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, pucPeerMac); ++ ++ if (prStaRec == NULL) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ if (prStaRec == NULL) { ++ /* TODO: only one TDLS entry, need to free old one if timeout */ ++ DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); ++ return; ++ } ++ ++ /* init the prStaRec */ ++ /* prStaRec will be zero first in cnmStaRecAlloc() */ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMac); ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ /* backup HT IE to station record */ ++ /* TODO: Maybe our TDLS only supports non-11n */ ++ while (s2FmeLen > 0) { ++ ucElmId = *pPkt++; ++ ucElmLen = *pPkt++; ++ ++ switch (ucElmId) { ++ case ELEM_ID_HT_CAP: /* 0x2d */ ++ /* backup the HT IE of 1st unhandled setup request frame */ ++ if (prGlueInfo->rTdlsHtCap.ucId == 0x00) { ++ kalMemCopy(prGlueInfo->aucTdlsHtPeerMac, pucPeerMac, 6); ++ kalMemCopy(&prGlueInfo->rTdlsHtCap, pPkt - 2, ucElmLen + 2); ++ ++ /* ++ cannot backup in prStaRec; or ++ ++ 1. we build a TDLS link ++ 2. peer re-sends setup req ++ 3. we backup HT cap element ++ 4. supplicant disables the link ++ 5. we clear the prStaRec ++ */ ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: %pM: find a HT IE\n", ++ __func__, (pucPeerMac)); ++ } ++ return; ++ ++ case ELEM_ID_EXTENDED_CAP: ++ /* TODO: backup the extended capability IE */ ++ break; ++ } ++ ++ pPkt += ucElmLen; ++ s2FmeLen -= (2 + ucElmLen); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to get the TDLS station record. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval TDLS_STATUS_SUCCESS: this is TDLS packet ++* TDLS_STATUS_FAILURE: this is not TDLS packet ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo) ++{ ++ BSS_INFO_T *prBssInfo; ++ STA_RECORD_T *prStaRec; ++ TDLS_STATUS Status; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (prMsduInfo == NULL)) ++ return TDLS_STATUS_FAILURE; ++ ++ if (prAdapter->prGlueInfo == NULL) ++ return TDLS_STATUS_FAILURE; ++ if (TDLS_IS_NO_LINK_GOING(prAdapter->prGlueInfo)) ++ return TDLS_STATUS_FAILURE; ++ ++ /* init */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ Status = TDLS_STATUS_SUCCESS; ++ ++ /* get record by ether dest */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMsduInfo->aucEthDestAddr); ++ ++ /* ++ TDLS Setup Request frames, TDLS Setup Response frames and TDLS Setup Confirm ++ frames shall be transmitted through the AP and shall not be transmitted to a group ++ address. ++ ++ 1. In first time, prStaRec == NULL or prStaRec->ucStaState != STA_STATE_3, ++ we will send them to AP; ++ 2. When link is still on, if you command to send TDLS setup from supplicant, ++ supplicant will DISABLE LINK first, prStaRec will be NULL then send TDLS ++ setup frame to the peer. ++ */ ++ ++ do { ++ if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3) && (IS_TDLS_STA(prStaRec))) { ++ /* ++ TDLS Test Case 5.3 Tear Down ++ Automatically sends TDLS Teardown frame to STA 2 via AP ++ ++ 11.21.5 TDLS Direct Link Teardown ++ The TDLS Teardown frame shall be sent over the direct path and the reason ++ code shall be set to "TDLS 40 direct link teardown for unspecified reason", ++ except when the TDLS peer STA is unreachable via the TDLS direct link, ++ in which case, the TDLS Teardown frame shall be sent through the AP and ++ the reason code shall be set to "TDLS direct link teardown due to TDLS peer ++ STA unreachable via the TDLS direct link". ++ */ ++ /* if (prStaRec->fgIsInPS == TRUE) */ ++ /* ++ check if the packet is tear down: ++ we do not want to use PTI to indicate the tear down and ++ we want to send the tear down to AP then AP help us to send it ++ */ ++ struct sk_buff *prSkb; ++ UINT8 *pEth; ++ UINT_16 u2EtherTypeLen; ++ ++ prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ if (prSkb != NULL) { ++ UINT8 ucActionCode, ucReasonCode; ++ ++ /* init */ ++ pEth = prSkb->data; ++ u2EtherTypeLen = (pEth[ETH_TYPE_LEN_OFFSET] << 8) | ++ (pEth[ETH_TYPE_LEN_OFFSET + 1]); ++ ucActionCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 3]; ++ ucReasonCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] | ++ (pEth[ETH_TYPE_LEN_OFFSET + 1 + 5] << 8); ++ ++ /* TDLS_REASON_CODE_UNREACHABLE: keep alive fail or PTI timeout */ ++ if ((u2EtherTypeLen == TDLS_FRM_PROT_TYPE) && ++ (ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && ++ (ucReasonCode == TDLS_REASON_CODE_UNREACHABLE)) { ++ /* ++ when we cannot reach the peer, ++ we need AP's help to send the tear down frame ++ */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prStaRec = prBssInfo->prStaRecOfAP; ++ if (prStaRec == NULL) { ++ Status = TDLS_STATUS_FAILURE; ++ break; ++ } ++#if 0 ++ /* change status code */ ++ pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] = TDLS_REASON_CODE_UNREACHABLE; ++#endif ++ } ++ } ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ } ++ } while (FALSE); ++ ++ DBGLOG(TDLS, INFO, " %s: (Status=%x) [%pM] ucStaRecIndex = %d!\n", ++ __func__, (INT32) Status, (prMsduInfo->aucEthDestAddr), ++ prMsduInfo->ucStaRecIndex); ++ return Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to check if we suffer timeout for TX quota empty case. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota) ++{ ++ OS_SYSTIME rCurTime; ++ ++ /* sanity check */ ++ if (!IS_TDLS_STA(prStaRec)) ++ return; ++ ++ if (FreeQuota != 0) { ++ /* reset timeout */ ++ prStaRec->rTdlsTxQuotaEmptyTime = 0; ++ return; ++ } ++ ++ /* work-around: check if the no free quota case is too long */ ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (prStaRec->rTdlsTxQuotaEmptyTime == 0) { ++ prStaRec->rTdlsTxQuotaEmptyTime = rCurTime; ++ } else { ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsTxQuotaEmptyTime, ++ SEC_TO_SYSTIME(TDLS_TX_QUOTA_EMPTY_TIMEOUT))) { ++ /* tear down the link */ ++ DBGLOG(TDLS, WARN, ++ " %s: [%pM] TX quota empty timeout!\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, ++ TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY, NULL); ++ ++ /* inform tear down to supplicant only in OPEN/NONE mode */ ++ /* ++ we need to tear down the link manually; or supplicant will display ++ "No FTIE in TDLS Teardown" and it will not tear down the link ++ */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNREACHABLE, GFP_ATOMIC); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to un-initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexUninit(ADAPTER_T *prAdapter) ++{ ++#if TDLS_CFG_CMD_TEST ++ cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); ++#endif /* TDLS_CFG_CMD_TEST */ ++} ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++/* End of tdls.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c +new file mode 100644 +index 000000000000..5450cbb65183 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c +@@ -0,0 +1,741 @@ ++/* ++** Id: tdls_com.c#1 ++*/ ++ ++/*! \file tdls_com.c ++ \brief This file includes IEEE802.11z TDLS main support. ++*/ ++ ++/* ++** Log: tdls_com.c ++ * ++ * 11 13 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++ ++#include "precomp.h" ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "tdls.h" ++ ++ /******************************************************************************* ++ * C O N S T A N T S ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * F U N C T I O N D E C L A R A T I O N S ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * P R I V A T E D A T A ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * P R I V A T E F U N C T I O N S ++ ******************************************************************************** ++ */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to append general IEs. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure. ++* \param[in] u2StatusCode Status code. ++* \param[in] pPkt Pointer to the frame body ++* ++* \retval append length ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ UINT_32 u4NonHTPhyType; ++ UINT_16 u2SupportedRateSet; ++ UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; ++ UINT_8 ucAllSupportedRatesLen; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ UINT_32 u4PktLen, u4IeLen; ++ BOOLEAN fg40mAllowed; ++ ++ /* reference to assocBuildReAssocReqFrameCommonIEs() */ ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ ++ /* 3. Frame Formation - (5) Supported Rates element */ ++ /* use all sup rate we can support */ ++ if (prStaRec != NULL) ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ else ++ u4NonHTPhyType = PHY_TYPE_ERP_INDEX; /* default */ ++ ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ ++ if (prStaRec != NULL) { ++ u2SupportedRateSet &= prStaRec->u2OperationalRateSet; ++ ++ if (u2SupportedRateSet == 0) ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ } ++ ++ rateGetDataRatesFromRateSet(u2SupportedRateSet, ++ prBssInfo->u2BSSBasicRateSet, aucAllSupportedRates, &ucAllSupportedRatesLen); ++ ++ ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? ++ ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); ++ ++ ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; ++ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pPkt)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pPkt)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pPkt)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (7) Extended sup rates element */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pPkt)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pPkt)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pPkt)->aucExtSupportedRates, ++ &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (8) Supported channels element */ ++ /* ++ The Supported channels element is included in Request frame and also in Response ++ frame if Status Code 0 (successful). ++ */ ++ if (u2StatusCode == 0) { ++ SUPPORTED_CHANNELS_IE(pPkt)->ucId = ELEM_ID_SUP_CHS; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 2; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[0] = 1; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[1] = 11; ++ ++#if CFG_SUPPORT_DFS ++ if (prAdapter->fgEnable5GBand == TRUE) { ++ /* 5G support */ ++ SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 10; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[2] = 36; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[3] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[4] = 52; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[5] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[6] = 149; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[7] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[8] = 165; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[9] = 4; ++ } ++#endif /* CFG_SUPPORT_DFS */ ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (14) HT capabilities element */ ++ ++ /* no need to check AP capability */ ++/* if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && */ ++ ++ /* ++ after we set ucPhyTypeSet to PHY_TYPE_SET_802_11N in TdlsexRxFrameHandle(), ++ supplicant will disable link if exists and we will clear prStaRec. ++ ++ finally, prStaRec->ucPhyTypeSet will also be 0 ++ ++ so we have a fix in TdlsexPeerAdd(). ++ */ ++ if (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ /* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */ ++#if 0 /* always support */ ++ if (prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode == CONFIG_BW_20M) ++ fg40mAllowed = FALSE; ++ else ++#endif ++ fg40mAllowed = TRUE; ++ ++ u4IeLen = rlmFillHtCapIEByParams(fg40mAllowed, ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, ++ prAdapter->rWifiVar.u8SupportRxSgi20, ++ prAdapter->rWifiVar.u8SupportRxSgi40, ++ prAdapter->rWifiVar.u8SupportRxGf, ++ prAdapter->rWifiVar.u8SupportRxSTBC, prBssInfo->eCurrentOPMode, pPkt); ++ ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (17) WMM Information element */ ++ ++ /* always support */ ++/* if (prAdapter->rWifiVar.fgSupportQoS) */ ++ ++ { ++ /* force to support all UAPSD in TDLS link */ ++ u4IeLen = mqmGenerateWmmInfoIEByParam(TRUE /*prAdapter->rWifiVar.fgSupportUAPSD */ , ++ 0xf /*prPmProfSetupInfo->ucBmpDeliveryAC */ , ++ 0xf /*prPmProfSetupInfo->ucBmpTriggerAC */ , ++ WMM_MAX_SP_LENGTH_ALL /*prPmProfSetupInfo->ucUapsdSp */ , ++ pPkt); ++ ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ return u4PktLen; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to transmit a TDLS data frame (setup req/rsp/confirm and tear down). ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure. ++* \param[in] pPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] ucActionCode TDLS Action ++* \param[in] ucDialogToken Dialog token ++* \param[in] u2StatusCode Status code ++* \param[in] pAppendIe Others IEs (here are security IEs from supplicant) ++* \param[in] AppendIeLen IE length of others IEs ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS ++TdlsDataFrameSend(ADAPTER_T *prAdapter, ++ STA_RECORD_T *prStaRec, ++ UINT_8 *pPeerMac, ++ UINT_8 ucActionCode, ++ UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen) ++{ ++#define LR_TDLS_FME_FIELD_FILL(__Len) \ ++do { \ ++ pPkt += __Len; \ ++ u4PktLen += __Len; \ ++} while (0) ++ ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ struct sk_buff *prMsduInfo; ++ MSDU_INFO_T *prMsduInfoMgmt; ++ UINT8 *pPkt, *pucInitiator, *pucResponder; ++ UINT32 u4PktLen, u4IeLen; ++ UINT16 u2CapInfo; ++/* UINT8 *pPktTemp; */ ++ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ ++ DBGLOG(TDLS, INFO, " %s: 2040=%d\n", __func__, prGlueInfo->rTdlsLink.fgIs2040Sup); ++ ++ /* sanity check */ ++ if (prStaRec != NULL) { ++ if (prStaRec->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { ++ DBGLOG(TDLS, ERROR, ++ " %s: net index %d fail\n", __func__, prStaRec->ucNetTypeIndex); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ } else { ++ /* prStaRec maybe NULL in setup request */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ } ++ ++ /* allocate/init packet */ ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ prMsduInfo = NULL; ++ prMsduInfoMgmt = NULL; ++ ++ /* make up frame content */ ++ if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { ++ /* ++ The STAUT will not respond to a TDLS Discovery Request Frame with different BSSID. ++ Supplicant will check this in wpa_tdls_process_discovery_request(). ++ */ ++ ++ /* TODO: reduce 1600 to correct size */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* 1. 802.3 header */ ++/* pPktTemp = pPkt; */ ++ kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } else { ++ /* discovery response */ ++ WLAN_MAC_HEADER_T *prHdr; ++ ++ prMsduInfoMgmt = (MSDU_INFO_T *) ++ cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); ++ if (prMsduInfoMgmt == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate mgmt pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ pPkt = (UINT8 *) prMsduInfoMgmt->prPacket; ++ prHdr = (WLAN_MAC_HEADER_T *) pPkt; ++ ++ /* 1. 802.11 header */ ++ prHdr->u2FrameCtrl = MAC_FRAME_ACTION; ++ prHdr->u2DurationID = 0; ++ kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, TDLS_FME_MAC_ADDR_LEN); ++ prHdr->u2SeqCtrl = 0; ++ LR_TDLS_FME_FIELD_FILL(sizeof(WLAN_MAC_HEADER_T)); ++ ++ /* Frame Formation - (1) Category */ ++ *pPkt = CATEGORY_PUBLIC_ACTION; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = ucActionCode; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - Status Code */ ++ switch (ucActionCode) { ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ case TDLS_FRM_ACTION_TEARDOWN: ++ WLAN_SET_FIELD_16(pPkt, u2StatusCode); ++ LR_TDLS_FME_FIELD_FILL(2); ++ break; ++ } ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } ++ ++ /* Fill elements */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* ++ Capability ++ ++ Support Rates ++ Extended Support Rates ++ Supported Channels ++ HT Capabilities ++ WMM Information Element ++ ++ Extended Capabilities ++ Link Identifier ++ ++ RSNIE ++ FTIE ++ Timeout Interval ++ */ ++ if (ucActionCode != TDLS_FRM_ACTION_CONFIRM) { ++ /* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be set */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ /* ++ TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode ++ must be CONFIG_BW_20_40M. ++ ++ TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if ++ Tdls 20/40 is enabled. ++ */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, u2StatusCode, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 5. Frame Formation - Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } else { ++ /* 5. Frame Formation - WMM Parameter element */ ++ if (prAdapter->rWifiVar.fgSupportQoS) { ++ u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, ++ prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); ++ ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ } ++ } ++ ++ /* 6. Frame Formation - 20/40 BSS Coexistence */ ++ /* ++ Follow WiFi test plan, add 20/40 element to request/response/confirm. ++ */ ++/* if (prGlueInfo->rTdlsLink.fgIs2040Sup == TRUE) */ /* force to enable */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* ++ bit0 = 1: The Information Request field is used to indicate that a ++ transmitting STA is requesting the recipient to transmit a 20/40 BSS ++ Coexistence Management frame with the transmitting STA as the ++ recipient. ++ ++ bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP ++ that receives this information or reports of this information from ++ operating a 20/40 MHz BSS. ++ ++ bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit ++ a receiving AP from operating its BSS as a 20/40 MHz BSS. ++ */ ++ BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; ++ BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; ++ LR_TDLS_FME_FIELD_FILL(3); ++ } ++ ++ /* 6. Frame Formation - HT Operation element */ ++/* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */ ++/* LR_TDLS_FME_FIELD_FILL(u4IeLen); */ ++ ++ /* 7. Frame Formation - Link identifier element */ ++ /* Note1: Link ID sequence must be correct; Or the calculated MIC will be error */ ++ /* ++ Note2: When we receive a setup request with link ID, Marvell will send setup response ++ to the peer in link ID, not the SA in the WLAN header. ++ */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ ++ switch (ucActionCode) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ case TDLS_FRM_ACTION_CONFIRM: ++ default: ++ /* we are initiator */ ++ pucInitiator = prBssInfo->aucOwnMacAddr; ++ pucResponder = pPeerMac; ++ ++ if (prStaRec != NULL) ++ prStaRec->flgTdlsIsInitiator = TRUE; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ ++ if (prStaRec != NULL) ++ prStaRec->flgTdlsIsInitiator = FALSE; ++ break; ++ ++ case TDLS_FRM_ACTION_TEARDOWN: ++ if (prStaRec != NULL) { ++ if (prStaRec->flgTdlsIsInitiator == TRUE) { ++ /* we are initiator */ ++ pucInitiator = prBssInfo->aucOwnMacAddr; ++ pucResponder = pPeerMac; ++ } else { ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ } ++ } else { ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ } ++ break; ++ } ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pucInitiator, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pucResponder, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 8. Append security IEs */ ++ /* ++ 11.21.5 TDLS Direct Link Teardown ++ If the STA has security enabled on the link 37 with the AP, then the FTIE shall be ++ included in the TDLS Teardown frame. ++ ++ For ralink station, it can accept our tear down without FTIE but marvell station. ++ */ ++/* if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) && (pAppendIe != NULL)) */ ++ if (pAppendIe != NULL) { ++ if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || ++ ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && ++ (prStaRec != NULL) && (prStaRec->fgTdlsInSecurityMode == TRUE))) { ++ kalMemCopy(pPkt, pAppendIe, AppendIeLen); ++ LR_TDLS_FME_FIELD_FILL(AppendIeLen); ++ } ++ } ++ ++ /* 7. Append Supported Operating Classes IE */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* Note: if we do not put the IE, Marvell STA will decline our TDLS setup request */ ++ u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ ++ /* 11. send the data or management frame */ ++ if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { ++#if 0 ++ /* ++ Note1: remember to modify our MAC & AP MAC & peer MAC in LINK ID ++ Note2: dialog token in rsp & confirm must be same as sender. ++ */ ++ ++#if 1 ++ /* example for Ralink's and Broadcom's TDLS setup request frame in open/none */ ++ if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { ++#if 0 ++ /* mediatek */ ++ char buffer[] = { 0x31, 0x04, ++ 0x01, 0x08, 0x02, 0x04, 0x0b, 0x16, 0xc, 0x12, 0x18, 0x24, ++ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, ++ 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, ++ 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e ++ }; ++#endif ++ ++#if 1 ++ /* ralink *//* from capability */ ++ char buffer[] = { 0x21, 0x04, ++ 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, ++ 0x32, 0x04, 0x0c, 0x18, 0x30, 0x60, ++ 0x24, 0x06, 0x01, 0x0b, 0x24, 0x08, 0x95, 0x04, ++ 0x7f, 0x05, 0x01, 0x00, 0x00, 0x50, 0x20, ++ 0x3b, 0x10, 0x20, 0x01, 0x02, 0x03, 0x04, 0x0c, 0x16, 0x17, 0x18, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f ++ }; ++#endif ++#if 0 ++ /* 6630 */ ++ char buffer[] = { 0x01, 0x01, ++ 0x01, 0x04, 0x02, 0x04, 0x0b, 0x16, ++ 0x24, 0x02, 0x01, 0x0d, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0xff, ++ 0x2d, 0x1a, 0x61, 0x01, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00, ++ 0xbf, 0x0c, 0x30, 0x01, 0x80, 0x03, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, ++ 0x00, 0x00 ++ }; ++#endif ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++ ++#if 1 ++ if (ucActionCode == TDLS_FRM_ACTION_CONFIRM) { ++ /* Note: dialog token must be same as request */ ++#if 1 ++ /* ralink */ ++ char buffer[] = { 0x00, ++ 0x01, 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x00, 0x03, ++ 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, ++ 0x62, 0x32, 0x2f, 0x00 ++ }; ++#endif ++ ++#if 0 ++ /* 6630 */ ++ char buffer[] = { 0x00, ++ 0x01, ++ 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x3f, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00 ++ }; ++#endif ++ ++#if 0 ++ /* A/D die */ ++ char buffer[] = { 0x00, ++ 0x01, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x6b, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x38, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, ++ 0x1c, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e ++ }; ++#endif ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++ ++#else ++ ++#if 0 ++ /* for test in open/none */ ++ if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { ++ char buffer[] = { 0x01, 0x04, ++ 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, ++ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, ++ 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, ++ 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1e, 0x20, 0x21 ++ }; ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++#endif /* 0 */ ++ ++ /* 9. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ } else { ++ /* ++ A TDLS capable STA that receives a TDLS Discovery Request frame is required to ++ send the response "to the requesting STA, via the direct path." ++ However, prior to establishment of the direct link, the responding STA may not ++ know the rate capabilities of the requesting STA. In this case, the responding ++ STA shall send the TDLS Discovery Response frame using a rate from the ++ BSSBasicRateSet of the BSS to which the STA is currently associated. ++ */ ++ prMsduInfoMgmt->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfoMgmt->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfoMgmt->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfoMgmt->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfoMgmt->fgIs802_1x = FALSE; ++ prMsduInfoMgmt->fgIs802_11 = TRUE; ++ prMsduInfoMgmt->u2FrameLength = u4PktLen; ++ prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfoMgmt->pfTxDoneHandler = NULL; ++ prMsduInfoMgmt->fgIsBasicRate = TRUE; /* use basic rate */ ++ ++ /* Send them to HW queue */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt); ++ } ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* End of tdls_com.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c +new file mode 100644 +index 000000000000..af66ef95d17c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c +@@ -0,0 +1,491 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/wapi.c#1 ++*/ ++ ++/*! \file "wapi.c" ++ \brief This file including the WAPI related function. ++ ++ This file provided the macros and functions library support the wapi ie parsing, ++ cipher and AKM check to help the AP seleced deciding. ++*/ ++ ++/* ++** Log: wapi.c ++** ++** 10 24 2012 wh.su ++** [ALPS00376392] [klocwork 9.1] in wapi.c, line 344 ++** Use MAX_NUM_SUPPORTED_WAPI_AKM_SUITESfor avoid Klocwork warning. ++** ++** 10 24 2012 wh.su ++** [ALPS00376391] [klocwork 9.1] in wapi.c, line 311 ++** Use the MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES for avoid Klccwork waring. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * fixed the network type ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 07 20 2010 wh.su ++ * ++ * . ++ * ++ * 04 06 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the firmware return the broadcast frame at wrong tc. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function to check and update the default wapi tx ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the generate wapi ie function, and replace the tabe by space ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++#if CFG_SUPPORT_WAPI ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WPA IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WPA IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 68 :0x44 */ ++ if (/* prWlanInfo->fgWapiMode && */ prAdapter->prGlueInfo->u2WapiAssocInfoIESz) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWapiAssocInfoIEs, ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WapiAssocInfoIESz; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse WAPI IE. ++* ++* \param[in] prInfoElem Pointer to the RSN IE ++* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the ++** WAPI information from the given WAPI IE ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainWapiIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = WAPI_CIPHER_SUITE_WPI; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUCHAR pucPairSuite = NULL; ++ PUCHAR pucAuthSuite = NULL; ++ PUCHAR cp; ++ ++ DEBUGFUNC("wapiParseWapiIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prWapiInfo); ++ ++ /* Verify the length of the WAPI IE. */ ++ if (prInfoElem->ucLength < 6) { ++ DBGLOG(SEC, TRACE, "WAPI IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check WAPI version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(SEC, TRACE, "Unsupported WAPI IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) &prInfoElem->u2AuthKeyMgtSuiteCount; ++ u4RemainWapiIeLen = (INT_32) prInfoElem->ucLength - 2; ++ ++ do { ++ if (u4RemainWapiIeLen == 0) ++ break; ++ ++ /* ++ AuthCount : 2 ++ AuthSuite : 4 * authSuiteCount ++ PairwiseCount: 2 ++ PairwiseSuite: 4 * pairSuiteCount ++ GroupSuite : 4 ++ Cap : 2 */ ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count ++ field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainWapiIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainWapiIeLen < (INT_32) i) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainWapiIeLen -= (INT_32) i; ++ ++ if (u4RemainWapiIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainWapiIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainWapiIeLen < (INT_32) i) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainWapiIeLen -= (INT_32) i; ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainWapiIeLen < 4) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainWapiIeLen -= 4; ++ ++ /* Parse the WAPI u2Capabilities field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in WAPI capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ u4RemainWapiIeLen -= 2; ++ ++ /* Todo:: BKID support */ ++ } while (FALSE); ++ ++ /* Save the WAPI information for the BSS. */ ++ ++ prWapiInfo->ucElemId = ELEM_ID_WAPI; ++ ++ prWapiInfo->u2Version = u2Version; ++ ++ prWapiInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(SEC, LOUD, "WAPI: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES; ++ ++ prWapiInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prWapiInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for WAPI: WPI. */ ++ prWapiInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prWapiInfo->au4PairwiseKeyCipherSuite[0] = WAPI_CIPHER_SUITE_WPI; ++ ++ DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_WAPI_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_WAPI_AKM_SUITES; ++ ++ prWapiInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prWapiInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(SEC, LOUD, "WAPI: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for WAPI. */ ++ prWapiInfo->u4AuthKeyMgtSuiteCount = 1; ++ prWapiInfo->au4AuthKeyMgtSuite[0] = WAPI_AKM_SUITE_802_1X; ++ ++ DBGLOG(SEC, LOUD, "WAPI: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ prWapiInfo->u2WapiCap = u2Cap; ++ DBGLOG(SEC, LOUD, "WAPI: cap: 0x%04x\n", prWapiInfo->u2WapiCap); ++ ++ return TRUE; ++} /* wapiParseWapiIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to perform WAPI policy selection for a given BSS. ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] prBss Pointer to the BSS description ++* ++* \retval TRUE - The WAPI policy selection for the given BSS is ++* successful. The selected pairwise and group cipher suites ++* are returned in the BSS description. ++* \retval FALSE - The WAPI policy selection for the given BSS is failed. ++* The driver shall not attempt to join the given BSS. ++* ++* \note The Encrypt status matched score will save to bss for final ap select. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++ UINT_32 i; ++ UINT_32 u4PairwiseCipher = 0; ++ UINT_32 u4GroupCipher = 0; ++ UINT_32 u4AkmSuite = 0; ++ P_WAPI_INFO_T prBssWapiInfo; ++ P_WLAN_INFO_T prWlanInfo; ++ ++ DEBUGFUNC("wapiPerformPolicySelection"); ++ ++ ASSERT(prBss); ++ ++ /* Notice!!!! WAPI AP not set the privacy bit for WAI and WAI-PSK at WZC configuration mode */ ++ prWlanInfo = &prAdapter->rWlanInfo; ++ ++ if (prBss->fgIEWAPI) { ++ prBssWapiInfo = &prBss->rIEWAPI; ++ } else { ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode == FALSE) { ++ DBGLOG(SEC, TRACE, "-- No Protected BSS\n"); ++ return TRUE; ++ } ++ DBGLOG(SEC, TRACE, "WAPI Information Element does not exist.\n"); ++ return FALSE; ++ } ++ ++ /* Select pairwise/group ciphers */ ++ for (i = 0; i < prBssWapiInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (prBssWapiInfo->au4PairwiseKeyCipherSuite[i] == ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher) { ++ u4PairwiseCipher = prBssWapiInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (prBssWapiInfo->u4GroupKeyCipherSuite == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher) ++ u4GroupCipher = prBssWapiInfo->u4GroupKeyCipherSuite; ++ ++ /* Exception handler */ ++ /* If we cannot find proper pairwise and group cipher suites to join the ++ BSS, do not check the supported AKM suites. */ ++ if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { ++ DBGLOG(SEC, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ ++ /* Select AKM */ ++ /* If the driver cannot support any authentication suites advertised in ++ the given BSS, we fail to perform RSNA policy selection. */ ++ /* Attempt to find any overlapping supported AKM suite. */ ++ for (i = 0; i < prBssWapiInfo->u4AuthKeyMgtSuiteCount; i++) { ++ if (prBssWapiInfo->au4AuthKeyMgtSuite[i] == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite) { ++ u4AkmSuite = prBssWapiInfo->au4AuthKeyMgtSuite[i]; ++ break; ++ } ++ } ++ ++ if (u4AkmSuite == 0) { ++ DBGLOG(SEC, TRACE, "Cannot support any AKM suites\n"); ++ return FALSE; ++ } ++ ++ DBGLOG(SEC, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4PairwiseCipher & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), ++ (UINT_8) (u4GroupCipher & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); ++ ++ DBGLOG(SEC, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4AkmSuite & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); ++ ++ return TRUE; ++} /* wapiPerformPolicySelection */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is use for wapi mode, to update the current wpi tx idx ? 0 :1 . ++* ++* \param[in] prStaRec Pointer to the Sta record ++* \param[out] ucWlanIdx The Rx status->wlanidx field ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiUpdateTxKeyIdx(IN P_STA_RECORD_T prStaRec, IN UINT_8 ucWlanIdx) ++{ ++ UINT_8 ucKeyId; ++ ++ if ((ucWlanIdx & BITS(0, 3)) == CIPHER_SUITE_WPI) { ++ ++ ucKeyId = ((ucWlanIdx & BITS(4, 5)) >> 4); ++ ++ if (ucKeyId != g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey) { ++ DBGLOG(RSN, STATE, ++ "Change wapi key index from %d->%d\n", ++ g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey, ucKeyId); ++ g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey = ucKeyId; ++ ++ prStaRec->ucWTEntry = ++ (ucKeyId == ++ WTBL_AIS_BSSID_WAPI_IDX_0) ? WTBL_AIS_BSSID_WAPI_IDX_0 : WTBL_AIS_BSSID_WAPI_IDX_1; ++ } ++ } ++} ++#endif ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c +new file mode 100644 +index 000000000000..f54d22941148 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c +@@ -0,0 +1,301 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/mgmt/wnm.c#1 ++*/ ++ ++/*! \file "wnm.c" ++ \brief This file includes the 802.11v default vale and functions. ++*/ ++ ++/* ++** Log: wnm.c ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_802_11V ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define WNM_MAX_TOD_ERROR 0 ++#define WNM_MAX_TOA_ERROR 0 ++#define MICRO_TO_10NANO(x) ((x)*100) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static UINT_8 ucTimingMeasToken; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11v wnm category action frame. ++* ++* ++* \note ++* Called by: Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_ACTION_FRAME prRxFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ if (prRxFrame->ucAction == ACTION_WNM_TIMING_MEASUREMENT_REQUEST) { ++ wnmTimingMeasRequest(prAdapter, prSwRfb); ++ return; ++ } ++#endif ++ ++ DBGLOG(WNM, TRACE, "Unsupport WNM action frame: %d\n", prRxFrame->ucAction); ++} ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to report timing measurement data. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, TRACE, "wnmReportTimingMeas: u4ToD %x u4ToA %x", u4ToD, u4ToA); ++ ++ if (!prStaRec->rWNMTimingMsmt.ucTrigger) ++ return; ++ ++ prStaRec->rWNMTimingMsmt.u4ToD = MICRO_TO_10NANO(u4ToD); ++ prStaRec->rWNMTimingMsmt.u4ToA = MICRO_TO_10NANO(u4ToA); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(TimingMeasurement) Event. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Timing Measurement frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ DBGLOG(WNM, LOUD, "EVENT-TX DONE: Current Time = %u\n", kalGetTimeTick()); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ ++ ++ DBGLOG(WNM, TRACE, "wnmRunEventTimgingMeasTxDone: ucDialog %d ucFollowUp %d u4ToD %x u4ToA %x", ++ prStaRec->rWNMTimingMsmt.ucDialogToken, ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken, ++ prStaRec->rWNMTimingMsmt.u4ToD, prStaRec->rWNMTimingMsmt.u4ToA); ++ ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, NULL); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wnmRunEventTimgingMeasTxDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Timing Measurement frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME prTxFrame; ++ UINT_16 u2PayloadLen; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_UNPROTECTED_WNM_ACTION; ++ prTxFrame->ucAction = ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT; ++ ++ /* 3 Compose the frame body's frame. */ ++ prTxFrame->ucDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; ++ prTxFrame->ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken; ++ prTxFrame->u4ToD = prStaRec->rWNMTimingMsmt.u4ToD; ++ prTxFrame->u4ToA = prStaRec->rWNMTimingMsmt.u4ToA; ++ prTxFrame->ucMaxToDErr = WNM_MAX_TOD_ERROR; ++ prTxFrame->ucMaxToAErr = WNM_MAX_TOA_ERROR; ++ ++ u2PayloadLen = 2 + ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ DBGLOG(WNM, TRACE, "wnmComposeTimingMeasFrame: ucDialogToken %d ucFollowUpDialogToken %d u4ToD %x u4ToA %x\n", ++ prTxFrame->ucDialogToken, prTxFrame->ucFollowUpDialogToken, ++ prTxFrame->u4ToD, prTxFrame->u4ToA); ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return; ++ ++} /* end of wnmComposeTimingMeasFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11v timing measurement request. ++* ++* ++* \note ++* Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_WNM_TIMING_MEAS_REQ_FRAME prRxFrame = NULL; ++ P_STA_RECORD_T prStaRec; ++ ++ prRxFrame = (P_ACTION_WNM_TIMING_MEAS_REQ_FRAME) prSwRfb->pvHeader; ++ if (!prRxFrame) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, TRACE, "IEEE 802.11: Received Timing Measuremen Request from %pM\n" ++ prStaRec->aucMacAdd); ++ ++ /* reset timing msmt */ ++ prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; ++ prStaRec->rWNMTimingMsmt.ucTrigger = prRxFrame->ucTrigger; ++ if (!prRxFrame->ucTrigger) ++ return; ++ ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); ++} ++ ++#if WNM_UNIT_TEST ++VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, INFO, "IEEE 802.11v: Test Timing Measuremen Request from %pM\n", ++ prStaRec->aucMacAddr); ++ ++ prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; ++ prStaRec->rWNMTimingMsmt.ucTrigger = 1; ++ ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); ++} ++#endif ++ ++#endif /* CFG_SUPPORT_802_11V_TIMING_MEASUREMENT */ ++ ++#endif /* CFG_SUPPORT_802_11V */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c +new file mode 100644 +index 000000000000..6f1bb6fd771e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c +@@ -0,0 +1,254 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/cmd_buf.c#1 ++*/ ++ ++/*! \file "cmd_buf.c" ++ \brief This file contain the management function of internal Command Buffer ++ for CMD_INFO_T. ++ ++ We'll convert the OID into Command Packet and then send to FW. Thus we need ++ to copy the OID information to Command Buffer for following reasons. ++ 1. The data structure of OID information may not equal to the data structure of ++ Command, we cannot use the OID buffer directly. ++ 2. If the Command was not generated by driver we also need a place to store the ++ information. ++ 3. Because the CMD is NOT FIFO when doing memory allocation (CMD will be generated ++ from OID or interrupt handler), thus we'll use the Block style of Memory Allocation ++ here. ++*/ ++ ++/* ++** Log: cmd_buf.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. clear prPendingCmdInfo properly ++ * * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-13 21:59:08 GMT mtk01084 ++** remove un-neceasary spaces ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-05-20 12:24:26 GMT mtk01461 ++** Increase CMD Buffer - HIF_RX_HW_APPENDED_LEN when doing CMD_INFO_T allocation ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 09:41:08 GMT mtk01461 ++** Add init of Driver Domain MCR flag and fix lint MTK WARN ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-17 19:51:45 GMT mtk01461 ++** allocation function of CMD_INFO_T ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static BOOLEAN fgCmdDumpIsDone = FALSE; ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initial the MGMT memory pool for CMD Packet. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ QUEUE_INITIALIZE(&prAdapter->rFreeCmdList); ++ ++ for (i = 0; i < CFG_TX_MAX_CMD_PKT_NUM; i++) { ++ prCmdInfo = &prAdapter->arHifCmdDesc[i]; ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ } ++ fgCmdDumpIsDone = FALSE; ++} /* end of cmdBufInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief dump CMD queue and print to trace, for debug use only ++* @param[in] prQueue Pointer to the command Queue to be dumped ++* @param[in] quename Name of the queue ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName) ++{ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_HEAD(prQueue); ++ ++ DBGLOG(NIC, INFO, "Dump CMD info for %s, Elem number:%u\n", queName, prQueue->u4NumElem); ++ while (prCmdInfo) { ++ P_CMD_INFO_T prCmdInfo1, prCmdInfo2, prCmdInfo3; ++ ++ prCmdInfo1 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo); ++ if (!prCmdInfo1) { ++ DBGLOG(NIC, INFO, "CID:%d SEQ:%d\n", prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum); ++ break; ++ } ++ prCmdInfo2 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo1); ++ if (!prCmdInfo2) { ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, ++ prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum); ++ break; ++ } ++ prCmdInfo3 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo2); ++ if (!prCmdInfo3) { ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, ++ prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum, ++ prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum); ++ break; ++ } ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", ++ prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, ++ prCmdInfo1->ucCmdSeqNum, prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum, ++ prCmdInfo3->ucCID, prCmdInfo3->ucCmdSeqNum); ++ prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo3); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Allocate CMD_INFO_T from a free list and MGMT memory pool. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] u4Length Length of the frame buffer to allocate. ++* ++* @retval NULL Pointer to the valid CMD Packet handler ++* @retval !NULL Fail to allocat CMD Packet ++*/ ++/*----------------------------------------------------------------------------*/ ++P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("cmdBufAllocateCmdInfo"); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ /* Setup initial value in CMD_INFO_T */ ++ /* Start address of allocated memory */ ++ prCmdInfo->pucInfoBuffer = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); ++ ++ if (prCmdInfo->pucInfoBuffer == NULL) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ prCmdInfo = NULL; ++ ++ DBGLOG(NIC, ERROR, "Allocate prCmdInfo->pucInfoBuffer fail!\n"); ++ } else { ++ prCmdInfo->u2InfoBufLen = 0; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ } ++ fgCmdDumpIsDone = FALSE; ++ } else if (!fgCmdDumpIsDone) { ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ P_QUE_T prCmdQue = &prGlueInfo->rCmdQueue; ++ P_QUE_T prPendingCmdQue = &prAdapter->rPendingCmdQueue; ++ P_TX_TCQ_STATUS_T prTc = &prAdapter->rTxCtrl.rTc; ++ ++ fgCmdDumpIsDone = TRUE; ++ cmdBufDumpCmdQueue(prCmdQue, "waiting Tx CMD queue"); ++ cmdBufDumpCmdQueue(prPendingCmdQue, "waiting response CMD queue"); ++ DBGLOG(NIC, INFO, "Tc4 number:%d\n", prTc->aucFreeBufferCount[TC4_INDEX]); ++ if (prTc->aucFreeBufferCount[TC4_INDEX] != 0) ++ glDoChipReset(); ++ } ++ ++ return prCmdInfo; ++ ++} /* end of cmdBufAllocateCmdInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to free the CMD Packet to the MGMT memory pool. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo CMD Packet handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("cmdBufFreeCmdInfo"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo) { ++ if (prCmdInfo->pucInfoBuffer) { ++ cnmMemFree(prAdapter, prCmdInfo->pucInfoBuffer); ++ prCmdInfo->pucInfoBuffer = NULL; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ } ++ ++ return; ++ ++} /* end of cmdBufFreeCmdPacket() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c +new file mode 100644 +index 000000000000..dfaaedd118bf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c +@@ -0,0 +1,4062 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic.c#2 ++*/ ++ ++/*! \file nic.c ++ \brief Functions that provide operation in NIC's (Network Interface Card) point of view. ++ ++ This file includes functions which unite multiple hal(Hardware) operations ++ and also take the responsibility of Software Resource Management in order ++ to keep the synchronization with Hardware Manipulation. ++*/ ++ ++/* ++** Log: nic.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 05 02 2012 terry.wu ++ * NULL ++ * Set the default value of AP StaRec index to "STA_REC_INDEX_NOT_FOUND" in update firmware bss command. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when ++ * returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 11 22 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * keep debug counter setting after wake up. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001079] [MT5931][Driver] Release pending MMPDU only when BSS is being deactivated ++ * pre-check for NULL before calling MMPDU free function ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to ++ * the AP.. ++ * ++ * 10 11 2011 terry.wu ++ * NULL ++ * Rewrite Assert Dump Function for Portability. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * New CMD definition about RLM parameters ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device ++ * issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for ++ * customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky ++ * AP which use space character as hidden SSID ++ * 1. correct logic ++ * 2. replace only BSS-DESC which doesn't have a valid SSID. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky ++ * AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 05 12 2011 puff.wen ++ * NULL ++ * FW Assert information dump to driver ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 15 2011 cp.wu ++ * [WCXRP00000651] [MT6620 Wi-Fi][Driver] Refine RSSI buffering mechanism ++ * ROLLBACK due to the special design is to workaround incorrect initial RCPI value coming from firmware domain. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 14 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected ++ * 2. add dummy function for both Win32 and Linux part. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for ++ * dedicated network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 12 2011 wh.su ++ * NULL ++ * enable the p2p check the cipher to set the bssInfo auth mode. ++ * ++ * 04 12 2011 wh.su ++ * NULL ++ * prepare the code for sync the auth mode and encryption status for P2P and BOW. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 04 10 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * Fix compiler issue. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 04 07 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside ++ * wlanAdapterStart ++ * . ++ * ++ * 04 07 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside ++ * wlanAdapterStart ++ * implementation of internal error handling of nicAllocateAdapterMemory. ++ * ++ * 03 31 2011 chinglan.wang ++ * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. ++ * . ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 08 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * Use kalPrint to print firmware assert info. ++ * ++ * 02 01 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * . ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 31 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * Print firmware ASSERT info at Android kernel log, driver side ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000372] [MT6620 Wi-Fi][Driver] Check bus access failure inside nicProcessIST() ++ * check bus error and/or card removal when retrieving interrupt status from HAL ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * 1) correct typo in scan.c ++ * 2) TX descriptors, RX descriptos and management buffer should use virtually continuous buffer instead of ++ * physically contineous one ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 12 17 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 02 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Add more control value but dont use it now. ++ * ++ * 11 30 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Add auto rate check window in registry ++ * ++ * 11 10 2010 eddie.chen ++ * [WCXRP00000156] [MT6620][FW] Change Auto rate window to 64 and add throughput swcr ++ * Use autorate parameter 1 as phy rate mask. ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to ++ * BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A ++ * reset ptrs when IEs are going to be dropped ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test ++ * with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Fix someones coding error while enable WIFI_DIRECT. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Add state change indication. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add support for P2P BSS update info. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [removing debugging] not to dump beacon content. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * FIX: structure of CMD_SET_BSS_INFO has been changed but no follow-ups are done. ++ * ++ * 07 22 2010 george.huang ++ * ++ * . ++ * ++ * 07 22 2010 george.huang ++ * ++ * Update fgIsQoS information in BSS INFO by CMD ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * update prStaRecOfAP with BSS-INFO. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill fgIsUapsdConnection when indicating BSS-CREATE with AIS-STA mode. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * correct nicProcessIST_impl() for interrupt status brought up by RX enhanced response ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always process TX interrupt first then RX interrupt. ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-16 18:03:43 GMT mtk02752 ++** handling enhanced response which fields are fetched at different moments ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-15 17:00:29 GMT mtk02752 ++** if RX enhanced response is used, D2H interrupt status should be coming from buffered result as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-15 12:01:55 GMT mtk02752 ++** if TX_DONE bit is not set but WTSR0/WTSR1 is non-zero, then set TX_DONE ++** bit due to time latency of interrupt status enhanced response ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:52:52 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-24 20:51:01 GMT mtk02752 ++** integrate with SD1 by invoking qmHandleMailboxRxMessage() ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-16 17:32:33 GMT mtk02752 ++** prepare code for invoking rxHandleMailboxRxMessage() ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:08 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-09 22:56:41 GMT mtk01084 ++** modify HW access routines ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:20 GMT mtk01084 ++** prevent warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:54:57 GMT mtk01084 ++** init HIF ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:30 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:12 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-09-09 17:26:15 GMT mtk01084 ++** modify for CFG_TEST_WITH_MT5921 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-19 10:55:22 GMT mtk01461 ++** Unmask the unused HISR ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-18 15:59:13 GMT mtk01084 ++** remove debug purpose code ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 14:05:02 GMT mtk01084 ++** update for WIFI ownback part on initial ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-04 21:32:57 GMT mtk01084 ++** add temporarily code to set driver own on adapter initialization ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:35:41 GMT mtk01461 ++** Add init of TX aggregation and fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-24 21:12:10 GMT mtk01104 ++** Add function nicRestoreSpiDefMode() ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:43:31 GMT mtk01461 ++** Revise for MTK coding style - nicInitializeAdapter() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:52:47 GMT mtk01461 ++** Update allocate Adapter Memory for MGMT Memory pool ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:57:08 GMT mtk01461 ++** Refine the order of release memory from pucRxCoalescingBufCached ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-19 18:32:57 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:00:14 GMT mtk01426 ++** Add CFG_SDIO_RX_ENHANCE support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:27 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:25:59 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++const UINT_8 aucPhyCfg2PhyTypeSet[PHY_CONFIG_NUM] = { ++ PHY_TYPE_SET_802_11ABG, /* PHY_CONFIG_802_11ABG */ ++ PHY_TYPE_SET_802_11BG, /* PHY_CONFIG_802_11BG */ ++ PHY_TYPE_SET_802_11G, /* PHY_CONFIG_802_11G */ ++ PHY_TYPE_SET_802_11A, /* PHY_CONFIG_802_11A */ ++ PHY_TYPE_SET_802_11B, /* PHY_CONFIG_802_11B */ ++ PHY_TYPE_SET_802_11ABGN, /* PHY_CONFIG_802_11ABGN */ ++ PHY_TYPE_SET_802_11BGN, /* PHY_CONFIG_802_11BGN */ ++ PHY_TYPE_SET_802_11AN, /* PHY_CONFIG_802_11AN */ ++ PHY_TYPE_SET_802_11GN /* PHY_CONFIG_802_11GN */ ++}; ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++#define REQ_GATING_ENABLE_H2D_INT BIT(31) ++#define REQ_GATING_DISABLE_H2D_INT BIT(30) ++#define ACK_GATING_ENABLE_D2H_INT BIT(31) ++#define ACK_GATING_DISABLE_D2H_INT BIT(30) ++ ++#define GATING_CONTROL_POLL_LIMIT 64 ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++static INT_EVENT_MAP_T arIntEventMapTable[] = { ++ {WHISR_ABNORMAL_INT, INT_EVENT_ABNORMAL}, ++ {WHISR_D2H_SW_INT, INT_EVENT_SW_INT}, ++ {WHISR_TX_DONE_INT, INT_EVENT_TX}, ++ {(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT), INT_EVENT_RX} ++}; ++ ++static const UINT_8 ucIntEventMapSize = (sizeof(arIntEventMapTable) / sizeof(INT_EVENT_MAP_T)); ++ ++static IST_EVENT_FUNCTION apfnEventFuncTable[] = { ++ nicProcessAbnormalInterrupt, /*!< INT_EVENT_ABNORMAL */ ++ nicProcessSoftwareInterrupt, /*!< INT_EVENT_SW_INT */ ++ nicProcessTxInterrupt, /*!< INT_EVENT_TX */ ++ nicProcessRxInterrupt, /*!< INT_EVENT_RX */ ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/*! This macro is used to reduce coding errors inside nicAllocateAdapterMemory() ++ * and also enhance the readability. ++ */ ++#define LOCAL_NIC_ALLOCATE_MEMORY(pucMem, u4Size, eMemType, pucComment) \ ++ { \ ++ DBGLOG(NIC, INFO, "Allocating %u bytes for %s.\n", u4Size, pucComment); \ ++ pucMem = (PUINT_8)kalMemAlloc(u4Size, eMemType); \ ++ if (pucMem == (PUINT_8)NULL) { \ ++ DBGLOG(NIC, ERROR, "Could not allocate %u bytes for %s.\n", u4Size, pucComment); \ ++ break; \ ++ } \ ++ ASSERT(((ULONG)pucMem % 4) == 0); \ ++ DBGLOG(NIC, TRACE, "Virtual Address = %p for %s.\n", pucMem, pucComment); \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter) ++{ ++ dumpMemory32((PUINT_32)prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++} ++ ++VOID HifRegDump(P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ UINT_32 RegVal = 0; ++ ++ for (i = 0; i <= 0x58; i += 4) { ++ if ((i != MCR_WTDR0) && (i != MCR_WTDR1) && (i != MCR_WRDR0) && ++ (i != MCR_WRDR1) && (i != MCR_WSDIOCSR) && (i != MCR_WRPLR)) { ++ HAL_MCR_RD(prAdapter, i, &RegVal); ++ DBGLOG(NIC, WARN, "HIF Reg 0x%x = 0x%x\n", i, RegVal); ++ } ++ } ++ DBGLOG(NIC, WARN, "\n\n"); ++} ++ ++BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter) ++{ ++ return prAdapter->fgIsFwOwn; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is responsible for the allocation of the data structures ++* inside the Adapter structure, include: ++* 1. SW_RFB_Ts ++* 2. Common coalescing buffer for TX PATH. ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @retval WLAN_STATUS_SUCCESS - Has enough memory. ++* @retval WLAN_STATUS_RESOURCES - Memory is not enough. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS status = WLAN_STATUS_RESOURCES; ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ ++ DEBUGFUNC("nicAllocateAdapterMemory"); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ do { ++ /* 4 <0> Reset all Memory Handler */ ++#if CFG_DBG_MGT_BUF ++ prAdapter->u4MemFreeDynamicCount = 0; ++ prAdapter->u4MemAllocDynamicCount = 0; ++#endif ++ prAdapter->pucMgtBufCached = (PUINT_8) NULL; ++ prRxCtrl->pucRxCached = (PUINT_8) NULL; ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; ++ ++ /* 4 <1> Memory for Management Memory Pool and CMD_INFO_T */ ++ /* Allocate memory for the CMD_INFO_T and its MGMT memory pool. */ ++ prAdapter->u4MgtBufCachedSize = MGT_BUFFER_SIZE; ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prAdapter->pucMgtBufCached, ++ prAdapter->u4MgtBufCachedSize, VIR_MEM_TYPE, "COMMON MGMT MEMORY POOL"); ++ ++ /* 4 <2> Memory for RX Descriptor */ ++ /* Initialize the number of rx buffers we will have in our queue. */ ++ /* We may setup ucRxPacketDescriptors by GLUE Layer, and using ++ * this variable directly. ++ */ ++ /* Allocate memory for the SW receive structures. */ ++ prRxCtrl->u4RxCachedSize = CFG_RX_MAX_PKT_NUM * ALIGN_4(sizeof(SW_RFB_T)); ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize, VIR_MEM_TYPE, "SW_RFB_T"); ++ ++ /* 4 <3> Memory for TX DEscriptor */ ++ prTxCtrl->u4TxCachedSize = CFG_TX_MAX_PKT_NUM * ALIGN_4(sizeof(MSDU_INFO_T)); ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prTxCtrl->pucTxCached, prTxCtrl->u4TxCachedSize, VIR_MEM_TYPE, "MSDU_INFO_T"); ++ ++ /* 4 <4> Memory for Common Coalescing Buffer */ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; ++ ++ /* Allocate memory for the common coalescing buffer. */ ++ prAdapter->u4CoalescingBufCachedSize = CFG_COALESCING_BUFFER_SIZE > CFG_RX_COALESCING_BUFFER_SIZE ? ++ CFG_COALESCING_BUFFER_SIZE : CFG_RX_COALESCING_BUFFER_SIZE; ++ ++ prAdapter->pucCoalescingBufCached = kalAllocateIOBuffer(prAdapter->u4CoalescingBufCachedSize); ++ ++ if (prAdapter->pucCoalescingBufCached == NULL) { ++ DBGLOG(NIC, ERROR, ++ "Could not allocate %u bytes for coalescing buffer.\n", ++ prAdapter->u4CoalescingBufCachedSize); ++ break; ++ } ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* 4 <5> Memory for enhanced interrupt response */ ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) ++ kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ if (prAdapter->prSDIOCtrl == NULL) { ++ DBGLOG(NIC, ERROR, ++ "Could not allocate %zu bytes for interrupt response.\n", ++ sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ break; ++ } ++ ++ status = WLAN_STATUS_SUCCESS; ++ ++ } while (FALSE); ++ ++ if (status != WLAN_STATUS_SUCCESS) ++ nicReleaseAdapterMemory(prAdapter); ++ ++ return status; ++ ++} /* end of nicAllocateAdapterMemory() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is responsible for releasing the allocated memory by ++* nicAllocatedAdapterMemory(). ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* 4 <5> Memory for enhanced interrupt response */ ++ if (prAdapter->prSDIOCtrl) { ++ kalReleaseIOBuffer((PVOID) prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; ++ } ++ /* 4 <4> Memory for Common Coalescing Buffer */ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ if (prAdapter->pucCoalescingBufCached) { ++ kalReleaseIOBuffer((PVOID) prAdapter->pucCoalescingBufCached, prAdapter->u4CoalescingBufCachedSize); ++ prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; ++ } ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* 4 <3> Memory for TX Descriptor */ ++ if (prTxCtrl->pucTxCached) { ++ kalMemFree((PVOID) prTxCtrl->pucTxCached, VIR_MEM_TYPE, prTxCtrl->u4TxCachedSize); ++ prTxCtrl->pucTxCached = (PUINT_8) NULL; ++ } ++ /* 4 <2> Memory for RX Descriptor */ ++ if (prRxCtrl->pucRxCached) { ++ kalMemFree((PVOID) prRxCtrl->pucRxCached, VIR_MEM_TYPE, prRxCtrl->u4RxCachedSize); ++ prRxCtrl->pucRxCached = (PUINT_8) NULL; ++ } ++ /* 4 <1> Memory for Management Memory Pool */ ++ if (prAdapter->pucMgtBufCached) { ++ kalMemFree((PVOID) prAdapter->pucMgtBufCached, VIR_MEM_TYPE, prAdapter->u4MgtBufCachedSize); ++ prAdapter->pucMgtBufCached = (PUINT_8) NULL; ++ } ++#if CFG_DBG_MGT_BUF ++ /* Check if all allocated memories are free */ ++ ASSERT(prAdapter->u4MemFreeDynamicCount == prAdapter->u4MemAllocDynamicCount); ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief disable global interrupt ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ prAdapter->fgIsIntEnable = FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief enable global interrupt ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ BOOLEAN fgIsIntEnableCache; ++ ++ ASSERT(prAdapter); ++ fgIsIntEnableCache = prAdapter->fgIsIntEnable; ++ ++ prAdapter->fgIsIntEnable = TRUE; /* NOTE(Kevin): It must be placed before MCR GINT write. */ ++ ++ /* If need enable INT and also set LPOwn at the same time. */ ++ if (prAdapter->fgIsIntEnableWithLPOwnSet) { ++ prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; /* NOTE(Kevin): It's better to place it ++ * before MCR GINT write. ++ */ ++ /* If INT was enabled, only set LPOwn */ ++ if (fgIsIntEnableCache) { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++ /* If INT was not enabled, enable it and also set LPOwn now */ ++ else { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET | WHLPCR_INT_EN_SET); ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++ } ++ /* If INT was not enabled, enable it now */ ++ else if (!fgIsIntEnableCache) ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++} /* end of nicEnableInterrupt() */ ++ ++#if CFG_SDIO_INTR_ENHANCE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief For SDIO enhance mode, set the max rx len and tx status ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* @return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSDIOInit(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Value = 0; ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <1> Check STATUS Buffer is DW alignment. */ ++ ASSERT(IS_ALIGN_4((ULONG)&prAdapter->prSDIOCtrl->u4WHISR)); ++ ++ /* 4 <2> Setup STATUS count. */ ++ { ++ HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); ++ ++ /* 4 <2.1> Setup the number of maximum RX length to be report */ ++ u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); ++ u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); ++ ++ /* 4 <2.2> Setup RX enhancement mode */ ++#if CFG_SDIO_RX_ENHANCE ++ u4Value |= WHCR_RX_ENHANCE_MODE_EN; ++#else ++ u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; ++#endif /* CFG_SDIO_RX_AGG */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); ++ } ++ ++ return; ++ ++} /* end of nicSDIOInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read interrupt status from hardware ++* ++* @param prAdapter pointer to the Adapter handler ++* @param the interrupts ++* ++* @return N/A ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus) ++{ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ ++ DEBUGFUNC("nicSDIOReadIntStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4IntStatus); ++ ++ /* ++ prSDIOCtrl is from IO buffer. ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) ++ kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ */ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ASSERT(prSDIOCtrl); ++ ++ HAL_PORT_RD(prAdapter, ++ MCR_WHISR, ++ sizeof(ENHANCE_MODE_DATA_STRUCT_T), (PUINT_8) prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ *pu4IntStatus = 0; ++ return; ++ } ++ ++ /* workaround */ ++ if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && ++ (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { ++ prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; ++ } ++ ++ if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && ++ HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && ++ (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { ++ prSDIOCtrl->u4WHISR |= BIT(31); ++ } ++ ++ *pu4IntStatus = prSDIOCtrl->u4WHISR; ++ ++} /* end of nicSDIOReadIntStatus() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function used to read interrupt status and then invoking ++* dispatching procedure for the appropriate functions ++* corresponding to specific interrupt bits ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 u4IntStatus = 0; ++ UINT_32 i; ++ ++ DEBUGFUNC("nicProcessIST"); ++ /* DBGLOG(NIC, LOUD, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(REQ, WARN, "Fail in set nicProcessIST! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ for (i = 0; i < CFG_IST_LOOP_COUNT; i++) { /* CFG_IST_LOOP_COUNT = 1 */ ++ ++#if CFG_SDIO_INTR_ENHANCE ++ nicSDIOReadIntStatus(prAdapter, &u4IntStatus); ++#else ++ HAL_MCR_RD(prAdapter, MCR_WHISR, &u4IntStatus); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++/* DBGLOG(NIC, TRACE, ("u4IntStatus: 0x%x\n", u4IntStatus)); */ ++ ++ if (u4IntStatus & ~(WHIER_DEFAULT | WHIER_FW_OWN_BACK_INT_EN)) { ++ DBGLOG(INTR, WARN, "Un-handled HISR %#x, HISR = %#x (HIER:0x%x)\n", ++ (UINT_32) (u4IntStatus & ~WHIER_DEFAULT), u4IntStatus, ++ (UINT_32) WHIER_DEFAULT); ++ u4IntStatus &= WHIER_DEFAULT; ++ } ++ ++ nicProcessIST_impl(prAdapter, u4IntStatus); ++ ++ if (u4IntStatus == 0) { ++ if (i == 0) ++ u4Status = WLAN_STATUS_NOT_INDICATING; ++ break; ++ } ++ } ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return u4Status; ++} /* end of nicProcessIST() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function used to dispatch the appropriate functions for specific ++* interrupt bits ++* ++* @param prAdapter pointer to the Adapter handler ++* u4IntStatus interrupt status bits ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus) ++{ ++ UINT_32 u4IntCount = 0; ++ P_INT_EVENT_MAP_T prIntEventMap = NULL; ++ ++ ASSERT(prAdapter); ++ ++ prAdapter->u4IntStatus = u4IntStatus; ++ ++ /* Process each of the interrupt status consequently */ ++ prIntEventMap = &arIntEventMapTable[0]; ++ for (u4IntCount = 0; u4IntCount < ucIntEventMapSize; prIntEventMap++, u4IntCount++) { ++ if (prIntEventMap->u4Int & prAdapter->u4IntStatus) { ++ if (prIntEventMap->u4Event == INT_EVENT_RX && prAdapter->fgIsEnterD3ReqIssued == TRUE) { ++ /* ignore */ ++ } else if (apfnEventFuncTable[prIntEventMap->u4Event] != NULL) { ++ apfnEventFuncTable[prIntEventMap->u4Event] (prAdapter); ++ } else { ++ DBGLOG(INTR, WARN, ++ "Empty INTR handler! ISAR bit#: %u, event:%u, func: %p\n", ++ prIntEventMap->u4Int, prIntEventMap->u4Event, ++ apfnEventFuncTable[prIntEventMap->u4Event]); ++ ++ ASSERT(0); /* to trap any NULL interrupt handler */ ++ } ++ prAdapter->u4IntStatus &= ~prIntEventMap->u4Int; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of nicProcessIST_impl() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Verify the CHIP ID ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* ++* @retval TRUE CHIP ID is the same as the setting compiled ++* @retval FALSE CHIP ID is different from the setting compiled ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4CIR = 0; ++ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR); ++ ++ DBGLOG(NIC, TRACE, "Chip ID: 0x%x\n", (UINT_32) (u4CIR & WCIR_CHIP_ID)); ++ DBGLOG(NIC, TRACE, "Revision ID: 0x%x\n", (UINT_32) ((u4CIR & WCIR_REVISION_ID) >> 16)); ++ ++#if 0 ++ if (((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_72) && ((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_82)) ++ return FALSE; ++#endif ++ ++ prAdapter->ucRevID = (UINT_8) (((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the MCR to the appropriate init value, and verify the init ++* value ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* @return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicMCRInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <0> Initial value */ ++} ++ ++VOID nicHifInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ ASSERT(prAdapter); ++#if 0 ++ /* reset event */ ++ nicPutMailbox(prAdapter, 0, 0x52455345); /* RESE */ ++ nicPutMailbox(prAdapter, 1, 0x545F5746); /* T_WF */ ++ nicSetSwIntr(prAdapter, BIT(16)); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the Adapter soft variable ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++ prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; ++ ++ do { ++ if (!nicVerifyChipID(prAdapter)) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* 4 <1> MCR init */ ++ nicMCRInit(prAdapter); ++ ++#if CFG_SDIO_INTR_ENHANCE ++ nicSDIOInit(prAdapter); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); ++ ++ /* 4 <2> init FW HIF */ ++ nicHifInit(prAdapter); ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++#if defined(_HIF_SPI) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Restore the SPI Mode Select to default mode, ++* this is important while driver is unload, and this must be last mcr ++* since the operation will let the hif use 8bit mode access ++* ++* \param[in] prAdapter a pointer to adapter private data structure. ++* \param[in] eGPIO2_Mode GPIO2 operation mode ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_WR(prAdapter, MCR_WCSR, SPICSR_8BIT_MODE_DATA); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process rx interrupt. When the rx ++* Interrupt is asserted, it means there are frames in queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Value = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prGlueInfo->IsrAbnormalCnt++; ++ HAL_MCR_RD(prAdapter, MCR_WASR, &u4Value); ++ DBGLOG(REQ, WARN, "MCR_WASR: 0x%x\n", u4Value); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief . ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessFwOwnBackInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of nicProcessFwOwnBackInterrupt() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief . ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4IntrBits; ++ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); ++ ++ prGlueInfo->IsrSoftWareCnt++; ++ ++ if ((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { ++ nicPrintFirmwareAssertInfo(prAdapter); ++#if CFG_CHIP_RESET_SUPPORT ++ glSendResetRequest(); ++#endif ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ ASSERT((u4IntrBits & (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)) ++ != (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)); ++ ++ if (u4IntrBits & ACK_GATING_ENABLE_D2H_INT) ++ prAdapter->fgIsClockGatingEnabled = TRUE; ++ ++ if (u4IntrBits & ACK_GATING_DISABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++ ++ /* Indicate Service Thread for TX */ ++ if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++#endif ++ ++ DBGLOG(REQ, WARN, "u4IntrBits: 0x%x\n", u4IntrBits); ++} /* end of nicProcessSoftwareInterrupt() */ ++ ++VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data) ++{ ++ if (u4MailboxNum == 0) { ++ /* HAL_MCR_WR */ ++ HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); ++ } else if (u4MailboxNum == 1) { ++ /* HAL_MCR_WR */ ++ HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); ++ } else { ++ ASSERT(0); ++ } ++} ++ ++VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data) ++{ ++ if (u4MailboxNum == 0) { ++ /* HAL_MCR_RD */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); ++ } else if (u4MailboxNum == 1) { ++ /* HAL_MCR_RD */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); ++ } else { ++ ASSERT(0); ++ } ++} ++ ++VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap) ++{ ++ /* NOTE: ++ * SW interrupt in HW bit 16 is mapping to SW bit 0 (shift 16bit in HW transparancy) ++ * SW interrupt valid from b0~b15 ++ */ ++ ASSERT((u4SwIntrBitmap & BITS(0, 15)) == 0); ++/* DBGLOG(NIC, TRACE, ("u4SwIntrBitmap: 0x%08x\n", u4SwIntrBitmap)); */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WSICR, u4SwIntrBitmap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to dequeue from prAdapter->rPendingCmdQueue ++* with specified sequential number ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ucSeqNum Sequential Number ++* ++* @retval - P_CMD_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->ucCmdSeqNum == ucSeqNum) ++ break; ++ ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ ++ prCmdInfo = NULL; ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ return prCmdInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to dequeue from prAdapter->rTxCtrl.rTxMgmtTxingQueue ++* with specified sequential number ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ucSeqNum Sequential Number ++* ++* @retval - P_MSDU_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) ++{ ++ P_QUE_T prTxingQue; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if (prMsduInfo->ucTxSeqNum == ucSeqNum) ++ break; ++ ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ return prMsduInfo; ++} ++ ++P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx) ++{ ++ P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; ++ P_QUE_T prTxingQue = (P_QUE_T) NULL; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if (prAdapter == NULL) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ do { ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if ((prMsduInfo->ucStaRecIndex == ucStaRecIdx) && (prMsduInfo->pfTxDoneHandler != NULL)) { ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfo, prMsduInfoListHead); ++ prMsduInfoListHead = prMsduInfo; ++ } else { ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ } while (FALSE); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ return prMsduInfoListHead; ++} /* nicGetPendingStaMMPDU */ ++ ++VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ P_QUE_T prTxingQue; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; ++ P_MSDU_INFO_T prMsduInfoListTail = (P_MSDU_INFO_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if ((ENUM_NETWORK_TYPE_INDEX_T) (prMsduInfo->ucNetworkType) == eNetworkType) { ++ if (prMsduInfoListHead == NULL) { ++ prMsduInfoListHead = prMsduInfoListTail = prMsduInfo; ++ } else { ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, prMsduInfo); ++ prMsduInfoListTail = prMsduInfo; ++ } ++ } else { ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ /* free */ ++ if (prMsduInfoListHead) ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); ++ ++ return; ++ ++} /* end of nicFreePendingTxMsduInfoByNetwork() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to retrieve a CMD sequence number atomically ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval - UINT_8 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucRetval; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); ++ ++ prAdapter->ucCmdSeqNum++; ++ ucRetval = prAdapter->ucCmdSeqNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); ++ ++ return ucRetval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to retrieve a TX sequence number atomically ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval - UINT_8 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucRetval; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); ++ ++ prAdapter->ucTxSeqNum++; ++ ucRetval = prAdapter->ucTxSeqNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); ++ ++ return ucRetval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to handle ++* media state change event ++* ++* @param ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ ASSERT(prAdapter); ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ switch (eNetworkType) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { /* disconnected */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ DBGLOG(NIC, TRACE, "DisByMC\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++ ++ /* reset buffered link quality information */ ++ prAdapter->fgIsLinkQualityValid = FALSE; ++ prAdapter->fgIsLinkRateValid = FALSE; ++ } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { /* connected */ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ ++ /* fill information for association result */ ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prConnectionStatus->aucBssid, MAC_ADDR_LEN); ++ prAdapter->rWlanInfo.rCurrBssId.u4Privacy ++ = prConnectionStatus->ucEncryptStatus; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse ++ = PARAM_NETWORK_TYPE_AUTOMODE; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod ++ = prConnectionStatus->u2BeaconPeriod; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow = prConnectionStatus->u2ATIMWindow; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig = prConnectionStatus->u4FreqInKHz; ++ prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode ++ = (ENUM_PARAM_OP_MODE_T) prConnectionStatus->ucInfraMode; ++ ++ /* always indicate to OS according to MSDN (re-association/roaming) */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); ++ } else { ++ /* connected -> connected : roaming ? */ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_ROAM_OUT_FIND_BEST, NULL, 0); ++ } ++ } ++ break; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ case NETWORK_TYPE_BOW_INDEX: ++ break; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case NETWORK_TYPE_P2P_INDEX: ++ break; ++#endif ++ default: ++ ASSERT(0); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* nicMediaStateChange */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to convert between ++* frequency and channel number ++* ++* @param u4ChannelNum ++* ++* @retval - Frequency in unit of KHz, 0 for invalid channel number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicChannelNum2Freq(UINT_32 u4ChannelNum) ++{ ++ UINT_32 u4ChannelInMHz; ++ ++ if (u4ChannelNum >= 1 && u4ChannelNum <= 13) ++ u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; ++ else if (u4ChannelNum == 14) ++ u4ChannelInMHz = 2484; ++ else if (u4ChannelNum == 133) ++ u4ChannelInMHz = 3665; /* 802.11y */ ++ else if (u4ChannelNum == 137) ++ u4ChannelInMHz = 3685; /* 802.11y */ ++ else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) ++ u4ChannelInMHz = 5000 + u4ChannelNum * 5; ++ else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) ++ u4ChannelInMHz = 4000 + u4ChannelNum * 5; ++ else ++ u4ChannelInMHz = 0; ++ ++ return 1000 * u4ChannelInMHz; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to convert between ++* frequency and channel number ++* ++* @param u4FreqInKHz ++* ++* @retval - Frequency Number, 0 for invalid freqency ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicFreq2ChannelNum(UINT_32 u4FreqInKHz) ++{ ++ switch (u4FreqInKHz) { ++ case 2412000: ++ return 1; ++ case 2417000: ++ return 2; ++ case 2422000: ++ return 3; ++ case 2427000: ++ return 4; ++ case 2432000: ++ return 5; ++ case 2437000: ++ return 6; ++ case 2442000: ++ return 7; ++ case 2447000: ++ return 8; ++ case 2452000: ++ return 9; ++ case 2457000: ++ return 10; ++ case 2462000: ++ return 11; ++ case 2467000: ++ return 12; ++ case 2472000: ++ return 13; ++ case 2484000: ++ return 14; ++ case 3665000: ++ return 133; /* 802.11y */ ++ case 3685000: ++ return 137; /* 802.11y */ ++ case 4915000: ++ return 183; ++ case 4920000: ++ return 184; ++ case 4925000: ++ return 185; ++ case 4930000: ++ return 186; ++ case 4935000: ++ return 187; ++ case 4940000: ++ return 188; ++ case 4945000: ++ return 189; ++ case 4960000: ++ return 192; ++ case 4980000: ++ return 196; ++ case 5170000: ++ return 34; ++ case 5180000: ++ return 36; ++ case 5190000: ++ return 38; ++ case 5200000: ++ return 40; ++ case 5210000: ++ return 42; ++ case 5220000: ++ return 44; ++ case 5230000: ++ return 46; ++ case 5240000: ++ return 48; ++ case 5250000: ++ return 50; ++ case 5260000: ++ return 52; ++ case 5270000: ++ return 54; ++ case 5280000: ++ return 56; ++ case 5290000: ++ return 58; ++ case 5300000: ++ return 60; ++ case 5320000: ++ return 64; ++ case 5500000: ++ return 100; ++ case 5520000: ++ return 104; ++ case 5540000: ++ return 108; ++ case 5560000: ++ return 112; ++ case 5580000: ++ return 116; ++ case 5600000: ++ return 120; ++ case 5620000: ++ return 124; ++ case 5640000: ++ return 128; ++ case 5660000: ++ return 132; ++ case 5680000: ++ return 136; ++ case 5700000: ++ return 140; ++ case 5745000: ++ return 149; ++ case 5765000: ++ return 153; ++ case 5785000: ++ return 157; ++ case 5805000: ++ return 161; ++ case 5825000: ++ return 165; ++ case 5845000: ++ return 169; ++ case 5865000: ++ return 173; ++ default: ++ return 0; ++ } ++} ++ ++/* firmware command wrapper */ ++/* NETWORK (WIFISYS) */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to activate WIFISYS for specified network ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of network type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdActivateCtrl.ucActive = 1; ++ ++ if (((UINT_8) eNetworkTypeIdx) < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]; ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BSS_ACTIVATE_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to deactivate WIFISYS for specified network ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of network type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ WLAN_STATUS u4Status; ++ CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdActivateCtrl.ucActive = 0; ++ ++ u4Status = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BSS_ACTIVATE_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); ++ ++ /* free all correlated station records */ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); ++ qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); ++ nicFreePendingTxMsduInfoByNetwork(prAdapter, eNetworkTypeIdx); ++ kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); ++ ++ return u4Status; ++} ++ ++/* BSS-INFO */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to sync bss info with firmware ++* when a new BSS has been connected or disconnected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ WLAN_STATUS u4Status; ++ P_BSS_INFO_T prBssInfo; ++ CMD_SET_BSS_INFO rCmdSetBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ kalMemZero(&rCmdSetBssInfo, sizeof(CMD_SET_BSS_INFO)); ++ ++ rCmdSetBssInfo.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdSetBssInfo.ucConnectionState = (UINT_8) prBssInfo->eConnectionState; ++ rCmdSetBssInfo.ucCurrentOPMode = (UINT_8) prBssInfo->eCurrentOPMode; ++ rCmdSetBssInfo.ucSSIDLen = (UINT_8) prBssInfo->ucSSIDLen; ++ kalMemCopy(rCmdSetBssInfo.aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ COPY_MAC_ADDR(rCmdSetBssInfo.aucBSSID, prBssInfo->aucBSSID); ++ rCmdSetBssInfo.ucIsQBSS = (UINT_8) prBssInfo->fgIsQBSS; ++ rCmdSetBssInfo.ucNonHTBasicPhyType = prBssInfo->ucNonHTBasicPhyType; ++ rCmdSetBssInfo.u2OperationalRateSet = prBssInfo->u2OperationalRateSet; ++ rCmdSetBssInfo.u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; ++ rCmdSetBssInfo.ucPhyTypeSet = prBssInfo->ucPhyTypeSet; ++ rCmdSetBssInfo.fgHiddenSsidMode = prBssInfo->eHiddenSsidType; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ COPY_MAC_ADDR(rCmdSetBssInfo.aucOwnMac, prBssInfo->aucOwnMacAddr); ++#endif ++ ++ rlmFillSyncCmdParam(&rCmdSetBssInfo.rBssRlmParam, prBssInfo); ++ ++ rCmdSetBssInfo.fgWapiMode = (UINT_8) FALSE; ++ ++ if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) prConnSettings->eAuthMode; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) prConnSettings->eEncStatus; ++ rCmdSetBssInfo.fgWapiMode = (UINT_8) prConnSettings->fgWapiMode; ++ } ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { ++ /* P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); */ ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++ } ++#endif ++ else { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++ } else { ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_OPEN; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION_DISABLED; ++ } ++ /* Need the probe response to detect the PBC overlap */ ++ rCmdSetBssInfo.fgIsApMode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); ++ } ++#else ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++#endif ++ } ++ ++ if (eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX && ++ prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && prBssInfo->prStaRecOfAP != NULL) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ ++ cnmAisInfraConnectNotify(prAdapter); ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && ++ (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && (prBssInfo->prStaRecOfAP != NULL)) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (eNetworkTypeIdx == NETWORK_TYPE_BOW_INDEX && ++ prBssInfo->eCurrentOPMode == OP_MODE_BOW && prBssInfo->prStaRecOfAP != NULL) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ } ++#endif ++ else ++ rCmdSetBssInfo.ucStaRecIdxOfAP = STA_REC_INDEX_NOT_FOUND; ++ ++ u4Status = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BSS_INFO, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SET_BSS_INFO), (PUINT_8)&rCmdSetBssInfo, NULL, 0); ++ ++ /* if BSS-INFO is going to be disconnected state, free all correlated station records */ ++ if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /* clear client list */ ++ bssClearClientList(prAdapter, prBssInfo); ++ ++ /* free all correlated station records */ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); ++ qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); ++ kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ if (prBssInfo->prIpV4NetAddrList) ++ FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); ++#endif ++ } ++ ++ return u4Status; ++} ++ ++/* BSS-INFO Indication (PM) */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been created. (for AdHoc / P2P-GO) ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_INDICATE_PM_BSS_CREATED rCmdIndicatePmBssCreated; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ rCmdIndicatePmBssCreated.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdIndicatePmBssCreated.ucDtimPeriod = prBssInfo->ucDTIMPeriod; ++ rCmdIndicatePmBssCreated.u2BeaconInterval = prBssInfo->u2BeaconInterval; ++ rCmdIndicatePmBssCreated.u2AtimWindow = prBssInfo->u2ATIMWindow; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_CREATED, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_CREATED), (PUINT_8)&rCmdIndicatePmBssCreated, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been connected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_INDICATE_PM_BSS_CONNECTED rCmdIndicatePmBssConnected; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ rCmdIndicatePmBssConnected.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdIndicatePmBssConnected.ucDtimPeriod = prBssInfo->ucDTIMPeriod; ++ rCmdIndicatePmBssConnected.u2AssocId = prBssInfo->u2AssocId; ++ rCmdIndicatePmBssConnected.u2BeaconInterval = prBssInfo->u2BeaconInterval; ++ rCmdIndicatePmBssConnected.u2AtimWindow = prBssInfo->u2ATIMWindow; ++ ++ rCmdIndicatePmBssConnected.ucBmpDeliveryAC = prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC; ++ rCmdIndicatePmBssConnected.ucBmpTriggerAC = prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC; ++ ++ /* DBGPRINTF("nicPmIndicateBssConnected: ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x", */ ++ /* rCmdIndicatePmBssConnected.ucBmpDeliveryAC, */ ++ /* rCmdIndicatePmBssConnected.ucBmpTriggerAC); */ ++ ++ if ((eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX) ++#if CFG_ENABLE_WIFI_DIRECT ++ || ((eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->fgIsP2PRegistered)) ++#endif ++ ) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = ++ (UINT_8) prBssInfo->prStaRecOfAP->fgIsUapsdSupported; ++ } else { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; /* @FIXME */ ++ } ++ } else { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; ++ } ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_CONNECTED, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_CONNECTED), ++ (PUINT_8)&rCmdIndicatePmBssConnected, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been disconnected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ CMD_INDICATE_PM_BSS_ABORT rCmdIndicatePmBssAbort; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdIndicatePmBssAbort.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_ABORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_ABORT), (PUINT_8)&rCmdIndicatePmBssAbort, NULL, 0); ++} ++ ++WLAN_STATUS ++nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent) ++{ ++ DEBUGFUNC("nicConfigPowerSaveProfile"); ++ DBGLOG(NIC, TRACE, "eNetTypeIndex:%d, ePwrMode:%d, fgEnCmdEvent:%d\n", ++ eNetTypeIndex, ePwrMode, fgEnCmdEvent); ++ ++ ASSERT(prAdapter); ++ ++ if (eNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { ++ ASSERT(0); ++ return WLAN_STATUS_NOT_SUPPORTED; ++ } ++/* prAdapter->rWlanInfo.ePowerSaveMode.ucNetTypeIndex = eNetTypeIndex; */ ++/* prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile = (UINT_8)ePwrMode; */ ++ prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucNetTypeIndex = eNetTypeIndex; ++ prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucPsProfile = (UINT_8) ePwrMode; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_POWER_SAVE_MODE, ++ TRUE, ++ FALSE, ++ (fgEnCmdEvent ? TRUE : FALSE), ++ (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), ++ (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), ++ sizeof(CMD_PS_PROFILE_T), ++ (PUINT_8)&(prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex]), ++ NULL, sizeof(PARAM_POWER_MODE) ++ ); ++ ++} /* end of wlanoidSetAcpiDevicePowerStateMode() */ ++ ++WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent) ++{ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ CMD_ACCESS_REG rCmdAccessReg; ++ WLAN_STATUS rWlanStatus; ++ ++ DEBUGFUNC("nicEnterCtiaMode"); ++ DBGLOG(NIC, TRACE, "nicEnterCtiaMode: %d\n", fgEnterCtia); ++ ++ ASSERT(prAdapter); ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ if (fgEnterCtia) { ++ /* 1. Disable On-Lin Scan */ ++ prAdapter->fgEnOnlineScan = FALSE; ++ ++ /* 3. Disable FIFO FULL no ack */ ++ rCmdAccessReg.u4Address = 0x60140028; ++ rCmdAccessReg.u4Data = 0x904; ++ wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ ++ FALSE, /* TRUE, */ ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); ++ ++ /* 4. Disable Roaming */ ++ rCmdSwCtrl.u4Id = 0x90000204; ++ rCmdSwCtrl.u4Data = 0x0; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ rCmdSwCtrl.u4Id = 0x90000200; ++ rCmdSwCtrl.u4Data = 0x820000; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* Disalbe auto tx power */ ++ rCmdSwCtrl.u4Id = 0xa0100003; ++ rCmdSwCtrl.u4Data = 0x0; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* 2. Keep at CAM mode */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ prAdapter->u4CtiaPowerMode = 0; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ ePowerMode = Param_PowerModeCAM; ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); ++ } ++ ++ /* 5. Disable Beacon Timeout Detection */ ++ prAdapter->fgDisBcnLostDetection = TRUE; ++ } else { ++ /* 1. Enaable On-Lin Scan */ ++ prAdapter->fgEnOnlineScan = TRUE; ++ ++ /* 3. Enable FIFO FULL no ack */ ++ rCmdAccessReg.u4Address = 0x60140028; ++ rCmdAccessReg.u4Data = 0x905; ++ wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ ++ FALSE, /* TRUE, */ ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); ++ ++ /* 4. Enable Roaming */ ++ rCmdSwCtrl.u4Id = 0x90000204; ++ rCmdSwCtrl.u4Data = 0x1; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ rCmdSwCtrl.u4Id = 0x90000200; ++ rCmdSwCtrl.u4Data = 0x820000; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* Enable auto tx power */ ++ /* */ ++ ++ rCmdSwCtrl.u4Id = 0xa0100003; ++ rCmdSwCtrl.u4Data = 0x1; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* 2. Keep at Fast PS */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ prAdapter->u4CtiaPowerMode = 2; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ ePowerMode = Param_PowerModeFast_PSP; ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); ++ } ++ ++ /* 5. Enable Beacon Timeout Detection */ ++ prAdapter->fgDisBcnLostDetection = FALSE; ++ ++ } ++ ++ return rWlanStatus; ++} /* end of nicEnterCtiaMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate firmware domain ++* for beacon generation parameters ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eIeUpdMethod, Update Method ++* eNetTypeIndex Index of Network ++* u2Capability Capability ++* aucIe Pointer to buffer of IEs ++* u2IELen Length of IEs ++* ++* @retval - WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* WLAN_STATUS_PENDING ++* WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, ++ IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen) ++{ ++ P_CMD_BEACON_TEMPLATE_UPDATE prCmdBcnUpdate; ++ UINT_16 u2CmdBufLen = 0; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanUpdateBeaconIETemplate"); ++ ++ DBGLOG(NIC, LOUD, "\nnicUpdateBeaconIETemplate\n"); ++ ++ ASSERT(prAdapter); ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u2IELen > MAX_IE_LENGTH) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (eIeUpdMethod == IE_UPD_METHOD_UPDATE_RANDOM || eIeUpdMethod == IE_UPD_METHOD_UPDATE_ALL) { ++ u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, aucIE) + u2IELen; ++ } else if (eIeUpdMethod == IE_UPD_METHOD_DELETE_ALL) { ++ u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, u2IELen); ++ } else { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* prepare command info */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u2CmdBufLen)); ++ if (!prCmdInfo) { ++ DBGLOG(NIC, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = eNetTypeIndex; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u2CmdBufLen); ++ prCmdInfo->pfCmdDoneHandler = NULL; /* @FIXME */ ++ prCmdInfo->pfCmdTimeoutHandler = NULL; /* @FIXME */ ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_UPDATE_BEACON_CONTENT; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u2CmdBufLen; ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdBcnUpdate = (P_CMD_BEACON_TEMPLATE_UPDATE) (prWifiCmd->aucBuffer); ++ ++ /* fill beacon updating command */ ++ prCmdBcnUpdate->ucUpdateMethod = (UINT_8) eIeUpdMethod; ++ prCmdBcnUpdate->ucNetTypeIndex = (UINT_8) eNetTypeIndex; ++ prCmdBcnUpdate->u2Capability = u2Capability; ++ prCmdBcnUpdate->u2IELen = u2IELen; ++ if (u2IELen > 0) ++ kalMemCopy(prCmdBcnUpdate->aucIE, aucIe, u2IELen); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to initialization PHY related ++* varaibles ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (prConnSettings->eDesiredPhyConfig >= PHY_CONFIG_NUM) { ++ ASSERT(0); ++ return; ++ } ++ ++ prAdapter->rWifiVar.ucAvailablePhyTypeSet = aucPhyCfg2PhyTypeSet[prConnSettings->eDesiredPhyConfig]; ++ ++ if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_BIT_ERP) ++ prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_ERP_INDEX; ++ /* NOTE(Kevin): Because we don't have N only mode, TBD */ ++ else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_UPDATE_WMM_PARMS_T rCmdUpdateWmmParms; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ DBGLOG(QM, EVENT, "sizeof(AC_QUE_PARMS_T): %zu\n", sizeof(AC_QUE_PARMS_T)); ++ DBGLOG(QM, EVENT, "sizeof(CMD_UPDATE_WMM_PARMS): %zu\n", sizeof(CMD_UPDATE_WMM_PARMS_T)); ++ DBGLOG(QM, EVENT, "sizeof(WIFI_CMD_T): %zu\n", sizeof(WIFI_CMD_T)); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ rCmdUpdateWmmParms.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ kalMemCopy(&rCmdUpdateWmmParms.arACQueParms[0], &prBssInfo->arACQueParms[0], (sizeof(AC_QUE_PARMS_T) * AC_NUM)); ++ ++ rCmdUpdateWmmParms.fgIsQBSS = prBssInfo->fgIsQBSS; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_UPDATE_WMM_PARMS, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_UPDATE_WMM_PARMS_T), (PUINT_8)&rCmdUpdateWmmParms, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update TX power gain corresponding to ++* each band/modulation combination ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) ++{ ++ DEBUGFUNC("nicUpdateTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_TX_PWR, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to set auto tx power parameter ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of Auto TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam) ++{ ++ DEBUGFUNC("nicSetAutoTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_AUTOPWR_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_AUTO_POWER_PARAM_T), (PUINT_8) prAutoPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update TX power gain corresponding to ++* each band/modulation combination ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicSetAutoTxPowerControl(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) ++{ ++ DEBUGFUNC("nicUpdateTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_TX_PWR, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update power offset around 5GHz band ++* ++* @param prAdapter Pointer of ADAPTER_T ++* pr5GPwrOffset Pointer of 5GHz power offset parameter ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset) ++{ ++ DEBUGFUNC("nicUpdate5GOffset"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_5G_PWR_OFFSET, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_5G_PWR_OFFSET_T), (PUINT_8) pr5GPwrOffset, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update DPD calibration result ++* ++* @param prAdapter Pointer of ADAPTER_T ++* pr5GPwrOffset Pointer of parameter for DPD calibration result ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult) ++{ ++ DEBUGFUNC("nicUpdateDPD"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PWR_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_PWR_PARAM_T), (PUINT_8) prDpdCalResult, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function starts system service such as timer and ++* memory pools ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* <1> Initialize MGMT Memory pool and STA_REC */ ++ cnmMemInit(prAdapter); ++ cnmStaRecInit(prAdapter); ++ cmdBufInitialize(prAdapter); ++ ++ /* <2> Mailbox Initialization */ ++ mboxInitialize(prAdapter); ++ ++ /* <3> Timer Initialization */ ++ cnmTimerInitialize(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function reset some specific system service, ++* such as STA-REC ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicResetSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* Timer Destruction */ ++ cnmTimerDestroy(prAdapter); ++ ++ /* Mailbox Destruction */ ++ mboxDestroy(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++ ASSERT(prAdapter); ++ ++ /* CNM Module - initialization */ ++ cnmInit(prAdapter); ++ ++ /* RLM Module - initialization */ ++ rlmFsmEventInit(prAdapter); ++ ++ /* SCN Module - initialization */ ++ scnInit(prAdapter); ++ ++ /* AIS Module - intiailization */ ++ aisInitializeConnectionSettings(prAdapter, prRegInfo); ++ aisFsmInit(prAdapter); ++ ++#if CFG_SUPPORT_ROAMING ++ /* Roaming Module - intiailization */ ++ roamingFsmInit(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++#if CFG_SUPPORT_SWCR ++ swCrDebugInit(prAdapter); ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexInit(prAdapter); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++#if CFG_SUPPORT_SWCR ++ swCrDebugUninit(prAdapter); ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if CFG_SUPPORT_ROAMING ++ /* Roaming Module - unintiailization */ ++ roamingFsmUninit(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* AIS Module - unintiailization */ ++ aisFsmUninit(prAdapter); ++ ++ /* SCN Module - unintiailization */ ++ scnUninit(prAdapter); ++ ++ /* RLM Module - uninitialization */ ++ rlmFsmEventUninit(prAdapter); ++ ++ /* CNM Module - uninitialization */ ++ cnmUninit(prAdapter); ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexUninit(prAdapter); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is to inform firmware to enable MCU clock gating ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4WHISR = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ ++ nicSetSwIntr(prAdapter, REQ_GATING_ENABLE_H2D_INT); ++ ++ i = 0; ++ while (i < GATING_CONTROL_POLL_LIMIT) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) ++ return WLAN_STATUS_FAILURE; ++ ++ HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); ++ ++ if (u4WHISR & ACK_GATING_ENABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = TRUE; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ ++ ASSERT(0); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is to inform firmware to disable MCU clock gating ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4WHISR = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ return WLAN_STATUS_SUCCESS; ++ ++ nicSetSwIntr(prAdapter, REQ_GATING_DISABLE_H2D_INT); ++ ++ i = 0; ++ while (i < GATING_CONTROL_POLL_LIMIT) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) ++ return WLAN_STATUS_FAILURE; ++ ++ HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); ++ ++ if (u4WHISR & ACK_GATING_DISABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ ++ ASSERT(0); ++ return WLAN_STATUS_PENDING; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked to buffer scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param rMacAddr BSSID ++* @param prSsid Pointer to SSID ++* @param u4Privacy Privacy settings (0: Open / 1: WEP/WPA/WPA2 enabled) ++* @param rRssi Received Strength (-10 ~ -200 dBm) ++* @param eNetworkType Network Type (a/b/g) ++* @param prConfiguration Network Parameter ++* @param eOpMode Infra/Ad-Hoc ++* @param rSupportedRates Supported basic rates ++* @param u2IELength IE Length ++* @param pucIEBuf Pointer to Information Elements(IEs) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicAddScanResult(IN P_ADAPTER_T prAdapter, ++ IN PARAM_MAC_ADDRESS rMacAddr, ++ IN P_PARAM_SSID_T prSsid, ++ IN UINT_32 u4Privacy, ++ IN PARAM_RSSI rRssi, ++ IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, ++ IN P_PARAM_802_11_CONFIG_T prConfiguration, ++ IN ENUM_PARAM_OP_MODE_T eOpMode, ++ IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf) ++{ ++ BOOLEAN bReplace; ++ UINT_32 i; ++ UINT_32 u4IdxWeakest = 0; ++ PARAM_RSSI rWeakestRssi; ++ UINT_32 u4BufferSize; ++ ++ ASSERT(prAdapter); ++ ++ rWeakestRssi = (PARAM_RSSI) INT_MAX; ++ u4BufferSize = sizeof(prAdapter->rWlanInfo.aucScanIEBuf) / sizeof(prAdapter->rWlanInfo.aucScanIEBuf[0]); ++ ++ bReplace = FALSE; ++ ++ /* decide to replace or add */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ /* find weakest entry && not connected one */ ++ if (UNEQUAL_MAC_ADDR ++ (prAdapter->rWlanInfo.arScanResult[i].arMacAddress, prAdapter->rWlanInfo.rCurrBssId.arMacAddress) ++ && prAdapter->rWlanInfo.arScanResult[i].rRssi < rWeakestRssi) { ++ u4IdxWeakest = i; ++ rWeakestRssi = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ } ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].eOpMode == eOpMode && ++ EQUAL_MAC_ADDR(&(prAdapter->rWlanInfo.arScanResult[i].arMacAddress), rMacAddr) && ++ (EQUAL_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen) ++ || prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen == 0)) { ++ /* replace entry */ ++ bReplace = TRUE; ++ ++ /* free IE buffer then zero */ ++ nicFreeScanResultIE(prAdapter, i); ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ /* IE - allocate buffer and update pointer */ ++ if (u2IELength > 0) { ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ ++ break; ++ } ++ } ++ ++ if (bReplace == FALSE) { ++ if (prAdapter->rWlanInfo.u4ScanResultNum < (CFG_MAX_NUM_BSS_LIST - 1)) { ++ i = prAdapter->rWlanInfo.u4ScanResultNum; ++ ++ /* zero */ ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ /* IE - allocate buffer and update pointer */ ++ if (u2IELength > 0) { ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ ++ prAdapter->rWlanInfo.u4ScanResultNum++; ++ } else if (rWeakestRssi != (PARAM_RSSI) INT_MAX) { ++ /* replace weakest one */ ++ i = u4IdxWeakest; ++ ++ /* free IE buffer then zero */ ++ nicFreeScanResultIE(prAdapter, i); ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ if (u2IELength > 0) { ++ /* IE - allocate buffer and update pointer */ ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked to free IE buffer for dedicated scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param u4Idx Index of Scan Result ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx) ++{ ++ UINT_32 i; ++ PUINT_8 pucPivot, pucMovePivot; ++ UINT_32 u4MoveSize, u4FreeSize, u4ReserveSize; ++ ++ ASSERT(prAdapter); ++ ASSERT(u4Idx < CFG_MAX_NUM_BSS_LIST); ++ ++ if (prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength == 0 ++ || prAdapter->rWlanInfo.apucScanResultIEs[u4Idx] == NULL) { ++ return; ++ } ++ ++ u4FreeSize = ALIGN_4(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength); ++ ++ pucPivot = prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]; ++ pucMovePivot = (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]) + u4FreeSize); ++ ++ u4ReserveSize = ((ULONG) pucPivot) - (ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])); ++ u4MoveSize = prAdapter->rWlanInfo.u4ScanIEBufferUsage - u4ReserveSize - u4FreeSize; ++ ++ /* 1. rest of buffer to move forward */ ++ kalMemCopy(pucPivot, pucMovePivot, u4MoveSize); ++ ++ /* 1.1 modify pointers */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ if (i != u4Idx) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[i] >= pucMovePivot) { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[i]) - u4FreeSize); ++ } ++ } ++ } ++ ++ /* 1.2 reset the freed one */ ++ prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ ++ /* 2. reduce IE buffer usage */ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4FreeSize; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to hack parameters for WLAN TABLE for ++* fixed rate settings ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param eRateSetting ++* @param pu2DesiredNonHTRateSet, ++* @param pu2BSSBasicRateSet, ++* @param pucMcsSet ++* @param pucSupMcs32 ++* @param pu2HtCapInfo ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateRateParams(IN P_ADAPTER_T prAdapter, ++ IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, ++ IN PUINT_8 pucDesiredPhyTypeSet, ++ IN PUINT_16 pu2DesiredNonHTRateSet, ++ IN PUINT_16 pu2BSSBasicRateSet, ++ IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 pu2HtCapInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eRateSetting > FIXED_RATE_NONE && eRateSetting < FIXED_RATE_NUM); ++ ++ switch (prAdapter->rWifiVar.eRateSetting) { ++ case FIXED_RATE_1M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_1M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_1M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_2M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_2M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_2M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_5_5M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_5_5M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_5_5M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_11M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_11M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_11M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_6M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_6M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_6M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_9M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_9M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_9M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_12M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_12M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_12M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_18M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_18M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_18M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_24M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_24M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_24M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_36M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_36M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_36M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_48M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_48M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_48M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_54M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_54M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_54M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_MCS0_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS1_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS2_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS3_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS4_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS5_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS6_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS7_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS0_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS1_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS2_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS3_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS4_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS5_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS6_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS7_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS0_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS1_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS2_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS3_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS4_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS5_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS6_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS7_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS32_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS32_INDEX; ++ *pucSupMcs32 = 1; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS0_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS1_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS2_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS3_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS4_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS5_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS6_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS7_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS32_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS32_INDEX; ++ *pucSupMcs32 = 1; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to write the register ++* ++* @param u4Address Register address ++* u4Value the value to be written ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value) ++{ ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ rCmdAccessReg.u4Address = u4Address; ++ rCmdAccessReg.u4Data = u4Value; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8) &rCmdAccessReg, NULL, 0); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to modify the auto rate parameters ++* ++* @param u4ArSysParam0 see description below ++* u4ArSysParam1 ++* u4ArSysParam2 ++* u4ArSysParam3 ++* ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* ++* @note ++* ArSysParam0[0:3] -> auto rate version (0:disable 1:version1 2:version2) ++* ArSysParam0[4:5]-> auto bw version (0:disable 1:version1 2:version2) ++* ArSysParam0[6:7]-> auto gi version (0:disable 1:version1 2:version2) ++* ArSysParam0[8:15]-> HT rate clear mask ++* ArSysParam0[16:31]-> Legacy rate clear mask ++* ArSysParam1[0:7]-> Auto Rate check weighting window ++* ArSysParam1[8:15]-> Auto Rate v1 Force Rate down ++* ArSysParam1[16:23]-> Auto Rate v1 PerH ++* ArSysParam1[24:31]-> Auto Rate v1 PerL ++* ++* Examples ++* ArSysParam0 = 1, ++* Enable auto rate version 1 ++* ++* ArSysParam0 = 983041, ++* Enable auto rate version 1 ++* Remove CCK 1M, 2M, 5.5M, 11M ++* ++* ArSysParam0 = 786433 ++* Enable auto rate version 1 ++* Remove CCK 5.5M 11M ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4ArSysParam0, ++ IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3) ++{ ++ UINT_8 ucArVer, ucAbwVer, ucAgiVer; ++ UINT_16 u2HtClrMask; ++ UINT_16 u2LegacyClrMask; ++ UINT_8 ucArCheckWindow; ++ UINT_8 ucArPerL; ++ UINT_8 ucArPerH; ++ UINT_8 ucArPerForceRateDownPer; ++ ++ ucArVer = (UINT_8) (u4ArSysParam0 & BITS(0, 3)); ++ ucAbwVer = (UINT_8) ((u4ArSysParam0 & BITS(4, 5)) >> 4); ++ ucAgiVer = (UINT_8) ((u4ArSysParam0 & BITS(6, 7)) >> 6); ++ u2HtClrMask = (UINT_16) ((u4ArSysParam0 & BITS(8, 15)) >> 8); ++ u2LegacyClrMask = (UINT_16) ((u4ArSysParam0 & BITS(16, 31)) >> 16); ++ ++#if 0 ++ ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); ++ ucArPerForceRateDownPer = (UINT_8) ((u4ArSysParam1 & BITS(8, 15) >> 8)); ++ ucArPerH = (UINT_8) ((u4ArSysParam1 & BITS(16, 23)) >> 16); ++ ucArPerL = (UINT_8) ((u4ArSysParam1 & BITS(24, 31)) >> 24); ++#endif ++ ++ ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); ++ ucArPerForceRateDownPer = (UINT_8) (((u4ArSysParam1 >> 8) & BITS(0, 7))); ++ ucArPerH = (UINT_8) (((u4ArSysParam1 >> 16) & BITS(0, 7))); ++ ucArPerL = (UINT_8) (((u4ArSysParam1 >> 24) & BITS(0, 7))); ++ ++ DBGLOG(NIC, INFO, "ArParam %u %u %u %u\n", u4ArSysParam0, u4ArSysParam1, u4ArSysParam2, u4ArSysParam3); ++ DBGLOG(NIC, INFO, "ArVer %u AbwVer %u AgiVer %u\n", ucArVer, ucAbwVer, ucAgiVer); ++ DBGLOG(NIC, INFO, "HtMask %x LegacyMask %x\n", u2HtClrMask, u2LegacyClrMask); ++ DBGLOG(NIC, INFO, ++ "CheckWin %u RateDownPer %u PerH %u PerL %u\n", ucArCheckWindow, ucArPerForceRateDownPer, ucArPerH, ++ ucArPerL); ++ ++#define SWCR_DATA_ADDR(MOD, ADDR) (0x90000000+(MOD<<8)+(ADDR)) ++#define SWCR_DATA_CMD(CATE, WRITE, INDEX, OPT0, OPT1) ((CATE<<24) | (WRITE<<23) | (INDEX<<16) | (OPT0 << 8) | OPT1) ++#define SWCR_DATA0 0x0 ++#define SWCR_DATA1 0x4 ++#define SWCR_DATA2 0x8 ++#define SWCR_DATA3 0xC ++#define SWCR_DATA4 0x10 ++#define SWCR_WRITE 1 ++#define SWCR_READ 0 ++ ++ if (ucArVer > 0) { ++ /* dummy = WiFi.WriteMCR(&h90000104, &h00000001) */ ++ /* dummy = WiFi.WriteMCR(&h90000100, &h00850000) */ ++ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 1); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); ++ } else { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 0); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); ++ } ++ ++ /* ucArVer 0: none 1:PER 2:Rcpi */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArVer); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 7, 0, 0)); ++ ++ /* Candidate rate Ht mask */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2HtClrMask); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1c, 0, 0)); ++ ++ /* Candidate rate legacy mask */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2LegacyClrMask); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1d, 0, 0)); ++ ++#if 0 ++ if (ucArCheckWindow != 0) { ++ /* TX DONE MCS INDEX CHECK STA RATE DOWN TH */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x14, 0, 0)); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0xc, 0, 0)); ++ } ++ ++ if (ucArPerForceRateDownPer != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerForceRateDownPer); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x18, 0, 0)); ++ } ++ if (ucArPerH != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerH); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1, 0, 0)); ++ } ++ if (ucArPerL != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerL); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x2, 0, 0)); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to enable roaming ++* ++* @param u4EnableRoaming ++* ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* ++* @note ++* u4EnableRoaming -> Enable Romaing ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prConnSettings->fgIsEnableRoaming = ((u4EnableRoaming > 0) ? (TRUE) : (FALSE)); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief dump firmware Assert message ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4MailBox0, u4MailBox1; ++ UINT_32 line = 0; ++ UINT_8 aucAssertFile[7]; ++ UINT_32 u4ChipId; ++ ++#if CFG_SDIO_INTR_ENHANCE ++ u4MailBox0 = prAdapter->prSDIOCtrl->u4RcvMailbox0; ++ u4MailBox1 = prAdapter->prSDIOCtrl->u4RcvMailbox1; ++#else ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ nicGetMailbox(prAdapter, 1, &u4MailBox1); ++#endif ++ ++ line = u4MailBox0 & 0x0000FFFF; ++ ++ u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); ++ ++ kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); ++ kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); ++ ++ aucAssertFile[6] = '\0'; ++ ++#if defined(MT6620) ++ u4ChipId = 6620; ++#elif defined(MT6628) ++ u4ChipId = 6582; ++#endif ++ ++ kalPrint("\n[MT%u][wifi][Firmware] Assert at \"%s\" #%u\n\n", u4ChipId, aucAssertFile, line); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* prEventLinkQuality ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ASSERT(prEventLinkQuality); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* check is to prevent RSSI to be updated by incorrect initial RSSI from hardware */ ++ /* buffer statistics for further query */ ++ if (prAdapter->fgIsLinkQualityValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ nicUpdateRSSI(prAdapter, eNetTypeIdx, prEventLinkQuality->cRssi, ++ prEventLinkQuality->cLinkQuality); ++ } ++ ++ if (prAdapter->fgIsLinkRateValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ nicUpdateLinkSpeed(prAdapter, eNetTypeIdx, prEventLinkQuality->u2LinkSpeed); ++ } ++ } ++ break; ++#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY ++ case NETWORK_TYPE_P2P_INDEX: ++ if (prAdapter->fgIsP2pLinkQualityValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ P_EVENT_LINK_QUALITY_EX prEventLQEx = (P_EVENT_LINK_QUALITY_EX) prEventLinkQuality; ++ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, prEventLQEx->cRssiP2P, ++ prEventLQEx->cLinkQualityP2P); ++ } ++ break; ++#endif ++ default: ++ break; ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update RSSI and Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateRSSI(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ prAdapter->fgIsLinkQualityValid = TRUE; ++ prAdapter->rLinkQualityUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rLinkQuality.cRssi = cRssi; ++ prAdapter->rLinkQuality.cLinkQuality = cLinkQuality; ++ ++ /* indicate to glue layer */ ++ kalUpdateRSSI(prAdapter->prGlueInfo, ++ KAL_NETWORK_TYPE_AIS_INDEX, ++ prAdapter->rLinkQuality.cRssi, prAdapter->rLinkQuality.cLinkQuality); ++ } ++ ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case NETWORK_TYPE_P2P_INDEX: ++ prAdapter->fgIsP2pLinkQualityValid = TRUE; ++ prAdapter->rP2pLinkQualityUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rP2pLinkQuality.cRssi = cRssi; ++ prAdapter->rP2pLinkQuality.cLinkQuality = cLinkQuality; ++ ++ kalUpdateRSSI(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_P2P_INDEX, cRssi, cLinkQuality); ++ break; ++#endif ++#endif ++ default: ++ break; ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* prEventLinkQuality ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* buffer statistics for further query */ ++ prAdapter->fgIsLinkRateValid = TRUE; ++ prAdapter->rLinkRateUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rLinkQuality.u2LinkSpeed = u2LinkSpeed; ++ } ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++} ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam) ++{ ++ DEBUGFUNC("nicUpdateRddTestMode.\n"); ++ ++ ASSERT(prAdapter); ++ ++/* aisFsmScanRequest(prAdapter, NULL); */ ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RDD_CH, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_RDD_CH_T), (PUINT_8) prRddChParam, NULL, 0); ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c +new file mode 100644 +index 000000000000..3c9c24f9542b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c +@@ -0,0 +1,1636 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_cmd_event.c#1 ++*/ ++ ++/*! \file nic_cmd_event.c ++ \brief Callback functions for Command packets. ++ ++ Various Event packet handlers which will be setup in the callback function of ++ a command packet. ++*/ ++ ++/* ++** Log: nic_cmd_event.c ++ * ++ * 04 10 2012 yuche.tsai ++ * NULL ++ * Update address for wifi direct connection issue. ++ * ++ * 06 15 2011 cm.chang ++ * [WCXRP00000785] [MT6620 Wi-Fi][Driver][FW] P2P/BOW MAC address is XOR with AIS MAC address ++ * P2P/BOW mac address XOR with local bit instead of OR ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000493] [MT6620 Wi-Fi][Driver] Do not indicate redundant disconnection to host when entering into RF ++ * test mode ++ * only indicate DISCONNECTION to host when entering RF test if necessary (connected -> disconnected cases) ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to ++ * system scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 01 2010 cp.wu ++ * [WCXRP00000223] MT6620 Wi-Fi][Driver][FW] Adopt NVRAM parameters when enter/exit RF test mode ++ * reload NVRAM settings before entering RF test mode and leaving from RF test mode. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 15 2010 yuche.tsai ++ * NULL ++ * Start to test AT GO only when P2P state is not IDLE. ++ * ++ * 09 09 2010 yuche.tsai ++ * NULL ++ * Add AT GO Test mode after MAC address available. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add support for P2P Device Address query from FW. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * reset FSMs before entering RF test mode. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. ++ * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change upon request: indicate as disconnected in driver domain when leaving from RF test mode ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not clear scanning list array after disassociation ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. ++ * 2) finish statistics OIDs ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glude code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sync statistics data structure definition with firmware implementation ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * limit RSSI return value to micxxsoft defined range. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * block until firmware finished RF test enter/leave then indicate completion to upper layer ++ * ++ * 01 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when entering RF test mode and leaving from RF test mode, wait for W_FUNC_RDY bit to be asserted forever until it ++ * is set or card is removed. ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * * 4. correct some HAL implementation ++ * ++ * 01 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * * OID_802_11_RSSI, ++ * * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * * OID_802_11_STATISTICS, ++ * * * * * OID_802_11_DISASSOCIATE, ++ * * * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:47:47 GMT mtk02752 ++** only handle MCR read when accessing FW domain register ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 17:37:28 GMT mtk02752 ++** * refine nicCmdEventQueryMcrRead ++** + add TxStatus/RxStatus for RF test QueryInformation OIDs ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 22:05:45 GMT mtk02752 ++** kalOidComplete() will decrease i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-01 23:02:57 GMT mtk02752 ++** remove unnecessary spin locks ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-01 22:51:18 GMT mtk02752 ++** maintein i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-30 10:55:03 GMT mtk02752 ++** modify for compatibility ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 14:46:32 GMT mtk02752 ++** add another version of command-done handler upon new event structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:33 GMT mtk01461 ++** Add comment ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 19:32:42 GMT mtk01461 ++** Add nicCmdEventSetCommon() for general set OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:35 GMT mtk01461 ++** Command Done Handler ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_ACCESS_REG prCmdAccessReg; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdAccessReg = (P_CMD_ACCESS_REG) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prMcrRdInfo->u4McrOffset = prCmdAccessReg->u4Address; ++ prMcrRdInfo->u4McrData = prCmdAccessReg->u4Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_SW_DBG_CTRL_T prCmdSwCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdSwCtrl = (P_CMD_SW_DBG_CTRL_T) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prSwCtrlInfo->u4Id = prCmdSwCtrl->u4Id; ++ prSwCtrlInfo->u4Data = prCmdSwCtrl->u4Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4InformationBufferLength, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ } ++ ++ DBGLOG(NIC, TRACE, "DisByCmdE\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++#if !defined(LINUX) ++ prAdapter->fgIsRadioOff = TRUE; ++#endif ++ ++} ++ ++VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4Count; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ u4Count = (prCmdInfo->u4SetInfoLen - OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress)) ++ / sizeof(IPV4_NETWORK_ADDRESS); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress) + u4Count * ++ (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP)), ++ WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_TEST_STATUS prTestStatus, prQueryBuffer; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTestStatus = (P_EVENT_TEST_STATUS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prQueryBuffer = (P_EVENT_TEST_STATUS) prCmdInfo->pvInformationBuffer; ++ ++ kalMemCopy(prQueryBuffer, prTestStatus, sizeof(EVENT_TEST_STATUS)); ++ ++ u4QueryInfoLen = sizeof(EVENT_TEST_STATUS); ++ ++ /* Update Query Information Length */ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ PARAM_RSSI rRssi, *prRssi; ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ rRssi = (PARAM_RSSI) prLinkQuality->cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ DBGLOG(NIC, INFO, " %s: rRssi = %d\n", __func__, rRssi); ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ } else { ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prRssi = (PARAM_RSSI *) prCmdInfo->pvInformationBuffer; ++ ++ kalMemCopy(prRssi, &rRssi, sizeof(PARAM_RSSI)); ++ u4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is in response of OID_GEN_LINK_SPEED query request ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the pending command info ++* @param pucEventBuf ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4LinkSpeed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ pu4LinkSpeed = (PUINT_32) (prCmdInfo->pvInformationBuffer); ++ ++ *pu4LinkSpeed = prLinkQuality->u2LinkSpeed * 5000; ++ ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ u4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prEventStatistics->rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prEventStatistics->rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prEventStatistics->rFailedCount; ++ prStatistics->rRetryCount = prEventStatistics->rRetryCount; ++ prStatistics->rMultipleRetryCount = prEventStatistics->rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prEventStatistics->rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prEventStatistics->rRTSFailureCount; ++ prStatistics->rACKFailureCount = prEventStatistics->rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prEventStatistics->rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prEventStatistics->rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prEventStatistics->rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prEventStatistics->rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++#define WAIT_FW_READY_RETRY_CNT 200 ++ ++ UINT_32 u4WHISR = 0, u4Value = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_16 u2RetryCnt = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* [driver-land] */ ++ prAdapter->fgTestMode = TRUE; ++ ++ /* 0. always indicate disconnection */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ /* 1. Remove pending TX */ ++ nicTxRelease(prAdapter); ++ ++ /* 1.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 1.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 2. Reset driver-domain FSMs */ ++ nicUninitMGMT(prAdapter); ++ ++ nicResetSystemService(prAdapter); ++ nicInitMGMT(prAdapter, NULL); ++ ++ /* 3. Disable Interrupt */ ++ HAL_INTR_DISABLE(prAdapter); ++ ++ /* 4. Block til firmware completed entering into RF test mode */ ++ kalMsleep(500); ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || ++ kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); ++ ++ } ++ return; ++ } ++ kalMsleep(10); ++ u2RetryCnt++; ++ } ++ ++ /* 5. Clear Interrupt Status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ /* 6. Reset TX Counter */ ++ nicTxResetResource(prAdapter); ++ ++ /* 7. Re-enable Interrupt */ ++ HAL_INTR_ENABLE(prAdapter); ++ ++ /* 8. completion indication */ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++#if CFG_SUPPORT_NVRAM ++ /* 9. load manufacture data */ ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ ++} ++ ++VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++#define WAIT_FW_READY_RETRY_CNT 200 ++ ++ UINT_32 u4WHISR = 0, u4Value = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_16 u2RetryCnt = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* 1. Disable Interrupt */ ++ HAL_INTR_DISABLE(prAdapter); ++ ++ /* 2. Block til firmware completed leaving from RF test mode */ ++ kalMsleep(500); ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || ++ kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); ++ ++ } ++ return; ++ } ++ kalMsleep(10); ++ u2RetryCnt++; ++ } ++ ++ /* 3. Clear Interrupt Status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ /* 4. Reset TX Counter */ ++ nicTxResetResource(prAdapter); ++ ++ /* 5. Re-enable Interrupt */ ++ HAL_INTR_ENABLE(prAdapter); ++ ++ /* 6. set driver-land variable */ ++ prAdapter->fgTestMode = FALSE; ++ ++ /* 7. completion indication */ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ /* 8. Indicate as disconnected */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++#if CFG_SUPPORT_NVRAM ++ /* 9. load manufacture data */ ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ ++ /* 10. Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++} ++ ++VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_BASIC_CONFIG prEventBasicConfig; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (pucEventBuf); ++ ++ /* copy to adapter */ ++ kalMemCopy(&(prAdapter->rMyMacAddr), &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ kalMemCopy(prCmdInfo->pvInformationBuffer, &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); ++ u4QueryInfoLen = MAC_ADDR_LEN; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ /* 4 <3> Update new MAC address and all 3 networks */ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, prAdapter->rMyMacAddr); ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucDeviceAddress, prAdapter->rMyMacAddr); ++ prAdapter->rWifiVar.aucDeviceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucInterfaceAddress, prAdapter->rMyMacAddr); ++ prAdapter->rWifiVar.aucInterfaceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucOwnMacAddr, prAdapter->rMyMacAddr); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++#endif ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++ if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_IDLE) { ++ wlanEnableP2pFunction(prAdapter); ++ ++ wlanEnableATGO(prAdapter); ++ } ++#endif ++ ++ kalUpdateMACAddress(prAdapter->prGlueInfo, prAdapter->rWifiVar.aucMacAddress); ++ ++} ++ ++VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_MAC_MCAST_ADDR prEventMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventMacMcastAddr = (P_EVENT_MAC_MCAST_ADDR) (pucEventBuf); ++ ++ u4QueryInfoLen = prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN; ++ ++ /* buffer length check */ ++ if (prCmdInfo->u4InformationBufferLength < u4QueryInfoLen) { ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_BUFFER_TOO_SHORT); ++ } else { ++ kalMemCopy(prCmdInfo->pvInformationBuffer, ++ prEventMacMcastAddr->arAddress, ++ prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ } ++} ++ ++VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRdInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_ACCESS_EEPROM prEventAccessEeprom; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventAccessEeprom = (P_EVENT_ACCESS_EEPROM) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ prEepromRdInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prEepromRdInfo->ucEepromIndex = (UINT_8) (prEventAccessEeprom->u2Offset); ++ prEepromRdInfo->u2EepromData = prEventAccessEeprom->u2Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ PARAM_MEDIA_STREAMING_INDICATION rParamMediaStreamIndication; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ rParamMediaStreamIndication.rStatus.eStatusType = ENUM_STATUS_TYPE_MEDIA_STREAM_MODE; ++ rParamMediaStreamIndication.eMediaStreamMode = ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&rParamMediaStreamIndication, sizeof(PARAM_MEDIA_STREAMING_INDICATION)); ++} ++ ++/* Statistics responder */ ++VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rTransmittedFragmentCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rTransmittedFragmentCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rReceivedFragmentCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rReceivedFragmentCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = 0; /* @FIXME? */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = 0; /* @FIXME? */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) 0; /* @FIXME */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = 0; /* @FIXME */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = ++ (UINT_32) (prEventStatistics->rMultipleRetryCount.QuadPart - ++ prEventStatistics->rRetryCount.QuadPart); ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = ++ (UINT_64) (prEventStatistics->rMultipleRetryCount.QuadPart - ++ prEventStatistics->rRetryCount.QuadPart); ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rMultipleRetryCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rMultipleRetryCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command by OID/ioctl has been timeout ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is a generic command timeout handler ++* ++* @param pfnOidHandler Pointer to the OID handler ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command for entering RF test has ++* failed sending due to timeout (highly possibly by firmware crash) ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ /* 1. Remove pending TX frames */ ++ nicTxRelease(prAdapter); ++ ++ /* 1.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 1.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 2. indicate for OID failure */ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command for memory dump has ++* replied a event. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_DUMP_MEM_T prEventDumpMem; ++ static UINT_8 aucPath[256]; ++ static UINT_32 u4CurTimeTick; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventDumpMem = (P_EVENT_DUMP_MEM_T) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T); ++ ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prMemDumpInfo->u4Address = prEventDumpMem->u4Address; ++ prMemDumpInfo->u4Length = prEventDumpMem->u4Length; ++ prMemDumpInfo->u4RemainLength = prEventDumpMem->u4RemainLength; ++ prMemDumpInfo->ucFragNum = prEventDumpMem->ucFragNum; ++ ++#if 0 ++ do { ++ UINT_32 i = 0; ++ ++ DBGLOG(REQ, TRACE, "Rx dump address 0x%X, Length %d, FragNum %d, remain %d\n", ++ prEventDumpMem->u4Address, ++ prEventDumpMem->u4Length, prEventDumpMem->ucFragNum, prEventDumpMem->u4RemainLength); ++#if 0 ++ for (i = 0; i < prEventDumpMem->u4Length; i++) { ++ DBGLOG(REQ, TRACE, "%02X ", prEventDumpMem->aucBuffer[i]); ++ if (i % 32 == 31) ++ DBGLOG(REQ, TRACE, "\n"); ++ } ++#endif ++ } while (FALSE); ++#endif ++ ++ if (prEventDumpMem->ucFragNum == 1) { ++ /* Store memory dump into sdcard, ++ * path /sdcard/dump___.hex ++ */ ++ u4CurTimeTick = kalGetTimeTick(); ++ sprintf(aucPath, "/sdcard/dump_%d_0x%08X_%d.hex", ++ u4CurTimeTick, ++ prEventDumpMem->u4Address, prEventDumpMem->u4Length + prEventDumpMem->u4RemainLength); ++ kalWriteToFile(aucPath, FALSE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); ++ } else { ++ /* Append current memory dump to the hex file */ ++ kalWriteToFile(aucPath, TRUE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); ++ } ++ ++ if (prEventDumpMem->u4RemainLength == 0 || prEventDumpMem->u4Address == 0xFFFFFFFF) { ++ /* The request is finished or firmware response a error */ ++ /* Reply time tick to iwpriv */ ++ *((PUINT_32) prCmdInfo->pvInformationBuffer) = u4CurTimeTick; ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } else { ++ /* The memory dump request is not finished, Send next command */ ++ wlanSendMemDumpCmd(prAdapter, ++ prCmdInfo->pvInformationBuffer, prCmdInfo->u4InformationBufferLength); ++ } ++ } ++ ++ return; ++ ++} ++ ++#if CFG_SUPPORT_BATCH_SCAN ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for SUPPORT_BATCH_SCAN ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_BATCH_RESULT_T prEventBatchResult; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DBGLOG(SCN, TRACE, "nicCmdEventBatchScanResult"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEventBatchResult, sizeof(EVENT_BATCH_RESULT_T)); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for build date code information ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_BUILD_DATE_CODE prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_BUILD_DATE_CODE) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(UINT_8) * 16; ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent->aucDateCode, sizeof(UINT_8) * 16); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query STA link status ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_STA_STATISTICS_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_STA_STATISTICS prStaStatistics; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_STA_STATISTICS_T) pucEventBuf; ++ prStaStatistics = (P_PARAM_GET_STA_STATISTICS) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ prStaStatistics->ucPer = prEvent->ucPer; ++ prStaStatistics->ucRcpi = prEvent->ucRcpi; ++ prStaStatistics->u4PhyMode = prEvent->u4PhyMode; ++ prStaStatistics->u2LinkSpeed = prEvent->u2LinkSpeed; ++ ++ prStaStatistics->u4TxFailCount = prEvent->u4TxFailCount; ++ prStaStatistics->u4TxLifeTimeoutCount = prEvent->u4TxLifeTimeoutCount; ++ ++ if (prEvent->u4TxCount) { ++ UINT_32 u4TxDoneAirTimeMs = USEC_TO_MSEC(prEvent->u4TxDoneAirTime * 32); ++ ++ prStaStatistics->u4TxAverageAirTime = (u4TxDoneAirTimeMs / prEvent->u4TxCount); ++ } else { ++ prStaStatistics->u4TxAverageAirTime = 0; ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query STA link status ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_CHN_LOAD_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_CHN_LOAD prChnLoad; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_CHN_LOAD_T) pucEventBuf; /* 4 The firmware responsed data */ ++ /* 4 Fill the firmware data in and send it back to host */ ++ prChnLoad = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ prChnLoad->rEachChnLoad[0].ucChannel = prEvent->ucChannel; ++ prChnLoad->rEachChnLoad[0].u2ChannelLoad = prEvent->u2ChannelLoad; ++ DBGLOG(P2P, INFO, "CHN[%d]=%d\n", prEvent->ucChannel, prEvent->u2ChannelLoad); ++ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_8 ucIdx = 0; ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_LTE_MODE_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_CHN_LOAD prLteSafeChnInfo; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_LTE_MODE_T) pucEventBuf; /* 4 The firmware responsed data */ ++ ++ prLteSafeChnInfo = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ for (ucIdx = 0; ucIdx < (NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1); ucIdx++) { ++ prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx] = ++ prEvent->rLteSafeChn.au4SafeChannelBitmask[ucIdx]; ++ ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]LTE safe channels [%d]=[%x]\n", ucIdx, ++ (UINT32) prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx]); ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query FW bss info ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_AIS_BSS_INFO_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_AIS_BSS_INFO_T) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent, sizeof(EVENT_AIS_BSS_INFO_T)); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prEvent->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ if (prEvent->eConnectionState != prAisBssInfo->eConnectionState) { ++ DBGLOG(NIC, ERROR, "driver[%d] & FW[%d] status didn't sync !!!\n", ++ prAisBssInfo->eConnectionState, prEvent->eCurrentOPMode); ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, FALSE); ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c +new file mode 100644 +index 000000000000..cf80fd999a24 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c +@@ -0,0 +1,669 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_pwr_mgt.c#1 ++*/ ++ ++/*! \file "nic_pwr_mgt.c" ++ \brief In this file we define the STATE and EVENT for Power Management FSM. ++ ++ The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter ++ ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail ++ description. ++*/ ++ ++/* ++** Log: nic_pwr_mgt.c ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when ++ * returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 29 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * fix for compilation error when applied with FW_DOWNLOAD = 0 ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 04 13 2011 cp.wu ++ * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete ++ * refine for MT5931/MT6620 logic separation. ++ * ++ * 04 13 2011 cp.wu ++ * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete ++ * bugfix: firmware download procedure for ACPI state transition is not complete. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * check success or failure for setting fw-own ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * reset ACPI power state before waking up MT6620 Wi-Fi firmware. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll ++ * 2) correct address list parsing ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sleepy notify is only used for sleepy state, ++ * while wake-up state is automatically set when host needs to access device ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct hibernation problem. ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when acquiring driver-own, wait for up to 8 seconds. ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove redundant firmware image unloading ++ * * 2) use compile-time macros to separate logic related to accquiring own ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * are now handled in glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct typo. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX ++ * response ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-13 21:59:15 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-09-09 17:26:36 GMT mtk01084 ++** remove CMD52 access ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-18 14:50:29 GMT mtk01084 ++** modify lines in nicpmSetDriverOwn() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:55:37 GMT mtk01084 ++** modify nicpmSetDriverOwn() ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:33:00 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:32 GMT mtk01084 ++** Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to process the POWER ON procedure. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt) ++{ ++ UINT_32 u4RegValue = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsFwOwn == TRUE) ++ return; ++ ++ if (nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ /* pending interrupts */ ++ return; ++ } ++ ++ if (fgEnableGlobalInt) { ++ prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; ++ } else { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ /* if set firmware own not successful (possibly pending interrupts), */ ++ /* indicate an own clear event */ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ ++ return; ++ } ++ ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to process the POWER OFF procedure. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4OriRegValue = 0; ++BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter) ++{ ++#define LP_OWN_BACK_TOTAL_DELAY_MS 2000 /* exponential of 2 */ ++#define LP_OWN_BACK_LOOP_DELAY_MS 1 /* exponential of 2 */ ++#define LP_OWN_BACK_CLR_OWN_ITERATION 256 /* exponential of 2 */ ++ ++ BOOLEAN fgStatus = TRUE; ++ UINT_32 i, u4CurrTick; ++ UINT_32 u4RegValue = 0; ++ GL_HIF_INFO_T *HifInfo; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsFwOwn == FALSE) ++ return fgStatus; ++ ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ ++ u4CurrTick = kalGetTimeTick(); ++ STATS_DRIVER_OWN_START_RECORD(); ++ i = 0; ++ ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); ++ prAdapter->fgIsFwOwn = FALSE; ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE ++ || fgIsBusAccessFailed == TRUE ++ || (kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS || fgIsResetting == TRUE) { ++ /* ERRORLOG(("LP cannot be own back (for %ld ms)", kalGetTimeTick() - u4CurrTick)); */ ++ fgStatus = FALSE; ++ if (fgIsResetting != TRUE) { ++ UINT_32 u4FwCnt; ++ static unsigned int u4OwnCnt; ++ /* MCR_D2HRM2R: low 4 bit means interrupt times, ++ * high 4 bit means firmware response times. ++ * ORI_MCR_D2HRM2R: the last successful value. ++ * for example: ++ * MCR_D2HRM2R = 0x44, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware no receive interrupt form hardware. ++ * MCR_D2HRM2R = 0x45, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware no send response. ++ * MCR_D2HRM2R = 0x55, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware send response, but driver no receive. */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); ++ DBGLOG(NIC, WARN, " [1]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", ++ u4RegValue, u4OriRegValue); ++ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); ++ prAdapter->fgIsFwOwn = FALSE; ++ break; ++ } ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); ++ DBGLOG(NIC, WARN, " [2]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", ++ u4RegValue, u4OriRegValue); ++ DBGLOG(NIC, WARN, ++ " Fatal error! Driver own fail!!!!!!!!!!!! %d, fgIsBusAccessFailed: %d\n", ++ u4OwnCnt++, fgIsBusAccessFailed); ++ ++ DBGLOG(NIC, WARN, "CONNSYS FW CPUINFO:\n"); ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(NIC, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ ++ kalSendAeeWarning("[Fatal error! Driver own fail!]", __func__); ++ glDoChipReset(); ++ } ++ break; ++ } ++ if ((i & (LP_OWN_BACK_CLR_OWN_ITERATION - 1)) == 0) { ++ /* Software get LP ownership - per 256 iterations */ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ } ++ ++ /* Delay for LP engine to complete its operation. */ ++ kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); ++ i++; ++ } ++ ++ STATS_DRIVER_OWN_END_RECORD(); ++ STATS_DRIVER_OWN_STOP(); ++ ++ return fgStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set ACPI power mode to D0. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 u4Value = 0, u4WHISR = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_32 i; ++#if CFG_ENABLE_FW_DOWNLOAD ++ UINT_32 u4FwImgLength, u4FwLoadAddr, u4ImgSecSize; ++ PVOID prFwMappingHandle; ++ PVOID pvFwImageMapFile = NULL; ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ UINT_32 j; ++ P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; ++ BOOLEAN fgValidHead; ++ const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); ++#endif ++#endif ++ ++ DEBUGFUNC("nicpmSetAcpiPowerD0"); ++ ASSERT(prAdapter); ++ ++ do { ++ /* 0. Reset variables in ADAPTER_T */ ++ prAdapter->fgIsFwOwn = TRUE; ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ prAdapter->rAcpiState = ACPI_STATE_D0; ++ prAdapter->fgIsEnterD3ReqIssued = FALSE; ++ ++ /* 1. Request Ownership to enter F/W download state */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++#if !CFG_ENABLE_FULL_PM ++ nicpmSetDriverOwn(prAdapter); ++#endif ++ ++ /* 2. Initialize the Adapter */ ++ u4Status = nicInitializeAdapter(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "nicInitializeAdapter failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ prFwMappingHandle = kalFirmwareImageMapping(prAdapter->prGlueInfo, &pvFwImageMapFile, &u4FwImgLength); ++ if (!prFwMappingHandle) { ++ DBGLOG(NIC, ERROR, "Fail to load FW image from file!\n"); ++ pvFwImageMapFile = NULL; ++ } ++ ++ if (pvFwImageMapFile == NULL) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ /* 3.1 disable interrupt, download is done by polling mode only */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 3.2 Initialize Tx Resource to fw download state */ ++ nicTxInitResetResource(prAdapter); ++ ++ /* 3.3 FW download here */ ++ u4FwLoadAddr = kalGetFwLoadAddress(prAdapter->prGlueInfo); ++ ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ /* 3a. parse file header for decision of divided firmware download or not */ ++ prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; ++ ++ if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && ++ prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, ++ u4FwImgLength - u4CRCOffset)) { ++ fgValidHead = TRUE; ++ } else { ++ fgValidHead = FALSE; ++ } ++ ++ /* 3b. engage divided firmware downloading */ ++ if (fgValidHead == TRUE) { ++ for (i = 0; i < prFwHead->u4NumOfEntries; i++) { ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ prFwHead->arSection[i].u4DestAddr, ++ prFwHead->arSection[i].u4Length, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = prFwHead->arSection[i].u4Length - j; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ prFwHead->arSection[i].u4DestAddr + j, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset + j) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ /* escape from loop if any pending error occurs */ ++ if (u4Status == WLAN_STATUS_FAILURE) ++ break; ++ } ++ } else ++#endif ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ u4FwLoadAddr, ++ u4FwImgLength, ++ (PUINT_8) pvFwImageMapFile) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (i = 0; i < u4FwImgLength; i += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImgLength) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = u4FwImgLength - i; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ u4FwLoadAddr + i, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "wlanImageSectionDownload failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ break; ++ } ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ ++ if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++#endif ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ ++ /* 4. send Wi-Fi Start command */ ++#if CFG_OVERRIDE_FW_START_ADDRESS ++ wlanConfigWifiFunc(prAdapter, TRUE, kalGetFwStartAddress(prAdapter->prGlueInfo)); ++#else ++ wlanConfigWifiFunc(prAdapter, FALSE, 0); ++#endif ++#endif /* if CFG_ENABLE_FW_DOWNLOAD */ ++ ++ /* 5. check Wi-Fi FW asserts ready bit */ ++ DBGLOG(NIC, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ DBGLOG(NIC, TRACE, "Ready bit asserted\n"); ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ DBGLOG(NIC, ERROR, "Waiting for Ready bit: Timeout\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* 6.1 reset interrupt status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)(&u4WHISR)); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ ++ /* 6.2 reset TX Resource for normal operation */ ++ nicTxResetResource(prAdapter); ++ ++ /* 6.3 Enable interrupt */ ++ nicEnableInterrupt(prAdapter); ++ ++ /* 6.4 Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++ /* 6.5 indicate disconnection as default status */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ /* MGMT Initialization */ ++ nicInitMGMT(prAdapter, NULL); ++ ++ } while (FALSE); ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is used to set ACPI power mode to D3. ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* 1. MGMT - unitialization */ ++ nicUninitMGMT(prAdapter); ++ ++ /* 2. Disable Interrupt */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 3. emit CMD_NIC_POWER_CTRL command packet */ ++ wlanSendNicPowerCtrlCmd(prAdapter, 1); ++ ++ /* 4. Clear Interrupt Status */ ++ i = 0; ++ while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ i++; ++ }; ++ ++ /* 5. Remove pending TX */ ++ nicTxRelease(prAdapter); ++ ++ /* 5.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 5.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 6. Set Onwership to F/W */ ++ nicpmSetFWOwn(prAdapter, FALSE); ++ ++ /* 7. Set variables */ ++ prAdapter->rAcpiState = ACPI_STATE_D3; ++ ++ return TRUE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +new file mode 100644 +index 000000000000..ba4840414da8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +@@ -0,0 +1,3782 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_rx.c#3 ++*/ ++ ++/*! \file nic_rx.c ++ \brief Functions that provide many rx-related functions ++ ++ This file includes the functions used to process RFB and dispatch RFBs to ++ the appropriate related rx functions for protocols. ++*/ ++ ++/* ++** Log: nic_rx.c ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, ++** one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 14 2012 cp.wu ++ * NULL ++ * remove another assertion by error message dump ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 09 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for beacon timeout and sta aging timeout. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 08 26 2011 cp.wu ++ * [WCXRP00000958] [MT6620 Wi-Fi][Driver] Extend polling timeout from 25ms to 1sec due to RF calibration might took ++ * up to 600ms ++ * extend polling RX response timeout period from 25ms to 1000ms. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 27 2011 cp.wu ++ * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count ++ * correct comment. ++ * ++ * 07 27 2011 cp.wu ++ * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count ++ * take use of QUE_MGT exported function to estimate currently RX buffer usage count. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support for GO. ++ * ++ * 04 01 2011 tsaiyuan.hsu ++ * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues ++ * fix the klocwork issues, 57500, 57501, 57502 and 57503. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 18 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the Anti_piracy check at driver . ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA ++ * module. ++ * Remove Station Record after Aging timeout. ++ * ++ * 02 10 2011 cp.wu ++ * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers ++ * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add MLME deauthentication support for Hot-Spot mode. ++ * ++ * 02 09 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Adjust variable order. ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Remove comments. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec ++ * is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * update beacon for NoA ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 20 2010 wh.su ++ * NULL ++ * add a cmd to reset the p2p key ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * fixed compilier error. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * release RX packet to packet pool when in RF test mode ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ @ associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a common buffer, store the IE of a P2P device in this common buffer. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * When enable WiFi Direct function, check each packet to tell which interface to indicate. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add P2P Device Discovery Function. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * Add support API for RX public action frame. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Update Device Capability Bitmap & Group Capability Bitmap from 16 bits to 8 bits. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill ucStaRecIdx into SW_RFB_T. ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add TX Done Event handle entry ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync with MT6620 driver for scan result replacement policy ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 04 29 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * fixing the PMKID candicate indicate code. ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * basic implementation for EVENT_BT_OVER_WIFI ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * nicRxProcessEvent packet doesn't access spin-lock directly from now on. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * do not need to release the spin lock due to it is done inside nicGetPendingCmdInfo() ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * 2) add KAPI for handling association info ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve Linux supplicant compliance ++ * ++ * 03 31 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl which may cause cmdinfo memory leak ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * rWlanInfo is modified before data is indicated to OS ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * rWlanInfo is modified before data is indicated to OS ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * * the frequency is used for adhoc connection only ++ * * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * * ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX ++ * response ++ * ++ * 03 15 2010 kevin.huang ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Add event for activate STA_RECORD_T ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct fgSetQuery/fgNeedResp check ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c ++ * * 'cause it involves OS dependent data structure handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Updated API interfaces for qmHandleEventRxAddBa() and qmHandleEventRxDelBa() ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * * 4) nicRxWaitResponse() revised ++ * * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * * * OID_802_11_RSSI, ++ * * * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * * * OID_802_11_STATISTICS, ++ * * * * * * OID_802_11_DISASSOCIATE, ++ * * * * * * OID_802_11_POWER_MODE ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 23 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a precheck: if free sw rfb is not enough, do not invoke read transactionu1rwduu`wvpghlqg|fu+rp ++ * ++ * 12 22 2009 cp.wu ++ * [WPD00003809][Bug] Host driver will crash when processing reordered MSDUs ++ * The root cause is pointer accessing by mistake. After dequeued from reordering-buffer, handling logic should access ++ * returned pointer instead of pointer which has been passed in before. ++** \main\maintrunk.MT6620WiFiDriver_Prj\58 2009-12-17 13:40:33 GMT mtk02752 ++** always update prAdapter->rSDIOCtrl when enhanced response is read by RX ++** \main\maintrunk.MT6620WiFiDriver_Prj\57 2009-12-16 18:01:38 GMT mtk02752 ++** if interrupt enhanced response is fetched by RX enhanced response, RX needs to invoke interrupt handlers too ++** \main\maintrunk.MT6620WiFiDriver_Prj\56 2009-12-16 14:16:52 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\55 2009-12-15 20:03:12 GMT mtk02752 ++** ASSERT when RX FreeSwRfb is not enough ++** \main\maintrunk.MT6620WiFiDriver_Prj\54 2009-12-15 17:01:29 GMT mtk02752 ++** when CFG_SDIO_RX_ENHANCE is enabled, after enhanced response is read, rx procedure should process ++** 1) TX_DONE_INT 2) D2H INT as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\53 2009-12-14 20:45:28 GMT mtk02752 ++** when CFG_SDIO_RX_ENHANCE is set, TC counter must be updated each time RX enhance response is read ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\52 2009-12-14 11:34:16 GMT mtk02752 ++** correct a trivial logic issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\51 2009-12-14 10:28:25 GMT mtk02752 ++** add a protection to avoid out-of-boundary access ++** \main\maintrunk.MT6620WiFiDriver_Prj\50 2009-12-10 16:55:18 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\49 2009-12-09 14:06:47 GMT MTK02468 ++** Added parsing event packets with EVENT_ID_RX_ADDBA or EVENT_ID_RX_DELBA ++** \main\maintrunk.MT6620WiFiDriver_Prj\48 2009-12-08 17:37:51 GMT mtk02752 ++** handle EVENT_ID_TEST_STATUS as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\47 2009-12-04 17:59:11 GMT mtk02752 ++** to pass free-build compilation check ++** \main\maintrunk.MT6620WiFiDriver_Prj\46 2009-12-04 12:09:52 GMT mtk02752 ++** correct trivial mistake ++** \main\maintrunk.MT6620WiFiDriver_Prj\45 2009-12-04 11:53:37 GMT mtk02752 ++** all API should be compilable under SD1_SD3_DATAPATH_INTEGRATION == 0 ++** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-03 16:19:48 GMT mtk01461 ++** Fix the Connected Event ++** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-11-30 10:56:18 GMT mtk02752 ++** 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-11-30 10:11:27 GMT mtk02752 ++** implement replacement for bss scan result ++** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-11-27 11:08:05 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-11-26 09:38:59 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-11-26 09:29:40 GMT mtk02752 ++** enable packet forwarding path (for AP mode) ++** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-11-25 21:37:00 GMT mtk02752 ++** sync. with EVENT_SCAN_RESULT_T change, and add an assert for checking event size ++** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-25 20:17:41 GMT mtk02752 ++** fill HIF_TX_HEADER_T.u2SeqNo ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-25 18:18:57 GMT mtk02752 ++** buffer scan result to prGlueInfo->rWlanInfo.arScanResult directly. ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-24 22:42:45 GMT mtk02752 ++** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event (not implemented yet) ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-24 20:51:41 GMT mtk02752 ++** integrate with SD1's data path API ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-24 19:56:17 GMT mtk02752 ++** adopt P_HIF_RX_HEADER_T in new path ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-23 20:31:21 GMT mtk02752 ++** payload to send into pfCmdDoneHandler() will not include WIFI_EVENT_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-23 17:51:34 GMT mtk02752 ++** when event packet corresponding to some pendingOID is received, pendingOID should be cleared ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 14:46:54 GMT mtk02752 ++** implement nicRxProcessEventPacket() ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-17 22:40:54 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-16 21:48:22 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION data path handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-16 15:41:18 GMT mtk01084 ++** modify the length to be read in emu mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-13 17:00:12 GMT mtk02752 ++** add blank function for event packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-13 13:54:24 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 14:41:51 GMT mtk02752 ++** fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-11 14:33:46 GMT mtk02752 ++** add protection when there is no packet avilable ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 12:33:36 GMT mtk02752 ++** add RX1 read path for aggregated/enhanced/normal packet read procedures ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:18 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-04 14:11:08 GMT mtk01084 ++** modify lines in RX aggregation ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:23 GMT mtk01084 ++** modify RX aggregation handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:56:12 GMT mtk01084 ++** modify HAL part ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:34 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:20 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-02 13:59:08 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-21 23:39:05 GMT mtk01461 ++** Fix the paste error of RX STATUS in OOB of HIF Loopback CTRL ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-20 12:25:32 GMT mtk01461 ++** Fix process of Read Done, and add u4MaxEventBufferLen to nicRxWaitResponse() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 21:13:18 GMT mtk01426 ++** Fixed compiler error ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:05:29 GMT mtk01426 ++** Fixed nicRxSDIOAggReceiveRFBs() ASSERT issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:38:43 GMT mtk01461 ++** Fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode and refine nicRxSDIOAggeceiveRFBs() for RX Aggregation ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-22 09:12:17 GMT mtk01461 ++** Fix nicRxProcessHIFLoopbackPacket(), the size of HIF CTRL LENGTH field is 1 byte ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-14 15:51:26 GMT mtk01426 ++** Update RX OOB Setting ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-03 14:58:58 GMT mtk01426 ++** Fixed logical error ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:58:31 GMT mtk01461 ++** Rename the HIF_PKT_TYPE_DATA ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:51:18 GMT mtk01461 ++** Fix u4HeaderOffset in nicRxProcessHIFLoopbackPacket() ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:02:58 GMT mtk01426 ++** Add CFG_SDIO_RX_ENHANCE and CFG_HIF_LOOPBACK support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:20:59 GMT mtk01426 ++** Add nicRxWaitResponse function ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:01 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#ifndef LINUX ++#include ++#else ++#include ++#endif ++ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include ++#include ++#include ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define RX_RESPONSE_TIMEOUT (1000) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_MGMT_FRAME_HANDLING ++static PROCESS_RX_MGT_FUNCTION apfnProcessRxMgtFrame[MAX_NUM_OF_FC_SUBTYPES] = { ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAssoc, /* subtype 0000: Association request */ ++#else ++ NULL, /* subtype 0000: Association request */ ++#endif /* CFG_SUPPORT_AAA */ ++ saaFsmRunEventRxAssoc, /* subtype 0001: Association response */ ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAssoc, /* subtype 0010: Reassociation request */ ++#else ++ NULL, /* subtype 0010: Reassociation request */ ++#endif /* CFG_SUPPORT_AAA */ ++ saaFsmRunEventRxAssoc, /* subtype 0011: Reassociation response */ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++ bssProcessProbeRequest, /* subtype 0100: Probe request */ ++#else ++ NULL, /* subtype 0100: Probe request */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ scanProcessBeaconAndProbeResp, /* subtype 0101: Probe response */ ++ NULL, /* subtype 0110: reserved */ ++ NULL, /* subtype 0111: reserved */ ++ scanProcessBeaconAndProbeResp, /* subtype 1000: Beacon */ ++ NULL, /* subtype 1001: ATIM */ ++ saaFsmRunEventRxDisassoc, /* subtype 1010: Disassociation */ ++ authCheckRxAuthFrameTransSeq, /* subtype 1011: Authentication */ ++ saaFsmRunEventRxDeauth, /* subtype 1100: Deauthentication */ ++ nicRxProcessActionFrame, /* subtype 1101: Action */ ++ NULL, /* subtype 1110: reserved */ ++ NULL /* subtype 1111: reserved */ ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the RFBs ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucMemHandle; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 i; ++ ++ DEBUGFUNC("nicRxInitialize"); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* 4 <0> Clear allocated memory. */ ++ kalMemZero((PVOID) prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize); ++ ++ /* 4 <1> Initialize the RFB lists */ ++ QUEUE_INITIALIZE(&prRxCtrl->rFreeSwRfbList); ++ QUEUE_INITIALIZE(&prRxCtrl->rReceivedRfbList); ++ QUEUE_INITIALIZE(&prRxCtrl->rIndicatedRfbList); ++ ++ pucMemHandle = prRxCtrl->pucRxCached; ++ for (i = CFG_RX_MAX_PKT_NUM; i != 0; i--) { ++ prSwRfb = (P_SW_RFB_T) pucMemHandle; ++ ++ nicRxSetupRFB(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ pucMemHandle += ALIGN_4(sizeof(SW_RFB_T)); ++ } ++ ++ ASSERT(prRxCtrl->rFreeSwRfbList.u4NumElem == CFG_RX_MAX_PKT_NUM); ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT((ULONG) (pucMemHandle - prRxCtrl->pucRxCached) == prRxCtrl->u4RxCachedSize); ++ ++ /* 4 <2> Clear all RX counters */ ++ RX_RESET_ALL_CNTS(prRxCtrl); ++ ++#if CFG_SDIO_RX_AGG ++ prRxCtrl->pucRxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; ++ HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, CFG_SDIO_MAX_RX_AGG_NUM); ++#else ++ HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, 1); ++#endif ++ ++#if CFG_HIF_STATISTICS ++ prRxCtrl->u4TotalRxAccessNum = 0; ++ prRxCtrl->u4TotalRxPacketNum = 0; ++#endif ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4QueuedCnt = 0; ++ prRxCtrl->u4DequeuedCnt = 0; ++#endif ++ ++} /* end of nicRxInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Uninitialize the RFBs ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ nicRxFlush(prAdapter); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (prSwRfb) { ++ if (prSwRfb->pvPacket) ++ kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); ++ prSwRfb->pvPacket = NULL; ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (prSwRfb) { ++ if (prSwRfb->pvPacket) ++ kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); ++ prSwRfb->pvPacket = NULL; ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++} /* end of nicRxUninitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Fill RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb specify the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ UINT_32 u4PktLen = 0; ++ UINT_32 u4MacHeaderLen; ++ UINT_32 u4HeaderOffset; ++ ++ DEBUGFUNC("nicRxFillRFB"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ u4PktLen = prHifRxHdr->u2PacketLen; ++ ++ u4HeaderOffset = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ u4MacHeaderLen = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_LEN) ++ >> HIF_RX_HDR_HEADER_LEN_OFFSET; ++ ++ /* DBGLOG(RX, TRACE, ("u4HeaderOffset = %d, u4MacHeaderLen = %d\n", */ ++ /* u4HeaderOffset, u4MacHeaderLen)); */ ++ ++ prSwRfb->u2HeaderLen = (UINT_16) u4MacHeaderLen; ++ prSwRfb->pvHeader = (PUINT_8) prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ prSwRfb->u2PacketLen = (UINT_16) (u4PktLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); ++ ++ /* DBGLOG(RX, TRACE, ("Dump Rx packet, u2PacketLen = %d\n", prSwRfb->u2PacketLen)); */ ++ /* DBGLOG_MEM8(RX, TRACE, prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ ++#if 0 ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_80211_HEADER_FORMAT) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_802_11_FORMAT; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_802_11_FORMAT\n"); ++ } ++ ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_DO_REORDER) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_DO_REORDERING; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_DO_REORDERING\n"); ++ ++ /* Get Seq. No and TID, Wlan Index info */ ++ if (prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_BAR_FRAME) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_BAR_FRAME; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_BAR_FRAME\n"); ++ } ++ ++ prSwRfb->u2SSN = prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_SEQ_NO_MASK; ++ prSwRfb->ucTid = (UINT_8) ((prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_TID_MASK) ++ >> HIF_RX_HDR_TID_OFFSET); ++ DBGLOG(RX, TRACE, "u2SSN = %d, ucTid = %d\n", prSwRfb->u2SSN, prSwRfb->ucTid); ++ } ++ ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_WDS) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_AMP_WDS; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_AMP_WDS\n"); ++ } ++#endif ++} ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Fill checksum status in RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* @param u4TcpUdpIpCksStatus specify the Checksum status ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus) ++{ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (prAdapter->u4CSUMFlags != CSUM_NOT_SUPPORTED) { ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv4) { /* IPv4 packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_IP) { /* IP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_SUCCESS; ++ } ++ ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv6) { /* IPv6 packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_SUCCESS; ++ ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; ++ } ++ } ++ ++} ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process packet doesn't need to do buffer reordering ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ BOOLEAN fgIsRetained = FALSE; ++ UINT_32 u4CurrentRxBufferCount; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ DEBUGFUNC("nicRxProcessPktWithoutReorder"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ u4CurrentRxBufferCount = prRxCtrl->rFreeSwRfbList.u4NumElem; ++ /* QM USED = $A, AVAILABLE COUNT = $B, INDICATED TO OS = $C ++ * TOTAL = $A + $B + $C ++ * ++ * Case #1 (Retain) ++ * ------------------------------------------------------- ++ * $A + $B < THRESHOLD := $A + $B + $C < THRESHOLD + $C := $TOTAL - THRESHOLD < $C ++ * => $C used too much, retain ++ * ++ * Case #2 (Non-Retain) ++ * ------------------------------------------------------- ++ * $A + $B > THRESHOLD := $A + $B + $C > THRESHOLD + $C := $TOTAL - THRESHOLD > $C ++ * => still available for $C to use ++ * ++ */ ++ fgIsRetained = (((u4CurrentRxBufferCount + ++ qmGetRxReorderQueuedBufferCount(prAdapter) + ++ prTxCtrl->i4PendingFwdFrameCount) < CFG_RX_RETAINED_PKT_THRESHOLD) ? TRUE : FALSE); ++ ++ /* DBGLOG(RX, INFO, ("fgIsRetained = %d\n", fgIsRetained)); */ ++ ++ if (kalProcessRxPacket(prAdapter->prGlueInfo, ++ prSwRfb->pvPacket, ++ prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, fgIsRetained, prSwRfb->aeCSUM) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(RX, ERROR, "kalProcessRxPacket return value != WLAN_STATUS_SUCCESS\n"); ++ ASSERT(0); ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ return; ++ } ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec) { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX && prAdapter->fgIsP2PRegistered == TRUE) ++ GLUE_SET_PKT_FLAG_P2P(prSwRfb->pvPacket); ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ GLUE_SET_PKT_FLAG_PAL(prSwRfb->pvPacket); ++#endif ++ ++ /* record the count to pass to os */ ++ STATS_RX_PASS2OS_INC(prStaRec, prSwRfb); ++ } ++ prRxCtrl->apvIndPacket[prRxCtrl->ucNumIndPacket] = prSwRfb->pvPacket; ++ prRxCtrl->ucNumIndPacket++; ++ ++ if (fgIsRetained) { ++ prRxCtrl->apvRetainedPacket[prRxCtrl->ucNumRetainedPacket] = prSwRfb->pvPacket; ++ prRxCtrl->ucNumRetainedPacket++; ++ /* TODO : error handling of nicRxSetupRFB */ ++ nicRxSetupRFB(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } else { ++ prSwRfb->pvPacket = NULL; ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process forwarding data packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_MSDU_INFO_T prMsduInfo, prRetMsduInfoList; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessForwardPkt"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo && kalProcessRxPacket(prAdapter->prGlueInfo, ++ prSwRfb->pvPacket, ++ prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, ++ prRxCtrl->rFreeSwRfbList.u4NumElem < ++ CFG_RX_RETAINED_PKT_THRESHOLD ? TRUE : FALSE, ++ prSwRfb->aeCSUM) == WLAN_STATUS_SUCCESS) { ++ ++ prMsduInfo->eSrc = TX_PACKET_FORWARDING; ++ /* pack into MSDU_INFO_T */ ++ nicTxFillMsduInfo(prAdapter, prMsduInfo, (P_NATIVE_PACKET) (prSwRfb->pvPacket)); ++ /* Overwrite the ucNetworkType */ ++ prMsduInfo->ucNetworkType = HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr); ++ ++ /* release RX buffer (to rIndicatedRfbList) */ ++ prSwRfb->pvPacket = NULL; ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ /* increase forward frame counter */ ++ GLUE_INC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ ++ /* send into TX queue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prRetMsduInfoList = qmEnqueueTxPackets(prAdapter, prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prRetMsduInfoList != NULL) { /* TX queue refuses queuing the packet */ ++ nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfoList); ++ nicTxReturnMsduInfo(prAdapter, prRetMsduInfoList); ++ } ++ /* indicate service thread for sending */ ++ if (prTxCtrl->i4PendingFwdFrameCount > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } else /* no TX resource */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process broadcast data packet for both host and forwarding ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_SW_RFB_T prSwRfbDuplicated; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessGOBroadcastPkt"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ ASSERT(CFG_NUM_OF_QM_RX_PKT_NUM >= 16); ++ ++ if (prRxCtrl->rFreeSwRfbList.u4NumElem ++ >= (CFG_RX_MAX_PKT_NUM - (CFG_NUM_OF_QM_RX_PKT_NUM - 16 /* Reserved for others */))) { ++ ++ /* 1. Duplicate SW_RFB_T */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfbDuplicated, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfbDuplicated) { ++ kalMemCopy(prSwRfbDuplicated->pucRecvBuff, ++ prSwRfb->pucRecvBuff, ALIGN_4(prHifRxHdr->u2PacketLen + HIF_RX_HW_APPENDED_LEN)); ++ ++ prSwRfbDuplicated->ucPacketType = HIF_RX_PKT_TYPE_DATA; ++ prSwRfbDuplicated->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ nicRxFillRFB(prAdapter, prSwRfbDuplicated); ++ ++ /* 2. Modify eDst */ ++ prSwRfbDuplicated->eDst = RX_PKT_DESTINATION_FORWARD; ++ ++ /* 4. Forward */ ++ nicRxProcessForwardPkt(prAdapter, prSwRfbDuplicated); ++ } ++ } else { ++ DBGLOG(RX, WARN, "Stop to forward BMC packet due to less free Sw Rfb %u\n", ++ prRxCtrl->rFreeSwRfbList.u4NumElem); ++ } ++ ++ /* 3. Indicate to host */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_HOST; ++ nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF data packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prRetSwRfb, prNextSwRfb; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fIsDummy = FALSE; ++ ++ DEBUGFUNC("nicRxProcessDataPacket"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ fIsDummy = (prHifRxHdr->u2PacketLen >= 12) ? FALSE : TRUE; ++ ++ nicRxFillRFB(prAdapter, prSwRfb); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ { ++ UINT_32 u4TcpUdpIpCksStatus; ++ ++ u4TcpUdpIpCksStatus = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); ++ nicRxFillChksumStatus(prAdapter, prSwRfb, u4TcpUdpIpCksStatus); ++ ++ } ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prHifRxHdr->ucStaRecIdx); ++ if (secCheckClassError(prAdapter, prSwRfb, prStaRec) == TRUE && prAdapter->fgTestMode == FALSE) { ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4QueuedCnt++; ++#endif ++ prRetSwRfb = qmHandleRxPackets(prAdapter, prSwRfb); ++ if (prRetSwRfb != NULL) { ++ do { ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prRetSwRfb); ++ if (fIsDummy == TRUE) { ++ nicRxReturnRFB(prAdapter, prRetSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ DBGLOG(RX, WARN, "Drop Dummy Packets"); ++ ++ } else { ++ switch (prRetSwRfb->eDst) { ++ case RX_PKT_DESTINATION_HOST: ++#if ARP_MONITER_ENABLE ++ if (IS_STA_IN_AIS(prStaRec)) ++ qmHandleRxArpPackets(prAdapter, prRetSwRfb); ++#endif ++ nicRxProcessPktWithoutReorder(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_FORWARD: ++ nicRxProcessForwardPkt(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_HOST_WITH_FORWARD: ++ nicRxProcessGOBroadcastPkt(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_NULL: ++ nicRxReturnRFB(prAdapter, prRetSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ break; ++ ++ default: ++ break; ++ } ++ } ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4DequeuedCnt++; ++#endif ++ prRetSwRfb = prNextSwRfb; ++ } while (prRetSwRfb); ++ } ++ } else { ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF event packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_8 nicRxProcessGSCNEvent(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_WIFI_EVENT_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ struct sk_buff *skb; ++ struct wiphy *wiphy; ++ ++ UINT_32 real_num = 0; ++ ++ P_EVENT_GSCAN_SCAN_AVAILABLE_T prEventGscnAvailable; ++ P_EVENT_GSCAN_RESULT_T prEventBuffer; ++ P_WIFI_GSCAN_RESULT_T prEventGscnResult; ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_32 scan_id; ++ UINT_8 scan_flag; ++ P_EVENT_GSCAN_CAPABILITY_T prEventGscnCapbiblity; ++ P_EVENT_GSCAN_SCAN_COMPLETE_T prEventGscnScnDone; ++ P_WIFI_GSCAN_RESULT_T prEventGscnFullResult; ++ P_PARAM_WIFI_GSCAN_RESULT prParamGscnFullResult; ++ P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnSignificantChange; ++ P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnGeofenceFound; ++ ++ P_PARAM_WIFI_GSCAN_RESULT prResults; ++ ++ DEBUGFUNC("nicRxProcessGSCNEvent"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ DBGLOG(SCN, INFO, "nicRxProcessGSCNEvent\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* Push the data to the skb */ ++ wiphy = priv_to_wiphy(prGlueInfo); ++ ++ /* prGlueInfo-> */ ++ ++ /* Event Handling */ ++ switch (prEvent->ucEID) { ++ case EVENT_ID_GSCAN_SCAN_AVAILABLE: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_AVAILABLE\n"); ++ ++ prEventGscnAvailable = (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnAvailable, (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SCAN_AVAILABLE_T)); ++ ++ mtk_cfg80211_vendor_event_scan_results_available(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnAvailable->u2Num); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_RESULT: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_RESULT 2\n"); ++ ++ prEventBuffer = (P_EVENT_GSCAN_RESULT_T) (prEvent->aucBuffer); ++ prEventGscnResult = prEventBuffer->rResult; ++/* ++ the following event struct should moved to kal and use the kal api to avoid future porting effort ++ ++*/ ++ scan_id = prEventBuffer->u2ScanId; ++ scan_flag = prEventBuffer->u2ScanFlags; ++ real_num = prEventBuffer->u2NumOfResults; ++ ++ DBGLOG(SCN, INFO, "scan_id=%d, scan_flag =%d, real_num=%d\r\n", scan_id, scan_flag, real_num); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num); ++ if (!skb) { ++ DBGLOG(RX, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ attr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); ++ /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_SCAN_ID, scan_id);*/ ++ { ++ unsigned int __tmp = scan_id; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_ID, sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, 1);*/ ++ { ++ unsigned char __tmp = 1; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, sizeof(u8), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, real_num);*/ ++ { ++ unsigned int __tmp = real_num; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ prResults = (P_PARAM_WIFI_GSCAN_RESULT) prEventGscnResult; ++ if (prResults) ++ DBGLOG(SCN, INFO, "ssid=%s, rssi=%d, channel=%d \r\n", ++ prResults->ssid, prResults->rssi, prResults->channel); ++ /*NLA_PUT(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num, ++ prResults);*/ ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, ++ sizeof(PARAM_WIFI_GSCAN_RESULT)*real_num, prResults) < 0)) ++ goto nla_put_failure; ++ ++ DBGLOG(SCN, INFO, "NLA_PUT scan results over\t"); ++ ++ if (attr) ++ nla_nest_end(skb, attr); ++ /* report_events=1 */ ++ /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, 1);*/ ++ { ++ unsigned char __tmp = 1; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ skb = NULL; ++ DBGLOG(SCN, INFO, " i4Status %d\n", i4Status); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_CAPABILITY: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_CAPABILITY\n"); ++ ++ prEventGscnCapbiblity = (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnCapbiblity, (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_CAPABILITY_T)); ++ ++ mtk_cfg80211_vendor_get_gscan_capabilities(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnCapbiblity, sizeof(EVENT_GSCAN_CAPABILITY_T)); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_SCAN_COMPLETE: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_COMPLETE\n"); ++ prEventGscnScnDone = (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnScnDone, (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SCAN_COMPLETE_T)); ++ ++ mtk_cfg80211_vendor_event_complete_scan(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnScnDone->ucScanState); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_FULL_RESULT: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_FULL_RESULT\n"); ++ ++ prEventGscnFullResult = kalMemAlloc(sizeof(WIFI_GSCAN_RESULT_T), VIR_MEM_TYPE); ++ if (prEventGscnFullResult) ++ memcpy(prEventGscnFullResult, (P_WIFI_GSCAN_RESULT_T) (prEvent->aucBuffer), ++ sizeof(WIFI_GSCAN_RESULT_T)); ++ ++ prParamGscnFullResult = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_RESULT), VIR_MEM_TYPE); ++ if (prEventGscnFullResult && prParamGscnFullResult) { ++ kalMemZero(prParamGscnFullResult, sizeof(PARAM_WIFI_GSCAN_RESULT)); ++ memcpy(prParamGscnFullResult, prEventGscnFullResult, sizeof(WIFI_GSCAN_RESULT_T)); ++ ++ mtk_cfg80211_vendor_event_full_scan_results(wiphy, ++ prGlueInfo->prDevHandler->ieee80211_ptr, ++ prParamGscnFullResult, ++ sizeof(PARAM_WIFI_GSCAN_RESULT)); ++ } ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: ++ { ++ prEventGscnSignificantChange = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnSignificantChange, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_GEOFENCE_FOUND: ++ { ++ prEventGscnGeofenceFound = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnGeofenceFound, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); ++ } ++ break; ++ ++ default: ++ DBGLOG(SCN, INFO, "not GSCN event ????\n"); ++ break; ++ } ++ ++ DBGLOG(SCN, INFO, "Done with GSCN event handling\n"); ++ return real_num; /* cfg80211_vendor_cmd_reply(skb); */ ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ DBGLOG(SCN, INFO, "nla_put_failure\n"); ++ return 0; /* cfg80211_vendor_cmd_reply(skb); */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF event packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_WIFI_EVENT_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("nicRxProcessEventPacket"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ DBGLOG(RX, EVENT, "prEvent->ucEID = 0x%02x\n", prEvent->ucEID); ++ /* Event Handling */ ++ switch (prEvent->ucEID) { ++ case EVENT_ID_CMD_RESULT: ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ P_EVENT_CMD_RESULT prCmdResult; ++ ++ prCmdResult = (P_EVENT_CMD_RESULT) ((PUINT_8) prEvent + EVENT_HDR_SIZE); ++ ++ /* CMD_RESULT should be only in response to Set commands */ ++ ASSERT(prCmdInfo->fgSetQuery == FALSE || prCmdInfo->fgNeedResp == TRUE); ++ ++ if (prCmdResult->ucStatus == 0) { /* success */ ++ if (prCmdInfo->pfCmdDoneHandler) { ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ } else if (prCmdInfo->fgIsOid == TRUE) { ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_SUCCESS); ++ } ++ } else if (prCmdResult->ucStatus == 1) { /* reject */ ++ if (prCmdInfo->fgIsOid == TRUE) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_FAILURE); ++ } else if (prCmdResult->ucStatus == 2) { /* unknown CMD */ ++ if (prCmdInfo->fgIsOid == TRUE) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_NOT_SUPPORTED); ++ } ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++#if 0 ++ case EVENT_ID_CONNECTION_STATUS: ++ /* OBSELETE */ ++ { ++ P_EVENT_CONNECTION_STATUS prConnectionStatus; ++ ++ prConnectionStatus = (P_EVENT_CONNECTION_STATUS) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_CONNECTION_STATUS = %d\n", prConnectionStatus->ucMediaStatus); ++ if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /* disconnected */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++ } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { ++ /* connected */ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ ++ /* fill information for association result */ ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); ++ ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prConnectionStatus->aucBssid, MAC_ADDR_LEN); ++ ++ /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.u4Privacy = prConnectionStatus->ucEncryptStatus; ++ prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ ++ /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse = PARAM_NETWORK_TYPE_AUTOMODE; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod ++ = prConnectionStatus->u2BeaconPeriod; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow ++ = prConnectionStatus->u2ATIMWindow; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig ++ = prConnectionStatus->u4FreqInKHz; ++ prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; ++ ++ switch (prConnectionStatus->ucInfraMode) { ++ case 0: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_IBSS; ++ break; ++ case 1: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_INFRA; ++ break; ++ case 2: ++ default: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_AUTO_SWITCH; ++ break; ++ } ++ /* always indicate to OS according to MSDN (re-association/roaming) */ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); ++ } ++ } ++ break; ++ ++ case EVENT_ID_SCAN_RESULT: ++ /* OBSELETE */ ++ break; ++#endif ++ ++ case EVENT_ID_RX_ADDBA: ++ /* The FW indicates that an RX BA agreement will be established */ ++ qmHandleEventRxAddBa(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_RX_DELBA: ++ /* The FW indicates that an RX BA agreement has been deleted */ ++ qmHandleEventRxDelBa(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_LINK_QUALITY: ++#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY ++ if (prEvent->u2PacketLen == EVENT_HDR_SIZE + sizeof(EVENT_LINK_QUALITY_EX)) { ++ P_EVENT_LINK_QUALITY_EX prLqEx = (P_EVENT_LINK_QUALITY_EX) (prEvent->aucBuffer); ++ ++ if (prLqEx->ucIsLQ0Rdy) ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); ++ if (prLqEx->ucIsLQ1Rdy) ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_P2P_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); ++ } else { ++ /* For old FW, P2P may invoke link quality query, and make driver flag becone TRUE. */ ++ DBGLOG(P2P, WARN, "Old FW version, not support P2P RSSI query.\n"); ++ ++ /* Must not use NETWORK_TYPE_P2P_INDEX, cause the structure is mismatch. */ ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, ++ (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); ++ } ++#else ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); ++#endif ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++#ifndef LINUX ++ if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_GREATER && ++ prAdapter->rWlanInfo.rRssiTriggerValue >= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), ++ sizeof(PARAM_RSSI)); ++ } else if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_LESS ++ && prAdapter->rWlanInfo.rRssiTriggerValue <= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), ++ sizeof(PARAM_RSSI)); ++ } ++#endif ++ ++ break; ++ ++ case EVENT_ID_MIC_ERR_INFO: ++ { ++ P_EVENT_MIC_ERR_INFO prMicError; ++ /* P_PARAM_AUTH_EVENT_T prAuthEvent; */ ++ P_STA_RECORD_T prStaRec; ++ ++ DBGLOG(RSN, EVENT, "EVENT_ID_MIC_ERR_INFO\n"); ++ ++ prMicError = (P_EVENT_MIC_ERR_INFO) (prEvent->aucBuffer); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (UINT_8) NETWORK_TYPE_AIS_INDEX, ++ prAdapter->rWlanInfo.rCurrBssId.arMacAddress); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) ++ rsnTkipHandleMICFailure(prAdapter, prStaRec, (BOOLEAN) prMicError->u4Flags); ++ else ++ DBGLOG(RSN, WARN, "No STA rec!!\n"); ++#if 0 ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: Authentication Event */ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; ++ ++ /* Authentication request */ ++ prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); ++ kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, ++ (PVOID) prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ /* whsu:Todo? */PARAM_MAC_ADDR_LEN); ++ ++ if (prMicError->u4Flags != 0) ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; ++ else ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); ++#endif ++ } ++ break; ++ ++ case EVENT_ID_ASSOC_INFO: ++ { ++ P_EVENT_ASSOC_INFO prAssocInfo; ++ ++ prAssocInfo = (P_EVENT_ASSOC_INFO) (prEvent->aucBuffer); ++ ++ kalHandleAssocInfo(prAdapter->prGlueInfo, prAssocInfo); ++ } ++ break; ++ ++ case EVENT_ID_802_11_PMKID: ++ { ++ P_PARAM_AUTH_EVENT_T prAuthEvent; ++ PUINT_8 cp; ++ UINT_32 u4LenOfUsedBuffer; ++ ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; ++ ++ u4LenOfUsedBuffer = (UINT_32) (prEvent->u2PacketLen - 8); ++ ++ prAuthEvent->arRequest[0].u4Length = u4LenOfUsedBuffer; ++ ++ cp = (PUINT_8) &prAuthEvent->arRequest[0]; ++ ++ /* Status type: PMKID Candidatelist Event */ ++ kalMemCopy(cp, (P_EVENT_PMKID_CANDIDATE_LIST_T) (prEvent->aucBuffer), prEvent->u2PacketLen - 8); ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + u4LenOfUsedBuffer); ++ } ++ break; ++ ++#if 0 ++ case EVENT_ID_ACTIVATE_STA_REC_T: ++ { ++ P_EVENT_ACTIVATE_STA_REC_T prActivateStaRec; ++ ++ prActivateStaRec = (P_EVENT_ACTIVATE_STA_REC_T) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_ACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", ++ prActivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); ++ ++ qmActivateStaRec(prAdapter, ++ (UINT_32) prActivateStaRec->ucStaRecIdx, ++ ((prActivateStaRec->fgIsQoS) ? TRUE : FALSE), ++ prActivateStaRec->ucNetworkTypeIndex, ++ ((prActivateStaRec->fgIsAP) ? TRUE : FALSE), prActivateStaRec->aucMacAddr); ++ ++ } ++ break; ++ ++ case EVENT_ID_DEACTIVATE_STA_REC_T: ++ { ++ P_EVENT_DEACTIVATE_STA_REC_T prDeactivateStaRec; ++ ++ prDeactivateStaRec = (P_EVENT_DEACTIVATE_STA_REC_T) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_DEACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", ++ prDeactivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); ++ ++ qmDeactivateStaRec(prAdapter, prDeactivateStaRec->ucStaRecIdx); ++ } ++ break; ++#endif ++ ++ case EVENT_ID_SCAN_DONE: ++ scnEventScanDone(prAdapter, (P_EVENT_SCAN_DONE) (prEvent->aucBuffer)); ++ break; ++ ++ case EVENT_ID_TX_DONE_STATUS: ++ STATS_TX_PKT_DONE_INFO_DISPLAY(prAdapter, prEvent->aucBuffer); ++ break; ++ ++ case EVENT_ID_TX_DONE: ++ { ++ P_EVENT_TX_DONE_T prTxDone; ++ ++ prTxDone = (P_EVENT_TX_DONE_T) (prEvent->aucBuffer); ++ if (prTxDone->ucStatus) ++ DBGLOG(RX, INFO, "EVENT_ID_TX_DONE PacketSeq:%u ucStatus: %u SN: %u\n", ++ prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->u2SequenceNumber); ++ ++ /* call related TX Done Handler */ ++ prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucPacketSeq); ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ DBGLOG(RX, TRACE, "EVENT_ID_TX_DONE u4TimeStamp = %x u2AirDelay = %x\n", ++ prTxDone->au4Reserved1, prTxDone->au4Reserved2); ++ ++ wnmReportTimingMeas(prAdapter, prMsduInfo->ucStaRecIndex, ++ prTxDone->au4Reserved1, prTxDone->au4Reserved1 + prTxDone->au4Reserved2); ++#endif ++ ++ if (prMsduInfo) { ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, ++ (ENUM_TX_RESULT_CODE_T) (prTxDone->ucStatus)); ++ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } ++ } ++ break; ++ case EVENT_ID_SLEEPY_NOTIFY: ++ { ++ P_EVENT_SLEEPY_NOTIFY prEventSleepyNotify; ++ ++ prEventSleepyNotify = (P_EVENT_SLEEPY_NOTIFY) (prEvent->aucBuffer); ++ ++ /* DBGLOG(RX, INFO, ("ucSleepyState = %d\n", prEventSleepyNotify->ucSleepyState)); */ ++ ++ prAdapter->fgWiFiInSleepyState = (BOOLEAN) (prEventSleepyNotify->ucSleepyState); ++ } ++ break; ++ case EVENT_ID_BT_OVER_WIFI: ++#if CFG_ENABLE_BT_OVER_WIFI ++ { ++ UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; ++ P_EVENT_BT_OVER_WIFI prEventBtOverWifi; ++ P_AMPC_EVENT prBowEvent; ++ P_BOW_LINK_CONNECTED prBowLinkConnected; ++ P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; ++ ++ prEventBtOverWifi = (P_EVENT_BT_OVER_WIFI) (prEvent->aucBuffer); ++ ++ /* construct event header */ ++ prBowEvent = (P_AMPC_EVENT) aucTmp; ++ ++ if (prEventBtOverWifi->ucLinkStatus == 0) { ++ /* Connection */ ++ prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; ++ prBowEvent->rHeader.ucSeqNumber = 0; ++ prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); ++ ++ /* fill event body */ ++ prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prBowEvent->aucPayload); ++ prBowLinkConnected->rChannel.ucChannelNum = prEventBtOverWifi->ucSelectedChannel; ++ kalMemZero(prBowLinkConnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); ++ } else { ++ /* Disconnection */ ++ prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; ++ prBowEvent->rHeader.ucSeqNumber = 0; ++ prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); ++ ++ /* fill event body */ ++ prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prBowEvent->aucPayload); ++ prBowLinkDisconnected->ucReason = 0; /* @FIXME */ ++ kalMemZero(prBowLinkDisconnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); ++ } ++ } ++ break; ++#endif ++ case EVENT_ID_STATISTICS: ++ /* buffer statistics for further query */ ++ prAdapter->fgIsStatValid = TRUE; ++ prAdapter->rStatUpdateTime = kalGetTimeTick(); ++ kalMemCopy(&prAdapter->rStatStruct, prEvent->aucBuffer, sizeof(EVENT_STATISTICS)); ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++ case EVENT_ID_CH_PRIVILEGE: ++ cnmChMngrHandleChEvent(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_BSS_ABSENCE_PRESENCE: ++ qmHandleEventBssAbsencePresence(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_STA_CHANGE_PS_MODE: ++ qmHandleEventStaChangePsMode(prAdapter, prEvent); ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++ case EVENT_ID_STA_UPDATE_FREE_QUOTA: ++ qmHandleEventStaUpdateFreeQuota(prAdapter, prEvent); ++ break; ++#endif ++ case EVENT_ID_BSS_BEACON_TIMEOUT: ++ if (prAdapter->fgDisBcnLostDetection == FALSE) { ++ P_EVENT_BSS_BEACON_TIMEOUT_T prEventBssBeaconTimeout; ++ ++ prEventBssBeaconTimeout = (P_EVENT_BSS_BEACON_TIMEOUT_T) (prEvent->aucBuffer); ++ ++ DBGLOG(RX, INFO, "Beacon Timeout Reason = %u\n", prEventBssBeaconTimeout->ucReason); ++ ++ if (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ /* Request stats report before beacon timeout */ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prBssInfo) { ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ++ prBssInfo->aucBSSID); ++ if (prStaRec) ++ STATS_ENV_REPORT_DETECT(prAdapter, prStaRec->ucIndex); ++ } ++ aisBssBeaconTimeout(prAdapter); ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && ++ (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) ++ ++ p2pFsmRunEventBeaconTimeout(prAdapter); ++#endif ++ else { ++ DBGLOG(RX, ERROR, "EVENT_ID_BSS_BEACON_TIMEOUT: (ucNetTypeIdx = %d)\n", ++ prEventBssBeaconTimeout->ucNetTypeIndex); ++ } ++ } ++ ++ break; ++ case EVENT_ID_UPDATE_NOA_PARAMS: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam; ++ ++ prEventUpdateNoaParam = (P_EVENT_UPDATE_NOA_PARAMS_T) (prEvent->aucBuffer); ++ ++ if (prEventUpdateNoaParam->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ p2pProcessEvent_UpdateNOAParam(prAdapter, ++ prEventUpdateNoaParam->ucNetTypeIndex, ++ prEventUpdateNoaParam); ++ } else { ++ ASSERT(0); ++ } ++ } ++#else ++ ASSERT(0); ++#endif ++ break; ++ ++ case EVENT_ID_STA_AGING_TIMEOUT: ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ if (prAdapter->fgDisStaAgingTimeoutDetection == FALSE) { ++ P_EVENT_STA_AGING_TIMEOUT_T prEventStaAgingTimeout; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ ++ prEventStaAgingTimeout = (P_EVENT_STA_AGING_TIMEOUT_T) (prEvent->aucBuffer); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prEventStaAgingTimeout->ucStaRecIdx); ++ if (prStaRec == NULL) ++ break; ++ ++ DBGLOG(RX, INFO, "EVENT_ID_STA_AGING_TIMEOUT %u %pM\n", ++ prEventStaAgingTimeout->ucStaRecIdx, ++ prStaRec->aucMacAddr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++ /* Call False Auth */ ++ if (prAdapter->fgIsP2PRegistered) ++ p2pFuncDisconnect(prAdapter, prStaRec, TRUE, REASON_CODE_DISASSOC_INACTIVITY); ++ ++ } ++ /* gDisStaAgingTimeoutDetection */ ++ } ++#endif ++ break; ++ ++ case EVENT_ID_AP_OBSS_STATUS: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ rlmHandleObssStatusEventPkt(prAdapter, (P_EVENT_AP_OBSS_STATUS_T) prEvent->aucBuffer); ++#endif ++ break; ++ ++ case EVENT_ID_ROAMING_STATUS: ++#if CFG_SUPPORT_ROAMING ++ { ++ P_ROAMING_PARAM_T prParam; ++ ++ prParam = (P_ROAMING_PARAM_T) (prEvent->aucBuffer); ++ roamingFsmProcessEvent(prAdapter, prParam); ++ } ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ case EVENT_ID_SEND_DEAUTH: ++ { ++ P_WLAN_MAC_HEADER_T prWlanMacHeader; ++ P_STA_RECORD_T prStaRec; ++ ++ prWlanMacHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; ++ DBGLOG(RSN, INFO, "nicRx: aucAddr1: %pM, nicRx: aucAddr2: %pM\n", ++ prWlanMacHeader->aucAddr1, prWlanMacHeader->aucAddr2); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanMacHeader->aucAddr2); ++ if (prStaRec != NULL && prStaRec->ucStaState == STA_STATE_3) { ++ DBGLOG(RSN, WARN, "Ignore Deauth for Rx Class 3 error!\n"); ++ } else { ++ /* receive packets without StaRec */ ++ prSwRfb->pvHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; ++ if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, ++ NULL, ++ prSwRfb, ++ REASON_CODE_CLASS_3_ERR, ++ (PFN_TX_DONE_HANDLER) NULL)) ++ DBGLOG(RSN, INFO, "Send Deauth for Rx Class3 Error\n"); ++ else ++ DBGLOG(RSN, WARN, "failed to send deauth for Rx class3 error\n"); ++ } ++ } ++ break; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ case EVENT_ID_UPDATE_RDD_STATUS: ++ { ++ P_EVENT_RDD_STATUS_T prEventRddStatus; ++ ++ prEventRddStatus = (P_EVENT_RDD_STATUS_T) (prEvent->aucBuffer); ++ ++ prAdapter->ucRddStatus = prEventRddStatus->ucRddStatus; ++ } ++ ++ break; ++#endif ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ case EVENT_ID_UPDATE_BWCS_STATUS: ++ { ++ P_PTA_IPC_T prEventBwcsStatus; ++ ++ prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); ++ ++#if CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(RSN, INFO, ++ "BCM BWCS Event: %02x%02x%02x%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++ ++ DBGLOG(RSN, INFO, ++ "BCM BWCS Event: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++#endif ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_BWCS_UPDATE, ++ (PVOID) prEventBwcsStatus, sizeof(PTA_IPC_T)); ++ } ++ ++ break; ++ ++ case EVENT_ID_UPDATE_BCM_DEBUG: ++ { ++ P_PTA_IPC_T prEventBwcsStatus; ++ ++ prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); ++ ++#if CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(RSN, INFO, ++ "BCM FW status: %02x%02x%02x%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++ ++ DBGLOG(RSN, INFO, ++ "BCM FW status: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]; ++#endif ++ } ++ ++ break; ++#endif ++ ++ case EVENT_ID_DEBUG_CODE: /* only for debug */ ++ { ++ UINT_32 u4CodeId; ++ ++ DBGLOG(RSN, INFO, "[wlan-fw] function sequence: "); ++ for (u4CodeId = 0; u4CodeId < 1000; u4CodeId++) ++ DBGLOG(RSN, INFO, "%d ", prEvent->aucBuffer[u4CodeId]); ++ DBGLOG(RSN, INFO, "\n\n"); ++ } ++ break; ++ ++ case EVENT_ID_RFTEST_READY: ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++ case EVENT_ID_GSCAN_SCAN_AVAILABLE: ++ case EVENT_ID_GSCAN_CAPABILITY: ++ case EVENT_ID_GSCAN_SCAN_COMPLETE: ++ case EVENT_ID_GSCAN_FULL_RESULT: ++ case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: ++ case EVENT_ID_GSCAN_GEOFENCE_FOUND: ++ nicRxProcessGSCNEvent(prAdapter, prSwRfb); ++ break; ++ ++ case EVENT_ID_GSCAN_RESULT: ++ { ++ ++ UINT_8 realnum = 0; ++ ++ DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent ----->\n"); ++ realnum = nicRxProcessGSCNEvent(prAdapter, prSwRfb); ++ DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent <-----\n"); ++ ++#if 0 /* workaround for FW events cnt mis-match with the actual reqirements from wifi_hal */ ++ if (g_GetResultsCmdCnt == 0) { ++ DBGLOG(SCN, INFO, ++ "FW report events more than the wifi_hal asked number, buffer the results\n"); ++ UINT_8 i = 0; ++ ++ for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { ++#if 1 ++ if (!g_arGscanResultsIndicateNumber[i]) { ++ DBGLOG(SCN, INFO, ++ "found available index %d to insert results number %d into buffer\r\n", ++ i, realnum); ++ ++ g_arGscnResultsTempBuffer[i] = prSwRfb; ++ g_arGscanResultsIndicateNumber[i] = realnum; ++ g_GetResultsBufferedCnt++; ++ fgKeepprSwRfb = TRUE; ++ DBGLOG(SCN, INFO, "results buffered in index[%d] \r\n", i); ++ break; ++ } ++#endif ++ } ++ if (i == MAX_BUFFERED_GSCN_RESULTS) ++ DBGLOG(SCN, INFO, ++ "Gscn results buffer is full(all valid), no space to buffer result\r\n"); ++ } else if (g_GetResultsCmdCnt > 0) { ++ DBGLOG(SCN, INFO, "FW report events match the wifi_hal asked number\n"); ++ g_GetResultsCmdCnt--; ++ } else ++ DBGLOG(SCN, INFO, "g_GetResultsCmdCnt < 0 ??? unexpected case\n"); ++#endif ++ /* end of workaround */ ++ ++ } ++ break; ++ ++ case EVENT_ID_NLO_DONE: ++ prAdapter->rWifiVar.rScanInfo.fgPscnOnnning = FALSE; ++ ++ DBGLOG(INIT, INFO, "EVENT_ID_NLO_DONE\n"); ++ scnEventNloDone(prAdapter, (P_EVENT_NLO_DONE_T) (prEvent->aucBuffer)); ++ ++ break; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ case EVENT_ID_BATCH_RESULT: ++ DBGLOG(SCN, TRACE, "Got EVENT_ID_BATCH_RESULT"); ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++#endif /* CFG_SUPPORT_BATCH_SCAN */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ case EVENT_ID_TDLS: ++ TdlsexEventHandle(prAdapter->prGlueInfo, ++ (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++ case EVENT_ID_STATS_ENV: ++ statsEventHandle(prAdapter->prGlueInfo, ++ (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); ++ break; ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++ case EVENT_ID_FW_LOG_ENV: ++ { ++ P_EVENT_FW_LOG_T prEventLog; ++ ++ prEventLog = (P_EVENT_FW_LOG_T) (prEvent->aucBuffer); ++ DBGLOG(RX, INFO, "[F-L]%s\n", prEventLog->log); ++ } ++ break; ++ ++ default: ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ } ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief nicRxProcessMgmtPacket is used to dispatch management frames ++* to corresponding modules ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ UINT_8 ucSubtype; ++#if CFG_SUPPORT_802_11W ++ BOOLEAN fgMfgDrop = FALSE; ++#endif ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ nicRxFillRFB(prAdapter, prSwRfb); ++ ++ ucSubtype = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FC_SUBTYPE) >> OFFSET_OF_FC_SUBTYPE; ++ ++#if 0 /* CFG_RX_PKTS_DUMP */ ++ { ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_16 u2TxFrameCtrl; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ u2TxFrameCtrl = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FRAME_TYPE); ++ /* if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_MANAGEMENT)) { */ ++ /* if (u2TxFrameCtrl == MAC_FRAME_BEACON || */ ++ /* u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { */ ++ ++ DBGLOG(RX, INFO, "QM RX MGT: net %u sta idx %u wlan idx %u ssn %u ptype %u subtype %u 11 %u\n", ++ (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), prHifRxHdr->ucStaRecIdx, ++ prSwRfb->ucWlanIdx, (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr),/* The new SN of the frame */ ++ prSwRfb->ucPacketType, ucSubtype, HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); ++ ++ /* DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ /* } */ ++ /* } */ ++ } ++#endif ++ ++ if ((prAdapter->fgTestMode == FALSE) && (prAdapter->prGlueInfo->fgIsRegistered == TRUE)) { ++#if CFG_MGMT_FRAME_HANDLING ++#if CFG_SUPPORT_802_11W ++ fgMfgDrop = rsnCheckRxMgmt(prAdapter, prSwRfb, ucSubtype); ++ if (fgMfgDrop) { ++#if DBG ++ LOG_FUNC("QM RX MGT: Drop Unprotected Mgmt frame!!!\n"); ++#endif ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ return; ++ } ++#endif ++ if (apfnProcessRxMgtFrame[ucSubtype]) { ++ switch (apfnProcessRxMgtFrame[ucSubtype] (prAdapter, prSwRfb)) { ++ case WLAN_STATUS_PENDING: ++ return; ++ case WLAN_STATUS_SUCCESS: ++ case WLAN_STATUS_FAILURE: ++ break; ++ ++ default: ++ DBGLOG(RX, WARN, ++ "Unexpected MMPDU(0x%02X) returned with abnormal status\n", ucSubtype); ++ break; ++ } ++ } ++#endif ++ } ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++static VOID nicRxCheckWakeupReason(P_SW_RFB_T prSwRfb) ++{ ++ PUINT_8 pvHeader = NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_16 u2PktLen = 0; ++ UINT_32 u4HeaderOffset; ++ ++ if (!prSwRfb) ++ return; ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ if (!prHifRxHdr) ++ return; ++ ++ switch (prSwRfb->ucPacketType) { ++ case HIF_RX_PKT_TYPE_DATA: ++ { ++ UINT_16 u2Temp = 0; ++ ++ if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { ++ DBGLOG(RX, INFO, "BAR frame[SSN:%d, TID:%d] wakeup host\n", ++ (UINT_16)HIF_RX_HDR_GET_SN(prHifRxHdr), (UINT_8)HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ break; ++ } ++ u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ u2PktLen = (UINT_16)(prHifRxHdr->u2PacketLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); ++ if (!pvHeader) { ++ DBGLOG(RX, ERROR, "data packet but pvHeader is NULL!\n"); ++ break; ++ } ++ u2Temp = (pvHeader[ETH_TYPE_LEN_OFFSET] << 8) | (pvHeader[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ switch (u2Temp) { ++ case ETH_P_IPV4: ++ u2Temp = *(UINT_16 *) &pvHeader[ETH_HLEN + 4]; ++ DBGLOG(RX, INFO, "IP Packet from:%d.%d.%d.%d, IP ID 0x%04x wakeup host\n", ++ pvHeader[ETH_HLEN + 12], pvHeader[ETH_HLEN + 13], ++ pvHeader[ETH_HLEN + 14], pvHeader[ETH_HLEN + 15], u2Temp); ++ break; ++ case ETH_P_ARP: ++ { ++ PUINT_8 pucEthBody = &pvHeader[ETH_HLEN]; ++ UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; ++ ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(RX, INFO, "Arp Req From IP: %d.%d.%d.%d wakeup host\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(RX, INFO, "Arp Rsp from IP: %d.%d.%d.%d wakeup host\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ break; ++ } ++ case ETH_P_1X: ++ case ETH_P_PRE_1X: ++#if CFG_SUPPORT_WAPI ++ case ETH_WPI_1X: ++#endif ++ case ETH_P_AARP: ++ case ETH_P_IPV6: ++ case ETH_P_IPX: ++ case 0x8100: /* VLAN */ ++ case 0x890d: /* TDLS */ ++ DBGLOG(RX, INFO, "Data Packet, EthType 0x%04x wakeup host\n", u2Temp); ++ break; ++ default: ++ DBGLOG(RX, WARN, "maybe abnormal data packet, EthType 0x%04x wakeup host, dump it\n", ++ u2Temp); ++ DBGLOG_MEM8(RX, INFO, pvHeader, u2PktLen > 50 ? 50:u2PacketLen); ++ break; ++ } ++ break; ++ } ++ case HIF_RX_PKT_TYPE_EVENT: ++ { ++ P_WIFI_EVENT_T prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ ++ DBGLOG(RX, INFO, "Event 0x%02x wakeup host\n", prEvent->ucEID); ++ break; ++ } ++ case HIF_RX_PKT_TYPE_MANAGEMENT: ++ { ++ UINT_8 ucSubtype; ++ P_WLAN_MAC_MGMT_HEADER_T prWlanMgmtHeader; ++ ++ u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ if (!pvHeader) { ++ DBGLOG(RX, ERROR, "Mgmt Frame but pvHeader is NULL!\n"); ++ break; ++ } ++ prWlanMgmtHeader = (P_WLAN_MAC_MGMT_HEADER_T)pvHeader; ++ ucSubtype = (prWlanMgmtHeader->u2FrameCtrl & MASK_FC_SUBTYPE) >> ++ OFFSET_OF_FC_SUBTYPE; ++ DBGLOG(RX, INFO, "MGMT frame subtype: %d SeqCtrl %d wakeup host\n", ++ ucSubtype, prWlanMgmtHeader->u2SeqCtrl); ++ break; ++ } ++ default: ++ DBGLOG(RX, WARN, "Unknown Packet %d wakeup host\n", prSwRfb->ucPacketType); ++ break; ++ } ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief nicProcessRFBs is used to process RFBs in the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prRxCtrl->ucNumIndPacket = 0; ++ prRxCtrl->ucNumRetainedPacket = 0; ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfb) { ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++ if (kalIsWakeupByWlan(prAdapter)) ++ nicRxCheckWakeupReason(prSwRfb); ++#endif ++ switch (prSwRfb->ucPacketType) { ++ case HIF_RX_PKT_TYPE_DATA: ++ nicRxProcessDataPacket(prAdapter, prSwRfb); ++ break; ++ ++ case HIF_RX_PKT_TYPE_EVENT: ++ nicRxProcessEventPacket(prAdapter, prSwRfb); ++ break; ++ ++ case HIF_RX_PKT_TYPE_TX_LOOPBACK: ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ { ++ kalDevLoopbkRxHandle(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } ++#else ++ DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ break; ++ ++ case HIF_RX_PKT_TYPE_MANAGEMENT: ++ nicRxProcessMgmtPacket(prAdapter, prSwRfb); ++ break; ++ ++ default: ++ RX_INC_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++ nicRxReturnRFB(prAdapter, prSwRfb); /* need to free it */ ++ break; ++ } ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++ if (prRxCtrl->ucNumIndPacket > 0) { ++ RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, prRxCtrl->ucNumIndPacket); ++ RX_ADD_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT, prRxCtrl->ucNumRetainedPacket); ++ ++ /* DBGLOG(RX, INFO, ("%d packets indicated, Retained cnt = %d\n", */ ++ /* prRxCtrl->ucNumIndPacket, prRxCtrl->ucNumRetainedPacket)); */ ++#if CFG_NATIVE_802_11 ++ kalRxIndicatePkts(prAdapter->prGlueInfo, (UINT_32) prRxCtrl->ucNumIndPacket, ++ (UINT_32) prRxCtrl->ucNumRetainedPacket); ++#else ++ kalRxIndicatePkts(prAdapter->prGlueInfo, prRxCtrl->apvIndPacket, (UINT_32) prRxCtrl->ucNumIndPacket); ++#endif ++ } ++ ++} /* end of nicRxProcessRFBs() */ ++ ++#if !CFG_SDIO_INTR_ENHANCE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read the rx data from data port and setup RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @retval WLAN_STATUS_SUCCESS: SUCCESS ++* @retval WLAN_STATUS_FAILURE: FAILURE ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucBuf; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4PktLen = 0, u4ReadBytes; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgResult = TRUE; ++ UINT_32 u4RegValue; ++ UINT_32 rxNum; ++ ++ DEBUGFUNC("nicRxReadBuffer"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ pucBuf = prSwRfb->pucRecvBuff; ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(pucBuf); ++ DBGLOG(RX, TRACE, "pucBuf= 0x%x, prHifRxHdr= 0x%x\n", pucBuf, prHifRxHdr); ++ ++ do { ++ /* Read the RFB DW length and packet length */ ++ HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 20091021 move the line to get the HIF RX header (for RX0/1) */ ++ if (u4RegValue == 0) { ++ DBGLOG(RX, ERROR, "No RX packet\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ u4PktLen = u4RegValue & BITS(0, 15); ++ if (u4PktLen != 0) { ++ rxNum = 0; ++ } else { ++ rxNum = 1; ++ u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; ++ } ++ ++ DBGLOG(RX, TRACE, "RX%d: u4PktLen = %d\n", rxNum, u4PktLen); ++ ++ /* 4 <4> Read Entire RFB and packet, include HW appended DW (Checksum Status) */ ++ u4ReadBytes = ALIGN_4(u4PktLen) + 4; ++ HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, CFG_RX_MAX_PKT_SIZE); ++ ++ /* 20091021 move the line to get the HIF RX header */ ++ /* u4PktLen = (UINT_32)prHifRxHdr->u2PacketLen; */ ++ if (u4PktLen != (UINT_32) prHifRxHdr->u2PacketLen) { ++ DBGLOG(RX, ERROR, "Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", ++ u4PktLen, prHifRxHdr->u2PacketLen); ++#if DBG ++ dumpMemory8((PUINT_8) prHifRxHdr, ++ (prHifRxHdr->u2PacketLen > 4096) ? 4096 : prHifRxHdr->u2PacketLen); ++#endif ++ ASSERT(0); ++ } ++ /* u4PktLen is byte unit, not inlude HW appended DW */ ++ ++ prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ /* fgResult will be updated in MACRO */ ++ if (!fgResult) ++ return WLAN_STATUS_FAILURE; ++ ++ DBGLOG(RX, TRACE, "Dump RX buffer, length = 0x%x\n", u4ReadBytes); ++ DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port, fill RFB ++* and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ UINT_32 u4HwAppendDW; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (!prSwRfb) { ++ DBGLOG(RX, TRACE, "No More RFB\n"); ++ break; ++ } ++ /* need to consider */ ++ if (nicRxReadBuffer(prAdapter, prSwRfb) == WLAN_STATUS_FAILURE) { ++ DBGLOG(RX, TRACE, "halRxFillRFB failed\n"); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ u4HwAppendDW = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); ++ DBGLOG(RX, TRACE, "u4HwAppendDW = 0x%x\n", u4HwAppendDW); ++ DBGLOG(RX, TRACE, "u2PacketLen = 0x%x\n", prHifRxHdr->u2PacketLen); ++ } while (FALSE); /* while (RX_STATUS_TEST_MORE_FLAG(u4HwAppendDW)); */ ++ ++ return; ++ ++} /* end of nicReceiveRFBs() */ ++ ++#else ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port, fill RFB ++* and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param u4DataPort Specify which port to read ++* @param u2RxLength Specify to the the rx packet length in Byte. ++* @param prSwRfb the RFB to receive rx data. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucBuf; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4PktLen = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; ++ BOOLEAN fgResult = TRUE; ++ ++ DEBUGFUNC("nicRxEnhanceReadBuffer"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ pucBuf = prSwRfb->pucRecvBuff; ++ ASSERT(pucBuf); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ /* DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); */ ++ ++ do { ++ /* 4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW */ ++ HAL_READ_RX_PORT(prAdapter, ++ u4DataPort, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), pucBuf, CFG_RX_MAX_PKT_SIZE); ++ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); ++ break; ++ } ++ ++ u4PktLen = (UINT_32) (prHifRxHdr->u2PacketLen); ++ /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ ++ ++ prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ /* 4 <2> if the RFB dw size or packet size is zero */ ++ if (u4PktLen == 0) { ++ DBGLOG(RX, ERROR, "Packet Length = %u\n", u4PktLen); ++ ASSERT(0); ++ break; ++ } ++ /* 4 <3> if the packet is too large or too small */ ++ if (u4PktLen > CFG_RX_MAX_PKT_SIZE) { ++ DBGLOG(RX, TRACE, "Read RX Packet Lentgh Error (%u)\n", u4PktLen); ++ ASSERT(0); ++ break; ++ } ++ ++ u4Status = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ DBGLOG_MEM8(RX, TRACE, pucBuf, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port for SDIO ++* I/F, fill RFB and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 i, rxNum; ++ UINT_16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxSDIOReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ASSERT(prSDIOCtrl); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ for (rxNum = 0; rxNum < 2; rxNum++) { ++ u2RxPktNum = ++ (rxNum == 0 ? prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); ++ ++ if (u2RxPktNum == 0) ++ continue; ++ ++ for (i = 0; i < u2RxPktNum; i++) { ++ if (rxNum == 0) { ++ /* HAL_READ_RX_LENGTH */ ++ HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, &u2Tmp); ++ } else if (rxNum == 1) { ++ /* HAL_READ_RX_LENGTH */ ++ HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, &u2RxLength); ++ } ++ ++ if (!u2RxLength) ++ break; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (!prSwRfb) { ++ DBGLOG(RX, TRACE, "No More RFB\n"); ++ break; ++ } ++ ASSERT(prSwRfb); ++ ++ if (nicRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, prSwRfb) == WLAN_STATUS_FAILURE) { ++ DBGLOG(RX, TRACE, "nicRxEnhanceRxReadBuffer failed\n"); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ } ++ /* prSDIOCtrl->au4RxLength[i] = 0; */ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ } ++ } ++ ++ prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; ++ prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; ++ ++} /* end of nicRxSDIOReceiveRFBs() */ ++ ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++#if CFG_SDIO_RX_AGG ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port for SDIO with Rx aggregation enabled ++* I/F, fill RFB and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; ++ P_RX_CTRL_T prRxCtrl; ++ P_SDIO_CTRL_T prSDIOCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 u4RxLength; ++ UINT_32 i, rxNum; ++ UINT_32 u4RxAggCount = 0, u4RxAggLength = 0; ++ UINT_32 u4RxAvailAggLen, u4CurrAvailFreeRfbCnt; ++ PUINT_8 pucSrcAddr; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ BOOLEAN fgResult = TRUE; ++ BOOLEAN fgIsRxEnhanceMode; ++ UINT_16 u2RxPktNum; ++#if CFG_SDIO_RX_ENHANCE ++ UINT_32 u4MaxLoopCount = CFG_MAX_RX_ENHANCE_LOOP_COUNT; ++#endif ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxSDIOAggReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ prEnhDataStr = prAdapter->prSDIOCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ++#if CFG_SDIO_RX_ENHANCE ++ fgIsRxEnhanceMode = TRUE; ++#else ++ fgIsRxEnhanceMode = FALSE; ++#endif ++ ++ do { ++#if CFG_SDIO_RX_ENHANCE ++ /* to limit maximum loop for RX */ ++ u4MaxLoopCount--; ++ if (u4MaxLoopCount == 0) ++ break; ++#endif ++ ++ if (prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) ++ break; ++ ++ for (rxNum = 0; rxNum < 2; rxNum++) { ++ u2RxPktNum = ++ (rxNum == ++ 0 ? prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); ++ ++ /* if this assertion happened, it is most likely a F/W bug */ ++ ASSERT(u2RxPktNum <= 16); ++ ++ if (u2RxPktNum > 16) ++ continue; ++ ++ if (u2RxPktNum == 0) ++ continue; ++ ++#if CFG_HIF_STATISTICS ++ prRxCtrl->u4TotalRxAccessNum++; ++ prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; ++#endif ++ ++ u4CurrAvailFreeRfbCnt = prRxCtrl->rFreeSwRfbList.u4NumElem; ++ ++ /* if SwRfb is not enough, abort reading this time */ ++ if (u4CurrAvailFreeRfbCnt < u2RxPktNum) { ++#if CFG_HIF_RX_STARVATION_WARNING ++ DbgPrint("FreeRfb is not enough: %d available, need %d\n", u4CurrAvailFreeRfbCnt, ++ u2RxPktNum); ++ DbgPrint("Queued Count: %d / Dequeud Count: %d\n", prRxCtrl->u4QueuedCnt, ++ prRxCtrl->u4DequeuedCnt); ++#endif ++ continue; ++ } ++#if CFG_SDIO_RX_ENHANCE ++ u4RxAvailAggLen = ++ CFG_RX_COALESCING_BUFFER_SIZE - (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + ++ 4 /* extra HW padding */); ++#else ++ u4RxAvailAggLen = CFG_RX_COALESCING_BUFFER_SIZE; ++#endif ++ u4RxAggCount = 0; ++ ++ for (i = 0; i < u2RxPktNum; i++) { ++ u4RxLength = (rxNum == 0 ? ++ (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : ++ (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); ++ ++ if (!u4RxLength) { ++ ASSERT(0); ++ break; ++ } ++ ++ if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < u4RxAvailAggLen) { ++ if (u4RxAggCount < u4CurrAvailFreeRfbCnt) { ++ u4RxAvailAggLen -= ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN); ++ u4RxAggCount++; ++ } else { ++ /* no FreeSwRfb for rx packet */ ++ ASSERT(0); ++ break; ++ } ++ } else { ++ /* CFG_RX_COALESCING_BUFFER_SIZE is not large enough */ ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ u4RxAggLength = (CFG_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); ++ /* DBGLOG(RX, INFO, ("u4RxAggCount = %d, u4RxAggLength = %d\n", */ ++ /* u4RxAggCount, u4RxAggLength)); */ ++ ++ HAL_READ_RX_PORT(prAdapter, ++ rxNum, ++ u4RxAggLength, prRxCtrl->pucRxCoalescingBufPtr, CFG_RX_COALESCING_BUFFER_SIZE); ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Agg Packet Error\n"); ++ continue; ++ } ++ ++ pucSrcAddr = prRxCtrl->pucRxCoalescingBufPtr; ++ for (i = 0; i < u4RxAggCount; i++) { ++ UINT_16 u2PktLength; ++ ++ u2PktLength = (rxNum == 0 ? ++ prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : ++ prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ ASSERT(prSwRfb); ++ kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, ++ ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); ++ ++ /* record the rx time */ ++ STATS_RX_ARRIVE_TIME_RECORD(prSwRfb); /* ms */ ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ prSwRfb->ucPacketType = ++ (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); ++ /* prEnhDataStr->au4RxLength[i] = 0; */ ++ } ++ ++#if CFG_SDIO_RX_ENHANCE ++ kalMemCopy(prAdapter->prSDIOCtrl, (pucSrcAddr + 4), sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ /* do the same thing what nicSDIOReadIntStatus() does */ ++ if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && ++ (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { ++ prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; ++ } ++ ++ if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && ++ HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && ++ (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { ++ prSDIOCtrl->u4WHISR |= BIT(31); ++ } ++ ++ /* dispatch to interrupt handler with RX bits masked */ ++ nicProcessIST_impl(prAdapter, ++ prSDIOCtrl->u4WHISR & (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))); ++#endif ++ } ++ ++#if !CFG_SDIO_RX_ENHANCE ++ prEnhDataStr->rRxInfo.u.u2NumValidRx0Len = 0; ++ prEnhDataStr->rRxInfo.u.u2NumValidRx1Len = 0; ++#endif ++ } while ((prEnhDataStr->rRxInfo.u.u2NumValidRx0Len || prEnhDataStr->rRxInfo.u.u2NumValidRx1Len) ++ && fgIsRxEnhanceMode); ++ ++} ++#endif /* CFG_SDIO_RX_AGG */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Setup a RFB and allocate the os packet to the RFB ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSwRfb Pointer to the RFB ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_RESOURCES ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ PVOID pvPacket; ++ PUINT_8 pucRecvBuff; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (!prSwRfb->pvPacket) { ++ kalMemZero(prSwRfb, sizeof(SW_RFB_T)); ++ pvPacket = kalPacketAlloc(prAdapter->prGlueInfo, CFG_RX_MAX_PKT_SIZE, &pucRecvBuff); ++ if (pvPacket == NULL) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSwRfb->pvPacket = pvPacket; ++ prSwRfb->pucRecvBuff = (PVOID) pucRecvBuff; ++ } else { ++ kalMemZero(((PUINT_8) prSwRfb + OFFSET_OF(SW_RFB_T, prHifRxHdr)), ++ (sizeof(SW_RFB_T) - OFFSET_OF(SW_RFB_T, prHifRxHdr))); ++ } ++ ++ prSwRfb->prHifRxHdr = (P_HIF_RX_HEADER_T) (prSwRfb->pucRecvBuff); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of nicRxSetupRFB() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is called to put a RFB back onto the "RFB with Buffer" list ++* or "RFB without buffer" list according to pvPacket. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSwRfb Pointer to the RFB ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_QUE_ENTRY_T prQueEntry; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prQueEntry = &prSwRfb->rQueEntry; ++ ++ ASSERT(prQueEntry); ++ ++ /* The processing on this RFB is done, so put it back on the tail of ++ our list */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfb->pvPacket) { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(&prRxCtrl->rFreeSwRfbList, prQueEntry); ++ } else { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(&prRxCtrl->rIndicatedRfbList, prQueEntry); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++} /* end of nicRxReturnRFB() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process rx interrupt. When the rx ++* Interrupt is asserted, it means there are frames in queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ prGlueInfo->IsrRxCnt++; ++#if CFG_SDIO_INTR_ENHANCE ++#if CFG_SDIO_RX_AGG ++ nicRxSDIOAggReceiveRFBs(prAdapter); ++#else ++ nicRxSDIOReceiveRFBs(prAdapter); ++#endif ++#else ++ nicRxReceiveRFBs(prAdapter); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ nicRxProcessRFBs(prAdapter); ++ ++ return; ++ ++} /* end of nicProcessRxInterrupt() */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Used to update IP/TCP/UDP checksum statistics of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param aeCSUM The array of checksum result. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(aeCSUM); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS) || ++ (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_IP_SUCCESS_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) || (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_FAILED)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_IP_FAILED_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L3_PKT_COUNT); ++ } else { ++ ASSERT(0); ++ } ++ ++ if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) { ++ /* count success num */ ++ RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_SUCCESS_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_FAILED_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_SUCCESS_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_FAILED_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_NONE)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L4_PKT_COUNT); ++ } else { ++ ASSERT(0); ++ } ++ ++} /* end of nicRxUpdateCSUMStatistics() */ ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to query current status of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pucBuffer Pointer to the message buffer. ++* @param pu4Count Pointer to the buffer of message length count. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucCurrBuf = pucBuffer; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ ++ ASSERT(pu4Count); ++ ++ SPRINTF(pucCurrBuf, ("\n\nRX CTRL STATUS:")); ++ SPRINTF(pucCurrBuf, ("\n===============")); ++ SPRINTF(pucCurrBuf, ("\nFREE RFB w/i BUF LIST :%9u", prRxCtrl->rFreeSwRfbList.u4NumElem)); ++ SPRINTF(pucCurrBuf, ("\nFREE RFB w/o BUF LIST :%9u", prRxCtrl->rIndicatedRfbList.u4NumElem)); ++ SPRINTF(pucCurrBuf, ("\nRECEIVED RFB LIST :%9u", prRxCtrl->rReceivedRfbList.u4NumElem)); ++ ++ SPRINTF(pucCurrBuf, ("\n\n")); ++ ++ /* *pu4Count = (UINT_32)((UINT_32)pucCurrBuf - (UINT_32)pucBuffer); */ ++ ++} /* end of nicRxQueryStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Clear RX related counters ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return - (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ RX_RESET_ALL_CNTS(prRxCtrl); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to query current statistics of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pucBuffer Pointer to the message buffer. ++* @param pu4Count Pointer to the buffer of message length count. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucCurrBuf = pucBuffer; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ ++ ASSERT(pu4Count); ++ ++#define SPRINTF_RX_COUNTER(eCounter) \ ++ SPRINTF(pucCurrBuf, ("%-30s : %u\n", #eCounter, (UINT_32)prRxCtrl->au8Statistics[eCounter])) ++ ++ SPRINTF_RX_COUNTER(RX_MPDU_TOTAL_COUNT); ++ SPRINTF_RX_COUNTER(RX_SIZE_ERR_DROP_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_INDICATION_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_RETURNED_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_RETAINED_COUNT); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ SPRINTF_RX_COUNTER(RX_CSUM_TCP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UDP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_IP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_TCP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UDP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_IP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L4_PKT_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L3_PKT_COUNT); ++ SPRINTF_RX_COUNTER(RX_IP_V6_PKT_CCOUNT); ++#endif ++ ++ /* *pu4Count = (UINT_32)(pucCurrBuf - pucBuffer); */ ++ ++ nicRxClearStatistics(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read the Response data from data port ++* ++* @param prAdapter pointer to the Adapter handler ++* @param pucRspBuffer pointer to the Response buffer ++* ++* @retval WLAN_STATUS_SUCCESS: Response packet has been read ++* @retval WLAN_STATUS_FAILURE: Read Response packet timeout or error occurred ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicRxWaitResponse(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length) ++{ ++ UINT_32 u4Value = 0, u4PktLen = 0; ++ UINT_32 i = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgResult = TRUE; ++ UINT_32 u4Time, u4Current; ++ ++ DEBUGFUNC("nicRxWaitResponse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pucRspBuffer); ++ ASSERT(ucPortIdx < 2); ++ ++ u4Time = kalGetTimeTick(); ++ ++ do { ++ /* Read the packet length */ ++ HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); ++ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read Response Packet Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ if (ucPortIdx == 0) ++ u4PktLen = u4Value & 0xFFFF; ++ else ++ u4PktLen = (u4Value >> 16) & 0xFFFF; ++ ++/* DBGLOG(RX, TRACE, ("i = %d, u4PktLen = %d\n", i, u4PktLen)); */ ++ ++ if (u4PktLen == 0) { ++ /* timeout exceeding check */ ++ u4Current = kalGetTimeTick(); ++ ++ if ((u4Current > u4Time) && ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) { ++ DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT1 %u %d %u\n", u4PktLen, i, u4Current); ++ return WLAN_STATUS_FAILURE; ++ } else if (u4Current < u4Time && ((u4Current + (0xFFFFFFFF - u4Time)) > RX_RESPONSE_TIMEOUT)) { ++ DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT2 %u %d %u\n", u4PktLen, i, u4Current); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Response packet is not ready */ ++ kalUdelay(50); ++ ++ i++; ++ continue; ++ } ++ if (u4PktLen > u4MaxRespBufferLen) { ++ /* ++ TO: buffer is not enough but we still need to read all data from HIF to avoid ++ HIF crazy. ++ */ ++ DBGLOG(RX, ERROR, ++ "Not enough Event Buffer: required length = 0x%x, available buffer length = %d\n", ++ u4PktLen, u4MaxRespBufferLen); ++ DBGLOG(RX, ERROR, "i = %d, u4PktLen = %u\n", i, u4PktLen); ++ return WLAN_STATUS_FAILURE; ++ } ++ HAL_PORT_RD(prAdapter, ++ ucPortIdx == 0 ? MCR_WRDR0 : MCR_WRDR1, u4PktLen, pucRspBuffer, u4MaxRespBufferLen); ++ ++ /* fgResult will be updated in MACRO */ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read Response Packet Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ DBGLOG(RX, TRACE, "Dump Response buffer, length = 0x%x\n", u4PktLen); ++ DBGLOG_MEM8(RX, TRACE, pucRspBuffer, u4PktLen); ++ ++ *pu4Length = u4PktLen; ++ break; ++ } while (TRUE); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Set filter to enable Promiscuous Mode ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++} /* end of nicRxEnablePromiscuousMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Set filter to disable Promiscuous Mode ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++} /* end of nicRxDisablePromiscuousMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function flushes all packets queued in reordering module ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Flushed successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter) ++{ ++ P_SW_RFB_T prSwRfb; ++ ++ ASSERT(prAdapter); ++ ++ prSwRfb = qmFlushRxQueues(prAdapter); ++ if (prSwRfb != NULL) { ++ do { ++ P_SW_RFB_T prNextSwRfb; ++ ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ ++ /* free */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_ACTION_FRAME prActFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (prSwRfb->u2PacketLen < sizeof(WLAN_ACTION_FRAME) - 1) ++ return WLAN_STATUS_INVALID_PACKET; ++ prActFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; ++ DBGLOG(RX, INFO, "Category %u\n", prActFrame->ucCategory); ++ ++ switch (prActFrame->ucCategory) { ++ case CATEGORY_PUBLIC_ACTION: ++ if (HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) ++ aisFuncValidateRxActionFrame(prAdapter, prSwRfb); ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered) { ++ rlmProcessPublicAction(prAdapter, prSwRfb); ++ ++ p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); ++ ++ } ++#endif ++ break; ++ ++ case CATEGORY_HT_ACTION: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ rlmProcessHtAction(prAdapter, prSwRfb); ++#endif ++ break; ++ case CATEGORY_VENDOR_SPECIFIC_ACTION: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); ++#endif ++ break; ++#if CFG_SUPPORT_802_11W ++ case CATEGORY_SA_QUERT_ACTION: ++ { ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) ++ && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { ++ if (!(prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC)) { ++ /* MFP test plan 5.3.3.4 */ ++ rsnSaQueryAction(prAdapter, prSwRfb); ++ } else { ++ DBGLOG(RSN, TRACE, "Un-Protected SA Query, do nothing\n"); ++ } ++ } ++ } ++ break; ++#endif ++#if CFG_SUPPORT_802_11V ++ case CATEGORY_WNM_ACTION: ++ { ++ wnmWNMAction(prAdapter, prSwRfb); ++ } ++ break; ++#endif ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ case CATEGORY_SPEC_MGT: ++ { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ rlmProcessSpecMgtAction(prAdapter, prSwRfb); ++ } ++ break; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ case 12: /* shall not be here */ ++ /* ++ A received TDLS Action frame with the Type field set to Management shall ++ be discarded. Note that the TDLS Discovery Response frame is not a TDLS ++ frame but a Public Action frame. ++ */ ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ default: ++ break; ++ } /* end of switch case */ ++ ++ return WLAN_STATUS_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c +new file mode 100644 +index 000000000000..024bd9507603 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c +@@ -0,0 +1,2350 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_tx.c#1 ++*/ ++ ++/*! \file nic_tx.c ++ \brief Functions that provide TX operation in NIC Layer. ++ ++ This file provides TX functions which are responsible for both Hardware and ++ Software Resource Management and keep their Synchronization. ++*/ ++ ++/* ++** Log: nic_tx.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add log counter for tx ++ * ++ * 11 09 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for beacon timeout and sta aging timeout. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 05 17 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss ++ * disconnection ++ * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame ++ * dropping cases for TC4 path ++ * remove unused variables. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame ++ * dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 02 16 2011 cp.wu ++ * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking available count ++ * and modify behavior ++ * 1. add new API: nicTxGetFreeCmdCount() ++ * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * since the u2TxByteCount_UserPriority will or another setting, keep the overall buffer for avoid error ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP000000058][MT6620 Wi-Fi][Driver] Fail to handshake with WAPI AP due the 802.1x frame send to fw with extra ++ * bytes padding. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * . ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network ++ * operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add checking for TX descriptor poll. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change zero-padding for TX port access to HAL. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill extra information for revised HIF_TX_HEADER. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change to enqueue TX frame infinitely. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add TX_PACKET_MGMT to indicate the frame is coming from management modules ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Tag the packet for QoS on Tx path ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * * * ++ * ++* 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * avoid referring to NDIS-specific data structure directly from non-glue layer. ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add Ethernet destination address information in packet info for TX ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * * * 4) nicRxWaitResponse() revised ++ * * * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * * * 4. correct some HAL implementation ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 01 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-10 16:52:15 GMT mtk02752 ++** remove unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-12-07 22:44:24 GMT mtk02752 ++** correct assertion criterion ++** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-12-07 21:15:52 GMT mtk02752 ++** correct trivial mistake ++** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-12-04 15:47:21 GMT mtk02752 ++** + always append a dword of zero on TX path to avoid TX aggregation to triggered on uninitialized data ++** + add more assertion for packet size check ++** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-12-04 14:51:55 GMT mtk02752 ++** nicTxMsduInfo(): save ptr for next entry before attaching to qDataPort ++** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-12-04 11:54:54 GMT mtk02752 ++** add 2 assertion for size check ++** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-12-03 16:20:35 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-30 10:57:10 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-30 09:20:43 GMT mtk02752 ++** use TC4 instead of TC5 for command packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-27 11:08:11 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-26 20:31:22 GMT mtk02752 ++** fill prMsduInfo->ucUserPriority ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-25 21:04:33 GMT mtk02752 ++** fill u2SeqNo ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-24 20:52:12 GMT mtk02752 ++** integration with SD1's data path API ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-24 19:54:25 GMT mtk02752 ++** nicTxRetransmitOfOsSendQue & nicTxData but changed to use nicTxMsduInfoList ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 17:53:18 GMT mtk02752 ++** add nicTxCmd() for SD1_SD3_DATAPATH_INTEGRATION, which will append only HIF_TX_HEADER. seqNum, ++** WIFI_CMD_T will be created inside oid handler ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-20 15:10:24 GMT mtk02752 ++** use TxAccquireResource instead of accessing TCQ directly. ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-17 22:40:57 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-17 17:35:40 GMT mtk02752 ++** add nicTxMsduInfoList () implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-17 11:07:10 GMT mtk02752 ++** add nicTxAdjustTcq() implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-16 22:28:38 GMT mtk02752 ++** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-16 21:45:32 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION data path handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-13 13:29:56 GMT mtk01084 ++** modify TX hdr format, fix tx retransmission issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 10:36:21 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-04 14:11:11 GMT mtk01084 ++** modify TX SW data structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-10-29 19:56:17 GMT mtk01084 ++** modify HAL part ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-13 21:59:23 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-02 14:00:18 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-05-20 12:26:06 GMT mtk01461 ++** Assign SeqNum to CMD Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-05-19 10:54:04 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-05-12 09:41:55 GMT mtk01461 ++** Fix Query Command need resp issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-29 15:44:38 GMT mtk01461 ++** Move OS dependent code to kalQueryTxOOBData() ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-28 10:40:03 GMT mtk01461 ++** Add nicTxReleaseResource() for SDIO_STATUS_ENHANCE, and also fix the TX aggregation issue for 1x packet to TX1 port ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-21 09:50:47 GMT mtk01461 ++** Update nicTxCmd() for moving wait RESP function call to wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-17 19:56:32 GMT mtk01461 ++** Move the CMD_INFO_T related function to cmd_buf.c ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-17 18:14:40 GMT mtk01426 ++** Update OOB query for TX packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:51:32 GMT mtk01426 ++** Support PKGUIO ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-02 17:26:40 GMT mtk01461 ++** Add virtual OOB for HIF LOOPBACK SW PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:54:43 GMT mtk01461 ++** Add function for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:53:47 GMT mtk01461 ++** Add code for retransmit of rOsSendQueue, mpSendPacket(), and add code for TX Checksum offload, Loopback Test. ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:33:51 GMT mtk01461 ++** Add code for TX Data & Cmd Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:40 GMT mtk01461 ++** Fix LINT warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:30 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:04 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial all variables in regard to SW TX Queues and ++* all free lists of MSDU_INFO_T and SW_TFCB_T. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ PUINT_8 pucMemHandle; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_32 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicTxInitialize"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* 4 <1> Initialization of Traffic Class Queue Parameters */ ++ nicTxResetResource(prAdapter); ++ ++#if CFG_SDIO_TX_AGG ++ prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; ++#endif /* CFG_SDIO_TX_AGG */ ++ ++ /* allocate MSDU_INFO_T and link it into rFreeMsduInfoList */ ++ QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); ++ ++ pucMemHandle = prTxCtrl->pucTxCached; ++ for (i = 0; i < CFG_TX_MAX_PKT_NUM; i++) { ++ prMsduInfo = (P_MSDU_INFO_T) pucMemHandle; ++ kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); ++ } ++ ++ ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT((UINT_32) (pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize); ++ ++ QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); ++ prTxCtrl->i4TxMgmtPendingNum = 0; ++ ++#if CFG_HIF_STATISTICS ++ prTxCtrl->u4TotalTxAccessNum = 0; ++ prTxCtrl->u4TotalTxPacketNum = 0; ++#endif ++ ++ prTxCtrl->i4PendingFwdFrameCount = 0; ++ ++ qmInit(prAdapter); ++ ++ TX_RESET_ALL_CNTS(prTxCtrl); ++ ++} /* end of nicTxInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will check if has enough TC Buffer for incoming ++* packet and then update the value after promise to provide the resources. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucTC Specify the resource of TC ++* ++* \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. ++* \retval WLAN_STATUS_RESOURCES Resource is not available. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4CurrTick = 0; ++WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt) ++{ ++#define TC4_NO_RESOURCE_DELAY_MS 5 /* exponential of 5s */ ++ ++ P_TX_CTRL_T prTxCtrl; ++ WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; ++ P_QUE_MGT_T prQM; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ prQM = &prAdapter->rQM; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++/* DbgPrint("nicTxAcquireResource prTxCtrl->rTc.aucFreeBufferCount[%d]=%d\n", ++ ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); */ ++ do { ++ if (pfgIsSecOrMgmt && (ucTC == TC4_INDEX)) { ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] < 2) { ++ DBGLOG(TX, EVENT, " aucFreeBufferCount = %d\n", ++ prTxCtrl->rTc.aucFreeBufferCount[ucTC]); ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) ++ u4CurrTick = 0; ++ ++ break; ++ } ++ } ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) { ++ ++ if (ucTC == TC4_INDEX) ++ u4CurrTick = 0; ++ /* get a available TX entry */ ++ prTxCtrl->rTc.aucFreeBufferCount[ucTC]--; ++ ++ prQM->au4ResourceUsedCounter[ucTC]++; ++ ++ DBGLOG(TX, EVENT, "Acquire: TC = %d aucFreeBufferCount = %d\n", ++ ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); ++ ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } while (FALSE); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ if (ucTC == TC4_INDEX) { ++ if (u4CurrTick == 0) ++ u4CurrTick = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(kalGetTimeTick(), u4CurrTick, ++ SEC_TO_SYSTIME(TC4_NO_RESOURCE_DELAY_MS))) { ++ wlanDumpTcResAndTxedCmd(NULL, 0); ++ cmdBufDumpCmdQueue(&prAdapter->rPendingCmdQueue, "waiting response CMD queue"); ++ glDumpConnSysCpuInfo(prAdapter->prGlueInfo); ++ kalSendAeeWarning("[TC4 no resource delay 5s!]", __func__); ++ glDoChipReset(); ++ u4CurrTick = 0; ++ } ++ } ++ return u4Status; ++ ++} /* end of nicTxAcquireResourceAndTFCBs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will do polling if FW has return the resource. ++* Used when driver start up before enable interrupt. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Resource is available. ++* @retval WLAN_STATUS_FAILURE Resource is not available. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; ++ INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; ++ UINT_32 au4WTSR[2]; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (ucTC >= TC_NUM) ++ return WLAN_STATUS_FAILURE; ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) ++ return WLAN_STATUS_SUCCESS; ++ ++ while (i-- > 0) { ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); ++ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } else if (nicTxReleaseResource(prAdapter, (PUINT_8) au4WTSR)) { ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) { ++ u4Status = WLAN_STATUS_SUCCESS; ++ break; ++ } ++ kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); ++ ++ } else { ++ kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); ++ } ++ } ++ ++ if (i <= 0 && ucTC == TC4_INDEX) { ++ DBGLOG(TX, ERROR, "polling Tx resource for Tc4 timeout\n"); ++ glDumpConnSysCpuInfo(prAdapter->prGlueInfo); ++ } ++#if DBG ++ { ++ INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i + 1); ++ ++ if (i4Times) { ++ DBGLOG(TX, TRACE, "Polling MCR_WTSR delay %d times, %d msec\n", ++ i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)); ++ } ++ } ++#endif /* DBG */ ++ ++ return u4Status; ++ ++} /* end of nicTxPollingResource() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will release TC Buffer count according to ++* the given TX_STATUS COUNTER after TX Done. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] u4TxStatusCnt Value of TX STATUS ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN unsigned char *aucTxRlsCnt) ++{ ++ PUINT_32 pu4Tmp = (PUINT_32) aucTxRlsCnt; ++ P_TX_CTRL_T prTxCtrl; ++ BOOLEAN bStatus = FALSE; ++ UINT_32 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (pu4Tmp[0] | pu4Tmp[1]) { ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ for (i = 0; i < TC_NUM; i++) ++ prTxCtrl->rTc.aucFreeBufferCount[i] += aucTxRlsCnt[i]; ++ for (i = 0; i < TC_NUM; i++) ++ prQM->au4QmTcResourceBackCounter[i] += aucTxRlsCnt[i]; ++ if (aucTxRlsCnt[TC4_INDEX] != 0) ++ wlanTraceReleaseTcRes(prAdapter, aucTxRlsCnt, prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX]); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++#if 0 ++ for (i = 0; i < TC_NUM; i++) { ++ DBGLOG(TX, TRACE, "aucFreeBufferCount[%d]: %d, aucMaxNumOfBuffer[%d]: %d\n", ++ i, prTxCtrl->rTc.aucFreeBufferCount[i], i, ++ prTxCtrl->rTc.aucMaxNumOfBuffer[i]); ++ } ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[0]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[0]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[1]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[1]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[2]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[2]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[3]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[3]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[4]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[4]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[5]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[5]); ++#endif ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX]); ++ bStatus = TRUE; ++ } ++ ++ return bStatus; ++} /* end of nicTxReleaseResource() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reset TC Buffer Count to initialized value ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicTxResetResource"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; ++ prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will return the value for other component ++* which needs this information for making decisions ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucTC Specify the resource of TC ++* ++* @retval UINT_8 The number of corresponding TC number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ ASSERT(prTxCtrl); ++ ++ if (ucTC >= TC_NUM) ++ return 0; ++ else ++ return prTxCtrl->rTc.aucFreeBufferCount[ucTC]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief In this function, we'll aggregate frame(PACKET_INFO_T) ++* corresponding to HIF TX port ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoListHead a link list of P_MSDU_INFO_T ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; ++ QUE_T qDataPort0, qDataPort1; ++ WLAN_STATUS status; ++ BOOLEAN pfgIsSecOrMgmt = FALSE; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ prMsduInfo = prMsduInfoListHead; ++ ++ QUEUE_INITIALIZE(&qDataPort0); ++ QUEUE_INITIALIZE(&qDataPort1); ++ ++ /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++#if DBG && 0 ++ LOG_FUNC("nicTxMsduInfoList Acquire TC %d net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prMsduInfo->ucTC, ++ prMsduInfo->ucNetworkType, ++ prMsduInfo->ucMacHeaderLength, ++ prMsduInfo->u2FrameLength, ++ prMsduInfo->ucPacketType, prMsduInfo->fgIs802_1x, prMsduInfo->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prMsduInfo->aucEthDestAddr); ++#endif ++ ++ /* double-check available TX resouce (need to sync with CONNSYS FW) */ ++ /* caller must guarantee that the TX resource is enough in the func; OR assert here */ ++ switch (prMsduInfo->ucTC) { ++ case TC0_INDEX: ++ case TC1_INDEX: ++ case TC2_INDEX: ++ case TC3_INDEX: ++ case TC5_INDEX: /* Broadcast/multicast data packets */ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); ++ status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, FALSE); ++ ASSERT(status == WLAN_STATUS_SUCCESS) ++ ++ break; ++ ++ case TC4_INDEX: /* Command or 802.1x packets */ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); ++ ++ if ((prMsduInfo->fgIs802_1x == TRUE) || ++ (prMsduInfo->fgIs802_11 == TRUE)) ++ pfgIsSecOrMgmt = TRUE; ++ ++ status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, pfgIsSecOrMgmt); ++ ASSERT(status == WLAN_STATUS_SUCCESS) ++ ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++ /* send packets to HIF port0 or port1 here */ ++ if (qDataPort0.u4NumElem > 0) ++ nicTxMsduQueue(prAdapter, 0, &qDataPort0); ++ ++ if (qDataPort1.u4NumElem > 0) ++ nicTxMsduQueue(prAdapter, 1, &qDataPort1); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ ++#if CFG_PRINT_RTP_PROFILE ++PKT_PROFILE_T rPrevRoundLastPkt; ++ ++BOOLEAN ++nicTxLifetimePrintCheckRTP(IN P_MSDU_INFO_T prPrevProfileMsduInfo, ++ IN P_PKT_PROFILE_T prPrevRoundLastPkt, ++ IN P_PKT_PROFILE_T prPktProfile, ++ IN OUT PBOOLEAN pfgGotFirst, IN UINT_32 u4MaxDeltaTime, IN UINT_8 ucSnToBePrinted) ++{ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ ++ if (u4MaxDeltaTime) { ++ /* 4 1. check delta between current round first pkt and prevous round last pkt */ ++ if (!*pfgGotFirst) { ++ *pfgGotFirst = TRUE; ++ ++ if (prPrevRoundLastPkt->fgIsValid) { ++ if (CHK_PROFILES_DELTA(prPktProfile, prPrevRoundLastPkt, u4MaxDeltaTime)) { ++ PRINT_PKT_PROFILE(prPrevRoundLastPkt, "PR"); ++ fgPrintCurPkt = TRUE; ++ } ++ } ++ } ++ /* 4 2. check delta between current pkt and previous pkt */ ++ if (prPrevProfileMsduInfo) { ++ if (CHK_PROFILES_DELTA(prPktProfile, &prPrevProfileMsduInfo->rPktProfile, u4MaxDeltaTime)) { ++ PRINT_PKT_PROFILE(&prPrevProfileMsduInfo->rPktProfile, "P"); ++ fgPrintCurPkt = TRUE; ++ } ++ } ++ /* 4 3. check delta of current pkt lifetime */ ++ if (CHK_PROFILE_DELTA(prPktProfile, u4MaxDeltaTime)) ++ fgPrintCurPkt = TRUE; ++ } ++ /* 4 4. print every X RTP packets */ ++#if CFG_SUPPORT_WFD ++ if ((ucSnToBePrinted != 0) && (prPktProfile->u2RtpSn % ucSnToBePrinted) == 0) ++ fgPrintCurPkt = TRUE; ++#endif ++ ++ return fgPrintCurPkt; ++} ++ ++BOOLEAN ++nicTxLifetimePrintCheckSnOrder(IN P_MSDU_INFO_T prPrevProfileMsduInfo, ++ IN P_PKT_PROFILE_T prPrevRoundLastPkt, ++ IN P_PKT_PROFILE_T prPktProfile, IN OUT PBOOLEAN pfgGotFirst, IN UINT_8 ucLayer) ++{ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ P_PKT_PROFILE_T prTarPktProfile = NULL; ++ UINT_16 u2PredictSn = 0; ++ UINT_16 u2CurrentSn = 0; ++ UINT_8 aucNote[8]; ++ ++ /* 4 1. Get the target packet profile to compare */ ++ ++ /* 4 1.1 check SN between current round first pkt and prevous round last pkt */ ++ if ((!*pfgGotFirst) && (prPrevRoundLastPkt->fgIsValid)) { ++ *pfgGotFirst = TRUE; ++ prTarPktProfile = prPrevRoundLastPkt; ++ kalMemCopy(aucNote, "PR\0", 3); ++ } ++ /* 4 1.2 check SN between current pkt and previous pkt */ ++ else if (prPrevProfileMsduInfo) { ++ prTarPktProfile = &prPrevProfileMsduInfo->rPktProfile; ++ kalMemCopy(aucNote, "P\0", 2); ++ } ++ ++ if (!prTarPktProfile) ++ return FALSE; ++ /* 4 2. Check IP or RTP SN */ ++ switch (ucLayer) { ++ /* Check IP SN */ ++ case 0: ++ u2PredictSn = prTarPktProfile->u2IpSn + 1; ++ u2CurrentSn = prPktProfile->u2IpSn; ++ break; ++ /* Check RTP SN */ ++ case 1: ++ default: ++ u2PredictSn = prTarPktProfile->u2RtpSn + 1; ++ u2CurrentSn = prPktProfile->u2RtpSn; ++ break; ++ ++ } ++ /* 4 */ ++ /* 4 3. Compare SN */ ++ if (u2CurrentSn != u2PredictSn) { ++ PRINT_PKT_PROFILE(prTarPktProfile, aucNote); ++ fgPrintCurPkt = TRUE; ++ } ++ ++ return fgPrintCurPkt; ++} ++#endif ++ ++VOID nicTxReturnMsduInfoProfiling(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; ++ P_PKT_PROFILE_T prPktProfile; ++ UINT_16 u2MagicCode = 0; ++ ++ UINT_8 ucDebugtMode = 0; ++#if CFG_PRINT_RTP_PROFILE ++ P_MSDU_INFO_T prPrevProfileMsduInfo = NULL; ++ P_PKT_PROFILE_T prPrevRoundLastPkt = &rPrevRoundLastPkt; ++ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ BOOLEAN fgGotFirst = FALSE; ++ UINT_8 ucSnToBePrinted = 0; ++ ++ UINT_32 u4MaxDeltaTime = 50; /* in ms */ ++#endif ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ UINT_32 u4PktPrintPeriod = 0; ++#endif ++ ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ u2MagicCode = prWfdCfgSettings->u2WfdMaximumTp; ++ ucDebugtMode = prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode; ++ /* if(prWfdCfgSettings->ucWfdEnable && (prWfdCfgSettings->u4WfdFlag & BIT(0))) { */ ++ /* u2MagicCode = 0xE040; */ ++ /* } */ ++ } ++#endif ++ ++#if CFG_PRINT_RTP_PROFILE ++ if ((u2MagicCode >= 0xF000)) { ++ ucSnToBePrinted = (UINT_8) (u2MagicCode & BITS(0, 7)); ++ u4MaxDeltaTime = (UINT_8) (((u2MagicCode & BITS(8, 11)) >> 8) * 10); ++ } else { ++ ucSnToBePrinted = 0; ++ u4MaxDeltaTime = 0; ++ } ++ ++#endif ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ if ((u2MagicCode >= 0xE000) && (u2MagicCode < 0xF000)) ++ u4PktPrintPeriod = (UINT_32) ((u2MagicCode & BITS(0, 7)) * 32); ++ else ++ u4PktPrintPeriod = 0; ++#endif ++ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ prPktProfile = &prMsduInfo->rPktProfile; ++ ++ if (prPktProfile->fgIsValid) { ++ ++ prPktProfile->rHifTxDoneTimestamp = kalGetTimeTick(); ++ if (ucDebugtMode > 1) { ++ ++#if CFG_PRINT_RTP_PROFILE ++#if CFG_PRINT_RTP_SN_SKIP ++ fgPrintCurPkt = nicTxLifetimePrintCheckSnOrder(prPrevProfileMsduInfo, ++ prPrevRoundLastPkt, ++ prPktProfile, &fgGotFirst, 0); ++#else ++ fgPrintCurPkt = nicTxLifetimePrintCheckRTP(prPrevProfileMsduInfo, ++ prPrevRoundLastPkt, ++ prPktProfile, ++ &fgGotFirst, ++ u4MaxDeltaTime, ucSnToBePrinted); ++#endif ++ ++ /* Print current pkt profile */ ++ if (fgPrintCurPkt && ucDebugtMode > 1) ++ PRINT_PKT_PROFILE(prPktProfile, "C"); ++ ++ prPrevProfileMsduInfo = prMsduInfo; ++ fgPrintCurPkt = FALSE; ++#endif ++ } ++#if CFG_ENABLE_PER_STA_STATISTICS ++ { ++ P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ UINT_32 u4DeltaTime; ++ UINT_32 u4DeltaHifTime; ++#if 0 ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++#endif ++ UINT_8 ucNetIndex; ++ ++ if (prStaRec) { ++ ucNetIndex = prStaRec->ucNetTypeIndex; ++ u4DeltaTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - ++ prPktProfile->rHardXmitArrivalTimestamp); ++ u4DeltaHifTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - ++ prPktProfile->rDequeueTimestamp); ++ prStaRec->u4TotalTxPktsNumber++; ++ ++ prStaRec->u4TotalTxPktsTime += u4DeltaTime; ++ prStaRec->u4TotalTxPktsHifTime += u4DeltaHifTime; ++ ++ if (u4DeltaTime > prStaRec->u4MaxTxPktsTime) ++ prStaRec->u4MaxTxPktsTime = u4DeltaTime; ++ ++ if (u4DeltaHifTime > prStaRec->u4MaxTxPktsHifTime) ++ prStaRec->u4MaxTxPktsHifTime = u4DeltaHifTime; ++ ++ ++ if (u4DeltaTime >= NIC_TX_TIME_THRESHOLD) ++ prStaRec->u4ThresholdCounter++; ++#if 0 ++ if (u4PktPrintPeriod && (prStaRec->u4TotalTxPktsNumber >= u4PktPrintPeriod)) { ++ ++ DBGLOG(TX, TRACE, "[%u]N[%4u]A[%5u]M[%4u]T[%4u]E[%4u]\n", ++ prStaRec->ucIndex, ++ prStaRec->u4TotalTxPktsNumber, ++ prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber, ++ prStaRec->u4MaxTxPktsTime, ++ prStaRec->u4ThresholdCounter, ++ prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX]); ++ ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++ prStaRec->u4ThresholdCounter = 0; ++ prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX] = 0; ++ } ++#endif ++ } ++ ++ } ++#endif ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ }; ++ ++#if CFG_PRINT_RTP_PROFILE ++ /* 4 4. record the lifetime of current round last pkt */ ++ if (prPrevProfileMsduInfo) { ++ prPktProfile = &prPrevProfileMsduInfo->rPktProfile; ++ prPrevRoundLastPkt->u2IpSn = prPktProfile->u2IpSn; ++ prPrevRoundLastPkt->u2RtpSn = prPktProfile->u2RtpSn; ++ prPrevRoundLastPkt->rHardXmitArrivalTimestamp = prPktProfile->rHardXmitArrivalTimestamp; ++ prPrevRoundLastPkt->rEnqueueTimestamp = prPktProfile->rEnqueueTimestamp; ++ prPrevRoundLastPkt->rDequeueTimestamp = prPktProfile->rDequeueTimestamp; ++ prPrevRoundLastPkt->rHifTxDoneTimestamp = prPktProfile->rHifTxDoneTimestamp; ++ prPrevRoundLastPkt->ucTcxFreeCount = prPktProfile->ucTcxFreeCount; ++ prPrevRoundLastPkt->fgIsPrinted = prPktProfile->fgIsPrinted; ++ prPrevRoundLastPkt->fgIsValid = TRUE; ++ } ++#endif ++ ++ nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); ++ ++} ++ ++VOID nicTxLifetimeRecordEn(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) ++{ ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* Enable packet lifetime profiling */ ++ prPktProfile->fgIsValid = TRUE; ++ ++ /* Packet arrival time at kernel Hard Xmit */ ++ prPktProfile->rHardXmitArrivalTimestamp = GLUE_GET_PKT_ARRIVAL_TIME(prPacket); ++ ++ /* Packet enqueue time */ ++ prPktProfile->rEnqueueTimestamp = (OS_SYSTIME) kalGetTimeTick(); ++ ++} ++ ++#if CFG_PRINT_RTP_PROFILE ++/* ++ in: ++ data RTP packet pointer ++ size RTP size ++ return ++ 0:audio 1: video, -1:none ++*/ ++UINT8 checkRtpAV(PUINT_8 data, UINT_32 size) ++{ ++ PUINT_8 buf = data + 12; ++ ++ while (buf + 188 <= data + size) { ++ int pid = ((buf[1] << 8) & 0x1F00) | (buf[2] & 0xFF); ++ ++ if (pid == 0 || pid == 0x100 || pid == 0x1000) ++ buf += 188; ++ else if (pid == 0x1100) ++ return 0; ++ else if (pid == 0x1011) ++ return 1; ++ } ++ return -1; ++} ++ ++VOID ++nicTxLifetimeCheckRTP(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_NATIVE_PACKET prPacket, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) ++{ ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ UINT_16 u2EtherTypeLen; ++ PUINT_8 aucLookAheadBuf = NULL; ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* UINT_8 ucRtpHdrOffset = 28; */ ++ UINT_8 ucRtpSnOffset = 30; ++ /* UINT_32 u4RtpSrcPort = 15550; */ ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_WFD_DBG_CFG_SETTINGS_T prWfdDbgSettings = (P_WFD_DBG_CFG_SETTINGS_T) NULL; ++ ++ BOOLEAN fgEnProfiling = FALSE; ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ prWfdDbgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting; ++#if CFG_PRINT_RTP_SN_SKIP ++ if (ucNetworkType == NETWORK_TYPE_P2P_INDEX) { ++ fgEnProfiling = TRUE; ++ } else ++#endif ++ if (((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000) || ++ (prWfdDbgSettings->ucWfdDebugMode > 0)) && (ucNetworkType == NETWORK_TYPE_P2P_INDEX)) { ++ fgEnProfiling = TRUE; ++ } ++ } ++ ++ if (fgEnProfiling == FALSE) { ++ /* prPktProfile->fgIsValid = FALSE; */ ++ return; ++ } ++#endif ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ /* prPktProfile->fgIsValid = FALSE; */ ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { ++ PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_16 u2tmpIpSN = 0; ++ UINT_8 ucIpVersion; ++ ++ ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if (ucIpVersion == IPVERSION) { ++ if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { ++ ++ /* if(checkRtpAV(&pucIpHdr[ucRtpHdrOffset], ++ (u4PacketLen - ETH_HLEN - ucRtpHdrOffset)) == 0) { */ ++ ++ if (prPktProfile->fgIsValid == FALSE) ++ nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); ++ ++ prPktProfile->fgIsPrinted = FALSE; ++ ++ prPktProfile->ucTcxFreeCount = prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX]; ++ ++ /* RTP SN */ ++ prPktProfile->u2RtpSn = pucIpHdr[ucRtpSnOffset] << 8 | pucIpHdr[ucRtpSnOffset + 1]; ++ ++ /* IP SN */ ++ prPktProfile->u2IpSn = pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET] << 8 | ++ pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET + 1]; ++ u2tmpIpSN = prPktProfile->u2IpSn; ++ if (prWfdDbgSettings->ucWfdDebugMode == 1) { ++ if ((u2tmpIpSN & (prWfdDbgSettings->u2WfdSNShowPeiroid)) == 0) ++ DBGLOG(TX, TRACE, ++ "RtpSn=%d IPId=%d j=%lu\n", prPktProfile->u2RtpSn, ++ prPktProfile->u2IpSn, jiffies); ++ } ++ /* } */ ++ } ++ } ++ } ++ ++} ++#endif ++#if CFG_ENABLE_PER_STA_STATISTICS ++VOID ++nicTxLifetimeCheckByAC(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket, IN UINT_8 ucPriorityParam) ++{ ++ switch (ucPriorityParam) { ++ /* BK */ ++ /* case 1: */ ++ /* case 2: */ ++ ++ /* BE */ ++ /* case 0: */ ++ /* case 3: */ ++ ++ /* VI */ ++ case 4: ++ case 5: ++ ++ /* VO */ ++ case 6: ++ case 7: ++ nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); ++ break; ++ default: ++ break; ++ } ++} ++ ++#endif ++ ++VOID ++nicTxLifetimeCheck(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_NATIVE_PACKET prPacket, ++ IN UINT_8 ucPriorityParam, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) ++{ ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* Reset packet profile */ ++ prPktProfile->fgIsValid = FALSE; ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ nicTxLifetimeCheckByAC(prAdapter, prMsduInfo, prPacket, ucPriorityParam); ++#endif ++ ++#if CFG_PRINT_RTP_PROFILE ++ nicTxLifetimeCheckRTP(prAdapter, prMsduInfo, prPacket, u4PacketLen, ucNetworkType); ++#endif ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucPortIdx Port Number ++* @param prQue a link list of P_MSDU_INFO_T ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue) ++{ ++ P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; ++ HIF_TX_HEADER_T rHwTxHeader; ++ P_NATIVE_PACKET prNativePacket; ++ UINT_16 u2OverallBufferLength; ++ UINT_8 ucEtherTypeOffsetInWord; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 u4TxHdrSize; ++ UINT_32 u4ValidBufSize; ++ UINT_32 u4TotalLength; ++ P_TX_CTRL_T prTxCtrl; ++ QUE_T rFreeQueue; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ UINT_8 ucChksumFlag; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(ucPortIdx < 2); ++ ASSERT(prQue); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ u4ValidBufSize = prAdapter->u4CoalescingBufCachedSize; ++ ++#if CFG_HIF_STATISTICS ++ prTxCtrl->u4TotalTxAccessNum++; ++ prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; ++#endif ++ ++ QUEUE_INITIALIZE(&rFreeQueue); ++ ++ if (prQue->u4NumElem > 0) { ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_HEAD(prQue); ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ u4TotalLength = 0; ++ ++ while (prMsduInfo) { ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(TX, TRACE, " %d\n", u2Identifier); ++ } ++ } ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetProfilingFinish(prAdapter, prMsduInfo); ++#endif ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ prNativePacket = prMsduInfo->prPacket; ++ ++ ASSERT(prNativePacket); ++ ++ u4TxHdrSize = TX_HDR_SIZE; ++ ++ u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & ++ (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ /* init TX header */ ++ rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; ++ rHwTxHeader.u2TxByteCount_UserPriority |= ++ ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); ++ ++ if (prMsduInfo->fgIs802_11) { ++ ucEtherTypeOffsetInWord = ++ (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; ++ } else { ++ ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; ++ } ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; ++ rHwTxHeader.ucResource_PktType_CSflags |= ++ (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & ++ (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ if (prAdapter->u4CSUMFlags & ++ (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP)) { ++ kalQueryTxChksumOffloadParam(prNativePacket, &ucChksumFlag); ++ ++ if (ucChksumFlag & TX_CS_IP_GEN) ++ rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_IP_CSUM; ++ ++ if (ucChksumFlag & TX_CS_TCP_UDP_GEN) ++ rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_TCP_CSUM; ++ } ++ } ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; ++ rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = ++ (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << ++ HIF_TX_HDR_PS_SESSION_ID_OFFSET) ++ | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); ++ ++ rHwTxHeader.ucWlanHeaderLength = ++ (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) ++ | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & ++ HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & ++ HIF_TX_HDR_FLAG_1X_FRAME_MASK) ++ | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & ++ HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); ++ ++ rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; ++ ++ if (prMsduInfo->pfTxDoneHandler) { ++ rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; ++ } else { ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = 0; ++ } ++ ++ if (prMsduInfo->fgNeedTxDoneStatus == TRUE) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_NEED_TX_DONE_STATUS; ++ ++ if (prMsduInfo->fgIsBIP) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; ++ ++ if (prMsduInfo->fgIsBasicRate) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ if (prMsduInfo->rPktProfile.fgIsValid) ++ prMsduInfo->rPktProfile.rDequeueTimestamp = kalGetTimeTick(); ++#endif ++ ++ /* record the queue time in driver */ ++ STATS_TX_TIME_TO_HIF(prMsduInfo, &rHwTxHeader); ++ ++#if CFG_SDIO_TX_AGG ++ /* attach to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength, &rHwTxHeader, u4TxHdrSize); ++ u4TotalLength += u4TxHdrSize; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TotalLength); ++ else if (prMsduInfo->eSrc == TX_PACKET_MGMT) ++ kalMemCopy(pucOutputBuf + u4TotalLength, prNativePacket, prMsduInfo->u2FrameLength); ++ else ++ ASSERT(0); ++ ++ u4TotalLength += ALIGN_4(prMsduInfo->u2FrameLength); ++ ++#else ++ kalMemCopy(pucOutputBuf, &rHwTxHeader, u4TxHdrSize); ++ ++ /* Copy Frame Body */ ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TxHdrSize); ++ else if (prMsduInfo->eSrc == TX_PACKET_MGMT) ++ kalMemCopy(pucOutputBuf + u4TxHdrSize, prNativePacket, prMsduInfo->u2FrameLength); ++ else ++ ASSERT(0); ++ ++ ASSERT(u2OverallBufferLength <= u4ValidBufSize); ++ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); ++ ++ /* send immediately */ ++#endif ++ prNextMsduInfo = (P_MSDU_INFO_T) ++ QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry); ++ ++ if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ if (prMsduInfo->pfTxDoneHandler == NULL) { ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ KAL_SPIN_LOCK_DECLARATION(); ++ DBGLOG(TX, TRACE, "Wait TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ } ++ } else { ++ /* only free MSDU when it is not a MGMT frame */ ++ QUEUE_INSERT_TAIL(&rFreeQueue, (P_QUE_ENTRY_T) prMsduInfo); ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS) ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_SUCCESS); ++ else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++#if CFG_SDIO_TX_AGG ++ ASSERT(u4TotalLength <= u4ValidBufSize); ++ ++#if CFG_DBG_GPIO_PINS ++ { ++ /* Start port write */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_LOW); ++ kalUdelay(1); ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_HIGH); ++ } ++#endif ++ ++ /* send coalescing buffer */ ++ HAL_WRITE_TX_PORT(prAdapter, ucPortIdx, u4TotalLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); ++#endif ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#if CFG_SUPPORT_WFD && CFG_PRINT_RTP_PROFILE && !CFG_ENABLE_PER_STA_STATISTICS ++ do { ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ ++ if ((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000)) { ++ /* Enable profiling */ ++ nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++ } else { ++ /* Skip profiling */ ++ nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++ } ++ } while (FALSE); ++#else ++ nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++#endif ++#else ++ /* return */ ++ nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++#endif ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prPacketInfo Pointer of CMD_INFO_T ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) ++{ ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_16 u2OverallBufferLength; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_8 ucPortIdx; ++ HIF_TX_HEADER_T rHwTxHeader; ++ P_NATIVE_PACKET prNativePacket; ++ UINT_8 ucEtherTypeOffsetInWord; ++ P_MSDU_INFO_T prMsduInfo; ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ ++ /* <1> Assign Data Port */ ++ if (ucTC != TC4_INDEX) { ++ ucPortIdx = 0; ++ } else { ++ /* Broadcast/multicast data frames, 1x frames, command packets, MMPDU */ ++ ucPortIdx = 1; ++ } ++ wlanTraceTxCmd(prCmdInfo); ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ /* <2> Compose HIF_TX_HEADER */ ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ prNativePacket = prCmdInfo->prPacket; ++ ++ ASSERT(prNativePacket); ++ ++ u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) ++ & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ rHwTxHeader.u2TxByteCount_UserPriority = ((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) ++ & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET); ++ ++ rHwTxHeader.ucStaRecIdx = prCmdInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = HIF_TX_HDR_BURST_END_MASK; ++ ++ rHwTxHeader.ucWlanHeaderLength = (ETH_HLEN & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = ++ (((UINT_8) (prCmdInfo->eNetworkType) << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & ++ HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((1 << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK); ++ ++ rHwTxHeader.u2SeqNo = 0; ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_TX_DONE_STATUS; ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE /* | HIF_TX_HDR_RTS */; ++ ++ /* <2.3> Copy HIF TX HEADER */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); ++ ++ /* <3> Copy Frame Body Copy */ ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + TX_HDR_SIZE); ++ } else if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; ++ ++ ASSERT(prMsduInfo->fgIs802_11 == TRUE); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ /* <2> Compose HIF_TX_HEADER */ ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & ++ (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; ++ rHwTxHeader.u2TxByteCount_UserPriority |= ++ ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); ++ ++ ucEtherTypeOffsetInWord = (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; ++ rHwTxHeader.ucResource_PktType_CSflags |= ++ (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & ++ (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++ rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; ++ rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = ++ (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET) ++ | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); ++ ++ rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) ++ | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK) ++ | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & ++ HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); ++ ++ rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; ++ ++ if (prMsduInfo->pfTxDoneHandler) { ++ rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; ++ } else { ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = 0; ++ } ++ ++ if (prMsduInfo->fgIsBIP) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; ++ ++ if (prMsduInfo->fgIsBasicRate) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; ++ /* <2.3> Copy HIF TX HEADER */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); ++ ++ /* <3> Copy Frame Body */ ++ kalMemCopy(pucOutputBuf + TX_HDR_SIZE, prMsduInfo->prPacket, prMsduInfo->u2FrameLength); ++ ++ /* <4> Management Frame Post-Processing */ ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ if (prMsduInfo->pfTxDoneHandler == NULL) { ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ ++ DBGLOG(TX, TRACE, "Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ } ++ } else { ++ prWifiCmd = (P_WIFI_CMD_T) prCmdInfo->pucInfoBuffer; ++ ++ /* <2> Compose the Header of Transmit Data Structure for CMD Packet */ ++ u2OverallBufferLength = ++ TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ prWifiCmd->u2TxByteCount_UserPriority = u2OverallBufferLength; ++ prWifiCmd->ucEtherTypeOffset = 0; ++ prWifiCmd->ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET) ++ | (UINT_8) ((HIF_TX_PKT_TYPE_CMD << HIF_TX_HDR_PACKET_TYPE_OFFSET) & (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++ /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); ++ ++ ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); ++ ++ if ((prCmdInfo->ucCID == CMD_ID_SCAN_REQ) || ++ (prCmdInfo->ucCID == CMD_ID_SCAN_CANCEL) || ++ (prCmdInfo->ucCID == CMD_ID_SCAN_REQ_V2)) ++ DBGLOG(TX, INFO, "ucCmdSeqNum =%d, ucCID =%d\n", prCmdInfo->ucCmdSeqNum, prCmdInfo->ucCID); ++ } ++ ++ /* <4> Write frame to data port */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, ++ (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of nicTxCmd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will clean up all the pending frames in internal SW Queues ++* by return the pending TX packet to the system. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxRelease(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ nicTxFlush(prAdapter); ++ ++ /* free MSDU_INFO_T from rTxMgmtMsduInfoList */ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ if (prMsduInfo) { ++ /* the packet must be mgmt frame with tx done callback */ ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ /* invoke done handler */ ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_LIFE_TIMEOUT); ++ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++} /* end of nicTxRelease() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process the TX Done interrupt and pull in more pending frames in SW ++* Queues for transmission. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SDIO_INTR_ENHANCE ++ P_SDIO_CTRL_T prSDIOCtrl; ++#else ++ UINT_32 au4TxCount[2]; ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ prGlueInfo->IsrTxCnt++; ++ ++ /* Get the TX STATUS */ ++#if CFG_SDIO_INTR_ENHANCE ++ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++#if DBG ++ /* dumpMemory8((PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T)); */ ++#endif ++ ++ nicTxReleaseResource(prAdapter, (PUINT_8) &prSDIOCtrl->rTxInfo); ++ kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); ++ ++#else ++ ++ HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); ++ HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); ++ DBGLOG(EMU, TRACE, "MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1]); ++ ++ nicTxReleaseResource(prAdapter, (PUINT_8) au4TxCount); ++ ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ nicTxAdjustTcq(prAdapter); ++ ++ /* Indicate Service Thread */ ++ if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ ++} /* end of nicProcessTxInterrupt() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function frees packet of P_MSDU_INFO_T linked-list ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoList a link list of P_MSDU_INFO_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_NATIVE_PACKET prNativePacket; ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ while (prMsduInfo) { ++ prNativePacket = prMsduInfo->prPacket; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS) { ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_FAILURE); ++ } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ P_MSDU_INFO_T prTempMsduInfo = prMsduInfo; ++ ++ if (prMsduInfo->pfTxDoneHandler) ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ cnmMgtPktFree(prAdapter, prTempMsduInfo); ++ continue; ++ } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ } ++ ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoList a link list of P_MSDU_INFO_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ ++ switch (prMsduInfo->eSrc) { ++ case TX_PACKET_FORWARDING: ++ wlanReturnPacket(prAdapter, prMsduInfo->prPacket); ++ break; ++ case TX_PACKET_OS: ++ case TX_PACKET_OS_OID: ++ case TX_PACKET_MGMT: ++ default: ++ break; ++ } ++ ++ /* Reset MSDU_INFO fields */ ++ kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo = prNextMsduInfo; ++ }; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function fills packet information to P_MSDU_INFO_T ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfo P_MSDU_INFO_T ++* @param prPacket P_NATIVE_PACKET ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_8 ucPriorityParam; ++ UINT_8 ucMacHeaderLen; ++ UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; ++ BOOLEAN fgIs1x = FALSE; ++ BOOLEAN fgIsPAL = FALSE; ++ UINT_32 u4PacketLen; ++ ULONG u4SysTime; ++ UINT_8 ucNetworkType; ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ if (kalQoSFrameClassifierAndPacketInfo(prGlueInfo, ++ prPacket, ++ &ucPriorityParam, ++ &u4PacketLen, ++ aucEthDestAddr, ++ &fgIs1x, &fgIsPAL, &ucNetworkType, ++ NULL) == FALSE) { ++ return FALSE; ++ } ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ nicTxLifetimeCheck(prAdapter, prMsduInfo, prPacket, ucPriorityParam, u4PacketLen, ucNetworkType); ++#endif ++ ++ /* Save the value of Priority Parameter */ ++ GLUE_SET_PKT_TID(prPacket, ucPriorityParam); ++ ++ if (fgIs1x) ++ GLUE_SET_PKT_FLAG_1X(prPacket); ++ ++ if (fgIsPAL) ++ GLUE_SET_PKT_FLAG_PAL(prPacket); ++ ++ ucMacHeaderLen = ETH_HLEN; ++ ++ /* Save the value of Header Length */ ++ GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen); ++ ++ /* Save the value of Frame Length */ ++ GLUE_SET_PKT_FRAME_LEN(prPacket, (UINT_16) u4PacketLen); ++ ++ /* Save the value of Arrival Time */ ++ u4SysTime = (OS_SYSTIME) kalGetTimeTick(); ++ GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); ++ ++ prMsduInfo->prPacket = prPacket; ++ prMsduInfo->fgIs802_1x = fgIs1x; ++ prMsduInfo->fgIs802_11 = FALSE; ++ prMsduInfo->ucNetworkType = ucNetworkType; ++ prMsduInfo->ucUserPriority = ucPriorityParam; ++ prMsduInfo->ucMacHeaderLength = ucMacHeaderLen; ++ prMsduInfo->u2FrameLength = (UINT_16) u4PacketLen; ++ COPY_MAC_ADDR(prMsduInfo->aucEthDestAddr, aucEthDestAddr); ++ ++ if (prSkb->len > ETH_HLEN) ++ STATS_TX_PKT_CALLBACK(prSkb->data, prMsduInfo); ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function update TCQ values by passing current status to txAdjustTcQuotas ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Updated successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Num; ++ TX_TCQ_ADJUST_T rTcqAdjust; ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ for (u4Num = 0; u4Num < TC_NUM; u4Num++) { ++ prTxCtrl->rTc.aucFreeBufferCount[u4Num] += rTcqAdjust.acVariation[u4Num]; ++ prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] += rTcqAdjust.acVariation[u4Num]; ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function flushes all packets queued in STA/AC queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Flushed successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* ask Per STA/AC queue to be fllushed and return all queued packets */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prMsduInfo = qmFlushTxQueues(prAdapter); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prMsduInfo != NULL) { ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); ++ nicTxReturnMsduInfo(prAdapter, prMsduInfo); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. ++* However this function is used for INIT_CMD. ++* ++* In order to avoid further maintenance issues, these 2 functions are separated ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prPacketInfo Pointer of CMD_INFO_T ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) ++{ ++ P_INIT_HIF_TX_HEADER_T prInitTxHeader; ++ UINT_16 u2OverallBufferLength; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 ucPortIdx; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(ucTC == TC0_INDEX); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ prInitTxHeader = (P_INIT_HIF_TX_HEADER_T) prCmdInfo->pucInfoBuffer; ++ ++ /* <1> Compose the Header of Transmit Data Structure for CMD Packet */ ++ u2OverallBufferLength = ++ TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ prInitTxHeader->u2TxByteCount = u2OverallBufferLength; ++ prInitTxHeader->ucEtherTypeOffset = 0; ++ prInitTxHeader->ucCSflags = 0; ++ ++ /* <2> Assign Data Port */ ++ if (ucTC != TC4_INDEX) { ++ ucPortIdx = 0; ++ } else { /* Broadcast/multicast data packets */ ++ ucPortIdx = 1; ++ } ++ ++ /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); ++ ++ ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); ++ ++ /* <4> Write frame to data port */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, ++ (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll reset TX resource counter to initial value used ++* in F/W download state ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ DEBUGFUNC("nicTxInitResetResource"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; ++ prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; ++ prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; ++ prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; ++ prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; ++ prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; ++ prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function enqueues MSDU_INFO_T into queue management, ++* or command queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prMsduInfo Pointer to MSDU ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; ++ QUE_T qDataPort0, qDataPort1; ++ P_CMD_INFO_T prCmdInfo; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ QUEUE_INITIALIZE(&qDataPort0); ++ QUEUE_INITIALIZE(&qDataPort1); ++ ++ /* check how many management frame are being queued */ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ /* MMPDU: force stick to TC4 */ ++ prMsduInfo->ucTC = TC4_INDEX; ++ ++ QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); ++ } else { ++ QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++ if (qDataPort0.u4NumElem) { ++ /* send to QM: queue the packet to different TX queue by policy */ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort0)); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ /* post-process for "dropped" packets */ ++ if (prRetMsduInfo != NULL) { /* unable to enqueue */ ++ nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); ++ nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); ++ } ++ } ++ ++ if (qDataPort1.u4NumElem) { ++ prMsduInfoHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort1); ++ ++ if (qDataPort1.u4NumElem > nicTxGetFreeCmdCount(prAdapter)) { ++ /* not enough descriptors for sending */ ++ u4Status = WLAN_STATUS_FAILURE; ++ ++ /* free all MSDUs */ ++ while (prMsduInfoHead) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); ++ ++ if (prMsduInfoHead->pfTxDoneHandler != NULL) { ++ prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, ++ TX_RESULT_DROPPED_IN_DRIVER); ++ } ++ ++ cnmMgtPktFree(prAdapter, prMsduInfoHead); ++ ++ prMsduInfoHead = prNextMsduInfo; ++ } ++ } else { ++ /* send to command queue */ ++ while (prMsduInfoHead) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); ++ ++ prCmdInfo->eCmdType = COMMAND_TYPE_MANAGEMENT_FRAME; ++ prCmdInfo->u2InfoBufLen = prMsduInfoHead->u2FrameLength; ++ prCmdInfo->pucInfoBuffer = NULL; ++ prCmdInfo->prPacket = (P_NATIVE_PACKET) prMsduInfoHead; ++ prCmdInfo->ucStaRecIndex = prMsduInfoHead->ucStaRecIndex; ++ prCmdInfo->eNetworkType = prMsduInfoHead->ucNetworkType; ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ } else { ++ /* Cmd free count is larger than expected, but allocation fail. */ ++ ASSERT(0); ++ ++ u4Status = WLAN_STATUS_FAILURE; ++ cnmMgtPktFree(prAdapter, prMsduInfoHead); ++ } ++ ++ prMsduInfoHead = prNextMsduInfo; ++ } ++ } ++ } ++ ++ /* indicate service thread for sending */ ++ if (prTxCtrl->i4TxMgmtPendingNum > 0 || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function returns available count in command queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rFreeCmdList.u4NumElem; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c +new file mode 100644 +index 000000000000..38e4569bc04f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c +@@ -0,0 +1,192 @@ ++/* ++** Id: @(#) p2p_nic.c@@ ++*/ ++ ++/*! \file p2p_nic.c ++ \brief Wi-Fi Direct Functions that provide operation in NIC's (Network Interface Card) point of view. ++ ++ This file includes functions which unite multiple hal(Hardware) operations ++ and also take the responsibility of Software Resource Management in order ++ to keep the synchronization with Hardware Manipulation. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief When Probe Rsp & Beacon frame is received and decide a P2P device, ++* this function will be invoked to buffer scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prEventScanResult Pointer of EVENT_SCAN_RESULT_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, ++ IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength) ++{ ++ P_P2P_INFO_T prP2pInfo = (P_P2P_INFO_T) NULL; ++ P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; ++ UINT_32 u4Idx = 0; ++ BOOLEAN bUpdate = FALSE; ++ ++ PUINT_8 pucIeBuf = (PUINT_8) NULL; ++ UINT_16 u2IELength = 0; ++ UINT_8 zeroMac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; ++ ++ ASSERT(prAdapter); ++ ++ prP2pInfo = prAdapter->prP2pInfo; ++ ++ for (u4Idx = 0; u4Idx < prP2pInfo->u4DeviceNum; u4Idx++) { ++ prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; ++ ++ if (EQUAL_MAC_ADDR(prTargetResult->aucDeviceAddr, prP2pResult->aucDeviceAddr)) { ++ bUpdate = TRUE; ++ ++ /* Backup OLD buffer result. */ ++ pucIeBuf = prTargetResult->pucIeBuf; ++ u2IELength = prTargetResult->u2IELength; ++ ++ /* Update Device Info. */ ++ /* zero */ ++ kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* then buffer */ ++ kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* See if new IE length is longer or not. */ ++ if ((u2RxIELength > u2IELength) && (u2IELength != 0)) { ++ /* Buffer is not enough. */ ++ u2RxIELength = u2IELength; ++ } else if ((u2IELength == 0) && (u2RxIELength != 0)) { ++ /* RX new IE buf. */ ++ ASSERT(pucIeBuf == NULL); ++ pucIeBuf = prP2pInfo->pucCurrIePtr; ++ ++ if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > ++ (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { ++ /* Common Buffer is no enough. */ ++ u2RxIELength = ++ (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - ++ (ULONG) prP2pInfo->pucCurrIePtr); ++ } ++ ++ /* Step to next buffer address. */ ++ prP2pInfo->pucCurrIePtr = ++ (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength); ++ } ++ ++ /* Restore buffer pointer. */ ++ prTargetResult->pucIeBuf = pucIeBuf; ++ ++ if (pucRxIEBuf) { ++ /* If new received IE is available. ++ * Replace the old one & update new IE length. ++ */ ++ kalMemCopy(pucIeBuf, pucRxIEBuf, u2RxIELength); ++ prTargetResult->u2IELength = u2RxIELength; ++ } else { ++ /* There is no new IE information, keep the old one. */ ++ prTargetResult->u2IELength = u2IELength; ++ } ++ } ++ } ++ ++ if (!bUpdate) { ++ /* We would flush the whole scan result after each scan request is issued. ++ * If P2P device is too many, it may over the scan list. ++ */ ++ if ((u4Idx < CFG_MAX_NUM_BSS_LIST) && (UNEQUAL_MAC_ADDR(zeroMac, prP2pResult->aucDeviceAddr))) { ++ /* whsu:XXX */ ++ prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; ++ ++ /* zero */ ++ kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* then buffer */ ++ kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* printk("DVC FND %d %pM, %pM\n", ++ prP2pInfo->u4DeviceNum, ++ prP2pResult->aucDeviceAddr, ++ prTargetResult->aucDeviceAddr); */ ++ ++ if (u2RxIELength) { ++ prTargetResult->pucIeBuf = prP2pInfo->pucCurrIePtr; ++ ++ if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > ++ (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { ++ /* Common Buffer is no enough. */ ++ u2IELength = ++ (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - ++ (ULONG) prP2pInfo->pucCurrIePtr); ++ } else { ++ u2IELength = u2RxIELength; ++ } ++ ++ prP2pInfo->pucCurrIePtr = ++ (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2IELength); ++ ++ kalMemCopy((PVOID) prTargetResult->pucIeBuf, (PVOID) pucRxIEBuf, (UINT_32) u2IELength); ++ prTargetResult->u2IELength = u2IELength; ++ } else { ++ prTargetResult->pucIeBuf = NULL; ++ prTargetResult->u2IELength = 0; ++ } ++ ++ prP2pInfo->u4DeviceNum++; ++ ++ } else { ++ /* TODO: Fixme to replace an old one. (?) */ ++ ASSERT(FALSE); ++ } ++ } ++} /* nicRxAddP2pDevice */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +new file mode 100644 +index 000000000000..dd00859d4608 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +@@ -0,0 +1,5038 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 ++*/ ++ ++/*! \file "que_mgt.c" ++ \brief TX/RX queues management ++ ++ The main tasks of queue management include TC-based HIF TX flow control, ++ adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save ++ forwarding control, RX packet reordering, and RX BA agreement management. ++*/ ++ ++/* ++** Log: que_mgt.c ++** ++** 04 11 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Drop the probe response packet when absent. ++** ++** 04 09 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Fix CMD buffer short issue. ++** ++** 04 09 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Fix CMD buffer short issue. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 23 2012 eddie.chen ++ * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule ++ * Change the enqueue policy when ACM = 1. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Code refine, remove one #if 0 code. ++ * ++ * 11 19 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for tx ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Fix xlog format to hex format ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug msg for xlog. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Use short name for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 10 2011 chinglan.wang ++ * NULL ++ * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP. ++ * ++ * 11 09 2011 chinglan.wang ++ * NULL ++ * [WiFi direct]Can't make P2P connect via PBC. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to ++ * the AP.. ++ * ++ * 10 25 2011 wh.su ++ * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check ++ * un-expect ++ * let the Rx BA accept even the sta not valid. ++ * ++ * 09 28 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * enlarge window size only by 4. ++ * ++ * 09 01 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * set rx window size as twice buffer size. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue. ++ * ++ * 08 03 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * force window size at least 16. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device ++ * issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 26 2011 eddie.chen ++ * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter ++ * API for query the RX reorder queued packets counter. ++ * ++ * 07 07 2011 eddie.chen ++ * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. ++ * Add setEvent when free quota is updated. ++ * ++ * 07 05 2011 eddie.chen ++ * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. ++ * Send 1x when peer STA is in PS. ++ * ++ * 05 31 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Fix the QM quota in MT5931. ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 yuche.tsai ++ * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved) ++ * Deauthentication frame is not bound to network active status. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Fix Klockwork warning. ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW ++ * Fix wmm parameters in beacon for BOW. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 02 23 2011 eddie.chen ++ * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap ++ * Fix parsing WMM INFO and bmp delivery bitmap definition. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Remove comments. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 14 2011 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] ++ * [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * Allow 802.1x can be send even the net is not active due the drver / fw sync issue. ++ * ++ * 01 13 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * Fix typo and compile error. ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * Fix WMM parameter condition for STA ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * 1) Check Bss if support QoS before adding WMMIE ++ * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control ++ * ++ * 01 12 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Update MQM for WMM IE generation method ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add per STA flow control when STA is in PS mode ++ * ++ * 01 03 2011 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * update prStaRec->fgIsUapsdSupported flag. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * use the #14 and modify the add code for check MMPDU. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * only MMPDU not check the netActive flag. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * not check the netActive flag for mgmt . ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 08 30 2010 yarco.yang ++ * NULL ++ * Fixed klockwork error message ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 10 2010 yarco.yang ++ * NULL ++ * Code refine ++ * ++ * 08 06 2010 yarco.yang ++ * NULL ++ * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 20 2010 yarco.yang ++ * ++ * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 yarco.yang ++ * ++ * [WPD00003849] ++ * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * . ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Use fgInUse instead of fgIsValid for De-queue judgement ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * For MMPDU, STA_REC will be decided by caller module ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add MGMT Packet type for HIF_TX_HEADER ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Refined the debug msg ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * comment out one assertion which refer to undefined data member. ++ * ++ * 03 30 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled adaptive TC resource control ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++* 03 17 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) ++ * ++ * 03 11 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed buffer leak when processing BAR frames ++ * ++ * 03 02 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5 ++ * ++ * 03 01 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed STA_REC index determination bug (fgIsValid shall be checked) ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Refined function qmDetermineStaRecIndex() for BMCAST packets ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled multi-STA TX path with fairness ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled dynamically activating and deactivating STA_RECs ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for dynamic activating and deactivating STA_RECs. ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the 802.1x path ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468 ++** Fixed casting for qmAddRxBaEntry() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752 ++** remove SD1_SD3.. flag ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468 ++** Added RX buffer reordering functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468 ++** Modified Flush Queue function to let queues be reinitialized ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468 ++** Added flushing per-Type queues code ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468 ++** Added Debug msgs and fixed incorrect assert ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468 ++** Bug fixing (qmDequeueTxPackets local variable initialization) ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752 ++** correct and surpress PREfast warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468 ++** Used SD1_SD3_DATAPATH_INTEGRATION ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468 ++** Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM]; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if ARP_MONITER_ENABLE ++static UINT_16 arpMoniter; ++static UINT_8 apIp[4]; ++#endif ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static inline VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++static inline VOID ++qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, ++ OUT P_QUE_T prQue, ++ IN UINT_8 ucTC, IN UINT_8 ucCurrentAvailableQuota, IN UINT_8 ucTotalQuota); ++ ++static inline VOID ++qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init Queue Management for TX ++* ++* \param[in] (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmInit(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4QueArrayIdx; ++ UINT_32 i; ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* DbgPrint("QM: Enter qmInit()\n"); */ ++#if CFG_SUPPORT_QOS ++ prAdapter->rWifiVar.fgSupportQoS = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportQoS = FALSE; ++#endif ++ ++#if CFG_SUPPORT_AMPDU_RX ++ prAdapter->rWifiVar.fgSupportAmpduRx = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportAmpduRx = FALSE; ++#endif ++ ++#if CFG_SUPPORT_AMPDU_TX ++ prAdapter->rWifiVar.fgSupportAmpduTx = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportAmpduTx = FALSE; ++#endif ++ ++#if CFG_SUPPORT_TSPEC ++ prAdapter->rWifiVar.fgSupportTspec = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportTspec = FALSE; ++#endif ++ ++#if CFG_SUPPORT_UAPSD ++ prAdapter->rWifiVar.fgSupportUAPSD = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportUAPSD = FALSE; ++#endif ++ ++#if CFG_SUPPORT_UL_PSMP ++ prAdapter->rWifiVar.fgSupportULPSMP = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportULPSMP = FALSE; ++#endif ++ ++#if CFG_SUPPORT_RX_SGI ++ prAdapter->rWifiVar.u8SupportRxSgi20 = 0; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = 0; ++#else ++ prAdapter->rWifiVar.u8SupportRxSgi20 = 2; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = 2; ++#endif ++ ++#if CFG_SUPPORT_RX_HT_GF ++ prAdapter->rWifiVar.u8SupportRxGf = 0; ++#else ++ prAdapter->rWifiVar.u8SupportRxGf = 2; ++#endif ++ ++ /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */ ++ for (u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++) ++ QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx])); ++ ++ /* 4 <3> Initialize the RX BA table and RX queues */ ++ /* Initialize the RX Reordering Parameters and Queues */ ++ for (u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++) { ++ prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE; ++ QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue)); ++ prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF; ++ prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF; ++ ++ prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE; ++ ++ } ++ prQM->ucRxBaCount = 0; ++ ++ kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout)); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ /* 4 <4> Initialize TC resource control variables */ ++ for (i = 0; i < TC_NUM; i++) ++ prQM->au4AverageQueLen[i] = 0; ++ prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; ++ prQM->u4TxNumOfVi = 0; ++ prQM->u4TxNumOfVo = 0; ++ ++/* ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); */ ++ ++ /* 1 20 1 1 4 1 */ ++ prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1) */ ++ prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC0 = %d\n", NIC_TX_BUFF_COUNT_TC0); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC1 = %d\n", NIC_TX_BUFF_COUNT_TC1); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC2 = %d\n", NIC_TX_BUFF_COUNT_TC2); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC3 = %d\n", NIC_TX_BUFF_COUNT_TC3); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC4 = %d\n", NIC_TX_BUFF_COUNT_TC4); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC5 = %d\n", NIC_TX_BUFF_COUNT_TC5); ++ ++ /* 1 1 1 1 2 1 */ ++ prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE; ++ prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE; ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; ++ prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE; ++ prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1) */ ++ prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE; ++ ++ /* 4 4 6 6 2 4 */ ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE; ++ ++ prQM->fgTcResourcePostAnnealing = FALSE; ++ ++ ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64); ++#endif ++ ++#if QM_TEST_MODE ++ prQM->u4PktCount = 0; ++ ++#if QM_TEST_FAIR_FORWARDING ++ ++ prQM->u4CurrentStaRecIndexToEnqueue = 0; ++ { ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ P_STA_RECORD_T prStaRec; ++ ++ /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ ++ aucMacAddr[0] = 0x11; ++ aucMacAddr[1] = 0x22; ++ aucMacAddr[2] = 0xAA; ++ aucMacAddr[3] = 0xBB; ++ aucMacAddr[4] = 0xCC; ++ aucMacAddr[5] = 0xDD; ++ ++ prStaRec = &prAdapter->arStaRec[1]; ++ ASSERT(prStaRec); ++ ++ prStaRec->fgIsValid = TRUE; ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsInPS = FALSE; ++ prStaRec->ucPsSessionID = 0xFF; ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prStaRec->fgIsAp = TRUE; ++ COPY_MAC_ADDR((prStaRec)->aucMacAddr, aucMacAddr); ++ ++ } ++ ++#endif ++ ++#endif ++ ++#if QM_FORWARDING_FAIRNESS ++ { ++ UINT_32 i; ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { ++ prQM->au4ForwardCount[i] = 0; ++ prQM->au4HeadStaRecIndex[i] = 0; ++ } ++ } ++#endif ++ ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ kalMemZero(prQM->au4QmTcResourceEmptyCounter, sizeof(prQM->au4QmTcResourceEmptyCounter)); ++#endif ++ ++} ++ ++#if QM_TEST_MODE ++VOID qmTestCases(IN P_ADAPTER_T prAdapter) ++{ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DbgPrint("QM: ** TEST MODE **\n"); ++ ++ if (QM_TEST_STA_REC_DETERMINATION) { ++ if (prAdapter->arStaRec[0].fgIsValid) { ++ prAdapter->arStaRec[0].fgIsValid = FALSE; ++ DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); ++ } else { ++ prAdapter->arStaRec[0].fgIsValid = TRUE; ++ DbgPrint("QM: (Test) Activate STA_REC[0]\n"); ++ } ++ } ++ ++ if (QM_TEST_STA_REC_DEACTIVATION) { ++ /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */ ++ ++ if (prAdapter->arStaRec[0].fgIsValid) { ++ ++ DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); ++ qmDeactivateStaRec(prAdapter, 0); ++ } else { ++ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ ++ /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ ++ aucMacAddr[0] = 0x11; ++ aucMacAddr[1] = 0x22; ++ aucMacAddr[2] = 0xAA; ++ aucMacAddr[3] = 0xBB; ++ aucMacAddr[4] = 0xCC; ++ aucMacAddr[5] = 0xDD; ++ ++ DbgPrint("QM: (Test) Activate STA_REC[0]\n"); ++ qmActivateStaRec(prAdapter, /* Adapter pointer */ ++ 0, /* STA_REC index from FW */ ++ TRUE, /* fgIsQoS */ ++ NETWORK_TYPE_AIS_INDEX, /* Network type */ ++ TRUE, /* fgIsAp */ ++ aucMacAddr /* MAC address */ ++ ); ++ } ++ } ++ ++ if (QM_TEST_FAIR_FORWARDING) { ++ if (prAdapter->arStaRec[1].fgIsValid) { ++ prQM->u4CurrentStaRecIndexToEnqueue++; ++ prQM->u4CurrentStaRecIndexToEnqueue %= 2; ++ DbgPrint("QM: (Test) Switch to STA_REC[%u]\n", prQM->u4CurrentStaRecIndexToEnqueue); ++ } ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Activate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the STA_REC ++* \param[in] fgIsQoS Set to TRUE if this is a QoS STA ++* \param[in] pucMacAddr The MAC address of the STA ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ /* 4 <1> Deactivate first */ ++ ASSERT(prStaRec); ++ ++ if (prStaRec->fgIsValid) { /* The STA_REC has been activated */ ++ DBGLOG(QM, WARN, "QM: (WARNING) Activating a STA_REC which has been activated\n"); ++ DBGLOG(QM, WARN, "QM: (WARNING) Deactivating a STA_REC before re-activating\n"); ++ /* To flush TX/RX queues and del RX BA agreements */ ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ } ++ /* 4 <2> Activate the STA_REC */ ++ /* Init the STA_REC */ ++ prStaRec->fgIsValid = TRUE; ++ prStaRec->fgIsInPS = FALSE; ++ prStaRec->ucPsSessionID = 0xFF; ++ prStaRec->fgIsAp = (IS_AP_STA(prStaRec)) ? TRUE : FALSE; ++ ++ /* Done in qmInit() or qmDeactivateStaRec() */ ++#if 0 ++ /* At the beginning, no RX BA agreements have been established */ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) ++ (prStaRec->aprRxReorderParamRefTbl)[i] = NULL; ++#endif ++ ++ DBGLOG(QM, TRACE, "QM: +STA[%u]\n", (UINT_32) prStaRec->ucIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Deactivate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the STA_REC ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_32 i; ++ P_MSDU_INFO_T prFlushedTxPacketList = NULL; ++ ++ ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* 4<1> Flush TX queues */ ++ prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx); ++ ++ if (prFlushedTxPacketList) ++ wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList); ++ /* 4 <2> Flush RX queues and delete RX BA agreements */ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { ++ /* Delete the RX BA entry with TID = i */ ++ qmDelRxBaEntry(prAdapter, (UINT_8) u4StaRecIdx, (UINT_8) i, FALSE); ++ } ++ ++ /* 4 <3> Deactivate the STA_REC */ ++ prStaRec->fgIsValid = FALSE; ++ prStaRec->fgIsInPS = FALSE; ++ ++ /* To reduce printk for IOT sta to connect all the time, */ ++ /* DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx)); */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Deactivate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the network ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ ++ P_QUE_MGT_T prQM; ++ P_QUE_T prQue; ++ QUE_T rNeedToFreeQue; ++ QUE_T rTempQue; ++ P_QUE_T prNeedToFreeQue; ++ P_QUE_T prTempQue; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ prQM = &prAdapter->rQM; ++ prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ++ QUEUE_INITIALIZE(&rNeedToFreeQue); ++ QUEUE_INITIALIZE(&rTempQue); ++ ++ prNeedToFreeQue = &rNeedToFreeQue; ++ prTempQue = &rTempQue; ++ ++ QUEUE_MOVE_ALL(prTempQue, prQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); ++ while (prMsduInfo) { ++ ++ if (prMsduInfo->ucNetworkType == eNetworkTypeIdx) { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T) prMsduInfo); ++ } else { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); ++ } ++ if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) ++ wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush all TX queues ++* ++* \param[in] (none) ++* ++* \return The flushed packets (in a list of MSDU_INFOs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucStaArrayIdx; ++ UINT_8 ucQueArrayIdx; ++ ++ P_MSDU_INFO_T prMsduInfoListHead; ++ P_MSDU_INFO_T prMsduInfoListTail; ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushTxQueues()\n"); ++ ++ prMsduInfoListHead = NULL; ++ prMsduInfoListTail = NULL; ++ ++ /* Concatenate all MSDU_INFOs in per-STA queues */ ++ for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++) { ++ ++ /* Always check each STA_REC when flushing packets no matter it is inactive or active */ ++#if 0 ++ if (!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid) ++ continue; /* Continue to check the next STA_REC */ ++#endif ++ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { ++ if (QUEUE_IS_EMPTY(&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))) ++ continue; /* Continue to check the next TX queue of the same STA */ ++ ++ if (!prMsduInfoListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, ++ QUEUE_GET_HEAD(&prAdapter-> ++ arStaRec[ucStaArrayIdx].arTxQueue ++ [ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } ++ } ++ ++ /* Flush per-Type queues */ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++) { ++ ++ if (QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))) ++ continue; /* Continue to check the next TX queue of the same STA */ ++ ++ if (!prMsduInfoListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]); ++ ++ } ++ ++ if (prMsduInfoListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL); ++ } ++ ++ return prMsduInfoListHead; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush TX packets for a particular STA ++* ++* \param[in] u4StaRecIdx STA_REC index ++* ++* \return The flushed packets (in a list of MSDU_INFOs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) ++{ ++ UINT_8 ucQueArrayIdx; ++ P_MSDU_INFO_T prMsduInfoListHead; ++ P_MSDU_INFO_T prMsduInfoListTail; ++ P_STA_RECORD_T prStaRec; ++ ++ /* To reduce printk for IOT sta to connect all the time, */ ++ /* DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx)); */ ++ ++ ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prMsduInfoListHead = NULL; ++ prMsduInfoListTail = NULL; ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* No matter whether this is an activated STA_REC, do flush */ ++#if 0 ++ if (!prStaRec->fgIsValid) ++ return NULL; ++#endif ++ ++ /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { ++ if (QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))) ++ continue; ++ ++ if (!prMsduInfoListHead) { ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, ++ QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ ++ } ++ ++#if 0 ++ if (prMsduInfoListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx)); ++ } else { ++ prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx); ++ } ++#endif ++ ++ return prMsduInfoListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush RX packets ++* ++* \param[in] (none) ++* ++* \return The flushed packets (in a list of SW_RFBs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ P_SW_RFB_T prSwRfbListHead; ++ P_SW_RFB_T prSwRfbListTail; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ prSwRfbListHead = prSwRfbListTail = NULL; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushRxQueues()\n"); ++ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) { ++ if (!prSwRfbListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prSwRfbListHead = (P_SW_RFB_T) ++ QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue)); ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail, ++ QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue))); ++ ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); ++ } ++ ++ QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue)); ++ ++ } else { ++ continue; ++ } ++ } ++ ++ if (prSwRfbListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); ++ } ++ return prSwRfbListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush RX packets with respect to a particular STA ++* ++* \param[in] u4StaRecIdx STA_REC index ++* \param[in] u4Tid TID ++* ++* \return The flushed packets (in a list of SW_RFBs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx, IN UINT_32 u4Tid) ++{ ++ /* UINT_32 i; */ ++ P_SW_RFB_T prSwRfbListHead; ++ P_SW_RFB_T prSwRfbListTail; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ P_STA_RECORD_T prStaRec; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushStaRxQueues(%u)\n", u4StaRecIdx); ++ ++ prSwRfbListHead = prSwRfbListTail = NULL; ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* No matter whether this is an activated STA_REC, do flush */ ++#if 0 ++ if (!prStaRec->fgIsValid) ++ return NULL; ++#endif ++ ++ /* Obtain the RX BA Entry pointer */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]); ++ ++ /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */ ++ if (prReorderQueParm) { ++ ++ if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) { ++ ++ prSwRfbListHead = (P_SW_RFB_T) ++ QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue)); ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue)); ++ ++ QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue)); ++ ++ } ++ } ++ ++ if (prSwRfbListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); ++ } ++ return prSwRfbListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Enqueue TX packets ++* ++* \param[in] prMsduInfoListHead Pointer to the list of TX packets ++* ++* \return The freed packets, which are not enqueued ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfoReleaseList; ++ P_MSDU_INFO_T prCurrentMsduInfo; ++ P_MSDU_INFO_T prNextMsduInfo; ++ ++ P_STA_RECORD_T prStaRec; ++ QUE_T rNotEnqueuedQue; ++ P_QUE_T prTxQue = &rNotEnqueuedQue; ++ ++ UINT_8 ucPacketType; ++ UINT_8 ucTC; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ UINT_8 aucNextUP[WMM_AC_INDEX_NUM] = { 1 /* BEtoBK */ , 1 /*na */ , 0 /*VItoBE */ , 4 /*VOtoVI */ }; ++ ++ DBGLOG(QM, LOUD, "Enter qmEnqueueTxPackets\n"); ++ ++ ASSERT(prMsduInfoListHead); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ { ++ /* UINT_32 i; */ ++ /* 4 <0> Update TC resource control related variables */ ++ /* Keep track of the queue length */ ++ if (--prQM->u4TimeToUpdateQueLen == 0) { /* -- only here */ ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; ++ qmUpdateAverageTxQueLen(prAdapter); ++ } ++ } ++#endif ++ ++ /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */ ++ prStaRec = NULL; ++ prMsduInfoReleaseList = NULL; ++ prCurrentMsduInfo = NULL; ++ QUEUE_INITIALIZE(&rNotEnqueuedQue); ++ prNextMsduInfo = prMsduInfoListHead; ++ ++ do { ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgCheckACMAgain; ++ ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; ++ ++ prCurrentMsduInfo = prNextMsduInfo; ++ prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo); ++ ucTC = TC1_INDEX; ++ ++ /* 4 <1> Lookup the STA_REC index */ ++ /* The ucStaRecIndex will be set in this function */ ++ qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo); ++ ucPacketType = HIF_TX_PACKET_TYPE_DATA; ++ ++ STATS_ENV_REPORT_DETECT(prAdapter, prCurrentMsduInfo->ucStaRecIndex); ++ ++ DBGLOG(QM, LOUD, "***** ucStaRecIndex = %d *****\n", prCurrentMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 0) ++ if (IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) { ++#else ++ /* force to send the loopback test packet */ ++ if (1) { ++ SET_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType); ++ prCurrentMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; ++ ucPacketType = HIF_TX_PKT_TYPE_HIF_LOOPBACK; ++#endif /* End of CONF_HIF_LOOPBACK_AUTO */ ++ ++ switch (prCurrentMsduInfo->ucStaRecIndex) { ++ case STA_REC_INDEX_BMCAST: ++ prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ucTC = TC5_INDEX; ++#if 0 ++ if (prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX ++ && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT) { ++ if (LINK_IS_EMPTY ++ (&prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_P2P_INDEX].rStaRecOfClientList)) { ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_AP_BORADCAST_DROP); ++ } ++ } ++#endif ++ ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); ++ break; ++ ++ case STA_REC_INDEX_NOT_FOUND: ++ ucTC = TC5_INDEX; ++ ++ if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ ++ /* if the packet is the forward type. the packet should be freed */ ++ DBGLOG(QM, TRACE, "Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"); ++ /* prTxQue = &rNotEnqueuedQue; */ ++ } ++ prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC]; ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); ++ ++ break; ++ ++ default: ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prCurrentMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ DBGLOG(QM, ERROR, "prStaRec is NULL\n"); ++ break; ++ } ++ ASSERT(prStaRec->fgIsValid); ++ ++ if (prCurrentMsduInfo->ucUserPriority < 8) { ++ QM_DBG_CNT_INC(prQM, prCurrentMsduInfo->ucUserPriority + 15); ++ /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */ ++ /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */ ++ } ++ ++ eAci = WMM_AC_BE_INDEX; ++ do { ++ fgCheckACMAgain = FALSE; ++ if (!prStaRec->fgIsQoS) { ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ break; ++ } ++ ++ switch (prCurrentMsduInfo->ucUserPriority) { ++ case 1: ++ case 2: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC0]; ++ ucTC = TC0_INDEX; ++ eAci = WMM_AC_BK_INDEX; ++ break; ++ case 0: ++ case 3: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ eAci = WMM_AC_BE_INDEX; ++ break; ++ case 4: ++ case 5: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC2]; ++ ucTC = TC2_INDEX; ++ eAci = WMM_AC_VI_INDEX; ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ prQM->u4TxNumOfVi++; ++#endif ++ break; ++ case 6: ++ case 7: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC3]; ++ ucTC = TC3_INDEX; ++ eAci = WMM_AC_VO_INDEX; ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ prQM->u4TxNumOfVo++; ++#endif ++ break; ++ default: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ eAci = WMM_AC_BE_INDEX; ++ ASSERT(0); ++ break; ++ } ++ if (prBssInfo->arACQueParms[eAci].fgIsACMSet && eAci ++ != WMM_AC_BK_INDEX) { ++ prCurrentMsduInfo->ucUserPriority = aucNextUP[eAci]; ++ fgCheckACMAgain = TRUE; ++ } ++ } while (fgCheckACMAgain); ++ ++ /* LOG_FUNC ("QoS %u UP %u TC %u", */ ++ /* prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); */ ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ /* ++ In TDLS or AP mode, peer maybe enter "sleep mode". ++ ++ If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, ++ we need to wait 60 * u4TimeToAdjustTcResource = 180 packets ++ u4TimeToAdjustTcResource = 3, ++ then we will adjust TC resouce for VI or VO. ++ ++ But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, ++ we will to wait about 12 seconds to collect 180 packets. ++ but the test time is only 20 seconds. ++ */ ++ if ((prQM->u4TxNumOfVi == 10) || (prQM->u4TxNumOfVo == 10)) { ++ /* force to do TC resouce update */ ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN; ++ prQM->u4TimeToAdjustTcResource = 1; ++ } ++#endif ++#if ARP_MONITER_ENABLE ++ if (IS_STA_IN_AIS(prStaRec) && prCurrentMsduInfo->eSrc == TX_PACKET_OS) ++ qmDetectArpNoResponse(prAdapter, prCurrentMsduInfo); ++#endif ++ ++ break; /*default */ ++ } /* switch (prCurrentMsduInfo->ucStaRecIndex) */ ++ ++ if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ if (prTxQue->u4NumElem > 32) { ++ DBGLOG(QM, WARN, ++ "Drop the Packet for full Tx queue (forwarding) Bss %u\n", ++ prCurrentMsduInfo->ucNetworkType); ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_FORWARD_OVERFLOW_DROP); ++ } ++ } ++ ++ } else { ++ ++ DBGLOG(QM, WARN, "Drop the Packet for inactive Bss %u\n", prCurrentMsduInfo->ucNetworkType); ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); ++ } ++ ++ /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */ ++ ++ /* TODO: Fill MSDU_INFO according to the network type, ++ * EtherType, and STA status (for PS forwarding control). ++ */ ++ ++ /* Note that the Network Type Index and STA_REC index are determined in ++ * qmDetermineStaRecIndex(prCurrentMsduInfo). ++ */ ++ QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(prCurrentMsduInfo, /* MSDU_INFO ptr */ ++ ucTC, /* TC tag */ ++ ucPacketType, /* Packet Type */ ++ 0, /* Format ID */ ++ prCurrentMsduInfo->fgIs802_1x, /* Flag 802.1x */ ++ prCurrentMsduInfo->fgIs802_11, /* Flag 802.11 */ ++ 0, /* PAL LLH */ ++ 0, /* ACL SN */ ++ PS_FORWARDING_TYPE_NON_PS, /* PS Forwarding Type */ ++ 0 /* PS Session ID */ ++ ); ++ ++ /* 4 <4> Enqueue the packet to different AC queue (max 5 AC queues) */ ++ QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T) prCurrentMsduInfo); ++ ++ if (prTxQue != &rNotEnqueuedQue) { ++ prQM->u4EnqeueuCounter++; ++ prQM->au4ResourceWantedCounter[ucTC]++; ++ } ++ if (prStaRec) ++ prStaRec->u4EnqeueuCounter++; ++ ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ { ++ P_TX_CTRL_T prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] == 0) { ++ prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC]++; ++ /* ++ DBGLOG(QM, TRACE, ("TC%d Q Empty Count: [%d]%ld\n", ++ ucTC, ++ prCurrentMsduInfo->ucNetworkType, ++ prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC])); ++ */ ++ } ++ ++ } ++#endif ++ ++#if QM_TEST_MODE ++ if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) { ++ prQM->u4PktCount = 0; ++ qmTestCases(prAdapter); ++ } ++#endif ++ ++ DBGLOG(QM, LOUD, "Current queue length = %u\n", prTxQue->u4NumElem); ++ } while (prNextMsduInfo); ++ ++ if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue)) { ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL); ++ prMsduInfoReleaseList = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rNotEnqueuedQue); ++ } ++ ++ return prMsduInfoReleaseList; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Determine the STA_REC index for a packet ++* ++* \param[in] prMsduInfo Pointer to the packet ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 i; ++ ++ P_STA_RECORD_T prTempStaRec; ++ /* P_QUE_MGT_T prQM = &prAdapter->rQM; */ ++ ++ prTempStaRec = NULL; ++ ++ ASSERT(prMsduInfo); ++ ++ /* 4 <1> DA = BMCAST */ ++ if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) { ++ /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP. ++ * FW shall take care of this. The host driver is not able to distinguish these cases. */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; ++ DBGLOG(QM, LOUD, "TX with DA = BMCAST\n"); ++ return; ++ } ++#if (CFG_SUPPORT_TDLS == 1) ++ /* Check if the peer is TDLS one */ ++ if (TdlsexStaRecIdxGet(prAdapter, prMsduInfo) == TDLS_STATUS_SUCCESS) ++ return; /* find a TDLS record */ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* 4 <2> Check if an AP STA is present */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ ++ if ((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType) ++ && (prTempStaRec->fgIsAp) ++ && (prTempStaRec->fgIsValid)) { ++ prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; ++ return; ++ } ++ } ++ ++ /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if (prTempStaRec->fgIsValid) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)) { ++ prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; ++ return; ++ } ++ } ++ } ++ ++ /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ DBGLOG(QM, LOUD, "QM: TX with STA_REC_INDEX_NOT_FOUND\n"); ++ ++#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING) ++ prMsduInfo->ucStaRecIndex = (UINT_8) prQM->u4CurrentStaRecIndexToEnqueue; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets from a STA_REC for a particular TC ++* ++* \param[out] prQue The queue to put the dequeued packets ++* \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX) ++* \param[in] ucMaxNum The maximum amount of dequeued packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, ++ OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucCurrentQuota, IN UINT_8 ucTotalQuota) ++{ ++ ++#if QM_FORWARDING_FAIRNESS ++ UINT_32 i; /* Loop for */ ++ ++ PUINT_32 pu4HeadStaRecIndex; /* The Head STA index */ ++ PUINT_32 pu4HeadStaRecForwardCount; /* The total forwarded packets for the head STA */ ++ ++ P_STA_RECORD_T prStaRec; /* The current focused STA */ ++ P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */ ++ P_QUE_T prCurrQueue; /* The current TX queue to dequeue */ ++ P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */ ++ ++ UINT_32 u4ForwardCount; /* To remember the total forwarded packets for a STA */ ++ UINT_32 u4MaxForwardCount; /* The maximum number of packets a STA can forward */ ++ UINT_32 u4Resource; /* The TX resource amount */ ++ ++ BOOLEAN fgChangeHeadSta; /* Whether a new head STA shall be determined at the end of the function */ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ PUINT_8 pucFreeQuota = NULL; ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ /*NFC Beam + Indication */ ++#endif ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); ++ ++ ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); ++ ++ if (!ucCurrentQuota) { ++ prQM->au4DequeueNoTcResourceCounter[ucTC]++; ++ DBGLOG(TX, LOUD, "@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n", ucTC, ucCurrentQuota); ++ return; ++ } ++ ++ u4Resource = ucCurrentQuota; ++ ++ /* 4 <1> Determine the head STA */ ++ /* The head STA shall be an active STA */ ++ ++ pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]); ++ pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]); ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Init Head STA = %u Resource = %u\n", ++ ucTC, *pu4HeadStaRecIndex, u4Resource); ++ ++ /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD + 1; i++) { ++ prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)]; ++ ASSERT(prStaRec); ++ ++ /* Only Data frame (1x was not included) will be queued in */ ++ if (prStaRec->fgIsValid) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ ++ /* Determine how many packets the head STA is allowed to send in a round */ ++ ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25); ++ u4MaxForwardCount = ucTotalQuota; ++#if CFG_ENABLE_WIFI_DIRECT ++ ++ pucFreeQuota = NULL; ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ ++ /* u4MaxForwardCount = ucTotalQuota; */ ++ /* Per STA flow control when STA in PS mode */ ++ /* The PHASE 1: only update from ucFreeQuota (now) */ ++ /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ ++ /* aucFreeQuotaPerQueue[] */ ++ /* NOTE: other method to set u4Resource */ ++ ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ ++ if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; ++ } else { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } else { ++ ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } /* fgIsInPS */ ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++ /*NFC Beam + Indication */ ++ ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ if ((prChnlReqInfo->NFC_BEAM != 1) && ++ (u4MaxForwardCount > prBssInfo->ucBssFreeQuota)) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } else { ++ if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* Determine whether the head STA can continue to forward packets in this round */ ++ if ((*pu4HeadStaRecForwardCount) < u4MaxForwardCount) ++ break; ++ ++ } /* prStaRec->fgIsValid */ ++ else { ++ /* The current Head STA has been deactivated, so search for a new head STA */ ++ prStaRec = NULL; ++ prBssInfo = NULL; ++ (*pu4HeadStaRecIndex)++; ++ (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; ++ ++ /* Reset the forwarding count before searching (since this is for a new selected STA) */ ++ (*pu4HeadStaRecForwardCount) = 0; ++ } ++ } /* i < CFG_NUM_OF_STA_RECORD + 1 */ ++ ++ /* All STA_RECs are inactive, so exit */ ++ if (!prStaRec) { ++ /* Under concurrent, it is possible that there is no candidcated STA. */ ++ /* DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); */ ++ return; ++ } ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Round Head STA = %u\n", ucTC, *pu4HeadStaRecIndex); ++ ++ /* 4 <2> Dequeue packets from the head STA */ ++ ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ prDequeuedPkt = NULL; ++ fgChangeHeadSta = FALSE; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ if (pucFreeQuota != NULL) ++ TdlsexTxQuotaCheck(prAdapter->prGlueInfo, prStaRec, *pucFreeQuota); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ while (prCurrQueue) { ++ ++#if QM_DEBUG_COUNTER ++ ++ if (ucTC <= TC4_INDEX) { ++ if (QUEUE_IS_EMPTY(prCurrQueue)) { ++ QM_DBG_CNT_INC(prQM, ucTC); ++ /* QM_DBG_CNT_00 *//* QM_DBG_CNT_01 *//* QM_DBG_CNT_02 */ ++ /* QM_DBG_CNT_03 *//* QM_DBG_CNT_04 */ ++ } ++ if (u4Resource == 0) { ++ QM_DBG_CNT_INC(prQM, ucTC + 5); ++ /* QM_DBG_CNT_05 *//* QM_DBG_CNT_06 *//* QM_DBG_CNT_07 */ ++ /* QM_DBG_CNT_08 *//* QM_DBG_CNT_09 */ ++ } ++ if (((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { ++ QM_DBG_CNT_INC(prQM, ucTC + 10); ++ /* QM_DBG_CNT_10 *//* QM_DBG_CNT_11 *//* QM_DBG_CNT_12 */ ++ /* QM_DBG_CNT_13 *//* QM_DBG_CNT_14 */ ++ } ++ } ++#endif ++ ++ /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ ++ if (QUEUE_IS_EMPTY(prCurrQueue) || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { ++ fgChangeHeadSta = TRUE; ++ break; ++ } else if (u4Resource == 0) { ++#if (CFG_SUPPORT_STATISTICS == 1) ++ prStaRec->u4NumOfNoTxQuota++; ++#endif /* CFG_SUPPORT_STATISTICS */ ++ break; ++ } ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ prStaRec->u4DeqeueuCounter++; ++ prQM->u4DequeueCounter++; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ if (prDequeuedPkt != NULL) { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(QM, LOUD, " %d\n", u2Identifier); ++ } ++ } ++#endif ++#if DBG && 0 ++ LOG_FUNC("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, ++ prCurrQueue->u4NumElem, ++ prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, ++ prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ if (!QUEUE_IS_EMPTY(prCurrQueue)) { ++ /* XXX: check all queues for STA */ ++ prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; ++ } ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ u4Resource--; ++ (*pu4HeadStaRecForwardCount)++; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ if ((pucFreeQuota) && (*pucFreeQuota > 0)) ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->ucBssFreeQuota > 0) ++ prBssInfo->ucBssFreeQuota--; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ } ++ ++ if (*pu4HeadStaRecForwardCount) { ++ DBGLOG(QM, LOUD, ++ "TC = %u Round Head STA = %u, u4HeadStaRecForwardCount = %u\n", ucTC, *pu4HeadStaRecIndex, ++ (*pu4HeadStaRecForwardCount)); ++ } ++#if QM_BURST_END_INFO_ENABLED ++ /* Let FW know which packet is the last one dequeued from the STA */ ++ if (prDequeuedPkt) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ ++ /* 4 <3> Dequeue from the other STAs if there is residual TX resource */ ++ ++ /* Check all of the STAs to continue forwarding packets (including the head STA) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ /* Break in case no reasource is available */ ++ if (u4Resource == 0) { ++ prQM->au4DequeueNoTcResourceCounter[ucTC]++; ++ break; ++ } ++ ++ /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */ ++ prStaRec = &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD]; ++ ASSERT(prStaRec); ++ ++ if (prStaRec->fgIsValid) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Sharing STA = %u Resource = %u\n", ++ ucTC, prStaRec->ucIndex, u4Resource); ++ ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ u4ForwardCount = 0; ++ u4MaxForwardCount = ucTotalQuota; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ pucFreeQuota = NULL; ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ ++ /* u4MaxForwardCount = ucTotalQuota; */ ++ /* Per STA flow control when STA in PS mode */ ++ /* The PHASE 1: only update from ucFreeQuota (now) */ ++ /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ ++ /* aucFreeQuotaPerQueue[] */ ++ /* NOTE: other method to set u4Resource */ ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ ++ if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; ++ } else { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } else { ++ ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ } /* prStaRec->fgIsValid */ ++ else { ++ prBssInfo = NULL; ++ /* Invalid STA, so check the next STA */ ++ continue; ++ } ++ ++ while (prCurrQueue) { ++ /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ ++ if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue) || (u4ForwardCount >= u4MaxForwardCount)) ++ break; ++ ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ ++#if DBG && 0 ++ DBGLOG(QM, LOUD, "Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, ++ prCurrQueue->u4NumElem, ++ prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, ++ prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, ++ prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11)); ++ ++ DBGLOG(QM, LOUD, "Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ if (!QUEUE_IS_EMPTY(prCurrQueue)) ++ /* more data field ? */ ++ prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ if (prStaRec) ++ prStaRec->u4DeqeueuCounter++; ++ prQM->u4DequeueCounter++; ++ u4Resource--; ++ u4ForwardCount++; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ ASSERT(pucFreeQuota); ++ ASSERT(*pucFreeQuota > 0); ++ if (*pucFreeQuota > 0) ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->ucBssFreeQuota > 0) ++ prBssInfo->ucBssFreeQuota--; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ } ++ ++#if QM_BURST_END_INFO_ENABLED ++ /* Let FW know which packet is the last one dequeued from the STA */ ++ if (u4ForwardCount) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ } ++ ++ if (fgChangeHeadSta) { ++ (*pu4HeadStaRecIndex)++; ++ (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; ++ (*pu4HeadStaRecForwardCount) = 0; ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Scheduled Head STA = %u Left Resource = %u\n", ++ ucTC, (*pu4HeadStaRecIndex), u4Resource); ++ } ++ ++/***************************************************************************************/ ++#else ++ UINT_8 ucStaRecIndex; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_T prCurrQueue; ++ UINT_8 ucPktCount; ++ P_MSDU_INFO_T prDequeuedPkt; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); ++ ++ if (ucCurrentQuota == 0) ++ return; ++ /* 4 <1> Determine the queue index and the head STA */ ++ ++ /* The head STA */ ++ ucStaRecIndex = 0; /* TODO: Get the current head STA */ ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ /* The queue to pull out packets */ ++ ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ ++ ucPktCount = ucCurrentQuota; ++ prDequeuedPkt = NULL; ++ ++ /* 4 <2> Dequeue packets for the head STA */ ++ while (TRUE) { ++ if (!(prStaRec->fgIsValid) || ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) { ++ break; ++ ++ } else { ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ /* DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); */ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ ucPktCount--; ++ } ++ } ++ ++ /* DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); */ ++ ++#if QM_BURST_END_INFO_ENABLED ++ if (prDequeuedPkt) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ ++ /* 4 <3> Update scheduling info */ ++ /* TODO */ ++ ++ /* 4 <4> Utilize the remainaing TX opportunities for non-head STAs */ ++ /* TODO */ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets from a per-Type-based Queue for a particular TC ++* ++* \param[out] prQue The queue to put the dequeued packets ++* \param[in] ucTC The TC index (Shall always be TC5_INDEX) ++* \param[in] ucMaxNum The maximum amount of dequeued packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum) ++{ ++ /* UINT_8 ucQueIndex; */ ++ /* UINT_8 ucStaRecIndex; */ ++ P_BSS_INFO_T prBssInfo; ++ P_BSS_INFO_T parBssInfo; ++ P_QUE_T prCurrQueue; ++ UINT_8 ucPktCount; ++ P_MSDU_INFO_T prDequeuedPkt; ++ P_MSDU_INFO_T prBurstEndPkt; ++ QUE_T rMergeQue; ++ P_QUE_T prMergeQue; ++ P_QUE_MGT_T prQM; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum); ++ ++ /* TC5: Broadcast/Multicast data packets */ ++ ASSERT(ucTC == TC5_INDEX); ++ ++ if (ucMaxNum == 0) ++ return; ++ ++ prQM = &prAdapter->rQM; ++ /* 4 <1> Determine the queue */ ++ ++ prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ucPktCount = ucMaxNum; ++ prDequeuedPkt = NULL; ++ prBurstEndPkt = NULL; ++ ++ parBssInfo = prAdapter->rWifiVar.arBssInfo; ++ ++ QUEUE_INITIALIZE(&rMergeQue); ++ prMergeQue = &rMergeQue; ++ ++ /* 4 <2> Dequeue packets */ ++ while (TRUE) { ++ if (ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) ++ break; ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo)) { ++ if (!prBssInfo->fgIsNetAbsent) { ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ prQM->u4DequeueCounter++; ++ prBurstEndPkt = prDequeuedPkt; ++ ucPktCount--; ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26); ++#if DBG && 0 ++ LOG_FUNC ++ ("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, prCurrQueue->u4NumElem, prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, ++ prDequeuedPkt->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ } else { ++ QUEUE_INSERT_TAIL(prMergeQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ } ++ } else { ++ QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL); ++ wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt); ++ } ++ } ++ ++ if (QUEUE_IS_NOT_EMPTY(prMergeQue)) { ++ QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue); ++ QUEUE_MOVE_ALL(prCurrQueue, prMergeQue); ++ if (QUEUE_GET_TAIL(prCurrQueue)) ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(prCurrQueue), NULL); ++ } ++#if QM_BURST_END_INFO_ENABLED ++ if (prBurstEndPkt) ++ prBurstEndPkt->fgIsBurstEnd = TRUE; ++#endif ++} /* qmDequeueTxPacketsFromPerTypeQueues */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets to send to HIF TX ++* ++* \param[in] prTcqStatus Info about the maximum amount of dequeued packets ++* ++* \return The list of dequeued TX packets ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus) ++{ ++ ++ INT32 i; ++ P_MSDU_INFO_T prReturnedPacketListHead; ++ QUE_T rReturnedQue; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPackets\n"); ++ ++ QUEUE_INITIALIZE(&rReturnedQue); ++ ++ prReturnedPacketListHead = NULL; ++ ++ /* dequeue packets from different AC queue based on available aucFreeBufferCount */ ++ /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */ ++ for (i = TC4_INDEX; i >= TC0_INDEX; i--) { ++ DBGLOG(QM, LOUD, "Dequeue packets from Per-STA queue[%d]\n", i); ++ ++ /* ++ in the function, we will re-calculate the ucFreeQuota. ++ If any packet with any priority for the station will be sent, ucFreeQuota -- ++ ++ Note1: ucFreeQuota will be decrease only when station is in power save mode. ++ In active mode, we will sent the packet to the air directly. ++ ++ if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { ++ ASSERT(pucFreeQuota); ++ ASSERT(*pucFreeQuota>0); ++ if ((pucFreeQuota) && (*pucFreeQuota>0)) { ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++ } ++ ++ Note2: maximum queued number for a station is 10, TXM_MAX_BUFFER_PER_STA_DEF in fw ++ i.e. default prStaRec->ucFreeQuota = 10 ++ ++ Note3: In qmUpdateFreeQuota(), we will adjust ++ ucFreeQuotaForNonDelivery = ucFreeQuota>>1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ */ ++ qmDequeueTxPacketsFromPerStaQueues(prAdapter, ++ &rReturnedQue, ++ (UINT_8) i, ++ prTcqStatus->aucFreeBufferCount[i], /* maximum dequeue number */ ++ prTcqStatus->aucMaxNumOfBuffer[i]); ++ ++ /* The aggregate number of dequeued packets */ ++ DBGLOG(QM, LOUD, "DQA)[%u](%u)\n", i, rReturnedQue.u4NumElem); ++ } ++ ++ /* TC5 (BMCAST or STA-NOT-FOUND packets) */ ++ qmDequeueTxPacketsFromPerTypeQueues(prAdapter, ++ &rReturnedQue, TC5_INDEX, prTcqStatus->aucFreeBufferCount[TC5_INDEX] ++ ); ++ ++ DBGLOG(QM, LOUD, "Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem); ++ ++ if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) { ++ prReturnedPacketListHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rReturnedQue); ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); ++ } ++ ++ return prReturnedPacketListHead; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Adjust the TC quotas according to traffic demands ++* ++* \param[out] prTcqAdjust The resulting adjustment ++* \param[in] prTcqStatus Info about the current TC quotas and counters ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus) ++{ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ UINT_32 i; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* Must reset */ ++ for (i = 0; i < TC_NUM; i++) ++ prTcqAdjust->acVariation[i] = 0; ++ ++ /* 4 <1> If TC resource is not just adjusted, exit directly */ ++ if (!prQM->fgTcResourcePostAnnealing) ++ return; ++ /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */ ++ else { ++ INT_32 i4TotalExtraQuota = 0; ++ INT_32 ai4ExtraQuota[TC_NUM]; ++ BOOLEAN fgResourceRedistributed = TRUE; ++ ++ /* Obtain the free-to-distribute resource */ ++ for (i = 0; i < TC_NUM; i++) { ++ ai4ExtraQuota[i] = ++ (INT_32) prTcqStatus->aucMaxNumOfBuffer[i] - (INT_32) prQM->au4CurrentTcResource[i]; ++ ++ if (ai4ExtraQuota[i] > 0) { /* The resource shall be reallocated to other TCs */ ++ ++ if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]) { ++ /* ++ we have residunt TC resources for the TC: ++ EX: aucMaxNumOfBuffer[] = 20, au4CurrentTcResource[] = 5 ++ ai4ExtraQuota[] = 15, aucFreeBufferCount[] = 10 ++ ++ so ai4ExtraQuota[] = aucFreeBufferCount[] = 10 ++ because we available TC resources actually is 10, not 20 ++ */ ++ ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i]; ++ ++ /* ++ FALSE means we can re-do TC resource adjustment in tx done ++ at next time, maybe more tx done is finished ++ */ ++ fgResourceRedistributed = FALSE; ++ } ++ ++ /* accumulate current all available TC resources */ ++ i4TotalExtraQuota += ai4ExtraQuota[i]; ++ ++ /* deduce unused TC resources for the TC */ ++ prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); ++ } ++ } ++ ++ /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */ ++ for (i = 0; i < TC_NUM; i++) { ++ if (ai4ExtraQuota[i] < 0) { ++ ++ /* The TC needs extra resources */ ++ if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) { ++ /* the number of needed extra resources is larger than total available */ ++ ai4ExtraQuota[i] = (-i4TotalExtraQuota); ++ ++ /* wait for next tx done to do adjustment */ ++ fgResourceRedistributed = FALSE; ++ } ++ ++ /* decrease the total available */ ++ i4TotalExtraQuota += ai4ExtraQuota[i]; ++ ++ /* mark to increase TC resources for the TC */ ++ prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); ++ } ++ } ++ ++ /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */ ++ ++ /* ++ if fgResourceRedistributed == TRUE, it means we will adjust at this time so ++ we need to re-adjust TC resources (fgTcResourcePostAnnealing = FALSE). ++ */ ++ prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); ++ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ DBGLOG(QM, LOUD, "QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n", ++ prTcqStatus->aucFreeBufferCount[0], ++ prTcqStatus->aucFreeBufferCount[1], ++ prTcqStatus->aucFreeBufferCount[2], ++ prTcqStatus->aucFreeBufferCount[3], ++ prTcqStatus->aucFreeBufferCount[4], prTcqStatus->aucFreeBufferCount[5] ++ )); ++#endif ++ } ++ ++#else ++ UINT_32 i; ++ ++ for (i = 0; i < TC_NUM; i++) ++ prTcqAdjust->acVariation[i] = 0; ++ ++#endif ++} ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update the average TX queue length for the TC resource control mechanism ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter) ++{ ++ INT_32 u4CurrQueLen, i, k; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ ++ /* use moving average algorithm to calculate au4AverageQueLen for every TC queue */ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++) { ++ u4CurrQueLen = 0; ++ ++ for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++) { ++ prStaRec = &prAdapter->arStaRec[k]; ++ ASSERT(prStaRec); ++ ++ /* If the STA is activated, get the queue length */ ++ if (prStaRec->fgIsValid && ++ (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent) ++ ) { ++ ++ u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem); ++ } ++ } ++ ++ if (prQM->au4AverageQueLen[i] == 0) { ++ prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); /* *8 */ ++ } else { ++ /* len => len - len/8 = 7/8 * len + new len */ ++ prQM->au4AverageQueLen[i] -= (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR); ++ prQM->au4AverageQueLen[i] += (u4CurrQueLen); ++ } ++ ++ } ++ ++ /* Update the queue length for TC5 (BMCAST) */ ++ u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem; ++ ++ if (prQM->au4AverageQueLen[TC_NUM - 1] == 0) { ++ prQM->au4AverageQueLen[TC_NUM - 1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); ++ } else { ++ prQM->au4AverageQueLen[TC_NUM - 1] -= ++ (prQM->au4AverageQueLen[TC_NUM - 1] >> QM_QUE_LEN_MOVING_AVE_FACTOR); ++ prQM->au4AverageQueLen[TC_NUM - 1] += (u4CurrQueLen); ++ } ++ ++ /* 4 <2> Adjust TC resource assignment every 3 times */ ++ /* Check whether it is time to adjust the TC resource assignment */ ++ if (--prQM->u4TimeToAdjustTcResource == 0) { /* u4TimeToAdjustTcResource = 3 */ ++ ++ /* The last assignment has not been completely applied */ ++ if (prQM->fgTcResourcePostAnnealing) { ++ /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */ ++ ++ /* wait for next time to do qmReassignTcResource */ ++ prQM->u4TimeToAdjustTcResource = 1; ++ } else { /* The last assignment has been applied */ ++ prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; ++ qmReassignTcResource(prAdapter); ++ } ++ } ++ ++ /* Debug */ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ for (i = 0; i < TC_NUM; i++) { ++ if (QM_GET_TX_QUEUE_LEN(prAdapter, i) >= 100) { ++ DBGLOG(QM, LOUD, "QM: QueLen [%u %u %u %u %u %u]\n", ++ QM_GET_TX_QUEUE_LEN(prAdapter, 0), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 1), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 2), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 3), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 4), QM_GET_TX_QUEUE_LEN(prAdapter, 5) ++ )); ++ break; ++ } ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Assign TX resource for each TC according to TX queue length and current assignment ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter) ++{ ++ INT_32 i4TotalResourceDemand = 0; ++ UINT_32 u4ResidualResource = 0; ++ UINT_32 i; ++ INT_32 ai4PerTcResourceDemand[TC_NUM]; ++ UINT_32 u4ShareCount = 0; ++ UINT_32 u4Share = 0; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to ++ * start the TC-quota adjusting procedure, which will be invoked upon every TX Done ++ */ ++ /* tx done -> nicProcessTxInterrupt() -> nicTxAdjustTcq() ++ * -> qmAdjustTcQuotas() -> check fgTcResourcePostAnnealing */ ++ ++ /* 4 <1> Determine the demands */ ++ /* Determine the amount of extra resource to fulfill all of the demands */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4, which is not adjustable */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* ++ Define: extra_demand = average que_length (includes all station records) + ++ min_reserved_quota - ++ current available TC resources ++ ++ extra_demand means we need extra TC resources to transmit; other TCs can ++ borrow their resources to us? ++ */ ++ ai4PerTcResourceDemand[i] = ++ ((UINT_32) (QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ++ /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */ ++ if (QM_GET_TX_QUEUE_LEN(prAdapter, i)) ++ ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY; /* 0 */ ++ ++ /* ++ accumulate all needed extra TC resources ++ maybe someone need + resource, maybe someone need - resource ++ */ ++ i4TotalResourceDemand += ai4PerTcResourceDemand[i]; ++ } ++ ++ /* 4 <2> Case 1: Demand <= Total Resource */ ++ if (i4TotalResourceDemand <= 0) { ++ /* 4 <2.1> Satisfy every TC */ ++ /* total TC resources are enough, no extra TC resources is needed */ ++ ++ /* adjust used TC resources to average TC resources + min reserve TC resources */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* ++ the number of resources that one TC releases can be used for ++ other TCs ++ ++ EX: TC0 au4CurrentTcResource[0] = 10 ai4PerTcResourceDemand[0] = -5 ++ TC1 au4CurrentTcResource[1] = 5 ai4PerTcResourceDemand[0] = +5 ++ => TC0 au4CurrentTcResource[0] = 10 + (-5) = 5 ++ TC1 au4CurrentTcResource[1] = 5 + (+5) = 10 ++ */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ } ++ ++ /* 4 <2.2> Share the residual resource evenly */ ++ u4ShareCount = (TC_NUM - 1); /* 5, excluding TC4 */ ++ ++ /* ++ EX: i4TotalResourceDemand = -10 ++ means we have 10 available resources can be used. ++ */ ++ u4ResidualResource = (UINT_32) (-i4TotalResourceDemand); ++ u4Share = (u4ResidualResource / u4ShareCount); ++ ++ /* share available TC resources to all TCs averagely */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* allocate residual average resources to the TC */ ++ prQM->au4CurrentTcResource[i] += u4Share; ++ ++ /* Every TC is fully satisfied so no need extra resources */ ++ ai4PerTcResourceDemand[i] = 0; ++ ++ /* decrease the allocated resources */ ++ u4ResidualResource -= u4Share; ++ } ++ ++ /* if still have available resources, we decide to give them to VO (TC3) queue */ ++ /* 4 <2.3> Allocate the left resource to TC3 (VO) */ ++ prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource); ++ ++ } ++ /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */ ++ else { ++ /* ++ u4ResidualResource means we at least need to keep ++ QM_INITIAL_RESIDUAL_TC_RESOURCE available TC resources ++ ++ in 6628, u4ResidualResource = 26, max 28 ++ */ ++ u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE; ++ ++ /* 4 <3.1> Allocated resource amount = minimum of (guaranteed, total demand) */ ++ for (i = 0; i < TC_NUM; i++) { ++ ++ if (i == TC4_INDEX) ++ continue; /* Skip TC4 (not adjustable) */ ++ ++ /* The demand can be fulfilled with the guaranteed resource amount 4 4 6 6 2 4 */ ++ ++ /* ++ ai4PerTcResourceDemand[i] = ++ ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] - ++ prQM->au4CurrentTcResource[i]); ++ ++ so au4CurrentTcResource + ai4PerTcResourceDemand = ++ ++ ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] = ++ ++ current average queue len + min TC resources ++ */ ++ if (prQM->au4CurrentTcResource[i] + ai4PerTcResourceDemand[i] < ++ prQM->au4GuaranteedTcResource[i]) { ++ ++ /* avg queue len + min reserve still smaller than guarantee so enough */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ ++ /* accumulate available TC resources from the TC */ ++ u4ResidualResource += ++ (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ai4PerTcResourceDemand[i] = 0; ++ } ++ ++ /* The demand can not be fulfilled with the guaranteed resource amount */ ++ else { ++ ++ /* means even we use all guarantee resources for the TC is still not enough */ ++ ++ /* ++ guarantee number is always for the TC so extra resource number cannot ++ include the guarantee number. ++ ++ EX: au4GuaranteedTcResource = 10, au4CurrentTcResource = 5 ++ ai4PerTcResourceDemand = 6 ++ ++ ai4PerTcResourceDemand -= (10 - 5) ==> 1 ++ only need extra 1 TC resouce is enough. ++ */ ++ ai4PerTcResourceDemand[i] -= ++ (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ++ /* update current avg TC resource to guarantee number */ ++ prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i]; ++ ++ /* count how many TC queues need to get extra resources */ ++ u4ShareCount++; ++ } ++ } ++ ++ /* 4 <3.2> Allocate the residual resource */ ++ do { ++ /* If there is no resource left, exit directly */ ++ if (u4ResidualResource == 0) ++ break; ++ ++ /* This shall not happen */ ++ if (u4ShareCount == 0) { ++ prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource; ++ DBGLOG(QM, ERROR, "QM: (Error) u4ShareCount = 0\n"); ++ break; ++ } ++ ++ /* Share the residual resource evenly */ ++ u4Share = (u4ResidualResource / u4ShareCount); ++ ++ if (u4Share) { ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ if (ai4PerTcResourceDemand[i] == 0) ++ continue; ++ ++ if (ai4PerTcResourceDemand[i] - u4Share) { ++ /* still not enough but we just can give it u4Share resources */ ++ prQM->au4CurrentTcResource[i] += u4Share; ++ u4ResidualResource -= u4Share; ++ ai4PerTcResourceDemand[i] -= u4Share; ++ } else { ++ /* enough */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ u4ResidualResource -= ai4PerTcResourceDemand[i]; ++ ai4PerTcResourceDemand[i] = 0; ++ } ++ } ++ } ++ ++ if (u4ResidualResource == 0) ++ break; ++ /* By priority, allocate the left resource that is not divisible by u4Share */ ++ ++ if (ai4PerTcResourceDemand[TC3_INDEX]) { /* VO */ ++ prQM->au4CurrentTcResource[TC3_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC2_INDEX]) { /* VI */ ++ prQM->au4CurrentTcResource[TC2_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC5_INDEX]) { /* BMCAST */ ++ prQM->au4CurrentTcResource[TC5_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC1_INDEX]) { /* BE */ ++ prQM->au4CurrentTcResource[TC1_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC0_INDEX]) { /* BK */ ++ prQM->au4CurrentTcResource[TC0_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ /* Allocate the left resource */ ++ prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource; ++ ++ } while (FALSE); ++ } ++ ++ /* mark the flag that we can start to do TC resource adjustment after TX done handle */ ++ prQM->fgTcResourcePostAnnealing = TRUE; ++ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ /* Debug print */ ++ DBGLOG(QM, LOUD, "QM: TC Rsc %u %u %u %u %u %u\n", ++ prQM->au4CurrentTcResource[0], ++ prQM->au4CurrentTcResource[1], ++ prQM->au4CurrentTcResource[2], ++ prQM->au4CurrentTcResource[3], prQM->au4CurrentTcResource[4], prQM->au4CurrentTcResource[5] ++ )); ++#endif ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* RX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init Queue Management for RX ++* ++* \param[in] (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */ ++ /* TODO */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle RX packets (buffer reordering) ++* ++* \param[in] prSwRfbListHead The list of RX packets ++* ++* \return The list of packets which are not buffered for reordering ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) ++{ ++ ++#if CFG_RX_REORDERING_ENABLED ++ /* UINT_32 i; */ ++ P_SW_RFB_T prCurrSwRfb; ++ P_SW_RFB_T prNextSwRfb; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ QUE_T rReturnedQue; ++ PUINT_8 pucEthDestAddr; ++ BOOLEAN fgIsBMC; ++ ++ /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ ++ ++ DEBUGFUNC("qmHandleRxPackets"); ++ ++ ASSERT(prSwRfbListHead); ++ ++ QUEUE_INITIALIZE(&rReturnedQue); ++ prNextSwRfb = prSwRfbListHead; ++ ++ do { ++ prCurrSwRfb = prNextSwRfb; ++ prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb); ++ ++ prHifRxHdr = prCurrSwRfb->prHifRxHdr; /* TODO: (Tehuang) Use macro to obtain the pointer */ ++ ++ /* TODO: (Tehuang) Check if relaying */ ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST; ++ ++ /* Decide the Destination */ ++#if CFG_RX_PKTS_DUMP ++ if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) { ++ DBGLOG(SW4, INFO, "QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", ++ (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), ++ prHifRxHdr->ucStaRecIdx, prCurrSwRfb->ucWlanIdx, ++ (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */ ++ (UINT_32) HIF_RX_HDR_GET_TID(prHifRxHdr), ++ prCurrSwRfb->ucPacketType, ++ (UINT_32) HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); ++ ++ DBGLOG_MEM8(SW4, TRACE, (PUINT_8) prCurrSwRfb->pvHeader, prCurrSwRfb->u2PacketLen); ++ } ++#endif ++ ++ fgIsBMC = FALSE; ++ if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { ++ ++ UINT_8 ucNetTypeIdx; ++ P_BSS_INFO_T prBssInfo; ++ ++ pucEthDestAddr = prCurrSwRfb->pvHeader; ++ ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); ++ /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */ ++ /* */ ++ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) ++ fgIsBMC = TRUE; ++ ++ if (prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem > ++ (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM)) { ++ ++ if (!IS_BSS_ACTIVE(prBssInfo)) { ++ DBGLOG(QM, WARN, "Mark NULL the Packet for inactive Bss %u\n", ucNetTypeIdx); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ ++ if (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) { ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; ++ else if (UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr, pucEthDestAddr) && ++ bssGetClientByAddress(prBssInfo, pucEthDestAddr)) ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD; ++ /* TODO : need to check the dst mac is valid */ ++ /* If src mac is invalid, the packet will be freed in fw */ ++ } /* OP_MODE_ACCESS_POINT */ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ else if (hs20IsFrameFilterEnabled(prAdapter, prBssInfo) && ++ hs20IsUnsecuredFrame(prAdapter, prBssInfo, prCurrSwRfb)) { ++ DBGLOG(QM, WARN, ++ "Mark NULL the Packet for Dropped Packet %u\n", ucNetTypeIdx); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++#endif ++ } else { ++ /* Dont not occupy other SW RFB */ ++ DBGLOG(QM, WARN, "Mark NULL the Packet for less Free Sw Rfb\n"); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ ++ } ++#if CFG_SUPPORT_WAPI ++ if (prCurrSwRfb->u2PacketLen > ETHER_HEADER_LEN) { ++ PUINT_8 pc = (PUINT_8) prCurrSwRfb->pvHeader; ++ UINT_16 u2Etype = 0; ++ ++ u2Etype = (pc[ETH_TYPE_LEN_OFFSET] << 8) | (pc[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ /* for wapi integrity test. WPI_1x packet should be always in non-encrypted mode. ++ if we received any WPI(0x88b4) packet that is encrypted, drop here. */ ++ if (u2Etype == ETH_WPI_1X && HIF_RX_HDR_GET_SEC_MODE(prHifRxHdr) != 0) { ++ DBGLOG(QM, INFO, "drop wpi packet with sec mode\n"); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ } ++#endif ++ /* BAR frame */ ++ if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue); ++ } ++ /* Reordering is not required for this packet, return it without buffering */ ++ else if (!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr) || fgIsBMC) { ++#if 0 ++ if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { ++ UINT_8 ucNetTypeIdx; ++ P_BSS_INFO_T prBssInfo; ++ ++ pucEthDestAddr = prCurrSwRfb->pvHeader; ++ ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); ++ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) ++ && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)) { ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; ++ } ++ } ++#endif ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ } ++ /* Reordering is required for this packet */ ++ else { ++ /* If this packet should dropped or indicated to the host immediately, ++ * it should be enqueued into the rReturnedQue with specific flags. If ++ * this packet should be buffered for reordering, it should be enqueued ++ * into the reordering queue in the STA_REC rather than into the ++ * rReturnedQue. ++ */ ++ qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue); ++ ++ } ++ } while (prNextSwRfb); ++ ++ /* RX_PKT_DESTINATION_HOST_WITH_FORWARD or RX_PKT_DESTINATION_FORWARD */ ++ /* The returned list of SW_RFBs must end with a NULL pointer */ ++ if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) ++ QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); ++ ++ return (P_SW_RFB_T) QUEUE_GET_HEAD(&rReturnedQue); ++ ++#else ++ ++ /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ ++ return prSwRfbListHead; ++ ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reorder the received packet ++* ++* \param[in] prSwRfb The RX packet to process ++* \param[out] prReturnedQue The queue for indicating packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ ++ UINT_32 u4SeqNo; ++ UINT_32 u4WinStart; ++ UINT_32 u4WinEnd; ++ P_QUE_T prReorderQue; ++ /* P_SW_RFB_T prReorderedSwRfb; */ ++ BOOLEAN fgIsBaTimeout; ++ ++ DEBUGFUNC("qmProcessPktWithReordering"); ++ ++ if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; ++ prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */ ++ prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ ++ ++ /* Incorrect STA_REC index */ ++ if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Check whether the STA_REC is activated */ ++ prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++#endif ++ ++ /* Check whether the BA agreement exists */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); ++ if (!prReorderQueParm) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for a NULL ReorderQueParm\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Start to reorder packets */ ++ u4SeqNo = (UINT_32) (prSwRfb->u2SSN); ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); ++ u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); ++ ++ /* Debug */ ++ /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ ++ /* Case 1: Fall within */ ++ if /* 0 - start - sn - end - 4095 */ ++ (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd)) ++ /* 0 - end - start - sn - 4095 */ ++ || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo)) ++ /* 0 - sn - end - start - 4095 */ ++ || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) { ++ ++ qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) { ++ /* Let the first received packet pass the reorder check */ ++ DBGLOG(QM, LOUD, "QM:(A)[%d](%u){%u,%u}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); ++ ++ prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo; ++ prReorderQueParm->u2WinEnd = ++ ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; ++ prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; ++ } ++#endif ++ ++ if (qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue, &fgIsBaTimeout) == FALSE) ++ STATS_RX_REORDER_HOLE_INC(prStaRec); /* record hole count */ ++ STATS_RX_REORDER_HOLE_TIMEOUT_INC(prStaRec, fgIsBaTimeout); ++ } ++ /* Case 2: Fall ahead */ ++ else if ++ /* 0 - start - end - sn - (start+2048) - 4095 */ ++ (((u4WinStart < u4WinEnd) ++ && (u4WinEnd < u4SeqNo) ++ && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT))) ++ /* 0 - sn - (start+2048) - start - end - 4095 */ ++ || ((u4SeqNo < u4WinStart) ++ && (u4WinStart < u4WinEnd) ++ && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT))) ++ /* 0 - end - sn - (start+2048) - start - 4095 */ ++ || ((u4WinEnd < u4SeqNo) ++ && (u4SeqNo < u4WinStart) ++ && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) { ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) ++ prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; ++#endif ++ ++ qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); ++ ++ /* Advance the window after inserting a new tail */ ++ prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo; ++ prReorderQueParm->u2WinStart = ++ (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1) ++ % MAX_SEQ_NO_COUNT); ++ ++ qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); ++ ++ STATS_RX_REORDER_FALL_AHEAD_INC(prStaRec); ++ ++ } ++ /* Case 3: Fall behind */ ++ else { ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++#if QM_RX_INIT_FALL_BEHIND_PASS ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) { ++ /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ return; ++ } ++#endif ++#endif ++ ++ STATS_RX_REORDER_FALL_BEHIND_INC(prStaRec); ++ /* An erroneous packet */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ return; ++ } ++ ++ return; ++ ++} ++ ++VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ ++ UINT_32 u4SSN; ++ UINT_32 u4WinStart; ++ UINT_32 u4WinEnd; ++ P_QUE_T prReorderQue; ++ /* P_SW_RFB_T prReorderedSwRfb; */ ++ ++ if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; ++ prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */ ++ prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ ++ /* Incorrect STA_REC index */ ++ if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Check whether the STA_REC is activated */ ++ prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++#endif ++ ++ /* Check whether the BA agreement exists */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); ++ if (!prReorderQueParm) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL ReorderQueParm\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ u4SSN = (UINT_32) (prSwRfb->u2SSN); ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); ++ u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); ++ ++ if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) { ++ prReorderQueParm->u2WinStart = (UINT_16) u4SSN; ++ prReorderQueParm->u2WinEnd = ++ ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; ++ DBGLOG(QM, TRACE, ++ "QM:(BAR)[%d](%u){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, ++ prReorderQueParm->u2WinEnd); ++ qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); ++ } else { ++ DBGLOG(QM, TRACE, "QM:(BAR)(%d)(%u){%u,%u}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd); ++ } ++} ++ ++VOID qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_SW_RFB_T prExaminedQueuedSwRfb; ++ P_QUE_T prReorderQue; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prReorderQueParm); ++ ASSERT(prReturnedQue); ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ ++ /* There are no packets queued in the Reorder Queue */ ++ if (prExaminedQueuedSwRfb == NULL) { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->u4NumElem++; ++ } ++ ++ /* Determine the insert position */ ++ else { ++ do { ++ /* Case 1: Terminate. A duplicate packet */ ++ if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) { ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ return; ++ } ++ ++ /* Case 2: Terminate. The insert point is found */ ++ else if (qmCompareSnIsLessThan((prSwRfb->u2SSN), (prExaminedQueuedSwRfb->u2SSN))) ++ break; ++ ++ /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */ ++ else ++ prExaminedQueuedSwRfb = (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext); ++ } while (prExaminedQueuedSwRfb); ++ ++ /* Update the Reorder Queue Parameters according to the found insert position */ ++ if (prExaminedQueuedSwRfb == NULL) { ++ /* The received packet shall be placed at the tail */ ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); ++ prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb); ++ } else { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb; ++ if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) { ++ /* The received packet will become the head */ ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ } else { ++ (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T) prSwRfb; ++ } ++ ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb; ++ } ++ ++ prReorderQue->u4NumElem++; ++ ++ } ++ ++} ++ ++VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_QUE_T prReorderQue; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prReorderQueParm); ++ ASSERT(prReturnedQue); ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ /* There are no packets queued in the Reorder Queue */ ++ if (QUEUE_IS_EMPTY(prReorderQue)) { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ } else { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); ++ } ++ prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->u4NumElem++; ++ ++} ++ ++BOOLEAN ++qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout) ++{ ++ P_SW_RFB_T prReorderedSwRfb; ++ P_QUE_T prReorderQue; ++ BOOLEAN fgDequeuHead, fgMissing; ++ OS_SYSTIME rCurrentTime, *prMissTimeout; ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ *fgIsTimeout = FALSE; ++ fgMissing = FALSE; ++ rCurrentTime = 0; ++ prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]); ++ if ((*prMissTimeout)) { ++ fgMissing = TRUE; ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ } ++ ++ /* Check whether any packet can be indicated to the higher layer */ ++ while (TRUE) { ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ break; ++ ++ /* Always examine the head packet */ ++ prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ fgDequeuHead = FALSE; ++ ++ /* SN == WinStart, so the head packet shall be indicated (advance the window) */ ++ if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { ++ ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ } ++ /* SN > WinStart, break to update WinEnd */ ++ else { ++ if ((fgMissing == TRUE) && ++ CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout), ++ MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) { ++ DBGLOG(QM, TRACE, ++ "QM:RX BA Timout Next Tid %d SSN %d\n", prReorderQueParm->ucTid, ++ prReorderedSwRfb->u2SSN); ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ ++ fgMissing = FALSE; ++ *fgIsTimeout = TRUE; ++ } else ++ break; ++ } ++ ++ /* Dequeue the head packet */ ++ if (fgDequeuHead) { ++ ++ if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { ++ prReorderQue->prHead = NULL; ++ prReorderQue->prTail = NULL; ++ } else { ++ prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; ++ (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; ++ } ++ prReorderQue->u4NumElem--; ++ /* DbgPrint("QM: [%d] %d (%d)\n", ++ prReorderQueParm->ucTid, ++ prReorderedSwRfb->u2PacketLen, ++ prReorderedSwRfb->u2SSN); */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); ++ } ++ } ++ ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ *prMissTimeout = 0; ++ else { ++ if (fgMissing == FALSE) ++ GET_CURRENT_SYSTIME(prMissTimeout); ++ } ++ ++ /* After WinStart has been determined, update the WinEnd */ ++ prReorderQueParm->u2WinEnd = ++ (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); ++ return QUEUE_IS_EMPTY(prReorderQue); ++} ++ ++VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_SW_RFB_T prReorderedSwRfb; ++ P_QUE_T prReorderQue; ++ BOOLEAN fgDequeuHead; ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ /* Check whether any packet can be indicated to the higher layer */ ++ while (TRUE) { ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ break; ++ ++ /* Always examine the head packet */ ++ prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ fgDequeuHead = FALSE; ++ ++ /* SN == WinStart, so the head packet shall be indicated (advance the window) */ ++ if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { ++ ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ } ++ ++ /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */ ++ else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN), ++ (UINT_32) (prReorderQueParm->u2WinStart))) ++ fgDequeuHead = TRUE; ++ ++ /* SN > WinStart, break to update WinEnd */ ++ else ++ break; ++ ++ /* Dequeue the head packet */ ++ if (fgDequeuHead) { ++ ++ if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { ++ prReorderQue->prHead = NULL; ++ prReorderQue->prTail = NULL; ++ } else { ++ prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; ++ (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; ++ } ++ prReorderQue->u4NumElem--; ++ /* DbgPrint("QM: [%d] %d (%d)\n", */ ++ /* prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); ++ } ++ } ++ ++ /* After WinStart has been determined, update the WinEnd */ ++ prReorderQueParm->u2WinEnd = ++ (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); ++ ++} ++ ++BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater) ++{ ++ /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */ ++ if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) /* Shall be <= */ ++ return FALSE; ++ ++ /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */ ++ else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) ++ return TRUE; ++ ++ /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */ ++ /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */ ++ else if (u4SnLess < u4SnGreater) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle Mailbox RX messages ++* ++* \param[in] prMailboxRxMsg The received Mailbox message from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg) ++{ ++ /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */ ++ /* TODO */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle ADD RX BA Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_RX_ADDBA_T prEventRxAddBa; ++ P_STA_RECORD_T prStaRec; ++ UINT_32 u4Tid; ++ UINT_32 u4WinSize; ++ ++ DBGLOG(QM, INFO, "QM:Event +RxBa\n"); ++ ++ prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx); ++ ++ if (!prStaRec) { ++ /* Invalid STA_REC index, discard the event packet */ ++ /* ASSERT(0); */ ++ DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"); ++ return; ++ } ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ ++ DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ /* return; */ ++ } ++#endif ++ ++ u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK) ++ >> BA_PARAM_SET_TID_MASK_OFFSET); ++ ++ u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK) ++ >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET); ++ ++ if (!qmAddRxBaEntry(prAdapter, ++ prStaRec->ucIndex, ++ (UINT_8) u4Tid, ++ (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN), (UINT_16) u4WinSize)) { ++ ++ /* FW shall ensure the availabiilty of the free-to-use BA entry */ ++ DBGLOG(QM, ERROR, "QM: (Error) qmAddRxBaEntry() failure\n"); ++ ASSERT(0); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle DEL RX BA Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_RX_DELBA_T prEventRxDelBa; ++ P_STA_RECORD_T prStaRec; ++ ++ /* DbgPrint("QM:Event -RxBa\n"); */ ++ ++ prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx); ++ ++ if (!prStaRec) ++ /* Invalid STA_REC index, discard the event packet */ ++ /* ASSERT(0); */ ++ return; ++#if 0 ++ if (!(prStaRec->fgIsValid)) ++ /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ ++ /* ASSERT(0); */ ++ return; ++#endif ++ ++ qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE); ++ ++} ++ ++P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid) ++{ ++ int i; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */ ++ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (prQM->arRxBaTable[i].fgIsValid) { ++ if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) && (prQM->arRxBaTable[i].ucTid == ucTid)) ++ return &prQM->arRxBaTable[i]; ++ } ++ } ++ return NULL; ++} ++ ++BOOLEAN ++qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize) ++{ ++ int i; ++ P_RX_BA_ENTRY_T prRxBaEntry = NULL; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ /* Invalid STA_REC index, discard the event packet */ ++ DBGLOG(QM, WARN, "QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx); ++ return FALSE; ++ } ++ ++ prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* if(!(prStaRec->fgIsValid)){ */ ++ /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */ ++ /* return FALSE; */ ++ /* } */ ++ ++ /* 4 <1> Delete before adding */ ++ /* Remove the BA entry for the same (STA, TID) tuple if it exists */ ++ if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) ++ qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */ ++ /* 4 <2> Add a new BA entry */ ++ /* No available entry to store the BA agreement info. Retrun FALSE. */ ++ if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) { ++ DBGLOG(QM, ERROR, "QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount); ++ return FALSE; ++ } ++ /* Find the free-to-use BA entry */ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (!prQM->arRxBaTable[i].fgIsValid) { ++ prRxBaEntry = &(prQM->arRxBaTable[i]); ++ prQM->ucRxBaCount++; ++ DBGLOG(QM, LOUD, "QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); ++ break; ++ } ++ } ++ /* If a free-to-use entry is found, configure it and associate it with the STA_REC */ ++ u2WinSize += CFG_RX_BA_INC_SIZE; ++ if (prRxBaEntry) { ++ prRxBaEntry->ucStaRecIdx = ucStaRecIdx; ++ prRxBaEntry->ucTid = ucTid; ++ prRxBaEntry->u2WinStart = u2WinStart; ++ prRxBaEntry->u2WinSize = u2WinSize; ++ prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT); ++ prRxBaEntry->fgIsValid = TRUE; ++ prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE; ++ ++ g_arMissTimeout[ucStaRecIdx][ucTid] = 0; ++ ++ DBGLOG(QM, INFO, "QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n", ++ ucStaRecIdx, ucTid, ++ prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize); ++ ++ /* Update the BA entry reference table for per-packet lookup */ ++ prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry; ++ } else { ++ /* This shall not happen because FW should keep track of the usage of RX BA entries */ ++ DBGLOG(QM, ERROR, "QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost) ++{ ++ P_RX_BA_ENTRY_T prRxBaEntry; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prFlushedPacketList = NULL; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n"); ++ return; ++ } ++#endif ++ ++ /* Remove the BA entry for the same (STA, TID) tuple if it exists */ ++ prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid]; ++ ++ if (prRxBaEntry) { ++ ++ prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid); ++ ++ if (prFlushedPacketList) { ++ ++ if (fgFlushToHost) { ++ wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList); ++ } else { ++ ++ P_SW_RFB_T prSwRfb; ++ P_SW_RFB_T prNextSwRfb; ++ ++ prSwRfb = prFlushedPacketList; ++ ++ do { ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ ++ } ++ ++ } ++#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0)) ++ /* Update RX BA entry state. Note that RX queue flush is not done here */ ++ prRxBaEntry->fgIsValid = FALSE; ++ prQM->ucRxBaCount--; ++ ++ /* Debug */ ++#if 0 ++ DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); ++#endif ++ ++ /* Update STA RX BA table */ ++ prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL; ++#endif ++ ++ DBGLOG(QM, INFO, "QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid); ++ ++ } ++ ++ /* Debug */ ++#if CFG_HIF_RX_STARVATION_WARNING ++ { ++ P_RX_CTRL_T prRxCtrl; ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ DBGLOG(QM, TRACE, ++ "QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, ++ prRxCtrl->u4DequeuedCnt); ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To process WMM related IEs in ASSOC_RSP ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ PUINT_8 pucIEStart; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ UINT_8 ucQosInfo; ++ UINT_8 ucQosInfoAC; ++ UINT_8 ucBmpAC; ++ ++ DEBUGFUNC("mqmProcessAssocReq"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->fgIsQoS = FALSE; ++ prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; ++ ++ pucIEStart = pucIE; ++ ++ /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ /* Determine whether QoS is enabled with the association */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsWmmSupported = TRUE; ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE; ++ ucQosInfo = prIeWmmInfo->ucQosInfo; ++ ucQosInfoAC = ucQosInfo & BITS(0, 3); ++ ++ prStaRec->fgIsUapsdSupported = ((ucQosInfoAC) ? TRUE : FALSE) & ++ prAdapter->rWifiVar.fgSupportUAPSD; ++ ++ ucBmpAC = 0; ++ ++ if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) ++ ucBmpAC |= BIT(ACI_VO); ++ if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) ++ ucBmpAC |= BIT(ACI_VI); ++ if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) ++ ucBmpAC |= BIT(ACI_BE); ++ if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) ++ ucBmpAC |= BIT(ACI_BK); ++ ++ prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC; ++ ++ prStaRec->ucUapsdSp = ++ (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5; ++ break; ++ default: ++ /* Other WMM QoS IEs. Ignore any */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ ++ ++ break; ++ ++ case ELEM_ID_HT_CAP: ++ /* Some client won't put the WMM IE if client is 802.11n */ ++ if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ DBGLOG(QM, TRACE, "MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To process WMM related IEs in ASSOC_RSP ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ PUINT_8 pucIEStart; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ DEBUGFUNC("mqmProcessAssocRsp"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->fgIsQoS = FALSE; ++ ++ pucIEStart = pucIE; ++ ++ DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n", ++ prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS); ++ ++ /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ ++ /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */ ++ if ((!prAdapter->rWifiVar.fgSupportQoS)) ++ return; ++ ++ /* Determine whether QoS is enabled with the association */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ ++ default: ++ /* Other WMM QoS IEs. Ignore any */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ ++ break; ++ ++ case ELEM_ID_HT_CAP: ++ /* Some AP won't put the WMM IE if client is 802.11n */ ++ if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Parse AC parameters and write to HW CRs */ ++ if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) { ++ mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE); ++#if ARP_MONITER_ENABLE ++ qmResetArpDetect(); ++#endif ++ } ++ ++ DBGLOG(QM, TRACE, "MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); ++ if (prStaRec->fgIsWmmSupported) ++ nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp) ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_BSS_INFO_T prBssInfo; ++ P_AC_QUE_PARMS_T prAcQueParams; ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ ENUM_WMM_ACI_T eAci; ++ PUINT_8 pucWmmParamSetCount; ++ ++ DEBUGFUNC("mqmParseEdcaParameters"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (prStaRec == NULL) ++ return; ++ ++ DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n", prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS); ++ ++ if ((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)) ++ return; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Goal: Obtain the EDCA parameters */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) != VENDOR_OUI_TYPE_WMM) || ++ (kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) ++ break; ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Param IE with a wrong length */ ++ ++ pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount); ++ prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE; ++ ++ /* Check the Parameter Set Count to determine whether EDCA parameters */ ++ /* have been changed */ ++ if (!fgForceOverride && (*pucWmmParamSetCount ++ == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT))) ++ break; /* Ignore the IE without updating HW CRs */ ++ ++ /* Update Parameter Set Count */ ++ *pucWmmParamSetCount = ++ (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* Update EDCA parameters */ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prAcQueParams = &prBssInfo->arACQueParms[eAci]; ++ mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams); ++ ++ prAcQueParams->fgIsACMSet = ++ (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE; ++ prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN; ++ ++ DBGLOG(QM, LOUD, ++ "eAci:%d, ACM:%d, Aifsn:%d, CWmin:%d, CWmax:%d, TxopLmt:%d\n", ++ eAci, prAcQueParams->fgIsACMSet, prAcQueParams->u2Aifsn, ++ prAcQueParams->u2CWmin, prAcQueParams->u2CWmax, ++ prAcQueParams->u2TxopLimit); ++ } ++ break; ++ default: ++ /* Other WMM QoS IEs. Ignore */ ++ break; ++ } ++ ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prIeWmmParam The pointer to the WMM Parameter IE ++* \param[in] u4AcOffset The offset specifying the AC queue for parsing ++* \param[in] prHwAcParams The parameter structure used to configure the HW CRs ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams) ++{ ++ prAcQueParams->u2Aifsn = *((PUINT_8) (&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4)); ++ ++ prAcQueParams->u2CWmax = BIT(((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK) ++ >> WMM_ECW_WMAX_OFFSET) - 1; ++ ++ prAcQueParams->u2CWmin = ++ BIT((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK) - 1; ++ ++ WLAN_GET_FIELD_16(((PUINT_8) (&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)), ++ &(prAcQueParams->u2TxopLimit)); ++ ++ prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To parse WMM/11n related IEs in scan results (only for AP peers) ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prScanResult The scan result which shall be parsed to obtain needed info ++* \param[out] prStaRec The obtained info is stored in the STA_REC ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++#if (CFG_SUPPORT_TDLS == 1) /* for test purpose */ ++BOOLEAN flgTdlsTestExtCapElm = FALSE; ++UINT8 aucTdlsTestExtCapElm[7]; ++#endif /* CFG_SUPPORT_TDLS */ ++VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec) ++{ ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ DEBUGFUNC("mqmProcessScanResult"); ++ ++ ASSERT(prScanResult); ++ ASSERT(prStaRec); ++ ++ /* Reset the flag before parsing */ ++ prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; ++ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ u2IELength = prScanResult->u2IELength; ++ pucIE = prScanResult->aucIEBuf; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* TDLS test purpose */ ++ if (flgTdlsTestExtCapElm == TRUE) ++ TdlsexBssExtCapParse(prStaRec, aucTdlsTestExtCapElm); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_EXTENDED_CAP: ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexBssExtCapParse(prStaRec, pucIE); ++#endif /* CFG_SUPPORT_TDLS */ ++ break; ++ ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Param IE with a wrong length */ ++ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = ++ (((((P_IE_WMM_PARAM_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? ++ TRUE : FALSE); ++ break; ++ ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = ++ (((((P_IE_WMM_INFO_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? ++ TRUE : FALSE); ++ break; ++ ++ default: ++ /* A WMM QoS IE that doesn't matter. Ignore it. */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ ++ ++ break; ++ ++ default: ++ /* A WMM IE that doesn't matter. Ignore it. */ ++ break; ++ } ++ } ++ DBGLOG(QM, LOUD, "MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n", ++ prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported); ++ ++} ++ ++UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ UINT_32 i; ++ P_STA_RECORD_T prTempStaRec; ++ ++ prTempStaRec = NULL; ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <1> DA = BMCAST */ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) ++ return STA_REC_INDEX_BMCAST; ++ /* 4 <2> Check if an AP STA is present */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if ((prTempStaRec->ucNetTypeIndex == eNetworkType) ++ && (prTempStaRec->fgIsAp) ++ && (prTempStaRec->fgIsValid)) { ++ return prTempStaRec->ucIndex; ++ } ++ } ++ ++ /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if (prTempStaRec->fgIsValid) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)) ++ return prTempStaRec->ucIndex; ++ } ++ } ++ ++ /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ ++ return STA_REC_INDEX_NOT_FOUND; ++} ++ ++UINT_32 ++mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, ++ UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf) ++{ ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ UINT_32 ucUapsd[] = { ++ WMM_QOS_INFO_BE_UAPSD, ++ WMM_QOS_INFO_BK_UAPSD, ++ WMM_QOS_INFO_VI_UAPSD, ++ WMM_QOS_INFO_VO_UAPSD ++ }; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ ASSERT(pOutBuf); ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) pOutBuf; ++ ++ prIeWmmInfo->ucId = ELEM_ID_WMM; ++ prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmInfo->aucOui[0] = aucWfaOui[0]; ++ prIeWmmInfo->aucOui[1] = aucWfaOui[1]; ++ prIeWmmInfo->aucOui[2] = aucWfaOui[2]; ++ prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; ++ ++ prIeWmmInfo->ucVersion = VERSION_WMM; ++ prIeWmmInfo->ucQosInfo = 0; ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (fgSupportUAPSD) { ++ ++ UINT_8 ucQosInfo = 0; ++ UINT_8 i; ++ ++ /* Static U-APSD setting */ ++ for (i = ACI_BE; i <= ACI_VO; i++) { ++ if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) ++ ucQosInfo |= (UINT_8) ucUapsd[i]; ++ } ++ ++ if (ucBmpDeliveryAC & ucBmpTriggerAC) { ++ switch (ucUapsdSp) { ++ case WMM_MAX_SP_LENGTH_ALL: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_2: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_4: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_6: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; ++ break; ++ ++ default: ++ DBGLOG(QM, WARN, "MQM: Incorrect SP length\n"); ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ } ++ } ++ prIeWmmInfo->ucQosInfo = ucQosInfo; ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ return IE_SIZE(prIeWmmInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Generate the WMM Info IE ++* ++* \param[in] prAdapter Adapter pointer ++* @param prMsduInfo The TX MMPDU ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("mqmGenerateWmmInfoIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ /* In case QoS is not turned off, exit directly */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ if (!prStaRec->fgIsWmmSupported) ++ return; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) ++ ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ prIeWmmInfo->ucId = ELEM_ID_WMM; ++ prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmInfo->aucOui[0] = aucWfaOui[0]; ++ prIeWmmInfo->aucOui[1] = aucWfaOui[1]; ++ prIeWmmInfo->aucOui[2] = aucWfaOui[2]; ++ prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; ++ ++ prIeWmmInfo->ucVersion = VERSION_WMM; ++ prIeWmmInfo->ucQosInfo = 0; ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++/* if(prAdapter->rWifiVar.fgSupportUAPSD){ */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported) { ++ ++ UINT_8 ucQosInfo = 0; ++ UINT_8 i; ++ ++ /* Static U-APSD setting */ ++ for (i = ACI_BE; i <= ACI_VO; i++) { ++ if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)) ++ ucQosInfo |= (UINT_8) ucUapsd[i]; ++ } ++ ++ if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) { ++ switch (prPmProfSetupInfo->ucUapsdSp) { ++ case WMM_MAX_SP_LENGTH_ALL: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_2: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_4: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_6: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; ++ break; ++ ++ default: ++ DBGLOG(QM, INFO, "MQM: Incorrect SP length\n"); ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ } ++ } ++ prIeWmmInfo->ucQosInfo = ucQosInfo; ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo); ++#else ++ ++ prMsduInfo->u2FrameLength += mqmGenerateWmmInfoIEByParam((prAdapter->rWifiVar.fgSupportUAPSD ++ && prStaRec->fgIsUapsdSupported), ++ prPmProfSetupInfo->ucBmpDeliveryAC, ++ prPmProfSetupInfo->ucBmpTriggerAC, ++ prPmProfSetupInfo->ucUapsdSp, (UINT_8 *) prIeWmmInfo); ++#endif ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief log2 calculation for CW ++* ++* @param[in] val value ++* ++* @return log2(val) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_32 cwlog2(UINT_32 val) ++{ ++ ++ UINT_32 n; ++ ++ n = 0; ++ ++ while (val >= 512) { ++ n += 9; ++ val = val >> 9; ++ } ++ while (val >= 16) { ++ n += 4; ++ val >>= 4; ++ } ++ while (val >= 2) { ++ n += 1; ++ val >>= 1; ++ } ++ return n; ++} ++#endif ++ ++UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode) ++{ ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ UINT_8 aucACI[] = { ++ WMM_ACI_AC_BE, ++ WMM_ACI_AC_BK, ++ WMM_ACI_AC_VI, ++ WMM_ACI_AC_VO ++ }; ++ ENUM_WMM_ACI_T eAci; ++ UCHAR *pucAciAifsn, *pucEcw, *pucTxopLimit; ++ ++ ASSERT(pOutBuf); ++ ++ prIeWmmParam = (P_IE_WMM_PARAM_T) pOutBuf; ++ ++ prIeWmmParam->ucId = ELEM_ID_WMM; ++ prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmParam->aucOui[0] = aucWfaOui[0]; ++ prIeWmmParam->aucOui[1] = aucWfaOui[1]; ++ prIeWmmParam->aucOui[2] = aucWfaOui[2]; ++ prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; ++ ++ prIeWmmParam->ucVersion = VERSION_WMM; ++ prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD) { ++ if (ucOpMode == OP_MODE_INFRASTRUCTURE) ++ prIeWmmParam->ucQosInfo = 0xf; ++ else ++ prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; ++ } ++ ++ /* EDCA parameter */ ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ /* DBGLOG(QM, LOUD, */ ++ /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ ++ /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ ++ ++#if 0 ++ *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].fgIsACMSet ? ++ WMM_ACIAIFSN_ACM : 0) ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].u2Aifsn & ++ (WMM_ACIAIFSN_AIFSN))); ++#else ++ /* avoid compile warnings in Klockwork tool */ ++ if (eAci == WMM_AC_BE_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_BE; ++ pucEcw = &prIeWmmParam->ucEcw_BE; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_BE; ++ } else if (eAci == WMM_AC_BK_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_BG; ++ pucEcw = &prIeWmmParam->ucEcw_BG; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_BG; ++ } else if (eAci == WMM_AC_VI_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_VI; ++ pucEcw = &prIeWmmParam->ucEcw_VI; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_VI; ++ } else if (eAci == WMM_AC_VO_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_VO; ++ pucEcw = &prIeWmmParam->ucEcw_VO; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_VO; ++ } ++ ++ *pucAciAifsn = (UINT_8) (aucACI[eAci] ++ | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM : 0) ++ | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN))); ++#endif ++ ++#if 1 ++/* *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0 */ ++ *pucEcw = (UINT_8) (0 | (((prBssInfo->aucCWminLog2ForBcast[eAci])) & WMM_ECW_WMIN_MASK) ++ | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci])) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#else ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmin + ++ 1)) & WMM_ECW_WMIN_MASK) ++ | ++ ((cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmax + ++ 1)) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#endif ++ ++#if 0 ++ WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) ++ , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++#else ++ WLAN_SET_FIELD_16(pucTxopLimit, prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++#endif ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ return IE_SIZE(prIeWmmParam); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Generate the WMM Param IE ++* ++* \param[in] prAdapter Adapter pointer ++* @param prMsduInfo The TX MMPDU ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ ++#if 0 ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ UINT_8 aucACI[] = { ++ WMM_ACI_AC_BE, ++ WMM_ACI_AC_BK, ++ WMM_ACI_AC_VI, ++ WMM_ACI_AC_VO ++ }; ++ ENUM_WMM_ACI_T eAci; ++#endif ++ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("mqmGenerateWmmParamIE"); ++ DBGLOG(QM, LOUD, "\n"); ++ ++ ASSERT(prMsduInfo); ++ ++ /* In case QoS is not turned off, exit directly */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec) { ++ if (!prStaRec->fgIsQoS) ++ return; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); ++ ++ if (!prBssInfo->fgIsQBSS) ++ return; ++/* 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. */ ++#if 0 ++ if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT && prBssInfo->eCurrentOPMode != OP_MODE_BOW) ++ return; ++#endif ++ ++ prIeWmmParam = (P_IE_WMM_PARAM_T) ++ ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ prIeWmmParam->ucId = ELEM_ID_WMM; ++ prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmParam->aucOui[0] = aucWfaOui[0]; ++ prIeWmmParam->aucOui[1] = aucWfaOui[1]; ++ prIeWmmParam->aucOui[2] = aucWfaOui[2]; ++ prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; ++ ++ prIeWmmParam->ucVersion = VERSION_WMM; ++ prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD) ++ prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; ++ ++ /* EDCA parameter */ ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ /* DBGLOG(QM, LOUD, */ ++ /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ ++ /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ ++ ++ *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].fgIsACMSet ? ++ WMM_ACIAIFSN_ACM : 0) ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].u2Aifsn & ++ (WMM_ACIAIFSN_AIFSN))); ++#if 1 ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (((prBssInfo->aucCWminLog2ForBcast ++ [eAci])) & WMM_ECW_WMIN_MASK) ++ | ++ ((((prBssInfo->aucCWmaxLog2ForBcast ++ [eAci])) << WMM_ECW_WMAX_OFFSET) ++ & WMM_ECW_WMAX_MASK) ++ ); ++#else ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmin + ++ 1)) & WMM_ECW_WMIN_MASK) ++ | ++ ((cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmax + ++ 1)) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#endif ++ ++ WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) ++ , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam); ++#else ++ ++ prMsduInfo->u2FrameLength += mqmGenerateWmmParamIEByParam(prAdapter, ++ prBssInfo, (UINT_8 *) prIeWmmParam, OP_MODE_ACCESS_POINT); ++#endif ++} ++ ++ENUM_FRAME_ACTION_T ++qmGetFrameAction(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, ++ IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_MAC_HEADER_T prWlanFrame; ++ UINT_16 u2TxFrameCtrl; ++ ++ DEBUGFUNC("qmGetFrameAction"); ++ ++#if (NIC_TX_BUFF_COUNT_TC4 > 2) ++#define QM_MGMT_QUUEUD_THRESHOLD 2 ++#else ++#define QM_MGMT_QUUEUD_THRESHOLD 1 ++#endif ++ ++ DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4)); ++ DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]); ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx); ++ ++ /* XXX Check BOW P2P AIS time ot set active */ ++ if (!IS_BSS_ACTIVE(prBssInfo)) { ++ if (eFrameType == FRAME_TYPE_MMPDU) { ++ prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; ++ u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ ++ if (((u2TxFrameCtrl == MAC_FRAME_DEAUTH) ++ && (prMsduInfo->pfTxDoneHandler == NULL)) ++ || (u2TxFrameCtrl == MAC_FRAME_ACTION)) /* whsu */ ++ return FRAME_ACTION_TX_PKT; ++ } ++ ++ DBGLOG(QM, WARN, "Drop packets Action, eFrameType: %d (Bss Index %u).\n", ++ eFrameType, prBssInfo->ucNetTypeIndex); ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); ++ return FRAME_ACTION_DROP_PKT; ++ } ++ ++ /* TODO Handle disconnect issue */ ++ ++ /* P2P probe Request frame */ ++ do { ++ if (eFrameType == FRAME_TYPE_MMPDU) { ++ prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; ++ u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ ++ ++ if (u2TxFrameCtrl == MAC_FRAME_BEACON) { ++ if (prBssInfo->fgIsNetAbsent) ++ return FRAME_ACTION_DROP_PKT; ++ } else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { ++ if (prBssInfo->fgIsNetAbsent) ++ return FRAME_ACTION_DROP_PKT; ++ } else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) { ++ if (prBssInfo->fgIsNetAbsent) ++ break; ++ DBGLOG(P2P, LOUD, "Sending DEAUTH Frame\n"); ++ return FRAME_ACTION_TX_PKT; ++ } ++ /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */ ++ else if (u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ ++ || u2TxFrameCtrl == MAC_FRAME_AUTH ++ || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ ++ || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ || u2TxFrameCtrl == MAC_FRAME_ACTION) { ++ ++ if ((prStaRec) && (prStaRec->fgIsInPS)) { ++ if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) ++ return FRAME_ACTION_TX_PKT; ++ else ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ return FRAME_ACTION_TX_PKT; ++ } ++ ++ if (!prStaRec) ++ return FRAME_ACTION_TX_PKT; ++ ++ if (!prStaRec->fgIsInUse) ++ return FRAME_ACTION_DROP_PKT; ++ ++ } /* FRAME_TYPE_MMPDU */ ++ else if (eFrameType == FRAME_TYPE_802_1X) { ++ ++ if (!prStaRec) ++ return FRAME_ACTION_TX_PKT; ++ ++ if (!prStaRec->fgIsInUse) ++ return FRAME_ACTION_DROP_PKT; ++ if (prStaRec->fgIsInPS) { ++ if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) ++ return FRAME_ACTION_TX_PKT; ++ else ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ ++ } /* FRAME_TYPE_802_1X */ ++ else if ((!IS_BSS_ACTIVE(prBssInfo)) ++ || (!prStaRec) ++ || (!prStaRec->fgIsInUse)) { ++ return FRAME_ACTION_DROP_PKT; ++ } ++ } while (0); ++ ++ if (prBssInfo->fgIsNetAbsent) { ++ DBGLOG(QM, LOUD, "Queue packets (Absent %u).\n", prBssInfo->ucNetTypeIndex); ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ ++ if (prStaRec && prStaRec->fgIsInPS) { ++ DBGLOG(QM, LOUD, "Queue packets (PS %u).\n", prStaRec->fgIsInPS); ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ switch (eFrameType) { ++ case FRAME_TYPE_802_1X: ++ if (!prStaRec->fgIsValid) ++ return FRAME_ACTION_QUEUE_PKT; ++ break; ++ ++ case FRAME_TYPE_MMPDU: ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ return FRAME_ACTION_TX_PKT; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle BSS change operation Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus; ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgIsNetAbsentOld; ++ ++ prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]); ++ fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent; ++ prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent; ++ prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota; ++ ++ /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */ ++ /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */ ++ ++ DBGLOG(QM, INFO, "NAF=%d,%d,%d\n", ++ prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota); ++ ++ if (!prBssInfo->fgIsNetAbsent) { ++ /* QM_DBG_CNT_27 */ ++ QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27); ++ } else { ++ /* QM_DBG_CNT_28 */ ++ QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28); ++ } ++ /* From Absent to Present */ ++ if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) ++ kalSetEvent(prAdapter->prGlueInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle STA change PS mode Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fgIsInPSOld; ++ ++ /* DbgPrint("QM:Event -RxBa\n"); */ ++ ++ prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ ++ fgIsInPSOld = prStaRec->fgIsInPS; ++ prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs; ++ ++ qmUpdateFreeQuota(prAdapter, ++ prStaRec, ++ prEventStaChangePsMode->ucUpdateMode, prEventStaChangePsMode->ucFreeQuota, 0); ++ ++ /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */ ++ /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */ ++ ++ DBGLOG(QM, TRACE, "PS=%d,%d\n", prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS); ++ ++ /* From PS to Awake */ ++ if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update STA free quota Event from FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota; ++ P_STA_RECORD_T prStaRec; ++ ++ prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ if (prStaRec->fgIsInPS) { ++ qmUpdateFreeQuota(prAdapter, ++ prStaRec, ++ prEventStaUpdateFreeQuota->ucUpdateMode, ++ prEventStaUpdateFreeQuota->ucFreeQuota, ++ prEventStaUpdateFreeQuota->aucReserved[0]); ++ ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++#if 0 ++ DBGLOG(QM, TRACE, ++ "qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n", ++ prEventStaUpdateFreeQuota->ucStaRecIdx, prEventStaUpdateFreeQuota->ucUpdateMode, ++ prEventStaUpdateFreeQuota->ucFreeQuota); ++#endif ++ ++ DBGLOG(QM, TRACE, "UFQ=%d,%d,%d\n", ++ prEventStaUpdateFreeQuota->ucStaRecIdx, ++ prEventStaUpdateFreeQuota->ucUpdateMode, prEventStaUpdateFreeQuota->ucFreeQuota); ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update STA free quota ++* ++* \param[in] prStaRec the STA ++* \param[in] ucUpdateMode the method to update free quota ++* \param[in] ucFreeQuota the value for update ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone) ++{ ++ ++ UINT_8 ucFreeQuotaForNonDelivery; ++ UINT_8 ucFreeQuotaForDelivery; ++ BOOLEAN flgIsUpdateForcedToDelivery; ++ ++ ASSERT(prStaRec); ++ DBGLOG(QM, LOUD, "qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n", ++ prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota); ++ ++ if (!prStaRec->fgIsInPS) ++ return; ++ ++ flgIsUpdateForcedToDelivery = FALSE; ++ ++ if (ucNumOfTxDone > 0) { ++ /* ++ update free quota by ++ num of tx done + resident free quota (delivery + non-delivery) ++ */ ++ UINT_8 ucAvailQuota; ++ ++ ucAvailQuota = ucNumOfTxDone + prStaRec->ucFreeQuotaForDelivery + prStaRec->ucFreeQuotaForNonDelivery; ++ if (ucAvailQuota > ucFreeQuota) /* sanity check */ ++ ucAvailQuota = ucFreeQuota; ++ ++ /* update current free quota */ ++ ucFreeQuota = ucAvailQuota; ++ ++ /* check if the update is from last packet */ ++ if (ucFreeQuota == (prStaRec->ucFreeQuota + 1)) { ++ /* just add the extra quota to delivery queue */ ++ ++ /* ++ EX: ++ 1. TDLS peer enters power save ++ 2. When the last 2 VI packets are tx done, we will receive 2 update events ++ 3. 1st update event: ucFreeQuota = 9 ++ 4. We will correct new quota for delivey and non-delivery to 7:2 ++ 5. 2rd update event: ucFreeQuota = 10 ++ 6. We will re-correct new quota for delivery and non-delivery to 5:5 ++ ++ But non-delivery queue is not busy. ++ So in the case, we will have wrong decision, i.e. higher queue always quota 5 ++ ++ Solution: skip the 2rd update event and just add the extra quota to delivery. ++ */ ++ ++ flgIsUpdateForcedToDelivery = TRUE; ++ } ++ } ++ ++ switch (ucUpdateMode) { ++ case FREE_QUOTA_UPDATE_MODE_INIT: ++ case FREE_QUOTA_UPDATE_MODE_OVERWRITE: ++ prStaRec->ucFreeQuota = ucFreeQuota; ++ break; ++ case FREE_QUOTA_UPDATE_MODE_INCREASE: ++ prStaRec->ucFreeQuota += ucFreeQuota; ++ break; ++ case FREE_QUOTA_UPDATE_MODE_DECREASE: ++ prStaRec->ucFreeQuota -= ucFreeQuota; ++ break; ++ default: ++ ASSERT(0); ++ } ++ ++ DBGLOG(QM, LOUD, "qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota); ++ ++ ucFreeQuota = prStaRec->ucFreeQuota; ++ ++ ucFreeQuotaForNonDelivery = 0; ++ ucFreeQuotaForDelivery = 0; ++ ++ if (ucFreeQuota > 0) { ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */ ++ ++ if (flgIsUpdateForcedToDelivery == FALSE) { ++ if (prStaRec->ucFreeQuotaForNonDelivery > 0 && prStaRec->ucFreeQuotaForDelivery > 0) { ++ ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else if (prStaRec->ucFreeQuotaForNonDelivery == 0 ++ && prStaRec->ucFreeQuotaForDelivery == 0) { ++ ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) { ++ /* NonDelivery is not busy */ ++ if (ucFreeQuota >= 3) { ++ ucFreeQuotaForNonDelivery = 2; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else { ++ ucFreeQuotaForDelivery = ucFreeQuota; ++ ucFreeQuotaForNonDelivery = 0; ++ } ++ } else if (prStaRec->ucFreeQuotaForDelivery > 0) { ++ /* Delivery is not busy */ ++ if (ucFreeQuota >= 3) { ++ ucFreeQuotaForDelivery = 2; ++ ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery; ++ } else { ++ ucFreeQuotaForNonDelivery = ucFreeQuota; ++ ucFreeQuotaForDelivery = 0; ++ } ++ } ++ } else { ++ ucFreeQuotaForNonDelivery = 2; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } ++ } else { ++ /* no use ? */ ++ /* !prStaRec->fgIsUapsdSupported */ ++ ucFreeQuotaForNonDelivery = ucFreeQuota; ++ ucFreeQuotaForDelivery = 0; ++ } ++ } ++ /* ucFreeQuota > 0 */ ++ prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery; ++ prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ if (IS_TDLS_STA(prStaRec)) ++ DBGLOG(QM, LOUD, " quota %d %d %d\n", ++ ucFreeQuota, ucFreeQuotaForDelivery, ucFreeQuotaForNonDelivery); ++#endif ++ ++ DBGLOG(QM, LOUD, "new QuotaForDelivery = %d QuotaForNonDelivery = %d\n", ++ prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the reorder queued RX packets ++* ++* \param[in] (none) ++* ++* \return The number of queued RX packets ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4Total; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ u4Total = 0; ++ /* XXX The summation may impact the performance */ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem; ++#if DBG && 0 ++ if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) ++ ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0); ++#endif ++ } ++ ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2)); ++ return u4Total; ++} ++ ++#if ARP_MONITER_ENABLE ++VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ struct sk_buff *prSkb = NULL; ++ PUINT_8 pucData = NULL; ++ UINT_16 u2EtherType = 0; ++ int arpOpCode = 0; ++ ++ prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ ++ if (!prSkb || (prSkb->len <= ETHER_HEADER_LEN)) ++ return; ++ ++ pucData = prSkb->data; ++ if (!pucData) ++ return; ++ u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if (u2EtherType != ETH_P_ARP || (apIp[0] | apIp[1] | apIp[2] | apIp[3]) == 0) ++ return; ++ ++ if (strncmp(apIp, &pucData[ETH_TYPE_LEN_OFFSET + 26], sizeof(apIp))) /* dest ip address */ ++ return; ++ ++ arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); ++ if (arpOpCode == ARP_PRO_REQ) { ++ arpMoniter++; ++ if (arpMoniter > 20) { ++ DBGLOG(INIT, WARN, "IOT Critical issue, arp no resp, check AP!\n"); ++ aisBssBeaconTimeout(prAdapter); ++ arpMoniter = 0; ++ kalMemZero(apIp, sizeof(apIp)); ++ } ++ } ++} ++ ++VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ PUINT_8 pucData = NULL; ++ UINT_16 u2EtherType = 0; ++ int arpOpCode = 0; ++ P_BSS_INFO_T prBssInfo = NULL; ++ ++ if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN) ++ return; ++ ++ pucData = (PUINT_8)prSwRfb->pvHeader; ++ if (!pucData) ++ return; ++ u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if (u2EtherType != ETH_P_ARP) ++ return; ++ ++ arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (arpOpCode == ARP_PRO_RSP) { ++ arpMoniter = 0; ++ if (prBssInfo && prBssInfo->prStaRecOfAP && prBssInfo->prStaRecOfAP->aucMacAddr) { ++ if (EQUAL_MAC_ADDR(&(pucData[ETH_TYPE_LEN_OFFSET + 10]), /* source hardware address */ ++ prBssInfo->prStaRecOfAP->aucMacAddr)) { ++ strncpy(apIp, &(pucData[ETH_TYPE_LEN_OFFSET + 16]), sizeof(apIp)); /* src ip address */ ++ DBGLOG(INIT, TRACE, "get arp response from AP %d.%d.%d.%d\n", ++ apIp[0], apIp[1], apIp[2], apIp[3]); ++ } ++ } ++ } ++} ++ ++VOID qmResetArpDetect(VOID) ++{ ++ arpMoniter = 0; ++ kalMemZero(apIp, sizeof(apIp)); ++} ++#endif ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c +new file mode 100644 +index 000000000000..6f5c0bcdd90b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c +@@ -0,0 +1,1177 @@ ++/* ++** Id: @(#) gl_bow.c@@ ++*/ ++ ++/*! \file gl_bow.c ++ \brief Main routines of Linux driver interface for 802.11 PAL (BT 3.0 + HS) ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_bow.c ++ * ++ * 02 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00235223] [Rose][ICS][Cross Feature][AEE-IPANIC]The device reboot automatically and then the "KE" pops up ++ * after you turn on the "Airplane mode".(once) ++ * ++ * [Root Cause] ++ * PAL operates BOW char dev poll after BOW char dev is registered. ++ * ++ * [Solution] ++ * Rejects PAL char device operation after BOW is unregistered or when wlan GLUE_FLAG_HALT is set. ++ * ++ * This is a workaround for BOW driver robustness, happens only in ICS. ++ * ++ * Root cause should be fixed by CR [ALPS00231570] ++ * ++ * 02 03 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00118114] [Rose][ICS][Free Test][Bluetooth]The "KE" pops up after you turn on the airplane mode.(5/5) ++ * ++ * [Root Cause] ++ * PAL operates BOW char dev poll after BOW char dev is registered. ++ * ++ * [Solution] ++ * Rejects PAL char device operation after BOW is unregistered. ++ * ++ * Happens only in ICS. ++ * ++ * Notified PAL owener to reivew MTKBT/PAL closing BOW char dev procedure. ++ * ++ * [Side Effect] ++ * None. ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 25 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Modify ampc0 char device for major number 151 for all MT6575 projects. ++ * ++ * 07 28 2011 cp.wu ++ * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl ++ * unlocked_ioctl returns as long instead of int. ++ * ++ * 07 28 2011 cp.wu ++ * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl ++ * migrate to unlocked ioctl interface ++ * ++ * 04 12 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add WMM IE for BOW initiator data. ++ * ++ * 04 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * replace alloc_netdev to alloc_netdev_mq for BoW ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update net register and BOW for concurrent features. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 11 11 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BoW timer assert issue. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 09 14 2010 cp.wu ++ * NULL ++ * correct typo: POLLOUT instead of POLL_OUT ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * add waitq for poll() and read(). ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change variable names for multiple physical link to match with coding convention ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * multiple BoW interfaces need to compare with peer address ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * fix kalIndicateBOWEvent. ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include ++#include "bss.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* @FIXME if there is command/event with payload length > 28 */ ++#define MAX_BUFFER_SIZE (64) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_BOW_TEST ++UINT_32 g_u4PrevSysTime = 0; ++UINT_32 g_u4CurrentSysTime = 0; ++UINT_32 g_arBowRevPalPacketTime[11]; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* forward declarations */ ++static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos); ++ ++static ssize_t ++mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos); ++ ++static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg); ++ ++static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait); ++ ++static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp); ++ ++static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp); ++ ++/* character file operations */ ++static const struct file_operations mt6620_ampc_fops = { ++ /* .owner = THIS_MODULE, */ ++ .read = mt6620_ampc_read, ++ .write = mt6620_ampc_write, ++ .unlocked_ioctl = mt6620_ampc_ioctl, ++ .poll = mt6620_ampc_poll, ++ .open = mt6620_ampc_open, ++ .release = mt6620_ampc_release, ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register for character device to communicate with 802.11 PAL ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glRegisterAmpc(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->rBowInfo.fgIsRegistered == TRUE) ++ return FALSE; ++ ++#if 0 ++ /* 1. allocate major number dynamically */ ++ ++ if (alloc_chrdev_region(&(prGlueInfo->rBowInfo.u4DeviceNumber), 0, /* first minor number */ ++ 1, /* number */ ++ GLUE_BOW_DEVICE_NAME) != 0) ++ ++ return FALSE; ++#endif ++ ++#if 1 ++ ++#if defined(CONFIG_AMPC_CDEV_NUM) ++ prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(CONFIG_AMPC_CDEV_NUM, 0); ++#else ++ prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(226, 0); ++#endif ++ ++ if (register_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1, /* number */ ++ GLUE_BOW_DEVICE_NAME) != 0) ++ ++ return FALSE; ++#endif ++ ++ /* 2. spin-lock initialization */ ++ /* spin_lock_init(&(prGlueInfo->rBowInfo.rSpinLock)); */ ++ ++ /* 3. initialize kfifo */ ++/* prGlueInfo->rBowInfo.prKfifo = kfifo_alloc(GLUE_BOW_KFIFO_DEPTH, ++ GFP_KERNEL, ++ &(prGlueInfo->rBowInfo.rSpinLock));*/ ++ if ((kfifo_alloc((struct kfifo *)&(prGlueInfo->rBowInfo.rKfifo), GLUE_BOW_KFIFO_DEPTH, GFP_KERNEL))) ++ goto fail_kfifo_alloc; ++ ++/* if(prGlueInfo->rBowInfo.prKfifo == NULL) */ ++ if (&(prGlueInfo->rBowInfo.rKfifo) == NULL) ++ goto fail_kfifo_alloc; ++ ++ /* 4. initialize cdev */ ++ cdev_init(&(prGlueInfo->rBowInfo.cdev), &mt6620_ampc_fops); ++ /* prGlueInfo->rBowInfo.cdev.owner = THIS_MODULE; */ ++ prGlueInfo->rBowInfo.cdev.ops = &mt6620_ampc_fops; ++ ++ /* 5. add character device */ ++ if (cdev_add(&(prGlueInfo->rBowInfo.cdev), prGlueInfo->rBowInfo.u4DeviceNumber, 1)) ++ goto fail_cdev_add; ++ ++ /* 6. in queue initialization */ ++ init_waitqueue_head(&(prGlueInfo->rBowInfo.outq)); ++ ++ /* 7. finish */ ++ prGlueInfo->rBowInfo.fgIsRegistered = TRUE; ++ return TRUE; ++ ++fail_cdev_add: ++ kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); ++/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ ++fail_kfifo_alloc: ++ unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); ++ return FALSE; ++} /* end of glRegisterAmpc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister character device for communicating with 802.11 PAL ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glUnregisterAmpc(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->rBowInfo.fgIsRegistered == FALSE) ++ return FALSE; ++ ++ prGlueInfo->rBowInfo.fgIsRegistered = FALSE; ++ ++ /* 1. free netdev if necessary */ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalUninitBowDevice(prGlueInfo); ++#endif ++ ++ /* 2. removal of character device */ ++ cdev_del(&(prGlueInfo->rBowInfo.cdev)); ++ ++ /* 3. free kfifo */ ++/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ ++ kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); ++/* prGlueInfo->rBowInfo.prKfifo = NULL; */ ++/* prGlueInfo->rBowInfo.rKfifo = NULL; */ ++ ++ /* 4. free device number */ ++ unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); ++ ++ return TRUE; ++} /* end of glUnregisterAmpc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief read handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos) ++{ ++ UINT_8 aucBuffer[MAX_BUFFER_SIZE]; ++ ssize_t retval; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ /* size check */ ++/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) >= size) */ ++ if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) >= size) ++ retval = size; ++ else ++ retval = kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); ++/* retval = kfifo_len(prGlueInfo->rBowInfo.prKfifo); */ ++ ++/* kfifo_get(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ ++/* kfifo_out(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ ++ if (!(kfifo_out(&(prGlueInfo->rBowInfo.rKfifo), aucBuffer, retval))) { ++ retval = -EIO; ++ return retval; ++ } ++ ++ if (copy_to_user(buf, aucBuffer, retval)) ++ retval = -EIO; ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief write handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t ++mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos) ++{ ++#if CFG_BOW_TEST ++ UINT_8 i; ++#endif ++ ++ UINT_8 aucBuffer[MAX_BUFFER_SIZE]; ++ P_AMPC_COMMAND prCmd; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ ++ if (size > MAX_BUFFER_SIZE) ++ return -EINVAL; ++ else if (copy_from_user(aucBuffer, buf, size)) ++ return -EIO; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "AMP driver CMD buffer size : %d.\n", size); ++ ++ for (i = 0; i < MAX_BUFFER_SIZE; i++) ++ DBGLOG(BOW, EVENT, "AMP write content : 0x%x.\n", aucBuffer[i]); ++ ++ DBGLOG(BOW, EVENT, "BoW CMD write.\n"); ++#endif ++ ++ prCmd = (P_AMPC_COMMAND) aucBuffer; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "AMP write content payload length : %d.\n", prCmd->rHeader.u2PayloadLength); ++ ++ DBGLOG(BOW, EVENT, "AMP write content header length : %d.\n", sizeof(AMPC_COMMAND_HEADER_T)); ++#endif ++ ++ /* size check */ ++ if (prCmd->rHeader.u2PayloadLength + sizeof(AMPC_COMMAND_HEADER_T) != size) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Wrong CMD total length.\n"); ++#endif ++ ++ return -EINVAL; ++ } ++ ++ if (wlanbowHandleCommand(prGlueInfo->prAdapter, prCmd) == WLAN_STATUS_SUCCESS) ++ return size; ++ else ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg) ++{ ++ int err = 0; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ /* permission check */ ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); ++ else if (_IOC_DIR(cmd) & _IOC_WRITE) ++ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); ++ if (err) ++ return -EFAULT; ++ ++ /* no ioctl is implemented yet */ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait) ++{ ++ unsigned int retval; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ ++ poll_wait(filp, &prGlueInfo->rBowInfo.outq, wait); ++ ++ retval = (POLLOUT | POLLWRNORM); /* always accepts incoming command packets */ ++ ++/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLOUT | POLLWRNORM, %x\n", retval)); */ ++ ++/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) > 0) */ ++ if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) > 0) { ++ retval |= (POLLIN | POLLRDNORM); ++ ++/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLIN | POLLRDNORM, %x\n", retval)); */ ++ ++ } ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief open handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_GL_BOW_INFO prBowInfo; ++ ++ prBowInfo = container_of(inodep->i_cdev, GL_BOW_INFO, cdev); ++ ASSERT(prBowInfo); ++ ++ prGlueInfo = container_of(prBowInfo, GLUE_INFO_T, rBowInfo); ++ ASSERT(prGlueInfo); ++ ++ /* set-up private data */ ++ filp->private_data = prGlueInfo; ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief close handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to indicate event for Bluetooth over Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* prEvent ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent) ++{ ++ size_t u4AvailSize, u4EventSize; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prEvent); ++ ++ /* check device */ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return; ++ ++/* u4AvailSize = ++ GLUE_BOW_KFIFO_DEPTH - kfifo_len(prGlueInfo->rBowInfo.prKfifo);*/ ++ ++ u4AvailSize = GLUE_BOW_KFIFO_DEPTH - kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); ++ ++ u4EventSize = prEvent->rHeader.u2PayloadLength + sizeof(AMPC_EVENT_HEADER_T); ++ ++ /* check kfifo availability */ ++ if (u4AvailSize < u4EventSize) { ++ DBGLOG(BOW, EVENT, "[bow] no space for event: %zu/%zu\n", u4EventSize, u4AvailSize); ++ return; ++ } ++ /* queue into kfifo */ ++/* kfifo_put(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ ++/* kfifo_in(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ ++ kfifo_in(&(prGlueInfo->rBowInfo.rKfifo), (PUINT_8) prEvent, u4EventSize); ++ wake_up_interruptible(&(prGlueInfo->rBowInfo.outq)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 i; ++ ++ ASSERT(prGlueInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalGetBowState.\n"); ++#endif ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalGetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalGetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, ++ prGlueInfo->rBowInfo.aeState[i]); ++ ++#endif ++ ++ return prGlueInfo->rBowInfo.aeState[i]; ++ } ++ } ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Bluetooth-over-Wi-Fi state in glue layer ++* ++* \param[in] ++* prGlueInfo ++* eBowState ++* rPeerAddr ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 i; ++ ++ ASSERT(prGlueInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalSetBowState.\n"); ++ ++ DBGLOG(BOW, EVENT, "kalSetBowState, prGlueInfo->rBowInfo.arPeerAddr, %x:%x:%x:%x:%x:%x.\n", ++ prGlueInfo->rBowInfo.arPeerAddr[0], ++ prGlueInfo->rBowInfo.arPeerAddr[1], ++ prGlueInfo->rBowInfo.arPeerAddr[2], ++ prGlueInfo->rBowInfo.arPeerAddr[3], ++ prGlueInfo->rBowInfo.arPeerAddr[4], prGlueInfo->rBowInfo.arPeerAddr[5])); ++ ++ DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5]); ++#endif ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { ++ prGlueInfo->rBowInfo.aeState[i] = eBowState; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalSetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, ++ prGlueInfo->rBowInfo.aeState[i]); ++#endif ++ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi global state ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* BOW_DEVICE_STATE_DISCONNECTED ++* in case there is no BoW connection or ++* BoW connection under initialization ++* ++* BOW_DEVICE_STATE_STARTING ++* in case there is no BoW connection but ++* some BoW connection under initialization ++* ++* BOW_DEVICE_STATE_CONNECTED ++* in case there is any BoW connection available ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ++/* Henry, can reduce this logic to indentify state change */ ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_CONNECTED) ++ return BOW_DEVICE_STATE_CONNECTED; ++ } ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_STARTING) ++ return BOW_DEVICE_STATE_STARTING; ++ } ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi operating frequency ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* in unit of KHz ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rBowInfo.u4FreqInKHz; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* 0: Responder ++* 1: Initiator ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) ++ return prGlueInfo->rBowInfo.aucRole[i]; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ucRole ++* 0: Responder ++* 1: Initiator ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ucRole <= 1); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) ++ prGlueInfo->rBowInfo.aucRole[i] = ucRole; /* Henry, 0 : Responder, 1 : Initiator */ ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get available Bluetooth-over-Wi-Fi physical link number ++* ++* \param[in] ++* prGlueInfo ++* \return ++* UINT_32 ++* how many physical links are aviailable ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 i; ++ UINT_8 ucLinkCount = 0; ++ ++ ASSERT(prGlueInfo); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_DISCONNECTED) ++ ucLinkCount++; ++ } ++ ++#if 0 /* CFG_BOW_TEST */ ++ DBGLOG(BOW, EVENT, "kalGetBowAvailablePhysicalLinkCount, ucLinkCount, %c.\n", ucLinkCount); ++#endif ++ ++ return ucLinkCount; ++} ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ ++/* Net Device Hooks */ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device open (ifup) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowOpen(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 2. carrier on & start TX queue */ ++ netif_carrier_on(prDev); ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device stop (ifdown) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowStop(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prDev); ++ ++ /* 2. turn of carrier */ ++ if (netif_carrier_ok(prDev)) ++ netif_carrier_off(prDev); ++ ++ return 0; ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function is TX entry point of NET DEVICE. ++ * ++ * \param[in] prSkb Pointer of the sk_buff to be sent ++ * \param[in] prDev Pointer to struct net_device ++ * ++ * \retval NETDEV_TX_OK - on success. ++ * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ UINT_16 u2QueueIdx = 0; ++ UINT_8 ucDSAP, ucSSAP, ucControl; ++ UINT_8 aucOUI[3]; ++ PUINT_8 aucLookAheadBuf = NULL; ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; ++ ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; ++ ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; ++ aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; ++ aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; ++ aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; ++ prGlueInfo->u8SkbToDriver++; ++ ++ if (!(ucDSAP == ETH_LLC_DSAP_SNAP && ++ ucSSAP == ETH_LLC_SSAP_SNAP && ++ ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && ++ aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && ++ aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) || (prSkb->len > 1514)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Invalid BOW packet, skip tx\n"); ++#endif ++ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(BOW, TRACE, "GLUE_FLAG_HALT skip tx\n"); ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Tx sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "Tx sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "Tx sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"; ++#endif ++#if CFG_BOW_TEST ++/* g_u4CurrentSysTime = (OS_SYSTIME)kalGetTimeTick(; */ ++ g_u4CurrentSysTime = (OS_SYSTIME) jiffies_to_usecs(jiffies); ++ i = g_u4CurrentSysTime - g_u4PrevSysTime; ++ if ((i >> 10) > 0) ++ i = 10; ++ else ++ i = i >> 7; ++ g_arBowRevPalPacketTime[i]++; ++ g_u4PrevSysTime = g_u4CurrentSysTime; ++#endif ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) ++ DBGLOG(TX, INFO, "netif_stop_subqueue for BOW, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); ++ ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ } else { ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ kalSetEvent(prGlueInfo); ++ /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ ++ return NETDEV_TX_OK; ++} ++ ++/* callbacks for netdevice */ ++static const struct net_device_ops bow_netdev_ops = { ++ .ndo_open = bowOpen, .ndo_stop = bowStop, .ndo_start_xmit = bowHardStartXmit,}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief initialize net device for Bluetooth-over-Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* prDevName ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName) ++{ ++ P_ADAPTER_T prAdapter; ++ P_GL_HIF_INFO_T prHif; ++ PARAM_MAC_ADDRESS rMacAddr; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ prHif = &prGlueInfo->rHifInfo; ++ ASSERT(prHif); ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered == FALSE) { ++ prGlueInfo->rBowInfo.prDevHandler = ++ alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prGlueInfo->rBowInfo.prDevHandler) ++ return FALSE; ++ ++ /* 1. setup netdev */ ++ /* 1.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->rBowInfo.prDevHandler)) = prGlueInfo; ++ /* 1.2 fill hardware address */ ++ COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] |= 0x2; ++ /* change to local administrated address */ ++ ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->dev_addr, rMacAddr); ++ ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->perm_addr, ++ prGlueInfo->rBowInfo.prDevHandler->dev_addr); ++ /* 1.3 register callback functions */ ++ prGlueInfo->rBowInfo.prDevHandler->netdev_ops = &bow_netdev_ops; ++#if (MTK_WCN_HIF_SDIO == 0) ++ SET_NETDEV_DEV(prGlueInfo->rBowInfo.prDevHandler, prHif->Dev); ++#endif ++ register_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ /* 2. net device initialize */ ++ netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); ++ /* 3. finish */ ++ prGlueInfo->rBowInfo.fgIsNetRegistered = TRUE; ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief uninitialize net device for Bluetooth-over-Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ /* ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); */ ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered == TRUE) { ++ prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; ++ if (netif_carrier_ok(prGlueInfo->rBowInfo.prDevHandler)) ++ netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); ++ ++ netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); ++ /* netdevice unregistration & free */ ++ unregister_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ free_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ prGlueInfo->rBowInfo.prDevHandler = NULL; ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++#endif /* CFG_BOW_SEPARATE_DATA_PATH */ ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c +new file mode 100644 +index 000000000000..1fed65ebc60e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c +@@ -0,0 +1,3110 @@ ++/* ++** Id: @(#) gl_cfg80211.c@@ ++*/ ++ ++/*! \file gl_cfg80211.c ++ \brief Main routines for supporintg MT6620 cfg80211 control interface ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_cfg80211.c ++** ++** 09 05 2013 cp.wu ++** correct length to pass to wlanoidSetBssid() ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 11 23 2012 yuche.tsai ++** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely ++** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include ++#include ++#include ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* workaround for some ANR CRs. if suppliant is blocked longer than 10s, wifi hal will tell wifiMonitor ++to teminate. for the case which can block supplicant 10s is to del key more than 5 times. the root cause ++is that there is no resource in TC4, so del key command was not able to set, and then oid ++timeout was happed. if we found the root cause why fw couldn't release TC resouce, we will remove this ++workaround */ ++static UINT_8 gucKeyIndex = 255; ++ ++P_SW_RFB_T g_arGscnResultsTempBuffer[MAX_BUFFERED_GSCN_RESULTS]; ++UINT_8 g_GscanResultsTempBufferIndex = 0; ++UINT_8 g_arGscanResultsIndicateNumber[MAX_BUFFERED_GSCN_RESULTS] = { 0, 0, 0, 0, 0 }; ++ ++UINT_8 g_GetResultsBufferedCnt = 0; ++UINT_8 g_GetResultsCmdCnt = 0; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for change STA type between ++ * 1. Infrastructure Client (Non-AP STA) ++ * 2. Ad-Hoc IBSS ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, enum nl80211_iftype type, /*u32 *flags,*/ struct vif_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (type == NL80211_IFTYPE_STATION) ++ eOpMode = NET_TYPE_INFRA; ++ else if (type == NL80211_IFTYPE_ADHOC) ++ eOpMode = NET_TYPE_IBSS; ++ else ++ return -EINVAL; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set infrastructure mode error:%x\n", rStatus); ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding key ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) ++{ ++ PARAM_KEY_T rKey; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Rslt = -EINVAL; ++ UINT_32 u4BufLen = 0; ++ UINT_8 tmp1[8]; ++ UINT_8 tmp2[8]; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(&rKey, sizeof(PARAM_KEY_T)); ++ ++ rKey.u4KeyIndex = key_index; ++ ++ if (mac_addr) { ++ COPY_MAC_ADDR(rKey.arBSSID, mac_addr); ++ if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && ++ (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ } ++ if (rKey.arBSSID[0] != 0xFF) { ++ rKey.u4KeyIndex |= BIT(31); ++ if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || ++ (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) ++ rKey.u4KeyIndex |= BIT(30); ++ } ++ } else { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ /* rKey.u4KeyIndex |= BIT(31);//Enable BIT 31 will make tx use bc key id,should use pairwise key id 0 */ ++ } ++ ++ if (params->key) { ++ /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ ++ kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); ++ if (params->key_len == 32) { ++ kalMemCopy(tmp1, ¶ms->key[16], 8); ++ kalMemCopy(tmp2, ¶ms->key[24], 8); ++ kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8); ++ kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8); ++ } ++ } ++ ++ rKey.u4KeyLength = params->key_len; ++ rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for getting key for specified STA ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *)) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for removing key for specified STA ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ PARAM_REMOVE_KEY_T rRemoveKey; ++ UINT_32 u4BufLen = 0; ++ INT_32 i4Rslt = -EINVAL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); ++ if (mac_addr) ++ COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); ++ else if (key_index <= gucKeyIndex) { /* new operation, reset gucKeyIndex */ ++ gucKeyIndex = 255; ++ } else { /* bypass the next remove key operation */ ++ gucKeyIndex = key_index; ++ return -EBUSY; ++ } ++ rRemoveKey.u4KeyIndex = key_index; ++ rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveKey, &rRemoveKey, rRemoveKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "remove key error:%x\n", rStatus); ++ if (WLAN_STATUS_FAILURE == rStatus && mac_addr) { ++ i4Rslt = -EBUSY; ++ gucKeyIndex = key_index; ++ } ++ } else { ++ gucKeyIndex = 255; ++ i4Rslt = 0; ++ } ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for setting default key on an interface ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for setting set_default_mgmt_ke on an interface ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for getting station information such as RSSI ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) ++{ ++#define LINKSPEED_MAX_RANGE_11BGN 3000 ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ PARAM_MAC_ADDRESS arBssid; ++ UINT_32 u4BufLen; ++ UINT_32 u4Rate = 0; ++ UINT_32 u8diffTxBad, u8diffRetry; ++ INT_32 i4Rssi = 0; ++ PARAM_802_11_STATISTICS_STRUCT_T rStatistics; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); ++ ++ /* 1. check BSSID */ ++ if (UNEQUAL_MAC_ADDR(arBssid, mac)) { ++ /* wrong MAC address */ ++ DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", ++ mac, arBssid); ++ return -ENOENT; ++ } ++ ++ /* 2. fill TX rate */ ++ if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { ++ /* not connected */ ++ DBGLOG(REQ, WARN, "not yet connected\n"); ++ } else { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); ++ ++ if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) { ++ /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n")); */ ++ DBGLOG(REQ, WARN, "last link speed\n"); ++ sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; ++ } else { ++ /* sinfo->filled |= STATION_INFO_TX_BITRATE; */ ++ sinfo->txrate.legacy = u4Rate / 1000; /* convert from 100bps to 100kbps */ ++ prGlueInfo->u4LinkSpeedCache = u4Rate / 1000; ++ } ++ } ++ ++ /* 3. fill RSSI */ ++ if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { ++ /* not connected */ ++ DBGLOG(REQ, WARN, "not yet connected\n"); ++ } else { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS || (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) ++ || (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { ++ /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n"); */ ++ DBGLOG(REQ, WARN, "last rssi\n"); ++ sinfo->signal = prGlueInfo->i4RssiCache; ++ } else { ++ /* in the cfg80211 layer, the signal is a signed char variable. */ ++ sinfo->signal = i4Rssi; /* dBm */ ++ prGlueInfo->i4RssiCache = i4Rssi; ++ } ++ sinfo->rx_packets = prGlueInfo->rNetDevStats.rx_packets; ++ ++ /* 4. Fill Tx OK and Tx Bad */ ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); ++ { ++ WLAN_STATUS rStatus; ++ ++ kalMemZero(&rStatistics, sizeof(rStatistics)); ++ /* Get Tx OK/Fail cnt from AIS statistic counter */ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatisticsPL, ++ &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "unable to retrieive statistic\n"); ++ } else { ++ INT_32 i4RssiThreshold = -85; /* set rssi threshold -85dBm */ ++ UINT_32 u4LinkspeedThreshold = 55; /* set link speed threshold 5.5Mbps */ ++ BOOLEAN fgWeighted = 0; ++ ++ /* calculate difference */ ++ u8diffTxBad = rStatistics.rFailedCount.QuadPart - prGlueInfo->u8Statistic[0]; ++ u8diffRetry = rStatistics.rRetryCount.QuadPart - prGlueInfo->u8Statistic[1]; ++ /* restore counters */ ++ prGlueInfo->u8Statistic[0] = rStatistics.rFailedCount.QuadPart; ++ prGlueInfo->u8Statistic[1] = rStatistics.rRetryCount.QuadPart; ++ ++ /* check threshold is valid */ ++ if (prGlueInfo->fgPoorlinkValid) { ++ if (prGlueInfo->i4RssiThreshold) ++ i4RssiThreshold = prGlueInfo->i4RssiThreshold; ++ if (prGlueInfo->u4LinkspeedThreshold) ++ u4LinkspeedThreshold = prGlueInfo->u4LinkspeedThreshold; ++ } ++ /* add weighted to fail counter */ ++ if (sinfo->txrate.legacy < u4LinkspeedThreshold || sinfo->signal < i4RssiThreshold) { ++ prGlueInfo->u8TotalFailCnt += (u8diffTxBad * 16 + u8diffRetry); ++ fgWeighted = 1; ++ } else { ++ prGlueInfo->u8TotalFailCnt += u8diffTxBad; ++ } ++ /* report counters */ ++ prGlueInfo->rNetDevStats.tx_packets = rStatistics.rTransmittedFragmentCount.QuadPart; ++ prGlueInfo->rNetDevStats.tx_errors = prGlueInfo->u8TotalFailCnt; ++ ++ sinfo->tx_packets = prGlueInfo->rNetDevStats.tx_packets; ++ sinfo->tx_failed = prGlueInfo->rNetDevStats.tx_errors; ++ /* Good Fail Bad Difference retry difference Linkspeed Rate Weighted */ ++ DBGLOG(REQ, TRACE, ++ "Poorlink State TxOK(%d) TxFail(%d) Bad(%d) Retry(%d)", ++ sinfo->tx_packets, ++ sinfo->tx_failed, ++ (int)u8diffTxBad, ++ (int)u8diffRetry); ++ DBGLOG(REQ, TRACE, ++ "Rate(%d) Signal(%d) Weight(%d) QuadPart(%d)\n", ++ sinfo->txrate.legacy, ++ sinfo->signal, ++ (int)fgWeighted, ++ (int)rStatistics.rMultipleRetryCount.QuadPart); ++ } ++ } ++ ++ } ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params) ++{ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* ++ EX: In supplicant, ++ (Supplicant) wpa_tdls_process_tpk_m3() -> ++ (Supplicant) wpa_tdls_enable_link() -> ++ (Supplicant) wpa_sm_tdls_peer_addset() -> ++ (Supplicant) ..tdls_peer_addset() -> ++ (Supplicant) wpa_supplicant_tdls_peer_addset() -> ++ (Supplicant) wpa_drv_sta_add() -> ++ (Supplicant) ..sta_add() -> ++ (Supplicant) wpa_driver_nl80211_sta_add() -> ++ (NL80211) nl80211_set_station() -> ++ (Driver) mtk_cfg80211_change_station() ++ ++ if nl80211_set_station fails, supplicant will tear down the link. ++ */ ++ P_GLUE_INFO_T prGlueInfo; ++ TDLS_CMD_PEER_UPDATE_T rCmdUpdate; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen, u4Temp; ++ ++ /* sanity check */ ++ if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) ++ return -EINVAL; ++ ++ DBGLOG(TDLS, INFO, "%s: 0x%p 0x%x\n", __func__, params->supported_rates, params->sta_flags_set); ++ ++ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) ++ return -EOPNOTSUPP; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) ++ return -EINVAL; ++ ++ /* TODO: check if we are station mode, not AP mode */ ++ ++ /* init */ ++ kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); ++ kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); ++ ++ if (params->supported_rates != NULL) { ++ u4Temp = params->supported_rates_len; ++ if (u4Temp > TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX) { ++ u4Temp = TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX; ++ DBGLOG(TDLS, ERROR, "%s sup rate too long: %d\n", __func__, params->supported_rates_len); ++ } ++ kalMemCopy(rCmdUpdate.aucSupRate, params->supported_rates, u4Temp); ++ rCmdUpdate.u2SupRateLen = u4Temp; ++ } ++ ++ /* ++ In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM ++ So force to support UAPSD here. ++ */ ++ rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */ ++ rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */ ++ ++ DBGLOG(TDLS, INFO, "%s: UapsdBitmap=0x%x UapsdMaxSp=%d\n", ++ __func__, rCmdUpdate.UapsdBitmap, rCmdUpdate.UapsdMaxSp); ++ ++ rCmdUpdate.u2Capability = params->capability; ++ ++ if (params->ext_capab != NULL) { ++ u4Temp = params->ext_capab_len; ++ if (u4Temp > TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN) { ++ u4Temp = TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN; ++ DBGLOG(TDLS, ERROR, "%s ext_capab too long: %d\n", __func__, params->ext_capab_len); ++ } ++ kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp); ++ rCmdUpdate.u2ExtCapLen = u4Temp; ++ } ++ ++ if (params->ht_capa != NULL) { ++ DBGLOG(TDLS, INFO, "%s: peer is 11n device\n", __func__); ++ ++ rCmdUpdate.rHtCap.u2CapInfo = params->ht_capa->cap_info; ++ rCmdUpdate.rHtCap.ucAmpduParamsInfo = params->ht_capa->ampdu_params_info; ++ rCmdUpdate.rHtCap.u2ExtHtCapInfo = params->ht_capa->extended_ht_cap_info; ++ rCmdUpdate.rHtCap.u4TxBfCapInfo = params->ht_capa->tx_BF_cap_info; ++ rCmdUpdate.rHtCap.ucAntennaSelInfo = params->ht_capa->antenna_selection_info; ++ kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask, ++ params->ht_capa->mcs.rx_mask, sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask)); ++ rCmdUpdate.rHtCap.rMCS.u2RxHighest = params->ht_capa->mcs.rx_highest; ++ rCmdUpdate.rHtCap.rMCS.ucTxParams = params->ht_capa->mcs.tx_params; ++ rCmdUpdate.fgIsSupHt = TRUE; ++ } ++ ++ /* update a TDLS peer record */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexPeerUpdate, ++ &rCmdUpdate, sizeof(TDLS_CMD_PEER_UPDATE_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s update error:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params) ++{ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ ++ P_GLUE_INFO_T prGlueInfo; ++ TDLS_CMD_PEER_ADD_T rCmdCreate; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) ++ return -EINVAL; ++ ++ /* ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, ++ NULL, 0); ++ ++ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, ++ u16 aid, u16 capability, const u8 *supp_rates, ++ size_t supp_rates_len, ++ const struct ieee80211_ht_capabilities *ht_capab, ++ const struct ieee80211_vht_capabilities *vht_capab, ++ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) ++ ++ Only MAC address of the peer is valid. ++ */ ++ ++ DBGLOG(TDLS, INFO, "%s: 0x%p %d\n", __func__, params->supported_rates, params->supported_rates_len); ++ ++ /* sanity check */ ++ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) ++ return -EOPNOTSUPP; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) ++ return -EINVAL; ++ ++ /* TODO: check if we are station mode, not AP mode */ ++ ++ /* init */ ++ kalMemZero(&rCmdCreate, sizeof(rCmdCreate)); ++ kalMemCopy(rCmdCreate.aucPeerMac, mac, 6); ++ ++#if 0 ++ rCmdCreate.eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ rCmdCreate.u2CapInfo = params->capability; ++ ++ DBGLOG(TDLS, INFO, " %s: capability = 0x%x\n", __func__, rCmdCreate.u2CapInfo); ++ ++ if ((params->supported_rates != NULL) && (params->supported_rates_len != 0)) { ++ UINT32 u4Idx; ++ ++ DBGLOG(TDLS, INFO, " %s: sup rate = 0x", __func__); ++ ++ rIeSup.ucId = ELEM_ID_SUP_RATES; ++ rIeSup.ucLength = params->supported_rates_len; ++ for (u4Idx = 0; u4Idx < rIeSup.ucLength; u4Idx++) { ++ rIeSup.aucSupportedRates[u4Idx] = params->supported_rates[u4Idx]; ++ DBGLOG(TDLS, INFO, "%x ", rIeSup.aucSupportedRates[u4Idx]); ++ } ++ DBGLOG(TDLS, INFO, "\n"); ++ ++ rateGetRateSetFromIEs(&rIeSup, ++ NULL, ++ &rCmdCreate.u2OperationalRateSet, ++ &rCmdCreate.u2BSSBasicRateSet, &rCmdCreate.fgIsUnknownBssBasicRate); ++ } ++ ++ /* phy type */ ++#endif ++ ++ /* create a TDLS peer record */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexPeerAdd, ++ &rCmdCreate, sizeof(TDLS_CMD_PEER_ADD_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s create error:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for deleting a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ * ++ * @other ++ * must implement if you have add_station(). ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params) ++//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to do a scan ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++static PARAM_SCAN_REQUEST_EXT_T rScanRequest; ++int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++/* PARAM_SCAN_REQUEST_EXT_T rScanRequest; */ ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "mtk_cfg80211_scan\n"); ++ kalMemZero(&rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T)); ++ ++ /* check if there is any pending scan not yet finished */ ++ if (prGlueInfo->prScanRequest != NULL) { ++ DBGLOG(REQ, ERROR, "prGlueInfo->prScanRequest != NULL\n"); ++ return -EBUSY; ++ } ++ ++ if (request->n_ssids == 0) { ++ rScanRequest.rSsid.u4SsidLen = 0; ++ } else if (request->n_ssids == 1) { ++ COPY_SSID(rScanRequest.rSsid.aucSsid, rScanRequest.rSsid.u4SsidLen, request->ssids[0].ssid, ++ request->ssids[0].ssid_len); ++ } else { ++ DBGLOG(REQ, ERROR, "request->n_ssids:%d\n", request->n_ssids); ++ return -EINVAL; ++ } ++ ++ if (request->ie_len > 0) { ++ rScanRequest.u4IELength = request->ie_len; ++ rScanRequest.pucIE = (PUINT_8) (request->ie); ++ } else { ++ rScanRequest.u4IELength = 0; ++ } ++#if 0 ++ prGlueInfo->prScanRequest = request; ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScanExt, ++ &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); ++ prGlueInfo->prScanRequest = NULL; ++ return -EINVAL; ++ } ++ ++ /*prGlueInfo->prScanRequest = request;*/ ++#endif ++ ++ prGlueInfo->prScanRequest = request; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScanExt, ++ &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ prGlueInfo->prScanRequest = NULL; ++ DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static UINT_8 wepBuf[48]; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to connect to ++ * the ESS with the specified parameters ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ UINT_32 cipher; ++ PARAM_CONNECT_T rNewSsid; ++ BOOLEAN fgCarryWPSIE = FALSE; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "[wlan] mtk_cfg80211_connect %p %zu\n", sme->ie, sme->ie_len); ++ ++ if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode > NET_TYPE_AUTO_SWITCH) ++ eOpMode = NET_TYPE_AUTO_SWITCH; ++ else ++ eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetInfrastructureMode fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* after set operation mode, key table are cleared */ ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA; ++ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2; ++ else ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ ++ switch (sme->auth_type) { ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ default: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY; ++ break; ++ } ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] = ++ sme->crypto.ciphers_pairwise[0]; ++ switch (sme->crypto.ciphers_pairwise[0]) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP40; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_TKIP; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ } ++ ++ if (sme->crypto.cipher_group) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite = sme->crypto.cipher_group; ++ switch (sme->crypto.cipher_group) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP40; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_TKIP; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ if (sme->crypto.n_akm_suites) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] = ++ sme->crypto.akm_suites[0]; ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ eAuthMode = AUTH_MODE_WPA; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ eAuthMode = AUTH_MODE_WPA_PSK; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } else if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ eAuthMode = AUTH_MODE_WPA2; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ eAuthMode = AUTH_MODE_WPA2_PSK; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? ++ AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; ++ } ++ ++ prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy; ++ ++ prGlueInfo->fgWpsActive = FALSE; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ prGlueInfo->fgConnectHS20AP = FALSE; ++#endif ++ ++ if (sme->ie && sme->ie_len > 0) { ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ PUINT_8 prDesiredIE = NULL; ++ PUINT_8 pucIEStart = (PUINT_8)sme->ie; ++ ++#if CFG_SUPPORT_WAPI ++ if (wextSrchDesiredWAPIIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiAssocInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(SEC, WARN, "[wapi] set wapi assoc info error:%x\n", rStatus); ++ } ++#endif ++ ++ DBGLOG(REQ, TRACE, "[wlan] wlanoidSetWapiAssocInfo: .fgWapiMode = %d\n", ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.fgWapiMode); ++ ++#if CFG_SUPPORT_WPS2 ++ if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ prGlueInfo->fgWpsActive = TRUE; ++ fgCarryWPSIE = TRUE; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWSCAssocInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(SEC, WARN, "WSC] set WSC assoc info error:%x\n", rStatus); ++ } ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (wextSrchDesiredHS20IE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetHS20Info, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ if (wextSrchDesiredInterworkingIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInterworkingInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ if (wextSrchDesiredRoamingConsortiumIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingConsortiumIEInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++ } ++ ++ /* clear WSC Assoc IE buffer in case WPS IE is not detected */ ++ if (fgCarryWPSIE == FALSE) { ++ kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); ++ prGlueInfo->u2WSCAssocInfoIELen = 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus); ++ ++ cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; ++ ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { ++ if (cipher & IW_AUTH_CIPHER_CCMP) { ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_TKIP) { ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_NONE) { ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } else { ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ } else { ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set encryption mode error:%x\n", rStatus); ++ ++ if (sme->key_len != 0 && prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ prWepKey->u4Length = 12 + sme->key_len; ++ prWepKey->u4KeyLength = (UINT_32) sme->key_len; ++ prWepKey->u4KeyIndex = (UINT_32) sme->key_idx; ++ prWepKey->u4KeyIndex |= BIT(31); ++ if (prWepKey->u4KeyLength > 32) { ++ DBGLOG(REQ, ERROR, "Too long key length (%u)\n", prWepKey->u4KeyLength); ++ return -EINVAL; ++ } ++ kalMemCopy(prWepKey->aucKeyMaterial, sme->key, prWepKey->u4KeyLength); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ } ++ ++ if (sme->channel) ++ rNewSsid.u4CenterFreq = sme->channel->center_freq; ++ else ++ rNewSsid.u4CenterFreq = 0; ++ rNewSsid.pucBssid = (UINT_8 *)sme->bssid; ++ rNewSsid.pucSsid = (UINT_8 *)sme->ssid; ++ rNewSsid.u4SsidLen = sme->ssid_len; ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetConnect, ++ (PVOID)(&rNewSsid), sizeof(PARAM_CONNECT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "set SSID:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to disconnect from ++ * currently connected ESS ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to join an IBSS group ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) ++{ ++ PARAM_SSID_T rNewSsid; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4ChnlFreq; /* Store channel or frequency information */ ++ UINT_32 u4BufLen = 0; ++ WLAN_STATUS rStatus; ++ struct ieee80211_channel *channel = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* set channel */ ++ if (params->chandef.chan) ++ channel = params->chandef.chan; ++ if (channel) { ++ u4ChnlFreq = nicChannelNum2Freq(channel->hw_value); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetFrequency, ++ &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ } ++ ++ /* set SSID */ ++ kalMemCopy(rNewSsid.aucSsid, params->ssid, params->ssid_len); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetSsid, ++ (PVOID)(&rNewSsid), sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to leave from IBSS group ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to configure ++ * WLAN power managemenet ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ PARAM_POWER_MODE ePowerMode; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (enabled) { ++ if (timeout == -1) ++ ePowerMode = Param_PowerModeFast_PSP; ++ else ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else { ++ ePowerMode = Param_PowerModeCAM; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSet802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set_power_mgmt error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cache ++ * a PMKID for a BSSID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); ++ return -ENOMEM; ++ } ++ ++ prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); ++ prPmkid->u4BSSIDInfoCount = 1; ++ kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, pmksa->bssid, 6); ++ kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, pmksa->pmkid, IW_PMKID_LEN); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "add pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to remove ++ * a cached PMKID for a BSSID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) ++{ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to flush ++ * all cached PMKID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_FLUSH\n"); ++ return -ENOMEM; ++ } ++ ++ prPmkid->u4Length = 8; ++ prPmkid->u4BSSIDInfoCount = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "flush pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8); ++ ++ return 0; ++} ++ ++void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ IN struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg) ++{ ++#if 0 ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++#endif ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ ++ DBGLOG(REQ, LOUD, "mtk_cfg80211_mgmt_frame_register\n"); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ switch (frame_type) { ++ case MAC_FRAME_PROBE_REQ: ++ if (reg) { ++ prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(REQ, LOUD, "Open packet filer probe request\n"); ++ } else { ++ prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(REQ, LOUD, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (reg) { ++ prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(REQ, LOUD, "Open packet filer action frame.\n"); ++ } else { ++ prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(REQ, LOUD, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(REQ, TRACE, "Ask frog to add code for mgmt:%x\n", frame_type); ++ break; ++ } ++ ++ if (prGlueInfo->prAdapter != NULL) { ++ /* prGlueInfo->ulFlag |= GLUE_FLAG_FRAME_FILTER_AIS; */ ++ set_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ if (in_interrupt()) ++ DBGLOG(REQ, TRACE, "It is in interrupt level\n"); ++ } ++#if 0 ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof ++ (MSG_P2P_MGMT_FRAME_REGISTER_T)); ++ ++ if (prMgmtFrameRegister == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; ++ ++ prMgmtFrameRegister->u2FrameType = frame_type; ++ prMgmtFrameRegister->fgIsRegister = reg; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); ++ ++#endif ++ ++ } while (FALSE); ++ ++} /* mtk_cfg80211_mgmt_frame_register */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to stay on a ++ * specified channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_REMAIN_ON_CHANNEL_T prMsgChnlReq = (P_MSG_REMAIN_ON_CHANNEL_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ *cookie = prGlueInfo->u8Cookie++; ++ ++ prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_REMAIN_ON_CHANNEL_T)); ++ ++ if (prMsgChnlReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ kalMemZero(prMsgChnlReq, sizeof(MSG_REMAIN_ON_CHANNEL_T)); ++ ++ prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_AIS_REMAIN_ON_CHANNEL; ++ prMsgChnlReq->u8Cookie = *cookie; ++ prMsgChnlReq->u4DurationMs = duration; ++ ++ prMsgChnlReq->ucChannelNum = nicFreq2ChannelNum(chan->center_freq * 1000); ++ ++ switch (chan->band) { ++ case NL80211_BAND_2GHZ: ++ prMsgChnlReq->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prMsgChnlReq->eBand = BAND_5G; ++ break; ++ default: ++ prMsgChnlReq->eBand = BAND_2G4; ++ break; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cancel staying ++ * on a specified channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prMsgChnlAbort = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ prMsgChnlAbort = ++ cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_CANCEL_REMAIN_ON_CHANNEL_T)); ++ ++ if (prMsgChnlAbort == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL; ++ prMsgChnlAbort->u8Cookie = cookie; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to send a management frame ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T) NULL; ++ P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucFrameBuf = (PUINT_8) NULL; ++ ++ do { ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ *cookie = prGlueInfo->u8Cookie++; ++ ++ /* Channel & Channel Type & Wait time are ignored. */ ++ prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_MGMT_TX_REQUEST_T)); ++ ++ if (prMsgTxReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->fgNoneCckRate = FALSE; ++ prMsgTxReq->fgIsWaitRsp = TRUE; ++ ++ prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); ++ prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; ++ if (prMsgTxReq->prMgmtMsduInfo == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->u8Cookie = *cookie; ++ prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX; ++ ++ pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucFrameBuf, params->buf, params->len); ++ ++ prMgmtFrame->u2FrameLength = params->len; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { ++ if (prMsgTxReq->prMgmtMsduInfo != NULL) ++ cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); ++ ++ cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); ++ } ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cancel the wait time ++ * from transmitting a management frame on another channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for handling sched_scan start/stop request ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++ ++int ++mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 i, u4BufLen; ++ P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ ASSERT(prGlueInfo); ++ ++ /* check if there is any pending scan/sched_scan not yet finished */ ++ if (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL) { ++ DBGLOG(SCN, ERROR, "(prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)\n"); ++ return -EBUSY; ++ } else if (request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM) { ++ DBGLOG(SCN, ERROR, "(request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM)\n"); ++ /* invalid scheduled scan request */ ++ return -EINVAL; ++ } else if (/* !request->n_ssids || */!request->n_match_sets) { ++ /* invalid scheduled scan request */ ++ return -EINVAL; ++ } ++ ++ prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) kalMemAlloc(sizeof(PARAM_SCHED_SCAN_REQUEST), VIR_MEM_TYPE); ++ if (prSchedScanRequest == NULL) { ++ DBGLOG(SCN, ERROR, "(prSchedScanRequest == NULL) kalMemAlloc fail\n"); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST)); ++ ++ prSchedScanRequest->u4SsidNum = request->n_match_sets; ++ for (i = 0; i < request->n_match_sets; i++) { ++ if (request->match_sets == NULL || &(request->match_sets[i]) == NULL) { ++ prSchedScanRequest->arSsid[i].u4SsidLen = 0; ++ } else { ++ COPY_SSID(prSchedScanRequest->arSsid[i].aucSsid, ++ prSchedScanRequest->arSsid[i].u4SsidLen, ++ request->match_sets[i].ssid.ssid, request->match_sets[i].ssid.ssid_len); ++ } ++ } ++ ++ prSchedScanRequest->u4IELength = request->ie_len; ++ if (request->ie_len > 0) ++ prSchedScanRequest->pucIE = (PUINT_8) (request->ie); ++ ++ prSchedScanRequest->u2ScanInterval = (UINT_16) (request->scan_plans[0].interval); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetStartSchedScan, ++ prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ kalMemFree(prSchedScanRequest, VIR_MEM_TYPE, sizeof(PARAM_SCHED_SCAN_REQUEST)); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(SCN, ERROR, "scheduled scan error:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ prGlueInfo->prSchedScanRequest = request; ++ ++ return 0; ++} ++ ++int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev, u64 reqid) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* check if there is any pending scan/sched_scan not yet finished */ ++ if (prGlueInfo->prSchedScanRequest == NULL) { ++ DBGLOG(SCN, ERROR, "prGlueInfo->prSchedScanRequest == NULL\n"); ++ return -EBUSY; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(SCN, ERROR, "scheduled scan error, rStatus: %d\n", rStatus); ++ return -EINVAL; ++ } ++ ++ /* 1. reset first for newly incoming request */ ++ /* GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ ++ if (prGlueInfo->prSchedScanRequest != NULL) ++ prGlueInfo->prSchedScanRequest = NULL; ++ /* GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ ++ ++ DBGLOG(SCN, TRACE, "start work queue to send event\n"); ++ schedule_delayed_work(&sched_workq, 0); ++ DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for handling association request ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_MAC_ADDRESS arBssid; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ PUINT_8 prDesiredIE = NULL; ++#endif ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); ++ ++ /* 1. check BSSID */ ++ if (UNEQUAL_MAC_ADDR(arBssid, req->bss->bssid)) { ++ /* wrong MAC address */ ++ DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", ++ req->bss->bssid, arBssid); ++ return -ENOENT; ++ } ++ ++ if (req->ie && req->ie_len > 0) { ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (wextSrchDesiredHS20IE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetHS20Info, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ ++ if (wextSrchDesiredInterworkingIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInterworkingInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ ++ if (wextSrchDesiredRoamingConsortiumIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingConsortiumIEInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssid, ++ (PVOID) req->bss->bssid, MAC_ADDR_LEN, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++#if CONFIG_NL80211_TESTMODE ++/* ++#define NLA_PUT(skb, attrtype, attrlen, data) \ ++do { \ ++ if (unlikely(nla_put(skb, attrtype, attrlen, data) < 0)) \ ++ goto nla_put_failure; \ ++} while (0) ++ ++#define NLA_PUT_TYPE(skb, type, attrtype, value) \ ++do { \ ++ type __tmp = value; \ ++ NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \ ++} while (0) ++ ++#define NLA_PUT_U8(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u8, attrtype, value) ++ ++#define NLA_PUT_U16(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u16, attrtype, value) ++ ++#define NLA_PUT_U32(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u32, attrtype, value) ++ ++#define NLA_PUT_U64(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u64, attrtype, value) ++*/ ++#if CFG_SUPPORT_WAPI ++int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SET_KEY_EXTS prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) NULL; ++ struct iw_encode_exts *prIWEncExt = (struct iw_encode_exts *)NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4BufLen = 0; ++ ++ P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_key_ext, data is NULL\n"); ++ return -EINVAL; ++ } ++ ++ if (prParams) ++ prIWEncExt = (struct iw_encode_exts *)&prParams->ext; ++ ++ if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { ++ /* KeyID */ ++ prWpiKey->ucKeyID = prParams->key_index; ++ prWpiKey->ucKeyID--; ++ if (prWpiKey->ucKeyID > 1) { ++ /* key id is out of range */ ++ /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ ++ return -EINVAL; ++ } ++ ++ if (prIWEncExt->key_len != 32) { ++ /* key length not valid */ ++ /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ ++ return -EINVAL; ++ } ++ /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ ++ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX; ++ } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX_TX; ++ } ++/* #if CFG_SUPPORT_WAPI */ ++ /* handle_sec_msg_final(prIWEncExt->key, 32, prIWEncExt->key, NULL); */ ++/* #endif */ ++ /* PN */ ++ memcpy(prWpiKey->aucPN, prIWEncExt->tx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ memcpy(prWpiKey->aucPN + IW_ENCODE_SEQ_MAX_SIZE, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ ++ ++ /* BSSID */ ++ memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr, 6); ++ ++ memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); ++ prWpiKey->u4LenWPIEK = 16; ++ ++ memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); ++ prWpiKey->u4LenWPICK = 16; ++ ++ rstatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiKey, ++ prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rstatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ ++ fgIsValid = -EFAULT; ++ } ++ ++ } ++ return fgIsValid; ++} ++#endif ++ ++int ++mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen; ++ UINT_32 u4LinkScore; ++ UINT_32 u4TotalError; ++ UINT_32 u4TxExceedThresholdCount; ++ UINT_32 u4TxTotalCount; ++ ++ P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; ++ PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS) data; ++ } else { ++ DBGLOG(QM, ERROR, "mtk_cfg80211_testmode_get_sta_statistics, data is NULL\n"); ++ return -EINVAL; ++ } ++/* ++ if (!prParams->aucMacAddr) { ++ DBGLOG(QM, INFO, "%s MAC Address is NULL\n", __func__); ++ return -EINVAL; ++ } ++*/ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); ++ ++ if (!skb) { ++ DBGLOG(QM, ERROR, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(QM, TRACE, "Get [ %pM ] STA statistics\n", prParams->aucMacAddr); ++ ++ kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); ++ COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, prParams->aucMacAddr); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStaStatistics, ++ &rQueryStaStatistics, sizeof(rQueryStaStatistics), TRUE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ /* Calcute Link Score */ ++ u4TxExceedThresholdCount = rQueryStaStatistics.u4TxExceedThresholdCount; ++ u4TxTotalCount = rQueryStaStatistics.u4TxTotalCount; ++ u4TotalError = rQueryStaStatistics.u4TxFailCount + rQueryStaStatistics.u4TxLifeTimeoutCount; ++ ++ /* u4LinkScore 10~100 , ExceedThreshold ratio 0~90 only */ ++ /* u4LinkScore 0~9 , Drop packet ratio 0~9 and all packets exceed threshold */ ++ if (u4TxTotalCount) { ++ if (u4TxExceedThresholdCount <= u4TxTotalCount) ++ u4LinkScore = (90 - ((u4TxExceedThresholdCount * 90) / u4TxTotalCount)); ++ else ++ u4LinkScore = 0; ++ } else { ++ u4LinkScore = 90; ++ } ++ ++ u4LinkScore += 10; ++ ++ if (u4LinkScore == 10) { ++ ++ if (u4TotalError <= u4TxTotalCount) ++ u4LinkScore = (10 - ((u4TotalError * 10) / u4TxTotalCount)); ++ else ++ u4LinkScore = 0; ++ ++ } ++ ++ if (u4LinkScore > 100) ++ u4LinkScore = 100; ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, NL80211_DRIVER_TESTMODE_VERSION);*/ ++ { ++ unsigned char __tmp = NL80211_DRIVER_TESTMODE_VERSION; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, u4LinkScore); */ ++ { ++ unsigned int __tmp = u4LinkScore; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, prParams->aucMacAddr);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, &prParams->aucMacAddr) < 0)) ++ goto nla_put_failure; ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, rQueryStaStatistics.u4Flag);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4Flag; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ /* FW part STA link status */ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_PER, rQueryStaStatistics.ucPer);*/ ++ { ++ unsigned char __tmp = rQueryStaStatistics.ucPer; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PER, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, rQueryStaStatistics.ucRcpi);*/ ++ { ++ unsigned char __tmp = rQueryStaStatistics.ucRcpi; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, rQueryStaStatistics.u4PhyMode);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4PhyMode; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U16(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, rQueryStaStatistics.u2LinkSpeed);*/ ++ { ++ unsigned short __tmp = rQueryStaStatistics.u2LinkSpeed; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, ++ sizeof(unsigned short), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, rQueryStaStatistics.u4TxFailCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxFailCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, rQueryStaStatistics.u4TxLifeTimeoutCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxLifeTimeoutCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, rQueryStaStatistics.u4TxAverageAirTime);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageAirTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* Driver part link status */ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, rQueryStaStatistics.u4TxTotalCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxTotalCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ rQueryStaStatistics.u4TxExceedThresholdCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxExceedThresholdCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ rQueryStaStatistics.u4TxAverageProcessTime);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageProcessTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxMaxTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageHifTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxMaxHifTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, rQueryStaStatistics.u4EnqueueCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4EnqueueCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, rQueryStaStatistics.u4DequeueCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4DequeueCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, rQueryStaStatistics.u4EnqueueStaCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4EnqueueStaCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, rQueryStaStatistics.u4DequeueStaCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4DequeueStaCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, rQueryStaStatistics.IsrCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, rQueryStaStatistics.IsrPassCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrPassCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, rQueryStaStatistics.TaskIsrCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.TaskIsrCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, rQueryStaStatistics.IsrAbnormalCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrAbnormalCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, rQueryStaStatistics.IsrSoftWareCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrSoftWareCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, rQueryStaStatistics.IsrTxCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrTxCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ *NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, rQueryStaStatistics.IsrRxCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrRxCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* Network counter */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), rQueryStaStatistics.au4TcResourceEmptyCount);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), &rQueryStaStatistics.au4TcResourceEmptyCount) < 0)) ++ goto nla_put_failure; ++ /* ++ NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ sizeof(rQueryStaStatistics.au4DequeueNoTcResource), rQueryStaStatistics.au4DequeueNoTcResource); ++ */ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ sizeof(rQueryStaStatistics.au4DequeueNoTcResource), &rQueryStaStatistics.au4DequeueNoTcResource) < 0)) ++ goto nla_put_failure; ++ /* ++ NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceBackCount), rQueryStaStatistics.au4TcResourceBackCount); ++ */ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceBackCount), &rQueryStaStatistics.au4TcResourceBackCount) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceUsedCount), &rQueryStaStatistics.au4TcResourceUsedCount) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceWantedCount), ++ &rQueryStaStatistics.au4TcResourceWantedCount) < 0)) ++ goto nla_put_failure; ++ ++ /* Sta queue length */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcQueLen), rQueryStaStatistics.au4TcQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcQueLen), &rQueryStaStatistics.au4TcQueLen) < 0)) ++ goto nla_put_failure; ++ ++ ++ /* Global QM counter */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcAverageQueLen), rQueryStaStatistics.au4TcAverageQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcAverageQueLen), &rQueryStaStatistics.au4TcAverageQueLen) < 0)) ++ goto nla_put_failure; ++ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcCurrentQueLen), rQueryStaStatistics.au4TcCurrentQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcCurrentQueLen), &rQueryStaStatistics.au4TcCurrentQueLen) < 0)) ++ goto nla_put_failure; ++ ++ ++ /* Reserved field */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ sizeof(rQueryStaStatistics.au4Reserved), rQueryStaStatistics.au4Reserved);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ sizeof(rQueryStaStatistics.au4Reserved), &rQueryStaStatistics.au4Reserved) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int ++mtk_cfg80211_testmode_get_link_detection(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen; ++ ++ PARAM_802_11_STATISTICS_STRUCT_T rStatistics; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); ++ ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rStatistics, sizeof(rStatistics)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, rStatistics.rFailedCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFailedCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, rStatistics.rRetryCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFailedCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, rStatistics.rMultipleRetryCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rMultipleRetryCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, rStatistics.rACKFailureCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rACKFailureCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, rStatistics.rFCSErrorCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFCSErrorCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if (prParams) { ++ if (prParams->set == 1) { ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, ++ &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct wpa_driver_hs20_data_s *prParams = NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) { ++ prParams = (struct wpa_driver_hs20_data_s *)data; ++ ++ DBGLOG(REQ, TRACE, "[%s] Cmd Type (%d)\n", __func__, prParams->CmdType); ++ } ++ ++ if (prParams) { ++ int i; ++ ++ switch (prParams->CmdType) { ++ case HS20_CMD_ID_SET_BSSID_POOL: ++ DBGLOG(REQ, TRACE, "fgBssidPoolIsEnable=%d, ucNumBssidPool=%d\n", ++ prParams->hs20_set_bssid_pool.fgBssidPoolIsEnable, ++ prParams->hs20_set_bssid_pool.ucNumBssidPool); ++ for (i = 0; i < prParams->hs20_set_bssid_pool.ucNumBssidPool; i++) { ++ DBGLOG(REQ, TRACE, "[%d][ %pM ]\n", i, ++ (prParams->hs20_set_bssid_pool.arBssidPool[i])); ++ } ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetHS20BssidPool, ++ &prParams->hs20_set_bssid_pool, ++ sizeof(struct param_hs20_set_bssid_pool), ++ FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ break; ++ default: ++ DBGLOG(REQ, TRACE, "[%s] Unknown Cmd Type (%d)\n", __func__, prParams->CmdType); ++ rstatus = WLAN_STATUS_FAILURE; ++ ++ } ++ ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#endif ++int ++mtk_cfg80211_testmode_set_poorlink_param(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ int fgIsValid = 0; ++ P_NL80211_DRIVER_POORLINK_PARAMS prParams = NULL; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_POORLINK_PARAMS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_poorlink_param, data is NULL\n"); ++ return -EINVAL; ++ } ++ if (prParams->ucLinkSpeed) ++ prGlueInfo->u4LinkspeedThreshold = prParams->ucLinkSpeed * 10; ++ if (prParams->cRssi) ++ prGlueInfo->i4RssiThreshold = prParams->cRssi; ++ if (!prGlueInfo->fgPoorlinkValid) ++ prGlueInfo->fgPoorlinkValid = 1; ++#if 0 ++ DBGLOG(REQ, TRACE, "poorlink set param valid(%d)rssi(%d)linkspeed(%d)\n", ++ prGlueInfo->fgPoorlinkValid, prGlueInfo->i4RssiThreshold, prGlueInfo->u4LinkspeedThreshold); ++#endif ++ ++ return fgIsValid; ++ ++} ++ ++int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) NULL; ++ INT_32 i4Status = -EINVAL; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ BOOLEAN fgIsValid = 0; ++#endif ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd, data is NULL\n"); ++ return i4Status; ++ } ++ ++ /* Clear the version byte */ ++ prParams->index = prParams->index & ~BITS(24, 31); ++ ++ if (prParams) { ++ switch (prParams->index) { ++ case TESTMODE_CMD_ID_SW_CMD: /* SW cmd */ ++ i4Status = mtk_cfg80211_testmode_sw_cmd(wiphy, data, len); ++ break; ++ case TESTMODE_CMD_ID_WAPI: /* WAPI */ ++#if CFG_SUPPORT_WAPI ++ i4Status = mtk_cfg80211_testmode_set_key_ext(wiphy, data, len); ++#endif ++ break; ++ case TESTMODE_CMD_ID_SUSPEND: ++ { ++ P_NL80211_DRIVER_SUSPEND_PARAMS prParams = (P_NL80211_DRIVER_SUSPEND_PARAMS) data; ++ ++ if (prParams->suspend == 1) { ++ wlanHandleSystemSuspend(); ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pHandleSystemSuspend(); ++ i4Status = 0; ++ } else if (prParams->suspend == 0) { ++ wlanHandleSystemResume(); ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pHandleSystemResume(); ++ i4Status = 0; ++ } ++ break; ++ } ++ case TESTMODE_CMD_ID_STATISTICS: ++ i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); ++ break; ++ case TESTMODE_CMD_ID_LINK_DETECT: ++ i4Status = mtk_cfg80211_testmode_get_link_detection(wiphy, data, len, prGlueInfo); ++ break; ++ case TESTMODE_CMD_ID_POORLINK: ++ i4Status = mtk_cfg80211_testmode_set_poorlink_param(wiphy, data, len, prGlueInfo); ++ break; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ case TESTMODE_CMD_ID_HS20: ++ if (mtk_cfg80211_testmode_hs20_cmd(wiphy, data, len)) ++ fgIsValid = TRUE; ++ break; ++#endif ++ default: ++ i4Status = -EINVAL; ++ break; ++ } ++ } ++ ++ return i4Status; ++} ++ ++int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++#define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0 ++#define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1 ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL, READY_TO_BEAM = 0; ++ ++/* P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; */ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(UINT_32)); ++ READY_TO_BEAM = ++ (UINT_32) (prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo. ++ fgIsGOInitialDone) & ++ (!prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); ++ DBGLOG(QM, TRACE, ++ "NFC:GOInitialDone[%d] and P2PScanning[%d]\n", ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone, ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); ++ ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, READY_TO_BEAM);*/ ++ { ++ unsigned int __tmp = READY_TO_BEAM; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++int ++mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++#define MAXMUN_2_4G_CHA_NUM 14 ++#define CHN_DIRTY_WEIGHT_UPPERBOUND 4 ++ ++ BOOLEAN fgIsReady = FALSE, fgIsFistRecord = TRUE; ++ BOOLEAN fgIsPureAP, fgIsLteSafeChn = FALSE; ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_8 ucIdx = 0, ucMax_24G_Chn_List = 11, ucDefaultIdx = 0, ucArrayIdx = 0; ++ UINT_16 u2APNumScore = 0, u2UpThreshold = 0, u2LowThreshold = 0, ucInnerIdx = 0; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen, u4LteSafeChnBitMask_2_4G = 0; ++ UINT32 AcsChnReport[4]; ++ /*RF_CHANNEL_INFO_T aucChannelList[MAXMUN_2_4G_CHA_NUM];*/ ++ ++ struct sk_buff *skb; ++ ++ /*PARAM_GET_CHN_LOAD rQueryLTEChn;*/ ++ P_PARAM_GET_CHN_LOAD prQueryLTEChn; ++ PARAM_PREFER_CHN_INFO rPreferChannels[2], ar2_4G_ChannelLoadingWeightScore[MAXMUN_2_4G_CHA_NUM]; ++ P_PARAM_CHN_LOAD_INFO prChnLoad; ++ P_PARAM_GET_CHN_LOAD prGetChnLoad; ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++/* ++ P_PARAM_GET_CHN_LOAD prParams = NULL; ++*/ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(rPreferChannels, sizeof(rPreferChannels)); ++ fgIsPureAP = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++#if 0 ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_GET_LTE_PARAMS) data; ++#endif ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(AcsChnReport) + sizeof(UINT8) + 1); ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]Get LTE Channels\n"); ++ prQueryLTEChn = kalMemAlloc(sizeof(PARAM_GET_CHN_LOAD), VIR_MEM_TYPE); ++ if (prQueryLTEChn == NULL) { ++ DBGLOG(QM, TRACE, "alloc QueryLTEChn fail\n"); ++ kalMemFree(skb, VIR_MEM_TYPE, sizeof(struct sk_buff)); ++ return -ENOMEM; ++ } ++ kalMemZero(prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD)); ++ ++ /* Query LTE Safe Channels */ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = ++ 0xFFFFFFFF; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryACSChannelList, prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD), ++ TRUE, FALSE, TRUE, TRUE, &u4BufLen); ++#if 0 ++ if (fgIsPureAP) { ++ ++ AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = 0x20; /* Channel 6 */ ++ } else ++#endif ++ { ++ fgIsReady = prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit; ++ rPreferChannels[0].u2APNum = 0xFFFF; ++ rPreferChannels[1].u2APNum = 0xFFFF; ++ ++ /* 4 In LTE Mode, Hotspot pick up channels from ch4. */ ++ ucDefaultIdx = 0; ++ /* ++ if (fgIsPureAP) { ++ ucDefaultIdx=3; //SKIP LTE Channels 1~3 ++ } ++ */ ++ ++ /* 4 Get the Maximun channel List in 2.4G Bands */ ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prGlueInfo->prAdapter); ++ ASSERT(prDomainInfo); ++ ++ /* 4 ToDo: Enable Step 2 only if we could get Country Code from framework */ ++ /* 4 2. Get current domain channel list */ ++ ++#if 0 ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, ++ BAND_2G4, MAXMUN_2_4G_CHA_NUM, &ucMax_24G_Chn_List, aucChannelList); ++#endif ++ ++ prGetChnLoad = (P_PARAM_GET_CHN_LOAD) &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); ++ for (ucIdx = 0; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ DBGLOG(P2P, INFO, ++ "[Auto Channel] ch[%d]=%d\n", ucIdx, ++ prGetChnLoad->rEachChnLoad[ucIdx + ucInnerIdx].u2APNum); ++ } ++ ++ /*Calculate Each Channel Direty Score */ ++ for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ ++#if 1 ++ u2APNumScore = prGetChnLoad->rEachChnLoad[ucIdx].u2APNum * CHN_DIRTY_WEIGHT_UPPERBOUND; ++ u2UpThreshold = u2LowThreshold = 3; ++ ++ if (ucIdx < 3) { ++ u2UpThreshold = ucIdx; ++ u2LowThreshold = 3; ++ } else if (ucIdx >= (ucMax_24G_Chn_List - 3)) { ++ u2UpThreshold = 3; ++ u2LowThreshold = ucMax_24G_Chn_List - (ucIdx + 1); ++ ++ } ++ ++ /*Calculate Lower Channel Dirty Score */ ++ for (ucInnerIdx = 0; ucInnerIdx < u2LowThreshold; ucInnerIdx++) { ++ ucArrayIdx = ucIdx + ucInnerIdx + 1; ++ if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { ++ u2APNumScore += ++ (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * ++ (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); ++ } ++ } ++ ++ /*Calculate Upper Channel Dirty Score */ ++ for (ucInnerIdx = 0; ucInnerIdx < u2UpThreshold; ucInnerIdx++) { ++ ucArrayIdx = ucIdx - ucInnerIdx - 1; ++ if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { ++ u2APNumScore += ++ (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * ++ (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); ++ } ++ } ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]chn=%d score=%d\n", ucIdx, u2APNumScore); ++#else ++ if (ucIdx == 0) { ++ /* ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = ++ (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ++ prGetChnLoad->rEachChnLoad[ucIdx+1].u2APNum*0.75); */ ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) ++ ((3 * ++ (prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 1]. ++ u2APNum + ++ prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 2]. ++ u2APNum)) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum)); ++ } ++ if ((ucIdx > 0) && (ucIdx < (MAXMUN_2_4G_CHA_NUM - 1))) { ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) ++ ((3 * ++ (prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 1]. ++ u2APNum + ++ prGetChnLoad-> ++ rEachChnLoad[ucIdx - ++ 1]. ++ u2APNum)) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); ++ } ++ ++ if (ucIdx == (MAXMUN_2_4G_CHA_NUM - 1)) { ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ++ ((UINT_16) ((3 * prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); ++ } ++#endif ++ ++ } ++ ++ u4LteSafeChnBitMask_2_4G = ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; ++ ++ /*Find out the best channel */ ++ for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ /* 4 Skip LTE Unsafe Channel */ ++ fgIsLteSafeChn = ((u4LteSafeChnBitMask_2_4G & BIT(ucIdx + 1)) >> ucIdx); ++ if (!fgIsLteSafeChn) ++ continue; ++ ++ prChnLoad = ++ (P_PARAM_CHN_LOAD_INFO) &(prGlueInfo->prAdapter->rWifiVar. ++ rChnLoadInfo.rEachChnLoad[ucIdx]); ++ if (rPreferChannels[0].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum) { ++ rPreferChannels[1].ucChannel = rPreferChannels[0].ucChannel; ++ rPreferChannels[1].u2APNum = rPreferChannels[0].u2APNum; ++ ++ rPreferChannels[0].ucChannel = ucIdx; ++ rPreferChannels[0].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; ++ } else { ++ if (rPreferChannels[1].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum ++ || fgIsFistRecord == 1) { ++ fgIsFistRecord = FALSE; ++ rPreferChannels[1].ucChannel = ucIdx; ++ rPreferChannels[1].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; ++ } ++ } ++ } ++ /* AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1-1] = ++ BITS((rQueryLTEChn.rLteSafeChnList.ucChannelLow-1),(rQueryLTEChn.rLteSafeChnList.ucChannelHigh-1)); */ ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = fgIsReady ? BIT(31) : 0; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] |= BIT(rPreferChannels[0].ucChannel); ++ } ++ ++ /* ToDo: Support 5G Channel Selection */ ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] = 0x11223344; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] = 0x55667788; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = 0x99AABBCC; ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]Relpy AcsChanInfo[%x:%x:%x:%x]\n", AcsChnReport[0], AcsChnReport[1], AcsChnReport[2], ++ AcsChnReport[3]); ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ /*need confirm cfg80211_testmode_reply will free skb*/ ++ skb = NULL; ++ /*kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD));*/ ++ ++nla_put_failure: ++ kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD)); ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++ ++} ++#endif ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief cfg80211 suspend callback, will be invoked in wiphy_suspend ++ * ++ * @param wiphy: pointer to wiphy ++ * wow: pointer to cfg80211_wowlan ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (kalHaltTryLock()) ++ return 0; ++ ++ if (kalIsHalted() || !wiphy) ++ goto end; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ set_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prGlueInfo->prAdapter->ulSuspendFlag); ++ set_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prGlueInfo->prAdapter->ulSuspendFlag); ++end: ++ kalHaltUnlock(); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief cfg80211 resume callback, will be invoked in wiphy_resume. ++ * ++ * @param wiphy: pointer to wiphy ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_resume(struct wiphy *wiphy) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_BSS_DESC_T *pprBssDesc = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ UINT_8 i = 0; ++ ++ if (kalHaltTryLock()) ++ return 0; ++ ++ if (kalIsHalted() || !wiphy) ++ goto end; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ prAdapter = prGlueInfo->prAdapter; ++ clear_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag); ++ pprBssDesc = &prAdapter->rWifiVar.rScanInfo.rNloParam.aprPendingBssDescToInd[0]; ++ for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { ++ if (pprBssDesc[i] == NULL) ++ break; ++ if (pprBssDesc[i]->u2RawLength == 0) ++ continue; ++ kalIndicateBssInfo(prGlueInfo, ++ (PUINT_8) pprBssDesc[i]->aucRawBuf, ++ pprBssDesc[i]->u2RawLength, ++ pprBssDesc[i]->ucChannelNum, ++ RCPI_TO_dBm(pprBssDesc[i]->ucRCPI)); ++ } ++ DBGLOG(SCN, INFO, "pending %d sched scan results\n", i); ++ if (i > 0) ++ kalMemZero(&pprBssDesc[0], i * sizeof(P_BSS_DESC_T)); ++end: ++ kalHaltUnlock(); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c +new file mode 100644 +index 000000000000..abe366585d05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c +@@ -0,0 +1,3501 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_init.c#7 ++*/ ++ ++/*! \file gl_init.c ++ \brief Main routines of Linux driver ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_init.c ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 05 25 2012 yuche.tsai ++ * NULL ++ * Fix reset KE issue. ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * EXPORT_SYMBOL(rsnParseCheckForWFAInfoElem);. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 12 22 2011 george.huang ++ * [WCXRP00000905] [MT6628 Wi-Fi][FW] Code refinement for ROM/ RAM module dependency ++ * using global variable instead of stack for setting wlanoidSetNetworkAddress(), due to buffer may be released before ++ * TX thread handling ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Fix large network type index assert in FW issue. ++ * ++ * 11 14 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 06 2011 eddie.chen ++ * [WCXRP00001027] [MT6628 Wi-Fi][Firmware/Driver] Tx fragmentation ++ * Add rlmDomainGetChnlList symbol. ++ * ++ * 09 22 2011 cm.chang ++ * NULL ++ * Safer writng stype to avoid unitialized regitry structure ++ * ++ * 09 21 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Avoid possible structure alignment problem ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * expose scnQuerySparseChannel() for P2P-FSM. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting ++ * device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 07 2011 wh.su ++ * [WCXRP00000839] [MT6620 Wi-Fi][Driver] Add the dumpMemory8 and dumpMemory32 EXPORT_SYMBOL ++ * Add the dumpMemory8 symbol export for debug mode. ++ * ++ * 07 06 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Improve BoW connection establishment speed. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Export one symbol for enhancement. ++ * ++ * 06 13 2011 eddie.chen ++ * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni ++ * Add tx rx statistics and netif_rx_ni. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain ++ * pass PHY_PARAM in NVRAM from driver to firmware. ++ * ++ * 05 09 2011 jeffrey.chang ++ * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change ++ * support ARP filter through kernel notifier ++ * ++ * 05 03 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Modify some driver connection flow or behavior to pass Sigma test more easier.. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 11 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * export wlan functions to p2p ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * glBusFreeIrq() should use the same pvCookie as glBusSetIrq() or request_irq()/free_irq() won't work as a pair. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port ++ * 2. update perm_addr as well for MAC address ++ * 3. not calling check_mem_region() anymore for eHPI ++ * 4. correct MSC_CS macro for 0-based notation ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * fix typo. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 23 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * apply multi-queue operation only for linux kernel > 2.6.26 ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability for compatible with linux 2.6.12. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 18 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * remove early suspend functions ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * reverse order to prevent probing racing. ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 jeffrey.chang ++ * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM ++ * refine the queue_select function ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 10 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Remove unnecessary assert and message. ++ * ++ * 03 08 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Export nicQmUpdateWmmParms. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 02 24 2011 george.huang ++ * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames ++ * Support ARP filter during suspended ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 02 17 2011 terry.wu ++ * [WCXRP00000459] [MT6620 Wi-Fi][Driver] Fix deference null pointer problem in wlanRemove ++ * Fix deference a null pointer problem in wlanRemove. ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * fix compilig error ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * Add query ipv4 and ipv6 address during early suspend and late resume ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 02 11 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add one more export symbol. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 02 09 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Halt p2p module init and exit until TxThread finished p2p register and unregister. ++ * ++ * 02 08 2011 george.huang ++ * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler ++ * Support querying power mode OID. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue ++ * Export Deactivation Network. ++ * ++ * 02 01 2011 jeffrey.chang ++ * [WCXRP00000414] KAL Timer is not unregistered when driver not loaded ++ * Unregister the KAL timer during driver unloading ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 ++ * add compile option to check linux version 2.6.35 for different usage of system API to improve portability ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 15 2010 cp.wu ++ * [WCXRP00000265] [MT6620 Wi-Fi][Driver] Remove set_mac_address routine from legacy Wi-Fi Android driver ++ * remove set MAC address. MAC address is always loaded from NVRAM instead. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 21 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * . ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000106] [MT6620 Wi-Fi][Driver] Enable setting multicast callback in Android ++ * . ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 16 2010 yarco.yang ++ * NULL ++ * Support Linux x86 ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 jeffrey.chang ++ * NULL ++ * fix memory leak for module unloading ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * bug fix: allocate regInfo when disabling firmware download ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * use glue layer api to decrease or increase counter atomically ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Query statistics from firmware ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * modify tcp/ip checksum offload flags ++ * ++ * 04 16 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix tcp/ip checksum offload bug ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set MAC address from firmware ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)improve none-glue code portability ++ * * (2) disable set Multicast address during atomic context ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding debug module ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix f/w download start and load address by using config.h ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download support ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\52 2009-10-27 22:49:59 GMT mtk01090 ++** Fix compile error for Linux EHPI driver ++** \main\maintrunk.MT5921\51 2009-10-20 17:38:22 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\50 2009-10-08 10:33:11 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\49 2009-09-28 20:19:05 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\48 2009-09-03 13:58:46 GMT mtk01088 ++** remove non-used code ++** \main\maintrunk.MT5921\47 2009-09-03 11:40:25 GMT mtk01088 ++** adding the module parameter for wapi ++** \main\maintrunk.MT5921\46 2009-08-18 22:56:41 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\45 2009-07-06 20:53:00 GMT mtk01088 ++** adding the code to check the wapi 1x frame ++** \main\maintrunk.MT5921\44 2009-06-23 23:18:55 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\43 2009-02-16 23:46:51 GMT mtk01461 ++** Revise the order of increasing u4TxPendingFrameNum because of CFG_TX_RET_TX_CTRL_EARLY ++** \main\maintrunk.MT5921\42 2009-01-22 13:11:59 GMT mtk01088 ++** set the tid and 1x value at same packet reserved field ++** \main\maintrunk.MT5921\41 2008-10-20 22:43:53 GMT mtk01104 ++** Fix wrong variable name "prDev" in wlanStop() ++** \main\maintrunk.MT5921\40 2008-10-16 15:37:10 GMT mtk01461 ++** add handle WLAN_STATUS_SUCCESS in wlanHardStartXmit() for CFG_TX_RET_TX_CTRL_EARLY ++** \main\maintrunk.MT5921\39 2008-09-25 15:56:21 GMT mtk01461 ++** Update driver for Code review ++** \main\maintrunk.MT5921\38 2008-09-05 17:25:07 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\37 2008-09-02 10:57:06 GMT mtk01461 ++** Update driver for code review ++** \main\maintrunk.MT5921\36 2008-08-05 01:53:28 GMT mtk01461 ++** Add support for linux statistics ++** \main\maintrunk.MT5921\35 2008-08-04 16:52:58 GMT mtk01461 ++** Fix ASSERT if removing module in BG_SSID_SCAN state ++** \main\maintrunk.MT5921\34 2008-06-13 22:52:24 GMT mtk01461 ++** Revise status code handling in wlanHardStartXmit() for WLAN_STATUS_SUCCESS ++** \main\maintrunk.MT5921\33 2008-05-30 18:56:53 GMT mtk01461 ++** Not use wlanoidSetCurrentAddrForLinux() ++** \main\maintrunk.MT5921\32 2008-05-30 14:39:40 GMT mtk01461 ++** Remove WMM Assoc Flag ++** \main\maintrunk.MT5921\31 2008-05-23 10:26:40 GMT mtk01084 ++** modify wlanISR interface ++** \main\maintrunk.MT5921\30 2008-05-03 18:52:36 GMT mtk01461 ++** Fix Unset Broadcast filter when setMulticast ++** \main\maintrunk.MT5921\29 2008-05-03 15:17:26 GMT mtk01461 ++** Move Query Media Status to GLUE ++** \main\maintrunk.MT5921\28 2008-04-24 22:48:21 GMT mtk01461 ++** Revise set multicast function by using windows oid style for LP own back ++** \main\maintrunk.MT5921\27 2008-04-24 12:00:08 GMT mtk01461 ++** Fix multicast setting in Linux and add comment ++** \main\maintrunk.MT5921\26 2008-03-28 10:40:22 GMT mtk01461 ++** Fix set mac address func in Linux ++** \main\maintrunk.MT5921\25 2008-03-26 15:37:26 GMT mtk01461 ++** Add set MAC Address ++** \main\maintrunk.MT5921\24 2008-03-26 14:24:53 GMT mtk01461 ++** For Linux, set net_device has feature with checksum offload by default ++** \main\maintrunk.MT5921\23 2008-03-11 14:50:52 GMT mtk01461 ++** Fix typo ++** \main\maintrunk.MT5921\22 2008-02-29 15:35:20 GMT mtk01088 ++** add 1x decide code for sw port control ++** \main\maintrunk.MT5921\21 2008-02-21 15:01:54 GMT mtk01461 ++** Rearrange the set off place of GLUE spin lock in HardStartXmit ++** \main\maintrunk.MT5921\20 2008-02-12 23:26:50 GMT mtk01461 ++** Add debug option - Packet Order for Linux and add debug level - Event ++** \main\maintrunk.MT5921\19 2007-12-11 00:11:12 GMT mtk01461 ++** Fix SPIN_LOCK protection ++** \main\maintrunk.MT5921\18 2007-11-30 17:02:25 GMT mtk01425 ++** 1. Set Rx multicast packets mode before setting the address list ++** \main\maintrunk.MT5921\17 2007-11-26 19:44:24 GMT mtk01461 ++** Add OS_TIMESTAMP to packet ++** \main\maintrunk.MT5921\16 2007-11-21 15:47:20 GMT mtk01088 ++** fixed the unload module issue ++** \main\maintrunk.MT5921\15 2007-11-07 18:37:38 GMT mtk01461 ++** Fix compile warnning ++** \main\maintrunk.MT5921\14 2007-11-02 01:03:19 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\13 2007-10-30 10:42:33 GMT mtk01425 ++** 1. Refine for multicast list ++** \main\maintrunk.MT5921\12 2007-10-25 18:08:13 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++** Revision 1.4 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:50 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "gl_cfg80211.h" ++#include "precomp.h" ++#if CFG_SUPPORT_AGPS_ASSIST ++#include "gl_kal.h" ++#endif ++#if defined(CONFIG_MTK_TC1_FEATURE) ++#include ++#endif ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* #define MAX_IOREQ_NUM 10 */ ++ ++BOOLEAN fgIsUnderSuspend = false; ++ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++spinlock_t g_p2p_lock; ++int g_u4P2PEnding = 0; ++int g_u4P2POnOffing = 0; ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Tasklet mechanism is like buttom-half in Linux. We just want to ++ * send a signal to OS for interrupt defer processing. All resources ++ * are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty. ++ */ ++typedef struct _WLANDEV_INFO_T { ++ struct net_device *prDev; ++} WLANDEV_INFO_T, *P_WLANDEV_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#define CHAN2G(_channel, _freq, _flags) \ ++{ \ ++ .band = NL80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_channel mtk_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0), ++}; ++ ++#define CHAN5G(_channel, _flags) \ ++{ \ ++ .band = NL80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_channel mtk_5ghz_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0), ++ CHAN5G(169, 0), CHAN5G(173, 0), ++ CHAN5G(184, 0), CHAN5G(188, 0), ++ CHAN5G(192, 0), CHAN5G(196, 0), ++ CHAN5G(200, 0), CHAN5G(204, 0), ++ CHAN5G(208, 0), CHAN5G(212, 0), ++ CHAN5G(216, 0), ++}; ++ ++#define RATETAB_ENT(_rate, _rateid, _flags) \ ++{ \ ++ .bitrate = (_rate), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++} ++ ++/* for cfg80211 - rate table */ ++static struct ieee80211_rate mtk_rates[] = { ++ RATETAB_ENT(10, 0x1000, 0), ++ RATETAB_ENT(20, 0x1001, 0), ++ RATETAB_ENT(55, 0x1002, 0), ++ RATETAB_ENT(110, 0x1003, 0), /* 802.11b */ ++ RATETAB_ENT(60, 0x2000, 0), ++ RATETAB_ENT(90, 0x2001, 0), ++ RATETAB_ENT(120, 0x2002, 0), ++ RATETAB_ENT(180, 0x2003, 0), ++ RATETAB_ENT(240, 0x2004, 0), ++ RATETAB_ENT(360, 0x2005, 0), ++ RATETAB_ENT(480, 0x2006, 0), ++ RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */ ++}; ++ ++#define mtk_a_rates (mtk_rates + 4) ++#define mtk_a_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 4) ++#define mtk_g_rates (mtk_rates + 0) ++#define mtk_g_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 0) ++ ++#define WLAN_MCS_INFO \ ++{ \ ++ .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},\ ++ .rx_highest = 0, \ ++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ ++} ++ ++#define WLAN_HT_CAP \ ++{ \ ++ .ht_supported = true, \ ++ .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \ ++ | IEEE80211_HT_CAP_SM_PS \ ++ | IEEE80211_HT_CAP_GRN_FLD \ ++ | IEEE80211_HT_CAP_SGI_20 \ ++ | IEEE80211_HT_CAP_SGI_40, \ ++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ ++ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \ ++ .mcs = WLAN_MCS_INFO, \ ++} ++ ++/********************************************************** ++* Public for both legacy Wi-Fi and P2P to access ++**********************************************************/ ++struct ieee80211_supported_band mtk_band_2ghz = { ++ .band = NL80211_BAND_2GHZ, ++ .channels = mtk_2ghz_channels, ++ .n_channels = ARRAY_SIZE(mtk_2ghz_channels), ++ .bitrates = mtk_g_rates, ++ .n_bitrates = mtk_g_rates_size, ++ .ht_cap = WLAN_HT_CAP, ++}; ++ ++struct ieee80211_supported_band mtk_band_5ghz = { ++ .band = NL80211_BAND_5GHZ, ++ .channels = mtk_5ghz_channels, ++ .n_channels = ARRAY_SIZE(mtk_5ghz_channels), ++ .bitrates = mtk_a_rates, ++ .n_bitrates = mtk_a_rates_size, ++ .ht_cap = WLAN_HT_CAP, ++}; ++ ++const UINT_32 mtk_cipher_suites[5] = { ++ /* keep WEP first, it may be removed below */ ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ ++ /* keep last -- depends on hw flags! */ ++ WLAN_CIPHER_SUITE_AES_CMAC ++}; ++ ++/*********************************************************/ ++ ++#define NIC_INF_NAME "wlan%d" /* interface name */ ++#if CFG_TC1_FEATURE ++#define NIC_INF_NAME_IN_AP_MODE "legacy%d" ++#endif ++ ++/* support to change debug module info dynamically */ ++UINT_8 aucDebugModule[DBG_MODULE_NUM]; ++UINT_32 u4DebugModule = 0; ++ ++/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan device to 1 */ ++static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { {0} }; ++ ++static UINT_32 u4WlanDevNum; /* How many NICs coexist now */ ++ ++/**20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan dead loack**/ ++struct delayed_work sched_workq; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_ENABLE_WIFI_DIRECT ++static SUB_MODULE_HANDLER rSubModHandler[SUB_MODULE_NUM] = { {NULL} }; ++#endif ++ ++static struct cfg80211_ops mtk_wlan_ops = { ++ .suspend = mtk_cfg80211_suspend, ++ .resume = mtk_cfg80211_resume, ++ .change_virtual_intf = mtk_cfg80211_change_iface, ++ .add_key = mtk_cfg80211_add_key, ++ .get_key = mtk_cfg80211_get_key, ++ .del_key = mtk_cfg80211_del_key, ++ .set_default_key = mtk_cfg80211_set_default_key, ++ .set_default_mgmt_key = mtk_cfg80211_set_default_mgmt_key, ++ .get_station = mtk_cfg80211_get_station, ++ .change_station = mtk_cfg80211_change_station, ++ .add_station = mtk_cfg80211_add_station, ++ .del_station = mtk_cfg80211_del_station, ++ .scan = mtk_cfg80211_scan, ++ .connect = mtk_cfg80211_connect, ++ .disconnect = mtk_cfg80211_disconnect, ++ .join_ibss = mtk_cfg80211_join_ibss, ++ .leave_ibss = mtk_cfg80211_leave_ibss, ++ .set_power_mgmt = mtk_cfg80211_set_power_mgmt, ++ .set_pmksa = mtk_cfg80211_set_pmksa, ++ .del_pmksa = mtk_cfg80211_del_pmksa, ++ .flush_pmksa = mtk_cfg80211_flush_pmksa, ++ .assoc = mtk_cfg80211_assoc, ++ /* Action Frame TX/RX */ ++ .remain_on_channel = mtk_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = mtk_cfg80211_mgmt_tx, ++/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */ ++ .mgmt_frame_register = mtk_cfg80211_mgmt_frame_register, ++#ifdef CONFIG_NL80211_TESTMODE ++ .testmode_cmd = mtk_cfg80211_testmode_cmd, ++#endif ++#if (CFG_SUPPORT_TDLS == 1) ++ .tdls_mgmt = TdlsexCfg80211TdlsMgmt, ++ .tdls_oper = TdlsexCfg80211TdlsOper, ++#endif /* CFG_SUPPORT_TDLS */ ++#if 1 /* Remove schedule_scan because we need more verification for NLO */ ++ .sched_scan_start = mtk_cfg80211_sched_scan_start, ++ .sched_scan_stop = mtk_cfg80211_sched_scan_stop, ++#endif ++}; ++ ++static const struct wiphy_vendor_command mtk_wlan_vendor_ops[] = { ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_channel_list ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_country_code ++ }, ++ /* GSCAN */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_gscan_capabilities ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_config ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV, ++ .doit = mtk_cfg80211_vendor_set_scan_config ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_enable_scan ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_enable_full_scan_results ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_scan_results ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_significant_change ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_HOTLIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_hotlist ++ }, ++ /* RTT */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = RTT_SUBCMD_GETCAPABILITY ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_rtt_capabilities ++ }, ++ /* Link Layer Statistics */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = LSTATS_SUBCMD_GET_INFO ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_llstats_get_info ++ }, ++ ++}; ++ ++static const struct nl80211_vendor_cmd_info mtk_wlan_vendor_events[] = { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_FOUND ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_SCAN_RESULTS_AVAILABLE ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_FULL_SCAN_RESULTS ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = RTT_EVENT_COMPLETE ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_COMPLETE_SCAN ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_LOST ++ }, ++}; ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++ mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = { ++ .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Override the implementation of select queue ++* ++* \param[in] dev Pointer to struct net_device ++* \param[in] skb Pointer to struct skb_buff ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++unsigned int _cfg80211_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp = 0; ++ ++ /* skb->priority values from 256->263 are magic values ++ * directly indicate a specific 802.1d priority. This is ++ * to allow 802.1d priority to be passed directly in from ++ * tags ++ */ ++ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ } ++ return dscp >> 5; ++} ++ ++static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++ ++static UINT_16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, ++ void *accel_priv, select_queue_fallback_t fallback) ++{ ++ skb->priority = _cfg80211_classify8021d(skb); ++ ++ return au16Wlan1dToQueueIdx[skb->priority]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Load NVRAM data and translate it into REG_INFO_T ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* \param[out] prRegInfo Pointer to struct REG_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void glLoadNvram(IN P_GLUE_INFO_T prGlueInfo, OUT P_REG_INFO_T prRegInfo) ++{ ++ UINT_32 i, j; ++ UINT_8 aucTmp[2]; ++ PUINT_8 pucDest; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prRegInfo); ++ ++ if ((!prGlueInfo) || (!prRegInfo)) ++ return; ++ ++ if (kalCfgDataRead16(prGlueInfo, sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(UINT_16), (PUINT_16) aucTmp) == TRUE) { ++ prGlueInfo->fgNvramAvailable = TRUE; ++ ++ /* load MAC Address */ ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ for (i = 0; i < PARAM_MAC_ADDR_LEN; i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, ++ (PUINT_16) (((PUINT_8) prRegInfo->aucMacAddr) + i)); ++ } ++#else ++ TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prRegInfo->aucMacAddr); ++#endif ++ ++ /* load country code */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), (PUINT_16) aucTmp); ++ ++ /* cast to wide characters */ ++ prRegInfo->au2CountryCode[0] = (UINT_16) aucTmp[0]; ++ prRegInfo->au2CountryCode[1] = (UINT_16) aucTmp[1]; ++ ++ /* load default normal TX power */ ++ for (i = 0; i < sizeof(TX_PWR_PARAM_T); i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i, ++ (PUINT_16) (((PUINT_8) &(prRegInfo->rTxPwr)) + i)); ++ } ++ ++ /* load feature flags */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), (PUINT_16) aucTmp); ++ prRegInfo->ucTxPwrValid = aucTmp[0]; ++ prRegInfo->ucSupport5GBand = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), (PUINT_16) aucTmp); ++ prRegInfo->uc2G4BwFixed20M = aucTmp[0]; ++ prRegInfo->uc5GBwFixed20M = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), (PUINT_16) aucTmp); ++ prRegInfo->ucEnable5GBand = aucTmp[0]; ++ ++ /* load EFUSE overriding part */ ++ for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i, ++ (PUINT_16) (((PUINT_8) &(prRegInfo->aucEFUSE)) + i)); ++ } ++ ++ /* load band edge tx power control */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), (PUINT_16) aucTmp); ++ prRegInfo->fg2G4BandEdgePwrUsed = (BOOLEAN) aucTmp[0]; ++ if (aucTmp[0]) { ++ prRegInfo->cBandEdgeMaxPwrCCK = (INT_8) aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, cBandEdgeMaxPwrOFDM20), (PUINT_16) aucTmp); ++ prRegInfo->cBandEdgeMaxPwrOFDM20 = (INT_8) aucTmp[0]; ++ prRegInfo->cBandEdgeMaxPwrOFDM40 = (INT_8) aucTmp[1]; ++ } ++ ++ /* load regulation subbands */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), (PUINT_16) aucTmp); ++ prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T) aucTmp[0]; ++ prRegInfo->ucRegChannelListIndex = aucTmp[1]; ++ ++ if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ pucDest = (PUINT_8) &prRegInfo->rDomainInfo.rSubBand[i]; ++ for (j = 0; j < 6; j += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) ++ + (i * 6 + j), (PUINT_16) aucTmp); ++ ++ *pucDest++ = aucTmp[0]; ++ *pucDest++ = aucTmp[1]; ++ } ++ } ++ } ++ /* load RSSI compensation */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2GRssiCompensation), (PUINT_16) aucTmp); ++ prRegInfo->uc2GRssiCompensation = aucTmp[0]; ++ prRegInfo->uc5GRssiCompensation = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fgRssiCompensationValidbit), (PUINT_16) aucTmp); ++ prRegInfo->fgRssiCompensationValidbit = aucTmp[0]; ++ prRegInfo->ucRxAntennanumber = aucTmp[1]; ++ } else { ++ prGlueInfo->fgNvramAvailable = FALSE; ++ } ++ ++} ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief called by txthread, run sub module init function ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /*now, we only have p2p module */ ++ if (rSubModHandler[P2P_MODULE].fgIsInited == FALSE) { ++ rSubModHandler[P2P_MODULE].subModInit(prGlueInfo); ++ rSubModHandler[P2P_MODULE].fgIsInited = TRUE; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief called by txthread, run sub module exit function ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /*now, we only have p2p module */ ++ if (rSubModHandler[P2P_MODULE].fgIsInited == TRUE) { ++ rSubModHandler[P2P_MODULE].subModExit(prGlueInfo); ++ rSubModHandler[P2P_MODULE].fgIsInited = FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set sub module init flag, force TxThread to run sub modle init ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++ prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_INIT; ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread finish sub module INIT */ ++ wait_for_completion_interruptible(&prGlueInfo->rSubModComp); ++ ++#if 0 ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pNetRegister(prGlueInfo); ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set sub module exit flag, force TxThread to run sub modle exit ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo) ++{ ++#if 0 ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pNetUnregister(prGlueInfo); ++#endif ++ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++ prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_EXIT; ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread finish sub module EXIT */ ++ wait_for_completion_interruptible(&prGlueInfo->rSubModComp); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set by sub module, indicate sub module is already inserted ++* ++* \param[in] rSubModInit, function pointer point to sub module init function ++* \param[in] rSubModExit, function pointer point to sub module exit function ++* \param[in] eSubModIdx, sub module index ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx) ++{ ++ rSubModHandler[eSubModIdx].subModInit = rSubModInit; ++ rSubModHandler[eSubModIdx].subModExit = rSubModExit; ++ rSubModHandler[eSubModIdx].fgIsInited = FALSE; ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief check wlan is launched or not ++* ++* \param[in] (none) ++* ++* \return TRUE, wlan is already started ++* FALSE, wlan is not started yet ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsLaunched(VOID) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ /* 4 <0> Sanity check */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (0 == u4WlanDevNum) ++ return FALSE; ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ ++ ASSERT(prDev); ++ if (NULL == prDev) ++ return FALSE; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (NULL == prGlueInfo) ++ return FALSE; ++ ++ return prGlueInfo->prAdapter->fgIsWlanLaunched; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Export wlan GLUE_INFO_T pointer to p2p module ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return TRUE: get GlueInfo pointer successfully ++* FALSE: wlan is not started yet ++*/ ++/*---------------------------------------------------------------------------*/ ++BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (0 == u4WlanDevNum) ++ return FALSE; ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ if (NULL == prDev) ++ return FALSE; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (NULL == prGlueInfo) ++ return FALSE; ++ ++ if (FALSE == prGlueInfo->prAdapter->fgIsWlanLaunched) ++ return FALSE; ++ ++ *prGlueInfoExpAddr = prGlueInfo; ++ return TRUE; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release prDev from wlandev_array and free tasklet object related to it. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void wlanClearDevIdx(struct net_device *prDev) ++{ ++ int i; ++ ++ ASSERT(prDev); ++ ++ for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { ++ if (arWlanDevInfo[i].prDev == prDev) { ++ arWlanDevInfo[i].prDev = NULL; ++ u4WlanDevNum--; ++ } ++ } ++ ++} /* end of wlanClearDevIdx() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate an unique interface index, net_device::ifindex member for this ++* wlan device. Store the net_device in wlandev_array, and initialize ++* tasklet object related to it. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \retval >= 0 The device number. ++* \retval -1 Fail to get index. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanGetDevIdx(struct net_device *prDev) ++{ ++ int i; ++ ++ ASSERT(prDev); ++ ++ for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { ++ if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) { ++ /* Reserve 2 bytes space to store one digit of ++ * device number and NULL terminator. ++ */ ++ arWlanDevInfo[i].prDev = prDev; ++ u4WlanDevNum++; ++ return i; ++ } ++ } ++ ++ return -1; ++} /* end of wlanGetDevIdx() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, a primary SOCKET interface to configure ++* the interface lively. Handle an ioctl call on one of our devices. ++* Everything Linux ioctl specific is done here. Then we pass the contents ++* of the ifr->data to the request message handler. ++* ++* \param[in] prDev Linux kernel netdevice ++* ++* \param[in] prIfReq Our private ioctl request structure, typed for the generic ++* struct ifreq so we can use ptr to function ++* ++* \param[in] cmd Command ID ++* ++* \retval 0 The IOCTL command is executed successfully. ++* \retval <0 The execution of IOCTL command is failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ ++ /* Verify input parameters for the following functions */ ++ ASSERT(prDev && prIfReq); ++ if (!prDev || !prIfReq) { ++ DBGLOG(INIT, ERROR, "Invalid input data\n"); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (!prGlueInfo) { ++ DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); ++ return -EFAULT; ++ } ++ ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ DBGLOG(INIT, ERROR, "Adapter is not ready\n"); ++ return -EINVAL; ++ } ++ ++ if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) { ++ /* 0x8B00 ~ 0x8BDF, wireless extension region */ ++ ret = wext_support_ioctl(prDev, prIfReq, i4Cmd); ++ } else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) { ++ /* 0x8BE0 ~ 0x8BFF, private ioctl region */ ++ ret = priv_support_ioctl(prDev, prIfReq, i4Cmd); ++ } else if (i4Cmd == SIOCDEVPRIVATE + 1) { ++ ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); ++ } else { ++ DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} /* end of wlanDoIOCTL() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to set multicast list and set rx mode. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static struct delayed_work workq; ++static struct net_device *gPrDev; ++static BOOLEAN fgIsWorkMcStart = FALSE; ++static BOOLEAN fgIsWorkMcEverInit = FALSE; ++static struct wireless_dev *gprWdev; ++ ++static void createWirelessDevice(void) ++{ ++ struct wiphy *prWiphy = NULL; ++ struct wireless_dev *prWdev = NULL; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ struct net_device *prNetDev = NULL; ++#endif ++ ++ /* <1.1> Create wireless_dev */ ++ prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); ++ return; ++ } ++ ++ ++ /* <1.2> Create wiphy */ ++ prWiphy = wiphy_new(&mtk_wlan_ops, sizeof(GLUE_INFO_T)); ++ if (!prWiphy) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wiphy device failed\n"); ++ goto free_wdev; ++ } ++ ++ /* <1.3> configure wireless_dev & wiphy */ ++ prWdev->iftype = NL80211_IFTYPE_STATION; ++ prWiphy->max_scan_ssids = 1; /* FIXME: for combo scan */ ++ prWiphy->max_scan_ie_len = 512; ++ ++ prWiphy->max_sched_scan_ssids = CFG_SCAN_SSID_MAX_NUM; ++ prWiphy->max_match_sets = CFG_SCAN_SSID_MATCH_MAX_NUM; ++ prWiphy->max_sched_scan_ie_len = CFG_CFG80211_IE_BUF_LEN; ++ ++ prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); ++ prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; ++ /* always assign 5Ghz bands here, if the chip is not support 5Ghz, ++ bands[IEEE80211_BAND_5GHZ] will be assign to NULL */ ++ prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; ++ prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ prWiphy->cipher_suites = mtk_cipher_suites; ++ prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); ++ prWiphy->flags = WIPHY_FLAG_SUPPORTS_FW_ROAM ++ | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL ++ | WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ++ prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; ++#if CFG_SUPPORT_TDLS ++ TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags); ++#endif /* CFG_SUPPORT_TDLS */ ++ prWiphy->max_remain_on_channel_duration = 5000; ++ prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes; ++ prWiphy->vendor_commands = mtk_wlan_vendor_ops; ++ prWiphy->n_vendor_commands = sizeof(mtk_wlan_vendor_ops) / sizeof(struct wiphy_vendor_command); ++ prWiphy->vendor_events = mtk_wlan_vendor_events; ++ prWiphy->n_vendor_events = ARRAY_SIZE(mtk_wlan_vendor_events); ++ ++ /* <1.4> wowlan support */ ++#ifdef CONFIG_PM ++ prWiphy->wowlan = &mtk_wlan_wowlan_support; ++#endif ++#ifdef CONFIG_CFG80211_WEXT ++ /* <1.5> Use wireless extension to replace IOCTL */ ++ prWiphy->wext = &wext_handler_def; ++#endif ++ ++ if (wiphy_register(prWiphy) < 0) { ++ DBGLOG(INIT, ERROR, "wiphy_register error\n"); ++ goto free_wiphy; ++ } ++ prWdev->wiphy = prWiphy; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* <2> allocate and register net_device */ ++#if CFG_TC1_FEATURE ++ if (wlan_if_changed) ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ else ++#else ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++#endif ++ if (!prNetDev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); ++ goto unregister_wiphy; ++ } ++ ++ *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = (P_GLUE_INFO_T) wiphy_priv(prWiphy); ++ ++ prNetDev->netdev_ops = &wlan_netdev_ops; ++#ifdef CONFIG_WIRELESS_EXT ++ prNetDev->wireless_handlers = &wext_handler_def; ++#endif ++ netif_carrier_off(prNetDev); ++ netif_tx_stop_all_queues(prNetDev); ++ ++ /* <2.1> co-relate with wireless_dev bi-directionally */ ++ prNetDev->ieee80211_ptr = prWdev; ++ prWdev->netdev = prNetDev; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prNetDev->features = NETIF_F_HW_CSUM; ++#endif ++ ++ /* <2.2> co-relate net device & device tree */ ++ SET_NETDEV_DEV(prNetDev, wiphy_dev(prWiphy)); ++ ++ /* <2.3> register net_device */ ++ if (register_netdev(prWdev->netdev) < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); ++ goto unregister_wiphy; ++ } ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ gprWdev = prWdev; ++ DBGLOG(INIT, INFO, "create wireless device success\n"); ++ return; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++unregister_wiphy: ++ wiphy_unregister(prWiphy); ++#endif ++free_wiphy: ++ wiphy_free(prWiphy); ++free_wdev: ++ kfree(prWdev); ++} ++ ++static void destroyWirelessDevice(void) ++{ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(gprWdev->netdev); ++ free_netdev(gprWdev->netdev); ++#endif ++ wiphy_unregister(gprWdev->wiphy); ++ wiphy_free(gprWdev->wiphy); ++ kfree(gprWdev); ++ gprWdev = NULL; ++} ++ ++static void wlanSetMulticastList(struct net_device *prDev) ++{ ++ gPrDev = prDev; ++ schedule_delayed_work(&workq, 0); ++} ++ ++/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange ++ * another workqueue for sleeping. We don't want to block ++ * tx_thread, so we can't let tx_thread to do this */ ++ ++static void wlanSetMulticastListWorkQueue(struct work_struct *work) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4PacketFilter = 0; ++ UINT_32 u4SetInfoLen; ++ struct net_device *prDev = gPrDev; ++ ++ fgIsWorkMcStart = TRUE; ++ ++ if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) ++ return; ++ if (kalIsHalted()) { ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ return; ++ } ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(INIT, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ return; ++ } ++ ++ if (prDev->flags & IFF_PROMISC) ++ u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; ++ ++ if (prDev->flags & IFF_BROADCAST) ++ u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; ++ ++ if (prDev->flags & IFF_MULTICAST) { ++ if ((prDev->flags & IFF_ALLMULTI) || ++ (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { ++ ++ u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } else { ++ u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; ++ } ++ } ++ ++ kalHaltUnlock(); ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetCurrentPacketFilter, ++ &u4PacketFilter, ++ sizeof(u4PacketFilter), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen) != WLAN_STATUS_SUCCESS) { ++ fgIsWorkMcStart = FALSE; ++ DBGLOG(INIT, ERROR, "wlanSetMulticastListWorkQueue kalIoctl u4PacketFilter=%d\n", u4PacketFilter); ++ return; ++ } ++ ++ if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { ++ /* Prepare multicast address list */ ++ struct netdev_hw_addr *ha; ++ PUINT_8 prMCAddrList = NULL; ++ UINT_32 i = 0; ++ ++ if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) ++ return; ++ if (kalIsHalted()) { ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ /*DBGLOG(INIT, WARN, "wlanSetMulticastListWorkQueue g_u4HaltFlag=%d\n", g_u4HaltFlag);*/ ++ return; ++ } ++ ++ prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE); ++ ++ netdev_for_each_mc_addr(ha, prDev) { ++ if (i < MAX_NUM_GROUP_ADDR) { ++ memcpy((prMCAddrList + i * ETH_ALEN), ha->addr, ETH_ALEN); ++ i++; ++ } ++ } ++ ++ kalHaltUnlock(); ++ ++ kalIoctl(prGlueInfo, ++ wlanoidSetMulticastList, ++ prMCAddrList, (i * ETH_ALEN), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN); ++ } ++ ++ fgIsWorkMcStart = FALSE; ++ ++} /* end of wlanSetMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan has been stopped ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSchedScanStoppedWorkQueue(struct work_struct *work) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct net_device *prDev = gPrDev; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ if (!prGlueInfo) { ++ DBGLOG(SCN, ERROR, "prGlueInfo == NULL unexpected\n"); ++ return; ++ } ++ ++ /* 2. indication to cfg80211 */ ++ /* 20150205 change cfg80211_sched_scan_stopped to work queue due to sched_scan_mtx dead lock issue */ ++ cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo),0); ++ DBGLOG(SCN, INFO, ++ "cfg80211_sched_scan_stopped event send done\n"); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is TX entry point of NET DEVICE. ++* ++* \param[in] prSkb Pointer of the sk_buff to be sent ++* \param[in] prDev Pointer to struct net_device ++* ++* \retval NETDEV_TX_OK - on success. ++* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++*/ ++/*----------------------------------------------------------------------------*/ ++int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ UINT_16 u2QueueIdx = 0; ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ UINT16 u2Identifier = 0; ++#endif ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ prGlueInfo->u8SkbToDriver++; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ { ++ UINT8 *pkt = prSkb->data; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ /* u2TdlsTxSeq[u4TdlsTxSeqId ++] = u2Identifier; */ ++ DBGLOG(INIT, INFO, " %d\n", u2Identifier); ++ } ++ } ++#endif ++ /* check if WiFi is halt */ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "GLUE_FLAG_HALT skip tx\n"); ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (prGlueInfo->fgIsDad) { ++ /* kalPrint("[Passpoint R2] Due to ipv4_dad...TX is forbidden\n"); */ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ if (prGlueInfo->fgIs6Dad) { ++ /* kalPrint("[Passpoint R2] Due to ipv6_dad...TX is forbidden\n"); */ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++#endif ++ ++ STATS_TX_TIME_ARRIVE(prSkb); ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"); ++#endif ++ ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ ++ /* non-1x packets */ ++ ++#if CFG_DBG_GPIO_PINS ++ { ++ /* TX request from OS */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_LOW); ++ kalUdelay(1); ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_HIGH); ++ } ++#endif ++ ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); ++#endif ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++/* GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); */ ++/* GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); */ ++ ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) { ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_stop_subqueue for wlan0, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); ++ ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ prGlueInfo->rHifInfo.HifLoopbkFlg |= 0x01; ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ } ++ } ++ } else { ++ /* printk("is security frame\n"); */ ++ ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ DBGLOG(TX, EVENT, "\n+++++ pending frame %d len = %d +++++\n", prGlueInfo->i4TxPendingFrameNum, prSkb->len); ++ prGlueInfo->rNetDevStats.tx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.tx_packets++; ++ kalPerMonStart(prGlueInfo); ++ ++ /* set GLUE_FLAG_TXREQ_BIT */ ++ ++ /* pr->u4Flag |= GLUE_FLAG_TXREQ; */ ++ /* wake_up_interruptible(&prGlueInfo->waitq); */ ++ kalSetEvent(prGlueInfo); ++ ++ /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ ++ return NETDEV_TX_OK; ++} /* end of wlanHardStartXmit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, to get the network interface statistical ++* information. ++* ++* Whenever an application needs to get statistics for the interface, this method ++* is called. This happens, for example, when ifconfig or netstat -i is run. ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return net_device_stats buffer pointer. ++*/ ++/*----------------------------------------------------------------------------*/ ++struct net_device_stats *wlanGetStats(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++#if 0 ++ WLAN_STATUS rStatus; ++ UINT_32 u4XmitError = 0; ++ UINT_32 u4XmitOk = 0; ++ UINT_32 u4RecvError = 0; ++ UINT_32 u4RecvOk = 0; ++ UINT_32 u4BufLen; ++ ++ ASSERT(prDev); ++ ++ /* @FIX ME: need a more clear way to do this */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryXmitError, &u4XmitError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryXmitOk, &u4XmitOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryRcvOk, &u4RecvOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRcvError, &u4RecvError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ prGlueInfo->rNetDevStats.rx_packets = u4RecvOk; ++ prGlueInfo->rNetDevStats.tx_packets = u4XmitOk; ++ prGlueInfo->rNetDevStats.tx_errors = u4XmitError; ++ prGlueInfo->rNetDevStats.rx_errors = u4RecvError; ++ /* prGlueInfo->rNetDevStats.rx_bytes = rCustomNetDevStats.u4RxBytes; */ ++ /* prGlueInfo->rNetDevStats.tx_bytes = rCustomNetDevStats.u4TxBytes; */ ++ /* prGlueInfo->rNetDevStats.rx_errors = rCustomNetDevStats.u4RxErrors; */ ++ /* prGlueInfo->rNetDevStats.multicast = rCustomNetDevStats.u4Multicast; */ ++#endif ++ /* prGlueInfo->rNetDevStats.rx_packets = 0; */ ++ /* prGlueInfo->rNetDevStats.tx_packets = 0; */ ++ prGlueInfo->rNetDevStats.tx_errors = 0; ++ prGlueInfo->rNetDevStats.rx_errors = 0; ++ /* prGlueInfo->rNetDevStats.rx_bytes = 0; */ ++ /* prGlueInfo->rNetDevStats.tx_bytes = 0; */ ++ prGlueInfo->rNetDevStats.rx_errors = 0; ++ prGlueInfo->rNetDevStats.multicast = 0; ++ ++ return &prGlueInfo->rNetDevStats; ++ ++} /* end of wlanGetStats() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->init ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanInit succeeds. ++* \retval -ENXIO No such device. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanInit(struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (fgIsWorkMcEverInit == FALSE) { ++ if (!prDev) ++ return -ENXIO; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue); ++ ++ /* 20150205 work queue for sched_scan */ ++ INIT_DELAYED_WORK(&sched_workq, wlanSchedScanStoppedWorkQueue); ++ ++ fgIsWorkMcEverInit = TRUE; ++ } ++ ++ return 0; /* success */ ++} /* end of wlanInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->uninit ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void wlanUninit(struct net_device *prDev) ++{ ++ ++} /* end of wlanUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->open ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanOpen succeeds. ++* \retval < 0 The execution of wlanOpen failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanOpen(struct net_device *prDev) ++{ ++ ASSERT(prDev); ++ ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of wlanOpen() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->stop ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanStop succeeds. ++* \retval < 0 The execution of wlanStop failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanStop(struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ /* CFG80211 down */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueInfo->prScanRequest; ++ prGlueInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (prScanRequest) ++ cfg80211_scan_done(prScanRequest, &info); ++ netif_tx_stop_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of wlanStop() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief Update channel table for cfg80211 based on current country domain ++ * ++ * \param[in] prGlueInfo Pointer to glue info ++ * ++ * \return none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 i, j; ++ UINT_8 ucNumOfChannel; ++ RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels)]; ++ ++ /* 1. Disable all channels */ ++ for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) { ++ mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; ++ mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) { ++ mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; ++ mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; ++ } ++ ++ /* 2. Get current domain channel list */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, ++ BAND_NULL, FALSE, ++ ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels), ++ &ucNumOfChannel, aucChannelList); ++ ++ /* 3. Enable specific channel based on domain channel list */ ++ for (i = 0; i < ucNumOfChannel; i++) { ++ switch (aucChannelList[i].eBand) { ++ case BAND_2G4: ++ for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) { ++ if (mtk_2ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { ++ mtk_2ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; ++ mtk_2ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; ++ break; ++ } ++ } ++ break; ++ ++ case BAND_5G: ++ for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) { ++ if (mtk_5ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { ++ mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; ++ mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; ++ break; ++ } ++ } ++ break; ++ ++ default: ++ DBGLOG(INIT, WARN, "Unknown band %d\n", aucChannelList[i].eBand); ++ break; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register the device to the kernel and return the index. ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanNetRegister succeeds. ++* \retval < 0 The execution of wlanNetRegister failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static INT_32 wlanNetRegister(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ INT_32 i4DevIdx = -1; ++ ++ ASSERT(prWdev); ++ ++ do { ++ if (!prWdev) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ i4DevIdx = wlanGetDevIdx(prWdev->netdev); ++ if (i4DevIdx < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device number exceeds.\n"); ++ break; ++ } ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ if (register_netdev(prWdev->netdev) < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); ++ ++ wiphy_unregister(prWdev->wiphy); ++ wlanClearDevIdx(prWdev->netdev); ++ i4DevIdx = -1; ++ } ++#endif ++ if (i4DevIdx != -1) ++ prGlueInfo->fgIsRegistered = TRUE; ++ ++ } while (FALSE); ++ ++ return i4DevIdx; /* success */ ++} /* end of wlanNetRegister() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister the device from the kernel ++* ++* \param[in] prWdev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanNetUnregister(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "wlanNetUnregister: The device context is NULL\n"); ++ return; ++ } ++ DBGLOG(INIT, TRACE, "unregister net_dev(0x%p)\n", prWdev->netdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ wlanClearDevIdx(prWdev->netdev); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(prWdev->netdev); ++#endif ++ prGlueInfo->fgIsRegistered = FALSE; ++ ++ DBGLOG(INIT, INFO, "unregister wireless_dev(0x%p), ifindex=%d\n", prWdev, prWdev->netdev->ifindex); ++ ++} /* end of wlanNetUnregister() */ ++ ++static const struct net_device_ops wlan_netdev_ops = { ++ .ndo_open = wlanOpen, ++ .ndo_stop = wlanStop, ++ .ndo_set_rx_mode = wlanSetMulticastList, ++ .ndo_get_stats = wlanGetStats, ++ .ndo_do_ioctl = wlanDoIOCTL, ++ .ndo_start_xmit = wlanHardStartXmit, ++ .ndo_init = wlanInit, ++ .ndo_uninit = wlanUninit, ++ .ndo_select_queue = wlanSelectQueue, ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method for creating Linux NET4 struct net_device object and the ++* private data(prGlueInfo and prAdapter). Setup the IO address to the HIF. ++* Assign the function pointer to the net_device object ++* ++* \param[in] pvData Memory address for the device ++* ++* \retval Not null The wireless_dev object. ++* \retval NULL Fail to create wireless_dev object ++*/ ++/*----------------------------------------------------------------------------*/ ++static struct lock_class_key rSpinKey[SPIN_LOCK_NUM]; ++static struct wireless_dev *wlanNetCreate(PVOID pvData) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct wireless_dev *prWdev = gprWdev; ++ UINT_32 i; ++ struct device *prDev; ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); ++ return NULL; ++ } ++ /* 4 <1> co-relate wiphy & prDev */ ++#if MTK_WCN_HIF_SDIO ++ mtk_wcn_hif_sdio_get_dev(*((MTK_WCN_HIF_SDIO_CLTCTX *) pvData), &prDev); ++#else ++/* prDev = &((struct sdio_func *) pvData)->dev; //samp */ ++ prDev = pvData; /* samp */ ++#endif ++ if (!prDev) ++ DBGLOG(INIT, WARN, "unable to get struct dev for wlan\n"); ++ /* don't set prDev as parent of wiphy->dev, because we have done device_add ++ in driver init. if we set parent here, parent will be not able to know this child, ++ and may occurs a KE in device_shutdown, to free wiphy->dev, because his parent ++ has been freed. */ ++ /*set_wiphy_dev(prWdev->wiphy, prDev);*/ ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ /* 4 <3> Initial Glue structure */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ kalMemZero(prGlueInfo, sizeof(GLUE_INFO_T)); ++ /* 4 <3.1> Create net device */ ++#if CFG_TC1_FEATURE ++ if (wlan_if_changed) { ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, ++ NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ } else { ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ } ++#else ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++#endif ++ if (!prGlueInfo->prDevHandler) { ++ DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); ++ return NULL; ++ } ++ DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated ifindex=%d\n", ++ prGlueInfo->prDevHandler, prGlueInfo->prDevHandler->ifindex); ++ ++ /* 4 <3.1.1> initialize net device varaiables */ ++ *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prDevHandler)) = prGlueInfo; ++ ++ prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops; ++#ifdef CONFIG_WIRELESS_EXT ++ prGlueInfo->prDevHandler->wireless_handlers = &wext_handler_def; ++#endif ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prDevHandler); ++ ++ /* 4 <3.1.2> co-relate with wiphy bi-directionally */ ++ prGlueInfo->prDevHandler->ieee80211_ptr = prWdev; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prGlueInfo->prDevHandler->features = NETIF_F_HW_CSUM; ++#endif ++ prWdev->netdev = prGlueInfo->prDevHandler; ++ ++ /* 4 <3.1.3> co-relate net device & prDev */ ++ /*SET_NETDEV_DEV(prGlueInfo->prDevHandler, wiphy_dev(prWdev->wiphy));*/ ++ SET_NETDEV_DEV(prGlueInfo->prDevHandler, prDev); ++#else /* CFG_SUPPORT_PERSIST_NETDEV */ ++ prGlueInfo->prDevHandler = gprWdev->netdev; ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ ++ /* 4 <3.2> initiali glue variables */ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ prGlueInfo->ePowerState = ParamDeviceStateD0; ++ prGlueInfo->fgIsMacAddrOverride = FALSE; ++ prGlueInfo->fgIsRegistered = FALSE; ++ prGlueInfo->prScanRequest = NULL; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* Init DAD */ ++ prGlueInfo->fgIsDad = FALSE; ++ prGlueInfo->fgIs6Dad = FALSE; ++ kalMemZero(prGlueInfo->aucDADipv4, 4); ++ kalMemZero(prGlueInfo->aucDADipv6, 16); ++#endif ++ ++ init_completion(&prGlueInfo->rScanComp); ++ init_completion(&prGlueInfo->rHaltComp); ++ init_completion(&prGlueInfo->rPendComp); ++#if CFG_ENABLE_WIFI_DIRECT ++ init_completion(&prGlueInfo->rSubModComp); ++#endif ++ ++ /* initialize timer for OID timeout checker */ ++ kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler); ++ ++ for (i = 0; i < SPIN_LOCK_NUM; i++) { ++ spin_lock_init(&prGlueInfo->rSpinLock[i]); ++ lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]); ++ } ++ ++ /* initialize semaphore for ioctl */ ++ sema_init(&prGlueInfo->ioctl_sem, 1); ++ ++ glSetHifInfo(prGlueInfo, (ULONG) pvData); ++ ++ /* 4 <8> Init Queues */ ++ init_waitqueue_head(&prGlueInfo->waitq); ++ QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue); ++ QUEUE_INITIALIZE(&prGlueInfo->rTxQueue); ++ ++ /* 4 <4> Create Adapter structure */ ++ prGlueInfo->prAdapter = (P_ADAPTER_T) wlanAdapterCreate(prGlueInfo); ++ ++ if (!prGlueInfo->prAdapter) { ++ DBGLOG(INIT, ERROR, "Allocating memory to adapter failed\n"); ++ return NULL; ++ } ++ KAL_WAKE_LOCK_INIT(prAdapter, &prGlueInfo->rAhbIsrWakeLock, "WLAN AHB ISR"); ++#if CFG_SUPPORT_PERSIST_NETDEV ++ dev_open(prGlueInfo->prDevHandler); ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prDevHandler); ++#endif ++ ++ return prWdev; ++} /* end of wlanNetCreate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Destroying the struct net_device object and the private data. ++* ++* \param[in] prWdev Pointer to struct wireless_dev. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanNetDestroy(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prWdev); ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "wlanNetDestroy: The device context is NULL\n"); ++ return; ++ } ++ ++ /* prGlueInfo is allocated with net_device */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* destroy kal OS timer */ ++ kalCancelTimer(prGlueInfo); ++ ++ glClearHifInfo(prGlueInfo); ++ ++ wlanAdapterDestroy(prGlueInfo->prAdapter); ++ prGlueInfo->prAdapter = NULL; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* take the net_device to down state */ ++ dev_close(prGlueInfo->prDevHandler); ++#else ++ /* Free net_device and private data prGlueInfo, which are allocated by alloc_netdev(). */ ++ free_netdev(prWdev->netdev); ++#endif ++ ++} /* end of wlanNetDestroy() */ ++ ++#ifndef CONFIG_X86 ++UINT_8 g_aucBufIpAddr[32] = { 0 }; ++static void wlanNotifyFwSuspend(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgSuspend) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidNotifyFwSuspend, ++ (PVOID)&fgSuspend, ++ sizeof(fgSuspend), ++ FALSE, ++ FALSE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, INFO, "wlanNotifyFwSuspend fail\n"); ++} ++ ++void wlanHandleSystemSuspend(void) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ ++ /* <1> Sanity check and acquire the net_device */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (u4WlanDevNum == 0) { ++ DBGLOG(INIT, ERROR, "wlanEarlySuspend u4WlanDevNum==0 invalid!!\n"); ++ return; ++ } ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ ++ fgIsUnderSuspend = true; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ kalPerMonDisable(prGlueInfo); ++ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ goto notify_suspend; ++ } ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++#ifdef CONFIG_IPV6 ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ goto notify_suspend; ++ } ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ++ ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] ++ ); ++ ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) { ++ /* Do nothing */ ++ /* u4NumIPv6++; */ ++ } ++#endif ++ ++ /* <7> set up the ARP filter */ ++ { ++ UINT_32 u4SetInfoLen = 0; ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#ifdef CONFIG_IPV6 ++ prParamNetAddrList->u4AddressCount += u4NumIPv6; ++#endif ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ prParamNetAddr = ++ (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); ++ } ++#ifdef CONFIG_IPV6 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(ip6)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ ++notify_suspend: ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ wlanNotifyFwSuspend(prGlueInfo, TRUE); ++} ++ ++void wlanHandleSystemResume(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_8 ip[4] = { 0 }; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++#endif ++ EVENT_AIS_BSS_INFO_T rParam; ++ UINT_32 u4BufLen = 0; ++ ++ /* <1> Sanity check and acquire the net_device */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (u4WlanDevNum == 0) { ++ DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n"); ++ return; ++ } ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ /* ASSERT(prDev); */ ++ ++ fgIsUnderSuspend = false; ++ ++ if (!prDev) { ++ DBGLOG(INIT, INFO, "prDev == NULL!!!\n"); ++ return; ++ } ++ /* <3> acquire the prGlueInfo */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ kalPerMonEnable(prGlueInfo); ++ ++ /* ++ We will receive the event in rx, we will check if the status is the same in driver ++ and FW, if not the same, trigger disconnetion procedure. ++ */ ++ ++ kalMemZero(&rParam, sizeof(EVENT_AIS_BSS_INFO_T)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBSSInfo, ++ &rParam, sizeof(EVENT_AIS_BSS_INFO_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Query BSSinfo fail 0x%x!!\n", rStatus); ++ } ++ ++ /* <2> get the IPv4 address */ ++ if (!(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ goto notify_resume; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ goto notify_resume; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ++ ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] ++ ); ++#endif ++ /* <7> clear the ARP filter */ ++ { ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = 0; ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ ++notify_resume: ++ DBGLOG(INIT, INFO, "Query BSS result: %d %d %d, IP: %d.%d.%d.%d, rStatus: %u\n", ++ rParam.eConnectionState, rParam.eCurrentOPMode, rParam.fgIsNetActive, ++ ip[0], ip[1], ip[2], ip[3], rStatus); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ wlanNotifyFwSuspend(prGlueInfo, FALSE); ++ } ++} ++#endif /* ! CONFIG_X86 */ ++ ++int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode) ++{ ++#if 0 ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ rSetP2P.u4Enable = p2pmode.u4Enable; ++ rSetP2P.u4Mode = p2pmode.u4Mode; ++ ++ if (!rSetP2P.u4Enable) ++ p2pNetUnregister(prGlueInfo, TRUE); ++ ++ rWlanStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pMode, ++ (PVOID) &rSetP2P, ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(INIT, INFO, "ret = %d\n", rWlanStatus); ++ if (rSetP2P.u4Enable) ++ p2pNetRegister(prGlueInfo, TRUE); ++ ++ return 0; ++ ++#else ++ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgIsP2PEnding; ++ UINT_32 u4BufLen = 0; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ DBGLOG(INIT, INFO, "%u %u\n", (UINT_32) p2pmode.u4Enable, (UINT_32) p2pmode.u4Mode); ++ ++ /* avoid remove & p2p off command simultaneously */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2PEnding = g_u4P2PEnding; ++ g_u4P2POnOffing = 1; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ if (fgIsP2PEnding == 1) { ++ /* skip the command if we are removing */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ return 0; ++ } ++ ++ rSetP2P.u4Enable = p2pmode.u4Enable; ++ rSetP2P.u4Mode = p2pmode.u4Mode; ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ if ((!rSetP2P.u4Enable) && (fgIsResetting == FALSE)) ++ p2pNetUnregister(prGlueInfo, TRUE); ++#endif ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ /* ++ Scenario: ++ 1. System enters suspend/resume but not yet enter wlanearlysuspend() ++ or wlanlateresume(); ++ ++ 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() ++ and get g_halt_sem then do glRegisterEarlySuspend() or ++ glUnregisterEarlySuspend(); ++ ++ But system suspend/resume procedure is not yet finished so we ++ suspend; ++ ++ 3. System switches back to do suspend/resume procedure and execute ++ kalIoctl(). But driver does not yet release g_halt_sem so system ++ suspend in wlanearlysuspend() or wlanlateresume(); ++ ++ ==> deadlock occurs. ++ */ ++ ++ rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, (PVOID) &rSetP2P,/* pu4IntBuf[0]is used as input SubCmd */ ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ /* Need to check fgIsP2PRegistered, in case of whole chip reset. ++ * in this case, kalIOCTL return success always, ++ * and prGlueInfo->prP2pInfo may be NULL */ ++ if ((rSetP2P.u4Enable) && (prGlueInfo->prAdapter->fgIsP2PRegistered) && (fgIsResetting == FALSE)) ++ p2pNetRegister(prGlueInfo, TRUE); ++#endif ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ return 0; ++#endif ++} ++ ++static void set_dbg_level_handler(unsigned char dbg_lvl[DBG_MODULE_NUM]) ++{ ++ kalMemCopy(aucDebugModule, dbg_lvl, sizeof(aucDebugModule)); ++ kalPrint("[wlan] change debug level"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Wlan probe function. This function probes and initializes the device. ++* ++* \param[in] pvData data passed by bus driver init function ++* _HIF_EHPI: NULL ++* _HIF_SDIO: sdio bus driver handle ++* ++* \retval 0 Success ++* \retval negative value Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++static INT_32 wlanProbe(PVOID pvData) ++{ ++ struct wireless_dev *prWdev = NULL; ++ enum probe_fail_reason { ++ BUS_INIT_FAIL, ++ NET_CREATE_FAIL, ++ BUS_SET_IRQ_FAIL, ++ ADAPTER_START_FAIL, ++ NET_REGISTER_FAIL, ++ PROC_INIT_FAIL, ++ FAIL_REASON_NUM ++ } eFailReason; ++ P_WLANDEV_INFO_T prWlandevInfo = NULL; ++ INT_32 i4DevIdx = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ INT_32 i4Status = 0; ++ BOOLEAN bRet = FALSE; ++ ++ eFailReason = FAIL_REASON_NUM; ++ do { ++ /* 4 <1> Initialize the IO port of the interface */ ++ /* GeorgeKuo: pData has different meaning for _HIF_XXX: ++ * _HIF_EHPI: pointer to memory base variable, which will be ++ * initialized by glBusInit(). ++ * _HIF_SDIO: bus driver handle ++ */ ++ ++ bRet = glBusInit(pvData); ++ wlanDebugInit(); ++ /* Cannot get IO address from interface */ ++ if (FALSE == bRet) { ++ DBGLOG(INIT, ERROR, KERN_ALERT "wlanProbe: glBusInit() fail\n"); ++ i4Status = -EIO; ++ eFailReason = BUS_INIT_FAIL; ++ break; ++ } ++ /* 4 <2> Create network device, Adapter, KalInfo, prDevHandler(netdev) */ ++ prWdev = wlanNetCreate(pvData); ++ if (prWdev == NULL) { ++ DBGLOG(INIT, ERROR, "wlanProbe: No memory for dev and its private\n"); ++ i4Status = -ENOMEM; ++ eFailReason = NET_CREATE_FAIL; ++ break; ++ } ++ /* 4 <2.5> Set the ioaddr to HIF Info */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ gPrDev = prGlueInfo->prDevHandler; ++ ++ /* 4 <4> Setup IRQ */ ++ prWlandevInfo = &arWlanDevInfo[i4DevIdx]; ++ ++ i4Status = glBusSetIrq(prWdev->netdev, NULL, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ ++ if (i4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n"); ++ eFailReason = BUS_SET_IRQ_FAIL; ++ break; ++ } ++ ++ prGlueInfo->i4DevIdx = i4DevIdx; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ prGlueInfo->u4ReadyFlag = 0; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prAdapter->u4CSUMFlags = (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP); ++#endif ++#if CFG_SUPPORT_CFG_FILE ++ { ++ PUINT_8 pucConfigBuf; ++ UINT_32 u4ConfigReadLen; ++ ++ wlanCfgInit(prAdapter, NULL, 0, 0); ++ pucConfigBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE); ++ u4ConfigReadLen = 0; ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read File...\n"); ++ if (pucConfigBuf) { ++ kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE); ++ if (kalReadToFile("/data/misc/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi.cfg\n"); ++ ++ } else if (kalReadToFile("/data/misc/wifi/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi/wifi.cfg\n"); ++ } else if (kalReadToFile("/etc/firmware/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /etc/firmware/wifi.cfg\n"); ++ } ++ ++ if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0) ++ wlanCfgInit(prAdapter, pucConfigBuf, u4ConfigReadLen, 0); ++ kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE); ++ } /* pucConfigBuf */ ++ } ++#endif ++ /* 4 <5> Start Device */ ++ /* */ ++#if CFG_ENABLE_FW_DOWNLOAD ++ DBGLOG(INIT, TRACE, "start to download firmware...\n"); ++ ++ /* before start adapter, we need to open and load firmware */ ++ { ++ UINT_32 u4FwSize = 0; ++ PVOID prFwBuffer = NULL; ++ P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; ++ ++ /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ ++ kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T)); ++ prRegInfo->u4StartAddress = CFG_FW_START_ADDRESS; ++ prRegInfo->u4LoadAddress = CFG_FW_LOAD_ADDRESS; ++ ++ /* Load NVRAM content to REG_INFO_T */ ++ glLoadNvram(prGlueInfo, prRegInfo); ++#if CFG_SUPPORT_CFG_FILE ++ wlanCfgApply(prAdapter); ++#endif ++ ++ /* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); */ ++ ++ prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; ++ prRegInfo->fgEnArpFilter = TRUE; ++ ++ if (kalFirmwareImageMapping(prGlueInfo, &prFwBuffer, &u4FwSize) == NULL) { ++ i4Status = -EIO; ++ DBGLOG(INIT, ERROR, "kalFirmwareImageMapping fail!\n"); ++ goto bailout; ++ } else { ++ ++ if (wlanAdapterStart(prAdapter, prRegInfo, prFwBuffer, ++ u4FwSize) != WLAN_STATUS_SUCCESS) { ++ i4Status = -EIO; ++ } ++ } ++ ++ kalFirmwareImageUnmapping(prGlueInfo, NULL, prFwBuffer); ++ ++bailout: ++ /* kfree(prRegInfo); */ ++ ++ DBGLOG(INIT, TRACE, "download firmware status = %d\n", i4Status); ++ ++ if (i4Status < 0) { ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4FwCnt; ++ ++ DBGLOG(INIT, WARN, "CONNSYS FW CPUINFO:\n"); ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ ++ ++ /* dump HIF/DMA registers, if fgIsBusAccessFailed is FALSE, otherwise, */ ++ /* dump HIF register may be hung */ ++ if (!fgIsBusAccessFailed) ++ HifRegDump(prGlueInfo->prAdapter); ++/* if (prGlueInfo->rHifInfo.DmaOps->DmaRegDump != NULL) */ ++/* prGlueInfo->rHifInfo.DmaOps->DmaRegDump(&prGlueInfo->rHifInfo); */ ++ eFailReason = ADAPTER_START_FAIL; ++ break; ++ } ++ } ++#else ++ /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ ++ kalMemSet(&prGlueInfo->rRegInfo, 0, sizeof(REG_INFO_T)); ++ P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; ++ ++ /* Load NVRAM content to REG_INFO_T */ ++ glLoadNvram(prGlueInfo, prRegInfo); ++ ++ prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; ++ ++ if (wlanAdapterStart(prAdapter, prRegInfo, NULL, 0) != WLAN_STATUS_SUCCESS) { ++ i4Status = -EIO; ++ eFailReason = ADAPTER_START_FAIL; ++ break; ++ } ++#endif ++ if (FALSE == prAdapter->fgEnable5GBand) ++ prWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; ++ ++ prGlueInfo->main_thread = kthread_run(tx_thread, prGlueInfo->prDevHandler, "tx_thread"); ++ kalSetHalted(FALSE); ++#if CFG_SUPPORT_ROAMING_ENC ++ /* adjust roaming threshold */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_ROAMING_INFO_T rRoamingInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ prAdapter->fgIsRoamingEncEnabled = TRUE; ++ ++ /* suggestion from Tsaiyuan.Hsu */ ++ kalMemZero(&rRoamingInfo, sizeof(CMD_ROAMING_INFO_T)); ++ rRoamingInfo.fgIsFastRoamingApplied = TRUE; ++ ++ DBGLOG(INIT, TRACE, "Enable roaming enhance function\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingInfo, ++ &rRoamingInfo, sizeof(rRoamingInfo), TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, ERROR, "set roaming advance info fail 0x%x\n", rStatus); ++ } ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++ /* adjust tx rate switch threshold */ ++ rlmTxRateEnhanceConfig(prGlueInfo->prAdapter); ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++ /* set MAC address */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ struct sockaddr MacAddr; ++ UINT_32 u4SetInfoLen = 0; ++ ++ kalMemZero(MacAddr.sa_data, sizeof(MacAddr.sa_data)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryCurrentAddr, ++ &MacAddr.sa_data, ++ PARAM_MAC_ADDR_LEN, TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, WARN, "set MAC addr fail 0x%x\n", rStatus); ++ prGlueInfo->u4ReadyFlag = 0; ++ } else { ++ ether_addr_copy(prGlueInfo->prDevHandler->dev_addr, (const u8 *)&(MacAddr.sa_data)); ++ ether_addr_copy(prGlueInfo->prDevHandler->perm_addr, ++ prGlueInfo->prDevHandler->dev_addr); ++ ++ /* card is ready */ ++ prGlueInfo->u4ReadyFlag = 1; ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "MAC address: %pM ", (&MacAddr.sa_data)); ++#endif ++ } ++ } ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ /* set HW checksum offload */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; ++ UINT_32 u4SetInfoLen = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetCSUMOffload, ++ (PVOID) &u4CSUMFlags, ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, WARN, "set HW checksum offload fail 0x%x\n", rStatus); ++ } ++#endif ++ ++ /* 4 <3> Register the card */ ++ DBGLOG(INIT, TRACE, "wlanNetRegister...\n"); ++ i4DevIdx = wlanNetRegister(prWdev); ++ if (i4DevIdx < 0) { ++ i4Status = -ENXIO; ++ DBGLOG(INIT, ERROR, "wlanProbe: Cannot register the net_device context to the kernel\n"); ++ eFailReason = NET_REGISTER_FAIL; ++ break; ++ } ++ ++ wlanRegisterNotifier(); ++ /* 4 <6> Initialize /proc filesystem */ ++#ifdef WLAN_INCLUDE_PROC ++ DBGLOG(INIT, TRACE, "init procfs...\n"); ++ i4Status = procCreateFsEntry(prGlueInfo); ++ if (i4Status < 0) { ++ DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n"); ++ eFailReason = PROC_INIT_FAIL; ++ break; ++ } ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; ++ prGlueInfo->rBowInfo.fgIsRegistered = FALSE; ++ glRegisterAmpc(prGlueInfo); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ DBGLOG(INIT, TRACE, "wlanSubModInit...\n"); ++ ++ /* wlan is launched */ ++ prGlueInfo->prAdapter->fgIsWlanLaunched = TRUE; ++ /* if p2p module is inserted, notify tx_thread to init p2p network */ ++ if (rSubModHandler[P2P_MODULE].subModInit) ++ wlanSubModInit(prGlueInfo); ++ /* register set_p2p_mode handler to mtk_wmt_wifi */ ++ register_set_p2p_mode_handler(set_p2p_mode_handler); ++#endif ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock, "WLAN AP"); ++#endif ++ } while (FALSE); ++ ++ if (i4Status != WLAN_STATUS_SUCCESS) { ++ switch (eFailReason) { ++ case PROC_INIT_FAIL: ++ wlanNetUnregister(prWdev); ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ wlanAdapterStop(prAdapter); ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case NET_REGISTER_FAIL: ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ wlanAdapterStop(prAdapter); ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case ADAPTER_START_FAIL: ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case BUS_SET_IRQ_FAIL: ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case NET_CREATE_FAIL: ++ break; ++ case BUS_INIT_FAIL: ++ break; ++ default: ++ break; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2PEnding = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ } ++#endif ++#if CFG_SUPPORT_AGPS_ASSIST ++ if (i4Status == WLAN_STATUS_SUCCESS) ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL, 0); ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ { ++ int iMetInitRet = WLAN_STATUS_FAILURE; ++ ++ if (i4Status == WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, TRACE, "init MET procfs...\n"); ++ iMetInitRet = kalMetInitProcfs(prGlueInfo); ++ if (iMetInitRet < 0) ++ DBGLOG(INIT, ERROR, "wlanProbe: init MET procfs failed\n"); ++ } ++ } ++#endif ++ if (i4Status == WLAN_STATUS_SUCCESS) { ++ /*Init performance monitor structure */ ++ kalPerMonInit(prGlueInfo); ++ /* probe ok */ ++ DBGLOG(INIT, TRACE, "wlanProbe ok\n"); ++ } else { ++ /* we don't care the return value of mtk_wcn_set_connsys_power_off_flag, ++ * because even this function returns ++ * error, we can also call core dump but only core dump failed. */ ++ if (g_IsNeedDoChipReset) ++ mtk_wcn_set_connsys_power_off_flag(0); ++ /* probe failed */ ++ DBGLOG(INIT, ERROR, "wlanProbe failed\n"); ++ } ++ ++ return i4Status; ++} /* end of wlanProbe() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method to stop driver operation and release all resources. Following ++* this call, no frame should go up or down through this interface. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanRemove(VOID) ++{ ++#define KAL_WLAN_REMOVE_TIMEOUT_MSEC 3000 ++ struct net_device *prDev = NULL; ++ P_WLANDEV_INFO_T prWlandevInfo = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ DBGLOG(INIT, LOUD, "Remove wlan!\n"); ++ ++ /* 4 <0> Sanity check */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (0 == u4WlanDevNum) { ++ DBGLOG(INIT, ERROR, "0 == u4WlanDevNum\n"); ++ return; ++ } ++ /* unregister set_p2p_mode handler to mtk_wmt_wifi */ ++ register_set_p2p_mode_handler(NULL); ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1]; ++ ++ ASSERT(prDev); ++ if (NULL == prDev) { ++ DBGLOG(INIT, ERROR, "NULL == prDev\n"); ++ return; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (NULL == prGlueInfo) { ++ DBGLOG(INIT, ERROR, "NULL == prGlueInfo\n"); ++ free_netdev(prDev); ++ return; ++ } ++ ++ kalPerMonDestroy(prGlueInfo); ++#if CFG_ENABLE_WIFI_DIRECT ++ /* avoid remove & p2p off command simultaneously */ ++ { ++ BOOLEAN fgIsP2POnOffing; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2PEnding = 1; ++ fgIsP2POnOffing = g_u4P2POnOffing; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ DBGLOG(INIT, TRACE, "waiting for fgIsP2POnOffing...\n"); ++ ++ /* History: cannot use down() here, sometimes we cannot come back here */ ++ /* waiting for p2p off command finishes, we cannot skip the remove */ ++ while (1) { ++ if (fgIsP2POnOffing == 0) ++ break; ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2POnOffing = g_u4P2POnOffing; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered) { ++ bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter); ++ /* wait 300ms for BoW module to send deauth */ ++ kalMsleep(300); ++ } ++#endif ++ ++ /* 4 <1> Stopping handling interrupt and free IRQ */ ++ DBGLOG(INIT, TRACE, "free IRQ...\n"); ++ glBusFreeIrq(prDev, *((P_GLUE_INFO_T *) netdev_priv(prDev))); ++ ++ kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); ++ ++ kalSetHalted(TRUE); /* before flush_delayed_work() */ ++ if (fgIsWorkMcStart == TRUE) { ++ DBGLOG(INIT, TRACE, "flush_delayed_work...\n"); ++ flush_delayed_work(&workq); /* flush_delayed_work_sync is deprecated */ ++ } ++ ++ flush_delayed_work(&sched_workq); ++ ++ DBGLOG(INIT, INFO, "down g_halt_sem...\n"); ++ kalHaltLock(KAL_WLAN_REMOVE_TIMEOUT_MSEC); ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ ++/* flush_delayed_work_sync(&workq); */ ++/* flush_delayed_work(&workq); */ /* flush_delayed_work_sync is deprecated */ ++ ++ /* 4 <2> Mark HALT, notify main thread to stop, and clean up queued requests */ ++/* prGlueInfo->u4Flag |= GLUE_FLAG_HALT; */ ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ DBGLOG(INIT, TRACE, "waiting for tx_thread stop...\n"); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ DBGLOG(INIT, TRACE, "wait_for_completion_interruptible\n"); ++ ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ ++ DBGLOG(INIT, TRACE, "mtk_sdiod stopped\n"); ++ ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rTxThreadWakeLock); ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ ++ /* prGlueInfo->rHifInfo.main_thread = NULL; */ ++ prGlueInfo->main_thread = NULL; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prGlueInfo->rBowInfo.fgIsRegistered) ++ glUnregisterAmpc(prGlueInfo); ++#endif ++ ++ /* 4 <3> Remove /proc filesystem. */ ++#ifdef WLAN_INCLUDE_PROC ++ procRemoveProcfs(); ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetRemoveProcfs(); ++#endif ++ ++ /* Force to do DMA reset */ ++ DBGLOG(INIT, TRACE, "glResetHif\n"); ++ glResetHif(prGlueInfo); ++ ++ /* 4 <4> wlanAdapterStop */ ++ prAdapter = prGlueInfo->prAdapter; ++#if CFG_SUPPORT_AGPS_ASSIST ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL, 0); ++#endif ++ ++ wlanAdapterStop(prAdapter); ++ DBGLOG(INIT, TRACE, "Number of Stalled Packets = %d\n", prGlueInfo->i4TxPendingFrameNum); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prGlueInfo->prAdapter->fgIsWlanLaunched = FALSE; ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) { ++ DBGLOG(INIT, TRACE, "p2pNetUnregister...\n"); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ p2pNetUnregister(prGlueInfo, FALSE); ++#endif ++ DBGLOG(INIT, INFO, "p2pRemove...\n"); ++ p2pRemove(prGlueInfo); ++ } ++#endif ++ ++ /* 4 <5> Release the Bus */ ++ glBusRelease(prDev); ++ ++ kalHaltUnlock(); ++ wlanDebugUninit(); ++ /* 4 <6> Unregister the card */ ++ wlanNetUnregister(prDev->ieee80211_ptr); ++ ++ /* 4 <7> Destroy the device */ ++ wlanNetDestroy(prDev->ieee80211_ptr); ++ prDev = NULL; ++ ++ DBGLOG(INIT, LOUD, "wlanUnregisterNotifier...\n"); ++ wlanUnregisterNotifier(); ++ ++ DBGLOG(INIT, INFO, "wlanRemove ok\n"); ++} /* end of wlanRemove() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver entry point when the driver is configured as a Linux Module, and ++* is called once at module load time, by the user-level modutils ++* application: insmod or modprobe. ++* ++* \retval 0 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Entry Point */ ++static int initWlan(void) ++{ ++ int ret = 0, i; ++#if DBG ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = DBG_CLASS_MASK; /* enable all */ ++#else ++ /* Initial debug level is D1 */ ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = DBG_CLASS_ERROR | DBG_CLASS_WARN | DBG_CLASS_INFO | DBG_CLASS_STATE; ++#endif /* DBG */ ++ DBGLOG(INIT, INFO, "initWlan\n"); ++ ++ spin_lock_init(&g_p2p_lock); ++ ++ /* memory pre-allocation */ ++ kalInitIOBuffer(); ++ procInitFs(); ++ createWirelessDevice(); ++ if (gprWdev) ++ glP2pCreateWirelessDevice((P_GLUE_INFO_T) wiphy_priv(gprWdev->wiphy)); ++ ++ ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0 : -EIO); ++ ++ if (ret == -EIO) { ++ kalUninitIOBuffer(); ++ return ret; ++ } ++#if (CFG_CHIP_RESET_SUPPORT) ++ glResetInit(); ++#endif ++ ++ /* register set_dbg_level handler to mtk_wmt_wifi */ ++ register_set_dbg_level_handler(set_dbg_level_handler); ++ ++ /* Set the initial DEBUG CLASS of each module */ ++ return ret; ++} /* end of initWlan() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver exit point when the driver as a Linux Module is removed. Called ++* at module unload time, by the user level modutils application: rmmod. ++* This is our last chance to clean up after ourselves. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Leave Point */ ++static VOID exitWlan(void) ++{ ++ DBGLOG(INIT, INFO, "exitWlan\n"); ++ ++ /* unregister set_dbg_level handler to mtk_wmt_wifi */ ++ register_set_dbg_level_handler(NULL); ++ ++#if CFG_CHIP_RESET_SUPPORT ++ glResetUninit(); ++#endif ++ destroyWirelessDevice(); ++ glP2pDestroyWirelessDevice(); ++ ++ glUnregisterBus(wlanRemove); ++ ++ /* free pre-allocated memory */ ++ kalUninitIOBuffer(); ++ ++ DBGLOG(INIT, INFO, "exitWlan\n"); ++ procUninitProcFs(); ++ ++} /* end of exitWlan() */ ++ ++#ifdef MTK_WCN_BUILT_IN_DRIVER ++ ++int mtk_wcn_wlan_gen2_init(void) ++{ ++ return initWlan(); ++} ++EXPORT_SYMBOL(mtk_wcn_wlan_gen2_init); ++ ++void mtk_wcn_wlan_gen2_exit(void) ++{ ++ return exitWlan(); ++} ++EXPORT_SYMBOL(mtk_wcn_wlan_gen2_exit); ++ ++#else ++ ++module_init(initWlan); ++module_exit(exitWlan); ++ ++#endif ++ ++MODULE_AUTHOR(NIC_AUTHOR); ++MODULE_DESCRIPTION(NIC_DESC); ++MODULE_SUPPORTED_DEVICE(NIC_NAME); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +new file mode 100644 +index 000000000000..e8f4f76960a5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +@@ -0,0 +1,4801 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_kal.c#3 ++*/ ++ ++/*! \file gl_kal.c ++ \brief GLUE Layer will export the required procedures here for internal driver stack. ++ ++ This file contains all routines which are exported from GLUE Layer to internal ++ driver stack. ++*/ ++ ++/* ++** Log: gl_kal.c ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 05 31 2012 terry.wu ++ * NULL ++ * . ++ * ++ * 03 26 2012 cp.wu ++ * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist ++ * invoke put_cred() after get_current_cred() calls. ++ * ++ * 03 07 2012 yuche.tsai ++ * NULL ++ * Fix compile error when WiFi Direct is off. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 02 20 2012 cp.wu ++ * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist ++ * do not need to invoke free() while firmware image file doesn't exist ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 21 2011 cp.wu ++ * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing ++ * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer ++ * add more checking for such cases ++ * ++ * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. ++ * add some tweaking to protect such cases because that net device has become invalid. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 16 2011 yuche.tsai ++ * NULL ++ * Avoid using work thread. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 23 2011 yuche.tsai ++ * [WCXRP00000998] [Volunteer Patch][WiFi Direct][FW] P2P Social Channel & country domain issue ++ * Regulation domain feature check in. ++ * ++ * 08 12 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 13 2011 eddie.chen ++ * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni ++ * Add tx rx statistics and netif_rx_ni. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * correct i4TxPendingFrameNum decreasing. ++ * ++ * 03 23 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * apply multi-queue operation only for linux kernel > 2.6.26 ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability for compatible with linux 2.6.12. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * refix ... ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * correct compiling warning/error. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * add more robust fault tolerance design when pre-allocation failed. (rarely happen) ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 14 2011 jeffrey.chang ++ * [WCXRP00000546] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] fix kernel build warning message ++ * fix kernel build warning message ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 ++ * add compile option to check linux version 2.6.35 for different usage of system API to improve portability ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field ++ * checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used ++ * to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 11 02 2010 jeffrey.chang ++ * [WCXRP00000145] [MT6620 Wi-Fi][Driver] fix issue of byte endian in packet classifier which discards BoW packets ++ * . ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 jeffrey.chang ++ * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform ++ * Remove redundant code which cause mismatch of power control release ++ * ++ * 10 25 2010 jeffrey.chang ++ * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform ++ * Remove redundant GLUE_HALT condfition to avoid unmatched release of power control ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue ++ * refine the scan ioctl to prevent hanging of Android UI ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * if there is NVRAM, then use MAC address on NVRAM as default MAC address. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Support second interface indicate when enabling P2P. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 16 2010 jeffrey.chang ++ * NULL ++ * remove redundant code which cause kernel panic ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * add new KAL api ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * bug fix: allocate regInfo when disabling firmware download ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * use glue layer api to decrease or increase counter atomically ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * modify tx thread and remove some spinlock ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * use different spin lock for security frame ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add spinlock for pending security frame count ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * adjust the timer unit to microsecond ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * timer should return value greater than zero ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add new kal api ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * for linux driver migration ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove unused files. ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix private ioctl for rftest ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * workaround for fixing request_firmware() failure on android 2.1 ++ * ++ * 05 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix kernel panic when debug mode enabled ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Disable network interface after disassociation ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 15 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * change firmware name ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * flush pending TX packets while unloading driver ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set driver own before handling cmd queue ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used ++ * 2) fix ioctl ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add spinlock for i4TxPendingFrameNum access ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * * 2) add KAPI for handling association info ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set MAC address from firmware ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. free cmdinfo after command is emiited. ++ * 2. for BoW frames, user priority is extracted from sk_buff directly. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)deliver the kalOidComplete status to upper layer ++ * (2) fix spin lock ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * * 2) add 2 kal API for later integration ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * raising the priority of processing interrupt ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Bug fix: the tx thread will cause starvation of MMC thread, and the interrupt will never come in ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding secondary command queue for improving non-glue code portability ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download kal api ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add Bluetooth-over-Wifi frame header check ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\50 2009-09-28 20:19:08 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\49 2009-08-18 22:56:44 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\48 2009-06-23 23:18:58 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\47 2008-11-19 11:55:43 GMT mtk01088 ++** fixed some lint warning, and rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\46 2008-09-02 21:07:42 GMT mtk01461 ++** Remove ASSERT(pvBuf) in kalIndicateStatusAndComplete(), this parameter can be NULL ++** \main\maintrunk.MT5921\45 2008-08-29 16:03:21 GMT mtk01088 ++** remove non-used code for code review, add assert check ++** \main\maintrunk.MT5921\44 2008-08-21 00:32:49 GMT mtk01461 ++** \main\maintrunk.MT5921\43 2008-05-30 20:27:02 GMT mtk01461 ++** Rename KAL function ++** \main\maintrunk.MT5921\42 2008-05-30 15:47:29 GMT mtk01461 ++** \main\maintrunk.MT5921\41 2008-05-30 15:13:04 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\40 2008-05-29 14:15:14 GMT mtk01084 ++** remove un-used KAL function ++** \main\maintrunk.MT5921\39 2008-05-03 15:17:30 GMT mtk01461 ++** Move Query Media Status to GLUE ++** \main\maintrunk.MT5921\38 2008-04-24 11:59:44 GMT mtk01461 ++** change awake queue threshold and remove code which mark #if 0 ++** \main\maintrunk.MT5921\37 2008-04-17 23:06:35 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\36 2008-04-08 15:38:56 GMT mtk01084 ++** add KAL function to setting pattern search function enable/ disable ++** \main\maintrunk.MT5921\35 2008-04-01 23:53:13 GMT mtk01461 ++** Add comment ++** \main\maintrunk.MT5921\34 2008-03-26 15:36:48 GMT mtk01461 ++** Add update MAC Address for Linux ++** \main\maintrunk.MT5921\33 2008-03-18 11:49:34 GMT mtk01084 ++** update function for initial value access ++** \main\maintrunk.MT5921\32 2008-03-18 10:25:22 GMT mtk01088 ++** use kal update associate request at linux ++** \main\maintrunk.MT5921\31 2008-03-06 23:43:08 GMT mtk01385 ++** 1. add Query Registry Mac address function. ++** \main\maintrunk.MT5921\30 2008-02-26 09:47:57 GMT mtk01084 ++** modify KAL set network address/ checksum offload part ++** \main\maintrunk.MT5921\29 2008-02-12 23:26:53 GMT mtk01461 ++** Add debug option - Packet Order for Linux ++** \main\maintrunk.MT5921\28 2008-01-09 17:54:43 GMT mtk01084 ++** modify the argument of kalQueryPacketInfo() ++** \main\maintrunk.MT5921\27 2007-12-24 16:02:03 GMT mtk01425 ++** 1. Revise csum offload ++** \main\maintrunk.MT5921\26 2007-11-30 17:03:36 GMT mtk01425 ++** 1. Fix bugs ++** ++** \main\maintrunk.MT5921\25 2007-11-29 01:57:17 GMT mtk01461 ++** Fix Windows RX multiple packet retain problem ++** \main\maintrunk.MT5921\24 2007-11-20 11:24:07 GMT mtk01088 ++** CR90, not doing the netif_carrier_off to let supplicant 1x pkt can be rcv at hardstattXmit ++** \main\maintrunk.MT5921\23 2007-11-09 16:36:44 GMT mtk01425 ++** 1. Modify for CSUM offloading with Tx Fragment ++** \main\maintrunk.MT5921\22 2007-11-07 18:37:39 GMT mtk01461 ++** Add Tx Fragmentation Support ++** \main\maintrunk.MT5921\21 2007-11-06 19:34:06 GMT mtk01088 ++** add the WPS code, indicate the mgmt frame to upper layer ++** \main\maintrunk.MT5921\20 2007-11-02 01:03:21 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\19 2007-10-30 11:59:38 GMT MTK01425 ++** 1. Update wlanQueryInformation ++** \main\maintrunk.MT5921\18 2007-10-30 10:44:57 GMT mtk01425 ++** 1. Refine multicast list code ++** 2. Refine TCP/IP csum offload code ++** ++** Revision 1.5 2007/07/17 13:01:18 MTK01088 ++** add associate req and rsp function ++** ++** Revision 1.4 2007/07/13 05:19:19 MTK01084 ++** provide timer set functions ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include "gl_os.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#if defined(CONFIG_MTK_TC1_FEATURE) ++#include ++#endif ++#if CFG_SUPPORT_AGPS_ASSIST ++#include ++#endif ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++#include ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if DBG ++int allocatedMemSize = 0; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++/* #define MTK_DMA_BUF_MEMCPY_SUP */ ++static PVOID pvIoBuffer; ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++static PVOID pvIoPhyBuf; ++static PVOID pvDmaBuffer; ++static PVOID pvDmaPhyBuf; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++static UINT_32 pvIoBufferSize; ++static UINT_32 pvIoBufferUsage; ++static struct KAL_HALT_CTRL_T rHaltCtrl = { ++ .lock = __SEMAPHORE_INITIALIZER(rHaltCtrl.lock, 1), ++ .owner = NULL, ++ .fgHalt = TRUE, ++ .fgHeldByKalIoctl = FALSE, ++ .u4HoldStart = 0, ++}; ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_MT6620_E1 = 0x0, ++ WMTHWVER_MT6620_E2 = 0x1, ++ WMTHWVER_MT6620_E3 = 0x2, ++ WMTHWVER_MT6620_E4 = 0x3, ++ WMTHWVER_MT6620_E5 = 0x4, ++ WMTHWVER_MT6620_E6 = 0x5, ++ WMTHWVER_MT6620_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &(prGlueInfo->rAhbIsrWakeLock), (HZ / 10)); /* 100ms */ ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++static struct file *filp; ++static uid_t orgfsuid; ++static gid_t orgfsgid; ++static mm_segment_t orgfs; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* open firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 aucFilePath[50]; ++ ++ /* FIX ME: since we don't have hotplug script in the filesystem ++ * , so the request_firmware() KAPI can not work properly ++ */ ++ ++ /* save uid and gid used for filesystem access. ++ * set user and group to 0(root) */ ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ orgfsuid = cred->fsuid.val; ++ orgfsgid = cred->fsgid.val; ++ cred->fsuid.val = cred->fsgid.val = 0; ++ ++ ASSERT(prGlueInfo); ++ ++ orgfs = get_fs(); ++ set_fs(get_ds()); ++ ++ /* open the fw file */ ++#if defined(MT6620) & CFG_MULTI_ECOVER_SUPPORT ++ switch (mtk_wcn_wmt_hwver_get()) { ++ case WMTHWVER_MT6620_E1: ++ case WMTHWVER_MT6620_E2: ++ case WMTHWVER_MT6620_E3: ++ case WMTHWVER_MT6620_E4: ++ case WMTHWVER_MT6620_E5: ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); ++ break; ++ ++ case WMTHWVER_MT6620_E6: ++ default: ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME "_E6", O_RDONLY, 0); ++ break; ++ } ++#elif defined(MT6628) ++/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6628", O_RDONLY, 0); */ ++/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6582", O_RDONLY, 0); */ ++#if 0 /* new wifi ram code mechanism, waiting firmware ready, then we can enable these code */ ++ kalMemZero(aucFilePath, sizeof(aucFilePath)); ++ kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_AD", sizeof("/etc/firmware/" CFG_FW_FILENAME "_AD")); ++ filp = filp_open(aucFilePath, O_RDONLY, 0); ++ if (!IS_ERR(filp)) ++ goto open_success; ++#endif ++ kalMemZero(aucFilePath, sizeof(aucFilePath)); ++ kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_", strlen("/etc/firmware/" CFG_FW_FILENAME "_")); ++ glGetChipInfo(prGlueInfo, &aucFilePath[strlen("/etc/firmware/" CFG_FW_FILENAME "_")]); ++ ++ DBGLOG(INIT, INFO, "open file: %s\n", aucFilePath); ++ ++ filp = filp_open(aucFilePath, O_RDONLY, 0); ++#else ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); ++#endif ++ if (IS_ERR(filp)) { ++ DBGLOG(INIT, ERROR, "Open FW image: %s failed\n", CFG_FW_FILENAME); ++ goto error_open; ++ } ++#if 0 ++open_success: ++#endif ++ DBGLOG(INIT, TRACE, "Open FW image: %s done\n", CFG_FW_FILENAME); ++ return WLAN_STATUS_SUCCESS; ++ ++error_open: ++ /* restore */ ++ set_fs(orgfs); ++ cred->fsuid.val = orgfsuid; ++ cred->fsgid.val = orgfsgid; ++ put_cred(cred); ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* release firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if ((filp != NULL) && !IS_ERR(filp)) { ++ /* close firmware file */ ++ filp_close(filp, NULL); ++ ++ /* restore */ ++ set_fs(orgfs); ++ { ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ cred->fsuid.val = orgfsuid; ++ cred->fsgid.val = orgfsgid; ++ put_cred(cred); ++ } ++ filp = NULL; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* load firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, OUT PVOID prBuf, IN UINT_32 u4Offset, OUT PUINT_32 pu4Size) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Size); ++ ASSERT(prBuf); ++ ++ /* l = filp->f_path.dentry->d_inode->i_size; */ ++#if 0 ++ /* the object must have a read method */ ++ if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) || (filp->f_op->read == NULL)) { ++ goto error_read; ++ } else { ++ filp->f_pos = u4Offset; ++ *pu4Size = filp->f_op->read(filp, prBuf, *pu4Size, &filp->f_pos); ++ } ++#else ++ /* the object must have a read method */ ++ if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) ) { ++ goto error_read; ++ } else { ++ filp->f_pos = u4Offset; ++ *pu4Size = vfs_read(filp, prBuf, *pu4Size, &filp->f_pos); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++ ++error_read: ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* query firmware image size in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_32 pu4Size) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Size); ++ ++ //*pu4Size = filp->f_path.dentry->d_inode->i_size; ++ *pu4Size = filp->f_op->llseek(filp, 0, 2); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to load firmware image ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image ++* \param pu4FileLength File length and memory mapped length as well ++ ++* \retval Map File Handle, used for unammping ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) ++{ ++ UINT_32 u4FwSize = 0; ++ PVOID prFwBuffer = NULL; ++ ++ DEBUGFUNC("kalFirmwareImageMapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ppvMapFileBuf); ++ ASSERT(pu4FileLength); ++ ++ do { ++ /* <1> Open firmware */ ++ if (kalFirmwareOpen(prGlueInfo) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, TRACE, "kalFirmwareOpen fail!\n"); ++ break; ++ } ++ ++ /* <2> Query firmare size */ ++ kalFirmwareSize(prGlueInfo, &u4FwSize); ++ printk(KERN_ERR "%s firmware size %d\n", __FUNCTION__, u4FwSize); ++ /* <3> Use vmalloc for allocating large memory trunk */ ++ prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); ++ /* <4> Load image binary into buffer */ ++ if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, &u4FwSize) != WLAN_STATUS_SUCCESS) { ++ vfree(prFwBuffer); ++ kalFirmwareClose(prGlueInfo); ++ DBGLOG(INIT, TRACE, "kalFirmwareLoad fail!\n"); ++ break; ++ } ++ /* <5> write back info */ ++ *pu4FileLength = u4FwSize; ++ *ppvMapFileBuf = prFwBuffer; ++ ++ return prFwBuffer; ++ ++ } while (FALSE); ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to unload firmware image mapped memory ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param pvFwHandle Pointer to mapping handle ++* \param pvMapFileBuf Pointer to memory-mapped firmware image ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) ++{ ++ DEBUGFUNC("kalFirmwareImageUnmapping"); ++ ++ ASSERT(prGlueInfo); ++ ++ /* pvMapFileBuf might be NULL when file doesn't exist */ ++ if (pvMapFileBuf) ++ vfree(pvMapFileBuf); ++ ++ kalFirmwareClose(prGlueInfo); ++} ++ ++#endif ++ ++#if 0 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to load firmware image ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image ++* \param pu4FileLength File length and memory mapped length as well ++ ++* \retval Map File Handle, used for unammping ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) ++{ ++ INT_32 i4Ret = 0; ++ ++ DEBUGFUNC("kalFirmwareImageMapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ppvMapFileBuf); ++ ASSERT(pu4FileLength); ++ ++ do { ++ GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; ++ ++ prGlueInfo->prFw = NULL; ++ ++ /* <1> Open firmware */ ++ i4Ret = request_firmware(&prGlueInfo->prFw, CFG_FW_FILENAME, prHifInfo->Dev); ++ ++ if (i4Ret) { ++ DBGLOG(INIT, TRACE, "fw %s:request failed %d\n", CFG_FW_FILENAME, i4Ret); ++ break; ++ } ++ *pu4FileLength = prGlueInfo->prFw->size; ++ *ppvMapFileBuf = prGlueInfo->prFw->data; ++ return prGlueInfo->prFw->data; ++ ++ } while (FALSE); ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to unload firmware image mapped memory ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param pvFwHandle Pointer to mapping handle ++* \param pvMapFileBuf Pointer to memory-mapped firmware image ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) ++{ ++ DEBUGFUNC("kalFirmwareImageUnmapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pvMapFileBuf); ++ ++ release_firmware(prGlueInfo->prFw); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to acquire ++* OS SPIN_LOCK. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags) ++{ ++ unsigned long u4Flags = 0; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Flags); ++ ++ if (rLockCategory < SPIN_LOCK_NUM) { ++ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++ spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++ *pu4Flags = u4Flags; ++/* DBGLOG(INIT, TRACE, ("A+%d\n", rLockCategory)); */ ++ } ++ ++} /* end of kalAcquireSpinLock() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to release ++* OS SPIN_LOCK. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[in] u4Flags Saved IRQ flags ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (rLockCategory < SPIN_LOCK_NUM) { ++ /* DBGLOG(INIT, TRACE, ("A-%d %d %d\n", rLockCategory, u4MemAllocCnt, u4MemFreeCnt)); */ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++ spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++ } ++ ++} /* end of kalReleaseSpinLock() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to update ++* current MAC address. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pucMacAddr Pointer of current MAC address ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pucMacAddr); ++ ++ if (UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) ++ memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, PARAM_MAC_ADDR_LEN); ++ ++} ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To query the packet information for offload related parameters. ++* ++* \param[in] pvPacket Pointer to the packet descriptor. ++* \param[in] pucFlag Points to the offload related parameter. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag) ++{ ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ UINT_8 ucFlag = 0; ++ ++ ASSERT(pvPacket); ++ ASSERT(pucFlag); ++ ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++#if DBG ++ /* Kevin: do double check, we can remove this part in Normal Driver. ++ * Because we register NIC feature with NETIF_F_IP_CSUM for MT5912B MAC, so ++ * we'll process IP packet only. ++ */ ++ if (skb->protocol != htons(ETH_P_IP)) { ++ /* printk("Wrong skb->protocol( = %08x) for TX Checksum Offload.\n", skb->protocol); */ ++ } else ++#endif ++ ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); ++ } ++ ++ *pucFlag = ucFlag; ++ ++} /* kalQueryChksumOffloadParam */ ++ ++/* 4 2007/10/8, mikewu, this is rewritten by Mike */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To update the checksum offload status to the packet to be indicated to OS. ++* ++* \param[in] pvPacket Pointer to the packet descriptor. ++* \param[in] pucFlag Points to the offload related parameter. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T aeCSUM[]) ++{ ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ ++ ASSERT(pvPacket); ++ ++ if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS) && ++ ((aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) || (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS))) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++#if DBG ++ if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) ++ DBGLOG(RX, TRACE, "RX: \"non-IPv4/IPv6\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad IP Checksum\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad TCP Checksum\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad UDP Checksum\" Packet\n"); ++ else ++ /* Do nothing */ ++#endif ++ } ++ ++} /* kalUpdateRxCSUMOffloadParam */ ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to free packet allocated from kalPacketAlloc. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of the packet descriptor ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) ++{ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ if (prGlueInfo) ++ prGlueInfo->u8SkbFreed++; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Only handles driver own creating packet (coalescing buffer). ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* \param u4Size Pointer of Packet Handle ++* \param ppucData Status Code for OS upper layer ++* ++* \return NULL: Failed to allocate skb, Not NULL get skb ++*/ ++/*----------------------------------------------------------------------------*/ ++PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData) ++{ ++ struct sk_buff *prSkb = dev_alloc_skb(u4Size); ++ ++ if (prSkb) ++ *ppucData = (PUINT_8) (prSkb->data); ++#if DBG ++ { ++ PUINT_32 pu4Head = (PUINT_32) &prSkb->cb[0]; ++ *pu4Head = (UINT_32) prSkb->head; ++ DBGLOG(RX, TRACE, "prSkb->head = %#x, prSkb->cb = %#x\n", (UINT_32) prSkb->head, *pu4Head); ++ } ++#endif ++ return (PVOID) prSkb; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Process the received packet for indicating to OS. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure. ++* \param[in] pvPacket Pointer of the packet descriptor ++* \param[in] pucPacketStart The starting address of the buffer of Rx packet. ++* \param[in] u4PacketLen The packet length. ++* \param[in] pfgIsRetain Is the packet to be retained. ++* \param[in] aerCSUM The result of TCP/ IP checksum offload. ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, ++ /* IN PBOOLEAN pfgIsRetain, */ ++ IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aerCSUM[]) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ ++ skb->data = pucPacketStart; ++ skb_reset_tail_pointer(skb); /* reset tail pointer first, for 64bit kernel,we should call linux kernel API */ ++ skb_trim(skb, 0); /* only if skb->len > len, then skb_trim has effect */ ++ skb_put(skb, u4PacketLen); /* shift tail and skb->len to correct value */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ kalUpdateRxCSUMOffloadParam(skb, aerCSUM); ++#endif ++ ++ return rStatus; ++} ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Do HIF loopback test. ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++unsigned int testmode = 0; ++unsigned int testlen = 64; ++ ++void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo) ++{ ++#define HIF_LOOPBK_AUTO_TEST_LEN 1600 ++/* GL_HIF_INFO_T *HifInfo; */ ++ static unsigned int txcnt; ++ struct sk_buff *MsduInfo; ++ UINT_8 *Pkt; ++ UINT_32 RegVal; ++ UINT_32 PktLen = 16; ++ ++ /* Init */ ++ if (testmode != 0) { ++ PktLen = kalRandomNumber() % 1520; ++ if (PktLen < 64) ++ PktLen = 64; ++ } else { ++ PktLen = testlen++; ++ if (PktLen > 1520) { ++ testmode = 1; ++ PktLen = 64; ++ } ++ } ++ ++/* PktLen = 100; */ ++ DBGLOG(INIT, INFO, "kalDevLoopbkAuto> Send a packet to HIF (len = %d) (total = %d)...\n", PktLen, ++txcnt); ++/* HifInfo = &GlueInfo->rHifInfo; */ ++ ++ /* Allocate a MSDU_INFO_T */ ++ MsduInfo = kalPacketAlloc(GlueInfo, HIF_LOOPBK_AUTO_TEST_LEN, &Pkt); ++ if (MsduInfo == NULL) { ++ DBGLOG(INIT, WARN, "No PKT_INFO_T for sending loopback packet!\n"); ++ return; ++ } ++ ++ /* Init the packet */ ++ MsduInfo->dev = GlueInfo->prDevHandler; ++ if (MsduInfo->dev == NULL) { ++ DBGLOG(INIT, WARN, "MsduInfo->dev == NULL!!\n"); ++ kalPacketFree(GlueInfo, MsduInfo); ++ return; ++ } ++ ++ MsduInfo->len = PktLen; ++ kalMemSet(MsduInfo->data, 0xff, 6); ++ kalMemSet(MsduInfo->data + 6, 0x5a, PktLen - 6); ++ ++ /* Simulate OS to send the packet */ ++ wlanHardStartXmit(MsduInfo, MsduInfo->dev); ++ ++#if 0 ++ PktLen += 4; ++ if (PktLen >= 1600) ++ PktLen = 16; ++#endif ++ ++ /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ ++/* HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(1000); */ ++/* add_timer(&(HifInfo->HifTmrLoopbkFn)); */ ++} ++ ++int kalDevLoopbkThread(IN void *data) ++{ ++ struct net_device *dev = data; ++ P_GLUE_INFO_T GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); ++ GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; ++ int ret; ++ static int test; ++ ++ while (TRUE) { ++ ret = wait_event_interruptible(HifInfo->HifWaitq, (HifInfo->HifLoopbkFlg != 0)); ++ ++ if (HifInfo->HifLoopbkFlg == 0xFFFFFFFF) ++ break; ++ ++ while (TRUE) { ++ /* if ((HifInfo->HifLoopbkFlg & 0x01) == 0) */ ++ if (GlueInfo->i4TxPendingFrameNum < 64) { ++ DBGLOG(INIT, INFO, "GlueInfo->i4TxPendingFrameNum = %d\n", ++ GlueInfo->i4TxPendingFrameNum); ++ kalDevLoopbkAuto(GlueInfo); ++ ++ if (testmode == 0) ++ kalMsleep(3000); ++ } else ++ kalMsleep(1); ++ } ++ } ++} ++ ++void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ static unsigned int rxcnt; ++ UINT_32 i; ++ UINT_8 *Buf = prSwRfb->pucRecvBuff + sizeof(HIF_TX_HEADER_T); ++ P_HIF_RX_HEADER_T prHifRxHdr = prSwRfb->prHifRxHdr; ++ UINT_32 len = prHifRxHdr->u2PacketLen - sizeof(HIF_TX_HEADER_T); ++ ++ if (len > 1600) { ++ while (1) ++ DBGLOG(INIT, ERROR, "HIF> Loopback len > 1600!!! error!!!\n"); ++ } ++ ++ for (i = 0; i < 6; i++) { ++ if (Buf[i] != 0xff) { ++ while (1) { ++ DBGLOG(INIT, ERROR, "HIF> Loopbk dst addr error (len = %d)!\n", len); ++ dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); ++ } ++ } ++ } ++ ++ for (i = 6; i < len; i++) { ++ if (Buf[i] != 0x5a) { ++ while (1) { ++ DBGLOG(INIT, ERROR, "HIF> Loopbk error (len = %d)!\n", len); ++ dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); ++ } ++ } ++ } ++ ++ DBGLOG(INIT, INFO, "HIF> Loopbk OK (len = %d) (total = %d)!\n", len, ++rxcnt); ++} ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate an array of received packets is available for higher ++* level protocol uses. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure. ++* \param[in] apvPkts The packet array to be indicated ++* \param[in] ucPktNum The number of packets to be indicated ++* ++* \retval TRUE Success. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum) ++{ ++ UINT_8 ucIdx = 0; ++ struct net_device *prNetDev = prGlueInfo->prDevHandler; ++ struct sk_buff *prSkb = NULL; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(apvPkts); ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ for (ucIdx = 0; ucIdx < ucPktNum; ucIdx++) { ++ prSkb = apvPkts[ucIdx]; ++#if DBG ++ do { ++ PUINT_8 pu4Head = (PUINT_8) &prSkb->cb[0]; ++ UINT_32 u4HeadValue = 0; ++ ++ kalMemCopy(&u4HeadValue, pu4Head, sizeof(u4HeadValue)); ++ DBGLOG(RX, TRACE, "prSkb->head = %p, prSkb->cb = 0x%x\n", pu4Head, u4HeadValue); ++ } while (0); ++#endif ++ ++ if (GLUE_GET_PKT_IS_P2P(prSkb)) { ++ /* P2P */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ prNetDev = kalP2PGetDevHdlr(prGlueInfo); ++ /* prNetDev->stats.rx_bytes += prSkb->len; */ ++ /* prNetDev->stats.rx_packets++; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_packets++; ++ ++#else ++ prNetDev = prGlueInfo->prDevHandler; ++#endif ++ } else if (GLUE_GET_PKT_IS_PAL(prSkb)) { ++ /* BOW */ ++#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_SEPARATE_DATA_PATH ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered) ++ prNetDev = prGlueInfo->rBowInfo.prDevHandler; ++#else ++ prNetDev = prGlueInfo->prDevHandler; ++#endif ++ } else { ++ /* AIS */ ++ prNetDev = prGlueInfo->prDevHandler; ++ prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.rx_packets++; ++ ++ } ++ ++ /* check if the "unicast" packet is from us */ ++ if (kalMemCmp(prSkb->data, prSkb->data + 6, 6) == 0) { ++ /* we will filter broadcast/multicast packet sent from us in hardware */ ++ /* source address = destination address ? */ ++ DBGLOG(RX, EVENT, ++ "kalRxIndicatePkts got from us!!! Drop it! ([ %pM ] len %d)\n", ++ prSkb->data, prSkb->len); ++ wlanReturnPacket(prGlueInfo->prAdapter, prSkb); ++ continue; ++ } ++#if (CFG_SUPPORT_TDLS == 1) ++ if (TdlsexRxFrameDrop(prGlueInfo, prSkb->data) == TRUE) { ++ /* drop the received TDLS action frame */ ++ DBGLOG(TDLS, WARN, ++ " %s: drop a received packet from %pM %u\n", ++ __func__, prSkb->data, ++ (UINT32) ((P_ADAPTER_T) (prGlueInfo->prAdapter))->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ wlanReturnPacket(prGlueInfo->prAdapter, prSkb); ++ continue; ++ } ++ ++ /* ++ get a TDLS request/response/confirm, we need to parse the HT IE ++ because older supplicant does not pass HT IE to us ++ */ ++ TdlsexRxFrameHandle(prGlueInfo, prSkb->data, prSkb->len); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ STATS_RX_PKT_INFO_DISPLAY(prSkb->data); ++ ++ //prNetDev->last_rx = jiffies; ++ prSkb->protocol = eth_type_trans(prSkb, prNetDev); ++ prSkb->dev = prNetDev; ++ /* DBGLOG_MEM32(RX, TRACE, (PUINT_32)prSkb->data, prSkb->len); */ ++ DBGLOG(RX, TRACE, "kalRxIndicatePkts len = %d\n", prSkb->len); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Rx sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "Rx sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "Rx sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"); ++#endif ++ ++ if (!in_interrupt()) ++ netif_rx_ni(prSkb); /* only in non-interrupt context */ ++ else ++ netif_rx(prSkb); ++ ++ wlanReturnPacket(prGlueInfo->prAdapter, NULL); ++ } ++ ++ kalPerMonStart(prGlueInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Called by driver to indicate event to upper layer, for example, the wpa ++* supplicant or wireless tools. ++* ++* \param[in] pvAdapter Pointer to the adapter descriptor. ++* \param[in] eStatus Indicated status. ++* \param[in] pvBuf Indicated message buffer. ++* \param[in] u4BufLen Indicated message buffer size. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ScanCnt = 0, ScanDoneFailCnt = 0; ++VOID ++kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen) ++{ ++ UINT_32 bufLen; ++ P_PARAM_STATUS_INDICATION_T pStatus = (P_PARAM_STATUS_INDICATION_T) pvBuf; ++ P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T) pStatus; ++ P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = (P_PARAM_PMKID_CANDIDATE_LIST_T) (pStatus + 1); ++ PARAM_MAC_ADDRESS arBssid; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ PARAM_SSID_T ssid; ++ struct ieee80211_channel *prChannel = NULL; ++ struct cfg80211_bss *bss; ++ UINT_8 ucChannelNum; ++ P_BSS_DESC_T prBssDesc = NULL; ++ struct cfg80211_scan_info info = { ++ .aborted = false, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ ++ ASSERT(prGlueInfo); ++ ++ switch (eStatus) { ++ case WLAN_STATUS_ROAM_OUT_FIND_BEST: ++ case WLAN_STATUS_MEDIA_CONNECT: ++ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; ++ ++ /* indicate assoc event */ ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &bufLen); ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); ++ ++ /* switch netif on */ ++ netif_carrier_on(prGlueInfo->prDevHandler); ++ ++ do { ++ /* print message on console */ ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQuerySsid, &ssid, sizeof(ssid), &bufLen); ++ ++ ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? ++ (PARAM_MAX_LEN_SSID - 1) : ssid.u4SsidLen] = '\0'; ++ DBGLOG(AIS, INFO, " %s netif_carrier_on [ssid:%s %pM ]\n", ++ prGlueInfo->prDevHandler->name, ssid.aucSsid, arBssid); ++ } while (0); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ struct cfg80211_bss *bss_others = NULL; ++ UINT_8 ucLoopCnt = 15; /* only loop 15 times to avoid dead loop */ ++ ++ /* retrieve channel */ ++ ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, ++ NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, ++ NL80211_BAND_5GHZ)); ++ } ++ ++ /* ensure BSS exists */ ++ bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), prChannel, arBssid, ++ ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ ++ if (bss == NULL) { ++ /* create BSS on-the-fly */ ++ prBssDesc = ++ wlanGetTargetBssDescByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prBssDesc != NULL) { ++ bss = cfg80211_inform_bss(priv_to_wiphy(prGlueInfo), prChannel, ++ CFG80211_BSS_FTYPE_PRESP, ++ arBssid, 0, /* TSF */ ++ WLAN_CAPABILITY_ESS, ++ prBssDesc->u2BeaconInterval, /* beacon interval */ ++ prBssDesc->aucIEBuf, /* IE */ ++ prBssDesc->u2IELength, /* IE Length */ ++ RCPI_TO_dBm(prBssDesc->ucRCPI) * 100, /* MBM */ ++ GFP_KERNEL); ++ } ++ } ++ /* remove all bsses that before and only channel different with the current connected one ++ if without this patch, UI will show channel A is connected even if AP has change channel ++ from A to B */ ++ while (ucLoopCnt--) { ++ bss_others = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), NULL, arBssid, ++ ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ if (bss && bss_others && bss_others != bss) { ++ DBGLOG(SCN, INFO, "remove BSSes that only channel different\n"); ++ cfg80211_unlink_bss(priv_to_wiphy(prGlueInfo), bss_others); ++ } else ++ break; ++ } ++ ++ /* CFG80211 Indication */ ++ if (eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { ++ /*cfg80211_roamed_bss(prGlueInfo->prDevHandler, ++ bss, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, prGlueInfo->u4RspIeLength, GFP_KERNEL); ++ */ ++ struct cfg80211_roam_info roam_info = { ++ .bss = bss, ++ .req_ie = prGlueInfo->aucReqIe, ++ .req_ie_len = prGlueInfo->u4ReqIeLength, ++ .resp_ie = prGlueInfo->aucRspIe, ++ .resp_ie_len = prGlueInfo->u4RspIeLength ++ }; ++ cfg80211_roamed(prGlueInfo->prDevHandler, ++ &roam_info, ++ GFP_KERNEL); ++ } else { ++ /* to support user space roaming, cfg80211 will change the sme_state to connecting ++ before reassociate */ ++ cfg80211_connect_result(prGlueInfo->prDevHandler, ++ arBssid, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, ++ prGlueInfo->u4RspIeLength, WLAN_STATUS_SUCCESS, GFP_KERNEL); ++ } ++ } ++ ++ break; ++ ++ case WLAN_STATUS_MEDIA_DISCONNECT: ++ case WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY: ++ /* indicate disassoc event */ ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); ++ /* For CR 90 and CR99, While supplicant do reassociate, driver will do netif_carrier_off first, ++ after associated success, at joinComplete(), do netif_carier_on, ++ but for unknown reason, the supplicant 1x pkt will not called the driver ++ hardStartXmit, for template workaround these bugs, add this compiling flag ++ */ ++ /* switch netif off */ ++ ++ DBGLOG(AIS, INFO, "[wifi] %s netif_carrier_off\n", ++ prGlueInfo->prDevHandler->name); ++ ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ P_WIFI_VAR_T prWifiVar = &prGlueInfo->prAdapter->rWifiVar; ++ UINT_16 u2DeauthReason = prWifiVar->arBssInfo[NETWORK_TYPE_AIS_INDEX].u2DeauthReason; ++ /* CFG80211 Indication */ ++ DBGLOG(AIS, INFO, "[wifi] %s cfg80211_disconnected\n", prGlueInfo->prDevHandler->name); ++ cfg80211_disconnected(prGlueInfo->prDevHandler, u2DeauthReason, NULL, 0, false, GFP_KERNEL); ++ } ++ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ break; ++ ++ case WLAN_STATUS_SCAN_COMPLETE: ++ /* indicate scan complete event */ ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); ++ ++ /* 1. reset first for newly incoming request */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueInfo->prScanRequest; ++ prGlueInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ /* 2. then CFG80211 Indication */ ++ DBGLOG(SCN, TRACE, "[ais] scan complete %p %d %d\n", prScanRequest, ScanCnt, ScanDoneFailCnt); ++ ++ if (prScanRequest != NULL) ++ cfg80211_scan_done(prScanRequest, &info); ++ break; ++ case WLAN_STATUS_CONNECT_INDICATION: ++ /* indicate AIS Jion fail event ++ if (prGlueInfo->prDevHandler->ieee80211_ptr->sme_state == CFG80211_SME_CONNECTING) */ ++ cfg80211_connect_result(prGlueInfo->prDevHandler, ++ prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc->aucBSSID, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, ++ prGlueInfo->u4RspIeLength, WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); ++ break; ++ ++#if 0 ++ case WLAN_STATUS_MSDU_OK: ++ if (netif_running(prGlueInfo->prDevHandler)) ++ netif_wake_queue(prGlueInfo->prDevHandler); ++ break; ++#endif ++ ++ case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: ++ if (pStatus) { ++ switch (pStatus->eStatusType) { ++ case ENUM_STATUS_TYPE_AUTHENTICATION: ++ /* ++ printk(KERN_NOTICE "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [ %pM ] F:%lx\n", ++ pAuth->Request[0].Length, ++ pAuth->Request[0].Bssid, ++ pAuth->Request[0].Flags); ++ */ ++ /* indicate (UC/GC) MIC ERROR event only */ ++ if ((pAuth->arRequest[0].u4Flags == ++ PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || ++ (pAuth->arRequest[0].u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR)) { ++ cfg80211_michael_mic_failure(prGlueInfo->prDevHandler, NULL, ++ (pAuth->arRequest[0].u4Flags == ++ PARAM_AUTH_REQUEST_PAIRWISE_ERROR) ? ++ NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP, ++ 0, NULL, GFP_KERNEL); ++ wext_indicate_wext_event(prGlueInfo, IWEVMICHAELMICFAILURE, ++ (unsigned char *)&pAuth->arRequest[0], ++ pAuth->arRequest[0].u4Length); ++ } ++ break; ++ ++ case ENUM_STATUS_TYPE_CANDIDATE_LIST: ++ /* ++ printk(KERN_NOTICE "Param_StatusType_PMKID_CandidateList: Ver(%ld) Num(%ld)\n", ++ pPmkid->u2Version, ++ pPmkid->u4NumCandidates); ++ if (pPmkid->u4NumCandidates > 0) { ++ printk(KERN_NOTICE "candidate[ %pM ] preAuth Flag:%lx\n", ++ pPmkid->arCandidateList[0].rBSSID, ++ pPmkid->arCandidateList[0].fgFlags); ++ } ++ */ ++ { ++ UINT_32 i = 0; ++ /*struct net_device *prDev = prGlueInfo->prDevHandler; */ ++ P_PARAM_PMKID_CANDIDATE_T prCand = NULL; ++ /* indicate pmk candidate via cfg80211 to supplicant, ++ the second parameter is 1000 for ++ cfg80211_pmksa_candidate_notify, because wpa_supplicant defined it. */ ++ for (i = 0; i < pPmkid->u4NumCandidates; i++) { ++ prCand = &pPmkid->arCandidateList[i]; ++ cfg80211_pmksa_candidate_notify(prGlueInfo->prDevHandler, 1000, ++ prCand->arBSSID, prCand->u4Flags, ++ GFP_KERNEL); ++ ++ wext_indicate_wext_event(prGlueInfo, ++ IWEVPMKIDCAND, ++ (unsigned char *)prCand, ++ pPmkid->u4NumCandidates); ++ } ++ } ++ break; ++ ++ default: ++ /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ ++ /* ++ printk(KERN_NOTICE "unknown media specific indication type:%x\n", ++ pStatus->StatusType); ++ */ ++ break; ++ } ++ } else { ++ /* ++ printk(KERN_WARNING "media specific indication buffer NULL\n"); ++ */ ++ } ++ break; ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ case WLAN_STATUS_BWCS_UPDATE: ++ { ++ wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, sizeof(PTA_IPC_T)); ++ } ++ ++ break; ++ ++#endif ++ ++ default: ++ /* ++ printk(KERN_WARNING "unknown indication:%lx\n", eStatus); ++ */ ++ break; ++ } ++} /* kalIndicateStatusAndComplete */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to update the (re)association request ++* information to the structure used to query and set ++* OID_802_11_ASSOCIATION_INFORMATION. ++* ++* \param[in] prGlueInfo Pointer to the Glue structure. ++* \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association ++* Request frame from the AP. ++* \param[in] u4FrameBodyLen The length of the frame body of the last ++* (Re)Association Request frame. ++* \param[in] fgReassocRequest TRUE, if it is a Reassociation Request frame. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) ++{ ++ PUINT_8 cp; ++ ++ ASSERT(prGlueInfo); ++ ++ /* reset */ ++ prGlueInfo->u4ReqIeLength = 0; ++ ++ if (fgReassocRequest) { ++ if (u4FrameBodyLen < 15) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } else { ++ if (u4FrameBodyLen < 9) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } ++ ++ cp = pucFrameBody; ++ ++ if (fgReassocRequest) { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ /* Current AP address 6 */ ++ cp += 10; ++ u4FrameBodyLen -= 10; ++ } else { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ cp += 4; ++ u4FrameBodyLen -= 4; ++ } ++ ++ wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, u4FrameBodyLen); ++ ++ if (u4FrameBodyLen <= CFG_CFG80211_IE_BUF_LEN) { ++ prGlueInfo->u4ReqIeLength = u4FrameBodyLen; ++ kalMemCopy(prGlueInfo->aucReqIe, cp, u4FrameBodyLen); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is called to update the (re)association ++* response information to the structure used to reply with ++* cfg80211_connect_result ++* ++* @param prGlueInfo Pointer to adapter descriptor ++* @param pucFrameBody Pointer to the frame body of the last (Re)Association ++* Response frame from the AP ++* @param u4FrameBodyLen The length of the frame body of the last ++* (Re)Association Response frame ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen) ++{ ++ UINT_32 u4IEOffset = 6; /* cap_info, status_code & assoc_id */ ++ UINT_32 u4IELength = u4FrameBodyLen - u4IEOffset; ++ ++ ASSERT(prGlueInfo); ++ ++ /* reset */ ++ prGlueInfo->u4RspIeLength = 0; ++ ++ if (u4IELength <= CFG_CFG80211_IE_BUF_LEN) { ++ prGlueInfo->u4RspIeLength = u4IELength; ++ kalMemCopy(prGlueInfo->aucRspIe, pucFrameBody + u4IEOffset, u4IELength); ++ } ++ ++} /* kalUpdateReAssocRspInfo */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Notify OS with SendComplete event of the specific packet. Linux should ++* free packets here. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] status Status Code for OS upper layer ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) ++{ ++ ++ struct net_device *prDev = NULL; ++ struct sk_buff *prSkb = NULL; ++ UINT_16 u2QueueIdx = 0; ++ UINT_8 ucNetworkType = 0; ++ BOOLEAN fgIsValidDevice = TRUE; ++ ++ ASSERT(pvPacket); ++ ASSERT(prGlueInfo->i4TxPendingFrameNum); ++ ++ prSkb = (struct sk_buff *)pvPacket; ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++ if (GLUE_GET_PKT_IS_PAL(prSkb)) { ++ ucNetworkType = NETWORK_TYPE_BOW_INDEX; ++ } else if (GLUE_GET_PKT_IS_P2P(prSkb)) { ++ ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* in case packet was sent after P2P device is unregistered */ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) ++ fgIsValidDevice = FALSE; ++#endif ++ } else { ++ ucNetworkType = NETWORK_TYPE_AIS_INDEX; ++ } ++ ++ GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) ++ GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); ++ prDev = prSkb->dev; ++ ++ ASSERT(prDev); ++ ++ if ((fgIsValidDevice == TRUE) && (u2QueueIdx < CFG_MAX_TXQ_NUM)) { ++ if (netif_subqueue_stopped(prDev, prSkb) && ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx] <= ++ CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_wake_subqueue for bss: %d. Queue len: %d\n", ++ ucNetworkType, ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); ++ netif_wake_subqueue(prDev, u2QueueIdx); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ prGlueInfo->rHifInfo.HifLoopbkFlg &= ~0x01; ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ } ++ } ++ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ prGlueInfo->u8SkbFreed++; ++ ++ DBGLOG(TX, EVENT, "----- pending frame %d -----\n", prGlueInfo->i4TxPendingFrameNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Copy Mac Address setting from registry. It's All Zeros in Linux. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \param[out] paucMacAddr Pointer to the Mac Address buffer ++* ++* \retval WLAN_STATUS_SUCCESS ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_8 paucMacAddr) ++{ ++ UINT_8 aucZeroMac[MAC_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 } ++ ++ DEBUGFUNC("kalQueryRegistryMacAddr"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(paucMacAddr); ++ ++ kalMemCopy((PVOID) paucMacAddr, (PVOID) aucZeroMac, MAC_ADDR_LEN); ++ ++} /* end of kalQueryRegistryMacAddr() */ ++ ++#if CFG_SUPPORT_EXT_CONFIG ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read external configuration, ex. NVRAM or file ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ /* External data is given from user space by ioctl or /proc, not read by ++ driver. ++ */ ++ if (0 != prGlueInfo->u4ExtCfgLength) ++ DBGLOG(INIT, TRACE, "Read external configuration data -- OK\n"); ++ else ++ DBGLOG(INIT, TRACE, "Read external configuration data -- fail\n"); ++ ++ return prGlueInfo->u4ExtCfgLength; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This inline function is to extract some packet information, including ++* user priority, packet length, destination address, 802.1x and BT over Wi-Fi ++* or not. ++* ++* @param prGlueInfo Pointer to the glue structure ++* @param prNdisPacket Packet descriptor ++* @param pucPriorityParam User priority ++* @param pu4PacketLen Packet length ++* @param pucEthDestAddr Destination address ++* @param pfgIs1X 802.1x packet or not ++* @param pfgIsPAL BT over Wi-Fi packet or not ++* @prGenUse General used param ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN ++kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_NATIVE_PACKET prPacket, ++ OUT PUINT_8 pucPriorityParam, ++ OUT PUINT_32 pu4PacketLen, ++ OUT PUINT_8 pucEthDestAddr, ++ OUT PBOOLEAN pfgIs1X, ++ OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, ++ OUT PVOID prGenUse) ++{ ++ ++ UINT_32 u4PacketLen; ++ ++ UINT_8 ucUserPriority = USER_PRIORITY_DEFAULT; /* Default */ ++ UINT_16 u2EtherTypeLen; ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ PUINT_8 aucLookAheadBuf = NULL; ++ ++ DEBUGFUNC("kalQoSFrameClassifierAndPacketInfo"); ++ ++ u4PacketLen = prSkb->len; ++ ++ if (u4PacketLen < ETH_HLEN) { ++ DBGLOG(TX, WARN, "Invalid Ether packet length: %u\n", (UINT_32) u4PacketLen); ++ return FALSE; ++ } ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ *pfgIs1X = FALSE; ++ *pfgIsPAL = FALSE; ++ ++ /* 4 <3> Obtain the User Priority for WMM */ ++ u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { ++ PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucIpVersion; ++ ++ ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if (ucIpVersion == IPVERSION) { ++ UINT_8 ucIpTos; ++ /* Get the DSCP value from the header of IP packet. */ ++ ucIpTos = pucIpHdr[1]; ++ ucUserPriority = ((ucIpTos & IPTOS_PREC_MASK) >> IPTOS_PREC_OFFSET); ++ } ++ ++ /* TODO(Kevin): Add TSPEC classifier here */ ++ } else if (u2EtherTypeLen == ETH_P_1X || u2EtherTypeLen == ETH_P_PRE_1X) { /* For Port Control */ ++ PUINT_8 pucEapol = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucEapolType = pucEapol[1]; ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ /* ++ * generate a seq number used to trace security frame TX ++ */ ++ if (prGenUse) ++ *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 1: /* eapol start */ ++ DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 3: /* key */ ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x... seqNo %d\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ } ++ *pfgIs1X = TRUE; ++ } ++#if CFG_SUPPORT_WAPI ++ else if (u2EtherTypeLen == ETH_WPI_1X) { ++ PUINT_8 pucEthBody = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ ++ UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; ++ UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; ++ ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ *pfgIs1X = TRUE; ++ } ++#endif ++#if (CFG_SUPPORT_TDLS == 1) ++ else if (u2EtherTypeLen == TDLS_FRM_PROT_TYPE) { ++ /* TDLS case */ ++ TDLSEX_UP_ASSIGN(ucUserPriority); ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ else if (u2EtherTypeLen <= 1500) { /* 802.3 Frame */ ++ UINT_8 ucDSAP, ucSSAP, ucControl; ++ UINT_8 aucOUI[3]; ++ ++ ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; ++ ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; ++ ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; ++ ++ aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; ++ aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; ++ aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; ++ ++ if (ucDSAP == ETH_LLC_DSAP_SNAP && ++ ucSSAP == ETH_LLC_SSAP_SNAP && ++ ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && ++ aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && ++ aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) { ++ ++ UINT_16 tmp = ++ ((aucLookAheadBuf[ETH_SNAP_OFFSET + 3] << 8) | aucLookAheadBuf[ETH_SNAP_OFFSET + 4]); ++ ++ *pfgIsPAL = TRUE; ++ ucUserPriority = (UINT_8) prSkb->priority; ++ ++ if (tmp == BOW_PROTOCOL_ID_SECURITY_FRAME) { ++ PUINT_8 pucEapol = &aucLookAheadBuf[ETH_SNAP_OFFSET + 5]; ++ UINT_8 ucEapolType = pucEapol[1]; ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ if (prGenUse) ++ *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 1: /* eapol start */ ++ DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 3: /* key */ ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x seqNo %d\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ } ++ *pfgIs1X = TRUE; ++ } ++ } ++ } ++ /* 4 <4> Return the value of Priority Parameter. */ ++ *pucPriorityParam = ucUserPriority; ++ ++ /* 4 <5> Retrieve Packet Information - DA */ ++ /* Packet Length/ Destination Address */ ++ *pu4PacketLen = u4PacketLen; ++ ++ kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); ++ ++ /* <6> Network type */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (*pfgIsPAL == TRUE) { ++ *pucNetworkType = NETWORK_TYPE_BOW_INDEX; ++ } else ++#endif ++ { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered && GLUE_GET_PKT_IS_P2P(prPacket)) { ++ *pucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } else ++#endif ++ { ++ *pucNetworkType = NETWORK_TYPE_AIS_INDEX; ++ } ++ } ++ return TRUE; ++} /* end of kalQoSFrameClassifier() */ ++ ++VOID ++kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, ++ IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus) ++{ ++ ++ ASSERT(prGlueInfo); ++ /* remove timeout check timer */ ++ wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); ++ ++ /* if (prGlueInfo->u4TimeoutFlag != 1) { */ ++ prGlueInfo->rPendStatus = rOidStatus; ++ DBGLOG(OID, TEMP, "kalOidComplete, caller: %p\n", __builtin_return_address(0)); ++ complete(&prGlueInfo->rPendComp); ++ prGlueInfo->u4OidCompleteFlag = 1; ++ /* } */ ++ /* else let it timeout on kalIoctl entry */ ++} ++ ++VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ /* if (prGlueInfo->u4TimeoutFlag != 1) { */ ++ /* clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag); */ ++ if (prGlueInfo->u4OidCompleteFlag != 1) { ++ DBGLOG(OID, TEMP, "kalOidClearance, caller: %p\n", __builtin_return_address(0)); ++ complete(&prGlueInfo->rPendComp); ++ } ++ /* } */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to transfer linux ioctl to OID, and we ++* need to specify the behavior of the OID by ourself ++* ++* @param prGlueInfo Pointer to the glue structure ++* @param pvInfoBuf Data buffer ++* @param u4InfoBufLen Data buffer length ++* @param fgRead Is this a read OID ++* @param fgWaitResp does this OID need to wait for values ++* @param fgCmd does this OID compose command packet ++* @param pu4QryInfoLen The data length of the return values ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++/* todo: enqueue the i/o requests for multiple processes access */ ++/* */ ++/* currently, return -1 */ ++/* */ ++ ++/* static GL_IO_REQ_T OidEntry; */ ++ ++WLAN_STATUS ++kalIoctl(IN P_GLUE_INFO_T prGlueInfo, ++ IN PFN_OID_HANDLER_FUNC pfnOidHandler, ++ IN PVOID pvInfoBuf, ++ IN UINT_32 u4InfoBufLen, ++ IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen) ++{ ++ P_GL_IO_REQ_T prIoReq = NULL; ++ WLAN_STATUS ret = WLAN_STATUS_SUCCESS; ++ ++ if (fgIsResetting == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ ++ /* GLUE_SPIN_LOCK_DECLARATION(); */ ++ ASSERT(prGlueInfo); ++ ++ /* <1> Check if driver is halt */ ++ /* if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { */ ++ /* return WLAN_STATUS_ADAPTER_NOT_READY; */ ++ /* } */ ++ ++ /* if wait longer than double OID timeout timer, then will show backtrace who held halt lock. ++ at this case, we will return kalIoctl failure because tx_thread may be hung */ ++ if (kalHaltLock(2 * WLAN_OID_TIMEOUT_THRESHOLD)) ++ return WLAN_STATUS_FAILURE; ++ ++ if (kalIsHalted()) { ++ kalHaltUnlock(); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (down_interruptible(&prGlueInfo->ioctl_sem)) { ++ kalHaltUnlock(); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* <2> TODO: thread-safe */ ++ ++ /* <3> point to the OidEntry of Glue layer */ ++ ++ prIoReq = &(prGlueInfo->OidEntry); ++ ++ ASSERT(prIoReq); ++ ++ /* <4> Compose the I/O request */ ++ prIoReq->prAdapter = prGlueInfo->prAdapter; ++ prIoReq->pfnOidHandler = pfnOidHandler; ++ prIoReq->pvInfoBuf = pvInfoBuf; ++ prIoReq->u4InfoBufLen = u4InfoBufLen; ++ prIoReq->pu4QryInfoLen = pu4QryInfoLen; ++ prIoReq->fgRead = fgRead; ++ prIoReq->fgWaitResp = fgWaitResp; ++ prIoReq->rStatus = WLAN_STATUS_FAILURE; ++#if CFG_ENABLE_WIFI_DIRECT ++ prIoReq->fgIsP2pOid = fgIsP2pOid; ++#endif ++ ++ /* <5> Reset the status of pending OID */ ++ prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; ++ /* prGlueInfo->u4TimeoutFlag = 0; */ ++ /* prGlueInfo->u4OidCompleteFlag = 0; */ ++ ++ /* <6> Check if we use the command queue */ ++ prIoReq->u4Flag = fgCmd; ++ ++ /* <7> schedule the OID bit */ ++ set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); ++ ++ /* <8> Wake up tx thread to handle kick start the I/O request */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ /* <9> Block and wait for event or timeout, current the timeout is 5 secs */ ++ /* if (wait_for_completion_interruptible_timeout(&prGlueInfo->rPendComp, 5 * KAL_HZ)) { */ ++ /* if (!wait_for_completion_interruptible(&prGlueInfo->rPendComp)) { */ ++ DBGLOG(OID, TEMP, "kalIoctl: before wait, caller: %p\n", __builtin_return_address(0)); ++ wait_for_completion(&prGlueInfo->rPendComp); { ++ /* Case 1: No timeout. */ ++ /* if return WLAN_STATUS_PENDING, the status of cmd is stored in prGlueInfo */ ++ if (prIoReq->rStatus == WLAN_STATUS_PENDING) ++ ret = prGlueInfo->rPendStatus; ++ else ++ ret = prIoReq->rStatus; ++ } ++#if 0 ++ else { ++ /* Case 2: timeout */ ++ /* clear pending OID's cmd in CMD queue */ ++ if (fgCmd) { ++ prGlueInfo->u4TimeoutFlag = 1; ++ wlanReleasePendingOid(prGlueInfo->prAdapter, 0); ++ } ++ ret = WLAN_STATUS_FAILURE; ++ } ++#endif ++ DBGLOG(OID, TEMP, "kalIoctl: done\n"); ++ up(&prGlueInfo->ioctl_sem); ++ kalHaltUnlock(); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending security frames ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending security frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear pending security frames ++* belongs to dedicated network type ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* \param eNetworkTypeIdx Network Type Index ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending security frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && prCmdInfo->eNetworkType == eNetworkTypeIdx) { ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending management frames ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending management frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending management frames ++* belongs to dedicated network type ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending management frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && ++ prCmdInfo->eNetworkType == eNetworkTypeIdx) { ++ wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} /* kalClearMgmtFramesByNetType */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is a kernel thread function for handling command packets ++* Tx requests and interrupt events ++* ++* @param data data pointer to private data of tx_thread ++* ++* @retval If the function succeeds, the return value is 0. ++* Otherwise, an error code is returned. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++int tx_thread(void *data) ++{ ++ struct net_device *dev = data; ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_GL_IO_REQ_T prIoReq = NULL; ++ P_QUE_T prTxQueue = NULL; ++ P_QUE_T prCmdQue = NULL; ++ ++ int ret = 0; ++ ++ BOOLEAN fgNeedHwAccess = FALSE; ++ ++ struct sk_buff *prSkb = NULL; ++ ++ /* for spin lock acquire and release */ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ prTxQueue = &prGlueInfo->rTxQueue; ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ current->flags |= PF_NOFREEZE; ++ ++ DBGLOG(INIT, INFO, "tx_thread starts running...\n"); ++ ++ while (TRUE) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*run p2p multicast list work. */ ++ if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) ++ p2pSetMulticastListWorkQueueWrapper(prGlueInfo); ++#endif ++ ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ DBGLOG(INIT, INFO, "tx_thread should stop now...\n"); ++ break; ++ } ++ ++ /* ++ * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT ++ * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT ++ * ++ */ ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ ++ ret = wait_event_interruptible(prGlueInfo->waitq, (prGlueInfo->ulFlag != 0)); ++ ++ KAL_WAKE_LOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ ++/* #if (CONF_HIF_LOOPBACK_AUTO == 1) */ ++/* if (test_and_clear_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &prGlueInfo->u4Flag)) { */ ++/* kalDevLoopbkAuto(prGlueInfo); */ ++/* } */ ++/* #endif */ /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if CFG_DBG_GPIO_PINS ++ /* TX thread Wake up */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_LOW); ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++ /*run p2p multicast list work. */ ++ if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) ++ p2pSetMulticastListWorkQueueWrapper(prGlueInfo); ++ ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag)) { ++ p2pFuncUpdateMgmtFrameRegister(prGlueInfo->prAdapter, ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter); ++ } ++#endif ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ DBGLOG(INIT, INFO, "<1>tx_thread should stop now...\n"); ++ break; ++ } ++ ++ fgNeedHwAccess = FALSE; ++ ++ /* Handle Interrupt */ ++ if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->ulFlag)) { ++ if (fgNeedHwAccess == FALSE) { ++ fgNeedHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prGlueInfo->prAdapter); ++ } ++ ++ /* the Wi-Fi interrupt is already disabled in mmc thread, ++ so we set the flag only to enable the interrupt later */ ++ prGlueInfo->prAdapter->fgIsIntEnable = FALSE; ++ /* wlanISR(prGlueInfo->prAdapter, TRUE); */ ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ /* Should stop now... skip pending interrupt */ ++ DBGLOG(INIT, INFO, "ignore pending interrupt\n"); ++ } else { ++ prGlueInfo->TaskIsrCnt++; ++ wlanIST(prGlueInfo->prAdapter); ++ } ++ } ++ ++ /* transfer ioctl to OID request */ ++#if 0 ++ if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "<2>tx_thread should stop now...\n"); ++ break; ++ } ++#endif ++ ++ do { ++ if (test_and_clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag)) { ++ /* get current prIoReq */ ++ prGlueInfo->u4OidCompleteFlag = 0; ++ ++ prIoReq = &(prGlueInfo->OidEntry); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE && prIoReq->fgIsP2pOid == TRUE) { ++ /* if this Oid belongs to p2p and p2p module is removed ++ * do nothing, ++ */ ++ } else ++#endif ++ { ++ if (FALSE == prIoReq->fgRead) { ++ prIoReq->rStatus = wlanSetInformation(prIoReq->prAdapter, ++ prIoReq->pfnOidHandler, ++ prIoReq->pvInfoBuf, ++ prIoReq->u4InfoBufLen, ++ prIoReq->pu4QryInfoLen); ++ } else { ++ prIoReq->rStatus = wlanQueryInformation(prIoReq->prAdapter, ++ prIoReq->pfnOidHandler, ++ prIoReq->pvInfoBuf, ++ prIoReq->u4InfoBufLen, ++ prIoReq->pu4QryInfoLen); ++ } ++ ++ if (prIoReq->rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(OID, TEMP, "tx_thread, complete\n"); ++ complete(&prGlueInfo->rPendComp); ++ } else { ++ wlanoidTimeoutCheck(prGlueInfo->prAdapter, prIoReq->pfnOidHandler); ++ } ++ } ++ } ++ ++ } while (FALSE); ++ ++ /* ++ * ++ * if TX request, clear the TXREQ flag. TXREQ set by kalSetEvent/GlueSetEvent ++ * indicates the following requests occur ++ * ++ */ ++#if 0 ++ if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "<3>tx_thread should stop now...\n"); ++ break; ++ } ++#endif ++ ++ if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, &prGlueInfo->ulFlag)) { ++ /* Process Mailbox Messages */ ++ wlanProcessMboxMessage(prGlueInfo->prAdapter); ++ ++ /* Process CMD request */ ++ do { ++ if (prCmdQue->u4NumElem > 0) { ++ if (fgNeedHwAccess == FALSE) { ++ fgNeedHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prGlueInfo->prAdapter); ++ } ++ wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); ++ } ++ } while (FALSE); ++ ++ /* Handle Packet Tx */ ++ { ++ while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_REMOVE_HEAD(prTxQueue, prQueueEntry, P_QUE_ENTRY_T); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ ASSERT(prQueueEntry); ++ if (NULL == prQueueEntry) ++ break; ++ ++ prSkb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); ++ ASSERT(prSkb); ++ if (NULL == prSkb) { ++ DBGLOG(INIT, ERROR, "prSkb == NULL!\n"); ++ continue; ++ } ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(INIT, LOUD, " %d\n", u2Identifier); ++ } ++#endif ++ if (wlanEnqueueTxPacket(prGlueInfo->prAdapter, ++ (P_NATIVE_PACKET) prSkb) == WLAN_STATUS_RESOURCES) { ++ /* no available entry in rFreeMsduInfoList */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_HEAD(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ break; ++ } ++ } ++ ++ if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) { ++ /* send packets to HIF here */ ++ wlanTxPendingPackets(prGlueInfo->prAdapter, &fgNeedHwAccess); ++ } ++ } ++ ++ } ++ ++ /* Process RX, In linux, we don't need to free sk_buff by ourself */ ++ ++ /* In linux, we don't need to free sk_buff by ourself */ ++ ++ /* In linux, we don't do reset */ ++ if (fgNeedHwAccess == TRUE) ++ wlanReleasePowerControl(prGlueInfo->prAdapter); ++ ++ /* handle cnmTimer time out */ ++ if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag)) ++ wlanTimerTimeoutCheck(prGlueInfo->prAdapter); ++#if CFG_DBG_GPIO_PINS ++ /* TX thread go to sleep */ ++ if (!prGlueInfo->ulFlag) ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_HIGH); ++#endif ++ } ++ ++#if 0 ++ if (fgNeedHwAccess == TRUE) ++ wlanReleasePowerControl(prGlueInfo->prAdapter); ++#endif ++ ++ /* exit while loop, tx thread is closed so we flush all pending packets */ ++ /* flush the pending TX packets */ ++ if (prGlueInfo->i4TxPendingFrameNum > 0) ++ kalFlushPendingTxPackets(prGlueInfo); ++ ++ /* flush pending security frames */ ++ if (prGlueInfo->i4TxPendingSecurityFrameNum > 0) ++ kalClearSecurityFrames(prGlueInfo); ++ ++ /* remove pending oid */ ++ wlanReleasePendingOid(prGlueInfo->prAdapter, 0); ++ ++ /* In linux, we don't need to free sk_buff by ourself */ ++ ++ DBGLOG(INIT, INFO, "mtk_sdiod stops\n"); ++ complete(&prGlueInfo->rHaltComp); ++ ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to check if card is removed ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval TRUE: card is removed ++* FALSE: card is still attached ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return FALSE; ++ /* Linux MMC doesn't have removal notification yet */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This routine is used to send command to firmware for overriding netweork address ++ * ++ * \param pvGlueInfo Pointer of GLUE Data Structure ++ ++ * \retval TRUE ++ * FALSE ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->fgIsMacAddrOverride == FALSE) { ++#if !defined(CONFIG_X86) ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ UINT_32 i; ++#endif ++ BOOLEAN fgIsReadError = FALSE; ++ ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ for (i = 0; i < MAC_ADDR_LEN; i += 2) { ++ if (kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, ++ (PUINT_16) (((PUINT_8) prMacAddr) + i)) == FALSE) { ++ fgIsReadError = TRUE; ++ break; ++ } ++ } ++#else ++ TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prMacAddr); ++#endif ++ ++ if (fgIsReadError == TRUE) ++ return FALSE; ++ else ++ return TRUE; ++#else ++ /* x86 Linux doesn't need to override network address so far */ ++ return FALSE; ++#endif ++ } else { ++ COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); ++ ++ return TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to flush pending TX packets in glue layer ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prTxQue; ++ P_QUE_ENTRY_T prQueueEntry; ++ PVOID prPacket; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ prTxQue = &(prGlueInfo->rTxQueue); ++ ++ if (prGlueInfo->i4TxPendingFrameNum) { ++ while (TRUE) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ if (prQueueEntry == NULL) ++ break; ++ ++ prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); ++ ++ kalSendComplete(prGlueInfo, prPacket, WLAN_STATUS_NOT_ACCEPTED); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is get indicated media state ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->eParamMediaStateIndicated; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set indicated media state ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate) ++{ ++ ASSERT(prGlueInfo); ++ ++ prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear pending OID staying in command queue ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ ++ if (((P_CMD_INFO_T) prQueueEntry)->fgIsOid) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ break; ++ } ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ ++ if (prCmdInfo) { ++ if (prCmdInfo->pfCmdTimeoutHandler) ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ else ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_NOT_ACCEPTED); ++ ++ prGlueInfo->u4OidCompleteFlag = 1; ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to insert command into prCmdQueue ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* prQueueEntry Pointer of queue entry to be inserted ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry) ++{ ++ P_QUE_T prCmdQue; ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prQueueEntry); ++ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ if (prCmdInfo->prPacket && prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); ++ prMsduInfo->eCmdType = prCmdInfo->eCmdType; ++ prMsduInfo->ucCID = prCmdInfo->ucCID; ++ prMsduInfo->u4InqueTime = kalGetTimeTick(); ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Handle EVENT_ID_ASSOC_INFO event packet by indicating to OS with ++* proper information ++* ++* @param pvGlueInfo Pointer of GLUE Data Structure ++* @param prAssocInfo Pointer of EVENT_ID_ASSOC_INFO Packet ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo) ++{ ++ /* to do */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to get firmware load address from registry ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rRegInfo.u4LoadAddress; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to get firmware start address from registry ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rRegInfo.u4StartAddress; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * * @brief Notify OS with SendComplete event of the specific packet. Linux should ++ * * free packets here. ++ * * ++ * * @param pvGlueInfo Pointer of GLUE Data Structure ++ * * @param pvPacket Pointer of Packet Handle ++ * * @param status Status Code for OS upper layer ++ * * ++ * * @return none ++ * */ ++/*----------------------------------------------------------------------------*/ ++ ++/* / Todo */ ++VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus) ++{ ++ ASSERT(pvPacket); ++ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ if (prGlueInfo) ++ prGlueInfo->u8SkbFreed++; ++ GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++} ++ ++UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return (UINT_32) (prGlueInfo->i4TxPendingFrameNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to retrieve the number of pending commands ++* (including MMPDU, 802.1X and command packets) ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ ++ ASSERT(prGlueInfo); ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ return prCmdQue->u4NumElem; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Timer Initialization Procedure ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* \param[in] prTimerHandler Pointer to timer handling function, whose only ++* argument is "prAdapter" ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++/* static struct timer_list tickfn; */ ++ ++VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler) ++{ ++ ++ ASSERT(prGlueInfo); ++ ++ init_timer(&(prGlueInfo->tickfn)); ++ prGlueInfo->tickfn.function = prTimerHandler; ++ prGlueInfo->tickfn.data = (ULONG) prGlueInfo; ++} ++ ++/* Todo */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the time to do the time out check. ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* \param[in] rInterval Time out interval from current time. ++* ++* \retval TRUE Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval) ++{ ++ ASSERT(prGlueInfo); ++ del_timer_sync(&(prGlueInfo->tickfn)); ++ ++ prGlueInfo->tickfn.expires = jiffies + u4Interval * HZ / MSEC_PER_SEC; ++ add_timer(&(prGlueInfo->tickfn)); ++ ++ return TRUE; /* success */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to cancel ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* ++* \retval TRUE : Timer has been canceled ++* FALAE : Timer doens't exist ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); ++ ++ if (del_timer_sync(&(prGlueInfo->tickfn)) >= 0) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is a callback function for scanning done ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prGlueInfo); ++ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ /* report all queued beacon/probe response frames to upper layer */ ++ scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); ++ cnmTimerStopTimer(prGlueInfo->prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ ++ /* check for system configuration for generating error message on scan list */ ++ wlanCheckSystemConfiguration(prGlueInfo->prAdapter); ++ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to generate a random number ++* ++* \param none ++* ++* \retval UINT_32 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalRandomNumber(VOID) ++{ ++ UINT_32 number = 0; ++ ++ get_random_bytes(&number, 4); ++ ++ return number; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief command timeout call-back function ++ * ++ * \param[in] prGlueInfo Pointer to the GLUE data structure. ++ * ++ * \retval (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID kalTimeoutHandler(ULONG arg) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) arg; ++ ++ ASSERT(prGlueInfo); ++ ++ /* Notify tx thread for timeout event */ ++ set_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++} ++ ++VOID kalSetEvent(P_GLUE_INFO_T pr) ++{ ++ set_bit(GLUE_FLAG_TXREQ_BIT, &pr->ulFlag); ++ wake_up_interruptible(&pr->waitq); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if configuration file (NVRAM/Registry) exists ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo) ++{ ++#if !defined(CONFIG_X86) ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->fgNvramAvailable; ++#else ++ /* there is no configuration data for x86-linux */ ++ return FALSE; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Registry information ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* Pointer of REG_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return &(prGlueInfo->rRegInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve version information of corresponding configuration file ++* ++* \param[in] ++* prGlueInfo ++* ++* \param[out] ++* pu2Part1CfgOwnVersion ++* pu2Part1CfgPeerVersion ++* pu2Part2CfgOwnVersion ++* pu2Part2CfgPeerVersion ++* ++* \return ++* NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PUINT_16 pu2Part1CfgOwnVersion, ++ OUT PUINT_16 pu2Part1CfgPeerVersion, ++ OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion) ++{ ++ ASSERT(prGlueInfo); ++ ++ ASSERT(pu2Part1CfgOwnVersion); ++ ASSERT(pu2Part1CfgPeerVersion); ++ ASSERT(pu2Part2CfgOwnVersion); ++ ASSERT(pu2Part2CfgPeerVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion), pu2Part1CfgOwnVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1PeerVersion), pu2Part1CfgPeerVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion), pu2Part2CfgOwnVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2PeerVersion), pu2Part2CfgPeerVersion); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the WPS is active or not ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->fgWpsActive; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief update RSSI and LinkQuality to GLUE layer ++* ++* \param[in] ++* prGlueInfo ++* eNetTypeIdx ++* cRssi ++* cLinkQuality ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) ++{ ++ struct iw_statistics *pStats = (struct iw_statistics *)NULL; ++ ++ ASSERT(prGlueInfo); ++ ++ switch (eNetTypeIdx) { ++ case KAL_NETWORK_TYPE_AIS_INDEX: ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case KAL_NETWORK_TYPE_P2P_INDEX: ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ break; ++#endif ++#endif ++ default: ++ break; ++ ++ } ++ ++ if (pStats) { ++ pStats->qual.qual = cLinkQuality; ++ pStats->qual.noise = 0; ++ pStats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; ++ pStats->qual.level = 0x100 + cRssi; ++ pStats->qual.updated |= IW_QUAL_LEVEL_UPDATED; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Pre-allocate I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitIOBuffer(VOID) ++{ ++ UINT_32 u4Size; ++ ++ if (CFG_COALESCING_BUFFER_SIZE >= CFG_RX_COALESCING_BUFFER_SIZE) ++ u4Size = CFG_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); ++ else ++ u4Size = CFG_RX_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ pvDmaBuffer = dma_alloc_coherent(NULL, CFG_RX_MAX_PKT_SIZE, &pvDmaPhyBuf, GFP_KERNEL); ++ if (pvDmaBuffer == NULL) ++ return FALSE; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ pvIoBuffer = kmalloc(u4Size, GFP_KERNEL); ++/* pvIoBuffer = dma_alloc_coherent(NULL, u4Size, &pvIoPhyBuf, GFP_KERNEL); */ ++ if (pvIoBuffer) { ++ pvIoBufferSize = u4Size; ++ pvIoBufferUsage = 0; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free pre-allocated I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUninitIOBuffer(VOID) ++{ ++ kfree(pvIoBuffer); ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ dma_free_coherent(NULL, CFG_RX_MAX_PKT_SIZE, pvDmaBuffer, pvDmaPhyBuf); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ /* dma_free_coherent(NULL, pvIoBufferSize, pvIoBuffer, pvIoPhyBuf); */ ++ ++ pvIoBuffer = (PVOID) NULL; ++ pvIoBufferSize = 0; ++ pvIoBufferUsage = 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dispatch pre-allocated I/O buffer ++* ++* \param[in] ++* u4AllocSize ++* ++* \return ++* PVOID for pointer of pre-allocated I/O buffer ++*/ ++/*----------------------------------------------------------------------------*/ ++PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize) ++{ ++ PVOID ret = (PVOID) NULL; ++ ++ if (pvIoBuffer) { ++ if (u4AllocSize <= (pvIoBufferSize - pvIoBufferUsage)) { ++ ret = (PVOID) &(((PUINT_8) (pvIoBuffer))[pvIoBufferUsage]); ++ pvIoBufferUsage += u4AllocSize; ++ } ++ } else { ++ /* fault tolerance */ ++ ret = (PVOID) kalMemAlloc(u4AllocSize, PHY_MEM_TYPE); ++ } ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release all dispatched I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size) ++{ ++ if (pvIoBuffer) { ++ pvIoBufferUsage -= u4Size; ++ } else { ++ /* fault tolerance */ ++ kalMemFree(pvAddr, PHY_MEM_TYPE, u4Size); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, ++ pucNumOfChannel, paucChannelList); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo) ++{ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX) && ++ p2pFuncIsAPMode(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo)) ++ return TRUE; ++#endif ++ ++ return FALSE; ++} ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the physical address for Pre-allocate I/O buffer. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return physical addr ++*/ ++/*----------------------------------------------------------------------------*/ ++ULONG kalIOPhyAddrGet(IN ULONG VirtAddr) ++{ ++ ULONG PhyAddr; ++ ++ if ((VirtAddr >= (ULONG) pvIoBuffer) && (VirtAddr <= ((ULONG) (pvIoBuffer) + pvIoBufferSize))) { ++ PhyAddr = (ULONG) pvIoPhyBuf; ++ PhyAddr += (VirtAddr - (ULONG) (pvIoBuffer)); ++ return PhyAddr; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the physical address for Pre-allocate I/O buffer. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return physical addr ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr) ++{ ++ *VirtAddr = pvDmaBuffer; ++ *PhyAddr = pvDmaPhyBuf; ++} ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++#if CFG_SUPPORT_802_11W ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the MFP is active or not ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rWpaInfo.u4Mfp; ++} ++#endif ++ ++struct file *kalFileOpen(const char *path, int flags, int rights) ++{ ++ struct file *filp = NULL; ++ mm_segment_t oldfs; ++ int err = 0; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ filp = filp_open(path, flags, rights); ++ set_fs(oldfs); ++ if (IS_ERR(filp)) { ++ err = PTR_ERR(filp); ++ return NULL; ++ } ++ return filp; ++} ++ ++VOID kalFileClose(struct file *file) ++{ ++ filp_close(file, NULL); ++} ++ ++UINT_32 kalFileRead(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) ++{ ++ mm_segment_t oldfs; ++ INT_32 ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ++ ret = vfs_read(file, data, size, &offset); ++ ++ set_fs(oldfs); ++ return ret; ++} ++ ++UINT_32 kalFileWrite(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) ++{ ++ mm_segment_t oldfs; ++ INT_32 ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ++ ret = vfs_write(file, data, size, &offset); ++ ++ set_fs(oldfs); ++ return ret; ++} ++ ++UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size) ++{ ++ struct file *file = NULL; ++ UINT_32 ret = -1; ++ UINT_32 u4Flags = 0; ++ ++ if (fgDoAppend) ++ u4Flags = O_APPEND; ++ ++ file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); ++ if (file) { ++ ret = kalFileWrite(file, 0, pucData, u4Size); ++ kalFileClose(file); ++ } ++ ++ return ret; ++} ++ ++INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize) ++{ ++ struct file *file = NULL; ++ INT_32 ret = -1; ++ UINT_32 u4ReadSize = 0; ++ ++ DBGLOG(INIT, LOUD, "kalReadToFile() path %s\n", pucPath); ++ ++ file = kalFileOpen(pucPath, O_RDONLY, 0); ++ ++ if ((file != NULL) && !IS_ERR(file)) { ++ u4ReadSize = kalFileRead(file, 0, pucData, u4Size); ++ kalFileClose(file); ++ if (pu4ReadSize) ++ *pu4ReadSize = u4ReadSize; ++ ret = 0; ++ } ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate BSS-INFO to NL80211 as scanning result ++* ++* \param[in] ++* prGlueInfo ++* pucBeaconProbeResp ++* u4FrameLen ++* ++* ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucBeaconProbeResp, ++ IN UINT_32 u4FrameLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength) ++{ ++ struct wiphy *wiphy; ++ struct ieee80211_channel *prChannel = NULL; ++ ++ ASSERT(prGlueInfo); ++ wiphy = priv_to_wiphy(prGlueInfo); ++ ++ /* search through channel entries */ ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ if (prChannel != NULL && (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)) { ++ struct cfg80211_bss *bss; ++#if CFG_SUPPORT_TSF_USING_BOOTTIME ++ struct ieee80211_mgmt *prMgmtFrame = (struct ieee80211_mgmt *)pucBeaconProbeResp; ++ ++ prMgmtFrame->u.beacon.timestamp = kalGetBootTime(); ++#endif ++ ScanCnt++; ++ ++ /* indicate to NL80211 subsystem */ ++ bss = cfg80211_inform_bss_frame(wiphy, ++ prChannel, ++ (struct ieee80211_mgmt *)pucBeaconProbeResp, ++ u4FrameLen, i4SignalStrength * 100, GFP_KERNEL); ++ ++ if (!bss) { ++ ScanDoneFailCnt++; ++ DBGLOG(SCN, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", ++ ucChannelNum, i4SignalStrength); ++ } else { ++ cfg80211_put_bss(wiphy, bss); ++ DBGLOG(SCN, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", ++ ucChannelNum, i4SignalStrength); ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate channel ready ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs) ++{ ++ struct ieee80211_channel *prChannel = NULL; ++ enum nl80211_channel_type rChannelType; ++ ++ /* ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); */ ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ switch (eSco) { ++ case CHNL_EXT_SCN: ++ rChannelType = NL80211_CHAN_NO_HT; ++ break; ++ ++ case CHNL_EXT_SCA: ++ rChannelType = NL80211_CHAN_HT40MINUS; ++ break; ++ ++ case CHNL_EXT_SCB: ++ rChannelType = NL80211_CHAN_HT40PLUS; ++ break; ++ ++ case CHNL_EXT_RES: ++ default: ++ rChannelType = NL80211_CHAN_HT20; ++ break; ++ } ++ ++ cfg80211_ready_on_channel(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, u4DurationMs, ++ GFP_KERNEL); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate channel expiration ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum) ++{ ++ struct ieee80211_channel *prChannel = NULL; ++ enum nl80211_channel_type rChannelType; ++ ++ ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ switch (eSco) { ++ case CHNL_EXT_SCN: ++ rChannelType = NL80211_CHAN_NO_HT; ++ break; ++ ++ case CHNL_EXT_SCA: ++ rChannelType = NL80211_CHAN_HT40MINUS; ++ break; ++ ++ case CHNL_EXT_SCB: ++ rChannelType = NL80211_CHAN_HT40PLUS; ++ break; ++ ++ case CHNL_EXT_RES: ++ default: ++ rChannelType = NL80211_CHAN_HT20; ++ break; ++ } ++ ++ cfg80211_remain_on_channel_expired(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, ++ GFP_KERNEL); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate Mgmt tx status ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) ++{ ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { ++ DBGLOG(AIS, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", ++ prGlueInfo, pucFrameBuf, u4FrameLen); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ cfg80211_mgmt_tx_status(prGlueInfo->prDevHandler->ieee80211_ptr, ++ u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalIndicateMgmtTxStatus */ ++ ++VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) ++{ ++#define DBG_MGMT_FRAME_INDICATION 1 ++ INT_32 i4Freq = 0; ++ UINT_8 ucChnlNum = 0; ++#if DBG_MGMT_FRAME_INDICATION ++ P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; ++#endif ++ ++ do { ++ if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; ++ ++#if DBG_MGMT_FRAME_INDICATION ++ prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; ++ ++ switch (prWlanHeader->u2FrameCtrl) { ++ case MAC_FRAME_PROBE_REQ: ++ DBGLOG(AIS, TRACE, "RX Probe Req at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(AIS, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_ACTION: ++ DBGLOG(AIS, TRACE, "RX Action frame at channel %d ", ucChnlNum); ++ break; ++ default: ++ DBGLOG(AIS, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); ++ break; ++ } ++ ++#endif ++ i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; ++ ++ cfg80211_rx_mgmt(prGlueInfo->prDevHandler->ieee80211_ptr, /* struct net_device * dev, */ ++ i4Freq, ++ RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), ++ prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalIndicateRxMgmtFrame */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen) ++{ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ struct sk_buff *skb = cfg80211_testmode_alloc_event_skb(priv_to_wiphy(prGlueInfo), ++ dataLen, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(AIS, ERROR, "kalIndicateAgpsNotify: alloc skb failed\n"); ++ return FALSE; ++ } ++ ++ /* DBGLOG(CCX, INFO, ("WLAN_STATUS_AGPS_NOTIFY, cmd=%d\n", cmd)); */ ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_CMD, sizeof(cmd), &cmd) < 0)) ++ goto nla_put_failure; ++ if (dataLen > 0 && data && unlikely(nla_put(skb, MTK_ATTR_AGPS_DATA, dataLen, data) < 0)) ++ goto nla_put_failure; ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFINDEX, sizeof(UINT_32), &prGlueInfo->prDevHandler->ifindex) < 0)) ++ goto nla_put_failure; ++ /* currently, the ifname maybe wlan0, p2p0, so the maximum name length will be 5 bytes */ ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFNAME, 5, prGlueInfo->prDevHandler->name) < 0)) ++ goto nla_put_failure; ++ cfg80211_testmode_event(skb, GFP_KERNEL); ++ return TRUE; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return FALSE; ++} ++#endif ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++#define PROC_MET_PROF_CTRL "met_ctrl" ++#define PROC_MET_PROF_PORT "met_port" ++ ++struct proc_dir_entry *pMetProcDir; ++void *pMetGlobalData = NULL; ++static unsigned long __read_mostly tracing_mark_write_addr; ++ ++static inline void __mt_update_tracing_mark_write_addr(void) ++{ ++ if (unlikely(0 == tracing_mark_write_addr)) ++ tracing_mark_write_addr = kallsyms_lookup_name("tracing_mark_write"); ++} ++ ++VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb) ++{ ++ UINT_8 ucIpVersion; ++ UINT_16 u2UdpSrcPort; ++ UINT_16 u2RtpSn; ++ PUINT_8 pucEthHdr = prSkb->data; ++ PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; ++ ++ /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ ++ /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ ++ /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ ++ /* printk("MET_PROF: MET enable=%d(HardXmit)\n", prGlueInfo->u8MetProfEnable); */ ++ if (prGlueInfo->u8MetProfEnable == 1) { ++ u2UdpSrcPort = prGlueInfo->u16MetUdpPort; ++ if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { ++ /* IP */ ++ pucIpHdr = pucEthHdr + ETH_HLEN; ++ ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { ++ /* UDP */ ++ pucUdpHdr = pucIpHdr + IP_HEADER_LEN; ++ /* check UDP port number */ ++ if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { ++ /* RTP */ ++ pucRtpHdr = pucUdpHdr + 8; ++ u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; ++ /* trace_printk("S|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); ++ //frm_sequence); */ ++#ifdef CONFIG_TRACING ++ __mt_update_tracing_mark_write_addr(); ++ if (tracing_mark_write_addr != 0) { ++ event_trace_printk(tracing_mark_write_addr, "S|%d|%s|%d\n", ++ current->tgid, "WIFI-CHIP", u2RtpSn); ++ } ++#endif ++ } ++ } ++ } ++ } ++} ++ ++VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_8 ucIpVersion; ++ UINT_16 u2UdpSrcPort; ++ UINT_16 u2RtpSn; ++ struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ PUINT_8 pucEthHdr = prSkb->data; ++ PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ ++ /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ ++ /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ ++ /* printk("MET_PROF: MET enable=%d(TxMsdu)\n", prGlueInfo->u8MetProfEnable); */ ++ if (prGlueInfo->u8MetProfEnable == 1) { ++ u2UdpSrcPort = prGlueInfo->u16MetUdpPort; ++ if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { ++ /* IP */ ++ pucIpHdr = pucEthHdr + ETH_HLEN; ++ ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { ++ /* UDP */ ++ pucUdpHdr = pucIpHdr + IP_HEADER_LEN; ++ /* check UDP port number */ ++ if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { ++ /* RTP */ ++ pucRtpHdr = pucUdpHdr + 8; ++ u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; ++ /* trace_printk("F|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); ++ //frm_sequence); */ ++#ifdef CONFIG_TRACING ++ __mt_update_tracing_mark_write_addr(); ++ if (tracing_mark_write_addr != 0) { ++ event_trace_printk(tracing_mark_write_addr, "F|%d|%s|%d\n", ++ current->tgid, "WIFI-CHIP", u2RtpSn); ++ } ++#endif ++ } ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t kalMetCtrlWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) ++{ ++ char acBuf[128 + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ int u8MetProfEnable; ++ ++ IN P_GLUE_INFO_T prGlueInfo; ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, u4CopySize)) ++ return -1; ++ acBuf[u4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, " %d", &u8MetProfEnable) == 1) ++ DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC Enable=%d\n", u8MetProfEnable); ++ if (pMetGlobalData != NULL) { ++ prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; ++ prGlueInfo->u8MetProfEnable = (UINT_8) u8MetProfEnable; ++ } ++ return count; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t kalMetPortWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) ++{ ++ char acBuf[128 + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ int u16MetUdpPort; ++ ++ IN P_GLUE_INFO_T prGlueInfo; ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, u4CopySize)) ++ return -1; ++ acBuf[u4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, " %d", &u16MetUdpPort) == 1) ++ DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC UDP_PORT=%d\n", u16MetUdpPort); ++ if (pMetGlobalData != NULL) { ++ prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; ++ prGlueInfo->u16MetUdpPort = (UINT_16) u16MetUdpPort; ++ } ++ return count; ++} ++ ++const struct file_operations rMetProcCtrlFops = { ++.write = kalMetCtrlWriteProcfs ++}; ++ ++const struct file_operations rMetProcPortFops = { ++.write = kalMetPortWriteProcfs ++}; ++ ++int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ /* struct proc_dir_entry *pMetProcDir; */ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ DBGLOG(INIT, INFO, "init proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ /* ++ * Directory: Root (/proc/net/wlan0) ++ */ ++ pMetProcDir = proc_mkdir("wlan0", init_net.proc_net); ++ if (pMetProcDir == NULL) ++ return -ENOENT; ++ /* ++ /proc/net/wlan0 ++ |-- met_ctrl (PROC_MET_PROF_CTRL) ++ |-- met_port (PROC_MET_PROF_PORT) ++ */ ++ /* proc_create(PROC_MET_PROF_CTRL, 0x0644, pMetProcDir, &rMetProcFops); */ ++ proc_create(PROC_MET_PROF_CTRL, 0, pMetProcDir, &rMetProcCtrlFops); ++ proc_create(PROC_MET_PROF_PORT, 0, pMetProcDir, &rMetProcPortFops); ++ ++ pMetGlobalData = (void *)prGlueInfo; ++ ++ return 0; ++} ++ ++int kalMetRemoveProcfs(void) ++{ ++ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ DBGLOG(INIT, WARN, "remove proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ remove_proc_entry(PROC_MET_PROF_CTRL, pMetProcDir); ++ remove_proc_entry(PROC_MET_PROF_PORT, pMetProcDir); ++ /* remove root directory (proc/net/wlan0) */ ++ remove_proc_entry("wlan0", init_net.proc_net); ++ /* clear MetGlobalData */ ++ pMetGlobalData = NULL; ++ ++ return 0; ++} ++#endif ++UINT_64 kalGetBootTime(void) ++{ ++ struct timespec ts; ++ UINT_64 bootTime = 0; ++ ++ get_monotonic_boottime(&ts); ++ /* we assign ts.tv_sec to bootTime first, then multiply USEC_PER_SEC ++ this will prevent multiply result turn to a negative value on 32bit system */ ++ bootTime = ts.tv_sec; ++ bootTime *= USEC_PER_SEC; ++ bootTime += ts.tv_nsec / NSEC_PER_USEC; ++ return bootTime; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan results are avilable ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ cfg80211_sched_scan_results(priv_to_wiphy(prGlueInfo),0); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan has been stopped ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* 1. reset first for newly incoming request */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prSchedScanRequest != NULL) ++ prGlueInfo->prSchedScanRequest = NULL; ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ DBGLOG(SCN, INFO, "cfg80211_sched_scan_stopped send event\n"); ++ ++ /* 2. indication to cfg80211 */ ++ /* 20150205 change cfg80211_sched_scan_stopped to work queue to use K thread to send event instead of Tx thread ++ due to sched_scan_mtx dead lock issue by Tx thread serves oid cmds and send event in the same time */ ++ DBGLOG(SCN, TRACE, "start work queue to send event\n"); ++ schedule_delayed_work(&sched_workq, 0); ++ DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); ++ ++} ++ ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++/* if SPM is not implement this function, we will use this default one */ ++wake_reason_t __weak slp_get_wake_reason(VOID) ++{ ++ return WR_NONE; ++} ++/* if SPM is not implement this function, we will use this default one */ ++UINT_32 __weak spm_get_last_wakeup_src(VOID) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To check if device if wake up by wlan ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE: wake up by wlan; otherwise, FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter) ++{ ++ /* SUSPEND_FLAG_FOR_WAKEUP_REASON is set means system has suspended, but may be failed ++ duo to some driver suspend failed. so we need help of function slp_get_wake_reason */ ++ if (test_and_clear_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prAdapter->ulSuspendFlag) == 0) ++ return FALSE; ++ /* if slp_get_wake_reason or spm_get_last_wakeup_src is NULL, it means SPM module didn't implement ++ it. then we should return FALSE always. otherwise, if slp_get_wake_reason returns WR_WAKE_SRC, ++ then it means the host is suspend successfully. */ ++ if (slp_get_wake_reason() != WR_WAKE_SRC) ++ return FALSE; ++ /* spm_get_last_wakeup_src will returns the last wakeup source, ++ WAKE_SRC_CONN2AP is connsys */ ++ return !!(spm_get_last_wakeup_src() & WAKE_SRC_CONN2AP); ++} ++#endif ++ ++INT_32 kalHaltLock(UINT_32 waitMs) ++{ ++ INT_32 i4Ret = 0; ++ ++ if (waitMs) { ++ i4Ret = down_timeout(&rHaltCtrl.lock, MSEC_TO_JIFFIES(waitMs)); ++ if (!i4Ret) ++ goto success; ++ if (i4Ret != -ETIME) ++ return i4Ret; ++ if (rHaltCtrl.fgHeldByKalIoctl) { ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ wlanExportGlueInfo(&prGlueInfo); ++ ++ DBGLOG(INIT, ERROR, ++ "kalIoctl was executed longer than %u ms, show backtrace of tx_thread!\n", ++ kalGetTimeTick() - rHaltCtrl.u4HoldStart); ++ if (prGlueInfo) ++ show_stack(prGlueInfo->main_thread, NULL); ++ } else { ++ DBGLOG(INIT, ERROR, "halt lock held by %s pid %d longer than %u ms!\n", ++ rHaltCtrl.owner->comm, rHaltCtrl.owner->pid, ++ kalGetTimeTick() - rHaltCtrl.u4HoldStart); ++ show_stack(rHaltCtrl.owner, NULL); ++ } ++ return i4Ret; ++ } ++ down(&rHaltCtrl.lock); ++success: ++ rHaltCtrl.owner = current; ++ rHaltCtrl.u4HoldStart = kalGetTimeTick(); ++ return 0; ++} ++ ++INT_32 kalHaltTryLock(VOID) ++{ ++ INT_32 i4Ret = 0; ++ ++ i4Ret = down_trylock(&rHaltCtrl.lock); ++ if (i4Ret) ++ return i4Ret; ++ rHaltCtrl.owner = current; ++ rHaltCtrl.u4HoldStart = kalGetTimeTick(); ++ return 0; ++} ++ ++VOID kalHaltUnlock(VOID) ++{ ++ if (kalGetTimeTick() - rHaltCtrl.u4HoldStart > WLAN_OID_TIMEOUT_THRESHOLD * 2 && ++ rHaltCtrl.owner) ++ DBGLOG(INIT, ERROR, "process %s pid %d hold halt lock longer than 4s!\n", ++ rHaltCtrl.owner->comm, rHaltCtrl.owner->pid); ++ rHaltCtrl.owner = NULL; ++ up(&rHaltCtrl.lock); ++} ++ ++VOID kalSetHalted(BOOLEAN fgHalt) ++{ ++ rHaltCtrl.fgHalt = fgHalt; ++} ++ ++BOOLEAN kalIsHalted(VOID) ++{ ++ return rHaltCtrl.fgHalt; ++} ++VOID kalPerMonDump(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, WARN, "ulPerfMonFlag:0x%lx\n", prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "ulLastTxBytes:%ld\n", prPerMonitor->ulLastTxBytes); ++ DBGLOG(SW4, WARN, "ulLastRxBytes:%ld\n", prPerMonitor->ulLastRxBytes); ++ DBGLOG(SW4, WARN, "ulP2PLastTxBytes:%ld\n", prPerMonitor->ulP2PLastTxBytes); ++ DBGLOG(SW4, WARN, "ulP2PLastRxBytes:%ld\n", prPerMonitor->ulP2PLastRxBytes); ++ DBGLOG(SW4, WARN, "ulThroughput:%ld\n", prPerMonitor->ulThroughput); ++ DBGLOG(SW4, WARN, "u4UpdatePeriod:%d\n", prPerMonitor->u4UpdatePeriod); ++ DBGLOG(SW4, WARN, "u4TarPerfLevel:%d\n", prPerMonitor->u4TarPerfLevel); ++ DBGLOG(SW4, WARN, "u4CurrPerfLevel:%d\n", prPerMonitor->u4CurrPerfLevel); ++ DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.tx_bytes); ++ DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.rx_bytes); ++ DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes); ++ DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes); ++} ++ ++inline INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) ++ DBGLOG(SW4, WARN, "abnormal, perf monitory already running\n"); ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ prPerMonitor->u4UpdatePeriod = 1000; ++ cnmTimerInitTimer(prGlueInfo->prAdapter, ++ &prPerMonitor->rPerfMonTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) kalPerMonHandler, (ULONG) NULL); ++ DBGLOG(SW4, INFO, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "need to stop before disable\n"); ++ kalPerMonStop(prGlueInfo); ++ } ++ KAL_SET_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) ++ return 0; ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitor already running\n"); ++ return 0; ++ } ++ cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); ++ KAL_SET_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_CLR_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, INFO, "perf monitor started\n"); ++ return 0; ++} ++ ++inline INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter %s\n", __func__); ++ ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitory disabled\n"); ++ return 0; ++ } ++ ++ if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitory already stopped\n"); ++ return 0; ++ } ++ ++ KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ cnmTimerStopTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer); ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ prPerMonitor->ulLastRxBytes = 0; ++ prPerMonitor->ulLastTxBytes = 0; ++ prPerMonitor->ulP2PLastRxBytes = 0; ++ prPerMonitor->ulP2PLastTxBytes = 0; ++ prPerMonitor->ulThroughput = 0; ++ prPerMonitor->u4CurrPerfLevel = 0; ++ prPerMonitor->u4TarPerfLevel = 0; ++ /*Cancel CPU performance mode request*/ ++ kalBoostCpu(0); ++ } ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ kalPerMonDisable(prGlueInfo); ++ return 0; ++} ++ ++VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ /*Calculate current throughput*/ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ LONG latestTxBytes, latestRxBytes, txDiffBytes, rxDiffBytes; ++ LONG p2pLatestTxBytes, p2pLatestRxBytes, p2pTxDiffBytes, p2pRxDiffBytes; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ if ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) || (!prAdapter->fgIsP2PRegistered)) ++ return; ++ ++ prPerMonitor = &prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter kalPerMonHandler\n"); ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "perf monitory disabled, omit timeout event\n"); ++ return; ++ } ++ ++ if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "perf monitory stopped, omit timeout event\n"); ++ return; ++ } ++ latestTxBytes = prGlueInfo->rNetDevStats.tx_bytes; ++ latestRxBytes = prGlueInfo->rNetDevStats.rx_bytes; ++ p2pLatestTxBytes = prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes; ++ p2pLatestRxBytes = prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes; ++ if (0 == prPerMonitor->ulLastRxBytes && ++ 0 == prPerMonitor->ulLastTxBytes && ++ 0 == prPerMonitor->ulP2PLastRxBytes && ++ 0 == prPerMonitor->ulP2PLastTxBytes) { ++ prPerMonitor->ulThroughput = 0; ++ } else { ++ txDiffBytes = latestTxBytes - prPerMonitor->ulLastTxBytes; ++ rxDiffBytes = latestRxBytes - prPerMonitor->ulLastRxBytes; ++ if (0 > txDiffBytes) ++ txDiffBytes = -(txDiffBytes); ++ if (0 > rxDiffBytes) ++ rxDiffBytes = -(rxDiffBytes); ++ ++ p2pTxDiffBytes = p2pLatestTxBytes - prPerMonitor->ulP2PLastTxBytes; ++ p2pRxDiffBytes = p2pLatestRxBytes - prPerMonitor->ulP2PLastRxBytes; ++ if (0 > p2pTxDiffBytes) ++ p2pTxDiffBytes = -(p2pTxDiffBytes); ++ if (0 > p2pRxDiffBytes) ++ p2pRxDiffBytes = -(p2pRxDiffBytes); ++ ++ prPerMonitor->ulThroughput = txDiffBytes + rxDiffBytes + p2pTxDiffBytes + p2pRxDiffBytes; ++ prPerMonitor->ulThroughput *= 1000; ++ prPerMonitor->ulThroughput /= prPerMonitor->u4UpdatePeriod; ++ prPerMonitor->ulThroughput <<= 3; ++ } ++ /*start the timer again to make sure we can cancel performance mode request in the end*/ ++ cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); ++ ++ prPerMonitor->ulLastTxBytes = latestTxBytes; ++ prPerMonitor->ulLastRxBytes = latestRxBytes; ++ prPerMonitor->ulP2PLastTxBytes = p2pLatestTxBytes; ++ prPerMonitor->ulP2PLastRxBytes = p2pLatestRxBytes; ++ ++ if (prPerMonitor->ulThroughput < THROUGHPUT_L1_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 0; ++ else if (prPerMonitor->ulThroughput < THROUGHPUT_L2_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 1; ++ else if (prPerMonitor->ulThroughput < THROUGHPUT_L3_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 2; ++ else ++ prPerMonitor->u4TarPerfLevel = 3; ++ if (prPerMonitor->u4TarPerfLevel != prPerMonitor->u4CurrPerfLevel) { ++ if (0 == prPerMonitor->u4TarPerfLevel) { ++ /*cancel CPU performance mode request*/ ++ kalPerMonStop(prGlueInfo); ++ } else{ ++ DBGLOG(SW4, TRACE, "throughput:%ld bps\n", prPerMonitor->ulThroughput); ++ /*adjust CPU core number to prPerMonitor->u4TarPerfLevel+1*/ ++ kalBoostCpu(prPerMonitor->u4TarPerfLevel+1); ++ /*start the timer again to make sure we can cancel performance mode request in the end*/ ++ cnmTimerStartTimer(prGlueInfo->prAdapter, ++ &prPerMonitor->rPerfMonTimer, ++ prPerMonitor->u4UpdatePeriod); ++ } ++ } ++ prPerMonitor->u4CurrPerfLevel = prPerMonitor->u4TarPerfLevel; ++ DBGLOG(SW4, TRACE, "exit kalPerMonHandler\n"); ++} ++ ++INT32 __weak kalBoostCpu(UINT_32 core_num) ++{ ++ DBGLOG(SW4, WARN, "enter weak kalBoostCpu, core_num:%d\n", core_num); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c +new file mode 100644 +index 000000000000..2d9631538942 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c +@@ -0,0 +1,4671 @@ ++/* ++** Id: @(#) gl_p2p.c@@ ++*/ ++ ++/*! \file gl_p2p.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_p2p.c ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 17 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** FPB from ALPS.JB to phase 2 release. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 01 09 2012 terry.wu ++ * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork ++ * cfg80211 integration for p2p network. ++ * ++ * 12 19 2011 terry.wu ++ * [WCXRP00001142] [Wi-Fi] [P2P Driver] XOR local admin bit to generate p2p net device MAC ++ * XOR local administrated bit to generate net device MAC of p2p network. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Fix possible KE when unload p2p. ++ * ++ * 11 24 2011 yuche.tsai ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 16 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Avoid using work thread in set p2p multicast address callback. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix default device name issue. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 11 07 2011 yuche.tsai ++ * NULL ++ * [ALPS 00087243] KE in worker thread. ++ * The multicast address list is scheduled in worker thread. ++ * Before the worker thread is excuted, if P2P is unloaded, a KE may occur. ++ * ++ * 10 26 2011 terry.wu ++ * [WCXRP00001066] [MT6620 Wi-Fi] [P2P Driver] Fix P2P Oid Issue ++ * Fix some P2P OID functions didn't raise its flag "fgIsP2pOid" issue. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * . ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 26 2011 yuche.tsai ++ * NULL ++ * Fix bug of parsing secondary device list type issue. ++ * ++ * 08 24 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Abort. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue of P2P. ++ * ++ * 08 22 2011 chinglan.wang ++ * NULL ++ * Fix invitation indication bug.. ++ * ++ * 08 16 2011 cp.wu ++ * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence ++ * auto channel decision for 2.4GHz hot spot mode ++ * ++ * 08 16 2011 chinglan.wang ++ * NULL ++ * Add the group id information in the invitation indication. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 08 05 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Add Password ID check for quick connection. ++ * Also modify some connection policy. ++ * ++ * 07 18 2011 chinglan.wang ++ * NULL ++ * Add IOC_P2P_GO_WSC_IE (p2p capability). ++ * ++ * 06 14 2011 yuche.tsai ++ * NULL ++ * Add compile flag to disable persistent group support. ++ * ++ * 05 04 2011 chinglan.wang ++ * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver ++ * . ++ * ++ * 05 02 2011 yuche.tsai ++ * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. ++ * Clear formation flag after formation timeout. ++ * ++ * 04 22 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * . ++ * ++ * 04 21 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * 1. Revise P2P power mode setting. ++ * 2. Revise fast-PS for concurrent ++ * ++ * 04 19 2011 wh.su ++ * NULL ++ * Adding length check before doing WPA RSN IE parsing for scan results indicate. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Connection flow refine for Sigma test. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 07 2011 terry.wu ++ * [WCXRP00000619] [MT6620 Wi-Fi][Driver] fix kernel panic may occur when removing wlan ++ * Fix kernel panic may occur when removing wlan driver. ++ * ++ * 03 31 2011 wh.su ++ * [WCXRP00000614] [MT6620 Wi-Fi][Driver] P2P: Update beacon content while setting WSC IE ++ * Update the wsc ie to beacon content. ++ * ++ * 03 25 2011 wh.su ++ * NULL ++ * add the sample code for set power mode and get power mode. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 22 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Modify formation policy. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Modify formation policy setting. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 15 2011 wh.su ++ * [WCXRP00000563] [MT6620 Wi-Fi] [P2P] Set local config method while set password Id ready ++ * set lccal config method method while set password Id ready. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 15 2011 jeffrey.chang ++ * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM ++ * refine queue_select function ++ * ++ * 03 13 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * add code for avoid compiling warning. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 10 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Remove unnecessary assert and message. ++ * ++ * 03 08 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * support the power save related p2p setting. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify P2P's netdevice functions to support multiple H/W queues ++ * ++ * 03 03 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * for get request, the buffer length to be copied is header + payload. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * add a missed break. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 02 25 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * add the Operation channel setting. ++ * ++ * 02 23 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * fixed the set int ioctl set index and value map to driver issue. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int from supplicant, and can used to set the p2p parameters ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the ioctl setting that index not map to spec defined config method. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * modify the structure pointer for set WSC IE. ++ * ++ * 02 16 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * fixed the probe request send out without WSC IE issue (at P2P). ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * fix typo ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 01 25 2011 terry.wu ++ * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter ++ * Add a new module parameter to indicate current runnig mode, P2P or AP. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. ++ * 2. Call cnmP2pIsPermit() before active P2P network. ++ * 3. Add channel selection support for AP mode. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx ++ * lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 10 2010 george.huang ++ * NULL ++ * update iwpriv LP related ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at win XP. ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add netdev_ops(NDO) for linux kernel 2.6.31 or greater ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 20 2010 cp.wu ++ * NULL ++ * correct typo. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Invert Connection request provision status parameter. ++ * ++ * 08 19 2010 cp.wu ++ * NULL ++ * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. ++ * ++ * 08 18 2010 cp.wu ++ * NULL ++ * modify pwp ioctls attribution by removing FIXED_SIZE. ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * correct p2p net device registration with NULL pointer access issue. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add wext handlers to link P2P set PS profile/ network address function (TBD) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * follow-up with ioctl interface update for Wi-Fi Direct application ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * add basic support for ioctl of getting scan result. (only address and SSID are reporterd though) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * p2p interface revised to be sync. with HAL ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement private io controls for Wi-Fi Direct ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement wireless extension ioctls in iw_handler form. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "gl_p2p_os.h" ++#include "gl_p2p_ioctl.h" ++#include "gl_vendor.h" ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define ARGV_MAX_NUM (4) ++ ++/*For CFG80211 - wiphy parameters*/ ++#define MAX_SCAN_LIST_NUM (1) ++#define MAX_SCAN_IE_LEN (512) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++static struct cfg80211_ops mtk_p2p_ops = { ++ .change_virtual_intf = mtk_p2p_cfg80211_change_iface, /* 1st */ ++ .change_bss = mtk_p2p_cfg80211_change_bss, ++ .scan = mtk_p2p_cfg80211_scan, ++ .remain_on_channel = mtk_p2p_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = mtk_p2p_cfg80211_mgmt_tx, ++ .connect = mtk_p2p_cfg80211_connect, ++ .disconnect = mtk_p2p_cfg80211_disconnect, ++ .deauth = mtk_p2p_cfg80211_deauth, ++ .disassoc = mtk_p2p_cfg80211_disassoc, ++ .start_ap = mtk_p2p_cfg80211_start_ap, ++ .change_beacon = mtk_p2p_cfg80211_change_beacon, ++ .stop_ap = mtk_p2p_cfg80211_stop_ap, ++ .set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params, ++ .del_station = mtk_p2p_cfg80211_del_station, ++ .set_monitor_channel = mtk_p2p_cfg80211_set_channel, ++ .set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask, ++ .mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register, ++ .get_station = mtk_p2p_cfg80211_get_station, ++ .add_key = mtk_p2p_cfg80211_add_key, ++ .get_key = mtk_p2p_cfg80211_get_key, ++ .del_key = mtk_p2p_cfg80211_del_key, ++ .set_default_key = mtk_p2p_cfg80211_set_default_key, ++ .join_ibss = mtk_p2p_cfg80211_join_ibss, ++ .leave_ibss = mtk_p2p_cfg80211_leave_ibss, ++ .set_tx_power = mtk_p2p_cfg80211_set_txpower, ++ .get_tx_power = mtk_p2p_cfg80211_get_txpower, ++ .set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt, ++#ifdef CONFIG_NL80211_TESTMODE ++ .testmode_cmd = mtk_p2p_cfg80211_testmode_cmd, ++#endif ++}; ++ ++static const struct wiphy_vendor_command mtk_p2p_vendor_ops[] = { ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_channel_list ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_country_code ++ }, ++}; ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++ mtk_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++#endif ++ ++/* the legacy wireless extension stuff */ ++static const iw_handler rP2PIwStandardHandler[] = { ++ [SIOCGIWPRIV - SIOCIWFIRST] = mtk_p2p_wext_get_priv, ++ [SIOCGIWSCAN - SIOCIWFIRST] = mtk_p2p_wext_discovery_results, ++ [SIOCSIWESSID - SIOCIWFIRST] = mtk_p2p_wext_reconnect, ++ [SIOCSIWAUTH - SIOCIWFIRST] = mtk_p2p_wext_set_auth, ++ [SIOCSIWENCODEEXT - SIOCIWFIRST] = mtk_p2p_wext_set_key, ++ [SIOCSIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_set_powermode, ++ [SIOCGIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_get_powermode, ++ [SIOCSIWTXPOW - SIOCIWFIRST] = mtk_p2p_wext_set_txpow, ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ [SIOCGIWSTATS - SIOCIWFIRST] = mtk_p2p_wext_get_rssi, ++#endif ++ [SIOCSIWMLME - SIOCIWFIRST] = mtk_p2p_wext_mlme_handler, ++}; ++ ++static const iw_handler rP2PIwPrivHandler[] = { ++ [IOC_P2P_CFG_DEVICE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_local_dev_info, ++ [IOC_P2P_PROVISION_COMPLETE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_provision_complete, ++ [IOC_P2P_START_STOP_DISCOVERY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_start_stop_discovery, ++ [IOC_P2P_DISCOVERY_RESULTS - SIOCIWFIRSTPRIV] = mtk_p2p_wext_discovery_results, ++ [IOC_P2P_WSC_BEACON_PROBE_RSP_IE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_wsc_ie, ++ [IOC_P2P_CONNECT_DISCONNECT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_connect_disconnect, ++ [IOC_P2P_PASSWORD_READY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_password_ready, ++/* [IOC_P2P_SET_PWR_MGMT_PARAM - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_pm_param, */ ++ [IOC_P2P_SET_INT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_int, ++ [IOC_P2P_GET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_get_struct, ++ [IOC_P2P_SET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_struct, ++ [IOC_P2P_GET_REQ_DEVICE_INFO - SIOCIWFIRSTPRIV] = mtk_p2p_wext_request_dev_info, ++}; ++ ++static const struct iw_priv_args rP2PIwPrivTable[] = { ++ { ++ .cmd = IOC_P2P_CFG_DEVICE, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CFG_DEVICE_TYPE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_CFG_DEVICE"} ++ , ++ { ++ .cmd = IOC_P2P_START_STOP_DISCOVERY, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_REQ_DEVICE_TYPE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_DISCOVERY"} ++ , ++ { ++ .cmd = IOC_P2P_DISCOVERY_RESULTS, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_RESULT"} ++ , ++ { ++ .cmd = IOC_P2P_WSC_BEACON_PROBE_RSP_IE, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_HOSTAPD_PARAM), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_WSC_IE"} ++ , ++ { ++ .cmd = IOC_P2P_CONNECT_DISCONNECT, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CONNECT_DEVICE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_CONNECT"} ++ , ++ { ++ .cmd = IOC_P2P_PASSWORD_READY, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_PASSWORD_READY), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_PASSWD_RDY"} ++ , ++ { ++ .cmd = IOC_P2P_GET_STRUCT, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = 256, ++ .name = "P2P_GET_STRUCT"} ++ , ++ { ++ .cmd = IOC_P2P_SET_STRUCT, ++ .set_args = 256, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_SET_STRUCT"} ++ , ++ { ++ .cmd = IOC_P2P_GET_REQ_DEVICE_INFO, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_DEVICE_REQ), ++ .name = "P2P_GET_REQDEV"} ++ , ++ { ++ /* SET STRUCT sub-ioctls commands */ ++ .cmd = PRIV_CMD_OID, ++ .set_args = 256, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "set_oid"} ++ , ++ { ++ /* GET STRUCT sub-ioctls commands */ ++ .cmd = PRIV_CMD_OID, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = 256, ++ .name = "get_oid"} ++}; ++ ++const struct iw_handler_def mtk_p2p_wext_handler_def = { ++ .num_standard = (__u16) sizeof(rP2PIwStandardHandler) / sizeof(iw_handler), ++ .num_private = (__u16) sizeof(rP2PIwPrivHandler) / sizeof(iw_handler), ++ .num_private_args = (__u16) sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args), ++ .standard = rP2PIwStandardHandler, ++ .private = rP2PIwPrivHandler, ++ .private_args = rP2PIwPrivTable, ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ .get_wireless_stats = mtk_p2p_wext_get_wireless_stats, ++#else ++ .get_wireless_stats = NULL, ++#endif ++}; ++ ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support p2p_wowlan_support = { ++ .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* for IE Searching */ ++extern BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++extern BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++/* Net Device Hooks */ ++static int p2pOpen(IN struct net_device *prDev); ++ ++static int p2pStop(IN struct net_device *prDev); ++ ++static struct net_device_stats *p2pGetStats(IN struct net_device *prDev); ++ ++static void p2pSetMulticastList(IN struct net_device *prDev); ++ ++static int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev); ++ ++static int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd); ++ ++static int p2pSetMACAddress(IN struct net_device *prDev, void *addr); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Override the implementation of select queue ++* ++* \param[in] dev Pointer to struct net_device ++* \param[in] skb Pointer to struct skb_buff ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++unsigned int _p2p_cfg80211_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp = 0; ++ ++ /* skb->priority values from 256->263 are magic values ++ * directly indicate a specific 802.1d priority. This is ++ * to allow 802.1d priority to be passed directly in from ++ * tags ++ */ ++ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ } ++ return dscp >> 5; ++} ++ ++static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++ ++static UINT_16 p2pSelectQueue(struct net_device *dev, struct sk_buff *skb, ++ void *accel_priv, select_queue_fallback_t fallback) ++{ ++ skb->priority = _p2p_cfg80211_classify8021d(skb); ++ ++ return au16Wlan1dToQueueIdx[skb->priority]; ++} ++ ++static struct net_device *g_P2pPrDev; ++static struct wireless_dev *gprP2pWdev; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->init ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanInit succeeds. ++* \retval -ENXIO No such device. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int p2pInit(struct net_device *prDev) ++{ ++/* P_GLUE_INFO_T prGlueInfo; */ ++ if (!prDev) ++ return -ENXIO; ++ ++ DBGLOG(P2P, INFO, "dev name=%s\n", prDev->name); ++ return 0; /* success */ ++} /* end of p2pInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->uninit ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void p2pUninit(IN struct net_device *prDev) ++{ ++ ++} /* end of p2pUninit() */ ++ ++static const struct net_device_ops p2p_netdev_ops = { ++ .ndo_open = p2pOpen, ++ .ndo_stop = p2pStop, ++ .ndo_set_mac_address = p2pSetMACAddress, ++ .ndo_set_rx_mode = p2pSetMulticastList, ++ .ndo_get_stats = p2pGetStats, ++ .ndo_do_ioctl = p2pDoIOCTL, ++ .ndo_start_xmit = p2pHardStartXmit, ++ .ndo_select_queue = p2pSelectQueue, ++ .ndo_init = p2pInit, ++ .ndo_uninit = p2pUninit, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS ++* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_WIFI_VAR_T prWifiVar = NULL; ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ prWifiVar = &(prAdapter->rWifiVar); ++ ++ if (!prWifiVar) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ do { ++ if (prGlueInfo->prP2PInfo == NULL) { ++ /*alloc memory for p2p info */ ++ prGlueInfo->prP2PInfo = kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); ++ prAdapter->prP2pInfo = kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); ++ prWifiVar->prP2PConnSettings = kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T), VIR_MEM_TYPE); ++ prWifiVar->prP2pFsmInfo = kalMemAlloc(sizeof(P2P_FSM_INFO_T), VIR_MEM_TYPE); ++ prWifiVar->prP2pSpecificBssInfo = kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T), VIR_MEM_TYPE); ++ } else { ++ ASSERT(prAdapter->prP2pInfo != NULL); ++ ASSERT(prWifiVar->prP2PConnSettings != NULL); ++ ASSERT(prWifiVar->prP2pFsmInfo != NULL); ++ ASSERT(prWifiVar->prP2pSpecificBssInfo != NULL); ++ } ++ /*MUST set memory to 0 */ ++ if (prGlueInfo->prP2PInfo) ++ kalMemZero(prGlueInfo->prP2PInfo, sizeof(GL_P2P_INFO_T)); ++ if (prAdapter->prP2pInfo) ++ kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); ++ if (prWifiVar->prP2PConnSettings) ++ kalMemZero(prWifiVar->prP2PConnSettings, sizeof(P2P_CONNECTION_SETTINGS_T)); ++ if (prWifiVar->prP2pFsmInfo) ++ kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); ++ if (prWifiVar->prP2pSpecificBssInfo) ++ kalMemZero(prWifiVar->prP2pSpecificBssInfo, sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ } while (FALSE); ++ ++ /* chk if alloc successful or not */ ++ if (prGlueInfo->prP2PInfo && ++ prAdapter->prP2pInfo && ++ prWifiVar->prP2PConnSettings && prWifiVar->prP2pFsmInfo && prWifiVar->prP2pSpecificBssInfo) { ++ return TRUE; ++ } ++ ++ if (prWifiVar->prP2pSpecificBssInfo) { ++ kalMemFree(prWifiVar->prP2pSpecificBssInfo, VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ prWifiVar->prP2pSpecificBssInfo = NULL; ++ } ++ if (prWifiVar->prP2pFsmInfo) { ++ kalMemFree(prWifiVar->prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); ++ ++ prWifiVar->prP2pFsmInfo = NULL; ++ } ++ if (prWifiVar->prP2PConnSettings) { ++ kalMemFree(prWifiVar->prP2PConnSettings, VIR_MEM_TYPE, sizeof(P2P_CONNECTION_SETTINGS_T)); ++ ++ prWifiVar->prP2PConnSettings = NULL; ++ } ++ if (prGlueInfo->prP2PInfo) { ++ kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); ++ ++ prGlueInfo->prP2PInfo = NULL; ++ } ++ if (prAdapter->prP2pInfo) { ++ kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); ++ ++ prAdapter->prP2pInfo = NULL; ++ } ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS ++* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ /* free memory after p2p module is ALREADY unregistered */ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { ++ ++ kalMemFree(prGlueInfo->prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); ++ kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings, VIR_MEM_TYPE, ++ sizeof(P2P_CONNECTION_SETTINGS_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo, VIR_MEM_TYPE, ++ sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ /*Reomve p2p bss scan list */ ++ scanRemoveAllP2pBssDesc(prGlueInfo->prAdapter); ++ ++ /*reset all pointer to NULL */ ++ prGlueInfo->prP2PInfo = NULL; ++ prGlueInfo->prAdapter->prP2pInfo = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo = NULL; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++ ++} ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) ++{ ++ BOOLEAN fgDoRegister = FALSE; ++/* BOOLEAN fgRollbackRtnlLock = FALSE; */ ++ BOOLEAN ret; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_UNREGISTERED) { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERING; ++ fgDoRegister = TRUE; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (!fgDoRegister) ++ return TRUE; ++ ++ /* net device initialize */ ++ netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ /* register for net device */ ++ if (register_netdev(prGlueInfo->prP2PInfo->prDevHandler) < 0) { ++ DBGLOG(P2P, WARN, "unable to register netdevice for p2p\n"); ++ ++ free_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ ret = FALSE; ++ } else { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED; ++ ret = TRUE; ++ } ++ return ret; ++} ++ ++BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) ++{ ++ BOOLEAN fgDoUnregister = FALSE; ++/* BOOLEAN fgRollbackRtnlLock = FALSE; */ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED) { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERING; ++ fgDoUnregister = TRUE; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (!fgDoUnregister) ++ return TRUE; ++ ++ /* prepare for removal */ ++ if (netif_carrier_ok(prGlueInfo->prP2PInfo->prDevHandler)) ++ netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ DBGLOG(P2P, INFO, "P2P unregister_netdev 0x%p\n", prGlueInfo->prP2PInfo->prDevHandler); ++ unregister_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; ++ ++ return TRUE; ++} ++#endif ++ ++BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo) ++{ ++ struct wiphy *prWiphy = NULL; ++ struct wireless_dev *prWdev = NULL; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ struct net_device *prNetDev = NULL; ++#endif ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); ++ if (!prWdev) { ++ DBGLOG(P2P, ERROR, "allocate p2p wireless device fail, no memory\n"); ++ return FALSE; ++ } ++ /* 1. allocate WIPHY */ ++ prWiphy = wiphy_new(&mtk_p2p_ops, sizeof(P_GLUE_INFO_T)); ++ if (!prWiphy) { ++ DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n"); ++ goto free_wdev; ++ } ++ ++ prWiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION); ++ ++ prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; ++ prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; ++ ++ prWiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes; ++ prWiphy->max_remain_on_channel_duration = 5000; ++ prWiphy->cipher_suites = mtk_cipher_suites; ++ prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); ++ prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME; ++ prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; ++ prWiphy->ap_sme_capa = 1; ++ ++ prWiphy->max_scan_ssids = MAX_SCAN_LIST_NUM; ++ prWiphy->max_scan_ie_len = MAX_SCAN_IE_LEN; ++ prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ prWiphy->vendor_commands = mtk_p2p_vendor_ops; ++ prWiphy->n_vendor_commands = sizeof(mtk_p2p_vendor_ops) / sizeof(struct wiphy_vendor_command); ++ ++#ifdef CONFIG_PM ++ prWiphy->wowlan = &p2p_wowlan_support; ++#endif ++ ++ /* 2.1 set priv as pointer to glue structure */ ++ *((P_GLUE_INFO_T *) wiphy_priv(prWiphy)) = prGlueInfo; ++ if (wiphy_register(prWiphy) < 0) { ++ DBGLOG(P2P, ERROR, "fail to register wiphy for p2p\n"); ++ goto free_wiphy; ++ } ++ prWdev->wiphy = prWiphy; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* 3. allocate netdev */ ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), P2P_MODE_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prNetDev) { ++ DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); ++ goto unregister_wiphy; ++ } ++ ++ /* 4. setup netdev */ ++ /* 4.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = prGlueInfo; ++ ++ /* 4.2 fill hardware address */ ++ /* COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] ^= 0x2; // change to local administrated address ++ memcpy(prGlueInfo->prP2PInfo->prDevHandler->dev_addr, rMacAddr, ETH_ALEN); ++ memcpy(prGlueInfo->prP2PInfo->prDevHandler->perm_addr, ++ prGlueInfo->prP2PInfo->prDevHandler->dev_addr, ETH_ALEN);*/ ++ ++ /* 4.3 register callback functions */ ++ prNetDev->netdev_ops = &p2p_netdev_ops; ++ /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def;*/ ++ ++ prNetDev->ieee80211_ptr = prWdev; ++ prWdev->netdev = prNetDev; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prNetDev->features = NETIF_F_IP_CSUM; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ /* net device initialize */ ++ netif_carrier_off(prNetDev); ++ netif_tx_stop_all_queues(prNetDev); ++ ++ /* register for net device */ ++ if (register_netdev(prNetDev) < 0) { ++ DBGLOG(P2P, ERROR, "unable to register netdevice for p2p\n"); ++ free_netdev(prNetDev); ++ goto unregister_wiphy; ++ } ++#endif ++ gprP2pWdev = prWdev; ++ return TRUE; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++unregister_wiphy: ++ wiphy_unregister(prWiphy); ++#endif ++free_wiphy: ++ wiphy_free(prWiphy); ++free_wdev: ++ kfree(prWdev); ++#endif ++ return FALSE; ++} ++ ++void glP2pDestroyWirelessDevice(VOID) ++{ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#if CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(gprP2pWdev->netdev); ++ free_netdev(gprP2pWdev->netdev); ++#endif ++ wiphy_unregister(gprP2pWdev->wiphy); ++ wiphy_free(gprP2pWdev->wiphy); ++ kfree(gprP2pWdev); ++ gprP2pWdev = NULL; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register for cfg80211 for Wi-Fi Direct ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GL_HIF_INFO_T prHif = NULL; ++ PARAM_MAC_ADDRESS rMacAddr; ++ struct net_device *prDevHandler = NULL; ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ struct device *prDev; ++#endif ++ ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prHif = &prGlueInfo->rHifInfo; ++ ASSERT(prHif); ++ ++ DBGLOG(P2P, TRACE, "glRegisterP2P\n"); ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ if (!gprP2pWdev) { ++ DBGLOG(P2P, ERROR, "gl_p2p, wireless device is not exist\n"); ++ return FALSE; ++ } ++#endif ++ /*0. allocate p2pinfo */ ++ if (!p2PAllocInfo(prGlueInfo)) { ++ DBGLOG(P2P, ERROR, "Allocate memory for p2p FAILED\n"); ++ ASSERT(0); ++ return FALSE; ++ } ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prGlueInfo->prP2PInfo->prWdev = gprP2pWdev; ++ /* 1. fill wiphy parameters */ ++#if MTK_WCN_HIF_SDIO ++ mtk_wcn_hif_sdio_get_dev(prHif->cltCtx, &prDev); ++ if (!prDev) ++ DBGLOG(P2P, WARN, "unable to get struct dev for p2p\n"); ++#else ++ prDev = prHif->Dev; ++#endif ++ /*set_wiphy_dev(gprP2pWdev->wiphy, prDev);*/ ++ if (!prGlueInfo->prAdapter->fgEnable5GBand) ++ gprP2pWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; ++ ++ /* 2 set priv as pointer to glue structure */ ++ *(P_GLUE_INFO_T *) wiphy_priv(gprP2pWdev->wiphy) = prGlueInfo; ++ ++ if (fgIsApMode) { ++ gprP2pWdev->iftype = NL80211_IFTYPE_AP; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ if (kalStrnCmp(gprP2pWdev->netdev->name, AP_MODE_INF_NAME, 2)) { ++ rtnl_lock(); ++ dev_change_name(gprP2pWdev->netdev->name, AP_MODE_INF_NAME); ++ rtnl_unlock(); ++ } ++#endif ++ } else { ++#if CFG_SUPPORT_PERSIST_NETDEV ++ if (kalStrnCmp(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME, 3)) { ++ rtnl_lock(); ++ dev_change_name(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME); ++ rtnl_unlock(); ++ } ++#endif ++ gprP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ prP2PInfo->prDevHandler = gprP2pWdev->netdev; ++#else /* CFG_SUPPORT_PERSIST_NETDEV */ ++ /* 3. allocate netdev */ ++ prDevHandler = ++ alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prDevHandler) { ++ DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); ++ return FALSE; ++ } ++ prGlueInfo->prP2PInfo->prDevHandler = prDevHandler; ++ /* 4. setup netdev */ ++ /* 4.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prDevHandler)) = prGlueInfo; ++ ++ /* 4.2 fill hardware address */ ++ COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] ^= 0x2; /* change to local administrated address */ ++ ether_addr_copy(prDevHandler->dev_addr, rMacAddr); ++ ether_addr_copy(prDevHandler->perm_addr, prDevHandler->dev_addr); ++ ++ /* 4.3 register callback functions */ ++ prDevHandler->netdev_ops = &p2p_netdev_ops; ++ /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; */ ++ ++#if (MTK_WCN_HIF_SDIO == 0) ++ SET_NETDEV_DEV(prDevHandler, prHif->Dev); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prDevHandler->ieee80211_ptr = gprP2pWdev; ++ gprP2pWdev->netdev = prDevHandler; ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prDevHandler->features = NETIF_F_IP_CSUM; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ ++ /* 5. set p2p net device register state */ ++ prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; ++ ++ /* 6. setup running mode */ ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = fgIsApMode; ++ ++ /* 7. finish */ ++ p2pFsmInit(prAdapter); ++ ++ p2pFuncInitConnectionSettings(prAdapter, prAdapter->rWifiVar.prP2PConnSettings); ++ ++ /* Active network too early would cause HW not able to sleep. ++ * Defer the network active time. ++ */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ return TRUE; ++} /* end of glRegisterP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister Net Device for Wi-Fi Direct ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ /* normal flow: this func will called first before wlanRemove, and it can do fsmUninit/deactivateNetwork ++ gracefully. */ ++ /* when reset: because tx_thread with fw has stopped, so it can't do these job and the recovery will be ++ dependent on chip system reset. */ ++ /* if so, just skip it by flag GLUE_FLAG_HALT(warning: when tx_thread was stop, this flag was not cleared, ++ and NEED TO KEEP IT NOT CLEARED!). */ ++ if (!(prGlueInfo->ulFlag & GLUE_FLAG_HALT)) { ++ p2pFsmUninit(prGlueInfo->prAdapter); ++ nicDeactivateNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++#if CFG_SUPPORT_PERSIST_NETDEV ++ dev_close(prGlueInfo->prP2PInfo->prDevHandler); ++#else ++ free_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ prGlueInfo->prP2PInfo->prDevHandler = NULL; ++#endif ++ /* Free p2p memory */ ++ if (!p2PFreeInfo(prGlueInfo)) { ++ DBGLOG(P2P, ERROR, "Free memory for p2p FAILED\n"); ++ ASSERT(0); ++ return FALSE; ++ } ++ return TRUE; ++} /* end of glUnregisterP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for stop p2p fsm immediate ++ * ++ * \param[in] prGlueInfo Pointer to struct P_GLUE_INFO_T. ++ * ++ * \retval TRUE The execution succeeds. ++ * \retval FALSE The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo) ++{ ++/* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ ++ ASSERT(prGlueInfo); ++ ++/* prAdapter = prGlueInfo->prAdapter; */ ++/* ASSERT(prAdapter); */ ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ ++#if 0 ++ /* 2. switch P2P-FSM off */ ++ /* 2.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ DBGLOG(P2P, ERROR, "Allocate for p2p mesasage FAILED\n"); ++ /* return -ENOMEM; */ ++ } ++ ++ /* 2.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = FALSE; ++ ++ /* 2.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_UNBUF); ++ ++#endif ++ ++ /* 3. stop queue and turn off carrier */ ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ return TRUE; ++} /* end of p2pStop() */ ++ ++/* Net Device Hooks */ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device open (ifup) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int p2pOpen(IN struct net_device *prDev) ++{ ++/* P_GLUE_INFO_T prGlueInfo = NULL; */ ++/* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ ++ ASSERT(prDev); ++ ++#if 0 /* Move after device name set. (mtk_p2p_set_local_dev_info) */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 1. switch P2P-FSM on */ ++ /* 1.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = TRUE; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++ /* 2. carrier on & start TX queue */ ++ netif_carrier_on(prDev); ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of p2pOpen() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device stop (ifdown) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int p2pStop(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ /* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ASSERT(prGlueP2pInfo); ++ ++ /* CFG80211 down */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueP2pInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueP2pInfo->prScanRequest; ++ prGlueP2pInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (prScanRequest) ++ cfg80211_scan_done(prScanRequest, &info); ++#if 0 ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prDev); ++ ++ /* 2. switch P2P-FSM off */ ++ /* 2.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 2.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = FALSE; ++ ++ /* 2.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ /* 3. stop queue and turn off carrier */ ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ netif_tx_stop_all_queues(prDev); ++ if (netif_carrier_ok(prDev)) ++ netif_carrier_off(prDev); ++ ++ return 0; ++} /* end of p2pStop() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A method of struct net_device, to get the network interface statistical ++ * information. ++ * ++ * Whenever an application needs to get statistics for the interface, this method ++ * is called. This happens, for example, when ifconfig or netstat -i is run. ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \return net_device_stats buffer pointer. ++ */ ++/*----------------------------------------------------------------------------*/ ++struct net_device_stats *p2pGetStats(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* @FIXME */ ++ /* prDev->stats.rx_packets = 0; */ ++ /* prDev->stats.tx_packets = 0; */ ++ prDev->stats.tx_errors = 0; ++ prDev->stats.rx_errors = 0; ++ /* prDev->stats.rx_bytes = 0; */ ++ /* prDev->stats.tx_bytes = 0; */ ++ prDev->stats.multicast = 0; ++ ++ return &prDev->stats; ++ ++#else ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_packets = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.tx_packets = 0; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_errors = 0; ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.multicast = 0; ++ ++ return &prGlueInfo->prP2PInfo->rNetDevStats; ++#endif ++} /* end of p2pGetStats() */ ++ ++static void p2pSetMulticastList(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ return; ++ } ++ ++ g_P2pPrDev = prDev; ++ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++/* prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_MULTICAST; */ ++ set_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++} /* p2pSetMulticastList */ ++ ++/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange ++ * another workqueue for sleeping. We don't want to block ++ * tx_thread, so we can't let tx_thread to do this */ ++ ++void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo) ++{ ++ if (!prGlueInfo) { ++ DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); ++ return; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ mtk_p2p_wext_set_Multicastlist(prGlueInfo); ++#endif ++} /* end of p2pSetMulticastListWorkQueueWrapper() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function is to set multicast list and set rx mode. ++ * ++ * \param[in] prDev Pointer to struct net_device ++ * ++ * \return (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++void mtk_p2p_wext_set_Multicastlist(P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_32 u4SetInfoLen = 0; ++ struct net_device *prDev = g_P2pPrDev; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ return; ++ } ++ ++ if (prDev->flags & IFF_PROMISC) ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; ++ ++ if (prDev->flags & IFF_BROADCAST) ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; ++ ++ if (prDev->flags & IFF_MULTICAST) { ++ if ((prDev->flags & IFF_ALLMULTI) || ++ (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } else { ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; ++ } ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { ++ /* Prepare multicast address list */ ++ struct netdev_hw_addr *ha; ++ UINT_32 i = 0; ++ ++ netdev_for_each_mc_addr(ha, prDev) { ++ if (i < MAX_NUM_GROUP_ADDR) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucMCAddrList[i]), ha->addr); ++ i++; ++ } ++ } ++ ++ DBGLOG(P2P, TRACE, "SEt Multicast Address List\n"); ++ ++ if (i >= MAX_NUM_GROUP_ADDR) ++ return; ++ wlanoidSetP2PMulticastList(prGlueInfo->prAdapter, ++ &(prGlueInfo->prP2PInfo->aucMCAddrList[0]), (i * ETH_ALEN), &u4SetInfoLen); ++ ++ } ++ ++} /* end of mtk_p2p_wext_set_Multicastlist */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * * \brief This function is TX entry point of NET DEVICE. ++ * * ++ * * \param[in] prSkb Pointer of the sk_buff to be sent ++ * * \param[in] prDev Pointer to struct net_device ++ * * ++ * * \retval NETDEV_TX_OK - on success. ++ * * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++ * */ ++/*----------------------------------------------------------------------------*/ ++int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) ++{ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_16 u2QueueIdx = 0; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prGlueInfo->u8SkbToDriver++; ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(P2P, ERROR, "GLUE_FLAG_HALT skip tx\n"); ++ prGlueInfo->u8SkbFreed++; ++ dev_kfree_skb(prSkb); ++ return NETDEV_TX_OK; ++ } ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetProfilingStart(prGlueInfo, prSkb); ++#endif ++ ++ /* mark as P2P packets */ ++ GLUE_SET_PKT_FLAG_P2P(prSkb); ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); ++#endif ++ ++ STATS_TX_TIME_ARRIVE(prSkb); ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++ if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { ++ DBGLOG(P2P, ERROR, "Incorrect queue index, skip this frame\n"); ++ prGlueInfo->u8SkbFreed++; ++ dev_kfree_skb(prSkb); ++ return NETDEV_TX_OK; ++ } ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); ++ ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_stop_subqueue for p2p0, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ } ++ } else { ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ kalSetEvent(prGlueInfo); ++ ++ /* Statistic usage. */ ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes += prSkb->len; ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_packets++; ++ /* prDev->stats.tx_packets++; */ ++ kalPerMonStart(prGlueInfo); ++ return NETDEV_TX_OK; ++} /* end of p2pHardStartXmit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A method of struct net_device, a primary SOCKET interface to configure ++ * the interface lively. Handle an ioctl call on one of our devices. ++ * Everything Linux ioctl specific is done here. Then we pass the contents ++ * of the ifr->data to the request message handler. ++ * ++ * \param[in] prDev Linux kernel netdevice ++ * ++ * \param[in] prIfReq Our private ioctl request structure, typed for the generic ++ * struct ifreq so we can use ptr to function ++ * ++ * \param[in] cmd Command ID ++ * ++ * \retval 0 The IOCTL command is executed successfully. ++ * \retval <0 The execution of IOCTL command is failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ struct iwreq *prIwReq = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ ++ ASSERT(prDev && prIfReq); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (!prGlueInfo) { ++ DBGLOG(P2P, ERROR, "prGlueInfo is NULL\n"); ++ return -EFAULT; ++ } ++ ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ DBGLOG(P2P, ERROR, "Adapter is not ready\n"); ++ return -EINVAL; ++ } ++ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case SIOCSIWENCODEEXT: ++ /* Set Encryption Material after 4-way handshaking is done */ ++ if (prIwReq->u.encoding.pointer) { ++ u4ExtraSize = prIwReq->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, prIwReq->u.encoding.pointer, prIwReq->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (prIwReq->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = mtk_p2p_wext_set_key(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCSIWMLME: ++ /* IW_MLME_DISASSOC used for disconnection */ ++ if (prIwReq->u.data.length != sizeof(struct iw_mlme)) { ++ DBGLOG(P2P, WARN, "MLME buffer strange:%d\n", prIwReq->u.data.length); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (!prIwReq->u.data.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, prIwReq->u.data.pointer, sizeof(struct iw_mlme))) ++ ret = -EFAULT; ++ else ++ ret = mtk_p2p_wext_mlme_handler(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCGIWPRIV: ++ /* This ioctl is used to list all IW privilege ioctls */ ++ ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case SIOCGIWSCAN: ++ ret = mtk_p2p_wext_discovery_results(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case SIOCSIWAUTH: ++ ret = mtk_p2p_wext_set_auth(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case IOC_P2P_CFG_DEVICE: ++ case IOC_P2P_PROVISION_COMPLETE: ++ case IOC_P2P_START_STOP_DISCOVERY: ++ case IOC_P2P_DISCOVERY_RESULTS: ++ case IOC_P2P_WSC_BEACON_PROBE_RSP_IE: ++ case IOC_P2P_CONNECT_DISCONNECT: ++ case IOC_P2P_PASSWORD_READY: ++ case IOC_P2P_GET_STRUCT: ++ case IOC_P2P_SET_STRUCT: ++ case IOC_P2P_GET_REQ_DEVICE_INFO: ++ ret = ++ rP2PIwPrivHandler[i4Cmd - SIOCIWFIRSTPRIV] (prDev, &rIwReqInfo, &(prIwReq->u), ++ (char *)&(prIwReq->u)); ++ break; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case SIOCGIWSTATS: ++ ret = mtk_p2p_wext_get_rssi(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++#endif ++ case IOC_GET_PRIVATE_IOCTL_CMD: ++ ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); ++ ++ break; ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} /* end of p2pDoIOCTL() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To report the iw private args table to user space. ++ * ++ * \param[in] prDev Net device requested. ++ * \param[in] info Pointer to iw_request_info. ++ * \param[inout] wrqu Pointer to iwreq_data. ++ * \param[inout] extra ++ * ++ * \retval 0 For success. ++ * \retval -E2BIG For user's buffer size is too small. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_priv(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ UINT_16 u2BufferSize = prData->length; ++ ++ /* Update our private args table size */ ++ prData->length = (__u16)sizeof(rP2PIwPrivTable); ++ if (u2BufferSize < prData->length) ++ return -E2BIG; ++ ++ if (prData->length) { ++ if (copy_to_user(prData->pointer, rP2PIwPrivTable, sizeof(rP2PIwPrivTable))) ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_get_priv() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To indicate P2P-FSM for re-associate to the connecting device ++ * ++ * \param[in] prDev Net device requested. ++ * \param[inout] wrqu Pointer to iwreq_data ++ * ++ * \retval 0 For success. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_reconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_HDR_T prMsgHdr; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_reconnect: P2P Reconnect\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_reconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief MLME command handler ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_mlme *mlme = (struct iw_mlme *)extra; ++ P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_mlme_handler:\n"); ++ ++ switch (mlme->cmd) { ++ case IW_MLME_DISASSOC: ++ prMsgP2PConnAbt = ++ (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ if (!prMsgP2PConnAbt) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, mlme->addr.sa_data); ++ ++ prMsgP2PConnAbt->u2ReasonCode = mlme->reason_code; ++ ++ if (EQUAL_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prP2pBssInfo->aucOwnMacAddr)) { ++ DBGLOG(P2P, TRACE, "P2P Connection Abort:\n"); ++ ++ /* 1.2 fill message */ ++ prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ } else { ++ DBGLOG(P2P, TRACE, "P2P Connection Pause:\n"); ++ ++ /* 1.2 fill message */ ++ } ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_mlme_handler() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_PROVISION_COMPLETE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_MSG_HDR_T prMsgHdr; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ switch (prData->flags) { ++ case P2P_PROVISIONING_SUCCESS: ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ ++ prGlueInfo->prP2PInfo->u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++ ++ break; ++ ++ case P2P_PROVISIONING_FAIL: ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ ++ return 0; ++} /* end of mtk_p2p_wext_set_provision_complete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_START_STOP_DISCOVERY) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_REQ_DEVICE_TYPE prReqDeviceType = (P_IW_P2P_REQ_DEVICE_TYPE) extra; ++ UINT_8 au4IeBuf[MAX_IE_LENGTH]; ++ P_MSG_HDR_T prMsgHdr; ++ P_MSG_P2P_DEVICE_DISCOVER_T prDiscoverMsg; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prData->flags == P2P_STOP_DISCOVERY) { ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++ } else if (prData->flags == P2P_START_DISCOVERY) { ++ ++ /* retrieve IE for Probe Response */ ++ if (prReqDeviceType->probe_rsp_len > 0) { ++ if (prReqDeviceType->probe_rsp_len <= MAX_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prReqDeviceType->probe_rsp_ie, ++ prReqDeviceType->probe_rsp_len)) { ++ return -EFAULT; ++ } ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prReqDeviceType->probe_rsp_len; ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ /* retrieve IE for Probe Request */ ++ if (prReqDeviceType->probe_req_len > 0) { ++ if (prReqDeviceType->probe_req_len <= MAX_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[1], prReqDeviceType->probe_req_ie, ++ prReqDeviceType->probe_req_len)) { ++ return -EFAULT; ++ } ++ prGlueInfo->prP2PInfo->u2WSCIELen[1] = prReqDeviceType->probe_req_len; ++ } else { ++ return -E2BIG; ++ } ++ } ++ /* update IE for Probe Request */ ++ ++ if (prReqDeviceType->scan_type == P2P_LISTEN) { ++ /* update listening parameter */ ++ ++ /* @TODO: update prConnSettings for Probe Response IE */ ++ } else { ++ /* indicate P2P-FSM with MID_MNY_P2P_DEVICE_DISCOVERY */ ++ prDiscoverMsg = (P_MSG_P2P_DEVICE_DISCOVER_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_DEVICE_DISCOVER_T)); ++ ++ if (!prDiscoverMsg) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ prDiscoverMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; ++ prDiscoverMsg->u4DevDiscoverTime = 0; /* unlimited */ ++ prDiscoverMsg->fgIsSpecificType = TRUE; ++ prDiscoverMsg->rTargetDeviceType.u2CategoryID = ++ *(PUINT_16) (&(prReqDeviceType->pri_device_type[0])); ++ prDiscoverMsg->rTargetDeviceType.u2SubCategoryID = ++ *(PUINT_16) (&(prReqDeviceType->pri_device_type[6])); ++ COPY_MAC_ADDR(prDiscoverMsg->aucTargetDeviceID, aucNullAddr); ++ ++ /* @FIXME: parameter to be refined, where to pass IE buffer ? */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDiscoverMsg, MSG_SEND_METHOD_BUF); ++ } ++ } else { ++ return -EINVAL; ++ } ++#endif ++ ++ return 0; ++} /* end of mtk_p2p_wext_start_stop_discovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++#if 0 ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_IOCTL_INVITATION_STRUCT prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) NULL; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ if (prIoctlInvitation->ucReinvoke == 1) { ++ /* TODO: Set Group ID */ ++ p2pFuncSetGroupID(prAdapter, prIoctlInvitation->aucGroupID, prIoctlInvitation->aucSsid, ++ prIoctlInvitation->u4SsidLen); ++ } ++ ++ else { ++ P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationReq = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; ++ ++ /* TODO: Do Invitation. */ ++ prMsgP2PInvitationReq = ++ (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_INVITATION_REQUEST_T)); ++ if (!prMsgP2PInvitationReq) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ i4Status = -ENOMEM; ++ break; ++ } ++ ++ /* 1.2 fill message */ ++ kalMemCopy(prMsgP2PInvitationReq->aucDeviceID, prIoctlInvitation->aucDeviceID, MAC_ADDR_LEN); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationReq, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++#endif ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_invitation_request */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_abort(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++#if 0 ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_IOCTL_ABORT_INVITATION prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) NULL; ++ ++ UINT_8 bssid[MAC_ADDR_LEN]; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationAbort = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; ++ ++ prMsgP2PInvitationAbort = ++ (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_INVITATION_REQUEST_T)); ++ ++ if (!prMsgP2PInvitationAbort) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ i4Status = -ENOMEM; ++ break; ++ } ++ ++ /* 1.2 fill message */ ++ kalMemCopy(prMsgP2PInvitationAbort->aucDeviceID, prIoctlInvitationAbort->dev_addr, ++ MAC_ADDR_LEN); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationAbort, MSG_SEND_METHOD_BUF); ++ ++ ++ } while (FALSE); ++#endif ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_invitation_abort */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To override p2p interface address ++ * ++ * \param[in] prDev Net device requested. ++ * \param[in] addr Pointer to address ++ * ++ * \retval 0 For success. ++ * \retval -E2BIG For user's buffer size is too small. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int p2pSetMACAddress(IN struct net_device *prDev, void *addr) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @FIXME */ ++ return eth_mac_addr(prDev, addr); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher suite ++* ++* \param[in] prDev Net device requested. ++* \param[out] ++* ++* \retval 0 Success. ++* \retval -EINVAL Invalid parameter ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_auth(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_param *prAuth = (struct iw_param *)wrqu; ++ ++ ASSERT(prDev); ++ ASSERT(prAuth); ++ if (FALSE == GLUE_CHK_PR2(prDev, prAuth)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ /* Save information to glue info and process later when ssid is set. */ ++ switch (prAuth->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ prGlueInfo->prP2PInfo->u4CipherPairwise = prAuth->value; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ case IW_AUTH_DROP_UNENCRYPTED: ++ case IW_AUTH_80211_AUTH_ALG: ++ case IW_AUTH_WPA_ENABLED: ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ case IW_AUTH_ROAMING_CONTROL: ++ case IW_AUTH_PRIVACY_INVOKED: ++ default: ++ /* @TODO */ ++ break; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_set_auth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[out] prIfReq Pointer to ifreq structure, content is copied back to ++* user space buffer in gl_iwpriv_table. ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_key(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int ret = 0; ++ struct iw_encode_ext *prIWEncExt; ++ struct iw_point *prEnc; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ UINT_8 keyStructBuf[100]; ++ P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; ++ P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ do { ++ if (wrqu->encoding.pointer) { ++ u4ExtraSize = wrqu->encoding.length; ++ /*need confirm u4ExtraSize > 0 but is not very large*/ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ /* here should set prExtraBuf default value */ ++ memset(prExtraBuf, 0, u4ExtraSize); ++ if (copy_from_user(prExtraBuf, wrqu->encoding.pointer, wrqu->encoding.length)) { ++ ret = -EFAULT; ++ break; ++ } ++ } else if (wrqu->encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prEnc = &wrqu->encoding; ++ /* here, need confirm (struct iw_encode_ext) < u4ExtraSize */ ++ prIWEncExt = (struct iw_encode_ext *)prExtraBuf; ++ ++ if (GLUE_CHK_PR3(prDev, prEnc, prExtraBuf) != TRUE) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { /* Key Removal */ ++ prRemoveKey->u4Length = sizeof(*prRemoveKey); ++ memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveP2PKey, ++ prRemoveKey, ++ prRemoveKey->u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ ret = -EFAULT; ++ } else { ++ if (prIWEncExt->alg == IW_ENCODE_ALG_CCMP) { ++ /* KeyID */ ++ prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ ((prEnc->flags & IW_ENCODE_INDEX) - 1) : 0; ++ if (prKey->u4KeyIndex <= 3) { ++ /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ ++ /* Tx Key Bit(31) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ prKey->u4KeyIndex |= 0x1UL << 31; ++ ++ /* Pairwise Key Bit(30) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* group key */ ++ } else { ++ /* pairwise key */ ++ prKey->u4KeyIndex |= 0x1UL << 30; ++ } ++ ++ /* Rx SC Bit(29) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ prKey->u4KeyIndex |= 0x1UL << 29; ++ memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, ++ IW_ENCODE_SEQ_MAX_SIZE); ++ } ++ ++ /* BSSID */ ++ memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ ++ prKey->u4KeyLength = prIWEncExt->key_len; ++ prKey->u4Length = ++ ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + ++ prKey->u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddP2PKey, ++ prKey, ++ prKey->u4Length, ++ FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ ret = -EFAULT; ++ } else { ++ ret = -EINVAL; ++ } ++ } else { ++ ret = -EINVAL; ++ } ++ } ++ ++ } while (FALSE); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ ++ return ret; ++} /* end of mtk_p2p_wext_set_key() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set the p2p gc power mode ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_powermode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ /* printk("set_powermode = %d, value = %d\n", wrqu->power.disabled, wrqu->power.value); */ ++ struct iw_param *prPower = (struct iw_param *)&wrqu->power; ++#if 1 ++ PARAM_POWER_MODE ePowerMode; ++ INT_32 i4PowerValue; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ if (prPower->disabled) { ++ ePowerMode = Param_PowerModeCAM; ++ } else { ++ i4PowerValue = prPower->value; ++#if WIRELESS_EXT < 21 ++ i4PowerValue /= 1000000; ++#endif ++ if (i4PowerValue == 0) { ++ ePowerMode = Param_PowerModeCAM; ++ } else if (i4PowerValue == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (i4PowerValue == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } else { ++ DBGLOG(P2P, ERROR, "%s(): unsupported power management mode value = %d.\n", ++ __func__, prPower->value); ++ ++ return -EINVAL; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief get the p2p gc power mode ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_powermode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ /* printk("mtk_p2p_wext_get_powermode\n"); */ ++ /* wrqu->power.disabled = 0; */ ++ /* wrqu->power.value = 1; */ ++ ++ struct iw_param *prPower = (struct iw_param *)&wrqu->power; ++ PARAM_POWER_MODE ePowerMode = Param_PowerModeMax; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pPowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), TRUE, FALSE, FALSE, TRUE, &u4BufLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryP2pPowerSaveProfile, &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++ ++ prPower->value = 0; ++ prPower->disabled = 1; ++ ++ if (Param_PowerModeCAM == ePowerMode) { ++ prPower->value = 0; ++ prPower->disabled = 1; ++ } else if (Param_PowerModeMAX_PSP == ePowerMode) { ++ prPower->value = 1; ++ prPower->disabled = 0; ++ } else if (Param_PowerModeFast_PSP == ePowerMode) { ++ prPower->value = 2; ++ prPower->disabled = 0; ++ } ++ ++ prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; ++#if WIRELESS_EXT < 21 ++ prPower->value *= 1000000; ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_CFG_DEVICE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_CFG_DEVICE_TYPE prDeviceCfg = (P_IW_P2P_CFG_DEVICE_TYPE) extra; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ /* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; */ ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ /* update connection settings for P2P-FSM */ ++ /* 1. update SSID */ ++ if (prDeviceCfg->ssid_len > ELEM_MAX_LEN_SSID) ++ prConnSettings->ucSSIDLen = ELEM_MAX_LEN_SSID; ++ else ++ prConnSettings->ucSSIDLen = prDeviceCfg->ssid_len; ++ ++ if (copy_from_user(prConnSettings->aucSSID, prDeviceCfg->ssid, prConnSettings->ucSSIDLen)) ++ return -EFAULT; ++ /* 2. update device type (WPS IE) */ ++ kalMemCopy(&(prConnSettings->rPrimaryDevTypeBE), &(prDeviceCfg->pri_device_type), sizeof(DEVICE_TYPE_T)); ++#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT ++ kalMemCopy(&(prConnSettings->arSecondaryDevTypeBE[0]), &(prDeviceCfg->snd_device_type), sizeof(DEVICE_TYPE_T)); ++#endif ++ ++ /* 3. update device name */ ++ if (prDeviceCfg->device_name_len > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ prConnSettings->ucDevNameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ else ++ prConnSettings->ucDevNameLen = prDeviceCfg->device_name_len; ++ if (copy_from_user(prConnSettings->aucDevName, prDeviceCfg->device_name, prConnSettings->ucDevNameLen)) ++ return -EFAULT; ++ /* 4. update GO intent */ ++ prConnSettings->ucGoIntent = prDeviceCfg->intend; ++ ++ /* Preferred channel bandwidth */ ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; ++ ++#if 0 ++ /* 1. switch P2P-FSM on */ ++ /* 1.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = TRUE; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_set_local_dev_info() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief I/O Control handler for both ++ * IOC_P2P_START_STOP_DISCOVERY & SIOCGIWSCAN ++ * ++ * \param[in] prDev Net device requested. ++ * \param[inout] wrqu Pointer to iwreq_data ++ * ++ * \retval 0 Success. ++ * \retval -EFAULT Setting parameters to driver fail. ++ * \retval -EOPNOTSUPP Key size not supported. ++ * ++ * \note ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_discovery_results(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ struct iw_event iwe; ++ char *current_ev = extra; ++ UINT_32 i; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ P_P2P_INFO_T prP2PInfo = (P_P2P_INFO_T) NULL; ++ P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; ++ P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prP2PInfo = prAdapter->prP2pInfo; ++ ++ for (i = 0; i < prP2PInfo->u4DeviceNum; i++) { ++ prTargetResult = &prP2PInfo->arP2pDiscoverResult[i]; ++ ++ /* SIOCGIWAP */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, prTargetResult->aucInterfaceAddr, 6); ++ ++ current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SIOCGIWESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = prTargetResult->u2NameLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, prTargetResult->aucName); ++ ++ /* IWEVGENIE for WPA IE */ ++ if (prTargetResult->u2IELength <= 600 && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++#if CFG_SUPPORT_WPS ++ ++ /* IWEVGENIE for WPS IE */ ++ if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPSIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++#endif ++ ++ /* IWEVGENIE for RSN IE */ ++ if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0x30, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++ ++ /* IOC_P2P_GO_WSC_IE */ ++#if 1 ++ /* device capability */ ++ if (1) { ++ UINT_8 data[40]; ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 9 + sizeof("p2p_cap="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_cap=%02x%02x%02x%02x%c", ++ prTargetResult->ucDeviceCapabilityBitmap, prTargetResult->ucGroupCapabilityBitmap, ++ (UINT_8) prTargetResult->u2ConfigMethod, ++ (UINT_8) (prTargetResult->u2ConfigMethod >> 8), '\0'); ++ current_ev = ++ iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ ++ /* printk("%s\n", data); */ ++ kalMemZero(data, 40); ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 13 + sizeof("p2p_dev_type="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_dev_type=%02x%02x%02x%02x%02x%02x%c", ++ (UINT_8) prTargetResult->rPriDevType.u2CategoryID, ++ (UINT_8) prTargetResult->rPriDevType.u2SubCategoryID, ++ (UINT_8) prTargetResult->arSecDevType[0].u2CategoryID, ++ (UINT_8) prTargetResult->arSecDevType[0].u2SubCategoryID, ++ (UINT_8) prTargetResult->arSecDevType[1].u2CategoryID, ++ (UINT_8) prTargetResult->arSecDevType[1].u2SubCategoryID, '\0'); ++ current_ev = ++ iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ /* printk("%s\n", data); */ ++ ++ kalMemZero(data, 40); ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 17 + sizeof("p2p_grp_bssid="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_grp_bssid= %pM %c", ++ prTargetResult->aucBSSID, '\0'); ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ /* printk("%s\n", data); */ ++ ++ } ++#endif ++ } ++ ++ /* Length of data */ ++ wrqu->data.length = (current_ev - extra); ++ wrqu->data.flags = 0; ++ ++ return 0; ++} /* end of mtk_p2p_wext_discovery_results() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_WSC_BEACON_PROBE_RSP_IE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_HOSTAPD_PARAM prHostapdParam = (P_IW_P2P_HOSTAPD_PARAM) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ if (prHostapdParam->len > 0) { ++ if (prHostapdParam->len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[0], prHostapdParam->data, prHostapdParam->len)) { ++ return -EFAULT; ++ } ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prHostapdParam->data, prHostapdParam->len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[0] = prHostapdParam->len; ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prHostapdParam->len; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* @TODO: send message to P2P-FSM */ ++ ++ return 0; ++} /* end of mtk_p2p_wext_wsc_ie() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_CONNECT_DISCONNECT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++/* P_IW_P2P_CONNECT_DEVICE prConnectDevice = (P_IW_P2P_CONNECT_DEVICE)extra; */ ++/* P_MSG_HDR_T prMsgHdr; */ ++/* P_MSG_P2P_CONNECTION_REQUEST_T prMsgP2PConnReq; */ ++/* P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt; */ ++/* UINT_8 aucBCAddr[] = BC_MAC_ADDR; */ ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ if (prData->flags == P2P_CONNECT) { ++#if 0 ++ /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_REQ */ ++ prMsgP2PConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ if (!prMsgP2PConnReq) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnReq, MSG_SEND_METHOD_BUF); ++#endif ++ } else if (prData->flags == P2P_DISCONNECT) { ++#if 0 ++ /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_ABORT */ ++ prMsgP2PConnAbt = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (!prMsgP2PConnAbt) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prConnectDevice->sta_addr); ++ ++ prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); ++#endif ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_connect_disconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_PASSWORD_READY) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_password_ready(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_PASSWORD_READY prPasswordReady = (P_IW_P2P_PASSWORD_READY) extra; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ /* retrieve IE for Probe Request */ ++ if (prPasswordReady->probe_req_len > 0) { ++ if (prPasswordReady->probe_req_len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[1], prPasswordReady->probe_req_ie, ++ prPasswordReady->probe_req_len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[1] = prPasswordReady->probe_req_len; ++ ++ /* retrieve IE for Probe Response */ ++ if (prPasswordReady->probe_rsp_len > 0) { ++ if (prPasswordReady->probe_rsp_len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prPasswordReady->probe_rsp_ie, ++ prPasswordReady->probe_rsp_len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prPasswordReady->probe_rsp_len; ++ ++ switch (prPasswordReady->active_config_method) { ++ case 1: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_PUSH_BUTTON; ++ break; ++ case 2: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_KEYPAD; ++ break; ++ case 3: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_DISPLAY; ++ break; ++ default: ++ break; ++ } ++ ++ prConnSettings->fgIsPasswordIDRdy = TRUE; ++ return 0; ++} /* end of mtk_p2p_wext_password_ready() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_REQ_DEVICE_INFO) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_DEVICE_REQ prDeviceReq = (P_IW_P2P_DEVICE_REQ) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_DEVICE_REQ); ++ ++ /* copy to upper-layer supplied buffer */ ++ kalMemCopy(prDeviceReq->name, prGlueInfo->prP2PInfo->aucConnReqDevName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ prDeviceReq->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; ++ prDeviceReq->name[prDeviceReq->name_len] = '\0'; ++ COPY_MAC_ADDR(prDeviceReq->device_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); ++ prDeviceReq->device_type = prGlueInfo->prP2PInfo->ucConnReqDevType; ++ prDeviceReq->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; ++ prDeviceReq->active_config_method = prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod; ++ ++ return 0; ++} /* end of mtk_p2p_wext_request_dev_info() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_IOCTL_INVITATION_INDICATE prInvIndicate = (P_IW_P2P_IOCTL_INVITATION_INDICATE) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_INDICATE); ++ ++ /* copy to upper-layer supplied buffer */ ++ kalMemCopy(prInvIndicate->dev_name, prGlueInfo->prP2PInfo->aucConnReqDevName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ kalMemCopy(prInvIndicate->group_bssid, prGlueInfo->prP2PInfo->rConnReqGroupAddr, MAC_ADDR_LEN); ++ prInvIndicate->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; ++ prInvIndicate->dev_name[prInvIndicate->name_len] = '\0'; ++ COPY_MAC_ADDR(prInvIndicate->dev_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); ++ prInvIndicate->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; ++ prInvIndicate->operating_channel = prGlueInfo->prP2PInfo->ucOperatingChnl; ++ prInvIndicate->invitation_type = prGlueInfo->prP2PInfo->ucInvitationType; ++ ++ return 0; ++} /* end of mtk_p2p_wext_invitation_indicate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_status(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_IOCTL_INVITATION_STATUS prInvStatus = (P_IW_P2P_IOCTL_INVITATION_STATUS) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_STATUS); ++ ++ /* copy to upper-layer supplied buffer */ ++ prInvStatus->status_code = prGlueInfo->prP2PInfo->u4InvStatus; ++ ++ return 0; ++} /* end of mtk_p2p_wext_invitation_status() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief indicate an event to supplicant for device found ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval TRUE Success. ++* \retval FALSE Failure ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_FND"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PDVCFND event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++ return FALSE; ++} /* end of kalP2PIndicateFound() */ ++ ++int ++mtk_p2p_wext_set_network_address(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pNetworkAddress, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++int ++mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++int ++mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_start_formation(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++/* struct iw_point *prData = (struct iw_point*)&wrqu->data; */ ++ P_IW_P2P_IOCTL_START_FORMATION prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) NULL; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_start_formation */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_int(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 index; ++ INT_32 value; ++ PUINT_32 pu4IntBuf; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ UINT_32 u4Leng; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ /* printk("mtk_p2p_wext_set_int\n"); */ ++ pu4IntBuf = (PUINT_32) extra; ++ ++ if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pFsmInfo = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ u4SubCmd = (UINT_32) wrqu->mode; ++ index = pu4IntBuf[1]; ++ value = pu4IntBuf[2]; ++ ++ DBGLOG(P2P, INFO, "set parameter, u4SubCmd=%d idx=%d value=%d\n", (INT_16) u4SubCmd, (INT_16) index, value); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_INT_P2P_SET: ++ switch (index) { ++ case 0: /* Listen CH */ ++ { ++ UINT_8 ucSuggestChnl = 0; ++ ++ prP2pConnSettings->ucListenChnl = value; ++ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ if (rlmFuncFindAvailableChannel ++ (prGlueInfo->prAdapter, value, &ucSuggestChnl, TRUE, TRUE)) { ++ prP2pSpecificBssInfo->ucListenChannel = value; ++ } else { ++ prP2pSpecificBssInfo->ucListenChannel = ucSuggestChnl; ++ } ++ ++ break; ++ } ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, ++ (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, ++ (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ status = ++ mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ prP2pConnSettings->ucOperatingChnl = value; ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ /* prP2pConnSettings->u2LocalConfigMethod; */ ++ break; ++ case 102: /* Sigma P2p reset */ ++ kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ status = ++ mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rOppPsParam); ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ u4SubCmd = (UINT_32) wrqu->data.flags; ++ ++ kalMemZero(&prGlueInfo->prP2PInfo->aucOidBuf[0], sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEND_SD_RESPONSE: ++ status = mtk_p2p_wext_send_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_SEND_SD_REQUEST: ++ status = mtk_p2p_wext_send_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_TERMINATE_SD_PHASE: ++ status = mtk_p2p_wext_terminate_service_discovery_phase(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_INVITATION: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_INVITATION_STRUCT)) { ++ /* Do nothing */ ++ /* status = mtk_p2p_wext_invitation_request(prDev, info, wrqu, ++ (char *)(prP2PReq->aucBuffer)); */ ++ } ++ break; ++ ++ case P2P_CMD_ID_INVITATION_ABORT: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_ABORT_INVITATION)) { ++ /* Do nothing */ ++ /* status = mtk_p2p_wext_invitation_abort(prDev, info, wrqu, ++ (char *)(prP2PReq->aucBuffer)); */ ++ } ++ break; ++ ++ case P2P_CMD_ID_START_FORMATION: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_START_FORMATION)) ++ status = mtk_p2p_wext_start_formation(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ break; ++#if CFG_SUPPORT_ANTI_PIRACY ++ case PRIV_SEC_CHECK_OID: ++ if (wrqu->data.length > 256) { ++ status = -EOPNOTSUPP; ++ break; ++ } ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEC_CHECK: ++ status = mtk_p2p_wext_set_sec_check_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ break; ++#endif ++ case PRIV_CMD_P2P_VERSION: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_P2P_VERSION: ++ status = mtk_p2p_wext_set_p2p_version(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ if (!prDev || !wrqu) { ++ DBGLOG(P2P, WARN, "%s(): invalid param(0x%p, 0x%p)\n", __func__, prDev, wrqu); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ u4SubCmd = (UINT_32) wrqu->data.flags; ++ ++ kalMemZero(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_GET_SD_REQUEST: ++ status = mtk_p2p_wext_get_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_GET_SD_RESPONSE: ++ status = mtk_p2p_wext_get_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_INVITATION_INDICATE: ++ { ++ status = ++ mtk_p2p_wext_invitation_indicate(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ prP2PReq->outBufferLength = wrqu->data.length; ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ case P2P_CMD_ID_INVITATION_STATUS: ++ { ++ status = ++ mtk_p2p_wext_invitation_status(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ prP2PReq->outBufferLength = wrqu->data.length; ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ case P2P_CMD_ID_GET_CH_LIST: ++ { ++ UINT_16 i; ++ UINT_8 NumOfChannel = 50; ++ RF_CHANNEL_INFO_T aucChannelList[50]; ++ UINT_8 ucMaxChannelNum = 50; ++ PUINT_8 pucChnlList = (PUINT_8) prP2PReq->aucBuffer; ++ ++ kalGetChnlList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); ++ if (NumOfChannel > 50) ++ NumOfChannel = 50; ++ prP2PReq->outBufferLength = NumOfChannel; ++ /*here must confirm NumOfChannel < 16, for prP2PReq->aucBuffer 16 byte*/ ++ if (NumOfChannel >= 15) { ++ /*DBGLOG(P2P, ERROR, "channel num > 15\n", __func__);*/ ++ ASSERT(FALSE); ++ } ++ ++ for (i = 0; i < NumOfChannel; i++) { ++#if 0 ++ /* 20120208 frog: modify to avoid clockwork warning. */ ++ prP2PReq->aucBuffer[i] = aucChannelList[i].ucChannelNum; ++#else ++ *pucChnlList = aucChannelList[i].ucChannelNum; ++ pucChnlList++; ++#endif ++ } ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ NumOfChannel + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ ++ case P2P_CMD_ID_GET_OP_CH: ++ { ++ prP2PReq->inBufferLength = 4; ++ ++ status = wlanoidQueryP2pOpChannel(prGlueInfo->prAdapter, ++ prP2PReq->aucBuffer, ++ prP2PReq->inBufferLength, &prP2PReq->outBufferLength); ++ ++ if (status == 0) { /* WLAN_STATUS_SUCCESS */ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, ++ aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } else { ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ break; ++ } ++ ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ break; ++#if CFG_SUPPORT_ANTI_PIRACY ++ case PRIV_SEC_CHECK_OID: ++ if (wrqu->data.length > 256) { ++ status = -EOPNOTSUPP; ++ break; ++ } ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEC_CHECK: ++ status = mtk_p2p_wext_get_sec_check_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ break; ++#endif ++ case PRIV_CMD_P2P_VERSION: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_P2P_VERSION: ++ status = mtk_p2p_wext_get_p2p_version(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ ++ /* Copy queried data to user. */ ++ if (status == 0) { /* WLAN_STATUS_SUCCESS */ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ ++ else { ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* getting service discovery request frame from driver ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetP2PSDRequest, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* getting service discovery response frame from driver ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetP2PSDResponse, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* sending service discovery request frame ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSendP2PSDRequest, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* sending service discovery response frame ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSendP2PSDResponse, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetSecCheckRequest, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_get_sec_check_response\n"); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetSecCheckResponse, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ prP2PReq->aucBuffer, u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ return 0; ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* terminating service discovery phase ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2PTerminateSDPhase, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ /* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_set_noa_param\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetNoaParam, prNoaParam, /* prP2PReq->aucBuffer, */ ++ sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ ++ FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++/* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_set_oppps_param\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetOppPsParam, prOppPsParam, /* prP2PReq->aucBuffer, */ ++ sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ ++ FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++int ++mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ UINT_32 u4SetInfoLen; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSupplicantVersion, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} ++ ++/* mtk_p2p_wext_set_p2p_version */ ++ ++int ++mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pVersion, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} /* mtk_p2p_wext_get_p2p_version */ ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ ++int ++mtk_p2p_wext_get_rssi(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ UINT_16 u2BufferSize = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rssi; ++ struct iw_statistics *pStats = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ if (!prGlueInfo) { ++ rStatus = WLAN_STATUS_FAILURE; ++ goto stat_out; ++ } ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ u2BufferSize = prData->length; ++ ++ if (u2BufferSize < sizeof(struct iw_statistics)) ++ return -E2BIG; ++ ++ if (copy_to_user(prData->pointer, pStats, sizeof(struct iw_statistics))) ++ rStatus = WLAN_STATUS_FAILURE; ++ ++stat_out: ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} /* mtk_p2p_wext_get_rssi */ ++ ++struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_statistics *pStats = NULL; ++ INT_32 i4Rssi; ++ UINT_32 bufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) ++ goto stat_out; ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ ++ if (!prDev || !netif_carrier_ok(prDev)) { ++ /* network not connected */ ++ goto stat_out; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &bufLen); ++ ++stat_out: ++ return pStats; ++} /* mtk_p2p_wext_get_wireless_stats */ ++ ++#endif /* CFG_SUPPORT_P2P_RSSI_QUERY */ ++ ++int ++mtk_p2p_wext_set_txpow(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++#if 0 ++ P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; ++#endif ++ int i4Ret = 0; ++ ++ ASSERT(prDev); ++ ASSERT(prTxPow); ++ ++ do { ++ if ((!prDev) || (!prTxPow)) { ++ i4Ret = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ if (!prGlueInfo) { ++ i4Ret = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++#if 0 ++ prMsgFuncSwitch = ++ (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ if (!prMsgFuncSwitch) { ++ ASSERT(0); ++ return -ENOMEM; ++ } ++ ++ prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ ++ if (prTxPow->disabled) { ++ /* Dissolve. */ ++ prMsgFuncSwitch->fgIsFuncOn = FALSE; ++ } else { ++ ++ /* Re-enable function. */ ++ prMsgFuncSwitch->fgIsFuncOn = TRUE; ++ } ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++ } while (FALSE); ++ ++ return i4Ret; ++} /* mtk_p2p_wext_set_txpow */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c +new file mode 100644 +index 000000000000..4d71e0c59b05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c +@@ -0,0 +1,1935 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_cfg80211.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ using cfg80211 interface ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_p2p_cfg80211.c ++** ++** 01 30 2013 yuche.tsai ++** [ALPS00455459] [GN_WIFI]??wifi direct??????????? ++** Fix possible race condition under GO mode. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 09 05 2012 wh.su ++** [ALPS00351547] [6577JB][WiFi direct]The 3rd device fail to establish p2p connection with GO sometimes ++** sync with the ICS code. ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, ++** one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 08 21 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++** ++** 08 17 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix p2p bug find on ALPS.JB trunk. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "config.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "precomp.h" ++#include "gl_cfg80211.h" ++#include "gl_p2p_ioctl.h" ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++BOOLEAN ++mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, ++ IN enum nl80211_channel_type channel_type, ++ IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ P2P_PARAM_KEY_T rKey; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ kalMemZero(&rKey, sizeof(P2P_PARAM_KEY_T)); ++ ++ rKey.u4KeyIndex = key_index; ++ if (mac_addr) { ++ ether_addr_copy(rKey.arBSSID, mac_addr); ++ if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && ++ (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ } ++ if (rKey.arBSSID[0] != 0xFF) { ++ rKey.u4KeyIndex |= BIT(31); ++ if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || ++ (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) ++ rKey.u4KeyIndex |= BIT(30); ++ } else { ++ rKey.u4KeyIndex |= BIT(31); ++ } ++ } else { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ rKey.u4KeyIndex |= BIT(31); /* ???? */ ++ } ++ if (params->key) { ++ /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ ++ kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); ++ } ++ rKey.u4KeyLength = params->key_len; ++ rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetAddP2PKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_REMOVE_KEY_T prRemoveKey; ++ INT_32 i4Rslt = -EINVAL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ i4Rslt = 0; ++ return i4Rslt; ++ } ++ ++ kalMemZero(&prRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); ++ if (mac_addr) ++ memcpy(prRemoveKey.arBSSID, mac_addr, PARAM_MAC_ADDR_LEN); ++ prRemoveKey.u4KeyIndex = key_index; ++ prRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveP2PKey, ++ &prRemoveKey, prRemoveKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++int ++mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, ++ struct net_device *netdev, u8 key_index, bool unicast, bool multicast) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_info *sinfo) ++{ ++ INT_32 i4RetRslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ P2P_STATION_INFO_T rP2pStaInfo; ++ ++ ASSERT(wiphy); ++ ++ do { ++ if ((wiphy == NULL) || (ndev == NULL) || (sinfo == NULL) || (mac == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_get_station\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ sinfo->filled = 0; ++ ++ /* Get station information. */ ++ /* 1. Inactive time? */ ++ p2pFuncGetStationInfo(prGlueInfo->prAdapter, (PUINT_8)mac, &rP2pStaInfo); ++ ++ /* Inactive time. */ ++ sinfo->filled |= NL80211_STA_INFO_INACTIVE_TIME; ++ sinfo->inactive_time = rP2pStaInfo.u4InactiveTime; ++ sinfo->generation = prP2pGlueInfo->i4Generation; ++ ++ i4RetRslt = 0; ++ } while (FALSE); ++ ++ return i4RetRslt; ++} ++ ++int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ P_MSG_P2P_SCAN_REQUEST_T prMsgScanRequest = (P_MSG_P2P_SCAN_REQUEST_T) NULL; ++ UINT_32 u4MsgSize = 0, u4Idx = 0; ++ INT_32 i4RetRslt = -EINVAL; ++ P_RF_CHANNEL_INFO_T prRfChannelInfo = (P_RF_CHANNEL_INFO_T) NULL; ++ P_P2P_SSID_STRUCT_T prSsidStruct = (P_P2P_SSID_STRUCT_T) NULL; ++ struct ieee80211_channel *prChannel = NULL; ++ struct cfg80211_ssid *prSsid = NULL; ++ ++ /* [---------Channel---------] [---------SSID---------][---------IE---------] */ ++ DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan\n"); ++ ++ do { ++ if ((wiphy == NULL) || (request == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ if (prP2pGlueInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_scan.\n"); ++ ++ if (prP2pGlueInfo->prScanRequest != NULL) { ++ /* There have been a scan request on-going processing. */ ++ DBGLOG(P2P, TRACE, "There have been a scan request on-going processing.\n"); ++ break; ++ } ++ ++ prP2pGlueInfo->prScanRequest = request; ++ ++ /* Should find out why the n_channels so many? */ ++ if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { ++ request->n_channels = MAXIMUM_OPERATION_CHANNEL_LIST; ++ DBGLOG(P2P, TRACE, "Channel list exceed the maximun support.\n"); ++ } ++ ++ u4MsgSize = sizeof(MSG_P2P_SCAN_REQUEST_T) + ++ (request->n_channels * sizeof(RF_CHANNEL_INFO_T)) + ++ (request->n_ssids * sizeof(PARAM_SSID_T)) + request->ie_len; ++ ++ prMsgScanRequest = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, u4MsgSize); ++ ++ if (prMsgScanRequest == NULL) { ++ ASSERT(FALSE); ++ i4RetRslt = -ENOMEM; ++ prP2pGlueInfo->prScanRequest = NULL; ++ DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan Allocate Mem failed\n"); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "Generating scan request message.\n"); ++ ++ prMsgScanRequest->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; ++ ++ DBGLOG(P2P, INFO, "Requesting channel number:%d.\n", request->n_channels); ++ ++ for (u4Idx = 0; u4Idx < request->n_channels; u4Idx++) { ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo = &(prMsgScanRequest->arChannelListInfo[u4Idx]); ++ prChannel = request->channels[u4Idx]; ++ ++ prRfChannelInfo->ucChannelNum = nicFreq2ChannelNum(prChannel->center_freq * 1000); ++ DBGLOG(P2P, TRACE, "Scanning Channel:%d, freq: %d\n", ++ prRfChannelInfo->ucChannelNum, prChannel->center_freq); ++ switch (prChannel->band) { ++ case NL80211_BAND_2GHZ: ++ prRfChannelInfo->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prRfChannelInfo->eBand = BAND_5G; ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "UNKNOWN Band info from supplicant\n"); ++ prRfChannelInfo->eBand = BAND_NULL; ++ break; ++ } ++ ++ /* Iteration. */ ++ prRfChannelInfo++; ++ } ++ prMsgScanRequest->u4NumChannel = request->n_channels; ++ ++ DBGLOG(P2P, TRACE, "Finish channel list.\n"); ++ ++ /* SSID */ ++ prSsid = request->ssids; ++ prSsidStruct = (P_P2P_SSID_STRUCT_T) prRfChannelInfo; ++ if (prSsidStruct) { ++ if (request->n_ssids) { ++ ASSERT((ULONG) prSsidStruct == (ULONG)&(prMsgScanRequest->arChannelListInfo[u4Idx])); ++ prMsgScanRequest->prSSID = prSsidStruct; ++ } ++ ++ for (u4Idx = 0; u4Idx < request->n_ssids; u4Idx++) { ++ COPY_SSID(prSsidStruct->aucSsid, ++ prSsidStruct->ucSsidLen, request->ssids->ssid, request->ssids->ssid_len); ++ ++ prSsidStruct++; ++ prSsid++; ++ } ++ ++ prMsgScanRequest->i4SsidNum = request->n_ssids; ++ ++ DBGLOG(P2P, TRACE, "Finish SSID list:%d.\n", request->n_ssids); ++ ++ /* IE BUFFERS */ ++ prMsgScanRequest->pucIEBuf = (PUINT_8) prSsidStruct; ++ if (request->ie_len) { ++ kalMemCopy(prMsgScanRequest->pucIEBuf, request->ie, request->ie_len); ++ prMsgScanRequest->u4IELen = request->ie_len; ++ } ++ } ++ ++ DBGLOG(P2P, TRACE, "Finish IE Buffer.\n"); ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = FALSE; ++#endif ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgScanRequest, MSG_SEND_METHOD_BUF); ++ ++ i4RetRslt = 0; ++ } while (FALSE); ++ ++ return i4RetRslt; ++} /* mtk_p2p_cfg80211_scan */ ++ ++int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_wiphy_params\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (changed & WIPHY_PARAM_RETRY_SHORT) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY short param is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_RETRY_LONG) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY long param is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY fragmentation threshold is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY RTS threshold is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_COVERAGE_CLASS) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The coverage class is changed???\n"); ++ } ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_set_wiphy_params */ ++ ++int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ enum nl80211_tx_power_setting type, int mbm) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ int *dbm) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 value; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ if (enabled) ++ value = 2; ++ else ++ value = 0; ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_power_mgmt ps=%d.\n", enabled); ++ ++ /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ return 0; ++} ++ ++/* &&&&&&&&&&&&&&&&&&&&&&&&&& Add for ICS Wi-Fi Direct Support. &&&&&&&&&&&&&&&&&&&&&&& */ ++int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ /* P_IE_SSID_T prSsidIE = (P_IE_SSID_T)NULL; */ ++ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct cfg80211_chan_def *chandef = &wdev->preset_chandef; ++ ++ do { ++ if ((wiphy == NULL) || (settings == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_ap.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++#if 1 ++ mtk_p2p_cfg80211_set_channel(wiphy, chandef); ++#else ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->ucOperatingChnl = ++ (chandef->chan->center_freq - 2407) / 5; ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->eBand = BAND_2G4; ++#endif ++ ++ prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_BEACON_UPDATE_T) + ++ settings->beacon.head_len + ++ settings->beacon.tail_len)); ++ ++ if (prP2pBcnUpdateMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; ++ pucBuffer = prP2pBcnUpdateMsg->aucBuffer; ++ ++ if (settings->beacon.head_len != 0) { ++ kalMemCopy(pucBuffer, settings->beacon.head, settings->beacon.head_len); ++ ++ prP2pBcnUpdateMsg->u4BcnHdrLen = settings->beacon.head_len; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) settings->beacon.head_len); ++ } else { ++ prP2pBcnUpdateMsg->u4BcnHdrLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = NULL; ++ } ++ ++ if (settings->beacon.tail_len != 0) { ++ UINT_32 ucLen = settings->beacon.tail_len; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; ++ ++ /*Add TIM IE */ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = 1; ++ TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; ++ /* will be overwrite by FW */ ++ ucLen += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ kalMemCopy(pucBuffer, settings->beacon.tail, settings->beacon.tail_len); ++ ++ prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; ++ } else { ++ prP2pBcnUpdateMsg->u4BcnBodyLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = NULL; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); ++ ++ prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_START_AP_T)); ++ ++ if (prP2pStartAPMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pStartAPMsg->rMsgHdr.eMsgId = MID_MNY_P2P_START_AP; ++ ++ prP2pStartAPMsg->fgIsPrivacy = settings->privacy; ++ ++ prP2pStartAPMsg->u4BcnInterval = settings->beacon_interval; ++ ++ prP2pStartAPMsg->u4DtimPeriod = settings->dtim_period; ++ ++ /* Copy NO SSID. */ ++ prP2pStartAPMsg->ucHiddenSsidType = settings->hidden_ssid; ++ ++ COPY_SSID(prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen, settings->ssid, settings->ssid_len); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pStartAPMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++/* /////////////////////// */ ++ /** ++ * struct cfg80211_ap_settings - AP configuration ++ * ++ * Used to configure an AP interface. ++ * ++ * @beacon: beacon data ++ * @beacon_interval: beacon interval ++ * @dtim_period: DTIM period ++ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from ++ * user space) ++ * @ssid_len: length of @ssid ++ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames ++ * @crypto: crypto settings ++ * @privacy: the BSS uses privacy ++ * @auth_type: Authentication type (algorithm) ++ * @inactivity_timeout: time in seconds to determine station's inactivity. ++ */ ++/* struct cfg80211_ap_settings { */ ++/* struct cfg80211_beacon_data beacon; */ ++/* */ ++/* int beacon_interval, dtim_period; */ ++/* const u8 *ssid; */ ++/* size_t ssid_len; */ ++/* enum nl80211_hidden_ssid hidden_ssid; */ ++/* struct cfg80211_crypto_settings crypto; */ ++/* bool privacy; */ ++/* enum nl80211_auth_type auth_type; */ ++/* int inactivity_timeout; */ ++/* }; */ ++/* ////////////////// */ ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_start_ap */ ++ ++int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (info == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_beacon.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_BEACON_UPDATE_T) + ++ info->head_len + info->tail_len)); ++ ++ if (prP2pBcnUpdateMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; ++ pucBuffer = prP2pBcnUpdateMsg->aucBuffer; ++ ++ if (info->head_len != 0) { ++ kalMemCopy(pucBuffer, info->head, info->head_len); ++ ++ prP2pBcnUpdateMsg->u4BcnHdrLen = info->head_len; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) info->head_len); ++ } else { ++ prP2pBcnUpdateMsg->u4BcnHdrLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = NULL; ++ } ++ ++ if (info->tail_len != 0) { ++ UINT_32 ucLen = info->tail_len; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; ++ ++ /*Add TIM IE */ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = 1; ++ TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; ++ /* will be overwrite by FW */ ++ ucLen += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ kalMemCopy(pucBuffer, info->tail, info->tail_len); ++ ++ prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; ++ } else { ++ prP2pBcnUpdateMsg->u4BcnBodyLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = NULL; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); ++ ++/* ////////////////////////// */ ++/** ++ * struct cfg80211_beacon_data - beacon data ++ * @head: head portion of beacon (before TIM IE) ++ * or %NULL if not changed ++ * @tail: tail portion of beacon (after TIM IE) ++ * or %NULL if not changed ++ * @head_len: length of @head ++ * @tail_len: length of @tail ++ * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL ++ * @beacon_ies_len: length of beacon_ies in octets ++ * @proberesp_ies: extra information element(s) to add into Probe Response ++ * frames or %NULL ++ * @proberesp_ies_len: length of proberesp_ies in octets ++ * @assocresp_ies: extra information element(s) to add into (Re)Association ++ * Response frames or %NULL ++ * @assocresp_ies_len: length of assocresp_ies in octets ++ * @probe_resp_len: length of probe response template (@probe_resp) ++ * @probe_resp: probe response template (AP mode only) ++ */ ++/* struct cfg80211_beacon_data { */ ++/* const u8 *head, *tail; */ ++/* const u8 *beacon_ies; */ ++/* const u8 *proberesp_ies; */ ++/* const u8 *assocresp_ies; */ ++/* const u8 *probe_resp; */ ++ ++/* size_t head_len, tail_len; */ ++/* size_t beacon_ies_len; */ ++/* size_t proberesp_ies_len; */ ++/* size_t assocresp_ies_len; */ ++/* size_t probe_resp_len; */ ++/* }; */ ++ ++/* ////////////////////////// */ ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_change_beacon */ ++ ++int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_stop_ap.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* Switch OP MOde. */ ++ prP2pSwitchMode = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_SWITCH_OP_MODE_T)); ++ ++ if (prP2pSwitchMode == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pSwitchMode->rMsgHdr.eMsgId = MID_MNY_P2P_STOP_AP; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pSwitchMode, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_stop_ap */ ++ ++/* TODO: */ ++int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_deauth.\n"); ++ ++ return -EINVAL; ++} /* mtk_p2p_cfg80211_deauth */ ++ ++/* TODO: */ ++int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_disassoc.\n"); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} /* mtk_p2p_cfg80211_disassoc */ ++ ++int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ P_MSG_P2P_CHNL_REQUEST_T prMsgChnlReq = (P_MSG_P2P_CHNL_REQUEST_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ *cookie = prGlueP2pInfo->u8Cookie++; ++ ++ prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_REQUEST_T)); ++ ++ if (prMsgChnlReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_remain_on_channel\n"); ++ ++ prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; ++ prMsgChnlReq->u8Cookie = *cookie; ++ prMsgChnlReq->u4Duration = duration; ++ ++ mtk_p2p_cfg80211func_channel_format_switch(chan, NL80211_CHAN_HT20, /* 4 KH Need Check */ ++ &prMsgChnlReq->rChannelInfo, &prMsgChnlReq->eChnlSco); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/* mtk_p2p_cfg80211_remain_on_channel */ ++int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_MSG_P2P_CHNL_ABORT_T prMsgChnlAbort = (P_MSG_P2P_CHNL_ABORT_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_ABORT_T)); ++ ++ if (prMsgChnlAbort == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_cancel_remain_on_channel\n"); ++ ++ prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_ABORT; ++ prMsgChnlAbort->u8Cookie = cookie; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_cancel_remain_on_channel */ ++ ++int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prMsgExtListenReq = NULL; ++ P_MSG_P2P_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; ++ P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucFrameBuf = (PUINT_8) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) ++ break; ++ /* DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_mgmt_tx\n")); */ ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ *cookie = prGlueP2pInfo->u8Cookie++; ++ ++ /* Channel & Channel Type & Wait time are ignored. */ ++ prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_TX_REQUEST_T)); ++ ++ if (prMsgTxReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ /* Here need to extend the listen interval */ ++ prMsgExtListenReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T)); ++ if (prMsgExtListenReq) { ++ prMsgExtListenReq->rMsgHdr.eMsgId = MID_MNY_P2P_EXTEND_LISTEN_INTERVAL; ++ prMsgExtListenReq->wait = params->wait; ++ DBGLOG(P2P, INFO, "ext listen, wait: %d\n", prMsgExtListenReq->wait); ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgExtListenReq, ++ MSG_SEND_METHOD_BUF); ++ } ++ ++ prMsgTxReq->fgNoneCckRate = FALSE; ++ prMsgTxReq->fgIsWaitRsp = TRUE; ++ ++ prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); ++ ++ prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; ++ if (prMsgTxReq->prMgmtMsduInfo == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->u8Cookie = *cookie; ++ prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_TX; ++ ++ pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucFrameBuf, params->buf, params->len); ++ ++ prMgmtFrame->u2FrameLength = params->len; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { ++ if (prMsgTxReq->prMgmtMsduInfo != NULL) ++ cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); ++ ++ cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); ++ } ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_mgmt_tx */ ++ ++int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ switch (params->use_cts_prot) { ++ case -1: ++ DBGLOG(P2P, TRACE, "CTS protection no change\n"); ++ break; ++ case 0: ++ DBGLOG(P2P, TRACE, "CTS protection disable.\n"); ++ break; ++ case 1: ++ DBGLOG(P2P, TRACE, "CTS protection enable\n"); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "CTS protection unknown\n"); ++ break; ++ } ++ ++ switch (params->use_short_preamble) { ++ case -1: ++ DBGLOG(P2P, TRACE, "Short prreamble no change\n"); ++ break; ++ case 0: ++ DBGLOG(P2P, TRACE, "Short prreamble disable.\n"); ++ break; ++ case 1: ++ DBGLOG(P2P, TRACE, "Short prreamble enable\n"); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Short prreamble unknown\n"); ++ break; ++ } ++ ++#if 0 ++ /* not implemented yet */ ++ p2pFuncChangeBssParam(prGlueInfo->prAdapter, ++ prBssInfo->fgIsProtection, ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortSlotTime, ++ /* Basic rates */ ++ /* basic rates len */ ++ /* ap isolate */ ++ /* ht opmode. */ ++ ); ++#else ++ i4Rslt = 0; ++#endif ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_change_bss */ ++ ++int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params) ++//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ UINT_8 aucBcMac[] = BC_MAC_ADDR; ++ const UINT_8 *mac = NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL)) ++ break; ++ ++ if (params->mac == NULL) ++ mac = aucBcMac; ++ else ++ mac = params->mac; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_del_station.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(MSG_P2P_CONNECTION_ABORT_T), ++ VIR_MEM_TYPE); */ ++ prDisconnectMsg = ++ (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (prDisconnectMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prDisconnectMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ COPY_MAC_ADDR(prDisconnectMsg->aucTargetID, mac); ++ prDisconnectMsg->u2ReasonCode = REASON_CODE_UNSPECIFIED; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnectMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} /* mtk_p2p_cfg80211_del_station */ ++ ++int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL) || (sme == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_connect.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prConnReqMsg = ++ (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_CONNECTION_REQUEST_T) + sme->ie_len)); ++ ++ if (prConnReqMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prConnReqMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ COPY_SSID(prConnReqMsg->rSsid.aucSsid, prConnReqMsg->rSsid.ucSsidLen, sme->ssid, sme->ssid_len); ++ ++ COPY_MAC_ADDR(prConnReqMsg->aucBssid, sme->bssid); ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_connect to %pM, IE len: %d\n", ++ prConnReqMsg->aucBssid, sme->ie_len); ++ ++ DBGLOG(P2P, TRACE, "Assoc Req IE Buffer Length:%d\n", sme->ie_len); ++ kalMemCopy(prConnReqMsg->aucIEBuf, sme->ie, sme->ie_len); ++ prConnReqMsg->u4IELen = sme->ie_len; ++ ++ mtk_p2p_cfg80211func_channel_format_switch(sme->channel, ++ NL80211_CHAN_NO_HT, ++ &prConnReqMsg->rChannelInfo, &prConnReqMsg->eChnlSco); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prConnReqMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_connect */ ++ ++int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL)) ++ break; ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++/* prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(P_MSG_P2P_CONNECTION_ABORT_T), VIR_MEM_TYPE); */ ++ prDisconnMsg = ++ (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (prDisconnMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.Allocate Memory Failed.\n"); ++ break; ++ } ++ ++ prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ prDisconnMsg->u2ReasonCode = reason_code; ++ prDisconnMsg->fgSendDeauth = TRUE; ++ COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_disconnect */ ++ ++int ++mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, ++ IN enum nl80211_iftype type,/* IN u32 *flags,*/ IN struct vif_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (ndev == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_iface.\n"); ++ ++ if (ndev->ieee80211_ptr) ++ ndev->ieee80211_ptr->iftype = type; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* Switch OP MOde. */ ++ prSwitchModeMsg = ++ (P_MSG_P2P_SWITCH_OP_MODE_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_SWITCH_OP_MODE_T)); ++ ++ if (prSwitchModeMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ ++ switch (type) { ++ case NL80211_IFTYPE_P2P_CLIENT: ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_CLIENT.\n"); ++ case NL80211_IFTYPE_STATION: ++ if (type == NL80211_IFTYPE_STATION) ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_STATION.\n"); ++ prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; ++ break; ++ case NL80211_IFTYPE_AP: ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_AP.\n"); ++ case NL80211_IFTYPE_P2P_GO: ++ if (type == NL80211_IFTYPE_P2P_GO) ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_GO not AP.\n"); ++ prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Other type :%d .\n", type); ++ prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; ++ break; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSwitchModeMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} /* mtk_p2p_cfg80211_change_iface */ ++ ++int mtk_p2p_cfg80211_set_channel(IN struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ RF_CHANNEL_INFO_T rRfChnlInfo; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_channel.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ mtk_p2p_cfg80211func_channel_format_switch(chandef->chan, chandef->width, &rRfChnlInfo, NULL); ++ p2pFuncSetChannel(prGlueInfo->prAdapter, &rRfChnlInfo); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} ++ ++/* mtk_p2p_cfg80211_set_channel */ ++ ++int ++mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, ++ IN struct net_device *dev, ++ IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL) || (mask == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_bitrate_mask\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* TODO: Set bitrate mask of the peer? */ ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_set_bitrate_mask */ ++ ++void mtk_p2p_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg) ++{ ++#if 0 ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++#endif ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_mgmt_frame_register\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ switch (frame_type) { ++ case MAC_FRAME_PROBE_REQ: ++ if (reg) { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); ++ } else { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (reg) { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); ++ } else { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(P2P, ERROR, "Ask frog to add code for mgmt:%x\n", frame_type); ++ break; ++ } ++ ++ if ((prGlueInfo->prAdapter != NULL) && (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE)) { ++ ++ /* prGlueInfo->u4Flag |= GLUE_FLAG_FRAME_FILTER; */ ++ set_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ if (in_interrupt()) ++ DBGLOG(P2P, TRACE, "It is in interrupt level\n"); ++ } ++#if 0 ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof ++ (MSG_P2P_MGMT_FRAME_REGISTER_T)); ++ ++ if (prMgmtFrameRegister == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; ++ ++ prMgmtFrameRegister->u2FrameType = frame_type; ++ prMgmtFrameRegister->fgIsRegister = reg; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); ++ ++#endif ++ ++ } while (FALSE); ++ ++} /* mtk_p2p_cfg80211_mgmt_frame_register */ ++ ++BOOLEAN ++mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, ++ IN enum nl80211_channel_type channel_type, ++ IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco) ++{ ++ BOOLEAN fgIsValid = FALSE; ++ ++ do { ++ if (channel == NULL) ++ break; ++ ++ if (prRfChnlInfo) { ++ prRfChnlInfo->ucChannelNum = nicFreq2ChannelNum(channel->center_freq * 1000); ++ ++ switch (channel->band) { ++ case NL80211_BAND_2GHZ: ++ prRfChnlInfo->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prRfChnlInfo->eBand = BAND_5G; ++ break; ++ default: ++ prRfChnlInfo->eBand = BAND_2G4; ++ break; ++ } ++ ++ } ++ ++ if (prChnlSco) { ++ ++ switch (channel_type) { ++ case NL80211_CHAN_NO_HT: ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ case NL80211_CHAN_HT20: ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ case NL80211_CHAN_HT40MINUS: ++ *prChnlSco = CHNL_EXT_SCA; ++ break; ++ case NL80211_CHAN_HT40PLUS: ++ *prChnlSco = CHNL_EXT_SCB; ++ break; ++ default: ++ ASSERT(FALSE); ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ } ++ } ++ ++ fgIsValid = TRUE; ++ } while (FALSE); ++ ++ return fgIsValid; ++} ++ ++/* mtk_p2p_cfg80211func_channel_format_switch */ ++ ++#if CONFIG_NL80211_TESTMODE ++int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_TEST_PARAMS prParams = (P_NL80211_DRIVER_TEST_PARAMS) NULL; ++ INT_32 i4Status = -EINVAL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = NULL; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_cmd\n"); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_TEST_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_cmd, data is NULL\n"); ++ return i4Status; ++ } ++ ++ if (prParams->index >> 24 == 0x01) { ++ /* New version */ ++ } else { ++ /* Old version */ ++ mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(wiphy, data, len); ++ i4Status = 0; ++ return i4Status; ++ } ++ ++ /* Clear the version byte */ ++ prParams->index = prParams->index & ~BITS(24, 31); ++ ++ if (prParams) { ++ switch (prParams->index) { ++ case 1: /* P2P Simga */ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ { ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParamsCmd; ++ ++ prParamsCmd = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if ((prParamsCmd->adr & 0xffff0000) == 0xffff0000) { ++ i4Status = mtk_p2p_cfg80211_testmode_sw_cmd(wiphy, data, len); ++ break; ++ } ++ } ++#endif ++ i4Status = mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(wiphy, data, len); ++ break; ++#if CFG_SUPPORT_WFD ++ case 2: /* WFD */ ++ i4Status = mtk_p2p_cfg80211_testmode_wfd_update_cmd(wiphy, data, len); ++ break; ++#endif ++ case 3: /* Hotspot Client Management */ ++ i4Status = mtk_p2p_cfg80211_testmode_hotspot_block_cmd(wiphy, data, len); ++ break; ++ case 0x10: ++ i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); ++ break; ++#if 1 ++ case 0x11: /*NFC Beam + Indication */ ++ prChnlReqInfo = &prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ if (data && len) { ++ P_NL80211_DRIVER_SET_NFC_PARAMS prParams = (P_NL80211_DRIVER_SET_NFC_PARAMS) data; ++ ++ prChnlReqInfo->NFC_BEAM = prParams->NFC_Enable; ++ DBGLOG(P2P, INFO, "NFC: BEAM[%d]\n", prChnlReqInfo->NFC_BEAM); ++ } ++ break; ++ case 0x12: /*NFC Beam + Indication */ ++ DBGLOG(P2P, INFO, "NFC: Polling\n"); ++ i4Status = mtk_cfg80211_testmode_get_scan_done(wiphy, data, len, prGlueInfo); ++ break; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ case 0x30: ++ i4Status = mtk_cfg80211_testmode_get_lte_channel(wiphy, data, len, prGlueInfo); ++ break; ++#endif ++ ++ default: ++ i4Status = -EINVAL; ++ break; ++ } ++ } ++ ++ return i4Status; ++} ++ ++int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ NL80211_DRIVER_TEST_PRE_PARAMS rParams; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 index_mode; ++ UINT_32 index; ++ INT_32 value; ++ int status = 0; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ kalMemZero(&rParams, sizeof(NL80211_DRIVER_TEST_PRE_PARAMS)); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd\n"); ++ ++ if (data && len) ++ memcpy(&rParams, data, len); ++ ++ DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA,idx_mode=%d idx=%d value=%u\n", ++ (INT_16) rParams.idx_mode, (INT_16) rParams.idx, rParams.value); ++ ++ index_mode = rParams.idx_mode; ++ index = rParams.idx; ++ value = rParams.value; ++ ++ switch (index) { ++ case 0: /* Listen CH */ ++ break; ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ /* prP2pConnSettings->ucOperatingChnl = value; */ ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ prP2pConnSettings->u2LocalConfigMethod = value; ++ break; ++ case 102: /* Sigma P2p reset */ ++ /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ p2pFsmUninit(prGlueInfo->prAdapter); ++ p2pFsmInit(prGlueInfo->prAdapter); ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++ ++} ++ ++int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_P2P_SIGMA_PARAMS prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 index; ++ INT_32 value; ++ int status = 0; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd\n"); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd, data is NULL or len is 0\n"); ++ return -EINVAL; ++ } ++ ++ index = (INT_32) prParams->idx; ++ value = (INT_32) prParams->value; ++ ++ DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA, idx=%d value=%d\n", ++ (INT_32) prParams->idx, (INT_32) prParams->value); ++ ++ switch (index) { ++ case 0: /* Listen CH */ ++ break; ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ /* prP2pConnSettings->ucOperatingChnl = value; */ ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ prP2pConnSettings->u2LocalConfigMethod = value; ++ break; ++ case 102: /* Sigma P2p reset */ ++ /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ case 109: /* Max Clients */ ++ kalP2PSetMaxClients(prGlueInfo, value); ++ break; ++ case 110: /* Hotspot WPS mode */ ++ kalIoctl(prGlueInfo, wlanoidSetP2pWPSmode, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++ ++} ++ ++#if CFG_SUPPORT_WFD ++int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_WFD_PARAMS prParams = (P_NL80211_DRIVER_WFD_PARAMS) NULL; ++ int status = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ static UINT_8 prevWfdEnable; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prParams = (P_NL80211_DRIVER_WFD_PARAMS) data; ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_testmode_wfd_update_cmd\n"); ++ ++ /* to reduce log, print when state changed */ ++ if (prevWfdEnable != prParams->WfdEnable) { ++ prevWfdEnable = prParams->WfdEnable; ++ DBGLOG(P2P, INFO, "WFD Enable:%x\n", prParams->WfdEnable); ++ DBGLOG(P2P, INFO, "WFD Session Available:%x\n", prParams->WfdSessionAvailable); ++ DBGLOG(P2P, INFO, "WFD Couple Sink Status:%x\n", prParams->WfdCoupleSinkStatus); ++ /* aucReserved0[2] */ ++ DBGLOG(P2P, INFO, "WFD Device Info:%x\n", prParams->WfdDevInfo); ++ DBGLOG(P2P, INFO, "WFD Control Port:%x\n", prParams->WfdControlPort); ++ DBGLOG(P2P, INFO, "WFD Maximum Throughput:%x\n", prParams->WfdMaximumTp); ++ DBGLOG(P2P, INFO, "WFD Extend Capability:%x\n", prParams->WfdExtendCap); ++ DBGLOG(P2P, INFO, "WFD Couple Sink Addr %pM\n", prParams->WfdCoupleSinkAddress); ++ DBGLOG(P2P, INFO, "WFD Associated BSSID %pM\n", prParams->WfdAssociatedBssid); ++ /* UINT_8 aucVideolp[4]; */ ++ /* UINT_8 aucAudiolp[4]; */ ++ DBGLOG(P2P, INFO, "WFD Video Port:%x\n", prParams->WfdVideoPort); ++ DBGLOG(P2P, INFO, "WFD Audio Port:%x\n", prParams->WfdAudioPort); ++ DBGLOG(P2P, INFO, "WFD Flag:%x\n", prParams->WfdFlag); ++ DBGLOG(P2P, INFO, "WFD Policy:%x\n", prParams->WfdPolicy); ++ DBGLOG(P2P, INFO, "WFD State:%x\n", prParams->WfdState); ++ /* UINT_8 aucWfdSessionInformationIE[24*8]; */ ++ DBGLOG(P2P, INFO, "WFD Session Info Length:%x\n", prParams->WfdSessionInformationIELen); ++ /* UINT_8 aucReserved1[2]; */ ++ DBGLOG(P2P, INFO, "WFD Primary Sink Addr %pM\n", prParams->aucWfdPrimarySinkMac); ++ DBGLOG(P2P, INFO, "WFD Secondary Sink Addr %pM\n", prParams->aucWfdSecondarySinkMac); ++ DBGLOG(P2P, INFO, "WFD Advanced Flag:%x\n", prParams->WfdAdvanceFlag); ++ DBGLOG(P2P, INFO, "WFD Sigma mode:%x\n", prParams->WfdSigmaMode); ++ /* UINT_8 aucReserved2[64]; */ ++ /* UINT_8 aucReserved3[64]; */ ++ /* UINT_8 aucReserved4[64]; */ ++ } ++ ++ prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ kalMemCopy(&prWfdCfgSettings->u4WfdCmdType, &prParams->WfdCmdType, sizeof(WFD_CFG_SETTINGS_T)); ++ ++ prMsgWfdCfgUpdate = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); ++ ++ if (prMsgWfdCfgUpdate == NULL) { ++ ASSERT(FALSE); ++ return status; ++ } ++ ++ prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; ++ prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); ++#if 0 /* Test Only */ ++/* prWfdCfgSettings->ucWfdEnable = 1; */ ++/* prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; */ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; ++ prWfdCfgSettings->u2WfdDevInfo = 123; ++ prWfdCfgSettings->u2WfdControlPort = 456; ++ prWfdCfgSettings->u2WfdMaximumTp = 789; ++ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_SINK_INFO_VALID; ++ prWfdCfgSettings->ucWfdCoupleSinkStatus = 0xAB; ++ { ++ UINT_8 aucTestAddr[MAC_ADDR_LEN] = { 0x77, 0x66, 0x55, 0x44, 0x33, 0x22 }; ++ ++ COPY_MAC_ADDR(prWfdCfgSettings->aucWfdCoupleSinkAddress, aucTestAddr); ++ } ++ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_EXT_CAPABILITY_VALID; ++ prWfdCfgSettings->u2WfdExtendCap = 0xCDE; ++ ++#endif ++ ++ return status; ++ ++} ++#endif /* CFG_SUPPORT_WFD */ ++ ++int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd, data is NULL or len is 0\n"); ++ return -EINVAL; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd\n"); ++ ++ return kalP2PSetBlackList(prGlueInfo, prParams->aucBssid, prParams->ucblocked); ++} ++ ++int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++#if 1 ++ DBGLOG(P2P, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if (prParams) { ++ if (prParams->set == 1) { ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, ++ &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#endif ++ ++#endif /* CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c +new file mode 100644 +index 000000000000..d0f2d25a4529 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c +@@ -0,0 +1,433 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/* ++** Id: @(#) gl_p2p_init.c@@ ++*/ ++ ++/*! \file gl_p2p_init.c ++ \brief init and exit routines of Linux driver interface for Wi-Fi Direct ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define P2P_MODE_INF_NAME "p2p%d" ++#if CFG_TC1_FEATURE ++#define AP_MODE_INF_NAME "wlan%d" ++#else ++#define AP_MODE_INF_NAME "ap%d" ++#endif ++/* #define MAX_INF_NAME_LEN 15 */ ++/* #define MIN_INF_NAME_LEN 1 */ ++ ++#define RUNNING_P2P_MODE 0 ++#define RUNNING_AP_MODE 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* Get interface name and running mode from module insertion parameter ++* Usage: insmod p2p.ko mode=1 ++* default: interface name is p2p%d ++* running mode is P2P ++*/ ++static PUCHAR ifname = P2P_MODE_INF_NAME; ++static UINT_16 mode = RUNNING_P2P_MODE; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief check interface name parameter is valid or not ++* if invalid, set ifname to P2P_MODE_INF_NAME ++* ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pCheckInterfaceName(VOID) ++{ ++ ++ if (mode) { ++ mode = RUNNING_AP_MODE; ++ ifname = AP_MODE_INF_NAME; ++ } ++#if 0 ++ UINT_32 ifLen = 0; ++ ++ if (ifname) { ++ ifLen = strlen(ifname); ++ ++ if (ifLen > MAX_INF_NAME_LEN) ++ ifname[MAX_INF_NAME_LEN] = '\0'; ++ else if (ifLen < MIN_INF_NAME_LEN) ++ ifname = P2P_MODE_INF_NAME; ++ } else { ++ ifname = P2P_MODE_INF_NAME; ++ } ++#endif ++} ++ ++void p2pHandleSystemSuspend(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ ++ ++ if (!wlanExportGlueInfo(&prGlueInfo)) { ++ DBGLOG(P2P, INFO, "No glue info\n"); ++ return; ++ } ++ ++ ASSERT(prGlueInfo); ++ /* <1> Sanity check and acquire the net_device */ ++ prDev = prGlueInfo->prP2PInfo->prDevHandler; ++ ASSERT(prDev); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ip is not available.\n"); ++ return; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ipv6 is not available.\n"); ++ return; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) ++ ; /* Do nothing */ ++#endif ++ /* <7> set up the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#ifdef CONFIG_IPV6 ++ prParamNetAddrList->u4AddressCount += u4NumIPv6; ++#endif ++ ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++#if 0 ++ kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prParamNetAddr + sizeof(ip)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); ++#else ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ ++/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++// TODO: frog. The pointer is not right. */ ++ ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + ++ (ULONG) (prParamNetAddr->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP); ++#endif ++ } ++#ifdef CONFIG_IPV6 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); */ ++ ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + ++ (ULONG) (prParamNetAddr->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ } ++} ++ ++void p2pHandleSystemResume(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++#endif ++ ++ if (!wlanExportGlueInfo(&prGlueInfo)) { ++ DBGLOG(P2P, WARN, "no glue info\n"); ++ return; ++ } ++ ++ ASSERT(prGlueInfo); ++ /* <1> Sanity check and acquire the net_device */ ++ prDev = prGlueInfo->prP2PInfo->prDevHandler; ++ ASSERT(prDev); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ip is not available.\n"); ++ return; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ipv6 is not available.\n"); ++ return; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++#endif ++ /* <7> clear the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = 0; ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* run p2p init procedure, include register pointer to wlan ++* glue register p2p ++* set p2p registered flag ++* \retval 1 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ DBGLOG(P2P, TRACE, "p2pLaunch\n"); ++ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE) { ++ DBGLOG(P2P, INFO, "p2p already registered\n"); ++ return FALSE; ++ } else if (glRegisterP2P(prGlueInfo, ifname, (BOOLEAN) mode)) { ++ prGlueInfo->prAdapter->fgIsP2PRegistered = TRUE; ++ ++ DBGLOG(P2P, TRACE, "Launch success, fgIsP2PRegistered TRUE.\n"); ++ return TRUE; ++ } ++ DBGLOG(P2P, ERROR, "Launch Fail\n"); ++ ++ return FALSE; ++} ++ ++VOID p2pSetMode(IN BOOLEAN fgIsAPMOde) ++{ ++ if (fgIsAPMOde) { ++ mode = RUNNING_AP_MODE; ++ ifname = AP_MODE_INF_NAME; ++ } else { ++ mode = RUNNING_P2P_MODE; ++ ifname = P2P_MODE_INF_NAME; ++ } ++ ++} /* p2pSetMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* run p2p exit procedure, include unregister pointer to wlan ++* glue unregister p2p ++* set p2p registered flag ++ ++* \retval 1 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo) ++{ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { ++ DBGLOG(P2P, INFO, "p2p is not Registered.\n"); ++ return FALSE; ++ } ++ /*Check p2p fsm is stop or not. If not then stop now */ ++ if (IS_P2P_ACTIVE(prGlueInfo->prAdapter)) ++ p2pStopImmediate(prGlueInfo); ++ prGlueInfo->prAdapter->fgIsP2PRegistered = FALSE; ++ glUnregisterP2P(prGlueInfo); ++ /*p2p is removed successfully */ ++ return TRUE; ++ ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver entry point when the driver is configured as a Linux Module, and ++* is called once at module load time, by the user-level modutils ++* application: insmod or modprobe. ++* ++* \retval 0 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++static int initP2P(void) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ /*check interface name validation */ ++ p2pCheckInterfaceName(); ++ ++ DBGLOG(P2P, INFO, "InitP2P, Ifname: %s, Mode: %s\n", ifname, mode ? "AP" : "P2P"); ++ ++ /*register p2p init & exit function to wlan sub module handler */ ++ wlanSubModRegisterInitExit(p2pLaunch, p2pRemove, P2P_MODULE); ++ ++ /*if wlan is not start yet, do nothing ++ * p2pLaunch will be called by txthread while wlan start ++ */ ++ /*if wlan is not started yet, return FALSE */ ++ if (wlanExportGlueInfo(&prGlueInfo)) { ++ wlanSubModInit(prGlueInfo); ++ return prGlueInfo->prAdapter->fgIsP2PRegistered ? 0 : -EIO; ++ } ++ ++ return 0; ++} /* end of initP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver exit point when the driver as a Linux Module is removed. Called ++* at module unload time, by the user level modutils application: rmmod. ++* This is our last chance to clean up after ourselves. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Leave Point */ ++static VOID __exit exitP2P(void) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DBGLOG(P2P, INFO, KERN_INFO DRV_NAME "ExitP2P\n"); ++ ++ /*if wlan is not started yet, return FALSE */ ++ if (wlanExportGlueInfo(&prGlueInfo)) ++ wlanSubModExit(prGlueInfo); ++ /*UNregister p2p init & exit function to wlan sub module handler */ ++ wlanSubModRegisterInitExit(NULL, NULL, P2P_MODULE); ++} /* end of exitP2P() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c +new file mode 100644 +index 000000000000..11a417e4c74c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c +@@ -0,0 +1,1314 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_kal.c ++ \brief ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "net/cfg80211.h" ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Wi-Fi Direct state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->eState; ++} /* end of kalP2PGetState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to update the assoc req to p2p ++* ++* \param[in] ++* prGlueInfo ++* pucFrameBody ++* u4FrameBodyLen ++* fgReassocRequest ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) ++{ ++ union iwreq_data wrqu; ++ unsigned char *pucExtraInfo = NULL; ++ unsigned char *pucDesiredIE = NULL; ++/* unsigned char aucExtraInfoBuf[200]; */ ++ PUINT_8 cp; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ if (fgReassocRequest) { ++ if (u4FrameBodyLen < 15) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } else { ++ if (u4FrameBodyLen < 9) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } ++ ++ cp = pucFrameBody; ++ ++ if (fgReassocRequest) { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ /* Current AP address 6 */ ++ cp += 10; ++ u4FrameBodyLen -= 10; ++ } else { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ cp += 4; ++ u4FrameBodyLen -= 4; ++ } ++ ++ /* do supplicant a favor, parse to the start of WPA/RSN IE */ ++ if (wextSrchDesiredWPSIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPSIE!!\n"); */ ++ /* WPS IE found */ ++ } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0x30, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPAIE!!\n"); */ ++ /* RSN IE found */ ++ } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPAIE!!\n"); */ ++ /* WPA IE found */ ++ } else { ++ /* no WPA/RSN IE found, skip this event */ ++ goto skip_indicate_event; ++ } ++ ++ /* IWEVASSOCREQIE, indicate binary string */ ++ pucExtraInfo = pucDesiredIE; ++ wrqu.data.length = pucDesiredIE[1] + 2; ++ ++ /* Send event to user space */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVASSOCREQIE, &wrqu, pucExtraInfo); ++ ++skip_indicate_event: ++ return; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Wi-Fi Direct state in glue layer ++* ++* \param[in] ++* prGlueInfo ++* eBowState ++* rPeerAddr ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ if (eState == PARAM_MEDIA_STATE_CONNECTED) { ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_CONNECTED; ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_CONNECT=%pM ", rPeerAddr); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++ } else if (eState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_DISCONNECT=%pM ", rPeerAddr); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ } else { ++ ASSERT(0); ++ } ++ ++} /* end of kalP2PSetState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Wi-Fi Direct operating frequency ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* in unit of KHz ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->u4FreqInKHz; ++} /* end of kalP2PGetFreqInKHz() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* 0: P2P Device ++* 1: Group Client ++* 2: Group Owner ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->ucRole; ++} /* end of kalP2PGetRole() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Wi-Fi Direct role ++* ++* \param[in] ++* prGlueInfo ++* ucResult ++* 0: successful ++* 1: error ++* ucRole ++* 0: P2P Device ++* 1: Group Client ++* 2: Group Owner ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ucRole <= 2); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ if (ucResult == 0) ++ prGlueInfo->prP2PInfo->ucRole = ucRole; ++ ++ if (pucSSID) ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, ++ 1 /* persistence or not */ , pucSSID[7], pucSSID[8]); ++ else ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, ++ 1 /* persistence or not */ , '0', '0'); ++ ++ evt.data.length = strlen(aucBuffer); ++ ++ /* if (pucSSID) */ ++ /* printk("P2P GO SSID DIRECT-%c%c\n", pucSSID[7], pucSSID[8]); */ ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PSetRole() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the cipher for p2p ++* ++* \param[in] ++* prGlueInfo ++* u4Cipher ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prGlueInfo->prP2PInfo->u4CipherPairwise = u4Cipher; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the cipher, return for cipher is ccmp ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE: cipher is ccmp ++* FALSE: cipher is none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return TRUE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return TRUE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return FALSE; ++ ++ return FALSE; ++} ++ ++BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return FALSE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the status of WSC ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prGlueInfo->prP2PInfo->ucWSCRunning = ucWscMode; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the status of WSC ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return 0; ++ } ++ ++ return prGlueInfo->prP2PInfo->ucWSCRunning; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the wsc ie length ++* ++* \param[in] ++* prGlueInfo ++* ucType : 0 for beacon, 1 for probe req, 2 for probe resp ++* ++* \return ++* The WSC IE length ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType) ++{ ++ ASSERT(prGlueInfo); ++ ++ ASSERT(ucType < 3); ++ ++ return prGlueInfo->prP2PInfo->u2WSCIELen[ucType]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to copy the wsc ie setting from p2p supplicant ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* The WPS IE length ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer) ++{ ++ P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (ucType >= 3) || (pucBuffer == NULL)) ++ break; ++ ++ prGlP2pInfo = prGlueInfo->prP2PInfo; ++ ++ kalMemCopy(pucBuffer, prGlP2pInfo->aucWSCIE[ucType], prGlP2pInfo->u2WSCIELen[ucType]); ++ ++ } while (FALSE); ++ ++} ++ ++VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength) ++{ ++ P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (ucType >= 3) || ((u2BufferLength > 0) && (pucBuffer == NULL))) ++ break; ++ ++ if (u2BufferLength > 400) { ++ DBGLOG(P2P, ERROR, ++ "Buffer length is not enough, GLUE only 400 bytes but %d received\n", u2BufferLength); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlP2pInfo = prGlueInfo->prP2PInfo; ++ ++ kalMemCopy(prGlP2pInfo->aucWSCIE[ucType], pucBuffer, u2BufferLength); ++ ++ prGlP2pInfo->u2WSCIELen[ucType] = u2BufferLength; ++ ++ } while (FALSE); ++ ++} /* kalP2PUpdateWSC_IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief indicate an event to supplicant for device connection request ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, ++ IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ ++ IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_REQ_DEVICE_INFO access */ ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength = u4NameLength > 32 ? 32 : u4NameLength; ++ kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, pucDevName, prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, rPeerAddr); ++ prGlueInfo->prP2PInfo->ucConnReqDevType = ucDevType; ++ prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = i4ConfigMethod; ++ prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod = i4ActiveConfigMethod; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_REQ"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateConnReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for device connection request from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* \param[in] pucGroupBssid Only valid when invitation Type equals to 0. ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_DEVICE_DESC_T prP2pDevDesc, ++ IN PUINT_8 pucSsid, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid) ++{ ++#if 1 ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_STRUCT access */ ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength = ++ (UINT_32) ((prP2pDevDesc->u2NameLength > 32) ? 32 : prP2pDevDesc->u2NameLength); ++ kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, prP2pDevDesc->aucName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, prP2pDevDesc->aucDeviceAddr); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqGroupAddr, pucGroupBssid); ++ prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = (INT_32) (prP2pDevDesc->u2ConfigMethod); ++ prGlueInfo->prP2PInfo->ucOperatingChnl = ucOperatingChnl; ++ prGlueInfo->prP2PInfo->ucInvitationType = ucInvitationType; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_INDICATE"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ return; ++ ++#else ++ P_MSG_P2P_CONNECTION_REQUEST_T prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prGlueInfo != NULL) && (prP2pDevDesc != NULL)); ++ ++ /* Not a real solution */ ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ if (prP2pConnReq == NULL) ++ break; ++ ++ kalMemZero(prP2pConnReq, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ prP2pConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ prP2pConnReq->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; ++ ++ COPY_MAC_ADDR(prP2pConnReq->aucDeviceID, prP2pDevDesc->aucDeviceAddr); ++ ++ prP2pConnReq->u2ConfigMethod = prP2pDevDesc->u2ConfigMethod; ++ ++ if (ucInvitationType == P2P_INVITATION_TYPE_INVITATION) { ++ prP2pConnReq->fgIsPersistentGroup = FALSE; ++ prP2pConnReq->fgIsTobeGO = FALSE; ++ ++ } ++ ++ else if (ucInvitationType == P2P_INVITATION_TYPE_REINVOKE) { ++ DBGLOG(P2P, TRACE, "Re-invoke Persistent Group\n"); ++ prP2pConnReq->fgIsPersistentGroup = TRUE; ++ prP2pConnReq->fgIsTobeGO = (prGlueInfo->prP2PInfo->ucRole == 2) ? TRUE : FALSE; ++ ++ } ++ ++ p2pFsmRunEventDeviceDiscoveryAbort(prGlueInfo->prAdapter, NULL); ++ ++ if (ucOperatingChnl != 0) ++ prP2pSpecificBssInfo->ucPreferredChannel = ucOperatingChnl; ++ ++ if ((ucSsidLen < 32) && (pucSsid != NULL)) ++ COPY_SSID(prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen, pucSsid, ucSsidLen); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pConnReq, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++ /* frog add. */ ++ /* TODO: Invitation Indication */ ++ ++ return; ++#endif ++ ++} /* kalP2PInvitationIndication */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an status to supplicant for device invitation status. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_STRUCT access */ ++ prGlueInfo->prP2PInfo->u4InvStatus = u4InvStatus; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_STATUS"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* kalP2PInvitationStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery request from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_REQ %d", ucSeqNum); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery response ++* from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_RESP %d", ucSeqNum); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery TX Done ++* from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* \param[in] ucSeqNum Sequence number of the frame ++* \param[in] ucStatus Status code for TX ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_XMITTED: %d %d", ucSeqNum, ucStatus); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDResponse() */ ++ ++struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ return prGlueInfo->prP2PInfo->prDevHandler; ++} ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SEC_CHECK_RSP="); ++ ++ kalMemCopy(prGlueInfo->prP2PInfo->aucSecCheckRsp, pucRsp, u2RspLen); ++ evt.data.length = strlen(aucBuffer); ++ ++#if DBG ++ DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u2RspLen); ++#endif ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++} /* p2pFsmRunEventRxDisassociation */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, ++ pucNumOfChannel, paucChannelList); ++} /* kalGetChnlList */ ++ ++/* ////////////////////////////////////ICS SUPPORT////////////////////////////////////// */ ++ ++VOID ++kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8SeqNum, ++ IN UINT_32 u4ChannelNum, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration) ++{ ++ struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; ++ ++ do { ++ if (prGlueInfo == NULL) ++ break; ++ ++ kalMemZero(&rChannelInfo, sizeof(RF_CHANNEL_INFO_T)); ++ ++ rChannelInfo.ucChannelNum = u4ChannelNum; ++ rChannelInfo.eBand = eBand; ++ ++ prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueInfo->prP2PInfo, &rChannelInfo); ++ ++ kalP2pFuncGetChannelType(eSco, &eChnlType); ++ ++ cfg80211_ready_on_channel(prGlueInfo->prP2PInfo->prWdev, /* struct wireless_dev, */ ++ u8SeqNum, /* u64 cookie, */ ++ prIEEE80211ChnlStruct, /* struct ieee80211_channel * chan, */ ++ u4Duration, /* unsigned int duration, */ ++ GFP_KERNEL); /* gfp_t gfp */ /* allocation flags */ ++ } while (FALSE); ++ ++} /* kalP2PIndicateChannelReady */ ++ ++VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; ++ enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; ++ RF_CHANNEL_INFO_T rRfChannelInfo; ++ ++ do { ++ if ((prGlueInfo == NULL) || (prChnlReqInfo == NULL)) { ++ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "kalP2PIndicateChannelExpired\n"); ++ ++ rRfChannelInfo.eBand = prChnlReqInfo->eBand; ++ rRfChannelInfo.ucChannelNum = prChnlReqInfo->ucReqChnlNum; ++ ++ prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueP2pInfo, &rRfChannelInfo); ++ ++ kalP2pFuncGetChannelType(prChnlReqInfo->eChnlSco, &eChnlType); ++ ++ cfg80211_remain_on_channel_expired(prGlueP2pInfo->prWdev, /* struct wireless_dev, */ ++ prChnlReqInfo->u8Cookie, prIEEE80211ChnlStruct, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalP2PIndicateChannelExpired */ ++ ++VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ do { ++ if (prGlueInfo == NULL) { ++ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(INIT, TRACE, "[p2p] scan complete %p\n", prGlueP2pInfo->prScanRequest); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueP2pInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueP2pInfo->prScanRequest; ++ prGlueP2pInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ /* 2. then CFG80211 Indication */ ++ ++ if (prScanRequest != NULL) { ++ ++ /* report all queued beacon/probe response frames to upper layer */ ++ scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_P2P_DEVICE, NULL); ++ ++ info.aborted = fgIsAbort; ++ DBGLOG(INIT, TRACE, "DBG:p2p_cfg_scan_done\n"); ++ cfg80211_scan_done(prScanRequest, &info); ++ } ++ ++ } while (FALSE); ++ ++} /* kalP2PIndicateScanDone */ ++ ++VOID ++kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, ++ IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct ieee80211_channel *prChannelEntry = (struct ieee80211_channel *)NULL; ++ struct ieee80211_mgmt *prBcnProbeRspFrame = (struct ieee80211_mgmt *)pucFrameBuf; ++ struct cfg80211_bss *prCfg80211Bss = (struct cfg80211_bss *)NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (prChannelInfo == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prChannelEntry = kalP2pFuncGetChannelEntry(prGlueP2pInfo, prChannelInfo); ++ ++ if (prChannelEntry == NULL) { ++ DBGLOG(P2P, WARN, "Unknown channel info\n"); ++ break; ++ } ++ /* rChannelInfo.center_freq = nicChannelNum2Freq((UINT_32)prChannelInfo->ucChannelNum) / 1000; */ ++ ++ prCfg80211Bss = cfg80211_inform_bss_frame(prGlueP2pInfo->prWdev->wiphy, /* struct wiphy * wiphy, */ ++ prChannelEntry, ++ prBcnProbeRspFrame, u4BufLen, i4SignalStrength, GFP_KERNEL); ++ ++ /* Return this structure. */ ++ if (!prCfg80211Bss) { ++ DBGLOG(P2P, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", ++ prChannelInfo->ucChannelNum, i4SignalStrength); ++ } else { ++ cfg80211_put_bss(prGlueP2pInfo->prWdev->wiphy, prCfg80211Bss); ++ DBGLOG(P2P, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", ++ prChannelInfo->ucChannelNum, i4SignalStrength); ++ } ++ } while (FALSE); ++ ++} /* kalP2PIndicateBssInfo */ ++ ++VOID ++kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { ++ DBGLOG(P2P, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", ++ prGlueInfo, pucFrameBuf, u4FrameLen); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ cfg80211_mgmt_tx_status(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ ++ u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); ++ ++ } while (FALSE); ++ ++} /* kalP2PIndicateMgmtTxStatus */ ++ ++VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) ++{ ++#define DBG_P2P_MGMT_FRAME_INDICATION 0 ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ INT_32 i4Freq = 0; ++ UINT_8 ucChnlNum = 0; ++#if DBG_P2P_MGMT_FRAME_INDICATION ++ P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; ++#endif ++ ++ do { ++ if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; ++ ++#if DBG_P2P_MGMT_FRAME_INDICATION ++ ++ prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; ++ ++ switch (prWlanHeader->u2FrameCtrl) { ++ case MAC_FRAME_PROBE_REQ: ++ DBGLOG(P2P, TRACE, "RX Probe Req at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(P2P, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_ACTION: ++ DBGLOG(P2P, TRACE, "RX Action frame at channel %d ", ucChnlNum); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "from: %pM\n", prWlanHeader->aucAddr2); ++#endif ++ i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; ++ ++ cfg80211_rx_mgmt(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ ++ i4Freq, ++ RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), ++ prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_ATOMIC); ++ } while (FALSE); ++ ++} /* kalP2PIndicateRxMgmtFrame */ ++ ++VOID ++kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, ++ IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, ++ IN WLAN_STATUS eStatus) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if (prGlueInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prP2pConnInfo) { ++ cfg80211_connect_result(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ ++ prP2pConnInfo->aucBssid, prP2pConnInfo->aucIEBuf, ++ prP2pConnInfo->u4BufLength, ++ pucRxIEBuf, u2RxIELen, u2StatusReason, GFP_KERNEL); ++ /* gfp_t gfp */ /* allocation flags */ ++ prP2pConnInfo->fgIsConnRequest = FALSE; ++ } else { ++ /* Disconnect, what if u2StatusReason == 0? */ ++ cfg80211_disconnected(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ ++ u2StatusReason, pucRxIEBuf, u2RxIELen, ++ eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ? true : false, ++ GFP_KERNEL); ++ } ++ ++ } while (FALSE); ++ ++} /* kalP2PGCIndicateConnectionStatus */ ++ ++VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew) ++{ ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ struct station_info rStationInfo; ++ ++ memset(&rStationInfo, 0, sizeof(struct station_info)); ++ ++ do { ++ if ((prGlueInfo == NULL) || (prCliStaRec == NULL)) ++ break; ++ ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ if (fgIsNew) { ++ //rStationInfo.filled = STATION_INFO_ASSOC_REQ_IES; ++ rStationInfo.generation = ++prP2pGlueInfo->i4Generation; ++ ++ rStationInfo.assoc_req_ies = prCliStaRec->pucAssocReqIe; ++ rStationInfo.assoc_req_ies_len = prCliStaRec->u2AssocReqIeLen; ++/* rStationInfo.filled |= STATION_INFO_ASSOC_REQ_IES; */ ++ ++ cfg80211_new_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ ++ prCliStaRec->aucMacAddr, &rStationInfo, GFP_KERNEL); ++ } else { ++ ++prP2pGlueInfo->i4Generation; ++ ++ cfg80211_del_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ ++ prCliStaRec->aucMacAddr, GFP_KERNEL); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* kalP2PGOStationUpdate */ ++ ++BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type) ++{ ++ BOOLEAN fgIsValid = FALSE; ++ ++ do { ++ if (channel_type) { ++ ++ switch (rChnlSco) { ++ case CHNL_EXT_SCN: ++ *channel_type = NL80211_CHAN_NO_HT; ++ break; ++ case CHNL_EXT_SCA: ++ *channel_type = NL80211_CHAN_HT40MINUS; ++ break; ++ case CHNL_EXT_SCB: ++ *channel_type = NL80211_CHAN_HT40PLUS; ++ break; ++ default: ++ ASSERT(FALSE); ++ *channel_type = NL80211_CHAN_NO_HT; ++ break; ++ } ++ ++ } ++ ++ fgIsValid = TRUE; ++ } while (FALSE); ++ ++ return fgIsValid; ++} /* kalP2pFuncGetChannelType */ ++ ++struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo) ++{ ++ struct ieee80211_channel *prTargetChannelEntry = (struct ieee80211_channel *)NULL; ++ UINT_32 u4TblSize = 0, u4Idx = 0; ++ struct ieee80211_supported_band **bands; ++ ++ do { ++ if ((prP2pInfo == NULL) || (prChannelInfo == NULL)) ++ break; ++ bands = &prP2pInfo->prWdev->wiphy->bands[0]; ++ switch (prChannelInfo->eBand) { ++ case BAND_2G4: ++ prTargetChannelEntry = bands[NL80211_BAND_2GHZ]->channels; ++ u4TblSize = bands[NL80211_BAND_2GHZ]->n_channels; ++ break; ++ case BAND_5G: ++ prTargetChannelEntry = bands[NL80211_BAND_5GHZ]->channels; ++ u4TblSize = bands[NL80211_BAND_5GHZ]->n_channels; ++ break; ++ default: ++ break; ++ } ++ ++ if (prTargetChannelEntry == NULL) ++ break; ++ ++ for (u4Idx = 0; u4Idx < u4TblSize; u4Idx++, prTargetChannelEntry++) { ++ if (prTargetChannelEntry->hw_value == prChannelInfo->ucChannelNum) ++ break; ++ } ++ ++ if (u4Idx == u4TblSize) { ++ prTargetChannelEntry = NULL; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return prTargetChannelEntry; ++} /* kalP2pFuncGetChannelEntry */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the block list of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock) ++{ ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->prP2PInfo); ++ ++ if (EQUAL_MAC_ADDR(rbssid, aucNullAddr)) ++ return -EINVAL; ++ ++ if (fgIsblock) { ++ for (i = 0; i < 8; i++) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ break; ++ } else if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr)) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid); ++ break; ++ } ++ } ++ if (i >= 8) { ++ DBGLOG(P2P, ERROR, "AP black list is full, cannot block more STA!!\n"); ++ return -ENOBUFS; ++ } ++ } else { ++ for (i = 0; i < 8; i++) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr); ++ break; ++ } ++ } ++ if (i >= 8) ++ DBGLOG(P2P, ERROR, "The STA is not found in black list!!\n"); ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to compare the black list of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid) ++{ ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ BOOLEAN fgIsExsit = FALSE; ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->prP2PInfo); ++ ++ for (i = 0; i < 8; i++) { ++ if (UNEQUAL_MAC_ADDR(rbssid, aucNullAddr)) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ fgIsExsit = TRUE; ++ return fgIsExsit; ++ } ++ } ++ } ++ ++ return fgIsExsit; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to return the max clients of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (u4MaxClient == 0 || prGlueInfo->prP2PInfo->ucMaxClients >= P2P_MAXIMUM_CLIENT_COUNT) ++ prGlueInfo->prP2PInfo->ucMaxClients = P2P_MAXIMUM_CLIENT_COUNT; ++ else ++ prGlueInfo->prP2PInfo->ucMaxClients = u4MaxClient; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to return the max clients of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->ucMaxClients) { ++ if ((UINT_8) u4NumClient > prGlueInfo->prP2PInfo->ucMaxClients) ++ return TRUE; ++ else ++ return FALSE; ++ } ++ ++ return FALSE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c +new file mode 100644 +index 000000000000..075045f547b7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c +@@ -0,0 +1,1020 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_proc.c#1 ++*/ ++ ++/*! \file "gl_proc.c" ++ \brief This file defines the interface which can interact with users in /proc fs. ++ ++ Detail description. ++*/ ++ ++/* ++** Log: gl_proc.c ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++** \main\maintrunk.MT5921\19 2008-09-02 21:08:37 GMT mtk01461 ++** Fix the compile error of SPRINTF() ++** \main\maintrunk.MT5921\18 2008-08-10 18:48:28 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\17 2008-08-04 16:52:01 GMT mtk01461 ++** Add proc dbg print message of DOMAIN_INDEX level ++** \main\maintrunk.MT5921\16 2008-07-10 00:45:16 GMT mtk01461 ++** Remove the check of MCR offset, we may use the MCR address which is not align to DW boundary or proprietary usage. ++** \main\maintrunk.MT5921\15 2008-06-03 20:49:44 GMT mtk01461 ++** \main\maintrunk.MT5921\14 2008-06-02 22:56:00 GMT mtk01461 ++** Rename some functions for linux proc ++** \main\maintrunk.MT5921\13 2008-06-02 20:23:18 GMT mtk01461 ++** Revise PROC mcr read / write for supporting TELNET ++** \main\maintrunk.MT5921\12 2008-03-28 10:40:25 GMT mtk01461 ++** Remove temporary set desired rate in linux proc ++** \main\maintrunk.MT5921\11 2008-01-07 15:07:29 GMT mtk01461 ++** Add User Update Desired Rate Set for QA in Linux ++** \main\maintrunk.MT5921\10 2007-12-11 00:11:14 GMT mtk01461 ++** Fix SPIN_LOCK protection ++** \main\maintrunk.MT5921\9 2007-12-04 18:07:57 GMT mtk01461 ++** Add additional debug category to proc ++** \main\maintrunk.MT5921\8 2007-11-02 01:03:23 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\7 2007-10-25 18:08:14 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++** Revision 1.3 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.2 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/* #include "wlan_lib.h" */ ++/* #include "debug.h" */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define PROC_WLAN_THERMO "wlanThermo" ++#define PROC_DRV_STATUS "status" ++#define PROC_RX_STATISTICS "rx_statistics" ++#define PROC_TX_STATISTICS "tx_statistics" ++#define PROC_DBG_LEVEL_NAME "dbgLevel" ++#define PROC_NEED_TX_DONE "TxDoneCfg" ++#define PROC_AUTO_PER_CFG "autoPerCfg" ++#define PROC_ROOT_NAME "wlan" ++#define PROC_CMD_DEBUG_NAME "cmdDebug" ++ ++#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20 ++#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10 ++#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10 ++#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN (20*10) ++#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 8 ++ ++#define PROC_UID_SHELL 2000 ++#define PROC_GID_WIFI 1010 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++/* static UINT_32 u4McrOffset; */ ++#if CFG_SUPPORT_THERMO_THROTTLING ++static P_GLUE_INFO_T g_prGlueInfo_proc; ++#endif ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading MCR register to User Space, the offset of ++* the MCR is specified in u4McrOffset. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++#if 0 ++static int procMCRRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; ++ UINT_32 u4BufLen; ++ char *p = page; ++ UINT_32 u4Count; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); ++ ++ rMcrInfo.u4McrOffset = u4McrOffset; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryMcrRead, ++ (PVOID)&rMcrInfo, sizeof(rMcrInfo), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ /* SPRINTF(p, ("MCR (0x%08lxh): 0x%08lx\n", */ ++ /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData)); */ ++ ++ u4Count = (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procMCRRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for writing MCR register to HW or update u4McrOffset ++* for reading MCR later. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procMCRWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ int i4CopySize; ++ PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(data); ++ ++ i4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, i4CopySize)) ++ return 0; ++ acBuf[i4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 2) { ++ /* NOTE: Sometimes we want to test if bus will still be ok, after accessing ++ * the MCR which is not align to DW boundary. ++ */ ++ /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); ++ ++ u4McrOffset = rMcrInfo.u4McrOffset; ++ ++ /* printk("Write 0x%lx to MCR 0x%04lx\n", */ ++ /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetMcrWrite, ++ (PVOID)&rMcrInfo, sizeof(rMcrInfo), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ ++ if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 1) { ++ /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ ++ u4McrOffset = rMcrInfo.u4McrOffset; ++ } ++ ++ return count; ++ ++} /* end of procMCRWrite() */ ++#endif ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver Status to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procDrvStatusRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("GLUE LAYER STATUS:")); ++ SPRINTF(p, ("\n==================")); ++ ++ SPRINTF(p, ("\n* Number of Pending Frames: %ld\n", prGlueInfo->u4TxPendingFrameNum)); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryDrvStatusForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procDrvStatusRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver RX Statistic Counters to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procRxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("RX STATISTICS (Write 1 to clear):")); ++ SPRINTF(p, ("\n=================================\n")); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryRxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procRxStatisticsRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reset Driver RX Statistic Counters. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procRxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ UINT_32 u4ClearCounter; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ copy_from_user(acBuf, buffer, u4CopySize); ++ acBuf[u4CopySize] = '\0'; ++ ++ if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { ++ if (u4ClearCounter == 1) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidSetRxStatisticsForLinuxProc(prGlueInfo->prAdapter); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ } ++ } ++ ++ return count; ++ ++} /* end of procRxStatisticsWrite() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver TX Statistic Counters to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procTxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("TX STATISTICS (Write 1 to clear):")); ++ SPRINTF(p, ("\n=================================\n")); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryTxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procTxStatisticsRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reset Driver TX Statistic Counters. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procTxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ UINT_32 u4ClearCounter; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ copy_from_user(acBuf, buffer, u4CopySize); ++ acBuf[u4CopySize] = '\0'; ++ ++ if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { ++ if (u4ClearCounter == 1) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidSetTxStatisticsForLinuxProc(prGlueInfo->prAdapter); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ } ++ } ++ ++ return count; ++ ++} /* end of procTxStatisticsWrite() */ ++#endif ++static struct proc_dir_entry *gprProcRoot; ++static UINT_8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = { ++ "INIT", "HAL", "INTR", "REQ", "TX", "RX", "RFTEST", "EMU", "SW1", "SW2", ++ "SW3", "SW4", "HEM", "AIS", "RLM", "MEM", "CNM", "RSN", "BSS", "SCN", ++ "SAA", "AAA", "P2P", "QM", "SEC", "BOW", "WAPI", "ROAMING", "TDLS", "OID", ++ "NIC" ++}; ++static UINT_8 aucProcBuf[1536]; ++static ssize_t procDbgLevelRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ UINT_16 i; ++ UINT_16 u2ModuleNum = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ kalStrCpy(temp, "\nTEMP |LOUD |INFO |TRACE|EVENT|STATE|WARN |ERROR\n" ++ "bit7 |bit6 |bit5 |bit4 |bit3 |bit2 |bit1 |bit0\n\n" ++ "Debug Module\tIndex\tLevel\tDebug Module\tIndex\tLevel\n\n"); ++ temp += kalStrLen(temp); ++ ++ u2ModuleNum = (sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0xfe; ++ for (i = 0; i < u2ModuleNum; i += 2) ++ SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\tDBG_%s_IDX\t(0x%02x):\t0x%02x\n", ++ &aucDbModuleName[i][0], i, aucDebugModule[i], ++ &aucDbModuleName[i+1][0], i+1, aucDebugModule[i+1])); ++ ++ if ((sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0x1) ++ SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\n", ++ &aucDbModuleName[u2ModuleNum][0], u2ModuleNum, aucDebugModule[u2ModuleNum])); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procDbgLevelWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++ UINT_32 u4NewDbgModule, u4NewDbgLevel; ++ UINT_8 i = 0; ++ UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); ++ UINT_8 *temp = &aucProcBuf[0]; ++ ++ if (u4CopySize >= count + 1) ++ u4CopySize = count; ++ ++ kalMemSet(aucProcBuf, 0, u4CopySize); ++ ++ if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { ++ kalPrint("error of copy from user\n"); ++ return -EFAULT; ++ } ++ aucProcBuf[u4CopySize] = '\0'; ++ ++ while (temp) { ++ if (sscanf(temp, "0x%x:0x%x", &u4NewDbgModule, &u4NewDbgLevel) != 2) { ++ kalPrint("debug module and debug level should be one byte in length\n"); ++ break; ++ } ++ if (u4NewDbgModule == 0xFF) { ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = u4NewDbgLevel & DBG_CLASS_MASK; ++ ++ break; ++ } else if (u4NewDbgModule >= DBG_MODULE_NUM) { ++ kalPrint("debug module index should less than %d\n", DBG_MODULE_NUM); ++ break; ++ } ++ aucDebugModule[u4NewDbgModule] = u4NewDbgLevel & DBG_CLASS_MASK; ++ temp = kalStrChr(temp, ','); ++ if (!temp) ++ break; ++ temp++; /* skip ',' */ ++ } ++ return count; ++} ++ ++ ++static const struct file_operations dbglevel_ops = { ++ .owner = THIS_MODULE, ++ .read = procDbgLevelRead, ++ .write = procDbgLevelWrite, ++}; ++ ++static ssize_t procTxDoneCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ UINT_16 u2TxDoneCfg = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ u2TxDoneCfg = StatsGetCfgTxDone(); ++ SPRINTF(temp, ("Tx Done Configure:\nARP %d\tDNS %d\nTCP %d\tUDP %d\nEAPOL %d\tDHCP %d\nICMP %d\n", ++ !!(u2TxDoneCfg & CFG_ARP), !!(u2TxDoneCfg & CFG_DNS), !!(u2TxDoneCfg & CFG_TCP), ++ !!(u2TxDoneCfg & CFG_UDP), !!(u2TxDoneCfg & CFG_EAPOL), !!(u2TxDoneCfg & CFG_DHCP), ++ !!(u2TxDoneCfg & CFG_ICMP))); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procTxDoneCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++#define MODULE_NAME_LENGTH 6 ++ ++ UINT_8 i = 0; ++ UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_16 u2SetTxDoneCfg = 0; ++ UINT_16 u2ClsTxDoneCfg = 0; ++ UINT_8 aucModule[MODULE_NAME_LENGTH]; ++ UINT_32 u4Enabled; ++ UINT_8 aucModuleArray[][MODULE_NAME_LENGTH] = {"ARP", "DNS", "TCP", "UDP", "EAPOL", "DHCP", "ICMP"}; ++ ++ if (u4CopySize >= count + 1) ++ u4CopySize = count; ++ ++ kalMemSet(aucProcBuf, 0, u4CopySize); ++ if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { ++ kalPrint("error of copy from user\n"); ++ return -EFAULT; ++ } ++ aucProcBuf[u4CopySize] = '\0'; ++ temp = &aucProcBuf[0]; ++ while (temp) { ++ /* pick up a string and teminated after meet : */ ++ if (sscanf(temp, "%s %d", aucModule, &u4Enabled) != 2) { ++ kalPrint("read param fail, aucModule=%s\n", aucModule); ++ break; ++ } ++ for (i = 0; i < sizeof(aucModuleArray)/MODULE_NAME_LENGTH; i++) { ++ if (kalStrniCmp(aucModule, aucModuleArray[i], MODULE_NAME_LENGTH) == 0) { ++ if (u4Enabled) ++ u2SetTxDoneCfg |= 1 << i; ++ else ++ u2ClsTxDoneCfg |= 1 << i; ++ break; ++ } ++ } ++ temp = kalStrChr(temp, ','); ++ if (!temp) ++ break; ++ temp++; /* skip ',' */ ++ } ++ if (u2SetTxDoneCfg) ++ StatsSetCfgTxDone(u2SetTxDoneCfg, TRUE); ++ ++ if (u2ClsTxDoneCfg) ++ StatsSetCfgTxDone(u2ClsTxDoneCfg, FALSE); ++ return count; ++} ++ ++static const struct file_operations proc_txdone_ops = { ++ .owner = THIS_MODULE, ++ .read = procTxDoneCfgRead, ++ .write = procTxDoneCfgWrite, ++}; ++ ++static ssize_t procAutoPerCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ SPRINTF(temp, ("Auto Performance Configure:\nperiod\tL1\nL2\tL3\n")); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procAutoPerCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++ DBGLOG(INIT, WARN, "%s\n", __func__); ++ return 0; ++} ++ ++static const struct file_operations auto_per_ops = { ++ .owner = THIS_MODULE, ++ .read = procAutoPerCfgRead, ++ .write = procAutoPerCfgWrite, ++}; ++ ++ ++static ssize_t procCmdDebug(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_32 u4CopySize = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ wlanDumpTcResAndTxedCmd(aucProcBuf, sizeof(aucProcBuf)); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static const struct file_operations proc_CmdDebug_ops = { ++ .owner = THIS_MODULE, ++ .read = procCmdDebug, ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function create a PROC fs in linux /proc/net subdirectory. ++* ++* \param[in] prDev Pointer to the struct net_device. ++* \param[in] pucDevName Pointer to the name of net_device. ++* ++* \return N/A ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++#if CFG_SUPPORT_THERMO_THROTTLING ++ ++/** ++ * This function is called then the /proc file is read ++ * ++ */ ++typedef struct _COEX_BUF1 { ++ UINT8 buffer[128]; ++ INT32 availSize; ++} COEX_BUF1, *P_COEX_BUF1; ++ ++COEX_BUF1 gCoexBuf1; ++ ++static ssize_t procfile_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ ++ INT32 retval = 0; ++ INT32 i_ret = 0; ++ CHAR *warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; ++ ++ if (*f_pos > 0) { ++ retval = 0; ++ } else { ++ /*len = sprintf(page, "%d\n", g_psm_enable); */ ++#if 1 ++ if (gCoexBuf1.availSize <= 0) { ++ DBGLOG(INIT, WARN, "no data available\n"); ++ retval = strlen(warn_msg) + 1; ++ if (count < retval) ++ retval = count; ++ i_ret = copy_to_user(buf, warn_msg, retval); ++ if (i_ret) { ++ DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } else ++#endif ++ { ++ INT32 i = 0; ++ INT32 len = 0; ++ CHAR msg_info[128]; ++ INT32 max_num = 0; ++ /*we do not check page buffer, because there are only 100 bytes in g_coex_buf, no reason page ++ buffer is not enough, a bomb is placed here on unexpected condition */ ++ ++ DBGLOG(INIT, TRACE, "%d bytes available\n", gCoexBuf1.availSize); ++ max_num = ((sizeof(msg_info) > count ? sizeof(msg_info) : count) - 1) / 5; ++ ++ if (max_num > gCoexBuf1.availSize) ++ max_num = gCoexBuf1.availSize; ++ else ++ DBGLOG(INIT, TRACE, ++ "round to %d bytes due to local buffer size limitation\n", max_num); ++ ++ for (i = 0; i < max_num; i++) ++ len += sprintf(msg_info + len, "%d", gCoexBuf1.buffer[i]); ++ ++ len += sprintf(msg_info + len, "\n"); ++ retval = len; ++ ++ i_ret = copy_to_user(buf, msg_info, retval); ++ if (i_ret) { ++ DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } ++ } ++ gCoexBuf1.availSize = 0; ++err_exit: ++ ++ return retval; ++} ++ ++#if 1 ++typedef INT32 (*WLAN_DEV_DBG_FUNC)(void); ++static INT32 wlan_get_thermo_power(void); ++static INT32 wlan_get_link_mode(void); ++ ++static const WLAN_DEV_DBG_FUNC wlan_dev_dbg_func[] = { ++ [0] = wlan_get_thermo_power, ++ [1] = wlan_get_link_mode, ++ ++}; ++ ++INT32 wlan_get_thermo_power(void) ++{ ++ P_ADAPTER_T prAdapter; ++ ++ prAdapter = g_prGlueInfo_proc->prAdapter; ++ ++ if (prAdapter->u4AirDelayTotal > 100) ++ gCoexBuf1.buffer[0] = 100; ++ else ++ gCoexBuf1.buffer[0] = prAdapter->u4AirDelayTotal; ++ gCoexBuf1.availSize = 1; ++ DBGLOG(RLM, TRACE, "PROC %s thrmo_power(%d)\n", __func__, gCoexBuf1.buffer[0]); ++ ++ return 0; ++} ++ ++INT32 wlan_get_link_mode(void) ++{ ++ UINT_8 ucLinkMode = 0; ++ P_ADAPTER_T prAdapter; ++ BOOLEAN fgIsAPmode; ++ ++ prAdapter = g_prGlueInfo_proc->prAdapter; ++ fgIsAPmode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); ++ ++ DBGLOG(RLM, TRACE, "PROC %s AIS(%d)P2P(%d)AP(%d)\n", ++ __func__, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState, fgIsAPmode); ++ ++#if 1 ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ ucLinkMode |= BIT(0); ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ ucLinkMode |= BIT(1); ++ if (fgIsAPmode) ++ ucLinkMode |= BIT(2); ++ ++#endif ++ gCoexBuf1.buffer[0] = ucLinkMode; ++ gCoexBuf1.availSize = 1; ++ ++ return 0; ++} ++ ++static ssize_t procfile_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ char buf[256]; ++ char *pBuf; ++ ULONG len = count; ++ INT32 x = 0, y = 0, z = 0; ++ char *pToken = NULL; ++ char *pDelimiter = " \t"; ++ INT32 i4Ret = 0; ++ ++ if (copy_from_user(gCoexBuf1.buffer, buffer, count)) ++ return -EFAULT; ++ /* gCoexBuf1.availSize = count; */ ++ ++ /* return gCoexBuf1.availSize; */ ++#if 1 ++ DBGLOG(INIT, TRACE, "write parameter len = %d\n\r", (INT32) len); ++ if (len >= sizeof(buf)) { ++ DBGLOG(INIT, ERROR, "input handling fail!\n"); ++ len = sizeof(buf) - 1; ++ return -1; ++ } ++ ++ if (copy_from_user(buf, buffer, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ DBGLOG(INIT, TRACE, "write parameter data = %s\n\r", buf); ++ ++ pBuf = buf; ++ pToken = strsep(&pBuf, pDelimiter); ++ ++ if (pToken) /* x = NULL != pToken ? simple_strtol(pToken, NULL, 16) : 0; */ ++ i4Ret = kalkStrtos32(pToken, 16, &x); ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "x = 0x%x\n", x); ++ ++#if 1 ++ pToken = strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ i4Ret = kalkStrtos32(pToken, 16, &y); /* y = simple_strtol(pToken, NULL, 16); */ ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "y = 0x%08x\n\r", y); ++ } else { ++ y = 3000; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ y = 0x80000000; ++ } ++ ++ pToken = strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ i4Ret = kalkStrtos32(pToken, 16, &z); /* z = simple_strtol(pToken, NULL, 16); */ ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "z = 0x%08x\n\r", z); ++ } else { ++ z = 10; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ z = 0xffffffff; ++ } ++ ++ DBGLOG(INIT, TRACE, " x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++#endif ++ ++ if (((sizeof(wlan_dev_dbg_func) / sizeof(wlan_dev_dbg_func[0])) > x) && NULL != wlan_dev_dbg_func[x]) ++ (*wlan_dev_dbg_func[x]) (); ++ else ++ DBGLOG(INIT, ERROR, "no handler defined for command id(0x%08x)\n\r", x); ++#endif ++ ++ /* len = gCoexBuf1.availSize; */ ++ return len; ++} ++#endif ++ static const struct file_operations proc_fops = { ++ .owner = THIS_MODULE, ++ .read = procfile_read, ++ .write = procfile_write, ++ }; ++#endif ++ ++INT_32 procInitFs(VOID) ++{ ++ struct proc_dir_entry *prEntry; ++ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ kalPrint("init proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ ++ /* ++ * Directory: Root (/proc/net/wlan0) ++ */ ++ ++ gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net); ++ if (!gprProcRoot) { ++ kalPrint("gprProcRoot == NULL\n"); ++ return -ENOENT; ++ } ++ proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_NEED_TX_DONE, 0664, gprProcRoot, &proc_txdone_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_AUTO_PER_CFG, 0664, gprProcRoot, &auto_per_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry autoPerCfg\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ return 0; ++} /* end of procInitProcfs() */ ++ ++INT_32 procUninitProcFs(VOID) ++{ ++ remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot); ++ remove_proc_subtree(PROC_ROOT_NAME, init_net.proc_net); ++ remove_proc_entry(PROC_AUTO_PER_CFG, gprProcRoot); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clean up a PROC fs created by procInitProcfs(). ++* ++* \param[in] prDev Pointer to the struct net_device. ++* \param[in] pucDevName Pointer to the name of net_device. ++* ++* \return N/A ++*/ ++/*----------------------------------------------------------------------------*/ ++INT_32 procRemoveProcfs(VOID) ++{ ++ /* remove root directory (proc/net/wlan0) */ ++ /* remove_proc_entry(pucDevName, init_net.proc_net); */ ++ remove_proc_entry(PROC_WLAN_THERMO, gprProcRoot); ++ remove_proc_entry(PROC_CMD_DEBUG_NAME, gprProcRoot); ++#if CFG_SUPPORT_THERMO_THROTTLING ++ g_prGlueInfo_proc = NULL; ++#endif ++ return 0; ++} /* end of procRemoveProcfs() */ ++ ++INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo) ++{ ++ struct proc_dir_entry *prEntry; ++ ++ DBGLOG(INIT, TRACE, "[%s]\n", __func__); ++ ++#if CFG_SUPPORT_THERMO_THROTTLING ++ g_prGlueInfo_proc = prGlueInfo; ++#endif ++ ++ prGlueInfo->pProcRoot = gprProcRoot; ++ ++ prEntry = proc_create(PROC_WLAN_THERMO, 0664, gprProcRoot, &proc_fops); ++ if (prEntry == NULL) { ++ DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ ++ prEntry = proc_create(PROC_CMD_DEBUG_NAME, 0444, gprProcRoot, &proc_CmdDebug_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +new file mode 100644 +index 000000000000..f97db8a69fd2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +@@ -0,0 +1,228 @@ ++/* ++** Id: @(#) gl_rst.c@@ ++*/ ++ ++/*! \file gl_rst.c ++ \brief Main routines for supporintg MT6620 whole-chip reset mechanism ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_rst.c ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 04 22 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * skip power-off handshaking when RESET indication is received. ++ * ++ * 04 14 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected ++ * 2. add dummy function for both Win32 and Linux part. ++ * ++ * 03 30 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * use netlink unicast instead of broadcast ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++ ++#include "precomp.h" ++#include "gl_rst.h" ++ ++#if CFG_CHIP_RESET_SUPPORT ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++BOOLEAN fgIsResetting = FALSE; ++UINT_32 g_IsNeedDoChipReset = 0; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static RESET_STRUCT_T wifi_rst; ++ ++static void mtk_wifi_reset(struct work_struct *work); ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, ++ ENUM_WMTDRV_TYPE_T eDstType, ++ ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for ++ * 1. register wifi reset callback ++ * 2. initialize wifi reset work ++ * ++ * @param none ++ * ++ * @retval none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glResetInit(VOID) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ /* 1. Register reset callback */ ++ mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_WIFI, (PF_WMT_CB) glResetCallback); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++ /* 2. Initialize reset work */ ++ INIT_WORK(&(wifi_rst.rst_work), mtk_wifi_reset); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for ++ * 1. deregister wifi reset callback ++ * ++ * @param none ++ * ++ * @retval none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glResetUninit(VOID) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ /* 1. Deregister reset callback */ ++ mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_WIFI); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is invoked when there is reset messages indicated ++ * ++ * @param eSrcType ++ * eDstType ++ * eMsgType ++ * prMsgBody ++ * u4MsgLength ++ * ++ * @retval ++ */ ++/*----------------------------------------------------------------------------*/ ++static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, ++ ENUM_WMTDRV_TYPE_T eDstType, ++ ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength) ++{ ++ switch (eMsgType) { ++ case WMTMSG_TYPE_RESET: ++ if (u4MsgLength == sizeof(ENUM_WMTRSTMSG_TYPE_T)) { ++ P_ENUM_WMTRSTMSG_TYPE_T prRstMsg = (P_ENUM_WMTRSTMSG_TYPE_T) prMsgBody; ++ ++ switch (*prRstMsg) { ++ case WMTRSTMSG_RESET_START: ++ DBGLOG(INIT, WARN, "Whole chip reset start!\n"); ++ fgIsResetting = TRUE; ++ wifi_reset_start(); ++ break; ++ ++ case WMTRSTMSG_RESET_END: ++ DBGLOG(INIT, WARN, "Whole chip reset end!\n"); ++ fgIsResetting = FALSE; ++ wifi_rst.rst_data = RESET_SUCCESS; ++ schedule_work(&(wifi_rst.rst_work)); ++ break; ++ ++ case WMTRSTMSG_RESET_END_FAIL: ++ DBGLOG(INIT, WARN, "Whole chip reset fail!\n"); ++ fgIsResetting = FALSE; ++ wifi_rst.rst_data = RESET_FAIL; ++ schedule_work(&(wifi_rst.rst_work)); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for wifi reset ++ * ++ * @param skb ++ * info ++ * ++ * @retval 0 ++ * nonzero ++ */ ++/*----------------------------------------------------------------------------*/ ++static void mtk_wifi_reset(struct work_struct *work) ++{ ++ RESET_STRUCT_T *rst = container_of(work, RESET_STRUCT_T, rst_work); ++ ++ wifi_reset_end(rst->rst_data); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for generating reset request to WMT ++ * ++ * @param None ++ * ++ * @retval None ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glSendResetRequest(VOID) ++{ ++ /* WMT thread would trigger whole chip reset itself */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for checking if connectivity chip is resetting ++ * ++ * @param None ++ * ++ * @retval TRUE ++ * FALSE ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsResetting(VOID) ++{ ++ return fgIsResetting; ++} ++ ++#endif /* CFG_CHIP_RESET_SUPPORT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c +new file mode 100644 +index 000000000000..862d011a43df +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c +@@ -0,0 +1,1220 @@ ++/* ++** Id: @(#) gl_cfg80211.c@@ ++*/ ++ ++/*! \file gl_cfg80211.c ++ \brief Main routines for supporintg MT6620 cfg80211 control interface ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_cfg80211.c ++** ++** 09 05 2013 cp.wu ++** correct length to pass to wlanoidSetBssid() ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 11 23 2012 yuche.tsai ++** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely ++** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++static struct nla_policy nla_parse_policy[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1] = { ++ [GSCAN_ATTRIBUTE_NUM_BUCKETS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BASE_PERIOD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKETS_BAND] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_ID] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_PERIOD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_CHANNELS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_REPORT_THRESHOLD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_REPORT_EVENTS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BSSID] = {.type = NLA_UNSPEC}, ++ [GSCAN_ATTRIBUTE_RSSI_LOW] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_RSSI_HIGH] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_MIN_BREACHING] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_NUM_AP] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_HOTLIST_FLUSH] = {.type = NLA_U8}, ++ [GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH] = {.type = NLA_U8}, ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ struct nlattr *attr; ++ UINT_32 band = 0; ++ UINT_8 ucNumOfChannel, i, j; ++ RF_CHANNEL_INFO_T aucChannelList[64]; ++ UINT_32 num_channels; ++ wifi_channel channels[64]; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy && wdev); ++ if ((data == NULL) || !data_len) ++ return -EINVAL; ++ ++ DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == WIFI_ATTRIBUTE_BAND) ++ band = nla_get_u32(attr); ++ ++ DBGLOG(REQ, INFO, "Get channel list for band: %d\n", band); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (!prGlueInfo) ++ return -EFAULT; ++ ++ if (band == 0) { /* 2.4G band */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, TRUE, ++ 64, &ucNumOfChannel, aucChannelList); ++ } else { /* 5G band */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, TRUE, ++ 64, &ucNumOfChannel, aucChannelList); ++ } ++ ++ kalMemZero(channels, sizeof(channels)); ++ for (i = 0, j = 0; i < ucNumOfChannel; i++) { ++ /* We need to report frequency list to HAL */ ++ channels[j] = nicChannelNum2Freq(aucChannelList[i].ucChannelNum) / 1000; ++ if (channels[j] == 0) ++ continue; ++ else if ((prGlueInfo->prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_TW) && ++ (channels[j] >= 5180 && channels[j] <= 5260)) { ++ /* Taiwan NCC has resolution to follow FCC spec to support 5G Band 1/2/3/4 ++ * (CH36~CH48, CH52~CH64, CH100~CH140, CH149~CH165) ++ * Filter CH36~CH52 for compatible with some old devices. ++ */ ++ continue; ++ } else { ++ DBGLOG(REQ, INFO, "channels[%d] = %d\n", j, channels[j]); ++ j++; ++ } ++ } ++ num_channels = j; ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(channels)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "Allocate skb failed\n"); ++ return -ENOMEM; ++ } ++ ++ if (unlikely(nla_put_u32(skb, WIFI_ATTRIBUTE_NUM_CHANNELS, num_channels) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, WIFI_ATTRIBUTE_CHANNEL_LIST, ++ (sizeof(wifi_channel) * num_channels), channels) < 0)) ++ goto nla_put_failure; ++ ++ return cfg80211_vendor_cmd_reply(skb); ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -EFAULT; ++} ++ ++int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ struct nlattr *attr; ++ UINT_8 country[2] = {0, 0}; ++ ++ ASSERT(wiphy && wdev); ++ if ((data == NULL) || (data_len == 0)) ++ return -EINVAL; ++ ++ DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == WIFI_ATTRIBUTE_COUNTRY_CODE) { ++ country[0] = *((PUINT_8)nla_data(attr)); ++ country[1] = *((PUINT_8)nla_data(attr) + 1); ++ } ++ ++ DBGLOG(REQ, INFO, "Set country code: %c%c\n", country[0], country[1]); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (!prGlueInfo) ++ return -EFAULT; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, country, 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, ++ struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Status = -EINVAL; ++ PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T rGscanCapabilities; ++ struct sk_buff *skb; ++ /* UINT_32 u4BufLen; */ ++ ++ DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rGscanCapabilities)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rGscanCapabilities, sizeof(rGscanCapabilities)); ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rGscanCapabilities, ++ sizeof(rGscanCapabilities), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ rGscanCapabilities.max_scan_cache_size = PSCAN_MAX_SCAN_CACHE_SIZE; ++ rGscanCapabilities.max_scan_buckets = GSCAN_MAX_BUCKETS; ++ rGscanCapabilities.max_ap_cache_per_scan = PSCAN_MAX_AP_CACHE_PER_SCAN; ++ rGscanCapabilities.max_rssi_sample_size = 10; ++ rGscanCapabilities.max_scan_reporting_threshold = GSCAN_MAX_REPORT_THRESHOLD; ++ rGscanCapabilities.max_hotlist_aps = MAX_HOTLIST_APS; ++ rGscanCapabilities.max_significant_wifi_change_aps = MAX_SIGNIFICANT_CHANGE_APS; ++ rGscanCapabilities.max_bssid_history_entries = PSCAN_MAX_AP_CACHE_PER_SCAN * PSCAN_MAX_SCAN_CACHE_SIZE; ++ ++ /* NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0); */ ++ /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_ID, GOOGLE_OUI); */ ++ /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_SUBCMD, GSCAN_SUBCMD_GET_CAPABILITIES); */ ++ /*NLA_PUT(skb, GSCAN_ATTRIBUTE_CAPABILITIES, sizeof(rGscanCapabilities), &rGscanCapabilities);*/ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_CAPABILITIES, ++ sizeof(rGscanCapabilities), &rGscanCapabilities) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ return i4Status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ /* CMD_GSCN_REQ_T rCmdGscnParam; */ ++ ++ /* INT_32 i4Status = -EINVAL; */ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; ++ struct nlattr *attr[GSCAN_ATTRIBUTE_REPORT_EVENTS + 1]; ++ struct nlattr *pbucket, *pchannel; ++ UINT_32 len_basic, len_bucket, len_channel; ++ int i, j, k; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ ++ prWifiScanCmd = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); ++ if (!prWifiScanCmd) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_REPORT_EVENTS + 1)); ++ ++ nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL); ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BASE_PERIOD: ++ prWifiScanCmd->base_period = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_BUCKETS: ++ prWifiScanCmd->num_buckets = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_buckets=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiScanCmd->num_buckets, attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ pbucket = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d pbucket=%p\r\n", len_basic, pbucket); ++ ++ for (i = 0; i < prWifiScanCmd->num_buckets; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)pbucket, ++ nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_bucket = 0; ++ for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BUCKETS_BAND: ++ prWifiScanCmd->buckets[i].band = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_ID: ++ prWifiScanCmd->buckets[i].bucket = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_PERIOD: ++ prWifiScanCmd->buckets[i].period = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_REPORT_EVENTS: ++ prWifiScanCmd->buckets[i].report_events = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: ++ prWifiScanCmd->buckets[i].num_channels = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "bucket%d: attr=0x%x, num_channels=%d nla_len = %d, \r\n", ++ i, *(UINT_32 *) attr[k], nla_get_u32(attr[k]), attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ pbucket = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ DBGLOG(REQ, TRACE, "+++pure bucket size=%d pbucket=%p \r\n", len_bucket, pbucket); ++ pbucket = (struct nlattr *)((UINT_8 *) pbucket + len_bucket); ++ /* pure bucket payload, not include channels */ ++ ++ /*don't need to use nla_parse_nested to parse channels */ ++ /* the header of channel in bucket i */ ++ pchannel = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); ++ for (j = 0; j < prWifiScanCmd->buckets[i].num_channels; j++) { ++ prWifiScanCmd->buckets[i].channels[j].channel = nla_get_u32(pchannel); ++ len_channel = NLA_ALIGN(pchannel->nla_len); ++ DBGLOG(REQ, TRACE, ++ "attr=0x%x, channel=%d, \r\n", *(UINT_32 *) pchannel, nla_get_u32(pchannel)); ++ ++ pchannel = (struct nlattr *)((UINT_8 *) pchannel + len_channel); ++ } ++ pbucket = pchannel; ++ } ++ ++ DBGLOG(REQ, TRACE, "base_period=%d, num_buckets=%d, bucket0: %d %d %d %d", ++ prWifiScanCmd->base_period, prWifiScanCmd->num_buckets, ++ prWifiScanCmd->buckets[0].bucket, prWifiScanCmd->buckets[0].period, ++ prWifiScanCmd->buckets[0].band, prWifiScanCmd->buckets[0].report_events); ++ ++ DBGLOG(REQ, TRACE, "num_channels=%d, channel0=%d, channel1=%d; num_channels=%d, channel0=%d, channel1=%d", ++ prWifiScanCmd->buckets[0].num_channels, ++ prWifiScanCmd->buckets[0].channels[0].channel, prWifiScanCmd->buckets[0].channels[1].channel, ++ prWifiScanCmd->buckets[1].num_channels, ++ prWifiScanCmd->buckets[1].channels[0].channel, prWifiScanCmd->buckets[1].channels[1].channel); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAParam, ++ prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiScanCmd != NULL) ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ INT_32 i4Status = -EINVAL; ++ /*PARAM_WIFI_GSCAN_CMD_PARAMS rWifiScanCmd;*/ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; ++ struct nlattr *attr[GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1]; ++ /* UINT_32 num_scans = 0; */ /* another attribute */ ++ int k; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ /*kalMemZero(&rWifiScanCmd, sizeof(rWifiScanCmd));*/ ++ prWifiScanCmd = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); ++ if (prWifiScanCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, ++ (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ for (k = GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN; k <= GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: ++ prWifiScanCmd->max_ap_per_scan = nla_get_u32(attr[k]); ++ break; ++ case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: ++ prWifiScanCmd->report_threshold = nla_get_u32(attr[k]); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: ++ prWifiScanCmd->num_scans = nla_get_u32(attr[k]); ++ break; ++ } ++ } ++ } ++ DBGLOG(REQ, TRACE, "attr=0x%x, attr2=0x%x ", *(UINT_32 *) attr[GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN], ++ *(UINT_32 *) attr[GSCAN_ATTRIBUTE_REPORT_THRESHOLD]); ++ ++ DBGLOG(REQ, TRACE, "max_ap_per_scan=%d, report_threshold=%d num_scans=%d \r\n", ++ prWifiScanCmd->max_ap_per_scan, prWifiScanCmd->report_threshold, prWifiScanCmd->num_scans); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAConfig, ++ prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiScanCmd != NULL) ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ P_PARAM_WIFI_SIGNIFICANT_CHANGE prWifiChangeCmd = NULL; ++ UINT_8 flush = 0; ++ /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ ++ struct nlattr **attr = NULL; ++ struct nlattr *paplist; ++ int i, k; ++ UINT_32 len_basic, len_aplist; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 6; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", ++ *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), ++ *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); ++ prWifiChangeCmd = kalMemAlloc(sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE), VIR_MEM_TYPE); ++ if (prWifiChangeCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiChangeCmd, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); ++ if (attr == NULL) ++ goto nla_put_failure; ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, ++ (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE; k <= GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: ++ prWifiChangeCmd->rssi_sample_size = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: ++ prWifiChangeCmd->lost_ap_sample_size = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_MIN_BREACHING: ++ prWifiChangeCmd->min_breaching = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_AP: ++ prWifiChangeCmd->num_ap = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiChangeCmd->num_ap, attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: ++ flush = nla_get_u8(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ paplist = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); ++ ++ if (paplist->nla_type == GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS) ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ ++ for (i = 0; i < prWifiChangeCmd->num_ap; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ len_aplist = 0; ++ for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BSSID: ++ kalMemCopy(prWifiChangeCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_LOW: ++ prWifiChangeCmd->ap[i].low = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_HIGH: ++ prWifiChangeCmd->ap[i].high = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ if (((i + 1) % 4 == 0) || (i == prWifiChangeCmd->num_ap - 1)) ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); ++ else ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); ++ paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); ++ } ++ ++ DBGLOG(REQ, TRACE, ++ "flush=%d, rssi_sample_size=%d lost_ap_sample_size=%d min_breaching=%d", ++ flush, prWifiChangeCmd->rssi_sample_size, prWifiChangeCmd->lost_ap_sample_size, ++ prWifiChangeCmd->min_breaching); ++ DBGLOG(REQ, TRACE, ++ "ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", ++ prWifiChangeCmd->ap[0].channel, prWifiChangeCmd->ap[0].low, prWifiChangeCmd->ap[0].high, ++ prWifiChangeCmd->ap[1].channel, prWifiChangeCmd->ap[1].low, prWifiChangeCmd->ap[1].high); ++ kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiChangeCmd) ++ kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ if (attr) ++ kalMemFree(attr, VIR_MEM_TYPE, ++ sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ /*WLAN_STATUS rStatus;*/ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; ++ ++ INT_32 i4Status = -EINVAL; ++ P_PARAM_WIFI_BSSID_HOTLIST prWifiHotlistCmd = NULL; ++ UINT_8 flush = 0; ++ /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ ++ struct nlattr **attr = NULL; ++ struct nlattr *paplist; ++ int i, k; ++ UINT_32 len_basic, len_aplist; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 5; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", ++ *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), ++ *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); ++ prWifiHotlistCmd = kalMemAlloc(sizeof(PARAM_WIFI_BSSID_HOTLIST), VIR_MEM_TYPE); ++ if (prWifiHotlistCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiHotlistCmd, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); ++ if (attr == NULL) ++ goto nla_put_failure; ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_AP, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_HOTLIST_FLUSH; k <= GSCAN_ATTRIBUTE_NUM_AP; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: ++ prWifiHotlistCmd->lost_ap_sample_size = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_AP: ++ prWifiHotlistCmd->num_ap = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiHotlistCmd->num_ap, attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: ++ flush = nla_get_u8(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ paplist = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); ++ ++ if (paplist->nla_type == GSCAN_ATTRIBUTE_HOTLIST_BSSIDS) ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ ++ for (i = 0; i < prWifiHotlistCmd->num_ap; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ len_aplist = 0; ++ for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BSSID: ++ kalMemCopy(prWifiHotlistCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_LOW: ++ prWifiHotlistCmd->ap[i].low = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_HIGH: ++ prWifiHotlistCmd->ap[i].high = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ if (((i + 1) % 4 == 0) || (i == prWifiHotlistCmd->num_ap - 1)) ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); ++ else ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); ++ paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); ++ } ++ ++ DBGLOG(REQ, TRACE, ++ "flush=%d, lost_ap_sample_size=%d, Hotlist:ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", ++ flush, prWifiHotlistCmd->lost_ap_sample_size, ++ prWifiHotlistCmd->ap[0].channel, prWifiHotlistCmd->ap[0].low, prWifiHotlistCmd->ap[0].high, ++ prWifiHotlistCmd->ap[1].channel, prWifiHotlistCmd->ap[1].low, prWifiHotlistCmd->ap[1].high); ++ ++ memcpy(&(rCmdPscnAddHotlist.aucMacAddr), &(prWifiHotlistCmd->ap[0].bssid), 6 * sizeof(UINT_8)); ++ rCmdPscnAddHotlist.ucFlags = (UINT_8) TRUE; ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiHotlistCmd) ++ kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ if (attr) ++ kalMemFree(attr, VIR_MEM_TYPE, ++ sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS rWifiScanActionCmd; ++ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_8 gGScanEn = 0; ++ ++ static UINT_8 k; /* only for test */ ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", ++ __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) ++ gGScanEn = nla_get_u32(attr); ++ DBGLOG(REQ, INFO, "gGScanEn=%d, \r\n", gGScanEn); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ if (gGScanEn == TRUE) ++ rWifiScanActionCmd.ucPscanAct = ENABLE; ++ else ++ rWifiScanActionCmd.ucPscanAct = DISABLE; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAction, ++ &rWifiScanActionCmd, ++ sizeof(PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ /* mtk_cfg80211_vendor_get_scan_results(wiphy, wdev, data, data_len ); */ ++ ++ return 0; ++ ++ /* only for test */ ++ if (k % 3 == 1) { ++ mtk_cfg80211_vendor_event_significant_change_results(wiphy, wdev, NULL, 0); ++ mtk_cfg80211_vendor_event_hotlist_ap_found(wiphy, wdev, NULL, 0); ++ mtk_cfg80211_vendor_event_hotlist_ap_lost(wiphy, wdev, NULL, 0); ++ } ++ k++; ++ ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_8 gFullScanResultsEn = 0; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", ++ __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ENABLE_FULL_SCAN_RESULTS) ++ gFullScanResultsEn = nla_get_u32(attr); ++ DBGLOG(REQ, INFO, "gFullScanResultsEn=%d, \r\n", gFullScanResultsEn); ++ ++ return 0; ++ ++ /* only for test */ ++ mtk_cfg80211_vendor_event_complete_scan(wiphy, wdev, WIFI_SCAN_COMPLETE); ++ mtk_cfg80211_vendor_event_scan_results_available(wiphy, wdev, 4); ++ if (gFullScanResultsEn == TRUE) ++ mtk_cfg80211_vendor_event_full_scan_results(wiphy, wdev, NULL, 0); ++ ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ /*WLAN_STATUS rStatus;*/ ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_WIFI_GSCAN_GET_RESULT_PARAMS rGSscnResultParm; ++ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_32 get_num = 0, real_num = 0; ++ UINT_8 flush = 0; ++ /*PARAM_WIFI_GSCAN_RESULT result[4], *pResult; ++ struct sk_buff *skb;*/ ++ int i; /*int j;*/ ++ /*UINT_32 scan_id;*/ ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, TRACE, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 2; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", *((UINT_32 *) data + i * 4), ++ *((UINT_32 *) data + i * 4 + 1), *((UINT_32 *) data + i * 4 + 2), ++ *((UINT_32 *) data + i * 4 + 3)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { ++ get_num = nla_get_u32(attr); ++ attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); ++ } ++ if (attr->nla_type == GSCAN_ATTRIBUTE_FLUSH_RESULTS) { ++ flush = nla_get_u8(attr); ++ attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); ++ } ++ DBGLOG(REQ, TRACE, "number=%d, flush=%d \r\n", get_num, flush); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ real_num = (get_num < PSCAN_MAX_SCAN_CACHE_SIZE) ? get_num : PSCAN_MAX_SCAN_CACHE_SIZE; ++ get_num = real_num; ++ ++#if 0 /* driver buffer FW results and reports by buffer workaround for FW mismatch with hal results numbers */ ++ g_GetResultsCmdCnt++; ++ DBGLOG(REQ, INFO, ++ "(g_GetResultsCmdCnt [%d], g_GetResultsBufferedCnt [%d]\n", g_GetResultsCmdCnt, ++ g_GetResultsBufferedCnt); ++ ++ BOOLEAN fgIsGetResultFromBuffer = FALSE; ++ UINT_8 BufferedResultReportIndex = 0; ++ ++ if (g_GetResultsBufferedCnt > 0) { ++ ++ DBGLOG(REQ, INFO, ++ "(g_GetResultsBufferedCnt > 0), report buffered results instead of ask from FW\n"); ++ ++ /* reply the results to wifi_hal */ ++ for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { ++ ++ if (g_arGscanResultsIndicateNumber[i] > 0) { ++ real_num = g_arGscanResultsIndicateNumber[i]; ++ get_num = real_num; ++ g_arGscanResultsIndicateNumber[i] = 0; ++ fgIsGetResultFromBuffer = TRUE; ++ BufferedResultReportIndex = i; ++ break; ++ } ++ } ++ if (i == MAX_BUFFERED_GSCN_RESULTS) ++ DBGLOG(REQ, TRACE, "all buffered results are invalid, unexpected case \r\n"); ++ DBGLOG(REQ, TRACE, "BufferedResultReportIndex[%d] i = %d real_num[%d] get_num[%d] \r\n", ++ BufferedResultReportIndex, i, real_num, get_num); ++ } ++#endif ++ ++ rGSscnResultParm.get_num = get_num; ++ rGSscnResultParm.flush = flush; ++#if 0/* //driver buffer FW results and reports by buffer workaround for FW results mismatch with hal results number */ ++ if (fgIsGetResultFromBuffer) { ++ nicRxProcessGSCNEvent(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); ++ g_GetResultsBufferedCnt--; ++ g_GetResultsCmdCnt--; ++ nicRxReturnRFB(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); ++ } else ++#endif ++ { ++ kalIoctl(prGlueInfo, ++ wlanoidGetGSCNResult, ++ &rGSscnResultParm, ++ sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, ++ struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Status = -EINVAL; ++ PARAM_WIFI_RTT_CAPABILITIES rRttCapabilities; ++ struct sk_buff *skb; ++ ++ DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rRttCapabilities)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rRttCapabilities, sizeof(rRttCapabilities)); ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rRttCapabilities, ++ sizeof(rRttCapabilities), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ rRttCapabilities.rtt_one_sided_supported = 0; ++ rRttCapabilities.rtt_ftm_supported = 0; ++ rRttCapabilities.lci_support = 0; ++ rRttCapabilities.lcr_support = 0; ++ rRttCapabilities.preamble_support = 0; ++ rRttCapabilities.bw_support = 0; ++ ++ if (unlikely(nla_put(skb, RTT_ATTRIBUTE_CAPABILITIES, ++ sizeof(rRttCapabilities), &rRttCapabilities) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ return i4Status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ WIFI_RADIO_STAT *pRadioStat; ++ struct sk_buff *skb; ++ UINT_32 u4BufLen; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ u4BufLen = sizeof(WIFI_RADIO_STAT) + sizeof(WIFI_IFACE_STAT); ++ pRadioStat = kalMemAlloc(u4BufLen, VIR_MEM_TYPE); ++ if (!pRadioStat) { ++ DBGLOG(REQ, ERROR, "%s kalMemAlloc pRadioStat failed\n", __func__); ++ return -ENOMEM; ++ } ++ kalMemZero(pRadioStat, u4BufLen); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, u4BufLen); ++ if (!skb) { ++ DBGLOG(REQ, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rRadioStat, ++ sizeof(rRadioStat), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ /* only for test */ ++ pRadioStat->radio = 10; ++ pRadioStat->on_time = 11; ++ pRadioStat->tx_time = 12; ++ pRadioStat->num_channels = 4; ++ ++ /*NLA_PUT(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat);*/ ++ if (unlikely(nla_put(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ kalMemFree(pRadioStat, VIR_MEM_TYPE, u4BufLen); ++ return -1; /* not support LLS now*/ ++ /* return i4Status; */ ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete) ++{ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ /* WIFI_SCAN_EVENT complete_scan; */ ++ ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(complete), GSCAN_EVENT_COMPLETE_SCAN, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ /* complete_scan = WIFI_SCAN_COMPLETE; */ ++ /*NLA_PUT_U32(skb, GSCAN_EVENT_COMPLETE_SCAN, complete);*/ ++ { ++ unsigned int __tmp = complete; ++ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_COMPLETE_SCAN, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num) ++{ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ /* UINT_32 scan_result; */ ++ ++ DBGLOG(REQ, INFO, "%s for vendor command %d \r\n", __func__, num); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(num), GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ /* scan_result = 2; */ ++ /*NLA_PUT_U32(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, num);*/ ++ { ++ unsigned int __tmp = num; ++ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(result), GSCAN_EVENT_FULL_SCAN_RESULTS, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&result, sizeof(result)); ++ kalMemCopy(result.ssid, "Gscan_full_test", sizeof("Gscan_full_test")); ++ result.channel = 2437; ++ ++ /* kalMemCopy(&result, pdata, sizeof(PARAM_WIFI_GSCAN_RESULT); */ ++ /*NLA_PUT(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, sizeof(result), &result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, ++ sizeof(result), &result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_CHANGE_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_CHANGE_RESULT), ++ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "213123", sizeof(mac_addr)); ++ presult->channel = 2437; ++ presult->rssi[0] = -45; ++ presult->rssi[1] = -46; ++ presult++; ++ presult->channel = 2439; ++ presult->rssi[0] = -47; ++ presult->rssi[1] = -48; ++ /*NLA_PUT(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, ++ (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), ++ GSCAN_EVENT_HOTLIST_RESULTS_FOUND, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "123123", sizeof(mac_addr)); ++ presult->channel = 2441; ++ presult->rssi = -45; ++ presult++; ++ presult->channel = 2443; ++ presult->rssi = -47; ++ /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, ++ (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), ++ GSCAN_EVENT_HOTLIST_RESULTS_LOST, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "321321", sizeof(mac_addr)); ++ presult->channel = 2445; ++ presult->rssi = -46; ++ presult++; ++ presult->channel = 2447; ++ presult->rssi = -48; ++ /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, ++ (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c +new file mode 100644 +index 000000000000..1793742e9802 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c +@@ -0,0 +1,4158 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext.c#3 ++*/ ++ ++/*! \file gl_wext.c ++ \brief ioctl() (mostly Linux Wireless Extensions) routines for STA driver. ++*/ ++ ++/* ++** Log: gl_wext.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 23 2011 tsaiyuan.hsu ++ * [WCXRP00000979] [MT6620 Wi-Fi][DRV]] stop attempting to connect to config AP after D3 state ++ * avoid entering D3 state after deep sleep. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 27 2011 wh.su ++ * [WCXRP00000877] [MT6620 Wi-Fi][Driver] Remove the netif_carry_ok check for avoid the wpa_supplicant fail to query ++ * the ap address ++ * Remove the netif check while query bssid and ssid ++ * ++ * 07 26 2011 chinglan.wang ++ * NULL ++ * [MT6620][WiFi Driver] Do not include the WSC IE in the association info packet when not do the wps connection.. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 17 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Initialize the vairlabes. ++ * ++ * 05 11 2011 jeffrey.chang ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * modify set_tx_pow ioctl ++ * ++ * 03 29 2011 terry.wu ++ * [WCXRP00000610] [MT 6620 Wi-Fi][Driver] Fix klocwork waring ++ * [MT6620 Wi-Fi][Driver] Fix klocwork warning. Add Null pointer check on wext_get_essid. Limit the upper bound of ++ * essid storage array. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 02 21 2011 wh.su ++ * [WCXRP00000483] [MT6620 Wi-Fi][Driver] Check the kalIoctl return value before doing the memory copy at linux get ++ * essid ++ * fixed the potential error to do a larget memory copy while wlanoid get essid not actually running. ++ * ++ * 02 08 2011 george.huang ++ * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler ++ * Support querying power mode OID. ++ * ++ * 01 29 2011 wh.su ++ * [WCXRP00000408] [MT6620 Wi-Fi][Driver] Not doing memory alloc while ioctl set ie with length 0 ++ * not doing mem alloc. while set ie length already 0 ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Remove debug text. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Adjust OID order. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish ++ * successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. . ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous types ++ * to ease slab system pressure ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Support set PS profile and set WMM-PS related iwpriv. ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Allow change PS profile function (through wext_set_power()). ++ * ++ * 12 14 2010 jeffrey.chang ++ * [WCXRP00000262] [MT6620 Wi-Fi][Driver] modify the scan request ioctl to handle hidden SSID ++ * handle hidden SSID ++ * ++ * 12 13 2010 chinglan.wang ++ * NULL ++ * Add WPS 1.0 feature flag to enable the WPS 1.0 function. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * Fix compiling error ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 30 2010 cp.wu ++ * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 ++ * . ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000121] [MT6620 Wi-Fi][Driver] Temporarily disable set power mode ioctl which may cause 6620 to enter power ++ * saving ++ * Temporarily disable set power mode ioctl which may cause MT6620 to enter power saving ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue ++ * refine the scan ioctl to prevent hanging of Android UI ++ * ++ * 10 01 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * add the scan result with wapi ie. ++ * ++ * 09 30 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * fixed the wapi ie assigned issue. ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * enable remove key ioctl ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) enable encyption ioctls ++ * 2) temporarily disable remove keys ioctl to prevent TX1 busy ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * for linux driver migration ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove unused macro and debug messages ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add dissassoication support for wpa supplicant ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add ioctl of power management ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug message ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used ++ * * 2) fix ioctl ++ * ++ * 04 12 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug messages for pre-release ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * are done in adapter layer. ++ * ++ * 04 02 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl type ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * enable pmksa cache operation ++ * ++ * 03 31 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl which may cause cmdinfo memory leak ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\38 2009-10-08 10:33:22 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). ++** Add more checking for input parameters and pointers. ++** \main\maintrunk.MT5921\37 2009-09-29 16:49:48 GMT mtk01090 ++** Remove unused variables ++** \main\maintrunk.MT5921\36 2009-09-28 20:19:11 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\35 2009-09-03 11:42:30 GMT mtk01088 ++** adding the wapi ioctl support ++** \main\maintrunk.MT5921\34 2009-08-18 22:56:50 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\33 2009-05-14 22:43:47 GMT mtk01089 ++** fix compiling warning ++** \main\maintrunk.MT5921\32 2009-05-07 22:26:18 GMT mtk01089 ++** Add mandatory and private IO control for Linux BWCS ++** \main\maintrunk.MT5921\31 2009-02-07 15:11:14 GMT mtk01088 ++** fixed the compiling error ++** \main\maintrunk.MT5921\30 2009-02-07 14:46:51 GMT mtk01088 ++** add the privacy setting from linux supplicant ap selection ++** \main\maintrunk.MT5921\29 2008-11-19 15:18:50 GMT mtk01088 ++** fixed the compling error ++** \main\maintrunk.MT5921\28 2008-11-19 11:56:18 GMT mtk01088 ++** rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\27 2008-08-29 16:59:43 GMT mtk01088 ++** fixed compiling error ++** \main\maintrunk.MT5921\26 2008-08-29 14:55:53 GMT mtk01088 ++** adjust the code for meet the coding style, and add assert check ++** \main\maintrunk.MT5921\25 2008-06-02 11:15:19 GMT mtk01461 ++** Update after wlanoidSetPowerMode changed ++** \main\maintrunk.MT5921\24 2008-05-30 15:13:12 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\23 2008-03-28 10:40:28 GMT mtk01461 ++** Add set desired rate in Linux STD IOCTL ++** \main\maintrunk.MT5921\22 2008-03-18 10:31:24 GMT mtk01088 ++** add pmkid ioctl and indicate ++** \main\maintrunk.MT5921\21 2008-03-11 15:21:24 GMT mtk01461 ++** \main\maintrunk.MT5921\20 2008-03-11 14:50:55 GMT mtk01461 ++** Refine WPS related priv ioctl for unified interface ++** ++** \main\maintrunk.MT5921\19 2008-03-06 16:30:41 GMT mtk01088 ++** move the configuration code from set essid function, ++** remove the non-used code ++** \main\maintrunk.MT5921\18 2008-02-21 15:47:09 GMT mtk01461 ++** Fix CR[489] ++** \main\maintrunk.MT5921\17 2008-02-12 23:38:31 GMT mtk01461 ++** Add Set Frequency & Channel oid support for Linux ++** \main\maintrunk.MT5921\16 2008-01-24 12:07:34 GMT mtk01461 ++** \main\maintrunk.MT5921\15 2008-01-24 12:00:10 GMT mtk01461 ++** Modify the wext_essid for set up correct information for IBSS, and fix the wrong input ptr for prAdapter ++** \main\maintrunk.MT5921\14 2007-12-06 09:30:12 GMT mtk01425 ++** 1. Branch Test ++** \main\maintrunk.MT5921\13 2007-12-04 18:07:59 GMT mtk01461 ++** fix typo ++** \main\maintrunk.MT5921\12 2007-11-30 17:10:21 GMT mtk01425 ++** 1. Fix compiling erros ++** ++** \main\maintrunk.MT5921\11 2007-11-27 10:43:22 GMT mtk01425 ++** 1. Add WMM-PS setting ++** \main\maintrunk.MT5921\10 2007-11-06 20:33:32 GMT mtk01088 ++** fixed the compiler error ++** \main\maintrunk.MT5921\9 2007-11-06 19:33:15 GMT mtk01088 ++** add WPS code ++** \main\maintrunk.MT5921\8 2007-10-30 12:00:44 GMT MTK01425 ++** 1. Update wlanQueryInformation ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_os.h" ++ ++#include "config.h" ++#include "wlan_oid.h" ++ ++#include "gl_wext.h" ++#include "gl_wext_priv.h" ++ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_WAPI ++#include "gl_sec.h" ++#endif ++ ++/* compatibility to wireless extensions */ ++#ifdef WIRELESS_EXT ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++const long channel_freq[] = { ++ 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 ++}; ++ ++ ++#define NUM_CHANNELS (sizeof(channel_freq) / sizeof(channel_freq[0])) ++ ++#define MAX_SSID_LEN 32 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/* NOTE: name in iwpriv_args only have 16 bytes */ ++static const struct iw_priv_args rIwPrivTable[] = { ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, ""}, ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, ""}, ++ ++ {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ ++ {IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_CHAR | 16, ""}, ++ ++ {IOCTL_SET_STRING, IW_PRIV_TYPE_CHAR | 256, 0, ""}, ++ ++ /* added for set_oid and get_oid */ ++ {IOCTL_SET_STRUCT, 256, 0, ""}, ++ {IOCTL_GET_STRUCT, 0, 256, ""}, ++ ++ /* sub-ioctl definitions */ ++#if 0 ++ {PRIV_CMD_REG_DOMAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_reg_domain"}, ++ {PRIV_CMD_REG_DOMAIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_reg_domain"}, ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ {PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_tcp_csum"}, ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ {PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power_mode"}, ++ {PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_power_mode"}, ++ ++ {PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_wmm_ps"}, ++ ++ {PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_test_mode"}, ++ {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_test_cmd"}, ++ {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_test_result"}, ++#if CFG_SUPPORT_PRIV_MCR_RW ++ {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_mcr"}, ++ {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_mcr"}, ++#endif ++ {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_sw_ctrl"}, ++ {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_sw_ctrl"}, ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_bwcs"}, ++ /* GET STRUCT sub-ioctls commands */ ++ {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_bwcs"}, ++#endif ++ ++ /* SET STRUCT sub-ioctls commands */ ++ {PRIV_CMD_OID, 256, 0, "set_oid"}, ++ /* GET STRUCT sub-ioctls commands */ ++ {PRIV_CMD_OID, 0, 256, "get_oid"}, ++ ++ {PRIV_CMD_BAND_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_band"}, ++ {PRIV_CMD_BAND_CONFIG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_band"}, ++ ++ {PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower"}, ++ {PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list"}, ++ {PRIV_CMD_DUMP_MEM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_mem"}, ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ {PRIV_CMD_P2P_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_p2p_mode"}, ++#endif ++ {PRIV_CMD_GET_BUILD_DATE_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_date_code"}, ++ {PRIV_CMD_GET_DEBUG_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_dbg_code"}, ++ /* handle any command with many input parameters */ ++ {PRIV_CMD_OTHER, IW_PRIV_TYPE_CHAR | 256, 0, "set_str_cmd"}, ++ ++ {PRIV_CMD_WFD_DEBUG_CODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_wfd_dbg_code"}, ++}; ++ ++static const iw_handler rIwPrivHandler[] = { ++ [IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int, ++ [IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int, ++ [IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_STRUCT - SIOCIWFIRSTPRIV] = priv_set_struct, ++ [IOCTL_GET_STRUCT - SIOCIWFIRSTPRIV] = priv_get_struct, ++ [IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct, ++ [IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints, ++ [IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints, ++ [IOCTL_SET_STRING - SIOCIWFIRSTPRIV] = priv_set_string, ++}; ++ ++const struct iw_handler_def wext_handler_def = { ++ .num_standard = 0, ++ .num_private = (__u16) sizeof(rIwPrivHandler) / sizeof(iw_handler), ++ .num_private_args = (__u16) sizeof(rIwPrivTable) / sizeof(struct iw_priv_args), ++ .standard = (iw_handler *) NULL, ++ .private = rIwPrivHandler, ++ .private_args = rIwPrivTable, ++ .get_wireless_stats = wext_get_wireless_stats, ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WPA/RSN Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { ++ if (ucDesiredElemId != 0xDD) { ++ /* Non 0xDD, OK! */ ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ /* EID == 0xDD, check WPA IE */ ++ if (pucIEStart[1] >= 4) { ++ if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } /* check WPA IE length */ ++ /* check EID == 0xDD */ ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* parseSearchDesiredWPAIE */ ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WAPI Information Element . ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_WAPI && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredWAPIIE */ ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired HS2.0 Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredHS20IE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { ++ if (pucCurIE[1] >= ELEM_MIN_LEN_HS20_INDICATION) { ++ if (memcmp(&pucCurIE[2], "\x50\x6f\x9a\x10", 4) == 0) ++ return TRUE; ++ } ++ } ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredHS20IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired interworking Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredInterworkingIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { ++ switch (pucCurIE[1]) { ++ case IW_IE_LENGTH_ANO: ++ case IW_IE_LENGTH_ANO_HESSID: ++ case IW_IE_LENGTH_ANO_VENUE: ++ case IW_IE_LENGTH_ANO_VENUE_HESSID: ++ return TRUE; ++ ++ default: ++ break; ++ } ++ ++ } ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredInterworkingIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired Adv Protocol Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredAdvProtocolIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) ++ return TRUE; ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredAdvProtocolIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired Roaming Consortium Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredRoamingConsortiumIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) ++ return TRUE; ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredRoamingConsortiumIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired HS2.0 Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { ++ if (pucIEStart[1] >= ELEM_MIN_LEN_HS20_INDICATION) { ++ if (memcmp(&pucIEStart[2], "\x50\x6f\x9a\x10", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredHS20IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired interworking Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredInterworkingIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired Adv Protocol Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredAdvProtocolIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired Roaming Consortium Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredRoamingConsortiumIE */ ++#endif ++ ++#if CFG_SUPPORT_WPS ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WPS Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { ++ if (ucDesiredElemId != 0xDD) { ++ /* Non 0xDD, OK! */ ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ /* EID == 0xDD, check WPS IE */ ++ if (pucIEStart[1] >= 4) { ++ if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } /* check WPS IE length */ ++ /* check EID == 0xDD */ ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* parseSearchDesiredWPSIE */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the name of the protocol used on the air. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] pcName Buffer to store protocol name string ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* ++* \note If netif_carrier_ok, protocol name is returned; ++* otherwise, "disconnected" is returned. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_name(IN struct net_device *prNetDev, IN struct iw_request_info *prIwrInfo, OUT char *pcName, IN char *pcExtra) ++{ ++ ENUM_PARAM_NETWORK_TYPE_T eNetWorkType = PARAM_NETWORK_TYPE_NUM; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcName); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcName)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (netif_carrier_ok(prNetDev)) { ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryNetworkTypeInUse, ++ &eNetWorkType, sizeof(eNetWorkType), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eNetWorkType) { ++ case PARAM_NETWORK_TYPE_DS: ++ strcpy(pcName, "IEEE 802.11b"); ++ break; ++ case PARAM_NETWORK_TYPE_OFDM24: ++ strcpy(pcName, "IEEE 802.11bgn"); ++ break; ++ case PARAM_NETWORK_TYPE_AUTOMODE: ++ case PARAM_NETWORK_TYPE_OFDM5: ++ strcpy(pcName, "IEEE 802.11abgn"); ++ break; ++ case PARAM_NETWORK_TYPE_FH: ++ default: ++ strcpy(pcName, "IEEE 802.11"); ++ break; ++ } ++ } else { ++ strcpy(pcName, "Disconnected"); ++ } ++ ++ return 0; ++} /* wext_get_name */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set the operating channel in the wireless device. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL ++* \param[in] prFreq Buffer to store frequency information ++* \param[in] pcExtra NULL ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS. ++* \retval -EINVAL Invalid channel frequency. ++* ++* \note If infrastructure mode is IBSS, new channel frequency is set to device. ++* The range of channel number depends on different regulatory domain. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_freq(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_freq *prIwFreq, IN char *pcExtra) ++{ ++ ++#if 0 ++ UINT_32 u4ChnlFreq; /* Store channel or frequency information */ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwFreq); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* ++ printk("set m:%d, e:%d, i:%d, flags:%d\n", ++ prIwFreq->m, prIwFreq->e, prIwFreq->i, prIwFreq->flags); ++ */ ++ ++ /* If setting by frequency, convert to a channel */ ++ if ((prIwFreq->e == 1) && (prIwFreq->m >= (int)2.412e8) && (prIwFreq->m <= (int)2.484e8)) { ++ ++ /* Change to KHz format */ ++ u4ChnlFreq = (UINT_32) (prIwFreq->m / (KILO / 10)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetFrequency, ++ &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ return -EINVAL; ++ } ++ /* Setting by channel number */ ++ else if ((prIwFreq->m > KILO) || (prIwFreq->e > 0)) ++ return -EOPNOTSUPP; ++ ++ /* Change to channel number format */ ++ u4ChnlFreq = (UINT_32) prIwFreq->m; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetChannel, &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ return -EINVAL; ++ ++#endif ++ ++ return 0; ++ ++} /* wext_set_freq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get the operating channel in the wireless device. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prFreq Buffer to store frequency information. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise ++* ++* \note If netif_carrier_ok, channel frequency information is stored in pFreq. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_freq(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_freq *prIwFreq, IN char *pcExtra) ++{ ++ UINT_32 u4Channel = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwFreq); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* GeorgeKuo: TODO skip checking in IBSS mode */ ++ if (!netif_carrier_ok(prNetDev)) ++ return -ENOTCONN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryFrequency, &u4Channel, sizeof(u4Channel), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prIwFreq->m = (int)u4Channel; /* freq in KHz */ ++ prIwFreq->e = 3; ++ ++ return 0; ++ ++} /* wext_get_freq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set operating mode. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] pu4Mode Pointer to new operation mode. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If new mode is not supported. ++* ++* \note Device will run in new operation mode if it is valid. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_mode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN unsigned int *pu4Mode, IN char *pcExtra) ++{ ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pu4Mode); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ switch (*pu4Mode) { ++ case IW_MODE_AUTO: ++ eOpMode = NET_TYPE_AUTO_SWITCH; ++ break; ++ ++ case IW_MODE_ADHOC: ++ eOpMode = NET_TYPE_IBSS; ++ break; ++ ++ case IW_MODE_INFRA: ++ eOpMode = NET_TYPE_INFRA; ++ break; ++ ++ default: ++ DBGLOG(REQ, ERROR, "%s(): Set UNSUPPORTED Mode = %d.\n", __func__, *pu4Mode); ++ return -EOPNOTSUPP; ++ } ++ ++ /* printk("%s(): Set Mode = %d\n", __FUNCTION__, *pu4Mode); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ /* after set operation mode, key table are cleared */ ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ return 0; ++} /* wext_set_mode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get operating mode. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo NULL. ++* \param[out] pu4Mode Buffer to store operating mode information. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If data is valid. ++* \retval -EINVAL Otherwise. ++* ++* \note If netif_carrier_ok, operating mode information is stored in pu4Mode. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_mode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, OUT unsigned int *pu4Mode, IN char *pcExtra) ++{ ++ ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_NUM; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pu4Mode); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eOpMode) { ++ case NET_TYPE_IBSS: ++ *pu4Mode = IW_MODE_ADHOC; ++ break; ++ ++ case NET_TYPE_INFRA: ++ *pu4Mode = IW_MODE_INFRA; ++ break; ++ ++ case NET_TYPE_AUTO_SWITCH: ++ *pu4Mode = IW_MODE_AUTO; ++ break; ++ ++ default: ++ DBGLOG(REQ, ERROR, "%s(): Get UNKNOWN Mode.\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} /* wext_get_mode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get the valid range for each configurable STA setting value. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData Pointer to iw_point structure, not used. ++* \param[out] pcExtra Pointer to buffer which is allocated by caller of this ++* function, wext_support_ioctl() or ioctl_standard_call() in ++* wireless.c. ++* ++* \retval 0 If data is valid. ++* ++* \note The extra buffer (pcExtra) is filled with information from driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_range(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, OUT char *pcExtra) ++{ ++ struct iw_range *prRange = NULL; ++ PARAM_RATES_EX aucSuppRate = { 0 }; /* data buffers */ ++ int i = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ prRange = (struct iw_range *)pcExtra; ++ ++ memset(prRange, 0, sizeof(*prRange)); ++ prRange->throughput = 20000000; /* 20Mbps */ ++ prRange->min_nwid = 0; /* not used */ ++ prRange->max_nwid = 0; /* not used */ ++ ++ /* scan_capa not implemented */ ++ ++ /* event_capa[6]: kernel + driver capabilities */ ++ prRange->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) ++ | IW_EVENT_CAPA_MASK(SIOCGIWSCAN) ++ /* can't display meaningful string in iwlist ++ | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW) ++ | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE) ++ | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE) ++ | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND) ++ */ ++ ); ++ prRange->event_capa[1] = IW_EVENT_CAPA_K_1; ++ ++ /* report 2.4G channel and frequency only */ ++ prRange->num_channels = (__u16) NUM_CHANNELS; ++ prRange->num_frequency = (__u8) NUM_CHANNELS; ++ for (i = 0; i < NUM_CHANNELS; i++) { ++ /* iwlib takes this number as channel number */ ++ prRange->freq[i].i = i + 1; ++ prRange->freq[i].m = channel_freq[i]; ++ prRange->freq[i].e = 6; /* Values in table in MHz */ ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQuerySupportedRates, ++ &aucSuppRate, sizeof(aucSuppRate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX; i++) { ++ if (aucSuppRate[i] == 0) ++ break; ++ prRange->bitrate[i] = (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps */ ++ } ++ prRange->num_bitrates = i; ++ ++ prRange->min_rts = 0; ++ prRange->max_rts = 2347; ++ prRange->min_frag = 256; ++ prRange->max_frag = 2346; ++ ++ prRange->min_pmp = 0; /* power management by driver */ ++ prRange->max_pmp = 0; /* power management by driver */ ++ prRange->min_pmt = 0; /* power management by driver */ ++ prRange->max_pmt = 0; /* power management by driver */ ++ prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */ ++ prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */ ++ prRange->pm_capa = IW_POWER_ON; /* power management by driver */ ++ ++ prRange->encoding_size[0] = 5; /* wep40 */ ++ prRange->encoding_size[1] = 16; /* tkip */ ++ prRange->encoding_size[2] = 16; /* ckip */ ++ prRange->encoding_size[3] = 16; /* ccmp */ ++ prRange->encoding_size[4] = 13; /* wep104 */ ++ prRange->encoding_size[5] = 16; /* wep128 */ ++ prRange->num_encoding_sizes = 6; ++ prRange->max_encoding_tokens = 6; /* token? */ ++ ++#if WIRELESS_EXT < 17 ++ prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */ ++#else ++ prRange->txpower_capa = IW_TXPOW_RELATIVE; ++#endif ++ prRange->num_txpower = 5; ++ prRange->txpower[0] = 0; /* minimum */ ++ prRange->txpower[1] = 25; /* 25% */ ++ prRange->txpower[2] = 50; /* 50% */ ++ prRange->txpower[3] = 100; /* 100% */ ++ ++ prRange->we_version_compiled = WIRELESS_EXT; ++ prRange->we_version_source = WIRELESS_EXT; ++ ++ prRange->retry_capa = IW_RETRY_LIMIT; ++ prRange->retry_flags = IW_RETRY_LIMIT; ++ prRange->min_retry = 7; ++ prRange->max_retry = 7; ++ prRange->r_time_flags = IW_RETRY_ON; ++ prRange->min_r_time = 0; ++ prRange->max_r_time = 0; ++ ++ /* signal strength and link quality */ ++ /* Just define range here, reporting value moved to wext_get_stats() */ ++ prRange->sensitivity = -83; /* fixed value */ ++ prRange->max_qual.qual = 100; /* max 100% */ ++ prRange->max_qual.level = (__u8) (0x100 - 0); /* max 0 dbm */ ++ prRange->max_qual.noise = (__u8) (0x100 - 0); /* max 0 dbm */ ++ ++ /* enc_capa */ ++#if WIRELESS_EXT > 17 ++ prRange->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ /* min_pms; Minimal PM saving */ ++ /* max_pms; Maximal PM saving */ ++ /* pms_flags; How to decode max/min PM saving */ ++ ++ /* modul_capa; IW_MODUL_* bit field */ ++ /* bitrate_capa; Types of bitrates supported */ ++ ++ return 0; ++} /* wext_get_range */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set BSSID of AP to connect. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* ++* \note Desired AP's BSSID is set to driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_ap(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN struct sockaddr *prAddr, IN char *pcExtra) ++{ ++ return 0; ++} /* wext_set_ap */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get AP MAC address. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_ap(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct sockaddr *prAddr, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prAddr); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prAddr)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* if (!netif_carrier_ok(prNetDev)) { */ ++ /* return -ENOTCONN; */ ++ /* } */ ++ ++ if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /*memset(prAddr, 0, 6);*/ ++ memset(prAddr, 0, sizeof(struct sockaddr)); ++ return 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssid, prAddr->sa_data, ETH_ALEN, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ return 0; ++} /* wext_get_ap */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set mlme operation request. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData Pointer of iw_point header. ++* \param[in] pcExtra Pointer to iw_mlme structure mlme request information. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP unsupported IW_MLME_ command. ++* \retval -EINVAL Set MLME Fail, different bssid. ++* ++* \note Driver will start mlme operation if valid. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_mlme(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, IN char *pcExtra) ++{ ++ struct iw_mlme *prMlme = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ prMlme = (struct iw_mlme *)pcExtra; ++ if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) { ++ if (!netif_carrier_ok(prNetDev)) { ++ DBGLOG(REQ, WARN, "[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n"); ++ return 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ return 0; ++ } ++ DBGLOG(REQ, WARN, "[wifi] unsupported IW_MLME_ command :%d\n", prMlme->cmd); ++ return -EOPNOTSUPP; ++ ++} /* wext_set_mlme */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To issue scan request. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData NULL. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EFAULT Tx power is off. ++* ++* \note Device will start scanning. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_scan(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN union iwreq_data *prData, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ int essid_len = 0; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_DEV(prNetDev)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++#if WIRELESS_EXT > 17 ++ /* retrieve SSID */ ++ if (prData) ++ essid_len = ((struct iw_scan_req *)(((struct iw_point *)prData)->pointer))->essid_len; ++#endif ++ ++ init_completion(&prGlueInfo->rScanComp); ++ ++ /* TODO: parse flags and issue different scan requests? */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScan, pcExtra, essid_len, FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * KAL_HZ); */ ++ /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ ++ ++ return 0; ++} /* wext_set_scan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To write the ie to buffer ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) ++{ ++ size_t i; ++ char *pos = buf, *end = buf + buf_size; ++ int ret; ++ ++ if (buf_size == 0) ++ return 0; ++ ++ for (i = 0; i < len; i++) { ++ ret = snprintf(pos, end - pos, "%02x", data[i]); ++ if (ret < 0 || ret >= end - pos) { ++ end[-1] = '\0'; ++ return pos - buf; ++ } ++ pos += ret; ++ } ++ end[-1] = '\0'; ++ return pos - buf; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get scan results, transform results from driver's format to WE's. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prData Pointer to iw_point structure, pData->length is the size of ++* pcExtra buffer before used, and is updated after filling scan ++* results. ++* \param[out] pcExtra Pointer to buffer which is allocated by caller of this ++* function, wext_support_ioctl() or ioctl_standard_call() in ++* wireless.c. ++* ++* \retval 0 For success. ++* \retval -ENOMEM If dynamic memory allocation fail. ++* \retval -E2BIG Invalid length. ++* ++* \note Scan results is filled into pcExtra buffer, data size is updated in ++* pData->length. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_scan(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT struct iw_point *prData, IN char *pcExtra) ++{ ++ UINT_32 i = 0; ++ UINT_32 j = 0; ++ P_PARAM_BSSID_LIST_EX_T prList = NULL; ++ P_PARAM_BSSID_EX_T prBss = NULL; ++ P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; ++ struct iw_event iwEvent; /* local iw_event buffer */ ++ ++ /* write pointer of extra buffer */ ++ char *pcCur = NULL; ++ /* pointer to the end of last full entry in extra buffer */ ++ char *pcValidEntryEnd = NULL; ++ char *pcEnd = NULL; /* end of extra buffer */ ++ ++ UINT_32 u4AllocBufLen = 0; ++ ++ /* arrange rate information */ ++ UINT_32 u4HighestRate = 0; ++ char aucRatesBuf[64]; ++ UINT_32 u4BufIndex; ++ ++ /* return value */ ++ int ret = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* Initialize local variables */ ++ pcCur = pcExtra; ++ pcValidEntryEnd = pcExtra; ++ pcEnd = pcExtra + prData->length; /* end of extra buffer */ ++ ++ /* Allocate another query buffer with the same size of extra buffer */ ++ u4AllocBufLen = prData->length; ++ prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); ++ if (prList == NULL) { ++ DBGLOG(REQ, ERROR, "[wifi] no memory for scan list:%d\n", prData->length); ++ ret = -ENOMEM; ++ goto error; ++ } ++ prList->u4NumberOfItems = 0; ++ ++ /* wait scan done */ ++ /* printk ("wait for scan results\n"); */ ++ /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * KAL_HZ); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_INVALID_LENGTH) { ++ /* Buffer length is not large enough. */ ++ /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ ++ ++#if WIRELESS_EXT >= 17 ++ /* This feature is supported in WE-17 or above, limited by iwlist. ++ ** Return -E2BIG and iwlist will request again with a larger buffer. ++ */ ++ ret = -E2BIG; ++ /* Update length to give application a hint on result length */ ++ prData->length = (__u16) u4BufLen; ++ goto error; ++#else ++ /* Realloc a larger query buffer here, but don't write too much to extra ++ ** buffer when filling it later. ++ */ ++ kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); ++ ++ u4AllocBufLen = u4BufLen; ++ prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); ++ if (prList == NULL) { ++ DBGLOG(REQ, ERROR, "[wifi] no memory for larger scan list :%u\n", u4BufLen); ++ ret = -ENOMEM; ++ goto error; ++ } ++ prList->NumberOfItems = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_INVALID_LENGTH) { ++ DBGLOG(REQ, ERROR, "[wifi] larger buf:%u result:%u\n", u4AllocBufLen, u4BufLen); ++ ret = -E2BIG; ++ prData->length = (__u16) u4BufLen; ++ goto error; ++ } ++#endif /* WIRELESS_EXT >= 17 */ ++ ++ } ++ ++ if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) { ++ DBGLOG(REQ, WARN, "[wifi] strange scan result count:%u\n", prList->u4NumberOfItems); ++ goto error; ++ } ++ ++ /* Copy required data from pList to pcExtra */ ++ prBss = &prList->arBssid[0]; /* set to the first entry */ ++ for (i = 0; i < prList->u4NumberOfItems; ++i) { ++ /* BSSID */ ++ iwEvent.cmd = SIOCGIWAP; ++ iwEvent.len = IW_EV_ADDR_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER; ++ ether_addr_copy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress); ++ memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN); ++ pcCur += IW_EV_ADDR_LEN; ++ ++ /* SSID */ ++ iwEvent.cmd = SIOCGIWESSID; ++ /* Modification to user space pointer(essid.pointer) is not needed. */ ++ iwEvent.u.essid.length = (__u16) prBss->rSsid.u4SsidLen; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length; ++ ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.essid.flags = 1; ++ iwEvent.u.essid.pointer = NULL; ++ ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, iwEvent.len); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, iwEvent.u.essid.length); ++ pcCur += iwEvent.len; ++ /* Frequency */ ++ iwEvent.cmd = SIOCGIWFREQ; ++ iwEvent.len = IW_EV_FREQ_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig; ++ iwEvent.u.freq.e = 3; /* (in KHz) */ ++ iwEvent.u.freq.i = 0; ++ memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN); ++ pcCur += IW_EV_FREQ_LEN; ++ ++ /* Operation Mode */ ++ iwEvent.cmd = SIOCGIWMODE; ++ iwEvent.len = IW_EV_UINT_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ if (prBss->eOpMode == NET_TYPE_IBSS) ++ iwEvent.u.mode = IW_MODE_ADHOC; ++ else if (prBss->eOpMode == NET_TYPE_INFRA) ++ iwEvent.u.mode = IW_MODE_INFRA; ++ else ++ iwEvent.u.mode = IW_MODE_AUTO; ++ memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN); ++ pcCur += IW_EV_UINT_LEN; ++ ++ /* Quality */ ++ iwEvent.cmd = IWEVQUAL; ++ iwEvent.len = IW_EV_QUAL_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.qual.qual = 0; /* Quality not available now */ ++ /* -100 < Rssi < -10, normalized by adding 0x100 */ ++ iwEvent.u.qual.level = 0x100 + prBss->rRssi; ++ iwEvent.u.qual.noise = 0; /* Noise not available now */ ++ iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; ++ memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN); ++ pcCur += IW_EV_QUAL_LEN; ++ ++ /* Security Mode */ ++ iwEvent.cmd = SIOCGIWENCODE; ++ iwEvent.len = IW_EV_POINT_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.pointer = NULL; ++ iwEvent.u.data.flags = 0; ++ iwEvent.u.data.length = 0; ++ if (!prBss->u4Privacy) ++ iwEvent.u.data.flags |= IW_ENCODE_DISABLED; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ pcCur += IW_EV_POINT_LEN; ++ ++ /* rearrange rate information */ ++ u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):"); ++ u4HighestRate = 0; ++ for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) { ++ UINT_8 curRate = prBss->rSupportedRates[j] & 0x7F; ++ ++ if (curRate == 0) ++ break; ++ ++ if (curRate > u4HighestRate) ++ u4HighestRate = curRate; ++ ++ if (curRate == RATE_5_5M) ++ u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " 5.5"); ++ else ++ u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " %d", curRate / 2); ++#if DBG ++ if (u4BufIndex > sizeof(aucRatesBuf)) { ++ /* printk("rate info too long\n"); */ ++ break; ++ } ++#endif ++ } ++ /* Report Highest Rates */ ++ iwEvent.cmd = SIOCGIWRATE; ++ iwEvent.len = IW_EV_PARAM_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.bitrate.value = u4HighestRate * 500000; ++ iwEvent.u.bitrate.fixed = 0; ++ iwEvent.u.bitrate.disabled = 0; ++ iwEvent.u.bitrate.flags = 0; ++ memcpy(pcCur, &iwEvent, iwEvent.len); ++ pcCur += iwEvent.len; ++ ++#if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */ ++ /* Report Residual Rates */ ++ iwEvent.cmd = IWEVCUSTOM; ++ iwEvent.u.data.length = u4BufIndex; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.flags = 0; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex); ++ pcCur += iwEvent.len; ++#endif /* WIRELESS_EXT >= 15 */ ++ ++ if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */ ++ if (wextSrchDesiredWPSIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#endif ++ ++ /* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */ ++ /* pBss->IEs starts from timestamp */ ++ if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0x30, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ if (wextSrchDesiredWAPIIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), (PUINT_8 *) &prDesiredIE)) { ++ ++#if 0 ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++#else ++ iwEvent.cmd = IWEVCUSTOM; ++ iwEvent.u.data.length = (2 + prDesiredIE->ucLength) * 2 + 8 /* wapi_ie= */; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.flags = 1; ++ ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++ ++ pcCur += (IW_EV_POINT_LEN); ++ ++ pcCur += sprintf(pcCur, "wapi_ie="); ++ ++ snprintf_hex(pcCur, pcEnd - pcCur, (UINT_8 *) prDesiredIE, prDesiredIE->ucLength + 2); ++ ++ pcCur += (2 + prDesiredIE->ucLength) * 2 /* iwEvent.len */; ++#endif ++ } ++#endif ++ /* Complete an entry. Update end of valid entry */ ++ pcValidEntryEnd = pcCur; ++ /* Extract next bss */ ++ prBss = (P_PARAM_BSSID_EX_T) ((char *)prBss + prBss->u4Length); ++ } ++ ++ /* Update valid data length for caller function and upper layer ++ * applications. ++ */ ++ prData->length = (pcValidEntryEnd - pcExtra); ++ /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ ++ ++ /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ ++ ++error: ++ /* free local query buffer */ ++ if (prList) ++ kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); ++ ++ return ret; ++} /* wext_get_scan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set desired network name ESSID. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEssid Pointer of iw_point header. ++* \param[in] pcExtra Pointer to buffer srtoring essid string. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -E2BIG Essid string length is too big. ++* \retval -EINVAL pcExtra is null pointer. ++* \retval -EFAULT Driver fail to set new essid. ++* ++* \note If string length is ok, device will try connecting to the new network. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_essid(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, IN char *pcExtra) ++{ ++ PARAM_SSID_T rNewSsid; ++ UINT_32 cipher; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEssid); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prEssid->length > IW_ESSID_MAX_SIZE) ++ return -E2BIG; ++ ++ /* set auth mode */ ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? ++ AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; ++ /* printk(KERN_INFO "IW_AUTH_WPA_VERSION_DISABLED->Param_AuthMode%s\n", */ ++ /* (eAuthMode == AUTH_MODE_OPEN) ? "Open" : "Shared"); */ ++ } else { ++ /* set auth mode */ ++ switch (prGlueInfo->rWpaInfo.u4KeyMgmt) { ++ case IW_AUTH_KEY_MGMT_802_1X: ++ eAuthMode = ++ (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? ++ AUTH_MODE_WPA : AUTH_MODE_WPA2; ++ /* printk("IW_AUTH_KEY_MGMT_802_1X->AUTH_MODE_WPA%s\n", */ ++ /* (eAuthMode == AUTH_MODE_WPA) ? "" : "2"); */ ++ break; ++ case IW_AUTH_KEY_MGMT_PSK: ++ eAuthMode = ++ (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? ++ AUTH_MODE_WPA_PSK : AUTH_MODE_WPA2_PSK; ++ /* printk("IW_AUTH_KEY_MGMT_PSK->AUTH_MODE_WPA%sPSK\n", */ ++ /* (eAuthMode == AUTH_MODE_WPA_PSK) ? "" : "2"); */ ++ break; ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ case IW_AUTH_KEY_MGMT_WAPI_PSK: ++ break; ++ case IW_AUTH_KEY_MGMT_WAPI_CERT: ++ break; ++#endif ++ ++/* #if defined (IW_AUTH_KEY_MGMT_WPA_NONE) */ ++/* case IW_AUTH_KEY_MGMT_WPA_NONE: */ ++/* eAuthMode = AUTH_MODE_WPA_NONE; */ ++/* //printk("IW_AUTH_KEY_MGMT_WPA_NONE->AUTH_MODE_WPA_NONE\n"); */ ++/* break; */ ++/* #endif */ ++#if CFG_SUPPORT_802_11W ++ case IW_AUTH_KEY_MGMT_802_1X_SHA256: ++ eAuthMode = AUTH_MODE_WPA2; ++ break; ++ case IW_AUTH_KEY_MGMT_PSK_SHA256: ++ eAuthMode = AUTH_MODE_WPA2_PSK; ++ break; ++#endif ++ default: ++ /* printk(KERN_INFO DRV_NAME"strange IW_AUTH_KEY_MGMT : %ld set auto switch\n", */ ++ /* prGlueInfo->rWpaInfo.u4KeyMgmt); */ ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ break; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* set encryption status */ ++ cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; ++ if (cipher & IW_AUTH_CIPHER_CCMP) { ++ /* printk("IW_AUTH_CIPHER_CCMP->ENUM_ENCRYPTION3_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_TKIP) { ++ /* printk("IW_AUTH_CIPHER_TKIP->ENUM_ENCRYPTION2_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { ++ /* printk("IW_AUTH_CIPHER_WEPx->ENUM_ENCRYPTION1_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_NONE) { ++ /* printk("IW_AUTH_CIPHER_NONE->ENUM_ENCRYPTION_DISABLED\n"); */ ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } else { ++ /* printk("unknown IW_AUTH_CIPHER->Param_EncryptionDisabled\n"); */ ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++#if WIRELESS_EXT < 21 ++ /* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel before ++ ** 2.6.19. Cut the trailing '\0'. ++ */ ++ rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0; ++#else ++ rNewSsid.u4SsidLen = prEssid->length; ++#endif ++ kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen); ++ ++ /* ++ rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0'; ++ printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid); ++ */ ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetSsid, ++ (PVOID)&rNewSsid, ++ sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen) != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_WARNING "Fail to set ssid\n"); */ ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* wext_set_essid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get current network name ESSID. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEssid Pointer to iw_point structure containing essid information. ++* \param[out] pcExtra Pointer to buffer srtoring essid string. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, network essid is stored in pcExtra. ++*/ ++/*----------------------------------------------------------------------------*/ ++/* static PARAM_SSID_T ssid; */ ++static int ++wext_get_essid(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, OUT char *pcExtra) ++{ ++ /* PARAM_SSID_T ssid; */ ++ ++ P_PARAM_SSID_T prSsid; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEssid); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* if (!netif_carrier_ok(prNetDev)) { */ ++ /* return -ENOTCONN; */ ++ /* } */ ++ ++ prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE); ++ ++ if (!prSsid) ++ return -ENOMEM; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQuerySsid, prSsid, sizeof(PARAM_SSID_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if ((rStatus == WLAN_STATUS_SUCCESS) && (prSsid->u4SsidLen <= MAX_SSID_LEN)) { ++ kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen); ++ prEssid->length = prSsid->u4SsidLen; ++ prEssid->flags = 1; ++ } ++ ++ kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T)); ++ ++ return 0; ++} /* wext_get_essid */ ++ ++#if 0 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set tx desired bit rate. Three cases here ++* iwconfig wlan0 auto -> Set to origianl supported rate set. ++* iwconfig wlan0 18M -> Imply "fixed" case, set to 18Mbps as desired rate. ++* iwconfig wlan0 18M auto -> Set to auto rate lower and equal to 18Mbps ++* ++* \param[in] prNetDev Pointer to the net_device handler. ++* \param[in] prIwReqInfo Pointer to the Request Info. ++* \param[in] prRate Pointer to the Rate Parameter. ++* \param[in] pcExtra Pointer to the extra buffer. ++* ++* \retval 0 Update desired rate. ++* \retval -EINVAL Wrong parameter ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++wext_set_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra) ++{ ++ PARAM_RATES_EX aucSuppRate = { 0 }; ++ PARAM_RATES_EX aucNewRate = { 0 }; ++ UINT_32 u4NewRateLen = 0; ++ UINT_32 i; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRate); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* ++ printk("value = %d, fixed = %d, disable = %d, flags = %d\n", ++ prRate->value, prRate->fixed, prRate->disabled, prRate->flags); ++ */ ++ ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuerySupportedRates, &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); ++ ++ /* Case: AUTO */ ++ if (prRate->value < 0) { ++ if (prRate->fixed == 0) { ++ /* iwconfig wlan0 rate auto */ ++ ++ /* set full supported rate to device */ ++ /* printk("wlanoidQuerySupportedRates():u4BufLen = %ld\n", u4BufLen); */ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetDesiredRates, ++ &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); ++ return 0; ++ } ++ /* iwconfig wlan0 rate fixed */ ++ ++ /* fix rate to what? DO NOTHING */ ++ return -EINVAL; ++ } ++ ++ aucNewRate[0] = prRate->value / 500000; /* In unit of 500k */ ++ ++ for (i = 0; i < PARAM_MAX_LEN_RATES_EX; i++) { ++ /* check the given value is supported */ ++ if (aucSuppRate[i] == 0) ++ break; ++ ++ if (aucNewRate[0] == aucSuppRate[i]) { ++ u4NewRateLen = 1; ++ break; ++ } ++ } ++ ++ if (u4NewRateLen == 0) { ++ /* the given value is not supported */ ++ /* return error or use given rate as upper bound? */ ++ return -EINVAL; ++ } ++ ++ if (prRate->fixed == 0) { ++ /* add all rates lower than desired rate */ ++ for (i = 0; i < PARAM_MAX_LEN_RATES_EX; ++i) { ++ if (aucSuppRate[i] == 0) ++ break; ++ ++ if (aucSuppRate[i] < aucNewRate[0]) ++ aucNewRate[u4NewRateLen++] = aucSuppRate[i]; ++ } ++ } ++ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetDesiredRates, &aucNewRate, sizeof(aucNewRate), &u4BufLen); ++ return 0; ++} /* wext_set_rate */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get current tx bit rate. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prRate Pointer to iw_param structure to store current tx rate. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, current tx rate is stored in pRate. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRate, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ UINT_32 u4Rate = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRate); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (!netif_carrier_ok(prNetDev)) ++ return -ENOTCONN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */ ++ prRate->fixed = 0; ++ ++ return 0; ++} /* wext_get_rate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set RTS/CTS theshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prRts Pointer to iw_param structure containing rts threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EINVAL Given value is out of range. ++* ++* \note If given value is valid, device will follow the new setting. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_rts(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prRts, IN char *pcExtra) ++{ ++ PARAM_RTS_THRESHOLD u4RtsThresh; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRts); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prRts->disabled == 1) ++ u4RtsThresh = 2347; ++ else if (prRts->value < 0 || prRts->value > 2347) ++ return -EINVAL; ++ ++ u4RtsThresh = (PARAM_RTS_THRESHOLD) prRts->value; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRtsThreshold, ++ &u4RtsThresh, sizeof(u4RtsThresh), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prRts->value = (typeof(prRts->value)) u4RtsThresh; ++ prRts->disabled = (prRts->value > 2347) ? 1 : 0; ++ prRts->fixed = 1; ++ ++ return 0; ++} /* wext_set_rts */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get RTS/CTS theshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prRts Pointer to iw_param structure containing rts threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note RTS threshold is stored in pRts. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_rts(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRts, IN char *pcExtra) ++{ ++ PARAM_RTS_THRESHOLD u4RtsThresh = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRts); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRtsThreshold, ++ &u4RtsThresh, sizeof(u4RtsThresh), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prRts->value = (typeof(prRts->value)) u4RtsThresh; ++ prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0; ++ prRts->fixed = 1; ++ ++ return 0; ++} /* wext_get_rts */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get fragmentation threshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prFrag Pointer to iw_param structure containing frag threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note RTS threshold is stored in pFrag. Fragmentation is disabled. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_frag(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prFrag, IN char *pcExtra) ++{ ++ ASSERT(prFrag); ++ ++ prFrag->value = 2346; ++ prFrag->fixed = 1; ++ prFrag->disabled = 1; ++ return 0; ++} /* wext_get_frag */ ++ ++#if 1 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set TX power, or enable/disable the radio. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prTxPow Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used ++* to enable/disable the radio. ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static int ++wext_set_txpow(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prTxPow, IN char *pcExtra) ++{ ++ int ret = 0; ++ /* PARAM_DEVICE_POWER_STATE ePowerState; */ ++ ENUM_ACPI_STATE_T ePowerState; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prTxPow); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prTxPow->disabled) { ++ /* <1> disconnect */ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "######set disassoc failed\n"); ++ else ++ DBGLOG(REQ, TRACE, "######set assoc ok\n"); ++ /* <2> mark to power state flag */ ++ ePowerState = ACPI_STATE_D0; ++ DBGLOG(REQ, INFO, "set to acpi d3(0)\n"); ++ wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); ++ ++ } else { ++ ePowerState = ACPI_STATE_D0; ++ DBGLOG(REQ, INFO, "set to acpi d0\n"); ++ wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); ++ } ++ ++ prGlueInfo->ePowerState = ePowerState; ++ ++ return ret; ++} /* wext_set_txpow */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get TX power. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prTxPow Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Tx power is stored in pTxPow. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_txpow(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prTxPow, IN char *pcExtra) ++{ ++ /* PARAM_DEVICE_POWER_STATE ePowerState; */ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prTxPow); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not ++ * current state. Use GLUE_INFO_T to store state. ++ */ ++ /* ePowerState = prGlueInfo->ePowerState; */ ++ ++ /* TxPow parameters: Fixed at relative 100% */ ++#if WIRELESS_EXT < 17 ++ prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */ ++#else ++ prTxPow->flags = IW_TXPOW_RELATIVE; ++#endif ++ prTxPow->value = 100; ++ prTxPow->fixed = 1; ++ /* prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? FALSE : TRUE; */ ++ prTxPow->disabled = TRUE; ++ ++ return 0; ++} /* wext_get_txpow */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Buffer to store key content. ++* ++* \retval 0 Success. ++* ++* \note Securiry information is stored in pEnc except key content. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_encode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_point *prEnc, IN char *pcExtra) ++{ ++#if 1 ++ /* ENUM_ENCRYPTION_STATUS_T eEncMode; */ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode = ENUM_WEP_ENABLED; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prEnc)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryEncryptionStatus, ++ &eEncMode, sizeof(eEncMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eEncMode) { ++ case ENUM_WEP_DISABLED: ++ prEnc->flags = IW_ENCODE_DISABLED; ++ break; ++ case ENUM_WEP_ENABLED: ++ prEnc->flags = IW_ENCODE_ENABLED; ++ break; ++ case ENUM_WEP_KEY_ABSENT: ++ prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ break; ++ default: ++ prEnc->flags = IW_ENCODE_ENABLED; ++ break; ++ } ++ ++ /* Cipher, Key Content, Key ID can't be queried */ ++ prEnc->flags |= IW_ENCODE_NOKEY; ++#endif ++ return 0; ++} /* wext_get_encode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 wepBuf[48]; ++ ++static int ++wext_set_encode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) ++{ ++#if 1 ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ /* UINT_8 wepBuf[48]; */ ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* reset to default mode */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ /* iwconfig wlan0 key off */ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { ++ eAuthMode = AUTH_MODE_OPEN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ return 0; ++ } ++ ++ /* iwconfig wlan0 key 0123456789 */ ++ /* iwconfig wlan0 key s:abcde */ ++ /* iwconfig wlan0 key 0123456789 [1] */ ++ /* iwconfig wlan0 key 01234567890123456789012345 [1] */ ++ /* check key size for WEP */ ++ if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) { ++ /* prepare PARAM_WEP key structure */ ++ prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++ if (prWepKey->u4KeyIndex > 3) { ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ prWepKey->u4KeyIndex |= 0x80000000; ++ prWepKey->u4Length = 12 + prEnc->length; ++ prWepKey->u4KeyLength = prEnc->length; ++ kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* change to auto switch */ ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSetAuthMode fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++ ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ ++ eEncStatus = ENUM_WEP_ENABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, ++ sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++ ++ return 0; ++ } ++#endif ++ return -EOPNOTSUPP; ++} /* wext_set_encode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set power management. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prPower Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note New Power Management Mode is set to driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_power(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prPower, IN char *pcExtra) ++{ ++#if 1 ++ ++ PARAM_POWER_MODE ePowerMode; ++ INT_32 i4PowerValue; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ if (prPower->disabled) { ++ ePowerMode = Param_PowerModeCAM; ++ } else { ++ i4PowerValue = prPower->value; ++#if WIRELESS_EXT < 21 ++ i4PowerValue /= 1000000; ++#endif ++ if (i4PowerValue == 0) { ++ ePowerMode = Param_PowerModeCAM; ++ } else if (i4PowerValue == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (i4PowerValue == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } else { ++ DBGLOG(REQ, ERROR, "%s(): unsupported power management mode value = %d.\n", ++ __func__, prPower->value); ++ ++ return -EINVAL; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSet802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++#endif ++ return 0; ++} /* wext_set_power */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get power management. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prPower Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Power management mode is stored in pTxPow->value. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_power(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prPower, IN char *pcExtra) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++#if 0 ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), TRUE, TRUE, &u4BufLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prPower->value = 0; ++ prPower->disabled = 1; ++ ++ if (Param_PowerModeCAM == ePowerMode) { ++ prPower->value = 0; ++ prPower->disabled = 1; ++ } else if (Param_PowerModeMAX_PSP == ePowerMode) { ++ prPower->value = 1; ++ prPower->disabled = 0; ++ } else if (Param_PowerModeFast_PSP == ePowerMode) { ++ prPower->value = 2; ++ prPower->disabled = 0; ++ } ++ ++ prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; ++#if WIRELESS_EXT < 21 ++ prPower->value *= 1000000; ++#endif ++ ++ /* printk(KERN_INFO "wext_get_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ return 0; ++} /* wext_get_power */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set authentication parameters. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] rpAuth Pointer to iw_param structure containing authentication information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_auth(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prAuth, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prAuth); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prAuth)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* Save information to glue info and process later when ssid is set. */ ++ switch (prAuth->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++#if CFG_SUPPORT_WAPI ++ if (wlanQueryWapiMode(prGlueInfo->prAdapter)) { ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++ } else { ++ prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; ++ } ++#else ++ prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; ++#endif ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value; ++ break; ++ ++ case IW_AUTH_CIPHER_GROUP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value; ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value; ++#if CFG_SUPPORT_WAPI ++ if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_PSK || ++ prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_CERT) { ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiMode, ++ &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); ++ } ++#endif ++ if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS) ++ prGlueInfo->fgWpsActive = TRUE; ++ else ++ prGlueInfo->fgWpsActive = FALSE; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value; ++ break; ++#if CFG_SUPPORT_802_11W ++ case IW_AUTH_MFP: ++ /* printk("wext_set_auth IW_AUTH_MFP=%d\n", prAuth->value); */ ++ prGlueInfo->rWpaInfo.u4Mfp = prAuth->value; ++ break; ++#endif ++#if CFG_SUPPORT_WAPI ++ case IW_AUTH_WAPI_ENABLED: ++ { ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiMode, ++ &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); ++ break; ++#endif ++ default: ++ /* ++ printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", prAuth->flags); ++ */ ++ break; ++ } ++ return 0; ++} /* wext_set_auth */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++#if CFG_SUPPORT_WAPI ++UINT_8 keyStructBuf[320]; /* add/remove key shared buffer */ ++#else ++UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ ++#endif ++ ++static int ++wext_set_encode_ext(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) ++{ ++ P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; ++ P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; ++ ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *)pcExtra; ++ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ /* ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; */ ++ ++#if CFG_SUPPORT_WAPI ++ P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; ++#endif ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++#if CFG_SUPPORT_WAPI ++ if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { ++ if (prEnc->flags & IW_ENCODE_DISABLED) { ++ /* printk(KERN_INFO "[wapi] IW_ENCODE_DISABLED\n"); */ ++ return 0; ++ } ++ /* KeyID */ ++ prWpiKey->ucKeyID = (prEnc->flags & IW_ENCODE_INDEX); ++ prWpiKey->ucKeyID--; ++ if (prWpiKey->ucKeyID > 1) { ++ /* key id is out of range */ ++ /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ ++ return -EINVAL; ++ } ++ ++ if (prIWEncExt->key_len != 32) { ++ /* key length not valid */ ++ /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ ++ return -EINVAL; ++ } ++ /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ ++ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX; ++ } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX_TX; ++ } ++ ++ /* PN */ ++ { ++ UINT_32 i; ++ ++ for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) ++ prWpiKey->aucPN[i] = prIWEncExt->tx_seq[i]; ++ for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) ++ prWpiKey->aucPN[IW_ENCODE_SEQ_MAX_SIZE + i] = prIWEncExt->rx_seq[i]; ++ } ++ ++ /* BSSID */ ++ memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr.sa_data, 6); ++ ++ memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); ++ prWpiKey->u4LenWPIEK = 16; ++ ++ memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); ++ prWpiKey->u4LenWPICK = 16; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiKey, ++ prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ ++ } ++ } else ++#endif ++ { ++ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { ++ prRemoveKey->u4Length = sizeof(*prRemoveKey); ++ memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ /* ++ printk("IW_ENCODE_DISABLED: ID:%d, Addr:[ %pM ]\n", ++ prRemoveKey->KeyIndex, prRemoveKey->BSSID); ++ */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveKey, ++ prRemoveKey, prRemoveKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, INFO, "remove key error:%x\n", rStatus); ++ return 0; ++ } ++ /* return 0; */ ++ /* printk ("alg %x\n", prIWEncExt->alg); */ ++ ++ switch (prIWEncExt->alg) { ++ case IW_ENCODE_ALG_NONE: ++ break; ++ case IW_ENCODE_ALG_WEP: ++ /* iwconfig wlan0 key 0123456789 */ ++ /* iwconfig wlan0 key s:abcde */ ++ /* iwconfig wlan0 key 0123456789 [1] */ ++ /* iwconfig wlan0 key 01234567890123456789012345 [1] */ ++ /* check key size for WEP */ ++ if (prIWEncExt->key_len == 5 || prIWEncExt->key_len == 13 || prIWEncExt->key_len == 16) { ++ /* prepare PARAM_WEP key structure */ ++ prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++ if (prWepKey->u4KeyIndex > 3) { ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ prWepKey->u4KeyIndex |= 0x80000000; ++ prWepKey->u4Length = 12 + prIWEncExt->key_len; ++ prWepKey->u4KeyLength = prIWEncExt->key_len; ++ /* kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prIWEncExt->key_len); */ ++ kalMemCopy(prWepKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* change to auto switch */ ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, ++ sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAuthMode fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ ++ eEncStatus = ENUM_WEP_ENABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, ++ sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), ++ FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetEncryptionStatus fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ } else { ++ DBGLOG(REQ, INFO, "key length %x\n", prIWEncExt->key_len); ++ DBGLOG(REQ, INFO, "key error\n"); ++ } ++ ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ case IW_ENCODE_ALG_CCMP: ++#if CFG_SUPPORT_802_11W ++ case IW_ENCODE_ALG_AES_CMAC: ++#endif ++ { ++ ++ /* KeyID */ ++ prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++#if CFG_SUPPORT_802_11W ++ if (prKey->u4KeyIndex > 5) { ++#else ++ if (prKey->u4KeyIndex > 3) { ++#endif ++ DBGLOG(REQ, ERROR, "key index error:0x%x\n", prKey->u4KeyIndex); ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ ++ /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ ++ /* Tx Key Bit(31) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prKey->u4KeyIndex |= 0x1UL << 31; ++ /* Code style */ ++ } ++ /* Pairwise Key Bit(30) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* Do nothing */ ++ /* group key */ ++ } else { ++ /* pairwise key */ ++ prKey->u4KeyIndex |= 0x1UL << 30; ++ } ++ } ++ /* Rx SC Bit(29) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ prKey->u4KeyIndex |= 0x1UL << 29; ++ memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ } ++ ++ /* BSSID */ ++ memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ ++ /* switch tx/rx MIC key for sta */ ++ if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && prIWEncExt->key_len == 32) { ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, 16); ++ memcpy(((PUINT_8) prKey->aucKeyMaterial) + 16, prIWEncExt->key + 24, 8); ++ memcpy((prKey->aucKeyMaterial) + 24, prIWEncExt->key + 16, 8); ++ } else { ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ } ++ ++ prKey->u4KeyLength = prIWEncExt->key_len; ++ prKey->u4Length = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + prKey->u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddKey, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "add key error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ break; ++ } ++ } ++ ++ return 0; ++} /* wext_set_encode_ext */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set country code ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prData iwreq.u.data carries country code value. ++* ++* \retval 0 For success. ++* \retval -EEFAULT For fail. ++* ++* \note Country code is stored and channel list is updated based on current country domain. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wext_set_country(IN struct net_device *prNetDev, IN struct iw_point *prData) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ UINT_8 aucCountry[2]; ++ ++ ASSERT(prNetDev); ++ ++ /* prData->pointer should be like "COUNTRY US", "COUNTRY EU" ++ * and "COUNTRY JP" ++ */ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prData) || !prData->pointer || prData->length < 10) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ aucCountry[0] = *((PUINT_8)prData->pointer + 8); ++ aucCountry[1] = *((PUINT_8)prData->pointer + 9); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To report the iw private args table to user space. ++* ++* \param[in] prNetDev Net device requested. ++* \param[out] prData iwreq.u.data to carry the private args table. ++* ++* \retval 0 For success. ++* \retval -E2BIG For user's buffer size is too small. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData) ++{ ++ UINT_16 u2BufferSize = prData->length; ++ ++ /* Update our private args table size */ ++ prData->length = (__u16)sizeof(rIwPrivTable); ++ if (u2BufferSize < prData->length) ++ return -E2BIG; ++ ++ if (prData->length) { ++ if (copy_to_user(prData->pointer, rIwPrivTable, sizeof(rIwPrivTable))) ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* wext_get_priv */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl() (Linux Wireless Extensions) routines ++* ++* \param[in] prDev Net device requested. ++* \param[in] ifr The ifreq structure for seeting the wireless extension. ++* \param[in] i4Cmd The wireless extension ioctl command. ++* ++* \retval zero On success. ++* \retval -EOPNOTSUPP If the cmd is not supported. ++* \retval -EFAULT If copy_to_user goes wrong. ++* \retval -EINVAL If any value's out of range. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd) ++{ ++ struct iwreq *iwr = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ int ret = 0; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ /* printk("%d CMD:0x%x\n", jiffies_to_msecs(jiffies), i4Cmd); */ ++ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */ ++ ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, NULL); ++ break; ++ ++ /* case SIOCSIWNWID: 0x8B02, deprecated */ ++ /* case SIOCGIWNWID: 0x8B03, deprecated */ ++ ++ case SIOCSIWFREQ: /* 0x8B04, set channel */ ++ ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL); ++ break; ++ ++ case SIOCGIWFREQ: /* 0x8B05, get channel */ ++ ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL); ++ break; ++ ++ case SIOCSIWMODE: /* 0x8B06, set operation mode */ ++ ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL); ++ /* ret = 0; */ ++ break; ++ ++ case SIOCGIWMODE: /* 0x8B07, get operation mode */ ++ ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL); ++ break; ++ ++ /* case SIOCSIWSENS: 0x8B08, unsupported */ ++ /* case SIOCGIWSENS: 0x8B09, unsupported */ ++ ++ /* case SIOCSIWRANGE: 0x8B0A, unused */ ++ case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */ ++ if (iwr->u.data.pointer != NULL) { ++ /* Buffer size should be large enough */ ++ if (iwr->u.data.length < sizeof(struct iw_range)) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_range), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* reset all fields */ ++ memset(prExtraBuf, 0, sizeof(struct iw_range)); ++ iwr->u.data.length = sizeof(struct iw_range); ++ ++ ret = wext_get_range(prDev, NULL, &iwr->u.data, prExtraBuf); ++ /* Push up to the caller */ ++ if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) ++ ret = -EFAULT; ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_range)); ++ prExtraBuf = NULL; ++ } else { ++ ret = -EINVAL; ++ } ++ break; ++ ++ case SIOCSIWPRIV: /* 0x8B0C, set country code */ ++ ret = wext_set_country(prDev, &iwr->u.data); ++ break; ++ ++ case SIOCGIWPRIV: /* 0x8B0D, get private args table */ ++ ret = wext_get_priv(prDev, &iwr->u.data); ++ break; ++ ++ /* case SIOCSIWSTATS: 0x8B0E, unused */ ++ /* case SIOCGIWSTATS: ++ get statistics, intercepted by wireless_process_ioctl() in wireless.c, ++ redirected to dev_iwstats(), dev->get_wireless_stats(). ++ */ ++ /* case SIOCSIWSPY: 0x8B10, unsupported */ ++ /* case SIOCGIWSPY: 0x8B11, unsupported */ ++ /* case SIOCSIWTHRSPY: 0x8B12, unsupported */ ++ /* case SIOCGIWTHRSPY: 0x8B13, unsupported */ ++ ++ case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */ ++ if (iwr->u.ap_addr.sa_data[0] == 0 && ++ iwr->u.ap_addr.sa_data[1] == 0 && ++ iwr->u.ap_addr.sa_data[2] == 0 && ++ iwr->u.ap_addr.sa_data[3] == 0 && ++ iwr->u.ap_addr.sa_data[4] == 0 && iwr->u.ap_addr.sa_data[5] == 0) { ++ /* WPA Supplicant will set 000000000000 in ++ ** wpa_driver_wext_deinit(), do nothing here or disassoc again? ++ */ ++ ret = 0; ++ break; ++ } ++ ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL); ++ ++ break; ++ ++ case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */ ++ ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL); ++ break; ++ ++ case SIOCSIWMLME: /* 0x8B16, request MLME operation */ ++ /* Fixed length structure */ ++ if (iwr->u.data.length != sizeof(struct iw_mlme)) { ++ DBGLOG(REQ, ERROR, "MLME buffer strange:%d\n", iwr->u.data.length); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (!iwr->u.data.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_mlme))) ++ ret = -EFAULT; ++ else ++ ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); ++ prExtraBuf = NULL; ++ break; ++ ++ /* case SIOCGIWAPLIST: 0x8B17, deprecated */ ++ case SIOCSIWSCAN: /* 0x8B18, scan request */ ++ if (iwr->u.data.pointer == NULL) ++ ret = wext_set_scan(prDev, NULL, NULL, NULL); ++#if WIRELESS_EXT > 17 ++ else if (iwr->u.data.length == sizeof(struct iw_scan_req)) { ++ prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(prExtraBuf, ((struct iw_scan_req *)(iwr->u.data.pointer))->essid, ++ ((struct iw_scan_req *)(iwr->u.data.pointer))->essid_len)) { ++ ret = -EFAULT; ++ } else { ++ ret = wext_set_scan(prDev, NULL, (union iwreq_data *)&(iwr->u.data), prExtraBuf); ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN); ++ prExtraBuf = NULL; ++ } ++#endif ++ else ++ ret = -EINVAL; ++ break; ++#if 1 ++ case SIOCGIWSCAN: /* 0x8B19, get scan results */ ++ if (!iwr->u.data.pointer || !iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ u4ExtraSize = iwr->u.data.length; ++ /* allocate the same size of kernel buffer to store scan results. */ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* iwr->u.data.length may be updated by wext_get_scan() */ ++ ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf); ++ if (ret != 0) { ++ if (ret == -E2BIG) ++ DBGLOG(REQ, WARN, "[wifi] wext_get_scan -E2BIG\n"); ++ } else { ++ /* check updated length is valid */ ++ ASSERT(iwr->u.data.length <= u4ExtraSize); ++ if (iwr->u.data.length > u4ExtraSize) { ++ DBGLOG(REQ, INFO, "Updated result length is larger than allocated (%d > %u)\n", ++ iwr->u.data.length, u4ExtraSize); ++ iwr->u.data.length = u4ExtraSize; ++ } ++ ++ if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) ++ ret = -EFAULT; ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ ++ break; ++ ++#endif ++ ++#if 1 ++ case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */ ++ if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) { ++ ret = -E2BIG; ++ break; ++ } ++ if (!iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.essid.pointer, iwr->u.essid.length)) { ++ ret = -EFAULT; ++ } else { ++ /* Add trailing '\0' for printk */ ++ /* prExtraBuf[iwr->u.essid.length] = 0; */ ++ /* printk(KERN_INFO "wext_set_essid: %s (%d)\n", prExtraBuf, iwr->u.essid.length); */ ++ ret = wext_set_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); ++ /* printk ("set essid %d\n", ret); */ ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4); ++ prExtraBuf = NULL; ++ break; ++ ++#endif ++ ++ case SIOCGIWESSID: /* 0x8B1B, get SSID */ ++ if (!iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (iwr->u.essid.length < IW_ESSID_MAX_SIZE) { ++ DBGLOG(REQ, ERROR, "[wifi] iwr->u.essid.length:%d too small\n", iwr->u.essid.length); ++ ret = -E2BIG; /* let caller try larger buffer */ ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* iwr->u.essid.length is updated by wext_get_essid() */ ++ ++ ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); ++ if (ret == 0) { ++ if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, iwr->u.essid.length)) ++ ret = -EFAULT; ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE); ++ prExtraBuf = NULL; ++ ++ break; ++ ++ /* case SIOCSIWNICKN: 0x8B1C, not supported */ ++ /* case SIOCGIWNICKN: 0x8B1D, not supported */ ++ ++ case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */ ++ /* ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, NULL); */ ++ break; ++ ++ case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */ ++ ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL); ++ break; ++ ++ case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */ ++ ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL); ++ break; ++ ++ case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */ ++ ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL); ++ break; ++ ++ /* case SIOCSIWFRAG: 0x8B24, unsupported */ ++ case SIOCGIWFRAG: /* 0x8B25, get frag threshold */ ++ ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL); ++ break; ++ ++ case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */ ++ ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL); ++ break; ++ ++ case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */ ++ ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL); ++ break; ++ ++ /* case SIOCSIWRETRY: 0x8B28, unsupported */ ++ /* case SIOCGIWRETRY: 0x8B29, unsupported */ ++ ++#if 1 ++ case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */ ++ /* Only DISABLED case has NULL pointer and length == 0 */ ++ if (iwr->u.encoding.pointer) { ++ if (iwr->u.encoding.length > 16) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ u4ExtraSize = iwr->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (iwr->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, prExtraBuf); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ break; ++ ++ case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */ ++ /* check pointer */ ++ ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL); ++ break; ++ ++ case SIOCSIWPOWER: /* 0x8B2C, set power management */ ++ ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL); ++ break; ++ ++ case SIOCGIWPOWER: /* 0x8B2D, get power management */ ++ ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL); ++ break; ++ ++#if WIRELESS_EXT > 17 ++ case SIOCSIWGENIE: /* 0x8B30, set gen ie */ ++ if (iwr->u.data.pointer == NULL) ++ break; ++ ++ if (0 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */) ++ break; ++ ++ /* Fixed length structure */ ++#if CFG_SUPPORT_WAPI ++ if (iwr->u.data.length > 42 /* The max wapi ie buffer */) { ++ ret = -EINVAL; ++ break; ++ } ++#endif ++ u4ExtraSize = iwr->u.data.length; ++ if (u4ExtraSize == 0) ++ break; ++ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, iwr->u.data.length)) { ++ ret = -EFAULT; ++ } else { ++#if CFG_SUPPORT_WAPI ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiAssocInfo, ++ prExtraBuf, ++ u4ExtraSize, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[wapi] set wapi assoc info error:%lx\n", ++ rStatus); */ ++#endif ++#if CFG_SUPPORT_WPS2 ++ PUINT_8 prDesiredIE = NULL; ++ ++ if (wextSrchDesiredWPSIE(prExtraBuf, ++ u4ExtraSize, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWSCAssocInfo, ++ prDesiredIE, ++ IE_SIZE(prDesiredIE), ++ FALSE, ++ FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[WSC] set WSC assoc info ++ error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++#if CFG_SUPPORT_WAPI ++ } ++#endif ++ } ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */ ++ break; ++ ++#endif ++ ++ case SIOCSIWAUTH: /* 0x8B32, set auth mode params */ ++ ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL); ++ break; ++ ++ /* case SIOCGIWAUTH: 0x8B33, unused? */ ++ case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */ ++ if (iwr->u.encoding.pointer) { ++ u4ExtraSize = iwr->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (iwr->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, prExtraBuf); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ break; ++ ++ /* case SIOCGIWENCODEEXT: 0x8B35, unused? */ ++ ++ case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */ ++#if 1 ++ if (iwr->u.data.pointer) { ++ /* Fixed length structure */ ++ if (iwr->u.data.length != sizeof(struct iw_pmksa)) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ u4ExtraSize = sizeof(struct iw_pmksa); ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_pmksa))) { ++ ret = -EFAULT; ++ } else { ++ switch (((struct iw_pmksa *)prExtraBuf)->cmd) { ++ case IW_PMKSA_ADD: ++ /* ++ printk(KERN_INFO "IW_PMKSA_ADD [ %pM ]\n", ++ (((struct iw_pmksa *)pExtraBuf)->bssid.sa_data)); ++ */ ++ prPmkid = ++ (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), ++ VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); ++ ret = -ENOMEM; ++ break; ++ } ++ ++ prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); ++ prPmkid->u4BSSIDInfoCount = 1; ++ kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, ++ ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, 6); ++ kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, ++ ((struct iw_pmksa *)prExtraBuf)->pmkid, IW_PMKID_LEN); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, ++ prPmkid, ++ sizeof(PARAM_PMKID_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "add pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); ++ break; ++ case IW_PMKSA_REMOVE: ++ /* ++ printk(KERN_INFO "IW_PMKSA_REMOVE [ %pM ]\n", ++ (((struct iw_pmksa *)buf)->bssid.sa_data)); ++ */ ++ break; ++ case IW_PMKSA_FLUSH: ++ /* ++ printk(KERN_INFO "IW_PMKSA_FLUSH\n"); ++ */ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, ++ "Can not alloc memory for IW_PMKSA_FLUSH\n"); ++ ret = -ENOMEM; ++ break; ++ } ++ ++ prPmkid->u4Length = 8; ++ prPmkid->u4BSSIDInfoCount = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, ++ prPmkid, ++ sizeof(PARAM_PMKID_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "flush pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8); ++ break; ++ default: ++ DBGLOG(REQ, WARN, "UNKNOWN iw_pmksa command:%d\n", ++ ((struct iw_pmksa *)prExtraBuf)->cmd); ++ ret = -EFAULT; ++ break; ++ } ++ } ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ } else if (iwr->u.data.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++#endif ++ break; ++ ++#endif ++ ++ default: ++ /* printk(KERN_NOTICE "unsupported IOCTL: 0x%x\n", i4Cmd); */ ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ /* printk("%ld CMD:0x%x ret:%d\n", jiffies_to_msecs(jiffies), i4Cmd, ret); */ ++ ++ return ret; ++} /* wext_support_ioctl */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To send an event (RAW socket pacekt) to user process actively. ++* ++* \param[in] prGlueInfo Glue layer info. ++* \param[in] u4cmd Whcih event command we want to indicate to user process. ++* \param[in] pData Data buffer to be indicated. ++* \param[in] dataLen Available data size in pData. ++* ++* \return (none) ++* ++* \note Event is indicated to upper layer if cmd is supported and data is valid. ++* Using of kernel symbol wireless_send_event(), which is defined in ++* after WE-14 (2.4.20). ++*/ ++/*----------------------------------------------------------------------------*/ ++void ++wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, ++ IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4dataLen) ++{ ++ union iwreq_data wrqu; ++ unsigned char *pucExtraInfo = NULL; ++#if WIRELESS_EXT >= 15 ++ unsigned char *pucDesiredIE = NULL; ++ unsigned char aucExtraInfoBuf[200]; ++#endif ++#if WIRELESS_EXT < 18 ++ int i; ++#endif ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ switch (u4Cmd) { ++ case SIOCGIWTXPOW: ++ memcpy(&wrqu.power, pucData, u4dataLen); ++ break; ++ case SIOCGIWSCAN: ++ complete_all(&prGlueInfo->rScanComp); ++ break; ++ ++ case SIOCGIWAP: ++ if (pucData) ++ ether_addr_copy((u8 *)&(wrqu.ap_addr.sa_data), pucData); ++ /*memcpy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN);*/ ++ else ++ memset(&wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ break; ++ ++ case IWEVASSOCREQIE: ++#if WIRELESS_EXT < 15 ++ /* under WE-15, no suitable Event can be used */ ++ goto skip_indicate_event; ++#else ++ /* do supplicant a favor, parse to the start of WPA/RSN IE */ ++ if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, &pucDesiredIE)) { ++ /* RSN IE found */ ++ /* Do nothing */ ++#if 0 ++ } else if (wextSrchDesiredWPSIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { ++ /* WPS IE found */ ++ /* Do nothing */ ++#endif ++ } else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { ++ /* WPA IE found */ ++ /* Do nothing*/ ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ } else if (wextSrchDesiredWAPIIE(pucData, u4dataLen, &pucDesiredIE)) { ++ /* WAPI IE found */ ++ /* printk("wextSrchDesiredWAPIIE!!\n"); */ ++#endif ++ } else { ++ /* no WPA/RSN IE found, skip this event */ ++ goto skip_indicate_event; ++ } ++#if WIRELESS_EXT < 18 ++ /* under WE-18, only IWEVCUSTOM can be used */ ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ pucExtraInfo += sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs="); ++ /* printk(KERN_DEBUG "assoc info buffer size needed:%d\n", infoElemLen * 2 + 17); */ ++ /* translate binary string to hex string, requirement of IWEVCUSTOM */ ++ for (i = 0; i < pucDesiredIE[1] + 2; ++i) ++ pucExtraInfo += sprintf(pucExtraInfo, "%02x", pucDesiredIE[i]); ++ pucExtraInfo = aucExtraInfoBuf; ++ wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2; ++#else ++ /* IWEVASSOCREQIE, indicate binary string */ ++ pucExtraInfo = pucDesiredIE; ++ wrqu.data.length = pucDesiredIE[1] + 2; ++#endif ++#endif /* WIRELESS_EXT < 15 */ ++ break; ++ ++ case IWEVMICHAELMICFAILURE: ++#if WIRELESS_EXT < 15 ++ /* under WE-15, no suitable Event can be used */ ++ goto skip_indicate_event; ++#else ++ if (pucData) { ++ P_PARAM_AUTH_REQUEST_T pAuthReq = (P_PARAM_AUTH_REQUEST_T) pucData; ++ /* under WE-18, only IWEVCUSTOM can be used */ ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ pucExtraInfo += sprintf(pucExtraInfo, "MLME-MICHAELMICFAILURE.indication "); ++ pucExtraInfo += sprintf(pucExtraInfo, ++ "%s", ++ (pAuthReq->u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR) ? ++ "groupcast " : "unicast "); ++ ++ wrqu.data.length = pucExtraInfo - aucExtraInfoBuf; ++ pucExtraInfo = aucExtraInfoBuf; ++ } ++#endif /* WIRELESS_EXT < 15 */ ++ break; ++ ++ case IWEVPMKIDCAND: ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2 && ++ prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) { ++ ++ /* only used in WPA2 */ ++#if WIRELESS_EXT >= 18 ++ P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T) pucData; ++ ++ struct iw_pmkid_cand rPmkidCand; ++ ++ pucExtraInfo = aucExtraInfoBuf; ++ ++ rPmkidCand.flags = prPmkidCand->u4Flags; ++ rPmkidCand.index = 0; ++ rPmkidCand.bssid.sa_family = 0; ++ kalMemCopy(rPmkidCand.bssid.sa_data, prPmkidCand->arBSSID, 6); ++ ++ kalMemCopy(pucExtraInfo, (PUINT_8) &rPmkidCand, sizeof(struct iw_pmkid_cand)); ++ wrqu.data.length = sizeof(struct iw_pmkid_cand); ++ ++ /* pmkid canadidate list is supported after WE-18 */ ++ /* indicate struct iw_pmkid_cand */ ++#else ++ /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, WE < 18\n"); */ ++ goto skip_indicate_event; ++#endif ++ } else { ++ /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, NOT WPA2\n"); */ ++ goto skip_indicate_event; ++ } ++ break; ++ ++ case IWEVCUSTOM: ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T)); ++ wrqu.data.length = sizeof(PTA_IPC_T); ++ break; ++ ++ default: ++ /* printk(KERN_INFO "Unsupported wext event:%x\n", cmd); */ ++ goto skip_indicate_event; ++ } ++ ++ /* Send event to user space */ ++ wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, pucExtraInfo); ++ ++skip_indicate_event: ++ return; ++} /* wext_indicate_wext_event */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, to get the network interface statistical ++* information. ++* ++* Whenever an application needs to get statistics for the interface, this method ++* is called. This happens, for example, when ifconfig or netstat -i is run. ++* ++* \param[in] pDev Pointer to struct net_device. ++* ++* \return net_device_stats buffer pointer. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev) ++{ ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_statistics *pStats = NULL; ++ INT_32 i4Rssi; ++ UINT_32 bufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) ++ goto stat_out; ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); ++ ++ if (!prDev || !netif_carrier_ok(prDev)) { ++ /* network not connected */ ++ goto stat_out; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, FALSE, &bufLen); ++ ++stat_out: ++ return pStats; ++} /* wlan_get_wireless_stats */ ++ ++ ++#endif /* WIRELESS_EXT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c +new file mode 100644 +index 000000000000..2b6c3df84594 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c +@@ -0,0 +1,3142 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext_priv.c#4 ++*/ ++ ++/*! \file gl_wext_priv.c ++ \brief This file includes private ioctl support. ++*/ ++ ++/* ++** Log: gl_wext_priv.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 20 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * [WCXRP00001202] [MT6628 Wi-Fi][FW] Adding the New PN init code ++ * use return to avoid the ioctl return not supported ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 11 02 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Fixed typo. ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 26 2011 wh.su ++ * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux ++ * adding the SW cmd ioctl support, use set/get structure ioctl. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Adjust OID order. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Support set PS profile and set WMM-PS related iwpriv. ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * correct typo for NVRAM access. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable OID_CUSTOM_MTK_WIFI_TEST for RFTest & META tool ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix private ioctl for rftest ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++** \main\maintrunk.MT5921\32 2009-10-08 10:33:25 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\31 2009-09-29 16:46:21 GMT mtk01090 ++** Remove unused functions ++** \main\maintrunk.MT5921\30 2009-09-29 14:46:47 GMT mtk01090 ++** Fix compile warning ++** \main\maintrunk.MT5921\29 2009-09-29 14:28:48 GMT mtk01090 ++** Fix compile warning ++** \main\maintrunk.MT5921\28 2009-09-28 22:21:38 GMT mtk01090 ++** Refine lines to suppress compile warning ++** \main\maintrunk.MT5921\27 2009-09-28 20:19:14 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\26 2009-08-18 22:56:53 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\25 2009-05-07 22:26:15 GMT mtk01089 ++** Add mandatory and private IO control for Linux BWCS ++** \main\maintrunk.MT5921\24 2009-04-29 10:07:05 GMT mtk01088 ++** fixed the compiling error at linux ++** \main\maintrunk.MT5921\23 2009-04-24 09:09:45 GMT mtk01088 ++** mark the code not used at linux supplicant v0.6.7 ++** \main\maintrunk.MT5921\22 2008-11-24 21:03:51 GMT mtk01425 ++** 1. Add PTA_ENABLED flag ++** \main\maintrunk.MT5921\21 2008-08-29 14:55:59 GMT mtk01088 ++** adjust the code for meet the coding style, and add assert check ++** \main\maintrunk.MT5921\20 2008-07-16 15:23:20 GMT mtk01104 ++** Support GPIO2 mode ++** \main\maintrunk.MT5921\19 2008-07-15 17:43:11 GMT mtk01084 ++** modify variable name ++** \main\maintrunk.MT5921\18 2008-07-14 14:37:58 GMT mtk01104 ++** Add exception handle about length in function priv_set_struct() ++** \main\maintrunk.MT5921\17 2008-07-14 13:55:32 GMT mtk01104 ++** Support PRIV_CMD_BT_COEXIST ++** \main\maintrunk.MT5921\16 2008-07-09 00:20:15 GMT mtk01461 ++** Add priv oid to support WMM_PS_TEST ++** \main\maintrunk.MT5921\15 2008-06-02 11:15:22 GMT mtk01461 ++** Update after wlanoidSetPowerMode changed ++** \main\maintrunk.MT5921\14 2008-05-30 19:31:07 GMT mtk01461 ++** Add IOCTL for Power Mode ++** \main\maintrunk.MT5921\13 2008-05-30 18:57:15 GMT mtk01461 ++** Not use wlanoidSetCSUMOffloadForLinux() ++** \main\maintrunk.MT5921\12 2008-05-30 15:13:18 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\11 2008-05-29 14:16:31 GMT mtk01084 ++** rename for wlanoidSetBeaconIntervalForLinux ++** \main\maintrunk.MT5921\10 2008-04-17 23:06:37 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\9 2008-03-31 21:00:55 GMT mtk01461 ++** Add priv IOCTL for VOIP setting ++** \main\maintrunk.MT5921\8 2008-03-31 13:49:43 GMT mtk01461 ++** Add priv ioctl to turn on / off roaming ++** \main\maintrunk.MT5921\7 2008-03-26 15:35:14 GMT mtk01461 ++** Add CSUM offload priv ioctl for Linux ++** \main\maintrunk.MT5921\6 2008-03-11 14:50:59 GMT mtk01461 ++** Unify priv ioctl ++** \main\maintrunk.MT5921\5 2007-11-06 19:32:30 GMT mtk01088 ++** add WPS code ++** \main\maintrunk.MT5921\4 2007-10-30 12:01:39 GMT MTK01425 ++** 1. Update wlanQueryInformation and wlanSetInformation ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#include "gl_os.h" ++#include "gl_wext_priv.h" ++#if CFG_SUPPORT_WAPI ++#include "gl_sec.h" ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_os.h" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define NUM_SUPPORTED_OIDS (sizeof(arWlanOidReqTable) / sizeof(WLAN_REQ_ENTRY)) ++#define CMD_START "START" ++#define CMD_STOP "STOP" ++#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" ++#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" ++#define CMD_RSSI "RSSI" ++#define CMD_LINKSPEED "LINKSPEED" ++#define CMD_RXFILTER_START "RXFILTER-START" ++#define CMD_RXFILTER_STOP "RXFILTER-STOP" ++#define CMD_RXFILTER_ADD "RXFILTER-ADD" ++#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" ++#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" ++#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" ++#define CMD_BTCOEXMODE "BTCOEXMODE" ++#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" ++#define CMD_SETFWPATH "SETFWPATH" ++#define CMD_SETBAND "SETBAND" ++#define CMD_GETBAND "GETBAND" ++#define CMD_COUNTRY "COUNTRY" ++#define CMD_P2P_SET_NOA "P2P_SET_NOA" ++#define CMD_P2P_GET_NOA "P2P_GET_NOA" ++#define CMD_P2P_SET_PS "P2P_SET_PS" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETROAMMODE "SETROAMMODE" ++#define CMD_MIRACAST "MIRACAST" ++ ++#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" ++#define CMD_PNOSETUP_SET "PNOSETUP " ++#define CMD_PNOENABLE_SET "PNOFORCE" ++#define CMD_PNODEBUG_SET "PNODEBUG" ++#define CMD_WLS_BATCHING "WLS_BATCHING" ++ ++#define CMD_OKC_SET_PMK "SET_PMK" ++#define CMD_OKC_ENABLE "OKC_ENABLE" ++ ++/* miracast related definition */ ++#define MIRACAST_MODE_OFF 0 ++#define MIRACAST_MODE_SOURCE 1 ++#define MIRACAST_MODE_SINK 2 ++ ++#ifndef MIRACAST_AMPDU_SIZE ++#define MIRACAST_AMPDU_SIZE 8 ++#endif ++ ++#ifndef MIRACAST_MCHAN_ALGO ++#define MIRACAST_MCHAN_ALGO 1 ++#endif ++ ++#ifndef MIRACAST_MCHAN_BW ++#define MIRACAST_MCHAN_BW 25 ++#endif ++ ++#define CMD_BAND_AUTO 0 ++#define CMD_BAND_5G 1 ++#define CMD_BAND_2G 2 ++#define CMD_BAND_ALL 3 ++ ++/* Mediatek private command */ ++ ++#define CMD_SET_SW_CTRL "SET_SW_CTRL" ++#define CMD_GET_SW_CTRL "GET_SW_CTRL" ++#define CMD_SET_CFG "SET_CFG" ++#define CMD_GET_CFG "GET_CFG" ++#define CMD_SET_CHIP "SET_CHIP" ++#define CMD_GET_CHIP "GET_CHIP" ++#define CMD_SET_DBG_LEVEL "SET_DBG_LEVEL" ++#define CMD_GET_DBG_LEVEL "GET_DBG_LEVEL" ++#define PRIV_CMD_SIZE 512 ++ ++static UINT_32 g_ucMiracastMode = MIRACAST_MODE_OFF; ++ ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subver; ++ char reserved; ++} cmd_tlv_t; ++ ++typedef struct priv_driver_cmd_s { ++ char buf[PRIV_CMD_SIZE]; ++ int used_len; ++ int total_len; ++} priv_driver_cmd_t; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++#define CMD_BATCH_SET "WLS_BATCHING SET" ++#define CMD_BATCH_GET "WLS_BATCHING GET" ++#define CMD_BATCH_STOP "WLS_BATCHING STOP" ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static int ++priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); ++ ++static int ++priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); ++ ++#if 0 /* CFG_SUPPORT_WPS */ ++static int ++priv_set_appie(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); ++ ++static int ++priv_set_filter(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); ++#endif /* CFG_SUPPORT_WPS */ ++ ++static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY * ppWlanReqEntry); ++ ++#if 0 ++static WLAN_STATUS ++reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++static WLAN_STATUS ++reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++static WLAN_STATUS ++reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static UINT_8 aucOidBuf[4096] = { 0 }; ++ ++/* OID processing table */ ++/* Order is important here because the OIDs should be in order of ++ increasing value for binary searching. */ ++static WLAN_REQ_ENTRY arWlanOidReqTable[] = { ++ /* ++ {(NDIS_OID)rOid, ++ (PUINT_8)pucOidName, ++ fgQryBufLenChecking, fgSetBufLenChecking, fgIsHandleInGlueLayerOnly, u4InfoBufLen, ++ pfOidQueryHandler, ++ pfOidSetHandler} ++ */ ++ /* General Operational Characteristics */ ++ ++ /* Ethernet Operational Characteristics */ ++ {OID_802_3_CURRENT_ADDRESS, ++ DISP_STRING("OID_802_3_CURRENT_ADDRESS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 6, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCurrentAddr, ++ NULL}, ++ ++ /* OID_802_3_MULTICAST_LIST */ ++ /* OID_802_3_MAXIMUM_LIST_SIZE */ ++ /* Ethernet Statistics */ ++ ++ /* NDIS 802.11 Wireless LAN OIDs */ ++ {OID_802_11_SUPPORTED_RATES, ++ DISP_STRING("OID_802_11_SUPPORTED_RATES"), ++ TRUE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_RATES_EX), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySupportedRates, ++ NULL} ++ , ++ /* ++ {OID_802_11_CONFIGURATION, ++ DISP_STRING("OID_802_11_CONFIGURATION"), ++ TRUE, TRUE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_802_11_CONFIG_T), ++ (PFN_OID_HANDLER_FUNC_REQ)reqExtQueryConfiguration, ++ (PFN_OID_HANDLER_FUNC_REQ)reqExtSetConfiguration}, ++ */ ++ {OID_PNP_SET_POWER, ++ DISP_STRING("OID_PNP_SET_POWER"), ++ TRUE, FALSE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_DEVICE_POWER_STATE), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) reqExtSetAcpiDevicePowerState} ++ , ++ ++ /* Custom OIDs */ ++ {OID_CUSTOM_OID_INTERFACE_VERSION, ++ DISP_STRING("OID_CUSTOM_OID_INTERFACE_VERSION"), ++ TRUE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryOidInterfaceVersion, ++ NULL} ++ , ++ ++ /* ++ #if PTA_ENABLED ++ {OID_CUSTOM_BT_COEXIST_CTRL, ++ DISP_STRING("OID_CUSTOM_BT_COEXIST_CTRL"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_BT_COEXIST_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtCoexistCtrl}, ++ #endif ++ */ ++ ++ /* ++ {OID_CUSTOM_POWER_MANAGEMENT_PROFILE, ++ DISP_STRING("OID_CUSTOM_POWER_MANAGEMENT_PROFILE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPwrMgmtProfParam, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPwrMgmtProfParam}, ++ {OID_CUSTOM_PATTERN_CONFIG, ++ DISP_STRING("OID_CUSTOM_PATTERN_CONFIG"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_PATTERN_SEARCH_CONFIG_STRUCT_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPatternConfig}, ++ {OID_CUSTOM_BG_SSID_SEARCH_CONFIG, ++ DISP_STRING("OID_CUSTOM_BG_SSID_SEARCH_CONFIG"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBgSsidParam}, ++ {OID_CUSTOM_VOIP_SETUP, ++ DISP_STRING("OID_CUSTOM_VOIP_SETUP"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryVoipConnectionStatus, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetVoipConnectionStatus}, ++ {OID_CUSTOM_ADD_TS, ++ DISP_STRING("OID_CUSTOM_ADD_TS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidAddTS}, ++ {OID_CUSTOM_DEL_TS, ++ DISP_STRING("OID_CUSTOM_DEL_TS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidDelTS}, ++ */ ++ ++ /* ++ #if CFG_LP_PATTERN_SEARCH_SLT ++ {OID_CUSTOM_SLT, ++ DISP_STRING("OID_CUSTOM_SLT"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySltResult, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSltMode}, ++ #endif ++ ++ {OID_CUSTOM_ROAMING_EN, ++ DISP_STRING("OID_CUSTOM_ROAMING_EN"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRoamingFunction, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetRoamingFunction}, ++ {OID_CUSTOM_WMM_PS_TEST, ++ DISP_STRING("OID_CUSTOM_WMM_PS_TEST"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWiFiWmmPsTest}, ++ {OID_CUSTOM_COUNTRY_STRING, ++ DISP_STRING("OID_CUSTOM_COUNTRY_STRING"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentCountry, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetCurrentCountry}, ++ ++ #if CFG_SUPPORT_802_11D ++ {OID_CUSTOM_MULTI_DOMAIN_CAPABILITY, ++ DISP_STRING("OID_CUSTOM_MULTI_DOMAIN_CAPABILITY"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMultiDomainCap, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMultiDomainCap}, ++ #endif ++ ++ {OID_CUSTOM_GPIO2_MODE, ++ DISP_STRING("OID_CUSTOM_GPIO2_MODE"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_PARAM_GPIO2_MODE_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetGPIO2Mode}, ++ {OID_CUSTOM_CONTINUOUS_POLL, ++ DISP_STRING("OID_CUSTOM_CONTINUOUS_POLL"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CONTINUOUS_POLL_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryContinuousPollInterval, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetContinuousPollProfile}, ++ {OID_CUSTOM_DISABLE_BEACON_DETECTION, ++ DISP_STRING("OID_CUSTOM_DISABLE_BEACON_DETECTION"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryDisableBeaconDetectionFunc, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisableBeaconDetectionFunc}, ++ */ ++ ++ /* WPS */ ++ /* ++ {OID_CUSTOM_DISABLE_PRIVACY_CHECK, ++ DISP_STRING("OID_CUSTOM_DISABLE_PRIVACY_CHECK"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisablePriavcyCheck}, ++ */ ++ ++ {OID_CUSTOM_MCR_RW, ++ DISP_STRING("OID_CUSTOM_MCR_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMcrRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetMcrWrite} ++ , ++ ++ {OID_CUSTOM_EEPROM_RW, ++ DISP_STRING("OID_CUSTOM_EEPROM_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetEepromWrite} ++ , ++ ++ {OID_CUSTOM_SW_CTRL, ++ DISP_STRING("OID_CUSTOM_SW_CTRL"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySwCtrlRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetSwCtrlWrite} ++ , ++ ++ {OID_CUSTOM_MEM_DUMP, ++ DISP_STRING("OID_CUSTOM_MEM_DUMP"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMemDump, ++ NULL} ++ , ++ ++ {OID_CUSTOM_TEST_MODE, ++ DISP_STRING("OID_CUSTOM_TEST_MODE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetTestMode} ++ , ++ ++ /* ++ {OID_CUSTOM_TEST_RX_STATUS, ++ DISP_STRING("OID_CUSTOM_TEST_RX_STATUS"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestRxStatus, ++ NULL}, ++ {OID_CUSTOM_TEST_TX_STATUS, ++ DISP_STRING("OID_CUSTOM_TEST_TX_STATUS"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestTxStatus, ++ NULL}, ++ */ ++ {OID_CUSTOM_ABORT_TEST_MODE, ++ DISP_STRING("OID_CUSTOM_ABORT_TEST_MODE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAbortTestMode} ++ , ++ {OID_CUSTOM_MTK_WIFI_TEST, ++ DISP_STRING("OID_CUSTOM_MTK_WIFI_TEST"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestQueryAutoTest, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAutoTest} ++ , ++ ++ /* OID_CUSTOM_EMULATION_VERSION_CONTROL */ ++ ++ /* BWCS */ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ {OID_CUSTOM_BWCS_CMD, ++ DISP_STRING("OID_CUSTOM_BWCS_CMD"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PTA_IPC_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryBT, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetBT} ++ , ++#endif ++ ++/* {OID_CUSTOM_SINGLE_ANTENNA, ++ DISP_STRING("OID_CUSTOM_SINGLE_ANTENNA"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBtSingleAntenna, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtSingleAntenna}, ++ {OID_CUSTOM_SET_PTA, ++ DISP_STRING("OID_CUSTOM_SET_PTA"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPta, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPta}, ++ */ ++ ++ {OID_CUSTOM_MTK_NVRAM_RW, ++ DISP_STRING("OID_CUSTOM_MTK_NVRAM_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryNvramRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetNvramWrite} ++ , ++ ++ {OID_CUSTOM_CFG_SRC_TYPE, ++ DISP_STRING("OID_CUSTOM_CFG_SRC_TYPE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_CFG_SRC_TYPE_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCfgSrcType, ++ NULL} ++ , ++ ++ {OID_CUSTOM_EEPROM_TYPE, ++ DISP_STRING("OID_CUSTOM_EEPROM_TYPE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_EEPROM_TYPE_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromType, ++ NULL} ++ , ++ ++#if CFG_SUPPORT_WAPI ++ {OID_802_11_WAPI_MODE, ++ DISP_STRING("OID_802_11_WAPI_MODE"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiMode} ++ , ++ {OID_802_11_WAPI_ASSOC_INFO, ++ DISP_STRING("OID_802_11_WAPI_ASSOC_INFO"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiAssocInfo} ++ , ++ {OID_802_11_SET_WAPI_KEY, ++ DISP_STRING("OID_802_11_SET_WAPI_KEY"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_WPI_KEY_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiKey} ++ , ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++ {OID_802_11_WSC_ASSOC_INFO, ++ DISP_STRING("OID_802_11_WSC_ASSOC_INFO"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWSCAssocInfo} ++ , ++#endif ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dispatching function for private ioctl region (SIOCIWFIRSTPRIV ~ ++* SIOCIWLASTPRIV). ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIfReq Pointer to ifreq structure. ++* \param[in] i4Cmd Command ID between SIOCIWFIRSTPRIV and SIOCIWLASTPRIV. ++* ++* \retval 0 for success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++int priv_support_ioctl(IN struct net_device *prNetDev, IN OUT struct ifreq *prIfReq, IN int i4Cmd) ++{ ++ /* prIfReq is verified in the caller function wlanDoIOCTL() */ ++ struct iwreq *prIwReq = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ ++ /* prDev is verified in the caller function wlanDoIOCTL() */ ++ ++ /* Prepare the call */ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case IOCTL_SET_INT: ++ /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ ++ return priv_set_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); ++ ++ case IOCTL_GET_INT: ++ /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ ++ return priv_get_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); ++ ++ case IOCTL_SET_STRUCT: ++ case IOCTL_SET_STRUCT_FOR_EM: ++ return priv_set_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); ++ ++ case IOCTL_GET_STRUCT: ++ return priv_get_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); ++ ++ default: ++ return -EOPNOTSUPP; ++ ++ } /* end of switch */ ++ ++} /* priv_support_ioctl */ ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++EVENT_BATCH_RESULT_T g_rEventBatchResult[CFG_BATCH_MAX_MSCAN]; ++ ++UINT_32 batchChannelNum2Freq(UINT_32 u4ChannelNum) ++{ ++ UINT_32 u4ChannelInMHz; ++ ++ if (u4ChannelNum >= 1 && u4ChannelNum <= 13) ++ u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; ++ else if (u4ChannelNum == 14) ++ u4ChannelInMHz = 2484; ++ else if (u4ChannelNum == 133) ++ u4ChannelInMHz = 3665; /* 802.11y */ ++ else if (u4ChannelNum == 137) ++ u4ChannelInMHz = 3685; /* 802.11y */ ++ else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) ++ u4ChannelInMHz = 5000 + u4ChannelNum * 5; ++ else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) ++ u4ChannelInMHz = 4000 + u4ChannelNum * 5; ++ else ++ u4ChannelInMHz = 0; ++ ++ return u4ChannelInMHz; ++} ++ ++#define TMP_TEXT_LEN_S 40 ++#define TMP_TEXT_LEN_L 60 ++static UCHAR text1[TMP_TEXT_LEN_S], text2[TMP_TEXT_LEN_L], text3[TMP_TEXT_LEN_L]; /* A safe len */ ++ ++WLAN_STATUS ++batchConvertResult(IN P_EVENT_BATCH_RESULT_T prEventBatchResult, ++ OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) ++{ ++ CHAR *p = pvBuffer; ++ CHAR ssid[ELEM_MAX_LEN_SSID + 1]; ++ INT_32 nsize = 0, nsize1, nsize2, nsize3, scancount; ++ INT_32 i, j, nleft; ++ UINT_32 freq; ++ ++ P_EVENT_BATCH_RESULT_ENTRY_T prEntry; ++ P_EVENT_BATCH_RESULT_T pBr; ++ ++ nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ ++ ++ pBr = prEventBatchResult; ++ scancount = 0; ++ for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { ++ scancount += pBr->ucScanCount; ++ pBr++; ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "scancount=%x\nnextcount=%x\n", scancount, scancount); ++ if (nsize1 < nleft) { ++ p += nsize1 = kalSprintf(p, "%s", text1); ++ nleft -= nsize1; ++ } else ++ goto short_buf; ++ ++ pBr = prEventBatchResult; ++ for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { ++ DBGLOG(SCN, TRACE, "convert mscan = %d, apcount=%d, nleft=%d\n", j, pBr->ucScanCount, nleft); ++ ++ if (pBr->ucScanCount == 0) { ++ pBr++; ++ continue; ++ } ++ ++ nleft -= 5; /* -5 for "####\n" */ ++ ++ /* We only support one round scan result now. */ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "apcount=%d\n", pBr->ucScanCount); ++ if (nsize1 < nleft) { ++ p += nsize1 = kalSprintf(p, "%s", text1); ++ nleft -= nsize1; ++ } else ++ goto short_buf; ++ ++ for (i = 0; i < pBr->ucScanCount; i++) { ++ prEntry = &pBr->arBatchResult[i]; ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "bssid=" MACSTR "\n", ++ prEntry->aucBssid[0], ++ prEntry->aucBssid[1], ++ prEntry->aucBssid[2], ++ prEntry->aucBssid[3], ++ prEntry->aucBssid[4], prEntry->aucBssid[5]); ++ ++ kalMemCopy(ssid, ++ prEntry->aucSSID, ++ (prEntry->ucSSIDLen < ELEM_MAX_LEN_SSID ? prEntry->ucSSIDLen : ELEM_MAX_LEN_SSID)); ++ ssid[(prEntry->ucSSIDLen < ++ (ELEM_MAX_LEN_SSID - 1) ? prEntry->ucSSIDLen : (ELEM_MAX_LEN_SSID - 1))] = '\0'; ++ nsize2 = kalSnprintf(text2, TMP_TEXT_LEN_L, "ssid=%s\n", ssid); ++ ++ freq = batchChannelNum2Freq(prEntry->ucFreq); ++ nsize3 = ++ kalSnprintf(text3, TMP_TEXT_LEN_L, ++ "freq=%u\nlevel=%d\ndist=%u\ndistSd=%u\n====\n", freq, ++ prEntry->cRssi, prEntry->u4Dist, prEntry->u4Distsd); ++ ++ nsize = nsize1 + nsize2 + nsize3; ++ if (nsize < nleft) { ++ ++ kalStrnCpy(p, text1, TMP_TEXT_LEN_S); ++ p += nsize1; ++ ++ kalStrnCpy(p, text2, TMP_TEXT_LEN_L); ++ p += nsize2; ++ ++ kalStrnCpy(p, text3, TMP_TEXT_LEN_L); ++ p += nsize3; ++ ++ nleft -= nsize; ++ } else { ++ DBGLOG(SCN, TRACE, "Warning: Early break! (%d)\n", i); ++ break; /* discard following entries, TODO: apcount? */ ++ } ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "####\n"); ++ p += kalSprintf(p, "%s", text1); ++ ++ pBr++; ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "----\n"); ++ kalSprintf(p, "%s", text1); ++ ++ *pu4RetLen = u4MaxBufferLen - nleft; ++ DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++short_buf: ++ DBGLOG(SCN, TRACE, ++ "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), ++ u4MaxBufferLen, (char *)pvBuffer); ++ return WLAN_STATUS_INVALID_LENGTH; ++} ++#endif ++ ++#if CFG_SUPPORT_GET_CH_ENV ++WLAN_STATUS ++scanEnvResult(P_GLUE_INFO_T prGlueInfo, OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ CHAR *p = pvBuffer; ++ INT_32 nsize; ++ INT_32 i, nleft; ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ CH_ENV_T chEnvInfo[54]; /* 54: from FW define; TODO: sync MAXIMUM_OPERATION_CHANNEL_LIST */ ++ UINT_32 i4GetCh = 0; ++ INT_32 i4Argc = 0; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; ++ UINT_8 ucTextLen = 40; ++ UCHAR text[ucTextLen]; ++ INT_32 u4Ret; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ kalMemZero(chEnvInfo, sizeof(chEnvInfo)); ++ ++ DBGLOG(SCN, TRACE, "pvBuffer:%s, pu4RetLen:%d\n", (char *)pvBuffer, *pu4RetLen); ++ ++ wlanCfgParseArgument(pvBuffer, &i4Argc, apcArgv); ++ DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); ++ ++ if (i4Argc >= 2) { ++ u4Ret = kalkStrtou32(apcArgv[1], 0, &i4GetCh); ++ if (u4Ret) ++ DBGLOG(SCN, TRACE, "parse pvBuffer error u4Ret=%d\n", u4Ret); ++ /* i4GetCh = kalStrtoul(apcArgv[1], NULL, 0); */ ++ } ++ ++ nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ ++ ++ nsize = kalSnprintf(text, ucTextLen, "%s", "scanEnvResult\nResult:1\n");/* Always return 1 for alpha version. */ ++ ++ if (nsize < nleft) { ++ p += nsize = kalSnprintf(p, ucTextLen, "%s", text); ++ nleft -= nsize; ++ } else ++ goto short_buf; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->ucChannelNum > 0) { ++ if (prBssDesc->ucChannelNum <= 14) { /* 1~14 */ ++ chEnvInfo[prBssDesc->ucChannelNum - 1].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum - 1].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 64) { /* 15~22 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 116) { /* 23~27 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 140) { /* 28~30 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 165) { /* 31~35 */ ++ chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucApNum++; ++ } ++ } ++ } ++ ++ for (i = 0; i < 54; i++) { ++ if (chEnvInfo[i].ucChNum != 0) { ++ if (i4GetCh == 0 || (chEnvInfo[i].ucChNum == (UINT_8)i4GetCh)) { ++ DBGLOG(SCN, TRACE, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, chEnvInfo[i].ucApNum); ++ p += nsize = ++ kalSnprintf(p, ucTextLen, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, ++ chEnvInfo[i].ucApNum); ++ nleft -= nsize; ++ } ++ } ++ } ++ ++ p += nsize = kalSnprintf(p, ucTextLen, "%s", "----\n"); ++ nleft -= nsize; ++ ++ *pu4RetLen = u4MaxBufferLen - nleft; ++ DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++short_buf: ++ DBGLOG(SCN, TRACE, "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), u4MaxBufferLen, p); ++ return WLAN_STATUS_INVALID_LENGTH; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set int handler. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. ++* \param[in] pcExtra The buffer with input value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ PUINT_32 pu4IntBuf; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4BufLen = 0; ++ int status = 0; ++ P_PTA_IPC_T prPtaIpc; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->mode; ++ pu4IntBuf = (PUINT_32) pcExtra; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_TEST_MODE: ++ /* printk("TestMode=%ld\n", pu4IntBuf[1]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY) { ++ prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_MODE; ++ } else if (pu4IntBuf[1] == 0) { ++ prNdisReq->ndisOidCmd = OID_CUSTOM_ABORT_TEST_MODE; ++ } else { ++ status = 0; ++ break; ++ } ++ prNdisReq->inNdisOidlength = 0; ++ prNdisReq->outNdisOidLength = 0; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++ case PRIV_CMD_TEST_CMD: ++ /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++#if CFG_SUPPORT_PRIV_MCR_RW ++ case PRIV_CMD_ACCESS_MCR: ++ /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) ++ prGlueInfo->fgMcrAccessAllowed = TRUE; ++ status = 0; ++ break; ++ } ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++#endif ++ ++ case PRIV_CMD_SW_CTRL: ++ /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++#if 0 ++ case PRIV_CMD_BEACON_PERIOD: ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetBeaconInterval, ++ (PVOID)&pu4IntBuf[1],/* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), &u4BufLen); ++ break; ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ case PRIV_CMD_CSUM_OFFLOAD: ++ { ++ UINT_32 u4CSUMFlags; ++ ++ if (pu4IntBuf[1] == 1) ++ u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; ++ else if (pu4IntBuf[1] == 0) ++ u4CSUMFlags = 0; ++ else ++ return -EINVAL; ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetCSUMOffload, ++ (PVOID)&u4CSUMFlags, ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { ++ if (pu4IntBuf[1] == 1) ++ prNetDev->features |= NETIF_F_HW_CSUM; ++ else if (pu4IntBuf[1] == 0) ++ prNetDev->features &= ~NETIF_F_HW_CSUM; ++ } ++ } ++ break; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ case PRIV_CMD_POWER_MODE: ++ kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, ++ (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ break; ++ ++ case PRIV_CMD_WMM_PS: ++ { ++ PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T rWmmPsTest; ++ ++ rWmmPsTest.bmfgApsdEnAc = (UINT_8) pu4IntBuf[1]; ++ rWmmPsTest.ucIsEnterPsAtOnce = (UINT_8) pu4IntBuf[2]; ++ rWmmPsTest.ucIsDisableUcTrigger = (UINT_8) pu4IntBuf[3]; ++ rWmmPsTest.reserved = 0; ++ ++ kalIoctl(prGlueInfo, ++ wlanoidSetWiFiWmmPsTest, ++ (PVOID)&rWmmPsTest, ++ sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ break; ++ ++#if 0 ++ case PRIV_CMD_ADHOC_MODE: ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetAdHocMode, ++ (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), &u4BufLen); ++ break; ++#endif ++ ++ case PRIV_CUSTOM_BWCS_CMD: ++ ++ DBGLOG(REQ, INFO, "pu4IntBuf[1] = %x, size of PTA_IPC_T = %zu.\n", ++ pu4IntBuf[1], sizeof(PARAM_PTA_IPC_T)); ++ ++ prPtaIpc = (P_PTA_IPC_T) aucOidBuf; ++ prPtaIpc->u.aucBTPParams[0] = (UINT_8) (pu4IntBuf[1] >> 24); ++ prPtaIpc->u.aucBTPParams[1] = (UINT_8) (pu4IntBuf[1] >> 16); ++ prPtaIpc->u.aucBTPParams[2] = (UINT_8) (pu4IntBuf[1] >> 8); ++ prPtaIpc->u.aucBTPParams[3] = (UINT_8) (pu4IntBuf[1]); ++ ++ DBGLOG(REQ, INFO, ++ "BCM BWCS CMD : BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", ++ prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], ++ prPtaIpc->u.aucBTPParams[3]); ++ ++#if 0 ++ status = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++ status = wlanoidSetBT(prGlueInfo->prAdapter, ++ (PVOID)&aucOidBuf[0], sizeof(PARAM_PTA_IPC_T), &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ status = -EFAULT; ++ ++ break; ++ ++ case PRIV_CMD_BAND_CONFIG: ++ { ++ DBGLOG(REQ, INFO, "CMD set_band=%u\n", (UINT_32) pu4IntBuf[1]); ++ } ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case PRIV_CMD_P2P_MODE: ++ { ++ /* no use, move to set_p2p_mode_handler() */ ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ ++ p2pmode.u4Enable = pu4IntBuf[1]; ++ p2pmode.u4Mode = pu4IntBuf[2]; ++ set_p2p_mode_handler(prNetDev, p2pmode); ++#if 0 ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgIsP2PEnding; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ /* avoid remove & p2p off command simultaneously */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2PEnding = g_u4P2PEnding; ++ g_u4P2POnOffing = 1; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ if (fgIsP2PEnding == 1) { ++ /* skip the command if we are removing */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ break; ++ } ++ rSetP2P.u4Enable = pu4IntBuf[1]; ++ rSetP2P.u4Mode = pu4IntBuf[2]; ++ ++ if (!rSetP2P.u4Enable) ++ p2pNetUnregister(prGlueInfo, TRUE); ++ ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ /* ++ Scenario: ++ 1. System enters suspend/resume but not yet enter wlanearlysuspend() ++ or wlanlateresume(); ++ ++ 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() ++ and get g_halt_sem then do glRegisterEarlySuspend() or ++ glUnregisterEarlySuspend(); ++ ++ But system suspend/resume procedure is not yet finished so we ++ suspend; ++ ++ 3. System switches back to do suspend/resume procedure and execute ++ kalIoctl(). But driver does not yet release g_halt_sem so system ++ suspend in wlanearlysuspend() or wlanlateresume(); ++ ++ ==> deadlock occurs. ++ */ ++ if ((!rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { ++ /* fgIsP2PRegistered == TRUE means P2P is enabled */ ++ DBGLOG(P2P, INFO, "p2pEalySuspendReg\n"); ++ p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p remove */ ++ } ++ ++ DBGLOG(P2P, INFO, ++ "wlanoidSetP2pMode 0x%p %d %d\n", &rSetP2P, rSetP2P.u4Enable, rSetP2P.u4Mode); ++ rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, ++ (PVOID)&rSetP2P, /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(P2P, INFO, "wlanoidSetP2pMode ok\n"); ++ ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ if ((rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { ++ /* fgIsP2PRegistered == TRUE means P2P on successfully */ ++ p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p on */ ++ } ++ ++ if (rSetP2P.u4Enable) ++ p2pNetRegister(prGlueInfo, TRUE); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++#endif ++ } ++ break; ++#endif ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ case PRIV_CMD_MET_PROFILING: ++ { ++ /* PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; */ ++ /* rWfdDebugModeInfo.ucWFDDebugMode=(UINT_8)pu4IntBuf[1]; */ ++ /* rWfdDebugModeInfo.u2SNPeriod=(UINT_16)pu4IntBuf[2]; */ ++ /* DBGLOG(REQ, INFO,("WFD Debug Mode:%d Period:%d\n", ++ rWfdDebugModeInfo.ucWFDDebugMode,rWfdDebugModeInfo.u2SNPeriod)); */ ++ prGlueInfo->u8MetProfEnable = (UINT_8) pu4IntBuf[1]; ++ prGlueInfo->u16MetUdpPort = (UINT_16) pu4IntBuf[2]; ++ DBGLOG(REQ, INFO, "MET_PROF: Enable=%d UDP_PORT=%d\n", prGlueInfo->u8MetProfEnable, ++ prGlueInfo->u16MetUdpPort); ++ ++ } ++ break; ++ ++#endif ++ case PRIV_CMD_WFD_DEBUG_CODE: ++ { ++ PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; ++ ++ rWfdDebugModeInfo.ucWFDDebugMode = (UINT_8) pu4IntBuf[1]; ++ rWfdDebugModeInfo.u2SNPeriod = (UINT_16) pu4IntBuf[2]; ++ DBGLOG(REQ, INFO, "WFD Debug Mode:%d Period:%d\n", rWfdDebugModeInfo.ucWFDDebugMode, ++ rWfdDebugModeInfo.u2SNPeriod); ++ kalIoctl(prGlueInfo, wlanoidSetWfdDebugMode, (PVOID)&rWfdDebugModeInfo, ++ sizeof(PARAM_CUSTOM_WFD_DEBUG_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get int handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. ++* \param[out] pcExtra The buffer with put the return value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 gucBufDbgCode[1000]; ++ ++static int ++_priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ PUINT_32 pu4IntBuf; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4BufLen = 0; ++ int status = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->mode; ++ pu4IntBuf = (PUINT_32) pcExtra; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_TEST_CMD: ++ /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ /* ++ if (copy_to_user(prIwReqData->data.pointer, ++ &prNdisReq->ndisOidContent[4], 4)) { ++ printk(KERN_NOTICE "priv_get_int() copy_to_user oidBuf fail(3)\n"); ++ return -EFAULT; ++ } ++ */ ++ } ++ return status; ++ ++#if CFG_SUPPORT_PRIV_MCR_RW ++ case PRIV_CMD_ACCESS_MCR: ++ /* printk("addr=0x%08lx\n", pu4IntBuf[1]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ status = 0; ++ return status; ++ } ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ } ++ return status; ++#endif ++ ++ case PRIV_CMD_DUMP_MEM: ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++#if 1 ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ status = 0; ++ return status; ++ } ++#endif ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MEM_DUMP; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[0]; ++ return status; ++ ++ case PRIV_CMD_SW_CTRL: ++ /* printk(" addr=0x%08lx\n", pu4IntBuf[1]); */ ++ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ } ++ return status; ++ ++#if 0 ++ case PRIV_CMD_BEACON_PERIOD: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryBeaconInterval, ++ (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++ ++ case PRIV_CMD_POWER_MODE: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++ ++ case PRIV_CMD_ADHOC_MODE: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryAdHocMode, (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++#endif ++ ++ case PRIV_CMD_BAND_CONFIG: ++ DBGLOG(REQ, INFO, "CMD get_band=\n"); ++ prIwReqData->mode = 0; ++ return status; ++ ++ default: ++ break; ++ } ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_GET_CH_LIST: ++ { ++ UINT_16 i, j = 0; ++ UINT_8 NumOfChannel = 50; ++ UINT_8 ucMaxChannelNum = 50; ++ INT_32 ch[50]; ++ /*RF_CHANNEL_INFO_T aucChannelList[50];*/ ++ P_RF_CHANNEL_INFO_T paucChannelList; ++ P_RF_CHANNEL_INFO_T ChannelList_t; ++ ++ paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); ++ if (paucChannelList == NULL) { ++ DBGLOG(REQ, INFO, "alloc ChannelList fail\n"); ++ return -EFAULT; ++ } ++ kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); ++ kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); ++ if (NumOfChannel > 50) { ++ ASSERT(0); ++ NumOfChannel = 50; ++ } ++ ++ ChannelList_t = paucChannelList; ++ if (kalIsAPmode(prGlueInfo)) { ++ for (i = 0; i < NumOfChannel; i++) { ++ if ((ChannelList_t->ucChannelNum <= 13) ++ || (ChannelList_t->ucChannelNum == 36 ++ || ChannelList_t->ucChannelNum == 40 ++ || ChannelList_t->ucChannelNum == 44 ++ || ChannelList_t->ucChannelNum == 48)) { ++ ch[j] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ j++; ++ } ++ } ++ } else { ++ for (j = 0; j < NumOfChannel; j++) { ++ ch[j] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ } ++ } ++ ++ kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); ++ ++ prIwReqData->data.length = j; ++ if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) ++ return -EFAULT; ++ else ++ return status; ++ } ++ ++ case PRIV_CMD_GET_BUILD_DATE_CODE: ++ { ++ UINT_8 aucBuffer[16]; ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidQueryBuildDateCode, ++ (PVOID) aucBuffer, ++ sizeof(UINT_8) * 16, TRUE, TRUE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { ++ prIwReqData->data.length = sizeof(UINT_8) * 16; ++ ++ if (copy_to_user(prIwReqData->data.pointer, aucBuffer, prIwReqData->data.length)) ++ return -EFAULT; ++ else ++ return status; ++ } else { ++ return -EFAULT; ++ } ++ } ++ ++ case PRIV_CMD_GET_DEBUG_CODE: ++ { ++ wlanQueryDebugCode(prGlueInfo->prAdapter); ++ ++ kalMemSet(gucBufDbgCode, '.', sizeof(gucBufDbgCode)); ++ if (copy_to_user(prIwReqData->data.pointer, gucBufDbgCode, prIwReqData->data.length)) ++ return -EFAULT; ++ else ++ return status; ++ } ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} /* priv_get_int */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set int array handler. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. ++* \param[in] pcExtra The buffer with input value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd, u4BufLen; ++ P_GLUE_INFO_T prGlueInfo; ++ int status = 0; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_SET_TXPWR_CTRL_T prTxpwr; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_SET_TX_POWER: ++ { ++ INT_32 *setting = prIwReqData->data.pointer; ++ UINT_16 i; ++ ++#if 0 ++ DBGLOG(REQ, INFO, "Tx power num = %d\n", prIwReqData->data.length); ++ ++ DBGLOG(REQ, INFO, "Tx power setting = %d %d %d %d\n", ++ setting[0], setting[1], setting[2], setting[3]); ++#endif ++ prTxpwr = &prGlueInfo->rTxPwr; ++ if (setting[0] == 0 && prIwReqData->data.length == 4 /* argc num */) { ++ /* 0 (All networks), 1 (legacy STA), 2 (Hotspot AP), 3 (P2P), 4 (BT over Wi-Fi) */ ++ if (setting[1] == 1 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GLegacyStaPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GLegacyStaPwrOffset = setting[3]; ++ } ++ if (setting[1] == 2 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GHotspotPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GHotspotPwrOffset = setting[3]; ++ } ++ if (setting[1] == 3 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GP2pPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GP2pPwrOffset = setting[3]; ++ } ++ if (setting[1] == 4 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GBowPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GBowPwrOffset = setting[3]; ++ } ++ } else if (setting[0] == 1 && prIwReqData->data.length == 2) { ++ prTxpwr->ucConcurrencePolicy = setting[1]; ++ } else if (setting[0] == 2 && prIwReqData->data.length == 3) { ++ if (setting[1] == 0) { ++ for (i = 0; i < 14; i++) ++ prTxpwr->acTxPwrLimit2G[i] = setting[2]; ++ } else if (setting[1] <= 14) ++ prTxpwr->acTxPwrLimit2G[setting[1] - 1] = setting[2]; ++ } else if (setting[0] == 3 && prIwReqData->data.length == 3) { ++ if (setting[1] == 0) { ++ for (i = 0; i < 4; i++) ++ prTxpwr->acTxPwrLimit5G[i] = setting[2]; ++ } else if (setting[1] <= 4) ++ prTxpwr->acTxPwrLimit5G[setting[1] - 1] = setting[2]; ++ } else if (setting[0] == 4 && prIwReqData->data.length == 2) { ++ if (setting[1] == 0) ++ wlanDefTxPowerCfg(prGlueInfo->prAdapter); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxPower, ++ prTxpwr, ++ sizeof(SET_TXPWR_CTRL_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ } else ++ return -EFAULT; ++ } ++ return status; ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get int array handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. ++* \param[out] pcExtra The buffer with put the return value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ P_GLUE_INFO_T prGlueInfo; ++ int status = 0; ++ INT_32 ch[50]; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_GET_CH_LIST: ++ { ++ UINT_16 i; ++ UINT_8 NumOfChannel = 50; ++ UINT_8 ucMaxChannelNum = 50; ++ /*RF_CHANNEL_INFO_T aucChannelList[50];*/ ++ P_RF_CHANNEL_INFO_T paucChannelList; ++ P_RF_CHANNEL_INFO_T ChannelList_t; ++ ++ paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); ++ if (paucChannelList == NULL) { ++ DBGLOG(REQ, INFO, "alloc fail\n"); ++ return -EINVAL; ++ } ++ kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); ++ ++ kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); ++ if (NumOfChannel > 50) ++ NumOfChannel = 50; ++ ++ ChannelList_t = paucChannelList; ++ for (i = 0; i < NumOfChannel; i++) { ++ ch[i] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ } ++ ++ kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); ++ prIwReqData->data.length = NumOfChannel; ++ if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) ++ return -EFAULT; ++ else ++ return status; ++ } ++ default: ++ break; ++ } ++ ++ return status; ++} /* priv_get_int */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set structure handler. ++* ++* \param[in] pDev Net device requested. ++* \param[in] prIwReqData Pointer to iwreq_data structure. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd = 0; ++ int status = 0; ++ /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ ++ UINT_32 u4CmdLen = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ PUINT_32 pu4IntBuf = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ /* ASSERT(prIwReqInfo); */ ++ ASSERT(prIwReqData); ++ /* ASSERT(pcExtra); */ ++ ++ kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); ++ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwReqData)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++#endif ++ ++ switch (u4SubCmd) { ++#if 0 /* PTA_ENABLED */ ++ case PRIV_CMD_BT_COEXIST: ++ u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); ++ ASSERT(sizeof(PARAM_CUSTOM_BT_COEXIST_T) >= u4CmdLen); ++ if (sizeof(PARAM_CUSTOM_BT_COEXIST_T) < u4CmdLen) ++ return -EFAULT; ++ ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { ++ status = -EFAULT; /* return -EFAULT; */ ++ break; ++ } ++ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBtCoexistCtrl, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ status = -EFAULT; ++ break; ++#endif ++ ++ case PRIV_CUSTOM_BWCS_CMD: ++ u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); ++ ASSERT(sizeof(PARAM_PTA_IPC_T) >= u4CmdLen); ++ if (sizeof(PARAM_PTA_IPC_T) < u4CmdLen) ++ return -EFAULT; ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(REQ, INFO, ++ "ucCmdLen = %d, size of PTA_IPC_T = %d, prIwReqData->data = 0x%x.\n", u4CmdLen, ++ sizeof(PARAM_PTA_IPC_T), prIwReqData->data); ++ ++ DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%u)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++ ++ DBGLOG(REQ, INFO, "*pcExtra = 0x%x\n", *pcExtra); ++#endif ++ ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { ++ status = -EFAULT; /* return -EFAULT; */ ++ break; ++ } ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(REQ, INFO, "priv_set_struct(): BWCS CMD = %02x%02x%02x%02x\n", ++ aucOidBuf[2], aucOidBuf[3], aucOidBuf[4], aucOidBuf[5]); ++#endif ++ ++#if 0 ++ status = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++#if 1 ++ status = wlanoidSetBT(prGlueInfo->prAdapter, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ status = -EFAULT; ++ ++ break; ++ ++#if CFG_SUPPORT_WPS2 ++ case PRIV_CMD_WSC_PROBE_REQ: ++ { ++ /* retrieve IE for Probe Request */ ++ if (prIwReqData->data.length > 0) { ++ if (copy_from_user(prGlueInfo->aucWSCIE, prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ prGlueInfo->u2WSCIELen = prIwReqData->data.length; ++ } else { ++ prGlueInfo->u2WSCIELen = 0; ++ } ++ } ++ break; ++#endif ++ case PRIV_CMD_OID: ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ if (!kalMemCmp(&aucOidBuf[0], pcExtra, prIwReqData->data.length)) ++ DBGLOG(REQ, INFO, "pcExtra buffer is valid\n"); ++ else ++ DBGLOG(REQ, INFO, "pcExtra 0x%p\n", pcExtra); ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0], &u4BufLen); ++ /* Copy result to user space */ ++ ((P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0])->outNdisOidLength = u4BufLen; ++ ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { ++ DBGLOG(REQ, INFO, "copy_to_user oidBuf fail\n"); ++ status = -EFAULT; ++ } ++ ++ break; ++ ++ case PRIV_CMD_SW_CTRL: ++ pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ /* kalMemCopy(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, 8); */ ++ if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get struct handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] cmd Private sub-command. ++* ++* \retval 0 For success. ++* \retval -EFAULT If copy from user space buffer fail. ++* \retval -EOPNOTSUPP Parameter "cmd" not recognized. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4BufLen = 0; ++ PUINT_32 pu4IntBuf = NULL; ++ int status = 0; ++ ++ kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqData); ++ if (!prNetDev || !prIwReqData) { ++ DBGLOG(REQ, INFO, "priv_get_struct(): invalid param(0x%p, 0x%p)\n", prNetDev, prIwReqData); ++ return -EINVAL; ++ } ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_get_struct(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++#endif ++ memset(aucOidBuf, 0, sizeof(aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, sizeof(NDIS_TRANSPORT_STRUCT))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); ++ return -EFAULT; ++ } ++ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++#if 0 ++ DBGLOG(REQ, INFO, "\n priv_get_struct cmd 0x%02x len:%d OID:0x%08x OID Len:%d\n", ++ cmd, pIwReq->u.data.length, ndisReq->ndisOidCmd, ndisReq->inNdisOidlength); ++#endif ++ if (priv_get_ndis(prNetDev, prNdisReq, &u4BufLen) == 0) { ++ prNdisReq->outNdisOidLength = u4BufLen; ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], ++ u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - ++ sizeof(prNdisReq->ndisOidContent))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(1)\n"); ++ return -EFAULT; ++ } ++ return 0; ++ } ++ prNdisReq->outNdisOidLength = u4BufLen; ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); ++ } ++ return -EFAULT; ++ ++ case PRIV_CMD_SW_CTRL: ++ pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); ++ return -EFAULT; ++ } ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ prNdisReq->outNdisOidLength = u4BufLen; ++ /* printk("len=%d Result=%08lx\n", u4BufLen, *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ ++ if (copy_to_user(prIwReqData->data.pointer, ++ &prNdisReq->ndisOidContent[4], ++ 4 /* OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent) */)) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); ++ } ++ } ++ return 0; ++ ++ default: ++ DBGLOG(REQ, WARN, "get struct cmd:0x%x\n", u4SubCmd); ++ return -EOPNOTSUPP; ++ } ++} /* priv_get_struct */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a set operation for a single OID. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) ++{ ++ P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prNdisReq); ++ ASSERT(pu4OutputLen); ++ ++ if (!prNetDev || !prNdisReq || !pu4OutputLen) { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", ++ prNetDev, prNdisReq, pu4OutputLen); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); ++#endif ++ ++ if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { ++ /* WARNLOG(("Set OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ ++ return -EOPNOTSUPP; ++ } ++ ++ if (NULL == prWlanReqEntry->pfOidSetHandler) { ++ /* WARNLOG(("Set %s: Null set handler\n", prWlanReqEntry->pucOidName)); */ ++ return -EOPNOTSUPP; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_ndis(): %s\n", prWlanReqEntry->pucOidName); ++#endif ++ ++ if (prWlanReqEntry->fgSetBufLenChecking) { ++ if (prNdisReq->inNdisOidlength != prWlanReqEntry->u4InfoBufLen) { ++ DBGLOG(REQ, WARN, "Set %s: Invalid length (current=%u, needed=%u)\n", ++ prWlanReqEntry->pucOidName, ++ prNdisReq->inNdisOidlength, prWlanReqEntry->u4InfoBufLen); ++ ++ *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; ++ return -EINVAL; ++ } ++ } ++ ++ if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { ++ /* GLUE sw info only */ ++ status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4SetInfoLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { ++ /* multiple sw operations */ ++ status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4SetInfoLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { ++ /* driver core */ ++ ++ status = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidSetHandler, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } else { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); ++ return -EOPNOTSUPP; ++ } ++ ++ *pu4OutputLen = u4SetInfoLen; ++ ++ switch (status) { ++ case WLAN_STATUS_SUCCESS: ++ break; ++ ++ case WLAN_STATUS_INVALID_LENGTH: ++ /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* u4SetInfoLen)); */ ++ break; ++ } ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ return -EFAULT; ++ ++ return 0; ++} /* priv_set_ndis */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a query operation for a single OID. Basically we ++* return information about the current state of the OID in question. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL invalid input parameters ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) ++{ ++ P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; ++ UINT_32 u4BufLen = 0; ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prNdisReq); ++ ASSERT(pu4OutputLen); ++ ++ if (!prNetDev || !prNdisReq || !pu4OutputLen) { ++ DBGLOG(REQ, INFO, "priv_get_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", ++ prNetDev, prNdisReq, pu4OutputLen); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_get_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); ++#endif ++ ++ if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { ++ /* WARNLOG(("Query OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ ++ return -EOPNOTSUPP; ++ } ++ ++ if (NULL == prWlanReqEntry->pfOidQueryHandler) { ++ /* WARNLOG(("Query %s: Null query handler\n", prWlanReqEntry->pucOidName)); */ ++ return -EOPNOTSUPP; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_ndis(): %s\n", prWlanReqEntry->pucOidName); ++#endif ++ ++ if (prWlanReqEntry->fgQryBufLenChecking) { ++ if (prNdisReq->inNdisOidlength < prWlanReqEntry->u4InfoBufLen) { ++ /* Not enough room in InformationBuffer. Punt */ ++ /* WARNLOG(("Query %s: Buffer too short (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* prWlanReqEntry->u4InfoBufLen)); */ ++ ++ *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; ++ ++ status = WLAN_STATUS_INVALID_LENGTH; ++ return -EINVAL; ++ } ++ } ++ ++ if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { ++ /* GLUE sw info only */ ++ status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4BufLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { ++ /* multiple sw operations */ ++ status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4BufLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { ++ /* driver core */ ++ ++ status = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidQueryHandler, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ } else { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); ++ return -EOPNOTSUPP; ++ } ++ ++ *pu4OutputLen = u4BufLen; ++ ++ switch (status) { ++ case WLAN_STATUS_SUCCESS: ++ break; ++ ++ case WLAN_STATUS_INVALID_LENGTH: ++ /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* u4BufLen)); */ ++ break; ++ } ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} /* priv_get_ndis */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse command value in a string. ++* ++* @param InStr Pointer to the string buffer. ++* @param OutStr Pointer to the next command value. ++* @param OutLen Record the resident buffer length. ++* ++* @retval Command value. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen) ++{ ++ unsigned char Charc, *Buf; ++ unsigned int Num; ++ int Maxloop; ++ int ReadId; ++ int TotalLen; ++ ++ /* init */ ++ Num = 0; ++ Maxloop = 0; ++ ReadId = 0; ++ Buf = (unsigned char *)InStr; ++ TotalLen = *OutLen; ++ *OutStr = Buf; ++ ++ /* sanity check */ ++ if (Buf[0] == 0x00) ++ return 0; ++ ++ /* check the value is decimal or hex */ ++ if ((Buf[ReadId] == 'x') || ((Buf[ReadId] == '0') && (Buf[ReadId + 1] == 'x'))) { ++ /* skip x or 0x */ ++ if (Buf[ReadId] == 'x') ++ ReadId++; ++ else ++ ReadId += 2; ++ ++ /* translate the hex number */ ++ while (Maxloop++ < 10) { ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc -= 'a'; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc -= 'A'; ++ else ++ break; /* exit the parsing */ ++ Num = Num * 16 + Charc + 10; ++ ReadId++; ++ TotalLen--; ++ } ++ } else { ++ /* translate the decimal number */ ++ while (Maxloop++ < 10) { ++ Charc = Buf[ReadId]; ++ if ((Charc < 0x30) || (Charc > 0x39)) ++ break; /* exit the parsing */ ++ Charc -= 0x30; ++ Num = Num * 10 + Charc; ++ ReadId++; ++ TotalLen--; ++ } ++ } ++ ++ if (Buf[ReadId] == 0x00) ++ *OutStr = &Buf[ReadId]; ++ else ++ *OutStr = &Buf[ReadId + 1]; /* skip the character: _ */ ++ ++ *OutLen = TotalLen - 1; /* skip the character: _ */ ++ return Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse command MAC address in a string. ++* ++* @param InStr Pointer to the string buffer. ++* @param OutStr Pointer to the next command value. ++* @param OutLen Record the resident buffer length. ++* ++* @retval Command value. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac) ++{ ++ unsigned char Charc, *Buf; ++ unsigned int Num; ++ int Maxloop; ++ int ReadId; ++ int TotalLen; ++ ++ /* init */ ++ Num = 0; ++ Maxloop = 0; ++ ReadId = 0; ++ Buf = (unsigned char *)InStr; ++ TotalLen = *OutLen; ++ *OutStr = Buf; ++ ++ /* sanity check */ ++ if (Buf[0] == 0x00) ++ return 0; ++ ++ /* parse MAC */ ++ while (Maxloop < 6) { ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc = Charc - 'a' + 10; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc = Charc - 'A' + 10; ++ else ++ return -1; /* error, exit the parsing */ ++ ++ Num = Charc; ++ ReadId++; ++ TotalLen--; ++ ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc = Charc - 'a' + 10; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc = Charc - 'A' + 10; ++ else ++ return -1; /* error, exit the parsing */ ++ ++ Num = Num * 16 + Charc; ++ ReadId += 2; /* skip the character and ':' */ ++ TotalLen -= 2; ++ ++ OutMac[Maxloop] = Num; ++ Maxloop++; ++ } ++ ++ *OutStr = &Buf[ReadId]; /* skip the character: _ */ ++ *OutLen = TotalLen; /* skip the character: _ */ ++ return Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a set operation for a single OID. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T GlueInfo; ++ INT_32 Status; ++ UINT_32 Subcmd; ++ UINT_8 *InBuf; ++ UINT_32 InBufLen; ++ ++ /* sanity check */ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ /* init */ ++ DBGLOG(REQ, INFO, "priv_set_string (%s)(%d)\n", ++ (UINT8 *) prIwReqData->data.pointer, (INT32) prIwReqData->data.length); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ InBuf = aucOidBuf; ++ InBufLen = prIwReqData->data.length; ++ Status = 0; ++ ++ if (copy_from_user(InBuf, prIwReqData->data.pointer, prIwReqData->data.length)) ++ return -EFAULT; ++ ++ Subcmd = CmdStringDecParse(prIwReqData->data.pointer, &InBuf, &InBufLen); ++ DBGLOG(REQ, INFO, "priv_set_string> command = %u\n", (UINT32) Subcmd); ++ ++ /* handle the command */ ++ switch (Subcmd) { ++#if (CFG_SUPPORT_TDLS == 1) ++ case PRIV_CMD_OTHER_TDLS: ++ TdlsexCmd(GlueInfo, InBuf, InBufLen); ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++ case PRIV_CMD_OTHER_TAR: ++ { ++ rlmCmd(GlueInfo, InBuf, InBufLen); ++ break; ++ } ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ default: ++ break; ++ } ++ ++ return Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search desired OID. ++* ++* \param rOid[in] Desired NDIS_OID ++* \param ppWlanReqEntry[out] Found registered OID entry ++* ++* \retval TRUE: Matched OID is found ++* \retval FALSE: No matched OID is found ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry) ++{ ++ INT_32 i, j, k; ++ ++ i = 0; ++ j = NUM_SUPPORTED_OIDS - 1; ++ ++ while (i <= j) { ++ k = (i + j) / 2; ++ ++ if (rOid == arWlanOidReqTable[k].rOid) { ++ *ppWlanReqEntry = &arWlanOidReqTable[k]; ++ return TRUE; ++ } else if (rOid < arWlanOidReqTable[k].rOid) { ++ j = k - 1; ++ } else { ++ i = k + 1; ++ } ++ } ++ ++ return FALSE; ++} /* reqSearchSupportedOidEntry */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the radio configuration used in IBSS ++* mode and RF test mode. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[out] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_802_11_CONFIG_T prQueryConfig = (P_PARAM_802_11_CONFIG_T) pvQueryBuffer; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ ++ DEBUGFUNC("wlanoidQueryConfiguration"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_CONFIG_T); ++ if (u4QueryBufferLen < sizeof(PARAM_802_11_CONFIG_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvQueryBuffer); ++ ++ kalMemZero(prQueryConfig, sizeof(PARAM_802_11_CONFIG_T)); ++ ++ /* Update the current radio configuration. */ ++ prQueryConfig->u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetBeaconInterval, ++ &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryBeaconInterval, ++ &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQueryAtimWindow, ++ &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryAtimWindow, ++ &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQueryFrequency, ++ &prQueryConfig->u4DSConfig, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryFrequency, ++ &prQueryConfig->u4DSConfig, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++ ++ prQueryConfig->rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ return rStatus; ++ ++} /* end of reqExtQueryConfiguration() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the radio configuration used in IBSS ++* mode. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_802_11_CONFIG_T prNewConfig = (P_PARAM_802_11_CONFIG_T) pvSetBuffer; ++ UINT_32 u4SetInfoLen = 0; ++ ++ DEBUGFUNC("wlanoidSetConfiguration"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_802_11_CONFIG_T); ++ ++ if (u4SetBufferLen < *pu4SetInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* OID_802_11_CONFIGURATION. If associated, NOT_ACCEPTED shall be returned. */ ++ if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ ++ ASSERT(pvSetBuffer); ++ ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetBeaconInterval, ++ &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBeaconInterval, ++ &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetAtimWindow, ++ &prNewConfig->u4ATIMWindow, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetAtimWindow, &prNewConfig->u4ATIMWindow, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetFrequency, ++ &prNewConfig->u4DSConfig, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetFrequency, &prNewConfig->u4DSConfig, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++ ++ return rStatus; ++ ++} /* end of reqExtSetConfiguration() */ ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set beacon detection function enable/disable state ++* This is mainly designed for usage under BT inquiry state (disable function). ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ /* WIFI is enabled, when ACPI is D0 (ParamDeviceStateD0 = 1). And vice versa */ ++ ++ /* rStatus = wlanSetInformation(prGlueInfo->prAdapter, */ ++ /* wlanoidSetAcpiDevicePowerState, */ ++ /* pvSetBuffer, */ ++ /* u4SetBufferLen, */ ++ /* pu4SetInfoLen); */ ++ return rStatus; ++} ++ ++int priv_driver_set_chip_config(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ UINT_32 u4BufLen = 0; ++ INT_32 i4BytesWritten = 0; ++ UINT_32 u4CmdLen = 0; ++ UINT_32 u4PrefixLen = 0; ++ /* INT_32 i4Argc = 0; */ ++ /* PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = {0}; */ ++ ++ PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ prAdapter = prGlueInfo->prAdapter; ++ DBGLOG(REQ, INFO, "priv_driver_set_chip_config command is %s\n", pcCommand); ++ /* wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); */ ++ /* DBGLOG(REQ, LOUD,("argc is %i\n",i4Argc)); */ ++ /* */ ++ u4CmdLen = kalStrnLen(pcCommand, i4TotalLen); ++ u4PrefixLen = kalStrLen(CMD_SET_CHIP) + 1 /*space */; ++ ++ kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); ++ ++ /* if(i4Argc >= 2) { */ ++ if (u4CmdLen > u4PrefixLen) { ++ ++ rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; ++ /* rChipConfigInfo.u2MsgSize = kalStrnLen(apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ ++ rChipConfigInfo.u2MsgSize = u4CmdLen - u4PrefixLen; ++ /* kalStrnCpy(rChipConfigInfo.aucCmd,apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ ++ if (u4PrefixLen <= CHIP_CONFIG_RESP_SIZE) { ++ kalStrnCpy(rChipConfigInfo.aucCmd, pcCommand + u4PrefixLen, ++ CHIP_CONFIG_RESP_SIZE - u4PrefixLen); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetChipConfig, ++ &rChipConfigInfo, ++ sizeof(rChipConfigInfo), FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ } else { ++ ++ DBGLOG(REQ, INFO, "%s: kalIoctl Command Len > %d\n", __func__, CHIP_CONFIG_RESP_SIZE); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, INFO, "%s: kalIoctl ret=%d\n", __func__, rStatus); ++ i4BytesWritten = -1; ++ } ++ } ++ ++ return i4BytesWritten; ++ ++} ++ ++int priv_driver_set_miracast(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 i4BytesWritten = 0; ++ /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ ++ /* UINT_32 u4BufLen = 0; */ ++ INT_32 i4Argc = 0; ++ UINT_32 ucMode = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; ++ INT_32 u4Ret; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); ++ wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); ++ DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ if (i4Argc >= 2) { ++ u4Ret = kalkStrtou32(apcArgv[1], 0, &ucMode); /* ucMode = kalStrtoul(apcArgv[1], NULL, 0); */ ++ if (u4Ret) ++ DBGLOG(REQ, LOUD, "parse pcCommand error u4Ret=%d\n", u4Ret); ++ ++ if (g_ucMiracastMode == ucMode) ++ ; ++ /* XXX: continue or skip */ ++ ++ g_ucMiracastMode = ucMode; ++ prMsgWfdCfgUpdate = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); ++ ++ if (prMsgWfdCfgUpdate != NULL) { ++ ++ prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; ++ prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; ++ ++ if (ucMode == MIRACAST_MODE_OFF) { ++ prWfdCfgSettings->ucWfdEnable = 0; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); ++ } else if (ucMode == MIRACAST_MODE_SOURCE) { ++ prWfdCfgSettings->ucWfdEnable = 1; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 1"); ++ } else if (ucMode == MIRACAST_MODE_SINK) { ++ prWfdCfgSettings->ucWfdEnable = 2; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 2"); ++ } else { ++ prWfdCfgSettings->ucWfdEnable = 0; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); ++ } ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); ++ ++ priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); ++ ++ } /* prMsgWfdCfgUpdate */ ++ else { ++ ASSERT(FALSE); ++ i4BytesWritten = -1; ++ } ++ } ++ ++ /* i4Argc */ ++ return i4BytesWritten; ++} ++ ++int priv_support_driver_cmd(IN struct net_device *prNetDev, IN OUT struct ifreq *prReq, IN int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ char *pcCommand = NULL; ++ priv_driver_cmd_t *priv_cmd = NULL; ++ int i4BytesWritten = 0; ++ int i4TotalLen = 0; ++ ++ if (!prReq->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (!prGlueInfo) { ++ DBGLOG(REQ, WARN, "No glue info\n"); ++ ret = -EFAULT; ++ goto exit; ++ } ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv_cmd = kzalloc(sizeof(priv_driver_cmd_t), GFP_KERNEL); ++ if (!priv_cmd) { ++ DBGLOG(REQ, WARN, "%s, alloc mem failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(priv_cmd, prReq->ifr_data, sizeof(priv_driver_cmd_t))) { ++ DBGLOG(REQ, INFO, "%s: copy_from_user fail\n", __func__); ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ i4TotalLen = priv_cmd->total_len; ++ ++ if (i4TotalLen <= 0) { ++ ret = -EINVAL; ++ DBGLOG(REQ, INFO, "%s: i4TotalLen invalid\n", __func__); ++ goto exit; ++ } ++ ++ pcCommand = priv_cmd->buf; ++ ++ DBGLOG(REQ, INFO, "%s: driver cmd \"%s\" on %s\n", __func__, pcCommand, prReq->ifr_name); ++ ++ i4BytesWritten = priv_driver_cmds(prNetDev, pcCommand, i4TotalLen); ++ ++ if (i4BytesWritten < 0) { ++ DBGLOG(REQ, INFO, "%s: command %s failed; Written is %d\n", ++ __func__, pcCommand, i4BytesWritten); ++ ret = -EFAULT; ++ } ++ ++exit: ++ kfree(priv_cmd); ++ ++ return ret; ++} ++ ++#if CFG_SUPPORT_BATCH_SCAN ++#define CMD_BATCH_SET "WLS_BATCHING SET" ++#define CMD_BATCH_GET "WLS_BATCHING GET" ++#define CMD_BATCH_STOP "WLS_BATCHING STOP" ++#endif ++ ++#if CFG_SUPPORT_GET_CH_ENV ++#define CMD_CH_ENV_GET "CH_ENV_GET" ++#endif ++ ++INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4BytesWritten = 0; ++ INT_32 i4CmdFound = 0; ++ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (i4CmdFound == 0) { ++ i4CmdFound = 1; ++ ++ if (strnicmp(pcCommand, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) ++ i4BytesWritten = priv_driver_set_miracast(prNetDev, pcCommand, i4TotalLen); ++#if CFG_SUPPORT_BATCH_SCAN ++ else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); ++ } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { ++ /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ ++ /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ ++ /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ ++ ++ UINT_32 u4BufLen; ++ int i; ++ /* int rlen=0; */ ++ ++ for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { ++ g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ ++ kalIoctl(prGlueInfo, ++ wlanoidQueryBatchScanResult, ++ (PVOID)&g_rEventBatchResult[i], ++ sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ } ++ ++#if 0 ++ DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); ++ for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { ++ prEntry = &g_rEventBatchResult.arBatchResult[i]; ++ DBGLOG(SCN, INFO, "Entry %u\n", i); ++ DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); ++ DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); ++ DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); ++ DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); ++ DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); ++ } ++#endif ++ ++ batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); ++ ++ /* Dump for debug */ ++ /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, ++ i4BytesWritten, TRUE); */ ++ ++ } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); ++ } ++#endif ++#if CFG_SUPPORT_GET_CH_ENV ++ else if (strnicmp(pcCommand, CMD_CH_ENV_GET, strlen(CMD_CH_ENV_GET)) == 0) ++ scanEnvResult(prGlueInfo, pcCommand, i4TotalLen, &i4BytesWritten); ++#endif ++ ++#if 0 ++ ++ else if (strnicmp(pcCommand, CMD_RSSI, strlen(CMD_RSSI)) == 0) { ++ /* i4BytesWritten = wl_android_get_rssi(net, command, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { ++ i4BytesWritten = priv_driver_get_linkspeed(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { ++ /* i4BytesWritten = wl_android_set_suspendopt(net, pcCommand, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { ++ i4BytesWritten = priv_driver_set_suspend_mode(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { ++ i4BytesWritten = priv_driver_set_band(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { ++ /* i4BytesWritten = wl_android_get_band(net, pcCommand, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { ++ i4BytesWritten = priv_driver_set_country(prNetDev, pcCommand, i4TotalLen); ++ } ++ /* Mediatek private command */ ++ else if (strnicmp(pcCommand, CMD_SET_SW_CTRL, strlen(CMD_SET_SW_CTRL)) == 0) { ++ i4BytesWritten = priv_driver_set_sw_ctrl(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_SW_CTRL, strlen(CMD_GET_SW_CTRL)) == 0) { ++ i4BytesWritten = priv_driver_get_sw_ctrl(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_CFG, strlen(CMD_SET_CFG)) == 0) { ++ i4BytesWritten = priv_driver_set_cfg(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_CFG, strlen(CMD_GET_CFG)) == 0) { ++ i4BytesWritten = priv_driver_get_cfg(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_CHIP, strlen(CMD_SET_CHIP)) == 0) { ++ i4BytesWritten = priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_CHIP, strlen(CMD_GET_CHIP)) == 0) { ++ i4BytesWritten = priv_driver_get_chip_config(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_DBG_LEVEL, strlen(CMD_SET_DBG_LEVEL)) == 0) { ++ i4BytesWritten = priv_driver_set_dbg_level(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_DBG_LEVEL, strlen(CMD_GET_DBG_LEVEL)) == 0) { ++ i4BytesWritten = priv_driver_get_dbg_level(prNetDev, pcCommand, i4TotalLen); ++ } ++#if CFG_SUPPORT_BATCH_SCAN ++ else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); ++ } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { ++ /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ ++ /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ ++ /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ ++ ++ UINT_32 u4BufLen; ++ int i; ++ /* int rlen=0; */ ++ ++ for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { ++ g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ ++ kalIoctl(prGlueInfo, ++ wlanoidQueryBatchScanResult, ++ (PVOID)&g_rEventBatchResult[i], ++ sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, &u4BufLen); ++ } ++ ++#if 0 ++ DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); ++ for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { ++ prEntry = &g_rEventBatchResult.arBatchResult[i]; ++ DBGLOG(SCN, INFO, "Entry %u\n", i); ++ DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); ++ DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); ++ DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); ++ DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); ++ DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); ++ } ++#endif ++ ++ batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); ++ ++ /* Dump for debug */ ++ /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, i4BytesWritten, ++ TRUE); */ ++ ++ } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); ++ } ++#endif ++ ++#endif ++ ++ else ++ i4CmdFound = 0; ++ } ++ ++ /* i4CmdFound */ ++ if (i4CmdFound == 0) ++ DBGLOG(REQ, TRACE, "Unknown driver command %s - ignored\n", pcCommand); ++ ++ if (i4BytesWritten >= 0) { ++ if ((i4BytesWritten == 0) && (i4TotalLen > 0)) { ++ /* reset the command buffer */ ++ pcCommand[0] = '\0'; ++ } ++ ++ if (i4BytesWritten >= i4TotalLen) { ++ DBGLOG(REQ, INFO, ++ "%s: i4BytesWritten %d > i4TotalLen < %d\n", __func__, i4BytesWritten, i4TotalLen); ++ i4BytesWritten = i4TotalLen; ++ } else { ++ pcCommand[i4BytesWritten] = '\0'; ++ i4BytesWritten++; ++ } ++ } ++ ++ return i4BytesWritten; ++ ++} ++ ++static int compat_priv(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra, ++ int (*priv_func)(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra)) ++{ ++ struct iw_point *prIwp; ++ int ret = 0; ++#ifdef CONFIG_COMPAT ++ struct compat_iw_point *iwp_compat = NULL; ++ struct iw_point iwp; ++#endif ++ ++ if (!prIwReqData) ++ return -EINVAL; ++ ++#ifdef CONFIG_COMPAT ++ if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { ++ iwp_compat = (struct compat_iw_point *) &prIwReqData->data; ++ iwp.pointer = compat_ptr(iwp_compat->pointer); ++ iwp.length = iwp_compat->length; ++ iwp.flags = iwp_compat->flags; ++ prIwp = &iwp; ++ } else ++#endif ++ prIwp = &prIwReqData->data; ++ ++ ++ ret = priv_func(prNetDev, prIwReqInfo, (union iwreq_data *)prIwp, pcExtra); ++ ++#ifdef CONFIG_COMPAT ++ if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { ++ iwp_compat->pointer = ptr_to_compat(iwp.pointer); ++ iwp_compat->length = iwp.length; ++ iwp_compat->flags = iwp.flags; ++ } ++#endif ++ return ret; ++} ++ ++int ++priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_int); ++} ++ ++int ++priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_int); ++} ++ ++int ++priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_ints); ++} ++ ++int ++priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_ints); ++} ++ ++int ++priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_struct); ++} ++ ++int ++priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_struct); ++} ++ ++int ++priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_string); ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c +new file mode 100644 +index 000000000000..c13d24906bf8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c +@@ -0,0 +1,1643 @@ ++/****************************************************************************** ++*[File] ahb.c ++*[Version] v1.0 ++*[Revision Date] 2013-01-16 ++*[Author] ++*[Description] ++* The program provides AHB HIF driver ++*[Copyright] ++* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: ahb.c ++ * ++ * 01 16 2013 vend_samp.lin ++ * Port sdio.c to ahb.c on MT6572/MT6582 ++ * 1) Initial version ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ * ++ * 02 14 2012 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * include correct header file upon setting. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 09 20 2011 cp.wu ++ * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized ++ * 1. always show error message for SDIO bus errors. ++ * 2. reset bus error flag when re-initialization ++ * ++ * 08 17 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628 related definitions for Linux/Android driver. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add device ID for MT5931. ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 11 15 2010 jeffrey.chang ++ * [WCXRP00000181] [MT6620 Wi-Fi][Driver] fix the driver message "GLUE_FLAG_HALT skip INT" during unloading ++ * Fix GLUE_FALG_HALT message which cause driver to hang ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * correct typo ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 19 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 08 21 2010 jeffrey.chang ++ * NULL ++ * 1) add sdio two setting ++ * 2) bug fix of sdio glue ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 18 2010 cp.wu ++ * NULL ++ * #if defined(__X86__) is not working, change to use #ifdef CONFIG_X86. ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * add ENE SDIO host workaround for x86 linux platform. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Fix hotplug bug ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * clear sdio interrupt ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++/* #include */ ++#include ++/* #include */ ++#include ++/* #include */ ++/* #include */ ++/* #include */ ++ ++#include ++#ifndef CONFIG_X86 ++#include ++#endif ++ ++#ifdef CONFIG_OF ++#include ++#include ++#include ++#else ++ ++#endif ++ ++/* #include ++#include */ ++ ++#include "gl_os.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#elif defined(MT6628) ++#include "mtreg.h" ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++#include ++#endif ++ ++/* #define MTK_DMA_BUF_MEMCPY_SUP */ /* no virt_to_phys() use */ ++/* #define HIF_DEBUG_SUP */ ++/* #define HIF_DEBUG_SUP_TX */ ++ ++#ifdef HIF_DEBUG_SUP ++#define HIF_DBG(msg) (printk msg) ++#else ++#define HIF_DBG(msg) ++#endif /* HIF_DEBUG_SUP */ ++ ++#ifdef HIF_DEBUG_SUP_TX ++#define HIF_DBG_TX(msg) (printk msg) ++#else ++#define HIF_DBG_TX(msg) ++#endif /* HIF_DEBUG_SUP */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static UINT_32 ++HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T *GlueInfo, IN UINT_32 BurstLen, IN UINT_32 PortId, IN UINT_32 TransByte); ++ ++static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg); ++ ++static int HifAhbProbe(VOID); ++ ++static int HifAhbRemove(VOID); ++ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++static int HifAhbBusCntGet(VOID); ++ ++static int HifAhbBusCntClr(VOID); ++ ++static int HifTxCnt; ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++#if (CONF_HIF_DEV_MISC == 1) ++static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos); ++ ++static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos); ++ ++static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg); ++ ++static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp); ++ ++static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp); ++#else ++ ++static int HifAhbPltmProbe(IN struct platform_device *PDev); ++ ++static int __exit HifAhbPltmRemove(IN struct platform_device *PDev); ++ ++#ifdef CONFIG_PM ++static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message); ++ ++static int HifAhbPltmResume(IN struct platform_device *PDev); ++#endif /* CONFIG_PM */ ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ ++static VOID HifAhbLoopbkAuto(IN unsigned long arg); ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg); ++#endif /* CONF_HIF_DMA_INT */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* initialiation function from other module */ ++static probe_card pfWlanProbe; ++ ++/* release function from other module */ ++static remove_card pfWlanRemove; ++ ++static BOOLEAN WlanDmaFatalErr; ++ ++#if (CONF_HIF_DEV_MISC == 1) ++static const struct file_operations MtkAhbOps = { ++ .owner = THIS_MODULE, ++ .read = HifAhbMiscRead, ++ .write = HifAhbMiscWrite, ++ .unlocked_ioctl = HifAhbMiscIoctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = HifAhbMiscIoctl, ++#endif ++ .open = HifAhbMiscOpen, ++ .release = HifAhbMiscClose, ++}; ++ ++static struct miscdevice MtkAhbDriver = { ++ .minor = MISC_DYNAMIC_MINOR, /* any minor number */ ++ .name = HIF_MOD_NAME, ++ .fops = &MtkAhbOps, ++}; ++#else ++ ++#ifdef CONFIG_OF ++static const struct of_device_id apwifi_of_ids[] = { ++ {.compatible = "mediatek,wifi", .data = (void *)0}, ++ {.compatible = "mediatek,mt7623-wifi", .data = (void *)0x7623}, ++ {} ++}; ++#endif ++ ++struct platform_driver MtkPltmAhbDriver = { ++ .driver = { ++ .name = "mt-wifi", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_OF ++ .of_match_table = apwifi_of_ids, ++#endif ++ }, ++ .probe = HifAhbPltmProbe, ++#ifdef CONFIG_PM ++ .suspend = HifAhbPltmSuspend, ++ .resume = HifAhbPltmResume, ++#else ++ .suspend = NULL, ++ .resume = NULL, ++#endif /* CONFIG_PM */ ++ .remove = __exit_p(HifAhbPltmRemove), ++}; ++ ++static struct platform_device *HifAhbPDev; ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will register sdio bus to the os ++* ++* \param[in] pfProbe Function pointer to detect card ++* \param[in] pfRemove Function pointer to remove card ++* ++* \return The result of registering HIF driver (WLAN_STATUS_SUCCESS = 0) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove) ++{ ++ WLAN_STATUS Ret; ++ ++ ASSERT(pfProbe); ++ ASSERT(pfRemove); ++ ++ pfWlanProbe = pfProbe; /* wlan card initialization in other modules = wlanProbe() */ ++ pfWlanRemove = pfRemove; ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ Ret = misc_register(&MtkAhbDriver); ++ if (Ret != 0) ++ return Ret; ++ HifAhbProbe(); ++#else ++ Ret = platform_driver_register(&MtkPltmAhbDriver); ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ return Ret; ++ ++} /* end of glRegisterBus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will unregister sdio bus to the os ++* ++* \param[in] pfRemove Function pointer to remove card ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glUnregisterBus(remove_card pfRemove) ++{ ++ ASSERT(pfRemove); ++ ++ pfRemove(); ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ HifAhbRemove(); ++ ++ if ((misc_deregister(&MtkAhbDriver)) != 0) ++ ; ++#else ++ ++ platform_driver_unregister(&MtkPltmAhbDriver); ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ return; ++ ++} /* end of glUnregisterBus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will inform us whole chip reset start event. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glResetHif(GLUE_INFO_T *GlueInfo) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ if (HifInfo->DmaOps) ++ HifInfo->DmaOps->DmaReset(HifInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function stores hif related info, which is initialized before. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* \param[in] u4Cookie Pointer to UINT_32 memory base variable for _HIF_HPI ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glSetHifInfo(GLUE_INFO_T *GlueInfo, ULONG ulCookie) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ const struct of_device_id *of_id; ++ ++ /* Init HIF */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++#if (CONF_HIF_DEV_MISC == 1) ++ HifInfo->Dev = MtkAhbDriver.this_device; ++#else ++ HifInfo->Dev = &HifAhbPDev->dev; ++#endif /* CONF_HIF_DEV_MISC */ ++ SET_NETDEV_DEV(GlueInfo->prDevHandler, HifInfo->Dev); ++ ++ HifInfo->HifRegBaseAddr = ioremap(HIF_DRV_BASE, HIF_DRV_LENGTH); ++ HifInfo->McuRegBaseAddr = ioremap(CONN_MCU_DRV_BASE, CONN_MCU_REG_LENGTH); ++ DBGLOG(INIT, INFO, "[WiFi/HIF]HifInfo->HifRegBaseAddr=0x%p, HifInfo->McuRegBaseAddr=0x%p\n", ++ HifInfo->HifRegBaseAddr, HifInfo->McuRegBaseAddr); ++ ++ /* default disable DMA */ ++ HifInfo->fgDmaEnable = FALSE; ++ HifInfo->DmaRegBaseAddr = 0; ++ HifInfo->DmaOps = NULL; ++ of_id = of_match_node(apwifi_of_ids, HifAhbPDev->dev.of_node); ++ if (of_id && of_id->data) { ++ HifInfo->ChipID = (UINT_32)(unsigned long)of_id->data; ++ } else { ++ /* read chip ID */ ++ HifInfo->ChipID = HIF_REG_READL(HifInfo, MCR_WCIR) & 0xFFFF; ++ if (HifInfo->ChipID == 0x0321 || HifInfo->ChipID == 0x0335 || HifInfo->ChipID == 0x0337) ++ HifInfo->ChipID = 0x6735; /* Denali ChipID transition */ ++ if (HifInfo->ChipID == 0x0326) ++ HifInfo->ChipID = 0x6755; ++ } ++ DBGLOG(INIT, INFO, "[WiFi/HIF] ChipID = 0x%x\n", HifInfo->ChipID); ++#ifdef CONFIG_OF ++#if !defined(CONFIG_MTK_CLKMGR) ++ HifInfo->clk_wifi_dma = devm_clk_get(&HifAhbPDev->dev, "wifi-dma"); ++ if (IS_ERR(HifInfo->clk_wifi_dma)) ++ DBGLOG(INIT, ERROR, "[WiFi/HIF][CCF]cannot get HIF clk_wifi_dma clock.\n"); ++ DBGLOG(INIT, TRACE, "[WiFi/HIF][CCF]HIF clk_wifi_dma=0x%p\n", HifInfo->clk_wifi_dma); ++#endif ++#endif ++ ++ /* Init DMA */ ++ WlanDmaFatalErr = 0; /* reset error flag */ ++ ++#if (CONF_MTK_AHB_DMA == 1) ++ spin_lock_init(&HifInfo->DdmaLock); ++ ++ HifPdmaInit(HifInfo); ++#endif /* CONF_MTK_AHB_DMA */ ++ ++ /* Start loopback test after 10 seconds */ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ ++ { ++ init_timer(&(HifInfo->HifTmrLoopbkFn)); ++ HifInfo->HifTmrLoopbkFn.function = HifAhbLoopbkAuto; ++ HifInfo->HifTmrLoopbkFn.data = (unsigned long)GlueInfo; ++ ++ init_waitqueue_head(&HifInfo->HifWaitq); ++ HifInfo->HifTaskLoopbkFn = kthread_run(kalDevLoopbkThread, GlueInfo->prDevHandler, "LoopbkThread"); ++ HifInfo->HifLoopbkFlg = 0; ++ ++ /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ ++ HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(30000); ++ add_timer(&(HifInfo->HifTmrLoopbkFn)); ++ ++ HIF_DBG(("[WiFi/HIF] Start loopback test after 10 seconds (jiffies = %u)...\n", jiffies)); ++ } ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++ init_waitqueue_head(&HifInfo->HifDmaWaitq); ++ HifInfo->HifDmaWaitFlg = 0; ++#endif /* CONF_HIF_DMA_INT */ ++ ++} /* end of glSetHifInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clears hif related info. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glClearHifInfo(GLUE_INFO_T *GlueInfo) ++{ ++ iounmap(GlueInfo->rHifInfo.HifRegBaseAddr); ++ iounmap(GlueInfo->rHifInfo.DmaRegBaseAddr); ++ iounmap(GlueInfo->rHifInfo.McuRegBaseAddr); ++ return; ++ ++} /* end of glClearHifInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clears hif related info. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ DBGLOG(INIT, TRACE, "glGetChipInfo ChipID = 0x%x\n", HifInfo->ChipID); ++ switch (HifInfo->ChipID) { ++ case MTK_CHIP_ID_6571: ++ case MTK_CHIP_ID_8127: ++ case MTK_CHIP_ID_6752: ++ case MTK_CHIP_ID_8163: ++ case MTK_CHIP_ID_6735: ++ case MTK_CHIP_ID_6580: ++ case MTK_CHIP_ID_6755: ++ case MTK_CHIP_ID_7623: ++ kalSprintf(pucChipBuf, "%04x", HifInfo->ChipID); ++ break; ++ default: ++ kalMemCopy(pucChipBuf, "SOC", strlen("SOC")); ++ } ++} /* end of glGetChipInfo() */ ++ ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function to check if we need wakelock under Hotspot mode. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ if (HifInfo->ChipID == MTK_CHIP_ID_6572 || HifInfo->ChipID == MTK_CHIP_ID_6582) ++ return TRUE; ++ else ++ return FALSE; ++} /* end of glIsChipNeedWakelock() */ ++#endif /* CFG_SPM_WORKAROUND_FOR_HOTSPOT */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initialize bus operation and hif related information, request resources. ++* ++* \param[out] pvData A pointer to HIF-specific data type buffer. ++* For eHPI, pvData is a pointer to UINT_32 type and stores a ++* mapped base address. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glBusInit(PVOID pvData) ++{ ++ return TRUE; ++} /* end of glBusInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop bus operation and release resources. ++* ++* \param[in] pvData A pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glBusRelease(PVOID pvData) ++{ ++} /* end of glBusRelease() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setup bus interrupt operation and interrupt handler for os. ++* ++* \param[in] pvData A pointer to struct net_device. ++* \param[in] pfnIsr A pointer to interrupt handler function. ++* \param[in] pvCookie Private data for pfnIsr function. ++* ++* \retval WLAN_STATUS_SUCCESS if success ++* NEGATIVE_VALUE if fail ++*/ ++/*----------------------------------------------------------------------------*/ ++#ifdef CONFIG_OF ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++ /* unsigned int phy_base; */ ++ unsigned int irq_id = 0; ++ unsigned int irq_flags = 0; ++ ++ struct net_device *prNetDevice; ++ ++ ASSERT(pvData); ++ if (!pvData) ++ return -1; ++ prNetDevice = (struct net_device *)pvData; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); ++ if (node) { ++ irq_id = irq_of_parse_and_map(node, 0); ++ DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); ++ } else { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); ++ } else { ++ irq_flags = irq_info[2]; ++ DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); ++ } ++ ++ /* Register AHB IRQ */ ++ if (request_irq(irq_id, HifAhbISR, irq_flags, HIF_MOD_NAME, prNetDevice)) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: request irq %d fail!\n", irq_id); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++ /* unsigned int phy_base; */ ++ unsigned int irq_id = 0; ++ unsigned int irq_flags = 0; ++ ++ struct net_device *prNetDevice; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return; ++ prNetDevice = (struct net_device *)pvData; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); ++ if (node) { ++ irq_id = irq_of_parse_and_map(node, 0); ++ DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); ++ } else { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); ++ } else { ++ irq_flags = irq_info[2]; ++ DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); ++ } ++ ++ /* Free the IRQ */ ++ free_irq(irq_id, prNetDevice); ++ return; ++ ++} ++#else ++/* the name is different in 72 and 82 */ ++#ifndef MT_WF_HIF_IRQ_ID /* for MT6572/82/92 */ ++#define MT_WF_HIF_IRQ_ID WF_HIF_IRQ_ID ++#endif /* MT_WF_HIF_IRQ_ID */ ++ ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) ++{ ++ int ret = 0; ++ struct net_device *prNetDevice; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return -1; ++ ++ prNetDevice = (struct net_device *)pvData; ++ GlueInfo = (GLUE_INFO_T *) pvCookie; ++ ASSERT(GlueInfo); ++ if (!GlueInfo) { ++ DBGLOG(INIT, ERROR, "GlueInfo == NULL!\n"); ++ return -1; ++ } ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* Register AHB IRQ */ ++ if (request_irq(MT_WF_HIF_IRQ_ID, HifAhbISR, IRQF_TRIGGER_LOW, HIF_MOD_NAME, prNetDevice)) { ++ DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_WF_HIF_IRQ_ID); ++ return -1; ++ } ++#if (CONF_HIF_DMA_INT == 1) ++ if (request_irq(MT_GDMA2_IRQ_ID, HifDmaISR, IRQF_TRIGGER_LOW, "AHB_DMA", prNetDevice)) { ++ DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_GDMA2_IRQ_ID); ++ free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); ++ return -1; ++ } ++#endif /* CONF_HIF_DMA_INT */ ++ ++ return ret; ++ ++} /* end of glBusSetIrq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop bus interrupt operation and disable interrupt handling for os. ++* ++* \param[in] pvData A pointer to struct net_device. ++* \param[in] pvCookie Private data for pfnIsr function. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) ++{ ++ struct net_device *prNetDevice; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return; ++ ++ prNetDevice = (struct net_device *)pvData; ++ GlueInfo = (GLUE_INFO_T *) pvCookie; ++ ASSERT(GlueInfo); ++ if (!GlueInfo) ++ return; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* Free the IRQ */ ++ free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); ++ return; ++ ++} /* end of glBusreeIrq() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read a 32-bit device register ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] RegOffset Register offset ++* \param[in] pu4Value Pointer to variable used to store read value ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegRead(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, OUT UINT_32 *pu4Value) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* sanity check and init */ ++ ASSERT(GlueInfo); ++ ASSERT(pu4Value); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* use PIO mode to read register */ ++ if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) ++ return FALSE; ++ *pu4Value = HIF_REG_READL(HifInfo, RegOffset); ++ ++ if ((RegOffset == MCR_WRDR0) || (RegOffset == MCR_WRDR1)) ++ HIF_DBG(("[WiFi/HIF] kalDevRegRead from Data Port 0 or 1\n")); ++ ++ return TRUE; ++ ++} /* end of kalDevRegRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Write a 32-bit device register ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] RegOffset Register offset ++* \param[in] RegValue RegValue to be written ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegWrite(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, IN UINT_32 RegValue) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* sanity check and init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* use PIO mode to write register */ ++ if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) ++ return FALSE; ++ HIF_REG_WRITEL(HifInfo, RegOffset, RegValue); ++ ++ if ((RegOffset == MCR_WTDR0) || (RegOffset == MCR_WTDR1)) ++ HIF_DBG(("[WiFi/HIF] kalDevRegWrite to Data Port 0 or 1\n")); ++ ++ return TRUE; ++ ++} /* end of kalDevRegWrite() */ ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read device I/O port ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Port I/O port offset ++* \param[in] Size Length to be read ++* \param[out] Buf Pointer to read buffer ++* \param[in] MaxBufSize Length of the buffer valid to be accessed ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++kalDevPortRead(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, OUT PUINT_8 Buf, IN UINT_32 MaxBufSize) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4HSTCRValue = 0; ++ UINT_32 RegWHLPCR = 0; ++ ++ /* sanity check */ ++ if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { ++ DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", ++ WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); ++ return FALSE; ++ } ++ /* Init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(Buf); ++ ASSERT(Size <= MaxBufSize); ++ ++ /* Note: burst length should be equal to the one used in DMA */ ++ if (Port == MCR_WRDR0) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD0, Size); ++ else if (Port == MCR_WRDR1) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD1, Size); ++ else if (Port == MCR_WHISR) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_WHISR, Size); ++ ++ RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* Read */ ++#if (CONF_MTK_AHB_DMA == 1) ++ if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) ++ && ((Port == MCR_WRDR0) || (Port == MCR_WRDR1))) { ++ /* only for data port */ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ VOID *DmaVBuf = NULL, *DmaPBuf = NULL; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; ++ MTK_WCN_HIF_DMA_CONF DmaConf; ++ UINT_32 LoopCnt; ++ unsigned long PollTimeout; ++#if (CONF_HIF_DMA_INT == 1) ++ INT_32 RtnVal = 0; ++#endif ++ /* config DMA, Port = MCR_WRDR0 or MCR_WRDR1 */ ++ DmaConf.Count = Size; ++ DmaConf.Dir = HIF_DMA_DIR_RX; ++ DmaConf.Src = HIF_DRV_BASE + Port; /* must be physical addr */ ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ DmaConf.Dst = kalIOPhyAddrGet(Buf); /* must be physical addr */ ++ ++ /* TODO: use virt_to_phys() */ ++ if (DmaConf.Dst == NULL) { ++ HIF_DBG(("[WiFi/HIF] Use Dma Buffer to RX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); ++ ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); ++ ++ kalDmaBufGet(&DmaVBuf, &DmaPBuf); ++ DmaConf.Dst = (ULONG) DmaPBuf; ++ } ++#else ++ /* ++ http://kernelnewbies.org/KernelMemoryAllocation ++ Since the cache-coherent mapping may be expensive, also a streaming allocation exists. ++ ++ This is a buffer for one-way communication, which means coherency is limited to ++ flushing the data from the cache after a write finishes. The buffer has to be ++ pre-allocated (e.g. using kmalloc()). DMA for it is set up with dma_map_single(). ++ ++ When the DMA is finished (e.g. when the device has sent an interrupt signaling end of ++ DMA), call dma_unmap_single(). Between map and unmap, the device is in control of the ++ buffer: if you write to the device, do it before dma_map_single(), if you read from ++ it, do it after dma_unmap_single(). ++ */ ++ /* DMA_FROM_DEVICE invalidated (without writeback) the cache */ ++ /* TODO: if dst_off was not cacheline aligned */ ++ DmaConf.Dst = dma_map_single(HifInfo->Dev, Buf, Size, DMA_FROM_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ /* start to read data */ ++ AP_DMA_HIF_LOCK(HifInfo); /* lock to avoid other codes config GDMA */ ++ ++ prDmaOps->DmaClockCtrl(TRUE); ++ prDmaOps->DmaConfig(HifInfo, &DmaConf); ++ prDmaOps->DmaStart(HifInfo); ++ ++#if (CONF_HIF_DMA_INT == 1) ++ RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); ++ if (RtnVal <= 0) ++ DBGLOG(RX, ERROR, "fatal error1! reset DMA!\n"); ++ HifInfo->HifDmaWaitFlg = 0; ++#else ++ PollTimeout = jiffies + HZ * 5; ++ ++ do { ++ if (time_before(jiffies, PollTimeout)) ++ continue; ++ DBGLOG(RX, INFO, "RX DMA Timeout, HSTCR: 0x%08x, and dump WHISR EnhanceMode data\n", ++ u4HSTCRValue); ++ HifDumpEnhanceModeData(GlueInfo->prAdapter); ++ if (prDmaOps->DmaRegDump != NULL) ++ prDmaOps->DmaRegDump(HifInfo); ++ WlanDmaFatalErr = 1; ++ /* we still need complete dma progress even dma timeout */ ++ break; ++ } while (!prDmaOps->DmaPollIntr(HifInfo)); ++#endif /* CONF_HIF_DMA_INT */ ++ /* we should disable dma interrupt then clear dma interrupt, otherwise, ++ for dma timeout case, interrupt may be set after we clear it */ ++ prDmaOps->DmaStop(HifInfo); ++ prDmaOps->DmaAckIntr(HifInfo); ++ ++ LoopCnt = 0; ++ do { ++ if (LoopCnt++ > 100000) { ++ /* TODO: impossible! reset DMA */ ++ DBGLOG(RX, ERROR, "fatal error2! reset DMA!\n"); ++ break; ++ } ++ } while (prDmaOps->DmaPollStart(HifInfo) != 0); ++ ++ prDmaOps->DmaClockCtrl(FALSE); ++ ++ AP_DMA_HIF_UNLOCK(HifInfo); ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ if (DmaVBuf != NULL) ++ kalMemCopy(Buf, DmaVBuf, Size); ++#else ++ dma_unmap_single(HifInfo->Dev, DmaConf.Dst, Size, DMA_FROM_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ if (WlanDmaFatalErr) { ++ if (!fgIsResetting) ++ glDoChipReset(); ++ return FALSE; ++ } ++ HIF_DBG(("[WiFi/HIF] DMA RX OK!\n")); ++ } else ++#endif /* CONF_MTK_AHB_DMA */ ++ { ++ UINT_32 IdLoop, MaxLoop; ++ UINT_32 *LoopBuf; ++ ++ /* default PIO mode */ ++ MaxLoop = Size >> 2; ++ if (Size & 0x3) ++ MaxLoop++; ++ LoopBuf = (UINT_32 *) Buf; ++ ++ for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { ++ ++ *LoopBuf = HIF_REG_READL(HifInfo, Port); ++ LoopBuf++; ++ } ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ } ++ ++ return TRUE; ++ ++} /* end of kalDevPortRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Write device I/O port ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Port I/O port offset ++* \param[in] Size Length to be write ++* \param[in] Buf Pointer to write buffer ++* \param[in] MaxBufSize Length of the buffer valid to be accessed ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++kalDevPortWrite(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, IN PUINT_8 Buf, IN UINT_32 MaxBufSize) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4HSTCRValue = 0; ++ UINT_32 RegWHLPCR = 0; ++ ++ /* sanity check */ ++ if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { ++ DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", ++ WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); ++ return FALSE; ++ } ++ ++ /* Init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(Buf); ++ ASSERT(Size <= MaxBufSize); ++ ++ HifTxCnt++; ++ ++ /* Note: burst length should be equal to the one used in DMA */ ++ if (Port == MCR_WTDR0) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD0, Size); ++ else if (Port == MCR_WTDR1) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD1, Size); ++ /* else other non-data port */ ++ ++ RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* Write */ ++#if (CONF_MTK_AHB_DMA == 1) ++ if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) && ((Port == MCR_WTDR0) || ++ (Port == MCR_WTDR1))) { ++ /* only for data port */ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ VOID *DmaVBuf = NULL, *DmaPBuf = NULL; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; ++ MTK_WCN_HIF_DMA_CONF DmaConf; ++ UINT_32 LoopCnt; ++ unsigned long PollTimeout; ++#if (CONF_HIF_DMA_INT == 1) ++ INT_32 RtnVal = 0; ++#endif ++ ++ /* config GDMA */ ++ HIF_DBG_TX(("[WiFi/HIF/DMA] Prepare to send data...\n")); ++ DmaConf.Count = Size; ++ DmaConf.Dir = HIF_DMA_DIR_TX; ++ DmaConf.Dst = HIF_DRV_BASE + Port; /* must be physical addr */ ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ DmaConf.Src = kalIOPhyAddrGet(Buf); /* must be physical addr */ ++ ++ /* TODO: use virt_to_phys() */ ++ if (DmaConf.Src == NULL) { ++ HIF_DBG_TX(("[WiFi/HIF] Use Dma Buffer to TX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); ++ ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); ++ ++ kalDmaBufGet(&DmaVBuf, &DmaPBuf); ++ DmaConf.Src = (ULONG) DmaPBuf; ++ ++ kalMemCopy(DmaVBuf, Buf, Size); ++ } ++#else ++ ++ /* DMA_TO_DEVICE writeback the cache */ ++ DmaConf.Src = dma_map_single(HifInfo->Dev, Buf, Size, DMA_TO_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ /* start to write */ ++ AP_DMA_HIF_LOCK(HifInfo); ++ ++ prDmaOps->DmaClockCtrl(TRUE); ++ prDmaOps->DmaConfig(HifInfo, &DmaConf); ++ prDmaOps->DmaStart(HifInfo); ++ ++#if (CONF_HIF_DMA_INT == 1) ++ RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); ++ if (RtnVal <= 0) ++ DBGLOG(TX, ERROR, "fatal error1! reset DMA!\n"); ++ HifInfo->HifDmaWaitFlg = 0; ++#else ++ ++ LoopCnt = 0; ++ PollTimeout = jiffies + HZ * 5; ++ ++ do { ++ if (time_before(jiffies, PollTimeout)) ++ continue; ++ DBGLOG(TX, INFO, "TX DMA Timeout, HSTCR: 0x%08x\n", u4HSTCRValue); ++ if (prDmaOps->DmaRegDump != NULL) ++ prDmaOps->DmaRegDump(HifInfo); ++ WlanDmaFatalErr = 1; ++ /* we still need complete dma progress even dma timeout */ ++ break; ++ } while (!prDmaOps->DmaPollIntr(HifInfo)); ++#endif /* CONF_HIF_DMA_INT */ ++ /* we should disable dma interrupt then clear dma interrupt, otherwise, ++ for dma timeout case, interrupt may be set after we clear it */ ++ prDmaOps->DmaStop(HifInfo); ++ prDmaOps->DmaAckIntr(HifInfo); ++ ++ LoopCnt = 0; ++ do { ++ if (LoopCnt++ > 100000) { ++ DBGLOG(TX, ERROR, "fatal error2! reset DMA!\n"); ++ break; ++ } ++ } while (prDmaOps->DmaPollStart(HifInfo) != 0); ++ ++ prDmaOps->DmaClockCtrl(FALSE); ++ ++ AP_DMA_HIF_UNLOCK(HifInfo); ++ ++#ifndef MTK_DMA_BUF_MEMCPY_SUP ++ dma_unmap_single(HifInfo->Dev, DmaConf.Src, Size, DMA_TO_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ if (WlanDmaFatalErr) { ++ if (!fgIsResetting) ++ glDoChipReset(); ++ return FALSE; ++ } ++ HIF_DBG_TX(("[WiFi/HIF] DMA TX OK!\n")); ++ } else ++#endif /* CONF_MTK_AHB_DMA */ ++ { ++ UINT_32 IdLoop, MaxLoop; ++ UINT_32 *LoopBuf; ++ ++ /* PIO mode */ ++ MaxLoop = Size >> 2; ++ LoopBuf = (UINT_32 *) Buf; ++ ++ HIF_DBG_TX(("[WiFi/HIF/PIO] Prepare to send data (%d 0x%p-0x%p)...\n", ++ Size, LoopBuf, (((UINT8 *) LoopBuf) + (Size & (~0x03))))); ++ ++ if (Size & 0x3) ++ MaxLoop++; ++ ++ for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { ++ HIF_REG_WRITEL(HifInfo, Port, *LoopBuf); ++ LoopBuf++; ++ } ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ HIF_DBG_TX(("\n\n")); ++ } ++ ++ return TRUE; ++ ++} /* end of kalDevPortWrite() */ ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO interrupt callback function ++* ++* \param[in] func pointer to SDIO handle ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg) ++{ ++ struct net_device *prNetDevice = (struct net_device *)Arg; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ IsrCnt++; ++ ASSERT(prNetDevice); ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); ++ ASSERT(GlueInfo); ++ ++ if (!GlueInfo) ++ return IRQ_HANDLED; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ GlueInfo->IsrCnt++; ++ ++ if (GlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ return IRQ_HANDLED; ++ } ++ ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* lock 100ms to avoid suspend */ ++ kalHifAhbKalWakeLockTimeout(GlueInfo); ++ ++ /* Wake up main thread */ ++ set_bit(GLUE_FLAG_INT_BIT, &GlueInfo->ulFlag); ++ ++ /* when we got sdio interrupt, we wake up the tx servie thread */ ++ wake_up_interruptible(&GlueInfo->waitq); ++ ++ IsrPassCnt++; ++ GlueInfo->IsrPassCnt++; ++ return IRQ_HANDLED; ++ ++} ++ ++#if (CONF_HIF_DMA_INT == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO interrupt callback function ++* ++* \param[in] func pointer to SDIO handle ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg) ++{ ++ struct net_device *prNetDevice = (struct net_device *)Arg; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(prNetDevice); ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); ++ ASSERT(GlueInfo); ++ ++ if (!GlueInfo) ++ return IRQ_HANDLED; ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* disable interrupt */ ++ HifInfo->DmaOps->DmaAckIntr(HifInfo); ++ ++ /* Wake up main thread */ ++ set_bit(1, &HifInfo->HifDmaWaitFlg); ++ ++ /* when we got sdio interrupt, we wake up the tx servie thread */ ++ wake_up_interruptible(&HifInfo->HifDmaWaitq); ++ ++ return IRQ_HANDLED; ++ ++} ++#endif /* CONF_HIF_DMA_INT */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO probe function ++* ++* \param[in] func pointer to SDIO handle ++* \param[in] id pointer to SDIO device id table ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(MTK_EXTERNAL_LDO) || defined(MTK_ALPS_BOX_SUPPORT) ++#include ++#endif ++#endif ++ ++static int HifAhbProbe(VOID) ++{ ++ int Ret = 0; ++ ++ DBGLOG(INIT, INFO, "HifAhbProbe()\n"); ++ ++ /* power on WiFi TX PA 3.3V and HIF GDMA clock */ ++ { ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#if defined(CONFIG_MTK_CLKMGR) ++#ifdef MTK_EXTERNAL_LDO ++ /* for 8127 tablet */ ++ mt_set_gpio_mode(GPIO51, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO51, GPIO_PULL_UP); ++#elif defined(MTK_ALPS_BOX_SUPPORT) ++ /* for 8127 box */ ++ mt_set_gpio_mode(GPIO89, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO89, GPIO_PULL_UP); ++#else ++ hwPowerOn(MT65XX_POWER_LDO_VGP4, VOL_3300, "WLAN"); ++#endif ++#endif ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++ mtk_wcn_consys_hw_wifi_paldo_ctrl(1); /* switch to HW mode */ ++#else /*for MT6572/82/92 */ ++ hwPowerOn(MT6323_POWER_LDO_VCN33_WIFI, VOL_3300, "WLAN"); ++ upmu_set_vcn33_on_ctrl_wifi(1); /* switch to HW mode */ ++#endif ++#endif ++ ++ } ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ if (pfWlanProbe((PVOID) &MtkAhbDriver.this_device) != WLAN_STATUS_SUCCESS) { ++#else ++ if (pfWlanProbe((PVOID) &HifAhbPDev->dev) != WLAN_STATUS_SUCCESS) { ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ pfWlanRemove(); ++ Ret = -1; ++ } ++ ++ return Ret; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do module remove. ++* ++* \param[in] None ++* ++* \return The result of remove (WLAN_STATUS_SUCCESS = 0) ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbRemove(VOID) ++{ ++ DBGLOG(INIT, INFO, "HifAhbRemove()\n"); ++ ++ pfWlanRemove(); ++ ++ { ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#if defined(CONFIG_MTK_CLKMGR) ++#ifdef MTK_EXTERNAL_LDO ++ /* for 8127 tablet */ ++ mt_set_gpio_mode(GPIO51, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO51, GPIO_PULL_DOWN); ++#elif defined(MTK_ALPS_BOX_SUPPORT) ++ /* for 8127 box */ ++ mt_set_gpio_mode(GPIO89, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO89, GPIO_PULL_DOWN); ++#else ++ hwPowerDown(MT65XX_POWER_LDO_VGP4, "WLAN"); ++#endif ++#endif ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++ mtk_wcn_consys_hw_wifi_paldo_ctrl(0); /* switch to SW mode */ ++#else /*for MT6572/82/92 */ ++ upmu_set_vcn33_on_ctrl_wifi(0); /* switch to SW mode */ ++ hwPowerDown(MT6323_POWER_LDO_VCN33_WIFI, "WLAN"); ++#endif ++#endif ++ ++ } ++ ++ return 0; ++} ++ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the TX count pass through HIF AHB bus. ++* ++* \param[in] None ++* ++* \return TX count ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbBusCntGet(VOID) ++{ ++ return HifTxCnt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function resets the TX count pass through HIF AHB bus. ++* ++* \param[in] None ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbBusCntClr(VOID) ++{ ++ HifTxCnt = 0; ++ return 0; ++} ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function configs the DMA TX/RX settings before any real TX/RX. ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] BurstLen 0(1DW), 1(4DW), 2(8DW), Others(Reserved) ++* \param[in] PortId 0(TXD0), 1(TXD1), 2(RXD0), 3(RXD1), 4(WHISR enhance) ++* \param[in] TransByte Should be 4-byte align. ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_32 HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T * GlueInfo, UINT_32 BurstLen, UINT_32 PortId, UINT_32 TransByte) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 RegHSTCR; ++ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ RegHSTCR = HIF_REG_READL(HifInfo, MCR_WHIER); ++ ++ RegHSTCR = HIF_REG_READL(HifInfo, MCR_HSTCR); ++ RegHSTCR = ++ ((BurstLen << HSTCR_AFF_BURST_LEN_OFFSET) & HSTCR_AFF_BURST_LEN) | ++ ((PortId << HSTCR_TRANS_TARGET_OFFSET) & HSTCR_TRANS_TARGET) | ++ (((TransByte & 0x3) == 0) ? (TransByte & HSTCR_HSIF_TRANS_CNT) : ((TransByte + 4) & HSTCR_HSIF_TRANS_CNT)); ++ HIF_REG_WRITEL(HifInfo, MCR_HSTCR, RegHSTCR); ++ return RegHSTCR; ++} ++ ++VOID glSetPowerState(IN GLUE_INFO_T *GlueInfo, IN UINT_32 ePowerMode) ++{ ++ ++} ++ ++#if (CONF_HIF_DEV_MISC == 1) ++/* no use */ ++static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos) ++{ ++ return 0; ++} ++ ++static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp) ++{ ++ return 0; ++} ++#else ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmProbe(IN struct platform_device *PDev) ++{ ++ HifAhbPDev = PDev; ++ ++ DBGLOG(INIT, INFO, "HifAhbPltmProbe\n"); ++ ++#if (CONF_HIF_PMIC_TEST == 1) ++ wmt_set_jtag_for_mcu(); ++ wmt_set_jtag_for_gps(); ++ ++#endif /* CONF_HIF_PMIC_TEST */ ++ ++#if (MTK_WCN_SINGLE_MODULE == 1) ++ HifAhbProbe(); /* only for test purpose without WMT module */ ++ ++#else ++ ++ /* register WiFi function to WMT */ ++ DBGLOG(INIT, INFO, "mtk_wcn_wmt_wlan_reg\n"); ++ { ++ MTK_WCN_WMT_WLAN_CB_INFO WmtCb; ++ ++ WmtCb.wlan_probe_cb = HifAhbProbe; ++ WmtCb.wlan_remove_cb = HifAhbRemove; ++ WmtCb.wlan_bus_cnt_get_cb = HifAhbBusCntGet; ++ WmtCb.wlan_bus_cnt_clr_cb = HifAhbBusCntClr; ++ mtk_wcn_wmt_wlan_reg(&WmtCb); ++ } ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int __exit HifAhbPltmRemove(IN struct platform_device *PDev) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ mtk_wcn_wmt_wlan_unreg(); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* \param[in] Message ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmResume(IN struct platform_device *PDev) ++{ ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Trigger to do HIF loopback test. ++* ++* \param[in] arg Pointer to the GLUE_INFO_T structure. ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifAhbLoopbkAuto(IN unsigned long arg) ++{ ++ ++ P_GLUE_INFO_T GlueInfo = (P_GLUE_INFO_T) arg; ++ GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(GlueInfo); ++ ++ HIF_DBG(("[WiFi/HIF] Trigger to do loopback test...\n")); ++ ++ set_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &HifInfo->HifLoopbkFlg); ++ wake_up_interruptible(&HifInfo->HifWaitq); ++ ++} ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo) ++{ ++ GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; ++ unsigned short j; ++ ++ for (j = 0; j < 512; j++) { ++ DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(prHifInfo, CONN_MCU_CPUPCR)); ++ if ((j + 1) % 16 == 0) ++ DBGLOG(INIT, WARN, "\n"); ++ } ++} ++ ++/* End of ahb.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c +new file mode 100644 +index 000000000000..6b719028ae93 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++*[File] mt6516-evb.c ++*[Version] v1.0 ++*[Revision Date] 2010-03-01 ++*[Author] ++*[Description] ++* dummy file for build system ++*[Copyright] ++* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: mt6516-evb.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug message ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h +new file mode 100644 +index 000000000000..1507d5560040 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h +@@ -0,0 +1,340 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif.h" ++ \brief Functions for the driver to register bus and setup the IRQ ++ ++ Functions for the driver to register bus and setup the IRQ ++*/ ++ ++/* ++** Log: hif.h ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * add ENE SDIO host workaround for x86 linux platform. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\4 2009-10-20 17:38:28 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\3 2009-09-28 20:19:20 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\2 2009-08-18 22:57:05 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\2 2008-09-22 23:18:17 GMT mtk01461 ++** Update driver for code review ++** Revision 1.1 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++*/ ++ ++#ifndef _HIF_H ++#define _HIF_H ++ ++#include "gl_typedef.h" ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CONF_MTK_AHB_DMA 1 /* PIO mode is default mode if DMA is disabled */ ++ ++#define CONF_HIF_DEV_MISC 0 /* register as misc device */ ++#define CONF_HIF_LOOPBACK_AUTO 0 /* hif loopback test triggered by open() */ ++ /* only for development test */ ++ ++#define CONF_HIF_PMIC_TEST 0 /* test purpose: power on CONNSYS */ ++ ++#define CONF_HIF_DMA_INT 0 /* DMA interrupt mode */ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern phys_addr_t gConEmiPhyBase; ++extern BOOLEAN fgIsResetting; ++extern UINT_32 IsrCnt, IsrPassCnt; ++extern int kalDevLoopbkThread(IN void *data); ++ ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++extern INT_32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT_32 enable); ++#else /*for MT6572/82/92 */ ++extern void upmu_set_vcn33_on_ctrl_wifi(UINT_32 val); ++#endif ++#endif ++ ++#if (CONF_HIF_DEV_MISC == 1) ++#else ++/* extern INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_en); */ ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#ifndef CONN_MCU_CONFIG_BASE ++#define CONN_MCU_CONFIG_BASE 0xF8070000 /* MT6572 */ ++#endif /* CONN_MCU_CONFIG_BASE */ ++ ++#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) ++#define CONSYS_REG_READ(addr) (*((volatile unsigned int *)(addr))) ++ ++#define CONN_MCU_DRV_BASE 0x18070000 ++#define CONN_MCU_REG_LENGTH 0x0200 ++#define CONN_MCU_CPUPCR 0x0160 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* host interface's private data structure, which is attached to os glue ++** layer info structure. ++ */ ++typedef struct _GL_HIF_DMA_OPS_T { /* DMA Operators */ ++ VOID (*DmaConfig)(IN VOID *HifInfo, IN VOID *Conf); ++ ++ VOID (*DmaStart)(IN VOID *HifInfo); ++ ++ VOID (*DmaStop)(IN VOID *HifInfo); ++ ++ MTK_WCN_BOOL (*DmaPollStart)(IN VOID *HifInfo); ++ ++ MTK_WCN_BOOL (*DmaPollIntr)(IN VOID *HifInfo); ++ ++ VOID (*DmaAckIntr)(IN VOID *HifInfo); ++ ++ VOID (*DmaClockCtrl)(IN UINT_32 FlgIsEnabled); ++ ++ VOID (*DmaRegDump)(IN VOID *HifInfo); ++ ++ VOID (*DmaReset)(IN VOID *HifInfo); ++ ++} GL_HIF_DMA_OPS_T; ++ ++typedef struct _GL_HIF_INFO_T { ++ ++ /* General */ ++ VOID *Dev; /* struct device */ ++ ++#define MTK_CHIP_ID_6571 0x6571 ++#define MTK_CHIP_ID_6572 0x6572 ++#define MTK_CHIP_ID_6582 0x6582 ++#define MTK_CHIP_ID_8127 0x8127 ++#define MTK_CHIP_ID_6752 0x6752 ++#define MTK_CHIP_ID_8163 0x8163 ++#define MTK_CHIP_ID_6735 0x6735 ++#define MTK_CHIP_ID_6580 0x6580 ++#define MTK_CHIP_ID_6755 0x6755 ++#define MTK_CHIP_ID_7623 0x7623 ++ ++ UINT_32 ChipID; ++ ++ /* Control flag */ ++ BOOLEAN fgIntReadClear; ++ BOOLEAN fgMbxReadClear; ++ BOOLEAN fgDmaEnable; /* TRUE: DMA mode is used (default) */ ++ ++ /* HIF related */ ++ UINT_8 *HifRegBaseAddr; /* HIF register base */ ++ UINT_8 *McuRegBaseAddr; /* CONN MCU register base */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ struct timer_list HifTmrLoopbkFn; /* HIF loopback test trigger timer */ ++ wait_queue_head_t HifWaitq; ++ UINT_32 HifLoopbkFlg; ++ struct task_struct *HifTaskLoopbkFn; /* HIF loopback test task */ ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++ wait_queue_head_t HifDmaWaitq; ++ UINT_32 HifDmaWaitFlg; ++#endif /* CONF_HIF_DMA_INT */ ++ ++ /* DMA related */ ++#define AP_DMA_HIF_LOCK(_lock) /* spin_lock_bh(&(_lock)->DdmaLock) */ ++#define AP_DMA_HIF_UNLOCK(_lock) /* spin_unlock_bh(&(_lock)->DdmaLock) */ ++ spinlock_t DdmaLock; /* protect DMA access */ ++ ++ UINT_8 *DmaRegBaseAddr; /* DMA register base */ ++ GL_HIF_DMA_OPS_T *DmaOps; /* DMA Operators */ ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ struct clk *clk_wifi_dma; ++#endif ++} GL_HIF_INFO_T, *P_GL_HIF_INFO_T; ++ ++#define HIF_MOD_NAME "AHB_SLAVE_HIF" ++ ++#define HIF_DRV_BASE 0x180F0000 ++#define HIF_DRV_LENGTH 0x005c ++ ++typedef enum _MTK_WCN_HIF_BURST_LEN { ++ HIF_BURST_1DW = 0, ++ HIF_BURST_4DW, ++ HIF_BURST_8DW ++} MTK_WCN_HIF_BURST_LEN; ++ ++typedef enum _MTK_WCN_HIF_TXRX_TARGET { ++ HIF_TARGET_TXD0 = 0, ++ HIF_TARGET_TXD1, ++ HIF_TARGET_RXD0, ++ HIF_TARGET_RXD1, ++ HIF_TARGET_WHISR ++} MTK_WCN_HIF_TXRX_TARGET; ++ ++typedef enum _MTK_WCN_HIF_DMA_DIR { ++ HIF_DMA_DIR_TX = 0, ++ HIF_DMA_DIR_RX ++} MTK_WCN_HIF_DMA_DIR; ++ ++typedef struct _MTK_WCN_HIF_DMA_CONF { ++ UINT_32 Count; ++ MTK_WCN_HIF_DMA_DIR Dir; ++ UINT_32 Burst; ++ UINT_32 Wsize; ++ UINT_32 Ratio; ++ UINT_32 Connect; ++ UINT_32 Fix_en; ++ ULONG Src; ++ ULONG Dst; ++} MTK_WCN_HIF_DMA_CONF; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define MCU_REG_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->McuRegBaseAddr + _addr)) ++ ++/* PIO mode HIF register read/write */ ++#define HIF_REG_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr)) ++ ++#define HIF_REG_WRITEL(_hif, _addr, _val) \ ++ writel(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) ++ ++#define HIF_REG_WRITEB(_hif, _addr, _val) \ ++ writeb(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) ++ ++/* PIO mode DMA register read/write */ ++#define HIF_DMAR_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr)) ++ ++#define HIF_DMAR_WRITEL(_hif, _addr, _val) \ ++ writel(_val, ((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr))) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#ifndef MODULE_AHB_DMA ++VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter); ++ ++VOID HifRegDump(P_ADAPTER_T prAdapter); ++ ++BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove); ++ ++VOID glUnregisterBus(remove_card pfRemove); ++ ++VOID glResetHif(GLUE_INFO_T *GlueInfo); ++ ++VOID glSetHifInfo(P_GLUE_INFO_T prGlueInfo, ULONG ulCookie); ++ ++VOID glClearHifInfo(P_GLUE_INFO_T prGlueInfo); ++ ++VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf); ++ ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo); ++#endif ++ ++BOOLEAN glBusInit(PVOID pvData); ++ ++VOID glBusRelease(PVOID pData); ++ ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie); ++ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie); ++ ++VOID glSetPowerState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 ePowerMode); ++ ++VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo); ++ ++#endif /* MODULE_AHB_DMA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config GDMA TX/RX. ++* ++* \param[in] DmaRegBaseAddr Pointer to the IO register base. ++* \param[in] Conf Pointer to the DMA operator. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifGdmaInit(GL_HIF_INFO_T *HifInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] DmaRegBaseAddr Pointer to the IO register base. ++* \param[in] Conf Pointer to the DMA operator. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h +new file mode 100644 +index 000000000000..094c07f98eff +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h +@@ -0,0 +1,154 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif_gdma.h" ++ \brief MARCO, definition, structure for GDMA. ++ ++ MARCO, definition, structure for GDMA. ++*/ ++ ++/* ++** Log: hif_gdma.h ++ * ++ * 01 16 2013 vend_samp.lin ++ * Add AHB GDMA support ++ * 1) Initial version ++** ++*/ ++ ++#ifndef _HIF_GDMA_H ++#define _HIF_GDMA_H ++ ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _MTK_WCN_HIF_GDMA_BURST_LEN { ++ HIF_GDMA_BURST_1_8 = 0, ++ HIF_GDMA_BURST_2_8, ++ HIF_GDMA_BURST_3_8, ++ HIF_GDMA_BURST_4_8, ++ HIF_GDMA_BURST_5_8, ++ HIF_GDMA_BURST_6_8, ++ HIF_GDMA_BURST_7_8, ++ HIF_GDMA_BURST_8_8 /* same as HIF_GDMA_BURST_7_8 */ ++} MTK_WCN_HIF_GDMA_BURST_LEN; ++ ++typedef enum _MTK_WCN_HIF_GDMA_WRITE_LEN { ++ HIF_GDMA_WRITE_0 = 0, /* transaction size is 1 byte */ ++ HIF_GDMA_WRITE_1, /* transaction size is 2 byte */ ++ HIF_GDMA_WRITE_2, /* transaction size is 4 byte */ ++ HIF_GDMA_WRITE_3 /* transaction size is 1 byte */ ++} MTK_WCN_HIF_GDMA_WRITE_LEN; ++ ++typedef enum _MTK_WCN_HIF_GDMA_RATIO { ++ HIF_GDMA_RATIO_0 = 0, /* 1/2 */ ++ HIF_GDMA_RATIO_1 /* 1/1 */ ++} MTK_WCN_HIF_GDMA_RATIO; ++ ++typedef enum _MTK_WCN_HIF_GDMA_CONNECT { ++ HIF_GDMA_CONNECT_NO = 0, /* no connect */ ++ HIF_GDMA_CONNECT_SET1, /* connect set1 (req/ack) */ ++ HIF_GDMA_CONNECT_SET2, /* connect set2 (req/ack) */ ++ HIF_GDMA_CONNECT_SET3 /* connect set3 (req/ack) */ ++} MTK_WCN_HIF_GDMA_CONNECT; ++ ++/* reference to MT6572_AP_P_DMA_Spec.doc */ ++#define AP_DMA_HIF_BASE 0x11000100 ++ ++#define AP_P_DMA_G_DMA_2_INT_FLAG (0x0000) ++#define AP_P_DMA_G_DMA_2_CON (0x0018) ++#define AP_P_DMA_G_DMA_2_CONNECT (0x0034) ++#define AP_P_DMA_G_DMA_2_LEN1 (0x0024) ++#define AP_P_DMA_G_DMA_2_SRC_ADDR (0x001C) ++#define AP_P_DMA_G_DMA_2_DST_ADDR (0x0020) ++#define AP_P_DMA_G_DMA_2_INT_EN (0x0004) ++#define AP_P_DMA_G_DMA_2_EN (0x0008) ++#define AP_P_DMA_G_DMA_2_RST (0x000C) ++#define AP_P_DMA_G_DMA_2_STOP (0x0010) ++ ++#define AP_DMA_HIF_0_LENGTH 0x0038 ++ ++/* AP_DMA_HIF_0_INT_FLAG */ ++#define ADH_CR_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_INT_EN */ ++#define ADH_CR_INTEN_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_EN */ ++#define ADH_CR_EN BIT(0) ++#define ADH_CR_CONN_BUR_EN BIT(1) ++ ++/* AP_DMA_HIF_0_STOP */ ++#define ADH_CR_PAUSE BIT(1) ++#define ADH_CR_STOP BIT(0) ++ ++/* AP_P_DMA_G_DMA_2_CON */ ++#define ADH_CR_FLAG_FINISH BIT(30) ++#define ADH_CR_RSIZE BITS(28, 29) ++#define ADH_CR_RSIZE_OFFSET 28 ++#define ADH_CR_WSIZE BITS(24, 25) ++#define ADH_CR_WSIZE_OFFSET 24 ++#define ADH_CR_BURST_LEN BITS(16, 18) ++#define ADH_CR_BURST_LEN_OFFSET 16 ++#define ADH_CR_WADDR_FIX_EN BIT(3) ++#define ADH_CR_WADDR_FIX_EN_OFFSET 3 ++#define ADH_CR_RADDR_FIX_EN BIT(4) ++#define ADH_CR_RADDR_FIX_EN_OFFSET 4 ++ ++/* AP_P_DMA_G_DMA_2_CONNECT */ ++#define ADH_CR_RATIO BIT(3) ++#define ADH_CR_RATIO_OFFSET 3 ++#define ADH_CR_DIR BIT(2) ++#define ADH_CR_DIR_OFFSET 2 ++#define ADH_CR_CONNECT BITS(0, 1) ++ ++/* AP_DMA_HIF_0_LEN */ ++#define ADH_CR_LEN BITS(0, 19) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_GDMA_H */ ++ ++/* End of hif_gdma.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h +new file mode 100644 +index 000000000000..32224e8f17d8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h +@@ -0,0 +1,141 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif_pdma.h" ++ \brief MARCO, definition, structure for PDMA. ++ ++ MARCO, definition, structure for PDMA. ++*/ ++ ++/* ++** Log: hif_pdma.h ++ * ++ * 01 16 2013 vend_samp.lin ++ * Add AHB PDMA support ++ * 1) Initial version ++** ++*/ ++ ++#ifndef _HIF_PDMA_H ++#define _HIF_PDMA_H ++ ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _MTK_WCN_HIF_PDMA_BURST_LEN { ++ HIF_PDMA_BURST_1_4 = 0, ++ HIF_PDMA_BURST_2_4, ++ HIF_PDMA_BURST_3_4, ++ HIF_PDMA_BURST_4_4 ++} MTK_WCN_HIF_PDMA_BURST_LEN; ++ ++/* reference to MT6572_AP_P_DMA_Spec.doc */ ++#ifdef CONFIG_OF ++/*for MT6752*/ ++#define AP_DMA_HIF_BASE 0x11000080 ++#else ++/*for MT6572/82/92*/ ++#define AP_DMA_HIF_BASE 0x11000180 ++#endif ++ ++#define AP_DMA_HIF_0_INT_FLAG (0x0000) ++#define AP_DMA_HIF_0_INT_EN (0x0004) ++#define AP_DMA_HIF_0_EN (0x0008) ++#define AP_DMA_HIF_0_RST (0x000C) ++#define AP_DMA_HIF_0_STOP (0x0010) ++#define AP_DMA_HIF_0_FLUSH (0x0014) ++#define AP_DMA_HIF_0_CON (0x0018) ++#define AP_DMA_HIF_0_SRC_ADDR (0x001C) ++#define AP_DMA_HIF_0_DST_ADDR (0x0020) ++#define AP_DMA_HIF_0_LEN (0x0024) ++#define AP_DMA_HIF_0_INT_BUF_SIZE (0x0038) ++#define AP_DMA_HIF_0_DEBUG_STATUS (0x0050) ++#define AP_DMA_HIF_0_SRC_ADDR2 (0x0054) ++#define AP_DMA_HIF_0_DST_ADDR2 (0x0058) ++ ++#define AP_DMA_HIF_0_LENGTH 0x0080 ++ ++/* AP_DMA_HIF_0_INT_FLAG */ ++#define ADH_CR_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_INT_EN */ ++#define ADH_CR_INTEN_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_EN */ ++#define ADH_CR_EN BIT(0) ++ ++/* AP_DMA_HIF_0_RST */ ++#define ADH_CR_HARD_RST BIT(1) ++#define ADH_CR_WARM_RST BIT(0) ++ ++/* AP_DMA_HIF_0_STOP */ ++#define ADH_CR_PAUSE BIT(1) ++#define ADH_CR_STOP BIT(0) ++ ++/* AP_DMA_HIF_0_FLUSH */ ++#define ADH_CR_FLUSH BIT(0) ++ ++/* AP_DMA_HIF_0_CON */ ++#define ADH_CR_BURST_LEN BITS(16, 17) ++#define ADH_CR_BURST_LEN_OFFSET 16 ++#define ADH_CR_SLOW_CNT BITS(5, 14) ++#define ADH_CR_SLOW_EN BIT(2) ++#define ADH_CR_FIX_EN BIT(1) ++#define ADH_CR_FIX_EN_OFFSET 1 ++#define ADH_CR_DIR BIT(0) ++ ++/* AP_DMA_HIF_0_LEN */ ++#define ADH_CR_LEN BITS(0, 19) ++ ++/* AP_DMA_HIF_0_SRC_ADDR2 */ ++#define ADH_CR_SRC_ADDR2 BIT(0) ++/* AP_DMA_HIF_0_DST_ADDR2 */ ++#define ADH_CR_DST_ADDR2 BIT(0) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_PDMA_H */ ++ ++/* End of hif_gdma.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h +new file mode 100644 +index 000000000000..91557137af9a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h +@@ -0,0 +1,91 @@ ++/* porting layer */ ++/* Android */ ++ ++#ifndef _MTK_PORTING_H_ ++#define _MTK_PORTING_H_ ++ ++#include /* include stddef.h for NULL */ ++ ++#define CONF_MTK_AHB_DMA 1 ++ ++/* Type definition for signed integers */ ++/*typedef signed char INT8, *PINT8; ++typedef signed short INT16, *PINT16; ++typedef signed int INT_32, *PINT32;*/ ++ ++/* Type definition for unsigned integers */ ++/*typedef unsigned char UINT8, *PUINT8; ++typedef unsigned short UINT16, *PUINT16; ++typedef unsigned int UINT32, *PUINT32;*/ ++ ++#ifndef VOID ++/*typedef void VOID, *PVOID;*/ ++#endif ++ ++#ifndef IN ++#define IN ++#endif ++ ++#ifndef OUT ++#define OUT ++#endif ++ ++#ifndef INTOUT ++#define INOUT ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef BIT ++#define BIT(n) ((UINT_32) 1U << (n)) ++#endif /* BIT */ ++ ++#ifndef BITS ++/* bits range: for example BITS(16,23) = 0xFF0000 ++ * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 ++ * ==> (BIT(n+1)-1) = 0x00FFFFFF ++ */ ++#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) ++#endif /* BIT */ ++ ++#ifndef BOOLEAN ++#define BOOLEAN unsigned char ++#endif ++ ++typedef int MTK_WCN_BOOL; ++#ifndef MTK_WCN_BOOL_TRUE ++#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) ++#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) ++#endif ++ ++typedef int MTK_WCN_MUTEX; ++ ++typedef int MTK_WCN_TIMER; ++ ++/* system APIs */ ++/* mutex */ ++typedef MTK_WCN_MUTEX(*MUTEX_CREATE) (const char *const name); ++typedef INT_32(*MUTEX_DESTROY) (MTK_WCN_MUTEX mtx); ++typedef INT_32(*MUTEX_LOCK) (MTK_WCN_MUTEX mtx); ++typedef INT_32(*MUTEX_UNLOCK) (MTK_WCN_MUTEX mtx, unsigned long flags); ++/* debug */ ++typedef INT_32(*DBG_PRINT) (const char *str, ...); ++typedef INT_32(*DBG_ASSERT) (INT_32 expr, const char *file, INT_32 line); ++/* timer */ ++typedef void (*MTK_WCN_TIMER_CB) (void); ++typedef MTK_WCN_TIMER(*TIMER_CREATE) (const char *const name); ++typedef INT_32(*TIMER_DESTROY) (MTK_WCN_TIMER tmr); ++typedef INT_32(*TIMER_START) (MTK_WCN_TIMER tmr, UINT_32 timeout, MTK_WCN_TIMER_CB tmr_cb, void *param); ++typedef INT_32(*TIMER_STOP) (MTK_WCN_TIMER tmr); ++/* kernel lib */ ++typedef void *(*SYS_MEMCPY) (void *dest, const void *src, UINT_32 n); ++typedef void *(*SYS_MEMSET) (void *s, INT_32 c, UINT_32 n); ++typedef INT_32(*SYS_SPRINTF) (char *str, const char *format, ...); ++ ++#endif /* _MTK_PORTING_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c +new file mode 100644 +index 000000000000..94cc05ba3224 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c +@@ -0,0 +1,480 @@ ++/****************************************************************************** ++*[File] ahb_pdma.c ++*[Version] v1.0 ++*[Revision Date] 2013-03-13 ++*[Author] ++*[Description] ++* The program provides AHB PDMA driver ++*[Copyright] ++* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: ahb_pdma.c ++ * ++ * 03 13 2013 vend_samp.lin ++ * Add AHB PDMA support ++ * 1) Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#define MODULE_AHB_DMA ++ ++#include /* constant of kernel version */ ++ ++#include /* bitops.h */ ++ ++#include /* struct timer_list */ ++#include /* jiffies */ ++#include /* udelay and mdelay macro */ ++ ++#if 0 ++#if CONFIG_ANDROID ++#include ++#endif ++#endif ++ ++#include /* IRQT_FALLING */ ++ ++#include /* struct net_device, struct net_device_stats */ ++#include /* for eth_type_trans() function */ ++#include /* struct iw_statistics */ ++#include ++#include /* struct in_device */ ++ ++#include /* struct iphdr */ ++ ++#include /* for memcpy()/memset() function */ ++#include /* for offsetof() macro */ ++ ++#include /* The proc filesystem constants/structures */ ++ ++#include /* for rtnl_lock() and rtnl_unlock() */ ++#include /* kthread_should_stop(), kthread_run() */ ++#include /* for copy_from_user() */ ++#include /* for firmware download */ ++#include ++ ++#include /* for kfifo interface */ ++#include /* for cdev interface */ ++ ++#include /* for firmware download */ ++ ++#include ++ ++#include /* readw and writew */ ++ ++#include ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#include ++#else ++#include ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ ++#include "hif.h" ++#include "hif_pdma.h" ++#include "gl_os.h" ++ ++/* #include */ ++ ++/* #if (CONF_MTK_AHB_DMA == 1) */ ++ ++/* #define PDMA_DEBUG_SUP */ ++ ++#ifdef PDMA_DEBUG_SUP ++#define PDMA_DBG pr_debug ++#else ++#define PDMA_DBG(_fmt, ...) ++#endif /* PDMA_DEBUG_SUP */ ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++struct clk *g_clk_wifi_pdma; ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Conf); ++ ++static VOID HifPdmaStart(IN void *HifInfoSrc); ++ ++static VOID HifPdmaStop(IN void *HifInfoSrc); ++ ++static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc); ++ ++static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc); ++ ++static VOID HifPdmaAckIntr(IN void *HifInfoSrc); ++ ++static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled); ++ ++static VOID HifPdmaRegDump(IN void *HifInfoSrc); ++ ++static VOID HifPdmaReset(IN void *HifInfoSrc); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++GL_HIF_DMA_OPS_T HifPdmaOps = { ++ .DmaConfig = HifPdmaConfig, ++ .DmaStart = HifPdmaStart, ++ .DmaStop = HifPdmaStop, ++ .DmaPollStart = HifPdmaPollStart, ++ .DmaPollIntr = HifPdmaPollIntr, ++ .DmaAckIntr = HifPdmaAckIntr, ++ .DmaClockCtrl = HifPdmaClockCtrl, ++ .DmaRegDump = HifPdmaRegDump, ++ .DmaReset = HifPdmaReset ++}; ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Conf Pointer to the settings. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo) ++{ ++ /* IO remap PDMA register memory */ ++#ifdef AP_DMA_HIF_BASE ++#undef AP_DMA_HIF_BASE ++#define AP_DMA_HIF_BASE 0x11000180 ++#endif ++ HifInfo->DmaRegBaseAddr = ioremap(AP_DMA_HIF_BASE, AP_DMA_HIF_0_LENGTH); ++ ++ /* assign PDMA operators */ ++ HifInfo->DmaOps = &HifPdmaOps; ++ ++ /* enable PDMA mode */ ++ HifInfo->fgDmaEnable = TRUE; ++ ++ /* Set EMI protection here */ ++#if 0 ++#ifdef MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT ++ DBGLOG(INIT, INFO, "WIFI set EMI MPU for TEE project\n"); ++ emi_mpu_set_region_protection(gConEmiPhyBase, ++ gConEmiPhyBase + SZ_1M / 2, ++ 5, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); ++#else ++ DBGLOG(INIT, INFO, "WIFI set EMI MPU for non-TEE project\n"); ++ emi_mpu_set_region_protection(gConEmiPhyBase, ++ gConEmiPhyBase + SZ_1M / 2, ++ 4, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); ++#endif ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ g_clk_wifi_pdma = HifInfo->clk_wifi_dma; ++#endif ++ ++ PDMA_DBG("PDMA> HifPdmaInit ok!\n"); ++} ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* \param[in] Param Pointer to the settings. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Param) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ MTK_WCN_HIF_DMA_CONF *Conf = (MTK_WCN_HIF_DMA_CONF *) Param; ++ UINT32 RegVal; ++ ++ /* Assign fixed value */ ++ Conf->Burst = HIF_PDMA_BURST_4_4; /* vs. HIF_BURST_4DW */ ++ Conf->Fix_en = FALSE; ++ ++ /* AP_P_DMA_G_DMA_2_CON */ ++ PDMA_DBG("PDMA> Conf->Dir = %d\n", Conf->Dir); ++ ++ /* AP_DMA_HIF_0_CON */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_CON); ++ RegVal &= ~(ADH_CR_BURST_LEN | ADH_CR_FIX_EN | ADH_CR_DIR); ++ RegVal |= (((Conf->Burst << ADH_CR_BURST_LEN_OFFSET) & ADH_CR_BURST_LEN) | ++ (Conf->Fix_en << ADH_CR_FIX_EN_OFFSET) | (Conf->Dir)); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_CON, RegVal); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_CON = 0x%08x\n", RegVal); ++ ++ /* AP_DMA_HIF_0_SRC_ADDR */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_SRC_ADDR, Conf->Src); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_SRC_ADDR = 0x%08lx\n", Conf->Src); ++ ++ /* AP_DMA_HIF_0_DST_ADDR */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_DST_ADDR, Conf->Dst); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_DST_ADDR = 0x%08lx\n", Conf->Dst); ++ ++ /* AP_DMA_HIF_0_LEN */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_LEN, (Conf->Count & ADH_CR_LEN)); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_LEN = %u\n", (UINT_32)(Conf->Count & ADH_CR_LEN)); ++ ++} /* End of HifPdmaConfig */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Start PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaStart(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ /* Enable interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal | ADH_CR_INTEN_FLAG_0)); ++ ++ /* Start DMA */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_EN, (RegVal | ADH_CR_EN)); ++ ++ PDMA_DBG("PDMA> HifPdmaStart...\n"); ++ ++} /* End of HifPdmaStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaStop(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++/* UINT32 pollcnt; */ ++ ++ /* Disable interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal & ~(ADH_CR_INTEN_FLAG_0))); ++ ++#if 0 /* DE says we donot need to do it */ ++ /* Stop DMA */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_STOP); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_STOP, (RegVal | ADH_CR_STOP)); ++ ++ /* Polling START bit turn to 0 */ ++ pollcnt = 0; ++ do { ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ if (pollcnt++ > 100000) ++ ; /* TODO: warm reset PDMA */ ++ } while (RegVal & ADH_CR_EN); ++#endif ++ ++} /* End of HifPdmaStop */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Enable PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ return ((RegVal & ADH_CR_EN) != 0) ? TRUE : FALSE; ++ ++} /* End of HifPdmaPollStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Poll PDMA TX/RX done. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); ++ return ((RegVal & ADH_CR_FLAG_0) != 0) ? TRUE : FALSE; ++ ++} /* End of HifPdmaPollIntr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Acknowledge PDMA TX/RX done. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaAckIntr(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ /* Write 0 to clear interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_FLAG, (RegVal & ~ADH_CR_FLAG_0)); ++ ++} /* End of HifPdmaAckIntr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Acknowledge PDMA TX/RX done. ++* ++* \param[in] FlgIsEnabled TRUE: enable; FALSE: disable ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled) ++{ ++#if !defined(CONFIG_MTK_CLKMGR) ++ int ret = 0; ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ if (FlgIsEnabled == TRUE) ++ enable_clock(MT_CG_INFRA_APDMA, "WLAN"); ++ else ++ disable_clock(MT_CG_INFRA_APDMA, "WLAN"); ++#else ++ if (FlgIsEnabled == TRUE) { ++ ret = clk_prepare_enable(g_clk_wifi_pdma); ++ if (ret) ++ DBGLOG(INIT, TRACE, "[CCF]clk_prepare_enable ret= %d\n", ret); ++ } else { ++ clk_disable_unprepare(g_clk_wifi_pdma); ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dump PDMA related registers. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaRegDump(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegId, RegVal; ++ UINT32 RegNum = 0; ++ ++ DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE); ++ for (RegId = 0; RegId < AP_DMA_HIF_0_LENGTH; RegId += 4) { ++ RegVal = HIF_DMAR_READL(HifInfo, RegId); ++ DBGLOG(INIT, INFO, "0x%08x ", RegVal); ++ ++ if (RegNum++ >= 3) { ++ DBGLOG(INIT, INFO, "\n"); ++ DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE + RegId + 4); ++ RegNum = 0; ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reset DMA. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaReset(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 LoopCnt; ++ ++ /* do warm reset: DMA will wait for current traction finished */ ++ DBGLOG(INIT, INFO, "\nDMA> do warm reset...\n"); ++ ++ /* normally, we need to sure that bit0 of AP_P_DMA_G_DMA_2_EN is 1 here */ ++ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x01); ++ ++ for (LoopCnt = 0; LoopCnt < 10000; LoopCnt++) { ++ if (!HifPdmaPollStart(HifInfo)) ++ break; /* reset ok */ ++ } ++ ++ if (HifPdmaPollStart(HifInfo)) { ++ /* do hard reset because warm reset fails */ ++ DBGLOG(INIT, INFO, "\nDMA> do hard reset...\n"); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x02); ++ mdelay(1); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x00); ++ } ++} ++ ++/* #endif */ /* CONF_MTK_AHB_DMA */ ++ ++/* End of ahb_pdma.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h +new file mode 100644 +index 000000000000..ec9f46bdab2e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h +@@ -0,0 +1,341 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_cfg80211.h#1 ++*/ ++ ++/*! \file gl_cfg80211.h ++ \brief This file is for Portable Driver linux cfg80211 support. ++*/ ++ ++/* ++** Log: gl_cfg80211.h ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++*/ ++ ++#ifndef _GL_CFG80211_H ++#define _GL_CFG80211_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include "gl_os.h" ++extern void wlanHandleSystemResume(void); ++extern void wlanHandleSystemSuspend(void); ++extern void p2pHandleSystemResume(void); ++extern void p2pHandleSystemSuspend(void); ++ ++#if CFG_SUPPORT_WAPI ++extern UINT_8 keyStructBuf[1024]; /* add/remove key shared buffer */ ++#else ++extern UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ ++#endif ++ ++extern struct delayed_work sched_workq; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#if CONFIG_NL80211_TESTMODE ++#define NL80211_DRIVER_TESTMODE_VERSION 2 ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CONFIG_NL80211_TESTMODE ++ ++typedef struct _NL80211_DRIVER_GET_STA_STATISTICS_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4Version; ++ UINT_32 u4Flag; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++} NL80211_DRIVER_GET_STA_STATISTICS_PARAMS, *P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS; ++ ++typedef struct _NL80211_DRIVER_POORLINK_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ INT_8 cRssi; /* cRssi=0 means it is a invalid value. */ ++ UINT_8 ucLinkSpeed; /* ucLinkSpeed=0 means it is a invalid value */ ++ UINT_16 u2Reserved; ++} NL80211_DRIVER_POORLINK_PARAMS, *P_NL80211_DRIVER_POORLINK_PARAMS; ++ ++typedef enum _ENUM_TESTMODE_STA_STATISTICS_ATTR { ++ NL80211_TESTMODE_STA_STATISTICS_INVALID = 0, ++ NL80211_TESTMODE_STA_STATISTICS_VERSION, ++ NL80211_TESTMODE_STA_STATISTICS_MAC, ++ NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, ++ NL80211_TESTMODE_STA_STATISTICS_FLAG, ++ ++ NL80211_TESTMODE_STA_STATISTICS_PER, ++ NL80211_TESTMODE_STA_STATISTICS_RSSI, ++ NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, ++ NL80211_TESTMODE_STA_STATISTICS_TX_RATE, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ ++ NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, ++ ++ NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ ++ /* ++ * how many packages TX during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, ++ ++ /* ++ * how many packages this TX during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, ++ ++ /* ++ * how many packages dequeue during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, ++ ++ /* ++ * how many packages this sta dequeue during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, ++ ++ /* ++ * how many TC[0-3] resource back from firmware during ++ * statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, ++ ++ NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_NUM ++} ENUM_TESTMODE_STA_STATISTICS_ATTR; ++typedef struct _NL80211_DRIVER_SET_NFC_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 NFC_Enable; ++ ++} NL80211_DRIVER_SET_NFC_PARAMS, *P_NL80211_DRIVER_SET_NFC_PARAMS; ++typedef struct _NL80211_DRIVER_GET_SCANDONE_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4ScanDone; ++ ++} NL80211_DRIVER_GET_SCANDONE_PARAMS, *P_NL80211_DRIVER_GET_SCANDONE_PARAMS; ++ ++typedef enum _ENUM_TESTMODE_LINK_DETECTION_ATTR { ++ NL80211_TESTMODE_LINK_INVALID = 0, ++ NL80211_TESTMODE_LINK_TX_FAIL_CNT, ++ NL80211_TESTMODE_LINK_TX_RETRY_CNT, ++ NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, ++ NL80211_TESTMODE_LINK_ACK_FAIL_CNT, ++ NL80211_TESTMODE_LINK_FCS_ERR_CNT, ++ ++ NL80211_TESTMODE_LINK_DETECT_NUM, ++} ENUM_TESTMODE_LINK_DETECTION_ATTR; ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++typedef struct _NL80211_DRIVER_GET_LTE_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4Version; ++ UINT_32 u4Flag; ++ ++} NL80211_DRIVER_GET_LTE_PARAMS, *P_NL80211_DRIVER_GET_LTE_PARAMS; ++ ++/*typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR{ ++ NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, ++ NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ ++ NL80211_TESTMODE_AVAILABLE_CHAN_NUM, ++}ENUM_TESTMODE_AVAILABLE_CHAN_ATTR;*/ ++ ++#endif ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* cfg80211 hooks */ ++int ++mtk_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); ++ ++int ++mtk_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); ++ ++int ++mtk_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++); ++ ++int ++mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); ++ ++int ++mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast); ++ ++int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); ++ ++int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo); ++ ++int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params); ++ ++int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params); ++ ++int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params); ++//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac); ++ ++int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); ++ ++int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme); ++ ++int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code); ++ ++int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params); ++ ++int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev); ++ ++int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout); ++ ++int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); ++ ++int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); ++ ++int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev); ++ ++int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie); ++ ++int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int ++mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie); ++ ++void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ IN struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg); ++ ++int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req); ++ ++int ++mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request); ++ ++int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev,u64 reqid); ++ ++#if CONFIG_NL80211_TESTMODE ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++WLAN_STATUS ++wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++int ++mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++#endif ++int ++mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, ++ IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++ ++int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++ ++int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); ++ ++int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#if CFG_SUPPORT_WAPI ++int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#else ++#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" ++#endif ++int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); ++int mtk_cfg80211_resume(struct wiphy *wiphy); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_CFG80211_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +new file mode 100644 +index 000000000000..512e149abf75 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +@@ -0,0 +1,1565 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_kal.h#1 ++*/ ++ ++/*! \file gl_kal.h ++ \brief Declaration of KAL functions - kal*() which is provided by GLUE Layer. ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/* ++** Log: gl_kal.h ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 02 06 2012 wh.su ++ * [WCXRP00001177] [MT6620 Wi-Fi][Driver][2.2] Adding the query channel filter for AP mode ++ * adding the channel query filter for AP mode. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adjust the code for Non-DBG and no XLOG. ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous ++ * approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join ++ * timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters, eCurPsProf, for PS. ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * include link.h for linux's port. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 01 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface ++ * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR ++ * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW table. ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep ++ * long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 31 2010 jeffrey.chang ++ * [WCXRP00000332] [MT6620 Wi-Fi][Driver] add kal sleep function for delay which use blocking call ++ * modify the implementation of kalDelay to msleep ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field ++ * checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used ++ * to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at win XP. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * modify kalSetEvent declaration ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * fix kal header file ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * use different spin lock for security frame ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add new kal api ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * gl_kal merged ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * modify kalMemAlloc method ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when acquiring driver-own, wait for up to 8 seconds. ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL ++ * * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * * * 2) add KAPI for handling association info ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * * * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * * * 2) add 2 kal API for later integration ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\41 2009-09-28 20:19:23 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\40 2009-08-18 22:57:09 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\39 2009-06-23 23:19:15 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\38 2009-02-09 14:03:17 GMT mtk01090 ++** Add KAL function kalDevSetPowerState(). It is not implemented yet. Only add an empty macro. ++** ++** \main\maintrunk.MT5921\37 2009-01-22 13:05:59 GMT mtk01088 ++** new defeine to got 1x value at packet reserved field ++** \main\maintrunk.MT5921\36 2008-12-08 16:15:02 GMT mtk01461 ++** Add kalQueryValidBufferLength() macro ++** \main\maintrunk.MT5921\35 2008-11-13 20:33:15 GMT mtk01104 ++** Remove lint warning ++** \main\maintrunk.MT5921\34 2008-10-22 11:05:52 GMT mtk01461 ++** Remove unused macro ++** \main\maintrunk.MT5921\33 2008-10-16 15:48:17 GMT mtk01461 ++** Update driver to fix lint warning ++** \main\maintrunk.MT5921\32 2008-09-02 11:50:51 GMT mtk01461 ++** SPIN_LOCK_SDIO_DDK_TX_QUE ++** \main\maintrunk.MT5921\31 2008-08-29 15:58:30 GMT mtk01088 ++** remove non-used function for code refine ++** \main\maintrunk.MT5921\30 2008-08-21 00:33:29 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\29 2008-06-19 13:29:14 GMT mtk01425 ++** 1. Add declaration of SPIN_LOCK_SDIO_DDK_TX_QUE and SPIN_LOCK_SDIO_DDK_RX_QUE ++** \main\maintrunk.MT5921\28 2008-05-30 20:27:34 GMT mtk01461 ++** Rename KAL function ++** \main\maintrunk.MT5921\27 2008-05-30 14:42:05 GMT mtk01461 ++** Remove WMM Assoc Flag in KAL ++** \main\maintrunk.MT5921\26 2008-05-29 14:15:18 GMT mtk01084 ++** remove un-used function ++** \main\maintrunk.MT5921\25 2008-04-23 14:02:20 GMT mtk01084 ++** modify KAL port access function prototype ++** \main\maintrunk.MT5921\24 2008-04-17 23:06:41 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\23 2008-04-08 15:38:50 GMT mtk01084 ++** add KAL function to setting pattern search function enable/ disable ++** \main\maintrunk.MT5921\22 2008-03-26 15:34:48 GMT mtk01461 ++** Add update MAC address func ++** \main\maintrunk.MT5921\21 2008-03-18 15:56:15 GMT mtk01084 ++** update ENUM_NIC_INITIAL_PARAM_E ++** \main\maintrunk.MT5921\20 2008-03-18 11:49:28 GMT mtk01084 ++** update function for initial value access ++** \main\maintrunk.MT5921\19 2008-03-18 10:21:31 GMT mtk01088 ++** use kal update associate request at linux ++** \main\maintrunk.MT5921\18 2008-03-14 18:03:41 GMT mtk01084 ++** refine register and port access function ++** \main\maintrunk.MT5921\17 2008-03-11 14:51:02 GMT mtk01461 ++** Add copy_to(from)_user macro ++** \main\maintrunk.MT5921\16 2008-03-06 23:42:21 GMT mtk01385 ++** 1. add Query Registry Mac address function. ++** \main\maintrunk.MT5921\15 2008-02-26 09:48:04 GMT mtk01084 ++** modify KAL set network address/ checksum offload part ++** \main\maintrunk.MT5921\14 2008-01-09 17:54:58 GMT mtk01084 ++** Modify the argument of kalQueryPacketInfo ++** \main\maintrunk.MT5921\13 2007-11-29 02:05:20 GMT mtk01461 ++** Fix Windows RX multiple packet retain problem ++** \main\maintrunk.MT5921\12 2007-11-26 19:43:45 GMT mtk01461 ++** Add OS_TIMESTAMP macro ++** ++** \main\maintrunk.MT5921\11 2007-11-09 16:36:15 GMT mtk01425 ++** 1. Modify for CSUM offloading with Tx Fragment ++** \main\maintrunk.MT5921\10 2007-11-07 18:38:37 GMT mtk01461 ++** Add Tx Fragmentation Support ++** \main\maintrunk.MT5921\9 2007-11-06 19:36:50 GMT mtk01088 ++** add the WPS related code ++** \main\maintrunk.MT5921\8 2007-11-02 01:03:57 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** Revision 1.4 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:50 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:23 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_KAL_H ++#define _GL_KAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "config.h" ++#include "gl_typedef.h" ++#include "gl_os.h" ++#include "link.h" ++#include "nic/mac.h" ++#include "nic/wlan_def.h" ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "gl_wext_priv.h" ++#include ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "nic/bow.h" ++#endif ++ ++#if DBG ++extern int allocatedMemSize; ++#endif ++ ++#if CFG_SUPPORT_MET_PROFILING ++#include "linux/kallsyms.h" ++#include ++#endif ++ ++extern BOOLEAN fgIsUnderSuspend; ++extern UINT_32 TaskIsrCnt; ++extern BOOLEAN fgIsResetting; ++extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); ++extern UINT_32 u4MemAllocCnt, u4MemFreeCnt; ++ ++ ++extern struct delayed_work sched_workq; ++ ++#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* #define USEC_PER_MSEC (1000) */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SPIN_LOCK_CATEGORY_E { ++ SPIN_LOCK_FSM = 0, ++ ++ /* FIX ME */ ++ SPIN_LOCK_RX_QUE, ++ SPIN_LOCK_TX_QUE, ++ SPIN_LOCK_CMD_QUE, ++ SPIN_LOCK_TX_RESOURCE, ++ SPIN_LOCK_CMD_RESOURCE, ++ SPIN_LOCK_QM_TX_QUEUE, ++ SPIN_LOCK_CMD_PENDING, ++ SPIN_LOCK_CMD_SEQ_NUM, ++ SPIN_LOCK_TX_MSDU_INFO_LIST, ++ SPIN_LOCK_TXING_MGMT_LIST, ++ SPIN_LOCK_TX_SEQ_NUM, ++ SPIN_LOCK_TX_COUNT, ++ SPIN_LOCK_TXS_COUNT, ++ /* end */ ++ SPIN_LOCK_TX, ++ SPIN_LOCK_IO_REQ, ++ SPIN_LOCK_INT, ++ ++ SPIN_LOCK_MGT_BUF, ++ SPIN_LOCK_MSG_BUF, ++ SPIN_LOCK_STA_REC, ++ ++ SPIN_LOCK_MAILBOX, ++ SPIN_LOCK_TIMER, ++ ++ SPIN_LOCK_BOW_TABLE, ++ ++ SPIN_LOCK_EHPI_BUS, /* only for EHPI */ ++ SPIN_LOCK_NET_DEV, ++ SPIN_LOCK_NUM ++} ENUM_SPIN_LOCK_CATEGORY_E; ++ ++/* event for assoc information update */ ++typedef struct _EVENT_ASSOC_INFO { ++ UINT_8 ucAssocReq; /* 1 for assoc req, 0 for assoc rsp */ ++ UINT_8 ucReassoc; /* 0 for assoc, 1 for reassoc */ ++ UINT_16 u2Length; ++ PUINT_8 pucIe; ++} EVENT_ASSOC_INFO, *P_EVENT_ASSOC_INFO; ++ ++typedef enum _ENUM_KAL_NETWORK_TYPE_INDEX_T { ++ KAL_NETWORK_TYPE_AIS_INDEX = 0, ++#if CFG_ENABLE_WIFI_DIRECT ++ KAL_NETWORK_TYPE_P2P_INDEX, ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ KAL_NETWORK_TYPE_BOW_INDEX, ++#endif ++ KAL_NETWORK_TYPE_INDEX_NUM ++} ENUM_KAL_NETWORK_TYPE_INDEX_T; ++ ++typedef enum _ENUM_KAL_MEM_ALLOCATION_TYPE_E { ++ PHY_MEM_TYPE, /* physically continuous */ ++ VIR_MEM_TYPE, /* virtually continuous */ ++ MEM_TYPE_NUM ++} ENUM_KAL_MEM_ALLOCATION_TYPE; ++ ++#if CONFIG_ANDROID /* Defined in Android kernel source */ ++typedef struct wake_lock KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; ++#else ++typedef UINT_32 KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; ++#endif ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++typedef enum _ENUM_MTK_AGPS_ATTR { ++ MTK_ATTR_AGPS_INVALID, ++ MTK_ATTR_AGPS_CMD, ++ MTK_ATTR_AGPS_DATA, ++ MTK_ATTR_AGPS_IFINDEX, ++ MTK_ATTR_AGPS_IFNAME, ++ MTK_ATTR_AGPS_MAX ++} ENUM_MTK_CCX_ATTR; ++ ++typedef enum _ENUM_AGPS_EVENT { ++ AGPS_EVENT_WLAN_ON, ++ AGPS_EVENT_WLAN_OFF, ++ AGPS_EVENT_WLAN_AP_LIST, ++ WIFI_EVENT_CHIP_RESET, ++} ENUM_CCX_EVENT; ++BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen); ++#endif ++ ++struct KAL_HALT_CTRL_T { ++ struct semaphore lock; ++ struct task_struct *owner; ++ BOOLEAN fgHalt; ++ BOOLEAN fgHeldByKalIoctl; ++ OS_SYSTIME u4HoldStart; ++}; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of bit operation */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_SET_BIT(bitOffset, value) set_bit(bitOffset, &value) ++#define KAL_CLR_BIT(bitOffset, value) clear_bit(bitOffset, &value) ++#define KAL_TEST_AND_CLEAR_BIT(bitOffset, value) test_and_clear_bit(bitOffset, &value) ++#define KAL_TEST_BIT(bitOffset, value) test_bit(bitOffset, &value) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of SPIN LOCK operations for using in Driver Layer */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_SPIN_LOCK_DECLARATION() unsigned long __u4Flags ++ ++#define KAL_ACQUIRE_SPIN_LOCK(_prAdapter, _rLockCategory) \ ++ kalAcquireSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, &__u4Flags) ++ ++#define KAL_RELEASE_SPIN_LOCK(_prAdapter, _rLockCategory) \ ++ kalReleaseSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, __u4Flags) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for accessing Reserved Fields of native packet */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_GET_PKT_QUEUE_ENTRY(_p) GLUE_GET_PKT_QUEUE_ENTRY(_p) ++#define KAL_GET_PKT_DESCRIPTOR(_prQueueEntry) GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) ++#define KAL_GET_PKT_TID(_p) GLUE_GET_PKT_TID(_p) ++#define KAL_GET_PKT_IS1X(_p) GLUE_GET_PKT_IS1X(_p) ++#define KAL_GET_PKT_HEADER_LEN(_p) GLUE_GET_PKT_HEADER_LEN(_p) ++#define KAL_GET_PKT_PAYLOAD_LEN(_p) GLUE_GET_PKT_PAYLOAD_LEN(_p) ++#define KAL_GET_PKT_ARRIVAL_TIME(_p) GLUE_GET_PKT_ARRIVAL_TIME(_p) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of wake_lock operations for using in Driver Layer */ ++/*----------------------------------------------------------------------------*/ ++#if CONFIG_ANDROID /* Defined in Android kernel source */ ++#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) \ ++ wake_lock_init(_prWakeLock, WAKE_LOCK_SUSPEND, _pcName) ++ ++#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) \ ++ wake_lock_destroy(_prWakeLock) ++ ++#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) \ ++ wake_lock(_prWakeLock) ++ ++#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) \ ++ wake_lock_timeout(_prWakeLock, _u4Timeout) ++ ++#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) \ ++ wake_unlock(_prWakeLock) ++ ++#else ++#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) ++#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) ++#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) ++#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) ++#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Cache memory allocation ++* ++* \param[in] u4Size Required memory size. ++* \param[in] eMemType Memory allocation type ++* ++* \return Pointer to allocated memory ++* or NULL ++*/ ++/*----------------------------------------------------------------------------*/ ++#if DBG ++#define kalMemAlloc(u4Size, eMemType) ({ \ ++ void *pvAddr; \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ pvAddr = kmalloc(u4Size, GFP_KERNEL); \ ++ } \ ++ else { \ ++ pvAddr = vmalloc(u4Size); \ ++ } \ ++ if (pvAddr) { \ ++ allocatedMemSize += u4Size; \ ++ DBGLOG(INIT, INFO, "%p(%u) allocated (%s:%s)\n", \ ++ pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ ++ } \ ++ pvAddr; \ ++}) ++#else ++#define kalMemAlloc(u4Size, eMemType) ({ \ ++ void *pvAddr; \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ pvAddr = kmalloc(u4Size, GFP_KERNEL); \ ++ } \ ++ else { \ ++ pvAddr = vmalloc(u4Size); \ ++ } \ ++ pvAddr; \ ++}) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free allocated cache memory ++* ++* \param[in] pvAddr Required memory size. ++* \param[in] eMemType Memory allocation type ++* \param[in] u4Size Allocated memory size. ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#if DBG ++#define kalMemFree(pvAddr, eMemType, u4Size) \ ++{ \ ++ if (pvAddr) { \ ++ allocatedMemSize -= u4Size; \ ++ DBGLOG(INIT, INFO, "%p(%u) freed (%s:%s)\n", \ ++ pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ ++ } \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ kfree(pvAddr); \ ++ } \ ++ else { \ ++ vfree(pvAddr); \ ++ } \ ++} ++#else ++#define kalMemFree(pvAddr, eMemType, u4Size) \ ++{ \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ kfree(pvAddr); \ ++ } \ ++ else { \ ++ vfree(pvAddr); \ ++ } \ ++} ++#endif ++ ++#define kalUdelay(u4USec) udelay(u4USec) ++ ++#define kalMdelay(u4MSec) mdelay(u4MSec) ++#define kalMsleep(u4MSec) msleep(u4MSec) ++ ++/* Copy memory from user space to kernel space */ ++#define kalMemCopyFromUser(_pvTo, _pvFrom, _u4N) copy_from_user(_pvTo, _pvFrom, _u4N) ++ ++/* Copy memory from kernel space to user space */ ++#define kalMemCopyToUser(_pvTo, _pvFrom, _u4N) copy_to_user(_pvTo, _pvFrom, _u4N) ++ ++/* Copy memory block with specific size */ ++#define kalMemCopy(pvDst, pvSrc, u4Size) memcpy(pvDst, pvSrc, u4Size) ++ ++/* Set memory block with specific pattern */ ++#define kalMemSet(pvAddr, ucPattern, u4Size) memset(pvAddr, ucPattern, u4Size) ++ ++/* Compare two memory block with specific length. ++ * Return zero if they are the same. ++ */ ++#define kalMemCmp(pvAddr1, pvAddr2, u4Size) memcmp(pvAddr1, pvAddr2, u4Size) ++ ++/* Zero specific memory block */ ++#define kalMemZero(pvAddr, u4Size) memset(pvAddr, 0, u4Size) ++ ++/* string operation */ ++#define kalStrCpy(dest, src) strcpy(dest, src) ++#define kalStrnCpy(dest, src, n) strncpy(dest, src, n) ++#define kalStrCmp(ct, cs) strcmp(ct, cs) ++#define kalStrnCmp(ct, cs, n) strncmp(ct, cs, n) ++#define kalStrChr(s, c) strchr(s, c) ++#define kalStrrChr(s, c) strrchr(s, c) ++#define kalStrnChr(s, n, c) strnchr(s, n, c) ++#define kalStrLen(s) strlen(s) ++#define kalStrnLen(s, b) strnlen(s, b) ++//#define kalStrniCmp(s1, s2, n) strnicmp(s1, s2, n) ++#define kalStrniCmp(s1, s2, n) strncasecmp(s1, s2, n) ++#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n) ++/* #define kalStrtoul(cp, endp, base) simple_strtoul(cp, endp, base) ++#define kalStrtol(cp, endp, base) simple_strtol(cp, endp, base) */ ++#define kalkStrtou32(cp, base, resp) kstrtou32(cp, base, resp) ++#define kalkStrtos32(cp, base, resp) kstrtos32(cp, base, resp) ++#define kalSnprintf(buf, size, fmt, ...) snprintf(buf, size, fmt, __VA_ARGS__) ++#define kalSprintf(buf, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) ++/* remove for AOSP */ ++/* #define kalSScanf(buf, fmt, ...) sscanf(buf, fmt, __VA_ARGS__) */ ++#define kalStrStr(ct, cs) strstr(ct, cs) ++#define kalStrSep(s, ct) strsep(s, ct) ++#define kalStrCat(dest, src) strcat(dest, src) ++ ++/* defined for wince sdio driver only */ ++#if defined(_HIF_SDIO) ++#define kalDevSetPowerState(prGlueInfo, ePowerMode) glSetPowerState(prGlueInfo, ePowerMode) ++#else ++#define kalDevSetPowerState(prGlueInfo, ePowerMode) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Notify OS with SendComplete event of the specific packet. Linux should ++* free packets here. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] status Status Code for OS upper layer ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalSendComplete(prGlueInfo, pvPacket, status) \ ++ kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to locate the starting address of incoming ethernet ++* frame for skb. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* ++* \return starting address of ethernet frame buffer. ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalQueryBufferPointer(prGlueInfo, pvPacket) \ ++ ((PUINT_8)((struct sk_buff *)pvPacket)->data) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to query the length of valid buffer which is accessible during ++* port read/write. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* ++* \return starting address of ethernet frame buffer. ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalQueryValidBufferLength(prGlueInfo, pvPacket) \ ++ ((UINT_32)((struct sk_buff *)pvPacket)->end - \ ++ (UINT_32)((struct sk_buff *)pvPacket)->data) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to copy the entire frame from skb to the destination ++* address in the input parameter. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] pucDestBuffer Destination Address ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalCopyFrame(prGlueInfo, pvPacket, pucDestBuffer) \ ++ do {struct sk_buff *skb = (struct sk_buff *)pvPacket; \ ++ memcpy(pucDestBuffer, skb->data, skb->len); } while (0) ++ ++#define kalGetTimeTick() jiffies_to_msecs(jiffies) ++ ++#define kalPrint pr_debug ++ ++#if !DBG ++#define AIS_ERROR_LOGFUNC(_Fmt...) ++#define AIS_WARN_LOGFUNC(_Fmt...) ++#define AIS_INFO_LOGFUNC(_Fmt...) ++#define AIS_STATE_LOGFUNC(_Fmt...) ++#define AIS_EVENT_LOGFUNC(_Fmt...) ++#define AIS_TRACE_LOGFUNC(_Fmt...) ++#define AIS_LOUD_LOGFUNC(_Fmt...) ++#define AIS_TEMP_LOGFUNC(_Fmt...) ++ ++#define INTR_ERROR_LOGFUNC(_Fmt...) ++#define INTR_WARN_LOGFUNC(_Fmt...) ++#define INTR_INFO_LOGFUNC(_Fmt...) ++#define INTR_STATE_LOGFUNC(_Fmt...) ++#define INTR_EVENT_LOGFUNC(_Fmt...) ++#define INTR_TRACE_LOGFUNC(_Fmt...) ++#define INTR_LOUD_LOGFUNC(_Fmt...) ++#define INTR_TEMP_LOGFUNC(_Fmt...) ++ ++#define INIT_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_TRACE_LOGFUNC(_Fmt...) ++#define INIT_LOUD_LOGFUNC(_Fmt...) ++#define INIT_TEMP_LOGFUNC(_Fmt...) ++ ++#define AAA_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_LOUD_LOGFUNC(_Fmt...) ++#define AAA_TEMP_LOGFUNC(_Fmt...) ++ ++#define ROAMING_ERROR_LOGFUNC(_Fmt...) ++#define ROAMING_WARN_LOGFUNC(_Fmt...) ++#define ROAMING_INFO_LOGFUNC(_Fmt...) ++#define ROAMING_STATE_LOGFUNC(_Fmt...) ++#define ROAMING_EVENT_LOGFUNC(_Fmt...) ++#define ROAMING_TRACE_LOGFUNC(_Fmt...) ++#define ROAMING_LOUD_LOGFUNC(_Fmt...) ++#define ROAMING_TEMP_LOGFUNC(_Fmt...) ++ ++#define REQ_ERROR_LOGFUNC(_Fmt...) ++#define REQ_WARN_LOGFUNC(_Fmt...) ++#define REQ_INFO_LOGFUNC(_Fmt...) ++#define REQ_STATE_LOGFUNC(_Fmt...) ++#define REQ_EVENT_LOGFUNC(_Fmt...) ++#define REQ_TRACE_LOGFUNC(_Fmt...) ++#define REQ_LOUD_LOGFUNC(_Fmt...) ++#define REQ_TEMP_LOGFUNC(_Fmt...) ++ ++#define TX_ERROR_LOGFUNC(_Fmt...) ++#define TX_WARN_LOGFUNC(_Fmt...) ++#define TX_INFO_LOGFUNC(_Fmt...) ++#define TX_STATE_LOGFUNC(_Fmt...) ++#define TX_EVENT_LOGFUNC(_Fmt...) ++#define TX_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TX_LOUD_LOGFUNC(_Fmt...) ++#define TX_TEMP_LOGFUNC(_Fmt...) ++ ++#define RX_ERROR_LOGFUNC(_Fmt...) ++#define RX_WARN_LOGFUNC(_Fmt...) ++#define RX_INFO_LOGFUNC(_Fmt...) ++#define RX_STATE_LOGFUNC(_Fmt...) ++#define RX_EVENT_LOGFUNC(_Fmt...) ++#define RX_TRACE_LOGFUNC(_Fmt...) ++#define RX_LOUD_LOGFUNC(_Fmt...) ++#define RX_TEMP_LOGFUNC(_Fmt...) ++ ++#define RFTEST_ERROR_LOGFUNC(_Fmt...) ++#define RFTEST_WARN_LOGFUNC(_Fmt...) ++#define RFTEST_INFO_LOGFUNC(_Fmt...) ++#define RFTEST_STATE_LOGFUNC(_Fmt...) ++#define RFTEST_EVENT_LOGFUNC(_Fmt...) ++#define RFTEST_TRACE_LOGFUNC(_Fmt...) ++#define RFTEST_LOUD_LOGFUNC(_Fmt...) ++#define RFTEST_TEMP_LOGFUNC(_Fmt...) ++ ++#define EMU_ERROR_LOGFUNC(_Fmt...) ++#define EMU_WARN_LOGFUNC(_Fmt...) ++#define EMU_INFO_LOGFUNC(_Fmt...) ++#define EMU_STATE_LOGFUNC(_Fmt...) ++#define EMU_EVENT_LOGFUNC(_Fmt...) ++#define EMU_TRACE_LOGFUNC(_Fmt...) ++#define EMU_LOUD_LOGFUNC(_Fmt...) ++#define EMU_TEMP_LOGFUNC(_Fmt...) ++ ++#define HEM_ERROR_LOGFUNC(_Fmt...) ++#define HEM_WARN_LOGFUNC(_Fmt...) ++#define HEM_INFO_LOGFUNC(_Fmt...) ++#define HEM_STATE_LOGFUNC(_Fmt...) ++#define HEM_EVENT_LOGFUNC(_Fmt...) ++#define HEM_TRACE_LOGFUNC(_Fmt...) ++#define HEM_LOUD_LOGFUNC(_Fmt...) ++#define HEM_TEMP_LOGFUNC(_Fmt...) ++ ++#define RLM_ERROR_LOGFUNC(_Fmt...) ++#define RLM_WARN_LOGFUNC(_Fmt...) ++#define RLM_INFO_LOGFUNC(_Fmt...) ++#define RLM_STATE_LOGFUNC(_Fmt...) ++#define RLM_EVENT_LOGFUNC(_Fmt...) ++#define RLM_TRACE_LOGFUNC(_Fmt...) ++#define RLM_LOUD_LOGFUNC(_Fmt...) ++#define RLM_TEMP_LOGFUNC(_Fmt...) ++ ++#define MEM_ERROR_LOGFUNC(_Fmt...) ++#define MEM_WARN_LOGFUNC(_Fmt...) ++#define MEM_INFO_LOGFUNC(_Fmt...) ++#define MEM_STATE_LOGFUNC(_Fmt...) ++#define MEM_EVENT_LOGFUNC(_Fmt...) ++#define MEM_TRACE_LOGFUNC(_Fmt...) ++#define MEM_LOUD_LOGFUNC(_Fmt...) ++#define MEM_TEMP_LOGFUNC(_Fmt...) ++ ++#define CNM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_STATE_LOGFUNC(_Fmt...) ++#define CNM_EVENT_LOGFUNC(_Fmt...) ++#define CNM_TRACE_LOGFUNC(_Fmt...) ++#define CNM_LOUD_LOGFUNC(_Fmt...) ++#define CNM_TEMP_LOGFUNC(_Fmt...) ++ ++#define RSN_ERROR_LOGFUNC(_Fmt...) ++#define RSN_WARN_LOGFUNC(_Fmt...) ++#define RSN_INFO_LOGFUNC(_Fmt...) ++#define RSN_STATE_LOGFUNC(_Fmt...) ++#define RSN_EVENT_LOGFUNC(_Fmt...) ++#define RSN_TRACE_LOGFUNC(_Fmt...) ++#define RSN_LOUD_LOGFUNC(_Fmt...) ++#define RSN_TEMP_LOGFUNC(_Fmt...) ++ ++#define BSS_ERROR_LOGFUNC(_Fmt...) ++#define BSS_WARN_LOGFUNC(_Fmt...) ++#define BSS_INFO_LOGFUNC(_Fmt...) ++#define BSS_STATE_LOGFUNC(_Fmt...) ++#define BSS_EVENT_LOGFUNC(_Fmt...) ++#define BSS_TRACE_LOGFUNC(_Fmt...) ++#define BSS_LOUD_LOGFUNC(_Fmt...) ++#define BSS_TEMP_LOGFUNC(_Fmt...) ++ ++#define SCN_ERROR_LOGFUNC(_Fmt...) ++#define SCN_WARN_LOGFUNC(_Fmt...) ++#define SCN_INFO_LOGFUNC(_Fmt...) ++#define SCN_STATE_LOGFUNC(_Fmt...) ++#define SCN_EVENT_LOGFUNC(_Fmt...) ++#define SCN_TRACE_LOGFUNC(_Fmt...) ++#define SCN_LOUD_LOGFUNC(_Fmt...) ++#define SCN_TEMP_LOGFUNC(_Fmt...) ++ ++#define SAA_ERROR_LOGFUNC(_Fmt...) ++#define SAA_WARN_LOGFUNC(_Fmt...) ++#define SAA_INFO_LOGFUNC(_Fmt...) ++#define SAA_STATE_LOGFUNC(_Fmt...) ++#define SAA_EVENT_LOGFUNC(_Fmt...) ++#define SAA_TRACE_LOGFUNC(_Fmt...) ++#define SAA_LOUD_LOGFUNC(_Fmt...) ++#define SAA_TEMP_LOGFUNC(_Fmt...) ++ ++#define P2P_ERROR_LOGFUNC(_Fmt...) ++#define P2P_WARN_LOGFUNC(_Fmt...) ++#define P2P_INFO_LOGFUNC(_Fmt...) ++#define P2P_STATE_LOGFUNC(_Fmt...) ++#define P2P_EVENT_LOGFUNC(_Fmt...) ++#define P2P_TRACE_LOGFUNC(_Fmt...) ++#define P2P_LOUD_LOGFUNC(_Fmt...) ++#define P2P_TEMP_LOGFUNC(_Fmt...) ++ ++#define QM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_STATE_LOGFUNC(_Fmt...) ++#define QM_EVENT_LOGFUNC(_Fmt...) ++#define QM_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_LOUD_LOGFUNC(_Fmt...) ++#define QM_TEMP_LOGFUNC(_Fmt...) ++ ++#define SEC_ERROR_LOGFUNC(_Fmt...) ++#define SEC_WARN_LOGFUNC(_Fmt...) ++#define SEC_INFO_LOGFUNC(_Fmt...) ++#define SEC_STATE_LOGFUNC(_Fmt...) ++#define SEC_EVENT_LOGFUNC(_Fmt...) ++#define SEC_TRACE_LOGFUNC(_Fmt...) ++#define SEC_LOUD_LOGFUNC(_Fmt...) ++#define SEC_TEMP_LOGFUNC(_Fmt...) ++ ++#define BOW_ERROR_LOGFUNC(_Fmt...) ++#define BOW_WARN_LOGFUNC(_Fmt...) ++#define BOW_INFO_LOGFUNC(_Fmt...) ++#define BOW_STATE_LOGFUNC(_Fmt...) ++#define BOW_EVENT_LOGFUNC(_Fmt...) ++#define BOW_TRACE_LOGFUNC(_Fmt...) ++#define BOW_LOUD_LOGFUNC(_Fmt...) ++#define BOW_TEMP_LOGFUNC(_Fmt...) ++ ++#define HAL_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define HAL_WARN_LOGFUNC(_Fmt...) ++#define HAL_INFO_LOGFUNC(_Fmt...) ++#define HAL_STATE_LOGFUNC(_Fmt...) ++#define HAL_EVENT_LOGFUNC(_Fmt...) ++#define HAL_TRACE_LOGFUNC(_Fmt...) ++#define HAL_LOUD_LOGFUNC(_Fmt...) ++#define HAL_TEMP_LOGFUNC(_Fmt...) ++ ++#define WAPI_ERROR_LOGFUNC(_Fmt...) ++#define WAPI_WARN_LOGFUNC(_Fmt...) ++#define WAPI_INFO_LOGFUNC(_Fmt...) ++#define WAPI_STATE_LOGFUNC(_Fmt...) ++#define WAPI_EVENT_LOGFUNC(_Fmt...) ++#define WAPI_TRACE_LOGFUNC(_Fmt...) ++#define WAPI_LOUD_LOGFUNC(_Fmt...) ++#define WAPI_TEMP_LOGFUNC(_Fmt...) ++ ++#define TDLS_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_STATE_LOGFUNC(_Fmt...) ++#define TDLS_EVENT_LOGFUNC(_Fmt...) ++#define TDLS_TRACE_LOGFUNC(_Fmt...) ++#define TDLS_LOUD_LOGFUNC(_Fmt...) ++#define TDLS_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW1_ERROR_LOGFUNC(_Fmt...) ++#define SW1_WARN_LOGFUNC(_Fmt...) ++#define SW1_INFO_LOGFUNC(_Fmt...) ++#define SW1_STATE_LOGFUNC(_Fmt...) ++#define SW1_EVENT_LOGFUNC(_Fmt...) ++#define SW1_TRACE_LOGFUNC(_Fmt...) ++#define SW1_LOUD_LOGFUNC(_Fmt...) ++#define SW1_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW2_ERROR_LOGFUNC(_Fmt...) ++#define SW2_WARN_LOGFUNC(_Fmt...) ++#define SW2_INFO_LOGFUNC(_Fmt...) ++#define SW2_STATE_LOGFUNC(_Fmt...) ++#define SW2_EVENT_LOGFUNC(_Fmt...) ++#define SW2_TRACE_LOGFUNC(_Fmt...) ++#define SW2_LOUD_LOGFUNC(_Fmt...) ++#define SW2_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW3_ERROR_LOGFUNC(_Fmt...) ++#define SW3_WARN_LOGFUNC(_Fmt...) ++#define SW3_INFO_LOGFUNC(_Fmt...) ++#define SW3_STATE_LOGFUNC(_Fmt...) ++#define SW3_EVENT_LOGFUNC(_Fmt...) ++#define SW3_TRACE_LOGFUNC(_Fmt...) ++#define SW3_LOUD_LOGFUNC(_Fmt...) ++#define SW3_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW4_ERROR_LOGFUNC(_Fmt...) ++#define SW4_WARN_LOGFUNC(_Fmt...) ++#define SW4_INFO_LOGFUNC(_Fmt...) ++#define SW4_STATE_LOGFUNC(_Fmt...) ++#define SW4_EVENT_LOGFUNC(_Fmt...) ++#define SW4_TRACE_LOGFUNC(_Fmt...) ++#define SW4_LOUD_LOGFUNC(_Fmt...) ++#define SW4_TEMP_LOGFUNC(_Fmt...) ++#endif ++ ++#define kalBreakPoint() \ ++do { \ ++ BUG(); \ ++ panic("Oops"); \ ++} while (0) ++ ++#if CFG_ENABLE_AEE_MSG ++#define kalSendAeeException aee_kernel_exception ++#define kalSendAeeWarning aee_kernel_warning ++#define kalSendAeeReminding aee_kernel_reminding ++#else ++#define kalSendAeeException(_module, _desc, ...) ++#define kalSendAeeWarning(_module, _desc, ...) ++#define kalSendAeeReminding(_module, _desc, ...) ++#endif ++ ++#define PRINTF_ARG(...) __VA_ARGS__ ++#define SPRINTF(buf, arg) {buf += sprintf((char *)(buf), PRINTF_ARG arg); } ++ ++#define USEC_TO_SYSTIME(_usec) ((_usec) / USEC_PER_MSEC) ++#define MSEC_TO_SYSTIME(_msec) (_msec) ++ ++#define MSEC_TO_JIFFIES(_msec) msecs_to_jiffies(_msec) ++ ++#define KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE 3000 /* 3s */ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in gl_kal.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags); ++ ++VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags); ++ ++VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr); ++ ++VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); ++ ++PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData); ++ ++VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler); ++ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN OS_SYSTIME rInterval); ++ ++WLAN_STATUS ++kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, ++ /* IN PBOOLEAN pfgIsRetain, */ ++ IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aeCSUM[] ++); ++ ++WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum); ++ ++VOID ++kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen); ++ ++VOID ++kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen); ++ ++#if CFG_TX_FRAGMENT ++BOOLEAN ++kalQueryTxPacketHeader(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvPacket, OUT PUINT_16 pu2EtherTypeLen, OUT PUINT_8 pucEthDestAddr); ++#endif /* CFG_TX_FRAGMENT */ ++ ++VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag); ++ ++VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T eCSUM[] ++); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr); ++ ++VOID ++kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs); ++ ++VOID ++kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum); ++ ++VOID ++kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); ++ ++VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in interface - ehpi/sdio.c */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegRead(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, OUT PUINT_32 pu4Value); ++ ++BOOLEAN kalDevRegWrite(P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, IN UINT_32 u4Value); ++ ++BOOLEAN ++kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_16 u2Port, IN UINT_32 u2Len, OUT PUINT_8 pucBuf, IN UINT_32 u2ValidOutBufSize); ++ ++BOOLEAN ++kalDevPortWrite(P_GLUE_INFO_T prGlueInfo, ++ IN UINT_16 u2Port, IN UINT_32 u2Len, IN PUINT_8 pucBuf, IN UINT_32 u2ValidInBufSize); ++ ++BOOLEAN kalDevWriteWithSdioCmd52(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Addr, IN UINT_8 ucData); ++ ++void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo); ++ ++#if CFG_SUPPORT_EXT_CONFIG ++UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++BOOLEAN ++kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_NATIVE_PACKET prPacket, ++ OUT PUINT_8 pucPriorityParam, ++ OUT PUINT_32 pu4PacketLen, ++ OUT PUINT_8 pucEthDestAddr, ++ OUT PBOOLEAN pfgIs1X, ++ OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, ++ OUT PVOID prGenUse); ++ ++VOID ++kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, ++ IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus); ++ ++WLAN_STATUS ++kalIoctl(IN P_GLUE_INFO_T prGlueInfo, ++ IN PFN_OID_HANDLER_FUNC pfnOidHandler, ++ IN PVOID pvInfoBuf, ++ IN UINT_32 u4InfoBufLen, ++ IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen); ++ ++VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength); ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Card Removal Check */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX */ ++/*----------------------------------------------------------------------------*/ ++VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Media State Indication */ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID handling */ ++/*----------------------------------------------------------------------------*/ ++VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry); ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++/*----------------------------------------------------------------------------*/ ++/* Bluetooth over Wi-Fi handling */ ++/*----------------------------------------------------------------------------*/ ++VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent); ++ ++ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, PARAM_MAC_ADDRESS rPeerAddr); ++ ++ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++/*----------------------------------------------------------------------------*/ ++/* Bluetooth over Wi-Fi Net Device Init/Uninit */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName); ++ ++BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo); ++#endif /* CFG_BOW_SEPARATE_DATA_PATH */ ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Firmware Download Handling */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Security Frame Clearance */ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Management Frame Clearance */ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval); ++ ++BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status); ++ ++UINT_32 kalRandomNumber(VOID); ++ ++VOID kalTimeoutHandler(ULONG arg); ++ ++VOID kalSetEvent(P_GLUE_INFO_T pr); ++ ++/*----------------------------------------------------------------------------*/ ++/* NVRAM/Registry Service */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo); ++ ++P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PUINT_16 pu2Part1CfgOwnVersion, ++ OUT PUINT_16 pu2Part1CfgPeerVersion, ++ OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion); ++ ++BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data); ++ ++BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, IN UINT_16 u2Data); ++ ++/*----------------------------------------------------------------------------*/ ++/* WSC Connection */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* RSSI Updating */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); ++ ++/*----------------------------------------------------------------------------*/ ++/* I/O Buffer Pre-allocation */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitIOBuffer(VOID); ++ ++VOID kalUninitIOBuffer(VOID); ++ ++PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize); ++ ++VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size); ++ ++VOID ++kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); ++ ++BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo); ++ ++ULONG kalIOPhyAddrGet(IN ULONG VirtAddr); ++ ++VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr); ++ ++#if CFG_SUPPORT_802_11W ++/*----------------------------------------------------------------------------*/ ++/* 802.11W */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size); ++ ++/*----------------------------------------------------------------------------*/ ++/* NL80211 */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, IN UINT_32 u4BufLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength); ++ ++/*----------------------------------------------------------------------------*/ ++/* PNO Support */ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int tx_thread(void *data); ++ ++VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo); ++VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb); ++VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo); ++int kalMetRemoveProcfs(void); ++ ++UINT_64 kalGetBootTime(void); ++ ++INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize); ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter); ++#endif ++INT_32 kalHaltLock(UINT_32 waitMs); ++INT_32 kalHaltTryLock(VOID); ++VOID kalHaltUnlock(VOID); ++VOID kalSetHalted(BOOLEAN fgHalt); ++BOOLEAN kalIsHalted(VOID); ++ ++INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo); ++VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++INT32 kalBoostCpu(UINT_32 core_num); ++ ++#endif /* _GL_KAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h +new file mode 100644 +index 000000000000..a4321e7f9a11 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h +@@ -0,0 +1,1270 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_os.h#2 ++*/ ++ ++/*! \file gl_os.h ++ \brief List the external reference to OS for GLUE Layer. ++ ++ In this file we define the data structure - GLUE_INFO_T to store those objects ++ we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the ++ external reference (header file, extern func() ..) to OS for GLUE Layer should ++ also list down here. ++*/ ++ ++/* ++** Log: gl_os.h ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++** ++** 08 20 2012 yuche.tsai ++** [ALPS00339327] [Rose][6575JB][BSP Package][Free Test][KE][WIFI]There is no response when you tap the turn off/on ++** button,wait a minutes, the device will reboot automatically and "KE" will pop up. ++** Fix possible KE when netlink operate mgmt frame register. ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 16 2011 yuche.tsai ++ * NULL ++ * Avoid using work thread. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 29 2011 terry.wu ++ * NULL ++ * Show DRV_NAME by chip id. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * Add query ipv4 and ipv6 address during early suspend and late resume ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align ++ * pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 02 09 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Halt p2p module init and exit until TxThread finished p2p register and unregister. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish ++ * successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * add waitq for poll() and read(). ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * add new KAL api ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * modify tx thread and remove some spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add security frame pending count ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change variable names for multiple physical link to match with coding convention ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * supporting power management ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * pvInformationBuffer and u4InformationBufferLength are no longer in glue ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple ++ * * * * * * * * * * * * * * * * * * * * handler capability ++ * * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other ++ * * * * * * * * * * * * * * * * * * * * purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * * * are done in adapter layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Tag the packet for QoS on Tx path ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)deliver the kalOidComplete status to upper layer ++ * * (2) fix spin lock ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download related data type ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * * * the frequency is used for adhoc connection only ++ * * * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add Bluetooth-over-Wifi frame header check ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\30 2009-10-20 17:38:31 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\29 2009-10-08 10:33:33 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\28 2009-09-28 20:19:26 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\27 2009-08-18 22:57:12 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\26 2009-07-06 21:42:25 GMT mtk01088 ++** fixed the compiling error at linux ++** \main\maintrunk.MT5921\25 2009-07-06 20:51:46 GMT mtk01088 ++** adding the wapi 1x ether type define ++** \main\maintrunk.MT5921\24 2009-06-23 23:19:18 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\23 2009-02-07 15:05:06 GMT mtk01088 ++** add the privacy flag to ingo driver the supplicant selected ap's security ++** \main\maintrunk.MT5921\22 2009-02-05 15:34:09 GMT mtk01088 ++** fixed the compiling error for using bits marco for only one parameter ++** \main\maintrunk.MT5921\21 2009-01-22 13:02:13 GMT mtk01088 ++** data frame is or not 802.1x value share with tid, using the same reserved byte, provide the function to set and get ++** \main\maintrunk.MT5921\20 2008-10-24 12:04:16 GMT mtk01088 ++** move the config.h from precomp.h to here for lint check ++** \main\maintrunk.MT5921\19 2008-09-22 23:19:02 GMT mtk01461 ++** Update driver for code review ++** \main\maintrunk.MT5921\18 2008-09-05 17:25:13 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\17 2008-08-01 13:32:47 GMT mtk01084 ++** Prevent redundent driver assertion in driver logic when BUS is detached ++** \main\maintrunk.MT5921\16 2008-05-30 14:41:43 GMT mtk01461 ++** Remove WMM Assoc Flag in KAL ++** \main\maintrunk.MT5921\15 2008-05-29 14:16:25 GMT mtk01084 ++** remoev un-used variable ++** \main\maintrunk.MT5921\14 2008-05-03 15:17:14 GMT mtk01461 ++** Add Media Status variable in Glue Layer ++** \main\maintrunk.MT5921\13 2008-04-24 11:58:41 GMT mtk01461 ++** change threshold to 256 ++** \main\maintrunk.MT5921\12 2008-03-11 14:51:05 GMT mtk01461 ++** Remove redundant GL_CONN_INFO_T ++** \main\maintrunk.MT5921\11 2008-01-07 15:07:41 GMT mtk01461 ++** Adjust the netif stop threshold to 150 ++** \main\maintrunk.MT5921\10 2007-11-26 19:43:46 GMT mtk01461 ++** Add OS_TIMESTAMP macro ++** ++** \main\maintrunk.MT5921\9 2007-11-07 18:38:38 GMT mtk01461 ++** Move definition ++** \main\maintrunk.MT5921\8 2007-11-02 01:04:00 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** Revision 1.5 2007/07/12 11:04:28 MTK01084 ++** update macro to delay for ms order ++** ++** Revision 1.4 2007/07/05 07:25:34 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_OS_H ++#define _GL_OS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++/*------------------------------------------------------------------------------ ++ * Flags for LINUX(OS) dependent ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_MAX_WLAN_DEVICES 1 /* number of wlan card will coexist */ ++ ++#define CFG_MAX_TXQ_NUM 4 /* number of tx queue for support multi-queue h/w */ ++ ++#define CFG_USE_SPIN_LOCK_BOTTOM_HALF 0 /* 1: Enable use of SPIN LOCK Bottom Half for LINUX ++ 0: Disable - use SPIN LOCK IRQ SAVE instead */ ++ ++#define CFG_TX_PADDING_SMALL_ETH_PACKET 0 /* 1: Enable - Drop ethernet packet if it < 14 bytes. ++ And pad ethernet packet with dummy 0 if it < 60 bytes. ++ 0: Disable */ ++ ++#define CFG_TX_STOP_NETIF_QUEUE_THRESHOLD 256 /* packets */ ++ ++#define CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD 256 /* packets */ ++#define CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD 128 /* packets */ ++ ++#define ETH_P_1X 0x888E ++#define IPTOS_PREC_OFFSET 5 ++#define USER_PRIORITY_DEFAULT 0 ++ ++#define ETH_WPI_1X 0x88B4 ++ ++#define ETH_HLEN 14 ++#define ETH_TYPE_LEN_OFFSET 12 ++#define ETH_P_IP 0x0800 ++#define ETH_P_1X 0x888E ++#define ETH_P_PRE_1X 0x88C7 ++#define ETH_P_ARP 0x0806 ++ ++#define ARP_PRO_REQ 1 ++#define ARP_PRO_RSP 2 ++ ++#define IPVERSION 4 ++#define IP_HEADER_LEN 20 ++ ++#define IP_PRO_ICMP 0x01 ++#define IP_PRO_UDP 0x11 ++#define IP_PRO_TCP 0x06 ++ ++#define UDP_PORT_DHCPS 0x43 ++#define UDP_PORT_DHCPC 0x44 ++#define UDP_PORT_DNS 0x35 ++ ++#define IPVH_VERSION_OFFSET 4 /* For Little-Endian */ ++#define IPVH_VERSION_MASK 0xF0 ++#define IPTOS_PREC_OFFSET 5 ++#define IPTOS_PREC_MASK 0xE0 ++ ++#define SOURCE_PORT_LEN 2 ++/* NOTE(Kevin): Without IP Option Length */ ++#define LOOK_AHEAD_LEN (ETH_HLEN + IP_HEADER_LEN + SOURCE_PORT_LEN) ++ ++/* 802.2 LLC/SNAP */ ++#define ETH_LLC_OFFSET (ETH_HLEN) ++#define ETH_LLC_LEN 3 ++#define ETH_LLC_DSAP_SNAP 0xAA ++#define ETH_LLC_SSAP_SNAP 0xAA ++#define ETH_LLC_CONTROL_UNNUMBERED_INFORMATION 0x03 ++ ++/* Bluetooth SNAP */ ++#define ETH_SNAP_OFFSET (ETH_HLEN + ETH_LLC_LEN) ++#define ETH_SNAP_LEN 5 ++#define ETH_SNAP_BT_SIG_OUI_0 0x00 ++#define ETH_SNAP_BT_SIG_OUI_1 0x19 ++#define ETH_SNAP_BT_SIG_OUI_2 0x58 ++ ++#define BOW_PROTOCOL_ID_SECURITY_FRAME 0x0003 ++ ++#if defined(MT6620) ++#define CHIP_NAME "MT6620" ++#elif defined(MT6628) ++#define CHIP_NAME "MT6582" ++#endif ++ ++#define DRV_NAME "["CHIP_NAME"]: " ++ ++#define CONFIG_ANDROID 1 ++/* Define if target platform is Android. ++ * It should already be defined in Android kernel source ++ */ ++ ++/* for CFG80211 IE buffering mechanism */ ++#define CFG_CFG80211_IE_BUF_LEN (512) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include /* constant of kernel version */ ++ ++#include /* bitops.h */ ++ ++#include /* struct timer_list */ ++#include /* jiffies */ ++#include /* udelay and mdelay macro */ ++ ++#if CONFIG_ANDROID ++#include ++#endif ++ ++#include /* IRQT_FALLING */ ++ ++#include /* struct net_device, struct net_device_stats */ ++#include /* for eth_type_trans() function */ ++#include /* struct iw_statistics */ ++#include ++#include /* struct in_device */ ++ ++#include /* struct iphdr */ ++ ++#include /* for memcpy()/memset() function */ ++#include /* for offsetof() macro */ ++ ++#include /* The proc filesystem constants/structures */ ++ ++#include /* for rtnl_lock() and rtnl_unlock() */ ++#include /* kthread_should_stop(), kthread_run() */ ++#include /* for copy_from_user() */ ++#include /* for firmware download */ ++#include ++ ++#include /* for kfifo interface */ ++#include /* for cdev interface */ ++ ++#include /* for firmware download */ ++ ++#if defined(_HIF_SDIO) ++#include ++#include ++#endif ++ ++#include ++ ++#include ++#include ++ ++#include /* readw and writew */ ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++#include "version.h" ++#include "config.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#endif ++ ++#include ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#include ++#endif ++ ++#include "gl_typedef.h" ++#include "typedef.h" ++#include "queue.h" ++#include "gl_kal.h" ++#include "hif.h" ++#if CFG_CHIP_RESET_SUPPORT ++#include "gl_rst.h" ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "tdls_extr.h" ++#endif ++#include "debug.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++ ++#if CFG_ENABLE_AEE_MSG ++#include ++#endif ++ ++extern BOOLEAN fgIsBusAccessFailed; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define GLUE_FLAG_HALT BIT(0) ++#define GLUE_FLAG_INT BIT(1) ++#define GLUE_FLAG_OID BIT(2) ++#define GLUE_FLAG_TIMEOUT BIT(3) ++#define GLUE_FLAG_TXREQ BIT(4) ++#define GLUE_FLAG_SUB_MOD_INIT BIT(5) ++#define GLUE_FLAG_SUB_MOD_EXIT BIT(6) ++#define GLUE_FLAG_SUB_MOD_MULTICAST BIT(7) ++#define GLUE_FLAG_FRAME_FILTER BIT(8) ++#define GLUE_FLAG_FRAME_FILTER_AIS BIT(9) ++#define GLUE_FLAG_HIF_LOOPBK_AUTO BIT(10) ++#define GLUE_FLAG_HALT_BIT (0) ++#define GLUE_FLAG_INT_BIT (1) ++#define GLUE_FLAG_OID_BIT (2) ++#define GLUE_FLAG_TIMEOUT_BIT (3) ++#define GLUE_FLAG_TXREQ_BIT (4) ++#define GLUE_FLAG_SUB_MOD_INIT_BIT (5) ++#define GLUE_FLAG_SUB_MOD_EXIT_BIT (6) ++#define GLUE_FLAG_SUB_MOD_MULTICAST_BIT (7) ++#define GLUE_FLAG_FRAME_FILTER_BIT (8) ++#define GLUE_FLAG_FRAME_FILTER_AIS_BIT (9) ++#define GLUE_FLAG_HIF_LOOPBK_AUTO_BIT (10) ++ ++#define GLUE_BOW_KFIFO_DEPTH (1024) ++/* #define GLUE_BOW_DEVICE_NAME "MT6620 802.11 AMP" */ ++#define GLUE_BOW_DEVICE_NAME "ampc0" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _GL_WPA_INFO_T { ++ UINT_32 u4WpaVersion; ++ UINT_32 u4KeyMgmt; ++ UINT_32 u4CipherGroup; ++ UINT_32 u4CipherPairwise; ++ UINT_32 u4AuthAlg; ++ BOOLEAN fgPrivacyInvoke; ++#if CFG_SUPPORT_802_11W ++ UINT_32 u4Mfp; ++#endif ++} GL_WPA_INFO_T, *P_GL_WPA_INFO_T; ++ ++typedef enum _ENUM_RSSI_TRIGGER_TYPE { ++ ENUM_RSSI_TRIGGER_NONE, ++ ENUM_RSSI_TRIGGER_GREATER, ++ ENUM_RSSI_TRIGGER_LESS, ++ ENUM_RSSI_TRIGGER_TRIGGERED, ++ ENUM_RSSI_TRIGGER_NUM ++} ENUM_RSSI_TRIGGER_TYPE; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++typedef enum _ENUM_SUB_MODULE_IDX_T { ++ P2P_MODULE = 0, ++ SUB_MODULE_NUM ++} ENUM_SUB_MODULE_IDX_T; ++ ++typedef enum _ENUM_NET_REG_STATE_T { ++ ENUM_NET_REG_STATE_UNREGISTERED, ++ ENUM_NET_REG_STATE_REGISTERING, ++ ENUM_NET_REG_STATE_REGISTERED, ++ ENUM_NET_REG_STATE_UNREGISTERING, ++ ENUM_NET_REG_STATE_NUM ++} ENUM_NET_REG_STATE_T; ++ ++#endif ++ ++typedef struct _GL_IO_REQ_T { ++ QUE_ENTRY_T rQueEntry; ++ /* wait_queue_head_t cmdwait_q; */ ++ BOOLEAN fgRead; ++ BOOLEAN fgWaitResp; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2pOid; ++#endif ++ P_ADAPTER_T prAdapter; ++ PFN_OID_HANDLER_FUNC pfnOidHandler; ++ PVOID pvInfoBuf; ++ UINT_32 u4InfoBufLen; ++ PUINT_32 pu4QryInfoLen; ++ WLAN_STATUS rStatus; ++ UINT_32 u4Flag; ++} GL_IO_REQ_T, *P_GL_IO_REQ_T; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++typedef struct _GL_BOW_INFO { ++ BOOLEAN fgIsRegistered; ++ dev_t u4DeviceNumber; /* dynamic device number */ ++/* struct kfifo *prKfifo; */ /* for buffering indicated events */ ++ struct kfifo rKfifo; /* for buffering indicated events */ ++ spinlock_t rSpinLock; /* spin lock for kfifo */ ++ struct cdev cdev; ++ UINT_32 u4FreqInKHz; /* frequency */ ++ ++ UINT_8 aucRole[CFG_BOW_PHYSICAL_LINK_NUM]; /* 0: Responder, 1: Initiator */ ++ ENUM_BOW_DEVICE_STATE aeState[CFG_BOW_PHYSICAL_LINK_NUM]; ++ PARAM_MAC_ADDRESS arPeerAddr[CFG_BOW_PHYSICAL_LINK_NUM]; ++ ++ wait_queue_head_t outq; ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ BOOLEAN fgIsNetRegistered; ++#endif ++ ++} GL_BOW_INFO, *P_GL_BOW_INFO; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++typedef struct _TDLS_INFO_LINK_T { ++ /* start time when link is built, end time when link is broken */ ++ unsigned long jiffies_start, jiffies_end; ++ ++ /* the peer MAC */ ++ UINT8 aucPeerMac[6]; ++ ++ /* broken reason */ ++ UINT8 ucReasonCode; ++ ++ /* TRUE: torn down is triggerred by us */ ++ UINT8 fgIsFromUs; ++ ++ /* duplicate count; same reason */ ++ UINT8 ucDupCount; ++ ++ /* HT capability */ ++#define TDLS_INFO_LINK_HT_CAP_SUP 0x01 ++ UINT8 ucHtCap; ++#define TDLS_INFO_LINK_HT_BA_SETUP 0x01 ++#define TDLS_INFO_LINK_HT_BA_SETUP_OK 0x02 ++#define TDLS_INFO_LINK_HT_BA_SETUP_DECLINE 0x04 ++#define TDLS_INFO_LINK_HT_BA_PEER 0x10 ++#define TDLS_INFO_LINK_HT_BA_RSP_OK 0x20 ++#define TDLS_INFO_LINK_HT_BA_RSP_DECLINE 0x40 ++ UINT8 ucHtBa[8]; /* TID0 ~ TID7 */ ++} TDLS_INFO_LINK_T; ++ ++typedef struct _TDLS_INFO_T { ++ /* link history */ ++#define TDLS_LINK_HISTORY_MAX 30 ++ TDLS_INFO_LINK_T rLinkHistory[TDLS_LINK_HISTORY_MAX]; ++ UINT32 u4LinkIdx; ++ ++ /* TRUE: support 20/40 bandwidth in TDLS link */ ++ BOOLEAN fgIs2040Sup; ++ ++ /* total TDLS link count */ ++ INT8 cLinkCnt; ++} TDLS_INFO_T; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++/* ++* type definition of pointer to p2p structure ++*/ ++typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; ++ ++struct _GLUE_INFO_T { ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ ++ /* Device Index(index of arWlanDevInfo[]) */ ++ INT_32 i4DevIdx; ++ ++ /* Device statistics */ ++ struct net_device_stats rNetDevStats; ++ ++ /* Wireless statistics struct net_device */ ++ struct iw_statistics rIwStats; ++ ++ /* spinlock to sync power save mechanism */ ++ spinlock_t rSpinLock[SPIN_LOCK_NUM]; ++ ++ /* semaphore for ioctl */ ++ struct semaphore ioctl_sem; ++ ++ UINT_64 u8Cookie; ++ ++ ULONG ulFlag; /* GLUE_FLAG_XXX */ ++ UINT_32 u4PendFlag; ++ /* UINT_32 u4TimeoutFlag; */ ++ UINT_32 u4OidCompleteFlag; ++ UINT_32 u4ReadyFlag; /* check if card is ready */ ++ ++ UINT_32 u4OsMgmtFrameFilter; ++ ++ /* Number of pending frames, also used for debuging if any frame is ++ * missing during the process of unloading Driver. ++ * ++ * NOTE(Kevin): In Linux, we also use this variable as the threshold ++ * for manipulating the netif_stop(wake)_queue() func. ++ */ ++ INT_32 ai4TxPendingFrameNumPerQueue[4][CFG_MAX_TXQ_NUM]; ++ INT_32 i4TxPendingFrameNum; ++ INT_32 i4TxPendingSecurityFrameNum; ++ ++ /* current IO request for kalIoctl */ ++ GL_IO_REQ_T OidEntry; ++ ++ /* registry info */ ++ REG_INFO_T rRegInfo; ++ ++ /* firmware */ ++ struct firmware *prFw; ++ ++ /* Host interface related information */ ++ /* defined in related hif header file */ ++ GL_HIF_INFO_T rHifInfo; ++ ++ /*! \brief wext wpa related information */ ++ GL_WPA_INFO_T rWpaInfo; ++ ++ /* Pointer to ADAPTER_T - main data structure of internal protocol stack */ ++ P_ADAPTER_T prAdapter; ++ ++#ifdef WLAN_INCLUDE_PROC ++ struct proc_dir_entry *pProcRoot; ++#endif /* WLAN_INCLUDE_PROC */ ++ ++ /* Indicated media state */ ++ ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicated; ++ ++ /* Device power state D0~D3 */ ++ PARAM_DEVICE_POWER_STATE ePowerState; ++ ++ struct completion rScanComp; /* indicate scan complete */ ++ struct completion rHaltComp; /* indicate main thread halt complete */ ++ struct completion rPendComp; /* indicate main thread halt complete */ ++#if CFG_ENABLE_WIFI_DIRECT ++ struct completion rSubModComp; /*indicate sub module init or exit complete */ ++#endif ++ WLAN_STATUS rPendStatus; ++ ++ QUE_T rTxQueue; ++ ++ /* OID related */ ++ QUE_T rCmdQueue; ++ /* PVOID pvInformationBuffer; */ ++ /* UINT_32 u4InformationBufferLength; */ ++ /* PVOID pvOidEntry; */ ++ /* PUINT_8 pucIOReqBuff; */ ++ /* QUE_T rIOReqQueue; */ ++ /* QUE_T rFreeIOReqQueue; */ ++ ++ wait_queue_head_t waitq; ++ struct task_struct *main_thread; ++ ++ struct timer_list tickfn; ++ ++#if CFG_SUPPORT_EXT_CONFIG ++ UINT_16 au2ExtCfg[256]; /* NVRAM data buffer */ ++ UINT_32 u4ExtCfgLength; /* 0 means data is NOT valid */ ++#endif ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ /* Should be large than the PARAM_WAPI_ASSOC_INFO_T */ ++ UINT_8 aucWapiAssocInfoIEs[42]; ++ UINT_16 u2WapiAssocInfoIESz; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ GL_BOW_INFO rBowInfo; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_GL_P2P_INFO_T prP2PInfo; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ /* Wireless statistics struct net_device */ ++ struct iw_statistics rP2pIwStats; ++#endif ++#endif ++ BOOLEAN fgWpsActive; ++ UINT_8 aucWSCIE[500]; /*for probe req */ ++ UINT_16 u2WSCIELen; ++ UINT_8 aucWSCAssocInfoIE[200]; /*for Assoc req */ ++ UINT_16 u2WSCAssocInfoIELen; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ UINT_8 aucHS20AssocInfoIE[200]; /*for Assoc req */ ++ UINT_16 u2HS20AssocInfoIELen; ++ UINT_8 ucHotspotConfig; ++ BOOLEAN fgConnectHS20AP; ++#endif ++ ++ /* NVRAM availability */ ++ BOOLEAN fgNvramAvailable; ++ ++ BOOLEAN fgMcrAccessAllowed; ++ ++ /* MAC Address Overridden by IOCTL */ ++ BOOLEAN fgIsMacAddrOverride; ++ PARAM_MAC_ADDRESS rMacAddrOverride; ++ ++ SET_TXPWR_CTRL_T rTxPwr; ++ ++ /* for cfg80211 scan done indication */ ++ struct cfg80211_scan_request *prScanRequest; ++ ++ /* for cfg80211 scheduled scan */ ++ struct cfg80211_sched_scan_request *prSchedScanRequest; ++ ++ /* to indicate registered or not */ ++ BOOLEAN fgIsRegistered; ++ ++ /* for cfg80211 connected indication */ ++ UINT_32 u4RspIeLength; ++ UINT_8 aucRspIe[CFG_CFG80211_IE_BUF_LEN]; ++ ++ UINT_32 u4ReqIeLength; ++ UINT_8 aucReqIe[CFG_CFG80211_IE_BUF_LEN]; ++ ++ KAL_WAKE_LOCK_T rAhbIsrWakeLock; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ BOOLEAN fgIsDad; ++ UINT_8 aucDADipv4[4]; ++ BOOLEAN fgIs6Dad; ++ UINT_8 aucDADipv6[16]; ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ UINT_8 u8MetProfEnable; ++ INT_16 u16MetUdpPort; ++#endif ++ BOOLEAN fgPoorlinkValid; ++ UINT_64 u8Statistic[2]; ++ UINT_64 u8TotalFailCnt; ++ UINT_32 u4LinkspeedThreshold; ++ INT_32 i4RssiThreshold; ++ INT_32 i4RssiCache; ++ UINT_32 u4LinkSpeedCache; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TDLS_INFO_T rTdlsLink; ++ ++ UINT8 aucTdlsHtPeerMac[6]; ++ IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ ++ ++ /* ++ [0~7]: jiffies ++ [8~13]: Peer MAC ++ [14]: Reason Code ++ [15]: From us or peer ++ [16]: Duplicate Count ++ */ ++/* UINT8 aucTdlsDisconHistory[TDLS_DISCON_HISTORY_MAX][20]; */ ++/* UINT32 u4TdlsDisconIdx; */ ++#endif /* CFG_SUPPORT_TDLS */ ++ UINT_32 IsrCnt; ++ UINT_32 IsrPassCnt; ++ UINT_32 TaskIsrCnt; ++ ++ UINT_32 IsrPreCnt; ++ UINT_32 IsrPrePassCnt; ++ UINT_32 TaskPreIsrCnt; ++ ++ UINT_32 IsrAbnormalCnt; ++ UINT_32 IsrSoftWareCnt; ++ UINT_32 IsrTxCnt; ++ UINT_32 IsrRxCnt; ++ UINT_64 u8SkbToDriver; ++ UINT_64 u8SkbFreed; ++}; ++ ++typedef irqreturn_t(*PFN_WLANISR) (int irq, void *dev_id, struct pt_regs *regs); ++ ++typedef void (*PFN_LINUX_TIMER_FUNC) (unsigned long); ++ ++/* generic sub module init/exit handler ++* now, we only have one sub module, p2p ++*/ ++#if CFG_ENABLE_WIFI_DIRECT ++typedef BOOLEAN(*SUB_MODULE_INIT) (P_GLUE_INFO_T prGlueInfo); ++typedef BOOLEAN(*SUB_MODULE_EXIT) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef struct _SUB_MODULE_HANDLER { ++ SUB_MODULE_INIT subModInit; ++ SUB_MODULE_EXIT subModExit; ++ BOOLEAN fgIsInited; ++} SUB_MODULE_HANDLER, *P_SUB_MODULE_HANDLER; ++ ++#endif ++ ++ ++#ifdef CONFIG_NL80211_TESTMODE ++enum TestModeCmdType { ++ /* old test mode command id, compatible with exist testmode command */ ++ TESTMODE_CMD_ID_SW_CMD = 1, ++ TESTMODE_CMD_ID_WAPI = 2, ++ TESTMODE_CMD_ID_HS20 = 3, ++ TESTMODE_CMD_ID_POORLINK = 4, ++ TESTMODE_CMD_ID_STATISTICS = 0x10, ++ TESTMODE_CMD_ID_LINK_DETECT = 0x20, ++ /* old test mode command id, compatible with exist testmode command */ ++ ++ /* all new added test mode command should great than TESTMODE_CMD_ID_NEW_BEGIN */ ++ TESTMODE_CMD_ID_NEW_BEGIN = 100, ++ TESTMODE_CMD_ID_SUSPEND = 101, ++}; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++enum Hs20CmdType { ++ HS20_CMD_ID_SET_BSSID_POOL = 0, ++ NUM_OF_HS20_CMD_ID ++}; ++#endif ++ ++typedef struct _NL80211_DRIVER_TEST_MODE_PARAMS { ++ UINT_32 index; ++ UINT_32 buflen; ++} NL80211_DRIVER_TEST_MODE_PARAMS, *P_NL80211_DRIVER_TEST_MODE_PARAMS; ++ ++/*SW CMD */ ++typedef struct _NL80211_DRIVER_SW_CMD_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 set; ++ UINT_32 adr; ++ UINT_32 data; ++} NL80211_DRIVER_SW_CMD_PARAMS, *P_NL80211_DRIVER_SW_CMD_PARAMS; ++ ++typedef struct _NL80211_DRIVER_SUSPEND_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 suspend; ++} NL80211_DRIVER_SUSPEND_PARAMS, *P_NL80211_DRIVER_SUSPEND_PARAMS; ++struct iw_encode_exts { ++ __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ ++ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 addr[MAC_ADDR_LEN]; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast ++ * (group) keys or unicast address for ++ * individual keys */ ++ __u16 alg; /*!< IW_ENCODE_ALG_* */ ++ __u16 key_len; ++ __u8 key[32]; ++}; ++ ++/*SET KEY EXT */ ++typedef struct _NL80211_DRIVER_SET_KEY_EXTS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 key_index; ++ UINT_8 key_len; ++ struct iw_encode_exts ext; ++} NL80211_DRIVER_SET_KEY_EXTS, *P_NL80211_DRIVER_SET_KEY_EXTS; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ ++struct param_hs20_set_bssid_pool { ++ u8 fgBssidPoolIsEnable; ++ u8 ucNumBssidPool; ++ u8 arBssidPool[8][ETH_ALEN]; ++}; ++ ++struct wpa_driver_hs20_data_s { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ enum Hs20CmdType CmdType; ++ struct param_hs20_set_bssid_pool hs20_set_bssid_pool; ++}; ++ ++#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Macros of SPIN LOCK operations for using in Glue Layer */ ++/*----------------------------------------------------------------------------*/ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++#define GLUE_SPIN_LOCK_DECLARATION() ++#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_lock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ ++ } ++#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_unlock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ ++ } ++#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ ++ spin_lock_bh(prLock) ++#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ ++ spin_unlock_bh(prLock) ++ ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++#define GLUE_SPIN_LOCK_DECLARATION() unsigned long __u4Flags = 0 ++#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_lock_irqsave(&(prGlueInfo)->rSpinLock[rLockCategory], __u4Flags); \ ++ } ++#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_unlock_irqrestore(&(prGlueInfo->rSpinLock[rLockCategory]), __u4Flags); \ ++ } ++#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ ++ spin_lock_irqsave(prLock, __u4Flags) ++#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ ++ spin_unlock_irqrestore(prLock, __u4Flags) ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for accessing Reserved Fields of native packet */ ++/*----------------------------------------------------------------------------*/ ++#define GLUE_CB_OFFSET 4 /* For 64-bit platform, avoiding that the cb ++ isoverwrited by "(prQueueEntry)->prNext = ++ (P_QUE_ENTRY_T)NULL;" in QUEUE_INSERT_TAIL */ ++#define GLUE_GET_PKT_QUEUE_ENTRY(_p) \ ++ (&(((struct sk_buff *)(_p))->cb[0])) ++ ++#define GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) \ ++ ((P_NATIVE_PACKET) ((ULONG)_prQueueEntry - offsetof(struct sk_buff, cb[0]))) ++ ++#define GLUE_SET_PKT_FLAG_802_11(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(7)) ++ ++#define GLUE_SET_PKT_FLAG_1X(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(6)) ++ ++#define GLUE_SET_PKT_FLAG_PAL(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(5)) ++ ++#define GLUE_SET_PKT_FLAG_P2P(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(4)) ++ ++#define GLUE_SET_PKT_TID(_p, _tid) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= (((UINT_8)((_tid) & (BITS(0, 3)))))) ++ ++#define GLUE_SET_PKT_FRAME_LEN(_p, _u2PayloadLen) \ ++ (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6])) = (UINT_16)(_u2PayloadLen)) ++ ++#define GLUE_GET_PKT_FRAME_LEN(_p) \ ++ (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6]))) ++ ++#define GLUE_GET_PKT_IS_802_11(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(7))) ++ ++#define GLUE_GET_PKT_IS_1X(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(6))) ++ ++#define GLUE_GET_PKT_TID(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BITS(0, 3))) ++ ++#define GLUE_GET_PKT_IS_PAL(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(5))) ++ ++#define GLUE_GET_PKT_IS_P2P(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(4))) ++ ++#define GLUE_SET_PKT_HEADER_LEN(_p, _ucMacHeaderLen) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5])) = (UINT_8)(_ucMacHeaderLen)) ++ ++#define GLUE_GET_PKT_HEADER_LEN(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5]))) ++ ++#define GLUE_SET_PKT_ARRIVAL_TIME(_p, _rSysTime) \ ++ (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8])) = (OS_SYSTIME)(_rSysTime)) ++ ++#define GLUE_GET_PKT_ARRIVAL_TIME(_p) \ ++ (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8]))) ++ ++#define GLUE_SET_PKT_XTIME(_p, _rSysTime) \ ++ (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16])) = (UINT_64)(_rSysTime)) ++ ++#define GLUE_GET_PKT_XTIME(_p) \ ++ (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16]))) ++ ++/* Check validity of prDev, private data, and pointers */ ++#define GLUE_CHK_DEV(prDev) \ ++ ((prDev && *((P_GLUE_INFO_T *) netdev_priv(prDev))) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR2(prDev, pr2) \ ++ ((GLUE_CHK_DEV(prDev) && pr2) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR3(prDev, pr2, pr3) \ ++ ((GLUE_CHK_PR2(prDev, pr2) && pr3) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR4(prDev, pr2, pr3, pr4) \ ++ ((GLUE_CHK_PR3(prDev, pr2, pr3) && pr4) ? TRUE : FALSE) ++ ++#define GLUE_SET_EVENT(pr) \ ++ kalSetEvent(pr) ++ ++#define GLUE_INC_REF_CNT(_refCount) atomic_inc((atomic_t *)&(_refCount)) ++#define GLUE_DEC_REF_CNT(_refCount) atomic_dec((atomic_t *)&(_refCount)) ++ ++#define DbgPrint(...) ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#ifdef WLAN_INCLUDE_PROC ++INT_32 procRemoveProcfs(VOID); ++ ++INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo); ++INT_32 procInitFs(VOID); ++INT_32 procUninitProcFs(VOID); ++ ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++BOOLEAN glRegisterAmpc(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN glUnregisterAmpc(P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo); ++ ++VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx); ++ ++BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr); ++ ++BOOLEAN wlanIsLaunched(VOID); ++ ++VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo); ++ ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_OS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h +new file mode 100644 +index 000000000000..a27294e33500 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h +@@ -0,0 +1,743 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_ioctl.h#9 ++*/ ++ ++/*! \file gl_p2p_ioctl.h ++ \brief This file is for custom ioctls for Wi-Fi Direct only ++*/ ++ ++/* ++** Log: gl_p2p_ioctl.h ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 03 25 2011 wh.su ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * . ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 16 2011 chinglan.wang ++ * NULL ++ * Add the group id information in the invitation indication. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 05 04 2011 chinglan.wang ++ * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver ++ * . ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000095] [MT6620 Wi-Fi] [FW] Refine the P2P GO send broadcast protected code ++ * add the set power and get power function sample. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 01 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * fixed the ioctl sumcmd to meet the p2p_supplicant setting. ++ * ++ * 02 23 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int define for p2p parameter. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int from supplicant, and can used to set the p2p parameters ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * adjust the set wsc ie structure. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() ++ * ++ * 12 07 2010 cp.wu ++ * [WCXRP00000237] [MT6620 Wi-Fi][Wi-Fi Direct][Driver] Add interface for supporting service discovery ++ * define a pair of i/o control for multiplexing layer ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 10 2010 george.huang ++ * NULL ++ * update iwpriv LP related ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add netdev_ops(NDO) for linux kernel 2.6.31 or greater ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Refine a function parameter name. ++ * ++ * 08 19 2010 cp.wu ++ * NULL ++ * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add wext handlers to link P2P set PS profile/ network address function (TBD) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * follow-up with ioctl interface update for Wi-Fi Direct application ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement wireless extension ioctls in iw_handler form. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++*/ ++ ++#ifndef _GL_P2P_IOCTL_H ++#define _GL_P2P_IOCTL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#endif ++ ++#include "wlan_oid.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Device private ioctl calls */ ++/* #define SIOCDEVPRIVATE 0x89F0*/ ++#define IOC_GET_PRIVATE_IOCTL_CMD (SIOCDEVPRIVATE+1) ++ ++/* (WirelessExtension) Private I/O Controls */ ++#define IOC_P2P_CFG_DEVICE (SIOCIWFIRSTPRIV+0) ++#define IOC_P2P_PROVISION_COMPLETE (SIOCIWFIRSTPRIV+2) ++#define IOC_P2P_START_STOP_DISCOVERY (SIOCIWFIRSTPRIV+4) ++#define IOC_P2P_DISCOVERY_RESULTS (SIOCIWFIRSTPRIV+5) ++#define IOC_P2P_WSC_BEACON_PROBE_RSP_IE (SIOCIWFIRSTPRIV+6) ++#define IOC_P2P_GO_WSC_IE IOC_P2P_WSC_BEACON_PROBE_RSP_IE ++#define IOC_P2P_CONNECT_DISCONNECT (SIOCIWFIRSTPRIV+8) ++#define IOC_P2P_PASSWORD_READY (SIOCIWFIRSTPRIV+10) ++/* #define IOC_P2P_SET_PWR_MGMT_PARAM (SIOCIWFIRSTPRIV+12) */ ++#define IOC_P2P_SET_INT (SIOCIWFIRSTPRIV+12) ++#define IOC_P2P_GET_STRUCT (SIOCIWFIRSTPRIV+13) ++#define IOC_P2P_SET_STRUCT (SIOCIWFIRSTPRIV+14) ++#define IOC_P2P_GET_REQ_DEVICE_INFO (SIOCIWFIRSTPRIV+15) ++ ++#define PRIV_CMD_INT_P2P_SET 0 ++ ++/* IOC_P2P_PROVISION_COMPLETE (iw_point . flags) */ ++#define P2P_PROVISIONING_SUCCESS 0 ++#define P2P_PROVISIONING_FAIL 1 ++ ++/* IOC_P2P_START_STOP_DISCOVERY (iw_point . flags) */ ++#define P2P_STOP_DISCOVERY 0 ++#define P2P_START_DISCOVERY 1 ++ ++/* IOC_P2P_CONNECT_DISCONNECT (iw_point . flags) */ ++#define P2P_CONNECT 0 ++#define P2P_DISCONNECT 1 ++ ++/* IOC_P2P_START_STOP_DISCOVERY (scan_type) */ ++#define P2P_SCAN_FULL_AND_FIND 0 ++#define P2P_SCAN_FULL 1 ++#define P2P_SCAN_SEARCH_AND_LISTEN 2 ++#define P2P_LISTEN 3 ++ ++/* IOC_P2P_GET_STRUCT/IOC_P2P_SET_STRUCT */ ++#define P2P_SEND_SD_RESPONSE 0 ++#define P2P_GET_SD_REQUEST 1 ++#define P2P_SEND_SD_REQUEST 2 ++#define P2P_GET_SD_RESPONSE 3 ++#define P2P_TERMINATE_SD_PHASE 4 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Wireless Extension: Private I/O Control */ ++/*----------------------------------------------------------------------------*/ ++typedef struct iw_p2p_cfg_device_type { ++ void __user *ssid; ++ UINT_8 ssid_len; ++ UINT_8 pri_device_type[8]; ++ UINT_8 snd_device_type[8]; ++ void __user *device_name; ++ UINT_8 device_name_len; ++ UINT_8 intend; ++ UINT_8 persistence; ++ UINT_8 sec_mode; ++ UINT_8 ch; ++ UINT_8 ch_width; /* 0: 20 Mhz 1:20/40 Mhz auto */ ++ UINT_8 max_scb; ++} IW_P2P_CFG_DEVICE_TYPE, *P_IW_P2P_CFG_DEVICE_TYPE; ++ ++typedef struct iw_p2p_hostapd_param { ++ UINT_8 cmd; ++ UINT_8 rsv[3]; ++ UINT_8 sta_addr[6]; ++ void __user *data; ++ UINT_16 len; ++} IW_P2P_HOSTAPD_PARAM, *P_IW_P2P_HOSTAPD_PARAM; ++ ++typedef struct iw_p2p_req_device_type { ++ UINT_8 scan_type; /* 0: Full scan + Find ++ * 1: Full scan ++ * 2: Scan (Search +Listen) ++ * 3: Listen ++ * other : reserved ++ */ ++ UINT_8 pri_device_type[8]; ++ void __user *probe_req_ie; ++ UINT_16 probe_req_len; ++ void __user *probe_rsp_ie; ++ UINT_16 probe_rsp_len; ++} IW_P2P_REQ_DEVICE_TYPE, *P_IW_P2P_REQ_DEVICE_TYPE; ++ ++typedef struct iw_p2p_connect_device { ++ UINT_8 sta_addr[6]; ++ UINT_8 p2pRole; /* 0: P2P Device, 1:GC, 2: GO */ ++ UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ ++ UINT_8 authPeer; /* 1: auth peer invitation request */ ++ UINT_8 intend_config_method; /* Request Peer Device used config method */ ++} IW_P2P_CONNECT_DEVICE, *P_IW_P2P_CONNECT_DEVICE; ++ ++typedef struct iw_p2p_password_ready { ++ UINT_8 active_config_method; ++ void __user *probe_req_ie; ++ UINT_16 probe_req_len; ++ void __user *probe_rsp_ie; ++ UINT_16 probe_rsp_len; ++} IW_P2P_PASSWORD_READY, *P_IW_P2P_PASSWORD_READY; ++ ++typedef struct iw_p2p_device_req { ++ UINT_8 name[33]; ++ UINT_32 name_len; ++ UINT_8 device_addr[6]; ++ UINT_8 device_type; ++ INT_32 config_method; ++ INT_32 active_config_method; ++} IW_P2P_DEVICE_REQ, *P_IW_P2P_DEVICE_REQ; ++ ++typedef struct iw_p2p_transport_struct { ++ UINT_32 u4CmdId; ++ UINT_32 inBufferLength; ++ UINT_32 outBufferLength; ++ UINT_8 aucBuffer[16]; ++} IW_P2P_TRANSPORT_STRUCT, *P_IW_P2P_TRANSPORT_STRUCT; ++ ++/* For Invitation */ ++typedef struct iw_p2p_ioctl_invitation_struct { ++ UINT_8 aucDeviceID[6]; ++ UINT_8 aucGroupID[6]; /* BSSID */ ++ UINT_8 aucSsid[32]; ++ UINT_32 u4SsidLen; ++ UINT_8 ucReinvoke; ++} IW_P2P_IOCTL_INVITATION_STRUCT, *P_IW_P2P_IOCTL_INVITATION_STRUCT; ++ ++typedef struct iw_p2p_ioctl_abort_invitation { ++ UINT_8 dev_addr[6]; ++} IW_P2P_IOCTL_ABORT_INVITATION, *P_IW_P2P_IOCTL_ABORT_INVITATION; ++ ++typedef struct iw_p2p_ioctl_invitation_indicate { ++ UINT_8 dev_addr[6]; ++ UINT_8 group_bssid[6]; ++ INT_32 config_method; /* peer device supported config method */ ++ UINT_8 dev_name[32]; /* for reinvoke */ ++ UINT_32 name_len; ++ UINT_8 operating_channel; /* for re-invoke, target operating channel */ ++ UINT_8 invitation_type; /* invitation or re-invoke */ ++} IW_P2P_IOCTL_INVITATION_INDICATE, *P_IW_P2P_IOCTL_INVITATION_INDICATE; ++ ++typedef struct iw_p2p_ioctl_invitation_status { ++ UINT_32 status_code; ++} IW_P2P_IOCTL_INVITATION_STATUS, *P_IW_P2P_IOCTL_INVITATION_STATUS; ++ ++/* For Formation */ ++typedef struct iw_p2p_ioctl_start_formation { ++ UINT_8 dev_addr[6]; /* bssid */ ++ UINT_8 role; /* 0: P2P Device, 1:GC, 2: GO */ ++ UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ ++ UINT_8 auth; /* 1: auth peer invitation request */ ++ UINT_8 config_method; /* Request Peer Device used config method */ ++} IW_P2P_IOCTL_START_FORMATION, *P_IW_P2P_IOCTL_START_FORMATION; ++ ++/* SET_STRUCT / GET_STRUCT */ ++typedef enum _ENUM_P2P_CMD_ID_T { ++ P2P_CMD_ID_SEND_SD_RESPONSE = 0, /* 0x00 (Set) */ ++ P2P_CMD_ID_GET_SD_REQUEST, /* 0x01 (Get) */ ++ P2P_CMD_ID_SEND_SD_REQUEST, /* 0x02 (Set) */ ++ P2P_CMD_ID_GET_SD_RESPONSE, /* 0x03 (Get) */ ++ P2P_CMD_ID_TERMINATE_SD_PHASE, /* 0x04 (Set) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ P2P_CMD_ID_SEC_CHECK, /* 0x05(Set) */ ++#endif ++ P2P_CMD_ID_INVITATION, /* 0x06 (Set) */ ++ P2P_CMD_ID_INVITATION_INDICATE, /* 0x07 (Get) */ ++ P2P_CMD_ID_INVITATION_STATUS, /* 0x08 (Get) */ ++ P2P_CMD_ID_INVITATION_ABORT, /* 0x09 (Set) */ ++ P2P_CMD_ID_START_FORMATION, /* 0x0A (Set) */ ++ P2P_CMD_ID_P2P_VERSION, /* 0x0B (Set/Get) */ ++ P2P_CMD_ID_GET_CH_LIST = 12, /* 0x0C (Get) */ ++ P2P_CMD_ID_GET_OP_CH = 14 /* 0x0E (Get) */ ++} ENUM_P2P_CMD_ID_T, *P_ENUM_P2P_CMD_ID_T; ++ ++/* Service Discovery */ ++typedef struct iw_p2p_cmd_send_sd_response { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucSeqNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_SEND_SD_RESPONSE, *P_IW_P2P_CMD_SEND_SD_RESPONSE; ++ ++typedef struct iw_p2p_cmd_get_sd_request { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_GET_SD_REQUEST, *P_IW_P2P_CMD_GET_SD_REQUEST; ++ ++typedef struct iw_p2p_cmd_send_service_discovery_request { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucSeqNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_SEND_SD_REQUEST, *P_IW_P2P_CMD_SEND_SD_REQUEST; ++ ++typedef struct iw_p2p_cmd_get_sd_response { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_GET_SD_RESPONSE, *P_IW_P2P_CMD_GET_SD_RESPONSE; ++ ++typedef struct iw_p2p_cmd_terminate_sd_phase { ++ PARAM_MAC_ADDRESS rPeerAddr; ++} IW_P2P_CMD_TERMINATE_SD_PHASE, *P_IW_P2P_CMD_TERMINATE_SD_PHASE; ++ ++typedef struct iw_p2p_version { ++ UINT_32 u4Version; ++} IW_P2P_VERSION, *P_IW_P2P_VERSION; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++extern struct ieee80211_supported_band mtk_band_2ghz; ++extern struct ieee80211_supported_band mtk_band_5ghz; ++extern UINT_32 mtk_cipher_suites[5]; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++int mtk_p2p_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, ++ enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); ++ ++int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); ++ ++int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++); ++ ++int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); ++ ++int ++mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, ++ struct net_device *netdev, u8 key_index, bool unicast, bool multicast); ++ ++int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_info *sinfo); ++ ++int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); ++ ++int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); ++ ++int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); ++ ++int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); ++ ++int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev); ++ ++int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); ++ ++int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params); ++ ++int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, unsigned int duration, u64 *cookie); ++ ++int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); ++ ++int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm); ++ ++int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); ++ ++int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req); ++ ++int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req); ++ ++int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings); ++ ++int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); ++ ++int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie); ++ ++int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev); ++ ++int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params); ++//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac); ++ ++int mtk_p2p_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef); ++ ++void mtk_p2p_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg); ++ ++int ++mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, ++ IN struct net_device *dev, ++ IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask); ++ ++#ifdef CONFIG_NL80211_TESTMODE ++int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); ++int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++ ++#if CFG_SUPPORT_WFD ++int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#else ++#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" ++#endif ++ ++#endif ++ ++/* I/O control handlers */ ++ ++int ++mtk_p2p_wext_get_priv(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_reconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_auth(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_key(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_powermode(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_powermode(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* Private Wireless I/O Controls takes use of iw_handler */ ++int ++mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_discovery_results(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_password_ready(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_invitation_status(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_network_address(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_int(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* Private Wireless I/O Controls for IOC_SET_STRUCT/IOC_GET_STRUCT */ ++int ++mtk_p2p_wext_set_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* IOC_SET_STRUCT/IOC_GET_STRUCT: Service Discovery */ ++int ++mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++int ++mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++#endif ++ ++int ++mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++void mtk_p2p_wext_set_Multicastlist(IN P_GLUE_INFO_T prGlueInfo); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++int ++mtk_p2p_wext_get_rssi(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev); ++ ++#endif ++ ++int ++mtk_p2p_wext_set_txpow(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_P2P_IOCTL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h +new file mode 100644 +index 000000000000..bf9d8871ef48 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h +@@ -0,0 +1,243 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_kal.h#2 ++*/ ++ ++/*! \file gl_p2p_kal.h ++ \brief Declaration of KAL functions for Wi-Fi Direct support ++ - kal*() which is provided by GLUE Layer. ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/* ++** Log: gl_p2p_kal.h ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 15 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Add group BSSID in invitation request indication. ++ * The BSSID is used for APP to decide the configure method. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 03 19 2011 terry.wu ++ * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver ++ * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++*/ ++ ++#ifndef _GL_P2P_KAL_H ++#define _GL_P2P_KAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "config.h" ++#include "gl_typedef.h" ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_p2p.h" ++#include "gl_kal.h" ++#include "gl_wext_priv.h" ++#include "nic/p2p.h" ++ ++#if DBG ++extern int allocatedMemSize; ++#endif ++ ++extern BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++extern BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type); ++struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo); ++ ++/* Service Discovery */ ++VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); ++ ++void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); ++ ++VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Wi-Fi Direct handling */ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole); ++ ++VOID ++kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole); ++ ++VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher); ++ ++BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode); ++ ++UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType); ++ ++VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer); ++ ++VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength); ++ ++BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, ++ IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ ++ IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod); ++ ++VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus); ++ ++VOID ++kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_DEVICE_DESC_T prP2pDevDesc, ++ IN PUINT_8 pucSsid, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid); ++ ++struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID ++kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8SeqNum, ++ IN UINT_32 u4ChannelNum, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration); ++ ++VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort); ++ ++VOID ++kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, ++ IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength); ++ ++VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); ++ ++VOID ++kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); ++ ++VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID ++kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, ++ IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, ++ IN WLAN_STATUS eStatus); ++ ++VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew); ++ ++INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock); ++ ++BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid); ++ ++VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient); ++ ++BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient); ++ ++#endif /* _GL_P2P_KAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h +new file mode 100644 +index 000000000000..e5026e7e6eec +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h +@@ -0,0 +1,242 @@ ++/* ++** Id: ++//Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/os/linux/include/gl_p2p_os.h#28 ++*/ ++ ++/*! \file gl_p2p_os.h ++ \brief List the external reference to OS for p2p GLUE Layer. ++ ++ In this file we define the data structure - GLUE_INFO_T to store those objects ++ we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the ++ external reference (header file, extern func() ..) to OS for GLUE Layer should ++ also list down here. ++*/ ++ ++#ifndef _GL_P2P_OS_H ++#define _GL_P2P_OS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#endif ++ ++#include "wlan_oid.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++struct _GL_P2P_INFO_T { ++ ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ /* cfg80211 */ ++ struct wireless_dev *prWdev; ++ ++ struct cfg80211_scan_request *prScanRequest; ++ ++ UINT_64 u8Cookie; ++ ++ /* Generation for station list update. */ ++ INT_32 i4Generation; ++ ++ UINT_32 u4OsMgmtFrameFilter; ++ ++#endif ++ ++ /* Device statistics */ ++ struct net_device_stats rNetDevStats; ++ ++ /* glue layer variables */ ++ UINT_32 u4FreqInKHz; /* frequency */ ++ UINT_8 ucRole; /* 0: P2P Device, 1: Group Client, 2: Group Owner */ ++ UINT_8 ucIntent; /* range: 0-15 */ ++ UINT_8 ucScanMode; /* 0: Search & Listen, 1: Scan without probe response */ ++ ++ ENUM_PARAM_MEDIA_STATE_T eState; ++ UINT_32 u4PacketFilter; ++ PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR]; ++ ++ /* connection-requested peer information */ ++ UINT_8 aucConnReqDevName[32]; ++ INT_32 u4ConnReqNameLength; ++ PARAM_MAC_ADDRESS rConnReqPeerAddr; ++ PARAM_MAC_ADDRESS rConnReqGroupAddr; /* For invitation group. */ ++ UINT_8 ucConnReqDevType; ++ INT_32 i4ConnReqConfigMethod; ++ INT_32 i4ConnReqActiveConfigMethod; ++ ++ UINT_32 u4CipherPairwise; ++ UINT_8 ucWSCRunning; ++ ++ UINT_8 aucWSCIE[3][400]; /* 0 for beacon, 1 for probe req, 2 for probe response */ ++ UINT_16 u2WSCIELen[3]; ++ ++#if CFG_SUPPORT_WFD ++ UINT_8 aucVenderIE[1024]; /* Save the other IE for prove resp */ ++ UINT_16 u2VenderIELen; ++#endif ++ ++ UINT_8 ucOperatingChnl; ++ UINT_8 ucInvitationType; ++ ++ UINT_32 u4InvStatus; ++ ++ /* For SET_STRUCT/GET_STRUCT */ ++ UINT_8 aucOidBuf[4096]; ++ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ UINT_8 aucSecCheck[256]; ++ UINT_8 aucSecCheckRsp[256]; ++#endif ++ ++ /* Hotspot Client Management */ ++ PARAM_MAC_ADDRESS aucblackMACList[8]; ++ UINT_8 ucMaxClients; ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ UINT_32 u4PsLevel; ++#endif ++}; ++ ++#ifdef CONFIG_NL80211_TESTMODE ++typedef struct _NL80211_DRIVER_TEST_PRE_PARAMS { ++ UINT_16 idx_mode; ++ UINT_16 idx; ++ UINT_32 value; ++} NL80211_DRIVER_TEST_PRE_PARAMS, *P_NL80211_DRIVER_TEST_PRE_PARAMS; ++ ++typedef struct _NL80211_DRIVER_TEST_PARAMS { ++ UINT_32 index; ++ UINT_32 buflen; ++} NL80211_DRIVER_TEST_PARAMS, *P_NL80211_DRIVER_TEST_PARAMS; ++ ++/* P2P Sigma*/ ++typedef struct _NL80211_DRIVER_P2P_SIGMA_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_32 idx; ++ UINT_32 value; ++} NL80211_DRIVER_P2P_SIGMA_PARAMS, *P_NL80211_DRIVER_P2P_SIGMA_PARAMS; ++ ++/* Hotspot Client Management */ ++typedef struct _NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_8 ucblocked; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++} NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS, *P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS; ++ ++#if CFG_SUPPORT_WFD ++typedef struct _NL80211_DRIVER_WFD_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_32 WfdCmdType; ++ UINT_8 WfdEnable; ++ UINT_8 WfdCoupleSinkStatus; ++ UINT_8 WfdSessionAvailable; ++ UINT_8 WfdSigmaMode; ++ UINT_16 WfdDevInfo; ++ UINT_16 WfdControlPort; ++ UINT_16 WfdMaximumTp; ++ UINT_16 WfdExtendCap; ++ UINT_8 WfdCoupleSinkAddress[MAC_ADDR_LEN]; ++ UINT_8 WfdAssociatedBssid[MAC_ADDR_LEN]; ++ UINT_8 WfdVideoIp[4]; ++ UINT_8 WfdAudioIp[4]; ++ UINT_16 WfdVideoPort; ++ UINT_16 WfdAudioPort; ++ UINT_32 WfdFlag; ++ UINT_32 WfdPolicy; ++ UINT_32 WfdState; ++ UINT_8 WfdSessionInformationIE[24 * 8]; /* Include Subelement ID, length */ ++ UINT_16 WfdSessionInformationIELen; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; ++ UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; ++ UINT_32 WfdAdvanceFlag; ++ /* Group 1 64 bytes */ ++ UINT_8 aucWfdLocalIp[4]; ++ UINT_16 WfdLifetimeAc2; /* Unit is 2 TU */ ++ UINT_16 WfdLifetimeAc3; /* Unit is 2 TU */ ++ UINT_16 WfdCounterThreshold; /* Unit is ms */ ++ UINT_8 aucReserved2[54]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReserved3[64]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReserved4[64]; ++} NL80211_DRIVER_WFD_PARAMS, *P_NL80211_DRIVER_WFD_PARAMS; ++#endif ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo); ++ ++VOID p2pSetMode(IN BOOLEAN fgIsAPMOde); ++ ++BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode); ++ ++VOID p2pEalySuspendReg(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsEnable); ++ ++BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); ++ ++BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); ++ ++BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo); ++ ++VOID glP2pDestroyWirelessDevice(VOID); ++ ++VOID p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h +new file mode 100644 +index 000000000000..f24ceee9e921 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h +@@ -0,0 +1,133 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_rst.h#1 ++*/ ++ ++/*! \file gl_rst.h ++ \brief Declaration of functions and finite state machine for ++ MT6620 Whole-Chip Reset Mechanism ++*/ ++ ++#ifndef _GL_RST_H ++#define _GL_RST_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if 1 ++typedef INT_32(*wmt_wlan_probe_cb) (VOID); ++typedef INT_32(*wmt_wlan_remove_cb) (VOID); ++typedef INT_32(*wmt_wlan_bus_cnt_get_cb) (VOID); ++typedef INT_32(*wmt_wlan_bus_cnt_clr_cb) (VOID); ++ ++typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { ++ wmt_wlan_probe_cb wlan_probe_cb; ++ wmt_wlan_remove_cb wlan_remove_cb; ++ wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; ++ wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; ++} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; ++ ++extern INT_32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); ++extern INT_32 mtk_wcn_wmt_wlan_unreg(VOID); ++#endif ++ ++typedef enum _ENUM_RESET_STATUS_T { ++ RESET_FAIL, ++ RESET_SUCCESS ++} ENUM_RESET_STATUS_T; ++ ++typedef struct _RESET_STRUCT_T { ++ ENUM_RESET_STATUS_T rst_data; ++ struct work_struct rst_work; ++} RESET_STRUCT_T; ++ ++typedef enum _ENUM_WMTRSTMSG_TYPE_T { ++ WMTRSTMSG_RESET_START = 0x0, ++ WMTRSTMSG_RESET_END = 0x1, ++ WMTRSTMSG_RESET_END_FAIL = 0x2, ++ WMTRSTMSG_RESET_MAX, ++ WMTRSTMSG_RESET_INVALID = 0xff ++} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ void *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ unsigned int /* Buffer size in unit of byte */ ++); ++ ++/******************************************************************************* ++* E X T E R N A L F U N C T I O N S ++******************************************************************************** ++*/ ++#define glDoChipReset() \ ++ do { \ ++ if (!kalStrnCmp(current->comm, "mtk_wmtd", 8)) { \ ++ g_IsNeedDoChipReset = 1; \ ++ DBGLOG(INIT, ERROR, "forbid core dump in mtk_wmtd %s line %d\n", __func__, __LINE__); \ ++ break; \ ++ } \ ++ DBGLOG(INIT, ERROR, "Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 0x40); \ ++ } while (0) ++ ++#if CFG_CHIP_RESET_SUPPORT ++extern int mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++extern int mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++extern int wifi_reset_start(void); ++extern int wifi_reset_end(ENUM_RESET_STATUS_T); ++#endif ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++extern BOOLEAN mtk_wcn_set_connsys_power_off_flag(BOOLEAN value); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern UINT_32 g_IsNeedDoChipReset; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID glResetInit(VOID); ++ ++VOID glResetUninit(VOID); ++ ++VOID glSendResetRequest(VOID); ++ ++BOOLEAN kalIsResetting(VOID); ++ ++#endif /* _GL_RST_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h +new file mode 100644 +index 000000000000..3cc57780f201 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h +@@ -0,0 +1,21 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_sec.h#1 ++*/ ++ ++/*! \file p2p_fsm.h ++ \brief Declaration of functions and finite state machine for P2P Module. ++ ++ Declaration of functions and finite state machine for P2P Module. ++*/ ++ ++#ifndef _GL_SEC_H ++#define _GL_SEC_H ++ ++extern void handle_sec_msg_1(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_2(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_3(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_4(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_5(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_final(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++ ++#endif /* _GL_SEC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h +new file mode 100644 +index 000000000000..e9aa3e849eb2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h +@@ -0,0 +1,298 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_typedef.h#1 ++*/ ++ ++/*! \file gl_typedef.h ++ \brief Definition of basic data type(os dependent). ++ ++ In this file we define the basic data type. ++*/ ++ ++/* ++** Log: gl_typedef.h ++ * ++ * 06 22 2012 cp.wu ++ * [WCXRP00001257] [MT6620][MT5931][MT6628][Driver][Linux] Modify KAL_HZ to align ms accuracy ++ * modify KAL_HZ to (1000) for correct definition. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\6 2009-08-18 22:57:14 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\5 2008-09-22 23:19:30 GMT mtk01461 ++** Update comment for code review ++** \main\maintrunk.MT5921\4 2008-09-05 17:25:16 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\3 2007-11-09 11:00:50 GMT mtk01425 ++** 1. Use macro to unify network-to-host and host-to-network related functions ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_TYPEDEF_H ++#define _GL_TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Define HZ of timer tick for function kalGetTimeTick() */ ++#define KAL_HZ (1000) ++ ++/* Miscellaneous Equates */ ++#ifndef FALSE ++#define FALSE ((BOOLEAN) 0) ++#define TRUE ((BOOLEAN) 1) ++#endif /* FALSE */ ++ ++#ifndef NULL ++#if defined(__cplusplus) ++#define NULL 0 ++#else ++#define NULL ((void *) 0) ++#endif ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for void */ ++/*mach/mt_typedefs.h define _TYPEDEFS_H, to avoid compile error*/ ++#ifndef _TYPEDEFS_H ++typedef void VOID; ++#endif ++typedef void *PVOID, **PPVOID; ++ ++/* Type definition for Boolean */ ++typedef unsigned char BOOLEAN, *PBOOLEAN; ++ ++/* Type definition for signed integers */ ++typedef signed char CHAR, *PCHAR, **PPCHAR; ++typedef signed char INT_8, *PINT_8, **PPINT_8; ++typedef signed short INT_16, *PINT_16, **PPINT_16; ++typedef signed int INT_32, *PINT_32, **PPINT_32; ++typedef long LONG, *PLONG, **PPLONG; ++typedef signed long long INT_64, *PINT_64, **PPINT_64; ++ ++/* Type definition for unsigned integers */ ++typedef unsigned char UCHAR, *PUCHAR, **PPUCHAR; ++typedef unsigned char UINT_8, *PUINT_8, **PPUINT_8, *P_UINT_8; ++typedef unsigned short UINT_16, *PUINT_16, **PPUINT_16; ++typedef unsigned int UINT32, *PUINT32; ++typedef unsigned int UINT_32, *PUINT_32, **PPUINT_32; ++typedef unsigned long ULONG, *PULONG, **PPULONG; ++typedef unsigned long long UINT_64, *PUINT_64, **PPUINT_64; ++ ++typedef unsigned int OS_SYSTIME, *POS_SYSTIME, **PPOS_SYSTIME; ++ ++#ifndef _TYPEDEFS_H ++typedef signed char INT8, *PINT8; ++typedef signed short INT16, *PINT16; ++typedef signed int INT32, *PINT32; ++typedef unsigned char UINT8, *PUINT8; ++typedef unsigned short UINT16, *PUINT16; ++typedef unsigned int UINT32, *PUINT32; ++#endif ++ ++/* Type definition of large integer (64bits) union to be comptaible with ++ * Windows definition, so we won't apply our own coding style to these data types. ++ * NOTE: LARGE_INTEGER must NOT be floating variable. ++ * : Check for big-endian compatibility. ++ */ ++typedef union _LARGE_INTEGER { ++ struct { ++ UINT_32 LowPart; ++ INT_32 HighPart; ++ } u; ++ INT_64 QuadPart; ++} LARGE_INTEGER, *PLARGE_INTEGER; ++ ++typedef union _ULARGE_INTEGER { ++ struct { ++ UINT_32 LowPart; ++ UINT_32 HighPart; ++ } u; ++ UINT_64 QuadPart; ++} ULARGE_INTEGER, *PULARGE_INTEGER; ++ ++typedef INT_32(*probe_card) (PVOID pvData); ++typedef VOID(*remove_card) (VOID); ++ ++/* duplicated from wmt_exp.h for better driver isolation */ ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_STP = 5, ++ WMTDRV_TYPE_SDIO1 = 6, ++ WMTDRV_TYPE_SDIO2 = 7, ++ WMTDRV_TYPE_LPBK = 8, ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define IN /* volatile */ ++#define OUT /* volatile */ ++ ++#define __KAL_ATTRIB_PACKED__ __attribute__((__packed__)) ++#define __KAL_ATTRIB_ALIGN_4__ __aligned(4) ++ ++#ifndef BIT ++#define BIT(n) ((UINT_32) 1U << (n)) ++#endif /* BIT */ ++ ++#ifndef BITS ++/* bits range: for example BITS(16,23) = 0xFF0000 ++ * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 ++ * ==> (BIT(n+1)-1) = 0x00FFFFFF ++ */ ++#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) ++#endif /* BIT */ ++ ++/* This macro returns the byte offset of a named field in a known structure ++ type. ++ _type - structure name, ++ _field - field name of the structure */ ++#ifndef OFFSET_OF ++#define OFFSET_OF(_type, _field) ((ULONG)&(((_type *)0)->_field)) ++#endif /* OFFSET_OF */ ++ ++/* This macro returns the base address of an instance of a structure ++ * given the type of the structure and the address of a field within the ++ * containing structure. ++ * _addrOfField - address of current field of the structure, ++ * _type - structure name, ++ * _field - field name of the structure ++ */ ++#ifndef ENTRY_OF ++#define ENTRY_OF(_addrOfField, _type, _field) \ ++ ((_type *)((PINT_8)(_addrOfField) - (PINT_8)OFFSET_OF(_type, _field))) ++#endif /* ENTRY_OF */ ++ ++/* This macro align the input value to the DW boundary. ++ * _value - value need to check ++ */ ++#ifndef ALIGN_4 ++#define ALIGN_4(_value) (((_value) + 3) & ~3u) ++#endif /* ALIGN_4 */ ++ ++/* This macro check the DW alignment of the input value. ++ * _value - value of address need to check ++ */ ++#ifndef IS_ALIGN_4 ++#define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE) ++#endif /* IS_ALIGN_4 */ ++ ++#ifndef IS_NOT_ALIGN_4 ++#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE) ++#endif /* IS_NOT_ALIGN_4 */ ++ ++/* This macro evaluate the input length in unit of Double Word(4 Bytes). ++ * _value - value in unit of Byte, output will round up to DW boundary. ++ */ ++#ifndef BYTE_TO_DWORD ++#define BYTE_TO_DWORD(_value) ((_value + 3) >> 2) ++#endif /* BYTE_TO_DWORD */ ++ ++/* This macro evaluate the input length in unit of Byte. ++ * _value - value in unit of DW, output is in unit of Byte. ++ */ ++#ifndef DWORD_TO_BYTE ++#define DWORD_TO_BYTE(_value) ((_value) << 2) ++#endif /* DWORD_TO_BYTE */ ++ ++#if 1 /* Little-Endian */ ++#define CONST_NTOHS(_x) ntohs(_x) ++ ++#define CONST_HTONS(_x) htons(_x) ++ ++#define NTOHS(_x) ntohs(_x) ++ ++#define HTONS(_x) htons(_x) ++ ++#define NTOHL(_x) ntohl(_x) ++ ++#define HTONL(_x) htonl(_x) ++ ++#else /* Big-Endian */ ++ ++#define CONST_NTOHS(_x) ++ ++#define CONST_HTONS(_x) ++ ++#define NTOHS(_x) ++ ++#define HTONS(_x) ++ ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h +new file mode 100644 +index 000000000000..d8d5b0fb6740 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h +@@ -0,0 +1,619 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_vendor.h#1 ++*/ ++ ++/*! \file gl_vendor.h ++ \brief This file is for Portable Driver linux gl_vendor support. ++*/ ++ ++/* ++** Log: gl_vendor.h ++** ++** 10 14 2014 ++** add vendor declaration ++** ++ * ++*/ ++ ++#ifndef _GL_VENDOR_H ++#define _GL_VENDOR_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "gl_os.h" ++ ++#include "wlan_lib.h" ++#include "gl_wext.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define GOOGLE_OUI 0x001A11 ++ ++typedef enum { ++ /* Don't use 0 as a valid subcommand */ ++ ANDROID_NL80211_SUBCMD_UNSPECIFIED, ++ ++ /* Define all vendor startup commands between 0x0 and 0x0FFF */ ++ ANDROID_NL80211_SUBCMD_WIFI_RANGE_START = 0x0001, ++ ANDROID_NL80211_SUBCMD_WIFI_RANGE_END = 0x0FFF, ++ ++ /* Define all GScan related commands between 0x1000 and 0x10FF */ ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, ++ ++ /* Define all RTT related commands between 0x1100 and 0x11FF */ ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, ++ ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, ++ ++ /* Define all Logger related commands between 0x1400 and 0x14FF */ ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400, ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF, ++ ++ /* Define all wifi offload related commands between 0x1600 and 0x16FF */ ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, ++ ++ /* This is reserved for future usage */ ++ ++} ANDROID_VENDOR_SUB_COMMAND; ++ ++typedef enum { ++ WIFI_SUBCMD_GET_CHANNEL_LIST = ANDROID_NL80211_SUBCMD_WIFI_RANGE_START, ++ ++ WIFI_SUBCMD_GET_FEATURE_SET, /* 0x0001 */ ++ WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x0002 */ ++ WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x0003 */ ++ WIFI_SUBCMD_NODFS_SET, /* 0x0004 */ ++ WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x0005 */ ++ /* Add more sub commands here */ ++ ++} WIFI_SUB_COMMAND; ++ ++typedef enum { ++ GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, ++ ++ GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */ ++ GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */ ++ GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */ ++ GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */ ++ GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */ ++ ++ GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */ ++ ++ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */ ++ GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */ ++ /* Add more sub commands here */ ++ ++} GSCAN_SUB_COMMAND; ++ ++typedef enum { ++ RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, ++ RTT_SUBCMD_CANCEL_CONFIG, ++ RTT_SUBCMD_GETCAPABILITY, ++} RTT_SUB_COMMAND; ++ ++typedef enum { ++ LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, ++} LSTATS_SUB_COMMAND; ++ ++typedef enum { ++ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, ++ GSCAN_EVENT_HOTLIST_RESULTS_FOUND, ++ GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, ++ GSCAN_EVENT_FULL_SCAN_RESULTS, ++ RTT_EVENT_COMPLETE, ++ GSCAN_EVENT_COMPLETE_SCAN, ++ GSCAN_EVENT_HOTLIST_RESULTS_LOST ++} WIFI_VENDOR_EVENT; ++ ++typedef enum { ++ WIFI_ATTRIBUTE_BAND, ++ WIFI_ATTRIBUTE_NUM_CHANNELS, ++ WIFI_ATTRIBUTE_CHANNEL_LIST, ++ ++ WIFI_ATTRIBUTE_NUM_FEATURE_SET, ++ WIFI_ATTRIBUTE_FEATURE_SET, ++ WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, ++ WIFI_ATTRIBUTE_NODFS_VALUE, ++ WIFI_ATTRIBUTE_COUNTRY_CODE ++ ++} WIFI_ATTRIBUTE; ++ ++typedef enum { ++ GSCAN_ATTRIBUTE_CAPABILITIES = 1, ++ ++ GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, ++ GSCAN_ATTRIBUTE_BASE_PERIOD, ++ GSCAN_ATTRIBUTE_BUCKETS_BAND, ++ GSCAN_ATTRIBUTE_BUCKET_ID, ++ GSCAN_ATTRIBUTE_BUCKET_PERIOD, ++ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, ++ GSCAN_ATTRIBUTE_BUCKET_CHANNELS, ++ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, ++ GSCAN_ATTRIBUTE_REPORT_THRESHOLD, ++ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, ++ ++ GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, ++ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ ++ GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ ++ GSCAN_ENABLE_FULL_SCAN_RESULTS, ++ GSCAN_ATTRIBUTE_REPORT_EVENTS, ++ ++ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, ++ GSCAN_ATTRIBUTE_FLUSH_RESULTS, ++ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ ++ GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ ++ GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ ++ GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ ++ ++ GSCAN_ATTRIBUTE_SSID = 40, ++ GSCAN_ATTRIBUTE_BSSID, ++ GSCAN_ATTRIBUTE_CHANNEL, ++ GSCAN_ATTRIBUTE_RSSI, ++ GSCAN_ATTRIBUTE_TIMESTAMP, ++ GSCAN_ATTRIBUTE_RTT, ++ GSCAN_ATTRIBUTE_RTTSD, ++ ++ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, ++ GSCAN_ATTRIBUTE_RSSI_LOW, ++ GSCAN_ATTRIBUTE_RSSI_HIGH, ++ GSCAN_ATTRIBUTE_HOTLIST_ELEM, ++ GSCAN_ATTRIBUTE_HOTLIST_FLUSH, ++ ++ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, ++ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, ++ GSCAN_ATTRIBUTE_MIN_BREACHING, ++ GSCAN_ATTRIBUTE_NUM_AP, ++ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, ++ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH ++ ++} GSCAN_ATTRIBUTE; ++ ++typedef enum { ++ RTT_ATTRIBUTE_CAPABILITIES = 1, ++ ++ RTT_ATTRIBUTE_TARGET_CNT = 10, ++ RTT_ATTRIBUTE_TARGET_INFO, ++ RTT_ATTRIBUTE_TARGET_MAC, ++ RTT_ATTRIBUTE_TARGET_TYPE, ++ RTT_ATTRIBUTE_TARGET_PEER, ++ RTT_ATTRIBUTE_TARGET_CHAN, ++ RTT_ATTRIBUTE_TARGET_PERIOD, ++ RTT_ATTRIBUTE_TARGET_NUM_BURST, ++ RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, ++ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, ++ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, ++ RTT_ATTRIBUTE_TARGET_LCI, ++ RTT_ATTRIBUTE_TARGET_LCR, ++ RTT_ATTRIBUTE_TARGET_BURST_DURATION, ++ RTT_ATTRIBUTE_TARGET_PREAMBLE, ++ RTT_ATTRIBUTE_TARGET_BW, ++ RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, ++ RTT_ATTRIBUTE_RESULTS_PER_TARGET, ++ RTT_ATTRIBUTE_RESULT_CNT, ++ RTT_ATTRIBUTE_RESULT ++} RTT_ATTRIBUTE; ++ ++typedef enum { ++ LSTATS_ATTRIBUTE_STATS = 2, ++} LSTATS_ATTRIBUTE; ++ ++typedef enum { ++ WIFI_BAND_UNSPECIFIED, ++ WIFI_BAND_BG = 1, /* 2.4 GHz */ ++ WIFI_BAND_A = 2, /* 5 GHz without DFS */ ++ WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ ++ WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ ++ WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ ++ WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ ++} WIFI_BAND; ++ ++typedef enum { ++ WIFI_SCAN_BUFFER_FULL, ++ WIFI_SCAN_COMPLETE, ++} WIFI_SCAN_EVENT; ++ ++#define GSCAN_MAX_REPORT_THRESHOLD 1024000 ++#define GSCAN_MAX_CHANNELS 8 ++#define GSCAN_MAX_BUCKETS 8 ++#define MAX_HOTLIST_APS 16 ++#define MAX_SIGNIFICANT_CHANGE_APS 16 ++#define PSCAN_MAX_SCAN_CACHE_SIZE 16 ++#define PSCAN_MAX_AP_CACHE_PER_SCAN 16 ++#define PSCAN_VERSION 1 ++ ++#define MAX_BUFFERED_GSCN_RESULTS 5 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_64 wifi_timestamp; /* In microseconds (us) */ ++typedef UINT_64 wifi_timespan; /* In nanoseconds (ns) */ ++ ++typedef UINT_8 mac_addr[6]; ++typedef UINT_32 wifi_channel; /* Indicates channel frequency in MHz */ ++typedef INT_32 wifi_rssi; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++typedef struct _PARAM_WIFI_GSCAN_GET_RESULT_PARAMS { ++ UINT_32 get_num; ++ UINT_8 flush; ++} PARAM_WIFI_GSCAN_GET_RESULT_PARAMS, *P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS { ++ UINT_8 ucPscanAct; ++ UINT_8 aucReserved[3]; ++} PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T { ++ UINT_32 max_scan_cache_size; /* total space allocated for scan (in bytes) */ ++ UINT_32 max_scan_buckets; /* maximum number of channel buckets */ ++ UINT_32 max_ap_cache_per_scan; /* maximum number of APs that can be stored per scan */ ++ UINT_32 max_rssi_sample_size; /* number of RSSI samples used for averaging RSSI */ ++ UINT_32 max_scan_reporting_threshold; /* max possible report_threshold as described */ ++ /* in wifi_scan_cmd_params */ ++ UINT_32 max_hotlist_aps; /* maximum number of entries for hotlist APs */ ++ UINT_32 max_significant_wifi_change_aps; /* maximum number of entries for */ ++ /* significant wifi change APs */ ++ UINT_32 max_bssid_history_entries; /* number of BSSID/RSSI entries that device can hold */ ++} PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T, *P_PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T; ++ ++typedef struct _PARAM_WIFI_GSCAN_CHANNEL_SPEC { ++ UINT_32 channel; /* frequency */ ++ UINT_32 dwellTimeMs; /* dwell time hint */ ++ UINT_32 passive; /* 0 => active, 1 => passive scan; ignored for DFS */ ++ /* Add channel class */ ++} PARAM_WIFI_GSCAN_CHANNEL_SPEC, *P_PARAM_WIFI_GSCAN_CHANNEL_SPEC; ++ ++typedef struct _PARAM_WIFI_GSCAN_BUCKET_SPEC { ++ UINT_32 bucket; /* bucket index, 0 based */ ++ WIFI_BAND band; /* when UNSPECIFIED, use channel list */ ++ UINT_32 period; /* desired period, in millisecond; if this is too */ ++ /* low, the firmware should choose to generate results as */ ++ /* fast as it can instead of failing the command */ ++ /* report_events semantics - ++ * 0 => report only when scan history is % full ++ * 1 => same as 0 + report a scan completion event after scanning this bucket ++ * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL ++ * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to ++ supplicant as well (optional) . */ ++ UINT_8 report_events; ++ ++ UINT_32 num_channels; ++ PARAM_WIFI_GSCAN_CHANNEL_SPEC channels[GSCAN_MAX_CHANNELS]; /* channels to scan; ++ these may include DFS channels */ ++} PARAM_WIFI_GSCAN_BUCKET_SPEC, *P_PARAM_WIFI_GSCAN_BUCKET_SPEC; ++ ++typedef struct _PARAM_WIFI_GSCAN_CMD_PARAMS { ++ UINT_32 base_period; /* base timer period in ms */ ++ UINT_32 max_ap_per_scan; /* number of APs to store in each scan in the */ ++ /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ ++ UINT_32 report_threshold; /* in %, when scan buffer is this much full, wake up AP */ ++ UINT_32 num_scans; ++ UINT_32 num_buckets; ++ PARAM_WIFI_GSCAN_BUCKET_SPEC buckets[GSCAN_MAX_BUCKETS]; ++} PARAM_WIFI_GSCAN_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_CMD_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_RESULT { ++ wifi_timestamp ts; /* time since boot (in microsecond) when the result was */ ++ /* retrieved */ ++ UINT_8 ssid[32 + 1]; /* null terminated */ ++ mac_addr bssid; ++ wifi_channel channel; /* channel frequency in MHz */ ++ wifi_rssi rssi; /* in db */ ++ wifi_timespan rtt; /* in nanoseconds */ ++ wifi_timespan rtt_sd; /* standard deviation in rtt */ ++ UINT_16 beacon_period; /* period advertised in the beacon */ ++ UINT_16 capability; /* capabilities advertised in the beacon */ ++ UINT_32 ie_length; /* size of the ie_data blob */ ++ UINT_8 ie_data[1]; /* blob of all the information elements found in the */ ++ /* beacon; this data should be a packed list of */ ++ /* wifi_information_element objects, one after the other. */ ++ /* other fields */ ++} PARAM_WIFI_GSCAN_RESULT, *P_PARAM_WIFI_GSCAN_RESULT; ++ ++/* Significant wifi change*/ ++/*typedef struct _PARAM_WIFI_CHANGE_RESULT{ ++ mac_addr bssid; // BSSID ++ wifi_channel channel; // channel frequency in MHz ++ UINT_32 num_rssi; // number of rssi samples ++ wifi_rssi rssi[8]; // RSSI history in db ++} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT;*/ ++ ++typedef struct _PARAM_WIFI_CHANGE_RESULT { ++ UINT_16 flags; ++ UINT_16 channel; ++ mac_addr bssid; /* BSSID */ ++ INT_8 rssi[8]; /* RSSI history in db */ ++} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT; ++ ++typedef struct _PARAM_AP_THRESHOLD { ++ mac_addr bssid; /* AP BSSID */ ++ wifi_rssi low; /* low threshold */ ++ wifi_rssi high; /* high threshold */ ++ wifi_channel channel; /* channel hint */ ++} PARAM_AP_THRESHOLD, *P_PARAM_AP_THRESHOLD; ++ ++typedef struct _PARAM_WIFI_BSSID_HOTLIST { ++ UINT_32 lost_ap_sample_size; ++ UINT_32 num_ap; /* number of hotlist APs */ ++ PARAM_AP_THRESHOLD ap[MAX_HOTLIST_APS]; /* hotlist APs */ ++} PARAM_WIFI_BSSID_HOTLIST, *P_PARAM_WIFI_BSSID_HOTLIST; ++ ++typedef struct _PARAM_WIFI_SIGNIFICANT_CHANGE { ++ UINT_16 rssi_sample_size; /* number of samples for averaging RSSI */ ++ UINT_16 lost_ap_sample_size; /* number of samples to confirm AP loss */ ++ UINT_16 min_breaching; /* number of APs breaching threshold */ ++ UINT_16 num_ap; /* max 64 */ ++ PARAM_AP_THRESHOLD ap[MAX_SIGNIFICANT_CHANGE_APS]; ++} PARAM_WIFI_SIGNIFICANT_CHANGE, *P_PARAM_WIFI_SIGNIFICANT_CHANGE; ++ ++/* RTT Capabilities */ ++typedef struct _PARAM_WIFI_RTT_CAPABILITIES { ++ UINT_8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ ++ UINT_8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ ++ UINT_8 lci_support; /* if initiator supports LCI request. Applies to 2-sided RTT */ ++ UINT_8 lcr_support; /* if initiator supports LCR request. Applies to 2-sided RTT */ ++ UINT_8 preamble_support; /* bit mask indicates what preamble is supported by initiator */ ++ UINT_8 bw_support; /* bit mask indicates what BW is supported by initiator */ ++} PARAM_WIFI_RTT_CAPABILITIES, *P_PARAM_WIFI_RTT_CAPABILITIES; ++ ++/* channel operating width */ ++typedef enum { ++ WIFI_CHAN_WIDTH_20 = 0, ++ WIFI_CHAN_WIDTH_40 = 1, ++ WIFI_CHAN_WIDTH_80 = 2, ++ WIFI_CHAN_WIDTH_160 = 3, ++ WIFI_CHAN_WIDTH_80P80 = 4, ++ WIFI_CHAN_WIDTH_5 = 5, ++ WIFI_CHAN_WIDTH_10 = 6, ++ WIFI_CHAN_WIDTH_INVALID = -1 ++} WIFI_CHANNEL_WIDTH; ++ ++/* channel information */ ++typedef struct { ++ WIFI_CHANNEL_WIDTH width; /* channel width (20, 40, 80, 80+80, 160) */ ++ UINT_32 center_freq; /* primary 20 MHz channel */ ++ UINT_32 center_freq0; /* center frequency (MHz) first segment */ ++ UINT_32 center_freq1; /* center frequency (MHz) second segment */ ++} WIFI_CHANNEL_INFO; ++ ++/* channel statistics */ ++typedef struct { ++ WIFI_CHANNEL_INFO channel; /* channel */ ++ UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ ++ UINT_32 cca_busy_time; /* msecs the CCA register is busy (32 bits number accruing over time) */ ++} WIFI_CHANNEL_STAT; ++ ++/* radio statistics */ ++typedef struct { ++ UINT_32 radio; /* wifi radio (if multiple radio supported) */ ++ UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ ++ UINT_32 tx_time; /* msecs the radio is transmitting (32 bits number accruing over time) */ ++ UINT_32 rx_time; /* msecs the radio is in active receive (32 bits number accruing over time) */ ++ UINT_32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits number accruing over time) */ ++ UINT_32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits number accruing over time) */ ++ UINT_32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits number accruing over time) */ ++ UINT_32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan ++ (32 bits number accruing over time) */ ++ UINT_32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan ++ (32 bits number accruing over time) */ ++ UINT_32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and GAS exchange ++ 32 bits number accruing over time) */ ++ UINT_32 num_channels; /* number of channels */ ++ WIFI_CHANNEL_STAT channels[]; /* channel statistics */ ++} WIFI_RADIO_STAT; ++ ++/* wifi rate */ ++typedef struct { ++ UINT_32 preamble:3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ ++ UINT_32 nss:2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ ++ UINT_32 bw:3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ ++ UINT_32 rateMcsIdx:8; /* OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps */ ++ /* HT/VHT it would be mcs index */ ++ UINT_32 reserved:16; /* reserved */ ++ UINT_32 bitrate; /* units of 100 Kbps */ ++} WIFI_RATE; ++ ++/* per rate statistics */ ++typedef struct { ++ WIFI_RATE rate; /* rate information */ ++ UINT_32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ ++ UINT_32 rx_mpdu; /* number of received data pkts */ ++ UINT_32 mpdu_lost; /* number of data packet losses (no ACK) */ ++ UINT_32 retries; /* total number of data pkt retries */ ++ UINT_32 retries_short; /* number of short data pkt retries */ ++ UINT_32 retries_long; /* number of long data pkt retries */ ++} WIFI_RATE_STAT; ++ ++/*wifi_interface_link_layer_info*/ ++typedef enum { ++ WIFI_DISCONNECTED = 0, ++ WIFI_AUTHENTICATING = 1, ++ WIFI_ASSOCIATING = 2, ++ WIFI_ASSOCIATED = 3, ++ WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ ++ WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ ++} WIFI_CONNECTION_STATE; ++ ++typedef enum { ++ WIFI_ROAMING_IDLE = 0, ++ WIFI_ROAMING_ACTIVE = 1, ++} WIFI_ROAM_STATE; ++ ++typedef enum { ++ WIFI_INTERFACE_STA = 0, ++ WIFI_INTERFACE_SOFTAP = 1, ++ WIFI_INTERFACE_IBSS = 2, ++ WIFI_INTERFACE_P2P_CLIENT = 3, ++ WIFI_INTERFACE_P2P_GO = 4, ++ WIFI_INTERFACE_NAN = 5, ++ WIFI_INTERFACE_MESH = 6, ++ WIFI_INTERFACE_UNKNOWN = -1 ++} WIFI_INTERFACE_MODE; ++ ++typedef struct { ++ WIFI_INTERFACE_MODE mode; /* interface mode */ ++ u8 mac_addr[6]; /* interface mac address (self) */ ++ WIFI_CONNECTION_STATE state; /* connection state (valid for STA, CLI only) */ ++ WIFI_ROAM_STATE roaming; /* roaming state */ ++ u32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ ++ u8 ssid[33]; /* null terminated SSID */ ++ u8 bssid[6]; /* bssid */ ++ u8 ap_country_str[3]; /* country string advertised by AP */ ++ u8 country_str[3]; /* country string for this association */ ++} WIFI_INTERFACE_LINK_LAYER_INFO; ++ ++/* access categories */ ++typedef enum { ++ WIFI_AC_VO = 0, ++ WIFI_AC_VI = 1, ++ WIFI_AC_BE = 2, ++ WIFI_AC_BK = 3, ++ WIFI_AC_MAX = 4, ++} WIFI_TRAFFIC_AC; ++ ++/* wifi peer type */ ++typedef enum { ++ WIFI_PEER_STA, ++ WIFI_PEER_AP, ++ WIFI_PEER_P2P_GO, ++ WIFI_PEER_P2P_CLIENT, ++ WIFI_PEER_NAN, ++ WIFI_PEER_TDLS, ++ WIFI_PEER_INVALID, ++} WIFI_PEER_TYPE; ++ ++/* per peer statistics */ ++typedef struct { ++ WIFI_PEER_TYPE type; /* peer type (AP, TDLS, GO etc.) */ ++ UINT_8 peer_mac_address[6]; /* mac address */ ++ UINT_32 capabilities; /* peer WIFI_CAPABILITY_XXX */ ++ UINT_32 num_rate; /* number of rates */ ++ WIFI_RATE_STAT rate_stats[]; /* per rate statistics, number of entries = num_rate */ ++} WIFI_PEER_INFO; ++ ++/* per access category statistics */ ++typedef struct { ++ WIFI_TRAFFIC_AC ac; /* access category (VI, VO, BE, BK) */ ++ UINT_32 tx_mpdu; /* number of successfully transmitted unicast data pkts (ACK rcvd) */ ++ UINT_32 rx_mpdu; /* number of received unicast mpdus */ ++ UINT_32 tx_mcast; /* number of successfully transmitted multicast data packets */ ++ /* STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent */ ++ UINT_32 rx_mcast; /* number of received multicast data packets */ ++ UINT_32 rx_ampdu; /* number of received unicast a-mpdus */ ++ UINT_32 tx_ampdu; /* number of transmitted unicast a-mpdus */ ++ UINT_32 mpdu_lost; /* number of data pkt losses (no ACK) */ ++ UINT_32 retries; /* total number of data pkt retries */ ++ UINT_32 retries_short; /* number of short data pkt retries */ ++ UINT_32 retries_long; /* number of long data pkt retries */ ++ UINT_32 contention_time_min; /* data pkt min contention time (usecs) */ ++ UINT_32 contention_time_max; /* data pkt max contention time (usecs) */ ++ UINT_32 contention_time_avg; /* data pkt avg contention time (usecs) */ ++ UINT_32 contention_num_samples; /* num of data pkts used for contention statistics */ ++} WIFI_WMM_AC_STAT; ++ ++/* interface statistics */ ++typedef struct { ++ /* wifi_interface_handle iface; // wifi interface */ ++ WIFI_INTERFACE_LINK_LAYER_INFO info; /* current state of the interface */ ++ UINT_32 beacon_rx; /* access point beacon received count from connected AP */ ++ UINT_32 mgmt_rx; /* access point mgmt frames received count from connected AP (including Beacon) */ ++ UINT_32 mgmt_action_rx; /* action frames received count */ ++ UINT_32 mgmt_action_tx; /* action frames transmit count */ ++ wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI (averaged) */ ++ wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from connected AP */ ++ wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from connected AP */ ++ WIFI_WMM_AC_STAT ac[WIFI_AC_MAX]; /* per ac data packet statistics */ ++ UINT_32 num_peers; /* number of peers */ ++ WIFI_PEER_INFO peer_info[]; /* per peer statistics */ ++} WIFI_IFACE_STAT; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete); ++ ++int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num); ++ ++int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++#endif /* _GL_VENDOR_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h +new file mode 100644 +index 000000000000..827ff92b1581 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h +@@ -0,0 +1,357 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext.h#1 ++*/ ++ ++/*! \file gl_wext.h ++ \brief This file is for Portable Driver linux wireless extension support. ++*/ ++ ++/* ++** Log: gl_wext.h ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. ++ * Connection establish successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. . ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\12 2009-10-20 17:38:33 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\11 2009-09-28 20:19:28 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\10 2009-09-03 12:12:35 GMT mtk01088 ++** adding the function declaration ++** \main\maintrunk.MT5921\9 2009-08-18 22:57:17 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\8 2008-08-29 16:59:07 GMT mtk01088 ++** fixed compiling error ++** \main\maintrunk.MT5921\7 2008-08-29 14:13:28 GMT mtk01088 ++** adjust the header file for code refine ++** \main\maintrunk.MT5921\6 2008-03-28 10:40:31 GMT mtk01461 ++** Add set desired rate in Linux STD IOCTL ++** \main\maintrunk.MT5921\5 2008-03-11 14:51:08 GMT mtk01461 ++** Refine private IOCTL functions ++** \main\maintrunk.MT5921\4 2008-02-12 23:45:45 GMT mtk01461 ++** Add Set Frequency & Channel oid support for Linux ++** \main\maintrunk.MT5921\3 2007-11-06 19:36:19 GMT mtk01088 ++** add the WPS related code ++*/ ++ ++#ifndef _GL_WEXT_H ++#define _GL_WEXT_H ++ ++#ifdef WIRELESS_EXT ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define KILO 1000 ++#define RATE_5_5M 11 /* 5.5M */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _PARAM_FIXED_IEs { ++ UINT_8 aucTimestamp[8]; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2Capabilities; ++} PARAM_FIXED_IEs; ++ ++typedef struct _PARAM_VARIABLE_IE_T { ++ UINT_8 ucElementID; ++ UINT_8 ucLength; ++ UINT_8 aucData[1]; ++} PARAM_VARIABLE_IE_T, *P_PARAM_VARIABLE_IE_T; ++ ++#if WIRELESS_EXT < 18 ++ ++#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses struct iw_mlme */ ++/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ ++#define IW_MLME_DEAUTH 0 ++#define IW_MLME_DISASSOC 1 ++ ++/*! \brief SIOCSIWMLME data */ ++struct iw_mlme { ++ __u16 cmd; /*!< IW_MLME_* */ ++ __u16 reason_code; ++ struct sockaddr addr; ++}; ++ ++#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ ++#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ ++/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ ++#define IW_AUTH_INDEX 0x0FFF ++#define IW_AUTH_FLAGS 0xF000 ++/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) ++ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the ++ * parameter that is being set/get to; value will be read/written to ++ * struct iw_param value field) */ ++#define IW_AUTH_WPA_VERSION 0 ++#define IW_AUTH_CIPHER_PAIRWISE 1 ++#define IW_AUTH_CIPHER_GROUP 2 ++#define IW_AUTH_KEY_MGMT 3 ++#define IW_AUTH_TKIP_COUNTERMEASURES 4 ++#define IW_AUTH_DROP_UNENCRYPTED 5 ++#define IW_AUTH_80211_AUTH_ALG 6 ++#define IW_AUTH_WPA_ENABLED 7 ++#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 ++#define IW_AUTH_ROAMING_CONTROL 9 ++#define IW_AUTH_PRIVACY_INVOKED 10 ++#if CFG_SUPPORT_802_11W ++#define IW_AUTH_MFP 12 ++ ++#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ ++#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ ++#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ ++#endif ++ ++/* IW_AUTH_WPA_VERSION values (bit field) */ ++#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 ++#define IW_AUTH_WPA_VERSION_WPA 0x00000002 ++#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 ++ ++/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ ++#define IW_AUTH_CIPHER_NONE 0x00000001 ++#define IW_AUTH_CIPHER_WEP40 0x00000002 ++#define IW_AUTH_CIPHER_TKIP 0x00000004 ++#define IW_AUTH_CIPHER_CCMP 0x00000008 ++#define IW_AUTH_CIPHER_WEP104 0x00000010 ++ ++/* IW_AUTH_KEY_MGMT values (bit field) */ ++#define IW_AUTH_KEY_MGMT_802_1X 1 ++#define IW_AUTH_KEY_MGMT_PSK 2 ++#define IW_AUTH_KEY_MGMT_WPA_NONE 4 ++ ++/* IW_AUTH_80211_AUTH_ALG values (bit field) */ ++#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 ++#define IW_AUTH_ALG_SHARED_KEY 0x00000002 ++#define IW_AUTH_ALG_LEAP 0x00000004 ++ ++/* IW_AUTH_ROAMING_CONTROL values */ ++#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ ++#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming ++ * control */ ++ ++#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ ++#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ ++/* SIOCSIWENCODEEXT definitions */ ++#define IW_ENCODE_SEQ_MAX_SIZE 8 ++/* struct iw_encode_ext ->alg */ ++#define IW_ENCODE_ALG_NONE 0 ++#define IW_ENCODE_ALG_WEP 1 ++#define IW_ENCODE_ALG_TKIP 2 ++#define IW_ENCODE_ALG_CCMP 3 ++#if CFG_SUPPORT_802_11W ++#define IW_ENCODE_ALG_AES_CMAC 5 ++#endif ++ ++/* struct iw_encode_ext ->ext_flags */ ++#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 ++#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 ++#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 ++#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 ++ ++struct iw_encode_ext { ++ __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ ++ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ struct sockaddr addr; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast ++ * (group) keys or unicast address for ++ * individual keys */ ++ __u16 alg; /*!< IW_ENCODE_ALG_* */ ++ __u16 key_len; ++ __u8 key[0]; ++}; ++ ++#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ ++#define IW_PMKSA_ADD 1 ++#define IW_PMKSA_REMOVE 2 ++#define IW_PMKSA_FLUSH 3 ++ ++#define IW_PMKID_LEN 16 ++ ++struct iw_pmksa { ++ __u32 cmd; /*!< IW_PMKSA_* */ ++ struct sockaddr bssid; ++ __u8 pmkid[IW_PMKID_LEN]; ++}; ++ ++#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) ++ * (scan results); This includes id and ++ * length fields. One IWEVGENIE may ++ * contain more than one IE. Scan ++ * results may contain one or more ++ * IWEVGENIE events. */ ++#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure ++ * (struct iw_michaelmicfailure) ++ */ ++#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. ++ * The data includes id and length ++ * fields and may contain more than one ++ * IE. This event is required in ++ * Managed mode if the driver ++ * generates its own WPA/RSN IE. This ++ * should be sent just before ++ * IWEVREGISTERED event for the ++ * association. */ ++#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association ++ * Response. The data includes id and ++ * length fields and may contain more ++ * than one IE. This may be sent ++ * between IWEVASSOCREQIE and ++ * IWEVREGISTERED events for the ++ * association. */ ++#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN ++ * pre-authentication ++ * (struct iw_pmkid_cand) */ ++ ++#endif /* WIRELESS_EXT < 18 */ ++ ++#if WIRELESS_EXT < 17 ++/* Statistics flags (bitmask in updated) */ ++#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */ ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#endif ++ ++enum { ++ IEEE80211_FILTER_TYPE_BEACON = 1 << 0, ++ IEEE80211_FILTER_TYPE_PROBE_REQ = 1 << 1, ++ IEEE80211_FILTER_TYPE_PROBE_RESP = 1 << 2, ++ IEEE80211_FILTER_TYPE_ASSOC_REQ = 1 << 3, ++ IEEE80211_FILTER_TYPE_ASSOC_RESP = 1 << 4, ++ IEEE80211_FILTER_TYPE_AUTH = 1 << 5, ++ IEEE80211_FILTER_TYPE_DEAUTH = 1 << 6, ++ IEEE80211_FILTER_TYPE_DISASSOC = 1 << 7, ++ IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */ ++}; ++ ++#if CFG_SUPPORT_WAPI ++#define IW_AUTH_WAPI_ENABLED 0x20 ++#define IW_ENCODE_ALG_SMS4 0x20 ++#endif ++ ++#if CFG_SUPPORT_WAPI /* Android+ */ ++#define IW_AUTH_KEY_MGMT_WAPI_PSK 3 ++#define IW_AUTH_KEY_MGMT_WAPI_CERT 4 ++#endif ++#define IW_AUTH_KEY_MGMT_WPS 5 ++ ++#if CFG_SUPPORT_802_11W ++#define IW_AUTH_KEY_MGMT_802_1X_SHA256 7 ++#define IW_AUTH_KEY_MGMT_PSK_SHA256 8 ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern const struct iw_handler_def wext_handler_def; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* wireless extensions' ioctls */ ++int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd); ++ ++int ++wext_set_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra); ++ ++void ++wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, ++ IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4DataLen); ++ ++struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev); ++ ++BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++#if CFG_SUPPORT_WAPI ++BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* WIRELESS_EXT */ ++ ++#endif /* _GL_WEXT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h +new file mode 100644 +index 000000000000..31933fc6a461 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h +@@ -0,0 +1,402 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext_priv.h#3 ++*/ ++ ++/*! \file gl_wext_priv.h ++ \brief This file includes private ioctl support. ++*/ ++ ++/* ++** Log: gl_wext_priv.h ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add a CMD ID for P2P driver version query. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\16 2009-09-29 16:47:23 GMT mtk01090 ++** Remove unused functions ++** \main\maintrunk.MT5921\15 2009-09-28 20:19:31 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\14 2009-05-07 22:26:06 GMT mtk01089 ++** add private IO control for Linux BWCS ++** \main\maintrunk.MT5921\13 2008-08-29 14:55:20 GMT mtk01088 ++** adjust the code to meet coding style ++** \main\maintrunk.MT5921\12 2008-07-16 15:23:45 GMT mtk01104 ++** Support GPIO2 mode ++** \main\maintrunk.MT5921\11 2008-07-14 13:55:58 GMT mtk01104 ++** Support PRIV_CMD_BT_COEXIST ++** \main\maintrunk.MT5921\10 2008-07-09 00:20:24 GMT mtk01461 ++** Add priv oid to support WMM_PS_TEST ++** \main\maintrunk.MT5921\9 2008-05-30 20:27:24 GMT mtk01461 ++** Add POWER_MODE Private IOCTL cmd ++** \main\maintrunk.MT5921\8 2008-04-17 23:06:44 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\7 2008-03-31 21:01:24 GMT mtk01461 ++** Add priv IOCTL for VOIP settings ++** \main\maintrunk.MT5921\6 2008-03-31 13:49:47 GMT mtk01461 ++** add priv ioctl arg definition for turning on / off roaming ++** \main\maintrunk.MT5921\5 2008-03-26 15:35:09 GMT mtk01461 ++** Add CSUM offload priv ioctl for Linux ++** \main\maintrunk.MT5921\4 2008-03-11 14:51:11 GMT mtk01461 ++** Refine private IOCTL functions ++** \main\maintrunk.MT5921\3 2007-11-06 19:36:25 GMT mtk01088 ++** add the WPS related code ++*/ ++ ++#ifndef _GL_WEXT_PRIV_H ++#define _GL_WEXT_PRIV_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++/* If it is set to 1, iwpriv will support register read/write */ ++#define CFG_SUPPORT_PRIV_MCR_RW 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++extern int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++#if 0 ++extern BOOLEAN fgIsResetting; ++extern BOOLEAN g_u4HaltFlag; ++extern spinlock_t g_p2p_lock; ++extern int g_u4P2PEnding; ++extern int g_u4P2POnOffing; ++#endif ++#endif ++ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++extern VOID rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* New wireless extensions API - SET/GET convention (even ioctl numbers are ++ * root only) ++ */ ++#define IOCTL_SET_INT (SIOCIWFIRSTPRIV + 0) ++#define IOCTL_GET_INT (SIOCIWFIRSTPRIV + 1) ++ ++#define IOCTL_SET_ADDRESS (SIOCIWFIRSTPRIV + 2) ++#define IOCTL_GET_ADDRESS (SIOCIWFIRSTPRIV + 3) ++#define IOCTL_SET_STR (SIOCIWFIRSTPRIV + 4) ++#define IOCTL_GET_STR (SIOCIWFIRSTPRIV + 5) ++#define IOCTL_SET_KEY (SIOCIWFIRSTPRIV + 6) ++#define IOCTL_GET_KEY (SIOCIWFIRSTPRIV + 7) ++#define IOCTL_SET_STRUCT (SIOCIWFIRSTPRIV + 8) ++#define IOCTL_GET_STRUCT (SIOCIWFIRSTPRIV + 9) ++#define IOCTL_SET_STRUCT_FOR_EM (SIOCIWFIRSTPRIV + 11) ++#define IOCTL_SET_INTS (SIOCIWFIRSTPRIV + 12) ++#define IOCTL_GET_INTS (SIOCIWFIRSTPRIV + 13) ++#define IOCTL_SET_STRING (SIOCIWFIRSTPRIV + 14) ++ ++#define PRIV_CMD_REG_DOMAIN 0 ++#define PRIV_CMD_BEACON_PERIOD 1 ++#define PRIV_CMD_ADHOC_MODE 2 ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++#define PRIV_CMD_CSUM_OFFLOAD 3 ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++#define PRIV_CMD_ROAMING 4 ++#define PRIV_CMD_VOIP_DELAY 5 ++#define PRIV_CMD_POWER_MODE 6 ++ ++#define PRIV_CMD_WMM_PS 7 ++#define PRIV_CMD_BT_COEXIST 8 ++#define PRIV_GPIO2_MODE 9 ++ ++#define PRIV_CUSTOM_SET_PTA 10 ++#define PRIV_CUSTOM_CONTINUOUS_POLL 11 ++#define PRIV_CUSTOM_SINGLE_ANTENNA 12 ++#define PRIV_CUSTOM_BWCS_CMD 13 ++#define PRIV_CUSTOM_DISABLE_BEACON_DETECTION 14 /* later */ ++#define PRIV_CMD_OID 15 ++#define PRIV_SEC_MSG_OID 16 ++ ++#define PRIV_CMD_TEST_MODE 17 ++#define PRIV_CMD_TEST_CMD 18 ++#define PRIV_CMD_ACCESS_MCR 19 ++#define PRIV_CMD_SW_CTRL 20 ++ ++#if 1 /* ANTI_PRIVCY */ ++#define PRIV_SEC_CHECK_OID 21 ++#endif ++ ++#define PRIV_CMD_WSC_PROBE_REQ 22 ++ ++#define PRIV_CMD_P2P_VERSION 23 ++ ++#define PRIV_CMD_GET_CH_LIST 24 ++ ++#define PRIV_CMD_SET_TX_POWER 25 ++ ++#define PRIV_CMD_BAND_CONFIG 26 ++ ++#define PRIV_CMD_DUMP_MEM 27 ++ ++#define PRIV_CMD_P2P_MODE 28 ++ ++#define PRIV_CMD_GET_BUILD_DATE_CODE 29 ++ ++#define PRIV_CMD_GET_DEBUG_CODE 30 ++ ++#define PRIV_CMD_OTHER 31 ++ ++#define PRIV_CMD_WFD_DEBUG_CODE 32 ++ ++#define PRIV_CMD_MET_PROFILING 33 ++ ++/* other string command ID */ ++#define PRIV_CMD_OTHER_TDLS 0x00 ++#define PRIV_CMD_OTHER_TAR 0x01 /* TX auto rate */ ++ ++/* 802.3 Objects (Ethernet) */ ++#define OID_802_3_CURRENT_ADDRESS 0x01010102 ++ ++/* IEEE 802.11 OIDs */ ++#define OID_802_11_SUPPORTED_RATES 0x0D01020E ++#define OID_802_11_CONFIGURATION 0x0D010211 ++ ++/* PnP and PM OIDs, NDIS default OIDS */ ++#define OID_PNP_SET_POWER 0xFD010101 ++ ++#define OID_CUSTOM_OID_INTERFACE_VERSION 0xFFA0C000 ++ ++/* MT5921 specific OIDs */ ++#define OID_CUSTOM_BT_COEXIST_CTRL 0xFFA0C580 ++#define OID_CUSTOM_POWER_MANAGEMENT_PROFILE 0xFFA0C581 ++#define OID_CUSTOM_PATTERN_CONFIG 0xFFA0C582 ++#define OID_CUSTOM_BG_SSID_SEARCH_CONFIG 0xFFA0C583 ++#define OID_CUSTOM_VOIP_SETUP 0xFFA0C584 ++#define OID_CUSTOM_ADD_TS 0xFFA0C585 ++#define OID_CUSTOM_DEL_TS 0xFFA0C586 ++#define OID_CUSTOM_SLT 0xFFA0C587 ++#define OID_CUSTOM_ROAMING_EN 0xFFA0C588 ++#define OID_CUSTOM_WMM_PS_TEST 0xFFA0C589 ++#define OID_CUSTOM_COUNTRY_STRING 0xFFA0C58A ++#define OID_CUSTOM_MULTI_DOMAIN_CAPABILITY 0xFFA0C58B ++#define OID_CUSTOM_GPIO2_MODE 0xFFA0C58C ++#define OID_CUSTOM_CONTINUOUS_POLL 0xFFA0C58D ++#define OID_CUSTOM_DISABLE_BEACON_DETECTION 0xFFA0C58E ++ ++/* CR1460, WPS privacy bit check disable */ ++#define OID_CUSTOM_DISABLE_PRIVACY_CHECK 0xFFA0C600 ++ ++/* Precedent OIDs */ ++#define OID_CUSTOM_MCR_RW 0xFFA0C801 ++#define OID_CUSTOM_EEPROM_RW 0xFFA0C803 ++#define OID_CUSTOM_SW_CTRL 0xFFA0C805 ++#define OID_CUSTOM_MEM_DUMP 0xFFA0C807 ++ ++/* RF Test specific OIDs */ ++#define OID_CUSTOM_TEST_MODE 0xFFA0C901 ++#define OID_CUSTOM_TEST_RX_STATUS 0xFFA0C903 ++#define OID_CUSTOM_TEST_TX_STATUS 0xFFA0C905 ++#define OID_CUSTOM_ABORT_TEST_MODE 0xFFA0C906 ++#define OID_CUSTOM_MTK_WIFI_TEST 0xFFA0C911 ++ ++/* BWCS */ ++#define OID_CUSTOM_BWCS_CMD 0xFFA0C931 ++#define OID_CUSTOM_SINGLE_ANTENNA 0xFFA0C932 ++#define OID_CUSTOM_SET_PTA 0xFFA0C933 ++ ++/* NVRAM */ ++#define OID_CUSTOM_MTK_NVRAM_RW 0xFFA0C941 ++#define OID_CUSTOM_CFG_SRC_TYPE 0xFFA0C942 ++#define OID_CUSTOM_EEPROM_TYPE 0xFFA0C943 ++ ++#if CFG_SUPPORT_WAPI ++#define OID_802_11_WAPI_MODE 0xFFA0CA00 ++#define OID_802_11_WAPI_ASSOC_INFO 0xFFA0CA01 ++#define OID_802_11_SET_WAPI_KEY 0xFFA0CA02 ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++#define OID_802_11_WSC_ASSOC_INFO 0xFFA0CB00 ++#endif ++ ++/* Define magic key of test mode (Don't change it for future compatibity) */ ++#define PRIV_CMD_TEST_MAGIC_KEY 2011 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* NIC BBCR configuration entry structure */ ++typedef struct _PRIV_CONFIG_ENTRY { ++ UINT_8 ucOffset; ++ UINT_8 ucValue; ++} PRIV_CONFIG_ENTRY, *PPRIV_CONFIG_ENTRY; ++ ++typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC_REQ) (IN PVOID prAdapter, ++ IN OUT PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); ++ ++typedef enum _ENUM_OID_METHOD_T { ++ ENUM_OID_GLUE_ONLY, ++ ENUM_OID_GLUE_EXTENSION, ++ ENUM_OID_DRIVER_CORE ++} ENUM_OID_METHOD_T, *P_ENUM_OID_METHOD_T; ++ ++/* OID set/query processing entry */ ++typedef struct _WLAN_REQ_ENTRY { ++ UINT_32 rOid; /* OID */ ++ PUINT_8 pucOidName; /* OID name text */ ++ BOOLEAN fgQryBufLenChecking; ++ BOOLEAN fgSetBufLenChecking; ++ ENUM_OID_METHOD_T eOidMethod; ++ UINT_32 u4InfoBufLen; ++ PFN_OID_HANDLER_FUNC_REQ pfOidQueryHandler; /* PFN_OID_HANDLER_FUNC */ ++ PFN_OID_HANDLER_FUNC_REQ pfOidSetHandler; /* PFN_OID_HANDLER_FUNC */ ++} WLAN_REQ_ENTRY, *P_WLAN_REQ_ENTRY; ++ ++typedef struct _NDIS_TRANSPORT_STRUCT { ++ UINT_32 ndisOidCmd; ++ UINT_32 inNdisOidlength; ++ UINT_32 outNdisOidLength; ++ UINT_8 ndisOidContent[16]; ++} NDIS_TRANSPORT_STRUCT, *P_NDIS_TRANSPORT_STRUCT; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++int ++priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++int ++priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++int ++priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen); ++ ++UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac); ++ ++int ++priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int priv_support_ioctl(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); ++ ++int priv_support_driver_cmd(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); ++ ++INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_WEXT_PRIV_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c +new file mode 100644 +index 000000000000..fba854cfd68e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c +@@ -0,0 +1,542 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/platform.c#1 ++*/ ++ ++/*! \file "platform.c" ++ \brief This file including the protocol layer privacy function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer security setting from wlan_oid.c and for parse.c and ++ rsn.c and nic_privacy.c ++ ++*/ ++ ++/* ++** Log: platform.c ++ * ++ * 11 14 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 09 13 2011 jeffrey.chang ++ * [WCXRP00000983] [MT6620][Wi-Fi Driver] invalid pointer casting causes kernel panic during p2p connection ++ * fix the pointer casting ++ * ++ * 06 29 2011 george.huang ++ * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 ++ * . ++ * ++ * 06 28 2011 george.huang ++ * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 ++ * remove un-used code ++ * ++ * 05 11 2011 jeffrey.chang ++ * NULL ++ * fix build error ++ * ++ * 05 09 2011 jeffrey.chang ++ * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change ++ * support ARP filter through kernel notifier ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 18 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * remove early suspend functions ++ * ++ * 03 03 2011 jeffrey.chang ++ * NULL ++ * add the ARP filter callback ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 02 01 2011 cp.wu ++ * [WCXRP00000413] [MT6620 Wi-Fi][Driver] Merge 1103 changes on NVRAM file path change to DaVinci main trunk and V1.1 ++ * branch ++ * upon Jason Zhang(NVRAM owner)'s change, ALPS has modified its NVRAM storage from /nvram/... to /data/nvram/... ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++** ++*/ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "gl_os.h" ++ ++#ifndef CONFIG_X86 ++#if defined(CONFIG_HAS_EARLY_SUSPEND) ++#include ++#endif ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define WIFI_NVRAM_FILE_NAME "/etc/firmware/nvram/WIFI" ++#define WIFI_NVRAM_CUSTOM_NAME "/etc/firmware/nvram/WIFI_CUSTOM" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static int netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) ++{ ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net_device *prDev = ifa->ifa_dev->dev; ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (prDev == NULL) { ++ DBGLOG(REQ, ERROR, "netdev_event: device is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ DBGLOG(REQ, INFO, "netdev_event, addr=%x, notification=%lx, dev_name=%s\n", ++ ifa->ifa_address, notification, prDev->name); ++ if (!fgIsUnderSuspend) ++ return NOTIFY_DONE; ++ if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { ++ DBGLOG(REQ, WARN, "netdev_event: not our device\n"); ++ return NOTIFY_DONE; ++ } ++#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ { ++ /* printk(KERN_INFO "[netdev_event] IPV4_DAD is unlock now!!\n"); */ ++ prGlueInfo->fgIsDad = FALSE; ++ } ++#endif ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ if (prGlueInfo == NULL) { ++ DBGLOG(REQ, ERROR, "netdev_event: prGlueInfo is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ ASSERT(prGlueInfo); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(REQ, INFO, "ip is not available.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ DBGLOG(REQ, INFO, "ip is %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(REQ, INFO, "ipv6 is not available.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(REQ, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++ ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) ++ /* u4NumIPv6++; */ ++#endif ++ ++ /* here we can compare the dev with other network's netdev to */ ++ /* set the proper arp filter */ ++ /* */ ++ /* IMPORTANT: please make sure if the context can sleep, if the context can't sleep */ ++ /* we should schedule a kernel thread to do this for us */ ++ ++ /* <7> set up the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++ UINT_8 aucBuf[32] = { 0 }; ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) aucBuf; ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; ++#else ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#endif ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++#if 0 ++ kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); ++#else ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ prParamNetAddr = ++ (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); ++#endif ++ } ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip6)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(aucBuf)); ++ ++ DBGLOG(REQ, INFO, "kalIoctl (0x%p, 0x%p)\n", prGlueInfo, prParamNetAddrList); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "set HW pattern filter fail 0x%x\n", rStatus); ++ } ++ ++ return NOTIFY_DONE; ++ ++} ++ ++/* #if CFG_SUPPORT_HOTSPOT_2_0 */ ++#if 0 ++static int net6dev_event(struct notifier_block *nb, unsigned long notification, void *ptr) ++{ ++ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; ++ struct net_device *prDev = ifa->idev->dev; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (prDev == NULL) { ++ DBGLOG(REQ, INFO, "net6dev_event: device is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { ++ DBGLOG(REQ, INFO, "net6dev_event: xxx\n"); ++ return NOTIFY_DONE; ++ } ++ ++ if (strncmp(prDev->name, "p2p", 3) == 0) { ++ /* because we store the address of prGlueInfo in p2p's private date of net device */ ++ /* *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ } else { /* wlan0 */ ++ prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); ++ } ++ ++ if (prGlueInfo == NULL) { ++ DBGLOG(REQ, INFO, "netdev_event: prGlueInfo is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ /* printk(KERN_INFO "[net6dev_event] IPV6_DAD is unlock now!!\n"); */ ++ prGlueInfo->fgIs6Dad = FALSE; ++ ++ return NOTIFY_DONE; ++} ++#endif ++ ++static struct notifier_block inetaddr_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ ++static struct notifier_block inet6addr_notifier = { ++ .notifier_call = net6dev_event, ++}; ++#endif ++ ++void wlanRegisterNotifier(void) ++{ ++ register_inetaddr_notifier(&inetaddr_notifier); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* register_inet6addr_notifier(&inet6addr_notifier); */ ++#endif ++} ++ ++/* EXPORT_SYMBOL(wlanRegisterNotifier); */ ++ ++void wlanUnregisterNotifier(void) ++{ ++ unregister_inetaddr_notifier(&inetaddr_notifier); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* unregister_inetaddr_notifier(&inet6addr_notifier); */ ++#endif ++} ++ ++/* EXPORT_SYMBOL(wlanUnregisterNotifier); */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Utility function for reading data from files on NVRAM-FS ++* ++* \param[in] ++* filename ++* len ++* offset ++* \param[out] ++* buf ++* \return ++* actual length of data being read ++*/ ++/*----------------------------------------------------------------------------*/ ++static int nvram_read(char *filename, char *buf, ssize_t len, int offset) ++{ ++#if CFG_SUPPORT_NVRAM ++ struct file *fd; ++ int retLen = -1; ++ ++ mm_segment_t old_fs = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ fd = filp_open(filename, O_RDONLY, 0644); ++ ++ if (IS_ERR(fd)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to open!!\n"); ++ return -1; ++ } ++ ++ do { ++ //if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) { ++ if ( fd->f_op == NULL ) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : file can not be read!!\n"); ++ break; ++ } ++ ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to seek!!\n"); ++ break; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ retLen = vfs_read(fd, buf, len, &fd->f_pos); ++ ++ } while (FALSE); ++ ++ filp_close(fd, NULL); ++ ++ set_fs(old_fs); ++ ++ return retLen; ++ ++#else /* !CFG_SUPPORT_NVRAM */ ++ ++ return -EIO; ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Utility function for writing data to files on NVRAM-FS ++* ++* \param[in] ++* filename ++* buf ++* len ++* offset ++* \return ++* actual length of data being written ++*/ ++/*----------------------------------------------------------------------------*/ ++static int nvram_write(char *filename, char *buf, ssize_t len, int offset) ++{ ++#if CFG_SUPPORT_NVRAM ++ struct file *fd; ++ int retLen = -1; ++ ++ mm_segment_t old_fs = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ fd = filp_open(filename, O_WRONLY | O_CREAT, 0644); ++ ++ if (IS_ERR(fd)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to open!!\n"); ++ return -1; ++ } ++ ++ do { ++ if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : file can not be write!!\n"); ++ break; ++ } ++ /* End of if */ ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to seek!!\n"); ++ break; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ retLen = vfs_write(fd, buf, len, &fd->f_pos); ++ ++ } while (FALSE); ++ ++ filp_close(fd, NULL); ++ ++ set_fs(old_fs); ++ ++ return retLen; ++ ++#else /* !CFG_SUPPORT_NVRAMS */ ++ ++ return -EIO; ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief API for reading data on NVRAM ++* ++* \param[in] ++* prGlueInfo ++* u4Offset ++* \param[out] ++* pu2Data ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data) ++{ ++ if (pu2Data == NULL) ++ return FALSE; ++ ++ if (nvram_read(WIFI_NVRAM_FILE_NAME, ++ (char *)pu2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { ++ return FALSE; ++ } else { ++ return TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief API for writing data on NVRAM ++* ++* \param[in] ++* prGlueInfo ++* u4Offset ++* u2Data ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, UINT_32 u4Offset, UINT_16 u2Data) ++{ ++ if (nvram_write(WIFI_NVRAM_FILE_NAME, ++ (char *)&u2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { ++ return FALSE; ++ } else { ++ return TRUE; ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h +new file mode 100644 +index 000000000000..9444d415c60e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h +@@ -0,0 +1,190 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/version.h#1 ++*/ ++ ++/*! \file "version.h" ++ \brief Driver's version definition ++ ++*/ ++ ++/* ++** Log: version.h ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.1.1. ++ * ++ * 08 26 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.9.. ++ * ++ * 08 23 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.8. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * correct typo. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * for building MT6628 Win32 driver environment ++ * ++ * 08 03 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.7. ++ * ++ * 07 24 2011 puff.wen ++ * NULL ++ * [MT5931][Beta 5]Change the version number to v0.2.2.0 ++ * ++ * 06 01 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.6.. ++ * ++ * 05 09 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.5.. ++ * ++ * 04 19 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.4. ++ * ++ * 04 18 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.3. ++ * ++ * 03 25 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.2. ++ * ++ * 03 21 2011 chinglan.wang ++ * NULL ++ * Change the version number to 2.0.0.1. ++ * ++ * 03 18 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.0. ++ * ++ * 02 11 2011 chinglan.wang ++ * NULL ++ * Change to the version 1.2.0.2. ++ * ++ * 02 10 2011 chinglan.wang ++ * NULL ++ * Change the version to 1.2.0.1. ++ * ++ * 02 08 2011 cp.wu ++ * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number ++ * change version number to v1.2.0.0 for preparing v1.2 software package release. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * [WINDDK] build system changes for MT5931 ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-12-14 14:10:55 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-17 22:41:00 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-13 16:20:33 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:27:13 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _VERSION_H ++#define _VERSION_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#ifndef NIC_AUTHOR ++#define NIC_AUTHOR "NIC_AUTHOR" ++#endif ++#ifndef NIC_DESC ++#define NIC_DESC "NIC_DESC" ++#endif ++ ++#ifndef NIC_NAME ++#if defined(MT6620) ++#define NIC_NAME "MT6620" ++#define NIC_DEVICE_ID "MT6620" ++#define NIC_DEVICE_ID_LOW "mt6620" ++#elif defined(MT6628) ++#define NIC_NAME "MT6582" ++#define NIC_DEVICE_ID "MT6582" ++#define NIC_DEVICE_ID_LOW "mt6582" ++#endif ++#endif ++ ++/* NIC driver information */ ++#define NIC_VENDOR "MediaTek Inc." ++#define NIC_VENDOR_OUI {0x00, 0x0C, 0xE7} ++ ++#if defined(MT6620) ++#define NIC_PRODUCT_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter" ++#define NIC_DRIVER_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter Driver" ++#elif defined(MT6628) ++/* #define NIC_PRODUCT_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter" */ ++/* #define NIC_DRIVER_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter Driver" */ ++#define NIC_PRODUCT_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter" ++#define NIC_DRIVER_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter Driver" ++#endif ++ ++/* Define our driver version */ ++#define NIC_DRIVER_MAJOR_VERSION 2 ++#define NIC_DRIVER_MINOR_VERSION 0 ++#define NIC_DRIVER_VERSION (2, 0, 1, 1) ++#define NIC_DRIVER_VERSION_STRING "2.0.1.1" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _VERSION_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/aee.h b/drivers/misc/mediatek/include/mt-plat/aee.h +new file mode 100644 +index 000000000000..d1cf448dafb2 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/aee.h +@@ -0,0 +1,284 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#if !defined(__AEE_H__) ++#define __AEE_H__ ++ ++#include ++#include ++ ++#define AEE_MODULE_NAME_LENGTH 64 ++#define AEE_PROCESS_NAME_LENGTH 256 ++#define AEE_BACKTRACE_LENGTH 3072 ++ ++typedef enum { ++ AE_DEFECT_FATAL, ++ AE_DEFECT_EXCEPTION, ++ AE_DEFECT_WARNING, ++ AE_DEFECT_REMINDING, ++ AE_DEFECT_ATTR_END ++} AE_DEFECT_ATTR; ++ ++typedef enum { ++ AE_KE = 0, /* Fatal Exception */ ++ AE_HWT, ++ AE_REBOOT, ++ AE_NE, ++ AE_JE, ++ AE_SWT, ++ AE_EE, ++ AE_EXP_ERR_END, ++ AE_ANR, /* Error or Warning or Defect */ ++ AE_RESMON, ++ AE_MODEM_WARNING, ++ AE_WTF, ++ AE_WRN_ERR_END, ++ AE_MANUAL, /* Manual Raise */ ++ AE_EXP_CLASS_END, ++ ++ AE_KERNEL_PROBLEM_REPORT = 1000, ++ AE_SYSTEM_JAVA_DEFECT, ++ AE_SYSTEM_NATIVE_DEFECT, ++ AE_MANUAL_MRDUMP_KEY, ++} AE_EXP_CLASS; /* General Program Exception Class */ ++ ++typedef enum { ++ AEE_REBOOT_MODE_NORMAL = 0, ++ AEE_REBOOT_MODE_KERNEL_OOPS, ++ AEE_REBOOT_MODE_KERNEL_PANIC, ++ AEE_REBOOT_MODE_NESTED_EXCEPTION, ++ AEE_REBOOT_MODE_WDT, ++ AEE_REBOOT_MODE_MANUAL_KDUMP, ++} AEE_REBOOT_MODE; ++ ++#define AEE_SZ_SYMBOL_L 140 ++#define AEE_SZ_SYMBOL_S 80 ++struct aee_bt_frame { ++ __u64 pc; ++ __u64 lr; ++ __u32 pad[5]; ++ char pc_symbol[AEE_SZ_SYMBOL_S]; /* Now we use different symbol length for PC &LR */ ++ char lr_symbol[AEE_SZ_SYMBOL_L]; ++}; ++ ++/* aee_process_info struct should strictly small than ipanic_buffer, now 4KB */ ++struct aee_process_info { ++ char process_path[AEE_PROCESS_NAME_LENGTH]; ++ char backtrace[AEE_BACKTRACE_LENGTH]; ++ struct aee_bt_frame ke_frame; ++}; ++ ++struct aee_process_bt { ++ __u32 pid; ++ __u32 nr_entries; ++ struct aee_bt_frame *entries; ++}; ++ ++ ++struct aee_thread_reg { ++ pid_t tid; ++ struct pt_regs regs; ++}; ++ ++struct aee_user_thread_stack { ++ pid_t tid; ++ int StackLength; ++ unsigned char *Userthread_Stack; /*8k stack ,define to char only for match 64bit/32bit*/ ++}; ++ ++struct aee_user_thread_maps { ++ pid_t tid; ++ int Userthread_mapsLength; ++ unsigned char *Userthread_maps; /*8k stack ,define to char only for match 64bit/32bit*/ ++}; ++ ++ ++ ++struct aee_oops { ++ struct list_head list; ++ AE_DEFECT_ATTR attr; ++ AE_EXP_CLASS clazz; ++ ++ char module[AEE_MODULE_NAME_LENGTH]; ++ /* consist with struct aee_process_info */ ++ char process_path[AEE_PROCESS_NAME_LENGTH]; ++ char backtrace[AEE_BACKTRACE_LENGTH]; ++ struct aee_bt_frame ke_frame; ++ ++ char *detail; ++ int detail_len; ++ ++ char *console; ++ int console_len; ++ ++ char *android_main; ++ int android_main_len; ++ char *android_radio; ++ int android_radio_len; ++ char *android_system; ++ int android_system_len; ++ ++ char *userspace_info; ++ int userspace_info_len; ++ ++ char *mmprofile; ++ int mmprofile_len; ++ ++ char *mini_rdump; ++ int mini_rdump_len; ++ ++ ++ struct aee_user_thread_stack userthread_stack; ++ struct aee_thread_reg userthread_reg; ++ struct aee_user_thread_maps userthread_maps; ++ ++ int dump_option; ++}; ++ ++struct aee_kernel_api { ++ void (*kernel_reportAPI)(const AE_DEFECT_ATTR attr, const int db_opt, const char *module, ++ const char *msg); ++ void (*md_exception)(const char *assert_type, const int *log, int log_size, const int *phy, ++ int phy_size, const char *detail, const int db_opt); ++ void (*md32_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++ void (*combo_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++ void (*scp_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++}; ++ ++void aee_sram_printk(const char *fmt, ...); ++int aee_nested_printf(const char *fmt, ...); ++void aee_wdt_irq_info(void); ++void aee_wdt_fiq_info(void *arg, void *regs, void *svc_sp); ++void aee_trigger_kdb(void); ++struct aee_oops *aee_oops_create(AE_DEFECT_ATTR attr, AE_EXP_CLASS clazz, const char *module); ++void aee_oops_set_backtrace(struct aee_oops *oops, const char *backtrace); ++void aee_oops_set_process_path(struct aee_oops *oops, const char *process_path); ++void aee_oops_free(struct aee_oops *oops); ++/* powerkey press,modules use bits */ ++#define AE_WDT_Powerkey_DEVICE_PATH "/dev/kick_powerkey" ++#define WDT_SETBY_DEFAULT (0) ++#define WDT_SETBY_Backlight (1<<0) ++#define WDT_SETBY_Display (1<<1) ++#define WDT_SETBY_SF (1<<2) ++#define WDT_SETBY_PM (1<<3) ++#define WDT_SETBY_WMS_DISABLE_PWK_MONITOR (0xAEEAEE00) ++#define WDT_SETBY_WMS_ENABLE_PWK_MONITOR (0xAEEAEE01) ++#define WDT_PWK_HANG_FORCE_HWT (0xAEE0FFFF) ++ ++/* QHQ RT Monitor */ ++#define AEEIOCTL_RT_MON_Kick _IOR('p', 0x0A, int) ++#define AE_WDT_DEVICE_PATH "/dev/RT_Monitor" ++/* QHQ RT Monitor end */ ++ ++/* DB dump option bits, set relative bit to 1 to include related file in db */ ++#define DB_OPT_DEFAULT (0) ++#define DB_OPT_FTRACE (1<<0) ++#define DB_OPT_PRINTK_TOO_MUCH (1<<1) ++#define DB_OPT_NE_JBT_TRACES (1<<2) ++#define DB_OPT_SWT_JBT_TRACES (1<<3) ++#define DB_OPT_VM_TRACES (1<<4) ++#define DB_OPT_DUMPSYS_ACTIVITY (1<<5) ++#define DB_OPT_DUMPSYS_WINDOW (1<<6) ++#define DB_OPT_DUMPSYS_GFXINFO (1<<7) ++#define DB_OPT_DUMPSYS_SURFACEFLINGER (1<<8) ++#define DB_OPT_DISPLAY_HANG_DUMP (1<<9) ++#define DB_OPT_LOW_MEMORY_KILLER (1<<10) ++#define DB_OPT_PROC_MEM (1<<11) ++#define DB_OPT_FS_IO_LOG (1<<12) ++#define DB_OPT_PROCESS_COREDUMP (1<<13) ++#define DB_OPT_VM_HPROF (1<<14) ++#define DB_OPT_PROCMEM (1<<15) ++#define DB_OPT_DUMPSYS_INPUT (1<<16) ++#define DB_OPT_MMPROFILE_BUFFER (1<<17) ++#define DB_OPT_BINDER_INFO (1<<18) ++#define DB_OPT_WCN_ISSUE_INFO (1<<19) ++#define DB_OPT_DUMMY_DUMP (1<<20) ++#define DB_OPT_PID_MEMORY_INFO (1<<21) ++#define DB_OPT_VM_OOME_HPROF (1<<22) ++#define DB_OPT_PID_SMAPS (1<<23) ++#define DB_OPT_PROC_CMDQ_INFO (1<<24) ++#define DB_OPT_PROC_USKTRK (1<<25) ++#define DB_OPT_SF_RTT_DUMP (1<<26) ++#define DB_OPT_PAGETYPE_INFO (1<<27) ++#define DB_OPT_DUMPSYS_PROCSTATS (1<<28) ++#define DB_OPT_DUMP_DISPLAY (1<<29) ++#define DB_OPT_NATIVE_BACKTRACE (1<<30) ++#define DB_OPT_AARCH64 (1<<31) ++ ++#define aee_kernel_exception(module, msg...) \ ++ aee_kernel_exception_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_warning(module, msg...) \ ++ aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_reminding(module, msg...) \ ++ aee_kernel_reminding_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_dal_show(msg) \ ++ aee_kernel_dal_api(__FILE__, __LINE__, msg) ++ ++#define aed_md_exception(log, log_size, phy, phy_size, detail) \ ++ aed_md_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_md32_exception(log, log_size, phy, phy_size, detail) \ ++ aed_md32_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_scp_exception(log, log_size, phy, phy_size, detail) \ ++ aed_scp_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_combo_exception(log, log_size, phy, phy_size, detail) \ ++ aed_combo_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++ ++void aee_kernel_exception_api(const char *file, const int line, const int db_opt, ++ const char *module, const char *msg, ...); ++void aee_kernel_warning_api(const char *file, const int line, const int db_opt, const char *module, ++ const char *msg, ...); ++void aee_kernel_reminding_api(const char *file, const int line, const int db_opt, ++ const char *module, const char *msg, ...); ++void aee_kernel_dal_api(const char *file, const int line, const char *msg); ++ ++void aed_md_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_md32_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_scp_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_combo_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++ ++void aee_kernel_wdt_kick_Powkey_api(const char *module, int msg); ++int aee_kernel_wdt_kick_api(int kinterval); ++void aee_powerkey_notify_press(unsigned long pressed); ++int aee_kernel_Powerkey_is_press(void); ++ ++void ipanic_recursive_ke(struct pt_regs *regs, struct pt_regs *excp_regs, int cpu); ++ ++/* QHQ RT Monitor */ ++void aee_kernel_RT_Monitor_api(int lParam); ++/* QHQ RT Monitor end */ ++void mt_fiq_printf(const char *fmt, ...); ++void aee_register_api(struct aee_kernel_api *aee_api); ++int aee_in_nested_panic(void); ++void aee_stop_nested_panic(struct pt_regs *regs); ++void aee_wdt_dump_info(void); ++void aee_wdt_printf(const char *fmt, ...); ++ ++void aee_fiq_ipi_cpu_stop(void *arg, void *regs, void *svc_sp); ++ ++#if defined(CONFIG_MTK_AEE_DRAM_CONSOLE) ++void aee_dram_console_reserve_memory(void); ++#else ++static inline void aee_dram_console_reserve_memory(void) ++{ ++} ++#endif ++ ++extern void *aee_excp_regs; /* To store latest exception, in case of stack corruption */ ++#endif /* __AEE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mrdump.h b/drivers/misc/mediatek/include/mt-plat/mrdump.h +new file mode 100644 +index 000000000000..b6bdfa2f7617 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mrdump.h +@@ -0,0 +1,204 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#if !defined(__MRDUMP_H__) ++#define __MRDUMP_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __aarch64__ ++#define reg_pc pc ++#define reg_lr regs[30] ++#define reg_sp sp ++#define reg_fp regs[29] ++#else ++#define reg_pc ARM_pc ++#define reg_lr ARM_lr ++#define reg_sp ARM_sp ++#define reg_ip ARM_ip ++#define reg_fp ARM_fp ++#endif ++ ++#define MRDUMP_CPU_MAX 16 ++ ++#define MRDUMP_DEV_NULL 0 ++#define MRDUMP_DEV_SDCARD 1 ++#define MRDUMP_DEV_EMMC 2 ++ ++#define MRDUMP_FS_NULL 0 ++#define MRDUMP_FS_VFAT 1 ++#define MRDUMP_FS_EXT4 2 ++ ++#define MRDUMP_GO_DUMP "MRDUMP04" ++ ++typedef uint32_t arm32_gregset_t[18]; ++typedef uint64_t aarch64_gregset_t[34]; ++ ++struct mrdump_crash_record { ++ int reboot_mode; ++ ++ char msg[128]; ++ char backtrace[512]; ++ ++ uint32_t fault_cpu; ++ ++ union { ++ arm32_gregset_t arm32_regs; ++ aarch64_gregset_t aarch64_regs; ++ } cpu_regs[MRDUMP_CPU_MAX]; ++}; ++ ++struct mrdump_machdesc { ++ uint32_t crc; ++ ++ uint32_t output_device; ++ ++ uint32_t nr_cpus; ++ ++ uint64_t page_offset; ++ uint64_t high_memory; ++ ++ uint64_t vmalloc_start; ++ uint64_t vmalloc_end; ++ ++ uint64_t modules_start; ++ uint64_t modules_end; ++ ++ uint64_t phys_offset; ++ uint64_t master_page_table; ++ ++ uint32_t output_fstype; ++ uint32_t output_lbaooo; ++}; ++ ++struct mrdump_control_block { ++ char sig[8]; ++ ++ struct mrdump_machdesc machdesc; ++ struct mrdump_crash_record crash_record; ++}; ++ ++/* NOTE!! any change to this struct should be compatible in aed */ ++struct mrdump_mini_reg_desc { ++ unsigned long reg; /* register value */ ++ unsigned long kstart; /* start kernel addr of memory dump */ ++ unsigned long kend; /* end kernel addr of memory dump */ ++ unsigned long pos; /* next pos to dump */ ++ int valid; /* 1: valid regiser, 0: invalid regiser */ ++ int pad; /* reserved */ ++ loff_t offset; /* offset in buffer */ ++}; ++ ++/* it should always be smaller than MRDUMP_MINI_HEADER_SIZE */ ++struct mrdump_mini_header { ++ struct mrdump_mini_reg_desc reg_desc[ELF_NGREG]; ++}; ++ ++#define MRDUMP_MINI_NR_SECTION 60 ++#define MRDUMP_MINI_SECTION_SIZE (32 * 1024) ++#define NT_IPANIC_MISC 4095 ++#define MRDUMP_MINI_NR_MISC 20 ++ ++struct mrdump_mini_elf_misc { ++ unsigned long vaddr; ++ unsigned long paddr; ++ unsigned long start; ++ unsigned long size; ++}; ++ ++#define NOTE_NAME_SHORT 12 ++#define NOTE_NAME_LONG 20 ++ ++struct mrdump_mini_elf_psinfo { ++ struct elf_note note; ++ char name[NOTE_NAME_SHORT]; ++ struct elf_prpsinfo data; ++}; ++ ++struct mrdump_mini_elf_prstatus { ++ struct elf_note note; ++ char name[NOTE_NAME_SHORT]; ++ struct elf_prstatus data; ++}; ++ ++struct mrdump_mini_elf_note { ++ struct elf_note note; ++ char name[NOTE_NAME_LONG]; ++ struct mrdump_mini_elf_misc data; ++}; ++ ++struct mrdump_mini_elf_header { ++ struct elfhdr ehdr; ++ struct elf_phdr phdrs[MRDUMP_MINI_NR_SECTION]; ++ struct mrdump_mini_elf_psinfo psinfo; ++ struct mrdump_mini_elf_prstatus prstatus[NR_CPUS + 1]; ++ struct mrdump_mini_elf_note misc[MRDUMP_MINI_NR_MISC]; ++}; ++ ++typedef struct mrdump_rsvmem_block { ++ phys_addr_t start_addr; ++ phys_addr_t size; ++} mrdump_rsvmem_block_t; ++ ++ ++#define MRDUMP_MINI_HEADER_SIZE ALIGN(sizeof(struct mrdump_mini_elf_header), PAGE_SIZE) ++#define MRDUMP_MINI_DATA_SIZE (MRDUMP_MINI_NR_SECTION * MRDUMP_MINI_SECTION_SIZE) ++#define MRDUMP_MINI_BUF_SIZE (MRDUMP_MINI_HEADER_SIZE + MRDUMP_MINI_DATA_SIZE) ++ ++#ifdef CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR ++#define MRDUMP_MINI_BUF_PADDR (CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR + 0xf0000) ++#else ++#define MRDUMP_MINI_BUF_PADDR 0 ++#endif ++ ++int mrdump_init(void); ++void __mrdump_create_oops_dump(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, ++ ...); ++#if defined(CONFIG_MTK_AEE_IPANIC) ++void mrdump_rsvmem(void); ++#else ++static inline void mrdump_rsvmem(void) ++{ ++} ++#endif ++ ++#if defined(CONFIG_MTK_AEE_MRDUMP) ++void aee_kdump_reboot(AEE_REBOOT_MODE, const char *msg, ...); ++#else ++static inline void aee_kdump_reboot(AEE_REBOOT_MODE reboot_mode, const char *msg, ...) ++{ ++} ++#endif ++ ++typedef int (*mrdump_write)(void *buf, int off, int len, int encrypt); ++#if defined(CONFIG_MTK_AEE_IPANIC) ++int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, ++ loff_t sd_offset, const char *msg, va_list ap); ++void mrdump_mini_reserve_memory(void); ++#else ++static inline int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, ++ loff_t sd_offset, const char *msg, va_list ap) ++{ ++ return 0; ++} ++ ++static inline void mrdump_mini_reserve_memory(void) ++{ ++} ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h +new file mode 100644 +index 000000000000..1b60f007d0fd +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++ ++#ifndef _MT8167_THERMAL_H ++#define _MT8167_THERMAL_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "sync_write.h" ++ ++extern void __iomem *thermal_base; ++extern void __iomem *auxadc_ts_base; ++extern void __iomem *apmixed_base; ++extern void __iomem *pericfg_base; ++extern int auxadc_ts_phy_base; ++extern int apmixed_phy_base; ++ ++#define THERM_CTRL_BASE_2 thermal_base ++#define AUXADC_BASE_2 auxadc_ts_base ++#define PERICFG_BASE pericfg_base ++#define APMIXED_BASE_2 apmixed_base ++ ++#define MT6752_EVB_BUILD_PASS /*Jerry fix build error FIX_ME*/ ++ ++/******************************************************************************* ++* AUXADC Register Definition ++******************************************************************************/ ++/*AUXADC_BASE: 0xF1001000 from Vincent Liang 2014.5.8*/ ++ ++#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /*yes, 0x11003000*/ ++#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) ++#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) ++#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) ++#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) ++/*#define AUXADC_CON3_V (AUXADC_BASE_2 + 0x014)*/ ++#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) ++#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) ++#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) ++#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) ++#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) ++#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) ++#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) ++#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) ++#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) ++#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) ++#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) ++#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) ++#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) ++ ++#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) ++#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) ++#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) ++#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) ++#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) ++/*#define AUXADC_CON3_P (auxadc_ts_phy_base + 0x014)*/ ++#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) ++#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) ++#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) ++#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) ++#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) ++#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) ++#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) ++#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) ++#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) ++#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) ++#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) ++#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) ++ ++#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) ++ ++/******************************************************************************* ++* Peripheral Configuration Register Definition ++******************************************************************************/ ++/*#define PERICFG_BASE (0x10002000)*/ ++#define PERI_GLOBALCON_RST0 (pericfg_base + 0x000) /*yes, 0x10002000*/ ++/******************************************************************************* ++ * APMixedSys Configuration Register Definition ++ ******************************************************************************/ ++#define TS_CON0 (APMIXED_BASE_2 + 0x600) /*yes 0x10209000*/ ++#define TS_CON1 (APMIXED_BASE_2 + 0x604) ++#define TS_CON0_TM (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ ++#define TS_CON1_TM (APMIXED_BASE_2 + 0x604) ++#define TS_CON0_P (apmixed_phy_base + 0x600) ++#define TS_CON1_P (apmixed_phy_base + 0x604) ++ ++/******************************************************************************* ++ * Thermal Controller Register Definition ++ ******************************************************************************/ ++#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /*yes 0x1100B000*/ ++#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) ++#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) ++#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) ++#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) ++#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) ++#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) ++#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) ++#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) ++#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) ++#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) ++#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) ++#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) ++#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) ++#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) ++#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) ++#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) ++#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) ++#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) ++#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) ++#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) ++ ++#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) ++#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) ++#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) ++#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) ++#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) ++#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) ++#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) ++#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) ++#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) ++#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) ++#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) ++#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) ++#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) ++#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) ++#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) ++#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) ++#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) ++#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) ++#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) ++ ++#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) ++#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) ++#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) ++#define TEMPIMMD3 (THERM_CTRL_BASE_2 + 0x0BC) ++ ++ ++#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) ++#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) ++#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) ++#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) ++ ++#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) ++#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) ++#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) ++#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) ++ ++#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) ++#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) ++#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) ++#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) ++#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) ++#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) ++#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) ++#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /*Only for DE debug*/ ++#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) ++#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) ++#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) ++#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) ++#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) ++ ++ ++#define PTPSPARE0_P (thermal_phy_base + 0x420) ++#define PTPSPARE1_P (thermal_phy_base + 0x424) ++#define PTPSPARE2_P (thermal_phy_base + 0x428) ++#define PTPSPARE3_P (thermal_phy_base + 0x42C) ++ ++/******************************************************************************* ++ * Thermal Controller Register Mask Definition ++ ******************************************************************************/ ++#define THERMAL_ENABLE_SEN0 0x1 ++#define THERMAL_ENABLE_SEN1 0x2 ++#define THERMAL_ENABLE_SEN2 0x4 ++#define THERMAL_MONCTL0_MASK 0x00000007 ++ ++#define THERMAL_PUNT_MASK 0x00000FFF ++#define THERMAL_FSINTVL_MASK 0x03FF0000 ++#define THERMAL_SPINTVL_MASK 0x000003FF ++#define THERMAL_MON_INT_MASK 0x0007FFFF ++ ++#define THERMAL_MON_CINTSTS0 0x000001 ++#define THERMAL_MON_HINTSTS0 0x000002 ++#define THERMAL_MON_LOINTSTS0 0x000004 ++#define THERMAL_MON_HOINTSTS0 0x000008 ++#define THERMAL_MON_NHINTSTS0 0x000010 ++#define THERMAL_MON_CINTSTS1 0x000020 ++#define THERMAL_MON_HINTSTS1 0x000040 ++#define THERMAL_MON_LOINTSTS1 0x000080 ++#define THERMAL_MON_HOINTSTS1 0x000100 ++#define THERMAL_MON_NHINTSTS1 0x000200 ++#define THERMAL_MON_CINTSTS2 0x000400 ++#define THERMAL_MON_HINTSTS2 0x000800 ++#define THERMAL_MON_LOINTSTS2 0x001000 ++#define THERMAL_MON_HOINTSTS2 0x002000 ++#define THERMAL_MON_NHINTSTS2 0x004000 ++#define THERMAL_MON_TOINTSTS 0x008000 ++#define THERMAL_MON_IMMDINTSTS0 0x010000 ++#define THERMAL_MON_IMMDINTSTS1 0x020000 ++#define THERMAL_MON_IMMDINTSTS2 0x040000 ++#define THERMAL_MON_FILTINTSTS0 0x080000 ++#define THERMAL_MON_FILTINTSTS1 0x100000 ++#define THERMAL_MON_FILTINTSTS2 0x200000 ++ ++ ++#define THERMAL_tri_SPM_State0 0x20000000 ++#define THERMAL_tri_SPM_State1 0x40000000 ++#define THERMAL_tri_SPM_State2 0x80000000 ++ ++ ++#define THERMAL_MSRCTL0_MASK 0x00000007 ++#define THERMAL_MSRCTL1_MASK 0x00000038 ++#define THERMAL_MSRCTL2_MASK 0x000001C0 ++ ++enum thermal_sensor_name { ++ THERMAL_SENSOR1 = 0,/*TS_MCU1*/ ++ THERMAL_SENSOR_NUM ++}; ++ ++enum thermal_bank_name { ++ THERMAL_BANK0 = 0, /*CPU (TS_MCU1) (TS1)*/ ++ THERMAL_BANK_NUM ++}; ++ ++struct TS_SVS { ++ unsigned int ts_MTS; ++ unsigned int ts_BTS; ++}; ++ ++struct mtk_gpu_power_info { ++ unsigned int gpufreq_khz; ++ unsigned int gpufreq_power; ++}; ++ ++/* svs driver need this function */ ++extern void get_thermal_slope_intercept(struct TS_SVS *ts_info, enum thermal_bank_name ts_bank); ++ ++/* mtk_thermal_platform.c need this */ ++extern void set_taklking_flag(bool flag); ++ ++#define THERMAL_WRAP_WR32(val, addr) mt_reg_sync_writel((val), ((void *)addr)) ++ ++enum MTK_THERMAL_SENSOR_CPU_ID_MET { ++ MTK_THERMAL_SENSOR_TS1 = 0, ++ MTK_THERMAL_SENSOR_TS2, ++ MTK_THERMAL_SENSOR_TS3, ++ MTK_THERMAL_SENSOR_TS4, ++ MTK_THERMAL_SENSOR_TSABB, ++ ++ ATM_CPU_LIMIT, ++ ATM_GPU_LIMIT, ++ ++ MTK_THERMAL_SENSOR_CPU_COUNT ++}; ++ ++extern int tscpu_get_cpu_temp_met(enum MTK_THERMAL_SENSOR_CPU_ID_MET id); ++extern int mtk_gpufreq_register(struct mtk_gpu_power_info *freqs, int num); ++ ++typedef void (*met_thermalsampler_funcMET)(void); ++void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); ++ ++void tscpu_start_thermal(void); ++void tscpu_stop_thermal(void); ++void tscpu_cancel_thermal_timer(void); ++void tscpu_start_thermal_timer(void); ++int mtkts_bts_get_hw_temp(void); ++ ++extern int get_immediate_ts1_wrap(void); ++extern int get_immediate_ts2_wrap(void); ++extern int get_immediate_ts3_wrap(void); ++ ++extern int is_cpu_power_unlimit(void); /* in mtk_ts_cpu.c */ ++extern int is_cpu_power_min(void); /* in mtk_ts_cpu.c */ ++extern int get_cpu_target_tj(void); ++extern int get_cpu_target_offset(void); ++ ++extern int mtktscpu_debug_log; ++ ++#endif ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h +new file mode 100644 +index 000000000000..142a007805b9 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright (C) 2011 MediaTek, Inc. ++ * ++ * Author: Holmes Chiou ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef __MT_FREQHOPPING_H__ ++#define __MT_FREQHOPPING_H__ ++ ++#define MT_FHPLL_MAX 6 ++#define MT_SSC_NR_PREDEFINE_SETTING 10 /* TODO: is 10 a good number ? */ ++ ++#define MEMPLL_SSC 0 ++#define MAINPLL_SSC 1 ++ ++#define FHTAG "[FH]" ++ ++#define VERBOSE_DEBUG 0 ++ ++#if VERBOSE_DEBUG ++#define FH_MSG(fmt, args...) \ ++ pr_debug(FHTAG""fmt" <- %s(): L<%d> PID<%s><%d>\n", ##args, __func__, __LINE__, current->comm, current->pid) ++#else ++ ++#if 1 /* log level is 6 xlog */ ++#define FH_MSG(fmt, args...) pr_debug(fmt, ##args) ++#else /* log level is 4 (printk) */ ++#define FH_MSG(fmt, args...) printk(FHTAG""fmt"\n", ##args) ++#endif ++ ++#endif ++ ++/* not support at mt2701 yet */ ++/* DRAMC */ ++#define FULLY_VERSION_FHCTL 0 ++ ++enum FH_FH_STATUS { ++ FH_FH_DISABLE = 0, ++ FH_FH_ENABLE_SSC, ++ FH_FH_ENABLE_DFH, ++ FH_FH_ENABLE_DVFS, ++}; ++ ++enum FH_PLL_STATUS { ++ FH_PLL_DISABLE = 0, ++ FH_PLL_ENABLE = 1 ++}; ++ ++/* TODO: FREQ_MODIFIED should not be here */ ++/* FH_PLL_STATUS_FREQ_MODIFIED = 3 */ ++ ++ ++enum FH_CMD { ++ FH_CMD_ENABLE = 1, ++ FH_CMD_DISABLE, ++ FH_CMD_ENABLE_USR_DEFINED, ++ FH_CMD_DISABLE_USR_DEFINED, ++ FH_CMD_INTERNAL_MAX_CMD, ++/* TODO: do we need these cmds ? ++ * FH_CMD_PLL_ENABLE, ++ * FH_CMD_PLL_DISABLE, ++ * FH_CMD_EXT_ALL_FULL_RANGE_CMD, ++ * FH_CMD_EXT_ALL_HALF_RANGE_CMD, ++ * FH_CMD_EXT_DISABLE_ALL_CMD, ++ * FH_CMD_EXT_DESIGNATED_PLL_FULL_RANGE_CMD, ++ * FH_CMD_EXT_DESIGNATED_PLL_AND_SETTING_CMD ++*/ ++}; ++ ++/* ++ * enum FH_OPCODE{ ++ * FH_OPCODE_ENABLE_WITH_ID = 1, ++ * FH_OPCODE_ENABLE_WITHOUT_ID, ++ * FH_OPCODE_DISABLE, ++ * }; ++*/ ++ ++enum FH_PLL_ID { ++ MT658X_FH_MINIMUMM_PLL = 0, ++ MT658X_FH_ARM_PLL = MT658X_FH_MINIMUMM_PLL, ++ MT658X_FH_MAIN_PLL = 1, ++ MT658X_FH_MEM_PLL = 2, ++ MT658X_FH_MSDC_PLL = 3, ++ MT658X_FH_MM_PLL = 4, /* MT658X_FH_TVD_PLL = 4, */ ++ MT658X_FH_VENC_PLL = 5, /* MT658X_FH_LVDS_PLL = 5, */ ++ /* 8127 FHCTL MB */ ++ MT658X_FH_TVD_PLL = 6, /* MT658X_FH_TVD_PLL = 6, */ ++ MT658X_FH_MAXIMUMM_PLL = MT658X_FH_TVD_PLL, ++ /* 8127 FHCTL ME */ ++ MT658X_FH_PLL_TOTAL_NUM ++}; ++ ++/* keep track the status of each PLL */ ++/* TODO: do we need another "uint mode" for Dynamic FH */ ++typedef struct { ++ unsigned int fh_status; ++ unsigned int pll_status; ++ unsigned int setting_id; ++ unsigned int curr_freq; ++ unsigned int user_defined; ++} fh_pll_t; ++ ++ ++/* Record the owner of enable freq hopping <==TBD */ ++struct freqhopping_pll { ++ union { ++ int mt_pll[MT_FHPLL_MAX]; ++ struct { ++ int mt_arm_fhpll; ++ int mt_main_fhpll; ++ int mt_mem_fhpll; ++ int mt_msdc_fhpll; ++ int mt_mm_fhpll; ++ int mt_venc_fhpll; ++ }; ++ }; ++}; ++ ++struct freqhopping_ssc { ++ unsigned int freq; ++ unsigned int dt; ++ unsigned int df; ++ unsigned int upbnd; ++ unsigned int lowbnd; ++ unsigned int dds; ++}; ++ ++struct freqhopping_ioctl { ++ unsigned int pll_id; ++ struct freqhopping_ssc ssc_setting; /* used only when user-define */ ++ int result; ++}; ++ ++int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable); ++void mt_freqhopping_init(void); ++void mt_freqhopping_pll_init(void); ++int mt_h2l_mempll(void); ++int mt_l2h_mempll(void); ++int mt_h2l_dvfs_mempll(void); ++int mt_l2h_dvfs_mempll(void); ++int mt_dfs_armpll(unsigned int current_freq, unsigned int target_freq); ++int mt_is_support_DFS_mode(void); ++void mt_fh_popod_save(void); ++void mt_fh_popod_restore(void); ++int mt_fh_dram_overclock(int clk); ++int mt_fh_get_dramc(void); ++unsigned int mt_get_emi_freq(void); ++ ++#endif /* !__MT_FREQHOPPING_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h +new file mode 100644 +index 000000000000..0c049db9aa97 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2015 MediaTek Inc. ++ * ++ * 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. ++ */ ++ ++#include ++ ++#define STA_POWER_DOWN 0 ++#define STA_POWER_ON 1 ++ ++/* ++ * 1. for CPU MTCMOS: CPU0, CPU1, CPU2, CPU3, DBG0, CPU4, CPU5, CPU6, CPU7, DBG1, CPUSYS1 ++ * 2. call spm_mtcmos_cpu_lock/unlock() before/after any operations ++ */ ++extern int spm_mtcmos_cpu_init(void); ++extern void spm_mtcmos_cpu_lock(unsigned long *flags); ++extern void spm_mtcmos_cpu_unlock(unsigned long *flags); ++extern int spm_mtcmos_ctrl_cpu(unsigned int cpu, int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu0(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu1(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu2(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu3(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu4(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu5(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu6(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu7(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpusys0(int state, int chkWfiBeforePdn); ++extern bool spm_cpusys0_can_power_down(void); +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h +new file mode 100644 +index 000000000000..28176b3cd9af +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2015 MediaTek Inc. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_BOOT_SHARE_PAGE_H__ ++#define __MTK_BOOT_SHARE_PAGE_H__ ++ ++#define BOOT_SHARE_BASE (0xC0002000) /* address in linux kernel */ ++#define BOOT_SHARE_SIZE (0x1000) /* page size 4K bytes */ ++ ++#define BOOT_SHARE_MAGIC (0x4545544D) /* MTEE */ ++ ++/* Memory map & defines for boot share page */ ++/* ++ * Note: ++ * 1. BOOT_SHARE_XXXXX_OFST is the address offset related to BOOT_SHARE_BASE ++ */ ++#define BOOT_SHARE_MAGIC1_OFST (0) ++#define BOOT_SHARE_MAGIC1_SIZE (4) ++ ++#define BOOT_SHARE_DEV_INFO_OFST (BOOT_SHARE_MAGIC1_OFST+BOOT_SHARE_MAGIC1_SIZE) ++#define BOOT_SHARE_DEV_INFO_SIZE (16) ++ ++#define BOOT_SHARE_HOTPLUG_OFST (1008) /* 16 bytes for hotplug/jump-reg */ ++#define BOOT_SHARE_HOTPLUG_SIZE (32) ++ ++#define BOOT_SHARE_MAGIC2_OFST (4092) ++#define BOOT_SHARE_MAGIC2_SIZE (4) ++ ++#endif /* __MTK_BOOT_SHARE_PAGE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h +new file mode 100644 +index 000000000000..eefdaad4aaa5 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h +@@ -0,0 +1,301 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#ifndef _MT8127_THERMAL_H ++#define _MT8127_THERMAL_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "mt-plat/sync_write.h" ++#include ++ ++/* #include */ ++/* #include "../../../../../thermal/mt8127/inc/mt_gpufreq.h" */ ++ ++#if 1 ++extern void __iomem *thermal_base; ++extern void __iomem *auxadc_ts_base; ++extern void __iomem *pericfg_base; ++extern void __iomem *apmixed_ts_base; ++ ++extern int mtktscpu_limited_dmips; ++ ++void __attribute__ ((weak)) mt_gpufreq_thermal_protect(unsigned int limited_power) { ++} ++ ++unsigned int __attribute__ ((weak)) mt_gpufreq_get_cur_freq(void) { ++ return 0; ++} ++ ++u32 __attribute__ ((weak)) get_devinfo_with_index(u32 index) { ++ return 0; ++} ++ ++extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); ++extern int IMM_IsAdcInitReady(void); ++extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); ++extern int thermal_phy_base; ++extern int auxadc_ts_phy_base; ++extern int apmixed_phy_base; ++extern int pericfg_phy_base; ++ ++/* extern int last_abb_t; */ ++/* extern int last_CPU2_t; */ ++extern int get_immediate_temp2_wrap(void); ++extern void mtkts_dump_cali_info(void); ++extern u32 get_devinfo_with_index(u32 index); ++extern int bts_cur_temp; ++ ++#define THERM_CTRL_BASE_2 thermal_base ++#define AUXADC_BASE_2 auxadc_ts_base ++#define PERICFG_BASE_2 pericfg_base ++#define APMIXED_BASE_2 apmixed_ts_base ++#endif ++ ++/******************************************************************************* ++ * AUXADC Register Definition ++ ******************************************************************************/ ++#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /* yes, 0x11001000 */ ++#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) ++#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) ++#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) ++#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) ++#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) ++#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) ++#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) ++#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) ++#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) ++#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) ++#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) ++#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) ++#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) ++#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) ++#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) ++#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) ++#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) ++#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) ++#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) ++#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) ++#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) ++#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) ++#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) ++#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) ++#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) ++#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) ++#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) ++#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) ++#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) ++#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) ++#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) ++#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) ++#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) ++#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) ++#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) ++ ++/******************************************************************************* ++ * Peripheral Configuration Register Definition ++ ******************************************************************************/ ++#define PERI_GLOBALCON_RST0 (PERICFG_BASE_2 + 0x000) /* yes, 0x10003000 */ ++ ++/******************************************************************************* ++ * APMixedSys Configuration Register Definition ++ ******************************************************************************/ ++#define TS_CON0 (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ ++#define TS_CON1 (APMIXED_BASE_2 + 0x604) ++/******************************************************************************* ++ * Thermal Controller Register Definition ++ ******************************************************************************/ ++#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /* yes 0x1100B000 */ ++#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) ++#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) ++#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) ++#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) ++#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) ++#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) ++#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) ++#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) ++#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) ++#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) ++#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) ++#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) ++#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) ++#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) ++#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) ++#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) ++#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) ++#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) ++#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) ++#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) ++ ++#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) ++#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) ++#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) ++#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) ++#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) ++#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) ++#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) ++#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) ++#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) ++#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) ++#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) ++#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) ++#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) ++#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) ++#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) ++#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) ++#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) ++#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) ++#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) ++ ++#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) ++#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) ++#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) ++ ++#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) ++#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) ++#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) ++#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) ++ ++#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) ++#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) ++#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) ++#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) ++ ++#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) ++#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) ++#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) ++#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) ++#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) ++#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) ++#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) ++#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /* Only for DE debug */ ++#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) ++#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) ++#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) ++#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) ++#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) ++ ++/******************************************************************************* ++ * Thermal Controller Register Mask Definition ++ ******************************************************************************/ ++#define THERMAL_ENABLE_SEN0 0x1 ++#define THERMAL_ENABLE_SEN1 0x2 ++#define THERMAL_ENABLE_SEN2 0x4 ++#define THERMAL_MONCTL0_MASK 0x00000007 ++ ++#define THERMAL_PUNT_MASK 0x00000FFF ++#define THERMAL_FSINTVL_MASK 0x03FF0000 ++#define THERMAL_SPINTVL_MASK 0x000003FF ++#define THERMAL_MON_INT_MASK 0x0007FFFF ++ ++#define THERMAL_MON_CINTSTS0 0x000001 ++#define THERMAL_MON_HINTSTS0 0x000002 ++#define THERMAL_MON_LOINTSTS0 0x000004 ++#define THERMAL_MON_HOINTSTS0 0x000008 ++#define THERMAL_MON_NHINTSTS0 0x000010 ++#define THERMAL_MON_CINTSTS1 0x000020 ++#define THERMAL_MON_HINTSTS1 0x000040 ++#define THERMAL_MON_LOINTSTS1 0x000080 ++#define THERMAL_MON_HOINTSTS1 0x000100 ++#define THERMAL_MON_NHINTSTS1 0x000200 ++#define THERMAL_MON_CINTSTS2 0x000400 ++#define THERMAL_MON_HINTSTS2 0x000800 ++#define THERMAL_MON_LOINTSTS2 0x001000 ++#define THERMAL_MON_HOINTSTS2 0x002000 ++#define THERMAL_MON_NHINTSTS2 0x004000 ++#define THERMAL_MON_TOINTSTS 0x008000 ++#define THERMAL_MON_IMMDINTSTS0 0x010000 ++#define THERMAL_MON_IMMDINTSTS1 0x020000 ++#define THERMAL_MON_IMMDINTSTS2 0x040000 ++#define THERMAL_MON_FILTINTSTS0 0x080000 ++#define THERMAL_MON_FILTINTSTS1 0x100000 ++#define THERMAL_MON_FILTINTSTS2 0x200000 ++ ++ ++#define THERMAL_tri_SPM_State0 0x20000000 ++#define THERMAL_tri_SPM_State1 0x40000000 ++#define THERMAL_tri_SPM_State2 0x80000000 ++ ++ ++#define THERMAL_MSRCTL0_MASK 0x00000007 ++#define THERMAL_MSRCTL1_MASK 0x00000038 ++#define THERMAL_MSRCTL2_MASK 0x000001C0 ++ ++/* extern int thermal_one_shot_handler(int times); */ ++ ++typedef enum { ++ THERMAL_SENSOR1 = 0, /* TS1 */ ++ THERMAL_SENSOR_NUM ++} thermal_sensor_name; ++ ++struct TS_PTPOD { ++ unsigned int ts_MTS; ++ unsigned int ts_BTS; ++}; ++ ++extern void get_thermal_slope_intercept(struct TS_PTPOD *ts_info); ++extern void set_taklking_flag(bool flag); ++extern int tscpu_get_cpu_temp(void); ++ ++/*5 thermal sensors*/ ++typedef enum { ++ MTK_THERMAL_SENSOR_TS1 = 0, ++ ATM_CPU_LIMIT, ++ ATM_GPU_LIMIT, ++ MTK_THERMAL_SENSOR_CPU_COUNT ++} MTK_THERMAL_SENSOR_CPU_ID_MET; ++ ++struct mtk_cpu_power_info { ++ unsigned int cpufreq_khz; ++ unsigned int cpufreq_ncpu; ++ unsigned int cpufreq_power; ++}; ++extern int mtk_cpufreq_register(struct mtk_cpu_power_info *freqs, int num); ++ ++extern int tscpu_get_cpu_temp_met(MTK_THERMAL_SENSOR_CPU_ID_MET id); ++ ++ ++typedef void (*met_thermalsampler_funcMET) (void); ++void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); ++ ++void tscpu_start_thermal(void); ++void tscpu_stop_thermal(void); ++void tscpu_cancel_thermal_timer(void); ++void tscpu_start_thermal_timer(void); ++int mtkts_AP_get_hw_temp(void); ++ ++extern int amddulthro_backoff(int level); ++/* extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); */ ++/* extern int IMM_IsAdcInitReady(void); */ ++extern int get_immediate_temp2_wrap(void); ++extern void mtkts_dump_cali_info(void); ++extern unsigned int read_dram_temperature(void); ++extern int mtk_thermal_get_cpu_load_sum(void); ++ ++/********************************** ++ * Power table struct for thermal ++ **********************************/ ++struct mt_gpufreq_power_table_info { ++ unsigned int gpufreq_khz; ++ unsigned int gpufreq_volt; ++ unsigned int gpufreq_power; ++}; ++ ++extern int mtk_gpufreq_register(struct mt_gpufreq_power_table_info *freqs, int num); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mt_sched.h b/drivers/misc/mediatek/include/mt-plat/mt_sched.h +new file mode 100644 +index 000000000000..71206f080548 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt_sched.h +@@ -0,0 +1,34 @@ ++/* ++* Copyright (C) 2016 MediaTek Inc. ++* ++* 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. ++* ++* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++*/ ++ ++#ifdef CONFIG_MTK_SCHED_RQAVG_US ++/* ++ * @cpu: cpu id ++ * @reset: reset the statistic start time after this time query ++ * @use_maxfreq: caculate cpu loading with max cpu max frequency ++ * return: cpu loading as percentage (0~100) ++ */ ++extern unsigned int sched_get_percpu_load(int cpu, bool reset, bool use_maxfreq); ++ ++/* ++ * return: heavy task(loading>90%) number in the system ++ */ ++extern unsigned int sched_get_nr_heavy_task(void); ++ ++/* ++ * @threshold: heavy task loading threshold (0~1023) ++ * return: heavy task(loading>threshold) number in the system ++ */ ++extern unsigned int sched_get_nr_heavy_task_by_threshold(unsigned int threshold); ++#endif /* CONFIG_MTK_SCHED_RQAVG_US */ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_io.h b/drivers/misc/mediatek/include/mt-plat/mtk_io.h +new file mode 100644 +index 000000000000..de17db505d3e +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_io.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MT_IO_H__ ++#define __MT_IO_H__ ++ ++/* only for arm64 */ ++#ifdef CONFIG_ARM64 ++#define IOMEM(a) ((void __force __iomem *)((a))) ++#endif ++ ++#endif /* !__MT_IO_H__ */ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h +new file mode 100644 +index 000000000000..d679c5a1ce73 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_LPAE_H__ ++#define __MTK_LPAE_H__ ++#ifdef CONFIG_MTK_LM_MODE ++ ++#include ++ ++#define INTERAL_MAPPING_OFFSET (0x40000000) ++#define INTERAL_MAPPING_LIMIT (INTERAL_MAPPING_OFFSET + 0x80000000) ++ ++#define MT_OVERFLOW_ADDR_START 0x100000000ULL ++ ++unsigned int __attribute__((weak)) enable_4G(void) ++{ ++ return 0; ++} ++ ++/* For HW modules which support 33-bit address setting */ ++#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) \ ++ do { \ ++ ret = 0; \ ++ if (enable_4G()) {\ ++ if (((phys_addr_t)phy_addr < MT_OVERFLOW_ADDR_START)\ ++ && (((phys_addr_t)phy_addr + size) >= MT_OVERFLOW_ADDR_START)) \ ++ ret = MT_OVERFLOW_ADDR_START - phy_addr; \ ++ } \ ++ } while (0) \ ++ ++/* For SPM and MD32 only in ROME */ ++#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) \ ++ do { \ ++ if (enable_4G()) {\ ++ if (phy_addr >= INTERAL_MAPPING_OFFSET && phy_addr < INTERAL_MAPPING_LIMIT) \ ++ phy_addr += INTERAL_MAPPING_OFFSET; \ ++ } \ ++ } while (0)\ ++ ++#else /* !CONFIG_ARM_LPAE */ ++ ++#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) ++#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) ++#define MT_OVERFLOW_ADDR_START 0 ++ ++static inline unsigned int enable_4G(void) ++{ ++ return 0; ++} ++ ++#endif ++#endif /*!__MTK_LPAE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h +new file mode 100644 +index 000000000000..7baafc4329bf +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_MDM_MONITOR_H ++#define _MTK_MDM_MONITOR_H ++ ++struct md_info { ++ char *attribute; ++ int value; ++ char *unit; ++ int invalid_value; ++ int index; ++}; ++ ++extern ++int mtk_mdm_get_md_info(struct md_info **p_inf, int *size); ++ ++extern ++int mtk_mdm_start_query(void); ++ ++extern ++int mtk_mdm_stop_query(void); ++ ++extern ++int mtk_mdm_set_signal_period(int second); ++ ++extern ++int mtk_mdm_set_md1_signal_period(int second); ++ ++extern ++int mtk_mdm_set_md2_signal_period(int second); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h +new file mode 100644 +index 000000000000..8f20f38b75d6 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_PLATFORM_DEBUG_H__ ++#define __MTK_PLATFORM_DEBUG_H__ ++ ++#ifdef CONFIG_MTK_PLAT_SRAM_FLAG ++/* plat_sram_flag */ ++extern int set_sram_flag_lastpc_valid(void); ++extern int set_sram_flag_dfd_valid(void); ++extern int set_sram_flag_etb_user(unsigned int etb_id, unsigned int user_id); ++#endif ++ ++#ifdef CONFIG_MTK_DFD_INTERNAL_DUMP ++extern int dfd_setup(void); ++#endif ++ ++#endif /* __MTK_PLATFORM_DEBUG_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h +new file mode 100644 +index 000000000000..3a94a1bbcd24 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h +@@ -0,0 +1,162 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_RAM_CONSOLE_H__ ++#define __MTK_RAM_CONSOLE_H__ ++ ++#include ++#include ++ ++typedef enum { ++ AEE_FIQ_STEP_FIQ_ISR_BASE = 1, ++ AEE_FIQ_STEP_WDT_FIQ_INFO = 4, ++ AEE_FIQ_STEP_WDT_FIQ_STACK, ++ AEE_FIQ_STEP_WDT_FIQ_LOOP, ++ AEE_FIQ_STEP_WDT_FIQ_DONE, ++ AEE_FIQ_STEP_WDT_IRQ_INFO = 8, ++ AEE_FIQ_STEP_WDT_IRQ_KICK, ++ AEE_FIQ_STEP_WDT_IRQ_SMP_STOP, ++ AEE_FIQ_STEP_WDT_IRQ_TIME, ++ AEE_FIQ_STEP_WDT_IRQ_STACK, ++ AEE_FIQ_STEP_WDT_IRQ_GIC, ++ AEE_FIQ_STEP_WDT_IRQ_LOCALTIMER, ++ AEE_FIQ_STEP_WDT_IRQ_IDLE, ++ AEE_FIQ_STEP_WDT_IRQ_SCHED, ++ AEE_FIQ_STEP_WDT_IRQ_DONE, ++ AEE_FIQ_STEP_KE_WDT_INFO = 20, ++ AEE_FIQ_STEP_KE_WDT_PERCPU, ++ AEE_FIQ_STEP_KE_WDT_LOG, ++ AEE_FIQ_STEP_KE_SCHED_DEBUG, ++ AEE_FIQ_STEP_KE_EINT_DEBUG, ++ AEE_FIQ_STEP_KE_WDT_DONE, ++ AEE_FIQ_STEP_KE_IPANIC_DIE = 32, ++ AEE_FIQ_STEP_KE_IPANIC_START, ++ AEE_FIQ_STEP_KE_IPANIC_OOP_HEADER, ++ AEE_FIQ_STEP_KE_IPANIC_DETAIL, ++ AEE_FIQ_STEP_KE_IPANIC_CONSOLE, ++ AEE_FIQ_STEP_KE_IPANIC_USERSPACE, ++ AEE_FIQ_STEP_KE_IPANIC_ANDROID, ++ AEE_FIQ_STEP_KE_IPANIC_MMPROFILE, ++ AEE_FIQ_STEP_KE_IPANIC_HEADER, ++ AEE_FIQ_STEP_KE_IPANIC_DONE, ++ AEE_FIQ_STEP_KE_NESTED_PANIC = 64, ++} AEE_FIQ_STEP_NUM; ++ ++#ifdef CONFIG_MTK_RAM_CONSOLE ++extern int aee_rr_curr_fiq_step(void); ++extern void aee_rr_rec_fiq_step(u8 i); ++extern void aee_rr_rec_reboot_mode(u8 mode); ++extern void aee_rr_rec_kdump_params(void *params); ++extern void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j); ++extern void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j); ++extern void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm); ++extern void aee_sram_fiq_log(const char *msg); ++extern void ram_console_write(struct console *console, const char *s, unsigned int count); ++extern void aee_sram_fiq_save_bin(const char *buffer, size_t len); ++extern void aee_rr_rec_hotplug_footprint(int cpu, u8 fp); ++extern void aee_rr_rec_hotplug_cpu_event(u8 val); ++extern void aee_rr_rec_hotplug_cb_index(u8 val); ++extern void aee_rr_rec_hotplug_cb_fp(unsigned long val); ++#ifdef CONFIG_MTK_EMMC_SUPPORT ++extern void last_kmsg_store_to_emmc(void); ++#endif ++ ++#else ++static inline void aee_rr_rec_hotplug_footprint(int cpu, u8 fp) ++{ ++} ++static inline void aee_rr_rec_hotplug_cpu_event(u8 val) ++{ ++} ++static inline void aee_rr_rec_hotplug_cb_index(u8 val) ++{ ++} ++static inline void aee_rr_rec_hotplug_cb_fp(unsigned long val) ++{ ++} ++static inline int aee_rr_curr_fiq_step(void) ++{ ++ return 0; ++} ++ ++static inline void aee_rr_rec_fiq_step(u8 i) ++{ ++} ++ ++static inline unsigned int aee_rr_curr_exp_type(void) ++{ ++ return 0; ++} ++ ++static inline void aee_rr_rec_exp_type(unsigned int type) ++{ ++} ++ ++static inline void aee_rr_rec_reboot_mode(u8 mode) ++{ ++} ++ ++static inline void aee_rr_rec_kdump_params(void *params) ++{ ++} ++ ++static inline void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j) ++{ ++} ++ ++static inline void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j) ++{ ++} ++ ++static inline void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm) ++{ ++} ++ ++static inline void aee_sram_fiq_log(const char *msg) ++{ ++} ++ ++static inline void ram_console_write(struct console *console, const char *s, unsigned int count) ++{ ++} ++ ++static inline void aee_sram_fiq_save_bin(unsigned char *buffer, size_t len) ++{ ++} ++ ++#ifdef CONFIG_MTK_EMMC_SUPPORT ++static inline void last_kmsg_store_to_emmc(void) ++{ ++} ++#endif ++ ++#endif /* CONFIG_MTK_RAM_CONSOLE */ ++ ++#ifdef CONFIG_MTK_AEE_IPANIC ++extern int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size); ++extern int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, ++ char **buf, struct pstore_info *psi); ++#else ++static inline int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size) ++{ ++ return 0; ++} ++ ++static inline int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, ++ char **buf, struct pstore_info *psi) ++{ ++ return 0; ++} ++#endif /* CONFIG_MTK_AEE_IPANIC */ ++ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h +new file mode 100644 +index 000000000000..2181e9989593 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef MTK_RTC_H ++#define MTK_RTC_H ++ ++#include ++#include ++#include ++ ++typedef enum { ++ RTC_GPIO_USER_WIFI = 8, ++ RTC_GPIO_USER_GPS = 9, ++ RTC_GPIO_USER_BT = 10, ++ RTC_GPIO_USER_FM = 11, ++ RTC_GPIO_USER_PMIC = 12, ++} rtc_gpio_user_t; ++ ++#ifdef CONFIG_MTK_RTC ++ ++/* ++ * NOTE: ++ * 1. RTC_GPIO always exports 32K enabled by some user even if the phone is powered off ++ */ ++ ++extern unsigned long rtc_read_hw_time(void); ++extern void rtc_gpio_enable_32k(rtc_gpio_user_t user); ++extern void rtc_gpio_disable_32k(rtc_gpio_user_t user); ++extern bool rtc_gpio_32k_status(void); ++ ++/* for AUDIOPLL (deprecated) */ ++extern void rtc_enable_abb_32k(void); ++extern void rtc_disable_abb_32k(void); ++ ++/* NOTE: used in Sleep driver to workaround Vrtc-Vore level shifter issue */ ++extern void rtc_enable_writeif(void); ++extern void rtc_disable_writeif(void); ++ ++extern void rtc_mark_recovery(void); ++#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) ++extern void rtc_mark_kpoc(void); ++#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ ++extern void rtc_mark_fast(void); ++extern u16 rtc_rdwr_uart_bits(u16 *val); ++extern void rtc_bbpu_power_down(void); ++extern void rtc_read_pwron_alarm(struct rtc_wkalrm *alm); ++extern int get_rtc_spare_fg_value(void); ++extern int set_rtc_spare_fg_value(int val); ++extern void rtc_irq_handler(void); ++extern bool crystal_exist_status(void); ++extern void mt_power_off(void); ++#else/*ifdef CONFIG_MTK_RTC*/ ++#define rtc_read_hw_time() ({ 0; }) ++#define rtc_gpio_enable_32k(user) do {} while (0) ++#define rtc_gpio_disable_32k(user) do {} while (0) ++#define rtc_gpio_32k_status() do {} while (0) ++#define rtc_enable_abb_32k() do {} while (0) ++#define rtc_disable_abb_32k() do {} while (0) ++#define rtc_enable_writeif() do {} while (0) ++#define rtc_disable_writeif() do {} while (0) ++#define rtc_mark_recovery() do {} while (0) ++#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) ++#define rtc_mark_kpoc() do {} while (0) ++#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ ++#define rtc_mark_fast() do {} while (0) ++#define rtc_rdwr_uart_bits(val) ({ 0; }) ++#define rtc_bbpu_power_down() do {} while (0) ++#define rtc_read_pwron_alarm(alm) do {} while (0) ++#define get_rtc_spare_fg_value() ({ 0; }) ++#define set_rtc_spare_fg_value(val) ({ 0; }) ++#define rtc_irq_handler() do {} while (0) ++#define crystal_exist_status() do {} while (0) ++__weak void mt_power_off(void); ++#endif/*ifdef CONFIG_MTK_RTC*/ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h +new file mode 100644 +index 000000000000..eac6bc713c98 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (c) 2009 Travis Geiselbrecht ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, ++ * including without limitation the rights to use, copy, modify, merge, ++ * publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, ++ * subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _MTK_THERMAL_EXT_CONTROL_H ++#define _MTK_THERMAL_EXT_CONTROL_H ++ ++#define THERMAL_MD32_IPI_MSG_BASE 0x1F00 ++#define THERMAL_AP_IPI_MSG_BASE 0x2F00 ++ ++typedef enum { ++ THERMAL_AP_IPI_MSG_SET_TZ_THRESHOLD = THERMAL_AP_IPI_MSG_BASE, ++ THERMAL_AP_IPI_MSG_MD32_START, ++ ++ THERMAL_MD32_IPI_MSG_READY = THERMAL_MD32_IPI_MSG_BASE, ++ THERMAL_MD32_IPI_MSG_MD32_START_ACK, ++ THERMAL_MD32_IPI_MSG_REACH_THRESHOLD, ++} thermal_ipi_msg_id; ++ ++typedef enum { ++/* MTK_THERMAL_EXT_SENSOR_CPU = 0, */ ++ MTK_THERMAL_EXT_SENSOR_ABB = 0, ++ MTK_THERMAL_EXT_SENSOR_PMIC, ++ MTK_THERMAL_EXT_SENSOR_BATTERY, ++ MTK_THERMAL_EXT_SENSOR_COUNT ++} MTK_THERMAL_EXT_SENSOR_ID; ++ ++typedef struct { ++ int id; /* id of this tz */ ++ int polling_delay; /* polling delay of this tz */ ++ long high_trip_point; /* high threshold of this tz */ ++ long low_trip_point; /* low threshold of this tz */ ++} thermal_zone_data; ++ ++typedef struct { ++ int id; /* id of this tz */ ++ long high_trip_point; /* high threshold of this tz */ ++ long low_trip_point; /* low threshold of this tz */ ++ long temperature; /* Current temperature gotten from TS */ ++} thermal_zone_status; ++ ++typedef struct { ++ short id; ++ union { ++ thermal_zone_data tz; ++ thermal_zone_status tz_status; ++ } data; ++} thermal_ipi_msg; ++ ++#endif /* _MTK_THERMAL_EXT_CONTROL_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h +new file mode 100644 +index 000000000000..7903b49dc419 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_THERMAL_MONITOR_H ++#define _MTK_THERMAL_MONITOR_H ++ ++#include ++ ++/* ++ * MTK_THERMAL_WRAPPER_BYPASS = 1 (use original Linux Thermal API) ++ * MTK_THERMAL_WRAPPER_BYPASS = 0 (use MTK Thermal API Monitor) ++ */ ++#define MTK_THERMAL_WRAPPER_BYPASS 0 ++ ++#if MTK_THERMAL_WRAPPER_BYPASS ++/* Original LTF API */ ++#define mtk_thermal_zone_device_register thermal_zone_device_register ++#define mtk_thermal_zone_device_unregister thermal_zone_device_unregister ++#define mtk_thermal_cooling_device_unregister thermal_cooling_device_unregister ++#define mtk_thermal_cooling_device_register thermal_cooling_device_register ++#define mtk_thermal_zone_bind_cooling_device thermal_zone_bind_cooling_device ++ ++#else ++ ++struct thermal_cooling_device_ops_extra { ++ int (*set_cur_temp)(struct thermal_cooling_device *, unsigned long); ++}; ++ ++extern ++struct thermal_zone_device *mtk_thermal_zone_device_register_wrapper ++(char *type, int trips, void *devdata, const struct thermal_zone_device_ops *ops, ++int tc1, int tc2, int passive_delay, int polling_delay); ++ ++extern ++void mtk_thermal_zone_device_unregister_wrapper(struct thermal_zone_device *tz); ++ ++extern ++struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper ++(char *type, void *devdata, const struct thermal_cooling_device_ops *ops); ++ ++extern ++struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper_extra ++(char *type, void *devdata, const struct thermal_cooling_device_ops *ops, ++const struct thermal_cooling_device_ops_extra *ops_ext); ++ ++extern ++int mtk_thermal_cooling_device_add_exit_point ++(struct thermal_cooling_device *cdev, int exit_point); ++ ++extern ++void mtk_thermal_cooling_device_unregister_wrapper(struct thermal_cooling_device *cdev); ++ ++extern int mtk_thermal_zone_bind_cooling_device_wrapper ++(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev); ++ ++extern int mtk_thermal_zone_bind_trigger_trip(struct thermal_zone_device *tz, int trip, int mode); ++#define mtk_thermal_zone_device_register mtk_thermal_zone_device_register_wrapper ++#define mtk_thermal_zone_device_unregister mtk_thermal_zone_device_unregister_wrapper ++#define mtk_thermal_cooling_device_unregister mtk_thermal_cooling_device_unregister_wrapper ++#define mtk_thermal_cooling_device_register mtk_thermal_cooling_device_register_wrapper ++#define mtk_thermal_zone_bind_cooling_device mtk_thermal_zone_bind_cooling_device_wrapper ++ ++#endif ++ ++typedef enum { ++ MTK_THERMAL_SENSOR_CPU = 0, ++ MTK_THERMAL_SENSOR_ABB, ++ MTK_THERMAL_SENSOR_PMIC, ++ MTK_THERMAL_SENSOR_BATTERY, ++ MTK_THERMAL_SENSOR_MD1, ++ MTK_THERMAL_SENSOR_MD2, ++ MTK_THERMAL_SENSOR_WIFI, ++ MTK_THERMAL_SENSOR_BATTERY2, ++ MTK_THERMAL_SENSOR_BUCK, ++ MTK_THERMAL_SENSOR_AP, ++ MTK_THERMAL_SENSOR_PCB1, ++ MTK_THERMAL_SENSOR_PCB2, ++ MTK_THERMAL_SENSOR_SKIN, ++ MTK_THERMAL_SENSOR_XTAL, ++ MTK_THERMAL_SENSOR_MD_PA, ++ ++ MTK_THERMAL_SENSOR_COUNT ++} MTK_THERMAL_SENSOR_ID; ++ ++extern int mtk_thermal_get_temp(MTK_THERMAL_SENSOR_ID id); ++extern struct proc_dir_entry *mtk_thermal_get_proc_drv_therm_dir_entry(void); ++ ++/* This API function is implemented in mediatek/kernel/drivers/leds/leds.c */ ++extern int setMaxbrightness(int max_level, int enable); ++ ++extern void machine_power_off(void); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h +new file mode 100644 +index 000000000000..305574031196 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_THERMAL_PLATFORM_H ++#define _MTK_THERMAL_PLATFORM_H ++ ++#include ++#include ++ ++extern ++int mtk_thermal_get_cpu_info(int *nocores, int **cpufreq, int **cpuloading); ++ ++extern ++int mtk_thermal_get_gpu_info(int *nocores, int **gpufreq, int **gpuloading); ++ ++extern ++int mtk_thermal_get_batt_info(int *batt_voltage, int *batt_current, int *batt_temp); ++ ++extern ++int mtk_thermal_get_extra_info(int *no_extra_attr, ++ char ***attr_names, int **attr_values, char ***attr_unit); ++ ++extern ++int mtk_thermal_force_get_batt_temp(void); ++ ++ ++enum { ++ MTK_THERMAL_SCEN_CALL = 0x1 ++}; ++ ++extern ++unsigned int mtk_thermal_set_user_scenarios(unsigned int mask); ++ ++extern ++unsigned int mtk_thermal_clear_user_scenarios(unsigned int mask); ++ ++ ++#if defined(CONFIG_MTK_SMART_BATTERY) ++/* global variable from battery driver... */ ++extern kal_bool gFG_Is_Charging; ++#endif ++ ++extern int force_get_tbat(void); ++#endif /* _MTK_THERMAL_PLATFORM_H */ ++ ++ ++typedef enum { ++ TA_DAEMON_CMD_GET_INIT_FLAG = 0, ++ TA_DAEMON_CMD_SET_DAEMON_PID, ++ TA_DAEMON_CMD_NOTIFY_DAEMON, ++ TA_DAEMON_CMD_NOTIFY_DAEMON_CATMINIT, ++ TA_DAEMON_CMD_SET_TTJ, ++ TA_DAEMON_CMD_GET_TPCB, ++ ++ TA_DAEMON_CMD_TO_KERNEL_NUMBER ++} TA_DAEMON_CTRL_CMD_TO_KERNEL; /*must sync userspace/kernel: TA_DAEMON_CTRL_CMD_FROM_USER*/ ++ ++#define TAD_NL_MSG_T_HDR_LEN 12 ++#define TAD_NL_MSG_MAX_LEN 2048 ++ ++struct tad_nl_msg_t { ++ unsigned int tad_cmd; ++ unsigned int tad_data_len; ++ unsigned int tad_ret_data_len; ++ char tad_data[TAD_NL_MSG_MAX_LEN]; ++}; ++ ++enum { ++ TA_CATMPLUS = 1, ++ TA_CONTINUOUS = 2, ++ TA_CATMPLUS_TTJ = 3 ++}; ++ ++ ++struct cATM_params_t { ++ int CATM_ON; ++ int K_TT; ++ int K_SUM_TT_LOW; ++ int K_SUM_TT_HIGH; ++ int MIN_SUM_TT; ++ int MAX_SUM_TT; ++ int MIN_TTJ; ++ int CATMP_STEADY_TTJ_DELTA; ++}; ++struct continuetm_params_t { ++ int STEADY_TARGET_TJ; ++ int MAX_TARGET_TJ; ++ int TRIP_TPCB; ++ int STEADY_TARGET_TPCB; ++}; ++ ++ ++struct CATM_T { ++ struct cATM_params_t t_catm_par; ++ struct continuetm_params_t t_continuetm_par; ++}; ++extern struct CATM_T thermal_atm_t; ++int wakeup_ta_algo(int flow_state); ++int ta_get_ttj(void); ++ ++extern int mtk_thermal_get_tpcb_target(void); ++extern int tsatm_thermal_get_catm_type(void); ++ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h +new file mode 100644 +index 000000000000..1c23a9f4a862 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM thermal ++ ++#if !defined(_MTK_THERMAL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _MTK_THERMAL_TRACE_H ++ ++#include ++ ++TRACE_EVENT(cooling_device_state, ++ TP_PROTO(int device, unsigned long state), ++ TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) ++ __field(unsigned long, state) ++ ), ++ TP_fast_assign(__entry->device = device; ++ __entry->state = state;), ++ TP_printk("cooling_device=%d, state=%lu\n", __entry->device, __entry->state) ++); ++ ++TRACE_EVENT(thermal_zone_state, ++ TP_PROTO(int device, int state), ++ TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) ++ __field(int, state) ++ ), ++ TP_fast_assign(__entry->device = device; ++ __entry->state = state;), ++ TP_printk("thermal_zone=%d, state=%d\n", __entry->device, __entry->state) ++); ++#endif /* _MTK_THERMAL_TRACE_H */ ++ ++/* This part must be outside protection */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#define TRACE_INCLUDE_FILE mach/mtk_thermal_trace ++#include +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h +new file mode 100644 +index 000000000000..dfcef3d952fc +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h +@@ -0,0 +1,241 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _TYPEDEFS_H ++#define _TYPEDEFS_H ++ ++#include ++ ++/* --------------------------------------------------------------------------- */ ++/* Basic Type Definitions */ ++/* --------------------------------------------------------------------------- */ ++ ++typedef volatile unsigned char *P_kal_uint8; ++typedef volatile unsigned short *P_kal_uint16; ++typedef volatile unsigned int *P_kal_uint32; ++ ++typedef long LONG; ++typedef unsigned char UBYTE; ++typedef short SHORT; ++ ++typedef signed char kal_int8; ++typedef signed short kal_int16; ++typedef signed int kal_int32; ++typedef long long kal_int64; ++typedef unsigned char kal_uint8; ++typedef unsigned short kal_uint16; ++typedef unsigned int kal_uint32; ++typedef unsigned long long kal_uint64; ++typedef char kal_char; ++ ++typedef unsigned int *UINT32P; ++typedef volatile unsigned short *UINT16P; ++typedef volatile unsigned char *UINT8P; ++typedef unsigned char *U8P; ++ ++typedef volatile unsigned char *P_U8; ++typedef volatile signed char *P_S8; ++typedef volatile unsigned short *P_U16; ++typedef volatile signed short *P_S16; ++typedef volatile unsigned int *P_U32; ++typedef volatile signed int *P_S32; ++typedef unsigned long long *P_U64; ++typedef signed long long *P_S64; ++ ++typedef unsigned char U8; ++typedef signed char S8; ++typedef unsigned short U16; ++typedef signed short S16; ++typedef unsigned int U32; ++typedef signed int S32; ++typedef unsigned long long U64; ++typedef signed long long S64; ++/* typedef unsigned char bool; */ ++ ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++typedef unsigned short USHORT; ++typedef signed char INT8; ++typedef signed short INT16; ++typedef signed int INT32; ++typedef unsigned int DWORD; ++typedef void VOID; ++typedef unsigned char BYTE; ++typedef float FLOAT; ++ ++typedef char *LPCSTR; ++typedef short *LPWSTR; ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Constants */ ++/* --------------------------------------------------------------------------- */ ++ ++#ifndef FALSE ++#define FALSE (0) ++#endif ++ ++#ifndef TRUE ++#define TRUE (1) ++#endif ++ ++#ifndef NULL ++#define NULL (0) ++#endif ++ ++/* enum boolean {false, true}; */ ++enum { RX, TX, NONE }; ++ ++#ifndef BOOL ++typedef unsigned char BOOL; ++#endif ++ ++#ifndef BATTERY_BOOL ++#define BATTERY_BOOL ++typedef enum { ++ KAL_FALSE = 0, ++ KAL_TRUE = 1, ++} kal_bool; ++#endif ++ ++/* --------------------------------------------------------------------------- */ ++/* Type Casting */ ++/* --------------------------------------------------------------------------- */ ++ ++#define AS_INT32(x) (*(INT32 *)((void *)x)) ++#define AS_INT16(x) (*(INT16 *)((void *)x)) ++#define AS_INT8(x) (*(INT8 *)((void *)x)) ++ ++#define AS_UINT32(x) (*(UINT32 *)((void *)x)) ++#define AS_UINT16(x) (*(UINT16 *)((void *)x)) ++#define AS_UINT8(x) (*(UINT8 *)((void *)x)) ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Register Manipulations */ ++/* --------------------------------------------------------------------------- */ ++ ++#define READ_REGISTER_UINT32(reg) \ ++ (*(volatile UINT32 * const)(reg)) ++ ++#define WRITE_REGISTER_UINT32(reg, val) \ ++ ((*(volatile UINT32 * const)(reg)) = (val)) ++ ++#define READ_REGISTER_UINT16(reg) \ ++ ((*(volatile UINT16 * const)(reg))) ++ ++#define WRITE_REGISTER_UINT16(reg, val) \ ++ ((*(volatile UINT16 * const)(reg)) = (val)) ++ ++#define READ_REGISTER_UINT8(reg) \ ++ ((*(volatile UINT8 * const)(reg))) ++ ++#define WRITE_REGISTER_UINT8(reg, val) \ ++ ((*(volatile UINT8 * const)(reg)) = (val)) ++ ++#define INREG8(x) READ_REGISTER_UINT8((UINT8 *)((void *)(x))) ++#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8 *)((void *)(x)), (UINT8)(y)) ++#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) ++#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) ++#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) ++ ++#define INREG16(x) READ_REGISTER_UINT16((UINT16 *)((void *)(x))) ++#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16 *)((void *)(x)), (UINT16)(y)) ++#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) ++#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) ++#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) ++ ++#define INREG32(x) READ_REGISTER_UINT32((UINT32 *)((void *)(x))) ++#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32 *)((void *)(x)), (UINT32)(y)) ++#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) ++#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) ++#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) ++ ++ ++#define DRV_Reg8(addr) INREG8(addr) ++#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) ++#define DRV_SetReg8(addr, data) SETREG8(addr, data) ++#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) ++ ++#define DRV_Reg16(addr) INREG16(addr) ++#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) ++#define DRV_SetReg16(addr, data) SETREG16(addr, data) ++#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) ++ ++#define DRV_Reg32(addr) INREG32(addr) ++#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) ++#define DRV_SetReg32(addr, data) SETREG32(addr, data) ++#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) ++ ++/* !!! DEPRECATED, WILL BE REMOVED LATER !!! */ ++#define DRV_Reg(addr) DRV_Reg16(addr) ++#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) ++#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) ++#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Compiler Time Deduction Macros */ ++/* --------------------------------------------------------------------------- */ ++ ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Assertions */ ++/* --------------------------------------------------------------------------- */ ++ ++/* ++*#ifndef ASSERT ++*#define ASSERT(expr) BUG_ON(!(expr)) ++*#endif ++* ++*#ifndef NOT_IMPLEMENTED ++*#define NOT_IMPLEMENTED() BUG_ON(1) ++*#endif ++*/ ++#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) ++#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) ++#define STATIC_ASSERT_XX(pred, line) \ ++extern char assertion_failed_at_##line[(pred) ? 1 : -1] ++ ++/* --------------------------------------------------------------------------- */ ++/* Resolve Compiler Warnings */ ++/* --------------------------------------------------------------------------- */ ++ ++#define NOT_REFERENCED(x) { (x) = (x); } ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Utilities */ ++/* --------------------------------------------------------------------------- */ ++ ++#define MAXIMUM(A, B) (((A) > (B))?(A):(B)) ++#define MINIMUM(A, B) (((A) < (B))?(A):(B)) ++ ++#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) ++#define DVT_DELAYMACRO(u4Num) \ ++{ \ ++ UINT32 u4Count = 0; \ ++ for (u4Count = 0; u4Count < u4Num; u4Count++) \ ++ ; \ ++} \ ++ ++#define A68351B 0 ++#define B68351B 1 ++#define B68351D 2 ++#define B68351E 3 ++#define UNKNOWN_IC_VERSION 0xFF ++ ++ ++#endif /* _TYPEDEFS_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h +new file mode 100644 +index 000000000000..0a4fda191654 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++/*! \file ++ * \brief Declaration of library functions ++ * ++ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _MTK_WCN_CMB_STUB_H_ ++#define _MTK_WCN_CMB_STUB_H_ ++ ++#include ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Audio GPIO naming style for 73/75/77 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_0 1 */ ++/* Audio GPIO naming style for 89/8135 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_1 1 */ ++/* Audio GPIO naming style for 6592 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_2 1 */ ++/* Audio GPIO naming style for 6595 */ ++#define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_3 1 ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum { ++ CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ ++ CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ ++ CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ ++ CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ ++ CMB_STUB_AIF_4 = 4, /* 0100: BT_I2S & FM disable in special projects, e.g. protea*/ ++ CMB_STUB_AIF_MAX = 5, ++} CMB_STUB_AIF_X; ++ ++/*COMBO_CHIP_AUDIO_PIN_CTRL*/ ++typedef enum { ++ CMB_STUB_AIF_CTRL_DIS = 0, ++ CMB_STUB_AIF_CTRL_EN = 1, ++ CMB_STUB_AIF_CTRL_MAX = 2, ++} CMB_STUB_AIF_CTRL; ++ ++typedef enum { ++ COMBO_FUNC_TYPE_BT = 0, ++ COMBO_FUNC_TYPE_FM = 1, ++ COMBO_FUNC_TYPE_GPS = 2, ++ COMBO_FUNC_TYPE_WIFI = 3, ++ COMBO_FUNC_TYPE_WMT = 4, ++ COMBO_FUNC_TYPE_STP = 5, ++ COMBO_FUNC_TYPE_NUM = 6 ++} COMBO_FUNC_TYPE; ++ ++typedef enum { ++ COMBO_IF_UART = 0, ++ COMBO_IF_MSDC = 1, ++ COMBO_IF_BTIF = 2, ++ COMBO_IF_MAX, ++} COMBO_IF; ++ ++typedef void (*wmt_bgf_eirq_cb) (void); ++typedef int (*wmt_aif_ctrl_cb) (CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); ++typedef void (*wmt_func_ctrl_cb) (unsigned int, unsigned int); ++typedef signed long (*wmt_thermal_query_cb) (void); ++typedef int (*wmt_deep_idle_ctrl_cb) (unsigned int); ++typedef int (*wmt_func_do_reset) (unsigned int); ++ ++/* for DVFS driver do 1v autok */ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++typedef unsigned int (*wmt_get_drv_status)(unsigned int); ++#endif ++ ++typedef void (*msdc_sdio_irq_handler_t) (void *); /* external irq handler */ ++typedef void (*pm_callback_t) (pm_message_t state, void *data); ++ ++struct sdio_ops { ++ void (*sdio_request_eirq)(msdc_sdio_irq_handler_t irq_handler, void *data); ++ void (*sdio_enable_eirq)(void); ++ void (*sdio_disable_eirq)(void); ++ void (*sdio_register_pm)(pm_callback_t pm_cb, void *data); ++}; ++ ++typedef struct _CMB_STUB_CB_ { ++ unsigned int size; /* structure size */ ++ /*wmt_bgf_eirq_cb bgf_eirq_cb; *//* remove bgf_eirq_cb from stub. handle it in platform */ ++ wmt_aif_ctrl_cb aif_ctrl_cb; ++ wmt_func_ctrl_cb func_ctrl_cb; ++ wmt_thermal_query_cb thermal_query_cb; ++ wmt_deep_idle_ctrl_cb deep_idle_ctrl_cb; ++ wmt_func_do_reset wmt_do_reset_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ wmt_get_drv_status get_drv_status_cb; ++#endif ++} CMB_STUB_CB, *P_CMB_STUB_CB; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern struct sdio_ops mt_sdio_ops[4]; ++ ++extern int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb); ++extern int mtk_wcn_cmb_stub_unreg(void); ++ ++extern int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); ++ ++static inline int mtk_wcn_cmb_stub_audio_ctrl(CMB_STUB_AIF_X state) ++{ ++/* return mtk_wcn_cmb_stub_aif_ctrl(state, 1); */ ++ return 0; ++} ++ ++extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); ++extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); ++ ++/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control ++ * function on/off. ++ */ ++extern void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on); ++extern int mtk_wcn_cmb_stub_query_ctrl(void); ++extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); ++extern int mtk_wcn_sdio_irq_flag_set(int falg); ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++extern int mtk_wcn_cmb_stub_1vautok_for_dvfs(void); ++#endif ++ ++extern int mtk_wcn_wmt_chipid_query(void); ++extern void mtk_wcn_wmt_set_chipid(int chipid); ++ ++/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver ++ * ++ * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" ++ * @ enable - "1", enable deep idle; "0", disable deep idle ++ * ++ * Return 0 if success, else -1 ++ */ ++extern unsigned int mtk_uart_pdn_enable(char *port, int enable); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MTK_WCN_CMB_STUB_H_ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/rt-regmap.h b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h +new file mode 100644 +index 000000000000..9a45e23005ca +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h +@@ -0,0 +1,291 @@ ++/* drivers/misc/mediatek/include/mt-plat/rt-regmap.h ++ * Header of Richtek regmap with debugfs Driver ++ * ++ * Copyright (C) 2014 Richtek Technology Corp. ++ * Jeff Chang ++ * ++ * 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. ++ */ ++ ++#ifndef MISC_MEDIATEK_RT_REGMAP_H ++#define MISC_MEDIATEK_RT_REGMAP_H ++ ++#include ++#include ++ ++/* #define RT_REGMAP_VERSION "1.1.11_G" */ ++ ++enum rt_access_mode { ++ RT_1BYTE_MODE = 1, ++ RT_2BYTE_MODE = 2, ++ RT_4BYTE_MODE = 4, ++}; ++ ++/* start : the start address of group ++ * end : the end address of group ++ * mode : access mode (1,2,4 bytes) ++ */ ++struct rt_access_group { ++ u32 start; ++ u32 end; ++ enum rt_access_mode mode; ++}; ++ ++/* rt_reg_type ++ * RT_NORMAL : Write data without mask ++ * Read from cache ++ * RT_WBITS : Write data with mask ++ * Read from cache ++ * RT_VOLATILE : Write data to chip directly ++ * Read data from chip ++ * RT_RESERVE : Reserve registers (Write/Read as RT_NORMAL) ++ */ ++ ++#define RT_REG_TYPE_MASK (0x03) ++#define RT_NORMAL (0x00) ++#define RT_WBITS (0x01) ++#define RT_VOLATILE (0x02) ++#define RT_RESERVE (0x03) ++ ++/* RT_WR_ONCE : write once will check write data and cache data, ++ * if write data = cache data, data will not be writen. ++ */ ++#define RT_WR_ONCE (0x08) ++#define RT_NORMAL_WR_ONCE (RT_NORMAL|RT_WR_ONCE) ++#define RT_WBITS_WR_ONCE (RT_WBITS|RT_WR_ONCE) ++ ++enum rt_data_format { ++ RT_LITTLE_ENDIAN, ++ RT_BIG_ENDIAN, ++}; ++ ++/* rt_regmap_mode ++ * 0 0 0 0 0 0 0 0 ++ * | | | | | | ++ * | | | |__| byte_mode ++ * | |__| || ++ * | || Cache_mode ++ * | Block_mode ++ * Debug_mode ++ */ ++ ++#define RT_BYTE_MODE_MASK (0x01) ++/* 1 byte for each register*/ ++#define RT_SINGLE_BYTE (0 << 0) ++/* multi bytes for each regiseter*/ ++#define RT_MULTI_BYTE (1 << 0) ++ ++#define RT_CACHE_MODE_MASK (0x06) ++/* write to cache and chip synchronously */ ++#define RT_CACHE_WR_THROUGH (0 << 1) ++/* write to cache and chip asynchronously */ ++#define RT_CACHE_WR_BACK (1 << 1) ++/* disable cache */ ++#define RT_CACHE_DISABLE (2 << 1) ++ ++#define RT_IO_BLK_MODE_MASK (0x18) ++/* pass through all write function */ ++#define RT_IO_PASS_THROUGH (0 << 3) ++/* block all write function */ ++#define RT_IO_BLK_ALL (1 << 3) ++/* block cache write function */ ++#define RT_IO_BLK_CACHE (2 << 3) ++/* block chip write function */ ++#define RT_IO_BLK_CHIP (3 << 3) ++ ++#define DBG_MODE_MASK (0x20) ++/* create general debugfs for register map */ ++#define RT_DBG_GENERAL (0 << 5) ++/* create node for each regisetr map by register address*/ ++#define RT_DBG_SPECIAL (1 << 5) ++ ++ ++/* struct rt_register ++ * ++ * Ricktek register map structure for store mapping data ++ * @addr: register address. ++ * @name: register name. ++ * @size: register byte size. ++ * @reg_type: register R/W type ( RT_NORMAL, RT_WBITS, RT_VOLATILE, RT_RESERVE) ++ * @wbit_mask: register writeable bits mask; ++ * @cache_data: cache data for store cache value. ++ */ ++struct rt_register { ++ u32 addr; ++ const char *name; ++ unsigned int size; ++ unsigned char reg_type; ++ unsigned char *wbit_mask; ++ unsigned char *cache_data; ++}; ++ ++/* Declare a rt_register by RT_REG_DECL ++ * @_addr: regisetr address. ++ * @_reg_length: register data length. ++ * @_reg_type: register type (rt_reg_type). ++ * @_mask: register writealbe mask. ++ */ ++#define RT_REG_DECL(_addr, _reg_length, _reg_type, _mask_...) \ ++ static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ ++ static struct rt_register rt_register_##_addr = { \ ++ .addr = _addr, \ ++ .size = _reg_length,\ ++ .reg_type = _reg_type,\ ++ .wbit_mask = rt_writable_mask_##_addr,\ ++ } ++ ++/* Declare a rt_register by RT_NAMED_REG_DECL ++ * @_name: a name for a rt_register. ++ */ ++#define RT_NAMED_REG_DECL(_addr, _name, _reg_length, _reg_type, _mask_...) \ ++ static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ ++ static struct rt_register rt_register_##_addr = { \ ++ .addr = _addr, \ ++ .name = _name, \ ++ .size = _reg_length,\ ++ .reg_type = _reg_type,\ ++ .wbit_mask = rt_writable_mask_##_addr,\ ++ } ++ ++#define RT_REG(_addr) (&rt_register_##_addr) ++ ++/* rt_regmap_properties ++ * @name: the name of debug node. ++ * @aliases: alisis name of rt_regmap_device. ++ * @register_num: the number of rt_register_map registers. ++ * @rm: rt_regiseter_map pointer array. ++ * @group: register map access group. ++ * @rt_format: default is little endian. ++ * @rt_regmap_mode: rt_regmap_device mode. ++ * @io_log_en: enable/disable io log ++ */ ++struct rt_regmap_properties { ++ const char *name; ++ const char *aliases; ++ int register_num; ++ struct rt_register **rm; ++ struct rt_access_group *group; ++ enum rt_data_format rt_format; ++ unsigned char rt_regmap_mode; ++ unsigned char io_log_en:1; ++}; ++ ++/* A passing struct for rt_regmap_reg_read and rt_regmap_reg_write function ++ * reg: regmap addr. ++ * mask: mask for update bits. ++ * rt_data: register value. ++ */ ++struct rt_reg_data { ++ u32 reg; ++ u32 mask; ++ union { ++ u32 data_u32; ++ u16 data_u16; ++ u8 data_u8; ++ u8 data[4]; ++ } rt_data; ++}; ++ ++struct rt_regmap_device; ++ ++struct rt_debug_st { ++ void *info; ++ int id; ++}; ++ ++/* basic chip read/write function */ ++struct rt_regmap_fops { ++ int (*read_device)(void *client, u32 addr, int leng, void *dst); ++ int (*write_device)(void *client, u32 addr, int leng, const void *src); ++}; ++ ++/* with slave address */ ++extern struct rt_regmap_device* ++ rt_regmap_device_register_ex(struct rt_regmap_properties *props, ++ struct rt_regmap_fops *rops, ++ struct device *parent, ++ void *client, int slv_addr, void *drvdata); ++ ++static inline struct rt_regmap_device* ++ rt_regmap_device_register(struct rt_regmap_properties *props, ++ struct rt_regmap_fops *rops, ++ struct device *parent, ++ struct i2c_client *client, void *drvdata) ++{ ++ return rt_regmap_device_register_ex(props, rops, parent, ++ client, client->addr, drvdata); ++} ++ ++extern void rt_regmap_device_unregister(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_cache_init(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_cache_reload(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg, ++ int bytes, const void *rc); ++extern int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg, ++ int bytes, const void *rc); ++extern int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg, ++ int bytes, void *dst); ++ ++extern int _rt_regmap_reg_read(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_regmap_update_bits(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++ ++static inline int rt_regmap_reg_read(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg) ++{ ++ rrd->reg = reg; ++ return _rt_regmap_reg_read(rd, rrd); ++}; ++ ++static inline int rt_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, const u32 data) ++{ ++ rrd->reg = reg; ++ rrd->rt_data.data_u32 = data; ++ return _rt_regmap_reg_write(rd, rrd); ++}; ++ ++static inline int rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, const u32 data) ++{ ++ rrd->reg = reg; ++ rrd->rt_data.data_u32 = data; ++ return _rt_asyn_regmap_reg_write(rd, rrd); ++}; ++ ++static inline int rt_regmap_update_bits(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, u32 mask, u32 data) ++{ ++ rrd->reg = reg; ++ rrd->mask = mask; ++ rrd->rt_data.data_u32 = data; ++ return _rt_regmap_update_bits(rd, rrd); ++} ++ ++extern void rt_regmap_cache_backup(struct rt_regmap_device *rd); ++ ++extern void rt_regmap_cache_sync(struct rt_regmap_device *rd); ++extern void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg); ++ ++extern int rt_is_reg_readable(struct rt_regmap_device *rd, u32 reg); ++extern int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg); ++extern int rt_get_regsize(struct rt_regmap_device *rd, u32 reg); ++extern void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf); ++extern void rt_cache_clrlasterror(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name, ++ umode_t mode, void *data, const struct file_operations *fops); ++ ++#define to_rt_regmap_device(obj) container_of(obj, struct rt_regmap_device, dev) ++ ++#endif /*MISC_MEDIATEK_RT_REGMAP_H*/ +diff --git a/drivers/misc/mediatek/include/mt-plat/sync_write.h b/drivers/misc/mediatek/include/mt-plat/sync_write.h +new file mode 100644 +index 000000000000..f9e5fe4c23e1 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/sync_write.h +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MT_SYNC_WRITE_H ++#define _MT_SYNC_WRITE_H ++ ++#if defined(__KERNEL__) ++ ++#include ++#include ++ ++/* ++ * Define macros. ++ */ ++#define mt_reg_sync_writel(v, a) \ ++ do { \ ++ __raw_writel((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#define mt_reg_sync_writew(v, a) \ ++ do { \ ++ __raw_writew((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#define mt_reg_sync_writeb(v, a) \ ++ do { \ ++ __raw_writeb((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#ifdef CONFIG_64BIT ++#define mt_reg_sync_writeq(v, a) \ ++ do { \ ++ __raw_writeq((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++#endif ++ ++#else /* __KERNEL__ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define mt_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) ++#define mt_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) ++#define mt_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) ++ ++#define mb() \ ++ { \ ++ __asm__ __volatile__ ("dsb" : : : "memory"); \ ++ } ++ ++#define mt65xx_reg_sync_writel(v, a) \ ++ do { \ ++ *(volatile unsigned int *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#define mt65xx_reg_sync_writew(v, a) \ ++ do { \ ++ *(volatile unsigned short *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#define mt65xx_reg_sync_writeb(v, a) \ ++ do { \ ++ *(volatile unsigned char *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* !_MT_SYNC_WRITE_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/wakelock.h b/drivers/misc/mediatek/include/mt-plat/wakelock.h +new file mode 100644 +index 000000000000..f4a698a22880 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/wakelock.h +@@ -0,0 +1,67 @@ ++/* include/linux/wakelock.h ++ * ++ * Copyright (C) 2007-2012 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LINUX_WAKELOCK_H ++#define _LINUX_WAKELOCK_H ++ ++#include ++#include ++ ++/* A wake_lock prevents the system from entering suspend or other low power ++ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock ++ * prevents a full system suspend. ++ */ ++ ++enum { ++ WAKE_LOCK_SUSPEND, /* Prevent suspend */ ++ WAKE_LOCK_TYPE_COUNT ++}; ++ ++struct wake_lock { ++ struct wakeup_source ws; ++}; ++ ++static inline void wake_lock_init(struct wake_lock *lock, int type, ++ const char *name) ++{ ++ wakeup_source_init(&lock->ws, name); ++} ++ ++static inline void wake_lock_destroy(struct wake_lock *lock) ++{ ++ wakeup_source_trash(&lock->ws); ++} ++ ++static inline void wake_lock(struct wake_lock *lock) ++{ ++ __pm_stay_awake(&lock->ws); ++} ++ ++static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) ++{ ++ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); ++} ++ ++static inline void wake_unlock(struct wake_lock *lock) ++{ ++ __pm_relax(&lock->ws); ++} ++ ++static inline int wake_lock_active(struct wake_lock *lock) ++{ ++ return lock->ws.active; ++} ++ ++#endif +diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c +index e3df1e96b141..086c9ea8d7cb 100644 +--- a/drivers/soc/mediatek/mtk-pmic-wrap.c ++++ b/drivers/soc/mediatek/mtk-pmic-wrap.c +@@ -1107,6 +1107,22 @@ static const struct of_device_id of_pwrap_match_tbl[] = { + }; + MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); + ++struct regmap *pwrap_node_to_regmap(struct device_node *np) ++{ ++ struct platform_device *pdev; ++ struct pmic_wrapper *wrp; ++ ++ pdev = of_find_device_by_node(np); ++ ++ if (!pdev) ++ return ERR_PTR(-ENODEV); ++ ++ wrp = platform_get_drvdata(pdev); ++ ++ return wrp->regmap; ++} ++EXPORT_SYMBOL_GPL(pwrap_node_to_regmap); ++ + static int pwrap_probe(struct platform_device *pdev) + { + int ret, irq; +diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c +index 7ed417a765c7..43676313f32b 100644 +--- a/drivers/watchdog/mtk_wdt.c ++++ b/drivers/watchdog/mtk_wdt.c +@@ -21,14 +21,34 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include ++#include ++#include + #include ++#include + #include ++#ifdef CONFIG_FIQ_GLUE ++#include ++#include ++#endif + #include + #include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_MT6397_MISC ++#include ++#endif + + #define WDT_MAX_TIMEOUT 31 + #define WDT_MIN_TIMEOUT 1 +@@ -47,37 +67,167 @@ + #define WDT_MODE_EXRST_EN (1 << 2) + #define WDT_MODE_IRQ_EN (1 << 3) + #define WDT_MODE_AUTO_START (1 << 4) ++#define WDT_MODE_IRQ_LVL (1 << 5) + #define WDT_MODE_DUAL_EN (1 << 6) + #define WDT_MODE_KEY 0x22000000 + ++#define WDT_STATUS 0x0c ++#define WDT_NONRST_REG 0x20 ++#define WDT_NONRST_REG2 0x24 ++ + #define WDT_SWRST 0x14 + #define WDT_SWRST_KEY 0x1209 + ++#define WDT_SWSYSRST 0x18 ++#define WDT_SWSYSRST_KEY 0x88000000 ++ ++#define WDT_REQ_MODE 0x30 ++#define WDT_REQ_MODE_KEY 0x33000000 ++#define WDT_REQ_IRQ_EN 0x34 ++#define WDT_REQ_IRQ_KEY 0x44000000 ++#define WDT_REQ_MODE_DEBUG_EN 0x80000 ++ ++ + #define DRV_NAME "mtk-wdt" +-#define DRV_VERSION "1.0" ++#define DRV_VERSION "2.0" + + static bool nowayout = WATCHDOG_NOWAYOUT; + static unsigned int timeout = WDT_MAX_TIMEOUT; + ++struct toprgu_reset { ++ spinlock_t lock; ++ void __iomem *toprgu_swrst_base; ++ int regofs; ++ struct reset_controller_dev rcdev; ++}; ++ + struct mtk_wdt_dev { + struct watchdog_device wdt_dev; + void __iomem *wdt_base; ++ int wdt_irq_id; ++ struct notifier_block restart_handler; ++ struct toprgu_reset reset_controller; + }; + +-static int mtk_wdt_restart(struct watchdog_device *wdt_dev, +- unsigned long action, void *data) ++static void __iomem *toprgu_base; ++static struct watchdog_device *wdt_dev; ++ ++static int toprgu_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) + { +- struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); ++ unsigned int tmp; ++ unsigned long flags; ++ struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); ++ tmp |= BIT(id); ++ tmp |= WDT_SWSYSRST_KEY; ++ writel(tmp, data->toprgu_swrst_base + data->regofs); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int toprgu_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ unsigned int tmp; ++ unsigned long flags; ++ struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); ++ tmp &= ~BIT(id); ++ tmp |= WDT_SWSYSRST_KEY; ++ writel(tmp, data->toprgu_swrst_base + data->regofs); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int toprgu_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = toprgu_reset_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return toprgu_reset_deassert(rcdev, id); ++} ++ ++static struct reset_control_ops toprgu_reset_ops = { ++ .assert = toprgu_reset_assert, ++ .deassert = toprgu_reset_deassert, ++ .reset = toprgu_reset, ++}; ++ ++static void toprgu_register_reset_controller(struct platform_device *pdev, int regofs) ++{ ++ int ret; ++ struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); ++ ++ spin_lock_init(&mtk_wdt->reset_controller.lock); ++ ++ mtk_wdt->reset_controller.toprgu_swrst_base = mtk_wdt->wdt_base; ++ mtk_wdt->reset_controller.regofs = regofs; ++ mtk_wdt->reset_controller.rcdev.owner = THIS_MODULE; ++ mtk_wdt->reset_controller.rcdev.nr_resets = 15; ++ mtk_wdt->reset_controller.rcdev.ops = &toprgu_reset_ops; ++ mtk_wdt->reset_controller.rcdev.of_node = pdev->dev.of_node; ++ ++ ret = reset_controller_register(&mtk_wdt->reset_controller.rcdev); ++ if (ret) ++ pr_err("could not register toprgu reset controller: %d\n", ret); ++} ++ ++static int mtk_reset_handler(struct notifier_block *this, unsigned long mode, ++ void *cmd) ++{ ++ struct mtk_wdt_dev *mtk_wdt; + void __iomem *wdt_base; ++ u32 reg; + ++ mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler); + wdt_base = mtk_wdt->wdt_base; + +- while (1) { +- writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); +- mdelay(5); ++ /* WDT_STATUS will be cleared to zero after writing to WDT_MODE, so we backup it in WDT_NONRST_REG, ++ * and then print it out in mtk_wdt_probe() after reset ++ */ ++ writel(__raw_readl(wdt_base + WDT_STATUS), wdt_base + WDT_NONRST_REG); ++ ++ reg = ioread32(wdt_base + WDT_MODE); ++ reg &= ~(WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EN); ++ reg |= WDT_MODE_KEY; ++ iowrite32(reg, wdt_base + WDT_MODE); ++ ++ if (cmd && !strcmp(cmd, "rpmbpk")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 0), wdt_base + WDT_NONRST_REG2); ++ } else if (cmd && !strcmp(cmd, "recovery")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 1), wdt_base + WDT_NONRST_REG2); ++ #ifdef CONFIG_MT6397_MISC ++ mtk_misc_mark_recovery(); ++ #endif ++ } else if (cmd && !strcmp(cmd, "bootloader")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 2), wdt_base + WDT_NONRST_REG2); ++ #ifdef CONFIG_MT6397_MISC ++ mtk_misc_mark_fast(); ++ #endif + } + +- return 0; ++ if (!arm_pm_restart) { ++ while (1) { ++ writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); ++ mdelay(5); ++ } ++ } ++ return NOTIFY_DONE; + } + + static int mtk_wdt_ping(struct watchdog_device *wdt_dev) +@@ -86,6 +236,7 @@ static int mtk_wdt_ping(struct watchdog_device *wdt_dev) + void __iomem *wdt_base = mtk_wdt->wdt_base; + + iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); ++ printk_deferred("[WDK]: kick Ex WDT\n"); + + return 0; + } +@@ -137,7 +288,8 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev) + return ret; + + reg = ioread32(wdt_base + WDT_MODE); +- reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); ++ reg |= (WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EXRST_EN); ++ reg &= ~(WDT_MODE_IRQ_LVL | WDT_MODE_EXT_POL_HIGH); + reg |= (WDT_MODE_EN | WDT_MODE_KEY); + iowrite32(reg, wdt_base + WDT_MODE); + +@@ -157,13 +309,56 @@ static const struct watchdog_ops mtk_wdt_ops = { + .stop = mtk_wdt_stop, + .ping = mtk_wdt_ping, + .set_timeout = mtk_wdt_set_timeout, +- .restart = mtk_wdt_restart, + }; + ++#ifdef CONFIG_FIQ_GLUE ++static void wdt_fiq(void *arg, void *regs, void *svc_sp) ++{ ++ unsigned int wdt_mode_val; ++ void __iomem *wdt_base = ((struct mtk_wdt_dev *)arg)->wdt_base; ++ ++ wdt_mode_val = __raw_readl(wdt_base + WDT_STATUS); ++ writel(wdt_mode_val, wdt_base + WDT_NONRST_REG); ++ ++ aee_wdt_fiq_info(arg, regs, svc_sp); ++} ++#else ++static void wdt_report_info(void) ++{ ++ struct task_struct *task; ++ ++ task = &init_task; ++ pr_debug("Qwdt: -- watchdog time out\n"); ++ ++ for_each_process(task) { ++ if (task->state == 0) { ++ pr_debug("PID: %d, name: %s\n backtrace:\n", task->pid, task->comm); ++ show_stack(task, NULL); ++ pr_debug("\n"); ++ } ++ } ++ ++ pr_debug("backtrace of current task:\n"); ++ show_stack(NULL, NULL); ++ pr_debug("Qwdt: -- watchdog time out\n"); ++} ++ ++static irqreturn_t mtk_wdt_isr(int irq, void *dev_id) ++{ ++ pr_err("fwq mtk_wdt_isr\n"); ++ ++ wdt_report_info(); ++ BUG(); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ + static int mtk_wdt_probe(struct platform_device *pdev) + { + struct mtk_wdt_dev *mtk_wdt; + struct resource *res; ++ unsigned int tmp; + int err; + + mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL); +@@ -174,9 +369,32 @@ static int mtk_wdt_probe(struct platform_device *pdev) + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); ++ + if (IS_ERR(mtk_wdt->wdt_base)) + return PTR_ERR(mtk_wdt->wdt_base); + ++ pr_err("MTK_WDT_NONRST_REG(%x)\n", __raw_readl(mtk_wdt->wdt_base + WDT_NONRST_REG)); ++ ++ mtk_wdt->wdt_irq_id = irq_of_parse_and_map(pdev->dev.of_node, 0); ++ if (!mtk_wdt->wdt_irq_id) { ++ pr_err("RGU get IRQ ID failed\n"); ++ return -ENODEV; ++ } ++ ++#ifndef CONFIG_FIQ_GLUE ++ err = request_irq(mtk_wdt->wdt_irq_id, (irq_handler_t)mtk_wdt_isr, IRQF_TRIGGER_NONE, DRV_NAME, mtk_wdt); ++#else ++ mtk_wdt->wdt_irq_id = get_hardware_irq(mtk_wdt->wdt_irq_id); ++ err = request_fiq(mtk_wdt->wdt_irq_id, wdt_fiq, IRQF_TRIGGER_FALLING, mtk_wdt); ++#endif ++ if (err != 0) { ++ pr_err("mtk_wdt_probe : failed to request irq (%d)\n", err); ++ return err; ++ } ++ ++ toprgu_base = mtk_wdt->wdt_base; ++ wdt_dev = &mtk_wdt->wdt_dev; ++ + mtk_wdt->wdt_dev.info = &mtk_wdt_info; + mtk_wdt->wdt_dev.ops = &mtk_wdt_ops; + mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT; +@@ -186,7 +404,6 @@ static int mtk_wdt_probe(struct platform_device *pdev) + + watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev); + watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout); +- watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128); + + watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt); + +@@ -196,9 +413,40 @@ static int mtk_wdt_probe(struct platform_device *pdev) + if (unlikely(err)) + return err; + ++ mtk_wdt->restart_handler.notifier_call = mtk_reset_handler; ++ mtk_wdt->restart_handler.priority = 128; ++ ++ if (arm_pm_restart) { ++ dev_info(&pdev->dev, "register restart_handler on reboot_notifier_list for psci reset\n"); ++ err = register_reboot_notifier(&mtk_wdt->restart_handler); ++ if (err != 0) ++ dev_warn(&pdev->dev, ++ "cannot register reboot notifier (err=%d)\n", err); ++ } else { ++ err = register_restart_handler(&mtk_wdt->restart_handler); ++ if (err) ++ dev_warn(&pdev->dev, ++ "cannot register restart handler (err=%d)\n", err); ++ } ++ + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n", + mtk_wdt->wdt_dev.timeout, nowayout); + ++ writel(WDT_REQ_MODE_KEY | (__raw_readl(mtk_wdt->wdt_base + WDT_REQ_MODE) & ++ (~WDT_REQ_MODE_DEBUG_EN)), mtk_wdt->wdt_base + WDT_REQ_MODE); ++ ++ toprgu_register_reset_controller(pdev, WDT_SWSYSRST); ++ ++ /* enable scpsys thermal and thermal_controller request, and set to reset directly mode */ ++ tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_MODE) | (1 << 18) | (1 << 0); ++ tmp |= WDT_REQ_MODE_KEY; ++ iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_MODE); ++ ++ tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); ++ tmp &= ~((1 << 18) | (1 << 0)); ++ tmp |= WDT_REQ_IRQ_KEY; ++ iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); ++ + return 0; + } + +@@ -214,8 +462,12 @@ static int mtk_wdt_remove(struct platform_device *pdev) + { + struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); + ++ unregister_restart_handler(&mtk_wdt->restart_handler); ++ + watchdog_unregister_device(&mtk_wdt->wdt_dev); + ++ reset_controller_unregister(&mtk_wdt->reset_controller.rcdev); ++ + return 0; + } + +@@ -267,6 +519,95 @@ static struct platform_driver mtk_wdt_driver = { + + module_platform_driver(mtk_wdt_driver); + ++static int wk_proc_cmd_read(struct seq_file *s, void *v) ++{ ++ unsigned int enabled = 1; ++ ++ if (!(ioread32(toprgu_base + WDT_MODE) & WDT_MODE_EN)) ++ enabled = 0; ++ ++ seq_printf(s, "enabled timeout\n%-4d %-8d\n", enabled, wdt_dev->timeout); ++ ++ return 0; ++} ++ ++static int wk_proc_cmd_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, wk_proc_cmd_read, NULL); ++} ++ ++static ssize_t wk_proc_cmd_write(struct file *file, const char *buf, size_t count, loff_t *data) ++{ ++ int ret; ++ int enable; ++ int timeout; ++ char wk_cmd_buf[256]; ++ ++ if (count == 0) ++ return -1; ++ ++ if (count > 255) ++ count = 255; ++ ++ ret = copy_from_user(wk_cmd_buf, buf, count); ++ if (ret < 0) ++ return -1; ++ ++ wk_cmd_buf[count] = '\0'; ++ ++ pr_debug("Write %s\n", wk_cmd_buf); ++ ++ ret = sscanf(wk_cmd_buf, "%d %d", &enable, &timeout); ++ if (ret != 2) ++ pr_debug("%s: expect 2 numbers\n", __func__); ++ ++ pr_debug("[WDK] enable=%d timeout=%d\n", enable, timeout); ++ ++ if (timeout > 20 && timeout <= WDT_MAX_TIMEOUT) { ++ wdt_dev->timeout = timeout; ++ mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout); ++ } else { ++ pr_err("[WDK] The timeout(%d) should bigger than 20 and not bigger than %d\n", ++ timeout, WDT_MAX_TIMEOUT); ++ ++ } ++ ++ if (enable == 1) { ++ mtk_wdt_start(wdt_dev); ++ set_bit(WDOG_ACTIVE, &wdt_dev->status); ++ pr_err("[WDK] enable wdt\n"); ++ } else if (enable == 0) { ++ mtk_wdt_stop(wdt_dev); ++ clear_bit(WDOG_ACTIVE, &wdt_dev->status); ++ pr_err("[WDK] disable wdt\n"); ++ } ++ ++ return count; ++} ++ ++static const struct file_operations wk_proc_cmd_fops = { ++ .owner = THIS_MODULE, ++ .open = wk_proc_cmd_open, ++ .read = seq_read, ++ .write = wk_proc_cmd_write, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init wk_proc_init(void) ++{ ++ struct proc_dir_entry *de = proc_create("wdk", 0660, NULL, &wk_proc_cmd_fops); ++ ++ if (!de) ++ pr_err("[wk_proc_init]: create /proc/wdk failed\n"); ++ ++ pr_debug("[WDK] Initialize proc\n"); ++ ++ return 0; ++} ++ ++late_initcall(wk_proc_init); ++ + module_param(timeout, uint, 0); + MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); + +diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h +new file mode 100644 +index 000000000000..f4a698a22880 +--- /dev/null ++++ b/include/linux/wakelock.h +@@ -0,0 +1,67 @@ ++/* include/linux/wakelock.h ++ * ++ * Copyright (C) 2007-2012 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LINUX_WAKELOCK_H ++#define _LINUX_WAKELOCK_H ++ ++#include ++#include ++ ++/* A wake_lock prevents the system from entering suspend or other low power ++ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock ++ * prevents a full system suspend. ++ */ ++ ++enum { ++ WAKE_LOCK_SUSPEND, /* Prevent suspend */ ++ WAKE_LOCK_TYPE_COUNT ++}; ++ ++struct wake_lock { ++ struct wakeup_source ws; ++}; ++ ++static inline void wake_lock_init(struct wake_lock *lock, int type, ++ const char *name) ++{ ++ wakeup_source_init(&lock->ws, name); ++} ++ ++static inline void wake_lock_destroy(struct wake_lock *lock) ++{ ++ wakeup_source_trash(&lock->ws); ++} ++ ++static inline void wake_lock(struct wake_lock *lock) ++{ ++ __pm_stay_awake(&lock->ws); ++} ++ ++static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) ++{ ++ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); ++} ++ ++static inline void wake_unlock(struct wake_lock *lock) ++{ ++ __pm_relax(&lock->ws); ++} ++ ++static inline int wake_lock_active(struct wake_lock *lock) ++{ ++ return lock->ws.active; ++} ++ ++#endif +diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h +index f12fa5245a45..946ccff6ddc0 100644 +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -3261,7 +3261,7 @@ enum wiphy_flags { + WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(8), + WIPHY_FLAG_MESH_AUTH = BIT(10), +- /* use hole at 11 */ ++ WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), + /* use hole at 12 */ + WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), + WIPHY_FLAG_AP_UAPSD = BIT(14), +diff --git a/include/net/genetlink.h b/include/net/genetlink.h +index 5ac169a735f4..b25568a44e59 100644 +--- a/include/net/genetlink.h ++++ b/include/net/genetlink.h +@@ -144,6 +144,51 @@ struct genl_ops { + }; + + int genl_register_family(struct genl_family *family); ++ ++/** ++ * genl_register_family_with_ops - register a generic netlink family with ops ++ * @family: generic netlink family ++ * @ops: operations to be registered ++ * @n_ops: number of elements to register ++ * ++ * Registers the specified family and operations from the specified table. ++ * Only one family may be registered with the same family name or identifier. ++ * ++ * The family id may equal GENL_ID_GENERATE causing an unique id to ++ * be automatically generated and assigned. ++ * ++ * Either a doit or dumpit callback must be specified for every registered ++ * operation or the function will fail. Only one operation structure per ++ * command identifier may be registered. ++ * ++ * See include/net/genetlink.h for more documenation on the operations ++ * structure. ++ * ++ * Return 0 on success or a negative error code. ++ */ ++static inline int ++_genl_register_family_with_ops_grps(struct genl_family *family, ++ const struct genl_ops *ops, size_t n_ops, ++ const struct genl_multicast_group *mcgrps, ++ size_t n_mcgrps) ++{ ++ family->module = THIS_MODULE; ++ family->ops = ops; ++ family->n_ops = n_ops; ++ family->mcgrps = mcgrps; ++ family->n_mcgrps = n_mcgrps; ++ return genl_register_family(family); ++} ++ ++#define genl_register_family_with_ops(family, ops) \ ++ _genl_register_family_with_ops_grps((family), \ ++ (ops), ARRAY_SIZE(ops), \ ++ NULL, 0) ++#define genl_register_family_with_ops_groups(family, ops, grps) \ ++ _genl_register_family_with_ops_grps((family), \ ++ (ops), ARRAY_SIZE(ops), \ ++ (grps), ARRAY_SIZE(grps)) ++ + int genl_unregister_family(const struct genl_family *family); + void genl_notify(const struct genl_family *family, struct sk_buff *skb, + struct genl_info *info, u32 group, gfp_t flags); +diff --git a/include/soc/mediatek/pmic_wrap.h b/include/soc/mediatek/pmic_wrap.h +new file mode 100644 +index 000000000000..5b5c85272c58 +--- /dev/null ++++ b/include/soc/mediatek/pmic_wrap.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __SOC_MEDIATEK_PMIC_WRAP_H ++#define __SOC_MEDIATEK_PMIC_WRAP_H ++ ++extern struct regmap *pwrap_node_to_regmap(struct device_node *np); ++ ++#endif /* __SOC_MEDIATEK_PMIC_WRAP_H */ +diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h +index 877f7fa95466..c8456b78cc25 100644 +--- a/include/uapi/linux/genetlink.h ++++ b/include/uapi/linux/genetlink.h +@@ -27,6 +27,7 @@ struct genlmsghdr { + /* + * List of reserved static generic netlink identifiers: + */ ++#define GENL_ID_GENERATE 0 + #define GENL_ID_CTRL NLMSG_MIN_TYPE + #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) + #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) +-- +2.17.1 + diff --git a/root/target/linux/mediatek/patches-4.14/0233-revert-unexport-vfs_read-write.patch b/root/target/linux/mediatek/patches-4.14/0233-revert-unexport-vfs_read-write.patch new file mode 100644 index 00000000..5b8e6131 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0233-revert-unexport-vfs_read-write.patch @@ -0,0 +1,35 @@ +From 16c20209050ce9dc0d67e256c3dfba902868c3ed Mon Sep 17 00:00:00 2001 +From: Nikolay Amiantov +Date: Tue, 3 Jul 2018 12:40:04 +0000 +Subject: [PATCH] Revert "fs: unexport vfs_read and vfs_write" + +This reverts commit bd8df82be66698042d11e7919e244c8d72b042ca. +--- + fs/read_write.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/read_write.c b/fs/read_write.c +index 0046d72efe94..62b9c341afa9 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -455,6 +455,8 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) + return ret; + } + ++EXPORT_SYMBOL(vfs_read); ++ + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { + struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; +@@ -553,6 +555,8 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + return ret; + } + ++EXPORT_SYMBOL(vfs_write); ++ + static inline loff_t file_pos_read(struct file *file) + { + return file->f_pos; +-- +2.17.1 + diff --git a/root/target/linux/mediatek/patches-4.14/0234-fix-mtk-wlan_gen2-module.patch b/root/target/linux/mediatek/patches-4.14/0234-fix-mtk-wlan_gen2-module.patch new file mode 100644 index 00000000..bc957ee1 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0234-fix-mtk-wlan_gen2-module.patch @@ -0,0 +1,127 @@ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +@@ -519,6 +519,9 @@ INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl( + } + + #endif ++ ++EXPORT_SYMBOL(mtk_wcn_consys_hw_wifi_paldo_ctrl); ++ + INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) + { + if (enable) { +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +@@ -4530,13 +4530,10 @@ INT_32 kalHaltLock(UINT_32 waitMs) + DBGLOG(INIT, ERROR, + "kalIoctl was executed longer than %u ms, show backtrace of tx_thread!\n", + kalGetTimeTick() - rHaltCtrl.u4HoldStart); +- if (prGlueInfo) +- show_stack(prGlueInfo->main_thread, NULL); + } else { + DBGLOG(INIT, ERROR, "halt lock held by %s pid %d longer than %u ms!\n", + rHaltCtrl.owner->comm, rHaltCtrl.owner->pid, + kalGetTimeTick() - rHaltCtrl.u4HoldStart); +- show_stack(rHaltCtrl.owner, NULL); + } + return i4Ret; + } +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +@@ -58,7 +58,6 @@ + ******************************************************************************** + */ + BOOLEAN fgIsResetting = FALSE; +-UINT_32 g_IsNeedDoChipReset = 0; + + /******************************************************************************* + * P R I V A T E D A T A +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -44,6 +44,9 @@ MODULE_LICENSE("Dual BSD/GPL"); + #define WIFI_LOG_WARN 1 + #define WIFI_LOG_ERR 0 + ++UINT32 g_IsNeedDoChipReset = 0; ++EXPORT_SYMBOL(g_IsNeedDoChipReset); ++ + UINT32 gDbgLevel = WIFI_LOG_DBG; + + #define WIFI_DBG_FUNC(fmt, arg...)\ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +@@ -21,7 +21,11 @@ endif + obj-y += osal.o \ + bgw_desense.o \ + wmt_idc.o +-obj-$(CONFIG_MTK_COMBO_BT) += stp_chrdev_bt.o +-obj-$(CONFIG_MTK_COMBO_WIFI) += wmt_chrdev_wifi.o ++ifneq ($(CONFIG_MTK_COMBO_BT),) ++ obj-y += stp_chrdev_bt.o ++endif ++ifneq ($(CONFIG_MTK_COMBO_WIFI),) ++ obj-y += wmt_chrdev_wifi.o ++endif + + endif +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +@@ -25,7 +25,7 @@ int do_wlan_drv_init(int chip_id) + { + int i_ret = 0; + +-#ifdef CONFIG_MTK_COMBO_WIFI ++#ifdef MTK_WIFI_ENABLED + int ret = 0; + + WMT_DETECT_INFO_FUNC("start to do wlan module init 0x%x\n", chip_id); +@@ -35,6 +35,7 @@ int do_wlan_drv_init(int chip_id) + WMT_DETECT_INFO_FUNC("WMT-WIFI char dev init, ret:%d\n", ret); + i_ret += ret; + ++#ifdef CONFIG_MTK_COMBO_WIFI + switch (chip_id) { + case 0x6630: + case 0x6797: +@@ -61,13 +62,10 @@ int do_wlan_drv_init(int chip_id) + #endif + break; + } +- ++#endif + WMT_DETECT_INFO_FUNC("finish wlan module init\n"); +- + #else +- + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_WIFI is not defined\n"); +- + #endif + + return i_ret; +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +@@ -11,6 +11,10 @@ else ifneq ($(filter "CONSYS_%",$(CONFIG + ccflags-y += -D MTK_WCN_WLAN_GEN2 + endif + ++ifneq ($(CONFIG_MTK_COMBO_WIFI),) ++ ccflags-y += -D MTK_WIFI_ENABLED ++endif ++ + obj-y += conn_drv_init.o + obj-y += common_drv_init.o + obj-y += bluetooth_drv_init.o diff --git a/root/target/linux/mediatek/patches-4.14/0235-mtk_wdt-remove-debug-printk.patch b/root/target/linux/mediatek/patches-4.14/0235-mtk_wdt-remove-debug-printk.patch new file mode 100644 index 00000000..a9f2078c --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0235-mtk_wdt-remove-debug-printk.patch @@ -0,0 +1,12 @@ +Index: linux-4.14.51/drivers/watchdog/mtk_wdt.c +=================================================================== +--- linux-4.14.51.orig/drivers/watchdog/mtk_wdt.c ++++ linux-4.14.51/drivers/watchdog/mtk_wdt.c +@@ -236,7 +236,6 @@ static int mtk_wdt_ping(struct watchdog_ + void __iomem *wdt_base = mtk_wdt->wdt_base; + + iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); +- printk_deferred("[WDK]: kick Ex WDT\n"); + + return 0; + } diff --git a/root/target/linux/mediatek/patches-4.14/0236-mt6625l-rename-wlan.patch b/root/target/linux/mediatek/patches-4.14/0236-mt6625l-rename-wlan.patch new file mode 100644 index 00000000..e1691fd3 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0236-mt6625l-rename-wlan.patch @@ -0,0 +1,13 @@ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -62,7 +62,7 @@ UINT32 gDbgLevel = WIFI_LOG_DBG; + + #define VERSION "1.0" + +-#define WLAN_IFACE_NAME "wlan0" ++#define WLAN_IFACE_NAME "mtkwlan0" + #if CFG_TC1_FEATURE + #define LEGACY_IFACE_NAME "legacy0" + #endif diff --git a/root/target/linux/mediatek/patches-4.14/0237-mt7623-add-HNAT-support.patch b/root/target/linux/mediatek/patches-4.14/0237-mt7623-add-HNAT-support.patch new file mode 100644 index 00000000..5f71df06 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.14/0237-mt7623-add-HNAT-support.patch @@ -0,0 +1,1824 @@ +From b3ba09aea285ecdac5228805411f1e7a6c68382a Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 8 Jul 2018 17:27:58 +0200 +Subject: [PATCH] [HNAT] applied full Patch from hnat-branch + +--- + arch/arm/boot/dts/mt7623.dtsi | 9 + + arch/arm/configs/mt7623n_evb_fwu_defconfig | 4 +- + drivers/net/ethernet/mediatek/Kconfig | 7 + + drivers/net/ethernet/mediatek/Makefile | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 + + .../net/ethernet/mediatek/mtk_hnat/Makefile | 4 + + drivers/net/ethernet/mediatek/mtk_hnat/hnat.c | 329 ++++++++++++ + drivers/net/ethernet/mediatek/mtk_hnat/hnat.h | 427 +++++++++++++++ + .../ethernet/mediatek/mtk_hnat/hnat_debugfs.c | 489 ++++++++++++++++++ + .../ethernet/mediatek/mtk_hnat/hnat_nf_hook.c | 312 +++++++++++ + .../ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h | 44 ++ + net/netfilter/nf_conntrack_proto_tcp.c | 19 + + 12 files changed, 1666 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/Makefile + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.h + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 44831a813a48f..1633d19564ca8 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -1207,6 +1207,15 @@ + status = "disabled"; + }; + ++ hnat: hnat@1b000000 { ++ compatible = "mediatek,mt7623-hnat"; ++ reg = <0 0x1b100000 0 0x3000>; ++ mtketh-wan = "wan"; ++ resets = <ðsys 0>; ++ reset-names = "mtketh"; ++ }; ++ ++ + crypto: crypto@1b240000 { + compatible = "mediatek,mt7623-crypto"; + reg = <0 0x1b240000 0 0x20000>; +diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig +index f9149d2a46940..314c6fe670f81 100644 +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -14,4 +14,11 @@ config NET_MEDIATEK_SOC + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. + ++config NET_MEDIATEK_HNAT ++ tristate "MediaTek MT7623 hardware NAT support" ++ depends on NET_MEDIATEK_SOC && NF_CONNTRACK && NF_CONNTRACK_IPV4 && IP_NF_NAT && IP_NF_TARGET_MASQUERADE ++ ---help--- ++ This driver supports the hardware NAT in the ++ MediaTek MT2701/MT7623 chipset family. ++ + endif #NET_VENDOR_MEDIATEK +diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile +index aa3f1c8ccd4ab..355c928f4700e 100644 +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -3,3 +3,4 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o ++obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/ +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index e6b6596e6a4a9..de4969cc672c4 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,10 @@ + #include + #include + ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++#include "mtk_hnat/nf_hnat_mtk.h" ++#endif ++ + #include "mtk_eth_soc.h" + + static int mtk_msg_level = -1; +@@ -699,6 +703,11 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + return -ENOMEM; + + /* set the forward port */ ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++ if (HNAT_SKB_CB2(skb)->magic == 0x78681415) ++ fport |= 0x4 << TX_DMA_FPORT_SHIFT; ++ else ++#endif + fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; + txd4 |= fport; + +@@ -1063,6 +1072,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + RX_DMA_VID(trxd.rxd3)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++ *(u32 *)(skb->head) = trxd.rxd4; ++ skb_hnat_alg(skb) = 0; ++#endif + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + +@@ -2000,6 +2013,12 @@ static int mtk_hw_init(struct mtk_eth *eth) + val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); + ++ /* Indicates CDM to parse the MTK special tag from CPU ++ * which also is working out for untag packets. ++ */ ++ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ + /* Enable RX VLan Offloading */ + if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX) + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); +@@ -2033,6 +2052,9 @@ static int mtk_hw_init(struct mtk_eth *eth) + /* Enable RX checksum */ + val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; + ++ /* Enable special tag */ ++ val |= BIT(24); ++ + /* setup the mac dma */ + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/Makefile b/drivers/net/ethernet/mediatek/mtk_hnat/Makefile +new file mode 100644 +index 0000000000000..e052abcd43020 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/Makefile +@@ -0,0 +1,4 @@ ++ccflags-y=-Werror -Wno-missing-braces ++ ++obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtkhnat.o ++mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c +new file mode 100644 +index 0000000000000..22a822737934f +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c +@@ -0,0 +1,329 @@ ++/* 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; version 2 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hnat.h" ++ ++struct hnat_priv *host; ++ ++static void cr_set_bits(void __iomem * reg, u32 bs) ++{ ++ u32 val = readl(reg); ++ ++ val |= bs; ++ writel(val, reg); ++} ++ ++static void cr_clr_bits(void __iomem * reg, u32 bs) ++{ ++ u32 val = readl(reg); ++ ++ val &= ~bs; ++ writel(val, reg); ++} ++ ++static void cr_set_field(void __iomem * reg, u32 field, u32 val) ++{ ++ unsigned int tv = readl(reg); ++ ++ tv &= ~field; ++ tv |= ((val) << (ffs((unsigned int)field) - 1)); ++ writel(tv, reg); ++} ++ ++static int hnat_start(void) ++{ ++ u32 foe_table_sz; ++ ++ /* mapp the FOE table */ ++ foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry); ++ host->foe_table_cpu = ++ dma_alloc_coherent(host->dev, foe_table_sz, &host->foe_table_dev, ++ GFP_KERNEL); ++ if (!host->foe_table_cpu) ++ return -1; ++ ++ writel(host->foe_table_dev, host->ppe_base + PPE_TB_BASE); ++ memset(host->foe_table_cpu, 0, foe_table_sz); ++ ++ /* setup hashing */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ETRY_NUM, TABLE_4K); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, HASH_MODE, HASH_MODE_1); ++ writel(HASH_SEED_KEY, host->ppe_base + PPE_HASH_SEED); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, XMODE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ENTRY_SIZE, ENTRY_64B); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, SMA, SMA_FWD_CPU_BUILD_ENTRY); ++ ++ /* set ip proto */ ++ writel(0xFFFFFFFF, host->ppe_base + PPE_IP_PROT_CHK); ++ ++ /* setup caching */ ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 1); ++ ++ /* enable FOE */ ++ cr_set_bits(host->ppe_base + PPE_FLOW_CFG, ++ BIT_IPV4_NAT_EN | BIT_IPV4_NAPT_EN | ++ BIT_IPV4_NAT_FRAG_EN | BIT_IPV4_HASH_GREK); ++ ++ /* setup FOE aging */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_MNP, 1000); ++ cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_DLTA, 3); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_0, UDP_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_0, NTU_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_1, FIN_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_1, TCP_DLTA, 5); ++ ++ /* setup FOE ka */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, KA_CFG, 3); ++ cr_set_field(host->ppe_base + PPE_KA, KA_T, 1); ++ cr_set_field(host->ppe_base + PPE_KA, TCP_KA, 1); ++ cr_set_field(host->ppe_base + PPE_KA, UDP_KA, 1); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_1, NTU_KA, 1); ++ ++ /* setup FOE rate limit */ ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_0, QURT_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_0, HALF_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_1, FULL_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BNDR, BIND_RATE, 1); ++ ++ /* setup FOE cf gen */ ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 1); ++ writel(0, host->ppe_base + PPE_DFT_CPORT); // pdma ++ //writel(0x55555555, host->ppe_base + PPE_DFT_CPORT); //qdma ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, TTL0_DRP, 1); ++ ++ /* fwd packets from gmac to PPE */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_PPE); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_PPE); ++ ++ dev_info(host->dev, "hwnat start\n"); ++ ++ return 0; ++} ++ ++static int ppe_busy_wait(void) ++{ ++ unsigned long t_start = jiffies; ++ u32 r = 0; ++ ++ while (1) { ++ r = readl((host->ppe_base + 0x0)); ++ if (!(r & BIT(31))) ++ return 0; ++ if (time_after(jiffies, t_start + HZ)) ++ break; ++ usleep_range(10, 20); ++ } ++ ++ dev_err(host->dev, "ppe:%s timeout\n", __func__); ++ ++ return -1; ++} ++ ++static void hnat_stop(void) ++{ ++ u32 foe_table_sz; ++ struct foe_entry *entry, *end; ++ u32 r1 = 0, r2 = 0; ++ ++ /* discard all traffic while we disable the PPE */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_DISCARD); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_DISCARD); ++ ++ if (ppe_busy_wait()) { ++#if 0 ++ reset_control_reset(host->rstc); ++#endif ++ msleep(2000); ++ return; ++ } ++ ++ entry = host->foe_table_cpu; ++ end = host->foe_table_cpu + FOE_4TB_SIZ; ++ while (entry < end) { ++ entry->bfib1.state = INVALID; ++ entry++; ++ } ++ ++ /* disable caching */ ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 0); ++ ++ /* flush cache has to be ahead of hnat diable --*/ ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 0); ++ ++ /* disable FOE */ ++ cr_clr_bits(host->ppe_base + PPE_FLOW_CFG, ++ BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN | ++ BIT_IPV4_NAT_FRAG_EN | ++ BIT_FUC_FOE | BIT_FMC_FOE | BIT_FUC_FOE); ++ ++ /* disable FOE aging */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 0); ++ ++ r1 = readl(host->fe_base + 0x100); ++ r2 = readl(host->fe_base + 0x10c); ++ ++ dev_info(host->dev, "0x100 = 0x%x, 0x10c = 0x%x\n", r1, r2); ++ ++ if (((r1 & 0xff00) >> 0x8) >= (r1 & 0xff) || ++ ((r1 & 0xff00) >> 0x8) >= (r2 & 0xff)) { ++ dev_info(host->dev, "reset pse\n"); ++ writel(0x1, host->fe_base + 0x4); ++ } ++ ++ /* free the FOE table */ ++ foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry); ++ dma_free_coherent(NULL, foe_table_sz, host->foe_table_cpu, ++ host->foe_table_dev); ++ writel(0, host->ppe_base + PPE_TB_BASE); ++ ++ if (ppe_busy_wait()) { ++#if 0 ++ reset_control_reset(host->rstc); ++#endif ++ msleep(2000); ++ return; ++ } ++ ++ /* send all traffic back to the DMA engine */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_CPU_PDMA); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_CPU_PDMA); ++} ++ ++static int hnat_probe(struct platform_device *pdev) ++{ ++ struct net *net; ++ int ret; ++ int err = 0; ++ struct resource *res ; ++ const char *name; ++ struct device_node *np; ++ ++ host = devm_kzalloc(&pdev->dev, sizeof(struct hnat_priv), GFP_KERNEL); ++ if (!host) ++ return -ENOMEM; ++ ++ host->dev = &pdev->dev; ++ np = host->dev->of_node; ++ ++ err = of_property_read_string(np, "mtketh-wan", &name); ++ if (err < 0) ++ return -EINVAL; ++ ++ memcpy(host->wan, (char *)name, IFNAMSIZ); ++ dev_info(&pdev->dev, "wan = %s\n", host->wan); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ host->fe_base = devm_ioremap_nocache(&pdev->dev, res->start, ++ res->end - res->start + 1); ++ if (!host->fe_base) ++ return -EADDRNOTAVAIL; ++ ++ host->ppe_base = host->fe_base + 0xe00; ++ err = hnat_init_debugfs(host); ++ if (err) ++ return err; ++#if 0 ++ host->rstc = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(host->rstc)) ++ return PTR_ERR(host->rstc); ++#endif ++ err = hnat_start(); ++ if (err) ++ goto err_out; ++ ++ //err = hnat_register_nf_hooks(); //how to call the function with net-param?? ++ for_each_net(net) { ++ ret=hnat_register_nf_hooks(net); ++ //if (err) ++ if (ret && ret != -ENOENT) ++ goto err_out; ++ } ++ return 0; ++ ++err_out: ++ hnat_stop(); ++ hnat_deinit_debugfs(host); ++ return err; ++} ++ ++static int hnat_remove(struct platform_device *pdev) ++{ ++ struct net *net; ++ //hnat_unregister_nf_hooks(); //how to call the function with net-param?? ++ for_each_net(net) { ++ hnat_unregister_nf_hooks(net); ++ } ++ ++ hnat_stop(); ++ hnat_deinit_debugfs(host); ++ ++ return 0; ++} ++ ++const struct of_device_id of_hnat_match[] = { ++ { .compatible = "mediatek,mt7623-hnat" }, ++ {}, ++}; ++ ++static struct platform_driver hnat_driver = { ++ .probe = hnat_probe, ++ .remove = hnat_remove, ++ .driver = { ++ .name = "mediatek_soc_hnat", ++ .of_match_table = of_hnat_match, ++ }, ++}; ++ ++module_platform_driver(hnat_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_AUTHOR("John Crispin "); ++MODULE_DESCRIPTION("Mediatek Hardware NAT"); +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h +new file mode 100644 +index 0000000000000..336ebb34c325d +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h +@@ -0,0 +1,427 @@ ++/* 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; version 2 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++/*--------------------------------------------------------------------------*/ ++/* Register Offset*/ ++/*--------------------------------------------------------------------------*/ ++#define PPE_GLO_CFG 0x00 ++#define PPE_FLOW_CFG 0x04 ++#define PPE_IP_PROT_CHK 0x08 ++#define PPE_IP_PROT_0 0x0C ++#define PPE_IP_PROT_1 0x10 ++#define PPE_IP_PROT_2 0x14 ++#define PPE_IP_PROT_3 0x18 ++#define PPE_TB_CFG 0x1C ++#define PPE_TB_BASE 0x20 ++#define PPE_TB_USED 0x24 ++#define PPE_BNDR 0x28 ++#define PPE_BIND_LMT_0 0x2C ++#define PPE_BIND_LMT_1 0x30 ++#define PPE_KA 0x34 ++#define PPE_UNB_AGE 0x38 ++#define PPE_BND_AGE_0 0x3C ++#define PPE_BND_AGE_1 0x40 ++#define PPE_HASH_SEED 0x44 ++#define PPE_DFT_CPORT 0x48 ++#define PPE_MCAST_PPSE 0x84 ++#define PPE_MCAST_L_0 0x88 ++#define PPE_MCAST_H_0 0x8C ++#define PPE_MCAST_L_1 0x90 ++#define PPE_MCAST_H_1 0x94 ++#define PPE_MCAST_L_2 0x98 ++#define PPE_MCAST_H_2 0x9C ++#define PPE_MCAST_L_3 0xA0 ++#define PPE_MCAST_H_3 0xA4 ++#define PPE_MCAST_L_4 0xA8 ++#define PPE_MCAST_H_4 0xAC ++#define PPE_MCAST_L_5 0xB0 ++#define PPE_MCAST_H_5 0xB4 ++#define PPE_MCAST_L_6 0xBC ++#define PPE_MCAST_H_6 0xC0 ++#define PPE_MCAST_L_7 0xC4 ++#define PPE_MCAST_H_7 0xC8 ++#define PPE_MCAST_L_8 0xCC ++#define PPE_MCAST_H_8 0xD0 ++#define PPE_MCAST_L_9 0xD4 ++#define PPE_MCAST_H_9 0xD8 ++#define PPE_MCAST_L_A 0xDC ++#define PPE_MCAST_H_A 0xE0 ++#define PPE_MCAST_L_B 0xE4 ++#define PPE_MCAST_H_B 0xE8 ++#define PPE_MCAST_L_C 0xEC ++#define PPE_MCAST_H_C 0xF0 ++#define PPE_MCAST_L_D 0xF4 ++#define PPE_MCAST_H_D 0xF8 ++#define PPE_MCAST_L_E 0xFC ++#define PPE_MCAST_H_E 0xE0 ++#define PPE_MCAST_L_F 0x100 ++#define PPE_MCAST_H_F 0x104 ++#define PPE_MTU_DRP 0x108 ++#define PPE_MTU_VLYR_0 0x10C ++#define PPE_MTU_VLYR_1 0x110 ++#define PPE_MTU_VLYR_2 0x114 ++#define PPE_VPM_TPID 0x118 ++#define PPE_CAH_CTRL 0x120 ++#define PPE_CAH_TAG_SRH 0x124 ++#define PPE_CAH_LINE_RW 0x128 ++#define PPE_CAH_WDATA 0x12C ++#define PPE_CAH_RDATA 0x130 ++ ++#define GDMA1_FWD_CFG 0x500 ++#define GDMA2_FWD_CFG 0x1500 ++/*--------------------------------------------------------------------------*/ ++/* Register Mask*/ ++/*--------------------------------------------------------------------------*/ ++/* PPE_TB_CFG mask */ ++#define TB_ETRY_NUM (0x7 << 0) /* RW */ ++#define TB_ENTRY_SIZE (0x1 << 3) /* RW */ ++#define SMA (0x3 << 4) /* RW */ ++#define NTU_AGE (0x1 << 7) /* RW */ ++#define UNBD_AGE (0x1 << 8) /* RW */ ++#define TCP_AGE (0x1 << 9) /* RW */ ++#define UDP_AGE (0x1 << 10) /* RW */ ++#define FIN_AGE (0x1 << 11) /* RW */ ++#define KA_CFG (0x3<< 12) ++#define HASH_MODE (0x3 << 14) /* RW */ ++#define XMODE (0x3 << 18) /* RW */ ++ ++/*PPE_CAH_CTRL mask*/ ++#define CAH_EN (0x1 << 0) /* RW */ ++#define CAH_X_MODE (0x1 << 9) /* RW */ ++ ++/*PPE_UNB_AGE mask*/ ++#define UNB_DLTA (0xff << 0) /* RW */ ++#define UNB_MNP (0xffff << 16) /* RW */ ++ ++/*PPE_BND_AGE_0 mask*/ ++#define UDP_DLTA (0xffff << 0) /* RW */ ++#define NTU_DLTA (0xffff << 16) /* RW */ ++ ++/*PPE_BND_AGE_1 mask*/ ++#define TCP_DLTA (0xffff << 0) /* RW */ ++#define FIN_DLTA (0xffff << 16) /* RW */ ++ ++/*PPE_KA mask*/ ++#define KA_T (0xffff << 0) /* RW */ ++#define TCP_KA (0xff << 16) /* RW */ ++#define UDP_KA (0xff << 24) /* RW */ ++ ++/*PPE_BIND_LMT_0 mask*/ ++#define QURT_LMT (0x3ff << 0) /* RW */ ++#define HALF_LMT (0x3ff << 16) /* RW */ ++ ++/*PPE_BIND_LMT_1 mask*/ ++#define FULL_LMT (0x3fff << 0) /* RW */ ++#define NTU_KA (0xff << 16) /* RW */ ++ ++/*PPE_BNDR mask*/ ++#define BIND_RATE (0xffff << 0) /* RW */ ++#define PBND_RD_PRD (0xffff << 16) /* RW */ ++ ++/*PPE_GLO_CFG mask*/ ++#define PPE_EN (0x1 << 0) /* RW */ ++#define TTL0_DRP (0x1 << 4) /* RW */ ++ ++/*GDMA1_FWD_CFG mask */ ++#define GDM1_UFRC_MASK (0x7 << 12) /* RW */ ++#define GDM1_BFRC_MASK (0x7 << 8) /*RW*/ ++#define GDM1_MFRC_MASK (0x7 << 4) /*RW*/ ++#define GDM1_OFRC_MASK (0x7 << 0) /*RW*/ ++#define GDM1_ALL_FRC_MASK (GDM1_UFRC_MASK | GDM1_BFRC_MASK | GDM1_MFRC_MASK | GDM1_OFRC_MASK) ++ ++#define GDM2_UFRC_MASK (0x7 << 12) /* RW */ ++#define GDM2_BFRC_MASK (0x7 << 8) /*RW*/ ++#define GDM2_MFRC_MASK (0x7 << 4) /*RW*/ ++#define GDM2_OFRC_MASK (0x7 << 0) /*RW*/ ++#define GDM2_ALL_FRC_MASK (GDM2_UFRC_MASK | GDM2_BFRC_MASK | GDM2_MFRC_MASK | GDM2_OFRC_MASK) ++ ++/*--------------------------------------------------------------------------*/ ++/* Descriptor Structure */ ++/*--------------------------------------------------------------------------*/ ++#define HNAT_SKB_CB(__skb) ((struct hnat_skb_cb *)&((__skb)->cb[40])) ++struct hnat_skb_cb { ++ __u16 iif; ++}; ++ ++struct hnat_unbind_info_blk { ++ u32 time_stamp:8; ++ u32 pcnt:16; /* packet count */ ++ u32 preb:1; ++ u32 pkt_type:3; ++ u32 state:2; ++ u32 udp:1; ++ u32 sta:1; /* static entry */ ++} __attribute__ ((packed)); ++ ++struct hnat_bind_info_blk { ++ u32 time_stamp:15; ++ u32 ka:1; /* keep alive */ ++ u32 vlan_layer:3; ++ u32 psn:1; /* egress packet has PPPoE session */ ++ u32 vpm:1; /* 0:ethertype remark, 1:0x8100(CR default) */ ++ u32 ps:1; /* packet sampling */ ++ u32 cah:1; /* cacheable flag */ ++ u32 rmt:1; /* remove tunnel ip header (6rd/dslite only) */ ++ u32 ttl:1; ++ u32 pkt_type:3; ++ u32 state:2; ++ u32 udp:1; ++ u32 sta:1; /* static entry */ ++} __attribute__ ((packed)); ++ ++struct hnat_info_blk2 { ++ u32 qid:4; /* QID in Qos Port */ ++ u32 fqos:1; /* force to PSE QoS port */ ++ u32 dp:3; /* force to PSE port x ++ 0:PSE,1:GSW, 2:GMAC,4:PPE,5:QDMA,7=DROP */ ++ u32 mcast:1; /* multicast this packet to CPU */ ++ u32 pcpl:1; /* OSBN */ ++ u32 mlen:1; /* 0:post 1:pre packet length in meter */ ++ u32 alen:1; /* 0:post 1:pre packet length in accounting */ ++ u32 port_mg:6; /* port meter group */ ++ u32 port_ag:6; /* port account group */ ++ u32 dscp:8; /* DSCP value */ ++} __attribute__ ((packed)); ++ ++struct hnat_ipv4_hnapt { ++ union { ++ struct hnat_bind_info_blk bfib1; ++ struct hnat_unbind_info_blk udib1; ++ u32 info_blk1; ++ }; ++ u32 sip; ++ u32 dip; ++ u16 dport; ++ u16 sport; ++ union { ++ struct hnat_info_blk2 iblk2; ++ u32 info_blk2; ++ }; ++ u32 new_sip; ++ u32 new_dip; ++ u16 new_dport; ++ u16 new_sport; ++ u32 resv1; ++ u32 resv2; ++ u32 resv3:26; ++ u32 act_dp:6; /* UDF */ ++ u16 vlan1; ++ u16 etype; ++ u32 dmac_hi; ++ u16 vlan2; ++ u16 dmac_lo; ++ u32 smac_hi; ++ u16 pppoe_id; ++ u16 smac_lo; ++} __attribute__ ((packed)); ++ ++struct foe_entry { ++ union { ++ struct hnat_unbind_info_blk udib1; ++ struct hnat_bind_info_blk bfib1; ++ struct hnat_ipv4_hnapt ipv4_hnapt; ++ }; ++}; ++ ++#define HNAT_AC_BYTE_LO(x) (0x2000 + (x * 16)) ++#define HNAT_AC_BYTE_HI(x) (0x2004 + (x * 16)) ++#define HNAT_AC_PACKET(x) (0x2008 + (x * 16)) ++#define HNAT_COUNTER_MAX 64 ++#define HNAT_AC_TIMER_INTERVAL (HZ) ++ ++struct hnat_accounting { ++ u64 bytes; ++ u64 packets; ++}; ++ ++struct hnat_priv { ++ struct device *dev; ++ void __iomem *fe_base; ++ void __iomem *ppe_base; ++ struct foe_entry *foe_table_cpu; ++ dma_addr_t foe_table_dev; ++ u8 enable; ++ u8 enable1; ++ struct dentry *root; ++ struct debugfs_regset32 *regset; ++ ++ struct timer_list ac_timer; ++ struct hnat_accounting acct[HNAT_COUNTER_MAX]; ++ ++ /*devices we plays for*/ ++ char wan[IFNAMSIZ]; ++ ++ struct reset_control *rstc; ++}; ++ ++enum FoeEntryState { ++ INVALID = 0, ++ UNBIND = 1, ++ BIND = 2, ++ FIN = 3 ++}; ++/*--------------------------------------------------------------------------*/ ++/* Common Definition*/ ++/*--------------------------------------------------------------------------*/ ++ ++#define FOE_4TB_SIZ 4096 ++#define HASH_SEED_KEY 0x12345678 ++ ++/*PPE_TB_CFG value*/ ++#define ENTRY_80B 1 ++#define ENTRY_64B 0 ++#define TABLE_1K 0 ++#define TABLE_2K 1 ++#define TABLE_4K 2 ++#define TABLE_8K 3 ++#define TABLE_16K 4 ++#define SMA_DROP 0 /* Drop the packet */ ++#define SMA_DROP2 1 /* Drop the packet */ ++#define SMA_ONLY_FWD_CPU 2 /* Only Forward to CPU */ ++#define SMA_FWD_CPU_BUILD_ENTRY 3 /* Forward to CPU and build new FOE entry */ ++#define HASH_MODE_0 0 ++#define HASH_MODE_1 1 ++#define HASH_MODE_2 2 ++#define HASH_MODE_3 3 ++ ++/*PPE_FLOW_CFG*/ ++#define BIT_FUC_FOE BIT(2) ++#define BIT_FMC_FOE BIT(1) ++#define BIT_FBC_FOE BIT(0) ++#define BIT_IPV4_NAT_EN BIT(12) ++#define BIT_IPV4_NAPT_EN BIT(13) ++#define BIT_IPV4_NAT_FRAG_EN BIT(17) ++#define BIT_IPV4_HASH_GREK BIT(19) ++ ++/*GDMA1_FWD_CFG value */ ++#define BITS_GDM1_UFRC_P_PPE (NR_PPE_PORT << 12) ++#define BITS_GDM1_BFRC_P_PPE (NR_PPE_PORT << 8) ++#define BITS_GDM1_MFRC_P_PPE (NR_PPE_PORT << 4) ++#define BITS_GDM1_OFRC_P_PPE (NR_PPE_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_PPE (BITS_GDM1_UFRC_P_PPE | BITS_GDM1_BFRC_P_PPE | BITS_GDM1_MFRC_P_PPE | BITS_GDM1_OFRC_P_PPE) ++ ++#define BITS_GDM1_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12) ++#define BITS_GDM1_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8) ++#define BITS_GDM1_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4) ++#define BITS_GDM1_OFRC_P_CPU_PDMA (NR_PDMA_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_CPU_PDMA (BITS_GDM1_UFRC_P_CPU_PDMA | BITS_GDM1_BFRC_P_CPU_PDMA | BITS_GDM1_MFRC_P_CPU_PDMA | BITS_GDM1_OFRC_P_CPU_PDMA) ++ ++#define BITS_GDM1_UFRC_P_CPU_QDMA (NR_QDMA_PORT << 12) ++#define BITS_GDM1_BFRC_P_CPU_QDMA (NR_QDMA_PORT << 8) ++#define BITS_GDM1_MFRC_P_CPU_QDMA (NR_QDMA_PORT << 4) ++#define BITS_GDM1_OFRC_P_CPU_QDMA (NR_QDMA_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_CPU_QDMA (BITS_GDM1_UFRC_P_CPU_QDMA | BITS_GDM1_BFRC_P_CPU_QDMA | BITS_GDM1_MFRC_P_CPU_QDMA | BITS_GDM1_OFRC_P_CPU_QDMA) ++ ++#define BITS_GDM1_UFRC_P_DISCARD (NR_DISCARD << 12) ++#define BITS_GDM1_BFRC_P_DISCARD (NR_DISCARD << 8) ++#define BITS_GDM1_MFRC_P_DISCARD (NR_DISCARD << 4) ++#define BITS_GDM1_OFRC_P_DISCARD (NR_DISCARD << 0) ++#define BITS_GDM1_ALL_FRC_P_DISCARD (BITS_GDM1_UFRC_P_DISCARD | BITS_GDM1_BFRC_P_DISCARD | BITS_GDM1_MFRC_P_DISCARD | BITS_GDM1_OFRC_P_DISCARD) ++ ++#define BITS_GDM2_UFRC_P_PPE (NR_PPE_PORT << 12) ++#define BITS_GDM2_BFRC_P_PPE (NR_PPE_PORT << 8) ++#define BITS_GDM2_MFRC_P_PPE (NR_PPE_PORT << 4) ++#define BITS_GDM2_OFRC_P_PPE (NR_PPE_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_PPE (BITS_GDM2_UFRC_P_PPE | BITS_GDM2_BFRC_P_PPE | BITS_GDM2_MFRC_P_PPE | BITS_GDM2_OFRC_P_PPE) ++ ++#define BITS_GDM2_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12) ++#define BITS_GDM2_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8) ++#define BITS_GDM2_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4) ++#define BITS_GDM2_OFRC_P_CPU_PDMA (NR_PDMA_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_CPU_PDMA (BITS_GDM2_UFRC_P_CPU_PDMA | BITS_GDM2_BFRC_P_CPU_PDMA | BITS_GDM2_MFRC_P_CPU_PDMA | BITS_GDM2_OFRC_P_CPU_PDMA) ++ ++#define BITS_GDM2_UFRC_P_CPU_QDMA (NR_QDMA_PORT << 12) ++#define BITS_GDM2_BFRC_P_CPU_QDMA (NR_QDMA_PORT << 8) ++#define BITS_GDM2_MFRC_P_CPU_QDMA (NR_QDMA_PORT << 4) ++#define BITS_GDM2_OFRC_P_CPU_QDMA (NR_QDMA_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_CPU_QDMA (BITS_GDM2_UFRC_P_CPU_QDMA | BITS_GDM2_BFRC_P_CPU_QDMA | BITS_GDM2_MFRC_P_CPU_QDMA | BITS_GDM2_OFRC_P_CPU_QDMA) ++ ++#define BITS_GDM2_UFRC_P_DISCARD (NR_DISCARD << 12) ++#define BITS_GDM2_BFRC_P_DISCARD (NR_DISCARD << 8) ++#define BITS_GDM2_MFRC_P_DISCARD (NR_DISCARD << 4) ++#define BITS_GDM2_OFRC_P_DISCARD (NR_DISCARD << 0) ++#define BITS_GDM2_ALL_FRC_P_DISCARD (BITS_GDM2_UFRC_P_DISCARD | BITS_GDM2_BFRC_P_DISCARD | BITS_GDM2_MFRC_P_DISCARD | BITS_GDM2_OFRC_P_DISCARD) ++ ++#define hnat_is_enabled(host) (host->enable) ++#define hnat_enabled(host) (host->enable = 1) ++#define hnat_disabled(host) (host->enable = 0) ++#define hnat_is_enabled1(host) (host->enable1) ++#define hnat_enabled1(host) (host->enable1 = 1) ++#define hnat_disabled1(host) (host->enable1 = 0) ++ ++#define entry_hnat_is_bound(e) (e->bfib1.state == BIND) ++#define entry_hnat_state(e) (e->bfib1.state) ++ ++#define skb_hnat_is_hashed(skb) (skb_hnat_entry(skb)!=0x3fff && skb_hnat_entry(skb)< FOE_4TB_SIZ) ++#define FROM_GE_LAN(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_LAN) ++#define FROM_GE_WAN(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_WAN) ++#define FROM_GE_PPD(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_PPD) ++#define FOE_MAGIC_GE_WAN 0x7273 ++#define FOE_MAGIC_GE_LAN 0x7272 ++#define FOE_INVALID 0xffff ++ ++#define TCP_FIN_SYN_RST 0x0C /* Ingress packet is TCP fin/syn/rst (for IPv4 NAPT/DS-Lite or IPv6 5T-route/6RD) */ ++#define UN_HIT 0x0D/* FOE Un-hit */ ++#define HIT_UNBIND 0x0E/* FOE Hit unbind */ ++#define HIT_UNBIND_RATE_REACH 0xf ++#define HNAT_HIT_BIND_OLD_DUP_HDR 0x15 ++#define HNAT_HIT_BIND_FORCE_TO_CPU 0x16 ++ ++#define HIT_BIND_KEEPALIVE_MC_NEW_HDR 0x14 ++#define HIT_BIND_KEEPALIVE_DUP_OLD_HDR 0x15 ++#define IPV4_HNAPT 0 ++#define IPV4_HNAT 1 ++#define IP_FORMAT(addr) \ ++ ((unsigned char *)&addr)[3], \ ++ ((unsigned char *)&addr)[2], \ ++ ((unsigned char *)&addr)[1], \ ++ ((unsigned char *)&addr)[0] ++ ++/*PSE Ports*/ ++#define NR_PDMA_PORT 0 ++#define NR_GMAC1_PORT 1 ++#define NR_GMAC2_PORT 2 ++#define NR_PPE_PORT 4 ++#define NR_QDMA_PORT 5 ++#define NR_DISCARD 7 ++#define IS_LAN(dev) (!strncmp(dev->name, "lan", 3)) ++#define IS_WAN(dev) (!strcmp(dev->name, host->wan)) ++#define IS_BR(dev) (!strncmp(dev->name, "br", 2)) ++#define IS_IPV4_HNAPT(x) (((x)->bfib1.pkt_type == IPV4_HNAPT) ? 1: 0) ++#define IS_IPV4_HNAT(x) (((x)->bfib1.pkt_type == IPV4_HNAT) ? 1 : 0) ++#define IS_IPV4_GRP(x) (IS_IPV4_HNAPT(x) | IS_IPV4_HNAT(x)) ++ ++#define es(entry) (entry_state[entry->bfib1.state]) ++#define ei(entry, end) (FOE_4TB_SIZ - (int)(end - entry)) ++#define pt(entry) (packet_type[entry->ipv4_hnapt.bfib1.pkt_type]) ++#define ipv4_smac(mac,e) ({mac[0]=e->ipv4_hnapt.smac_hi[3]; mac[1]=e->ipv4_hnapt.smac_hi[2];\ ++ mac[2]=e->ipv4_hnapt.smac_hi[1]; mac[3]=e->ipv4_hnapt.smac_hi[0];\ ++ mac[4]=e->ipv4_hnapt.smac_lo[1]; mac[5]=e->ipv4_hnapt.smac_lo[0];}) ++#define ipv4_dmac(mac,e) ({mac[0]=e->ipv4_hnapt.dmac_hi[3]; mac[1]=e->ipv4_hnapt.dmac_hi[2];\ ++ mac[2]=e->ipv4_hnapt.dmac_hi[1]; mac[3]=e->ipv4_hnapt.dmac_hi[0];\ ++ mac[4]=e->ipv4_hnapt.dmac_lo[1]; mac[5]=e->ipv4_hnapt.dmac_lo[0];}) ++ ++extern struct hnat_priv *host; ++ ++extern void hnat_deinit_debugfs(struct hnat_priv *h); ++extern int hnat_init_debugfs(struct hnat_priv *h); ++//extern int hnat_register_nf_hooks(void); ++//extern void hnat_unregister_nf_hooks(void); ++extern int hnat_register_nf_hooks(struct net *net); ++extern void hnat_unregister_nf_hooks(struct net *net); ++ +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c +new file mode 100644 +index 0000000000000..fbb0380ea0d92 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c +@@ -0,0 +1,489 @@ ++/* 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; version 2 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++ ++#include "hnat.h" ++ ++static const char *entry_state[] = { ++ "INVALID", ++ "UNBIND", ++ "BIND", ++ "FIN" ++}; ++ ++static const char *packet_type[] = { ++ "IPV4_HNAPT", ++ "IPV4_HNAT", ++ "IPV6_1T_ROUTE", ++ "IPV4_DSLITE", ++ "IPV6_3T_ROUTE", ++ "IPV6_5T_ROUTE", ++ "IPV6_6RD", ++}; ++ ++static int hnat_debug_show(struct seq_file *m, void *private) ++{ ++ struct hnat_priv *h = host; ++ struct foe_entry *entry, *end; ++ ++ entry = h->foe_table_cpu; ++ end = h->foe_table_cpu + FOE_4TB_SIZ; ++ while (entry < end) { ++ if (!entry->bfib1.state) { ++ entry++; ++ continue; ++ } ++ ++ if (IS_IPV4_HNAPT(entry)) { ++ __be32 saddr = htonl(entry->ipv4_hnapt.sip); ++ __be32 daddr = htonl(entry->ipv4_hnapt.dip); ++ __be32 nsaddr = htonl(entry->ipv4_hnapt.new_sip); ++ __be32 ndaddr = htonl(entry->ipv4_hnapt.new_dip); ++ unsigned char h_dest[ETH_ALEN]; ++ unsigned char h_source[ETH_ALEN]; ++ ++ *((u32*) h_source) = swab32(entry->ipv4_hnapt.smac_hi); ++ *((u16*) &h_source[4]) = swab16(entry->ipv4_hnapt.smac_lo); ++ *((u32*) h_dest) = swab32(entry->ipv4_hnapt.dmac_hi); ++ *((u16*) &h_dest[4]) = swab16(entry->ipv4_hnapt.dmac_lo); ++ seq_printf(m, ++ "(%p)0x%05x|state=%s|type=%s|%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x|vlan1=%d|vlan2=%d\n", ++ (void *)h->foe_table_dev + ((void *)(entry) - (void *)h->foe_table_cpu), ++ ei(entry, end), es(entry), pt(entry), ++ &saddr, entry->ipv4_hnapt.sport, ++ &daddr, entry->ipv4_hnapt.dport, ++ &nsaddr, entry->ipv4_hnapt.new_sport, ++ &ndaddr, entry->ipv4_hnapt.new_dport, h_source, ++ h_dest, ntohs(entry->ipv4_hnapt.etype), ++ entry->ipv4_hnapt.info_blk1, ++ entry->ipv4_hnapt.info_blk2, ++ entry->ipv4_hnapt.vlan1, ++ entry->ipv4_hnapt.vlan2); ++ } else ++ seq_printf(m, "0x%05x state=%s\n", ++ ei(entry, end), es(entry)); ++ entry++; ++ } ++ ++ return 0; ++} ++ ++static int hnat_debug_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, hnat_debug_show, file->private_data); ++} ++ ++static const struct file_operations hnat_debug_fops = { ++ .open = hnat_debug_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++#define QDMA_TX_SCH_TX 0x1a14 ++ ++static ssize_t hnat_sched_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX); ++ int enable; ++ int max_rate; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ ++ if (id) ++ reg >>= 16; ++ reg &= 0xffff; ++ enable = !! (reg & BIT(11)); ++ max_rate = ((reg >> 4) & 0x7f); ++ reg &= 0xf; ++ while (reg--) ++ max_rate *= 10; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "EN\tMAX\n%d\t%d\n", enable, max_rate); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static ssize_t hnat_sched_write(struct file *file, ++ const char __user *buf, size_t length, loff_t *offset) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ char line[64]; ++ int enable, rate, exp = 0, shift = 0; ++ size_t size; ++ u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX); ++ u32 val = 0; ++ ++ if (length > sizeof(line)) ++ return -EINVAL; ++ ++ if (copy_from_user(line, buf, length)) ++ return -EFAULT; ++ ++ sscanf(line, "%d %d", &enable, &rate); ++ ++ while (rate > 127) { ++ rate /= 10; ++ exp++; ++ } ++ ++ if (enable) ++ val |= BIT(11); ++ val |= (rate & 0x7f) << 4; ++ val |= exp & 0xf; ++ if (id) ++ shift = 16; ++ reg &= ~(0xffff << shift); ++ reg |= val << shift; ++ writel(reg, h->fe_base + QDMA_TX_SCH_TX); ++ ++ size = strlen(line); ++ *offset += size; ++ ++ return length; ++} ++ ++static const struct file_operations hnat_sched_fops = { ++ .open = simple_open, ++ .read = hnat_sched_show, ++ .write = hnat_sched_write, ++ .llseek = default_llseek, ++}; ++ ++#define QTX_CFG(x) (0x1800 + (x * 0x10)) ++#define QTX_SCH(x) (0x1804 + (x * 0x10)) ++ ++static ssize_t hnat_queue_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct hnat_priv *h = host; ++ int id = (int) file->private_data; ++ u32 reg = readl(h->fe_base + QTX_SCH(id)); ++ u32 cfg = readl(h->fe_base + QTX_CFG(id)); ++ int scheduler = !!(reg & BIT(31)); ++ int min_rate_en = !!(reg & BIT(27)); ++ int min_rate = (reg >> 20) & 0x7f; ++ int min_rate_exp = (reg >> 16) & 0xf; ++ int max_rate_en = !!(reg & BIT(11)); ++ int max_weight = (reg >> 12) & 0xf; ++ int max_rate = (reg >> 4) & 0x7f; ++ int max_rate_exp = reg & 0xf; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ while (min_rate_exp--) ++ min_rate *= 10; ++ ++ while (max_rate_exp--) ++ max_rate *= 10; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "scheduler: %d\nhw resv: %d\nsw resv: %d\n", ++ scheduler, (cfg >> 8) & 0xff, cfg & 0xff); ++ len += scnprintf(buf + len, buf_len - len, ++ "\tEN\tRATE\t\tWEIGHT\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "max\t%d\t%8d\t%d\n", max_rate_en, max_rate, max_weight); ++ len += scnprintf(buf + len, buf_len - len, ++ "min\t%d\t%8d\t-\n", min_rate_en, min_rate); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static ssize_t hnat_queue_write(struct file *file, ++ const char __user *buf, size_t length, loff_t *offset) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ char line[64]; ++ int max_enable, max_rate, max_exp = 0; ++ int min_enable, min_rate, min_exp = 0; ++ int weight; ++ int resv; ++ int scheduler; ++ size_t size; ++ u32 reg = readl(h->fe_base + QTX_SCH(id)); ++ ++ if (length > sizeof(line)) ++ return -EINVAL; ++ ++ if (copy_from_user(line, buf, length)) ++ return -EFAULT; ++ ++ sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate, &max_enable, &max_rate, &weight, &resv); ++ ++ while (max_rate > 127) { ++ max_rate /= 10; ++ max_exp++; ++ } ++ ++ while (min_rate > 127) { ++ min_rate /= 10; ++ min_exp++; ++ } ++ ++ reg &= 0x70000000; ++ if (scheduler) ++ reg |= BIT(31); ++ if (min_enable) ++ reg |= BIT(27); ++ reg |= (min_rate & 0x7f) << 20; ++ reg |= (min_exp & 0xf) << 16; ++ if (max_enable) ++ reg |= BIT(11); ++ reg |= (weight & 0xf) << 12; ++ reg |= (max_rate & 0x7f) << 4; ++ reg |= max_exp & 0xf; ++ writel(reg, h->fe_base + QTX_SCH(id)); ++ ++ resv &= 0xff; ++ reg = readl(h->fe_base + QTX_CFG(id)); ++ reg &= 0xffff0000; ++ reg |= (resv << 8) | resv; ++ writel(reg, h->fe_base + QTX_CFG(id)); ++ ++ size = strlen(line); ++ *offset += size; ++ ++ return length; ++} ++ ++static const struct file_operations hnat_queue_fops = { ++ .open = simple_open, ++ .read = hnat_queue_show, ++ .write = hnat_queue_write, ++ .llseek = default_llseek, ++}; ++ ++static void hnat_ac_timer_handle(unsigned long priv) ++{ ++ struct hnat_priv *h = (struct hnat_priv*) priv; ++ int i; ++ ++ for (i = 0; i < HNAT_COUNTER_MAX; i++) { ++ u32 b_hi, b_lo; ++ u64 b; ++ ++ b_lo = readl(h->fe_base + HNAT_AC_BYTE_LO(i)); ++ b_hi = readl(h->fe_base + HNAT_AC_BYTE_HI(i)); ++ b = b_hi; ++ b <<= 32; ++ b += b_lo; ++ h->acct[i].bytes += b; ++ h->acct[i].packets += readl(h->fe_base + HNAT_AC_PACKET(i)); ++ } ++ ++ mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL); ++} ++ ++static ssize_t hnat_counter_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct hnat_priv *h = host; ++ int id = (int) file->private_data; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ int id2 = id + (HNAT_COUNTER_MAX / 2); ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "tx pkts : %llu\ntx bytes: %llu\nrx pktks : %llu\nrx bytes : %llu\n", ++ h->acct[id].packets, h->acct[id].bytes, ++ h->acct[id2].packets, h->acct[id2].bytes); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static const struct file_operations hnat_counter_fops = { ++ .open = simple_open, ++ .read = hnat_counter_show, ++ .llseek = default_llseek, ++}; ++ ++#define dump_register(nm) \ ++{ \ ++ .name = __stringify(nm), \ ++ .offset = PPE_ ##nm , \ ++} ++ ++static const struct debugfs_reg32 hnat_regs[] = { ++ dump_register(GLO_CFG), ++ dump_register(FLOW_CFG), ++ dump_register(IP_PROT_CHK), ++ dump_register(IP_PROT_0), ++ dump_register(IP_PROT_1), ++ dump_register(IP_PROT_2), ++ dump_register(IP_PROT_3), ++ dump_register(TB_CFG), ++ dump_register(TB_BASE), ++ dump_register(TB_USED), ++ dump_register(BNDR), ++ dump_register(BIND_LMT_0), ++ dump_register(BIND_LMT_1), ++ dump_register(KA), ++ dump_register(UNB_AGE), ++ dump_register(BND_AGE_0), ++ dump_register(BND_AGE_1), ++ dump_register(HASH_SEED), ++ dump_register(DFT_CPORT), ++ dump_register(MCAST_PPSE), ++ dump_register(MCAST_L_0), ++ dump_register(MCAST_H_0), ++ dump_register(MCAST_L_1), ++ dump_register(MCAST_H_1), ++ dump_register(MCAST_L_2), ++ dump_register(MCAST_H_2), ++ dump_register(MCAST_L_3), ++ dump_register(MCAST_H_3), ++ dump_register(MCAST_L_4), ++ dump_register(MCAST_H_4), ++ dump_register(MCAST_L_5), ++ dump_register(MCAST_H_5), ++ dump_register(MCAST_L_6), ++ dump_register(MCAST_H_6), ++ dump_register(MCAST_L_7), ++ dump_register(MCAST_H_7), ++ dump_register(MCAST_L_8), ++ dump_register(MCAST_H_8), ++ dump_register(MCAST_L_9), ++ dump_register(MCAST_H_9), ++ dump_register(MCAST_L_A), ++ dump_register(MCAST_H_A), ++ dump_register(MCAST_L_B), ++ dump_register(MCAST_H_B), ++ dump_register(MCAST_L_C), ++ dump_register(MCAST_H_C), ++ dump_register(MCAST_L_D), ++ dump_register(MCAST_H_D), ++ dump_register(MCAST_L_E), ++ dump_register(MCAST_H_E), ++ dump_register(MCAST_L_F), ++ dump_register(MCAST_H_F), ++ dump_register(MTU_DRP), ++ dump_register(MTU_VLYR_0), ++ dump_register(MTU_VLYR_1), ++ dump_register(MTU_VLYR_2), ++ dump_register(VPM_TPID), ++ dump_register(VPM_TPID), ++ dump_register(CAH_CTRL), ++ dump_register(CAH_TAG_SRH), ++ dump_register(CAH_LINE_RW), ++ dump_register(CAH_WDATA), ++ dump_register(CAH_RDATA), ++}; ++ ++int hnat_init_debugfs(struct hnat_priv *h) ++{ ++ int ret = 0; ++ struct dentry *root; ++ struct dentry *file; ++ int i; ++ char name[16]; ++ ++ root = debugfs_create_dir("hnat", NULL); ++ if (!root) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err0; ++ } ++ h->root = root; ++ h->regset = kzalloc(sizeof(*h->regset), GFP_KERNEL); ++ if (!h->regset) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ h->regset->regs = hnat_regs; ++ h->regset->nregs = ARRAY_SIZE(hnat_regs); ++ h->regset->base = h->ppe_base; ++ ++ file = debugfs_create_regset32("regdump", S_IRUGO, root, h->regset); ++ if (!file) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ debugfs_create_file("all_entry", S_IRUGO, root, h, &hnat_debug_fops); ++ for (i = 0; i < HNAT_COUNTER_MAX / 2; i++) { ++ snprintf(name, sizeof(name), "counter%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_counter_fops); ++ } ++ ++ for (i = 0; i < 2; i++) { ++ snprintf(name, sizeof(name), "scheduler%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_sched_fops); ++ } ++ ++ for (i = 0; i < 16; i++) { ++ snprintf(name, sizeof(name), "queue%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_queue_fops); ++ } ++ ++ setup_timer(&h->ac_timer, hnat_ac_timer_handle, (unsigned long) h); ++ mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL); ++ ++ return 0; ++ ++ err1: ++ debugfs_remove_recursive(root); ++ err0: ++ return ret; ++} ++ ++void hnat_deinit_debugfs(struct hnat_priv *h) ++{ ++ del_timer(&h->ac_timer); ++ debugfs_remove_recursive(h->root); ++ h->root = NULL; ++} +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c +new file mode 100644 +index 0000000000000..0ce436ac00e61 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c +@@ -0,0 +1,312 @@ ++/* 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; version 2 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "nf_hnat_mtk.h" ++#include "hnat.h" ++ ++#include "../mtk_eth_soc.h" ++ ++static unsigned int skb_to_hnat_info(struct sk_buff *skb, ++ const struct net_device *dev, ++ struct foe_entry *foe) ++{ ++ struct foe_entry entry = { 0 }; ++ int lan = IS_LAN(dev); ++ int wan = IS_WAN(dev); ++ struct ethhdr *eth; ++ struct iphdr *iph; ++ struct tcphdr *tcph; ++ struct udphdr *udph; ++ int tcp = 0; ++ int ipv4 = 0; ++ u32 gmac; ++ ++ eth = eth_hdr(skb); ++ switch (ntohs(eth->h_proto)) { ++ case ETH_P_IP: ++ ipv4 = 1; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ iph = ip_hdr(skb); ++ switch (iph->protocol) { ++ case IPPROTO_TCP: ++ tcph = tcp_hdr(skb); ++ tcp = 1; ++ break; ++ ++ case IPPROTO_UDP: ++ udph = udp_hdr(skb); ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ entry.ipv4_hnapt.etype = htons(ETH_P_IP); ++ ++ if (lan) { ++ entry.ipv4_hnapt.etype = htons(ETH_P_8021Q); ++ entry.bfib1.vlan_layer = 1; ++ ++ /* lan0-port1, lan1-port2, lan2-port3, lan3-port4 */ ++ entry.ipv4_hnapt.vlan1 = BIT((dev->name[3] - '0')+1); ++ } else if (wan) { ++ entry.ipv4_hnapt.etype = htons(ETH_P_8021Q); ++ entry.bfib1.vlan_layer = 1; ++ ++ /* wan port 0 */ ++ entry.ipv4_hnapt.vlan1 = BIT(0); ++ } ++ ++ if (dev->priv_flags & IFF_802_1Q_VLAN) { ++ struct vlan_dev_priv *vlan = vlan_dev_priv(dev); ++ ++ entry.ipv4_hnapt.etype = htons(ETH_P_8021Q); ++ entry.bfib1.vlan_layer = 1; ++ entry.ipv4_hnapt.vlan2 = vlan->vlan_id; ++ } ++ ++ entry.ipv4_hnapt.dmac_hi = swab32(*((u32*) eth->h_dest)); ++ entry.ipv4_hnapt.dmac_lo = swab16(*((u16*) ð->h_dest[4])); ++ entry.ipv4_hnapt.smac_hi = swab32(*((u32*) eth->h_source)); ++ entry.ipv4_hnapt.smac_lo = swab16(*((u16*) ð->h_source[4])); ++ entry.ipv4_hnapt.pppoe_id = 0; ++ entry.bfib1.psn = 0; ++ entry.ipv4_hnapt.bfib1.vpm = 1; ++ ++ if (ipv4) ++ entry.ipv4_hnapt.bfib1.pkt_type = IPV4_HNAPT; ++ ++ entry.ipv4_hnapt.new_sip = ntohl(iph->saddr); ++ entry.ipv4_hnapt.new_dip = ntohl(iph->daddr); ++ entry.ipv4_hnapt.iblk2.dscp = iph->tos; ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ entry.ipv4_hnapt.iblk2.qid = skb->mark & 0x7; ++ if (lan) ++ entry.ipv4_hnapt.iblk2.qid += 8; ++ entry.ipv4_hnapt.iblk2.fqos = 1; ++#endif ++ if (tcp) { ++ entry.ipv4_hnapt.new_sport = ntohs(tcph->source); ++ entry.ipv4_hnapt.new_dport = ntohs(tcph->dest); ++ entry.ipv4_hnapt.bfib1.udp = 0; ++ } else { ++ entry.ipv4_hnapt.new_sport = ntohs(udph->source); ++ entry.ipv4_hnapt.new_dport = ntohs(udph->dest); ++ entry.ipv4_hnapt.bfib1.udp = 1; ++ } ++ ++ if (IS_LAN(dev)) ++ gmac = NR_GMAC1_PORT; ++ else if (IS_WAN(dev)) ++ gmac = NR_GMAC2_PORT; ++ ++ if (is_multicast_ether_addr(ð->h_dest[0])) ++ entry.ipv4_hnapt.iblk2.mcast = 1; ++ else ++ entry.ipv4_hnapt.iblk2.mcast = 0; ++ ++ entry.ipv4_hnapt.iblk2.dp = gmac; ++ entry.ipv4_hnapt.iblk2.port_mg = 0x3f; ++ entry.ipv4_hnapt.iblk2.port_ag = (skb->mark >> 3) & 0x1f; ++ if (IS_LAN(dev)) ++ entry.ipv4_hnapt.iblk2.port_ag += 32; ++ entry.bfib1.time_stamp = readl((host->fe_base + 0x0010)) & (0xFFFF); ++ entry.ipv4_hnapt.bfib1.ttl = 1; ++ entry.ipv4_hnapt.bfib1.cah = 1; ++ entry.ipv4_hnapt.bfib1.ka = 1; ++ entry.bfib1.state = BIND; ++ ++ entry.ipv4_hnapt.sip = foe->ipv4_hnapt.sip; ++ entry.ipv4_hnapt.dip = foe->ipv4_hnapt.dip; ++ entry.ipv4_hnapt.sport = foe->ipv4_hnapt.sport; ++ entry.ipv4_hnapt.dport = foe->ipv4_hnapt.dport; ++ ++ memcpy(foe, &entry, sizeof(entry)); ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_nf_post_routing(struct sk_buff *skb, ++ const struct net_device *out, ++ unsigned int (*fn)(struct sk_buff *, const struct net_device *), ++ const char *func) ++{ ++ struct foe_entry *entry; ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++ const struct nf_conn_help *help; ++ ++#if 0 ++ if ((skb->mark & 0x7) < 4) ++ return 0; ++#endif ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return 0; ++ ++ /* rcu_read_lock()ed by nf_hook_slow */ ++ help = nfct_help(ct); ++ if (help && rcu_dereference(help->helper)) ++ return 0; ++ ++ if ((FROM_GE_WAN(skb) || FROM_GE_LAN(skb)) && ++ skb_hnat_is_hashed(skb) && ++ (skb_hnat_reason(skb) == HIT_BIND_KEEPALIVE_DUP_OLD_HDR)) ++ return -1; ++ ++ if ((IS_LAN(out) && FROM_GE_WAN(skb)) || ++ (IS_WAN(out) && FROM_GE_LAN(skb))) { ++ if (!skb_hnat_is_hashed(skb)) ++ return 0; ++ ++ entry = &host->foe_table_cpu[skb_hnat_entry(skb)]; ++ if (entry_hnat_is_bound(entry)) ++ return 0; ++ ++ if (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH && ++ skb_hnat_alg(skb) == 0) { ++ if (fn && fn(skb, out)) ++ return 0; ++ skb_to_hnat_info(skb, out, entry); ++ } ++ } ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_nf_pre_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (IS_WAN(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_WAN; ++ else if (IS_LAN(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_LAN; ++ else if (!IS_BR(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_INVALID; ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int hnat_get_nexthop(struct sk_buff *skb, const struct net_device *out) { ++ ++ u32 nexthop; ++ struct neighbour *neigh; ++ struct dst_entry *dst = skb_dst(skb); ++ struct rtable *rt = (struct rtable *)dst; ++ struct net_device *dev = (__force struct net_device *)out; ++ ++ rcu_read_lock_bh(); ++ nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr); ++ neigh = __ipv4_neigh_lookup_noref(dev, nexthop); ++ if (unlikely(!neigh)) { ++ dev_err(host->dev, "%s:++ no neigh\n", __func__); ++ return -1; ++ } ++ ++ /* why do we get all zero ethernet address ? */ ++ if (!is_valid_ether_addr(neigh->ha)){ ++ rcu_read_unlock_bh(); ++ return -1; ++ } ++ ++ memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN); ++ memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN); ++ ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_ipv4_nf_post_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (!mtk_hnat_nf_post_routing(skb, state->out, hnat_get_nexthop, __func__)) ++ return NF_ACCEPT; ++ ++ return NF_DROP; ++} ++ ++static unsigned int mtk_hnat_br_nf_post_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (!mtk_hnat_nf_post_routing(skb, state->out , 0, __func__)) ++ return NF_ACCEPT; ++ ++ return NF_DROP; ++} ++ ++static struct nf_hook_ops mtk_hnat_nf_ops[] __read_mostly = { ++ { ++ .hook = mtk_hnat_nf_pre_routing, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_FIRST, ++ }, { ++ .hook = mtk_hnat_ipv4_nf_post_routing, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_POST_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, { ++ .hook = mtk_hnat_nf_pre_routing, ++ .pf = NFPROTO_BRIDGE, ++ .hooknum = NF_BR_PRE_ROUTING, ++ .priority = NF_BR_PRI_FIRST, ++ }, { ++ .hook = mtk_hnat_br_nf_post_routing, ++ .pf = NFPROTO_BRIDGE, ++ .hooknum = NF_BR_POST_ROUTING, ++ .priority = NF_BR_PRI_LAST - 1, ++ }, ++}; ++ ++/* ++int hnat_register_nf_hooks(void) ++{ ++ return nf_register_hooks(mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} ++ ++void hnat_unregister_nf_hooks(void) ++{ ++ nf_unregister_hooks(mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} ++*/ ++int hnat_register_nf_hooks(struct net *net) ++{ ++ return nf_register_net_hooks(net,mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} ++ ++void hnat_unregister_nf_hooks(struct net *net) ++{ ++ nf_unregister_net_hooks(net,mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} +diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h +new file mode 100644 +index 0000000000000..e19812840a840 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h +@@ -0,0 +1,44 @@ ++/* 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; version 2 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#ifndef NF_HNAT_MTK_H ++#define NF_HNAT_MTK_H ++ ++#include ++#include ++ ++#define HNAT_SKB_CB2(__skb) ((struct hnat_skb_cb2 *)&((__skb)->cb[44])) ++struct hnat_skb_cb2 { ++ __u32 magic; ++}; ++ ++struct hnat_desc { ++ u32 entry:14; ++ u32 crsn:5; ++ u32 sport:4; ++ u32 alg:9; ++} __attribute__ ((packed)); ++ ++#define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic) ++#define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn) ++#define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry) ++#define skb_hnat_sport(skb) (((struct hnat_desc *)(skb->head))->sport) ++#define skb_hnat_alg(skb) (((struct hnat_desc *)(skb->head))->alg) ++ ++u32 hnat_tx(struct sk_buff *skb); ++u32 hnat_set_skb_info(struct sk_buff *skb, u32 *rxd); ++u32 hnat_reg(struct net_device *, void __iomem *); ++u32 hnat_unreg(void); ++ ++#endif ++ +diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c +index 8febdd48b9f16..9bcc787f8abf3 100644 +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -20,6 +21,7 @@ + #include + #include + ++#include + #include + + #include +@@ -51,6 +53,11 @@ static int nf_ct_tcp_max_retrans __read_mostly = 3; + /* FIXME: Examine ipfilter's timeouts and conntrack transitions more + closely. They're more complex. --RR */ + ++#ifndef IPV4_DEVCONF_DFLT ++ #define IPV4_DEVCONF_DFLT(net, attr) \ ++ IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr) ++#endif ++ + static const char *const tcp_conntrack_names[] = { + "NONE", + "SYN_SENT", +@@ -506,6 +513,18 @@ static bool tcp_in_window(const struct nf_conn *ct, + s32 receiver_offset; + bool res, in_recv_win; + ++ if (net) { ++ if ((net->ipv4.devconf_all && net->ipv4.devconf_dflt && net->ipv6.devconf_all) && ++ net->ipv6.devconf_dflt) { ++ if ((IPV4_DEVCONF_DFLT(net, FORWARDING) || ++ IPV4_DEVCONF_ALL(net, FORWARDING)) || ++ (net->ipv6.devconf_all->forwarding || ++ net->ipv6.devconf_dflt->forwarding)) { ++ return true; ++ } ++ } ++ } ++ + /* + * Get the required data from the packet. + */ diff --git a/root/target/linux/mediatek/patches-4.19/0001-adding-defconfig-and-build-script-change-gitignore-m.patch b/root/target/linux/mediatek/patches-4.19/0001-adding-defconfig-and-build-script-change-gitignore-m.patch new file mode 100644 index 00000000..467141c7 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0001-adding-defconfig-and-build-script-change-gitignore-m.patch @@ -0,0 +1,747 @@ +From 8196b5b6d823fb8c61268121052826db7fb6ce3c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Mon, 22 Oct 2018 19:06:10 +0200 +Subject: [PATCH 01/77] adding defconfig and build-script, change gitignore, + making kernel compatible with r2-images + +--- + arch/arm/boot/dts/mt7623.dtsi | 42 +- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 651 +++++++++++++++++++++ + 4 files changed, 1200 insertions(+), 22 deletions(-) + create mode 100644 arch/arm/configs/mt7623n_evb_fwu_defconfig + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 1cdc346a05e8..04228cf9ddbb 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -354,6 +354,17 @@ + #io-channel-cells = <1>; + }; + ++ uart2: serial@11004000 { ++ compatible = "mediatek,mt7623-uart", ++ "mediatek,mt6577-uart"; ++ reg = <0 0x11004000 0 0x400>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_UART2_SEL>, ++ <&pericfg CLK_PERI_UART2>; ++ clock-names = "baud", "bus"; ++ status = "disabled"; ++ }; ++ + uart0: serial@11002000 { + compatible = "mediatek,mt7623-uart", + "mediatek,mt6577-uart"; +@@ -376,17 +387,6 @@ + status = "disabled"; + }; + +- uart2: serial@11004000 { +- compatible = "mediatek,mt7623-uart", +- "mediatek,mt6577-uart"; +- reg = <0 0x11004000 0 0x400>; +- interrupts = ; +- clocks = <&pericfg CLK_PERI_UART2_SEL>, +- <&pericfg CLK_PERI_UART2>; +- clock-names = "baud", "bus"; +- status = "disabled"; +- }; +- + uart3: serial@11005000 { + compatible = "mediatek,mt7623-uart", + "mediatek,mt6577-uart"; +@@ -661,24 +661,24 @@ + }; + }; + +- mmc0: mmc@11230000 { ++ mmc1: mmc@11240000 { + compatible = "mediatek,mt7623-mmc", + "mediatek,mt2701-mmc"; +- reg = <0 0x11230000 0 0x1000>; +- interrupts = ; +- clocks = <&pericfg CLK_PERI_MSDC30_0>, +- <&topckgen CLK_TOP_MSDC30_0_SEL>; ++ reg = <0 0x11240000 0 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_MSDC30_1>, ++ <&topckgen CLK_TOP_MSDC30_1_SEL>; + clock-names = "source", "hclk"; + status = "disabled"; + }; + +- mmc1: mmc@11240000 { ++ mmc0: mmc@11230000 { + compatible = "mediatek,mt7623-mmc", + "mediatek,mt2701-mmc"; +- reg = <0 0x11240000 0 0x1000>; +- interrupts = ; +- clocks = <&pericfg CLK_PERI_MSDC30_1>, +- <&topckgen CLK_TOP_MSDC30_1_SEL>; ++ reg = <0 0x11230000 0 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_MSDC30_0>, ++ <&topckgen CLK_TOP_MSDC30_0_SEL>; + clock-names = "source", "hclk"; + status = "disabled"; + }; +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +new file mode 100644 +index 000000000000..09df75013c09 +--- /dev/null ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -0,0 +1,651 @@ ++CONFIG_LOCALVERSION="-bpi-r2" ++CONFIG_LOCALVERSION_AUTO=n ++ ++#spectre/meltdown ++CONFIG_PAGE_TABLE_ISOLATION=y ++ ++CONFIG_SYSVIPC=y ++CONFIG_IRQ_DOMAIN_DEBUG=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_CGROUPS=y ++CONFIG_NAMESPACES=y ++ ++#for lxc ++CONFIG_USER_NS=y ++CONFIG_MEMCG=y ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_CGROUP_DEVICE=y ++CONFIG_CGROUP_SCHED=y ++CONFIG_CPUSETS=y ++#some options for docker ++CONFIG_CGROUP_FREEZER=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_OVERLAY_FS=y ++CONFIG_MEMCG_SWAP=y ++CONFIG_MEMCG_SWAP_ENABLED=y ++CONFIG_BLK_CGROUP=y ++CONFIG_CFS_BANDWIDTH=y ++CONFIG_RT_GROUP_SCHED=y ++CONFIG_CGROUP_PIDS=y ++CONFIG_CGROUP_PERF=y ++CONFIG_CGROUP_NET_CLASSID=y ++CONFIG_CGROUP_NET_PRIO=y ++CONFIG_CFQ_GROUP_IOSCHED=y ++ ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_EMBEDDED=y ++CONFIG_PERF_EVENTS=y ++CONFIG_MODULES=y ++CONFIG_MODULE_FORCE_LOAD=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_PARTITION_ADVANCED=y ++CONFIG_CMDLINE_PARTITION=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_ARM_THUMB=y ++CONFIG_ARM_THUMBEE=y ++CONFIG_ARM_ERRATA_720789=y ++CONFIG_ARM_ERRATA_754322=y ++CONFIG_ARM_ERRATA_754327=y ++CONFIG_ARM_ERRATA_764369=y ++CONFIG_ARM_ERRATA_775420=y ++CONFIG_ARM_ERRATA_798181=y ++ ++CONFIG_PL310_ERRATA_588369=y ++CONFIG_PL310_ERRATA_727915=y ++CONFIG_PL310_ERRATA_753970=y ++CONFIG_PL310_ERRATA_769419=y ++ ++CONFIG_PCI=y ++CONFIG_SMP=y ++CONFIG_HAVE_ARM_ARCH_TIMER=y ++CONFIG_NR_CPUS=16 ++CONFIG_AEABI=y ++CONFIG_HIGHMEM=y ++CONFIG_CMA=y ++CONFIG_FORCE_MAX_ZONEORDER=12 ++CONFIG_ARM_APPENDED_DTB=y ++CONFIG_ARM_ATAG_DTB_COMPAT=y ++CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 vmalloc=496M debug=7 no_console_suspend" ++#CONFIG_CMDLINE_FORCE=y ++ ++CONFIG_IKCONFIG=m ++CONFIG_IKCONFIG_PROC=y ++ ++CONFIG_KEXEC=y ++ ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_STAT=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y ++CONFIG_ARM_MEDIATEK_CPUFREQ=y ++ ++CONFIG_VFP=y ++CONFIG_NEON=y ++CONFIG_KERNEL_MODE_NEON=y ++CONFIG_PM_AUTOSLEEP=y ++CONFIG_PM_DEBUG=y ++CONFIG_PM_ADVANCED_DEBUG=y ++CONFIG_APM_EMULATION=y ++ ++CONFIG_NET=y ++CONFIG_DUMMY=m ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_IPV6_ROUTER_PREF=y ++CONFIG_IPV6_OPTIMISTIC_DAD=y ++CONFIG_INET6_AH=m ++CONFIG_INET6_ESP=m ++CONFIG_INET6_IPCOMP=m ++CONFIG_IPV6_MIP6=m ++CONFIG_IPV6_TUNNEL=m ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_BRIDGE=y ++CONFIG_NET_DSA=y ++CONFIG_VLAN_8021Q=y ++CONFIG_NETLINK_DIAG=y ++CONFIG_INET_UDP_DIAG=m ++CONFIG_NET_IPIP=m ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++ ++#added for lxc ++CONFIG_UNIX_DIAG=m ++CONFIG_PACKET_DIAG=m ++ ++ ++CONFIG_IPV6=m ++CONFIG_NETFILTER=y ++CONFIG_NF_CONNTRACK=m ++CONFIG_NF_CONNTRACK_IPV4=m ++CONFIG_NF_CONNTRACK_IPV6=m ++CONFIG_NETFILTER_NETLINK=m ++CONFIG_NF_CT_NETLINK=m ++CONFIG_IP_NF_IPTABLES=m ++CONFIG_NF_LOG_IPV4=m ++CONFIG_NF_REJECT_IPV4=m ++CONFIG_IP6_NF_IPTABLES=m ++CONFIG_NF_LOG_IPV6=m ++CONFIG_NF_REJECT_IPV6=m ++CONFIG_IP_NF_NAT=m ++CONFIG_IP6_NF_NAT=m ++CONFIG_NF_NAT_MASQUERADE_IPV4=m ++CONFIG_NF_NAT_MASQUERADE_IPV6=m ++CONFIG_IP_NF_FILTER=m ++CONFIG_IP6_NF_FILTER=m ++CONFIG_IP_NF_TARGET_MASQUERADE=m ++CONFIG_IP6_NF_TARGET_MASQUERADE=m ++CONFIG_IP_NF_MANGLE=m ++CONFIG_IP6_NF_MANGLE=m ++CONFIG_IP_NF_TARGET_REJECT=m ++CONFIG_IP6_NF_TARGET_REJECT=m ++CONFIG_IP6_NF_MATCH_RT=m ++ ++CONFIG_NETFILTER_SYNPROXY=m ++CONFIG_IP_NF_TARGET_SYNPROXY=m ++CONFIG_IP6_NF_TARGET_SYNPROXY=m ++ ++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m ++CONFIG_NETFILTER_XT_MATCH_LIMIT=m ++CONFIG_NETFILTER_XT_MATCH_STATE=m ++CONFIG_NETFILTER_XT_TARGET_LOG=m ++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m ++CONFIG_NETFILTER_XT_MATCH_MAC=m ++CONFIG_NETFILTER_XT_MATCH_RECENT=m ++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m ++CONFIG_NETFILTER_XT_MARK=m ++CONFIG_NETFILTER_XT_CONNMARK=m ++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m ++CONFIG_IP_VS=m ++CONFIG_NETFILTER_XT_MATCH_IPVS=m ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m ++ ++CONFIG_NET_MEDIATEK_HNAT=m ++CONFIG_DEBUG_SECTION_MISMATCH=y ++ ++#active ftp-support ++CONFIG_NF_CONNTRACK_FTP=m ++CONFIG_NF_NAT_FTP=m ++ ++ ++CONFIG_SYN_COOKIES=y ++ ++CONFIG_PPP=m ++CONFIG_PPPOE=m ++CONFIG_PPP_FILTER=y ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_MPPE=m ++ ++#veth for lxc ++CONFIG_VETH=m ++ ++#for systemd ++CONFIG_AF_KCM=y ++CONFIG_CGROUP_BPF=y ++ ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_DMA_CMA=y ++CONFIG_CMA_SIZE_MBYTES=64 ++CONFIG_ARM_CCI400_PMU=y ++CONFIG_MTD=y ++CONFIG_OF_OVERLAY=y ++CONFIG_CONFIGFS_FS=m ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_SRAM=y ++CONFIG_EEPROM_93CX6=y ++CONFIG_IDE=y ++CONFIG_BLK_DEV_SD=y ++CONFIG_ATA=y ++CONFIG_SATA_AHCI=y ++CONFIG_AHCI_MTK=m ++ ++CONFIG_NETDEVICES=y ++CONFIG_NET_DSA_MT7530=y ++CONFIG_NET_VENDOR_MEDIATEK=y ++CONFIG_NET_MEDIATEK_SOC=y ++ ++CONFIG_ICPLUS_PHY=y ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=m ++CONFIG_KEYBOARD_MATRIX=y ++CONFIG_KEYBOARD_SAMSUNG=y ++CONFIG_KEYBOARD_MTK_PMIC=m ++CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_MOUSE_PS2_SENTELIC=y ++CONFIG_INPUT_MOUSEDEV=y ++CONFIG_INPUT_MOUSEDEV_PSAUX=y ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_SERIO_SERPORT is not set ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=4 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=4 ++CONFIG_SERIAL_8250_MT6577=y ++CONFIG_SERIAL_8250_BTIF=y ++CONFIG_HW_RANDOM=y ++CONFIG_I2C=y ++CONFIG_I2C_MT65XX=y ++CONFIG_PINCTRL_MT2701=y ++# CONFIG_PINCTRL_MT6397 is not set ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_MEDIATEK_WATCHDOG=y ++CONFIG_MFD_MT6397=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_MT6323=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_RC_SUPPORT=y ++CONFIG_RC_DEVICES=y ++CONFIG_IR_MTK=y ++CONFIG_MMC=y ++CONFIG_MMC_MTK=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_MT6323=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_PCA963X=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_ONESHOT=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y ++CONFIG_DMADEVICES=y ++CONFIG_DMATEST=m ++CONFIG_COMMON_CLK_MT2701_HIFSYS=y ++CONFIG_COMMON_CLK_MT2701_ETHSYS=y ++CONFIG_ARM_TIMER_SP804=y ++CONFIG_MTK_IOMMU_V1=y ++CONFIG_MTK_PMIC_WRAP=y ++CONFIG_IIO=y ++CONFIG_RESET_CONTROLLER=y ++CONFIG_PHY_MT65XX_USB3=y ++CONFIG_PSTORE=y ++CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_PMSG=y ++CONFIG_PSTORE_FTRACE=y ++CONFIG_PSTORE_RAM=y ++CONFIG_PRINTK_TIME=y ++CONFIG_DYNAMIC_DEBUG=y ++CONFIG_DEBUG_INFO=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DETECT_HUNG_TASK=y ++CONFIG_DEBUG_LIST=y ++CONFIG_FUNCTION_TRACER=y ++CONFIG_FTRACE_SYSCALLS=y ++CONFIG_FUNCTION_PROFILER=y ++CONFIG_DEBUG_LL=y ++CONFIG_DEBUG_UART_PHYS=0x11002000 ++CONFIG_DEBUG_UART_VIRT=0xf1002000 ++CONFIG_KEYS=y ++CONFIG_CRYPTO_RSA=y ++CONFIG_CRYPTO_CCM=m ++CONFIG_CRYPTO_GCM=m ++CONFIG_CRYPTO_ECB=m ++CONFIG_CRYPTO_CMAC=m ++CONFIG_CRYPTO_ARC4=m ++CONFIG_CRYPTO_DEFLATE=y ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_ITU_T=m ++CONFIG_CRYPTO_DEV_MEDIATEK=y ++ ++#ARM Accelerated Cryptographic Algorithms ++CONFIG_ARM_CRYPTO=y ++CONFIG_CRYPTO_SHA1_ARM=m ++CONFIG_CRYPTO_SHA1_ARM_NEON=m ++CONFIG_CRYPTO_SHA1_ARM_CE=m ++CONFIG_CRYPTO_SHA2_ARM_CE=m ++CONFIG_CRYPTO_SHA512_ARM=m ++CONFIG_CRYPTO_AES_ARM=m ++CONFIG_CRYPTO_AES_ARM_BS=m ++CONFIG_CRYPTO_AES_ARM_CE=m ++CONFIG_CRYPTO_GHASH_ARM_CE=m ++CONFIG_CRYPTO_CRC32_ARM_CE=m ++CONFIG_CRYPTO_CHACHA20_NEON=m ++ ++#LVM ++CONFIG_MD=y ++CONFIG_BLK_DEV_DM=y ++CONFIG_DM_BUFIO=y ++CONFIG_DM_CRYPT=y ++CONFIG_DM_SNAPSHOT=y ++CONFIG_DM_MIRROR=y ++CONFIG_DM_MULTIPATH=y ++CONFIG_DM_MULTIPATH_QL=y ++CONFIG_DM_MULTIPATH_ST=y ++CONFIG_DM_THIN_PROVISIONING=m ++CONFIG_DAX=y ++CONFIG_CRYPTO_CBC=y ++ ++#RAID ++CONFIG_DM_RAID=y ++CONFIG_MD_RAID0=y ++CONFIG_MD_RAID1=y ++CONFIG_MD_RAID10=y ++CONFIG_MD_RAID456=y ++ ++#RamFS ++#CONFIG_INITRAMFS_SOURCE="../rootfs_ttys0_rng.cpio.gz" ++#CONFIG_INITRAMFS_SOURCE="../initramfs.cpio" ++#CONFIG_INITRAMFS_FORCE=y ++ ++#Filesystem ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_AUTOFS4_FS=y ++CONFIG_FUSE_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_VFAT_FS=y ++CONFIG_NTFS_FS=m ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_UTF8=y ++CONFIG_CIFS=m ++CONFIG_F2FS_FS=m ++CONFIG_BTRFS_FS=m ++ ++#GPIO ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_GPIO=y ++CONFIG_GPIO_SYSFS=y ++ ++#wlan ++CONFIG_MAC80211=y ++CONFIG_CFG80211=y ++ ++#internal wlan (not working yet) ++# CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set ++#CONFIG_MTK_COMBO=y ++#CONFIG_MTK_COMBO_CHIP_CONSYS_7623=y ++#used in 4.4, but should be set in Kconfig by selecting mt7623 COMBO ++#CONFIG_MTK_PLATFORM="mt7623" ++ ++#CONFIG_MTK_COMBO_COMM=y ++#CONFIG_MTK_COMBO_WIFI=y ++#CONFIG_NL80211_TESTMODE=y ++ ++#internal Bluetooth (also not working yet) ++#CONFIG_BT=y ++#CONFIG_MTK_COMBO_BT=y ++#CONFIG_MTK_COMBO_BT_HCI=y ++#needed for BT? ++#Bluetooth Classic (BR/EDR) features ++CONFIG_BT_BREDR=y ++#Bluetooth High Speed (HS) features ++CONFIG_BT_HS=y ++#Bluetooth Low Energy (LE) features ++CONFIG_BT_LE=y ++#Export Bluetooth internals in debugfs ++CONFIG_BT_DEBUGFS=y ++CONFIG_BT_RFCOMM=m ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_HIDP=m ++CONFIG_BT_BNEP=m ++ ++#to run bluetoothd rfkill needed ++CONFIG_RFKILL=y ++CONFIG_RFKILL_LEDS=y ++CONFIG_RFKILL_INPUT=y ++CONFIG_RFKILL_GPIO=y ++ ++#if you use a mt76x2 or mt76x3 pcie-card ++#CONFIG_MT76=m ++ ++#pcie ++CONFIG_PCIEPORTBUS=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY_MTK_TPHY=y ++ ++CONFIG_I2C_CHARDEV=m ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_DS1307=m ++CONFIG_RTC_DRV_DS1307_CENTURY=y ++CONFIG_RTC_DRV_MT6397=m ++ ++CONFIG_SPI=y ++CONFIG_SPI_MASTER=y ++CONFIG_SPI_SPIDEV=m ++CONFIG_SPI_MT65XX=m ++ ++CONFIG_PWM=y ++CONFIG_PWM_MEDIATEK=m ++ ++#Temperature sensor driver for mediatek SoCs ++CONFIG_MEDIATEK_MT6577_AUXADC=m ++CONFIG_THERMAL=m ++CONFIG_MTK_THERMAL=m ++CONFIG_MTK_EFUSE=m ++ ++#HDMI ++#CONFIG_DRM=y ++#CONFIG_DRM_ARM=y ++#CONFIG_DRM_MALI_DISPLAY=y ++#CONFIG_DRM_MEDIATEK=y ++#CONFIG_DRM_MEDIATEK_HDMI=y ++#CONFIG_COMMON_CLK_MT2701_MMSYS=y ++#CONFIG_COMMON_CLK_MT2701_IMGSYS=y ++#CONFIG_COMMON_CLK_MT2701_VDECSYS=y ++#CONFIG_FRAMEBUFFER_CONSOLE=y ++#CONFIG_DRM_FBDEV_EMULATION=y ++ ++#Sound ++CONFIG_SOUND=y ++CONFIG_SND=y #alsa core ++CONFIG_SND_SOC=y ++ ++#CONFIG_SOUND_OSS_CORE=y ++#CONFIG_SOUND_OSS_CORE_PRECLAIM=y ++#CONFIG_SND_OSSEMUL=y ++#CONFIG_SND_MIXER_OSS=m ++#CONFIG_SND_PCM_OSS=m #alsa The PCM OSS emulation module. ++ ++#USB/HID ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_SERIAL=y ++#CONFIG_NOP_USB_XCEIV=y ++#CONFIG_USB_GPIO_VBUS=y ++#CONFIG_USB_GADGET=y ++#CONFIG_USB_CONFIGFS=y ++CONFIG_USB_CONFIGFS_SERIAL=y ++#CONFIG_USB_CONFIGFS_ACM=y ++#CONFIG_USB_CONFIGFS_OBEX=y ++#CONFIG_USB_CONFIGFS_NCM=y ++#CONFIG_USB_CONFIGFS_ECM=y ++#CONFIG_USB_CONFIGFS_ECM_SUBSET=y ++#CONFIG_USB_CONFIGFS_RNDIS=y ++#CONFIG_USB_CONFIGFS_EEM=y ++CONFIG_USB_CONFIGFS_MASS_STORAGE=y ++ ++CONFIG_HID=y ++CONFIG_HIDRAW=y ++#CONFIG_UHID=m ++CONFIG_HID_GENERIC=y ++ ++CONFIG_USB_HID=y ++#CONFIG_HID_PID=y ++CONFIG_USB_HIDDEV=y ++ ++# CONFIG_USB_OHCI_LITTLE_ENDIAN=y ? ++CONFIG_USB_SUPPORT=y ++CONFIG_USB_COMMON=y ++# CONFIG_USB_ARCH_HAS_HCD=y ? ++ ++#additional NET (e.g. tunneling incl. openvpn,vlan-base-support) ++CONFIG_TUN=m ++#vlan ++CONFIG_BRIDGE_VLAN_FILTERING=y ++CONFIG_VLAN_8021Q_GVRP=y ++CONFIG_VLAN_8021Q_MVRP=y ++CONFIG_NET_L3_MASTER_DEV=y ++CONFIG_IPVLAN=m ++CONFIG_MACVLAN=m ++CONFIG_NET_ACT_VLAN=m ++CONFIG_NET_CLS_ACT=y ++ ++# QoS and/or fair queueing ++CONFIG_NET_SCHED=y ++CONFIG_NET_SCH_CBQ=m ++CONFIG_NET_SCH_HTB=m ++CONFIG_NET_SCH_CSZ=m ++CONFIG_NET_SCH_PRIO=m ++CONFIG_NET_SCH_RED=m ++CONFIG_NET_SCH_SFQ=m ++CONFIG_NET_SCH_TEQL=m ++CONFIG_NET_SCH_TBF=m ++CONFIG_NET_SCH_GRED=m ++CONFIG_NET_SCH_DSMARK=m ++CONFIG_NET_SCH_INGRESS=m ++CONFIG_NET_SCH_NETEM=m ++CONFIG_NET_QOS=y ++CONFIG_NET_ESTIMATOR=y ++CONFIG_NET_CLS=y ++CONFIG_NET_CLS_TCINDEX=m ++CONFIG_NET_CLS_ROUTE4=m ++CONFIG_NET_CLS_ROUTE=y ++CONFIG_NET_CLS_FW=m ++CONFIG_NET_CLS_U32=m ++CONFIG_NET_CLS_RSVP=m ++CONFIG_NET_CLS_RSVP6=m ++CONFIG_NET_CLS_POLICE=y ++ ++#unused drivers which are set by default ++CONFIG_WLAN_VENDOR_ADMTEK=n ++CONFIG_WLAN_VENDOR_ATH=n ++CONFIG_WLAN_VENDOR_ATMEL=n ++CONFIG_WLAN_VENDOR_BROADCOM=n ++CONFIG_WLAN_VENDOR_CISCO=n ++CONFIG_WLAN_VENDOR_INTEL=n ++CONFIG_WLAN_VENDOR_INTERSIL=n ++CONFIG_WLAN_VENDOR_MARVELL=n ++CONFIG_WLAN_VENDOR_REALTEK=n ++CONFIG_WLAN_VENDOR_RALINK=n ++CONFIG_WLAN_VENDOR_RSI=n ++CONFIG_WLAN_VENDOR_ST=n ++CONFIG_WLAN_VENDOR_TI=n ++CONFIG_WLAN_VENDOR_ZYDAS=n ++CONFIG_WLAN_VENDOR_QUANTENNA=n ++# CONFIG_ADAPTEC_STARFIRE is not set ++# CONFIG_NET_VENDOR_ADAPTEC is not set ++# CONFIG_NET_VENDOR_AGERE is not set ++# CONFIG_NET_VENDOR_ALACRITECH is not set ++# CONFIG_NET_VENDOR_ALTEON is not set ++# CONFIG_NET_VENDOR_AMAZON is not set ++# CONFIG_NET_VENDOR_AMD is not set ++# CONFIG_NET_VENDOR_AQUANTIA is not set ++# CONFIG_NET_VENDOR_ARC is not set ++# CONFIG_NET_VENDOR_ATHEROS is not set ++# CONFIG_NET_VENDOR_AURORA is not set ++# CONFIG_NET_CADENCE is not set ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_BROCADE is not set ++# CONFIG_NET_VENDOR_CAVIUM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_CISCO is not set ++# CONFIG_NET_VENDOR_MELLANOX is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_MYRI is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_NETRONOME is not set ++# CONFIG_NET_VENDOR_NVIDIA is not set ++# CONFIG_NET_VENDOR_OKI is not set ++# CONFIG_NET_PACKET_ENGINE is not set ++# CONFIG_NET_VENDOR_QLOGIC is not set ++# CONFIG_NET_VENDOR_QUALCOMM is not set ++# CONFIG_NET_VENDOR_REALTEK is not set ++# CONFIG_NET_VENDOR_RENESAS is not set ++# CONFIG_NET_VENDOR_RDC is not set ++# CONFIG_NET_VENDOR_ROCKER is not set ++# CONFIG_NET_VENDOR_SAMSUNG is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SILAN is not set ++# CONFIG_NET_VENDOR_SIS is not set ++# CONFIG_NET_VENDOR_SOLARFLARE is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++# CONFIG_NET_VENDOR_SUN is not set ++# CONFIG_NET_VENDOR_TEHUTI is not set ++# CONFIG_NET_VENDOR_TI is not set ++# CONFIG_NET_VENDOR_VIA is not set ++# CONFIG_NET_VENDOR_WIZNET is not set ++# CONFIG_NET_VENDOR_SYNOPSYS is not set ++# CONFIG_NET_VENDOR_DEC is not set ++# CONFIG_NET_VENDOR_DLINK is not set ++# CONFIG_NET_VENDOR_EMULEX is not set ++# CONFIG_NET_VENDOR_EZCHIP is not set ++# CONFIG_NET_VENDOR_EXAR is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_HISILICON is not set ++# CONFIG_NET_VENDOR_HP is not set ++# CONFIG_NET_VENDOR_HUAWEI is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_3COM is not set ++ ++#NFS Client ++CONFIG_NFS_FS=y ++CONFIG_NFS_V2=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_NFS_SWAP=y ++CONFIG_NFS_V4_1=y ++CONFIG_NFS_V4_2=y ++CONFIG_PNFS_FILE_LAYOUT=m ++CONFIG_PNFS_BLOCK=m ++CONFIG_PNFS_FLEXFILE_LAYOUT=m ++CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" ++CONFIG_NFS_V4_1_MIGRATION=y ++CONFIG_NFS_USE_LEGACY_DNS=y ++ ++#NFS Server ++CONFIG_NFSD=m ++CONFIG_NFSD_V2_ACL=y ++CONFIG_NFSD_V3=y ++CONFIG_NFSD_V3_ACL=y ++CONFIG_NFSD_V4=y ++CONFIG_NFSD_PNFS=y ++CONFIG_NFSD_BLOCKLAYOUT=y ++CONFIG_NFSD_SCSILAYOUT=y ++CONFIG_NFSD_FLEXFILELAYOUT=y ++CONFIG_NFSD_FAULT_INJECTION=y ++CONFIG_NFS_ACL_SUPPORT=m ++CONFIG_NFS_COMMON=y ++ ++CONFIG_ROOT_NFS=y ++ ++#xfs ++CONFIG_XFS_FS=m ++ ++#RTC/POWER ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_MT6323=y ++CONFIG_POWER_RESET_MT6397_RTC=y ++ ++#CONFIG_NET_MEDIATEK_HW_QOS=m ++ +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0006-wifi-adding-driver-folder.patch b/root/target/linux/mediatek/patches-4.19/0006-wifi-adding-driver-folder.patch new file mode 100644 index 00000000..a9380314 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0006-wifi-adding-driver-folder.patch @@ -0,0 +1,216265 @@ +From ce8c582c6121469db64197b1b4aa4e4c377c660f Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 23 Oct 2018 13:12:12 +0200 +Subject: [PATCH 06/77] [wifi] adding driver-folder + +--- + drivers/misc/Kconfig | 1 + + drivers/misc/Makefile | 1 + + drivers/misc/mediatek/Kconfig | 11 + + drivers/misc/mediatek/Makefile | 19 + + drivers/misc/mediatek/btif/Kconfig | 4 + + drivers/misc/mediatek/btif/Makefile | 33 + + drivers/misc/mediatek/btif/common/Makefile | 31 + + .../misc/mediatek/btif/common/btif_dma_plat.c | 1436 ++ + drivers/misc/mediatek/btif/common/btif_plat.c | 1396 ++ + .../misc/mediatek/btif/common/inc/mtk_btif.h | 370 + + .../mediatek/btif/common/inc/mtk_btif_exp.h | 280 + + drivers/misc/mediatek/btif/common/mtk_btif.c | 3472 +++++ + .../misc/mediatek/btif/common/mtk_btif_exp.c | 786 ++ + .../btif/common/plat_inc/btif_dma_priv.h | 164 + + .../btif/common/plat_inc/btif_dma_pub.h | 197 + + .../mediatek/btif/common/plat_inc/btif_priv.h | 105 + + .../mediatek/btif/common/plat_inc/btif_pub.h | 237 + + .../btif/common/plat_inc/plat_common.h | 307 + + drivers/misc/mediatek/connectivity/Kconfig | 299 + + drivers/misc/mediatek/connectivity/Makefile | 41 + + .../mediatek/connectivity/common/Makefile | 23 + + .../common/common_detect/Makefile | 47 + + .../common/common_detect/drv_init/Makefile | 22 + + .../common_detect/drv_init/ant_drv_init.c | 38 + + .../drv_init/bluetooth_drv_init.c | 35 + + .../common_detect/drv_init/common_drv_init.c | 103 + + .../common_detect/drv_init/conn_drv_init.c | 80 + + .../common_detect/drv_init/fm_drv_init.c | 33 + + .../common_detect/drv_init/gps_drv_init.c | 35 + + .../common_detect/drv_init/inc/ant_drv_init.h | 20 + + .../drv_init/inc/bluetooth_drv_init.h | 20 + + .../drv_init/inc/common_drv_init.h | 31 + + .../drv_init/inc/conn_drv_init.h | 18 + + .../common_detect/drv_init/inc/fm_drv_init.h | 20 + + .../common_detect/drv_init/inc/gps_drv_init.h | 19 + + .../drv_init/inc/wlan_drv_init.h | 30 + + .../common_detect/drv_init/wlan_drv_init.c | 74 + + .../common/common_detect/mtk_wcn_stub_alps.c | 605 + + .../common/common_detect/sdio_detect.c | 269 + + .../common/common_detect/sdio_detect.h | 43 + + .../common/common_detect/wmt_detect.c | 380 + + .../common/common_detect/wmt_detect.h | 114 + + .../common/common_detect/wmt_detect_pwr.c | 232 + + .../common/common_detect/wmt_detect_pwr.h | 29 + + .../common/common_detect/wmt_gpio.c | 371 + + .../common/common_detect/wmt_gpio.h | 103 + + .../common/common_detect/wmt_stp_exp.c | 480 + + .../common/common_detect/wmt_stp_exp.h | 610 + + .../connectivity/common/conn_soc/Makefile | 65 + + .../common/conn_soc/core/Makefile | 22 + + .../common/conn_soc/core/btm_core.c | 1376 ++ + .../common/conn_soc/core/dbg_core.c | 13 + + .../common/conn_soc/core/include/btm_core.h | 133 + + .../common/conn_soc/core/include/dbg_core.h | 69 + + .../common/conn_soc/core/include/psm_core.h | 251 + + .../common/conn_soc/core/include/stp_core.h | 629 + + .../common/conn_soc/core/include/stp_wmt.h | 89 + + .../common/conn_soc/core/include/wmt_conf.h | 74 + + .../common/conn_soc/core/include/wmt_core.h | 428 + + .../common/conn_soc/core/include/wmt_ctrl.h | 120 + + .../common/conn_soc/core/include/wmt_func.h | 140 + + .../common/conn_soc/core/include/wmt_ic.h | 122 + + .../common/conn_soc/core/include/wmt_lib.h | 300 + + .../common/conn_soc/core/psm_core.c | 1890 +++ + .../common/conn_soc/core/stp_core.c | 3358 +++++ + .../common/conn_soc/core/wmt_conf.c | 529 + + .../common/conn_soc/core/wmt_core.c | 2521 ++++ + .../common/conn_soc/core/wmt_ctrl.c | 1019 ++ + .../common/conn_soc/core/wmt_func.c | 713 + + .../common/conn_soc/core/wmt_ic_soc.c | 2452 ++++ + .../common/conn_soc/core/wmt_lib.c | 1938 +++ + .../common/conn_soc/include/stp_exp.h | 252 + + .../common/conn_soc/include/wmt.h | 19 + + .../common/conn_soc/include/wmt_exp.h | 329 + + .../common/conn_soc/include/wmt_plat.h | 295 + + .../common/conn_soc/linux/Makefile | 6 + + .../conn_soc/linux/include/bgw_desense.h | 74 + + .../common/conn_soc/linux/include/osal.h | 349 + + .../conn_soc/linux/include/osal_typedef.h | 90 + + .../common/conn_soc/linux/include/wmt_idc.h | 97 + + .../common/conn_soc/linux/pri/Makefile | 21 + + .../conn_soc/linux/pri/include/stp_btif.h | 31 + + .../conn_soc/linux/pri/include/stp_dbg.h | 316 + + .../conn_soc/linux/pri/include/wmt_dev.h | 71 + + .../common/conn_soc/linux/pri/stp_btif.c | 279 + + .../common/conn_soc/linux/pri/stp_dbg.c | 2061 +++ + .../common/conn_soc/linux/pri/stp_exp.c | 279 + + .../common/conn_soc/linux/pri/wmt_dev.c | 2566 ++++ + .../common/conn_soc/linux/pri/wmt_exp.c | 610 + + .../common/conn_soc/linux/pub/Makefile | 27 + + .../common/conn_soc/linux/pub/bgw_desense.c | 153 + + .../common/conn_soc/linux/pub/osal.c | 1211 ++ + .../common/conn_soc/linux/pub/stp_chrdev_bt.c | 899 ++ + .../conn_soc/linux/pub/wmt_chrdev_wifi.c | 668 + + .../common/conn_soc/linux/pub/wmt_idc.c | 307 + + .../common/conn_soc/mt7623/Makefile | 25 + + .../mt7623/include/mtk_wcn_consys_hw.h | 287 + + .../conn_soc/mt7623/mtk_wcn_consys_hw.c | 738 ++ + .../common/conn_soc/mt7623/wmt_plat_alps.c | 1071 ++ + .../misc/mediatek/connectivity/wlan/Makefile | 8 + + .../mediatek/connectivity/wlan/gen2/Makefile | 237 + + .../connectivity/wlan/gen2/common/debug.c | 165 + + .../connectivity/wlan/gen2/common/dump.c | 345 + + .../connectivity/wlan/gen2/common/wlan_bow.c | 3442 +++++ + .../connectivity/wlan/gen2/common/wlan_lib.c | 6240 +++++++++ + .../connectivity/wlan/gen2/common/wlan_oid.c | 11050 ++++++++++++++++ + .../connectivity/wlan/gen2/common/wlan_p2p.c | 1654 +++ + .../wlan/gen2/include/CFG_Wifi_File.h | 238 + + .../connectivity/wlan/gen2/include/config.h | 1628 +++ + .../connectivity/wlan/gen2/include/debug.h | 466 + + .../connectivity/wlan/gen2/include/link.h | 368 + + .../wlan/gen2/include/mgmt/aa_fsm.h | 188 + + .../wlan/gen2/include/mgmt/ais_fsm.h | 573 + + .../wlan/gen2/include/mgmt/assoc.h | 112 + + .../wlan/gen2/include/mgmt/auth.h | 125 + + .../wlan/gen2/include/mgmt/bow_fsm.h | 184 + + .../connectivity/wlan/gen2/include/mgmt/bss.h | 265 + + .../connectivity/wlan/gen2/include/mgmt/cnm.h | 258 + + .../wlan/gen2/include/mgmt/cnm_mem.h | 1164 ++ + .../wlan/gen2/include/mgmt/cnm_scan.h | 169 + + .../wlan/gen2/include/mgmt/cnm_timer.h | 235 + + .../wlan/gen2/include/mgmt/hem_mbox.h | 446 + + .../wlan/gen2/include/mgmt/hs20.h | 148 + + .../connectivity/wlan/gen2/include/mgmt/mib.h | 153 + + .../wlan/gen2/include/mgmt/p2p_assoc.h | 55 + + .../wlan/gen2/include/mgmt/p2p_bss.h | 56 + + .../wlan/gen2/include/mgmt/p2p_fsm.h | 2190 +++ + .../wlan/gen2/include/mgmt/p2p_func.h | 155 + + .../wlan/gen2/include/mgmt/p2p_ie.h | 156 + + .../wlan/gen2/include/mgmt/p2p_rlm.h | 74 + + .../wlan/gen2/include/mgmt/p2p_rlm_obss.h | 64 + + .../wlan/gen2/include/mgmt/p2p_scan.h | 81 + + .../wlan/gen2/include/mgmt/p2p_state.h | 43 + + .../wlan/gen2/include/mgmt/privacy.h | 230 + + .../wlan/gen2/include/mgmt/rate.h | 93 + + .../connectivity/wlan/gen2/include/mgmt/rlm.h | 396 + + .../wlan/gen2/include/mgmt/rlm_domain.h | 557 + + .../wlan/gen2/include/mgmt/rlm_obss.h | 150 + + .../wlan/gen2/include/mgmt/rlm_protection.h | 122 + + .../wlan/gen2/include/mgmt/rlm_txpwr_init.h | 1213 ++ + .../wlan/gen2/include/mgmt/roaming_fsm.h | 171 + + .../connectivity/wlan/gen2/include/mgmt/rsn.h | 271 + + .../wlan/gen2/include/mgmt/scan.h | 988 ++ + .../wlan/gen2/include/mgmt/sec_fsm.h | 233 + + .../wlan/gen2/include/mgmt/stats.h | 368 + + .../wlan/gen2/include/mgmt/swcr.h | 187 + + .../wlan/gen2/include/mgmt/tdls.h | 262 + + .../wlan/gen2/include/mgmt/wapi.h | 104 + + .../wlan/gen2/include/mgmt/wlan_typedef.h | 87 + + .../connectivity/wlan/gen2/include/mgmt/wnm.h | 95 + + .../wlan/gen2/include/nic/adapter.h | 1506 +++ + .../connectivity/wlan/gen2/include/nic/bow.h | 322 + + .../wlan/gen2/include/nic/cmd_buf.h | 150 + + .../connectivity/wlan/gen2/include/nic/hal.h | 618 + + .../wlan/gen2/include/nic/hif_rx.h | 220 + + .../wlan/gen2/include/nic/hif_tx.h | 214 + + .../connectivity/wlan/gen2/include/nic/mac.h | 2323 ++++ + .../wlan/gen2/include/nic/mtreg.h | 272 + + .../connectivity/wlan/gen2/include/nic/nic.h | 498 + + .../wlan/gen2/include/nic/nic_rx.h | 420 + + .../wlan/gen2/include/nic/nic_tx.h | 642 + + .../connectivity/wlan/gen2/include/nic/p2p.h | 192 + + .../wlan/gen2/include/nic/p2p_cmd_buf.h | 83 + + .../wlan/gen2/include/nic/p2p_mac.h | 207 + + .../wlan/gen2/include/nic/p2p_nic.h | 62 + + .../wlan/gen2/include/nic/p2p_nic_cmd_event.h | 70 + + .../wlan/gen2/include/nic/que_mgt.h | 971 ++ + .../wlan/gen2/include/nic/wlan_def.h | 1010 ++ + .../wlan/gen2/include/nic_cmd_event.h | 2290 ++++ + .../wlan/gen2/include/nic_init_cmd_event.h | 177 + + .../wlan/gen2/include/p2p_precomp.h | 201 + + .../wlan/gen2/include/p2p_typedef.h | 165 + + .../connectivity/wlan/gen2/include/precomp.h | 388 + + .../connectivity/wlan/gen2/include/pwr_mgt.h | 141 + + .../connectivity/wlan/gen2/include/queue.h | 195 + + .../connectivity/wlan/gen2/include/rftest.h | 294 + + .../wlan/gen2/include/tdls_extr.h | 427 + + .../connectivity/wlan/gen2/include/typedef.h | 244 + + .../connectivity/wlan/gen2/include/wlan_bow.h | 352 + + .../connectivity/wlan/gen2/include/wlan_lib.h | 1001 ++ + .../connectivity/wlan/gen2/include/wlan_oid.h | 1715 +++ + .../connectivity/wlan/gen2/include/wlan_p2p.h | 307 + + .../connectivity/wlan/gen2/mgmt/aaa_fsm.c | 1303 ++ + .../connectivity/wlan/gen2/mgmt/ais_fsm.c | 5039 +++++++ + .../connectivity/wlan/gen2/mgmt/assoc.c | 1932 +++ + .../connectivity/wlan/gen2/mgmt/auth.c | 1211 ++ + .../connectivity/wlan/gen2/mgmt/bss.c | 2521 ++++ + .../connectivity/wlan/gen2/mgmt/cnm.c | 738 ++ + .../connectivity/wlan/gen2/mgmt/cnm_mem.c | 1236 ++ + .../connectivity/wlan/gen2/mgmt/cnm_timer.c | 482 + + .../connectivity/wlan/gen2/mgmt/hem_mbox.c | 816 ++ + .../connectivity/wlan/gen2/mgmt/hs20.c | 498 + + .../connectivity/wlan/gen2/mgmt/mib.c | 111 + + .../connectivity/wlan/gen2/mgmt/p2p_assoc.c | 87 + + .../connectivity/wlan/gen2/mgmt/p2p_bss.c | 58 + + .../connectivity/wlan/gen2/mgmt/p2p_fsm.c | 3139 +++++ + .../connectivity/wlan/gen2/mgmt/p2p_func.c | 3796 ++++++ + .../connectivity/wlan/gen2/mgmt/p2p_ie.c | 612 + + .../connectivity/wlan/gen2/mgmt/p2p_rlm.c | 905 ++ + .../wlan/gen2/mgmt/p2p_rlm_obss.c | 313 + + .../connectivity/wlan/gen2/mgmt/p2p_scan.c | 756 ++ + .../connectivity/wlan/gen2/mgmt/p2p_state.c | 466 + + .../connectivity/wlan/gen2/mgmt/privacy.c | 915 ++ + .../connectivity/wlan/gen2/mgmt/rate.c | 497 + + .../connectivity/wlan/gen2/mgmt/rlm.c | 1858 +++ + .../connectivity/wlan/gen2/mgmt/rlm_domain.c | 1791 +++ + .../connectivity/wlan/gen2/mgmt/rlm_obss.c | 436 + + .../wlan/gen2/mgmt/rlm_protection.c | 105 + + .../connectivity/wlan/gen2/mgmt/roaming_fsm.c | 539 + + .../connectivity/wlan/gen2/mgmt/rsn.c | 2533 ++++ + .../connectivity/wlan/gen2/mgmt/saa_fsm.c | 1788 +++ + .../connectivity/wlan/gen2/mgmt/scan.c | 3103 +++++ + .../connectivity/wlan/gen2/mgmt/scan_fsm.c | 2136 +++ + .../connectivity/wlan/gen2/mgmt/sec_fsm.c | 1112 ++ + .../connectivity/wlan/gen2/mgmt/stats.c | 1342 ++ + .../connectivity/wlan/gen2/mgmt/swcr.c | 1170 ++ + .../connectivity/wlan/gen2/mgmt/tdls.c | 5199 ++++++++ + .../connectivity/wlan/gen2/mgmt/tdls_com.c | 741 ++ + .../connectivity/wlan/gen2/mgmt/wapi.c | 491 + + .../connectivity/wlan/gen2/mgmt/wnm.c | 301 + + .../connectivity/wlan/gen2/nic/cmd_buf.c | 254 + + .../mediatek/connectivity/wlan/gen2/nic/nic.c | 4062 ++++++ + .../wlan/gen2/nic/nic_cmd_event.c | 1636 +++ + .../connectivity/wlan/gen2/nic/nic_pwr_mgt.c | 669 + + .../connectivity/wlan/gen2/nic/nic_rx.c | 3782 ++++++ + .../connectivity/wlan/gen2/nic/nic_tx.c | 2350 ++++ + .../connectivity/wlan/gen2/nic/p2p_nic.c | 192 + + .../connectivity/wlan/gen2/nic/que_mgt.c | 5038 +++++++ + .../connectivity/wlan/gen2/os/linux/gl_bow.c | 1177 ++ + .../wlan/gen2/os/linux/gl_cfg80211.c | 3110 +++++ + .../connectivity/wlan/gen2/os/linux/gl_init.c | 3502 +++++ + .../connectivity/wlan/gen2/os/linux/gl_kal.c | 4799 +++++++ + .../connectivity/wlan/gen2/os/linux/gl_p2p.c | 4672 +++++++ + .../wlan/gen2/os/linux/gl_p2p_cfg80211.c | 1935 +++ + .../wlan/gen2/os/linux/gl_p2p_init.c | 433 + + .../wlan/gen2/os/linux/gl_p2p_kal.c | 1314 ++ + .../connectivity/wlan/gen2/os/linux/gl_proc.c | 1020 ++ + .../connectivity/wlan/gen2/os/linux/gl_rst.c | 228 + + .../wlan/gen2/os/linux/gl_vendor.c | 1220 ++ + .../connectivity/wlan/gen2/os/linux/gl_wext.c | 4158 ++++++ + .../wlan/gen2/os/linux/gl_wext_priv.c | 3142 +++++ + .../wlan/gen2/os/linux/hif/ahb/ahb.c | 1643 +++ + .../wlan/gen2/os/linux/hif/ahb/arm.c | 31 + + .../wlan/gen2/os/linux/hif/ahb/include/hif.h | 340 + + .../gen2/os/linux/hif/ahb/include/hif_gdma.h | 154 + + .../gen2/os/linux/hif/ahb/include/hif_pdma.h | 141 + + .../os/linux/hif/ahb/include/mtk_porting.h | 91 + + .../gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c | 480 + + .../wlan/gen2/os/linux/include/gl_cfg80211.h | 341 + + .../wlan/gen2/os/linux/include/gl_kal.h | 1565 +++ + .../wlan/gen2/os/linux/include/gl_os.h | 1270 ++ + .../wlan/gen2/os/linux/include/gl_p2p_ioctl.h | 743 ++ + .../wlan/gen2/os/linux/include/gl_p2p_kal.h | 243 + + .../wlan/gen2/os/linux/include/gl_p2p_os.h | 242 + + .../wlan/gen2/os/linux/include/gl_rst.h | 133 + + .../wlan/gen2/os/linux/include/gl_sec.h | 21 + + .../wlan/gen2/os/linux/include/gl_typedef.h | 298 + + .../wlan/gen2/os/linux/include/gl_vendor.h | 619 + + .../wlan/gen2/os/linux/include/gl_wext.h | 357 + + .../wlan/gen2/os/linux/include/gl_wext_priv.h | 402 + + .../wlan/gen2/os/linux/platform.c | 542 + + .../connectivity/wlan/gen2/os/version.h | 190 + + drivers/misc/mediatek/include/mt-plat/aee.h | 284 + + .../misc/mediatek/include/mt-plat/mrdump.h | 204 + + .../mt-plat/mt7622/include/mach/mtk_thermal.h | 295 + + .../mt8127/include/mach/mt_freqhopping.h | 159 + + .../mt8127/include/mach/mt_spm_mtcmos.h | 37 + + .../mt8127/include/mach/mtk_boot_share_page.h | 40 + + .../mt-plat/mt8127/include/mach/mtk_thermal.h | 301 + + .../misc/mediatek/include/mt-plat/mt_sched.h | 34 + + .../misc/mediatek/include/mt-plat/mtk_io.h | 23 + + .../misc/mediatek/include/mt-plat/mtk_lpae.h | 62 + + .../include/mt-plat/mtk_mdm_monitor.h | 42 + + .../include/mt-plat/mtk_platform_debug.h | 28 + + .../include/mt-plat/mtk_ram_console.h | 162 + + .../misc/mediatek/include/mt-plat/mtk_rtc.h | 85 + + .../include/mt-plat/mtk_thermal_ext_control.h | 69 + + .../include/mt-plat/mtk_thermal_monitor.h | 102 + + .../include/mt-plat/mtk_thermal_platform.h | 114 + + .../include/mt-plat/mtk_thermal_trace.h | 47 + + .../include/mt-plat/mtk_thermal_typedefs.h | 241 + + .../include/mt-plat/mtk_wcn_cmb_stub.h | 185 + + .../misc/mediatek/include/mt-plat/rt-regmap.h | 291 + + .../mediatek/include/mt-plat/sync_write.h | 88 + + .../misc/mediatek/include/mt-plat/wakelock.h | 67 + + 285 files changed, 213970 insertions(+) + create mode 100644 drivers/misc/mediatek/Kconfig + create mode 100644 drivers/misc/mediatek/Makefile + create mode 100644 drivers/misc/mediatek/btif/Kconfig + create mode 100644 drivers/misc/mediatek/btif/Makefile + create mode 100644 drivers/misc/mediatek/btif/common/Makefile + create mode 100644 drivers/misc/mediatek/btif/common/btif_dma_plat.c + create mode 100644 drivers/misc/mediatek/btif/common/btif_plat.c + create mode 100644 drivers/misc/mediatek/btif/common/inc/mtk_btif.h + create mode 100644 drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h + create mode 100644 drivers/misc/mediatek/btif/common/mtk_btif.c + create mode 100644 drivers/misc/mediatek/btif/common/mtk_btif_exp.c + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h + create mode 100644 drivers/misc/mediatek/btif/common/plat_inc/plat_common.h + create mode 100644 drivers/misc/mediatek/connectivity/Kconfig + create mode 100644 drivers/misc/mediatek/connectivity/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c + create mode 100644 drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/Makefile + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c + create mode 100644 drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/aee.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mrdump.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mt_sched.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_io.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_lpae.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_rtc.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/rt-regmap.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/sync_write.h + create mode 100644 drivers/misc/mediatek/include/mt-plat/wakelock.h + +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 3726eacdf65d..9008a09172e1 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -527,4 +527,5 @@ source "drivers/misc/echo/Kconfig" + source "drivers/misc/cxl/Kconfig" + source "drivers/misc/ocxl/Kconfig" + source "drivers/misc/cardreader/Kconfig" ++source "drivers/misc/mediatek/Kconfig" + endmenu +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index af22bbc3d00c..cdced6d59e2c 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o + obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o + obj-$(CONFIG_OCXL) += ocxl/ + obj-$(CONFIG_MISC_RTSX) += cardreader/ ++obj-$(CONFIG_MTK_COMBO) += mediatek/ +diff --git a/drivers/misc/mediatek/Kconfig b/drivers/misc/mediatek/Kconfig +new file mode 100644 +index 000000000000..4829a6598c7a +--- /dev/null ++++ b/drivers/misc/mediatek/Kconfig +@@ -0,0 +1,11 @@ ++menu "Mediatek Peripherals " ++ ++config MTK_PLATFORM ++ string "MTK platform name" ++source "drivers/misc/mediatek/btif/Kconfig" ++ ++menu "Modem & Connectivity related configs" ++source "drivers/misc/mediatek/connectivity/Kconfig" ++endmenu ++ ++endmenu # CONN +diff --git a/drivers/misc/mediatek/Makefile b/drivers/misc/mediatek/Makefile +new file mode 100644 +index 000000000000..5e7f06db38f2 +--- /dev/null ++++ b/drivers/misc/mediatek/Makefile +@@ -0,0 +1,19 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++#$(call all-subdir-src-or-makefile) ++subdir-ccflags-y += -Werror ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/ ++ ++obj-$(CONFIG_MTK_COMBO) += connectivity/ ++obj-$(CONFIG_MTK_BTIF) += btif/ +diff --git a/drivers/misc/mediatek/btif/Kconfig b/drivers/misc/mediatek/btif/Kconfig +new file mode 100644 +index 000000000000..908898bd95c3 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/Kconfig +@@ -0,0 +1,4 @@ ++config MTK_BTIF ++ tristate"MediaTek BTIF Driver" ++ help ++ MTK connectivity BTIF driver for A/D die +diff --git a/drivers/misc/mediatek/btif/Makefile b/drivers/misc/mediatek/btif/Makefile +new file mode 100644 +index 000000000000..2be3ab66f426 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/Makefile +@@ -0,0 +1,33 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# BTIF driver for AD DIE ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++ #subdir-ccflags-y can be used in 2.6.34 in the future ++ MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM)) ++ subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include ++ subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/include/mach ++ subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat ++ ++ obj-y += common/ ++ ++# Otherwise we were called directly from the command ++# line; invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/btif/common/Makefile b/drivers/misc/mediatek/btif/common/Makefile +new file mode 100644 +index 000000000000..61e9d4ea9e89 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/Makefile +@@ -0,0 +1,31 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# BTIF driver for AD DIE ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++ ccflags-y += -I$(src)/inc ++ ccflags-y += -I$(src)/plat_inc ++ ++ obj-y += btif.o ++ btif-y := mtk_btif.o mtk_btif_exp.o btif_dma_plat.o btif_plat.o ++ ++# Otherwise we were called directly from the command ++# line; invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/btif/common/btif_dma_plat.c b/drivers/misc/mediatek/btif/common/btif_dma_plat.c +new file mode 100644 +index 000000000000..58be46927953 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/btif_dma_plat.c +@@ -0,0 +1,1436 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF-DMA" ++ ++#include "btif_dma_priv.h" ++ ++#define DMA_USER_ID "btif_driver" ++ ++/************************************Global variable***********************************/ ++ ++static MTK_BTIF_DMA_VFIFO mtk_tx_dma_vfifo = { ++ .vfifo = { ++ .p_vir_addr = NULL, ++ .phy_addr = 0, ++ .vfifo_size = TX_DMA_VFF_SIZE, ++ .thre = DMA_TX_THRE(TX_DMA_VFF_SIZE), ++ }, ++ .wpt = 0, ++ .last_wpt_wrap = 0, ++ .rpt = 0, ++ .last_rpt_wrap = 0, ++}; ++ ++static MTK_BTIF_IRQ_STR mtk_btif_tx_dma_irq = { ++ .name = "mtk btif tx dma irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_DMA_BTIF_TX_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++static MTK_BTIF_DMA_VFIFO mtk_rx_dma_vfifo = { ++ .vfifo = { ++ .p_vir_addr = NULL, ++ .phy_addr = 0, ++ .vfifo_size = RX_DMA_VFF_SIZE, ++ .thre = DMA_RX_THRE(RX_DMA_VFF_SIZE), ++ }, ++ ++ .wpt = 0, ++ .last_wpt_wrap = 0, ++ .rpt = 0, ++ .last_rpt_wrap = 0, ++}; ++ ++static MTK_BTIF_IRQ_STR mtk_btif_rx_dma_irq = { ++ .name = "mtk btif rx dma irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_DMA_BTIF_RX_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++static MTK_DMA_INFO_STR mtk_btif_tx_dma = { ++#ifndef CONFIG_OF ++ .base = AP_DMA_BASE + BTIF_TX_DMA_OFFSET, ++#endif ++ .dir = DMA_DIR_TX, ++ .p_irq = &mtk_btif_tx_dma_irq, ++ .p_vfifo = &(mtk_tx_dma_vfifo.vfifo), ++}; ++ ++static MTK_DMA_INFO_STR mtk_btif_rx_dma = { ++#ifndef CONFIG_OF ++ .base = AP_DMA_BASE + BTIF_RX_DMA_OFFSET, ++#endif ++ .dir = DMA_DIR_RX, ++ .p_irq = &mtk_btif_rx_dma_irq, ++ .p_vfifo = &(mtk_rx_dma_vfifo.vfifo), ++}; ++ ++static spinlock_t g_clk_cg_spinlock; /*dma clock's spinlock */ ++ ++/************************************Function declearation***********************************/ ++static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info); ++static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info); ++static int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_DMA_CTRL ctrl_id); ++static int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_DMA_CTRL ctrl_id); ++static int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++static int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag); ++static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag); ++static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info); ++static int _btif_dma_dump_dbg_reg(void); ++static void hal_btif_tx_dma_vff_set_for_4g(void); ++static void hal_btif_rx_dma_vff_set_for_4g(void); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ier_ctrl ++* DESCRIPTION ++* BTIF Tx DMA's interrupt enable/disable ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* enable [IN] control if tx interrupt enabled or not ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_receive_data ++* DESCRIPTION ++* receive data from btif module in DMA polling mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++static int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ const unsigned int max_len); ++ ++/************************************Function***********************************/ ++#endif ++ ++#ifdef CONFIG_OF ++static void hal_dma_set_default_setting(ENUM_DMA_DIR dma_dir) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = {0, 0, 0}; ++ unsigned int phy_base; ++ ++ if (dma_dir == DMA_DIR_RX) { ++ node = of_find_compatible_node(NULL, NULL, "mediatek,btif_rx"); ++ if (node) { ++ mtk_btif_rx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif_rx_dma.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get rx_dma irq(%d),register base(0x%lx)\n", ++ mtk_btif_rx_dma.p_irq->irq_id, mtk_btif_rx_dma.base); ++ } else { ++ BTIF_ERR_FUNC("get rx_dma device node fail\n"); ++ } ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif_rx_dma.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", ++ mtk_btif_rx_dma.p_irq->irq_flags); ++ } ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { ++ BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", ++ dma_dir); ++ } else { ++ BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", ++ dma_dir, (unsigned int)phy_base); ++ } ++ } else if (dma_dir == DMA_DIR_TX) { ++ node = of_find_compatible_node(NULL, NULL, "mediatek,btif_tx"); ++ if (node) { ++ mtk_btif_tx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif_tx_dma.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get tx_dma irq(%d),register base(0x%lx)\n", ++ mtk_btif_tx_dma.p_irq->irq_id, mtk_btif_tx_dma.base); ++ } else { ++ BTIF_ERR_FUNC("get tx_dma device node fail\n"); ++ } ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif_tx_dma.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", ++ mtk_btif_tx_dma.p_irq->irq_flags); ++ } ++ ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { ++ BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", ++ dma_dir); ++ } else { ++ BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", ++ dma_dir, (unsigned int)phy_base); ++ } ++ } ++ ++} ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_info_get ++* DESCRIPTION ++* get btif tx dma channel's information ++* PARAMETERS ++* dma_dir [IN] DMA's direction ++* RETURNS ++* pointer to btif dma's information structure ++*****************************************************************************/ ++P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = NULL; ++ ++ BTIF_TRC_FUNC(); ++#ifdef CONFIG_OF ++ hal_dma_set_default_setting(dma_dir); ++#endif ++ if (dma_dir == DMA_DIR_RX) ++ /*Rx DMA*/ ++ p_dma_info = &mtk_btif_rx_dma; ++ else if (dma_dir == DMA_DIR_TX) ++ /*Tx DMA*/ ++ p_dma_info = &mtk_btif_tx_dma; ++ else ++ /*print error log*/ ++ BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); ++ spin_lock_init(&g_clk_cg_spinlock); ++ BTIF_TRC_FUNC(); ++ return p_dma_info; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag) ++{ ++/*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/ ++/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ ++ int i_ret = 0; ++ unsigned long irq_flag = 0; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ static atomic_t s_clk_ref = ATOMIC_INIT(0); ++#else ++ static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; ++#endif ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_CTL ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++ if (flag == CLK_OUT_ENABLE) { ++ if (atomic_inc_return(&s_clk_ref) == 1) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); ++ i_ret = clk_enable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++ if (atomic_dec_return(&s_clk_ref) == 0) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif_apdma) calling\n"); ++ clk_disable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ ++#else ++ ++ if (status == flag) { ++ i_ret = 0; ++ BTIF_DBG_FUNC("dma clock already %s\n", ++ CLK_OUT_ENABLE == ++ status ? "enabled" : "disabled"); ++ } else { ++ if (flag == CLK_OUT_ENABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); ++ i_ret = clk_enable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); ++ clk_disable(clk_btif_apdma); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ } ++#endif ++ ++#else ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++#else ++ ++ status = flag; ++#endif ++ ++ i_ret = 0; ++#endif ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#else ++ ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ BTIF_DBG_FUNC("DMA's clock is %s\n", (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) ? "off" : "on"); ++#endif ++ return i_ret; ++} ++ ++int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int i_ret = 0; ++ unsigned int dat = 0; ++ unsigned long base = p_dma_info->base; ++ unsigned long addr_h = 0; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ if (p_dma_info->dir == DMA_DIR_RX) { ++ /*Rx DMA*/ ++ /*do hardware reset*/ ++ /* BTIF_SET_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ ++ /* BTIF_CLR_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ ++ BTIF_SET_BIT(RX_DMA_RST(base), DMA_WARM_RST); ++ do { ++ dat = BTIF_READ32(RX_DMA_EN(base)); ++ } while (0x01 & dat); ++ /*write vfifo base address to VFF_ADDR*/ ++ btif_reg_sync_writel(p_vfifo->phy_addr, RX_DMA_VFF_ADDR(base)); ++ if (enable_4G()) ++ hal_btif_rx_dma_vff_set_for_4g(); ++ else { ++ addr_h = p_vfifo->phy_addr >> 16; ++ addr_h = addr_h >> 16; ++ btif_reg_sync_writel(addr_h, RX_DMA_VFF_ADDR_H(base)); ++ } ++ /*write vfifo length to VFF_LEN*/ ++ btif_reg_sync_writel(p_vfifo->vfifo_size, RX_DMA_VFF_LEN(base)); ++ /*write wpt to VFF_WPT*/ ++ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, ++ RX_DMA_VFF_WPT(base)); ++ btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, ++ RX_DMA_VFF_RPT(base)); ++ /*write vff_thre to VFF_THRESHOLD*/ ++ btif_reg_sync_writel(p_vfifo->thre, RX_DMA_VFF_THRE(base)); ++ /*clear Rx DMA's interrupt status*/ ++ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), ++ RX_DMA_INT_DONE | RX_DMA_INT_THRE); ++ ++ /*enable Rx IER by default*/ ++ btif_rx_dma_ier_ctrl(p_dma_info, true); ++ } else { ++/*Tx DMA*/ ++/*do hardware reset*/ ++/* BTIF_SET_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ ++/* BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ ++ BTIF_SET_BIT(TX_DMA_RST(base), DMA_WARM_RST); ++ do { ++ dat = BTIF_READ32(TX_DMA_EN(base)); ++ } while (0x01 & dat); ++/*write vfifo base address to VFF_ADDR*/ ++ btif_reg_sync_writel(p_vfifo->phy_addr, TX_DMA_VFF_ADDR(base)); ++ if (enable_4G()) ++ hal_btif_tx_dma_vff_set_for_4g(); ++ else { ++ addr_h = p_vfifo->phy_addr >> 16; ++ addr_h = addr_h >> 16; ++ btif_reg_sync_writel(addr_h, TX_DMA_VFF_ADDR_H(base)); ++ } ++/*write vfifo length to VFF_LEN*/ ++ btif_reg_sync_writel(p_vfifo->vfifo_size, TX_DMA_VFF_LEN(base)); ++/*write wpt to VFF_WPT*/ ++ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, ++ TX_DMA_VFF_WPT(base)); ++ btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, ++ TX_DMA_VFF_RPT(base)); ++/*write vff_thre to VFF_THRESHOLD*/ ++ btif_reg_sync_writel(p_vfifo->thre, TX_DMA_VFF_THRE(base)); ++ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); ++ ++ hal_btif_dma_ier_ctrl(p_dma_info, false); ++ } ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ctrl ++* DESCRIPTION ++* enable/disable Tx DMA channel ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* ctrl_id [IN] enable/disable ID ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ ENUM_DMA_DIR dir = p_dma_info->dir; ++ ++ if (dir == DMA_DIR_RX) ++ i_ret = btif_rx_dma_ctrl(p_dma_info, ctrl_id); ++ else if (dir == DMA_DIR_TX) ++ i_ret = btif_tx_dma_ctrl(p_dma_info, ctrl_id); ++ else { ++ /*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid dma ctrl id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ return i_ret; ++} ++ ++int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ dma_rx_buf_write rx_cb) ++{ ++ if (p_dma_info->rx_cb != NULL) { ++ BTIF_DBG_FUNC ++ ("rx_cb already registered, replace (0x%p) with (0x%p)\n", ++ p_dma_info->rx_cb, rx_cb); ++ } ++ p_dma_info->rx_cb = rx_cb; ++ return 0; ++} ++ ++int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int dat; ++ ++ BTIF_TRC_FUNC(); ++ if (ctrl_id == DMA_CTRL_DISABLE) { ++ /*if write 0 to EN bit, DMA will be stopped imediately*/ ++ /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ ++ /*BTIF_CLR_BIT(TX_DMA_EN(base), DMA_EN_BIT);*/ ++ BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT); ++ do { ++ dat = BTIF_READ32(TX_DMA_STOP(base)); ++ } while (0x1 & dat); ++ BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n", ++ BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base))); ++ i_ret = 0; ++ } else if (ctrl_id == DMA_CTRL_ENABLE) { ++ BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT); ++ BTIF_DBG_FUNC("BTIF Tx DMA enabled\n"); ++ i_ret = 0; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int dat; ++ ++ BTIF_TRC_FUNC(); ++ ++ if (ctrl_id == DMA_CTRL_DISABLE) { ++ /*if write 0 to EN bit, DMA will be stopped imediately*/ ++ /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ ++ /*BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT);*/ ++ BTIF_SET_BIT(RX_DMA_STOP(base), DMA_STOP_BIT); ++ do { ++ dat = BTIF_READ32(RX_DMA_STOP(base)); ++ } while (0x1 & dat); ++ BTIF_DBG_FUNC("BTIF Rx DMA disabled,EN(0x%x),STOP(0x%x)\n", ++ BTIF_READ32(RX_DMA_EN(base)), BTIF_READ32(RX_DMA_STOP(base))); ++ i_ret = 0; ++ } else if (ctrl_id == DMA_CTRL_ENABLE) { ++ BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT); ++ BTIF_DBG_FUNC("BTIF Rx DMA enabled\n"); ++ i_ret = 0; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); ++ i_ret = ERR_INVALID_PAR; ++ } ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_vfifo_reset ++* DESCRIPTION ++* reset tx virtual fifo information, except memory information ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ unsigned int i_ret = -1; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ BTIF_TRC_FUNC(); ++ p_mtk_dma_vfifo->rpt = 0; ++ p_mtk_dma_vfifo->last_rpt_wrap = 0; ++ p_mtk_dma_vfifo->wpt = 0; ++ p_mtk_dma_vfifo->last_wpt_wrap = 0; ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ier_ctrl ++* DESCRIPTION ++* BTIF Tx DMA's interrupt enable/disable ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ ENUM_DMA_DIR dir = p_dma_info->dir; ++ ++ if (dir == DMA_DIR_RX) { ++ i_ret = btif_rx_dma_ier_ctrl(p_dma_info, en); ++ } else if (dir == DMA_DIR_TX) { ++ i_ret = btif_tx_dma_ier_ctrl(p_dma_info, en); ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("invalid DMA dma dir (%d)\n", dir); ++ i_ret = ERR_INVALID_PAR; ++ } ++ ++ return i_ret; ++} ++ ++int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++ BTIF_TRC_FUNC(); ++ if (!en) { ++ BTIF_CLR_BIT(RX_DMA_INT_EN(base), ++ (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); ++ } else { ++ BTIF_SET_BIT(RX_DMA_INT_EN(base), ++ (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); ++ } ++ i_ret = 0; ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++ BTIF_TRC_FUNC(); ++ if (!en) ++ BTIF_CLR_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); ++ else ++ BTIF_SET_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); ++ i_ret = 0; ++ BTIF_TRC_FUNC(); ++ ++ return i_ret; ++} ++ ++static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int tx_irq_done = 0; ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++/*if we enable this clock reference couner, just return , because when enter IRQ handler, DMA's clock will be opened*/ ++ tx_irq_done = 1; ++#else ++ unsigned long flag = 0; ++ unsigned long base = p_dma_info->base; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++ tx_irq_done = ((BTIF_READ32(TX_DMA_INT_FLAG(base)) & TX_DMA_INT_FLAG_MASK) == 0) ? 1 : 0; ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++#endif ++ return tx_irq_done; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++#define MAX_CONTINIOUS_TIMES 512 ++ unsigned int i_ret = -1; ++ unsigned int valid_size = 0; ++ unsigned int vff_len = 0; ++ unsigned int left_len = 0; ++ unsigned long base = p_dma_info->base; ++ static int flush_irq_counter; ++ static struct timeval start_timer; ++ static struct timeval end_timer; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ BTIF_ERR_FUNC ++ ("%s: clock is off before irq status clear done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*check if Tx VFF Left Size equal to VFIFO size or not*/ ++ vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base)); ++ valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ if (flush_irq_counter == 0) ++ do_gettimeofday(&start_timer); ++ if ((valid_size > 0) && (valid_size < 8)) { ++ i_ret = _tx_dma_flush(p_dma_info); ++ flush_irq_counter++; ++ if (flush_irq_counter >= MAX_CONTINIOUS_TIMES) { ++ do_gettimeofday(&end_timer); ++/* ++ * when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while ++ * we assume that btif cannot send data for a long time ++ * in order not to generate interrupt continiously, which may effect system's performance. ++ * we clear tx flag and disable btif tx interrupt ++ */ ++/*clear interrupt flag*/ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), ++ TX_DMA_INT_FLAG_MASK); ++/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ ++ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); ++ BTIF_ERR_FUNC ++ ("**********************ERROR, ERROR, ERROR**************************\n"); ++ BTIF_ERR_FUNC ++ ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n", ++ MAX_CONTINIOUS_TIMES, start_timer.tv_sec, ++ start_timer.tv_usec, end_timer.tv_usec, ++ end_timer.tv_usec); ++ } ++ } else if (vff_len == left_len) { ++ flush_irq_counter = 0; ++/*clear interrupt flag*/ ++ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); ++/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ ++ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); ++ } else { ++#if 0 ++ BTIF_ERR_FUNC ++ ("**********************WARNING**************************\n"); ++ BTIF_ERR_FUNC("invalid irq condition, dump register\n"); ++ hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL); ++#endif ++ BTIF_DBG_FUNC ++ ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n", ++ vff_len, valid_size, left_len); ++ } ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_send_data ++* DESCRIPTION ++* send data through btif in DMA mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, ++ const unsigned char *p_buf, const unsigned int buf_len) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ unsigned int len_to_send = buf_len; ++ unsigned int ava_len = 0; ++ unsigned int wpt = 0; ++ unsigned int last_wpt_wrap = 0; ++ unsigned int vff_size = 0; ++ unsigned char *p_data = (unsigned char *)p_buf; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ ++ BTIF_TRC_FUNC(); ++ if ((p_buf == NULL) || (buf_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid parameters, p_buf:0x%p, buf_len:%d\n", ++ p_buf, buf_len); ++ return i_ret; ++ } ++/*check if tx dma in flush operation? if yes, should wait until DMA finish flush operation*/ ++/*currently uplayer logic will make sure this pre-condition*/ ++/*disable Tx IER, in case Tx irq happens, flush bit may be set in irq handler*/ ++ btif_tx_dma_ier_ctrl(p_dma_info, false); ++ ++ vff_size = p_mtk_vfifo->vfifo.vfifo_size; ++ ava_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_MASK; ++ last_wpt_wrap = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_WRAP; ++ ++/* ++ * copy data to vFIFO, Note: ava_len should always large than buf_len, ++ * otherwise common logic layer will not call hal_dma_send_data ++ */ ++ if (buf_len > ava_len) { ++ BTIF_ERR_FUNC ++ ("length to send:(%d) < length available(%d), abnormal!!!---!!!\n", ++ buf_len, ava_len); ++ WARN_ON(buf_len > ava_len); /* this will cause kernel panic */ ++ } ++ ++ len_to_send = buf_len < ava_len ? buf_len : ava_len; ++ if (len_to_send + wpt >= vff_size) { ++ unsigned int tail_len = vff_size - wpt; ++ ++ memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, tail_len); ++ p_data += tail_len; ++ memcpy(p_mtk_vfifo->vfifo.p_vir_addr, ++ p_data, len_to_send - tail_len); ++/*make sure all data write to memory area tx vfifo locates*/ ++ mb(); ++ ++/*calculate WPT*/ ++ wpt = wpt + len_to_send - vff_size; ++ last_wpt_wrap ^= DMA_WPT_WRAP; ++ } else { ++ memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), ++ p_data, len_to_send); ++/*make sure all data write to memory area tx vfifo locates*/ ++ mb(); ++ ++/*calculate WPT*/ ++ wpt += len_to_send; ++ } ++ p_mtk_vfifo->wpt = wpt; ++ p_mtk_vfifo->last_wpt_wrap = last_wpt_wrap; ++ ++/*make sure tx dma is allowed(tx flush bit is not set) to use before update WPT*/ ++ if (hal_dma_is_tx_allow(p_dma_info)) { ++ /*make sure tx dma enabled*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ ++ /*update WTP to Tx DMA controller's control register*/ ++ btif_reg_sync_writel(wpt | last_wpt_wrap, TX_DMA_VFF_WPT(base)); ++ ++ if ((BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) < 8) && ++ (BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) > 0)) { ++ /* ++ * 0 < valid size in Tx vFIFO < 8 && TX Flush is not in process? ++ * if yes, set flush bit to DMA ++ */ ++ _tx_dma_flush(p_dma_info); ++ } ++ i_ret = len_to_send; ++ } else { ++/*TODO: print error log*/ ++ BTIF_ERR_FUNC("Tx DMA flush operation is in process, this case should never happen,", ++ "please check if tx operation is allowed before call this API\n"); ++/*if flush operation is in process , we will return 0*/ ++ i_ret = 0; ++ } ++ ++/*Enable Tx IER*/ ++ btif_tx_dma_ier_ctrl(p_dma_info, true); ++ ++ BTIF_TRC_FUNC(); ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ bool b_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); ++ unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info); ++ ++/* ++ * only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0, ++ * we can identify tx operation finished ++ * confirmed with DE. ++ */ ++ if ((valid_size == 0) && (inter_size == 0) && (tx_done == 1)) { ++ b_ret = true; ++ BTIF_DBG_FUNC("DMA tx finished.\n"); ++ } else { ++ BTIF_DBG_FUNC ++ ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n", ++ valid_size, inter_size, tx_done); ++ b_ret = false; ++ } ++ ++ return b_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_get_ava_room ++* DESCRIPTION ++* get tx available room ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* available room size ++*****************************************************************************/ ++int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ ++/*read vFIFO's left size*/ ++ i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); ++ BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret); ++ if (i_ret == 0) ++ BTIF_INFO_FUNC("DMA tx vfifo is full.\n"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_allow ++* DESCRIPTION ++* is tx operation allowed by DMA ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) ++#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) ++ ++ bool b_ret = false; ++ unsigned int wait_us = 8 / MIN_TX_MB; /*only ava length */ ++/*see if flush operation is in process*/ ++ b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; ++ if (!b_ret) { ++ usleep_range(wait_us, 2 * wait_us); ++ b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; ++ } ++ if (!b_ret) ++ BTIF_WARN_FUNC("btif tx dma is not allowed\n"); ++/*after Tx flush operation finished, HW will set DMA_EN back to 0 and stop DMA*/ ++ return b_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_rx_dma_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++ int i_ret = -1; ++ unsigned int valid_len = 0; ++ unsigned int wpt_wrap = 0; ++ unsigned int rpt_wrap = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int tail_len = 0; ++ unsigned int real_len = 0; ++ unsigned long base = p_dma_info->base; ++ P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; ++ dma_rx_buf_write rx_cb = p_dma_info->rx_cb; ++ unsigned char *p_vff_buf = NULL; ++ unsigned char *vff_base = p_vfifo->p_vir_addr; ++ unsigned int vff_size = p_vfifo->vfifo_size; ++ P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, ++ MTK_BTIF_DMA_VFIFO, ++ vfifo); ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), flag); ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*disable DMA Rx IER*/ ++ hal_btif_dma_ier_ctrl(p_dma_info, false); ++ ++/*clear Rx DMA's interrupt status*/ ++ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); ++ ++ valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ if ((valid_len == 0) && (rpt == wpt)) { ++ BTIF_DBG_FUNC ++ ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n", ++ rpt, wpt); ++ } ++ ++ i_ret = 0; ++ ++ while ((valid_len > 0) || (rpt != wpt)) { ++ rpt_wrap = rpt & DMA_RPT_WRAP; ++ wpt_wrap = wpt & DMA_WPT_WRAP; ++ rpt &= DMA_RPT_MASK; ++ wpt &= DMA_WPT_MASK; ++ ++/*calcaute length of available data in vFIFO*/ ++ if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) ++ real_len = wpt + vff_size - rpt; ++ else ++ real_len = wpt - rpt; ++ ++ if (rx_cb != NULL) { ++ tail_len = vff_size - rpt; ++ p_vff_buf = vff_base + rpt; ++ if (tail_len >= real_len) { ++ (*rx_cb) (p_dma_info, p_vff_buf, real_len); ++ } else { ++ (*rx_cb) (p_dma_info, p_vff_buf, tail_len); ++ p_vff_buf = vff_base; ++ (*rx_cb) (p_dma_info, p_vff_buf, real_len - ++ tail_len); ++ } ++ i_ret += real_len; ++ } else ++ BTIF_ERR_FUNC("no rx_cb found, please check your init process\n"); ++ mb(); ++ rpt += real_len; ++ if (rpt >= vff_size) { ++ /*read wrap bit should be revert*/ ++ rpt_wrap ^= DMA_RPT_WRAP; ++ rpt %= vff_size; ++ } ++ rpt |= rpt_wrap; ++/*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/ ++ p_mtk_vfifo->wpt = wpt; ++ p_mtk_vfifo->last_wpt_wrap = wpt_wrap; ++ ++ p_mtk_vfifo->rpt = rpt; ++ p_mtk_vfifo->last_rpt_wrap = rpt_wrap; ++ ++/*update rpt information to DMA controller*/ ++ btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base)); ++ ++/*get vff valid size again and check if rx data is processed completely*/ ++ valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ } ++ ++/*enable DMA Rx IER*/ ++ hal_btif_dma_ier_ctrl(p_dma_info, true); ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); ++ ++ return i_ret; ++} ++ ++static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int int_flag = 0; ++ unsigned int enable = 0; ++ unsigned int stop = 0; ++ unsigned int flush = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int int_buf = 0; ++ unsigned int valid_size = 0; ++ /*unsigned long irq_flag = 0;*/ ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ int_flag = BTIF_READ32(TX_DMA_INT_FLAG(base)); ++ enable = BTIF_READ32(TX_DMA_EN(base)); ++ stop = BTIF_READ32(TX_DMA_STOP(base)); ++ flush = BTIF_READ32(TX_DMA_FLUSH(base)); ++ wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)); ++ rpt = BTIF_READ32(TX_DMA_VFF_RPT(base)); ++ int_buf = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); ++ valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ ++ BTIF_INFO_FUNC("DMA's clock is on\n"); ++ BTIF_INFO_FUNC("Tx DMA's base address: 0x%lx\n", base); ++ ++ if (flag == REG_TX_DMA_ALL) { ++ BTIF_INFO_FUNC("TX_EN(:0x%x\n", enable); ++ BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); ++ BTIF_INFO_FUNC("TX_STOP:0x%x\n", stop); ++ BTIF_INFO_FUNC("TX_FLUSH:0x%x\n", flush); ++ BTIF_INFO_FUNC("TX_WPT:0x%x\n", wpt); ++ BTIF_INFO_FUNC("TX_RPT:0x%x\n", rpt); ++ BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); ++ BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); ++ BTIF_INFO_FUNC("INT_EN:0x%x\n", ++ BTIF_READ32(TX_DMA_INT_EN(base))); ++ BTIF_INFO_FUNC("TX_RST:0x%x\n", BTIF_READ32(TX_DMA_RST(base))); ++ BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_ADDR(base))); ++ BTIF_INFO_FUNC("VFF_LEN:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_LEN(base))); ++ BTIF_INFO_FUNC("TX_THRE:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_THRE(base))); ++ BTIF_INFO_FUNC("W_INT_BUF_SIZE:0x%x\n", ++ BTIF_READ32(TX_DMA_W_INT_BUF_SIZE(base))); ++ BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", ++ BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base))); ++ BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", ++ BTIF_READ32(TX_DMA_DEBUG_STATUS(base))); ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("unknown flag:%d\n", flag); ++ } ++ BTIF_INFO_FUNC("tx dma %s\n", (enable & DMA_EN_BIT) && ++ (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); ++ BTIF_INFO_FUNC("data in tx dma is %s sent by HW\n", ++ ((wpt == rpt) && ++ (int_buf == 0)) ? "completely" : "not completely"); ++ ++ return i_ret; ++} ++ ++static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ ENUM_BTIF_REG_ID flag) ++{ ++ int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int int_flag = 0; ++ unsigned int enable = 0; ++ unsigned int stop = 0; ++ unsigned int flush = 0; ++ unsigned int wpt = 0; ++ unsigned int rpt = 0; ++ unsigned int int_buf = 0; ++ unsigned int valid_size = 0; ++ /*unsigned long irq_flag = 0;*/ ++#if defined(CONFIG_MTK_CLKMGR) ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++ if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ BTIF_INFO_FUNC("dump DMA status register\n"); ++ _btif_dma_dump_dbg_reg(); ++ ++ int_flag = BTIF_READ32(RX_DMA_INT_FLAG(base)); ++ enable = BTIF_READ32(RX_DMA_EN(base)); ++ stop = BTIF_READ32(RX_DMA_STOP(base)); ++ flush = BTIF_READ32(RX_DMA_FLUSH(base)); ++ wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); ++ rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); ++ int_buf = BTIF_READ32(RX_DMA_INT_BUF_SIZE(base)); ++ valid_size = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ ++ BTIF_INFO_FUNC("DMA's clock is on\n"); ++ BTIF_INFO_FUNC("Rx DMA's base address: 0x%lx\n", base); ++ ++ if (flag == REG_RX_DMA_ALL) { ++ BTIF_INFO_FUNC("RX_EN(:0x%x\n", enable); ++ BTIF_INFO_FUNC("RX_STOP:0x%x\n", stop); ++ BTIF_INFO_FUNC("RX_FLUSH:0x%x\n", flush); ++ BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); ++ BTIF_INFO_FUNC("RX_WPT:0x%x\n", wpt); ++ BTIF_INFO_FUNC("RX_RPT:0x%x\n", rpt); ++ BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); ++ BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); ++ BTIF_INFO_FUNC("INT_EN:0x%x\n", ++ BTIF_READ32(RX_DMA_INT_EN(base))); ++ BTIF_INFO_FUNC("RX_RST:0x%x\n", BTIF_READ32(RX_DMA_RST(base))); ++ BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_ADDR(base))); ++ BTIF_INFO_FUNC("VFF_LEN:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_LEN(base))); ++ BTIF_INFO_FUNC("RX_THRE:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_THRE(base))); ++ BTIF_INFO_FUNC("RX_FLOW_CTRL_THRE:0x%x\n", ++ BTIF_READ32(RX_DMA_FLOW_CTRL_THRE(base))); ++ BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", ++ BTIF_READ32(RX_DMA_VFF_LEFT_SIZE(base))); ++ BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", ++ BTIF_READ32(RX_DMA_DEBUG_STATUS(base))); ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("unknown flag:%d\n", flag); ++ } ++ BTIF_INFO_FUNC("rx dma %s\n", (enable & DMA_EN_BIT) && ++ (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); ++ BTIF_INFO_FUNC("data in rx dma is %s by driver\n", ++ ((wpt == rpt) && ++ (int_buf == 0)) ? "received" : "not received"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag) ++{ ++ unsigned int i_ret = -1; ++ ++ if (p_dma_info->dir == DMA_DIR_TX) ++ i_ret = hal_tx_dma_dump_reg(p_dma_info, flag); ++ else if (p_dma_info->dir == DMA_DIR_RX) ++ i_ret = hal_rx_dma_dump_reg(p_dma_info, flag); ++ else ++ BTIF_WARN_FUNC("unknown dir:%d\n", p_dma_info->dir); ++ ++ return i_ret; ++} ++ ++static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ unsigned int i_ret = -1; ++ unsigned long base = p_dma_info->base; ++ unsigned int stop = BTIF_READ32(TX_DMA_STOP(base)); ++ ++/*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/ ++ if ((stop && DMA_STOP_BIT) != 0) ++ BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n"); ++ else { ++ BTIF_DBG_FUNC("flush tx dma\n"); ++ BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT); ++ i_ret = 0; ++ } ++ return i_ret; ++} ++ ++static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info) ++{ ++ bool b_ret = true; ++ unsigned long base = p_dma_info->base; ++ ++/*see if flush operation is in process*/ ++ b_ret = ((DMA_FLUSH_BIT & BTIF_READ32(TX_DMA_FLUSH(base))) != 0) ? true : false; ++ ++ return b_ret; ++} ++ ++int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("op id: %d\n", opid); ++ switch (opid) { ++ case BTIF_PM_DPIDLE_EN: ++ i_ret = 0; ++ break; ++ case BTIF_PM_DPIDLE_DIS: ++ i_ret = 0; ++ break; ++ case BTIF_PM_SUSPEND: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESUME: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESTORE_NOIRQ:{ ++ unsigned int flag = 0; ++ P_MTK_BTIF_IRQ_STR p_irq = p_dma_info->p_irq; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING; ++ else ++ flag = IRQF_TRIGGER_FALLING; /*make this as default type */ ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ default: ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ } ++#endif ++/* irq_set_irq_type(p_irq->irq_id, flag); */ ++ i_ret = 0; ++ } ++ i_ret = 0; ++ break; ++ default: ++ i_ret = ERR_INVALID_PAR; ++ break; ++ } ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_receive_data ++* DESCRIPTION ++* receive data from btif module in DMA polling mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++ unsigned int i_ret = -1; ++ ++ return i_ret; ++} ++#endif ++ ++int _btif_dma_dump_dbg_reg(void) ++{ ++#if 0 ++ static MTK_BTIF_DMA_REG_DMP_DBG g_dma_dbg_regs[] = { ++ {0x10201180, 0x0}, ++ {0x10201184, 0x0}, ++ {0x10201188, 0x0}, ++ {0x1020118C, 0x0}, ++ {0x10201190, 0x0}, ++ {0x1000320C, 0x0}, ++ {0x10003210, 0x0}, ++ {0x10003214, 0x0}, ++ }; ++ ++ int i = 0; ++ char *addr1 = NULL; ++ char *addr2 = NULL; ++ ++ int array_num = ARRAY_SIZE(g_dma_dbg_regs) ++ ++ addr1 = ioremap(g_dma_dbg_regs[0].reg_addr, 0x20); ++ if (addr1) { ++ for (i = 0; i < 5; i++) ++ g_dma_dbg_regs[i].reg_val = *(volatile unsigned int*)(addr1 + i*4); ++ iounmap(addr1); ++ } ++ ++ addr2 = ioremap(g_dma_dbg_regs[5].reg_addr, 0x10); ++ if (addr2) { ++ g_dma_dbg_regs[5].reg_val = *(volatile unsigned int*)(addr2); ++ g_dma_dbg_regs[6].reg_val = *(volatile unsigned int*)(addr2+4); ++ g_dma_dbg_regs[7].reg_val = *(volatile unsigned int*)(addr2+8); ++ iounmap(addr2); ++ } ++ ++ for (i = 0; i < array_num; i++) ++ BTIF_INFO_FUNC("-<0x%lx, 0x%08x>\n", g_dma_dbg_regs[i].reg_addr, g_dma_dbg_regs[i].reg_val); ++#endif ++ return 0; ++} ++ ++static void hal_btif_tx_dma_vff_set_for_4g(void) ++{ ++ BTIF_DBG_FUNC("Set btif tx_vff_addr bit29\n"); ++ BTIF_SET_BIT(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), DMA_VFF_BIT29_OFFSET); ++ BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), ++ BTIF_READ32(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base))); ++} ++static void hal_btif_rx_dma_vff_set_for_4g(void) ++{ ++ BTIF_DBG_FUNC("Set btif rx_vff_addr bit29\n"); ++ BTIF_SET_BIT(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), DMA_VFF_BIT29_OFFSET); ++ BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), ++ BTIF_READ32(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base))); ++} ++ +diff --git a/drivers/misc/mediatek/btif/common/btif_plat.c b/drivers/misc/mediatek/btif/common/btif_plat.c +new file mode 100644 +index 000000000000..e098e902317c +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/btif_plat.c +@@ -0,0 +1,1396 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF" ++ ++#define NEW_TX_HANDLING_SUPPORT 1 ++ ++#include "btif_pub.h" ++#include "btif_priv.h" ++ ++#define BTIF_USER_ID "btif_driver" ++ ++static spinlock_t g_clk_cg_spinlock; /*BTIF clock's spinlock */ ++ ++/*-----------------------------BTIF Module Clock and Power Control Defination------------------*/ ++ ++MTK_BTIF_IRQ_STR mtk_btif_irq = { ++ .name = "mtk btif irq", ++ .is_irq_sup = true, ++ .reg_flag = false, ++#ifdef CONFIG_OF ++ .irq_flags = IRQF_TRIGGER_NONE, ++#else ++ .irq_id = MT_BTIF_IRQ_ID, ++ .sens_type = IRQ_SENS_LVL, ++ .lvl_type = IRQ_LVL_LOW, ++#endif ++ .p_irq_handler = NULL, ++}; ++ ++/* ++ * will call clock manager's API export by WCP to control BTIF's clock, ++ * but we may need to access these registers in case of btif clock control logic is wrong in clock manager ++ */ ++ ++MTK_BTIF_INFO_STR mtk_btif = { ++#ifndef CONFIG_OF ++ .base = MTK_BTIF_REG_BASE, ++#endif ++ .p_irq = &mtk_btif_irq, ++ .tx_fifo_size = BTIF_TX_FIFO_SIZE, ++ .rx_fifo_size = BTIF_RX_FIFO_SIZE, ++ .tx_tri_lvl = BTIF_TX_FIFO_THRE, ++ .rx_tri_lvl = BTIF_RX_FIFO_THRE, ++ .rx_data_len = 0, ++ .p_tx_fifo = NULL, ++}; ++#if !(NEW_TX_HANDLING_SUPPORT) ++static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); ++#endif ++ ++static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ const unsigned int max_len); ++static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_ier_ctrl ++* DESCRIPTION ++* BTIF Rx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if rx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_ier_ctrl ++* DESCRIPTION ++* BTIF Tx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++static int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* _btif_receive_data ++* DESCRIPTION ++* receive data from btif module in FIFO polling mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++static int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len); ++static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count); ++#endif ++ ++static int btif_dump_array(char *string, char *p_buf, int len) ++{ ++ unsigned int idx = 0; ++ unsigned char str[30]; ++ unsigned char *p_str; ++ ++ pr_debug("========dump %s start ========\n", string, len); ++ p_str = &str[0]; ++ for (idx = 0; idx < len; idx++, p_buf++) { ++ sprintf(p_str, "%02x ", *p_buf); ++ p_str += 3; ++ if (7 == (idx % 8)) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ p_str = &str[0]; ++ } ++ } ++ if (len % 8) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ } ++ pr_debug("========dump %s end========\n", string); ++ return 0; ++} ++ ++#if NEW_TX_HANDLING_SUPPORT ++static int _btif_tx_fifo_init(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = -1; ++ ++ spin_lock_init(&(p_btif_info->tx_fifo_spinlock)); ++ ++ if (p_btif_info->p_tx_fifo == NULL) { ++ p_btif_info->p_tx_fifo = kzalloc(sizeof(struct kfifo), ++ GFP_ATOMIC); ++ if (p_btif_info->p_tx_fifo == NULL) { ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); ++ goto ret; ++ } ++ ++ i_ret = kfifo_alloc(p_btif_info->p_tx_fifo, ++ BTIF_HAL_TX_FIFO_SIZE, GFP_ATOMIC); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); ++ i_ret = -ENOMEM; ++ goto ret; ++ } ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC ++ ("p_btif_info->p_tx_fifo is already init p_btif_info->p_tx_fifo(0x%p)\n", ++ p_btif_info->p_tx_fifo); ++ i_ret = 0; ++ } ++ret: ++ return i_ret; ++} ++ ++static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = 0; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag); ++ if (p_btif_info->p_tx_fifo == NULL) ++ i_ret = 0; ++ else ++ i_ret = kfifo_avail(p_btif_info->p_tx_fifo); ++ spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("tx kfifo:0x%p, available room:%d\n", p_btif_info->p_tx_fifo, i_ret); ++ return i_ret; ++} ++ ++static int _btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif_info) ++{ ++ int i_ret = 0; ++ ++ if (p_btif_info->p_tx_fifo != NULL) ++ kfifo_reset(p_btif_info->p_tx_fifo); ++ return i_ret; ++} ++ ++#endif ++ ++#ifdef CONFIG_OF ++static void _btif_set_default_setting(void) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = {0, 0, 0}; ++ unsigned int phy_base; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,mtk-btif"); ++ if (node) { ++ mtk_btif.p_irq->irq_id = irq_of_parse_and_map(node, 0); ++ /*fixme, be compitable arch 64bits*/ ++ mtk_btif.base = (unsigned long)of_iomap(node, 0); ++ BTIF_INFO_FUNC("get btif irq(%d),register base(0x%lx)\n", ++ mtk_btif.p_irq->irq_id, mtk_btif.base); ++ } else { ++ BTIF_ERR_FUNC("get btif device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); ++ } else { ++ mtk_btif.p_irq->irq_flags = irq_info[2]; ++ BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", mtk_btif.p_irq->irq_flags); ++ } ++ ++ if (of_property_read_u32_index(node, "reg", 1, &phy_base)) ++ BTIF_ERR_FUNC("get register phy base from DTS fail\n"); ++ else ++ BTIF_INFO_FUNC("get register phy base(0x%x)\n", (unsigned int)phy_base); ++} ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_info_get ++* DESCRIPTION ++* get btif's information included base address , irq related information ++* PARAMETERS ++* RETURNS ++* BTIF's information ++*****************************************************************************/ ++P_MTK_BTIF_INFO_STR hal_btif_info_get(void) ++{ ++#if NEW_TX_HANDLING_SUPPORT ++ int i_ret = 0; ++/*tx fifo and fifo lock init*/ ++ i_ret = _btif_tx_fifo_init(&mtk_btif); ++ if (i_ret == 0) ++ BTIF_INFO_FUNC("_btif_tx_fifo_init succeed\n"); ++ else ++ BTIF_ERR_FUNC("_btif_tx_fifo_init failed, i_ret:%d\n", i_ret); ++ ++#endif ++ ++#ifdef CONFIG_OF ++ _btif_set_default_setting(); ++#endif ++ ++ spin_lock_init(&g_clk_cg_spinlock); ++ ++ return &mtk_btif; ++} ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_get_and_prepare ++* DESCRIPTION ++* get clock from device tree and prepare for enable/disable control ++* PARAMETERS ++* pdev device pointer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++#if !defined(CONFIG_MTK_CLKMGR) ++int hal_btif_clk_get_and_prepare(struct platform_device *pdev) ++{ ++ int i_ret = -1; ++ ++ clk_btif = devm_clk_get(&pdev->dev, "main"); ++ if (IS_ERR(clk_btif)) { ++ BTIF_ERR_FUNC("[CCF]cannot get clk_btif clock.\n"); ++ return PTR_ERR(clk_btif); ++ } ++ BTIF_ERR_FUNC("[CCF]clk_btif=%p\n", clk_btif); ++ clk_btif_apdma = devm_clk_get(&pdev->dev, "apdmac"); ++ if (IS_ERR(clk_btif_apdma)) { ++ BTIF_ERR_FUNC("[CCF]cannot get clk_btif_apdma clock.\n"); ++ return PTR_ERR(clk_btif_apdma); ++ } ++ BTIF_ERR_FUNC("[CCF]clk_btif_apdma=%p\n", clk_btif_apdma); ++ ++ i_ret = clk_prepare(clk_btif); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("clk_prepare clk_btif failed! ret:%d\n", i_ret); ++ return i_ret; ++ } ++ ++ i_ret = clk_prepare(clk_btif_apdma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("clk_prepare clk_btif_apdma failed! ret:%d\n", i_ret); ++ return i_ret; ++ } ++ return i_ret; ++} ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_unprepare ++* DESCRIPTION ++* unprepare btif clock and apdma clock ++* PARAMETERS ++* none ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_unprepare(void) ++{ ++ clk_unprepare(clk_btif); ++ clk_unprepare(clk_btif_apdma); ++ return 0; ++} ++#endif ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of BTIF module ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag) ++{ ++/*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/ ++/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ ++ int i_ret = 0; ++ unsigned long irq_flag = 0; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ static atomic_t s_clk_ref = ATOMIC_INIT(0); ++#else ++ static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; ++#endif ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_CTL ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++ if (flag == CLK_OUT_ENABLE) { ++ if (atomic_inc_return(&s_clk_ref) == 1) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); ++ i_ret = clk_enable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++ if (atomic_dec_return(&s_clk_ref) == 0) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); ++ clk_disable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ ++#else ++ ++ if (status == flag) { ++ i_ret = 0; ++ BTIF_DBG_FUNC("btif clock already %s\n", ++ CLK_OUT_ENABLE == ++ status ? "enabled" : "disabled"); ++ } else { ++ if (flag == CLK_OUT_ENABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++#else ++ BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); ++ i_ret = clk_enable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++ } else if (flag == CLK_OUT_DISABLE) { ++#if defined(CONFIG_MTK_CLKMGR) ++ i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); ++ status = (i_ret == 0) ? flag : status; ++ if (i_ret) { ++ BTIF_WARN_FUNC ++ ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", ++ i_ret); ++ } ++#else ++ BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); ++ clk_disable(clk_btif); ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ } else { ++ i_ret = ERR_INVALID_PAR; ++ BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); ++ } ++ } ++#endif ++ ++#else ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ ++#else ++ ++ status = flag; ++#endif ++ ++ i_ret = 0; ++#endif ++ ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#else ++ ++ if (i_ret == 0) { ++ BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); ++ } else { ++ BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", ++ flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); ++ } ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ BTIF_DBG_FUNC("BTIF's clock is %s\n", (clock_is_on(MTK_BTIF_CG_BIT) == 0) ? "off" : "on"); ++#endif ++ return i_ret; ++} ++ ++static int btif_new_handshake_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool enable) ++{ ++ unsigned long base = p_btif->base; ++ ++ if (enable == true) ++ BTIF_SET_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); ++ else ++ BTIF_CLR_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); ++ return true; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_hw_init ++* DESCRIPTION ++* BTIF hardware init ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ _btif_tx_fifo_reset(p_btif); ++#endif ++ ++/*set to normal mode*/ ++ btif_reg_sync_writel(BTIF_FAKELCR_NORMAL_MODE, BTIF_FAKELCR(base)); ++/*set to newhandshake mode*/ ++ btif_new_handshake_ctrl(p_btif, true); ++/*No need to access: enable sleep mode*/ ++/*No need to access: set Rx timeout count*/ ++/*set Tx threshold*/ ++/*set Rx threshold*/ ++/*disable internal loopback test*/ ++ ++/*set Rx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++/*clear Rx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++/*set Tx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++/*clear Tx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++ btif_reg_sync_writel(BTIF_TRI_LVL_TX(p_btif->tx_tri_lvl) ++ | BTIF_TRI_LVL_RX(p_btif->rx_tri_lvl) ++ | BTIF_TRI_LOOP_DIS, BTIF_TRI_LVL(base)); ++ hal_btif_loopback_ctrl(p_btif, false); ++/*disable BTIF Tx DMA mode*/ ++ hal_btif_tx_mode_ctrl(p_btif, false); ++/*disable BTIF Rx DMA mode*/ ++ hal_btif_rx_mode_ctrl(p_btif, false); ++/*auto reset*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_AUTORST_EN); ++/*disable Tx IER*/ ++ hal_btif_tx_ier_ctrl(p_btif, false); ++/*enable Rx IER by default*/ ++ hal_btif_rx_ier_ctrl(p_btif, true); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_ier_ctrl ++* DESCRIPTION ++* BTIF Rx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if rx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_RXFEN); ++ else ++ BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_RXFEN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_ier_ctrl ++* DESCRIPTION ++* BTIF Tx interrupt enable/disable ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* enable [IN] control if tx interrupt enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_TXEEN); ++ else ++ BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_TXEEN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++ i_ret = 0; ++ ++ return i_ret; ++} ++ ++#ifndef MTK_BTIF_MARK_UNUSED_API ++ ++/***************************************************************************** ++* FUNCTION ++* _btif_receive_data ++* DESCRIPTION ++* receive data from btif module in FIFO polling mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* positive means data is available, 0 means no data available ++*****************************************************************************/ ++int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (max_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++ i_ret = btif_rx_irq_handler(p_btif, p_buf, max_len); ++ ++ return i_ret; ++} ++ ++int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); ++ else ++ BTIF_SET_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ unsigned int value = 0; ++ ++/*read BTIF_TRI_LVL*/ ++ value = BTIF_READ32(BTIF_TRI_LVL(base)); ++/*clear Tx threshold bits*/ ++ value &= (~BTIF_TRI_LVL_TX_MASK); ++/*set tx threshold bits*/ ++ value |= BTIF_TRI_LVL_TX(BTIF_TX_FIFO_THRE); ++/*write back to BTIF_TRI_LVL*/ ++ btif_reg_sync_writel(value, BTIF_TRI_LVL(base)); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_rx_fifo_reset ++* DESCRIPTION ++* reset BTIF's rx fifo ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* ec [IN] control if loopback mode is enabled or not ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_rx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++/*set Rx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++ ++/*clear Rx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_tx_fifo_reset ++* DESCRIPTION ++* reset BTIF's tx fifo ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++/*set Tx FIFO clear bit to 1*/ ++ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++/*clear Tx FIFO clear bit to 0*/ ++ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_loopback_ctrl ++* DESCRIPTION ++* BTIF Tx/Rx loopback mode set, this operation can only be done after set BTIF to normal mode ++* PARAMETERS ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (en == false) ++ BTIF_CLR_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); ++ else ++ BTIF_SET_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); ++ ++/*TODO:do we need to read back ? Answer: no*/ ++/*TODO:do we need to dsb?*/ ++ i_ret = 0; ++ return i_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_handler ++* DESCRIPTION ++* lower level interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success; negative means fail; positive means rx data length ++*****************************************************************************/ ++int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ unsigned int iir = 0; ++ unsigned int rx_len = 0; ++ unsigned long base = p_btif->base; ++ ++#if 0 ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (max_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++#endif ++ unsigned long irq_flag = 0; ++ ++ spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); ++ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*read interrupt identifier register*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ ++/*is rx interrupt exist?*/ ++#if 0 ++ while ((iir & BTIF_IIR_RX) && (rx_len < max_len)) { ++ rx_len += ++ btif_rx_irq_handler(p_btif, (p_buf + rx_len), ++ (max_len - rx_len)); ++ ++/*update IIR*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++#endif ++ ++ while (iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) { ++ rx_len += btif_rx_irq_handler(p_btif, p_buf, max_len); ++ ++/*update IIR*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++ ++/*is tx interrupt exist?*/ ++ if (iir & BTIF_IIR_TX_EMPTY) ++ i_ret = btif_tx_irq_handler(p_btif); ++ spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); ++ ++ i_ret = rx_len != 0 ? rx_len : i_ret; ++ return i_ret; ++} ++ ++int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, btif_rx_buf_write rx_cb) ++{ ++ if (p_btif_info->rx_cb != NULL) ++ BTIF_DBG_FUNC("rx_cb already registered, replace (0x%p) with (0x%p)\n", ++ p_btif_info->rx_cb, rx_cb); ++ p_btif_info->rx_cb = rx_cb; ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_rx_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* positive means length of rx data , negative means fail ++*****************************************************************************/ ++static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, const unsigned int max_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = 0; ++ unsigned int iir = 0; ++ unsigned int rx_len = 0; ++ unsigned long base = p_btif_info->base; ++ unsigned char rx_buf[256]; ++ unsigned int local_buf_len = 256; ++ btif_rx_buf_write rx_cb = p_btif_info->rx_cb; ++ unsigned int total_len = 0; ++ ++/*read interrupt identifier register*/ ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ while ((iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) && ++ (rx_len < local_buf_len)) { ++ rx_buf[rx_len] = BTIF_READ8(base); ++ rx_len++; ++/*need to consult CC Hwang for advice */ ++/* ++ * whether we need to do memory barrier here ++ * Ans: no ++ */ ++/* ++ * whether we need to d memory barrier when call BTIF_SET_BIT or BTIF_CLR_BIT ++ * Ans: no ++ */ ++ if (rx_len == local_buf_len) { ++ if (rx_cb) ++ (*rx_cb) (p_btif_info, rx_buf, rx_len); ++ rx_len = 0; ++ total_len += rx_len; ++ } ++ iir = BTIF_READ32(BTIF_IIR(base)); ++ } ++ total_len += rx_len; ++ if (rx_len && rx_cb) ++ (*rx_cb) (p_btif_info, rx_buf, rx_len); ++ ++/* ++ * make sure all data write back to memory, mb or dsb? ++ * need to consult CC Hwang for advice ++ * Ans: no need here ++ */ ++ i_ret = total_len; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* btif_tx_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ int how_many = 0; ++ unsigned int lsr; ++ unsigned int ava_len = 0; ++ unsigned long base = p_btif->base; ++ char local_buf[BTIF_TX_FIFO_SIZE]; ++ char *p_data = local_buf; ++ unsigned long flag = 0; ++ ++ struct kfifo *p_tx_fifo = p_btif->p_tx_fifo; ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (lsr & BTIF_LSR_TEMT_BIT) ++ /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE; ++ else if (lsr & BTIF_LSR_THRE_BIT) ++ /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; ++ else { ++ /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ++ ava_len = 0; ++ goto ret; ++ } ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++ how_many = kfifo_out(p_tx_fifo, local_buf, ava_len); ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, ++ kfifo_avail(p_tx_fifo)); ++ while (how_many--) ++ btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++/*clear Tx enable flag if necessary*/ ++ if (kfifo_is_empty(p_tx_fifo)) { ++ hal_btif_tx_ier_ctrl(p_btif, false); ++ BTIF_DBG_FUNC("BTIF tx FIFO is empty\n"); ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ret: ++#else ++/*clear Tx enable flag*/ ++ hal_btif_tx_ier_ctrl(p_btif, false); ++#endif ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_mode_ctrl ++* DESCRIPTION ++* set BTIF tx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (mode == BTIF_MODE_DMA) ++ /*set to DMA mode*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); ++ else ++ /*set to PIO mode*/ ++ BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_mode_ctrl ++* DESCRIPTION ++* set BTIF rx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++ ++ if (mode == BTIF_MODE_DMA) ++ /*set to DMA mode*/ ++ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); ++ else ++ /*set to PIO mode*/ ++ BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); ++ ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_send_data ++* DESCRIPTION ++* send data through btif in FIFO mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* positive means number of data sent; 0 means no data put to FIFO; negative means error happens ++*****************************************************************************/ ++int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, ++ const unsigned char *p_buf, const unsigned int buf_len) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ ++ unsigned int ava_len = 0; ++ unsigned int sent_len = 0; ++ ++#if !(NEW_TX_HANDLING_SUPPORT) ++ unsigned long base = p_btif->base; ++ unsigned int lsr = 0; ++ unsigned int left_len = 0; ++ unsigned char *p_data = (unsigned char *)p_buf; ++#endif ++ ++/*check parameter valid or not*/ ++ if ((p_buf == NULL) || (buf_len == 0)) { ++ i_ret = ERR_INVALID_PAR; ++ return i_ret; ++ } ++#if NEW_TX_HANDLING_SUPPORT ++ ava_len = _get_btif_tx_fifo_room(p_btif); ++ sent_len = buf_len <= ava_len ? buf_len : ava_len; ++ if (sent_len > 0) { ++ int enqueue_len = 0; ++ unsigned long flag = 0; ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); ++ enqueue_len = kfifo_in(p_btif->p_tx_fifo, ++ (unsigned char *)p_buf, sent_len); ++ if (sent_len != enqueue_len) { ++ BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n", ++ sent_len, enqueue_len); ++ } ++ i_ret = enqueue_len; ++ mb(); ++/*enable BTIF Tx IRQ*/ ++ hal_btif_tx_ier_ctrl(p_btif, true); ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ++ BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len); ++ } else { ++ i_ret = 0; ++ } ++#else ++ while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) { ++ /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (lsr & BTIF_LSR_TEMT_BIT) ++ /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE; ++ else if (lsr & BTIF_LSR_THRE_BIT) ++ /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ++ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; ++ else { ++ /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ++ ava_len = 0; ++ break; ++ } ++ ++ left_len = buf_len - sent_len; ++/*ava_len will be real length will write to BTIF THR*/ ++ ava_len = ava_len > left_len ? left_len : ava_len; ++/*update sent length valud after this operation*/ ++ sent_len += ava_len; ++/* ++ * whether we need memory barrier here? ++ * Ans: No, no memory ordering issue exist, ++ * CPU will make sure logically right ++ */ ++ while (ava_len--) ++ btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); ++ ++ } ++/* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */ ++ ++ i_ret = sent_len; ++ ++/*enable BTIF Tx IRQ*/ ++ hal_btif_tx_ier_ctrl(p_btif, true); ++#endif ++ return i_ret; ++} ++ ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_raise_wak_sig ++* DESCRIPTION ++* raise wakeup signal to counterpart ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif) ++{ ++ int i_ret = -1; ++ unsigned long base = p_btif->base; ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ BTIF_ERR_FUNC("%s: clock is off before send wakeup signal!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++/*write 0 to BTIF_WAK to pull ap_wakeup_consyss low */ ++ BTIF_CLR_BIT(BTIF_WAK(base), BTIF_WAK_BIT); ++ ++/*wait for a period for longer than 1/32k period, here we use 40us*/ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ usleep_range(128, 160); ++/* ++ * according to linux/documentation/timers/timers-how-to, we choose usleep_range ++ * SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): * Use usleep_range ++ */ ++/*write 1 to pull ap_wakeup_consyss high*/ ++ BTIF_SET_BIT(BTIF_WAK(base), BTIF_WAK_BIT); ++ i_ret = 0; ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag) ++{ ++/*Chaozhong: To be implement*/ ++ int i_ret = -1; ++ int idx = 0; ++ /*unsigned long irq_flag = 0;*/ ++ unsigned long base = p_btif->base; ++ unsigned char reg_map[0xE0 / 4] = { 0 }; ++ unsigned int lsr = 0x0; ++ unsigned int dma_en = 0; ++ ++ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ ++#if defined(CONFIG_MTK_CLKMGR) ++ if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", ++ __FILE__); ++ return i_ret; ++ } ++#endif ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ dma_en = BTIF_READ32(BTIF_DMA_EN(base)); ++ /* ++ * here we omit 1st register which is THR/RBR register to avoid ++ * Rx data read by this debug information accidently ++ */ ++ for (idx = 1; idx < sizeof(reg_map); idx++) ++ reg_map[idx] = BTIF_READ8(p_btif->base + (4 * idx)); ++ /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ ++ BTIF_INFO_FUNC("BTIF's clock is on\n"); ++ BTIF_INFO_FUNC("base address: 0x%lx\n", base); ++ switch (flag) { ++ case REG_BTIF_ALL: ++#if 0 ++ BTIF_INFO_FUNC("BTIF_IER:0x%x\n", BTIF_READ32(BTIF_IER(base))); ++ BTIF_INFO_FUNC("BTIF_IIR:0x%x\n", BTIF_READ32(BTIF_IIR(base))); ++ BTIF_INFO_FUNC("BTIF_FAKELCR:0x%x\n", ++ BTIF_READ32(BTIF_FAKELCR(base))); ++ BTIF_INFO_FUNC("BTIF_LSR:0x%x\n", BTIF_READ32(BTIF_LSR(base))); ++ BTIF_INFO_FUNC("BTIF_SLEEP_EN:0x%x\n", ++ BTIF_READ32(BTIF_SLEEP_EN(base))); ++ BTIF_INFO_FUNC("BTIF_DMA_EN:0x%x\n", ++ BTIF_READ32(BTIF_DMA_EN(base))); ++ BTIF_INFO_FUNC("BTIF_RTOCNT:0x%x\n", ++ BTIF_READ32(BTIF_RTOCNT(base))); ++ BTIF_INFO_FUNC("BTIF_TRI_LVL:0x%x\n", ++ BTIF_READ32(BTIF_TRI_LVL(base))); ++ BTIF_INFO_FUNC("BTIF_WAT_TIME:0x%x\n", ++ BTIF_READ32(BTIF_WAT_TIME(base))); ++ BTIF_INFO_FUNC("BTIF_HANDSHAKE:0x%x\n", ++ BTIF_READ32(BTIF_HANDSHAKE(base))); ++#endif ++ btif_dump_array("BTIF register", reg_map, sizeof(reg_map)); ++ break; ++ default: ++ break; ++ } ++ ++ BTIF_INFO_FUNC("Tx DMA %s\n", ++ (dma_en & BTIF_DMA_EN_TX) ? "enabled" : "disabled"); ++ BTIF_INFO_FUNC("Rx DMA %s\n", ++ (dma_en & BTIF_DMA_EN_RX) ? "enabled" : "disabled"); ++ ++ BTIF_INFO_FUNC("Rx data is %s\n", ++ (lsr & BTIF_LSR_DR_BIT) ? "not empty" : "empty"); ++ BTIF_INFO_FUNC("Tx data is %s\n", ++ (lsr & BTIF_LSR_TEMT_BIT) ? "empty" : "not empty"); ++ ++ return i_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ unsigned int lsr = 0; ++ unsigned long flags = 0; ++ unsigned long base = p_btif->base; ++ unsigned int tx_empty = 0; ++ unsigned int rx_dr = 0; ++ unsigned int tx_irq_disable = 0; ++ ++/* ++ * 3 conditions allow clock to be disable ++ * 1. if TEMT is set or not ++ * 2. if DR is set or not ++ * 3. Tx IRQ is disabled or not ++ */ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ tx_empty = lsr & BTIF_LSR_TEMT_BIT; ++ rx_dr = lsr & BTIF_LSR_DR_BIT; ++ tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN; ++ ++ b_ret = ++ (tx_empty && (tx_irq_disable == 0) && (rx_dr == 0)) ? true : false; ++ if (!b_ret) { ++ BTIF_DBG_FUNC ++ ("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", ++ tx_empty, rx_dr, tx_irq_disable); ++ } ++#if NEW_TX_HANDLING_SUPPORT ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); ++/*clear Tx enable flag if necessary*/ ++ if (!(kfifo_is_empty(p_btif->p_tx_fifo))) { ++ BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n"); ++ b_ret = false; ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); ++#endif ++ return b_ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_allow ++* DESCRIPTION ++* whether tx is allowed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) ++{ ++#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) ++#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) ++ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ ++#if NEW_TX_HANDLING_SUPPORT ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); ++/*clear Tx enable flag if necessary*/ ++ if (kfifo_is_full(p_btif->p_tx_fifo)) { ++ BTIF_WARN_FUNC("BTIF tx FIFO is full\n"); ++ b_ret = false; ++ } else { ++ b_ret = true; ++ } ++ spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); ++#else ++ unsigned int lsr = 0; ++ unsigned long base = p_btif->base; ++ unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB; /*only ava length */ ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ ++ if (!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT))) { ++ BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us); ++/* usleep_range(wait_us, 3 * 10 * wait_us); */ ++ usleep_range(wait_us, 3 * wait_us); ++ } ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; ++ if (!b_ret) ++ BTIF_DBG_FUNC(" tx is not allowed for the moment\n"); ++ else ++ BTIF_DBG_FUNC(" tx is allowed\n"); ++#endif ++ return b_ret; ++} ++ ++#if !(NEW_TX_HANDLING_SUPPORT) ++ ++static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) ++{ ++/*Chaozhong: To be implement*/ ++ bool b_ret = false; ++ unsigned long base = p_btif->base; ++ unsigned int lsr = 0; ++ ++/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ ++ lsr = BTIF_READ32(BTIF_LSR(base)); ++ b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; ++ return b_ret; ++} ++#endif ++ ++int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid) ++{ ++ int i_ret = -1; ++ ++ BTIF_DBG_FUNC("op id: %d\n", opid); ++ switch (opid) { ++ case BTIF_PM_DPIDLE_EN: ++ i_ret = 0; ++ break; ++ case BTIF_PM_DPIDLE_DIS: ++ i_ret = 0; ++ break; ++ case BTIF_PM_SUSPEND: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESUME: ++ i_ret = 0; ++ break; ++ case BTIF_PM_RESTORE_NOIRQ:{ ++ unsigned int flag = 0; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING; ++ else ++ flag = IRQF_TRIGGER_FALLING; /*make this as default type */ ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ default: ++ flag = IRQF_TRIGGER_LOW; /*make this as default type */ ++ break; ++ } ++#endif ++/* irq_set_irq_type(p_irq->irq_id, flag); */ ++ i_ret = 0; ++ } ++ break; ++ default: ++ i_ret = ERR_INVALID_PAR; ++ break; ++ } ++ ++ return i_ret; ++} ++void mtk_btif_read_cpu_sw_rst_debug_plat(void) ++{ ++#define CONSYS_AP2CONN_WAKEUP_OFFSET 0x00000064 ++ BTIF_WARN_FUNC("+CONSYS_AP2CONN_WAKEUP_OFFSET(0x%x)\n", ++ BTIF_READ32(mtk_btif.base + CONSYS_AP2CONN_WAKEUP_OFFSET)); ++} ++ +diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h +new file mode 100644 +index 000000000000..5e2f5a9857d9 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_BTIF_H_ ++#define __MTK_BTIF_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* gettimeofday */ ++#include ++ ++#include "btif_pub.h" ++#include "btif_dma_pub.h" ++#include "mtk_btif_exp.h" ++ ++#define BTIF_PORT_NR 1 ++#define BTIF_USER_NAME_MAX_LEN 32 ++ ++/*-------------Register Defination Start ---------------*/ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) ++#define BTIF_RX_BUFFER_SIZE (1024 * 32) ++#else ++#define BTIF_RX_BUFFER_SIZE (1024 * 64) ++#endif ++#define BTIF_TX_FIFO_SIZE (1024 * 4) ++ ++/*------------Register Defination End ----------------*/ ++ ++/*------------BTIF Module Clock and Power Control Defination---------------*/ ++typedef enum _ENUM_BTIF_RX_TYPE_ { ++ BTIF_IRQ_CTX = 0, ++ BTIF_TASKLET_CTX = BTIF_IRQ_CTX + 1, ++ BTIF_THREAD_CTX = BTIF_TASKLET_CTX + 1, ++ BTIF_WQ_CTX = BTIF_THREAD_CTX + 1, ++ BTIF_RX_TYPE_MAX, ++} ENUM_BTIF_RX_TYPE; ++ ++typedef enum _ENUM_BTIF_TX_TYPE_ { ++ BTIF_TX_USER_CTX = 0, ++ BTIF_TX_SINGLE_CTX = BTIF_TX_USER_CTX + 1, ++ BTIF_TX_TYPE_MAX, ++} ENUM_BTIF_TX_TYPE; ++ ++typedef enum _ENUM_BTIF_STATE_ { ++ B_S_OFF = 0, ++ B_S_SUSPEND = B_S_OFF + 1, ++ B_S_DPIDLE = B_S_SUSPEND + 1, ++ B_S_ON = B_S_DPIDLE + 1, ++ B_S_MAX, ++} ENUM_BTIF_STATE; ++ ++#define ENABLE_BTIF_RX_DMA 1 ++#define ENABLE_BTIF_TX_DMA 1 ++ ++#if ENABLE_BTIF_TX_DMA ++#define BTIF_TX_MODE BTIF_MODE_DMA ++#else ++#define BTIF_TX_MODE BTIF_MODE_PIO ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++#define BTIF_RX_MODE BTIF_MODE_DMA ++#else ++#define BTIF_RX_MODE BTIF_MODE_PIO ++#endif ++ ++#define BTIF_RX_BTM_CTX BTIF_THREAD_CTX/*BTIF_WQ_CTX*//* BTIF_TASKLET_CTX */ ++/* ++ * -- cannot be used because , ++ * mtk_wcn_stp_parser data will call *(stp_if_tx) to send ack, ++ * in which context sleepable lock or usleep operation may be used, ++ * these operation is not allowed in tasklet, may cause schedule_bug ++ */ ++ ++#define BTIF_TX_CTX BTIF_TX_USER_CTX /* BTIF_TX_SINGLE_CTX */ ++ ++#define ENABLE_BTIF_RX_THREAD_RT_SCHED 0 ++#define MAX_BTIF_RXD_TIME_REC 3 ++ ++/*Structure Defination*/ ++ ++/*-----------------BTIF setting--------------*/ ++typedef struct _mtk_btif_setting_ { ++ ENUM_BTIF_MODE tx_mode; /*BTIF Tx Mode Setting */ ++ ENUM_BTIF_MODE rx_mode; /*BTIF Tx Mode Setting */ ++ ENUM_BTIF_RX_TYPE rx_type; /*rx handle type */ ++ ENUM_BTIF_TX_TYPE tx_type; /*tx type */ ++} mtk_btif_setting, *p_mtk_btif_setting; ++/*---------------------------------------------------------------------------*/ ++ ++#if 0 ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_register_ { ++ unsigned int iir; /*Interrupt Identification Register */ ++ unsigned int lsr; /*Line Status Register */ ++ unsigned int fake_lcr; /*Fake Lcr Regiseter */ ++ unsigned int fifo_ctrl; /*FIFO Control Register */ ++ unsigned int ier; /*Interrupt Enable Register */ ++ unsigned int sleep_en; /*Sleep Enable Register */ ++ unsigned int rto_counter; /*Rx Timeout Counter Register */ ++ unsigned int dma_en; /*DMA Enalbe Register */ ++ unsigned int tri_lvl; /*Tx/Rx Trigger Level Register */ ++ unsigned int wat_time; /*Async Wait Time Register */ ++ unsigned int handshake; /*New HandShake Mode Register */ ++ unsigned int sleep_wak; /*Sleep Wakeup Reigster */ ++} mtk_btif_register, *p_mtk_btif_register; ++/*---------------------------------------------------------------------------*/ ++ ++#endif ++ ++typedef struct _btif_buf_str_ { ++ unsigned int size; ++ unsigned char *p_buf; ++ /* ++ * For Tx: next Tx data pointer to FIFO; ++ * For Rx: next read data pointer from BTIF user ++ */ ++ unsigned int rd_idx; ++ /* ++ * For Tx: next Tx data pointer from BTIF user; ++ * For Rx: next write data(from FIFO) pointer ++ */ ++ unsigned int wr_idx; ++} btif_buf_str, *p_btif_buf_str; ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_dma_ { ++ /*p_mtk_btif*/ void *p_btif; ++ /*BTIF pointer to which DMA belongs */ ++ ++#if 0 ++ unsigned int channel; /*DMA's channel */ ++#endif ++ ++ ENUM_BTIF_DIR dir; /*DMA's direction: */ ++ bool enable; /*DMA enable or disable flag */ ++ ++ P_MTK_DMA_INFO_STR p_dma_info; /*DMA's IRQ information */ ++ ++#if 0 ++ mtk_dma_register register; /*DMA's register */ ++#endif ++ ++ spinlock_t iolock; /*io lock for DMA channel */ ++ atomic_t entry; /* entry count */ ++} mtk_btif_dma, *p_mtk_btif_dma; ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) ++#define BTIF_LOG_ENTRY_NUM 10 ++#else ++#define BTIF_LOG_ENTRY_NUM 30 ++#endif ++ ++#define BTIF_LOG_SZ 1536 ++ ++typedef void (*MTK_BTIF_RX_NOTIFY) (void); ++ ++typedef struct _btif_log_buf_t_ { ++ unsigned int len; ++ struct timeval timer; ++ unsigned char buffer[BTIF_LOG_SZ]; ++} BTIF_LOG_BUF_T, *P_BTIF_LOG_BUF_T; ++ ++typedef struct _btif_log_queue_t_ { ++ ENUM_BTIF_DIR dir; ++ bool enable; ++ bool output_flag; ++ unsigned int in; ++ unsigned int out; ++ unsigned int size; ++ spinlock_t lock; ++ P_BTIF_LOG_BUF_T p_queue[BTIF_LOG_ENTRY_NUM]; ++} BTIF_LOG_QUEUE_T, *P_BTIF_LOG_QUEUE_T; ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_ { ++ unsigned int open_counter; /*open counter */ ++ bool enable; /*BTIF module enable flag */ ++ bool lpbk_flag; /*BTIF module enable flag */ ++#if 0 ++ unsigned long base; /* BTIF controller base address */ ++#endif ++ ++ ENUM_BTIF_STATE state; /*BTIF state mechanism */ ++ struct mutex state_mtx; /*lock to BTIF state mechanism's state change */ ++ struct mutex ops_mtx; /*lock to BTIF's open and close */ ++ ++#if 0 ++ mtk_btif_register register; /*BTIF registers */ ++#endif ++ ++ ENUM_BTIF_MODE tx_mode; /* BTIF Tx channel mode */ ++ ENUM_BTIF_MODE rx_mode; /* BTIF Rx channel mode */ ++ struct mutex tx_mtx; /*lock to BTIF's tx process */ ++/*rx handling */ ++ ENUM_BTIF_RX_TYPE btm_type; /*BTIF Rx bottom half context */ ++/*tx handling*/ ++ ENUM_BTIF_TX_TYPE tx_ctx; /*BTIF tx context */ ++/* unsigned char rx_buf[BTIF_RX_BUFFER_SIZE]; */ ++ btif_buf_str btif_buf; ++ spinlock_t rx_irq_spinlock; /*lock for rx irq handling */ ++ ++/*rx workqueue information*/ ++ /*lock to BTIF's rx bottom half when kernel thread is used */ ++ struct mutex rx_mtx; ++ struct workqueue_struct *p_rx_wq; ++ struct work_struct rx_work; ++ ++ struct workqueue_struct *p_tx_wq; ++ struct work_struct tx_work; ++ struct kfifo *p_tx_fifo; ++ ++/*rx tasklet information*/ ++ struct tasklet_struct rx_tasklet; ++ /*lock to BTIF's rx bottom half when tasklet is used */ ++ spinlock_t rx_tasklet_spinlock; ++ ++/*rx thread information*/ ++ struct task_struct *p_task; ++ struct completion rx_comp; ++ ++ mtk_btif_setting *setting; /*BTIF setting */ ++ ++ p_mtk_btif_dma p_tx_dma; /*BTIF Tx channel DMA */ ++ p_mtk_btif_dma p_rx_dma; /*BTIF Rx channel DMA */ ++ ++ MTK_WCN_BTIF_RX_CB rx_cb; /*Rx callback function */ ++ MTK_BTIF_RX_NOTIFY rx_notify; ++ ++ P_MTK_BTIF_INFO_STR p_btif_info; /*BTIF's information */ ++ ++/*Log Tx data to buffer*/ ++ BTIF_LOG_QUEUE_T tx_log; ++ ++/*Log Rx data to buffer*/ ++ BTIF_LOG_QUEUE_T rx_log; ++ ++/* struct list_head *p_user_list; */ ++ struct list_head user_list; ++/* get btif dev pointer*/ ++ void *private_data; ++} mtk_btif, *p_mtk_btif; ++/*---------------------------------------------------------------------------*/ ++ ++/*---------------------------------------------------------------------------*/ ++#if 0 ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_dma_register_ { ++ unsigned int int_flag; /*Tx offset:0x0 Rx offset:0x0 */ ++ unsigned int int_enable; /*Tx offset:0x4 Rx offset:0x4 */ ++ unsigned int dma_enable; /*Tx offset:0x8 Rx offset:0x8 */ ++ unsigned int dma_reset; /*Tx offset:0xc Rx offset:0xc */ ++ unsigned int dma_stop; /*Tx offset:0x10 Rx offset:0x10 */ ++ unsigned int dma_flush; /*Tx offset:0x14 Rx offset:0x14 */ ++ unsigned int vff_addr; /*Tx offset:0x1c Rx offset:0x1c */ ++ unsigned int vff_len; /*Tx offset:0x24 Rx offset:0x24 */ ++ unsigned int vff_thr; /*Tx offset:0x28 Rx offset:0x28 */ ++ unsigned int vff_wpt; /*Tx offset:0x2c Rx offset:0x2c */ ++ unsigned int vff_rpt; /*Tx offset:0x30 Rx offset:0x30 */ ++ unsigned int rx_fc_thr; /*Tx:No this register Rx offset:0x34 */ ++ unsigned int int_buf_size; /*Tx offset:0x38 Rx offset:0x38 */ ++ unsigned int vff_valid_size; /*Tx offset:0x3c Rx offset:0x3c */ ++ unsigned int vff_left_size; /*Tx offset:0x40 Rx offset:0x40 */ ++ unsigned int debug_status; /*Tx offset:0x50 Rx offset:0x50 */ ++} mtk_dma_register, *p_mtk_dma_register; ++/*---------------------------------------------------------------------------*/ ++#endif ++ ++/*---------------------------------------------------------------------------*/ ++typedef struct _mtk_btif_user_ { ++ bool enable; /*register its state */ ++ struct list_head entry; /*btif_user's bi-direction list table */ ++ /*BTIF's user, static allocation */ ++ char u_name[BTIF_USER_NAME_MAX_LEN]; ++ unsigned long u_id; ++ p_mtk_btif p_btif; ++} mtk_btif_user, *p_mtk_btif_user; ++ ++/*---------------------------------------------------------------------------*/ ++#define BBS_PTR(ptr, idx) ((ptr->p_buf) + idx) ++ ++#define BBS_SIZE(ptr) ((ptr)->size) ++#define BBS_MASK(ptr) (BBS_SIZE(ptr) - 1) ++#define BBS_COUNT(ptr) ((ptr)->wr_idx >= (ptr)->rd_idx ? (ptr)->wr_idx - \ ++(ptr)->rd_idx : BBS_SIZE(ptr) - \ ++((ptr)->rd_idx - (ptr)->wr_idx)) ++#define BBS_COUNT_CUR(ptr, wr_idx) (wr_idx >= (ptr)->rd_idx ? wr_idx - \ ++(ptr)->rd_idx : BBS_SIZE(ptr) - \ ++((ptr)->rd_idx - wr_idx)) ++ ++#define BBS_LEFT(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) ++ ++#define BBS_AVL_SIZE(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) ++#define BBS_FULL(ptr) (BBS_COUNT(ptr) - BBS_SIZE(ptr)) ++#define BBS_EMPTY(ptr) ((ptr)->wr_idx == (ptr)->rd_idx) ++#define BBS_WRITE_MOVE_NEXT(ptr) ((ptr)->wr_idx = \ ++((ptr)->wr_idx + 1) & BBS_MASK(ptr)) ++#define BBS_READ_MOVE_NEXT(ptr) ((ptr)->rd_idx = \ ++((ptr)->rd_idx + 1) & BBS_MASK(ptr)) ++ ++#define BBS_INIT(ptr) \ ++{ \ ++(ptr)->rd_idx = (ptr)->wr_idx = 0; \ ++(ptr)->size = BTIF_RX_BUFFER_SIZE; \ ++} ++ ++ ++#define BTIF_MUTEX_UNLOCK(x) mutex_unlock(x) ++ ++extern mtk_btif g_btif[]; ++ ++int btif_open(p_mtk_btif p_btif); ++int btif_close(p_mtk_btif p_btif); ++int btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++int btif_enter_dpidle(p_mtk_btif p_btif); ++int btif_exit_dpidle(p_mtk_btif p_btif); ++int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb); ++ ++/*for test purpose*/ ++int _btif_suspend(p_mtk_btif p_btif); ++int _btif_resume(p_mtk_btif p_btif); ++int _btif_restore_noirq(p_mtk_btif p_btif); ++ ++int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); ++int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, ++ int len); ++int btif_dump_data(char *p_buf, int len); ++int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que); ++int btif_log_buf_init(p_mtk_btif p_btif); ++int btif_dump_reg(p_mtk_btif p_btif); ++int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify); ++int btif_raise_wak_signal(p_mtk_btif p_btif); ++int btif_clock_ctrl(p_mtk_btif p_btif, int en); ++bool btif_parser_wmt_evt(p_mtk_btif p_btif, ++ const char *sub_str, ++ unsigned int sub_len); ++void mtk_btif_read_cpu_sw_rst_debug(void); ++ ++#endif /*__MTK_BTIF_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h +new file mode 100644 +index 000000000000..3752644fe0aa +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h +@@ -0,0 +1,280 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_BTIF_EXP_H_ ++#define _MTK_BTIF_EXP_H_ ++ ++/*--------------marco defination---------------*/ ++#define BTIF_MAX_LEN_PER_PKT 2048 ++#define BTIF_RXD_BE_BLOCKED_DETECT 1 ++/*--------------Enum Defination---------------*/ ++typedef enum _ENUM_BTIF_DPIDLE_ { ++ BTIF_DPIDLE_DISABLE = 0, ++ BTIF_DPIDLE_ENABLE = BTIF_DPIDLE_DISABLE + 1, ++ BTIF_DPIDLE_MAX, ++} ENUM_BTIF_DPIDLE_CTRL; ++ ++typedef enum _ENUM_BTIF_LPBK_MODE_ { ++ BTIF_LPBK_DISABLE = 0, ++ BTIF_LPBK_ENABLE = BTIF_LPBK_DISABLE + 1, ++ BTIF_LPBK_MAX, ++} ENUM_BTIF_LPBK_MODE; ++ ++typedef enum _ENUM_BTIF_DBG_ID_ { ++ BTIF_DISABLE_LOGGER = 0, ++ BTIF_ENABLE_LOGGER = BTIF_DISABLE_LOGGER + 1, ++ BTIF_DUMP_LOG = BTIF_ENABLE_LOGGER + 1, ++ BTIF_CLR_LOG = BTIF_DUMP_LOG + 1, ++ BTIF_DUMP_BTIF_REG = BTIF_CLR_LOG + 1, ++ BTIF_ENABLE_RT_LOG = BTIF_DUMP_BTIF_REG + 1, ++ BTIF_DISABLE_RT_LOG = BTIF_ENABLE_RT_LOG + 1, ++ BTIF_DBG_MAX, ++} ENUM_BTIF_DBG_ID; ++ ++typedef enum _ENUM_BTIF_OP_ERROR_CODE_ { ++ E_BTIF_AGAIN = 0, ++ E_BTIF_FAIL = -1, ++ E_BTIF_BAD_POINTER = -2, ++ E_BTIF_NO_SPACE = -3, ++ E_BTIF_INTR = -4, ++ E_BTIF_INVAL_PARAM = -5, ++ E_BTIF_ALREADY_OPEN = -6, ++ E_BTIF_NOT_OPEN = -7, ++ E_BTIF_INVAL_STATE = -8, ++} ENUM_BTIF_OP_ERROR_CODE; ++ ++/*--------------End of Enum Defination---------------*/ ++ ++/*--------------Type Definition---------------*/ ++ ++typedef int (*MTK_WCN_BTIF_RX_CB) (const unsigned char *p_buf, ++ unsigned int len); ++ ++/*--------------End of Type Definition---------------*/ ++ ++/*--------------Normal Mode API declearation---------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_open ++* DESCRIPTION ++* open BTIF interface, will do BTIF module HW and SW initialization ++* PARAMETERS ++* p_owner [IN] pointer to owner who call this API, ++* currently there are 2 owner ("stp" or "btif_tester") ++* may use this module ++* user's id string must be less than 32 bytes ++* for "stp", BTIF will call rx callback function to route rx data to STP module ++* for "stp_tester", BTIF will save rx data ++* and wait for native process to access ++* p_id [IN] BTIF's user id will be put to this address ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++* if open success, value p_id will be the only identifier for ++* user to access BTIF's other operations ++* including read/write/dpidle_ctrl/rx_cb_retister ++* this user id is only an identifier used for owner identification ++*****************************************************************************/ ++int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id); ++//EXPORT_SYMBOL(mtk_wcn_btif_open) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_close ++* DESCRIPTION ++* close BTIF interface, will do BTIF module HW and SW de-initialization ++* once this API is called, p_btif should never be used by BTIF's user again ++* PARAMETERS ++* u_id [IN] BTIF's user id ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_close(unsigned long u_id); ++//EXPORT_SYMBOL(mtk_wcn_btif_close) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_write ++* DESCRIPTION ++* send data throuth BTIF module ++* there's no internal buffer to cache STP data in BTIF driver, ++* if in DMA mode ++* btif driver will check if there's enough space ++* in vFIFO for data to send in DMA mode ++* if yes, put data to vFIFO and return corresponding data length to caller ++* if no, corresponding error code will be returned to called ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN] pointer to target data to send ++* len [IN] data length (should be less than 2014 bytes per STP package) ++* ++* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller ++* if btif driver detected that no space is available in Tx FIFO, ++* will return E_BTIF_NO_SPACE, ++* mostly something is wrong with BTIF or consys when this ++* return value is returned ++* RETURNS ++* int positive: data length send through BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++* E_BTIF_AGAIN (0) will be returned to caller if btif does not have ++* enough vFIFO to send data, when caller get 0, ++* he should wait for a moment (5~10ms maybe) and ++* try a few times (maybe 10~20) ++* if still get E_BTIF_AGAIN, should call BTIF's debug API and ++* dump BTIF driver and BTIF/DMA register information to kernel log ++* for debug ++* E_BTIF_BAD_POINTER will be returned to caller if btif is not ++* opened successfully before call this API ++* E_BTIF_INVAL_PARAM will be returned if parameter is not valid ++ ++*****************************************************************************/ ++int mtk_wcn_btif_write(unsigned long u_id, ++ const unsigned char *p_buf, unsigned int len); ++//EXPORT_SYMBOL(mtk_wcn_btif_write) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_read ++* DESCRIPTION ++* read data from BTIF module ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN/OUT] pointer to buffer where rx data will be put ++* max_len [IN] max buffer length ++* RETURNS ++* int positive: data length read from BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_read(unsigned long u_id, ++ unsigned char *p_buf, unsigned int max_len); ++//EXPORT_SYMBOL(mtk_wcn_btif_read) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_dpidle_ctrl ++* DESCRIPTION ++* control if BTIF module allow system enter deepidle state or not ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL ++* RETURNS ++* int always return 0 ++*****************************************************************************/ ++int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_rx_cb_register ++* DESCRIPTION ++* register rx callback function to BTIF module by btif user ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* rx_cb [IN] pointer to stp rx handler callback function, ++* should be comply with MTK_WCN_BTIF_RX_CB ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_wakeup_consys ++* DESCRIPTION ++* once sleep command is sent to con sys, ++* should call this API before send wakeup command to ++* make con sys aware host want to send data to consys ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_wakeup_consys(unsigned long u_id); ++ ++/*--------------End of Normal Mode API declearation----------------*/ ++ ++/*--------------Debug Purpose API declearation----------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_loopback_ctrl ++* DESCRIPTION ++* enable/disable BTIF internal loopback function, ++* when this function is enabled, ++* data send to btif will be received by btif itself ++* only for debug purpose, should never use this function in normal mode ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* enable [IN] loopback mode control flag, enable or disable, ++* shou be one of ENUM_BTIF_LPBK_MODE ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable); ++//EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl) ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_logger_ctrl ++* DESCRIPTION ++* control BTIF logger function's behavior ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* flag [IN] should be one of ENUM_BTIF_DBG_ID ++* BTIF_DISABLE_LOGGER - disable btif logger ++* BTIF_ENABLE_LOGGER - enable btif logger ++* BTIF_DUMP_LOG - dump log logged by btif ++* BTIF_CLR_LOG - clear btif log buffer ++* BTIF_DUMP_BTIF_REG - dump btif controller's register ++* BTIF_DUMP_DMA_REG - dump DMA controller's register ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag); ++//EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); ++/*-----------End of Debug Purpose API declearation------------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_parser_wmt_evt ++* DESCRIPTION ++* parser wmt sleep/wakeup evt in btif bbs buffer for debug ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* sub_str [IN] the str to be parsered ++* str_len [IN] the length of sub_str ++* RETURNS ++* bool true = succeed; ++* false = fail; ++*****************************************************************************/ ++bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, ++ const char *sub_str, unsigned int str_len); ++ ++int mtk_btif_exp_open_test(void); ++int mtk_btif_exp_close_test(void); ++int mtk_btif_exp_write_test(void); ++int mtk_btif_exp_suspend_test(void); ++int mtk_btif_exp_resume_test(void); ++int mtk_btif_exp_enter_dpidle_test(void); ++int mtk_btif_exp_exit_dpidle_test(void); ++int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int loop); ++int mtk_btif_exp_log_debug_test(int flag); ++int mtk_btif_exp_restore_noirq_test(void); ++int btif_wakeup_consys_no_id(void); ++int mtk_btif_exp_clock_ctrl(int en); ++#if BTIF_RXD_BE_BLOCKED_DETECT ++int mtk_btif_rxd_be_blocked_flag_get(void); ++#endif ++void mtk_btif_read_cpu_sw_rst_debug_exp(void); ++#endif /*_MTK_BTIF_EXP_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/mtk_btif.c b/drivers/misc/mediatek/btif/common/mtk_btif.c +new file mode 100644 +index 000000000000..0212ad41049f +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/mtk_btif.c +@@ -0,0 +1,3472 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++/*-----------linux system header files----------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*#include */ ++/*-----------driver own header files----------------*/ ++#ifdef CONFIG_COMPAT ++#include ++#endif ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF" ++ ++#define BTIF_CDEV_SUPPORT 1 ++ ++#include "btif_pub.h" ++#include "btif_dma_pub.h" ++#include "mtk_btif_exp.h" ++#include "mtk_btif.h" ++ ++/*-----------static function declearation----------------*/ ++static int mtk_btif_probe(struct platform_device *pdev); ++static int mtk_btif_remove(struct platform_device *pdev); ++static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state); ++static int mtk_btif_resume(struct platform_device *pdev); ++static int mtk_btif_drv_resume(struct device *dev); ++static int mtk_btif_drv_suspend(struct device *pdev); ++ ++static int mtk_btif_restore_noirq(struct device *device); ++static int btif_file_open(struct inode *pinode, struct file *pfile); ++static int btif_file_release(struct inode *pinode, struct file *pfile); ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops); ++static unsigned int btif_poll(struct file *filp, poll_table *wait); ++static int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, ++ mtk_btif_irq_handler irq_handler, void *data); ++static int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data); ++static int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en); ++static int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en); ++static irqreturn_t btif_irq_handler(int irq, void *data); ++static unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++ ++static irqreturn_t btif_tx_dma_irq_handler(int irq, void *data); ++static irqreturn_t btif_rx_dma_irq_handler(int irq, void *data); ++ ++static unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++static int _btif_controller_tx_setup(p_mtk_btif p_btif); ++static int _btif_controller_tx_free(p_mtk_btif p_btif); ++static int _btif_controller_rx_setup(p_mtk_btif p_btif); ++static int _btif_controller_rx_free(p_mtk_btif p_btif); ++static int _btif_tx_pio_setup(p_mtk_btif p_btif); ++static int _btif_rx_pio_setup(p_mtk_btif p_btif); ++static int _btif_rx_dma_setup(p_mtk_btif p_btif); ++static int _btif_rx_dma_free(p_mtk_btif p_btif); ++static int _btif_tx_dma_setup(p_mtk_btif p_btif); ++static int _btif_tx_dma_free(p_mtk_btif p_btif); ++static int _btif_controller_setup(p_mtk_btif p_btif); ++static int _btif_controller_free(p_mtk_btif p_btif); ++ ++static int _btif_pio_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++static int _btif_dma_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++ ++static unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static unsigned int btif_bbs_read(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static unsigned int btif_bbs_write(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len); ++static void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs); ++static int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len); ++static int _btif_rx_btm_deinit(p_mtk_btif p_btif); ++static int _btif_rx_btm_sched(p_mtk_btif p_btif); ++static int _btif_rx_btm_init(p_mtk_btif p_btif); ++static void btif_rx_tasklet(unsigned long func_data); ++static void btif_rx_worker(struct work_struct *p_work); ++static int btif_rx_thread(void *p_data); ++static int btif_rx_data_consummer(p_mtk_btif p_btif); ++ ++static int _btif_tx_ctx_init(p_mtk_btif p_btif); ++static int _btif_tx_ctx_deinit(p_mtk_btif p_btif); ++static void btif_tx_worker(struct work_struct *p_work); ++ ++static int _btif_state_deinit(p_mtk_btif p_btif); ++static int _btif_state_release(p_mtk_btif p_btif); ++static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif); ++static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state); ++static int _btif_state_hold(p_mtk_btif p_btif); ++static int _btif_state_init(p_mtk_btif p_btif); ++ ++static int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ++ ENUM_BTIF_DPIDLE_CTRL en_flag); ++static int _btif_enter_dpidle(p_mtk_btif p_btif); ++static int _btif_exit_dpidle(p_mtk_btif p_btif); ++static int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif); ++static int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif); ++static int _btif_enter_dpidle_from_on(p_mtk_btif p_btif); ++static int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif); ++ ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma); ++static int _btif_vfifo_init(p_mtk_btif_dma p_dma); ++#endif ++ ++static bool _btif_is_tx_complete(p_mtk_btif p_btif); ++static int _btif_init(p_mtk_btif p_btif); ++static int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); ++static int btif_rx_dma_mode_set(int en); ++static int btif_tx_dma_mode_set(int en); ++ ++static int _btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len); ++ ++/*-----------end of static function declearation----------------*/ ++ ++static const char *g_state[B_S_MAX] = { ++ "OFF", ++ "SUSPEND", ++ "DPIDLE", ++ "ON", ++}; ++ ++/*-----------BTIF setting--------------*/ ++mtk_btif_setting g_btif_setting[BTIF_PORT_NR] = { ++ { ++ .tx_mode = BTIF_TX_MODE, ++ .rx_mode = BTIF_RX_MODE, ++ .rx_type = BTIF_RX_BTM_CTX, ++ .tx_type = BTIF_TX_CTX, ++ }, ++}; ++ ++mtk_btif g_btif[BTIF_PORT_NR] = { ++ { ++ .open_counter = 0, ++ .state = B_S_OFF, ++ .setting = &g_btif_setting[0], ++ .p_tx_dma = NULL, ++ .p_rx_dma = NULL, ++ .rx_cb = NULL, ++ .p_btif_info = NULL, ++ }, ++}; ++ ++mtk_btif_dma g_dma[BTIF_PORT_NR][BTIF_DIR_MAX] = { ++ { ++ { ++ .p_btif = NULL, ++ .dir = BTIF_TX, ++ .p_dma_info = NULL, ++ .entry = ATOMIC_INIT(0), ++ }, ++ { ++ .p_btif = NULL, ++ .dir = BTIF_RX, ++ .p_dma_info = NULL, ++ .entry = ATOMIC_INIT(0), ++ }, ++ }, ++}; ++ ++#define G_MAX_PKG_LEN (7 * 1024) ++static int g_max_pkg_len = G_MAX_PKG_LEN; /*DMA vFIFO is set to 8 * 1024, we set this to 7/8 * vFIFO size*/ ++static int g_max_pding_data_size = BTIF_RX_BUFFER_SIZE * 3 / 4; ++ ++ ++static int mtk_btif_dbg_lvl = BTIF_LOG_ERR; ++ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++static struct timeval btif_rxd_time_stamp[MAX_BTIF_RXD_TIME_REC]; ++#endif ++/*-----------Platform bus related structures----------------*/ ++#define DRV_NAME "mtk_btif" ++ ++#ifdef CONFIG_OF ++const struct of_device_id apbtif_of_ids[] = { ++ { .compatible = "mediatek,mtk-btif", }, ++ {} ++}; ++#endif ++ ++const struct dev_pm_ops mtk_btif_drv_pm_ops = { ++ .restore_noirq = mtk_btif_restore_noirq, ++ .suspend = mtk_btif_drv_suspend, ++ .resume = mtk_btif_drv_resume, ++}; ++ ++struct platform_driver mtk_btif_dev_drv = { ++ .probe = mtk_btif_probe, ++ .remove = mtk_btif_remove, ++#ifdef CONFIG_PM ++ .suspend = mtk_btif_suspend, ++ .resume = mtk_btif_resume, ++#endif ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &mtk_btif_drv_pm_ops, ++#endif ++#ifdef CONFIG_OF ++ .of_match_table = apbtif_of_ids, ++#endif ++ } ++}; ++ ++#define BTIF_STATE_RELEASE(x) _btif_state_release(x) ++ ++/*-----------End of Platform bus related structures----------------*/ ++ ++/*-----------platform bus related operation APIs----------------*/ ++ ++static int mtk_btif_probe(struct platform_device *pdev) ++{ ++/*Chaozhong: ToDo: to be implement*/ ++/*register IRQ for BTIF and Tx Rx DMA and disable them by default*/ ++ BTIF_INFO_FUNC("DO BTIF PROBE\n"); ++ platform_set_drvdata(pdev, &g_btif[0]); ++ g_btif[0].private_data = (struct device *)&pdev->dev; ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ hal_btif_clk_get_and_prepare(pdev); ++#endif ++ ++ return 0; ++} ++ ++static int mtk_btif_remove(struct platform_device *pdev) ++{ ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_INFO_FUNC("DO BTIF REMOVE\n"); ++ platform_set_drvdata(pdev, NULL); ++ g_btif[0].private_data = NULL; ++ return 0; ++} ++ ++int _btif_suspend(p_mtk_btif p_btif) ++{ ++ int i_ret; ++ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif != NULL) { ++ if (!(p_btif->enable)) ++ i_ret = 0; ++ else { ++ if (_btif_state_get(p_btif) == B_S_ON) { ++ BTIF_ERR_FUNC("BTIF in ON state,", ++ "there are data need to be send or recev,suspend fail\n"); ++ i_ret = -1; ++ } else { ++ /* ++ * before disable BTIF controller and DMA controller ++ * we need to set BTIF to ON state ++ */ ++ i_ret = _btif_exit_dpidle(p_btif); ++ if (i_ret == 0) { ++ i_ret += _btif_controller_free(p_btif); ++ i_ret = _btif_controller_tx_free(p_btif); ++ i_ret += _btif_controller_rx_free(p_btif); ++ } ++ if (i_ret != 0) { ++ BTIF_INFO_FUNC("failed\n"); ++ /*Chaozhong: what if failed*/ ++ } else { ++ BTIF_INFO_FUNC("succeed\n"); ++ i_ret = _btif_state_set(p_btif, B_S_SUSPEND); ++ if (i_ret && _btif_init(p_btif)) { ++ /*Chaozhong:BTIF re-init failed? what to do*/ ++ i_ret = _btif_state_set(p_btif, B_S_OFF); ++ } ++ } ++ } ++ } ++ } else ++ i_ret = -1; ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++ ++static int mtk_btif_drv_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ pm_message_t state = PMSG_SUSPEND; ++ ++ return mtk_btif_suspend(pdev, state); ++} ++ ++static int mtk_btif_drv_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ ++ return mtk_btif_resume(pdev); ++} ++ ++static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = NULL; ++ ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_DBG_FUNC("++\n"); ++ p_btif = platform_get_drvdata(pdev); ++ i_ret = _btif_suspend(p_btif); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int _btif_restore_noirq(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*BTIF IRQ restore no irq*/ ++ i_ret = hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF HW IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC("BTIF HW IRQ restore failed, i_ret:%d\n", i_ret); ++ return i_ret; ++ } ++/*BTIF DMA restore no irq*/ ++ if (p_btif->tx_mode & BTIF_MODE_DMA) { ++ i_ret = hal_dma_pm_ops(p_btif->p_tx_dma->p_dma_info, ++ BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF Tx DMA IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC ++ ("BTIF Tx DMA IRQ restore failed, i_ret:%d\n", ++ i_ret); ++ return i_ret; ++ } ++ } ++ if (p_btif->rx_mode & BTIF_MODE_DMA) { ++ i_ret = hal_dma_pm_ops(p_btif->p_rx_dma->p_dma_info, ++ BTIF_PM_RESTORE_NOIRQ); ++ if (i_ret == 0) { ++ BTIF_INFO_FUNC("BTIF Rx DMA IRQ restore succeed\n"); ++ } else { ++ BTIF_INFO_FUNC ++ ("BTIF Rx DMA IRQ restore failed, i_ret:%d\n", ++ i_ret); ++ return i_ret; ++ } ++ } ++ return i_ret; ++} ++ ++static int mtk_btif_restore_noirq(struct device *dev) ++{ ++ int i_ret = 0; ++ struct platform_device *pdev = to_platform_device(dev); ++ p_mtk_btif p_btif = platform_get_drvdata(pdev); ++ ++ BTIF_INFO_FUNC("++\n"); ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif->enable) ++ BTIF_ERR_FUNC("!!!-----------------!BTIF is not closed before IPOH shutdown!!!---------------!\n"); ++ WARN_ON(p_btif->enable); ++ ++ i_ret = _btif_restore_noirq(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ BTIF_INFO_FUNC("--\n"); ++ return 0; ++} ++ ++int _btif_resume(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ if (p_btif != NULL) { ++ state = _btif_state_get(p_btif); ++ if (!(p_btif->enable)) ++ i_ret = 0; ++ else if (state == B_S_SUSPEND) ++ i_ret = _btif_enter_dpidle(p_btif); ++ else ++ BTIF_INFO_FUNC ++ ("BTIF state: %s before resume, do nothing\n", g_state[state]); ++ } else ++ i_ret = -1; ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++static int mtk_btif_resume(struct platform_device *pdev) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = NULL; ++/*Chaozhong: ToDo: to be implement*/ ++ BTIF_DBG_FUNC("++\n"); ++ p_btif = platform_get_drvdata(pdev); ++ i_ret = _btif_resume(p_btif); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return 0; ++} ++ ++/*-----------device node----------------*/ ++#if BTIF_CDEV_SUPPORT ++ ++dev_t btif_dev; ++struct class *p_btif_class; ++struct device *p_btif_dev; ++const char *p_btif_dev_name = "btif"; ++static struct semaphore wr_mtx; ++static struct semaphore rd_mtx; ++unsigned char wr_buf[2048]; ++unsigned char rd_buf[2048]; ++static int rx_notify_flag; ++static DECLARE_WAIT_QUEUE_HEAD(btif_wq); ++static int btif_file_open(struct inode *pinode, struct file *pfile); ++static int btif_file_release(struct inode *pinode, struct file *pfile); ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops); ++ ++static ssize_t btif_file_write(struct file *filp, ++ const char __user *buf, size_t count, loff_t *f_pos); ++static long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, ++ unsigned long arg); ++#ifdef CONFIG_COMPAT ++static long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); ++#endif ++static struct cdev btif_dev_c; ++static wait_queue_head_t btif_read_inq; /* read queues */ ++ ++const struct file_operations mtk_btif_fops = { ++ .owner = THIS_MODULE, ++ .open = btif_file_open, ++ .release = btif_file_release, ++ .read = btif_file_read, ++ .write = btif_file_write, ++ .unlocked_ioctl = btif_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = btif_compat_ioctl, ++#endif ++ .poll = btif_poll, ++}; ++ ++static int btif_chrdev_init(void) ++{ ++ int i_ret; ++ ++ int i_err; ++ ++ /* alloc device number dynamically */ ++ i_ret = alloc_chrdev_region(&btif_dev, 0, 1, p_btif_dev_name); ++ if (i_ret) { ++ BTIF_ERR_FUNC("devuce number allocation failed, i_ret:%d\n", ++ i_ret); ++ } else { ++ BTIF_INFO_FUNC("devuce number allocation succeed\n"); ++ } ++ cdev_init(&btif_dev_c, &mtk_btif_fops); ++ btif_dev_c.owner = THIS_MODULE; ++ i_err = cdev_add(&btif_dev_c, btif_dev, 1); ++ if (i_err) { ++ BTIF_ERR_FUNC("error add btif dev to kernel, error code:%d\n", ++ i_err); ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -1; ++ } ++ BTIF_INFO_FUNC("add btif dev to kernel succeed\n"); ++ ++ p_btif_class = class_create(THIS_MODULE, p_btif_dev_name); ++ if (IS_ERR(p_btif_class)) { ++ BTIF_ERR_FUNC("error happened when doing class_create\n"); ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -2; ++ } ++ BTIF_INFO_FUNC("create class for btif succeed\n"); ++ ++ p_btif_dev = device_create(p_btif_class, ++ NULL, btif_dev, 0, p_btif_dev_name); ++ if (IS_ERR(p_btif_dev)) { ++ BTIF_ERR_FUNC("error happened when doing device_create\n"); ++ class_destroy(p_btif_class); ++ p_btif_class = NULL; ++ unregister_chrdev_region(btif_dev, 1); ++ btif_dev = 0; ++ return -3; ++ } ++ BTIF_INFO_FUNC("create device for btif succeed\n"); ++ ++ return 0; ++} ++ ++void btif_rx_notify_cb(void) ++{ ++ BTIF_DBG_FUNC("++\n"); ++ rx_notify_flag = 1; ++ wake_up(&btif_wq); ++ wake_up_interruptible(&btif_read_inq); ++ BTIF_DBG_FUNC("--\n"); ++} ++ ++unsigned int btif_poll(struct file *filp, poll_table *wait) ++{ ++ unsigned int mask = 0; ++ unsigned int ava_len = 0; ++/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ ++ unsigned int wr_idx = g_btif[0].btif_buf.wr_idx; ++ ++/* BTIF_Rx_IRQ_Disable(); */ ++ ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); ++ BTIF_INFO_FUNC("++\n"); ++ if (ava_len == 0) { ++ poll_wait(filp, &btif_read_inq, wait); ++ wr_idx = g_btif[0].btif_buf.wr_idx; ++ ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); ++/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ ++ if (ava_len) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ } else { ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ } ++/*make for writable*/ ++ mask |= POLLOUT | POLLWRNORM; /* writable */ ++ BTIF_INFO_FUNC("--, mask:%d\n", mask); ++ return mask; ++} ++ ++static int _btif_file_open(void) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_INFO_FUNC("++\n"); ++ ++/*Chaozhong: ToDo: to be implement*/ ++ i_ret = btif_open(p_btif); ++ if ((i_ret != 0) && (i_ret != E_BTIF_ALREADY_OPEN)) { ++ BTIF_ERR_FUNC("btif_open failed, error code:%d\n", i_ret); ++ } else { ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ i_ret = 0; ++ } ++/*semaphore for read and write operation init*/ ++ sema_init(&wr_mtx, 1); ++ sema_init(&rd_mtx, 1); ++ ++/*buffer for read and write init*/ ++ memset(wr_buf, 0, sizeof(wr_buf)); ++ memset(rd_buf, 0, sizeof(rd_buf)); ++ init_waitqueue_head(&(btif_read_inq)); ++ btif_rx_notify_reg(p_btif, btif_rx_notify_cb); ++ BTIF_INFO_FUNC("--\n"); ++ return i_ret; ++} ++ ++static int _btif_file_close(void) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("++\n"); ++/*Chaozhong: ToDo: to be implement*/ ++ i_ret = btif_close(&g_btif[0]); ++ if (i_ret != 0) ++ BTIF_ERR_FUNC("btif_close failed, error code:%d\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_close succeed\n"); ++ ++ BTIF_INFO_FUNC("--\n"); ++ return i_ret; ++} ++ ++static int btif_file_open(struct inode *pinode, struct file *pfile) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("pid:%d\n", current->pid); ++ i_ret = 0; ++ return i_ret; ++} ++ ++static int btif_file_release(struct inode *pinode, struct file *pfile) ++{ ++ int i_ret = -1; ++ ++ BTIF_INFO_FUNC("pid:%d\n", current->pid); ++ i_ret = 0; ++ return i_ret; ++} ++ ++static ssize_t btif_file_read(struct file *pfile, ++ char __user *buf, size_t count, loff_t *f_ops) ++{ ++ int i_ret = 0; ++ int rd_len = 0; ++ ++ BTIF_INFO_FUNC("++\n"); ++ down(&rd_mtx); ++ rd_len = btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); ++ while (rd_len == 0) { ++ if (pfile->f_flags & O_NONBLOCK) ++ break; ++ ++ wait_event(btif_wq, rx_notify_flag != 0); ++ rx_notify_flag = 0; ++ rd_len = ++ btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, ++ sizeof(rd_buf)); ++ } ++ ++ if (rd_len == 0) ++ i_ret = 0; ++ else if ((rd_len > 0) && (copy_to_user(buf, rd_buf, rd_len) == 0)) ++ i_ret = rd_len; ++ else ++ i_ret = -EFAULT; ++ ++ up(&rd_mtx); ++ BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++ssize_t btif_file_write(struct file *filp, ++ const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ int i_ret = 0; ++ int copy_size = 0; ++ ++ copy_size = count > sizeof(wr_buf) ? sizeof(wr_buf) : count; ++ ++ BTIF_INFO_FUNC("++\n"); ++ down(&wr_mtx); ++ if (copy_from_user(&wr_buf[0], &buf[0], copy_size)) ++ i_ret = -EFAULT; ++ else ++ i_ret = btif_send_data(&g_btif[0], wr_buf, copy_size); ++ ++ up(&wr_mtx); ++ BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); ++ ++ return i_ret; ++} ++#ifdef CONFIG_COMPAT ++long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ ++ BTIF_INFO_FUNC("cmd[0x%x]\n", cmd); ++ ret = btif_unlocked_ioctl(filp, cmd, arg); ++ return ret; ++} ++#endif ++long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++#define BTIF_IOC_MAGIC 0xb0 ++#define BTIF_IOCTL_OPEN _IOW(BTIF_IOC_MAGIC, 1, int) ++#define BTIF_IOCTL_CLOSE _IOW(BTIF_IOC_MAGIC, 2, int) ++#define BTIF_IOCTL_LPBK_CTRL _IOWR(BTIF_IOC_MAGIC, 3, int) ++#define BTIF_IOCTL_LOG_FUNC_CTRL _IOWR(BTIF_IOC_MAGIC, 4, int) ++#define BTIF_IOCTL_RT_LOG_CTRL _IOWR(BTIF_IOC_MAGIC, 5, int) ++#define BTIF_IOCTL_LOG_DUMP _IOWR(BTIF_IOC_MAGIC, 6, int) ++#define BTIF_IOCTL_REG_DUMP _IOWR(BTIF_IOC_MAGIC, 7, int) ++#define BTIF_IOCTL_DMA_CTRL _IOWR(BTIF_IOC_MAGIC, 8, int) ++ ++ long ret = 0; ++/* unsigned char p_buf[NAME_MAX + 1]; */ ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_INFO_FUNC("++\n"); ++ BTIF_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); ++ ++ switch (cmd) { ++ case BTIF_IOCTL_OPEN: ++ ret = _btif_file_open(); ++ break; ++ case BTIF_IOCTL_CLOSE: ++ ret = _btif_file_close(); ++ break; ++ case BTIF_IOCTL_LPBK_CTRL: ++ ret = btif_lpbk_ctrl(p_btif, arg == 0 ? 0 : 1); ++ break; ++ case BTIF_IOCTL_LOG_FUNC_CTRL: ++ if (arg == 0) { ++ ret += btif_log_buf_disable(&p_btif->tx_log); ++ ret += btif_log_buf_disable(&p_btif->rx_log); ++ } else { ++ ret += btif_log_buf_enable(&p_btif->tx_log); ++ ret += btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_IOCTL_RT_LOG_CTRL: ++ if (arg == 0) { ++ ret += btif_log_output_disable(&p_btif->tx_log); ++ ret += btif_log_output_disable(&p_btif->rx_log); ++ } else { ++ ret += btif_log_output_enable(&p_btif->tx_log); ++ ret += btif_log_output_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_IOCTL_LOG_DUMP: ++ ++ ret += btif_log_buf_dmp_out(&p_btif->tx_log); ++ ret += btif_log_buf_dmp_out(&p_btif->rx_log); ++ break; ++ case BTIF_IOCTL_REG_DUMP: ++ ret += btif_dump_reg(p_btif); ++ break; ++ case BTIF_IOCTL_DMA_CTRL: ++ if (arg == 0) { ++ ret += btif_tx_dma_mode_set(0); ++ ret += btif_rx_dma_mode_set(0); ++ } else { ++ ret += btif_tx_dma_mode_set(1); ++ ret += btif_rx_dma_mode_set(1); ++ } ++ break; ++ default: ++ BTIF_INFO_FUNC("unknown cmd(%d)\n", cmd); ++ ret = -2; ++ break; ++ } ++ BTIF_INFO_FUNC("--\n"); ++ return ret; ++} ++ ++#endif ++ ++/*-----------device property----------------*/ ++//static ssize_t driver_flag_read(struct device_driver *drv, char *buf) ++static ssize_t flag_show(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "btif driver debug level:%d\n", mtk_btif_dbg_lvl); ++} ++ ++//static ssize_t driver_flag_set(struct device_driver *drv, ++static ssize_t flag_store(struct device_driver *drv, ++ const char *buffer, size_t count) ++{ ++ char buf[256]; ++ char *p_buf; ++ unsigned long len = count; ++ long x = 0; ++ long y = 0; ++ long z = 0; ++ int result = 0; ++ char *p_token = NULL; ++ char *p_delimiter = " \t"; ++ ++ BTIF_INFO_FUNC("buffer = %s, count = %zd\n", buffer, count); ++ if (len >= sizeof(buf)) { ++ BTIF_ERR_FUNC("input handling fail!\n"); ++ len = sizeof(buf) - 1; ++ return -1; ++ } ++ ++ memcpy(buf, buffer, sizeof(buf)); ++ p_buf = buf; ++ ++ p_token = strsep(&p_buf, p_delimiter); ++ if (p_token != NULL) { ++ result = kstrtol(p_token, 16, &x); ++ BTIF_INFO_FUNC("x = 0x%08x\n\r", x); ++ } else ++ x = 0; ++/* x = (NULL != p_token) ? kstrtol(p_token, 16, NULL) : 0;*/ ++ ++ p_token = strsep(&p_buf, "\t\n "); ++ if (p_token != NULL) { ++ result = kstrtol(p_token, 16, &y); ++ BTIF_INFO_FUNC("y = 0x%08x\n\r", y); ++ } else ++ y = 0; ++ ++ p_token = strsep(&p_buf, "\t\n "); ++ if (p_token != NULL) ++ result = kstrtol(p_token, 16, &z); ++ else ++ z = 0; ++ ++ BTIF_INFO_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++ ++ switch (x) { ++ case 1: ++ mtk_btif_exp_open_test(); ++ break; ++ case 2: ++ mtk_btif_exp_close_test(); ++ break; ++ case 3: ++ mtk_btif_exp_write_test(); ++ break; ++ case 4: ++ mtk_btif_exp_enter_dpidle_test(); ++ break; ++ case 5: ++ mtk_btif_exp_exit_dpidle_test(); ++ break; ++ case 6: ++ mtk_btif_exp_suspend_test(); ++ break; ++ case 7: ++ mtk_btif_exp_resume_test(); ++ break; ++ case 8: ++ if (y > BTIF_LOG_LOUD) ++ mtk_btif_dbg_lvl = BTIF_LOG_LOUD; ++ else if (y < BTIF_LOG_ERR) ++ mtk_btif_dbg_lvl = BTIF_LOG_WARN; ++ else ++ mtk_btif_dbg_lvl = y; ++ BTIF_ERR_FUNC("mtk_btif_dbg_lvl set to %d\n", mtk_btif_dbg_lvl); ++ break; ++ case 9: ++ mtk_btif_exp_open_test(); ++ mtk_btif_exp_write_test(); ++ mtk_btif_exp_close_test(); ++ break; ++ case 0xa: ++ mtk_btif_exp_log_debug_test(y); ++ break; ++ case 0xb: ++ btif_tx_dma_mode_set(1); ++ btif_rx_dma_mode_set(1); ++ break; ++ case 0xc: ++ btif_tx_dma_mode_set(0); ++ btif_rx_dma_mode_set(0); ++ break; ++ case 0xd: ++ mtk_btif_exp_restore_noirq_test(); ++ break; ++ case 0xe: ++ btif_wakeup_consys_no_id(); ++ break; ++ case 0xf: ++ mtk_btif_exp_clock_ctrl(y); ++ break; ++ case 0x10: ++ y = y > G_MAX_PKG_LEN ? G_MAX_PKG_LEN : y; ++ y = y < 1024 ? 1024 : y; ++ BTIF_INFO_FUNC("g_max_pkg_len is set to %d\n", y); ++ g_max_pkg_len = y; ++ break; ++ case 0x11: ++ y = y > BTIF_RX_BUFFER_SIZE ? BTIF_RX_BUFFER_SIZE : y; ++ y = y < 1024 ? 1024 : y; ++ BTIF_INFO_FUNC("g_max_pding_data_size is set to %d\n", y); ++ g_max_pding_data_size = y; ++ break; ++ default: ++ mtk_btif_exp_open_test(); ++ mtk_btif_exp_write_stress_test(3030, 1); ++ mtk_btif_exp_close_test(); ++ BTIF_WARN_FUNC("not supported.\n"); ++ break; ++ } ++ ++ return count; ++} ++ ++//FWU: driver_ATTR dropped in 4.14 ++//static DRIVER_ATTR(flag, S_IRUGO | S_IWUSR, driver_flag_read, driver_flag_set); ++static DRIVER_ATTR_RW(flag); ++ ++/*-----------End of platform bus related operation APIs------------*/ ++ ++/*-----------------------platform driver ----------------*/ ++ ++int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, ++ mtk_btif_irq_handler irq_handler, void *data) ++{ ++ int i_ret = -1; ++ unsigned int irq_id; ++ unsigned int flag; ++ ++ if ((p_irq == NULL) || (irq_handler == NULL)) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (!(p_irq->is_irq_sup)) { ++ BTIF_WARN_FUNC("%s is not supported\n", p_irq->name); ++ return 0; ++ } ++ ++ irq_id = p_irq->irq_id; ++ ++#ifdef CONFIG_OF ++ flag = p_irq->irq_flags; ++#else ++ switch (p_irq->sens_type) { ++ case IRQ_SENS_EDGE: ++ if (p_irq->edge_type == IRQ_EDGE_FALL) ++ flag = IRQF_TRIGGER_FALLING; ++ else if (p_irq->edge_type == IRQ_EDGE_RAISE) ++ flag = IRQF_TRIGGER_RISING; ++ else if (p_irq->edge_type == IRQ_EDGE_BOTH) ++ flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; ++ else ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_FALLING; ++ break; ++ case IRQ_SENS_LVL: ++ if (p_irq->lvl_type == IRQ_LVL_LOW) ++ flag = IRQF_TRIGGER_LOW; ++ else if (p_irq->lvl_type == IRQ_LVL_HIGH) ++ flag = IRQF_TRIGGER_HIGH; ++ else ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_LOW; ++ break; ++ default: ++ /*make this as default type */ ++ flag = IRQF_TRIGGER_LOW; ++ break; ++ } ++#endif ++ ++ p_irq->p_irq_handler = irq_handler; ++ i_ret = request_irq(irq_id, ++ (irq_handler_t) irq_handler, ++ flag, p_irq->name, data); ++ if (i_ret) ++ return i_ret; ++ ++ p_irq->reg_flag = true; ++ return 0; ++} ++ ++int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data) ++{ ++ int i_ret = 0; ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if ((p_irq->is_irq_sup) && (p_irq->reg_flag)) { ++ _btif_irq_ctrl(p_irq, false); ++ free_irq(eint_num, data); ++ p_irq->reg_flag = false; ++ } ++/*do nothing for this operation*/ ++ return i_ret; ++} ++ ++int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en) ++{ ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if (en) ++ enable_irq(eint_num); ++ else ++ disable_irq_nosync(eint_num); ++ ++ return 0; ++} ++ ++int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en) ++{ ++ unsigned int eint_num = p_irq->irq_id; ++ ++ if (en) ++ enable_irq(eint_num); ++ else ++ disable_irq(eint_num); ++ ++ return 0; ++} ++ ++ ++irqreturn_t btif_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++/*Chaozhong: do we need lock here?*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ ++ _btif_irq_ctrl(p_btif->p_btif_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_btif_irq_handler(p_btif->p_btif_info, NULL, 0); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_irq_ctrl(p_btif->p_btif_info->p_irq, true); ++ _btif_rx_btm_sched(p_btif); ++ ++ BTIF_DBG_FUNC("--\n"); ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t btif_tx_dma_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ p_mtk_btif_dma p_tx_dma = p_btif->p_tx_dma; ++ P_MTK_DMA_INFO_STR p_dma_info = p_tx_dma->p_dma_info; ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ _btif_irq_ctrl(p_dma_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_tx_dma_irq_handler(p_dma_info); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++#endif ++ _btif_irq_ctrl(p_dma_info->p_irq, true); ++ BTIF_DBG_FUNC("--\n"); ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t btif_rx_dma_irq_handler(int irq, void *data) ++{ ++/*search BTIF? just use index 0*/ ++ ++ p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ ++ p_mtk_btif_dma p_rx_dma = p_btif->p_rx_dma; ++ P_MTK_DMA_INFO_STR p_rx_dma_info = p_rx_dma->p_dma_info; ++ ++ BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); ++ ++ _btif_irq_ctrl(p_rx_dma_info->p_irq, false); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++ hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_ENABLE); ++#endif ++ ++ hal_rx_dma_irq_handler(p_rx_dma_info, NULL, 0); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_DISABLE); ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_irq_ctrl(p_rx_dma_info->p_irq, true); ++ ++ _btif_rx_btm_sched(p_btif); ++ ++ BTIF_DBG_FUNC("--\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len) ++{ ++ unsigned int index = 0; ++ p_mtk_btif p_btif = &(g_btif[index]); ++ ++#if 0 ++ _btif_dump_memory("", p_buf, buf_len); ++#endif ++ ++ btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); ++/*save DMA Rx packet here*/ ++ if (buf_len > 0) ++ btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); ++ ++ return 0; ++} ++ ++unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len) ++{ ++ unsigned int index = 0; ++ p_mtk_btif p_btif = &(g_btif[index]); ++ ++#if 0 ++ _btif_dump_memory("", p_buf, buf_len); ++#endif ++ btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); ++ ++/*save PIO Rx packet here*/ ++ if (buf_len > 0) ++ btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); ++ ++ return 0; ++} ++ ++bool btif_parser_wmt_evt(p_mtk_btif p_btif, ++ const char *sub_str, ++ unsigned int str_len) ++{ ++ unsigned int data_cnt = 0; ++ unsigned int copy_cnt = 0; ++ char *local_buf = NULL; ++ bool b_ret = false; ++ p_btif_buf_str p_bbs = &(p_btif->btif_buf); ++ unsigned int wr_idx = p_bbs->wr_idx; ++ unsigned int rd_idx = p_bbs->rd_idx; ++ ++ data_cnt = copy_cnt = BBS_COUNT(p_bbs); ++ ++ if (data_cnt < str_len) { ++ BTIF_WARN_FUNC("there is not enough data for parser,need(%d),have(%d)\n", str_len, data_cnt); ++ return false; ++ } ++ BTIF_INFO_FUNC("data count in bbs buffer:%d,wr_idx(%d),rd_idx(%d)\n", data_cnt, wr_idx, rd_idx); ++ local_buf = vmalloc((data_cnt + 3) & ~0x3UL); ++ if (!local_buf) { ++ BTIF_WARN_FUNC("vmalloc memory fail\n"); ++ return false; ++ } ++ ++ if (wr_idx >= rd_idx) { ++ memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), copy_cnt); ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - rd_idx; ++ ++ BTIF_INFO_FUNC("tail_Len(%d)\n", tail_len); ++ memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), tail_len); ++ memcpy(local_buf + tail_len, BBS_PTR(p_bbs, 0), copy_cnt - tail_len); ++ } ++ ++ do { ++ int i = 0; ++ int j = 0; ++ int k = 0; ++ int d = 0; ++ ++ BTIF_INFO_FUNC("sub_str_len:%d\n", str_len); ++ for (i = 0; i < copy_cnt; i++) { ++ BTIF_DBG_FUNC("i:%d\n", i); ++ k = i; ++ while (1) { ++ if ((j >= str_len) || (k >= copy_cnt) || (sub_str[j++] != local_buf[k++])) ++ break; ++ } ++ ++ if (j == str_len) { ++ for (d = i; d < (str_len + i); d++) ++ BTIF_INFO_FUNC("0x%2x", local_buf[d]); ++ BTIF_INFO_FUNC("find sub str index:%d\n", i); ++ b_ret = true; ++ break; ++ } ++ if (j < str_len) ++ j = 0; ++ } ++ ++ } while (0); ++ ++ vfree(local_buf); ++ return b_ret; ++} ++int _btif_controller_tx_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_tx_dma_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_setup failed,i_ret(%d),", ++ "set tx to PIO mode\n", i_ret); ++ i_ret = _btif_tx_pio_setup(p_btif); ++ } ++ } else ++/*enable Tx PIO mode*/ ++ i_ret = _btif_tx_pio_setup(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_controller_tx_free(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_tx_dma_free(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_free failed, i_ret(%d)\n", ++ i_ret); ++ } ++ } else { ++/*do nothing for Tx PIO mode*/ ++ } ++ return i_ret; ++} ++ ++int _btif_controller_rx_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_rx_dma_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_tx_dma_setup failed, i_ret(%d),", ++ "set tx to PIO mode\n", i_ret); ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } ++ } else { ++/*enable Tx PIO mode*/ ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } ++ return i_ret; ++} ++ ++int _btif_controller_rx_free(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ i_ret = _btif_rx_dma_free(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_rx_dma_free failed, i_ret(%d)\n", ++ i_ret); ++ } ++ } else { ++/*do nothing for Rx PIO mode*/ ++ } ++ return i_ret; ++} ++ ++int _btif_tx_pio_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++/*set Tx to PIO mode*/ ++ p_btif->tx_mode = BTIF_MODE_PIO; ++/*enable Tx PIO mode*/ ++ i_ret = hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); ++ return i_ret; ++} ++ ++int _btif_rx_pio_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; ++ ++ p_btif->rx_mode = BTIF_MODE_PIO; ++/*Enable Rx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, true); ++/*enable Rx PIO mode*/ ++ i_ret = hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); ++ return i_ret; ++} ++ ++int _btif_rx_dma_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = NULL; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = NULL; ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; ++ ++ p_btif_info = p_btif->p_btif_info; ++ p_btif_irq = p_dma_info->p_irq; ++ ++/*vFIFO reset*/ ++ hal_btif_vfifo_reset(p_dma_info); ++ ++ i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d),", ++ "set rx to pio mode\n", i_ret); ++/*DMA control failed set Rx to PIO mode*/ ++ return _btif_rx_pio_setup(p_btif); ++ } ++/*hardware init*/ ++ hal_btif_dma_hw_init(p_dma_info); ++ ++ hal_btif_dma_rx_cb_reg(p_dma_info, ++ (dma_rx_buf_write) btif_dma_rx_data_receiver); ++ ++/*DMA controller enable*/ ++ i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", ++ "set rx to pio mode\n", i_ret); ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++/*DMA control failed set Rx to PIO mode*/ ++ i_ret = _btif_rx_pio_setup(p_btif); ++ } else { ++/*enable Rx DMA mode*/ ++ hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); ++ ++/*DMA Rx IRQ register*/ ++ _btif_irq_reg(p_btif_irq, btif_rx_dma_irq_handler, p_btif); ++#if 0 ++/*Enable DMA Rx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, true); ++#endif ++ BTIF_DBG_FUNC("succeed\n"); ++ } ++ return i_ret; ++} ++ ++int _btif_rx_dma_free(p_mtk_btif p_btif) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_rx_dma->p_dma_info->p_irq; ++ ++ hal_btif_dma_rx_cb_reg(p_dma_info, (dma_rx_buf_write) NULL); ++ _btif_irq_free(p_irq, p_btif); ++/*disable BTIF Rx DMA channel*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); ++/*disable clock output*/ ++ return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++} ++ ++int _btif_tx_dma_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_dma_info->p_irq; ++ ++/*vFIFO reset*/ ++ hal_btif_vfifo_reset(p_dma_info); ++ ++ i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d)\n", ++ i_ret); ++ return i_ret; ++ } ++/*DMA controller setup*/ ++ hal_btif_dma_hw_init(p_dma_info); ++ ++/*DMA HW Enable*/ ++ i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", ++ "set tx to pio mode\n", i_ret); ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++ hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++#endif ++ ++ _btif_tx_pio_setup(p_btif); ++ } else { ++ hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); ++/*DMA Tx IRQ register*/ ++ _btif_irq_reg(p_btif_irq, btif_tx_dma_irq_handler, p_btif); ++#if 0 ++/*disable DMA Tx IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, false); ++#endif ++ ++ BTIF_DBG_FUNC("succeed\n"); ++ } ++ return i_ret; ++} ++ ++int _btif_tx_dma_free(p_mtk_btif p_btif) ++{ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_tx_dma->p_dma_info->p_irq; ++ ++ _btif_irq_free(p_irq, p_btif); ++/*disable BTIF Tx DMA channel*/ ++ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); ++/*disable clock output*/ ++ return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); ++} ++ ++int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) ++{ ++ int i_ret = -1; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++#if 0 ++ state = _btif_state_get(p_btif); ++ if (p_btif->enable && B_S_ON == state) ++ i_ret = _btif_lpbk_ctrl(p_btif, flag); ++ else ++ i_ret = E_BTIF_INVAL_STATE; ++#endif ++ i_ret = _btif_exit_dpidle(p_btif); ++ if (i_ret == 0) ++ i_ret = _btif_lpbk_ctrl(p_btif, flag); ++ else ++ i_ret = E_BTIF_INVAL_STATE; ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) ++{ ++ int i_ret = -1; ++ ++ if (flag) { ++ i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, true); ++ BTIF_DBG_FUNC("loopback function enabled\n"); ++ } else { ++ i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, false); ++ BTIF_DBG_FUNC("loopback function disabled\n"); ++ } ++ if (i_ret == 0) ++ p_btif->lpbk_flag = flag; ++ ++ return i_ret; ++} ++ ++int btif_clock_ctrl(p_mtk_btif p_btif, int en) ++{ ++ int i_ret = 0; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ENUM_CLOCK_CTRL ctrl_flag = en == 0 ? CLK_OUT_DISABLE : CLK_OUT_ENABLE; ++ ++ i_ret = hal_btif_clk_ctrl(p_btif_info, ctrl_flag); ++ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ctrl_flag); ++ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ctrl_flag); ++ ++ return i_ret; ++} ++ ++int _btif_controller_setup(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; ++ ++/*BTIF rx buffer init*/ ++/* memset(p_btif->rx_buf, 0, BTIF_RX_BUFFER_SIZE); */ ++ BBS_INIT(&(p_btif->btif_buf)); ++/************************************************/ ++ hal_btif_rx_cb_reg(p_btif_info, ++ (btif_rx_buf_write) btif_pio_rx_data_receiver); ++ ++ i_ret = hal_btif_clk_ctrl(p_btif_info, CLK_OUT_ENABLE); ++ if (i_ret) { ++ BTIF_ERR_FUNC("hal_btif_clk_ctrl failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++/*BTIF controller init*/ ++ i_ret = hal_btif_hw_init(p_btif_info); ++ if (i_ret) { ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++ BTIF_ERR_FUNC("hal_btif_hw_init failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++ _btif_lpbk_ctrl(p_btif, p_btif->lpbk_flag); ++/*BTIF IRQ register*/ ++ i_ret = _btif_irq_reg(p_btif_irq, btif_irq_handler, p_btif); ++ if (i_ret) { ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++ ++ BTIF_ERR_FUNC("_btif_irq_reg failed, i_ret(%d)\n", i_ret); ++ return i_ret; ++ } ++ ++/*disable IRQ*/ ++ _btif_irq_ctrl(p_btif_irq, false); ++ i_ret = 0; ++ BTIF_DBG_FUNC("succeed\n"); ++ return i_ret; ++} ++ ++int _btif_controller_free(p_mtk_btif p_btif) ++{ ++/*No need to set BTIF to PIO mode, only enable BTIF CG*/ ++ hal_btif_rx_cb_reg(p_btif->p_btif_info, (btif_rx_buf_write) NULL); ++ _btif_irq_free(p_btif->p_btif_info->p_irq, p_btif); ++ return hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++} ++ ++int _btif_init(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ i_ret = _btif_controller_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_init failed, i_ret(%d)\n", ++ i_ret); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ ++ i_ret = _btif_controller_tx_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", ++ i_ret); ++ _btif_controller_free(p_btif); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ ++ i_ret = _btif_controller_rx_setup(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", ++ i_ret); ++ _btif_controller_tx_free(p_btif); ++ _btif_controller_free(p_btif); ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++ } ++ return i_ret; ++} ++ ++int btif_open(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif->enable) ++ return E_BTIF_ALREADY_OPEN; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++/*disable deepidle*/ ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); ++ ++ i_ret = _btif_init(p_btif); ++ if (i_ret == 0) { ++ /*set BTIF's enable flag*/ ++ p_btif->enable = true; ++ _btif_state_set(p_btif, B_S_ON); ++ } else { ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ } ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ ++ BTIF_DBG_FUNC("BTIF's Tx Mode:%d, Rx Mode(%d)\n", ++ p_btif->tx_mode, p_btif->rx_mode); ++ return i_ret; ++} ++ ++int btif_close(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ if (!(p_btif->enable)) ++ return E_BTIF_NOT_OPEN; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++/*always set state back to B_S_ON before do close operation*/ ++ _btif_exit_dpidle(p_btif); ++/*set BTIF's state to disable state*/ ++ p_btif->enable = false; ++ ++ _btif_controller_free(p_btif); ++ _btif_controller_tx_free(p_btif); ++ _btif_controller_rx_free(p_btif); ++ ++/*reset BTIF's rx_cb function*/ ++ p_btif->rx_cb = NULL; ++ p_btif->rx_notify = NULL; ++ p_btif->lpbk_flag = false; ++ ++/*set state mechine to B_S_OFF*/ ++ _btif_state_set(p_btif, B_S_OFF); ++ ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_exit_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ state = _btif_state_get(p_btif); ++ switch (state) { ++ case B_S_DPIDLE: ++ i_ret = _btif_exit_dpidle_from_dpidle(p_btif); ++ break; ++ case B_S_SUSPEND: ++/*in suspend state, need to do reinit of btif*/ ++ i_ret = _btif_exit_dpidle_from_sus(p_btif); ++ break; ++ case B_S_OFF: ++ i_ret = _btif_init(p_btif); ++ break; ++ case B_S_ON: ++ i_ret = 0; /* for btif_close case */ ++ break; ++ default: ++ i_ret = E_BTIF_INVAL_PARAM; ++ BTIF_INFO_FUNC("invalid state change:%d->\n", state, B_S_ON); ++ break; ++ } ++ ++ if (i_ret == 0) ++ i_ret = _btif_state_set(p_btif, B_S_ON); ++ return i_ret; ++} ++ ++int btif_exit_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ i_ret = _btif_exit_dpidle(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_enter_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ENUM_BTIF_STATE state = B_S_MAX; ++ ++ state = _btif_state_get(p_btif); ++ if (state == B_S_ON) { ++ i_ret = _btif_enter_dpidle_from_on(p_btif); ++ } else if (state == B_S_SUSPEND) { ++ /*do reinit and enter deepidle*/ ++ i_ret = _btif_enter_dpidle_from_sus(p_btif); ++ } else if (state == B_S_DPIDLE) { ++ /*do nothing*/ ++ i_ret = 0; ++ } else { ++ BTIF_WARN_FUNC("operation is not allowed, current state:%d\n", ++ state); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++/*anyway, set to B_S_DPIDLE state*/ ++ if (i_ret == 0) ++ i_ret = _btif_state_set(p_btif, B_S_DPIDLE); ++ return i_ret; ++} ++ ++int btif_enter_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*hold state mechine lock*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ i_ret = _btif_enter_dpidle(p_btif); ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++/*in dpidle state, only need to open related clock*/ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*enable BTIF Tx DMA's clock*/ ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ++ CLK_OUT_ENABLE); ++ } ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ /*enable BTIF Rx DMA's clock*/ ++ i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ++ CLK_OUT_ENABLE); ++ } ++/*enable BTIF's clock*/ ++ i_ret += hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++ ++ if (i_ret != 0) ++ BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif) ++{ ++/*in suspend state, need to do driver re-init*/ ++ ++ int i_ret = _btif_init(p_btif); ++ ++ return i_ret; ++} ++ ++int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif) ++{ ++/*do driiver reinit*/ ++ int i_ret = _btif_init(p_btif); ++ ++ if (i_ret == 0) ++ i_ret = _btif_enter_dpidle_from_on(p_btif); ++ return i_ret; ++} ++ ++int _btif_enter_dpidle_from_on(p_mtk_btif p_btif) ++{ ++#define MAX_WAIT_TIME_MS 5000 ++/* ++ * this max wait time cannot exceed 12s, ++ * because dpm will monitor each device's ++ * resume/suspend process by start up a watch dog timer of 12s ++ * incase of one driver's suspend/resume process block other device's suspend/resume ++ */ ++ int i_ret = 0; ++ unsigned int retry = 0; ++ unsigned int wait_period = 1; ++ unsigned int max_retry = MAX_WAIT_TIME_MS / wait_period; ++ struct timeval timer_start; ++ struct timeval timer_now; ++ ++ do_gettimeofday(&timer_start); ++ ++ while ((!_btif_is_tx_complete(p_btif)) && (retry < max_retry)) { ++ do_gettimeofday(&timer_now); ++ if ((MAX_WAIT_TIME_MS/1000) <= (timer_now.tv_sec - timer_start.tv_sec)) { ++ BTIF_WARN_FUNC("max retry timer expired, timer_start.tv_sec:%d, timer_now.tv_sec:%d,", ++ "retry:%d\n", timer_start.tv_sec, timer_now.tv_sec, retry); ++ break; ++ } ++ msleep(wait_period); ++ retry++; ++ } ++ ++ if (retry < max_retry) { ++ if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*disable BTIF Tx DMA's clock*/ ++ i_ret += ++ hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ } ++ if (p_btif->rx_mode == BTIF_MODE_DMA) { ++ /*disable BTIF Rx DMA's clock*/ ++ i_ret += ++ hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ } ++/*disable BTIF's clock*/ ++ i_ret += ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); ++ ++ if (i_ret) ++ BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); ++ } else ++ i_ret = -1; ++ ++ return i_ret; ++} ++ ++int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++/*call WCP's API to control deepidle's enable/disable*/ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_DIS); ++ else ++ hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_EN); ++ ++ return 0; ++} ++ ++int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ if (p_btif->rx_cb) { ++ BTIF_WARN_FUNC ++ ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", ++ p_btif->rx_cb, rx_cb); ++ } ++ p_btif->rx_cb = rx_cb; ++ ++ return 0; ++} ++ ++int btif_raise_wak_signal(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); ++#endif ++ ++ i_ret = hal_btif_raise_wak_sig(p_btif_info); ++ ++#if MTK_BTIF_ENABLE_CLK_REF_COUNTER ++ hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); ++#endif ++ return i_ret; ++} ++ ++bool _btif_is_tx_complete(p_mtk_btif p_btif) ++{ ++ bool b_ret = false; ++ ENUM_BTIF_MODE tx_mode = p_btif->tx_mode; ++ ++/* ++ * make sure BTIF tx finished in PIO mode ++ * make sure BTIF tx finished and DMA tx finished in DMA mode ++ */ ++ if (tx_mode == BTIF_MODE_DMA) { ++ b_ret = hal_dma_is_tx_complete(p_btif->p_tx_dma->p_dma_info); ++ if (b_ret == false) { ++ BTIF_DBG_FUNC("Tx DMA is not finished\n"); ++ return b_ret; ++ } ++ } ++ ++ b_ret = hal_btif_is_tx_complete(p_btif->p_btif_info); ++ if (b_ret == false) { ++ BTIF_DBG_FUNC("BTIF Tx is not finished\n"); ++ return b_ret; ++ } ++ b_ret = true; ++ return b_ret; ++} ++ ++/*--------------------------------Functions-------------------------------------------*/ ++ ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_init(p_mtk_btif_dma p_dma) ++{ ++ P_DMA_VFIFO p_vfifo = NULL; ++ struct device *dev = NULL; ++ p_mtk_btif p_btif = NULL; ++ ++ if (p_dma == NULL) { ++ BTIF_ERR_FUNC("p_dma is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ p_btif = (p_mtk_btif)p_dma->p_btif; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ dev = (struct device *)p_btif->private_data; ++ if (dev == NULL) ++ BTIF_WARN_FUNC("Null dev pointer!!!!\n"); ++ ++ p_vfifo = p_dma->p_dma_info->p_vfifo; ++ if (p_vfifo->p_vir_addr != NULL) { ++ BTIF_ERR_FUNC ++ ("BTIF vFIFO memory already allocated, do nothing\n"); ++ return E_BTIF_BAD_POINTER; ++ } ++ ++/*vFIFO memory allocation*/ ++ p_vfifo->p_vir_addr = dma_zalloc_coherent(dev, ++ p_vfifo->vfifo_size, ++ &p_vfifo->phy_addr, GFP_DMA | GFP_DMA32); ++ if (p_vfifo->p_vir_addr == NULL) { ++ BTIF_ERR_FUNC("alloc vFIFO memory for BTIF failed\n"); ++ return E_BTIF_FAIL; ++ } ++ ++ if (sizeof(dma_addr_t) == sizeof(unsigned long long)) ++ BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch64,vir addr:0x%p,", ++ "phy addr:0x%llx\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ else ++ BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch32,vir addr:0x%p,", ++ "phy addr:0x%08x\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ ++ return 0; ++} ++#endif ++#if ENABLE_BTIF_TX_DMA ++static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma) ++{ ++ P_DMA_VFIFO p_vfifo = NULL; ++ struct device *dev = NULL; ++ p_mtk_btif p_btif = NULL; ++ ++ if (p_dma == NULL) { ++ BTIF_ERR_FUNC("p_dma is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ ++ p_btif = (p_mtk_btif)p_dma->p_btif; ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ dev = (struct device *)p_btif->private_data; ++ if (dev == NULL) ++ BTIF_WARN_FUNC("Null dev pointer!!!!\n"); ++ ++ p_vfifo = p_dma->p_dma_info->p_vfifo; ++ ++/*free DMA memory if allocated successfully before*/ ++ if (p_vfifo->p_vir_addr != NULL) { ++ dma_free_coherent(dev, ++ p_vfifo->vfifo_size, ++ p_vfifo->p_vir_addr, p_vfifo->phy_addr); ++ p_vfifo->p_vir_addr = NULL; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int _btif_state_init(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ p_btif->state = B_S_OFF; ++ mutex_init(&(p_btif->state_mtx)); ++ ++ return 0; ++} ++ ++static int _btif_state_hold(p_mtk_btif p_btif) ++{ ++ return mutex_lock_killable(&(p_btif->state_mtx)); ++} ++ ++static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state) ++{ ++/*chaozhong: To do: need to finished state mechine here*/ ++ int i_ret = 0; ++ int ori_state = p_btif->state; ++ ++ if (ori_state == state) { ++ BTIF_INFO_FUNC("already in %s state\n", g_state[state]); ++ return i_ret; ++ } ++ if ((state >= B_S_OFF) && (state < B_S_MAX)) { ++ BTIF_DBG_FUNC("%s->%s request\n", g_state[ori_state], ++ g_state[state]); ++ if (state == B_S_ON) ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); ++ switch (ori_state) { ++ case B_S_ON: ++/*B_S_ON can only be switched to B_S_OFF, B_S_SUSPEND and B_S_DPIDLE*/ ++/*B_S_ON->B_S_OFF : do nothing here*/ ++/* ++ * B_S_ON->B_S_DPLE : disable clock backup ++ * BTIF and DMA controller's register if necessary ++ */ ++ if (state == B_S_DPIDLE) { ++ /*clock controlled id done in _btif_enter_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_OFF) { ++ /*clock controlled is done in btif_close*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_SUSPEND) { ++ /*clock controlled is done in btif_close*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ case B_S_DPIDLE: ++/*B_S_DPIDLE can only be switched to B_S_ON and B_S_SUSPEND*/ ++/*B_S_DPIDLE-> B_S_ON: do nothing for this moment*/ ++/* ++ * B_S_DPIDLE-> B_S_SUSPEND: ++ * disable clock backup BTIF and DMA controller's register if necessary ++ */ ++ if (state == B_S_ON) { ++ /*clock controlled id done in _btif_exit_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_SUSPEND) { ++ /*clock controlled is done in _btif_exit_dpidle*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ ++ case B_S_SUSPEND: ++/*B_S_SUSPEND can be switched to B_S_IDLE and B_S_ON*/ ++/*reinit BTIF controller and DMA controller*/ ++ if (state == B_S_DPIDLE) { ++ /* ++ * system call resume API, do resume operation, ++ * change to deepidle state ++ */ ++ p_btif->state = state; ++ i_ret = 0; ++ } else if (state == B_S_ON) { ++ /* ++ * when stp want to send data before ++ * system do resume operation ++ */ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ break; ++ ++ case B_S_OFF:{ ++/*B_S_OFF can only be switched to B_S_ON*/ ++ if (state == B_S_ON) { ++ /*clock controlled is done in btif_open*/ ++ p_btif->state = state; ++ i_ret = 0; ++ } else { ++ BTIF_ERR_FUNC("%s->%s is not allowed\n", ++ g_state[ori_state], ++ g_state[state]); ++ i_ret = E_BTIF_INVAL_STATE; ++ } ++ } ++ break; ++ default: ++/*no this possibility*/ ++ BTIF_ERR_FUNC ++ ("state change request is not allowed, this should never happen\n"); ++ break; ++ } ++ ++ if (state != B_S_ON) ++ _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); ++ ++ } else { ++ i_ret = E_BTIF_INVAL_PARAM; ++ BTIF_ERR_FUNC("invalid state:%d, do nothing\n", state); ++ } ++ return i_ret; ++} ++ ++static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif) ++{ ++ return p_btif->state; ++} ++ ++static int _btif_state_release(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ BTIF_MUTEX_UNLOCK(&(p_btif->state_mtx)); ++ return i_ret; ++} ++ ++static int _btif_state_deinit(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ p_btif->state = B_S_OFF; ++ mutex_destroy(&(p_btif->state_mtx)); ++ ++ return 0; ++} ++ ++static int btif_rx_data_consummer(p_mtk_btif p_btif) ++{ ++ unsigned int length = 0; ++ unsigned char *p_buf = NULL; ++/*get BTIF rx buffer's information*/ ++ p_btif_buf_str p_bbs = &(p_btif->btif_buf); ++/* ++ * wr_idx of btif_buf may be modified in IRQ handler, ++ * in order not to be effected by case in which irq interrupt this operation, ++ * we record wr_idx here ++ */ ++ unsigned int wr_idx = p_bbs->wr_idx; ++ ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ ++/*make sure length of rx buffer data > 0*/ ++ do { ++ if (length > 0) { ++ /* ++ * check if rx_cb empty or not, if registered , ++ * call user's rx callback to handle these data ++ */ ++ if (p_btif->rx_cb) { ++ if (p_bbs->rd_idx <= wr_idx) { ++ p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); ++ /* p_buf = &(p_bbs->buf[p_bbs->rd_idx]); */ ++ /* length = BBS_COUNT(p_bbs); */ ++ length = (wr_idx >= (p_bbs)->rd_idx) ? ++ (wr_idx - (p_bbs)->rd_idx) : ++ BBS_SIZE(p_bbs) - ++ ((p_bbs)->rd_idx - wr_idx); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, length); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ /*update rx data read index*/ ++ p_bbs->rd_idx = wr_idx; ++ } else { ++ unsigned int len_tail = ++ BBS_SIZE(p_bbs) - (p_bbs)->rd_idx; ++ /*p_buf = &(p_bbs->buf[p_bbs->->rd_idx]);*/ ++ p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, len_tail); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ length -= len_tail; ++ /*p_buf = &(p_bbs->buf[0]);*/ ++ p_buf = BBS_PTR(p_bbs, 0); ++ if (p_btif->rx_cb) ++ (*(p_btif->rx_cb)) (p_buf, length); ++ else ++ BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); ++ /*update rx data read index*/ ++ p_bbs->rd_idx = wr_idx; ++ } ++ } else if (p_btif->rx_notify != NULL) { ++ (*p_btif->rx_notify) (); ++ } else { ++ BTIF_WARN_FUNC ++ ("p_btif:0x%p, both rx_notify and rx_cb are NULL\n", ++ p_btif); ++ break; ++ } ++ } else { ++ BTIF_DBG_FUNC("length:%d\n", length); ++ break; ++ } ++ wr_idx = p_bbs->wr_idx; ++ length = BBS_COUNT_CUR(p_bbs, wr_idx); ++ } while (1); ++ return length; ++} ++ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++static int mtk_btif_rxd_be_blocked_by_timer(void) ++{ ++ int ret = 0; ++ int counter = 0; ++ unsigned int i; ++ struct timeval now; ++ int time_gap[MAX_BTIF_RXD_TIME_REC]; ++ ++ do_gettimeofday(&now); ++ ++ for (i = 0; i < MAX_BTIF_RXD_TIME_REC; i++) { ++ BTIF_INFO_FUNC("btif_rxd_time_stamp[%d]=%d.%d\n", i, ++ btif_rxd_time_stamp[i].tv_sec, btif_rxd_time_stamp[i].tv_usec); ++ if (now.tv_sec >= btif_rxd_time_stamp[i].tv_sec) { ++ time_gap[i] = now.tv_sec - btif_rxd_time_stamp[i].tv_sec; ++ time_gap[i] *= 1000000; /*second*/ ++ if (now.tv_usec >= btif_rxd_time_stamp[i].tv_usec) ++ time_gap[i] += now.tv_usec - btif_rxd_time_stamp[i].tv_usec; ++ else ++ time_gap[i] += 1000000 - now.tv_usec + btif_rxd_time_stamp[i].tv_usec; ++ ++ if (time_gap[i] > 1000000) ++ counter++; ++ BTIF_INFO_FUNC("time_gap[%d]=%d,counter:%d\n", i, time_gap[i], counter); ++ } else { ++ time_gap[i] = 0; ++ BTIF_ERR_FUNC("abnormal case now:%d < time_stamp[%d]:%d\n", now.tv_sec, ++ i, btif_rxd_time_stamp[i].tv_usec); ++ } ++ } ++ if (counter > (MAX_BTIF_RXD_TIME_REC - 2)) ++ ret = 1; ++ return ret; ++} ++static int mtk_btif_rxd_be_blocked_by_data(void) ++{ ++ unsigned int out_index = 0; ++ unsigned int in_index = 0; ++ unsigned int dump_size = 0; ++ unsigned int len = 0; ++ unsigned long flags; ++ unsigned int sync_pkt_n = 0; ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ P_BTIF_LOG_QUEUE_T p_log_que = NULL; ++ p_mtk_btif p_btif = &(g_btif[0]); ++ ++ p_log_que = &p_btif->rx_log; ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ in_index = p_log_que->in; ++ dump_size = p_log_que->size; ++ out_index = p_log_que->size >= ++ BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - ++ p_log_que->size + ++ in_index) % BTIF_LOG_ENTRY_NUM; ++ if (dump_size != 0) { ++ while (dump_size--) { ++ p_log_buf = p_log_que->p_queue[0] + out_index; ++ len = p_log_buf->len; ++ if (len > BTIF_LOG_SZ) ++ len = BTIF_LOG_SZ; ++ if ((0x7f == *(p_log_buf->buffer)) && (0x7f == *(p_log_buf->buffer + 1))) { ++ sync_pkt_n++; ++ BTIF_INFO_FUNC("tx pkt_count:%d is sync pkt\n", out_index); ++ } ++ out_index++; ++ out_index %= BTIF_LOG_ENTRY_NUM; ++ } ++ } ++ if (sync_pkt_n == 0) ++ BTIF_ERR_FUNC("there is no sync pkt in BTIF buffer\n"); ++ else ++ BTIF_ERR_FUNC("there are %d sync pkt in BTIF buffer\n", sync_pkt_n); ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ return sync_pkt_n; ++} ++ ++int mtk_btif_rxd_be_blocked_flag_get(void) ++{ ++ int ret = 0; ++ int condition1 = 0, condition2 = 0; ++ ++ condition1 = mtk_btif_rxd_be_blocked_by_timer(); ++ condition2 = mtk_btif_rxd_be_blocked_by_data(); ++ if (condition1 && condition2) { ++ BTIF_ERR_FUNC("btif_rxd thread be blocked too long!\n"); ++ ret = 1; ++ } ++ return ret; ++} ++#endif ++static int btif_rx_thread(void *p_data) ++{ ++#if BTIF_RXD_BE_BLOCKED_DETECT ++ unsigned int i = 0; ++#endif ++ p_mtk_btif p_btif = (p_mtk_btif)p_data; ++ ++ ++ while (1) { ++ wait_for_completion_interruptible(&p_btif->rx_comp); ++ ++ if (kthread_should_stop()) { ++ BTIF_WARN_FUNC("btif rx thread stoping ...\n"); ++ break; ++ } ++#ifdef BTIF_RXD_BE_BLOCKED_DETECT ++ do_gettimeofday(&btif_rxd_time_stamp[i]); ++ i++; ++ if (i >= MAX_BTIF_RXD_TIME_REC) ++ i = 0; ++#endif ++ btif_rx_data_consummer(p_btif); ++ } ++ return 0; ++} ++ ++static void btif_rx_worker(struct work_struct *p_work) ++{ ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = container_of(p_work, mtk_btif, rx_work); ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++/*lock rx_mutex*/ ++ ++ if (mutex_lock_killable(&(p_btif->rx_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return; ++ } ++ btif_rx_data_consummer(p_btif); ++ BTIF_MUTEX_UNLOCK(&(p_btif->rx_mtx)); ++} ++ ++static void btif_tx_worker(struct work_struct *p_work) ++{ ++ int i_ret = 0; ++ int leng_sent = 0; ++/*tx fifo out*/ ++ int how_much_get = 0; ++ unsigned char local_buf[384]; ++ ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = container_of(p_work, mtk_btif, tx_work); ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++ ++ if (mutex_lock_killable(&(p_btif->tx_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return; ++ } ++ how_much_get = ++ kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); ++ do { ++ while (leng_sent < how_much_get) { ++ i_ret = _btif_send_data(p_btif, ++ local_buf + leng_sent, ++ how_much_get - leng_sent); ++ if (i_ret > 0) { ++ leng_sent += i_ret; ++ } else if (i_ret == 0) { ++ BTIF_WARN_FUNC ++ ("_btif_send_data return 0, retry\n"); ++ } else { ++ BTIF_WARN_FUNC ++ ("btif send data fail,reset tx fifo, i_ret(%d)\n", ++ i_ret); ++ kfifo_reset(p_btif->p_tx_fifo); ++ break; ++ } ++ } ++ how_much_get = ++ kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); ++ leng_sent = 0; ++ } while (how_much_get > 0); ++ BTIF_MUTEX_UNLOCK(&(p_btif->tx_mtx)); ++} ++ ++static void btif_rx_tasklet(unsigned long func_data) ++{ ++ unsigned long flags; ++/*get mtk_btif's pointer*/ ++ p_mtk_btif p_btif = (p_mtk_btif) func_data; ++ ++ BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); ++/*lock rx_spinlock*/ ++ spin_lock_irqsave(&p_btif->rx_tasklet_spinlock, flags); ++ btif_rx_data_consummer(p_btif); ++ spin_unlock_irqrestore(&p_btif->rx_tasklet_spinlock, flags); ++} ++ ++static int _btif_tx_ctx_init(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ p_btif->p_tx_wq = create_singlethread_workqueue("btif_txd"); ++ ++ if (!(p_btif->p_tx_wq)) { ++ BTIF_ERR_FUNC ++ ("create_singlethread_workqueue for tx thread fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ mutex_init(&(p_btif->tx_mtx)); ++/* init btif tx work */ ++ INIT_WORK(&(p_btif->tx_work), btif_tx_worker); ++ BTIF_INFO_FUNC("btif_tx_worker init succeed\n"); ++ ++ p_btif->p_tx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); ++ if (p_btif->p_tx_fifo == NULL) { ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); ++ goto btm_init_err; ++ } ++ ++ i_ret = kfifo_alloc(p_btif->p_tx_fifo, ++ BTIF_TX_FIFO_SIZE, GFP_ATOMIC); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ } else if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { ++ BTIF_INFO_FUNC ++ ("nothing is done when btif tx in user's thread\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported tx context type:%d\n", ++ p_btif->tx_ctx); ++ goto btm_init_err; ++ } ++ ++ BTIF_INFO_FUNC("succeed\n"); ++ ++ i_ret = 0; ++ return i_ret; ++btm_init_err: ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ if (p_btif->p_tx_wq) { ++ destroy_workqueue(p_btif->p_tx_wq); ++ p_btif->p_tx_wq = NULL; ++ BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); ++ } ++ kfree(p_btif->p_tx_fifo); ++ } ++ return i_ret; ++} ++ ++static int _btif_tx_ctx_deinit(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ ++ if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ if (p_btif->p_tx_wq) { ++ destroy_workqueue(p_btif->p_tx_wq); ++ p_btif->p_tx_wq = NULL; ++ BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); ++ } ++ if (p_btif->p_tx_fifo) { ++ kfifo_free(p_btif->p_tx_fifo); ++ kfree(p_btif->p_tx_fifo); ++ p_btif->p_tx_fifo = NULL; ++ } ++ } ++ return i_ret; ++} ++ ++static int _btif_rx_btm_init(p_mtk_btif p_btif) ++{ ++ int i_ret = -1; ++ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ init_completion(&p_btif->rx_comp); ++ ++ /*create kernel thread for later rx data handle*/ ++ p_btif->p_task = kthread_create(btif_rx_thread, p_btif, "btif_rxd"); ++ if (p_btif->p_task == NULL) { ++ BTIF_ERR_FUNC("kthread_create fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ ++#if ENABLE_BTIF_RX_THREAD_RT_SCHED ++ { ++ int i_ret = -1; ++ int policy = SCHED_FIFO; ++ struct sched_param param; ++ ++ param.sched_priority = MAX_RT_PRIO - 20; ++ i_ret = sched_setscheduler(p_btif->p_task, policy, ¶m); ++ if (i_ret != 0) ++ BTIF_WARN_FUNC("set RT to btif_rxd workqueue failed\n"); ++ else ++ BTIF_INFO_FUNC("set RT to btif_rxd workqueue succeed\n"); ++ } ++#endif ++ ++ wake_up_process(p_btif->p_task); ++ BTIF_INFO_FUNC("btif_rxd start to work!\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ p_btif->p_rx_wq = create_singlethread_workqueue("btif_rxwq"); ++ if (!(p_btif->p_rx_wq)) { ++ BTIF_ERR_FUNC("create_singlethread_workqueue fail\n"); ++ i_ret = -ENOMEM; ++ goto btm_init_err; ++ } ++ mutex_init(&(p_btif->rx_mtx)); ++ /* init btif rx work */ ++ INIT_WORK(&(p_btif->rx_work), btif_rx_worker); ++ BTIF_INFO_FUNC("btif_rx_worker init succeed\n"); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ /*init rx tasklet*/ ++ tasklet_init(&(p_btif->rx_tasklet), btif_rx_tasklet, ++ (unsigned long)p_btif); ++ spin_lock_init(&(p_btif->rx_tasklet_spinlock)); ++ BTIF_INFO_FUNC("btif_rx_tasklet init succeed\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++/*spinlock init*/ ++ spin_lock_init(&(p_btif->rx_irq_spinlock)); ++ BTIF_INFO_FUNC("rx_spin_lock init succeed\n"); ++ ++ i_ret = 0; ++ return i_ret; ++btm_init_err: ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ /*do nothing*/ ++ BTIF_INFO_FUNC("failed\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ if (p_btif->p_rx_wq) { ++ destroy_workqueue(p_btif->p_rx_wq); ++ p_btif->p_rx_wq = NULL; ++ BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); ++ } ++ } ++ return i_ret; ++} ++ ++static int _btif_rx_btm_sched(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ complete(&p_btif->rx_comp); ++ BTIF_DBG_FUNC("schedule btif_rx_thread\n"); ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ queue_work(p_btif->p_rx_wq, &(p_btif->rx_work)); ++ BTIF_DBG_FUNC("schedule btif_rx_worker\n"); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ /*schedule it!*/ ++ tasklet_schedule(&(p_btif->rx_tasklet)); ++ BTIF_DBG_FUNC("schedule btif_rx_tasklet\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++ return 0; ++} ++ ++static int _btif_rx_btm_deinit(p_mtk_btif p_btif) ++{ ++ if (p_btif == NULL) { ++ BTIF_ERR_FUNC("p_btif is NULL\n"); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if (p_btif->btm_type == BTIF_THREAD_CTX) { ++ if (p_btif->p_task != NULL) { ++ BTIF_INFO_FUNC("signaling btif rx thread to stop ...\n"); ++ kthread_stop(p_btif->p_task); ++ } ++ } else if (p_btif->btm_type == BTIF_WQ_CTX) { ++ if (p_btif->p_rx_wq) { ++ cancel_work_sync(&(p_btif->rx_work)); ++ BTIF_INFO_FUNC("btif_rx_worker cancelled\n"); ++ destroy_workqueue(p_btif->p_rx_wq); ++ p_btif->p_rx_wq = NULL; ++ BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); ++ } ++ mutex_destroy(&(p_btif->rx_mtx)); ++ } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { ++ tasklet_kill(&(p_btif->rx_tasklet)); ++ BTIF_INFO_FUNC("rx_tasklet killed\n"); ++ } else { ++ BTIF_ERR_FUNC("unsupported rx context type:%d\n", ++ p_btif->btm_type); ++ } ++ ++ spin_lock_init(&(p_btif->rx_irq_spinlock)); ++ ++ return 0; ++} ++ ++ ++void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs) ++{ ++ BTIF_INFO_FUNC ++ ("%s UBS:0x%p\n Size:0x%p\n read:0x%08x\n write:0x%08x\n", ++ p_str, p_bbs, p_bbs->size, p_bbs->rd_idx, p_bbs->wr_idx); ++} ++ ++unsigned int btif_bbs_write(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++/*in IRQ context, so read operation won't interrupt this operation*/ ++ ++ unsigned int wr_len = 0; ++ ++ unsigned int emp_len = BBS_LEFT(p_bbs); ++ unsigned int ava_len = emp_len - 1; ++ p_mtk_btif p_btif = container_of(p_bbs, mtk_btif, btif_buf); ++ ++ if (ava_len <= 0) { ++ BTIF_ERR_FUNC ++ ("no empty space left for write, (%d)ava_len, (%d)to write\n", ++ ava_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ return 0; ++ } ++ ++ if (ava_len < buf_len) { ++ BTIF_ERR_FUNC("BTIF overrun, (%d)empty, (%d)needed\n", ++ emp_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ } ++ ++ if (buf_len >= g_max_pkg_len) { ++ BTIF_WARN_FUNC("buf_len too long, (%d)ava_len, (%d)to write\n", ++ ava_len, buf_len); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ } ++ ++ wr_len = min(buf_len, ava_len); ++ btif_bbs_wr_direct(p_bbs, p_buf, wr_len); ++ ++ if (BBS_COUNT(p_bbs) >= g_max_pding_data_size) { ++ BTIF_WARN_FUNC("Rx buf_len too long, size(%d)\n", ++ BBS_COUNT(p_bbs)); ++ btif_dump_bbs_str("Rx buffer tooo long", p_bbs); ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ _btif_dump_memory("", p_buf, buf_len); ++ BBS_INIT(p_bbs); ++ } ++ ++ return wr_len; ++} ++ ++unsigned int btif_bbs_read(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int rd_len = 0; ++ unsigned int ava_len = 0; ++ unsigned int wr_idx = p_bbs->wr_idx; ++ ++ ava_len = BBS_COUNT_CUR(p_bbs, wr_idx); ++ if (ava_len >= 4096) { ++ BTIF_WARN_FUNC("ava_len too long, size(%d)\n", ava_len); ++ btif_dump_bbs_str("Rx buffer tooo long", p_bbs); ++ } ++ if (ava_len != 0) { ++ if (buf_len >= ava_len) { ++ rd_len = ava_len; ++ if (wr_idx >= (p_bbs)->rd_idx) { ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ ava_len); ++ (p_bbs)->rd_idx = wr_idx; ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - ++ (p_bbs)->rd_idx; ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ tail_len); ++ memcpy(p_buf + tail_len, BBS_PTR(p_bbs, ++ 0), ava_len - tail_len); ++ (p_bbs)->rd_idx = wr_idx; ++ } ++ } else { ++ rd_len = buf_len; ++ if (wr_idx >= (p_bbs)->rd_idx) { ++ memcpy(p_buf, BBS_PTR(p_bbs, ++ p_bbs->rd_idx), ++ rd_len); ++ (p_bbs)->rd_idx = (p_bbs)->rd_idx + rd_len; ++ } else { ++ unsigned int tail_len = BBS_SIZE(p_bbs) - ++ (p_bbs)->rd_idx; ++ if (tail_len >= rd_len) { ++ memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), ++ rd_len); ++ (p_bbs)->rd_idx = ++ ((p_bbs)->rd_idx + rd_len) & (BBS_MASK(p_bbs)); ++ } else { ++ memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), tail_len); ++ memcpy(p_buf + tail_len, ++ (p_bbs)->p_buf, rd_len - tail_len); ++ (p_bbs)->rd_idx = rd_len - tail_len; ++ } ++ } ++ } ++ } ++ mb(); ++ return rd_len; ++} ++ ++unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, ++ unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int tail_len = 0; ++ unsigned int l = 0; ++ unsigned int tmp_wr_idx = p_bbs->wr_idx; ++ ++ tail_len = BBS_SIZE(p_bbs) - (tmp_wr_idx & BBS_MASK(p_bbs)); ++ ++ l = min(tail_len, buf_len); ++ ++ memcpy((p_bbs->p_buf) + (tmp_wr_idx & BBS_MASK(p_bbs)), p_buf, l); ++ memcpy(p_bbs->p_buf, p_buf + l, buf_len - l); ++ ++ mb(); ++ ++ tmp_wr_idx += buf_len; ++ tmp_wr_idx &= BBS_MASK(p_bbs); ++ p_bbs->wr_idx = tmp_wr_idx; ++ ++ mb(); ++ return buf_len; ++} ++ ++int _btif_dma_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int i_ret = 0; ++ unsigned int retry = 0; ++ unsigned int max_tx_retry = 10; ++ ++ P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; ++ ++ _btif_irq_ctrl_sync(p_dma_info->p_irq, false); ++ do { ++ /*wait until tx is allowed*/ ++ while (!hal_dma_is_tx_allow(p_dma_info) && ++ (retry < max_tx_retry)) { ++ retry++; ++ if (retry >= max_tx_retry) { ++ BTIF_ERR_FUNC("wait for tx allowed timeout\n"); ++ break; ++ } ++ } ++ if (retry >= max_tx_retry) ++ break; ++ ++ if (buf_len <= hal_dma_get_ava_room(p_dma_info)) ++ i_ret = hal_dma_send_data(p_dma_info, p_buf, buf_len); ++ else ++ i_ret = 0; ++ } while (0); ++ _btif_irq_ctrl_sync(p_dma_info->p_irq, true); ++ return i_ret; ++} ++ ++int _btif_pio_write(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int i_ret = 0; ++ unsigned int sent_len = 0; ++ unsigned int retry = 0; ++ unsigned int max_tx_retry = 10; ++ P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; ++ ++ while ((sent_len < buf_len)) { ++ if (hal_btif_is_tx_allow(p_btif_info)) { ++ i_ret = hal_btif_send_data(p_btif_info, ++ p_buf + sent_len, ++ buf_len - sent_len); ++ if (i_ret > 0) { ++ sent_len += i_ret; ++ BTIF_DBG_FUNC("lent sent:%d, total sent:%d\n", ++ i_ret, sent_len); ++ retry = 0; ++ } ++ } ++ if ((++retry > max_tx_retry) || (i_ret < 0)) { ++ BTIF_INFO_FUNC("exceed retry times limit :%d\n", retry); ++ break; ++ } ++ } ++ i_ret = sent_len; ++ return i_ret; ++} ++ ++int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len) ++{ ++ unsigned int idx = 0; ++ ++ pr_debug("%s:, length:%d\n", str, buf_len); ++ for (idx = 0; idx < buf_len;) { ++ pr_debug("%02x ", p_buf[idx]); ++ idx++; ++ if (idx % 8 == 0) ++ pr_debug("\n"); ++ } ++ return 0; ++} ++ ++int btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ int i_ret = 0; ++ ++ if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { ++ i_ret = _btif_send_data(p_btif, p_buf, buf_len); ++ } else if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { ++ int length = 0; ++/*tx fifo in*/ ++ length = kfifo_in(p_btif->p_tx_fifo, ++ (unsigned char *)p_buf, buf_len); ++ if (length == buf_len) { ++ queue_work(p_btif->p_tx_wq, &(p_btif->tx_work)); ++ BTIF_DBG_FUNC("schedule btif_tx_worker\n"); ++ i_ret = length; ++ } else { ++ i_ret = 0; ++ BTIF_ERR_FUNC("fifo in failed, target len(%d),in len(%d),", ++ "don't schedule btif_tx_worker\n", buf_len, length); ++ } ++ } else { ++ BTIF_ERR_FUNC("invalid btif tx context:%d\n", p_btif->tx_ctx); ++ i_ret = 0; ++ } ++ ++ return i_ret; ++} ++ ++int _btif_send_data(p_mtk_btif p_btif, ++ const unsigned char *p_buf, unsigned int buf_len) ++{ ++ int i_ret = 0; ++ unsigned int state = 0; ++ ++/*make sure BTIF in ON state before doing tx operation*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ state = _btif_state_get(p_btif); ++ ++ if (state != B_S_ON) ++ i_ret = _btif_exit_dpidle(p_btif); ++ ++ if (i_ret != 0) { ++ i_ret = E_BTIF_INVAL_STATE; ++ } else if (p_btif->tx_mode == BTIF_MODE_DMA) { ++ /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ ++ i_ret = _btif_dma_write(p_btif, p_buf, buf_len); ++ } else if (p_btif->tx_mode == BTIF_MODE_PIO) { ++ /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ ++ i_ret = _btif_pio_write(p_btif, p_buf, buf_len); ++ } else { ++ BTIF_ERR_FUNC("invalid tx mode:%d\n", p_btif->tx_mode); ++ i_ret = 0; ++ } ++ ++/*save Tx packet here*/ ++ if (i_ret > 0) ++ btif_log_buf_dmp_in(&p_btif->tx_log, p_buf, i_ret); ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int btif_dump_reg(p_mtk_btif p_btif) ++{ ++ int i_ret = 0; ++ unsigned int ori_state = 0; ++ ++/*make sure BTIF in ON state before doing tx operation*/ ++ if (_btif_state_hold(p_btif)) ++ return E_BTIF_INTR; ++ ori_state = _btif_state_get(p_btif); ++ ++ if (ori_state == B_S_OFF) { ++ i_ret = E_BTIF_INVAL_STATE; ++ BTIF_ERR_FUNC ++ ("BTIF in OFF state, ", ++ "should no need to dump register, ", ++ "please check wmt's operation is okay or not.\n"); ++ goto dmp_reg_err; ++ } ++ ++ if ((ori_state != B_S_ON) && (ori_state < B_S_MAX)) { ++ BTIF_ERR_FUNC("BTIF's original state is %s, not B_S_ON\n", g_state[ori_state]); ++ BTIF_ERR_FUNC("!!!!---<<>>---!!!"); ++ i_ret = _btif_exit_dpidle(p_btif); ++ } ++ ++ if (i_ret != 0) { ++ i_ret = E_BTIF_INVAL_STATE; ++ BTIF_ERR_FUNC("switch to B_S_ON failed\n"); ++ goto dmp_reg_err; ++ } ++ ++/*dump BTIF register*/ ++ hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); ++ ++/*dump BTIF Tx DMA channel register if in DMA mode*/ ++ if (p_btif->tx_mode == BTIF_MODE_DMA) ++ hal_dma_dump_reg(p_btif->p_tx_dma->p_dma_info, REG_TX_DMA_ALL); ++ else ++ BTIF_INFO_FUNC("BTIF Tx in PIO mode,no need to dump Tx DMA's register\n"); ++ ++/*dump BTIF Rx DMA channel register if in DMA mode*/ ++ if (p_btif->rx_mode == BTIF_MODE_DMA) ++ hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); ++ else ++ BTIF_INFO_FUNC("BTIF Rx in PIO mode,no need to dump Rx DMA's register\n"); ++ ++ switch (ori_state) { ++ case B_S_SUSPEND: ++/*return to dpidle state*/ ++/* break; */ ++ case B_S_DPIDLE: ++/*return to dpidle state*/ ++ _btif_enter_dpidle(p_btif); ++ break; ++ case B_S_ON: ++/*nothing needs to be done*/ ++ break; ++ default: ++ break; ++ } ++ ++dmp_reg_err: ++ ++ BTIF_STATE_RELEASE(p_btif); ++ return i_ret; ++} ++ ++int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify) ++{ ++ if (p_btif->rx_notify) { ++ BTIF_WARN_FUNC ++ ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", ++ p_btif->rx_notify, rx_notify); ++ } ++ p_btif->rx_notify = rx_notify; ++ ++ return 0; ++} ++ ++int btif_dump_data(char *p_buf, int len) ++{ ++ unsigned int idx = 0; ++ unsigned char str[30]; ++ unsigned char *p_str; ++ ++ p_str = &str[0]; ++ for (idx = 0; idx < len; idx++, p_buf++) { ++ sprintf(p_str, "%02x ", *p_buf); ++ p_str += 3; ++ if (7 == (idx % 8)) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ p_str = &str[0]; ++ } ++ } ++ if (len % 8) { ++ *p_str++ = '\n'; ++ *p_str = '\0'; ++ pr_debug("%s", str); ++ } ++ return 0; ++} ++ ++int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, ++ int len) ++{ ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ char *dir = NULL; ++ struct timeval *p_timer = NULL; ++ unsigned long flags; ++ bool output_flag = false; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++ if ((p_log_que == NULL) || (p_buf == NULL) || (len == 0)) { ++ BTIF_ERR_FUNC("invalid parameter, p_log_que(0x%x), buf(0x%x), ", ++ "len(%d)\n", p_log_que, p_buf, len); ++ return 0; ++ } ++ if (!(p_log_que->enable)) ++ return 0; ++ ++ dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; ++ output_flag = p_log_que->output_flag; ++ ++ spin_lock_irqsave(&(p_log_que->lock), flags); ++ ++/*get next log buffer for record usage*/ ++ p_log_buf = p_log_que->p_queue[0] + p_log_que->in; ++ p_timer = &p_log_buf->timer; ++ ++/*log time stamp*/ ++ do_gettimeofday(p_timer); ++ ++/*record data information including length and content*/ ++ p_log_buf->len = len; ++ memcpy(p_log_buf->buffer, p_buf, len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len); ++ ++/*update log queue size information*/ ++ p_log_que->size++; ++ p_log_que->size = p_log_que->size > ++ BTIF_LOG_ENTRY_NUM ? BTIF_LOG_ENTRY_NUM : p_log_que->size; ++ ++/*update log queue index information*/ ++ p_log_que->in++; ++ p_log_que->in %= BTIF_LOG_ENTRY_NUM; ++ ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ ++/*check if log dynamic output function is enabled or not*/ ++ if (output_flag) { ++ pr_debug("BTIF-DBG, dir:%s, %d.%ds len:%d\n", ++ dir, (int)p_timer->tv_sec, (int)p_timer->tv_usec, len); ++/*output buffer content*/ ++ btif_dump_data((char *)p_buf, len); ++ } ++ BTIF_DBG_FUNC("--\n"); ++ ++ return 0; ++} ++ ++int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ P_BTIF_LOG_BUF_T p_log_buf = NULL; ++ unsigned int out_index = 0; ++ unsigned int in_index = 0; ++ unsigned int dump_size = 0; ++ unsigned char *p_buf = NULL; ++ unsigned int len = 0; ++ unsigned int pkt_count = 0; ++ unsigned char *p_dir = NULL; ++ struct timeval *p_timer = NULL; ++ unsigned long flags; ++ ++#if 0 /* no matter enable or not, we allowed output */ ++ if (!(p_log_que->enable)) ++ return; ++#endif ++ BTIF_DBG_FUNC("++\n"); ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ in_index = p_log_que->in; ++ dump_size = p_log_que->size; ++ out_index = p_log_que->size >= ++ BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - ++ p_log_que->size + ++ in_index) % BTIF_LOG_ENTRY_NUM; ++ p_dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; ++ ++ BTIF_INFO_FUNC("btif %s log buffer size:%d\n", p_dir, dump_size); ++ ++ if (dump_size != 0) { ++ while (dump_size--) { ++ p_log_buf = p_log_que->p_queue[0] + out_index; ++ ++ len = p_log_buf->len; ++ p_buf = p_log_buf->buffer; ++ p_timer = &p_log_buf->timer; ++ ++ len = len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len; ++ ++ BTIF_INFO_FUNC("dir:%s, pkt_count:%d, %d.%ds len:%d\n", ++ p_dir, ++ pkt_count++, ++ (int)p_timer->tv_sec, ++ (int)p_timer->tv_usec, len); ++/*output buffer content*/ ++ btif_dump_data(p_log_buf->buffer, len); ++ out_index++; ++ out_index %= BTIF_LOG_ENTRY_NUM; ++ } ++ } ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_DBG_FUNC("--\n"); ++ ++ return 0; ++} ++ ++int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->enable = true; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("enable %s log function\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->enable = false; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("disable %s log function\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->output_flag = true; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("%s log rt output enabled\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ p_log_que->output_flag = false; ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_INFO_FUNC("%s log rt output disabled\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p_log_que->lock, flags); ++ ++/*tx log buffer init*/ ++ p_log_que->in = 0; ++ p_log_que->out = 0; ++ p_log_que->size = 0; ++ p_log_que->enable = true; ++ memset((p_log_que->p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++ spin_unlock_irqrestore(&p_log_que->lock, flags); ++ BTIF_DBG_FUNC("reset %s log buffer\n", ++ p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); ++ return 0; ++} ++ ++int btif_log_buf_init(p_mtk_btif p_btif) ++{ ++/*tx log buffer init*/ ++ p_btif->tx_log.dir = BTIF_TX; ++ p_btif->tx_log.in = 0; ++ p_btif->tx_log.out = 0; ++ p_btif->tx_log.size = 0; ++ p_btif->tx_log.output_flag = false; ++ p_btif->tx_log.enable = true; ++ spin_lock_init(&(p_btif->tx_log.lock)); ++ BTIF_DBG_FUNC("tx_log.p_queue:0x%p\n", p_btif->tx_log.p_queue[0]); ++ memset((p_btif->tx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++/*rx log buffer init*/ ++ p_btif->rx_log.dir = BTIF_RX; ++ p_btif->rx_log.in = 0; ++ p_btif->rx_log.out = 0; ++ p_btif->rx_log.size = 0; ++ p_btif->rx_log.output_flag = false; ++ p_btif->rx_log.enable = true; ++ spin_lock_init(&(p_btif->rx_log.lock)); ++ BTIF_DBG_FUNC("rx_log.p_queue:0x%p\n", p_btif->rx_log.p_queue[0]); ++ memset((p_btif->rx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); ++ ++ return 0; ++} ++ ++int btif_tx_dma_mode_set(int en) ++{ ++ int index = 0; ++ ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ g_btif[index].tx_mode = mode; ++ ++ return 0; ++} ++ ++int btif_rx_dma_mode_set(int en) ++{ ++ int index = 0; ++ ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ g_btif[index].rx_mode = mode; ++ ++ return 0; ++} ++ ++static int BTIF_init(void) ++{ ++ int i_ret = -1; ++ int index = 0; ++ p_mtk_btif_dma p_tx_dma = NULL; ++ p_mtk_btif_dma p_rx_dma = NULL; ++ unsigned char *p_btif_buffer = NULL; ++ unsigned char *p_tx_queue = NULL; ++ unsigned char *p_rx_queue = NULL; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++/*Platform Driver initialization*/ ++ i_ret = platform_driver_register(&mtk_btif_dev_drv); ++ if (i_ret) { ++ BTIF_ERR_FUNC("BTIF platform driver registered failed, ret(%d)\n", i_ret); ++ goto err_exit1; ++ } ++ ++ i_ret = driver_create_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ if (i_ret) ++ BTIF_ERR_FUNC("BTIF pdriver_create_file failed, ret(%d)\n", i_ret); ++ ++/*SW init*/ ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ p_btif_buffer = kmalloc(BTIF_RX_BUFFER_SIZE, GFP_ATOMIC); ++ if (!p_btif_buffer) { ++ BTIF_ERR_FUNC("p_btif_buffer kmalloc memory fail\n"); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_btif_buffer get memory 0x%p\n", p_btif_buffer); ++ p_tx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); ++ if (!p_tx_queue) { ++ BTIF_ERR_FUNC("p_tx_queue kmalloc memory fail\n"); ++ kfree(p_btif_buffer); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_tx_queue get memory 0x%p\n", p_tx_queue); ++ p_rx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); ++ if (!p_rx_queue) { ++ BTIF_ERR_FUNC("p_rx_queue kmalloc memory fail\n"); ++ kfree(p_btif_buffer); ++ kfree(p_tx_queue); ++ return -1; ++ } ++ BTIF_INFO_FUNC("p_rx_queue get memory 0x%p\n", p_rx_queue); ++ ++ INIT_LIST_HEAD(&(g_btif[index].user_list)); ++ BBS_INIT(&(g_btif[index].btif_buf)); ++ g_btif[index].enable = false; ++ g_btif[index].open_counter = 0; ++ g_btif[index].setting = &g_btif_setting[index]; ++ g_btif[index].p_btif_info = hal_btif_info_get(); ++ g_btif[index].tx_mode = g_btif_setting[index].tx_mode; ++ g_btif[index].rx_mode = g_btif_setting[index].rx_mode; ++ g_btif[index].btm_type = g_btif_setting[index].rx_type; ++ g_btif[index].tx_ctx = g_btif_setting[index].tx_type; ++ g_btif[index].lpbk_flag = false; ++ g_btif[index].rx_cb = NULL; ++ g_btif[index].rx_notify = NULL; ++ g_btif[index].btif_buf.p_buf = p_btif_buffer; ++ g_btif[index].tx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_tx_queue; ++ g_btif[index].rx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_rx_queue; ++ btif_log_buf_init(&g_btif[index]); ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF clock gating by default*/ ++ i_ret = hal_btif_clk_ctrl(g_btif[index].p_btif_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF controller CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++/* ++ * viftual FIFO memory must be physical continious, ++ * because DMA will access it directly without MMU ++ */ ++#if ENABLE_BTIF_TX_DMA ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ g_btif[index].p_tx_dma = p_tx_dma; ++ p_tx_dma->dir = BTIF_TX; ++ p_tx_dma->p_btif = &(g_btif[index]); ++ ++/*DMA Tx vFIFO initialization*/ ++ p_tx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_TX); ++/*spinlock init*/ ++ spin_lock_init(&(p_tx_dma->iolock)); ++/*entry setup*/ ++ atomic_set(&(p_tx_dma->entry), 0); ++/*vFIFO initialization*/ ++ i_ret = _btif_vfifo_init(p_tx_dma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx vFIFO allocation failed\n"); ++ goto err_exit2; ++ } ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF Tx DMA channel's clock gating by default*/ ++ i_ret = hal_btif_dma_clk_ctrl(p_tx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx DMA's CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++#else ++ g_btif[index].p_tx_dma = NULL; ++/*force tx mode to DMA no matter what it is in default setting*/ ++ g_btif[index].tx_mode = BTIF_MODE_PIO; ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++ g_btif[index].p_rx_dma = p_rx_dma; ++ p_rx_dma->p_btif = &(g_btif[index]); ++ p_rx_dma->dir = BTIF_RX; ++ ++/*DMA Tx vFIFO initialization*/ ++ p_rx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_RX); ++/*spinlock init*/ ++ spin_lock_init(&(p_rx_dma->iolock)); ++/*entry setup*/ ++ atomic_set(&(p_rx_dma->entry), 0); ++/*vFIFO initialization*/ ++ i_ret = _btif_vfifo_init(p_rx_dma); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx vFIFO allocation failed\n"); ++ goto err_exit2; ++ } ++ ++#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) ++/*enable BTIF Tx DMA channel's clock gating by default*/ ++ i_ret = hal_btif_dma_clk_ctrl(p_rx_dma->p_dma_info, ++ CLK_OUT_DISABLE); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx DMA's CG failed\n"); ++ goto err_exit2; ++ } ++#endif ++ ++#else ++ g_btif[index].p_rx_dma = NULL; ++/*force rx mode to DMA no matter what it is in default setting*/ ++ g_btif[index].rx_mode = BTIF_MODE_PIO; ++ ++#endif ++/*PM state mechine initialization*/ ++ i_ret = _btif_state_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF state mechanism init failed\n"); ++ goto err_exit2; ++ } ++ ++/*Rx bottom half initialization*/ ++ i_ret = _btif_rx_btm_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Rx btm init failed\n"); ++ goto err_exit3; ++ } ++ i_ret = _btif_tx_ctx_init(&(g_btif[index])); ++ if (i_ret != 0) { ++ BTIF_ERR_FUNC("BTIF Tx context init failed\n"); ++ goto err_exit4; ++ } ++/*Character Device initialization*/ ++/*Chaozhong: ToDo: to be initialized*/ ++ ++ mutex_init(&g_btif[index].ops_mtx); ++ } ++ ++/*Debug purpose initialization*/ ++ ++#if BTIF_CDEV_SUPPORT ++ btif_chrdev_init(); ++#endif ++ ++ return 0; ++ ++err_exit4: ++ for (index = 0; index < BTIF_PORT_NR; index++) ++ _btif_tx_ctx_deinit(&(g_btif[index])); ++ ++err_exit3: ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ _btif_rx_btm_deinit(&(g_btif[index])); ++ ++ _btif_state_deinit(&(g_btif[index])); ++ } ++ ++err_exit2: ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++#if ENABLE_BTIF_TX_DMA ++ _btif_vfifo_deinit(p_tx_dma); ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ _btif_vfifo_deinit(p_rx_dma); ++#endif ++ g_btif[index].open_counter = 0; ++ g_btif[index].enable = false; ++ } ++ driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ platform_driver_unregister(&mtk_btif_dev_drv); ++ ++err_exit1: ++ i_ret = -1; ++ BTIF_DBG_FUNC("--\n"); ++ return i_ret; ++} ++ ++static void BTIF_exit(void) ++{ ++ unsigned int index = 0; ++ p_mtk_btif_dma p_tx_dma = NULL; ++ p_mtk_btif_dma p_rx_dma = NULL; ++ ++ BTIF_DBG_FUNC("++\n"); ++ ++ for (index = 0; index < BTIF_PORT_NR; index++) { ++ g_btif[index].open_counter = 0; ++ g_btif[index].enable = false; ++ p_tx_dma = &g_dma[index][BTIF_TX]; ++ p_rx_dma = &g_dma[index][BTIF_RX]; ++#if ENABLE_BTIF_TX_DMA ++ _btif_vfifo_deinit(p_tx_dma); ++#endif ++ ++#if ENABLE_BTIF_RX_DMA ++ _btif_vfifo_deinit(p_rx_dma); ++#endif ++ _btif_state_deinit(&(g_btif[index])); ++ ++ _btif_rx_btm_deinit(&(g_btif[index])); ++ ++ mutex_destroy(&g_btif[index].ops_mtx); ++ } ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ hal_btif_clk_unprepare(); ++#endif ++ ++ driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); ++ platform_driver_unregister(&mtk_btif_dev_drv); ++ BTIF_DBG_FUNC("--\n"); ++} ++ ++int mtk_btif_hal_get_log_lvl(void) ++{ ++ return mtk_btif_dbg_lvl; ++} ++ ++void mtk_btif_read_cpu_sw_rst_debug(void) ++{ ++ mtk_btif_read_cpu_sw_rst_debug_plat(); ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++module_init(BTIF_init); ++module_exit(BTIF_exit); ++ ++/*---------------------------------------------------------------------------*/ ++ ++MODULE_AUTHOR("MBJ/WCN/SE/SS1/Chaozhong.Liang"); ++MODULE_DESCRIPTION("MTK BTIF Driver$1.0$"); ++MODULE_LICENSE("GPL"); ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/drivers/misc/mediatek/btif/common/mtk_btif_exp.c b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c +new file mode 100644 +index 000000000000..c0df44558357 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c +@@ -0,0 +1,786 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "MTK-BTIF-EXP" ++ ++/*#include "mtk_btif_exp.h"*/ ++#include "mtk_btif.h" ++ ++/*---------------------------------Function----------------------------------*/ ++ ++p_mtk_btif btif_exp_srh_id(unsigned long u_id) ++{ ++ int index = 0; ++ p_mtk_btif p_btif = NULL; ++ struct list_head *p_list = NULL; ++ struct list_head *tmp = NULL; ++ p_mtk_btif_user p_user = NULL; ++ ++ for (index = 0; (index < BTIF_PORT_NR) && (p_btif == NULL); index++) { ++ p_list = &(g_btif[index].user_list); ++ list_for_each(tmp, p_list) { ++ p_user = container_of(tmp, mtk_btif_user, entry); ++ if (u_id == p_user->u_id) { ++ p_btif = p_user->p_btif; ++ BTIF_DBG_FUNC ++ ("BTIF's user id(0x%p), p_btif(0x%p)\n", ++ p_user->u_id, p_btif); ++ break; ++ } ++ } ++ } ++ if (p_btif == NULL) { ++ BTIF_INFO_FUNC ++ ("no btif structure found for BTIF's user id(0x%lx)\n", ++ u_id); ++ } ++ return p_btif; ++} ++ ++/*-----Normal Mode API declearation-------*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_open ++* DESCRIPTION ++* open BTIF interface, will do BTIF module HW and SW initialization ++* PARAMETERS ++* p_owner [IN] pointer to owner who call this API, ++* currently there are 2 owner ("stp" or "btif_tester") ++* may use this module ++* for "stp", BTIF will call rx callback function to route rx data to STP module ++* for "stp_tester", BTIF will save rx data and wait for native process to access ++* p_id [IN] BTIF's user id will be put to this address ++* RETURNS ++* int 0 = BTIF module initialization fail; negative = BTIF module initialization success ++* if open success, value p_id will be the only identifier ++* for user to access BTIF's other operations ++* including read/write/dpidle_ctrl/rx_cb_retister ++* this user id is only an identifier used for owner identification ++*****************************************************************************/ ++int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id) ++{ ++ int i_ret = -1; ++ unsigned int index = 0; ++ p_mtk_btif_user p_new_user = NULL; ++ p_mtk_btif p_btif = &g_btif[index]; ++ struct list_head *p_user_list = &(p_btif->user_list); ++ ++ BTIF_DBG_FUNC("++"); ++ BTIF_DBG_FUNC("p_btif(0x%p)\n", p_btif); ++ ++ if (mutex_lock_killable(&(p_btif->ops_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return E_BTIF_INTR; ++ } ++ if ((p_owner == NULL) || (p_id == NULL)) { ++ if (p_id) ++ *p_id = 0; ++ BTIF_ERR_FUNC("parameter invalid, p_owner(0x%p), p_id(0x%p)\n", ++ p_owner, p_id); ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++/*check if btif is already opened or not, if yes, just return fail*/ ++ if (!list_empty(p_user_list)) { ++ struct list_head *pos; ++ p_mtk_btif_user p_user; ++ ++ BTIF_ERR_FUNC("BTIF's user list is not empty\n"); ++ list_for_each(pos, p_user_list) { ++ p_user = container_of(pos, mtk_btif_user, entry); ++ BTIF_INFO_FUNC("BTIF's user id(0x%lx), name(%s)\n", ++ p_user->u_id, p_user->u_name); ++ } ++/*leave p_id alone*/ ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ return E_BTIF_ALREADY_OPEN; ++ } ++ p_new_user = vmalloc(sizeof(mtk_btif_user)); ++ ++ if (p_new_user != NULL) { ++ INIT_LIST_HEAD(&(p_new_user->entry)); ++ p_new_user->enable = false; ++ p_new_user->p_btif = p_btif; ++ p_new_user->u_id = (unsigned long)p_new_user; ++ strncpy(p_new_user->u_name, p_owner, sizeof(p_new_user->u_name) - 1); ++ p_new_user->u_name[sizeof(p_new_user->u_name) - 1] = '\0'; ++ BTIF_DBG_FUNC("owner name:%s, recorded name:%s\n", ++ p_owner, p_new_user->u_name); ++ ++ i_ret = btif_open(p_btif); ++ if (i_ret) { ++ BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); ++ *p_id = 0; ++/*free btif new user's structure*/ ++ vfree(p_new_user); ++ p_new_user = NULL; ++ } else { ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ *p_id = p_new_user->u_id; ++/*mark enable flag to true*/ ++ p_new_user->enable = true; ++/*add to uer lsit*/ ++ list_add_tail(&(p_new_user->entry), p_user_list); ++ } ++ } else { ++ *p_id = 0; ++ i_ret = -ENOMEM; ++ BTIF_ERR_FUNC("allocate memory for mtk_btif_user failed\n"); ++ } ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ BTIF_DBG_FUNC("--"); ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_open); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_close ++* DESCRIPTION ++* close BTIF interface, will do BTIF module HW and SW de-initialization ++* once this API is called, p_btif should never be used by BTIF's user again ++* PARAMETERS ++* u_id [IN] BTIF's user id ++* RETURNS ++* int 0 = succeed; ++* others = fail, ++* for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_close(unsigned long u_id) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ struct list_head *pos = NULL; ++ struct list_head *p_user_list = NULL; ++ ++ BTIF_DBG_FUNC("++"); ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (mutex_lock_killable(&(p_btif->ops_mtx))) { ++ BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); ++ return E_BTIF_INTR; ++ } ++ p_user_list = &(p_btif->user_list); ++ list_for_each(pos, p_user_list) { ++ p_mtk_btif_user p_user = ++ container_of(pos, mtk_btif_user, entry); ++ ++ if (p_user->u_id == u_id) { ++ BTIF_INFO_FUNC ++ ("user who's id is 0x%lx deleted from user list\n", ++ u_id); ++ list_del(pos); ++ vfree(p_user); ++ i_ret = btif_close(p_btif); ++ if (i_ret) ++ BTIF_WARN_FUNC("BTIF close failed"); ++ break; ++ } ++ } ++ BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); ++ BTIF_DBG_FUNC("--"); ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_close); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_write ++* DESCRIPTION ++* send data throuth BTIF module ++* there's no internal buffer to cache STP data in BTIF driver, ++* if in DMA mode ++* btif driver will check if there's enough space in vFIFO for data to send in DMA mode ++* if yes, put data to vFIFO and return corresponding data length to caller ++* if no, corresponding error code will be returned to called ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN] pointer to target data to send ++* len [IN] data length (should be less than 2014 bytes per STP package) ++* ++* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller ++* if btif driver detected that no space is available in Tx FIFO, ++* will return E_BTIF_NO_SPACE, mostly something is wrong with BTIF or ++* consys when this return value is returned ++* RETURNS ++* int positive: data length send through BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++* E_BTIF_AGAIN (0) will be returned to caller ++* if btif does not have enough vFIFO to send data, ++* when caller get 0, he should wait for a moment ++* (5~10ms maybe) and try a few times (maybe 10~20) ++* if still get E_BTIF_AGAIN, ++* should call BTIF's debug API and dump BTIF driver ++* and BTIF/DMA register information to kernel log for debug ++* E_BTIF_BAD_POINTER will be returned to caller ++* if btif is not opened successfully before call this API ++* E_BTIF_INVAL_PARAM will be returned if parameter is not valid ++ ++*****************************************************************************/ ++int mtk_wcn_btif_write(unsigned long u_id, ++ const unsigned char *p_buf, unsigned int len) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ BTIF_DBG_FUNC("++"); ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ if (p_buf == NULL) { ++ BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { ++ BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ i_ret = btif_send_data(p_btif, p_buf, len); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_write); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_read ++* DESCRIPTION ++* read data from BTIF module ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* p_buf [IN/OUT] pointer to buffer where rx data will be put ++* max_len [IN] max buffer length ++* RETURNS ++* int positive: data length read from BTIF; ++* negative: please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_read(unsigned long u_id, ++ unsigned char *p_buf, unsigned int max_len) ++{ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_dpidle_ctrl ++* DESCRIPTION ++* control if BTIF module allow system enter deepidle state or not ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL ++* RETURNS ++* int always return 0 ++*****************************************************************************/ ++int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ i_ret = btif_exit_dpidle(p_btif); ++ else ++ i_ret = btif_enter_dpidle(p_btif); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_dpidle_ctrl); ++ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_rx_cb_register ++* DESCRIPTION ++* register rx callback function to BTIF module by btif user ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* rx_cb [IN] pointer to stp rx handler callback function, ++* should be comply with MTK_WCN_BTIF_RX_CB ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, ++* please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ i_ret = btif_rx_cb_reg(p_btif, rx_cb); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_rx_cb_register); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_wakeup_consys ++* DESCRIPTION ++* once sleep command is sent to con sys, ++* should call this API before send wakeup command ++* to make con sys aware host want to send data to consys ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_wakeup_consys(unsigned long u_id) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ ++ i_ret = btif_raise_wak_signal(p_btif); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_wakeup_consys); ++ ++ ++/***************End of Normal Mode API declearation**********/ ++ ++/***************Debug Purpose API declearation**********/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_loopback_ctrl ++* DESCRIPTION ++* enable/disable BTIF internal loopback function, ++* when this function is enabled data send to btif ++* will be received by btif itself ++* only for debug purpose, should never use this function in normal mode ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* enable [IN] loopback mode control flag, enable or disable, ++* shou be one of ENUM_BTIF_LPBK_MODE ++* RETURNS ++* int 0 = succeed; ++* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ i_ret = ++ btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_btif_logger_ctrl ++* DESCRIPTION ++* control BTIF logger function's behavior ++* PARAMETERS ++* p_btif [IN] pointer returned by mtk_wcn_btif_open ++* flag [IN] should be one of ENUM_BTIF_DBG_ID ++* BTIF_DISABLE_LOGGER - disable btif logger ++* BTIF_ENABLE_LOGGER - enable btif logger ++* BTIF_DUMP_LOG - dump log logged by btif ++* BTIF_CLR_LOG - clear btif log buffer ++* BTIF_DUMP_BTIF_REG - dump btif controller's register ++* BTIF_DUMP_DMA_REG - dump DMA controller's register ++* RETURNS ++* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE ++*****************************************************************************/ ++int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ ++ i_ret = 0; ++ switch (flag) { ++ case BTIF_DISABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("disable btif log function for both Tx and Rx\n"); ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_ENABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("enable btif log function for both Tx and Rx\n"); ++ btif_log_buf_enable(&p_btif->tx_log); ++ btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_LOG:{ ++ BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); ++ btif_log_buf_dmp_out(&p_btif->tx_log); ++ btif_log_buf_dmp_out(&p_btif->rx_log); ++ } ++ break; ++ ++ case BTIF_CLR_LOG:{ ++ BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_BTIF_REG: ++ /*TBD*/ btif_dump_reg(p_btif); ++ break; ++ case BTIF_ENABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("enable btif real time log for both Tx and Rx\n"); ++ btif_log_output_enable(&p_btif->tx_log); ++ btif_log_output_enable(&p_btif->rx_log); ++ break; ++ case BTIF_DISABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("disable btif real time log for both Tx and Rx\n"); ++ btif_log_output_disable(&p_btif->tx_log); ++ btif_log_output_disable(&p_btif->rx_log); ++ break; ++ default: ++ BTIF_INFO_FUNC("not supported flag:%d\n", flag); ++ i_ret = -2; ++ break; ++ } ++ ++ return i_ret; ++} ++EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); ++ ++bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, ++ const char *sub_str, unsigned int str_len) ++{ ++ bool b_ret = false; ++ p_mtk_btif p_btif = NULL; ++ ++ p_btif = btif_exp_srh_id(u_id); ++ ++ if (p_btif == NULL) ++ return E_BTIF_INVAL_PARAM; ++ b_ret = btif_parser_wmt_evt(p_btif, sub_str, str_len); ++ BTIF_INFO_FUNC("parser wmt evt %s\n", b_ret ? "ok" : "fail"); ++ ++ return b_ret; ++} ++ ++/**********End of Debug Purpose API declearation**********/ ++ ++int btif_open_no_id(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_open(p_btif); ++ ++ if (i_ret) ++ BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_open succeed\n"); ++ ++ return i_ret; ++} ++ ++int btif_close_no_id(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_close(p_btif); ++ ++ if (i_ret) ++ BTIF_ERR_FUNC("btif_close failed, i_ret(%d)\n", i_ret); ++ else ++ BTIF_INFO_FUNC("btif_close succeed\n"); ++ return i_ret; ++} ++ ++int btif_write_no_id(const unsigned char *p_buf, unsigned int len) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ BTIF_DBG_FUNC("++"); ++ ++ if (p_buf == NULL) { ++ BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); ++ return E_BTIF_INVAL_PARAM; ++ } ++ if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { ++ BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); ++ return E_BTIF_INVAL_PARAM; ++ } ++ ++ i_ret = btif_send_data(p_btif, p_buf, len); ++ BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); ++ return i_ret; ++} ++ ++int btif_dpidle_ctrl_no_id(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ if (en_flag == BTIF_DPIDLE_DISABLE) ++ i_ret = btif_exit_dpidle(p_btif); ++ else ++ i_ret = btif_enter_dpidle(p_btif); ++ ++ return i_ret; ++} ++ ++int btif_wakeup_consys_no_id(void) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ ++ i_ret = btif_raise_wak_signal(p_btif); ++ ++ return i_ret; ++} ++ ++int btif_loopback_ctrl_no_id(ENUM_BTIF_LPBK_MODE enable) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = ++ btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); ++ ++ return i_ret; ++} ++ ++int btif_dbg_ctrl_no_id(ENUM_BTIF_DBG_ID flag) ++{ ++ int i_ret = -1; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = 0; ++ switch (flag) { ++ case BTIF_DISABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("disable btif log function for both Tx and Rx\n"); ++ btif_log_buf_disable(&p_btif->tx_log); ++ btif_log_buf_disable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_ENABLE_LOGGER:{ ++ BTIF_INFO_FUNC ++ ("enable btif log function for both Tx and Rx\n"); ++ btif_log_buf_enable(&p_btif->tx_log); ++ btif_log_buf_enable(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_LOG:{ ++ BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); ++ btif_log_buf_dmp_out(&p_btif->tx_log); ++ btif_log_buf_dmp_out(&p_btif->rx_log); ++ } ++ break; ++ ++ case BTIF_CLR_LOG:{ ++ BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); ++ btif_log_buf_reset(&p_btif->tx_log); ++ btif_log_buf_reset(&p_btif->rx_log); ++ } ++ break; ++ case BTIF_DUMP_BTIF_REG: ++ /*TBD*/ btif_dump_reg(p_btif); ++ break; ++ case BTIF_ENABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("enable btif real time log for both Tx and Rx\n"); ++ btif_log_output_enable(&p_btif->tx_log); ++ btif_log_output_enable(&p_btif->rx_log); ++ break; ++ case BTIF_DISABLE_RT_LOG: ++ BTIF_INFO_FUNC ++ ("disable btif real time log for both Tx and Rx\n"); ++ btif_log_output_disable(&p_btif->tx_log); ++ btif_log_output_disable(&p_btif->rx_log); ++ break; ++ default: ++ BTIF_INFO_FUNC("not supported flag:%d\n", flag); ++ i_ret = -2; ++ break; ++ } ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_open_test(void) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_open_no_id(); ++ if (i_ret < 0) { ++ BTIF_INFO_FUNC("mtk_wcn_btif_open failed\n"); ++ return -1; ++ } ++ ++ BTIF_INFO_FUNC("mtk_wcn_btif_open succeed\n"); ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_close_test(void) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_close_no_id(); ++ if (i_ret < 0) { ++ BTIF_INFO_FUNC("mtk_wcn_btif_close failed\n"); ++ return -1; ++ } ++ ++ BTIF_INFO_FUNC("mtk_wcn_btif_close succeed\n"); ++ ++ return i_ret; ++} ++ ++int mtk_btif_exp_write_test(void) ++{ ++ return mtk_btif_exp_write_stress_test(100, 10); ++} ++ ++int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int max_loop) ++{ ++#define BUF_LEN 1024 ++ int i_ret = 0; ++ int idx = 0; ++ int buf_len = length > BUF_LEN ? BUF_LEN : length; ++ int loop = max_loop > 1000000 ? 1000000 : max_loop; ++ unsigned char *buffer; ++ ++ buffer = kmalloc(BUF_LEN, GFP_KERNEL); ++ if (!buffer) { ++ BTIF_ERR_FUNC("btif tester kmalloc failed\n"); ++ return -1; ++ } ++ ++ for (idx = 0; idx < buf_len; idx++) ++ /* btif_stress_test_buf[idx] = BUF_LEN -idx; */ ++ *(buffer + idx) = idx % 255; ++ i_ret = btif_loopback_ctrl_no_id(BTIF_LPBK_ENABLE); ++ BTIF_INFO_FUNC("mtk_wcn_btif_loopback_ctrl returned %d\n", i_ret); ++ while (loop--) { ++ i_ret = btif_write_no_id(buffer, buf_len); ++ BTIF_INFO_FUNC("mtk_wcn_btif_write left loop:%d, i_ret:%d\n", ++ loop, i_ret); ++ if (i_ret != buf_len) { ++ BTIF_INFO_FUNC ++ ("mtk_wcn_btif_write failed, target len %d, sent len: %d\n", ++ buf_len, i_ret); ++ break; ++ } ++ buf_len--; ++ if (buf_len <= 0) ++ buf_len = length > BUF_LEN ? BUF_LEN : length; ++ } ++ kfree(buffer); ++ return i_ret; ++} ++ ++int mtk_btif_exp_suspend_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_suspend(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_restore_noirq_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_restore_noirq(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_clock_ctrl(int en) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = btif_clock_ctrl(p_btif, en); ++ return i_ret; ++} ++ ++int mtk_btif_exp_resume_test(void) ++{ ++ int i_ret = 0; ++ p_mtk_btif p_btif = &g_btif[0]; ++ ++ i_ret = _btif_resume(p_btif); ++ return i_ret; ++} ++ ++int mtk_btif_exp_enter_dpidle_test(void) ++{ ++ return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_ENABLE); ++} ++ ++int mtk_btif_exp_exit_dpidle_test(void) ++{ ++ return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_DISABLE); ++} ++ ++int mtk_btif_exp_log_debug_test(int flag) ++{ ++ int i_ret = 0; ++ ++ i_ret = btif_dbg_ctrl_no_id(flag); ++ return i_ret; ++} ++ ++void mtk_btif_read_cpu_sw_rst_debug_exp(void) ++{ ++ mtk_btif_read_cpu_sw_rst_debug(); ++} ++ ++/************End of Function**********/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h +new file mode 100644 +index 000000000000..97756f684ab4 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_DMA_H_ ++#define __HAL_BTIF_DMA_H_ ++ ++#include ++#include "btif_dma_pub.h" ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(CONFIG_ARCH_MT6580) ++#define MTK_BTIF_APDMA_CLK_CG MT_CG_APDMA_SW_CG ++#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) ++#define MTK_BTIF_APDMA_CLK_CG MT_CG_PERI_APDMA ++#endif ++#else ++extern struct clk *clk_btif_apdma; /*btif apdma clock*/ ++#endif /* !defined(CONFIG_MTK_CLKMGR) */ ++ ++#define TX_DMA_VFF_SIZE (1024 * 8) /*Tx vFIFO Len must be 8 Byte allignment */ ++#define RX_DMA_VFF_SIZE (1024 * 8) /*Rx vFIFO Len must be 8 Byte allignment */ ++ ++#define DMA_TX_THRE(n) (n - 7) /*Tx Trigger Level */ ++#define DMA_RX_THRE(n) ((n) * 3 / 4) /*Rx Trigger Level */ ++ ++/**********************************Hardware related defination**************************/ ++#ifndef CONFIG_OF ++/*DMA channel's offset refer to AP_DMA's base address*/ ++#define BTIF_TX_DMA_OFFSET 0x880 ++#define BTIF_RX_DMA_OFFSET 0x900 ++#endif ++ ++/*Register Address Mapping*/ ++#define DMA_INT_FLAG_OFFSET 0x00 ++#define DMA_INT_EN_OFFSET 0x04 ++#define DMA_EN_OFFSET 0x08 ++#define DMA_RST_OFFSET 0x0C ++#define DMA_STOP_OFFSET 0x10 ++#define DMA_FLUSH_OFFSET 0x14 ++ ++#define DMA_BASE_OFFSET 0x1C ++#define DMA_LEN_OFFSET 0x24 ++ ++#define DMA_THRE_OFFSET 0x28 ++#define DMA_WPT_OFFSET 0x2C ++#define DMA_RPT_OFFSET 0x30 ++#define DMA_VALID_OFFSET 0x3C ++#define DMA_LEFT_OFFSET 0x40 ++#define DMA_VFF_BIT29_OFFSET 0x01 ++ ++#define TX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Tx Virtual FIFO Interrupt Flag Register */ ++#define TX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Tx Virtual FIFO Interrupt Enable Register */ ++#define TX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET)/*BTIF Tx Virtual FIFO Enable Register */ ++#define TX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET)/*BTIF Tx Virtual FIFO Reset Register */ ++#define TX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET)/*BTIF Tx Virtual FIFO STOP Register */ ++#define TX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET)/*BTIF Tx Virtual FIFO Flush Register */ ++#define TX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Tx Virtual FIFO Base Address Register */ ++#define TX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Tx Virtual FIFO Length Register */ ++#define TX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Tx Virtual FIFO Threshold Register */ ++#define TX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Tx Virtual FIFO Write Pointer Register */ ++#define TX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Tx Virtual FIFO Read Pointer Register */ ++#define TX_DMA_W_INT_BUF_SIZE(base) (unsigned long)(base + 0x34) ++/*BTIF Tx Virtual FIFO Internal Tx Write Buffer Size Register */ ++#define TX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) ++/*BTIF Tx Virtual FIFO Internal Tx Buffer Size Register */ ++ ++#define TX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Tx Virtual FIFO Valid Size Register */ ++#define TX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Tx Virtual FIFO Left Size Register */ ++#define TX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Tx Virtual FIFO Debug Status Register */ ++#define TX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Tx Virtual FIFO Base High Address Register */ ++ ++/*Rx Register Address Mapping*/ ++#define RX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Rx Virtual FIFO Interrupt Flag Register */ ++#define RX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Rx Virtual FIFO Interrupt Enable Register */ ++#define RX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET) /*BTIF Rx Virtual FIFO Enable Register */ ++#define RX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET) /*BTIF Rx Virtual FIFO Reset Register */ ++#define RX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET) /*BTIF Rx Virtual FIFO Stop Register */ ++#define RX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET) /*BTIF Rx Virtual FIFO Flush Register */ ++#define RX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Rx Virtual FIFO Base Address Register */ ++#define RX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Rx Virtual FIFO Length Register */ ++#define RX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Rx Virtual FIFO Threshold Register */ ++#define RX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Rx Virtual FIFO Write Pointer Register */ ++#define RX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Rx Virtual FIFO Read Pointer Register */ ++#define RX_DMA_FLOW_CTRL_THRE(base) (unsigned long)(base + 0x34) /*BTIF Rx Virtual FIFO Flow Control Register */ ++#define RX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) /*BTIF Rx Virtual FIFO Internal Buffer Register */ ++#define RX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Rx Virtual FIFO Valid Size Register */ ++#define RX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Rx Virtual FIFO Left Size Register */ ++#define RX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Rx Virtual FIFO Debug Status Register */ ++#define RX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Rx Virtual FIFO Base High Address Register */ ++ ++#define DMA_EN_BIT (0x1) ++#define DMA_STOP_BIT (0x1) ++#define DMA_RST_BIT (0x1) ++#define DMA_FLUSH_BIT (0x1) ++ ++#define DMA_WARM_RST (0x1 << 0) ++#define DMA_HARD_RST (0x1 << 1) ++ ++#define DMA_WPT_MASK (0x0000FFFF) ++#define DMA_WPT_WRAP (0x00010000) ++ ++#define DMA_RPT_MASK (0x0000FFFF) ++#define DMA_RPT_WRAP (0x00010000) ++ ++/*APDMA BTIF Tx Reg Ctrl Bit*/ ++#define TX_DMA_INT_FLAG_MASK (0x1) ++ ++#define TX_DMA_INTEN_BIT (0x1) ++ ++#define TX_DMA_ADDR_MASK (0xFFFFFFF8) ++#define TX_DMA_LEN_MASK (0x0000FFF8) ++ ++#define TX_DMA_THRE_MASK (0x0000FFFF) ++ ++#define TX_DMA_W_INT_BUF_MASK (0x000000FF) ++ ++#define TX_DMA_VFF_VALID_MASK (0x0000FFFF) ++#define TX_DMA_VFF_LEFT_MASK (0x0000FFFF) ++ ++/*APDMA BTIF Rx Reg Ctrl Bit*/ ++#define RX_DMA_INT_THRE (0x1 << 0) ++#define RX_DMA_INT_DONE (0x1 << 1) ++ ++#define RX_DMA_INT_THRE_EN (0x1 << 0) ++#define RX_DMA_INT_DONE_EN (0x1 << 1) ++ ++#define RX_DMA_ADDR_MASK (0xFFFFFFF8) ++#define RX_DMA_LEN_MASK (0x0000FFF8) ++ ++#define RX_DMA_THRE_MASK (0x0000FFFF) ++ ++#define RX_DMA_FLOW_CTRL_THRE_MASK (0x000000FF) ++ ++#define RX_DMA_INT_BUF_SIZE_MASK (0x0000001F) ++ ++#define RX_DMA_VFF_VALID_MASK (0x0000001F) ++ ++#define RX_DMA_VFF_LEFT_MASK (0x0000FFFF) ++ ++typedef struct _MTK_BTIF_DMA_VFIFO_ { ++ DMA_VFIFO vfifo; ++ unsigned int wpt; /*DMA's write pointer, which is maintained by SW for Tx DMA and HW for Rx DMA */ ++ unsigned int last_wpt_wrap; /*last wrap bit for wpt */ ++ unsigned int rpt; /*DMA's read pointer, which is maintained by HW for Tx DMA and SW for Rx DMA */ ++ unsigned int last_rpt_wrap; /*last wrap bit for rpt */ ++} MTK_BTIF_DMA_VFIFO, *P_MTK_BTIF_DMA_VFIFO; ++ ++/*for DMA debug purpose*/ ++typedef struct _MTK_BTIF_DMA_REG_DMP_DBG_ { ++ unsigned long reg_addr; ++ unsigned int reg_val; ++} MTK_BTIF_DMA_REG_DMP_DBG, *P_MTK_BTIF_DMA_REG_DMP_DBG; ++ ++#endif /*__HAL_BTIF_DMA_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h +new file mode 100644 +index 000000000000..0773f2ce387a +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIFD_DMA_PUB_H_ ++#define __HAL_BTIFD_DMA_PUB_H_ ++ ++#include ++ ++#include "plat_common.h" ++ ++typedef enum _ENUM_DMA_CTRL_ { ++ DMA_CTRL_DISABLE = 0, ++ DMA_CTRL_ENABLE = DMA_CTRL_DISABLE + 1, ++ DMA_CTRL_BOTH, ++} ENUM_DMA_CTRL; ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_info_get ++* DESCRIPTION ++* get btif tx dma channel's information ++* PARAMETERS ++* dma_dir [IN] DMA's direction ++* RETURNS ++* pointer to btif dma's information structure ++*****************************************************************************/ ++P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dma_hw_init ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of DMA module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_ctrl ++* DESCRIPTION ++* enable/disable Tx DMA channel ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* ctrl_id [IN] enable/disable ID ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dma_rx_cb_reg ++* DESCRIPTION ++* register rx callback function to dma module ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* rx_cb [IN] function pointer to btif ++* RETURNS ++* 0 means success; negative means fail ++*****************************************************************************/ ++int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, ++ dma_rx_buf_write rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_vfifo_reset ++* DESCRIPTION ++* reset tx virtual fifo information, except memory information ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* dma_dir [IN] DMA's direction ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_tx_dma_irq_handler ++* DESCRIPTION ++* lower level tx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_send_data ++* DESCRIPTION ++* send data through btif in DMA mode ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, ++ const unsigned char *p_buf, const unsigned int buf_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_get_ava_room ++* DESCRIPTION ++* get tx available room ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* available room size ++*****************************************************************************/ ++int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_is_tx_allow ++* DESCRIPTION ++* is tx operation allowed by DMA ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_rx_dma_irq_handler ++* DESCRIPTION ++* lower level rx interrupt handler ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, ++ unsigned char *p_buf, const unsigned int max_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_dma_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_dma_info [IN] pointer to BTIF dma channel's information ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag); ++ ++int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid); ++ ++#endif /*__HAL_BTIFD_DMA_PUB_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h +new file mode 100644 +index 000000000000..51fe58a82b49 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_H_ ++#define __HAL_BTIF_H_ ++ ++#ifndef CONFIG_OF ++#define MTK_BTIF_REG_BASE BTIF_BASE ++#endif ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(CONFIG_ARCH_MT6580) ++#define MTK_BTIF_CG_BIT MT_CG_BTIF_SW_CG ++#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) ++#define MTK_BTIF_CG_BIT MT_CG_PERI_BTIF ++#endif ++#else ++struct clk *clk_btif_apdma; /*btif apdma clock*/ ++struct clk *clk_btif; /*btif clock*/ ++#endif /* !defined(CONFIG_MTK_CLKMGR) */ ++ ++#define BTIF_RBR(base) (unsigned long)(base + 0x0) /*RX Buffer Register: read only */ ++#define BTIF_THR(base) (unsigned long)(base + 0x0) /*Rx Holding Register: write only */ ++#define BTIF_IER(base) (unsigned long)(base + 0x4) /*Interrupt Enable Register: read/write */ ++#define BTIF_IIR(base) (unsigned long)(base + 0x8) /*Interrupt Identification Register: read only */ ++#define BTIF_FIFOCTRL(base) (unsigned long)(base + 0x8) /*FIFO Control Register: write only */ ++#define BTIF_FAKELCR(base) (unsigned long)(base + 0xC) /*FAKE LCR Register: read/write */ ++#define BTIF_LSR(base) (unsigned long)(base + 0x14) /*Line Status Register: read only */ ++#define BTIF_SLEEP_EN(base) (unsigned long)(base + 0x48) /*Sleep Enable Register: read/write */ ++#define BTIF_DMA_EN(base) (unsigned long)(base + 0x4C) /*DMA Enable Register: read/write */ ++#define BTIF_RTOCNT(base) (unsigned long)(base + 0x54) /*Rx Timeout Count Register: read/write */ ++#define BTIF_TRI_LVL(base) (unsigned long)(base + 0x60) /*Tx/Rx Trigger Level Control Register: read/write */ ++#define BTIF_WAK(base) (unsigned long)(base + 0x64) /*BTIF module wakeup Register: write only */ ++#define BTIF_WAT_TIME(base) (unsigned long)(base + 0x68) /*BTIF ASYNC Wait Time Control Register: read/write */ ++#define BTIF_HANDSHAKE(base) (unsigned long)(base + 0x6C) /*BTIF New Handshake Control Register: read/write */ ++ ++/*BTIF_IER bits*/ ++#define BTIF_IER_TXEEN (0x1 << 1) /*1: Tx holding register is empty */ ++#define BTIF_IER_RXFEN (0x1 << 0) /*1: Rx buffer contains data */ ++ ++/*BTIF_IIR bits*/ ++#define BTIF_IIR_NINT (0x1 << 0) /*No INT Pending */ ++#define BTIF_IIR_TX_EMPTY (0x1 << 1) /*Tx Holding Register empty */ ++#define BTIF_IIR_RX (0x1 << 2) /*Rx data received */ ++#define BTIF_IIR_RX_TIMEOUT (0x11 << 2) /*Rx data received */ ++ ++/*BTIF_LSR bits*/ ++#define BTIF_LSR_DR_BIT (0x1 << 0) ++#define BTIF_LSR_THRE_BIT (0x1 << 5) ++#define BTIF_LSR_TEMT_BIT (0x1 << 6) ++ ++/*BTIF_FIFOCTRL bits*/ ++#define BTIF_FIFOCTRL_CLR_TX (0x1 << 2) /*Clear Tx FIRO */ ++#define BTIF_FIFOCTRL_CLR_RX (0x1 << 1) /*Clear Rx FIRO */ ++ ++/*BTIF_FAKELCR bits*/ ++#define BTIF_FAKELCR_NORMAL_MODE 0x0 ++ ++/*BTIF_SLEEP_EN bits*/ ++#define BTIF_SLEEP_EN_BIT (0x1 << 0) /*enable Sleep mode */ ++#define BTIF_SLEEP_DIS_BIT (0x0) /*disable sleep mode */ ++ ++/*BTIF_DMA_EN bits*/ ++#define BTIF_DMA_EN_RX (0x1 << 0) /*Enable Rx DMA */ ++#define BTIF_DMA_EN_TX (0x1 << 1) /*Enable Tx DMA */ ++#define BTIF_DMA_EN_AUTORST_EN (0x1 << 2) /*1: timeout counter will be auto reset */ ++#define BTIF_DMA_EN_AUTORST_DIS (0x0 << 2) /* ++ * 0: after Rx timeout happens, ++ * SW shall reset the interrupt by reading BTIF 0x4C ++ */ ++ ++/*BTIF_TRI_LVL bits*/ ++#define BTIF_TRI_LVL_TX_MASK ((0xf) << 0) ++#define BTIF_TRI_LVL_RX_MASK ((0x7) << 4) ++ ++#define BTIF_TRI_LVL_TX(x) ((x & 0xf) << 0) ++#define BTIF_TRI_LVL_RX(x) ((x & 0x7) << 4) ++ ++#define BTIF_TRI_LOOP_EN (0x1 << 7) ++#define BTIF_TRI_LOOP_DIS (0x0 << 7) ++ ++/*BTIF_WAK bits*/ ++#define BTIF_WAK_BIT (0x1 << 0) ++ ++/*BTIF_HANDSHAKE bits*/ ++#define BTIF_HANDSHAKE_EN_HANDSHAKE 1 ++#define BTIF_HANDSHAKE_DIS_HANDSHAKE 0 ++ ++#define BTIF_TX_FIFO_SIZE 16 ++#define BTIF_RX_FIFO_SIZE 8 ++ ++#define BTIF_TX_FIFO_THRE (BTIF_TX_FIFO_SIZE / 2) ++#define BTIF_RX_FIFO_THRE 0x1 /* 0x5 */ ++ ++#endif /*__HAL_BTIF_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h +new file mode 100644 +index 000000000000..1555d5a50c38 +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_BTIF_PUB_H_ ++#define __HAL_BTIF_PUB_H_ ++ ++#include "plat_common.h" ++ ++/*Enum Defination*/ ++/*BTIF Mode Enum */ ++typedef enum _ENUM_BTIF_MODE_ { ++ BTIF_MODE_PIO = 0, ++ BTIF_MODE_DMA = BTIF_MODE_PIO + 1, ++ BTIF_MODE_MAX, ++} ENUM_BTIF_MODE; ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_info_get ++* DESCRIPTION ++* get btif's information included base address , irq related information ++* PARAMETERS ++* RETURNS ++* BTIF's information ++*****************************************************************************/ ++P_MTK_BTIF_INFO_STR hal_btif_info_get(void); ++ ++#if 0 /*included in hal_btif_info_get */ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_get_irq ++* DESCRIPTION ++* get BTIF module's IRQ information ++* PARAMETERS ++* RETURNS ++* pointer to BTIF's irq structure ++*****************************************************************************/ ++P_MTK_BTIF_IRQ_STR hal_btif_get_irq(void); ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_get_and_prepare ++* DESCRIPTION ++* get clock from device tree and prepare for enable/disable control ++* PARAMETERS ++* pdev device pointer ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_get_and_prepare(struct platform_device *pdev); ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_unprepare ++* DESCRIPTION ++* unprepare btif clock and apdma clock ++* PARAMETERS ++* none ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_unprepare(void); ++#endif ++/***************************************************************************** ++* FUNCTION ++* hal_btif_clk_ctrl ++* DESCRIPTION ++* control clock output enable/disable of BTIF module ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_hw_init ++* DESCRIPTION ++* BTIF module init, after this step, BTIF should enable to do tx/rx with PIO ++* mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_cb_reg ++* DESCRIPTION ++* BTIF rx callback register API ++* PARAMETERS ++* p_btif_info [IN] pointer to BTIF's information ++* rx_cb [IN] rx callback function ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, ++ btif_rx_buf_write rx_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_loopback_ctrl ++* DESCRIPTION ++* BTIF Tx/Rx loopback mode set, this operation can only be done ++* after set BTIF to normal mode ++* PARAMETERS ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_handler ++* DESCRIPTION ++* lower level interrupt handler ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN/OUT] pointer to rx data buffer ++* max_len [IN] max length of rx buffer ++* RETURNS ++* 0 means success; negative means fail; positive means rx data length ++*****************************************************************************/ ++int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, ++ unsigned char *p_buf, const unsigned int max_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_tx_mode_ctrl ++* DESCRIPTION ++* set BTIF tx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_rx_mode_ctrl ++* DESCRIPTION ++* set BTIF rx to corresponding mode (PIO/DMA) ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* mode [IN] rx mode ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_send_data ++* DESCRIPTION ++* send data through btif in FIFO mode ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* p_buf [IN] pointer to rx data buffer ++* max_len [IN] tx buffer length ++* RETURNS ++* positive means number of data sent; ++* 0 means no data put to FIFO; ++* negative means error happens ++*****************************************************************************/ ++int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, ++ const unsigned char *p_buf, const unsigned int buf_len); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_raise_wak_sig ++* DESCRIPTION ++* raise wakeup signal to counterpart ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_dump_reg ++* DESCRIPTION ++* dump BTIF module's information when needed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* flag [IN] register id flag ++* RETURNS ++* 0 means success, negative means fail ++*****************************************************************************/ ++int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_complete ++* DESCRIPTION ++* get tx complete flag ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true means tx complete, false means tx in process ++*****************************************************************************/ ++bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif); ++ ++/***************************************************************************** ++* FUNCTION ++* hal_btif_is_tx_allow ++* DESCRIPTION ++* whether tx is allowed ++* PARAMETERS ++* p_base [IN] BTIF module's base address ++* RETURNS ++* true if tx operation is allowed; false if tx is not allowed ++*****************************************************************************/ ++bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); ++ ++int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif, MTK_BTIF_PM_OPID opid); ++ ++void mtk_btif_read_cpu_sw_rst_debug_plat(void); ++ ++#endif /*__HAL_BTIF_PUB_H_*/ +diff --git a/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h +new file mode 100644 +index 000000000000..2a1462cb32ff +--- /dev/null ++++ b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h +@@ -0,0 +1,307 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __HAL_PUB_H_ ++#define __HAL_PUB_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_OF ++#include ++#include ++#include ++#else ++#include ++#include ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++#include ++#else ++#include ++#include ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++#include ++ ++extern int mtk_btif_hal_get_log_lvl(void); ++ ++#define MTK_BTIF_MARK_UNUSED_API ++ ++typedef irq_handler_t mtk_btif_irq_handler; ++ ++#define MTK_BTIF_ENABLE_CLK_CTL 1 ++#define MTK_BTIF_ENABLE_CLK_REF_COUNTER 1 ++ ++#define DBG_LOG_STR_SIZE 256 ++ ++/*Log defination*/ ++static int hal_log_print(const char *str, ...) ++{ ++ va_list args; ++ char temp_sring[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(temp_sring, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_err("%s", temp_sring); ++ ++ return 0; ++} ++ ++#define BTIF_LOG_LOUD 4 ++#define BTIF_LOG_DBG 3 ++#define BTIF_LOG_INFO 2 ++#define BTIF_LOG_WARN 1 ++#define BTIF_LOG_ERR 0 ++ ++#ifndef DFT_TAG ++#define DFT_TAG "[BTIF-DFT]" ++#endif ++ ++#define BTIF_LOUD_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_LOUD) \ ++ hal_log_print(DFT_TAG "[L]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_INFO_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_INFO)\ ++ hal_log_print(DFT_TAG "[I]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_WARN_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_WARN)\ ++ hal_log_print(DFT_TAG "[W]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_ERR_FUNC(fmt, arg ...)\ ++do {\ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_ERR)\ ++ hal_log_print(DFT_TAG "[E]%s(%d):" fmt,\ ++ __func__, __LINE__, ## arg);\ ++} while (0) ++ ++#define BTIF_DBG_FUNC(fmt, arg ...) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ ++ hal_log_print(DFT_TAG "[D]%s:" fmt, \ ++ __func__, ## arg); \ ++} while (0) ++ ++#define BTIF_TRC_FUNC(f) \ ++do { \ ++ if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ ++ hal_log_print(DFT_TAG "<%s> <%d>\n", \ ++ __func__, __LINE__); \ ++} while (0) ++ ++/*-----------------------------------Enum Defination--------------------------------*/ ++/*IRQ sensetive type */ ++typedef enum _ENUM_IRQ_SENS_TYPE_ { ++ IRQ_SENS_EDGE = 0, ++ IRQ_SENS_LVL = IRQ_SENS_EDGE + 1, ++ IRQ_SENS_TYPE_MAX ++} ENUM_IRQ_SENS_TYPE; ++ ++/*IRQ level trigger type */ ++typedef enum _ENUM_IRQ_LVL_TYPE_ { ++ IRQ_LVL_LOW = 0, ++ IRQ_LVL_HIGH = IRQ_LVL_LOW + 1, ++ IRQ_LVL_MAX ++} ENUM_IRQ_LVL; ++ ++/*IRQ edge trigger type */ ++typedef enum _ENUM_IRQ_EDGE_TYPE_ { ++ IRQ_EDGE_FALL = 0, ++ IRQ_EDGE_RAISE = IRQ_EDGE_FALL + 1, ++ IRQ_EDGE_BOTH = IRQ_EDGE_RAISE + 1, ++ IRQ_EDGE_MAX ++} ENUM_IRQ_EDGE; ++ ++typedef enum _ENUM_CLOCK_CTRL_ { ++ CLK_OUT_DISABLE = 0, ++ CLK_OUT_ENABLE = CLK_OUT_DISABLE + 1, ++ CLK_OUT_MAX ++} ENUM_CLOCK_CTRL; ++ ++/*Error No. table */ ++typedef enum _ENUM_ERROR_CODE_ { ++ ERR_NO_ERROR = 0, ++ ERR_INVALID_PAR = ERR_NO_ERROR - 1, ++ ERR_MAX = ERR_INVALID_PAR - 1, ++} ENUM_ERROR_CODE; ++ ++typedef enum _ENUM_BTIF_DIR_ { ++ BTIF_TX = 0, ++ BTIF_RX = BTIF_TX + 1, ++ BTIF_DIR_MAX, ++} ENUM_BTIF_DIR; ++ ++typedef enum _ENUM_DMA_DIR_ { ++ DMA_DIR_RX = 0, ++ DMA_DIR_TX = DMA_DIR_RX + 1, ++ DMA_DIR_BOTH, ++} ENUM_DMA_DIR; ++ ++typedef enum _ENUM_BTIF_REG_ID_ { ++ REG_IIR = 0, /*Interrupt Identification Register */ ++ REG_LSR = 1, /*Line Status Register */ ++ REG_FAKE_LCR = 2, /*Fake Lcr Regiseter */ ++ REG_FIFO_CTRL = 3, /*FIFO Control Register */ ++ REG_IER = 4, /*Interrupt Enable Register */ ++ REG_SLEEP_EN = 5, /*Sleep Enable Register */ ++ REG_RTO_COUNTER = 6, /*Rx Timeout Counter Register */ ++ REG_DMA_EN = 7, /*DMA Enalbe Register */ ++ REG_TRIG_LVL = 8, /*Tx/Rx Trigger Level Register */ ++ REG_WAT_TIME = 9, /*Async Wait Time Register */ ++ REG_HANDSHAKE = 10, /*New HandShake Mode Register */ ++ REG_SLP_WAK = 11, /*Sleep Wakeup Reigster */ ++ REG_BTIF_ALL = 12, /*all btif controller's registers */ ++ REG_TX_DMA_ALL = 13, ++ REG_RX_DMA_ALL = 14, ++ REG_MAX ++} ENUM_BTIF_REG_ID; ++ ++typedef enum _MTK_BTIF_PM_OPID_ { ++ BTIF_PM_DPIDLE_EN, ++ BTIF_PM_DPIDLE_DIS, ++ BTIF_PM_SUSPEND, ++ BTIF_PM_RESUME, ++ BTIF_PM_RESTORE_NOIRQ, ++} MTK_BTIF_PM_OPID; ++ ++#define BTIF_HAL_TX_FIFO_SIZE (1024 * 4) ++ ++/*-----------------------------------Enum Defination End--------------------------------*/ ++ ++/*****************************structure definition***************************/ ++/*IRQ related information*/ ++typedef struct _MTK_BTIF_IRQ_STR_ { ++ const char *name; ++ bool is_irq_sup; ++ unsigned int irq_id; ++#ifdef CONFIG_OF ++ unsigned int irq_flags; ++#else ++ ENUM_IRQ_SENS_TYPE sens_type; ++ union { ++ ENUM_IRQ_LVL lvl_type; ++ ENUM_IRQ_EDGE edge_type; ++ }; ++#endif ++ bool reg_flag; ++ irq_handler_t p_irq_handler; ++} MTK_BTIF_IRQ_STR, *P_MTK_BTIF_IRQ_STR; ++ ++typedef struct _DMA_VFIFO_ { ++ /*[Driver Access] vFIFO memory'svirtual address */ ++ unsigned char *p_vir_addr; ++ /*[HW Access] dma handle , physically address, set to DMA's HW Register */ ++ dma_addr_t phy_addr; ++ /*DMA's vFIFO size */ ++ unsigned int vfifo_size; ++ /*DMA's threshold value */ ++ unsigned int thre; ++} DMA_VFIFO, *P_DMA_VFIFO; ++ ++typedef unsigned int (*dma_rx_buf_write) (void *p_dma_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++typedef unsigned int (*btif_rx_buf_write) (void *p_btif_info, ++ unsigned char *p_buf, ++ unsigned int buf_len); ++ ++/*DMA related information*/ ++typedef struct _MTK_DMA_INFO_STR_ { ++ unsigned long base; ++ ENUM_DMA_DIR dir; ++ P_MTK_BTIF_IRQ_STR p_irq; ++ dma_rx_buf_write rx_cb; ++ P_DMA_VFIFO p_vfifo; ++} MTK_DMA_INFO_STR, *P_MTK_DMA_INFO_STR; ++ ++/*DMA related information*/ ++typedef struct _MTK_BTIF_INFO_STR_ { ++ unsigned long base; /*base address */ ++ P_MTK_BTIF_IRQ_STR p_irq; /*irq related information */ ++ ++ unsigned int tx_fifo_size; /*BTIF tx FIFO size */ ++ unsigned int rx_fifo_size; /*BTIF rx FIFO size */ ++ ++ unsigned int tx_tri_lvl; /*BTIFtx trigger level in FIFO mode */ ++ unsigned int rx_tri_lvl; /*BTIFrx trigger level in FIFO mode */ ++ ++ unsigned int clk_gat_addr; /*clock gating address */ ++ unsigned int set_bit; /*enable clock gating bit */ ++ unsigned int clr_bit; /*clear clock gating bit */ ++ ++ unsigned int rx_data_len; /*rx data length */ ++ ++ btif_rx_buf_write rx_cb; ++ ++ struct kfifo *p_tx_fifo; /*tx fifo */ ++ spinlock_t tx_fifo_spinlock; /*tx fifo spinlock */ ++} MTK_BTIF_INFO_STR, *P_MTK_BTIF_INFO_STR; ++ ++/**********End of Structure Definition***********/ ++ ++/***********register operation***********/ ++#ifdef __KERNEL__ ++/*byte write <1 byte> */ ++#define btif_reg_sync_writeb(v, a) mt_reg_sync_writeb(v, a) ++/*word write <2 byte> */ ++#define btif_reg_sync_writew(v, a) mt_reg_sync_writew(v, a) ++/*long write <4 byte> */ ++#define btif_reg_sync_writel(v, a) mt_reg_sync_writel(v, a) ++#else ++/*byte write <1 byte> */ ++#define btif_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) ++/*word write <2 byte> */ ++#define btif_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) ++/*long write <4 byte> */ ++#define btif_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) ++#endif ++#define BTIF_READ8(REG) __raw_readb((unsigned char *)(REG)) ++#define BTIF_READ16(REG) __raw_readw((unsigned short *)(REG)) ++#define BTIF_READ32(REG) __raw_readl((unsigned int *)(REG)) ++ ++#define BTIF_SET_BIT(REG, BITVAL) do { \ ++*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL)); \ ++mb(); /**/ \ ++} \ ++while (0) ++#define BTIF_CLR_BIT(REG, BITVAL) do { \ ++(*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL)); \ ++mb(); /**/\ ++} \ ++while (0) ++ ++/***********end of register operation *********/ ++ ++#endif /*__HAL_PUB_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/Kconfig b/drivers/misc/mediatek/connectivity/Kconfig +new file mode 100644 +index 000000000000..4a944b1f0ebe +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/Kconfig +@@ -0,0 +1,299 @@ ++config MTK_COMBO ++ tristate "MediaTek Connectivity Combo Chip Support" ++ help ++ MTK connectivity combo chip driver for MT66xx ++ ++# ++# MTK Combo Chip Selection ++# ++ ++choice ++ prompt "Select Chip" ++ depends on MTK_COMBO ++ ++config MTK_COMBO_CHIP_MT6620 ++ bool "MT6620" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6620 ++ ++config MTK_COMBO_CHIP_MT6628 ++ bool "MT6628" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6628 ++ ++config MTK_COMBO_CHIP_MT6630 ++ bool "MT6630" ++ help ++ this config is used to decided combo chip version ++ in current platform ++ is ++ MT6630 ++ ++config MTK_COMBO_CHIP_CONSYS_6572 ++ bool "CONSYS_6572" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6572 ++ ++config MTK_COMBO_CHIP_CONSYS_6582 ++ bool "CONSYS_6582" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6582 ++ ++config MTK_COMBO_CHIP_CONSYS_8127 ++ bool "CONSYS_8127" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6572 ++ ++config MTK_COMBO_CHIP_CONSYS_7623 ++ bool "CONSYS_7623" ++ #select MTK_PLATFORM::="mt7623" ++ help ++ this config is used to decide SOC consys version ++ in current platform is MT7623 and prepare proper ++ system services like radio power on/off and firmware ++ download for the Bluetotoh and Wifi. ++ ++ ++config MTK_COMBO_CHIP_CONSYS_6752 ++ bool "CONSYS_6752" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6752 ++ ++config MTK_COMBO_CHIP_CONSYS_6592 ++ bool "CONSYS_6592" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6592 ++ ++config MTK_COMBO_CHIP_CONSYS_8163 ++ bool "CONSYS_8163" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT8163 ++ ++config MTK_COMBO_CHIP_CONSYS_6735 ++ bool "CONSYS_6735" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6735 ++ ++config MTK_COMBO_CHIP_CONSYS_6755 ++ bool "CONSYS_6755" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6755 ++ ++config MTK_COMBO_CHIP_CONSYS_6580 ++ bool "CONSYS_6580" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6580 ++ ++config MTK_COMBO_CHIP_CONSYS_6797 ++ bool "CONSYS_6797" ++ help ++ this config is used to decided SOC consys version ++ in current platform ++ is ++ MT6797 ++endchoice ++ ++config MTK_COMBO_CHIP ++ string ++ default "MT6620" if MTK_COMBO_CHIP_MT6620 ++ default "MT6628" if MTK_COMBO_CHIP_MT6628 ++ default "MT6630" if MTK_COMBO_CHIP_MT6630 ++ default "CONSYS_6572" if MTK_COMBO_CHIP_CONSYS_6572 ++ default "CONSYS_6582" if MTK_COMBO_CHIP_CONSYS_6582 ++ default "CONSYS_8127" if MTK_COMBO_CHIP_CONSYS_8127 ++ default "CONSYS_7623" if MTK_COMBO_CHIP_CONSYS_7623 ++ default "CONSYS_6752" if MTK_COMBO_CHIP_CONSYS_6752 ++ default "CONSYS_6755" if MTK_COMBO_CHIP_CONSYS_6755 ++ default "CONSYS_6592" if MTK_COMBO_CHIP_CONSYS_6592 ++ default "CONSYS_8163" if MTK_COMBO_CHIP_CONSYS_8163 ++ default "CONSYS_6735" if MTK_COMBO_CHIP_CONSYS_6735 ++ default "CONSYS_6580" if MTK_COMBO_CHIP_CONSYS_6580 ++ default "CONSYS_6797" if MTK_COMBO_CHIP_CONSYS_6797 ++ help ++ this feature is used to identify combo chip version or SOC chip ++ consys version. ++ ++# ++# Target Platform Selection ++# ++config MTK_COMBO_PLAT_PATH ++ string "Platform folder name" ++ depends on MTK_COMBO ++ default "sample" if MTK_COMBO_PLAT_SAMPLE ++ help ++ Specify platform folder under common driver platform folder: ++ mtk_wcn_combo/common/platform/* ++ ++# ++# MTK COMBO Chip Configuration ++# ++config MTK_COMBO_COMM ++ depends on MTK_COMBO ++ tristate "MediaTek Combo Chip Common part driver" ++ help ++ MediaTek combo chip common part driver ++ ++#config MTK_COMBO_COMM_PS ++# depends on MTK_COMBO_COMM ++# bool "Enable PS support" ++# default n ++# help ++# Enable PS support of common UART interface ++ ++config MTK_COMBO_COMM_UART ++ depends on MTK_COMBO_COMM ++ tristate "Common interface UART" ++ help ++ Use UART for common part interface type ++ ++config MTK_COMBO_COMM_SDIO ++ depends on MTK_COMBO_COMM ++ tristate "Common interface SDIO" ++ help ++ Use SDIO for common part interface type ++ ++config MTK_COMBO_COMM_NPWR ++ depends on MTK_COMBO_COMM ++ bool "Enable NPWR support" ++ default n ++ help ++ Enable NPWR support of new power on swquence ++ ++config MTK_COMBO_COMM_APO ++ depends on MTK_COMBO_COMM ++ bool "Enable always power on support" ++ #default y ++ help ++ Enable chip will always power on ++ ++config MTK_COMBO_BT ++ tristate "MediaTek Combo Chip BT driver" ++ depends on BT && MTK_COMBO ++ select MTK_BTIF ++ help ++ MTK BT /dev/stpbt driver for Bluedroid ++ ++config MTK_COMBO_BT_HCI ++ tristate "MediaTek Combo Chip BlueZ driver" ++ depends on BT && MTK_COMBO ++ select MTK_BTIF ++ help ++ MTK BT driver for BlueZ ++ ++config MTK_COMBO_WIFI ++ tristate "MediaTek combo chip Wi-Fi support" ++ depends on MTK_COMBO ++ select MTK_BTIF ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ ++config MTK_WAPI_SUPPORT ++ bool "MTK_WAPI_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ #default y ++ help ++ if it is set to TRUE: Support WAPI (WLAN Authentication and ++ Privacy Infrastructure) ++ ++config MTK_PASSPOINT_R1_SUPPORT ++ bool "MTK_PASSPOINT_R1_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ help ++ Support Passpoint R1 (Hotspot 2.0 R1) ++ ++config MTK_PASSPOINT_R2_SUPPORT ++ bool "MTK_PASSPOINT_R2_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ help ++ Support Passpoint R2 ++ ++config MTK_WIFI_MCC_SUPPORT ++ bool "MTK_WIFI_MCC_SUPPORT" ++ depends on MTK_COMBO_WIFI ++ #default y ++ help ++ if it is set to TRUE, wlan will support Multi-Channel Concurrency, ++ otherwise, only support Single Channel Concurrency ++ ++config MTK_DHCPV6C_WIFI ++ bool "MTK_DHCPV6C_WIFI" ++ help ++ no: disable this feature ++ ++config MTK_CONN_LTE_IDC_SUPPORT ++ bool "MediaTek CONN LTE IDC support" ++ select MTK_CONN_MD ++ #default y ++ help ++ This option enables CONN LTE IDC support ++ ++menuconfig GPS ++ tristate "GPS drivers" ++ #default y ++ ---help--- ++ Say Y here for supporting GPS. ++ ++if GPS ++config MTK_GPS ++ tristate "MediaTek GPS driver" ++ #default y ++ ---help--- ++ MTK GPS driver ++ To switch gps nmea port driver. ++ Set "yes" to turn on. ++ Set "no" to turn off. ++endif # GPS ++ ++config MTK_GPS_SUPPORT ++ tristate "MediaTek GPS driver" ++ select MTK_GPS ++ help ++ to switch GPS feature on the platform. ++ Set "yes" to turn on and set "no" ++ (with MTK_AGPS_APP=no at the same time) ++ to turn off. ++ ++config MTK_GPS_REGISTER_SETTING ++ tristate "MediaTek GPS Register Setting" ++ depends on MTK_COMBO_GPS ++ help ++ GPS register settings. ++ ++config MTK_GPS_EMI ++ tristate "MediaTek GPS EMI Driver" ++ depends on MTK_COMBO_GPS ++ help ++ GPS EMI driver is for MNL OFFLOAD feature. +diff --git a/drivers/misc/mediatek/connectivity/Makefile b/drivers/misc/mediatek/connectivity/Makefile +new file mode 100644 +index 000000000000..0947788d189a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/Makefile +@@ -0,0 +1,41 @@ ++# ++# Copyright (C) 2015 MediaTek Inc. ++# ++# 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. ++# ++# 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. ++# ++ ++# Connectivity combo driver ++# If KERNELRELEASE is defined, we've been invoked from the ++# kernel build system and can use its language. ++ifneq ($(KERNELRELEASE),) ++subdir-ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE ++ifeq ($(CONFIG_ARM64), y) ++subdir-ccflags-y += -D CONFIG_MTK_WCN_ARM64 ++endif ++ ++ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) ++ subdir-ccflags-y += -D WMT_IDC_SUPPORT=1 ++else ++ subdir-ccflags-y += -D WMT_IDC_SUPPORT=0 ++endif ++ subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++ obj-y += common/ ++ obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/ ++ obj-n := dummy.o ++ ++# Otherwise we were called directly from the command line; ++# invoke the kernel build system. ++else ++ KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ PWD := $(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/Makefile b/drivers/misc/mediatek/connectivity/common/Makefile +new file mode 100644 +index 000000000000..622b74430e13 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/Makefile +@@ -0,0 +1,23 @@ ++subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include ++subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat ++ ++#ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) ++# obj-y += combo/ ++#endif ++#ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) ++# subdir-ccflags-y += -D MT6628 ++# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT ++# obj-y += combo/ ++#endif ++#ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++# subdir-ccflags-y += -D MT6630 ++#ifneq ($(CONFIG_ARCH_MT2601),y) ++# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT ++#endif ++# obj-y += combo/ ++#endif ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ obj-y += conn_soc/ ++endif ++ ++obj-y += common_detect/ +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile +new file mode 100644 +index 000000000000..8d7dc690affd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile +@@ -0,0 +1,47 @@ ++subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/$(ARCH_MTK_PROJECT)/dct/dct ++subdir-ccflags-y += -DWMT_PLAT_ALPS=1 ++ ++COMBO_CHIP_SUPPORT := false ++ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++ COMBO_CHIP_SUPPORT := true ++endif ++ifeq ($(COMBO_CHIP_SUPPORT), true) ++ subdir-ccflags-y += -D MTK_WCN_COMBO_CHIP_SUPPORT ++ ccflags-y += -I$(src)/../combo/linux/include ++endif ++ ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ subdir-ccflags-y += -D MTK_WCN_SOC_CHIP_SUPPORT ++ ccflags-y += -I$(src)/../conn_soc/linux/include ++endif ++ ++ ++ifeq ($(CONFIG_MTK_COMBO),y) ++ ccflags-y += -I$(src)/drv_init/inc ++ obj-y += mtk_wcn_stub_alps.o ++ obj-y += wmt_stp_exp.o ++ obj-y += wmt_gpio.o ++ ++ obj-y += wmt_detect.o ++ obj-y += sdio_detect.o ++ obj-y += wmt_detect_pwr.o ++ ++ obj-y += drv_init/ ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO),m) ++ obj-y += mtk_wcn_stub_alps.o ++ obj-y += wmt_stp_exp.o ++ obj-y += wmt_gpio.o ++ ++ obj-$(CONFIG_MTK_COMBO) += mtk_wmt_detect.o ++ mtk_wmt_detect-objs := wmt_detect.o ++ mtk_wmt_detect-objs += sdio_detect.o ++ mtk_wmt_detect-objs += wmt_detect_pwr.o ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +new file mode 100644 +index 000000000000..bb84384b9a24 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +@@ -0,0 +1,22 @@ ++ifeq ($(CONFIG_MTK_COMBO),y) ++ ccflags-y += -I$(src)/inc/ ++ ccflags-y += -I$(src)/../ ++ ++ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN3 ++endif ++ifneq ($(filter "CONSYS_6797",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN3 ++else ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++ ccflags-y += -D MTK_WCN_WLAN_GEN2 ++endif ++ ++ obj-y += conn_drv_init.o ++ obj-y += common_drv_init.o ++ obj-y += bluetooth_drv_init.o ++ obj-y += gps_drv_init.o ++ obj-y += fm_drv_init.o ++ obj-y += wlan_drv_init.o ++ obj-($(CONFIG_MTK_COMBO_ANT)) += ant_drv_init.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c +new file mode 100644 +index 000000000000..aa453f9397a4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c +@@ -0,0 +1,38 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[ANT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "ant_drv_init.h" ++ ++int do_ant_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++ ++ WMT_DETECT_INFO_FUNC("start to do ANT driver init\n"); ++ switch (chip_id) { ++ case 0x6630: ++ case 0x6797: ++ i_ret = mtk_wcn_stpant_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish ANT driver init, i_ret:%d\n", i_ret); ++ break; ++ default: ++ WMT_DETECT_ERR_FUNC("chipid is not 6630,ANT is not supported!\n"); ++ } ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +new file mode 100644 +index 000000000000..47b055433443 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +@@ -0,0 +1,35 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[BT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "bluetooth_drv_init.h" ++ ++int do_bluetooth_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++ ++#if defined(CONFIG_MTK_COMBO_BT) || defined(CONFIG_MTK_COMBO_BT_HCI) ++ WMT_DETECT_INFO_FUNC("start to do bluetooth driver init\n"); ++ i_ret = mtk_wcn_stpbt_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish bluetooth driver init, i_ret:%d\n", i_ret); ++#else ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_BT is not defined\n"); ++#endif ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c +new file mode 100644 +index 000000000000..f9c332ea266b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c +@@ -0,0 +1,103 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "common_drv_init.h" ++ ++static int do_combo_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ int i_ret_tmp = 0; ++ ++ WMT_DETECT_DBG_FUNC("start to do combo driver init, chipid:0x%08x\n", chip_id); ++ ++ /* HIF-SDIO driver init */ ++ i_ret_tmp = mtk_wcn_hif_sdio_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("HIF-SDIO driver init, i_ret:%d\n", i_ret); ++ ++ /* WMT driver init */ ++ i_ret_tmp = mtk_wcn_combo_common_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); ++ ++ /* STP-UART driver init */ ++ i_ret_tmp = mtk_wcn_stp_uart_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("STP-UART driver init, i_ret:%d\n", i_ret); ++ ++ /* STP-SDIO driver init */ ++ i_ret_tmp = mtk_wcn_stp_sdio_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("STP-SDIO driver init, i_ret:%d\n", i_ret); ++ ++#else ++ i_ret = -1; ++ WMT_DETECT_ERR_FUNC("COMBO chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); ++#endif ++ WMT_DETECT_DBG_FUNC("finish combo driver init\n"); ++ return i_ret; ++} ++ ++static int do_soc_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++ int i_ret_tmp = 0; ++ ++ WMT_DETECT_DBG_FUNC("start to do soc common driver init, chipid:0x%08x\n", chip_id); ++ ++ /* WMT driver init */ ++ i_ret_tmp = mtk_wcn_soc_common_drv_init(); ++ i_ret += i_ret_tmp; ++ WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); ++ ++#else ++ i_ret = -1; ++ WMT_DETECT_ERR_FUNC("SOC chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); ++#endif ++ ++ WMT_DETECT_DBG_FUNC("TBD........\n"); ++ return i_ret; ++} ++ ++int do_common_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++ WMT_DETECT_INFO_FUNC("start to do common driver init, chipid:0x%08x\n", chip_id); ++ ++ switch (chip_id) { ++ case 0x6620: ++ case 0x6628: ++ case 0x6630: ++ i_ret = do_combo_common_drv_init(chip_id); ++ break; ++ default: ++ i_ret = do_soc_common_drv_init(chip_id); ++ break; ++ } ++ ++ WMT_DETECT_INFO_FUNC("finish common driver init\n"); ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c +new file mode 100644 +index 000000000000..8112d2a1d95e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c +@@ -0,0 +1,80 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WCN-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "conn_drv_init.h" ++#include "common_drv_init.h" ++#include "fm_drv_init.h" ++#include "wlan_drv_init.h" ++#include "bluetooth_drv_init.h" ++#include "gps_drv_init.h" ++#include "ant_drv_init.h" ++ ++int __weak do_wlan_drv_init(int chip_id) ++{ ++ WMT_DETECT_ERR_FUNC("Can not find wlan module for chip: %d !\n", chip_id); ++ return 0; ++} ++ ++int __weak do_ant_drv_init(int chip_id) ++{ ++ WMT_DETECT_DBG_FUNC("Chip: %d can not support ANT !\n", chip_id); ++ return 0; ++} ++ ++int do_connectivity_driver_init(int chip_id) ++{ ++ int i_ret = 0; ++ int tmp_ret = 0; ++ ++ tmp_ret = do_common_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) { ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ WMT_DETECT_ERR_FUNC("abort connectivity driver init, because common part is not ready\n"); ++ return i_ret; ++ } ++ ++ tmp_ret = do_bluetooth_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_gps_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_fm_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do fm module init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_wlan_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do wlan module init failed, ret:%d\n", tmp_ret); ++ ++ tmp_ret = do_ant_drv_init(chip_id); ++ i_ret += tmp_ret; ++ if (tmp_ret) ++ WMT_DETECT_ERR_FUNC("do ANT module init failed, ret:%d\n", tmp_ret); ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c +new file mode 100644 +index 000000000000..069c1cf13bba +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c +@@ -0,0 +1,33 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[FM-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "fm_drv_init.h" ++ ++int do_fm_drv_init(int chip_id) ++{ ++ WMT_DETECT_INFO_FUNC("start to do fm module init\n"); ++ ++#ifdef CONFIG_MTK_FMRADIO ++ mtk_wcn_fm_init(); ++#endif ++ ++ WMT_DETECT_INFO_FUNC("finish fm module init\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c +new file mode 100644 +index 000000000000..6da1d70a3ca6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c +@@ -0,0 +1,35 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[GPS-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "gps_drv_init.h" ++ ++int do_gps_drv_init(int chip_id) ++{ ++ int i_ret = -1; ++#ifdef CONFIG_MTK_COMBO_GPS ++ WMT_DETECT_INFO_FUNC("start to do gps driver init\n"); ++ i_ret = mtk_wcn_stpgps_drv_init(); ++ WMT_DETECT_INFO_FUNC("finish gps driver init, i_ret:%d\n", i_ret); ++#else ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_GPS is not defined\n"); ++#endif ++ return i_ret; ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h +new file mode 100644 +index 000000000000..4a436a236290 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _ANT_DRIVER_INIT_H_ ++#define _ANT_DRIVER_INIT_H_ ++ ++extern int do_ant_drv_init(int chip_id); ++extern int mtk_wcn_stpant_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h +new file mode 100644 +index 000000000000..8a847d361fc8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _BLUETOOTH_DRIVER_INIT_H_ ++#define _BLUETOOTH_DRIVER_INIT_H_ ++ ++extern int do_bluetooth_drv_init(int chip_id); ++extern int mtk_wcn_stpbt_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h +new file mode 100644 +index 000000000000..ea01bd633c3c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h +@@ -0,0 +1,31 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _COMMON_DRV_INIT_H_ ++#define _COMMON_DRV_INIT_H_ ++extern int do_common_drv_init(int chip_id); ++ ++/*defined in common part driver*/ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++extern int mtk_wcn_combo_common_drv_init(void); ++extern int mtk_wcn_hif_sdio_drv_init(void); ++extern int mtk_wcn_stp_uart_drv_init(void); ++extern int mtk_wcn_stp_sdio_drv_init(void); ++#endif ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++extern int mtk_wcn_soc_common_drv_init(void); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h +new file mode 100644 +index 000000000000..971193eade9e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h +@@ -0,0 +1,18 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _CONNECTIVITY_DRV_INIT_H_ ++#define _CONNECTIVITY_DRV_INIT_H_ ++extern int do_connectivity_driver_init(int chip_id); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h +new file mode 100644 +index 000000000000..f6ea30addc5d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h +@@ -0,0 +1,20 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _FM_DRV_INIT_H_ ++#define _FM_DRV_INIT_H_ ++extern int do_fm_drv_init(int chip_id); ++extern int mtk_wcn_fm_init(void); ++extern void mtk_wcn_fm_exit(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h +new file mode 100644 +index 000000000000..006ce072c53b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h +@@ -0,0 +1,19 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _GPS_DRIVER_INIT_H_ ++#define _GPS_DRIVER_INIT_H_ ++extern int do_gps_drv_init(int chip_id); ++extern int mtk_wcn_stpgps_drv_init(void); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h +new file mode 100644 +index 000000000000..cb71b50bf950 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h +@@ -0,0 +1,30 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WLAN_DRV_INIT_H_ ++#define _WLAN_DRV_INIT_H_ ++ ++ ++extern int do_wlan_drv_init(int chip_id); ++ ++extern int mtk_wcn_wmt_wifi_init(void); ++ ++#ifdef MTK_WCN_WLAN_GEN2 ++extern int mtk_wcn_wlan_gen2_init(void); ++#endif ++#ifdef MTK_WCN_WLAN_GEN3 ++extern int mtk_wcn_wlan_gen3_init(void); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +new file mode 100644 +index 000000000000..5b0d039a4a42 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WLAN-MOD-INIT]" ++ ++#include "wmt_detect.h" ++#include "wlan_drv_init.h" ++ ++ ++int do_wlan_drv_init(int chip_id) ++{ ++ int i_ret = 0; ++ ++#ifdef CONFIG_MTK_COMBO_WIFI ++ int ret = 0; ++ ++ WMT_DETECT_INFO_FUNC("start to do wlan module init 0x%x\n", chip_id); ++ ++ /* WMT-WIFI char dev init */ ++ ret = mtk_wcn_wmt_wifi_init(); ++ WMT_DETECT_INFO_FUNC("WMT-WIFI char dev init, ret:%d\n", ret); ++ i_ret += ret; ++ ++ switch (chip_id) { ++ case 0x6630: ++ case 0x6797: ++#ifdef MTK_WCN_WLAN_GEN3 ++ /* WLAN driver init */ ++ ret = mtk_wcn_wlan_gen3_init(); ++ WMT_DETECT_INFO_FUNC("WLAN-GEN3 driver init, ret:%d\n", ret); ++ i_ret += ret; ++#else ++ WMT_DETECT_ERR_FUNC("WLAN-GEN3 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); ++ i_ret = -1; ++#endif ++ break; ++ ++ default: ++#ifdef MTK_WCN_WLAN_GEN2 ++ /* WLAN driver init */ ++ ret = mtk_wcn_wlan_gen2_init(); ++ WMT_DETECT_INFO_FUNC("WLAN-GEN2 driver init, ret:%d\n", ret); ++ i_ret += ret; ++#else ++ WMT_DETECT_ERR_FUNC("WLAN-GEN2 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); ++ i_ret = -1; ++#endif ++ break; ++ } ++ ++ WMT_DETECT_INFO_FUNC("finish wlan module init\n"); ++ ++#else ++ ++ WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_WIFI is not defined\n"); ++ ++#endif ++ ++ return i_ret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c +new file mode 100644 +index 000000000000..fa8d437686f2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c +@@ -0,0 +1,605 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CMB_STUB_DBG_LOG 3 ++#define CMB_STUB_INFO_LOG 2 ++#define CMB_STUB_WARN_LOG 1 ++ ++int gCmbStubLogLevel = CMB_STUB_INFO_LOG; ++ ++#define CMB_STUB_LOG_INFO(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_INFO_LOG) \ ++ pr_warn(fmt, ##arg); \ ++} while (0) ++#define CMB_STUB_LOG_WARN(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_WARN_LOG) \ ++ pr_warn(fmt, ##arg); \ ++} while (0) ++#define CMB_STUB_LOG_DBG(fmt, arg...) \ ++do { \ ++ if (gCmbStubLogLevel >= CMB_STUB_DBG_LOG) \ ++ pr_debug(fmt, ##arg); \ ++} while (0) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wmt_detect.h" ++ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 ++#endif ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++struct work_struct *g_sdio_1v_autok_wk = NULL; ++#endif ++int gConnectivityChipId = -1; ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++/* ++* current used uart port name, default is "ttyMT2", ++* will be changed when wmt driver init ++*/ ++char *wmt_uart_port_desc = "ttyMT2"; ++EXPORT_SYMBOL(wmt_uart_port_desc); ++#endif ++ ++static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data); ++static void mtk_wcn_cmb_sdio_enable_eirq(void); ++static void mtk_wcn_cmb_sdio_disable_eirq(void); ++static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data); ++ ++struct sdio_ops mt_sdio_ops[4] = { ++ {NULL, NULL, NULL, NULL}, ++ {NULL, NULL, NULL, NULL}, ++ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, ++ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}, ++ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, ++ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm} ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb; ++static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb; ++static wmt_thermal_query_cb cmb_stub_thermal_ctrl_cb; ++static CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0; ++static wmt_deep_idle_ctrl_cb cmb_stub_deep_idle_ctrl_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++static wmt_get_drv_status cmb_stub_drv_status_ctrl_cb; ++#endif ++static wmt_func_do_reset cmb_stub_do_reset_cb; ++/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X. ++ * This is used for ALPS backward compatible ONLY!!! Remove this table, related ++ * functions, and type definition after modifying other kernel built-in modules, ++ * such as AUDIO. [FixMe][GeorgeKuo] ++ */ ++#if 0 ++static CMB_STUB_AIF_X audio2aif[] = { ++ [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0, ++ [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1, ++ [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2, ++ [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3, ++}; ++#endif ++static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler; ++static atomic_t sdio_claim_irq_enable_flag; ++static atomic_t irq_enable_flag; ++static pm_callback_t mtk_wcn_cmb_sdio_pm_cb; ++static void *mtk_wcn_cmb_sdio_pm_data; ++static void *mtk_wcn_cmb_sdio_eirq_data; ++ ++static u32 wifi_irq = 0xffffffff; ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++static void mtk_wcn_cmb_stub_1v_autok_work(struct work_struct *work) ++{ ++ CMB_STUB_LOG_WARN("++enter++\n"); ++ mtk_wcn_cmb_stub_func_ctrl(11, 1); ++ mtk_wcn_cmb_stub_func_ctrl(11, 0); ++ CMB_STUB_LOG_WARN("--exit--\n"); ++} ++ ++/*! ++ * \brief A function for Getting current driver status:on/off ++ * ++ * \param driver type:0/bt,1/fm,2/gps,3/wifi,11/autok->run wmt turn on/off wifi flow ++ * ++ * \retval 0/off,2/on,-1/null pointer ++ */ ++static int mtk_wcn_cmb_stub_drv_status(unsigned int type) ++{ ++ int ret = -1; ++ ++ if (cmb_stub_drv_status_ctrl_cb) ++ ret = (*cmb_stub_drv_status_ctrl_cb) (type); ++ else ++ CMB_STUB_LOG_WARN("cmb_stub_drv_status_ctrl_cb is NULL\n"); ++ return ret; ++} ++ ++/*! ++ * \brief A 1v AutoK function for kernel DVFS driver calling when screen off ++ * ++ * \param void ++ * ++ * \retval int,mt6630 state:0/off,1/power on,2/func on, -1/null ++ */ ++int mtk_wcn_cmb_stub_1vautok_for_dvfs(void) ++{ ++ int wmt_status; ++ ++ CMB_STUB_LOG_WARN("DVFS driver call sdio 1v autok\n"); ++ ++ wmt_status = mtk_wcn_cmb_stub_drv_status(4); ++ CMB_STUB_LOG_WARN("current mt6630 status is %d\n", wmt_status); ++ if (0 == wmt_status) { ++ if (g_sdio_1v_autok_wk) ++ schedule_work(g_sdio_1v_autok_wk); ++ else ++ CMB_STUB_LOG_WARN("g_sdio_1v_autok_wk is NULL\n"); ++ } else if ((2 == wmt_status) || (1 == wmt_status)) { ++ CMB_STUB_LOG_WARN("mt6630 is on state,skip AUTOK\n"); ++ } else { ++ CMB_STUB_LOG_WARN("mt6630 is unknown state(%d)\n", wmt_status); ++ } ++ ++ return wmt_status; ++ ++} ++#endif ++/*! ++ * \brief A registration function for WMT-PLAT to register itself to CMB-STUB. ++ * ++ * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register ++ * itself and related callback functions when driver being loaded into kernel. ++ * ++ * \param p_stub_cb a pointer carrying CMB_STUB_CB information ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ */ ++int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb) ++{ ++ if ((!p_stub_cb) ++ || (p_stub_cb->size != sizeof(CMB_STUB_CB))) { ++ CMB_STUB_LOG_WARN("[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n", ++ p_stub_cb, (p_stub_cb) ? p_stub_cb->size : 0); ++ return -1; ++ } ++ ++ CMB_STUB_LOG_DBG("[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n", p_stub_cb, p_stub_cb->size); ++ ++ cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb; ++ cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb; ++ cmb_stub_thermal_ctrl_cb = p_stub_cb->thermal_query_cb; ++ cmb_stub_deep_idle_ctrl_cb = p_stub_cb->deep_idle_ctrl_cb; ++ cmb_stub_do_reset_cb = p_stub_cb->wmt_do_reset_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ cmb_stub_drv_status_ctrl_cb = p_stub_cb->get_drv_status_cb; ++ g_sdio_1v_autok_wk = vmalloc(sizeof(struct work_struct)); ++ if (!g_sdio_1v_autok_wk) ++ CMB_STUB_LOG_WARN("vmalloc work_struct(%zd) fail\n", sizeof(struct work_struct)); ++ else ++ INIT_WORK(g_sdio_1v_autok_wk, mtk_wcn_cmb_stub_1v_autok_work); ++ ++#endif ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg); ++/*! ++ * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB. ++ * ++ * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to ++ * unregister itself and clear callback function references. ++ * ++ * \retval 0 operation success ++ */ ++int mtk_wcn_cmb_stub_unreg(void) ++{ ++ cmb_stub_aif_ctrl_cb = NULL; ++ cmb_stub_func_ctrl_cb = NULL; ++ cmb_stub_thermal_ctrl_cb = NULL; ++ cmb_stub_deep_idle_ctrl_cb = NULL; ++ cmb_stub_do_reset_cb = NULL; ++ CMB_STUB_LOG_INFO("[cmb_stub] unregistered\n"); /* KERN_DEBUG */ ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ if (g_sdio_1v_autok_wk) { ++ vfree(g_sdio_1v_autok_wk); ++ g_sdio_1v_autok_wk = NULL; ++ } ++#endif ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg); ++ ++/* stub functions for kernel to control audio path pin mux */ ++int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) ++{ ++ int ret; ++ ++ if ((CMB_STUB_AIF_MAX <= state) ++ || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { ++ ++ CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n", state, ctrl); ++ return -1; ++ } ++ ++ /* avoid the early interrupt before we register the eirq_handler */ ++ if (cmb_stub_aif_ctrl_cb) { ++ ret = (*cmb_stub_aif_ctrl_cb) (state, ctrl); ++ CMB_STUB_LOG_INFO("[cmb_stub] aif_ctrl_cb state(%d->%d) ctrl(%d) ret(%d)\n", ++ cmb_stub_aif_stat, state, ctrl, ret); /* KERN_DEBUG */ ++ ++ cmb_stub_aif_stat = state; ++ } else { ++ CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl_cb null\n"); ++ ret = -2; ++ } ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl); ++ ++/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X ++ * for ALPS backward compatible ONLY!!! Remove this table, related functions, ++ * and type definition after modifying other kernel built-in modules, such as ++ * AUDIO. [FixMe][GeorgeKuo] ++ */ ++ ++void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on) ++{ ++ if (cmb_stub_func_ctrl_cb) ++ (*cmb_stub_func_ctrl_cb) (type, on); ++ else ++ CMB_STUB_LOG_WARN("[cmb_stub] func_ctrl_cb null\n"); ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl); ++ ++int mtk_wcn_cmb_stub_query_ctrl(void) ++{ ++ signed long temp = 0; ++ ++ if (cmb_stub_thermal_ctrl_cb) ++ temp = (*cmb_stub_thermal_ctrl_cb) (); ++ else ++ CMB_STUB_LOG_WARN("[cmb_stub] thermal_ctrl_cb null\n"); ++ ++ return temp; ++} ++ ++/*platform-related APIs*/ ++/* void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); */ ++/* void set_device_working_ability(UINT32 clockId, MT6573_STATE state); */ ++ ++static int _mt_combo_plt_do_deep_idle(COMBO_IF src, int enter) ++{ ++ int ret = -1; ++ ++#if 0 ++ if (src != COMBO_IF_UART && src != COMBO_IF_MSDC && src != COMBO_IF_BTIF) { ++ CMB_STUB_LOG_WARN("src = %d is error\n", src); ++ return ret; ++ } ++ if (src >= 0 && src < COMBO_IF_MAX) ++ CMB_STUB_LOG_INFO("src = %s, to enter deep idle? %d\n", combo_if_name[src], enter); ++#endif ++ /*TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI ++ to decide if the msdc will enter deep idle safely */ ++ ++ switch (src) { ++ case COMBO_IF_UART: ++ if (enter == 0) { ++ /* clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ ++ /* disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++#if 0 ++ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 0); ++ if (ret < 0) ++ CMB_STUB_LOG_WARN("[CMB] %s exit deep idle failed\n", wmt_uart_port_desc); ++#endif ++#endif ++ } else { ++ /* set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ ++ /* enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++#if 0 ++ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 1); ++ if (ret < 0) ++ CMB_STUB_LOG_WARN("[CMB] %s enter deep idle failed\n", wmt_uart_port_desc); ++#endif ++#endif ++ } ++ ret = 0; ++ break; ++ ++ case COMBO_IF_MSDC: ++ if (enter == 0) { ++ /* for common sdio hif */ ++ /* clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ ++ } else { ++ /* for common sdio hif */ ++ /* set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ ++ } ++ ret = 0; ++ break; ++ ++ case COMBO_IF_BTIF: ++ if (cmb_stub_deep_idle_ctrl_cb) ++ ret = (*cmb_stub_deep_idle_ctrl_cb) (enter); ++ else ++ CMB_STUB_LOG_WARN("NULL function pointer\n"); ++ ++ if (ret) ++ CMB_STUB_LOG_WARN("%s deep idle fail(%d)\n", enter == 1 ? "enter" : "exit", ret); ++ else ++ CMB_STUB_LOG_DBG("%s deep idle ok(%d)\n", enter == 1 ? "enter" : "exit", ret); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++int mt_combo_plt_enter_deep_idle(COMBO_IF src) ++{ ++ /* return 0; */ ++ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ ++ return _mt_combo_plt_do_deep_idle(src, 1); ++} ++EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle); ++ ++int mt_combo_plt_exit_deep_idle(COMBO_IF src) ++{ ++ /* return 0; */ ++ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ ++ return _mt_combo_plt_do_deep_idle(src, 0); ++} ++EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle); ++ ++int mtk_wcn_wmt_chipid_query(void) ++{ ++ return gConnectivityChipId; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query); ++ ++void mtk_wcn_wmt_set_chipid(int chipid) ++{ ++ CMB_STUB_LOG_INFO("set current consys chipid (0x%x)\n", chipid); ++ gConnectivityChipId = chipid; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_set_chipid); ++ ++int mtk_wcn_cmb_stub_do_reset(unsigned int type) ++{ ++ if (cmb_stub_do_reset_cb) ++ return (*cmb_stub_do_reset_cb) (type); ++ else ++ return -1; ++} ++EXPORT_SYMBOL(mtk_wcn_cmb_stub_do_reset); ++ ++static void mtk_wcn_cmb_sdio_enable_eirq(void) ++{ ++ if (atomic_read(&irq_enable_flag)) ++ CMB_STUB_LOG_DBG("wifi eint has been enabled\n"); ++ else { ++ atomic_set(&irq_enable_flag, 1); ++ if (wifi_irq != 0xfffffff) { ++ enable_irq(wifi_irq); ++ CMB_STUB_LOG_DBG(" enable WIFI EINT irq %d !!\n", wifi_irq); ++ } ++ } ++} ++ ++static void mtk_wcn_cmb_sdio_disable_eirq(void) ++{ ++ if (!atomic_read(&irq_enable_flag)) ++ CMB_STUB_LOG_DBG("wifi eint has been disabled!\n"); ++ else { ++ if (wifi_irq != 0xfffffff) { ++ disable_irq_nosync(wifi_irq); ++ CMB_STUB_LOG_DBG("disable WIFI EINT irq %d !!\n", wifi_irq); ++ } ++ atomic_set(&irq_enable_flag, 0); ++ } ++} ++ ++irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data) ++{ ++ if ((NULL != mtk_wcn_cmb_sdio_eirq_handler)&&(0 != atomic_read(&sdio_claim_irq_enable_flag))) ++ mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data); ++ return IRQ_HANDLED; ++} ++ ++static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data) ++{ ++ struct device_node *node; ++ int ret = -EINVAL; ++#if 0 ++ unsigned int gpio_wifi_eint_pin; ++#endif ++ ++ CMB_STUB_LOG_INFO("enter %s\n", __func__); ++ mtk_wcn_sdio_irq_flag_set(0); ++ atomic_set(&irq_enable_flag, 0); ++ mtk_wcn_cmb_sdio_eirq_data = data; ++ mtk_wcn_cmb_sdio_eirq_handler = irq_handler; ++ ++ node = (struct device_node *)of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); ++ if (node) { ++#if 0 ++ gpio_wifi_eint_pin = of_get_gpio(node, 5); ++ CMB_STUB_LOG_INFO("WIFI EINT pin %d !!\n", gpio_wifi_eint_pin); ++ wifi_irq = gpio_to_irq(gpio_wifi_eint_pin); ++#else ++ wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */ ++#endif ++#if 1 ++ ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW, ++ "WIFI-eint", NULL); ++ CMB_STUB_LOG_DBG("WIFI EINT irq %d !!\n", wifi_irq); ++#endif ++ ++ if (ret) ++ CMB_STUB_LOG_WARN("WIFI EINT IRQ LINE NOT AVAILABLE!!\n"); ++ else ++ mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/ ++ } else ++ CMB_STUB_LOG_WARN("[%s] can't find connectivity compatible node\n", __func__); ++ ++ CMB_STUB_LOG_INFO("exit %s\n", __func__); ++} ++ ++static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data) ++{ ++ CMB_STUB_LOG_DBG("mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data); ++ /* register pm change callback */ ++ mtk_wcn_cmb_sdio_pm_cb = pm_cb; ++ mtk_wcn_cmb_sdio_pm_data = data; ++} ++ ++static void mtk_wcn_cmb_sdio_on(int sdio_port_num) ++{ ++ pm_message_t state = {.event = PM_EVENT_USER_RESUME }; ++ ++ CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_on (%d)\n", sdio_port_num); ++ ++ /* 1. disable sdio eirq */ ++ mtk_wcn_cmb_sdio_disable_eirq(); ++ ++ /* 2. call sd callback */ ++ if (mtk_wcn_cmb_sdio_pm_cb) { ++ /* pr_warn("mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p)\n", ++ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ ++ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); ++ } else ++ CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_on no sd callback!!\n"); ++} ++ ++static void mtk_wcn_cmb_sdio_off(int sdio_port_num) ++{ ++ pm_message_t state = {.event = PM_EVENT_USER_SUSPEND }; ++ ++ CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_off (%d)\n", sdio_port_num); ++ ++ /* 1. call sd callback */ ++ if (mtk_wcn_cmb_sdio_pm_cb) { ++ /* pr_warn("mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p)\n", ++ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ ++ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); ++ } else ++ CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_off no sd callback!!\n"); ++ ++ /* 2. disable sdio eirq */ ++ mtk_wcn_cmb_sdio_disable_eirq(); ++} ++ ++int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on) ++{ ++ CMB_STUB_LOG_DBG("mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", sdio_port_num, on); ++ if (on) { ++#if 1 ++ CMB_STUB_LOG_DBG("board_sdio_ctrl force off before on\n"); ++ mtk_wcn_cmb_sdio_off(sdio_port_num); ++#else ++ CMB_STUB_LOG_WARN("skip sdio off before on\n"); ++#endif ++ /* off -> on */ ++ mtk_wcn_cmb_sdio_on(sdio_port_num); ++ if (wifi_irq != 0xfffffff) ++ irq_set_irq_wake(wifi_irq, 1); ++ else ++ CMB_STUB_LOG_WARN("wifi_irq is not available\n"); ++ } else { ++ if (wifi_irq != 0xfffffff) ++ irq_set_irq_wake(wifi_irq, 0); ++ else ++ CMB_STUB_LOG_WARN("wifi_irq is not available\n"); ++ /* on -> off */ ++ mtk_wcn_cmb_sdio_off(sdio_port_num); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(board_sdio_ctrl); ++ ++int mtk_wcn_sdio_irq_flag_set(int flag) ++{ ++ if (0 != flag) ++ atomic_set(&sdio_claim_irq_enable_flag, 1); ++ else ++ atomic_set(&sdio_claim_irq_enable_flag, 0); ++ ++ CMB_STUB_LOG_DBG("sdio_claim_irq_enable_flag:%d\n", atomic_read(&sdio_claim_irq_enable_flag)); ++ ++ return atomic_read(&sdio_claim_irq_enable_flag); ++} ++EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set); +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c +new file mode 100644 +index 000000000000..7ac5ac73ef5d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c +@@ -0,0 +1,269 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[SDIO-DETECT]" ++ ++#include "wmt_detect.h" ++ ++#if MTK_HIF_SDIO_AUTOK_ENABLED ++#include ++#endif ++ ++unsigned int gComboChipId = -1; ++struct sdio_func *g_func = NULL; ++ ++MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = { ++ /* MT6620 *//* Not an SDIO standard class device */ ++ {{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620}, /* SDIO1:FUNC1:WIFI */ ++ {{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ {{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ ++ ++ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628}, ++ ++ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630}, ++ ++}; ++ ++/* Supported SDIO device table */ ++static const struct sdio_device_id mtk_sdio_id_tbl[] = { ++ /* MT6618 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */ ++ {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */ ++ {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ ++ ++ /* MT6619 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ ++ /* MT6620 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */ ++ {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */ ++ {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ ++ ++ /* MT5921 *//* Not an SDIO standard class device */ ++ {SDIO_DEVICE(0x037A, 0x5921)}, ++ ++ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {SDIO_DEVICE(0x037A, 0x6628)}, ++ ++ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ ++ {SDIO_DEVICE(0x037A, 0x6630)}, ++ { /* end: all zeroes */ }, ++}; ++ ++static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id); ++ ++static void sdio_detect_remove(struct sdio_func *func); ++ ++static struct sdio_driver mtk_sdio_client_drv = { ++ .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ ++ .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ ++ .probe = sdio_detect_probe, ++ .remove = sdio_detect_remove, ++}; ++ ++static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id); ++ ++int hif_sdio_is_chipid_valid(int chipId) ++{ ++ int index = -1; ++ ++ int left = 0; ++ int middle = 0; ++ int right = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]) - 1; ++ ++ if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId)) ++ return index; ++ ++ middle = (left + right) / 2; ++ ++ while (left <= right) { ++ if (chipId > gChipInfoArray[middle].chipId) { ++ left = middle + 1; ++ } else if (chipId < gChipInfoArray[middle].chipId) { ++ right = middle - 1; ++ } else { ++ index = middle; ++ break; ++ } ++ middle = (left + right) / 2; ++ } ++ ++ if (0 > index) ++ WMT_DETECT_ERR_FUNC("no supported chipid found\n"); ++ else ++ WMT_DETECT_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId); ++ ++ return index; ++} ++ ++int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id) ++{ ++ int maxIndex = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]); ++ int index = 0; ++ struct sdio_device_id *localId = NULL; ++ int chipId = -1; ++ ++ for (index = 0; index < maxIndex; index++) { ++ localId = &(gChipInfoArray[index].deviceId); ++ if ((localId->vendor == id->vendor) && (localId->device == id->device)) { ++ chipId = gChipInfoArray[index].chipId; ++ WMT_DETECT_INFO_FUNC ++ ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index, ++ localId->vendor, localId->device, chipId); ++ gComboChipId = chipId; ++ mtk_wcn_wmt_set_chipid(gComboChipId); ++ break; ++ } ++ } ++ if (0 > chipId) { ++ WMT_DETECT_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, ++ id->device); ++ } ++ ++ return chipId; ++} ++ ++int sdio_detect_query_chipid(int waitFlag) ++{ ++ unsigned int timeSlotMs = 200; ++ unsigned int maxTimeSlot = 15; ++ unsigned int counter = 0; ++ /* gComboChipId = 0x6628; */ ++ if (0 == waitFlag) ++ return gComboChipId; ++ if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) ++ return gComboChipId; ++ ++ while (counter < maxTimeSlot) { ++ if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) ++ break; ++ msleep(timeSlotMs); ++ counter++; ++ } ++ ++ return gComboChipId; ++} ++ ++int sdio_detect_do_autok(int chipId) ++{ ++ int i_ret = 0; ++ ++#if MTK_HIF_SDIO_AUTOK_ENABLED ++#if 0 ++ BOOTMODE boot_mode; ++ ++ boot_mode = get_boot_mode(); ++ ++ if (boot_mode == META_BOOT) { ++ WMT_DETECT_INFO_FUNC("omit autok in meta mode\n"); ++ return 0; ++ } ++#endif ++ if (0x6630 == chipId) { ++#ifdef CONFIG_SDIOAUTOK_SUPPORT ++ if (NULL != g_func) { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready++\n"); ++ i_ret = wait_sdio_autok_ready(g_func->card->host); ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready--\n"); ++ if (0 == i_ret) { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return success\n"); ++ } else { ++ WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return fail, i_ret:%d\n", i_ret); ++ gComboChipId = -1; ++ } ++ } else { ++ WMT_DETECT_INFO_FUNC("g_func NULL, omit autok\n"); ++ } ++#else ++ i_ret = 0; ++ WMT_DETECT_INFO_FUNC("MTK_SDIOAUTOK_SUPPORT not defined\n"); ++#endif ++ } else { ++ WMT_DETECT_INFO_FUNC("MT%x does not support SDIO3.0 autoK is not needed\n", chipId); ++ } ++#else ++ i_ret = 0; ++ WMT_DETECT_INFO_FUNC("MTK_HIF_SDIO_AUTOK_ENABLED is not defined\n"); ++#endif ++ return i_ret; ++} ++ ++/*! ++ * \brief hif_sdio probe function ++ * ++ * hif_sdio probe function called by mmc driver when any matched SDIO function ++ * is detected by it. ++ * ++ * \param func ++ * \param id ++ * ++ * \retval 0 register successfully ++ * \retval < 0 list error code here ++ */ ++static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id) ++{ ++ int chipId = 0; ++ ++ WMT_DETECT_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); ++ chipId = hif_sdio_match_chipid_by_dev_id(id); ++ ++ if ((0x6630 == chipId) && (1 == func->num)) { ++ int ret = 0; ++ ++ g_func = func; ++ WMT_DETECT_INFO_FUNC("autok function detected, func:0x%p\n", g_func); ++ ++ sdio_claim_host(func); ++ ret = sdio_enable_func(func); ++ sdio_release_host(func); ++ if (ret) ++ WMT_DETECT_ERR_FUNC("sdio_enable_func failed!\n"); ++ } ++ ++ return 0; ++} ++ ++static void sdio_detect_remove(struct sdio_func *func) ++{ ++ if (g_func == func) { ++ sdio_claim_host(func); ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ g_func = NULL; ++ } ++ WMT_DETECT_INFO_FUNC("do sdio remove\n"); ++} ++ ++int sdio_detect_init(void) ++{ ++ int ret = -1; ++ /* register to mmc driver */ ++ ret = sdio_register_driver(&mtk_sdio_client_drv); ++ WMT_DETECT_INFO_FUNC("sdio_register_driver() ret=%d\n", ret); ++ return 0; ++} ++ ++int sdio_detect_exit(void) ++{ ++ g_func = NULL; ++ /* register to mmc driver */ ++ sdio_unregister_driver(&mtk_sdio_client_drv); ++ WMT_DETECT_INFO_FUNC("sdio_unregister_driver\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h +new file mode 100644 +index 000000000000..3a0bff9def1b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h +@@ -0,0 +1,43 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _SDIO_DETECT_H_ ++#define _SDIO_DETECT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_SDIOAUTOK_SUPPORT ++#define MTK_HIF_SDIO_AUTOK_ENABLED 1 ++extern int wait_sdio_autok_ready(void *); ++#else ++#define MTK_HIF_SDIO_AUTOK_ENABLED 0 ++#endif ++ ++typedef struct _MTK_WCN_HIF_SDIO_CHIP_INFO_ { ++ struct sdio_device_id deviceId; ++ unsigned int chipId; ++} MTK_WCN_HIF_SDIO_CHIP_INFO, *P_MTK_WCN_HIF_SDIO_CHIP_INFO; ++ ++extern int sdio_detect_exit(void); ++extern int sdio_detect_init(void); ++extern int sdio_detect_query_chipid(int waitFlag); ++extern int hif_sdio_is_chipid_valid(int chipId); ++ ++extern int sdio_detect_do_autok(int chipId); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c +new file mode 100644 +index 000000000000..487852df8f20 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c +@@ -0,0 +1,380 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DETECT]" ++ ++#include "wmt_detect.h" ++#include "wmt_gpio.h" ++ ++#if MTK_WCN_REMOVE_KO ++#include "conn_drv_init.h" ++#endif ++#ifdef CONFIG_COMPAT ++#include ++#endif ++ ++#define WMT_DETECT_MAJOR 154 ++#define WMT_DETECT_DEV_NUM 1 ++#define WMT_DETECT_DRVIER_NAME "mtk_wcn_detect" ++#define WMT_DETECT_DEVICE_NAME "wmtdetect" ++ ++struct class *pDetectClass = NULL; ++struct device *pDetectDev = NULL; ++static int gWmtDetectMajor = WMT_DETECT_MAJOR; ++static struct cdev gWmtDetectCdev; ++unsigned int gWmtDetectDbgLvl = WMT_DETECT_LOG_INFO; ++ ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++inline unsigned int wmt_plat_get_soc_chipid(void) ++{ ++ WMT_DETECT_INFO_FUNC("no soc chip supported, due to MTK_WCN_SOC_CHIP_SUPPORT is not set.\n"); ++ return -1; ++} ++#endif ++ ++static int wmt_detect_open(struct inode *inode, struct file *file) ++{ ++ WMT_DETECT_INFO_FUNC("open major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static int wmt_detect_close(struct inode *inode, struct file *file) ++{ ++ WMT_DETECT_INFO_FUNC("close major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static ssize_t wmt_detect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_DETECT_INFO_FUNC(" ++\n"); ++ WMT_DETECT_INFO_FUNC(" --\n"); ++ ++ return 0; ++} ++ ++ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_DETECT_INFO_FUNC(" ++\n"); ++ WMT_DETECT_INFO_FUNC(" --\n"); ++ ++ return 0; ++} ++ ++static long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int retval = 0; ++ ++ WMT_DETECT_INFO_FUNC("cmd (%d),arg(%ld)\n", cmd, arg); ++ ++ switch (cmd) { ++ case COMBO_IOCTL_GET_CHIP_ID: ++ /*just get chipid from sdio-detect module */ ++ /*check if external combo chip exists or not */ ++ /*if yes, just return combo chip id */ ++ /*if no, get soc chipid */ ++ retval = mtk_wcn_wmt_chipid_query(); ++ break; ++ ++ case COMBO_IOCTL_SET_CHIP_ID: ++ mtk_wcn_wmt_set_chipid(arg); ++ ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_PWR_ON: ++ retval = wmt_detect_ext_chip_pwr_on(); ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_DETECT: ++ retval = wmt_detect_ext_chip_detect(); ++ break; ++ ++ case COMBO_IOCTL_EXT_CHIP_PWR_OFF: ++ retval = wmt_detect_ext_chip_pwr_off(); ++ break; ++ ++ case COMBO_IOCTL_DO_SDIO_AUDOK: ++ retval = sdio_detect_do_autok(arg); ++ break; ++ ++ case COMBO_IOCTL_GET_SOC_CHIP_ID: ++ retval = wmt_plat_get_soc_chipid(); ++ /*get soc chipid by HAL interface */ ++ break; ++ ++ case COMBO_IOCTL_MODULE_CLEANUP: ++#if (MTK_WCN_REMOVE_KO) ++ /*deinit SDIO-DETECT module */ ++ retval = sdio_detect_exit(); ++#else ++ WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); ++#endif ++ break; ++ ++ case COMBO_IOCTL_DO_MODULE_INIT: ++#if (MTK_WCN_REMOVE_KO) ++ /*deinit SDIO-DETECT module */ ++ retval = do_connectivity_driver_init(arg); ++#else ++ WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); ++#endif ++ break; ++ ++ default: ++ WMT_DETECT_WARN_FUNC("unknown cmd (%d)\n", cmd); ++ retval = 0; ++ break; ++ } ++ return retval; ++} ++#ifdef CONFIG_COMPAT ++static long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ ++ WMT_DETECT_INFO_FUNC("cmd (%d)\n", cmd); ++ ret = wmt_detect_unlocked_ioctl(filp, cmd, arg); ++ return ret; ++} ++#endif ++const struct file_operations gWmtDetectFops = { ++ .open = wmt_detect_open, ++ .release = wmt_detect_close, ++ .read = wmt_detect_read, ++ .write = wmt_detect_write, ++ .unlocked_ioctl = wmt_detect_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = WMT_compat_detect_ioctl, ++#endif ++}; ++ ++int wmt_detect_ext_chip_pwr_on(void) ++{ ++ /*pre power on external chip */ ++ /* wmt_plat_pwr_ctrl(FUNC_ON); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ WMT_DETECT_INFO_FUNC("++\n"); ++ if (0 != wmt_detect_chip_pwr_ctrl(1)) ++ return -1; ++ if (0 != wmt_detect_sdio_pwr_ctrl(1)) ++ return -2; ++ return 0; ++#else ++ WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); ++ return -1; ++#endif ++} ++ ++int wmt_detect_ext_chip_pwr_off(void) ++{ ++ /*pre power off external chip */ ++ /* wmt_plat_pwr_ctrl(FUNC_OFF); */ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ WMT_DETECT_INFO_FUNC("--\n"); ++ wmt_detect_sdio_pwr_ctrl(0); ++ return wmt_detect_chip_pwr_ctrl(0); ++#else ++ WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); ++ return 0; ++#endif ++} ++ ++int wmt_detect_ext_chip_detect(void) ++{ ++ int iRet = -1; ++ unsigned int chipId = -1; ++ /*if there is no external combo chip, return -1 */ ++ int bgfEintStatus = -1; ++ ++ WMT_DETECT_INFO_FUNC("++\n"); ++ /*wait for a stable time */ ++ msleep(20); ++ ++ /*read BGF_EINT_PIN status */ ++ bgfEintStatus = wmt_detect_read_ext_cmb_status(); ++ ++ if (0 == bgfEintStatus) { ++ /*external chip does not exist */ ++ WMT_DETECT_INFO_FUNC("external combo chip not detected\n"); ++ } else if (1 == bgfEintStatus) { ++ /*combo chip exists */ ++ WMT_DETECT_INFO_FUNC("external combo chip detected\n"); ++ ++ /*detect chipid by sdio_detect module */ ++ chipId = sdio_detect_query_chipid(1); ++ if (0 <= hif_sdio_is_chipid_valid(chipId)) ++ WMT_DETECT_INFO_FUNC("valid external combo chip id (0x%x)\n", chipId); ++ else ++ WMT_DETECT_INFO_FUNC("invalid external combo chip id (0x%x)\n", chipId); ++ iRet = 0; ++ } else { ++ /*Error exists */ ++ WMT_DETECT_ERR_FUNC("error happens when detecting combo chip\n"); ++ } ++ WMT_DETECT_INFO_FUNC("--\n"); ++ /*return 0 */ ++ return iRet; ++ /*todo: if there is external combo chip, power on chip return 0 */ ++} ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++static int wmt_detect_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ WMT_DETECT_ERR_FUNC("platform name: %s\n", pdev->name); ++ ret = wmt_gpio_init(pdev); ++ if (-1 == ret) ++ WMT_DETECT_ERR_FUNC("gpio init fail ret:%d\n", ret); ++ return ret; ++} ++ ++static int wmt_detect_remove(struct platform_device *pdev) ++{ ++ wmt_gpio_deinit(); ++ return 0; ++} ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++static struct of_device_id wmt_detect_match[] = { ++ { .compatible = "mediatek,connectivity-combo", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, wmt_detect_match); ++ ++static struct platform_driver wmt_detect_driver = { ++ .probe = wmt_detect_probe, ++ .remove = wmt_detect_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "mediatek,connectivity-combo", ++ .of_match_table = wmt_detect_match, ++ }, ++}; ++#endif ++ ++/*module_platform_driver(wmt_detect_driver);*/ ++static int wmt_detect_driver_init(void) ++{ ++ dev_t devID = MKDEV(gWmtDetectMajor, 0); ++ int cdevErr = -1; ++ int ret = -1; ++ ++ ret = register_chrdev_region(devID, WMT_DETECT_DEV_NUM, WMT_DETECT_DRVIER_NAME); ++ if (ret) { ++ WMT_DETECT_ERR_FUNC("fail to register chrdev\n"); ++ return ret; ++ } ++ ++ cdev_init(&gWmtDetectCdev, &gWmtDetectFops); ++ gWmtDetectCdev.owner = THIS_MODULE; ++ ++ cdevErr = cdev_add(&gWmtDetectCdev, devID, WMT_DETECT_DEV_NUM); ++ if (cdevErr) { ++ WMT_DETECT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); ++ goto err1; ++ } ++ ++ pDetectClass = class_create(THIS_MODULE, WMT_DETECT_DEVICE_NAME); ++ if (IS_ERR(pDetectClass)) { ++ WMT_DETECT_ERR_FUNC("class create fail, error code(%ld)\n", PTR_ERR(pDetectClass)); ++ goto err1; ++ } ++ ++ pDetectDev = device_create(pDetectClass, NULL, devID, NULL, WMT_DETECT_DEVICE_NAME); ++ if (IS_ERR(pDetectDev)) { ++ WMT_DETECT_ERR_FUNC("device create fail, error code(%ld)\n", PTR_ERR(pDetectDev)); ++ goto err2; ++ } ++ ++ WMT_DETECT_INFO_FUNC("driver(major %d) installed success\n", gWmtDetectMajor); ++ ++ /*init SDIO-DETECT module */ ++ sdio_detect_init(); ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ ret = platform_driver_register(&wmt_detect_driver); ++ if (ret) ++ WMT_DETECT_ERR_FUNC("platform driver register fail ret:%d\n", ret); ++#endif ++ ++ return 0; ++ ++err2: ++ ++ if (pDetectClass) { ++ class_destroy(pDetectClass); ++ pDetectClass = NULL; ++ } ++ ++err1: ++ ++ if (cdevErr == 0) ++ cdev_del(&gWmtDetectCdev); ++ ++ if (ret == 0) { ++ unregister_chrdev_region(devID, WMT_DETECT_DEV_NUM); ++ gWmtDetectMajor = -1; ++ } ++ ++ WMT_DETECT_ERR_FUNC("fail\n"); ++ ++ return -1; ++} ++ ++static void wmt_detect_driver_exit(void) ++{ ++ dev_t dev = MKDEV(gWmtDetectMajor, 0); ++ ++ if (pDetectDev) { ++ device_destroy(pDetectClass, dev); ++ pDetectDev = NULL; ++ } ++ ++ if (pDetectClass) { ++ class_destroy(pDetectClass); ++ pDetectClass = NULL; ++ } ++ ++ cdev_del(&gWmtDetectCdev); ++ unregister_chrdev_region(dev, WMT_DETECT_DEV_NUM); ++ ++#if !(MTK_WCN_REMOVE_KO) ++/*deinit SDIO-DETECT module*/ ++ sdio_detect_exit(); ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ platform_driver_unregister(&wmt_detect_driver); ++#endif ++ ++ WMT_DETECT_INFO_FUNC("done\n"); ++} ++ ++module_init(wmt_detect_driver_init); ++module_exit(wmt_detect_driver_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Zhiguo.Niu & Chaozhong.Liang @ MBJ/WCNSE/SS1"); ++ ++module_param(gWmtDetectMajor, uint, 0); +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h +new file mode 100644 +index 000000000000..7e152bfd39ec +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h +@@ -0,0 +1,114 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_DETECT_H_ ++#define _WMT_DETECT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++#define MTK_WCN_REMOVE_KO 1 ++#else ++#define MTK_WCN_REMOVE_KO 0 ++#endif ++ ++#include "sdio_detect.h" ++#include "wmt_detect_pwr.h" ++#include ++ ++#define WMT_DETECT_LOG_LOUD 4 ++#define WMT_DETECT_LOG_DBG 3 ++#define WMT_DETECT_LOG_INFO 2 ++#define WMT_DETECT_LOG_WARN 1 ++#define WMT_DETECT_LOG_ERR 0 ++ ++extern unsigned int gWmtDetectDbgLvl; ++ ++#define WMT_DETECT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_LOUD) \ ++ pr_debug(DFT_TAG"[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_DBG) \ ++ pr_debug(DFT_TAG"[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_INFO) \ ++ pr_err(DFT_TAG"[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_DETECT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_WARN) \ ++ pr_warn(DFT_TAG"[W]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_DETECT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_ERR) \ ++ pr_err(DFT_TAG"[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++ ++#define WMT_IOC_MAGIC 'w' ++#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_IOC_MAGIC, 0, int) ++#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_IOC_MAGIC, 1, int) ++#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_IOC_MAGIC, 2, int) ++#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_IOC_MAGIC, 3, int) ++#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_IOC_MAGIC, 4, int) ++#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_IOC_MAGIC, 5, int) ++#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_IOC_MAGIC, 6, int) ++#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_IOC_MAGIC, 7, int) ++#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_IOC_MAGIC, 8, int) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++********************************************************************************/ ++extern int wmt_detect_ext_chip_detect(void); ++extern int wmt_detect_ext_chip_pwr_on(void); ++extern int wmt_detect_ext_chip_pwr_off(void); ++ ++#ifdef MTK_WCN_SOC_CHIP_SUPPORT ++extern unsigned int wmt_plat_get_soc_chipid(void); ++#endif ++ ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver ++ * ++ * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" ++ * @ enable - "1", enable deep idle; "0", disable deep idle ++ * ++ * Return 0 if success, else -1 ++ */ ++extern unsigned int mtk_uart_pdn_enable(char *port, int enable); ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c +new file mode 100644 +index 000000000000..1dcb7ed358bc +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c +@@ -0,0 +1,232 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DETECT]" ++ ++#include "wmt_detect.h" ++#include "wmt_gpio.h" ++ ++#define INVALID_PIN_ID (0xFFFFFFFF) ++ ++/*copied form WMT module*/ ++static int wmt_detect_dump_pin_conf(void) ++{ ++ WMT_DETECT_DBG_FUNC("[WMT-DETECT]=>dump wmt pin configuration start<=\n"); ++ ++ WMT_DETECT_INFO_FUNC("LDO(GPIO%d), PMU(GPIO%d), PMUV28(GPIO%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num); ++ ++ WMT_DETECT_INFO_FUNC("RST(GPIO%d), BGF_EINT(GPIO%d), BGF_EINT_NUM(%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num, ++ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num)); ++ ++ WMT_DETECT_INFO_FUNC("WIFI_EINT(GPIO%d), WIFI_EINT_NUM(%d)\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num, ++ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)); ++ ++ WMT_DETECT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration ends<=\n"); ++ ++ return 0; ++} ++ ++int _wmt_detect_output_low(unsigned int id) ++{ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 0); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); ++ } ++ ++ return 0; ++} ++ ++int _wmt_detect_output_high(unsigned int id) ++{ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 1); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); ++ } ++ ++ return 0; ++} ++ ++int _wmt_detect_read_gpio_input(unsigned int id) ++{ ++ int retval = 0; ++ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { ++ retval = gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num); ++ WMT_DETECT_DBG_FUNC("WMT-DETECT: get GPIO%d val%d\n", ++ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, retval); ++ } ++ ++ return retval; ++} ++ ++/*This power on sequence must support all combo chip's basic power on sequence ++ * 1. LDO control is a must, if external LDO exist ++ * 2. PMU control is a must ++ * 3. RST control is a must ++ * 4. WIFI_EINT pin control is a must, used for GPIO mode for EINT status checkup ++ * 5. RTC32k clock control is a must ++ * */ ++static int wmt_detect_chip_pwr_on(void) ++{ ++ int retval = -1; ++ /*setting validiation check*/ ++ if ((INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) || ++ (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) || ++ (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)) { ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: either PMU(%d) or RST(%d) or WIFI_EINT(%d) is not set\n", ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num); ++ ++ return retval; ++ } ++ /*set LDO/PMU/RST to output 0, no pull*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]); ++ WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); ++ WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ _wmt_detect_output_low(GPIO_COMBO_RST_PIN); ++ ++#if 0 ++ _wmt_detect_output_high(GPIO_WIFI_EINT_PIN); ++#endif ++ ++ /*pull high LDO*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_high(GPIO_COMBO_LDO_EN_PIN); ++ /*sleep for LDO stable time*/ ++ msleep(MAX_LDO_STABLE_TIME); ++ ++ /*export RTC clock, sleep for RTC stable time*/ ++ rtc_gpio_enable_32k(RTC_GPIO_USER_GPS); ++ msleep(MAX_RTC_STABLE_TIME); ++ /*PMU output low, RST output low, to make chip power off completely*/ ++ /*always done*/ ++ /*sleep for power off stable time*/ ++ msleep(MAX_OFF_STABLE_TIME); ++ /*PMU output high, and sleep for reset stable time*/ ++ _wmt_detect_output_high(GPIO_COMBO_PMU_EN_PIN); ++#ifdef CONFIG_MTK_COMBO_COMM_NPWR ++ if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != INVALID_PIN_ID) && ++ (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != INVALID_PIN_ID)) { ++ msleep(20); ++ _wmt_detect_output_high(GPIO_PCM_DAISYNC_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_high(GPIO_COMBO_I2S_DAT_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_low(GPIO_COMBO_I2S_DAT_PIN); ++ ++ msleep(20); ++ _wmt_detect_output_low(GPIO_PCM_DAISYNC_PIN); ++ ++ msleep(20); ++ } ++#endif ++ msleep(MAX_RST_STABLE_TIME); ++ /*RST output high, and sleep for power on stable time */ ++ _wmt_detect_output_high(GPIO_COMBO_RST_PIN); ++ msleep(MAX_ON_STABLE_TIME); ++ ++ retval = 0; ++ return retval; ++} ++ ++static int wmt_detect_chip_pwr_off(void) ++{ ++ ++ /*set RST pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); ++ /*set RST pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_RST_PIN); ++ /*set PMU pin to input low status*/ ++ if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) ++ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); ++ return 0; ++} ++ ++int wmt_detect_read_ext_cmb_status(void) ++{ ++ int retval = 0; ++ /*read WIFI_EINT pin status*/ ++ if (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num) { ++ retval = 0; ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: no WIFI_EINT pin set\n"); ++ } else { ++ retval = _wmt_detect_read_gpio_input(GPIO_WIFI_EINT_PIN); ++ WMT_DETECT_ERR_FUNC("WMT-DETECT: WIFI_EINT input status:%d\n", retval); ++ } ++ return retval; ++} ++ ++int wmt_detect_chip_pwr_ctrl(int on) ++{ ++ int retval = -1; ++ ++ if (0 == on) { ++ /*power off combo chip */ ++ retval = wmt_detect_chip_pwr_off(); ++ } else { ++ wmt_detect_dump_pin_conf(); ++ /*power on combo chip */ ++ retval = wmt_detect_chip_pwr_on(); ++ } ++ return retval; ++} ++ ++int wmt_detect_sdio_pwr_ctrl(int on) ++{ ++ int retval = -1; ++#ifdef MTK_WCN_COMBO_CHIP_SUPPORT ++ if (0 == on) { ++ /*power off SDIO slot */ ++ retval = board_sdio_ctrl(1, 0); ++ } else { ++ /*power on SDIO slot */ ++ retval = board_sdio_ctrl(1, 1); ++ } ++#else ++ WMT_DETECT_WARN_FUNC("WMT-DETECT: MTK_WCN_COMBO_CHIP_SUPPORT is not set\n"); ++#endif ++ return retval; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h +new file mode 100644 +index 000000000000..32e661520fd0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h +@@ -0,0 +1,29 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef __WMT_DETECT_PWR_H_ ++#define __WMT_DETECT_PWR_H_ ++ ++#define MAX_RTC_STABLE_TIME 100 ++#define MAX_LDO_STABLE_TIME 100 ++#define MAX_RST_STABLE_TIME 30 ++#define MAX_OFF_STABLE_TIME 10 ++#define MAX_ON_STABLE_TIME 30 ++ ++extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); ++extern int wmt_detect_chip_pwr_ctrl(int on); ++extern int wmt_detect_sdio_pwr_ctrl(int on); ++extern int wmt_detect_read_ext_cmb_status(void); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c +new file mode 100644 +index 000000000000..3a79e1e9d15a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c +@@ -0,0 +1,371 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "wmt_gpio.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX] = {{"gpio_ldo_en_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_ldo_en_in_pulldown", ++ ""}, ++ {"gpio_pmuv28_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_pmuv28_in_pulldown", ++ ""}, ++ {"gpio_pmu_en_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_pmu_en_in_pulldown", ++ ""}, ++ {"gpio_rst_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_bgf_eint_in_pulldown", ++ "gpio_bgf_eint_in_pullup"}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_wifi_eint_in_pull_dis", ++ "", ++ "gpio_wifi_eint_in_pullup"}, ++ {"", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_all_eint_in_pulldown", ++ "gpio_all_eint_in_pullup"}, ++ {"gpio_urxd_uart_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "gpio_urxd_gpio_in_pull_dis", ++ "", ++ "gpio_urxd_gpio_in_pullup"}, ++ {"gpio_utxd_uart_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daiclk_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daipcmin_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daipcmout_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_pcm_daisync_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_ck_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_ws_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_i2s_dat_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_gps_sync_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""}, ++ {"gpio_gps_lna_pull_dis", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ ""} ++}; ++ ++const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX] = {"gpio_combo_ldo_en_pin", ++ "gpio_combo_pmuv28_en_pin", ++ "gpio_combo_pmu_en_pin", ++ "gpio_combo_rst_pin", ++ "gpio_combo_bgf_eint_pin", ++ "gpio_wifi_eint_pin", ++ "gpio_all_eint_pin", ++ "gpio_combo_urxd_pin", ++ "gpio_combo_utxd_pin", ++ "gpio_pcm_daiclk_pin", ++ "gpio_pcm_daipcmin_pin", ++ "gpio_pcm_daipcmout_pin", ++ "gpio_pcm_daisync_pin", ++ "gpio_combo_i2s_ck_pin", ++ "gpio_combo_i2s_ws_pin", ++ "gpio_combo_i2s_dat_pin", ++ "gpio_gps_sync_pin", ++ "gpio_gps_lna_pin"}; ++ ++GPIO_CTRL_INFO gpio_ctrl_info; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_gpio_init(struct platform_device *pdev) ++{ ++ INT32 iret = 0; ++ UINT32 i, j; ++ struct device_node *node; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); ++ if (!node) { ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ pr_err("wmt_gpio:can't find device tree node!\n"); ++ iret = -1; ++ goto err; ++ } ++ ++ gpio_ctrl_info.pinctrl_info = devm_pinctrl_get(&pdev->dev); ++ if (gpio_ctrl_info.pinctrl_info) { ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = of_get_named_gpio(node, ++ gpio_pin_name[i], 0); ++ if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num < 0) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { ++ for (j = 0; j < GPIO_STATE_MAX; j++) { ++ if (0 != strlen(gpio_state_name[i][j])) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = ++ pinctrl_lookup_state(gpio_ctrl_info.pinctrl_info, ++ gpio_state_name[i][j]); ++ } else ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; ++ } ++ } ++ } ++ ++ pr_err("wmt_gpio: gpio init start!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, ++ 0); ++ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN out to 0: %d!\n", ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); ++ } ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) { ++ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, ++ 0); ++ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN out to 0: %d!\n", ++ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); ++ } ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); ++ pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]) { ++ pinctrl_select_state(gpio_ctrl_info.pinctrl_info, ++ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN]. ++ gpio_state[GPIO_PULL_DIS]); ++ pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS done!\n"); ++ } else ++ pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS fail, is NULL!\n"); ++ ++ pr_err("wmt_gpio: gpio init done!\n"); ++ } else { ++ pr_err("wmt_gpio:can't find pinctrl dev!\n"); ++ iret = -1; ++ } ++err: ++ return iret; ++} ++ ++INT32 wmt_gpio_deinit(VOID) ++{ ++ INT32 iret = 0; ++ UINT32 i; ++ UINT32 j; ++ ++ for (i = 0; i < GPIO_PIN_ID_MAX; i++) { ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; ++ if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { ++ for (j = 0; j < GPIO_STATE_MAX; j++) { ++ if (0 != strlen(gpio_state_name[i][j])) ++ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; ++ } ++ } ++ } ++ if (gpio_ctrl_info.pinctrl_info) { ++ devm_pinctrl_put(gpio_ctrl_info.pinctrl_info); ++ gpio_ctrl_info.pinctrl_info = NULL; ++ } ++ ++ return iret; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h +new file mode 100644 +index 000000000000..cd935bfddd99 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h +@@ -0,0 +1,103 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_GPIO_H_ ++#define _WMT_GPIO_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "osal.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define DEFAULT_PIN_ID (0xffffffff) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_GPIO_PIN_ID { ++ GPIO_COMBO_LDO_EN_PIN = 0, ++ GPIO_COMBO_PMUV28_EN_PIN, ++ GPIO_COMBO_PMU_EN_PIN, ++ GPIO_COMBO_RST_PIN, ++ GPIO_COMBO_BGF_EINT_PIN, ++ GPIO_WIFI_EINT_PIN, ++ GPIO_COMBO_ALL_EINT_PIN, ++ GPIO_COMBO_URXD_PIN, ++ GPIO_COMBO_UTXD_PIN, ++ GPIO_PCM_DAICLK_PIN, ++ GPIO_PCM_DAIPCMIN_PIN, ++ GPIO_PCM_DAIPCMOUT_PIN, ++ GPIO_PCM_DAISYNC_PIN, ++ GPIO_COMBO_I2S_CK_PIN, ++ GPIO_COMBO_I2S_WS_PIN, ++ GPIO_COMBO_I2S_DAT_PIN, ++ GPIO_GPS_SYNC_PIN, ++ GPIO_GPS_LNA_PIN, ++ GPIO_PIN_ID_MAX ++} ENUM_GPIO_PIN_ID, *P_ENUM_GPIO_PIN_ID; ++ ++typedef enum _ENUM_GPIO_STATE_ID { ++ GPIO_PULL_DIS = 0, ++ GPIO_PULL_DOWN, ++ GPIO_PULL_UP, ++ GPIO_OUT_LOW, ++ GPIO_OUT_HIGH, ++ GPIO_IN_DIS, ++ GPIO_IN_EN, ++ GPIO_IN_PULL_DIS, ++ GPIO_IN_PULLDOWN, ++ GPIO_IN_PULLUP, ++ GPIO_STATE_MAX, ++} ENUM_GPIO_STATE_ID, *P_ENUM_GPIO_STATE_ID; ++ ++typedef struct _GPIO_CTRL_STATE { ++ INT32 gpio_num; ++ struct pinctrl_state *gpio_state[GPIO_STATE_MAX]; ++} GPIO_CTRL_STATE, *P_GPIO_CTRL_STATE; ++ ++typedef struct _GPIO_CTRL_INFO { ++ struct pinctrl *pinctrl_info; ++ GPIO_CTRL_STATE gpio_ctrl_state[GPIO_PIN_ID_MAX]; ++} GPIO_CTRL_INFO, *P_GPIO_CTRL_INFO; ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX]; ++extern const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX]; ++extern GPIO_CTRL_INFO gpio_ctrl_info; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_gpio_init(struct platform_device *pdev); ++ ++INT32 wmt_gpio_deinit(VOID); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c +new file mode 100644 +index 000000000000..4fc3144b3ba6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c +@@ -0,0 +1,480 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include "osal_typedef.h" ++#include "wmt_stp_exp.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-STP-EXP]" ++ ++#define WMT_STP_EXP_INFO_FUNC(fmt, arg...) pr_debug(DFT_TAG "[I]%s: " fmt, __func__ , ##arg) ++#define WMT_STP_EXP_WARN_FUNC(fmt, arg...) pr_warn(DFT_TAG "[W]%s: " fmt, __func__ , ##arg) ++#define WMT_STP_EXP_ERR_FUNC(fmt, arg...) pr_err(DFT_TAG "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++/*STP exp*/ ++MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_f = NULL; ++MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_raw_f = NULL; ++MTK_WCN_STP_PARSER_DATA mtk_wcn_stp_parser_data_f = NULL; ++MTK_WCN_STP_RECV_DATA mtk_wcn_stp_receive_data_f = NULL; ++MTK_WCN_STP_IS_RXQ_EMPTY mtk_wcn_stp_is_rxqueue_empty_f = NULL; ++MTK_WCN_STP_IS_RDY mtk_wcn_stp_is_ready_f = NULL; ++MTK_WCN_STP_SET_BLUEZ mtk_wcn_stp_set_bluez_f = NULL; ++MTK_WCN_STP_REG_IF_TX mtk_wcn_stp_if_tx_f = NULL; ++MTK_WCN_STP_REG_IF_RX mtk_wcn_stp_if_rx_f = NULL; ++MTK_WCN_STP_REG_EVENT_CB mtk_wcn_stp_reg_event_cb_f = NULL; ++MTK_WCN_STP_RGE_TX_EVENT_CB mtk_wcn_stp_reg_tx_event_cb_f = NULL; ++MTK_WCN_STP_COREDUMP_START_GET mtk_wcn_stp_coredump_start_get_f = NULL; ++ ++/*WMT exp*/ ++MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_on_f = NULL; ++MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_off_f = NULL; ++MTK_WCN_WMT_THERM_CTRL mtk_wcn_wmt_therm_ctrl_f = NULL; ++MTK_WCN_WMT_HWVER_GET mtk_wcn_wmt_hwver_get_f = NULL; ++MTK_WCN_WMT_DSNS_CTRL mtk_wcn_wmt_dsns_ctrl_f = NULL; ++MTK_WCN_WMT_MSGCB_REG mtk_wcn_wmt_msgcb_reg_f = NULL; ++MTK_WCN_WMT_MSGCB_UNREG mtk_wcn_wmt_msgcb_unreg_f = NULL; ++MTK_WCN_WMT_SDIO_OP_REG mtk_wcn_wmt_sdio_op_reg_f = NULL; ++MTK_WCN_WMT_SDIO_HOST_AWAKE mtk_wcn_wmt_sdio_host_awake_f = NULL; ++MTK_WCN_WMT_ASSERT mtk_wcn_wmt_assert_f = NULL; ++MTK_WCN_WMT_ASSERT_TIMEOUT mtk_wcn_wmt_assert_timeout_f = NULL; ++MTK_WCN_WMT_IC_INFO_GET mtk_wcn_wmt_ic_info_get_f = NULL; ++MTK_WCN_WMT_PSM_CTRL mtk_wcn_wmt_psm_ctrl_f = NULL; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb) ++{ ++ WMT_STP_EXP_INFO_FUNC("call stp exp cb reg\n"); ++ ++ mtk_wcn_stp_send_data_f = pStpExpCb->stp_send_data_cb; ++ mtk_wcn_stp_send_data_raw_f = pStpExpCb->stp_send_data_raw_cb; ++ mtk_wcn_stp_parser_data_f = pStpExpCb->stp_parser_data_cb; ++ mtk_wcn_stp_receive_data_f = pStpExpCb->stp_receive_data_cb; ++ mtk_wcn_stp_is_rxqueue_empty_f = pStpExpCb->stp_is_rxqueue_empty_cb; ++ mtk_wcn_stp_is_ready_f = pStpExpCb->stp_is_ready_cb; ++ mtk_wcn_stp_set_bluez_f = pStpExpCb->stp_set_bluez_cb; ++ mtk_wcn_stp_if_tx_f = pStpExpCb->stp_if_tx_cb; ++ mtk_wcn_stp_if_rx_f = pStpExpCb->stp_if_rx_cb; ++ mtk_wcn_stp_reg_event_cb_f = pStpExpCb->stp_reg_event_cb; ++ mtk_wcn_stp_reg_tx_event_cb_f = pStpExpCb->stp_reg_tx_event_cb; ++ mtk_wcn_stp_coredump_start_get_f = pStpExpCb->stp_coredump_start_get_cb; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_reg); ++ ++UINT32 mtk_wcn_stp_exp_cb_unreg(VOID) ++{ ++ WMT_STP_EXP_INFO_FUNC("call stp exp cb unreg\n"); ++ ++ mtk_wcn_stp_send_data_f = NULL; ++ mtk_wcn_stp_send_data_raw_f = NULL; ++ mtk_wcn_stp_parser_data_f = NULL; ++ mtk_wcn_stp_receive_data_f = NULL; ++ mtk_wcn_stp_is_rxqueue_empty_f = NULL; ++ mtk_wcn_stp_is_ready_f = NULL; ++ mtk_wcn_stp_set_bluez_f = NULL; ++ mtk_wcn_stp_if_tx_f = NULL; ++ mtk_wcn_stp_if_rx_f = NULL; ++ mtk_wcn_stp_reg_event_cb_f = NULL; ++ mtk_wcn_stp_reg_tx_event_cb_f = NULL; ++ mtk_wcn_stp_coredump_start_get_f = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_unreg); ++ ++INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_send_data_f) { ++ ret = (*mtk_wcn_stp_send_data_f) (buffer, length, type); ++ /* WMT_STP_EXP_INFO_FUNC("mtk_wcn_stp_send_data_f send data(%d)\n",ret); */ ++ } else { ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_f cb is null\n"); ++ } ++ ++ return ret; ++ ++} ++EXPORT_SYMBOL(mtk_wcn_stp_send_data); ++ ++INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_send_data_raw_f) ++ ret = (*mtk_wcn_stp_send_data_raw_f) (buffer, length, type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_raw_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); ++ ++INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_parser_data_f) ++ ret = (*mtk_wcn_stp_parser_data_f) (buffer, length); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_parser_data_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_parser_data); ++ ++INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_receive_data_f) ++ ret = (*mtk_wcn_stp_receive_data_f) (buffer, length, type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_receive_data_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_receive_data); ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_stp_is_rxqueue_empty_f) ++ ret = (*mtk_wcn_stp_is_rxqueue_empty_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_rxqueue_empty_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_stp_is_ready_f) ++ ret = (*mtk_wcn_stp_is_ready_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_ready_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_is_ready); ++ ++void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags) ++{ ++ ++ if (mtk_wcn_stp_set_bluez_f) ++ (*mtk_wcn_stp_set_bluez_f) (flags); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_set_bluez_f cb is null\n"); ++ ++} ++EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); ++ ++INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_if_tx_f) ++ ret = (*mtk_wcn_stp_if_tx_f) (stp_if, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_tx_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); ++ ++INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_if_rx_f) ++ ret = (*mtk_wcn_stp_if_rx_f) (func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_rx_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); ++ ++INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_reg_event_cb_f) ++ ret = (*mtk_wcn_stp_reg_event_cb_f) (type, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_event_cb_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); ++ ++INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_reg_tx_event_cb_f) ++ ret = (*mtk_wcn_stp_reg_tx_event_cb_f) (type, func); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_tx_event_cb_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); ++ ++INT32 mtk_wcn_stp_coredump_start_get(VOID) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_coredump_start_get_f) ++ ret = (*mtk_wcn_stp_coredump_start_get_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_coredump_start_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get); ++ ++UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb) ++{ ++ WMT_STP_EXP_INFO_FUNC("call wmt exp cb reg\n"); ++ ++ mtk_wcn_wmt_func_on_f = pWmtExpCb->wmt_func_on_cb; ++ mtk_wcn_wmt_func_off_f = pWmtExpCb->wmt_func_off_cb; ++ mtk_wcn_wmt_therm_ctrl_f = pWmtExpCb->wmt_therm_ctrl_cb; ++ mtk_wcn_wmt_hwver_get_f = pWmtExpCb->wmt_hwver_get_cb; ++ mtk_wcn_wmt_dsns_ctrl_f = pWmtExpCb->wmt_dsns_ctrl_cb; ++ mtk_wcn_wmt_msgcb_reg_f = pWmtExpCb->wmt_msgcb_reg_cb; ++ mtk_wcn_wmt_msgcb_unreg_f = pWmtExpCb->wmt_msgcb_unreg_cb; ++ mtk_wcn_wmt_sdio_op_reg_f = pWmtExpCb->wmt_sdio_op_reg_cb; ++ mtk_wcn_wmt_sdio_host_awake_f = pWmtExpCb->wmt_sdio_host_awake_cb; ++ mtk_wcn_wmt_assert_f = pWmtExpCb->wmt_assert_cb; ++ mtk_wcn_wmt_assert_timeout_f = pWmtExpCb->wmt_assert_timeout_cb; ++ mtk_wcn_wmt_ic_info_get_f = pWmtExpCb->wmt_ic_info_get_cb; ++ mtk_wcn_wmt_psm_ctrl_f = pWmtExpCb->wmt_psm_ctrl_cb; ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_reg); ++ ++UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID) ++{ ++ WMT_STP_EXP_INFO_FUNC("call wmt exp cb unreg\n"); ++ ++ mtk_wcn_wmt_func_on_f = NULL; ++ mtk_wcn_wmt_func_off_f = NULL; ++ mtk_wcn_wmt_therm_ctrl_f = NULL; ++ mtk_wcn_wmt_hwver_get_f = NULL; ++ mtk_wcn_wmt_dsns_ctrl_f = NULL; ++ mtk_wcn_wmt_msgcb_reg_f = NULL; ++ mtk_wcn_wmt_msgcb_unreg_f = NULL; ++ mtk_wcn_wmt_sdio_op_reg_f = NULL; ++ mtk_wcn_wmt_sdio_host_awake_f = NULL; ++ mtk_wcn_wmt_assert_f = NULL; ++ mtk_wcn_wmt_assert_timeout_f = NULL; ++ mtk_wcn_wmt_ic_info_get_f = NULL; ++ mtk_wcn_wmt_psm_ctrl_f = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_unreg); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_func_off_f) ++ ret = (*mtk_wcn_wmt_func_off_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_off_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_func_off); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_func_on_f) { ++ ret = (*mtk_wcn_wmt_func_on_f) (type); ++ WMT_STP_EXP_INFO_FUNC("mtk_wcn_wmt_func_on_f type(%d)\n", type); ++ } else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_on_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_func_on); ++ ++INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_therm_ctrl_f) ++ ret = (*mtk_wcn_wmt_therm_ctrl_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_therm_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); ++ ++ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) ++{ ++ ENUM_WMTHWVER_TYPE_T ret = WMTHWVER_INVALID; ++ ++ if (mtk_wcn_wmt_hwver_get_f) ++ ret = (*mtk_wcn_wmt_hwver_get_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_hwver_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_dsns_ctrl_f) ++ ret = (*mtk_wcn_wmt_dsns_ctrl_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_dsns_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); ++ ++INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++{ ++ INT32 ret = 0; ++ ++ if (mtk_wcn_wmt_msgcb_reg_f) ++ ret = (*mtk_wcn_wmt_msgcb_reg_f) (eType, pCb); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_reg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); ++ ++INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++{ ++ INT32 ret = 0; ++ ++ if (mtk_wcn_wmt_msgcb_unreg_f) ++ ret = (*mtk_wcn_wmt_msgcb_unreg_f) (eType); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_unreg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); ++ ++INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_sdio_op_reg_f) ++ ret = (*mtk_wcn_wmt_sdio_op_reg_f) (own_cb); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_op_reg_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); ++ ++INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_wmt_sdio_host_awake_f) ++ ret = (*mtk_wcn_wmt_sdio_host_awake_f) (); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_host_awake_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_assert_f) ++ ret = (*mtk_wcn_wmt_assert_f) (type, reason); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_assert); ++ ++MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout) ++{ ++ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_wcn_wmt_assert_timeout_f) ++ ret = (*mtk_wcn_wmt_assert_timeout_f)(type, reason, timeout); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_timeout_f cb is null\n"); ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_assert_timeout); ++ ++UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type) ++{ ++ UINT32 ret = 0; ++ ++ if (mtk_wcn_wmt_ic_info_get_f) ++ ret = (*mtk_wcn_wmt_ic_info_get_f) (type); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_ic_info_get_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get); ++ ++INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag) ++{ ++ UINT32 ret = 0; ++ ++ if (mtk_wcn_wmt_psm_ctrl_f) ++ ret = (*mtk_wcn_wmt_psm_ctrl_f)(flag); ++ else ++ WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_psm_ctrl_f cb is null\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h +new file mode 100644 +index 000000000000..1c3dc8965298 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h +@@ -0,0 +1,610 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_STP_EXP_H_ ++#define _WMT_STP_EXP_H_ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "osal_typedef.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 ++#endif ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++#if (WMT_IDC_SUPPORT) ++#define CFG_WMT_LTE_COEX_HANDLING 1 ++#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0 ++#else ++#define CFG_WMT_LTE_COEX_HANDLING 0 ++#endif ++ ++/*from stp_exp.h*/ ++#define BT_TASK_INDX (0) ++#define FM_TASK_INDX (1) ++#define GPS_TASK_INDX (2) ++#define WIFI_TASK_INDX (3) ++#define WMT_TASK_INDX (4) ++#define STP_TASK_INDX (5) ++#define INFO_TASK_INDX (6) ++#define ANT_TASK_INDX (7) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define COEX_TASK_INDX (8) ++#define MTKSTP_MAX_TASK_NUM (9) ++#else ++#define MTKSTP_MAX_TASK_NUM (8) ++#endif ++ ++#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ ++/*end from stp_exp.h*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++********************************************************************************/ ++ ++/*moved from stp_exp.h*/ ++typedef void (*MTK_WCN_STP_EVENT_CB) (void); ++typedef INT32(*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); ++/* export for HIF driver */ ++typedef void (*MTK_WCN_STP_IF_RX) (const PUINT8 data, INT32 size); ++ ++typedef enum { ++ STP_UART_IF_TX = 0, ++ STP_SDIO_IF_TX = 1, ++ STP_BTIF_IF_TX = 2, ++ STP_MAX_IF_TX ++} ENUM_STP_TX_IF_TYPE; ++ ++/*end moved from stp_exp.h*/ ++ ++typedef INT32(*MTK_WCN_STP_SEND_DATA) (const PUINT8 buffer, const UINT32 length, const UINT8 type); ++typedef INT32(*MTK_WCN_STP_PARSER_DATA) (PUINT8 buffer, UINT32 length); ++typedef INT32(*MTK_WCN_STP_RECV_DATA) (PUINT8 buffer, UINT32 length, UINT8 type); ++typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RXQ_EMPTY) (UINT8 type); ++typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RDY) (VOID); ++typedef VOID(*MTK_WCN_STP_SET_BLUEZ) (MTK_WCN_BOOL flags); ++typedef INT32(*MTK_WCN_STP_REG_IF_TX) (ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++typedef INT32(*MTK_WCN_STP_REG_IF_RX) (MTK_WCN_STP_IF_RX func); ++typedef INT32(*MTK_WCN_STP_REG_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); ++typedef INT32(*MTK_WCN_STP_RGE_TX_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); ++typedef INT32(*MTK_WCN_STP_COREDUMP_START_GET)(VOID); ++ ++typedef struct _MTK_WCN_STP_EXP_CB_INFO_ { ++ MTK_WCN_STP_SEND_DATA stp_send_data_cb; ++ MTK_WCN_STP_SEND_DATA stp_send_data_raw_cb; ++ MTK_WCN_STP_PARSER_DATA stp_parser_data_cb; ++ MTK_WCN_STP_RECV_DATA stp_receive_data_cb; ++ MTK_WCN_STP_IS_RXQ_EMPTY stp_is_rxqueue_empty_cb; ++ MTK_WCN_STP_IS_RDY stp_is_ready_cb; ++ MTK_WCN_STP_SET_BLUEZ stp_set_bluez_cb; ++ MTK_WCN_STP_REG_IF_TX stp_if_tx_cb; ++ MTK_WCN_STP_REG_IF_RX stp_if_rx_cb; ++ MTK_WCN_STP_REG_EVENT_CB stp_reg_event_cb; ++ MTK_WCN_STP_RGE_TX_EVENT_CB stp_reg_tx_event_cb; ++ MTK_WCN_STP_COREDUMP_START_GET stp_coredump_start_get_cb; ++} MTK_WCN_STP_EXP_CB_INFO, *P_MTK_WCN_STP_EXP_CB_INFO; ++ ++/*moved from wmt_exp.h*/ ++ ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_ANT = 5, ++ WMTDRV_TYPE_STP = 6, ++ WMTDRV_TYPE_SDIO1 = 7, ++ WMTDRV_TYPE_SDIO2 = 8, ++ WMTDRV_TYPE_LPBK = 9, ++ WMTDRV_TYPE_COREDUMP = 10, ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ WMTDRV_TYPE_AUTOK = 11, ++#endif ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++typedef enum _ENUM_WMTDSNS_TYPE_T { ++ WMTDSNS_FM_DISABLE = 0, ++ WMTDSNS_FM_ENABLE = 1, ++ WMTDSNS_FM_GPS_DISABLE = 2, ++ WMTDSNS_FM_GPS_ENABLE = 3, ++ WMTDSNS_MAX ++} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; ++ ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_E1 = 0x0, ++ WMTHWVER_E2 = 0x1, ++ WMTHWVER_E3 = 0x2, ++ WMTHWVER_E4 = 0x3, ++ WMTHWVER_E5 = 0x4, ++ WMTHWVER_E6 = 0x5, ++ WMTHWVER_E7 = 0x6, ++ WMTHWVER_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++ ++typedef enum _ENUM_WMTTHERM_TYPE_T { ++ WMTTHERM_ZERO = 0, ++ WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, ++ WMTTHERM_READ = WMTTHERM_ENABLE + 1, ++ WMTTHERM_DISABLE = WMTTHERM_READ + 1, ++ WMTTHERM_MAX ++} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ UINT32 /* Buffer size in unit of byte */ ++); ++ ++typedef enum _SDIO_PS_OP { ++ OWN_SET = 0, ++ OWN_CLR = 1, ++ OWN_STATE = 2, ++} SDIO_PS_OP; ++ ++typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); ++ ++typedef enum _ENUM_WMTCHIN_TYPE_T { ++ WMTCHIN_CHIPID = 0x0, ++ WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, ++ WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, ++ WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, ++ WMTCHIN_MAX, ++ ++} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; ++ ++/*end moved from wmt_exp.h*/ ++ ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_FUNC_CTRL) (ENUM_WMTDRV_TYPE_T type); ++typedef INT8(*MTK_WCN_WMT_THERM_CTRL) (ENUM_WMTTHERM_TYPE_T eType); ++typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET) (VOID); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_DSNS_CTRL) (ENUM_WMTDSNS_TYPE_T eType); ++typedef INT32(*MTK_WCN_WMT_MSGCB_REG) (ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++typedef INT32(*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType); ++typedef INT32(*MTK_WCN_WMT_SDIO_OP_REG) (PF_WMT_SDIO_PSOP own_cb); ++typedef INT32(*MTK_WCN_WMT_SDIO_HOST_AWAKE) (VOID); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT) (ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT_TIMEOUT)(ENUM_WMTDRV_TYPE_T type, ++ UINT32 reason, INT32 timeout); ++typedef UINT32(*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type); ++typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag); ++ ++typedef struct _MTK_WCN_WMT_EXP_CB_INFO_ { ++ MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb; ++ MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb; ++ MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb; ++ MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb; ++ MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb; ++ MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb; ++ MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb; ++ MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb; ++ MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb; ++ MTK_WCN_WMT_ASSERT wmt_assert_cb; ++ MTK_WCN_WMT_ASSERT_TIMEOUT wmt_assert_timeout_cb; ++ MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb; ++ MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb; ++} MTK_WCN_WMT_EXP_CB_INFO, *P_MTK_WCN_WMT_EXP_CB_INFO; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*exp for WMT/STP register callback*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_reg ++* DESCRIPTION ++* stp driver reigster exp symbols ++* PARAMETERS ++* pStpExpCb [IN] stp callback structure pointer ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_unreg ++* DESCRIPTION ++* stp driver unreigster exp symbols ++* PARAMETERS ++* VOID ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_stp_exp_cb_unreg(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_exp_cb_reg ++* DESCRIPTION ++* WMT driver reigster exp symbols ++* PARAMETERS ++* pStpExpCb [IN] wmt callback structure pointer ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_exp_cb_unreg ++* DESCRIPTION ++* wmt driver unreigster exp symbols ++* PARAMETERS ++* VOID ++* RETURNS ++* UINT32 = 0: OK ++*****************************************************************************/ ++UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID); ++ ++/*stp exp symbols*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* subfunction send data through STP without seq/ack ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* Is STP ready? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:ready, FALSE:not ready ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); ++ ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_tx ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_rx ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_event_cb ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_tx_event_cb ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* INT32: 0:successful , -1: fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get coredump flag is set or not ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32: 0:coredump flag is not set , 1: coredump flag is set ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_get(VOID); ++ ++/*wmt exp symbols*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_func_off ++* DESCRIPTION ++* wmt turn off subsystem ++* PARAMETERS ++* type [IN] subsystem type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_func_on ++* DESCRIPTION ++* wmt turn on subsystem ++* PARAMETERS ++* type [IN] subsystem type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_therm_ctrl ++* DESCRIPTION ++* query chip temperature by WMT CMD ++* PARAMETERS ++* eType [IN] thermal ctrl type ++* RETURNS ++* >=0: chip temperature; 0xff:error ++*****************************************************************************/ ++extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_hwver_get ++* DESCRIPTION ++* get chip hardware version ++* PARAMETERS ++* VOID ++* RETURNS ++* >=0: chip hw version; 0xff:error ++*****************************************************************************/ ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_ic_info_get ++* DESCRIPTION ++* get chip hardware version or f/w version ++* PARAMETERS ++* type : which kind of information is needed ++* RETURNS ++* f/w version or hw version information ++*****************************************************************************/ ++extern UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_dsns_ctrl ++* DESCRIPTION ++* fm dsns cmd ctrl ++* PARAMETERS ++* eType [IN] fm dsns ctrl type ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_msgcb_reg ++* DESCRIPTION ++* used for subsystem register chip reset callback for received wmt reset msg. ++* PARAMETERS ++* eType [IN] subsystem type ++* pCb [IN] rst callback ++* RETURNS ++* 1: OK; 0:error ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_msgcb_unreg ++* DESCRIPTION ++* used for subsystem unregister chip reset callback for received wmt reset msg. ++* PARAMETERS ++* eType [IN] subsystem type ++* RETURNS ++* 1: OK; 0:error ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wmt_sdio_op_reg ++* DESCRIPTION ++* used to register callback for set sdio ownership. ++* PARAMETERS ++* own_cb [IN] set owner ship callback ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wmt_sdio_host_awake ++* DESCRIPTION ++* handing host awake when link is stp sdio? ++* PARAMETERS ++* VOID ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_assert ++* DESCRIPTION ++* host trigger firmware assert ++* PARAMETERS ++* type [IN] subsystem driver type ++* reason [IN] trigger assert reason ++* RETURNS ++* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++/***************************************************************************** ++ * * FUNCTION ++ * * mtk_wcn_wmt_assert_timeout ++ * * DESCRIPTION ++ * * host trigger firmware assert ++ * * PARAMETERS ++ * * type [IN] subsystem driver type ++ * * reason [IN] trigger assert reason ++ * * timeout [IN] trigger assert timeout data ++ * * RETURNS ++ * * MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error ++ * *****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, ++ UINT32 reason, INT32 timeout); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmt_psm_ctrl ++* DESCRIPTION ++* disable/enable psm ++* PARAMETERS ++* flag [IN] disable:0, enable:1 ++* RETURNS ++* always return 0; ++*****************************************************************************/ ++extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag); ++ ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile +new file mode 100644 +index 000000000000..286bfd4bfed3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile +@@ -0,0 +1,65 @@ ++subdir-ccflags-y += \ ++ -I$(src)/linux/include \ ++ -I$(src)/linux/pri/include \ ++ -I$(src)/core/include \ ++ -I$(src)/include \ ++ -I$(src)/../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc ++ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM) ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs/ ++subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include ++ ++EXT_FLAG=_soc ++COMMON_SRC_PATH := $(src) ++COMMON_OBJ_PATH := $(src) ++ ++ifeq ($(CONFIG_ARCH_MT6580), y) ++subdir-ccflags-y += -D CFG_WMT_READ_EFUSE_VCN33 ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO), m) ++# WMT DRIVER ++obj-$(CONFIG_MTK_COMBO) += mtk_stp_wmt$(EXT_FLAG).o ++# WMT DRIVER-core part ++mtk_stp_wmt$(EXT_FLAG)-objs := core/wmt_core.o core/wmt_ctrl.o core/wmt_func.o core/wmt_ic_soc.o core/wmt_lib.o core/wmt_conf.o ++ ++ ++# WMT DRIVER-linux private part ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/wmt_dev.o linux/pri/wmt_exp.o ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_btif.o ++ ++ ++# WMT DRIVER-OSAL ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pub/osal.o linux/pub/bgw_desense.o ++# WMT DRIVER-platform implementation ++# ccflags-y += -D WMT_PLAT_ALPS ++# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/wmt_plat_alps.o ++ ++# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/mtk_wcn_consys_hw.o ++ ++ ++mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_exp.o core/stp_core.o core/psm_core.o core/btm_core.o linux/pri/stp_dbg.o ++ ++# WMT stub part (built-in kernel image) ++# obj-y += platform/alps/mtk_wcn_consys_stub_alps.o ++ ++ ++ ++obj-$(CONFIG_MTK_COMBO_BT) += mtk_stp_bt$(EXT_FLAG).o ++mtk_stp_bt$(EXT_FLAG)-objs := linux/pub/stp_chrdev_bt.o ++ ++ ++obj-$(CONFIG_MTK_COMBO_WIFI) += mtk_wmt_wifi$(EXT_FLAG).o ++mtk_wmt_wifi$(EXT_FLAG)-objs := linux/pub/wmt_chrdev_wifi.o ++ ++endif ++ ++ifeq ($(CONFIG_MTK_COMBO), y) ++# subdir-ccflags-y += -D WMT_PLAT_ALPS ++obj-y += core/ ++obj-y += linux/ ++#obj-y += $(subst ",,$(CONFIG_MTK_PLATFORM))/ ++obj-y += mt7623/ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile +new file mode 100644 +index 000000000000..9df71b9e163e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile +@@ -0,0 +1,22 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../linux/include \ ++ -I$(src)/../linux/pri/include \ ++ -I$(src)/../core/include \ ++ -I$(src)/../include \ ++ -I$(src)/../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ ++ ++obj-y += wmt_core.o \ ++ wmt_ctrl.o \ ++ wmt_func.o \ ++ wmt_ic_soc.o \ ++ wmt_lib.o \ ++ wmt_conf.o \ ++ btm_core.o \ ++ dbg_core.o \ ++ psm_core.o \ ++ stp_core.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c +new file mode 100644 +index 000000000000..4946b682d826 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c +@@ -0,0 +1,1376 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_dbg.h" ++#include "stp_core.h" ++#include "btm_core.h" ++#include "wmt_plat.h" ++ ++#define PFX_BTM "[STP-BTM] " ++#define STP_BTM_LOG_LOUD 4 ++#define STP_BTM_LOG_DBG 3 ++#define STP_BTM_LOG_INFO 2 ++#define STP_BTM_LOG_WARN 1 ++#define STP_BTM_LOG_ERR 0 ++ ++INT32 gBtmDbgLevel = STP_BTM_LOG_INFO; ++ ++#define STP_BTM_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_LOUD) \ ++ pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ ++ pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_INFO) \ ++ pr_debug(PFX_BTM "[I]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_WARN) \ ++ pr_warn(PFX_BTM "[W]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_BTM_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_ERR) \ ++ pr_err(PFX_BTM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define STP_BTM_TRC_FUNC(f) \ ++do { \ ++ if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ ++ pr_debug(PFX_BTM "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#define ASSERT(expr) ++ ++MTKSTP_BTM_T stp_btm_i; ++MTKSTP_BTM_T *stp_btm = &stp_btm_i; ++ ++const char *g_btm_op_name[] = { ++ "STP_OPID_BTM_RETRY", ++ "STP_OPID_BTM_RST", ++ "STP_OPID_BTM_DBG_DUMP", ++ "STP_OPID_BTM_DUMP_TIMEOUT", ++ "STP_OPID_BTM_POLL_CPUPCR", ++ "STP_OPID_BTM_PAGED_DUMP", ++ "STP_OPID_BTM_FULL_DUMP", ++ "STP_OPID_BTM_PAGED_TRACE", ++ "STP_OPID_BTM_FORCE_FW_ASSERT", ++#if CFG_WMT_LTE_COEX_HANDLING ++ "STP_OPID_BTM_WMT_LTE_COEX", ++#endif ++ "STP_OPID_BTM_EXIT" ++}; ++ ++#if 0 ++static char *_stp_pkt_type(int type) ++{ ++ ++ static char s[10]; ++ ++ switch (type) { ++ case WMT_TASK_INDX: ++ osal_memcpy(s, "WMT", strlen("WMT") + 1); ++ break; ++ case BT_TASK_INDX: ++ osal_memcpy(s, "BT", strlen("BT") + 1); ++ break; ++ case GPS_TASK_INDX: ++ osal_memcpy(s, "GPS", strlen("GPS") + 1); ++ break; ++ case FM_TASK_INDX: ++ osal_memcpy(s, "FM", strlen("FM") + 1); ++ break; ++ default: ++ osal_memcpy(s, "UNKNOWN", strlen("UNKNOWN") + 1); ++ break; ++ } ++ ++ return s; ++} ++#endif ++ ++static INT32 _stp_btm_put_dump_to_nl(void) ++{ ++#define NUM_FETCH_ENTRY 8 ++ ++ static UINT8 buf[2048]; ++ static UINT8 tmp[2048]; ++ ++ UINT32 buf_len; ++ STP_PACKET_T *pkt; ++ STP_DBG_HDR_T *hdr; ++ INT32 len; ++ INT32 remain = 0, index = 0; ++ INT32 retry = 0, rc = 0, nl_retry = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ index = 0; ++ tmp[index++] = '['; ++ tmp[index++] = 'M'; ++ tmp[index++] = ']'; ++ ++ do { ++ index = 3; ++ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); ++ if (buf_len > 0) { ++ pkt = (STP_PACKET_T *) buf; ++ hdr = &pkt->hdr; ++ len = pkt->hdr.len; ++ osal_memcpy(&tmp[index], &len, 2); ++ index += 2; ++ if (hdr->dbg_type == STP_DBG_FW_DMP) { ++ osal_memcpy(&tmp[index], pkt->raw, len); ++ ++ if (len <= 1500) { ++ /* pr_warn("\n%s\n+++\n", tmp); */ ++ /* pr_warn("send coredump len:%d\n", len); */ ++ /* pr_warn("send coredump:%s\n", tmp); */ ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); ++ ++ while (rc) { ++ nl_retry++; ++ if (nl_retry > 1000) ++ break; ++ STP_BTM_WARN_FUNC ++ ("**dump send fails, and retry again.**\n"); ++ osal_sleep_ms(3); ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); ++ if (!rc) ++ STP_BTM_WARN_FUNC("****retry again ok!**\n"); ++ } ++ /* schedule(); */ ++ } else { ++ STP_BTM_INFO_FUNC("dump entry length is over long\n"); ++ BUG_ON(0); ++ } ++ retry = 0; ++ } ++ } else { ++ retry++; ++ osal_sleep_ms(100); ++ } ++ } while ((remain > 0) || (retry < 2)); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return 0; ++} ++ ++#define SUB_PKT_SIZE 1024 ++#define SUB_PKT_HEADER 5 /*'[M]',3Bytes; len,2Bytes*/ ++ ++INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len) ++{ ++ static UINT8 tmp[SUB_PKT_SIZE + SUB_PKT_HEADER]; ++ ++ INT32 remain = dump_len, index = 0; ++ INT32 rc = 0, nl_retry = 0; ++ INT32 len; ++ INT32 offset = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ if (dump_len > 0) { ++ index = 0; ++ tmp[index++] = '['; ++ tmp[index++] = 'M'; ++ tmp[index++] = ']'; ++ ++ do { ++ index = 3; ++ if (remain >= SUB_PKT_SIZE) ++ len = SUB_PKT_SIZE; ++ else ++ len = remain; ++ remain -= len; ++ ++ osal_memcpy(&tmp[index], &len, 2); ++ index += 2; ++ osal_memcpy(&tmp[index], data_buf + offset, len); ++ offset += len; ++ STP_BTM_DBG_FUNC ++ ("send %d remain %d\n", len, remain); ++ ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); ++ while (rc) { ++ nl_retry++; ++ if (nl_retry > 1000) ++ break; ++ STP_BTM_WARN_FUNC ++ ("**dump send fails, and retry again.**\n"); ++ osal_sleep_ms(3); ++ rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); ++ if (!rc) { ++ STP_BTM_WARN_FUNC ++ ("****retry again ok!**\n"); ++ } ++ } ++ /* schedule(); */ ++ } while (remain > 0); ++ } else ++ STP_BTM_INFO_FUNC("dump entry length is 0\n"); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return 0; ++} ++ ++static INT32 _stp_btm_put_dump_to_aee(void) ++{ ++ static UINT8 buf[2048]; ++ static UINT8 tmp[2048]; ++ ++ UINT32 buf_len; ++ STP_PACKET_T *pkt; ++ STP_DBG_HDR_T *hdr; ++ INT32 remain = 0; ++ INT32 retry = 0; ++ INT32 ret = 0; ++ ++ STP_BTM_INFO_FUNC("Enter..\n"); ++ ++ do { ++ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); ++ if (buf_len > 0) { ++ pkt = (STP_PACKET_T *) buf; ++ hdr = &pkt->hdr; ++ if (hdr->dbg_type == STP_DBG_FW_DMP) { ++ memcpy(&tmp[0], pkt->raw, pkt->hdr.len); ++ ++ if (pkt->hdr.len <= 1500) { ++ tmp[pkt->hdr.len] = '\n'; ++ tmp[pkt->hdr.len + 1] = '\0'; ++ ++ ret = stp_dbg_aee_send(tmp, pkt->hdr.len, 0); ++ } else { ++ STP_BTM_INFO_FUNC("dump entry length is over long\n"); ++ BUG_ON(0); ++ } ++ retry = 0; ++ } ++ } else { ++ retry++; ++ msleep(100); ++ } ++ } while ((remain > 0) || (retry < 2)); ++ ++ STP_BTM_INFO_FUNC("Exit..\n"); ++ return ret; ++} ++ ++#if 0 ++INT32 _stp_trigger_firmware_assert_via_emi(VOID) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ INT32 status = -1; ++ INT32 i = 0, j = 0; ++ ++ do { ++ STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); ++ if (!p_virtual_addr) { ++ STP_BTM_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); ++ STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); ++#if 1 ++ /* wait for firmware assert */ ++ osal_sleep_ms(50); ++ /* if firmware is not assert self, host driver helps it. */ ++ do { ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ mtk_wcn_stp_wakeup_consys(); ++ STP_BTM_INFO_FUNC("[Force Assert] wakeup consys (%d)\n", i); ++ stp_dbg_poll_cpupcr(5, 1, 1); ++ osal_sleep_ms(5); ++ ++ i++; ++ if (i > 20) { ++ i = 0; ++ break; ++ } ++ } while (1); ++#endif ++ ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ j++; ++ if (j > 8) { ++ j = 0; ++ break; ++ } ++ } while (1); ++ ++ return status; ++} ++#else ++INT32 _stp_trigger_firmware_assert_via_emi(VOID) ++{ ++ INT32 status = -1; ++ INT32 j = 0; ++ ++ wmt_plat_force_trigger_assert(STP_FORCE_TRG_ASSERT_DEBUG_PIN); ++ ++ do { ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ status = 0; ++ break; ++ } ++ ++ stp_dbg_poll_cpupcr(5, 1, 1); ++ stp_dbg_poll_dmaregs(5, 1); ++ j++; ++ STP_BTM_INFO_FUNC("Wait for assert message (%d)\n", j); ++ osal_sleep_ms(20); ++ if (j > 49) { /* wait for 1 second */ ++ stp_dbg_set_fw_info("host trigger fw assert timeout", ++ osal_strlen("host trigger fw assert timeout"), ++ STP_HOST_TRIGGER_ASSERT_TIMEOUT); ++ wcn_core_dump_timeout(); /* trigger collect SYS_FTRACE */ ++ break; ++ } ++ } while (1); ++ ++ return status; ++} ++#endif ++ ++#define COMBO_DUMP2AEE ++#if 1 ++#define STP_DBG_PAGED_DUMP_BUFFER_SIZE (32*1024*sizeof(char)) ++UINT8 g_paged_dump_buffer[STP_DBG_PAGED_DUMP_BUFFER_SIZE] = { 0 }; ++ ++#define STP_DBG_PAGED_TRACE_SIZE (2048*sizeof(char)) ++UINT8 g_paged_trace_buffer[STP_DBG_PAGED_TRACE_SIZE] = { 0 }; ++ ++UINT32 g_paged_dump_len = 0; ++UINT32 g_paged_trace_len = 0; ++VOID _stp_dump_emi_dump_buffer(UINT8 *buffer, UINT32 len) ++{ ++ UINT32 i = 0; ++ ++ if (len > 16) ++ len = 16; ++ for (i = 0; i < len; i++) { ++ if (i % 16 == 0 && i != 0) ++ pr_cont("\n "); ++ ++ if (buffer[i] == ']' || buffer[i] == '[' || buffer[i] == ',') ++ pr_cont("%c", buffer[i]); ++ else ++ pr_cont("0x%02x ", buffer[i]); ++ } ++} ++#endif ++static INT32 _stp_btm_handler(MTKSTP_BTM_T *stp_btm, P_STP_BTM_OP pStpOp) ++{ ++ INT32 ret = -1; ++ INT32 dump_sink = 1; /* core dump target, 0: aee; 1: netlink */ ++ INT32 Ret = 0; ++ static UINT32 counter; ++ UINT32 full_dump_left = STP_FULL_DUMP_TIME; ++ UINT32 page_counter = 0; ++ UINT32 packet_num = STP_PAGED_DUMP_TIME_LIMIT/100; ++ UINT32 dump_num = 0; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ P_CONSYS_EMI_ADDR_INFO p_ecsi; ++ ++ p_ecsi = wmt_plat_get_emi_phy_add(); ++ osal_assert(p_ecsi); ++ if (NULL == pStpOp) ++ return -1; ++ ++ switch (pStpOp->opId) { ++ case STP_OPID_BTM_EXIT: ++ /* TODO: clean all up? */ ++ ret = 0; ++ break; ++ ++ /*tx timeout retry */ ++ case STP_OPID_BTM_RETRY: ++ stp_do_tx_timeout(); ++ ret = 0; ++ ++ break; ++ ++ /*whole chip reset */ ++ case STP_OPID_BTM_RST: ++ STP_BTM_INFO_FUNC("whole chip reset start!\n"); ++ STP_BTM_INFO_FUNC("....+\n"); ++ if (stp_btm->wmt_notify) { ++ stp_btm->wmt_notify(BTM_RST_OP); ++ ret = 0; ++ } else { ++ STP_BTM_ERR_FUNC("stp_btm->wmt_notify is NULL."); ++ ret = -1; ++ } ++ ++ STP_BTM_INFO_FUNC("whole chip reset end!\n"); ++ ++ break; ++ ++ case STP_OPID_BTM_DBG_DUMP: ++ /*Notify the wmt to get dump data */ ++ STP_BTM_DBG_FUNC("wmt dmp notification\n"); ++ dump_sink = ((stp_btm->wmt_notify(BTM_GET_AEE_SUPPORT_FLAG) == MTK_WCN_BOOL_TRUE) ? 0 : 1); ++ ++ if (dump_sink == 0) ++ _stp_btm_put_dump_to_aee(); ++ else if (dump_sink == 1) ++ _stp_btm_put_dump_to_nl(); ++ else ++ STP_BTM_ERR_FUNC("unknown sink %d\n", dump_sink); ++ ++ break; ++ ++ case STP_OPID_BTM_DUMP_TIMEOUT: ++ /* Flush dump data, and reset compressor */ ++ STP_BTM_INFO_FUNC("Flush dump data\n"); ++ wcn_core_dump_flush(0, MTK_WCN_BOOL_TRUE); ++ break; ++ ++ case STP_OPID_BTM_POLL_CPUPCR: ++ do { ++ UINT32 times; ++ UINT32 sleep; ++ ++ times = pStpOp->au4OpData[0]; ++ sleep = pStpOp->au4OpData[1]; ++ ++ ret = stp_dbg_poll_cpupcr(times, sleep, 0); ++ ret += stp_dbg_poll_dmaregs(times, sleep); ++ } while (0); ++ break; ++ ++ case STP_OPID_BTM_PAGED_DUMP: ++ g_paged_dump_len = 0; ++ issue_type = STP_FW_ASSERT_ISSUE; ++ /*packet number depend on dump_num get from register:0xf0080044 ,support jade*/ ++ wcn_core_dump_deinit_gcoredump(); ++ dump_num = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_page_dump_num); ++ if (dump_num != 0) { ++ packet_num = dump_num; ++ STP_BTM_WARN_FUNC("get consys dump num packet_num(%d)\n", packet_num); ++ } else { ++ STP_BTM_ERR_FUNC("can not get consys dump num and default num is 35\n"); ++ } ++ Ret = wcn_core_dump_init_gcoredump(packet_num, STP_CORE_DUMP_TIMEOUT); ++ if (Ret) { ++ STP_BTM_ERR_FUNC("core dump init fail\n"); ++ break; ++ } ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ page_counter = 0; ++ do { ++ UINT32 loop_cnt1 = 0; ++ UINT32 loop_cnt2 = 0; ++ ENUM_HOST_DUMP_STATE host_state; ++ ENUM_CHIP_DUMP_STATE chip_state; ++ UINT32 dump_phy_addr = 0; ++ UINT8 *dump_vir_addr = NULL; ++ UINT32 dump_len = 0; ++ UINT32 isEnd = 0; ++ ++ host_state = (ENUM_HOST_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_state); ++ if (STP_HOST_DUMP_NOT_START == host_state) { ++ counter++; ++ STP_BTM_INFO_FUNC("counter(%d)\n", counter); ++ osal_sleep_ms(100); ++ } else { ++ counter = 0; ++ } ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_PUT_DONE == chip_state) { ++ STP_BTM_INFO_FUNC("chip put done\n"); ++ break; ++ } ++ STP_BTM_INFO_FUNC("waiting chip put done\n"); ++ STP_BTM_INFO_FUNC("chip_state: %d\n", chip_state); ++ loop_cnt1++; ++ osal_sleep_ms(5); ++ ++ if (loop_cnt1 > 10) ++ goto paged_dump_end; ++ ++ } ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); ++ ++ dump_phy_addr = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); ++ ++ if (!dump_phy_addr) { ++ STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); ++ ret = -2; ++ break; ++ } ++ dump_len = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); ++ STP_BTM_INFO_FUNC("dump_phy_ddr(%08x),dump_vir_add(0x%p),dump_len(%d)\n", ++ dump_phy_addr, dump_vir_addr, dump_len); ++ ++ /*move dump info according to dump_addr & dump_len */ ++#if 1 ++ osal_memcpy(&g_paged_dump_buffer[0], dump_vir_addr, dump_len); ++ _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], dump_len); ++ ++ if (0 == page_counter) { /* do fw assert infor paser in first paged dump */ ++ if (1 == stp_dbg_get_host_trigger_assert()) ++ issue_type = STP_HOST_TRIGGER_FW_ASSERT; ++ ++ ret = stp_dbg_set_fw_info(&g_paged_dump_buffer[0], 512, issue_type); ++ if (ret) { ++ STP_BTM_ERR_FUNC("set fw issue infor fail(%d),maybe fw warm reset...\n", ret); ++ stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"), ++ STP_FW_WARM_RST_ISSUE); ++ } ++ } ++ ++ if (dump_len <= 32 * 1024) { ++ pr_err("g_coredump_mode: %d!\n", g_coredump_mode); ++ if (1 == g_coredump_mode) ++ ret = stp_dbg_aee_send(&g_paged_dump_buffer[0], dump_len, 0); ++ else if (2 == g_coredump_mode) ++ ret = _stp_btm_put_emi_dump_to_nl(&g_paged_dump_buffer[0], dump_len); ++ else{ ++ STP_BTM_INFO_FUNC("coredump is disabled!\n"); ++ return 0; ++ } ++ if (ret == 0) ++ STP_BTM_INFO_FUNC("aee send ok!\n"); ++ else if (ret == 1) ++ STP_BTM_INFO_FUNC("aee send fisish!\n"); ++ else ++ STP_BTM_ERR_FUNC("aee send error!\n"); ++ } else ++ STP_BTM_ERR_FUNC("dump len is over than 32K(%d)\n", dump_len); ++ ++ g_paged_dump_len += dump_len; ++ STP_BTM_INFO_FUNC("dump len update(%d)\n", g_paged_dump_len); ++#endif ++ wmt_plat_update_host_sync_num(); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); ++ ++ STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); ++ ++ page_counter++; ++ STP_BTM_INFO_FUNC("\n\n++ paged dump counter(%d) ++\n\n\n", page_counter); ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_END == chip_state) { ++ STP_BTM_INFO_FUNC("chip put end\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); ++ break; ++ } ++ STP_BTM_INFO_FUNC("waiting chip put end\n"); ++ ++ loop_cnt2++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt2 > 10) ++ goto paged_dump_end; ++ } ++ ++paged_dump_end: ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ ++ if (counter > packet_num) { ++ isEnd = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_paded_dump_end); ++ ++ if (isEnd) { ++ STP_BTM_INFO_FUNC("paged dump end\n"); ++ ++ STP_BTM_INFO_FUNC("\n\n paged dump print ++\n\n"); ++ _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], g_paged_dump_len); ++ STP_BTM_INFO_FUNC("\n\n paged dump print --\n\n"); ++ STP_BTM_INFO_FUNC("\n\n paged dump size = %d, paged dump page number = %d\n\n", ++ g_paged_dump_len, page_counter); ++ counter = 0; ++ ret = 0; ++ } else { ++ STP_BTM_ERR_FUNC("paged dump fail\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ stp_dbg_poll_cpupcr(5, 5, 0); ++ stp_dbg_poll_dmaregs(5, 1); ++ counter = 0; ++ ret = -1; ++ } ++ break; ++ } ++ ++ } while (1); ++ ++ break; ++ ++ case STP_OPID_BTM_FULL_DUMP: ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ do { ++ UINT32 loop_cnt1 = 0; ++ UINT32 loop_cnt2 = 0; ++ ENUM_CHIP_DUMP_STATE chip_state; ++ UINT32 dump_phy_addr = 0; ++ UINT8 *dump_vir_addr = NULL; ++ UINT32 dump_len = 0; ++ UINT32 isFail = 0; ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_PUT_DONE == chip_state) ++ break; ++ ++ loop_cnt1++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt1 > 10) { ++ isFail = 1; ++ goto full_dump_end; ++ } ++ } ++ ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); ++ ++ dump_phy_addr = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); ++ if (!dump_phy_addr) { ++ STP_BTM_ERR_FUNC("get phy dump address fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get vir dump address fail\n"); ++ ret = -2; ++ break; ++ } ++ dump_len = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); ++ /*move dump info according to dump_addr & dump_len */ ++ wmt_plat_update_host_sync_num(); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); ++ ++ STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), ++ wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); ++ ++ while (1) { ++ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); ++ if (STP_CHIP_DUMP_END == chip_state) { ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); ++ break; ++ } ++ loop_cnt2++; ++ osal_sleep_ms(10); ++ ++ if (loop_cnt2 > 10) { ++ isFail = 1; ++ goto full_dump_end; ++ } ++ } ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++full_dump_end: ++ if (isFail) { ++ STP_BTM_ERR_FUNC("full dump fail\n"); ++ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); ++ ret = -1; ++ break; ++ } ++ } while (--full_dump_left > 0); ++ if (0 == full_dump_left) { ++ STP_BTM_INFO_FUNC("full dump end\n"); ++ ret = 0; ++ } ++ break; ++ case STP_OPID_BTM_PAGED_TRACE: ++ g_paged_trace_len = 0; ++ do { ++ UINT32 ctrl_val = 0; ++ UINT32 loop_cnt1 = 0; ++ UINT32 buffer_start = 0; ++ UINT32 buffer_idx = 0; ++ UINT8 *dump_vir_addr = NULL; ++ ++ while (loop_cnt1 < 10) { ++ ctrl_val = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state); ++ if (0x8 == ctrl_val) ++ break; ++ osal_sleep_ms(10); ++ loop_cnt1++; ++ } ++ ++ if (loop_cnt1 >= 10) { ++ STP_BTM_ERR_FUNC("polling CTRL STATE fail\n"); ++ ret = -1; ++ break; ++ } ++ ++ buffer_start = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_start); ++ buffer_idx = wmt_plat_get_dump_info( ++ p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_idx); ++ /* buffer_len = buffer_idx - buffer_start; */ ++ g_paged_trace_len = buffer_idx; ++ STP_BTM_INFO_FUNC("paged trace buffer addr(%08x),buffer_len(%d)\n", buffer_start, buffer_idx); ++ dump_vir_addr = wmt_plat_get_emi_virt_add(buffer_start - p_ecsi->emi_phy_addr); ++ if (!dump_vir_addr) { ++ STP_BTM_ERR_FUNC("get vir dump address fail\n"); ++ ret = -2; ++ break; ++ } ++ osal_memcpy(&g_paged_trace_buffer[0], dump_vir_addr, ++ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE); ++ /*moving paged trace according to buffer_start & buffer_len */ ++ do { ++ int i = 0; ++ int dump_len = 0; ++ ++ dump_len = ++ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE; ++ pr_warn("\n\n -- paged trace hex output --\n\n"); ++ for (i = 0; i < dump_len; i++) { ++ if (i % 16 == 0) ++ pr_cont("\n"); ++ ++ pr_cont("%02x ", g_paged_trace_buffer[i]); ++ } ++ pr_warn("\n\n -- paged trace ascii output --\n\n"); ++ for (i = 0; i < dump_len; i++) { ++ if (i % 64 == 0) ++ pr_cont("\n"); ++ pr_cont("%c", g_paged_trace_buffer[i]); ++ } ++ } while (0); ++ /*move parser fw assert infor to paged dump in the one paged dump */ ++ /* ret = stp_dbg_set_fw_info(&g_paged_trace_buffer[0],g_paged_trace_len,issue_type); */ ++ ret = 0; ++ ++ } while (0); ++ mtk_wcn_stp_ctx_restore(); ++ break; ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ case STP_OPID_BTM_WMT_LTE_COEX: ++ ret = wmt_idc_msg_to_lte_handing(); ++ break; ++#endif ++ default: ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ /* INT32 ret = 0; */ ++ ++ if (!pOpQ) { ++ STP_BTM_WARN_FUNC("!pOpQ\n"); ++ return NULL; ++ } ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ ++ if (!pOp) ++ STP_BTM_WARN_FUNC("RB_GET fail\n"); ++ ++ return pOp; ++} ++ ++static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 ret; ++ ++ if (!pOpQ || !pOp) { ++ STP_BTM_WARN_FUNC("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); ++ return 0; /* ;MTK_WCN_BOOL_FALSE; */ ++ } ++ ++ ret = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ ret = -1; ++ ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ ++ if (ret) { ++ STP_BTM_WARN_FUNC("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", ++ pOpQ, ++ RB_COUNT(pOpQ), ++ &stp_btm->rFreeOpQ, ++ &stp_btm->rActiveOpQ); ++ return 0; ++ } ++ /* STP_BTM_WARN_FUNC("RB_COUNT = %d\n",RB_COUNT(pOpQ)); */ ++ return 1; ++ ++} ++ ++P_OSAL_OP _stp_btm_get_free_op(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ ++ if (stp_btm) { ++ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, sizeof(pOp->op)); ++ ++ return pOp; ++ } else ++ return NULL; ++} ++ ++INT32 _stp_btm_put_act_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp) ++{ ++ INT32 bRet = 0; ++ INT32 bCleanup = 0; ++ long wait_ret = -1; ++ ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ if (!stp_btm || !pOp) { ++ STP_BTM_ERR_FUNC("Input NULL pointer\n"); ++ return bRet; ++ } ++ do { ++ pSignal = &pOp->signal; ++ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(&pOp->signal); ++ } ++ ++ /* put to active Q */ ++ bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp); ++ if (0 == bRet) { ++ STP_BTM_WARN_FUNC("put active queue fail\n"); ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ break; ++ } ++ ++ /* wake up wmtd */ ++ osal_trigger_event(&stp_btm->STPd_event); ++ ++ if (pSignal->timeoutValue == 0) { ++ bRet = 1; /* MTK_WCN_BOOL_TRUE; */ ++ /* clean it in wmtd */ ++ break; ++ } ++ ++ /* wait result, clean it here */ ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ ++ /* check result */ ++ wait_ret = osal_wait_for_signal_timeout(&pOp->signal); ++ ++ STP_BTM_DBG_FUNC("wait completion:%ld\n", wait_ret); ++ if (!wait_ret) { ++ STP_BTM_ERR_FUNC("wait completion timeout\n"); ++ /* TODO: how to handle it? retry? */ ++ } else { ++ if (pOp->result) ++ STP_BTM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); ++ ++ bRet = (pOp->result) ? 0 : 1; ++ } ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); ++ } ++ bRet = (pOp->result) ? 0 : 1; ++ return bRet; ++} ++ ++static INT32 _stp_btm_wait_for_msg(void *pvData) ++{ ++ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; ++ ++ return (!RB_EMPTY(&stp_btm->rActiveOpQ)) || osal_thread_should_stop(&stp_btm->BTMd); ++} ++ ++static INT32 _stp_btm_proc(void *pvData) ++{ ++ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; ++ P_OSAL_OP pOp; ++ INT32 id; ++ INT32 result; ++ ++ if (!stp_btm) { ++ STP_BTM_WARN_FUNC("!stp_btm\n"); ++ return -1; ++ } ++ ++ for (;;) { ++ pOp = NULL; ++ ++ osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (void *)stp_btm); ++ ++ if (osal_thread_should_stop(&stp_btm->BTMd)) { ++ STP_BTM_INFO_FUNC("should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); ++ ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_lxop activeQ fail\n"); ++ continue; ++ } ++ ++ id = osal_op_get_id(pOp); ++ ++ STP_BTM_DBG_FUNC("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", ++ id, (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), ++ RB_COUNT(&stp_btm->rActiveOpQ)); ++ ++ if (id >= STP_OPID_BTM_NUM) { ++ STP_BTM_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ result = -1; ++ goto handler_done; ++ } ++ ++ result = _stp_btm_handler(stp_btm, &pOp->op); ++ ++handler_done: ++ ++ if (result) { ++ STP_BTM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, ++ (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), ++ result); ++ } ++ ++ if (osal_op_is_wait_for_signal(pOp)) { ++ osal_op_raise_signal(pOp, result); ++ } else { ++ /* put Op back to freeQ */ ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); ++ } ++ ++ if (STP_OPID_BTM_EXIT == id) { ++ break; ++ } else if (STP_OPID_BTM_RST == id) { ++ /* prevent multi reset case */ ++ stp_btm_reset_btm_wq(stp_btm); ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ } ++ } ++ ++ STP_BTM_INFO_FUNC("exits\n"); ++ ++ return 0; ++}; ++ ++static inline INT32 _stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_RST; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_RETRY; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (!stp_btm) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_DUMP_TIMEOUT; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ STP_BTM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = opid; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ INT32 retval; ++#if 0 ++ UINT32 dump_type; ++ UINT8 *virtual_addr = NULL; ++#endif ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++#if 1 /* Paged dump */ ++ STP_BTM_INFO_FUNC("paged dump start++\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); ++ if (retval) ++ STP_BTM_ERR_FUNC("paged dump fail\n"); ++#else ++ virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_CHIP_SYNC_ADDR); ++ if (!virtual_addr) { ++ STP_BTM_ERR_FUNC("get dump type virtual addr fail\n"); ++ return -1; ++ } ++ dump_type = CONSYS_REG_READ(virtual_addr); ++ STP_BTM_INFO_FUNC("dump type:%08x\n", dump_type); ++ ++ if ((dump_type & 0xfffff) == (CONSYS_PAGED_DUMP_START_ADDR & 0xfffff)) { ++ STP_BTM_INFO_FUNC("do paged dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); ++ if (retval) { ++ STP_BTM_ERR_FUNC("paged dump fail,do full dump\n"); ++ _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); ++ } ++ } else if ((dump_type & 0xfffff) == (CONSYS_FULL_DUMP_START_ADDR & 0xfffff)) { ++ STP_BTM_INFO_FUNC("do full dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); ++ } else { ++ STP_BTM_INFO_FUNC("do normal dump\n"); ++ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DBG_DUMP); ++ } ++#endif ++ ++ return retval; ++} ++ ++static inline INT32 _stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_POLL_CPUPCR; ++ pOp->signal.timeoutValue = 0; ++ pOp->op.au4OpData[0] = times; ++ pOp->op.au4OpData[1] = sleep; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_PAGED_TRACE; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) ++{ ++ INT32 ret = -1; ++ ++ ret = _stp_trigger_firmware_assert_via_emi(); ++ ++ return ret; ++ ++} ++ ++INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_rst_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_stp_retry_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_coredump_timeout_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_dmp_wq(stp_btm); ++} ++ ++INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_btm_notify_wmt_trace_wq(stp_btm); ++} ++ ++INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) ++{ ++ return _stp_notify_btm_poll_cpupcr(stp_btm, times, sleep); ++} ++ ++INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en) ++{ ++ return stp_dbg_poll_cuppcr_ctrl(en); ++} ++ ++INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) ++{ ++ INT32 ret = -1; ++#if BTIF_RXD_BE_BLOCKED_DETECT ++ if (is_btif_rxd_be_blocked()) ++ ret = wcn_btif_rxd_blocked_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ else ++#endif ++ ret = _stp_btm_do_fw_assert_via_emi(stp_btm); ++ return ret; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++static inline INT32 _stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_btm == NULL) ++ return STP_BTM_OPERATION_FAIL; ++ ++ pOp = _stp_btm_get_free_op(stp_btm); ++ if (!pOp) { ++ /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ ++ return -1; /* break; */ ++ } ++ pOp->op.opId = STP_OPID_BTM_WMT_LTE_COEX; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_btm_put_act_op(stp_btm, pOp); ++ STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) ++{ ++ return _stp_notify_btm_handle_wmt_lte_coex(stp_btm); ++} ++ ++#endif ++MTKSTP_BTM_T *stp_btm_init(void) ++{ ++ INT32 i = 0x0; ++ INT32 ret = -1; ++ ++ osal_unsleepable_lock_init(&stp_btm->wq_spinlock); ++ osal_event_init(&stp_btm->STPd_event); ++ stp_btm->wmt_notify = wmt_lib_btm_cb; ++ ++ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); ++ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); ++ ++ /* Put all to free Q */ ++ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_btm->arQue[i].signal)); ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); ++ } ++ ++ /*Generate PSM thread, to servie STP-CORE for packet retrying and core dump receiving */ ++ stp_btm->BTMd.pThreadData = (VOID *) stp_btm; ++ stp_btm->BTMd.pThreadFunc = (VOID *) _stp_btm_proc; ++ osal_memcpy(stp_btm->BTMd.threadName, BTM_THREAD_NAME, osal_strlen(BTM_THREAD_NAME)); ++ ++ ret = osal_thread_create(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_create fail...\n"); ++ goto ERR_EXIT1; ++ } ++ ++ /* Start STPd thread */ ++ ret = osal_thread_run(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_run FAILS\n"); ++ goto ERR_EXIT1; ++ } ++ ++ return stp_btm; ++ ++ERR_EXIT1: ++ ++ return NULL; ++ ++} ++ ++INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm) ++{ ++ ++ INT32 ret = -1; ++ ++ STP_BTM_INFO_FUNC("btm deinit\n"); ++ ++ if (!stp_btm) ++ return STP_BTM_OPERATION_FAIL; ++ ++ ret = osal_thread_destroy(&stp_btm->BTMd); ++ if (ret < 0) { ++ STP_BTM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ return STP_BTM_OPERATION_FAIL; ++ } ++ ++ return STP_BTM_OPERATION_SUCCESS; ++} ++ ++INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm) ++{ ++ UINT32 i = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); ++ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); ++ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); ++ /* Put all to free Q */ ++ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_btm->arQue[i].signal)); ++ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); ++ } ++ ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c +new file mode 100644 +index 000000000000..246448b38b31 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c +@@ -0,0 +1,13 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h +new file mode 100644 +index 000000000000..9a429b4af1e3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h +@@ -0,0 +1,133 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _BTM_CORE_H ++#define _BTM_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_wmt.h" ++#include "wmt_plat.h" ++#include "wmt_idc.h" ++#include "mtk_btif_exp.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define STP_BTM_OPERATION_FAIL (-1) ++#define STP_BTM_OPERATION_SUCCESS (0) ++ ++#define STP_BTM_OP_BUF_SIZE (64) ++ ++#define BTM_THREAD_NAME "mtk_stp_btm" ++ ++#define STP_PAGED_DUMP_TIME_LIMIT 3500 ++#define STP_FULL_DUMP_TIME 3 ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_STP_BTM_OPID_T { ++ STP_OPID_BTM_RETRY = 0x0, ++ STP_OPID_BTM_RST = 0x1, ++ STP_OPID_BTM_DBG_DUMP = 0x2, ++ STP_OPID_BTM_DUMP_TIMEOUT = 0x3, ++ STP_OPID_BTM_POLL_CPUPCR = 0x4, ++ STP_OPID_BTM_PAGED_DUMP = 0x5, ++ STP_OPID_BTM_FULL_DUMP = 0x6, ++ STP_OPID_BTM_PAGED_TRACE = 0x7, ++ STP_OPID_BTM_FORCE_FW_ASSERT = 0x8, ++#if CFG_WMT_LTE_COEX_HANDLING ++ STP_OPID_BTM_WMT_LTE_COEX = 0x9, ++#endif ++ STP_OPID_BTM_EXIT, ++ STP_OPID_BTM_NUM ++} ENUM_STP_BTM_OPID_T, *P_ENUM_STP_BTM_OPID_T; ++ ++typedef OSAL_OP_DAT STP_BTM_OP; ++typedef P_OSAL_OP_DAT P_STP_BTM_OP; ++ ++typedef struct mtk_stp_btm { ++ OSAL_THREAD BTMd; /* main thread (wmtd) handle */ ++ OSAL_EVENT STPd_event; ++ OSAL_UNSLEEPABLE_LOCK wq_spinlock; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[STP_BTM_OP_BUF_SIZE]; /* real op instances */ ++ ++ /*wmt_notify */ ++ INT32 (*wmt_notify)(MTKSTP_BTM_WMT_OP_T); ++} MTKSTP_BTM_T; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm); ++INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep); ++INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en); ++INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm); ++INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm); ++INT32 wcn_psm_flag_trigger_collect_ftrace(void); ++#if BTIF_RXD_BE_BLOCKED_DETECT ++INT32 wcn_btif_rxd_blocked_collect_ftrace(void); ++MTK_WCN_BOOL is_btif_rxd_be_blocked(void); ++#endif ++MTKSTP_BTM_T *stp_btm_init(void); ++extern unsigned int g_coredump_mode; ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h +new file mode 100644 +index 000000000000..d8c6ebe9c4b0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h +@@ -0,0 +1,69 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _DBG_CORE_H ++#define _DBG_CORE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h +new file mode 100644 +index 000000000000..fe92f25e92c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h +@@ -0,0 +1,251 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _PSM_CORE_H ++#define _PSM_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_wmt.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define PFX_PSM "[STP-PSM] " ++#define STP_PSM_LOG_LOUD 4 ++#define STP_PSM_LOG_DBG 3 ++#define STP_PSM_LOG_INFO 2 ++#define STP_PSM_LOG_WARN 1 ++#define STP_PSM_LOG_ERR 0 ++ ++#define ASSERT(expr) ++#define STP_PSM_FIFO_SIZE 0x2000 /* 8kbytes */ ++#define STP_PSM_TX_SIZE 0x800 /* 2kbytes */ ++ ++#define STP_PSM_OPERATION_FAIL (-1) ++#define STP_PSM_OPERATION_SUCCESS (0) ++ ++#define STP_PSM_PACKET_SIZE_MAX (2000) ++ ++#define PSM_HANDLING 127 ++ ++#define STP_PSM_WMT_PS_TASK_HANDLING_TIME 30 /* 20 milli-seconds */ ++#define STP_PSM_IDLE_TIME_SLEEP 30 /* temporary for stress testing */ ++#define STP_PSM_IDLE_TIME_SLEEP_1000 1000 /* for high speed transmission e.g. BT OPP*/ ++#define STP_PSM_SDIO_IDLE_TIME_SLEEP 100 /* temporary for SDIO stress testing */ ++#define STP_PSM_WAIT_EVENT_TIMEOUT 6000 ++#if 0 ++#define STP_PSM_WMT_EVENT_SLEEP_EN (0x1UL << 0) ++#define STP_PSM_WMT_EVENT_WAKEUP_EN (0x1UL << 1) ++#define STP_PSM_BLOCK_DATA_EN (0x1UL << 2) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (0x1UL << 3) ++#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (0x1UL << 4) ++#define STP_PSM_RESET_EN (0x1UL << 5) ++#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (0x1UL << 6) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (0x1UL << 7) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (0x1UL << 8) ++#endif ++ ++#define STP_PSM_WMT_EVENT_SLEEP_EN (0) ++#define STP_PSM_WMT_EVENT_WAKEUP_EN (1) ++#define STP_PSM_BLOCK_DATA_EN (2) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (3) ++#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (4) ++#define STP_PSM_RESET_EN (5) ++#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (6) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (7) ++#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (8) ++ ++#define STP_PSM_DBG_SIZE (16) ++ ++/* OP command ring buffer : must be power of 2 */ ++#define STP_OP_BUF_SIZE (16) ++ ++#define PSM_THREAD_NAME "mtk_stp_psm" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum { ++ ACT = 0, ++ ACT_INACT, ++ INACT, ++ INACT_ACT, ++ STP_PSM_MAX_STATE, ++} MTKSTP_PSM_STATE_T; ++ ++typedef enum _ENUM_STP_OPID_T { ++ STP_OPID_PSM_SLEEP = 0, ++ STP_OPID_PSM_WAKEUP, ++ STP_OPID_PSM_HOST_AWAKE, ++ STP_OPID_PSM_EXIT, ++ STP_OPID_PSM_NUM, ++ STP_OPID_PSM_INALID = STP_OPID_PSM_NUM, ++} ENUM_STP_OPID_T, *P_ENUM_STP_OPID_T; ++ ++typedef enum { ++ MON = 0, ++ UNMON, ++} MTKSTP_PSM_MONSTATE_T; ++ ++typedef INT32(*wmt_notify_t) (MTKSTP_PSM_ACTION_T action); ++typedef INT32(*stp_tx_cb_t) (unsigned char *buffer, UINT32 length, UINT8 type); ++ ++typedef OSAL_OP_DAT STP_OP; ++typedef P_OSAL_OP_DAT P_STP_OP; ++ ++typedef struct mtk_stp_psm { ++ OSAL_THREAD PSMd; /* main thread (wmtd) handle */ ++ OSAL_EVENT STPd_event; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[STP_OP_BUF_SIZE]; /* real op instances */ ++ ++ /* OSAL_OP current_active_op; */ ++ /* P_OSAL_OP current_active_op; */ ++ UINT32 last_active_opId; ++ MTKSTP_PSM_STATE_T work_state; /*working state */ ++ OSAL_BIT_OP_VAR flag; ++ ++ /* in normal cases, sleep op is always enabled; ++ * but in error cases, we can't execute sleep cmd, ++ * Eg: FW assert, core dump ++ */ ++ INT32 sleep_en; ++ ++/* OSAL_UNSLEEPABLE_LOCK flagSpinlock; */ ++ INT32 idle_time_to_sleep; ++ OSAL_WAKE_LOCK wake_lock; ++ OSAL_TIMER psm_timer; /*monitor if active */ ++ OSAL_EVENT wait_wmt_q; ++ OSAL_FIFO hold_fifo; ++ OSAL_SLEEPABLE_LOCK hold_fifo_spinlock_global; ++ OSAL_UNSLEEPABLE_LOCK wq_spinlock; ++ OSAL_SLEEPABLE_LOCK stp_psm_lock; ++ INT32 (*wmt_notify)(MTKSTP_PSM_ACTION_T action); ++ INT32 (*stp_tx_cb)(unsigned char *buffer, UINT32 length, UINT8 type); ++ ++ MTK_WCN_BOOL (*is_wmt_quick_ps_support)(VOID); ++ UINT8 out_buf[STP_PSM_TX_SIZE]; ++} MTKSTP_PSM_T; ++ ++typedef struct { ++ UINT32 prev_flag; ++ UINT32 cur_flag; ++ UINT32 line_num; ++ UINT32 package_no; ++ UINT32 sec; ++ UINT32 usec; ++ UINT32 pid; ++} STP_PSM_ENTRY_T; ++ ++typedef struct stp_psm_record { ++ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; ++ UINT32 in; ++ UINT32 out; ++ UINT32 size; ++ OSAL_UNSLEEPABLE_LOCK lock; ++} STP_PSM_RECORD_T; ++ ++typedef struct stp_psm_opid_record { ++ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; ++ UINT32 in; ++ UINT32 out; ++ UINT32 size; ++ OSAL_UNSLEEPABLE_LOCK lock; ++} STP_PSM_OPID_RECORD, *P_STP_PSM_OPID_RECORD; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#define PSM_USE_COUNT_PACKAGE 0 ++ ++#if PSM_USE_COUNT_PACKAGE ++#define MTK_COMBO_PSM_RX_TH_DEFAULT (1600) ++#define MTK_COMBO_PSM_TX_TH_DEFAULT (300) ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir); ++#else ++#define SAMPLE_DURATION 1 /*1 second */ ++#define RTX_SPEED_THRESHOLD 50000 /*50KB/s */ ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*stp-psm external function*/ ++INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); ++INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm); ++ ++INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type); ++INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep); ++struct mtk_stp_psm *stp_psm_init(void); ++INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm); ++MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel); ++INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state); ++MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID); ++ ++INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm); ++INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h +new file mode 100644 +index 000000000000..eaa5ce773e33 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h +@@ -0,0 +1,629 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_CORE_H ++#define _STP_CORE_H ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "stp_exp.h" ++#include "psm_core.h" ++#include "btm_core.h" ++#include "stp_btif.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CFG_STP_CORE_CTX_SPIN_LOCK (0) ++ ++#define WMT_LTE_COEX_FLAG (0x16) ++ ++/*configure using SPINLOCK or just mutex for STP-CORE tx*/ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define CONFIG_POWER_SAVING_SUPPORT ++ ++#ifdef PFX ++#undef PFX ++#endif ++#define PFX "[STP] " ++ ++#define STP_LOG_DBG 4 ++#define STP_LOG_PKHEAD 3 ++#define STP_LOG_INFO 2 ++#define STP_LOG_WARN 1 ++#define STP_LOG_ERR 0 ++ ++extern unsigned int gStpDbgLvl; ++ ++#define STP_DBG_FUNC(fmt, arg...)\ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_INFO) \ ++ osal_dbg_print(PFX "%s:[I] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_WARN) \ ++ osal_warn_print(PFX "%s:[W] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_ERR) \ ++ osal_err_print(PFX "%s:[E] " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_TRC_FUNC(f) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#define STP_DUMP_PACKET_HEAD(a, b, c) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_PKHEAD) \ ++ stp_dump_data(a, b, c); \ ++} while (0) ++#define STP_TRACE_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgLvl >= STP_LOG_DBG) \ ++ osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++ ++#define STP_MODE_BIT(x) (0x1UL << x) ++#define MTKSTP_UART_FULL_MODE STP_MODE_BIT(0) ++#define MTKSTP_UART_MAND_MODE STP_MODE_BIT(1) ++#define MTKSTP_BTIF_FULL_MODE STP_MODE_BIT(2) ++#define MTKSTP_BTIF_MAND_MODE STP_MODE_BIT(3) ++#define MTKSTP_SDIO_MODE STP_MODE_BIT(4) ++ ++#define MTKSTP_BUFFER_SIZE (16384) ++ ++/*To check function driver's status by the the interface*/ ++/*Operation definition*/ ++#define OP_FUNCTION_ACTIVE 0 ++ ++/*Driver's status*/ ++#define STATUS_OP_INVALID 0 ++#define STATUS_FUNCTION_INVALID 1 ++ ++#define STATUS_FUNCTION_ACTIVE 31 ++#define STATUS_FUNCTION_INACTIVE 32 ++ ++#define MTKSTP_CRC_SIZE (2) ++#define MTKSTP_HEADER_SIZE (4) ++#define MTKSTP_SEQ_SIZE (8) ++ ++/*#define MTKSTP_WINSIZE (4)*/ ++#define MTKSTP_WINSIZE (7) ++#define MTKSTP_TX_TIMEOUT (180) /*TODO: Baudrate to decide this */ ++#define MTKSTP_RETRY_LIMIT (10) ++ ++#define INDEX_INC(idx) \ ++{ \ ++ idx++; \ ++ idx &= 0x7; \ ++} ++ ++#define INDEX_DEC(idx) \ ++{ \ ++ idx--; \ ++ idx &= 0x7; \ ++} ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef INT32(*IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); ++/* event/signal */ ++typedef INT32(*EVENT_SET) (UINT8 function_type); ++typedef INT32(*EVENT_TX_RESUME) (UINT8 winspace); ++typedef INT32(*FUNCTION_STATUS) (UINT8 type, UINT8 op); ++typedef INT32(*WMT_NOTIFY_FUNC_T) (UINT32 action); ++typedef INT32(*BTM_NOTIFY_WMT_FUNC_T) (INT32); ++ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++typedef OSAL_UNSLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; ++#else ++typedef OSAL_SLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; ++#endif ++ ++typedef struct { ++ /* common interface */ ++ IF_TX cb_if_tx; ++ /* event/signal */ ++ EVENT_SET cb_event_set; ++ EVENT_TX_RESUME cb_event_tx_resume; ++ FUNCTION_STATUS cb_check_funciton_status; ++} mtkstp_callback; ++ ++typedef enum { ++ MTKSTP_SYNC = 0, ++ MTKSTP_SEQ, ++ MTKSTP_ACK, ++ MTKSTP_NAK, ++ MTKSTP_TYPE, ++ MTKSTP_LENGTH, ++ MTKSTP_CHECKSUM, ++ MTKSTP_DATA, ++ MTKSTP_CRC1, ++ MTKSTP_CRC2, ++ MTKSTP_RESYNC1, ++ MTKSTP_RESYNC2, ++ MTKSTP_RESYNC3, ++ MTKSTP_RESYNC4, ++ MTKSTP_FW_MSG, ++} mtkstp_parser_state; ++ ++typedef struct { ++ mtkstp_parser_state state; ++ UINT8 seq; ++ UINT8 ack; ++ UINT8 nak; ++ UINT8 type; ++ UINT16 length; ++ UINT8 checksum; ++ UINT16 crc; ++#if 1 ++ UINT8 wmtsubtype; ++#endif ++} mtkstp_parser_context_struct; ++ ++typedef struct { ++ UINT8 txseq; /* last tx pkt's seq + 1 */ ++ UINT8 txack; /* last tx pkt's ack */ ++ UINT8 rxack; /* last rx pkt's ack */ ++ UINT8 winspace; /* current sliding window size */ ++ UINT8 expected_rxseq; /* last rx pkt's seq + 1 */ ++ UINT8 retry_times; ++} mtkstp_sequence_context_struct; ++ ++typedef struct { ++ /* MTK_WCN_MUTEX mtx; */ ++ OSAL_UNSLEEPABLE_LOCK mtx; ++ UINT8 buffer[MTKSTP_BUFFER_SIZE]; ++ UINT32 read_p; ++ UINT32 write_p; ++} mtkstp_ring_buffer_struct; ++ ++typedef struct { ++ UINT8 inband_rst_set; ++ UINT32 rx_counter; /* size of current processing pkt in rx_buf[] */ ++ UINT8 rx_buf[MTKSTP_BUFFER_SIZE]; /* input buffer of STP, room for current processing pkt */ ++ UINT32 tx_read; /* read ptr of tx_buf[] */ ++ UINT32 tx_write; /* write ptr of tx_buf[] */ ++ UINT8 tx_buf[MTKSTP_BUFFER_SIZE]; /* output buffer of STP */ ++ UINT32 tx_start_addr[MTKSTP_SEQ_SIZE]; /* ptr of each pkt in tx_buf[] */ ++ UINT32 tx_length[MTKSTP_SEQ_SIZE]; /* length of each pkt in tx_buf[] */ ++ mtkstp_ring_buffer_struct ring[MTKSTP_MAX_TASK_NUM]; /* ring buffers for each function driver */ ++ mtkstp_parser_context_struct parser; /* current rx pkt's content */ ++ mtkstp_sequence_context_struct sequence; /* state machine's current status */ ++ /* MTK_WCN_MUTEX stp_mutex; */ ++ /* OSAL_UNSLEEPABLE_LOCK stp_mutex; */ ++ STP_CTX_LOCK stp_mutex; ++ /* MTK_WCN_TIMER tx_timer; // timer for tx timeout handling */ ++ OSAL_TIMER tx_timer; ++ ++ MTKSTP_PSM_T *psm; ++ MTKSTP_BTM_T *btm; ++ UINT8 f_enable; /* default disabled */ ++ UINT8 f_ready; /* default non-ready */ ++ UINT8 f_pending_type; ++ UINT8 f_coredump; /*block tx flag, for now, only when f/w assert happens, we will set this bit on */ ++ UINT8 en_coredump; ++ /* Flag to identify Blueztooth is Bluez/or MTK Stack */ ++ MTK_WCN_BOOL f_bluez; ++ MTK_WCN_BOOL f_dbg_en; ++ MTK_WCN_BOOL f_autorst_en; ++ ++ /* Flag to identify STP by SDIO or UART */ ++ UINT32 f_mode; ++ ++ /* Flag to indicate the last WMT CLOSE */ ++ UINT32 f_wmt_last_close; ++ ++ /* Flag to indicate evt err has triggered assert or not */ ++ UINT32 f_evt_err_assert; ++} mtkstp_context_struct; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_init ++* DESCRIPTION ++* init STP kernel ++* PARAMETERS ++* cb_func [IN] function pointers of system APIs ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_deinit ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_deinit(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_enable ++* DESCRIPTION ++* enable/disable STP ++* PARAMETERS ++* value [IN] 0 = disable, others = enable ++* RETURNS ++* INT32 0 = success, others = error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_enable(INT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_ready ++* DESCRIPTION ++* ready/non-ready STP ++* PARAMETERS ++* value [IN] 0 = non-ready, others = ready ++* RETURNS ++* INT32 0 = success, others = error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_ready(INT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_ctrl ++* DESCRIPTION ++* set f/w assert flag in STP context ++* PARAMETERS ++* value [IN] 0=assert end, others=assert begins ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get f/w assert flag in STP context ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0= f/w assert flag is not set, others=f/w assert flag is set ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_coredump_start_get(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* send raw data to common interface, bypass STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 length transmitted ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_set_sdio_mode ++* DESCRIPTION ++* Set stp for SDIO mode ++* PARAMETERS ++* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_mode(UINT32 sdio_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_fullset_mode ++* DESCRIPTION ++* Is stp use UART Fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:UART Fullset, FALSE:UART Fullset ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_mand_mode ++* DESCRIPTION ++* Is stp use UART Mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:UART Mandatory, FALSE:UART Mandatory ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void); ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_fullset_mode ++* DESCRIPTION ++* Is stp use BTIF Fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Fullset, FALSE:BTIF Fullset ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_mand_mode ++* DESCRIPTION ++* Is stp use BTIF Mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Mandatory, FALSE:BTIF Mandatory ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_sdio_mode ++* DESCRIPTION ++* Is stp use SDIO mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To sync to oringnal stp state with f/w stp ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_inband_reset(void); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To send testing command to chip ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_test_cmd(INT32 no); ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To control STP debugging mechanism ++* PARAMETERS ++* func_no: function control, func_op: dumpping filer, func_param: dumpping parameter ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_debug_ctrl(INT32 func_no, INT32 func_op, INT32 func_param); ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush ++* DESCRIPTION ++* flush all stp context ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_flush_context(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_rx_queue ++* DESCRIPTION ++* flush all stp rx queue ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++extern void mtk_wcn_stp_flush_rx_queue(UINT32 type); ++ ++/***************************************************************************** ++* FUNCTION ++* set stp debugging mdoe ++* DESCRIPTION ++* set stp debugging mdoe ++* PARAMETERS ++* dbg_mode: switch to dbg mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode); ++ ++/***************************************************************************** ++* FUNCTION ++* set stp auto reset mdoe ++* DESCRIPTION ++* set stp auto reset mdoe ++* PARAMETERS ++* auto_rst: switch to auto reset mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst); ++ ++/*stp_psm support*/ ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_notify_stp ++* DESCRIPTION ++* WMT notification to STP that power saving job is done or not ++* PARAMETERS ++* ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_notify_stp(const UINT32 action); ++ ++extern int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_enabla ++* DESCRIPTION ++* enable STP PSM ++* PARAMETERS ++* int idle_time_to_sleep: IDLE time to sleep ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_enable(int idle_time_to_sleep); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_disable ++* DESCRIPTION ++* disable STP PSM ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_disable(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_reset ++* DESCRIPTION ++* reset STP PSM (used on whole chip reset) ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_psm_reset(void); ++extern void stp_do_tx_timeout(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_btm_get_dmp ++* DESCRIPTION ++* get stp dump related information ++* PARAMETERS ++* buffer: dump placement, len: dump size ++* RETURNS ++* 0: Success Negative Value: Fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_btm_get_dmp(char *buf, int *len); ++ ++extern int mtk_wcn_stp_dbg_enable(void); ++ ++extern int mtk_wcn_stp_dbg_disable(void); ++ ++extern void mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type); ++ ++extern int mtk_wcn_sys_if_rx(UINT8 *data, INT32 size); ++ ++extern MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel); ++ ++extern INT32 mtk_wcn_stp_dbg_dump_package(VOID); ++ ++extern int stp_drv_init(void); ++ ++extern void stp_drv_exit(void); ++ ++extern INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on); ++ ++extern INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on); ++ ++extern INT32 mtk_wcn_stp_coredump_flag_get(VOID); ++extern INT32 mtk_wcn_stp_notify_sleep_for_thermal(void); ++ ++extern INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value); ++ ++/*stp btif API declared*/ ++extern INT32 mtk_wcn_stp_open_btif(VOID); ++extern INT32 mtk_wcn_stp_close_btif(VOID); ++extern INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb); ++extern INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len); ++extern INT32 mtk_wcn_stp_wakeup_consys(VOID); ++extern INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); ++extern INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); ++extern INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag); ++extern VOID mtk_wcn_stp_ctx_save(VOID); ++extern VOID mtk_wcn_stp_ctx_restore(VOID); ++extern INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(VOID); ++extern VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value); ++extern UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(VOID); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _STP_CORE_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h +new file mode 100644 +index 000000000000..94b3d8a597ac +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h +@@ -0,0 +1,89 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_WMT_H ++#define _STP_WMT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum { ++ BTM_RST_OP = 0, ++ BTM_DMP_OP = 1, ++ BTM_GET_AEE_SUPPORT_FLAG = 2, ++ BTM_MAX_OP, ++} MTKSTP_BTM_WMT_OP_T; ++ ++typedef enum { ++ SLEEP = 0, ++ HOST_AWAKE, ++ WAKEUP, ++ EIRQ, ++ ROLL_BACK, ++ STP_PSM_MAX_ACTION ++} MTKSTP_PSM_ACTION_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++extern MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op); ++ ++extern INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action); ++extern MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _STP_WMT_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h +new file mode 100644 +index 000000000000..4c64b6b5e65b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CONF_H_ ++#define _WMT_CONF_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CUST_CFG_WMT "WMT_SOC.cfg" ++#define CUST_CFG_WMT_PREFIX "/system/etc/firmware/" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_conf_read_file(VOID); ++P_WMT_GEN_CONF wmt_conf_get_cfg(VOID); ++INT32 wmt_conf_set_cfg_file(const char *name); ++ ++#endif /* _WMT_CONF_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h +new file mode 100644 +index 000000000000..cca52a15cc98 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h +@@ -0,0 +1,428 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CORE_H_ ++#define _WMT_CORE_H_ ++ ++#include "osal.h" ++#include "wmt_ctrl.h" ++#include "wmt_exp.h" ++#include "wmt_plat.h" ++/* TODO: [GeorgeKuo][FixMe] remove temporarily */ ++/* for AIF state definition */ ++/* #include "mtk_wcn_cmb_stub.h" */ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++#define CFG_CORE_MT6620_SUPPORT 0 /* whether MT6620 is supported or not */ ++ ++#define CFG_CORE_MT6628_SUPPORT 0 /* whether MT6628 is supported or not */ ++ ++#define CFG_CORE_SOC_SUPPORT 1 ++ ++/* TODO:[ChangeFeature][George] move this definition outside so that wmt_dev can remove wmt_core.h inclusion. */ ++#define defaultPatchName "mt66xx_patch_hdr.bin" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define BCNT_PATCH_BUF_HEADROOM (8) ++ ++#define DWCNT_HIF_CONF (4) ++#define DWCNT_STRAP_CONF (4) ++#define DWCNT_RESERVED (8) ++#define DWCNT_CTRL_DATA (16) ++ ++#if 0 /* TODO: [obsolete][GeorgeKuo]: remove ubsolete definitions */ ++#define WMT_SET (1) ++#define WMT_QUERY (0) ++#define WMT_PKT_FMT_RAW (1) ++#define WMT_PKT_FMT_STP (0) ++#endif ++ ++#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE) ++#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE) ++ ++#define WMT_HDR_LEN (4) /* header length */ ++#define WMT_STS_LEN (1) /* status length */ ++#define WMT_FLAG_LEN (1) ++#define WMT_HIF_UART_INFO_LEN (4) ++#define WMT_FUNC_CTRL_PARAM_LEN (1) ++ ++#define WMT_DEFAULT_BAUD_RATE (115200) ++ ++#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_WMT_FM_T { ++ WMT_FM_INVALID = 0, ++ WMT_FM_I2C = 1, ++ WMT_FM_COMM = 2, ++ WMT_FM_MAX ++} ENUM_WMT_FM_T, *P_ENUM_WMT_FM_T; ++ ++typedef enum _ENUM_WMT_HIF_T { ++ WMT_HIF_UART = 0, ++ WMT_HIF_SDIO = 1, ++ WMT_HIF_BTIF = 2, ++ WMT_HIF_MAX ++} ENUM_WMT_HIF_T, *P_ENUM_WMT_HIF_T; ++ ++#if 0 /* [George] moved to wmt_exp.h for hif_sdio's use */ ++typedef enum { ++ WMT_SDIO_SLOT_INVALID = 0, ++ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ ++ WMT_SDIO_SLOT_SDIO2 = 2, ++ WMT_SDIO_SLOT_MAX ++} WMT_SDIO_SLOT_NUM; ++ ++typedef enum { ++ WMT_SDIO_FUNC_STP = 0, ++ WMT_SDIO_FUNC_WIFI = 1, ++ WMT_SDIO_FUNC_MAX ++} WMT_SDIO_FUNC_TYPE; ++#endif ++ ++typedef enum _ENUM_WMT_OPID_T { ++ WMT_OPID_HIF_CONF = 0, ++ WMT_OPID_PWR_ON = 1, ++ WMT_OPID_PWR_OFF = 2, ++ WMT_OPID_FUNC_ON = 3, ++ WMT_OPID_FUNC_OFF = 4, ++ WMT_OPID_REG_RW = 5, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++ WMT_OPID_EXIT = 6, ++ WMT_OPID_PWR_SV = 7, ++ WMT_OPID_DSNS = 8, ++ WMT_OPID_LPBK = 9, ++ WMT_OPID_CMD_TEST = 10, ++ WMT_OPID_HW_RST = 11, ++ WMT_OPID_SW_RST = 12, ++ WMT_OPID_BAUD_RST = 13, ++ WMT_OPID_STP_RST = 14, ++ WMT_OPID_THERM_CTRL = 15, ++ WMT_OPID_EFUSE_RW = 16, ++ WMT_OPID_GPIO_CTRL = 17, ++ WMT_OPID_FW_COREDMP = 18, ++ WMT_OPID_GPIO_STATE = 19, ++ WMT_OPID_BGW_DS = 20, ++ WMT_OPID_SET_MCU_CLK = 21, ++ WMT_OPID_ADIE_LPBK_TEST = 22, ++#if CFG_WMT_LTE_COEX_HANDLING ++ WMT_OPID_IDC_MSG_HANDLING = 23, ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++ WMT_OPID_ANT_RAM_DOWN = 24, ++ WMT_OPID_ANT_RAM_STA_GET = 25, ++#endif ++ WMT_OPID_MAX ++} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T; ++ ++typedef OSAL_OP_DAT WMT_OP; ++typedef P_OSAL_OP_DAT P_WMT_OP; ++ ++typedef struct _WMT_HIF_CONF { ++ UINT32 hifType; /* HIF Type */ ++ UINT32 au4HifConf[DWCNT_HIF_CONF]; /* HIF Config */ ++ UINT32 au4StrapConf[DWCNT_STRAP_CONF]; /* Strap Config */ ++} WMT_HIF_CONF, *P_WMT_HIF_CONF; ++ ++typedef INT32(*WMT_OPID_FUNC) (P_WMT_OP); ++ ++typedef struct _WMT_GEN_CONF { ++ UINT8 cfgExist; ++ ++ UINT8 coex_wmt_ant_mode; ++ UINT8 coex_wmt_ext_component; ++ UINT8 coex_wmt_wifi_time_ctl; ++ UINT8 coex_wmt_ext_pta_dev_on; ++ /*mt6592 and LTE coex filter mode setting */ ++ UINT8 coex_wmt_filter_mode; ++ ++ UINT8 coex_bt_rssi_upper_limit; ++ UINT8 coex_bt_rssi_mid_limit; ++ UINT8 coex_bt_rssi_lower_limit; ++ UINT8 coex_bt_pwr_high; ++ UINT8 coex_bt_pwr_mid; ++ UINT8 coex_bt_pwr_low; ++ ++ UINT8 coex_wifi_rssi_upper_limit; ++ UINT8 coex_wifi_rssi_mid_limit; ++ UINT8 coex_wifi_rssi_lower_limit; ++ UINT8 coex_wifi_pwr_high; ++ UINT8 coex_wifi_pwr_mid; ++ UINT8 coex_wifi_pwr_low; ++ ++ UINT8 coex_ext_pta_hi_tx_tag; ++ UINT8 coex_ext_pta_hi_rx_tag; ++ UINT8 coex_ext_pta_lo_tx_tag; ++ UINT8 coex_ext_pta_lo_rx_tag; ++ UINT16 coex_ext_pta_sample_t1; ++ UINT16 coex_ext_pta_sample_t2; ++ UINT8 coex_ext_pta_wifi_bt_con_trx; ++ ++ UINT32 coex_misc_ext_pta_on; ++ UINT32 coex_misc_ext_feature_set; ++ /*GPS LNA setting */ ++ UINT8 wmt_gps_lna_pin; ++ UINT8 wmt_gps_lna_enable; ++ /*Power on sequence */ ++ UINT8 pwr_on_rtc_slot; ++ UINT8 pwr_on_ldo_slot; ++ UINT8 pwr_on_rst_slot; ++ UINT8 pwr_on_off_slot; ++ UINT8 pwr_on_on_slot; ++ UINT8 co_clock_flag; ++ ++ /* Combo chip side SDIO driving setting */ ++ UINT32 sdio_driving_cfg; ++ ++} WMT_GEN_CONF, *P_WMT_GEN_CONF; ++ ++typedef enum _ENUM_DRV_STS_ { ++#if 0 ++ DRV_STS_INVALID = 0, ++ DRV_STS_UNREG = 1, /* Initial State */ ++#endif ++ DRV_STS_POWER_OFF = 0, /* initial state */ ++ DRV_STS_POWER_ON = 1, /* powered on, only WMT */ ++ DRV_STS_FUNC_ON = 2, /* FUNC ON */ ++ DRV_STS_MAX ++} ENUM_DRV_STS, *P_ENUM_DRV_STS; ++ ++typedef enum _WMT_IC_PIN_ID_ { ++ WMT_IC_PIN_AUDIO = 0, ++ WMT_IC_PIN_EEDI = 1, ++ WMT_IC_PIN_EEDO = 2, ++ WMT_IC_PIN_GSYNC = 3, ++ WMT_IC_PIN_MAX ++} WMT_IC_PIN_ID, *P_WMT_IC_PIN_ID; ++ ++typedef enum _WMT_IC_PIN_STATE_ { ++ WMT_IC_PIN_EN = 0, ++ WMT_IC_PIN_DIS = 1, ++ WMT_IC_AIF_0 = 2, /* = CMB_STUB_AIF_0, */ ++ WMT_IC_AIF_1 = 3, /* = CMB_STUB_AIF_1, */ ++ WMT_IC_AIF_2 = 4, /* = CMB_STUB_AIF_2, */ ++ WMT_IC_AIF_3 = 5, /* = CMB_STUB_AIF_3, */ ++ WMT_IC_PIN_MUX = 6, ++ WMT_IC_PIN_GPIO = 7, ++ WMT_IC_PIN_GPIO_HIGH = 8, ++ WMT_IC_PIN_GPIO_LOW = 9, ++ WMT_IC_PIN_STATE_MAX ++} WMT_IC_PIN_STATE, *P_WMT_IC_PIN_STATE; ++ ++typedef enum _WMT_CO_CLOCK_ { ++ WMT_CO_CLOCK_DIS = 0, ++ WMT_CO_CLOCK_EN = 1, ++ WMT_CO_CLOCK_MAX ++} WMT_CO_CLOCK, *P_WMT_CO_CLOCK; ++ ++typedef INT32(*SW_INIT) (P_WMT_HIF_CONF pWmtHifConf); ++typedef INT32(*SW_DEINIT) (P_WMT_HIF_CONF pWmtHifConf); ++typedef INT32(*IC_PIN_CTRL) (WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); ++typedef INT32(*IC_VER_CHECK) (VOID); ++typedef INT32(*CO_CLOCK_CTRL) (WMT_CO_CLOCK on); ++typedef MTK_WCN_BOOL(*IS_QUICK_SLEEP_SUPPORT) (VOID); ++typedef MTK_WCN_BOOL(*IS_AEE_DUMP_SUPPORT) (VOID); ++ ++typedef struct _WMT_IC_OPS_ { ++ UINT32 icId; ++ SW_INIT sw_init; ++ SW_DEINIT sw_deinit; ++ IC_PIN_CTRL ic_pin_ctrl; ++ IC_VER_CHECK ic_ver_check; ++ CO_CLOCK_CTRL co_clock_ctrl; ++ IS_QUICK_SLEEP_SUPPORT is_quick_sleep; ++ IS_AEE_DUMP_SUPPORT is_aee_dump_support; ++} WMT_IC_OPS, *P_WMT_IC_OPS; ++ ++typedef struct _WMT_CTX_ { ++ ENUM_DRV_STS eDrvStatus[WMTDRV_TYPE_MAX]; /* Controlled driver status */ ++ UINT32 wmtInfoBit; /* valid info bit */ ++ WMT_HIF_CONF wmtHifConf; /* HIF information */ ++ ++ /* Pointer to WMT_IC_OPS. Shall be assigned to a correct table in stp_init ++ * if and only if getting chip id successfully. hwver and fwver are kept in ++ * WMT-IC module only. ++ */ ++ P_WMT_IC_OPS p_ic_ops; ++} WMT_CTX, *P_WMT_CTX; ++ ++/* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ ++/* Using this struct relies on compiler's implementation and pack() settings */ ++typedef struct _WMT_PKT_ { ++ UINT8 eType; /* PKT_TYPE_* */ ++ UINT8 eOpCode; /* OPCODE_* */ ++ UINT16 u2SduLen; /* 2 bytes length, little endian */ ++ UINT8 aucParam[32]; ++} WMT_PKT, *P_WMT_PKT; ++ ++/* WMT Packet Format */ ++typedef enum _ENUM_PKT_TYPE { ++ PKT_TYPE_INVALID = 0, ++ PKT_TYPE_CMD = 1, ++ PKT_TYPE_EVENT = 2, ++ _PKT_TYPE_MAX ++} ENUM_PKT_TYPE, *P_ENUM_PKT_TYPE; ++ ++typedef enum _ENUM_OPCODE { ++ OPCODE_INVALID = 0, ++ OPCODE_PATCH = 1, ++ OPCODE_TEST = 2, ++ OPCODE_WAKEUP = 3, ++ OPCODE_HIF = 4, ++ OPCODE_STRAP_CONF = 5, ++ OPCODE_FUNC_CTRL = 6, ++ OPCODE_RESET = 7, ++ OPCODE_INT = 8, ++ OPCODE_MAX ++} ENUM_OPCODE, *P_ENUM_OPCODE; ++ ++typedef enum { ++ WMT_STP_CONF_EN = 0, ++ WMT_STP_CONF_RDY = 1, ++ WMT_STP_CONF_MODE = 2, ++ WMT_STP_CONF_MAX ++} WMT_STP_CONF_TYPE; ++ ++struct init_script { ++ UINT8 *cmd; ++ UINT32 cmdSz; ++ UINT8 *evt; ++ UINT32 evtSz; ++ UINT8 *str; ++}; ++ ++typedef struct _WMT_PATCH { ++ UINT8 ucDateTime[16]; ++ UINT8 ucPLat[4]; ++ UINT16 u2HwVer; ++ UINT16 u2SwVer; ++ UINT32 u4PatchVer; ++} WMT_PATCH, *P_WMT_PATCH; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_CORE_MT6620_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_mt6620; ++#endif ++ ++#if CFG_CORE_MT6628_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_mt6628; ++#endif ++ ++#if CFG_CORE_SOC_SUPPORT ++extern WMT_IC_OPS wmt_ic_ops_soc; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern INT32 wmt_core_init(VOID); ++extern INT32 wmt_core_deinit(VOID); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_wmtd ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++extern INT32 wmt_core_opid(P_WMT_OP pWmtOp); ++ ++extern INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2); ++ ++extern INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn); ++ ++extern INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask); ++ ++extern VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len); ++ ++extern MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer); ++ ++extern INT32 wmt_core_init_script(struct init_script *script, INT32 count); ++ ++extern INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize); ++ ++extern INT32 wmt_core_tx(const PUINT8 pData, UINT32 size, PUINT32 writtenSize, MTK_WCN_BOOL bRawFlag); ++extern MTK_WCN_BOOL wmt_core_is_quick_ps_support(void); ++ ++extern MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void); ++ ++#if CFG_CORE_INTERNAL_TXRX ++extern INT32 wmt_core_lpbk_do_stp_init(void); ++extern INT32 wmt_core_lpbk_do_stp_deinit(void); ++#endif ++ ++extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state); ++#if CFG_WMT_LTE_COEX_HANDLING ++extern VOID wmt_core_set_flag_for_test(UINT32 enable); ++extern UINT32 wmt_core_get_flag_for_test(VOID); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static _osal_inline_ MTK_WCN_BOOL wmt_core_ic_ops_check(P_WMT_IC_OPS p_ops) ++{ ++ if (!p_ops) ++ return MTK_WCN_BOOL_FALSE; ++ ++ if ((NULL == p_ops->sw_init) ++ || (NULL == p_ops->sw_deinit) ++ || (NULL == p_ops->ic_ver_check) ++ || (NULL == p_ops->ic_pin_ctrl)) ++ return MTK_WCN_BOOL_FALSE; ++ else ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++#endif /* _WMT_CORE_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h +new file mode 100644 +index 000000000000..0ff3d6058c39 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h +@@ -0,0 +1,120 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_CTRL_H_ ++#define _WMT_CTRL_H_ ++ ++#include "osal.h" ++#include "wmt_stp_exp.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define DWCNT_CTRL_DATA (16) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _WMT_CTRL_DATA_ { ++ SIZE_T ctrlId; ++ SIZE_T au4CtrlData[DWCNT_CTRL_DATA]; ++} WMT_CTRL_DATA, *P_WMT_CTRL_DATA; ++ ++typedef enum _ENUM_WMT_CTRL_T { ++ WMT_CTRL_HW_PWR_OFF = 0, /* whole chip power off */ ++ WMT_CTRL_HW_PWR_ON = 1, /* whole chip power on */ ++ WMT_CTRL_HW_RST = 2, /* whole chip rst */ ++ WMT_CTRL_STP_CLOSE = 3, ++ WMT_CTRL_STP_OPEN = 4, ++ WMT_CTRL_STP_CONF = 5, ++ WMT_CTRL_FREE_PATCH = 6, ++ WMT_CTRL_GET_PATCH = 7, ++ WMT_CTRL_GET_PATCH_NAME = 8, ++ WMT_CTRL_HWIDVER_SET = 9, /* TODO: rename this and add chip id information in addition to chip version */ ++ WMT_CTRL_STP_RST = 10, ++ WMT_CTRL_GET_WMT_CONF = 11, ++ WMT_CTRL_TX = 12, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ ++ WMT_CTRL_RX = 13, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ ++ WMT_CTRL_RX_FLUSH = 14, /* [FixMe][SeanWang]: to be removed by Sean's stp integration */ ++ WMT_CTRL_GPS_SYNC_SET = 15, ++ WMT_CTRL_GPS_LNA_SET = 16, ++ WMT_CTRL_PATCH_SEARCH = 17, ++ WMT_CTRL_CRYSTAL_TRIMING_GET = 18, ++ WMT_CTRL_CRYSTAL_TRIMING_PUT = 19, ++ WMT_CTRL_HW_STATE_DUMP = 20, ++ WMT_CTRL_GET_PATCH_NUM = 21, ++ WMT_CTRL_GET_PATCH_INFO = 22, ++ WMT_CTRL_SOC_PALDO_CTRL = 23, ++ WMT_CTRL_SOC_WAKEUP_CONSYS = 24, ++ WMT_CTRL_SET_STP_DBG_INFO = 25, ++ WMT_CTRL_BGW_DESENSE_CTRL = 26, ++ WMT_CTRL_EVT_ERR_TRG_ASSERT = 27, ++#if CFG_WMT_LTE_COEX_HANDLING ++ WMT_CTRL_GET_TDM_REQ_ANTSEL = 28, ++#endif ++ WMT_CTRL_EVT_PARSER = 29, ++ WMT_CTRL_MAX ++} ENUM_WMT_CTRL_T, *P_ENUM_WMT_CTRL_T; ++ ++typedef INT32(*WMT_CTRL_FUNC) (P_WMT_CTRL_DATA); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData); ++ ++extern INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_CTRL_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h +new file mode 100644 +index 000000000000..d586f442e7ef +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h +@@ -0,0 +1,140 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_FUNC_H_ ++#define _WMT_FUNC_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_core.h" ++#include "wmt_plat.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_HCI_DRIVER) || defined(CONFIG_MTK_COMBO_BT) */ ++#define CFG_FUNC_BT_SUPPORT 1 ++#else ++#define CFG_FUNC_BT_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_FM) */ ++#define CFG_FUNC_FM_SUPPORT 1 ++#else ++#define CFG_FUNC_FM_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_GPS) */ ++#define CFG_FUNC_GPS_SUPPORT 1 ++#else ++#define CFG_FUNC_GPS_SUPPORT 0 ++#endif ++ ++#if 1 /* defined(CONFIG_MTK_COMBO_WIFI) */ ++#define CFG_FUNC_WIFI_SUPPORT 1 ++#else ++#define CFG_FUNC_WIFI_SUPPORT 0 ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef INT32(*SUBSYS_FUNC_ON) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++typedef INT32(*SUBSYS_FUNC_OFF) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++typedef struct _WMT_FUNC_OPS_ { ++ SUBSYS_FUNC_ON func_on; ++ SUBSYS_FUNC_OFF func_off; ++} WMT_FUNC_OPS, *P_WMT_FUNC_OPS; ++ ++typedef struct _CMB_PIN_CTRL_REG_ { ++ UINT32 regAddr; ++ UINT32 regValue; ++ UINT32 regMask; ++ ++} CMB_PIN_CTRL_REG, *P_CMB_PIN_CTRL_REG; ++ ++typedef struct _CMB_PIN_CTRL_ { ++ UINT32 pinId; ++ UINT32 regNum; ++ P_CMB_PIN_CTRL_REG pFuncOnArray; ++ P_CMB_PIN_CTRL_REG pFuncOffArray; ++ ++} CMB_PIN_CTRL, *P_CMB_PIN_CTRL; ++ ++typedef enum _ENUM_CMP_PIN_ID_ { ++ CMB_PIN_EEDI_ID = 0, ++ CMB_PIN_EEDO_ID = 1, ++ CMB_PIN_GSYNC_ID = 2, ++} ENUM_CMP_PIN_ID, *P_ENUM_CMP_PIN_ID; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_BT_SUPPORT ++extern WMT_FUNC_OPS wmt_func_bt_ops; ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++extern WMT_FUNC_OPS wmt_func_fm_ops; ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++extern WMT_FUNC_OPS wmt_func_gps_ops; ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++extern WMT_FUNC_OPS wmt_func_wifi_ops; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_FUNC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h +new file mode 100644 +index 000000000000..901becfdb92f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h +@@ -0,0 +1,122 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_IC_H_ ++#define _WMT_IC_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "wmt_core.h" ++#include "wmt_exp.h" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define WMT_IC_NAME_MT6620 "MT6620" ++#define WMT_IC_NAME_MT6628 "MT6628" ++#define WMT_IC_NAME_DEFAULT "SOC_CONSYS" ++ ++#define WMT_IC_VER_E1 "E1" ++#define WMT_IC_VER_E2 "E2" ++#define WMT_IC_VER_E3 "E3" ++#define WMT_IC_VER_E4 "E4" ++#define WMT_IC_VER_E5 "E5" ++#define WMT_IC_VER_E6 "E6" ++ ++#define WMT_IC_PATCH_DUMMY_EXT "_ex" ++#define WMT_IC_PATCH_NO_EXT "" ++#define WMT_IC_PATCH_E1_EXT "_e1" ++#define WMT_IC_PATCH_E2_EXT "_e2" ++#define WMT_IC_PATCH_E3_EXT "_e3" ++#define WMT_IC_PATCH_E4_EXT "_e4" ++#define WMT_IC_PATCH_E5_EXT "_e5" ++#define WMT_IC_PATCH_E6_EXT "_e6" ++ ++#define WMT_IC_PATCH_TAIL "_hdr.bin" ++ ++#define WMT_IC_INVALID_CHIP_ID 0xFFFF ++ ++#define MAJORNUM(x) (x & 0x00F0) ++#define MINORNUM(x) (x & 0x000F) ++ ++/******************************************************************************* ++* R E G I S T E R M A P ++******************************************************************************** ++*/ ++/* General definition used for ALL/UNKNOWN CHIPS */ ++/* Now MT6620 uses these definitions */ ++#define GEN_CONFG_BASE (0x80000000UL) ++#define GEN_HVR (GEN_CONFG_BASE + 0x0UL) /* HW_VER */ ++#define GEN_FVR (GEN_CONFG_BASE + 0x4UL) /* FW_VER */ ++#define GEN_VER_MASK (0x0000FFFFUL) /* HW_VER and FW_VER valid bits mask */ ++#define GEN_HCR (GEN_CONFG_BASE + 0x8UL) /* HW_CODE, chip id */ ++#define GEN_HCR_MASK (0x0000FFFFUL) /* HW_CODE valid bits mask */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _WMT_IC_INFO_S { ++ UINT32 u4HwVer; /* u4HwId */ ++ PUINT8 cChipName; ++ PUINT8 cChipVersion; ++ PUINT8 cPatchNameExt; ++ MTK_WCN_BOOL bPsmSupport; ++ MTK_WCN_BOOL bWorkWithoutPatch; ++ ENUM_WMTHWVER_TYPE_T eWmtHwVer; ++} WMT_IC_INFO_S, *P_WMT_IC_INFO_S; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_IC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h +new file mode 100644 +index 000000000000..b0c05cf3a252 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h +@@ -0,0 +1,300 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_LIB_H_ ++#define _WMT_LIB_H_ ++ ++#include "osal.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++#include ++#include "stp_wmt.h" ++#include "wmt_plat.h" ++#include "wmt_idc.h" ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define WMT_OP_BUF_SIZE (16) ++ ++typedef enum _ENUM_WMTRSTRET_TYPE_T { ++ WMTRSTRET_SUCCESS = 0x0, ++ WMTRSTRET_FAIL = 0x1, ++ WMTRSTRET_ONGOING = 0x2, ++ WMTRSTRET_MAX ++} ENUM_WMTRSTRET_TYPE_T, *P_ENUM_WMTRSTRET_TYPE_T; ++ ++/* ++3(retry times) * 180 (STP retry time out) +++ 10 (firmware process time) + ++10 (transmit time) + ++10 (uart process -> WMT response pool) + ++230 (others) ++*/ ++#define WMT_LIB_RX_TIMEOUT 20000 /*800-->cover v1.2phone BT function on time (~830ms) */ ++/* ++open wifi during wifi power on procedure ++(because wlan is insert to system after mtk_hif_sdio module, ++so wifi card is not registered to hif module ++when mtk_wcn_wmt_func_on is called by wifi through rfkill) ++*/ ++#define MAX_WIFI_ON_TIME 55000 ++ ++#define WMT_PWRON_RTY_DFT 2 ++#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT) ++#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY WMT_LIB_RX_TIMEOUT /*each WMT command */ ++#define MAX_FUNC_ON_TIME \ ++ (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT + MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3) ++ ++#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ ++#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4) ++ ++#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ ++ ++#define MAX_GPIO_CTRL_TIME (2000) /* [FixMe][GeorgeKuo] a temp value */ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* AIF FLAG definition */ ++/* bit(0): share pin or not */ ++#define WMT_LIB_AIF_FLAG_MASK (0x1UL) ++#define WMT_LIB_AIF_FLAG_SHARE (0x1UL << 0) ++#define WMT_LIB_AIF_FLAG_SEPARATE (0x0UL << 0) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* bit field offset definition */ ++typedef enum { ++ WMT_STAT_PWR = 0, /* is powered on */ ++ WMT_STAT_STP_REG = 1, /* is STP driver registered: */ ++ WMT_STAT_STP_OPEN = 2, /* is STP opened: default FALSE */ ++ WMT_STAT_STP_EN = 3, /* is STP enabled: default FALSE */ ++ WMT_STAT_STP_RDY = 4, /* is STP ready for client: default FALSE */ ++ WMT_STAT_RX = 5, /* is rx data available */ ++ WMT_STAT_CMD = 6, /* is cmd string to be read */ ++ WMT_STAT_RST_ON = 7, ++ WMT_STAT_MAX ++} WMT_STAT; ++ ++typedef enum _ENUM_WMTRSTSRC_TYPE_T { ++ WMTRSTSRC_RESET_BT = 0x0, ++ WMTRSTSRC_RESET_FM = 0x1, ++ WMTRSTSRC_RESET_GPS = 0x2, ++ WMTRSTSRC_RESET_WIFI = 0x3, ++ WMTRSTSRC_RESET_STP = 0x4, ++ WMTRSTSRC_RESET_TEST = 0x5, ++ WMTRSTSRC_RESET_MAX ++} ENUM_WMTRSTSRC_TYPE_T, *P_ENUM_WMTRSTSRC_TYPE_T; ++ ++typedef struct { ++ PF_WMT_CB fDrvRst[4]; ++} WMT_FDRV_CB, *P_WMT_FDRV_CB; ++ ++typedef struct { ++ UINT32 dowloadSeq; ++ UINT8 addRess[4]; ++ UINT8 patchName[256]; ++} WMT_PATCH_INFO, *P_WMT_PATCH_INFO; ++ ++/* OS independent wrapper for WMT_OP */ ++typedef struct _DEV_WMT_ { ++ ++ OSAL_SLEEPABLE_LOCK psm_lock; ++ OSAL_SLEEPABLE_LOCK idc_lock; ++ /* WMTd thread information */ ++ /* struct task_struct *pWmtd; */ ++ OSAL_THREAD thread; /* main thread (wmtd) handle */ ++ /* wait_queue_head_t rWmtdWq; */ ++ OSAL_EVENT rWmtdWq; /*WMTd command wait queue */ ++ /* ULONG state; */ ++ OSAL_BIT_OP_VAR state; /* bit field of WMT_STAT */ ++ ++ /* STP context information */ ++ /* wait_queue_head_t rWmtRxWq; */ ++ OSAL_EVENT rWmtRxWq; /* STP Rx wait queue */ ++ /* WMT_STP_FUNC rStpFunc; */ ++ WMT_FDRV_CB rFdrvCb; /* STP functions */ ++ ++ /* WMT Configurations */ ++ WMT_HIF_CONF rWmtHifConf; ++ WMT_GEN_CONF rWmtGenConf; ++ ++ /* Patch information */ ++ UINT8 cPatchName[NAME_MAX + 1]; ++ UINT8 cFullPatchName[NAME_MAX + 1]; ++ UINT32 patchNum; ++ ++ const osal_firmware *pPatch; ++ ++ UINT8 cWmtcfgName[NAME_MAX + 1]; ++ const osal_firmware *pWmtCfg; ++ ++ const osal_firmware *pNvram; ++ ++ /* Current used UART port description */ ++ INT8 cUartName[NAME_MAX + 1]; ++ ++ OSAL_OP_Q rFreeOpQ; /* free op queue */ ++ OSAL_OP_Q rActiveOpQ; /* active op queue */ ++ OSAL_OP arQue[WMT_OP_BUF_SIZE]; /* real op instances */ ++ P_OSAL_OP pCurOP; /* current op */ ++ ++ /* cmd str buffer */ ++ UINT8 cCmd[NAME_MAX + 1]; ++ INT32 cmdResult; ++ /* struct completion cmd_comp; */ ++ /* wait_queue_head_t cmd_wq; */ ++ OSAL_SIGNAL cmdResp; /* read command queues */ ++ OSAL_EVENT cmdReq; ++ ++ /* WMT loopback Thread Information */ ++ /* WMT_CMB_VER combo_ver; */ ++ /* P_WMT_CMB_CHIP_INFO_S pChipInfo; */ ++ UINT32 chip_id; ++ UINT32 hw_ver; ++ UINT32 fw_ver; ++ /* TODO: [FixMe][GeorgeKuo] remove this translated version code in the */ ++ /* future. Just return the above 3 info to querist */ ++ ENUM_WMTHWVER_TYPE_T eWmtHwVer; ++ ++ P_WMT_PATCH_INFO pWmtPatchInfo; ++} DEV_WMT, *P_DEV_WMT; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern DEV_WMT gDevWmt; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++extern INT32 wmt_lib_init(VOID); ++extern INT32 wmt_lib_deinit(VOID); ++extern INT32 wmt_lib_tx(PUINT8 data, UINT32 size, PUINT32 writtenSize); ++extern INT32 wmt_lib_tx_raw(PUINT8 data, UINT32 size, PUINT32 writtenSize); ++extern INT32 wmt_lib_rx(PUINT8 buff, UINT32 buffLen, PUINT32 readSize); ++extern VOID wmt_lib_flush_rx(VOID); ++ ++#if CFG_WMT_PS_SUPPORT ++extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime); ++extern INT32 wmt_lib_ps_init(VOID); ++extern INT32 wmt_lib_ps_deinit(VOID); ++extern INT32 wmt_lib_ps_enable(VOID); ++extern INT32 wmt_lib_ps_ctrl(UINT32 state); ++ ++extern INT32 wmt_lib_ps_disable(VOID); ++extern VOID wmt_lib_ps_irq_cb(VOID); ++#endif ++extern VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb); ++ ++/* LXOP functions: */ ++extern P_OSAL_OP wmt_lib_get_free_op(VOID); ++extern INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp); ++extern MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp); ++ ++/* extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); */ ++extern UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T type); ++ ++extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID); ++extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID); ++extern INT32 wmt_lib_trigger_cmd_signal(INT32 result); ++extern PUINT8 wmt_lib_get_cmd(VOID); ++extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID); ++extern INT32 wmt_lib_set_patch_name(PUINT8 cPatchName); ++extern INT32 wmt_lib_set_hif(unsigned long hifconf); ++extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID); ++extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID); ++ ++/* GeorgeKuo: replace set_chip_gpio() with more specific ones */ ++#if 0 /* moved to wmt_exp.h */ ++extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ ++#endif ++extern INT32 wmt_lib_host_awake_get(VOID); ++extern INT32 wmt_lib_host_awake_put(VOID); ++extern UINT32 wmt_lib_dbg_level_set(UINT32 level); ++ ++extern INT32 wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++extern INT32 wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src); ++MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst); ++MTK_WCN_BOOL wmt_lib_hw_rst(VOID); ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); ++INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); ++ ++extern INT32 DISABLE_PSM_MONITOR(void); ++extern VOID ENABLE_PSM_MONITOR(void); ++extern INT32 wmt_lib_notify_stp_sleep(void); ++extern void wmt_lib_psm_lock_release(void); ++extern INT32 wmt_lib_psm_lock_aquire(void); ++extern VOID wmt_lib_idc_lock_release(VOID); ++extern INT32 wmt_lib_idc_lock_aquire(VOID); ++extern INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value); ++ ++extern VOID wmt_lib_set_patch_num(UINT32 num); ++extern VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo); ++extern INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp); ++extern P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev); ++extern PUINT8 wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, PUINT8 buff, UINT32 len); ++extern INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee); ++extern PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 len); ++extern INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl); ++extern UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en); ++extern INT8 wmt_lib_co_clock_get(VOID); ++extern UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver); ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++extern MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor); ++#endif ++#if CFG_WMT_PS_SUPPORT ++extern UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en); ++#endif ++#if CONSYS_ENALBE_SET_JTAG ++extern UINT32 wmt_lib_jtag_flag_set(UINT32 en); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_LIB_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c +new file mode 100644 +index 000000000000..c826c513e2bd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c +@@ -0,0 +1,1890 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "psm_core.h" ++#include "stp_core.h" ++#include ++ ++INT32 gPsmDbgLevel = STP_PSM_LOG_INFO; ++MTKSTP_PSM_T stp_psm_i; ++MTKSTP_PSM_T *stp_psm = &stp_psm_i; ++ ++STP_PSM_RECORD_T *g_stp_psm_dbg = NULL; ++static UINT32 g_record_num; ++ ++P_STP_PSM_OPID_RECORD g_stp_psm_opid_dbg = NULL; ++static UINT32 g_opid_record_num; ++ ++#define STP_PSM_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) \ ++ pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ ++ pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_INFO) \ ++ pr_debug(PFX_PSM "[I]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_WARN) \ ++ pr_warn(PFX_PSM "[W]%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_PSM_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_ERR) \ ++ pr_err(PFX_PSM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define STP_PSM_TRC_FUNC(f) \ ++do { \ ++ if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ ++ pr_debug(PFX_PSM "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); ++static INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); ++static INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); ++static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num); ++static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg); ++ ++static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num); ++static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg); ++ ++static const char *g_psm_state[STP_PSM_MAX_STATE] = { ++ "ACT", ++ "ACT_INACT", ++ "INACT", ++ "INACT_ACT" ++}; ++ ++static const char *g_psm_action[STP_PSM_MAX_ACTION] = { ++ "SLEEP", ++ "HOST_AWAKE", ++ "WAKEUP", ++ "EIRQ", ++ "ROLL_BACK" ++}; ++ ++static const char *g_psm_op_name[STP_OPID_PSM_NUM] = { ++ "STP_OPID_PSM_SLEEP", ++ "STP_OPID_PSM_WAKEUP", ++ "STP_OPID_PSM_HOST_AWAKE", ++ "STP_OPID_PSM_EXIT" ++}; ++ ++static int _stp_psm_release_data(MTKSTP_PSM_T *stp_psm); ++ ++static inline int _stp_psm_get_state(MTKSTP_PSM_T *stp_psm); ++ ++static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ); ++ ++static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ); ++static MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID); ++ ++MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel) ++{ ++ if (dbglevel <= 4) { ++ gPsmDbgLevel = dbglevel; ++ STP_PSM_INFO_FUNC("gPsmDbgLevel = %d\n", gPsmDbgLevel); ++ return true; ++ } ++ STP_PSM_INFO_FUNC("invalid psm debug level. gPsmDbgLevel = %d\n", gPsmDbgLevel); ++ ++ return false; ++} ++ ++static INT32 _stp_psm_handler(MTKSTP_PSM_T *stp_psm, P_STP_OP pStpOp) ++{ ++ INT32 ret = -1; ++ ++ /* if (NULL == pStpOp) */ ++ /* { */ ++ /* return -1; */ ++ /* } */ ++ ret = _stp_psm_thread_lock_aquire(stp_psm); ++ if (ret) { ++ STP_PSM_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ switch (pStpOp->opId) { ++ case STP_OPID_PSM_EXIT: ++ /* TODO: clean all up? */ ++ ret = 0; ++ break; ++ ++ case STP_OPID_PSM_SLEEP: ++ if (stp_psm_check_sleep_enable(stp_psm) > 0) ++ ret = _stp_psm_notify_wmt(stp_psm, SLEEP); ++ else ++ STP_PSM_INFO_FUNC("cancel sleep request\n"); ++ ++ break; ++ ++ case STP_OPID_PSM_WAKEUP: ++ ret = _stp_psm_notify_wmt(stp_psm, WAKEUP); ++ break; ++ ++ case STP_OPID_PSM_HOST_AWAKE: ++ ret = _stp_psm_notify_wmt(stp_psm, HOST_AWAKE); ++ break; ++ ++ default: ++ STP_PSM_ERR_FUNC("invalid operation id (%d)\n", pStpOp->opId); ++ ret = -1; ++ break; ++ } ++ _stp_psm_thread_lock_release(stp_psm); ++ return ret; ++} ++ ++static P_OSAL_OP _stp_psm_get_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ ++ if (!pOpQ) { ++ STP_PSM_WARN_FUNC("pOpQ == NULL\n"); ++ return NULL; ++ } ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) { ++ /* stp_psm->current_active_op = pOp; */ ++ stp_psm->last_active_opId = pOp->op.opId; ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) ++ STP_PSM_DBG_FUNC("last_active_opId(%d)\n", stp_psm->last_active_opId); ++ ++ if (!pOp) ++ STP_PSM_WARN_FUNC("RB_GET fail\n"); ++ ++ return pOp; ++} ++ ++static INT32 _stp_psm_dump_active_q(P_OSAL_OP_Q pOpQ) ++{ ++ UINT32 read_idx; ++ UINT32 write_idx; ++ UINT32 opId; ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ read_idx = stp_psm->rActiveOpQ.read; ++ write_idx = stp_psm->rActiveOpQ.write; ++ ++ STP_PSM_DBG_FUNC("Active op list:++\n"); ++ while ((read_idx & RB_MASK(pOpQ)) != (write_idx & RB_MASK(pOpQ))) { ++ opId = pOpQ->queue[read_idx & RB_MASK(pOpQ)]->op.opId; ++ if (opId < STP_OPID_PSM_NUM) ++ STP_PSM_DBG_FUNC("%s\n", g_psm_op_name[opId]); ++ else ++ STP_PSM_WARN_FUNC("Unknown OP Id\n"); ++ ++ ++read_idx; ++ } ++ STP_PSM_DBG_FUNC("Active op list:--\n"); ++ } else { ++ STP_PSM_DBG_FUNC("%s: not active queue, dont dump\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ) ++{ ++ unsigned int opId = 0; ++ unsigned int prev_opId = 0; ++ ++ /* if((pOpQ == &stp_psm->rActiveOpQ) && (NULL != stp_psm->current_active_op)) */ ++ if ((pOpQ == &stp_psm->rActiveOpQ) && (STP_OPID_PSM_INALID != stp_psm->last_active_opId)) { ++ opId = pOp->op.opId; ++ ++ if (opId == STP_OPID_PSM_SLEEP) { ++ if (RB_EMPTY(pOpQ)) { ++ /* prev_opId = stp_psm->current_active_op->op.opId; */ ++ prev_opId = stp_psm->last_active_opId; ++ } else { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ } ++ ++ if (prev_opId == STP_OPID_PSM_SLEEP) { ++ STP_PSM_DBG_FUNC("redundant sleep opId found\n"); ++ return 1; ++ } else { ++ return 0; ++ } ++ } else { ++ if (RB_EMPTY(pOpQ)) { ++ /* prev_opId = stp_psm->current_active_op->op.opId; */ ++ prev_opId = stp_psm->last_active_opId; ++ } else { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ } ++ ++ if (((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_WAKEUP)) || ++ ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_WAKEUP)) || ++ ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) || ++ ((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) ++ ) { ++ STP_PSM_DBG_FUNC("redundant opId found, opId(%d), preOpid(%d)\n", opId, prev_opId); ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++ } else { ++ return 0; ++ } ++ ++} ++ ++static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ) ++{ ++ unsigned int prev_opId = 0; ++ unsigned int prev_prev_opId = 0; ++ ++ P_OSAL_OP pOp; ++ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ /* sleep , wakeup | sleep, --> null | sleep (x) */ ++ /* wakeup , sleep , wakeup | sleep --> wakeup | sleep (v) */ ++ /* sleep , wakeup , sleep | wakeup --> sleep | wakeup (v) */ ++ /* xxx, sleep | sleep --> xxx, sleep (v) */ ++ /* xxx, wakeup | wakeup --> xxx, wakeup (v) */ ++ /* xxx, awake | awake --> xxx, awake (v) --> should never happen */ ++ while (RB_COUNT(pOpQ) > 2) { ++ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; ++ prev_prev_opId = pOpQ->queue[(pOpQ->write - 2) & RB_MASK(pOpQ)]->op.opId; ++ ++ if ((prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_WAKEUP) || ++ (prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE) || ++ (prev_opId == STP_OPID_PSM_WAKEUP && prev_prev_opId == STP_OPID_PSM_SLEEP) || ++ (prev_opId == STP_OPID_PSM_HOST_AWAKE && prev_prev_opId == STP_OPID_PSM_SLEEP) ++ ) { ++ RB_GET(pOpQ, pOp); ++ RB_PUT(pFreeOpQ, pOp); ++ RB_GET(pOpQ, pOp); ++ RB_PUT(pFreeOpQ, pOp); ++ } else if (prev_opId == prev_prev_opId) { ++ RB_GET(pOpQ, pOp); ++ STP_PSM_DBG_FUNC("redundant opId(%d) found, remove it\n", pOp->op.opId); ++ RB_PUT(pFreeOpQ, pOp); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static INT32 _stp_psm_put_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 ret; ++ ++ /* if (!pOpQ || !pOp) */ ++ /* { */ ++ /* STP_PSM_WARN_FUNC("pOpQ = 0x%p, pLxOp = 0x%p\n", pOpQ, pOp); */ ++ /* return 0; */ ++ /* } */ ++ ret = 0; ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* acquire lock success */ ++ if (pOpQ == &stp_psm->rActiveOpQ) { ++ if (!_stp_psm_is_redundant_active_op(pOp, pOpQ)) { ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) { ++ RB_PUT(pOpQ, pOp); ++ STP_PSM_DBG_FUNC("opId(%d) enqueue\n", pOp->op.opId); ++ } else { ++ STP_PSM_INFO_FUNC("************ Active Queue Full ************\n"); ++ ret = -1; ++ } ++ ++ _stp_psm_clean_up_redundant_active_op(pOpQ); ++ } else { ++ /*redundant opId, mark ret as success */ ++ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; ++ ++ if (!RB_FULL(pFreeOpQ)) ++ RB_PUT(pFreeOpQ, pOp); ++ else ++ osal_assert(!RB_FULL(pFreeOpQ)); ++ ++ ret = 0; ++ } ++ } else { ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ ret = -1; ++ ++ } ++ ++ if (pOpQ == &stp_psm->rActiveOpQ) ++ _stp_psm_dump_active_q(&stp_psm->rActiveOpQ); ++ ++ ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ STP_PSM_DBG_FUNC("stp_psm do unlock,active queue? (%s)\n", (pOpQ == &stp_psm->rActiveOpQ) ? "y" : "n"); ++ ++ if (ret) { ++ STP_PSM_WARN_FUNC("RB_FULL, RB_COUNT=%d , RB_SIZE=%d\n", RB_COUNT(pOpQ), RB_SIZE(pOpQ)); ++ return 0; ++ } else ++ return 1; ++ ++} ++ ++P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ ++ if (stp_psm) { ++ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, sizeof(pOp->op)); ++ ++ return pOp; ++ } else ++ return NULL; ++ ++} ++ ++INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp) ++{ ++ INT32 bRet = 0; /* MTK_WCN_BOOL_FALSE; */ ++ INT32 bCleanup = 0; /* MTK_WCN_BOOL_FALSE; */ ++ INT32 wait_ret = -1; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ do { ++ if (!stp_psm || !pOp) { ++ STP_PSM_ERR_FUNC("stp_psm = %p, pOp = %p\n", stp_psm, pOp); ++ break; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(&pOp->signal); ++ } ++ ++ /* put to active Q */ ++ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rActiveOpQ, pOp); ++ ++ if (0 == bRet) { ++ STP_PSM_WARN_FUNC("+++++++++++ Put op Active queue Fail\n"); ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ break; ++ } ++ _stp_psm_opid_dbg_dmp_in(g_stp_psm_opid_dbg, pOp->op.opId, __LINE__); ++ ++ /* wake up wmtd */ ++ osal_trigger_event(&stp_psm->STPd_event); ++ ++ if (pSignal->timeoutValue == 0) { ++ bRet = 1; /* MTK_WCN_BOOL_TRUE; */ ++ /* clean it in wmtd */ ++ break; ++ } ++ ++ /* wait result, clean it here */ ++ bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ ++ ++ /* check result */ ++ wait_ret = osal_wait_for_signal_timeout(&pOp->signal); ++ STP_PSM_DBG_FUNC("wait completion:%d\n", wait_ret); ++ if (!wait_ret) { ++ STP_PSM_ERR_FUNC("wait completion timeout\n"); ++ /* TODO: how to handle it? retry? */ ++ } else { ++ if (pOp->result) ++ STP_PSM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); ++ /* op completes, check result */ ++ bRet = (pOp->result) ? 0 : 1; ++ } ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp); ++ if (bRet == 0) ++ STP_PSM_WARN_FUNC("+++++++++++ Put op active free fail, maybe disable/enable psm\n"); ++ } ++ ++ return bRet; ++} ++ ++static INT32 _stp_psm_wait_for_msg(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ ++ STP_PSM_DBG_FUNC("%s: stp_psm->rActiveOpQ = %d\n", __func__, RB_COUNT(&stp_psm->rActiveOpQ)); ++ ++ return (!RB_EMPTY(&stp_psm->rActiveOpQ)) || osal_thread_should_stop(&stp_psm->PSMd); ++} ++ ++static INT32 _stp_psm_proc(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ P_OSAL_OP pOp; ++ UINT32 id; ++ INT32 result; ++ ++ if (!stp_psm) { ++ STP_PSM_WARN_FUNC("!stp_psm\n"); ++ return -1; ++ } ++/* STP_PSM_INFO_FUNC("wmtd starts running: pWmtDev(0x%p) [pol, rt_pri, n_pri, pri]=[%d, %d, %d, %d]\n", */ ++/* stp_psm, current->policy, current->rt_priority, current->normal_prio, current->prio); */ ++ ++ for (;;) { ++ ++ pOp = NULL; ++ ++ osal_wait_for_event(&stp_psm->STPd_event, _stp_psm_wait_for_msg, (void *)stp_psm); ++ ++ /* we set reset flag when calling stp_reset after cleanup all op. */ ++ if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_RESET_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ if (osal_thread_should_stop(&stp_psm->PSMd)) { ++ STP_PSM_INFO_FUNC("should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rActiveOpQ); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("+++++++++++ Get op from activeQ fail, maybe disable/enable psm\n"); ++ continue; ++ } ++ ++ id = osal_op_get_id(pOp); ++ ++ if (id >= STP_OPID_PSM_NUM) { ++ STP_PSM_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ result = -1; ++ goto handler_done; ++ } ++ ++ result = _stp_psm_handler(stp_psm, &pOp->op); ++ ++handler_done: ++ ++ if (result) { ++ STP_PSM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, ++ (id >= 4) ? ("???") : (g_psm_op_name[id]), result); ++ } ++ ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, result); ++ else { ++ /* put Op back to freeQ */ ++ if (_stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp) == 0) ++ STP_PSM_WARN_FUNC("+++++++++++ Put op to FreeOpQ fail, maybe disable/enable psm\n"); ++ } ++ ++ if (STP_OPID_PSM_EXIT == id) ++ break; ++ } ++ STP_PSM_INFO_FUNC("exits\n"); ++ ++ return 0; ++}; ++ ++static inline INT32 _stp_psm_get_time(void) ++{ ++ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) ++ osal_printtimeofday(">>>"); ++ ++ return 0; ++} ++ ++static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (stp_psm->work_state < STP_PSM_MAX_STATE) ++ return stp_psm->work_state; ++ STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); ++ ++ return STP_PSM_OPERATION_FAIL; ++} ++ ++static inline INT32 _stp_psm_set_state(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_STATE_T state) ++{ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (stp_psm->work_state < STP_PSM_MAX_STATE) { ++ _stp_psm_get_time(); ++ /* STP_PSM_INFO_FUNC("work_state = %s --> %s\n", ++ * g_psm_state[stp_psm->work_state], g_psm_state[state]); ++ */ ++ ++ stp_psm->work_state = state; ++ if (stp_psm->work_state != ACT) { ++ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ osal_set_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ } ++ } else ++ STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); ++ ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_DBG_FUNC("STP-PSM DISABLE, DONT restart monitor!\n\r"); ++ return STP_PSM_OPERATION_SUCCESS; ++ } ++ ++ STP_PSM_LOUD_FUNC("start monitor\n"); ++ osal_timer_modify(&stp_psm->psm_timer, stp_psm->idle_time_to_sleep); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_stop_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_DBG_FUNC("stop monitor\n"); ++ osal_timer_stop_sync(&stp_psm->psm_timer); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++INT32 _stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) ++{ ++ INT32 available_space = 0; ++ INT32 needed_space = 0; ++ UINT8 delimiter[] = { 0xbb, 0xbb }; ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ available_space = STP_PSM_FIFO_SIZE - osal_fifo_len(&stp_psm->hold_fifo); ++ needed_space = len + sizeof(UINT8) + sizeof(UINT32) + 2; ++ ++ /* STP_PSM_INFO_FUNC("*******FIFO Available(%d), Need(%d)\n", available_space, needed_space); */ ++ ++ if (available_space < needed_space) { ++ STP_PSM_ERR_FUNC("FIFO Available!! Reset FIFO\n"); ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ } ++ /* type */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); ++ /* length */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); ++ /* buffer */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) buffer, len); ++ /* delimiter */ ++ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); ++ ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ return len; ++ ++} ++ ++INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return osal_fifo_len(&stp_psm->hold_fifo); ++} ++ ++INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 i = 20; /*Max buffered packet number */ ++ INT32 ret = 0; ++ UINT8 type = 0; ++ UINT32 len = 0; ++ UINT8 delimiter[2]; ++ ++ /* STP_PSM_ERR_FUNC("++++++++++release data++len=%d\n", osal_fifo_len(&stp_psm->hold_fifo)); */ ++ while (osal_fifo_len(&stp_psm->hold_fifo) && i > 0) { ++ /* acquire spinlock */ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); ++ ++ if (len > STP_PSM_PACKET_SIZE_MAX) { ++ STP_PSM_ERR_FUNC("***psm packet's length too Long!****\n"); ++ STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); ++ } else { ++ osal_memset(stp_psm->out_buf, 0, STP_PSM_TX_SIZE); ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) stp_psm->out_buf, len); ++ } ++ ++ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); ++ ++ if (delimiter[0] == 0xbb && delimiter[1] == 0xbb) { ++ /* osal_buffer_dump(stp_psm->out_buf, "psm->out_buf", len, 32); */ ++ stp_send_data_no_ps(stp_psm->out_buf, len, type); ++ } else { ++ STP_PSM_ERR_FUNC("***psm packet fifo parsing fail****\n"); ++ STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); ++ ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ } ++ i--; ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ } ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_host_awake_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_HOST_AWAKE; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ ++ STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 0; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_wakeup_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_WAKEUP; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ if (0 == bRet) { ++ STP_PSM_WARN_FUNC("OPID(%d) type(%zd) bRet(%s)\n\n", ++ pOp->op.opId, pOp->op.au4OpData[0], "fail"); ++ } ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : (STP_PSM_OPERATION_SUCCESS); ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_wmt_sleep_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ P_OSAL_OP pOp; ++ INT32 bRet; ++ INT32 retval; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag)) ++ return 0; ++#if PSM_USE_COUNT_PACKAGE ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag)) ++ return 0; ++#endif ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) ++ return 0; ++ ++ pOp = _stp_psm_get_free_op(stp_psm); ++ if (!pOp) { ++ STP_PSM_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; /* break; */ ++ } ++ ++ pOp->op.opId = STP_OPID_PSM_SLEEP; ++ pOp->signal.timeoutValue = 0; ++ bRet = _stp_psm_put_act_op(stp_psm, pOp); ++ ++ STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); ++ ++ retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 1; ++ ++ return retval; ++} ++ ++/*internal function*/ ++ ++static inline INT32 _stp_psm_reset(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 i = 0; ++ P_OSAL_OP_Q pOpQ; ++ P_OSAL_OP pOp; ++ ++ STP_PSM_DBG_FUNC("PSM MODE RESET=============================>\n\r"); ++ ++ STP_PSM_DBG_FUNC("_stp_psm_reset\n"); ++ STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_unlock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ /* --> disable psm <--// */ ++ stp_psm->flag.data = 0; ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_stop_monitor(stp_psm); ++ ++ /* --> prepare the op list <--// */ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); ++ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); ++ ++ /* stp_psm->current_active_op = NULL; */ ++ stp_psm->last_active_opId = STP_OPID_PSM_INALID; ++ ++ pOpQ = &stp_psm->rFreeOpQ; ++ for (i = 0; i < STP_OP_BUF_SIZE; i++) { ++ if (!RB_FULL(pOpQ)) { ++ pOp = &stp_psm->arQue[i]; ++ RB_PUT(pOpQ, pOp); ++ } ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ /* --> clean up interal data structure<--// */ ++ _stp_psm_set_state(stp_psm, ACT); ++ ++ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); ++ ++ /* --> stop psm thread wait <--// */ ++ osal_set_bit(STP_PSM_RESET_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ ++ STP_PSM_DBG_FUNC("PSM MODE RESET<============================\n\r"); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static INT32 _stp_psm_wait_wmt_event(void *pvData) ++{ ++ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; ++ ++ STP_PSM_DBG_FUNC("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data); ++ ++ return (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) || ++ (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)); ++} ++ ++static inline INT32 _stp_psm_wait_wmt_event_wq(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 retval = 0; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ osal_wait_for_event_timeout(&stp_psm->wait_wmt_q, _stp_psm_wait_wmt_event, (void *)stp_psm); ++ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ /* STP send data here: STP enqueue data to psm buffer. */ ++ _stp_psm_release_data(stp_psm); ++ /* STP send data here: STP enqueue data to psm buffer. We release packet by the next one. */ ++ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* STP send data here: STP sends data directly without PSM. */ ++ _stp_psm_set_state(stp_psm, ACT); ++/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ ++ if (stp_psm_is_quick_ps_support()) ++ stp_psm_notify_wmt_sleep(stp_psm); ++ else ++ _stp_psm_start_monitor(stp_psm); ++ } else if (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_set_state(stp_psm, INACT); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle++\n"); ++ mt_combo_plt_enter_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle--\n"); ++ ++ STP_PSM_DBG_FUNC("sleep-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_unlock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("sleep-wake_lock#(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ } else if (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ if (_stp_psm_get_state(stp_psm) == ACT_INACT) { ++ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ _stp_psm_release_data(stp_psm); ++ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ _stp_psm_set_state(stp_psm, ACT); ++ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ } else if (_stp_psm_get_state(stp_psm) == INACT_ACT) { ++ _stp_psm_set_state(stp_psm, INACT); ++ STP_PSM_INFO_FUNC("[WARNING]PSM state rollback due too wakeup fail\n"); ++ } ++ } else if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } else { ++ STP_PSM_ERR_FUNC("flag = %ld<== Abnormal flag be set!!\n\r", stp_psm->flag.data); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ wcn_psm_flag_trigger_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ } ++ retval = STP_PSM_OPERATION_SUCCESS; ++ ++ return retval; ++} ++ ++static inline INT32 _stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ ++ INT32 retval = 0; ++ ++ if (action == EIRQ) { ++ STP_PSM_DBG_FUNC("Call _stp_psm_notify_wmt_host_awake_wq\n\r"); ++ ++ _stp_psm_notify_wmt_host_awake_wq(stp_psm); ++ ++ return STP_PSM_OPERATION_FAIL; ++ } ++ ++ if ((_stp_psm_get_state(stp_psm) < STP_PSM_MAX_STATE) && (_stp_psm_get_state(stp_psm) >= 0)) { ++ STP_PSM_DBG_FUNC("state = %s, action=%s\n\r", g_psm_state[_stp_psm_get_state(stp_psm)], ++ g_psm_action[action]); ++ } ++ /* If STP trigger WAKEUP and SLEEP, to do the job below */ ++ switch (_stp_psm_get_state(stp_psm)) { ++ /* stp trigger */ ++ case ACT_INACT: ++ ++ if (action == SLEEP) { ++ STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, ready to INACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == ROLL_BACK) { ++ STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, back to ACT\n\r", g_psm_action[action]); ++ /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */ ++ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else { ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, ACT_INACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ } ++ break; ++ /* stp trigger */ ++ ++ case INACT_ACT: ++ ++ if (action == WAKEUP) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == HOST_AWAKE) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); ++ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else if (action == ROLL_BACK) { ++ STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, back to INACT\n\r", g_psm_action[action]); ++ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ /* wake_up(&stp_psm->wait_wmt_q); */ ++ osal_trigger_event(&stp_psm->wait_wmt_q); ++ } else { ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, INACT_ACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ } ++ break; ++ ++ case INACT: ++ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, INACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = -1; ++ ++ break; ++ ++ case ACT: ++ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, ACT state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ ++ default: ++ ++ /*invalid */ ++ if (action < STP_PSM_MAX_ACTION) { ++ STP_PSM_ERR_FUNC("Action = %s, Invalid state, the case should not happens\n\r", ++ g_psm_action[action]); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ } else { ++ STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); ++ } ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ retval = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ } ++ ++ return retval; ++ ++} ++ ++static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm == NULL) ++ return STP_PSM_OPERATION_FAIL; ++ ++ switch (_stp_psm_get_state(stp_psm)) { ++ case ACT: ++ ++ if (action == SLEEP) { ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_ERR_FUNC("psm monitor disabled, can't do sleep op\n"); ++ return STP_PSM_OPERATION_FAIL; ++ } ++ ++ _stp_psm_set_state(stp_psm, ACT_INACT); ++ ++ _stp_psm_release_data(stp_psm); ++ ++ if (stp_psm->wmt_notify) { ++ stp_psm->wmt_notify(SLEEP); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == WAKEUP || action == HOST_AWAKE) { ++ STP_PSM_INFO_FUNC("In ACT state, dont do WAKEUP/HOST_AWAKE again\n"); ++ _stp_psm_release_data(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ ++ } ++ ++ break; ++ ++ case INACT: ++ ++ if (action == WAKEUP) { ++ _stp_psm_set_state(stp_psm, INACT_ACT); ++ ++ if (stp_psm->wmt_notify) { ++ STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); ++ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); ++ ++ stp_psm->wmt_notify(WAKEUP); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == HOST_AWAKE) { ++ _stp_psm_set_state(stp_psm, INACT_ACT); ++ ++ if (stp_psm->wmt_notify) { ++ STP_PSM_DBG_FUNC("host awake +wake_lock(%d)\n", ++ osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("host awake +wake_lock(%d)#\n", ++ osal_wake_lock_count(&stp_psm->wake_lock)); ++ ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); ++ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); ++ STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); ++ ++ stp_psm->wmt_notify(HOST_AWAKE); ++ _stp_psm_wait_wmt_event_wq(stp_psm); ++ } else { ++ STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ } else if (action == SLEEP) { ++ STP_PSM_INFO_FUNC("In INACT state, dont do SLEEP again\n"); ++ } else { ++ STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ } ++ ++ break; ++ ++ default: ++ ++ /*invalid */ ++ STP_PSM_ERR_FUNC("invalid state, the case should not happen\n"); ++ STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); ++ _stp_psm_dbg_out_printk(g_stp_psm_dbg); ++ ret = STP_PSM_OPERATION_FAIL; ++ ++ break; ++ } ++ return ret; ++} ++ ++static inline void _stp_psm_stp_is_idle(/*unsigned long data*/struct timer_list *t) ++{ ++ //MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) data; ++ MTKSTP_PSM_T *stp_psm = from_timer(stp_psm,t,psm_timer.timer); ++ ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { ++ STP_PSM_DBG_FUNC("STP-PSM DISABLE!\n"); ++ return; ++ } ++ ++ if (1 == _stp_psm_notify_wmt_sleep_wq(stp_psm)) ++ STP_PSM_INFO_FUNC("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep); ++} ++ ++static inline INT32 _stp_psm_init_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_INFO_FUNC("init monitor\n"); ++ ++ stp_psm->psm_timer.timeoutHandler = _stp_psm_stp_is_idle; ++ stp_psm->psm_timer.timeroutHandlerData = (unsigned long)stp_psm; ++ osal_timer_create(&stp_psm->psm_timer); ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_deinit_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_INFO_FUNC("deinit monitor\n"); ++ ++ osal_timer_stop_sync(&stp_psm->psm_timer); ++ ++ return 0; ++} ++ ++static inline INT32 _stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 iRet = -1; ++ ++/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ ++ if (osal_test_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag)) ++ iRet = 1; ++ else ++ iRet = 0; ++ ++/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ ++ return iRet; ++} ++ ++static inline INT32 _stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) ++ return 1; ++ else ++ return 0; ++} ++ ++static inline INT32 _stp_psm_do_wait(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) ++{ ++ ++#define POLL_WAIT 20 /* 200 */ ++#define POLL_WAIT_TIME 2000 ++ ++ INT32 i = 0; ++ INT32 limit = POLL_WAIT_TIME / POLL_WAIT; ++ ++ while (_stp_psm_get_state(stp_psm) != state && i < limit) { ++ osal_sleep_ms(POLL_WAIT); ++ i++; ++ STP_PSM_INFO_FUNC("STP is waiting state for %s, i=%d, state = %d\n", g_psm_state[state], i, ++ _stp_psm_get_state(stp_psm)); ++ } ++ ++ if (i == limit) { ++ STP_PSM_WARN_FUNC("-Wait for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); ++ _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg); ++ return STP_PSM_OPERATION_FAIL; ++ } ++ STP_PSM_DBG_FUNC("+Total waits for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); ++ /* _stp_psm_dbg_out_printk(g_stp_psm_opid_dbg); */ ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ INT32 ret = 0; ++ INT32 retry = 10; ++ P_OSAL_OP_Q pOpQ; ++ P_OSAL_OP pOp; ++ ++ STP_PSM_LOUD_FUNC("*** Do Force Wakeup!***\n\r"); ++ ++ /* <1>If timer is active, we will stop it. */ ++ _stp_psm_stop_monitor(stp_psm); ++ ++ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ ++ pOpQ = &stp_psm->rFreeOpQ; ++ ++ while (!RB_EMPTY(&stp_psm->rActiveOpQ)) { ++ RB_GET(&stp_psm->rActiveOpQ, pOp); ++ if (NULL != pOp && !RB_FULL(pOpQ)) { ++ STP_PSM_DBG_FUNC("opid = %d\n", pOp->op.opId); ++ RB_PUT(pOpQ, pOp); ++ } else { ++ STP_PSM_ERR_FUNC("clear up active queue fail, freeQ full\n"); ++ } ++ } ++ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); ++ /* <5>We issue wakeup request into op queue. and wait for active. */ ++ do { ++ ret = _stp_psm_notify_wmt_wakeup_wq(stp_psm); ++ ++ if (ret == STP_PSM_OPERATION_SUCCESS) { ++ ret = _stp_psm_do_wait(stp_psm, ACT); ++ ++ /* STP_PSM_INFO_FUNC("<< wait ret = %d, num of activeQ = %d\n", ++ * ret, RB_COUNT(&stp_psm->rActiveOpQ)); ++ */ ++ if (ret == STP_PSM_OPERATION_SUCCESS) ++ break; ++ } else ++ STP_PSM_ERR_FUNC("_stp_psm_notify_wmt_wakeup_wq fail!!\n"); ++ ++ /* STP_PSM_INFO_FUNC("retry = %d\n", retry); */ ++ retry--; ++ ++ if (retry == 0) ++ break; ++ } while (1); ++ ++ if (retry == 0) ++ return STP_PSM_OPERATION_FAIL; ++ else ++ return STP_PSM_OPERATION_SUCCESS; ++} ++ ++static inline INT32 _stp_psm_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_DBG_FUNC("PSM Disable start\n\r"); ++ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ ret = _stp_psm_do_wakeup(stp_psm); ++ if (ret == STP_PSM_OPERATION_SUCCESS) ++ STP_PSM_DBG_FUNC("PSM Disable Success\n"); ++ else ++ STP_PSM_ERR_FUNC("***PSM Disable Fail***\n"); ++ ++ return ret; ++} ++ ++static inline INT32 _stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) ++{ ++ INT32 ret = STP_PSM_OPERATION_FAIL; ++ ++ STP_PSM_LOUD_FUNC("PSM Enable start\n\r"); ++ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ ++ ret = _stp_psm_do_wakeup(stp_psm); ++ if (ret == STP_PSM_OPERATION_SUCCESS) { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm->idle_time_to_sleep = idle_time_to_sleep; ++ ++ if (osal_wake_lock_count(&stp_psm->wake_lock) == 0) { ++ STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ osal_wake_lock(&stp_psm->wake_lock); ++ STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); ++ } ++ ++ _stp_psm_start_monitor(stp_psm); ++ ++ STP_PSM_DBG_FUNC("PSM Enable succeed\n\r"); ++ } else ++ STP_PSM_ERR_FUNC("***PSM Enable Fail***\n"); ++ ++ return ret; ++} ++ ++INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) ++{ ++ return osal_lock_sleepable_lock(&stp_psm->stp_psm_lock); ++} ++ ++INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) ++{ ++ osal_unlock_sleepable_lock(&stp_psm->stp_psm_lock); ++ return 0; ++} ++ ++MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID) ++{ ++ if (stp_psm->is_wmt_quick_ps_support) ++ return (*(stp_psm->is_wmt_quick_ps_support)) (); ++ ++ STP_PSM_DBG_FUNC("stp_psm->is_wmt_quick_ps_support is NULL, return false\n\r"); ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID) ++{ ++ return _stp_psm_is_quick_ps_support(); ++} ++ ++#if PSM_USE_COUNT_PACKAGE ++int stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, int dir) ++{ ++ ++ /* easy the variable maintain beween stp tx, rx thread. */ ++ /* so we create variable for tx, rx respectively. */ ++ ++ static int tx_cnt; ++ static int rx_cnt; ++ static int is_tx_first = 1; ++ static int is_rx_first = 1; ++ static unsigned long tx_end_time; ++ static unsigned long rx_end_time; ++ ++ /* */ ++ /* BT A2DP TX CNT = 220, RX CNT = 843 */ ++ /* BT FTP Transferring TX CNT = 574, RX CNT = 2233 (1228~1588) */ ++ /* BT FTP Receiving TX CNT = 204, RX CNT = 3301 (2072~2515) */ ++ /* BT OPP Tx TX_CNT= 330, RX CNT = 1300~1800 */ ++ /* BT OPP Rx TX_CNT= (109~157), RX CNT = 1681~2436 */ ++ if (dir == 0) { /* tx */ ++ ++ tx_cnt++; ++ ++ if (((long)jiffies - (long)tx_end_time >= 0) || (is_tx_first)) { ++ tx_end_time = jiffies + (3 * HZ); ++ STP_PSM_INFO_FUNC("tx cnt = %d in the previous 3 sec\n", tx_cnt); ++ /* if(tx_cnt > 400)//for high traffic , not to do sleep. */ ++ if (tx_cnt > 300) { ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ tx_cnt = 0; ++ if (is_tx_first) ++ is_tx_first = 0; ++ } ++ } else { ++ rx_cnt++; ++ ++ if (((long)jiffies - (long)rx_end_time >= 0) || (is_rx_first)) { ++ rx_end_time = jiffies + (3 * HZ); ++ STP_PSM_INFO_FUNC("rx cnt = %d in the previous 3 sec\n", rx_cnt); ++ ++ /* if(rx_cnt > 2000)//for high traffic , not to do sleep. */ ++ if (rx_cnt > 1200) { /* for high traffic , not to do sleep. */ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); ++ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); ++ } ++ rx_cnt = 0; ++ if (is_rx_first) ++ is_rx_first = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++#else ++static struct timeval tv_now, tv_end; ++static INT32 sample_start; ++static INT32 tx_sum_len; ++static INT32 rx_sum_len; ++ ++INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length) ++{ ++ if (sample_start) { ++ if (dir) ++ rx_sum_len += length; ++ else ++ tx_sum_len += length; ++ ++ do_gettimeofday(&tv_now); ++ /* STP_PSM_INFO_FUNC("tv_now:%d.%d tv_end:%d.%d\n", ++ * tv_now.tv_sec,tv_now.tv_usec,tv_end.tv_sec,tv_end.tv_usec); ++ */ ++ if (((tv_now.tv_sec == tv_end.tv_sec) && (tv_now.tv_usec > tv_end.tv_usec)) || ++ (tv_now.tv_sec > tv_end.tv_sec)) { ++ STP_PSM_INFO_FUNC("STP speed rx:%d tx:%d\n", rx_sum_len, tx_sum_len); ++ if ((rx_sum_len + tx_sum_len) > RTX_SPEED_THRESHOLD) { ++ /* STP_PSM_INFO_FUNC("High speed,Disable monitor\n"); */ ++ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP_1000; ++ stp_psm_start_monitor(stp_psm); ++ } else { ++ /* STP_PSM_INFO_FUNC("Low speed,Enable monitor\n"); */ ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; ++ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); ++ } ++ sample_start = 0; ++ rx_sum_len = 0; ++ tx_sum_len = 0; ++ } ++ } else { ++ sample_start = 1; ++ do_gettimeofday(&tv_now); ++ tv_end = tv_now; ++ tv_end.tv_sec += SAMPLE_DURATION; ++ } ++ ++ return 0; ++} ++#endif ++ ++/*external function for WMT module to do sleep/wakeup*/ ++INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) ++{ ++ return _stp_psm_set_state(stp_psm, state); ++} ++ ++INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_thread_lock_aquire(stp_psm); ++} ++ ++INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_thread_lock_release(stp_psm); ++} ++ ++INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_do_wakeup(stp_psm); ++} ++ ++INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) ++{ ++ ++ return _stp_psm_notify_stp(stp_psm, action); ++} ++ ++INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_notify_wmt_wakeup_wq(stp_psm); ++} ++ ++int stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm) ++{ ++ ++ return _stp_psm_notify_wmt_sleep_wq(stp_psm); ++} ++ ++INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_start_monitor(stp_psm); ++} ++ ++INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_is_to_block_traffic(stp_psm); ++} ++ ++INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_is_disable(stp_psm); ++} ++ ++INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_has_pending_data(stp_psm); ++} ++ ++INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_release_data(stp_psm); ++} ++ ++INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) ++{ ++ return _stp_psm_hold_data(stp_psm, buffer, len, type); ++} ++ ++INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_disable(stp_psm); ++} ++ ++INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) ++{ ++ return _stp_psm_enable(stp_psm, idle_time_to_sleep); ++} ++ ++INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm) ++{ ++ stp_psm_set_sleep_enable(stp_psm); ++ ++ return _stp_psm_reset(stp_psm); ++} ++ ++INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm) ++{ ++ return _stp_psm_notify_wmt_sleep_wq(stp_psm); ++} ++ ++INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ stp_psm->sleep_en = 1; ++ STP_PSM_DBG_FUNC("\n"); ++ ret = 0; ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ stp_psm->sleep_en = 0; ++ STP_PSM_DBG_FUNC("\n"); ++ ret = 0; ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++/* stp_psm_check_sleep_enable - to check if sleep cmd is enabled or not ++ * @ stp_psm - pointer of psm ++ * ++ * return 1 if sleep is enabled; else return 0 if disabled; else error code ++ */ ++INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = 0; ++ ++ if (stp_psm) { ++ ret = stp_psm->sleep_en; ++ STP_PSM_DBG_FUNC("%s\n", ret ? "enabled" : "disabled"); ++ } else { ++ STP_PSM_INFO_FUNC("Null pointer\n"); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num) ++{ ++ INT32 index = 0; ++ struct timeval now; ++ ++ if (stp_psm_dbg) { ++ osal_lock_unsleepable_lock(&stp_psm_dbg->lock); ++ do_gettimeofday(&now); ++ index = stp_psm_dbg->in - 1; ++ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; ++ STP_PSM_DBG_FUNC("index(%d)\n", index); ++ stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag = stp_psm_dbg->queue[index].cur_flag; ++ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag = flag; ++ stp_psm_dbg->queue[stp_psm_dbg->in].line_num = line_num; ++ stp_psm_dbg->queue[stp_psm_dbg->in].package_no = g_record_num++; ++ stp_psm_dbg->queue[stp_psm_dbg->in].sec = now.tv_sec; ++ stp_psm_dbg->queue[stp_psm_dbg->in].usec = now.tv_usec; ++ stp_psm_dbg->size++; ++ STP_PSM_DBG_FUNC("pre_Flag = %d, cur_flag = %d\n", stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag, ++ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag); ++ stp_psm_dbg->size = (stp_psm_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : stp_psm_dbg->size; ++ stp_psm_dbg->in = (stp_psm_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (stp_psm_dbg->in + 1); ++ STP_PSM_DBG_FUNC("record size = %d, in = %d num = %d\n", stp_psm_dbg->size, stp_psm_dbg->in, line_num); ++ ++ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); ++ } ++ return 0; ++} ++ ++static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg) ++{ ++ ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ if (!stp_psm_dbg) { ++ STP_PSM_ERR_FUNC("NULL g_stp_psm_dbg reference\n"); ++ return -1; ++ } ++ osal_lock_unsleepable_lock(&stp_psm_dbg->lock); ++ ++ inIndex = stp_psm_dbg->in; ++ dumpSize = stp_psm_dbg->size; ++ if (STP_PSM_DBG_SIZE == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; ++ ++ STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ ++ pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d)\n", ++ stp_psm_dbg->queue[outIndex].sec, ++ stp_psm_dbg->queue[outIndex].usec, ++ stp_psm_dbg->queue[outIndex].package_no, ++ stp_psm_dbg->queue[outIndex].prev_flag, ++ stp_psm_dbg->queue[outIndex].cur_flag, stp_psm_dbg->queue[outIndex].line_num); ++ ++ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); ++ ++ return 0; ++} ++ ++static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num) ++{ ++ INT32 index = 0; ++ struct timeval now; ++ ++ if (p_opid_dbg) { ++ osal_lock_unsleepable_lock(&p_opid_dbg->lock); ++ do_gettimeofday(&now); ++ index = p_opid_dbg->in - 1; ++ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; ++ STP_PSM_DBG_FUNC("index(%d)\n", index); ++ p_opid_dbg->queue[p_opid_dbg->in].prev_flag = p_opid_dbg->queue[index].cur_flag; ++ p_opid_dbg->queue[p_opid_dbg->in].cur_flag = opid; ++ p_opid_dbg->queue[p_opid_dbg->in].line_num = line_num; ++ p_opid_dbg->queue[p_opid_dbg->in].package_no = g_opid_record_num++; ++ p_opid_dbg->queue[p_opid_dbg->in].sec = now.tv_sec; ++ p_opid_dbg->queue[p_opid_dbg->in].usec = now.tv_usec; ++ p_opid_dbg->queue[p_opid_dbg->in].pid = current->pid; ++ p_opid_dbg->size++; ++ STP_PSM_DBG_FUNC("pre_opid = %d, cur_opid = %d\n", p_opid_dbg->queue[p_opid_dbg->in].prev_flag, ++ p_opid_dbg->queue[p_opid_dbg->in].cur_flag); ++ p_opid_dbg->size = (p_opid_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : p_opid_dbg->size; ++ p_opid_dbg->in = (p_opid_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (p_opid_dbg->in + 1); ++ STP_PSM_DBG_FUNC("opid record size = %d, in = %d num = %d\n", p_opid_dbg->size, p_opid_dbg->in, ++ line_num); ++ ++ osal_unlock_unsleepable_lock(&p_opid_dbg->lock); ++ } ++ return 0; ++ ++} ++ ++static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg) ++{ ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ if (!p_opid_dbg) { ++ STP_PSM_ERR_FUNC("NULL p_opid_dbg reference\n"); ++ return -1; ++ } ++ osal_lock_unsleepable_lock(&p_opid_dbg->lock); ++ ++ inIndex = p_opid_dbg->in; ++ dumpSize = p_opid_dbg->size; ++ if (STP_PSM_DBG_SIZE == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; ++ ++ STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ ++ pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d) pid(%d)\n", ++ p_opid_dbg->queue[outIndex].sec, ++ p_opid_dbg->queue[outIndex].usec, ++ p_opid_dbg->queue[outIndex].package_no, ++ p_opid_dbg->queue[outIndex].prev_flag, ++ p_opid_dbg->queue[outIndex].cur_flag, ++ p_opid_dbg->queue[outIndex].line_num, p_opid_dbg->queue[outIndex].pid); ++ ++ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ osal_unlock_unsleepable_lock(&p_opid_dbg->lock); ++ ++ return 0; ++ ++} ++ ++MTKSTP_PSM_T *stp_psm_init(void) ++{ ++ INT32 err = 0; ++ INT32 i = 0; ++ INT32 ret = -1; ++ ++ STP_PSM_INFO_FUNC("psm init\n"); ++ ++ stp_psm->work_state = ACT; ++ stp_psm->wmt_notify = wmt_lib_ps_stp_cb; ++ stp_psm->is_wmt_quick_ps_support = wmt_lib_is_quick_ps_support; ++ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; ++ stp_psm->flag.data = 0; ++ stp_psm->stp_tx_cb = NULL; ++ stp_psm_set_sleep_enable(stp_psm); ++ ++ ret = osal_fifo_init(&stp_psm->hold_fifo, NULL, STP_PSM_FIFO_SIZE); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("FIFO INIT FAILS\n"); ++ goto ERR_EXIT4; ++ } ++ ++ osal_fifo_reset(&stp_psm->hold_fifo); ++ osal_sleepable_lock_init(&stp_psm->hold_fifo_spinlock_global); ++ osal_unsleepable_lock_init(&stp_psm->wq_spinlock); ++ osal_sleepable_lock_init(&stp_psm->stp_psm_lock); ++ ++/* osal_unsleepable_lock_init(&stp_psm->flagSpinlock); */ ++ ++ osal_memcpy(stp_psm->wake_lock.name, "MT662x", 6); ++ osal_wake_lock_init(&stp_psm->wake_lock); ++ ++ osal_event_init(&stp_psm->STPd_event); ++ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); ++ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); ++ /* Put all to free Q */ ++ for (i = 0; i < STP_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(stp_psm->arQue[i].signal)); ++ _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, &(stp_psm->arQue[i])); ++ } ++ /* stp_psm->current_active_op = NULL; */ ++ stp_psm->last_active_opId = STP_OPID_PSM_INALID; ++ /*Generate BTM thread, to servie STP-CORE and WMT-CORE for sleeping, waking up and host awake */ ++ stp_psm->PSMd.pThreadData = (VOID *) stp_psm; ++ stp_psm->PSMd.pThreadFunc = (VOID *) _stp_psm_proc; ++ osal_memcpy(stp_psm->PSMd.threadName, PSM_THREAD_NAME, osal_strlen(PSM_THREAD_NAME)); ++ ++ ret = osal_thread_create(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_create fail...\n"); ++ goto ERR_EXIT5; ++ } ++ /* init_waitqueue_head(&stp_psm->wait_wmt_q); */ ++ stp_psm->wait_wmt_q.timeoutValue = STP_PSM_WAIT_EVENT_TIMEOUT; ++ osal_event_init(&stp_psm->wait_wmt_q); ++ ++ err = _stp_psm_init_monitor(stp_psm); ++ if (err) { ++ STP_PSM_ERR_FUNC("__stp_psm_init ERROR\n"); ++ goto ERR_EXIT6; ++ } ++ /* Start STPd thread */ ++ ret = osal_thread_run(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_run FAILS\n"); ++ goto ERR_EXIT6; ++ } ++ /* psm disable in default */ ++ _stp_psm_disable(stp_psm); ++ ++ g_stp_psm_dbg = (STP_PSM_RECORD_T *) osal_malloc(osal_sizeof(STP_PSM_RECORD_T)); ++ if (!g_stp_psm_dbg) { ++ STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); ++ return NULL; ++ } ++ osal_memset(g_stp_psm_dbg, 0, osal_sizeof(STP_PSM_RECORD_T)); ++ osal_unsleepable_lock_init(&g_stp_psm_dbg->lock); ++ ++ g_stp_psm_opid_dbg = (STP_PSM_OPID_RECORD *) osal_malloc(osal_sizeof(STP_PSM_OPID_RECORD)); ++ if (!g_stp_psm_opid_dbg) { ++ STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); ++ return NULL; ++ } ++ osal_memset(g_stp_psm_opid_dbg, 0, osal_sizeof(STP_PSM_OPID_RECORD)); ++ osal_unsleepable_lock_init(&g_stp_psm_opid_dbg->lock); ++ ++ return stp_psm; ++ ++ERR_EXIT6: ++ ++ ret = osal_thread_destroy(&stp_psm->PSMd); ++ if (ret < 0) { ++ STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ goto ERR_EXIT5; ++ } ++ERR_EXIT5: ++ osal_fifo_deinit(&stp_psm->hold_fifo); ++ERR_EXIT4: ++ ++ return NULL; ++} ++ ++INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm) ++{ ++ INT32 ret = -1; ++ ++ STP_PSM_INFO_FUNC("psm deinit\n"); ++ ++ if (g_stp_psm_dbg) { ++ osal_unsleepable_lock_deinit(&g_stp_psm_dbg->lock); ++ osal_free(g_stp_psm_dbg); ++ g_stp_psm_dbg = NULL; ++ } ++ ++ if (!stp_psm) ++ return STP_PSM_OPERATION_FAIL; ++ ++ ret = osal_thread_destroy(&stp_psm->PSMd); ++ if (ret < 0) ++ STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); ++ ++ ret = _stp_psm_deinit_monitor(stp_psm); ++ if (ret < 0) ++ STP_PSM_ERR_FUNC("_stp_psm_deinit_monitor ERROR\n"); ++ ++ osal_wake_lock_deinit(&stp_psm->wake_lock); ++ osal_fifo_deinit(&stp_psm->hold_fifo); ++ osal_sleepable_lock_deinit(&stp_psm->hold_fifo_spinlock_global); ++ osal_unsleepable_lock_deinit(&stp_psm->wq_spinlock); ++ osal_sleepable_lock_deinit(&stp_psm->stp_psm_lock); ++/* osal_unsleepable_lock_deinit(&stp_psm->flagSpinlock); */ ++ ++ return STP_PSM_OPERATION_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c +new file mode 100644 +index 000000000000..a3c24ca14441 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c +@@ -0,0 +1,3358 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "osal_typedef.h" ++#include "stp_core.h" ++#include "psm_core.h" ++#include "btm_core.h" ++#include "stp_dbg.h" ++#include "stp_btif.h" ++ ++#define PFX "[STP] " ++#define STP_LOG_DBG 4 ++#define STP_LOG_PKHEAD 3 ++#define STP_LOG_INFO 2 ++#define STP_LOG_WARN 1 ++#define STP_LOG_ERR 0 ++ ++#define STP_DEL_SIZE 2 /* STP delimiter length */ ++ ++UINT32 gStpDbgLvl = STP_LOG_INFO; ++unsigned int g_coredump_mode = 0; ++#define REMOVE_USELESS_LOG 1 ++ ++#define STP_POLL_CPUPCR_NUM 16 ++#define STP_POLL_CPUPCR_DELAY 10 ++#define STP_RETRY_OPTIMIZE 0 ++ ++/* global variables */ ++static const UINT8 stp_delimiter[STP_DEL_SIZE] = { 0x55, 0x55 }; ++ ++static INT32 fgEnableNak; /* 0=enable NAK; 1=disable NAK */ ++static INT32 fgEnableDelimiter; /* 0=disable Delimiter; 1=enable Delimiter */ ++#if STP_RETRY_OPTIMIZE ++static UINT32 g_retry_times; ++#endif ++/* common interface */ ++static IF_TX sys_if_tx; ++/* event/signal */ ++static EVENT_SET sys_event_set; ++static EVENT_TX_RESUME sys_event_tx_resume; ++static FUNCTION_STATUS sys_check_function_status; ++/* kernel lib */ ++/* int g_block_tx = 0; */ ++static mtkstp_context_struct stp_core_ctx = { 0 }; ++ ++#define STP_PSM_CORE(x) ((x).psm) ++#define STP_SET_PSM_CORE(x, v) ((x).psm = (v)) ++ ++#define STP_BTM_CORE(x) ((x).btm) ++#define STP_SET_BTM_CORE(x, v) ((x).btm = (v)) ++ ++#define STP_IS_ENABLE(x) ((x).f_enable != 0) ++#define STP_NOT_ENABLE(x) ((x).f_enable == 0) ++#define STP_SET_ENABLE(x, v) ((x).f_enable = (v)) ++ ++#define STP_IS_READY(x) ((x).f_ready != 0) ++#define STP_NOT_READY(x) ((x).f_ready == 0) ++#define STP_SET_READY(x, v) ((x).f_ready = (v)) ++ ++#define STP_PENDING_TYPE(x) ((x).f_pending_type) ++#define STP_SET_PENDING_TYPE(x, v) ((x).f_pending_type = (v)) ++ ++#define STP_BLUE_ANGEL (0) ++#define STP_BLUE_Z (1) ++#define STP_BT_STK(x) ((x).f_bluez) ++#define STP_BT_STK_IS_BLUEZ(x) ((x).f_bluez == (STP_BLUE_Z)) ++#define STP_SET_BT_STK(x, v) ((x).f_bluez = (v)) ++ ++#define STP_IS_ENABLE_DBG(x) ((x).f_dbg_en != 0) ++#define STP_NOT_ENABLE_DBG(x) ((x).f_dbg_en == 0) ++#define STP_SET_ENABLE_DBG(x, v) ((x).f_dbg_en = (v)) ++ ++#define STP_IS_ENABLE_RST(x) ((x).f_autorst_en != 0) ++#define STP_NOT_ENABLE_RST(x) ((x).f_autorst_en == 0) ++#define STP_SET_ENABLE_RST(x, v) ((x).f_autorst_en = (v)) ++ ++#define STP_SUPPORT_PROTOCOL(x) ((x).f_mode) ++#define STP_SET_SUPPORT_PROTOCOL(x, v) ((x).f_mode = (v)) ++ ++#define STP_FW_COREDUMP_FLAG(x) ((x).f_coredump) ++#define STP_SET_FW_COREDUMP_FLAG(x, v) ((x).f_coredump = (v)) ++#define STP_ENABLE_FW_COREDUMP(x, v) ((x).en_coredump = (v)) ++#define STP_ENABLE_FW_COREDUMP_FLAG(x) ((x).en_coredump) ++ ++#define STP_WMT_LAST_CLOSE(x) ((x).f_wmt_last_close) ++#define STP_SET_WMT_LAST_CLOSE(x, v) ((x).f_wmt_last_close = (v)) ++ ++#define STP_EVT_ERR_ASSERT(x) ((x).f_evt_err_assert) ++#define STP_SET_EVT_ERR_ASSERT(x, v) ((x).f_evt_err_assert = (v)) ++ ++/*[PatchNeed]Need to calculate the timeout value*/ ++static UINT32 mtkstp_tx_timeout = MTKSTP_TX_TIMEOUT; ++static mtkstp_parser_state prev_state = -1; ++ ++#define CONFIG_DEBUG_STP_TRAFFIC_SUPPORT ++#ifdef CONFIG_DEBUG_STP_TRAFFIC_SUPPORT ++static MTKSTP_DBG_T *g_mtkstp_dbg; ++#endif ++static VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len); ++static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc); ++static VOID stp_update_tx_queue(UINT32 txseq); ++static VOID stp_rest_ctx_state(VOID); ++static VOID stp_change_rx_state(mtkstp_parser_state next); ++static void stp_tx_timeout_handler(/*unsigned long data*/ struct timer_list *t); ++static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len); ++static VOID stp_dump_tx_queue(UINT32 txseq); ++static INT32 stp_is_apply_powersaving(VOID); ++/*static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type);*/ ++static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length); ++static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length); ++static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type); ++static VOID stp_send_tx_queue(UINT32 txseq); ++static VOID stp_send_ack(UINT8 txAck, UINT8 nak); ++static INT32 stp_process_rxack(VOID); ++static VOID stp_process_packet(VOID); ++ ++/*private functions*/ ++ ++static INT32 stp_ctx_lock_init(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unsleepable_lock_init(&((pctx)->stp_mutex)); ++#else ++ osal_sleepable_lock_init(&((pctx)->stp_mutex)); ++ return 0; ++#endif ++} ++ ++static INT32 stp_ctx_lock_deinit(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unsleepable_lock_deinit(&((pctx)->stp_mutex)); ++#else ++ return osal_sleepable_lock_deinit(&((pctx)->stp_mutex)); ++#endif ++} ++ ++static INT32 stp_ctx_lock(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_lock_unsleepable_lock(&((pctx)->stp_mutex)); ++#else ++ return osal_lock_sleepable_lock(&((pctx)->stp_mutex)); ++#endif ++} ++ ++static INT32 stp_ctx_unlock(mtkstp_context_struct *pctx) ++{ ++#if CFG_STP_CORE_CTX_SPIN_LOCK ++ return osal_unlock_unsleepable_lock(&((pctx)->stp_mutex)); ++#else ++ return osal_unlock_sleepable_lock(&((pctx)->stp_mutex)); ++#endif ++} ++ ++MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel) ++{ ++ if (dbglevel <= 4) { ++ gStpDbgLvl = dbglevel; ++ STP_INFO_FUNC("gStpDbgLvl = %d\n", gStpDbgLvl); ++ return MTK_WCN_BOOL_TRUE; ++ } ++ STP_INFO_FUNC("invalid stp debug level. gStpDbgLvl = %d\n", gStpDbgLvl); ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++#if !(REMOVE_USELESS_LOG) ++static UINT8 *stp_type_to_dbg_string(UINT32 type) ++{ ++ UINT8 *type_name = NULL; ++ ++ if (type == BT_TASK_INDX) ++ type_name = "< BT>"; ++ else if (type == GPS_TASK_INDX) ++ type_name = ""; ++ else if (type == WMT_TASK_INDX) ++ type_name = ""; ++ else if (type == FM_TASK_INDX) ++ type_name = "< FM>"; ++ else if (type == ANT_TASK_INDX) ++ type_name = ""; ++ ++ return type_name; ++} ++#endif ++#if 0 ++/***************************************************************************** ++* FUNCTION ++* crc16 ++* DESCRIPTION ++* Compute the CRC-16 for the data buffer ++* PARAMETERS ++* crc [IN] previous CRC value ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* the updated CRC value ++*****************************************************************************/ ++static UINT16 crc16(const UINT8 *buffer, const UINT32 length) ++{ ++ UINT32 crc, i; ++ ++ /* FIXME: Add STP checksum feature */ ++ crc = 0; ++ for (i = 0; i < length; i++, buffer++) ++ crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; ++ ++ return crc; ++} ++ ++#endif ++ ++VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len) ++{ ++ ++#ifndef CONFIG_LOG_STP_INTERNAL ++ return; ++#endif ++ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx)) { ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_PKT, type, /* type */ ++ txAck, /* ack */ ++ seq, /* seq */ ++ crc, /* crc */ ++ dir, /* dir */ ++ len, /* len */ ++ pBuf); /* body */ ++ } else { ++ STP_DBG_FUNC("stp_dbg not enabled"); ++ } ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_check_crc ++* DESCRIPTION ++* check the check sum of packet payload ++* PARAMETERS ++* pdata [IN] the data want to check ++* length [IN] the length of pdata ++* crc [IN] the crc of pdata ++* RETURNS ++* KAL_TRUE crc is ok ++* KAL_FALSE crc is wrong ++*****************************************************************************/ ++static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc) ++{ ++ /*----------------------------------------------------------------*/ ++ /* Local Variables */ ++ /*----------------------------------------------------------------*/ ++ UINT16 checksum; ++ ++ /*----------------------------------------------------------------*/ ++ /* Code Body */ ++ /*----------------------------------------------------------------*/ ++ ++ /* FIXME: Add STP feature: check or skip crc */ ++ ++ checksum = osal_crc16(buffer, length); ++ if (checksum == crc) ++ return MTK_WCN_BOOL_TRUE; ++ ++ STP_ERR_FUNC("CRC fail, length = %d, rx = %x, calc = %x \r\n", length, crc, checksum); ++ return MTK_WCN_BOOL_FALSE; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_update_tx_queue ++* DESCRIPTION ++* update packet's ACK field ++* PARAMETERS ++* txseq [IN] index of the tx packet which we want to update ++* RETURNS ++* void ++*****************************************************************************/ ++static void stp_update_tx_queue(UINT32 txseq) ++{ ++ INT32 tx_read, i; ++ UINT8 checksum = 0; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ stp_core_ctx.tx_buf[tx_read] &= 0xf8; ++ stp_core_ctx.tx_buf[tx_read] |= stp_core_ctx.sequence.txack; ++ ++ for (i = 0; i < 3; i++) { ++ checksum += stp_core_ctx.tx_buf[tx_read]; ++ tx_read++; ++ if (tx_read >= MTKSTP_BUFFER_SIZE) ++ tx_read -= MTKSTP_BUFFER_SIZE; ++ ++ } ++ ++ stp_core_ctx.tx_buf[tx_read] = checksum; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_rest_ctx_state ++* DESCRIPTION ++* Reset stp context state variables only. Mutex and timer resources are not touched. ++* ++* PARAMETERS ++* void ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_rest_ctx_state(VOID) ++{ ++ INT32 i; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ stp_core_ctx.rx_counter = 0; ++ ++ /*reset rx buffer pointer */ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) { ++ stp_core_ctx.ring[i].read_p = 0; ++ stp_core_ctx.ring[i].write_p = 0; ++ } ++ ++ /*reset tx buffer pointer */ ++ stp_core_ctx.tx_write = 0; ++ stp_core_ctx.tx_read = 0; ++ ++ /*reset STP protocol context */ ++ stp_core_ctx.parser.state = MTKSTP_SYNC; ++ stp_core_ctx.sequence.txseq = 0; ++ stp_core_ctx.sequence.txack = 7; ++ stp_core_ctx.sequence.rxack = 7; ++ stp_core_ctx.sequence.winspace = MTKSTP_WINSIZE; ++ stp_core_ctx.sequence.expected_rxseq = 0; ++ stp_core_ctx.sequence.retry_times = 0; ++ stp_core_ctx.inband_rst_set = 0; ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_change_rx_state ++* DESCRIPTION ++* change the rx fsm of STP to "next" ++* PARAMETERS ++* next [IN] the next state of rx fsm ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_change_rx_state(mtkstp_parser_state next) ++{ ++ prev_state = stp_core_ctx.parser.state; ++ stp_core_ctx.parser.state = next; ++ ++} ++ ++/* static void stp_tx_timeout_handler(void){ */ ++static void stp_tx_timeout_handler(/*unsigned long data*/struct timer_list *t) ++{ ++ STP_WARN_FUNC("call retry btm retry wq ...\n"); ++ /*shorten the softirq lattency */ ++ stp_btm_notify_stp_retry_wq(STP_BTM_CORE(stp_core_ctx)); ++ STP_WARN_FUNC("call retry btm retry wq ...#\n"); ++} ++ ++VOID stp_do_tx_timeout(VOID) ++{ ++ UINT32 seq; ++ UINT32 ret; ++ INT32 iRet; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ UINT8 resync[4]; ++ ++ STP_WARN_FUNC("==============================================================================\n"); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++#if STP_RETRY_OPTIMIZE ++ if ((g_retry_times != 0) && (stp_core_ctx.sequence.retry_times == 0)) { ++ STP_INFO_FUNC("STP TX timeout has been recoveryed by resend,record_retry_time(%d)\n", g_retry_times); ++ g_retry_times = 0; ++ stp_ctx_unlock(&stp_core_ctx); ++ return; ++ } ++#endif ++ if (stp_core_ctx.sequence.retry_times > (MTKSTP_RETRY_LIMIT)) { ++ STP_INFO_FUNC("STP retry times(%d) have reached retry limit,stop it\n", ++ stp_core_ctx.sequence.retry_times); ++ stp_ctx_unlock(&stp_core_ctx); ++ return; ++ } ++#if STP_RETRY_OPTIMIZE ++ else ++ STP_DBG_FUNC("current TX timeout package has not received ACK yet,retry_times(%d)\n", ++ g_retry_times); ++#endif ++ /*polling cpupcr when no ack occurs at first retry */ ++ stp_notify_btm_poll_cpupcr(STP_BTM_CORE(stp_core_ctx), STP_POLL_CPUPCR_NUM, STP_POLL_CPUPCR_DELAY); ++ ++ seq = stp_core_ctx.sequence.rxack; ++ INDEX_INC(seq); ++ ++ if (seq != stp_core_ctx.sequence.txseq) { ++ osal_memset(&resync[0], 127, 4); ++ (*sys_if_tx) (&resync[0], 4, &ret); ++ if (ret != 4) { ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: send resync fail\n"); ++ osal_assert(0); ++ } ++ ++ do { ++ STP_WARN_FUNC("[stp.ctx]*rxack (=last rx ack) = %d\n\r", stp_core_ctx.sequence.rxack); ++ STP_WARN_FUNC("[stp.ctx]txack (=last rx seq)= %d\n\r", stp_core_ctx.sequence.txack); ++ STP_WARN_FUNC("[stp.ctx]*txseq (=next tx seq)= %d\n\r", stp_core_ctx.sequence.txseq); ++ STP_WARN_FUNC("Resend STP packet from %d -> %d\n\r", seq, ++ (stp_core_ctx.sequence.txseq <= 0) ? (7) : (stp_core_ctx.sequence.txseq - 1)); ++ stp_dump_tx_queue(seq); ++ ++ stp_send_tx_queue(seq); ++ INDEX_INC(seq); ++ } while (seq != stp_core_ctx.sequence.txseq); ++ ++ } ++ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ ++ if (stp_core_ctx.sequence.winspace == MTKSTP_WINSIZE) { ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); ++ } else { ++ stp_core_ctx.sequence.retry_times++; ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler, retry = %d\n", stp_core_ctx.sequence.retry_times); ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = stp_core_ctx.sequence.retry_times; ++#endif ++ /*If retry too much, try to recover STP by return back to initializatin state */ ++ /*And not to retry again */ ++ if (stp_core_ctx.sequence.retry_times > MTKSTP_RETRY_LIMIT) { ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = 0; ++#endif ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ stp_ctx_unlock(&stp_core_ctx); ++ ++ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); ++ ++ STP_ERR_FUNC("TX retry limit = %d\n", MTKSTP_RETRY_LIMIT); ++ osal_assert(0); ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ /*Whole Chip Reset Procedure Invoke */ ++ /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ ++ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ stp_dbg_set_host_assert_info(4, 36, 1); ++ STP_INFO_FUNC("**STP NoAck trigger firmware assert**\n"); ++ iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ ++ if (iRet) { ++ STP_ERR_FUNC("host tigger fw assert fail(%d), do noack handle flow\n", iRet); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ issue_type = STP_FW_NOACK_ISSUE; ++ iRet = stp_dbg_set_fw_info("STP NoAck", osal_strlen("STP NoAck"), issue_type); ++ ++ osal_dbg_assert_aee("[SOC_CONNSYS]NoAck", ++ "**[WCN_ISSUE_INFO]STP Tx Timeout**\n F/W has NO any RESPONSE. Please check F/W status first\n"); ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ } else { ++ STP_INFO_FUNC("do trigger assert & chip reset in wmt\n"); ++ } ++ return; ++ } ++ } ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ STP_WARN_FUNC("==============================================================================#\n"); ++} ++ ++static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len) ++{ ++ osal_buffer_dump(buf, title, len, 32); ++} ++ ++/***************************************************************************** ++ * FUNCTION ++ * stp_tx_timeout_handler ++ * DESCRIPTION ++ * tx timeout handler, send resync & retransmitt ++ * PARAMETERS ++ * void ++ * RETURNS ++ * void ++ *****************************************************************************/ ++static VOID stp_dump_tx_queue(UINT32 txseq) ++{ ++ INT32 tx_read, tx_length, last_len; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ tx_length = stp_core_ctx.tx_length[txseq]; ++ ++ STP_ERR_FUNC("tx_seq=%d ..", txseq); ++ ++ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { ++ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q", (tx_length >= 8) ? (8) : (tx_length)); ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - tx_read; ++ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q_0", (last_len >= 8) ? (8) : (last_len)); ++ stp_dump_data(&stp_core_ctx.tx_buf[0], "tx_q_0", ++ ((tx_length - last_len) ? (8) : (tx_length - last_len))); ++ } ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_is_apply_powersaving ++* DESCRIPTION ++* Check if STP support power saving mode. ++* PARAMETERS ++* ++* RETURNS ++* True: support power saving False: not support power saving ++*****************************************************************************/ ++static INT32 stp_is_apply_powersaving(VOID) ++{ ++ ++ if (STP_IS_READY(stp_core_ctx) && !stp_psm_is_disable(STP_PSM_CORE(stp_core_ctx))) { ++ /* osal_dbg_print("apply power saving\n"); */ ++ return MTK_WCN_BOOL_TRUE; ++ } ++ if (mtk_wcn_stp_is_sdio_mode()) ++ return MTK_WCN_BOOL_FALSE; ++ ++ STP_DBG_FUNC("not apply power saving\n"); ++ return MTK_WCN_BOOL_FALSE; ++} ++#if 0 ++/***************************************************************************** ++* FUNCTION ++* stp_is_privileges_cmd ++* DESCRIPTION ++* Check if the data is privilege command ++* PARAMETERS ++* ++* RETURNS ++* True/False ++*****************************************************************************/ ++static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type) ++{ ++ typedef struct privileges_cmd { ++ UINT32 length; ++ UINT8 type; ++ UINT8 buf[7]; /* MAX length of target command is only 5 currently */ ++ } p_cmd_t; ++ ++ p_cmd_t p_cmd_table[] = { ++ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x01} }, /* sleep command */ ++ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x02} }, /* host_awake command */ ++ }; ++ ++ UINT32 i; ++ UINT32 size = sizeof(p_cmd_table) / sizeof(p_cmd_table[0]); ++ ++ for (i = 0; i < size; i++) { ++ if (type != p_cmd_table[i].type) ++ continue; ++ ++ if (length != p_cmd_table[i].length) ++ continue; ++ ++ if (osal_memcmp(p_cmd_table[i].buf, buffer, length)) ++ continue; ++ ++ /* matched entry is found */ ++ STP_DBG_FUNC("It's p_cmd_t\n"); ++ return MTK_WCN_BOOL_TRUE; ++ } ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++#endif ++/***************************************************************************** ++* FUNCTION ++* tx_queue_room_available ++* DESCRIPTION ++* check room if available, ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length) ++{ ++ UINT32 roomLeft; ++ ++ /* ++ Get available space of TX Queue ++ */ ++ if (stp_core_ctx.tx_read <= stp_core_ctx.tx_write) ++ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write + stp_core_ctx.tx_read - 1; ++ else ++ roomLeft = stp_core_ctx.tx_read - stp_core_ctx.tx_write - 1; ++ ++ if (roomLeft < length) { ++ STP_ERR_FUNC("%s: tx queue room shortage\n", __func__); ++ return MTK_WCN_BOOL_FALSE; ++ } else ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_add_to_tx_queue ++* DESCRIPTION ++* put data to tx queue ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length) ++{ ++ UINT32 last_len; ++ ++ /* Get available space of TX Queue */ ++ if (length + stp_core_ctx.tx_write < MTKSTP_BUFFER_SIZE) { ++ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, length); ++ stp_core_ctx.tx_write += length; ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write; ++ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, last_len); ++ osal_memcpy(stp_core_ctx.tx_buf, buffer + last_len, length - last_len); ++ ++ stp_core_ctx.tx_write = length - last_len; ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_add_to_rx_queue ++* DESCRIPTION ++* put data to corresponding task's rx queue and notify corresponding task ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] corresponding task index ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type) ++{ ++ UINT32 roomLeft, last_len; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if (stp_core_ctx.ring[type].read_p <= stp_core_ctx.ring[type].write_p) ++ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p + stp_core_ctx.ring[type].read_p - 1; ++ else ++ roomLeft = stp_core_ctx.ring[type].read_p - stp_core_ctx.ring[type].write_p - 1; ++ ++ if (roomLeft < length) { ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ STP_ERR_FUNC("Queue is full !!!, type = %d\n", type); ++ osal_assert(0); ++ return -1; ++ } ++ ++ if (length + stp_core_ctx.ring[type].write_p < MTKSTP_BUFFER_SIZE) { ++ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, length); ++ stp_core_ctx.ring[type].write_p += length; ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p; ++ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, last_len); ++ osal_memcpy(stp_core_ctx.ring[type].buffer, buffer + last_len, length - last_len); ++ stp_core_ctx.ring[type].write_p = length - last_len; ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_tx_queue ++* DESCRIPTION ++* send data in tx buffer to common interface ++* PARAMETERS ++* txseq [IN] sequence number of outgoing packet in tx buffer ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_send_tx_queue(UINT32 txseq) ++{ ++ UINT32 ret; ++ INT32 tx_read, tx_length, last_len; ++ ++ tx_read = stp_core_ctx.tx_start_addr[txseq]; ++ tx_length = stp_core_ctx.tx_length[txseq]; ++ ++ stp_update_tx_queue(txseq); ++ ++ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { ++ ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], tx_length, &ret); ++ ++ if (ret != tx_length) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length, ret); ++ osal_assert(0); ++ } ++ } else { ++ last_len = MTKSTP_BUFFER_SIZE - tx_read; ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], last_len, &ret); ++ ++ if (ret != last_len) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", last_len, ret); ++ osal_assert(0); ++ } ++ ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], tx_length - last_len, &ret); ++ ++ if (ret != tx_length - last_len) { ++ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length - last_len, ret); ++ osal_assert(0); ++ } ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_ack ++* DESCRIPTION ++* send ack packet to the peer ++* PARAMETERS ++* txAck [IN] Ack number ++* nak [IN] 0 = ack; !0 = NAK ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_send_ack(UINT8 txAck, UINT8 nak) ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE]; ++ UINT32 ret; ++ INT32 iStatus; ++ ++ mtkstp_header[0] = 0x80 + (0 << 3) + txAck; /* stp_core_ctx.sequence.txack; */ ++ ++ if (fgEnableNak == 0) ++ mtkstp_header[1] = 0x00; /* disable NAK */ ++ else ++ mtkstp_header[1] = ((nak == 0) ? 0x00 : 0x80); ++ ++ mtkstp_header[2] = 0; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ ++ stp_dbg_pkt_log(STP_TASK_INDX, txAck, 0, 0, PKT_DIR_TX, NULL, 0); ++ ++ if (fgEnableDelimiter == 1) { ++ iStatus = (*sys_if_tx) ((PUINT8) &stp_delimiter[0], STP_DEL_SIZE, &ret); ++ STP_DUMP_PACKET_HEAD((PUINT8) &stp_delimiter[0], "tx del", STP_DEL_SIZE); ++ if (ret != STP_DEL_SIZE) { ++ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", STP_DEL_SIZE, ret, iStatus); ++ osal_assert(0); ++ } ++ } ++ ++ iStatus = (*sys_if_tx) (&mtkstp_header[0], MTKSTP_HEADER_SIZE, &ret); ++ ++ if (ret != MTKSTP_HEADER_SIZE) { ++ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", MTKSTP_HEADER_SIZE, ret, iStatus); ++ osal_assert(0); ++ } ++ ++} ++ ++INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type) ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; ++ UINT8 *p_tx_buf = NULL; ++ UINT16 crc; ++ INT32 ret = 0; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*Only WMT can set raw data */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { ++ /* no op */ ++ /* NULL; */ ++ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { ++ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ ++ /* NULL; */ ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ osal_printtimeofday("[ STP][SDIO][ B][W]"); ++ ++ mtkstp_header[0] = 0x80; ++ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); ++ mtkstp_header[2] = (length) & 0xff; ++ mtkstp_header[3] = 0x00; ++ ++ p_tx_buf = &stp_core_ctx.tx_buf[0]; ++ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); ++ p_tx_buf += MTKSTP_HEADER_SIZE; ++ ++ osal_memcpy(p_tx_buf, buffer, length); ++ p_tx_buf += length; ++ ++ temp[0] = 0x00; ++ temp[1] = 0x00; ++ osal_memcpy(p_tx_buf, temp, 2); ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, 0, PKT_DIR_TX, buffer, length); ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); ++ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { ++ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); ++ osal_assert(0); ++ ret = 0; ++ } else { ++ ret = (INT32) length; ++ } ++ ++ osal_printtimeofday("[ STP][SDIO][ E][W]"); ++ } ++ /* STP over BTIF OR UART */ ++ else if ((mtk_wcn_stp_is_btif_fullset_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ if ((stp_core_ctx.sequence.winspace > 0) && ++ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { ++ mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; ++ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); ++ mtkstp_header[2] = length & 0xff; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ ++ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; ++ ++ if (fgEnableDelimiter == 1) { ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; ++ stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); ++ } ++ ++ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); ++ ++ /*Make Payload */ ++ stp_add_to_tx_queue(buffer, length); ++ ++ /*Make CRC */ ++ crc = osal_crc16(buffer, length); ++ temp[0] = crc & 0xff; ++ temp[1] = (crc & 0xff00) >> 8; ++ stp_add_to_tx_queue(temp, 2); ++ ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); ++ ++ /*Kick to UART */ ++ stp_send_tx_queue(stp_core_ctx.sequence.txseq); ++ INDEX_INC(stp_core_ctx.sequence.txseq); ++ stp_core_ctx.sequence.winspace--; ++ ++ /*Setup the Retry Timer */ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ else ++ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); ++ ++ ret = (INT32) length; ++ } else { ++ /* No winspace to send. Let caller retry */ ++ STP_ERR_FUNC("%s: There is no winspace/txqueue to send !!!\n", __func__); ++ ret = 0; ++ } ++ } ++ ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ ++ return ret; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_process_rxack ++* DESCRIPTION ++* process ack packet ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++static INT32 stp_process_rxack(VOID) ++{ ++ INT32 j, k; ++ UINT8 rxack; ++ INT32 fgResult = (-1); ++ ++ if (stp_core_ctx.sequence.rxack != stp_core_ctx.parser.ack) { ++ j = k = 0; ++ rxack = stp_core_ctx.sequence.rxack; ++ INDEX_INC(rxack); ++ while (rxack != stp_core_ctx.sequence.txseq) { ++ j++; ++ if (rxack == stp_core_ctx.parser.ack) { ++ k = 1; ++ break; ++ } ++ INDEX_INC(rxack); ++ } ++ if (k == 1) { ++ stp_core_ctx.sequence.rxack = stp_core_ctx.parser.ack; ++ stp_core_ctx.tx_read = stp_core_ctx.tx_start_addr[rxack] + stp_core_ctx.tx_length[rxack]; ++ if (stp_core_ctx.tx_read >= MTKSTP_BUFFER_SIZE) ++ stp_core_ctx.tx_read -= MTKSTP_BUFFER_SIZE; ++ ++ stp_core_ctx.sequence.winspace += j; ++ stp_core_ctx.sequence.retry_times = 0; ++ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ ++ fgResult = 0; ++ } ++ } ++ ++ return fgResult; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_process_packet ++* DESCRIPTION ++* process STP packet ++* PARAMETERS ++* void ++* RETURNS ++* void ++*****************************************************************************/ ++static VOID stp_process_packet(VOID) ++{ ++ INT32 fgTriggerResume = (-1); ++ UINT8 txAck = 0; ++ static INT32 fgRxOk; ++ MTK_WCN_BOOL b; ++ MTK_WCN_BOOL is_function_active = 0; ++ static INT32 stp_process_packet_fail_count; ++ INT32 iRet = -1; ++ ++ stp_dbg_pkt_log(stp_core_ctx.parser.type, ++ stp_core_ctx.parser.ack, ++ stp_core_ctx.parser.seq, ++ stp_core_ctx.parser.crc, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.parser.length); ++ /*Optimization */ ++ /*If bluez, direct send packet to hci_core not through RX buffer! */ ++ if ((stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) && ++ (stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { ++ /*Indicate packet to hci_stp */ ++ STP_DBG_FUNC("Send Packet to BT_SUBFUCTION, len = %d\n", stp_core_ctx.rx_counter); ++ ++ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if (b) ++ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ /*Process rx ack */ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ txAck = stp_core_ctx.sequence.txack; ++ ++ /*Send ack back */ ++ stp_send_ack(txAck, 0); ++ ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ fgRxOk = 0; ++ } ++ /* sequence matches expected, enqueue packet */ ++ else if (stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) { ++ is_function_active = ++ ((*sys_check_function_status) (stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) == ++ STATUS_FUNCTION_ACTIVE); ++ /*If type is valid and function works, then try to enqueue */ ++ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && (is_function_active == MTK_WCN_BOOL_TRUE)) { ++ if (stp_core_ctx.parser.type == BT_TASK_INDX) { ++ static const UINT8 rst_buf[7] = { 0x04, 0x0e, 0x04, 0x01, 0x3, 0xc, 0x00 }; ++ ++ if (!osal_strncmp(stp_core_ctx.rx_buf, rst_buf, 7)) ++ osal_printtimeofday("############ BT Rest end <--"); ++ } ++ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ ++ /*Send tx ack */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 0); ++ ++ stp_ctx_unlock(&stp_core_ctx); ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, COEX_TASK_INDX); ++ } else { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ STP_WARN_FUNC("BT/WIFI & LTE coex in non-LTE projects,drop it...\n"); ++ } else { ++ fgRxOk = ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ if (is_function_active == MTK_WCN_BOOL_FALSE) { ++ STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n", ++ stp_core_ctx.parser.type); ++ fgRxOk = 0; /*drop packet */ ++ } else { ++ STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n", ++ stp_core_ctx.parser.type); ++ fgRxOk = 0; /*drop packet */ ++ } ++ stp_ctx_lock(&stp_core_ctx); ++ ++ fgTriggerResume = stp_process_rxack(); ++ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; ++ INDEX_INC(stp_core_ctx.sequence.expected_rxseq); ++ ++ /*Send tx ack */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 0); ++ ++ stp_ctx_unlock(&stp_core_ctx); ++ } ++ ++ /* enqueue successfully */ ++ if (fgRxOk == 0) { ++ stp_process_packet_fail_count = 0; ++ /*notify corresponding subfunction of incoming data */ ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++#if 1 ++ STP_DBG_FUNC ++ ("WMT/LTE package:[0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x]\n", ++ stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], stp_core_ctx.rx_buf[2], ++ stp_core_ctx.rx_buf[3], stp_core_ctx.rx_buf[4], stp_core_ctx.rx_buf[5], ++ stp_core_ctx.rx_buf[6], stp_core_ctx.rx_buf[7]); ++#endif ++ stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && ++ (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { ++ STP_WARN_FUNC("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); ++ } else { ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ stp_process_packet_fail_count++; ++ /*Queue is full */ ++ if (stp_core_ctx.parser.type == GPS_TASK_INDX) { ++ /*Clear Rx Queue if GPS */ ++ mtk_wcn_stp_flush_rx_queue(GPS_TASK_INDX); ++ } else { ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++ /*enqueue fail, don't send ack and wait for peer retry */ ++ STP_ERR_FUNC("Enqueue to Rx queue fail, maybe function %d queue is full\n", ++ stp_core_ctx.parser.type); ++ } ++ } ++ /*sequence not match && previous packet enqueue successfully, send the previous ACK */ ++ else if (fgRxOk == 0) { ++ STP_ERR_FUNC("mtkstp_process_packet: expected_rxseq = %d, parser.seq = %d\n", ++ stp_core_ctx.sequence.expected_rxseq, stp_core_ctx.parser.seq); ++ stp_process_packet_fail_count++; ++ ++ stp_ctx_lock(&stp_core_ctx); ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ txAck = stp_core_ctx.sequence.txack; ++ stp_send_ack(txAck, 1); ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ STP_ERR_FUNC ++ ("sequence not match && previous packet enqueue successfully, send the previous ACK (ack no =%d)\n", ++ txAck); ++ } ++ /*sequence not match && previous packet enqueue failed, do nothing, make the other side timeout */ ++ else { ++ stp_process_packet_fail_count++; ++ STP_ERR_FUNC ++ ("sequence not match && previous packet enqueue failed, do nothing, make the other side timeout\n"); ++ } ++ ++ if (fgTriggerResume == 0) { ++ /*[PatchNeed]Just Notificaiton, not blocking call */ ++ /* notify adaptation layer for possible tx resume mechanism */ ++ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); ++ } ++ ++ if (stp_process_packet_fail_count > MTKSTP_RETRY_LIMIT) { ++ stp_process_packet_fail_count = 0; ++ STP_ERR_FUNC("The process packet fail count > 10 lastly\n\r, whole chip reset\n\r"); ++ mtk_wcn_stp_dbg_dump_package(); ++ /*Whole Chip Reset Procedure Invoke */ ++ /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ stp_dbg_set_host_assert_info(4, 37, 1); ++ STP_INFO_FUNC("**Ack Miss trigger firmware assert**\n"); ++ iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ if (iRet) { ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ /* (*sys_dbg_assert_aee)("[MT662x]Ack Miss", "**STP Ack Miss**\n Ack Miss.\n"); */ ++ osal_dbg_assert_aee("[SOC_CONSYS]Ack Miss", ++ "**[WCN_ISSUE_INFO]STP Ack Miss**\n Ack Miss.\n"); ++ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ } ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_init ++* DESCRIPTION ++* init STP kernel ++* PARAMETERS ++* cb_func [IN] function pointers of system APIs ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func) ++{ ++ INT32 ret = 0; ++ INT32 i = 0; ++ ++ /* Function pointer to point to the currently used transmission interface ++ */ ++ sys_if_tx = cb_func->cb_if_tx; ++ ++ /* Used to inform the function driver has received the corresponding type of information */ ++ sys_event_set = cb_func->cb_event_set; ++ ++ /* Used to inform the function driver can continue to send information and ++ STP has resources to deal with ++ */ ++ sys_event_tx_resume = cb_func->cb_event_tx_resume; ++ ++ /* STP driver determines whether the function is enable. If not enable and ++ STP has received the kind of information, and STP have the right to put it away. ++ */ ++ sys_check_function_status = cb_func->cb_check_funciton_status; ++ ++ /* osal_unsleepable_lock_init(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock_init(&stp_core_ctx); ++ /* Setup timer to be used to check if f/w receive the data in the specific time ++ interval after being sent ++ */ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) ++ osal_unsleepable_lock_init(&stp_core_ctx.ring[i].mtx); ++ ++ stp_core_ctx.tx_timer.timeoutHandler = stp_tx_timeout_handler; ++ stp_core_ctx.tx_timer.timeroutHandlerData = 0; ++ osal_timer_create(&stp_core_ctx.tx_timer); ++ ++ STP_SET_BT_STK(stp_core_ctx, 0); ++ STP_SET_ENABLE(stp_core_ctx, 0); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 0); ++ STP_SET_ENABLE_RST(stp_core_ctx, 0); ++ STP_SET_PENDING_TYPE(stp_core_ctx, 0); ++ STP_SET_READY(stp_core_ctx, 0); ++ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, 0); ++ STP_SET_PSM_CORE(stp_core_ctx, stp_psm_init()); ++ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, 0); ++ STP_ENABLE_FW_COREDUMP(stp_core_ctx, 0); ++ STP_SET_WMT_LAST_CLOSE(stp_core_ctx, 0); ++ STP_SET_EVT_ERR_ASSERT(stp_core_ctx, 0); ++ ++ if (!STP_PSM_CORE(stp_core_ctx)) { ++ ret = (-3); ++ goto ERROR; ++ } ++ ++ STP_SET_BTM_CORE(stp_core_ctx, stp_btm_init()); ++ if (!STP_BTM_CORE(stp_core_ctx)) { ++ STP_ERR_FUNC("STP_BTM_CORE(stp_core_ctx) initialization fail!\n"); ++ ret = (-3); ++ goto ERROR; ++ } ++ ++ if (STP_BTM_CORE(stp_core_ctx) != NULL) ++ g_mtkstp_dbg = stp_dbg_init(STP_BTM_CORE(stp_core_ctx)); ++ else ++ g_mtkstp_dbg = stp_dbg_init(NULL); ++ ++ if (!g_mtkstp_dbg) { ++ STP_ERR_FUNC("g_mtkstp_dbg initialization fail!\n"); ++ ret = (-3); ++ goto ERROR; ++ } ++ STP_SET_ENABLE_RST(stp_core_ctx, 1); ++#ifdef CONFIG_LOG_STP_INTERNAL ++ mtk_wcn_stp_dbg_enable(); ++#else ++ mtk_wcn_stp_dbg_enable(); ++#endif ++ goto RETURN; ++ ++ERROR: ++ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); ++ ++RETURN: ++ return ret; ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_deinit ++* DESCRIPTION ++* deinit STP kernel ++* PARAMETERS ++* void ++* RETURNS ++* INT32 0 = success, others = failure ++*****************************************************************************/ ++INT32 mtk_wcn_stp_deinit(void) ++{ ++ UINT32 i = 0; ++ ++ sys_if_tx = NULL; ++ sys_event_set = NULL; ++ sys_event_tx_resume = NULL; ++ sys_check_function_status = NULL; ++ ++ stp_dbg_deinit(g_mtkstp_dbg); ++ stp_btm_deinit(STP_BTM_CORE(stp_core_ctx)); ++ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); ++ ++ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) ++ osal_unsleepable_lock_deinit(&stp_core_ctx.ring[i].mtx); ++ ++ stp_ctx_lock_deinit(&stp_core_ctx); ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_btm_get_dmp ++* DESCRIPTION ++* get stp dump related information ++* PARAMETERS ++* buffer: dump placement, len: dump size ++* RETURNS ++* 0: Success Negative Value: Fail ++*****************************************************************************/ ++ ++int mtk_wcn_stp_btm_get_dmp(char *buf, int *len) ++{ ++ return stp_dbg_dmp_out(g_mtkstp_dbg, buf, len); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_notify_stp ++* DESCRIPTION ++* WMT notification to STP that power saving job is done or not ++* PARAMETERS ++* ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++int mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action) ++{ ++ return stp_psm_notify_stp(STP_PSM_CORE(stp_core_ctx), action); ++} ++ ++int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state) ++{ ++ return stp_psm_set_state(STP_PSM_CORE(stp_core_ctx), state); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_enable ++* DESCRIPTION ++* enable STP sleep/wakeup support ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep) ++{ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { ++ if (mtk_wcn_stp_is_ready()) ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_DBG_FUNC("PSM is not support under SDIO mode\n"); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ ++#else ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); ++ STP_DBG_FUNC("PSM is not support under SDIO mode\n"); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++#endif ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_psm_disable ++* DESCRIPTION ++* disable STP sleep/wakeup support ++* PARAMETERS ++* void ++* RETURNS ++* 0: Sccuess Negative value: Fail ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_psm_disable(VOID) ++{ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { ++ if (mtk_wcn_stp_is_ready()) ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ return 0; ++ } ++ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return -1; ++ ++#else ++ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { ++ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } else if (mtk_wcn_stp_is_sdio_mode()) { ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ return 0; ++ } ++ STP_DBG_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); ++ return 0; ++ ++#endif ++} ++ ++extern INT32 mtk_wcn_stp_psm_reset(VOID) ++{ ++ return stp_psm_reset(STP_PSM_CORE(stp_core_ctx)); ++} ++ ++extern INT32 mtk_wcn_stp_dbg_disable(VOID) ++{ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx)) { ++ STP_DBG_FUNC("STP dbg mode is turned off\n"); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 0); ++ stp_dbg_disable(g_mtkstp_dbg); ++ } else { ++ STP_WARN_FUNC("STP dbg mode has been turned off\n"); ++ } ++ ++ return 0; ++} ++ ++extern INT32 mtk_wcn_stp_dbg_enable(VOID) ++{ ++ if (STP_NOT_ENABLE_DBG(stp_core_ctx)) { ++ STP_DBG_FUNC("STP dbg mode is turned on\n"); ++ STP_SET_ENABLE_DBG(stp_core_ctx, 1); ++ stp_dbg_enable(g_mtkstp_dbg); ++ } else { ++ STP_WARN_FUNC("STP dbg mode has been turned on\n"); ++ } ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on) ++{ ++ stp_dbg_log_ctrl(on); ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on) ++{ ++ STP_ENABLE_FW_COREDUMP(stp_core_ctx, on); ++ STP_INFO_FUNC("coredump function mode: %d.\n", on); ++ g_coredump_mode = on; ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_coredump_flag_get(VOID) ++{ ++ return STP_ENABLE_FW_COREDUMP_FLAG(stp_core_ctx); ++} ++ ++static INT32 stp_parser_data_in_mand_mode(UINT32 length, UINT8 *p_data) ++{ ++ UINT8 padding_len = 0; ++ INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ ++ MTK_WCN_BOOL is_function_active = 0; ++ INT32 i = length; ++ ++ while (i > 0) { ++ switch (stp_core_ctx.parser.state) { ++ case MTKSTP_SYNC: /* b'10 */ ++ /* if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) */ ++ /* if(*p_data == 0x80) */ ++ if ((*p_data & 0x80) == 0x80) { ++ /* STP_DBG_FUNC("[STP] STP Packet Start =========>\n"); */ ++ if (*p_data != 0x80) ++ STP_WARN_FUNC("SDIO not 0x80!!(0x%x)\n", *p_data); ++ ++ if (i >= 4) { ++#if !(REMOVE_USELESS_LOG) ++ /*print header, when get the full STP header */ ++ UINT32 type = (*(p_data + 1) & 0x70) >> 4; ++ UINT8 *type_name = ""; ++ ++ type_name = stp_type_to_dbg_string(type); ++ STP_DBG_FUNC( ++ "STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", ++ *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), ++ type_name, ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), ++ (*p_data & 0x38) >> 3, *p_data & 0x07); ++#endif ++ } else { ++ STP_WARN_FUNC("STP Rx: discard due to i < 4 (%d)\n", i); ++ } ++ ++ /* STP_DBG_FUNC("[STP] sync->nak\n"); */ ++ stp_change_rx_state(MTKSTP_NAK); ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("sync to sync!!(0x%x)\n", *p_data); ++ stp_change_rx_state(MTKSTP_SYNC); ++ } ++ break; ++ ++ case MTKSTP_NAK: ++ /* STP_DBG_FUNC("[STP] nak->length\n"); */ ++ stp_change_rx_state(MTKSTP_LENGTH); ++ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; ++ if (stp_core_ctx.parser.type <= MTKSTP_MAX_TASK_NUM) { ++ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("nak to sync\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ } ++ break; ++ ++ case MTKSTP_LENGTH: ++ /* STP_DBG_FUNC("[STP] length -> checksum\n"); */ ++ stp_change_rx_state(MTKSTP_CHECKSUM); ++ stp_core_ctx.parser.length += *p_data; ++ ++ /*Valid length checking */ ++ if (stp_core_ctx.parser.length < 2000) { ++ stp_core_ctx.rx_counter++; ++ } else { ++ STP_WARN_FUNC("The length of STP packet is not valid !!! length = %d\n", ++ stp_core_ctx.parser.length); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ /* return -1; */ ++ } ++ ++ break; ++ ++ case MTKSTP_CHECKSUM: ++ ++ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || ++ (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_change_rx_state(MTKSTP_FW_MSG); ++ stp_core_ctx.rx_counter = 0; ++ i -= 1; ++ if (i != 0) ++ p_data += 1; ++ ++ continue; ++ } ++ ++ if (stp_core_ctx.parser.length == 0) { ++ STP_WARN_FUNC("checksum to sync\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ } else { ++ /* STP_DBG_FUNC("[STP] checksum->data\n"); */ ++ stp_change_rx_state(MTKSTP_DATA); ++ stp_core_ctx.rx_counter = 0; ++ } ++ break; ++ ++ case MTKSTP_DATA: ++ ++ /* block copy instead of byte copy */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ /*boundary checking */ ++ if (stp_core_ctx.rx_counter + remain_length >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC("Abnormal!! Memory operation over boundary!!\n"); ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_core_ctx.parser.state = MTKSTP_CRC1; ++ continue; ++ ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ /*boundary checking */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC("Abnormal!! Memory operation over boundary 2!!\n"); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++ break; ++ ++ case MTKSTP_CRC1: ++ stp_change_rx_state(MTKSTP_CRC2); ++ break; ++ ++ case MTKSTP_CRC2: ++#if 1 ++ if (stp_core_ctx.parser.type == WMT_TASK_INDX) { ++ stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; ++ STP_DBG_FUNC("wmt sub type (0x%x)\n", stp_core_ctx.parser.wmtsubtype); ++ } ++#endif ++ /*SDIO mode do it. */ ++ if (mtk_wcn_stp_is_sdio_mode()) { ++ /*STP packet 4-bytes alignment */ ++ /*Discard padding bytes , otherwise make parser state machine disorder */ ++ if (i <= 4) { ++ /*STP_DBG_FUNC("STP last block padding %d bytes\n", i-1); */ ++ p_data += (i - 1); ++ i -= (i - 1); ++ } else { ++ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; ++ p_data += padding_len; ++ i -= padding_len; ++ /*STP_DBG_FUNC("STP Agg padding %d bytes\n", padding_len); */ ++ } ++ } ++ stp_dbg_pkt_log(stp_core_ctx.parser.type, ++ 0, 0, 0, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if ((stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { ++ int b; ++ ++ /*Indicate packet to hci_stp */ ++ if (gStpDbgLvl >= STP_LOG_DBG) { ++ stp_dump_data(stp_core_ctx.rx_buf, "indicate_to_bt_core", ++ stp_core_ctx.rx_counter); ++ } ++ ++ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); ++ if (b) ++ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); ++ ++ } else { ++ ++ is_function_active = ( ++ (*sys_check_function_status)(stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) ++ == STATUS_FUNCTION_ACTIVE); ++ ++ /*check type and function if active? */ ++ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) ++ && (is_function_active == MTK_WCN_BOOL_TRUE)) { ++#if CFG_WMT_LTE_COEX_HANDLING ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) ++ && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { ++ STP_INFO_FUNC("wmt/lte coex package!\n"); ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, COEX_TASK_INDX); ++ stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#else ++ if ((stp_core_ctx.parser.type == WMT_TASK_INDX) ++ && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { ++ STP_WARN_FUNC ++ ("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); ++ } else { ++ stp_add_to_rx_queue(stp_core_ctx.rx_buf, ++ stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type); ++ ++ /*notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (stp_core_ctx.parser.type); ++ } ++#endif ++ } else { ++ if (is_function_active == MTK_WCN_BOOL_FALSE) { ++ STP_ERR_FUNC ++ ("function type = %d is inactive, so no en-queue to rx\n", ++ stp_core_ctx.parser.type); ++ } else { ++ STP_ERR_FUNC ++ ("mtkstp_process_packet: type = %x, the type is invalid\n", ++ stp_core_ctx.parser.type); ++ } ++ } ++ } ++ ++ /* STP_DBG_FUNC("[STP] crc2->sync\n"); */ ++ /* STP_DBG_FUNC("[STP] STP Packet End <=========\n"); */ ++ stp_core_ctx.rx_counter = 0; ++ stp_change_rx_state(MTKSTP_SYNC); ++ ++ break; ++ ++ case MTKSTP_FW_MSG: ++ ++ /*f/w assert and exception information */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ } ++ ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; ++ /*Trace32 Dump */ ++ if (stp_core_ctx.parser.type == STP_TASK_INDX) { ++ /* g_block_tx = 1; */ ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ pr_debug("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type, stp_core_ctx.rx_buf); ++ /*use paged dump or full dump */ ++ stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); ++#if 0 ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_DMP /*STP_DBG_FW_ASSERT */ , 5, ++ 0, 0, 0, 0, ++ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); ++#endif ++ } ++ ++ /*discard CRC */ ++ /* we will discard antoher CRC on the outer switch procedure. */ ++ if (i >= 1) { ++ STP_INFO_FUNC("crc discard.. i = %d\n", i); ++ i -= 1; ++ if (i > 0) ++ p_data += 1; ++ ++ } ++ ++ /*STP packet 4-bytes alignment */ ++ /*Discard padding bytes , otherwise make parser state machine disorder */ ++ if (i <= 4) { ++ STP_INFO_FUNC ++ ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", ++ i - 1); ++ p_data += (i - 1); ++ i -= (i - 1); ++ } else { ++ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; ++ p_data += padding_len; ++ i -= padding_len; ++ STP_INFO_FUNC ++ ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n", ++ padding_len); ++ } ++ stp_change_rx_state(MTKSTP_SYNC); ++ ++ } else { /* only copy by data length */ ++ ++ STP_ERR_FUNC("raw data doesn't contain full stp packet!!\n"); ++ } ++ break; ++ default: ++ break; ++ } ++ p_data++; ++ i--; ++ } ++ ++ return 0; ++} ++ ++static INT32 stp_parser_data_in_full_mode(UINT32 length, UINT8 *p_data) ++{ ++ INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ ++ INT32 i = length; ++ ++ while (i > 0) { ++ switch (stp_core_ctx.parser.state) { ++ ++ case MTKSTP_RESYNC1: /* RESYNC must be 4 _continuous_ 0x7f */ ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC2); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC2: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC3); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC3: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_RESYNC4); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_RESYNC4: ++ if (*p_data == 0x7f) ++ stp_change_rx_state(MTKSTP_SYNC); ++ else ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ break; ++ case MTKSTP_SYNC: /* b'10 */ ++ STP_DUMP_PACKET_HEAD(p_data, "rx (uart):", length > 4 ? 4 : length); ++ if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) { ++ stp_change_rx_state(MTKSTP_NAK); ++ stp_core_ctx.parser.seq = (*p_data & 0x38) >> 3; ++ stp_core_ctx.parser.ack = *p_data & 0x07; ++ stp_core_ctx.rx_buf[0] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /* stp_core_ctx.rx_counter++; */ ++ ++ if (i >= 4 && gStpDbgLvl >= STP_LOG_DBG) { ++ /*print header, when get the full STP header */ ++#if !(REMOVE_USELESS_LOG) ++ int type = (*(p_data + 1) & 0x70) >> 4; ++ char *type_name = ""; ++ ++ type_name = stp_type_to_dbg_string(type); ++ ++ STP_DBG_FUNC ++ ("STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", ++ *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), type_name, ++ ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), ++ (*p_data & 0x38) >> 3, *p_data & 0x07); ++#endif ++ } else { ++ STP_DBG_FUNC("STP Rx: discard due to i < 4\n"); ++ } ++ } else if ((*p_data == 0x7f) && (prev_state == MTKSTP_RESYNC4)) { ++ /* if this 0x7f is continuous to resync pattern */ ++ /* skip this continuous 0x7f, remain current & prev state */ ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: continuous resync pattern, buff = %x\n", *p_data); ++ } else if (*p_data == 0x7f) { /* a start of 0x7f, maybe this is resync pattern */ ++ stp_change_rx_state(MTKSTP_RESYNC2); ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: go to MTKSTP_RESYNC2, buff = %x\n", *p_data); ++ } else if (*p_data == 0x55) { /* STP delimiter */ ++ /* do nothing for delimiter */ ++ } else { /* unexpected, go to resync1 */ ++ osal_assert(0); ++ STP_ERR_FUNC("MTKSTP_SYNC: unexpected data, buff = %x\n", *p_data); ++ } ++ break; ++ ++ case MTKSTP_NAK: ++ /* (*sys_dbg_print)("MTKSTP_NAK : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ if (fgEnableNak == 0) ++ stp_core_ctx.parser.nak = 0; /* disable NAK */ ++ else ++ stp_core_ctx.parser.nak = (*p_data & 0x80) >> 7; ++ ++ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; ++ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; ++ stp_core_ctx.rx_buf[1] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /*stp_core_ctx.rx_counter++; */ ++ if (stp_core_ctx.parser.nak) ++ STP_ERR_FUNC("MTKSTP_NAK TRUE: mtk_wcn_stp_parser_data, buff = %x\n", *p_data); ++ ++ if (stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) ++ stp_change_rx_state(MTKSTP_LENGTH); ++ else ++ stp_change_rx_state(MTKSTP_SYNC); ++ break; ++ ++ case MTKSTP_LENGTH: ++ /* (*sys_dbg_print)("MTKSTP_LENGTH : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ stp_change_rx_state(MTKSTP_CHECKSUM); ++ stp_core_ctx.parser.length += *p_data; ++ ++ /*Valid length checking */ ++ if (stp_core_ctx.parser.length > 2048) { ++ STP_ERR_FUNC("The length of STP packet is not valid !!! length = %d\n", ++ stp_core_ctx.parser.length); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ STP_TRACE_FUNC("--\n"); ++ return -1; ++ } ++ ++ stp_core_ctx.rx_buf[2] = *p_data; ++ /* Geoge FIXME: WHY comment the following line? */ ++ /*stp_core_ctx.rx_counter++; */ ++ break; ++ ++ case MTKSTP_CHECKSUM: ++ /* (*sys_dbg_print)("MTKSTP_CHECKSUM : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ ++ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || ++ (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_change_rx_state(MTKSTP_FW_MSG); ++ stp_core_ctx.rx_counter = 0; ++ i -= 1; ++ if (i != 0) ++ p_data += 1; ++ ++ continue; ++ } ++ ++ if (((stp_core_ctx.rx_buf[0] + ++ stp_core_ctx.rx_buf[1] + stp_core_ctx.rx_buf[2]) & 0xff) == *p_data) { ++ /* header only packet */ ++ if (stp_core_ctx.parser.length == 0) { ++ INT32 fgTriggerResume = (-1); ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ if (stp_core_ctx.inband_rst_set == 0) { ++ stp_dbg_pkt_log(STP_TASK_INDX, ++ stp_core_ctx.parser.ack, ++ stp_core_ctx.parser.seq, ++ 5, /* STP type id */ ++ PKT_DIR_RX, ++ NULL, ++ 0); ++ fgTriggerResume = stp_process_rxack(); ++ } else { ++ STP_WARN_FUNC ++ ("Now it's inband reset process and drop ACK packet.\n"); ++ } ++ ++ if (fgTriggerResume == 0) { ++ /* notify adaptation layer for ++ * possible tx resume mechanism ++ */ ++ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); ++ } ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.rx_counter = 0; ++ } else { ++ stp_change_rx_state(MTKSTP_DATA); ++ stp_core_ctx.rx_counter = 0; ++ } ++ } else { ++ STP_ERR_FUNC("The checksum of header is error !!! %02x %02x %02x %02x\n", ++ stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], ++ stp_core_ctx.rx_buf[2], *p_data); ++ /* George FIXME: error handling mechanism shall be refined */ ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ ++ /* since checksum error is usually related to interface ++ * buffer overflow, so we just let timeout mechanism to ++ * handle such error. ++ */ ++ STP_TRACE_FUNC("--\n"); ++ /* return and purge COMM port */ ++ return -1; ++ /*stp_send_ack(1); NAK mechanism is removed */ ++ } ++ break; ++ ++ case MTKSTP_DATA: ++#if 0 ++ if (stp_core_ctx.rx_counter < stp_core_ctx.parser.length) { ++ stp_core_ctx.rx_buf[stp_core_ctx.rx_counter] = *p_data; ++ stp_core_ctx.rx_counter++; ++ } ++ if (stp_core_ctx.rx_counter == stp_core_ctx.parser.length) ++ stp_change_rx_state(MTKSTP_CRC1); ++#else ++ /* block copy instead of byte copy */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_core_ctx.parser.state = MTKSTP_CRC1; ++ continue; ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC ++ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ STP_TRACE_FUNC("--\n"); ++ return -1; ++ } ++ ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++#endif ++ break; ++ ++ case MTKSTP_CRC1: ++ stp_change_rx_state(MTKSTP_CRC2); ++ stp_core_ctx.parser.crc = *p_data; ++ break; ++ case MTKSTP_CRC2: ++ stp_change_rx_state(MTKSTP_SYNC); ++ stp_core_ctx.parser.crc += (*p_data) << 8; ++#if 1 ++ if (stp_core_ctx.parser.type == WMT_TASK_INDX) { ++ stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; ++ STP_DBG_FUNC("wmt sub type is (0x%x)\n", stp_core_ctx.parser.wmtsubtype); ++ } ++#endif ++ if (stp_check_crc(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, stp_core_ctx.parser.crc) ++ == MTK_WCN_BOOL_TRUE) { ++ if (stp_core_ctx.inband_rst_set == 0) ++ stp_process_packet(); ++ else ++ STP_WARN_FUNC("Now it's inband reset process and drop packet.\n"); ++ } else { ++ STP_ERR_FUNC("The CRC of packet is error !!!\n"); ++ /* George FIXME: error handling mechanism shall be refined */ ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ ++ /* since checksum error is usually related to interface ++ * buffer overflow, so we just let timeout mechanism to ++ * handle such error. ++ */ ++ STP_TRACE_FUNC("--\n"); ++ /* return and purge COMM port */ ++ return -1; ++ /*stp_send_ack(1); NAK mechanism is removed */ ++ } ++ break; ++ ++ case MTKSTP_FW_MSG: ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ if (STP_IS_READY(stp_core_ctx)) ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ STP_SET_READY(stp_core_ctx, 0); ++ /*stp inband reset */ ++ if (stp_core_ctx.parser.type == STP_TASK_INDX && ++ stp_core_ctx.parser.seq == 0 && ++ stp_core_ctx.parser.ack == 0 && ++ stp_core_ctx.parser.length == 0 && stp_core_ctx.inband_rst_set == 1) { ++ STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r"); ++ stp_rest_ctx_state(); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.inband_rst_set = 0; ++ /* STP_INFO_FUNC("Restart STP Timer\n\r"); */ ++ /* (*sys_timer_start)(stp_core_ctx.tx_timer, ++ * mtkstp_tx_timeout, ++ * (MTK_WCN_TIMER_CB)stp_tx_timeout_handler, ++ * NULL); ++ */ ++ STP_TRACE_FUNC("--\n"); ++ return 0; ++ } ++ ++ /*f/w assert and exception information */ ++ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { ++ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", ++ stp_core_ctx.parser.length, stp_core_ctx.rx_counter); ++ osal_assert(0); ++ } ++ ++ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; ++ if (i >= remain_length) { ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, ++ remain_length); ++ i -= remain_length; ++ p_data += remain_length; ++ stp_core_ctx.rx_counter = stp_core_ctx.parser.length; ++ stp_change_rx_state(MTKSTP_SYNC); ++ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; ++ /* STP_ERR_FUNC("%s [%d]\n", stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); */ ++#if 0 ++ if ((stp_core_ctx.rx_counter == 1) && (stp_core_ctx.rx_buf[0] == 0xFF)) { ++ /* For MT6620, enable/disable coredump function is controlled by ++ * firmware for the moment, we need to set coredump enable flag ++ * to be 1 after see firmware send a pariticallar character(0xff) ++ * before any coredump packet is sent ++ */ ++ mtk_wcn_stp_coredump_flag_ctrl(1); ++ } ++#endif ++ /*Trace32 Dump */ ++ if (STP_IS_ENABLE_DBG(stp_core_ctx) && ++ (stp_core_ctx.parser.type == STP_TASK_INDX)) { ++ if (0 != stp_core_ctx.rx_counter) { ++ STP_SET_READY(stp_core_ctx, 0); ++ mtk_wcn_stp_ctx_save(); ++ STP_INFO_FUNC("++ start to read paged dump and paged trace ++\n"); ++ stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); ++ stp_btm_notify_wmt_trace_wq(stp_core_ctx.btm); ++ STP_INFO_FUNC("++ start to read paged dump and paged trace --\n"); ++ ++ } ++ STP_INFO_FUNC("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, ++ stp_core_ctx.parser.type, stp_core_ctx.rx_buf); ++ } ++ ++ /*Runtime FW Log */ ++ else if (STP_IS_ENABLE_DBG(stp_core_ctx) ++ && (stp_core_ctx.parser.type == INFO_TASK_INDX)) { ++ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0, ++ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); ++ mtk_wcn_stp_dbg_dump_package(); ++ } ++ /*Normal mode: whole chip reset */ ++ else { ++ /*Aee Kernel Warning Message Shown First */ ++ /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */ ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ mtk_wcn_stp_dbg_dump_package(); ++ ++ osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf); ++ /*Whole Chip Reset Procedure Invoke */ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) { ++ STP_SET_READY(stp_core_ctx, 0); ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ } else { ++ STP_INFO_FUNC ++ ("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ } ++ /*discard CRC */ ++ if (i >= 2) { ++ STP_DBG_FUNC("crc discard.. i = %d\n", i); ++ i -= 2; ++ if (i > 0) ++ p_data += 2; ++ } ++ continue; ++ } else { /* only copy by data length */ ++ ++ /*fixed klocwork insight issue */ ++ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { ++ STP_ERR_FUNC ++ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); ++ stp_change_rx_state(MTKSTP_RESYNC1); ++ stp_core_ctx.rx_counter = 0; ++ return -1; ++ } ++ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); ++ stp_core_ctx.rx_counter += i; /* all remain buffer are data */ ++ i = 0; ++ p_data += i; ++ continue; ++ } ++ ++ break; ++ default: ++ break; ++ } ++ p_data++; ++ i--; ++ } ++ ++ return 0; ++} ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* int 0 = success; -1 = crc/checksum error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++int _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) ++#else ++int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) ++#endif ++{ ++ /*----------------------------------------------------------------*/ ++ /* Local Variables */ ++ /*----------------------------------------------------------------*/ ++ INT32 i; ++ UINT8 *p_data; ++ INT32 ret = 0; ++#ifdef DEBUG_DUMP_PACKET_HEAD ++ static UINT32 counter; ++ ++ STP_TRACE_FUNC("++, rx (cnt=%d,len=%d)\n", ++counter, length); ++#endif ++ ++#if 0 ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ if (stp_is_apply_powersaving()) { ++ /* If now chip is awake, to restart monitor! */ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ STP_DBG_FUNC("To restart moinotr when rx\n\r"); ++ stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } ++#endif ++#endif ++ ++ /*----------------------------------------------------------------*/ ++ /* Code Body */ ++ /*----------------------------------------------------------------*/ ++ /* George FIXME: WHY or HOW can we reduct the locked region? */ ++ /*flags = (*sys_mutex_lock)(stp_core_ctx.stp_mutex); */ ++ i = length; ++ p_data = (UINT8 *) buffer; ++ ++/* stp_dump_data(buffer, "rx queue", length); */ ++ ++ /*STP is not enabled and only WMT can use Raw data path */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == STP_PENDING_TYPE(stp_core_ctx)) { ++ /* route to task who send command */ ++ stp_add_to_rx_queue(buffer, length, STP_PENDING_TYPE(stp_core_ctx)); ++ ++ /* mike: notify corresponding subfunction of incoming data */ ++ (*sys_event_set) (STP_PENDING_TYPE(stp_core_ctx)); ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++#if !(REMOVE_USELESS_LOG) ++ if (gStpDbgLvl >= STP_LOG_DBG) ++ stp_dump_data(buffer, "sdio parser_in", length); ++#endif ++ /* STP_DBG_FUNC("sdio stp parser data length = %d\n", length); */ ++ ret = stp_parser_data_in_mand_mode(i, p_data); ++ } ++ /* STP over UART */ ++ else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) ++ ret = stp_parser_data_in_full_mode(i, p_data); ++ ++ /* George FIXME: WHY or HOW can we reduct the locked region? */ ++ /*(*sys_mutex_unlock)(stp_core_ctx.stp_mutex, flags); */ ++ STP_TRACE_FUNC("--\n"); ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_parser_data); ++#endif ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_enable ++* DESCRIPTION ++* enable/disable STP ++* PARAMETERS ++* value [IN] 0=disable, others=enable ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_enable(INT32 value) ++{ ++ STP_DBG_FUNC("%s: set the current enable = (%d)\n", __func__, value); ++ ++ stp_rest_ctx_state(); ++ STP_SET_ENABLE(stp_core_ctx, value); ++ if (!value) { ++ mtk_wcn_stp_psm_reset(); ++ } else { ++/* g_block_tx = 0; */ ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ } ++ return 0; ++} ++ ++INT32 mtk_wcn_stp_dbg_dump_package(VOID) ++{ ++ if (STP_NOT_ENABLE(stp_core_ctx)) { ++ STP_INFO_FUNC("STP dbg mode is off\n"); ++ ++ } else { ++ STP_INFO_FUNC("STP dbg mode is on\n"); ++ /* if (0 == g_block_tx) */ ++ if (0 == mtk_wcn_stp_coredump_start_get()) { ++ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); ++ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); ++ stp_dbg_dmp_printk(g_mtkstp_dbg); ++ } else { ++ STP_INFO_FUNC("assert start flag is set, disable packet dump function\n"); ++ } ++ } ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_ready ++* DESCRIPTION ++* ready/un-ready STP ++* PARAMETERS ++* value [IN] 0=un-ready, others=ready ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_ready(INT32 value) ++{ ++ STP_DBG_FUNC("set ready (%d)\n", value); ++ ++ STP_SET_READY(stp_core_ctx, value); ++ /*if whole chip reset, reset the debuggine mode */ ++#ifndef CONFIG_LOG_STP_INTERNAL ++ /* mtk_wcn_stp_dbg_disable(); */ ++#endif ++ ++ if (stp_is_apply_powersaving()) { ++ STP_INFO_FUNC("Restart the stp-psm monitor !!\n"); ++ stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); ++ } ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_ctrl ++* DESCRIPTION ++* set f/w assert flag in STP context ++* PARAMETERS ++* value [IN] 0=assert end, others=assert begins ++* RETURNS ++* INT32 0=success, others=error ++*****************************************************************************/ ++INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value) ++{ ++ STP_DBG_FUNC("set f/w assert (%d)\n", value); ++ ++ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, value); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_coredump_start_get ++* DESCRIPTION ++* get f/w assert flag in STP context ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0= f/w assert flag is not set, others=f/w assert flag is set ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_coredump_start_get(VOID) ++#else ++INT32 mtk_wcn_stp_coredump_start_get(VOID) ++#endif ++{ ++ return STP_FW_COREDUMP_FLAG(stp_core_ctx); ++} ++ ++/* mtk_wcn_stp_set_wmt_last_close -- set the state of link(UART or SDIO) ++ * @ value - 1, link already be closed; 0, link is open ++ * ++ * Return 0 if success; else error code ++ */ ++INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value) ++{ ++ STP_INFO_FUNC("set wmt_last_close flag (%d)\n", value); ++ ++ STP_SET_WMT_LAST_CLOSE(stp_core_ctx, value); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 > 0: length transmitted; = 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#else ++INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#endif ++{ ++ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; ++ UINT8 *p_tx_buf = NULL; ++ UINT16 crc; ++ INT32 ret = 0; ++ MTK_WCN_BOOL is_quick_enable = MTK_WCN_BOOL_TRUE; ++ ++ /* osal_buffer_dump(buffer,"tx", length, 32); */ ++ ++ if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { ++ STP_ERR_FUNC("WMT lats close,should not have tx request!\n"); ++ return length; ++ } ++ /* if(g_block_tx) */ ++ if (0 != mtk_wcn_stp_coredump_start_get()) { ++ STP_ERR_FUNC("STP fw coredump start flag set...\n"); ++ return length; ++ } ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ is_quick_enable = stp_psm_is_quick_ps_support(); ++ STP_DBG_FUNC("is quick sleep enable:%s\n", is_quick_enable ? "yes" : "no"); ++ if (MTK_WCN_BOOL_TRUE == is_quick_enable) { ++ if (type != WMT_TASK_INDX) { ++#if PSM_USE_COUNT_PACKAGE ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0); ++#else ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0, length); ++#endif ++ } ++ /* if(stp_is_apply_powersaving()) */ ++ { ++ if (type == WMT_TASK_INDX) ++ goto DONT_MONITOR; ++ /*-----------------------------STP_PSM_Lock----------------------------------------*/ ++ ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { ++ STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); ++ stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } else { ++ ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); ++ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); ++ /*-----------------------------STP_PSM_UnLock----------------------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ return ret; ++ } ++ } ++ } else { ++ /* if(stp_is_apply_powersaving()) */ ++ { ++ if (type == WMT_TASK_INDX) ++ goto DONT_MONITOR; ++ /* If now chip is awake, to restart monitor! */ ++ /* STP_INFO_FUNC("check if block traffic !!\n"); */ ++ /*-----------------------------STP_PSM_Lock----------------------------------------*/ ++ ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { ++ /* STP_INFO_FUNC("not to block !!\n"); */ ++ if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { ++ STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); ++ stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); ++ } ++ stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); ++ } else { ++ /* STP_INFO_FUNC("to block !!\n"); */ ++ ++ /* STP_INFO_FUNC("*****hold data in psm queue data length = %d\n", ++ * length); ++ */ ++ /* stp_dump_data(buffer, "Hold in psm queue", length); */ ++ /* hold datas */ ++ ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); ++ /* wmt notification */ ++ STP_INFO_FUNC("#####Type = %d, to inform WMT to wakeup chip, ret = %d:0x%2x,0x%2x\n", ++ type, ret, *buffer, *(buffer + 1)); ++ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); ++ /* STP_INFO_FUNC("*********Type = %d, to inform WMT to wakeup chip>end\n", type); */ ++ /*-----------------------------STP_PSM_UnLock----------------------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ return ret; ++ } ++ } ++ } ++DONT_MONITOR: ++#endif ++ if (type == BT_TASK_INDX) { ++ static const UINT8 rst_buf[4] = { 0x01, 0x03, 0x0c, 0x00 }; ++ ++ if (!osal_strncmp(buffer, rst_buf, 4)) ++ osal_printtimeofday("############ BT Rest start -->"); ++ } ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ /*Only WMT can set raw data */ ++ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { ++ /* no-op */ ++ /* NULL; */ ++ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { ++ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ ++ /* NULL; */ ++ } ++ /* STP over SDIO */ ++ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ /* osal_printtimeofday("[ STP][SDIO][ B][W]"); */ ++ ++ mtkstp_header[0] = 0x80; ++ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); ++ mtkstp_header[2] = (length) & 0xff; ++ mtkstp_header[3] = 0x00; ++ ++ /* HEADER */ ++ p_tx_buf = &stp_core_ctx.tx_buf[0]; ++ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); ++ p_tx_buf += MTKSTP_HEADER_SIZE; ++ ++ /* PAYLOAD */ ++ osal_memcpy(p_tx_buf, buffer, length); ++ p_tx_buf += length; ++ ++ /* CRC */ ++ temp[0] = 0x00; ++ temp[1] = 0x00; ++ osal_memcpy(p_tx_buf, temp, 2); ++ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length); ++ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); ++ ++ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { ++ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); ++ osal_assert(0); ++ ret = 0; ++ } else { ++ ret = (INT32) length; ++ } ++ ++ /* osal_printtimeofday("[ STP][SDIO][ E][W]"); */ ++ } ++ /* STP over UART */ ++ else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) { ++ ++ /* osal_printtimeofday("[ STP][UART][ B][W]"); */ ++ /* STP_INFO_FUNC("Write byte %d\n", length); */ ++ ++ if ((stp_core_ctx.sequence.winspace > 0) && ++ (stp_core_ctx.inband_rst_set == 0) && ++ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { ++ /*Make Header */ ++ /* (*sys_dbg_print)("mtk_wcn_stp_send_data 1, txseq = %d, winspace = %d", ++ * stp_core_ctx.sequence.txseq, stp_core_ctx.sequence.winspace); ++ */ ++ mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; ++ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); ++ mtkstp_header[2] = length & 0xff; ++ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; ++ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; ++ if (fgEnableDelimiter == 1) { ++ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; ++ stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); ++ } ++ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); ++ ++ /*Make Payload */ ++ stp_add_to_tx_queue(buffer, length); ++ ++ /*Make CRC */ ++ crc = osal_crc16(buffer, length); ++ temp[0] = crc & 0xff; ++ temp[1] = (crc & 0xff00) >> 8; ++ stp_add_to_tx_queue(temp, 2); ++ stp_dbg_pkt_log(type, ++ stp_core_ctx.sequence.txack, ++ stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); ++ ++ /*Kick to UART */ ++ stp_send_tx_queue(stp_core_ctx.sequence.txseq); ++ ++ INDEX_INC(stp_core_ctx.sequence.txseq); ++ stp_core_ctx.sequence.winspace--; ++ ++ /*Setup the Retry Timer */ ++ osal_timer_stop(&stp_core_ctx.tx_timer); ++ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) ++ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); ++ else ++ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); ++ ++ ret = (INT32) length; ++ } else { ++ /* ++ No winspace to send. Let caller retry ++ */ ++ if (stp_core_ctx.inband_rst_set == 1) ++ STP_WARN_FUNC("Now it's inband reset process and drop sent packet.\n"); ++ else ++ STP_ERR_FUNC("There is no winspace/txqueue to send !!!\n"); ++ ++ ret = 0; ++ } ++ ++ /* osal_printtimeofday("[ STP][UART][ E][W]"); */ ++ } ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ ++#ifdef CONFIG_POWER_SAVING_SUPPORT ++ ++ if (MTK_WCN_BOOL_TRUE == is_quick_enable) { ++ if (type != WMT_TASK_INDX) { ++ stp_psm_notify_wmt_sleep(STP_PSM_CORE(stp_core_ctx)); ++ /*-----------------------STP_PSM_UnLock-------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ } ++ } else { ++ /* if(stp_is_apply_powersaving()) */ ++ /* { */ ++ if (type != WMT_TASK_INDX) { ++ ++ /*--------------------STP_PSM_UnLock--------------------------*/ ++ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); ++ } ++ /* } */ ++ } ++#endif ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_send_data); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data_raw ++* DESCRIPTION ++* send raw data to common interface, bypass STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#else ++INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) ++#endif ++{ ++ UINT32 written = 0; ++ INT32 ret = 0; ++ ++ if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { ++ STP_ERR_FUNC("WMT lats close,should not have tx request!"); ++ return length; ++ } ++ ++ STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d, data = %x %x %x %x %x %x ", type, buffer[0], buffer[1], ++ buffer[2], buffer[3], buffer[4], buffer[5]); ++ STP_SET_PENDING_TYPE(stp_core_ctx, type); /* remember tx type, forward following rx to this type */ ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, 1); ++ (*sys_if_tx) (&buffer[0], length, &written); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ ++ if (written == 0) ++ stp_dump_data(&buffer[0], "tx raw failed:", length); ++ ++ if (written == length) ++ ret = (INT32) written; ++ else ++ ret = (-1); ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) ++#else ++INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) ++#endif ++{ ++ /* GeorgeKuo modify: reduce "if" branch */ ++ UINT16 copyLen = 0; ++ UINT16 tailLen = 0; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ while (stp_core_ctx.ring[type].read_p != stp_core_ctx.ring[type].write_p) { ++ /* GeorgeKuo modify: reduce if branch */ ++ if (stp_core_ctx.ring[type].write_p > stp_core_ctx.ring[type].read_p) { ++ copyLen = stp_core_ctx.ring[type].write_p - stp_core_ctx.ring[type].read_p; ++ if (copyLen > length) ++ copyLen = length; ++ ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, copyLen); ++ stp_core_ctx.ring[type].read_p += copyLen; ++ } else { ++ tailLen = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].read_p; ++ if (tailLen > length) { /* exclude equal case to skip wrap check */ ++ copyLen = length; ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, ++ copyLen); ++ stp_core_ctx.ring[type].read_p += copyLen; ++ } else { ++ /* part 1: copy tailLen */ ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, ++ tailLen); ++ ++ buffer += tailLen; /* update buffer offset */ ++ ++ /* part 2: check if head length is enough */ ++ copyLen = length - tailLen; ++ copyLen = ++ (stp_core_ctx.ring[type].write_p < ++ copyLen) ? stp_core_ctx.ring[type].write_p : copyLen; ++ ++ if (copyLen) ++ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + 0, copyLen); ++ ++ /* Update read_p final position */ ++ stp_core_ctx.ring[type].read_p = copyLen; ++ ++ /* update return length: head + tail */ ++ copyLen += tailLen; ++ } ++ } ++ break; ++ } ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if ((MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) && (type != WMT_TASK_INDX)) { ++#if PSM_USE_COUNT_PACKAGE ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1); ++#else ++ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1, copyLen); ++#endif ++ } ++ ++ return copyLen; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_receive_data); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++#else ++INT32 mtk_wcn_stp_is_rxqueue_empty(UINT8 type) ++#endif ++{ ++ INT32 ret; ++ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ if (stp_core_ctx.ring[type].read_p == stp_core_ctx.ring[type].write_p) ++ ret = 1; /* queue is empty */ ++ else ++ ret = 0; /* queue is not empty */ ++ ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ ++ return ret; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); ++#endif ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_set_sdio_mode ++* DESCRIPTION ++* Set stp for SDIO mode ++* PARAMETERS ++* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) ++* RETURNS ++* void ++*****************************************************************************/ ++ ++void mtk_wcn_stp_set_mode(UINT32 mode) ++{ ++ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, mode); ++ ++ STP_DBG_FUNC("STP_SUPPORT_PROTOCOL = %08x\n", STP_SUPPORT_PROTOCOL(stp_core_ctx)); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_fullset_mode ++* DESCRIPTION ++* Is stp use UART fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:Uart Fullset mode, FALSE:Not UART Fullset mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_FULL_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_uart_mand_mode ++* DESCRIPTION ++* Is stp use UART mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:Uart Mandatory mode, FALSE:Not UART Mandotary mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_MAND_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_fullset_mode ++* DESCRIPTION ++* Is stp use BTIF fullset mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Fullset mode, FALSE:Not BTIF Fullset mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void) ++{ ++ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_FULL_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_btif_mand_mode ++* DESCRIPTION ++* Is stp use BTIF mandatory mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:BTIF Mandatory mode, FALSE:Not BTIF Mandotary mode ++*****************************************************************************/ ++ ++MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void) ++{ ++ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_MAND_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_sdio_mode ++* DESCRIPTION ++* Is stp use SDIO mode? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode ++*****************************************************************************/ ++MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void) ++{ ++ /* ++ bit 0: uart fullset mode ++ bit 1: uart mandatory mode ++ bit 2: sdio mode ++ */ ++ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_SDIO_MODE) ++ return MTK_WCN_BOOL_TRUE; ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* stp_send_inband_reset ++* DESCRIPTION ++* To sync to oringnal stp state with f/w stp ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++void mtk_wcn_stp_inband_reset(void) ++{ ++ UINT8 inband_reset_packet[64]; ++ UINT32 txseq = 0; ++ UINT32 txack = 0; ++ UINT32 crc = 0; ++ UINT32 ret = 0; ++ UINT32 reset_payload_len = 0; ++ ++ /*512 bytes */ ++ UINT8 reset_payload[] = { ++ 0xc0, 0x01, 0xc0, 0xde, 0x3e, 0xd1, 0xa7, 0xef ++ }; ++ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*RESYNC*/ inband_reset_packet[0] = 0x7f; ++ inband_reset_packet[1] = 0x7f; ++ inband_reset_packet[2] = 0x7f; ++ inband_reset_packet[3] = 0x7f; ++ inband_reset_packet[4] = 0x7f; ++ inband_reset_packet[5] = 0x7f; ++ inband_reset_packet[6] = 0x7f; ++ inband_reset_packet[7] = 0x7f; ++ ++ /*header */ ++ reset_payload_len = sizeof(reset_payload) / sizeof(reset_payload[0]); ++ inband_reset_packet[8] = 0x80 + (txseq << 3) + txack; ++ inband_reset_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); ++ inband_reset_packet[10] = reset_payload_len & 0xff; ++ inband_reset_packet[11] = (inband_reset_packet[8] + inband_reset_packet[9] + inband_reset_packet[10]) & 0xff; ++ ++ /*payload */ ++ osal_memcpy(&inband_reset_packet[12], reset_payload, reset_payload_len); ++ ++ /*crc */ ++ crc = osal_crc16(&reset_payload[0], reset_payload_len); ++ inband_reset_packet[12 + reset_payload_len] = crc & 0xff; ++ inband_reset_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; ++ ++ (*sys_if_tx) (&inband_reset_packet[0], 14 + reset_payload_len, &ret); ++ ++ if (ret != (14 + reset_payload_len)) ++ STP_ERR_FUNC("Inband sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, ret); ++ ++ stp_core_ctx.inband_rst_set = 1; ++ stp_ctx_unlock(&stp_core_ctx); ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++} ++ ++void mtk_wcn_stp_debug_ctrl(INT32 op, INT32 filter, INT32 filter_param) ++{ ++ /*nothing at now*/ ++} ++ ++void mtk_wcn_stp_test_cmd(INT32 cmd_no) ++{ ++ UINT8 test_packet[64]; ++ UINT32 txseq = 0; ++ UINT32 txack = 0; ++ UINT32 crc = 0; ++ UINT32 ret = 0; ++ UINT32 reset_payload_len = 0; ++ ++ UINT8 test_payload[] = { ++ 0xAA, 0xAA, 0xC0, 0xDE, 0x3E, 0xD1, 0xA7, 0xEF ++ }; ++/* */ ++/* select your test command by cmd_no */ ++/* */ ++ if (cmd_no == 0) { ++ /* to test new command to chip */ ++ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_lock(&stp_core_ctx); ++ ++ /*RESYNC*/ test_packet[0] = 0x7f; ++ test_packet[1] = 0x7f; ++ test_packet[2] = 0x7f; ++ test_packet[3] = 0x7f; ++ test_packet[4] = 0x7f; ++ test_packet[5] = 0x7f; ++ test_packet[6] = 0x7f; ++ test_packet[7] = 0x7f; ++ ++ /*header */ ++ reset_payload_len = sizeof(test_payload) / sizeof(test_payload[0]); ++ test_packet[8] = 0x80 + (txseq << 3) + txack; ++ test_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); ++ test_packet[10] = reset_payload_len & 0xff; ++ test_packet[11] = (test_packet[8] + test_packet[9] + test_packet[10]) & 0xff; ++ ++ /*payload */ ++ osal_memcpy(&test_packet[12], test_payload, reset_payload_len); ++ ++ /*crc */ ++ crc = osal_crc16(&test_payload[0], reset_payload_len); ++ test_packet[12 + reset_payload_len] = crc & 0xff; ++ test_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; ++ ++ (*sys_if_tx) (&test_packet[0], 14 + reset_payload_len, &ret); ++ if (ret != (14 + reset_payload_len)) { ++ STP_ERR_FUNC("stp test sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, ++ ret); ++ } ++ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ ++ stp_ctx_unlock(&stp_core_ctx); ++ } ++ ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush_context ++* DESCRIPTION ++* Flush STP Context ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++void mtk_wcn_stp_flush_context(void) ++{ ++ stp_rest_ctx_state(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_flush_rx_queue ++* DESCRIPTION ++* Flush STP Rx Queue ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++ ++void mtk_wcn_stp_flush_rx_queue(UINT32 type) ++{ ++ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++ if (type < MTKSTP_MAX_TASK_NUM) { ++ stp_core_ctx.ring[type].read_p = 0; ++ stp_core_ctx.ring[type].write_p = 0; ++ } ++ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* STP is ready? ++* PARAMETERS ++* none. ++* RETURNS ++* none ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void) ++#else ++MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) ++#endif ++{ ++ return STP_IS_READY(stp_core_ctx); ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_is_ready); ++#endif ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++#if STP_EXP_HID_API_EXPORT ++void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) ++#else ++void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) ++#endif ++{ ++ /* g_mtkstp_bluez_flag = bluez_flag; */ ++ STP_SET_BT_STK(stp_core_ctx, bluez_flag); ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); ++#endif ++/***************************************************************************** ++* FUNCTION ++* set stp debugging mdoe ++* DESCRIPTION ++* set stp debugging mdoe ++* PARAMETERS ++* dbg_mode: switch to dbg mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode) ++{ ++ STP_SET_ENABLE_DBG(stp_core_ctx, dbg_mode); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* set stp auto reset mdoe ++* DESCRIPTION ++* set stp auto reset mdoe ++* PARAMETERS ++* auto_rst: switch to auto reset mode ? ++* RETURNS ++* void ++*****************************************************************************/ ++void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst) ++{ ++ STP_SET_ENABLE_RST(stp_core_ctx, auto_rst); ++} ++ ++INT32 mtk_wcn_stp_notify_sleep_for_thermal(void) ++{ ++ return stp_psm_sleep_for_thermal(STP_PSM_CORE(stp_core_ctx)); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_open_btif ++* DESCRIPTION ++* init btif hw & sw by owner stp ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_open_btif(VOID) ++{ ++ return mtk_wcn_consys_stp_btif_open(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_open_close ++* DESCRIPTION ++* close btif hw & sw by owner stp ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_close_btif(VOID) ++{ ++ return mtk_wcn_consys_stp_btif_close(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_rx_cb_register ++* DESCRIPTION ++* register stp rx cb to btif ++* PARAMETERS ++* MTK_WCN_BTIF_RX_CB stp rx handle function ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ return mtk_wcn_consys_stp_btif_rx_cb_register(rx_cb); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_tx ++* DESCRIPTION ++* send stp package by btif ++* PARAMETERS ++* pBuf:package buffer pointer,len:package length ++* written_len:package written length ++* RETURNS ++* INT32 package length-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len) ++{ ++ INT32 iRet = -1; ++ ++ iRet = mtk_wcn_consys_stp_btif_tx(pBuf, len, written_len); ++ return iRet; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_wakeup_consys ++* DESCRIPTION ++* STP wakeup consys by btif ++* PARAMETERS ++* VOID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_wakeup_consys(VOID) ++{ ++ /*log wakeup int for debug */ ++ stp_dbg_pkt_log(7, 0, 0, 0, PKT_DIR_TX, NULL, 0); ++ return mtk_wcn_consys_stp_btif_wakeup(); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_dpidle_ctrl ++* DESCRIPTION ++* decide AP enter or exit deep idle ++* PARAMETERS ++* en_flag:1,enter,0,exit ++* RETURNS ++* always 0 ++*****************************************************************************/ ++INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ mtk_wcn_consys_stp_btif_dpidle_ctrl(en_flag); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_lpbk_ctrl ++* DESCRIPTION ++* enable stp internal lpbk test or not ++* PARAMETERS ++* mode:1,enable,0,disabel ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) ++{ ++ return mtk_wcn_consys_stp_btif_lpbk_ctrl(mode); ++} ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_logger_ctrl ++* DESCRIPTION ++* dump btif buffer or register status when No ACK or assert occurs ++* PARAMETERS ++* flag:see enum value in ENUM_BTIF_DBG_ID ++* RETURNS ++* INT32 0-success,other fail. ++*****************************************************************************/ ++INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag) ++{ ++ return mtk_wcn_consys_stp_btif_logger_ctrl(flag); ++} ++ ++VOID mtk_wcn_stp_ctx_save(void) ++{ ++ STP_INFO_FUNC("start ++\n"); ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ stp_psm_set_sleep_disable(stp_core_ctx.psm); ++ STP_INFO_FUNC("exit --\n"); ++} ++ ++VOID mtk_wcn_stp_ctx_restore(void) ++{ ++ STP_INFO_FUNC("start ++\n"); ++ stp_psm_set_sleep_enable(stp_core_ctx.psm); ++ stp_btm_reset_btm_wq(STP_BTM_CORE(stp_core_ctx)); ++ ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ else ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++#if STP_RETRY_OPTIMIZE ++ g_retry_times = 0; ++#endif ++ STP_INFO_FUNC("exit --\n"); ++} ++ ++INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(void) ++{ ++ INT32 ret = -1; ++ ++ if (mtk_wcn_stp_coredump_start_get() != 0) { ++ STP_INFO_FUNC("firmware assert has been triggered\n"); ++ return 0; ++ } ++ ++ ret = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); ++ if (ret) { ++ STP_ERR_FUNC("evt err trigger assert fail,do chip reset to recovery\n"); ++ ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ if (STP_IS_ENABLE_RST(stp_core_ctx)) ++ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); ++ else ++ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); ++ } ++ ++ return ret; ++} ++ ++VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value) ++{ ++ STP_INFO_FUNC("set evt err tigger assert flag to %d\n", value); ++ STP_SET_EVT_ERR_ASSERT(stp_core_ctx, value); ++} ++ ++UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(void) ++{ ++ return STP_EVT_ERR_ASSERT(stp_core_ctx); ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c +new file mode 100644 +index 000000000000..3009bd26df41 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c +@@ -0,0 +1,529 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CONF]" ++ ++#include "osal_typedef.h" ++/* #include "osal.h" */ ++#include "wmt_lib.h" ++#include "wmt_dev.h" ++#include "wmt_conf.h" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++struct parse_data { ++ PINT8 name; ++ INT32 (*parser)(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 value); ++ PINT8 (*writer)(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ /*PINT8 param1, *param2, *param3; */ ++ /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */ ++ PINT8 param1; ++ PINT8 param2; ++ PINT8 param3; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); ++ ++static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data); ++ ++static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal); ++ ++static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size); ++ ++#define OFFSET(v) ((void *) &((P_DEV_WMT) 0)->v) ++ ++#define CHAR(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_char, \ ++ wmt_conf_write_char, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define CHAR(f) _CHAR(f), NULL, NULL} */ ++ ++#define SHORT(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_short, \ ++ wmt_conf_write_short, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define SHORT(f) _SHORT(f), NULL, NULL */ ++ ++#define INT(f) \ ++{ \ ++ #f, \ ++ wmt_conf_parse_int, \ ++ wmt_conf_write_int, \ ++ OFFSET(rWmtGenConf.f), \ ++ NULL, \ ++ NULL \ ++} ++/* #define INT(f) _INT(f), NULL, NULL */ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static const struct parse_data wmtcfg_fields[] = { ++ CHAR(coex_wmt_ant_mode), ++ CHAR(coex_wmt_ext_component), ++ CHAR(coex_wmt_wifi_time_ctl), ++ CHAR(coex_wmt_ext_pta_dev_on), ++ CHAR(coex_wmt_filter_mode), ++ ++ CHAR(coex_bt_rssi_upper_limit), ++ CHAR(coex_bt_rssi_mid_limit), ++ CHAR(coex_bt_rssi_lower_limit), ++ CHAR(coex_bt_pwr_high), ++ CHAR(coex_bt_pwr_mid), ++ CHAR(coex_bt_pwr_low), ++ ++ CHAR(coex_wifi_rssi_upper_limit), ++ CHAR(coex_wifi_rssi_mid_limit), ++ CHAR(coex_wifi_rssi_lower_limit), ++ CHAR(coex_wifi_pwr_high), ++ CHAR(coex_wifi_pwr_mid), ++ CHAR(coex_wifi_pwr_low), ++ ++ CHAR(coex_ext_pta_hi_tx_tag), ++ CHAR(coex_ext_pta_hi_rx_tag), ++ CHAR(coex_ext_pta_lo_tx_tag), ++ CHAR(coex_ext_pta_lo_rx_tag), ++ SHORT(coex_ext_pta_sample_t1), ++ SHORT(coex_ext_pta_sample_t2), ++ CHAR(coex_ext_pta_wifi_bt_con_trx), ++ ++ INT(coex_misc_ext_pta_on), ++ INT(coex_misc_ext_feature_set), ++ ++ CHAR(wmt_gps_lna_pin), ++ CHAR(wmt_gps_lna_enable), ++ ++ CHAR(pwr_on_rtc_slot), ++ CHAR(pwr_on_ldo_slot), ++ CHAR(pwr_on_rst_slot), ++ CHAR(pwr_on_off_slot), ++ CHAR(pwr_on_on_slot), ++ CHAR(co_clock_flag), ++ ++ INT(sdio_driving_cfg), ++ ++}; ++ ++#define NUM_WMTCFG_FIELDS (osal_sizeof(wmtcfg_fields) / osal_sizeof(wmtcfg_fields[0])) ++ ++static int wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PINT8 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT8 src; ++ INT32 res; ++ PINT8 value; ++ ++ src = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static int wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PUINT16 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT16 src; ++ INT32 res; ++ PINT8 value; ++ ++ /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */ ++ src = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static int wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) ++{ ++ PUINT32 dst; ++ long res; ++ int ret; ++ ++ dst = (PINT32) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ ++ ++ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { ++ ret = osal_strtol(pos + 2, 16, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); ++ } else { ++ ret = osal_strtol(pos, 10, &res); ++ if (ret) ++ WMT_ERR_FUNC("fail(%d)\n", ret); ++ *dst = res; ++ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); ++ } ++ ++ return 0; ++} ++ ++static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data) ++{ ++ PINT32 src; ++ INT32 res; ++ PINT8 value; ++ ++ src = (PUINT32) (((PUINT8) pWmtDev) + (long)data->param1); ++ ++ value = osal_malloc(20); ++ if (value == NULL) ++ return NULL; ++ res = osal_snprintf(value, 20, "0x%x", *src); ++ if (res < 0 || res >= 20) { ++ osal_free(value); ++ return NULL; ++ } ++ value[20 - 1] = '\0'; ++ return value; ++} ++ ++static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal) ++{ ++ int i = 0; ++ int ret = 0; ++ ++ /* WMT_INFO_FUNC( DBG_NAME "cfg(%s) val(%s)\n", pKey, pVal); */ ++ ++ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { ++ const struct parse_data *field = &wmtcfg_fields[i]; ++ ++ if (osal_strcmp(pKey, field->name) != 0) ++ continue; ++ if (field->parser(pWmtDev, field, pVal)) { ++ WMT_ERR_FUNC("failed to parse %s '%s'.\n", pKey, pVal); ++ ret = -1; ++ } ++ break; ++ } ++ if (i == NUM_WMTCFG_FIELDS) { ++ WMT_ERR_FUNC("unknown field '%s'.\n", pKey); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size) ++{ ++ PINT8 pch; ++ PINT8 pBuf; ++ PINT8 pLine; ++ PINT8 pKey; ++ PINT8 pVal; ++ PINT8 pPos; ++ INT32 ret = 0; ++ INT32 i = 0; ++ PINT8 pa = NULL; ++ ++ pBuf = osal_malloc(size); ++ if (!pBuf) ++ return -1; ++ ++ osal_memcpy(pBuf, pInBuf, size); ++ pBuf[size] = '\0'; ++ ++ pch = pBuf; ++ /* pch is to be updated by strsep(). Keep pBuf unchanged!! */ ++ ++#if 0 ++ { ++ PINT8 buf_ptr = pBuf; ++ INT32 k = 0; ++ ++ WMT_INFO_FUNC("%s len=%d", "wmcfg.content:", size); ++ for (k = 0; k < size; k++) { ++ /* if(k%16 == 0) WMT_INFO_FUNC("\n"); */ ++ WMT_INFO_FUNC("%c", buf_ptr[k]); ++ } ++ WMT_INFO_FUNC("--end\n"); ++ } ++#endif ++ ++ while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) { ++ /* pch is updated to the end of pLine by strsep() and updated to '\0' */ ++ /*WMT_INFO_FUNC("strsep offset(%d), char(%d, '%c' )\n", pLine-pBuf, *pLine, *pLine); */ ++ /* parse each line */ ++ ++ /* WMT_INFO_FUNC("==> Line = (%s)\n", pLine); */ ++ ++ if (!*pLine) ++ continue; ++ ++ pVal = osal_strchr(pLine, '='); ++ if (!pVal) { ++ WMT_WARN_FUNC("mal-format cfg string(%s)\n", pLine); ++ continue; ++ } ++ ++ /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */ ++ *pVal = '\0'; /* replace '=' with '\0' to get key */ ++ /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */ ++ pKey = pLine; ++ ++ if ((pVal - pBuf) < size) ++ pVal++; ++ ++ /*key handling */ ++ pPos = pKey; ++ /*skip space characeter */ ++ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*key head */ ++ pKey = pPos; ++ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*key tail */ ++ (*pPos) = '\0'; ++ ++ /*value handling */ ++ pPos = pVal; ++ /*skip space characeter */ ++ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*value head */ ++ pVal = pPos; ++ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { ++ if ((pPos - pBuf) >= size) ++ break; ++ pPos++; ++ } ++ /*value tail */ ++ (*pPos) = '\0'; ++ ++ /* WMT_DBG_FUNC("parse (key: #%s#, value: #%s#)\n", pKey, pVal); */ ++ ret = wmt_conf_parse_pair(pWmtDev, pKey, pVal); ++ WMT_DBG_FUNC("parse (%s, %s, %d)\n", pKey, pVal, ret); ++ if (ret) ++ WMT_WARN_FUNC("parse fail (%s, %s, %d)\n", pKey, pVal, ret); ++ } ++ ++ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { ++ const struct parse_data *field = &wmtcfg_fields[i]; ++ ++ pa = field->writer(pWmtDev, field); ++ if (pa) { ++ WMT_DBG_FUNC("#%d(%s)=>%s\n", i, field->name, pa); ++ osal_free(pa); ++ } else { ++ WMT_ERR_FUNC("failed to parse '%s'.\n", field->name); ++ } ++ } ++ osal_free(pBuf); ++ return 0; ++} ++ ++INT32 wmt_conf_set_cfg_file(const char *name) ++{ ++ if (NULL == name) { ++ WMT_ERR_FUNC("name is NULL\n"); ++ return -1; ++ } ++ if (osal_strlen(name) >= osal_sizeof(gDevWmt.cWmtcfgName)) { ++ WMT_ERR_FUNC("name is too long, length=%d, expect to < %d\n", osal_strlen(name), ++ osal_sizeof(gDevWmt.cWmtcfgName)); ++ return -2; ++ } ++ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); ++ osal_strcpy(&(gDevWmt.cWmtcfgName[0]), name); ++ WMT_ERR_FUNC("WMT config file is set to (%s)\n", &(gDevWmt.cWmtcfgName[0])); ++ ++ return 0; ++} ++ ++INT32 wmt_conf_read_file(VOID) ++{ ++ INT32 ret = -1; ++ ++ osal_memset(&gDevWmt.rWmtGenConf, 0, osal_sizeof(gDevWmt.rWmtGenConf)); ++ osal_memset(&gDevWmt.pWmtCfg, 0, osal_sizeof(gDevWmt.pWmtCfg)); ++ ++#if 1 ++ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); ++ ++ osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT_PREFIX, osal_sizeof(CUST_CFG_WMT_PREFIX)); ++ osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT, osal_sizeof(CUST_CFG_WMT)); ++#endif ++ ++ if (!osal_strlen(&(gDevWmt.cWmtcfgName[0]))) { ++ WMT_ERR_FUNC("empty Wmtcfg name\n"); ++ osal_assert(0); ++ return ret; ++ } ++ WMT_DBG_FUNC("WMT config file:%s\n", &(gDevWmt.cWmtcfgName[0])); ++ if (0 == wmt_dev_patch_get(&gDevWmt.cWmtcfgName[0], (osal_firmware **) &gDevWmt.pWmtCfg, 0)) { ++ /*get full name patch success */ ++ WMT_DBG_FUNC("get full file name(%s) buf(0x%p) size(%d)\n", ++ &gDevWmt.cWmtcfgName[0], gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size); ++ ++ if (0 == wmt_conf_parse(&gDevWmt, (const PINT8)gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size)) { ++ /*config file exists */ ++ gDevWmt.rWmtGenConf.cfgExist = 1; ++ ++ WMT_DBG_FUNC("&gDevWmt.rWmtGenConf=%p\n", &gDevWmt.rWmtGenConf); ++ ret = 0; ++ } else { ++ WMT_ERR_FUNC("wmt conf parsing fail\n"); ++ osal_assert(0); ++ ret = -1; ++ } ++ wmt_dev_patch_put((osal_firmware **) &gDevWmt.pWmtCfg); ++/* ++ if (gDevWmt.pWmtCfg) ++ { ++ if (gDevWmt.pWmtCfg->data) ++ { ++ osal_free(gDevWmt.pWmtCfg->data); ++ } ++ osal_free(gDevWmt.pWmtCfg); ++ gDevWmt.pWmtCfg = 0; ++ } ++*/ ++ return ret; ++ } ++ WMT_ERR_FUNC("read %s file fails\n", &(gDevWmt.cWmtcfgName[0])); ++ osal_assert(0); ++ ++ gDevWmt.rWmtGenConf.cfgExist = 0; ++ return ret; ++} ++ ++P_WMT_GEN_CONF wmt_conf_get_cfg(VOID) ++{ ++ if (0 == gDevWmt.rWmtGenConf.cfgExist) ++ return NULL; ++ ++ return &gDevWmt.rWmtGenConf; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c +new file mode 100644 +index 000000000000..cca6729d53a0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c +@@ -0,0 +1,2521 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CORE]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_lib.h" ++#include "wmt_core.h" ++#include "wmt_ctrl.h" ++#include "wmt_ic.h" ++#include "wmt_conf.h" ++ ++#include "wmt_func.h" ++#include "stp_core.h" ++#include "psm_core.h" ++ ++ ++P_WMT_FUNC_OPS gpWmtFuncOps[4] = { ++#if CFG_FUNC_BT_SUPPORT ++ [0] = &wmt_func_bt_ops, ++#else ++ [0] = NULL, ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ [1] = &wmt_func_fm_ops, ++#else ++ [1] = NULL, ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ [2] = &wmt_func_gps_ops, ++#else ++ [2] = NULL, ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++ [3] = &wmt_func_wifi_ops, ++#else ++ [3] = NULL, ++#endif ++ ++}; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* TODO:[FixMe][GeorgeKuo]: is it an MT6620 only or general general setting? ++*move to wmt_ic_6620 temporarily. ++*/ ++/* BT Port 2 Feature. */ ++/* #define CFG_WMT_BT_PORT2 (1) */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++static WMT_CTX gMtkWmtCtx; ++static UINT8 gLpbkBuf[1024+5] = { 0 }; ++#ifdef CONFIG_MTK_COMBO_ANT ++static UINT8 gAntBuf[1024] = { 0 }; ++#define CFG_CHECK_WMT_RESULT (1) ++#endif ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp); ++static INT32 opfunc_func_on(P_WMT_OP pWmtOp); ++static INT32 opfunc_func_off(P_WMT_OP pWmtOp); ++static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp); ++static INT32 opfunc_exit(P_WMT_OP pWmtOp); ++static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp); ++static INT32 opfunc_dsns(P_WMT_OP pWmtOp); ++static INT32 opfunc_lpbk(P_WMT_OP pWmtOp); ++static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp); ++static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp); ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp); ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp); ++static INT32 opfunc_pin_state(P_WMT_OP pWmtOp); ++static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp); ++static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp); ++static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp); ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp); ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++static INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp); ++static INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp); ++#endif ++static VOID wmt_core_dump_func_state(PINT8 pSource); ++static INT32 wmt_core_stp_init(VOID); ++static INT32 wmt_core_stp_deinit(VOID); ++static INT32 wmt_core_hw_check(VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static const UINT8 WMT_SLEEP_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x01 }; ++static const UINT8 WMT_SLEEP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; ++ ++static const UINT8 WMT_HOST_AWAKE_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x02 }; ++static const UINT8 WMT_HOST_AWAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; ++ ++static const UINT8 WMT_WAKEUP_CMD[] = { 0xFF }; ++static const UINT8 WMT_WAKEUP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++ ++static UINT8 WMT_THERM_CMD[] = { 0x01, 0x11, 0x01, 0x00, ++ 0x00 /*thermal sensor operation */ ++}; ++static UINT8 WMT_THERM_CTRL_EVT[] = { 0x02, 0x11, 0x01, 0x00, 0x00 }; ++static UINT8 WMT_THERM_READ_EVT[] = { 0x02, 0x11, 0x02, 0x00, 0x00, 0x00 }; ++ ++static UINT8 WMT_EFUSE_CMD[] = { 0x01, 0x0D, 0x08, 0x00, ++ 0x01, /*[4]operation, 0:init, 1:write 2:read */ ++ 0x01, /*[5]Number of register setting */ ++ 0xAA, 0xAA, /*[6-7]Address */ ++ 0xBB, 0xBB, 0xBB, 0xBB /*[8-11] Value */ ++}; ++ ++static UINT8 WMT_EFUSE_EVT[] = { 0x02, 0x0D, 0x08, 0x00, ++ 0xAA, /*[4]operation, 0:init, 1:write 2:read */ ++ 0xBB, /*[5]Number of register setting */ ++ 0xCC, 0xCC, /*[6-7]Address */ ++ 0xDD, 0xDD, 0xDD, 0xDD /*[8-11] Value */ ++}; ++ ++static UINT8 WMT_DSNS_CMD[] = { 0x01, 0x0E, 0x02, 0x00, 0x01, ++ 0x00 /*desnse type */ ++}; ++static UINT8 WMT_DSNS_EVT[] = { 0x02, 0x0E, 0x01, 0x00, 0x00 }; ++ ++/* TODO:[NewFeature][GeorgeKuo] Update register group in ONE CMD/EVT */ ++static UINT8 WMT_SET_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x00 /*op: w(1) & r(2) */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*res */ ++ , 0x01 /*1 register */ ++ , 0x00, 0x00, 0x00, 0x00 /* addr */ ++ , 0x00, 0x00, 0x00, 0x00 /* value */ ++ , 0xFF, 0xFF, 0xFF, 0xFF /*mask */ ++}; ++ ++static UINT8 WMT_SET_REG_WR_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 register */ ++ /* , 0x00, 0x00, 0x00, 0x00 */ /* addr */ ++ /* , 0x00, 0x00, 0x00, 0x00 */ /* value */ ++}; ++ ++static UINT8 WMT_SET_REG_RD_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 register */ ++ , 0x00, 0x00, 0x00, 0x00 /* addr */ ++ , 0x00, 0x00, 0x00, 0x00 /* value */ ++}; ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++static UINT8 WMT_ANT_RAM_STA_GET_CMD[] = { 0x01, 0x06, 0x02, 0x00, 0x05, 0x02 ++}; ++ ++static UINT8 WMT_ANT_RAM_STA_GET_EVT[] = { 0x02, 0x06, 0x03, 0x00 /*length */ ++ , 0x05, 0x02, 0x00 /*S: result */ ++}; ++ ++static UINT8 WMT_ANT_RAM_DWN_CMD[] = { 0x01, 0x15, 0x00, 0x00, 0x01 ++}; ++ ++static UINT8 WMT_ANT_RAM_DWN_EVT[] = { 0x02, 0x15, 0x01, 0x00 /*length */ ++ , 0x00 ++}; ++#endif ++ ++/* GeorgeKuo: Use designated initializers described in ++ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html ++ */ ++ ++static const WMT_OPID_FUNC wmt_core_opfunc[] = { ++ [WMT_OPID_HIF_CONF] = opfunc_hif_conf, ++ [WMT_OPID_PWR_ON] = opfunc_pwr_on, ++ [WMT_OPID_PWR_OFF] = opfunc_pwr_off, ++ [WMT_OPID_FUNC_ON] = opfunc_func_on, ++ [WMT_OPID_FUNC_OFF] = opfunc_func_off, ++ [WMT_OPID_REG_RW] = opfunc_reg_rw, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++ [WMT_OPID_EXIT] = opfunc_exit, ++ [WMT_OPID_PWR_SV] = opfunc_pwr_sv, ++ [WMT_OPID_DSNS] = opfunc_dsns, ++ [WMT_OPID_LPBK] = opfunc_lpbk, ++ [WMT_OPID_CMD_TEST] = opfunc_cmd_test, ++ [WMT_OPID_HW_RST] = opfunc_hw_rst, ++ [WMT_OPID_SW_RST] = opfunc_sw_rst, ++ [WMT_OPID_STP_RST] = opfunc_stp_rst, ++ [WMT_OPID_THERM_CTRL] = opfunc_therm_ctrl, ++ [WMT_OPID_EFUSE_RW] = opfunc_efuse_rw, ++ [WMT_OPID_GPIO_CTRL] = opfunc_gpio_ctrl, ++ [WMT_OPID_GPIO_STATE] = opfunc_pin_state, ++ [WMT_OPID_BGW_DS] = opfunc_bgw_ds, ++ [WMT_OPID_SET_MCU_CLK] = opfunc_set_mcu_clk, ++ [WMT_OPID_ADIE_LPBK_TEST] = opfunc_adie_lpbk_test, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [WMT_OPID_IDC_MSG_HANDLING] = opfunc_idc_msg_handling, ++#endif ++#ifdef CONFIG_MTK_COMBO_ANT ++ [WMT_OPID_ANT_RAM_DOWN] = opfunc_ant_ram_down, ++ [WMT_OPID_ANT_RAM_STA_GET] = opfunc_ant_ram_stat_get, ++#endif ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_core_init(VOID) ++{ ++ INT32 i = 0; ++ ++ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); ++ /* gMtkWmtCtx.p_ops is cleared to NULL */ ++ ++ /* default FUNC_OFF state */ ++ for (i = 0; i < WMTDRV_TYPE_MAX; ++i) { ++ /* WinMo is default to DRV_STS_UNREG; */ ++ gMtkWmtCtx.eDrvStatus[i] = DRV_STS_POWER_OFF; ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_core_deinit(VOID) ++{ ++ /* return to init state */ ++ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); ++ /* gMtkWmtCtx.p_ops is cleared to NULL */ ++ return 0; ++} ++ ++/* TODO: [ChangeFeature][George] Is wmt_ctrl a good interface? maybe not...... */ ++/* parameters shall be copied in/from ctrl buffer, which is also a size-wasting buffer. */ ++INT32 wmt_core_tx(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) ++{ ++ INT32 iRet; ++#if 0 /* Test using direct function call instead of wmt_ctrl() interface */ ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_TX; ++ ctrlData.au4CtrlData[0] = (UINT32) pData; ++ ctrlData.au4CtrlData[1] = size; ++ ctrlData.au4CtrlData[2] = (UINT32) writtenSize; ++ ctrlData.au4CtrlData[3] = bRawFlag; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_TX, iRet:%d\n", iRet); ++ /* (*sys_dbg_assert)(0, __FILE__, __LINE__); */ ++ osal_assert(0); ++ } ++#endif ++ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++ if (0 == *writtenSize) { ++ INT32 retry_times = 0; ++ INT32 max_retry_times = 3; ++ INT32 retry_delay_ms = 360; ++ ++ WMT_WARN_FUNC("WMT-CORE: wmt_ctrl_tx_ex failed and written ret:%d, maybe no winspace in STP layer\n", ++ *writtenSize); ++ while ((0 == *writtenSize) && (retry_times < max_retry_times)) { ++ WMT_ERR_FUNC("WMT-CORE: retrying, wait for %d ms\n", retry_delay_ms); ++ osal_sleep_ms(retry_delay_ms); ++ ++ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++ retry_times++; ++ } ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize) ++{ ++ INT32 iRet; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_RX; ++ ctrlData.au4CtrlData[0] = (SIZE_T) pBuf; ++ ctrlData.au4CtrlData[1] = bufLen; ++ ctrlData.au4CtrlData[2] = (SIZE_T) readSize; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX, iRet:%d\n", iRet); ++ mtk_wcn_stp_dbg_dump_package(); ++ osal_assert(0); ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_rx_flush(UINT32 type) ++{ ++ INT32 iRet; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_RX_FLUSH; ++ ctrlData.au4CtrlData[0] = (UINT32) type; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX_FLUSH, iRet:%d\n", iRet); ++ osal_assert(0); ++ } ++ return iRet; ++} ++ ++INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn) ++{ ++ INT32 iRet = 0; ++ UINT32 u4WmtCmdPduLen; ++ UINT32 u4WmtEventPduLen; ++ UINT32 u4ReadSize; ++ UINT32 u4WrittenSize; ++ WMT_PKT rWmtPktCmd; ++ WMT_PKT rWmtPktEvent; ++ MTK_WCN_BOOL fgFail; ++ ++ /* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ ++ /* Using this struct relies on compiler's implementation and pack() settings */ ++ osal_memset(&rWmtPktCmd, 0, osal_sizeof(rWmtPktCmd)); ++ osal_memset(&rWmtPktEvent, 0, osal_sizeof(rWmtPktEvent)); ++ ++ rWmtPktCmd.eType = (UINT8) PKT_TYPE_CMD; ++ rWmtPktCmd.eOpCode = (UINT8) OPCODE_FUNC_CTRL; ++ ++ /* Flag field: driver type */ ++ rWmtPktCmd.aucParam[0] = (UINT8) type; ++ /* Parameter field: ON/OFF */ ++ rWmtPktCmd.aucParam[1] = (fgEn == WMT_FUNC_CTRL_ON) ? 1 : 0; ++ rWmtPktCmd.u2SduLen = WMT_FLAG_LEN + WMT_FUNC_CTRL_PARAM_LEN; /* (2) */ ++ ++ /* WMT Header + WMT SDU */ ++ u4WmtCmdPduLen = WMT_HDR_LEN + rWmtPktCmd.u2SduLen; /* (6) */ ++ u4WmtEventPduLen = WMT_HDR_LEN + WMT_STS_LEN; /* (5) */ ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++/* iRet = (*kal_stp_tx)((PUINT8)&rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize); */ ++ iRet = wmt_core_tx((PUINT8) &rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize, MTK_WCN_BOOL_FALSE); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_tx failed\n"); ++ break; ++ } ++ ++ iRet = wmt_core_rx((PUINT8) &rWmtPktEvent, u4WmtEventPduLen, &u4ReadSize); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_rx failed\n"); ++ break; ++ } ++ ++ /* Error Checking */ ++ if (PKT_TYPE_EVENT != rWmtPktEvent.eType) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd PKT_TYPE_EVENT != rWmtPktEvent.eType %d\n", ++ rWmtPktEvent.eType); ++ break; ++ } ++ ++ if (rWmtPktCmd.eOpCode != rWmtPktEvent.eOpCode) { ++ WMT_ERR_FUNC ++ ("WMT-CORE: wmt_func_ctrl_cmd rWmtPktCmd.eOpCode(0x%x) != rWmtPktEvent.eType(0x%x)\n", ++ rWmtPktCmd.eOpCode, rWmtPktEvent.eOpCode); ++ break; ++ } ++ ++ if (u4WmtEventPduLen != (rWmtPktEvent.u2SduLen + WMT_HDR_LEN)) { ++ WMT_ERR_FUNC ++ ("WMT-CORE: wmt_func_ctrl_cmd u4WmtEventPduLen(0x%x) != rWmtPktEvent.u2SduLen(0x%x)+4\n", ++ u4WmtEventPduLen, rWmtPktEvent.u2SduLen); ++ break; ++ } ++ /* Status field of event check */ ++ if (0 != rWmtPktEvent.aucParam[0]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd, 0 != status(%d)\n", rWmtPktEvent.aucParam[0]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ } while (0); ++ ++ if (MTK_WCN_BOOL_FALSE == fgFail) { ++ /* WMT_INFO_FUNC("WMT-CORE: wmt_func_ctrl_cmd OK!\n"); */ ++ return 0; ++ } ++ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd 0x%x FAIL\n", rWmtPktCmd.aucParam[0]); ++ return -3; ++} ++ ++INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp) ++{ ++ UINT32 opId; ++ INT32 ret; ++ ++ opId = pWmtOp->opId; ++ ++ if (wmt_core_opfunc[opId]) { ++ ret = (*(wmt_core_opfunc[opId])) (pWmtOp); /*wmtCoreOpidHandlerPack[].opHandler */ ++ return ret; ++ } ++ WMT_ERR_FUNC("WMT-CORE: null handler (%d)\n", pWmtOp->opId); ++ return -2; ++ ++} ++ ++INT32 wmt_core_opid(P_WMT_OP pWmtOp) ++{ ++ ++ /*sanity check */ ++ if (NULL == pWmtOp) { ++ WMT_ERR_FUNC("null pWmtOP\n"); ++ /*print some message with error info */ ++ return -1; ++ } ++ ++ if (WMT_OPID_MAX <= pWmtOp->opId) { ++ WMT_ERR_FUNC("WMT-CORE: invalid OPID(%d)\n", pWmtOp->opId); ++ return -2; ++ } ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ return wmt_core_opid_handler(pWmtOp); ++} ++ ++INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2) ++{ ++ INT32 iRet = -1; ++ WMT_CTRL_DATA ctrlData; ++ SIZE_T val1 = (pPa1) ? *pPa1 : 0; ++ SIZE_T val2 = (pPa2) ? *pPa2 : 0; ++ ++ ctrlData.ctrlId = (SIZE_T) ctrId; ++ ctrlData.au4CtrlData[0] = val1; ++ ctrlData.au4CtrlData[1] = val2; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /* ERROR */ ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: id(%d), type(%d), value(%d) iRet:(%d)\n", ctrId, val1, ++ val2, iRet); ++ osal_assert(0); ++ } else { ++ if (pPa1) ++ *pPa1 = ctrlData.au4CtrlData[0]; ++ if (pPa2) ++ *pPa2 = ctrlData.au4CtrlData[1]; ++ } ++ return iRet; ++} ++ ++VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len) ++{ ++ PUINT8 ptr = pData; ++ INT32 k = 0; ++ ++ WMT_INFO_FUNC("%s len=%d\n", pTitle, len); ++ for (k = 0; k < len; k++) { ++ if (k % 16 == 0) ++ WMT_INFO_FUNC("\n"); ++ WMT_INFO_FUNC("0x%02x ", *ptr); ++ ptr++; ++ } ++ WMT_INFO_FUNC("--end\n"); ++} ++ ++/*! ++ * \brief An WMT-CORE function to support read, write, and read after write to ++ * an internal register. ++ * ++ * Detailed description. ++ * ++ * \param isWrite 1 for write, 0 for read ++ * \param offset of register to be written or read ++ * \param pVal a pointer to the 32-bit value to be writtern or read ++ * \param mask a 32-bit mask to be applied for the read or write operation ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ * \retval -2 tx cmd fail ++ * \retval -3 rx event fail ++ * \retval -4 read check error ++ */ ++INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask) ++{ ++ INT32 iRet; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_SET_REG_CMD[4] = (isWrite) ? 0x1 : 0x2; /* w:1, r:2 */ ++ osal_memcpy(&WMT_SET_REG_CMD[8], &offset, 4); /* offset */ ++ osal_memcpy(&WMT_SET_REG_CMD[12], pVal, 4); /* [2] is var addr */ ++ osal_memcpy(&WMT_SET_REG_CMD[16], &mask, 4); /* mask */ ++ ++ /* send command */ ++ iRet = wmt_core_tx(WMT_SET_REG_CMD, sizeof(WMT_SET_REG_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if ((iRet) || (u4Res != sizeof(WMT_SET_REG_CMD))) { ++ WMT_ERR_FUNC("Tx REG_CMD fail!(%d) len (%d, %d)\n", iRet, u4Res, sizeof(WMT_SET_REG_CMD)); ++ return -2; ++ } ++ ++ /* receive event */ ++ evtLen = (isWrite) ? sizeof(WMT_SET_REG_WR_EVT) : sizeof(WMT_SET_REG_RD_EVT); ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if ((iRet) || (u4Res != evtLen)) { ++ WMT_ERR_FUNC("Rx REG_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ return -3; ++ } ++ ++ if (!isWrite) { ++ UINT32 rxEvtAddr; ++ UINT32 txCmdAddr; ++ ++ osal_memcpy(&txCmdAddr, &WMT_SET_REG_CMD[8], 4); ++ osal_memcpy(&rxEvtAddr, &evtBuf[8], 4); ++ ++ /* check read result */ ++ if (txCmdAddr != rxEvtAddr) { ++ WMT_ERR_FUNC("Check read addr fail (0x%08x, 0x%08x)\n", rxEvtAddr, txCmdAddr); ++ return -4; ++ } ++ WMT_DBG_FUNC("Check read addr(0x%08x) ok\n", rxEvtAddr); ++ ++ osal_memcpy(pVal, &evtBuf[12], 4); ++ } ++ ++ /* no error here just return 0 */ ++ return 0; ++} ++ ++INT32 wmt_core_init_script(struct init_script *script, INT32 count) ++{ ++ UINT8 evtBuf[256]; ++ UINT32 u4Res; ++ INT32 i = 0; ++ INT32 iRet; ++ ++ for (i = 0; i < count; i++) { ++ WMT_DBG_FUNC("WMT-CORE: init_script operation %s start\n", script[i].str); ++ /* CMD */ ++ /* iRet = (*kal_stp_tx)(script[i].cmd, script[i].cmdSz, &u4Res); */ ++ iRet = wmt_core_tx(script[i].cmd, script[i].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != script[i].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", script[i].str, iRet, u4Res, ++ script[i].cmdSz); ++ break; ++ } ++ /* EVENT BUF */ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ iRet = wmt_core_rx(evtBuf, script[i].evtSz, &u4Res); ++ if (iRet || (u4Res != script[i].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", script[i].str, iRet, ++ u4Res, script[i].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ break; ++ } ++ /* RESULT */ ++ if (0x14 != evtBuf[1]) { /* workaround RF calibration data EVT,do not care this EVT */ ++ if (osal_memcmp(evtBuf, script[i].evt, script[i].evtSz) != 0) { ++ WMT_ERR_FUNC("WMT-CORE:compare %s result error\n", script[i].str); ++ WMT_ERR_FUNC ++ ("WMT-CORE:rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], script[i].evtSz, ++ script[i].evt[0], script[i].evt[1], script[i].evt[2], script[i].evt[3], ++ script[i].evt[4]); ++ mtk_wcn_stp_dbg_dump_package(); ++ break; ++ } ++ } ++ WMT_DBG_FUNC("init_script operation %s ok\n", script[i].str); ++ } ++ ++ return (i == count) ? 0 : -1; ++} ++ ++static INT32 wmt_core_stp_init(VOID) ++{ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT8 co_clock_type; ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ P_WMT_GEN_CONF pWmtGenConf = NULL; ++ ++ wmt_conf_read_file(); ++ pWmtGenConf = wmt_conf_get_cfg(); ++ if (!(pctx->wmtInfoBit & WMT_OP_HIF_BIT)) { ++ WMT_ERR_FUNC("WMT-CORE: no hif info!\n"); ++ osal_assert(0); ++ return -1; ++ } ++ /* 4 <1> open stp */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -2; ++ } ++ /* 4 <1.5> disable and un-ready stp */ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ /* 4 <2> set mode and enable */ ++ if (WMT_HIF_BTIF == pctx->wmtHifConf.hifType) { ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_MAND_MODE; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ } ++ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); ++ return -3; ++ } ++ /* TODO: [ChangeFeature][GeorgeKuo] can we apply raise UART baud rate firstly for ALL supported chips??? */ ++ ++ iRet = wmt_core_hw_check(); ++ if (iRet) { ++ WMT_ERR_FUNC("hw_check fail:%d\n", iRet); ++ return -4; ++ } ++ /* mtkWmtCtx.p_ic_ops is identified and checked ok */ ++ if ((NULL != pctx->p_ic_ops->co_clock_ctrl) && (pWmtGenConf != NULL)) { ++ co_clock_type = (pWmtGenConf->co_clock_flag & 0x0f); ++ (*(pctx->p_ic_ops->co_clock_ctrl)) (co_clock_type == 0 ? WMT_CO_CLOCK_DIS : WMT_CO_CLOCK_EN); ++ } else { ++ WMT_WARN_FUNC("pctx->p_ic_ops->co_clock_ctrl(0x%x), pWmtGenConf(0x%x)\n", pctx->p_ic_ops->co_clock_ctrl, ++ pWmtGenConf); ++ } ++ osal_assert(NULL != pctx->p_ic_ops->sw_init); ++ if (NULL != pctx->p_ic_ops->sw_init) { ++ iRet = (*(pctx->p_ic_ops->sw_init)) (&pctx->wmtHifConf); ++ } else { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); ++ return -5; ++ } ++ if (iRet) { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init fail:%d\n", iRet); ++ return -6; ++ } ++ /* 4 <10> set stp ready */ ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 1; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ return iRet; ++} ++ ++static INT32 wmt_core_stp_deinit(VOID) ++{ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ WMT_DBG_FUNC(" start\n"); ++ ++ if (NULL == gMtkWmtCtx.p_ic_ops) { ++ WMT_WARN_FUNC("gMtkWmtCtx.p_ic_ops is NULL\n"); ++ goto deinit_ic_ops_done; ++ } ++ if (NULL != gMtkWmtCtx.p_ic_ops->sw_deinit) { ++ iRet = (*(gMtkWmtCtx.p_ic_ops->sw_deinit)) (&gMtkWmtCtx.wmtHifConf); ++ /* unbind WMT-IC */ ++ gMtkWmtCtx.p_ic_ops = NULL; ++ } else { ++ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); ++ } ++ ++deinit_ic_ops_done: ++ ++ /* 4 <1> un-ready, disable, and close stp. */ ++ ctrlPa1 = WMT_STP_CONF_RDY; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ ++ if (iRet) ++ WMT_WARN_FUNC("end with fail:%d\n", iRet); ++ ++ return iRet; ++} ++ ++static VOID wmt_core_dump_func_state(PINT8 pSource) ++{ ++ WMT_WARN_FUNC("[%s]status(b:%d f:%d g:%d w:%d lpbk:%d coredump:%d wmt:%d stp:%d)\n", ++ (pSource == NULL ? (PINT8) "CORE" : pSource), ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP], ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] ++ ); ++ return; ++ ++} ++ ++MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer) ++{ ++ if (MAJORNUM(u4HwVer) != MAJORNUM(u4PatchVer)) { ++ /*major no. does not match */ ++ WMT_ERR_FUNC("WMT-CORE: chip version(0x%d) does not match patch version(0x%d)\n", u4HwVer, u4PatchVer); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++static INT32 wmt_core_hw_check(VOID) ++{ ++ UINT32 chipid; ++ P_WMT_IC_OPS p_ops; ++ INT32 iret; ++ ++ /* 1. get chip id */ ++ chipid = 0; ++ WMT_LOUD_FUNC("before read hwcode (chip id)\n"); ++ iret = wmt_core_reg_rw_raw(0, GEN_HCR, &chipid, GEN_HCR_MASK); /* read 0x80000008 */ ++ if (iret) { ++ WMT_ERR_FUNC("get hwcode (chip id) fail (%d)\n", iret); ++ return -2; ++ } ++ WMT_DBG_FUNC("get hwcode (chip id) (0x%x)\n", chipid); ++ ++ /* TODO:[ChangeFeature][George]: use a better way to select a correct ops table based on chip id */ ++ switch (chipid) { ++#if CFG_CORE_MT6620_SUPPORT ++ case 0x6620: ++ p_ops = &wmt_ic_ops_mt6620; ++ break; ++#endif ++#if CFG_CORE_MT6628_SUPPORT ++ case 0x6628: ++ p_ops = &wmt_ic_ops_mt6628; ++ break; ++#endif ++#if CFG_CORE_SOC_SUPPORT ++ case 0x6572: ++ case 0x6582: ++ case 0x6592: ++ case 0x8127: ++ case 0x6571: ++ case 0x6752: ++ case 0x0279: ++ case 0x0326: ++ case 0x0321: ++ case 0x0335: ++ case 0x0337: ++ case 0x8163: ++ case 0x6580: ++ p_ops = &wmt_ic_ops_soc; ++ break; ++#endif ++ default: ++ p_ops = (P_WMT_IC_OPS) NULL; ++#if CFG_CORE_SOC_SUPPORT ++ if (0x7f90 == chipid - 0x600) { ++ p_ops = &wmt_ic_ops_soc; ++ chipid -= 0xf6d; ++ } ++#endif ++ break; ++ } ++ ++ if (NULL == p_ops) { ++ WMT_ERR_FUNC("unsupported chip id (hw_code): 0x%x\n", chipid); ++ return -3; ++ } else if (MTK_WCN_BOOL_FALSE == wmt_core_ic_ops_check(p_ops)) { ++ WMT_ERR_FUNC ++ ("chip id(0x%x) with null operation fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", ++ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); ++ return -4; ++ } ++ WMT_DBG_FUNC("chip id(0x%x) fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", ++ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); ++ ++ wmt_ic_ops_soc.icId = chipid; ++ WMT_DBG_FUNC("wmt_ic_ops_soc.icId(0x%x)\n", wmt_ic_ops_soc.icId); ++ iret = p_ops->ic_ver_check(); ++ if (iret) { ++ WMT_ERR_FUNC("chip id(0x%x) ver_check error:%d\n", chipid, iret); ++ return -5; ++ } ++ ++ WMT_DBG_FUNC("chip id(0x%x) ver_check ok\n", chipid); ++ gMtkWmtCtx.p_ic_ops = p_ops; ++ return 0; ++} ++ ++static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp) ++{ ++ if (!(pWmtOp->u4InfoBit & WMT_OP_HIF_BIT)) { ++ WMT_ERR_FUNC("WMT-CORE: no HIF_BIT in WMT_OP!\n"); ++ return -1; ++ } ++ ++ if (gMtkWmtCtx.wmtInfoBit & WMT_OP_HIF_BIT) { ++ WMT_ERR_FUNC("WMT-CORE: WMT HIF already exist. overwrite! old (%d), new(%d))\n", ++ gMtkWmtCtx.wmtHifConf.hifType, pWmtOp->au4OpData[0]); ++ } else { ++ gMtkWmtCtx.wmtInfoBit |= WMT_OP_HIF_BIT; ++ WMT_ERR_FUNC("WMT-CORE: WMT HIF info added\n"); ++ } ++ ++ osal_memcpy(&gMtkWmtCtx.wmtHifConf, &pWmtOp->au4OpData[0], osal_sizeof(gMtkWmtCtx.wmtHifConf)); ++ return 0; ++ ++} ++ ++static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ INT32 retry = WMT_PWRON_RTY_DFT; ++ ++ if (DRV_STS_POWER_OFF != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: already powered on, WMT DRV_STS_[0x%x]\n", ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); ++ osal_assert(0); ++ return -1; ++ } ++ /* TODO: [FixMe][GeorgeKuo]: clarify the following is reqiured or not! */ ++ if (pWmtOp->u4InfoBit & WMT_OP_HIF_BIT) ++ opfunc_hif_conf(pWmtOp); ++ ++pwr_on_rty: ++ /* power on control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); ++ if (0 == retry--) { ++ WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); ++ goto pwr_on_rty; ++ } ++ return -1; ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* init stp */ ++ iRet = wmt_core_stp_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_init fail (%d)\n", iRet); ++ osal_assert(0); ++ ++ /* deinit stp */ ++ iRet = wmt_core_stp_deinit(); ++ iRet = opfunc_pwr_off(pWmtOp); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: opfunc_pwr_off fail during pwr_on retry\n"); ++ ++ if (0 < retry--) { ++ WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); ++ goto pwr_on_rty; ++ } ++ iRet = -2; ++ return iRet; ++ } ++ ++ WMT_DBG_FUNC("WMT-CORE: WMT [FUNC_ON]\n"); ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; ++ ++ /* What to do when state is changed from POWER_OFF to POWER_ON? ++ * 1. STP driver does s/w reset ++ * 2. UART does 0xFF wake up ++ * 3. SDIO does re-init command(changed to trigger by host) ++ */ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_WARN_FUNC("WMT-CORE: WMT already off, WMT DRV_STS_[0x%x]\n", ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); ++ osal_assert(0); ++ return -1; ++ } ++ if (MTK_WCN_BOOL_FALSE == g_pwr_off_flag) { ++ WMT_WARN_FUNC("CONNSYS power off be disabled, maybe need trigger core dump!\n"); ++ osal_assert(0); ++ return -2; ++ } ++ ++ /* wmt and stp are initialized successfully */ ++ if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ iRet = wmt_core_stp_deinit(); ++ if (iRet) { ++ WMT_WARN_FUNC("wmt_core_stp_deinit fail (%d)\n", iRet); ++ /*should let run to power down chip */ ++ } ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* power off control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_OFF, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_WARN_FUNC("HW_PWR_OFF fail (%d)\n", iRet); ++ WMT_WARN_FUNC("HW_PWR_OFF ok\n"); ++ ++ /*anyway, set to POWER_OFF state */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; ++ return iRet; ++ ++} ++ ++static INT32 opfunc_func_on(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ INT32 iPwrOffRet = -1; ++ UINT32 drvType; ++ ++ drvType = pWmtOp->au4OpData[0]; ++ ++ /* Check abnormal type */ ++ if (WMTDRV_TYPE_COREDUMP < drvType) { ++ WMT_ERR_FUNC("abnormal Fun(%d)\n", drvType); ++ osal_assert(0); ++ return -1; ++ } ++ ++ /* Check abnormal state */ ++ if ((DRV_STS_POWER_OFF > gMtkWmtCtx.eDrvStatus[drvType]) ++ || (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType])) { ++ WMT_ERR_FUNC("func(%d) status[0x%x] abnormal\n", drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ osal_assert(0); ++ return -2; ++ } ++ ++ /* check if func already on */ ++ if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_WARN_FUNC("func(%d) already on\n", drvType); ++ return 0; ++ } ++ /*enable power off flag, if flag=0, power off connsys will not be executed */ ++ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); ++ /* check if chip power on is needed */ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ iRet = opfunc_pwr_on(pWmtOp); ++ ++ if (iRet) { ++ WMT_ERR_FUNC("func(%d) pwr_on fail(%d)\n", drvType, iRet); ++ osal_assert(0); ++ ++ /* check all sub-func and do power off */ ++ return -3; ++ } ++ } ++ ++ if (WMTDRV_TYPE_WMT > drvType) { ++ if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_on) { ++ iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ if (0 != iRet) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ else ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ } else { ++ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); ++ iRet = -5; ++ } ++ } else { ++ if (WMTDRV_TYPE_LPBK == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ else if (WMTDRV_TYPE_COREDUMP == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; ++ iRet = 0; ++ } ++ ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet); ++ osal_assert(0); ++ /* FIX-ME:[Chaozhong Liang], Error handling? check subsystem state and do pwr off if necessary? */ ++ /* check all sub-func and do power off */ ++ if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { ++ WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); ++ mtk_wcn_wmt_system_state_reset(); ++ ++ iPwrOffRet = opfunc_pwr_off(pWmtOp); ++ if (iPwrOffRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iPwrOffRet, ++ drvType); ++ osal_assert(0); ++ } ++ } ++ return iRet; ++ } ++ ++ wmt_core_dump_func_state("AF FUNC ON"); ++ ++ return 0; ++} ++ ++static INT32 opfunc_func_off(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 drvType; ++ ++ drvType = pWmtOp->au4OpData[0]; ++ /* Check abnormal type */ ++ if (WMTDRV_TYPE_COREDUMP < drvType) { ++ WMT_ERR_FUNC("WMT-CORE: abnormal Fun(%d) in wmt_func_off\n", drvType); ++ osal_assert(0); ++ return -1; ++ } ++ ++ /* Check abnormal state */ ++ if (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_ERR_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] abnormal in wmt_func_off\n", ++ drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ osal_assert(0); ++ return -2; ++ } ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[drvType]) { ++ WMT_WARN_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n", ++ drvType, gMtkWmtCtx.eDrvStatus[drvType]); ++ /* needs to check 4 subsystem's state? */ ++ return 0; ++ } else if (WMTDRV_TYPE_WMT > drvType) { ++ if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_off) { ++ iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ } else { ++ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); ++ iRet = -3; ++ } ++ } else { ++ if (WMTDRV_TYPE_LPBK == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ else if (WMTDRV_TYPE_COREDUMP == drvType) ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ iRet = 0; ++ } ++ ++ /* shall we put device state to POWER_OFF state when fail? */ ++ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; ++ ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet); ++ osal_assert(0); ++ /* no matter subsystem function control fail or not, ++ *chip should be powered off when no subsystem is active ++ */ ++ /* return iRet; */ ++ } ++ ++ /* check all sub-func and do power off */ ++ if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && ++ (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { ++ WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); ++ ++ iRet = opfunc_pwr_off(pWmtOp); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iRet, drvType); ++ osal_assert(0); ++ } ++ } ++ ++ wmt_core_dump_func_state("AF FUNC OFF"); ++ return iRet; ++} ++ ++/* TODO:[ChangeFeature][George] is this OP obsoleted? */ ++static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp) ++{ ++ INT32 iret; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("reg_rw when WMT is powered off\n"); ++ return -1; ++ } ++ iret = wmt_core_reg_rw_raw(pWmtOp->au4OpData[0], ++ pWmtOp->au4OpData[1], (PUINT32) pWmtOp->au4OpData[2], pWmtOp->au4OpData[3]); ++ ++ return iret; ++} ++ ++static INT32 opfunc_exit(P_WMT_OP pWmtOp) ++{ ++ /* TODO: [FixMe][George] is ok to leave this function empty??? */ ++ WMT_WARN_FUNC("EMPTY FUNCTION\n"); ++ return 0; ++} ++ ++static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp) ++{ ++ INT32 ret = -1; ++ UINT32 u4_result = 0; ++ UINT32 evt_len; ++ UINT8 evt_buf[16] = { 0 }; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ typedef INT32(*STP_PSM_CB) (INT32); ++ STP_PSM_CB psm_cb = NULL; ++ ++ if (SLEEP == pWmtOp->au4OpData[0]) { ++ WMT_DBG_FUNC("**** Send sleep command\n"); ++ /* mtk_wcn_stp_set_psm_state(ACT_INACT); */ ++ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ ++ ret = wmt_core_tx((PUINT8) &WMT_SLEEP_CMD[0], sizeof(WMT_SLEEP_CMD), &u4_result, 0); ++ if (ret || (u4_result != sizeof(WMT_SLEEP_CMD))) { ++ WMT_ERR_FUNC("wmt_core: SLEEP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_SLEEP_CMD)); ++ goto pwr_sv_done; ++ } ++ ++ evt_len = sizeof(WMT_SLEEP_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 33; ++ unsigned long ctrlpa = 1; ++ ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: read SLEEP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 38; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_SLEEP_EVT, sizeof(WMT_SLEEP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_SLEEP_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_SLEEP_EVT), ++ WMT_SLEEP_EVT[0], ++ WMT_SLEEP_EVT[1], ++ WMT_SLEEP_EVT[2], ++ WMT_SLEEP_EVT[3], ++ WMT_SLEEP_EVT[4], ++ WMT_SLEEP_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ goto pwr_sv_done; ++ } else { ++ WMT_DBG_FUNC("Send sleep command OK!\n"); ++ } ++ } else if (pWmtOp->au4OpData[0] == WAKEUP) { ++ WMT_DBG_FUNC("wakeup connsys by btif"); ++ ++ ret = wmt_core_ctrl(WMT_CTRL_SOC_WAKEUP_CONSYS, &ctrlPa1, &ctrlPa2); ++ if (ret) { ++ WMT_ERR_FUNC("wmt-core:WAKEUP_CONSYS by BTIF fail(%d)", ret); ++ goto pwr_sv_done; ++ } ++#if 0 ++ WMT_DBG_FUNC("**** Send wakeup command\n"); ++ ret = wmt_core_tx(WMT_WAKEUP_CMD, sizeof(WMT_WAKEUP_CMD), &u4_result, 1); ++ ++ if (ret || (u4_result != sizeof(WMT_WAKEUP_CMD))) { ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: WAKEUP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_WAKEUP_CMD)); ++ goto pwr_sv_done; ++ } ++#endif ++ evt_len = sizeof(WMT_WAKEUP_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 34; ++ unsigned long ctrlpa = 2; ++ ++ WMT_ERR_FUNC("wmt_core: read WAKEUP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 39; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_WAKEUP_EVT, sizeof(WMT_WAKEUP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_WAKEUP_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_WAKEUP_EVT), ++ WMT_WAKEUP_EVT[0], ++ WMT_WAKEUP_EVT[1], ++ WMT_WAKEUP_EVT[2], ++ WMT_WAKEUP_EVT[3], ++ WMT_WAKEUP_EVT[4], ++ WMT_WAKEUP_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ goto pwr_sv_done; ++ } else { ++ WMT_DBG_FUNC("Send wakeup command OK!\n"); ++ } ++ } else if (pWmtOp->au4OpData[0] == HOST_AWAKE) { ++ ++ WMT_DBG_FUNC("**** Send host awake command\n"); ++ ++ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; ++ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ ++ ret = wmt_core_tx((PUINT8) WMT_HOST_AWAKE_CMD, sizeof(WMT_HOST_AWAKE_CMD), &u4_result, 0); ++ if (ret || (u4_result != sizeof(WMT_HOST_AWAKE_CMD))) { ++ WMT_ERR_FUNC("wmt_core: HOST_AWAKE_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, ++ sizeof(WMT_HOST_AWAKE_CMD)); ++ goto pwr_sv_done; ++ } ++ ++ evt_len = sizeof(WMT_HOST_AWAKE_EVT); ++ ret = wmt_core_rx(evt_buf, evt_len, &u4_result); ++ if (ret || (u4_result != evt_len)) { ++ unsigned long type = WMTDRV_TYPE_WMT; ++ unsigned long reason = 35; ++ unsigned long ctrlpa = 3; ++ ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: read HOST_AWAKE_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); ++ mtk_wcn_stp_dbg_dump_package(); ++ ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); ++ if (!ret) { /* parser ok */ ++ reason = 40; /* host schedule issue reason code */ ++ WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); ++ } ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); ++ goto pwr_sv_done; ++ } ++ ++ if (osal_memcmp(evt_buf, WMT_HOST_AWAKE_EVT, sizeof(WMT_HOST_AWAKE_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_HOST_AWAKE_EVT error\n"); ++ wmt_core_rx_flush(WMT_TASK_INDX); ++ WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ u4_result, ++ evt_buf[0], ++ evt_buf[1], ++ evt_buf[2], ++ evt_buf[3], ++ evt_buf[4], ++ evt_buf[5]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_HOST_AWAKE_EVT), ++ WMT_HOST_AWAKE_EVT[0], ++ WMT_HOST_AWAKE_EVT[1], ++ WMT_HOST_AWAKE_EVT[2], ++ WMT_HOST_AWAKE_EVT[3], ++ WMT_HOST_AWAKE_EVT[4], ++ WMT_HOST_AWAKE_EVT[5]); ++ mtk_wcn_stp_dbg_dump_package(); ++ /* goto pwr_sv_done; */ ++ } else { ++ WMT_DBG_FUNC("Send host awake command OK!\n"); ++ } ++ } ++pwr_sv_done: ++ ++ if (pWmtOp->au4OpData[0] < STP_PSM_MAX_ACTION) { ++ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; ++ WMT_DBG_FUNC("Do STP-CB! %d %p / %p\n", pWmtOp->au4OpData[0], (PVOID) pWmtOp->au4OpData[1], ++ (PVOID) psm_cb); ++ if (NULL != psm_cb) { ++ psm_cb(pWmtOp->au4OpData[0]); ++ } else { ++ WMT_ERR_FUNC("fatal error !!!, psm_cb = %p, god, someone must have corrupted our memory.\n", ++ psm_cb); ++ } ++ } ++ ++ return ret; ++} ++ ++static INT32 opfunc_dsns(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_DSNS_CMD[4] = (UINT8) pWmtOp->au4OpData[0]; ++ WMT_DSNS_CMD[5] = (UINT8) pWmtOp->au4OpData[1]; ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_DSNS_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: DSNS_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_DSNS_CMD)); ++ return iRet; ++ } ++ ++ evtLen = osal_sizeof(WMT_DSNS_EVT); ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || (u4Res != evtLen)) { ++ WMT_ERR_FUNC("WMT-CORE: read DSNS_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ mtk_wcn_stp_dbg_dump_package(); ++ return iRet; ++ } ++ ++ if (osal_memcmp(evtBuf, WMT_DSNS_EVT, osal_sizeof(WMT_DSNS_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_DSNS_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], ++ osal_sizeof(WMT_DSNS_EVT), WMT_DSNS_EVT[0], WMT_DSNS_EVT[1], WMT_DSNS_EVT[2], ++ WMT_DSNS_EVT[3], WMT_DSNS_EVT[4]); ++ } else { ++ WMT_INFO_FUNC("Send WMT_DSNS_CMD command OK!\n"); ++ } ++ ++ return iRet; ++} ++ ++#if CFG_CORE_INTERNAL_TXRX ++INT32 wmt_core_lpbk_do_stp_init(void) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -1; ++ } ++ ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_MAND_MODE; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); ++ return -2; ++ } ++} ++ ++INT32 wmt_core_lpbk_do_stp_deinit(void) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++#endif ++static INT32 opfunc_lpbk(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT32 buf_length = 0; ++ UINT32 *pbuffer = NULL; ++ UINT16 len_in_cmd; ++ ++ /* UINT32 offset; */ ++ UINT8 WMT_TEST_LPBK_CMD[] = { 0x1, 0x2, 0x0, 0x0, 0x7 }; ++ UINT8 WMT_TEST_LPBK_EVT[] = { 0x2, 0x2, 0x0, 0x0, 0x0 }; ++ ++ /* UINT8 lpbk_buf[1024 + 5] = {0}; */ ++ MTK_WCN_BOOL fgFail; ++ ++ buf_length = pWmtOp->au4OpData[0]; /* packet length */ ++ pbuffer = (VOID *) pWmtOp->au4OpData[1]; /* packet buffer pointer */ ++ WMT_DBG_FUNC("WMT-CORE: -->wmt_do_lpbk\n"); ++ ++#if 0 ++ osal_memcpy(&WMT_TEST_LPBK_EVT[0], &WMT_TEST_LPBK_CMD[0], osal_sizeof(WMT_TEST_LPBK_CMD)); ++#endif ++#if !CFG_CORE_INTERNAL_TXRX ++ /*check if WMTDRV_TYPE_LPBK function is already on */ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] ++ || buf_length + osal_sizeof(WMT_TEST_LPBK_CMD) > osal_sizeof(gLpbkBuf)) { ++ WMT_ERR_FUNC("WMT-CORE: abnormal LPBK in wmt_do_lpbk\n"); ++ osal_assert(0); ++ return -2; ++ } ++#endif ++ /*package loopback for STP */ ++ ++ /* init buffer */ ++ osal_memset(gLpbkBuf, 0, osal_sizeof(gLpbkBuf)); ++ ++ len_in_cmd = buf_length + 1; /* add flag field */ ++ ++ osal_memcpy(&WMT_TEST_LPBK_CMD[2], &len_in_cmd, 2); ++ osal_memcpy(&WMT_TEST_LPBK_EVT[2], &len_in_cmd, 2); ++ ++ /* wmt cmd */ ++ osal_memcpy(gLpbkBuf, WMT_TEST_LPBK_CMD, osal_sizeof(WMT_TEST_LPBK_CMD)); ++ osal_memcpy(gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), pbuffer, buf_length); ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ /*send packet through STP */ ++ ++ /* iRet = (*kal_stp_tx)( ++ *(PUINT8)gLpbkBuf, ++ *osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length, ++ *&u4WrittenSize); ++ */ ++ iRet = wmt_core_tx((PUINT8) gLpbkBuf, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length), ++ &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet) { ++ WMT_ERR_FUNC("opfunc_lpbk wmt_core_tx failed\n"); ++ break; ++ } ++ WMT_INFO_FUNC("opfunc_lpbk wmt_core_tx OK\n"); ++ ++ /*receive firmware response from STP */ ++ iRet = wmt_core_rx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_EVT) + buf_length), &u4ReadSize); ++ if (iRet) { ++ WMT_ERR_FUNC("opfunc_lpbk wmt_core_rx failed\n"); ++ break; ++ } ++ WMT_INFO_FUNC("opfunc_lpbk wmt_core_rx OK\n"); ++ /*check if loopback response ok or not */ ++ if (u4ReadSize != (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)) { ++ WMT_ERR_FUNC("lpbk event read size wrong(%d, %d)\n", u4ReadSize, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); ++ break; ++ } ++ WMT_INFO_FUNC("lpbk event read size right(%d, %d)\n", u4ReadSize, ++ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); ++ ++ if (osal_memcmp(WMT_TEST_LPBK_EVT, gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_EVT))) { ++ WMT_ERR_FUNC("WMT-CORE WMT_TEST_LPBK_EVT error! read len %d [%02x,%02x,%02x,%02x,%02x]\n", ++ (INT32) u4ReadSize, gLpbkBuf[0], gLpbkBuf[1], gLpbkBuf[2], gLpbkBuf[3], gLpbkBuf[4] ++ ); ++ break; ++ } ++ pWmtOp->au4OpData[0] = u4ReadSize - osal_sizeof(WMT_TEST_LPBK_EVT); ++ osal_memcpy((VOID *) pWmtOp->au4OpData[1], gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), buf_length); ++ fgFail = MTK_WCN_BOOL_FALSE; ++ } while (0); ++ /*return result */ ++ /* WMT_DBG_FUNC("WMT-CORE: <--wmt_do_lpbk, fgFail = %d\n", fgFail); */ ++ return fgFail; ++ ++} ++ ++static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = 0; ++ UINT32 cmdNo = 0; ++ UINT32 cmdNoPa = 0; ++ ++ UINT8 tstCmd[64]; ++ UINT8 tstEvt[64]; ++ UINT8 tstEvtTmp[64]; ++ UINT32 u4Res; ++ SIZE_T tstCmdSz = 0; ++ SIZE_T tstEvtSz = 0; ++ ++ UINT8 *pRes = NULL; ++ UINT32 resBufRoom = 0; ++ /*test command list */ ++ /*1 */ ++ UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; ++ UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_NOACK_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0A }; ++ UINT8 WMT_NOACK_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_WARNRST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0B }; ++ UINT8 WMT_WARNRST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ UINT8 WMT_FWLOGTST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0C }; ++ UINT8 WMT_FWLOGTST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ ++ UINT8 WMT_EXCEPTION_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x09 }; ++ UINT8 WMT_EXCEPTION_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; ++ /*2 */ ++ UINT8 WMT_COEXDBG_CMD[] = { 0x01, 0x10, 0x02, 0x00, ++ 0x08, ++ 0xAA /*Debugging Parameter */ ++ }; ++ UINT8 WMT_COEXDBG_1_EVT[] = { 0x02, 0x10, 0x05, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA /*event content */ ++ }; ++ UINT8 WMT_COEXDBG_2_EVT[] = { 0x02, 0x10, 0x07, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB /*event content */ ++ }; ++ UINT8 WMT_COEXDBG_3_EVT[] = { 0x02, 0x10, 0x0B, 0x00, ++ 0x00, ++ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB /*event content */ ++ }; ++ /*test command list -end */ ++ ++ cmdNo = pWmtOp->au4OpData[0]; ++ ++ WMT_INFO_FUNC("Send Test command %d!\n", cmdNo); ++ if (cmdNo == 0) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Assert command !\n"); ++ tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); ++ tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); ++ osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); ++ } else if (cmdNo == 1) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Exception command !\n"); ++ tstCmdSz = osal_sizeof(WMT_EXCEPTION_CMD); ++ tstEvtSz = osal_sizeof(WMT_EXCEPTION_EVT); ++ osal_memcpy(tstCmd, WMT_EXCEPTION_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_EXCEPTION_EVT, tstEvtSz); ++ } else if (cmdNo == 2) { ++ cmdNoPa = pWmtOp->au4OpData[1]; ++ pRes = (PUINT8) pWmtOp->au4OpData[2]; ++ resBufRoom = pWmtOp->au4OpData[3]; ++ if (cmdNoPa <= 0xf) { ++ WMT_INFO_FUNC("Send Coexistence Debug command [0x%x]!\n", cmdNoPa); ++ tstCmdSz = osal_sizeof(WMT_COEXDBG_CMD); ++ osal_memcpy(tstCmd, WMT_COEXDBG_CMD, tstCmdSz); ++ if (tstCmdSz > 5) ++ tstCmd[5] = cmdNoPa; ++ ++ /*setup the expected event length */ ++ if (cmdNoPa <= 0x4) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_1_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_1_EVT, tstEvtSz); ++ } else if (cmdNoPa == 0x5) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_2_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_2_EVT, tstEvtSz); ++ } else if (cmdNoPa >= 0x6 && cmdNoPa <= 0xf) { ++ tstEvtSz = osal_sizeof(WMT_COEXDBG_3_EVT); ++ osal_memcpy(tstEvt, WMT_COEXDBG_3_EVT, tstEvtSz); ++ } else { ++ ++ } ++ } else { ++ WMT_ERR_FUNC("cmdNoPa is wrong\n"); ++ return iRet; ++ } ++ } else if (cmdNo == 3) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send No Ack command !\n"); ++ tstCmdSz = osal_sizeof(WMT_NOACK_CMD); ++ tstEvtSz = osal_sizeof(WMT_NOACK_EVT); ++ osal_memcpy(tstCmd, WMT_NOACK_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_NOACK_EVT, tstEvtSz); ++ } else if (cmdNo == 4) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send Warm reset command !\n"); ++ tstCmdSz = osal_sizeof(WMT_WARNRST_CMD); ++ tstEvtSz = osal_sizeof(WMT_WARNRST_EVT); ++ osal_memcpy(tstCmd, WMT_WARNRST_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_WARNRST_EVT, tstEvtSz); ++ } else if (cmdNo == 5) { ++ /*dead command */ ++ WMT_INFO_FUNC("Send f/w log test command !\n"); ++ tstCmdSz = osal_sizeof(WMT_FWLOGTST_CMD); ++ tstEvtSz = osal_sizeof(WMT_FWLOGTST_EVT); ++ osal_memcpy(tstCmd, WMT_FWLOGTST_CMD, tstCmdSz); ++ osal_memcpy(tstEvt, WMT_FWLOGTST_EVT, tstEvtSz); ++ } ++ ++ else { ++ /*Placed youer test WMT command here, easiler to integrate and test with F/W side */ ++ } ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(tstCmd, tstCmdSz, &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != tstCmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, tstCmdSz); ++ return -1; ++ } ++ ++ if ((cmdNo == 0) || (cmdNo == 1) || cmdNo == 3) { ++ WMT_INFO_FUNC("WMT-CORE: not to rx event for assert command\n"); ++ return 0; ++ } ++ ++ iRet = wmt_core_rx(tstEvtTmp, tstEvtSz, &u4Res); ++ ++ /*Event Post Handling */ ++ if (cmdNo == 2) { ++ WMT_INFO_FUNC("#=========================================================#\n"); ++ WMT_INFO_FUNC("coext debugging id = %d", cmdNoPa); ++ if (tstEvtSz > 5) { ++ wmt_core_dump_data(&tstEvtTmp[5], "coex debugging ", tstEvtSz - 5); ++ } else { ++ /* error log */ ++ WMT_ERR_FUNC("error coex debugging event\n"); ++ } ++ /*put response to buffer for shell to read */ ++ if (pRes != NULL && resBufRoom > 0) { ++ pWmtOp->au4OpData[3] = resBufRoom < tstEvtSz - 5 ? resBufRoom : tstEvtSz - 5; ++ osal_memcpy(pRes, &tstEvtTmp[5], pWmtOp->au4OpData[3]); ++ } else ++ pWmtOp->au4OpData[3] = 0; ++ WMT_INFO_FUNC("#=========================================================#\n"); ++ } ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ wmt_core_dump_func_state("BE HW RST"); ++ /*-->Reset WMT data structure*/ ++ /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] = DRV_STS_POWER_OFF; ++ /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; */ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] = DRV_STS_POWER_OFF; ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = DRV_STS_POWER_OFF; ++ /*enable power off flag, if flag=0, power off connsys will not be executed */ ++ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); ++ /* if wmt is poweroff, we need poweron chip first */ ++ /* Zhiguo : this action also needed in BTIF interface to avoid KE */ ++#if 1 ++ if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_WARN_FUNC("WMT-CORE: WMT is off, need re-poweron\n"); ++ /* power on control */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); ++ return -1; ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ } ++#endif ++ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_FUNC_ON) { ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); ++ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; ++ } ++ ++ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_FUNC_ON) { ++ ++ if (NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI] && NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off) { ++ iRet = gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off(gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-CORE: turn off WIFI func fail (%d)\n", iRet); ++ ++ /* check all sub-func and do power off */ ++ } else { ++ WMT_INFO_FUNC("wmt core: turn off WIFI func ok!!\n"); ++ } ++ } ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; ++ } ++#if 0 ++ /*<4>Power off Combo chip */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF fail (%d)", iRet); ++ WMT_INFO_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF ok (%d)", iRet); ++#endif ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; ++ ++ /*-->PesetCombo chip*/ ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); ++ if (iRet) ++ WMT_ERR_FUNC("WMT-CORE: -->[HW RST] fail iRet(%d)\n", iRet); ++ WMT_WARN_FUNC("WMT-CORE: -->[HW RST] ok\n"); ++ ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; ++ ++ /* 4 close stp */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ if (iRet == -2) { ++ WMT_INFO_FUNC("WMT-CORE:stp should have be closed\n"); ++ return 0; ++ } ++ WMT_ERR_FUNC("WMT-CORE: wmt close stp failed\n"); ++ return -1; ++ } ++ ++ wmt_core_dump_func_state("AF HW RST"); ++ return iRet; ++ ++} ++ ++static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ ++ iRet = wmt_core_stp_init(); ++ if (!iRet) ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; ++ return iRet; ++} ++ ++static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp) ++{ ++ ++ return 0; ++} ++ ++static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ WMT_THERM_CMD[4] = pWmtOp->au4OpData[0]; /*CMD type, refer to ENUM_WMTTHERM_TYPE_T */ ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_THERM_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: THERM_CTRL_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_THERM_CMD)); ++ return iRet; ++ } ++ ++ evtLen = 16; ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || ((u4Res != osal_sizeof(WMT_THERM_CTRL_EVT)) && (u4Res != osal_sizeof(WMT_THERM_READ_EVT)))) { ++ WMT_ERR_FUNC("WMT-CORE: read THERM_CTRL_EVT/THERM_READ_EVENT fail(%d) len(%d, %d)\n", iRet, u4Res, ++ evtLen); ++ mtk_wcn_stp_dbg_dump_package(); ++ return iRet; ++ } ++ if (u4Res == osal_sizeof(WMT_THERM_CTRL_EVT)) { ++ if (osal_memcmp(evtBuf, WMT_THERM_CTRL_EVT, osal_sizeof(WMT_THERM_CTRL_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_CTRL_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], ++ osal_sizeof(WMT_THERM_CTRL_EVT), WMT_THERM_CTRL_EVT[0], WMT_THERM_CTRL_EVT[1], ++ WMT_THERM_CTRL_EVT[2], WMT_THERM_CTRL_EVT[3], WMT_THERM_CTRL_EVT[4]); ++ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_FALSE; /*will return to function driver */ ++ mtk_wcn_stp_dbg_dump_package(); ++ } else { ++ WMT_DBG_FUNC("Send WMT_THERM_CTRL_CMD command OK!\n"); ++ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_TRUE; /*will return to function driver */ ++ } ++ } else { ++ /*no need to judge the real thermal value */ ++ if (osal_memcmp(evtBuf, WMT_THERM_READ_EVT, osal_sizeof(WMT_THERM_READ_EVT) - 1) != 0) { ++ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_READ_EVT error\n"); ++ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X]\n", ++ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5], ++ osal_sizeof(WMT_THERM_READ_EVT), WMT_THERM_READ_EVT[0], WMT_THERM_READ_EVT[1], ++ WMT_THERM_READ_EVT[2], WMT_THERM_READ_EVT[3]); ++ pWmtOp->au4OpData[1] = 0xFF; /*will return to function driver */ ++ mtk_wcn_stp_dbg_dump_package(); ++ } else { ++ WMT_DBG_FUNC("Send WMT_THERM_READ_CMD command OK!\n"); ++ pWmtOp->au4OpData[1] = evtBuf[5]; /*will return to function driver */ ++ } ++ } ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 u4Res; ++ UINT32 evtLen; ++ UINT8 evtBuf[16] = { 0 }; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_efuse_rw fail: chip is powered off\n"); ++ return -1; ++ } ++ ++ WMT_EFUSE_CMD[4] = (pWmtOp->au4OpData[0]) ? 0x1 : 0x2; /* w:2, r:1 */ ++ osal_memcpy(&WMT_EFUSE_CMD[6], (PUINT8) &pWmtOp->au4OpData[1], 2); /* address */ ++ osal_memcpy(&WMT_EFUSE_CMD[8], (PUINT32) pWmtOp->au4OpData[2], 4); /* value */ ++ ++ wmt_core_dump_data(&WMT_EFUSE_CMD[0], "efuse_cmd", osal_sizeof(WMT_EFUSE_CMD)); ++ ++ /* send command */ ++ /* iRet = (*kal_stp_tx)(WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res); */ ++ iRet = wmt_core_tx((PUINT8) WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(WMT_EFUSE_CMD))) { ++ WMT_ERR_FUNC("WMT-CORE: EFUSE_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, ++ osal_sizeof(WMT_EFUSE_CMD)); ++ return iRet; ++ } ++ ++ evtLen = (pWmtOp->au4OpData[0]) ? osal_sizeof(WMT_EFUSE_EVT) : osal_sizeof(WMT_EFUSE_EVT); ++ ++ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); ++ if (iRet || (u4Res != evtLen)) ++ WMT_ERR_FUNC("WMT-CORE: read REG_EVB fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); ++ wmt_core_dump_data(&evtBuf[0], "efuse_evt", osal_sizeof(evtBuf)); ++ ++ return iRet; ++ ++} ++ ++static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ WMT_IC_PIN_ID id; ++ WMT_IC_PIN_STATE stat; ++ UINT32 flag; ++ ++ if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { ++ WMT_ERR_FUNC("WMT-CORE: wmt_gpio_ctrl fail: chip is powered off\n"); ++ return -1; ++ } ++ ++ if (!gMtkWmtCtx.p_ic_ops->ic_pin_ctrl) { ++ WMT_ERR_FUNC("WMT-CORE: error, gMtkWmtCtx.p_ic_ops->ic_pin_ctrl(NULL)\n"); ++ return -1; ++ } ++ ++ id = pWmtOp->au4OpData[0]; ++ stat = pWmtOp->au4OpData[1]; ++ flag = pWmtOp->au4OpData[2]; ++ ++ WMT_INFO_FUNC("ic pin id:%d, stat:%d, flag:0x%x\n", id, stat, flag); ++ ++ iRet = (*(gMtkWmtCtx.p_ic_ops->ic_pin_ctrl)) (id, stat, flag); ++ ++ return iRet; ++} ++ ++MTK_WCN_BOOL wmt_core_is_quick_ps_support(void) ++{ ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ ++ if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_quick_sleep)) ++ return (*(pctx->p_ic_ops->is_quick_sleep)) (); ++ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_WMT_CTX pctx = &gMtkWmtCtx; ++ ++ if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_aee_dump_support)) ++ bRet = (*(pctx->p_ic_ops->is_aee_dump_support)) (); ++ else ++ bRet = MTK_WCN_BOOL_FALSE; ++ ++ return bRet; ++} ++ ++INT32 opfunc_pin_state(P_WMT_OP pWmtOp) ++{ ++ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ UINT32 iRet = 0; ++ ++ iRet = wmt_core_ctrl(WMT_CTRL_HW_STATE_DUMP, &ctrlPa1, &ctrlPa2); ++ return iRet; ++} ++ ++static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = -1; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT32 buf_len = 0; ++ UINT8 *buffer = NULL; ++ UINT8 evt_buffer[8] = { 0 }; ++ MTK_WCN_BOOL fgFail; ++ ++ UINT8 WMT_BGW_DESENSE_CMD[] = { ++ 0x01, 0x0e, 0x0f, 0x00, ++ 0x02, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00 ++ }; ++ UINT8 WMT_BGW_DESENSE_EVT[] = { 0x02, 0x0e, 0x01, 0x00, 0x00 }; ++ ++ buf_len = pWmtOp->au4OpData[0]; ++ buffer = (PUINT8) pWmtOp->au4OpData[1]; ++ ++ osal_memcpy(&WMT_BGW_DESENSE_CMD[5], buffer, buf_len); ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ iRet = ++ wmt_core_tx(&WMT_BGW_DESENSE_CMD[0], osal_sizeof(WMT_BGW_DESENSE_CMD), &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4WrittenSize != osal_sizeof(WMT_BGW_DESENSE_CMD))) { ++ WMT_ERR_FUNC("bgw desense tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); ++ break; ++ } ++ ++ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_BGW_DESENSE_EVT), &u4ReadSize); ++ if (iRet || (u4ReadSize != osal_sizeof(WMT_BGW_DESENSE_EVT))) { ++ WMT_ERR_FUNC("bgw desense rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize); ++ break; ++ } ++ ++ if (osal_memcmp(evt_buffer, WMT_BGW_DESENSE_EVT, osal_sizeof(WMT_BGW_DESENSE_EVT)) != 0) { ++ WMT_ERR_FUNC ++ ("bgw desense WMT_BGW_DESENSE_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", ++ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ return fgFail; ++} ++ ++static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp) ++{ ++ UINT32 kind = 0; ++ INT32 iRet = -1; ++ UINT32 u4WrittenSize = 0; ++ UINT32 u4ReadSize = 0; ++ UINT8 evt_buffer[12] = { 0 }; ++ MTK_WCN_BOOL fgFail; ++ PUINT8 set_mcu_clk_str[] = { ++ "Enable MCU PLL", ++ "SET MCU CLK to 26M", ++ "SET MCU CLK to 37M", ++ "SET MCU CLK to 64M", ++ "SET MCU CLK to 69M", ++ "SET MCU CLK to 104M", ++ "SET MCU CLK to 118.857M", ++ "SET MCU CLK to 138.67M", ++ "Disable MCU PLL" ++ }; ++ UINT8 WMT_SET_MCU_CLK_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++ }; ++ UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++ UINT8 WMT_EN_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00 }; /* enable pll clk */ ++ UINT8 WMT_26_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x00, 0x4d, 0x84, 0x00 }; /* set 26M */ ++ UINT8 WMT_37_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1e, 0x4d, 0x84, 0x00 }; /* set 37.8M */ ++ UINT8 WMT_64_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1d, 0x4d, 0x84, 0x00 }; /* set 64M */ ++ UINT8 WMT_69_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1c, 0x4d, 0x84, 0x00 }; /* set 69M */ ++ UINT8 WMT_104_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5b, 0x4d, 0x84, 0x00 }; /* set 104M */ ++ UINT8 WMT_108_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5a, 0x4d, 0x84, 0x00 }; /* set 118.857M */ ++ UINT8 WMT_138_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x59, 0x4d, 0x84, 0x00 }; /* set 138.67M */ ++ UINT8 WMT_DIS_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 }; /* disable pll clk */ ++ ++ kind = pWmtOp->au4OpData[0]; ++ WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]); ++ ++ switch (kind) { ++ case 0: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_EN_MCU_CLK_CMD[0], osal_sizeof(WMT_EN_MCU_CLK_CMD)); ++ break; ++ case 1: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_26_MCU_CLK_CMD[0], osal_sizeof(WMT_26_MCU_CLK_CMD)); ++ break; ++ case 2: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_37_MCU_CLK_CMD[0], osal_sizeof(WMT_37_MCU_CLK_CMD)); ++ break; ++ case 3: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_64_MCU_CLK_CMD[0], osal_sizeof(WMT_64_MCU_CLK_CMD)); ++ break; ++ case 4: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_69_MCU_CLK_CMD[0], osal_sizeof(WMT_69_MCU_CLK_CMD)); ++ break; ++ case 5: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_104_MCU_CLK_CMD[0], osal_sizeof(WMT_104_MCU_CLK_CMD)); ++ break; ++ case 6: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_108_MCU_CLK_CMD[0], osal_sizeof(WMT_108_MCU_CLK_CMD)); ++ break; ++ case 7: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_138_MCU_CLK_CMD[0], osal_sizeof(WMT_138_MCU_CLK_CMD)); ++ break; ++ case 8: ++ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_DIS_MCU_CLK_CMD[0], osal_sizeof(WMT_DIS_MCU_CLK_CMD)); ++ break; ++ default: ++ WMT_ERR_FUNC("unknown kind\n"); ++ break; ++ } ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ iRet = ++ wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); ++ break; ++ } ++ ++ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); ++ if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); ++ break; ++ } ++ ++ if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { ++ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", ++ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4], ++ evt_buffer[5], evt_buffer[6], evt_buffer[7]); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ if (MTK_WCN_BOOL_FALSE == fgFail) ++ WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]); ++ ++ WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]); ++ ++ return fgFail; ++} ++ ++static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp) ++{ ++ UINT8 *buffer = NULL; ++ MTK_WCN_BOOL fgFail; ++ UINT32 u4Res; ++ UINT32 aDieChipid = 0; ++ UINT8 soc_adie_chipid_cmd[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; ++ UINT8 soc_adie_chipid_evt[] = { 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ UINT8 evtbuf[20]; ++ INT32 iRet = -1; ++ ++ buffer = (PUINT8) pWmtOp->au4OpData[1]; ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ /* read A die chipid by wmt cmd */ ++ iRet = ++ wmt_core_tx((PUINT8) &soc_adie_chipid_cmd[0], osal_sizeof(soc_adie_chipid_cmd), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_cmd))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, osal_sizeof(soc_adie_chipid_evt), &u4Res); ++ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_evt))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); ++ osal_memcpy(buffer, &evtbuf[u4Res - 2], 2); ++ pWmtOp->au4OpData[0] = 2; ++ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ ++ return fgFail; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp) ++{ ++ MTK_WCN_BOOL fgFail; ++ UINT32 u4Res; ++ UINT8 host_lte_btwf_coex_cmd[] = { 0x01, 0x10, 0x00, 0x00, 0x00 }; ++ UINT8 host_lte_btwf_coex_evt[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ UINT8 *pTxBuf = NULL; ++ UINT8 evtbuf[8] = { 0 }; ++ INT32 iRet = -1; ++ UINT16 msg_len = 0; ++ UINT32 total_len = 0; ++ UINT32 index = 0; ++ UINT8 *msg_local_buffer = NULL; ++ ++ msg_local_buffer = kmalloc(1300, GFP_KERNEL); ++ if (!msg_local_buffer) { ++ WMT_ERR_FUNC("msg_local_buffer kmalloc memory fail\n"); ++ return 0; ++ } ++ ++ pTxBuf = (UINT8 *) pWmtOp->au4OpData[0]; ++ if (NULL == pTxBuf) { ++ WMT_ERR_FUNC("idc msg buffer is NULL\n"); ++ return -1; ++ } ++ iRet = wmt_lib_idc_lock_aquire(); ++ if (iRet) { ++ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", iRet); ++ return iRet; ++ } ++ osal_memcpy(&msg_len, &pTxBuf[0], osal_sizeof(msg_len)); ++ if (msg_len > 1200) { ++ wmt_lib_idc_lock_release(); ++ WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len); ++ return -2; ++ } ++ msg_len += 1; /*flag byte */ ++ ++ osal_memcpy(&host_lte_btwf_coex_cmd[2], &msg_len, 2); ++ host_lte_btwf_coex_cmd[4] = (pWmtOp->au4OpData[1] & 0x00ff); ++ osal_memcpy(&msg_local_buffer[0], &host_lte_btwf_coex_cmd[0], osal_sizeof(host_lte_btwf_coex_cmd)); ++ osal_memcpy(&msg_local_buffer[osal_sizeof(host_lte_btwf_coex_cmd)], ++ &pTxBuf[osal_sizeof(msg_len)], msg_len - 1); ++ ++ wmt_lib_idc_lock_release(); ++ total_len = osal_sizeof(host_lte_btwf_coex_cmd) + msg_len - 1; ++ ++ WMT_DBG_FUNC("wmt_core:idc msg payload len form lte(%d),wmt msg total len(%d)\n", msg_len - 1, ++ total_len); ++ WMT_DBG_FUNC("wmt_core:idc msg payload:\n"); ++ ++ for (index = 0; index < total_len; index++) ++ WMT_DBG_FUNC("0x%02x ", msg_local_buffer[index]); ++ ++ ++ do { ++ fgFail = MTK_WCN_BOOL_TRUE; ++ ++ /* read A die chipid by wmt cmd */ ++ iRet = wmt_core_tx((PUINT8) &msg_local_buffer[0], total_len, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != total_len)) { ++ WMT_ERR_FUNC("wmt_core:send lte idc msg to connsys fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, osal_sizeof(host_lte_btwf_coex_evt), &u4Res); ++ if (iRet || (u4Res != osal_sizeof(host_lte_btwf_coex_evt))) { ++ WMT_ERR_FUNC("wmt_core:recv host_lte_btwf_coex_evt fail(%d),size(%d)\n", iRet, u4Res); ++ break; ++ } ++ ++ fgFail = MTK_WCN_BOOL_FALSE; ++ ++ } while (0); ++ kfree(msg_local_buffer); ++ return fgFail; ++} ++#endif ++ ++VOID wmt_core_set_coredump_state(ENUM_DRV_STS state) ++{ ++ WMT_INFO_FUNC("wmt-core: set coredump state(%d)\n", state); ++ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = state; ++} ++#ifdef CONFIG_MTK_COMBO_ANT ++INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ size_t ctrlPa1 = pWmtOp->au4OpData[0]; ++ UINT32 ctrlPa2 = pWmtOp->au4OpData[1]; ++ PUINT8 pbuf = (PUINT8) ctrlPa1; ++ UINT32 fragSeq = 0; ++ UINT16 fragSize = 0; ++ UINT16 wmtCmdLen; ++ UINT16 wmtPktLen; ++ UINT32 u4Res = 0; ++ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_DWN_EVT)]; ++#if 1 ++ UINT32 ctrlPa3 = pWmtOp->au4OpData[2]; ++ ++ do { ++ fragSize = ctrlPa2; ++ fragSeq = ctrlPa3; ++ gAntBuf[5] = fragSeq; ++ ++ ++ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_DWN_CMD) + 1; ++ ++ /*WMT command length cal */ ++ wmtCmdLen = wmtPktLen - 4; ++#if 0 ++ WMT_ANT_RAM_DWN_CMD[2] = wmtCmdLen & 0xFF; ++ WMT_ANT_RAM_DWN_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; ++#else ++ osal_memcpy(&WMT_ANT_RAM_DWN_CMD[2], &wmtCmdLen, 2); ++#endif ++ ++ ++ ++ WMT_ANT_RAM_DWN_CMD[4] = 1; /*RAM CODE download */ ++ ++ osal_memcpy(gAntBuf, WMT_ANT_RAM_DWN_CMD, sizeof(WMT_ANT_RAM_DWN_CMD)); ++ ++ /*copy ram code content to global buffer */ ++ osal_memcpy(&gAntBuf[osal_sizeof(WMT_ANT_RAM_DWN_CMD) + 1], pbuf, fragSize); ++ ++ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, wmtPktLen, u4Res); ++ ++ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); ++ ++ WMT_ANT_RAM_DWN_EVT[4] = 0; /*download result; 0 */ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_DWN_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_DWN_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) fail(%d)\n", ++ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res, iRet); ++ iRet = -5; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_DWN_EVT, sizeof(WMT_ANT_RAM_DWN_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_DWN_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], ++ antEvtBuf[4], sizeof(WMT_ANT_RAM_DWN_EVT), WMT_ANT_RAM_DWN_EVT[0], ++ WMT_ANT_RAM_DWN_EVT[1], WMT_ANT_RAM_DWN_EVT[2], WMT_ANT_RAM_DWN_EVT[3], ++ WMT_ANT_RAM_DWN_EVT[4]); ++ iRet = -6; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) ok\n", ++ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res); ++ ++ } while (0); ++#else ++ UINT32 patchSize = ctrlPa2; ++ UINT32 patchSizePerFrag = 1000; ++ UINT32 offset; ++ UINT32 fragNum = 0; ++ /*cal patch fragNum */ ++ fragNum = (patchSize + patchSizePerFrag - 1) / patchSizePerFrag; ++ if (2 >= fragNum) { ++ WMT_WARN_FUNC("ANT ramcode size(%d) too short\n", patchSize); ++ return -1; ++ } ++ ++ while (fragSeq < fragNum) { ++ /*update fragNum */ ++ fragSeq++; ++ ++ if (1 == fragSeq) { ++ fragSize = patchSizePerFrag; ++ /*first package */ ++ gAntBuf[5] = 1; /*RAM CODE start */ ++ } else if (fragNum == fragSeq) { ++ /*last package */ ++ fragSize = patchSizePerFrag; ++ gAntBuf[5] = 3; /*RAM CODE end */ ++ } else { ++ /*middle package */ ++ fragSize = patchSize - ((fragNum - 1) * patchSizePerFrag); ++ gAntBuf[5] = 2; /*RAM CODE confinue */ ++ } ++ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_OP_CMD) + 1; ++ ++ /*WMT command length cal */ ++ wmtCmdLen = wmtPktLen - 4; ++ ++ WMT_ANT_RAM_OP_CMD[2] = wmtCmdLen & 0xFF; ++ WMT_ANT_RAM_OP_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; ++ ++ WMT_ANT_RAM_OP_CMD[4] = 1; /*RAM CODE download */ ++ ++ osal_memcpy(gAntBuf, WMT_ANT_RAM_OP_CMD, sizeof(WMT_ANT_RAM_OP_CMD)); ++ ++ /*copy ram code content to global buffer */ ++ osal_memcpy(&gAntBuf[6], pbuf, fragSize); ++ ++ /*update offset */ ++ offset += fragSize; ++ pbuf += offset; ++ ++ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, wmtPktLen, u4Res); ++ ++ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); ++ ++ WMT_SET_RAM_OP_EVT[4] = 0; /*download result; 0 */ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_SET_RAM_OP_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_SET_RAM_OP_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) fail(%d)\n", ++ sizeof(WMT_SET_RAM_OP_EVT), u4Res, iRet); ++ iRet = -5; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_SET_RAM_OP_EVT, sizeof(WMT_SET_RAM_OP_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_SET_RAM_OP_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], ++ antEvtBuf[4], sizeof(WMT_SET_RAM_OP_EVT), WMT_SET_RAM_OP_EVT[0], ++ WMT_SET_RAM_OP_EVT[1], WMT_SET_RAM_OP_EVT[2], WMT_SET_RAM_OP_EVT[3], ++ WMT_SET_RAM_OP_EVT[4]); ++ iRet = -6; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) ok\n", ++ sizeof(WMT_SET_RAM_OP_EVT), u4Res); ++ ++ ++ } ++ if (fragSeq != fragNum) ++ iRet = -7; ++#endif ++ return iRet; ++} ++ ++ ++INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp) ++{ ++ INT32 iRet = 0; ++ UINT32 u4Res = 0; ++ UINT32 wmtPktLen = osal_sizeof(WMT_ANT_RAM_STA_GET_CMD); ++ UINT32 u4AntRamStatus = 0; ++ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_STA_GET_EVT)]; ++ ++ ++ iRet = wmt_core_tx(WMT_ANT_RAM_STA_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != wmtPktLen)) { ++ WMT_ERR_FUNC ++ ("wmt_core: write wmt and ramcode status query command failed, (%d, %d), iRet(%d)\n", ++ wmtPktLen, u4Res, iRet); ++ iRet = -4; ++ return iRet; ++ } ++ ++ ++ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_STA_GET_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_STA_GET_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_STA_GET_EVT length(%zu, %d) fail(%d)\n", ++ sizeof(WMT_ANT_RAM_STA_GET_EVT), u4Res, iRet); ++ iRet = -5; ++ return iRet; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_STA_GET_EVT, sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1) != ++ 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_STA_GET_EVT result error\n"); ++ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], antEvtBuf[4], ++ sizeof(WMT_ANT_RAM_STA_GET_EVT), WMT_ANT_RAM_STA_GET_EVT[0], ++ WMT_ANT_RAM_STA_GET_EVT[1], WMT_ANT_RAM_STA_GET_EVT[2], ++ WMT_ANT_RAM_STA_GET_EVT[3], WMT_ANT_RAM_STA_GET_EVT[4]); ++ iRet = -6; ++ return iRet; ++ } ++#endif ++ if (0 == iRet) { ++ u4AntRamStatus = antEvtBuf[sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1]; ++ pWmtOp->au4OpData[2] = u4AntRamStatus; ++ WMT_INFO_FUNC("ANT ram code %s\n", ++ 1 == u4AntRamStatus ? "exist already" : "not exist"); ++ } ++ return iRet; ++} ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++/*TEST CODE*/ ++static UINT32 g_open_wmt_lte_flag; ++VOID wmt_core_set_flag_for_test(UINT32 enable) ++{ ++ WMT_INFO_FUNC("%s wmt_lte_flag\n", enable ? "enable" : "disable"); ++ g_open_wmt_lte_flag = enable; ++} ++ ++UINT32 wmt_core_get_flag_for_test(VOID) ++{ ++ return g_open_wmt_lte_flag; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c +new file mode 100644 +index 000000000000..fa603c208e59 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c +@@ -0,0 +1,1019 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CTRL]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++ ++#include "wmt_ctrl.h" ++#include "wmt_core.h" ++#include "wmt_ic.h" ++#include "wmt_lib.h" ++#include "wmt_dev.h" ++#include "wmt_plat.h" ++#include "stp_core.h" ++#include "stp_dbg.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* moved to wmt_ctrl.h */ ++/*static INT32 wmt_ctrl_tx_ex (UINT8 *pData, UINT32 size, UINT32 *writtenSize, MTK_WCN_BOOL bRawFlag);*/ ++ ++static INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value); ++ ++static INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA); ++#if 0 ++static INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA); ++#endif ++static INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_others(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData); ++static INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA); ++static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData); ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA); ++#endif ++ ++static INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA); ++ ++static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData); ++ ++static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData); ++ ++static INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData); ++ ++/* TODO: [FixMe][GeorgeKuo]: remove unused function */ ++/*static INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA);*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* GeorgeKuo: Use designated initializers described in ++ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html ++ */ ++static const WMT_CTRL_FUNC wmt_ctrl_func[] = { ++ [WMT_CTRL_HW_PWR_OFF] = wmt_ctrl_hw_pwr_off, ++ [WMT_CTRL_HW_PWR_ON] = wmt_ctrl_hw_pwr_on, ++ [WMT_CTRL_HW_RST] = wmt_ctrl_hw_rst, ++ [WMT_CTRL_STP_CLOSE] = wmt_ctrl_stp_close, ++ [WMT_CTRL_STP_OPEN] = wmt_ctrl_stp_open, ++ [WMT_CTRL_STP_CONF] = wmt_ctrl_stp_conf, ++ [WMT_CTRL_FREE_PATCH] = wmt_ctrl_free_patch, ++ [WMT_CTRL_GET_PATCH] = wmt_ctrl_get_patch, ++ [WMT_CTRL_GET_PATCH_NAME] = wmt_ctrl_get_patch_name, ++ [WMT_CTRL_HWIDVER_SET] = wmt_ctrl_hwidver_set, ++ [WMT_CTRL_STP_RST] = wmt_ctrl_stp_rst, ++ [WMT_CTRL_GET_WMT_CONF] = wmt_ctrl_get_wmt_conf, ++ [WMT_CTRL_TX] = wmt_ctrl_tx, ++ [WMT_CTRL_RX] = wmt_ctrl_rx, ++ [WMT_CTRL_RX_FLUSH] = wmt_ctrl_rx_flush, ++ [WMT_CTRL_GPS_SYNC_SET] = wmt_ctrl_gps_sync_set, ++ [WMT_CTRL_GPS_LNA_SET] = wmt_ctrl_gps_lna_set, ++ [WMT_CTRL_PATCH_SEARCH] = wmt_ctrl_patch_search, ++ [WMT_CTRL_CRYSTAL_TRIMING_GET] = wmt_ctrl_crystal_triming_get, ++ [WMT_CTRL_CRYSTAL_TRIMING_PUT] = wmt_ctrl_crystal_triming_put, ++ [WMT_CTRL_HW_STATE_DUMP] = wmt_ctrl_hw_state_show, ++ [WMT_CTRL_GET_PATCH_NUM] = wmt_ctrl_get_patch_num, ++ [WMT_CTRL_GET_PATCH_INFO] = wmt_ctrl_get_patch_info, ++ [WMT_CTRL_SOC_PALDO_CTRL] = wmt_ctrl_soc_paldo_ctrl, ++ [WMT_CTRL_SOC_WAKEUP_CONSYS] = wmt_ctrl_soc_wakeup_consys, ++ [WMT_CTRL_SET_STP_DBG_INFO] = wmt_ctrl_set_stp_dbg_info, ++ [WMT_CTRL_BGW_DESENSE_CTRL] = wmt_ctrl_bgw_desense_ctrl, ++ [WMT_CTRL_EVT_ERR_TRG_ASSERT] = wmt_ctrl_evt_err_trg_assert, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [WMT_CTRL_GET_TDM_REQ_ANTSEL] = wmt_ctrl_get_tdm_req_antsel, ++#endif ++ [WMT_CTRL_EVT_PARSER] = wmt_ctrl_evt_parser, ++ [WMT_CTRL_MAX] = wmt_ctrl_others, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 ctrlId; ++ ++ if (NULL == pWmtCtrlData) { ++ osal_assert(0); ++ return -1; ++ } ++ ++ ctrlId = pWmtCtrlData->ctrlId; ++ /*1sanity check, including wmtCtrlId */ ++ if ((NULL == pWmtCtrlData) ++ || (WMT_CTRL_MAX <= ctrlId)) ++ /* || (ctrlId < WMT_CTRL_HW_PWR_OFF) ) [FixMe][GeorgeKuo]: useless comparison */ ++ { ++ osal_assert(NULL != pWmtCtrlData); ++ osal_assert(WMT_CTRL_MAX > ctrlId); ++ /* osal_assert(ctrlId >= WMT_CTRL_HW_PWR_OFF); [FixMe][GeorgeKuo]: useless comparison */ ++ return -2; ++ } ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ if (wmt_ctrl_func[ctrlId]) { ++ /*call servicd handling API */ ++ return (*(wmt_ctrl_func[ctrlId])) (pWmtCtrlData); /* serviceHandlerPack[ctrlId].serviceHandler */ ++ } ++ osal_assert(NULL != wmt_ctrl_func[ctrlId]); ++ return -3; ++ ++} ++ ++INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pData, UINT32 size, UINT32 *writtenSize */) ++{ ++ UINT8 *pData = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ UINT32 size = pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 writtenSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ MTK_WCN_BOOL bRawFlag = pWmtCtrlData->au4CtrlData[3]; ++ ++ return wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); ++} ++ ++INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pBuff, UINT32 buffLen, UINT32 *readSize */) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 readLen; ++ long waitRet = -1; ++ PUINT8 pBuff = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ UINT32 buffLen = pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 readSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ ++ if (readSize) ++ *readSize = 0; ++ ++ /* sanity check */ ++ if (!buffLen) { ++ WMT_WARN_FUNC("buffLen = 0\n"); ++ osal_assert(buffLen); ++ return 0; ++ } ++#if 0 ++ if (!pDev) { ++ WMT_WARN_FUNC("gpDevWmt = NULL\n"); ++ osal_assert(pDev); ++ return -1; ++ } ++#endif ++ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { ++ WMT_WARN_FUNC("state(0x%lx)\n", pDev->state); ++ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); ++ return -2; ++ } ++ ++ /* sanity ok, proceeding rx operation */ ++ /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ ++ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); ++ ++ while (readLen == 0) { /* got nothing, wait for STP's signal */ ++ WMT_LOUD_FUNC("before wmt_dev_rx_timeout\n"); ++ /* iRet = wait_event_interruptible(pdev->rWmtRxWq, osal_test_bit(WMT_STAT_RX, &pdev->state)); */ ++ /* waitRet = wait_event_interruptible_timeout( ++ * pDev->rWmtRxWq, ++ * osal_test_bit(WMT_STAT_RX, &pdev->state), ++ * msecs_to_jiffies(WMT_LIB_RX_TIMEOUT)); ++ */ ++ pDev->rWmtRxWq.timeoutValue = WMT_LIB_RX_TIMEOUT; ++ /* waitRet = osal_wait_for_event_bit_timeout(&pDev->rWmtRxWq, &pDev->state, WMT_STAT_RX); */ ++ waitRet = wmt_dev_rx_timeout(&pDev->rWmtRxWq); ++ ++ WMT_LOUD_FUNC("wmt_dev_rx_timeout returned\n"); ++ ++ if (0 == waitRet) { ++ WMT_ERR_FUNC("wmt_dev_rx_timeout: timeout,jiffies(%lu),timeoutvalue(%d)\n", ++ jiffies, pDev->rWmtRxWq.timeoutValue); ++ return -1; ++ } else if (waitRet < 0) { ++ WMT_WARN_FUNC("wmt_dev_rx_timeout: interrupted by signal (%ld)\n", waitRet); ++ return waitRet; ++ } ++ WMT_DBG_FUNC("wmt_dev_rx_timeout, iRet(%ld)\n", waitRet); ++ /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ ++ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); ++ ++ if (0 == readLen) ++ WMT_WARN_FUNC("wmt_ctrl_rx be signaled, but no rx data(%ld)\n", waitRet); ++ ++ } ++ ++ if (readSize) ++ *readSize = readLen; ++ ++ return 0; ++ ++} ++ ++INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ ++ if (NULL != writtenSize) ++ *writtenSize = 0; ++ ++ /* sanity check */ ++ if (0 == size) { ++ WMT_WARN_FUNC("size to tx is 0\n"); ++ osal_assert(size); ++ return -1; ++ } ++ ++ /* if STP is not enabled yet, can't use this function. Use tx_raw instead */ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state) || !osal_test_bit(WMT_STAT_STP_EN, &pDev->state)) { ++ WMT_ERR_FUNC("wmt state(0x%lx)\n", pDev->state); ++ osal_assert(osal_test_bit(WMT_STAT_STP_EN, &pDev->state)); ++ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); ++ return -2; ++ } ++ ++ /* sanity ok, proceeding tx operation */ ++ /*retval = mtk_wcn_stp_send_data(data, size, WMTDRV_TYPE_WMT); */ ++ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); ++ if (bRawFlag) ++ iRet = mtk_wcn_stp_send_data_raw(pData, size, WMT_TASK_INDX); ++ else ++ iRet = mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX); ++ ++ if (iRet != size) { ++ WMT_WARN_FUNC("write(%d) written(%d)\n", size, iRet); ++ osal_assert(iRet == size); ++ } ++ ++ if (writtenSize) ++ *writtenSize = iRet; ++ ++ return 0; ++ ++} ++ ++INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 type = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_INFO_FUNC("flush rx %d queue\n", type); ++ mtk_wcn_stp_flush_rx_queue(type); ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iret; ++ ++/*psm should be disabled before wmt_ic_deinit*/ ++ P_DEV_WMT pDev = &gDevWmt; ++ ++ if (osal_test_and_clear_bit(WMT_STAT_PWR, &pDev->state)) { ++ WMT_DBG_FUNC("on->off\n"); ++ iret = wmt_plat_pwr_ctrl(FUNC_OFF); ++ } else { ++ WMT_WARN_FUNC("already off\n"); ++ iret = 0; ++ } ++ ++ return iret; ++} ++ ++INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iret; ++ /*psm should be enabled right after wmt_ic_init */ ++ P_DEV_WMT pDev = &gDevWmt; ++ if (osal_test_and_set_bit(WMT_STAT_PWR, &pDev->state)) { ++ WMT_WARN_FUNC("already on\n"); ++ iret = 0; ++ } else { ++ WMT_DBG_FUNC("off->on\n"); ++ iret = wmt_plat_pwr_ctrl(FUNC_ON); ++ } ++ ++ return iret; ++} ++ ++INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const UINT8 *pCmdStr) ++{ ++ INT32 waitRet = -1; ++ P_OSAL_SIGNAL pCmdSignal; ++ P_OSAL_EVENT pCmdReq; ++ ++ if (osal_test_and_set_bit(WMT_STAT_CMD, &pWmtDev->state)) { ++ WMT_WARN_FUNC("cmd buf is occupied by (%s)\n", pWmtDev->cCmd); ++ return -1; ++ } ++ ++ /* indicate baud rate change to user space app */ ++#if 0 ++ INIT_COMPLETION(pWmtDev->cmd_comp); ++ pWmtDev->cmd_result = -1; ++ strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); ++ pWmtDev->cCmd[NAME_MAX] = '\0'; ++ wake_up_interruptible(&pWmtDev->cmd_wq); ++#endif ++ ++ pCmdSignal = &pWmtDev->cmdResp; ++ osal_signal_init(pCmdSignal); ++ pCmdSignal->timeoutValue = 2000; ++ osal_strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); ++ pWmtDev->cCmd[NAME_MAX] = '\0'; ++ ++ pCmdReq = &pWmtDev->cmdReq; ++ ++ osal_trigger_event(&pWmtDev->cmdReq); ++ WMT_DBG_FUNC("str(%s) request ok\n", pCmdStr); ++ ++/* waitRet = wait_for_completion_interruptible_timeout(&pWmtDev->cmd_comp, msecs_to_jiffies(2000)); */ ++ waitRet = osal_wait_for_signal_timeout(pCmdSignal); ++ WMT_LOUD_FUNC("wait signal iRet:%d\n", waitRet); ++ if (0 == waitRet) { ++ WMT_ERR_FUNC("wait signal timeout\n"); ++ return -2; ++ } ++ ++ WMT_DBG_FUNC("str(%s) result(%d)\n", pCmdStr, pWmtDev->cmdResult); ++ ++ return pWmtDev->cmdResult; ++} ++ ++INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ wmt_plat_pwr_ctrl(FUNC_RST); ++ return 0; ++} ++ ++INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ wmt_plat_pwr_ctrl(FUNC_STAT); ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet = 0; ++ /* un-register to STP-core for rx */ ++ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, NULL); /* mtk_wcn_stp_register_event_cb */ ++ if (iRet) { ++ WMT_WARN_FUNC("stp_reg cb unregister fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /*un-register rxcb to btif */ ++ iRet = mtk_wcn_stp_rxcb_register(NULL); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_unregister fail(%d)\n", iRet); ++ return -2; ++ } ++ ++ iRet = mtk_wcn_stp_close_btif(); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_close_btif fail(%d)\n", iRet); ++ return -3; ++ } ++ osal_clear_bit(WMT_STAT_STP_OPEN, &pDev->state); ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ ++ iRet = mtk_wcn_stp_open_btif(); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_open_btif fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /*register stp rx call back to btif */ ++ iRet = mtk_wcn_stp_rxcb_register((MTK_WCN_BTIF_RX_CB) mtk_wcn_stp_parser_data); ++ if (iRet) { ++ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_register fail(%d)\n", iRet); ++ return -2; ++ } ++ /* register to STP-core for rx */ ++ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, wmt_dev_rx_event_cb); ++ if (iRet) { ++ WMT_WARN_FUNC("stp_reg cb fail(%d)\n", iRet); ++ return -3; ++ } ++ ++ osal_set_bit(WMT_STAT_STP_OPEN, &pDev->state); ++ ++#if 0 ++ iRet = mtk_wcn_stp_lpbk_ctrl(1); ++#endif ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ INT32 iRet; ++ UINT8 cmdStr[NAME_MAX + 1] = { 0 }; ++ ++ osal_snprintf(cmdStr, NAME_MAX, "srh_patch"); ++ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); ++ if (iRet) { ++ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); ++ return -1; ++ } ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ pWmtCtrlData->au4CtrlData[0] = pDev->patchNum; ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ UINT32 downLoadSeq = 0; ++ P_WMT_PATCH_INFO pPatchinfo = NULL; ++ PUINT8 pNbuf = NULL; ++ PUINT8 pAbuf = NULL; ++ ++ downLoadSeq = pWmtCtrlData->au4CtrlData[0]; ++ WMT_DBG_FUNC("download seq is %d\n", downLoadSeq); ++ ++ pPatchinfo = pDev->pWmtPatchInfo + downLoadSeq - 1; ++ pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1]; ++ pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2]; ++ if (pPatchinfo) { ++ osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName)); ++ osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess)); ++ WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", pAbuf[0], pAbuf[1], pAbuf[2], pAbuf[3]); ++ } else { ++ WMT_ERR_FUNC("NULL patchinfo pointer\n"); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ ENUM_PALDO_TYPE ept = pWmtCtrlData->au4CtrlData[0]; ++ ENUM_PALDO_OP epo = pWmtCtrlData->au4CtrlData[1]; ++ ++ WMT_DBG_FUNC("ept(%d),epo(%d)\n", ept, epo); ++ iRet = wmt_plat_soc_paldo_ctrl(ept, epo); ++ if (iRet) { ++ if (PMIC_CHIPID_PALDO == ept) { ++ /* special handling for PMIC CHIPID */ ++ pWmtCtrlData->au4CtrlData[2] = iRet; ++ } else { ++ /* for other PA handling */ ++ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ ++ iRet = mtk_wcn_stp_wakeup_consys(); ++ if (iRet) ++ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value) ++{ ++ INT32 iRet = -1; ++ ++ switch (type) { ++ case WMT_STP_CONF_EN: ++ iRet = mtk_wcn_stp_enable(value); ++ break; ++ ++ case WMT_STP_CONF_RDY: ++ iRet = mtk_wcn_stp_ready(value); ++ break; ++ ++ case WMT_STP_CONF_MODE: ++ mtk_wcn_stp_set_mode(value); ++ iRet = 0; ++ break; ++ ++ default: ++ WMT_WARN_FUNC("invalid type(%d) value(%d)\n", type, value); ++ break; ++ } ++ return iRet; ++} ++ ++INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ UINT32 type; ++ UINT32 value; ++ ++ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_STP_ENABLE but invalid Handle of WmtStp\n"); ++ return -1; ++ } ++ ++ type = pWmtCtrlData->au4CtrlData[0]; ++ value = pWmtCtrlData->au4CtrlData[1]; ++ iRet = wmt_ctrl_stp_conf_ex(type, value); ++ ++ if (!iRet) { ++ if (WMT_STP_CONF_EN == type) { ++ if (value) { ++ osal_set_bit(WMT_STAT_STP_EN, &pDev->state); ++ WMT_DBG_FUNC("enable STP\n"); ++ } else { ++ osal_clear_bit(WMT_STAT_STP_EN, &pDev->state); ++ WMT_DBG_FUNC("disable STP\n"); ++ } ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 patchSeq = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (NULL != gDevWmt.pPatch) ++ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pPatch)); ++ ++ WMT_DBG_FUNC("AF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (patchSeq == gDevWmt.patchNum) { ++ WMT_DBG_FUNC("the %d patch has been download\n", patchSeq); ++ wmt_dev_patch_info_free(); ++ } ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ PUINT8 pBuf = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ ++ osal_memcpy(pBuf, gDevWmt.cPatchName, osal_sizeof(gDevWmt.cPatchName)); ++ return 0; ++} ++ ++INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); ++ if (NULL != gDevWmt.pNvram) ++ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pNvram)); ++ ++ WMT_DBG_FUNC("AF free patch, gDevWmt.pNvram(0x%08x)\n", gDevWmt.pNvram); ++ return 0; ++} ++ ++INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0x0; ++ PUINT8 pFileName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[1]; ++ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; ++ ++ osal_firmware *pNvram = NULL; ++ ++ if ((NULL == pFileName) || (NULL == pSize)) { ++ WMT_ERR_FUNC("parameter error, pFileName(0x%08x), pSize(0x%08x)\n", pFileName, pSize); ++ iRet = -1; ++ return iRet; ++ } ++ if (0 == wmt_dev_patch_get(pFileName, &pNvram, 0)) { ++ *ppBuf = (PUINT8) (pNvram)->data; ++ *pSize = (pNvram)->size; ++ gDevWmt.pNvram = pNvram; ++ return 0; ++ } ++ return -1; ++ ++} ++ ++INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT8 *pFullPatchName = NULL; ++ UINT8 *pDefPatchName = NULL; ++ PUINT8 *ppBuf = (PUINT8 *) pWmtCtrlData->au4CtrlData[2]; ++ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[3]; ++ ++ osal_firmware *pPatch = NULL; ++ ++ pFullPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[1]; ++ WMT_DBG_FUNC("BF get patch, pPatch(0x%08x)\n", pPatch); ++ if ((NULL != pFullPatchName) ++ && (0 == wmt_dev_patch_get(pFullPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { ++ /*get full name patch success */ ++ WMT_DBG_FUNC("get full patch name(%s) buf(0x%p) size(%d)\n", ++ pFullPatchName, (pPatch)->data, (pPatch)->size); ++ WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); ++ *ppBuf = (PUINT8) (pPatch)->data; ++ *pSize = (pPatch)->size; ++ gDevWmt.pPatch = pPatch; ++ return 0; ++ } ++ ++ pDefPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; ++ if ((NULL != pDefPatchName) ++ && (0 == wmt_dev_patch_get(pDefPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { ++ WMT_DBG_FUNC("get def patch name(%s) buf(0x%p) size(%d)\n", ++ pDefPatchName, (pPatch)->data, (pPatch)->size); ++ WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); ++ /*get full name patch success */ ++ *ppBuf = (PUINT8) (pPatch)->data; ++ *pSize = (pPatch)->size; ++ gDevWmt.pPatch = pPatch; ++ return 0; ++ } ++ return -1; ++ ++} ++ ++/*do not need contol uart because B/G/F send/receive data by BTIF*/ ++#if 0 ++INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ char cmdStr[NAME_MAX + 1] = { 0 }; ++ UINT32 u4Baudrate = pWmtCtrlData->au4CtrlData[0]; ++ UINT32 u4FlowCtrl = pWmtCtrlData->au4CtrlData[1]; ++ ++ WMT_DBG_FUNC("baud(%d), flowctrl(%d)\n", u4Baudrate, u4FlowCtrl); ++ ++ if (osal_test_bit(WMT_STAT_STP_OPEN, &gDevWmt.state)) { ++ osal_snprintf(cmdStr, NAME_MAX, "baud_%d_%d", u4Baudrate, u4FlowCtrl); ++ iRet = wmt_ctrl_ul_cmd(&gDevWmt, cmdStr); ++ if (iRet) { ++ WMT_WARN_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) fail(%d)\n", ++ u4Baudrate, pWmtCtrlData->au4CtrlData[1], iRet); ++ } else { ++ WMT_DBG_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) ok\n", u4Baudrate, u4FlowCtrl); ++ } ++ } else { ++ WMT_INFO_FUNC("CTRL_BAUDRATE but invalid Handle of WmtStp\n"); ++ } ++ return iRet; ++} ++#endif ++/*do not need control SDIO because wifi send/receive data by sdio*/ ++#if 0 ++INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = 0; ++ UINT32 statBit = WMT_STAT_SDIO1_ON; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ WMT_SDIO_SLOT_NUM sdioSlotNum = pWmtCtrlData->au4CtrlData[0]; ++ ENUM_FUNC_STATE funcState = pWmtCtrlData->au4CtrlData[1]; ++ ++ if ((WMT_SDIO_SLOT_INVALID == sdioSlotNum) ++ || (WMT_SDIO_SLOT_MAX <= sdioSlotNum)) { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT(%d) but invalid slot num\n", sdioSlotNum); ++ return -1; ++ } ++ ++ WMT_DBG_FUNC("WMT_CTRL_SDIO_HW (0x%x, %d)\n", sdioSlotNum, funcState); ++ ++ if (WMT_SDIO_SLOT_SDIO2 == sdioSlotNum) ++ statBit = WMT_STAT_SDIO2_ON; ++ ++ if (funcState) { ++ if (osal_test_and_set_bit(statBit, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already ON\n", sdioSlotNum); ++ /* still return 0 */ ++ iRet = 0; ++ } else { ++ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_ON); ++ } ++ } else { ++ if (osal_test_and_clear_bit(statBit, &pDev->state)) { ++ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_OFF); ++ } else { ++ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already OFF\n", sdioSlotNum); ++ /* still return 0 */ ++ iRet = 0; ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ UINT32 statBit = WMT_STAT_SDIO_WIFI_ON; ++ INT32 retry = 10; ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ WMT_SDIO_FUNC_TYPE sdioFuncType = pWmtCtrlData->au4CtrlData[0]; ++ UINT32 u4On = pWmtCtrlData->au4CtrlData[1]; ++ ++ if (WMT_SDIO_FUNC_MAX <= sdioFuncType) { ++ WMT_ERR_FUNC("CTRL_SDIO_FUNC, invalid func type (%d)\n", sdioFuncType); ++ return -1; ++ } ++ ++ if (WMT_SDIO_FUNC_STP == sdioFuncType) ++ statBit = WMT_STAT_SDIO_STP_ON; ++ ++ if (u4On) { ++ if (osal_test_bit(statBit, &pDev->state)) { ++ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already ON\n", sdioFuncType); ++ iRet = 0; ++ } else { ++ while (retry-- > 0 && iRet != 0) { ++ if (iRet) { ++ /* sleep 150ms before sdio slot ON ready */ ++ osal_sleep_ms(150); ++ } ++ iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_TRUE); ++ if (HIF_SDIO_ERR_NOT_PROBED == iRet) { ++ /* not probed case, retry */ ++ continue; ++ } else if (HIF_SDIO_ERR_CLT_NOT_REG == iRet) { ++ /* For WiFi, client not reg yet, no need to retry, ++ *WiFi function can work any time when wlan.ko ++ *is insert into system ++ */ ++ iRet = 0; ++ } else { ++ /* other fail cases, stop */ ++ break; ++ } ++ } ++ if (!retry || iRet) { ++ WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, TRUE) fail(%d) retry(%d)\n", ++ sdioFuncType, iRet, retry); ++ } else { ++ osal_set_bit(statBit, &pDev->state); ++ } ++ } ++ } else { ++ if (osal_test_bit(statBit, &pDev->state)) { ++ iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_FALSE); ++ if (iRet) ++ WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, FALSE) fail(%d)\n", sdioFuncType, iRet); ++ /*any way, set to OFF state */ ++ osal_clear_bit(statBit, &pDev->state); ++ } else { ++ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already OFF\n", sdioFuncType); ++ iRet = 0; ++ } ++ } ++ ++ return iRet; ++} ++#endif ++ ++ ++INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ /* input sanity check is done in wmt_ctrl() */ ++ pDev->chip_id = (pWmtCtrlData->au4CtrlData[0] & 0xFFFF0000) >> 16; ++ pDev->hw_ver = pWmtCtrlData->au4CtrlData[0] & 0x0000FFFF; ++ pDev->fw_ver = pWmtCtrlData->au4CtrlData[1] & 0x0000FFFF; ++ ++ /* TODO: [FixMe][GeorgeKuo] remove translated ENUM_WMTHWVER_TYPE_T in the future!!! */ ++ /* Only use hw_ver read from hw. */ ++ pDev->eWmtHwVer = (ENUM_WMTHWVER_TYPE_T) (pWmtCtrlData->au4CtrlData[1] & 0xFFFF0000) >> 16; ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT8 *pRomVer = NULL; ++ P_WMT_PATCH pPatch = NULL; ++ UINT32 chipID = 0; ++ ++ chipID = pWmtCtrlData->au4CtrlData[0]; ++ pRomVer = (PUINT8) (pWmtCtrlData->au4CtrlData[1]); ++ pPatch = (P_WMT_PATCH) (pWmtCtrlData->au4CtrlData[2]); ++ if (!pRomVer) { ++ WMT_ERR_FUNC("pRomVer null pointer\n"); ++ return -1; ++ } ++ if (!pPatch) { ++ WMT_ERR_FUNC("pPatch null pointer\n"); ++ return -2; ++ } ++ WMT_DBG_FUNC("chipid(0x%x),rom(%s),patch date(%s),patch plat(%s)\n", chipID, pRomVer, pPatch->ucDateTime, ++ pPatch->ucPLat); ++ return stp_dbg_set_version_info(chipID, pRomVer, &(pPatch->ucDateTime[0]), &(pPatch->ucPLat[0])); ++} ++ ++static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ UINT32 cmd = pWmtCtrlData->au4CtrlData[0]; ++ ++ WMT_INFO_FUNC("wmt-ctrl:send native cmd(%d)\n", cmd); ++ wmt_dev_send_cmd_to_daemon(cmd); ++ ++ return 0; ++} ++ ++static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 iRet = -1; ++ ++ ENUM_WMTDRV_TYPE_T drv_type; ++ UINT32 reason = 0; ++ ++ drv_type = pWmtCtrlData->au4CtrlData[0]; ++ reason = pWmtCtrlData->au4CtrlData[1]; ++ WMT_WARN_FUNC("wmt-ctrl:drv_type(%d),reason(%d)\n", drv_type, reason); ++ ++ if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); ++ wmt_lib_set_host_assert_info(drv_type, reason, 1); ++ ++ iRet = mtk_wcn_stp_wmt_evt_err_trg_assert(); ++ if (iRet) ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++ } else { ++ /* maybe assert triggered by stp noack*/ ++ WMT_INFO_FUNC("do trigger assert & chip reset in stp noack\n"); ++ } ++ return 0; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 antsel_index = wmt_plat_get_tdm_antsel_index(); ++ ++ if (0 <= antsel_index) ++ pWmtCtrlData->au4CtrlData[0] = antsel_index; ++ else ++ pWmtCtrlData->au4CtrlData[0] = 0xff; ++ ++ WMT_INFO_FUNC("get tdm req antsel index is %d\n", antsel_index); ++ ++ return 0; ++} ++#endif ++ ++static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ INT32 ret = -1; ++ UINT32 evt_idx = (UINT32) pWmtCtrlData->au4CtrlData[0]; ++ UINT8 *p_buf = NULL; ++ ++ static UINT8 sleep_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; ++ static UINT8 wakeup_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++ static UINT8 hostawake_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; ++ static UINT8 *evt_array[] = { sleep_evt, wakeup_evt, hostawake_evt }; ++ ++ p_buf = evt_array[evt_idx - 1]; ++ ++ WMT_INFO_FUNC("evt index:%d,p_buf:%p\n", evt_idx, p_buf); ++ ++ ret = mtk_wcn_consys_stp_btif_parser_wmt_evt(p_buf, 6); ++ if (ret == 1) { ++ WMT_INFO_FUNC("parser wmt evt from BTIF buf is OK\n"); ++ return 0; ++ } ++ WMT_ERR_FUNC("parser wmt evt from BTIF buf fail(%d)\n", ret); ++ return -1; ++} ++ ++static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData) ++{ ++ INT32 iret; ++ ++ WMT_INFO_FUNC("ctrl GPS_SYNC(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); ++ iret = wmt_plat_gpio_ctrl(PIN_GPS_SYNC, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); ++ ++ if (iret) { ++ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", ++ (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX, iret); ++ } ++ ++ return 0; ++} ++ ++static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData) ++{ ++ INT32 iret; ++ ++ WMT_INFO_FUNC("ctrl GPS_LNA(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); ++ iret = wmt_plat_gpio_ctrl(PIN_GPS_LNA, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); ++ ++ if (iret) { ++ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", ++ (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H, iret); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ return 0; ++} ++ ++INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ P_DEV_WMT pDev = &gDevWmt; /* single instance */ ++ ++ pWmtCtrlData->au4CtrlData[0] = (SIZE_T) &pDev->rWmtGenConf; ++ ++ return 0; ++} ++ ++INT32 wmt_ctrl_others(P_WMT_CTRL_DATA pWmtCtrlData) ++{ ++ WMT_ERR_FUNC("wmt_ctrl_others, invalid CTRL ID (%d)\n", pWmtCtrlData->ctrlId); ++ return -1; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c +new file mode 100644 +index 000000000000..d42d572c9292 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c +@@ -0,0 +1,713 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-FUNC]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_func.h" ++#include "wmt_lib.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_BT_SUPPORT ++ ++static INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_bt_ops = { ++ /* BT subsystem function on/off */ ++ .func_on = wmt_func_bt_on, ++ .func_off = wmt_func_bt_off ++}; ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ ++static INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_fm_ops = { ++ /* FM subsystem function on/off */ ++ .func_on = wmt_func_fm_on, ++ .func_off = wmt_func_fm_off ++}; ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ ++static INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_gps_ops = { ++ /* GPS subsystem function on/off */ ++ .func_on = wmt_func_gps_on, ++ .func_off = wmt_func_gps_off ++}; ++ ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++static INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++static INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); ++ ++WMT_FUNC_OPS wmt_func_wifi_ops = { ++ /* Wi-Fi subsystem function on/off */ ++ .func_on = wmt_func_wifi_on, ++ .func_off = wmt_func_wifi_off ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_FUNC_GPS_SUPPORT ++CMB_PIN_CTRL_REG eediPinOhRegs[] = { ++ { ++ /* pull down ctrl register */ ++ .regAddr = 0x80050020, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ }, ++ { ++ /* pull up ctrl register */ ++ .regAddr = 0x80050000, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020, ++ }, ++ { ++ /* iomode ctrl register */ ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 0, ++ .regMask = 0x00000007, ++ }, ++ { ++ /* output high/low ctrl register */ ++ .regAddr = 0x80050040, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG eediPinOlRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = 0x1 << 5, ++ .regMask = 0x00000020UL, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 0, ++ .regMask = 0x00000007, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = ~(0x1 << 5), ++ .regMask = 0x00000020, ++ } ++}; ++ ++CMB_PIN_CTRL_REG eedoPinOhRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080UL, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080UL, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 12, ++ .regMask = 0x00007000UL, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080, ++ } ++}; ++ ++CMB_PIN_CTRL_REG eedoPinOlRegs[] = { ++ { ++ .regAddr = 0x80050020, ++ .regValue = 0x1 << 7, ++ .regMask = 0x00000080, ++ }, ++ { ++ .regAddr = 0x80050000, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080, ++ }, ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x1 << 12, ++ .regMask = 0x00007000, ++ }, ++ { ++ .regAddr = 0x80050040, ++ .regValue = ~(0x1 << 7), ++ .regMask = 0x00000080, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG gsyncPinOnRegs[] = { ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x3 << 20, ++ .regMask = 0x7 << 20, ++ } ++ ++}; ++ ++CMB_PIN_CTRL_REG gsyncPinOffRegs[] = { ++ { ++ .regAddr = 0x80050110, ++ .regValue = 0x0 << 20, ++ .regMask = 0x7 << 20, ++ } ++}; ++ ++/* templete usage for GPIO control */ ++CMB_PIN_CTRL gCmbPinCtrl[3] = { ++ { ++ .pinId = CMB_PIN_EEDI_ID, ++ .regNum = 4, ++ .pFuncOnArray = eediPinOhRegs, ++ .pFuncOffArray = eediPinOlRegs, ++ }, ++ { ++ .pinId = CMB_PIN_EEDO_ID, ++ .regNum = 4, ++ .pFuncOnArray = eedoPinOhRegs, ++ .pFuncOffArray = eedoPinOlRegs, ++ }, ++ { ++ .pinId = CMB_PIN_GSYNC_ID, ++ .regNum = 1, ++ .pFuncOnArray = gsyncPinOnRegs, ++ .pFuncOffArray = gsyncPinOffRegs, ++ } ++}; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_FUNC_BT_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_bt_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*only need to send turn BT subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_bt_ctrl(FUNC_ON); */ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); ++ return -1; ++ } ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_on) failed(%d)\n", iRet); ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ /*do coredump when bt on fail */ ++ wmt_core_set_coredump_state(DRV_STS_FUNC_ON); ++ ctrlPa1 = WMTDRV_TYPE_BT; ++ ctrlPa2 = 32; ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); ++ return -2; ++ } ++ osal_set_bit(WMT_BT_ON, &gBtWifiGpsState); ++ if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ return 0; ++} ++ ++INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_bt_ctrl(FUNC_OFF); */ ++ INT32 iRet1 = -1; ++ INT32 iRet2 = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ iRet1 = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE); ++ if (iRet1) ++ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_off) failed(%d)\n", iRet1); ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet2 = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ if (iRet2) ++ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl(bt_off) failed(%d)\n", iRet2); ++ ++ if (iRet1 + iRet2) { ++ /*do coredump when bt off fail */ ++ wmt_core_set_coredump_state(DRV_STS_FUNC_ON); ++ ctrlPa1 = WMTDRV_TYPE_BT; ++ ctrlPa2 = 32; ++ wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); ++ return -1; ++ } ++ ++ osal_clear_bit(WMT_BT_ON, &gBtWifiGpsState); ++ if ((!osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stopping send de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ return 0; ++} ++ ++#endif ++ ++#if CFG_FUNC_GPS_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_gps_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*send turn GPS subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_GPS, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_gps_pre_ctrl(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf, ENUM_FUNC_STATE funcStatus) ++{ ++ UINT32 i = 0; ++ INT32 iRet = 0; ++ UINT32 regAddr = 0; ++ UINT32 regValue = 0; ++ UINT32 regMask = 0; ++ UINT32 regNum = 0; ++ P_CMB_PIN_CTRL_REG pReg; ++ P_CMB_PIN_CTRL pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; ++ WMT_CTRL_DATA ctrlData; ++ WMT_IC_PIN_ID wmtIcPinId = WMT_IC_PIN_MAX; ++ /* sanity check */ ++ if (FUNC_ON != funcStatus && FUNC_OFF != funcStatus) { ++ WMT_ERR_FUNC("invalid funcStatus(%d)\n", funcStatus); ++ return -1; ++ } ++ /* turn on GPS sync function on both side */ ++ ctrlData.ctrlId = WMT_CTRL_GPS_SYNC_SET; ++ ctrlData.au4CtrlData[0] = (FUNC_ON == funcStatus) ? 1 : 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /*we suppose this would never print */ ++ WMT_ERR_FUNC("ctrl GPS_SYNC_SET(%d) fail, ret(%d)\n", funcStatus, iRet); ++ /* TODO:[FixMe][George] error handling? */ ++ return -2; ++ } ++ WMT_INFO_FUNC("ctrl GPS_SYNC_SET(%d) ok\n", funcStatus); ++ ++ ++ if ((NULL == pOps->ic_pin_ctrl) || ++ (0 > pOps->ic_pin_ctrl( ++ WMT_IC_PIN_GSYNC, ++ FUNC_ON == funcStatus ? WMT_IC_PIN_MUX : WMT_IC_PIN_GPIO, ++ 1))) { /*WMT_IC_PIN_GSYNC */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; ++ regNum = pCmbPinCtrl->regNum; ++ for (i = 0; i < regNum; i++) { ++ if (FUNC_ON == funcStatus) ++ pReg = &pCmbPinCtrl->pFuncOnArray[i]; ++ else ++ pReg = &pCmbPinCtrl->pFuncOffArray[i]; ++ ++ regAddr = pReg->regAddr; ++ regValue = pReg->regValue; ++ regMask = pReg->regMask; ++ ++ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); ++ if (iRet) { ++ WMT_ERR_FUNC("set reg for GPS_SYNC function fail(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -2; ++ } ++ ++ } ++ } else { ++ WMT_INFO_FUNC("set reg for GPS_SYNC function okay by chip ic_pin_ctrl\n"); ++ } ++ WMT_INFO_FUNC("ctrl combo chip gps sync function succeed\n"); ++ /* turn on GPS lna ctrl function */ ++ if (NULL != pConf) { ++ if (0 == pConf->wmt_gps_lna_enable) { ++ ++ WMT_INFO_FUNC("host pin used for gps lna\n"); ++ /* host LNA ctrl pin needed */ ++ ctrlData.ctrlId = WMT_CTRL_GPS_LNA_SET; ++ ctrlData.au4CtrlData[0] = FUNC_ON == funcStatus ? 1 : 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ /*we suppose this would never print */ ++ WMT_ERR_FUNC("ctrl host GPS_LNA output high fail, ret(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -3; ++ } ++ WMT_INFO_FUNC("ctrl host gps lna function succeed\n"); ++ } else { ++ WMT_INFO_FUNC("combo chip pin(%s) used for gps lna\n", ++ 0 == pConf->wmt_gps_lna_pin ? "EEDI" : "EEDO"); ++ wmtIcPinId = 0 == pConf->wmt_gps_lna_pin ? WMT_IC_PIN_EEDI : WMT_IC_PIN_EEDO; ++ if ((NULL == pOps->ic_pin_ctrl) || ++ (0 > pOps->ic_pin_ctrl( ++ wmtIcPinId, ++ FUNC_ON == funcStatus ? WMT_IC_PIN_GPIO_HIGH : WMT_IC_PIN_GPIO_LOW, ++ 1))) { /*WMT_IC_PIN_GSYNC */ ++ if (0 == pConf->wmt_gps_lna_pin) { ++ /* EEDI needed */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDI_ID]; ++ } else if (1 == pConf->wmt_gps_lna_pin) { ++ /* EEDO needed */ ++ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDO_ID]; ++ } ++ regNum = pCmbPinCtrl->regNum; ++ for (i = 0; i < regNum; i++) { ++ if (FUNC_ON == funcStatus) ++ pReg = &pCmbPinCtrl->pFuncOnArray[i]; ++ else ++ pReg = &pCmbPinCtrl->pFuncOffArray[i]; ++ regAddr = pReg->regAddr; ++ regValue = pReg->regValue; ++ regMask = pReg->regMask; ++ ++ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); ++ if (iRet) { ++ WMT_ERR_FUNC("set reg for GPS_LNA function fail(%d)\n", iRet); ++ /* TODO:[FixMe][Chaozhong] error handling? */ ++ return -3; ++ } ++ } ++ WMT_INFO_FUNC("ctrl combo chip gps lna succeed\n"); ++ } else { ++ WMT_INFO_FUNC("set reg for GPS_LNA function okay by chip ic_pin_ctrl\n"); ++ } ++ } ++ } ++ return 0; ++ ++} ++ ++INT32 wmt_func_gps_pre_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_ON); ++} ++ ++INT32 wmt_func_gps_pre_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ ++ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_OFF); ++} ++ ++INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ ++ if (!osal_test_bit(WMT_FM_ON, &gGpsFmState)) { ++ ctrlPa1 = GPS_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_INFO_FUNC("LDO VCN28 has been turn on by FM\n"); ++ } ++ } ++ ++ iRet = wmt_func_gps_pre_on(pOps, pConf); ++ if (0 == iRet) { ++ iRet = wmt_func_gps_ctrl(FUNC_ON); ++ if (!iRet) { ++ osal_set_bit(WMT_GPS_ON, &gBtWifiGpsState); ++ if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) ++ || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) /* use SOC external LNA */ ++ osal_set_bit(WMT_GPS_ON, &gGpsFmState); ++ } ++ } ++ return iRet; ++} ++ ++INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ iRet = wmt_func_gps_pre_off(pOps, pConf); ++ if (0 == iRet) { ++ iRet = wmt_func_gps_ctrl(FUNC_OFF); ++ if (!iRet) { ++ osal_clear_bit(WMT_GPS_ON, &gBtWifiGpsState); ++ if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) ++ || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stop sending de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ } ++ ++ if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ ++ if (osal_test_bit(WMT_FM_ON, &gGpsFmState)) ++ WMT_INFO_FUNC("FM is still on, do not turn off LDO VCN28\n"); ++ else { ++ ctrlPa1 = GPS_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ osal_clear_bit(WMT_GPS_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++ ++} ++#endif ++ ++#if CFG_FUNC_FM_SUPPORT ++ ++INT32 _osal_inline_ wmt_func_fm_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ /*only need to send turn FM subsystem wmt command */ ++ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++} ++ ++INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_fm_ctrl(FUNC_ON); */ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ INT32 iRet = -1; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ if (co_clock_type) { ++ if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { ++ ctrlPa1 = FM_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_INFO_FUNC("LDO VCN28 has been turn on by GPS\n"); ++ } ++ } ++ ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE); ++ if (!iRet) { ++ if (co_clock_type) ++ osal_set_bit(WMT_FM_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++} ++ ++INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ /* return wmt_func_fm_ctrl(FUNC_OFF); */ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ INT32 iRet = -1; ++ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); ++ ++ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE); ++ ++ if (co_clock_type) { ++ if (osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { ++ WMT_INFO_FUNC("GPS is still on, do not turn off LDO VCN28\n"); ++ } else { ++ ctrlPa1 = FM_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ ++ osal_clear_bit(WMT_FM_ON, &gGpsFmState); ++ } ++ ++ return iRet; ++} ++ ++#endif ++ ++#if CFG_FUNC_WIFI_SUPPORT ++ ++/*in soc, wmt turn on wifi directly, no not need operate SDIO*/ ++#if 0 ++INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState) ++{ ++ INT32 iRet = 0; ++ unsigned long ctrlPa1 = WMT_SDIO_FUNC_WIFI; ++ unsigned long ctrlPa2 = (FUNC_ON == funcState) ? 1 : 0; /* turn on Wi-Fi driver */ ++ ++ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: turn on WIFI function fail (%d)", iRet); ++ return -1; ++ } ++ return 0; ++} ++#endif ++ ++INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ int iRet = 0; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ if (NULL != mtk_wcn_wlan_probe) { ++ ++ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan probe\n"); ++ iRet = (*mtk_wcn_wlan_probe) (); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan probe fail(%d)\n", iRet); ++ iRet = -1; ++ } else { ++ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan probe ok\n"); ++ } ++ } else { ++ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_probe\n"); ++ gWifiProbed = 1; ++ iRet = -2; ++ } ++ ++ if (!iRet) { ++ osal_set_bit(WMT_WIFI_ON, &gBtWifiGpsState); ++ if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { ++ /* send msg to GPS native for sending de-sense CMD */ ++ ctrlPa1 = 1; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ return iRet; ++#if 0 ++ return wmt_func_wifi_ctrl(FUNC_ON); ++#endif ++} ++ ++INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) ++{ ++ int iRet = 0; ++ ++ unsigned long ctrlPa1 = 0; ++ unsigned long ctrlPa2 = 0; ++ ++ if (NULL != mtk_wcn_wlan_remove) { ++ ++ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan remove\n"); ++ iRet = (*mtk_wcn_wlan_remove) (); ++ if (iRet) { ++ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan remove fail(%d)\n", iRet); ++ iRet = -1; ++ } else { ++ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan remove ok\n"); ++ } ++ } else { ++ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_remove\n"); ++ iRet = -2; ++ } ++ ++ if (!iRet) { ++ osal_clear_bit(WMT_WIFI_ON, &gBtWifiGpsState); ++ if ((!osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { ++ /* send msg to GPS native for stopping send de-sense CMD */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); ++ } ++ } ++ return iRet; ++#if 0 ++ return wmt_func_wifi_ctrl(FUNC_OFF); ++#endif ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c +new file mode 100644 +index 000000000000..c07052bce8e6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c +@@ -0,0 +1,2452 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-IC]" ++#define CFG_IC_SOC 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "wmt_ic.h" ++#include "wmt_core.h" ++#include "wmt_lib.h" ++#include "stp_core.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define DEFAULT_PATCH_FRAG_SIZE (1000) ++#define WMT_PATCH_FRAG_1ST (0x1) ++#define WMT_PATCH_FRAG_MID (0x2) ++#define WMT_PATCH_FRAG_LAST (0x3) ++ ++#define CFG_CHECK_WMT_RESULT (1) ++/* BT Port 2 Feature. this command does not need ++ * after coex command is downconfirmed by LC, ++ */ ++#define CFG_WMT_BT_PORT2 (0) ++ ++#define CFG_SET_OPT_REG (0) ++#define CFG_WMT_I2S_DBGUART_SUPPORT (0) ++#define CFG_SET_OPT_REG_SWLA (0) ++#define CFG_SET_OPT_REG_MCUCLK (0) ++#define CFG_SET_OPT_REG_MCUIRQ (0) ++ ++#define CFG_SUBSYS_COEX_NEED 0 ++ ++#define CFG_WMT_COREDUMP_ENABLE 0 ++ ++#define CFG_WMT_MULTI_PATCH (1) ++ ++#define CFG_WMT_CRYSTAL_TIMING_SET (0) ++ ++#define CFG_WMT_SDIO_DRIVING_SET (0) ++ ++#define CFG_WMT_UART_HIF_USE (0) ++ ++#define CFG_WMT_WIFI_5G_SUPPORT (1) ++ ++#define CFG_WMT_PATCH_DL_OPTM (1) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define CFG_WMT_FILTER_MODE_SETTING (1) ++#else ++#define CFG_WMT_FILTER_MODE_SETTING (0) ++#endif ++#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT (0) ++ ++#define CFG_WMT_POWER_ON_DLM (1) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static UINT8 gFullPatchName[NAME_MAX + 1]; ++static const WMT_IC_INFO_S *gp_soc_info; ++static WMT_PATCH gp_soc_patch_info; ++static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; ++#if 0 ++static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; ++ ++static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; ++static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; ++#endif ++ ++#if CFG_WMT_UART_HIF_USE ++static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; ++static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; ++static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; ++static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; ++static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; ++static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; ++static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; ++#endif ++static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_QUERY_STP_EVT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; ++static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; ++static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; ++static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; ++ ++#if CFG_WMT_BT_PORT2 ++static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; ++static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++#endif ++ ++/*soc patial patch address cmd & evt need firmware owner provide*/ ++#if CFG_WMT_MULTI_PATCH ++static UINT8 WMT_PATCH_ADDRESS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x3c, 0x02, 0x09, 0x02, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0xc4, 0x04, 0x09, 0x02, ++ 0x00, 0x3f, 0x00, 0x01, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++#endif ++ ++/*coex cmd/evt++*/ ++static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; ++static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++#if CFG_SUBSYS_COEX_NEED ++static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, ++ 0x00, 0x02, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA ++}; ++static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, ++ 0x00, 0x03, ++ 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA ++}; ++static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, ++ 0x00, 0x04, ++ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE ++}; ++static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, ++ 0x00, 0x05, ++ 0xAA, 0xAA, 0xAA, 0xAA, ++ 0xBB, 0xBB, 0xBB, 0xBB ++}; ++static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++#endif ++ ++/*coex cmd/evt--*/ ++static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; ++static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; ++static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; ++static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; ++ ++#if 0 ++static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; ++static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; ++#endif ++ ++#if 0 ++/* to enable dump feature */ ++static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 }; ++static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get system stack dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get task and system stack dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++/* to get bt related memory dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A }; ++static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++#endif ++/* to get full dump when f/w assert */ ++static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; ++static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_CORE_START_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x1, 0x00, 0x01 }; ++static UINT8 WMT_CORE_START_RF_CALIBRATION_EVT[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x01 }; ++ ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */ ++ , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */ ++ , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */ ++ , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */ ++ , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */ ++ , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */ ++ , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */ ++}; ++ ++static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++#endif ++ ++#if !(CFG_IC_SOC) /* For MT6628 no need to set ALLEINT registers, done in f/w */ ++/* enable all interrupt */ ++static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ ++ , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ ++ , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ ++}; ++ ++static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++ ++#endif ++ ++#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ ++static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ ++ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ ++ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ ++ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ ++ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ ++ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ ++}; ++ ++static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++}; ++#endif ++ ++#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ ++static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ ++ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ ++ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ ++ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ ++ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ ++ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ ++ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ ++}; ++ ++static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++}; ++#endif ++ ++#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ ++static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ ++ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ ++ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ ++ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ ++ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ ++ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ ++}; ++ ++static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x02 /*2 registers */ ++}; ++#endif ++ ++#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ ++#if 1 /* Ray */ ++static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 4 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ ++ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ ++ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ ++ /* cirq_int_n */ ++ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ ++ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ ++ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ ++ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ ++ /* 1. ARM irq_b, monitor flag 0 */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ ++ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ ++ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ ++}; ++ ++static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x04 /* 5 registers */ ++}; ++#elif 0 /* KC */ ++static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x05 /* 5 registers */ ++ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ ++ , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ ++ , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ ++ /* 1. ARM irq_b, monitor flag 0 */ ++ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ ++ , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ ++ , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ ++ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ ++ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ ++ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ ++ /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ ++ , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ ++ , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ ++ , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ ++ , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ ++ , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ ++ , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ ++}; ++ ++static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /* S: 0 */ ++ , 0x00 /* type: reg */ ++ , 0x00 /* rev */ ++ , 0x05 /* 5 registers */ ++}; ++#endif ++#endif ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; ++static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; ++ ++static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; ++static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; ++#endif ++ ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++static UINT8 WMT_GET_EFUSE_VCN33_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x04, 0x00 }; ++static UINT8 WMT_GET_EFUSE_VCN33_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x04, 0x00 }; ++#endif ++ ++/* set sdio driving */ ++#if CFG_WMT_SDIO_DRIVING_SET ++static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ ++ , 0x01 /* op: w */ ++ , 0x01 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ ++ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ ++ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ ++}; ++ ++static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ ++ , 0x00 /*S: 0 */ ++ , 0x00 /*type: reg */ ++ , 0x00 /*rev */ ++ , 0x01 /*1 registers */ ++}; ++#endif ++ ++#if CFG_WMT_WIFI_5G_SUPPORT ++static UINT8 WMT_GET_SOC_ADIE_CHIPID_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; ++static UINT8 WMT_GET_SOC_ADIE_CHIPID_EVT[] = { ++ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static UINT8 WMT_GET_SOC_6625_L_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x20, 0x01 }; ++static UINT8 WMT_GET_SOC_6625_L_EVT[] = { ++ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x20, ++ 0x01, 0x00, 0x00, 0x00, 0x00 ++}; ++#endif ++ ++#if CFG_WMT_PATCH_DL_OPTM ++static UINT8 WMT_SET_MCU_CLK_EN_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x34, 0x03, 0x00, 0x80, ++ 0x00, 0x00, 0x01, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_EN_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_138_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, ++ 0x59, 0x4d, 0x84, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_138_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_26_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, ++ 0x00, 0x4d, 0x84, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_26_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++static UINT8 WMT_SET_MCU_CLK_DIS_CMD[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x34, 0x03, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff ++}; ++static UINT8 WMT_SET_MCU_CLK_DIS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++ ++/*only for 6797,enable high clock frequency*/ ++/*CLK EN*/ ++static UINT8 WMT_SET_MCU_CLK_EN_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x10, ++ 0x00, 0x00, 0x00, 0x10 ++}; ++/*RATIO SET*/ ++static UINT8 WMT_SET_MCU_RATIO_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, ++ 0xc0, 0x00, 0x00, 0x00 ++}; ++/*DIV SET*/ ++static UINT8 WMT_SET_MCU_DIV_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x18, 0x11, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00, ++ 0x3f, 0x00, 0x00, 0x00 ++}; ++/*HCLK SET*/ ++static UINT8 WMT_SET_MCU_HCLK_SET_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x11, 0x02, 0x81, 0x04, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x00 ++}; ++ ++/*Change clock to 26MHz*/ ++/*HCLK DIS*/ ++static UINT8 WMT_SET_MCU_HCLK_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x00, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x00 ++}; ++/*RATIO DIS*/ ++static UINT8 WMT_SET_MCU_RATIO_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x0c, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, ++ 0xc0, 0x00, 0x00, 0x00 ++}; ++/*CLK DIS*/ ++static UINT8 WMT_SET_MCU_CLK_DIS_6797[] = { ++ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, ++ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10 ++}; ++ ++static UINT8 WMT_SET_MCU_CLK_EVT_6797[] = { ++ 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 ++}; ++ ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = {0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00}; ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, ++ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x00, 0x0a, 0x0c, 0x0e, ++ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xd4, ++ 0x09, 0xe3, 0x09, 0x5a, 0x0a, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x60, 0x09, 0xd3, 0x09, 0xe2, ++ 0x09, 0x59, 0x0a, 0x8B, 0x0a}; ++static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; ++static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; ++ ++#if 0 ++static UINT8 WMT_COEX_SPLIT_FILTER_CMD_TEST[] = { ++ 0x01, 0x10, 0x19, 0x00, 0x0F, 0x00, 0x00, 0x00, ++ 0x00, 0x6c, 0x09, 0x8a, 0x09, 0x8a, 0x09, 0x9e, ++ 0x09, 0x01, 0x07, 0x07, 0x0b, 0x07, 0x07, 0x00, ++ 0x32, 0x27, 0x4e, 0x27, 0x32 ++}; ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x07, 0x07, 0x07, 0x54, 0x54, 0x00, 0x00, ++ 0x00, 0x50, 0x50, 0x50, 0x54, 0x54, 0x39, 0x39, ++ 0x39, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, ++ 0x09, 0xf6, 0x09, 0x0f, 0xaf, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, ++ 0x09, 0x0d, 0x0a, 0x27, 0x0a ++}; ++static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; ++static UINT8 WMT_COEX_EXT_COMPONENT_CMD_TEST[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x7f, 0x03 }; ++#endif ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_0[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x63, 0x3c, 0x3c, 0x3c, ++ 0x3c, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, ++ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, ++ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, ++ 0x09, 0xf6, 0x09, 0x0f, 0x0a, 0x14, 0x09, 0x2d, ++ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, ++ 0x09, 0x0d, 0x0a, 0x27, 0x0a ++}; ++static UINT8 WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x14, 0x00 }; ++static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; ++static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; ++ ++static UINT8 WMT_COEX_FILTER_SPEC_CMD_6752[] = { ++ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, ++ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, ++ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, ++ 0x01, 0x0E, 0x0E, 0x0E, 0x00, 0x0A, 0x0C, 0x0E, ++ 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00 ++}; ++ ++static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752[] = { ++ 0x01, 0x10, 0x21, 0x00, 0x12, 0xFC, 0x08, 0x15, ++ 0x09, 0x2E, 0x09, 0x47, 0x09, 0xC4, 0x09, 0xD4, ++ 0x09, 0xE3, 0x09, 0x5A, 0x0A, 0x14, 0x09, 0x2D, ++ 0x09, 0x46, 0x09, 0x60, 0x09, 0xD3, 0x09, 0xE2, ++ 0x09, 0x59, 0x0A, 0x8B, 0x0A ++}; ++#endif ++ ++#if CFG_WMT_POWER_ON_DLM ++static UINT8 WMT_POWER_CTRL_DLM_CMD1[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x0f, 0x00, 0x00 ++}; ++ ++static UINT8 WMT_POWER_CTRL_DLM_CMD2[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0x00, 0x00, 0x00 ++}; ++ ++static UINT8 WMT_POWER_CTRL_DLM_CMD3[] = { ++ 0x01, 0x08, 0x10, 0x00, ++ 0x01, 0x01, 0x00, 0x01, ++ 0x60, 0x00, 0x10, 0x80, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0x00 ++}; ++static UINT8 WMT_POWER_CTRL_DLM_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; ++#endif ++ ++#if (!CFG_IC_SOC) ++ ++/* stp sdio init scripts */ ++static struct init_script init_table_1_1[] = { ++ /* table_1_1 is only applied to common SDIO interface */ ++ INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), ++ /* applied to MT6628 ? */ ++ INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), ++}; ++ ++#endif ++ ++static struct init_script init_table_1_2[] = { ++ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), ++}; ++ ++#if CFG_WMT_UART_HIF_USE ++static struct init_script init_table_2[] = { ++ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), ++}; ++#endif ++ ++static struct init_script init_table_3[] = { ++ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), ++#if CFG_WMT_BT_PORT2 ++ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), ++#endif ++}; ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static struct init_script set_crystal_timing_script[] = { ++ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, "set crystal trim value"), ++}; ++ ++static struct init_script get_crystal_timing_script[] = { ++ INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, "get crystal trim value"), ++}; ++#endif ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++static struct init_script get_efuse_vcn33_script[] = { ++ INIT_CMD(WMT_GET_EFUSE_VCN33_CMD, WMT_GET_EFUSE_VCN33_EVT, "get efuse vcn33 value"), ++}; ++#endif ++ ++static struct init_script init_table_4[] = { ++ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), ++}; ++ ++static struct init_script init_table_5[] = { ++ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT, "query stp"), ++}; ++ ++static struct init_script init_table_5_1[] = { ++ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), ++}; ++ ++static struct init_script init_table_6[] = { ++ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), ++}; ++ ++static struct init_script calibration_table[] = { ++ INIT_CMD(WMT_CORE_START_RF_CALIBRATION_CMD, WMT_CORE_START_RF_CALIBRATION_EVT, "start RF calibration data"), ++}; ++ ++#if CFG_WMT_PATCH_DL_OPTM ++static struct init_script set_mcuclk_table_1[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_EN_CMD, WMT_SET_MCU_CLK_EN_EVT, "enable set mcu clk"), ++ INIT_CMD(WMT_SET_MCU_CLK_138_CMD, WMT_SET_MCU_CLK_138_EVT, "set mcu clk to 138.67MH"), ++}; ++ ++static struct init_script set_mcuclk_table_2[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_26_CMD, WMT_SET_MCU_CLK_26_EVT, "set mcu clk to 26MH"), ++ INIT_CMD(WMT_SET_MCU_CLK_DIS_CMD, WMT_SET_MCU_CLK_DIS_EVT, "disable set mcu clk"), ++}; ++ ++static struct init_script set_mcuclk_table_3[] = { ++ INIT_CMD(WMT_SET_MCU_CLK_EN_6797, WMT_SET_MCU_CLK_EVT_6797, "enable set mcu clk"), ++ INIT_CMD(WMT_SET_MCU_RATIO_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu ratio set"), ++ INIT_CMD(WMT_SET_MCU_DIV_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu div set"), ++ INIT_CMD(WMT_SET_MCU_HCLK_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "set mcu clk to hclk"), ++}; ++static struct init_script set_mcuclk_table_4[] = { ++ INIT_CMD(WMT_SET_MCU_HCLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu hclk"), ++ INIT_CMD(WMT_SET_MCU_RATIO_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu ratio set"), ++ INIT_CMD(WMT_SET_MCU_CLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu clk set"), ++}; ++ ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static struct init_script set_wifi_lte_coex_table_1[] = { ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), ++ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"), ++}; ++ ++static struct init_script set_wifi_lte_coex_table_2[] = { ++ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), ++ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), ++ INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), ++}; ++ ++static struct init_script set_wifi_lte_coex_table_0[] = { ++#if 0 ++ INIT_CMD(WMT_COEX_SPLIT_FILTER_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex split filter"), ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), ++ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte channel unsafe"), ++ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi coex ext component"), ++#endif ++ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte coex filter spec"), ++ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte freq idx"), ++}; ++ ++static struct init_script get_tdm_req_antsel_num_table[] = { ++ INIT_CMD(WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD, WMT_COEX_SPLIT_MODE_EVT, "get tdm req antsel num"), ++}; ++#endif ++ ++#if CFG_SET_OPT_REG ++static struct init_script set_registers[] = { ++ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ ++ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ ++#if CFG_WMT_I2S_DBGUART_SUPPORT ++ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), ++#endif ++#if CFG_SET_OPT_REG_SWLA ++ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), ++#endif ++#if CFG_SET_OPT_REG_MCUCLK ++ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), ++#endif ++#if CFG_SET_OPT_REG_MCUIRQ ++ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), ++#endif ++}; ++#endif ++ ++static struct init_script coex_table[] = { ++ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), ++ ++#if CFG_SUBSYS_COEX_NEED ++/* no need in MT6628 */ ++ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), ++ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), ++ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), ++ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), ++#endif ++}; ++ ++static struct init_script osc_type_table[] = { ++ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), ++}; ++ ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++static struct init_script merge_pcm_table[] = { ++ INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"), ++ INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"), ++ INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"), ++}; ++#endif ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static struct init_script sdio_driving_table[] = { ++ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), ++}; ++#endif ++ ++#if CFG_WMT_POWER_ON_DLM ++static struct init_script wmt_power_on_dlm_table[] = { ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD1, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd1"), ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD2, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd2"), ++ INIT_CMD(WMT_POWER_CTRL_DLM_CMD3, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd3") ++}; ++#endif ++ ++/* SOC Chip Version and Info Table */ ++static const WMT_IC_INFO_S mtk_wcn_soc_info_table[] = { ++ { ++ .u4HwVer = 0x8A00, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E1, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ /* need to refine? */ ++ .eWmtHwVer = WMTHWVER_E1, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ }, ++ { ++ .u4HwVer = 0x8A01, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E2, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ .eWmtHwVer = WMTHWVER_E2, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ }, ++ { ++ .u4HwVer = 0x8B01, ++ .cChipName = WMT_IC_NAME_DEFAULT, ++ .cChipVersion = WMT_IC_VER_E3, ++ .cPatchNameExt = WMT_IC_PATCH_E1_EXT, ++ .eWmtHwVer = WMTHWVER_E3, ++ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, ++ .bPsmSupport = MTK_WCN_BOOL_TRUE, ++ } ++}; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf); ++ ++static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); ++ ++static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); ++ ++static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); ++ ++static INT32 mtk_wcn_soc_ver_check(VOID); ++ ++static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver); ++ ++static INT32 wmt_stp_init_coex(VOID); ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static INT32 wmt_stp_wifi_lte_coex(VOID); ++#endif ++ ++#if CFG_WMT_MULTI_PATCH ++static INT32 mtk_wcn_soc_patch_dwn(UINT32 index); ++static INT32 mtk_wcn_soc_patch_info_prepare(VOID); ++#else ++static INT32 mtk_wcn_soc_patch_dwn(VOID); ++#endif ++ ++static INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on); ++static WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID); ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static INT32 mtk_wcn_soc_crystal_triming_set(VOID); ++#endif ++ ++static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID); ++ ++static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID); ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static INT32 mtk_wcn_soc_set_sdio_driving(void); ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* SOC Operation Function Table */ ++WMT_IC_OPS wmt_ic_ops_soc = { ++ .icId = 0x0000, /* soc may have mt6572/82/71/83,but they have the same sw init flow */ ++ .sw_init = mtk_wcn_soc_sw_init, ++ .sw_deinit = mtk_wcn_soc_sw_deinit, ++ .ic_pin_ctrl = mtk_wcn_soc_pin_ctrl, ++ .ic_ver_check = mtk_wcn_soc_ver_check, ++ .co_clock_ctrl = mtk_wcn_soc_co_clock_ctrl, ++ .is_quick_sleep = mtk_wcn_soc_quick_sleep_flag_get, ++ .is_aee_dump_support = mtk_wcn_soc_aee_dump_flag_get, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf) ++{ ++ INT32 iRet = -1; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ UINT32 hw_ver; ++ WMT_CTRL_DATA ctrlData; ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++ UINT32 efuse_d3_vcn33 = 2; /*default voltage is 3.5V*/ ++#endif ++#if CFG_WMT_MULTI_PATCH ++ UINT32 patch_num = 0; ++ UINT32 patch_index = 0; ++#endif ++#if CFG_WMT_WIFI_5G_SUPPORT ++ UINT32 dDieChipid = 0; ++ UINT32 aDieChipid = 0; ++ UINT8 evtbuf[20]; ++ UINT32 u4Res; ++ UINT32 pmicChipid = 0; ++#endif ++ WMT_DBG_FUNC(" start\n"); ++ ++ osal_assert(NULL != gp_soc_info); ++ if ((NULL == gp_soc_info) ++ || (NULL == pWmtHifConf) ++ ) { ++ WMT_ERR_FUNC("null pointers: gp_soc_info(0x%p), pWmtHifConf(0x%p)\n", gp_soc_info, pWmtHifConf); ++ return -1; ++ } ++ ++ hw_ver = gp_soc_info->u4HwVer; ++ ++ /* 4 <3.2> start init for BTIF */ ++ if (WMT_HIF_BTIF == pWmtHifConf->hifType) { ++ /* 1. Query chip STP default options (TEST-ONLY) */ ++ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ ++ iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); ++ osal_assert(0); ++ return -2; ++ } ++ /* 2. Set chip STP options */ ++ iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); ++ return -3; ++ } ++ ++ /* 3. Enable host full mode */ ++ ctrlPa1 = WMT_STP_CONF_MODE; ++ ctrlPa2 = MTKSTP_BTIF_FULL_MODE; ++ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WMT_STP_CONF_EN; ++ ctrlPa2 = 1; ++ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); ++ if (iRet) { ++ WMT_ERR_FUNC("enable host STP-BTIF-FULL mode fail(%d)\n", iRet); ++ return -4; ++ } ++ WMT_DBG_FUNC("enable host STP-BTIF-FULL mode\n"); ++ /*4. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ ++ osal_sleep_ms(10); ++ /* 5. Query chip STP options (TEST-ONLY) */ ++ iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); ++ return -5; ++ } ++ } ++#if CFG_WMT_POWER_ON_DLM ++ iRet = wmt_core_init_script(wmt_power_on_dlm_table, osal_array_size(wmt_power_on_dlm_table)); ++ if (iRet) ++ WMT_ERR_FUNC("wmt_power_on_dlm_table fail(%d)\n", iRet); ++ WMT_DBG_FUNC("wmt_power_on_dlm_table ok\n"); ++#endif ++ /* 6. download patch */ ++#if CFG_WMT_MULTI_PATCH ++ /* 6.1 Let launcher to search patch info */ ++ iRet = mtk_wcn_soc_patch_info_prepare(); ++ if (iRet) { ++ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); ++ return -6; ++ } ++ ++ /* 6.2 Read patch number */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); ++ patch_num = ctrlPa1; ++ WMT_DBG_FUNC("patch total num = [%d]\n", patch_num); ++ ++#if CFG_WMT_PATCH_DL_OPTM ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ iRet = wmt_core_init_script(set_mcuclk_table_3, osal_array_size(set_mcuclk_table_3)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_3 fail(%d)\n", iRet); ++ } else { ++ iRet = wmt_core_init_script(set_mcuclk_table_1, osal_array_size(set_mcuclk_table_1)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_1 fail(%d)\n", iRet); ++ } ++#endif ++ /* 6.3 Multi-patch Patch download */ ++ for (patch_index = 0; patch_index < patch_num; patch_index++) { ++ iRet = mtk_wcn_soc_patch_dwn(patch_index); ++ if (iRet) { ++ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); ++ return -7; ++ } ++ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); ++ return -8; ++ } ++ } ++ ++#if CFG_WMT_PATCH_DL_OPTM ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ iRet = wmt_core_init_script(set_mcuclk_table_4, osal_array_size(set_mcuclk_table_4)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_4 fail(%d)\n", iRet); ++ } else { ++ iRet = wmt_core_init_script(set_mcuclk_table_2, osal_array_size(set_mcuclk_table_2)); ++ if (iRet) ++ WMT_ERR_FUNC("set_mcuclk_table_2 fail(%d)\n", iRet); ++ } ++#endif ++ ++#else ++ /* 6.3 Patch download */ ++ iRet = mtk_wcn_soc_patch_dwn(); ++ /* If patch download fail, we just ignore this error and let chip init process goes on */ ++ if (iRet) ++ WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); ++ ++ /* 6.4. WMT Reset command */ ++ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); ++ return -8; ++ } ++#endif ++ ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++ /*get CrystalTiming value before set it */ ++ iRet = wmt_core_tx(get_efuse_vcn33_script[0].cmd, get_efuse_vcn33_script[0].cmdSz, &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != get_efuse_vcn33_script[0].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", ++ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].cmdSz); ++ } ++ /* EVENT BUF */ ++ osal_memset(get_efuse_vcn33_script[0].evt, 0, get_efuse_vcn33_script[0].evtSz); ++ iRet = wmt_core_rx(get_efuse_vcn33_script[0].evt, get_efuse_vcn33_script[0].evtSz, &u4Res); ++ if (iRet || (u4Res != get_efuse_vcn33_script[0].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", ++ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ } ++ efuse_d3_vcn33 = WMT_GET_EFUSE_VCN33_EVT[5] & 0x03; ++ WMT_INFO_FUNC("Read efuse to set PMIC voltage:(%d)\n", efuse_d3_vcn33); ++ wmt_set_pmic_voltage(efuse_d3_vcn33); ++#endif ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++ if ((0x6580 == wmt_ic_ops_soc.icId) || ++ (0x8163 == wmt_ic_ops_soc.icId) || ++ (0x6752 == wmt_ic_ops_soc.icId) || ++ (0x6582 == wmt_ic_ops_soc.icId) || ++ (0x6592 == wmt_ic_ops_soc.icId) || ++ (0x0279 == wmt_ic_ops_soc.icId) || ++ (0x0326 == wmt_ic_ops_soc.icId) || ++ (0x0321 == wmt_ic_ops_soc.icId) || (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { ++ wmt_stp_wifi_lte_coex(); ++ WMT_DBG_FUNC("wmt_stp_wifi_lte_coex done!\n"); ++ } ++ if ((0x6582 == wmt_ic_ops_soc.icId) || (0x6592 == wmt_ic_ops_soc.icId)) { ++ /*get gpio tdm req antsel number */ ++ ctrlPa1 = 0; ++ ctrlPa2 = 0; ++ wmt_core_ctrl(WMT_CTRL_GET_TDM_REQ_ANTSEL, &ctrlPa1, &ctrlPa2); ++ WMT_INFO_FUNC("get GPIO TDM REQ ANTSEL number(%d)\n", ctrlPa1); ++ /*set gpio tdm req antsel number to firmware */ ++ WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[5] = ctrlPa1; ++ iRet = wmt_core_init_script(get_tdm_req_antsel_num_table, ++ osal_array_size(get_tdm_req_antsel_num_table)); ++ if (iRet) ++ WMT_ERR_FUNC("get_tdm_req_antsel_num_table fail(%d)\n", iRet); ++ } ++#endif ++ /* 7. start RF calibration data */ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WIFI_PALDO; ++ ctrlPa2 = PALDO_ON; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ iRet = wmt_core_init_script(calibration_table, osal_array_size(calibration_table)); ++ if (iRet) { ++ /* pwrap_read(0x0210,&ctrlPa1); */ ++ /* pwrap_read(0x0212,&ctrlPa2); */ ++ WMT_ERR_FUNC("power status: 210:(%d),212:(%d)!\n", ctrlPa1, ctrlPa2); ++ WMT_ERR_FUNC("calibration_table fail(%d)\n", iRet); ++ return -9; ++ } ++ ++ ctrlPa1 = BT_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ctrlPa1 = WIFI_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ ++ iRet = wmt_stp_init_coex(); ++ if (iRet) { ++ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); ++ return -10; ++ } ++ WMT_DBG_FUNC("init_coex ok\n"); ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++ mtk_wcn_soc_crystal_triming_set(); ++#endif ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++ mtk_wcn_soc_set_sdio_driving(); ++#endif ++ ++ if (WMT_CO_CLOCK_EN == mtk_wcn_soc_co_clock_get()) { ++ WMT_INFO_FUNC("co-clock enabled.\n"); ++ ++ iRet = wmt_core_init_script(osc_type_table, osal_array_size(osc_type_table)); ++ if (iRet) { ++ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); ++ return -11; ++ } ++ } else { ++ WMT_WARN_FUNC("co-clock disabled.\n"); ++ } ++#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) ++ iRet = wmt_core_init_script(merge_pcm_table, osal_array_size(merge_pcm_table)); ++ if (iRet) { ++ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); ++ return -12; ++ } ++#endif ++ ++ /* 15. Set FM strap */ ++ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; ++ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; ++ iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", pWmtHifConf->au4StrapConf[0], iRet); ++ return -13; ++ } ++ WMT_DBG_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); ++ ++#if CFG_SET_OPT_REG /*set registers */ ++ iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); ++ if (iRet) { ++ WMT_ERR_FUNC("set_registers fail(%d)", iRet); ++ return -14; ++ } ++#endif ++ ++#if CFG_WMT_COREDUMP_ENABLE ++ /*Open Core Dump Function @QC begin */ ++ mtk_wcn_stp_coredump_flag_ctrl(1); ++#endif ++ if (0 != mtk_wcn_stp_coredump_flag_get()) { ++ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); ++ if (iRet) { ++ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); ++ return -15; ++ } ++ WMT_DBG_FUNC("enable soc_consys firmware coredump\n"); ++ } else { ++ WMT_DBG_FUNC("disable soc_consys firmware coredump\n"); ++ } ++ ++#if CFG_WMT_WIFI_5G_SUPPORT ++ dDieChipid = wmt_ic_ops_soc.icId; ++ WMT_DBG_FUNC("current SOC chipid is 0x%x\n", dDieChipid); ++ if (0x6592 == dDieChipid) { ++ /* read A die chipid by wmt cmd */ ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_GET_SOC_ADIE_CHIPID_CMD[0], sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); ++ return -16; ++ } ++ osal_memset(evtbuf, 0, sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT))) { ++ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); ++ return -17; ++ } ++ ++ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); ++ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); ++ ++ if (0x6625 == aDieChipid) { ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_GET_SOC_6625_L_CMD[0], sizeof(WMT_GET_SOC_6625_L_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_CMD))) ++ WMT_ERR_FUNC("wmt_core:read A die efuse CMD fail(%d),size(%d)\n", iRet, u4Res); ++ osal_memset(evtbuf, 0, sizeof(evtbuf)); ++ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_6625_L_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_EVT))) ++ WMT_ERR_FUNC("wmt_core:read A die efuse EVT fail(%d),size(%d)\n", iRet, u4Res); ++ ++ WMT_INFO_FUNC("read SOC Adie Efuse(0x120) value:0x%2x,0x%2x,0x%2x,0x%2x -> %s\n", ++ evtbuf[u4Res - 4], evtbuf[u4Res - 3], evtbuf[u4Res - 2], evtbuf[u4Res - 1], ++ evtbuf[u4Res - 2] == 0x31 ? "MT6625L" : "MT6625"); ++ } ++ /* get PMIC chipid */ ++ ++ ctrlData.ctrlId = WMT_CTRL_SOC_PALDO_CTRL; ++ ctrlData.au4CtrlData[0] = PMIC_CHIPID_PALDO; ++ ctrlData.au4CtrlData[1] = 0; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet < 0) { ++ WMT_ERR_FUNC("wmt_core: read PMIC chipid fail(%d)\n", iRet); ++ return -18; ++ } ++ pmicChipid = ctrlData.au4CtrlData[2]; ++ WMT_INFO_FUNC("current PMIC chipid(0x%x)\n", pmicChipid); ++ ++ /* MT6625 & MT6322, write 1 to 0x0414[12] */ ++ /* MT6625 & MT6323, assert */ ++ /* MT6627 & (MT6322 or MT6323),write 0 to 0x0414[12] */ ++ ++ switch (aDieChipid) { ++ case 0x6625: ++ if (0x6322 == pmicChipid) { ++ WMT_INFO_FUNC("wmt-core:enable wifi 5G support\n"); ++ ctrlPa1 = WIFI_5G_PALDO; ++ ctrlPa2 = PALDO_ON; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else if (0x6323 == pmicChipid) { ++ osal_assert(0); ++ } else { ++ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); ++ } ++ break; ++ case 0x6627: ++ if ((0x6322 == pmicChipid) || (0x6323 == pmicChipid)) { ++ WMT_INFO_FUNC("wmt-core: disable wifi 5G support\n"); ++ ctrlPa1 = WIFI_5G_PALDO; ++ ctrlPa2 = PALDO_OFF; ++ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); ++ } else { ++ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); ++ } ++ break; ++ default: ++ WMT_WARN_FUNC("wmt-core: unknown A die chipid(0x%x)\n", aDieChipid); ++ break; ++ } ++ } ++#endif ++ ++#if 1 ++ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; ++ ctrlData.au4CtrlData[0] = wmt_ic_ops_soc.icId; ++ ctrlData.au4CtrlData[1] = (SIZE_T) gp_soc_info->cChipVersion; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &gp_soc_patch_info; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); ++ return -19; ++ } ++#endif ++ ++#if CFG_WMT_PS_SUPPORT ++ osal_assert(NULL != gp_soc_info); ++ if (NULL != gp_soc_info) { ++ if (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport) ++ wmt_lib_ps_enable(); ++ else ++ wmt_lib_ps_disable(); ++ } ++#endif ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) ++{ ++ WMT_DBG_FUNC(" start\n"); ++ ++#if CFG_WMT_PS_SUPPORT ++ osal_assert(NULL != gp_soc_info); ++ if ((NULL != gp_soc_info) ++ && (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport)) { ++ wmt_lib_ps_disable(); ++ } ++#endif ++ ++ gp_soc_info = NULL; ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 ret = -1; ++ UINT32 val; ++ ++ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { ++ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); ++#if 0 ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ val = 0x00000770; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ val = 0x00000700; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x00000710; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#else ++ WMT_WARN_FUNC("TBD!!"); ++ ret = 0; ++#endif ++ } else { ++ /*PCM & I2S separate */ ++ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); ++#if 0 ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ val = 0x00000770; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ val = 0x00000700; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000000; ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x00000070; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ ++ break; ++ case WMT_IC_AIF_3: ++ val = 0x00000000; ++ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); ++ val = 0x00000800; /* 800:3-wire, 000: 4-wire */ ++ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); ++ ++ break; ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#else ++ switch (state) { ++ case WMT_IC_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ ret = 0; ++ break; ++ case WMT_IC_AIF_1: ++ /* BT_PCM_ON & FM line in/out */ ++ ret = 0; ++ break; ++ ++ case WMT_IC_AIF_2: ++ /* BT_PCM_OFF & FM I2S */ ++ val = 0x01110000; ++ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); ++ ++ break; ++ case WMT_IC_AIF_3: ++ ret = 0; ++ break; ++ ++ default: ++ WMT_ERR_FUNC("unsupported state (%d)\n", state); ++ ret = -1; ++ break; ++ } ++#endif ++ } ++ ++ if (!ret) ++ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); ++ WMT_INFO_FUNC("new state(%d) ok\n", state); ++ ++ return ret; ++} ++ ++static INT32 mtk_wcn_soc_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 iRet = -1; ++ UINT32 uVal = 0; ++ ++ /* mt6797 can not access reg:0x80050078 and no need to do GPS SYNC */ ++ if (0x0279 != wmt_ic_ops_soc.icId) { ++ if (WMT_IC_PIN_MUX == state) ++ uVal = 0x1 << 28; ++ else ++ uVal = 0x5 << 28; ++ iRet = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28); ++ if (iRet) ++ WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet); ++ } else ++ WMT_INFO_FUNC("This chip no need to sync GPS and MODEM!\n"); ++ ++ /* anyway, we return 0 */ ++ return 0; ++} ++ ++static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) ++{ ++ INT32 ret; ++ ++ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); ++ ++ ret = -1; ++ switch (id) { ++ case WMT_IC_PIN_AUDIO: ++ ret = mtk_wcn_soc_aif_ctrl(state, flag); ++ break; ++ ++ case WMT_IC_PIN_EEDI: ++ WMT_WARN_FUNC("TBD!!"); ++ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ ++ ret = 0; ++ break; ++ ++ case WMT_IC_PIN_EEDO: ++ WMT_WARN_FUNC("TBD!!"); ++ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ ++ ret = 0; ++ break; ++ case WMT_IC_PIN_GSYNC: ++ ret = mtk_wcn_soc_gps_sync_ctrl(state, flag); ++ break; ++ default: ++ break; ++ } ++ WMT_INFO_FUNC("ret = (%d)\n", ret); ++ ++ return ret; ++} ++ ++INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on) ++{ ++ INT32 iRet = 0; ++ ++ if ((WMT_CO_CLOCK_DIS <= on) && (WMT_CO_CLOCK_MAX > on)) { ++ gCoClockEn = on; ++ } else { ++ WMT_DBG_FUNC("0x%x: error parameter:%d\n", wmt_ic_ops_soc.icId, on); ++ iRet = -1; ++ } ++ WMT_DBG_FUNC("0x%x: Co-clock %s\n", wmt_ic_ops_soc.icId, ++ (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled"); ++ ++ return iRet; ++} ++ ++static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID) ++{ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID) ++{ ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID) ++{ ++ return gCoClockEn; ++} ++ ++static INT32 mtk_wcn_soc_ver_check(VOID) ++{ ++ UINT32 hw_ver; ++ UINT32 fw_ver; ++ INT32 iret; ++ const WMT_IC_INFO_S *p_info; ++ unsigned long ctrlPa1; ++ unsigned long ctrlPa2; ++ ++ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ ++ WMT_LOUD_FUNC("0x%x: before read hw_ver (hw version)\n", wmt_ic_ops_soc.icId); ++ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); ++ if (iret) { ++ WMT_ERR_FUNC("0x%x: read hw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); ++ return -2; ++ } ++ WMT_WARN_FUNC("0x%x: read hw_ver (hw version) (0x%x)\n", wmt_ic_ops_soc.icId, hw_ver); ++ ++ WMT_LOUD_FUNC("0x%x: before fw_ver (rom version)\n", wmt_ic_ops_soc.icId); ++ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); ++ if (iret) { ++ WMT_ERR_FUNC("0x%x: read fw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); ++ return -2; ++ } ++ WMT_WARN_FUNC("0x%x: read fw_ver (rom version) (0x%x)\n", wmt_ic_ops_soc.icId, fw_ver); ++ ++ p_info = mtk_wcn_soc_find_wmt_ic_info(hw_ver); ++ if (NULL == p_info) { ++ WMT_ERR_FUNC("0x%x: hw_ver(0x%x) find wmt ic info fail\n", wmt_ic_ops_soc.icId); ++ return -3; ++ } ++ WMT_WARN_FUNC("0x%x: ic info: %s.%s (0x%x/0x%x, WMTHWVER:%d, patch_ext:%s)\n", ++ wmt_ic_ops_soc.icId, p_info->cChipName, p_info->cChipVersion, ++ hw_ver, fw_ver, p_info->eWmtHwVer, p_info->cPatchNameExt); ++ ++ /* hw id & version */ ++ ctrlPa1 = (wmt_ic_ops_soc.icId << 16) | (hw_ver & 0x0000FFFF); ++ /* translated hw version & fw rom version */ ++ ctrlPa2 = ((UINT32) (p_info->eWmtHwVer) << 16) | (fw_ver & 0x0000FFFF); ++ ++ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); ++ if (iret) ++ WMT_WARN_FUNC("0x%x: WMT_CTRL_HWIDVER_SET fail(%d)\n", wmt_ic_ops_soc.icId, iret); ++ ++ gp_soc_info = p_info; ++ return 0; ++} ++ ++static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver) ++{ ++ /* match chipversion with u4HwVer item in mtk_wcn_soc_info_table */ ++ const UINT32 size = osal_array_size(mtk_wcn_soc_info_table); ++ INT32 index = 0; ++ ++ /* George: reverse the search order to favor newer version products ++ * TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() ++ * is changed correctly in the future!! ++ * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. ++ */ ++ index = size - 1; ++ /* full match */ ++ while ((0 <= index) && (hw_ver != mtk_wcn_soc_info_table[index].u4HwVer)) ++ --index; ++ if (0 <= index) { ++ WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); ++ return &mtk_wcn_soc_info_table[index]; ++ } ++ ++ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); ++ ++ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR ++ * NUM only can help us support future minor hw ECO, or fab switch, etc. ++ * FULL matching eliminate such flexibility and software package have to be ++ * updated EACH TIME even when minor hw ECO or fab switch!!! ++ */ ++ /* George: reverse the search order to favor newer version products */ ++ index = size - 1; ++ /* major num match */ ++ while ((0 <= index) && ++ (MAJORNUM(hw_ver) != MAJORNUM(mtk_wcn_soc_info_table[index].u4HwVer))) { ++ --index; ++ } ++ if (0 <= index) { ++ WMT_DBG_FUNC("0x%x: found ic info for hw_ver(0x%x) by major num! index:%d\n", ++ wmt_ic_ops_soc.icId, hw_ver, index); ++ return &mtk_wcn_soc_info_table[index]; ++ } ++ ++ WMT_ERR_FUNC("0x%x: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", ++ wmt_ic_ops_soc.icId, hw_ver); ++ WMT_ERR_FUNC("Set default chip version: E1!\n"); ++ return &mtk_wcn_soc_info_table[0]; ++} ++ ++#if CFG_WMT_FILTER_MODE_SETTING ++static INT32 wmt_stp_wifi_lte_coex(VOID) ++{ ++ INT32 iRet; ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ ++ /*Get wmt config */ ++ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (iRet) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); ++ return -2; ++ } ++ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ osal_sleep_ms(5); ++ ++ if (pWmtGenConf->coex_wmt_filter_mode == 0) { ++ if ((0x6752 == wmt_ic_ops_soc.icId) || ++ (0x6580 == wmt_ic_ops_soc.icId) || ++ (0x8163 == wmt_ic_ops_soc.icId) || ++ (0x0326 == wmt_ic_ops_soc.icId) || ++ (0x0321 == wmt_ic_ops_soc.icId) || ++ (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_1, osal_array_size(set_wifi_lte_coex_table_1)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_1 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } else if (0x0279 == wmt_ic_ops_soc.icId) { ++ /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/ ++ if (pWmtGenConf->coex_wmt_ext_component) { ++ WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); ++ set_wifi_lte_coex_table_2[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; ++ } ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_2, osal_array_size(set_wifi_lte_coex_table_2)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_2 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } else { ++ iRet = ++ wmt_core_init_script(set_wifi_lte_coex_table_0, osal_array_size(set_wifi_lte_coex_table_0)); ++ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 %s(%d)\n", iRet ? "fail" : "ok", iRet); ++ } ++ } ++ ++ return iRet; ++} ++#endif ++ ++static INT32 wmt_stp_init_coex(VOID) ++{ ++ INT32 iRet; ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ ++#define COEX_WMT 0 ++ ++#if CFG_SUBSYS_COEX_NEED ++ /* no need for MT6628 */ ++#define COEX_BT 1 ++#define COEX_WIFI 2 ++#define COEX_PTA 3 ++#define COEX_MISC 4 ++#endif ++ /*Get wmt config */ ++ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (iRet) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); ++ return -2; ++ } ++ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ /*Dump the coex-related info */ ++ WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode); ++#if CFG_SUBSYS_COEX_NEED ++ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_bt_rssi_upper_limit, ++ pWmtGenConf->coex_bt_rssi_mid_limit, ++ pWmtGenConf->coex_bt_rssi_lower_limit, ++ pWmtGenConf->coex_bt_pwr_high, pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); ++ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_wifi_rssi_upper_limit, ++ pWmtGenConf->coex_wifi_rssi_mid_limit, ++ pWmtGenConf->coex_wifi_rssi_lower_limit, ++ pWmtGenConf->coex_wifi_pwr_high, pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); ++ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_ext_pta_hi_tx_tag, ++ pWmtGenConf->coex_ext_pta_hi_rx_tag, ++ pWmtGenConf->coex_ext_pta_lo_tx_tag, ++ pWmtGenConf->coex_ext_pta_lo_rx_tag, ++ pWmtGenConf->coex_ext_pta_sample_t1, ++ pWmtGenConf->coex_ext_pta_sample_t2, pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); ++ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", ++ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); ++#endif ++ ++ /*command adjustion due to WMT.cfg */ ++ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); ++ ++#if CFG_SUBSYS_COEX_NEED ++ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; ++ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; ++ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; ++ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; ++ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; ++ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); ++ ++ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; ++ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; ++ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; ++ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; ++ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; ++ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], ++ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); ++ ++ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; ++ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; ++ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; ++ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; ++ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); ++ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); ++ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); ++ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); ++ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; ++ if (gWmtDbgLvl >= WMT_LOG_DBG) ++ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); ++ ++ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, ++ sizeof(pWmtGenConf->coex_misc_ext_pta_on)); ++ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, ++ sizeof(pWmtGenConf->coex_misc_ext_feature_set)); ++ ++ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, coex_table[COEX_MISC].cmdSz); ++#endif ++ ++ iRet = wmt_core_init_script(coex_table, sizeof(coex_table) / sizeof(coex_table[0])); ++ ++ return iRet; ++} ++ ++#if CFG_WMT_SDIO_DRIVING_SET ++static INT32 mtk_wcn_soc_set_sdio_driving(void) ++{ ++ INT32 ret = 0; ++ ++ unsigned long addr; ++ WMT_GEN_CONF *pWmtGenConf; ++ UINT32 drv_val = 0; ++ ++ /*Get wmt config */ ++ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); ++ if (ret) { ++ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); ++ return -1; ++ } ++ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); ++ ++ pWmtGenConf = (P_WMT_GEN_CONF) addr; ++ ++ /*Check if WMT.cfg exists */ ++ if (pWmtGenConf->cfgExist == 0) { ++ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); ++ /*if WMT.cfg not existed, still return success and adopt the default value */ ++ return 0; ++ } ++ ++ drv_val = pWmtGenConf->sdio_driving_cfg; ++ ++ /*Dump the sdio driving related info */ ++ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); ++ ++ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ ++ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ ++ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ ++ ++ ret = wmt_core_init_script(sdio_driving_table, sizeof(sdio_driving_table) / sizeof(sdio_driving_table[0])); ++ ++ return ret; ++} ++#endif ++ ++#if CFG_WMT_CRYSTAL_TIMING_SET ++static INT32 mtk_wcn_soc_crystal_triming_set(VOID) ++{ ++ INT32 iRet = 0; ++ PUINT8 pbuf = NULL; ++ UINT32 bufLen = 0; ++ WMT_CTRL_DATA ctrlData; ++ UINT32 uCryTimOffset = 0x6D; ++ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ INT8 cCrystalTimingOffset = 0x0; ++ UINT8 cCrystalTiming = 0x0; ++ INT32 iCrystalTiming = 0x0; ++ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ UINT32 u4Res; ++ ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ /**/ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; ++ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; ++ ctrlData.au4CtrlData[1] = (UINT32) &pbuf; ++ ctrlData.au4CtrlData[2] = (UINT32) &bufLen; ++ ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 != iRet) { ++ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", wmt_ic_ops_soc.icId, iRet); ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ cCrystalTimingOffset = 0x0; ++ cCrystalTiming = 0x0; ++ iRet = -1; ++ } else { ++ WMT_DBG_FUNC("0x%x: nvram pBuf(0x%08x), bufLen(%d)\n", wmt_ic_ops_soc.icId, pbuf, bufLen); ++ if (bufLen < (uCryTimOffset + 1)) { ++ WMT_ERR_FUNC("0x%x: nvram len(%d) too short, crystalTimging value offset(%d)\n", ++ wmt_ic_ops_soc.icId, bufLen, uCryTimOffset); ++ bIsNvramExist = MTK_WCN_BOOL_FALSE; ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; ++ cCrystalTimingOffset = 0x0; ++ cCrystalTiming = 0x0; ++ } else { ++ bIsNvramExist = MTK_WCN_BOOL_TRUE; ++ cCrystalTimingOffset = *(pbuf + uCryTimOffset); ++ if (cCrystalTimingOffset & 0x80) { ++ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; ++ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; ++ } ++ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", cCrystalTimingOffset, ++ bIsCrysTrimEnabled); ++ } ++ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; ++ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 != iRet) { ++ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", wmt_ic_ops_soc.icId, iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n", wmt_ic_ops_soc.icId); ++ } ++ } ++ if ((MTK_WCN_BOOL_TRUE == bIsNvramExist) && (MTK_WCN_BOOL_TRUE == bIsCrysTrimEnabled)) { ++ /*get CrystalTiming value before set it */ ++ iRet = ++ wmt_core_tx(get_crystal_timing_script[0].cmd, get_crystal_timing_script[0].cmdSz, &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { ++ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", ++ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].cmdSz); ++ iRet = -3; ++ goto done; ++ } ++ /* EVENT BUF */ ++ osal_memset(get_crystal_timing_script[0].evt, 0, get_crystal_timing_script[0].evtSz); ++ iRet = wmt_core_rx(get_crystal_timing_script[0].evt, get_crystal_timing_script[0].evtSz, &u4Res); ++ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { ++ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", ++ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].evtSz); ++ mtk_wcn_stp_dbg_dump_package(); ++ iRet = -4; ++ goto done; ++ } ++ ++ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; ++ if (cCrystalTimingOffset & 0x40) { ++ /*nagative offset value */ ++ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; ++ } else { ++ iCrystalTiming += cCrystalTimingOffset; ++ } ++ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); ++ cCrystalTiming = iCrystalTiming > 0x7f ? 0x7f : iCrystalTiming; ++ cCrystalTiming = iCrystalTiming < 0 ? 0 : iCrystalTiming; ++ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); ++ /* set_crystal_timing_script */ ++ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; ++ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; ++ ++ iRet = wmt_core_init_script(set_crystal_timing_script, osal_array_size(set_crystal_timing_script)); ++ if (iRet) { ++ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); ++ iRet = -5; ++ } else { ++ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", WMT_SET_CRYSTAL_TRIMING_CMD[5]); ++ iRet = ++ wmt_core_init_script(get_crystal_timing_script, osal_array_size(get_crystal_timing_script)); ++ if (iRet) { ++ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); ++ iRet = -6; ++ } else { ++ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", ++ WMT_GET_CRYSTAL_TRIMING_EVT[5]); ++ iRet = 0x0; ++ } ++ } ++ } ++done: ++ return iRet; ++} ++#endif ++ ++#if CFG_WMT_MULTI_PATCH ++static INT32 mtk_wcn_soc_patch_info_prepare(VOID) ++{ ++ INT32 iRet = -1; ++ WMT_CTRL_DATA ctrlData; ++ ++ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; ++ iRet = wmt_ctrl(&ctrlData); ++ ++ return iRet; ++} ++ ++static INT32 mtk_wcn_soc_patch_dwn(UINT32 index) ++{ ++ INT32 iRet = -1; ++ P_WMT_PATCH patchHdr; ++ PUINT8 pbuf; ++ UINT32 patchSize; ++ UINT32 fragSeq; ++ UINT32 fragNum; ++ UINT16 fragSize = 0; ++ UINT16 cmdLen; ++ UINT32 offset; ++ UINT32 u4Res; ++ UINT8 evtBuf[8]; ++ UINT8 addressevtBuf[12]; ++ UINT8 addressByte[4]; ++ PINT8 cDataTime = NULL; ++ /*PINT8 cPlat = NULL; */ ++ UINT16 u2HwVer = 0; ++ UINT16 u2SwVer = 0; ++ UINT32 u4PatchVer = 0; ++ UINT32 patchSizePerFrag = 0; ++ WMT_CTRL_DATA ctrlData; ++ ++ /*1.check hardware information */ ++ if (NULL == gp_soc_info) { ++ WMT_ERR_FUNC("null gp_soc_info!\n"); ++ return -1; ++ } ++ ++ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); ++ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; ++ ctrlData.au4CtrlData[0] = index + 1; ++ ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &addressByte; ++ iRet = wmt_ctrl(&ctrlData); ++ WMT_DBG_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); ++ ++ /* <2.2> read patch content */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH; ++ ctrlData.au4CtrlData[0] = (SIZE_T) NULL; ++ ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; ++ ctrlData.au4CtrlData[2] = (SIZE_T) &pbuf; ++ ctrlData.au4CtrlData[3] = (SIZE_T) &patchSize; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); ++ iRet -= 1; ++ goto done; ++ } ++ ++ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ ++ pbuf += BCNT_PATCH_BUF_HEADROOM; ++ /* patch file with header: ++ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| ++ */ ++ patchHdr = (P_WMT_PATCH) pbuf; ++ /* check patch file information */ ++ ++ cDataTime = patchHdr->ucDateTime; ++ u2HwVer = patchHdr->u2HwVer; ++ u2SwVer = patchHdr->u2SwVer; ++ u4PatchVer = patchHdr->u4PatchVer; ++ /*cPlat = &patchHdr->ucPLat[0]; */ ++ ++ cDataTime[15] = '\0'; ++ if (index == 0) { ++ WMT_DBG_FUNC("===========================================\n"); ++ WMT_INFO_FUNC("[Patch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", ++ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), ++ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), ++ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); ++ WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], ++ patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("===========================================\n"); ++ } ++ ++ /* remove patch header: ++ * |<-patch body: X Bytes (X=patchSize)--->| ++ */ ++ patchSize -= sizeof(WMT_PATCH); ++ pbuf += sizeof(WMT_PATCH); ++ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; ++ /* reserve 1st patch cmd space before patch body ++ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| ++ */ ++ /* gp_soc_patch_info = patchHdr; */ ++ osal_memcpy(&gp_soc_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); ++ pbuf -= sizeof(WMT_PATCH_CMD); ++ ++ fragNum = patchSize / patchSizePerFrag; ++ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; ++ ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ ++ /*send wmt part patch address command */ ++ if (0x6752 == wmt_ic_ops_soc.icId || ++ 0x8127 == wmt_ic_ops_soc.icId || ++ 0x7623 == wmt_ic_ops_soc.icId || ++ 0x6571 == wmt_ic_ops_soc.icId || ++ 0x0326 == wmt_ic_ops_soc.icId || ++ 0x0321 == wmt_ic_ops_soc.icId || ++ 0x0335 == wmt_ic_ops_soc.icId || ++ 0x0337 == wmt_ic_ops_soc.icId || 0x8163 == wmt_ic_ops_soc.icId || 0x6580 == wmt_ic_ops_soc.icId) { ++ /* MT6571 patch RAM base */ ++ WMT_PATCH_ADDRESS_CMD[8] = 0x40; ++ WMT_PATCH_P_ADDRESS_CMD[8] = 0xc8; ++ } ++ /*send wmt part patch address command */ ++ if (0x0279 == wmt_ic_ops_soc.icId) { ++ /* MT6797 patch RAM base */ ++ WMT_PATCH_ADDRESS_CMD[8] = 0x08; ++ WMT_PATCH_ADDRESS_CMD[9] = 0x05; ++ WMT_PATCH_P_ADDRESS_CMD[8] = 0x2c; ++ WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b; ++ } ++ ++ /*send wmt part patch address command */ ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); ++ iRet -= 1; ++ goto done; ++ } ++ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); ++ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); ++ iRet -= 1; ++ goto done; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); ++ iRet -= 1; ++ goto done; ++ } ++#endif ++ ++ /*send part patch address command */ ++ osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); ++ WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", ++ WMT_PATCH_P_ADDRESS_CMD[12], ++ WMT_PATCH_P_ADDRESS_CMD[13], WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); ++ iRet = ++ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { ++ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); ++ iRet -= 1; ++ goto done; ++ } ++ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); ++ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { ++ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); ++ iRet -= 1; ++ goto done; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", index); ++ iRet -= 1; ++ goto done; ++ } ++#endif ++ ++ /* send all fragments */ ++ offset = sizeof(WMT_PATCH_CMD); ++ fragSeq = 0; ++ while (fragSeq < fragNum) { ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ if (fragSeq == (fragNum - 1)) { ++ /* last fragment */ ++ fragSize = patchSize - fragSeq * patchSizePerFrag; ++ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; ++ } else { ++ fragSize = patchSizePerFrag; ++ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; ++ } ++ /* update length field in CMD:flag+frag */ ++ cmdLen = 1 + fragSize; ++ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); ++ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ ++ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); ++ ++ /* iRet = ++ *(*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ *&u4Res); ++ */ ++ iRet = ++ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ &u4Res, MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); ++ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ ++ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), ++ u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, ++ evtBuf[0], ++ evtBuf[1], ++ evtBuf[2], ++ evtBuf[3], ++ evtBuf[4]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_PATCH_EVT), ++ WMT_PATCH_EVT[0], ++ WMT_PATCH_EVT[1], ++ WMT_PATCH_EVT[2], ++ WMT_PATCH_EVT[3], ++ WMT_PATCH_EVT[4]); ++ iRet -= 1; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); ++ offset += patchSizePerFrag; ++ ++fragSeq; ++ } ++ ++ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", ++ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); ++ ++ if (fragSeq != fragNum) ++ iRet -= 1; ++done: ++ /* WMT_CTRL_FREE_PATCH always return 0 */ ++ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ ++ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; ++ ctrlData.au4CtrlData[0] = index + 1; ++ wmt_ctrl(&ctrlData); ++ ++ return iRet; ++} ++ ++#else ++static INT32 mtk_wcn_soc_patch_dwn(VOID) ++{ ++ INT32 iRet = -1; ++ P_WMT_PATCH patchHdr; ++ PUINT8 pbuf; ++ UINT32 patchSize; ++ UINT32 fragSeq; ++ UINT32 fragNum; ++ UINT16 fragSize = 0; ++ UINT16 cmdLen; ++ UINT32 offset; ++ UINT32 u4Res; ++ UINT8 evtBuf[8]; ++ PINT8 cDataTime = NULL; ++ /*PINT8 cPlat = NULL; */ ++ UINT16 u2HwVer = 0; ++ UINT16 u2SwVer = 0; ++ UINT32 u4PatchVer = 0; ++ UINT32 patchSizePerFrag = 0; ++ WMT_CTRL_DATA ctrlData; ++ ++ /*1.check hardware information */ ++ if (NULL == gp_soc_info) { ++ WMT_ERR_FUNC("null gp_soc_info!\n"); ++ return -1; ++ } ++ /* <2> search patch and read patch content */ ++ /* <2.1> search patch */ ++ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; ++ iRet = wmt_ctrl(&ctrlData); ++ if (0 == iRet) { ++ /* patch with correct Hw Ver Major Num found */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; ++ ctrlData.au4CtrlData[0] = (UINT32) &gFullPatchName; ++ iRet = wmt_ctrl(&ctrlData); ++ ++ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); ++ /* <2.2> read patch content */ ++ ctrlData.ctrlId = WMT_CTRL_GET_PATCH; ++ ctrlData.au4CtrlData[0] = (UINT32) NULL; ++ ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName; ++ ++ } else { ++ iRet -= 1; ++ return iRet; ++ } ++ ctrlData.au4CtrlData[2] = (UINT32) &pbuf; ++ ctrlData.au4CtrlData[3] = (UINT32) &patchSize; ++ iRet = wmt_ctrl(&ctrlData); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); ++ iRet -= 1; ++ goto done; ++ } ++ ++ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ ++ pbuf += BCNT_PATCH_BUF_HEADROOM; ++ /* patch file with header: ++ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| ++ */ ++ patchHdr = (P_WMT_PATCH) pbuf; ++ /* check patch file information */ ++ ++ cDataTime = patchHdr->ucDateTime; ++ u2HwVer = patchHdr->u2HwVer; ++ u2SwVer = patchHdr->u2SwVer; ++ u4PatchVer = patchHdr->u4PatchVer; ++ /*cPlat = &patchHdr->ucPLat[0]; */ ++ ++ cDataTime[15] = '\0'; ++ WMT_DBG_FUNC("===========================================\n"); ++ WMT_INFO_FUNC("[ConsysPatch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", ++ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), ++ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), ++ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); ++ WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", ++ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); ++ WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], ++ patchHdr->ucPLat[2], patchHdr->ucPLat[3]); ++ WMT_DBG_FUNC("===========================================\n"); ++ ++ /* remove patch header: ++ * |<-patch body: X Bytes (X=patchSize)--->| ++ */ ++ patchSize -= sizeof(WMT_PATCH); ++ pbuf += sizeof(WMT_PATCH); ++ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; ++ /* reserve 1st patch cmd space before patch body ++ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| ++ */ ++ pbuf -= sizeof(WMT_PATCH_CMD); ++ ++ fragNum = patchSize / patchSizePerFrag; ++ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; ++ ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ ++ /* send all fragments */ ++ offset = sizeof(WMT_PATCH_CMD); ++ fragSeq = 0; ++ while (fragSeq < fragNum) { ++ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); ++ if (fragSeq == (fragNum - 1)) { ++ /* last fragment */ ++ fragSize = patchSize - fragSeq * patchSizePerFrag; ++ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; ++ } else { ++ fragSize = patchSizePerFrag; ++ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; ++ } ++ /* update length field in CMD:flag+frag */ ++ cmdLen = 1 + fragSize; ++ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); ++ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ ++ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); ++ ++ /* iRet = ++ * (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), ++ * &u4Res); ++ */ ++ iRet = ++ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), &u4Res, ++ MTK_WCN_BOOL_FALSE); ++ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { ++ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, ++ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", ++ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); ++ ++ osal_memset(evtBuf, 0, sizeof(evtBuf)); ++ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ ++ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); ++ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { ++ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), ++ u4Res, iRet); ++ iRet -= 1; ++ break; ++ } ++#if CFG_CHECK_WMT_RESULT ++ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { ++ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ u4Res, ++ evtBuf[0], ++ evtBuf[1], ++ evtBuf[2], ++ evtBuf[3], ++ evtBuf[4]); ++ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", ++ sizeof(WMT_PATCH_EVT), ++ WMT_PATCH_EVT[0], ++ WMT_PATCH_EVT[1], ++ WMT_PATCH_EVT[2], ++ WMT_PATCH_EVT[3], ++ WMT_PATCH_EVT[4]); ++ iRet -= 1; ++ break; ++ } ++#endif ++ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); ++ offset += patchSizePerFrag; ++ ++fragSeq; ++ } ++ ++ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", ++ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); ++ ++ if (fragSeq != fragNum) ++ iRet -= 1; ++done: ++ /* WMT_CTRL_FREE_PATCH always return 0 */ ++ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); ++ ++ return iRet; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c +new file mode 100644 +index 000000000000..747ed64af2d2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c +@@ -0,0 +1,1938 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-LIB]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include "wmt_dev.h" ++#include "wmt_lib.h" ++#include "wmt_conf.h" ++#include "wmt_core.h" ++#include "wmt_plat.h" ++ ++#include "stp_core.h" ++#include "btm_core.h" ++#include "psm_core.h" ++#include "stp_dbg.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* A table for translation: CMB_STUB_AIF_X=>WMT_IC_PIN_STATE */ ++static const WMT_IC_PIN_STATE cmb_aif2pin_stat[] = { ++ [CMB_STUB_AIF_0] = WMT_IC_AIF_0, ++ [CMB_STUB_AIF_1] = WMT_IC_AIF_1, ++ [CMB_STUB_AIF_2] = WMT_IC_AIF_2, ++ [CMB_STUB_AIF_3] = WMT_IC_AIF_3, ++}; ++ ++#if CFG_WMT_PS_SUPPORT ++static UINT32 gPsIdleTime = STP_PSM_IDLE_TIME_SLEEP; ++static UINT32 gPsEnable = 1; ++static PF_WMT_SDIO_PSOP sdio_own_ctrl; ++#endif ++ ++#define WMT_STP_CPUPCR_BUF_SIZE 6144 ++static UINT8 g_cpupcr_buf[WMT_STP_CPUPCR_BUF_SIZE] = { 0 }; ++ ++static UINT32 g_quick_sleep_ctrl = 1; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++DEV_WMT gDevWmt; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_WMT_PS_SUPPORT ++static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action); ++static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID); ++static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID); ++static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID); ++static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action); ++#endif ++ ++static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pLxOp); ++ ++static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ); ++ ++static INT32 wmtd_thread(PVOID pvData); ++ ++static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag); ++static MTK_WCN_BOOL wmt_lib_hw_state_show(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++INT32 wmt_lib_idc_lock_aquire(VOID) ++{ ++ return osal_lock_sleepable_lock(&gDevWmt.idc_lock); ++} ++ ++VOID wmt_lib_idc_lock_release(VOID) ++{ ++ osal_unlock_sleepable_lock(&gDevWmt.idc_lock); ++} ++INT32 wmt_lib_psm_lock_aquire(void) ++{ ++ return osal_lock_sleepable_lock(&gDevWmt.psm_lock); ++} ++ ++void wmt_lib_psm_lock_release(void) ++{ ++ osal_unlock_sleepable_lock(&gDevWmt.psm_lock); ++} ++ ++INT32 DISABLE_PSM_MONITOR(void) ++{ ++ INT32 ret = 0; ++ ++ /* osal_lock_sleepable_lock(&gDevWmt.psm_lock); */ ++ ret = wmt_lib_psm_lock_aquire(); ++ if (ret) { ++ WMT_ERR_FUNC("--->lock psm_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++#if CFG_WMT_PS_SUPPORT ++ ret = wmt_lib_ps_disable(); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_lib_ps_disable fail, ret=%d\n", ret); ++ wmt_lib_psm_lock_release(); ++ } ++#endif ++ ++ return ret; ++} ++ ++void ENABLE_PSM_MONITOR(void) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_enable(); ++#endif ++ /* osal_unlock_sleepable_lock(&gDevWmt.psm_lock); */ ++ wmt_lib_psm_lock_release(); ++} ++ ++INT32 wmt_lib_init(VOID) ++{ ++ INT32 iRet; ++ UINT32 i; ++ P_DEV_WMT pDevWmt; ++ P_OSAL_THREAD pThraed; ++ ++ /* create->init->start */ ++ /* 1. create: static allocation with zero initialization */ ++ pDevWmt = &gDevWmt; ++ osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); ++ ++ iRet = wmt_conf_read_file(); ++ if (iRet) { ++ WMT_ERR_FUNC("read wmt config file fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ pThraed = &gDevWmt.thread; ++ ++ /* Create mtk_wmtd thread */ ++ osal_strncpy(pThraed->threadName, "mtk_wmtd", sizeof(pThraed->threadName)); ++ pThraed->pThreadData = (VOID *) pDevWmt; ++ pThraed->pThreadFunc = (VOID *) wmtd_thread; ++ iRet = osal_thread_create(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThraed, iRet); ++ return -2; ++ } ++ ++ /* 2. initialize */ ++ /* Initialize wmt_core */ ++ ++ iRet = wmt_core_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core_init() fail(%d)\n", iRet); ++ return -1; ++ } ++ ++ /* Initialize WMTd Thread Information: Thread */ ++ osal_event_init(&pDevWmt->rWmtdWq); ++ osal_sleepable_lock_init(&pDevWmt->psm_lock); ++ osal_sleepable_lock_init(&pDevWmt->idc_lock); ++ osal_sleepable_lock_init(&pDevWmt->rActiveOpQ.sLock); ++ osal_sleepable_lock_init(&pDevWmt->rFreeOpQ.sLock); ++ pDevWmt->state.data = 0; ++ ++ /* Initialize op queue */ ++ RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); ++ RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); ++ /* Put all to free Q */ ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(pDevWmt->arQue[i].signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); ++ } ++ ++ /* initialize stp resources */ ++ osal_event_init(&pDevWmt->rWmtRxWq); ++ ++ /*function driver callback */ ++ for (i = 0; i < WMTDRV_TYPE_WIFI; i++) ++ pDevWmt->rFdrvCb.fDrvRst[i] = NULL; ++ ++ pDevWmt->hw_ver = WMTHWVER_MAX; ++ WMT_INFO_FUNC("***********Init, hw->ver = %x\n", pDevWmt->hw_ver); ++ ++ /* TODO:[FixMe][GeorgeKuo]: wmt_lib_conf_init */ ++ /* initialize default configurations */ ++ /* i4Result = wmt_lib_conf_init(VOID); */ ++ /* WMT_WARN_FUNC("wmt_drv_conf_init(%d)\n", i4Result); */ ++ ++ osal_signal_init(&pDevWmt->cmdResp); ++ osal_event_init(&pDevWmt->cmdReq); ++ ++ /* initialize platform resources */ ++ if (0 != gDevWmt.rWmtGenConf.cfgExist) ++ iRet = wmt_plat_init(gDevWmt.rWmtGenConf.co_clock_flag & 0x0f); ++ else ++ iRet = wmt_plat_init(0); ++ ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_plat_init() fail(%d)\n", iRet); ++ return -3; ++ } ++#if CFG_WMT_PS_SUPPORT ++ iRet = wmt_lib_ps_init(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_lib_ps_init() fail(%d)\n", iRet); ++ return -4; ++ } ++#endif ++ ++ /* 3. start: start running mtk_wmtd */ ++ iRet = osal_thread_run(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", pThraed, iRet); ++ return -5; ++ } ++ ++ /*4. register irq callback to WMT-PLAT */ ++ wmt_plat_irq_cb_reg(wmt_lib_ps_irq_cb); ++ ++ /*5. register audio if control callback to WMT-PLAT */ ++ wmt_plat_aif_cb_reg(wmt_lib_set_aif); ++ ++ /*6. register function control callback to WMT-PLAT */ ++ wmt_plat_func_ctrl_cb_reg(mtk_wcn_wmt_func_ctrl_for_plat); ++ ++ wmt_plat_deep_idle_ctrl_cb_reg(mtk_wcn_consys_stp_btif_dpidle_ctrl); ++ /*7 reset gps/bt state */ ++ ++ mtk_wcn_wmt_system_state_reset(); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_wmt_exp_init(); ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ wmt_idc_init(); ++#endif ++ WMT_DBG_FUNC("init success\n"); ++ return 0; ++} ++ ++INT32 wmt_lib_deinit(VOID) ++{ ++ INT32 iRet; ++ P_DEV_WMT pDevWmt; ++ P_OSAL_THREAD pThraed; ++ INT32 i; ++ INT32 iResult; ++ ++ pDevWmt = &gDevWmt; ++ pThraed = &gDevWmt.thread; ++ iResult = 0; ++ ++ /* stop->deinit->destroy */ ++ ++ /* 1. stop: stop running mtk_wmtd */ ++ iRet = osal_thread_stop(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); ++ iResult += 1; ++ } ++ ++ /* 2. deinit: */ ++ ++#if CFG_WMT_PS_SUPPORT ++ iRet = wmt_lib_ps_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_lib_ps_deinit fail(%d)\n", iRet); ++ iResult += 2; ++ } ++#endif ++ ++ iRet = wmt_plat_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_plat_deinit fail(%d)\n", iRet); ++ iResult += 4; ++ } ++ ++ osal_event_deinit(&pDevWmt->cmdReq); ++ osal_signal_deinit(&pDevWmt->cmdResp); ++ ++ /* de-initialize stp resources */ ++ osal_event_deinit(&pDevWmt->rWmtRxWq); ++ ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) ++ osal_signal_deinit(&(pDevWmt->arQue[i].signal)); ++ ++ ++ osal_sleepable_lock_deinit(&pDevWmt->rFreeOpQ.sLock); ++ osal_sleepable_lock_deinit(&pDevWmt->rActiveOpQ.sLock); ++ osal_sleepable_lock_deinit(&pDevWmt->idc_lock); ++ osal_sleepable_lock_deinit(&pDevWmt->psm_lock); ++ osal_event_deinit(&pDevWmt->rWmtdWq); ++ ++ iRet = wmt_core_deinit(); ++ if (iRet) { ++ WMT_ERR_FUNC("wmt_core_deinit fail(%d)\n", iRet); ++ iResult += 8; ++ } ++ ++ /* 3. destroy */ ++ iRet = osal_thread_destroy(pThraed); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); ++ iResult += 16; ++ } ++ osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_wmt_exp_deinit(); ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ wmt_idc_deinit(); ++#endif ++ ++ return iResult; ++} ++ ++VOID wmt_lib_flush_rx(VOID) ++{ ++ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); ++} ++ ++INT32 wmt_lib_trigger_cmd_signal(INT32 result) ++{ ++ P_OSAL_SIGNAL pSignal = &gDevWmt.cmdResp; ++ ++ gDevWmt.cmdResult = result; ++ osal_raise_signal(pSignal); ++ WMT_DBG_FUNC("wakeup cmdResp\n"); ++ return 0; ++} ++ ++P_OSAL_EVENT wmt_lib_get_cmd_event(VOID) ++{ ++ return &gDevWmt.cmdReq; ++} ++ ++INT32 wmt_lib_set_patch_name(PUINT8 cPatchName) ++{ ++ osal_strncpy(gDevWmt.cPatchName, cPatchName, NAME_MAX); ++ return 0; ++} ++ ++INT32 wmt_lib_set_hif(unsigned long hifconf) ++{ ++ UINT32 val; ++ P_WMT_HIF_CONF pHif = &gDevWmt.rWmtHifConf; ++ ++ val = hifconf & 0xF; ++ if (STP_UART_FULL == val) { ++ pHif->hifType = WMT_HIF_UART; ++ val = (hifconf >> 8); ++ pHif->au4HifConf[0] = val; ++ pHif->au4HifConf[1] = val; ++ mtk_wcn_stp_set_if_tx_type(STP_UART_IF_TX); ++ } else if (STP_SDIO == val) { ++ pHif->hifType = WMT_HIF_SDIO; ++ mtk_wcn_stp_set_if_tx_type(STP_SDIO_IF_TX); ++ } else if (STP_BTIF_FULL == val) { ++ pHif->hifType = WMT_HIF_BTIF; ++ mtk_wcn_stp_set_if_tx_type(STP_BTIF_IF_TX); ++ } else { ++ WMT_WARN_FUNC("invalid stp mode: %u\n", val); ++ mtk_wcn_stp_set_if_tx_type(STP_MAX_IF_TX); ++ return -1; ++ } ++ ++ val = (hifconf & 0xF0) >> 4; ++ if (WMT_FM_COMM == val) { ++ pHif->au4StrapConf[0] = WMT_FM_COMM; ++ } else if (WMT_FM_I2C == val) { ++ pHif->au4StrapConf[0] = WMT_FM_I2C; ++ } else { ++ WMT_WARN_FUNC("invalid fm mode: %u\n", val); ++ return -2; ++ } ++ ++ WMT_WARN_FUNC("new hifType: %d, fm:%d\n", pHif->hifType, pHif->au4StrapConf[0]); ++ return 0; ++} ++ ++P_WMT_HIF_CONF wmt_lib_get_hif(VOID) ++{ ++ return &gDevWmt.rWmtHifConf; ++} ++ ++PUINT8 wmt_lib_get_cmd(VOID) ++{ ++ if (osal_test_and_clear_bit(WMT_STAT_CMD, &gDevWmt.state)) ++ return gDevWmt.cCmd; ++ ++ return NULL; ++} ++ ++MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID) ++{ ++ return osal_test_bit(WMT_STAT_CMD, &gDevWmt.state) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; ++} ++ ++#if CFG_WMT_PS_SUPPORT ++INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime) ++{ ++ gPsIdleTime = psIdleTime; ++ return gPsIdleTime; ++} ++ ++INT32 wmt_lib_ps_ctrl(UINT32 state) ++{ ++ if (0 == state) { ++ wmt_lib_ps_disable(); ++ gPsEnable = 0; ++ } else { ++ gPsEnable = 1; ++ wmt_lib_ps_enable(); ++ } ++ return 0; ++} ++ ++INT32 wmt_lib_ps_enable(VOID) ++{ ++ if (gPsEnable) ++ mtk_wcn_stp_psm_enable(gPsIdleTime); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_disable(VOID) ++{ ++ if (gPsEnable) ++ return mtk_wcn_stp_psm_disable(); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_init(VOID) ++{ ++ /* mtk_wcn_stp_psm_register_wmt_cb(wmt_lib_ps_stp_cb); */ ++ return 0; ++} ++ ++INT32 wmt_lib_ps_deinit(VOID) ++{ ++ /* mtk_wcn_stp_psm_unregister_wmt_cb(); */ ++ return 0; ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action) ++{ ++ P_OSAL_OP lxop; ++ MTK_WCN_BOOL bRet; ++ UINT32 u4Wait; ++ P_OSAL_SIGNAL pSignal; ++ ++ lxop = wmt_lib_get_free_op(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ pSignal = &lxop->signal; ++ pSignal->timeoutValue = 0; ++ lxop->op.opId = WMT_OPID_PWR_SV; ++ lxop->op.au4OpData[0] = action; ++ lxop->op.au4OpData[1] = (SIZE_T) mtk_wcn_stp_psm_notify_stp; ++ u4Wait = 0; ++ bRet = wmt_lib_put_act_op(lxop); ++ return bRet; ++} ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor) ++{ ++ P_OSAL_OP lxop; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ INT32 ret = 0; ++ UINT16 msg_len = 0; ++ static UINT8 msg_local_buffer[1300]; ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++#endif ++ WMT_DBG_FUNC("idc_infor from conn_md is 0x%p\n", idc_infor); ++ ret = wmt_lib_idc_lock_aquire(); ++ if (ret) { ++ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", ret); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ msg_len = idc_infor->local_para_ptr->msg_len - osal_sizeof(local_para_struct); ++ osal_memcpy(&msg_local_buffer[0], &msg_len, osal_sizeof(msg_len)); ++ osal_memcpy(&msg_local_buffer[osal_sizeof(msg_len)], ++ &(idc_infor->local_para_ptr->data[0]), msg_len - 1); ++ wmt_lib_idc_lock_release(); ++ lxop = wmt_lib_get_free_op(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ pSignal = &lxop->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ lxop->op.opId = WMT_OPID_IDC_MSG_HANDLING; ++ lxop->op.au4OpData[0] = (size_t) msg_local_buffer; ++ /*msg opcode fill rule is still not clrear,need scott comment */ ++ /***********************************************************/ ++ WMT_DBG_FUNC("ilm msg id is (0x%08x)\n", idc_infor->msg_id); ++ ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ switch (idc_infor->msg_id) { ++ case IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_PARA; ++ break; ++ case IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_FREQ; ++ break; ++ case IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_WIFI_MAX_POWER; ++ break; ++ case IPC_MSG_ID_EL1_LTE_TX_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_INDICATION; ++ break; ++ case IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND: ++ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS; ++ break; ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ break; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(lxop); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(lxop); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); ++ else ++ WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", lxop->op.opId, lxop->op.au4OpData[1]); ++ } else { ++ bRet = MTK_WCN_BOOL_FALSE; ++ wmt_lib_put_op_to_free_queue(lxop); ++ WMT_ERR_FUNC("unknown msgid from LTE(%d)\n", idc_infor->msg_id); ++ } ++#else ++ if ((idc_infor->msg_id >= IPC_EL1_MSG_ID_BEGIN) ++ && (idc_infor->msg_id <= IPC_EL1_MSG_ID_BEGIN + IPC_EL1_MSG_ID_RANGE)) { ++ lxop->op.au4OpData[1] = idc_infor->msg_id - IPC_EL1_MSG_ID_BEGIN + LTE_MSG_ID_OFFSET - 1; ++ ++ WMT_DBG_FUNC("LTE->CONN:(0x%x->0x%zx)\n", idc_infor->msg_id, lxop->op.au4OpData[1]); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(lxop); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(lxop); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); ++ } else { ++ WMT_DBG_FUNC("wmt_lib_handle_idc_msg OPID(%d) type(%d) ok\n", ++ lxop->op.opId, lxop->op.au4OpData[1]); ++ } ++ } else { ++ wmt_lib_put_op_to_free_queue(lxop); ++ WMT_ERR_FUNC("msgid(%d) out of range,wmt drop it!\n", idc_infor->msg_id); ++ } ++#endif ++ ++ return bRet; ++} ++#endif ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID) ++{ ++ return wmt_lib_ps_action(SLEEP); ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID) ++{ ++ return wmt_lib_ps_action(WAKEUP); ++} ++ ++static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID) ++{ ++#if 1 ++ return wmt_lib_ps_action(WAKEUP); ++#else ++ return wmt_lib_ps_action(HOST_AWAKE); ++#endif ++} ++ ++/* extern int g_block_tx; */ ++static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action) ++{ ++ INT32 ret; ++ ++ ret = 0; /* TODO:[FixMe][George] initial value or compile warning? */ ++ /* if(g_block_tx && (action == SLEEP)) */ ++ if ((0 != mtk_wcn_stp_coredump_start_get()) && (action == SLEEP)) { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ return ret; ++ } ++ ++ /*MT662x Not Ready */ ++ if (!mtk_wcn_stp_is_ready()) { ++ WMT_DBG_FUNC("MT662x Not Ready, Dont Send Sleep/Wakeup Command\n"); ++ mtk_wcn_stp_psm_notify_stp(ROLL_BACK); ++ return 0; ++ } ++ ++ if (SLEEP == action) { ++ WMT_DBG_FUNC("send op-----------> sleep job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ ret = wmt_lib_ps_do_sleep(); ++ WMT_DBG_FUNC("enable host eirq\n"); ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_EN); ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ } else { ++ /* ret = mtk_wcn_stp_sdio_do_own_set(); */ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_SET); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ } else if (ret == -2) { ++ mtk_wcn_stp_psm_notify_stp(ROLL_BACK); ++ WMT_WARN_FUNC("===[SDIO-PS] rollback due to tx busy===%%\n"); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(SLEEP); ++ WMT_ERR_FUNC("===[SDIO-PS] set own fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<---------- sleep job\n"); ++ } else if (WAKEUP == action) { ++ WMT_DBG_FUNC("send op --------> wake job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++#if CFG_WMT_DUMP_INT_STATUS ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ ret = wmt_lib_ps_do_wakeup(); ++ } else { ++ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ ++ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_CLR); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(WAKEUP); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(WAKEUP); ++ WMT_ERR_FUNC("===[SDIO-PS] set own back fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<---------- wake job\n"); ++ } else if (HOST_AWAKE == action) { ++ WMT_DBG_FUNC("send op-----------> host awake job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++ /* IRQ already disabled */ ++ /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ ++#if 0 ++ if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) ++ wmt_plat_BGF_irq_dump_status(); ++#endif ++ ret = wmt_lib_ps_do_host_awake(); ++ } else { ++ WMT_DBG_FUNC("[SDIO-PS] SDIO host awake! ####\n"); ++ ++ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ ++ ++ if (sdio_own_ctrl) { ++ ret = (*sdio_own_ctrl) (OWN_CLR); ++ } else { ++ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); ++ ret = -1; ++ } ++ ++ /* Here we set ret to 0 directly */ ++ ret = 0; ++ if (!ret) { ++ mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); ++ } else { ++ mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); ++ WMT_ERR_FUNC("===[SDIO-PS]set own back fails!===%%\n"); ++ } ++ } ++ ++ WMT_DBG_FUNC("send op<----------- host awake job\n"); ++ } else if (EIRQ == action) { ++ WMT_DBG_FUNC("send op -------------> eirq job\n"); ++ ++ if (!mtk_wcn_stp_is_sdio_mode()) { ++ WMT_DBG_FUNC("disable host eirq\n"); ++ /* Disable interrupt */ ++ /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ ++ ret = mtk_wcn_stp_psm_notify_stp(EIRQ); ++ } else { ++ WMT_ERR_FUNC("[SDIO-PS]sdio own-back eirq!######\n"); ++ ret = mtk_wcn_stp_psm_notify_stp(EIRQ); ++ } ++ ++ WMT_DBG_FUNC("send op<----------- eirq job\n"); ++ } ++ ++ return ret; ++} ++#endif /* end of CFG_WMT_PS_SUPPORT */ ++ ++INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action) ++{ ++#if CFG_WMT_PS_SUPPORT ++ return wmt_lib_ps_handler(action); ++#else ++ WMT_WARN_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); ++ return 0; ++#endif ++} ++ ++MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID) ++{ ++ if ((g_quick_sleep_ctrl) && (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_TRUE)) ++ return wmt_core_is_quick_ps_support(); ++ else ++ return MTK_WCN_BOOL_FALSE; ++} ++ ++VOID wmt_lib_ps_irq_cb(VOID) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_handler(EIRQ); ++#else ++ WMT_DBG_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); ++ return; ++#endif ++} ++ ++VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb) ++{ ++#if CFG_WMT_PS_SUPPORT ++ sdio_own_ctrl = own_cb; ++#endif ++} ++ ++UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread) ++{ ++ P_DEV_WMT pDevWmt; ++ ++ if (pThread) { ++ pDevWmt = (P_DEV_WMT) (pThread->pThreadData); ++ return !RB_EMPTY(&pDevWmt->rActiveOpQ); ++ } ++ WMT_ERR_FUNC("pThread(NULL)\n"); ++ return 0; ++} ++ ++static INT32 wmtd_thread(void *pvData) ++{ ++ P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData; ++ P_OSAL_EVENT pEvent = NULL; ++ P_OSAL_OP pOp; ++ INT32 iResult; ++ ++ if (NULL == pWmtDev) { ++ WMT_ERR_FUNC("pWmtDev(NULL)\n"); ++ return -1; ++ } ++ WMT_INFO_FUNC("wmtd thread starts\n"); ++ ++ pEvent = &(pWmtDev->rWmtdWq); ++ ++ for (;;) { ++ pOp = NULL; ++ pEvent->timeoutValue = 0; ++/* osal_thread_wait_for_event(&pWmtDev->thread, pEvent);*/ ++ osal_thread_wait_for_event(&pWmtDev->thread, pEvent, wmt_lib_wait_event_checker); ++ ++ if (osal_thread_should_stop(&pWmtDev->thread)) { ++ WMT_INFO_FUNC("wmtd thread should stop now...\n"); ++ /* TODO: clean up active opQ */ ++ break; ++ } ++ ++ /* get Op from activeQ */ ++ pOp = wmt_lib_get_op(&pWmtDev->rActiveOpQ); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_lxop activeQ fail\n"); ++ continue; ++ } ++#if 0 /* wmt_core_opid_handler will do sanity check on opId, so no usage here */ ++ id = lxop_get_opid(pLxOp); ++ if (id >= WMT_OPID_MAX) { ++ WMT_WARN_FUNC("abnormal opid id: 0x%x\n", id); ++ iResult = -1; ++ goto handlerDone; ++ } ++#endif ++ ++ if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) { ++ /* when whole chip reset, only HW RST and SW RST cmd can execute */ ++ if ((pOp->op.opId == WMT_OPID_HW_RST) || (pOp->op.opId == WMT_OPID_SW_RST) ++ || (pOp->op.opId == WMT_OPID_GPIO_STATE)) { ++ iResult = wmt_core_opid(&pOp->op); ++ } else { ++ iResult = -2; ++ WMT_WARN_FUNC("Whole chip resetting, opid (%d) failed, iRet(%d)\n", pOp->op.opId, ++ iResult); ++ } ++ } else { ++ wmt_lib_set_current_op(pWmtDev, pOp); ++ iResult = wmt_core_opid(&pOp->op); ++ wmt_lib_set_current_op(pWmtDev, NULL); ++ } ++ ++ if (iResult) ++ WMT_WARN_FUNC("opid (%d) failed, iRet(%d)\n", pOp->op.opId, iResult); ++ ++ if (osal_op_is_wait_for_signal(pOp)) { ++ osal_op_raise_signal(pOp, iResult); ++ } else { ++ /* put Op back to freeQ */ ++ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); ++ } ++ ++ if (WMT_OPID_EXIT == pOp->op.opId) { ++ WMT_INFO_FUNC("wmtd thread received exit signal\n"); ++ break; ++ } ++ } ++ ++ WMT_INFO_FUNC("wmtd thread exits succeed\n"); ++ ++ return 0; ++}; ++ ++static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) ++{ ++ INT32 iRet; ++ ++ if (!pOpQ || !pOp) { ++ WMT_WARN_FUNC("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", pOpQ, pOp); ++ osal_assert(pOpQ); ++ osal_assert(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ iRet = osal_lock_sleepable_lock(&pOpQ->sLock); ++ if (iRet) { ++ WMT_WARN_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); ++ return MTK_WCN_BOOL_FALSE; ++ } ++#if 0 ++ if (pOpQ == &gDevWmt.rFreeOpQ) ++ WMT_INFO_FUNC("current wmt free queue count is(%d),opid(%d)\n", RB_COUNT(pOpQ), pOp->op.opId); ++#endif ++ /* acquire lock success */ ++ if (!RB_FULL(pOpQ)) ++ RB_PUT(pOpQ, pOp); ++ else ++ iRet = -1; ++ ++ osal_unlock_sleepable_lock(&pOpQ->sLock); ++ ++ if (iRet) { ++ WMT_WARN_FUNC("RB_FULL(0x%p)\n", pOpQ); ++ return MTK_WCN_BOOL_FALSE; ++ } else { ++ return MTK_WCN_BOOL_TRUE; ++ } ++} ++ ++static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ) ++{ ++ P_OSAL_OP pOp; ++ INT32 iRet; ++ ++ if (NULL == pOpQ) { ++ WMT_ERR_FUNC("pOpQ = NULL\n"); ++ osal_assert(pOpQ); ++ return NULL; ++ } ++ ++ iRet = osal_lock_sleepable_lock(&pOpQ->sLock); ++ if (iRet) { ++ WMT_ERR_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); ++ return NULL; ++ } ++ ++ /* acquire lock success */ ++ RB_GET(pOpQ, pOp); ++ osal_unlock_sleepable_lock(&pOpQ->sLock); ++ ++ if (NULL == pOp) { ++ WMT_WARN_FUNC("RB_GET return NULL\n"); ++ osal_assert(pOp); ++ } ++ ++ return pOp; ++} ++ ++INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (MTK_WCN_BOOL_FALSE == wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp)) ++ return -1; ++ else ++ return 0; ++} ++ ++P_OSAL_OP wmt_lib_get_free_op(VOID) ++{ ++ P_OSAL_OP pOp = NULL; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ ++ osal_assert(pDevWmt); ++ ++ pOp = wmt_lib_get_op(&pDevWmt->rFreeOpQ); ++ if (pOp) ++ osal_memset(&pOp->op, 0, osal_sizeof(pOp->op)); ++ return pOp; ++} ++ ++MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ MTK_WCN_BOOL bCleanup = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal = NULL; ++ long waitRet = -1; ++ P_OSAL_THREAD pThread; ++ ++ osal_assert(pWmtDev); ++ osal_assert(pOp); ++ ++ do { ++ if (!pWmtDev || !pOp) { ++ WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp); ++ break; ++ } ++ if ((0 != mtk_wcn_stp_coredump_start_get()) && ++ (WMT_OPID_HW_RST != pOp->op.opId) && ++ (WMT_OPID_SW_RST != pOp->op.opId) && (WMT_OPID_GPIO_STATE != pOp->op.opId)) { ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ WMT_WARN_FUNC("block tx flag is set\n"); ++ break; ++ } ++ pSignal = &pOp->signal; ++/* pOp->u4WaitMs = u4WaitMs; */ ++ if (pSignal->timeoutValue) { ++ pOp->result = -9; ++ osal_signal_init(pSignal); ++ } ++ ++ /* put to active Q */ ++ bRet = wmt_lib_put_op(&pWmtDev->rActiveOpQ, pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("put to active queue fail\n"); ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ break; ++ } ++ ++ /* wake up wmtd */ ++ /* wake_up_interruptible(&pWmtDev->rWmtdWq); */ ++ osal_trigger_event(&pWmtDev->rWmtdWq); ++ ++ if (0 == pSignal->timeoutValue) { ++ bRet = MTK_WCN_BOOL_TRUE; ++ /* clean it in wmtd */ ++ break; ++ } ++ /* wait result, clean it here */ ++ bCleanup = MTK_WCN_BOOL_TRUE; ++ ++ /* check result */ ++ /* wait_ret = wait_for_completion_interruptible_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ ++ /* wait_ret = wait_for_completion_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ ++ waitRet = osal_wait_for_signal_timeout(pSignal); ++ WMT_DBG_FUNC("osal_wait_for_signal_timeout:%ld\n", waitRet); ++ ++ /* if (unlikely(!wait_ret)) { */ ++ if (0 == waitRet) { ++ pThread = &gDevWmt.thread; ++ WMT_ERR_FUNC ++ ("wait completion timeout, opId(%d), show wmtd_thread stack!\n", pOp->op.opId); ++ /* TODO: how to handle it? retry? */ ++ wcn_wmtd_timeout_collect_ftrace(); /* trigger collect SYS_FTRACE */ ++ osal_thread_show_stack(pThread); ++ } else { ++ if (pOp->result) ++ WMT_WARN_FUNC("opId(%d) result:%d\n", pOp->op.opId, pOp->result); ++ } ++ /* op completes, check result */ ++ bRet = (pOp->result) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; ++ } while (0); ++ ++ if (bCleanup) { ++ /* put Op back to freeQ */ ++ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); ++ } ++ ++ return bRet; ++} ++ ++/* TODO:[ChangeFeature][George] is this function obsoleted? */ ++#if 0 ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_WMT_LXOP lxop; ++ MTK_WCN_BOOL bRet; ++ PUINT32 plv = NULL; ++ UINT32 pbuf[2]; ++ P_OSAL_EVENT pSignal = NULL; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ lxop = wmt_lib_get_free_lxop(); ++ if (!lxop) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ ++ return -1; ++ } ++ ++ plv = (PUINT32) (((UINT32) pbuf + 0x3) & ~0x3UL); ++ *plv = *pvalue; ++ pSignal = &lxop->signal; ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%d) offset(0x%x) value(0x%x) mask(0x%x)\n", isWrite, offset, *pvalue, mask); ++ ++ lxop->op.opId = WMT_OPID_REG_RW; ++ lxop->op.au4OpData[0] = isWrite; ++ lxop->op.au4OpData[1] = offset; ++ lxop->op.au4OpData[2] = (UINT32) plv; ++ lxop->op.au4OpData[3] = mask; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ DISABLE_PSM_MONITOR(); ++ bRet = wmt_lib_put_act_lxop(lxop); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, *plv, mask); ++ if (!isWrite) ++ *pvalue = *plv; ++ } else { ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, *plv, mask, bRet); ++ } ++ ++ return bRet; ++} ++#endif ++ ++/* TODO:[ChangeFeature][George] is this function obsoleted? */ ++#if 0 ++static VOID wmt_lib_clear_chip_id(VOID) ++{ ++/* ++ gDevWmt.pChipInfo = NULL; ++*/ ++ gDevWmt.hw_ver = WMTHWVER_INVALID; ++} ++#endif ++ ++/* TODO: [FixMe][GeorgeKuo]: change this API to report real chip id, hw_ver, and */ ++/* fw_ver instead of WMT-translated WMTHWVER */ ++ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver(VOID) ++{ ++/* ++ P_WMT_CMB_CHIP_INFO_S pChipInfo = NULL; ++ P_DEV_WMT pWmtDev = gpDevWmt; ++ pChipInfo = wmt_lib_get_chip_info(pWmtDev); ++ return pChipInfo != NULL ? pChipInfo->eHwVersion : WMTHWVER_INVALID; ++ */ ++ return gDevWmt.eWmtHwVer; ++} ++ ++UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T index) ++{ ++ if (WMTCHIN_CHIPID == index) ++ return gDevWmt.chip_id; ++ else if (WMTCHIN_HWVER == index) ++ return gDevWmt.hw_ver; ++ else if (WMTCHIN_MAPPINGHWVER == index) ++ return gDevWmt.eWmtHwVer; ++ else if (WMTCHIN_FWVER == index) ++ return gDevWmt.fw_ver; ++ ++ return 0; ++ ++} ++ ++PUINT8 wmt_lib_def_patch_name(VOID) ++{ ++ WMT_INFO_FUNC("wmt-lib: use default patch name (%s)\n", gDevWmt.cPatchName); ++ return gDevWmt.cPatchName; ++} ++ ++MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID) ++{ ++ MTK_WCN_BOOL bIsSupportTherm = MTK_WCN_BOOL_TRUE; ++ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ ++ if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) ++ || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { ++ WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); ++ bIsSupportTherm = MTK_WCN_BOOL_FALSE; ++ } ++ if (!mtk_wcn_stp_is_ready()) { ++ WMT_ERR_FUNC("thermal command can not be send: STP is not ready\n"); ++ bIsSupportTherm = MTK_WCN_BOOL_FALSE; ++ } ++ ++ return bIsSupportTherm; ++} ++ ++MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ ++ if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) ++ || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { ++ WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++/*! ++ * \brief Update combo chip pin settings (GPIO) ++ * ++ * An internal library function to support various settings for chip GPIO. It is ++ * updated in a grouping way: configure all required pins in a single call. ++ * ++ * \param id desired pin ID to be controlled ++ * \param stat desired pin states to be set ++ * \param flag supplementary options for this operation ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid id ++ * \retval -2 invalid stat ++ * \retval < 0 error for operation fail ++ */ ++static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /* input sanity check */ ++ if (WMT_IC_PIN_MAX <= id) { ++ WMT_ERR_FUNC("invalid ic pin id(%d)\n", id); ++ return -1; ++ } ++ if (WMT_IC_PIN_STATE_MAX <= stat) { ++ WMT_ERR_FUNC("invalid ic pin state (%d)\n", stat); ++ return -2; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_GPIO_CTRL (ic pin id:%d, stat:%d, flag:0x%x)\n", id, stat, flag); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_GPIO_CTRL; ++ pOp->op.au4OpData[0] = id; ++ pOp->op.au4OpData[1] = stat; ++ pOp->op.au4OpData[2] = flag; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("PIN_ID(%d) PIN_STATE(%d) flag(%d) fail\n", id, stat, flag); ++ else ++ WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return 0; ++} ++ ++INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 value; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ value = *pvalue; ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", isWrite, offset, *pvalue, mask); ++ pOp->op.opId = WMT_OPID_REG_RW; ++ pOp->op.au4OpData[0] = isWrite; ++ pOp->op.au4OpData[1] = offset; ++ pOp->op.au4OpData[2] = (SIZE_T)&value; ++ pOp->op.au4OpData[3] = mask; ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, value, mask); ++ if (!isWrite) ++ *pvalue = value; ++ ++ return 0; ++ } ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, value, mask, bRet); ++ return -1; ++} ++ ++INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 value; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (!pvalue) { ++ WMT_WARN_FUNC("!pvalue\n"); ++ return -1; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ value = *pvalue; ++ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", ++ isWrite, offset, *pvalue, mask); ++ pOp->op.opId = WMT_OPID_EFUSE_RW; ++ pOp->op.au4OpData[0] = isWrite; ++ pOp->op.au4OpData[1] = offset; ++ pOp->op.au4OpData[2] = (SIZE_T)&value; ++ pOp->op.au4OpData[3] = mask; ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE != bRet) { ++ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", ++ isWrite, offset, value, mask); ++ if (!isWrite) ++ *pvalue = value; ++ ++ return 0; ++ } ++ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", ++ isWrite, offset, value, mask, bRet); ++ return -1; ++ ++} ++ ++/*! ++ * \brief update combo chip AUDIO Interface (AIF) settings ++ * ++ * A library function to support updating chip AUDIO pin settings. A group of ++ * pins is updated as a whole. ++ * ++ * \param aif desired audio interface state to use ++ * \param flag whether audio pin is shared or not ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid aif ++ * \retval < 0 error for invalid parameters or operation fail ++ */ ++INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share) ++{ ++ if (CMB_STUB_AIF_MAX <= aif) { ++ WMT_ERR_FUNC("invalid aif (%d)\n", aif); ++ return -1; ++ } ++ WMT_DBG_FUNC("call pin_ctrl for aif:%d, share:%d\n", aif, (MTK_WCN_BOOL_TRUE == share) ? 1 : 0); ++ /* Translate CMB_STUB_AIF_X into WMT_IC_PIN_STATE by array */ ++ return wmt_lib_pin_ctrl(WMT_IC_PIN_AUDIO, ++ cmb_aif2pin_stat[aif], ++ (MTK_WCN_BOOL_TRUE == share) ? WMT_LIB_AIF_FLAG_SHARE : WMT_LIB_AIF_FLAG_SEPARATE); ++} ++ ++INT32 wmt_lib_host_awake_get(VOID) ++{ ++ return wmt_plat_wake_lock_ctrl(WL_OP_GET); ++} ++ ++INT32 wmt_lib_host_awake_put(VOID) ++{ ++ return wmt_plat_wake_lock_ctrl(WL_OP_PUT); ++} ++ ++MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (op == BTM_RST_OP) { ++ /* high priority, not to enqueue into the queue of wmtd */ ++ WMT_INFO_FUNC("Invoke whole chip reset from stp_btm!!!\n"); ++ wmt_lib_cmb_rst(WMTRSTSRC_RESET_STP); ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else if (op == BTM_DMP_OP) { ++ ++ WMT_WARN_FUNC("TBD!!!\n"); ++ } else if (op == BTM_GET_AEE_SUPPORT_FLAG) { ++ bRet = wmt_core_get_aee_dump_flag(); ++ } ++ return bRet; ++} ++ ++MTK_WCN_BOOL wmt_cdev_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg) ++{ ++ ++ INT32 i = 0; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ PUINT8 drv_name[] = { ++ "DRV_TYPE_BT", ++ "DRV_TYPE_FM", ++ "DRV_TYPE_GPS", ++ "DRV_TYPE_WIFI" ++ }; ++ ++ for (i = 0; i <= WMTDRV_TYPE_WIFI; i++) { ++ /* <1> check if reset callback is registered */ ++ if (pDevWmt->rFdrvCb.fDrvRst[i]) { ++ /* <2> send the msg to this subfucntion */ ++ /*src, dst, msg_type, msg_data, msg_size */ ++ pDevWmt->rFdrvCb.fDrvRst[i] (WMTDRV_TYPE_WMT, i, WMTMSG_TYPE_RESET, &msg, ++ sizeof(ENUM_WMTRSTMSG_TYPE_T)); ++ WMT_INFO_FUNC("type = %s, msg sent\n", drv_name[i]); ++ } else { ++ WMT_DBG_FUNC("type = %s, unregistered\n", drv_name[i]); ++ } ++ } ++ ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++VOID wmt_lib_state_init(VOID) ++{ ++ /* UINT32 i = 0; */ ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ P_OSAL_OP pOp; ++ ++ /* Initialize op queue */ ++ /* RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); */ ++ /* RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); */ ++ ++ while (!RB_EMPTY(&pDevWmt->rActiveOpQ)) { ++#if 0 ++ osal_signal_init(&(pOp->signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); ++#endif ++ pOp = wmt_lib_get_op(&pDevWmt->rActiveOpQ); ++ if (pOp) { ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, -1); ++ else ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); ++ } ++ } ++ ++ /* Put all to free Q */ ++ /* ++ for (i = 0; i < WMT_OP_BUF_SIZE; i++) { ++ osal_signal_init(&(pDevWmt->arQue[i].signal)); ++ wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); ++ } */ ++} ++ ++#if 0 ++INT32 wmt_lib_sdio_ctrl(UINT32 on) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_SDIO_CTRL\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_SDIO_CTRL; ++ pOp->op.au4OpData[0] = on; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_SDIO_CTRL failed\n"); ++ return -1; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_SDIO_CTRL)ok\n"); ++ ++ return 0; ++} ++#endif ++ ++MTK_WCN_BOOL wmt_lib_hw_state_show(VOID) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_HW_STATE_SHOW\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_GPIO_STATE; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_HW_STATE_SHOW failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_HW_STATE_SHOW)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++MTK_WCN_BOOL wmt_lib_hw_rst(VOID) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ ++ wmt_lib_state_init(); ++ ++ osal_clear_bit(WMT_STAT_STP_REG, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_OPEN, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_EN, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_STP_RDY, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_RX, &pDevWmt->state); ++ osal_clear_bit(WMT_STAT_CMD, &pDevWmt->state); ++ ++ /*Before do hardware reset, we show GPIO state to check if others modified our pin state accidentially */ ++ wmt_lib_hw_state_show(); ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_HW_RST\n"); ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_HW_RST; ++ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_HW_RST failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_HW_RST)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst) ++{ ++ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /* <1> wmt state reset */ ++ wmt_lib_state_init(); ++ ++ /* <2> Reset STP data structure */ ++ WMT_DBG_FUNC("Cleanup STP context\n"); ++ mtk_wcn_stp_flush_context(); ++ /* <3> Reset STP-PSM data structure */ ++ WMT_DBG_FUNC("Cleanup STP-PSM context\n"); ++ mtk_wcn_stp_psm_reset(); ++ ++ /* <4> do sw reset in wmt-core */ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ WMT_DBG_FUNC("call WMT_OPID_SW_RST\n"); ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = MAX_FUNC_ON_TIME; ++ ++ pOp->op.opId = WMT_OPID_SW_RST; ++ pOp->op.au4OpData[0] = baudRst; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("WMT_OPID_SW_RST failed\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_DBG_FUNC("OPID(WMT_OPID_SW_RST)ok\n"); ++ return MTK_WCN_BOOL_TRUE; ++} ++ ++ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src) ++{ ++#define RETRYTIMES 10 ++ MTK_WCN_BOOL bRet; ++ ENUM_WMTRSTRET_TYPE_T retval = WMTRSTRET_MAX; ++ ENUM_WMTRSTMSG_TYPE_T rstMsg = WMTRSTMSG_RESET_MAX; ++ INT32 retries = RETRYTIMES; ++ P_DEV_WMT pDevWmt = &gDevWmt; ++ P_OSAL_OP pOp; ++ PUINT8 srcName[] = { "WMTRSTSRC_RESET_BT", ++ "WMTRSTSRC_RESET_FM", ++ "WMTRSTSRC_RESET_GPS", ++ "WMTRSTSRC_RESET_WIFI", ++ "WMTRSTSRC_RESET_STP", ++ "WMTRSTSRC_RESET_TEST" ++ }; ++ ++ if (src < WMTRSTSRC_RESET_MAX) ++ WMT_INFO_FUNC("reset source = %s\n", srcName[src]); ++ ++ if (WMTRSTSRC_RESET_TEST == src) { ++ pOp = wmt_lib_get_current_op(pDevWmt); ++ if (pOp && ((WMT_OPID_FUNC_ON == pOp->op.opId) ++ || (WMT_OPID_FUNC_OFF == pOp->op.opId))) { ++ WMT_INFO_FUNC("can't do reset by test src when func on/off\n"); ++ return -1; ++ } ++ } ++ /* <1> Consider the multi-context combo_rst case. */ ++ if (osal_test_and_set_bit(WMT_STAT_RST_ON, &pDevWmt->state)) { ++ retval = WMTRSTRET_ONGOING; ++ goto rstDone; ++ } ++ /* <2> Block all STP request */ ++ mtk_wcn_stp_enable(0); ++ ++ /* <3> RESET_START notification */ ++ bRet = wmt_cdev_rstmsg_snd(WMTRSTMSG_RESET_START); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); ++ retval = WMTRSTRET_FAIL; ++ goto rstDone; ++ } ++ /* wakeup blocked opid */ ++ pOp = wmt_lib_get_current_op(pDevWmt); ++ if (osal_op_is_wait_for_signal(pOp)) ++ osal_op_raise_signal(pOp, -1); ++ ++ /* wakeup blocked cmd */ ++ wmt_dev_rx_event_cb(); ++ ++ /* <4> retry until reset flow successful */ ++ while (retries > 0) { ++ /* <4.1> reset combo hw */ ++ bRet = wmt_lib_hw_rst(); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_hw_rst!\n"); ++ retries--; ++ continue; ++ } ++ /* <4.2> reset driver/combo sw */ ++ bRet = wmt_lib_sw_rst(1); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_sw_rst!\n"); ++ retries--; ++ continue; ++ } ++ break; ++ } ++ ++ osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state); ++ ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ rstMsg = WMTRSTMSG_RESET_END_FAIL; ++ WMT_WARN_FUNC("[whole chip reset] fail! retries = %d\n", RETRYTIMES - retries); ++ } else { ++ rstMsg = WMTRSTMSG_RESET_END; ++ WMT_INFO_FUNC("[whole chip reset] ok! retries = %d\n", RETRYTIMES - retries); ++ } ++ ++ /* <5> RESET_END notification */ ++ bRet = wmt_cdev_rstmsg_snd(rstMsg); ++ if (bRet == MTK_WCN_BOOL_FALSE) { ++ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); ++ retval = WMTRSTRET_FAIL; ++ } else { ++ retval = WMTRSTMSG_RESET_END == rstMsg ? WMTRSTRET_SUCCESS : WMTRSTRET_FAIL; ++ } ++ mtk_wcn_stp_coredump_start_ctrl(0); ++ mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); ++rstDone: ++ if (osal_test_and_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state)) ++ WMT_WARN_FUNC("[whole chip reset] retval = %d\n", retval); ++ ++ return retval; ++} ++ ++MTK_WCN_BOOL wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++{ ++ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { ++ WMT_DBG_FUNC("reg ok!\n"); ++ pWmtDev->rFdrvCb.fDrvRst[eType] = pCb; ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else { ++ WMT_WARN_FUNC("reg fail!\n"); ++ } ++ ++ return bRet; ++} ++ ++MTK_WCN_BOOL wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++{ ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { ++ WMT_DBG_FUNC("unreg ok!\n"); ++ pWmtDev->rFdrvCb.fDrvRst[eType] = NULL; ++ bRet = MTK_WCN_BOOL_TRUE; ++ } else { ++ WMT_WARN_FUNC("unreg fail!\n"); ++ } ++ ++ return bRet; ++} ++ ++UINT32 wmt_lib_dbg_level_set(UINT32 level) ++{ ++ gWmtDbgLvl = level > WMT_LOG_LOUD ? WMT_LOG_LOUD : level; ++ return 0; ++} ++ ++INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value) ++{ ++ return mtk_wcn_stp_set_wmt_last_close(value); ++} ++ ++INT32 wmt_lib_notify_stp_sleep(void) ++{ ++ INT32 iRet = 0x0; ++ ++ iRet = wmt_lib_psm_lock_aquire(); ++ if (iRet) { ++ WMT_ERR_FUNC("--->lock psm_lock failed, iRet=%d\n", iRet); ++ return iRet; ++ } ++ ++ iRet = mtk_wcn_stp_notify_sleep_for_thermal(); ++ wmt_lib_psm_lock_release(); ++ ++ return iRet; ++} ++ ++VOID wmt_lib_set_patch_num(UINT32 num) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ pWmtDev->patchNum = num; ++} ++ ++VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo) ++{ ++ P_DEV_WMT pWmtDev = &gDevWmt; ++ ++ if (pPatchinfo) ++ pWmtDev->pWmtPatchInfo = pPatchinfo; ++ ++} ++ ++INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp) ++{ ++ if (pWmtDev) { ++ pWmtDev->pCurOP = pOp; ++ WMT_DBG_FUNC("pOp=0x%p\n", pOp); ++ return 0; ++ } ++ WMT_ERR_FUNC("Invalid pointer\n"); ++ return -1; ++} ++ ++P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev) ++{ ++ if (pWmtDev) ++ return pWmtDev->pCurOP; ++ ++ WMT_ERR_FUNC("Invalid pointer\n"); ++ return NULL; ++} ++ ++UINT8 *wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, UINT8 *buf, UINT32 len) ++{ ++ UINT8 *pAddr = NULL; ++ UINT32 sublen1 = 0; ++ UINT32 sublen2 = 0; ++ P_CONSYS_EMI_ADDR_INFO p_consys_info; ++ ++ p_consys_info = wmt_plat_get_emi_phy_add(); ++ osal_assert(p_consys_info); ++ ++ if (section == 0) { ++ pAddr = wmt_plat_get_emi_virt_add(0x0); ++ if (len > 1024) ++ len = 1024; ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); ++ osal_memcpy(&buf[0], pAddr, len); ++ } ++ } else { ++ if (offset >= 0x7fff) ++ offset = 0x0; ++ ++ if (offset + len > 32768) { ++ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get part1 EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("part1 vir addr(0x%p)\n", pAddr); ++ sublen1 = 0x7fff - offset; ++ osal_memcpy(&buf[0], pAddr, sublen1); ++ } ++ pAddr = wmt_plat_get_emi_virt_add(p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get part2 EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("part2 vir addr(0x%p)\n", pAddr); ++ sublen2 = len - sublen1; ++ osal_memcpy(&buf[sublen1], pAddr, sublen2); ++ } ++ } else { ++ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); ++ if (!pAddr) { ++ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); ++ } else { ++ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); ++ osal_memcpy(&buf[0], pAddr, len); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee) ++{ ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ ++ issue_type = STP_DBG_PROC_TEST; ++ ++ stp_dbg_poll_cpupcr(count, sleep, 1); ++ ++ if (toAee) { ++ stp_dbg_set_fw_info("STP ProcTest", osal_strlen("STP ProcTest"), issue_type); ++ osal_dbg_assert_aee("[SOC_CONSYS]ProcTest", ++ "**[WCN_ISSUE_INFO]STP Tx Timeout**\n Polling CPUPCR for FW debug usage\n"); ++ } else { ++ WMT_INFO_FUNC("wmt_lib:do not pass cpupcr to AEE\n"); ++ } ++ return 0; ++} ++ ++UINT8 *wmt_lib_get_cpupcr_xml_format(UINT32 *len) ++{ ++ PUINT8 temp; ++ UINT32 i = 0; ++ ++ osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE); ++ temp = g_cpupcr_buf; ++ stp_dbg_cpupcr_infor_format(&temp, len); ++ ++ pr_debug("print xml buffer,len(%d):\n\n", *len); ++ for (i = 0; i < *len; i++) ++ pr_cont("%c", g_cpupcr_buf[i]); ++ ++ return &g_cpupcr_buf[0]; ++} ++ ++UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en) ++{ ++ return stp_dbg_set_host_assert_info(type, reason, en); ++} ++ ++INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl) ++{ ++ wmt_plat_thermal_ctrl_cb_reg(thermal_ctrl); ++ return 0; ++} ++ ++INT8 wmt_lib_co_clock_get(void) ++{ ++ if (gDevWmt.rWmtGenConf.cfgExist) ++ return gDevWmt.rWmtGenConf.co_clock_flag; ++ else ++ return -1; ++} ++ ++#if CFG_WMT_PS_SUPPORT ++UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en) ++{ ++ WMT_WARN_FUNC("%s quick sleep mode\n", en ? "enable" : "disable"); ++ g_quick_sleep_ctrl = en; ++ return 0; ++} ++#endif ++ ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_lib_jtag_flag_set(UINT32 en) ++{ ++ return wmt_plat_jtag_flag_ctrl(en); ++} ++#endif ++ ++UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver) ++{ ++ return stp_dbg_set_wifiver(wifiver); ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h +new file mode 100644 +index 000000000000..b1b5285638f9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h +@@ -0,0 +1,252 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _STP_EXP_H_ ++#define _STP_EXP_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_stp_exp.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++#define BT_TASK_INDX (0) ++#define FM_TASK_INDX (1) ++#define GPS_TASK_INDX (2) ++#define WIFI_TASK_INDX (3) ++#define WMT_TASK_INDX (4) ++#define STP_TASK_INDX (5) ++#define INFO_TASK_INDX (6) ++#define ANT_TASK_INDX (7) ++#if CFG_WMT_LTE_COEX_HANDLING ++#define COEX_TASK_INDX (8) ++#define MTKSTP_MAX_TASK_NUM (9) ++#else ++#define MTKSTP_MAX_TASK_NUM (8) ++#endif ++ ++#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ ++ ++#define STP_EXP_HID_API_EXPORT 0 ++ ++#else ++ ++#define STP_EXP_HID_API_EXPORT 1 ++ ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++typedef void (*MTK_WCN_STP_EVENT_CB) (void); ++typedef INT32 (*MTK_WCN_STP_IF_TX) (const UINT8 *data, const UINT32 size, UINT32 *written_size); ++/* export for HIF driver */ ++typedef void (*MTK_WCN_STP_IF_RX) (const UINT8 *data, INT32 size); ++ ++typedef enum { ++ STP_UART_IF_TX = 0, ++ STP_SDIO_IF_TX = 1, ++ STP_BTIF_IF_TX = 2, ++ STP_MAX_IF_TX ++} ENUM_STP_TX_IF_TYPE; ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_receive_data ++* DESCRIPTION ++* receive data from serial protocol engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* INT32 >= 0: size of data received; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_send_data ++* DESCRIPTION ++* subfunction send data through STP ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* type [IN] subfunction type ++* RETURNS ++* INT32 >= 0: length transmitted; < 0: error ++*****************************************************************************/ ++extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_rxqueue_empty ++* DESCRIPTION ++* Is certain rx queue empty? ++* PARAMETERS ++* type [IN] subfunction type ++* RETURNS ++* INT32 0: queue is NOT empyt; !0: queue is empty ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_is_enable ++* DESCRIPTION ++* Is STP ready? ++* PARAMETERS ++* none. ++* RETURNS ++* MTK_WCN_BOOL TRUE:ready, FALSE:not ready ++*****************************************************************************/ ++extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_parser_data ++* DESCRIPTION ++* push data to serial transport protocol parser engine ++* PARAMETERS ++* buffer [IN] data buffer ++* length [IN] data buffer length ++* RETURNS ++* void ++*****************************************************************************/ ++extern int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); ++ ++/***************************************************************************** ++* FUNCTION ++* set_bluetooth_rx_interface ++* DESCRIPTION ++* Set bluetooth rx interface ++* PARAMETERS ++* rx interface type ++* RETURNS ++* void ++*****************************************************************************/ ++extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_tx_event_cb ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_tx_event_cb(int type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_event_cb ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* func ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_event_cb(int type, MTK_WCN_STP_EVENT_CB func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_tx ++* DESCRIPTION ++* regiter Tx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++ ++/***************************************************************************** ++* FUNCTION ++* mtk_wcn_stp_register_if_rx ++* DESCRIPTION ++* regiter Rx event callback function ++* PARAMETERS ++* stp_if: SDIO or UART, fnnc: Call back function ++* RETURNS ++* int: 0:successful , -1: fail ++*****************************************************************************/ ++extern int mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#else ++extern INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); ++extern INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++extern INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); ++extern MTK_WCN_BOOL _mtk_wcn_stp_is_rxqueue_empty(UINT8 type); ++extern MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void); ++extern INT32 _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); ++extern void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); ++extern INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++extern INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); ++extern INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); ++extern INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); ++extern INT32 _mtk_wcn_stp_coredump_start_get(VOID); ++ ++#endif ++ ++#endif /* _WMT_EXP_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h +new file mode 100644 +index 000000000000..6d10c3ff2659 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h +@@ -0,0 +1,19 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _MTKWMT_H_ ++#define _MTKWMT_H_ ++#include "wmt_core.h" ++ ++#endif /*_MTKWMT_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h +new file mode 100644 +index 000000000000..06238e07879f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h +@@ -0,0 +1,329 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_EXP_H_ ++#define _WMT_EXP_H_ ++ ++#include ++#include "osal.h" ++#include "wmt_plat.h" ++#include "wmt_stp_exp.h" ++/* not to reference to internal wmt */ ++/* #include "wmt_core.h" */ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++#ifndef DFT_TAG ++#define DFT_TAG "[WMT-DFT]" ++#endif ++ ++#define WMT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_LOUD) \ ++ osal_dbg_print(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_INFO) \ ++ osal_dbg_print(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_WARN) \ ++ osal_warn_print(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_ERR) \ ++ osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_DBG) \ ++ osal_dbg_print(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_TRC_FUNC(f) \ ++do { \ ++ if (gWmtDbgLvl >= WMT_LOG_DBG) \ ++ osal_dbg_print(DFT_TAG "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++extern UINT32 gWmtDbgLvl; ++#endif ++extern OSAL_BIT_OP_VAR gBtWifiGpsState; ++extern OSAL_BIT_OP_VAR gGpsFmState; ++extern UINT32 gWifiProbed; ++extern MTK_WCN_BOOL g_pwr_off_flag; ++extern UINT32 g_IsNeedDoChipReset; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#if 1 /* moved from wmt_lib.h */ ++#define WMT_LOG_LOUD 4 ++#define WMT_LOG_DBG 3 ++#define WMT_LOG_INFO 2 ++#define WMT_LOG_WARN 1 ++#define WMT_LOG_ERR 0 ++#endif ++#define CFG_CORE_INTERNAL_TXRX 0 /*just do TX/RX in host side */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_STP = 5, ++ WMTDRV_TYPE_LPBK = 6, ++ WMTDRV_TYPE_COREDUMP = 7, ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++/* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ ++/* TODO: how do we extend for new chip and newer revision? */ ++/* TODO: This way is hard to extend */ ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_E1 = 0x0, ++ WMTHWVER_E2 = 0x1, ++ WMTHWVER_E3 = 0x2, ++ WMTHWVER_E4 = 0x3, ++ WMTHWVER_E5 = 0x4, ++ WMTHWVER_E6 = 0x5, ++ WMTHWVER_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++ ++typedef enum _ENUM_WMTDSNS_TYPE_T { ++ WMTDSNS_FM_DISABLE = 0, ++ WMTDSNS_FM_ENABLE = 1, ++ WMTDSNS_FM_GPS_DISABLE = 2, ++ WMTDSNS_FM_GPS_ENABLE = 3, ++ WMTDSNS_MAX ++} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; ++ ++typedef enum _ENUM_WMTTHERM_TYPE_T { ++ WMTTHERM_ZERO = 0, ++ WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, ++ WMTTHERM_READ = WMTTHERM_ENABLE + 1, ++ WMTTHERM_DISABLE = WMTTHERM_READ + 1, ++ WMTTHERM_MAX ++} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ UINT32 /* Buffer size in unit of byte */ ++); ++ ++typedef enum _SDIO_PS_OP { ++ OWN_SET = 0, ++ OWN_CLR = 1, ++ OWN_STATE = 2, ++} SDIO_PS_OP; ++ ++typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); ++ ++typedef enum _ENUM_WMTCHIN_TYPE_T { ++ WMTCHIN_CHIPID = 0x0, ++ WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, ++ WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, ++ WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, ++ WMTCHIN_MAX, ++ ++} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; ++ ++#endif ++ ++typedef enum _ENUM_WMTRSTMSG_TYPE_T { ++ WMTRSTMSG_RESET_START = 0x0, ++ WMTRSTMSG_RESET_END = 0x1, ++ WMTRSTMSG_RESET_END_FAIL = 0x2, ++ WMTRSTMSG_RESET_MAX, ++ WMTRSTMSG_RESET_INVALID = 0xff ++} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; ++ ++typedef enum _ENUM_BT_GPS_ONOFF_STATE_T { ++ WMT_BT_ON = 0, ++ WMT_GPS_ON = 1, ++ WMT_WIFI_ON = 2, ++ WMT_FM_ON = 3, ++ WMT_BT_GPS_STATE_MAX, ++ WMT_BT_GPS_STATE_INVALID = 0xff ++} ENUM_BT_GPS_ONOFF_STATE_T, *P_ENUM_BT_GPS_ONOFF_STATE_T; ++ ++#if 1 /* moved from wmt_core.h */ ++typedef enum { ++ WMT_SDIO_SLOT_INVALID = 0, ++ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ ++ WMT_SDIO_SLOT_SDIO2 = 2, ++ WMT_SDIO_SLOT_MAX ++} WMT_SDIO_SLOT_NUM; ++ ++typedef enum { ++ WMT_SDIO_FUNC_STP = 0, ++ WMT_SDIO_FUNC_WIFI = 1, ++ WMT_SDIO_FUNC_MAX ++} WMT_SDIO_FUNC_TYPE; ++#endif ++ ++typedef INT32(*wmt_wlan_probe_cb) (VOID); ++typedef INT32(*wmt_wlan_remove_cb) (VOID); ++typedef INT32(*wmt_wlan_bus_cnt_get_cb) (VOID); ++typedef INT32(*wmt_wlan_bus_cnt_clr_cb) (VOID); ++ ++typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { ++ wmt_wlan_probe_cb wlan_probe_cb; ++ wmt_wlan_remove_cb wlan_remove_cb; ++ wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; ++ wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; ++} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++typedef enum _ENUM_WMT_ANT_RAM_CTRL_T { ++ WMT_ANT_RAM_GET_STATUS = 0, ++ WMT_ANT_RAM_DOWNLOAD = WMT_ANT_RAM_GET_STATUS + 1, ++ WMT_ANT_RAM_CTRL_MAX ++} ENUM_WMT_ANT_RAM_CTRL, *P_ENUM_WMT_ANT_RAM_CTRL; ++ ++typedef enum _ENUM_WMT_ANT_RAM_SEQ_T { ++ WMT_ANT_RAM_START_PKT = 1, ++ WMT_ANT_RAM_CONTINUE_PKT = WMT_ANT_RAM_START_PKT + 1, ++ WMT_ANT_RAM_END_PKT = WMT_ANT_RAM_CONTINUE_PKT + 1, ++ WMT_ANT_RAM_SEQ_MAX ++} ENUM_WMT_ANT_RAM_SEQ, *P_ENUM_WMT_ANT_RAM_SEQ; ++ ++typedef enum _ENUM_WMT_ANT_RAM_STATUS_T { ++ WMT_ANT_RAM_NOT_EXIST = 0, ++ WMT_ANT_RAM_EXIST = WMT_ANT_RAM_NOT_EXIST + 1, ++ WMT_ANT_RAM_DOWN_OK = WMT_ANT_RAM_EXIST + 1, ++ WMT_ANT_RAM_DOWN_FAIL = WMT_ANT_RAM_DOWN_OK + 1, ++ WMT_ANT_RAM_PARA_ERR = WMT_ANT_RAM_DOWN_FAIL + 1, ++ WMT_ANT_RAM_OP_ERR = WMT_ANT_RAM_PARA_ERR + 1, ++ WMT_ANT_RAM_MAX ++} ENUM_WMT_ANT_RAM_STATUS, *P_ENUM_WMT_ANT_RAM_STATUS; ++#endif ++ ++extern INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); ++extern INT32 mtk_wcn_wmt_wlan_unreg(VOID); ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern wmt_wlan_probe_cb mtk_wcn_wlan_probe; ++extern wmt_wlan_remove_cb mtk_wcn_wlan_remove; ++extern wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt; ++extern wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*subsystem function ctrl APIs*/ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++#define WMT_EXP_HID_API_EXPORT 0 ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); ++ ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++ ++extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++ ++extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++ ++extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); ++ ++extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); ++/* ++return value: ++enable/disable thermal sensor function: true(1)/false(0) ++read thermal sensor function: thermal value ++ ++*/ ++extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); ++ ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++ ++#else ++#define WMT_EXP_HID_API_EXPORT 1 ++#endif ++ ++#ifdef CONFIG_MTK_COMBO_ANT ++extern ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, ++ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq); ++#endif ++extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ ++extern VOID wmt_lib_ps_irq_cb(VOID); ++ ++extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type); ++ ++extern INT32 mtk_wcn_wmt_system_state_reset(VOID); ++extern MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value); ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++extern VOID mtk_wcn_wmt_exp_init(VOID); ++extern VOID mtk_wcn_wmt_exp_deinit(VOID); ++#endif ++extern INT8 mtk_wcn_wmt_co_clock_flag_get(VOID); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_EXP_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h +new file mode 100644 +index 000000000000..075496cac54f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h +@@ -0,0 +1,295 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _WMT_PLAT_H_ ++#define _WMT_PLAT_H_ ++#include "osal_typedef.h" ++#include "stp_exp.h" ++#include ++ ++/* #include "mtk_wcn_consys_hw.h" */ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if 1 /* moved from wmt_exp.h */ ++#ifndef DFT_TAG ++#define DFT_TAG "[WMT-DFT]" ++#endif ++ ++#define WMT_PLAT_LOG_LOUD 4 ++#define WMT_PLAT_LOG_DBG 3 ++#define WMT_PLAT_LOG_INFO 2 ++#define WMT_PLAT_LOG_WARN 1 ++#define WMT_PLAT_LOG_ERR 0 ++ ++extern UINT32 wmtPlatLogLvl; ++ ++#define WMT_PLAT_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_LOUD) \ ++ pr_debug(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_INFO) \ ++ pr_debug(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_WARN) \ ++ pr_warn(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++#define WMT_PLAT_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_ERR) \ ++ pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ ++} while (0) ++#define WMT_PLAT_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (wmtPlatLogLvl >= WMT_PLAT_LOG_DBG) \ ++ pr_debug(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ ++} while (0) ++ ++#endif ++ ++#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_exp.h */ ++ ++#define CFG_WMT_DUMP_INT_STATUS 0 ++#define CONSYS_ENALBE_SET_JTAG 1 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_FUNC_STATE_ { ++ FUNC_ON = 0, ++ FUNC_OFF = 1, ++ FUNC_RST = 2, ++ FUNC_STAT = 3, ++ FUNC_CTRL_MAX, ++} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE; ++ ++typedef enum _ENUM_PIN_ID_ { ++ PIN_BGF_EINT = 0, ++ PIN_I2S_GRP = 1, ++ PIN_GPS_SYNC = 2, ++ PIN_GPS_LNA = 3, ++#if CFG_WMT_LTE_COEX_HANDLING ++ PIN_TDM_REQ = 4, ++#endif ++ PIN_ID_MAX ++} ENUM_PIN_ID, *P_ENUM_PIN_ID; ++ ++typedef enum _ENUM_PIN_STATE_ { ++ PIN_STA_INIT = 0, ++ PIN_STA_OUT_L = 1, ++ PIN_STA_OUT_H = 2, ++ PIN_STA_IN_L = 3, ++ PIN_STA_MUX = 4, ++ PIN_STA_EINT_EN = 5, ++ PIN_STA_EINT_DIS = 6, ++ PIN_STA_DEINIT = 7, ++ PIN_STA_SHOW = 8, ++ PIN_STA_MAX ++} ENUM_PIN_STATE, *P_ENUM_PIN_STATE; ++ ++typedef enum _CMB_IF_TYPE_ { ++ CMB_IF_UART = 0, ++ CMB_IF_WIFI_SDIO = 1, ++ CMB_IF_BGF_SDIO = 2, ++ CMB_IF_BGWF_SDIO = 3, ++ CMB_IF_TYPE_MAX ++} CMB_IF_TYPE, *P_CMB_IF_TYPE; ++ ++typedef INT32(*fp_set_pin) (ENUM_PIN_STATE); ++ ++typedef enum _ENUM_WL_OP_ { ++ WL_OP_GET = 0, ++ WL_OP_PUT = 1, ++ WL_OP_MAX ++} ENUM_WL_OP, *P_ENUM_WL_OP; ++ ++typedef enum _ENUM_PALDO_TYPE_ { ++ BT_PALDO = 0, ++ WIFI_PALDO = 1, ++ FM_PALDO = 2, ++ GPS_PALDO = 3, ++ PMIC_CHIPID_PALDO = 4, ++ WIFI_5G_PALDO = 5, ++ PALDO_TYPE_MAX ++} ENUM_PALDO_TYPE, *P_ENUM_PALDO_TYPE; ++ ++typedef enum _ENUM_PALDO_OP_ { ++ PALDO_OFF = 0, ++ PALDO_ON = 1, ++ PALDO_OP_MAX ++} ENUM_PALDO_OP, *P_ENUM_PALDO_OP; ++ ++typedef enum _ENUM_HOST_DUMP_STATE_T { ++ STP_HOST_DUMP_NOT_START = 0, ++ STP_HOST_DUMP_GET = 1, ++ STP_HOST_DUMP_GET_DONE = 2, ++ STP_HOST_DUMP_END = 3, ++ STP_HOST_DUMP_MAX ++} ENUM_HOST_DUMP_STATE, *P_ENUM_HOST_DUMP_STATE_T; ++ ++typedef enum _ENUM_FORCE_TRG_ASSERT_T { ++ STP_FORCE_TRG_ASSERT_EMI = 0, ++ STP_FORCE_TRG_ASSERT_DEBUG_PIN = 1, ++ STP_FORCE_TRG_ASSERT_MAX = 2 ++} ENUM_FORCE_TRG_ASSERT_T, *P_ENUM_FORCE_TRG_ASSERT_T; ++ ++typedef enum _ENUM_CHIP_DUMP_STATE_T { ++ STP_CHIP_DUMP_NOT_START = 0, ++ STP_CHIP_DUMP_PUT = 1, ++ STP_CHIP_DUMP_PUT_DONE = 2, ++ STP_CHIP_DUMP_END = 3, ++ STP_CHIP_DUMP_MAX ++} ENUM_CHIP_DUMP_STATE, *P_ENUM_CHIP_DUMP_STATE_T; ++ ++typedef struct _EMI_CTRL_STATE_OFFSET_ { ++ UINT32 emi_apmem_ctrl_state; ++ UINT32 emi_apmem_ctrl_host_sync_state; ++ UINT32 emi_apmem_ctrl_host_sync_num; ++ UINT32 emi_apmem_ctrl_chip_sync_state; ++ UINT32 emi_apmem_ctrl_chip_sync_num; ++ UINT32 emi_apmem_ctrl_chip_sync_addr; ++ UINT32 emi_apmem_ctrl_chip_sync_len; ++ UINT32 emi_apmem_ctrl_chip_print_buff_start; ++ UINT32 emi_apmem_ctrl_chip_print_buff_len; ++ UINT32 emi_apmem_ctrl_chip_print_buff_idx; ++ UINT32 emi_apmem_ctrl_chip_int_status; ++ UINT32 emi_apmem_ctrl_chip_paded_dump_end; ++ UINT32 emi_apmem_ctrl_host_outband_assert_w1; ++ UINT32 emi_apmem_ctrl_chip_page_dump_num; ++} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET; ++ ++typedef struct _BGF_IRQ_BALANCE_ { ++ UINT32 counter; ++ unsigned long flags; ++ spinlock_t lock; ++} BGF_IRQ_BALANCE, *P_BGF_IRQ_BALANCE; ++ ++typedef struct _CONSYS_EMI_ADDR_INFO_ { ++ UINT32 emi_phy_addr; ++ UINT32 paged_trace_off; ++ UINT32 paged_dump_off; ++ UINT32 full_dump_off; ++ P_EMI_CTRL_STATE_OFFSET p_ecso; ++} CONSYS_EMI_ADDR_INFO, *P_CONSYS_EMI_ADDR_INFO; ++ ++typedef struct _GPIO_TDM_REQ_INFO_ { ++ UINT32 ant_sel_index; ++ UINT32 gpio_number; ++ UINT32 cr_address; ++} GPIO_TDM_REQ_INFO, *P_GPIO_TDM_REQ_INFO; ++ ++typedef VOID(*irq_cb) (VOID); ++typedef INT32(*device_audio_if_cb) (CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); ++typedef VOID(*func_ctrl_cb) (UINT32 on, UINT32 type); ++typedef long (*thermal_query_ctrl_cb) (VOID); ++typedef INT32(*deep_idle_ctrl_cb) (UINT32); ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern UINT32 gWmtDbgLvl; ++extern struct device *wmt_dev; ++#ifdef CFG_WMT_READ_EFUSE_VCN33 ++extern INT32 wmt_set_pmic_voltage(UINT32 level); ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++INT32 wmt_plat_init(UINT32 co_clock_type); ++ ++INT32 wmt_plat_deinit(VOID); ++ ++INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state); ++ ++INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); ++ ++INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); ++ ++INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId); ++ ++INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); ++ ++VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb); ++VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb); ++VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl); ++VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl); ++VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl); ++ ++INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo); ++UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset); ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en); ++#endif ++#if CFG_WMT_DUMP_INT_STATUS ++VOID wmt_plat_BGF_irq_dump_status(VOID); ++MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID); ++#endif ++P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID); ++UINT32 wmt_plat_read_cpupcr(VOID); ++UINT32 wmt_plat_read_dmaregs(UINT32); ++INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state); ++UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type); ++INT32 wmt_plat_update_host_sync_num(VOID); ++INT32 wmt_plat_get_dump_info(UINT32 offset); ++UINT32 wmt_plat_get_soc_chipid(VOID); ++INT32 wmt_plat_set_dbg_mode(UINT32 flag); ++VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf); ++#if CFG_WMT_LTE_COEX_HANDLING ++INT32 wmt_plat_get_tdm_antsel_index(VOID); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WMT_PLAT_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile +new file mode 100644 +index 000000000000..905207118938 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile +@@ -0,0 +1,6 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++obj-y += pub/ ++obj-y += pri/ ++ ++endif +\ No newline at end of file +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h +new file mode 100644 +index 000000000000..95d1ab02a9fa +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h +@@ -0,0 +1,74 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef __BGW_DESENSE_H_ ++#define __BGW_DESENSE_H_ ++ ++#ifdef MSG ++#undef MSG ++#endif ++ ++#ifdef ERR ++#undef ERR ++#endif ++ ++#define PFX1 "[BWG] " ++#define MSG(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) ++#define ERR(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) ++ ++#ifdef NETLINK_TEST ++#undef NETLINK_TEST ++#endif ++ ++#define NETLINK_TEST 17 ++ ++#ifdef MAX_NL_MSG_LEN ++#undef MAX_NL_MSG_LEN ++#endif ++ ++#define MAX_NL_MSG_LEN 1024 ++ ++ ++#ifdef ON ++#undef ON ++#endif ++#ifdef OFF ++#undef OFF ++#endif ++#ifdef ACK ++#undef ACK ++#endif ++ ++#define ON 1 ++#define OFF 0 ++#define ACK 2 ++ ++/* ++used send command to native process ++ ++parameter: command could be macro ON: enable co-exist; OFF: disable co-exist; ++ACK: after get native process init message send ACK ++ ++*/ ++extern void send_command_to_daemon(const int command); ++ ++/* ++before use kernel socket, please call init socket first ++return value: 0: ok; -1: fail ++*/ ++extern int bgw_init_socket(void); ++ ++extern void bgw_destroy_netlink_kernel(void); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h +new file mode 100644 +index 000000000000..cf3e830003ac +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h +@@ -0,0 +1,349 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _OSAL_H_ ++#define _OSAL_H_ ++ ++#include ++#include ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define OS_BIT_OPS_SUPPORT 1 ++ ++#define _osal_inline_ inline ++ ++#define MAX_THREAD_NAME_LEN 16 ++#define MAX_WAKE_LOCK_NAME_LEN 16 ++#define OSAL_OP_BUF_SIZE 64 ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) ++#define OSAL_OP_DATA_SIZE 8 ++#else ++#define OSAL_OP_DATA_SIZE 32 ++#endif ++ ++#define DBG_LOG_STR_SIZE 256 ++ ++#define osal_sizeof(x) sizeof(x) ++ ++#define osal_array_size(x) (sizeof(x)/sizeof(x[0])) ++ ++#ifndef NAME_MAX ++#define NAME_MAX 256 ++#endif ++ ++#define WMT_OP_BIT(x) (0x1UL << x) ++#define WMT_OP_HIF_BIT WMT_OP_BIT(0) ++ ++#define RB_SIZE(prb) ((prb)->size) ++#define RB_MASK(prb) (RB_SIZE(prb) - 1) ++#define RB_COUNT(prb) ((prb)->write - (prb)->read) ++#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) ++#define RB_EMPTY(prb) ((prb)->write == (prb)->read) ++ ++#define RB_INIT(prb, qsize) \ ++do { \ ++ (prb)->read = (prb)->write = 0; \ ++ (prb)->size = (qsize); \ ++} while (0) ++ ++#define RB_PUT(prb, value) \ ++do { \ ++ if (!RB_FULL(prb)) { \ ++ (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \ ++ ++((prb)->write); \ ++ } \ ++ else { \ ++ osal_assert(!RB_FULL(prb)); \ ++ } \ ++} while (0) ++ ++#define RB_GET(prb, value) \ ++do { \ ++ if (!RB_EMPTY(prb)) { \ ++ value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \ ++ ++((prb)->read); \ ++ if (RB_EMPTY(prb)) { \ ++ (prb)->read = (prb)->write = 0; \ ++ } \ ++ } \ ++ else { \ ++ value = NULL; \ ++ osal_assert(!RB_EMPTY(prb)); \ ++ } \ ++} while (0) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++//typedef VOID(*P_TIMEOUT_HANDLER) (unsigned long); ++typedef VOID(*P_TIMEOUT_HANDLER) (struct timer_list *t); ++typedef INT32(*P_COND) (VOID *); ++ ++typedef struct _OSAL_TIMER_ { ++ struct timer_list timer; ++ P_TIMEOUT_HANDLER timeoutHandler; ++ unsigned long timeroutHandlerData; ++} OSAL_TIMER, *P_OSAL_TIMER; ++ ++typedef struct _OSAL_UNSLEEPABLE_LOCK_ { ++ spinlock_t lock; ++ unsigned long flag; ++} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; ++ ++typedef struct _OSAL_SLEEPABLE_LOCK_ { ++ struct mutex lock; ++} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; ++ ++typedef struct _OSAL_SIGNAL_ { ++ struct completion comp; ++ UINT32 timeoutValue; ++} OSAL_SIGNAL, *P_OSAL_SIGNAL; ++ ++typedef struct _OSAL_EVENT_ { ++ wait_queue_head_t waitQueue; ++/* VOID *pWaitQueueData; */ ++ UINT32 timeoutValue; ++ INT32 waitFlag; ++ ++} OSAL_EVENT, *P_OSAL_EVENT; ++ ++typedef struct _OSAL_THREAD_ { ++ struct task_struct *pThread; ++ VOID *pThreadFunc; ++ VOID *pThreadData; ++ char threadName[MAX_THREAD_NAME_LEN]; ++} OSAL_THREAD, *P_OSAL_THREAD; ++ ++typedef struct _OSAL_FIFO_ { ++ /*fifo definition */ ++ VOID *pFifoBody; ++ spinlock_t fifoSpinlock; ++ /*fifo operations */ ++ INT32 (*FifoInit)(struct _OSAL_FIFO_ *pFifo, UINT8 *buf, UINT32); ++ INT32 (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoReset)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoSz)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoLen)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); ++ INT32 (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const VOID *buf, UINT32 len); ++ INT32 (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, void *buf, UINT32 len); ++} OSAL_FIFO, *P_OSAL_FIFO; ++ ++typedef struct firmware osal_firmware; ++ ++typedef struct _OSAL_OP_DAT { ++ UINT32 opId; /* Event ID */ ++ UINT32 u4InfoBit; /* Reserved */ ++ SIZE_T au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */ ++} OSAL_OP_DAT, *P_OSAL_OP_DAT; ++ ++typedef struct _OSAL_LXOP_ { ++ OSAL_OP_DAT op; ++ OSAL_SIGNAL signal; ++ INT32 result; ++} OSAL_OP, *P_OSAL_OP; ++ ++typedef struct _OSAL_LXOP_Q { ++ OSAL_SLEEPABLE_LOCK sLock; ++ UINT32 write; ++ UINT32 read; ++ UINT32 size; ++ P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; ++} OSAL_OP_Q, *P_OSAL_OP_Q; ++ ++typedef struct _OSAL_WAKE_LOCK_ { ++ #ifdef CONFIG_PM_WAKELOCKS ++ struct wakeup_source wake_lock; ++ #else ++ struct wake_lock wake_lock; ++ #endif ++ UINT8 name[MAX_WAKE_LOCK_NAME_LEN]; ++} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK; ++#if 1 ++typedef struct _OSAL_BIT_OP_VAR_ { ++ unsigned long data; ++ OSAL_UNSLEEPABLE_LOCK opLock; ++} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; ++#else ++#define OSAL_BIT_OP_VAR unsigned long ++#define P_OSAL_BIT_OP_VAR unsigned long * ++ ++#endif ++typedef UINT32(*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread); ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern UINT32 osal_strlen(const char *str); ++extern INT32 osal_strcmp(const char *dst, const char *src); ++extern INT32 osal_strncmp(const char *dst, const char *src, UINT32 len); ++extern char *osal_strcpy(char *dst, const char *src); ++extern char *osal_strncpy(char *dst, const char *src, UINT32 len); ++extern char *osal_strcat(char *dst, const char *src); ++extern char *osal_strncat(char *dst, const char *src, UINT32 len); ++extern char *osal_strchr(const char *str, UINT8 c); ++extern char *osal_strsep(char **str, const char *c); ++extern int osal_strtol(const char *str, UINT32 adecimal, long *res); ++extern INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...); ++extern char *osal_strstr(char *str1, const char *str2); ++ ++extern INT32 osal_err_print(const char *str, ...); ++extern INT32 osal_dbg_print(const char *str, ...); ++extern INT32 osal_warn_print(const char *str, ...); ++ ++extern INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line); ++extern INT32 osal_sprintf(char *str, const char *format, ...); ++extern VOID *osal_malloc(UINT32 size); ++extern VOID osal_free(const VOID *dst); ++extern VOID *osal_memset(VOID *buf, INT32 i, UINT32 len); ++extern VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len); ++extern INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len); ++ ++extern INT32 osal_sleep_ms(UINT32 ms); ++extern INT32 osal_udelay(UINT32 us); ++extern INT32 osal_timer_create(P_OSAL_TIMER); ++extern INT32 osal_timer_start(P_OSAL_TIMER, UINT32); ++extern INT32 osal_timer_stop(P_OSAL_TIMER); ++extern INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer); ++extern INT32 osal_timer_modify(P_OSAL_TIMER, UINT32); ++extern INT32 osal_timer_delete(P_OSAL_TIMER); ++ ++extern INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size); ++extern VOID osal_fifo_deinit(P_OSAL_FIFO pFifo); ++extern INT32 osal_fifo_reset(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); ++extern UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); ++extern UINT32 osal_fifo_len(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo); ++extern UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo); ++ ++extern INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK plock); ++extern INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock); ++ ++#if defined(CONFIG_PROVE_LOCKING) ++#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); } ++#else ++extern INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK); ++#endif ++extern INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); ++extern INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); ++extern INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK); ++ ++#if defined(CONFIG_PROVE_LOCKING) ++#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); } ++#else ++extern INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK); ++#endif ++extern INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); ++extern INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); ++extern INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK); ++ ++extern INT32 osal_signal_init(P_OSAL_SIGNAL); ++extern INT32 osal_wait_for_signal(P_OSAL_SIGNAL); ++extern INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL); ++extern INT32 osal_raise_signal(P_OSAL_SIGNAL); ++extern INT32 osal_signal_deinit(P_OSAL_SIGNAL); ++ ++extern INT32 osal_event_init(P_OSAL_EVENT); ++extern INT32 osal_wait_for_event(P_OSAL_EVENT, P_COND, void *); ++extern INT32 osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, void *); ++extern INT32 osal_trigger_event(P_OSAL_EVENT); ++ ++extern INT32 osal_event_deinit(P_OSAL_EVENT); ++ ++extern INT32 osal_thread_create(P_OSAL_THREAD); ++extern INT32 osal_thread_run(P_OSAL_THREAD); ++extern INT32 osal_thread_should_stop(P_OSAL_THREAD); ++extern INT32 osal_thread_stop(P_OSAL_THREAD); ++/*extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ ++extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); ++/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ ++extern INT32 osal_thread_destroy(P_OSAL_THREAD); ++ ++extern INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++extern INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); ++ ++extern INT32 osal_dbg_assert_aee(const char *module, const char *detail_description); ++extern INT32 osal_gettimeofday(PINT32 sec, PINT32 usec); ++extern INT32 osal_printtimeofday(const PUINT8 prefix); ++ ++extern VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, UINT32 len, UINT32 limit); ++ ++extern UINT32 osal_op_get_id(P_OSAL_OP pOp); ++extern MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); ++extern VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result); ++extern VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result); ++extern UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length); ++extern VOID osal_thread_show_stack(P_OSAL_THREAD pThread); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#define osal_assert(condition) \ ++do { \ ++ if (!(condition)) \ ++ osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition); \ ++} while (0) ++ ++#endif /* _OSAL_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h +new file mode 100644 +index 000000000000..b3a9c57e062d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h +@@ -0,0 +1,90 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _OSAL_TYPEDEF_H_ ++#define _OSAL_TYPEDEF_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_EARLYSUSPEND ++#include ++#else ++#include ++#endif ++#include ++#include ++#ifdef WMT_PLAT_ALPS ++#include ++#endif ++#include ++#ifdef CONFIG_PM_WAKELOCKS ++#include ++#else ++#include ++#endif ++#include ++ ++#ifndef _TYPEDEFS_H /*fix redifine */ ++typedef char INT8; ++#endif ++ ++typedef void VOID, *PVOID, **PPVOID; ++typedef char *PINT8, **PPINT8; ++typedef short INT16, *PINT16, **PPINT16; ++typedef int INT32, *PINT32, **PPINT32; ++typedef long long INT64, *PINT64, **PPINT64; ++ ++typedef unsigned char UINT8, *PUINT8, **PPUINT8; ++typedef unsigned short UINT16, *PUINT16, **PPUINT16; ++typedef unsigned int UINT32, *PUINT32, **PPUINT32; ++typedef unsigned long long UINT64, *PUINT64, **PPUINT64; ++ ++typedef size_t SIZE_T; ++ ++typedef int MTK_WCN_BOOL; ++#ifndef MTK_WCN_BOOL_TRUE ++#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) ++#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) ++#endif ++ ++#endif /*_OSAL_TYPEDEF_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h +new file mode 100644 +index 000000000000..17be778484c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h +@@ -0,0 +1,97 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_IDC_H_ ++#define _WMT_IDC_H_ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_stp_exp.h" ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++#include "wmt_stp_exp.h" ++#include "conn_md_exp.h" ++ ++#define LTE_IDC_BUFFER_MAX_SIZE 1024 ++/*comment from firmware owner,max pckage num is 5,but should not happened*/ ++#define WMT_IDC_RX_MAX_LEN 384 ++#define LTE_MSG_ID_OFFSET 0x30 ++ ++typedef enum { ++ WMT_IDC_TX_OPCODE_MIN = 0, ++ WMT_IDC_TX_OPCODE_LTE_PARA = 0x0a, ++ WMT_IDC_TX_OPCODE_LTE_FREQ = 0x0b, ++ WMT_IDC_TX_OPCODE_WIFI_MAX_POWER = 0x0c, ++ WMT_IDC_TX_OPCODE_DEBUG_MONITOR = 0x0e, ++ WMT_IDC_TX_OPCODE_SPLIT_FILTER = 0x0f, ++ WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS = 0x16, ++ WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION = 0x17, ++ WMT_IDC_TX_OPCODE_LTE_INDICATION = 0x20, ++ WMT_IDC_TX_OPCODE_MAX ++} WMT_IDC_TX_OPCODE; ++ ++typedef enum { ++ WMT_IDC_RX_OPCODE_BTWF_DEF_PARA = 0x0, ++ WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN = 0x1, ++ /* WMT_IDC_RX_OPCODE_TDM_REQ = 0x10, */ ++ WMT_IDC_RX_OPCODE_DEBUG_MONITOR = 0x02, ++ WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE = 0x03, ++ WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND = 0x04, ++ WMT_IDC_RX_OPCODE_UART_PIN_SEL = 0x05, ++ WMT_IDC_RX_OPCODE_MAX ++} WMT_IDC_RX_OPCODE; ++ ++#if (CFG_WMT_LTE_ENABLE_MSGID_MAPPING == 0) ++typedef enum { ++ IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN, ++ IPC_L4C_MSG_ID_END, ++ IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN, ++ /* below are EL1 IPC messages sent from AP */ ++ IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND, ++ IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND, ++ IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND, ++ IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND, ++ IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND, ++ ++ /* below are EL1 messages sent to AP */ ++ IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, ++ IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, ++ IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, ++ IPC_MSG_ID_EL1_LTE_TX_IND, ++ IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND, ++ IPC_MSG_ID_EL1_PIN_TYPE_IND, ++ IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND, ++ IPC_MSG_ID_EL1_DUMMY13_IND, ++ IPC_MSG_ID_EL1_DUMMY14_IND, ++ IPC_MSG_ID_EL1_DUMMY15_IND, ++ IPC_EL1_MSG_ID_END, ++} IPC_MSG_ID_CODE; ++#endif ++ ++typedef struct _MTK_WCN_WMT_IDC_INFO_ { ++ ipc_ilm_t iit; ++ CONN_MD_BRIDGE_OPS ops; ++ UINT8 buffer[LTE_IDC_BUFFER_MAX_SIZE]; ++} MTK_WCN_WMT_IDC_INFO, *P_MTK_WCN_WMT_IDC_INFO; ++ ++extern INT32 wmt_idc_init(VOID); ++extern INT32 wmt_idc_deinit(VOID); ++extern INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm); ++extern INT32 wmt_idc_msg_to_lte_handing(VOID); ++extern UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len); ++ ++#endif /* endif CFG_WMT_LTE_COEX_HANDLING */ ++ ++#endif /* _WMT_IDC_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile +new file mode 100644 +index 000000000000..ff0f0b0aefda +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile +@@ -0,0 +1,21 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../../linux/include \ ++ -I$(src)/../../linux/pri/include \ ++ -I$(src)/../../core/include \ ++ -I$(src)/../../include \ ++ -I$(src)/../include \ ++ -I$(src)/../../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ ++ -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach ++ ++ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 ++ ++obj-y += stp_btif.o \ ++ stp_dbg.o \ ++ stp_exp.o \ ++ wmt_dev.o \ ++ wmt_exp.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h +new file mode 100644 +index 000000000000..3730fbba6928 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h +@@ -0,0 +1,31 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _STP_BTIF_H_ ++#define _STP_BTIF_H_ ++ ++#include "osal_typedef.h" ++#include "mtk_btif_exp.h" ++ ++extern INT32 mtk_wcn_consys_stp_btif_open(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_close(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb); ++extern INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len); ++extern INT32 mtk_wcn_consys_stp_btif_wakeup(VOID); ++extern INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); ++extern INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); ++extern INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag); ++extern MTK_WCN_BOOL mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h +new file mode 100644 +index 000000000000..de5684a16853 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h +@@ -0,0 +1,316 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _STP_DEBUG_H_ ++#define _STP_DEBUG_H_ ++ ++#include ++#include "osal.h" ++ ++#define CONFIG_LOG_STP_INTERNAL ++ ++#if 1 /* #ifndef CONFIG_LOG_STP_INTERNAL */ ++#define STP_PKT_SZ 16 ++#define STP_DMP_SZ 2048 ++#define STP_PKT_NO 2048 ++ ++#define STP_DBG_LOG_ENTRY_NUM 60 ++#define STP_DBG_LOG_ENTRY_SZ 64 ++ ++#else ++ ++#define STP_PKT_SZ 16 ++#define STP_DMP_SZ 16 ++#define STP_PKT_NO 16 ++ ++#define STP_DBG_LOG_ENTRY_NUM 28 ++#define STP_DBG_LOG_ENTRY_SZ 64 ++ ++#endif ++ ++typedef enum { ++ STP_DBG_EN = 0, ++ STP_DBG_PKT = 1, ++ STP_DBG_DR = 2, ++ STP_DBG_FW_ASSERT = 3, ++ STP_DBG_FW_LOG = 4, ++ STP_DBG_FW_DMP = 5, ++ STP_DBG_MAX ++} STP_DBG_OP_T; ++ ++typedef enum { ++ STP_DBG_PKT_FIL_ALL = 0, ++ STP_DBG_PKT_FIL_BT = 1, ++ STP_DBG_PKT_FIL_GPS = 2, ++ STP_DBG_PKT_FIL_FM = 3, ++ STP_DBG_PKT_FIL_WMT = 4, ++ STP_DBG_PKT_FIL_MAX ++} STP_DBG_PKT_FIL_T; ++ ++static char *const gStpDbgType[] = { ++ "< BT>", ++ "< FM>", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "" ++}; ++ ++typedef enum { ++ STP_DBG_DR_MAX = 0, ++} STP_DBG_DR_FIL_T; ++ ++typedef enum { ++ STP_DBG_FW_MAX = 0, ++} STP_DBG_FW_FIL_T; ++ ++typedef enum { ++ PKT_DIR_RX = 0, ++ PKT_DIR_TX ++} STP_DBG_PKT_DIR_T; ++ ++/*simple log system ++*/ ++ ++typedef struct { ++ /*type: 0. pkt trace 1. fw info ++ * 2. assert info 3. trace32 dump . ++ * -1. linked to the the previous ++ */ ++ int id; ++ int len; ++ char buffer[STP_DBG_LOG_ENTRY_SZ]; ++} MTKSTP_LOG_ENTRY_T; ++ ++typedef struct log_sys { ++ MTKSTP_LOG_ENTRY_T queue[STP_DBG_LOG_ENTRY_NUM]; ++ unsigned int size; ++ unsigned int in; ++ unsigned int out; ++ spinlock_t lock; ++} MTKSTP_LOG_SYS_T; ++/*--*/ ++ ++typedef struct stp_dbg_pkt_hdr { ++ /* packet information */ ++ unsigned int sec; ++ unsigned int usec; ++ unsigned int dbg_type; ++ unsigned int dmy; ++ unsigned int no; ++ unsigned int dir; ++ ++ /* packet content */ ++ unsigned int type; ++ unsigned int len; ++ unsigned int ack; ++ unsigned int seq; ++ unsigned int chs; ++ unsigned int crc; ++} STP_DBG_HDR_T; ++ ++typedef struct stp_dbg_pkt { ++ struct stp_dbg_pkt_hdr hdr; ++ unsigned char raw[STP_DMP_SZ]; ++} STP_PACKET_T; ++ ++typedef struct mtkstp_dbg_t { ++ /*log_sys */ ++ int pkt_trace_no; ++ void *btm; ++ int is_enable; ++ MTKSTP_LOG_SYS_T *logsys; ++} MTKSTP_DBG_T; ++ ++/* extern void aed_combo_exception(const int *, int, const int *, int, const char *); */ ++ ++#define STP_CORE_DUMP_TIMEOUT (5*60*1000) /* default 5minutes */ ++#define STP_OJB_NAME_SZ 20 ++#define STP_CORE_DUMP_INFO_SZ 500 ++#define STP_CORE_DUMP_INIT_SIZE 1 ++typedef enum wcn_compress_algorithm_t { ++ GZIP = 0, ++ BZIP2 = 1, ++ RAR = 2, ++ LMA = 3, ++ MAX ++} WCN_COMPRESS_ALG_T; ++ ++typedef INT32 (*COMPRESS_HANDLER) (void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, ++ INT32 finish); ++typedef struct wcn_compressor_t { ++ /* current object name */ ++ UINT8 name[STP_OJB_NAME_SZ + 1]; ++ ++ /* buffer for raw data, named L1 */ ++ PUINT8 L1_buf; ++ INT32 L1_buf_sz; ++ INT32 L1_pos; ++ ++ /* target buffer, named L2 */ ++ PUINT8 L2_buf; ++ INT32 L2_buf_sz; ++ INT32 L2_pos; ++ ++ /* compress state */ ++ UINT8 f_done; ++ UINT16 reserved; ++ UINT32 uncomp_size; ++ UINT32 crc32; ++ ++ /* compress algorithm */ ++ UINT8 f_compress_en; ++ WCN_COMPRESS_ALG_T compress_type; ++ void *worker; ++ COMPRESS_HANDLER handler; ++} WCN_COMPRESSOR_T, *P_WCN_COMPRESSOR_T; ++ ++P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz); ++INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T compressor); ++INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T compressor, PUINT8 buf, INT32 len, INT32 finish); ++INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T compressor, PUINT8 *pbuf, PINT32 len); ++INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T compressor, UINT8 enable, WCN_COMPRESS_ALG_T type); ++ ++typedef enum core_dump_state_t { ++ CORE_DUMP_INIT = 0, ++ CORE_DUMP_DOING, ++ CORE_DUMP_TIMEOUT, ++ CORE_DUMP_DONE, ++ CORE_DUMP_MAX ++} CORE_DUMP_STA; ++ ++typedef struct core_dump_t { ++ /* compress dump data and buffered */ ++ P_WCN_COMPRESSOR_T compressor; ++ ++ /* timer for monitor timeout */ ++ OSAL_TIMER dmp_timer; ++ UINT32 timeout; ++ ++ OSAL_SLEEPABLE_LOCK dmp_lock; ++ ++ /* state machine for core dump flow */ ++ CORE_DUMP_STA sm; ++ ++ /* dump info */ ++ INT8 info[STP_CORE_DUMP_INFO_SZ + 1]; ++} WCN_CORE_DUMP_T, *P_WCN_CORE_DUMP_T; ++ ++typedef enum _ENUM_STP_FW_ISSUE_TYPE_ { ++ STP_FW_ISSUE_TYPE_INVALID = 0x0, ++ STP_FW_ASSERT_ISSUE = 0x1, ++ STP_FW_NOACK_ISSUE = 0x2, ++ STP_FW_WARM_RST_ISSUE = 0x3, ++ STP_DBG_PROC_TEST = 0x4, ++ STP_HOST_TRIGGER_FW_ASSERT = 0x5, ++ STP_HOST_TRIGGER_ASSERT_TIMEOUT = 0x6, ++ STP_FW_ISSUE_TYPE_MAX ++} ENUM_STP_FW_ISSUE_TYPE, *P_ENUM_STP_FW_ISSUE_TYPE; ++ ++/* this was added for support dmareg's issue */ ++typedef enum _ENUM_DMA_ISSUE_TYPE_ { ++ CONNSYS_CLK_GATE_STATUS = 0x00, ++ CONSYS_EMI_STATUS, ++ SYSRAM1, ++ SYSRAM2, ++ SYSRAM3, ++ DMA_REGS_MAX ++} ENUM_DMA_ISSUE_TYPE; ++#define STP_PATCH_TIME_SIZE 12 ++#define STP_DBG_CPUPCR_NUM 512 ++#define STP_DBG_DMAREGS_NUM 16 ++#define STP_PATCH_BRANCH_SZIE 8 ++#define STP_ASSERT_INFO_SIZE 64 ++#define STP_DBG_ROM_VER_SIZE 4 ++#define STP_ASSERT_TYPE_SIZE 32 ++ ++typedef struct stp_dbg_host_assert_t { ++ UINT32 drv_type; ++ UINT32 reason; ++ UINT32 assert_from_host; ++} STP_DBG_HOST_ASSERT_T, *P_STP_DBG_HOST_ASSERT_T; ++ ++typedef struct stp_dbg_cpupcr_t { ++ UINT32 chipId; ++ UINT8 romVer[STP_DBG_ROM_VER_SIZE]; ++ UINT8 patchVer[STP_PATCH_TIME_SIZE]; ++ UINT8 branchVer[STP_PATCH_BRANCH_SZIE]; ++ UINT32 wifiVer; ++ UINT32 count; ++ UINT32 stop_flag; ++ UINT32 buffer[STP_DBG_CPUPCR_NUM]; ++ UINT8 assert_info[STP_ASSERT_INFO_SIZE]; ++ UINT32 fwTaskId; ++ UINT32 fwRrq; ++ UINT32 fwIsr; ++ STP_DBG_HOST_ASSERT_T host_assert_info; ++ UINT8 assert_type[STP_ASSERT_TYPE_SIZE]; ++ ENUM_STP_FW_ISSUE_TYPE issue_type; ++ OSAL_SLEEPABLE_LOCK lock; ++} STP_DBG_CPUPCR_T, *P_STP_DBG_CPUPCR_T; ++ ++typedef struct stp_dbg_dmaregs_t { ++ UINT32 count; ++ UINT32 dmaIssue[DMA_REGS_MAX][STP_DBG_DMAREGS_NUM]; ++ OSAL_SLEEPABLE_LOCK lock; ++} STP_DBG_DMAREGS_T, *P_STP_DBG_DMAREGS_T; ++ ++typedef enum _ENUM_ASSERT_INFO_PARSER_TYPE_ { ++ STP_DBG_ASSERT_INFO = 0x0, ++ STP_DBG_FW_TASK_ID = 0x1, ++ STP_DBG_FW_ISR = 0x2, ++ STP_DBG_FW_IRQ = 0x3, ++ STP_DBG_ASSERT_TYPE = 0x4, ++ STP_DBG_PARSER_TYPE_MAX ++} ENUM_ASSERT_INFO_PARSER_TYPE, *P_ENUM_ASSERT_INFO_PARSER_TYPE; ++ ++P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout); ++INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp); ++INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len); ++INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 len); ++INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout); ++INT32 wcn_core_dump_timeout(void); ++INT32 wcn_wmtd_timeout_collect_ftrace(void); ++ ++extern INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout); ++extern INT32 wcn_core_dump_deinit_gcoredump(VOID); ++extern INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL is_coredump_timeout); ++extern int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg); ++extern int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg); ++extern MTKSTP_DBG_T *stp_dbg_init(void *); ++extern int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg); ++extern int stp_dbg_dmp_out_ex(char *buf, int *len); ++extern int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len); ++extern int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg); ++extern char stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len); ++ ++extern INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd); ++extern INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len); ++extern int ++stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, ++ int dbg_type, int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body); ++extern int stp_dbg_log_ctrl(unsigned int on); ++extern INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); ++extern INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep); ++extern INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en); ++extern INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, ++ PUINT8 pPatchBrh); ++extern INT32 stp_dbg_set_wifiver(UINT32 wifiver); ++extern INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 len); ++extern INT32 stp_dbg_set_fw_info(PUINT8 assert_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type); ++extern INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en); ++extern UINT32 stp_dbg_get_host_trigger_assert(VOID); ++#endif /* end of _STP_DEBUG_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h +new file mode 100644 +index 000000000000..5788eb355549 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h +@@ -0,0 +1,71 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#ifndef _WMT_DEV_H_ ++#define _WMT_DEV_H_ ++ ++#include "osal.h" ++ ++#define STP_UART_FULL 0x01 ++#define STP_UART_MAND 0x02 ++#define STP_BTIF_FULL 0x03 ++#define STP_SDIO 0x04 ++ ++#define CFG_WMT_DBG_SUPPORT 1 /* support wmt_dbg or not */ ++#define CFG_WMT_PROC_FOR_AEE 1 ++ ++extern VOID wmt_dev_rx_event_cb(VOID); ++extern INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent); ++extern INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf); ++extern INT32 wmt_dev_patch_put(osal_firmware **ppPatch); ++extern VOID wmt_dev_patch_info_free(VOID); ++extern VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd); ++extern MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID); ++ ++#if CFG_WMT_DBG_SUPPORT ++typedef struct _COEX_BUF { ++ UINT8 buffer[128]; ++ INT32 availSize; ++} COEX_BUF, *P_COEX_BUF; ++ ++typedef enum _ENUM_CMD_TYPE_T { ++ WMTDRV_CMD_ASSERT = 0, ++ WMTDRV_CMD_EXCEPTION = 1, ++ WMTDRV_CMD_COEXDBG_00 = 2, ++ WMTDRV_CMD_COEXDBG_01 = 3, ++ WMTDRV_CMD_COEXDBG_02 = 4, ++ WMTDRV_CMD_COEXDBG_03 = 5, ++ WMTDRV_CMD_COEXDBG_04 = 6, ++ WMTDRV_CMD_COEXDBG_05 = 7, ++ WMTDRV_CMD_COEXDBG_06 = 8, ++ WMTDRV_CMD_COEXDBG_07 = 9, ++ WMTDRV_CMD_COEXDBG_08 = 10, ++ WMTDRV_CMD_COEXDBG_09 = 11, ++ WMTDRV_CMD_COEXDBG_10 = 12, ++ WMTDRV_CMD_COEXDBG_11 = 13, ++ WMTDRV_CMD_COEXDBG_12 = 14, ++ WMTDRV_CMD_COEXDBG_13 = 15, ++ WMTDRV_CMD_COEXDBG_14 = 16, ++ WMTDRV_CMD_COEXDBG_15 = 17, ++ WMTDRV_CMD_NOACK_TEST = 18, ++ WMTDRV_CMD_WARNRST_TEST = 19, ++ WMTDRV_CMD_FWTRACE_TEST = 20, ++ WMTDRV_CMD_MAX ++} ENUM_WMTDRV_CMD_T, *P_ENUM_WMTDRV_CMD_T; ++ ++#endif ++ ++typedef INT32(*WMT_DEV_DBG_FUNC) (INT32 par1, INT32 par2, INT32 par3); ++ ++#endif /*_WMT_DEV_H_*/ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c +new file mode 100644 +index 000000000000..76debb4674f9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c +@@ -0,0 +1,279 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*file: stp_btif, mainly control stp & btif interaction*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[STP-BTIF]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "wmt_exp.h" ++#include "stp_exp.h" ++#include "stp_btif.h" ++ ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BTIF_OWNER_NAME "CONSYS_STP" ++ ++#define STP_MAX_PACKAGE_ALLOWED (2000) ++ ++#define STP_BTIF_TX_RTY_LMT (10) ++#define STP_BTIF_TX_RTY_DLY (5) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++unsigned long stpBtifId = 0; ++unsigned long *pBtifRef = &stpBtifId; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 mtk_wcn_consys_stp_btif_open(VOID) ++{ ++ INT32 iRet = -1; ++ ++ iRet = mtk_wcn_btif_open(BTIF_OWNER_NAME, pBtifRef); ++ if (iRet) { ++ WMT_WARN_FUNC("STP open btif fail(%d)\n", iRet); ++ return -1; ++ } ++ WMT_DBG_FUNC("STP open bitf OK\n"); ++ ++ mtk_wcn_stp_register_if_tx(STP_BTIF_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_consys_stp_btif_tx); ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_close(VOID) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_close(stpBtifId); ++ if (iRet) { ++ WMT_WARN_FUNC("STP close btif fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ stpBtifId = 0; ++ WMT_DBG_FUNC("STP close btif OK\n"); ++ } ++ } ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference\n!"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_rx_cb_register(stpBtifId, rx_cb); ++ if (iRet) { ++ WMT_WARN_FUNC("STP register rxcb to btif fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("STP register rxcb to btif OK\n"); ++ } ++ } ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len) ++{ ++ INT32 retry_left = STP_BTIF_TX_RTY_LMT; ++ INT32 wr_count = 0; ++ INT32 written = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ return -1; ++ } ++ ++ if (len == 0) { ++ *written_len = 0; ++ WMT_INFO_FUNC("special case for STP-CORE,pbuf(%p)\n", pBuf); ++ return 0; ++ } ++ ++ *written_len = 0; ++ ++ if (len > STP_MAX_PACKAGE_ALLOWED) { ++ WMT_WARN_FUNC("abnormal pacage length,len(%d),pid[%d/%s]\n", len, current->pid, current->comm); ++ return -2; ++ } ++ wr_count = mtk_wcn_btif_write(stpBtifId, pBuf, len); ++ ++ if (wr_count < 0) { ++ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)\n", wr_count); ++ *written_len = 0; ++ return -3; ++ } ++ if (wr_count == len) { ++ /*perfect case */ ++ *written_len = wr_count; ++ return wr_count; ++ } ++ ++ while ((retry_left--) && (wr_count < len)) { ++ osal_sleep_ms(STP_BTIF_TX_RTY_DLY); ++ written = mtk_wcn_btif_write(stpBtifId, pBuf + wr_count, len - wr_count); ++ if (written < 0) { ++ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)when do recovered\n", written); ++ break; ++ } ++ wr_count += written; ++ } ++ ++ if (wr_count == len) { ++ WMT_INFO_FUNC("recovered,len(%d),retry_left(%d)\n", len, retry_left); ++ /*recovered case */ ++ *written_len = wr_count; ++ return wr_count; ++ } ++ ++ WMT_ERR_FUNC("stp btif write fail,len(%d),written(%d),retry_left(%d),pid[%d/%s]\n", ++ len, wr_count, retry_left, current->pid, current->comm); ++ *written_len = 0; ++ return -wr_count; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_rx(UINT8 *pBuf, UINT32 len) ++{ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_wakeup(VOID) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_wakeup_consys(stpBtifId); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif wakeup consys fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_DBG_FUNC("STP btif wakeup consys ok\n"); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ mtk_wcn_btif_dpidle_ctrl(stpBtifId, en_flag); ++ WMT_DBG_FUNC("stp btif dpidle ctrl done,en_flag(%d)\n", en_flag); ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_loopback_ctrl(stpBtifId, mode); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif lpbk ctrl fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_INFO_FUNC("stp btif lpbk ctrl ok,mode(%d)\n", mode); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag) ++{ ++ INT32 iRet = 0; ++ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ iRet = -1; ++ } else { ++ iRet = mtk_wcn_btif_dbg_ctrl(stpBtifId, flag); ++ if (iRet) { ++ WMT_WARN_FUNC("STP btif log dbg ctrl fail(%d)\n", iRet); ++ iRet = -2; ++ } else { ++ WMT_INFO_FUNC("stp btif log dbg ctrl ok,flag(%d)\n", flag); ++ } ++ } ++ ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len) ++{ ++ if (!stpBtifId) { ++ WMT_WARN_FUNC("NULL BTIF ID reference!\n"); ++ return -1; ++ } else { ++ return (INT32) mtk_wcn_btif_parser_wmt_evt(stpBtifId, str, len); ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c +new file mode 100644 +index 000000000000..fdb610cc3897 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c +@@ -0,0 +1,2061 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++#include /* GFP_KERNEL */ ++#include /* init_timer, add_time, del_timer_sync */ ++#include /* gettimeofday */ ++#include ++#include /* kzalloc */ ++#include /* task's status */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "osal_typedef.h" ++#include "stp_dbg.h" ++/* #include "stp_btm.h" */ ++#include "btm_core.h" ++#include "wmt_plat.h" ++ ++#define PFX_STP_DBG "[STPDbg]" ++#define STP_DBG_LOG_LOUD 4 ++#define STP_DBG_LOG_DBG 3 ++#define STP_DBG_LOG_INFO 2 ++#define STP_DBG_LOG_WARN 1 ++#define STP_DBG_LOG_ERR 0 ++ ++unsigned int gStpDbgDbgLevel = STP_DBG_LOG_INFO; ++unsigned int gStpDbgLogOut = 0; ++ ++#define STP_DBG_LOUD_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_DBG_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_INFO_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \ ++ pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_WARN_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \ ++ pr_warn(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_ERR_FUNC(fmt, arg...) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \ ++ pr_err(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ ++} while (0) ++#define STP_DBG_TRC_FUNC(f) \ ++do { \ ++ if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ ++ pr_debug(PFX_STP_DBG "<%s> <%d>\n", __func__, __LINE__); \ ++} while (0) ++ ++MTKSTP_DBG_T *g_stp_dbg = NULL; ++ ++#define STP_DBG_FAMILY_NAME "STP_DBG" ++#define MAX_BIND_PROCESS (4) ++#ifdef WMT_PLAT_ALPS ++#define STP_DBG_AEE_EXP_API (1) ++#else ++#define STP_DBG_AEE_EXP_API (0) ++#endif ++enum { ++ __STP_DBG_ATTR_INVALID, ++ STP_DBG_ATTR_MSG, ++ __STP_DBG_ATTR_MAX, ++}; ++#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1) ++ ++enum { ++ __STP_DBG_COMMAND_INVALID, ++ STP_DBG_COMMAND_BIND, ++ STP_DBG_COMMAND_RESET, ++ __STP_DBG_COMMAND_MAX, ++}; ++#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1) ++ ++static struct genl_family stp_dbg_gnl_family = { ++ .id = GENL_ID_GENERATE, ++ .hdrsize = 0, ++ .name = STP_DBG_FAMILY_NAME, ++ .version = 1, ++ .maxattr = STP_DBG_ATTR_MAX, ++}; ++ ++static void stp_dbg_nl_init(void); ++static void stp_dbg_nl_deinit(void); ++static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info); ++static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info); ++ ++/* attribute policy */ ++static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = { ++ [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING}, ++}; ++ ++/* operation definition */ ++#if 0 ++static struct genl_ops stp_dbg_gnl_ops_bind = { ++ .cmd = STP_DBG_COMMAND_BIND, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_bind, ++ .dumpit = NULL, ++}; ++ ++static struct genl_ops stp_dbg_gnl_ops_reset = { ++ .cmd = STP_DBG_COMMAND_RESET, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_reset, ++ .dumpit = NULL, ++}; ++#endif ++static struct genl_ops stp_dbg_gnl_ops_array[] = { ++ { ++ .cmd = STP_DBG_COMMAND_BIND, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_bind, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = STP_DBG_COMMAND_RESET, ++ .flags = 0, ++ .policy = stp_dbg_genl_policy, ++ .doit = stp_dbg_nl_reset, ++ .dumpit = NULL, ++ }, ++}; ++ ++#if 0 ++#define E2S(x) #x ++static char *dmaRegsStr[] = { ++ E2S(CONNSYS_CLK_GATE_STATUS), ++ E2S(CONSYS_EMI_STATUS), ++ E2S(SYSRAM1), ++ E2S(SYSRAM2), ++ E2S(SYSRAM3) ++}; ++#endif ++static unsigned int stp_dbg_seqnum; ++static int num_bind_process; ++static pid_t bind_pid[MAX_BIND_PROCESS]; ++ ++static P_WCN_CORE_DUMP_T g_core_dump; ++ ++static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr; ++ ++/* just show in log at present */ ++static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs; ++ ++/* core_dump_timeout_handler - handler of coredump timeout ++ * @ data - core dump object's pointer ++ * ++ * No return value ++ */ ++static void core_dump_timeout_handler(/*unsigned long data*/struct timer_list *t) ++{ ++ //P_WCN_CORE_DUMP_T dmp = (P_WCN_CORE_DUMP_T) data; ++ P_WCN_CORE_DUMP_T dmp = from_timer(dmp,t,dmp_timer.timer); ++ ++ STP_DBG_INFO_FUNC(" start\n"); ++ ++ stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm); ++ ++ STP_DBG_INFO_FUNC(" end\n"); ++ ++ if (dmp) ++ dmp->sm = CORE_DUMP_TIMEOUT; ++} ++ ++/* wcn_core_dump_init - create core dump sys ++ * @ timeout - core dump time out value ++ * ++ * Return object pointer if success, else NULL ++ */ ++P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout) ++{ ++#define KBYTES (1024*sizeof(char)) ++#define L1_BUF_SIZE (32*KBYTES) ++ ++ P_WCN_CORE_DUMP_T core_dmp = NULL; ++ ++ core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T)); ++ if (!core_dmp) { ++ STP_DBG_ERR_FUNC("alloc mem failed!\n"); ++ goto fail; ++ } ++ ++ osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T)); ++ ++ core_dmp->compressor = wcn_compressor_init("core_dump_compressor", L1_BUF_SIZE, 18*packet_num*KBYTES); ++ if (!core_dmp->compressor) { ++ STP_DBG_ERR_FUNC("create compressor failed!\n"); ++ goto fail; ++ } ++ wcn_compressor_reset(core_dmp->compressor, 1, GZIP); ++ ++ core_dmp->dmp_timer.timeoutHandler = core_dump_timeout_handler; ++ core_dmp->dmp_timer.timeroutHandlerData = (unsigned long)core_dmp; ++ osal_timer_create(&core_dmp->dmp_timer); ++ core_dmp->timeout = timeout; ++ ++ osal_sleepable_lock_init(&core_dmp->dmp_lock); ++ ++ core_dmp->sm = CORE_DUMP_INIT; ++ STP_DBG_INFO_FUNC("create coredump object OK!\n"); ++ ++ return core_dmp; ++ ++fail: ++ if (core_dmp && core_dmp->compressor) { ++ wcn_compressor_deinit(core_dmp->compressor); ++ core_dmp->compressor = NULL; ++ } ++ if (core_dmp) ++ osal_free(core_dmp); ++ ++ return NULL; ++} ++INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout) ++{ ++ INT32 Ret = 0; ++ ++ g_core_dump = wcn_core_dump_init(packet_num, timeout); ++ if (g_core_dump == NULL) ++ Ret = -1; ++ return Ret; ++} ++ ++/* wcn_core_dump_deinit - destroy core dump object ++ * @ dmp - pointer of object ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp) ++{ ++ if (dmp && dmp->compressor) { ++ wcn_compressor_deinit(dmp->compressor); ++ dmp->compressor = NULL; ++ } ++ ++ if (dmp) { ++ osal_sleepable_lock_deinit(&dmp->dmp_lock); ++ osal_timer_stop(&dmp->dmp_timer); ++ osal_free(dmp); ++ } ++ ++ return 0; ++} ++ ++INT32 wcn_core_dump_deinit_gcoredump(VOID) ++{ ++ wcn_core_dump_deinit(g_core_dump); ++ return 0; ++} ++ ++static INT32 wcn_core_dump_check_end(PUINT8 buf, INT32 len) ++{ ++ if (strnstr(buf, "coredump end", len)) ++ return 1; ++ else ++ return 0; ++} ++ ++/* wcn_core_dump_in - add a packet to compressor buffer ++ * @ dmp - pointer of object ++ * @ buf - input buffer ++ * @ len - data length ++ * ++ * Retunr 0 if success; return 1 if find end string; else error code ++ */ ++INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) ++{ ++ INT32 ret = 0; ++ INT32 tmp; ++ ++#define INFO_HEAD ";SOC_CONSYS FW CORE, " ++ ++ if ((!dmp) || (!buf)) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ ret = osal_lock_sleepable_lock(&dmp->dmp_lock); ++ if (ret) { ++ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ switch (dmp->sm) { ++ case CORE_DUMP_INIT: ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); ++ ++ /* first package, copy to info buffer */ ++ osal_strcpy(&dmp->info[0], INFO_HEAD); ++ ++ if (NULL == (strnstr(buf, "", 32))) { ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...", ++ osal_strlen("Fw warm reset exception...")); ++ dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] = '\0'; ++ } else { ++ char *pStr = buf; ++ char *pDtr = NULL; ++ ++ pDtr = osal_strchr(pStr, '-'); ++ if (NULL != pDtr) { ++ tmp = pDtr - pStr; ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); ++ dmp->info[osal_strlen(dmp->info) + 1] = '\0'; ++ } else { ++ tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD); ++ tmp = (len > tmp) ? tmp : len; ++ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); ++ dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0'; ++ } ++ ++ } ++ /* show coredump start info on UI */ ++ /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */ ++#if STP_DBG_AEE_EXP_API ++ aee_kernel_dal_show("SOC_CONSYS coredump start ....\n"); ++#endif ++ /* parsing data, and check end srting */ ++ ret = wcn_core_dump_check_end(buf, len); ++ if (ret == 1) { ++ STP_DBG_INFO_FUNC("core dump end!\n"); ++ dmp->sm = CORE_DUMP_DONE; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } else { ++ dmp->sm = CORE_DUMP_DOING; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } ++ break; ++ ++ case CORE_DUMP_DOING: ++ /* parsing data, and check end srting */ ++ ret = wcn_core_dump_check_end(buf, len); ++ if (ret == 1) { ++ STP_DBG_INFO_FUNC("core dump end!\n"); ++ dmp->sm = CORE_DUMP_DONE; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } else { ++ dmp->sm = CORE_DUMP_DOING; ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ } ++ break; ++ ++ case CORE_DUMP_DONE: ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); ++ wcn_compressor_in(dmp->compressor, buf, len, 0); ++ dmp->sm = CORE_DUMP_DOING; ++ break; ++ ++ case CORE_DUMP_TIMEOUT: ++ break; ++ default: ++ break; ++ } ++ ++ osal_unlock_sleepable_lock(&dmp->dmp_lock); ++ ++ return ret; ++} ++ ++/* wcn_core_dump_out - get compressed data from compressor buffer ++ * @ dmp - pointer of object ++ * @ pbuf - target buffer's pointer ++ * @ len - data length ++ * ++ * Retunr 0 if success; else error code ++ */ ++INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 plen) ++{ ++ INT32 ret = 0; ++ ++ if ((!dmp) || (!pbuf) || (!plen)) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ ret = osal_lock_sleepable_lock(&dmp->dmp_lock); ++ if (ret) { ++ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ ret = wcn_compressor_out(dmp->compressor, pbuf, plen); ++ ++ osal_unlock_sleepable_lock(&dmp->dmp_lock); ++ ++ return ret; ++} ++ ++/* wcn_core_dump_reset - reset core dump sys ++ * @ dmp - pointer of object ++ * @ timeout - core dump time out value ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout) ++{ ++ if (!dmp) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ dmp->sm = CORE_DUMP_INIT; ++ dmp->timeout = timeout; ++ osal_timer_stop(&dmp->dmp_timer); ++ wcn_compressor_reset(dmp->compressor, 1, GZIP); ++ osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1); ++ ++ wcn_core_dump_deinit(dmp); ++ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); ++ ++ return 0; ++} ++ ++/* wcn_wmtd_timeout_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define WMTD_TIMEOUT_INFO_HEAD "Wait wmtd complation timeout ,just collect SYS_FTRACE to DB" ++INT32 wcn_wmtd_timeout_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Wait wmtd complation timeout"; ++ len = osal_strlen("Wait wmtd complation timeout"); ++ osal_strcpy(&g_core_dump->info[0], WMTD_TIMEOUT_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++/* wcn_psm_flag_trigger_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define PSM_ABNORMAL_FLAG_INFO_HEAD "Abnormal PSM flag be set ,just collect SYS_FTRACE to DB" ++INT32 wcn_psm_flag_trigger_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Abnormal PSM flag be set"; ++ len = osal_strlen("Abnormal PSM flag be set"); ++ osal_strcpy(&g_core_dump->info[0], PSM_ABNORMAL_FLAG_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++#if BTIF_RXD_BE_BLOCKED_DETECT ++MTK_WCN_BOOL is_btif_rxd_be_blocked(void) ++{ ++ MTK_WCN_BOOL flag = MTK_WCN_BOOL_FALSE; ++ ++ if (mtk_btif_rxd_be_blocked_flag_get()) ++ flag = MTK_WCN_BOOL_TRUE; ++ return flag; ++} ++/* wcn_btif_rxd_blocked_collect_ftrace - btif rxd be blocked,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define BTIF_RXD_BLOCKED_INFO_HEAD "Btif_rxd thread be blocked too long,just collect SYS_FTRACE to DB" ++INT32 wcn_btif_rxd_blocked_collect_ftrace(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Btif_rxd thread be blocked too long"; ++ len = osal_strlen("Btif_rxd thread be blocked too long"); ++ osal_strcpy(&g_core_dump->info[0], BTIF_RXD_BLOCKED_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++#endif ++/* wcn_core_dump_timeout - wait for FW assert info timeout ,this func can collect SYS_FTRACE ++ * ++ * Retunr 0 if success ++ */ ++#define TIMEOUT_INFO_HEAD "Trigger assert timeout ,just collect SYS_FTRACE to DB" ++INT32 wcn_core_dump_timeout(void) ++{ ++ PUINT8 pbuf; ++ INT32 len; ++ ++ pbuf = "Trigger assert timeout"; ++ len = osal_strlen("Trigger assert timeout"); ++ osal_strcpy(&g_core_dump->info[0], TIMEOUT_INFO_HEAD); ++#ifdef WMT_PLAT_ALPS ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ return 0; ++} ++ ++#define ENABLE_F_TRACE 0 ++/* wcn_core_dump_flush - Fulsh dump data and reset core dump sys ++ * ++ * Retunr 0 if success, else error code ++ */ ++INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout) ++{ ++ PUINT8 pbuf = NULL; ++ INT32 len = 0; ++ ++ if (!g_core_dump) { ++ STP_DBG_ERR_FUNC("invalid pointer!\n"); ++ return -1; ++ } ++ ++ wcn_core_dump_out(g_core_dump, &pbuf, &len); ++ STP_DBG_INFO_FUNC("buf 0x%zx, len %d\n", (SIZE_T) pbuf, len); ++#ifdef WMT_PLAT_ALPS ++ /* show coredump end info on UI */ ++ /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */ ++#if STP_DBG_AEE_EXP_API ++ if (coredump_is_timeout) ++ aee_kernel_dal_show("++ SOC_CONSYS coredump tiemout ,pass received coredump to AEE ++\n"); ++ else ++ aee_kernel_dal_show("++ SOC_CONSYS coredump get successfully ++\n"); ++ /* call AEE driver API */ ++#if ENABLE_F_TRACE ++ aed_combo_exception_api(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info, DB_OPT_FTRACE); ++#else ++ aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); ++#endif ++ ++#endif ++ ++#endif // WMT_PLAT_ALPS ++ ++ /* reset */ ++ wcn_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT); ++ ++ return 0; ++} ++ ++static INT32 wcn_gzip_compressor(void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, ++ INT32 finish) ++{ ++ INT32 ret = 0; ++ z_stream *stream = NULL; ++ INT32 tmp = *out_sz; ++ ++ STP_DBG_INFO_FUNC("need to compressor :buf 0x%zx, size %d\n", (SIZE_T) in_buf, in_sz); ++ STP_DBG_INFO_FUNC("before compressor,avalible buf: 0x%zx, size %d\n", (SIZE_T) out_buf, tmp); ++ ++ stream = (z_stream *) worker; ++ if (!stream) { ++ STP_DBG_ERR_FUNC("invalid workspace!\n"); ++ return -1; ++ } ++ ++ if (in_sz > 0) { ++#if 0 ++ ret = zlib_deflateReset(stream); ++ if (ret != Z_OK) { ++ STP_DBG_ERR_FUNC("reset failed!\n"); ++ return -2; ++ } ++#endif ++ ++ stream->next_in = in_buf; ++ stream->avail_in = in_sz; ++ stream->next_out = out_buf; ++ stream->avail_out = tmp; ++ ++ zlib_deflate(stream, Z_FULL_FLUSH); ++ ++ if (finish) { ++ while (1) { ++ int val = zlib_deflate(stream, Z_FINISH); ++ ++ if (val == Z_OK) ++ continue; ++ else if (val == Z_STREAM_END) ++ break; ++ STP_DBG_ERR_FUNC("finish operation failed %d\n", val); ++ return -3; ++ } ++ } ++ ++ *out_sz = tmp - stream->avail_out; ++ } ++ ++ STP_DBG_INFO_FUNC("after compressor,avalible buf: 0x%zx, compress rate %d -> %d\n", (SIZE_T) out_buf, in_sz, ++ *out_sz); ++ ++ return ret; ++} ++ ++/* wcn_compressor_init - create a compressor and do init ++ * @ name - compressor's name ++ * @ L1_buf_sz - L1 buffer size ++ * @ L2_buf_sz - L2 buffer size ++ * ++ * Retunr object's pointer if success, else NULL ++ */ ++P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz) ++{ ++ z_stream *pstream = NULL; ++ P_WCN_COMPRESSOR_T compress = NULL; ++ ++ compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T)); ++ if (!compress) { ++ STP_DBG_ERR_FUNC("alloc compressor failed!\n"); ++ goto fail; ++ } ++ ++ osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T)); ++ osal_memcpy(compress->name, name, STP_OJB_NAME_SZ); ++ ++ compress->f_compress_en = 0; ++ compress->compress_type = GZIP; ++ ++ if (compress->compress_type == GZIP) { ++ compress->worker = osal_malloc(sizeof(z_stream)); ++ if (!compress->worker) { ++ STP_DBG_ERR_FUNC("alloc stream failed!\n"); ++ goto fail; ++ } ++ pstream = (z_stream *) compress->worker; ++ ++ pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); ++ if (!pstream->workspace) { ++ STP_DBG_ERR_FUNC("alloc workspace failed!\n"); ++ goto fail; ++ } ++ zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, ++ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); ++ } ++ ++ compress->handler = wcn_gzip_compressor; ++ compress->L1_buf_sz = L1_buf_sz; ++ compress->L2_buf_sz = L2_buf_sz; ++ compress->L1_pos = 0; ++ compress->L2_pos = 0; ++ compress->uncomp_size = 0; ++ compress->crc32 = 0xffffffffUL; ++ ++ compress->L1_buf = osal_malloc(compress->L1_buf_sz); ++ if (!compress->L1_buf) { ++ STP_DBG_ERR_FUNC("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz); ++ goto fail; ++ } ++ ++ compress->L2_buf = osal_malloc(compress->L2_buf_sz); ++ if (!compress->L2_buf) { ++ STP_DBG_ERR_FUNC("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz); ++ goto fail; ++ } ++ ++ STP_DBG_INFO_FUNC("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz); ++ return compress; ++ ++fail: ++ if (compress) { ++ if (compress->L2_buf) { ++ osal_free(compress->L2_buf); ++ compress->L2_buf = NULL; ++ } ++ ++ if (compress->L1_buf) { ++ osal_free(compress->L1_buf); ++ compress->L1_buf = NULL; ++ } ++ ++ if (compress->worker) { ++ pstream = (z_stream *) compress->worker; ++ if ((compress->compress_type == GZIP) && pstream->workspace) { ++ zlib_deflateEnd(pstream); ++ osal_free(pstream->workspace); ++ } ++ osal_free(compress->worker); ++ compress->worker = NULL; ++ } ++ ++ if (compress->worker) { ++ osal_free(compress->worker); ++ compress->worker = NULL; ++ } ++ ++ osal_free(compress); ++ compress = NULL; ++ } ++ ++ STP_DBG_ERR_FUNC("init failed!\n"); ++ ++ return NULL; ++} ++ ++/* wcn_compressor_deinit - distroy a compressor ++ * @ cprs - compressor's pointer ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T cprs) ++{ ++ z_stream *pstream = NULL; ++ ++ if (cprs) { ++ if (cprs->L2_buf) { ++ osal_free(cprs->L2_buf); ++ cprs->L2_buf = NULL; ++ } ++ ++ if (cprs->L1_buf) { ++ osal_free(cprs->L1_buf); ++ cprs->L1_buf = NULL; ++ } ++ ++ if (cprs->worker) { ++ pstream = (z_stream *) cprs->worker; ++ if ((cprs->compress_type == GZIP) && pstream->workspace) { ++ zlib_deflateEnd(pstream); ++ osal_free(pstream->workspace); ++ } ++ osal_free(cprs->worker); ++ cprs->worker = NULL; ++ } ++ ++ cprs->handler = NULL; ++ ++ osal_free(cprs); ++ } ++ ++ STP_DBG_INFO_FUNC("destroy OK\n"); ++ ++ return 0; ++} ++ ++/* wcn_compressor_in - put in a raw data, and compress L1 buffer if need ++ * @ cprs - compressor's pointer ++ * @ buf - raw data buffer ++ * @ len - raw data length ++ * @ finish - core dump finish or not, 1: finished; 0: not finish ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, INT32 finish) ++{ ++ INT32 tmp_len = 0; ++ INT32 ret = 0; ++ ++ if (!cprs) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ ++ cprs->uncomp_size += len; ++ ++ /* check L1 buf valid space */ ++ if (len > (cprs->L1_buf_sz - cprs->L1_pos)) { ++ STP_DBG_INFO_FUNC("L1 buffer full\n"); ++ ++ if (cprs->f_compress_en && cprs->handler) { ++ /* need compress */ ++ /* compress L1 buffer, and put result to L2 buffer */ ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ ret = ++ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], ++ &tmp_len, finish); ++ if (!ret) { ++ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); ++ cprs->L2_pos += tmp_len; ++ if (cprs->L2_pos > cprs->L2_buf_sz) ++ STP_DBG_ERR_FUNC("coredump size too large(%d), L2 buf overflow\n", ++ cprs->L2_pos); ++ ++ if (finish) { ++ /* Add 8 byte suffix ++ === ++ 32 bits UNCOMPRESS SIZE ++ 32 bits CRC ++ */ ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; ++ cprs->L2_pos += 8; ++ } ++ STP_DBG_INFO_FUNC("compress OK!\n"); ++ } else ++ STP_DBG_ERR_FUNC("compress error!\n"); ++ } else { ++ /* no need compress */ ++ /* Flush L1 buffer to L2 buffer */ ++ STP_DBG_INFO_FUNC("No need do compress, Put to L2 buf\n"); ++ ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; ++ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); ++ cprs->L2_pos += tmp_len; ++ } ++ ++ /* reset L1 buf pos */ ++ cprs->L1_pos = 0; ++ ++ /* put curren data to L1 buf */ ++ if (len > cprs->L1_buf_sz) { ++ STP_DBG_ERR_FUNC("len=%d, too long err!\n", len); ++ } else { ++ STP_DBG_INFO_FUNC("L1 Flushed, and Put %d bytes to L1 buf\n", len); ++ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); ++ cprs->L1_pos += len; ++ } ++ } else { ++ /* put to L1 buffer */ ++ STP_DBG_INFO_FUNC("Put %d bytes to L1 buf\n", len); ++ ++ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); ++ cprs->L1_pos += len; ++ } ++ ++ return ret; ++} ++ ++/* wcn_compressor_out - get the result data from L2 buffer ++ * @ cprs - compressor's pointer ++ * @ pbuf - point to L2 buffer ++ * @ plen - out len ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T cprs, PUINT8 *pbuf, PINT32 plen) ++{ ++ INT32 ret = 0; ++ INT32 tmp_len = 0; ++ ++ if ((!cprs) || (!pbuf) || (!plen)) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ /* check if there's L1 data need flush to L2 buffer */ ++ if (cprs->L1_pos > 0) { ++ tmp_len = cprs->L2_buf_sz - cprs->L2_pos; ++ ++ if (cprs->f_compress_en && cprs->handler) { ++ /* need compress */ ++ ret = ++ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], ++ &tmp_len, 1); ++ ++ if (!ret) { ++ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); ++ cprs->L2_pos += tmp_len; ++ ++ /* Add 8 byte suffix ++ === ++ 32 bits UNCOMPRESS SIZE ++ 32 bits CRC ++ */ ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); ++ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; ++ cprs->L2_pos += 8; ++ ++ STP_DBG_INFO_FUNC("compress OK!\n"); ++ } else { ++ STP_DBG_ERR_FUNC("compress error!\n"); ++ } ++ } else { ++ /* no need compress */ ++ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; ++ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); ++ cprs->L2_pos += tmp_len; ++ } ++ ++ cprs->L1_pos = 0; ++ } ++ ++ *pbuf = cprs->L2_buf; ++ *plen = cprs->L2_pos; ++ ++ STP_DBG_INFO_FUNC("0x%zx, len %d\n", (SIZE_T)*pbuf, *plen); ++ ++ return 0; ++} ++ ++/* wcn_compressor_reset - reset compressor ++ * @ cprs - compressor's pointer ++ * @ enable - enable/disable compress ++ * @ type - compress algorithm ++ * ++ * Retunr 0 if success, else NULL ++ */ ++INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type) ++{ ++ if (!cprs) { ++ STP_DBG_ERR_FUNC("invalid para!\n"); ++ return -1; ++ } ++ ++ cprs->f_compress_en = enable; ++ /* cprs->f_compress_en = 0; // disable compress for test */ ++ cprs->compress_type = type; ++ cprs->L1_pos = 0; ++ cprs->L2_pos = 0; ++ cprs->uncomp_size = 0; ++ cprs->crc32 = 0xffffffffUL; ++ ++ /* zlib_deflateEnd((z_stream*)cprs->worker); */ ++ ++ STP_DBG_INFO_FUNC("OK! compress algorithm %d\n", type); ++ ++ return 0; ++} ++ ++static void stp_dbg_dump_data(unsigned char *pBuf, char *title, int len) ++{ ++ int k = 0; ++ ++ pr_debug(" %s-len:%d\n", title, len); ++ ++ for (k = 0; k < len; k++) { ++ if (k % 16 == 0 && k != 0) ++ pr_cont("\n "); ++ pr_cont("0x%02x ", pBuf[k]); ++ } ++ pr_debug("--end\n"); ++} ++ ++static int _stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ stp_dbg->pkt_trace_no = 0; ++ stp_dbg->is_enable = 1; ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++static int _stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ stp_dbg->pkt_trace_no = 0; ++ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); ++ stp_dbg->is_enable = 0; ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++static int _stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) ++{ ++ unsigned long flags; ++ STP_DBG_HDR_T *pHdr = NULL; ++ char *pBuf = NULL; ++ unsigned int length = 0; ++ unsigned int internalFlag = stp_dbg->logsys->size < STP_DBG_LOG_ENTRY_NUM; ++ /* #ifdef CONFIG_LOG_STP_INTERNAL */ ++ /* Here we record log in this circle buffer, if buffer is full , ++ select to overlap earlier log, logic should be okay */ ++ internalFlag = 1; ++ /* #endif */ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ ++ if (internalFlag) { ++ stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0; ++ stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len; ++ memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), ++ 0, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); ++ memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), ++ buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); ++ ++ stp_dbg->logsys->size++; ++ stp_dbg->logsys->size = ++ (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ? STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size; ++ ++ if (0 != gStpDbgLogOut) { ++ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]); ++ pBuf = (char *)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) + sizeof(STP_DBG_HDR_T); ++ length = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T); ++ pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", ++ pHdr->sec, ++ pHdr->usec, ++ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", ++ gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); ++ if (0 < length) ++ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", length); ++ } ++ stp_dbg->logsys->in = ++ (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1); ++ STP_DBG_DBG_FUNC("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in); ++ } else { ++ STP_DBG_WARN_FUNC("logsys FULL!\n"); ++ } ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++int stp_gdb_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg) ++{ ++ int retval = 0; ++/* #ifndef CONFIG_LOG_STP_INTERNAL */ ++ ++ if (stp_dbg->btm != NULL) ++ retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm); ++/* #endif */ ++ ++ return retval; ++} ++ ++int stp_dbg_log_ctrl(unsigned int on) ++{ ++ if (on != 0) { ++ gStpDbgLogOut = 1; ++ pr_debug("STP-DBG: enable pkt log dump out.\n"); ++ } else { ++ gStpDbgLogOut = 0; ++ pr_debug("STP-DBG: disable pkt log dump out.\n"); ++ } ++ return 0; ++} ++ ++int stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) ++{ ++ return _stp_dbg_dmp_in(stp_dbg, buf, len); ++} ++ ++int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg) ++{ ++#define MAX_DMP_NUM 80 ++ unsigned long flags; ++ char *pBuf = NULL; ++ int len = 0; ++ STP_DBG_HDR_T *pHdr = NULL; ++ UINT32 dumpSize = 0; ++ UINT32 inIndex = 0; ++ UINT32 outIndex = 0; ++ ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ /* Not to dequeue from loging system */ ++ inIndex = stp_dbg->logsys->in; ++ dumpSize = stp_dbg->logsys->size; ++ if (STP_DBG_LOG_ENTRY_NUM == dumpSize) ++ outIndex = inIndex; ++ else ++ outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM; ++ ++ if (dumpSize > MAX_DMP_NUM) { ++ ++ outIndex += (dumpSize - MAX_DMP_NUM); ++ outIndex %= STP_DBG_LOG_ENTRY_NUM; ++ dumpSize = MAX_DMP_NUM; ++ ++ } ++ STP_DBG_INFO_FUNC("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); ++ while (dumpSize > 0) { ++ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[outIndex].buffer[0]); ++ pBuf = &(stp_dbg->logsys->queue[outIndex].buffer[0]) + sizeof(STP_DBG_HDR_T); ++ len = stp_dbg->logsys->queue[outIndex].len - sizeof(STP_DBG_HDR_T); ++ len = len > STP_PKT_SZ ? STP_PKT_SZ : len; ++ pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", ++ pHdr->sec, ++ pHdr->usec, ++ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", ++ gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); ++ ++ if (0 < len) ++ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len); ++ outIndex = (outIndex >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (outIndex + 1); ++ dumpSize--; ++ ++ } ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return 0; ++} ++ ++int stp_dbg_dmp_out_ex(char *buf, int *len) ++{ ++ return stp_dbg_dmp_out(g_stp_dbg, buf, len); ++} ++ ++int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len) ++{ ++ ++ unsigned long flags; ++ int remaining = 0; ++ *len = 0; ++ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); ++ ++ if (stp_dbg->logsys->size > 0) { ++ memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]), ++ stp_dbg->logsys->queue[stp_dbg->logsys->out].len); ++ ++ (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len; ++ stp_dbg->logsys->out = ++ (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->out + 1); ++ stp_dbg->logsys->size--; ++ ++ STP_DBG_DBG_FUNC("logsys size = %d, out = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->out); ++ } else { ++ STP_DBG_LOUD_FUNC("logsys EMPTY!\n"); ++ } ++ ++ remaining = (stp_dbg->logsys->size == 0) ? (0) : (1); ++ ++ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); ++ ++ return remaining; ++} ++ ++static int stp_dbg_fill_hdr(struct stp_dbg_pkt_hdr *hdr, int type, int ack, int seq, int crc, int dir, int len, ++ int dbg_type) ++{ ++ ++ struct timeval now; ++ ++ if (!hdr) { ++ STP_DBG_ERR_FUNC("function invalid\n"); ++ return -EINVAL; ++ } ++ do_gettimeofday(&now); ++ hdr->dbg_type = dbg_type; ++ hdr->ack = ack; ++ hdr->seq = seq; ++ hdr->sec = now.tv_sec; ++ hdr->usec = now.tv_usec; ++ hdr->crc = crc; ++ hdr->dir = dir; /* rx */ ++ hdr->dmy = 0xffffffff; ++ hdr->len = len; ++ hdr->type = type; ++ return 0; ++ ++} ++ ++static int stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, struct stp_dbg_pkt_hdr *hdr, const unsigned char *body) ++{ ++ /* fix the frame size large issues. */ ++ static struct stp_dbg_pkt stp_pkt; ++ uint32_t hdr_sz = sizeof(struct stp_dbg_pkt_hdr); ++ uint32_t body_sz = 0; ++ ++ BUG_ON(!stp_dbg); ++ ++ if (hdr->dbg_type == STP_DBG_PKT) ++ body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ); ++ else ++ body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ); ++ ++ hdr->no = stp_dbg->pkt_trace_no++; ++ memcpy((uint8_t *) &stp_pkt.hdr, (uint8_t *) hdr, hdr_sz); ++ if (body != NULL) ++ memcpy((uint8_t *) &stp_pkt.raw[0], body, body_sz); ++ ++ _stp_dbg_dmp_in(stp_dbg, (char *)&stp_pkt, hdr_sz + body_sz); ++ /* Only FW DMP MSG should inform BTM-CORE to dump packet to native process */ ++ if (hdr->dbg_type == STP_DBG_FW_DMP) ++ stp_gdb_notify_btm_dmp_wq(stp_dbg); ++ ++ return 0; ++} ++ ++int stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, int dbg_type, ++ int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body) ++{ ++ ++ struct stp_dbg_pkt_hdr hdr; ++ ++ if (stp_dbg->is_enable == 0) { ++ /*dbg is disable,and not to log */ ++ } else { ++ hdr.no = 0; ++ hdr.chs = 0; ++ stp_dbg_fill_hdr(&hdr, ++ (int)type, (int)ack_no, (int)seq_no, (int)crc, (int)dir, (int)len, (int)dbg_type); ++ ++ stp_dbg_add_pkt(stp_dbg, &hdr, body); ++ } ++ ++ return 0; ++} ++ ++int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) ++{ ++ return _stp_dbg_enable(stp_dbg); ++} ++ ++int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) ++{ ++ return _stp_dbg_disable(stp_dbg); ++} ++ ++static void stp_dbg_nl_init(void) ++{ ++#if 0 ++ if (genl_register_family(&stp_dbg_gnl_family) != 0) { ++ STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); ++ } else { ++ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0) ++ STP_DBG_ERR_FUNC("%s(): BIND operation registration fail\n", __func__); ++ ++ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0) ++ STP_DBG_ERR_FUNC("%s(): RESET operation registration fail\n", __func__); ++ ++ } ++#endif ++ if (genl_register_family_with_ops(&stp_dbg_gnl_family, stp_dbg_gnl_ops_array) != 0) ++ STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); ++} ++ ++static void stp_dbg_nl_deinit(void) ++{ ++ genl_unregister_family(&stp_dbg_gnl_family); ++} ++ ++static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct nlattr *na; ++ char *mydata; ++ ++ if (info == NULL) ++ goto out; ++ ++ STP_DBG_INFO_FUNC("%s():->\n", __func__); ++ ++ na = info->attrs[STP_DBG_ATTR_MSG]; ++ ++ if (na) ++ mydata = (char *)nla_data(na); ++ ++ if (num_bind_process < MAX_BIND_PROCESS) { ++ bind_pid[num_bind_process] = info->snd_portid; ++ num_bind_process++; ++ STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_portid); ++ } else { ++ STP_DBG_ERR_FUNC("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS); ++ } ++ ++out: ++ return 0; ++} ++ ++static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info) ++{ ++ STP_DBG_ERR_FUNC("%s(): should not be invoked\n", __func__); ++ ++ return 0; ++} ++ ++INT8 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len) ++{ ++ struct sk_buff *skb = NULL; ++ void *msg_head = NULL; ++ int rc = -1; ++ int i; ++ ++ if (num_bind_process == 0) { ++ /* no listening process */ ++ STP_DBG_ERR_FUNC("%s(): the process is not invoked\n", __func__); ++ return 0; ++ } ++ ++ for (i = 0; i < num_bind_process; i++) { ++ skb = genlmsg_new(2048, GFP_KERNEL); ++ ++ if (skb) { ++ msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd); ++ if (msg_head == NULL) { ++ nlmsg_free(skb); ++ STP_DBG_ERR_FUNC("%s(): genlmsg_put fail...\n", __func__); ++ return -1; ++ } ++ ++ rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg); ++ if (rc != 0) { ++ nlmsg_free(skb); ++ STP_DBG_ERR_FUNC("%s(): nla_put_string fail...%d\n", __func__, rc); ++ return -1; ++ } ++ ++ /* finalize the message */ ++ genlmsg_end(skb, msg_head); ++ ++ /* sending message */ ++ rc = genlmsg_unicast(&init_net, skb, bind_pid[i]); ++ if (rc != 0) { ++ STP_DBG_ERR_FUNC("%s(): genlmsg_unicast fail...\n", __func__); ++ return -1; ++ } ++ } else { ++ STP_DBG_ERR_FUNC("%s(): genlmsg_new fail...\n", __func__); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd) ++{ ++ INT32 ret = 0; ++ ++ /* buffered to compressor */ ++ ret = wcn_core_dump_in(g_core_dump, aucMsg, len); ++ if (ret == 1) ++ wcn_core_dump_flush(0, MTK_WCN_BOOL_FALSE); ++ ++ return ret; ++} ++ ++UINT8 *_stp_dbg_id_to_task(UINT32 id) ++{ ++ UINT8 *taskStr[] = { ++ "Task_WMT", ++ "Task_BT", ++ "Task_Wifi", ++ "Task_Tst", ++ "Task_FM", ++ "Task_Idle", ++ "Task_DrvStp", ++ "Task_DrvBtif", ++ "Task_NatBt" ++ }; ++ return taskStr[id]; ++} ++ ++INT32 _stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type) ++{ ++ char *pStr = NULL; ++ char *pDtr = NULL; ++ char *pTemp = NULL; ++ char *pTemp2 = NULL; ++ char tempBuf[64] = { 0 }; ++ UINT32 len = 0; ++ long res; ++ INT32 ret; ++ ++ PUINT8 parser_sub_string[] = { ++ " ", ++ "id=", ++ "isr=", ++ "irq=", ++ "rc=" ++ }; ++ ++ if (!str) { ++ STP_DBG_ERR_FUNC("NULL string source\n"); ++ return -1; ++ } ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -2; ++ } ++ ++ pStr = str; ++ STP_DBG_DBG_FUNC("source infor:%s\n", pStr); ++ switch (type) { ++ case STP_DBG_ASSERT_INFO: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ' '); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@")); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len); ++ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_'; ++ ++ pTemp = osal_strchr(pDtr, '#'); ++ pTemp += 1; ++ ++ pTemp2 = osal_strchr(pTemp, ' '); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp, pTemp2 - pTemp); ++ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0'; ++ STP_DBG_INFO_FUNC("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]); ++ break; ++ case STP_DBG_FW_TASK_ID: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ' '); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw task id :%x\n", (UINT32)res); ++ break; ++ case STP_DBG_FW_ISR: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw isr id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwIsr = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw isr str:%x\n", (UINT32)res); ++ break; ++ case STP_DBG_FW_IRQ: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw irq id fail(%d)\n", ret); ++ return -4; ++ } ++ g_stp_dbg_cpupcr->fwRrq = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("fw irq value:%x\n", (UINT32)res); ++ break; ++ case STP_DBG_ASSERT_TYPE: ++ pDtr = osal_strstr(pStr, parser_sub_string[type]); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen(parser_sub_string[type]); ++ pTemp = osal_strchr(pDtr, ','); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); ++ return -3; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ++ if (0 == osal_memcmp(tempBuf, "*", len)) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert", osal_strlen("general assert")); ++ if (0 == osal_memcmp(tempBuf, "Watch Dog Timeout", len)) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt")); ++ if (0 == osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL"))) { ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len); ++ ++ pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL("); ++ if (NULL != pDtr) { ++ pDtr += osal_strlen("RB_FULL("); ++ pTemp = osal_strchr(pDtr, ')'); ++ } else { ++ STP_DBG_ERR_FUNC("parser str is NULL,substring(RB_FULL()\n"); ++ return -4; ++ } ++ len = pTemp - pDtr; ++ osal_memcpy(&tempBuf[0], pDtr, len); ++ tempBuf[len] = '\0'; ++ ret = osal_strtol(tempBuf, 16, &res); ++ if (ret) { ++ STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); ++ return -5; ++ } ++ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; ++ ++ STP_DBG_INFO_FUNC("update fw task id :%x\n", (UINT32)res); ++ } ++ ++ STP_DBG_INFO_FUNC("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type); ++ break; ++ default: ++ STP_DBG_ERR_FUNC("unknown parser type\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID) ++{ ++ P_STP_DBG_CPUPCR_T pSdCpupcr = NULL; ++ ++ pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T)); ++ if (!pSdCpupcr) { ++ STP_DBG_ERR_FUNC("stp dbg cpupcr allocate memory fail!\n"); ++ return NULL; ++ } ++ ++ osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T)); ++ ++ osal_sleepable_lock_init(&pSdCpupcr->lock); ++ ++ return pSdCpupcr; ++} ++ ++P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID) ++{ ++ P_STP_DBG_DMAREGS_T pDmaRegs = NULL; ++ ++ pDmaRegs = (P_STP_DBG_DMAREGS_T) osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T)); ++ if (!pDmaRegs) { ++ STP_DBG_ERR_FUNC("stp dbg dmareg allocate memory fail!\n"); ++ return NULL; ++ } ++ ++ osal_memset(pDmaRegs, 0, osal_sizeof(STP_DBG_DMAREGS_T)); ++ ++ osal_sleepable_lock_init(&pDmaRegs->lock); ++ ++ return pDmaRegs; ++} ++ ++VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr) ++{ ++ if (pCpupcr) { ++ osal_sleepable_lock_deinit(&pCpupcr->lock); ++ osal_free(pCpupcr); ++ pCpupcr = NULL; ++ } ++} ++ ++VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs) ++{ ++ if (pDmaRegs) { ++ osal_sleepable_lock_deinit(&pDmaRegs->lock); ++ osal_free(pDmaRegs); ++ pDmaRegs = NULL; ++ } ++} ++ ++INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd) ++{ ++ INT32 i = 0; ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL reference pointer\n"); ++ return -1; ++ } ++ ++ if (!cmd) { ++ if (g_stp_dbg_cpupcr->count + times > STP_DBG_CPUPCR_NUM) ++ times = STP_DBG_CPUPCR_NUM - g_stp_dbg_cpupcr->count; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ for (i = 0; i < times; i++) { ++ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); ++ /* osal_memcpy( ++ * &g_stp_dbg_cpupcr->buffer[i], ++ * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), ++ * osal_sizeof(UINT32)); ++ */ ++ g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count + i] = wmt_plat_read_cpupcr(); ++ osal_sleep_ms(sleep); ++ } ++ g_stp_dbg_cpupcr->count += times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_INFO_FUNC("stp-dbg: for proc test polling cpupcr\n"); ++ if (times > STP_DBG_CPUPCR_NUM) ++ times = STP_DBG_CPUPCR_NUM; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->count = 0; ++ for (i = 0; i < times; i++) { ++ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); ++ /* osal_memcpy( ++ * &g_stp_dbg_cpupcr->buffer[i], ++ * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), ++ * osal_sizeof(UINT32)); ++ */ ++ g_stp_dbg_cpupcr->buffer[i] = wmt_plat_read_cpupcr(); ++ osal_sleep_ms(sleep); ++ } ++ g_stp_dbg_cpupcr->count = times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ } ++ return 0; ++} ++ ++INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep) ++{ ++#if 0 ++ INT32 i = 0; ++ ++ if (!g_stp_dbg_dmaregs) { ++ STP_DBG_ERR_FUNC("NULL reference pointer\n"); ++ return -1; ++ } ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock); ++ ++ if (g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM) { ++ if (g_stp_dbg_dmaregs->count > STP_DBG_DMAREGS_NUM) { ++ STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count:%d must less than STP_DBG_DMAREGS_NUM:%d\n", ++ g_stp_dbg_dmaregs->count, STP_DBG_DMAREGS_NUM); ++ g_stp_dbg_dmaregs->count = 0; ++ STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count be set default value 0\n"); ++ } ++ times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count; ++ } ++ if (times > STP_DBG_DMAREGS_NUM) { ++ STP_DBG_ERR_FUNC("times overflow, set default value:0\n"); ++ times = 0; ++ } ++ STP_DBG_WARN_FUNC("---------Now Polling DMA relative Regs -------------\n"); ++ for (i = 0; i < times; i++) { ++ INT32 k = 0; ++ ++ for (; k < DMA_REGS_MAX; k++) { ++ STP_DBG_WARN_FUNC("times:%d,i:%d reg: %s, regs:%08x\n", times, i, dmaRegsStr[k], ++ wmt_plat_read_dmaregs(k)); ++ /* g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] = wmt_plat_read_dmaregs(k); */ ++ } ++ osal_sleep_ms(sleep); ++ } ++ STP_DBG_WARN_FUNC("---------Polling DMA relative Regs End-------------\n"); ++ g_stp_dbg_dmaregs->count += times; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock); ++#else ++ return 0; ++#endif ++} ++ ++INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en) ++{ ++ ++ STP_DBG_INFO_FUNC("%s polling cpupcr\n", en == 0 ? "start" : "stop"); ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->stop_flag = en; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ return 0; ++} ++ ++INT32 stp_dbg_set_version_info(UINT32 chipid, UINT8 *pRomVer, UINT8 *pPatchVer, UINT8 *pPatchBrh) ++{ ++ if (g_stp_dbg_cpupcr) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->chipId = chipid; ++ ++ if (pRomVer) ++ osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2); ++ if (pPatchVer) ++ osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8); ++ if (pPatchBrh) ++ osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4); ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("chipid(0x%x),romver(%s),patchver(%s),branchver(%s)\n", g_stp_dbg_cpupcr->chipId, ++ &g_stp_dbg_cpupcr->romVer[0], &g_stp_dbg_cpupcr->patchVer[0], &g_stp_dbg_cpupcr->branchVer[0]); ++ return 0; ++} ++INT32 stp_dbg_set_wifiver(UINT32 wifiver) ++{ ++ if (g_stp_dbg_cpupcr) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ g_stp_dbg_cpupcr->wifiVer = wifiver; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("wifiver(%x)\n", g_stp_dbg_cpupcr->wifiVer); ++ return 0; ++} ++ ++INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en) ++{ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en; ++ g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type; ++ g_stp_dbg_cpupcr->host_assert_info.reason = reason; ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ return 0; ++} ++ ++UINT32 stp_dbg_get_host_trigger_assert(VOID) ++{ ++ return g_stp_dbg_cpupcr->host_assert_info.assert_from_host; ++} ++ ++INT32 stp_dbg_set_fw_info(UINT8 *issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type) ++{ ++ ENUM_ASSERT_INFO_PARSER_TYPE type_index; ++ PUINT8 tempbuf = NULL; ++ UINT32 i = 0; ++ INT32 iRet = 0; ++ ++ if (NULL == issue_info) { ++ STP_DBG_ERR_FUNC("null issue infor\n"); ++ return -1; ++ } ++ STP_DBG_INFO_FUNC("issue type(%d)\n", issue_type); ++ g_stp_dbg_cpupcr->issue_type = issue_type; ++ osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE); ++ ++ /*print patch version when assert happened */ ++ STP_DBG_INFO_FUNC("=======================================\n"); ++ STP_DBG_INFO_FUNC("[consys patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer); ++ STP_DBG_INFO_FUNC("[consys patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer); ++ STP_DBG_INFO_FUNC("=======================================\n"); ++ ++ if ((STP_FW_ASSERT_ISSUE == issue_type) || ++ (STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { ++ if ((STP_FW_ASSERT_ISSUE == issue_type) || (STP_HOST_TRIGGER_FW_ASSERT == issue_type)) { ++ tempbuf = osal_malloc(len + 1); ++ if (!tempbuf) ++ return -2; ++ ++ osal_memcpy(&tempbuf[0], issue_info, len); ++ ++ for (i = 0; i < len; i++) { ++ if (tempbuf[i] == '\0') ++ tempbuf[i] = '?'; ++ } ++ ++ tempbuf[len] = '\0'; ++ ++ for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX; type_index++) ++ iRet += _stp_dbg_parser_assert_str(&tempbuf[0], type_index); ++ ++ if (iRet) ++ STP_DBG_ERR_FUNC("passert assert infor fail(%d)\n", iRet); ++ ++ } ++ if ((STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { ++ switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) { ++ case 0: ++ STP_DBG_INFO_FUNC("BT trigger assert\n"); ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ if (31 != g_stp_dbg_cpupcr->host_assert_info.reason) ++ /*BT firmware trigger assert */ ++ { ++ g_stp_dbg_cpupcr->fwTaskId = 1; ++ ++ } else ++ /*BT stack trigger assert */ ++ { ++ g_stp_dbg_cpupcr->fwTaskId = 8; ++ } ++ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; ++ /* g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; */ ++ /* g_stp_dbg_cpupcr->host_assert_info.reason = 0; */ ++ ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ break; ++ case 4: ++ STP_DBG_INFO_FUNC("WMT trigger assert\n"); ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ if (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type) ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ ++ if ((38 == g_stp_dbg_cpupcr->host_assert_info.reason) || ++ (39 == g_stp_dbg_cpupcr->host_assert_info.reason) || ++ (40 == g_stp_dbg_cpupcr->host_assert_info.reason)) ++ g_stp_dbg_cpupcr->fwTaskId = 6; /* HOST schedule reason trigger */ ++ else ++ g_stp_dbg_cpupcr->fwTaskId = 0; /* Must be firmware reason */ ++ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ break; ++ default: ++ break; ++ } ++ ++ } ++ osal_free(tempbuf); ++ } else if (STP_FW_NOACK_ISSUE == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 6; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else if (STP_DBG_PROC_TEST == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 0; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else if (STP_FW_WARM_RST_ISSUE == issue_type) { ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); ++ g_stp_dbg_cpupcr->fwTaskId = 0; ++ g_stp_dbg_cpupcr->fwRrq = 0; ++ g_stp_dbg_cpupcr->fwIsr = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ } else { ++ STP_DBG_ERR_FUNC("invalid issue type(%d)\n", issue_type); ++ return -3; ++ } ++ ++ return iRet; ++} ++ ++INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 str_len) ++{ ++ UINT32 len = 0; ++ UINT32 i = 0; ++ ++ if (!g_stp_dbg_cpupcr) { ++ STP_DBG_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ ++ /*format common information about issue */ ++ len = osal_sprintf(*buf, "
\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tMT%x\n\t\n\t", g_stp_dbg_cpupcr->chipId); ++ len += osal_sprintf(*buf + len, "\n\t\t"); ++ len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->romVer); ++ if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", strlen("ALPS")))) ++ len += osal_sprintf(*buf + len, "Internal Dev\n\t\t", g_stp_dbg_cpupcr->branchVer); ++ else ++ len += osal_sprintf(*buf + len, "W%sMP\n\t\t", g_stp_dbg_cpupcr->branchVer); ++ ++ len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->patchVer); ++ ++ if (0 == g_stp_dbg_cpupcr->wifiVer) ++ len += osal_sprintf(*buf + len, "NULL\n\t"); ++ else ++ len += osal_sprintf(*buf + len, "0x%X.%X\n\t", ++ (UINT8)((g_stp_dbg_cpupcr->wifiVer & 0xFF00)>>8), (UINT8)(g_stp_dbg_cpupcr->wifiVer & 0xFF)); ++ ++ len += osal_sprintf(*buf + len, "\n\t"); ++ ++ /*format issue information: no ack, assert */ ++ len += osal_sprintf(*buf + len, "\n\t\t\n\t\t\t"); ++ if ((STP_FW_NOACK_ISSUE == g_stp_dbg_cpupcr->issue_type) || ++ (STP_DBG_PROC_TEST == g_stp_dbg_cpupcr->issue_type) || ++ (STP_FW_WARM_RST_ISSUE == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", ++ g_stp_dbg_cpupcr->assert_info); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += ++ osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", ++ _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); ++ len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); ++ len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } else if ((STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", ++ g_stp_dbg_cpupcr->assert_info); ++ len += osal_sprintf(*buf + len, "%s\n\t\t\n\t\n\t", g_stp_dbg_cpupcr->assert_type); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += ++ osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", ++ _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); ++ if (32 == g_stp_dbg_cpupcr->host_assert_info.reason || 33 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 34 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 35 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 36 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 37 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 38 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 39 == g_stp_dbg_cpupcr->host_assert_info.reason ++ || 40 == g_stp_dbg_cpupcr->host_assert_info.reason) { ++ /*handling wmt turn on/off bt cmd has ack but no evt issue */ ++ /*one of both the irqx and irs is nULL, then use task to find MOF */ ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } else { ++ len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); ++ } ++ len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); ++ ++ if (STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) { ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } ++ ++ if ((STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || ++ (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { ++ len += ++ osal_sprintf(*buf + len, "%d\n\t\t\t", ++ g_stp_dbg_cpupcr->host_assert_info.drv_type); ++ len += ++ osal_sprintf(*buf + len, "%d\n\t\t\t", ++ g_stp_dbg_cpupcr->host_assert_info.reason); ++ } ++ } else { ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\t\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); ++ len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t"); ++ len += osal_sprintf(*buf + len, "\n\t\t\tNULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); ++ } ++ ++ len += osal_sprintf(*buf + len, ""); ++ STP_DBG_INFO_FUNC("stp-dbg:sub len1 for debug(%d)\n", len); ++ ++ if (!g_stp_dbg_cpupcr->count) ++ len += osal_sprintf(*buf + len, "NULL"); ++ else { ++ for (i = 0; i < g_stp_dbg_cpupcr->count; i++) ++ len += osal_sprintf(*buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]); ++ } ++ STP_DBG_INFO_FUNC("stp-dbg:sub len2 for debug(%d)\n", len); ++ len += osal_sprintf(*buf + len, "\n\t\t\t"); ++ len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n
\n"); ++ STP_DBG_INFO_FUNC("buffer len[%d]\n", len); ++ /* STP_DBG_INFO_FUNC("Format infor:\n%s\n",*buf); */ ++ *str_len = len; ++ ++ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM); ++ g_stp_dbg_cpupcr->count = 0; ++ g_stp_dbg_cpupcr->host_assert_info.reason = 0; ++ g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; ++ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); ++ ++ return 0; ++ ++} ++ ++MTKSTP_DBG_T *stp_dbg_init(void *btm_half) ++{ ++ ++ MTKSTP_DBG_T *stp_dbg = NULL; ++ ++ STP_DBG_INFO_FUNC("stp-dbg init\n"); ++ ++ stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL); ++ if (stp_dbg == NULL) ++ goto ERR_EXIT1; ++ if (IS_ERR(stp_dbg)) { ++ STP_DBG_ERR_FUNC("-ENOMEM\n"); ++ goto ERR_EXIT1; ++ } ++ ++ stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T)); ++ if (stp_dbg->logsys == NULL) ++ goto ERR_EXIT2; ++ if (IS_ERR(stp_dbg->logsys)) { ++ STP_DBG_ERR_FUNC("-ENOMEM stp_gdb->logsys\n"); ++ goto ERR_EXIT2; ++ } ++ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); ++ spin_lock_init(&(stp_dbg->logsys->lock)); ++ stp_dbg->pkt_trace_no = 0; ++ stp_dbg->is_enable = 0; ++ g_stp_dbg = stp_dbg; ++ ++ if (btm_half != NULL) ++ stp_dbg->btm = btm_half; ++ else ++ stp_dbg->btm = NULL; ++ ++ ++ /* bind to netlink */ ++ stp_dbg_nl_init(); ++ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); ++ g_stp_dbg_cpupcr = stp_dbg_cpupcr_init(); ++ g_stp_dbg_dmaregs = stp_dbg_dmaregs_init(); ++ ++ return stp_dbg; ++ ++ERR_EXIT2: ++ kfree(stp_dbg); ++ return NULL; ++ ++ERR_EXIT1: ++ kfree(stp_dbg); ++ return NULL; ++} ++ ++int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg) ++{ ++ ++ STP_DBG_INFO_FUNC("stp-dbg deinit\n"); ++ ++ wcn_core_dump_deinit(g_core_dump); ++ ++ stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr); ++ stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs); ++ /* unbind with netlink */ ++ stp_dbg_nl_deinit(); ++ ++ if (stp_dbg->logsys) ++ vfree(stp_dbg->logsys); ++ ++ kfree(stp_dbg); ++ ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c +new file mode 100644 +index 000000000000..f7f4aff010d4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c +@@ -0,0 +1,279 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include /* udelay() */ ++ ++#include ++ ++ ++#include "osal_typedef.h" ++#include "stp_core.h" ++#include "stp_exp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static MTK_WCN_STP_IF_TX stp_uart_if_tx; ++static MTK_WCN_STP_IF_TX stp_sdio_if_tx; ++static MTK_WCN_STP_IF_TX stp_btif_if_tx; ++static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX; ++static MTK_WCN_STP_IF_RX stp_if_rx; ++static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; ++static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size) ++{ ++ if (stp_if_rx == 0x0) ++ return -1; ++ ++ (*stp_if_rx) (data, size); ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_if_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) ++{ ++ ++ if (STP_UART_IF_TX == g_stp_if_type) ++ return stp_uart_if_tx != NULL ? (*stp_uart_if_tx) (data, size, written_size) : -1; ++ else if (STP_SDIO_IF_TX == g_stp_if_type) ++ return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx) (data, size, written_size) : -1; ++ else if (STP_BTIF_IF_TX == g_stp_if_type) ++ return stp_btif_if_tx != NULL ? (*stp_btif_if_tx) (data, size, written_size) : -1; ++ /*if (g_stp_if_type >= STP_MAX_IF_TX) *//* George: remove ALWAYS TRUE condition */ ++ return -1; ++} ++ ++static INT32 mtk_wcn_sys_event_set(UINT8 function_type) ++{ ++ if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0)) { ++ (*event_callback_tbl[function_type]) (); ++ } else { ++ /* FIXME: error handling */ ++ pr_err("[%s] STP set event fail. It seems the function is not active.\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace) ++{ ++ int type = 0; ++ ++ for (type = 0; type < MTKSTP_MAX_TASK_NUM; type++) { ++ if (tx_event_callback_tbl[type]) ++ tx_event_callback_tbl[type] (); ++ } ++ ++ return 0; ++} ++ ++static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op) ++{ ++ ++ /* op == FUNCTION_ACTIVE, to check if funciton[type] is active ? */ ++ if (!(type < MTKSTP_MAX_TASK_NUM)) ++ return STATUS_FUNCTION_INVALID; ++ ++ if (op == OP_FUNCTION_ACTIVE) { ++ if (event_callback_tbl[type] != 0x0) ++ return STATUS_FUNCTION_ACTIVE; ++ else ++ return STATUS_FUNCTION_INACTIVE; ++ ++ } ++ /* you can define more operation here ..., to queury function's status/information */ ++ ++ return STATUS_OP_INVALID; ++} ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++#else ++INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) ++#endif ++{ ++ stp_if_rx = func; ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); ++#endif ++ ++VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type) ++{ ++ static const char * const ifType[] = { ++ "UART", ++ "SDIO", ++ "BTIF", ++ "UNKNOWN" ++ }; ++ g_stp_if_type = stp_if_type; ++ pr_debug("[%s] set STP_IF_TX to %s.\n", __func__, ifType[stp_if_type]); ++} ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++#else ++INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) ++#endif ++{ ++ if (STP_UART_IF_TX == stp_if) { ++ stp_uart_if_tx = func; ++ } else if (STP_SDIO_IF_TX == stp_if) { ++ stp_sdio_if_tx = func; ++ } else if (STP_BTIF_IF_TX == stp_if) { ++ stp_btif_if_tx = func; ++ } else { ++ pr_debug("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); ++ return -1; ++ } ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); ++#endif ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#else ++INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#endif ++{ ++ if (type < MTKSTP_MAX_TASK_NUM) { ++ event_callback_tbl[type] = func; ++ ++ /*clear rx queue */ ++ pr_debug("Flush type = %d Rx Queue\n", type); ++ mtk_wcn_stp_flush_rx_queue(type); ++ } ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); ++#endif ++ ++#if STP_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#else ++INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) ++#endif ++{ ++ if (type < MTKSTP_MAX_TASK_NUM) ++ tx_event_callback_tbl[type] = func; ++ else ++ BUG_ON(0); ++ ++ return 0; ++} ++#if !STP_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); ++#endif ++ ++INT32 stp_drv_init(VOID) ++{ ++ INT32 ret = 0; ++ ++ mtkstp_callback cb = { ++ .cb_if_tx = mtk_wcn_sys_if_tx, ++ .cb_event_set = mtk_wcn_sys_event_set, ++ .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume, ++ .cb_check_funciton_status = mtk_wcn_sys_check_function_status ++ }; ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ MTK_WCN_STP_EXP_CB_INFO stpExpCb = { ++ .stp_send_data_cb = _mtk_wcn_stp_send_data, ++ .stp_send_data_raw_cb = _mtk_wcn_stp_send_data_raw, ++ .stp_parser_data_cb = _mtk_wcn_stp_parser_data, ++ .stp_receive_data_cb = _mtk_wcn_stp_receive_data, ++ .stp_is_rxqueue_empty_cb = _mtk_wcn_stp_is_rxqueue_empty, ++ .stp_is_ready_cb = _mtk_wcn_stp_is_ready, ++ .stp_set_bluez_cb = _mtk_wcn_stp_set_bluez, ++ .stp_if_tx_cb = _mtk_wcn_stp_register_if_tx, ++ .stp_if_rx_cb = _mtk_wcn_stp_register_if_rx, ++ .stp_reg_event_cb = _mtk_wcn_stp_register_event_cb, ++ .stp_reg_tx_event_cb = _mtk_wcn_stp_register_tx_event_cb, ++ .stp_coredump_start_get_cb = _mtk_wcn_stp_coredump_start_get, ++ }; ++#endif ++ ++ ret = mtk_wcn_stp_init(&cb); ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_stp_exp_cb_reg(&stpExpCb); ++#endif ++ return ret; ++} ++ ++VOID stp_drv_exit(VOID) ++{ ++ mtk_wcn_stp_deinit(); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ mtk_wcn_stp_exp_cb_unreg(); ++#endif ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c +new file mode 100644 +index 000000000000..f70c88796f09 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c +@@ -0,0 +1,2566 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief brief description ++ ++ Detailed descriptions here. ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-DEV]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "osal_typedef.h" ++#include "osal.h" ++#include "wmt_dev.h" ++#include "wmt_core.h" ++#include "wmt_exp.h" ++#include "wmt_lib.h" ++#include "wmt_conf.h" ++#include "psm_core.h" ++#include "stp_core.h" ++#include "stp_exp.h" ++#include "bgw_desense.h" ++#include ++#include "wmt_idc.h" ++#ifdef CONFIG_COMPAT ++#include ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++#include ++#endif ++#define BUF_LEN_MAX 384 ++#include ++#ifdef CONFIG_COMPAT ++#define COMPAT_WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, compat_uptr_t) ++#define COMPAT_WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, compat_uptr_t) ++#endif ++ ++#define WMT_IOC_MAGIC 0xa0 ++#define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, char*) ++#define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC, 5, int) ++#define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC, 6, int) ++#define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC, 7, int) ++#define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, char*) ++#define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC, 12, int) ++#define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC, 13, int) ++#define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC, 14, int) ++#define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, char*) ++#define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*) ++#define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*) ++#define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int) ++#define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int) ++#define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int) ++#define WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, char*) ++#define WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, char*) ++#define WMT_IOCTL_FW_DBGLOG_CTRL _IOR(WMT_IOC_MAGIC, 29, int) ++#define WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, char*) ++ ++#define MTK_WMT_VERSION "SOC Consys WMT Driver - v1.0" ++#define MTK_WMT_DATE "2013/01/20" ++#define WMT_DEV_MAJOR 190 /* never used number */ ++#define WMT_DEV_NUM 1 ++#define WMT_DEV_INIT_TO_MS (2 * 1000) ++#define DYNAMIC_DUMP_BUF 109 ++ ++#if CFG_WMT_DBG_SUPPORT ++#define WMT_DBG_PROCNAME "driver/wmt_dbg" ++#endif ++ ++#define WMT_DRIVER_NAME "mtk_stp_wmt" ++ ++P_OSAL_EVENT gpRxEvent = NULL; ++ ++UINT32 u4RxFlag = 0x0; ++static atomic_t gRxCount = ATOMIC_INIT(0); ++ ++/* Linux UINT8 device */ ++static int gWmtMajor = WMT_DEV_MAJOR; ++static struct cdev gWmtCdev; ++static atomic_t gWmtRefCnt = ATOMIC_INIT(0); ++/* WMT driver information */ ++static UINT8 gLpbkBuf[1024+5] = { 0 }; ++ ++static UINT32 gLpbkBufLog; /* George LPBK debug */ ++static INT32 gWmtInitDone; ++static wait_queue_head_t gWmtInitWq; ++ ++P_WMT_PATCH_INFO pPatchInfo = NULL; ++UINT32 pAtchNum = 0; ++ ++#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) ++#define WMT_EMI_DEBUG_BUF_SIZE (8*1024) ++#else ++#define WMT_EMI_DEBUG_BUF_SIZE (32*1024) ++#endif ++ ++static UINT8 gEmiBuf[WMT_EMI_DEBUG_BUF_SIZE]; ++UINT8 *buf_emi; ++ ++#if CFG_WMT_PROC_FOR_AEE ++static struct proc_dir_entry *gWmtAeeEntry; ++#define WMT_AEE_PROCNAME "driver/wmt_aee" ++#define WMT_PROC_AEE_SIZE 3072 ++static UINT32 g_buf_len; ++static UINT8 *pBuf; ++#endif ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *wmt_class = NULL; ++struct device *wmt_dev = NULL; ++#endif ++ ++#if CFG_WMT_DBG_SUPPORT ++static struct proc_dir_entry *gWmtDbgEntry; ++COEX_BUF gCoexBuf; ++ ++static INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd); ++static INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3); ++ ++#if CFG_CORE_INTERNAL_TXRX ++static INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3); ++#endif ++static INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3); ++static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3); ++#if CONSYS_ENALBE_SET_JTAG ++static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3); ++#endif ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3); ++#endif ++#endif ++static void wmt_dbg_fwinfor_print_buff(UINT32 len) ++{ ++ UINT32 i = 0; ++ UINT32 idx = 0; ++ ++ for (i = 0; i < len; i++) { ++ buf_emi[idx] = gEmiBuf[i]; ++ if (gEmiBuf[i] == '\n') { ++ pr_cont("%s", buf_emi); ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ idx = 0; ++ } else { ++ idx++; ++ } ++ if (idx == BUF_LEN_MAX-1) { ++ buf_emi[idx] = '\0'; ++ pr_cont("%s", buf_emi); ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ idx = 0; ++ } ++ } ++} ++ ++/*LCM on/off ctrl for wmt varabile*/ ++static struct work_struct gPwrOnOffWork; ++UINT32 g_es_lr_flag_for_quick_sleep = 1; /* for ctrl quick sleep flag */ ++UINT32 g_es_lr_flag_for_lpbk_onoff = 0; /* for ctrl lpbk on off */ ++OSAL_SLEEPABLE_LOCK g_es_lr_lock; ++ ++#ifdef CONFIG_EARLYSUSPEND ++ ++static void wmt_dev_early_suspend(struct early_suspend *h) ++{ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 1; ++ g_es_lr_flag_for_lpbk_onoff = 0; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter early suspend@@@@@@@@@@@@@@\n"); ++ ++ schedule_work(&gPwrOnOffWork); ++} ++ ++static void wmt_dev_late_resume(struct early_suspend *h) ++{ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 0; ++ g_es_lr_flag_for_lpbk_onoff = 1; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter late resume@@@@@@@@@@@@@@\n"); ++ ++ schedule_work(&gPwrOnOffWork); ++ ++} ++ ++struct early_suspend wmt_early_suspend_handler = { ++ .suspend = wmt_dev_early_suspend, ++ .resume = wmt_dev_late_resume, ++}; ++ ++#else ++ ++static struct notifier_block wmt_fb_notifier; ++static int wmt_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) ++{ ++ struct fb_event *evdata = data; ++ INT32 blank; ++ ++ WMT_DBG_FUNC("wmt_fb_notifier_callback\n"); ++ ++ /* If we aren't interested in this event, skip it immediately ... */ ++ if (event != FB_EVENT_BLANK) ++ return 0; ++ ++ blank = *(INT32 *)evdata->data; ++ WMT_DBG_FUNC("fb_notify(blank=%d)\n", blank); ++ ++ switch (blank) { ++ case FB_BLANK_UNBLANK: ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 0; ++ g_es_lr_flag_for_lpbk_onoff = 1; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter UNBLANK @@@@@@@@@@@@@@\n"); ++ schedule_work(&gPwrOnOffWork); ++ break; ++ case FB_BLANK_POWERDOWN: ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ g_es_lr_flag_for_quick_sleep = 1; ++ g_es_lr_flag_for_lpbk_onoff = 0; ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ WMT_WARN_FUNC("@@@@@@@@@@wmt enter early POWERDOWN @@@@@@@@@@@@@@\n"); ++ schedule_work(&gPwrOnOffWork); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static void wmt_pwr_on_off_handler(struct work_struct *work) ++{ ++ INT32 retryCounter = 1; ++ ++ WMT_DBG_FUNC("wmt_pwr_on_off_handler start to run\n"); ++ ++ osal_lock_sleepable_lock(&g_es_lr_lock); ++ ++ if (g_es_lr_flag_for_lpbk_onoff) { ++ do { ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK)) { ++ WMT_WARN_FUNC("WMT turn on LPBK fail, retrying, retryCounter left:%d!\n", retryCounter); ++ retryCounter--; ++ osal_sleep_ms(1000); ++ } else { ++ WMT_INFO_FUNC("WMT turn on LPBK suceed\n"); ++ break; ++ } ++ } while (retryCounter > 0); ++ } else { ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK)) ++ WMT_WARN_FUNC("WMT turn off LPBK fail\n"); ++ else ++ WMT_DBG_FUNC("WMT turn off LPBK suceed\n"); ++ ++ } ++ ++ osal_unlock_sleepable_lock(&g_es_lr_lock); ++ ++} ++ ++ ++MTK_WCN_BOOL wmt_dev_get_early_suspend_state(void) ++{ ++ MTK_WCN_BOOL bRet = (0 == g_es_lr_flag_for_quick_sleep) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; ++ /* WMT_INFO_FUNC("bRet:%d\n", bRet); */ ++ return bRet; ++} ++ ++#if CFG_WMT_DBG_SUPPORT ++ ++static const WMT_DEV_DBG_FUNC wmt_dev_dbg_func[] = { ++ [0] = wmt_dbg_psm_ctrl, ++ [1] = wmt_dbg_quick_sleep_ctrl, ++ [2] = wmt_dbg_dsns_ctrl, ++ [3] = wmt_dbg_hwver_get, ++ [4] = wmt_dbg_assert_test, ++ [5] = wmt_dbg_inband_rst, ++ [6] = wmt_dbg_chip_rst, ++ [7] = wmt_dbg_func_ctrl, ++ [8] = wmt_dbg_raed_chipid, ++ [9] = wmt_dbg_wmt_dbg_level, ++ [0xa] = wmt_dbg_stp_dbg_level, ++ [0xb] = wmt_dbg_reg_read, ++ [0xc] = wmt_dbg_reg_write, ++ [0xd] = wmt_dbg_coex_test, ++ [0xe] = wmt_dbg_rst_ctrl, ++ [0xf] = wmt_dbg_ut_test, ++ [0x10] = wmt_dbg_efuse_read, ++ [0x11] = wmt_dbg_efuse_write, ++ [0x12] = wmt_dbg_sdio_ctrl, ++ [0x13] = wmt_dbg_stp_dbg_ctrl, ++ [0x14] = wmt_dbg_stp_dbg_log_ctrl, ++ [0x15] = wmt_dbg_wmt_assert_ctrl, ++ [0x16] = wmt_dbg_fwinfor_from_emi, ++ [0x17] = wmt_dbg_set_mcu_clock, ++ [0x18] = wmt_dbg_poll_cpupcr, ++ [0x19] = wmt_dbg_jtag_flag_ctrl, ++#if CFG_WMT_LTE_COEX_HANDLING ++ [0x20] = wmt_dbg_lte_coex_test, ++#endif ++}; ++ ++INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++#if CFG_WMT_PS_SUPPORT ++ if (0 == par2) { ++ wmt_lib_ps_ctrl(0); ++ WMT_INFO_FUNC("disable PSM\n"); ++ } else { ++ par2 = (1 > par2 || 20000 < par2) ? STP_PSM_IDLE_TIME_SLEEP : par2; ++ wmt_lib_ps_set_idle_time(par2); ++ wmt_lib_ps_ctrl(1); ++ WMT_WARN_FUNC("enable PSM, idle to sleep time = %d ms\n", par2); ++ } ++#else ++ WMT_INFO_FUNC("WMT PS not supported\n"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++#if CFG_WMT_PS_SUPPORT ++ UINT32 en_flag = par2; ++ ++ wmt_lib_quick_sleep_ctrl(en_flag); ++#else ++ WMT_WARN_FUNC("WMT PS not supported\n"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (WMTDSNS_FM_DISABLE <= par2 && WMTDSNS_MAX > par2) { ++ WMT_INFO_FUNC("DSNS type (%d)\n", par2); ++ mtk_wcn_wmt_dsns_ctrl(par2); ++ } else { ++ WMT_WARN_FUNC("invalid DSNS type\n"); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("query chip version\n"); ++ mtk_wcn_wmt_hwver_get(); ++ return 0; ++} ++ ++INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par3) { ++ /* par2 = 0: send assert command */ ++ /* par2 != 0: send exception command */ ++ return wmt_dbg_cmd_test_api(0 == par2 ? 0 : 1); ++ } else if (1 == par3) { ++ /* send noack command */ ++ return wmt_dbg_cmd_test_api(18); ++ } else if (2 == par3) { ++ /* warn reset test */ ++ return wmt_dbg_cmd_test_api(19); ++ } else if (3 == par3) { ++ /* firmware trace test */ ++ return wmt_dbg_cmd_test_api(20); ++ } ++ { ++ INT32 sec = 8; ++ INT32 times = 0; ++ ++ times = par3; ++ do { ++ WMT_INFO_FUNC("Send Assert Command per 8 secs!!\n"); ++ wmt_dbg_cmd_test_api(0); ++ osal_sleep_ms(sec * 1000); ++ } while (--times); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd) ++{ ++ ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = WMT_OPID_CMD_TEST; ++ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*this test command should be run with usb cable connected, so no host awake is needed */ ++ /* wmt_lib_host_awake_get(); */ ++ switch (cmd) { ++ case WMTDRV_CMD_ASSERT: ++ pOp->op.au4OpData[0] = 0; ++ break; ++ case WMTDRV_CMD_EXCEPTION: ++ pOp->op.au4OpData[0] = 1; ++ break; ++ case WMTDRV_CMD_NOACK_TEST: ++ pOp->op.au4OpData[0] = 3; ++ break; ++ case WMTDRV_CMD_WARNRST_TEST: ++ pOp->op.au4OpData[0] = 4; ++ break; ++ case WMTDRV_CMD_FWTRACE_TEST: ++ pOp->op.au4OpData[0] = 5; ++ break; ++ default: ++ if (WMTDRV_CMD_COEXDBG_00 <= cmd && WMTDRV_CMD_COEXDBG_15 >= cmd) { ++ pOp->op.au4OpData[0] = 2; ++ pOp->op.au4OpData[1] = cmd - 2; ++ } else { ++ pOp->op.au4OpData[0] = 0xff; ++ pOp->op.au4OpData[1] = 0xff; ++ } ++ pOp->op.au4OpData[2] = (SIZE_T) gCoexBuf.buffer; ++ pOp->op.au4OpData[3] = osal_sizeof(gCoexBuf.buffer); ++ break; ++ } ++ WMT_INFO_FUNC("CMD_TEST, opid(%d), par(%d, %d)\n", pOp->op.opId, pOp->op.au4OpData[0], pOp->op.au4OpData[1]); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if ((cmd != WMTDRV_CMD_ASSERT) && ++ (cmd != WMTDRV_CMD_EXCEPTION) && ++ (cmd != WMTDRV_CMD_NOACK_TEST) && (cmd != WMTDRV_CMD_WARNRST_TEST) && (cmd != WMTDRV_CMD_FWTRACE_TEST)) { ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ gCoexBuf.availSize = 0; ++ } else { ++ gCoexBuf.availSize = pOp->op.au4OpData[3]; ++ WMT_INFO_FUNC("gCoexBuf.availSize = %d\n", gCoexBuf.availSize); ++ } ++ } ++ /* wmt_lib_host_awake_put(); */ ++ WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", ++ pOp->op.opId, ++ pOp->op.au4OpData[0], ++ pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par2) { ++ WMT_INFO_FUNC("inband reset test!!\n"); ++ mtk_wcn_stp_inband_reset(); ++ } else { ++ WMT_INFO_FUNC("STP context reset in host side!!\n"); ++ mtk_wcn_stp_flush_context(); ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (0 == par2) { ++ if (mtk_wcn_stp_is_ready()) { ++ WMT_INFO_FUNC("whole chip reset test\n"); ++ wmt_lib_cmb_rst(WMTRSTSRC_RESET_TEST); ++ } else { ++ WMT_INFO_FUNC("STP not ready , not to launch whole chip reset test\n"); ++ } ++ } else if (1 == par2) { ++ WMT_INFO_FUNC("chip hardware reset test\n"); ++ wmt_lib_hw_rst(); ++ } else { ++ WMT_INFO_FUNC("chip software reset test\n"); ++ wmt_lib_sw_rst(1); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (WMTDRV_TYPE_WMT > par2 || WMTDRV_TYPE_LPBK == par2) { ++ if (0 == par3) { ++ WMT_INFO_FUNC("function off test, type(%d)\n", par2); ++ mtk_wcn_wmt_func_off(par2); ++ } else { ++ WMT_INFO_FUNC("function on test, type(%d)\n", par2); ++ mtk_wcn_wmt_func_on(par2); ++ } ++ } else { ++ WMT_INFO_FUNC("function ctrl test, invalid type(%d)\n", par2); ++ } ++ return 0; ++} ++ ++INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("chip version = %d\n", wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER)); ++ return 0; ++} ++ ++INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3) ++{ ++ par2 = (WMT_LOG_ERR <= par2 && WMT_LOG_LOUD >= par2) ? par2 : WMT_LOG_INFO; ++ wmt_lib_dbg_level_set(par2); ++ WMT_INFO_FUNC("set wmt log level to %d\n", par2); ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3) ++{ ++ par2 = (0 <= par2 && 4 >= par2) ? par2 : 2; ++ mtk_wcn_stp_dbg_level(par2); ++ WMT_INFO_FUNC("set stp log level to %d\n", par2); ++ return 0; ++ ++} ++ ++INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->register address */ ++ /* par3-->register mask */ ++ UINT32 value = 0x0; ++ UINT32 iRet = -1; ++#if 0 ++ DISABLE_PSM_MONITOR(); ++ iRet = wmt_core_reg_rw_raw(0, par2, &value, par3); ++ ENABLE_PSM_MONITOR(); ++#endif ++ iRet = wmt_lib_reg_rw(0, par2, &value, par3); ++ WMT_INFO_FUNC("read combo chip register (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); ++ return 0; ++} ++ ++INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->register address */ ++ /* par3-->value to set */ ++ UINT32 iRet = -1; ++#if 0 ++ DISABLE_PSM_MONITOR(); ++ iRet = wmt_core_reg_rw_raw(1, par2, &par3, 0xffffffff); ++ ENABLE_PSM_MONITOR(); ++#endif ++ iRet = wmt_lib_reg_rw(1, par2, &par3, 0xffffffff); ++ WMT_INFO_FUNC("write combo chip register (0x%08x) with value (0x%08x) %s\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed"); ++ return 0; ++} ++ ++INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->efuse address */ ++ /* par3-->register mask */ ++ UINT32 value = 0x0; ++ UINT32 iRet = -1; ++ ++ iRet = wmt_lib_efuse_rw(0, par2, &value, par3); ++ WMT_INFO_FUNC("read combo chip efuse (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); ++ return 0; ++} ++ ++INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3) ++{ ++ /* par2-->efuse address */ ++ /* par3-->value to set */ ++ UINT32 iRet = -1; ++ ++ iRet = wmt_lib_efuse_rw(1, par2, &par3, 0xffffffff); ++ WMT_INFO_FUNC("write combo chip efuse (0x%08x) with value (0x%08x) %s\n", ++ par2, par3, iRet != 0 ? "failed" : "succeed"); ++ return 0; ++} ++ ++INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++/*remove sdio card detect/remove control because of btif is used*/ ++#if 0 ++ INT32 iRet = -1; ++ ++ iRet = wmt_lib_sdio_ctrl(0 != par2 ? 1 : 0); ++ WMT_INFO_FUNC("ctrl SDIO function %s\n", 0 == iRet ? "succeed" : "failed"); ++#endif ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ if (1 < par2) { ++ mtk_wcn_stp_dbg_dump_package(); ++ return 0; ++ } ++ WMT_INFO_FUNC("%s stp debug function\n", 0 == par2 ? "disable" : "enable"); ++ if (0 == par2) ++ mtk_wcn_stp_dbg_disable(); ++ else if (1 == par2) ++ mtk_wcn_stp_dbg_enable(); ++ ++ return 0; ++} ++ ++INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ mtk_wcn_stp_dbg_log_ctrl(0 != par2 ? 1 : 0); ++ return 0; ++} ++ ++INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ mtk_wcn_stp_coredump_flag_ctrl(0 != par2 ? 1 : 0); ++ return 0; ++} ++ ++INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 offset = 0; ++ UINT32 len = 0; ++ UINT32 *pAddr = NULL; ++ UINT32 cur_idx_pagedtrace; ++ static UINT32 prev_idx_pagedtrace; ++ MTK_WCN_BOOL isBreak = MTK_WCN_BOOL_TRUE; ++ ++ offset = par2; ++ len = par3; ++ ++ buf_emi = kmalloc(sizeof(UINT8) * BUF_LEN_MAX, GFP_KERNEL); ++ if (!buf_emi) { ++ WMT_ERR_FUNC("buf kmalloc memory fail\n"); ++ return 0; ++ } ++ osal_memset(buf_emi, 0, BUF_LEN_MAX); ++ osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); ++ wmt_lib_get_fwinfor_from_emi(0, offset, &gEmiBuf[0], 0x100); ++ ++ if (offset == 1) { ++ do { ++ pAddr = (PUINT32) wmt_plat_get_emi_virt_add(0x24); ++ cur_idx_pagedtrace = *pAddr; ++ ++ if (cur_idx_pagedtrace > prev_idx_pagedtrace) { ++ len = cur_idx_pagedtrace - prev_idx_pagedtrace; ++ wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); ++ wmt_dbg_fwinfor_print_buff(len); ++ prev_idx_pagedtrace = cur_idx_pagedtrace; ++ } ++ ++ if (cur_idx_pagedtrace < prev_idx_pagedtrace) { ++ if (prev_idx_pagedtrace >= 0x8000) { ++ pr_debug("++ prev_idx_pagedtrace invalid ...++\n\\n"); ++ prev_idx_pagedtrace = 0x8000 - 1; ++ continue; ++ } ++ ++ len = 0x8000 - prev_idx_pagedtrace - 1; ++ wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); ++ pr_debug("\n\n -- CONNSYS paged trace ascii output (cont...) --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ ++ len = cur_idx_pagedtrace; ++ wmt_lib_get_fwinfor_from_emi(1, 0x0, &gEmiBuf[0], len); ++ pr_debug("\n\n -- CONNSYS paged trace ascii output (end) --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ prev_idx_pagedtrace = cur_idx_pagedtrace; ++ } ++ msleep(100); ++ } while (isBreak); ++ } ++ ++ pr_debug("\n\n -- control word --\n\n"); ++ wmt_dbg_fwinfor_print_buff(256); ++ if (len > 1024 * 4) ++ len = 1024 * 4; ++ ++ WMT_WARN_FUNC("get fw infor from emi at offset(0x%x),len(0x%x)\n", offset, len); ++ osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); ++ wmt_lib_get_fwinfor_from_emi(1, offset, &gEmiBuf[0], len); ++ ++ pr_debug("\n\n -- paged trace hex output --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ pr_debug("\n\n -- paged trace ascii output --\n\n"); ++ wmt_dbg_fwinfor_print_buff(len); ++ kfree(buf_emi); ++ return 0; ++} ++ ++INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("coexistance test cmd!!\n"); ++ return wmt_dbg_cmd_test_api(par2 + WMTDRV_CMD_COEXDBG_00); ++} ++ ++INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ WMT_INFO_FUNC("%s audo rst\n", 0 == par2 ? "disable" : "enable"); ++ mtk_wcn_stp_set_auto_rst(0 == par2 ? 0 : 1); ++ return 0; ++} ++ ++INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ ++ INT32 i = 0; ++ INT32 j = 0; ++ INT32 iRet = 0; ++ ++ i = 20; ++ while ((i--) > 0) { ++ WMT_INFO_FUNC("#### UT WMT and STP Function On/Off .... %d\n", i); ++ j = 10; ++ while ((j--) > 0) { ++ WMT_INFO_FUNC("#### BT On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### GPS On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### FM On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### WIFI On .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### BT Off .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### GPS Off ....(%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### FM Off .... (%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ WMT_INFO_FUNC("#### WIFI Off ....(%d, %d)\n", i, j); ++ iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI); ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ } ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ break; ++ ++ } ++ if (iRet == MTK_WCN_BOOL_FALSE) ++ WMT_INFO_FUNC("#### UT FAIL!!\n"); ++ else ++ WMT_INFO_FUNC("#### UT PASS!!\n"); ++ ++ return iRet; ++} ++ ++#if CFG_CORE_INTERNAL_TXRX ++ ++struct lpbk_package { ++ long payload_length; ++ unsigned char out_payload[2048]; ++ unsigned char in_payload[2048]; ++}; ++ ++static INT32 wmt_internal_loopback(INT32 count, INT32 max) ++{ ++ int ret = 0; ++ int loop; ++ int offset; ++ struct lpbk_package lpbk_buffer; ++ P_OSAL_OP pOp; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ for (loop = 0; loop < count; loop++) { ++ /* <1> init buffer */ ++ osal_memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package)); ++ lpbk_buffer.payload_length = max; ++ for (offset = 0; offset < max; offset++) ++ lpbk_buffer.out_payload[offset] = (offset + 1) /*for test use: begin from 1 */ & 0xFF; ++ ++ ++ memcpy(&gLpbkBuf[0], &lpbk_buffer.out_payload[0], max); ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ ret = -1; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_LPBK; ++ pOp->op.au4OpData[0] = lpbk_buffer.payload_length; /* packet length */ ++ pOp->op.au4OpData[1] = (UINT32) &gLpbkBuf[0]; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ ret = -2; ++ } ++ ++ ret = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == ret) { ++ WMT_WARN_FUNC("OPID(%d) type(%d)fail\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ret = -3; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ memcpy(&lpbk_buffer.in_payload[0], &gLpbkBuf[0], max); ++ ++ ret = pOp->op.au4OpData[0]; ++ /*<3> compare result */ ++ if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) { ++ WMT_INFO_FUNC("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __func__); ++ ret = -4; ++ break; ++ } ++ WMT_ERR_FUNC("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld)\n", __func__, loop, ++ lpbk_buffer.payload_length); ++ ++ } ++ ++ if (loop != count) ++ WMT_ERR_FUNC("fail at loop(%d) buf_length(%d)\n", loop, max); ++ ++ ++ return ret; ++} ++ ++INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 count; ++ UINT32 length; ++ ++ count = par1; ++ length = par2; ++ ++ WMT_INFO_FUNC("count[%d],length[%d]\n", count, length); ++ ++ wmt_core_lpbk_do_stp_init(); ++ ++ wmt_internal_loopback(count, length); ++ ++ wmt_core_lpbk_do_stp_deinit(); ++ return 0; ++} ++#endif ++ ++static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3) ++{ ++ int ret = 0; ++ P_OSAL_OP pOp; ++ P_OSAL_SIGNAL pSignal = NULL; ++ UINT32 kind = 0; ++ ++ kind = par2; ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return -1; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_SET_MCU_CLK; ++ pOp->op.au4OpData[0] = kind; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ WMT_INFO_FUNC("OPID(%d) kind(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) kind(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -2; ++ } ++ ++ ret = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == ret) { ++ WMT_WARN_FUNC("OPID(%d) kind(%d)fail(%d)\n", pOp->op.opId, pOp->op.au4OpData[0], ret); ++ return -3; ++ } ++ WMT_INFO_FUNC("OPID(%d) kind(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return ret; ++} ++ ++static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 count = 0; ++ UINT16 sleep = 0; ++ UINT16 toAee = 0; ++ ++ count = par2; ++ sleep = (par3 & 0xF0) >> 4; ++ toAee = (par3 & 0x0F); ++ ++ WMT_INFO_FUNC("polling count[%d],polling sleep[%d],toaee[%d]\n", count, sleep, toAee); ++ wmt_lib_poll_cpupcr(count, sleep, toAee); ++ ++ return 0; ++} ++ ++#if CONSYS_ENALBE_SET_JTAG ++static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT32 en_flag = par2; ++ ++ wmt_lib_jtag_flag_set(en_flag); ++ return 0; ++} ++#endif ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++static INT32 wmt_dbg_lte_to_wmt_test(UINT32 opcode, UINT32 msg_len) ++{ ++ ipc_ilm_t ilm; ++ local_para_struct *p_buf_str; ++ INT32 i = 0; ++ INT32 iRet = -1; ++ ++ WMT_INFO_FUNC("opcode(0x%02x),msg_len(%d)\n", opcode, msg_len); ++ p_buf_str = osal_malloc(osal_sizeof(local_para_struct) + msg_len); ++ if (NULL == p_buf_str) { ++ WMT_ERR_FUNC("kmalloc for local para ptr structure failed.\n"); ++ return -1; ++ } ++ p_buf_str->msg_len = msg_len; ++ for (i = 0; i < msg_len; i++) ++ p_buf_str->data[i] = i; ++ ++ ilm.local_para_ptr = p_buf_str; ++ ilm.msg_id = opcode; ++ ++ iRet = wmt_lib_handle_idc_msg(&ilm); ++ osal_free(p_buf_str); ++ return iRet; ++ ++} ++ ++static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3) ++{ ++ UINT8 *local_buffer = NULL; ++ UINT32 handle_len; ++ INT32 iRet = -1; ++ static UINT8 wmt_to_lte_test_evt1[] = { 0x02, 0x16, 0x0d, 0x00, ++ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, ++ 0xa, 0xb ++ }; ++ static UINT8 wmt_to_lte_test_evt2[] = { 0x02, 0x16, 0x09, 0x00, ++ 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ++ }; ++ static UINT8 wmt_to_lte_test_evt3[] = { 0x02, 0x16, 0x02, 0x00, ++ 0x02, 0xff ++ }; ++ static UINT8 wmt_to_lte_test_evt4[] = { 0x02, 0x16, 0x0d, 0x00, ++ 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, ++ 0xa, 0xb ++ }; ++ ++ local_buffer = kmalloc(512, GFP_KERNEL); ++ if (!local_buffer) { ++ WMT_ERR_FUNC("local_buffer kmalloc memory fail\n"); ++ return 0; ++ } ++ ++ if (par2 == 1) { ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt1)) { ++ WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt1)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 2) { ++ osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], ++ &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); ++ ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], ++ osal_sizeof(wmt_to_lte_test_evt1) + ++ osal_sizeof(wmt_to_lte_test_evt2)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)) { ++ WMT_ERR_FUNC("par2=2,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 3) { ++ osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], ++ &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); ++ osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)], ++ &wmt_to_lte_test_evt3[0], osal_sizeof(wmt_to_lte_test_evt3)); ++ ++ handle_len = wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], osal_sizeof(wmt_to_lte_test_evt1) + ++ osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)); ++ if (handle_len != ++ osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)) { ++ WMT_ERR_FUNC("par2=3,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", handle_len, ++ osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + ++ osal_sizeof(wmt_to_lte_test_evt3)); ++ } else { ++ WMT_INFO_FUNC("par3=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 4) { ++ handle_len = ++ wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt4[0], osal_sizeof(wmt_to_lte_test_evt4)); ++ if (handle_len != osal_sizeof(wmt_to_lte_test_evt4)) { ++ WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", ++ handle_len, osal_sizeof(wmt_to_lte_test_evt4)); ++ } else { ++ WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); ++ } ++ } ++ if (par2 == 5) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 6) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 7) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 8) { ++ if (par3 >= 1024) ++ par3 = 1024; ++ ++ iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_TX_IND, par3); ++ WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_TX_IND test result(%d)\n", iRet); ++ } ++ if (par2 == 9) { ++ if (par3 > 0) ++ wmt_core_set_flag_for_test(1); ++ else ++ wmt_core_set_flag_for_test(0); ++ } ++ return 0; ++ kfree(local_buffer); ++} ++#endif ++ ++static ssize_t wmt_dev_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ ++ INT32 retval = 0; ++ INT32 i_ret = 0; ++ PINT8 warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; ++ ++ if (*f_pos > 0) { ++ retval = 0; ++ } else { ++ /*len = sprintf(page, "%d\n", g_psm_enable); */ ++ if (gCoexBuf.availSize <= 0) { ++ WMT_INFO_FUNC("no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"); ++ retval = osal_strlen(warn_msg) + 1; ++ if (count < retval) ++ retval = count; ++ ++ i_ret = copy_to_user(buf, warn_msg, retval); ++ if (i_ret) { ++ WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } else { ++ INT32 i = 0; ++ INT32 len = 0; ++ INT8 msg_info[128]; ++ INT32 max_num = 0; ++ /*we do not check page buffer, because there are only ++ * 100 bytes in g_coex_buf, no reason page buffer is not ++ * enough, a bomb is placed here on unexpected condition ++ */ ++ ++ WMT_INFO_FUNC("%d bytes available\n", gCoexBuf.availSize); ++ max_num = ((osal_sizeof(msg_info) > count ? osal_sizeof(msg_info) : count) - 1) / 5; ++ ++ if (max_num > gCoexBuf.availSize) ++ max_num = gCoexBuf.availSize; ++ else ++ WMT_INFO_FUNC("round to %d bytes due to local buffer size limitation\n", max_num); ++ ++ ++ for (i = 0; i < max_num; i++) ++ len += osal_sprintf(msg_info + len, "0x%02x ", gCoexBuf.buffer[i]); ++ ++ ++ len += osal_sprintf(msg_info + len, "\n"); ++ retval = len; ++ ++ i_ret = copy_to_user(buf, msg_info, retval); ++ if (i_ret) { ++ WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ ++ } ++ } ++ gCoexBuf.availSize = 0; ++err_exit: ++ ++ return retval; ++} ++ ++static ssize_t wmt_dev_dbg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ INT8 buf[256]; ++ PINT8 pBuf; ++ ssize_t len = count; ++ INT32 x = 0, y = 0, z = 0; ++ PINT8 pToken = NULL; ++ PINT8 pDelimiter = " \t"; ++ long res; ++ INT32 ret; ++ ++ WMT_INFO_FUNC("write parameter len = %d\n\r", (INT32) len); ++ if (len >= osal_sizeof(buf)) { ++ WMT_ERR_FUNC("input handling fail!\n"); ++ len = osal_sizeof(buf) - 1; ++ return -1; ++ } ++ ++ if (copy_from_user(buf, buffer, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ WMT_INFO_FUNC("write parameter data = %s\n\r", buf); ++ ++ pBuf = buf; ++ pToken = osal_strsep(&pBuf, pDelimiter); ++ ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get x fail(%d)\n", ret); ++ x = 0; ++ } ++ x = res; ++ } else { ++ x = 0; ++ } ++ ++ pToken = osal_strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get y fail(%d)\n", ret); ++ y = 0; ++ } ++ y = res; ++ WMT_INFO_FUNC("y = 0x%08x\n\r", y); ++ } else { ++ y = 3000; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ y = 0x80000000; ++ ++ } ++ ++ pToken = osal_strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ ret = osal_strtol(pToken, 16, &res); ++ if (ret) { ++ WMT_ERR_FUNC("get z fail(%d)\n", ret); ++ z = 0; ++ } ++ z = res; ++ } else { ++ z = 10; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ z = 0xffffffff; ++ ++ } ++ ++ WMT_WARN_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++ ++ if (osal_array_size(wmt_dev_dbg_func) > x && NULL != wmt_dev_dbg_func[x]) ++ (*wmt_dev_dbg_func[x]) (x, y, z); ++ else ++ WMT_WARN_FUNC("no handler defined for command id(0x%08x)\n\r", x); ++ ++ return len; ++} ++ ++INT32 wmt_dev_dbg_setup(VOID) ++{ ++ static const struct file_operations wmt_dbg_fops = { ++ .owner = THIS_MODULE, ++ .read = wmt_dev_dbg_read, ++ .write = wmt_dev_dbg_write, ++ }; ++ gWmtDbgEntry = proc_create(WMT_DBG_PROCNAME, 0664, NULL, &wmt_dbg_fops); ++ if (gWmtDbgEntry == NULL) { ++ WMT_ERR_FUNC("Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ return 0; ++} ++ ++INT32 wmt_dev_dbg_remove(VOID) ++{ ++ if (NULL != gWmtDbgEntry) ++ remove_proc_entry(WMT_DBG_PROCNAME, NULL); ++ ++#if CFG_WMT_PS_SUPPORT ++ wmt_lib_ps_deinit(); ++#endif ++ return 0; ++} ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ ++static ssize_t wmt_dev_proc_for_aee_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = 0; ++ UINT32 len = 0; ++ ++ WMT_INFO_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos); ++ ++ if (0 == *f_pos) { ++ pBuf = wmt_lib_get_cpupcr_xml_format(&len); ++ g_buf_len = len; ++ WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len); ++ } ++ ++ if (g_buf_len >= count) { ++ ++ retval = copy_to_user(buf, pBuf, count); ++ if (retval) { ++ WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ ++ *f_pos += count; ++ g_buf_len -= count; ++ pBuf += count; ++ WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); ++ ++ retval = count; ++ } else if (0 != g_buf_len) { ++ ++ retval = copy_to_user(buf, pBuf, g_buf_len); ++ if (retval) { ++ WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ ++ *f_pos += g_buf_len; ++ len = g_buf_len; ++ g_buf_len = 0; ++ pBuf += len; ++ retval = len; ++ WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); ++ } else { ++ WMT_INFO_FUNC("wmt_dev: no data available for aee\n"); ++ retval = 0; ++ } ++err_exit: ++ return retval; ++} ++ ++static ssize_t wmt_dev_proc_for_aee_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ WMT_TRC_FUNC(); ++ return 0; ++} ++ ++INT32 wmt_dev_proc_for_aee_setup(VOID) ++{ ++ static const struct file_operations wmt_aee_fops = { ++ .owner = THIS_MODULE, ++ .read = wmt_dev_proc_for_aee_read, ++ .write = wmt_dev_proc_for_aee_write, ++ }; ++ ++ gWmtDbgEntry = proc_create(WMT_AEE_PROCNAME, 0664, NULL, &wmt_aee_fops); ++ if (gWmtDbgEntry == NULL) { ++ WMT_ERR_FUNC("Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++INT32 wmt_dev_proc_for_aee_remove(VOID) ++{ ++ if (NULL != gWmtAeeEntry) ++ remove_proc_entry(WMT_AEE_PROCNAME, NULL); ++ ++ return 0; ++} ++#endif ++ ++VOID wmt_dev_rx_event_cb(VOID) ++{ ++ u4RxFlag = 1; ++ atomic_inc(&gRxCount); ++ if (NULL != gpRxEvent) { ++ /* u4RxFlag = 1; */ ++ /* atomic_inc(&gRxCount); */ ++ wake_up_interruptible(&gpRxEvent->waitQueue); ++ } else { ++ /* WMT_ERR_FUNC("null gpRxEvent, flush rx!\n"); */ ++ /* wmt_lib_flush_rx(); */ ++ } ++} ++ ++INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent) ++{ ++ ++ UINT32 ms = pEvent->timeoutValue; ++ long lRet = 0; ++ ++ gpRxEvent = pEvent; ++ if (0 != ms) ++ lRet = wait_event_interruptible_timeout(gpRxEvent->waitQueue, 0 != u4RxFlag, msecs_to_jiffies(ms)); ++ else ++ lRet = wait_event_interruptible(gpRxEvent->waitQueue, u4RxFlag != 0); ++ ++ u4RxFlag = 0; ++/* gpRxEvent = NULL; */ ++ if (atomic_dec_return(&gRxCount)) { ++ WMT_ERR_FUNC("gRxCount != 0 (%d), reset it!\n", atomic_read(&gRxCount)); ++ atomic_set(&gRxCount, 0); ++ } ++ ++ return lRet; ++} ++ ++INT32 wmt_dev_read_file(PUINT8 pName, const PPUINT8 ppBufPtr, INT32 offset, INT32 padSzBuf) ++{ ++ INT32 iRet = -1; ++ struct file *fd; ++ /* ssize_t iRet; */ ++ INT32 file_len; ++ INT32 read_len; ++ PVOID pBuf; ++ mm_segment_t fs; ++ ++ /* struct cred *cred = get_task_cred(current); */ ++ //const struct cred *cred = get_current_cred(); ++ ++ if (!ppBufPtr) { ++ WMT_ERR_FUNC("invalid ppBufptr!\n"); ++ return -1; ++ } ++ *ppBufPtr = NULL; ++ ++ fd = filp_open(pName, O_RDONLY, 0); ++ if (IS_ERR(fd)) { ++ WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); ++ return -2; ++ } ++ ++ if(fd->f_op == NULL) { ++ printk(KERN_ERR "invalid file op \r\n"); ++ return -3; ++ } ++ ++#if 0 ++ if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { ++ WMT_ERR_FUNC("failed to open or read!(0x%p, %d, %d, %d)\n", fd, PTR_ERR(fd), cred->fsuid, cred->fsgid); ++ if (IS_ERR(fd)) ++ WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); ++ return -1; ++ } ++#endif ++ file_len = fd->f_path.dentry->d_inode->i_size; ++ file_len = fd->f_op->llseek(fd, 0, 2); ++ fd->f_op->llseek(fd, 0, 0); ++ pBuf = vmalloc((file_len + BCNT_PATCH_BUF_HEADROOM + 3) & ~0x3UL); ++ if (!pBuf) { ++ WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32) ((file_len + 3) & ~0x3UL)); ++ goto read_file_done; ++ } ++ ++ do { ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ WMT_ERR_FUNC("failed to seek!!\n"); ++ goto read_file_done; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ fs=get_fs(); ++ read_len = vfs_read(fd, pBuf + padSzBuf, file_len, &fd->f_pos); ++ set_fs(fs); ++ if (read_len != file_len) ++ WMT_WARN_FUNC("read abnormal: read_len(%d), file_len(%d)\n", read_len, file_len); ++ ++ } while (false); ++ ++ iRet = 0; ++ *ppBufPtr = pBuf; ++ ++read_file_done: ++ if (iRet) { ++ if (pBuf) ++ vfree(pBuf); ++ ++ } ++ ++ filp_close(fd, NULL); ++ ++ return (iRet) ? iRet : read_len; ++} ++ ++/* TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. */ ++INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf) ++{ ++ INT32 iRet = -1; ++ osal_firmware *pfw; ++ uid_t orig_uid; ++ gid_t orig_gid; ++ ++ /* struct cred *cred = get_task_cred(current); */ ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ mm_segment_t orig_fs = get_fs(); ++ ++ if (*ppPatch) { ++ WMT_WARN_FUNC("f/w patch already exists\n"); ++ if ((*ppPatch)->data) ++ vfree((*ppPatch)->data); ++ ++ kfree(*ppPatch); ++ *ppPatch = NULL; ++ } ++ ++ if (!osal_strlen(pPatchName)) { ++ WMT_ERR_FUNC("empty f/w name\n"); ++ osal_assert((osal_strlen(pPatchName) > 0)); ++ return -1; ++ } ++ ++ pfw = kzalloc(sizeof(osal_firmware), /*GFP_KERNEL */ GFP_ATOMIC); ++ if (!pfw) { ++ WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(osal_firmware)); ++ return -2; ++ } ++ ++ orig_uid = cred->fsuid.val; ++ orig_gid = cred->fsgid.val; ++ cred->fsuid.val = cred->fsgid.val = 0; ++ ++ set_fs(get_ds()); ++ ++ /* load patch file from fs */ ++ iRet = wmt_dev_read_file(pPatchName, (const PPUINT8)&pfw->data, 0, padSzBuf); ++ set_fs(orig_fs); ++ ++ cred->fsuid.val = orig_uid; ++ cred->fsgid.val = orig_gid; ++ ++ ++ if (iRet > 0) { ++ pfw->size = iRet; ++ *ppPatch = pfw; ++ WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName, pfw->data); ++ return 0; ++ } ++ kfree(pfw); ++ *ppPatch = NULL; ++ WMT_ERR_FUNC("load file (%s) fail, iRet(%d)\n", pPatchName, iRet); ++ return -1; ++} ++ ++INT32 wmt_dev_patch_put(osal_firmware **ppPatch) ++{ ++ if (NULL != *ppPatch) { ++ if ((*ppPatch)->data) ++ vfree((*ppPatch)->data); ++ ++ kfree(*ppPatch); ++ *ppPatch = NULL; ++ } ++ return 0; ++} ++ ++VOID wmt_dev_patch_info_free(VOID) ++{ ++ ++ kfree(pPatchInfo); ++ pPatchInfo = NULL; ++ ++} ++ ++MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName) ++{ ++ struct file *fd = NULL; ++ /* ssize_t iRet; */ ++ INT32 fileLen = -1; ++ const struct cred *cred = get_current_cred(); ++ ++ if (pFileName == NULL) { ++ WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) { ++ WMT_ERR_FUNC("invalid file name(%s)\n", pFileName); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ /* struct cred *cred = get_task_cred(current); */ ++ ++ fd = filp_open(pFileName, O_RDONLY, 0); ++ if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { ++ WMT_ERR_FUNC("failed to open or read(%s)!(0x%p, %d, %d)\n", pFileName, fd, cred->fsuid, cred->fsgid); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ fileLen = fd->f_path.dentry->d_inode->i_size; ++ filp_close(fd, NULL); ++ fd = NULL; ++ if (fileLen <= 0) { ++ WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName, fileLen); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName, fileLen); ++ return true; ++ ++} ++ ++/* static unsigned long count_last_access_sdio = 0; */ ++static unsigned long count_last_access_btif; ++static unsigned long jiffies_last_poll; ++ ++#if 0 ++static INT32 wmt_dev_tra_sdio_update(void) ++{ ++ count_last_access_sdio += 1; ++ /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */ ++ ++ return 0; ++} ++#endif ++ ++extern INT32 wmt_dev_tra_bitf_update(void) ++{ ++ count_last_access_btif += 1; ++ /* WMT_INFO_FUNC("jiffies_last_access_btif: jiffies = %ul\n", jiffies); */ ++ ++ return 0; ++} ++ ++static UINT32 wmt_dev_tra_ahb_poll(void) ++{ ++#define TIME_THRESHOLD_TO_TEMP_QUERY 3000 ++#define COUNT_THRESHOLD_TO_TEMP_QUERY 200 ++ ++ unsigned long ahb_during_count = 0; ++ unsigned long poll_during_time = 0; ++ ++ /* if (jiffies > jiffies_last_poll) */ ++ if (time_after(jiffies, jiffies_last_poll)) ++ poll_during_time = jiffies - jiffies_last_poll; ++ else ++ poll_during_time = 0xffffffff; ++ ++ ++ WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %lu\n", jiffies_to_msecs(0xffffffff)); ++ ++ if (jiffies_to_msecs(poll_during_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { ++ WMT_DBG_FUNC("**poll_during_time = %lu < %lu, not to query\n", ++ jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY); ++ return -1; ++ } ++ /* ahb_during_count = count_last_access_sdio; */ ++ if (NULL == mtk_wcn_wlan_bus_tx_cnt) { ++ WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt null pointer\n"); ++ return -1; ++ } ++ ahb_during_count = (*mtk_wcn_wlan_bus_tx_cnt) (); ++ ++ if (ahb_during_count < COUNT_THRESHOLD_TO_TEMP_QUERY) { ++ WMT_DBG_FUNC("**ahb_during_count = %lu < %lu, not to query\n", ++ ahb_during_count, COUNT_THRESHOLD_TO_TEMP_QUERY); ++ return -2; ++ } ++ ++ if (NULL == mtk_wcn_wlan_bus_tx_cnt_clr) { ++ WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt_clr null pointer\n"); ++ return -3; ++ } ++ (*mtk_wcn_wlan_bus_tx_cnt_clr) (); ++ /* count_last_access_sdio = 0; */ ++ jiffies_last_poll = jiffies; ++ ++ WMT_INFO_FUNC("**poll_during_time = %lu > %lu, ahb_during_count = %lu > %lu, query\n", ++ jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY, ++ jiffies_to_msecs(ahb_during_count), COUNT_THRESHOLD_TO_TEMP_QUERY); ++ ++ return 0; ++} ++ ++long wmt_dev_tm_temp_query(void) ++{ ++#define HISTORY_NUM 5 ++#define TEMP_THRESHOLD 65 ++#define REFRESH_TIME 300 /* sec */ ++ ++ static INT32 temp_table[HISTORY_NUM] = { 99 }; /* not query yet. */ ++ static INT32 idx_temp_table; ++ static struct timeval query_time, now_time; ++ ++ INT8 query_cond = 0; ++ INT32 current_temp = 0; ++ INT32 index = 0; ++ long return_temp = 0; ++ /* Query condition 1: */ ++ /* If we have the high temperature records on the past, we continue to query/monitor */ ++ /* the real temperature until cooling */ ++ for (index = 0; index < HISTORY_NUM; index++) { ++ if (temp_table[index] >= TEMP_THRESHOLD) { ++ query_cond = 1; ++ WMT_DBG_FUNC("temperature table is still initial value, we should query temp temperature..\n"); ++ } ++ } ++ ++ do_gettimeofday(&now_time); ++#if 1 ++ /* Query condition 2: */ ++ /* Moniter the ahb bus activity to decide if we have the need to query temperature. */ ++ if (!query_cond) { ++ if (wmt_dev_tra_ahb_poll() == 0) { ++ query_cond = 1; ++ WMT_INFO_FUNC("ahb traffic , we must query temperature..\n"); ++ } else { ++ WMT_DBG_FUNC("ahb idle traffic ....\n"); ++ } ++ ++ /* only WIFI tx power might make temperature varies largely */ ++#if 0 ++ if (!query_cond) { ++ last_access_time = wmt_dev_tra_uart_poll(); ++ if (jiffies_to_msecs(last_access_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { ++ query_cond = 1; ++ WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n"); ++ } else { ++ WMT_DBG_FUNC("uart still idle traffic , we don't query temp temperature..\n"); ++ } ++ } ++#endif ++ } ++#endif ++ /* Query condition 3: */ ++ /* If the query time exceeds the a certain of period, refresh temp table. */ ++ /* */ ++ if (!query_cond) { ++ /* time overflow, we refresh temp table again for simplicity! */ ++ if ((now_time.tv_sec < query_time.tv_sec) || ++ ((now_time.tv_sec > query_time.tv_sec) && (now_time.tv_sec - query_time.tv_sec) > REFRESH_TIME)) { ++ query_cond = 1; ++ ++ WMT_INFO_FUNC("It is long time (> %d sec) not to query, we must query temp temperature..\n", ++ REFRESH_TIME); ++ for (index = 0; index < HISTORY_NUM; index++) ++ temp_table[index] = 99; ++ ++ } ++ } ++ ++ if (query_cond) { ++ /* update the temperature record */ ++ mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE); ++ current_temp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ); ++ mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE); ++ idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; ++ temp_table[idx_temp_table] = current_temp; ++ do_gettimeofday(&query_time); ++ ++ WMT_INFO_FUNC("[Thermal] current_temp = 0x%x\n", (current_temp & 0xFF)); ++ } else { ++ current_temp = temp_table[idx_temp_table]; ++ idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; ++ temp_table[idx_temp_table] = current_temp; ++ } ++ ++ /* */ ++ /* Dump information */ ++ /* */ ++ WMT_DBG_FUNC("[Thermal] idx_temp_table = %d\n", idx_temp_table); ++ WMT_DBG_FUNC("[Thermal] now.time = %d, query.time = %d, REFRESH_TIME = %d\n", now_time.tv_sec, ++ query_time.tv_sec, REFRESH_TIME); ++ ++ WMT_DBG_FUNC("[0] = %d, [1] = %d, [2] = %d, [3] = %d, [4] = %d\n----\n", ++ temp_table[0], temp_table[1], temp_table[2], temp_table[3], temp_table[4]); ++ ++ return_temp = ((current_temp & 0x80) == 0x0) ? current_temp : (-1) * (current_temp & 0x7f); ++ ++ return return_temp; ++} ++ ++ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 iRet = 0; ++ UINT8 wrBuf[NAME_MAX + 1] = { 0 }; ++ INT32 copySize = (count < NAME_MAX) ? count : NAME_MAX; ++ ++ WMT_LOUD_FUNC("count:%d copySize:%d\n", count, copySize); ++ ++ if (copySize > 0) { ++ if (copy_from_user(wrBuf, buf, copySize)) { ++ iRet = -EFAULT; ++ goto write_done; ++ } ++ iRet = copySize; ++ wrBuf[NAME_MAX] = '\0'; ++ ++ if (!strncasecmp(wrBuf, "ok", NAME_MAX)) { ++ WMT_DBG_FUNC("resp str ok\n"); ++ /* pWmtDevCtx->cmd_result = 0; */ ++ wmt_lib_trigger_cmd_signal(0); ++ } else { ++ WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf); ++ /* pWmtDevCtx->cmd_result = -1; */ ++ wmt_lib_trigger_cmd_signal(-1); ++ } ++ /* complete(&pWmtDevCtx->cmd_comp); */ ++ ++ } ++ ++write_done: ++ return iRet; ++} ++ ++ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 iRet = 0; ++ PUINT8 pCmd = NULL; ++ UINT32 cmdLen = 0; ++ ++ pCmd = wmt_lib_get_cmd(); ++ ++ if (pCmd != NULL) { ++ cmdLen = osal_strlen(pCmd) < NAME_MAX ? osal_strlen(pCmd) : NAME_MAX; ++ WMT_DBG_FUNC("cmd str(%s)\n", pCmd); ++ if (copy_to_user(buf, pCmd, cmdLen)) ++ iRet = -EFAULT; ++ else ++ iRet = cmdLen; ++ ++ } ++#if 0 ++ if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { ++ iRet = osal_strlen(localBuf) < NAME_MAX ? osal_strlen(localBuf) : NAME_MAX; ++ /* we got something from STP driver */ ++ WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf); ++ if (copy_to_user(buf, localBuf, iRet)) { ++ iRet = -EFAULT; ++ goto read_done; ++ } ++ } ++#endif ++ return iRet; ++} ++ ++unsigned int WMT_poll(struct file *filp, poll_table *wait) ++{ ++ UINT32 mask = 0; ++ P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event(); ++ ++ poll_wait(filp, &pEvent->waitQueue, wait); ++ /* empty let select sleep */ ++ if (MTK_WCN_BOOL_TRUE == wmt_lib_get_cmd_status()) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ ++#if 0 ++ if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) ++ mask |= POLLIN | POLLRDNORM; /* readable */ ++ ++#endif ++ mask |= POLLOUT | POLLWRNORM; /* writable */ ++ return mask; ++} ++ ++/* INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) */ ++long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ ++ INT32 iRet = 0; ++ UINT8 *pBuffer = NULL; ++ ++ WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); ++ switch (cmd) { ++ case WMT_IOCTL_SET_PATCH_NAME: /* patch location */ ++ { ++ ++ pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++ if (!pBuffer) { ++ WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); ++ return 0; ++ } ++ if (copy_from_user(pBuffer, (void *)arg, NAME_MAX)) { ++ iRet = -EFAULT; ++ kfree(pBuffer); ++ break; ++ } ++ pBuffer[NAME_MAX] = '\0'; ++ wmt_lib_set_patch_name(pBuffer); ++ kfree(pBuffer); ++ } ++ break; ++ ++ case WMT_IOCTL_SET_STP_MODE: /* stp/hif/fm mode */ ++ ++ /* set hif conf */ ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal = NULL; ++ P_WMT_HIF_CONF pHif = NULL; ++ ++ iRet = wmt_lib_set_hif(arg); ++ if (0 != iRet) { ++ WMT_INFO_FUNC("wmt_lib_set_hif fail\n"); ++ break; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_INFO_FUNC("get_free_lxop fail\n"); ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_HIF_CONF; ++ ++ pHif = wmt_lib_get_hif(); ++ ++ osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF)); ++ pOp->op.u4InfoBit = WMT_OP_HIF_BIT; ++ pSignal->timeoutValue = 0; ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d)\n", bRet); ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_FUNC_ONOFF_CTRL: /* test turn on/off func */ ++ ++ do { ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (arg & 0x80000000) ++ bRet = mtk_wcn_wmt_func_on(arg & 0xF); ++ else ++ bRet = mtk_wcn_wmt_func_off(arg & 0xF); ++ ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_LPBK_POWER_CTRL: ++ /*switch Loopback function on/off ++ arg: bit0 = 1:turn loopback function on ++ bit0 = 0:turn loopback function off ++ */ ++ do { ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ ++ if (arg & 0x01) ++ bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); ++ else ++ bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); ++ ++ iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_LPBK_TEST: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT32 u4Wait; ++ /* UINT8 lpbk_buf[1024] = {0}; */ ++ UINT32 effectiveLen = 0; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ if (copy_from_user(&effectiveLen, (void *)arg, sizeof(effectiveLen))) { ++ iRet = -EFAULT; ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ break; ++ } ++ if (effectiveLen > sizeof(gLpbkBuf)) { ++ iRet = -EFAULT; ++ WMT_ERR_FUNC("length is too long\n"); ++ break; ++ } ++ WMT_DBG_FUNC("len = %d\n", effectiveLen); ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ u4Wait = 2000; ++ if (copy_from_user(&gLpbkBuf[0], (void *)arg + sizeof(unsigned long), effectiveLen)) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_LPBK; ++ pOp->op.au4OpData[0] = effectiveLen; /* packet length */ ++ pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; /* packet buffer pointer */ ++ memcpy(&gLpbkBufLog, &gLpbkBuf[((effectiveLen >= 4) ? effectiveLen - 4 : 0)], 4); ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", ++ pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n", ++ pOp->op.opId, pOp->op.au4OpData[0], gLpbkBufLog); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ if (copy_to_user((void *)arg + sizeof(SIZE_T) + sizeof(UINT8[2048]), gLpbkBuf, iRet)) { ++ iRet = -EFAULT; ++ break; ++ } ++ ++ } while (0); ++ ++ break; ++ ++ case WMT_IOCTL_ADIE_LPBK_TEST: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_ADIE_LPBK_TEST; ++ pOp->op.au4OpData[0] = 0; ++ pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d)abort\n", pOp->op.opId); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ if (copy_to_user((void *)arg + sizeof(SIZE_T), gLpbkBuf, iRet)) { ++ iRet = -EFAULT; ++ break; ++ } ++ ++ } while (0); ++ ++ break; ++ ++ case 10: ++ { ++ pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++ if (!pBuffer) { ++ WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); ++ return 0; ++ } ++ wmt_lib_host_awake_get(); ++ mtk_wcn_stp_coredump_start_ctrl(1); ++ osal_strcpy(pBuffer, "MT662x f/w coredump start-"); ++ if (copy_from_user ++ (pBuffer + osal_strlen(pBuffer), (void *)arg, NAME_MAX - osal_strlen(pBuffer))) { ++ /* osal_strcpy(pBuffer, "MT662x f/w assert core dump start"); */ ++ WMT_ERR_FUNC("copy assert string failed\n"); ++ } ++ pBuffer[NAME_MAX] = '\0'; ++ osal_dbg_assert_aee(pBuffer, pBuffer); ++ kfree(pBuffer); ++ } ++ break; ++ case 11: ++ { ++ osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); ++ wmt_lib_host_awake_put(); ++ } ++ break; ++ ++ case WMT_IOCTL_GET_CHIP_INFO: ++ { ++ if (0 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_CHIPID); ++ else if (1 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_HWVER); ++ else if (2 == arg) ++ return wmt_lib_get_icinfo(WMTCHIN_FWVER); ++ ++ } ++ break; ++ ++ case WMT_IOCTL_SET_LAUNCHER_KILL:{ ++ if (1 == arg) { ++ WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n"); ++ wmt_lib_set_stp_wmt_last_close(1); ++ } else { ++ wmt_lib_set_stp_wmt_last_close(0); ++ } ++ ++ } ++ break; ++ ++ case WMT_IOCTL_SET_PATCH_NUM:{ ++ pAtchNum = arg; ++ WMT_DBG_FUNC(" get patch num from launcher = %d\n", pAtchNum); ++ wmt_lib_set_patch_num(pAtchNum); ++ pPatchInfo = kcalloc(pAtchNum, sizeof(WMT_PATCH_INFO), GFP_ATOMIC); ++ if (!pPatchInfo) { ++ WMT_ERR_FUNC("allocate memory fail!\n"); ++ break; ++ } ++ } ++ break; ++ ++ case WMT_IOCTL_SET_PATCH_INFO:{ ++ WMT_PATCH_INFO wMtPatchInfo; ++ P_WMT_PATCH_INFO pTemp = NULL; ++ UINT32 dWloadSeq; ++ static UINT32 counter; ++ ++ if (!pPatchInfo) { ++ WMT_ERR_FUNC("NULL patch info pointer\n"); ++ break; ++ } ++ ++ if (copy_from_user(&wMtPatchInfo, (void *)arg, sizeof(WMT_PATCH_INFO))) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ ++ dWloadSeq = wMtPatchInfo.dowloadSeq; ++ WMT_DBG_FUNC( ++ "patch dl seq %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n", ++ dWloadSeq, wMtPatchInfo.patchName, ++ wMtPatchInfo.addRess[0], ++ wMtPatchInfo.addRess[1], ++ wMtPatchInfo.addRess[2], ++ wMtPatchInfo.addRess[3]); ++ osal_memcpy(pPatchInfo + dWloadSeq - 1, &wMtPatchInfo, sizeof(WMT_PATCH_INFO)); ++ pTemp = pPatchInfo + dWloadSeq - 1; ++ if (++counter == pAtchNum) { ++ wmt_lib_set_patch_info(pPatchInfo); ++ counter = 0; ++ } ++ } ++ break; ++ ++ case WMT_IOCTL_WMT_COREDUMP_CTRL: ++ mtk_wcn_stp_coredump_flag_ctrl(arg); ++ break; ++ case WMT_IOCTL_WMT_QUERY_CHIPID: ++ { ++ iRet = mtk_wcn_wmt_chipid_query(); ++ WMT_WARN_FUNC("chipid = 0x%x\n", iRet); ++ } ++ break; ++ case WMT_IOCTL_SEND_BGW_DS_CMD: ++ do { ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ UINT8 desense_buf[14] = { 0 }; ++ UINT32 effectiveLen = 14; ++ P_OSAL_SIGNAL pSignal = NULL; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ iRet = -EFAULT; ++ break; ++ } ++ if (copy_from_user(&desense_buf[0], (void *)arg, effectiveLen)) { ++ WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); ++ iRet = -EFAULT; ++ break; ++ } ++ pSignal = &pOp->signal; ++ pOp->op.opId = WMT_OPID_BGW_DS; ++ pOp->op.au4OpData[0] = effectiveLen; /* packet length */ ++ pOp->op.au4OpData[1] = (SIZE_T) &desense_buf[0]; /* packet buffer pointer */ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,opid(%d) abort\n", pOp->op.opId); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); ++ iRet = -1; ++ break; ++ } ++ WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ iRet = pOp->op.au4OpData[0]; ++ ++ } while (0); ++ ++ break; ++ case WMT_IOCTL_FW_DBGLOG_CTRL: ++ { ++ iRet = wmt_plat_set_dbg_mode(arg); ++ if (iRet == 0) ++ wmt_dbg_fwinfor_from_emi(0, 1, 0); ++ } ++ break; ++ case WMT_IOCTL_DYNAMIC_DUMP_CTRL: ++ { ++ UINT32 i = 0, j = 0, k = 0; ++ UINT8 *pBuf = NULL; ++ UINT32 int_buf[10]; ++ char Buffer[10][11]; ++ ++ pBuf = kmalloc(DYNAMIC_DUMP_BUF + 1, GFP_KERNEL); ++ if (!pBuf) { ++ WMT_ERR_FUNC("pBuf kmalloc memory fail\n"); ++ return 0; ++ } ++ if (copy_from_user(pBuf, (void *)arg, DYNAMIC_DUMP_BUF)) { ++ iRet = -EFAULT; ++ kfree(pBuf); ++ break; ++ } ++ pBuf[DYNAMIC_DUMP_BUF] = '\0'; ++ WMT_INFO_FUNC("get dynamic dump data from property(%s)\n", pBuf); ++ memset(Buffer, 0, 10*11); ++ for (i = 0; i < DYNAMIC_DUMP_BUF; i++) { ++ if (pBuf[i] == '/') { ++ k = 0; ++ j++; ++ } else { ++ Buffer[j][k] = pBuf[i]; ++ k++; ++ } ++ } ++ for (j = 0; j < 10; j++) { ++ iRet = kstrtou32(Buffer[j], 0, &int_buf[j]); ++ if (iRet) { ++ WMT_ERR_FUNC("string convert fail(%d)\n", iRet); ++ break; ++ } ++ WMT_INFO_FUNC("dynamic dump data buf[%d]:(0x%x)\n", j, int_buf[j]); ++ } ++ wmt_plat_set_dynamic_dumpmem(int_buf); ++ kfree(pBuf); ++ } ++ break; ++ default: ++ iRet = -EINVAL; ++ WMT_WARN_FUNC("unknown cmd (%d)\n", cmd); ++ break; ++ } ++ ++ return iRet; ++} ++#ifdef CONFIG_COMPAT ++long WMT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret; ++ WMT_INFO_FUNC("cmd[0x%x]\n", cmd); ++ switch (cmd) { ++ case COMPAT_WMT_IOCTL_SET_PATCH_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_LPBK_TEST: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_LPBK_TEST, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_SET_PATCH_INFO: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_INFO, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_PORT_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_PORT_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_WMT_CFG_NAME: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_WMT_CFG_NAME, (unsigned long)compat_ptr(arg)); ++ break; ++ case COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD: ++ ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SEND_BGW_DS_CMD, (unsigned long)compat_ptr(arg)); ++ break; ++ default: { ++ ret = WMT_unlocked_ioctl(filp, cmd, arg); ++ break; ++ } ++ } ++ return ret; ++} ++#endif ++static int WMT_open(struct inode *inode, struct file *file) ++{ ++ long ret; ++ ++ WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ret = wait_event_timeout(gWmtInitWq, gWmtInitDone != 0, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); ++ if (!ret) { ++ WMT_WARN_FUNC("wait_event_timeout (%d)ms,(%d)jiffies,return -EIO\n", ++ WMT_DEV_INIT_TO_MS, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); ++ return -EIO; ++ } ++ ++ if (atomic_inc_return(&gWmtRefCnt) == 1) ++ WMT_INFO_FUNC("1st call\n"); ++ ++ return 0; ++} ++ ++static int WMT_close(struct inode *inode, struct file *file) ++{ ++ WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); ++ ++ if (atomic_dec_return(&gWmtRefCnt) == 0) ++ WMT_INFO_FUNC("last call\n"); ++ ++ return 0; ++} ++ ++const struct file_operations gWmtFops = { ++ .open = WMT_open, ++ .release = WMT_close, ++ .read = WMT_read, ++ .write = WMT_write, ++/* .ioctl = WMT_ioctl, */ ++ .unlocked_ioctl = WMT_unlocked_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = WMT_compat_ioctl, ++#endif ++ .poll = WMT_poll, ++}; ++ ++void wmt_dev_bgw_desense_init(VOID) ++{ ++ bgw_init_socket(); ++} ++ ++void wmt_dev_bgw_desense_deinit(VOID) ++{ ++ bgw_destroy_netlink_kernel(); ++} ++ ++void wmt_dev_send_cmd_to_daemon(UINT32 cmd) ++{ ++ send_command_to_daemon(cmd); ++} ++ ++static int WMT_init(void) ++{ ++ dev_t devID = MKDEV(gWmtMajor, 0); ++ INT32 cdevErr = -1; ++ INT32 ret = -1; ++ ++ WMT_INFO_FUNC("WMT Version= %s DATE=%s\n", MTK_WMT_VERSION, MTK_WMT_DATE); ++ /* Prepare a UINT8 device */ ++ /*static allocate chrdev */ ++ gWmtInitDone = 0; ++ init_waitqueue_head((wait_queue_head_t *) &gWmtInitWq); ++ stp_drv_init(); ++ ++ ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME); ++ if (ret) { ++ WMT_ERR_FUNC("fail to register chrdev\n"); ++ return ret; ++ } ++ cdev_init(&gWmtCdev, &gWmtFops); ++ gWmtCdev.owner = THIS_MODULE; ++ cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM); ++ if (cdevErr) { ++ WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); ++ goto error; ++ } ++ WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor); ++#if WMT_CREATE_NODE_DYNAMIC ++ wmt_class = class_create(THIS_MODULE, "stpwmt"); ++ if (IS_ERR(wmt_class)) ++ goto error; ++ wmt_dev = device_create(wmt_class, NULL, devID, NULL, "stpwmt"); ++ if (IS_ERR(wmt_dev)) ++ goto error; ++#endif ++ ++#if 0 ++ pWmtDevCtx = wmt_drv_create(); ++ if (!pWmtDevCtx) { ++ WMT_ERR_FUNC("wmt_drv_create() fails\n"); ++ goto error; ++ } ++ ret = wmt_drv_init(pWmtDevCtx); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret); ++ goto error; ++ } ++ WMT_INFO_FUNC("stp_btmcb_reg\n"); ++ wmt_cdev_btmcb_reg(); ++ ret = wmt_drv_start(pWmtDevCtx); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret); ++ goto error; ++ } ++#endif ++ ret = wmt_lib_init(); ++ if (ret) { ++ WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret); ++ goto error; ++ } ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_setup(); ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ wmt_dev_proc_for_aee_setup(); ++#endif ++ ++ WMT_INFO_FUNC("wmt_dev register thermal cb\n"); ++ wmt_lib_register_thermal_ctrl_cb(wmt_dev_tm_temp_query); ++ wmt_dev_bgw_desense_init(); ++ gWmtInitDone = 1; ++ wake_up(&gWmtInitWq); ++ osal_sleepable_lock_init(&g_es_lr_lock); ++ INIT_WORK(&gPwrOnOffWork, wmt_pwr_on_off_handler); ++#ifdef CONFIG_EARLYSUSPEND ++ register_early_suspend(&wmt_early_suspend_handler); ++ WMT_INFO_FUNC("register_early_suspend finished\n"); ++#else ++ wmt_fb_notifier.notifier_call = wmt_fb_notifier_callback; ++ ret = fb_register_client(&wmt_fb_notifier); ++ if (ret) ++ WMT_ERR_FUNC("wmt register fb_notifier failed! ret(%d)\n", ret); ++ else ++ WMT_INFO_FUNC("wmt register fb_notifier OK!\n"); ++#endif ++ WMT_INFO_FUNC("success\n"); ++ return 0; ++ ++error: ++ wmt_lib_deinit(); ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_remove(); ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!(IS_ERR(wmt_dev))) ++ device_destroy(wmt_class, devID); ++ if (!(IS_ERR(wmt_class))) { ++ class_destroy(wmt_class); ++ wmt_class = NULL; ++ } ++#endif ++ ++ if (cdevErr == 0) ++ cdev_del(&gWmtCdev); ++ ++ if (ret == 0) { ++ unregister_chrdev_region(devID, WMT_DEV_NUM); ++ gWmtMajor = -1; ++ } ++ ++ WMT_ERR_FUNC("fail\n"); ++ ++ return -1; ++} ++ ++static void WMT_exit(void) ++{ ++ dev_t dev = MKDEV(gWmtMajor, 0); ++ ++ osal_sleepable_lock_deinit(&g_es_lr_lock); ++#ifdef CONFIG_EARLYSUSPEND ++ unregister_early_suspend(&wmt_early_suspend_handler); ++ WMT_INFO_FUNC("unregister_early_suspend finished\n"); ++#else ++ fb_unregister_client(&wmt_fb_notifier); ++#endif ++ ++ wmt_dev_bgw_desense_deinit(); ++ ++ wmt_lib_register_thermal_ctrl_cb(NULL); ++ ++ wmt_lib_deinit(); ++ ++#if CFG_WMT_DBG_SUPPORT ++ wmt_dev_dbg_remove(); ++#endif ++ ++#if CFG_WMT_PROC_FOR_AEE ++ wmt_dev_proc_for_aee_remove(); ++#endif ++#if WMT_CREATE_NODE_DYNAMIC ++ if (wmt_dev) { ++ device_destroy(wmt_class, dev); ++ wmt_dev = NULL; ++ } ++ if (wmt_class) { ++ class_destroy(wmt_class); ++ wmt_class = NULL; ++ } ++#endif ++ cdev_del(&gWmtCdev); ++ unregister_chrdev_region(dev, WMT_DEV_NUM); ++ gWmtMajor = -1; ++ ++ stp_drv_exit(); ++ ++ WMT_INFO_FUNC("done\n"); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++int mtk_wcn_soc_common_drv_init(void) ++{ ++ return WMT_init(); ++ ++} ++EXPORT_SYMBOL(mtk_wcn_soc_common_drv_init); ++void mtk_wcn_soc_common_drv_exit(void) ++{ ++ return WMT_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_soc_common_drv_exit); ++ ++#else ++module_init(WMT_init); ++module_exit(WMT_exit); ++#endif ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("MediaTek Inc WCN"); ++MODULE_DESCRIPTION("MTK WCN combo driver for WMT function"); ++ ++module_param(gWmtMajor, uint, 0); +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c +new file mode 100644 +index 000000000000..8d5c23732c1c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c +@@ -0,0 +1,610 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-EXP]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++ ++#include ++#include ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++wmt_wlan_probe_cb mtk_wcn_wlan_probe = NULL; ++wmt_wlan_remove_cb mtk_wcn_wlan_remove = NULL; ++wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt = NULL; ++wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr = NULL; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++OSAL_BIT_OP_VAR gBtWifiGpsState; ++OSAL_BIT_OP_VAR gGpsFmState; ++UINT32 gWifiProbed = 0; ++UINT32 gWmtDbgLvl = WMT_LOG_ERR; ++MTK_WCN_BOOL g_pwr_off_flag = MTK_WCN_BOOL_TRUE; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId) ++{ ++ P_OSAL_OP pOp; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = opId; ++ pOp->op.au4OpData[0] = type; ++ if (WMTDRV_TYPE_WIFI == type) ++ pSignal->timeoutValue = 4000; ++ /*donot block system server/init/netd from longer than 5s, in case of ANR happens*/ ++ else ++ pSignal->timeoutValue = (WMT_OPID_FUNC_ON == pOp->op.opId) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ /*do not check return value, we will do this either way */ ++ wmt_lib_host_awake_get(); ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ wmt_lib_host_awake_put(); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ wmt_lib_host_awake_put(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ else ++ WMT_WARN_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ return bRet; ++} ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) ++#endif ++{ ++ MTK_WCN_BOOL ret; ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT OFF ====>"); ++ ++ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF); ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT OFF <===="); ++ ++ return ret; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_func_off); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) ++#endif ++{ ++ MTK_WCN_BOOL ret; ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday("############ BT ON ====>"); ++ ++ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON); ++ ++ if (type == WMTDRV_TYPE_BT) ++ osal_printtimeofday(" ############BT ON <===="); ++ ++ return ret; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_func_on); ++#endif ++ ++VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type) ++{ ++ if (on) ++ mtk_wcn_wmt_func_on(type); ++ else ++ mtk_wcn_wmt_func_off(type); ++} ++ ++/* ++return value: ++enable/disable thermal sensor function: true(1)/false(0) ++read thermal sensor function:thermal value ++ ++*/ ++#if WMT_EXP_HID_API_EXPORT ++INT8 _mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++#else ++INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) ++#endif ++{ ++ P_OSAL_OP pOp; ++ P_WMT_OP pOpData; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ /*parameter validation check */ ++ if (WMTTHERM_MAX < eType || WMTTHERM_ENABLE > eType) { ++ WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ /*check if chip support thermal control function or not */ ++ bRet = wmt_lib_is_therm_ctrl_support(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("thermal ctrl function not supported\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pOpData = &pOp->op; ++ pOpData->opId = WMT_OPID_THERM_CTRL; ++ /*parameter fill */ ++ pOpData->au4OpData[0] = eType; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return -1; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ /*0xFF means read error occurs */ ++ /*will return to function driver */ ++ pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE; ++ } else { ++ WMT_INFO_FUNC("OPID(%d) type(%d) return(%d) ok\n\n", ++ pOpData->opId, pOpData->au4OpData[0], pOpData->au4OpData[1]); ++ } ++ /*return value will be put to lxop->op.au4OpData[1] */ ++ WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08x)\n", eType, pOpData->au4OpData[1]); ++ return (INT8) pOpData->au4OpData[1]; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++ENUM_WMTHWVER_TYPE_T _mtk_wcn_wmt_hwver_get(VOID) ++#else ++ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) ++#endif ++{ ++ /* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ ++ /* TODO: how do we extend for new chip and newer revision? */ ++ /* TODO: This way is hard to extend */ ++ return wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) ++#endif ++{ ++ P_OSAL_OP pOp; ++ P_WMT_OP pOpData; ++ MTK_WCN_BOOL bRet; ++ P_OSAL_SIGNAL pSignal; ++ ++ if (WMTDSNS_MAX <= eType) { ++ WMT_ERR_FUNC("invalid desense control command (%d)\n", eType); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ /*check if chip support thermal control function or not */ ++ bRet = wmt_lib_is_dsns_ctrl_support(); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("thermal ctrl function not supported\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pOpData = &pOp->op; ++ pOpData->opId = WMT_OPID_DSNS; ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*parameter fill */ ++ if ((WMTDSNS_FM_DISABLE <= eType) && (WMTDSNS_FM_GPS_ENABLE >= eType)) { ++ pOpData->au4OpData[0] = WMTDRV_TYPE_FM; ++ pOpData->au4OpData[1] = eType; ++ } ++ ++ WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ if (MTK_WCN_BOOL_FALSE == bRet) ++ WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ else ++ WMT_INFO_FUNC("OPID(%d) type(%d) ok\n\n", pOpData->opId, pOpData->au4OpData[0]); ++ ++ return bRet; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++#else ++INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) ++#endif ++{ ++ return (INT32) wmt_lib_msgcb_reg(eType, pCb); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++#else ++INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) ++#endif ++{ ++ return (INT32) wmt_lib_msgcb_unreg(eType); ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++#else ++INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) ++#endif ++{ ++ wmt_lib_ps_set_sdio_psop(own_cb); ++ return 0; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++INT32 _mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++#else ++INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) ++#endif ++{ ++ wmt_lib_ps_irq_cb(); ++ return 0; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); ++#endif ++ ++#if WMT_EXP_HID_API_EXPORT ++MTK_WCN_BOOL _mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++#else ++MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) ++#endif ++{ ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_WARN_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ wmt_lib_set_host_assert_info(type, reason, 1); ++ ++ pSignal = &pOp->signal; ++ ++ pOp->op.opId = WMT_OPID_CMD_TEST; ++ ++ pSignal->timeoutValue = MAX_EACH_WMT_CMD; ++ /*this test command should be run with usb cable connected, so no host awake is needed */ ++ /* wmt_lib_host_awake_get(); */ ++ pOp->op.au4OpData[0] = 0; ++ ++ /*wake up chip first */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed,assert flow abort\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ bRet = wmt_lib_put_act_op(pOp); ++ ENABLE_PSM_MONITOR(); ++ ++ /* wmt_lib_host_awake_put(); */ ++ WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", ++ pOp->op.opId, ++ pOp->op.au4OpData[0], ++ pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ return bRet; ++} ++#if !WMT_EXP_HID_API_EXPORT ++EXPORT_SYMBOL(mtk_wcn_wmt_assert); ++#endif ++ ++INT8 mtk_wcn_wmt_co_clock_flag_get(void) ++{ ++ return wmt_lib_co_clock_get(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_co_clock_flag_get); ++ ++INT32 mtk_wcn_wmt_system_state_reset(void) ++{ ++ osal_memset(&gBtWifiGpsState, 0, osal_sizeof(gBtWifiGpsState)); ++ osal_memset(&gGpsFmState, 0, osal_sizeof(gGpsFmState)); ++ ++ return 0; ++} ++ ++INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo) ++{ ++ INT32 iRet = -1; ++ ++ if (!pWmtWlanCbInfo) { ++ WMT_ERR_FUNC("wlan cb info in null!\n"); ++ return -1; ++ } ++ ++ WMT_INFO_FUNC("wmt wlan cb register\n"); ++ mtk_wcn_wlan_probe = pWmtWlanCbInfo->wlan_probe_cb; ++ mtk_wcn_wlan_remove = pWmtWlanCbInfo->wlan_remove_cb; ++ mtk_wcn_wlan_bus_tx_cnt = pWmtWlanCbInfo->wlan_bus_cnt_get_cb; ++ mtk_wcn_wlan_bus_tx_cnt_clr = pWmtWlanCbInfo->wlan_bus_cnt_clr_cb; ++ ++ if (gWifiProbed) { ++ WMT_INFO_FUNC("wlan has been done power on,call probe directly\n"); ++ iRet = (*mtk_wcn_wlan_probe) (); ++ if (!iRet) { ++ WMT_INFO_FUNC("call wlan probe OK when do wlan register to wmt\n"); ++ gWifiProbed = 0; ++ } else { ++ WMT_ERR_FUNC("call wlan probe fail(%d) when do wlan register to wmt\n", iRet); ++ return -2; ++ } ++ } ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wlan_reg); ++ ++INT32 mtk_wcn_wmt_wlan_unreg(void) ++{ ++ WMT_INFO_FUNC("wmt wlan cb unregister\n"); ++ mtk_wcn_wlan_probe = NULL; ++ mtk_wcn_wlan_remove = NULL; ++ mtk_wcn_wlan_bus_tx_cnt = NULL; ++ mtk_wcn_wlan_bus_tx_cnt_clr = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wlan_unreg); ++ ++MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value) ++{ ++ g_pwr_off_flag = value; ++ if (g_pwr_off_flag) ++ WMT_DBG_FUNC("enable connsys power off flag\n"); ++ else ++ WMT_INFO_FUNC("disable connsys power off, maybe need trigger coredump!\n"); ++ return g_pwr_off_flag; ++} ++EXPORT_SYMBOL(mtk_wcn_set_connsys_power_off_flag); ++ ++#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++VOID mtk_wcn_wmt_exp_init(void) ++{ ++ MTK_WCN_WMT_EXP_CB_INFO wmtExpCb = { ++ ++ .wmt_func_on_cb = _mtk_wcn_wmt_func_on, ++ .wmt_func_off_cb = _mtk_wcn_wmt_func_off, ++ .wmt_therm_ctrl_cb = _mtk_wcn_wmt_therm_ctrl, ++ .wmt_hwver_get_cb = _mtk_wcn_wmt_hwver_get, ++ .wmt_dsns_ctrl_cb = _mtk_wcn_wmt_dsns_ctrl, ++ .wmt_msgcb_reg_cb = _mtk_wcn_wmt_msgcb_reg, ++ .wmt_msgcb_unreg_cb = _mtk_wcn_wmt_msgcb_unreg, ++ .wmt_sdio_op_reg_cb = _mtk_wcn_stp_wmt_sdio_op_reg, ++ .wmt_sdio_host_awake_cb = _mtk_wcn_stp_wmt_sdio_host_awake, ++ .wmt_assert_cb = _mtk_wcn_wmt_assert ++ }; ++ ++ mtk_wcn_wmt_exp_cb_reg(&wmtExpCb); ++} ++ ++VOID mtk_wcn_wmt_exp_deinit(void) ++{ ++ mtk_wcn_wmt_exp_cb_unreg(); ++} ++#ifdef CONFIG_MTK_COMBO_ANT ++/* ++ ctrlId: get ram code status opId or ram code download opId ++ pBuf: pointer to ANT ram code ++ length: total length of ANT ram code ++*/ ++ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, ++ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq) ++{ ++ ENUM_WMT_ANT_RAM_STATUS eRet = 0; ++ P_OSAL_OP pOp = NULL; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; ++ P_OSAL_SIGNAL pSignal; ++ ++ /*1. parameter validation check */ ++ /*for WMT_ANT_RAM_GET_STATUS, ignore pBuf and length */ ++ /*for WMT_ANT_RAM_DOWNLOAD, ++ pBuf must not be NULL, kernel space memory pointer ++ length must be large than 0 */ ++ ++ if ((WMT_ANT_RAM_GET_STATUS > ctrlId) || (WMT_ANT_RAM_CTRL_MAX <= ctrlId)) { ++ WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); ++ eRet = WMT_ANT_RAM_PARA_ERR; ++ return eRet; ++ } ++ ++ if ((WMT_ANT_RAM_DOWNLOAD == ctrlId) && ++ ((NULL == pBuf) || ++ (0 >= length) || ++ (1000 < length) || (seq >= WMT_ANT_RAM_SEQ_MAX) || (seq < WMT_ANT_RAM_START_PKT))) { ++ eRet = WMT_ANT_RAM_PARA_ERR; ++ WMT_ERR_FUNC ++ ("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x),seq(%d) .\n", ++ ctrlId, pBuf, length, seq); ++ return eRet; ++ } ++ /*get WMT opId */ ++ pOp = wmt_lib_get_free_op(); ++ if (!pOp) { ++ WMT_DBG_FUNC("get_free_lxop fail\n"); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ ++ pSignal = &pOp->signal; ++ pSignal->timeoutValue = ++ (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD; ++ ++ pOp->op.opId = ++ (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? WMT_OPID_ANT_RAM_DOWN : WMT_OPID_ANT_RAM_STA_GET; ++ pOp->op.au4OpData[0] = (size_t) pBuf; ++ pOp->op.au4OpData[1] = length; ++ pOp->op.au4OpData[2] = seq; ++ ++ ++ /*disable PSM monitor */ ++ if (DISABLE_PSM_MONITOR()) { ++ WMT_ERR_FUNC("wake up failed\n"); ++ wmt_lib_put_op_to_free_queue(pOp); ++ return MTK_WCN_BOOL_FALSE; ++ } ++ /*wakeup wmtd thread */ ++ bRet = wmt_lib_put_act_op(pOp); ++ ++ /*enable PSM monitor */ ++ ENABLE_PSM_MONITOR(); ++ ++ WMT_DBG_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n", ++ pOp->op.opId, ++ bRet, ++ pOp->op.au4OpData[2], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); ++ ++ /*check return value and return result */ ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ eRet = WMT_ANT_RAM_OP_ERR; ++ } else { ++ eRet = (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? ++ WMT_ANT_RAM_DOWN_OK : ++ ((1 == pOp->op.au4OpData[2]) ? WMT_ANT_RAM_EXIST : WMT_ANT_RAM_NOT_EXIST); ++ } ++ ++ return eRet; ++ ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_ant_ram_ctrl); ++#endif ++ ++#endif ++VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value) ++{ ++ wmt_lib_soc_set_wifiver(Value); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_set_wifi_ver); +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +new file mode 100644 +index 000000000000..eb37baf87b02 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +@@ -0,0 +1,27 @@ ++ifeq ($(CONFIG_MTK_COMBO), y) ++ ++ccflags-y += \ ++ -I$(src)/../../linux/include \ ++ -I$(src)/../../linux/pri/include \ ++ -I$(src)/../../core/include \ ++ -I$(src)/../../include \ ++ -I$(src)/../include \ ++ -I$(src)/../../../common_detect \ ++ -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach \ ++ -DMTK_BT_HCI=1 ++ ++ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 ++ ++ifeq ($(CONFIG_MTK_TC1_FEATURE), y) ++ ccflags-y += -DCFG_TC1_FEATURE=1 ++else ++ ccflags-y += -DCFG_TC1_FEATURE=0 ++endif ++ ++obj-y += osal.o \ ++ bgw_desense.o \ ++ wmt_idc.o ++obj-$(CONFIG_MTK_COMBO_BT) += stp_chrdev_bt.o ++obj-$(CONFIG_MTK_COMBO_WIFI) += wmt_chrdev_wifi.o ++ ++endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c +new file mode 100644 +index 000000000000..11e45aa13087 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c +@@ -0,0 +1,153 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include "bgw_desense.h" ++ ++static struct sock *g_nl_sk; ++/* static struct sockaddr_nl src_addr, des_addr; */ ++/* static struct iovec iov; */ ++static int pid; ++/* static struct msghdr msg; */ ++ ++void bgw_destroy_netlink_kernel(void) ++{ ++ if (g_nl_sk != NULL) { ++ /* sock_release(g_nl_sk->sk_socket); */ ++ netlink_kernel_release(g_nl_sk); ++ MSG("release socket\n"); ++ return; ++ } ++ ERR("no socket yet\n"); ++} ++ ++void send_command_to_daemon(const int command /*struct sk_buff *skb */) ++{ ++/* ++ struct iphdr *iph; ++ struct ethhdr *ehdr; ++ */ ++ struct nlmsghdr *nlh; ++ struct sk_buff *nl_skb; ++ int res; ++ ++ MSG("here we will send command to native daemon\n"); ++/* if(skb == NULL) ++ { ++ ERR("invalid sk_buff\n"); ++ return; ++ } ++*/ ++ if (!g_nl_sk) { ++ ERR("invalid socket\n"); ++ return; ++ } ++ if (pid == 0) { ++ ERR("invalid native process pid\n"); ++ return; ++ } ++ /*alloc data buffer for sending to native */ ++ /*malloc data space at least 1500 bytes, which is ethernet data length */ ++ nl_skb = alloc_skb(NLMSG_SPACE(MAX_NL_MSG_LEN), GFP_ATOMIC); ++ if (nl_skb == NULL) { ++ ERR("malloc skb error\n"); ++ return; ++ } ++ MSG("malloc data space done\n"); ++ /* ++ ehdr = eth_hdr(skb); ++ iph = ip_hdr(skb); ++ */ ++ ++/* nlh = NLMSG_PUT(nl_skb, 0, 0, 0, NLMSG_SPACE(1500)-sizeof(struct nlmsghdr)); */ ++ nlh = nlmsg_put(nl_skb, 0, 0, 0, MAX_NL_MSG_LEN, 0); ++ if (nlh == NULL) { ++ MSG("nlh is NULL\n"); ++ kfree_skb(nl_skb); ++ return; ++ } ++ NETLINK_CB(nl_skb).portid = 0; ++ ++/* memcpy(NLMSG_DATA(nlh), ACK, 5); */ ++ *(char *)NLMSG_DATA(nlh) = command; ++ res = netlink_unicast(g_nl_sk, nl_skb, pid, MSG_DONTWAIT); ++ if (res == 0) { ++ MSG("send to user space process error\n"); ++ return; ++ } ++ ERR("send to user space process done, data length = %d\n", res); ++} ++ ++static void nl_data_handler(struct sk_buff *__skb) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ int i; ++ int len; ++ char str[128]; ++ ++ MSG("we got netlink message\n"); ++ len = NLMSG_SPACE(MAX_NL_MSG_LEN); ++ skb = skb_get(__skb); ++ if (skb == NULL) ++ ERR("skb_get return NULL"); ++ if (skb->len >= NLMSG_SPACE(0)) { /*presume there is 5byte payload at leaset */ ++ MSG("length is enough\n"); ++ nlh = nlmsg_hdr(skb); /* point to data which include in skb */ ++ memcpy(str, NLMSG_DATA(nlh), sizeof(str)); ++ for (i = 0; i < 3; i++) ++ MSG("str[%d = %c]", i, str[i]); ++ MSG("str[0] = %d, str[1] = %d, str[2] = %d\n", str[0], str[1], str[2]); ++ if (str[0] == 'B' && str[1] == 'G' && str[2] == 'W') { ++ MSG("got native daemon init command, record it's pid\n"); ++ pid = nlh->nlmsg_pid; /*record the native process PID */ ++ MSG("native daemon pid is %d\n", pid); ++ } else { ++ ERR("this is not BGW message, ignore it\n"); ++ return; ++ } ++ } else { ++ ERR("not engouth data length\n"); ++ return; ++ } ++ ++ kfree_skb(skb); ++ ++ send_command_to_daemon(ACK); ++} ++ ++int bgw_init_socket(void) ++{ ++ struct netlink_kernel_cfg cfg; ++ ++ memset(&cfg, 0, sizeof(cfg)); ++ cfg.input = nl_data_handler; ++ ++ g_nl_sk = __netlink_kernel_create(&init_net, NETLINK_TEST, THIS_MODULE, &cfg); ++ ++ if (g_nl_sk == NULL) { ++ ERR("netlink_kernel_create error\n"); ++ return -1; ++ } ++ MSG("netlink_kernel_create ok\n"); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c +new file mode 100644 +index 000000000000..959b68de2431 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c +@@ -0,0 +1,1211 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "osal_typedef.h" ++#include "osal.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ ++static UINT16 const crc16_table[256] = { ++ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, ++ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, ++ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, ++ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, ++ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, ++ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, ++ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, ++ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, ++ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, ++ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, ++ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, ++ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, ++ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, ++ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, ++ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, ++ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, ++ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, ++ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, ++ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, ++ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, ++ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, ++ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, ++ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, ++ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, ++ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, ++ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, ++ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, ++ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, ++ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, ++ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, ++ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, ++ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 ++}; ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*string operations*/ ++_osal_inline_ UINT32 osal_strlen(const char *str) ++{ ++ return strlen(str); ++} ++ ++_osal_inline_ INT32 osal_strcmp(const char *dst, const char *src) ++{ ++ return strcmp(dst, src); ++} ++ ++_osal_inline_ INT32 osal_strncmp(const char *dst, const char *src, UINT32 len) ++{ ++ return strncmp(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strcpy(char *dst, const char *src) ++{ ++ return strcpy(dst, src); ++} ++ ++_osal_inline_ char *osal_strncpy(char *dst, const char *src, UINT32 len) ++{ ++ return strncpy(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strcat(char *dst, const char *src) ++{ ++ return strcat(dst, src); ++} ++ ++_osal_inline_ char *osal_strncat(char *dst, const char *src, UINT32 len) ++{ ++ return strncat(dst, src, len); ++} ++ ++_osal_inline_ char *osal_strchr(const char *str, UINT8 c) ++{ ++ return strchr(str, c); ++} ++ ++_osal_inline_ char *osal_strsep(char **str, const char *c) ++{ ++ return strsep(str, c); ++} ++ ++_osal_inline_ int osal_strtol(const char *str, UINT32 adecimal, long *res) ++{ ++ return kstrtol(str, adecimal, res); ++} ++ ++_osal_inline_ char *osal_strstr(char *str1, const char *str2) ++{ ++ return strstr(str1, str2); ++} ++ ++INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...) ++{ ++ INT32 iRet = 0; ++ va_list args; ++ ++ /*va_start(args, fmt); */ ++ va_start(args, fmt); ++ /*iRet = snprintf(buf, len, fmt, args); */ ++ iRet = vsnprintf(buf, len, fmt, args); ++ va_end(args); ++ ++ return iRet; ++} ++ ++INT32 osal_err_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_err("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_dbg_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_debug("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_warn_print(const char *str, ...) ++{ ++ va_list args; ++ char tempString[DBG_LOG_STR_SIZE]; ++ ++ va_start(args, str); ++ vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); ++ va_end(args); ++ ++ pr_warn("%s", tempString); ++ ++ return 0; ++} ++ ++INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line) ++{ ++ if (!expr) { ++ pr_warn("%s (%d)\n", file, line); ++ /*BUG_ON(!expr); */ ++#ifdef CFG_COMMON_GPIO_DBG_PIN ++/* package this part */ ++ mt_set_gpio_out(GPIO70, GPIO_OUT_ZERO); ++ pr_warn("toggle GPIO70\n"); ++ udelay(10); ++ mt_set_gpio_out(GPIO70, GPIO_OUT_ONE); ++#endif ++ return 1; ++ } ++ return 0; ++ ++} ++ ++INT32 osal_dbg_assert_aee(const char *module, const char *detail_description) ++{ ++ osal_err_print("[WMT-ASSERT]" "[E][Module]:%s, [INFO]%s\n", module, detail_description); ++ ++#ifdef WMT_PLAT_ALPS ++ /* aee_kernel_warning(module,detail_description); */ ++ aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_WCN_ISSUE_INFO, module, detail_description); ++#endif ++ return 0; ++} ++ ++INT32 osal_sprintf(char *str, const char *format, ...) ++{ ++ INT32 iRet = 0; ++ va_list args; ++ ++ va_start(args, format); ++ iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); ++ va_end(args); ++ ++ return iRet; ++} ++ ++_osal_inline_ VOID *osal_malloc(UINT32 size) ++{ ++ return vmalloc(size); ++} ++ ++_osal_inline_ VOID osal_free(const VOID *dst) ++{ ++ vfree(dst); ++} ++ ++_osal_inline_ VOID *osal_memset(VOID *buf, INT32 i, UINT32 len) ++{ ++ return memset(buf, i, len); ++} ++ ++_osal_inline_ VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len) ++{ ++#ifdef CONFIG_MTK_WCN_ARM64 ++ char *tmp; ++ const char *s; ++ size_t i; ++ ++ tmp = dst; ++ s = src; ++ for (i = 0; i < len; i++) ++ tmp[i] = s[i]; ++ ++ return dst; ++ ++#else ++ return memcpy(dst, src, len); ++#endif ++} ++ ++_osal_inline_ INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len) ++{ ++ return memcmp(buf1, buf2, len); ++} ++ ++_osal_inline_ UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length) ++{ ++ UINT16 crc = 0; ++ UINT32 i = 0; ++ ++ /* FIXME: Add STP checksum feature */ ++ crc = 0; ++ for (i = 0; i < length; i++, buffer++) ++ crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; ++ ++ return crc; ++} ++ ++_osal_inline_ VOID osal_thread_show_stack(P_OSAL_THREAD pThread) ++{ ++ return show_stack(pThread->pThread, NULL); ++} ++ ++/* ++ *OSAL layer Thread Opeartion related APIs ++ * ++ * ++*/ ++_osal_inline_ INT32 osal_thread_create(P_OSAL_THREAD pThread) ++{ ++ pThread->pThread = kthread_create(pThread->pThreadFunc, pThread->pThreadData, pThread->threadName); ++ if (NULL == pThread->pThread) ++ return -1; ++ ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_thread_run(P_OSAL_THREAD pThread) ++{ ++ if (pThread->pThread) { ++ wake_up_process(pThread->pThread); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_thread_stop(P_OSAL_THREAD pThread) ++{ ++ INT32 iRet; ++ ++ if ((pThread) && (pThread->pThread)) { ++ iRet = kthread_stop(pThread->pThread); ++ /* pThread->pThread = NULL; */ ++ return iRet; ++ } ++ return -1; ++} ++ ++_osal_inline_ INT32 osal_thread_should_stop(P_OSAL_THREAD pThread) ++{ ++ if ((pThread) && (pThread->pThread)) ++ return kthread_should_stop(); ++ else ++ return 1; ++ ++} ++ ++_osal_inline_ INT32 ++osal_thread_wait_for_event(P_OSAL_THREAD pThread, P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker) ++{ ++ /* P_DEV_WMT pDevWmt;*/ ++ ++ if ((pThread) && (pThread->pThread) && (pEvent) && (pChecker)) { ++ /* pDevWmt = (P_DEV_WMT)(pThread->pThreadData);*/ ++ return wait_event_interruptible(pEvent->waitQueue, (/*!RB_EMPTY(&pDevWmt->rActiveOpQ) || */ ++ osal_thread_should_stop(pThread) ++ || (*pChecker) (pThread))); ++ } ++ return -1; ++} ++ ++_osal_inline_ INT32 osal_thread_destroy(P_OSAL_THREAD pThread) ++{ ++ if (pThread && (pThread->pThread)) { ++ kthread_stop(pThread->pThread); ++ pThread->pThread = NULL; ++ } ++ return 0; ++} ++ ++/* ++ *OSAL layer Signal Opeartion related APIs ++ *initialization ++ *wait for signal ++ *wait for signal timerout ++ *raise signal ++ *destroy a signal ++ * ++*/ ++ ++_osal_inline_ INT32 osal_signal_init(P_OSAL_SIGNAL pSignal) ++{ ++ if (pSignal) { ++ init_completion(&pSignal->comp); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_wait_for_signal(P_OSAL_SIGNAL pSignal) ++{ ++ if (pSignal) { ++ wait_for_completion_interruptible(&pSignal->comp); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++_osal_inline_ INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal) ++{ ++ /* return wait_for_completion_interruptible_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); */ ++ /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. ++ * Avoid using *interruptible" version in order to complete our jobs, such ++ * as function off gracefully. ++ */ ++ return wait_for_completion_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); ++} ++ ++_osal_inline_ INT32 osal_raise_signal(P_OSAL_SIGNAL pSignal) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ ++ complete(&pSignal->comp); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_signal_deinit(P_OSAL_SIGNAL pSignal) ++{ ++ /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ ++ pSignal->timeoutValue = 0; ++ return 0; ++} ++ ++/* ++ *OSAL layer Event Opeartion related APIs ++ *initialization ++ *wait for signal ++ *wait for signal timerout ++ *raise signal ++ *destroy a signal ++ * ++*/ ++ ++INT32 osal_event_init(P_OSAL_EVENT pEvent) ++{ ++ init_waitqueue_head(&pEvent->waitQueue); ++ ++ return 0; ++} ++ ++INT32 osal_wait_for_event(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) ++{ ++ return wait_event_interruptible(pEvent->waitQueue, condition(cond_pa)); ++} ++ ++INT32 osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) ++{ ++ return wait_event_interruptible_timeout(pEvent->waitQueue, condition(cond_pa), ++ msecs_to_jiffies(pEvent->timeoutValue)); ++} ++ ++INT32 osal_trigger_event(P_OSAL_EVENT pEvent) ++{ ++ INT32 ret = 0; ++ ++ wake_up_interruptible(&pEvent->waitQueue); ++ return ret; ++} ++ ++INT32 osal_event_deinit(P_OSAL_EVENT pEvent) ++{ ++ return 0; ++} ++ ++_osal_inline_ long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) ++{ ++ UINT32 ms = pEvent->timeoutValue; ++ ++ if (ms != 0) { ++ return wait_event_interruptible_timeout(pEvent->waitQueue, test_bit(bitOffset, pState), ++ msecs_to_jiffies(ms)); ++ } else { ++ return wait_event_interruptible(pEvent->waitQueue, test_bit(bitOffset, pState)); ++ } ++ ++} ++ ++_osal_inline_ long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) ++{ ++ UINT32 ms = pEvent->timeoutValue; ++ ++ if (ms != 0) { ++ return wait_event_interruptible_timeout(pEvent->waitQueue, !test_bit(bitOffset, pState), ++ msecs_to_jiffies(ms)); ++ } else { ++ return wait_event_interruptible(pEvent->waitQueue, !test_bit(bitOffset, pState)); ++ } ++ ++} ++ ++/* ++ *bit test and set/clear operations APIs ++ * ++ * ++*/ ++#if OS_BIT_OPS_SUPPORT ++#define osal_bit_op_lock(x) ++#define osal_bit_op_unlock(x) ++#else ++ ++_osal_inline_ INT32 osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) ++{ ++ ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) ++{ ++ ++ return 0; ++} ++#endif ++_osal_inline_ INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ osal_bit_op_lock(&(pData->opLock)); ++ clear_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ osal_bit_op_lock(&(pData->opLock)); ++ set_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return 0; ++} ++ ++_osal_inline_ INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++} ++ ++_osal_inline_ INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_and_clear_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++ ++} ++ ++_osal_inline_ INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) ++{ ++ UINT32 iRet = 0; ++ ++ osal_bit_op_lock(&(pData->opLock)); ++ iRet = test_and_set_bit(bitOffset, &pData->data); ++ osal_bit_op_unlock(&(pData->opLock)); ++ return iRet; ++} ++ ++/* ++ *tiemr operations APIs ++ *create ++ *stop ++ * modify ++ *create ++ *delete ++ * ++*/ ++ ++INT32 osal_timer_create(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ /*init_timer(timer); ++ timer->function = pTimer->timeoutHandler; ++ timer->data = (unsigned long)pTimer->timeroutHandlerData;*/ ++ timer_setup(timer,pTimer->timeoutHandler,0); ++ return 0; ++} ++ ++INT32 osal_timer_start(P_OSAL_TIMER pTimer, UINT32 ms) ++{ ++ ++ struct timer_list *timer = &pTimer->timer; ++ ++ timer->expires = jiffies + (ms / (1000 / HZ)); ++ add_timer(timer); ++ return 0; ++} ++ ++INT32 osal_timer_stop(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ del_timer(timer); ++ return 0; ++} ++ ++INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer) ++{ ++ struct timer_list *timer = &pTimer->timer; ++ ++ del_timer_sync(timer); ++ return 0; ++} ++ ++INT32 osal_timer_modify(P_OSAL_TIMER pTimer, UINT32 ms) ++{ ++ ++ mod_timer(&pTimer->timer, jiffies + (ms) / (1000 / HZ)); ++ return 0; ++} ++ ++INT32 _osal_fifo_init(OSAL_FIFO *pFifo, UINT8 *buf, UINT32 size) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = -1; ++ ++ if (!pFifo) { ++ pr_err("pFifo must be !NULL\n"); ++ return -1; ++ } ++ if (pFifo->pFifoBody) { ++ pr_err("pFifo->pFifoBody must be NULL\n"); ++ pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", pFifo, pFifo->pFifoBody); ++ return -1; ++ } ++ fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); ++ if (!buf) { ++ /*fifo's buffer is not ready, we allocate automatically */ ++ ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC); ++ } else { ++ if (is_power_of_2(size)) { ++ kfifo_init(fifo, buf, size); ++ ret = 0; ++ } else { ++ kfifo_free(fifo); ++ fifo = NULL; ++ ret = -1; ++ } ++ } ++ ++ pFifo->pFifoBody = fifo; ++ return (ret < 0) ? (-1) : (0); ++} ++ ++INT32 _osal_fifo_deinit(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ kfifo_free(fifo); ++ ++ return 0; ++} ++ ++INT32 _osal_fifo_size(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_size(fifo); ++ ++ return ret; ++} ++ ++/*returns unused bytes in fifo*/ ++INT32 _osal_fifo_avail_size(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_avail(fifo); ++ ++ return ret; ++} ++ ++/*returns used bytes in fifo*/ ++INT32 _osal_fifo_len(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_len(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_is_empty(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_is_empty(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_is_full(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ ret = kfifo_is_full(fifo); ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_data_in(OSAL_FIFO *pFifo, const VOID *buf, UINT32 len) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) { ++ ret = kfifo_in(fifo, buf, len); ++ } else { ++ pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", ++ __func__, len, _osal_fifo_avail_size(pFifo), buf); ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, UINT32 len) ++{ ++ struct kfifo *fifo = NULL; ++ INT32 ret = 0; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo && buf && (len <= _osal_fifo_len(pFifo))) { ++ ret = kfifo_out(fifo, buf, len); ++ } else { ++ pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", ++ __func__, len, _osal_fifo_len(pFifo), buf); ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++INT32 _osal_fifo_reset(OSAL_FIFO *pFifo) ++{ ++ struct kfifo *fifo = NULL; ++ ++ if (!pFifo || !pFifo->pFifoBody) { ++ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ fifo = (struct kfifo *)pFifo->pFifoBody; ++ ++ if (fifo) ++ kfifo_reset(fifo); ++ ++ return 0; ++} ++ ++INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size) ++{ ++ if (!pFifo) { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ return -1; ++ } ++ ++ pFifo->FifoInit = _osal_fifo_init; ++ pFifo->FifoDeInit = _osal_fifo_deinit; ++ pFifo->FifoSz = _osal_fifo_size; ++ pFifo->FifoAvailSz = _osal_fifo_avail_size; ++ pFifo->FifoLen = _osal_fifo_len; ++ pFifo->FifoIsEmpty = _osal_fifo_is_empty; ++ pFifo->FifoIsFull = _osal_fifo_is_full; ++ pFifo->FifoDataIn = _osal_fifo_data_in; ++ pFifo->FifoDataOut = _osal_fifo_data_out; ++ pFifo->FifoReset = _osal_fifo_reset; ++ ++ if (NULL != pFifo->pFifoBody) { ++ pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__); ++ pFifo->FifoDeInit(pFifo->pFifoBody); ++ pFifo->pFifoBody = NULL; ++ } ++ ++ pFifo->FifoInit(pFifo, buffer, size); ++ ++ return 0; ++} ++ ++VOID osal_fifo_deinit(P_OSAL_FIFO pFifo) ++{ ++ if (pFifo) ++ pFifo->FifoDeInit(pFifo); ++ else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ return; ++ } ++ kfree(pFifo->pFifoBody); ++} ++ ++INT32 osal_fifo_reset(P_OSAL_FIFO pFifo) ++{ ++ INT32 ret = -1; ++ ++ if (pFifo) { ++ ret = pFifo->FifoReset(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = -1; ++ } ++ return ret; ++} ++ ++UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoDataIn(pFifo, buffer, size); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoDataOut(pFifo, buffer, size); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_len(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoLen(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoSz(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoAvailSz(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoIsEmpty(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo) ++{ ++ UINT32 ret = 0; ++ ++ if (pFifo) { ++ ret = pFifo->FifoIsFull(pFifo); ++ } else { ++ pr_err("%s:pFifo = NULL, error\n", __func__); ++ ret = 0; ++ } ++ return ret; ++} ++ ++INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_init(&pLock->wake_lock, pLock->name); ++ #else ++ wake_lock_init(&pLock->wake_lock, WAKE_LOCK_SUSPEND, pLock->name); ++ #endif ++ return 0; ++} ++ ++INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_trash(&pLock->wake_lock); ++ #else ++ wake_lock_destroy(&pLock->wake_lock); ++ #endif ++ return 0; ++} ++ ++INT32 osal_wake_lock(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_stay_awake(&pLock->wake_lock); ++ #else ++ wake_lock(&pLock->wake_lock); ++ #endif ++ ++ return 0; ++} ++ ++INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK pLock) ++{ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_relax(&pLock->wake_lock); ++ #else ++ wake_unlock(&pLock->wake_lock); ++ #endif ++ ++ return 0; ++ ++} ++ ++INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock) ++{ ++ INT32 count = 0; ++ ++ if (!pLock) ++ return -1; ++ ++ #ifdef CONFIG_PM_WAKELOCKS ++ count = pLock->wake_lock.active; ++ #else ++ count = wake_lock_active(&pLock->wake_lock); ++ #endif ++ return count; ++} ++ ++/* ++ *sleepable lock operations APIs ++ *init ++ *lock ++ *unlock ++ *destroy ++ * ++*/ ++ ++#if !defined(CONFIG_PROVE_LOCKING) ++INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_lock_init(&(pUSL->lock)); ++ return 0; ++} ++#endif ++ ++INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_lock_irqsave(&(pUSL->lock), pUSL->flag); ++ return 0; ++} ++ ++INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); ++ return 0; ++} ++ ++INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL) ++{ ++ return 0; ++} ++ ++/* ++ *unsleepable operations APIs ++ *init ++ *lock ++ *unlock ++ *destroy ++ ++ * ++*/ ++ ++#if !defined(CONFIG_PROVE_LOCKING) ++INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_init(&pSL->lock); ++ return 0; ++} ++#endif ++ ++INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ return mutex_lock_killable(&pSL->lock); ++} ++ ++INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_unlock(&pSL->lock); ++ return 0; ++} ++ ++INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL) ++{ ++ mutex_destroy(&pSL->lock); ++ return 0; ++} ++ ++INT32 osal_sleep_ms(UINT32 ms) ++{ ++ msleep(ms); ++ return 0; ++} ++ ++INT32 osal_udelay(UINT32 us) ++{ ++ udelay(us); ++ return 0; ++} ++ ++INT32 osal_gettimeofday(PINT32 sec, PINT32 usec) ++{ ++ INT32 ret = 0; ++ struct timeval now; ++ ++ do_gettimeofday(&now); ++ ++ if (sec != NULL) ++ *sec = now.tv_sec; ++ else ++ ret = -1; ++ ++ if (usec != NULL) ++ *usec = now.tv_usec; ++ else ++ ret = -1; ++ ++ return ret; ++} ++ ++INT32 osal_printtimeofday(const PUINT8 prefix) ++{ ++ INT32 ret; ++ INT32 sec; ++ INT32 usec; ++ ++ ret = osal_gettimeofday(&sec, &usec); ++ ret += osal_dbg_print("%s>sec=%d, usec=%d\n", prefix, sec, usec); ++ ++ return ret; ++} ++ ++VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, const UINT32 len, const UINT32 limit) ++{ ++ INT32 k; ++ UINT32 dump_len; ++ ++ pr_warn("start of dump>[%s] len=%d, limit=%d,", title, len, limit); ++ ++ dump_len = ((0 != limit) && (len > limit)) ? limit : len; ++#if 0 ++ if (limit != 0) ++ len = (len > limit) ? (limit) : (len); ++ ++#endif ++ ++ for (k = 0; k < dump_len; k++) { ++ if ((k != 0) && (k % 16 == 0)) ++ pr_cont("\n"); ++ pr_cont("0x%02x ", buf[k]); ++ } ++ pr_warn("op.opId : 0xFFFFFFFF; ++} ++ ++MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) ++{ ++ return (pOp && pOp->signal.timeoutValue) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; ++} ++ ++VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result) ++{ ++ if (pOp) { ++ pOp->result = result; ++ osal_raise_signal(&pOp->signal); ++ } ++} ++ ++VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result) ++{ ++ if (pOp) ++ pOp->result = result; ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +new file mode 100644 +index 000000000000..190fa3944d80 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +@@ -0,0 +1,899 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if WMT_CREATE_NODE_DYNAMIC ++#include ++#endif ++#include ++ ++#include "osal_typedef.h" ++#include "stp_exp.h" ++#include "wmt_exp.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++#ifdef MTK_BT_HCI ++#define MTK_BT_DEBUG 0 ++#include ++#include ++#endif ++ ++ ++#define BT_DRIVER_NAME "mtk_stp_BT_chrdev" ++#define BT_DEV_MAJOR 192 /* Never used number */ ++ ++#define PFX "[MTK-BT] " ++#define BT_LOG_DBG 3 ++#define BT_LOG_INFO 2 ++#define BT_LOG_WARN 1 ++#define BT_LOG_ERR 0 ++ ++#define COMBO_IOC_MAGIC 0xb0 ++#define COMBO_IOCTL_FW_ASSERT _IOWR(COMBO_IOC_MAGIC, 0, int) ++#define COMBO_IOCTL_BT_IC_HW_VER _IOWR(COMBO_IOC_MAGIC, 1, void*) ++#define COMBO_IOCTL_BT_IC_FW_VER _IOWR(COMBO_IOC_MAGIC, 2, void*) ++#define COMBO_IOC_BT_HWVER _IOWR(COMBO_IOC_MAGIC, 3, void*) ++ ++static UINT32 gDbgLevel = BT_LOG_INFO; ++ ++#define BT_DBG_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_DBG) \ ++ pr_debug(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_INFO_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_INFO) \ ++ pr_warn(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_WARN_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_WARN) \ ++ pr_err(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++#define BT_ERR_FUNC(fmt, arg...) \ ++ do { if (gDbgLevel >= BT_LOG_ERR) \ ++ pr_err(PFX "%s: " fmt, __func__ , ##arg); \ ++ } while (0) ++ ++#define VERSION "1.0" ++ ++#ifdef MTK_BT_HCI ++ ++#define NUM_REASSEMBLY 32 ++struct mtk_hci { ++ struct hci_dev *hdev; ++ struct work_struct work; ++ struct sk_buff_head txq; ++ struct sk_buff *reassembly[NUM_REASSEMBLY]; ++}; ++ ++static struct mtk_hci mtk_hci; ++ ++#endif ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *stpbt_class = NULL; ++struct device *stpbt_dev = NULL; ++#endif ++ ++static INT32 BT_devs = 1; /* Device count */ ++static INT32 BT_major = BT_DEV_MAJOR; /* Dynamic allocation */ ++module_param(BT_major, uint, 0); ++static struct cdev BT_cdev; ++ ++#define BT_BUFFER_SIZE 2048 ++static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer of read() */ ++static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer of write() */ ++ ++static struct semaphore wr_mtx, rd_mtx; ++/* Wait queue for poll and read */ ++static wait_queue_head_t inq; ++static DECLARE_WAIT_QUEUE_HEAD(BT_wq); ++static INT32 flag; ++/* Reset flag for whole chip reset senario */ ++static volatile INT32 rstflag; ++ ++#ifdef MTK_BT_HCI ++static int hci_reassembly(struct hci_dev *hdev, int type, void *data, ++ int count, __u8 index) ++{ ++ int len = 0; ++ int hlen = 0; ++ int offset = 0; ++ int remain = count; ++ struct sk_buff *skb; ++ struct bt_skb_cb *scb; ++ u16 opcode = 0; ++ unsigned char *pdata = data; ++ ++ struct mtk_hci *info = NULL; ++ struct hci_event_hdr *ehdr = NULL; ++ struct hci_ev_cmd_complete *ev = NULL; ++ struct hci_rp_read_local_ext_features *ext = NULL; ++ ++ info = hci_get_drvdata(hdev); ++ if ( NULL == info ) { ++ printk(KERN_ERR "mtk_bt_hci: invalid info point\n"); ++ return 0; ++ } ++ ++ if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || ++ index >= NUM_REASSEMBLY) ++ return -EILSEQ; ++ ++ skb = info->reassembly[index]; ++ ++ if (!skb) { ++ switch (type) { ++ case HCI_ACLDATA_PKT: ++ len = HCI_MAX_FRAME_SIZE; ++ hlen = HCI_ACL_HDR_SIZE; ++ break; ++ case HCI_EVENT_PKT: ++ len = HCI_MAX_EVENT_SIZE; ++ hlen = HCI_EVENT_HDR_SIZE; ++ break; ++ case HCI_SCODATA_PKT: ++ len = HCI_MAX_SCO_SIZE; ++ hlen = HCI_SCO_HDR_SIZE; ++ break; ++ } ++ ++ skb = bt_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) ++ return -ENOMEM; ++ ++ scb = (void *) skb->cb; ++ scb->expect = hlen; ++ scb->pkt_type = type; ++ ++ info->reassembly[index] = skb; ++ } ++ ++ while (count) { ++ scb = (void *) skb->cb; ++ len = min_t(uint, scb->expect, count); ++ ++ /* ++ * Workaround for MT7623+MT6625 BT: the max page in response of cmd READ_LOCAL_EXT_FEATURES ++ * should be 1, instead of 2, so changing it to 1 here ++ */ ++ ++ if (HCI_EVENT_PKT == type) ++ { ++ ehdr = (void *)pdata; ++ offset = sizeof(struct hci_event_hdr); ++ if ( HCI_EV_CMD_COMPLETE == ehdr->evt) ++ { ++ ev = (struct hci_ev_cmd_complete *)&pdata[offset]; ++ ++ offset += sizeof(struct hci_ev_cmd_complete); ++ ++ opcode = __le16_to_cpu(ev->opcode); ++ if(HCI_OP_READ_LOCAL_EXT_FEATURES == opcode) { ++ ext = (struct hci_rp_read_local_ext_features *) &pdata[offset]; ++ if( !ext->status && ext->max_page >= 2) { ++ pr_info("%s: this workaround is applied for mediatek BT\n", __func__); ++ ext->max_page = 1; ++ } ++ } ++ ++ } ++ } ++ ++ memcpy(skb_put(skb, len), data, len); ++ ++ count -= len; ++ data += len; ++ scb->expect -= len; ++ remain = count; ++ ++ switch (type) { ++ case HCI_EVENT_PKT: ++ if (skb->len == HCI_EVENT_HDR_SIZE) { ++ struct hci_event_hdr *h = hci_event_hdr(skb); ++ ++ scb->expect = h->plen; ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ if (skb->len == HCI_ACL_HDR_SIZE) { ++ struct hci_acl_hdr *h = hci_acl_hdr(skb); ++ ++ scb->expect = __le16_to_cpu(h->dlen); ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ break; ++ ++ case HCI_SCODATA_PKT: ++ if (skb->len == HCI_SCO_HDR_SIZE) { ++ struct hci_sco_hdr *h = hci_sco_hdr(skb); ++ ++ scb->expect = h->dlen; ++ ++ if (skb_tailroom(skb) < scb->expect) { ++ kfree_skb(skb); ++ info->reassembly[index] = NULL; ++ return -ENOMEM; ++ } ++ } ++ break; ++ } ++ ++ if (scb->expect == 0) { ++ /* Complete frame */ ++ ++ bt_cb(skb)->pkt_type = type; ++ hci_recv_frame(hdev, skb); ++ ++ info->reassembly[index] = NULL; ++ return remain; ++ } ++ } ++ ++ return remain; ++} ++ ++int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) ++{ ++ int rem = 0; ++ ++ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ++ return -EILSEQ; ++ ++ while (count) { ++ rem = hci_reassembly(hdev, type, data, count, type - 1); ++ if (rem < 0) ++ return rem; ++ ++ data += (count - rem); ++ count = rem; ++ } ++ ++ return rem; ++} ++#endif ++ ++#ifdef MTK_BT_HCI ++void ++hex_dump(char *prefix, char *p, int len) ++{ ++ int i; ++ ++ pr_err("%s ", prefix); ++ for (i = 0; i < len; i++) ++ pr_err("%02x ", (*p++ & 0xff)); ++ pr_err("\n"); ++} ++ ++static int ++mtk_bt_hci_open(struct hci_dev *hdev) ++{ ++ int err = 0; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ err = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); ++ if (err != MTK_WCN_BOOL_TRUE) { ++ pr_err("%s func on failed with %d\n", __func__, err); ++ return -ENODEV; ++ } ++ ++ set_bit(HCI_RUNNING, &hdev->flags); ++ ++ mtk_wcn_stp_set_bluez(1); ++ ++ return 0; ++} ++ ++static int ++mtk_bt_hci_close(struct hci_dev *hdev) ++{ ++ int err = 0; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ mtk_wcn_stp_set_bluez(0); ++ ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ ++ err = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ if (err != MTK_WCN_BOOL_TRUE) { ++ pr_err("%s func off failed with %d\n", __func__, err); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void ++mtk_bt_hci_work(struct work_struct *work) ++{ ++ int err; ++ struct sk_buff *skb; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ while ((skb = skb_dequeue(&mtk_hci.txq))) { ++ skb_push(skb, 1); ++ skb->data[0] = bt_cb(skb)->pkt_type; ++ ++#if MTK_BT_DEBUG == 1 ++ hex_dump(">>", skb->data, skb->len); ++#endif ++ ++ err = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX); ++ if (err < 0) { ++ pr_err("%s err=%d\n", __func__, err); ++ mtk_hci.hdev->stat.err_tx++; ++ skb_queue_head(&mtk_hci.txq, skb); ++ break; ++ } ++ ++ mtk_hci.hdev->stat.byte_tx += skb->len; ++ kfree_skb(skb); ++ } ++} ++ ++static int ++mtk_bt_hci_send(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++#endif ++ ++ if (mtk_hci.hdev && !test_bit(HCI_RUNNING, &mtk_hci.hdev->flags)) ++ return -EBUSY; ++ ++ switch (bt_cb(skb)->pkt_type) { ++ case HCI_COMMAND_PKT: ++ mtk_hci.hdev->stat.cmd_tx++; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ mtk_hci.hdev->stat.acl_tx++; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ mtk_hci.hdev->stat.sco_tx++; ++ break; ++ ++ default: ++ return -EILSEQ; ++ } ++ ++ skb_queue_tail(&mtk_hci.txq, skb); ++ schedule_work(&mtk_hci.work); ++ ++ return 0; ++} ++ ++static int ++mtk_bt_hci_flush(struct hci_dev *hdev) ++{ ++ pr_err("%s: todo\n", __func__); ++ ++ return 0; ++} ++ ++static void ++mtk_bt_hci_receive(const PUINT8 data, INT32 size) ++{ ++ int err; ++ ++#if MTK_BT_DEBUG == 1 ++ pr_err("# %s\n", __func__); ++ hex_dump("<<", data, size); ++#endif ++ ++ err = hci_recv_fragment(mtk_hci.hdev, data[0], (void *)&data[1], size - 1); ++ if (err < 0) ++ pr_err("%s: hci_recv_fragment failed with %d\n", __func__, err); ++ ++ if (mtk_hci.hdev) ++ mtk_hci.hdev->stat.byte_rx += size - 1; ++} ++ ++static void ++mtk_bt_hci_notify(struct hci_dev *hdev, unsigned int evt) ++{ ++ static const char * const notify_str[] = { ++ "null", ++ "HCI_NOTIFY_CONN_ADD", ++ "HCI_NOTIFY_CONN_DEL", ++ "HCI_NOTIFY_VOICE_SETTING" ++ }; ++ ++ if (evt > HCI_NOTIFY_VOICE_SETTING) ++ pr_info("%s event=0x%x\n", __func__, evt); ++ else ++ pr_info("%s event(%d)=%s\n", __func__, evt, notify_str[evt]); ++} ++#endif ++ ++#ifdef MTK_BT_HCI ++ ++int mtk_bt_hci_init(void) ++{ ++ INT32 hci_err = 0; ++ ++ mtk_hci.hdev = hci_alloc_dev(); ++ if (!(mtk_hci.hdev)) { ++ mtk_hci.hdev = NULL; ++ BT_ERR_FUNC("%s hci_alloc_dev failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ mtk_hci.hdev->bus = HCI_SDIO; ++ mtk_hci.hdev->open = mtk_bt_hci_open; ++ mtk_hci.hdev->close = mtk_bt_hci_close; ++ mtk_hci.hdev->send = mtk_bt_hci_send; ++ mtk_hci.hdev->flush = mtk_bt_hci_flush; ++ mtk_hci.hdev->notify = mtk_bt_hci_notify; ++ SET_HCIDEV_DEV(mtk_hci.hdev, stpbt_dev); ++ ++ hci_set_drvdata(mtk_hci.hdev, &mtk_hci); ++ ++ mtk_wcn_stp_register_if_rx(mtk_bt_hci_receive); ++ ++ hci_err = hci_register_dev(mtk_hci.hdev); ++ if (hci_err) { ++ BT_ERR_FUNC("%s hci_register_dev failed with %d\n", __func__, hci_err); ++ hci_free_dev(mtk_hci.hdev); ++ mtk_hci.hdev = NULL; ++ return hci_err; ++ } ++ ++ skb_queue_head_init(&mtk_hci.txq); ++ INIT_WORK(&mtk_hci.work, mtk_bt_hci_work); ++ ++ return 0; ++} ++#endif ++ ++ ++static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, ++ ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz) ++{ ++ /* ++ Handle whole chip reset messages ++ */ ++ ENUM_WMTRSTMSG_TYPE_T rst_msg; ++ ++ if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { ++ memcpy((PINT8)&rst_msg, (PINT8)buf, sz); ++ BT_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, ++ dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); ++ if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) ++ && (type == WMTMSG_TYPE_RESET)) { ++ if (rst_msg == WMTRSTMSG_RESET_START) { ++ BT_INFO_FUNC("BT reset start!\n"); ++ rstflag = 1; ++ wake_up_interruptible(&inq); ++ ++ } else if (rst_msg == WMTRSTMSG_RESET_END) { ++ BT_INFO_FUNC("BT reset end!\n"); ++ rstflag = 2; ++ wake_up_interruptible(&inq); ++ } ++ } ++ } else { ++ /* Invalid message format */ ++ BT_WARN_FUNC("Invalid message format!\n"); ++ } ++} ++ ++VOID BT_event_cb(VOID) ++{ ++ BT_DBG_FUNC("BT_event_cb()\n"); ++ ++ flag = 1; ++ ++ /* ++ * Finally, wake up any reader blocked in poll or read ++ */ ++ wake_up_interruptible(&inq); ++ wake_up(&BT_wq); ++} ++ ++unsigned int BT_poll(struct file *filp, poll_table *wait) ++{ ++ UINT32 mask = 0; ++ ++/* down(&wr_mtx); */ ++ /* ++ * The buffer is circular; it is considered full ++ * if "wp" is right behind "rp". "left" is 0 if the ++ * buffer is empty, and it is "1" if it is completely full. ++ */ ++ if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) { ++ poll_wait(filp, &inq, wait); ++ ++ if (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) || rstflag) ++ /* BT Rx queue has valid data, or whole chip reset occurs */ ++ mask |= POLLIN | POLLRDNORM; /* Readable */ ++ } else { ++ mask |= POLLIN | POLLRDNORM; /* Readable */ ++ } ++ ++ /* Do we need condition here? */ ++ mask |= POLLOUT | POLLWRNORM; /* Writable */ ++/* up(&wr_mtx); */ ++ return mask; ++} ++ ++ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = 0; ++ INT32 write_size; ++ INT32 written = 0; ++ ++ down(&wr_mtx); ++ ++ BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); ++ if (rstflag) { ++ if (rstflag == 1) { /* Reset start */ ++ retval = -88; ++ BT_INFO_FUNC("%s: detect whole chip reset start\n", __func__); ++ } else if (rstflag == 2) { /* Reset end */ ++ retval = -99; ++ BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); ++ } ++ goto OUT; ++ } ++ ++ if (count > 0) { ++ if (count < BT_BUFFER_SIZE) { ++ write_size = count; ++ } else { ++ write_size = BT_BUFFER_SIZE; ++ BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); ++ } ++ ++ if (copy_from_user(&o_buf[0], &buf[0], write_size)) { ++ retval = -EFAULT; ++ goto OUT; ++ } ++ ++ written = mtk_wcn_stp_send_data(&o_buf[0], write_size, BT_TASK_INDX); ++ if (0 == written) { ++ retval = -ENOSPC; ++ /* No space is available, native program should not call BT_write with no delay */ ++ BT_ERR_FUNC ++ ("Packet length %zd, sent length %d, retval = %d\n", ++ count, written, retval); ++ } else { ++ retval = written; ++ } ++ ++ } else { ++ retval = -EFAULT; ++ BT_ERR_FUNC("Packet length %zd is not allowed, retval = %d\n", count, retval); ++ } ++ ++OUT: ++ up(&wr_mtx); ++ return retval; ++} ++ ++ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ static int chip_reset_count; ++ INT32 retval = 0; ++ ++ down(&rd_mtx); ++ ++ BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); ++ if (rstflag) { ++ if (rstflag == 1) { /* Reset start */ ++ retval = -88; ++ if ((chip_reset_count%500) == 0) ++ BT_INFO_FUNC("%s: detect whole chip reset start, %d\n", __func__, chip_reset_count); ++ chip_reset_count++; ++ } else if (rstflag == 2) { /* Reset end */ ++ retval = -99; ++ BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); ++ chip_reset_count = 0; ++ } ++ goto OUT; ++ } ++ ++ if (count > BT_BUFFER_SIZE) { ++ count = BT_BUFFER_SIZE; ++ BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); ++ } ++ ++ retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); ++ ++ while (retval == 0) { /* Got nothing, wait for STP's signal */ ++ /* ++ * If nonblocking mode, return directly. ++ * O_NONBLOCK is specified during open() ++ */ ++ if (filp->f_flags & O_NONBLOCK) { ++ BT_DBG_FUNC("Non-blocking BT_read\n"); ++ retval = -EAGAIN; ++ goto OUT; ++ } ++ ++ BT_DBG_FUNC("%s: wait_event 1\n", __func__); ++ wait_event(BT_wq, flag != 0); ++ BT_DBG_FUNC("%s: wait_event 2\n", __func__); ++ flag = 0; ++ retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); ++ BT_DBG_FUNC("%s: mtk_wcn_stp_receive_data returns %d\n", __func__, retval); ++ } ++ ++ /* Got something from STP driver */ ++ if (copy_to_user(buf, i_buf, retval)) { ++ retval = -EFAULT; ++ goto OUT; ++ } ++ ++OUT: ++ up(&rd_mtx); ++ BT_DBG_FUNC("%s: retval = %d\n", __func__, retval); ++ return retval; ++} ++ ++/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ ++long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ INT32 retval = 0; ++ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; ++ ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; ++ ++ BT_DBG_FUNC("%s: cmd: 0x%x\n", __func__, cmd); ++ ++ switch (cmd) { ++ case COMBO_IOC_BT_HWVER: ++ /* Get combo HW version */ ++ hw_ver_sym = mtk_wcn_wmt_hwver_get(); ++ BT_INFO_FUNC("%s: HW version = %d, sizeof(hw_ver_sym) = %zd\n", ++ __func__, hw_ver_sym, sizeof(hw_ver_sym)); ++ if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) ++ retval = -EFAULT; ++ break; ++ ++ case COMBO_IOCTL_FW_ASSERT: ++ /* Trigger FW assert for debug */ ++ BT_INFO_FUNC("%s: Host trigger FW assert......, reason:%lu\n", __func__, arg); ++ bRet = mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, arg); ++ if (bRet == MTK_WCN_BOOL_TRUE) { ++ BT_INFO_FUNC("Host trigger FW assert succeed\n"); ++ retval = 0; ++ } else { ++ BT_ERR_FUNC("Host trigger FW assert Failed\n"); ++ retval = (-EBUSY); ++ } ++ break; ++ case COMBO_IOCTL_BT_IC_HW_VER: ++ retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); ++ break; ++ case COMBO_IOCTL_BT_IC_FW_VER: ++ retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); ++ break; ++ default: ++ retval = -EFAULT; ++ BT_ERR_FUNC("Unknown cmd (%d)\n", cmd); ++ break; ++ } ++ ++ return retval; ++} ++ ++long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ return BT_unlocked_ioctl(filp, cmd, arg); ++} ++ ++static int BT_open(struct inode *inode, struct file *file) ++{ ++ BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); ++ ++ /* Turn on BT */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { ++ BT_WARN_FUNC("WMT turn on BT fail!\n"); ++ return -ENODEV; ++ } ++ ++ BT_INFO_FUNC("WMT turn on BT OK!\n"); ++ rstflag = 0; ++ ++ if (mtk_wcn_stp_is_ready()) { ++ ++ mtk_wcn_stp_set_bluez(0); ++ ++ BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); ++ BT_INFO_FUNC("STP is ready!\n"); ++ ++ BT_DBG_FUNC("Register BT event callback!\n"); ++ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); ++ } else { ++ BT_ERR_FUNC("STP is not ready\n"); ++ mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); ++ return -ENODEV; ++ } ++ ++ BT_DBG_FUNC("Register BT reset callback!\n"); ++ mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); ++ ++ /* init_MUTEX(&wr_mtx); */ ++ sema_init(&wr_mtx, 1); ++ /* init_MUTEX(&rd_mtx); */ ++ sema_init(&rd_mtx, 1); ++ BT_INFO_FUNC("%s: finish\n", __func__); ++ ++ return 0; ++} ++ ++static int BT_close(struct inode *inode, struct file *file) ++{ ++ BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); ++ rstflag = 0; ++ mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); ++ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { ++ BT_ERR_FUNC("WMT turn off BT fail!\n"); ++ return -EIO; /* Mostly, native program will not check this return value. */ ++ } ++ ++ BT_INFO_FUNC("WMT turn off BT OK!\n"); ++ ++ return 0; ++} ++ ++const struct file_operations BT_fops = { ++ .open = BT_open, ++ .release = BT_close, ++ .read = BT_read, ++ .write = BT_write, ++ /* .ioctl = BT_ioctl, */ ++ .unlocked_ioctl = BT_unlocked_ioctl, ++ .compat_ioctl = BT_compat_ioctl, ++ .poll = BT_poll ++}; ++ ++ ++ ++static int BT_init(void) ++{ ++ dev_t dev = MKDEV(BT_major, 0); ++ INT32 alloc_ret = 0; ++ INT32 cdev_err = 0; ++ ++ /* Static allocate char device */ ++ alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME); ++ if (alloc_ret) { ++ BT_ERR_FUNC("%s: Failed to register char device\n", __func__); ++ return alloc_ret; ++ } ++ ++ cdev_init(&BT_cdev, &BT_fops); ++ BT_cdev.owner = THIS_MODULE; ++ ++ cdev_err = cdev_add(&BT_cdev, dev, BT_devs); ++ if (cdev_err) ++ goto error; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ stpbt_class = class_create(THIS_MODULE, "stpbt"); ++ if (IS_ERR(stpbt_class)) ++ goto error; ++ stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt"); ++ if (IS_ERR(stpbt_dev)) ++ goto error; ++#endif ++ ++ BT_INFO_FUNC("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major); ++ ++ /* Init wait queue */ ++ init_waitqueue_head(&(inq)); ++ ++#ifdef MTK_BT_HCI ++ mtk_bt_hci_init(); ++#endif ++ ++ return 0; ++ ++error: ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!IS_ERR(stpbt_dev)) ++ device_destroy(stpbt_class, dev); ++ if (!IS_ERR(stpbt_class)) { ++ class_destroy(stpbt_class); ++ stpbt_class = NULL; ++ } ++#endif ++ if (cdev_err == 0) ++ cdev_del(&BT_cdev); ++ ++ if (alloc_ret == 0) ++ unregister_chrdev_region(dev, BT_devs); ++ ++ return -1; ++} ++ ++static void BT_exit(void) ++{ ++ dev_t dev = MKDEV(BT_major, 0); ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ if (stpbt_dev) { ++ device_destroy(stpbt_class, dev); ++ stpbt_dev = NULL; ++ } ++ if (stpbt_class) { ++ class_destroy(stpbt_class); ++ stpbt_class = NULL; ++ } ++#endif ++ ++ cdev_del(&BT_cdev); ++ unregister_chrdev_region(dev, BT_devs); ++ ++ BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++int mtk_wcn_stpbt_drv_init(void) ++{ ++ return BT_init(); ++} ++EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init); ++ ++void mtk_wcn_stpbt_drv_exit(void) ++{ ++ return BT_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit); ++ ++#else ++ ++module_init(BT_init); ++module_exit(BT_exit); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +new file mode 100644 +index 000000000000..3c7b2969c98a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -0,0 +1,668 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wmt_exp.h" ++#include "stp_exp.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++#define WIFI_DRIVER_NAME "mtk_wmt_WIFI_chrdev" ++#define WIFI_DEV_MAJOR 155 ++ ++#define PFX "[MTK-WIFI] " ++#define WIFI_LOG_DBG 3 ++#define WIFI_LOG_INFO 2 ++#define WIFI_LOG_WARN 1 ++#define WIFI_LOG_ERR 0 ++ ++UINT32 gDbgLevel = WIFI_LOG_DBG; ++ ++#define WIFI_DBG_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_INFO_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_INFO) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_WARN_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_WARN) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_ERR_FUNC(fmt, arg...)\ ++ do {if (gDbgLevel >= WIFI_LOG_ERR) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) ++#define WIFI_TRC_FUNC(f)\ ++ do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "<%s> <%d>\n", __func__, __LINE__); } while (0) ++ ++#define VERSION "1.0" ++ ++#define WLAN_IFACE_NAME "wlan0" ++#if CFG_TC1_FEATURE ++#define LEGACY_IFACE_NAME "legacy0" ++#endif ++ ++enum { ++ WLAN_MODE_HALT, ++ WLAN_MODE_AP, ++ WLAN_MODE_STA_P2P, ++ WLAN_MODE_MAX ++}; ++static INT32 wlan_mode = WLAN_MODE_HALT; ++static INT32 powered; ++static INT8 *ifname = WLAN_IFACE_NAME; ++#if CFG_TC1_FEATURE ++volatile INT32 wlan_if_changed = 0; ++EXPORT_SYMBOL(wlan_if_changed); ++#endif ++ ++typedef enum _ENUM_RESET_STATUS_T { ++ RESET_FAIL, ++ RESET_SUCCESS ++} ENUM_RESET_STATUS_T; ++ ++/* ++ * enable = 1, mode = 0 => init P2P network ++ * enable = 1, mode = 1 => init Soft AP network ++ * enable = 0 => uninit P2P/AP network ++ */ ++typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { ++ UINT32 u4Enable; ++ UINT32 u4Mode; ++} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; ++typedef INT32(*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++ ++static set_p2p_mode pf_set_p2p_mode; ++VOID register_set_p2p_mode_handler(set_p2p_mode handler) ++{ ++ WIFI_INFO_FUNC("(pid %d) register set p2p mode handler %p\n", current->pid, handler); ++ pf_set_p2p_mode = handler; ++} ++EXPORT_SYMBOL(register_set_p2p_mode_handler); ++ ++/* For dynamical debug level setting */ ++/* copy of debug.h in wlan driver */ ++#define DBG_CLASS_ERROR BIT(0) ++#define DBG_CLASS_WARN BIT(1) ++#define DBG_CLASS_STATE BIT(2) ++#define DBG_CLASS_EVENT BIT(3) ++#define DBG_CLASS_TRACE BIT(4) ++#define DBG_CLASS_INFO BIT(5) ++#define DBG_CLASS_LOUD BIT(6) ++#define DBG_CLASS_TEMP BIT(7) ++#define DBG_CLASS_MASK BITS(0, 7) ++ ++typedef enum _ENUM_DBG_MODULE_T { ++ DBG_INIT_IDX = 0, /* For driver initial */ ++ DBG_HAL_IDX, /* For HAL(HW) Layer */ ++ DBG_INTR_IDX, /* For Interrupt */ ++ DBG_REQ_IDX, ++ DBG_TX_IDX, ++ DBG_RX_IDX, ++ DBG_RFTEST_IDX, /* For RF test mode */ ++ DBG_EMU_IDX, /* Developer specific */ ++ ++ DBG_SW1_IDX, /* Developer specific */ ++ DBG_SW2_IDX, /* Developer specific */ ++ DBG_SW3_IDX, /* Developer specific */ ++ DBG_SW4_IDX, /* Developer specific */ ++ ++ DBG_HEM_IDX, /* HEM */ ++ DBG_AIS_IDX, /* AIS */ ++ DBG_RLM_IDX, /* RLM */ ++ DBG_MEM_IDX, /* RLM */ ++ DBG_CNM_IDX, /* CNM */ ++ DBG_RSN_IDX, /* RSN */ ++ DBG_BSS_IDX, /* BSS */ ++ DBG_SCN_IDX, /* SCN */ ++ DBG_SAA_IDX, /* SAA */ ++ DBG_AAA_IDX, /* AAA */ ++ DBG_P2P_IDX, /* P2P */ ++ DBG_QM_IDX, /* QUE_MGT */ ++ DBG_SEC_IDX, /* SEC */ ++ DBG_BOW_IDX, /* BOW */ ++ DBG_WAPI_IDX, /* WAPI */ ++ DBG_ROAMING_IDX, /* ROAMING */ ++ ++ DBG_MODULE_NUM /* Notice the XLOG check */ ++} ENUM_DBG_MODULE_T; ++/* end */ ++typedef VOID(*set_dbg_level) (UINT8 modules[DBG_MODULE_NUM]); ++ ++UINT8 wlan_dbg_level[DBG_MODULE_NUM]; ++static set_dbg_level pf_set_dbg_level; ++VOID register_set_dbg_level_handler(set_dbg_level handler) ++{ ++ pf_set_dbg_level = handler; ++} ++EXPORT_SYMBOL(register_set_dbg_level_handler); ++ ++static INT32 WIFI_devs = 1; ++static INT32 WIFI_major = WIFI_DEV_MAJOR; ++module_param(WIFI_major, uint, 0); ++static struct cdev WIFI_cdev; ++volatile INT32 retflag = 0; ++static struct semaphore wr_mtx; ++ ++#define WMT_CHECK_DO_CHIP_RESET() \ ++do { \ ++ if (g_IsNeedDoChipReset) { \ ++ g_IsNeedDoChipReset = 0; \ ++ WIFI_ERR_FUNC("Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); \ ++ } \ ++} while (0) ++ ++/******************************************************************* ++ * WHOLE CHIP RESET PROCEDURE: ++ * ++ * WMTRSTMSG_RESET_START callback ++ * -> wlanRemove ++ * -> WMTRSTMSG_RESET_END callback ++ * ++ ******************************************************************* ++*/ ++/*-----------------------------------------------------------------*/ ++/* ++ * Receiving RESET_START message ++ */ ++/*-----------------------------------------------------------------*/ ++INT32 wifi_reset_start(VOID) ++{ ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ ++ down(&wr_mtx); ++ ++ if (powered == 1) { ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev == NULL) { ++ WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); ++ } else { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ ++ if (pf_set_p2p_mode) { ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ else ++ WIFI_INFO_FUNC("Turn off p2p/ap mode"); ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ } else { ++ /* WIFI is off before whole chip reset, do nothing */ ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(wifi_reset_start); ++ ++/*-----------------------------------------------------------------*/ ++/* ++ * Receiving RESET_END/RESET_END_FAIL message ++ */ ++/*-----------------------------------------------------------------*/ ++INT32 wifi_reset_end(ENUM_RESET_STATUS_T status) ++{ ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ INT32 wait_cnt = 0; ++ INT32 ret = -1; ++ ++ if (status == RESET_FAIL) { ++ /* whole chip reset fail, donot recover WIFI */ ++ ret = 0; ++ up(&wr_mtx); ++ } else if (status == RESET_SUCCESS) { ++ WIFI_WARN_FUNC("WIFI state recovering...\n"); ++ ++ if (powered == 1) { ++ /* WIFI is on before whole chip reset, reopen it now */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ } ++ ++ if (pf_set_p2p_mode == NULL) { ++ WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ while (netdev == NULL && wait_cnt < 10) { ++ WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); ++ msleep(300); ++ wait_cnt++; ++ netdev = dev_get_by_name(&init_net, ifname); ++ } ++ if (wait_cnt >= 10) { ++ WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); ++ goto done; ++ } ++ ++ if (wlan_mode == WLAN_MODE_STA_P2P) { ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_P2P); ++ ret = 0; ++ } ++ } else if (wlan_mode == WLAN_MODE_AP) { ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 1; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_AP); ++ ret = 0; ++ } ++ } ++done: ++ if (netdev != NULL) ++ dev_put(netdev); ++ } else { ++ /* WIFI is off before whole chip reset, do nothing */ ++ ret = 0; ++ } ++ up(&wr_mtx); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(wifi_reset_end); ++ ++static int WIFI_open(struct inode *inode, struct file *file) ++{ ++ WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); ++ ++ return 0; ++} ++ ++static int WIFI_close(struct inode *inode, struct file *file) ++{ ++ WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); ++ retflag = 0; ++ ++ return 0; ++} ++ ++ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) ++{ ++ INT32 retval = -EIO; ++ INT8 local[12] = { 0 }; ++ struct net_device *netdev = NULL; ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ INT32 wait_cnt = 0; ++ ++ down(&wr_mtx); ++ if (count <= 0) { ++ WIFI_ERR_FUNC("WIFI_write invalid param\n"); ++ goto done; ++ } ++ ++ if (0 == copy_from_user(local, buf, (count > sizeof(local)) ? sizeof(local) : count)) { ++ local[11] = 0; ++ WIFI_INFO_FUNC("WIFI_write %s\n", local); ++ ++ if (local[0] == '0') { ++ if (powered == 0) { ++ WIFI_INFO_FUNC("WIFI is already power off!\n"); ++ retval = count; ++ wlan_mode = WLAN_MODE_HALT; ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev == NULL) { ++ WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); ++ } else { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ ++ if (pf_set_p2p_mode) { ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ } else { ++ WIFI_INFO_FUNC("Turn off p2p/ap mode"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn off WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ } else { ++ WIFI_INFO_FUNC("WMT turn off WIFI OK!\n"); ++ powered = 0; ++ retval = count; ++ wlan_mode = WLAN_MODE_HALT; ++#if CFG_TC1_FEATURE ++ ifname = WLAN_IFACE_NAME; ++ wlan_if_changed = 0; ++#endif ++ } ++ } else if (local[0] == '1') { ++ if (powered == 1) { ++ WIFI_INFO_FUNC("WIFI is already power on!\n"); ++ retval = count; ++ goto done; ++ } ++ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ } else { ++ powered = 1; ++ retval = count; ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } else if (local[0] == 'D') { ++ INT32 k = 0; ++ /* ++ * 0: no debug ++ * 1: common debug output ++ * 2: more detials ++ * 3: verbose ++ */ ++ switch (local[1]) { ++ case '0': ++ for (k = 0; k < DBG_MODULE_NUM; k++) ++ wlan_dbg_level[k] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '1': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; ++ } ++ wlan_dbg_level[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); ++ wlan_dbg_level[DBG_INTR_IDX] = 0; ++ wlan_dbg_level[DBG_MEM_IDX] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '2': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; ++ } ++ wlan_dbg_level[DBG_INTR_IDX] = 0; ++ wlan_dbg_level[DBG_MEM_IDX] = 0; ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ case '3': ++ for (k = 0; k < DBG_MODULE_NUM; k++) { ++ wlan_dbg_level[k] = DBG_CLASS_ERROR | ++ DBG_CLASS_WARN | ++ DBG_CLASS_STATE | ++ DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO | DBG_CLASS_LOUD; ++ } ++ if (pf_set_dbg_level) ++ pf_set_dbg_level(wlan_dbg_level); ++ break; ++ default: ++ break; ++ } ++ } else if (local[0] == 'S' || local[0] == 'P' || local[0] == 'A') { ++ if (powered == 0) { ++ /* If WIFI is off, turn on WIFI first */ ++ if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { ++ WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); ++ WMT_CHECK_DO_CHIP_RESET(); ++ goto done; ++ } else { ++ powered = 1; ++ WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); ++ wlan_mode = WLAN_MODE_HALT; ++ } ++ } ++ ++ if (pf_set_p2p_mode == NULL) { ++ WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); ++ goto done; ++ } ++ ++ netdev = dev_get_by_name(&init_net, ifname); ++ while (netdev == NULL && wait_cnt < 10) { ++ WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); ++ msleep(300); ++ wait_cnt++; ++ netdev = dev_get_by_name(&init_net, ifname); ++ } ++ if (wait_cnt >= 10) { ++ WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); ++ goto done; ++ } ++ ++ if ((wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'S' || local[0] == 'P')) || ++ (wlan_mode == WLAN_MODE_AP && (local[0] == 'A'))) { ++ WIFI_INFO_FUNC("WIFI is already in mode %d!\n", wlan_mode); ++ retval = count; ++ goto done; ++ } ++ ++ if ((wlan_mode == WLAN_MODE_AP && (local[0] == 'S' || local[0] == 'P')) || ++ (wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'A'))) { ++ p2pmode.u4Enable = 0; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); ++ goto done; ++ } ++ } ++ ++ if (local[0] == 'S' || local[0] == 'P') { ++#if CFG_TC1_FEATURE ++ /* Restore NIC name to wlan0 */ ++ rtnl_lock(); ++ if (strcmp(ifname, WLAN_IFACE_NAME) != 0) { ++ if (dev_change_name(netdev, WLAN_IFACE_NAME) != 0) { ++ WIFI_ERR_FUNC("netdev name change to %s fail\n", WLAN_IFACE_NAME); ++ rtnl_unlock(); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, ++ WLAN_IFACE_NAME); ++ ifname = WLAN_IFACE_NAME; ++ wlan_if_changed = 0; ++ } ++ } ++ rtnl_unlock(); ++#endif ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 0; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_STA_P2P); ++ wlan_mode = WLAN_MODE_STA_P2P; ++ retval = count; ++ } ++ } else if (local[0] == 'A') { ++#if CFG_TC1_FEATURE ++ /* Change NIC name to legacy0, since wlan0 is used for AP */ ++ rtnl_lock(); ++ if (strcmp(ifname, LEGACY_IFACE_NAME) != 0) { ++ if (dev_change_name(netdev, LEGACY_IFACE_NAME) != 0) { ++ WIFI_ERR_FUNC("netdev name change to %s fail\n", LEGACY_IFACE_NAME); ++ rtnl_unlock(); ++ goto done; ++ } else { ++ WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, ++ LEGACY_IFACE_NAME); ++ ifname = LEGACY_IFACE_NAME; ++ wlan_if_changed = 1; ++ } ++ } ++ rtnl_unlock(); ++#endif ++ p2pmode.u4Enable = 1; ++ p2pmode.u4Mode = 1; ++ if (pf_set_p2p_mode(netdev, p2pmode) != 0) { ++ WIFI_ERR_FUNC("Set wlan mode fail\n"); ++ } else { ++ WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_AP); ++ wlan_mode = WLAN_MODE_AP; ++ retval = count; ++ } ++ } ++ dev_put(netdev); ++ netdev = NULL; ++ } ++ } ++done: ++ if (netdev != NULL) ++ dev_put(netdev); ++ ++ up(&wr_mtx); ++ return retval; ++} ++ ++const struct file_operations WIFI_fops = { ++ .open = WIFI_open, ++ .release = WIFI_close, ++ .write = WIFI_write, ++}; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++struct class *wmtwifi_class = NULL; ++#endif ++ ++static int WIFI_init(void) ++{ ++ dev_t dev = MKDEV(WIFI_major, 0); ++ INT32 alloc_ret = 0; ++ INT32 cdev_err = 0; ++#if WMT_CREATE_NODE_DYNAMIC ++ struct device *wmtwifi_dev = NULL; ++#endif ++ ++ /* static allocate chrdev */ ++ alloc_ret = register_chrdev_region(dev, 1, WIFI_DRIVER_NAME); ++ if (alloc_ret) { ++ WIFI_ERR_FUNC("Fail to register chrdev\n"); ++ return alloc_ret; ++ } ++ ++ cdev_init(&WIFI_cdev, &WIFI_fops); ++ WIFI_cdev.owner = THIS_MODULE; ++ ++ cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs); ++ if (cdev_err) ++ goto error; ++ ++#if WMT_CREATE_NODE_DYNAMIC /* mknod replace */ ++ wmtwifi_class = class_create(THIS_MODULE, "wmtWifi"); ++ if (IS_ERR(wmtwifi_class)) ++ goto error; ++ wmtwifi_dev = device_create(wmtwifi_class, NULL, dev, NULL, "wmtWifi"); ++ if (wmtwifi_dev == NULL) ++ goto error; ++ if (IS_ERR(wmtwifi_dev)) ++ goto error; ++#endif ++ ++ sema_init(&wr_mtx, 1); ++ ++ WIFI_INFO_FUNC("%s driver(major %d) installed.\n", WIFI_DRIVER_NAME, WIFI_major); ++ retflag = 0; ++ wlan_mode = WLAN_MODE_HALT; ++ pf_set_p2p_mode = NULL; ++ ++ return 0; ++ ++error: ++#if WMT_CREATE_NODE_DYNAMIC ++ if (!IS_ERR(wmtwifi_dev)) ++ device_destroy(wmtwifi_class, dev); ++ if (!IS_ERR(wmtwifi_class)) { ++ class_destroy(wmtwifi_class); ++ wmtwifi_class = NULL; ++ } ++#endif ++ ++ if (cdev_err == 0) ++ cdev_del(&WIFI_cdev); ++ ++ if (alloc_ret == 0) ++ unregister_chrdev_region(dev, WIFI_devs); ++ ++ return -1; ++} ++ ++static void WIFI_exit(void) ++{ ++ dev_t dev = MKDEV(WIFI_major, 0); ++ ++ retflag = 0; ++ ++#if WMT_CREATE_NODE_DYNAMIC ++ device_destroy(wmtwifi_class, dev); ++ class_destroy(wmtwifi_class); ++ wmtwifi_class = NULL; ++#endif ++ ++ cdev_del(&WIFI_cdev); ++ unregister_chrdev_region(dev, WIFI_devs); ++ ++ WIFI_INFO_FUNC("%s driver removed.\n", WIFI_DRIVER_NAME); ++} ++ ++#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++ ++INT32 mtk_wcn_wmt_wifi_init(VOID) ++{ ++ return WIFI_init(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wifi_init); ++ ++VOID mtk_wcn_wmt_wifi_exit(VOID) ++{ ++ return WIFI_exit(); ++} ++EXPORT_SYMBOL(mtk_wcn_wmt_wifi_exit); ++ ++#else ++ ++module_init(WIFI_init); ++module_exit(WIFI_exit); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c +new file mode 100644 +index 000000000000..641e516f603d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c +@@ -0,0 +1,307 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++#include "osal_typedef.h" ++#include "wmt_idc.h" ++#include "wmt_lib.h" ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++ ++MTK_WCN_WMT_IDC_INFO gWmtIdcInfo; ++ ++INT32 wmt_idc_init(VOID) ++{ ++ INT32 iRet; ++ ++ osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); ++ gWmtIdcInfo.iit.src_mod_id = AP_MOD_WMT; ++ gWmtIdcInfo.iit.dest_mod_id = MD_MOD_EL1; ++ gWmtIdcInfo.iit.sap_id = 0; ++ gWmtIdcInfo.ops.rx_cb = wmt_idc_msg_from_lte_handing; ++ ++ iRet = mtk_conn_md_bridge_reg(gWmtIdcInfo.iit.src_mod_id, &gWmtIdcInfo.ops); ++ if (iRet) { ++ WMT_ERR_FUNC("mtk_conn_md_bridge_reg fail(%d)\n", iRet); ++ return -1; ++ } ++ /* mtk_wcn_stp_flush_rx_queue(COEX_TASK_INDX); */ ++ return 0; ++ ++} ++ ++INT32 wmt_idc_deinit(VOID) ++{ ++ INT32 iRet; ++ ++ iRet = mtk_conn_md_bridge_unreg(gWmtIdcInfo.iit.src_mod_id); ++ if (iRet) ++ WMT_ERR_FUNC("mtk_conn_md_bridge_unreg fail(%d)\n", iRet); ++ ++ osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); ++ ++ return 0; ++} ++ ++INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm) ++{ ++ MTK_WCN_BOOL bRet; ++ ++ if (NULL == ilm) { ++ WMT_ERR_FUNC("NULL pointer\n"); ++ return -1; ++ } ++ if (mtk_wcn_stp_is_ready()) { ++ bRet = wmt_lib_handle_idc_msg(ilm); ++ if (MTK_WCN_BOOL_FALSE == bRet) { ++ WMT_ERR_FUNC("wmt handing idc msg fail\n"); ++ return -2; ++ } ++ } else { ++ WMT_INFO_FUNC("Received LTE msg,but STP is not ready,drop it!\n"); ++ } ++ return 0; ++} ++ ++VOID wmt_idc_dump_debug_msg(UINT8 *str, UINT8 *p_buf, UINT32 buf_len) ++{ ++ UINT32 idx = 0; ++ ++ WMT_DBG_FUNC("%s:, length:%d\n", str, buf_len); ++ ++ WMT_DBG_FUNC("ASCII output:\n"); ++ ++ for (idx = 0; idx < buf_len;) { ++ WMT_DBG_FUNC("%c", p_buf[idx]); ++ idx++; ++ if (0 == idx % 16) ++ WMT_DBG_FUNC("\n"); ++ } ++ ++ WMT_DBG_FUNC("HEX output:\n"); ++ ++ for (idx = 0; idx < buf_len;) { ++ WMT_DBG_FUNC("%02x ", p_buf[idx]); ++ idx++; ++ if (0 == idx % 16) ++ WMT_DBG_FUNC("\n"); ++ } ++} ++ ++INT32 wmt_idc_msg_to_lte_handing(VOID) ++{ ++ UINT32 readlen = 0; ++ local_para_struct *p_lps = NULL; ++ UINT8 *p_data = NULL; ++ UINT8 opcode = 0; ++ UINT16 msg_len = 0; ++ UINT32 handle_len = 0; ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++#endif ++ readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); ++ if (readlen == 0) { ++ osal_sleep_ms(5); ++ readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); ++ } ++ ++ if (readlen > 0) { ++ WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); ++ wmt_idc_dump_debug_msg("WMT->LTE from STP buffer", &gWmtIdcInfo.buffer[0], readlen); ++ p_data = &gWmtIdcInfo.buffer[0]; ++ ++ while (handle_len < readlen) { ++ p_data += 2; /*omit direction & opcode 2 bytes */ ++ osal_memcpy(&msg_len, p_data, 2); ++ msg_len -= 1; /*flag byte */ ++ WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); ++ ++ p_data += 2; /*length: 2 bytes */ ++ ++ /*how to handle flag(msg type) need to Scott comment */ ++ /************************************************/ ++ ++ if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) ++ /*do not need transfer to LTE */ ++ { ++ p_data += 1; /*flag : 1 byte */ ++ /*need to handle these debug message */ ++ wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); ++ } else ++ /*need to transfer to LTE */ ++ { ++ p_lps = ++ (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + ++ osal_sizeof(UINT8) * msg_len); ++ if (NULL == p_lps) { ++ WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); ++ return -1; ++ } ++ ++ p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); ++ ++ opcode = *p_data; ++ WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); ++ ++ p_data += 1; /*flag : 1 byte */ ++ osal_memcpy(p_lps->data, p_data, msg_len); ++ ++ gWmtIdcInfo.iit.local_para_ptr = p_lps; ++ ++#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING ++ switch (opcode) { ++ case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_UART_PIN_SEL: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_PIN_TYPE_IND; ++ break; ++ /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ ++ /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ ++ /* break; */ ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); ++ break; ++ } ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ } ++#else ++ if (opcode >= LTE_MSG_ID_OFFSET) { ++ gWmtIdcInfo.iit.msg_id = opcode + IPC_EL1_MSG_ID_BEGIN - LTE_MSG_ID_OFFSET + 1; ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ WMT_DBG_FUNC("CONN->LTE: (0x%x->0x%x)\n", opcode, gWmtIdcInfo.iit.msg_id); ++ } else { ++ WMT_ERR_FUNC("opcode(%d)from connsys fw is out of range,drop it!\n", opcode); ++ } ++#endif ++ osal_free(p_lps); ++ } ++ ++ p_data += msg_len; /*point to next package header */ ++ ++ handle_len += (msg_len + 5); ++ } ++ ++ } else { ++ WMT_ERR_FUNC("there is no coex data in stp buffer\n"); ++ } ++ ++ osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); ++ ++ return 0; ++} ++ ++UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len) ++{ ++ UINT32 readlen = len; ++ local_para_struct *p_lps = NULL; ++ UINT8 *p_data = NULL; ++ UINT8 opcode = 0; ++ UINT16 msg_len = 0; ++ UINT32 handle_len = 0; ++ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; ++ ++ osal_memcpy(&gWmtIdcInfo.buffer[0], p_buf, len); ++ ++ if (readlen > 0) { ++ WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); ++ p_data = &gWmtIdcInfo.buffer[0]; ++ ++ while (handle_len < readlen) { ++ p_data += 2; /*omit direction & opcode 2 bytes */ ++ osal_memcpy(&msg_len, p_data, 2); ++ msg_len -= 1; /*flag byte */ ++ WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); ++ ++ p_data += 2; /*length: 2 bytes */ ++ ++ /*how to handle flag(msg type) need to Scott comment */ ++ /************************************************/ ++ ++ if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) ++ /*do not need transfer to LTE */ ++ { ++ p_data += 1; /*flag : 1 byte */ ++ /*need to handle these debug message */ ++ wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); ++ } else ++ /*need to transfer to LTE */ ++ { ++ p_lps = ++ (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + ++ osal_sizeof(UINT8) * msg_len); ++ if (NULL == p_lps) { ++ WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); ++ return -1; ++ } ++ ++ p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); ++ ++ opcode = *p_data; ++ WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); ++ ++ p_data += 1; /*flag : 1 byte */ ++ osal_memcpy(p_lps->data, p_data, msg_len); ++ ++ gWmtIdcInfo.iit.local_para_ptr = p_lps; ++ ++ switch (opcode) { ++ case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; ++ break; ++ case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: ++ gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; ++ break; ++ /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ ++ /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ ++ /* break; */ ++ default: ++ unknown_msgid = MTK_WCN_BOOL_TRUE; ++ WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); ++ break; ++ } ++ if (MTK_WCN_BOOL_FALSE == unknown_msgid) { ++ /*handling flag value in wmt cmd */ ++ mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); ++ } ++ osal_free(p_lps); ++ } ++ ++ p_data += msg_len; /*point to next package header */ ++ ++ handle_len += (msg_len + 5); ++ } ++ ++ } else { ++ WMT_ERR_FUNC("there is no coex data in stp buffer\n"); ++ } ++ ++ osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); ++ ++ return handle_len; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile +new file mode 100644 +index 000000000000..c201e8291b8e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile +@@ -0,0 +1,25 @@ ++# WMT HAL driver for MT7623 ++ ++ccflags-y += \ ++ -I$(src)/include \ ++ -I$(src)/../linux/include \ ++ -I$(src)/../include \ ++ -I$(src)/../../common_detect ++ ++ ifeq ($(CONFIG_MTK_CLKMGR),y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach ++ endif ++ #ifeq ($(CONFIG_MTK_EMI_MPU),y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach ++ #endif ++ ++subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT ++ ++ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) ++ subdir-ccflags-y += -DWMT_IDC_SUPPORT=1 ++else ++ subdir-ccflags-y += -DWMT_IDC_SUPPORT=0 ++endif ++ ++obj-y += mtk_wcn_consys_hw.o ++obj-y += wmt_plat_alps.o +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h +new file mode 100644 +index 000000000000..94d6af9d0b3e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h +@@ -0,0 +1,287 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _MTK_WCN_CONSYS_HW_H_ ++#define _MTK_WCN_CONSYS_HW_H_ ++ ++#include ++/*#include */ ++#include "wmt_plat.h" ++ ++/*device tree mode*/ ++#ifdef CONFIG_OF ++/* #if 1 */ ++#include ++#include ++#include ++#include ++#endif ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CONSYS_BT_WIFI_SHARE_V33 0 ++#define CONSYS_PMIC_CTRL_ENABLE 1 ++#define CONSYS_PMIC_CTRL_UPMU 1 ++#define CONSYS_EMI_MPU_SETTING 0 ++#define CONSYS_AHB_CLK_MAGEMENT 1 ++#define CONSYS_USE_PLATFORM_WRITE 1 ++#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 ++#define CONSYS_CLOCK_BUF_CTRL 0 ++#if defined(CONFIG_MTK_LEGACY) ++#define CONFIG_MTK_PMIC_LEGACY 0 ++#endif ++#define CONFIG_RESET_CONTROL 1 ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*tag start:new platform need to make sure these define */ ++#define PLATFORM_SOC_CHIP 0x7623 ++/*tag end*/ ++ ++#ifdef CONFIG_OF ++ ++struct CONSYS_BASE_ADDRESS { ++ SIZE_T mcu_base; ++ SIZE_T ap_rgu_base; ++ SIZE_T topckgen_base; ++ SIZE_T spm_base; ++}; ++ ++/*TOPCKGEN_BASE*/ ++#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 ++#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 ++#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 ++#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000800 ++#define CONSYS_EMI_MAPPING_OFFSET 0x00000310 ++/*AP_RGU_BASE*/ ++#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 ++/*SPM_BASE*/ ++#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 ++#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000280 ++#define CONSYS_PWR_CONN_ACK_OFFSET 0x0000060c ++#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000610 ++/*CONN_MCU_CONFIG_BASE*/ ++#define CONSYS_CHIP_ID_OFFSET 0x00000008 ++#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 ++#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 ++#define CONSYS_CPUPCR_OFFSET 0x00000160 ++/*AXI bus*/ ++ ++#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 ++#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x0228 ++#endif ++ ++#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile UINT32*)(REG)) |= ((UINT32)(BITVAL))) ++#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile UINT32*)(REG)) &= ~((UINT32)(BITVAL))) ++#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ ++ UINT32 val = (*(volatile UINT32*)(REG)); \ ++ val &= ~((UINT32)(BITVAL)); \ ++ val |= ((UINT32)(KEY)); \ ++ (*(volatile UINT32*)(REG)) = val;\ ++} ++#define CONSYS_REG_READ(addr) (*((volatile UINT32*)(addr))) ++#if CONSYS_USE_PLATFORM_WRITE ++#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) ++#else ++#define CONSYS_REG_WRITE(addr, data) (*((volatile UINT32*)(addr)) = (UINT32)(data)) ++#endif ++ ++/*tag start: connsys register base address (hard code, no use) */ ++#define AP_RGU_BASE 0xF0007000 ++#define TOPCKGEN_BASE 0xF0000000 ++#define SPM_BASE 0xF0006000 ++#define CONN_MCU_CONFIG_BASE 0xF8070000 ++/*GIC Interrupt ID*/ ++#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 237 ++/*tag end*/ ++ ++/*connsys register offset define(hard code mode)*/ ++#if 1 ++ /*top clock gating control register */ ++#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) ++#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) ++#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) ++ ++ /*SPM clock gating control register */ ++#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) ++#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) ++#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) ++#endif ++ ++#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) ++#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x00000280) ++#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x0000060c) ++#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000610) ++ ++#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) ++#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) ++#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) ++#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) ++#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) ++#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) ++#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) ++#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) ++#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) ++#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) ++#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) ++ ++#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x0220) ++#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x0228) ++#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14) | (0x1<<15)) /* bit 13, 14, 15 */ ++/*CONSYS_CPU_SW_RST_REG*/ ++#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) ++#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) ++ ++/*CONSYS_TOP1_PWR_CTRL_REG*/ ++#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) ++#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) ++#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) ++#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) ++#define CONSYS_CLK_CTRL_BIT (0x1 << 4) ++#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) ++ ++/*CONSYS_PWR_CONN_ACK_REG*/ ++#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) ++ ++/*CONSYS_PWR_CONN_ACK_S_REG*/ ++#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) ++ ++/*CONSYS_WD_SYS_RST_REG*/ ++#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) ++#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) ++ ++/*CONSYS_MCU_CFG_ACR_REG*/ ++#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) ++ ++/* EMI part mapping & ctrl*/ ++#define KBYTE (1024*sizeof(char)) ++#define CONSYS_EMI_AP_PHY_OFFSET (0x80000) ++#define CONSYS_EMI_AP_PHY_BASE (0x80080000) ++#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) ++#define CONSYS_EMI_MEM_SIZE (343*KBYTE) /*coredump space , 343K is enough */ ++#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) ++#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) ++#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) ++ ++/*cpupcr*/ ++#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) ++/*emi mapping*/ ++#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + 0x1310) ++ ++/*control app2cnn_osc_en*/ ++#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) ++#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 16) ++#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 17) ++ ++/*paged dump address start*/ ++#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) ++#define CONSYS_PAGED_DUMP_SIZE (32*KBYTE) ++ ++/*full dump address start*/ ++#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) ++#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) ++#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) ++#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) ++#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) ++#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) ++ ++/*force fw assert pattern*/ ++#define EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1 (0x19b30bb1) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_EMI_CTRL_STATE_OFFSET_ { ++ EXP_APMEM_CTRL_STATE = 0x0, ++ EXP_APMEM_CTRL_HOST_SYNC_STATE = 0x4, ++ EXP_APMEM_CTRL_HOST_SYNC_NUM = 0x8, ++ EXP_APMEM_CTRL_CHIP_SYNC_STATE = 0xc, ++ EXP_APMEM_CTRL_CHIP_SYNC_NUM = 0x10, ++ EXP_APMEM_CTRL_CHIP_SYNC_ADDR = 0x14, ++ EXP_APMEM_CTRL_CHIP_SYNC_LEN = 0x18, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START = 0x1c, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN = 0x20, ++ EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX = 0x24, ++ EXP_APMEM_CTRL_CHIP_INT_STATUS = 0x28, ++ EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END = 0x2c, ++ EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 = 0x30, ++ EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP = 0x48, ++ EXP_APMEM_CTRL_MAX ++} ENUM_EMI_CTRL_STATE_OFFSET, *P_ENUM_EMI_CTRL_STATE_OFFSET; ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++typedef struct _BT_WIFI_V33_STATUS_ { ++ UINT32 counter; ++ UINT32 flags; ++ spinlock_t lock; ++} BT_WIFI_V33_STATUS; ++ ++#endif ++ ++typedef enum _CONSYS_GPS_CO_CLOCK_TYPE_ { ++ GPS_TCXO_TYPE = 0, ++ GPS_CO_TSX_TYPE = 1, ++ GPS_CO_DCXO_TYPE = 2, ++ GPS_CO_VCTCXO_TYPE = 3, ++ GPS_CO_CLOCK_TYPE_MAX ++} CONSYS_GPS_CO_CLOCK_TYPE, *P_CONSYS_GPS_CO_CLOCK_TYPE; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern struct CONSYS_BASE_ADDRESS conn_reg; ++#if CONSYS_BT_WIFI_SHARE_V33 ++extern BT_WIFI_V33_STATUS gBtWifiV33; ++#endif ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++extern INT32 mtk_wcn_consys_hw_init(VOID); ++extern INT32 mtk_wcn_consys_hw_deinit(VOID); ++extern INT32 mtk_wcn_consys_hw_pwr_off(VOID); ++extern INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type); ++extern INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type); ++extern INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable); ++extern INT32 mtk_wcn_consys_hw_state_show(VOID); ++extern UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset); ++#if CONSYS_ENALBE_SET_JTAG ++extern UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en); ++#endif ++extern UINT32 mtk_wcn_consys_soc_chipid(VOID); ++#if !defined(CONFIG_MTK_GPIO_LEGACY) ++extern struct pinctrl *mtk_wcn_consys_get_pinctrl(VOID); ++#endif ++extern INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 buf); ++#endif /* _MTK_WCN_CMB_HW_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +new file mode 100644 +index 000000000000..53b69a7b3e87 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +@@ -0,0 +1,738 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-CONSYS-HW]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include "osal_typedef.h" ++#include "mtk_wcn_consys_hw.h" ++#include ++#include ++#include ++#if CONSYS_EMI_MPU_SETTING ++#include ++#endif ++ ++#include ++#include ++#ifdef CONFIG_MTK_HIBERNATION ++#include ++#endif ++ ++#include ++ ++#if CONSYS_CLOCK_BUF_CTRL ++#include ++#endif ++ ++#include ++#include ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static INT32 mtk_wmt_probe(struct platform_device *pdev); ++static INT32 mtk_wmt_remove(struct platform_device *pdev); ++ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++struct CONSYS_BASE_ADDRESS conn_reg; ++static phys_addr_t gConEmiPhyBase; ++static UINT8 __iomem *pEmibaseaddr; ++static struct clk *clk_infra_conn_main; /*ctrl infra_connmcu_bus clk */ ++static struct platform_device *my_pdev; ++static struct reset_control *rstc; ++static struct regulator *reg_VCN18; ++static struct regulator *reg_VCN28; ++static struct regulator *reg_VCN33_BT; ++static struct regulator *reg_VCN33_WIFI; ++static struct pinctrl *consys_pinctrl; ++static struct pinctrl *mt6625_spi_pinctrl; ++static struct pinctrl_state *mt6625_spi_default; ++static struct regmap *pmic_regmap; ++#define DYNAMIC_DUMP_GROUP_NUM 5 ++ ++static const struct of_device_id apwmt_of_ids[] = { ++ {.compatible = "mediatek,mt7623-consys",} ++}; ++MODULE_DEVICE_TABLE(of, apwmt_of_ids); ++ ++static struct platform_driver mtk_wmt_dev_drv = { ++ .probe = mtk_wmt_probe, ++ .remove = mtk_wmt_remove, ++ .driver = { ++ .name = "mt7623consys", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(apwmt_of_ids), ++ }, ++}; ++ ++static INT32 mtk_wmt_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct device_node *node = NULL; ++ ++ pm_runtime_enable(&pdev->dev); ++ my_pdev = pdev; ++ mt6625_spi_pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(mt6625_spi_pinctrl)) { ++ ret = PTR_ERR(mt6625_spi_pinctrl); ++ WMT_PLAT_ERR_FUNC("Wmt cannot find pinctrl!\n"); ++ goto set_pin_exit; ++ } ++ mt6625_spi_default = pinctrl_lookup_state(mt6625_spi_pinctrl, "consys_pins_default"); ++ if (IS_ERR(mt6625_spi_default)) { ++ ret = PTR_ERR(mt6625_spi_default); ++ WMT_PLAT_ERR_FUNC("Wmt Cannot find pinctrl default!\n"); ++ goto set_pin_exit; ++ } ++ pinctrl_select_state(mt6625_spi_pinctrl, mt6625_spi_default); ++set_pin_exit: ++ ++ node = of_parse_phandle(pdev->dev.of_node, "mediatek,pwrap-regmap", 0); ++ if (node) { ++ pmic_regmap = pwrap_node_to_regmap(node); ++ if (IS_ERR(pmic_regmap)) ++ goto set_pmic_wrap_exit; ++ } else { ++ WMT_PLAT_ERR_FUNC("Pwrap node has not register regmap.\n"); ++ goto set_pmic_wrap_exit; ++ } ++set_pmic_wrap_exit: ++ ++ clk_infra_conn_main = devm_clk_get(&pdev->dev, "consysbus"); ++ if (IS_ERR(clk_infra_conn_main)) { ++ WMT_PLAT_ERR_FUNC("sean debug [CCF]cannot get clk_infra_conn_main clock.\n"); ++ return PTR_ERR(clk_infra_conn_main); ++ } ++ WMT_PLAT_DBG_FUNC("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); ++ ++ reg_VCN18 = devm_regulator_get(&pdev->dev, "vcn18"); ++ if (IS_ERR(reg_VCN18)) { ++ ret = PTR_ERR(reg_VCN18); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN_1V8 fail, ret=%d\n", ret); ++ } ++ reg_VCN28 = devm_regulator_get(&pdev->dev, "vcn28"); ++ if (IS_ERR(reg_VCN28)) { ++ ret = PTR_ERR(reg_VCN28); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN_2V8 fail, ret=%d\n", ret); ++ } ++ reg_VCN33_BT = devm_regulator_get(&pdev->dev, "vcn33_bt"); ++ if (IS_ERR(reg_VCN33_BT)) { ++ ret = PTR_ERR(reg_VCN33_BT); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN33_BT fail, ret=%d\n", ret); ++ } ++ reg_VCN33_WIFI = devm_regulator_get(&pdev->dev, "vcn33_wifi"); ++ if (IS_ERR(reg_VCN33_WIFI)) { ++ ret = PTR_ERR(reg_VCN33_WIFI); ++ WMT_PLAT_ERR_FUNC("Regulator_get VCN33_WIFI fail, ret=%d\n", ret); ++ } ++ ++ rstc = devm_reset_control_get(&pdev->dev, "connsys"); ++ if (IS_ERR(rstc)) { ++ ret = PTR_ERR(rstc); ++ WMT_PLAT_ERR_FUNC("CanNot get consys reset. ret=%d\n", ret); ++ return PTR_ERR(rstc); ++ } ++ ++ consys_pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(consys_pinctrl)) { ++ ret = PTR_ERR(consys_pinctrl); ++ WMT_PLAT_ERR_FUNC("CanNot find consys pinctrl. ret=%d\n", ret); ++ return PTR_ERR(consys_pinctrl); ++ } ++ return 0; ++} ++ ++static INT32 mtk_wmt_remove(struct platform_device *pdev) ++{ ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++VOID mtk_wcn_consys_power_on(VOID) ++{ ++ INT32 iRet = -1; ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ iRet = pm_runtime_get_sync(&my_pdev->dev); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("pm_runtime_get_sync() fail(%d)\n", iRet); ++ else ++ WMT_PLAT_INFO_FUNC("pm_runtime_get_sync() CONSYS ok\n"); ++ ++ iRet = device_init_wakeup(&my_pdev->dev, true); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("device_init_wakeup(true) fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("device_init_wakeup(true) CONSYS ok\n"); ++} ++ ++VOID mtk_wcn_consys_power_off(VOID) ++{ ++ INT32 iRet = -1; ++ ++ iRet = pm_runtime_put_sync(&my_pdev->dev); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("pm_runtime_put_sync() fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("pm_runtime_put_sync() CONSYS ok\n"); ++ ++ iRet = device_init_wakeup(&my_pdev->dev, false); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("device_init_wakeup(false) fail.\n"); ++ else ++ WMT_PLAT_INFO_FUNC("device_init_wakeup(false) CONSYS ok\n"); ++} ++ ++INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_type) ++{ ++ UINT32 retry = 10; ++ UINT32 consysHwChipId = 0; ++ ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),start\n", on); ++ if (on) { ++ WMT_PLAT_DBG_FUNC("++\n"); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /*need PMIC driver provide new API protocol */ ++ /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ ++ regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ ++ if (reg_VCN18) { ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ regulator_set_voltage(reg_VCN18, 1800000, 1800000); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (regulator_enable(reg_VCN18)) ++ WMT_PLAT_ERR_FUNC("enable VCN18 fail\n"); ++ else ++ WMT_PLAT_DBG_FUNC("enable VCN18 ok\n"); ++ } ++ udelay(150); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ if (co_clock_type) { ++ /*step0,clk buf ctrl */ ++ WMT_PLAT_INFO_FUNC("co clock type(%d),turn on clk buf\n", co_clock_type); ++#if CONSYS_CLOCK_BUF_CTRL ++ clk_buf_ctrl(CLK_BUF_CONN, 1); ++#endif ++ /*if co-clock mode: */ ++ /*2.set VCN28 to SW control mode (with PMIC_WRAP API) */ ++ /*turn on VCN28 LDO only when FMSYS is activated" */ ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ ++ } else { ++ /*if NOT co-clock: */ ++ /*2.1.switch VCN28 to HW control mode (with PMIC_WRAP API) */ ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x1 << 14);/*V28*/ ++ /*2.2.turn on VCN28 LDO (with PMIC_WRAP API)" */ ++ /*fix vcn28 not balance warning */ ++ if (reg_VCN28) { ++ regulator_set_voltage(reg_VCN28, 2800000, 2800000); ++ if (regulator_enable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("enable VCN_2V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("enable VCN_2V8 ok\n"); ++ } ++ } ++ ++ /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ reset_control_reset(rstc); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ mtk_wcn_consys_power_on(); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ /*11.26M is ready now, delay 10us for mem_pd de-assert */ ++ udelay(10); ++ /*enable AP bus clock : connmcu_bus_pd API: enable_clock() ++?? */ ++ clk_prepare_enable(clk_infra_conn_main); ++printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ++ WMT_PLAT_DBG_FUNC("[CCF]enable clk_infra_conn_main\n"); ++ /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ ++ while (retry-- > 0) { ++ consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET) - 0xf6d; ++ ++ if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { ++ WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); ++ break; ++ } ++ if ((consysHwChipId == 0x8163) || (consysHwChipId == 0x8127) || (consysHwChipId == 0x7623)) { ++ WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); ++ break; ++ } ++ ++ WMT_PLAT_ERR_FUNC("Read CONSYS chipId(0x%08x)", consysHwChipId); ++ msleep(20); ++ } ++ ++ if ((0 == retry) || (0 == consysHwChipId)) ++ WMT_PLAT_ERR_FUNC("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); ++ ++ msleep(40); ++ ++ } else { ++ ++ clk_disable_unprepare(clk_infra_conn_main); ++ WMT_PLAT_DBG_FUNC("[CCF] clk_disable_unprepare(clk_infra_conn_main) calling\n"); ++ mtk_wcn_consys_power_off(); ++ ++ if (co_clock_type) { ++ /*VCN28 has been turned off by GPS OR FM */ ++#if CONSYS_CLOCK_BUF_CTRL ++ clk_buf_ctrl(CLK_BUF_CONN, 0); ++#endif ++ } else { ++ regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ ++ /*turn off VCN28 LDO (with PMIC_WRAP API)" */ ++ if (reg_VCN28) { ++ if (regulator_disable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("disable VCN_2V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("disable VCN_2V8 ok\n"); ++ } ++ } ++ ++ /*AP power off MT6625L VCN_1V8 LDO */ ++ regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); ++ if (reg_VCN18) { ++ if (regulator_disable(reg_VCN18)) ++ WMT_PLAT_ERR_FUNC("disable VCN_1V8 fail!\n"); ++ else ++ WMT_PLAT_DBG_FUNC("disable VCN_1V8 ok\n"); ++ } ++ ++ } ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),finish\n", on); ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_gpio_ctrl(UINT32 on) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), start\n", on); ++ ++ if (on) { ++ ++ /* TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok */ ++ /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); */ ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ registered and disabled\n"); ++ ++ } else { ++ ++ /* set bgf eint/all eint to deinit state, namely input low state */ ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); ++ WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ unregistered and disabled\n"); ++ /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); */ ++ } ++ WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), finish\n", on); ++ return iRet; ++ ++} ++ ++INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, start\n"); ++ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); ++ iRet += mtk_wcn_consys_hw_gpio_ctrl(1); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, finish(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_pwr_off(VOID) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, start\n"); ++ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(0, 0); ++ iRet += mtk_wcn_consys_hw_gpio_ctrl(0); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, finish(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type) ++{ ++ INT32 iRet = 0; ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst start, eirq should be disabled before this step\n"); ++ ++ /*1. do whole hw power off flow */ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(0, co_clock_type); ++ ++ /*2. do whole hw power on flow */ ++ iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst finish, eirq should be enabled after this step\n"); ++ return iRet; ++} ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) ++{ ++ /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ ++ if (enable) { ++ if (1 == gBtWifiV33.counter) { ++ gBtWifiV33.counter++; ++ WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); ++ } else if (2 == gBtWifiV33.counter) { ++ WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); ++ } else { ++#if CONSYS_PMIC_CTRL_ENABLE ++ /*do BT PMIC on,depenency PMIC API ready */ ++ /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ ++ /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ ++ hwPowerOn(MT6323_POWER_LDO_VCN33, VOL_3300, "wcn_drv"); ++ upmu_set_vcn33_on_ctrl_bt(1); ++#endif ++ WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 on\n"); ++ gBtWifiV33.counter++; ++ } ++ ++ } else { ++ if (1 == gBtWifiV33.counter) { ++ /*do BT PMIC off */ ++ /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ ++#if CONSYS_PMIC_CTRL_ENABLE ++ upmu_set_vcn33_on_ctrl_bt(0); ++ hwPowerDown(MT6323_POWER_LDO_VCN33, "wcn_drv"); ++#endif ++ WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 off\n"); ++ gBtWifiV33.counter--; ++ } else if (2 == gBtWifiV33.counter) { ++ gBtWifiV33.counter--; ++ WMT_PLAT_DBG_FUNC("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); ++ } else { ++ WMT_PLAT_DBG_FUNC("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); ++ } ++ ++ } ++ /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) ++{ ++ mtk_wcn_consys_hw_bt_paldo_ctrl(enable); ++ return 0; ++} ++ ++#else ++INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) ++{ ++ ++ if (enable) { ++ /*do BT PMIC on,depenency PMIC API ready */ ++ /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ ++ if (reg_VCN33_BT) { ++ regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); ++ if (regulator_enable(reg_VCN33_BT)) ++ WMT_PLAT_ERR_FUNC("WMT do BT PMIC on fail!\n"); ++ } ++ regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x1 << 5);/*BT*/ ++ WMT_PLAT_INFO_FUNC("WMT do BT PMIC on\n"); ++ } else { ++ /*do BT PMIC off */ ++ /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ ++ regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x0 << 5);/*BT*/ ++ if (reg_VCN33_BT) ++ if (regulator_disable(reg_VCN33_BT)) ++ WMT_PLAT_ERR_FUNC("WMT do BT PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("WMT do BT PMIC off\n"); ++ } ++ ++ return 0; ++ ++} ++ ++INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) ++{ ++ ++ if (enable) { ++ /*do WIFI PMIC on,depenency PMIC API ready */ ++ /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ ++ if (reg_VCN33_WIFI) { ++ regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); ++ if (regulator_enable(reg_VCN33_WIFI)) ++ WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC on fail!\n"); ++ else ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on !\n"); ++ } ++ regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x1 << 14);/*WIFI*/ ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on\n"); ++ } else { ++ /*do WIFI PMIC off */ ++ /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ ++ regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x0 << 14);/*WIFI*/ ++ if (reg_VCN33_WIFI) ++ if (regulator_disable(reg_VCN33_WIFI)) ++ WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC off\n"); ++ } ++ ++ return 0; ++} ++ ++#endif ++INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) ++{ ++ if (enable) { ++ /*in co-clock mode,need to turn on vcn28 when fm on */ ++ if (reg_VCN28) { ++ regulator_set_voltage(reg_VCN28, 2800000, 2800000); ++ if (regulator_enable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC on fail!\n"); ++ } ++ WMT_PLAT_INFO_FUNC("turn on vcn28 for fm/gps usage in co-clock mode\n"); ++ } else { ++ /*in co-clock mode,need to turn off vcn28 when fm off */ ++ if (reg_VCN28) ++ if (regulator_disable(reg_VCN28)) ++ WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC off fail!\n"); ++ WMT_PLAT_INFO_FUNC("turn off vcn28 for fm/gps usage in co-clock mode\n"); ++ } ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_state_show(VOID) ++{ ++ return 0; ++} ++ ++INT32 mtk_wcn_consys_hw_restore(struct device *device) ++{ ++ UINT32 addrPhy = 0; ++ ++ if (gConEmiPhyBase) { ++ ++#if CONSYS_EMI_MPU_SETTING ++ /*set MPU for EMI share Memory */ ++ WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); ++ ++#if 0 ++ emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, ++ gConEmiPhyBase + SZ_1M, ++ 5, ++ SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); ++ ++ ++#else ++ WMT_PLAT_WARN_FUNC("not define platform config\n"); ++#endif ++ ++#endif ++ /*consys to ap emi remapping register:10001310, cal remapping address */ ++ addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; ++ ++ /*enable consys to ap emi remapping bit12 */ ++ addrPhy = addrPhy | 0x1000; ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); ++ ++#if 1 ++ pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); ++#else ++ pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); ++#endif ++ if (pEmibaseaddr) { ++ WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); ++ memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); ++ } else { ++ WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); ++ } ++ } else { ++ WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); ++ } ++ ++ return 0; ++} ++ ++/*Reserved memory by device tree!*/ ++int reserve_memory_consys_fn(struct reserved_mem *rmem) ++{ ++ WMT_PLAT_WARN_FUNC(" name: %s, base: 0x%llx, size: 0x%llx\n", rmem->name, ++ (unsigned long long)rmem->base, (unsigned long long)rmem->size); ++ gConEmiPhyBase = rmem->base; ++ return 0; ++} ++ ++RESERVEDMEM_OF_DECLARE(reserve_memory_test, "mediatek,consys-reserve-memory", reserve_memory_consys_fn); ++ ++ ++INT32 mtk_wcn_consys_hw_init(void) ++{ ++ ++ INT32 iRet = -1; ++ UINT32 addrPhy = 0; ++ INT32 i = 0; ++ struct device_node *node = NULL; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); ++ if (node) { ++ /* registers base address */ ++ conn_reg.mcu_base = (SIZE_T) of_iomap(node, i); ++ WMT_PLAT_DBG_FUNC("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); ++ i++; ++ ++ conn_reg.topckgen_base = (SIZE_T) of_iomap(node, i); ++ WMT_PLAT_DBG_FUNC("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); ++ i++; ++ } else { ++ WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); ++ return iRet; ++ } ++ if (gConEmiPhyBase) { ++#if CONSYS_EMI_MPU_SETTING ++ /*set MPU for EMI share Memory */ ++ WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); ++ ++#if 0 ++ emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, ++ gConEmiPhyBase + SZ_1M, ++ 5, ++ SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); ++#else ++ WMT_PLAT_WARN_FUNC("not define platform config\n"); ++#endif ++ ++#endif ++ WMT_PLAT_DBG_FUNC("get consys start phy address(0x%zx)\n", (SIZE_T) gConEmiPhyBase); ++ ++ /*consys to ap emi remapping register:10001310, cal remapping address */ ++ addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; ++ ++ /*enable consys to ap emi remapping bit12 */ ++ addrPhy = addrPhy | 0x1000; ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); ++ ++ WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump(0x%08x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); ++ ++#if 1 ++ pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); ++#else ++ pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); ++#endif ++ /* pEmibaseaddr = ioremap_nocache(0x80090400,270*KBYTE); */ ++ if (pEmibaseaddr) { ++ WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); ++ memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); ++ iRet = 0; ++ } else { ++ WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); ++ } ++ } else { ++ WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); ++ } ++#ifdef CONFIG_MTK_HIBERNATION ++ WMT_PLAT_INFO_FUNC("register connsys restore cb for complying with IPOH function\n"); ++ register_swsusp_restore_noirq_func(ID_M_CONNSYS, mtk_wcn_consys_hw_restore, NULL); ++#endif ++ iRet = platform_driver_register(&mtk_wmt_dev_drv); ++ if (iRet) ++ WMT_PLAT_ERR_FUNC("WMT platform driver registered failed(%d)\n", iRet); ++ return iRet; ++} ++ ++INT32 mtk_wcn_consys_hw_deinit(void) ++{ ++ if (pEmibaseaddr) { ++ iounmap(pEmibaseaddr); ++ pEmibaseaddr = NULL; ++ } ++#ifdef CONFIG_MTK_HIBERNATION ++ unregister_swsusp_restore_noirq_func(ID_M_CONNSYS); ++#endif ++ ++ platform_driver_unregister(&mtk_wmt_dev_drv); ++ return 0; ++} ++ ++UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset) ++{ ++ UINT8 *p_virtual_addr = NULL; ++ ++ if (!pEmibaseaddr) { ++ WMT_PLAT_ERR_FUNC("EMI base address is NULL\n"); ++ return NULL; ++ } ++ WMT_PLAT_DBG_FUNC("ctrl_state_offset(%08x)\n", ctrl_state_offset); ++ p_virtual_addr = pEmibaseaddr + ctrl_state_offset; ++ ++ return p_virtual_addr; ++} ++ ++UINT32 mtk_wcn_consys_soc_chipid(void) ++{ ++ return PLATFORM_SOC_CHIP; ++} ++ ++struct pinctrl *mtk_wcn_consys_get_pinctrl() ++{ ++ return consys_pinctrl; ++} ++INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 str_buf) ++{ ++ PUINT8 vir_addr = NULL; ++ ++ vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP); ++ if (!vir_addr) { ++ WMT_PLAT_ERR_FUNC("get vir address fail\n"); ++ return -2; ++ } ++ memcpy(vir_addr, str_buf, DYNAMIC_DUMP_GROUP_NUM*8); ++ WMT_PLAT_INFO_FUNC("dynamic dump register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); ++ return 0; ++} +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c +new file mode 100644 +index 000000000000..7163dc18a255 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c +@@ -0,0 +1,1071 @@ ++/*! \file ++ \brief Declaration of library functions ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#ifdef DFT_TAG ++#undef DFT_TAG ++#endif ++#define DFT_TAG "[WMT-PLAT]" ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++/* ALPS header files */ ++/*#include */ ++/*#include */ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++#include ++#endif ++#include ++ ++/* MTK_WCN_COMBO header files */ ++#include "osal_typedef.h" ++#include "mtk_wcn_consys_hw.h" ++#include "stp_dbg.h" ++ ++#define CFG_WMT_WAKELOCK_SUPPORT 1 ++ ++#ifdef CONFIG_MTK_MT6306_SUPPORT ++#define MTK_WCN_MT6306_IS_READY 1 ++#else ++#define MTK_WCN_MT6306_IS_READY 0 ++#endif ++ ++#if MTK_WCN_MT6306_IS_READY ++#include ++ ++#ifdef GPIO_GPS_LNA_PIN ++#undef GPIO_GPS_LNA_PIN ++#endif ++ ++#define GPIO_GPS_LNA_PIN GPIO7 ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { ++ .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, ++ .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, ++ .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, ++ .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, ++ .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, ++ .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, ++ .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, ++ .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, ++ .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, ++ .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, ++ .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, ++ .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, ++ .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, ++}; ++ ++CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { ++ .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, ++ .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, ++ .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, ++ .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, ++ .p_ecso = &mtk_wcn_emi_state_off, ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static VOID wmt_plat_bgf_eirq_cb(VOID); ++ ++static INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state); ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state); ++ ++static INT32 wmt_plat_dump_pin_conf(VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++UINT32 gCoClockFlag = 0; ++BGF_IRQ_BALANCE gbgfIrqBle; ++UINT32 wmtPlatLogLvl = WMT_PLAT_LOG_DBG; ++#if CONSYS_BT_WIFI_SHARE_V33 ++BT_WIFI_V33_STATUS gBtWifiV33; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_WMT_WAKELOCK_SUPPORT ++static struct mutex gOsSLock; ++#ifdef CONFIG_PM_WAKELOCKS ++static struct wakeup_source wmtWakeLock; ++#else ++static struct wake_lock wmtWakeLock; ++#endif ++#endif ++ ++irq_cb wmt_plat_bgf_irq_cb = NULL; ++device_audio_if_cb wmt_plat_audio_if_cb = NULL; ++func_ctrl_cb wmt_plat_func_ctrl_cb = NULL; ++thermal_query_ctrl_cb wmt_plat_thermal_query_ctrl_cb = NULL; ++deep_idle_ctrl_cb wmt_plat_deep_idle_ctrl_cb = NULL; ++ ++static const fp_set_pin gfp_set_pin_table[] = { ++ [PIN_BGF_EINT] = wmt_plat_bgf_eint_ctrl, ++ [PIN_I2S_GRP] = wmt_plat_i2s_ctrl, ++ [PIN_GPS_SYNC] = wmt_plat_gps_sync_ctrl, ++ [PIN_GPS_LNA] = wmt_plat_gps_lna_ctrl, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*! ++ * \brief audio control callback function for CMB_STUB on ALPS ++ * ++ * A platform function required for dynamic binding with CMB_STUB on ALPS. ++ * ++ * \param state desired audio interface state to use ++ * \param flag audio interface control options ++ * ++ * \retval 0 operation success ++ * \retval -1 invalid parameters ++ * \retval < 0 error for operation fail ++ */ ++INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) ++{ ++ INT32 iRet = 0; ++ UINT32 pinShare = 0; ++ ++ /* input sanity check */ ++ if ((CMB_STUB_AIF_MAX <= state) ++ || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { ++ return -1; ++ } ++ ++ iRet = 0; ++ ++ /* set host side first */ ++ switch (state) { ++ case CMB_STUB_AIF_0: ++ /* BT_PCM_OFF & FM line in/out */ ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); ++ break; ++ ++ case CMB_STUB_AIF_1: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); ++ break; ++ ++ case CMB_STUB_AIF_2: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); ++ break; ++ ++ case CMB_STUB_AIF_3: ++ iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); ++ break; ++ ++ default: ++ /* FIXME: move to cust folder? */ ++ WMT_PLAT_ERR_FUNC("invalid state [%d]\n", state); ++ iRet = -1; ++ break; ++ } ++ ++ if (CMB_STUB_AIF_CTRL_EN == ctrl) { ++ WMT_PLAT_INFO_FUNC("call chip aif setting\n"); ++ /* need to control chip side GPIO */ ++ if (NULL != wmt_plat_audio_if_cb) { ++ iRet += (*wmt_plat_audio_if_cb) (state, (pinShare) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); ++ } else { ++ WMT_PLAT_WARN_FUNC("wmt_plat_audio_if_cb is not registered\n"); ++ iRet -= 1; ++ } ++ ++ } else { ++ WMT_PLAT_INFO_FUNC("skip chip aif setting\n"); ++ } ++ ++ return iRet; ++ ++} ++ ++static VOID wmt_plat_func_ctrl(UINT32 type, UINT32 on) ++{ ++ if (wmt_plat_func_ctrl_cb) ++ (*wmt_plat_func_ctrl_cb) (on, type); ++} ++ ++static long wmt_plat_thermal_ctrl(VOID) ++{ ++ long temp = 0; ++ ++ if (wmt_plat_thermal_query_ctrl_cb) ++ temp = (*wmt_plat_thermal_query_ctrl_cb) (); ++ ++ return temp; ++} ++ ++static INT32 wmt_plat_deep_idle_ctrl(UINT32 dpilde_ctrl) ++{ ++ INT32 iRet = -1; ++ ++ if (wmt_plat_deep_idle_ctrl_cb) ++ iRet = (*wmt_plat_deep_idle_ctrl_cb) (dpilde_ctrl); ++ ++ return iRet; ++} ++ ++static VOID wmt_plat_bgf_eirq_cb(VOID) ++{ ++#if CFG_WMT_PS_SUPPORT ++/* #error "need to disable EINT here" */ ++ /* wmt_lib_ps_irq_cb(); */ ++ if (NULL != wmt_plat_bgf_irq_cb) ++ (*(wmt_plat_bgf_irq_cb)) (); ++ else ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: wmt_plat_bgf_irq_cb not registered\n"); ++#else ++ return; ++#endif ++ ++} ++ ++irqreturn_t wmt_plat_bgf_irq_isr(INT32 i, VOID *arg) ++{ ++#if CFG_WMT_PS_SUPPORT ++ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); ++ wmt_plat_bgf_eirq_cb(); ++#else ++ WMT_PLAT_INFO_FUNC("skip irq handing because psm is disable"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb) ++{ ++ wmt_plat_bgf_irq_cb = bgf_irq_cb; ++} ++EXPORT_SYMBOL(wmt_plat_irq_cb_reg); ++ ++VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb) ++{ ++ wmt_plat_audio_if_cb = aif_ctrl_cb; ++} ++EXPORT_SYMBOL(wmt_plat_aif_cb_reg); ++ ++VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl) ++{ ++ wmt_plat_func_ctrl_cb = subsys_func_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_func_ctrl_cb_reg); ++ ++VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl) ++{ ++ wmt_plat_thermal_query_ctrl_cb = thermal_query_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_thermal_ctrl_cb_reg); ++ ++VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl) ++{ ++ wmt_plat_deep_idle_ctrl_cb = deep_idle_ctrl; ++} ++EXPORT_SYMBOL(wmt_plat_deep_idle_ctrl_cb_reg); ++ ++UINT32 wmt_plat_soc_co_clock_flag_get(VOID) ++{ ++ return gCoClockFlag; ++} ++ ++static UINT32 wmt_plat_soc_co_clock_flag_set(UINT32 flag) ++{ ++ gCoClockFlag = flag; ++ return 0; ++} ++ ++INT32 wmt_plat_init(UINT32 co_clock_type) ++{ ++ CMB_STUB_CB stub_cb; ++ INT32 iret; ++ /*init wmt function ctrl wakelock if wake lock is supported by host platform */ ++ ++ wmt_plat_soc_co_clock_flag_set(co_clock_type); ++ ++ stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; ++ stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; ++ stub_cb.thermal_query_cb = wmt_plat_thermal_ctrl; ++ stub_cb.deep_idle_ctrl_cb = wmt_plat_deep_idle_ctrl; ++ stub_cb.size = sizeof(stub_cb); ++ ++ /* register to cmb_stub */ ++ iret = mtk_wcn_cmb_stub_reg(&stub_cb); ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++#ifdef CONFIG_PM_WAKELOCKS ++ wakeup_source_init(&wmtWakeLock, "wmtFuncCtrl"); ++#else ++ wake_lock_init(&wmtWakeLock, WAKE_LOCK_SUSPEND, "wmtFuncCtrl"); ++#endif ++ mutex_init(&gOsSLock); ++#endif ++ ++#if CONSYS_BT_WIFI_SHARE_V33 ++ gBtWifiV33.counter = 0; ++ spin_lock_init(&gBtWifiV33.lock); ++#endif ++ ++ iret += mtk_wcn_consys_hw_init(); ++ ++ spin_lock_init(&gbgfIrqBle.lock); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_init); ++ ++INT32 wmt_plat_deinit(VOID) ++{ ++ INT32 iret = 0; ++ /* 2. unreg to cmb_stub */ ++ iret = mtk_wcn_cmb_stub_unreg(); ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wmt wakelock deinit\n",__FUNCTION__,__LINE__); ++ /*3. wmt wakelock deinit */ ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++#ifdef CONFIG_PM_WAKELOCKS ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wakeup_source_trash\n",__FUNCTION__,__LINE__); ++ wakeup_source_trash(&wmtWakeLock); ++#else ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling wake lock destroy %d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); ++//destroy calls wakeup_source_trash with &lock->ws ++printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock:%d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); ++printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock->ws: %d\n",__FUNCTION__,__LINE__,(int)&(wmtWakeLock.ws)); ++ wake_lock_destroy(&wmtWakeLock); ++#endif ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling mutex_destroy\n",__FUNCTION__,__LINE__); ++ mutex_destroy(&gOsSLock); ++ WMT_PLAT_DBG_FUNC("destroy wmtWakeLock\n"); ++#endif ++printk(KERN_ALERT "DEBUG: Passed %s %d now calling consys hw deinit\n",__FUNCTION__,__LINE__); ++ ++ iret += mtk_wcn_consys_hw_deinit(); ++ ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_deinit); ++ ++static INT32 wmt_plat_dump_pin_conf(VOID) ++{ ++ WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration start<=\n"); ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#ifdef GPIO_COMBO_BGF_EINT_PIN ++ WMT_PLAT_DBG_FUNC("BGF_EINT(GPIO%d)\n", GPIO_COMBO_BGF_EINT_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("BGF_EINT(not defined)\n"); ++#endif ++ ++#ifdef CUST_EINT_COMBO_BGF_NUM ++ WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(%d)\n", CUST_EINT_COMBO_BGF_NUM); ++#else ++ WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(not defined)\n"); ++#endif ++ ++#ifdef GPIO_COMBO_URXD_PIN ++ WMT_PLAT_DBG_FUNC("UART_RX(GPIO%d)\n", GPIO_COMBO_URXD_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("UART_RX(not defined)\n"); ++#endif ++#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) ++#ifdef GPIO_COMBO_I2S_CK_PIN ++ WMT_PLAT_DBG_FUNC("I2S_CK(GPIO%d)\n", GPIO_COMBO_I2S_CK_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_CK(not defined)\n"); ++#endif ++#ifdef GPIO_COMBO_I2S_WS_PIN ++ WMT_PLAT_DBG_FUNC("I2S_WS(GPIO%d)\n", GPIO_COMBO_I2S_WS_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_WS(not defined)\n"); ++#endif ++#ifdef GPIO_COMBO_I2S_DAT_PIN ++ WMT_PLAT_DBG_FUNC("I2S_DAT(GPIO%d)\n", GPIO_COMBO_I2S_DAT_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("I2S_DAT(not defined)\n"); ++#endif ++#else /* FM_ANALOG_INPUT || FM_ANALOG_OUTPUT */ ++ WMT_PLAT_DBG_FUNC("FM digital mode is not set, no need for I2S GPIOs\n"); ++#endif ++#ifdef GPIO_GPS_SYNC_PIN ++ WMT_PLAT_DBG_FUNC("GPS_SYNC(GPIO%d)\n", GPIO_GPS_SYNC_PIN); ++#else ++ WMT_PLAT_DBG_FUNC("GPS_SYNC(not defined)\n"); ++#endif ++ ++#ifdef GPIO_GPS_LNA_PIN ++ WMT_PLAT_INFO_FUNC("GPS_LNA(GPIO%d)\n", GPIO_GPS_LNA_PIN); ++#else ++ WMT_PLAT_INFO_FUNC("GPS_LNA(not defined)\n"); ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration emds<=\n"); ++ return 0; ++} ++ ++INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state) ++{ ++ INT32 ret = -1; ++ ++ switch (state) { ++ case FUNC_ON: ++ /* TODO:[ChangeFeature][George] always output this or by request throuth /proc or sysfs? */ ++ wmt_plat_dump_pin_conf(); ++ ret = mtk_wcn_consys_hw_pwr_on(gCoClockFlag); ++ break; ++ ++ case FUNC_OFF: ++ ret = mtk_wcn_consys_hw_pwr_off(); ++ break; ++ ++ case FUNC_RST: ++ ret = mtk_wcn_consys_hw_rst(gCoClockFlag); ++ break; ++ case FUNC_STAT: ++ ret = mtk_wcn_consys_hw_state_show(); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) in pwr_ctrl\n", state); ++ break; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(wmt_plat_pwr_ctrl); ++ ++INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) ++{ ++#ifdef CONFIG_OF ++ struct device_node *node; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++#endif ++ INT32 iret = -EINVAL; ++ static INT32 bgf_irq_num = -1; ++ static UINT32 bgf_irq_flag; ++ /* TODO: [ChangeFeature][GeorgeKuo]: use another function to handle this, as done in gpio_ctrls */ ++ ++ if ((PIN_STA_INIT != state) ++ && (PIN_STA_DEINIT != state) ++ && (PIN_STA_EINT_EN != state) ++ && (PIN_STA_EINT_DIS != state)) { ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:invalid PIN_STATE(%d) in eirq_ctrl for PIN(%d)\n", state, id); ++ return -1; ++ } ++ ++ switch (id) { ++ case PIN_BGF_EINT: ++ ++ if (PIN_STA_INIT == state) { ++#ifdef CONFIG_OF ++ node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); ++ if (node) { ++ bgf_irq_num = irq_of_parse_and_map(node, 0); ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ WMT_PLAT_ERR_FUNC("get irq flags from DTS fail!!\n"); ++ return iret; ++ } ++ bgf_irq_flag = irq_info[2]; ++ WMT_PLAT_INFO_FUNC("get irq id(%d) and irq trigger flag(%d) from DT\n", bgf_irq_num, ++ bgf_irq_flag); ++ } else { ++ WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); ++ return iret; ++ } ++#else ++ bgf_irq_num = MT_CONN2AP_BTIF_WAKEUP_IRQ_ID; ++ bgf_irq_flag = IRQF_TRIGGER_LOW; ++#endif ++ iret = request_irq(bgf_irq_num, wmt_plat_bgf_irq_isr, bgf_irq_flag, "BTIF_WAKEUP_IRQ", NULL); ++ if (iret) { ++ WMT_PLAT_ERR_FUNC("request_irq fail,irq_no(%d),iret(%d)\n", bgf_irq_num, iret); ++ return iret; ++ } ++ gbgfIrqBle.counter = 1; ++ ++ } else if (PIN_STA_EINT_EN == state) { ++ ++ spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ if (gbgfIrqBle.counter) { ++ WMT_PLAT_DBG_FUNC("BGF INT has been enabled,counter(%d)\n", gbgfIrqBle.counter); ++ } else { ++ enable_irq(bgf_irq_num); ++ gbgfIrqBle.counter++; ++ } ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (en)\n"); ++ spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ } else if (PIN_STA_EINT_DIS == state) { ++ spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ if (!gbgfIrqBle.counter) { ++ WMT_PLAT_INFO_FUNC("BGF INT has been disabled,counter(%d)\n", gbgfIrqBle.counter); ++ } else { ++ disable_irq_nosync(bgf_irq_num); ++ gbgfIrqBle.counter--; ++ } ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (dis)\n"); ++ spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); ++ } else { ++ free_irq(bgf_irq_num, NULL); ++ /* de-init: nothing to do in ALPS, such as un-registration... */ ++ } ++ iret = 0; ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:unsupported EIRQ(PIN_ID:%d) in eirq_ctrl\n", id); ++ iret = -1; ++ break; ++ } ++ ++ return iret; ++} ++EXPORT_SYMBOL(wmt_plat_eirq_ctrl); ++ ++INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) ++{ ++ if ((PIN_ID_MAX > id) ++ && (PIN_STA_MAX > state)) { ++ ++ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ ++ if (gfp_set_pin_table[id]) ++ return (*(gfp_set_pin_table[id])) (state); /* .handler */ ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: null fp for gpio_ctrl(%d)\n", id); ++ return -2; ++ } ++ return -1; ++} ++EXPORT_SYMBOL(wmt_plat_gpio_ctrl); ++ ++INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state) ++{ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++#ifdef GPIO_COMBO_BGF_EINT_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ /*set to gpio input low, pull down enable */ ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt init(in pd)\n"); ++ break; ++ ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_UP); ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_EINT); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt mux (eint)\n"); ++ break; ++ ++ case PIN_STA_IN_L: ++ case PIN_STA_DEINIT: ++ /*set to gpio input low, pull down enable */ ++ mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); ++ mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); ++ mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt deinit(in pd)\n"); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on BGF EINT\n", state); ++ break; ++ } ++#else ++ WMT_PLAT_INFO_FUNC("WMT-PLAT:BGF EINT not defined\n"); ++#endif ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state) ++{ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#ifdef GPIO_GPS_SYNC_PIN ++#ifndef GPIO_GPS_SYNC_PIN_M_GPS_SYNC ++#ifdef GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC ++#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC ++#else ++#ifdef GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC ++#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC ++#endif ++#endif ++#endif ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_GPS_SYNC_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_GPS_SYNC_PIN, GPIO_OUT_ZERO); ++ break; ++ ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPS_SYNC); ++ break; ++ ++ default: ++ break; ++ } ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++#if MTK_WCN_MT6306_IS_READY ++/* MT6306 GPIO7 is GPIO_GPS_LNA_EN, for K2 common phone pin modification */ ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) ++{ ++#ifdef GPIO_GPS_LNA_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin ctrl %d!\n", state); ++ mt6306_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ case PIN_STA_OUT_H: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin output high!\n"); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); ++ break; ++ case PIN_STA_OUT_L: ++ WMT_PLAT_ERR_FUNC("Gps LNA pin output low!\n"); ++ mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); ++ return 0; ++#endif ++} ++#else ++ ++static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) ++{ ++#if !defined(CONFIG_MTK_GPIO_LEGACY) ++ static struct pinctrl_state *gps_lna_init; ++ static struct pinctrl_state *gps_lna_oh; ++ static struct pinctrl_state *gps_lna_ol; ++ static struct pinctrl *consys_pinctrl; ++ ++ WMT_PLAT_DBG_FUNC("ENTER++\n"); ++ consys_pinctrl = mtk_wcn_consys_get_pinctrl(); ++ if (NULL == consys_pinctrl) { ++ WMT_PLAT_ERR_FUNC("get consys pinctrl fail\n"); ++ return -1; ++ } ++ ++ gps_lna_init = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_init"); ++ if (NULL == gps_lna_init) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin init state!\n"); ++ return -2; ++ } ++ ++ gps_lna_oh = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_oh"); ++ if (NULL == gps_lna_oh) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin oh state!\n"); ++ return -3; ++ } ++ ++ gps_lna_ol = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_ol"); ++ if (NULL == gps_lna_ol) { ++ WMT_PLAT_ERR_FUNC("Cannot find gps lna pin ol state!\n"); ++ return -4; ++ } ++ ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ pinctrl_select_state(consys_pinctrl, gps_lna_init); ++ WMT_PLAT_INFO_FUNC("set gps lna to init\n"); ++ break; ++ case PIN_STA_OUT_H: ++ pinctrl_select_state(consys_pinctrl, gps_lna_oh); ++ WMT_PLAT_INFO_FUNC("set gps lna to oh\n"); ++ break; ++ case PIN_STA_OUT_L: ++ pinctrl_select_state(consys_pinctrl, gps_lna_ol); ++ WMT_PLAT_INFO_FUNC("set gps lna to ol\n"); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++#ifdef GPIO_GPS_LNA_PIN ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_pull_enable(GPIO_GPS_LNA_PIN, GPIO_PULL_DISABLE); ++ mt_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_mode(GPIO_GPS_LNA_PIN, GPIO_GPS_LNA_PIN_M_GPIO); ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ case PIN_STA_OUT_H: ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); ++ break; ++ case PIN_STA_OUT_L: ++ mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); ++ break; ++ ++ default: ++ WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); ++ break; ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); ++ return 0; ++#endif ++#endif /* !defined(CONFIG_MTK_GPIO_LEGACY) */ ++} ++#endif ++ ++INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state) ++{ ++ /* TODO: [NewFeature][GeorgeKuo]: GPIO_I2Sx is changed according to different project. */ ++ /* TODO: provide a translation table in board_custom.h for different ALPS project customization. */ ++#if defined(CONFIG_MTK_GPIO_LEGACY) ++ ++#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) ++#if defined(GPIO_COMBO_I2S_CK_PIN) ++ switch (state) { ++ case PIN_STA_INIT: ++ case PIN_STA_MUX: ++ mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_I2S0_CK); ++ mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_I2S0_WS); ++ mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_I2S0_DAT); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S init (I2S0 system)\n"); ++ break; ++ case PIN_STA_IN_L: ++ case PIN_STA_DEINIT: ++ mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_CK_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_CK_PIN, GPIO_OUT_ZERO); ++ ++ mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_WS_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_WS_PIN, GPIO_OUT_ZERO); ++ ++ mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_GPIO); ++ mt_set_gpio_dir(GPIO_COMBO_I2S_DAT_PIN, GPIO_DIR_OUT); ++ mt_set_gpio_out(GPIO_COMBO_I2S_DAT_PIN, GPIO_OUT_ZERO); ++ WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S deinit (out 0)\n"); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on I2S Group\n", state); ++ break; ++ } ++#else ++ WMT_PLAT_ERR_FUNC("[MT6620]Error:FM digital mode set, but no I2S GPIOs defined\n"); ++#endif ++#else ++ WMT_PLAT_INFO_FUNC ++ ("[MT6620]warnning:FM digital mode is not set, no I2S GPIO settings should be modified by combo driver\n"); ++#endif ++ ++#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ ++#endif ++ return 0; ++} ++ ++INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId) ++{ ++#ifdef CFG_WMT_WAKELOCK_SUPPORT ++ static INT32 counter; ++ INT32 status; ++ INT32 ret = 0; ++ ++ ret = mutex_lock_killable(&gOsSLock); ++ if (ret) { ++ WMT_PLAT_ERR_FUNC("--->lock gOsSLock failed, ret=%d\n", ret); ++ return ret; ++ } ++ ++ if (WL_OP_GET == opId) ++ ++counter; ++ else if (WL_OP_PUT == opId) ++ --counter; ++ ++ mutex_unlock(&gOsSLock); ++ if (WL_OP_GET == opId && counter == 1) { ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_stay_awake(&wmtWakeLock); ++ status = wmtWakeLock.active; ++ #else ++ wake_lock(&wmtWakeLock); ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_lock(%d), counter(%d)\n", status, counter); ++ ++ } else if (WL_OP_PUT == opId && counter == 0) { ++ #ifdef CONFIG_PM_WAKELOCKS ++ __pm_relax(&wmtWakeLock); ++ status = wmtWakeLock.active; ++ #else ++ wake_unlock(&wmtWakeLock); ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_unlock(%d), counter(%d)\n", status, counter); ++ } else { ++ #ifdef CONFIG_PM_WAKELOCKS ++ status = wmtWakeLock.active; ++ #else ++ status = wake_lock_active(&wmtWakeLock); ++ #endif ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: wakelock status(%d), counter(%d)\n", status, counter); ++ } ++ return 0; ++#else ++ WMT_PLAT_WARN_FUNC("WMT-PLAT: host awake function is not supported.\n"); ++ return 0; ++ ++#endif ++} ++EXPORT_SYMBOL(wmt_plat_wake_lock_ctrl); ++ ++INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo) ++{ ++ INT32 iRet = 0; ++ ++ switch (ePt) { ++ ++ case BT_PALDO: ++ iRet = mtk_wcn_consys_hw_bt_paldo_ctrl(ePo); ++ break; ++ case WIFI_PALDO: ++ iRet = mtk_wcn_consys_hw_wifi_paldo_ctrl(ePo); ++ break; ++ case FM_PALDO: ++ case GPS_PALDO: ++ iRet = mtk_wcn_consys_hw_vcn28_ctrl(ePo); ++ break; ++ default: ++ WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid type(%d) in palod_ctrl\n", ePt); ++ break; ++ } ++ return iRet; ++} ++EXPORT_SYMBOL(wmt_plat_soc_paldo_ctrl); ++ ++UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset) ++{ ++ return mtk_wcn_consys_emi_virt_addr_get(offset); ++} ++EXPORT_SYMBOL(wmt_plat_get_emi_virt_add); ++ ++P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID) ++{ ++ return &mtk_wcn_emi_addr_info; ++} ++EXPORT_SYMBOL(wmt_plat_get_emi_phy_add); ++ ++#if CONSYS_ENALBE_SET_JTAG ++UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en) ++{ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_jtag_flag_ctrl); ++#endif ++ ++#if CFG_WMT_DUMP_INT_STATUS ++VOID wmt_plat_BGF_irq_dump_status(VOID) ++{ ++ WMT_PLAT_INFO_FUNC("this function is null in MT8127\n"); ++} ++EXPORT_SYMBOL(wmt_plat_BGF_irq_dump_status); ++ ++MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID) ++{ ++ return MTK_WCN_BOOL_FALSE; ++} ++EXPORT_SYMBOL(wmt_plat_dump_BGF_irq_status); ++#endif ++ ++UINT32 wmt_plat_read_cpupcr(void) ++{ ++ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); ++} ++EXPORT_SYMBOL(wmt_plat_read_cpupcr); ++ ++UINT32 wmt_plat_read_dmaregs(UINT32 type) ++{ ++ return 0; ++#if 0 ++ switch (type) { ++ case CONNSYS_CLK_GATE_STATUS: ++ return CONSYS_REG_READ(CONNSYS_CLK_GATE_STATUS_REG); ++ case CONSYS_EMI_STATUS: ++ return CONSYS_REG_READ(CONSYS_EMI_STATUS_REG); ++ case SYSRAM1: ++ return CONSYS_REG_READ(SYSRAM1_REG); ++ case SYSRAM2: ++ return CONSYS_REG_READ(SYSRAM2_REG); ++ case SYSRAM3: ++ return CONSYS_REG_READ(SYSRAM3_REG); ++ default: ++ return 0; ++ } ++#endif ++} ++ ++INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_STATE); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, state); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_set_host_dump_state); ++ ++UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ switch (type) { ++ case STP_FORCE_TRG_ASSERT_EMI: ++ ++ WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); ++ WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); ++ break; ++ case STP_FORCE_TRG_ASSERT_DEBUG_PIN: ++ ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + ++ CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); ++ WMT_PLAT_INFO_FUNC("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); ++ usleep_range(64, 96); ++ CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, ++ CONSYS_REG_READ(conn_reg.topckgen_base + ++ CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); ++ WMT_PLAT_INFO_FUNC("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", ++ CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); ++ ++ break; ++ default: ++ WMT_PLAT_ERR_FUNC("unknown force trigger assert type\n"); ++ break; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_force_trigger_assert); ++ ++INT32 wmt_plat_update_host_sync_num(VOID) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ UINT32 sync_num = 0; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_NUM); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ ++ sync_num = CONSYS_REG_READ(p_virtual_addr); ++ CONSYS_REG_WRITE(p_virtual_addr, sync_num + 1); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_update_host_sync_num); ++ ++INT32 wmt_plat_get_dump_info(UINT32 offset) ++{ ++ PUINT8 p_virtual_addr = NULL; ++ ++ p_virtual_addr = wmt_plat_get_emi_virt_add(offset); ++ if (!p_virtual_addr) { ++ WMT_PLAT_ERR_FUNC("get virtual address fail\n"); ++ return -1; ++ } ++ WMT_PLAT_INFO_FUNC("connsys_reg_read (0x%x), (0x%p), (0x%x)\n", CONSYS_REG_READ(p_virtual_addr), p_virtual_addr, ++ offset); ++ return CONSYS_REG_READ(p_virtual_addr); ++} ++EXPORT_SYMBOL(wmt_plat_get_dump_info); ++ ++UINT32 wmt_plat_get_soc_chipid(void) ++{ ++ UINT32 chipId = mtk_wcn_consys_soc_chipid(); ++ ++ WMT_PLAT_INFO_FUNC("current SOC chip:0x%x\n", chipId); ++ return chipId; ++} ++EXPORT_SYMBOL(wmt_plat_get_soc_chipid); ++ ++#if CFG_WMT_LTE_COEX_HANDLING ++INT32 wmt_plat_get_tdm_antsel_index(VOID) ++{ ++ WMT_PLAT_INFO_FUNC("not support LTE in this platform\n"); ++ return 0; ++} ++EXPORT_SYMBOL(wmt_plat_get_tdm_antsel_index); ++#endif ++INT32 wmt_plat_set_dbg_mode(UINT32 flag) ++{ ++ return -1; ++} ++VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf) ++{ ++ mtk_wcn_consys_set_dynamic_dump(buf); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/Makefile b/drivers/misc/mediatek/connectivity/wlan/Makefile +new file mode 100644 +index 000000000000..2961aeb073ea +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/Makefile +@@ -0,0 +1,8 @@ ++ifeq ($(CONFIG_MTK_COMBO_WIFI),y) ++ subdir-ccflags-y += -D MTK_WCN_BUILT_IN_DRIVER ++endif ++ ++ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) ++#$(warning include gen2) ++ obj-y += gen2/ ++endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile +new file mode 100644 +index 000000000000..b86ab49fce3a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile +@@ -0,0 +1,237 @@ ++# --------------------------------------------------- ++# Compile Options ++# --------------------------------------------------- ++ccflags-y += -DLINUX -DMT6628 ++ ++ccflags-y += -DCFG_SUPPORT_AGPS_ASSIST=1 ++ccflags-y += -DCFG_SUPPORT_TSF_USING_BOOTTIME=1 ++ccflags-y += -DCFG_P2P_LEGACY_COEX_REVISE=1 ++ccflags-y += -DARP_MONITER_ENABLE=1 ++ ++ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_WAPI=1 ++else ++ ccflags-y += -DCFG_SUPPORT_WAPI=0 ++endif ++ ++ifeq ($(CONFIG_MTK_WIFI_MCC_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_MCC=1 ++else ++ ccflags-y += -DCFG_SUPPORT_MCC=0 ++endif ++ ++ifeq ($(CONFIG_HAVE_XLOG_FEATURE), y) ++ ccflags-y += -DCFG_SUPPORT_XLOG=1 ++else ++ ccflags-y += -DCFG_SUPPORT_XLOG=0 ++endif ++ ++ifeq ($(CONFIG_MTK_AEE_FEATURE), y) ++ ccflags-y += -DCFG_SUPPORT_AEE=1 ++else ++ ccflags-y += -DCFG_SUPPORT_AEE=0 ++endif ++ ++#ifeq ($(CONFIG_MTK_COMBO_WIFI_HIF_SDIO1), y) ++# ccflags-y += -D_HIF_SDIO=1 ++#endif ++ ++ifeq ($(CONFIG_MTK_PASSPOINT_R1_SUPPORT), y) ++ ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=1 ++ ccflags-y += -DCFG_HS20_DEBUG=1 ++ ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=1 ++else ++ ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=0 ++ ccflags-y += -DCFG_HS20_DEBUG=0 ++ ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=0 ++endif ++ ++MTK_MET_PROFILING_SUPPORT = no ++ifeq ($(MTK_MET_PROFILING_SUPPORT), yes) ++ ccflags-y += -DCFG_SUPPORT_MET_PROFILING=1 ++else ++ ccflags-y += -DCFG_SUPPORT_MET_PROFILING=0 ++endif ++ ++ifeq ($(CONFIG_MTK_TC1_FEATURE), y) ++ifeq ($(CONFIG_MTK_GPT_SCHEME_SUPPORT), y) ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/gpt ++else ++ ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/pmt ++endif ++ ccflags-y += -DCFG_TC1_FEATURE=1 ++ ccflags-y += -DCFG_SUPPORT_CFG_FILE=1 ++else ++ ccflags-y += -DCFG_TC1_FEATURE=0 ++endif ++ ++MTK_SRAM_SIZE_OPTION=0 ++ifeq ($(CONFIG_ARCH_MT6755), y) ++ MTK_SRAM_SIZE_OPTION=2 ++endif ++ifeq ($(CONFIG_ARCH_MT6735), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6735M), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6753), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT6580), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ifeq ($(CONFIG_ARCH_MT8163), y) ++ MTK_SRAM_SIZE_OPTION=1 ++endif ++ccflags-y += -DCFG_SRAM_SIZE_OPTION=$(MTK_SRAM_SIZE_OPTION) ++ ++ifeq ($(strip $(TRUSTONIC_TEE_SUPPORT)),yes) ++ifeq ($(strip $(MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT)),yes) ++ ccflags-y += -DTRUSTONIC_TEE_SUPPORT ++ ccflags-y += -DMTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT ++endif ++endif ++ ++ccflags-y += -D_HIF_SDIO=1 ++ ++ccflags-y += -DDBG=0 ++ccflags-y += -I$(src)/os -I$(src)/os/linux/include -I$(src)/os/linux/hif/ahb/include ++ccflags-y += -I$(src)/include -I$(src)/include/nic -I$(src)/include/mgmt ++ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include ++ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/ ++ ++MODULE_NAME := wlan_gen2 ++obj-$(CONFIG_MTK_COMBO_WIFI) += $(MODULE_NAME).o ++#obj-m += $(MODULE_NAME).o if CONFIG_MTK_COMBO_WIFI=m ==> obj-m means ko module, not build in obj-y ++ ++# --------------------------------------------------- ++# Directory List ++# --------------------------------------------------- ++COMMON_DIR := common/ ++OS_DIR := os/linux/ ++HIF_DIR := os/linux/hif/ahb/ ++NIC_DIR := nic/ ++MGMT_DIR := mgmt/ ++DMA_DIR := ../../../../platform/$(call lc,$(MTK_PLATFORM))/kernel/drivers/wifi/ ++PLAT_DIR := os/linux/plat/$(MTK_PLATFORM)/ ++HIF_AHB_PDMA := $(HIF_DIR)$(MTK_PLATFORM)/ ++#$(call lc,$(MTK_PLATFORM)) ++ ++ ++# --------------------------------------------------- ++# Objects List ++# --------------------------------------------------- ++ ++COMMON_OBJS := $(COMMON_DIR)dump.o \ ++ $(COMMON_DIR)wlan_lib.o \ ++ $(COMMON_DIR)wlan_oid.o \ ++ $(COMMON_DIR)wlan_bow.o \ ++ $(COMMON_DIR)debug.o ++ ++NIC_OBJS := $(NIC_DIR)nic.o \ ++ $(NIC_DIR)nic_tx.o \ ++ $(NIC_DIR)nic_rx.o \ ++ $(NIC_DIR)nic_pwr_mgt.o \ ++ $(NIC_DIR)cmd_buf.o \ ++ $(NIC_DIR)que_mgt.o \ ++ $(NIC_DIR)nic_cmd_event.o ++ ++OS_OBJS := $(OS_DIR)gl_init.o \ ++ $(OS_DIR)gl_kal.o \ ++ $(OS_DIR)gl_bow.o \ ++ $(OS_DIR)gl_wext.o \ ++ $(OS_DIR)gl_wext_priv.o \ ++ $(OS_DIR)gl_rst.o \ ++ $(OS_DIR)gl_cfg80211.o \ ++ $(OS_DIR)gl_vendor.o \ ++ $(OS_DIR)platform.o \ ++ $(OS_DIR)gl_proc.o ++ ++MGMT_OBJS := $(MGMT_DIR)ais_fsm.o \ ++ $(MGMT_DIR)aaa_fsm.o \ ++ $(MGMT_DIR)assoc.o \ ++ $(MGMT_DIR)auth.o \ ++ $(MGMT_DIR)bss.o \ ++ $(MGMT_DIR)cnm.o \ ++ $(MGMT_DIR)cnm_timer.o \ ++ $(MGMT_DIR)cnm_mem.o \ ++ $(MGMT_DIR)hem_mbox.o \ ++ $(MGMT_DIR)mib.o \ ++ $(MGMT_DIR)privacy.o \ ++ $(MGMT_DIR)rate.o \ ++ $(MGMT_DIR)rlm.o \ ++ $(MGMT_DIR)rlm_domain.o \ ++ $(MGMT_DIR)rlm_obss.o \ ++ $(MGMT_DIR)rlm_protection.o \ ++ $(MGMT_DIR)rsn.o \ ++ $(MGMT_DIR)saa_fsm.o \ ++ $(MGMT_DIR)scan.o \ ++ $(MGMT_DIR)scan_fsm.o \ ++ $(MGMT_DIR)sec_fsm.o \ ++ $(MGMT_DIR)swcr.o \ ++ $(MGMT_DIR)swcr.o \ ++ $(MGMT_DIR)roaming_fsm.o \ ++ $(MGMT_DIR)hs20.o ++ ++# --------------------------------------------------- ++# TDLS Objects List ++# --------------------------------------------------- ++MGMT_OBJS += $(MGMT_DIR)tdls.o \ ++ $(MGMT_DIR)tdls_com.o ++ ++# --------------------------------------------------- ++# STATS Objects List ++# --------------------------------------------------- ++MGMT_OBJS += $(MGMT_DIR)stats.o ++ ++# --------------------------------------------------- ++# P2P Objects List ++# --------------------------------------------------- ++ ++COMMON_OBJS += $(COMMON_DIR)wlan_p2p.o ++ ++NIC_OBJS += $(NIC_DIR)p2p_nic.o ++ ++OS_OBJS += $(OS_DIR)gl_p2p.o \ ++ $(OS_DIR)gl_p2p_cfg80211.o \ ++ $(OS_DIR)gl_p2p_init.o \ ++ $(OS_DIR)gl_p2p_kal.o ++ ++MGMT_OBJS += $(MGMT_DIR)p2p_assoc.o \ ++ $(MGMT_DIR)p2p_bss.o \ ++ $(MGMT_DIR)p2p_fsm.o \ ++ $(MGMT_DIR)p2p_func.o \ ++ $(MGMT_DIR)p2p_rlm.o \ ++ $(MGMT_DIR)p2p_rlm_obss.o \ ++ $(MGMT_DIR)p2p_scan.o \ ++ $(MGMT_DIR)p2p_ie.o \ ++ $(MGMT_DIR)p2p_state.o ++ ++ ++ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) ++MGMT_OBJS += $(MGMT_DIR)wapi.o ++endif ++ ++ifeq ($(WLAN_PROC), y) ++OS_OBJS += gl_proc.o ++endif ++ ++#$(warning $(CONFIG_MACH_MT7623)) ++ ++ifeq ($(CONFIG_MACH_MT7623), y) ++HIF_AHB_PDMA = $(HIF_DIR)mt8127/ ++endif ++HIF_OBJS := $(HIF_DIR)arm.o \ ++ $(HIF_DIR)ahb.o \ ++ $(HIF_AHB_PDMA)ahb_pdma.o ++ifeq ($(CONFIG_ARCH_MT6755), y) ++PLAT_OBJS := $(PLAT_DIR)plat_priv.o ++$(MODULE_NAME)-objs += $(PLAT_OBJS) ++endif ++$(MODULE_NAME)-objs += $(COMMON_OBJS) ++$(MODULE_NAME)-objs += $(NIC_OBJS) ++$(MODULE_NAME)-objs += $(OS_OBJS) ++$(MODULE_NAME)-objs += $(HIF_OBJS) ++$(MODULE_NAME)-objs += $(MGMT_OBJS) ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c +new file mode 100644 +index 000000000000..e31e0b86d231 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c +@@ -0,0 +1,165 @@ ++#include "precomp.h" ++#include "gl_kal.h" ++ ++struct COMMAND { ++ UINT_8 ucCID; ++ BOOLEAN fgSetQuery; ++ BOOLEAN fgNeedResp; ++ UINT_8 ucCmdSeqNum; ++}; ++ ++struct SECURITY_FRAME { ++ UINT_16 u2EthType; ++ UINT_16 u2Reserved; ++}; ++ ++struct MGMT_FRAME { ++ UINT_16 u2FrameCtl; ++ UINT_16 u2DurationID; ++}; ++ ++struct TC_RES_RELEASE_ENTRY { ++ UINT_64 u8RelaseTime; ++ UINT_32 u4RelCID; ++ UINT_8 ucTc4RelCnt; ++ UINT_8 ucAvailableTc4; ++}; ++ ++struct CMD_TRACE_ENTRY { ++ UINT_64 u8TxTime; ++ COMMAND_TYPE eCmdType; ++ union { ++ struct COMMAND rCmd; ++ struct SECURITY_FRAME rSecFrame; ++ struct MGMT_FRAME rMgmtFrame; ++ } u; ++}; ++ ++#define TC_RELEASE_TRACE_BUF_MAX_NUM 100 ++#define TXED_CMD_TRACE_BUF_MAX_NUM 100 ++ ++static struct TC_RES_RELEASE_ENTRY *gprTcReleaseTraceBuffer; ++static struct CMD_TRACE_ENTRY *gprCmdTraceEntry; ++VOID wlanDebugInit(VOID) ++{ ++ /* debug for command/tc4 resource begin */ ++ gprTcReleaseTraceBuffer = ++ kalMemAlloc(TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY), PHY_MEM_TYPE); ++ kalMemZero(gprTcReleaseTraceBuffer, TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); ++ gprCmdTraceEntry = kalMemAlloc(TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY), PHY_MEM_TYPE); ++ kalMemZero(gprCmdTraceEntry, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); ++ /* debug for command/tc4 resource end */ ++} ++ ++VOID wlanDebugUninit(VOID) ++{ ++ /* debug for command/tc4 resource begin */ ++ kalMemFree(gprTcReleaseTraceBuffer, PHY_MEM_TYPE, ++ TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); ++ kalMemFree(gprCmdTraceEntry, PHY_MEM_TYPE, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); ++ /* debug for command/tc4 resource end */ ++} ++ ++VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd) ++{ ++ static UINT_16 u2CurEntry; ++ struct CMD_TRACE_ENTRY *prCurCmd = &gprCmdTraceEntry[u2CurEntry]; ++ ++ prCurCmd->u8TxTime = sched_clock(); ++ prCurCmd->eCmdType = prCmd->eCmdType; ++ if (prCmd->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ P_WLAN_MAC_MGMT_HEADER_T prMgmt = (P_WLAN_MAC_MGMT_HEADER_T)((P_MSDU_INFO_T)prCmd->prPacket)->prPacket; ++ ++ prCurCmd->u.rMgmtFrame.u2FrameCtl = prMgmt->u2FrameCtrl; ++ prCurCmd->u.rMgmtFrame.u2DurationID = prMgmt->u2Duration; ++ } else if (prCmd->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ PUINT_8 pucPkt = (PUINT_8)((struct sk_buff *)prCmd->prPacket)->data; ++ ++ prCurCmd->u.rSecFrame.u2EthType = ++ (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ } else { ++ prCurCmd->u.rCmd.ucCID = prCmd->ucCID; ++ prCurCmd->u.rCmd.ucCmdSeqNum = prCmd->ucCmdSeqNum; ++ prCurCmd->u.rCmd.fgNeedResp = prCmd->fgNeedResp; ++ prCurCmd->u.rCmd.fgSetQuery = prCmd->fgSetQuery; ++ } ++ u2CurEntry++; ++ if (u2CurEntry == TC_RELEASE_TRACE_BUF_MAX_NUM) ++ u2CurEntry = 0; ++} ++ ++VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable) ++{ ++ static UINT_16 u2CurEntry; ++ struct TC_RES_RELEASE_ENTRY *prCurBuf = &gprTcReleaseTraceBuffer[u2CurEntry]; ++ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &prCurBuf->u4RelCID); ++ prCurBuf->u8RelaseTime = sched_clock(); ++ prCurBuf->ucTc4RelCnt = aucTxRlsCnt[TC4_INDEX]; ++ prCurBuf->ucAvailableTc4 = ucAvailable; ++ u2CurEntry++; ++ if (u2CurEntry == TXED_CMD_TRACE_BUF_MAX_NUM) ++ u2CurEntry = 0; ++} ++ ++VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen) ++{ ++ UINT_16 i = 0; ++ struct CMD_TRACE_ENTRY *prCmd = gprCmdTraceEntry; ++ struct TC_RES_RELEASE_ENTRY *prTcRel = gprTcReleaseTraceBuffer; ++ ++ if (pucBuf) { ++ int bufLen = 0; ++ ++ for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/2; i++) { ++ bufLen = snprintf(pucBuf, maxLen, ++ "%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", ++ i*2, prCmd[i*2].u8TxTime, prCmd[i*2].eCmdType, *(PUINT_32)(&prCmd[i*2].u.rCmd.ucCID), ++ i*2+1, prCmd[i*2+1].u8TxTime, prCmd[i*2+1].eCmdType, ++ *(PUINT_32)(&prCmd[i*2+1].u.rCmd.ucCID)); ++ if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) ++ break; ++ pucBuf += bufLen; ++ maxLen -= bufLen; ++ } ++ for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/2; i++) { ++ bufLen = snprintf(pucBuf, maxLen, ++ "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d CID %08x\n", ++ i*2, prTcRel[i*2].u8RelaseTime, prTcRel[i*2].ucTc4RelCnt, prTcRel[i*2].ucAvailableTc4, ++ prTcRel[i*2].u4RelCID, ++ i*2+1, prTcRel[i*2+1].u8RelaseTime, prTcRel[i*2+1].ucTc4RelCnt, ++ prTcRel[i*2+1].ucAvailableTc4, prTcRel[i*2+1].u4RelCID); ++ if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) ++ break; ++ pucBuf += bufLen; ++ maxLen -= bufLen; ++ } ++ return; ++ } ++ for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/4; i++) { ++ LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x; ", ++ i*4, prCmd[i*4].u8TxTime, prCmd[i*4].eCmdType, ++ *(PUINT_32)(&prCmd[i*4].u.rCmd.ucCID), ++ i*4+1, prCmd[i*4+1].u8TxTime, prCmd[i*4+1].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+1].u.rCmd.ucCID)); ++ LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", ++ i*4+2, prCmd[i*4+2].u8TxTime, prCmd[i*4+2].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+2].u.rCmd.ucCID), ++ i*4+3, prCmd[i*4+3].u8TxTime, prCmd[i*4+3].eCmdType, ++ *(PUINT_32)(&prCmd[i*4+3].u.rCmd.ucCID)); ++ } ++ for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/4; i++) { ++ LOG_FUNC( ++ "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x;", ++ i*4, prTcRel[i*4].u8RelaseTime, prTcRel[i*4].ucTc4RelCnt, ++ prTcRel[i*4].ucAvailableTc4, prTcRel[i*4].u4RelCID, ++ i*4+1, prTcRel[i*4+1].u8RelaseTime, prTcRel[i*4+1].ucTc4RelCnt, ++ prTcRel[i*4+1].ucAvailableTc4, prTcRel[i*4+1].u4RelCID); ++ LOG_FUNC( ++ " %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x\n", ++ i*4+2, prTcRel[i*4+2].u8RelaseTime, prTcRel[i*4+2].ucTc4RelCnt, ++ prTcRel[i*4+2].ucAvailableTc4, prTcRel[i*4+2].u4RelCID, ++ i*4+3, prTcRel[i*4+3].u8RelaseTime, prTcRel[i*4+3].ucTc4RelCnt, ++ prTcRel[i*4+3].ucAvailableTc4, prTcRel[i*4+3].u4RelCID); ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c +new file mode 100644 +index 000000000000..486ba239f16a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c +@@ -0,0 +1,345 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/dump.c#1 ++*/ ++ ++/*! \file "dump.c" ++ \brief Provide memory dump function for debugging. ++ ++ Provide memory dump function for debugging. ++*/ ++ ++/* ++** Log: dump.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 19:58:51 GMT mtk01426 ++** Init develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump a segment of memory in bytes. ++* ++* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. ++* \param[in] u4Length Length of the memory to be dumped. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length) ++{ ++ ASSERT(pucStartAddr); ++ ++ LOG_FUNC("DUMP8 ADDRESS: %p, Length: %u\n", pucStartAddr, u4Length); ++ ++ while (u4Length > 0) { ++ if (u4Length >= 16) { ++ LOG_FUNC( ++ "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], pucStartAddr[8], ++ pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], pucStartAddr[12], pucStartAddr[13], ++ pucStartAddr[14], pucStartAddr[15]); ++ u4Length -= 16; ++ pucStartAddr += 16; ++ } else { ++ switch (u4Length) { ++ case 1: ++ LOG_FUNC("(%p) %02x\n", pucStartAddr, pucStartAddr[0]); ++ break; ++ case 2: ++ LOG_FUNC("(%p) %02x %02x\n", pucStartAddr, pucStartAddr[0], pucStartAddr[1]); ++ break; ++ case 3: ++ LOG_FUNC("(%p) %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2]); ++ break; ++ case 4: ++ LOG_FUNC("(%p) %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3]); ++ break; ++ case 5: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4]); ++ break; ++ case 6: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5]); ++ break; ++ case 7: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6]); ++ break; ++ case 8: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7]); ++ break; ++ case 9: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8]); ++ break; ++ case 10: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9]); ++ break; ++ case 11: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10]); ++ break; ++ case 12: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11]); ++ break; ++ case 13: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", ++ pucStartAddr, ++ pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12]); ++ break; ++ case 14: ++ LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12], pucStartAddr[13]); ++ break; ++ case 15: ++ LOG_FUNC( ++ "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", ++ pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], ++ pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], ++ pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], ++ pucStartAddr[12], pucStartAddr[13], pucStartAddr[14]); ++ break; ++ /* ++ default: ++ break; ++ */ ++ } ++ u4Length = 0; ++ } ++ } ++ ++ LOG_FUNC("\n"); ++ ++} /* end of dumpMemory8() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump a segment of memory in double words. ++* ++* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. ++* \param[in] u4Length Length of the memory to be dumped. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length) ++{ ++ PUINT_8 pucAddr; ++ ++ ASSERT(pu4StartAddr); ++ ++ LOG_FUNC("DUMP32 ADDRESS: %p, Length: %u\n", pu4StartAddr, u4Length); ++ ++ if (IS_NOT_ALIGN_4((ULONG) pu4StartAddr)) { ++ UINT_32 u4ProtrudeLen = sizeof(UINT_32) - ((ULONG) pu4StartAddr % 4); ++ ++ u4ProtrudeLen = ((u4Length < u4ProtrudeLen) ? u4Length : u4ProtrudeLen); ++ LOG_FUNC("pu4StartAddr is not at DW boundary.\n"); ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ ++ switch (u4ProtrudeLen) { ++ case 1: ++ LOG_FUNC("(%p) %02x------\n", pu4StartAddr, pucAddr[0]); ++ break; ++ case 2: ++ LOG_FUNC("(%p) %02x%02x----\n", pu4StartAddr, pucAddr[1], pucAddr[0]); ++ break; ++ case 3: ++ LOG_FUNC("(%p) %02x%02x%02x--\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ default: ++ break; ++ } ++ ++ u4Length -= u4ProtrudeLen; ++ pu4StartAddr = (PUINT_32) ((ULONG) pu4StartAddr + u4ProtrudeLen); ++ } ++ ++ while (u4Length > 0) { ++ if (u4Length >= 16) { ++ LOG_FUNC("(%p) %08x %08x %08x %08x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pu4StartAddr[3]); ++ pu4StartAddr += 4; ++ u4Length -= 16; ++ } else { ++ switch (u4Length) { ++ case 1: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) ------%02x\n", pu4StartAddr, pucAddr[0]); ++ break; ++ case 2: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) ----%02x%02x\n", pu4StartAddr, pucAddr[1], pucAddr[0]); ++ break; ++ case 3: ++ pucAddr = (PUINT_8) &pu4StartAddr[0]; ++ LOG_FUNC("(%p) --%02x%02x%02x\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 4: ++ LOG_FUNC("(%p) %08x\n", pu4StartAddr, pu4StartAddr[0]); ++ break; ++ case 5: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x ------%02x\n", pu4StartAddr, pu4StartAddr[0], pucAddr[0]); ++ break; ++ case 6: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x ----%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pucAddr[1], pucAddr[0]); ++ break; ++ case 7: ++ pucAddr = (PUINT_8) &pu4StartAddr[1]; ++ LOG_FUNC("(%p) %08x --%02x%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 8: ++ LOG_FUNC("(%p) %08x %08x\n", pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1]); ++ break; ++ case 9: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x ------%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[0]); ++ break; ++ case 10: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x ----%02x%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[1], pucAddr[0]); ++ break; ++ case 11: ++ pucAddr = (PUINT_8) &pu4StartAddr[2]; ++ LOG_FUNC("(%p) %08x %08x --%02x%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 12: ++ LOG_FUNC("(%p) %08x %08x %08x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2]); ++ break; ++ case 13: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x ------%02x\n", ++ pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[0]); ++ break; ++ case 14: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x ----%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ case 15: ++ pucAddr = (PUINT_8) &pu4StartAddr[3]; ++ LOG_FUNC("(%p) %08x %08x %08x --%02x%02x%02x\n", ++ pu4StartAddr, ++ pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], ++ pucAddr[2], pucAddr[1], pucAddr[0]); ++ break; ++ /* ++ default: ++ break; ++ */ ++ } ++ u4Length = 0; ++ } ++ } ++ ++} /* end of dumpMemory32() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c +new file mode 100644 +index 000000000000..21bd849827e1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c +@@ -0,0 +1,3442 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_bow.c#1 ++*/ ++ ++/*! \file wlan_bow.c ++ \brief This file contains the 802.11 PAL commands processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_bow.c ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 01 09 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00110632] [Rose][LCA42][Cross Feature][Bluetooth]The "KE" pops up after the device reboots automatically.(once) ++ * ++ * Fix bow link disconnected event dereference. ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 07 06 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Improve BoW connection establishment speed. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 21 2011 terry.wu ++ * NULL ++ * Fix BoW KE. ++ * ++ * 06 20 2011 terry.wu ++ * NULL ++ * Add BoW Rate Limitation. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 07 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * aware more compile options. ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 23 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add some BoW error handling. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * . ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Only reply probe response to its peer or mached SSID for BoW AP. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW SAA retry and disable disconnect event when AAA fail . ++ * ++ * 05 21 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Protect BoW connection establishment. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting ++ * Send deauth while disconnecting BoW link. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix wrong StaRec state of BoW . ++ * ++ * 05 06 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix BoW Multiple Physical Link connect/disconnect issue. ++ * ++ * 05 03 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix prAssocRspSwRfb casting. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 12 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add WMM IE for BOW initiator data. ++ * ++ * 04 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 28 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Simplify link disconnected routine, remove link disconnected other routine. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add new feature - multiple physical link support. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000486] [MT6620 Wi-Fi][BOW] Fixed the bow send frame but not encrypted issue ++ * fixed the BOW packet sending without encrypted issue. ++ * ++ * 02 21 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BOW link disconnection bug. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting. ++ * ++ * 02 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW channel granted function. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW Activity Report structure and bug fix. ++ * ++ * 01 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW to support multiple physical link. ++ * ++ * 12 08 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support concurrent networks. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 11 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BoW timer assert issue. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix for event returnning Band. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix wrong BoW event size. ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 chinghwa.yu ++ * NULL ++ * Fix bowResponderScanDone error when prBssDesc is NULL. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 09 14 2010 cp.wu ++ * NULL ++ * indicate correct AIS network information for PAL. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Initialize nicActivateNetwork(prAdapter as soon as bow is starting.. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * 2) command sequence number is now increased atomically ++ * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++static UINT_32 g_u4LinkCount; ++static UINT_32 g_u4Beaconing; ++static BOW_TABLE_T arBowTable[CFG_BOW_PHYSICAL_LINK_NUM]; ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++const BOW_CMD_T arBowCmdTable[] = { ++ {BOW_CMD_ID_GET_MAC_STATUS, bowCmdGetMacStatus}, ++ {BOW_CMD_ID_SETUP_CONNECTION, bowCmdSetupConnection}, ++ {BOW_CMD_ID_DESTROY_CONNECTION, bowCmdDestroyConnection}, ++ {BOW_CMD_ID_SET_PTK, bowCmdSetPTK}, ++ {BOW_CMD_ID_READ_RSSI, bowCmdReadRSSI}, ++ {BOW_CMD_ID_READ_LINK_QUALITY, bowCmdReadLinkQuality}, ++ {BOW_CMD_ID_SHORT_RANGE_MODE, bowCmdShortRangeMode}, ++ {BOW_CMD_ID_GET_CHANNEL_LIST, bowCmdGetChannelList}, ++}; ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCID, ++ IN BOOLEAN fgSetQuery, ++ IN BOOLEAN fgNeedResp, ++ IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ IN UINT_32 u4SetQueryInfoLen, IN PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_BOW_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ prCmdInfo->u4PrivateData = (UINT_32) ucSeqNumber; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dispatch command coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ WLAN_STATUS retval = WLAN_STATUS_FAILURE; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < sizeof(arBowCmdTable) / sizeof(BOW_CMD_T); i++) { ++ if ((arBowCmdTable[i].uCmdID == prCmd->rHeader.ucCommandId) && arBowCmdTable[i].pfCmdHandle) { ++ retval = arBowCmdTable[i].pfCmdHandle(prAdapter, prCmd); ++ break; ++ } ++ } ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_GET_MAC_STATUS ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_MAC_STATUS prMacStatus; ++ UINT_8 idx = 0; ++ UINT_8 ucPrimaryChannel; ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eBssSCO; ++ UINT_8 ucNumOfChannel = 0; /* MAX_BOW_NUMBER_OF_CHANNEL; */ ++ ++ RF_CHANNEL_INFO_T aucChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; ++ ++ ASSERT(prAdapter); ++ ++ /* 3 <1> If LinkCount != 0 -> OK (optional) */ ++ ++ eBand = BAND_2G4; ++ eBssSCO = CHNL_EXT_SCN; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return WLAN_STATUS_FAILURE; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_MAC_STATUS; ++ prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_MAC_STATUS); ++ ++ /* fill event body */ ++ prMacStatus = (P_BOW_MAC_STATUS) (prEvent->aucPayload); ++ kalMemZero(prMacStatus, sizeof(BOW_MAC_STATUS)); ++ ++ /* 3 <2> Call CNM to decide if BOW available. */ ++ if (cnmBowIsPermitted(prAdapter)) ++ prMacStatus->ucAvailability = TRUE; ++ else ++ prMacStatus->ucAvailability = FALSE; ++ ++ memcpy(prMacStatus->aucMacAddr, prAdapter->rWifiVar.aucDeviceAddress, PARAM_MAC_ADDR_LEN); ++ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucPrimaryChannel, &eBssSCO)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "bowCmdGetMacStatus, Get preferred channel.\n"); ++#endif ++ ++ prMacStatus->ucNumOfChannel = 1; ++ prMacStatus->arChannelList[0].ucChannelBand = eBand; ++ prMacStatus->arChannelList[0].ucChannelNum = ucPrimaryChannel; ++ } else { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, ++ "bowCmdGetMacStatus, Get channel list. Current number of channel, %d.\n", ucNumOfChannel); ++#endif ++ ++ rlmDomainGetChnlList(prAdapter, BAND_2G4, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_2G4, ++ &ucNumOfChannel, aucChannelList); ++ ++ if (ucNumOfChannel > 0) { ++ for (idx = 0; idx < ucNumOfChannel; idx++) { ++ prMacStatus->arChannelList[idx].ucChannelBand = aucChannelList[idx].eBand; ++ prMacStatus->arChannelList[idx].ucChannelNum = aucChannelList[idx].ucChannelNum; ++ } ++ ++ prMacStatus->ucNumOfChannel = ucNumOfChannel; ++ } ++ ++ rlmDomainGetChnlList(prAdapter, BAND_5G, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_5G, ++ &ucNumOfChannel, aucChannelList); ++ ++ if (ucNumOfChannel > 0) { ++ for (idx = 0; idx < ucNumOfChannel; idx++) { ++ prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelBand = ++ aucChannelList[idx].eBand; ++ prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelNum = ++ aucChannelList[idx].ucChannelNum; ++ } ++ ++ prMacStatus->ucNumOfChannel = prMacStatus->ucNumOfChannel + ucNumOfChannel; ++ ++ } ++ } ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, ++ "ucNumOfChannel,eBand,aucChannelList,%x,%x,%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ ucNumOfChannel, aucChannelList[0].eBand, aucChannelList[0].ucChannelNum, aucChannelList[1].ucChannelNum, ++ aucChannelList[2].ucChannelNum, aucChannelList[3].ucChannelNum, aucChannelList[4].ucChannelNum, ++ aucChannelList[5].ucChannelNum, aucChannelList[6].ucChannelNum, aucChannelList[7].ucChannelNum, ++ aucChannelList[8].ucChannelNum, aucChannelList[9].ucChannelNum, aucChannelList[10].ucChannelNum, ++ aucChannelList[11].ucChannelNum, aucChannelList[12].ucChannelNum, aucChannelList[13].ucChannelNum, ++ aucChannelList[14].ucChannelNum, aucChannelList[15].ucChannelNum, aucChannelList[16].ucChannelNum, ++ aucChannelList[17].ucChannelNum)); ++ ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->ucNumOfChannel, eBand, %x, %x.\n", ++ prMacStatus->ucNumOfChannel, prMacStatus->arChannelList[0].ucChannelBand); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ prMacStatus->arChannelList[0].ucChannelNum, prMacStatus->arChannelList[1].ucChannelNum, ++ prMacStatus->arChannelList[2].ucChannelNum, prMacStatus->arChannelList[3].ucChannelNum, ++ prMacStatus->arChannelList[4].ucChannelNum, prMacStatus->arChannelList[5].ucChannelNum, ++ prMacStatus->arChannelList[6].ucChannelNum, prMacStatus->arChannelList[7].ucChannelNum, ++ prMacStatus->arChannelList[8].ucChannelNum, prMacStatus->arChannelList[9].ucChannelNum, ++ prMacStatus->arChannelList[10].ucChannelNum, prMacStatus->arChannelList[11].ucChannelNum, ++ prMacStatus->arChannelList[12].ucChannelNum, prMacStatus->arChannelList[13].ucChannelNum, ++ prMacStatus->arChannelList[14].ucChannelNum, prMacStatus->arChannelList[15].ucChannelNum, ++ prMacStatus->arChannelList[16].ucChannelNum, prMacStatus->arChannelList[17].ucChannelNum)); ++ ++ DBGLOG(BOW, TRACE, "prMacStatus->ucNumOfChannel, %x.\n", prMacStatus->ucNumOfChannel); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList[0].ucChannelBand, %x.\n", prMacStatus->arChannelList[0].ucChannelBand); ++ DBGLOG(BOW, TRACE, ++ "prMacStatus->arChannelList[0].ucChannelNum, %x.\n", prMacStatus->arChannelList[0].ucChannelNum); ++ DBGLOG(BOW, TRACE, "prMacStatus->ucAvailability, %x.\n", prMacStatus->ucAvailability); ++ DBGLOG(BOW, TRACE, "prMacStatus->aucMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prMacStatus->aucMacAddr[0], ++ prMacStatus->aucMacAddr[1], ++ prMacStatus->aucMacAddr[2], ++ prMacStatus->aucMacAddr[3], prMacStatus->aucMacAddr[4], prMacStatus->aucMacAddr[5])); ++#endif ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS))); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SETUP_CONNECTION ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SETUP_CONNECTION prBowSetupConnection; ++ CMD_BT_OVER_WIFI rCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ BOW_TABLE_T rBowTable; ++ ++ UINT_8 ucBowTableIdx = 0; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowSetupConnection = (P_BOW_SETUP_CONNECTION) &(prCmd->aucPayload[0]); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SETUP_CONNECTION)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* 3 <1> If ucLinkCount >= 4 -> Fail. */ ++ if (g_u4LinkCount >= CFG_BOW_PHYSICAL_LINK_NUM) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* 3 <2> Call CNM, check if BOW is available. */ ++ if (!cnmBowIsPermitted(prAdapter)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* 3 <3> Lookup BOW Table, if Peer MAC address exist and valid -> Fail. */ ++ if (bowCheckBowTableIfVaild(prAdapter, prBowSetupConnection->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (EQUAL_MAC_ADDR(prBowSetupConnection->aucPeerAddress, prAdapter->rWifiVar.aucDeviceAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* fill CMD_BT_OVER_WIFI */ ++ rCmdBtOverWifi.ucAction = BOW_SETUP_CMD; ++ rCmdBtOverWifi.ucChannelNum = prBowSetupConnection->ucChannelNum; ++ COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowSetupConnection->aucPeerAddress); ++ rCmdBtOverWifi.u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; ++ rCmdBtOverWifi.ucTimeoutDiscovery = prBowSetupConnection->ucTimeoutDiscovery; ++ rCmdBtOverWifi.ucTimeoutInactivity = prBowSetupConnection->ucTimeoutInactivity; ++ rCmdBtOverWifi.ucRole = prBowSetupConnection->ucRole; ++ rCmdBtOverWifi.PAL_Capabilities = prBowSetupConnection->ucPAL_Capabilities; ++ rCmdBtOverWifi.cMaxTxPower = prBowSetupConnection->cMaxTxPower; ++ ++ if (prBowSetupConnection->ucChannelNum > 14) ++ rCmdBtOverWifi.ucChannelBand = BAND_5G; ++ else ++ rCmdBtOverWifi.ucChannelBand = BAND_2G4; ++ ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowSetupConnection->aucPeerAddress); ++ ++#if CFG_BOW_PHYSICAL_LINK_NUM > 1 ++ /*Channel check for supporting multiple physical link */ ++ if (g_u4LinkCount > 0) { ++ if (prBowSetupConnection->ucChannelNum != prBowFsmInfo->ucPrimaryChannel) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ } ++#endif ++ ++ prBowFsmInfo->ucPrimaryChannel = prBowSetupConnection->ucChannelNum; ++ prBowFsmInfo->eBand = rCmdBtOverWifi.ucChannelBand; ++ prBowFsmInfo->u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; ++ prBowFsmInfo->ucRole = prBowSetupConnection->ucRole; ++ ++ if (prBowSetupConnection->ucPAL_Capabilities > 0) ++ prBowFsmInfo->fgSupportQoS = TRUE; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdSetupConnection.\n"); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Channel Number - 0x%x.\n", rCmdBtOverWifi.ucChannelNum); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Peer address - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], ++ rCmdBtOverWifi.rPeerAddr[1], ++ rCmdBtOverWifi.rPeerAddr[2], ++ rCmdBtOverWifi.rPeerAddr[3], rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Beacon interval - 0x%x.\n", rCmdBtOverWifi.u2BeaconInterval); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout activity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutDiscovery); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout inactivity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutInactivity); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Role - 0x%x.\n", rCmdBtOverWifi.ucRole); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi PAL capability - 0x%x.\n", rCmdBtOverWifi.PAL_Capabilities); ++ DBGLOG(BOW, EVENT, "rCmdBtOverWifi Max Tx power - 0x%x.\n", rCmdBtOverWifi.cMaxTxPower); ++#endif ++ ++ /* 3 <4> Get a free BOW entry, mark as Valid, fill in Peer MAC address, LinkCount += 1, state == Starting. */ ++ if (!bowGetBowTableFreeEntry(prAdapter, &ucBowTableIdx)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ prBowFsmInfo->prTargetBssDesc = NULL; ++ ++ kalMemZero(&rBowTable, sizeof(BOW_TABLE_T)); ++ ++ COPY_MAC_ADDR(rBowTable.aucPeerAddress, prBowSetupConnection->aucPeerAddress); ++ /* owTable.eState = BOW_DEVICE_STATE_ACQUIRING_CHANNEL; */ ++ rBowTable.fgIsValid = TRUE; ++ rBowTable.ucAcquireID = prBowFsmInfo->ucSeqNumOfChReq; ++ /* rBowTable.ucRole = prBowSetupConnection->ucRole; */ ++ /* rBowTable.ucChannelNum = prBowSetupConnection->ucChannelNum; */ ++ bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); ++ ++ kalSetBowRole(prAdapter->prGlueInfo, rCmdBtOverWifi.ucRole, prBowSetupConnection->aucPeerAddress); ++ ++ GLUE_INC_REF_CNT(g_u4LinkCount); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ if (g_u4LinkCount == 1) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting, cnmTimerInitTimer.\n"); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo->u2BeaconInterval, %d.\n", prBowFsmInfo->u2BeaconInterval); ++#endif ++ cnmTimerInitTimer(prAdapter, ++ &prBowFsmInfo->rStartingBeaconTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) bowSendBeacon, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) bowChGrantedTimeout, (ULONG) NULL); ++ ++ /* Reset Global Variable */ ++ g_u4Beaconing = 0; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdSetupConnection, g_u4LinkCount, %x.\n", g_u4LinkCount); ++ DBGLOG(BOW, EVENT, "kalInitBowDevice, bow0\n"); ++#endif ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalInitBowDevice(prAdapter->prGlueInfo, BOWDEVNAME); ++#endif ++ ++ /*Active BoW Network */ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ } ++ ++ if (rCmdBtOverWifi.ucRole == BOW_INITIATOR) { ++ bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL); ++ bowRequestCh(prAdapter); ++ } else { ++ bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); ++ bowResponderScan(prAdapter); ++ } ++ ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_DESTROY_CONNECTION ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_DESTROY_CONNECTION prBowDestroyConnection; ++ CMD_BT_OVER_WIFI rCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++#if CFG_BOW_TEST ++ UINT_8 ucIdx; ++#endif ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* 3 <1> If LinkCount == 0 ->Fail (Optional) */ ++ if (g_u4LinkCount == 0) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_DESTROY_CONNECTION)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* 3 <2> Lookup BOW table, check if is not exist (Valid and Peer MAC address) -> Fail */ ++ prBowDestroyConnection = (P_BOW_DESTROY_CONNECTION) &(prCmd->aucPayload[0]); ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowDestroyConnection->aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdDestroyConnection, bowCheckIfVaild, not accepted.\n"); ++#endif ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowCmdDestroyConnection, destroy Peer address - %x:%x:%x:%x:%x:%x.\n", ++ prBowDestroyConnection->aucPeerAddress[0], prBowDestroyConnection->aucPeerAddress[1], ++ prBowDestroyConnection->aucPeerAddress[2], prBowDestroyConnection->aucPeerAddress[3], ++ prBowDestroyConnection->aucPeerAddress[4], prBowDestroyConnection->aucPeerAddress[5])); ++#endif ++ ++ /* fill CMD_BT_OVER_WIFI */ ++ rCmdBtOverWifi.ucAction = 2; ++ COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowDestroyConnection->aucPeerAddress); ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowDestroyConnection->aucPeerAddress); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowCmdDestroyConnection, rCmdBtOverWifi.rPeerAddr - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], ++ rCmdBtOverWifi.rPeerAddr[1], rCmdBtOverWifi.rPeerAddr[2], rCmdBtOverWifi.rPeerAddr[3], ++ rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); ++#endif ++ ++#if CFG_BOW_TEST ++ for (ucIdx = 0; ucIdx < 11; ucIdx++) { ++ DBGLOG(BOW, EVENT, ++ "BoW receiving PAL packet delta time vs packet number -- %d ms vs %x.\n", ucIdx, ++ g_arBowRevPalPacketTime[ucIdx]); ++ } ++#endif ++ ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, ++ sizeof(CMD_BT_OVER_WIFI), ++ (PUINT_8)&rCmdBtOverWifi, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SET_PTK ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SET_PTK prBowSetPTK; ++ CMD_802_11_KEY rCmdKey; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SET_PTK)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowSetPTK = (P_BOW_SET_PTK) &(prCmd->aucPayload[0]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowSetPTK->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowSetPTK->aucPeerAddress[0], ++ prBowSetPTK->aucPeerAddress[1], ++ prBowSetPTK->aucPeerAddress[2], ++ prBowSetPTK->aucPeerAddress[3], ++ prBowSetPTK->aucPeerAddress[4], prBowSetPTK->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "rCmdKey.ucIsAuthenticator, %x.\n", kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress)); ++#endif ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowSetPTK->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (bowGetBowTableState(prAdapter, prBowSetPTK->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ /* fill CMD_802_11_KEY */ ++ rCmdKey.ucAddRemove = 1; /* add */ ++ rCmdKey.ucTxKey = 1; ++ rCmdKey.ucKeyType = 1; ++ rCmdKey.ucIsAuthenticator = kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress); ++ COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prBowSetPTK->aucPeerAddress); ++ rCmdKey.ucNetType = NETWORK_TYPE_BOW_INDEX; /* BT Over Wi-Fi */ ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ ++ rCmdKey.ucKeyId = 0; ++ rCmdKey.ucKeyLen = 16; /* AES = 128bit */ ++ kalMemCopy(rCmdKey.aucKeyMaterial, prBowSetPTK->aucTemporalKey, 16); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowSetPTK->aucTemporalKey, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ prBowSetPTK->aucTemporalKey[0], ++ prBowSetPTK->aucTemporalKey[1], ++ prBowSetPTK->aucTemporalKey[2], ++ prBowSetPTK->aucTemporalKey[3], ++ prBowSetPTK->aucTemporalKey[4], ++ prBowSetPTK->aucTemporalKey[5], ++ prBowSetPTK->aucTemporalKey[6], ++ prBowSetPTK->aucTemporalKey[7], ++ prBowSetPTK->aucTemporalKey[8], ++ prBowSetPTK->aucTemporalKey[9], ++ prBowSetPTK->aucTemporalKey[10], ++ prBowSetPTK->aucTemporalKey[11], ++ prBowSetPTK->aucTemporalKey[12], ++ prBowSetPTK->aucTemporalKey[13], ++ prBowSetPTK->aucTemporalKey[14], prBowSetPTK->aucTemporalKey[15])); ++ ++ DBGLOG(BOW, EVENT, "rCmdKey.aucKeyMaterial, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", ++ rCmdKey.aucKeyMaterial[0], ++ rCmdKey.aucKeyMaterial[1], ++ rCmdKey.aucKeyMaterial[2], ++ rCmdKey.aucKeyMaterial[3], ++ rCmdKey.aucKeyMaterial[4], ++ rCmdKey.aucKeyMaterial[5], ++ rCmdKey.aucKeyMaterial[6], ++ rCmdKey.aucKeyMaterial[7], ++ rCmdKey.aucKeyMaterial[8], ++ rCmdKey.aucKeyMaterial[9], ++ rCmdKey.aucKeyMaterial[10], ++ rCmdKey.aucKeyMaterial[11], ++ rCmdKey.aucKeyMaterial[12], ++ rCmdKey.aucKeyMaterial[13], rCmdKey.aucKeyMaterial[14], rCmdKey.aucKeyMaterial[15])); ++#endif ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventSetCommon, ++ wlanbowCmdTimeoutHandler, ++ sizeof(CMD_802_11_KEY), (PUINT_8)&rCmdKey, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_READ_RSSI ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_READ_RSSI prBowReadRSSI; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_READ_RSSI)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowReadRSSI = (P_BOW_READ_RSSI) &(prCmd->aucPayload[0]); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ wlanbowCmdEventReadRssi, ++ wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_READ_LINK_QUALITY ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_READ_LINK_QUALITY prBowReadLinkQuality; ++ ++ ASSERT(prAdapter); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(P_BOW_READ_LINK_QUALITY)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prBowReadLinkQuality = (P_BOW_READ_LINK_QUALITY) &(prCmd->aucPayload[0]); ++ ++ return wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ wlanbowCmdEventReadLinkQuality, ++ wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_SHORT_RANGE_MODE ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ P_BOW_SHORT_RANGE_MODE prBowShortRangeMode; ++ CMD_TX_PWR_T rTxPwrParam; ++ ++ ASSERT(prAdapter); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdShortRangeMode.\n"); ++#endif ++ ++ prBowShortRangeMode = (P_BOW_SHORT_RANGE_MODE) &(prCmd->aucPayload[0]); ++ ++ /* parameter size check */ ++ if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SHORT_RANGE_MODE)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (!bowCheckBowTableIfVaild(prAdapter, prBowShortRangeMode->aucPeerAddress)) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (bowGetBowTableState(prAdapter, prBowShortRangeMode->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prBowShortRangeMode->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowShortRangeMode->aucPeerAddress[0], ++ prBowShortRangeMode->aucPeerAddress[1], ++ prBowShortRangeMode->aucPeerAddress[2], ++ prBowShortRangeMode->aucPeerAddress[3], ++ prBowShortRangeMode->aucPeerAddress[4], prBowShortRangeMode->aucPeerAddress[5])); ++#endif ++ ++ rTxPwrParam.cTxPwr2G4Cck = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4OFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4OFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4OFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4HT20_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr2G4HT40_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr2G4HT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr5GOFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GOFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); ++ ++ rTxPwrParam.cTxPwr5GHT20_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_BPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_QPSK = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_16QAM = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); ++ rTxPwrParam.cTxPwr5GHT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); ++ ++ if (nicUpdateTxPower(prAdapter, &rTxPwrParam) == WLAN_STATUS_SUCCESS) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowCmdShortRangeMode, %x.\n", WLAN_STATUS_SUCCESS); ++#endif ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); ++ return WLAN_STATUS_SUCCESS; ++ } ++ wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is command handler for BOW_CMD_ID_GET_CHANNEL_LIST ++* coming from 802.11 PAL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmd Pointer to the buffer that holds the command ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) ++{ ++ ASSERT(prAdapter); ++ ++ /* not supported yet */ ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is generic command done handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = ucEventBuf; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is generic command done handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_CONNECTED prBowLinkConnected; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); ++ ++ /* fill event body */ ++ prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prEvent->aucPayload); ++ kalMemZero(prBowLinkConnected, sizeof(BOW_LINK_CONNECTED)); ++ prBowLinkConnected->rChannel.ucChannelNum = prBssInfo->ucPrimaryChannel; ++ prBowLinkConnected->rChannel.ucChannelBand = prBssInfo->eBand; ++ COPY_MAC_ADDR(prBowLinkConnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); ++ DBGLOG(BOW, EVENT, ++ "prBowLinkConnected->rChannel.ucChannelNum, 0x%x\n", prBowLinkConnected->rChannel.ucChannelNum); ++ DBGLOG(BOW, EVENT, ++ "prBowLinkConnected->rChannel.ucChannelBand, 0x%x\n", prBowLinkConnected->rChannel.ucChannelBand); ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkConnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5]); ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkConnected, prBowLinkConnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowLinkConnected->aucPeerAddress[0], prBowLinkConnected->aucPeerAddress[1], ++ prBowLinkConnected->aucPeerAddress[2], prBowLinkConnected->aucPeerAddress[3], ++ prBowLinkConnected->aucPeerAddress[4], prBowLinkConnected->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkConnected, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Indicate Event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED))); ++ ++ /*Release channel if granted */ ++ if (prBowFsmInfo->fgIsChannelGranted) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ /* bowReleaseCh(prAdapter); */ ++ /*Requested, not granted yet */ ++ } else if (prBowFsmInfo->fgIsChannelRequested) { ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ } ++ ++ /* set to connected status */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTED); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ BOW_TABLE_T rBowTable; ++ UINT_8 ucBowTableIdx; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ BOOLEAN fgSendDeauth = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /*do nothing */ ++ return; ++ } ++ /*Cancel scan */ ++ else if (eFsmState == BOW_DEVICE_STATE_SCANNING && !(prBowFsmInfo->fgIsChannelRequested)) { ++ bowResponderCancelScan(prAdapter, FALSE); ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_DISCONNECTING); ++ return; ++ } ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; ++ if ((prCmdInfo->u4PrivateData)) ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ else ++ prEvent->rHeader.ucSeqNumber = 0; ++ ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); ++ ++ /* fill event body */ ++ prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prEvent->aucPayload); ++ kalMemZero(prBowLinkDisconnected, sizeof(BOW_LINK_DISCONNECTED)); ++ prBowLinkDisconnected->ucReason = 0x0; ++ COPY_MAC_ADDR(prBowLinkDisconnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); ++ DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); ++ ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkDisconnected, prBowLinkDisconnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowLinkDisconnected->aucPeerAddress[0], prBowLinkDisconnected->aucPeerAddress[1], ++ prBowLinkDisconnected->aucPeerAddress[2], prBowLinkDisconnected->aucPeerAddress[3], ++ prBowLinkDisconnected->aucPeerAddress[4], prBowLinkDisconnected->aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Indicate BoW event to PAL */ ++#if 0 ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++#endif ++ ++ /* set to disconnected status */ ++ prBowFsmInfo->prTargetStaRec = ++ cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_BOW_INDEX, prBowLinkDisconnected->aucPeerAddress); ++ if (!(prBowFsmInfo->prTargetStaRec)) { ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ /*Release channel if granted */ ++ if (prBowFsmInfo->fgIsChannelGranted) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ bowReleaseCh(prAdapter); ++ /*Requested, not granted yet */ ++ } else if (prBowFsmInfo->fgIsChannelRequested) { ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ /* bowReleaseCh(prAdapter); */ ++ } ++#if 1 ++ /*Send Deauth to connected peer */ ++ if (eFsmState == BOW_DEVICE_STATE_CONNECTED && (prBowFsmInfo->prTargetStaRec->ucStaState == STA_STATE_3)) { ++ fgSendDeauth = TRUE; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "wlanbowCmdEventLinkDisconnected, bowGetBowTableState, %x.\n", ++ bowGetBowTableState(prAdapter, prBowLinkDisconnected->aucPeerAddress)); ++#endif ++ authSendDeauthFrame(prAdapter, ++ prBowFsmInfo->prTargetStaRec, ++ (P_SW_RFB_T) NULL, ++ REASON_CODE_DEAUTH_LEAVING_BSS, (PFN_TX_DONE_HANDLER) bowDisconnectLink); ++ } ++#endif ++ ++#if 0 ++ /* 3 <3>Stop this link; flush Tx; ++ * send deAuthentication -> abort. SAA, AAA. need to check BOW table state == Connected. ++ */ ++ if (prAdapter->prGlueInfo->i4TxPendingFrameNum > 0) ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* flush pending security frames */ ++ if (prAdapter->prGlueInfo->i4TxPendingSecurityFrameNum > 0) ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++#endif ++ ++ /*Update BoW table */ ++ bowGetBowTableEntryByPeerAddress(prAdapter, prBowLinkDisconnected->aucPeerAddress, &ucBowTableIdx); ++ rBowTable.fgIsValid = FALSE; ++ rBowTable.eState = BOW_DEVICE_STATE_DISCONNECTED; ++ kalMemZero(rBowTable.aucPeerAddress, sizeof(rBowTable.aucPeerAddress)); ++ bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); ++ ++ /*Indicate BoW event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); ++ ++ /*Decrease link count */ ++ GLUE_DEC_REF_CNT(g_u4LinkCount); ++ ++ /*If no need to send deauth, DO disconnect now */ ++ /*If need to send deauth, DO disconnect at deauth Tx done */ ++ if (!fgSendDeauth) ++ bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_BT_OVER_WIFI prCmdBtOverWifi; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* restore original command for rPeerAddr */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prCmdBtOverWifi = (P_CMD_BT_OVER_WIFI) (prWifiCmd->aucBuffer); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; ++ ++ /*Indicate BoW event to PAL */ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++ ++ /* set to starting status */ ++ kalSetBowState(prAdapter->prGlueInfo, BOW_DEVICE_STATE_STARTING, prCmdBtOverWifi->rPeerAddr); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the command done handler for BOW_CMD_ID_READ_LINK_QUALITY ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_AMPC_EVENT prEvent; ++ P_BOW_LINK_QUALITY prBowLinkQuality; ++ ++ ASSERT(prAdapter); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_QUALITY; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_QUALITY); ++ ++ /* fill event body */ ++ prBowLinkQuality = (P_BOW_LINK_QUALITY) (prEvent->aucPayload); ++ kalMemZero(prBowLinkQuality, sizeof(BOW_LINK_QUALITY)); ++ prBowLinkQuality->ucLinkQuality = (UINT_8) prLinkQuality->cLinkQuality; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the command done handler for BOW_CMD_ID_READ_RSSI ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* \param[in] pucEventBuf Pointer to the set buffer OR event buffer ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_AMPC_EVENT prEvent; ++ P_BOW_RSSI prBowRssi; ++ ++ ASSERT(prAdapter); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_RSSI; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_RSSI); ++ ++ /* fill event body */ ++ prBowRssi = (P_BOW_RSSI) (prEvent->aucPayload); ++ kalMemZero(prBowRssi, sizeof(BOW_RSSI)); ++ prBowRssi->cRssi = (INT_8) prLinkQuality->cRssi; ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is the default command timeout handler ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] prCmdInfo Pointer to the buffer that holds the command info ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_AMPC_EVENT prEvent; ++ P_BOW_COMMAND_STATUS prBowCmdStatus; ++ ++ ASSERT(prAdapter); ++ ++ /* fill event header */ ++ prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); ++ if (!prEvent) { ++ ASSERT(FALSE); ++ return; ++ } ++ prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; ++ prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; ++ prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); ++ ++ /* fill event body */ ++ prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); ++ kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); ++ ++ prBowCmdStatus->ucStatus = BOWCMD_STATUS_TIMEOUT; /* timeout */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); ++ ++ kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); ++ ++} ++ ++VOID bowStopping(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBowBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStoping.\n"); ++ DBGLOG(BOW, EVENT, "bowStoping, SSID %s.\n", prBowBssInfo->aucSSID); ++ DBGLOG(BOW, EVENT, "bowStoping, prBowBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", ++ prBowBssInfo->aucBSSID[0], ++ prBowBssInfo->aucBSSID[1], ++ prBowBssInfo->aucBSSID[2], ++ prBowBssInfo->aucBSSID[3], prBowBssInfo->aucBSSID[4], prBowBssInfo->aucBSSID[5])); ++ DBGLOG(BOW, EVENT, "bowStoping, prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prBowBssInfo->aucOwnMacAddr[0], ++ prBowBssInfo->aucOwnMacAddr[1], ++ prBowBssInfo->aucOwnMacAddr[2], ++ prBowBssInfo->aucOwnMacAddr[3], ++ prBowBssInfo->aucOwnMacAddr[4], prBowBssInfo->aucOwnMacAddr[5])); ++ DBGLOG(BOW, EVENT, "bowStoping, prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", ++ prAdapter->rWifiVar.aucDeviceAddress[0], ++ prAdapter->rWifiVar.aucDeviceAddress[1], ++ prAdapter->rWifiVar.aucDeviceAddress[2], ++ prAdapter->rWifiVar.aucDeviceAddress[3], ++ prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); ++ DBGLOG(BOW, EVENT, "bowStopping, g_u4LinkCount, %x.\n", g_u4LinkCount); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ kalPrint("BoW Stoping,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++#endif ++ ++ if (g_u4LinkCount == 0) { ++ /*Stop beaconing */ ++ GLUE_DEC_REF_CNT(g_u4Beaconing); ++ ++ /*Deactive BoW network */ ++ /* prBowBssInfo->fgIsNetActive = FALSE; */ ++ /* prBowBssInfo->fgIsBeaconActivated = FALSE; */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ /*temp solution for FW hal_pwr_mgt.c#3037 ASSERT */ ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ } ++ ++} ++ ++VOID bowStarting(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (g_u4LinkCount == 1) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "BoW Starting.\n"); ++ DBGLOG(BOW, EVENT, "BoW channel granted.\n"); ++#endif ++ ++#if 0 ++ /*Active BoW Network */ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#endif ++ ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBssInfo->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prBssInfo->eCurrentOPMode = OP_MODE_BOW; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucDeviceAddress); ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); ++ prBssInfo->ucSSIDLen = BOW_SSID_LEN; ++ bowAssignSsid(prBssInfo->aucSSID, prBssInfo->aucOwnMacAddr); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "SSID %s.\n", prBssInfo->aucSSID); ++ DBGLOG(BOW, EVENT, "prBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", ++ prBssInfo->aucBSSID[0], ++ prBssInfo->aucBSSID[1], ++ prBssInfo->aucBSSID[2], ++ prBssInfo->aucBSSID[3], prBssInfo->aucBSSID[4], prBssInfo->aucBSSID[5])); ++ DBGLOG(BOW, EVENT, "prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", ++ prBssInfo->aucOwnMacAddr[0], ++ prBssInfo->aucOwnMacAddr[1], ++ prBssInfo->aucOwnMacAddr[2], ++ prBssInfo->aucOwnMacAddr[3], ++ prBssInfo->aucOwnMacAddr[4], prBssInfo->aucOwnMacAddr[5])); ++ DBGLOG(BOW, EVENT, "prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", ++ prAdapter->rWifiVar.aucDeviceAddress[0], ++ prAdapter->rWifiVar.aucDeviceAddress[1], ++ prAdapter->rWifiVar.aucDeviceAddress[2], ++ prAdapter->rWifiVar.aucDeviceAddress[3], ++ prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); ++#endif ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.4> Setup Channel, Band and Phy Attributes */ ++ prBssInfo->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; ++ if (prBowFsmInfo->eBand == BAND_2G4) ++ prBssInfo->eBand = BAND_2G4; ++ else ++ prBssInfo->eBand = BAND_5G; ++ ++#if CFG_BOW_SUPPORT_11N ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ ++#else ++ if (prBssInfo->eBand == BAND_2G4) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ ++ /* RATE_SET_ERP; */ ++ prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; ++ prBssInfo->u2OperationalRateSet = RATE_SET_ERP; ++ prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else { ++ /* Depend on eBand */ ++ /* prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; */ ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ /* prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; */ ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11A; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; ++ ++ /* RATE_SET_ERP; */ ++ /* prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; */ ++ /* prBssInfo->u2OperationalRateSet = RATE_SET_ERP; */ ++ ++ /* RATE_SET_ERP; */ ++ prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_OFDM; ++ prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; ++ prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } ++ ++#endif ++ prBssInfo->fgErpProtectMode = FALSE; ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2BeaconInterval = prBowFsmInfo->u2BeaconInterval; ++ prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ prBssInfo->u2ATIMWindow = 0; ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ if (prBowFsmInfo->fgSupportQoS) { ++ prAdapter->rWifiVar.fgSupportQoS = TRUE; ++ prBssInfo->fgIsQBSS = TRUE; ++ } ++ /* 3 <2> Update BSS_INFO_T common part */ ++#if CFG_SUPPORT_AAA ++ bssInitForAP(prAdapter, prBssInfo, TRUE); ++ nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#endif /* CFG_SUPPORT_AAA */ ++ prBssInfo->fgIsNetActive = TRUE; ++ prBssInfo->fgIsBeaconActivated = TRUE; ++ ++ /* 3 <3> Set MAC HW */ ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BOW_BSS_INFO_INIT(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], ++ prBowFsmInfo->aucPeerAddress[5])); ++#endif ++ ++ /* 4 <3.1> use command packets to inform firmware */ ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /* 4 <3.2> Update AdHoc PM parameter */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /* 4 <3.1> Reset HW TSF Update Mode and Beacon Mode */ ++ ++ /* 4 <3.2> Setup BSSID */ ++ /* TODO: rxmSetRxFilterBSSID0 */ ++/* rxmSetRxFilterBSSID0(prBssInfo->ucHwBssidId, prBssInfo->aucBSSID); */ ++ ++ /* 4 <3.3> Setup RX Filter to accept Probe Request */ ++ /* TODO: f get/set RX filter. */ ++ ++#if 0 ++ { ++ UINT_32 u4RxFilter; ++ ++ if (halMacRxGetRxFilters(&u4RxFilter) == HAL_STATUS_SUCCESS) { ++ ++ u4RxFilter &= ~BIT(RXFILTER_DROP_PROBE_REQ); ++ ++ halMacRxSetRxFilters(u4RxFilter); ++ } ++ } ++#endif ++ } ++ ++ /*Update BoW Table */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_STARTING); ++ ++#if CFG_BOW_TEST ++ kalPrint("BoW Starting,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++ DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); ++#endif ++ ++ /*Start beaconing */ ++ if (g_u4Beaconing < 1) { ++ GLUE_INC_REF_CNT(g_u4Beaconing); ++ bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); ++ cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); ++ } ++#if 0 ++ /*Responder: Start to scan Initiator */ ++ if (prBowFsmInfo->ucRole == BOW_RESPONDER) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowStarting responder, start scan result searching.\n"); ++#endif ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); ++ bowReleaseCh(prAdapter); ++ bowResponderScan(prAdapter); ++ } ++ /*Initiator: Request channel, wait for responder */ ++ else { ++ /* Todo:: Nothing*/ ++ /* bowRequestCh(prAdapter); */ ++ } ++#endif ++ ++} ++ ++VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 puOwnMacAddr) ++{ ++ UINT_8 i; ++ UINT_8 aucSSID[] = BOW_WILDCARD_SSID; ++ ++ kalMemCopy(pucSsid, aucSSID, BOW_WILDCARD_SSID_LEN); ++ ++ for (i = 0; i < 6; i++) { ++ pucSsid[(3 * i) + 3] = 0x2D; ++ if ((*(puOwnMacAddr + i) >> 4) < 0xA) ++ *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x30; ++ else ++ *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x57; ++ ++ if ((*(puOwnMacAddr + i) & 0x0F) < 0xA) ++ pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x30; ++ else ++ pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x57; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ BOOLEAN fgReplyProbeResp = FALSE; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu4ControlFlags); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if 0 /* CFG_BOW_TEST */ ++ DBGLOG(BOW, EVENT, "bowValidateProbeReq.\n"); ++#endif ++ ++ /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions */ ++ /*If BoW AP is beaconing */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_BOW && g_u4Beaconing > 0) { ++ ++ /*Check the probe requset sender is our peer */ ++ if (bowCheckBowTableIfVaild(prAdapter, prMgtHdr->aucSrcAddr)) ++ fgReplyProbeResp = TRUE; ++ /*Check the probe request target SSID is our SSID */ ++ else if ((prIeSsid) && ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prIeSsid->aucSSID, prIeSsid->ucLength)) ++ fgReplyProbeResp = TRUE; ++ else ++ fgReplyProbeResp = FALSE; ++ } ++ ++ return fgReplyProbeResp; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if ((g_u4Beaconing != 0) && (g_u4LinkCount > 0) && (g_u4LinkCount < CFG_BOW_PHYSICAL_LINK_NUM)) { ++ /* Send beacon */ ++ bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); ++ cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); ++ } ++#if CFG_BOW_TEST ++ else ++ kalPrint("BoW Send Beacon,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderScan(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderScan.\n"); ++ kalPrint("BOW SCAN [REQ:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq + 1); ++#endif ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ ++ if (!prScanReqMsg) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ /*Fill scan message */ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfScanReq; ++ prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_BOW_INDEX; ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ prScanReqMsg->ucSSIDLength = BOW_SSID_LEN; ++ bowAssignSsid(prScanReqMsg->aucSSID, prBowFsmInfo->aucPeerAddress); ++ prScanReqMsg->ucChannelListNum = 1; ++ ++ if (prBowFsmInfo->eBand == BAND_2G4) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ prScanReqMsg->arChnlInfoList[0].eBand = BAND_2G4; ++ } else { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ prScanReqMsg->arChnlInfoList[0].eBand = BAND_5G; ++ } ++ ++ prScanReqMsg->arChnlInfoList[0].ucChannelNum = prBowFsmInfo->ucPrimaryChannel; ++ prScanReqMsg->u2IELen = 0; ++ ++ /*Send scan message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ ++ /*Change state to SCANNING */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); ++ ++ /* prBowFsmInfo->fgTryScan = FALSE; */ /* Will enable background sleep for infrastructure */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_DESC_T prBssDesc; ++ UINT_8 ucSeqNumOfCompMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ENUM_SCAN_STATUS eScanStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ ASSERT(prScanDoneMsg->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX); ++ ++ ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; ++ eScanStatus = prScanDoneMsg->eScanStatus; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderScanDone.\n"); ++ kalPrint("BOW SCAN [DONE:%d]\n", ucSeqNumOfCompMsg); ++#endif ++ ++ if (eScanStatus == SCAN_STATUS_CANCELLED) { ++#if CFG_BOW_TEST ++ kalPrint("BOW SCAN [CANCELLED:%d]\n", ucSeqNumOfCompMsg); ++#endif ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTING) { ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ } ++ return; ++ } else if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /* bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); */ ++ return; ++ } else if (ucSeqNumOfCompMsg != prBowFsmInfo->ucSeqNumOfScanReq) { ++ DBGLOG(BOW, EVENT, "Sequence no. of BOW Responder scan done is not matched.\n"); ++ return; ++ } ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prBowFsmInfo->aucPeerAddress); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "End scan result searching.\n"); ++#endif ++ ++ /* Initiator is FOUND */ ++ if (prBssDesc != NULL) { ++ /* (prBssDesc->aucBSSID != NULL)) */ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Search Bow Peer address - %x:%x:%x:%x:%x:%x.\n", prBssDesc->aucBSSID[0], ++ prBssDesc->aucBSSID[1], ++ prBssDesc->aucBSSID[2], ++ prBssDesc->aucBSSID[3], prBssDesc->aucBSSID[4], prBssDesc->aucBSSID[5]); ++ DBGLOG(BOW, EVENT, "Starting to join initiator.\n"); ++#endif ++ /*Set target BssDesc */ ++ prBowFsmInfo->prTargetBssDesc = prBssDesc; ++ /*Request channel to do JOIN */ ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL); ++ bowRequestCh(prAdapter); ++ } ++ /*Initiator is NOT FOUND */ ++ else { ++ /*Scan again, until PAL timeout */ ++ bowResponderScan(prAdapter); ++#if 0 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#endif ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Function for cancelling scan request. There is another option to extend channel privilige ++* for another purpose. ++* ++* @param fgIsChannelExtention - Keep the channel previlege, but can cancel scan timer. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention) ++{ ++ ++ P_MSG_SCN_SCAN_CANCEL prScanCancel = (P_MSG_SCN_SCAN_CANCEL) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo = (P_BOW_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("bowResponderCancelScan()"); ++ ++ do { ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (TRUE) { ++#if CFG_BOW_TEST ++ kalPrint("BOW SCAN [CANCEL:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq); ++#endif ++ /* There is a channel privilege on hand. */ ++ ++ DBGLOG(P2P, TRACE, "BOW Cancel Scan\n"); ++ ++ prScanCancel = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancel) { ++ /* Buffer not enough, can not cancel scan request. */ ++ DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanCancel->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_CANCEL; ++ prScanCancel->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prScanCancel->ucSeqNum = prBowFsmInfo->ucSeqNumOfScanReq; ++#if CFG_ENABLE_WIFI_DIRECT ++ prScanCancel->fgIsChannelExt = fgIsChannelExtention; ++#endif ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancel, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++ ++} /* bowResponderCancelScan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialization of JOIN STATE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ ASSERT(prBssDesc); ++ ASSERT(prAdapter); ++ ++ DBGLOG(BOW, EVENT, "Starting bowResponderJoin.\n"); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> We are going to connect to this BSS. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTING); ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ /*Support First JOIN and retry */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_BOW_AP, NETWORK_TYPE_BOW_INDEX, prBssDesc); ++ if (!prStaRec) ++ return; ++ ++ prBowFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ ++ prStaRec->fgIsReAssoc = FALSE; ++ prBowFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ ++ /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ ++ if (prBowFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(BOW, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ prBowFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <4.1> sync. to firmware domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy */ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prBssDesc->aucSSID); ++ DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prConnSettings->aucSSID); ++#endif ++ } ++ /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_BOW_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ prBssInfo->prStaRecOfAP = prStaRec; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "prStaRec->eStaType, %x.\n", prStaRec->eStaType); ++ DBGLOG(BOW, INFO, "BoW trigger SAA [%pM]\n", prStaRec->aucMacAddr); ++#endif ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Join Complete Event from SAA FSM for BOW FSM ++* ++* @param[in] prMsgHdr Message of Join Complete of SAA FSM. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_JOIN_COMP_T prJoinCompMsg; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prAssocRspSwRfb; ++ P_BSS_INFO_T prBssInfo; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prStaRec = prJoinCompMsg->prStaRec; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete.\n"); ++ DBGLOG(BOW, EVENT, "bowfsmRunEventJoinComplete ptr check\n"); ++ DBGLOG(BOW, EVENT, "prMsgHdr %x\n", prMsgHdr); ++ DBGLOG(BOW, EVENT, "prAdapter %x\n", prAdapter); ++ DBGLOG(BOW, EVENT, "prBowFsmInfo %x\n", prBowFsmInfo); ++ DBGLOG(BOW, EVENT, "prStaRec %x\n", prStaRec); ++#endif ++ ++ ASSERT(prStaRec); ++ ASSERT(prBowFsmInfo); ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prBowFsmInfo->ucSeqNumOfReqMsg) { ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); ++ ++ /* 4 <1> JOIN was successful */ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - ++ WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ prStaRec->eStaType = STA_TYPE_BOW_AP; ++ prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; ++#if CFG_BOW_RATE_LIMITATION ++ /* 4 <1.2>Update Rate Set */ ++ /*Limit Rate Set to 24M, 48M, 54M */ ++ prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); ++ /*If peer cannot support the above rate set, fix on the available highest rate */ ++ if (prStaRec->u2DesiredNonHTRateSet == 0) { ++ UINT_8 ucHighestRateIndex; ++ ++ if (rateGetHighestRateIndexFromRateSet ++ (prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) { ++ prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); ++ } ++ } ++#endif ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <1.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++#if CFG_BOW_SUPPORT_11N ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++#endif ++ ++ /* 4 <1.3> Update BSS_INFO_T */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Finish bowUpdateBssInfoForJOIN.\n"); ++#endif ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowFsmRunEventJoinComplete, qmActivateStaRec.\n"); ++#endif ++ ++ /* 4 <1.7> Set the Next State of BOW FSM */ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ } ++ /* 4 <2> JOIN was not successful */ ++ else { ++ /*Retry */ ++ bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); ++#if 0 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#endif ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete -- Join failed.\n"); ++ DBGLOG(BOW, INFO, "BoW trigger SAA REJOIN\n"); ++#endif ++ } ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Media State to HOST ++* ++* @param[in] eConnectionState Current Media State ++* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN BOOLEAN fgDelayIndication) ++{ ++ EVENT_CONNECTION_STATUS rEventConnStatus; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /* NOTE(Kevin): Move following line to bowChangeMediaState() macro per CM's request. */ ++ /* prBowBssInfo->eConnectionState = eConnectionState; */ ++ ++ /* For indicating the Disconnect Event only if current media state is ++ * disconnected and we didn't do indication yet. ++ */ ++ if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ if (prBssInfo->eConnectionStateIndicated == eConnectionState) ++ return; ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <0> Cancel Delay Timer */ ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rIndicationOfDisconnectTimer); ++ ++ /* 4 <1> Fill EVENT_CONNECTION_STATUS */ ++ rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; ++ ++ if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_BOW) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; ++ rEventConnStatus.u2AID = prBssInfo->u2AssocId; ++ rEventConnStatus.u2ATIMWindow = 0; ++ } else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; ++ rEventConnStatus.u2AID = 0; ++ rEventConnStatus.u2ATIMWindow = prBssInfo->u2ATIMWindow; ++ } else { ++ ASSERT(0); ++ } ++ ++ COPY_SSID(rEventConnStatus.aucSsid, ++ rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ COPY_MAC_ADDR(rEventConnStatus.aucBssid, prBssInfo->aucBSSID); ++ ++ rEventConnStatus.u2BeaconPeriod = prBssInfo->u2BeaconInterval; ++ rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prBssInfo->ucPrimaryChannel); ++ ++ switch (prBssInfo->ucNonHTBasicPhyType) { ++ case PHY_TYPE_HR_DSSS_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PHY_TYPE_ERP_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PHY_TYPE_OFDM_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ default: ++ ASSERT(0); ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ } ++ } else { ++#if CFG_PRIVACY_MIGRATION ++ /* Clear the pmkid cache while media disconnect */ ++ secClearPmkid(prAdapter); ++#endif ++ ++ rEventConnStatus.ucReasonOfDisconnect = prBssInfo->ucReasonOfDisconnect; ++ ++ } ++ ++ /* 4 <2> Indication */ ++ nicMediaStateChange(prAdapter, NETWORK_TYPE_BOW_INDEX, &rEventConnStatus); ++ prBssInfo->eConnectionStateIndicated = eConnectionState; ++ } else { ++ /* NOTE: Only delay the Indication of Disconnect Event */ ++ ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ DBGLOG(BOW, INFO, "Postpone the indication of Disconnect for %d seconds\n", ++ prConnSettings->ucDelayTimeOfDisconnectEvent); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rIndicationOfDisconnectTimer, ++ SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Tx Fail of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowRunEventAAATxFail , bssRemoveStaRecFromClientList.\n"); ++ DBGLOG(BOW, INFO, "BoW AAA TxFail, target state %d\n", prStaRec->ucStaState + 1); ++#endif ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ++ ASSERT(prStaRec); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowRunEventAAAComplete, cnmStaRecChangeState, STA_STATE_3.\n"); ++ DBGLOG(BOW, INFO, "BoW AAA complete [%pM]\n", prStaRec->aucMacAddr); ++#endif ++ ++ /*Update BssInfo to connected */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /*Update StaRec to State3 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /*Connected */ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, FALSE, wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle RxDeauth ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBowBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if (!IS_STA_IN_BOW(prStaRec)) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ ++ eFsmState = bowGetBowTableState(prAdapter, prStaRec->aucMacAddr); ++ ++ if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { ++ /*do nothing */ ++ return WLAN_STATUS_NOT_ACCEPTED; ++ } ++ ++ if (prStaRec->ucStaState > STA_STATE_1) { ++ ++ if (STA_STATE_3 == prStaRec->ucStaState) { ++ /* P_MSG_AIS_ABORT_T prAisAbortMsg; */ ++ ++ /* NOTE(Kevin): Change state immediately to avoid starvation of ++ * MSG buffer because of too many deauth frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); ++ ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, wlanbowCmdEventLinkDisconnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ return WLAN_STATUS_NOT_ACCEPTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handle BoW Link disconnect. ++* ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++* ++* \note after receive deauth frame, callback function call this ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ /*Free target StaRec */ ++ if (prMsduInfo) ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ else ++ prStaRec = prBowFsmInfo->prTargetStaRec; ++ ++ if (prStaRec) ++ /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ kalPrint("bowDisconnectLink\n"); ++ /*No one connected */ ++ if (g_u4LinkCount == 0 && g_u4Beaconing != 0) { ++ cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer); ++ bowStopping(prAdapter); ++ kalPrint("bowStopping\n"); ++ /*Restore TxPower from Short range mode */ ++#if CFG_SUPPORT_NVRAM && 0 ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ /*Uninit BoW Interface */ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalUninitBowDevice(prAdapter->prGlueInfo); ++#endif ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Assoc Req Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Assoc Resp ++* @retval FALSE Don't reply the Assoc Resp ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAssocResp = FALSE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; ++ OS_SYSTIME rCurrentTime; ++ static OS_SYSTIME rLastRejectAssocTime; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, prAssocReqFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", ++ prAssocReqFrame->aucSrcAddr[0], ++ prAssocReqFrame->aucSrcAddr[1], ++ prAssocReqFrame->aucSrcAddr[2], ++ prAssocReqFrame->aucSrcAddr[3], ++ prAssocReqFrame->aucSrcAddr[4], prAssocReqFrame->aucSrcAddr[5])); ++#endif ++ ++ /*Assoc Accept */ ++ while (EQUAL_MAC_ADDR(prAssocReqFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAssocReq, return wlanbowCmdEventLinkConnected.\n"); ++#endif ++ /*Update StaRec */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (UINT_8) NETWORK_TYPE_BOW_INDEX, prAssocReqFrame->aucSrcAddr); ++ if (!prStaRec) ++ break; ++ prStaRec->eStaType = STA_TYPE_BOW_CLIENT; ++ prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; ++ ++#if CFG_BOW_RATE_LIMITATION ++ /*Limit Rate Set to 24M, 48M, 54M */ ++ prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); ++ /*If peer cannot support the above rate set, fix on the available highest rate */ ++ if (prStaRec->u2DesiredNonHTRateSet == 0) { ++ UINT_8 ucHighestRateIndex; ++ ++ if (rateGetHighestRateIndexFromRateSet(prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) ++ prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); ++ else { ++ /*If no available rate is found, DECLINE the association */ ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ } ++#endif ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ ++ /*Undpate BssInfo to FW */ ++ bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ ++ /*reply successful */ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ fgReplyAssocResp = TRUE; ++ break; ++ } ++ ++ /*Reject Assoc */ ++ if (*pu2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ /*Reply Assoc with reject every 5s */ ++ rCurrentTime = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAssocTime, MSEC_TO_SYSTIME(5000)) || ++ rLastRejectAssocTime == 0) { ++ fgReplyAssocResp = TRUE; ++ rLastRejectAssocTime = rCurrentTime; ++ } ++ } ++ ++ return fgReplyAssocResp; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Auth Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Auth ++* @retval FALSE Don't reply the Auth ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++bowValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAuth = FALSE; ++ P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; ++ OS_SYSTIME rCurrentTime; ++ static OS_SYSTIME rLastRejectAuthTime; ++ ++ /* TODO(Kevin): Call BoW functions to check .. ++ 1. Check we are BoW now. ++ 2. Check we can accept connection from thsi peer ++ 3. Check Black List here. ++ */ ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ prBowFsmInfo->aucPeerAddress[0], ++ prBowFsmInfo->aucPeerAddress[1], ++ prBowFsmInfo->aucPeerAddress[2], ++ prBowFsmInfo->aucPeerAddress[3], ++ prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prAuthFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", ++ prAuthFrame->aucSrcAddr[0], ++ prAuthFrame->aucSrcAddr[1], ++ prAuthFrame->aucSrcAddr[2], ++ prAuthFrame->aucSrcAddr[3], prAuthFrame->aucSrcAddr[4], prAuthFrame->aucSrcAddr[5])); ++#endif ++ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX, prAuthFrame->aucSrcAddr); ++ if (!prStaRec) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecAlloc.\n"); ++#endif ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ if (!prStaRec) ++ return fgReplyAuth; ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ prBowBssInfo->prStaRecOfAP = prStaRec; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecChangeState.\n"); ++#endif ++ } else { ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucIndex, %x.\n", prStaRec->ucIndex); ++#endif ++ bssRemoveStaRecFromClientList(prAdapter, prBowBssInfo, prStaRec); ++ } ++ ++ if (EQUAL_MAC_ADDR(prAuthFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { ++ ++ prStaRec->eStaType = STA_TYPE_BOW_CLIENT; ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->eStaType, %x.\n", prStaRec->eStaType); ++ DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucNetTypeIndex, %x.\n", prStaRec->ucNetTypeIndex); ++#endif ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->ucJoinFailureCount = 0; ++ *pprStaRec = prStaRec; ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ fgReplyAuth = TRUE; ++ } else { ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ /*Reply auth with reject every 5s */ ++ rCurrentTime = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAuthTime, MSEC_TO_SYSTIME(5000)) || ++ rLastRejectAuthTime == 0) { ++ fgReplyAuth = TRUE; ++ rLastRejectAuthTime = rCurrentTime; ++ } ++ } ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowValidateAuth, fgReplyAuth, %x.\n", fgReplyAuth); ++#endif ++ return fgReplyAuth; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is invoked when CNM granted channel privilege ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prBowBssInfo; ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_GRANT_T prMsgChGrant; ++ UINT_8 ucTokenID; ++ UINT_32 u4GrantInterval; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ucTokenID = prMsgChGrant->ucTokenID; ++ u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ /* 1. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ prBowFsmInfo->fgIsChannelGranted = TRUE; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Entering bowRunEventChGrant.\n"); ++#endif ++ ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ /*Release channel */ ++ if ((!prBowFsmInfo->fgIsChannelRequested) || ++ (prBowFsmInfo->ucSeqNumOfChReq != ucTokenID) || ++ (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) || (eFsmState == BOW_DEVICE_STATE_DISCONNECTING)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [GIVE UP:%d]\n", ucTokenID); ++ DBGLOG(BOW, INFO, "[Requested:%d][ucSeqNumOfChReq:%d][eFsmState:%d]\n", ++ prBowFsmInfo->fgIsChannelRequested, prBowFsmInfo->ucSeqNumOfChReq, eFsmState); ++#endif ++ bowReleaseCh(prAdapter); ++ return; ++ } ++ ++ /* 2. channel privilege has been approved */ ++ prBowFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++#if 0 ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, ++ prBowFsmInfo->u4ChGrantedInterval - BOW_JOIN_CH_GRANT_THRESHOLD); ++#else ++ cnmTimerStartTimer(prAdapter, ++ &prBowFsmInfo->rChGrantedTimer, BOW_JOIN_CH_REQUEST_INTERVAL - BOW_JOIN_CH_GRANT_THRESHOLD); ++#endif ++ ++ /* 3.2 set local variable to indicate join timer is ticking */ ++ prBowFsmInfo->fgIsInfraChannelFinished = FALSE; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [GRANTED:%d].\n", ucTokenID); ++#endif ++ ++ if (eFsmState == BOW_DEVICE_STATE_ACQUIRING_CHANNEL) { ++ bowStarting(prAdapter); ++ bowReleaseCh(prAdapter); ++ if (prBowFsmInfo->ucRole == BOW_RESPONDER) ++ bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); ++ } else { ++ /*update bssinfo */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); ++ bowReleaseCh(prAdapter); ++ } ++ ++} /* end of aisFsmRunEventChGrant() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM for channel privilege requesting ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowRequestCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_REQ_T prMsgChReq; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (prBowFsmInfo->fgIsChannelGranted == FALSE) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW channel [REQUEST:%d], %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq + 1, ++ prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); ++#endif ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prMsgChReq->ucTokenID = ++prBowFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++#if 0 ++ prMsgChReq->u4MaxInterval = BOW_JOIN_CH_REQUEST_INTERVAL; ++#else ++ prMsgChReq->u4MaxInterval = 1; ++#endif ++ /* prBowFsmInfo->prTargetBssDesc->ucChannelNum; */ ++ prMsgChReq->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; ++ /* prBowFsmInfo->prTargetBssDesc->eSco; */ ++ prMsgChReq->eRfSco = CHNL_EXT_SCN; ++ /* prBowFsmInfo->prTargetBssDesc->eBand; */ ++ prMsgChReq->eRfBand = prBowFsmInfo->eBand; ++ COPY_MAC_ADDR(prMsgChReq->aucBSSID, prBowFsmInfo->aucPeerAddress); ++ ++ prBowFsmInfo->fgIsChannelRequested = TRUE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform BOW that channel privilege is granted ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowReleaseCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++ if (prBowFsmInfo->fgIsChannelGranted != FALSE || prBowFsmInfo->fgIsChannelRequested != FALSE) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW channel [RELEASE:%d] %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq, ++ prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); ++#endif ++ ++ prBowFsmInfo->fgIsChannelRequested = FALSE; ++ prBowFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChAbort) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ return; ++ } ++ ++ prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ prMsgChAbort->ucTokenID = prBowFsmInfo->ucSeqNumOfChReq; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); ++ } ++ ++} /* end of aisFsmReleaseCh() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_BOW_FSM_INFO_T prBowFsmInfo; ++ ENUM_BOW_DEVICE_STATE eFsmState; ++ ++ ASSERT(prAdapter); ++ ++ prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "BoW Channel [TIMEOUT]\n"); ++#endif ++#if 1 ++ /* bowReleaseCh(prAdapter); */ ++ eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); ++ ++ /*If connecting is not completed, request CH again */ ++ if ((eFsmState == BOW_DEVICE_STATE_CONNECTING) || (eFsmState == BOW_DEVICE_STATE_STARTING)) ++ bowRequestCh(prAdapter); ++#endif ++} ++ ++BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucBowTableIdx = 0; ++ CMD_INFO_T rCmdInfo; ++ ++ ASSERT(prAdapter); ++ ++ kalMemZero(&rCmdInfo, sizeof(CMD_INFO_T)); ++ ++ while (ucBowTableIdx < CFG_BOW_PHYSICAL_LINK_NUM) { ++ if (arBowTable[ucBowTableIdx].fgIsValid) { ++ COPY_MAC_ADDR(prAdapter->rWifiVar.rBowFsmInfo.aucPeerAddress, ++ arBowTable[ucBowTableIdx].aucPeerAddress); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowNotifyAllLinkDisconnected, arBowTable[%x].aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ ucBowTableIdx, arBowTable[ucBowTableIdx].aucPeerAddress[0], ++ arBowTable[ucBowTableIdx].aucPeerAddress[1], ++ arBowTable[ucBowTableIdx].aucPeerAddress[2], ++ arBowTable[ucBowTableIdx].aucPeerAddress[3], ++ arBowTable[ucBowTableIdx].aucPeerAddress[4], ++ arBowTable[ucBowTableIdx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "bowNotifyAllLinkDisconnected, arBowTable[%x].fgIsValid, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++#endif ++#if 1 ++ wlanoidSendSetQueryBowCmd(prAdapter, ++ CMD_ID_CMD_BT_OVER_WIFI, ++ TRUE, ++ FALSE, ++ wlanbowCmdEventLinkDisconnected, ++ wlanbowCmdTimeoutHandler, 0, NULL, 0); ++#else ++ wlanbowCmdEventLinkDisconnected(prAdapter, &rCmdInfo, NULL); ++#endif ++ } ++ ++ ucBowTableIdx += 1; ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++ ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ return FALSE; ++} ++ ++BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ if (arBowTable[ucBowTableIdx].fgIsValid) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowGetBowTableContent, arBowTable[idx].fgIsValid, %x, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++ DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[ucBowTableIdx].eState); ++#endif ++ prBowTable = &(arBowTable[ucBowTableIdx]); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return TRUE; ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ COPY_MAC_ADDR(arBowTable[ucBowTableIdx].aucPeerAddress, prBowTable->aucPeerAddress); ++ arBowTable[ucBowTableIdx].eState = prBowTable->eState; ++ arBowTable[ucBowTableIdx].fgIsValid = prBowTable->fgIsValid; ++ arBowTable[ucBowTableIdx].ucAcquireID = prBowTable->ucAcquireID; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ kalSetBowState(prAdapter->prGlueInfo, prBowTable->eState, prBowTable->aucPeerAddress); ++ /* kalSetBowRole(prAdapter->prGlueInfo, prBowTable->ucRole, prBowTable->aucPeerAddress); */ ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "SET State [%d]\n", arBowTable[ucBowTableIdx].eState); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[ucBowTableIdx].fgIsValid, %x, %x.\n", ucBowTableIdx, ++ arBowTable[ucBowTableIdx].fgIsValid); ++#endif ++ ++ return TRUE; ++ ++} ++ ++BOOLEAN ++bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ *pucBowTableIdx = idx; ++ ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (!arBowTable[idx].fgIsValid) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, ++ "bowGetBowTableFreeEntry, arBowTable[idx].fgIsValid, %x, %x.\n", idx, ++ arBowTable[idx].fgIsValid); ++#endif ++ *pucBowTableIdx = idx; ++ arBowTable[idx].fgIsValid = TRUE; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return TRUE; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return FALSE; ++} ++ ++ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 idx; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { ++ if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "bowGetState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, "bowGetState, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, ++ arBowTable[idx].aucPeerAddress[0], ++ arBowTable[idx].aucPeerAddress[1], ++ arBowTable[idx].aucPeerAddress[2], ++ arBowTable[idx].aucPeerAddress[3], ++ arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); ++ DBGLOG(BOW, EVENT, ++ "bowGetState, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid); ++ DBGLOG(BOW, EVENT, ++ "bowGetState, arBowTable[idx].eState;, %x, %x.\n", idx, arBowTable[idx].eState); ++ DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[idx].eState); ++#endif ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return arBowTable[idx].eState; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState) ++{ ++ UINT_8 ucBowTableIdx; ++ ++ if (bowGetBowTableEntryByPeerAddress(prAdapter, aucPeerAddress, &ucBowTableIdx)) { ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ arBowTable[ucBowTableIdx].eState = eState; ++#if CFG_BOW_TEST ++ DBGLOG(BOW, INFO, "SET State [%d]\n", eState); ++#endif ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); ++ ++ kalSetBowState(prAdapter->prGlueInfo, eState, aucPeerAddress); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c +new file mode 100644 +index 000000000000..1c59f861047e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c +@@ -0,0 +1,6240 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_lib.c#2 ++*/ ++/*! \file wlan_lib.c ++ \brief Internal driver stack will export the required procedures here for GLUE Layer. ++ ++ This file contains all routines which are exported from MediaTek 802.11 Wireless ++ LAN driver stack to GLUE Layer. ++*/ ++ ++/* ++** Log: wlan_lib.c ++** ++** 08 15 2012 eason.tsai ++** [ALPS00338170] [Need Patch] [Volunteer Patch] modify build warning ++** fix build waring for codechange ++ * ++ * 07 13 2012 cp.wu ++ * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for termination ++ * after SDIO error has happened ++ * [driver domain] add force reset by host-to-device interrupt mechanism ++ * ++ * 06 11 2012 cp.wu ++ * [WCXRP00001252] [MT6620 Wi-Fi][Driver] Add debug message while encountering firmware response timeout ++ * output message while timeout event occurs ++ * ++ * 06 11 2012 eason.tsai ++ * NULL ++ * change from binay to hex code ++ * ++ * 06 08 2012 eason.tsai ++ * NULL ++ * Nvram context covert from 6620 to 6628 for old 6620 meta tool ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 04 2012 eason.tsai ++ * NULL ++ * modify the cal fail report code. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band ++ * configuration with corresponding network configuration correct scan result removing policy. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with ++ * corresponding network configuration add wlanSetPreferBandByNetwork() for glue layer to invoke ++ * for setting preferred band configuration corresponding to network type. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment ++ * when returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 11 14 2011 cm.chang ++ * [WCXRP00001104] [All Wi-Fi][FW] Show init process by HW mail-box register ++ * Show FW initial ID when timeout to wait for ready bit ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 10 18 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * when powering off, always clear pending interrupts, then wait for RDY to be de-asserted ++ * ++ * 10 14 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * shorten the packet length for firmware download if no more than 2048 bytes. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 20 2011 cp.wu ++ * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized ++ * 1. always show error message for SDIO bus errors. ++ * 2. reset bus error flag when re-initialization ++ * ++ * 08 26 2011 cm.chang ++ * [WCXRP00000952] [MT5931 Wi-Fi][FW] Handshake with BWCS before DPD/TX power calibration ++ * Fix compiling error for WinXP MT5931 driver ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS Sync ready for WinXP. ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 19 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * escape from normal path if any error is occurred. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a ++ * disconnecting device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 24 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * if there is no valid address in chip, generate a new one from driver domain instead of firmware domain ++ * due to sufficient randomness ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * disable whole-chip resetting mechanism due to the need of further ECO to work as expected. ++ * ++ * 05 31 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * changed to use non-zero checking for valid bit in NVRAM content ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain ++ * pass PHY_PARAM in NVRAM from driver to firmware. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * correct assertion. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 05 11 2011 cm.chang ++ * [WCXRP00000717] [MT5931 Wi-Fi][Driver] Handle wrong NVRAM content about AP bandwidth setting ++ * . ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * change delay from 100ms to 120ms upon DE's suggestion. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 22 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space ++ * process for RESET_START and RESET_END events skip power-off handshaking when RESET indication is received. ++ * ++ * 04 22 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * . ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 04 15 2011 cp.wu ++ * [WCXRP00000654] [MT6620 Wi-Fi][Driver] Add loop termination criterion for wlanAdapterStop(). ++ * add loop termination criteria for wlanAdapterStop(). ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing ++ * frame dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure ++ * happend inside wlanAdapterStart invoke nicReleaseAdapterMemory() as failure handling in case ++ * wlanAdapterStart() failed unexpectedly ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error ++ * fixed the kclocwork error. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically ++ * continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 02 25 2011 cp.wu ++ * [WCXRP00000496] [MT5931][Driver] Apply host-triggered chip reset before initializing firmware download procedures ++ * apply host-triggered chip reset mechanism before initializing firmware download procedures. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 01 2011 george.huang ++ * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers ++ * init variable for CTIA. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the ++ * corresponding BSS is disconnected due to beacon timeout remove from scanning result when the BSS ++ * is disconnected due to beacon timeout. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ++ * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous ++ * and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * while being unloaded, clear all pending interrupt then set LP-own to firmware ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay ++ * to avoid blocking to system scheduling change to use msleep() and shorten waiting interval ++ * to reduce blocking to other task while Wi-Fi driver is being loaded ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 22 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Remove controling auto rate from initial setting. The initial setting is defined by FW code. ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * sync. with ALPS code by enabling interrupt just before leaving wlanAdapterStart() ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * Change Param name for invitation connection. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 03 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) use 8 buffers for MT5931 which is equipped with less memory ++ * 2) modify MT5931 debug level to TRACE when download is successful ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * for MT5931, adapter initialization is done *after* firmware is downloaded. ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * correct MT5931 firmware download procedure: ++ * MT5931 will download firmware first then acquire LP-OWN ++ * ++ * 11 02 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) update MT5931 firmware encryption tool. (using 64-bytes unit) ++ * 2) update MT5931 firmware download procedure ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying ++ * current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function ++ * for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add option for enable/disable TX PWR gain adjustment (default: off) ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 15 2010 cp.wu ++ * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A ++ * bugfix: always reset pointer to IEbuf to zero when keeping scanning result for the connected AP ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with ++ * AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * acquire & release power control in oid handing wrapper. ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * move IE to buffer head when the IE pointer is not pointed at head. ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 13 2010 cp.wu ++ * NULL ++ * correction issue: desired phy type not initialized as ABGN mode. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 10 2010 cm.chang ++ * NULL ++ * Support EEPROM read/write in RF test mode ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 13 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Reduce unnecessary type casting ++ * ++ * 07 13 2010 cp.wu ++ * ++ * use multiple queues to keep 1x/MMPDU/CMD's strict order even when there is incoming 1x frames. ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent ++ * network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * initialize mbox & ais_fsm in wlanAdapterStart() ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * simplify timer usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable interrupt then send power control command packet. ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when stopping adapter, wait til RDY bit has been cleaerd. ++ * 2) set TASK_OFFLOAD as driver-core OIDs ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * roll-back to rev.60. ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove redundant firmware image unloading ++ * 2) use compile-time macros to separate logic related to accquiring own ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always set fw-own before driver is unloaded. ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * 2) command sequence number is now increased atomically ++ * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * 2) add 2 kal API for later integration ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) eliminate unused definitions ++ * 2) ready bit will be polled for limited iteration ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * kalOidComplete is not necessary in linux ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use pass-in prRegInfo instead of accessing prGlueInfo directly ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding none-glue code portability ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding non-glue code portability ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve non-glue code portability ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * due to the different configurations on FPGA and ASIC ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * only send CMD_NIC_POWER_CTRL in wlanAdapterStop() when card is not removed and is not in D3 state ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++* 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when starting adapter, read local adminsitrated address from registry and send to firmware via CMD_BASIC_CONFIG. ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 03 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add command/event definitions for initial states ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for QM_TEST_MODE ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct function name .. ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * separate wlanProcesQueuePacket() into 2 APIs upon request ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct wlanAdapterStart ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * 2) firmware image length is now retrieved via NdisFileOpen ++ * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * 4) nicRxWaitResponse() revised ++ * 5) another set of TQ counter default value is added for fw-download state ++ * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * 2. follow MSDN defined behavior when associates to another AP ++ * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * wlanoidSetFrequency is now implemented by RF test command. ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * QueryRssi is no longer w/o hardware access, it is now implemented by command/event handling loop ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. clear prPendingCmdInfo properly ++ * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. ++ * ++ * 01 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * allow MCR read/write OIDs in RF test mode ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * 2. block TX/ordinary OID when RF test mode is engaged ++ * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * 4. correct some HAL implementation ++ * ++ * 01 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-12-10 16:54:36 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-12-09 20:04:59 GMT mtk02752 ++** only report as connected when CFG_HIF_EMULATION_TEST is set to 1 ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-12-08 17:39:41 GMT mtk02752 ++** wlanoidRftestQueryAutoTest could be executed without touching hardware ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-12-03 16:10:26 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-02 22:05:33 GMT mtk02752 ++** kalOidComplete() will decrease i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-01 23:02:36 GMT mtk02752 ++** remove unnecessary spinlock ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-01 22:50:38 GMT mtk02752 ++** use TC4 for command, maintein i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-27 12:45:34 GMT mtk02752 ++** prCmdInfo should be freed when invoking wlanReleasePendingOid() to clear pending oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-24 19:55:51 GMT mtk02752 ++** wlanSendPacket & wlanRetransmitOfPendingFrames is only used in old data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-23 17:59:55 GMT mtk02752 ++** clear prPendingOID inside wlanSendCommand() when the OID didn't need to be replied. ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-23 14:45:29 GMT mtk02752 ++** add another version of wlanSendCommand() for command-sending only without blocking for response ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-17 22:40:44 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 10:14:56 GMT mtk01084 ++** modify place to invoke wlanIst ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-10-30 18:17:07 GMT mtk01084 ++** fix compiler warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-10-29 19:46:15 GMT mtk01084 ++** invoke interrupt process routine ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-10-13 21:58:24 GMT mtk01084 ++** modify for new HW architecture ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-09-09 17:26:01 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-05-20 12:21:27 GMT mtk01461 ++** Add SeqNum check when process Event Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-05-19 10:38:44 GMT mtk01461 ++** Add wlanReleasePendingOid() for mpReset() if there is a pending OID and no available TX resource to send it. ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-04-29 15:41:34 GMT mtk01461 ++** Add handle of EVENT of CMD Result in wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-04-22 09:11:23 GMT mtk01461 ++** Fix wlanSendCommand() for Driver Domain CR ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-04-21 09:33:56 GMT mtk01461 ++** Update wlanSendCommand() for Driver Domain Response and handle Event Packet, ++** wlanQuery/SetInformation() for enqueue CMD_INFO_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-17 20:00:08 GMT mtk01461 ++** Update wlanImageSectionDownload for optimized CMD process ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-14 20:50:51 GMT mtk01426 ++** Fixed compile error ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-13 16:38:40 GMT mtk01084 ++** add wifi start function ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-13 14:26:44 GMT mtk01084 ++** modify a parameter about FW download length ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-10 21:53:42 GMT mtk01461 ++** Update wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-08 16:51:04 GMT mtk01084 ++** Update for the image download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-01 10:32:47 GMT mtk01461 ++** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-03-23 21:44:13 GMT mtk01461 ++** Refine TC assignment for WmmAssoc flag ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 16:51:57 GMT mtk01084 ++** modify the input argument of caller to RECLAIM_POWER_CONTROL_TO_PM() ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:27:13 GMT mtk01461 ++** Add reference code of FW Image Download ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:37 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:08 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 16:28:45 GMT mtk01426 ++** Init develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++#include "mgmt/ais_fsm.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */ ++/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to Traffic Class */ ++const UINT_8 aucPriorityParam2TC[] = { ++ TC1_INDEX, ++ TC0_INDEX, ++ TC0_INDEX, ++ TC1_INDEX, ++ TC2_INDEX, ++ TC2_INDEX, ++ TC3_INDEX, ++ TC3_INDEX ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _CODE_MAPPING_T { ++ UINT_32 u4RegisterValue; ++ INT_32 i4TxpowerOffset; ++} CODE_MAPPING_T, *P_CODE_MAPPING_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++BOOLEAN fgIsBusAccessFailed = FALSE; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SIGNED_EXTEND(n, _sValue) \ ++ (((_sValue) & BIT((n)-1)) ? ((_sValue) | BITS(n, 31)) : \ ++ ((_sValue) & ~BITS(n, 31))) ++ ++/* TODO: Check */ ++/* OID set handlers without the need to access HW register */ ++PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = { ++ wlanoidSetChannel, ++ wlanoidSetBeaconInterval, ++ wlanoidSetAtimWindow, ++ wlanoidSetFrequency, ++}; ++ ++/* TODO: Check */ ++/* OID query handlers without the need to access HW register */ ++PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = { ++ wlanoidQueryBssid, ++ wlanoidQuerySsid, ++ wlanoidQueryInfrastructureMode, ++ wlanoidQueryAuthMode, ++ wlanoidQueryEncryptionStatus, ++ wlanoidQueryPmkid, ++ wlanoidQueryNetworkTypeInUse, ++ wlanoidQueryBssidList, ++ wlanoidQueryAcpiDevicePowerState, ++ wlanoidQuerySupportedRates, ++ wlanoidQueryDesiredRates, ++ wlanoidQuery802dot11PowerSaveProfile, ++ wlanoidQueryBeaconInterval, ++ wlanoidQueryAtimWindow, ++ wlanoidQueryFrequency, ++}; ++ ++/* OID set handlers allowed in RF test mode */ ++PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = { ++ wlanoidRftestSetTestMode, ++ wlanoidRftestSetAbortTestMode, ++ wlanoidRftestSetAutoTest, ++ wlanoidSetMcrWrite, ++ wlanoidSetEepromWrite ++}; ++ ++/* OID query handlers allowed in RF test mode */ ++PFN_OID_HANDLER_FUNC apfnOidQueryHandlerAllowedInRFTest[] = { ++ wlanoidRftestQueryAutoTest, ++ wlanoidQueryMcrRead, ++ wlanoidQueryEepromRead ++} ++ ++; ++ ++PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = { ++ wlanoidRftestSetTestMode, ++ wlanoidRftestSetAbortTestMode, ++ wlanoidSetAcpiDevicePowerState, ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 /* no use */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is a private routine, which is used to check if HW access is needed ++* for the OID query/ set handlers. ++* ++* \param[IN] pfnOidHandler Pointer to the OID handler. ++* \param[IN] fgSetInfo It is a Set information handler. ++* ++* \retval TRUE This function needs HW access ++* \retval FALSE This function does not need HW access ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerWOHwAccess; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ if (fgSetInfo) { ++ apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess; ++ u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); ++ } else { ++ apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess; ++ u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); ++ } ++ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler) ++ return FALSE; ++ } ++ ++ return TRUE; ++} /* wlanIsHandlerNeedHwAccess */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set flag for later handling card ++* ejected event. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++* ++* \note When surprised removal happens, Glue layer should invoke this ++* function to notify WPDD not to do any hw access. ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanCardEjected(IN P_ADAPTER_T prAdapter) ++{ ++ DEBUGFUNC("wlanCardEjected"); ++ /* INITLOG(("\n")); */ ++ ++ ASSERT(prAdapter); ++ ++ /* mark that the card is being ejected, NDIS will shut us down soon */ ++ nicTxRelease(prAdapter); ++ ++} /* wlanCardEjected */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Create adapter object ++* ++* \param prAdapter This routine is call to allocate the driver software objects. ++* If fails, return NULL. ++* \retval NULL If it fails, NULL is returned. ++* \retval NOT NULL If the adapter was initialized successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_ADAPTER_T prAdpater = (P_ADAPTER_T) NULL; ++ ++ DEBUGFUNC("wlanAdapterCreate"); ++ ++ do { ++ prAdpater = (P_ADAPTER_T) kalMemAlloc(sizeof(ADAPTER_T), VIR_MEM_TYPE); ++ ++ if (!prAdpater) { ++ DBGLOG(INIT, ERROR, "Allocate ADAPTER memory ==> FAILED\n"); ++ break; ++ } ++ ++ kalMemZero(prAdpater, sizeof(ADAPTER_T)); ++ prAdpater->prGlueInfo = prGlueInfo; ++ ++ } while (FALSE); ++ ++ return prAdpater; ++} /* wlanAdapterCreate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Destroy adapter object ++* ++* \param prAdapter This routine is call to destroy the driver software objects. ++* If fails, return NULL. ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ ++ if (!prAdapter) ++ return; ++ ++ kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initialize the adapter. The sequence is ++* 1. Disable interrupt ++* 2. Read adapter configuration from EEPROM and registry, verify chip ID. ++* 3. Create NIC Tx/Rx resource. ++* 4. Initialize the chip ++* 5. Initialize the protocol ++* 6. Enable Interrupt ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanAdapterStart(IN P_ADAPTER_T prAdapter, ++ IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 i, u4Value = 0; ++ UINT_32 u4WHISR = 0; ++ UINT_8 aucTxCount[8]; ++#if CFG_ENABLE_FW_DOWNLOAD ++ UINT_32 u4FwLoadAddr, u4ImgSecSize; ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ UINT_32 j; ++ P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; ++ BOOLEAN fgValidHead; ++ const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); ++#endif ++#endif ++ enum Adapter_Start_Fail_Reason { ++ ALLOC_ADAPTER_MEM_FAIL, ++ DRIVER_OWN_FAIL, ++ INIT_ADAPTER_FAIL, ++ RAM_CODE_DOWNLOAD_FAIL, ++ WAIT_FIRMWARE_READY_FAIL, ++ FAIL_REASON_MAX ++ } eFailReason; ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanAdapterStart"); ++ ++ eFailReason = FAIL_REASON_MAX; ++ /* 4 <0> Reset variables in ADAPTER_T */ ++ prAdapter->fgIsFwOwn = TRUE; ++ prAdapter->fgIsEnterD3ReqIssued = FALSE; ++ ++ QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue)); ++ ++ /* Initialize rWlanInfo */ ++ kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); ++ ++ /* 4 <0.1> reset fgIsBusAccessFailed */ ++ fgIsBusAccessFailed = FALSE; ++ prAdapter->ulSuspendFlag = 0; ++ ++ do { ++ u4Status = nicAllocateAdapterMemory(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicAllocateAdapterMemory Error!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = ALLOC_ADAPTER_MEM_FAIL; ++ break; ++ } ++ ++ prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; ++ ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): Acquiring LP-OWN %d\n", fgIsResetting); ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++#if !CFG_ENABLE_FULL_PM ++ nicpmSetDriverOwn(prAdapter); ++#endif ++ ++ if (prAdapter->fgIsFwOwn == TRUE) { ++ DBGLOG(INIT, ERROR, "nicpmSetDriverOwn() failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = DRIVER_OWN_FAIL; ++ break; ++ } ++ /* 4 <1> Initialize the Adapter */ ++ u4Status = nicInitializeAdapter(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicInitializeAdapter failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = INIT_ADAPTER_FAIL; ++ break; ++ } ++ ++ /* init wake lock before interrupt enable and tx thread */ ++ KAL_WAKE_LOCK_INIT(prAdapter, &prAdapter->rTxThreadWakeLock, "WLAN TX THREAD"); ++ ++ /* 4 <2> Initialize System Service (MGMT Memory pool and STA_REC) */ ++ nicInitSystemService(prAdapter); ++ ++ /* 4 <3> Initialize Tx */ ++ nicTxInitialize(prAdapter); ++ wlanDefTxPowerCfg(prAdapter); ++ ++ /* 4 <4> Initialize Rx */ ++ nicRxInitialize(prAdapter); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ if (pvFwImageMapFile == NULL) { ++ DBGLOG(INIT, ERROR, "No Firmware found!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = RAM_CODE_DOWNLOAD_FAIL; ++ break; ++ } ++ ++ /* 1. disable interrupt, download is done by polling mode only */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 2. Initialize Tx Resource to fw download state */ ++ nicTxInitResetResource(prAdapter); ++ ++ /* 3. FW download here */ ++ u4FwLoadAddr = prRegInfo->u4LoadAddress; ++ ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ /* 3a. parse file header for decision of divided firmware download or not */ ++ prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; ++ ++ if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && ++ prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, ++ u4FwImageFileLength - u4CRCOffset)) { ++ fgValidHead = TRUE; ++ } else { ++ fgValidHead = FALSE; ++ } ++ ++ /* 3b. engage divided firmware downloading */ ++ if (fgValidHead == TRUE) { ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): fgValidHead == TRUE\n"); ++ ++ for (i = 0; i < prFwHead->u4NumOfEntries; i++) { ++ ++#if CFG_START_ADDRESS_IS_1ST_SECTION_ADDR ++ if (i == 0) { ++ prRegInfo->u4StartAddress = prFwHead->arSection[i].u4DestAddr; ++ DBGLOG(INIT, TRACE, ++ "wlanAdapterStart(): FW start address 0x%08x\n", ++ prRegInfo->u4StartAddress); ++ } ++#endif ++ ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ prFwHead->arSection[i].u4DestAddr, ++ prFwHead->arSection[i].u4Length, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = prFwHead->arSection[i].u4Length - j; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ prFwHead->arSection[i].u4DestAddr + j, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset + j) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, ++ "Firmware scatter download failed %d!\n", (int)i); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ /* escape from loop if any pending error occurs */ ++ if (u4Status == WLAN_STATUS_FAILURE) ++ break; ++ } ++ } else ++#endif ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ u4FwLoadAddr, ++ u4FwImageFileLength, ++ (PUINT_8) pvFwImageMapFile) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (i = 0; i < u4FwImageFileLength; i += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImageFileLength) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = u4FwImageFileLength - i; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ u4FwLoadAddr + i, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + i) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ eFailReason = RAM_CODE_DOWNLOAD_FAIL; ++ break; ++ } ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ ++ if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Firmware download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++#endif ++ ++ /* 4. send Wi-Fi Start command */ ++ DBGLOG(INIT, INFO, " send Wi-Fi Start command\n"); ++#if CFG_OVERRIDE_FW_START_ADDRESS ++ wlanConfigWifiFunc(prAdapter, TRUE, prRegInfo->u4StartAddress); ++#else ++ wlanConfigWifiFunc(prAdapter, FALSE, 0); ++#endif ++#endif ++ ++ DBGLOG(INIT, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); ++ /* 4 <5> check Wi-Fi FW asserts ready bit */ ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ DBGLOG(INIT, TRACE, "Ready bit asserted\n"); ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ UINT_32 u4MailBox0; ++ ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ DBGLOG(INIT, ERROR, "Waiting for Ready bit: Timeout, ID=%u\n", ++ (u4MailBox0 & 0x0000FFFF)); ++ u4Status = WLAN_STATUS_FAILURE; ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* 1. reset interrupt status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ ++ /* 2. reset TX Resource for normal operation */ ++ nicTxResetResource(prAdapter); ++ ++ /* 3. query for permanent address by polling */ ++ wlanQueryPermanentAddress(prAdapter); ++ ++#if (CFG_SUPPORT_NIC_CAPABILITY == 1) ++ /* 4. query for NIC capability */ ++ wlanQueryNicCapability(prAdapter); ++#endif ++ /* 4.1 query for compiler flags */ ++ wlanQueryCompileFlags(prAdapter); ++ ++ /* 5. Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++ /* 6. indicate disconnection as default status */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ eFailReason = WAIT_FIRMWARE_READY_FAIL; ++ break; ++ } ++ ++ /* OID timeout timer initialize */ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rOidTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) wlanReleasePendingOid, (ULONG) NULL); ++ ++ /* Return Indicated Rfb list timer */ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rReturnIndicatedRfbListTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) wlanReturnIndicatedPacketsTimeOut, (ULONG) NULL); ++ ++ /* Power state initialization */ ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ prAdapter->rAcpiState = ACPI_STATE_D0; ++ ++ /* Online scan option */ ++ if (prRegInfo->fgDisOnlineScan == 0) ++ prAdapter->fgEnOnlineScan = TRUE; ++ else ++ prAdapter->fgEnOnlineScan = FALSE; ++ ++ /* Beacon lost detection option */ ++ if (prRegInfo->fgDisBcnLostDetection != 0) ++ prAdapter->fgDisBcnLostDetection = TRUE; ++ ++ /* Load compile time constant */ ++ prAdapter->rWlanInfo.u2BeaconPeriod = CFG_INIT_ADHOC_BEACON_INTERVAL; ++ prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW; ++ ++#if 1 /* set PM parameters */ ++ prAdapter->fgEnArpFilter = prRegInfo->fgEnArpFilter; ++ prAdapter->u4PsCurrentMeasureEn = prRegInfo->u4PsCurrentMeasureEn; ++ ++ prAdapter->u4UapsdAcBmp = prRegInfo->u4UapsdAcBmp; ++ ++ prAdapter->u4MaxSpLen = prRegInfo->u4MaxSpLen; ++ ++ DBGLOG(INIT, TRACE, "[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x", ++ prAdapter->fgEnArpFilter, prAdapter->u4UapsdAcBmp, prAdapter->u4MaxSpLen); ++ ++ prAdapter->fgEnCtiaPowerMode = FALSE; ++ ++#if CFG_SUPPORT_DBG_POWERMODE ++ prAdapter->fgEnDbgPowerMode = FALSE; ++#endif ++ ++#endif ++ ++ /* MGMT Initialization */ ++ nicInitMGMT(prAdapter, prRegInfo); ++ ++ /* Enable WZC Disassociation */ ++ prAdapter->rWifiVar.fgSupportWZCDisassociation = TRUE; ++ ++ /* Apply Rate Setting */ ++ if ((ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate) < FIXED_RATE_NUM) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate); ++ else ++ prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; ++ ++ if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { ++ /* Enable Auto (Long/Short) Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; ++ } else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) ++ || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) { ++ /* Force Short Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; ++ } else { ++ /* Force Long Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; ++ } ++ ++ /* Disable Hidden SSID Join */ ++ prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = FALSE; ++ ++ /* Enable Short Slot Time */ ++ prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = TRUE; ++ ++ /* configure available PHY type set */ ++ nicSetAvailablePhyTypeSet(prAdapter); ++ ++#if 1 /* set PM parameters */ ++ { ++#if CFG_SUPPORT_PWR_MGT ++ prAdapter->u4PowerMode = prRegInfo->u4PowerMode; ++ prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucNetTypeIndex = ++ NETWORK_TYPE_P2P_INDEX; ++ prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile = ENUM_PSP_FAST_SWITCH; ++#else ++ prAdapter->u4PowerMode = ENUM_PSP_CONTINUOUS_ACTIVE; ++#endif ++ ++ nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, /* FIXIT */ ++ prAdapter->u4PowerMode, FALSE); ++ } ++ ++#endif ++ ++#if CFG_SUPPORT_NVRAM ++ /* load manufacture data */ ++ wlanLoadManufactureData(prAdapter, prRegInfo); ++#endif ++ ++#ifdef CONFIG_MTK_TC1_FEATURE /* 1 //keep alive packet time change from default 30secs to 20secs. //TC01// */ ++ { ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ ++ rCmdSwCtrl.u4Id = 0x90100000; ++ rCmdSwCtrl.u4Data = 30; ++ DBGLOG(INIT, TRACE, "wlanAdapterStart Keepaliveapcket 0x%x, %d\n", ++ rCmdSwCtrl.u4Id, rCmdSwCtrl.u4Data); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8) (&rCmdSwCtrl), NULL, 0); ++ } ++#endif ++ ++#if 0 ++ /* Update Auto rate parameters in FW */ ++ nicRlmArUpdateParms(prAdapter, ++ prRegInfo->u4ArSysParam0, ++ prRegInfo->u4ArSysParam1, prRegInfo->u4ArSysParam2, prRegInfo->u4ArSysParam3); ++#endif ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ /* clock gating workaround */ ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++#endif ++ ++ } while (FALSE); ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* restore to hardware default */ ++ HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter); ++ HAL_SET_MAILBOX_READ_CLEAR(prAdapter, FALSE); ++ ++ /* Enable interrupt */ ++ nicEnableInterrupt(prAdapter); ++ ++ } else { ++ /* release allocated memory */ ++ switch (eFailReason) { ++ case WAIT_FIRMWARE_READY_FAIL: ++ DBGLOG(INIT, ERROR, "Wait firmware ready fail, FailReason: %d\n", ++ eFailReason); ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Wait firmware ready fail!]", __func__); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ nicRxUninitialize(prAdapter); ++ nicTxRelease(prAdapter); ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case RAM_CODE_DOWNLOAD_FAIL: ++ DBGLOG(INIT, ERROR, "Ram code download fail, FailReason: %d\n", ++ eFailReason); ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Ram code download fail!]", __func__); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ nicRxUninitialize(prAdapter); ++ nicTxRelease(prAdapter); ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case INIT_ADAPTER_FAIL: ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case DRIVER_OWN_FAIL: ++ nicReleaseAdapterMemory(prAdapter); ++ break; ++ case ALLOC_ADAPTER_MEM_FAIL: ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return u4Status; ++} /* wlanAdapterStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Uninitialize the adapter ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4Value = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ /* MGMT - unitialization */ ++ nicUninitMGMT(prAdapter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D0 && ++#if (CFG_CHIP_RESET_SUPPORT == 1) ++ kalIsResetting() == FALSE && ++#endif ++ kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { ++ ++ /* 0. Disable interrupt, this can be done without Driver own */ ++ nicDisableInterrupt(prAdapter); ++ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* 1. Set CMD to FW to tell WIFI to stop (enter power off state) */ ++ /* the command must be issue to firmware even in wlanRemove() */ ++ if (prAdapter->fgIsFwOwn == FALSE && wlanSendNicPowerCtrlCmd(prAdapter, 1) == WLAN_STATUS_SUCCESS) { ++ /* 2. Clear pending interrupt */ ++ i = 0; ++ while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ i++; ++ }; ++ ++ /* 3. Wait til RDY bit has been cleaerd */ ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if ((u4Value & WCIR_WLAN_READY) == 0) ++ break; ++ else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE ++ || fgIsBusAccessFailed == TRUE || i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Read WCIR_WLAN_READY fail!]", __func__); ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ } ++ ++ /* 4. Set Onwership to F/W */ ++ nicpmSetFWOwn(prAdapter, FALSE); ++ ++#if CFG_FORCE_RESET_UNDER_BUS_ERROR ++ if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == TRUE) { ++ /* force acquire firmware own */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ ++ /* delay for 10ms */ ++ kalMdelay(10); ++ ++ /* force firmware reset via software interrupt */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, WSICR_H2D_SW_INT_SET); ++ ++ /* force release firmware own */ ++ kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ } ++#endif ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } ++ ++ nicRxUninitialize(prAdapter); ++ ++ nicTxRelease(prAdapter); ++ ++ /* System Service Uninitialization */ ++ nicUninitSystemService(prAdapter); ++ ++ nicReleaseAdapterMemory(prAdapter); ++ ++#if defined(_HIF_SPI) ++ /* Note: restore the SPI Mode Select from 32 bit to default */ ++ nicRestoreSpiDefMode(prAdapter); ++#endif ++ ++ return u4Status; ++} /* wlanAdapterStop */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by ISR (interrupt). ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \retval TRUE: NIC's interrupt ++* \retval FALSE: Not NIC's interrupt ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl) ++{ ++ ASSERT(prAdapter); ++ ++ if (fgGlobalIntrCtrl) { ++ nicDisableInterrupt(prAdapter); ++ ++ /* wlanIST(prAdapter); */ ++ } ++ ++ return TRUE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by IST (task_let). ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanIST(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* wake up CONNSYS */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* handle interrupts */ ++ nicProcessIST(prAdapter); ++ ++ /* re-enable HIF interrupts */ ++ nicEnableInterrupt(prAdapter); ++ ++ /* CONNSYS can decide to sleep */ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will check command queue to find out if any could be dequeued ++* and/or send to HIF to MT6620 ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param prCmdQue Pointer of Command Queue (in Glue Layer) ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue) ++{ ++ WLAN_STATUS rStatus; ++ QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue; ++ P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue; ++ P_QUE_ENTRY_T prQueueEntry; ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(prCmdQue); ++ ++ /* init */ ++ prTempCmdQue = &rTempCmdQue; ++ prMergeCmdQue = &rMergeCmdQue; ++ prStandInCmdQue = &rStandInCmdQue; ++ ++ QUEUE_INITIALIZE(prTempCmdQue); ++ QUEUE_INITIALIZE(prMergeCmdQue); ++ QUEUE_INITIALIZE(prStandInCmdQue); ++ ++ /* 4 <1> Move whole list of CMD_INFO to the temp queue */ ++ /* copy all commands to prTempCmdQue and empty prCmdQue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ /* 4 <2> Dequeue from head and check it is able to be sent */ ++ /* remove the first one */ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ /* check how to handle the command: drop, queue, or tx */ ++ switch (prCmdInfo->eCmdType) { ++ case COMMAND_TYPE_GENERAL_IOCTL: ++ case COMMAND_TYPE_NETWORK_IOCTL: ++ /* command packet will be always sent */ ++ eFrameAction = FRAME_ACTION_TX_PKT; ++ break; ++ ++ case COMMAND_TYPE_SECURITY_FRAME: ++ /* inquire with QM */ ++ eFrameAction = qmGetFrameAction(prAdapter, ++ prCmdInfo->eNetworkType, ++ prCmdInfo->ucStaRecIndex, NULL, FRAME_TYPE_802_1X); ++ break; ++ ++ case COMMAND_TYPE_MANAGEMENT_FRAME: ++ /* inquire with QM */ ++ prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); ++ ++ eFrameAction = qmGetFrameAction(prAdapter, ++ prMsduInfo->ucNetworkType, ++ prMsduInfo->ucStaRecIndex, prMsduInfo, FRAME_TYPE_MMPDU); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ /* 4 <3> handling upon dequeue result */ ++ if (eFrameAction == FRAME_ACTION_DROP_PKT) { ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) ++ DBGLOG(TX, WARN, "Drop Security frame seqNo=%d\n", ++ prCmdInfo->ucCmdSeqNum); ++ wlanReleaseCommand(prAdapter, prCmdInfo); ++ } else if (eFrameAction == FRAME_ACTION_QUEUE_PKT) { ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) ++ DBGLOG(TX, INFO, "Queue Security frame seqNo=%d\n", ++ prCmdInfo->ucCmdSeqNum); ++ QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); ++ } else if (eFrameAction == FRAME_ACTION_TX_PKT) { ++ /* 4 <4> Send the command */ ++ rStatus = wlanSendCommand(prAdapter, prCmdInfo); ++ ++ if (rStatus == WLAN_STATUS_RESOURCES) { ++ /* no more TC4 resource for further transmission */ ++ QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); ++ DBGLOG(TX, EVENT, "No TC4 resource to send cmd, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", ++ prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, ++ prCmdInfo->eCmdType, prCmdInfo->fgIsOid); ++ break; ++ } else if (rStatus == WLAN_STATUS_PENDING) { ++ /* command packet which needs further handling upon response */ ++ /* i.e. we need to wait for FW's response */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), prQueueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ } else { ++ /* send success or fail */ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* send success */ ++ if (prCmdInfo->pfCmdDoneHandler) { ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, ++ prCmdInfo->pucInfoBuffer); ++ } ++ } else { ++ /* send fail */ ++ if (prCmdInfo->fgIsOid) { ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, rStatus); ++ } ++ DBGLOG(TX, WARN, "Send CMD, status=%u, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", ++ rStatus, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, ++ prCmdInfo->eCmdType, prCmdInfo->fgIsOid); ++ } ++ ++ /* free the command memory */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ } else { ++ ++ /* impossible, wrong eFrameAction */ ++ ASSERT(0); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ /* 4 <3> Merge back to original queue */ ++ /* 4 <3.1> Merge prMergeCmdQue & prTempCmdQue */ ++ QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue); ++ ++ /* 4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ due to incoming 802.1X frames */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ /* ??? here, prCmdQue shall be empty, why QUEUE_MOVE_ALL ??? */ ++ QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue); ++ ++ /* 4 <3.3> concatenate prStandInQue to prMergeCmdQue */ ++ QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue); ++ ++ /* 4 <3.4> then move prMergeCmdQue to prCmdQue */ ++ QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanProcessCommandQueue() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will take CMD_INFO_T which carry some information of ++* incoming OID and notify the NIC_TX to send CMD. ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param prCmdInfo Pointer of P_CMD_INFO_T ++* ++* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately. ++* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous ++* frame finishing their transmission. ++* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN pfgIsSecOrMgmt = FALSE; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* init */ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* DbgPrint("wlanSendCommand()\n"); */ ++ /* */ ++ /* */ ++#if DBG && 0 ++ LOG_FUNC("wlanSendCommand()\n"); ++ LOG_FUNC("CmdType %u NetworkType %u StaRecIndex %u Oid %u CID 0x%x SetQuery %u NeedResp %u CmdSeqNum %u\n", ++ prCmdInfo->eCmdType, ++ prCmdInfo->eNetworkType, ++ prCmdInfo->ucStaRecIndex, ++ prCmdInfo->fgIsOid, ++ prCmdInfo->ucCID, prCmdInfo->fgSetQuery, prCmdInfo->fgNeedResp, prCmdInfo->ucCmdSeqNum); ++#endif ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ do { ++ /* <0> card removal check */ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ rStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* <1> Normal case of sending CMD Packet */ ++ if (!prCmdInfo->fgDriverDomainMCR) { ++ /* <1.1> Assign Traffic Class(TC) = TC4. */ ++ ucTC = TC4_INDEX; ++ ++ if ((prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) || ++ (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME)) ++ pfgIsSecOrMgmt = TRUE; ++ ++ /* <1.2> Check if pending packet or resource was exhausted */ ++ rStatus = nicTxAcquireResource(prAdapter, ucTC, pfgIsSecOrMgmt); ++ if (rStatus == WLAN_STATUS_RESOURCES) { ++ DbgPrint("NO Resource:%d\n", ucTC); ++ break; ++ } ++ /* <1.3> Forward CMD_INFO_T to NIC Layer */ ++ rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC); ++ ++ /* <1.4> Set Pending in response to Query Command/Need Response */ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) ++ rStatus = WLAN_STATUS_PENDING; ++ } ++ } ++ /* <2> "Special case" for access Driver Domain MCR */ ++ else { ++ ++ P_CMD_ACCESS_REG prCmdAccessReg; ++ ++ prCmdAccessReg = (P_CMD_ACCESS_REG) (prCmdInfo->pucInfoBuffer + CMD_HDR_SIZE); ++ ++ if (prCmdInfo->fgSetQuery) { ++ /* address is in DWORD unit */ ++ HAL_MCR_WR(prAdapter, (prCmdAccessReg->u4Address & BITS(2, 31)), ++ prCmdAccessReg->u4Data); ++ } else { ++ P_CMD_ACCESS_REG prEventAccessReg; ++ UINT_32 u4Address; ++ ++ u4Address = prCmdAccessReg->u4Address; ++ prEventAccessReg = (P_CMD_ACCESS_REG) prCmdInfo->pucInfoBuffer; ++ prEventAccessReg->u4Address = u4Address; ++ /* address is in DWORD unit */ ++ HAL_MCR_RD(prAdapter, prEventAccessReg->u4Address & BITS(2, 31), ++ &prEventAccessReg->u4Data); ++ } ++ } ++ ++ } while (FALSE); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return rStatus; ++} /* end of wlanSendCommand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function will release thd CMD_INFO upon its attribution ++ * ++ * \param prAdapter Pointer of Adapter Data Structure ++ * \param prCmdInfo Pointer of CMD_INFO_T ++ * ++ * \return (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ switch (prCmdInfo->eCmdType) { ++ case COMMAND_TYPE_GENERAL_IOCTL: ++ case COMMAND_TYPE_NETWORK_IOCTL: ++ if (prCmdInfo->fgIsOid) { ++ /* for OID command, we need to do complete() to wake up kalIoctl() */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_FAILURE); ++ } ++ break; ++ ++ case COMMAND_TYPE_SECURITY_FRAME: ++ /* free packets in kalSecurityFrameSendComplete() */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); ++ break; ++ ++ case COMMAND_TYPE_MANAGEMENT_FRAME: ++ prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; ++ ++ /* invoke callbacks */ ++ if (prMsduInfo->pfTxDoneHandler != NULL) ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); ++ ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ break; ++ ++ default: ++ /* impossible, shall not be here */ ++ ASSERT(0); ++ break; ++ } ++ ++ /* free command buffer and return the command header to command pool */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++} /* end of wlanReleaseCommand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will search the CMD Queue to look for the pending OID and ++* compelete it immediately when system request a reset. ++* ++* \param prAdapter ointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("wlanReleasePendingOid"); ++ ++ ASSERT(prAdapter); ++ ++ DBGLOG(OID, ERROR, "OID Timeout! Releasing pending OIDs ..\n"); ++ ++ do { ++ /* 1: Handle OID commands in pending queue */ ++ /* Clear Pending OID in prAdapter->rPendingCmdQueue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ /* move all pending commands to prTempCmdQue and empty prCmdQue */ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ /* get first pending command */ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->fgIsOid) { ++ if (prCmdInfo->pfCmdTimeoutHandler) { ++ prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); ++ } else { ++ /* send complete() to wake up kalIoctl() */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++ } ++ ++ /* free command memory */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } else { ++ /* nothing to do so re-queue it to prCmdQue */ ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ /* 2: Clear pending OID staying in command queue */ ++ kalOidCmdClearance(prAdapter->prGlueInfo); ++ ++ /* 3: Do complete(), do we need this? because we have completed in kalOidComplete */ ++ kalOidClearance(prAdapter->prGlueInfo); ++ ++ } while (FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will search the CMD Queue to look for the pending CMD/OID for specific ++* NETWORK TYPE and compelete it immediately when system request a reset. ++* ++* \param prAdapter ointer of Adapter Data Structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* only free commands from the network interface, AIS, P2P, or BOW */ ++ ++ do { ++ /* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ DBGLOG(P2P, TRACE, "Pending CMD for Network Type:%d\n", prCmdInfo->eNetworkType); ++ ++ if (prCmdInfo->eNetworkType == eNetworkType) { ++ if (prCmdInfo->pfCmdTimeoutHandler) { ++ prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); ++ } else ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ } while (FALSE); ++ ++} /* wlanReleasePendingCMDbyNetwork */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the packet buffer and reallocate one to the RFB ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param pvPacket Pointer of returned packet ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("wlanReturnPacket"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* free the packet */ ++ if (pvPacket) { ++ kalPacketFree(prAdapter->prGlueInfo, pvPacket); ++ RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1); ++#if CFG_NATIVE_802_11 ++ if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) { ++ /*Todo:: nothing*/ ++ /*Todo:: nothing*/ ++ } ++#endif ++ } ++ ++ /* free the packet control block */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (!prSwRfb) { ++ ASSERT(0); ++ return; ++ } ++ ++ if (nicRxSetupRFB(prAdapter, prSwRfb)) { ++ ASSERT(0); ++ /* return; // Don't return here or it would lost SwRfb --kc */ ++ if (!timerPendingTimer(&prAdapter->rReturnIndicatedRfbListTimer)) { ++ DBGLOG(RX, WARN, ++ "wlanReturnPacket, Start ReturnIndicatedRfbList Timer (%ds)\n", ++ RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); ++ cnmTimerStartTimer(prAdapter, &prAdapter->rReturnIndicatedRfbListTimer, ++ SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); ++ } ++ } ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the indicated packet buffer and reallocate one to the RFB ++* ++* \param prAdapter Pointer of Adapter Data Structure ++* \param pvPacket Pointer of returned packet ++* ++* \retval WLAN_STATUS_SUCCESS: Success ++* \retval WLAN_STATUS_FAILURE: Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_QUE_T prQueList; ++ ++ DEBUGFUNC("wlanReturnIndicatedPacketsTimeOut"); ++ DBGLOG(RX, WARN, "wlanReturnIndicatedPacketsTimeOut"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prQueList = &prRxCtrl->rIndicatedRfbList; ++ DBGLOG(RX, WARN, "IndicatedRfbList num = %u\n", (unsigned int)prQueList->u4NumElem); ++ ++ while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rIndicatedRfbList)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (nicRxSetupRFB(prAdapter, prSwRfb)) { ++ status = WLAN_STATUS_RESOURCES; ++ ASSERT(0); ++ } ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ if (status == WLAN_STATUS_RESOURCES) ++ break; ++ } ++ if (status == WLAN_STATUS_RESOURCES) { ++ DBGLOG(RX, WARN, "Start ReturnIndicatedRfbList Timer (%ds)\n", RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); ++ /* restart timer */ ++ cnmTimerStartTimer(prAdapter, ++ &prAdapter->rReturnIndicatedRfbListTimer, ++ SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a required function that returns information about ++* the capabilities and status of the driver and/or its network adapter. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] pfnOidQryHandler Function pointer for the OID query handler. ++* \param[IN] pvInfoBuf Points to a buffer for return the query information. ++* \param[IN] u4QueryBufferLen Specifies the number of bytes at pvInfoBuf. ++* \param[OUT] pu4QueryInfoLen Points to the number of bytes it written or is needed. ++* ++* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanQueryInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfnOidQryHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QryInfoLen); ++ ++ /* ignore any OID request after connected, under PS current measurement mode */ ++ /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for ++ * blocking OIDs during current measurement ++ */ ++ if (prAdapter->u4PsCurrentMeasureEn && ++ (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) ++ return WLAN_STATUS_SUCCESS; ++#if 1 ++ /* most OID handler will just queue a command packet */ ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++#else ++ if (wlanIsHandlerNeedHwAccess(pfnOidQryHandler, FALSE)) { ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } else ++ status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); ++#endif ++ ++ return status; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a required function that allows bound protocol drivers, ++* or NDIS, to request changes in the state information that the miniport ++* maintains for particular object identifiers, such as changes in multicast ++* addresses. ++* ++* \param[IN] prAdapter Pointer to the Glue info structure. ++* \param[IN] pfnOidSetHandler Points to the OID set handlers. ++* \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data for the set. ++* \param[IN] u4InfoBufLen Specifies the number of bytes at prSetBuffer. ++* \param[OUT] pu4SetInfoLen Points to the number of bytes it read or is needed. ++* ++* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSetInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfnOidSetHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* ignore any OID request after connected, under PS current measurement mode */ ++ /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for blocking ++ * OIDs during current measurement ++ */ ++ if (prAdapter->u4PsCurrentMeasureEn && ++ (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) ++ return WLAN_STATUS_SUCCESS; ++#if 1 ++ /* most OID handler will just queue a command packet ++ * for power state transition OIDs, handler will acquire power control by itself ++ */ ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++#else ++ if (wlanIsHandlerNeedHwAccess(pfnOidSetHandler, TRUE)) { ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ } else { ++ status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); ++ } ++#endif ++ ++ return status; ++} ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a used to query driver's config wapi mode or not ++* ++* \param[IN] prAdapter Pointer to the Glue info structure. ++* ++* \retval TRUE for use wapi mode ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rWifiVar.rConnSettings.fgWapiMode; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to set RX filter to Promiscuous Mode. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode) ++{ ++ ASSERT(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to set RX filter to allow to receive ++* broadcast address packets. ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to send out CMD_NIC_POWER_CTRL command packet ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] ucPowerMode refer to CMD/EVENT document ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode) ++{ ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucTC, ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* 1. Prepare CMD */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL))); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* 2.1 increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* 2.2 Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL); ++ ++ /* 2.3 Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL)); ++ ((P_CMD_NIC_POWER_CTRL) (prWifiCmd->aucBuffer))->ucPowerMode = ucPowerMode; ++ ++ /* 3. Issue CMD for entering specific power mode */ ++ ucTC = TC4_INDEX; ++ ++ while (1) { ++ /* 3.0 Removal check */ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* 3.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ ++ /* wait and poll tx resource */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ continue; ++ } ++ /* 3.2 Send CMD Info Packet */ ++ if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Fail to transmit CMD_NIC_POWER_CTRL command\n"); ++ status = WLAN_STATUS_FAILURE; ++ } ++ ++ break; ++ }; ++ ++ /* 4. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* 5. Add flag */ ++ if (ucPowerMode == 1) ++ prAdapter->fgIsEnterD3ReqIssued = TRUE; ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to check if it is RF test mode and ++* the OID is allowed to be called or not ++* ++* \param[IN] prAdapter Pointer to the Adapter structure. ++* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerAllowedInRFTest; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ if (fgSetInfo) { ++ apfnOidHandlerAllowedInRFTest = apfnOidSetHandlerAllowedInRFTest; ++ u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); ++ } else { ++ apfnOidHandlerAllowedInRFTest = apfnOidQueryHandlerAllowedInRFTest; ++ u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); ++ } ++ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to download FW image in an aggregated way ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) ++{ ++#if defined(MT6620) || defined(MT6628) ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 u4PktCnt, u4Offset, u4Length; ++ UINT_32 u4TotalLength; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucImgSecBuf); ++ ++ pucOutputBuf = prAdapter->rTxCtrl.pucTxCoalescingBufPtr; ++ ++ DEBUGFUNC("wlanImageSectionDownloadAggregated"); ++ ++ if (u4ImgSecSize == 0) ++ return WLAN_STATUS_SUCCESS; ++ /* 1. Allocate CMD Info Packet and Pre-fill Headers */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + ++ CMD_PKT_SIZE_FOR_IMAGE); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + CMD_PKT_SIZE_FOR_IMAGE; ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->ucEtherTypeOffset = 0; ++ prInitHifTxHeader->ucCSflags = 0; ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; ++ ++ /* 4. Setup CMD_DOWNLOAD_BUF */ ++ prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdDownloadBuf->u4DataMode = 0 ++#if CFG_ENABLE_FW_ENCRYPTION ++ | DOWNLOAD_BUF_ENCRYPTION_MODE ++#endif ++ ; ++ ++ /* 5.0 reset loop control variable */ ++ u4TotalLength = 0; ++ u4Offset = u4PktCnt = 0; ++ ++ /* 5.1 main loop for maximize transmission count per access */ ++ while (u4Offset < u4ImgSecSize) { ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_SUCCESS) { ++ /* 5.1.1 calculate u4Length */ ++ if (u4Offset + CMD_PKT_SIZE_FOR_IMAGE < u4ImgSecSize) ++ u4Length = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4Length = u4ImgSecSize - u4Offset; ++ ++ /* 5.1.1 increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5.1.2 update HIF TX hardware header */ ++ prInitHifTxHeader->u2TxByteCount = ++ ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4Length); ++ ++ /* 5.1.3 fill command header */ ++ prInitCmdDownloadBuf->u4Address = u4DestAddr + u4Offset; ++ prInitCmdDownloadBuf->u4Length = u4Length; ++ prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf + u4Offset, u4Length); ++ ++ /* 5.1.4.1 copy header to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength, ++ (PVOID) prCmdInfo->pucInfoBuffer, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF)); ++ ++ /* 5.1.4.2 copy payload to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength + sizeof(INIT_HIF_TX_HEADER_T) + ++ sizeof(INIT_CMD_DOWNLOAD_BUF), pucImgSecBuf + u4Offset, u4Length); ++ ++ /* 5.1.4.3 update length and other variables */ ++ u4TotalLength += ++ ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4Length); ++ u4Offset += u4Length; ++ u4PktCnt++; ++ ++ if (u4Offset < u4ImgSecSize) ++ continue; ++ } else if (u4PktCnt == 0) { ++ /* no resource, so get some back */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ } ++ ++ if (u4PktCnt != 0) { ++ /* start transmission */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ 0, ++ u4TotalLength, (PUINT_8) pucOutputBuf, prAdapter->u4CoalescingBufCachedSize); ++ ++ /* reset varaibles */ ++ u4PktCnt = 0; ++ u4TotalLength = 0; ++ } ++ } ++ ++ /* 8. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++ ++#else ++#error "Only MT6620/MT6628/MT6582 supports firmware download in an aggregated way" ++ ++ return WLAN_STATUS_FAILURE; ++ ++#endif ++} ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to download FW image. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucImgSecBuf); ++ ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); ++ ++ DEBUGFUNC("wlanImageSectionDownload"); ++ ++ if (u4ImgSecSize == 0) ++ return WLAN_STATUS_SUCCESS; ++ /* 1. Allocate CMD Info Packet and its Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, ++ sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4ImgSecSize); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4ImgSecSize; ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5. Setup CMD_DOWNLOAD_BUF */ ++ prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdDownloadBuf->u4Address = u4DestAddr; ++ prInitCmdDownloadBuf->u4Length = u4ImgSecSize; ++ prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf, u4ImgSecSize); ++ ++ prInitCmdDownloadBuf->u4DataMode = 0 ++#if CFG_ENABLE_FW_DOWNLOAD_ACK ++ | DOWNLOAD_BUF_ACK_OPTION /* ACK needed */ ++#endif ++#if CFG_ENABLE_FW_ENCRYPTION ++ | DOWNLOAD_BUF_ENCRYPTION_MODE ++#endif ++ ; ++ ++ kalMemCopy(prInitCmdDownloadBuf->aucBuffer, pucImgSecBuf, u4ImgSecSize); ++ ++ /* 6. Send FW_Download command */ ++ while (1) { ++ /* 6.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ continue; ++ } ++ /* 6.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); ++ } ++ ++ break; ++ }; ++ ++#if CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* 7. Wait for INIT_EVENT_ID_CMD_RESULT */ ++ u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum); ++#endif ++ ++ /* 8. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to confirm previously firmware download is done without error ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR)]; ++ UINT_32 u4RxPktLength; ++ P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; ++ P_INIT_EVENT_PENDING_ERROR prEventPendingError; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_8 ucTC, ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanImageQueryStatus"); ++ ++ /* 1. Allocate CMD Info Packet and it Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ kalMemZero(prCmdInfo, sizeof(INIT_HIF_TX_HEADER_T)); ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); ++ ++ /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ /* 5. Send command */ ++ while (1) { ++ /* 5.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ continue; ++ } ++ /* 5.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); ++ } ++ ++ break; ++ }; ++ ++ /* 6. Wait for INIT_EVENT_ID_PENDING_ERROR */ ++ do { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (nicRxWaitResponse(prAdapter, ++ 0, ++ aucBuffer, ++ sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; ++ ++ /* EID / SeqNum check */ ++ if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PENDING_ERROR) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prEventPendingError = ++ (P_INIT_EVENT_PENDING_ERROR) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); ++ if (prEventPendingError->ucStatus != 0) { /* 0 for download success */ ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ } while (FALSE); ++ ++ /* 7. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++#else ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to confirm the status of ++* previously downloaded firmware scatter ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ucCmdSeqNum Sequence number of previous firmware scatter ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum) ++{ ++ UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)]; ++ P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; ++ P_INIT_EVENT_CMD_RESULT prEventCmdResult; ++ UINT_32 u4RxPktLength; ++ WLAN_STATUS u4Status; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ DBGLOG(INIT, ERROR, "kalIsCardRemoved or fgIsBusAccessFailed\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else if (nicRxWaitResponse(prAdapter, ++ 0, ++ aucBuffer, ++ sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT),/* 4B + 4B */ ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "nicRxWaitResponse fail\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; ++ ++ /* EID / SeqNum check */ ++ if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT) { ++ DBGLOG(INIT, ERROR, "rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Check EID error!]", __func__); ++ } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { ++ DBGLOG(INIT, ERROR, "rInitWifiEvent.ucSeqNum != ucCmdSeqNum\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ g_IsNeedDoChipReset = 1; ++ kalSendAeeWarning("[Check SeqNum error!]", __func__); ++ } else { ++ prEventCmdResult = ++ (P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); ++ if (prEventCmdResult->ucStatus != 0) { /* 0 for download success */ ++ /* ++ 0: success ++ 1: rejected by invalid param ++ 2: rejected by incorrect CRC ++ 3: rejected by decryption failure ++ 4: unknown CMD ++ */ ++ DBGLOG(INIT, ERROR, "Read Response status error = %d\n", ++ prEventCmdResult->ucStatus); ++ u4Status = WLAN_STATUS_FAILURE; ++ } else { ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to start FW normal operation. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; ++ P_INIT_CMD_WIFI_START prInitCmdWifiStart; ++ UINT_8 ucTC, ucCmdSeqNum; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanConfigWifiFunc"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer. */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); ++ prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START); ++ ++ /* 2. Always use TC0 */ ++ ucTC = TC0_INDEX; ++ ++ /* 3. increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* 4. Setup common CMD Info Packet */ ++ prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); ++ prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_WIFI_START; ++ prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; ++ ++ prInitCmdWifiStart = (P_INIT_CMD_WIFI_START) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); ++ prInitCmdWifiStart->u4Override = (fgEnable == TRUE ? 1 : 0); ++ prInitCmdWifiStart->u4Address = u4StartAddress; ++ ++ /* 5. Seend WIFI start command */ ++ while (1) { ++ /* 5.1 Acquire TX Resource */ ++ if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { ++ ++ /* wait and poll tx resource */ ++ if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); ++ break; ++ } ++ ++ continue; ++ } ++ /* 5.2 Send CMD Info Packet */ ++ if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { ++ u4Status = WLAN_STATUS_FAILURE; ++ DBGLOG(INIT, ERROR, "Fail to transmit WIFI start command\n"); ++ } ++ ++ break; ++ }; ++ ++ /* 6. Free CMD Info Packet. */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate CRC32 checksum ++* ++* @param buf Pointer to the data. ++* @param len data length ++* ++* @return crc32 value ++*/ ++/*----------------------------------------------------------------------------*/ ++static const UINT_32 crc32_ccitt_table[256] = { ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, ++ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, ++ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, ++ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, ++ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, ++ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, ++ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, ++ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, ++ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, ++ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, ++ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, ++ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, ++ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, ++ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, ++ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, ++ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, ++ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, ++ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, ++ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, ++ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, ++ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, ++ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, ++ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, ++ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, ++ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, ++ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, ++ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, ++ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, ++ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, ++ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, ++ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, ++ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, ++ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, ++ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, ++ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, ++ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, ++ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, ++ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, ++ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, ++ 0x2d02ef8d ++ }; ++ ++UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len) ++{ ++ UINT_32 i, crc32 = 0xFFFFFFFF; ++ ++ for (i = 0; i < len; i++) ++ crc32 = crc32_ccitt_table[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8); ++ ++ return ~crc32; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to process queued RX packets ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prSwRfbListHead Pointer to head of RX packets link list ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) ++{ ++ P_SW_RFB_T prSwRfb, prNextSwRfb; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfbListHead); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ prSwRfb = prSwRfbListHead; ++ ++ do { ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ ++ switch (prSwRfb->eDst) { ++ case RX_PKT_DESTINATION_HOST: ++ /* to host */ ++ nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_FORWARD: ++ /* need ot forward */ ++ nicRxProcessForwardPkt(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_HOST_WITH_FORWARD: ++ /* to host and forward */ ++ nicRxProcessGOBroadcastPkt(prAdapter, prSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_NULL: ++ /* free it */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ ++ default: ++ break; ++ } ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4DequeuedCnt++; ++#endif ++ ++ /* check next queued packet */ ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to purge queued TX packets ++* by indicating failure to OS and returned to free list ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prMsduInfoListHead Pointer to head of TX packets link list ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); ++ nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if the OID handler needs timeout ++* ++* @param prAdapter Pointer to the Adapter structure. ++* pfnOidHandler Pointer to the OID handler ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler) ++{ ++ PFN_OID_HANDLER_FUNC *apfnOidHandlerWOTimeoutCheck; ++ UINT_32 i; ++ UINT_32 u4NumOfElem; ++ ++ apfnOidHandlerWOTimeoutCheck = apfnOidWOTimeoutCheck; ++ u4NumOfElem = sizeof(apfnOidWOTimeoutCheck) / sizeof(PFN_OID_HANDLER_FUNC); ++ ++ /* skip some OID timeout checks ? */ ++ for (i = 0; i < u4NumOfElem; i++) { ++ if (apfnOidHandlerWOTimeoutCheck[i] == pfnOidHandler) ++ return FALSE; ++ } ++ ++ /* set timer if need timeout check */ ++ /* cnmTimerStartTimer(prAdapter, */ ++ /* &(prAdapter->rOidTimeoutTimer), */ ++ /* 1000); */ ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rOidTimeoutTimer), 2000); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to clear any pending OID timeout check ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rOidTimeoutTimer)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update network address in firmware domain ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return WLAN_STATUS_FAILURE The request could not be processed ++* WLAN_STATUS_PENDING The request has been queued for later processing ++* WLAN_STATUS_SUCCESS The request has been processed ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter) ++{ ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ PARAM_MAC_ADDRESS rMacAddr = {0}; ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_BASIC_CONFIG prCmdBasicConfig; ++ UINT_32 u4SysTime; ++ ++ DEBUGFUNC("wlanUpdateNetworkAddress"); ++ ++ ASSERT(prAdapter); ++ ++ if (kalRetrieveNetworkAddress(prAdapter->prGlueInfo, &rMacAddr) == FALSE || IS_BMCAST_MAC_ADDR(rMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, rMacAddr)) { ++ /* eFUSE has a valid address, don't do anything */ ++ if (prAdapter->fgIsEmbbededMacAddrValid == TRUE) { ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "Using embedded MAC address"); ++#endif ++ return WLAN_STATUS_SUCCESS; ++ } ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, TRACE, "Using dynamically generated MAC address"); ++#endif ++ /* dynamic generate */ ++ u4SysTime = kalGetTimeTick(); ++ ++ rMacAddr[0] = 0x00; ++ rMacAddr[1] = 0x08; ++ rMacAddr[2] = 0x22; ++ ++ kalMemCopy(&rMacAddr[3], &u4SysTime, 3); ++ } else { ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "Using host-supplied MAC address"); ++#endif ++ } ++ ++ /* allocate command memory */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* configure CMD_BASIC_CONFIG */ ++ prCmdBasicConfig = (P_CMD_BASIC_CONFIG) (prWifiCmd->aucBuffer); ++ kalMemCopy(&(prCmdBasicConfig->rMyMacAddr), &rMacAddr, PARAM_MAC_ADDR_LEN); ++ prCmdBasicConfig->ucNative80211 = 0; ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum = 0; ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum = 0; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(2); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(1); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) ++ prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(0); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(2); ++ ++ if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(1); ++ ++ if (prAdapter->u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) ++ prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(0); ++#endif ++ ++ /* send the command to FW */ ++ if (wlanSendCommand(prAdapter, prCmdInfo) == WLAN_STATUS_RESOURCES) { ++ ++ /* backup the command to wait response */ ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryAddress; ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ return WLAN_STATUS_PENDING; ++ } ++ /* send ok without response */ ++ nicCmdEventQueryAddress(prAdapter, prCmdInfo, (PUINT_8) prCmdBasicConfig); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if the device is in RF test mode ++* ++* @param pfnOidHandler Pointer to the OID handler ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->fgTestMode; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to identify 802.1x and Bluetooth-over-Wi-Fi ++* security frames, and queued into command queue for strict ordering ++* due to 802.1x frames before add-key OIDs are not to be encrypted ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prPacket Pointer of native packet ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket) ++{ ++ UINT_8 ucPriorityParam; ++ UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; ++ BOOLEAN fgIs1x = FALSE; ++ BOOLEAN fgIsPAL = FALSE; ++ UINT_32 u4PacketLen; ++ ULONG u4SysTime; ++ UINT_8 ucNetworkType; ++ P_CMD_INFO_T prCmdInfo; ++ UINT_8 ucCmdSeqNo = 0; ++ ++ /* 1x data packets */ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prPacket); ++ ++ /* retrieve some information for packet classification */ ++ if (kalQoSFrameClassifierAndPacketInfo(prAdapter->prGlueInfo, ++ prPacket, ++ &ucPriorityParam, ++ &u4PacketLen, ++ aucEthDestAddr, ++ &fgIs1x, ++ &fgIsPAL, ++ &ucNetworkType, ++ &ucCmdSeqNo) == TRUE) { ++ /* almost TRUE except frame length < 14B */ ++ ++ if (fgIs1x == FALSE) ++ return FALSE; ++ ++ /* get a free command entry */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ P_STA_RECORD_T prStaRec; ++ ++ /* fill arrival time */ ++ u4SysTime = (OS_SYSTIME) kalGetTimeTick(); ++ GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); ++ ++ kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); ++ ++ prCmdInfo->eCmdType = COMMAND_TYPE_SECURITY_FRAME; ++ prCmdInfo->u2InfoBufLen = (UINT_16) u4PacketLen; ++ prCmdInfo->pucInfoBuffer = NULL; ++ prCmdInfo->prPacket = prPacket; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNo; ++#if 0 ++ prCmdInfo->ucStaRecIndex = qmGetStaRecIdx(prAdapter, ++ aucEthDestAddr, ++ (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType); ++#endif ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType, ++ aucEthDestAddr); ++ if (prStaRec) ++ prCmdInfo->ucStaRecIndex = prStaRec->ucIndex; ++ else ++ prCmdInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ ++ prCmdInfo->eNetworkType = (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType; ++ prCmdInfo->pfCmdDoneHandler = wlanSecurityFrameTxDone; ++ prCmdInfo->pfCmdTimeoutHandler = wlanSecurityFrameTxTimeout; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ ++ /* ++ queue the 1x packet and we will send the packet to CONNSYS by ++ using command queue ++ */ ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* TRUE: means we have already handled it in the function */ ++ return TRUE; ++ } ++ ++ /* no memory, why assert ? can skip the packet ? */ ++ ASSERT(0); ++ return FALSE; ++ } ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi ++* security frames has been sent to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prCmdInfo Pointer of CMD_INFO_T ++* @param pucEventBuf meaningless, only for API compatibility ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->eNetworkType == NETWORK_TYPE_AIS_INDEX && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) { ++ ++ /* AIS counter measure so change RSN FSM to SEND_DEAUTH state */ ++ P_STA_RECORD_T prSta = cnmGetStaRecByIndex(prAdapter, prCmdInfo->ucStaRecIndex); ++ ++ if (prSta) { ++ kalMsleep(10); ++ secFsmEventEapolTxDone(prAdapter, prSta, TX_RESULT_SUCCESS); ++ } ++ } ++ ++ /* free the packet */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_SUCCESS); ++ DBGLOG(TX, INFO, "Security frame tx done, SeqNum: %d\n", prCmdInfo->ucCmdSeqNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi ++* security frames has failed sending to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prCmdInfo Pointer of CMD_INFO_T ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* free the packet */ ++ kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called before AIS is starting a new scan ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter) ++{ ++ BOOLEAN fgKeepCurrOne = FALSE; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* clear scanning result except current one */ ++ /* copy current one to prAdapter->rWlanInfo.arScanResult[0] */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { ++ fgKeepCurrOne = TRUE; ++ ++ if (i != 0) { ++ /* copy structure */ ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[0]), ++ &(prAdapter->rWlanInfo.arScanResult[i]), ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ } ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[i] != ++ &(prAdapter->rWlanInfo.aucScanIEBuf[0])) { ++ /* move IEs to head */ ++ kalMemCopy(prAdapter->rWlanInfo.aucScanIEBuf, ++ prAdapter->rWlanInfo.apucScanResultIEs[i], ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ } ++ /* modify IE pointer */ ++ prAdapter->rWlanInfo.apucScanResultIEs[0] = ++ &(prAdapter->rWlanInfo.aucScanIEBuf[0]); ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[0] = NULL; ++ } ++ ++ break; ++ } ++ } ++ } ++ ++ if (fgKeepCurrOne == TRUE) { ++ prAdapter->rWlanInfo.u4ScanResultNum = 1; ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage = ALIGN_4(prAdapter->rWlanInfo.arScanResult[0].u4IELength); ++ } else { ++ prAdapter->rWlanInfo.u4ScanResultNum = 0; ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage = 0; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when AIS received a beacon timeout event ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param arBSSID MAC address of the specified BSS ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID) ++{ ++ UINT_32 i, j, u4IELength = 0, u4IEMoveLength; ++ PUINT_8 pucIEPtr; ++ ++ ASSERT(prAdapter); ++ ++ /* clear the scanning result for arBSSID */ ++ i = 0; ++ while (1) { ++ if (i >= prAdapter->rWlanInfo.u4ScanResultNum) ++ break; ++ ++ if (EQUAL_MAC_ADDR(arBSSID, prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { ++ ++ /* backup current IE length */ ++ u4IELength = ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ pucIEPtr = prAdapter->rWlanInfo.apucScanResultIEs[i]; ++ ++ /* removed from middle */ ++ for (j = i + 1; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[j - 1]), ++ &(prAdapter->rWlanInfo.arScanResult[j]), ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[j - 1] = ++ prAdapter->rWlanInfo.apucScanResultIEs[j]; ++ } ++ ++ prAdapter->rWlanInfo.u4ScanResultNum--; ++ ++ /* remove IE buffer if needed := move rest of IE buffer */ ++ if (u4IELength > 0) { ++ u4IEMoveLength = prAdapter->rWlanInfo.u4ScanIEBufferUsage - ++ (((ULONG) pucIEPtr) + (ULONG) u4IELength - ++ ((ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])))); ++ ++ kalMemCopy(pucIEPtr, pucIEPtr + u4IELength, u4IEMoveLength); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4IELength; ++ ++ /* correction of pointers to IE buffer */ ++ for (j = 0; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[j] > pucIEPtr) { ++ prAdapter->rWlanInfo.apucScanResultIEs[j] = ++ (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[j]) - ++ u4IELength); ++ } ++ } ++ } ++ } ++ ++ i++; ++ } ++ ++} ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter) ++{ ++#if 0 ++ P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; ++ ++ prMsgFuncSwitch = ++ (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ if (!prMsgFuncSwitch) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prMsgFuncSwitch->fgIsFuncOn = TRUE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++} ++ ++VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter) ++{ ++ ++ P_MSG_P2P_CONNECTION_REQUEST_T prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ UINT_8 aucTargetDeviceID[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; ++ ++ prMsgConnReq = ++ (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ if (!prMsgConnReq) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prMsgConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ /*=====Param Modified for test=====*/ ++ COPY_MAC_ADDR(prMsgConnReq->aucDeviceID, aucTargetDeviceID); ++ prMsgConnReq->fgIsTobeGO = TRUE; ++ prMsgConnReq->fgIsPersistentGroup = FALSE; ++ ++ /*=====Param Modified for test=====*/ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgConnReq, MSG_SEND_METHOD_BUF); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve permanent address from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_EVENT_BASIC_CONFIG prEventBasicConfig; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryPermanentAddress"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* wait for response */ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG), /* 8B + 12B */ ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_BASIC_CONFIG) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (prEvent->aucBuffer); ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucPermanentAddress, &(prEventBasicConfig->rMyMacAddr)); ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, &(prEventBasicConfig->rMyMacAddr)); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve NIC capability from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_32 u4FwIDVersion = 0; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_EVENT_NIC_CAPABILITY prEventNicCapability; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryNicCapability"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ /* wait for FW response */ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_NIC_CAPABILITY) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventNicCapability = (P_EVENT_NIC_CAPABILITY) (prEvent->aucBuffer); ++ ++ prAdapter->rVerInfo.u2FwProductID = prEventNicCapability->u2ProductID; ++ prAdapter->rVerInfo.u2FwOwnVersion = prEventNicCapability->u2FwVersion; ++ prAdapter->rVerInfo.u2FwPeerVersion = prEventNicCapability->u2DriverVersion; ++ prAdapter->fgIsHw5GBandDisabled = (BOOLEAN) prEventNicCapability->ucHw5GBandDisabled; ++ prAdapter->fgIsEepromUsed = (BOOLEAN) prEventNicCapability->ucEepromUsed; ++ prAdapter->fgIsEfuseValid = (BOOLEAN) prEventNicCapability->ucEfuseValid; ++ prAdapter->fgIsEmbbededMacAddrValid = (BOOLEAN) prEventNicCapability->ucMacAddrValid; ++ ++ u4FwIDVersion = (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); ++ mtk_wcn_wmt_set_wifi_ver(u4FwIDVersion); ++#if (CFG_SUPPORT_TDLS == 1) ++ if (prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_TDLS)) ++ prAdapter->fgTdlsIsSup = TRUE; ++ DBGLOG(TDLS, TRACE, " support flag: 0x%x\n", prEventNicCapability->ucFeatureSet); ++#else ++ prAdapter->fgTdlsIsSup = 0; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ if (!(prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_5G_SUPPORT))) ++ prAdapter->fgEnable5GBand = FALSE; /* firmware does not support */ ++ ++#if CFG_ENABLE_CAL_LOG ++ DBGLOG(INIT, LOUD, " RF CAL FAIL = (%d),BB CAL FAIL = (%d)\n", ++ prEventNicCapability->ucRfCalFail, prEventNicCapability->ucBbCalFail); ++#endif ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve NIC capability from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC("wlanQueryDebugCode"); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE; ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_GET_DEBUG_CODE; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* send the command */ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to retrieve compiler flag from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryCompileFlag(IN P_ADAPTER_T prAdapter, IN UINT_32 u4QueryID, OUT PUINT_32 pu4CompilerFlag) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_CMD_SW_DBG_CTRL_T prCmdNicCompileFlag, prEventNicCompileFlag; ++ ++ ASSERT(prAdapter); ++ ++ DEBUGFUNC(__func__); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T)); ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_SW_DBG_CTRL; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = 0; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ /* Fill up SW CR */ ++ prCmdNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prWifiCmd->aucBuffer); ++ ++ prCmdNicCompileFlag->u4Id = u4QueryID; ++ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T), ++ &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ if (prEvent->ucEID != EVENT_ID_SW_DBG_CTRL) ++ return WLAN_STATUS_FAILURE; ++ ++ prEventNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prEvent->aucBuffer); ++ ++ *pu4CompilerFlag = prEventNicCompileFlag->u4Data; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter) ++{ ++ wlanQueryCompileFlag(prAdapter, 0xA0240000, &prAdapter->u4FwCompileFlag0); ++ wlanQueryCompileFlag(prAdapter, 0xA0240001, &prAdapter->u4FwCompileFlag1); ++ ++ DBGLOG(INIT, TRACE, ++ "Compile Flags: 0x%08x 0x%08x\n", prAdapter->u4FwCompileFlag0, prAdapter->u4FwCompileFlag1); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if defined(MT6628) ++static INT_32 wlanChangeCodeWord(INT_32 au4Input) ++{ ++ ++ UINT_16 i; ++#if TXPWR_USE_PDSLOPE ++ CODE_MAPPING_T arCodeTable[] = { ++ {0X100, -40}, ++ {0X104, -35}, ++ {0X128, -30}, ++ {0X14C, -25}, ++ {0X170, -20}, ++ {0X194, -15}, ++ {0X1B8, -10}, ++ {0X1DC, -5}, ++ {0, 0}, ++ {0X24, 5}, ++ {0X48, 10}, ++ {0X6C, 15}, ++ {0X90, 20}, ++ {0XB4, 25}, ++ {0XD8, 30}, ++ {0XFC, 35}, ++ {0XFF, 40}, ++ ++ }; ++#else ++ CODE_MAPPING_T arCodeTable[] = { ++ {0X100, 0x80}, ++ {0X104, 0x80}, ++ {0X128, 0x80}, ++ {0X14C, 0x80}, ++ {0X170, 0x80}, ++ {0X194, 0x94}, ++ {0X1B8, 0XB8}, ++ {0X1DC, 0xDC}, ++ {0, 0}, ++ {0X24, 0x24}, ++ {0X48, 0x48}, ++ {0X6C, 0x6c}, ++ {0X90, 0x7F}, ++ {0XB4, 0x7F}, ++ {0XD8, 0x7F}, ++ {0XFC, 0x7F}, ++ {0XFF, 0x7F}, ++ ++ }; ++#endif ++ ++ for (i = 0; i < sizeof(arCodeTable) / sizeof(CODE_MAPPING_T); i++) { ++ ++ if (arCodeTable[i].u4RegisterValue == au4Input) ++ return arCodeTable[i].i4TxpowerOffset; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if TXPWR_USE_PDSLOPE ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo) ++{ ++ UINT_8 ucCmdSeqNum; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_32 u4RxPktLength; ++ UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG)]; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_WIFI_EVENT_T prEvent; ++ P_CMD_ACCESS_REG prCmdMcrQuery; ++ ++ ASSERT(prAdapter); ++ ++ /* 1. Allocate CMD Info Packet and its Buffer */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_ACCESS_REG; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_ACCESS_REG); ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ kalMemCopy(prWifiCmd->aucBuffer, prMcrRdInfo, sizeof(CMD_ACCESS_REG)); ++ ++ wlanSendCommand(prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ ++ if (nicRxWaitResponse(prAdapter, ++ 1, ++ aucBuffer, ++ sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG), &u4RxPktLength) != WLAN_STATUS_SUCCESS) ++ return WLAN_STATUS_FAILURE; ++ /* header checking .. */ ++ prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; ++ if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) ++ return WLAN_STATUS_FAILURE; ++ ++ prEvent = (P_WIFI_EVENT_T) aucBuffer; ++ ++ if (prEvent->ucEID != EVENT_ID_ACCESS_REG) ++ return WLAN_STATUS_FAILURE; ++ ++ prCmdMcrQuery = (P_CMD_ACCESS_REG) (prEvent->aucBuffer); ++ prMcrRdInfo->u4McrOffset = prCmdMcrQuery->u4Address; ++ prMcrRdInfo->u4McrData = prCmdMcrQuery->u4Data; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++static INT_32 wlanIntRound(INT_32 au4Input) ++{ ++ ++ if (au4Input >= 0) { ++ if ((au4Input % 10) == 5) { ++ au4Input = au4Input + 5; ++ return au4Input; ++ } ++ } ++ ++ if (au4Input < 0) { ++ if ((au4Input % 10) == -5) { ++ au4Input = au4Input - 5; ++ return au4Input; ++ } ++ } ++ ++ return au4Input; ++} ++ ++static INT_32 wlanCal6628EfuseForm(IN P_ADAPTER_T prAdapter, INT_32 au4Input) ++{ ++ ++ PARAM_MCR_RW_STRUCT_T rMcrRdInfo; ++ INT_32 au4PdSlope, au4TxPwrOffset, au4TxPwrOffset_Round; ++ INT_8 auTxPwrOffset_Round; ++ ++ rMcrRdInfo.u4McrOffset = 0x60205c68; ++ rMcrRdInfo.u4McrData = 0; ++ au4TxPwrOffset = au4Input; ++ wlanQueryPdMcr(prAdapter, &rMcrRdInfo); ++ ++ au4PdSlope = (rMcrRdInfo.u4McrData) & BITS(0, 6); ++ au4TxPwrOffset_Round = wlanIntRound((au4TxPwrOffset * au4PdSlope)) / 10; ++ ++ au4TxPwrOffset_Round = -au4TxPwrOffset_Round; ++ ++ if (au4TxPwrOffset_Round < -128) ++ au4TxPwrOffset_Round = 128; ++ else if (au4TxPwrOffset_Round < 0) ++ au4TxPwrOffset_Round += 256; ++ else if (au4TxPwrOffset_Round > 127) ++ au4TxPwrOffset_Round = 127; ++ ++ auTxPwrOffset_Round = (UINT8) au4TxPwrOffset_Round; ++ ++ return au4TxPwrOffset_Round; ++} ++ ++#endif ++ ++#if defined(MT6628) ++static VOID wlanChangeNvram6620to6628(PUINT_8 pucEFUSE) ++{ ++ ++#define EFUSE_CH_OFFSET1_L_MASK_6620 BITS(0, 8) ++#define EFUSE_CH_OFFSET1_L_SHIFT_6620 0 ++#define EFUSE_CH_OFFSET1_M_MASK_6620 BITS(9, 17) ++#define EFUSE_CH_OFFSET1_M_SHIFT_6620 9 ++#define EFUSE_CH_OFFSET1_H_MASK_6620 BITS(18, 26) ++#define EFUSE_CH_OFFSET1_H_SHIFT_6620 18 ++#define EFUSE_CH_OFFSET1_VLD_MASK_6620 BIT(27) ++#define EFUSE_CH_OFFSET1_VLD_SHIFT_6620 27 ++ ++#define EFUSE_CH_OFFSET1_L_MASK_5931 BITS(0, 7) ++#define EFUSE_CH_OFFSET1_L_SHIFT_5931 0 ++#define EFUSE_CH_OFFSET1_M_MASK_5931 BITS(8, 15) ++#define EFUSE_CH_OFFSET1_M_SHIFT_5931 8 ++#define EFUSE_CH_OFFSET1_H_MASK_5931 BITS(16, 23) ++#define EFUSE_CH_OFFSET1_H_SHIFT_5931 16 ++#define EFUSE_CH_OFFSET1_VLD_MASK_5931 BIT(24) ++#define EFUSE_CH_OFFSET1_VLD_SHIFT_5931 24 ++#define EFUSE_ALL_CH_OFFSET1_MASK_5931 BITS(25, 27) ++#define EFUSE_ALL_CH_OFFSET1_SHIFT_5931 25 ++ ++ INT_32 au4ChOffset; ++ INT_16 au2ChOffsetL, au2ChOffsetM, au2ChOffsetH; ++ ++ au4ChOffset = *(UINT_32 *) (pucEFUSE + 72); ++ ++ if ((au4ChOffset & EFUSE_CH_OFFSET1_VLD_MASK_6620) && ((*(UINT_32 *) (pucEFUSE + 28)) == 0)) { ++ ++ au2ChOffsetL = ((au4ChOffset & EFUSE_CH_OFFSET1_L_MASK_6620) >> EFUSE_CH_OFFSET1_L_SHIFT_6620); ++ ++ au2ChOffsetM = ((au4ChOffset & EFUSE_CH_OFFSET1_M_MASK_6620) >> EFUSE_CH_OFFSET1_M_SHIFT_6620); ++ ++ au2ChOffsetH = ((au4ChOffset & EFUSE_CH_OFFSET1_H_MASK_6620) >> EFUSE_CH_OFFSET1_H_SHIFT_6620); ++ ++ au2ChOffsetL = wlanChangeCodeWord(au2ChOffsetL); ++ au2ChOffsetM = wlanChangeCodeWord(au2ChOffsetM); ++ au2ChOffsetH = wlanChangeCodeWord(au2ChOffsetH); ++ ++ au4ChOffset = 0; ++ au4ChOffset |= *(UINT_32 *) (pucEFUSE + 72) ++ >> (EFUSE_CH_OFFSET1_VLD_SHIFT_6620 - ++ EFUSE_CH_OFFSET1_VLD_SHIFT_5931) & EFUSE_CH_OFFSET1_VLD_MASK_5931; ++ ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetL) << EFUSE_CH_OFFSET1_L_SHIFT_5931) & EFUSE_CH_OFFSET1_L_MASK_5931); ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetM) << EFUSE_CH_OFFSET1_M_SHIFT_5931) & EFUSE_CH_OFFSET1_M_MASK_5931); ++ au4ChOffset |= ++ ((((UINT_32) au2ChOffsetH) << EFUSE_CH_OFFSET1_H_SHIFT_5931) & EFUSE_CH_OFFSET1_H_MASK_5931); ++ ++ *((INT_32 *) ((pucEFUSE + 28))) = au4ChOffset; ++ ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to load manufacture data from NVRAM ++* if available and valid ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param prRegInfo Pointer of REG_INFO_T ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ CMD_RDD_CH_T rRddParam; ++#endif ++ ++ ASSERT(prAdapter); ++ ++ /* 1. Version Check */ ++ kalGetConfigurationVersion(prAdapter->prGlueInfo, ++ &(prAdapter->rVerInfo.u2Part1CfgOwnVersion), ++ &(prAdapter->rVerInfo.u2Part1CfgPeerVersion), ++ &(prAdapter->rVerInfo.u2Part2CfgOwnVersion), ++ &(prAdapter->rVerInfo.u2Part2CfgPeerVersion)); ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ if (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION) { ++ return WLAN_STATUS_FAILURE; ++ } ++#endif ++ ++ /* MT6620 E1/E2 would be ignored directly */ ++ if (prAdapter->rVerInfo.u2Part1CfgOwnVersion == 0x0001) { ++ prRegInfo->ucTxPwrValid = 1; ++ } else { ++ /* 2. Load TX power gain parameters if valid */ ++ if (prRegInfo->ucTxPwrValid != 0) { ++ /* send to F/W */ ++ nicUpdateTxPower(prAdapter, (P_CMD_TX_PWR_T) (&(prRegInfo->rTxPwr))); ++ } ++ } ++ ++ /* Workaround for supporting 5G */ ++ prRegInfo->ucEnable5GBand = 1; ++ prRegInfo->ucSupport5GBand = 1; ++ ++ /* 3. Check if needs to support 5GHz */ ++ /* if(prRegInfo->ucEnable5GBand) { // Frank workaround */ ++ if (1) { ++ /* check if it is disabled by hardware */ ++ if (prAdapter->fgIsHw5GBandDisabled || prRegInfo->ucSupport5GBand == 0) ++ prAdapter->fgEnable5GBand = FALSE; ++ else ++ prAdapter->fgEnable5GBand = TRUE; ++ } else ++ prAdapter->fgEnable5GBand = FALSE; ++ /* Workaround for supporting 5G */ ++ prAdapter->fgEnable5GBand = TRUE; ++/* ++ DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d)\n", ++ prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled); ++*/ ++ /* 4. Send EFUSE data */ ++#if defined(MT6628) ++ wlanChangeNvram6620to6628(prRegInfo->aucEFUSE); ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PHY_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_PHY_PARAM_T), (PUINT_8) (prRegInfo->aucEFUSE), NULL, 0); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ rRddParam.ucRddTestMode = (UINT_8) prRegInfo->u4RddTestMode; ++ rRddParam.ucRddShutCh = (UINT_8) prRegInfo->u4RddShutFreq; ++ rRddParam.ucRddStartCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStartFreq); ++ rRddParam.ucRddStopCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStopFreq); ++ rRddParam.ucRddDfs = (UINT_8) prRegInfo->u4RddDfs; ++ prAdapter->ucRddStatus = 0; ++ nicUpdateRddTestMode(prAdapter, (P_CMD_RDD_CH_T) (&rRddParam)); ++#endif ++ ++ /* 5. Get 16-bits Country Code and Bandwidth */ ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = ++ (((UINT_16) prRegInfo->au2CountryCode[0]) << 8) | (((UINT_16) prRegInfo->au2CountryCode[1]) & BITS(0, 7)); ++ ++ DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d) CountryCode(0x%x 0x%x)\n", ++ prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled, ++ prRegInfo->au2CountryCode[0], prRegInfo->au2CountryCode[1]); ++ ++#if 0 /* Bandwidth control will be controlled by GUI. 20110930 ++ * So ignore the setting from registry/NVRAM ++ */ ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = ++ prRegInfo->uc2G4BwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = ++ prRegInfo->uc5GBwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; ++#endif ++ ++ /* 6. Set domain and channel information to chip */ ++ rlmDomainSendCmd(prAdapter, FALSE); ++ /* Update supported channel list in channel table */ ++ wlanUpdateChannelTable(prAdapter->prGlueInfo); ++ ++ /* 7. Set band edge tx power if available */ ++ if (prRegInfo->fg2G4BandEdgePwrUsed) { ++ CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; ++ ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK = prRegInfo->cBandEdgeMaxPwrCCK; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 = prRegInfo->cBandEdgeMaxPwrOFDM20; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 = prRegInfo->cBandEdgeMaxPwrOFDM40; ++ ++ DBGLOG(INIT, TRACE, "NVRAM 2G Bandedge CCK(%d) HT20(%d)HT40(%d)\n", ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK, ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_EDGE_TXPWR_LIMIT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); ++ } ++ /* 8. set 5G band edge tx power if available (add for 6625) */ ++ if (prAdapter->fgEnable5GBand) { ++#define NVRAM_5G_TX_BANDEDGE_VALID_OFFSET 10 ++#define NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET 11 ++#define NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET 12 ++ ++ if (prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_VALID_OFFSET]) { ++ CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; ++ ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 ++ = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET]; ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 ++ = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET]; ++ ++ DBGLOG(INIT, TRACE, "NVRAM 5G Bandedge HT20(%d)HT40(%d)\n", ++ rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); ++ } ++ } ++ /* 9. set RSSI compensation */ ++ /* DBGLOG(INIT, INFO, ("[frank] RSSI valid(%d) 2G(%d) 5G(%d)", ++ prRegInfo->fgRssiCompensationValidbit, ++ prRegInfo->uc2GRssiCompensation, ++ prRegInfo->uc5GRssiCompensation)); */ ++ if (prRegInfo->fgRssiCompensationValidbit) { ++ CMD_RSSI_COMPENSATE_T rCmdRssiCompensate; ++ ++ rCmdRssiCompensate.uc2GRssiCompensation = prRegInfo->uc2GRssiCompensation; ++ rCmdRssiCompensate.uc5GRssiCompensation = prRegInfo->uc5GRssiCompensation; ++ ++ DBGLOG(INIT, LOUD, "NVRAM RSSI Comp. 2G(%d)5G(%d)\n", ++ rCmdRssiCompensate.uc2GRssiCompensation, rCmdRssiCompensate.uc5GRssiCompensation); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RSSI_COMPENSATE, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_RSSI_COMPENSATE_T), (PUINT_8)&rCmdRssiCompensate, NULL, 0); ++ } ++ /* 10. notify FW Band Support 5G */ ++ if (prAdapter->fgEnable5GBand) { ++ CMD_BAND_SUPPORT_T rCmdBandSupport; ++ ++ rCmdBandSupport.uc5GBandSupport = TRUE; ++ DBGLOG(INIT, TRACE, "NVRAM 5G BandSupport\n"); ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BAND_SUPPORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_BAND_SUPPORT_T), (PUINT_8)&rCmdBandSupport, NULL, 0); ++ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check ++* Media Stream Mode is set to non-default value or not, ++* and clear to default value if above criteria is met ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return TRUE ++* The media stream mode was non-default value and has been reset ++* FALSE ++* The media stream mode is default value ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode != 0) { ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if any pending timer has expired ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* check timer status */ ++ cnmTimerDoTimeOutCheck(prAdapter); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to check if any pending mailbox message ++* to be handled ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { /* MBOX_ID_TOTAL_NUM = 1 */ ++ mboxRcvAllMsg(prAdapter, (ENUM_MBOX_ID_T) i); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to enqueue a single TX packet into CORE ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* prNativePacket Pointer of Native Packet ++* ++* @return WLAN_STATUS_SUCCESS ++* WLAN_STATUS_RESOURCES ++* WLAN_STATUS_INVALID_PACKET ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* get a free packet header */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo == NULL) ++ return WLAN_STATUS_RESOURCES; ++ ++ prMsduInfo->eSrc = TX_PACKET_OS; ++ ++ if (nicTxFillMsduInfo(prAdapter, prMsduInfo, prNativePacket) == FALSE) { ++ /* packet is not extractable */ ++ ++ /* fill fails */ ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_INVALID_PACKET); ++ ++ nicTxReturnMsduInfo(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_INVALID_PACKET; ++ } ++ /* enqueue to QM */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to flush pending TX packets in CORE ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return nicTxFlush(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function sends pending MSDU_INFO_T to MT6620 ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pfgHwAccess Pointer for tracking LP-OWN status ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ ASSERT(pfgHwAccess); ++ ++ /* <1> dequeue packets by txDequeuTxPackets() */ ++ /* Note: prMsduInfo is a packet list queue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prMsduInfo = qmDequeueTxPackets(prAdapter, &prTxCtrl->rTc); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prMsduInfo != NULL) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { ++ /* <2> Acquire LP-OWN if necessary */ ++ if (*pfgHwAccess == FALSE) { ++ *pfgHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prAdapter); ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ /* <3> send packet"s" to HIF */ ++ nicTxMsduInfoList(prAdapter, prMsduInfo); ++ ++ /* <4> update TC by txAdjustTcQuotas() */ ++ nicTxAdjustTcq(prAdapter); ++ } else ++ wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); /* free the packet */ ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to acquire power control from firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* do driver own */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++ ++ /* Reset sleepy state *//* no use */ ++ if (prAdapter->fgWiFiInSleepyState == TRUE) ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to release power control to firmware ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* do FW own */ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to report currently pending TX frames count ++* (command packets are not included) ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return number of pending TX frames ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ UINT_32 u4Num; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* number in prTxQueue + number in RX forward */ ++ u4Num = kalGetTxPendingFrameCount(prAdapter->prGlueInfo) + (UINT_32) (prTxCtrl->i4PendingFwdFrameCount); ++ ++ return u4Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to report current ACPI state ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return ACPI_STATE_D0 Normal Operation Mode ++* ACPI_STATE_D3 Suspend Mode ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rAcpiState; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to update current ACPI state only ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param ePowerState ACPI_STATE_D0 Normal Operation Mode ++* ACPI_STATE_D3 Suspend Mode ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState) ++{ ++ ASSERT(prAdapter); ++ ASSERT(ePowerState <= ACPI_STATE_D3); ++ ++ prAdapter->rAcpiState = ePowerState; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to query ECO version from HIFSYS CR ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return zero Unable to retrieve ECO version information ++* non-zero ECO version (1-based) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (nicVerifyChipID(prAdapter) == TRUE) ++ return prAdapter->ucRevID + 1; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to setting the default Tx Power configuration ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return zero Unable to retrieve ECO version information ++* non-zero ECO version (1-based) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 i; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ P_SET_TXPWR_CTRL_T prTxpwr; ++ ++ ASSERT(prGlueInfo); ++ ++ prTxpwr = &prGlueInfo->rTxPwr; ++ ++ prTxpwr->c2GLegacyStaPwrOffset = 0; ++ prTxpwr->c2GHotspotPwrOffset = 0; ++ prTxpwr->c2GP2pPwrOffset = 0; ++ prTxpwr->c2GBowPwrOffset = 0; ++ prTxpwr->c5GLegacyStaPwrOffset = 0; ++ prTxpwr->c5GHotspotPwrOffset = 0; ++ prTxpwr->c5GP2pPwrOffset = 0; ++ prTxpwr->c5GBowPwrOffset = 0; ++ prTxpwr->ucConcurrencePolicy = 0; ++ for (i = 0; i < 3; i++) ++ prTxpwr->acReserved1[i] = 0; ++ ++ for (i = 0; i < 14; i++) ++ prTxpwr->acTxPwrLimit2G[i] = 63; ++ ++ for (i = 0; i < 4; i++) ++ prTxpwr->acTxPwrLimit5G[i] = 63; ++ ++ for (i = 0; i < 2; i++) ++ prTxpwr->acReserved2[i] = 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* set preferred band configuration corresponding to network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eBand Given band ++* @param eNetTypeIndex Given Network Type ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eBand <= BAND_NUM); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ /* 1. set prefer band according to network type */ ++ prAdapter->aePreferBand[eNetTypeIndex] = eBand; ++ ++ /* 2. remove buffered BSS descriptors correspondingly */ ++ if (eBand == BAND_2G4) ++ scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_5G, eNetTypeIndex); ++ else if (eBand == BAND_5G) ++ scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_2G4, eNetTypeIndex); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* get channel information corresponding to specified network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eNetTypeIndex Given Network Type ++* ++* @return channel number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ return prBssInfo->ucPrimaryChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* get BSS descriptor information corresponding to specified network type ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* @param eNetTypeIndex Given Network Type ++* ++* @return pointer to BSS_DESC_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ return prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; ++ ++ case NETWORK_TYPE_P2P_INDEX: ++ return NULL; ++ ++ case NETWORK_TYPE_BOW_INDEX: ++ return prAdapter->rWifiVar.rBowFsmInfo.prTargetBssDesc; ++ ++ default: ++ return NULL; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to ++* check unconfigured system properties and generate related message on ++* scan list to notify users ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter) ++{ ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) || (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ const UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ BOOLEAN fgIsConfExist = TRUE; ++ BOOLEAN fgGenErrMsg = FALSE; ++ P_REG_INFO_T prRegInfo = NULL; ++ P_WLAN_BEACON_FRAME_T prBeacon = NULL; ++ P_IE_SSID_T prSsid = NULL; ++ UINT_32 u4ErrCode = 0; ++ UINT_8 aucErrMsg[32]; ++ PARAM_SSID_T rSsid; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ PARAM_RATES_EX rSupportedRates; ++#endif ++ ++ DEBUGFUNC("wlanCheckSystemConfiguration"); ++ ++ ASSERT(prAdapter); ++ ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) ++ if (kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) { ++ fgIsConfExist = FALSE; ++ fgGenErrMsg = TRUE; ++ } ++#endif ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++ prRegInfo = kalGetConfiguration(prAdapter->prGlueInfo); ++ ++ if (fgIsConfExist == TRUE && (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion ++ || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ || prAdapter->fgIsPowerLimitTableValid == FALSE ++#endif ++ || (prAdapter->fgIsEmbbededMacAddrValid == FALSE && ++ (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) ++ || prRegInfo->ucTxPwrValid == 0)) ++ fgGenErrMsg = TRUE; ++#endif ++ ++ if (fgGenErrMsg == TRUE) { ++ prBeacon = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); ++ if (!prBeacon) { ++ ASSERT(FALSE); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* initialization */ ++ kalMemZero(prBeacon, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); ++ ++ /* prBeacon initialization */ ++ prBeacon->u2FrameCtrl = MAC_FRAME_BEACON; ++ COPY_MAC_ADDR(prBeacon->aucDestAddr, aucBCAddr); ++ COPY_MAC_ADDR(prBeacon->aucSrcAddr, aucZeroMacAddr); ++ COPY_MAC_ADDR(prBeacon->aucBSSID, aucZeroMacAddr); ++ prBeacon->u2BeaconInterval = 100; ++ prBeacon->u2CapInfo = CAP_INFO_ESS; ++ ++ /* prSSID initialization */ ++ prSsid = (P_IE_SSID_T) (&prBeacon->aucInfoElem[0]); ++ prSsid->ucId = ELEM_ID_SSID; ++ ++ /* rConfiguration initialization */ ++ rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ rConfiguration.u4BeaconPeriod = 100; ++ rConfiguration.u4ATIMWindow = 1; ++ rConfiguration.u4DSConfig = 2412; ++ rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ /* rSupportedRates initialization */ ++ kalMemZero(rSupportedRates, sizeof(PARAM_RATES_EX)); ++ } ++#if (CFG_NVRAM_EXISTENCE_CHECK == 1) ++#define NVRAM_ERR_MSG "NVRAM WARNING: Err = 0x01" ++ if ((kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) && (prBeacon) && (prSsid)) { ++ COPY_SSID(prSsid->aucSSID, prSsid->ucLength, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBeacon, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + prSsid->ucLength, ++ 1, 0); ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ nicAddScanResult(prAdapter, ++ prBeacon->aucBSSID, ++ &rSsid, ++ 0, ++ 0, ++ PARAM_NETWORK_TYPE_FH, ++ &rConfiguration, ++ NET_TYPE_INFRA, ++ rSupportedRates, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + prSsid->ucLength - ++ WLAN_MAC_MGMT_HEADER_LEN, (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); ++ } ++#endif ++ ++#if (CFG_SW_NVRAM_VERSION_CHECK == 1) ++#define VER_ERR_MSG "NVRAM WARNING: Err = 0x%02X" ++ if ((fgIsConfExist == TRUE) && (prBeacon) && (prSsid)) { ++ if ((CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion ++ || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION ++ || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ ++ || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion ++ || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION)) ++ u4ErrCode |= NVRAM_ERROR_VERSION_MISMATCH; ++ ++ if (prRegInfo->ucTxPwrValid == 0) ++ u4ErrCode |= NVRAM_ERROR_INVALID_TXPWR; ++ ++ if (prAdapter->fgIsEmbbededMacAddrValid == FALSE && (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) ++ || EQUAL_MAC_ADDR(aucZeroMacAddr, ++ prRegInfo->aucMacAddr))) ++ u4ErrCode |= NVRAM_ERROR_INVALID_MAC_ADDR; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ if (prAdapter->fgIsPowerLimitTableValid == FALSE) ++ u4ErrCode |= NVRAM_POWER_LIMIT_TABLE_INVALID; ++#endif ++ if (u4ErrCode != 0) { ++ sprintf(aucErrMsg, VER_ERR_MSG, (unsigned int)u4ErrCode); ++ COPY_SSID(prSsid->aucSSID, prSsid->ucLength, aucErrMsg, strlen(aucErrMsg)); ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBeacon, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + ++ prSsid->ucLength, 1, 0); ++ ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); ++ nicAddScanResult(prAdapter, ++ prBeacon->aucBSSID, ++ &rSsid, ++ 0, ++ 0, ++ PARAM_NETWORK_TYPE_FH, ++ &rConfiguration, ++ NET_TYPE_INFRA, ++ rSupportedRates, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, ++ aucSSID) + ++ prSsid->ucLength - WLAN_MAC_MGMT_HEADER_LEN, ++ (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); ++ } ++ } ++#endif ++ ++ if (fgGenErrMsg == TRUE) ++ cnmMemFree(prAdapter, prBeacon); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prStaRec, prTempStaRec; ++ P_PARAM_GET_STA_STATISTICS prQueryStaStatistics; ++ UINT_8 ucStaRecIdx; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ CMD_GET_STA_STATISTICS_T rQueryCmdStaStatistics; ++ UINT_8 ucIdx; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ do { ++ ASSERT(pvQueryBuffer); ++ ++ /* 4 1. Sanity test */ ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(PARAM_GET_STA_STA_STATISTICS)) { ++ *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ prQueryStaStatistics = (P_PARAM_GET_STA_STATISTICS) pvQueryBuffer; ++ *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ ++ /* 4 5. Get driver global QM counter */ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { ++ prQueryStaStatistics->au4TcAverageQueLen[ucIdx] = prQM->au4AverageQueLen[ucIdx]; ++ prQueryStaStatistics->au4TcCurrentQueLen[ucIdx] = prQM->au4CurrentTcResource[ucIdx]; ++ } ++ ++ /* 4 2. Get StaRec by MAC address */ ++ prStaRec = NULL; ++ ++ for (ucStaRecIdx = 0; ucStaRecIdx < CFG_NUM_OF_STA_RECORD; ucStaRecIdx++) { ++ prTempStaRec = &(prAdapter->arStaRec[ucStaRecIdx]); ++ if (prTempStaRec->fgIsValid && prTempStaRec->fgIsInUse) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prQueryStaStatistics->aucMacAddr)) { ++ prStaRec = prTempStaRec; ++ break; ++ } ++ } ++ } ++ ++ if (!prStaRec) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ prQueryStaStatistics->u4Flag |= BIT(0); ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ /* 4 3. Get driver statistics */ ++ DBGLOG(TX, INFO, "skbToDriver %lld, skbFreed: %lld\n", ++ prAdapter->prGlueInfo->u8SkbToDriver, ++ prAdapter->prGlueInfo->u8SkbFreed); ++ prAdapter->prGlueInfo->u8SkbFreed = 0; ++ prAdapter->prGlueInfo->u8SkbToDriver = 0; ++ ++ prQueryStaStatistics->u4TxTotalCount = prStaRec->u4TotalTxPktsNumber; ++ prQueryStaStatistics->u4TxExceedThresholdCount = prStaRec->u4ThresholdCounter; ++ prQueryStaStatistics->u4TxMaxTime = prStaRec->u4MaxTxPktsTime; ++ prQueryStaStatistics->u4TxMaxHifTime = prStaRec->u4MaxTxPktsHifTime; ++ if (prStaRec->u4TotalTxPktsNumber) { ++ prQueryStaStatistics->u4TxAverageProcessTime = ++ (prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber); ++ prQueryStaStatistics->u4TxAverageHifTime = ++ (prStaRec->u4TotalTxPktsHifTime / prStaRec->u4TotalTxPktsNumber); ++ } else ++ prQueryStaStatistics->u4TxAverageProcessTime = 0; ++ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { ++ prQueryStaStatistics->au4TcResourceEmptyCount[ucIdx] = ++ prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx]; ++ /* Reset */ ++ prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceBackCount[ucIdx] = ++ prQM->au4QmTcResourceBackCounter[ucIdx]; ++ prQM->au4QmTcResourceBackCounter[ucIdx] = 0; ++ ++ prQueryStaStatistics->au4DequeueNoTcResource[ucIdx] = ++ prQM->au4DequeueNoTcResourceCounter[ucIdx]; ++ prQM->au4DequeueNoTcResourceCounter[ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceUsedCount[ucIdx] = ++ prQM->au4ResourceUsedCounter[ucIdx]; ++ prQM->au4ResourceUsedCounter[ucIdx] = 0; ++ prQueryStaStatistics->au4TcResourceWantedCount[ucIdx] = ++ prQM->au4ResourceWantedCounter[ucIdx]; ++ prQM->au4ResourceWantedCounter[ucIdx] = 0; ++ } ++ ++ prQueryStaStatistics->u4EnqueueCounter = prQM->u4EnqeueuCounter; ++ prQueryStaStatistics->u4DequeueCounter = prQM->u4DequeueCounter; ++ prQueryStaStatistics->u4EnqueueStaCounter = prStaRec->u4EnqeueuCounter; ++ prQueryStaStatistics->u4DequeueStaCounter = prStaRec->u4DeqeueuCounter; ++ ++ prQueryStaStatistics->IsrCnt = prGlueInfo->IsrCnt - prGlueInfo->IsrPreCnt; ++ prQueryStaStatistics->IsrPassCnt = prGlueInfo->IsrPassCnt - prGlueInfo->IsrPrePassCnt; ++ prQueryStaStatistics->TaskIsrCnt = prGlueInfo->TaskIsrCnt - prGlueInfo->TaskPreIsrCnt; ++ ++ prQueryStaStatistics->IsrAbnormalCnt = prGlueInfo->IsrAbnormalCnt; ++ prQueryStaStatistics->IsrSoftWareCnt = prGlueInfo->IsrSoftWareCnt; ++ prQueryStaStatistics->IsrRxCnt = prGlueInfo->IsrRxCnt; ++ prQueryStaStatistics->IsrTxCnt = prGlueInfo->IsrTxCnt; ++ ++ /* 4 4.1 Reset statistics */ ++ prStaRec->u4ThresholdCounter = 0; ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsHifTime = 0; ++ ++ prStaRec->u4EnqeueuCounter = 0; ++ prStaRec->u4DeqeueuCounter = 0; ++ ++ prQM->u4EnqeueuCounter = 0; ++ prQM->u4DequeueCounter = 0; ++ ++ prGlueInfo->IsrPreCnt = prGlueInfo->IsrCnt; ++ prGlueInfo->IsrPrePassCnt = prGlueInfo->IsrPassCnt; ++ prGlueInfo->TaskPreIsrCnt = prGlueInfo->TaskIsrCnt; ++ prGlueInfo->IsrAbnormalCnt = 0; ++ prGlueInfo->IsrSoftWareCnt = 0; ++ prGlueInfo->IsrRxCnt = 0; ++ prGlueInfo->IsrTxCnt = 0; ++#endif ++ ++ for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) ++ prQueryStaStatistics->au4TcQueLen[ucIdx] = prStaRec->arTxQueue[ucIdx].u4NumElem; ++ ++ rResult = WLAN_STATUS_SUCCESS; ++ ++ /* 4 6. Ensure FW supports get station link status */ ++ if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { ++ ++ rQueryCmdStaStatistics.ucIndex = prStaRec->ucIndex; ++ COPY_MAC_ADDR(rQueryCmdStaStatistics.aucMacAddr, prQueryStaStatistics->aucMacAddr); ++ rQueryCmdStaStatistics.ucReadClear = TRUE; ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STA_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStaStatistics, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_STA_STATISTICS_T), ++ (PUINT_8)&rQueryCmdStaStatistics, ++ pvQueryBuffer, u4QueryBufferLen); ++ ++ prQueryStaStatistics->u4Flag |= BIT(1); ++ } else { ++ rResult = WLAN_STATUS_NOT_SUPPORTED; ++ } ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++WLAN_STATUS ++wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ /* P_PARAM_GET_CHN_LOAD prQueryChnLoad; */ ++ P_PARAM_GET_LTE_MODE prLteMode; ++ CMD_GET_LTE_SAFE_CHN_T rQuery_LTE_SAFE_CHN; ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]wlanoidQueryACSChannelList\n"); ++ do { ++ ASSERT(pvQueryBuffer); ++ ++ /* 4 1. Sanity test */ ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ prLteMode = (P_PARAM_GET_LTE_MODE) pvQueryBuffer; ++ ++ /* 4 3. Ensure FW supports get station link status */ ++#if 0 ++ if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ rCmdAccessReg.u4Address = 0xFFFFFFFF; ++ rCmdAccessReg.u4Data = ELEM_RM_TYPE_ACS_CHN; ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ TRUE, ++ TRUE, ++ /* The handler to receive firmware notification */ ++ nicCmdEventQueryChannelLoad, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8)&rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); ++ ++ prQueryChnLoad->u4Flag |= BIT(1); ++ } else { ++ rResult = WLAN_STATUS_NOT_SUPPORTED; ++ } ++#endif ++ /* 4 4.Avoid LTE Channels */ ++ prLteMode->u4Flags &= BIT(0); ++ /*if(prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) */ { ++ ++ rResult = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LTE_CHN, ++ FALSE, ++ TRUE, ++ /* Query ID */ ++ TRUE, ++ /* The handler to receive firmware notification */ ++ nicCmdEventQueryLTESafeChn, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_LTE_SAFE_CHN_T), ++ (PUINT_8)&rQuery_LTE_SAFE_CHN, ++ pvQueryBuffer, u4QueryBufferLen); ++ ++ DBGLOG(P2P, INFO, "[Auto Channel] Get LTE Channels\n"); ++ prLteMode->u4Flags |= BIT(1); ++ } ++ ++ /* 4 5. Calc the value */ ++ ++ DBGLOG(P2P, INFO, "[Auto Channel] Candidated Channels\n"); ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++#endif ++#if CFG_SUPPORT_CFG_FILE ++ ++P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 i; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ASSERT(pucKey); ++ ++ prWlanCfgEntry = NULL; ++ ++ for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; ++ if (prWlanCfgEntry->aucKey[0] != '\0') { ++ DBGLOG(INIT, LOUD, "compare key %s saved key %s\n", pucKey, prWlanCfgEntry->aucKey); ++ if (kalStrniCmp(pucKey, prWlanCfgEntry->aucKey, WLAN_CFG_KEY_LEN_MAX - 1) == 0) ++ return prWlanCfgEntry; ++ } ++ } ++ ++ DBGLOG(INIT, LOUD, "wifi config there is no entry \'%s\'\n", pucKey); ++ return NULL; ++ ++} ++ ++WLAN_STATUS wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ASSERT(pucValue); ++ ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ kalStrnCpy(pucValue, prWlanCfgEntry->aucValue, WLAN_CFG_VALUE_LEN_MAX - 1); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (pucValueDef) ++ kalStrnCpy(pucValue, pucValueDef, WLAN_CFG_VALUE_LEN_MAX - 1); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef) ++{ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 u4Value; ++ INT_32 u4Ret; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ u4Value = u4ValueDef; ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ u4Ret = kalkStrtou32(prWlanCfgEntry->aucValue, 0, &u4Value); ++ if (u4Ret) ++ DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue u4Ret=%u\n", u4Ret); ++ /* u4Value = kalStrtoul(prWlanCfgEntry->aucValue, NULL, 0); */ ++ } ++ ++ return u4Value; ++} ++ ++INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef) ++{ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ INT_32 i4Value; ++ INT_32 i4Ret; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ i4Value = i4ValueDef; ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ i4Ret = kalkStrtos32(prWlanCfgEntry->aucValue, 0, &i4Value); ++ /* i4Ret = kalStrtol(prWlanCfgEntry->aucValue, NULL, 0); */ ++ if (i4Ret) ++ DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue i4Ret=%u\n\r", i4Ret); ++ } ++ ++ return i4Value; ++} ++ ++WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_32 u4EntryIndex; ++ UINT_32 i; ++ UINT_8 ucExist; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ASSERT(prWlanCfg); ++ ASSERT(pucKey); ++ ++ /* Find the exist */ ++ ucExist = 0; ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (!prWlanCfgEntry) { ++ /* Find the empty */ ++ for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; ++ if (prWlanCfgEntry->aucKey[0] == '\0') ++ break; ++ } ++ ++ u4EntryIndex = i; ++ if (u4EntryIndex < WLAN_CFG_ENTRY_NUM_MAX) { ++ prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[u4EntryIndex]; ++ kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); ++ } else { ++ prWlanCfgEntry = NULL; ++ DBGLOG(INIT, ERROR, "wifi config there is no empty entry\n"); ++ } ++ } /* !prWlanCfgEntry */ ++ else ++ ucExist = 1; ++ ++ if (prWlanCfgEntry) { ++ if (ucExist == 0) { ++ kalStrnCpy(prWlanCfgEntry->aucKey, pucKey, WLAN_CFG_KEY_LEN_MAX - 1); ++ prWlanCfgEntry->aucKey[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; ++ } ++ ++ if (pucValue && pucValue[0] != '\0') { ++ kalStrnCpy(prWlanCfgEntry->aucValue, pucValue, WLAN_CFG_VALUE_LEN_MAX - 1); ++ prWlanCfgEntry->aucValue[WLAN_CFG_VALUE_LEN_MAX - 1] = '\0'; ++ ++ if (ucExist) { ++ if (prWlanCfgEntry->pfSetCb) ++ prWlanCfgEntry->pfSetCb(prAdapter, ++ prWlanCfgEntry->aucKey, ++ prWlanCfgEntry->aucValue, prWlanCfgEntry->pPrivate, 0); ++ } ++ } else { ++ /* Call the pfSetCb if value is empty ? */ ++ /* remove the entry if value is empty */ ++ kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); ++ } ++ ++ } ++ /* prWlanCfgEntry */ ++ if (prWlanCfgEntry) { ++ DBGLOG(INIT, LOUD, "Set wifi config exist %u \'%s\' \'%s\'\n", ++ ucExist, prWlanCfgEntry->aucKey, prWlanCfgEntry->aucValue); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (pucKey) ++ DBGLOG(INIT, ERROR, "Set wifi config error key \'%s\'\n", pucKey); ++ if (pucValue) ++ DBGLOG(INIT, ERROR, "Set wifi config error value \'%s\'\n", pucValue); ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++WLAN_STATUS ++wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags) ++{ ++ ++ P_WLAN_CFG_ENTRY_T prWlanCfgEntry; ++ P_WLAN_CFG_T prWlanCfg; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ASSERT(prWlanCfg); ++ ++ /* Find the exist */ ++ prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); ++ ++ if (prWlanCfgEntry) { ++ prWlanCfgEntry->pfSetCb = pfSetCb; ++ prWlanCfgEntry->pPrivate = pPrivate; ++ } ++ ++ if (prWlanCfgEntry) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++ ++} ++ ++WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value) ++{ ++ ++ P_WLAN_CFG_T prWlanCfg; ++ UINT_8 aucBuf[WLAN_CFG_VALUE_LEN_MAX]; ++ ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ ASSERT(prWlanCfg); ++ ++ kalMemZero(aucBuf, sizeof(aucBuf)); ++ ++ kalSnprintf(aucBuf, WLAN_CFG_VALUE_LEN_MAX, "0x%x", (unsigned int)u4Value); ++ ++ return wlanCfgSet(prAdapter, pucKey, aucBuf, 0); ++} ++ ++enum { ++ STATE_EOF = 0, ++ STATE_TEXT = 1, ++ STATE_NEWLINE = 2 ++}; ++ ++struct WLAN_CFG_PARSE_STATE_S { ++ CHAR *ptr; ++ CHAR *text; ++ INT_32 nexttoken; ++ UINT_32 maxSize; ++}; ++ ++INT_32 wlanCfgFindNextToken(struct WLAN_CFG_PARSE_STATE_S *state) ++{ ++ CHAR *x = state->ptr; ++ CHAR *s; ++ ++ if (state->nexttoken) { ++ INT_32 t = state->nexttoken; ++ ++ state->nexttoken = 0; ++ return t; ++ } ++ ++ for (;;) { ++ switch (*x) { ++ case 0: ++ state->ptr = x; ++ return STATE_EOF; ++ case '\n': ++ x++; ++ state->ptr = x; ++ return STATE_NEWLINE; ++ case ' ': ++ case '\t': ++ case '\r': ++ x++; ++ continue; ++ case '#': ++ while (*x && (*x != '\n')) ++ x++; ++ if (*x == '\n') { ++ state->ptr = x + 1; ++ return STATE_NEWLINE; ++ } ++ state->ptr = x; ++ return STATE_EOF; ++ default: ++ goto text; ++ } ++ } ++ ++textdone: ++ state->ptr = x; ++ *s = 0; ++ return STATE_TEXT; ++text: ++ state->text = s = x; ++textresume: ++ for (;;) { ++ switch (*x) { ++ case 0: ++ goto textdone; ++ case ' ': ++ case '\t': ++ case '\r': ++ x++; ++ goto textdone; ++ case '\n': ++ state->nexttoken = STATE_NEWLINE; ++ x++; ++ goto textdone; ++ case '"': ++ x++; ++ for (;;) { ++ switch (*x) { ++ case 0: ++ /* unterminated quoted thing */ ++ state->ptr = x; ++ return STATE_EOF; ++ case '"': ++ x++; ++ goto textresume; ++ default: ++ *s++ = *x++; ++ } ++ } ++ break; ++ case '\\': ++ x++; ++ switch (*x) { ++ case 0: ++ goto textdone; ++ case 'n': ++ *s++ = '\n'; ++ break; ++ case 'r': ++ *s++ = '\r'; ++ break; ++ case 't': ++ *s++ = '\t'; ++ break; ++ case '\\': ++ *s++ = '\\'; ++ break; ++ case '\r': ++ /* \ -> line continuation */ ++ if (x[1] != '\n') { ++ x++; ++ continue; ++ } ++ case '\n': ++ /* \ -> line continuation */ ++ x++; ++ /* eat any extra whitespace */ ++ while ((*x == ' ') || (*x == '\t')) ++ x++; ++ continue; ++ default: ++ /* unknown escape -- just copy */ ++ *s++ = *x++; ++ } ++ continue; ++ default: ++ *s++ = *x++; ++ } ++ } ++ return STATE_EOF; ++} ++ ++WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]) ++{ ++ struct WLAN_CFG_PARSE_STATE_S state; ++ CHAR **args; ++ INT_32 nargs; ++ ++ if (cmdLine == NULL || argc == NULL || argv == NULL) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ args = argv; ++ nargs = 0; ++ state.ptr = cmdLine; ++ state.nexttoken = 0; ++ state.maxSize = 0; ++ ++ if (kalStrnLen(cmdLine, 512) >= 512) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ for (;;) { ++ switch (wlanCfgFindNextToken(&state)) { ++ case STATE_EOF: ++ goto exit; ++ case STATE_NEWLINE: ++ goto exit; ++ case STATE_TEXT: ++ if (nargs < WLAN_CFG_ARGV_MAX) ++ args[nargs++] = state.text; ++ break; ++ } ++ } ++ ++exit: ++ *argc = nargs; ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanCfgParseAddEntry(IN P_ADAPTER_T prAdapter, ++ PUINT_8 pucKeyHead, PUINT_8 pucKeyTail, PUINT_8 pucValueHead, PUINT_8 pucValueTail) ++{ ++ ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ UINT_32 u4Len; ++ ++ kalMemZero(aucKey, sizeof(aucKey)); ++ kalMemZero(aucValue, sizeof(aucValue)); ++ ++ if ((pucKeyHead == NULL) ++ || (pucValueHead == NULL) ++ ) ++ return WLAN_STATUS_FAILURE; ++ ++ if (pucKeyTail) { ++ if (pucKeyHead > pucKeyTail) ++ return WLAN_STATUS_FAILURE; ++ u4Len = pucKeyTail - pucKeyHead + 1; ++ } else ++ u4Len = kalStrnLen(pucKeyHead, WLAN_CFG_KEY_LEN_MAX - 1); ++ ++ if (u4Len >= WLAN_CFG_KEY_LEN_MAX) ++ u4Len = WLAN_CFG_KEY_LEN_MAX - 1; ++ ++ if (u4Len < WLAN_CFG_VALUE_LEN_MAX) ++ kalStrnCpy(aucKey, pucKeyHead, u4Len); ++ else ++ DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); ++ ++ if (pucValueTail) { ++ if (pucValueHead > pucValueTail) ++ return WLAN_STATUS_FAILURE; ++ u4Len = pucValueTail - pucValueHead + 1; ++ } else ++ u4Len = kalStrnLen(pucValueHead, WLAN_CFG_VALUE_LEN_MAX - 1); ++ ++ if (u4Len >= WLAN_CFG_VALUE_LEN_MAX) ++ u4Len = WLAN_CFG_VALUE_LEN_MAX - 1; ++ ++ if (u4Len < WLAN_CFG_VALUE_LEN_MAX) ++ kalStrnCpy(aucValue, pucValueHead, u4Len); ++ else ++ DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); ++ ++ return wlanCfgSet(prAdapter, aucKey, aucValue, 0); ++} ++ ++enum { ++ WAIT_KEY_HEAD = 0, ++ WAIT_KEY_TAIL, ++ WAIT_VALUE_HEAD, ++ WAIT_VALUE_TAIL, ++ WAIT_COMMENT_TAIL ++}; ++ ++WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen) ++{ ++ ++ struct WLAN_CFG_PARSE_STATE_S state; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; ++ CHAR **args; ++ INT_32 nargs; ++ ++ if (pucConfigBuf == NULL) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ if (kalStrnLen(pucConfigBuf, 4000) >= 4000) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ if (u4ConfigBufLen == 0) ++ return WLAN_STATUS_FAILURE; ++ args = apcArgv; ++ nargs = 0; ++ state.ptr = pucConfigBuf; ++ state.nexttoken = 0; ++ state.maxSize = u4ConfigBufLen; ++ ++ for (;;) { ++ switch (wlanCfgFindNextToken(&state)) { ++ case STATE_EOF: ++ if (nargs > 1) ++ wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); ++ goto exit; ++ case STATE_NEWLINE: ++ if (nargs > 1) ++ wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); ++ nargs = 0; ++ break; ++ case STATE_TEXT: ++ if (nargs < WLAN_CFG_ARGV_MAX) ++ args[nargs++] = state.text; ++ break; ++ } ++ } ++ ++exit: ++ return WLAN_STATUS_SUCCESS; ++ ++#if 0 ++ /* Old version */ ++ UINT_32 i; ++ UINT_8 c; ++ PUINT_8 pbuf; ++ UINT_8 ucState; ++ PUINT_8 pucKeyTail = NULL; ++ PUINT_8 pucKeyHead = NULL; ++ PUINT_8 pucValueHead = NULL; ++ PUINT_8 pucValueTail = NULL; ++ ++ ucState = WAIT_KEY_HEAD; ++ pbuf = pucConfigBuf; ++ ++ for (i = 0; i < u4ConfigBufLen; i++) { ++ c = pbuf[i]; ++ if (c == '\r' || c == '\n') { ++ ++ if (ucState == WAIT_VALUE_TAIL) { ++ /* Entry found */ ++ if (pucValueHead) ++ wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, ++ pucValueHead, pucValueTail); ++ } ++ ucState = WAIT_KEY_HEAD; ++ pucKeyTail = NULL; ++ pucKeyHead = NULL; ++ pucValueHead = NULL; ++ pucValueTail = NULL; ++ ++ } else if (c == '=') { ++ if (ucState == WAIT_KEY_TAIL) { ++ pucKeyTail = &pbuf[i - 1]; ++ ucState = WAIT_VALUE_HEAD; ++ } ++ } else if (c == ' ' || c == '\t') { ++ if (ucState == WAIT_KEY_HEAD) ++ ; ++ else if (ucState == WAIT_KEY_TAIL) { ++ pucKeyTail = &pbuf[i - 1]; ++ ucState = WAIT_VALUE_HEAD; ++ } ++ } else { ++ ++ if (c == '#') { ++ /* comments */ ++ if (ucState == WAIT_KEY_HEAD) ++ ucState = WAIT_COMMENT_TAIL; ++ else if (ucState == WAIT_VALUE_TAIL) ++ pucValueTail = &pbuf[i]; ++ ++ } else { ++ if (ucState == WAIT_KEY_HEAD) { ++ pucKeyHead = &pbuf[i]; ++ pucKeyTail = &pbuf[i]; ++ ucState = WAIT_KEY_TAIL; ++ } else if (ucState == WAIT_VALUE_HEAD) { ++ pucValueHead = &pbuf[i]; ++ pucValueTail = &pbuf[i]; ++ ucState = WAIT_VALUE_TAIL; ++ } else if (ucState == WAIT_VALUE_TAIL) ++ pucValueTail = &pbuf[i]; ++ } ++ } ++ ++ } /* for */ ++ ++ if (ucState == WAIT_VALUE_TAIL) { ++ /* Entry found */ ++ if (pucValueTail) ++ wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, pucValueHead, pucValueTail); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++#endif ++ ++#if CFG_SUPPORT_CFG_FILE ++WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags) ++{ ++ P_WLAN_CFG_T prWlanCfg; ++ /* P_WLAN_CFG_ENTRY_T prWlanCfgEntry; */ ++ prAdapter->prWlanCfg = &prAdapter->rWlanCfg; ++ prWlanCfg = prAdapter->prWlanCfg; ++ ++ kalMemZero(prWlanCfg, sizeof(WLAN_CFG_T)); ++ ASSERT(prWlanCfg); ++ prWlanCfg->u4WlanCfgEntryNumMax = WLAN_CFG_ENTRY_NUM_MAX; ++ prWlanCfg->u4WlanCfgKeyLenMax = WLAN_CFG_KEY_LEN_MAX; ++ prWlanCfg->u4WlanCfgValueLenMax = WLAN_CFG_VALUE_LEN_MAX; ++#if 0 ++ DBGLOG(INIT, INFO, "Init wifi config len %u max entry %u\n", u4ConfigBufLen, prWlanCfg->u4WlanCfgEntryNumMax); ++#endif ++ /* self test */ ++ wlanCfgSet(prAdapter, "ConfigValid", "0x123", 0); ++ if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 0x123) ++ DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); ++ wlanCfgSet(prAdapter, "ConfigValid", "1", 0); ++ if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 1) ++ DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); ++#if 0 /* soc chip didn't support these parameters now */ ++ /* Add initil config */ ++ /* use g,wlan,p2p,ap as prefix */ ++ /* Don't set cb here , overwrite by another api */ ++ wlanCfgSet(prAdapter, "TxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "RxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "RxBeamformee", "1", 0); ++ wlanCfgSet(prAdapter, "RoamTh1", "100", 0); ++ wlanCfgSet(prAdapter, "RoamTh2", "150", 0); ++ wlanCfgSet(prAdapter, "wlanRxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "apRxLdpc", "1", 0); ++ wlanCfgSet(prAdapter, "p2pRxLdpc", "1", 0); ++#endif ++ /* Parse the pucConfigBuff */ ++ ++ if (pucConfigBuf && (u4ConfigBufLen > 0)) ++ wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigBufLen); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to initialize WLAN feature options ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanCfgApply(IN P_ADAPTER_T prAdapter) ++{ ++#define STR2BYTE(s) (((((PUINT_8)s)[0]-'0')*10)+(((PUINT_8)s)[1]-'0')) ++ CHAR aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; ++ P_REG_INFO_T prRegInfo = &prAdapter->prGlueInfo->rRegInfo; ++ P_TX_PWR_PARAM_T prTxPwr = &prRegInfo->rTxPwr; ++ ++ kalMemZero(aucValue, sizeof(aucValue)); ++ DBGLOG(INIT, LOUD, "CFG_FILE: Apply Config File\n"); ++ /* Apply COUNTRY Config */ ++ if (wlanCfgGet(prAdapter, "country", aucValue, "", 0) == WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Found Country Key, Value=%s\n", aucValue); ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = ++ (((UINT_16) aucValue[0]) << 8) | ((UINT_16) aucValue[1]); ++ prRegInfo->au2CountryCode[0] = aucValue[0]; ++ prRegInfo->au2CountryCode[1] = aucValue[1]; ++ } ++ prWifiVar->ucApWpsMode = (UINT_8) wlanCfgGetUint32(prAdapter, "ApWpsMode", 0); ++ prWifiVar->ucCert11nMode = (UINT_8)wlanCfgGetUint32(prAdapter, "Cert11nMode", 0); ++ DBGLOG(INIT, LOUD, "CFG_FILE: ucApWpsMode = %u, ucCert11nMode = %u\n", ++ prWifiVar->ucApWpsMode, prWifiVar->ucCert11nMode); ++ if (prWifiVar->ucCert11nMode == 1) ++ nicWriteMcr(prAdapter, 0x11111115 , 1); ++ ++ if (wlanCfgGet(prAdapter, "5G_support", aucValue, "", 0) == WLAN_STATUS_SUCCESS) ++ prRegInfo->ucSupport5GBand = (*aucValue == 'y') ? 1 : 0; ++ if (wlanCfgGet(prAdapter, "TxPower2G4CCK", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 2) { ++ prTxPwr->cTxPwr2G4Cck = STR2BYTE(aucValue); ++ DBGLOG(INIT, LOUD, "2.4G cck=%d\n", prTxPwr->cTxPwr2G4Cck); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4OFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 10) { ++ prTxPwr->cTxPwr2G4OFDM_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4OFDM_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4OFDM_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4OFDM_48Mbps = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4OFDM_54Mbps = STR2BYTE(aucValue + 8); ++ DBGLOG(INIT, LOUD, "2.4G OFDM=%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4OFDM_BPSK, prTxPwr->cTxPwr2G4OFDM_QPSK, ++ prTxPwr->cTxPwr2G4OFDM_16QAM, prTxPwr->cTxPwr2G4OFDM_48Mbps, ++ prTxPwr->cTxPwr2G4OFDM_54Mbps); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4HT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr2G4HT20_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4HT20_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4HT20_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4HT20_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4HT20_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr2G4HT20_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "2.4G HT20=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4HT20_BPSK, prTxPwr->cTxPwr2G4HT20_QPSK, ++ prTxPwr->cTxPwr2G4HT20_16QAM, prTxPwr->cTxPwr2G4HT20_MCS5, ++ prTxPwr->cTxPwr2G4HT20_MCS6, prTxPwr->cTxPwr2G4HT20_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower2G4HT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS && ++ kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr2G4HT40_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr2G4HT40_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr2G4HT40_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr2G4HT40_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr2G4HT40_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr2G4HT40_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "2.4G HT40=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr2G4HT40_BPSK, prTxPwr->cTxPwr2G4HT40_QPSK, ++ prTxPwr->cTxPwr2G4HT40_16QAM, prTxPwr->cTxPwr2G4HT40_MCS5, ++ prTxPwr->cTxPwr2G4HT40_MCS6, prTxPwr->cTxPwr2G4HT40_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GOFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 10) { ++ prTxPwr->cTxPwr5GOFDM_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GOFDM_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GOFDM_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GOFDM_48Mbps = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GOFDM_54Mbps = STR2BYTE(aucValue + 8); ++ DBGLOG(INIT, LOUD, "5G OFDM=%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GOFDM_BPSK, prTxPwr->cTxPwr5GOFDM_QPSK, ++ prTxPwr->cTxPwr5GOFDM_16QAM, prTxPwr->cTxPwr5GOFDM_48Mbps, ++ prTxPwr->cTxPwr5GOFDM_54Mbps); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GHT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr5GHT20_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GHT20_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GHT20_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GHT20_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GHT20_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr5GHT20_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "5G HT20=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GHT20_BPSK, prTxPwr->cTxPwr5GHT20_QPSK, ++ prTxPwr->cTxPwr5GHT20_16QAM, prTxPwr->cTxPwr5GHT20_MCS5, prTxPwr->cTxPwr5GHT20_MCS6, ++ prTxPwr->cTxPwr5GHT20_MCS7); ++ } ++ if (wlanCfgGet(prAdapter, "TxPower5GHT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS ++ && kalStrLen(aucValue) == 12) { ++ prTxPwr->cTxPwr5GHT40_BPSK = STR2BYTE(aucValue); ++ prTxPwr->cTxPwr5GHT40_QPSK = STR2BYTE(aucValue + 2); ++ prTxPwr->cTxPwr5GHT40_16QAM = STR2BYTE(aucValue + 4); ++ prTxPwr->cTxPwr5GHT40_MCS5 = STR2BYTE(aucValue + 6); ++ prTxPwr->cTxPwr5GHT40_MCS6 = STR2BYTE(aucValue + 8); ++ prTxPwr->cTxPwr5GHT40_MCS7 = STR2BYTE(aucValue + 10); ++ DBGLOG(INIT, LOUD, "5G HT40=%d,%d,%d,%d,%d,%d\n", ++ prTxPwr->cTxPwr5GHT40_BPSK, prTxPwr->cTxPwr5GHT40_QPSK, ++ prTxPwr->cTxPwr5GHT40_16QAM, prTxPwr->cTxPwr5GHT40_MCS5, prTxPwr->cTxPwr5GHT40_MCS6, ++ prTxPwr->cTxPwr5GHT40_MCS7); ++ } ++ /* TODO: Apply other Config */ ++} ++#endif /* CFG_SUPPORT_CFG_FILE */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c +new file mode 100644 +index 000000000000..993ff061ed20 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c +@@ -0,0 +1,11050 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_oid.c#5 ++*/ ++ ++/*! \file wlanoid.c ++ \brief This file contains the WLAN OID processing routines of Windows driver for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_oid.c ++** ++** 09 05 2013 cp.wu ++** isolate logic regarding roaming & reassociation ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 09 02 2013 cp.wu ++** add path to handle reassociation request ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * using the wlanSendSetQueryCmd to set the tx power control cmd. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * change the set tx power cmd name. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 12 20 2011 cp.wu ++ * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information ++ * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO ++ * to expose version information ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to ++ * asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state ++ * without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 21 2011 cp.wu ++ * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing ++ * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer ++ * add more checking for such cases ++ * ++ * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. ++ * add some tweaking to protect such cases because that net device has become invalid. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 11 09 2011 george.huang ++ * [WCXRP00000871] [MT6620 Wi-Fi][FW] Include additional wakeup condition, which is by ++ * consequent DTIM unicast indication add XLOG for Set PS mode entry ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 11 02 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add RDD certification features. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 15 2011 tsaiyuan.hsu ++ * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA ++ * correct fifo full control from query to set operation for CTIA. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 17 2011 tsaiyuan.hsu ++ * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA ++ * add system config for CTIA. ++ * ++ * 08 15 2011 george.huang ++ * [MT6620 Wi-Fi][FW] handle TSF drift for connection detection ++ * . ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, ++ * for customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 05 02 2011 eddie.chen ++ * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control ++ * Fix compile warning. ++ * ++ * 04 29 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * . ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * add more debug message ++ * ++ * 04 26 2011 eddie.chen ++ * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control ++ * Add rx path profiling. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 31 2011 puff.wen ++ * NULL ++ * . ++ * ++ * 03 29 2011 puff.wen ++ * NULL ++ * Add chennel switch for stress test ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning ++ * surpress klock warning with code path rewritten ++ * ++ * 03 24 2011 wh.su ++ * [WCXRP00000595] [MT6620 Wi-Fi][Driver] at CTIA indicate disconnect to make the ps profile can apply ++ * use disconnect event instead of ais abort for CTIA testing. ++ * ++ * 03 23 2011 george.huang ++ * [WCXRP00000586] [MT6620 Wi-Fi][FW] Modify for blocking absence request right after connected ++ * revise for CTIA power mode setting ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 17 2011 yarco.yang ++ * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage ++ * . ++ * ++ * 03 15 2011 george.huang ++ * [WCXRP00000557] [MT6620 Wi-Fi] Support current consumption test mode commands ++ * Support current consumption measurement mode command ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 04 2011 cp.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * surpress compile warning occurred when compiled by GNU compiler collection. ++ * ++ * 03 03 2011 wh.su ++ * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue ++ * fixed the enter ctia test mode issue. ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Update sigma CAPI for U-APSD setting ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as ++ * initial RSSI right after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting ++ * Support CTIA power mode setting. ++ * ++ * 01 26 2011 wh.su ++ * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux ++ * adding the SW cmd ioctl support, use set/get structure ioctl. ++ * ++ * 01 25 2011 cp.wu ++ * [WCXRP00000394] [MT6620 Wi-Fi][Driver] Count space needed for generating error message in ++ * scanning list into buffer size checking ++ * when doing size prechecking, check illegal MAC address as well ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * check if allow to switch to IBSS mode via concurrent module before setting to IBSS mode ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000342] [MT6620 Wi-Fi][Driver] show error code in scanning list when MAC address is not ++ * correctly configured in NVRAM ++ * show error code 0x10 when MAC address in NVRAM is not configured correctly. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 28 2010 george.huang ++ * [WCXRP00000232] [MT5931 Wi-Fi][FW] Modifications for updated HW power on sequence and related design ++ * support WMM-PS U-APSD AC assignment. ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 16 2010 cp.wu ++ * [WCXRP00000268] [MT6620 Wi-Fi][Driver] correction for WHQL failed items ++ * correction for OID_802_11_NETWORK_TYPES_SUPPORTED handlers ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork ++ * suppress warning reported by Klockwork. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 30 2010 cp.wu ++ * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 ++ * . ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only ++ * with necessary data field checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available ++ * but extra scan result used to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 21 2010 wh.su ++ * [WCXRP00000192] [MT6620 Wi-Fi][Driver] Fixed fail trying to build connection with Security ++ * AP while enable WAPI message check ++ * Not set the wapi mode while the wapi assoc info set non-wapi ie. ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying ++ * current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 22 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * dos2unix conversion. ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version ++ * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android complete ++ * implementation of Android NVRAM access ++ * ++ * 10 06 2010 yuche.tsai ++ * NULL ++ * Update SLT 5G Test Channel Set. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 06 2010 yuche.tsai ++ * NULL ++ * Update For SLT 5G Test Channel Selection Rule. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form ++ * Query buffer size needs to be enlarged due to result is filled in 4-bytes alignment boundary ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and ++ * replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form ++ * Extend result length to multiples of 4-bytes ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Update SLT due to API change of SCAN module. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 yuche.tsai ++ * NULL ++ * Refine SLT IO control handler. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Modify the rescan condition. ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 27 2010 chinglan.wang ++ * NULL ++ * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * . ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * update params defined in CMD_SET_NETWORK_ADDRESS_LIST ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * fix for check build WHQL testing: ++ * 1) do not assert query buffer if indicated buffer length is zero ++ * 2) sdio.c has bugs which cause freeing same pointer twice ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * bypass u4FuncData for RF-Test query request as well. ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 26 2010 cp.wu ++ * ++ * re-commit code logic being overwriten. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one ++ * 2) refine disconnection behaviour when issued during BG-SCAN process ++ * ++ * 07 19 2010 wh.su ++ * ++ * modify the auth and encry status variable. ++ * ++ * 07 16 2010 cp.wu ++ * ++ * remove work-around in case SCN is not available. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. ++ * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add SCN compilation option. ++ * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement SCAN-REQUEST oid as mailbox message dispatching. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * adding the compiling flag for oid pmkid. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 28 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * simplify cmd packet sending for RF test and MCR access OIDs ++ * ++ * 05 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable radio even when STA is not associated. ++ * ++ * 05 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct 2 OID behaviour to meet WHQL requirement. ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct BSSID_LIST oid when radio if turned off. ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll ++ * 2) correct address list parsing ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * disable wlanoidSetNetworkAddress() temporally. ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * some OIDs should be DRIVER_CORE instead of GLUE_EXTENSION ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. ++ * 2) finish statistics OIDs ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct wlanoidSet802dot11PowerSaveProfile implementation. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) enable CMD/EVENT ver 0.9 definition. ++ * 2) abandon use of ENUM_MEDIA_STATE ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add dissassocation support for wpa supplicant ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct return value. ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * for disassociation, still use parameter with current setting. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * for disassociation, generate a WZC-compatible invalid SSID. ++ * ++ * 05 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * associate to illegal SSID when handling OID_802_11_DISASSOCIATE ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * reserve field of privacy filter and RTS threshold setting. ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00003830]add OID_802_11_PRIVACY_FILTER support ++ * enable RX filter OID ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add ioctl of power management ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * 2) command sequence number is now increased atomically ++ * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_CONFIGURATION query for infrastructure mode. ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) remove unused spin lock declaration ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * are done in adapter layer. ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)improve none-glue code portability ++ * (2) disable set Multicast address during atomic context ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve glue code portability ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * the frequency is used for adhoc connection only ++ * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list ++ * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result ++ * ++ * 03 19 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * adding the check for pass WHQL test item. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++* 03 16 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * fixed some whql pre-test fail case. ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. ++ * ++ * 02 24 2010 wh.su ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Don't needed to check the auth mode, WHQL testing not specific at auth wpa2. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not check SSID validity anymore. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * 2. follow MSDN defined behavior when associates to another AP ++ * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move ucCmdSeqNum as instance variable ++ * ++ * 02 04 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when OID_CUSTOM_OID_INTERFACE_VERSION is queried, do modify connection states ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * 4. correct some HAL implementation ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * OID_802_11_RSSI, ++ * OID_802_11_RSSI_TRIGGER, ++ * OID_802_11_STATISTICS, ++ * OID_802_11_DISASSOCIATE, ++ * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not fill ucJoinOnly currently ++ * ++ * 01 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable to connect to ad-hoc network ++ * ++ * 01 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * .implement Set/Query BeaconInterval/AtimWindow ++ * ++ * 01 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * .Set/Get AT Info is not blocked even when driver is not in fg test mode ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * and result is retrieved by get ATInfo instead ++ * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 28 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate redundant variables for connection_state ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-16 22:13:36 GMT mtk02752 ++** change hard-coded MAC address to match with FW (temporally) ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-10 16:49:50 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-08 17:38:49 GMT mtk02752 ++** + add OID for RF test ++** * MCR RD/WR are modified to match with cmd/event definition ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-12-08 11:32:20 GMT mtk02752 ++** add skeleton for RF test implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-12-03 16:43:24 GMT mtk01461 ++** Modify query SCAN list oid by adding prEventScanResult ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-03 16:39:27 GMT mtk01461 ++** Sync CMD data structure in set ssid oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-03 16:28:22 GMT mtk01461 ++** Add invalid check of set SSID oid and fix query scan list oid ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-30 17:33:08 GMT mtk02752 ++** implement wlanoidSetInfrastructureMode/wlanoidQueryInfrastructureMode ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-30 10:53:49 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-30 09:22:48 GMT mtk02752 ++** correct wifi cmd length mismatch ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-25 21:34:33 GMT mtk02752 ++** sync EVENT_SCAN_RESULT_T with firmware ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 21:03:27 GMT mtk02752 ++** implement wlanoidQueryBssidList() ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-25 18:17:17 GMT mtk02752 ++** refine GL_WLAN_INFO_T for buffering scan result ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-23 20:28:51 GMT mtk02752 ++** some OID will be set to WLAN_STATUS_PENDING until it is sent via wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-23 17:56:36 GMT mtk02752 ++** implement wlanoidSetBssidListScan(), wlanoidSetBssid() and wlanoidSetSsid() ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-13 17:20:53 GMT mtk02752 ++** add Set BSSID/SSID path but disabled temporally due to FW is not ready yet ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 12:28:58 GMT mtk02752 ++** add wlanoidSetBssidListScan -> cmd_info path ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-09 22:48:07 GMT mtk01084 ++** modify test cases entry ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-04 14:10:58 GMT mtk01084 ++** add new test interfaces ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-30 18:17:10 GMT mtk01084 ++** fix compiler warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:46:26 GMT mtk01084 ++** add test functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:07:56 GMT mtk01084 ++** include new file ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:29 GMT mtk01084 ++** modify for new HW architecture ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-02 13:48:49 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-09-09 17:26:04 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-21 12:09:50 GMT mtk01461 ++** Update for MCR Write OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:35:18 GMT mtk01461 ++** Update wlanoidQueryMcrRead() for composing CMD_INFO_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 18:09:51 GMT mtk01426 ++** Remove kalIndicateStatusAndComplete() in wlanoidQueryOidInterfaceVersion() ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-14 15:51:50 GMT mtk01426 ++** Add MCR read/write support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:40 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:06:31 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++#include "mgmt/rsn.h" ++ ++#include ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++#if CFG_ENABLE_STATISTICS_BUFFERING ++static BOOLEAN IsBufferedStatisticsUsable(P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsStatValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rStatUpdateTime) <= CFG_STATISTICS_VALID_CYCLE) ++ return TRUE; ++ else ++ return FALSE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the supported physical layer network ++* type that can be used by the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ UINT_32 u4NumItem = 0; ++ ENUM_PARAM_NETWORK_TYPE_T eSupportedNetworks[PARAM_NETWORK_TYPE_NUM]; ++ PPARAM_NETWORK_TYPE_LIST prSupported; ++ ++ /* The array of all physical layer network subtypes that the driver supports. */ ++ ++ DEBUGFUNC("wlanoidQueryNetworkTypesSupported"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ /* Init. */ ++ for (u4NumItem = 0; u4NumItem < PARAM_NETWORK_TYPE_NUM; u4NumItem++) ++ eSupportedNetworks[u4NumItem] = 0; ++ ++ u4NumItem = 0; ++ ++ eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_DS; ++ u4NumItem++; ++ ++ eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_OFDM24; ++ u4NumItem++; ++ ++ *pu4QueryInfoLen = ++ (UINT_32) OFFSET_OF(PARAM_NETWORK_TYPE_LIST, eNetworkType) + ++ (u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prSupported = (PPARAM_NETWORK_TYPE_LIST) pvQueryBuffer; ++ prSupported->NumberOfItems = u4NumItem; ++ kalMemCopy(prSupported->eNetworkType, eSupportedNetworks, u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); ++ ++ DBGLOG(OID, TRACE, "NDIS supported network type list: %u\n", prSupported->NumberOfItems); ++ DBGLOG_MEM8(OID, TRACE, prSupported, *pu4QueryInfoLen); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryNetworkTypesSupported */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current physical layer network ++* type used by the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ /* TODO: need to check the OID handler content again!! */ ++ ++ ENUM_PARAM_NETWORK_TYPE_T rCurrentNetworkTypeInUse = PARAM_NETWORK_TYPE_OFDM24; ++ ++ DEBUGFUNC("wlanoidQueryNetworkTypeInUse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) ++ rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkType); ++ else ++ rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkTypeInUse); ++ ++ *(P_ENUM_PARAM_NETWORK_TYPE_T) pvQueryBuffer = rCurrentNetworkTypeInUse; ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ ++ DBGLOG(OID, TRACE, "Network type in use: %d\n", rCurrentNetworkTypeInUse); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryNetworkTypeInUse */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the physical layer network type used ++* by the driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns the ++* amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS The given network type is supported and accepted. ++* \retval WLAN_STATUS_INVALID_DATA The given network type is not in the ++* supported list. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ /* TODO: need to check the OID handler content again!! */ ++ ++ ENUM_PARAM_NETWORK_TYPE_T eNewNetworkType; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetNetworkTypeInUse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ eNewNetworkType = *(P_ENUM_PARAM_NETWORK_TYPE_T) pvSetBuffer; ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); ++ ++ DBGLOG(OID, INFO, "New network type: %d mode\n", eNewNetworkType); ++ ++ switch (eNewNetworkType) { ++ ++ case PARAM_NETWORK_TYPE_DS: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PARAM_NETWORK_TYPE_OFDM5: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ case PARAM_NETWORK_TYPE_OFDM24: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PARAM_NETWORK_TYPE_AUTOMODE: ++ prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_AUTOMODE; ++ break; ++ ++ case PARAM_NETWORK_TYPE_FH: ++ DBGLOG(OID, INFO, "Not support network type: %d\n", eNewNetworkType); ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Unknown network type: %d\n", eNewNetworkType); ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ /* Verify if we support the new network type. */ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(OID, WARN, "Unknown network type: %d\n", eNewNetworkType); ++ ++ return rStatus; ++} /* wlanoidSetNetworkTypeInUse */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current BSSID. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidQueryBssid"); ++ ++ ASSERT(prAdapter); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) { ++ ASSERT(pu4QueryInfoLen); ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ ASSERT(u4QueryBufferLen >= MAC_ADDR_LEN); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) ++ kalMemCopy(pvQueryBuffer, prAdapter->rWlanInfo.rCurrBssId.arMacAddress, MAC_ADDR_LEN); ++ else if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS) { ++ PARAM_MAC_ADDRESS aucTemp; /*!< BSSID */ ++ ++ COPY_MAC_ADDR(aucTemp, prAdapter->rWlanInfo.rCurrBssId.arMacAddress); ++ aucTemp[0] &= ~BIT(0); ++ aucTemp[1] |= BIT(1); ++ COPY_MAC_ADDR(pvQueryBuffer, aucTemp); ++ } else ++ rStatus = WLAN_STATUS_ADAPTER_NOT_READY; ++ ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ return rStatus; ++} /* wlanoidQueryBssid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the list of all BSSIDs detected by ++* the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i, u4BssidListExLen; ++ P_PARAM_BSSID_LIST_EX_T prList; ++ P_PARAM_BSSID_EX_T prBssidEx; ++ PUINT_8 cp; ++ ++ DEBUGFUNC("wlanoidQueryBssidList"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) { ++ ASSERT(pvQueryBuffer); ++ ++ if (!pvQueryBuffer) ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in qeury BSSID list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ u4BssidListExLen = 0; ++ ++ if (prAdapter->fgIsRadioOff == FALSE) { ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) ++ u4BssidListExLen += ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4Length); ++ } ++ ++ if (u4BssidListExLen) ++ u4BssidListExLen += 4; /* u4NumberOfItems. */ ++ else ++ u4BssidListExLen = sizeof(PARAM_BSSID_LIST_EX_T); ++ ++ *pu4QueryInfoLen = u4BssidListExLen; ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Clear the buffer */ ++ kalMemZero(pvQueryBuffer, u4BssidListExLen); ++ ++ prList = (P_PARAM_BSSID_LIST_EX_T) pvQueryBuffer; ++ cp = (PUINT_8) &prList->arBssid[0]; ++ ++ if (prAdapter->fgIsRadioOff == FALSE && prAdapter->rWlanInfo.u4ScanResultNum > 0) { ++ /* fill up for each entry */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ prBssidEx = (P_PARAM_BSSID_EX_T) cp; ++ ++ /* copy structure */ ++ kalMemCopy(prBssidEx, ++ &(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /*For WHQL test, Rssi should be in range -10 ~ -200 dBm */ ++ if (prBssidEx->rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ prBssidEx->rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { ++ /* copy IEs */ ++ kalMemCopy(prBssidEx->aucIEs, ++ prAdapter->rWlanInfo.apucScanResultIEs[i], ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength); ++ } ++ /* 4-bytes alignement */ ++ prBssidEx->u4Length = ALIGN_4(prBssidEx->u4Length); ++ ++ cp += prBssidEx->u4Length; ++ prList->u4NumberOfItems++; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryBssidList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to perform ++* scanning. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SSID_T prSsid; ++ PARAM_SSID_T rSsid; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetBssidListScan()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(OID, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(OID, TRACE, "Scan\n"); ++ ++ if (pvSetBuffer != NULL && u4SetBufferLen != 0) { ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, pvSetBuffer, u4SetBufferLen); ++ prSsid = &rSsid; ++ } else { ++ prSsid = NULL; ++ } ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { ++ if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else ++#endif ++ { ++ if (prAdapter->fgEnOnlineScan == TRUE) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, NULL, 0); ++ } else { ++ /* reject the scan request */ ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ return rStatus; ++} /* wlanoidSetBssidListScan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to perform ++* scanning with attaching information elements(IEs) specified from user space ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SCAN_REQUEST_EXT_T prScanRequest; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_PARAM_SSID_T prSsid; ++ PUINT_8 pucIe; ++ UINT_32 u4IeLength; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_8 ucScanTime = AIS_SCN_DONE_TIMEOUT_SEC; ++ ++ DEBUGFUNC("wlanoidSetBssidListScanExt()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, ERROR, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgTestMode) { ++ DBGLOG(OID, WARN, "didn't support Scan in test mode\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)) { ++ DBGLOG(OID, ERROR, "u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(OID, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(OID, TRACE, "ScanEx\n"); ++ ++ /* clear old scan backup results if exists */ ++ { ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); ++ prBssDesc->u2RawLength = 0; ++ } ++ } ++ } ++ ++ if (pvSetBuffer != NULL && u4SetBufferLen != 0) { ++ prScanRequest = (P_PARAM_SCAN_REQUEST_EXT_T) pvSetBuffer; ++ prSsid = &(prScanRequest->rSsid); ++ pucIe = prScanRequest->pucIE; ++ u4IeLength = prScanRequest->u4IELength; ++ } else { ++ prScanRequest = NULL; ++ prSsid = NULL; ++ pucIe = NULL; ++ u4IeLength = 0; ++ } ++ ++/* P_AIS_FSM_INFO_T prAisFsmInfo; */ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++/* #if CFG_SUPPORT_WFD */ ++#if 0 ++ if ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.ucWfdEnable) && ++ ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ DBGLOG(OID, TRACE, "Twice the Scan Time for WFD\n"); ++ ucScanTime *= 2; ++ } ++ } ++#endif /* CFG_SUPPORT_WFD */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer, SEC_TO_MSEC(ucScanTime)); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { ++ if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else ++#endif ++ { ++ if (prAdapter->fgEnOnlineScan == TRUE) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); ++ } else { ++ /* reject the scan request */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ rStatus = WLAN_STATUS_FAILURE; ++ DBGLOG(OID, WARN, "ScanEx fail %d!\n", prAdapter->fgEnOnlineScan); ++ } ++ } ++ ++ return rStatus; ++} /* wlanoidSetBssidListScanWithIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will initiate the join procedure to attempt to associate ++* with the specified BSSID. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_UINT_8 pAddr; ++ UINT_32 i; ++ INT_32 i4Idx = -1; ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ UINT_8 ucReasonOfDisconnect; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = MAC_ADDR_LEN; ++ if (u4SetBufferLen != MAC_ADDR_LEN) { ++ *pu4SetInfoLen = MAC_ADDR_LEN; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ pAddr = (P_UINT_8) pvSetBuffer; ++ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; ++ } else { ++ DBGLOG(OID, TRACE, "DisByBssid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ } else { ++ ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ ++ /* check if any scanned result matchs with the BSSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { ++ i4Idx = (INT_32) i; ++ break; ++ } ++ } ++ ++ /* prepare message to AIS */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS ++ || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_BSSID; ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = ucReasonOfDisconnect; ++ ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAdapter->rWifiVar.rConnSettings.ucSSIDLen = 0; ++ prAdapter->rWifiVar.rConnSettings.aucSSID[0] = '\0'; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr); ++ ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ else ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(OID, INFO, "SetBssid\n"); ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetBssid() */ ++ ++WLAN_STATUS ++wlanoidSetConnect(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_CONNECT_T pParamConn; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_32 i; ++ /*INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN;*/ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ BOOLEAN fgIsValidSsid = TRUE; ++ BOOLEAN fgEqualSsid = FALSE; ++ BOOLEAN fgEqualBssid = FALSE; ++ const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* MSDN: ++ * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE ++ */ ++ if (prAdapter->fgIsRadioOff == TRUE) ++ prAdapter->fgIsRadioOff = FALSE; ++ ++ if (u4SetBufferLen != sizeof(PARAM_CONNECT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ ++ pParamConn = (P_PARAM_CONNECT_T) pvSetBuffer; ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ ++ if (pParamConn->u4SsidLen > 32) { ++ cnmMemFree(prAdapter, prAisAbortMsg); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (!pParamConn->pucBssid && !pParamConn->pucSsid) { ++ cnmMemFree(prAdapter, prAisAbortMsg); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ kalMemZero(prConnSettings->aucSSID, sizeof(prConnSettings->aucSSID)); ++ kalMemZero(prConnSettings->aucBSSID, sizeof(prConnSettings->aucBSSID)); ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_ANY; ++ prConnSettings->fgIsConnByBssidIssued = FALSE; ++ ++ if (pParamConn->pucSsid) { ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ COPY_SSID(prConnSettings->aucSSID, ++ prConnSettings->ucSSIDLen, pParamConn->pucSsid, (UINT_8) pParamConn->u4SsidLen); ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, ++ pParamConn->pucSsid, pParamConn->u4SsidLen)) ++ fgEqualSsid = TRUE; ++ } ++ if (pParamConn->pucBssid) { ++ if (!EQUAL_MAC_ADDR(aucZeroMacAddr, pParamConn->pucBssid) && IS_UCAST_MAC_ADDR(pParamConn->pucBssid)) { ++ prConnSettings->eConnectionPolicy = CONNECT_BY_BSSID; ++ prConnSettings->fgIsConnByBssidIssued = TRUE; ++ COPY_MAC_ADDR(prConnSettings->aucBSSID, pParamConn->pucBssid); ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pParamConn->pucBssid)) ++ fgEqualBssid = TRUE; ++ } else ++ DBGLOG(OID, TRACE, "wrong bssid %pM to connect\n", pParamConn->pucBssid); ++ } else ++ DBGLOG(OID, TRACE, "No Bssid set\n"); ++ prConnSettings->u4FreqInKHz = pParamConn->u4CenterFreq; ++ ++ /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (fgEqualSsid) { ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_ROAMING; ++ if (fgEqualBssid) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; ++ } ++ } else { ++ DBGLOG(OID, TRACE, "DisBySsid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ } ++ } else ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++#if 0 ++ /* check if any scanned result matchs with the SSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; ++ UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; ++ INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ ++ if (EQUAL_SSID(aucSsid, ucSsidLength, pParamConn->pucSsid, pParamConn->u4SsidLen) && ++ i4RSSI >= i4MaxRSSI) { ++ i4Idx = (INT_32) i; ++ i4MaxRSSI = i4RSSI; ++ } ++ if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { ++ i4Idx = (INT_32) i; ++ break; ++ } ++ } ++#endif ++ /* prepare message to AIS */ ++ if (prConnSettings->eOPMode == NET_TYPE_IBSS || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prConnSettings->u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prConnSettings->u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { ++ if (pParamConn->u4SsidLen == ELEM_MAX_LEN_SSID) { ++ fgIsValidSsid = FALSE; ++ ++ for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { ++ if (pParamConn->pucSsid) { ++ if (!((0 < pParamConn->pucSsid[i]) && (pParamConn->pucSsid[i] <= 0x1F))) { ++ fgIsValidSsid = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ if (fgIsValidSsid) ++ prConnSettings->fgIsConnReqIssued = TRUE; ++ else ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ ++ if (fgEqualSsid || fgEqualBssid) ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ else ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(OID, INFO, "ssid %s, bssid %pM, conn policy %d, disc reason %d\n", ++ prConnSettings->aucSSID, prConnSettings->aucBSSID, ++ prConnSettings->eConnectionPolicy, prAisAbortMsg->ucReasonOfDisconnect); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will initiate the join procedure to attempt ++* to associate with the new SSID. If the previous scanning ++* result is aged, we will scan the channels at first. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_SSID_T pParamSsid; ++ UINT_32 i; ++ INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN; ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ BOOLEAN fgIsValidSsid = TRUE; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* MSDN: ++ * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE ++ */ ++ if (prAdapter->fgIsRadioOff == TRUE) ++ prAdapter->fgIsRadioOff = FALSE; ++ ++ if (u4SetBufferLen < sizeof(PARAM_SSID_T) || u4SetBufferLen > sizeof(PARAM_SSID_T)) { ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ pParamSsid = (P_PARAM_SSID_T) pvSetBuffer; ++ ++ if (pParamSsid->u4SsidLen > 32) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ ++ /* re-association check */ ++ if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, ++ pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { ++ kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); ++ } else { ++ DBGLOG(OID, TRACE, "DisBySsid\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ } ++ /* check if any scanned result matchs with the SSID */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; ++ UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; ++ INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ ++ if (EQUAL_SSID(aucSsid, ucSsidLength, pParamSsid->aucSsid, pParamSsid->u4SsidLen) && ++ i4RSSI >= i4MaxRSSI) { ++ i4Idx = (INT_32) i; ++ i4MaxRSSI = i4RSSI; ++ } ++ } ++ ++ /* prepare message to AIS */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS ++ || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { ++ /* IBSS *//* beacon period */ ++ prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; ++ prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; ++ } ++ ++ if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { ++ if (pParamSsid->u4SsidLen == ELEM_MAX_LEN_SSID) { ++ fgIsValidSsid = FALSE; ++ ++ for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { ++ if (!((0 < pParamSsid->aucSsid[i]) && (pParamSsid->aucSsid[i] <= 0x1F))) { ++ fgIsValidSsid = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ ++ /* Set Connection Request Issued Flag */ ++ if (fgIsValidSsid) { ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; ++ ++ if (pParamSsid->u4SsidLen) { ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ } else { ++ /* wildcard SSID */ ++ prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_ANY; ++ } ++ } else { ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ } ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ ++ COPY_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, ++ prAdapter->rWifiVar.rConnSettings.ucSSIDLen, pParamSsid->aucSsid, (UINT_8) pParamSsid->u4SsidLen); ++ ++ prAdapter->rWifiVar.rConnSettings.u4FreqInKHz = pParamSsid->u4CenterFreq; ++ if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { ++ prAisAbortMsg->fgDelayIndication = TRUE; ++ } else { ++ /* Update the information to CONNECTION_SETTINGS_T */ ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ } ++ DBGLOG(SCN, INFO, "SSID %s\n", prAdapter->rWifiVar.rConnSettings.aucSSID); ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidSetSsid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the currently associated SSID. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_SSID_T prAssociatedSsid; ++ ++ DEBUGFUNC("wlanoidQuerySsid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_SSID_T); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prAssociatedSsid = (P_PARAM_SSID_T) pvQueryBuffer; ++ ++ kalMemZero(prAssociatedSsid->aucSsid, sizeof(prAssociatedSsid->aucSsid)); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ prAssociatedSsid->u4SsidLen = prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen; ++ ++ if (prAssociatedSsid->u4SsidLen) { ++ kalMemCopy(prAssociatedSsid->aucSsid, ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, prAssociatedSsid->u4SsidLen); ++ } ++ } else { ++ prAssociatedSsid->u4SsidLen = 0; ++ ++ DBGLOG(OID, TRACE, "Null SSID\n"); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQuerySsid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 network type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryInfrastructureMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eOPMode; ++ ++ /* ++ ** According to OID_802_11_INFRASTRUCTURE_MODE ++ ** If there is no prior OID_802_11_INFRASTRUCTURE_MODE, ++ ** NDIS_STATUS_ADAPTER_NOT_READY shall be returned. ++ */ ++#if DBG ++ switch (*(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer) { ++ case NET_TYPE_IBSS: ++ DBGLOG(OID, INFO, "IBSS mode\n"); ++ break; ++ case NET_TYPE_INFRA: ++ DBGLOG(OID, INFO, "Infrastructure mode\n"); ++ break; ++ default: ++ DBGLOG(OID, INFO, "Automatic mode\n"); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryInfrastructureMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set mode to infrastructure or ++* IBSS, or automatic switch between the two. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid ++* length of the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ DEBUGFUNC("wlanoidSetInfrastructureMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set infrastructure mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ eOpMode = *(P_ENUM_PARAM_OP_MODE_T) pvSetBuffer; ++ /* Verify the new infrastructure mode. */ ++ if (eOpMode >= NET_TYPE_NUM) { ++ DBGLOG(OID, TRACE, "Invalid mode value %d\n", eOpMode); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* check if possible to switch to AdHoc mode */ ++ if (eOpMode == NET_TYPE_IBSS || eOpMode == NET_TYPE_DEDICATED_IBSS) { ++ if (cnmAisIbssIsPermitted(prAdapter) == FALSE) { ++ DBGLOG(OID, TRACE, "Mode value %d unallowed\n", eOpMode); ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ /* Save the new infrastructure mode setting. */ ++ prAdapter->rWifiVar.rConnSettings.eOPMode = eOpMode; ++ ++ /* Clean up the Tx key flag */ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++#if CFG_SUPPORT_WAPI ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz = 0; ++ kalMemZero(&prAdapter->prGlueInfo->aucWapiAssocInfoIEs, 42); ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled = FALSE; ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++ kalMemZero(&prAdapter->prGlueInfo->aucWSCAssocInfoIE, 200); ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INFRASTRUCTURE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, nicOidCmdTimeoutCommon, 0, NULL, pvSetBuffer, u4SetBufferLen); ++ ++} /* wlanoidSetInfrastructureMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 authentication ++* mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryAuthMode"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eAuthMode; ++ ++#if DBG ++ switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer) { ++ case AUTH_MODE_OPEN: ++ DBGLOG(OID, INFO, "Current auth mode: Open\n"); ++ break; ++ ++ case AUTH_MODE_SHARED: ++ DBGLOG(OID, INFO, "Current auth mode: Shared\n"); ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(OID, INFO, "Current auth mode: Auto-switch\n"); ++ break; ++ ++ case AUTH_MODE_WPA: ++ DBGLOG(OID, INFO, "Current auth mode: WPA\n"); ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ DBGLOG(OID, INFO, "Current auth mode: WPA PSK\n"); ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ DBGLOG(OID, INFO, "Current auth mode: WPA None\n"); ++ break; ++ ++ case AUTH_MODE_WPA2: ++ DBGLOG(OID, INFO, "Current auth mode: WPA2\n"); ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ DBGLOG(OID, INFO, "Current auth mode: WPA2 PSK\n"); ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); ++ break; ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryAuthMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the IEEE 802.11 authentication mode ++* to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i, u4AkmSuite; ++ P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; ++ ++ DEBUGFUNC("wlanoidSetAuthMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* RF Test */ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* Check if the new authentication mode is valid. */ ++ if (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer >= AUTH_MODE_NUM) { ++ DBGLOG(OID, TRACE, "Invalid auth mode %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer) { ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ /* infrastructure mode only */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_INFRA) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ /* ad hoc mode only */ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_IBSS) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Save the new authentication mode. */ ++ prAdapter->rWifiVar.rConnSettings.eAuthMode = *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer; ++ ++#if DBG ++ switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { ++ case AUTH_MODE_OPEN: ++ DBGLOG(RSN, TRACE, "New auth mode: open\n"); ++ break; ++ ++ case AUTH_MODE_SHARED: ++ DBGLOG(RSN, TRACE, "New auth mode: shared\n"); ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(RSN, TRACE, "New auth mode: auto-switch\n"); ++ break; ++ ++ case AUTH_MODE_WPA: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA\n"); ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA PSK\n"); ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA None\n"); ++ break; ++ ++ case AUTH_MODE_WPA2: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA2\n"); ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ DBGLOG(RSN, TRACE, "New auth mode: WPA2 PSK\n"); ++ break; ++ ++ default: ++ DBGLOG(RSN, TRACE, "New auth mode: unknown (%d)\n", prAdapter->rWifiVar.rConnSettings.eAuthMode); ++ } ++#endif ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode >= AUTH_MODE_WPA) { ++ switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { ++ case AUTH_MODE_WPA: ++ u4AkmSuite = WPA_AKM_SUITE_802_1X; ++ break; ++ ++ case AUTH_MODE_WPA_PSK: ++ u4AkmSuite = WPA_AKM_SUITE_PSK; ++ break; ++ ++ case AUTH_MODE_WPA_NONE: ++ u4AkmSuite = WPA_AKM_SUITE_NONE; ++ break; ++ ++ case AUTH_MODE_WPA2: ++ u4AkmSuite = RSN_AKM_SUITE_802_1X; ++ break; ++ ++ case AUTH_MODE_WPA2_PSK: ++ u4AkmSuite = RSN_AKM_SUITE_PSK; ++ break; ++ ++ default: ++ u4AkmSuite = 0; ++ } ++ } else { ++ u4AkmSuite = 0; ++ } ++ ++ /* Enable the specific AKM suite only. */ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; ++ ++ if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = FALSE; ++#if CFG_SUPPORT_802_11W ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED) { ++ if ((u4AkmSuite == RSN_AKM_SUITE_PSK) && ++ prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_PSK_SHA256) { ++ DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_PSK_SHA256 AKM support\n"); ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ ++ } ++ if ((u4AkmSuite == RSN_AKM_SUITE_802_1X) && ++ prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_802_1X_SHA256) { ++ DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_802_1X_SHA256 AKM support\n"); ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; ++ } ++ } ++#endif ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetAuthMode */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current 802.11 privacy filter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryPrivacyFilter"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); ++ ++ if (u4QueryBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer = prAdapter->rWlanInfo.ePrivacyFilter; ++ ++#if DBG ++ switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer) { ++ case PRIVACY_FILTER_ACCEPT_ALL: ++ DBGLOG(OID, INFO, "Current privacy mode: open mode\n"); ++ break; ++ ++ case PRIVACY_FILTER_8021xWEP: ++ DBGLOG(OID, INFO, "Current privacy mode: filtering mode\n"); ++ break; ++ ++ default: ++ DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryPrivacyFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the IEEE 802.11 privacy filter ++* to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("wlanoidSetPrivacyFilter"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); ++ ++ if (u4SetBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* Check if the new authentication mode is valid. */ ++ if (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer >= PRIVACY_FILTER_NUM) { ++ DBGLOG(OID, TRACE, "Invalid privacy filter %d\n", *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer) { ++ default: ++ break; ++ } ++ ++ /* Save the new authentication mode. */ ++ prAdapter->rWlanInfo.ePrivacyFilter = *(ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetPrivacyFilter */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to reload the available default settings for ++* the specified type field. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType; ++ UINT_32 u4Len; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetReloadDefaults"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = sizeof(PARAM_RELOAD_DEFAULTS); ++ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set Reload default! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ /* Verify the available reload options and reload the settings. */ ++ switch (*(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer) { ++ case ENUM_RELOAD_WEP_KEYS: ++ /* Reload available default WEP keys from the permanent ++ storage. */ ++ prAdapter->rWifiVar.rConnSettings.eAuthMode = AUTH_MODE_OPEN; ++ /* ENUM_ENCRYPTION_DISABLED; */ ++ prAdapter->rWifiVar.rConnSettings.eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; ++ { ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 0; /* Remove */ ++ prCmdKey->ucKeyId = 0; /* (UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); */ ++ kalMemCopy(prCmdKey->aucPeerAddr, aucBCAddr, MAC_ADDR_LEN); ++ ++ ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); ++ ++ prCmdKey->ucKeyType = 0; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++ } ++ ++ break; ++ ++ default: ++ DBGLOG(OID, TRACE, "Invalid reload option %d\n", *(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer); ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* OID_802_11_RELOAD_DEFAULTS requiest to reset to auto mode */ ++ eNetworkType = PARAM_NETWORK_TYPE_AUTOMODE; ++ wlanoidSetNetworkTypeInUse(prAdapter, &eNetworkType, sizeof(eNetworkType), &u4Len); ++ ++ return rStatus; ++} /* wlanoidSetReloadDefaults */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a WEP key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++#ifdef LINUX ++UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; ++UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++#endif ++WLAN_STATUS ++wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#ifndef LINUX ++ UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++#endif ++ P_PARAM_WEP_T prNewWepKey; ++ P_PARAM_KEY_T prParamKey = (P_PARAM_KEY_T) keyBuffer; ++ UINT_32 u4KeyId, u4SetLen; ++ ++ DEBUGFUNC("wlanoidSetAddWep"); ++ ++ ASSERT(prAdapter); ++ ++ *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); ++ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)) { ++ ASSERT(pu4SetInfoLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewWepKey = (P_PARAM_WEP_T) pvSetBuffer; ++ ++ /* Verify the total buffer for minimum length. */ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + prNewWepKey->u4KeyLength) { ++ DBGLOG(OID, WARN, "Invalid total buffer length (%d) than minimum length (%d)\n", ++ (UINT_8) u4SetBufferLen, (UINT_8) OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)); ++ ++ *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Verify the key structure length. */ ++ if (prNewWepKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewWepKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Verify the key material length for maximum key material length:16 */ ++ if (prNewWepKey->u4KeyLength > 16 /* LEGACY_KEY_MAX_LEN */) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d) greater than maximum key material length (16)\n", ++ (UINT_8) prNewWepKey->u4KeyLength); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ u4KeyId = prNewWepKey->u4KeyIndex & BITS(0, 29) /* WEP_KEY_ID_FIELD */; ++ ++ /* Verify whether key index is valid or not, current version ++ driver support only 4 global WEP keys setting by this OID */ ++ if (u4KeyId > MAX_KEY_NUM - 1) { ++ DBGLOG(OID, ERROR, "Error, invalid WEP key ID: %d\n", (UINT_8) u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prParamKey->u4KeyIndex = u4KeyId; ++ ++ /* Transmit key */ ++ if (prNewWepKey->u4KeyIndex & IS_TRANSMIT_KEY) ++ prParamKey->u4KeyIndex |= IS_TRANSMIT_KEY; ++ ++ /* Per client key */ ++ if (prNewWepKey->u4KeyIndex & IS_UNICAST_KEY) ++ prParamKey->u4KeyIndex |= IS_UNICAST_KEY; ++ ++ prParamKey->u4KeyLength = prNewWepKey->u4KeyLength; ++ ++ kalMemCopy(prParamKey->arBSSID, aucBCAddr, MAC_ADDR_LEN); ++ ++ kalMemCopy(prParamKey->aucKeyMaterial, prNewWepKey->aucKeyMaterial, prNewWepKey->u4KeyLength); ++ ++ prParamKey->u4Length = OFFSET_OF(PARAM_KEY_T, aucKeyMaterial) + prNewWepKey->u4KeyLength; ++ ++ wlanoidSetAddKey(prAdapter, (PVOID) prParamKey, prParamKey->u4Length, &u4SetLen); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetAddWep */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to remove the WEP key ++* at the specified key index. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 u4KeyId, u4SetLen; ++ PARAM_REMOVE_KEY_T rRemoveKey; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ DEBUGFUNC("wlanoidSetRemoveWep"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_KEY_INDEX); ++ ++ if (u4SetBufferLen < sizeof(PARAM_KEY_INDEX)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ u4KeyId = *(PUINT_32) pvSetBuffer; ++ ++ /* Dump PARAM_WEP content. */ ++ DBGLOG(OID, INFO, "Set: Dump PARAM_KEY_INDEX content\n"); ++ DBGLOG(OID, INFO, "Index : 0x%08x\n", u4KeyId); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4KeyId & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "Invalid WEP key index: 0x%08x\n", u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ u4KeyId &= BITS(0, 7); ++ ++ /* Verify whether key index is valid or not. Current version ++ driver support only 4 global WEP keys. */ ++ if (u4KeyId > MAX_KEY_NUM - 1) { ++ DBGLOG(OID, ERROR, "invalid WEP key ID %u\n", u4KeyId); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ rRemoveKey.u4KeyIndex = *(PUINT_32) pvSetBuffer; ++ ++ kalMemCopy(rRemoveKey.arBSSID, aucBCAddr, MAC_ADDR_LEN); ++ ++ wlanoidSetRemoveKey(prAdapter, (PVOID)&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T), &u4SetLen); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetRemoveWep */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_KEY_T prNewKey; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 ucCmdSeqNum; ++ ++#if 0 ++ DEBUGFUNC("wlanoidSetAddKey"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++#endif ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++#if 0 ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ /* Verify the key material length for key material buffer */ ++ if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check */ ++ if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || ++ prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyIndex & 0xff) != 0) || ++ ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) ++ && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) ++ && (prNewKey->arBSSID[5] == 0xff))) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++#endif ++ ++ /* Dump PARAM_KEY content. */ ++ DBGLOG(OID, TRACE, "Set: PARAM_KEY Length: 0x%08x, Key Index: 0x%08x, Key Length: 0x%08x\n", ++ prNewKey->u4Length, prNewKey->u4KeyIndex, prNewKey->u4KeyLength); ++ DBGLOG(OID, TRACE, "BSSID:\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ DBGLOG(OID, TRACE, "Key RSC:\n"); ++ DBGLOG_MEM8(OID, TRACE, &prNewKey->rKeyRSC, sizeof(PARAM_KEY_RSC)); ++ DBGLOG(OID, TRACE, "Key Material:\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->aucKeyMaterial, prNewKey->u4KeyLength); ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { ++ /* Todo:: Store the legacy wep key for OID_802_11_RELOAD_DEFAULTS */ ++ /* Todo:: Nothing */ ++ } ++ ++ if (prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = TRUE; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(OID, TRACE, "ucCmdSeqNum = %d\n", ucCmdSeqNum); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 1; /* Add */ ++ ++ prCmdKey->ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; ++ prCmdKey->ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; ++ prCmdKey->ucIsAuthenticator = ((prNewKey->u4KeyIndex & IS_AUTHENTICATOR) == IS_AUTHENTICATOR) ? 1 : 0; ++ ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->arBSSID, MAC_ADDR_LEN); ++ ++ prCmdKey->ucNetType = 0; /* AIS */ ++ ++ prCmdKey->ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); ++ ++ /* Note: adjust the key length for WPA-None */ ++ prCmdKey->ucKeyLen = (UINT_8) prNewKey->u4KeyLength; ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, prCmdKey->ucKeyLen); ++ ++ if (prNewKey->u4KeyLength == 5) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP40; ++ } else if (prNewKey->u4KeyLength == 13) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP104; ++ } else if (prNewKey->u4KeyLength == 16) { ++ if ((ucAlgorithmId != CIPHER_SUITE_CCMP) && ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA)) ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP128; ++ else { ++#if CFG_SUPPORT_802_11W ++ if (prCmdKey->ucKeyId >= 4) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_BIP; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ prAisSpecBssInfo->fgBipKeyInstalled = TRUE; ++ } else ++#endif ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; ++ if (rsnCheckPmkidCandicate(prAdapter)) { ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ DBGLOG(RSN, TRACE, ++ "Add key: Prepare a timer to indicate candidate PMKID Candidate\n"); ++ cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++ } else if (prNewKey->u4KeyLength == 32) { ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; ++ else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) { ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; ++ prCmdKey->ucKeyLen = CCMP_KEY_LEN; ++ } ++ } else ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; ++ } ++ ++ DBGLOG(RSN, TRACE, "prCmdKey->ucAlgorithmId=%d, key len=%d\n", ++ prCmdKey->ucAlgorithmId, (UINT32) prNewKey->u4KeyLength); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS ++wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_KEY_T prNewKey; ++ ++ DEBUGFUNC("wlanoidSetAddKey"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ /* Verify the key material length for key material buffer */ ++ if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Exception check */ ++ if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN) && ++ (prNewKey->u4KeyIndex & 0xff) != 0) || ++ EQUAL_MAC_ADDR(prNewKey->arBSSID, "\xff\xff\xff\xff\xff\xff")) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || ++ prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* ++ supplicant will set key before updating station & enabling the link so we need to ++ backup the key information and set key when link is enabled ++ */ ++ if (TdlsexKeyHandle(prAdapter, prNewKey) == TDLS_STATUS_SUCCESS) ++ return WLAN_STATUS_SUCCESS; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return _wlanoidSetAddKey(prAdapter, pvSetBuffer, u4SetBufferLen, TRUE, CIPHER_SUITE_NONE, pu4SetInfoLen); ++} /* wlanoidSetAddKey */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request the driver to remove the key at ++* the specified key index. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_REMOVE_KEY_T prRemovedKey; ++ P_CMD_802_11_KEY prCmdKey; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetRemoveKey"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set remove key! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; ++ ++ /* Dump PARAM_REMOVE_KEY content. */ ++ DBGLOG(OID, TRACE, "Set: Dump PARAM_REMOVE_KEY content\n"); ++ DBGLOG(OID, TRACE, "Length : 0x%08x\n", prRemovedKey->u4Length); ++ DBGLOG(OID, TRACE, "Key Index : 0x%08x\n", prRemovedKey->u4KeyIndex); ++ DBGLOG(OID, TRACE, "BSSID:\n"); ++ DBGLOG_MEM8(OID, TRACE, prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ ++ /* Check bit 31: this bit should always 0 */ ++ if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Check bits 8 ~ 29 should always be 0 */ ++ if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { ++ /* Bit 31 should not be set */ ++ DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Clean up the Tx key flag */ ++ if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_802_11_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 0; /* Remove */ ++ prCmdKey->ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ ++#if CFG_SUPPORT_802_11W ++ ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM + 2); ++#else ++ /* ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); */ ++#endif ++ ++ if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) ++ prCmdKey->ucKeyType = 1; ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetRemoveKey */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current encryption status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ BOOLEAN fgTransmitKeyAvailable = TRUE; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus = 0; ++ ++ DEBUGFUNC("wlanoidQueryEncryptionStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); ++ ++ fgTransmitKeyAvailable = prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist; ++ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION3_ENABLED: ++ if (fgTransmitKeyAvailable) ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION3_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: ++ if (fgTransmitKeyAvailable) { ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ break; ++ } ++ eEncStatus = ENUM_ENCRYPTION2_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: ++ if (fgTransmitKeyAvailable) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; ++ break; ++ ++ case ENUM_ENCRYPTION_DISABLED: ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ break; ++ ++ default: ++ DBGLOG(OID, ERROR, "Unknown Encryption Status Setting:%d\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++ ++#if DBG ++ DBGLOG(OID, INFO, ++ "Encryption status: %d Return:%d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, eEncStatus); ++#endif ++ ++ *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvQueryBuffer = eEncStatus; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryEncryptionStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the encryption status to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_NOT_SUPPORTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEewEncrypt; ++ ++ DEBUGFUNC("wlanoidSetEncryptionStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ *pu4SetInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); ++ ++ /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ ++ /* return WLAN_STATUS_SUCCESS; */ ++ /* } */ ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set encryption status! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ eEewEncrypt = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; ++ DBGLOG(OID, TRACE, "ENCRYPTION_STATUS %d\n", eEewEncrypt); ++ ++ switch (eEewEncrypt) { ++ case ENUM_ENCRYPTION_DISABLED: /* Disable WEP, TKIP, AES */ ++ DBGLOG(RSN, TRACE, "Disable Encryption\n"); ++ secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: /* Enable WEP. Disable TKIP, AES */ ++ DBGLOG(RSN, TRACE, "Enable Encryption1\n"); ++ secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: /* Enable WEP, TKIP. Disable AES */ ++ secSetCipherSuite(prAdapter, ++ CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP); ++ DBGLOG(RSN, TRACE, "Enable Encryption2\n"); ++ break; ++ ++ case ENUM_ENCRYPTION3_ENABLED: /* Enable WEP, TKIP, AES */ ++ secSetCipherSuite(prAdapter, ++ CIPHER_FLAG_WEP40 | ++ CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP | CIPHER_FLAG_CCMP); ++ DBGLOG(RSN, TRACE, "Enable Encryption3\n"); ++ break; ++ ++ default: ++ DBGLOG(RSN, WARN, "Unacceptible encryption status: %d\n", ++ *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer); ++ ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ } ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* Save the new encryption status. */ ++ prAdapter->rWifiVar.rConnSettings.eEncStatus = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; ++ ++ DBGLOG(RSN, TRACE, "wlanoidSetEncryptionStatus to %d\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++ ++ return rStatus; ++} /* wlanoidSetEncryptionStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to test the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_802_11_TEST_T prTest; ++ PVOID pvTestData; ++ PVOID pvStatusBuffer; ++ UINT_32 u4StatusBufferSize; ++ ++ DEBUGFUNC("wlanoidSetTest"); ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prTest = (P_PARAM_802_11_TEST_T) pvSetBuffer; ++ ++ DBGLOG(OID, TRACE, "Test - Type %u\n", prTest->u4Type); ++ ++ switch (prTest->u4Type) { ++ case 1: /* Type 1: generate an authentication event */ ++ pvTestData = (PVOID) &prTest->u.AuthenticationEvent; ++ pvStatusBuffer = (PVOID) prAdapter->aucIndicationEventBuffer; ++ u4StatusBufferSize = prTest->u4Length - 8; ++ if (u4StatusBufferSize > sizeof(PARAM_AUTH_EVENT_T)) { ++ DBGLOG(OID, TRACE, "prTest->u4Length error %u\n", u4StatusBufferSize); ++ ASSERT(FALSE); ++ } ++ break; ++ ++ case 2: /* Type 2: generate an RSSI status indication */ ++ pvTestData = (PVOID) &prTest->u.RssiTrigger; ++ pvStatusBuffer = (PVOID) &prAdapter->rWlanInfo.rCurrBssId.rRssi; ++ u4StatusBufferSize = sizeof(PARAM_RSSI); ++ break; ++ ++ default: ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ASSERT(u4StatusBufferSize <= 180); ++ if (u4StatusBufferSize > 180) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Get the contents of the StatusBuffer from the test structure. */ ++ kalMemCopy(pvStatusBuffer, pvTestData, u4StatusBufferSize); ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, pvStatusBuffer, u4StatusBufferSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetTest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the driver's WPA2 status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CAPABILITY_T prCap; ++ P_PARAM_AUTH_ENCRYPTION_T prAuthenticationEncryptionSupported; ++ ++ DEBUGFUNC("wlanoidQueryCapability"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = 4 * sizeof(UINT_32) + 14 * sizeof(PARAM_AUTH_ENCRYPTION_T); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prCap = (P_PARAM_CAPABILITY_T) pvQueryBuffer; ++ ++ prCap->u4Length = *pu4QueryInfoLen; ++ prCap->u4Version = 2; /* WPA2 */ ++ prCap->u4NoOfPMKIDs = CFG_MAX_PMKID_CACHE; ++ prCap->u4NoOfAuthEncryptPairsSupported = 14; ++ ++ prAuthenticationEncryptionSupported = &prCap->arAuthenticationEncryptionSupported[0]; ++ ++ /* fill 14 entries of supported settings */ ++ prAuthenticationEncryptionSupported[0].eAuthModeSupported = AUTH_MODE_OPEN; ++ ++ prAuthenticationEncryptionSupported[0].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; ++ ++ prAuthenticationEncryptionSupported[1].eAuthModeSupported = AUTH_MODE_OPEN; ++ prAuthenticationEncryptionSupported[1].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; ++ ++ prAuthenticationEncryptionSupported[2].eAuthModeSupported = AUTH_MODE_SHARED; ++ prAuthenticationEncryptionSupported[2].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; ++ ++ prAuthenticationEncryptionSupported[3].eAuthModeSupported = AUTH_MODE_SHARED; ++ prAuthenticationEncryptionSupported[3].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; ++ ++ prAuthenticationEncryptionSupported[4].eAuthModeSupported = AUTH_MODE_WPA; ++ prAuthenticationEncryptionSupported[4].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[5].eAuthModeSupported = AUTH_MODE_WPA; ++ prAuthenticationEncryptionSupported[5].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[6].eAuthModeSupported = AUTH_MODE_WPA_PSK; ++ prAuthenticationEncryptionSupported[6].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[7].eAuthModeSupported = AUTH_MODE_WPA_PSK; ++ prAuthenticationEncryptionSupported[7].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[8].eAuthModeSupported = AUTH_MODE_WPA_NONE; ++ prAuthenticationEncryptionSupported[8].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[9].eAuthModeSupported = AUTH_MODE_WPA_NONE; ++ prAuthenticationEncryptionSupported[9].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[10].eAuthModeSupported = AUTH_MODE_WPA2; ++ prAuthenticationEncryptionSupported[10].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[11].eAuthModeSupported = AUTH_MODE_WPA2; ++ prAuthenticationEncryptionSupported[11].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ prAuthenticationEncryptionSupported[12].eAuthModeSupported = AUTH_MODE_WPA2_PSK; ++ prAuthenticationEncryptionSupported[12].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; ++ ++ prAuthenticationEncryptionSupported[13].eAuthModeSupported = AUTH_MODE_WPA2_PSK; ++ prAuthenticationEncryptionSupported[13].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryCapability */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the PMKID in the PMK cache. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ UINT_32 i; ++ P_PARAM_PMKID_T prPmkid; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("wlanoidQueryPmkid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ *pu4QueryInfoLen = OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo) + ++ prAisSpecBssInfo->u4PmkidCacheCount * sizeof(PARAM_BSSID_INFO_T); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prPmkid = (P_PARAM_PMKID_T) pvQueryBuffer; ++ ++ prPmkid->u4Length = *pu4QueryInfoLen; ++ prPmkid->u4BSSIDInfoCount = prAisSpecBssInfo->u4PmkidCacheCount; ++ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { ++ kalMemCopy(prPmkid->arBSSIDInfo[i].arBSSID, ++ prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ kalMemCopy(prPmkid->arBSSIDInfo[i].arPMKID, ++ prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryPmkid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the PMKID to the PMK cache in the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i, j; ++ P_PARAM_PMKID_T prPmkid; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("wlanoidSetPmkid"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* It's possibble BSSIDInfoCount is zero, because OS wishes to clean PMKID */ ++ if (u4SetBufferLen < OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ ASSERT(pvSetBuffer); ++ prPmkid = (P_PARAM_PMKID_T) pvSetBuffer; ++ ++ if (u4SetBufferLen < ++ ((prPmkid->u4BSSIDInfoCount * sizeof(PARAM_BSSID_INFO_T)) + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo))) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ DBGLOG(OID, TRACE, "Count %u\n", prPmkid->u4BSSIDInfoCount); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* This OID replace everything in the PMKID cache. */ ++ if (prPmkid->u4BSSIDInfoCount == 0) { ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++ } ++ if ((prAisSpecBssInfo->u4PmkidCacheCount + prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE)) { ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++ } ++ ++ /* ++ The driver can only clear its PMKID cache whenever it make a media disconnect ++ indication. Otherwise, it must change the PMKID cache only when set through this OID. ++ */ ++#if CFG_RSN_MIGRATION ++ for (i = 0; i < prPmkid->u4BSSIDInfoCount; i++) { ++ /* Search for desired BSSID. If desired BSSID is found, ++ then set the PMKID */ ++ if (!rsnSearchPmkidEntry(prAdapter, (PUINT_8) prPmkid->arBSSIDInfo[i].arBSSID, &j)) { ++ /* No entry found for the specified BSSID, so add one entry */ ++ if (prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE - 1) { ++ j = prAisSpecBssInfo->u4PmkidCacheCount; ++ kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prPmkid->arBSSIDInfo[i].arBSSID, sizeof(PARAM_MAC_ADDRESS)); ++ prAisSpecBssInfo->u4PmkidCacheCount++; ++ } else { ++ j = CFG_MAX_PMKID_CACHE; ++ } ++ } ++ ++ if (j < CFG_MAX_PMKID_CACHE) { ++ kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID, ++ prPmkid->arBSSIDInfo[i].arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ DBGLOG(RSN, TRACE, "Add BSSID %pM idx=%d PMKID value %pM\n", ++ (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID), (UINT_32) j, ++ (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID)); ++ prAisSpecBssInfo->arPmkidCache[j].fgPmkidExist = TRUE; ++ } ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetPmkid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the set of supported data rates that ++* the radio is capable of running ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query ++* \param[in] u4QueryBufferLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number ++* of bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ PARAM_RATES eRate = { ++ /* BSSBasicRateSet for 802.11n Non-HT rates */ ++ 0x8C, /* 6M */ ++ 0x92, /* 9M */ ++ 0x98, /* 12M */ ++ 0xA4, /* 18M */ ++ 0xB0, /* 24M */ ++ 0xC8, /* 36M */ ++ 0xE0, /* 48M */ ++ 0xEC /* 54M */ ++ }; ++ ++ DEBUGFUNC("wlanoidQuerySupportedRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, (PVOID) &eRate, sizeof(PARAM_RATES)); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQuerySupportedRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current desired rates. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryDesiredRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, (PVOID) &(prAdapter->rWlanInfo.eDesiredRates), sizeof(PARAM_RATES)); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidQueryDesiredRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to Set the desired rates. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i; ++ ++ DEBUGFUNC("wlanoidSetDesiredRates"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(PARAM_RATES)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(PARAM_RATES); ++ ++ if (u4SetBufferLen < sizeof(PARAM_RATES)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ kalMemCopy((PVOID) &(prAdapter->rWlanInfo.eDesiredRates), pvSetBuffer, sizeof(PARAM_RATES)); ++ ++ prAdapter->rWlanInfo.eLinkAttr.ucDesiredRateLen = PARAM_MAX_LEN_RATES; ++ for (i = 0; i < PARAM_MAX_LEN_RATES; i++) ++ prAdapter->rWlanInfo.eLinkAttr.u2DesiredRate[i] = (UINT_16) (prAdapter->rWlanInfo.eDesiredRates[i]); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_LINK_ATTRIB, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_LINK_ATTRIB), ++ (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetDesiredRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the maximum frame size in bytes, ++* not including the header. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMaxFrameSize"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ - ETHERNET_HEADER_SZ; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryMaxFrameSize */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the maximum total packet length ++* in bytes. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMaxTotalSize"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryMaxTotalSize */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the vendor ID of the NIC. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#if DBG ++ PUINT_8 cp; ++#endif ++ DEBUGFUNC("wlanoidQueryVendorId"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ kalMemCopy(pvQueryBuffer, prAdapter->aucMacAddress, 3); ++ *((PUINT_8) pvQueryBuffer + 3) = 1; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++#if DBG ++ cp = (PUINT_8) pvQueryBuffer; ++ DBGLOG(OID, LOUD, "Vendor ID=%02x-%02x-%02x-%02x\n", cp[0], cp[1], cp[2], cp[3]); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryVendorId */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RSSI value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call failed due to invalid length of ++* the query buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRssi"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgIsLinkQualityValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ PARAM_RSSI rRssi; ++ ++ rRssi = (PARAM_RSSI) prAdapter->rLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ ++ kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); ++ return WLAN_STATUS_SUCCESS; ++ } ++#ifdef LINUX ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, ++ *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++#endif ++} /* end of wlanoidQueryRssi() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RSSI trigger value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call failed due to invalid length of ++* the query buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRssiTrigger"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_NONE) ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ *(PARAM_RSSI *) pvQueryBuffer = prAdapter->rWlanInfo.rRssiTriggerValue; ++ DBGLOG(OID, INFO, "RSSI trigger: %d dBm\n", *(PARAM_RSSI *) pvQueryBuffer); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryRssiTrigger */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a trigger value of the RSSI event. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns the ++* amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PARAM_RSSI rRssiTriggerValue; ++ ++ DEBUGFUNC("wlanoidSetRssiTrigger"); ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_RSSI); ++ rRssiTriggerValue = *(PARAM_RSSI *) pvSetBuffer; ++ ++ if (rRssiTriggerValue > PARAM_WHQL_RSSI_MAX_DBM || rRssiTriggerValue < PARAM_WHQL_RSSI_MIN_DBM) ++ return ++ /* Save the RSSI trigger value to the Adapter structure */ ++ prAdapter->rWlanInfo.rRssiTriggerValue = rRssiTriggerValue; ++ ++ /* If the RSSI trigger value is equal to the current RSSI value, the ++ * indication triggers immediately. We need to indicate the protocol ++ * that an RSSI status indication event triggers. */ ++ if (rRssiTriggerValue == (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) &prAdapter->rWlanInfo.rRssiTriggerValue, sizeof(PARAM_RSSI)); ++ } else if (rRssiTriggerValue < (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_GREATER; ++ else if (rRssiTriggerValue > (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_LESS; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetRssiTrigger */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a suggested value for the number of ++* bytes of received packet data that will be indicated to the protocol ++* driver. We just accept the set and ignore this value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ DEBUGFUNC("wlanoidSetCurrentLookahead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) { ++ *pu4SetInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetCurrentLookahead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames that the driver ++* receives but does not indicate to the protocols due to errors. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the number of frames that the NIC ++* cannot receive due to lack of NIC receive buffer space. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS If success; ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvNoBuffer"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) 0; /* @FIXME */ ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) 0; /* @FIXME */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvNoBuffer, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvNoBuffer */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the number of frames that the NIC ++* received and it is CRC error. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS If success; ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvCrcError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvCrcError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvCrcError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the current 802.11 statistics. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; ++ prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; ++ prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; ++ prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS_PL, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStatistics, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryStatistics */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the current 802.11 statistics. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryStatistics"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; ++ prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; ++ prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; ++ prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryStatistics, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryStatistics */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query current media streaming status. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryMediaStreamMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); ++ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *(P_ENUM_MEDIA_STREAM_MODE) pvQueryBuffer = ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryMediaStreamMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to enter media streaming mode or exit media streaming mode ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ENUM_MEDIA_STREAM_MODE eStreamMode; ++ ++ DEBUGFUNC("wlanoidSetMediaStreamMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(ENUM_MEDIA_STREAM_MODE)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); ++ ++ eStreamMode = *(P_ENUM_MEDIA_STREAM_MODE) pvSetBuffer; ++ ++ if (eStreamMode == ENUM_MEDIA_STREAM_OFF) ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; ++ else ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 1; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_LINK_ATTRIB, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetMediaStreamMode, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_LINK_ATTRIB), ++ (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); ++} /* wlanoidSetMediaStreamMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the permanent MAC address of the NIC. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryPermanentAddr"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucPermanentAddress); ++ *pu4QueryInfoLen = MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryPermanentAddr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_BASIC_CONFIG rCmdBasicConfig; ++ ++ DEBUGFUNC("wlanoidQueryCurrentAddr"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < MAC_ADDR_LEN) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BASIC_CONFIG, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryAddress, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BASIC_CONFIG), ++ (PUINT_8) &rCmdBasicConfig, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryCurrentAddr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query NIC link speed. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryLinkSpeed"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (prAdapter->fgIsLinkRateValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ *(PUINT_32) pvQueryBuffer = prAdapter->rLinkQuality.u2LinkSpeed * 5000; /* change to unit of 100bps */ ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkSpeed, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ } ++} /* end of wlanoidQueryLinkSpeed() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query MCR value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ DEBUGFUNC("wlanoidQueryMcrRead"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvQueryBuffer; ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++#if CFG_SUPPORT_SWCR ++ if ((prMcrRdInfo->u4McrOffset >> 16) == 0x9F00) { ++ swCrReadWriteCmd(prAdapter, ++ SWCR_READ, ++ (UINT_16) (prMcrRdInfo->u4McrOffset & BITS(0, 15)), &prMcrRdInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ /* Check if access F/W Domain MCR (due to WiFiSYS is placed from 0x6000-0000 */ ++ if (prMcrRdInfo->u4McrOffset & 0xFFFF0000) { ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrRdInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = 0; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMcrRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); ++ } else { ++ HAL_MCR_RD(prAdapter, prMcrRdInfo->u4McrOffset & BITS(2, 31), /* address is in DWORD unit */ ++ &prMcrRdInfo->u4McrData); ++ ++ DBGLOG(OID, TRACE, "MCR Read: Offset = %#08x, Data = %#08x\n", ++ prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++} /* end of wlanoidQueryMcrRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write MCR and enable specific function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrWrInfo; ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++#if CFG_STRESS_TEST_SUPPORT ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); ++ P_STA_RECORD_T prStaRec = prBssInfo->prStaRecOfAP; ++ UINT_32 u4McrOffset, u4McrData; ++#endif ++ ++ DEBUGFUNC("wlanoidSetMcrWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvSetBuffer; ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++ /* -- Puff Stress Test Begin */ ++#if CFG_STRESS_TEST_SUPPORT ++ ++ /* 0xFFFFFFFE for Control Rate */ ++ if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFE) { ++ if (prMcrWrInfo->u4McrData < FIXED_RATE_NUM && prMcrWrInfo->u4McrData > 0) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prMcrWrInfo->u4McrData); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DEBUGFUNC("[Stress Test]Complete Rate is Changed...\n"); ++ DBGLOG(OID, TRACE, ++ "[Stress Test] Rate is Changed to index %d...\n", prAdapter->rWifiVar.eRateSetting); ++ } ++ /* 0xFFFFFFFD for Switch Channel */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFD) { ++ if (prMcrWrInfo->u4McrData <= 11 && prMcrWrInfo->u4McrData >= 1) ++ prBssInfo->ucPrimaryChannel = prMcrWrInfo->u4McrData; ++ nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); ++ DBGLOG(OID, TRACE, "[Stress Test] Channel is switched to %d ...\n", prBssInfo->ucPrimaryChannel); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 0xFFFFFFFFC for Control RF Band and SCO */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFC) { ++ /* Band */ ++ if (prMcrWrInfo->u4McrData & 0x80000000) { ++ /* prBssInfo->eBand = BAND_5G; */ ++ /* prBssInfo->ucPrimaryChannel = 52; // Bond to Channel 52 */ ++ } else { ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = 8; /* Bond to Channel 6 */ ++ } ++ ++ /* Bandwidth */ ++ if (prMcrWrInfo->u4McrData & 0x00010000) { ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ ++ if (prMcrWrInfo->u4McrData == 0x00010002) { ++ prBssInfo->eBssSCO = CHNL_EXT_SCB; /* U20 */ ++ prBssInfo->ucPrimaryChannel += 2; ++ } else if (prMcrWrInfo->u4McrData == 0x00010001) { ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* L20 */ ++ prBssInfo->ucPrimaryChannel -= 2; ++ } else { ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* 40 */ ++ } ++ } ++ ++ if (prMcrWrInfo->u4McrData & 0x00000000) { ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ } ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ } ++ /* 0xFFFFFFFB for HT Capability */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFB) { ++ /* Enable HT Capability */ ++ if (prMcrWrInfo->u4McrData & 0x00000001) { ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ DEBUGFUNC("[Stress Test]Enable HT capability...\n"); ++ } else { ++ prStaRec->u2HtCapInfo &= (~HT_CAP_INFO_HT_GF); ++ DEBUGFUNC("[Stress Test]Disable HT capability...\n"); ++ } ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ } ++ /* 0xFFFFFFFA for Enable Random Rx Reset */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFA) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_RANDOM_RX_RESET_EN, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF9 for Disable Random Rx Reset */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF9) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_RANDOM_RX_RESET_DE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF8 for Enable SAPP */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF8) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SAPP_EN, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ /* 0xFFFFFFF7 for Disable SAPP */ ++ else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF7) { ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SAPP_DE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++ ++ else ++#endif ++ /* -- Puff Stress Test End */ ++ ++ /* Check if access F/W Domain MCR */ ++ if (prMcrWrInfo->u4McrOffset & 0xFFFF0000) { ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++#if CFG_SUPPORT_SWCR ++ if ((prMcrWrInfo->u4McrOffset >> 16) == 0x9F00) { ++ swCrReadWriteCmd(prAdapter, ++ SWCR_WRITE, ++ (UINT_16) (prMcrWrInfo->u4McrOffset & BITS(0, 15)), &prMcrWrInfo->u4McrData); ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if 1 ++ /* low power test special command */ ++ if (prMcrWrInfo->u4McrOffset == 0x11111110) { ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ /* DbgPrint("Enter test mode\n"); */ ++ prAdapter->fgTestMode = TRUE; ++ return rStatus; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111111) { ++ /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ ++ ++ nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111112) { ++ ++ /* DbgPrint("LP enter sleep\n"); */ ++ ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++#endif ++ ++#if 1 ++ /* low power test special command */ ++ if (prMcrWrInfo->u4McrOffset == 0x11111110) { ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ /* DbgPrint("Enter test mode\n"); */ ++ prAdapter->fgTestMode = TRUE; ++ return rStatus; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111111) { ++ /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ ++ ++ nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ return WLAN_STATUS_SUCCESS; ++ } ++ if (prMcrWrInfo->u4McrOffset == 0x11111112) { ++ ++ /* DbgPrint("LP enter sleep\n"); */ ++ ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } ++#endif ++ /* fill command */ ++ rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; ++ rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_REG), ++ (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); ++ } else { ++ HAL_MCR_WR(prAdapter, (prMcrWrInfo->u4McrOffset & BITS(2, 31)), /* address is in DWORD unit */ ++ prMcrWrInfo->u4McrData); ++ ++ DBGLOG(OID, TRACE, "MCR Write: Offset = %#08x, Data = %#08x\n", ++ prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++} /* wlanoidSetMcrWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query SW CTRL ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ WLAN_STATUS rWlanStatus; ++ UINT_16 u2Id, u2SubId; ++ UINT_32 u4Data; ++ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ ++ DEBUGFUNC("wlanoidQuerySwCtrlRead"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvQueryBuffer; ++ ++ u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); ++ u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); ++ u4Data = 0; ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ switch (u2Id) { ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++#if CFG_SUPPORT_SWCR ++ case 0x9F00: ++ swCrReadWriteCmd(prAdapter, SWCR_READ /* Read */ , ++ (UINT_16) u2SubId, &u4Data); ++ break; ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ case 0xFFFF: ++ { ++ u4Data = 0x5AA56620; ++ } ++ break; ++ ++ case 0x9000: ++ default: ++ { ++ rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; ++ rCmdSwCtrl.u4Data = 0; ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQuerySwCtrlRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_SW_DBG_CTRL_T), ++ (PUINT_8) &rCmdSwCtrl, pvQueryBuffer, u4QueryBufferLen); ++ } ++ } /* switch(u2Id) */ ++ ++ prSwCtrlInfo->u4Data = u4Data; ++ ++ return rWlanStatus; ++ ++} ++ ++ /* end of wlanoidQuerySwCtrlRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write SW CTRL ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ WLAN_STATUS rWlanStatus; ++ UINT_16 u2Id, u2SubId; ++ UINT_32 u4Data; ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ P_GLUE_INFO_T prGlueInfo; ++ CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; ++#endif ++ ++ DEBUGFUNC("wlanoidSetSwCtrlWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ prGlueInfo = prAdapter->prGlueInfo; ++#endif ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvSetBuffer; ++ ++ u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); ++ u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); ++ u4Data = prSwCtrlInfo->u4Data; ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ switch (u2Id) { ++ ++ /* 0x9000 - 0x9EFF reserved for FW */ ++ /* 0xFFFE reserved for FW */ ++ ++#if CFG_SUPPORT_SWCR ++ case 0x9F00: ++ swCrReadWriteCmd(prAdapter, SWCR_WRITE, (UINT_16) u2SubId, &u4Data); ++ break; ++#endif /* CFG_SUPPORT_SWCR */ ++ ++ case 0x1000: ++ if (u2SubId == 0x8000) { ++ /* CTIA power save mode setting (code: 0x10008000) */ ++ prAdapter->u4CtiaPowerMode = u4Data; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ /* */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ if (prAdapter->u4CtiaPowerMode == 0) ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ else if (prAdapter->u4CtiaPowerMode == 1) ++ ePowerMode = Param_PowerModeMAX_PSP; ++ else ++ ePowerMode = Param_PowerModeFast_PSP; ++ ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); ++ } ++ } ++ break; ++ case 0x1001: ++ if (u2SubId == 0x0) ++ prAdapter->fgEnOnlineScan = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x1) ++ prAdapter->fgDisBcnLostDetection = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x2) ++ prAdapter->rWifiVar.fgSupportUAPSD = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x3) { ++ prAdapter->u4UapsdAcBmp = u4Data & BITS(0, 15); ++ prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpDeliveryAC = ++ (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpTriggerAC = ++ (UINT_8) prAdapter->u4UapsdAcBmp; ++ } else if (u2SubId == 0x4) ++ prAdapter->fgDisStaAgingTimeoutDetection = (BOOLEAN) u4Data; ++ else if (u2SubId == 0x5) ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = (UINT_8) u4Data; ++ else if (u2SubId == 0x0100) ++ prAdapter->rWifiVar.u8SupportRxGf = (UINT_8) u4Data; ++ else if (u2SubId == 0x0101) { ++ prAdapter->rWifiVar.u8SupportRxSgi20 = (UINT_8) u4Data; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = (UINT_8) u4Data; ++ } else if (u2SubId == 0x0102) ++ prAdapter->rWifiVar.u8SupportRxSTBC = (UINT_8) u4Data; ++ break; ++ ++#if CFG_SUPPORT_SWCR ++ case 0x1002: ++ if (u2SubId == 0x0) { ++ if (u4Data) ++ u4Data = BIT(HIF_RX_PKT_TYPE_MANAGEMENT); ++ swCrFrameCheckEnable(prAdapter, u4Data); ++ } else if (u2SubId == 0x1) { ++ BOOLEAN fgIsEnable; ++ UINT_8 ucType; ++ UINT_32 u4Timeout; ++ ++ fgIsEnable = (BOOLEAN) (u4Data & 0xff); ++ ucType = 0; /* ((u4Data>>4) & 0xf); */ ++ u4Timeout = ((u4Data >> 8) & 0xff); ++ swCrDebugCheckEnable(prAdapter, fgIsEnable, ucType, u4Timeout); ++ } ++ break; ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ case 0x2000: ++ DBGLOG(RSN, TRACE, "802.11w test 0x%x\n", u2SubId); ++ if (u2SubId == 0x0) ++ rsnStartSaQuery(prAdapter); ++ if (u2SubId == 0x1) ++ rsnStopSaQuery(prAdapter); ++ if (u2SubId == 0x2) ++ rsnSaQueryRequest(prAdapter, NULL); ++ if (u2SubId == 0x3) { ++ P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); ++ ++ authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP, NULL, 7, NULL); ++ } ++ /* wext_set_mode */ ++ /* ++ if (u2SubId == 0x3) { ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_DISABLED; ++ } ++ if (u2SubId == 0x4) { ++ //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_OPTIONAL; ++ } ++ if (u2SubId == 0x5) { ++ //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_REQUIRED; ++ } ++ */ ++ break; ++#endif ++ case 0xFFFF: ++ { ++/* CMD_ACCESS_REG rCmdAccessReg; */ ++#if 1 /* CFG_MT6573_SMT_TEST */ ++ if (u2SubId == 0x0123) { ++ ++ DBGLOG(HAL, TRACE, "set smt fixed rate: %u\n", u4Data); ++ ++ if ((ENUM_REGISTRY_FIXED_RATE_T) (u4Data) < FIXED_RATE_NUM) ++ prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (u4Data); ++ else ++ prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; ++ ++ if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) ++ /* Enable Auto (Long/Short) Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; ++ else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) ++ || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && ++ prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) ++ /* Force Short Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; ++ else ++ /* Force Long Preamble */ ++ prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; ++ ++ /* abort to re-connect */ ++#if 1 ++ DBGLOG(OID, TRACE, "DisBySwC\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++#else ++ aisBssBeaconTimeout(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++ ++ } else if (u2SubId == 0x1234) { ++ /* 1. Disable On-Lin Scan */ ++ /* 3. Disable FIFO FULL no ack */ ++ /* 4. Disable Roaming */ ++ /* Disalbe auto tx power */ ++ /* 2. Keep at CAM mode */ ++ /* 5. Disable Beacon Timeout Detection */ ++ rWlanStatus = nicEnterCtiaMode(prAdapter, TRUE, TRUE); ++ } else if (u2SubId == 0x1235) { ++ /* 1. Enaable On-Lin Scan */ ++ /* 3. Enable FIFO FULL no ack */ ++ /* 4. Enable Roaming */ ++ /* Enable auto tx power */ ++ /* 2. Keep at Fast PS */ ++ /* 5. Enable Beacon Timeout Detection */ ++ rWlanStatus = nicEnterCtiaMode(prAdapter, FALSE, TRUE); ++ } ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ else if (u2SubId == 0x1240) { ++ DBGLOG(P2P, TRACE, "Disable Hotspot Optimization!\n"); ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = FALSE; ++ arHotspotOptimizationCfg.u4Level = 0; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); ++ } else if (u2SubId == 0x1241) { ++ DBGLOG(P2P, TRACE, "Enable Hotspot Optimization!\n"); ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; ++ arHotspotOptimizationCfg.u4Level = 5; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); ++ } ++#endif /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ else if (u2SubId == 0x1250) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET DUAL BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_NULL; ++ } else if (u2SubId == 0x1251) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET 2.4G BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_2G4; ++ } else if (u2SubId == 0x1252) { ++ DBGLOG(OID, TRACE, "LTE_COEX: SW SET 5G BAND\n"); ++ prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_5G; ++ } ++#endif ++ } ++ break; ++ ++ case 0x9000: ++ default: ++ { ++ rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; ++ rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_SW_DBG_CTRL_T), ++ (PUINT_8) &rCmdSwCtrl, pvSetBuffer, u4SetBufferLen); ++ } ++ } /* switch(u2Id) */ ++ ++ return rWlanStatus; ++} ++ ++ /* wlanoidSetSwCtrlWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query EEPROM value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; ++ CMD_ACCESS_EEPROM rCmdAccessEeprom; ++ ++ DEBUGFUNC("wlanoidQueryEepromRead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvQueryBuffer; ++ ++ kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); ++ rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_EEPROM, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryEepromRead, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_EEPROM), ++ (PUINT_8) &rCmdAccessEeprom, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryEepromRead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write EEPROM value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; ++ CMD_ACCESS_EEPROM rCmdAccessEeprom; ++ ++ DEBUGFUNC("wlanoidSetEepromWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); ++ rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; ++ rCmdAccessEeprom.u2Data = prEepromRwInfo->u2EepromData; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_EEPROM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ACCESS_EEPROM), ++ (PUINT_8) &rCmdAccessEeprom, pvSetBuffer, u4SetBufferLen); ++ ++} /* wlanoidSetEepromWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of the successfully transmitted ++* packets. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitOk"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitOk, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitOk */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of the successfully received ++* packets. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRcvOk"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryRecvOk, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryRcvOk */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames that the driver ++* fails to transmit. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitError"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitError, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitError */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames successfully ++* transmitted after exactly one collision. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitOneCollision"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) ++ (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - ++ prAdapter->rStatStruct.rRetryCount.QuadPart); ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) ++ (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - ++ prAdapter->rStatStruct.rRetryCount.QuadPart); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitOneCollision, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* wlanoidQueryXmitOneCollision */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames successfully ++* transmitted after more than one collision. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitMoreCollisions"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitMoreCollisions, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++} /* wlanoidQueryXmitMoreCollisions */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the number of frames ++* not transmitted due to excessive collisions. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryXmitMaxCollisions"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } else if (u4QueryBufferLen < sizeof(UINT_32) ++ || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++#if CFG_ENABLE_STATISTICS_BUFFERING ++ if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { ++ if (u4QueryBufferLen == sizeof(UINT_32)) { ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } else { ++ *pu4QueryInfoLen = sizeof(UINT_64); ++ *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_STATISTICS, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryXmitMaxCollisions, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++} /* wlanoidQueryXmitMaxCollisions */ ++ ++#define MTK_CUSTOM_OID_INTERFACE_VERSION 0x00006620 /* for WPDWifi DLL */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current the OID interface version, ++* which is the interface between the application and driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryOidInterfaceVersion"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *(PUINT_32) pvQueryBuffer = MTK_CUSTOM_OID_INTERFACE_VERSION; ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ DBGLOG(OID, WARN, "Custom OID interface version: %#08X\n", *(PUINT_32) pvQueryBuffer); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryOidInterfaceVersion */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#ifndef LINUX ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_MAC_MCAST_ADDR, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMcastAddr, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return WLAN_STATUS_SUCCESS; ++#endif ++} /* end of wlanoidQueryMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_8 ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Caller should provide this information */ ++ CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* The data must be a multiple of the Ethernet address size. */ ++ if ((u4SetBufferLen % MAC_ADDR_LEN)) { ++ DBGLOG(OID, WARN, "Invalid MC list length %u\n", u4SetBufferLen); ++ ++ *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Verify if we can support so many multicast addresses. */ ++ if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { ++ DBGLOG(OID, WARN, "Too many MC addresses\n"); ++ ++ return WLAN_STATUS_MULTICAST_FULL; ++ } ++ ++ /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && ++ * pvSetBuffer == NULL to clear exist Multicast List. ++ */ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; ++ rCmdMacMcastAddr.ucNetTypeIndex = ucNetTypeIndex; ++ kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_MAC_MCAST_ADDR, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_MAC_MCAST_ADDR), ++ (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); ++} /* end of wlanoidSetMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Packet Filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 u4NewPacketFilter; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) { ++ *pu4SetInfoLen = sizeof(UINT_32); ++ DBGLOG(OID, INFO, "iput buffer is too small"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ASSERT(pvSetBuffer); ++ ++ /* Set the new packet filter. */ ++ u4NewPacketFilter = *(PUINT_32) pvSetBuffer; ++ ++ DBGLOG(OID, TRACE, "New packet filter: %#08x\n", u4NewPacketFilter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set current packet filter! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ do { ++ /* Verify the bits of the new packet filter. If any bits are set that ++ we don't support, leave. */ ++ if (u4NewPacketFilter & ~(PARAM_PACKET_FILTER_SUPPORTED)) { ++ rStatus = WLAN_STATUS_NOT_SUPPORTED; ++ break; ++ } ++#if DBG ++ /* Need to enable or disable promiscuous support depending on the new ++ filter. */ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_PROMISCUOUS) ++ DBGLOG(OID, TRACE, "Enable promiscuous mode\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable promiscuous mode\n"); ++ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) ++ DBGLOG(OID, TRACE, "Enable all-multicast mode\n"); ++ else if (u4NewPacketFilter & PARAM_PACKET_FILTER_MULTICAST) ++ DBGLOG(OID, TRACE, "Enable multicast\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable multicast\n"); ++ ++ if (u4NewPacketFilter & PARAM_PACKET_FILTER_BROADCAST) ++ DBGLOG(OID, TRACE, "Enable Broadcast\n"); ++ else ++ DBGLOG(OID, TRACE, "Disable Broadcast\n"); ++#endif ++ } while (FALSE); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) { ++ /* Store the packet filter */ ++ ++ prAdapter->u4OsPacketFilter &= PARAM_PACKET_FILTER_P2P_MASK; ++ prAdapter->u4OsPacketFilter |= u4NewPacketFilter; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, pvSetBuffer, u4SetBufferLen); ++ } else { ++ return rStatus; ++ } ++} /* wlanoidSetCurrentPacketFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current packet filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryCurrentPacketFilter"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen >= sizeof(UINT_32)) { ++ ASSERT(pvQueryBuffer); ++ *(PUINT_32) pvQueryBuffer = prAdapter->u4OsPacketFilter; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidQueryCurrentPacketFilter */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query ACPI device power state. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++#if DBG ++ PPARAM_DEVICE_POWER_STATE prPowerState; ++#endif ++ ++ DEBUGFUNC("wlanoidQueryAcpiDevicePowerState"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); ++ ++#if DBG ++ prPowerState = (PPARAM_DEVICE_POWER_STATE) pvQueryBuffer; ++ switch (*prPowerState) { ++ case ParamDeviceStateD0: ++ DBGLOG(OID, INFO, "Query Power State: D0\n"); ++ break; ++ case ParamDeviceStateD1: ++ DBGLOG(OID, INFO, "Query Power State: D1\n"); ++ break; ++ case ParamDeviceStateD2: ++ DBGLOG(OID, INFO, "Query Power State: D2\n"); ++ break; ++ case ParamDeviceStateD3: ++ DBGLOG(OID, INFO, "Query Power State: D3\n"); ++ break; ++ default: ++ break; ++ } ++#endif ++ ++ /* Since we will disconnect the newwork, therefore we do not ++ need to check queue empty */ ++ *(PPARAM_DEVICE_POWER_STATE) pvQueryBuffer = ParamDeviceStateD3; ++ /* WARNLOG(("Ready to transition to D3\n")); */ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* pwrmgtQueryPower */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set ACPI device power state. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PPARAM_DEVICE_POWER_STATE prPowerState; ++ BOOLEAN fgRetValue = TRUE; ++ ++ DEBUGFUNC("wlanoidSetAcpiDevicePowerState"); ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); ++ ++ ASSERT(pvSetBuffer); ++ prPowerState = (PPARAM_DEVICE_POWER_STATE) pvSetBuffer; ++ switch (*prPowerState) { ++ case ParamDeviceStateD0: ++ DBGLOG(OID, INFO, "Set Power State: D0\n"); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD0); ++ fgRetValue = nicpmSetAcpiPowerD0(prAdapter); ++ break; ++ case ParamDeviceStateD1: ++ DBGLOG(OID, INFO, "Set Power State: D1\n"); ++ /* no break here */ ++ case ParamDeviceStateD2: ++ DBGLOG(OID, INFO, "Set Power State: D2\n"); ++ /* no break here */ ++ case ParamDeviceStateD3: ++ DBGLOG(OID, INFO, "Set Power State: D3\n"); ++ fgRetValue = nicpmSetAcpiPowerD3(prAdapter); ++ kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); ++ break; ++ default: ++ break; ++ } ++ ++ if (fgRetValue == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++} /* end of wlanoidSetAcpiDevicePowerState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current fragmentation threshold. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryFragThreshold"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ DBGLOG(OID, LOUD, "\n"); ++ ++#if CFG_TX_FRAGMENT ++ ++ return WLAN_STATUS_SUCCESS; ++ ++#else ++ ++ return WLAN_STATUS_NOT_SUPPORTED; ++#endif /* CFG_TX_FRAGMENT */ ++ ++} /* end of wlanoidQueryFragThreshold() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a new fragmentation threshold to the ++* driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if CFG_TX_FRAGMENT ++ ++ return WLAN_STATUS_SUCCESS; ++ ++#else ++ ++ return WLAN_STATUS_NOT_SUPPORTED; ++#endif /* CFG_TX_FRAGMENT */ ++ ++} /* end of wlanoidSetFragThreshold() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the current RTS threshold. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryRtsThreshold"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ DBGLOG(OID, LOUD, "\n"); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { ++ *pu4QueryInfoLen = sizeof(PARAM_RTS_THRESHOLD); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ *((PARAM_RTS_THRESHOLD *) pvQueryBuffer) = prAdapter->rWlanInfo.eRtsThreshold; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidQueryRtsThreshold */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a new RTS threshold to the driver. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PARAM_RTS_THRESHOLD *prRtsThreshold; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_RTS_THRESHOLD); ++ if (u4SetBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRtsThreshold = (PARAM_RTS_THRESHOLD *) pvSetBuffer; ++ *prRtsThreshold = prAdapter->rWlanInfo.eRtsThreshold; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* wlanoidSetRtsThreshold */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to turn radio off. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ ++ DEBUGFUNC("wlanoidSetDisassociate"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set disassociate! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ /* prepare message to AIS */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++ /* Send AIS Abort Message */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; ++ prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ /* indicate for disconnection */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ DBGLOG(OID, INFO, "DisconnectByOid\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, NULL, 0); ++ } ++#if !defined(LINUX) ++ prAdapter->fgIsRadioOff = TRUE; ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} /* wlanoidSetDisassociate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query the power save profile. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQuery802dot11PowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen != 0) { ++ ASSERT(pvQueryBuffer); ++ ++/* *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile); */ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = ++ (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_AIS_INDEX].ucPsProfile); ++ *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); ++ ++ /* hack for CTIA power mode setting function */ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ /* set to non-zero value (to prevent MMI query 0, before it intends to set 0, */ ++ /* which will skip its following state machine) */ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE) 2; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ PARAM_POWER_MODE ePowerMode; ++ ++ DEBUGFUNC("wlanoidSet802dot11PowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); ++ if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { ++ /* WARNLOG(("Invalid power mode %d\n", */ ++ /* *(PPARAM_POWER_MODE) pvSetBuffer)); */ ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; ++ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ if (ePowerMode == Param_PowerModeCAM) ++ ; ++ else { ++ /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ ++ ++ if (prAdapter->u4CtiaPowerMode == 0) ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ else if (prAdapter->u4CtiaPowerMode == 1) ++ ePowerMode = Param_PowerModeMAX_PSP; ++ else if (prAdapter->u4CtiaPowerMode == 2) ++ ePowerMode = Param_PowerModeFast_PSP; ++ } ++ } ++ ++ status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); ++ ++ switch (ePowerMode) { ++ case Param_PowerModeCAM: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to CAM (%d)\n", ePowerMode); ++ break; ++ case Param_PowerModeMAX_PSP: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to MAX PS (%d)\n", ePowerMode); ++ break; ++ case Param_PowerModeFast_PSP: ++ DBGLOG(OID, INFO, "Set Wi-Fi PS mode to FAST PS (%d)\n", ePowerMode); ++ break; ++ default: ++ DBGLOG(OID, INFO, "invalid Wi-Fi PS mode setting (%d)\n", ePowerMode); ++ break; ++ } ++ ++ return status; ++ ++} /* end of wlanoidSetAcpiDevicePowerStateMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current status of AdHoc Mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set AdHoc Mode. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query RF frequency. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryFrequency"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ *(PUINT_32) pvQueryBuffer = ++ nicChannelNum2Freq(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].ucPrimaryChannel); ++ } else { ++ *(PUINT_32) pvQueryBuffer = 0; ++ } ++ } else { ++ *(PUINT_32) pvQueryBuffer = nicChannelNum2Freq(prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryFrequency() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set RF frequency by User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4FreqInKHz; ++ ++ DEBUGFUNC("wlanoidSetFrequency"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4FreqInKHz = (PUINT_32) pvSetBuffer; ++ ++ prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(*pu4FreqInKHz); ++ prAdapter->rWifiVar.rConnSettings.eAdHocBand = *pu4FreqInKHz < 5000000 ? BAND_2G4 : BAND_5G; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetFrequency() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set 802.11 channel of the radio frequency. ++* This is a proprietary function call to Lunux currently. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetChannel(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(0); /* // */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the Beacon Interval from User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryBeaconInterval"); ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; ++ } else { ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = 0; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidQueryBeaconInterval() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the Beacon Interval to User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4BeaconInterval; ++ ++ DEBUGFUNC("wlanoidSetBeaconInterval"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4BeaconInterval = (PUINT_32) pvSetBuffer; ++ ++ if ((*pu4BeaconInterval < DOT11_BEACON_PERIOD_MIN) || (*pu4BeaconInterval > DOT11_BEACON_PERIOD_MAX)) { ++ DBGLOG(OID, TRACE, "Invalid Beacon Interval = %u\n", *pu4BeaconInterval); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ prAdapter->rWlanInfo.u2BeaconPeriod = (UINT_16) *pu4BeaconInterval; ++ ++ DBGLOG(OID, INFO, "Set beacon interval: %d\n", prAdapter->rWlanInfo.u2BeaconPeriod); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetBeaconInterval() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the ATIM window from User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryAtimWindow"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) ++ *(PUINT_32) pvQueryBuffer = 0; ++ else ++ *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2AtimWindow; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wlanoidQueryAtimWindow() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the ATIM window to User Settings. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4AtimWindow; ++ ++ DEBUGFUNC("wlanoidSetAtimWindow"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ pu4AtimWindow = (PUINT_32) pvSetBuffer; ++ ++ prAdapter->rWlanInfo.u2AtimWindow = (UINT_16) *pu4AtimWindow; ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetAtimWindow() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to Set the MAC address which is currently used by the NIC. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(0); /* // */ ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of wlanoidSetCurrentAddr() */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the checksum offload function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ UINT_32 i, u4CSUMFlags; ++ CMD_BASIC_CONFIG rCmdBasicConfig; ++ ++ DEBUGFUNC("wlanoidSetCSUMOffload"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ u4CSUMFlags = *(PUINT_32) pvSetBuffer; ++ ++ kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); ++ ++ for (i = 0; i < 6; i++) { /* set to broadcast address for not-specified */ ++ rCmdBasicConfig.rMyMacAddr[i] = 0xff; ++ } ++ ++ rCmdBasicConfig.ucNative80211 = 0; /* @FIXME: for Vista */ ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(2); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(1); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) ++ rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(0); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(2); ++ ++ if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(1); ++ ++ if (u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) ++ rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(0); ++ ++ prAdapter->u4CSUMFlags = u4CSUMFlags; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BASIC_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BASIC_CONFIG), (PUINT_8) &rCmdBasicConfig, pvSetBuffer, u4SetBufferLen); ++} ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the IP address for pattern search function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ UINT_32 u4IpV4AddrListSize; ++ P_BSS_INFO_T prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++#endif ++ ++ DEBUGFUNC("wlanoidSetNetworkAddress"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ if (u4IpAddressCount == 0) ++ u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ u4IpV4AddrListSize = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + ++ (u4IpAddressCount * sizeof(IPV4_NETWORK_ADDRESS)); ++ if (prBssInfo->prIpV4NetAddrList) ++ FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); ++ prBssInfo->prIpV4NetAddrList = (P_IPV4_NETWORK_ADDRESS_LIST) kalMemAlloc(u4IpV4AddrListSize, VIR_MEM_TYPE); ++ if (prBssInfo->prIpV4NetAddrList == NULL) { ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return WLAN_STATUS_FAILURE; ++ } ++ prBssInfo->prIpV4NetAddrList->ucAddrCount = (UINT_8) u4IpAddressCount; ++#endif ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ /* only to set IP address to FW once ARP filter is enabled */ ++ if (prAdapter->fgEnArpFilter) { ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ ++ DBGLOG(OID, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); ++ ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ kalMemCopy(prBssInfo->prIpV4NetAddrList->arNetAddr[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++#endif ++ ++ j++; ++ ++ pucBuf = (PUINT_8) &prNetAddrIp->in_addr; ++ DBGLOG(OID, INFO, ++ "prNetAddrIp->in_addr:%d:%d:%d:%d\n", pucBuf[0], pucBuf[1], pucBuf[2], ++ pucBuf[3]); ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ } ++ ++ } else { ++ prCmdNetworkAddressList->ucAddressCount = 0; ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set driver to switch into RF test mode ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, ++* should be NULL ++* \param[in] u4SetBufferLen The length of the set buffer, should be 0 ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_DATA ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus; ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ DEBUGFUNC("wlanoidRftestSetTestMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen == 0) { ++ if (prAdapter->fgTestMode == FALSE) { ++ /* switch to RF Test mode */ ++ rCmdTestCtrl.ucAction = 0; /* Switch mode */ ++ rCmdTestCtrl.u.u4OpMode = 1; /* RF test mode */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ TRUE, ++ TRUE, ++ nicCmdEventEnterRfTest, ++ nicOidCmdEnterRFTestTimeout, ++ sizeof(CMD_TEST_CTRL_T), ++ (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); ++ } else { ++ /* already in test mode .. */ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } ++ } else { ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ DBGLOG(OID, INFO, "Enter TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", ++ u4SetBufferLen, prAdapter->fgTestMode, rStatus); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set driver to switch into normal operation mode from RF test mode ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* should be NULL ++* \param[in] u4SetBufferLen The length of the set buffer, should be 0 ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_DATA ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus; ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ DEBUGFUNC("wlanoidRftestSetTestMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen == 0) { ++ if (prAdapter->fgTestMode == TRUE) { ++ /* switch to normal mode */ ++ rCmdTestCtrl.ucAction = 0; /* Switch mode */ ++ rCmdTestCtrl.u.u4OpMode = 0; /* normal mode */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventLeaveRfTest, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_TEST_CTRL_T), ++ (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); ++ } else { ++ /* already in normal mode .. */ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } ++ } else { ++ rStatus = WLAN_STATUS_INVALID_DATA; ++ } ++ DBGLOG(OID, INFO, "Abort TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", ++ u4SetBufferLen, prAdapter->fgTestMode, rStatus); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief query for RF test parameter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidRftestQueryAutoTest"); ++ ++ ASSERT(prAdapter); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); ++ ++ if (u4QueryBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { ++ DBGLOG(OID, ERROR, "Invalid data. QueryBufferLen: %u.\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvQueryBuffer; ++ rStatus = rftestQueryATInfo(prAdapter, ++ prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData, pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set RF test parameter ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidRftestSetAutoTest"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); ++ ++ if (u4SetBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { ++ DBGLOG(OID, ERROR, "Invalid data. SetBufferLen: %u.\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvSetBuffer; ++ rStatus = rftestSetATInfo(prAdapter, prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData); ++ ++ return rStatus; ++} ++ ++/* RF test OID set handler */ ++WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_TEST_CTRL_T pCmdTestCtrl; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_TEST_MODE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ ++ /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); ++ pCmdTestCtrl->ucAction = 1; /* Set ATInfo */ ++ pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; ++ pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS ++rftestQueryATInfo(IN P_ADAPTER_T prAdapter, ++ UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_CMD_TEST_CTRL_T pCmdTestCtrl; ++ UINT_8 ucCmdSeqNum; ++ P_EVENT_TEST_STATUS prTestStatus; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u4FuncIndex == RF_AT_FUNCID_FW_INFO) { ++ /* driver implementation */ ++ prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; ++ ++ prTestStatus->rATInfo.u4FuncData = ++ (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); ++ u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); ++ ++ return WLAN_STATUS_SUCCESS; ++ } else if (u4FuncIndex == RF_AT_FUNCID_DRV_INFO) { ++ /* driver implementation */ ++ prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; ++ ++ prTestStatus->rATInfo.u4FuncData = CFG_DRV_OWN_VERSION; ++ u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryRfTestATInfo; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_TEST_MODE; ++ prCmdInfo->fgSetQuery = FALSE; ++ prCmdInfo->fgNeedResp = TRUE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); ++ prCmdInfo->pvInformationBuffer = pvQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4QueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); ++ pCmdTestCtrl->ucAction = 2; /* Get ATInfo */ ++ pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; ++ pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} ++ ++WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen) ++{ ++ CMD_TEST_CTRL_T rCmdTestCtrl; ++ ++ ASSERT(prAdapter); ++ ++ rCmdTestCtrl.ucAction = 5; /* Set Channel Frequency */ ++ rCmdTestCtrl.u.u4ChannelFreq = u4FreqInKHz; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TEST_MODE, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, sizeof(CMD_TEST_CTRL_T), (PUINT_8) &rCmdTestCtrl, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ DEBUGFUNC("wlanSendSetQueryCmd"); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(OID, TRACE, "ucCmdSeqNum =%d, ucCID =%d\n", ucCmdSeqNum, ucCID); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WAPI ui to set wapi mode, which is needed to info the the driver ++* to operation at WAPI mode while driver initialize. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ DEBUGFUNC("wlanoidSetWapiMode"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ASSERT(pvSetBuffer); ++ ++ /* Todo:: For support WAPI and Wi-Fi at same driver, use the set wapi assoc ie at the check point */ ++ /* The Adapter Connection setting fgUseWapi will cleat whil oid set mode (infra), */ ++ /* And set fgUseWapi True while set wapi assoc ie */ ++ /* policay selection, add key all depend on this flag, */ ++ /* The fgUseWapi may remove later */ ++ if (*(PUINT_32) pvSetBuffer) ++ prAdapter->fgUseWapi = TRUE; ++ else ++ prAdapter->fgUseWapi = FALSE; ++ ++#if 0 ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + 4)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_BUILD_CONNECTION cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + 4; ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_WAPI_MODE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ cp = (PUINT_8) (prWifiCmd->aucBuffer); ++ ++ kalMemCopy(cp, (PUINT_8) pvSetBuffer, 4); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++#else ++ return WLAN_STATUS_SUCCESS; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WAPI to set the assoc info, which is needed to add to ++* Association request frame while join WAPI AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_WAPI_INFO_ELEM_T prWapiInfo; ++ PUINT_8 cp; ++ UINT_16 u2AuthSuiteCount = 0; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_32 u4AuthKeyMgtSuite = 0; ++ UINT_32 u4PairSuite = 0; ++ UINT_32 u4GroupSuite = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetWapiAssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen < 20 /* From EID to Group cipher */) { ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++ DBGLOG(SEC, INFO, "fgWapiMode = FALSE due to u4SetBufferLen %u < 20!\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = TRUE; ++ ++ /* if (prWapiInfo->ucElemId != ELEM_ID_WAPI) */ ++ /* DBGLOG(SEC, TRACE, ("Not WAPI IE ?!\n")); */ ++ ++ /* if (prWapiInfo->ucLength < 18) */ ++ /* return WLAN_STATUS_INVALID_LENGTH; */ ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prWapiInfo = (P_WAPI_INFO_ELEM_T) pvSetBuffer; ++ ++ if (prWapiInfo->ucElemId != ELEM_ID_WAPI) { ++ DBGLOG(SEC, INFO, "Not WAPI IE ?! u4SetBufferLen = %u\n", u4SetBufferLen); ++ prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prWapiInfo->ucLength < 18) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* Skip Version check */ ++ cp = (PUINT_8) &prWapiInfo->u2AuthKeyMgtSuiteCount; ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ ++ if (u2AuthSuiteCount > 1) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ cp = (PUINT_8) &prWapiInfo->aucAuthKeyMgtSuite1[0]; ++ WLAN_GET_FIELD_32(cp, &u4AuthKeyMgtSuite); ++ ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info auth mgt suite [%d]: %02x-%02x-%02x-%02x\n", ++ u2AuthSuiteCount, ++ (UCHAR) (u4AuthKeyMgtSuite & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 16) & 0x000000FF), ++ (UCHAR) ((u4AuthKeyMgtSuite >> 24) & 0x000000FF)); ++ ++ if (u4AuthKeyMgtSuite != WAPI_AKM_SUITE_802_1X && u4AuthKeyMgtSuite != WAPI_AKM_SUITE_PSK) ++ ASSERT(FALSE); ++ ++ cp += 4; ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ if (u2PairSuiteCount > 1) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ cp += 2; ++ WLAN_GET_FIELD_32(cp, &u4PairSuite); ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info pairwise cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ u2PairSuiteCount, ++ (UCHAR) (u4PairSuite & 0x000000FF), ++ (UCHAR) ((u4PairSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4PairSuite >> 16) & 0x000000FF), (UCHAR) ((u4PairSuite >> 24) & 0x000000FF)); ++ ++ if (u4PairSuite != WAPI_CIPHER_SUITE_WPI) ++ ASSERT(FALSE); ++ ++ cp += 4; ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ DBGLOG(SEC, TRACE, "WAPI: Assoc Info group cipher suite : %02x-%02x-%02x-%02x\n", ++ (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (u4GroupSuite != WAPI_CIPHER_SUITE_WPI) ++ ASSERT(FALSE); ++ ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite = u4AuthKeyMgtSuite; ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher = u4PairSuite; ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher = u4GroupSuite; ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucWapiAssocInfoIEs, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the wpi key to the driver. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer P_PARAM_WPI_KEY, which is set by NDIS, is unpacked. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ P_PARAM_WPI_KEY_T prNewKey; ++ P_CMD_802_11_KEY prCmdKey; ++ PUINT_8 pc; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanoidSetWapiKey"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\r\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ prNewKey = (P_PARAM_WPI_KEY_T) pvSetBuffer; ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) pvSetBuffer, 560); ++ pc = (PUINT_8) pvSetBuffer; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Exception check */ ++ if (prNewKey->ucKeyID != 0x1 || prNewKey->ucKeyID != 0x0) { ++ prNewKey->ucKeyID = prNewKey->ucKeyID & BIT(0); ++ /* DBGLOG(SEC, INFO, ("Invalid WAPI key ID (%d)\r\n", prNewKey->ucKeyID)); */ ++ } ++ ++ /* Dump P_PARAM_WPI_KEY_T content. */ ++ DBGLOG(OID, TRACE, "Set: Dump P_PARAM_WPI_KEY_T content\r\n"); ++ DBGLOG(OID, TRACE, "TYPE : %d\r\n", prNewKey->eKeyType); ++ DBGLOG(OID, TRACE, "Direction : %d\r\n", prNewKey->eDirection); ++ DBGLOG(OID, TRACE, "KeyID : %d\r\n", prNewKey->ucKeyID); ++ DBGLOG(OID, TRACE, "AddressIndex:\r\n"); ++ DBGLOG_MEM8(OID, TRACE, prNewKey->aucAddrIndex, 12); ++ prNewKey->u4LenWPIEK = 16; ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPIEK, (UINT_8) prNewKey->u4LenWPIEK); ++ prNewKey->u4LenWPICK = 16; ++ ++ DBGLOG(OID, TRACE, "CK Key(%d):\r\n", (UINT_8) prNewKey->u4LenWPICK); ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPICK, (UINT_8) prNewKey->u4LenWPICK); ++ DBGLOG(OID, TRACE, "PN:\r\n"); ++ if (prNewKey->eKeyType == 0) { ++ prNewKey->aucPN[0] = 0x5c; ++ prNewKey->aucPN[1] = 0x36; ++ prNewKey->aucPN[2] = 0x5c; ++ prNewKey->aucPN[3] = 0x36; ++ prNewKey->aucPN[4] = 0x5c; ++ prNewKey->aucPN[5] = 0x36; ++ prNewKey->aucPN[6] = 0x5c; ++ prNewKey->aucPN[7] = 0x36; ++ prNewKey->aucPN[8] = 0x5c; ++ prNewKey->aucPN[9] = 0x36; ++ prNewKey->aucPN[10] = 0x5c; ++ prNewKey->aucPN[11] = 0x36; ++ prNewKey->aucPN[12] = 0x5c; ++ prNewKey->aucPN[13] = 0x36; ++ prNewKey->aucPN[14] = 0x5c; ++ prNewKey->aucPN[15] = 0x36; ++ } ++ ++ DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucPN, 16); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetBufferLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ ++ /* compose CMD_ID_ADD_REMOVE_KEY cmd pkt */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; ++ prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); ++ prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; ++ prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; ++ prCmdInfo->fgIsOid = TRUE; ++ prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetBufferLen; ++ prCmdInfo->pvInformationBuffer = pvSetBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetBufferLen; ++ ++ /* Setup WIFI_CMD_T */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); ++ ++ kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ prCmdKey->ucAddRemove = 1; /* Add */ ++ ++ if (prNewKey->eKeyType == ENUM_WPI_PAIRWISE_KEY) { ++ prCmdKey->ucTxKey = 1; ++ prCmdKey->ucKeyType = 1; ++ } ++ ++ kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->aucAddrIndex, MAC_ADDR_LEN); ++ ++ prCmdKey->ucNetType = 0; /* AIS */ ++ ++ prCmdKey->ucKeyId = prNewKey->ucKeyID; ++ ++ prCmdKey->ucKeyLen = 32; ++ ++ prCmdKey->ucAlgorithmId = CIPHER_SUITE_WPI; ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucWPIEK, 16); ++ ++ kalMemCopy(prCmdKey->aucKeyMaterial + 16, (PUINT_8) prNewKey->aucWPICK, 16); ++ ++ kalMemCopy(prCmdKey->aucKeyRsc, (PUINT_8) prNewKey->aucPN, 16); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ ++ return WLAN_STATUS_PENDING; ++} /* wlanoidSetAddKey */ ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the assoc info, which is needed to add to ++* Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetWSCAssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucWSCAssocInfoIE, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++#endif ++ ++#if CFG_ENABLE_WAKEUP_ON_LAN ++WLAN_STATUS ++wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_PM_PACKET_PATTERN prPacketPattern; ++ ++ DEBUGFUNC("wlanoidSetAddWakeupPattern"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); ++ ++ if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; ++ ++ /* FIXME: ++ * Send the struct to firmware */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++ ++WLAN_STATUS ++wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_PM_PACKET_PATTERN prPacketPattern; ++ ++ DEBUGFUNC("wlanoidSetAddWakeupPattern"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); ++ ++ if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; ++ ++ /* FIXME: ++ * Send the struct to firmware */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++ ++WLAN_STATUS ++wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ PUINT_32 pu4WakeupEventEnable; ++ ++ DEBUGFUNC("wlanoidQueryEnableWakeup"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ if (u4QueryBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ ++ pu4WakeupEventEnable = (PUINT_32) pvQueryBuffer; ++ ++ *pu4WakeupEventEnable = prAdapter->u4WakeupEventEnable; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4WakeupEventEnable; ++ ++ DEBUGFUNC("wlanoidSetEnableWakup"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ ++ if (u4SetBufferLen < sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ pu4WakeupEventEnable = (PUINT_32) pvSetBuffer; ++ prAdapter->u4WakeupEventEnable = *pu4WakeupEventEnable; ++ ++ /* FIXME: ++ * Send Command Event for setting wakeup-pattern / Magic Packet to firmware ++ * */ ++ ++ return WLAN_STATUS_FAILURE; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure PS related settings for WMM-PS test. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T prWmmPsTestInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_SET_WMM_PS_TEST_STRUCT_T rSetWmmPsTestParam; ++ UINT_16 u2CmdBufLen; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetWiFiWmmPsTest"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T); ++ ++ prWmmPsTestInfo = (P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T) pvSetBuffer; ++ ++ rSetWmmPsTestParam.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rSetWmmPsTestParam.bmfgApsdEnAc = prWmmPsTestInfo->bmfgApsdEnAc; ++ rSetWmmPsTestParam.ucIsEnterPsAtOnce = prWmmPsTestInfo->ucIsEnterPsAtOnce; ++ rSetWmmPsTestParam.ucIsDisableUcTrigger = prWmmPsTestInfo->ucIsDisableUcTrigger; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[rSetWmmPsTestParam.ucNetTypeIndex]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ prPmProfSetupInfo->ucBmpDeliveryAC = (rSetWmmPsTestParam.bmfgApsdEnAc >> 4) & BITS(0, 3); ++ prPmProfSetupInfo->ucBmpTriggerAC = rSetWmmPsTestParam.bmfgApsdEnAc & BITS(0, 3); ++ ++ u2CmdBufLen = sizeof(CMD_SET_WMM_PS_TEST_STRUCT_T); ++ ++#if 0 ++ /* it will apply the disable trig or not immediately */ ++ if (prPmInfo->ucWmmPsDisableUcPoll && prPmInfo->ucWmmPsConnWithTrig) ++ ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, TRUE); */ ++ else ++ ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, FALSE); */ ++#endif ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_WMM_PS_TEST_PARMS, TRUE, FALSE, TRUE, NULL, /* TODO? */ ++ NULL, u2CmdBufLen, (PUINT_8) &rSetWmmPsTestParam, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetWiFiWmmPsTest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure enable/disable TX A-MPDU feature. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_TX_AMPDU_T rTxAmpdu; ++ UINT_16 u2CmdBufLen; ++ PBOOLEAN pfgEnable; ++ ++ DEBUGFUNC("wlanoidSetTxAmpdu"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(BOOLEAN); ++ ++ pfgEnable = (PBOOLEAN) pvSetBuffer; ++ ++ rTxAmpdu.fgEnable = *pfgEnable; ++ ++ u2CmdBufLen = sizeof(CMD_TX_AMPDU_T); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TX_AMPDU, ++ TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rTxAmpdu, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetTxAmpdu */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to configure reject/accept ADDBA Request. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ CMD_ADDBA_REJECT_T rAddbaReject; ++ UINT_16 u2CmdBufLen; ++ PBOOLEAN pfgEnable; ++ ++ DEBUGFUNC("wlanoidSetAddbaReject"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(BOOLEAN); ++ ++ pfgEnable = (PBOOLEAN) pvSetBuffer; ++ ++ rAddbaReject.fgEnable = *pfgEnable; ++ ++ u2CmdBufLen = sizeof(CMD_ADDBA_REJECT_T); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ADDBA_REJECT, ++ TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rAddbaReject, NULL, 0); ++ ++ return rStatus; ++} /* wlanoidSetAddbaReject */ ++ ++#if CFG_SLT_SUPPORT ++ ++WLAN_STATUS ++wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++ ++ DEBUGFUNC("wlanoidQuerySLTStatus"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvQueryBuffer); ++ ++ prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvQueryBuffer; ++ ++ prSltInfo = &(prAdapter->rWifiVar.rSltInfo); ++ ++ switch (prMtkSltInfo->rSltFuncIdx) { ++ case ENUM_MTK_SLT_FUNC_LP_SET: ++ { ++ P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); ++ ++ prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ prLpSetting->u4BcnRcvNum = prSltInfo->u4BeaconReceiveCnt; ++ } ++ break; ++ default: ++ /* TBD... */ ++ break; ++ } ++ ++ return rWlanStatus; ++} /* wlanoidQuerySLTStatus */ ++ ++WLAN_STATUS ++wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ ++ /* 1. Action: Update or Initial Set ++ * 2. Role. ++ * 3. Target MAC address. ++ * 4. RF BW & Rate Settings ++ */ ++ ++ DEBUGFUNC("wlanoidUpdateSLTMode"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvSetBuffer; ++ ++ prSltInfo = &(prAdapter->rWifiVar.rSltInfo); ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ switch (prMtkSltInfo->rSltFuncIdx) { ++ case ENUM_MTK_SLT_FUNC_INITIAL: /* Initialize */ ++ { ++ P_PARAM_MTK_SLT_INITIAL_STRUCT_T prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_INITIAL_STRUCT_T)); ++ ++ prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prSltInfo->prPseudoStaRec != NULL) { ++ /* The driver has been initialized. */ ++ prSltInfo->prPseudoStaRec = NULL; ++ } ++ ++ prSltInfo->prPseudoBssDesc = scanSearchExistingBssDesc(prAdapter, ++ BSS_TYPE_IBSS, ++ prMtkSltInit->aucTargetMacAddr, ++ prMtkSltInit->aucTargetMacAddr); ++ ++ prSltInfo->u2SiteID = prMtkSltInit->u2SiteID; ++ ++ /* Bandwidth 2.4G: Channel 1~14 ++ * Bandwidth 5G: *36, 40, 44, 48, 52, 56, 60, 64, ++ * *100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, ++ * 149, 153, *157, 161, ++ * 184, 188, 192, 196, 200, 204, 208, 212, *216 ++ */ ++ prSltInfo->ucChannel2G4 = 1 + (prSltInfo->u2SiteID % 4) * 5; ++ ++ switch (prSltInfo->ucChannel2G4) { ++ case 1: ++ prSltInfo->ucChannel5G = 36; ++ break; ++ case 6: ++ prSltInfo->ucChannel5G = 52; ++ break; ++ case 11: ++ prSltInfo->ucChannel5G = 104; ++ break; ++ case 16: ++ prSltInfo->ucChannel2G4 = 14; ++ prSltInfo->ucChannel5G = 161; ++ break; ++ default: ++ ASSERT(FALSE); ++ } ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ do { ++ prSltInfo->prPseudoBssDesc = scanAllocateBssDesc(prAdapter); ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ } while (FALSE); ++ } else { ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ } ++ ++ if (prBssDesc) { ++ prBssDesc->eBSSType = BSS_TYPE_IBSS; ++ ++ COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prMtkSltInit->aucTargetMacAddr); ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ ++ prBssDesc->u2BeaconInterval = 100; ++ prBssDesc->u2ATIMWindow = 0; ++ prBssDesc->ucDTIMPeriod = 1; ++ ++ prBssDesc->u2IELength = 0; ++ ++ prBssDesc->fgIsERPPresent = TRUE; ++ prBssDesc->fgIsHTPresent = TRUE; ++ ++ prBssDesc->u2OperationalRateSet = BIT(RATE_36M_INDEX); ++ prBssDesc->u2BSSBasicRateSet = BIT(RATE_36M_INDEX); ++ prBssDesc->fgIsUnknownBssBasicRate = FALSE; ++ ++ prBssDesc->fgIsLargerTSF = TRUE; ++ ++ prBssDesc->eBand = BAND_2G4; ++ ++ prBssDesc->ucChannelNum = prSltInfo->ucChannel2G4; ++ ++ prBssDesc->ucPhyTypeSet = PHY_TYPE_SET_802_11ABGN; ++ ++ GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); ++ } ++ } ++ break; ++ case ENUM_MTK_SLT_FUNC_RATE_SET: /* Update RF Settings. */ ++ if (prSltInfo->prPseudoStaRec == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ P_PARAM_MTK_SLT_TR_TEST_STRUCT_T prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_TR_TEST_STRUCT_T)); ++ ++ prStaRec = prSltInfo->prPseudoStaRec; ++ prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { ++ prBssInfo->eBand = BAND_5G; ++ prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel5G; ++ } ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM24) { ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel2G4; ++ } ++ ++ if ((prTRSetting->u4FixedRate & FIXED_BW_DL40) != 0) { ++ /* RF 40 */ ++ /* It would controls RFBW capability in WTBL. */ ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ /* This controls RF BW, RF BW would be 40 only if */ ++ /* 1. PHY_TYPE_BIT_HT is TRUE. */ ++ /* 2. SCO is SCA/SCB. */ ++ prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ ++ /* U20/L20 Control. */ ++ switch (prTRSetting->u4FixedRate & 0xC000) { ++ case FIXED_EXT_CHNL_U20: ++ prBssInfo->eBssSCO = CHNL_EXT_SCB; /* +2 */ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) ++ prBssInfo->ucPrimaryChannel += 2; ++ else { ++ /* For channel 1, testing L20 at channel 8. */ ++ if (prBssInfo->ucPrimaryChannel < 5) ++ prBssInfo->ucPrimaryChannel = 8; ++ } ++ break; ++ case FIXED_EXT_CHNL_L20: ++ default: /* 40M */ ++ prBssInfo->eBssSCO = CHNL_EXT_SCA; /* -2 */ ++ if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { ++ prBssInfo->ucPrimaryChannel -= 2; ++ } else { ++ /* For channel 11 / 14. testing U20 at channel 3. */ ++ if (prBssInfo->ucPrimaryChannel > 10) ++ prBssInfo->ucPrimaryChannel = 3; ++ } ++ break; ++ } ++ } else { ++ /* RF 20 */ ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ } ++ ++ prBssInfo->fgErpProtectMode = FALSE; ++ prBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; ++ prBssInfo->eGfOperationMode = GF_MODE_NORMAL; ++ ++ nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); ++ ++ prStaRec->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ switch (prTRSetting->u4FixedRate & 0xFF) { ++ case RATE_OFDM_54M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_54M_INDEX); ++ break; ++ case RATE_OFDM_48M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_48M_INDEX); ++ break; ++ case RATE_OFDM_36M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); ++ break; ++ case RATE_OFDM_24M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_24M_INDEX); ++ break; ++ case RATE_OFDM_6M: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_6M_INDEX); ++ break; ++ case RATE_CCK_11M_LONG: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_11M_INDEX); ++ break; ++ case RATE_CCK_1M_LONG: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_1M_INDEX); ++ break; ++ case RATE_GF_MCS_0: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ break; ++ case RATE_MM_MCS_7: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; ++#if 0 /* Only for Current Measurement Mode. */ ++ prStaRec->u2HtCapInfo |= (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++#endif ++ break; ++ case RATE_GF_MCS_7: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; ++ break; ++ default: ++ prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); ++ break; ++ } ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ break; ++ case ENUM_MTK_SLT_FUNC_LP_SET: /* Reset LP Test Result. */ ++ { ++ P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; ++ ++ ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); ++ ++ prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; ++ ++ if (prSltInfo->prPseudoBssDesc == NULL) { ++ /* Please initial SLT Mode first. */ ++ break; ++ } ++ prBssDesc = prSltInfo->prPseudoBssDesc; ++ ++ switch (prLpSetting->rLpTestMode) { ++ case ENUM_MTK_LP_TEST_NORMAL: ++ /* In normal mode, we would use target MAC address to be the BSSID. */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ prSltInfo->fgIsDUT = FALSE; ++ break; ++ case ENUM_MTK_LP_TEST_GOLDEN_SAMPLE: ++ /* 1. Lower AIFS of BCN queue. ++ * 2. Fixed Random Number tobe 0. ++ */ ++ prSltInfo->fgIsDUT = FALSE; ++ /* In LP test mode, we would use MAC address of Golden Sample to be the BSSID. */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); ++ break; ++ case ENUM_MTK_LP_TEST_DUT: ++ /* 1. Enter Sleep Mode. ++ * 2. Fix random number a large value & enlarge AIFN of BCN queue. ++ */ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssDesc->aucSrcAddr); ++ prSltInfo->u4BeaconReceiveCnt = 0; ++ prSltInfo->fgIsDUT = TRUE; ++ break; ++ } ++ ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ return WLAN_STATUS_FAILURE; ++ ++ return rWlanStatus; ++} /* wlanoidUpdateSLTMode */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query NVRAM value. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; ++ UINT_16 u2Data; ++ BOOLEAN fgStatus; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidQueryNvramRead"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvQueryBuffer; ++ ++ if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_READ) { ++ /* change to byte offset */ ++ fgStatus = kalCfgDataRead16(prAdapter->prGlueInfo, ++ prNvramRwInfo->ucEepromIndex << 1, ++ &u2Data); ++ ++ if (fgStatus) { ++ prNvramRwInfo->u2EepromData = u2Data; ++ DBGLOG(OID, INFO, "NVRAM Read: index=%#X, data=%#02X\r\n", ++ prNvramRwInfo->ucEepromIndex, u2Data); ++ } else { ++ DBGLOG(OID, ERROR, "NVRAM Read Failed: index=%#x.\r\n", prNvramRwInfo->ucEepromIndex); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ } else if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_GETSIZE) { ++ prNvramRwInfo->u2EepromData = CFG_FILE_WIFI_REC_SIZE; ++ DBGLOG(OID, INFO, "EEPROM size =%d\r\n", prNvramRwInfo->u2EepromData); ++ } ++ ++ *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ return rStatus; ++} /* wlanoidQueryNvramRead */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to write NVRAM value. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; ++ BOOLEAN fgStatus; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ DEBUGFUNC("wlanoidSetNvramWrite"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvSetBuffer; ++ ++ /* change to byte offset */ ++ fgStatus = kalCfgDataWrite16(prAdapter->prGlueInfo, ++ prNvramRwInfo->ucEepromIndex << 1, ++ prNvramRwInfo->u2EepromData); ++ ++ if (fgStatus == FALSE) { ++ DBGLOG(OID, ERROR, "NVRAM Write Failed.\r\n"); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ ++ return rStatus; ++} /* wlanoidSetNvramWrite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ *pu4QueryInfoLen = sizeof(ENUM_CFG_SRC_TYPE_T); ++ ++ if (kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE) ++ *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_NVRAM; ++ else ++ *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_EEPROM; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ *pu4QueryInfoLen = sizeof(P_ENUM_EEPROM_TYPE_T); ++ ++#if CFG_SUPPORT_NIC_CAPABILITY ++ if (prAdapter->fgIsEepromUsed == TRUE) ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_PRESENT; ++ else ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; ++#else ++ *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get the config data source type. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_8 pucCountry; ++ UINT_16 u2CountryCode; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(u4SetBufferLen == 2); ++ ++ *pu4SetInfoLen = 2; ++ ++ pucCountry = pvSetBuffer; ++ u2CountryCode = (((UINT_16) pucCountry[0]) << 8) | ((UINT_16) pucCountry[1]); ++ ++ /* previous country code == FF : ignore country code, current country code == FE : resume */ ++ if (prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup == COUNTRY_CODE_FF) { ++ if (u2CountryCode != COUNTRY_CODE_FE) { ++ DBGLOG(OID, INFO, "Skip country code cmd (0x%04x)\n", u2CountryCode); ++ return WLAN_STATUS_SUCCESS; ++ } ++ DBGLOG(OID, INFO, "Resume handle country code cmd (0x%04x)\n", u2CountryCode); ++ } ++ ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode = u2CountryCode; ++ prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ DBGLOG(OID, LOUD, "u2CountryCodeBakup=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup); ++ ++ /* Force to re-search country code in country domains */ ++ prAdapter->prDomainInfo = NULL; ++ rlmDomainSendCmd(prAdapter, TRUE); ++ ++ /* Update supported channel list in channel table based on current country domain */ ++ wlanUpdateChannelTable(prAdapter->prGlueInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if 0 ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; ++ CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; ++ ++ DEBUGFUNC("wlanoidSetNoaParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); ++ rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; ++ rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; ++ rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++} ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; ++ CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; ++ ++ DEBUGFUNC("wlanoidSetOppPsParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_OPPPS_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++} ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; ++ CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetUApsdParam"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; ++ prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; ++ ++ rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; ++ rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; ++ rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; ++ rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; ++ prPmProfSetupInfo->ucBmpDeliveryAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ prPmProfSetupInfo->ucBmpTriggerAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ ++ rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; ++ prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set BT profile or BT information and the ++* driver will set the built-in PTA configuration into chip. ++* ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ++ P_PTA_IPC_T prPtaIpc; ++ ++ DEBUGFUNC("wlanoidSetBT.\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PTA_IPC_T); ++ if (u4SetBufferLen != sizeof(PTA_IPC_T)) { ++ WARNLOG(("Invalid length %u\n", u4SetBufferLen)); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set BT profile because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ prPtaIpc = (P_PTA_IPC_T) pvSetBuffer; ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(OID, INFO, ++ "BCM BWCS CMD: BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", ++ prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], ++ prPtaIpc->u.aucBTPParams[3]; ++ ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BWCS, ++ TRUE, FALSE, FALSE, NULL, NULL, sizeof(PTA_IPC_T), (PUINT_8) prPtaIpc, NULL, 0); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query current BT profile and BTCR values ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBT(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++/* P_PARAM_PTA_IPC_T prPtaIpc; */ ++/* UINT_32 u4QueryBuffLen; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PTA_IPC_T); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(PTA_IPC_T)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++/* prPtaIpc = (P_PTA_IPC_T)pvQueryBuffer; */ ++/* prPtaIpc->ucCmd = BT_CMD_PROFILE; */ ++/* prPtaIpc->ucLen = sizeof(prPtaIpc->u); */ ++/* nicPtaGetProfile(prAdapter, (PUINT_8)&prPtaIpc->u, &u4QueryBuffLen); */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if 0 ++WLAN_STATUS ++wlanoidQueryBtSingleAntenna(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PTA_INFO_T prPtaInfo; ++ PUINT_32 pu4SingleAntenna; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(UINT_32)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ pu4SingleAntenna = (PUINT_32) pvQueryBuffer; ++ ++ if (prPtaInfo->fgSingleAntenna) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 1\r\n")); */ ++ *pu4SingleAntenna = 1; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 0\r\n")); */ ++ *pu4SingleAntenna = 0; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetBtSingleAntenna(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ++ PUINT_32 pu4SingleAntenna; ++ UINT_32 u4SingleAntenna; ++ P_PTA_INFO_T prPtaInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen != sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (IS_ARB_IN_RFTEST_STATE(prAdapter)) ++ return WLAN_STATUS_SUCCESS; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set antenna because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ pu4SingleAntenna = (PUINT_32) pvSetBuffer; ++ u4SingleAntenna = *pu4SingleAntenna; ++ ++ if (u4SingleAntenna == 0) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 0\r\n")); */ ++ prPtaInfo->fgSingleAntenna = FALSE; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 1\r\n")); */ ++ prPtaInfo->fgSingleAntenna = TRUE; ++ } ++ ptaFsmRunEventSetConfig(prAdapter, &prPtaInfo->rPtaParam); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++WLAN_STATUS ++wlanoidQueryPta(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PTA_INFO_T prPtaInfo; ++ PUINT_32 pu4Pta; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen != sizeof(UINT_32)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ ASSERT(pvQueryBuffer); ++ ++ prPtaInfo = &prAdapter->rPtaInfo; ++ pu4Pta = (PUINT_32) pvQueryBuffer; ++ ++ if (prPtaInfo->fgEnabled) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 1\r\n")); */ ++ *pu4Pta = 1; ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 0\r\n")); */ ++ *pu4Pta = 0; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS ++wlanoidSetPta(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ PUINT_32 pu4PtaCtrl; ++ UINT_32 u4PtaCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(UINT_32); ++ if (u4SetBufferLen != sizeof(UINT_32)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ if (IS_ARB_IN_RFTEST_STATE(prAdapter)) ++ return WLAN_STATUS_SUCCESS; ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(OID, WARN, "Fail to set BT setting because of ACPI_D3\n"); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pvSetBuffer); ++ pu4PtaCtrl = (PUINT_32) pvSetBuffer; ++ u4PtaCtrl = *pu4PtaCtrl; ++ ++ if (u4PtaCtrl == 0) { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 0\r\n")); */ ++ nicPtaSetFunc(prAdapter, FALSE); ++ } else { ++ /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 1\r\n")); */ ++ nicPtaSetFunc(prAdapter, TRUE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++#endif ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Tx power profile. ++* ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ /* P_SET_TXPWR_CTRL_T pTxPwr = (P_SET_TXPWR_CTRL_T)pvSetBuffer; */ ++ /* UINT_32 i; */ ++ WLAN_STATUS rStatus; ++ ++ DEBUGFUNC("wlanoidSetTxPower"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ++#if 0 ++ DBGLOG(OID, INFO, "c2GLegacyStaPwrOffset=%d\n", pTxPwr->c2GLegacyStaPwrOffset); ++ DBGLOG(OID, INFO, "c2GHotspotPwrOffset=%d\n", pTxPwr->c2GHotspotPwrOffset); ++ DBGLOG(OID, INFO, "c2GP2pPwrOffset=%d\n", pTxPwr->c2GP2pPwrOffset); ++ DBGLOG(OID, INFO, "c2GBowPwrOffset=%d\n", pTxPwr->c2GBowPwrOffset); ++ DBGLOG(OID, INFO, "c5GLegacyStaPwrOffset=%d\n", pTxPwr->c5GLegacyStaPwrOffset); ++ DBGLOG(OID, INFO, "c5GHotspotPwrOffset=%d\n", pTxPwr->c5GHotspotPwrOffset); ++ DBGLOG(OID, INFO, "c5GP2pPwrOffset=%d\n", pTxPwr->c5GP2pPwrOffset); ++ DBGLOG(OID, INFO, "c5GBowPwrOffset=%d\n", pTxPwr->c5GBowPwrOffset); ++ DBGLOG(OID, INFO, "ucConcurrencePolicy=%d\n", pTxPwr->ucConcurrencePolicy); ++ ++ for (i = 0; i < 14; i++) ++ DBGLOG(OID, INFO, "acTxPwrLimit2G[%d]=%d\n", i, pTxPwr->acTxPwrLimit2G[i]); ++ ++ for (i = 0; i < 4; i++) ++ DBGLOG(OID, INFO, "acTxPwrLimit5G[%d]=%d\n", i, pTxPwr->acTxPwrLimit5G[i]); ++#endif ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_TXPWR_CTRL, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ TRUE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ u4SetBufferLen, /* u4SetQueryInfoLen */ ++ (PUINT_8) pvSetBuffer, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ return rStatus; ++ ++} ++ ++WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) ++{ ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ P_CMD_DUMP_MEM prCmdDumpMem; ++ CMD_DUMP_MEM rCmdDumpMem; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4MemSize = PARAM_MEM_DUMP_MAX_SIZE; ++ ++ UINT_32 u4RemainLeng = 0; ++ UINT_32 u4CurAddr = 0; ++ UINT_8 ucFragNum = 0; ++ ++ prCmdDumpMem = &rCmdDumpMem; ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; ++ ++ u4RemainLeng = prMemDumpInfo->u4RemainLength; ++ u4CurAddr = prMemDumpInfo->u4Address + prMemDumpInfo->u4Length; ++ ucFragNum = prMemDumpInfo->ucFragNum + 1; ++ ++ /* Query. If request length is larger than max length, do it as ping pong. ++ * Send a command and wait for a event. Send next command while the event is received. ++ * ++ */ ++ do { ++ UINT_32 u4CurLeng = 0; ++ ++ if (u4RemainLeng > u4MemSize) { ++ u4CurLeng = u4MemSize; ++ u4RemainLeng -= u4MemSize; ++ } else { ++ u4CurLeng = u4RemainLeng; ++ u4RemainLeng = 0; ++ } ++ ++ prCmdDumpMem->u4Address = u4CurAddr; ++ prCmdDumpMem->u4Length = u4CurLeng; ++ prCmdDumpMem->u4RemainLength = u4RemainLeng; ++ prCmdDumpMem->ucFragNum = ucFragNum; ++ ++ DBGLOG(OID, TRACE, "[%d] 0x%X, len %u, remain len %u\n", ++ ucFragNum, ++ prCmdDumpMem->u4Address, prCmdDumpMem->u4Length, prCmdDumpMem->u4RemainLength); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_DUMP_MEM, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryMemDump, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_DUMP_MEM), ++ (PUINT_8) prCmdDumpMem, pvQueryBuffer, u4QueryBufferLen); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to dump memory. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ ++ DEBUGFUNC("wlanoidQueryMemDump"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_32); ++ ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; ++ DBGLOG(OID, TRACE, "Dump 0x%X, len %u\n", prMemDumpInfo->u4Address, prMemDumpInfo->u4Length); ++ ++ prMemDumpInfo->u4RemainLength = prMemDumpInfo->u4Length; ++ prMemDumpInfo->u4Length = 0; ++ prMemDumpInfo->ucFragNum = 0; ++ ++ return wlanSendMemDumpCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* end of wlanoidQueryMcrRead() */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the p2p mode. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_PARAM_CUSTOM_P2P_SET_STRUCT_T prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) NULL; ++ /* P_MSG_P2P_NETDEV_REGISTER_T prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T)NULL; */ ++ DEBUGFUNC("wlanoidSetP2pMode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T); ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T)) { ++ DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) pvSetBuffer; ++ ++ DBGLOG(P2P, INFO, "Set P2P enable %p [%u] mode[%u]\n", prSetP2P, prSetP2P->u4Enable, prSetP2P->u4Mode); ++ ++ /* ++ * enable = 1, mode = 0 => init P2P network ++ * enable = 1, mode = 1 => init Soft AP network ++ * enable = 0 => uninit P2P/AP network ++ */ ++ ++ if (prSetP2P->u4Enable) { ++ p2pSetMode((prSetP2P->u4Mode == 1) ? TRUE : FALSE); ++ ++ if (p2pLaunch(prAdapter->prGlueInfo)) ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ } else { ++ DBGLOG(P2P, TRACE, "prAdapter->fgIsP2PRegistered = %d\n", prAdapter->fgIsP2PRegistered); ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ DBGLOG(P2P, INFO, "p2pRemove\n"); ++ p2pRemove(prAdapter->prGlueInfo); ++ } ++ ++ } ++ ++#if 0 ++ prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_NETDEV_REGISTER_T))); ++ ++ if (prP2pNetdevRegMsg == NULL) { ++ ASSERT(FALSE); ++ status = WLAN_STATUS_RESOURCES; ++ return status; ++ } ++ ++ prP2pNetdevRegMsg->rMsgHdr.eMsgId = MID_MNY_P2P_NET_DEV_REGISTER; ++ prP2pNetdevRegMsg->fgIsEnable = (prSetP2P->u4Enable == 1) ? TRUE : FALSE; ++ prP2pNetdevRegMsg->ucMode = (UINT_8) prSetP2P->u4Mode; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pNetdevRegMsg, MSG_SEND_METHOD_BUF); ++#endif ++ ++ return status; ++} ++#endif ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query build date code information from firmware ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_GET_BUILD_DATE_CODE rCmdGetBuildDateCode; ++ ++ DEBUGFUNC("wlanoidQueryBuildDateCode"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(UINT_8) * 16; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8) * 16) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BUILD_DATE_CODE, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventBuildDateCode, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_GET_BUILD_DATE_CODE), ++ (PUINT_8) &rCmdGetBuildDateCode, pvQueryBuffer, u4QueryBufferLen); ++ ++} /* end of wlanoidQueryBuildDateCode() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query BSS info from firmware ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ EVENT_AIS_BSS_INFO_T rCmdBSSInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); ++ ++ if (u4QueryBufferLen < sizeof(EVENT_AIS_BSS_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ kalMemZero(&rCmdBSSInfo, sizeof(EVENT_AIS_BSS_INFO_T)); ++ /* ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BSS_INFO, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventGetBSSInfo, ++ nicOidCmdTimeoutCommon, ++ sizeof(P_EVENT_AIS_BSS_INFO_T), ++ (PUINT_8) &rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); ++ */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_BSS_INFO, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventGetBSSInfo, ++ nicOidCmdTimeoutCommon, ++ sizeof(EVENT_AIS_BSS_INFO_T), ++ (PUINT_8) & rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} /* wlanoidSetWiFiWmmPsTest */ ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++#define CMD_WLS_BATCHING "WLS_BATCHING" ++ ++#define BATCHING_SET "SET" ++#define BATCHING_GET "GET" ++#define BATCHING_STOP "STOP" ++ ++#define PARAM_SCANFREQ "SCANFREQ" ++#define PARAM_MSCAN "MSCAN" ++#define PARAM_BESTN "BESTN" ++#define PARAM_CHANNEL "CHANNEL" ++#define PARAM_RTT "RTT" ++ ++WLAN_STATUS ++batchSetCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4WritenLen) ++{ ++ P_CHANNEL_INFO_T prRfChannelInfo; ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ PCHAR head, p, p2; ++ UINT_32 tokens; ++ INT_32 scanfreq, mscan, bestn, rtt; ++ ++ DBGLOG(SCN, TRACE, "[BATCH] command=%s, len=%u\n", (PCHAR) pvSetBuffer, (UINT_32) u4SetBufferLen); ++ ++ if (!pu4WritenLen) ++ return -EINVAL; ++ *pu4WritenLen = 0; ++ ++ if (u4SetBufferLen < kalStrLen(CMD_WLS_BATCHING)) { ++ DBGLOG(SCN, TRACE, "[BATCH] invalid len %u\n", (UINT_32) u4SetBufferLen); ++ return -EINVAL; ++ } ++ ++ head = pvSetBuffer + kalStrLen(CMD_WLS_BATCHING) + 1; ++ kalMemSet(&rCmdBatchReq, 0, sizeof(CMD_BATCH_REQ_T)); ++ ++ if (!kalStrnCmp(head, BATCHING_SET, kalStrLen(BATCHING_SET))) { ++ ++ DBGLOG(SCN, TRACE, "XXX Start Batch Scan XXX\n"); ++ ++ head += kalStrLen(BATCHING_SET) + 1; ++ ++ /* SCANFREQ, MSCAN, BESTN */ ++ tokens = kalSScanf(head, "SCANFREQ=%d MSCAN=%d BESTN=%d", &scanfreq, &mscan, &bestn); ++ if (tokens != 3) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, SCANFREQ=%d MSCAN=%d BESTN=%d\n", ++ (UINT_32) tokens, scanfreq, mscan, bestn); ++ return -EINVAL; ++ } ++ /* RTT */ ++ p = kalStrStr(head, PARAM_RTT); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse RTT fail. head=%s\n", head); ++ return -EINVAL; ++ } ++ tokens = kalSScanf(p, "RTT=%d", &rtt); ++ if (tokens != 1) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, rtt=%d\n", (UINT_32) tokens, rtt); ++ return -EINVAL; ++ } ++ /* CHANNEL */ ++ p = kalStrStr(head, PARAM_CHANNEL); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(1)\n"); ++ return -EINVAL; ++ } ++ head = p; ++ p = kalStrChr(head, '>'); ++ if (!p) { ++ DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(2)\n"); ++ return -EINVAL; ++ } ++ /* else { ++ *p = '.'; // remove '>' because sscanf can not parse <%s> ++ }*/ ++ /*tokens = kalSScanf(head, "CHANNEL=<%s", c_channel); ++ if (tokens != 1) { ++ DBGLOG(SCN, TRACE, ("[BATCH] Parse fail: tokens=%d, CHANNEL=<%s>\n", ++ tokens, c_channel)); ++ return -EINVAL; ++ } */ ++ rCmdBatchReq.ucChannelType = SCAN_CHANNEL_SPECIFIED; ++ rCmdBatchReq.ucChannelListNum = 0; ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ p = head + kalStrLen(PARAM_CHANNEL) + 2; /* c_channel; */ ++ while ((p2 = kalStrSep((char **)&p, ",")) != NULL) { ++ if (p2 == NULL || *p2 == 0) ++ break; ++ if (*p2 == '\0') ++ continue; ++ if (*p2 == 'A') { ++ rCmdBatchReq.ucChannelType = ++ rCmdBatchReq.ucChannelType == ++ SCAN_CHANNEL_2G4 ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_5G; ++ } else if (*p2 == 'B') { ++ rCmdBatchReq.ucChannelType = ++ rCmdBatchReq.ucChannelType == ++ SCAN_CHANNEL_5G ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_2G4; ++ } else { ++ ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo->ucChannelNum = kalStrtol(p2, NULL, 0); ++ DBGLOG(SCN, TRACE, "Scanning Channel:%u, freq: %d\n", ++ (UINT_32) prRfChannelInfo->ucChannelNum, ++ (UINT_32) nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); ++ prRfChannelInfo->ucBand = prRfChannelInfo->ucChannelNum < 15 ? BAND_2G4 : BAND_5G; ++ ++ rCmdBatchReq.ucChannelListNum++; ++ if (rCmdBatchReq.ucChannelListNum >= 32) ++ break; ++ prRfChannelInfo++; ++ } ++ } ++ ++ /* set channel for test */ ++#if 0 ++ rCmdBatchReq.ucChannelType = 4; /* SCAN_CHANNEL_SPECIFIED; */ ++ rCmdBatchReq.ucChannelListNum = 0; ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ for (i = 1; i <= 14; i++) { ++ ++ /* filter out some */ ++ if (i == 1 || i == 5 || i == 11) ++ continue; ++ ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo->ucChannelNum = i; ++ DBGLOG(SCN, TRACE, "Scanning Channel:%d, freq: %d\n", ++ prRfChannelInfo->ucChannelNum, ++ nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); ++ prRfChannelInfo->ucBand = BAND_2G4; ++ ++ rCmdBatchReq.ucChannelListNum++; ++ prRfChannelInfo++; ++ } ++#endif ++#if 0 ++ rCmdBatchReq.ucChannelType = 0; /* SCAN_CHANNEL_FULL; */ ++#endif ++ ++ rCmdBatchReq.u4Scanfreq = scanfreq; ++ rCmdBatchReq.ucMScan = mscan > CFG_BATCH_MAX_MSCAN ? CFG_BATCH_MAX_MSCAN : mscan; ++ rCmdBatchReq.ucBestn = bestn; ++ rCmdBatchReq.ucRtt = rtt; ++ DBGLOG(SCN, TRACE, "[BATCH] SCANFREQ=%u MSCAN=%u BESTN=%u RTT=%u\n", ++ (UINT_32) rCmdBatchReq.u4Scanfreq, ++ (UINT_32) rCmdBatchReq.ucMScan, ++ (UINT_32) rCmdBatchReq.ucBestn, (UINT_32) rCmdBatchReq.ucRtt; ++ ++ if (rCmdBatchReq.ucChannelType != SCAN_CHANNEL_SPECIFIED) { ++ DBGLOG(SCN, TRACE, "[BATCH] CHANNELS = %s\n", ++ rCmdBatchReq.ucChannelType == SCAN_CHANNEL_FULL ? "FULL" : ++ rCmdBatchReq.ucChannelType == SCAN_CHANNEL_2G4 ? "2.4G all" : "5G all"); ++ } else { ++ DBGLOG(SCN, TRACE, "[BATCH] CHANNEL list\n"); ++ prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; ++ for (tokens = 0; tokens < rCmdBatchReq.ucChannelListNum; tokens++) { ++ DBGLOG(SCN, TRACE, "[BATCH] %s, %d\n", ++ prRfChannelInfo->ucBand == BAND_2G4 ? "2.4G" : "5G", ++ prRfChannelInfo->ucChannelNum); ++ prRfChannelInfo++; ++ } ++ } ++ ++ rCmdBatchReq.ucSeqNum = 1; ++ rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_START; ++ ++ *pu4WritenLen = kalSnprintf(pvSetBuffer, 3, "%d", rCmdBatchReq.ucMScan); ++ ++ } else if (!kalStrnCmp(head, BATCHING_STOP, kalStrLen(BATCHING_STOP))) { ++ ++ DBGLOG(SCN, TRACE, "XXX Stop Batch Scan XXX\n"); ++ ++ rCmdBatchReq.ucSeqNum = 1; ++ rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_STOP; ++ } else { ++ return -EINVAL; ++ } ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BATCH_REQ, ++ TRUE, FALSE, TRUE, NULL, NULL, sizeof(CMD_BATCH_REQ_T), (PUINT_8) &rCmdBatchReq, NULL, 0); ++ ++ /* kalMemSet(pvSetBuffer, 0, u4SetBufferLen); */ ++ /* rStatus = kalSnprintf(pvSetBuffer, 2, "%s", "OK"); */ ++ ++ return rStatus; ++} ++ ++WLAN_STATUS ++batchGetCmd(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_EVENT_BATCH_RESULT_T prEventBatchResult; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pvQueryBuffer; ++ ++ DBGLOG(SCN, TRACE, "XXX Get Batch Scan Result (%u) XXX\n", (UINT_32) prEventBatchResult->ucScanCount); ++ ++ *pu4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); ++ ++ rCmdBatchReq.ucSeqNum = 2; ++ rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_RESULT; ++ rCmdBatchReq.ucMScan = prEventBatchResult->ucScanCount; /* Get which round result */ ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BATCH_REQ, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventBatchScanResult, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_BATCH_REQ_T), ++ (PUINT_8) &rCmdBatchReq, (PVOID) pvQueryBuffer, u4QueryBufferLen); ++ ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ return batchSetCmd(prAdapter, pvSetBuffer, u4SetBufferLen, pu4SetInfoLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ return batchGetCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen, pu4QueryInfoLen); ++ ++} /* end of wlanoidQueryBatchScanResult() */ ++ ++#endif /* CFG_SUPPORT_BATCH_SCAN */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request starting of schedule scan ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; ++ ++ DEBUGFUNC("wlanoidSetStartSchedScan()"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set scheduled scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ ASSERT(pu4SetInfoLen); ++ *pu4SetInfoLen = 0; ++ ++ if (u4SetBufferLen != sizeof(PARAM_SCHED_SCAN_REQUEST)) { ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ return WLAN_STATUS_INVALID_DATA; ++ } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED && ++ prAdapter->fgEnOnlineScan == FALSE) { ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) pvSetBuffer; ++ ++ if (scnFsmSchedScanRequest(prAdapter, ++ (UINT_8) (prSchedScanRequest->u4SsidNum), ++ prSchedScanRequest->arSsid, ++ prSchedScanRequest->u4IELength, ++ prSchedScanRequest->pucIE, prSchedScanRequest->u2ScanInterval) == TRUE) { ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request termination of schedule scan ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ++ /* ask SCN module to stop scan request */ ++ if (scnFsmSchedScanStopRequest(prAdapter) == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ else ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a periodically scan action ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_CMD_SET_PSCAN_ENABLE prCmdPscnAction; ++ P_SCAN_INFO_T prScanInfo; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ DBGLOG(SCN, TRACE, "wlanoidSetGSCNAction\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4SetBufferLen != sizeof(CMD_SET_PSCAN_ENABLE)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ else if (pvSetBuffer == NULL) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prCmdPscnAction = (P_CMD_SET_PSCAN_ENABLE) pvSetBuffer; ++ ++ if (prCmdPscnAction->ucPscanAct == ENABLE) { ++#if 0 ++ DBGLOG(OID, INFO, "set PCSN ENABLE\n"); ++ if (scnFsmPSCNAction(prAdapter, (UINT_8) (prCmdPscnAction->ucPscanAct)) == TRUE) { ++ ++ DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); ++ return WLAN_STATUS_PENDING; ++ } ++ DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); ++ return WLAN_STATUS_FAILURE; ++ ++#endif ++ scnPSCNFsm(prAdapter, PSCN_SCANNING, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, TRUE); ++ } else if (prCmdPscnAction->ucPscanAct == DISABLE) { ++#if 0 ++ DBGLOG(OID, INFO, "disable PCSN\n"); ++ scnFsmPSCNAction(prAdapter, (UINT_8) DISABLE); ++ ++ DBGLOG(OID, TRACE, "set new PCSN\n"); ++ scnCombineParamsIntoPSCN(prAdapter, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE); ++ ++ DBGLOG(OID, INFO, "ENABLE or disable PCSN\n"); ++ if (!prScanInfo->fgPscnOnnning) { ++ DBGLOG(OID, INFO, "ENABLE PCSN\n"); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ } else { ++ DBGLOG(OID, INFO, "All PCSN is disabled...\n"); ++ } ++#endif ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE, FALSE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a periodically scan action ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam; ++ /*UINT_8 i, j = 0;*/ ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam v1\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(P_PARAM_WIFI_GSCAN_CMD_PARAMS))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prCmdGscnParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; ++ /* KC-XXX memcpy(prCmdGscnParam, */ ++ /* (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer, */ ++ /* sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS) ); */ ++ DBGLOG(SCN, INFO, ++ "prCmdGscnParam : base_period[%u], max_ap_per_scan[%u] num_buckets[%u], report_threshold[%u]\n", ++ prCmdGscnParam->base_period, prCmdGscnParam->max_ap_per_scan, prCmdGscnParam->num_buckets, ++ prCmdGscnParam->report_threshold); ++#if 0 ++ for (i = 0; i < prCmdGscnParam->num_buckets; i++) { ++ ++ DBGLOG(OID, INFO, ++ "prCmdGscnParam->buckets : band[%u], bucket[%u] num_buckets[%u], period[%u] report_events[%u]\n", ++ prCmdGscnParam->buckets[i].band, prCmdGscnParam->buckets[i].bucket, ++ prCmdGscnParam->buckets[i].num_channels, prCmdGscnParam->buckets[i].period, ++ prCmdGscnParam->buckets[i].report_events)); ++ DBGLOG(OID, INFO, "prCmdGscnParam->buckets[%d] has channel: ", i); ++ for (j = 0; j < prCmdGscnParam->buckets[i].num_channels; j++) ++ DBGLOG(OID, INFO, " %d, ", prCmdGscnParam->buckets[i].channels[j].channel); ++ DBGLOG(OID, INFO, "\n"); ++ } ++#endif ++ if (scnSetGSCNParam(prAdapter, prCmdGscnParam) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set configure gscan PARAMs ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnScnConfigParam; ++ CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; ++ ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAConfig v1\n"); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer\n"); ++ prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; ++ memcpy(prCmdGscnScnConfigParam, (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer, ++ sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam assign prCmdGscnScnConfig\n"); ++ rCmdGscnScnConfig.u4BufferThreshold = prCmdGscnScnConfigParam->report_threshold; ++ rCmdGscnScnConfig.ucNumApPerScn = prCmdGscnScnConfigParam->max_ap_per_scan; ++ rCmdGscnScnConfig.u4NumScnToCache = prCmdGscnScnConfigParam->num_scans; ++ DBGLOG(SCN, INFO, " report_threshold %d report_threshold %d num_scans %d\n", ++ rCmdGscnScnConfig.u4BufferThreshold, ++ rCmdGscnScnConfig.ucNumApPerScn, rCmdGscnScnConfig.u4NumScnToCache); ++ if (scnFsmSetGSCNConfig(prAdapter, &rCmdGscnScnConfig) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get a gscan result ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++* ++* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS prGetGscnScnResultParm; ++ CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; ++ ++ DEBUGFUNC("wlanoidGetGSCNResult()"); ++ DBGLOG(SCN, INFO, "wlanoidGetGSCNResult v1\n"); ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS)) { ++ DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (pvSetBuffer == NULL) { ++ DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ if (prAdapter->fgIsRadioOff) { ++ DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_SUCCESS; ++ } ++ ++ prGetGscnScnResultParm = (P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) pvSetBuffer; ++ /* memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultParm, sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) ); */ ++ ++ rGetGscnScnResultCmd.u4Num = prGetGscnScnResultParm->get_num; ++ rGetGscnScnResultCmd.ucFlush = prGetGscnScnResultParm->flush; ++ rGetGscnScnResultCmd.ucVersion = PSCAN_VERSION; ++ kalMemZero(rGetGscnScnResultCmd.aucReserved, sizeof(rGetGscnScnResultCmd.aucReserved)); ++ ++ if (scnFsmGetGSCNResult(prAdapter, &rGetGscnScnResultCmd) == TRUE) { ++ DBGLOG(SCN, INFO, "wlanoidGetGSCNResult --->scnFsmGetGSCNResult\n"); ++ return WLAN_STATUS_PENDING; ++ } else { ++ return WLAN_STATUS_FAILURE; ++ } ++ ++} ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by HS2.0 to set the assoc info, which is needed to add to ++* Association request frame while join HS2.0 AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_IE_HS20_INDICATION_T prHS20IndicationIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DEBUGFUNC("wlanoidSetHS20AssocInfo"); ++ DBGLOG(OID, LOUD, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pvSetBuffer; ++ ++ prAdapter->prGlueInfo->ucHotspotConfig = prHS20IndicationIe->ucHotspotConfig; ++ prAdapter->prGlueInfo->fgConnectHS20AP = TRUE; ++ ++ DBGLOG(SEC, TRACE, "HS20 IE sz %u\n", u4SetBufferLen); ++ ++ kalMemCopy(prAdapter->prGlueInfo->aucHS20AssocInfoIE, pvSetBuffer, u4SetBufferLen); ++ prAdapter->prGlueInfo->u2HS20AssocInfoIELen = (UINT_16) u4SetBufferLen; ++ DBGLOG(SEC, TRACE, "HS20 Assoc Info IE sz %u\n", u4SetBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the assoc info, which is needed to add to ++* Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if 0 ++ P_HS20_INFO_T prHS20Info = NULL; ++ P_IE_INTERWORKING_T prInterWorkingIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ DEBUGFUNC("wlanoidSetInterworkingInfo"); ++ DBGLOG(OID, TRACE, "\r\n"); ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ prInterWorkingIe = (P_IE_INTERWORKING_T) pvSetBuffer; ++ ++ prHS20Info->ucAccessNetworkOptions = prInterWorkingIe->ucAccNetOpt; ++ prHS20Info->ucVenueGroup = prInterWorkingIe->ucVenueGroup; ++ prHS20Info->ucVenueType = prInterWorkingIe->ucVenueType; ++ COPY_MAC_ADDR(prHS20Info->aucHESSID, prInterWorkingIe->aucHESSID); ++ ++ DBGLOG(SEC, TRACE, "IW IE sz %ld\n", u4SetBufferLen); ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called by WSC to set the Roaming Consortium IE info, which is needed to ++* add to Association request frame while join WPS AP. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++#if 0 ++ P_HS20_INFO_T prHS20Info = NULL; ++ P_PARAM_HS20_ROAMING_CONSORTIUM_INFO prRCInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ /* DEBUGFUNC("wlanoidSetRoamingConsortiumInfo"); */ ++ /* DBGLOG(HS2, TRACE, ("\r\n")); */ ++ ++ if (u4SetBufferLen == 0) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ prRCInfo = (P_PARAM_HS20_ROAMING_CONSORTIUM_INFO) pvSetBuffer; ++ ++ kalMemCopy(&(prHS20Info->rRCInfo), prRCInfo, sizeof(PARAM_HS20_ROAMING_CONSORTIUM_INFO)); ++ ++ /* DBGLOG(HS2, TRACE, ("RoamingConsortium IE sz %ld\n", u4SetBufferLen)); */ ++#endif ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set_bssid_pool ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_HS20_SET_BSSID_POOL)) { ++ *pu4SetInfoLen = sizeof(PARAM_HS20_SET_BSSID_POOL); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ rWlanStatus = hs20SetBssidPool(prAdapter, pvSetBuffer, NETWORK_TYPE_AIS_INDEX); ++ ++ return rWlanStatus; ++} /* end of wlanoidSendHS20GASRequest() */ ++ ++#endif ++ ++#if CFG_SUPPORT_ROAMING_ENC ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_ROAMING_INFO_T *prCmdRoamingInfo; ++ ++ DEBUGFUNC("wlanoidSetRoamingInfo"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_ROAMING_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_ROAMING_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdRoamingInfo = (CMD_ROAMING_INFO_T *) pvSetBuffer; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_ROAMING_INFO, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_ROAMING_INFO_T), (PUINT_8) prCmdRoamingInfo, NULL, 0); ++} ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set chip ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; ++ CMD_CHIP_CONFIG_T rCmdChipConfig; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(prChipConfigInfo->aucCmd) == CHIP_CONFIG_RESP_SIZE); ++ DEBUGFUNC("wlanoidSetChipConfig"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prChipConfigInfo = (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T) pvSetBuffer; ++ kalMemZero(&rCmdChipConfig, sizeof(rCmdChipConfig)); ++ ++ rCmdChipConfig.u2Id = prChipConfigInfo->u2Id; ++ rCmdChipConfig.ucType = prChipConfigInfo->ucType; ++ rCmdChipConfig.ucRespType = prChipConfigInfo->ucRespType; ++ rCmdChipConfig.u2MsgSize = prChipConfigInfo->u2MsgSize; ++ if (rCmdChipConfig.u2MsgSize > CHIP_CONFIG_RESP_SIZE) { ++ DBGLOG(OID, INFO, "Chip config Msg Size %u is not valid (set)\n", rCmdChipConfig.u2MsgSize); ++ rCmdChipConfig.u2MsgSize = CHIP_CONFIG_RESP_SIZE; ++ } ++ kalMemCopy(rCmdChipConfig.aucCmd, prChipConfigInfo->aucCmd, rCmdChipConfig.u2MsgSize); ++ ++ DBGLOG(OID, TRACE, "rCmdChipConfig.aucCmd=%s\n", rCmdChipConfig.aucCmd); ++#if 1 ++ rWlanStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_CHIP_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CHIP_CONFIG_T), ++ (PUINT_8) &rCmdChipConfig, pvSetBuffer, u4SetBufferLen); ++#endif ++ return rWlanStatus; ++} /* wlanoidSetChipConfig */ ++ ++WLAN_STATUS ++wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_CMD_WFD_DEBUG_MODE_INFO_T prCmdWfdDebugModeInfo; ++ ++ DEBUGFUNC("wlanoidSetWFDDebugMode"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_WFD_DEBUG_MODE_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_WFD_DEBUG_MODE_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdWfdDebugModeInfo = (CMD_WFD_DEBUG_MODE_INFO_T *) pvSetBuffer; ++ ++ DBGLOG(OID, INFO, "New WFD Debug: %d mode and period=0x%x\n", prCmdWfdDebugModeInfo->ucDebugMode, ++ prCmdWfdDebugModeInfo->u2PeriodInteval); ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode = (UINT_8) prCmdWfdDebugModeInfo->ucDebugMode; ++ prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.u2WfdSNShowPeiroid = ++ (UINT_16) prCmdWfdDebugModeInfo->u2PeriodInteval; ++ ++ return WLAN_STATUS_SUCCESS; ++} /*wlanoidSetWfdDebugMode */ ++ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to query the MAC address the NIC is currently using. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the ++* query buffer ++* \param[in] u4QueryBufLen The length of the query buffer ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_BUFFER_TOO_SHORT ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetTxRateInfo( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_RLM_INFO_T *prCmdTxRInfo; ++ ++ DEBUGFUNC("wlanoidSetTxRateInfo"); ++ DBGLOG(OID, LOUD, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(CMD_RLM_INFO_T); ++ ++ if (u4SetBufferLen < sizeof(CMD_RLM_INFO_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prCmdTxRInfo = (CMD_RLM_INFO_T *)pvSetBuffer; ++ ++ DBGLOG(OID, INFO, " command = %u %u %u %u %d %u %u\n", ++ prCmdTxRInfo->u4Version, ++ prCmdTxRInfo->fgIsErrRatioEnhanceApplied, ++ prCmdTxRInfo->ucErrRatio2LimitMinRate, ++ prCmdTxRInfo->ucMinLegacyRateIdx, ++ prCmdTxRInfo->cMinRssiThreshold, ++ prCmdTxRInfo->fgIsRtsApplied, ++ prCmdTxRInfo->ucRecoverTime)); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_TX_AR_ERR_CONFIG, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_RLM_INFO_T), ++ (PUINT_8)prCmdTxRInfo, ++ NULL, ++ 0 ++ ); ++} ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++WLAN_STATUS ++wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WIFI_SYSTEM_SUSPEND_CMD_T rSuspendCmd; ++ ++ if (!prAdapter || !pvSetBuffer) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ rSuspendCmd.fgIsSystemSuspend = *(PBOOLEAN)pvSetBuffer; ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_SYSTEM_SUSPEND, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(BOOLEAN), ++ (PUINT_8)&rSuspendCmd, ++ NULL, ++ 0); ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c +new file mode 100644 +index 000000000000..7ca7ee48922e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c +@@ -0,0 +1,1654 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/common/wlan_p2p.c#8 ++*/ ++ ++/*! \file wlan_bow.c ++ \brief This file contains the Wi-Fi Direct commands processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_p2p.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 24 2011 yuche.tsai ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support ++ * for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix Multicast Issue of P2P. ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 wh.su ++ * [WCXRP00000571] [MT6620 Wi-Fi] [Driver] Not check the p2p role during set key ++ * Skip the p2p role for adding broadcast key issue. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * fixed compiling error while enable dbg. ++ * ++ * 03 08 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format ++ * issue[WCXRP00000509] [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix SD Request Query Length issue. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Service Discovery Request. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Wlan OID related function. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ioctl implementations for P2P Service Discovery ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ++ * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous ++ * and physically-continuous type to ease slab system pressure ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * . ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * support wlanoidSetP2pPowerSaveProfile() in P2P ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * Support wlanoidSetNetworkAddress() for P2P ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++** ++*/ ++ ++/****************************************************************************** ++* C O M P I L E R F L A G S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************* ++*/ ++#include "precomp.h" ++#include "gl_p2p_ioctl.h" ++ ++/****************************************************************************** ++* C O N S T A N T S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* D A T A T Y P E S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* P R I V A T E D A T A ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* M A C R O S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************* ++*/ ++ ++/****************************************************************************** ++* F U N C T I O N S ++******************************************************************************* ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief command packet generation utility ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucCID Command ID ++* \param[in] fgSetQuery Set or Query ++* \param[in] fgNeedResp Need for response ++* \param[in] pfCmdDoneHandler Function pointer when command is done ++* \param[in] u4SetQueryInfoLen The length of the set/query buffer ++* \param[in] pucInfoBuffer Pointer to set/query buffer ++* ++* ++* \retval WLAN_STATUS_PENDING ++* \retval WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ DEBUGFUNC("wlanoidSendSetQueryP2PCmd"); ++ DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); ++ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); ++ ++ if (!prCmdInfo) { ++ DBGLOG(P2P, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = NETWORK_TYPE_P2P_INDEX; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); ++ prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; ++ prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; ++ prCmdInfo->fgIsOid = fgIsOid; ++ prCmdInfo->ucCID = ucCID; ++ prCmdInfo->fgSetQuery = fgSetQuery; ++ prCmdInfo->fgNeedResp = fgNeedResp; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; ++ prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; ++ prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) ++ kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set a key to Wi-Fi Direct driver ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_802_11_KEY rCmdKey; ++ P_PARAM_KEY_T prNewKey; ++ ++ DEBUGFUNC("wlanoidSetAddP2PKey"); ++ DBGLOG(REQ, INFO, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ prNewKey = (P_PARAM_KEY_T) pvSetBuffer; ++ ++ /* Verify the key structure length. */ ++ if (prNewKey->u4Length > u4SetBufferLen) { ++ DBGLOG(REQ, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", ++ (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ /* Verify the key material length for key material buffer */ ++ else if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { ++ DBGLOG(REQ, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); ++ *pu4SetInfoLen = u4SetBufferLen; ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ /* Exception check */ ++ else if (prNewKey->u4KeyIndex & 0x0fffff00) ++ return WLAN_STATUS_INVALID_DATA; ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) { ++ return WLAN_STATUS_INVALID_DATA; ++ } else if (!(prNewKey->u4KeyLength == CCMP_KEY_LEN) && !(prNewKey->u4KeyLength == TKIP_KEY_LEN)) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ /* Exception check, pairwise key must with transmit bit enabled */ ++ else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { ++ if (((prNewKey->u4KeyIndex & 0xff) != 0) || ++ ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) ++ && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) ++ && (prNewKey->arBSSID[5] == 0xff))) { ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* fill CMD_802_11_KEY */ ++ kalMemZero(&rCmdKey, sizeof(CMD_802_11_KEY)); ++ rCmdKey.ucAddRemove = 1; /* add */ ++ rCmdKey.ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; ++ rCmdKey.ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ ++ rCmdKey.ucIsAuthenticator = 0; ++ } else { /* group owner */ ++ rCmdKey.ucIsAuthenticator = 1; ++ } ++ COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prNewKey->arBSSID); ++ rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; ++ if (prNewKey->u4KeyLength == CCMP_KEY_LEN) ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ ++ else if (prNewKey->u4KeyLength == TKIP_KEY_LEN) ++ rCmdKey.ucAlgorithmId = CIPHER_SUITE_TKIP; /* TKIP */ ++ rCmdKey.ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); ++ rCmdKey.ucKeyLen = (UINT_8) prNewKey->u4KeyLength; ++ kalMemCopy(rCmdKey.aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, rCmdKey.ucKeyLen); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ NULL, ++ sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to request Wi-Fi Direct driver to remove keys ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_802_11_KEY rCmdKey; ++ P_PARAM_REMOVE_KEY_T prRemovedKey; ++ ++ DEBUGFUNC("wlanoidSetRemoveP2PKey"); ++ ASSERT(prAdapter); ++ ++ if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; ++ ++ /* Check bit 31: this bit should always 0 */ ++ if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { ++ /* Bit 31 should not be set */ ++ DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* Check bits 8 ~ 29 should always be 0 */ ++ if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { ++ /* Bit 31 should not be set */ ++ DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ /* There should not be any key operation for P2P Device */ ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 0) ++ ; /* return WLAN_STATUS_NOT_ACCEPTED; */ ++ ++ kalMemZero((PUINT_8) &rCmdKey, sizeof(CMD_802_11_KEY)); ++ ++ rCmdKey.ucAddRemove = 0; /* remove */ ++ if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ ++ rCmdKey.ucIsAuthenticator = 0; ++ } else { /* group owner */ ++ rCmdKey.ucIsAuthenticator = 1; ++ } ++ kalMemCopy(rCmdKey.aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); ++ rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; ++ rCmdKey.ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_ADD_REMOVE_KEY, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ NULL, ++ sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setting the IP address for pattern search function. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++* \return WLAN_STATUS_ADAPTER_NOT_READY ++* \return WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ ++ DEBUGFUNC("wlanoidSetP2pNetworkAddress"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++ j++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to query the power save profile. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuf A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryP2pPowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen != 0) { ++ ASSERT(pvQueryBuffer); ++ ++ *(PPARAM_POWER_MODE) pvQueryBuffer = ++ (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile); ++ *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ PARAM_POWER_MODE ePowerMode; ++ ++ DEBUGFUNC("wlanoidSetP2pPowerSaveProfile"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); ++ if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { ++ DBGLOG(REQ, WARN, "Invalid length %u\n", u4SetBufferLen); ++ return WLAN_STATUS_INVALID_LENGTH; ++ } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { ++ WARNLOG(("Invalid power mode %d\n", *(PPARAM_POWER_MODE) pvSetBuffer)); ++ return WLAN_STATUS_INVALID_DATA; ++ } ++ ++ ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; ++ ++ if (prAdapter->fgEnCtiaPowerMode) { ++ if (ePowerMode == Param_PowerModeCAM) { ++ /*Todo:: Nothing*/ ++ /*Todo:: Nothing*/ ++ } else { ++ /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ ++ ++ if (prAdapter->u4CtiaPowerMode == 0) { ++ /* force to keep in CAM mode */ ++ ePowerMode = Param_PowerModeCAM; ++ } else if (prAdapter->u4CtiaPowerMode == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (prAdapter->u4CtiaPowerMode == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } ++ } ++ } ++ ++ status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_P2P_INDEX, ePowerMode, TRUE); ++ return status; ++} /* end of wlanoidSetP2pPowerSaveProfile() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the power save profile. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 i, j; ++ P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; ++ P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; ++ P_PARAM_NETWORK_ADDRESS prNetworkAddress; ++ P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; ++ UINT_32 u4IpAddressCount, u4CmdSize; ++ PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; ++ ++ DEBUGFUNC("wlanoidSetP2pSetNetworkAddress"); ++ DBGLOG(P2P, TRACE, "\n"); ++ DBGLOG(P2P, INFO, "wlanoidSetP2pSetNetworkAddress (%d)\n", (INT_16) u4SetBufferLen); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = 4; ++ ++ if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ *pu4SetInfoLen = 0; ++ u4IpAddressCount = 0; ++ ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ u4IpAddressCount++; ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); ++ } ++ ++ /* construct payload of command packet */ ++ u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + ++ sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; ++ ++ if (u4IpAddressCount == 0) ++ u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); ++ ++ prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); ++ ++ if (prCmdNetworkAddressList == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ ++ prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ ++ /* only to set IP address to FW once ARP filter is enabled */ ++ if (prAdapter->fgEnArpFilter) { ++ prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; ++ prNetworkAddress = prNetworkAddressList->arAddress; ++ ++ DBGLOG(P2P, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); ++ for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { ++ if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && ++ prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { ++ prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; ++ ++ kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, ++ &(prNetAddrIp->in_addr), sizeof(UINT_32)); ++ ++ j++; ++ ++ pucBuf = (PUINT_8) &prNetAddrIp->in_addr; ++ DBGLOG(P2P, INFO, "prNetAddrIp->in_addr:%d:%d:%d:%d\n", ++ (UINT_8) pucBuf[0], (UINT_8) pucBuf[1], ++ (UINT_8) pucBuf[2], (UINT_8) pucBuf[3]); ++ } ++ ++ prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + ++ (ULONG) (prNetworkAddress->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ } ++ ++ } else { ++ prCmdNetworkAddressList->ucAddressCount = 0; ++ } ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_IP_ADDRESS, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetIpAddress, ++ nicOidCmdTimeoutCommon, ++ u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); ++ ++ kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); ++ return rStatus; ++} /* end of wlanoidSetP2pSetNetworkAddress() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Multicast Address List. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ /* The data must be a multiple of the Ethernet address size. */ ++ if ((u4SetBufferLen % MAC_ADDR_LEN)) { ++ DBGLOG(REQ, WARN, "Invalid MC list length %u\n", u4SetBufferLen); ++ ++ *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; ++ ++ return WLAN_STATUS_INVALID_LENGTH; ++ } ++ ++ *pu4SetInfoLen = u4SetBufferLen; ++ ++ /* Verify if we can support so many multicast addresses. */ ++ if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { ++ DBGLOG(REQ, WARN, "Too many MC addresses\n"); ++ ++ return WLAN_STATUS_MULTICAST_FULL; ++ } ++ ++ /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && ++ * pvSetBuffer == NULL to clear exist Multicast List. ++ */ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(REQ, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; ++ rCmdMacMcastAddr.ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); ++ ++ /* This CMD response is no need to complete the OID. Or the event would unsync. */ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, CMD_ID_MAC_MCAST_ADDR, TRUE, FALSE, FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_MAC_MCAST_ADDR), ++ (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetP2PMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send GAS frame for P2P Service Discovery Request ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_REQUEST)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_REQUEST); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++/* rWlanStatus = p2pFsmRunEventSDRequest(prAdapter, (P_PARAM_P2P_SEND_SD_REQUEST)pvSetBuffer); */ ++ ++ return rWlanStatus; ++} /* end of wlanoidSendP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send GAS frame for P2P Service Discovery Response ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_RESPONSE)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_RESPONSE); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++/* rWlanStatus = p2pFsmRunEventSDResponse(prAdapter, (P_PARAM_P2P_SEND_SD_RESPONSE)pvSetBuffer); */ ++ ++ return rWlanStatus; ++} /* end of wlanoidGetP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get GAS frame for P2P Service Discovery Request ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /*PUINT_8 pucPacketBuffer = NULL, pucTA = NULL;*/ ++/* PUINT_8 pucChannelNum = NULL; */ ++ /*PUINT_16 pu2PacketLength = NULL;*/ ++ /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ ++ /*UINT_8 ucVersionNum = 0;*/ ++/* UINT_8 ucChannelNum = 0, ucSeqNum = 0; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_REQUEST)) { ++ *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_REQUEST); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ DBGLOG(P2P, TRACE, "Get Service Discovery Request\n"); ++#if 0 ++ ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); ++ if (ucVersionNum == 0) { ++ P_PARAM_P2P_GET_SD_REQUEST prP2pGetSdReq = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ ++ pucPacketBuffer = prP2pGetSdReq->aucPacketContent; ++ pu2PacketLength = &prP2pGetSdReq->u2PacketLength; ++ pucTA = &prP2pGetSdReq->rTransmitterAddr; ++ } else { ++ P_PARAM_P2P_GET_SD_REQUEST_EX prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST_EX) NULL; ++ ++ prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ pucPacketBuffer = prP2pGetSdReqEx->aucPacketContent; ++ pu2PacketLength = &prP2pGetSdReqEx->u2PacketLength; ++ pucTA = &prP2pGetSdReqEx->rTransmitterAddr; ++ pucChannelNum = &prP2pGetSdReqEx->ucChannelNum; ++ ucSeqNum = prP2pGetSdReqEx->ucSeqNum; ++ } ++ ++ rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, ++ pucPacketBuffer, ++ (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_REQUEST)), ++ (PUINT_32) pu2PacketLength, pucChannelNum, ucSeqNum); ++#else ++ *pu4QueryInfoLen = 0; ++ return rWlanStatus; ++#endif ++ /* ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketBuffer; ++ ++ kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); ++ ++ if (pu4QueryInfoLen) { ++ if (ucVersionNum == 0) ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST) + (*pu2PacketLength)); ++ else ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST_EX) + (*pu2PacketLength)); ++ ++ } ++ ++ return rWlanStatus; ++ */ ++} /* end of wlanoidGetP2PSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get GAS frame for P2P Service Discovery Response ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ ++ /* UINT_8 ucSeqNum = 0, */ ++ /*UINT_8 ucVersionNum = 0;*/ ++ /*PUINT_8 pucPacketContent = (PUINT_8) NULL, pucTA = (PUINT_8) NULL;*/ ++ /*PUINT_16 pu2PacketLength = (PUINT_16) NULL;*/ ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_RESPONSE)) { ++ *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_RESPONSE); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ DBGLOG(P2P, TRACE, "Get Service Discovery Response\n"); ++ ++#if 0 ++ ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); ++ if (ucVersionNum == 0) { ++ P_PARAM_P2P_GET_SD_RESPONSE prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_RESPONSE) NULL; ++ ++ prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; ++ pucPacketContent = prP2pGetSdRsp->aucPacketContent; ++ pucTA = &prP2pGetSdRsp->rTransmitterAddr; ++ pu2PacketLength = &prP2pGetSdRsp->u2PacketLength; ++ } else { ++ P_PARAM_P2P_GET_SD_RESPONSE_EX prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) NULL; ++ ++ prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) pvQueryBuffer; ++ pucPacketContent = prP2pGetSdRspEx->aucPacketContent; ++ pucTA = &prP2pGetSdRspEx->rTransmitterAddr; ++ pu2PacketLength = &prP2pGetSdRspEx->u2PacketLength; ++ ucSeqNum = prP2pGetSdRspEx->ucSeqNum; ++ } ++ ++/* rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, */ ++/* pucPacketContent, */ ++/* (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_RESPONSE)), */ ++/* (PUINT_32)pu2PacketLength, */ ++/* NULL, */ ++/* ucSeqNum); */ ++#else ++ *pu4QueryInfoLen = 0; ++ return rWlanStatus; ++#endif ++ /* ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketContent; ++ ++ kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); ++ ++ if (pu4QueryInfoLen) { ++ if (ucVersionNum == 0) ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE) + *pu2PacketLength); ++ else ++ *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE_EX) + *pu2PacketLength); ++ } ++ ++ return rWlanStatus; ++ */ ++} /* end of wlanoidGetP2PSDResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to terminate P2P Service Discovery Phase ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_P2P_TERMINATE_SD_PHASE prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) NULL; ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ ++ do { ++ if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) ++ break; ++ ++ if ((u4SetBufferLen) && (pvSetBuffer == NULL)) ++ break; ++ ++ if (u4SetBufferLen < sizeof(PARAM_P2P_TERMINATE_SD_PHASE)) { ++ *pu4SetInfoLen = sizeof(PARAM_P2P_TERMINATE_SD_PHASE); ++ rWlanStatus = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) pvSetBuffer; ++ ++ if (EQUAL_MAC_ADDR(prP2pTerminateSD->rPeerAddr, aucNullAddr)) { ++ DBGLOG(P2P, TRACE, "Service Discovery Version 2.0\n"); ++/* p2pFuncSetVersionNumOfSD(prAdapter, 2); */ ++ } ++ /* rWlanStatus = p2pFsmRunEventSDAbort(prAdapter); */ ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* end of wlanoidSetP2PTerminateSDPhase() */ ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (u4SetBufferLen) ++ ASSERT(pvSetBuffer); ++ ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SEC_CHECK, ++ FALSE, ++ TRUE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ u4SetBufferLen, (PUINT_8) pvSetBuffer, pvSetBuffer, u4SetBufferLen); ++ ++} /* end of wlanoidSetSecCheckRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of ++* the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++* \retval WLAN_STATUS_MULTICAST_FULL ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ /* P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; */ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ if (u4QueryBufferLen > 256) ++ u4QueryBufferLen = 256; ++ ++ *pu4QueryInfoLen = u4QueryBufferLen; ++ ++#if DBG ++ DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); ++#endif ++ kalMemCopy((PUINT_8) (pvQueryBuffer + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer)), ++ prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); ++ ++ return rWlanStatus; ++} /* end of wlanoidGetSecCheckResponse() */ ++#endif ++ ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; ++ CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; ++ ++ DEBUGFUNC("wlanoidSetNoaParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); ++ rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; ++ rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; ++ rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++ ++} ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; ++ CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; ++ ++ DEBUGFUNC("wlanoidSetOppPsParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_OPPPS_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_NOA_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++ ++} ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; ++ CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("wlanoidSetUApsdParam"); ++ DBGLOG(P2P, TRACE, "\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); ++ ++ if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvSetBuffer); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; ++ ++ kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); ++ rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; ++ prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; ++ ++ rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; ++ rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; ++ rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; ++ rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; ++ prPmProfSetupInfo->ucBmpDeliveryAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ prPmProfSetupInfo->ucBmpTriggerAC = ++ ((prUapsdParam->fgEnAPSD_AcBe << 0) | ++ (prUapsdParam->fgEnAPSD_AcBk << 1) | ++ (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); ++ ++ rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; ++ prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; ++ ++#if 0 ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++#else ++ return wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_UAPSD_PARAM, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), ++ (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); ++ ++#endif ++} ++ ++WLAN_STATUS ++wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++/* PUINT_8 pucOpChnl = (PUINT_8)pvQueryBuffer; */ ++ ++ do { ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8)) { ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++#if 0 ++ if (!p2pFuncGetCurrentOpChnl(prAdapter, pucOpChnl)) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++#else ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++#endif ++ /* ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_SUCCESS; ++ */ ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pOpChannel */ ++ ++WLAN_STATUS ++wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++/* PUINT_8 pucVersionNum = (PUINT_8)pvQueryBuffer; */ ++ ++ do { ++ if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) ++ break; ++ ++ if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) ++ break; ++ ++ if (u4QueryBufferLen < sizeof(UINT_8)) { ++ *pu4QueryInfoLen = sizeof(UINT_8); ++ rResult = WLAN_STATUS_BUFFER_TOO_SHORT; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidQueryP2pVersion */ ++ ++WLAN_STATUS ++wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rResult = WLAN_STATUS_FAILURE; ++ UINT_8 ucVersionNum; ++ ++ do { ++ if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { ++ ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { ++ rResult = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ *pu4SetInfoLen = sizeof(UINT_8); ++ ++ if (u4SetBufferLen < sizeof(UINT_8)) { ++ rResult = WLAN_STATUS_INVALID_LENGTH; ++ break; ++ } ++ ++ ucVersionNum = *((PUINT_8) pvSetBuffer); ++ ++ rResult = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rResult; ++} /* wlanoidSetP2pSupplicantVersion */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set the WPS mode. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS status; ++ UINT_32 u4IsWPSmode = 0; ++ ++ DEBUGFUNC("wlanoidSetP2pWPSmode"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4SetInfoLen); ++ ++ if (pvSetBuffer) ++ u4IsWPSmode = *(PUINT_32) pvSetBuffer; ++ else ++ u4IsWPSmode = 0; ++ ++ if (u4IsWPSmode) ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 1; ++ else ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 0; ++ ++ status = nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ return status; ++} /* end of wlanoidSetP2pWPSmode() */ ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++WLAN_STATUS ++wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ DEBUGFUNC("wlanoidQueryP2pRssi"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4QueryInfoLen); ++ if (u4QueryBufferLen) ++ ASSERT(pvQueryBuffer); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ /* Check for query buffer length */ ++ if (u4QueryBufferLen < *pu4QueryInfoLen) { ++ DBGLOG(REQ, WARN, "Too short length %u\n", u4QueryBufferLen); ++ return WLAN_STATUS_BUFFER_TOO_SHORT; ++ } ++ ++ if (prAdapter->fgIsP2pLinkQualityValid == TRUE && ++ (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { ++ PARAM_RSSI rRssi; ++ ++ rRssi = (PARAM_RSSI) prAdapter->rP2pLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ ++ kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); ++ return WLAN_STATUS_SUCCESS; ++ } ++#ifdef LINUX ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, ++ *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); ++#else ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_LINK_QUALITY, ++ FALSE, ++ TRUE, ++ TRUE, ++ nicCmdEventQueryLinkQuality, ++ nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); ++ ++#endif ++} /* wlanoidQueryP2pRssi */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h +new file mode 100644 +index 000000000000..89de18c89c1c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h +@@ -0,0 +1,238 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/CFG_Wifi_File.h#1 ++*/ ++ ++/*! \file CFG_Wifi_File.h ++ \brief Collection of NVRAM structure used for YuSu project ++ ++ In this file we collect all compiler flags and detail the driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++/* ++** Log: CFG_Wifi_File.h ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 09 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * update NVRAM data structure definition. ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition ++ * follow-up for CMD_5G_PWR_OFFSET_T definition change ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++*/ ++ ++#ifndef _CFG_WIFI_FILE_H ++#define _CFG_WIFI_FILE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/* duplicated from nic_cmd_event.h to avoid header dependency */ ++typedef struct _TX_PWR_PARAM_T { ++ INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ ++ INT_8 acReserved[3]; /* form MT6628 acReserved[0]=cTxPwr2G4Dsss */ ++ INT_8 cTxPwr2G4OFDM_BPSK; ++ INT_8 cTxPwr2G4OFDM_QPSK; ++ INT_8 cTxPwr2G4OFDM_16QAM; ++ INT_8 cTxPwr2G4OFDM_Reserved; ++ INT_8 cTxPwr2G4OFDM_48Mbps; ++ INT_8 cTxPwr2G4OFDM_54Mbps; ++ ++ INT_8 cTxPwr2G4HT20_BPSK; ++ INT_8 cTxPwr2G4HT20_QPSK; ++ INT_8 cTxPwr2G4HT20_16QAM; ++ INT_8 cTxPwr2G4HT20_MCS5; ++ INT_8 cTxPwr2G4HT20_MCS6; ++ INT_8 cTxPwr2G4HT20_MCS7; ++ ++ INT_8 cTxPwr2G4HT40_BPSK; ++ INT_8 cTxPwr2G4HT40_QPSK; ++ INT_8 cTxPwr2G4HT40_16QAM; ++ INT_8 cTxPwr2G4HT40_MCS5; ++ INT_8 cTxPwr2G4HT40_MCS6; ++ INT_8 cTxPwr2G4HT40_MCS7; ++ ++ INT_8 cTxPwr5GOFDM_BPSK; ++ INT_8 cTxPwr5GOFDM_QPSK; ++ INT_8 cTxPwr5GOFDM_16QAM; ++ INT_8 cTxPwr5GOFDM_Reserved; ++ INT_8 cTxPwr5GOFDM_48Mbps; ++ INT_8 cTxPwr5GOFDM_54Mbps; ++ ++ INT_8 cTxPwr5GHT20_BPSK; ++ INT_8 cTxPwr5GHT20_QPSK; ++ INT_8 cTxPwr5GHT20_16QAM; ++ INT_8 cTxPwr5GHT20_MCS5; ++ INT_8 cTxPwr5GHT20_MCS6; ++ INT_8 cTxPwr5GHT20_MCS7; ++ ++ INT_8 cTxPwr5GHT40_BPSK; ++ INT_8 cTxPwr5GHT40_QPSK; ++ INT_8 cTxPwr5GHT40_16QAM; ++ INT_8 cTxPwr5GHT40_MCS5; ++ INT_8 cTxPwr5GHT40_MCS6; ++ INT_8 cTxPwr5GHT40_MCS7; ++} TX_PWR_PARAM_T, *P_TX_PWR_PARAM_T; ++ ++typedef struct _PWR_5G_OFFSET_T { ++ INT_8 cOffsetBand0; /* 4.915-4.980G */ ++ INT_8 cOffsetBand1; /* 5.000-5.080G */ ++ INT_8 cOffsetBand2; /* 5.160-5.180G */ ++ INT_8 cOffsetBand3; /* 5.200-5.280G */ ++ INT_8 cOffsetBand4; /* 5.300-5.340G */ ++ INT_8 cOffsetBand5; /* 5.500-5.580G */ ++ INT_8 cOffsetBand6; /* 5.600-5.680G */ ++ INT_8 cOffsetBand7; /* 5.700-5.825G */ ++} PWR_5G_OFFSET_T, *P_PWR_5G_OFFSET_T; ++ ++typedef struct _PWR_PARAM_T { ++ UINT_32 au4Data[28]; ++ UINT_32 u4RefValue1; ++ UINT_32 u4RefValue2; ++} PWR_PARAM_T, *P_PWR_PARAM_T; ++ ++typedef struct _MT6620_CFG_PARAM_STRUCT { ++ /* 256 bytes of MP data */ ++ UINT_16 u2Part1OwnVersion; ++ UINT_16 u2Part1PeerVersion; ++ UINT_8 aucMacAddress[6]; ++ UINT_8 aucCountryCode[2]; ++ TX_PWR_PARAM_T rTxPwr; ++ UINT_8 aucEFUSE[144]; ++ UINT_8 ucTxPwrValid; ++ UINT_8 ucSupport5GBand; ++ UINT_8 fg2G4BandEdgePwrUsed; ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ ++ UINT_8 ucRegChannelListMap; ++ UINT_8 ucRegChannelListIndex; ++ UINT_8 aucRegSubbandInfo[36]; ++ ++ UINT_8 aucReserved2[256 - 240]; ++ ++ /* 256 bytes of function data */ ++ UINT_16 u2Part2OwnVersion; ++ UINT_16 u2Part2PeerVersion; ++ UINT_8 uc2G4BwFixed20M; ++ UINT_8 uc5GBwFixed20M; ++ UINT_8 ucEnable5GBand; ++ UINT_8 aucPreTailReserved; ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 fgRssiCompensationValidbit; ++ UINT_8 ucRxAntennanumber; ++ UINT_8 aucTailReserved[256 - 12]; ++} MT6620_CFG_PARAM_STRUCT, *P_MT6620_CFG_PARAM_STRUCT, WIFI_CFG_PARAM_STRUCT, *P_WIFI_CFG_PARAM_STRUCT; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#ifndef DATA_STRUCT_INSPECTING_ASSERT ++#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ ++{ \ ++ switch (0) {case 0: case (expr): default:; } \ ++} ++#endif ++ ++#define CFG_FILE_WIFI_REC_SIZE sizeof(WIFI_CFG_PARAM_STRUCT) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* We don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this to guarantee the same member order in different structures ++ * to simply handling effort in some functions. ++ */ ++static inline VOID nvramOffsetCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion) == 256); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(WIFI_CFG_PARAM_STRUCT) == 512); ++ ++ DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) & 0x0001) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) & 0x0001) == 0); ++} ++#endif ++ ++#endif /* _CFG_WIFI_FILE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h +new file mode 100644 +index 000000000000..a52053d5752d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h +@@ -0,0 +1,1628 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/config.h#2 ++*/ ++ ++/*! \file "config.h" ++ \brief This file includes the various configurable parameters for customers ++ ++ This file ncludes the configurable parameters except the parameters indicate the turning-on/off of some features ++*/ ++ ++/* ++** Log: config.h ++ * ++ * 07 13 2012 cp.wu ++ * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for ++ * termination after SDIO error has happened ++ * [driver domain] add force reset by host-to-device interrupt mechanism ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 06 05 2012 tsaiyuan.hsu ++ * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" ++ * resolve build waring for "WNM_UNIT_TEST not defined".. ++ * ++ * 06 04 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * discussed with WH, privacy bit in associate response is not necessary to be checked, ++ * and identified as association failure when mismatching with beacon/probe response ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 23 2011 cp.wu ++ * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection ++ * add compile option to disable beacon content change detection. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 10 28 2011 cp.wu ++ * [MT6620 Wi-Fi][Win32 Driver] Enable 5GHz support as default ++ * enable 5GHz as default for DaVinci trunk and V2.1 driver release . ++ * ++ * 10 18 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * surpress compiler warning for MT6628 build ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * enable divided firmware downloading. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 28 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * enlarge window size only by 4. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 12 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. ++ * ++ * 08 09 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS definition for MT6620. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Refine compile flag. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 06 24 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * increase RX buffer number to have a 2:1 ping-pong ratio ++ * ++ * 06 23 2011 eddie.chen ++ * [WCXRP00000810] [MT5931][DRV/FW] Adjust TxRx Buffer number and Rx buffer size ++ * 1. Different TX RX buffer ++ * 2. Enlarge RX buffer and increase the number 8->11 ++ * 3. Separate the WINSZIE and RX buffer number ++ * 4. Fix RX maximum size in MAC ++ * ++ * 06 20 2011 terry.wu ++ * NULL ++ * Add BoW Rate Limitation. ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * . ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add compile flag for persistent group support. ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Limit AIS to fixed channel same with BOW ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * Enable RX STBC capability ++ * ++ * 04 11 2011 george.huang ++ * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF ++ * . ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. correction: RX aggregation is not limited to SDIO but for all host interface options ++ * 2. add forward declarations for DBG-only symbols ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port ++ * 2. update perm_addr as well for MAC address ++ * 3. not calling check_mem_region() anymore for eHPI ++ * 4. correct MSC_CS macro for 0-based notation ++ * ++ * 04 01 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface ++ * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR ++ * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with ++ * user space process for RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 18 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the Anti_piracy check at driver . ++ * ++ * 03 17 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * enable roaming feature. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one ++ * to reduce physically continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 03 01 2011 george.huang ++ * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames ++ * Fix compile issue ++ * ++ * 02 25 2011 george.huang ++ * [WCXRP00000497] [MT6620 Wi-Fi][FW] Change default UAPSD AC assignment ++ * Assign all AC default to be U-APSD enabled. ++ * ++ * 02 14 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * Let the privacy check at hotspot mode default enable. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 02 08 2011 cp.wu ++ * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number ++ * change version number to v1.2.0.0 for preparing v1.2 software package release. ++ * ++ * 02 01 2011 yarco.yang ++ * [WCXRP00000417] [MT6620 Driver] Change CFG_HANDLE_IST_IN_SDIO_CALLBACK from 1 to 0 for Interoperability ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 19 2011 wh.su ++ * [WCXRP00000370] [MT6620 Wi-Fi][Driver] Disable Rx RDG for workaround pre-N ccmp issue ++ * Not announce support Rx RDG for wokaround pre-N ccmp construct AAD issue.. ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause ++ * hardware header translation needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW only for Linux. ++ * ++ * 01 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Enable BOW and 4 physical links. ++ * ++ * 01 08 2011 yuche.tsai ++ * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, ++ * but the SSID length is still invalid. ++ * Modify CFG_SLT_SUPPORT default value. ++ * ++ * 01 08 2011 yuche.tsai ++ * [WCXRP00000341] [MT6620][SLT] Create Branch for SLT SW. ++ * Update configure flag. ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 15 2010 yuche.tsai ++ * NULL ++ * Update SLT Descriptor number configure in driver. ++ * ++ * 12 13 2010 chinglan.wang ++ * NULL ++ * Add WPS 1.0 feature flag to enable the WPS 1.0 function. ++ * ++ * 11 23 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Enable PM function by default ++ * ++ * 11 15 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * use config.mk WAPI config define. ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * use the config.mk define. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add option for enable/disable TX PWR gain adjustment (default: off) ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * enable the WAPI compiling flag as default ++ * ++ * 10 19 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * Add a define CFG_TEST_ANDROID_DIRECT_GO compiling flag ++ * ++ * 10 08 2010 cm.chang ++ * NULL ++ * Remove unused compiling flags (TX_RDG and TX_SGI) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 05 2010 yarco.yang ++ * [WCXRP00000082] [MT6620 Wi-Fi][Driver]High throughput performance tuning ++ * Change CFG_IST_LOOP_COUNT from 2 to 1 to reduce unnecessary SDIO bus access ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 20 2010 cm.chang ++ * NULL ++ * Disable RX STBC by BB HEC based on MT6620E1_PHY_BUG v05.docx ++ * ++ * 09 17 2010 chinglan.wang ++ * NULL ++ * Add performance test option ++ * ++ * 09 10 2010 chinglan.wang ++ * NULL ++ * Modify for Software Migration Phase 2.10 for E2 FPGA ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a CFG for max common IE buffer size. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * restore configuration as before. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Enable the MT6620_FPGA_BWCS value. ++ * ++ * 08 30 2010 chinglan.wang ++ * NULL ++ * Disable the FW encryption. ++ * ++ * 08 27 2010 chinglan.wang ++ * NULL ++ * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add option for enabling AIS 5GHz scan ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cp.wu ++ * NULL ++ * 1) initialize variable for enabling short premable/short time slot. ++ * 2) add compile option for disabling online scan ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Disable BOW Test. ++ * ++ * 08 23 2010 jeffrey.chang ++ * NULL ++ * fix config.h typo ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 21 2010 jeffrey.chang ++ * NULL ++ * 1) add sdio two setting ++ * 2) bug fix of sdio glue ++ * ++ * 08 09 2010 wh.su ++ * NULL ++ * let the firmware download default enabled. ++ * ++ * 08 07 2010 wh.su ++ * NULL ++ * adding the privacy related code for P2P network ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add a configure flag for P2P unitest. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) enable Ad-Hoc ++ * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Add for SLT support. ++ * ++ * 07 16 2010 cp.wu ++ * ++ * remove work-around in case SCN is not available. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor ++ * underflow under concurrent network operation ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * for first connection, if connecting failed do not enter into scan state. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add SCN compilation option. ++ * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * set default compiling flag for security disable. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add config option for cfg80211. ++ * ++ * 05 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * set ATIMwindow default value to zero. ++ * ++ * 05 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add option for FPGA_BWCS & FPGA_V5 ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) enable CMD/EVENT ver 0.9 definition. ++ * 2) abandon use of ENUM_MEDIA_STATE ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change firmware name to WIFI_RAM_CODE. ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * disable bt-over-wifi configuration, turn it on after firmware finished implementation ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * re-enable power management ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable TCP/IP checksum offloading by default. ++ * ++ * 04 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * set CFG_ENABLE_FULL_PM to 1 as default to ++ * 1) acquire own before hardware access ++ * 2) set own back after hardware access ++ * ++ * 04 15 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * change firmware name ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * disable RX-enhanced response temporally, it seems the CQ is not resolved yet. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * re-enable RX enhanced mode as WPD00003827 is resolved. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * turn off RX_ENHANCE mode by default. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) eliminate unused definitions ++ * * 2) ready bit will be polled for limited iteration ++ * ++ * 04 02 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * firmware download: Linux uses different firmware path ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * * due to the different configurations on FPGA and ASIC ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add options for full PM support. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * turn on FW-DOWNLOAD as default for release. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 05 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * change CFG_NUM_OF_QM_RX_PKT_NUM to 120 ++ * ++ * 03 04 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * . ++ * ++ * 03 04 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * increase RX buffer number to avoid RX buffer starvation. ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed the number of STA_RECs to 20 ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * and result is retrieved by get ATInfo instead ++ * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-16 22:12:28 GMT mtk02752 ++** enable interrupt enhanced response, TX/RX Aggregation as default ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:38:43 GMT mtk02752 ++** eliminate compile options which are obsolete or for emulation purpose ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 13:56:26 GMT MTK02468 ++** Added RX buffer reordering configurations ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-12-04 12:09:09 GMT mtk02752 ++** once enhanced intr/rx response is taken, RX must be access in aggregated basis ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 17:54:50 GMT mtk02752 ++** correct a typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:47 GMT mtk01084 ++** add defines ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:33:37 GMT mtk02752 ++** add coalescing buffer definition for SD1_SD3_DATAPATH_INTEGRATION ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 20:32:40 GMT mtk02752 ++** add CFG_TX_MAX_PKT_NUM for limiting queued TX packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 13:34:44 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION define for source control ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 13:54:11 GMT mtk01084 ++** enable INT enhance mode by default ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-30 18:17:14 GMT mtk01084 ++** add new define ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-10-29 19:47:36 GMT mtk01084 ++** not use HIF loopback mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-13 21:58:33 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-09-09 17:26:08 GMT mtk01084 ++** add CFG_TEST_WITH_MT5921 ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:02:30 GMT mtk01426 ++** Update CFG_RX_COALESCING_BUFFER_SIZE ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-21 09:35:51 GMT mtk01461 ++** Add CFG_TX_DBG_MGT_BUF to debug MGMT Buffer depth ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:52:21 GMT mtk01426 ++** Add OOB_DATA_PRE_FIXED_LEN define ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-08 16:51:08 GMT mtk01084 ++** update for FW download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:33:37 GMT mtk01461 ++** Add SW pre test flag CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 00:29:18 GMT mtk01461 ++** Fix CFG_COALESCING_BUFFER_SIZE if enable the CFG_TX_FRAGMENT ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-18 20:58:34 GMT mtk01426 ++** Add CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-17 20:17:36 GMT mtk01426 ++** Add CMD/Response related configure ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:21 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:21 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _CONFIG_H ++#define _CONFIG_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#ifdef MT6620 ++#undef MT6620 ++#endif ++ ++#ifndef MT6628 ++#define MT6628 ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 2 Flags for OS capability */ ++ ++#define MTK_WCN_SINGLE_MODULE 0 /* 1: without WMT */ ++ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define MTK_WCN_HIF_SDIO 0 ++#else ++#define MTK_WCN_HIF_SDIO 0 /* samp */ ++#endif ++#else ++#define MTK_WCN_HIF_SDIO 0 ++#endif ++ ++#if (CFG_SUPPORT_AEE == 1) ++#define CFG_ENABLE_AEE_MSG 1 ++#else ++#define CFG_ENABLE_AEE_MSG 0 ++#endif ++ ++#if CFG_ENABLE_AEE_MSG ++#include ++#endif ++ ++/* 2 Flags for Driver Features */ ++#define CFG_TX_FRAGMENT 1 /*!< 1: Enable TX fragmentation ++ 0: Disable */ ++#define CFG_SUPPORT_PERFORMANCE_TEST 0 /*Only for performance Test */ ++ ++#define CFG_COUNTRY_CODE NULL /* "US" */ ++ ++#ifndef LINUX ++#define CFG_FW_FILENAME L"WIFI_RAM_CODE" ++#define CFG_FW_FILENAME_E6 L"WIFI_RAM_CODE_E6" ++#else ++#define CFG_FW_FILENAME "WIFI_RAM_CODE" ++#endif ++#ifndef LINUX ++#define CFG_SUPPORT_CFG_FILE 0 ++#else ++#define CFG_SUPPORT_CFG_FILE 1 ++#endif ++ ++#define CFG_SUPPORT_CE_FCC_TXPWR_LIMIT 0 /* Support CE FCC Tx Power limit */ ++ ++#define CFG_SUPPORT_802_11D 1 /*!< 1(default): Enable 802.11d ++ 0: Disable */ ++ ++#define CFG_SUPPORT_RRM 0 /* Radio Reasource Measurement (802.11k) */ ++#define CFG_SUPPORT_DFS 1 /* DFS (802.11h) */ ++ ++#if (CFG_SUPPORT_DFS == 1) /* Add by Enlai */ ++#define CFG_SUPPORT_QUIET 1 /* Quiet (802.11h) */ ++#define CFG_SUPPORT_SPEC_MGMT 1 /* Spectrum Management (802.11h): TPC and DFS */ ++#else ++#define CFG_SUPPORT_QUIET 0 /* Quiet (802.11h) */ ++#define CFG_SUPPORT_SPEC_MGMT 0 /* Spectrum Management (802.11h): TPC and DFS */ ++#endif ++ ++#define CFG_SUPPORT_RX_RDG 0 /* 11n feature. RX RDG capability */ ++#define CFG_SUPPORT_MFB 0 /* 802.11n MCS Feedback responder */ ++#define CFG_SUPPORT_RX_STBC 1 /* 802.11n RX STBC (1SS) */ ++#define CFG_SUPPORT_RX_SGI 1 /* 802.11n RX short GI for both 20M and 40M BW */ ++#define CFG_SUPPORT_RX_HT_GF 1 /* 802.11n RX HT green-field capability */ ++ ++#define CFG_SUPPORT_ROAMING_ENC 0 /* enahnced roaming */ ++ ++#define CFG_SUPPORT_TDLS 1 /* IEEE802.11z TDLS */ ++#define CFG_SUPPORT_TDLS_DBG 0 /* TDLS debug */ ++#define CFG_SUPPORT_STATISTICS 1 ++#define CFG_SUPPORT_DBG_POWERMODE 1 /* for debugging power always active mode */ ++ ++#define CFG_SUPPORT_GSCN 1 ++ ++#define CFG_SUPPORT_TXR_ENC 0 /* enhanced tx rate switch */ ++ ++#define CFG_SUPPORT_PERSIST_NETDEV 0 /* create NETDEV when system bootup */ ++ ++#define CFG_FORCE_USE_20BW 1 ++/*------------------------------------------------------------------------------ ++ * SLT Option ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SLT_SUPPORT 0 ++ ++#define MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE 0 ++ ++#if defined(MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE) ++#define CFG_AUTO_CHANNEL_SEL_SUPPORT 1 ++#else ++#define CFG_AUTO_CHANNEL_SEL_SUPPORT 0 ++#endif ++ ++#ifdef NDIS60_MINIPORT ++#define CFG_NATIVE_802_11 1 ++ ++#define CFG_TX_MAX_PKT_SIZE 2304 ++#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 /* !< 1: Enable TCP/IP header checksum offload ++ 0: Disable */ ++#define CFG_TCP_IP_CHKSUM_OFFLOAD 0 ++#define CFG_WHQL_DOT11_STATISTICS 1 ++#define CFG_WHQL_ADD_REMOVE_KEY 1 ++#define CFG_WHQL_CUSTOM_IE 1 ++#define CFG_WHQL_SAFE_MODE_ENABLED 1 ++ ++#else ++#define CFG_TCP_IP_CHKSUM_OFFLOAD 1 /* !< 1: Enable TCP/IP header checksum offload ++ 0: Disable */ ++#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 ++#define CFG_TX_MAX_PKT_SIZE 1600 ++#define CFG_NATIVE_802_11 0 ++#endif ++ ++/* 2 Flags for Driver Parameters */ ++/*------------------------------------------------------------------------------ ++ * Flags for EHPI Interface in Colibri Platform ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_EHPI_FASTER_BUS_TIMING 0 /*!< 1: Do workaround for faster bus timing ++ 0(default): Disable */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags for HIFSYS Interface ++ *------------------------------------------------------------------------------ ++ */ ++#ifdef _lint ++#define _HIF_SDIO 0 /* samp */ ++#endif ++ ++#define CFG_SDIO_INTR_ENHANCE 1 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode ++ 0: Disable */ ++#define CFG_SDIO_RX_ENHANCE 0 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode ++ 0: Disable */ ++#define CFG_SDIO_TX_AGG 1 /*!< 1: Enable SDIO TX enhance ++ mode(Multiple frames in single BLOCK CMD) ++ 0(default): Disable */ ++ ++#define CFG_SDIO_RX_AGG 1 /*!< 1: Enable SDIO RX enhance ++ mode(Multiple frames in single BLOCK CMD) ++ 0(default): Disable */ ++ ++#if (CFG_SDIO_RX_AGG == 1) && (CFG_SDIO_INTR_ENHANCE == 0) ++#error "CFG_SDIO_INTR_ENHANCE should be 1 once CFG_SDIO_RX_AGG equals to 1" ++#elif (CFG_SDIO_INTR_ENHANCE == 1 || CFG_SDIO_RX_ENHANCE == 1) && (CFG_SDIO_RX_AGG == 0) ++#error "CFG_SDIO_RX_AGG should be 1 once CFG_SDIO_INTR_ENHANCE and/or CFG_SDIO_RX_ENHANCE equals to 1" ++#endif ++ ++#define CFG_SDIO_MAX_RX_AGG_NUM 0 /*!< 1: Setting the maximum RX aggregation number ++ 0(default): no limited */ ++ ++#ifdef WINDOWS_CE ++#define CFG_SDIO_PATHRU_MODE 1 /*!< 1: Support pass through (PATHRU) mode ++ 0: Disable */ ++#else ++#define CFG_SDIO_PATHRU_MODE 0 /*!< 0: Always disable if WINDOWS_CE is not defined */ ++#endif ++ ++#define CFG_MAX_RX_ENHANCE_LOOP_COUNT 3 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Integration ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(MT6620) ++#define MT6620_FPGA_BWCS 0 ++#define MT6620_FPGA_V5 0 ++ ++#if (MT6620_FPGA_BWCS == 1) && (MT6620_FPGA_V5 == 1) ++#error ++#endif ++ ++#if (MTK_WCN_HIF_SDIO == 1) ++#define CFG_MULTI_ECOVER_SUPPORT 1 ++#elif !defined(LINUX) ++#define CFG_MULTI_ECOVER_SUPPORT 1 ++#else ++#define CFG_MULTI_ECOVER_SUPPORT 0 ++#endif ++ ++#define CFG_ENABLE_CAL_LOG 0 ++#define CFG_REPORT_RFBB_VERSION 0 ++ ++#elif defined(MT6628) ++ ++#define CFG_MULTI_ECOVER_SUPPORT 0 ++ ++#define CFG_ENABLE_CAL_LOG 1 ++#define CFG_REPORT_RFBB_VERSION 1 ++ ++#endif ++ ++#define CFG_CHIP_RESET_SUPPORT 1 ++ ++#if defined(MT6628) ++#define CFG_EMBED_FIRMWARE_BUILD_DATE_CODE 1 ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * Flags for workaround ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(MT6620) && (MT6620_FPGA_BWCS == 0) && (MT6620_FPGA_V5 == 0) ++#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 ++#else ++#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 ++#endif ++ ++/* SPM issue: suspend current is higher than deep idle */ ++#define CFG_SPM_WORKAROUND_FOR_HOTSPOT 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for driver version ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_DRV_OWN_VERSION \ ++ ((UINT_16)((NIC_DRIVER_MAJOR_VERSION << 8) | (NIC_DRIVER_MINOR_VERSION))) ++#define CFG_DRV_PEER_VERSION ((UINT_16)0x0000) ++ ++/*------------------------------------------------------------------------------ ++ * Flags for TX path which are OS dependent ++ *------------------------------------------------------------------------------ ++ */ ++/*! NOTE(Kevin): If the Network buffer is non-scatter-gather like structure(without ++ * NETIF_F_FRAGLIST in LINUX), then we can set CFG_TX_BUFFER_IS_SCATTER_LIST to "0" ++ * for zero copy TX packets. ++ * For scatter-gather like structure, we set "1", driver will do copy frame to ++ * internal coalescing buffer before write it to FIFO. ++ */ ++#if defined(LINUX) ++#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 /*!< 1: Do frame copy before write to TX FIFO. ++ Used when Network buffer is scatter-gather. ++ 0(default): Do not copy frame */ ++#else /* WINDOWS/WINCE */ ++#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 ++#endif /* LINUX */ ++ ++#if CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST ++#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE * NIC_TX_BUFF_SUM) ++#else ++#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE) ++#endif /* CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for TX path ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*! Maximum number of SW TX packet queue */ ++#define CFG_TX_MAX_PKT_NUM 512 /* 256 must >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD * 2; ++ or wmm will fail when queue is full */ ++ ++/*! Maximum number of SW TX CMD packet buffer */ ++#define CFG_TX_MAX_CMD_PKT_NUM 32 ++ ++/*! Maximum number of associated STAs */ ++#define CFG_NUM_OF_STA_RECORD 20 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for RX path ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*! Max. descriptor number - sync. with firmware */ ++#if CFG_SLT_SUPPORT ++#define CFG_NUM_OF_RX0_HIF_DESC 42 ++#else ++#define CFG_NUM_OF_RX0_HIF_DESC 16 ++#endif ++#define CFG_NUM_OF_RX1_HIF_DESC 2 ++ ++/*! Max. buffer hold by QM */ ++#define CFG_NUM_OF_QM_RX_PKT_NUM 120 ++ ++/*! Maximum number of SW RX packet buffer */ ++#define CFG_RX_MAX_PKT_NUM ((CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC) * 3 \ ++ + CFG_NUM_OF_QM_RX_PKT_NUM) ++ ++#define CFG_RX_REORDER_Q_THRESHOLD 8 ++ ++#ifndef LINUX ++#define CFG_RX_RETAINED_PKT_THRESHOLD \ ++ (CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC + CFG_NUM_OF_QM_RX_PKT_NUM) ++#else ++#define CFG_RX_RETAINED_PKT_THRESHOLD 0 ++#endif ++ ++/*! Maximum RX packet size, if exceed this value, drop incoming packet */ ++/* 7.2.3 Maganement frames */ ++#define CFG_RX_MAX_PKT_SIZE (28 + 2312 + 12 /*HIF_RX_HEADER_T*/) /* TODO: it should be ++ 4096 under emulation mode */ ++ ++/*! Minimum RX packet size, if lower than this value, drop incoming packet */ ++#define CFG_RX_MIN_PKT_SIZE 10 /*!< 802.11 Control Frame is 10 bytes */ ++ ++#if CFG_SDIO_RX_AGG ++ /* extra size for CS_STATUS and enhanced response */ ++#define CFG_RX_COALESCING_BUFFER_SIZE ((CFG_NUM_OF_RX0_HIF_DESC + 1) \ ++ * CFG_RX_MAX_PKT_SIZE) ++#else ++#define CFG_RX_COALESCING_BUFFER_SIZE (CFG_RX_MAX_PKT_SIZE) ++#endif ++ ++/*! RX BA capability */ ++#define CFG_NUM_OF_RX_BA_AGREEMENTS 8 ++#define CFG_RX_BA_MAX_WINSIZE 16 ++#define CFG_RX_BA_INC_SIZE 4 ++#define CFG_RX_MAX_BA_TID_NUM 8 ++#define CFG_RX_REORDERING_ENABLED 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for CMD/RESPONSE ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_RESPONSE_POLLING_TIMEOUT 512 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Protocol Stack ++ *------------------------------------------------------------------------------ ++ */ ++/*! Maximum number of BSS in the SCAN list */ ++#define CFG_MAX_NUM_BSS_LIST 64 ++ ++#define CFG_MAX_COMMON_IE_BUF_LEN ((1500 * CFG_MAX_NUM_BSS_LIST) / 3) ++ ++/*! Maximum size of Header buffer of each SCAN record */ ++#define CFG_RAW_BUFFER_SIZE 1024 ++ ++/*! Maximum size of IE buffer of each SCAN record */ ++#define CFG_IE_BUFFER_SIZE 512 ++ ++/*! Maximum number of STA records */ ++#define CFG_MAX_NUM_STA_RECORD 32 ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Power management ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FULL_PM 1 ++#define CFG_ENABLE_WAKEUP_ON_LAN 0 ++#if defined(CONFIG_ARCH_MT6755) || defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || \ ++ defined(CONFIG_ARCH_MT6753) || defined(CONFIG_ARCH_MT6580) ++#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 1 /* debug which packet wake up host */ ++#else ++#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 0 /* debug which packet wake up host */ ++#endif ++#define CFG_INIT_POWER_SAVE_PROF ENUM_PSP_FAST_SWITCH ++ ++#define CFG_INIT_ENABLE_PATTERN_FILTER_ARP 0 ++ ++#define CFG_INIT_UAPSD_AC_BMP 0 /* (BIT(3) | BIT(2) | BIT(1) | BIT(0)) */ ++ ++/* #define CFG_SUPPORT_WAPI 0 */ ++#define CFG_SUPPORT_WPS 1 ++#define CFG_SUPPORT_WPS2 1 ++ ++/*------------------------------------------------------------------------------ ++ * 802.11i RSN Pre-authentication PMKID cahce maximun number ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_MAX_PMKID_CACHE 16 /*!< max number of PMKID cache ++ 16(default) : The Max PMKID cache */ ++/*------------------------------------------------------------------------------ ++ * Auto Channel Selection Maximun Channel Number ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define MAX_AUTO_CHAL_NUM 23 /* Ch1~Ch14,Ch36,Ch40,Ch44, ++ Ch48,Ch149,Ch153,Ch157,Ch161 */ ++/*------------------------------------------------------------------------------ ++ * FAST SCAN ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FAST_SCAN 0 ++#define CFG_CN_SUPPORT_CLASS121 0 /* Add Class 121, 5470-5725MHz, support for China domain */ ++#if CFG_ENABLE_FAST_SCAN ++ #define CFG_FAST_SCAN_DWELL_TIME 40 ++ #define CFG_FAST_SCAN_REG_DOMAIN_DEF_IDX 10 ++#endif ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Ad-Hoc ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_INIT_ADHOC_FREQ (2462000) ++#define CFG_INIT_ADHOC_MODE AD_HOC_MODE_MIXED_11BG ++#define CFG_INIT_ADHOC_BEACON_INTERVAL (100) ++#define CFG_INIT_ADHOC_ATIM_WINDOW (0) ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Maximum Scan SSID number ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SCAN_SSID_MAX_NUM (4) ++#define CFG_SCAN_SSID_MATCH_MAX_NUM (16) ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Load Setup Default ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags for enable 802.11A Band setting ++ *------------------------------------------------------------------------------ ++ */ ++ ++/*------------------------------------------------------------------------------ ++ * Flags and Parameters for Interrupt Process ++ *------------------------------------------------------------------------------ ++ */ ++#if defined(_HIF_SDIO) && defined(WINDOWS_CE) ++#define CFG_IST_LOOP_COUNT 8 ++#else ++#define CFG_IST_LOOP_COUNT 8 ++#endif /* _HIF_SDIO */ ++ ++#define CFG_INT_WRITE_CLEAR 0 ++ ++#if defined(LINUX) ++#define CFG_DBG_GPIO_PINS 0 /* if 1, use MT6516 GPIO pin to log TX behavior */ ++#endif ++ ++/* 2 Flags for Driver Debug Options */ ++/*------------------------------------------------------------------------------ ++ * Flags of TX Debug Option. NOTE(Kevin): Confirm with SA before modifying following flags. ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_DBG_MGT_BUF 1 /*!< 1: Debug statistics usage of MGMT Buffer ++ 0: Disable */ ++ ++#define CFG_HIF_STATISTICS 0 ++ ++#define CFG_HIF_RX_STARVATION_WARNING 0 ++ ++#define CFG_STARTUP_DEBUG 0 ++ ++#define CFG_RX_PKTS_DUMP 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Firmware Download Option. ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_FW_DOWNLOAD 1 ++ ++#define CFG_ENABLE_FW_DOWNLOAD_ACK 1 ++#define CFG_ENABLE_FW_ENCRYPTION 1 ++ ++#if defined(MT6628) ++#define CFG_ENABLE_FW_DOWNLOAD_AGGREGATION 0 ++#define CFG_ENABLE_FW_DIVIDED_DOWNLOAD 1 ++#endif ++ ++#if defined(MT6620) ++#if MT6620_FPGA_BWCS ++#define CFG_FW_LOAD_ADDRESS 0x10014000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10014001 ++#elif MT6620_FPGA_V5 ++#define CFG_FW_LOAD_ADDRESS 0x10008000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10008001 ++#else ++#define CFG_FW_LOAD_ADDRESS 0x10008000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 0 ++#define CFG_FW_START_ADDRESS 0x10008001 ++#endif ++#elif defined(MT6628) ++#define CFG_FW_LOAD_ADDRESS 0x00060000 ++#define CFG_OVERRIDE_FW_START_ADDRESS 1 ++#define CFG_FW_START_ADDRESS 0x00060000 ++#define CFG_START_ADDRESS_IS_1ST_SECTION_ADDR 1 ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Bluetooth-over-WiFi (BT 3.0 + HS) support ++ *------------------------------------------------------------------------------ ++ */ ++ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define CFG_ENABLE_BT_OVER_WIFI 0 ++#else ++#define CFG_ENABLE_BT_OVER_WIFI 1 ++#endif ++#else ++#define CFG_ENABLE_BT_OVER_WIFI 0 ++#endif ++ ++#define CFG_BOW_SEPARATE_DATA_PATH 1 ++ ++#define CFG_BOW_PHYSICAL_LINK_NUM 4 ++ ++#define CFG_BOW_TEST 0 ++ ++#define CFG_BOW_LIMIT_AIS_CHNL 1 ++ ++#define CFG_BOW_SUPPORT_11N 0 ++ ++#define CFG_BOW_RATE_LIMITATION 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Wi-Fi Direct support ++ *------------------------------------------------------------------------------ ++ */ ++#ifdef LINUX ++#ifdef CONFIG_X86 ++#define CFG_ENABLE_WIFI_DIRECT 0 ++#define CFG_SUPPORT_802_11W 0 ++#else ++#define CFG_ENABLE_WIFI_DIRECT 1 ++#define CFG_SUPPORT_802_11W 0 /*!< 0(default): Disable 802.11W */ ++#endif ++#else ++#define CFG_ENABLE_WIFI_DIRECT 0 ++#define CFG_SUPPORT_802_11W 0 /* Not support at WinXP */ ++#endif ++ ++#define CFG_SUPPORT_PERSISTENT_GROUP 0 ++ ++#define CFG_TEST_WIFI_DIRECT_GO 0 ++ ++#define CFG_TEST_ANDROID_DIRECT_GO 0 ++ ++#define CFG_UNITEST_P2P 0 ++ ++/* ++ * Enable cfg80211 option after Android 2.2(Froyo) is suggested, ++ * cfg80211 on linux 2.6.29 is not mature yet ++ */ ++#define CFG_ENABLE_WIFI_DIRECT_CFG_80211 1 ++ ++#define CFG_SUPPORT_HOTSPOT_OPTIMIZATION 1 ++#define CFG_HOTSPOT_OPTIMIZATION_BEACON_INTERVAL 300 ++#define CFG_HOTSPOT_OPTIMIZATION_DTIM 1 ++ ++/*------------------------------------------------------------------------------ ++ * Configuration Flags (Linux Only) ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_EXT_CONFIG 0 ++ ++/*------------------------------------------------------------------------------ ++ * Statistics Buffering Mechanism ++ *------------------------------------------------------------------------------ ++ */ ++#if CFG_SUPPORT_PERFORMANCE_TEST ++#define CFG_ENABLE_STATISTICS_BUFFERING 1 ++#else ++#define CFG_ENABLE_STATISTICS_BUFFERING 0 ++#endif ++#define CFG_STATISTICS_VALID_CYCLE 2000 ++#define CFG_LINK_QUALITY_VALID_PERIOD 5000 ++ ++/*------------------------------------------------------------------------------ ++ * Migration Option ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_ADHOC 0 ++#define CFG_SUPPORT_AAA 1 ++ ++#define CFG_SUPPORT_BCM 0 ++#define CFG_SUPPORT_BCM_BWCS 0 ++#define CFG_SUPPORT_BCM_BWCS_DEBUG 0 ++ ++#define CFG_SUPPORT_RDD_TEST_MODE 0 ++ ++#define CFG_SUPPORT_PWR_MGT 1 ++ ++#define CFG_RSN_MIGRATION 1 ++ ++#define CFG_PRIVACY_MIGRATION 1 ++ ++#define CFG_ENABLE_HOTSPOT_PRIVACY_CHECK 1 ++ ++#define CFG_MGMT_FRAME_HANDLING 1 ++ ++#define CFG_MGMT_HW_ACCESS_REPLACEMENT 0 ++ ++#if CFG_SUPPORT_PERFORMANCE_TEST ++ ++#else ++ ++#endif ++ ++#define CFG_SUPPORT_AIS_5GHZ 1 ++#define CFG_SUPPORT_BEACON_CHANGE_DETECTION 0 ++ ++/*------------------------------------------------------------------------------ ++ * Option for NVRAM and Version Checking ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_NVRAM 1 ++#define CFG_NVRAM_EXISTENCE_CHECK 1 ++#define CFG_SW_NVRAM_VERSION_CHECK 1 ++#define CFG_SUPPORT_NIC_CAPABILITY 1 ++ ++/*------------------------------------------------------------------------------ ++ * CONFIG_TITLE : Stress Test Option ++ * OWNER : Puff Wen ++ * Description : For stress test only. DO NOT enable it while normal operation ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_STRESS_TEST_SUPPORT 0 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for LINT ++ *------------------------------------------------------------------------------ ++ */ ++#define LINT_SAVE_AND_DISABLE /*lint -save -e* */ ++ ++#define LINT_RESTORE /*lint -restore */ ++ ++#define LINT_EXT_HEADER_BEGIN LINT_SAVE_AND_DISABLE ++ ++#define LINT_EXT_HEADER_END LINT_RESTORE ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Features ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define CFG_SUPPORT_QOS 1 /* Enable/disable QoS TX, AMPDU */ ++#define CFG_SUPPORT_AMPDU_TX 1 ++#define CFG_SUPPORT_AMPDU_RX 1 ++#define CFG_SUPPORT_TSPEC 0 /* Enable/disable TS-related Action frames handling */ ++#define CFG_SUPPORT_UAPSD 1 ++#define CFG_SUPPORT_UL_PSMP 0 ++ ++#define CFG_SUPPORT_ROAMING 1 /* Roaming System */ ++#define CFG_SUPPORT_SWCR 1 ++ ++#define CFG_SUPPORT_ANTI_PIRACY 1 ++ ++#define CFG_SUPPORT_OSC_SETTING 1 ++ ++#define CFG_SUPPORT_P2P_RSSI_QUERY 0 ++ ++#define CFG_SHOW_MACADDR_SOURCE 1 ++ ++#define CFG_SUPPORT_802_11V 0 /* Support 802.11v Wireless Network Management */ ++#define CFG_SUPPORT_802_11V_TIMING_MEASUREMENT 0 ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (CFG_SUPPORT_802_11V == 0) ++#error "CFG_SUPPORT_802_11V should be 1 once CFG_SUPPORT_802_11V_TIMING_MEASUREMENT equals to 1" ++#endif ++#if (CFG_SUPPORT_802_11V == 0) ++#define WNM_UNIT_TEST 0 ++#endif ++ ++#define CFG_DRIVER_COMPOSE_ASSOC_REQ 1 ++ ++#define CFG_STRICT_CHECK_CAPINFO_PRIVACY 0 ++ ++#define CFG_SUPPORT_WFD 1 ++ ++#define CFG_SUPPORT_WFD_COMPOSE_IE 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Packet Lifetime Profiling Mechanism ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_ENABLE_PKT_LIFETIME_PROFILE 1 ++ ++#define CFG_ENABLE_PER_STA_STATISTICS 1 ++ ++#define CFG_PRINT_RTP_PROFILE 0 /* If want to enable WFD Debug, please change it to 1. */ ++#define CFG_PRINT_RTP_SN_SKIP 0 ++ ++#define CFG_SUPPORT_PWR_LIMIT_COUNTRY 1 ++/*------------------------------------------------------------------------------ ++ * Flags of bus error tolerance ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_FORCE_RESET_UNDER_BUS_ERROR 0 ++ ++/*------------------------------------------------------------------------------ ++ * Build Date Code Integration ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_BUILD_DATE_CODE 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags for prepare the FW compile flag ++ *------------------------------------------------------------------------------ ++ */ ++#define COMPILE_FLAG0_GET_STA_LINK_STATUS (1<<0) ++#define COMPILE_FLAG0_WFD_ENHANCEMENT_PROTECT (1<<1) ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Batch Scan SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_BATCH_SCAN 0 ++#define CFG_BATCH_MAX_MSCAN 2 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of Channel Environment SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_SUPPORT_GET_CH_ENV 1 ++ ++/*------------------------------------------------------------------------------ ++ * Flags of THERMO_THROTTLING SUPPORT ++ *------------------------------------------------------------------------------ ++ */ ++ ++#define CFG_SUPPORT_THERMO_THROTTLING 1 ++#define WLAN_INCLUDE_PROC 1 ++ ++#define CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE 1 ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _CONFIG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h +new file mode 100644 +index 000000000000..af586063c21a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h +@@ -0,0 +1,466 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/debug.h#1 ++*/ ++ ++/*! \file debug.h ++ \brief Definition of SW debugging level. ++ ++ In this file, it describes the definition of various SW debugging levels and ++ assert functions. ++*/ ++ ++/* ++** Log: debug.h ++ * ++ * 12 16 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * fixed the Windows DDK free build compiling error. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 07 2011 wh.su ++ * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * . ++ * ++ * 09 23 2010 cp.wu ++ * NULL ++ * add BOW index for debugging message and passing compilation ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add one more debug moduel for P2P. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add debug module index for cnm and ais. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add CFG_STARTUP_DEBUG for debugging starting up issue. ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-29 19:47:50 GMT mtk01084 ++** add emu category ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-17 18:12:04 GMT mtk01426 ++** Don't use dynamic memory allocate for debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:29 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _DEBUG_H ++#define _DEBUG_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#ifndef BUILD_QA_DBG ++#define BUILD_QA_DBG 0 ++#endif ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++extern UINT_8 aucDebugModule[]; ++extern UINT_32 u4DebugModule; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Define debug category (class): ++ * (1) ERROR (2) WARN (3) STATE (4) EVENT (5) TRACE (6) INFO (7) LOUD (8) TEMP ++ */ ++#define DBG_CLASS_ERROR BIT(0) ++#define DBG_CLASS_WARN BIT(1) ++#define DBG_CLASS_STATE BIT(2) ++#define DBG_CLASS_EVENT BIT(3) ++#define DBG_CLASS_TRACE BIT(4) ++#define DBG_CLASS_INFO BIT(5) ++#define DBG_CLASS_LOUD BIT(6) ++#define DBG_CLASS_TEMP BIT(7) ++#define DBG_CLASS_MASK BITS(0, 7) ++ ++#if defined(LINUX) ++#define DBG_PRINTF_64BIT_DEC "lld" ++ ++#else /* Windows */ ++#define DBG_PRINTF_64BIT_DEC "I64d" ++ ++#endif ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Define debug module index */ ++typedef enum _ENUM_DBG_MODULE_T { ++ DBG_INIT_IDX = 0, /* For driver initial */ ++ DBG_HAL_IDX, /* For HAL(HW) Layer */ ++ DBG_INTR_IDX, /* For Interrupt */ ++ DBG_REQ_IDX, ++ DBG_TX_IDX, ++ DBG_RX_IDX, ++ DBG_RFTEST_IDX, /* For RF test mode */ ++ DBG_EMU_IDX, /* Developer specific */ ++ ++ DBG_SW1_IDX, /* Developer specific */ ++ DBG_SW2_IDX, /* Developer specific */ ++ DBG_SW3_IDX, /* Developer specific */ ++ DBG_SW4_IDX, /* Developer specific */ ++ ++ DBG_HEM_IDX, /* HEM */ ++ DBG_AIS_IDX, /* AIS */ ++ DBG_RLM_IDX, /* RLM */ ++ DBG_MEM_IDX, /* RLM */ ++ DBG_CNM_IDX, /* CNM */ ++ DBG_RSN_IDX, /* RSN */ ++ DBG_BSS_IDX, /* BSS */ ++ DBG_SCN_IDX, /* SCN */ ++ DBG_SAA_IDX, /* SAA */ ++ DBG_AAA_IDX, /* AAA */ ++ DBG_P2P_IDX, /* P2P */ ++ DBG_QM_IDX, /* QUE_MGT */ ++ DBG_SEC_IDX, /* SEC */ ++ DBG_BOW_IDX, /* BOW */ ++ DBG_WAPI_IDX, /* WAPI */ ++ DBG_ROAMING_IDX, /* ROAMING */ ++ DBG_TDLS_IDX, /* TDLS *//* CFG_SUPPORT_TDLS */ ++ DBG_OID_IDX, ++ DBG_NIC_IDX, ++ ++ DBG_MODULE_NUM /* Notice the XLOG check */ ++} ENUM_DBG_MODULE_T; ++ ++/* XLOG */ ++/* #define XLOG_DBG_MODULE_IDX 28 */ /* DBG_MODULE_NUM */ ++/* #if (XLOG_DBG_MODULE_IDX != XLOG_DBG_MODULE_IDX) */ ++/* #error "Please modify the DBG_MODULE_NUM and make sure this include at XLOG" */ ++/* #endif */ ++ ++/* Define who owns developer specific index */ ++#define DBG_YARCO_IDX DBG_SW1_IDX ++#define DBG_KEVIN_IDX DBG_SW2_IDX ++#define DBG_CMC_IDX DBG_SW3_IDX ++#define DBG_GEORGE_IDX DBG_SW4_IDX ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Debug print format string for the OS system time */ ++#define OS_SYSTIME_DBG_FORMAT "0x%08x" ++ ++/* Debug print argument for the OS system time */ ++#define OS_SYSTIME_DBG_ARGUMENT(systime) (systime) ++ ++/* Debug print format string for the MAC Address */ ++#define MACSTR "%pM" ++/* "%02x:%02x:%02x:%02x:%02x:%02x" */ ++ ++/* Debug print argument for the MAC Address */ ++#define MAC2STR(a) a ++/* ((PUINT_8)a)[0], ((PUINT_8)a)[1], ((PUINT_8)a)[2], ((PUINT_8)a)[3], ((PUINT_8)a)[4], ((PUINT_8)a)[5] */ ++ ++/* The pre-defined format to dump the value of a varaible with its name shown. */ ++#define DUMPVAR(variable, format) (#variable " = " format "\n", variable) ++ ++/* The pre-defined format to dump the MAC type value with its name shown. */ ++#define DUMPMACADDR(addr) (#addr " = %pM\n", (addr)) ++ ++/* Basiclly, we just do renaming of KAL functions although they should ++ * be defined as "Nothing to do" if DBG=0. But in some compiler, the macro ++ * syntax does not support #define LOG_FUNC(x,...) ++ * ++ * A caller shall not invoke these three macros when DBG=0. ++ */ ++ ++/*LOG_FUNC("[wlan]%s:(" #_Module " " #_Class ") "_Fmt, __func__, ##__VA_ARGS__);*/ ++ ++#define LOG_FUNC kalPrint ++ ++#if defined(LINUX) ++#define DBGLOG(_Module, _Class, _Fmt, ...) \ ++ do { \ ++ if ((aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) == 0) \ ++ break; \ ++ LOG_FUNC("%s:(" #_Module " " #_Class ")"_Fmt, __func__, ##__VA_ARGS__); \ ++ } while (0) ++#else ++#define DBGLOG(_Module, _Class, _Fmt) ++#endif ++ ++#if DBG ++ ++#define TMP_BUF_LEN 256 ++#define TMP_WBUF_LEN (TMP_BUF_LEN * 2) ++ ++extern PINT_16 g_wbuf_p; ++extern PINT_8 g_buf_p; ++ ++ /* If __FUNCTION__ is already defined by compiler, we just use it. */ ++#if defined(__func__) ++#define DEBUGFUNC(_Func) ++#else ++#define DEBUGFUNC(_Func) \ ++ static const char __func__[] = _Func ++#endif ++ ++#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ ++ { \ ++ if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ ++ LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ ++ dumpMemory8((PUINT_8) (_StartAddr), (UINT_32) (_Length)); \ ++ } \ ++ } ++ ++#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) \ ++ { \ ++ if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ ++ LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ ++ dumpMemory32((PUINT_32) (_StartAddr), (UINT_32) (_Length)); \ ++ } \ ++ } ++ /*lint -restore */ ++ ++ /*lint -save -e961 use of '#undef' is discouraged */ ++#undef ASSERT ++ /*lint -restore */ ++ ++#ifdef _lint ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp)) { \ ++ do {} while (1); \ ++ } \ ++ } ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#endif /* _lint */ ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define DISP_STRING(_str) _str ++ ++#else /* !DBG */ ++ ++#define DEBUGFUNC(_Func) ++#define INITLOG(_Fmt) ++#define ERRORLOG(_Fmt) ++#define WARNLOG(_Fmt) ++ ++#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) ++#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) ++ ++#undef ASSERT ++ ++#if BUILD_QA_DBG ++#if defined(LINUX) /* For debugging in Linux w/o GDB */ ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#else ++#ifdef WINDOWS_CE ++#define UNICODE_TEXT(_msg) TEXT(_msg) ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ TCHAR rUbuf[256]; \ ++ kalBreakPoint(); \ ++ _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ ++ UNICODE_TEXT(__FILE__), \ ++ __LINE__, \ ++ UNICODE_TEXT(#_exp)); \ ++ MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ TCHAR rUbuf[256]; \ ++ kalBreakPoint(); \ ++ _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ ++ UNICODE_TEXT(__FILE__), \ ++ __LINE__, \ ++ UNICODE_TEXT(#_exp)); \ ++ MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ ++ } \ ++ } ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ kalBreakPoint(); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ kalBreakPoint(); \ ++ } \ ++ } ++#endif /* WINDOWS_CE */ ++#endif /* LINUX */ ++#else ++#define ASSERT(_exp) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ ++ } \ ++ } ++ ++#define ASSERT_REPORT(_exp, _fmt) \ ++ { \ ++ if (!(_exp) && !fgIsBusAccessFailed) { \ ++ LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ ++ LOG_FUNC _fmt; \ ++ } \ ++ } ++#endif /* BUILD_QA_DBG */ ++ ++#define DISP_STRING(_str) "" ++ ++#endif /* DBG */ ++ ++#if CFG_STARTUP_DEBUG ++#if defined(LINUX) ++#define DBGPRINTF kalPrint ++#else ++#define DBGPRINTF DbgPrint ++#endif ++#else ++#define DBGPRINTF(...) ++#endif ++ ++/* The following macro is used for debugging packed structures. */ ++#ifndef DATA_STRUCT_INSPECTING_ASSERT ++#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ ++{ \ ++ switch (0) {case 0: case (expr): default:; } \ ++} ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length); ++ ++VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length); ++ ++VOID wlanDebugInit(VOID); ++VOID wlanDebugUninit(VOID); ++VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable); ++VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd); ++VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _DEBUG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h +new file mode 100644 +index 000000000000..108860c80e2d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h +@@ -0,0 +1,368 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/link.h#1 ++*/ ++ ++/*! \file link.h ++ \brief Definition for simple doubly linked list operations. ++ ++ In this file we define the simple doubly linked list data structure and its ++ operation MACROs and INLINE functions. ++*/ ++ ++/* ++** Log: link.h ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify a MACRO of LINK_FOR_EACH_SAFE for compile error. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833] [MT6620 and MT5931] Driver migration ++ * . ++ * ++ * ++ * ++ * ++ * May 4 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * add WIFI to BORA source control ++** \main\maintrunk.MT5921\8 2008-10-16 15:57:11 GMT mtk01461 ++** Update driver to fix lint warning ++** \main\maintrunk.MT5921\7 2008-08-10 18:47:53 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\6 2007-12-11 00:09:00 GMT mtk01461 ++** Add macro for checking valid list ++** \main\maintrunk.MT5921\5 2007-11-13 14:27:01 GMT mtk01461 ++** Add LINK_IS_INVALID macro ++** Revision 1.1.1.1 2007/06/22 08:09:05 MTK01461 ++** no message ++** ++*/ ++ ++#ifndef _LINK_H ++#define _LINK_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* May cause page fault & unalignment issue (data abort) */ ++#define INVALID_LINK_POISON1 ((VOID *) 0x00100101) ++/* Used to verify that nonbody uses non-initialized link entries. */ ++#define INVALID_LINK_POISON2 ((VOID *) 0x00100201) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Simple Doubly Linked List Structures - Entry Part */ ++typedef struct _LINK_ENTRY_T { ++ struct _LINK_ENTRY_T *prNext, *prPrev; ++} LINK_ENTRY_T, *P_LINK_ENTRY_T; ++ ++/* Simple Doubly Linked List Structures - List Part */ ++typedef struct _LINK_T { ++ P_LINK_ENTRY_T prNext; ++ P_LINK_ENTRY_T prPrev; ++ UINT_32 u4NumElem; ++} LINK_T, *P_LINK_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#if 0 /* No one use it, temporarily mark it for [Lint - Info 773] */ ++#define LINK_ADDR(rLink) { (P_LINK_ENTRY_T)(&(rLink)), (P_LINK_ENTRY_T)(&(rLink)), 0 } ++ ++#define LINK_DECLARATION(rLink) \ ++ struct _LINK_T rLink = LINK_ADDR(rLink) ++#endif ++ ++#define LINK_INITIALIZE(prLink) \ ++ do { \ ++ ((P_LINK_T)(prLink))->prNext = (P_LINK_ENTRY_T)(prLink); \ ++ ((P_LINK_T)(prLink))->prPrev = (P_LINK_ENTRY_T)(prLink); \ ++ ((P_LINK_T)(prLink))->u4NumElem = 0; \ ++ } while (0) ++ ++#define LINK_ENTRY_INITIALIZE(prEntry) \ ++ do { \ ++ ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)NULL; \ ++ ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)NULL; \ ++ } while (0) ++ ++#define LINK_ENTRY_INVALID(prEntry) \ ++ do { \ ++ ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)INVALID_LINK_POISON1; \ ++ ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)INVALID_LINK_POISON2; \ ++ } while (0) ++ ++#define LINK_IS_EMPTY(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)(prLink)) ++ ++/* NOTE: We should do memory zero before any LINK been initiated, so we can check ++ * if it is valid before parsing the LINK. ++ */ ++#define LINK_IS_INVALID(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)NULL) ++ ++#define LINK_IS_VALID(prLink) (((P_LINK_T)(prLink))->prNext != (P_LINK_ENTRY_T)NULL) ++ ++#define LINK_ENTRY(ptr, type, member) ENTRY_OF(ptr, type, member) ++ ++/* Insert an entry into a link list's head */ ++#define LINK_INSERT_HEAD(prLink, prEntry) \ ++ { \ ++ linkAdd(prEntry, prLink); \ ++ ((prLink)->u4NumElem)++; \ ++ } ++ ++/* Append an entry into a link list's tail */ ++#define LINK_INSERT_TAIL(prLink, prEntry) \ ++ { \ ++ linkAddTail(prEntry, prLink); \ ++ ((prLink)->u4NumElem)++; \ ++ } ++ ++/* Peek head entry, but keep still in link list */ ++#define LINK_PEEK_HEAD(prLink, _type, _member) \ ++ ( \ ++ LINK_IS_EMPTY(prLink) ? \ ++ NULL : LINK_ENTRY((prLink)->prNext, _type, _member) \ ++ ) ++ ++/* Peek tail entry, but keep still in link list */ ++#define LINK_PEEK_TAIL(prLink, _type, _member) \ ++ ( \ ++ LINK_IS_EMPTY(prLink) ? \ ++ NULL : LINK_ENTRY((prLink)->prPrev, _type, _member) \ ++ ) ++ ++/* Get first entry from a link list */ ++/* NOTE: We assume the link entry located at the beginning of "prEntry Type", ++ * so that we can cast the link entry to other data type without doubts. ++ * And this macro also decrease the total entry count at the same time. ++ */ ++#define LINK_REMOVE_HEAD(prLink, prEntry, _P_TYPE) \ ++ { \ ++ ASSERT(prLink); \ ++ if (LINK_IS_EMPTY(prLink)) { \ ++ prEntry = (_P_TYPE)NULL; \ ++ } \ ++ else { \ ++ prEntry = (_P_TYPE)(((P_LINK_T)(prLink))->prNext); \ ++ linkDel((P_LINK_ENTRY_T)prEntry); \ ++ ((prLink)->u4NumElem)--; \ ++ } \ ++ } ++ ++/* Assume the link entry located at the beginning of prEntry Type. ++ * And also decrease the total entry count. ++ */ ++#define LINK_REMOVE_KNOWN_ENTRY(prLink, prEntry) \ ++ { \ ++ ASSERT(prLink); \ ++ ASSERT(prEntry); \ ++ linkDel((P_LINK_ENTRY_T)prEntry); \ ++ ((prLink)->u4NumElem)--; \ ++ } ++ ++/* Iterate over a link list */ ++#define LINK_FOR_EACH(prEntry, prLink) \ ++ for (prEntry = (prLink)->prNext; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = (P_LINK_ENTRY_T)prEntry->prNext) ++ ++/* Iterate over a link list backwards */ ++#define LINK_FOR_EACH_PREV(prEntry, prLink) \ ++ for (prEntry = (prLink)->prPrev; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = (P_LINK_ENTRY_T)prEntry->prPrev) ++ ++/* Iterate over a link list safe against removal of link entry */ ++#define LINK_FOR_EACH_SAFE(prEntry, prNextEntry, prLink) \ ++ for (prEntry = (prLink)->prNext, prNextEntry = prEntry->prNext; \ ++ prEntry != (P_LINK_ENTRY_T)(prLink); \ ++ prEntry = prNextEntry, prNextEntry = prEntry->prNext) ++ ++/* Iterate over a link list of given type */ ++#define LINK_FOR_EACH_ENTRY(prObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember)) ++ ++/* Iterate backwards over a link list of given type */ ++#define LINK_FOR_EACH_ENTRY_PREV(prObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prPrev, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = LINK_ENTRY(prObj->rMember.prPrev, _TYPE, rMember)) ++ ++/* Iterate over a link list of given type safe against removal of link entry */ ++#define LINK_FOR_EACH_ENTRY_SAFE(prObj, prNextObj, prLink, rMember, _TYPE) \ ++ for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember), \ ++ prNextObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember); \ ++ &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ ++ prObj = prNextObj, \ ++ prNextObj = LINK_ENTRY(prNextObj->rMember.prNext, _TYPE, rMember)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is only for internal link list manipulation. ++* ++* \param[in] prNew Pointer of new link head ++* \param[in] prPrev Pointer of previous link head ++* \param[in] prNext Pointer of next link head ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID __linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) ++{ ++ prNext->prPrev = prNew; ++ prNew->prNext = prNext; ++ prNew->prPrev = prPrev; ++ prPrev->prNext = prNew; ++ ++} /* end of __linkAdd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will add a new entry after the specified link head. ++* ++* \param[in] prNew New entry to be added ++* \param[in] prHead Specified link head to add it after ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) ++{ ++ __linkAdd(prNew, (P_LINK_ENTRY_T) prLink, prLink->prNext); ++ ++} /* end of linkAdd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will add a new entry before the specified link head. ++* ++* \param[in] prNew New entry to be added ++* \param[in] prHead Specified link head to add it before ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkAddTail(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) ++{ ++ __linkAdd(prNew, prLink->prPrev, (P_LINK_ENTRY_T) prLink); ++ ++} /* end of linkAddTail() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is only for internal link list manipulation. ++* ++* \param[in] prPrev Pointer of previous link head ++* \param[in] prNext Pointer of next link head ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID __linkDel(IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) ++{ ++ prNext->prPrev = prPrev; ++ prPrev->prNext = prNext; ++ ++} /* end of __linkDel() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list. ++* NOTE: the entry is in an initial state. ++* ++* \param prEntry Specified link head(entry) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkDel(IN P_LINK_ENTRY_T prEntry) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ ++ LINK_ENTRY_INITIALIZE(prEntry); ++ ++} /* end of linkDel() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list and then add it ++* after the specified link head. ++* ++* \param[in] prEntry Specified link head(entry) ++* \param[in] prOtherHead Another link head to add it after ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkMove(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ linkAdd(prEntry, prLink); ++ ++} /* end of linkMove() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will delete a specified entry from link list and then add it ++* before the specified link head. ++* ++* \param[in] prEntry Specified link head(entry) ++* \param[in] prOtherHead Another link head to add it before ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID linkMoveTail(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) ++{ ++ __linkDel(prEntry->prPrev, prEntry->prNext); ++ linkAddTail(prEntry, prLink); ++ ++} /* end of linkMoveTail() */ ++ ++#endif /* _LINK_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h +new file mode 100644 +index 000000000000..fd83c79ffe10 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h +@@ -0,0 +1,188 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/aa_fsm.h#1 ++*/ ++ ++/*! \file aa_fsm.h ++ \brief Declaration of functions and finite state machine for SAA/AAA Module. ++ ++ Declaration of functions and finite state machine for SAA/AAA Module. ++*/ ++ ++/* ++** Log: aa_fsm.h ++ * ++ * 10 13 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS ++ * 1. short join failure count limit to 2 ++ * 2. treat join timeout as kind of join failure as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _AA_FSM_H ++#define _AA_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Retry interval for retransmiting authentication-request MMPDU. */ ++#define TX_AUTHENTICATION_RETRY_TIMEOUT_TU 100 /* TU. */ ++ ++/* Retry interval for retransmiting association-request MMPDU. */ ++#define TX_ASSOCIATION_RETRY_TIMEOUT_TU 100 /* TU. */ ++ ++/* Wait for a response to a transmitted authentication-request MMPDU. */ ++#define DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ ++ ++/* Wait for a response to a transmitted association-request MMPDU. */ ++#define DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ ++ ++/* The maximum time to wait for JOIN process complete. */ ++#define JOIN_FAILURE_TIMEOUT_BEACON_INTERVAL 20 /* Beacon Interval, 20 * 100TU = 2 sec. */ ++ ++/* Retry interval for next JOIN request. */ ++#define JOIN_RETRY_INTERVAL_SEC 10 /* Seconds */ ++ ++/* Maximum Retry Count for accept a JOIN request. */ ++#define JOIN_MAX_RETRY_FAILURE_COUNT 2 /* Times */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_AA_STATE_T { ++ AA_STATE_IDLE = 0, ++ SAA_STATE_SEND_AUTH1, ++ SAA_STATE_WAIT_AUTH2, ++ SAA_STATE_SEND_AUTH3, ++ SAA_STATE_WAIT_AUTH4, ++ SAA_STATE_SEND_ASSOC1, ++ SAA_STATE_WAIT_ASSOC2, ++ AAA_STATE_SEND_AUTH2, ++ AAA_STATE_SEND_AUTH4, /* We may not use, because P2P GO didn't support WEP and 11r */ ++ AAA_STATE_SEND_ASSOC2, ++ AA_STATE_RESOURCE, /* A state for debugging the case of out of msg buffer. */ ++ AA_STATE_NUM ++} ENUM_AA_STATE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in saa_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++saaFsmSteps(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb); ++ ++WLAN_STATUS ++saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, ++ WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb); ++ ++VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS ++saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in aaa_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AA_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h +new file mode 100644 +index 000000000000..b771bdacf2c6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h +@@ -0,0 +1,573 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/ais_fsm.h#1 ++*/ ++ ++/*! \file ais_fsm.h ++ \brief Declaration of functions and finite state machine for AIS Module. ++ ++ Declaration of functions and finite state machine for AIS Module. ++*/ ++ ++/* ++** Log: ais_fsm.h ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition ++ * from synchronous to asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS ++ * is in Normal TR state without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 04 25 2011 cp.wu ++ * [WCXRP00000676] [MT6620 Wi-Fi][Driver] AIS to reduce request channel period from 5 seconds to 2 seconds ++ * channel interval for joining is shortened to 2 seconds to avoid interruption of concurrent operating network. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 02 22 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with ++ * a queue-based approach to improve response time for scanning request ++ * handle SCAN and RECONNECT with a FIFO approach. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 14 2011 cp.wu ++ * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent ++ * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. ++ * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, RLM/CNM will handle ++ * the channel switching when BSS information is updated ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, ++ * just pend it til 5-sec. period finishes ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * separate AIS-FSM states into different cases of channel request. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Refine AIS-FSM by divided into more states ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 23 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * reduce the background ssid idle time min and max value ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * and will send Null frame to diagnose connection ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Support dynamic channel selection ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Media disconnect indication and related postpone functions ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmRunEventJoinComplete() ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Virtual CMD & RESP for testing CMD PATH ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * add aisFsmInitializeConnectionSettings() ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_MGMT_FSM for aisFsmTest() ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function prototype of aisFsmInit() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _AIS_FSM_H ++#define _AIS_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define AIS_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ ++#define AIS_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ ++ ++#define AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4 2 /* 2.4G scan need about 0.5s, so delay 2s to reconnect is enough */ ++#define AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND 5 /* 2.4G scan need about 3.3s, so delay 5s to reconnect is enough */ ++ ++#define AIS_IBSS_ALONE_TIMEOUT_SEC 20 /* seconds */ ++ ++#define AIS_BEACON_TIMEOUT_COUNT_ADHOC 30 ++#define AIS_BEACON_TIMEOUT_COUNT_INFRA 10 ++#define AIS_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ ++ ++#define AIS_BEACON_MAX_TIMEOUT_TU 100 ++#define AIS_BEACON_MIN_TIMEOUT_TU 5 ++#define AIS_BEACON_MAX_TIMEOUT_VALID TRUE ++#define AIS_BEACON_MIN_TIMEOUT_VALID TRUE ++ ++#define AIS_BMC_MAX_TIMEOUT_TU 100 ++#define AIS_BMC_MIN_TIMEOUT_TU 5 ++#define AIS_BMC_MAX_TIMEOUT_VALID TRUE ++#define AIS_BMC_MIN_TIMEOUT_VALID TRUE ++ ++#define AIS_JOIN_CH_GRANT_THRESHOLD 10 ++#define AIS_JOIN_CH_REQUEST_INTERVAL 3000 ++ ++#define AIS_SCN_DONE_TIMEOUT_SEC 30 /* 15 for 2.4G + 5G */ /* 5 */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_AIS_STATE_T { ++ AIS_STATE_IDLE = 0, ++ AIS_STATE_SEARCH, ++ AIS_STATE_SCAN, ++ AIS_STATE_ONLINE_SCAN, ++ AIS_STATE_LOOKING_FOR, ++ AIS_STATE_WAIT_FOR_NEXT_SCAN, ++ AIS_STATE_REQ_CHANNEL_JOIN, ++ AIS_STATE_JOIN, ++ AIS_STATE_IBSS_ALONE, ++ AIS_STATE_IBSS_MERGE, ++ AIS_STATE_NORMAL_TR, ++ AIS_STATE_DISCONNECTING, ++ AIS_STATE_REQ_REMAIN_ON_CHANNEL, ++ AIS_STATE_REMAIN_ON_CHANNEL, ++ AIS_STATE_NUM ++} ENUM_AIS_STATE_T; ++ ++typedef struct _MSG_AIS_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucReasonOfDisconnect; ++ BOOLEAN fgDelayIndication; ++} MSG_AIS_ABORT_T, *P_MSG_AIS_ABORT_T; ++ ++typedef struct _MSG_AIS_IBSS_PEER_FOUND_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ BOOLEAN fgIsMergeIn; /* TRUE: Merge In, FALSE: Merge Out */ ++ P_STA_RECORD_T prStaRec; ++} MSG_AIS_IBSS_PEER_FOUND_T, *P_MSG_AIS_IBSS_PEER_FOUND_T; ++ ++typedef enum _ENUM_AIS_REQUEST_TYPE_T { ++ AIS_REQUEST_SCAN, ++ AIS_REQUEST_RECONNECT, ++ AIS_REQUEST_ROAMING_SEARCH, ++ AIS_REQUEST_ROAMING_CONNECT, ++ AIS_REQUEST_REMAIN_ON_CHANNEL, ++ AIS_REQUEST_NUM ++} ENUM_AIS_REQUEST_TYPE_T; ++ ++typedef struct _AIS_REQ_HDR_T { ++ LINK_ENTRY_T rLinkEntry; ++ ENUM_AIS_REQUEST_TYPE_T eReqType; ++} AIS_REQ_HDR_T, *P_AIS_REQ_HDR_T; ++ ++typedef struct _AIS_REQ_CHNL_INFO { ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eSco; ++ UINT_8 ucChannelNum; ++ UINT_32 u4DurationMs; ++ UINT_64 u8Cookie; ++} AIS_REQ_CHNL_INFO, *P_AIS_REQ_CHNL_INFO; ++ ++typedef struct _AIS_MGMT_TX_REQ_INFO_T { ++ BOOLEAN fgIsMgmtTxRequested; ++ P_MSDU_INFO_T prMgmtTxMsdu; ++ UINT_64 u8Cookie; ++} AIS_MGMT_TX_REQ_INFO_T, *P_AIS_MGMT_TX_REQ_INFO_T; ++ ++typedef struct _AIS_FSM_INFO_T { ++ ENUM_AIS_STATE_T ePreviousState; ++ ENUM_AIS_STATE_T eCurrentState; ++ ++ BOOLEAN fgTryScan; ++ ++ BOOLEAN fgIsInfraChannelFinished; ++ BOOLEAN fgIsChannelRequested; ++ BOOLEAN fgIsChannelGranted; ++ ++#if CFG_SUPPORT_ROAMING ++ BOOLEAN fgIsRoamingScanPending; ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++ P_BSS_DESC_T prTargetBssDesc; /* For destination */ ++ ++ P_STA_RECORD_T prTargetStaRec; /* For JOIN Abort */ ++ ++ UINT_32 u4SleepInterval; ++ ++ TIMER_T rBGScanTimer; ++ ++ TIMER_T rIbssAloneTimer; ++ ++ TIMER_T rIndicationOfDisconnectTimer; ++ ++ TIMER_T rJoinTimeoutTimer; ++ ++ TIMER_T rChannelTimeoutTimer; ++ ++ TIMER_T rScanDoneTimer; ++ ++ TIMER_T rDeauthDoneTimer; ++ ++ UINT_8 ucSeqNumOfReqMsg; ++ UINT_8 ucSeqNumOfChReq; ++ UINT_8 ucSeqNumOfScanReq; ++ ++ UINT_32 u4ChGrantedInterval; ++ ++ UINT_8 ucConnTrialCount; ++ ++ UINT_8 ucScanSSIDLen; ++ UINT_8 aucScanSSID[ELEM_MAX_LEN_SSID]; ++ ++ UINT_32 u4ScanIELength; ++ UINT_8 aucScanIEBuf[MAX_IE_LENGTH]; ++ ++ /* Pending Request List */ ++ LINK_T rPendingReqList; ++ ++ /* Join Request Timestamp */ ++ OS_SYSTIME rJoinReqTime; ++ ++ /* for cfg80211 REMAIN_ON_CHANNEL support */ ++ AIS_REQ_CHNL_INFO rChReqInfo; ++ ++ /* Mgmt tx related. */ ++ AIS_MGMT_TX_REQ_INFO_T rMgmtTxInfo; ++ ++ /* Packet filter for AIS module. */ ++ UINT_32 u4AisPacketFilter; ++ ++} AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define aisChangeMediaState(_prAdapter, _eNewMediaState) \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState = (_eNewMediaState)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++VOID aisFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication); ++ ++VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter); ++#if 0 ++VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState); ++#endif ++VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Handling for Ad-Hoc Network */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++/*----------------------------------------------------------------------------*/ ++/* Handling of Incoming Mailbox Message from CNM */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++/*----------------------------------------------------------------------------*/ ++/* Generating Outgoing Mailbox Message to CNM */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Event Indication */ ++/*----------------------------------------------------------------------------*/ ++VOID ++aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); ++ ++VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb); ++ ++VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter); ++ ++VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++WLAN_STATUS ++aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Disconnection Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication); ++ ++/*----------------------------------------------------------------------------*/ ++/* Event Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter); ++ ++VOID aisBssSecurityChanged(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if CFG_SUPPORT_ROAMING ++VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan); ++ ++ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter); ++ ++VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec); ++ ++VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++#endif /*CFG_SUPPORT_ROAMING */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Timeout Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength); ++ ++/*----------------------------------------------------------------------------*/ ++/* Internal State Checking */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove); ++ ++P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType); ++ ++VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); ++ ++VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) ++VOID aisTest(VOID); ++#endif /* CFG_TEST_MGMT_FSM */ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AIS_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h +new file mode 100644 +index 000000000000..70b32bca102b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h +@@ -0,0 +1,112 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/assoc.h#1 ++*/ ++ ++/*! \file assoc.h ++ \brief This file contains the ASSOC REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: assoc.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add assocCheckTxReAssocRespFrame() proto type for P2P usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _ASSOC_H ++#define _ASSOC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in assoc.c */ ++/*----------------------------------------------------------------------------*/ ++UINT_16 assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++WLAN_STATUS ++assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode); ++ ++WLAN_STATUS ++assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); ++ ++WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ASSOC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h +new file mode 100644 +index 000000000000..4f76f03324dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h +@@ -0,0 +1,125 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/auth.h#1 ++*/ ++ ++/*! \file auth.h ++ \brief This file contains the authentication REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: auth.h ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _AUTH_H ++#define _AUTH_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in auth.c */ ++/*----------------------------------------------------------------------------*/ ++VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo); ++ ++#if !CFG_SUPPORT_AAA ++WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum); ++#else ++WLAN_STATUS ++authSendAuthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode); ++#endif /* CFG_SUPPORT_AAA */ ++ ++WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum); ++ ++WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode); ++ ++VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr); ++ ++WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++authSendDeauthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); ++ ++WLAN_STATUS ++authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN UINT_8 aucExpectedBSSID[], ++ IN UINT_16 u2ExpectedAuthAlgNum, ++ IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _AUTH_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h +new file mode 100644 +index 000000000000..5995d133a6cd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h +@@ -0,0 +1,184 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/bow_fsm.h#1 ++*/ ++ ++/*! \file bow_fsm.h ++ \brief Declaration of functions and finite state machine for BOW Module. ++ ++ Declaration of functions and finite state machine for BOW Module. ++*/ ++ ++/* ++** Log: bow_fsm.h ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Submit missing BoW header files. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add channel previledge into _BOW_FSM_INFO_T. ++ * ++ * 09 16 2010 chinghwa.yu ++ * NULL ++ * update bowChangeMediaState. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ */ ++ ++#ifndef _BOW_FSM_H ++#define _BOW_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define BOW_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ ++#define BOW_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ ++ ++#define BOW_DELAY_TIME_OF_DISCONNECT_SEC 10 ++ ++#define BOW_BEACON_TIMEOUT_COUNT_STARTING 10 ++#define BOW_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ ++ ++#define BOW_BEACON_MAX_TIMEOUT_TU 100 ++#define BOW_BEACON_MIN_TIMEOUT_TU 5 ++#define BOW_BEACON_MAX_TIMEOUT_VALID TRUE ++#define BOW_BEACON_MIN_TIMEOUT_VALID TRUE ++ ++#define BOW_BMC_MAX_TIMEOUT_TU 100 ++#define BOW_BMC_MIN_TIMEOUT_TU 5 ++#define BOW_BMC_MAX_TIMEOUT_VALID TRUE ++#define BOW_BMC_MIN_TIMEOUT_VALID TRUE ++ ++#define BOW_JOIN_CH_GRANT_THRESHOLD 10 ++#define BOW_JOIN_CH_REQUEST_INTERVAL 2000 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_BOW_STATE_T { ++ BOW_STATE_IDLE = 0, ++ BOW_STATE_SEARCH, ++ BOW_STATE_SCAN, ++ BOW_STATE_ONLINE_SCAN, ++ BOW_STATE_LOOKING_FOR, ++ BOW_STATE_WAIT_FOR_NEXT_SCAN, ++ BOW_STATE_REQ_CHANNEL_JOIN, ++ BOW_STATE_REQ_CHANNEL_ALONE, ++ BOW_STATE_REQ_CHANNEL_MERGE, ++ BOW_STATE_JOIN, ++ BOW_STATE_IBSS_ALONE, ++ BOW_STATE_IBSS_MERGE, ++ BOW_STATE_NORMAL_TR, ++ BOW_STATE_NUM ++} ENUM_BOW_STATE_T; ++ ++typedef struct _BOW_FSM_INFO_T { ++ ENUM_BOW_STATE_T ePreviousState; ++ ENUM_BOW_STATE_T eCurrentState; ++ ++ BOOLEAN fgTryScan; ++ ++ /* Channel Privilege */ ++ ++ BOOLEAN fgIsInfraChannelFinished; ++ BOOLEAN fgIsChannelRequested; ++ BOOLEAN fgIsChannelGranted; ++ BOOLEAN fgIsScanPending; ++ UINT_32 u4ChGrantedInterval; ++ ++ UINT_8 ucPrimaryChannel; ++ ENUM_BAND_T eBand; ++ UINT_16 u2BeaconInterval; ++ ++ ENUM_BOW_STATE_T eReturnState; /* Return state after current activity finished or abort. */ ++ ENUM_BOW_STATE_T eForwardState; /* Step to next state if ACTION frame is TX successfully. */ ++ ++ P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ ++ ++ P_STA_RECORD_T prTargetStaRec; ++ P_BSS_DESC_T prTargetBssDesc; /* For destination */ ++ ++ UINT_8 aucPeerAddress[6]; ++ ++ UINT_8 ucRole; ++ ++ BOOLEAN fgSupportQoS; ++ ++ BOOLEAN fgIsRsponseProbe; /* Indicate if BOW can response probe request frame. */ ++ ++ /* Sequence number of requested message. */ ++ UINT_8 ucSeqNumOfChReq; ++ UINT_8 ucSeqNumOfReqMsg; ++ UINT_8 ucSeqNumOfScnMsg; ++ UINT_8 ucSeqNumOfScanReq; ++ ++ UINT_8 ucSeqNumOfCancelMsg; ++ ++ UINT_8 ucDialogToken; ++ ++ /* Timer */ ++ TIMER_T rStartingBeaconTimer; /* For device discovery time of each discovery request from user. */ ++ TIMER_T rStartingDiscoveryTimer; ++ TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ ++ TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ ++ TIMER_T rIndicationOfDisconnectTimer; ++ TIMER_T rChGrantedTimer; ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++} BOW_FSM_INFO_T, *P_BOW_FSM_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define bowChangeMediaState(_prAdapter, _eNewMediaState) \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].eConnectionState = (_eNewMediaState)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h +new file mode 100644 +index 000000000000..0597132b970e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h +@@ -0,0 +1,265 @@ ++/* ++** Id: @(#) bss.h ++*/ ++ ++/*! \file "bss.h" ++ \brief In this file we define the function prototype used in BSS/IBSS. ++ ++ The file contains the function declarations and defines for used in BSS/IBSS. ++*/ ++ ++/* ++** Log: bss.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 02 23 2011 eddie.chen ++ * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap ++ * Fix parsing WMM INFO and bmp delivery bitmap definition. ++ * ++ * 01 31 2011 george.huang ++ * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers ++ * Extend TIM PVB, from 2 to 3 octets. ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Update bssProcessProbeRequest() and bssSendBeaconProbeResponse() declarations ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add CTRL FLAGS for Probe Response. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Remove unused typedef. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix file merge error ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * and will send Null frame to diagnose connection ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add DTIM count update while TX Beacon ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++#ifndef _BSS_H ++#define _BSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* NOTE(Kevin): change define for george */ ++/* #define MAX_LEN_TIM_PARTIAL_BMP (((MAX_ASSOC_ID + 1) + 7) / 8) */ /* Required bits = (MAX_ASSOC_ID + 1) */ ++#define MAX_LEN_TIM_PARTIAL_BMP ((CFG_STA_REC_NUM + 7) / 8) ++/* reserve length greater than maximum size of STA_REC */ /* obsoleted: Assume we only use AID:1~15 */ ++ ++/* CTRL FLAGS for Probe Response */ ++#define BSS_PROBE_RESP_USE_P2P_DEV_ADDR BIT(0) ++#define BSS_PROBE_RESP_INCLUDE_P2P_IE BIT(1) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define bssAssignAssocID(_prStaRec) ((_prStaRec)->ucIndex + 1) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines for all Operation Modes */ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T ++bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_STA_TYPE_T eStaType, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc); ++ ++VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec); ++ ++VOID ++bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP); ++ ++WLAN_STATUS ++bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++WLAN_STATUS ++bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for both IBSS(AdHoc) and BSS(AP) */ ++/*----------------------------------------------------------------------------*/ ++VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr); ++ ++VOID ++bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN PUINT_8 pucDestAddr, ++ IN PUINT_8 pucOwnMACAddress, ++ IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo); ++ ++WLAN_STATUS ++bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags); ++ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); ++ ++VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for IBSS(AdHoc) only */ ++/*----------------------------------------------------------------------------*/ ++VOID ++ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI); ++ ++WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for BSS(AP) only */ ++/*----------------------------------------------------------------------------*/ ++VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate); ++ ++VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId); ++ ++P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr); ++ ++/*link function to p2p module for txBcnIETable*/ ++ ++/* WMM-2.2.2 WMM ACI to AC coding */ ++typedef enum _ENUM_ACI_T { ++ ACI_BE = 0, ++ ACI_BK = 1, ++ ACI_VI = 2, ++ ACI_VO = 3, ++ ACI_NUM ++} ENUM_ACI_T, *P_ENUM_ACI_T; ++ ++typedef enum _ENUM_AC_PRIORITY_T { ++ AC_BK_PRIORITY = 0, ++ AC_BE_PRIORITY, ++ AC_VI_PRIORITY, ++ AC_VO_PRIORITY ++} ENUM_AC_PRIORITY_T, *P_ENUM_AC_PRIORITY_T; ++ ++#endif /* _BSS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h +new file mode 100644 +index 000000000000..81b16b588867 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h +@@ -0,0 +1,258 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm.h#1 ++*/ ++ ++/*! \file "cnm.h" ++ \brief ++*/ ++ ++/* ++** Log: cnm.h ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Provide function to decide if BSS can be activated or not ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 13 2010 cm.chang ++ * ++ * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Need bandwidth info when requesting channel privilege ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add a new function to send abort message ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support partial part about cmd basic configuration ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add prototype of cnmFsmEventInit() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_H ++#define _CNM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _ENUM_CH_REQ_TYPE_T { ++ CH_REQ_TYPE_JOIN, ++ CH_REQ_TYPE_P2P_LISTEN, ++ ++ CH_REQ_TYPE_NUM ++} ENUM_CH_REQ_TYPE_T, *P_ENUM_CH_REQ_TYPE_T; ++ ++typedef struct _MSG_CH_REQ_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++ UINT_32 u4MaxInterval; /* In unit of ms */ ++ UINT_8 aucBSSID[6]; ++ UINT_8 aucReserved[2]; ++} MSG_CH_REQ_T, *P_MSG_CH_REQ_T; ++ ++typedef struct _MSG_CH_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++} MSG_CH_ABORT_T, *P_MSG_CH_ABORT_T; ++ ++typedef struct _MSG_CH_GRANT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++ UINT_32 u4GrantInterval; /* In unit of ms */ ++} MSG_CH_GRANT_T, *P_MSG_CH_GRANT_T; ++ ++typedef struct _MSG_CH_REOCVER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucPrimaryChannel; ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ENUM_CH_REQ_TYPE_T eReqType; ++} MSG_CH_RECOVER_T, *P_MSG_CH_RECOVER_T; ++ ++typedef struct _CNM_INFO_T { ++ UINT_32 u4Reserved; ++} CNM_INFO_T, *P_CNM_INFO_T; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/* Moved from p2p_fsm.h */ ++typedef struct _DEVICE_TYPE_T { ++ UINT_16 u2CategoryId; /* Category ID */ ++ UINT_8 aucOui[4]; /* OUI */ ++ UINT_16 u2SubCategoryId; /* Sub Category ID */ ++} __KAL_ATTRIB_PACKED__ DEVICE_TYPE_T, *P_DEVICE_TYPE_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cnmInit(P_ADAPTER_T prAdapter); ++ ++VOID cnmUninit(P_ADAPTER_T prAdapter); ++ ++VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent); ++ ++BOOLEAN ++cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO); ++ ++BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); ++ ++VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter); ++ ++BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); ++#if CFG_P2P_LEGACY_COEX_REVISE ++BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* We don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this to guarantee the same member order in different structures ++ * to simply handling effort in some functions. ++ */ ++static inline VOID cnmMsgDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == OFFSET_OF(MSG_CH_RECOVER_T, rMsgHdr)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucNetTypeIndex) == ++ OFFSET_OF(MSG_CH_RECOVER_T, ucNetTypeIndex)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucTokenID) == OFFSET_OF(MSG_CH_RECOVER_T, ucTokenID)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucPrimaryChannel) == ++ OFFSET_OF(MSG_CH_RECOVER_T, ucPrimaryChannel)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfSco) == OFFSET_OF(MSG_CH_RECOVER_T, eRfSco)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfBand) == OFFSET_OF(MSG_CH_RECOVER_T, eRfBand)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eReqType) == OFFSET_OF(MSG_CH_RECOVER_T, eReqType)); ++ ++} ++#endif /* _lint */ ++ ++#endif /* _CNM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h +new file mode 100644 +index 000000000000..c8f25b1b29a9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h +@@ -0,0 +1,1164 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_mem.h#1 ++*/ ++ ++/*! \file "cnm_mem.h" ++ \brief In this file we define the structure of the control unit of ++ packet buffer and MGT/MSG Memory Buffer. ++*/ ++ ++/* ++** Log: cnm_mem.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Resize the Secondary Device Type array when WiFi Direct is enabled. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add per STA flow control when STA is in PS mode ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 12 2010 cp.wu ++ * ++ * SAA will take a record for tracking request sequence number. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error for P2P related defination. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related fields. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [BORA00000678] [MT6620]WiFi LP integration ++ * 1. add u8TimeStamp in MSDU_INFO ++ * 2. move fgIsRxTSFUpdated/fgIsTxTSFUpdated from static to BSS_INFO ++ * 3. add new member for supporting PM in STA_RECORD, which is for AP PS mode ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support checking of duplicated buffer free ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 19 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fixed MAC RX Desc be overwritten issue ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 10 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support Rx header translation for A-MSDU subframe ++ * ++ * 05 07 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * add more sanity check about setting timer ++ * ++ * 04 29 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * modify the compiling flag for RAM usage ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Modified some MQM-related data structures (SN counter, TX/RX BA table) ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Added new TX/RX BA tables in STA_REC ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 09 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * [BORA00000644] WiFi phase 4 integration ++ * Added per-TID SN cache in STA_REC ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support power control ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 11 2010 yuche.tsai ++ * [BORA00000343][MT6620] Emulation For TX ++ * . ++ * ++ * 03 05 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove Emulation definition ++ * ++ * 03 04 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * eliminate HIF_EMULATION in cnm_mem.h ++ * ++ * 03 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add cnmStaRecChangeState() declaration. ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning for some emulation flags ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * To store field AMPDU Parameters in STA_REC ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsWmmSupported in STA_RECORD_T. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsUapsdSupported in STA_RECORD_T ++ * ++ * 02 13 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added arTspecTable in STA_REC for TSPEC management ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable mgmt buffer debug by default ++ * ++ * 02 12 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added BUFFER_SOURCE_BCN ++ * ++ * 02 10 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Renamed MSDU_INFO.ucFixedRateIndex as MSDU_INFO.ucFixedRateCode ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 02 02 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added SN info in MSDU_INFO_T ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h ++ * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem ++ * 3) use cnmMemAlloc() instead to allocate SRAM buffer ++ * ++ * 12 31 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) surpress debug message emitted from hal_hif.c ++ * 2) add two set of field for recording buffer process time ++ * ++ * 12 31 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1. move wifi task initialization from wifi_task.c(rom) to wifi_init.c (TCM) for integrating F/W download later ++ * * * * * 2. WIFI_Event_Dispatcher() prototype changed to return to suspend mode from normal operation mode ++ * * * * * 2. HIF emulation logic revised ++ * ++ * 12 29 2009 yuche.tsai ++ * [BORA00000343][MT6620] Emulation For TX ++ * .Using global buffer declaring by SD1 instead of using another one. ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * MQM: BA handling ++ * * TXM: Macros updates ++ * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 24 2009 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 23 2009 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * allocating SRAM for emulation purpose by ruducing MEM_BANK3_BUF_SZ ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove individual DATA_BUF_BLOCK_NUM definition for emulation compiling flagsu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support several data buffer banks. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * .For new FPGA memory size ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 17 2009 george.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 17 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Modified the DATA_BLOCK_SIZE from 1620 to 2048 ++ * ++ * Dec 16 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_SEC_EMULATION flag ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add HT cap to sta record ++ * ++ * Dec 9 2009 mtk02752 ++ * [BORA00000368] Integrate HIF part into BORA ++ * add cnmDataPktFree() for emulation loopback purpose ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the buffer for key handshake 1x and cmd key order issue ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * move the tx call back function proto type to typedef.h ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add cnmGetStaRecByAddress() and modify variable in STA_RECORD_T ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the port block flag ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add variables to STA_RECORD_T for assoc/auth ++ * ++ * Nov 23 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed the value of STA_WAIT_QUEUE_NUM (from 7 to 5) ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed u2FrameLength from SW_RFB ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed indenting ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Updated MSDU_INFO and SW_RFB ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * update the variable for security ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove the variable to make the compiler ok ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the variable for security module ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo in define of MSG_BUF_BLOCK_SIZE ++ * ++ * Nov 13 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Let typedef STA_REC_T precede typedef MSDU_INFO_T and SW_RFB_T ++ * ++ * Nov 13 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Modified MSDU_INFO and STA_REC for TXM and MQM ++ * ++ * Nov 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename STA_REC_T to STA_RECORD_T and add ucIndex member ++ * ++ * Nov 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Make sure ucBufferSource the same offset in MSDU_INFO and SW_RFB ++ * ++ * Nov 6 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Nov 5 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comment ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add draft content of MSDU_INFO_T and SW_RFB_T ++ * ++ * Oct 30 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 21 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_RX_EMULATION flag ++ * ++ * Oct 20 2009 mtk01426 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 9 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added field ucTC to MSDU_INFO_T and field pucHifRxPacket to SW_RFB_T ++ * ++ * Oct 8 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_MEM_H ++#define _CNM_MEM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#ifndef POWER_OF_2 ++#define POWER_OF_2(n) BIT(n) ++#endif ++ ++/* Size of a basic management buffer block in power of 2 */ ++#define MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2 7 /* 7 to the power of 2 = 128 */ ++#define MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2 5 /* 5 to the power of 2 = 32 */ ++ ++/* Size of a basic management buffer block */ ++#define MGT_BUF_BLOCK_SIZE POWER_OF_2(MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++#define MSG_BUF_BLOCK_SIZE POWER_OF_2(MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++ ++/* Total size of (n) basic management buffer blocks */ ++#define MGT_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++#define MSG_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) ++ ++/* Number of management buffer block */ ++#define MAX_NUM_OF_BUF_BLOCKS 32 /* Range: 1~32 */ ++ ++/* Size of overall management frame buffer */ ++#define MGT_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MGT_BUF_BLOCK_SIZE) ++#define MSG_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MSG_BUF_BLOCK_SIZE) ++ ++/* STA_REC related definitions */ ++#define STA_REC_INDEX_BMCAST 0xFF ++#define STA_REC_INDEX_NOT_FOUND 0xFE ++#define STA_WAIT_QUEUE_NUM 5 /* Number of SW queues in each STA_REC: AC0~AC4 */ ++#define SC_CACHE_INDEX_NUM 5 /* Number of SC caches in each STA_REC: AC0~AC4 */ ++ ++/* P2P related definitions */ ++#ifdef CFG_ENABLE_WIFI_DIRECT ++/* Moved from p2p_fsm.h */ ++#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ ++#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if ((MAX_NUM_OF_BUF_BLOCKS > 32) || (MAX_NUM_OF_BUF_BLOCKS <= 0)) ++#error > #define MAX_NUM_OF_MGT_BUF_BLOCKS : Out of boundary ! ++#elif MAX_NUM_OF_BUF_BLOCKS > 16 ++typedef UINT_32 BUF_BITMAP; ++#elif MAX_NUM_OF_BUF_BLOCKS > 8 ++typedef UINT_16 BUF_BITMAP; ++#else ++typedef UINT_8 BUF_BITMAP; ++#endif /* MAX_NUM_OF_MGT_BUF_BLOCKS */ ++ ++/* Control variable of TX management memory pool */ ++typedef struct _BUF_INFO_T { ++ PUINT_8 pucBuf; ++ ++#if CFG_DBG_MGT_BUF ++ UINT_32 u4AllocCount; ++ UINT_32 u4FreeCount; ++ UINT_32 u4AllocNullCount; ++#endif /* CFG_DBG_MGT_BUF */ ++ ++ BUF_BITMAP rFreeBlocksBitmap; ++ UINT_8 aucAllocatedBlockNum[MAX_NUM_OF_BUF_BLOCKS]; ++} BUF_INFO_T, *P_BUF_INFO_T; ++ ++/* Wi-Fi divides RAM into three types ++ * MSG: Mailbox message (Small size) ++ * BUF: HW DMA buffers (HIF/MAC) ++ */ ++typedef enum _ENUM_RAM_TYPE_T { ++ RAM_TYPE_MSG = 0, ++ RAM_TYPE_BUF ++} ENUM_RAM_TYPE_T, P_ENUM_RAM_TYPE_T; ++ ++typedef enum _ENUM_BUFFER_SOURCE_T { ++ BUFFER_SOURCE_HIF_TX0 = 0, ++ BUFFER_SOURCE_HIF_TX1, ++ BUFFER_SOURCE_MAC_RX, ++ BUFFER_SOURCE_MNG, ++ BUFFER_SOURCE_BCN, ++ BUFFER_SOURCE_NUM ++} ENUM_BUFFER_SOURCE_T, *P_ENUM_BUFFER_SOURCE_T; ++ ++typedef enum _ENUM_SEC_STATE_T { ++ SEC_STATE_INIT, ++ SEC_STATE_INITIATOR_PORT_BLOCKED, ++ SEC_STATE_RESPONDER_PORT_BLOCKED, ++ SEC_STATE_CHECK_OK, ++ SEC_STATE_SEND_EAPOL, ++ SEC_STATE_SEND_DEAUTH, ++ SEC_STATE_COUNTERMEASURE, ++ SEC_STATE_NUM ++} ENUM_SEC_STATE_T; ++ ++typedef struct _TSPEC_ENTRY_T { ++ UINT_8 ucStatus; ++ UINT_8 ucToken; /* Dialog Token in ADDTS_REQ or ADDTS_RSP */ ++ UINT_16 u2MediumTime; ++ UINT_32 u4TsInfo; ++ /* PARAM_QOS_TS_INFO rParamTsInfo; */ ++ /* Add other retained QoS parameters below */ ++} TSPEC_ENTRY_T, *P_TSPEC_ENTRY_T, TSPEC_TABLE_ENTRY_T, *P_TSPEC_TABLE_ENTRY_T; ++ ++typedef struct _SEC_INFO_T { ++ ++ ENUM_SEC_STATE_T ePreviousState; ++ ENUM_SEC_STATE_T eCurrentState; ++ ++ BOOLEAN fg2nd1xSend; ++ BOOLEAN fgKeyStored; ++ ++ UINT_8 aucStoredKey[64]; ++ ++ BOOLEAN fgAllowOnly1x; ++} SEC_INFO_T, *P_SEC_INFO_T; ++ ++#define MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS 3 ++ ++#define UPDATE_BSS_RSSI_INTERVAL_SEC 3 /* Seconds */ ++ ++/* Fragment information structure */ ++typedef struct _FRAG_INFO_T { ++ UINT_16 u2NextFragSeqCtrl; ++ PUINT_8 pucNextFragStart; ++ P_SW_RFB_T pr1stFrag; ++ OS_SYSTIME rReceiveLifetimeLimit; /* The receive time of 1st fragment */ ++} FRAG_INFO_T, *P_FRAG_INFO_T; ++ ++typedef struct _STAT_CNT_INFO_FW_T { ++ UINT32 u4NumOfTx; /* number of packets sent from host */ ++ UINT32 u4NumOfTxOK; /* number of packets sent to air OK */ ++ UINT32 u4NumOfTxRetry; /* number of packets sent to air RETRY */ ++ UINT32 u4TxDoneAirTimeMax; /* maximum tx done air time */ ++ ++ UINT32 u4NumOfPtiRspTxOk; /* number of PTI RSP sent to air OK */ ++ UINT32 u4NumOfPtiRspTxErr; /* number of PTI RSP sent to air ERROR */ ++ ++ UINT32 u4NumOfTxErr; /* number of packets sent to air ERROR */ ++ ++ UINT32 u4NumOfRx; /* number of received packets */ ++ UINT32 u4NumOfPtiRspRx; /* number of PTI RSP rcv */ ++ ++#define STAT_CNT_INFO_TX_ERR_FLUSHED 0x00000001 ++#define STAT_CNT_INFO_TX_ERR_AGE_TIMEOUT 0x00000002 ++#define STAT_CNT_INFO_TX_ERR_MPDU 0x00000004 ++#define STAT_CNT_INFO_TX_ERR_RTS 0x00000010 ++#define STAT_CNT_INFO_TX_ERR_LIFETIME 0x00000020 ++#define STAT_CNT_INFO_TX_ERR_UNKNOWN 0x80000000 ++ UINT32 u4TxErrBitmap; /* TX error type */ ++ ++#define STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM 10 /* TX OK history */ ++ UINT8 aucTxRateOkHis[STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM][2]; ++ UINT32 u4TxRateOkHisId; ++ ++#define STAT_CNT_INFO_MAX_RATE_ID (32) /* MCS0 ~ MCS31 */ ++ UINT32 aucTxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; ++ UINT32 aucRxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; ++ ++ UINT8 aucStateHis[100][3]; /* State history */ ++ UINT32 u4StateHisId; /* history ID */ ++} STAT_CNT_INFO_FW_T; ++ ++typedef struct _STAT_CNT_INFO_DRV_T { ++ ++ UINT32 u4NumOfTxFromOs; /* number of packets sent from OS */ ++ UINT32 u4NumOfTxQueFull; /* number of packets dropped due to queue full */ ++ UINT32 u4NumOfTxToFw; /* number of packets sent to firmware */ ++ ++ STAT_CNT_INFO_FW_T rFw; ++} STAT_CNT_INFO_DRV_T; ++ ++/* Define STA record structure */ ++struct _STA_RECORD_T { ++ LINK_ENTRY_T rLinkEntry; ++ UINT_8 ucIndex; /* Not modify it except initializing */ ++ ++ BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; /* MAC address */ ++ ++ /* SAA/AAA */ ++ ENUM_AA_STATE_T eAuthAssocState; /* Store STATE Value used in SAA/AAA */ ++ UINT_8 ucAuthAssocReqSeqNum; ++ ++ ENUM_STA_TYPE_T eStaType; /* Indicate the role of this STA in ++ * the network (for example, P2P GO) ++ */ ++ ++ UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ ++ ++ UINT_8 ucStaState; /* STATE_1,2,3 */ ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer ++ * (may deduced from received BSS_DESC_T) ++ */ ++ UINT_8 ucDesiredPhyTypeSet; /* The match result by AND operation of peer's ++ * PhyTypeSet and ours. ++ */ ++ BOOLEAN fgHasBasicPhyType; /* A flag to indicate a Basic Phy Type which ++ * is used to generate some Phy Attribute IE ++ * (e.g. capability, MIB) during association. ++ */ ++ UINT_8 ucNonHTBasicPhyType; /* The Basic Phy Type chosen among the ++ * ucDesiredPhyTypeSet. ++ */ ++ ++ UINT_16 u2CapInfo; /* For Infra Mode, to store Capability Info. from Association Resp(SAA). ++ * For AP Mode, to store Capability Info. from Association Req(AAA). ++ */ ++ UINT_16 u2AssocId; /* For Infra Mode, to store AID from Association Resp(SAA). ++ * For AP Mode, to store the Assigned AID(AAA). ++ */ ++ ++ UINT_16 u2ListenInterval; /* Listen Interval from STA(AAA) */ ++ ++ UINT_16 u2DesiredNonHTRateSet; /* Our Current Desired Rate Set after ++ * match with STA's Operational Rate Set ++ */ ++ ++ UINT_16 u2OperationalRateSet; /* Operational Rate Set of peer BSS */ ++ UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of peer BSS */ ++ ++ BOOLEAN fgIsMerging; /* For IBSS Mode, to indicate that Merge is ongoing */ ++ ++ BOOLEAN fgDiagnoseConnection; /* For Infra/AP Mode, to diagnose the Connection with ++ * this peer by sending ProbeReq/Null frame */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* 802.11n HT capabilities when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) is true */ ++ /* They have the same definition with fields of information element */ ++ /*------------------------------------------------------------------------------------------*/ ++ UINT_8 ucMcsSet; /* MCS0~7 rate set of peer BSS */ ++ BOOLEAN fgSupMcs32; /* MCS32 is supported by peer BSS */ ++ UINT_16 u2HtCapInfo; /* HT cap info field by HT cap IE */ ++ UINT_8 ucAmpduParam; /* Field A-MPDU Parameters in HT cap IE */ ++ UINT_16 u2HtExtendedCap; /* HT extended cap field by HT cap IE */ ++ UINT_32 u4TxBeamformingCap; /* TX beamforming cap field by HT cap IE */ ++ UINT_8 ucAselCap; /* ASEL cap field by HT cap IE */ ++ ++ UINT_8 ucRCPI; /* RCPI of peer */ ++ ++ UINT_8 ucDTIMPeriod; /* Target BSS's DTIM Period, we use this ++ * value for setup Listen Interval ++ * TODO(Kevin): TBD ++ */ ++ UINT_8 ucAuthAlgNum; /* For Infra/AP Mode, the Auth Algorithm Num used in Authentication(SAA/AAA) */ ++ BOOLEAN fgIsReAssoc; /* For Infra/AP Mode, to indicate ReAssoc Frame was in used(SAA/AAA) */ ++ ++ UINT_8 ucTxAuthAssocRetryCount; /* For Infra Mode, the Retry Count of TX Auth/Assod Frame(SAA) */ ++ UINT_8 ucTxAuthAssocRetryLimit; /* For Infra Mode, the Retry Limit of TX Auth/Assod Frame(SAA) */ ++ ++ UINT_16 u2StatusCode; /* Status of Auth/Assoc Req */ ++ UINT_16 u2ReasonCode; /* Reason that been Deauth/Disassoc */ ++ ++ P_IE_CHALLENGE_TEXT_T prChallengeText; /* Point to an allocated buffer for storing Challenge Text ++ * for Shared Key Authentication ++ */ ++ ++ TIMER_T rTxReqDoneOrRxRespTimer; /* For Infra Mode, a timer used to send a timeout event ++ * while waiting for TX request done or RX response. ++ */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* Power Management related fields (for STA/ AP/ P2P/ BOW power saving mode) */ ++ /*------------------------------------------------------------------------------------------*/ ++ BOOLEAN fgSetPwrMgtBit; /* For Infra Mode, to indicate that outgoing frame need toggle ++ * the Pwr Mgt Bit in its Frame Control Field. ++ */ ++ ++ BOOLEAN fgIsInPS; /* For AP Mode, to indicate the client PS state(PM). ++ * TRUE: In PS Mode; FALSE: In Active Mode. */ ++ ++ BOOLEAN fgIsInPsPollSP; /* For Infra Mode, to indicate we've sent a PS POLL to AP and start ++ * the PS_POLL Service Period(LP) ++ */ ++ ++ BOOLEAN fgIsInTriggerSP; /* For Infra Mode, to indicate we've sent a Trigger Frame to AP and start ++ * the Delivery Service Period(LP) ++ */ ++ ++ UINT_8 ucBmpDeliveryAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ ++ ++ UINT_8 ucBmpTriggerAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ ++ ++ UINT_8 ucUapsdSp; /* Max SP length */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ ++ BOOLEAN fgIsRtsEnabled; ++ ++ OS_SYSTIME rUpdateTime; /* (4) System Timestamp of Successful TX and RX */ ++ ++ OS_SYSTIME rLastJoinTime; /* (4) System Timestamp of latest JOIN process */ ++ ++ UINT_8 ucJoinFailureCount; /* Retry Count of JOIN process */ ++ ++ LINK_T arStaWaitQueue[STA_WAIT_QUEUE_NUM]; /* For TXM to defer pkt forwarding to MAC TX DMA */ ++ ++ UINT_16 au2CachedSeqCtrl[TID_NUM + 1]; /* Duplicate removal for HT STA on a per-TID basis ++ * ("+1" is for MMPDU and non-QoS) ++ */ ++ ++#if 0 ++ /* RXM */ ++ P_RX_BA_ENTRY_T aprRxBaTable[TID_NUM]; ++ ++ /* TXM */ ++ P_TX_BA_ENTRY_T aprTxBaTable[TID_NUM]; ++#endif ++ ++ FRAG_INFO_T rFragInfo[MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS]; ++ ++ SEC_INFO_T rSecInfo; /* The security state machine */ ++ ++ BOOLEAN fgPortBlock; /* The 802.1x Port Control flag */ ++ ++ BOOLEAN fgTransmitKeyExist; /* Unicast key exist for this STA */ ++ ++ UINT_8 ucWTEntry; ++ ++ BOOLEAN fgTxAmpduEn; /* Enable TX AMPDU for this Peer */ ++ BOOLEAN fgRxAmpduEn; /* Enable RX AMPDU for this Peer */ ++ ++ PUINT_8 pucAssocReqIe; ++ UINT_16 u2AssocReqIeLen; ++ /*------------------------------------------------------------------------------------------*/ ++ /* WMM/QoS related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++ BOOLEAN fgIsQoS; /* If the STA is associated as a QSTA or QAP (for TX/RX) */ ++ BOOLEAN fgIsWmmSupported; /* If the peer supports WMM, set to TRUE (for association) */ ++ BOOLEAN fgIsUapsdSupported; /* Set according to the scan result (for association) */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* P2P related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 u2DevNameLen; ++ UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; ++ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ ++ UINT_16 u2ConfigMethods; ++ ++ UINT_8 ucDeviceCap; ++ ++ UINT_8 ucSecondaryDevTypeCount; ++ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; ++ ++ DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT]; ++#endif /* CFG_SUPPORT_P2P */ ++ ++ /*------------------------------------------------------------------------------------------*/ ++ /* QM related fields */ ++ /*------------------------------------------------------------------------------------------*/ ++ ++ UINT_8 ucFreeQuota; /* Per Sta flow controal. Valid when fgIsInPS is TRUE. ++ Change it for per Queue flow control */ ++ /* UINT_8 aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]; */ /* used in future */ ++ UINT_8 ucFreeQuotaForDelivery; ++ UINT_8 ucFreeQuotaForNonDelivery; ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE && CFG_ENABLE_PER_STA_STATISTICS ++ UINT_32 u4TotalTxPktsNumber; ++ UINT_32 u4TotalTxPktsTime; ++ UINT_32 u4TotalTxPktsHifTime; ++ ++ UINT_32 u4MaxTxPktsTime; ++ UINT_32 u4MaxTxPktsHifTime; ++ ++ UINT_32 u4ThresholdCounter; ++ UINT_32 u4EnqeueuCounter; ++ UINT_32 u4DeqeueuCounter; ++ UINT_32 u4PrevIntCount; ++ UINT_32 u4ThisIntCount; ++ UINT_32 u4NoTcResource; ++#endif ++ ++#if 1 ++ /*------------------------------------------------------------------------------------------*/ ++ /* To be removed, this is to make que_mgt compilation success only */ ++ /*------------------------------------------------------------------------------------------*/ ++ /* When this STA_REC is in use, set to TRUE. */ ++ BOOLEAN fgIsValid; ++ ++ /* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ ++ QUE_T arTxQueue[NUM_OF_PER_STA_TX_QUEUES]; ++ ++ /* When this STA is in PS Mode, set to TRUE. */ ++ /* BOOLEAN fgIsPS; */ ++ ++ /* When this STA enters Power-Saving, FW will notify the driver with a Session ID */ ++ UINT_8 ucPsSessionID; ++ ++ BOOLEAN fgIsAp; ++ ++ /* Reorder Parameter reference table */ ++ P_RX_BA_ENTRY_T aprRxReorderParamRefTbl[CFG_RX_MAX_BA_TID_NUM]; ++#endif ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ TIMINGMSMT_PARAM_T rWNMTimingMsmt; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ ++ BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ ++ ++ BOOLEAN flgTdlsIsInitiator; /* TRUE: the peer is the initiator */ ++ IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ ++ BOOLEAN fgTdlsInSecurityMode; /* TRUE: security mode */ ++ PARAM_KEY_T rTdlsKeyTemp; /* temp to queue the key information */ ++ ++#define TDLS_SETUP_TIMEOUT_SEC 5 /* unit: second */ ++ OS_SYSTIME rTdlsSetupStartTime; /* time when link setup is started */ ++ ++ OS_SYSTIME rTdlsTxQuotaEmptyTime; /* time when TX quota is 0 */ ++ ++ STAT_CNT_INFO_DRV_T rTdlsStatistics; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++#define STATS_ENV_TIMEOUT_SEC 10 /* unit: second */ ++ OS_SYSTIME rStatsEnvTxPeriodLastTime; ++ ++#define STATS_ENV_TX_CNT_REPORT_TRIGGER 2500 /* 6Mbps */ ++#define STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC 5 /* unit: second */ ++ OS_SYSTIME rStatsEnvTxLastTime; ++ UINT32 u4StatsEnvTxCnt; ++ ++ UINT32 u4NumOfNoTxQuota; ++ ++ UINT32 u4RxReorderFallAheadCnt; ++ UINT32 u4RxReorderFallBehindCnt; ++ UINT32 u4RxReorderHoleCnt; ++ UINT32 u4RxReorderHoleTimeoutCnt; ++ ++ UINT32 u4StatsRxPassToOsCnt; ++ ++ /* delay from HIF to pass to OS: us */ ++#define STATS_STAY_INT_BYTE_THRESHOLD 500 ++ UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; ++ ++ UINT8 ucStatsGenDisplayCnt; ++#endif /* CFG_SUPPORT_STATISTICS */ ++}; ++ ++#if 0 ++/* use nic_tx.h instead */ ++/* MSDU_INFO and SW_RFB structure */ ++typedef struct _MSDU_INFO_T { ++ ++ /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ ++ ++ LINK_ENTRY_T rLinkEntry; ++ PUINT_8 pucBuffer; /* Pointer to the associated buffer */ ++ ++ UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ ++ UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ ++ UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ ++ UINT_8 ucTID; /* Traffic Identification */ ++ ++ BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ ++ UINT_8 ucMacHeaderLength; ++ UINT_16 u2PayloadLength; ++ PUINT_8 pucMacHeader; /* 802.11 header */ ++ PUINT_8 pucPayload; /* 802.11 payload */ ++ ++ OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ ++ P_STA_RECORD_T prStaRec; ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; ++ UINT_32 rActivityTime[2]; ++#endif ++#if DBG && CFG_BUFFER_FREE_CHK ++ BOOLEAN fgBufferInSource; ++#endif ++ ++ UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ ++ ++ /* 4 -----------------------Non-Common ------------------------- */ ++ /* TODO: move flags to ucControlFlag */ ++ ++ BOOLEAN fgIs1xFrame; /* Set to TRUE for 802.1x frame */ ++ ++ /* TXM: For TX Done handling, callback function & parameter (5) */ ++ BOOLEAN fgIsTxFailed; /* Set to TRUE if transmission failure */ ++ ++ PFN_TX_DONE_HANDLER pfTxDoneHandler; ++ ++ UINT_64 u8TimeStamp; /* record the TX timestamp */ ++ ++ /* TXM: For PS forwarding control (per-STA flow control) */ ++ UINT_8 ucPsForwardingType; /* Delivery-enabled, non-delivery-enabled, non-PS */ ++ UINT_8 ucPsSessionID; /* The Power Save session id for PS forwarding control */ ++ ++ /* TXM: For MAC TX DMA operations */ ++ UINT_8 ucMacTxQueIdx; /* MAC TX queue: AC0-AC6, BCM, or BCN */ ++ BOOLEAN fgNoAck; /* Set to true if Ack is not required for this packet */ ++ BOOLEAN fgBIP; /* Set to true if BIP is used for this packet */ ++ UINT_8 ucFragTotalCount; ++ UINT_8 ucFragFinishedCount; ++ UINT_16 u2FragThreshold; /* Fragmentation threshold without WLAN Header & FCS */ ++ BOOLEAN fgFixedRate; /* If a fixed rate is used, set to TRUE. */ ++ UINT_8 ucFixedRateCode; /* The rate code copied to MAC TX Desc */ ++ UINT_8 ucFixedRateRetryLimit; /* The retry limit when a fixed rate is used */ ++ BOOLEAN fgIsBmcQueueEnd; /* Set to true if this packet is the end of BMC */ ++ ++ /* TXM: For flushing ACL frames */ ++ UINT_16 u2PalLLH; /* 802.11 PAL LLH */ ++ /* UINT_16 u2LLH; */ ++ UINT_16 u2ACLSeq; /* u2LLH+u2ACLSeq for AM HCI flush ACL frame */ ++ ++ /* TXM for retransmitting a flushed packet */ ++ BOOLEAN fgIsSnAssigned; ++ UINT_16 u2SequenceNumber; /* To remember the Sequence Control field of this MPDU */ ++ ++} MSDU_INFO_T, *P_MSDU_INFO_T; ++#endif ++ ++#if 0 ++/* nic_rx.h */ ++typedef struct _SW_RFB_T { ++ ++ /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ ++ ++ LINK_ENTRY_T rLinkEntry; ++ PUINT_8 pucBuffer; /* Pointer to the associated buffer */ ++ ++ UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ ++ UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ ++ UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ ++ UINT_8 ucTID; /* Traffic Identification */ ++ ++ BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ ++ UINT_8 ucMacHeaderLength; ++ UINT_16 u2PayloadLength; ++ PUINT_8 pucMacHeader; /* 802.11 header */ ++ PUINT_8 pucPayload; /* 802.11 payload */ ++ ++ OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ ++ P_STA_RECORD_T prStaRec; ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; ++ UINT_32 rActivityTime[2]; ++#endif ++#if DBG && CFG_BUFFER_FREE_CHK ++ BOOLEAN fgBufferInSource; ++#endif ++ ++ UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ ++ ++ /* 4 -----------------------Non-Common ------------------------- */ ++ ++ /* For composing the HIF RX Header (TODO: move flags to ucControlFlag) */ ++ PUINT_8 pucHifRxPacket; /* Pointer to the Response packet to HIF RX0 or RX1 */ ++ UINT_16 u2HifRxPacketLength; ++ UINT_8 ucHeaderOffset; ++ UINT_8 ucHifRxPortIndex; ++ ++ UINT_16 u2SequenceControl; ++ BOOLEAN fgIsA4Frame; /* (For MAC RX packet parsing) set to TRUE if 4 addresses are present */ ++ BOOLEAN fgIsBAR; ++ BOOLEAN fgIsQoSData; ++ BOOLEAN fgIsAmsduSubframe; /* Set to TRUE for A-MSDU Subframe */ ++ ++ /* For HIF RX DMA Desc */ ++ BOOLEAN fgTUChecksumCheckRequired; ++ BOOLEAN fgIPChecksumCheckRequired; ++ UINT_8 ucEtherTypeOffset; ++ ++} SW_RFB_T, *P_SW_RFB_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++P_MSDU_INFO_T cnmMgtPktAlloc(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); ++ ++VOID cnmMgtPktFree(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID cnmMemInit(IN P_ADAPTER_T prAdapter); ++ ++PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length); ++ ++VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory); ++ ++VOID cnmStaRecInit(IN P_ADAPTER_T prAdapter); ++ ++VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter); ++ ++P_STA_RECORD_T cnmStaRecAlloc(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex); ++ ++VOID cnmStaRecFree(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSyncToChip); ++ ++VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip); ++ ++P_STA_RECORD_T cnmGetStaRecByIndex(IN P_ADAPTER_T prAdapter, IN UINT_8 ucIndex); ++ ++P_STA_RECORD_T cnmGetStaRecByAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex, IN UINT_8 aucPeerMACAddress[]); ++ ++VOID cnmStaRecResetStatus(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++VOID cnmStaRecChangeState(IN P_ADAPTER_T prAdapter, IN OUT P_STA_RECORD_T prStaRec, IN UINT_8 ucNewState); ++ ++P_STA_RECORD_T ++cnmStaTheTypeGet(P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID cnmMemDataTypeCheck(VOID) ++{ ++#if 0 ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == 0); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == OFFSET_OF(SW_RFB_T, rLinkEntry)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucBuffer) == OFFSET_OF(SW_RFB_T, pucBuffer)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucBufferSource) == OFFSET_OF(SW_RFB_T, ucBufferSource)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucMacHeader) == OFFSET_OF(SW_RFB_T, pucMacHeader)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucMacHeaderLength) == ++ OFFSET_OF(SW_RFB_T, ucMacHeaderLength)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucPayload) == OFFSET_OF(SW_RFB_T, pucPayload)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, u2PayloadLength) == OFFSET_OF(SW_RFB_T, u2PayloadLength)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, prStaRec) == OFFSET_OF(SW_RFB_T, prStaRec)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucNetworkTypeIndex) == ++ OFFSET_OF(SW_RFB_T, ucNetworkTypeIndex)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTID) == OFFSET_OF(SW_RFB_T, ucTID)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgIs802_11Frame) == OFFSET_OF(SW_RFB_T, fgIs802_11Frame)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucControlFlag) == OFFSET_OF(SW_RFB_T, ucControlFlag)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rArrivalTime) == OFFSET_OF(SW_RFB_T, rArrivalTime)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTC) == OFFSET_OF(SW_RFB_T, ucTC)); ++ ++#if CFG_PROFILE_BUFFER_TRACING ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, eActivity[0]) == OFFSET_OF(SW_RFB_T, eActivity[0])); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rActivityTime[0]) == ++ OFFSET_OF(SW_RFB_T, rActivityTime[0])); ++#endif ++ ++#if DBG && CFG_BUFFER_FREE_CHK ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgBufferInSource) == ++ OFFSET_OF(SW_RFB_T, fgBufferInSource)); ++#endif ++ ++ DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(STA_RECORD_T, rLinkEntry) == 0); ++ ++ return; ++#endif ++} ++#endif /* _lint */ ++ ++#endif /* _CNM_MEM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h +new file mode 100644 +index 000000000000..cc5d0fa1adfc +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h +@@ -0,0 +1,169 @@ ++/* ++** Id: @(#) ++*/ ++ ++/*! \file "cnm_scan.h" ++ \brief ++ ++*/ ++ ++/* ++** Log: cnm_scan.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * remove unused definitions. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function prototype of cnmScanInit() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_SCAN_H ++#define _CNM_SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define SCN_CHANNEL_DWELL_TIME_MIN_MSEC 12 ++#define SCN_CHANNEL_DWELL_TIME_EXT_MSEC 98 ++ ++#define SCN_TOTAL_PROBEREQ_NUM_FOR_FULL 3 ++#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_FULL 1 ++ ++#define SCN_TOTAL_PROBEREQ_NUM_FOR_PARTIAL 2 ++#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_PARTIAL 1 ++ ++#define SCN_INTERLACED_CHANNEL_GROUPS_NUM 3 /* Used by partial scan */ ++ ++#define SCN_PARTIAL_SCAN_NUM 3 ++ ++#define SCN_PARTIAL_SCAN_IDLE_MSEC 100 ++ ++#define MAXIMUM_OPERATION_CHANNEL_LIST 46 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* The type of Scan Source */ ++typedef enum _ENUM_SCN_REQ_SOURCE_T { ++ SCN_REQ_SOURCE_HEM = 0, ++ SCN_REQ_SOURCE_NET_FSM, ++ SCN_REQ_SOURCE_ROAMING, /* ROAMING Module is independent of AIS FSM */ ++ SCN_REQ_SOURCE_OBSS, /* 2.4G OBSS scan */ ++ SCN_REQ_SOURCE_NUM ++} ENUM_SCN_REQ_SOURCE_T, *P_ENUM_SCN_REQ_SOURCE_T; ++ ++typedef enum _ENUM_SCAN_PROFILE_T { ++ SCAN_PROFILE_FULL = 0, ++ SCAN_PROFILE_PARTIAL, ++ SCAN_PROFILE_VOIP, ++ SCAN_PROFILE_FULL_2G4, ++ SCAN_PROFILE_NUM ++} ENUM_SCAN_PROFILE_T, *P_ENUM_SCAN_PROFILE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 ++VOID cnmScanInit(VOID); ++ ++VOID cnmScanRunEventScanRequest(IN P_MSG_HDR_T prMsgHdr); ++ ++BOOLEAN cnmScanRunEventScanAbort(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanProfileSelection(VOID); ++ ++VOID cnmScanProcessStart(VOID); ++ ++VOID cnmScanProcessStop(VOID); ++ ++VOID cnmScanRunEventReqAISAbsDone(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanRunEventCancelAISAbsDone(IN P_MSG_HDR_T prMsgHdr); ++ ++VOID cnmScanPartialScanTimeout(UINT_32 u4Param); ++ ++VOID cnmScanRunEventScnFsmComplete(IN P_MSG_HDR_T prMsgHdr); ++#endif ++ ++#endif /* _CNM_SCAN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h +new file mode 100644 +index 000000000000..a2ed9cd02fed +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h +@@ -0,0 +1,235 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_timer.h#1 ++*/ ++ ++/*! \file cnm_timer.h ++ \brief Declaration of timer obj and related timer macro for setup time out ++ event. ++ ++ In this file we declare the timer object and provide several macro for ++ Protocol functional blocks to setup their own time out event. ++*/ ++ ++/* ++** Log: cnm_timer.h ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Return timer token back to COS when entering wait off state ++ * ++ * 01 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 01 06 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix system time is 32KHz instead of 1ms ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * add the copy time function ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix LINT warnning ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++#ifndef _CNM_TIMER_H ++#define _CNM_TIMER_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#undef MSEC_PER_SEC ++#define MSEC_PER_SEC 1000 ++#undef USEC_PER_MSEC ++#define USEC_PER_MSEC 1000 ++#define USEC_PER_TU 1024 /* microsecond */ ++ ++#define MSEC_PER_MIN (60 * MSEC_PER_SEC) ++ ++#define MGMT_MAX_TIMEOUT_INTERVAL ((UINT_32)0x7fffffff) ++ ++#define WAKE_LOCK_MAX_TIME 5 /* Unit: sec */ ++ ++/* If WAKE_LOCK_MAX_TIME is too large, the whole system may always keep awake ++ * because of periodic timer of OBSS scanning ++ */ ++#if (WAKE_LOCK_MAX_TIME >= OBSS_SCAN_MIN_INTERVAL) ++#error WAKE_LOCK_MAX_TIME is too large ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef VOID(*PFN_MGMT_TIMEOUT_FUNC) (P_ADAPTER_T, ULONG); ++ ++typedef struct _TIMER_T { ++ LINK_ENTRY_T rLinkEntry; ++ OS_SYSTIME rExpiredSysTime; ++ UINT_16 u2Minutes; ++ UINT_16 u2Reserved; ++ ULONG ulData; ++ PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; ++} TIMER_T, *P_TIMER_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Check if time "a" is before time "b" */ ++/* In 32-bit variable, 0x00000001~0x7fffffff -> positive number, ++ * 0x80000000~0xffffffff -> negative number ++ */ ++#define TIME_BEFORE_64bit(a, b) (a < b) ++ ++#define TIME_BEFORE(a, b) ((UINT_32)((UINT_32)(a) - (UINT_32)(b)) > 0x7fffffff) ++ ++/* #define TIME_BEFORE(a,b) ((INT_32)((INT_32)(b) - (INT_32)(a)) > 0) ++ * may cause UNexpect result between Free build and Check build for WinCE ++ */ ++ ++#define TIME_AFTER(a, b) TIME_BEFORE(b, a) ++ ++#define SYSTIME_TO_SEC(_systime) ((_systime) / KAL_HZ) ++#define SEC_TO_SYSTIME(_sec) ((_sec) * KAL_HZ) ++ ++/* The macros to convert second & millisecond */ ++#define MSEC_TO_SEC(_msec) ((_msec) / MSEC_PER_SEC) ++#define SEC_TO_MSEC(_sec) ((UINT_32)(_sec) * MSEC_PER_SEC) ++ ++/* The macros to convert millisecond & microsecond */ ++#define USEC_TO_MSEC(_usec) ((_usec) / USEC_PER_MSEC) ++#define MSEC_TO_USEC(_msec) ((UINT_32)(_msec) * USEC_PER_MSEC) ++ ++/* The macros to convert TU & microsecond, TU & millisecond */ ++#define TU_TO_USEC(_tu) ((_tu) * USEC_PER_TU) ++#define TU_TO_MSEC(_tu) USEC_TO_MSEC(TU_TO_USEC(_tu)) ++ ++/* The macros to convert TU & & OS system time, round up by 0.5 */ ++#define TU_TO_SYSTIME(_tu) MSEC_TO_SYSTIME(TU_TO_MSEC(_tu)) ++#define SYSTIME_TO_TU(_systime) \ ++ ((SYSTIME_TO_USEC(_systime) + ((USEC_PER_TU / 2) - 1)) / USEC_PER_TU) ++ ++/* The macros to convert OS system time & microsecond */ ++#define SYSTIME_TO_USEC(_systime) (SYSTIME_TO_MSEC(_systime) * USEC_PER_MSEC) ++ ++/* The macro to get the current OS system time */ ++#define GET_CURRENT_SYSTIME(_systime_p) {*(_systime_p) = kalGetTimeTick(); } ++ ++/* The macro to copy the system time */ ++#define COPY_SYSTIME(_destTime, _srcTime) {(_destTime) = (_srcTime); } ++ ++/* The macro to get the system time difference between t1 and t2 (t1 - t2) */ ++/* #define GET_SYSTIME_DIFFERENCE(_time1, _time2, _diffTime) \ ++ (_diffTime) = (_time1) - (_time2) */ ++ ++/* The macro to check for the expiration, if TRUE means _currentTime >= _expirationTime */ ++#define CHECK_FOR_EXPIRATION(_currentTime, _expirationTime) \ ++ (((UINT_32)(_currentTime) - (UINT_32)(_expirationTime)) <= 0x7fffffffUL) ++ ++/* The macro to check for the timeout */ ++#define CHECK_FOR_TIMEOUT(_currentTime, _timeoutStartingTime, _timeout) \ ++ CHECK_FOR_EXPIRATION((_currentTime), ((_timeoutStartingTime) + (_timeout))) ++ ++/* The macro to set the expiration time with a specified timeout *//* Watch out for round up. */ ++#define SET_EXPIRATION_TIME(_expirationTime, _timeout) \ ++ { \ ++ GET_CURRENT_SYSTIME(&(_expirationTime)); \ ++ (_expirationTime) += (OS_SYSTIME)(_timeout); \ ++ } ++ ++#define timerRenewTimer(adapter, tmr, interval) \ ++ timerStartTimer(adapter, tmr, interval, (tmr)->function, (tmr)->data) ++ ++#define MGMT_INIT_TIMER(_adapter_p, _timer, _callbackFunc) \ ++ timerInitTimer(_adapter_p, &(_timer), (ULONG)(_callbackFunc)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID ++cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData); ++ ++VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer); ++ ++VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs); ++ ++VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++static inline INT_32 timerPendingTimer(IN P_TIMER_T prTimer) ++{ ++ ASSERT(prTimer); ++ ++ return prTimer->rLinkEntry.prNext != NULL; ++} ++ ++#endif /* _CNM_TIMER_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h +new file mode 100644 +index 000000000000..868de4a6c40a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h +@@ -0,0 +1,446 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/hem_mbox.h#2 ++*/ ++ ++/*! \file hem_mbox.h ++ \brief ++ ++*/ ++ ++/* ++** Log: hem_mbox.h ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for ++ * more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. ++ * cnm_timer[WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add invitation support. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Remove unused message ID ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some message ID for P2P FSM under provisioning phase. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add Message Event ID for P2P Module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * remove unused mailbox message definitions. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * message table should not be commented out by compilation option without modifying header file ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Develop partial DPD code ++ * ++ * 02 11 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added MID_RXM_MQM_QOS_ACTION_FRAME for RXM to indicate QoS Action frames to MQM ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename the parameter of mboxDummy() ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove Dummy MSG ID ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add JOIN REQ related MSG ID ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add AIS ABORT MSG ID ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add SCN MSG IDs ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _HEM_MBOX_H ++#define _HEM_MBOX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Message IDs */ ++typedef enum _ENUM_MSG_ID_T { ++ MID_MNY_CNM_CH_REQ, /* MANY notify CNM to obtain channel privilege */ ++ MID_MNY_CNM_CH_ABORT, /* MANY notify CNM to abort/release channel privilege */ ++ ++ MID_CNM_AIS_CH_GRANT, /* CNM notify AIS for indicating channel granted */ ++ MID_CNM_P2P_CH_GRANT, /* CNM notify P2P for indicating channel granted */ ++ MID_CNM_BOW_CH_GRANT, /* CNM notify BOW for indicating channel granted */ ++ ++ /*--------------------------------------------------*/ ++ /* SCN Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_AIS_SCN_SCAN_REQ, /* AIS notify SCN for starting scan */ ++ MID_AIS_SCN_SCAN_REQ_V2, /* AIS notify SCN for starting scan with multiple SSID support */ ++ MID_AIS_SCN_SCAN_CANCEL, /* AIS notify SCN for cancelling scan */ ++ MID_P2P_SCN_SCAN_REQ, /* P2P notify SCN for starting scan */ ++ MID_P2P_SCN_SCAN_REQ_V2, /* P2P notify SCN for starting scan with multiple SSID support */ ++ MID_P2P_SCN_SCAN_CANCEL, /* P2P notify SCN for cancelling scan */ ++ MID_BOW_SCN_SCAN_REQ, /* BOW notify SCN for starting scan */ ++ MID_BOW_SCN_SCAN_REQ_V2, /* BOW notify SCN for starting scan with multiple SSID support */ ++ MID_BOW_SCN_SCAN_CANCEL, /* BOW notify SCN for cancelling scan */ ++ MID_RLM_SCN_SCAN_REQ, /* RLM notify SCN for starting scan (OBSS-SCAN) */ ++ MID_RLM_SCN_SCAN_REQ_V2, /* RLM notify SCN for starting scan (OBSS-SCAN) with multiple SSID support */ ++ MID_RLM_SCN_SCAN_CANCEL, /* RLM notify SCN for cancelling scan (OBSS-SCAN) */ ++ MID_SCN_AIS_SCAN_DONE, /* SCN notify AIS for scan completion */ ++ MID_SCN_P2P_SCAN_DONE, /* SCN notify P2P for scan completion */ ++ MID_SCN_BOW_SCAN_DONE, /* SCN notify BOW for scan completion */ ++ MID_SCN_RLM_SCAN_DONE, /* SCN notify RLM for scan completion (OBSS-SCAN) */ ++ ++ /*--------------------------------------------------*/ ++ /* AIS Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_OID_AIS_FSM_JOIN_REQ, /* OID/IOCTL notify AIS for join */ ++ MID_OID_AIS_FSM_ABORT, /* OID/IOCTL notify AIS for abort */ ++ MID_AIS_SAA_FSM_START, /* AIS notify SAA for Starting authentication/association fsm */ ++ MID_AIS_SAA_FSM_ABORT, /* AIS notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_AIS_JOIN_COMPLETE, /* SAA notify AIS for indicating join complete */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /*--------------------------------------------------*/ ++ /* BOW Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_BOW_SAA_FSM_START, /* BOW notify SAA for Starting authentication/association fsm */ ++ MID_BOW_SAA_FSM_ABORT, /* BOW notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_BOW_JOIN_COMPLETE, /* SAA notify BOW for indicating join complete */ ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*--------------------------------------------------*/ ++ /* P2P Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ MID_P2P_SAA_FSM_START, /* P2P notify SAA for Starting authentication/association fsm */ ++ MID_P2P_SAA_FSM_ABORT, /* P2P notify SAA for Aborting authentication/association fsm */ ++ MID_SAA_P2P_JOIN_COMPLETE, /* SAA notify P2P for indicating join complete */ ++ ++ MID_MNY_P2P_FUN_SWITCH, /* Enable P2P FSM. */ ++ MID_MNY_P2P_DEVICE_DISCOVERY, /* Start device discovery. */ ++ MID_MNY_P2P_CONNECTION_REQ, /* Connection request. */ ++ MID_MNY_P2P_CONNECTION_ABORT, /* Abort connection request, P2P FSM return to IDLE. */ ++ MID_MNY_P2P_BEACON_UPDATE, ++ MID_MNY_P2P_STOP_AP, ++ MID_MNY_P2P_CHNL_REQ, ++ MID_MNY_P2P_CHNL_ABORT, ++ MID_MNY_P2P_MGMT_TX, ++ MID_MNY_P2P_GROUP_DISSOLVE, ++ MID_MNY_P2P_MGMT_FRAME_REGISTER, ++ MID_MNY_P2P_NET_DEV_REGISTER, ++ MID_MNY_P2P_START_AP, ++ MID_MNY_P2P_MGMT_FRAME_UPDATE, ++ MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, ++#if CFG_SUPPORT_WFD ++ MID_MNY_P2P_WFD_CFG_UPDATE, ++#endif ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ MID_SCN_AIS_FOUND_IBSS, /* SCN notify AIS that an IBSS Peer has been found and can merge into */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ MID_SAA_AIS_FSM_ABORT, /* SAA notify AIS for indicating deauthentication/disassociation */ ++ ++ /*--------------------------------------------------*/ ++ /* AIS MGMT-TX Support */ ++ /*--------------------------------------------------*/ ++ MID_MNY_AIS_REMAIN_ON_CHANNEL, ++ MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, ++ MID_MNY_AIS_MGMT_TX, ++ ++ MID_TOTAL_NUM ++} ENUM_MSG_ID_T, *P_ENUM_MSG_ID_T; ++ ++/* Message header of inter-components */ ++struct _MSG_HDR_T { ++ LINK_ENTRY_T rLinkEntry; ++ ENUM_MSG_ID_T eMsgId; ++}; ++ ++typedef VOID(*PFN_MSG_HNDL_FUNC) (P_ADAPTER_T, P_MSG_HDR_T); ++ ++typedef struct _MSG_HNDL_ENTRY { ++ ENUM_MSG_ID_T eMsgId; ++ PFN_MSG_HNDL_FUNC pfMsgHndl; ++} MSG_HNDL_ENTRY_T, *P_MSG_HNDL_ENTRY_T; ++ ++typedef enum _EUNM_MSG_SEND_METHOD_T { ++ MSG_SEND_METHOD_BUF = 0, /* Message is put in the queue and will be ++ executed when mailbox is checked. */ ++ MSG_SEND_METHOD_UNBUF /* The handler function is called immediately ++ in the same context of the sender */ ++} EUNM_MSG_SEND_METHOD_T, *P_EUNM_MSG_SEND_METHOD_T; ++ ++typedef enum _ENUM_MBOX_ID_T { ++ MBOX_ID_0 = 0, ++ MBOX_ID_TOTAL_NUM ++} ENUM_MBOX_ID_T, *P_ENUM_MBOX_ID_T; ++ ++/* Define Mailbox structure */ ++typedef struct _MBOX_T { ++ LINK_T rLinkHead; ++} MBOX_T, *P_MBOX_T; ++ ++typedef struct _MSG_SAA_FSM_START_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ P_STA_RECORD_T prStaRec; ++} MSG_SAA_FSM_START_T, *P_MSG_SAA_FSM_START_T; ++ ++typedef struct _MSG_SAA_FSM_COMP_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ WLAN_STATUS rJoinStatus; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prSwRfb; ++} MSG_SAA_FSM_COMP_T, *P_MSG_SAA_FSM_COMP_T; ++ ++typedef struct _MSG_SAA_FSM_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ P_STA_RECORD_T prStaRec; ++} MSG_SAA_FSM_ABORT_T, *P_MSG_SAA_FSM_ABORT_T; ++ ++typedef struct _MSG_CONNECTION_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucNetTypeIndex; ++} MSG_CONNECTION_ABORT_T, *P_MSG_CONNECTION_ABORT_T; ++ ++typedef struct _MSG_REMAIN_ON_CHANNEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eSco; ++ UINT_8 ucChannelNum; ++ UINT_32 u4DurationMs; ++ UINT_64 u8Cookie; ++} MSG_REMAIN_ON_CHANNEL_T, *P_MSG_REMAIN_ON_CHANNEL_T; ++ ++typedef struct _MSG_CANCEL_REMAIN_ON_CHANNEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++} MSG_CANCEL_REMAIN_ON_CHANNEL_T, *P_MSG_CANCEL_REMAIN_ON_CHANNEL_T; ++ ++typedef struct _MSG_MGMT_TX_REQUEST_T { ++ MSG_HDR_T rMsgHdr; ++ P_MSDU_INFO_T prMgmtMsduInfo; ++ UINT_64 u8Cookie; /* For indication. */ ++ BOOLEAN fgNoneCckRate; ++ BOOLEAN fgIsWaitRsp; ++} MSG_MGMT_TX_REQUEST_T, *P_MSG_MGMT_TX_REQUEST_T; ++ ++/* specific message data types */ ++typedef MSG_SAA_FSM_START_T MSG_JOIN_REQ_T, *P_MSG_JOIN_REQ_T; ++typedef MSG_SAA_FSM_COMP_T MSG_JOIN_COMP_T, *P_MSG_JOIN_COMP_T; ++typedef MSG_SAA_FSM_ABORT_T MSG_JOIN_ABORT_T, *P_MSG_JOIN_ABORT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); ++ ++VOID ++mboxSendMsg(IN P_ADAPTER_T prAdapter, ++ IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod); ++ ++VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); ++ ++VOID mboxInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID mboxDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID mboxDummy(IN P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _HEM_MBOX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h +new file mode 100644 +index 000000000000..88b99222133f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h +@@ -0,0 +1,148 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/include/mgmt/hs20.h#2 ++*/ ++ ++/*! \file hs20.h ++ \brief This file contains the function declaration for hs20.c. ++*/ ++ ++/* ++** Log: ++ * ++ */ ++ ++#ifndef _HS20_H ++#define _HS20_H ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BSSID_POOL_MAX_SIZE 8 ++#define HS20_SIGMA_SCAN_RESULT_TIMEOUT 30 /* sec */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++/*For GTK Frame Filter*/ ++typedef struct _IPV4_NETWORK_ADDRESS_LIST { ++ UINT_8 ucAddrCount; ++ IPV4_NETWORK_ADDRESS arNetAddr[1]; ++} IPV4_NETWORK_ADDRESS_LIST, *P_IPV4_NETWORK_ADDRESS_LIST; ++#endif ++ ++/* Entry of BSSID Pool - For SIGMA Test */ ++typedef struct _BSSID_ENTRY_T { ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++} BSSID_ENTRY_T, P_HS20_BSSID_POOL_ENTRY_T; ++ ++struct _HS20_INFO_T { ++ ++ /*Hotspot 2.0 Information */ ++ UINT_8 aucHESSID[MAC_ADDR_LEN]; ++ UINT_8 ucAccessNetworkOptions; ++ UINT_8 ucVenueGroup; /* VenueInfo - Group */ ++ UINT_8 ucVenueType; ++ UINT_8 ucHotspotConfig; ++ ++ /*Roaming Consortium Information */ ++ /* PARAM_HS20_ROAMING_CONSORTIUM_INFO rRCInfo; */ ++ ++ /*Hotspot 2.0 dummy AP Info */ ++ ++ /*Time Advertisement Information */ ++ /* UINT_32 u4UTCOffsetTime; */ ++ /* UINT_8 aucTimeZone[ELEM_MAX_LEN_TIME_ZONE]; */ ++ /* UINT_8 ucLenTimeZone; */ ++ ++ /* For SIGMA Test */ ++ /* BSSID Pool */ ++ BSSID_ENTRY_T arBssidPool[BSSID_POOL_MAX_SIZE]; ++ UINT_8 ucNumBssidPoolEntry; ++ BOOLEAN fgIsHS2SigmaMode; ++ ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*For GTK Frame Filter*/ ++#if DBG ++#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ ++ { \ ++ UINT_32 u4Size = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + \ ++ (((_prAddrList)->ucAddrCount) * sizeof(IPV4_NETWORK_ADDRESS)); \ ++ kalMemFree((_prAddrList), VIR_MEM_TYPE, u4Size); \ ++ (_prAddrList) = NULL; \ ++ } ++#else ++#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ ++ { \ ++ kalMemFree((_prAddrList), VIR_MEM_TYPE, 0); \ ++ (_prAddrList) = NULL; \ ++ } ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); ++ ++VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); ++ ++UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID); ++ ++WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE); ++ ++BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); ++ ++BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); ++#endif ++ ++BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); ++ ++BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); ++ ++WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); ++ ++#endif ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h +new file mode 100644 +index 000000000000..cb89fd8793ee +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h +@@ -0,0 +1,153 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/mib.h#1 ++*/ ++ ++/*! \file mib.h ++ \brief This file contains the IEEE 802.11 family related MIB definition ++ for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: mib.h ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++#ifndef _MIB_H ++#define _MIB_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Entry in SMT AuthenticationAlgorithms Table: dot11AuthenticationAlgorithmsEntry */ ++typedef struct _DOT11_AUTHENTICATION_ALGORITHMS_ENTRY { ++ BOOLEAN dot11AuthenticationAlgorithmsEnable; /* dot11AuthenticationAlgorithmsEntry 3 */ ++} DOT11_AUTHENTICATION_ALGORITHMS_ENTRY, *P_DOT11_AUTHENTICATION_ALGORITHMS_ENTRY; ++ ++/* Entry in SMT dot11RSNAConfigPairwiseCiphersTalbe Table: dot11RSNAConfigPairwiseCiphersEntry */ ++typedef struct _DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY { ++ UINT_32 dot11RSNAConfigPairwiseCipher; /* dot11RSNAConfigPairwiseCiphersEntry 2 */ ++ BOOLEAN dot11RSNAConfigPairwiseCipherEnabled; /* dot11RSNAConfigPairwiseCiphersEntry 3 */ ++} DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY, *P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY; ++ ++/* Entry in SMT dot11RSNAConfigAuthenticationSuitesTalbe Table: dot11RSNAConfigAuthenticationSuitesEntry */ ++typedef struct _DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY { ++ UINT_32 dot11RSNAConfigAuthenticationSuite; /* dot11RSNAConfigAuthenticationSuitesEntry 2 */ ++ BOOLEAN dot11RSNAConfigAuthenticationSuiteEnabled; /* dot11RSNAConfigAuthenticationSuitesEntry 3 */ ++} DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY, *P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY; ++ ++/* ----- IEEE 802.11 MIB Major sections ----- */ ++typedef struct _IEEE_802_11_MIB_T { ++ /* dot11PrivacyTable (dot11smt 5) */ ++ UINT_8 dot11WEPDefaultKeyID; /* dot11PrivacyEntry 2 */ ++ BOOLEAN dot11TranmitKeyAvailable; ++ UINT_32 dot11WEPICVErrorCount; /* dot11PrivacyEntry 5 */ ++ UINT_32 dot11WEPExcludedCount; /* dot11PrivacyEntry 6 */ ++ ++ /* dot11RSNAConfigTable (dot11smt 8) */ ++ UINT_32 dot11RSNAConfigGroupCipher; /* dot11RSNAConfigEntry 4 */ ++ ++ /* dot11RSNAConfigPairwiseCiphersTable (dot11smt 9) */ ++ DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY dot11RSNAConfigPairwiseCiphersTable[MAX_NUM_SUPPORTED_CIPHER_SUITES]; ++ ++ /* dot11RSNAConfigAuthenticationSuitesTable (dot11smt 10) */ ++ DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY ++ dot11RSNAConfigAuthenticationSuitesTable[MAX_NUM_SUPPORTED_AKM_SUITES]; ++ ++#if 0 /* SUPPORT_WAPI */ ++ BOOLEAN fgWapiKeyInstalled; ++ PARAM_WPI_KEY_T rWapiPairwiseKey[2]; ++ BOOLEAN fgPairwiseKeyUsed[2]; ++ UINT_8 ucWpiActivedPWKey; /* Must be 0 or 1, by wapi spec */ ++ PARAM_WPI_KEY_T rWapiGroupKey[2]; ++ BOOLEAN fgGroupKeyUsed[2]; ++#endif ++} IEEE_802_11_MIB_T, *P_IEEE_802_11_MIB_T; ++ ++/* ------------------ IEEE 802.11 non HT PHY characteristics ---------------- */ ++typedef const struct _NON_HT_PHY_ATTRIBUTE_T { ++ UINT_16 u2SupportedRateSet; ++ ++ BOOLEAN fgIsShortPreambleOptionImplemented; ++ ++ BOOLEAN fgIsShortSlotTimeOptionImplemented; ++ ++} NON_HT_PHY_ATTRIBUTE_T, *P_NON_HT_PHY_ATTRIBUTE_T; ++ ++typedef const struct _NON_HT_ADHOC_MODE_ATTRIBUTE_T { ++ ++ ENUM_PHY_TYPE_INDEX_T ePhyTypeIndex; ++ ++ UINT_16 u2BSSBasicRateSet; ++ ++} NON_HT_ADHOC_MODE_ATTRIBUTE_T, *P_NON_HT_ADHOC_MODE_ATTRIBUTE_T; ++ ++typedef NON_HT_ADHOC_MODE_ATTRIBUTE_T NON_HT_AP_MODE_ATTRIBUTE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[]; ++extern NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[]; ++extern NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[]; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MIB_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h +new file mode 100644 +index 000000000000..11145c31dbfa +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h +@@ -0,0 +1,55 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_assoc.h#1 ++*/ ++ ++/*! \file p2p_assoc.h ++ \brief This file contains the Wi-Fi Direct ASSOC REQ/RESP of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++#ifndef _P2P_ASSOC_H ++#define _P2P_ASSOC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h +new file mode 100644 +index 000000000000..869d7bf0ee61 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h +@@ -0,0 +1,56 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_bss.h#2 ++*/ ++ ++/*! \file "p2p_bss.h" ++ \brief In this file we define the function prototype used in p2p BSS/IBSS. ++ ++ The file contains the function declarations and defines for used in BSS/IBSS. ++*/ ++ ++#ifndef _P2P_BSS_H ++#define _P2P_BSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++UINT_32 p2pGetTxProbRspIeTableSize(VOID); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h +new file mode 100644 +index 000000000000..2541e1d2883e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h +@@ -0,0 +1,2190 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_fsm.h#23 ++*/ ++ ++/*! \file p2p_fsm.h ++ \brief Declaration of functions and finite state machine for P2P Module. ++ ++ Declaration of functions and finite state machine for P2P Module. ++*/ ++ ++/* ++** Log: p2p_fsm.h ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix compile error. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 18 2012 yuche.tsai ++ * NULL ++ * add one file. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve class 3 error issue under AP mode. ++ * ++ * data frame may TX before Assoc Response TX. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix default device name issue. ++ * ++ * 11 09 2011 yuche.tsai ++ * [WCXRP00001093] [Need Patch][Volunteer Patch] Service Discovery 2.0 state transition issue. ++ * Fix SD2.0 issue which may cause KE. (Monkey test) ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version ++ * query & set support for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 09 01 2011 yuche.tsai ++ * NULL ++ * Fix channel stay interval. ++ * Sync channel stay interval & channel request interval under AP mode.. ++ * ++ * 08 30 2011 yuche.tsai ++ * [WCXRP00000953] [Volunteer Patch][Driver] Hot Spot Channel ASSERT issue. ++ * Fix hot spot FW assert issue when under concurrent case. (DBG enable only) ++ * ++ * 08 16 2011 cp.wu ++ * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence ++ * auto channel decision for 2.4GHz hot spot mode ++ * ++ * 08 16 2011 yuche.tsai ++ * NULL ++ * Fix scan policy for Active LISTEN scan. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, ++ * TX deauth to a disconnecting device issue. ++ * Support TX Deauth Issue. ++ * ++ * 07 26 2011 yuche.tsai ++ * [WCXRP00000875] [Volunteer Patch][WiFi Direct][Driver] MT6620 IOT issue with realtek test bed solution. ++ * Turn off persistent group support for V2.0 release. ++ * ++ * 07 18 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Fix compile error. ++ * ++ * 07 18 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Fix MT6620 WiFi Direct IOT Issue with BCM solution. ++ * ++ * 07 11 2011 yuche.tsai ++ * [WCXRP00000845] [Volunteer Patch][WiFi Direct] WiFi Direct Device Connection Robustness ++ * Enhance Connection Robustness. ++ * ++ * 07 08 2011 yuche.tsai ++ * [WCXRP00000841] [Volunteer Patch][WiFi Direct] Group Owner Setting. ++ * Update GO configure parameter. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Disable enhancement II for debugging. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Refine compile flag. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix connection indication twice issue. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 05 04 2011 yuche.tsai ++ * NULL ++ * Support partial persistent group function. ++ * ++ * 04 20 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1.Shorten the LISTEN interval. ++ * 2. Fix IF address issue when we are GO ++ * 3. Fix LISTEN channel issue. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Change P2P Connection Request Flow. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 07 2011 yuche.tsai ++ * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the ioctl setting that index not map to spec defined config method. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC IE BE format issue. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 11 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add two function prototype. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Support Disassoc & Deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++ ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++ ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 25 2011 terry.wu ++ * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter ++ * Add a new module parameter to indicate current runnig mode, P2P or AP. ++ * ++ * 01 19 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Null NOA attribute setting when no related parameters. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify some behavior of AP mode. ++ * ++ * 12 22 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Compile Error. ++ * ++ * 12 15 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Refine Connection Flow. ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. ++ * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client ++ * by checking the P2P IE in assoc req frame. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation & Provision Discovery. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ ++ * ++ * 11 29 2010 yuche.tsai ++ * NULL ++ * Update P2P related function for INVITATION & PROVISION DISCOVERY. ++ * ++ * 11 26 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Update P2P PS for NOA function. ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update Code for Invitation Related Function. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] ++ * Set the Tx lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at WinXP. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add connection abort message event prototype. ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix P2P Intended Interface Address Bug. ++ * Extend GO Nego Timeout Time. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Extend Listen Interval default value & remove deprecated variable. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add function prototype for join complete. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some function proto type for P2P FSM under provisioning phase.. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Change P2P data structure for supporting ++ * 1. P2P Device discovery. ++ * 2. P2P Group Negotiation. ++ * 3. P2P JOIN ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Update P2P FSM header file. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * P2P/RSN/WAPI IEs need to be declared with compact structure. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Update P2P FSM header file. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix some P2P function prototype. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename CFG flag for P2P ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify parameter of p2pStartGO ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add Wi-Fi Direct SSID and P2P GO Test Mode ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++#ifndef _P2P_FSM_H ++#define _P2P_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CID52_53_54 0 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_P2P_STATE_T { ++ P2P_STATE_IDLE = 0, ++ P2P_STATE_SCAN, ++ P2P_STATE_AP_CHANNEL_DETECT, ++ P2P_STATE_REQING_CHANNEL, ++ P2P_STATE_CHNL_ON_HAND, /* Requesting Channel to Send Specific Frame. */ ++ P2P_STATE_GC_JOIN, /* Sending Specific Frame. May extending channel by other event. */ ++ P2P_STATE_NUM ++} ENUM_P2P_STATE_T, *P_ENUM_P2P_STATE_T; ++ ++enum _ENUM_P2P_DEV_EXT_LISTEN_T { ++ P2P_DEV_NOT_EXT_LISTEN, ++ P2P_DEV_EXT_LISTEN_ING, ++ P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT, ++ P2P_DEV_EXT_LISTEN_NUM ++}; ++ ++typedef enum _ENUM_CHANNEL_REQ_TYPE_T { ++ CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL, ++ CHANNEL_REQ_TYPE_GC_JOIN_REQ, ++ CHANNEL_REQ_TYPE_GO_START_BSS ++} ENUM_CHANNEL_REQ_TYPE_T, *P_ENUM_CHANNEL_REQ_TYPE_T; ++ ++typedef enum _ENUM_BUFFER_TYPE_T { ++ ENUM_FRAME_TYPE_EXTRA_IE_BEACON, ++ ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP, ++ ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP, ++ ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE, ++ ENUM_FRAME_TYPE_BEACON_TEMPLATE, ++ ENUM_FRAME_IE_NUM ++} ENUM_BUFFER_TYPE_T, *P_ENUM_BUFFER_TYPE_T; ++ ++typedef enum _ENUM_HIDDEN_SSID_TYPE_T { ++ ENUM_HIDDEN_SSID_NONE, ++ ENUM_HIDDEN_SSID_LEN, ++ ENUM_HIDDEN_SSID_ZERO_CONTENT, ++ ENUM_HIDDEN_SSID_NUM ++} ENUM_HIDDEN_SSID_TYPE_T, *P_ENUM_HIDDEN_SSID_TYPE_T; ++ ++typedef struct _P2P_SSID_STRUCT_T { ++ UINT_8 aucSsid[32]; ++ UINT_8 ucSsidLen; ++} P2P_SSID_STRUCT_T, *P_P2P_SSID_STRUCT_T; ++ ++typedef struct _P2P_STATION_INFO_T { ++ UINT_32 u4InactiveTime; ++ UINT_32 u4RxBytes; /* TODO: */ ++ UINT_32 u4TxBytes; /* TODO: */ ++ UINT_32 u4RxPackets; /* TODO: */ ++ UINT_32 u4TxPackets; /* TODO: */ ++ /* TODO: Add more for requirement. */ ++} P2P_STATION_INFO_T, *P_P2P_STATION_INFO_T; ++ ++typedef struct _AP_CRYPTO_SETTINGS_T { ++ UINT_32 u4WpaVersion; ++ UINT_32 u4CipherGroup; ++ INT_32 i4NumOfCiphers; ++ UINT_32 aucCiphersPairwise[5]; ++ INT_32 i4NumOfAkmSuites; ++ UINT_32 aucAkmSuites[2]; ++ BOOLEAN fgIsControlPort; ++ UINT_16 u2ControlPortBE; ++ BOOLEAN fgIsControlPortEncrypt; ++} AP_CRYPTO_SETTINGS_T, *P_AP_CRYPTO_SETTINGS_T; ++ ++/*-------------------- P2P FSM ACTION STRUCT ---------------------*/ ++typedef struct _P2P_CHNL_REQ_INFO_T { ++ BOOLEAN fgIsChannelRequested; ++ UINT_8 ucSeqNumOfChReq; ++ UINT_64 u8Cookie; ++ UINT_8 ucReqChnlNum; ++ ENUM_BAND_T eBand; ++ ENUM_CHNL_EXT_T eChnlSco; ++ UINT_32 u4MaxInterval; ++ ENUM_CHANNEL_REQ_TYPE_T eChannelReqType; ++ ++ UINT_8 ucOriChnlNum; ++ ENUM_BAND_T eOriBand; ++ ENUM_CHNL_EXT_T eOriChnlSco; ++ UINT_32 NFC_BEAM; /*NFC Beam + Indication */ ++} P2P_CHNL_REQ_INFO_T, *P_P2P_CHNL_REQ_INFO_T; ++ ++typedef struct _P2P_SCAN_REQ_INFO_T { ++ ENUM_SCAN_TYPE_T eScanType; ++ ENUM_SCAN_CHANNEL eChannelSet; ++ UINT_16 u2PassiveDewellTime; ++ UINT_8 ucSeqNumOfScnMsg; ++ BOOLEAN fgIsAbort; ++ BOOLEAN fgIsScanRequest; ++ UINT_8 ucNumChannelList; ++ RF_CHANNEL_INFO_T arScanChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++ P2P_SSID_STRUCT_T rSsidStruct; /* Currently we can only take one SSID scan request */ ++ BOOLEAN fgIsGOInitialDone; ++} P2P_SCAN_REQ_INFO_T, *P_P2P_SCAN_REQ_INFO_T; ++ ++typedef struct _P2P_CONNECTION_REQ_INFO_T { ++ ++ BOOLEAN fgIsConnRequest; ++ P2P_SSID_STRUCT_T rSsidStruct; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ /* For ASSOC Req. */ ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++} P2P_CONNECTION_REQ_INFO_T, *P_P2P_CONNECTION_REQ_INFO_T; ++ ++typedef struct _P2P_MGMT_TX_REQ_INFO_T { ++ BOOLEAN fgIsMgmtTxRequested; ++ P_MSDU_INFO_T prMgmtTxMsdu; ++ UINT_64 u8Cookie; ++} P2P_MGMT_TX_REQ_INFO_T, *P_P2P_MGMT_TX_REQ_INFO_T; ++ ++struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 wait; /* interval supplicant expected to stay in listen interval */ ++}; ++ ++typedef struct _P2P_BEACON_UPDATE_INFO_T { ++ PUINT_8 pucBcnHdr; ++ UINT_32 u4BcnHdrLen; ++ PUINT_8 pucBcnBody; ++ UINT_32 u4BcnBodyLen; ++} P2P_BEACON_UPDATE_INFO_T, *P_P2P_BEACON_UPDATE_INFO_T; ++ ++typedef struct _P2P_PROBE_RSP_UPDATE_INFO_T { ++ P_MSDU_INFO_T prProbeRspMsduTemplate; ++} P2P_PROBE_RSP_UPDATE_INFO_T, *P_P2P_PROBE_RSP_UPDATE_INFO_T; ++ ++typedef struct _P2P_ASSOC_RSP_UPDATE_INFO_T { ++ PUINT_8 pucAssocRspExtIE; ++ UINT_16 u2AssocIELen; ++} P2P_ASSOC_RSP_UPDATE_INFO_T, *P_P2P_ASSOC_RSP_UPDATE_INFO_T; ++ ++typedef struct _P2P_JOIN_INFO_T { ++ UINT_32 ucSeqNumOfReqMsg; ++ UINT_8 ucAvailableAuthTypes; ++ P_STA_RECORD_T prTargetStaRec; ++ P2P_SSID_STRUCT_T rSsidStruct; ++ BOOLEAN fgIsJoinComplete; ++ /* For ASSOC Rsp. */ ++ UINT_32 u4BufLength; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++} P2P_JOIN_INFO_T, *P_P2P_JOIN_INFO_T; ++ ++#if CFG_SUPPORT_WFD ++ ++#define WFD_FLAGS_DEV_INFO_VALID BIT(0) /* 1. WFD_DEV_INFO, 2. WFD_CTRL_PORT, 3. WFD_MAT_TP. */ ++#define WFD_FLAGS_SINK_INFO_VALID BIT(1) /* 1. WFD_SINK_STATUS, 2. WFD_SINK_MAC. */ ++#define WFD_FLAGS_ASSOC_MAC_VALID BIT(2) /* 1. WFD_ASSOC_MAC. */ ++#define WFD_FLAGS_EXT_CAPABILITY_VALID BIT(3) /* 1. WFD_EXTEND_CAPABILITY. */ ++ ++struct _WFD_CFG_SETTINGS_T { ++ UINT_32 u4WfdCmdType; ++ UINT_8 ucWfdEnable; ++ UINT_8 ucWfdCoupleSinkStatus; ++ UINT_8 ucWfdSessionAvailable; /* 0: NA 1:Set 2:Clear */ ++ UINT_8 ucWfdSigmaMode; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2WfdControlPort; ++ UINT_16 u2WfdMaximumTp; ++ UINT_16 u2WfdExtendCap; ++ UINT_8 aucWfdCoupleSinkAddress[MAC_ADDR_LEN]; ++ UINT_8 aucWfdAssociatedBssid[MAC_ADDR_LEN]; ++ UINT_8 aucWfdVideoIp[4]; ++ UINT_8 aucWfdAudioIp[4]; ++ UINT_16 u2WfdVideoPort; ++ UINT_16 u2WfdAudioPort; ++ UINT_32 u4WfdFlag; ++ UINT_32 u4WfdPolicy; ++ UINT_32 u4WfdState; ++ UINT_8 aucWfdSessionInformationIE[24 * 8]; ++ UINT_16 u2WfdSessionInformationIELen; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; ++ UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; ++ UINT_32 u4WfdAdvancedFlag; ++ /* Group 1 64 bytes */ ++ UINT_8 aucWfdLocalIp[4]; ++ UINT_16 u2WfdLifetimeAc2; /* Unit is 2 TU */ ++ UINT_16 u2WfdLifetimeAc3; /* Unit is 2 TU */ ++ UINT_16 u2WfdCounterThreshold; /* Unit is ms */ ++ UINT_8 aucReverved2[54]; ++ /* Group 2 64 bytes */ ++ UINT_8 aucReverved3[64]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReverved4[64]; ++ ++}; ++ ++struct _WFD_DBG_CFG_SETTINGS_T { ++ UINT_8 ucWfdDebugMode; ++ UINT_16 u2WfdSNShowPeiroid; ++ UINT_8 Reserved; ++ ++}; ++ ++#endif ++ ++struct _P2P_FSM_INFO_T { ++ /* State related. */ ++ ENUM_P2P_STATE_T ePreviousState; ++ ENUM_P2P_STATE_T eCurrentState; ++ ++ /* Channel related. */ ++ P2P_CHNL_REQ_INFO_T rChnlReqInfo; ++ ++ /* Scan related. */ ++ P2P_SCAN_REQ_INFO_T rScanReqInfo; ++ ++ /* Connection related. */ ++ P2P_CONNECTION_REQ_INFO_T rConnReqInfo; ++ ++ /* Mgmt tx related. */ ++ P2P_MGMT_TX_REQ_INFO_T rMgmtTxInfo; ++ ++ /* Beacon related. */ ++ P2P_BEACON_UPDATE_INFO_T rBcnContentInfo; ++ ++ /* Probe Response related. */ ++ P2P_PROBE_RSP_UPDATE_INFO_T rProbeRspContentInfo; ++ ++ /* Assoc Rsp related. */ ++ P2P_ASSOC_RSP_UPDATE_INFO_T rAssocRspContentInfo; ++ ++ /* GC Join related. */ ++ P2P_JOIN_INFO_T rJoinInfo; ++ ++ /* FSM Timer */ ++/* TIMER_T rP2pFsmTimeoutTimer; */ ++ ++ /* GC Target BSS. */ ++ P_BSS_DESC_T prTargetBss; ++ ++ /* GC Connection Request. */ ++ BOOLEAN fgIsConnectionRequested; ++ ++ BOOLEAN fgIsApMode; ++ ++ /* Channel grant interval. */ ++ UINT_32 u4GrantInterval; ++ ++ /* Packet filter for P2P module. */ ++ UINT_32 u4P2pPacketFilter; ++ ++ /* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Prepare for use vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ ++ /* Msg event queue. */ ++ LINK_T rMsgEventQueue; ++ ++#if CFG_SUPPORT_WFD ++ WFD_CFG_SETTINGS_T rWfdConfigureSettings; ++ WFD_DBG_CFG_SETTINGS_T rWfdDebugSetting; ++#endif ++ ++ BOOLEAN fgIsWPSMode; ++ ++ enum _ENUM_P2P_DEV_EXT_LISTEN_T eListenExted; ++}; ++ ++/*---------------- Messages -------------------*/ ++typedef struct _MSG_P2P_SCAN_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P_P2P_SSID_STRUCT_T prSSID; ++ INT_32 i4SsidNum; ++ UINT_32 u4NumChannel; ++ PUINT_8 pucIEBuf; ++ UINT_32 u4IELen; ++ BOOLEAN fgIsAbort; ++ RF_CHANNEL_INFO_T arChannelListInfo[1]; ++} MSG_P2P_SCAN_REQUEST_T, *P_MSG_P2P_SCAN_REQUEST_T; ++ ++typedef struct _MSG_P2P_CHNL_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++ UINT_32 u4Duration; ++ ENUM_CHNL_EXT_T eChnlSco; ++ RF_CHANNEL_INFO_T rChannelInfo; ++} MSG_P2P_CHNL_REQUEST_T, *P_MSG_P2P_CHNL_REQUEST_T; ++ ++typedef struct _MSG_P2P_CHNL_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_64 u8Cookie; ++} MSG_P2P_CHNL_ABORT_T, *P_MSG_P2P_CHNL_ABORT_T; ++ ++typedef struct _MSG_P2P_CONNECTION_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P2P_SSID_STRUCT_T rSsid; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ ENUM_CHNL_EXT_T eChnlSco; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ UINT_32 u4IELen; ++ UINT_8 aucIEBuf[1]; ++ /* TODO: Auth Type, OPEN, SHARED, FT, EAP... */ ++} MSG_P2P_CONNECTION_REQUEST_T, *P_MSG_P2P_CONNECTION_REQUEST_T; ++ ++typedef struct _MSG_P2P_CONNECTION_ABORT_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member. */ ++ UINT_8 aucTargetID[MAC_ADDR_LEN]; ++ UINT_16 u2ReasonCode; ++ BOOLEAN fgSendDeauth; ++} MSG_P2P_CONNECTION_ABORT_T, *P_MSG_P2P_CONNECTION_ABORT_T; ++ ++typedef struct _MSG_P2P_MGMT_TX_REQUEST_T { ++ MSG_HDR_T rMsgHdr; ++ P_MSDU_INFO_T prMgmtMsduInfo; ++ UINT_64 u8Cookie; /* For indication. */ ++ BOOLEAN fgNoneCckRate; ++ BOOLEAN fgIsWaitRsp; ++} MSG_P2P_MGMT_TX_REQUEST_T, *P_MSG_P2P_MGMT_TX_REQUEST_T; ++ ++typedef struct _MSG_P2P_START_AP_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 u4DtimPeriod; ++ UINT_32 u4BcnInterval; ++ UINT_8 aucSsid[32]; ++ UINT_16 u2SsidLen; ++ UINT_8 ucHiddenSsidType; ++ BOOLEAN fgIsPrivacy; ++ AP_CRYPTO_SETTINGS_T rEncryptionSettings; ++ INT_32 i4InactiveTimeout; ++} MSG_P2P_START_AP_T, *P_MSG_P2P_START_AP_T; ++ ++typedef struct _MSG_P2P_BEACON_UPDATE_T { ++ MSG_HDR_T rMsgHdr; ++ UINT_32 u4BcnHdrLen; ++ UINT_32 u4BcnBodyLen; ++ PUINT_8 pucBcnHdr; ++ PUINT_8 pucBcnBody; ++ UINT_8 aucBuffer[1]; /* Header & Body are put here. */ ++} MSG_P2P_BEACON_UPDATE_T, *P_MSG_P2P_BEACON_UPDATE_T; ++ ++typedef struct _MSG_P2P_MGMT_FRAME_UPDATE_T { ++ MSG_HDR_T rMsgHdr; ++ ENUM_BUFFER_TYPE_T eBufferType; ++ UINT_32 u4BufferLen; ++ UINT_8 aucBuffer[1]; ++} MSG_P2P_MGMT_FRAME_UPDATE_T, *P_MSG_P2P_MGMT_FRAME_UPDATE_T; ++ ++typedef struct _MSG_P2P_SWITCH_OP_MODE_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ ENUM_OP_MODE_T eOpMode; ++} MSG_P2P_SWITCH_OP_MODE_T, *P_MSG_P2P_SWITCH_OP_MODE_T; ++ ++typedef struct _MSG_P2P_MGMT_FRAME_REGISTER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_16 u2FrameType; ++ BOOLEAN fgIsRegister; ++} MSG_P2P_MGMT_FRAME_REGISTER_T, *P_MSG_P2P_MGMT_FRAME_REGISTER_T; ++ ++typedef struct _MSG_P2P_NETDEV_REGISTER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ BOOLEAN fgIsEnable; ++ UINT_8 ucMode; ++} MSG_P2P_NETDEV_REGISTER_T, *P_MSG_P2P_NETDEV_REGISTER_T; ++ ++#if CFG_SUPPORT_WFD ++typedef struct _MSG_WFD_CONFIG_SETTINGS_CHANGED_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings; ++} MSG_WFD_CONFIG_SETTINGS_CHANGED_T, *P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS ++p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++#if CFG_SUPPORT_WFD ++VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++#endif ++ ++#if 0 ++/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ///////////////////////////////////////////////////////////////////////////////////// */ ++/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ ++#endif ++ ++/* 3 --------------- WFA P2P DEFAULT PARAMETERS --------------- */ ++#define P2P_WILDCARD_SSID "DIRECT-" ++#define P2P_WILDCARD_SSID_LEN 7 ++#define P2P_GROUP_ID_LEN 9 ++ ++#define P2P_DRIVER_VERSION 2 /* Update when needed. */ ++ ++#define P2P_DEFAULT_DEV_NAME "Wireless Client" ++#define P2P_DEFAULT_DEV_NAME_LEN 15 ++#define P2P_DEFAULT_PRIMARY_CATEGORY_ID 10 ++#define P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID 5 ++#define P2P_DEFAULT_CONFIG_METHOD \ ++ (WPS_ATTRI_CFG_METHOD_PUSH_BUTTON | WPS_ATTRI_CFG_METHOD_KEYPAD | WPS_ATTRI_CFG_METHOD_DISPLAY) ++#define P2P_DEFAULT_LISTEN_CHANNEL 1 ++ ++#define P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT 0 /* NOTE(Kevin): Shall <= 16 */ ++#define P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT 13 ++ ++#define P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE 51 /* Contains 6 sub-band. */ ++ ++#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ ++ ++#define P2P_MAXIMUM_CLIENT_COUNT 8 ++#define P2P_MAXIMUM_NOA_COUNT 8 ++ ++#define P2P_MAXIMUM_ATTRIBUTE_LEN 251 ++ ++#define P2P_CTWINDOW_DEFAULT 25 /* in TU=(1024usec) */ ++ ++#define P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE 768 ++ ++/* P2P 3.1.2.1.3 - Find Phase */ ++#define P2P_MAX_DISCOVERABLE_INTERVAL 8 /* 3 */ ++#define P2P_MIN_DISCOVERABLE_INTERVAL 5 /* 1 */ ++ ++#define P2P_LISTEN_SCAN_UNIT 100 /* MS */ ++ ++/* FSM Time Related constrain. */ ++#define P2P_SERACH_STATE_PERIOD_MS 1000 /* Deprecated. */ ++ ++#define P2P_GO_CHANNEL_STAY_INTERVAL 1000 ++ ++#define P2P_GO_NEGO_TIMEOUT_MS 500 ++#define P2P_CONNECTION_TIMEOUT_SEC 120 ++ ++#define P2P_INVITAION_TIMEOUT_MS 500 /* Timeout Wait Invitation Resonse. */ ++#define P2P_PROVISION_DISCOVERY_TIMEOUT_MS 500 /* Timeout Wait Provision Discovery Resonse. */ ++ ++/* 3 --------------- WFA P2P IE --------------- */ ++/* P2P 4.1.1 - P2P IE format */ ++#define P2P_OUI_TYPE_LEN 4 ++#define P2P_IE_OUI_HDR (ELEM_HDR_LEN + P2P_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, ++ aucP2PAttributes[0]) */ ++ ++/* P2P 4.1.1 - General P2P Attribute */ ++#define P2P_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ ++#define P2P_ATTRI_LEN_NOTICE_OF_ABSENCE (P2P_ATTRI_HDR_LEN + 2) /* 5 */ ++ ++/* P2P 4.1.1 - P2P Attribute ID definitions */ ++#define P2P_ATTRI_ID_STATUS 0 ++#define P2P_ATTRI_ID_REASON_CODE 1 ++#define P2P_ATTRI_ID_P2P_CAPABILITY 2 ++#define P2P_ATTRI_ID_P2P_DEV_ID 3 ++#define P2P_ATTRI_ID_GO_INTENT 4 ++#define P2P_ATTRI_ID_CFG_TIMEOUT 5 ++#define P2P_ATTRI_ID_LISTEN_CHANNEL 6 ++#define P2P_ATTRI_ID_P2P_GROUP_BSSID 7 ++#define P2P_ATTRI_ID_EXT_LISTEN_TIMING 8 ++#define P2P_ATTRI_ID_INTENDED_P2P_IF_ADDR 9 ++#define P2P_ATTRI_ID_P2P_MANAGEABILITY 10 ++#define P2P_ATTRI_ID_CHANNEL_LIST 11 ++#define P2P_ATTRI_ID_NOTICE_OF_ABSENCE 12 ++#define P2P_ATTRI_ID_P2P_DEV_INFO 13 ++#define P2P_ATTRI_ID_P2P_GROUP_INFO 14 ++#define P2P_ATTRI_ID_P2P_GROUP_ID 15 ++#define P2P_ATTRI_ID_P2P_INTERFACE 16 ++#define P2P_ATTRI_ID_OPERATING_CHANNEL 17 ++#define P2P_ATTRI_ID_INVITATION_FLAG 18 ++#define P2P_ATTRI_ID_VENDOR_SPECIFIC 221 ++ ++/* Maximum Length of P2P Attributes */ ++#define P2P_ATTRI_MAX_LEN_STATUS 1 /* 0 */ ++#define P2P_ATTRI_MAX_LEN_REASON_CODE 1 /* 1 */ ++#define P2P_ATTRI_MAX_LEN_P2P_CAPABILITY 2 /* 2 */ ++#define P2P_ATTRI_MAX_LEN_P2P_DEV_ID 6 /* 3 */ ++#define P2P_ATTRI_MAX_LEN_GO_INTENT 1 /* 4 */ ++#define P2P_ATTRI_MAX_LEN_CFG_TIMEOUT 2 /* 5 */ ++#if CID52_53_54 ++#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ ++#else ++#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ ++#endif ++#define P2P_ATTRI_MAX_LEN_P2P_GROUP_BSSID 6 /* 7 */ ++#define P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING 4 /* 8 */ ++#define P2P_ATTRI_MAX_LEN_INTENDED_P2P_IF_ADDR 6 /* 9 */ ++#define P2P_ATTRI_MAX_LEN_P2P_MANAGEABILITY 1 /* 10 */ ++/* #define P2P_ATTRI_MAX_LEN_CHANNEL_LIST 3 + (n* (2 + num_of_ch)) */ /* 11 */ ++#define P2P_ATTRI_LEN_CHANNEL_LIST 3 /* 11 */ ++#define P2P_ATTRI_LEN_CHANNEL_ENTRY 2 /* 11 */ ++ ++/* #define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE 2 + (n* (13)) */ /* 12 */ ++#define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE (2 + (P2P_MAXIMUM_NOA_COUNT*(13))) /* 12 */ ++ ++#define P2P_ATTRI_MAX_LEN_P2P_DEV_INFO (17 + (8 * (8)) + 36) /* 13 */ ++/* #define P2P_ATTRI_MAX_LEN_P2P_GROUP_INFO n* (25 + (m* (8)) + 32) */ /* 14 */ ++#define P2P_ATTRI_MAX_LEN_P2P_GROUP_ID 38 /* 15 */ ++#define P2P_ATTRI_MAX_LEN_P2P_INTERFACE 253 /* 7 + 6* [0~41] */ /* 16 */ ++#if CID52_53_54 ++#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ ++#else ++#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ ++#endif ++#define P2P_ATTRI_MAX_LEN_INVITATION_FLAGS 1 /* 18 */ ++ ++/* P2P 4.1.2 - P2P Status definitions */ ++#define P2P_STATUS_SUCCESS 0 ++#define P2P_STATUS_FAIL_INFO_IS_CURRENTLY_UNAVAILABLE 1 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 2 ++#define P2P_STATUS_FAIL_LIMIT_REACHED 3 ++#define P2P_STATUS_FAIL_INVALID_PARAM 4 ++#define P2P_STATUS_FAIL_UNABLE_ACCOMMODATE_REQ 5 ++#define P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR 6 ++#define P2P_STATUS_FAIL_NO_COMMON_CHANNELS 7 ++#define P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP 8 ++#define P2P_STATUS_FAIL_SAME_INTENT_VALUE_15 9 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVISION_METHOD 10 ++#define P2P_STATUS_FAIL_REJECTED_BY_USER 11 ++ ++/* P2P 4.1.3 - P2P Minor Reason Code definitions */ ++#define P2P_REASON_SUCCESS 0 ++#define P2P_REASON_DISASSOCIATED_DUE_CROSS_CONNECTION 1 ++#define P2P_REASON_DISASSOCIATED_DUE_UNMANAGEABLE 2 ++#define P2P_REASON_DISASSOCIATED_DUE_NO_P2P_COEXIST_PARAM 3 ++#define P2P_REASON_DISASSOCIATED_DUE_MANAGEABLE 4 ++ ++/* P2P 4.1.4 - Device Capability Bitmap definitions */ ++#define P2P_DEV_CAPABILITY_SERVICE_DISCOVERY BIT(0) ++#define P2P_DEV_CAPABILITY_CLIENT_DISCOVERABILITY BIT(1) ++#define P2P_DEV_CAPABILITY_CONCURRENT_OPERATION BIT(2) ++#define P2P_DEV_CAPABILITY_P2P_INFRA_MANAGED BIT(3) ++#define P2P_DEV_CAPABILITY_P2P_DEVICE_LIMIT BIT(4) ++#define P2P_DEV_CAPABILITY_P2P_INVITATION_PROCEDURE BIT(5) ++ ++/* P2P 4.1.4 - Group Capability Bitmap definitions */ ++#define P2P_GROUP_CAPABILITY_P2P_GROUP_OWNER BIT(0) ++#define P2P_GROUP_CAPABILITY_PERSISTENT_P2P_GROUP BIT(1) ++#define P2P_GROUP_CAPABILITY_P2P_GROUP_LIMIT BIT(2) ++#define P2P_GROUP_CAPABILITY_INTRA_BSS_DISTRIBUTION BIT(3) ++#define P2P_GROUP_CAPABILITY_CROSS_CONNECTION BIT(4) ++#define P2P_GROUP_CAPABILITY_PERSISTENT_RECONNECT BIT(5) ++#define P2P_GROUP_CAPABILITY_GROUP_FORMATION BIT(6) ++ ++/* P2P 4.1.6 - GO Intent field definitions */ ++#define P2P_GO_INTENT_TIE_BREAKER_FIELD BIT(0) ++#define P2P_GO_INTENT_VALUE_MASK BITS(1, 7) ++#define P2P_GO_INTENT_VALUE_OFFSET 1 ++ ++/* P2P 4.1.12 - Manageability Bitmap definitions */ ++#define P2P_DEVICE_MANAGEMENT BIT(0) ++ ++/* P2P 4.1.14 - CTWindow and OppPS Parameters definitions */ ++#define P2P_CTW_OPPPS_PARAM_OPPPS_FIELD BIT(7) ++#define P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK BITS(0, 6) ++ ++#define ELEM_MAX_LEN_P2P_FOR_PROBE_REQ \ ++ (P2P_OUI_TYPE_LEN + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_ID) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL)) ++ ++#define ELEM_MAX_LEN_P2P_FOR_ASSOC_REQ \ ++ (P2P_OUI_TYPE_LEN + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING) + \ ++ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_INFO)) ++ ++/* P2P 4.1.16 - P2P Client Infor Descriptor */ ++#define P2P_CLIENT_INFO_DESC_HDR_LEN 1 /* Length(1 octets) */ ++ ++/* P2P 4.1.20 - P2P Invitation Flags Attribute*/ ++#define P2P_INVITATION_FLAGS_INVITATION_TYPE BIT(0) ++#define P2P_INVITATION_TYPE_INVITATION 0 ++#define P2P_INVITATION_TYPE_REINVOKE 1 ++/* 3 --------------- WPS Data Element Definitions --------------- */ ++/* P2P 4.2.2 - General WSC Attribute */ ++#define WSC_ATTRI_HDR_LEN 4 /* ID(2 octet) + Length(2 octets) */ ++#define WSC_ATTRI_MAX_LEN_VERSION 1 ++#define WSC_ATTRI_MAX_LEN_DEVICE_PASSWORD_ID 2 ++#define WSC_ATTRI_LEN_CONFIG_METHOD 2 ++ ++/* WPS 11 - Data Element Definitions */ ++#define WPS_ATTRI_ID_VERSION 0x104A ++#define WPS_ATTRI_ID_CONFIGURATION_METHODS 0x1008 ++#define WPS_ATTRI_ID_DEVICE_PASSWORD 0x1012 ++#define WPS_ATTRI_ID_DEVICE_NAME 0x1011 ++#define WPS_ATTRI_ID_PRI_DEVICE_TYPE 0x1054 ++#define WPS_ATTRI_ID_SEC_DEVICE_TYPE 0x1055 ++ ++#define WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE 300 ++ ++#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ ++ ++#define WPS_ATTRI_CFG_METHOD_USBA BIT(0) ++#define WPS_ATTRI_CFG_METHOD_ETHERNET BIT(1) ++#define WPS_ATTRI_CFG_METHOD_LABEL BIT(2) ++#define WPS_ATTRI_CFG_METHOD_DISPLAY BIT(3) ++#define WPS_ATTRI_CFG_METHOD_EXT_NFC BIT(4) ++#define WPS_ATTRI_CFG_METHOD_INT_NFC BIT(5) ++#define WPS_ATTRI_CFG_METHOD_NFC_IF BIT(6) ++#define WPS_ATTRI_CFG_METHOD_PUSH_BUTTON BIT(7) ++#define WPS_ATTRI_CFG_METHOD_KEYPAD BIT(8) ++ ++#define P2P_FLAGS_PROVISION_COMPLETE 0x00000001 ++#define P2P_FLAGS_PROVISION_DISCOVERY_COMPLETE 0x00000002 ++#define P2P_FLAGS_PROVISION_DISCOVERY_WAIT_RESPONSE 0x00000004 ++#define P2P_FLAGS_PROVISION_DISCOVERY_RESPONSE_WAIT 0x00000008 ++#define P2P_FLAGS_MASK_PROVISION 0x00000017 ++#define P2P_FLAGS_MASK_PROVISION_COMPLETE 0x00000015 ++#define P2P_FLAGS_PROVISION_DISCOVERY_INDICATED 0x00000010 ++#define P2P_FLAGS_INVITATION_TOBE_GO 0x00000100 ++#define P2P_FLAGS_INVITATION_TOBE_GC 0x00000200 ++#define P2P_FLAGS_INVITATION_SUCCESS 0x00000400 ++#define P2P_FLAGS_INVITATION_WAITING_TARGET 0x00000800 ++#define P2P_FLAGS_MASK_INVITATION 0x00000F00 ++#define P2P_FLAGS_FORMATION_ON_GOING 0x00010000 ++#define P2P_FLAGS_FORMATION_LOCAL_PWID_RDY 0x00020000 ++#define P2P_FLAGS_FORMATION_TARGET_PWID_RDY 0x00040000 ++#define P2P_FLAGS_FORMATION_COMPLETE 0x00080000 ++#define P2P_FLAGS_MASK_FORMATION 0x000F0000 ++#define P2P_FLAGS_DEVICE_DISCOVER_REQ 0x00100000 ++#define P2P_FLAGS_DEVICE_DISCOVER_DONE 0x00200000 ++#define P2P_FLAGS_DEVICE_INVITATION_WAIT 0x00400000 ++#define P2P_FLAGS_DEVICE_SERVICE_DISCOVER_WAIT 0x00800000 ++#define P2P_FLAGS_MASK_DEVICE_DISCOVER 0x00F00000 ++ ++#define P2P_FLAGS_DEVICE_FORMATION_REQUEST 0x01000000 ++ ++/* MACRO for flag operation */ ++#define SET_FLAGS(_FlagsVar, _BitsToSet) \ ++ {(_FlagsVar) = ((_FlagsVar) | (_BitsToSet))} ++ ++#define TEST_FLAGS(_FlagsVar, _BitsToCheck) \ ++ (((_FlagsVar) & (_BitsToCheck)) == (_BitsToCheck)) ++ ++#define CLEAR_FLAGS(_FlagsVar, _BitsToClear) \ ++ {(_FlagsVar) &= ~(_BitsToClear)} ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_I 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_II 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_III 0 ++ ++#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_IV 0 ++ ++#define CFG_DISABLE_DELAY_PROVISION_DISCOVERY 0 ++ ++#define CFG_CONNECTION_POLICY_2_0 0 ++ ++/* Device Password ID */ ++enum wps_dev_password_id { ++ DEV_PW_DEFAULT = 0x0000, ++ DEV_PW_USER_SPECIFIED = 0x0001, ++ DEV_PW_MACHINE_SPECIFIED = 0x0002, ++ DEV_PW_REKEY = 0x0003, ++ DEV_PW_PUSHBUTTON = 0x0004, ++ DEV_PW_REGISTRAR_SPECIFIED = 0x0005 ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack(1) ++#endif ++ ++/* 3 --------------- WFA P2P IE and Attributes --------------- */ ++ ++/* P2P 4.1.1 - P2P Information Element */ ++typedef struct _IE_P2P_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 aucP2PAttributes[1]; /* P2P Attributes */ ++} __KAL_ATTRIB_PACKED__ IE_P2P_T, *P_IE_P2P_T; ++ ++/* P2P 4.1.1 - General P2P Attribute */ ++typedef struct _P2P_ATTRIBUTE_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRIBUTE_T, ATTRIBUTE_HDR_T, *P_P2P_ATTRIBUTE_T, *P_ATTRIBUTE_HDR_T; ++ ++/* P2P 4.1.2 - P2P Status Attribute */ ++typedef struct _P2P_ATTRI_STATUS_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucStatusCode; /* Status Code */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_STATUS_T, *P_P2P_ATTRI_STATUS_T; ++ ++/* P2P 4.1.3 - P2P Minor Reason Code Attribute */ ++typedef struct _P2P_ATTRI_REASON_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucMinorReasonCode; /* Minor Reason Code */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_REASON_T, *P_P2P_ATTRI_REASON_T; ++ ++/* P2P 4.1.4 - P2P Capability Attribute */ ++typedef struct _P2P_ATTRI_CAPABILITY_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucDeviceCap; /* Device Capability Bitmap */ ++ UINT_8 ucGroupCap; /* Group Capability Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CAPABILITY_T, *P_P2P_ATTRI_CAPABILITY_T; ++ ++/* P2P 4.1.5 - P2P Device ID Attribute */ ++typedef struct _P2P_ATTRI_DEV_ID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_ID_T, *P_P2P_ATTRI_DEV_ID_T; ++ ++/* P2P 4.1.6 - Group Owner Intent Attribute */ ++typedef struct _P2P_ATTRI_GO_INTENT_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucGOIntent; /* Group Owner Intent */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GO_INTENT_T, *P_P2P_ATTRI_GO_INTENT_T; ++ ++/* P2P 4.1.7 - Configuration Timeout Attribute */ ++typedef struct _P2P_ATTRI_CFG_TIMEOUT_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucGOCfgTimeout; /* GO Configuration Timeout */ ++ UINT_8 ucClientCfgTimeout; /* Client Configuration Timeout */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CFG_TIMEOUT_T, *P_P2P_ATTRI_CFG_TIMEOUT_T; ++ ++/* P2P 4.1.8 - Listen Channel Attribute */ ++typedef struct _P2P_ATTRI_LISTEN_CHANNEL_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ ++ UINT_8 ucChannelNumber; /* Channel Number */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_LISTEN_CHANNEL_T, *P_P2P_ATTRI_LISTEN_CHANNEL_T; ++ ++/* P2P 4.1.9 - P2P Group BSSID Attribute */ ++typedef struct _P2P_ATTRI_GROUP_BSSID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBssid[MAC_ADDR_LEN]; /* P2P Group BSSID */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_BSSID_T, *P_P2P_ATTRI_GROUP_BSSID_T; ++ ++/* P2P 4.1.10 - Extended Listen Timing Attribute */ ++typedef struct _P2P_ATTRI_EXT_LISTEN_TIMING_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2AvailPeriod; /* Availability Period */ ++ UINT_16 u2AvailInterval; /* Availability Interval */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_EXT_LISTEN_TIMING_T, *P_P2P_ATTRI_EXT_LISTEN_TIMING_T; ++ ++/* P2P 4.1.11 - Intended P2P Interface Address Attribute */ ++typedef struct _P2P_ATTRI_INTENDED_IF_ADDR_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTENDED_IF_ADDR_T, *P_P2P_ATTRI_INTENDED_IF_ADDR_T; ++ ++/* P2P 4.1.12 - P2P Manageability Attribute */ ++typedef struct _P2P_ATTRI_MANAGEABILITY_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucManageability; /* P2P Manageability Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_MANAGEABILITY_T, *P_P2P_ATTRI_MANAGEABILITY_T; ++ ++/* P2P 4.1.13 - Channel List Attribute */ ++typedef struct _P2P_ATTRI_CHANNEL_LIST_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 aucChannelEntry[1]; /* Channel Entry List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CHANNEL_T, *P_P2P_ATTRI_CHANNEL_T; ++ ++typedef struct _CHANNEL_ENTRY_FIELD_T { ++ UINT_8 ucRegulatoryClass; /* Regulatory Class */ ++ UINT_8 ucNumberOfChannels; /* Number Of Channels */ ++ UINT_8 aucChannelList[1]; /* Channel List */ ++} __KAL_ATTRIB_PACKED__ CHANNEL_ENTRY_FIELD_T, *P_CHANNEL_ENTRY_FIELD_T; ++ ++/* P2P 4.1.14 - Notice of Absence Attribute */ ++typedef struct _P2P_ATTRI_NOA_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucIndex; /* Index */ ++ UINT_8 ucCTWOppPSParam; /* CTWindow and OppPS Parameters */ ++ UINT_8 aucNoADesc[1]; /* NoA Descriptor */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_NOA_T, *P_P2P_ATTRI_NOA_T; ++ ++typedef struct _NOA_DESCRIPTOR_T { ++ UINT_8 ucCountType; /* Count/Type */ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} __KAL_ATTRIB_PACKED__ NOA_DESCRIPTOR_T, *P_NOA_DESCRIPTOR_T; ++ ++typedef struct _P2P_ATTRI_DEV_INFO_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_16 u2ConfigMethodsBE; /* Config Method */ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ ++ UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ ++ DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_INFO_T, *P_P2P_ATTRI_DEV_INFO_T; ++ ++/* WPS 7.1 & 11 WPS TLV Data Format - Device Name */ ++typedef struct _DEVICE_NAME_TLV_T { ++ UINT_16 u2Id; /* WPS Attribute Type */ ++ UINT_16 u2Length; /* Data Length */ ++ UINT_8 aucName[32]; /* Device Name */ /* TODO: Fixme */ ++} __KAL_ATTRIB_PACKED__ DEVICE_NAME_TLV_T, *P_DEVICE_NAME_TLV_T; ++ ++/* P2P 4.1.16 - P2P Group Info Attribute */ ++typedef struct _P2P_CLIENT_INFO_DESC_T { ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ ++ UINT_8 ucDeviceCap; /* Device Capability Bitmap */ ++ UINT_16 u2ConfigMethodsBE; /* Config Method */ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ ++ UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ ++ DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ ++} __KAL_ATTRIB_PACKED__ P2P_CLIENT_INFO_DESC_T, *P_P2P_CLIENT_INFO_DESC_T; ++ ++typedef struct _P2P_ATTRI_GROUP_INFO_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ P2P_CLIENT_INFO_DESC_T arClientDesc[1]; /* P2P Client Info Descriptors */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_INFO_T, *P_P2P_ATTRI_GROUP_INFO_T; ++ ++/* P2P 4.1.17 - P2P Group ID Attribute */ ++typedef struct _P2P_ATTRI_GROUP_ID_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_ID_T, *P_P2P_ATTRI_GROUP_ID_T; ++ ++/* P2P 4.1.18 - P2P Interface Attribute */ ++typedef struct _P2P_ATTRI_INTERFACE_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ ++ UINT_8 ucIfAddrCount; /* P2P Interface Address Count */ ++ UINT_8 aucIfAddrList[MAC_ADDR_LEN]; /* P2P Interface Address List */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTERFACE_T, *P_P2P_ATTRI_INTERFACE_T; ++ ++/* P2P 4.1.19 - Operating Channel Attribute */ ++typedef struct _P2P_ATTRI_OPERATING_CHANNEL_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucCountryString[3]; /* Country String */ ++ UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ ++ UINT_8 ucChannelNumber; /* Channel Number */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_OPERATING_CHANNEL_T, *P_P2P_ATTRI_OPERATING_CHANNEL_T; ++ ++/* P2P 4.1.20 - Invitation Flags Attribute */ ++typedef struct _P2P_ATTRI_INVITATION_FLAG_T { ++ UINT_8 ucId; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucInviteFlagsBitmap; /* Invitation Flags Bitmap */ ++} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INVITATION_FLAG_T, *P_P2P_ATTRI_INVITATION_FLAG_T; ++ ++/* P2P 4.1.1 - General WSC Attribute */ ++typedef struct _WSC_ATTRIBUTE_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRIBUTE_T, *P_WSC_ATTRIBUTE_T; ++ ++/* WSC 1.0 Table 28 */ ++typedef struct _WSC_ATTRI_VERSION_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 ucVersion; /* Version 1.0 or 1.1 */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_VERSION_T, *P_WSC_ATTRI_VERSION_T; ++ ++typedef struct _WSC_ATTRI_DEVICE_PASSWORD_ID_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2DevPasswordId; /* Device Password ID */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_DEVICE_PASSWORD_ID_T, *P_WSC_ATTRI_DEVICE_PASSWORD_ID_T; ++ ++typedef struct _WSC_ATTRI_CONFIGURATION_METHOD_T { ++ UINT_16 u2Id; /* Attribute ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_16 u2ConfigMethods; /* Configure Methods */ ++} __KAL_ATTRIB_PACKED__ WSC_ATTRI_CONFIGURATION_METHOD_T, *P_WSC_ATTRI_CONFIGURATION_METHOD_T; ++ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack() ++#endif ++ ++/* 3 --------------- WFA P2P Attributes Handler prototype --------------- */ ++typedef UINT_32(*PFN_APPEND_ATTRI_FUNC) (P_ADAPTER_T, BOOLEAN, PUINT_16, PUINT_8, UINT_16); ++ ++typedef VOID(*PFN_HANDLE_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T); ++ ++typedef VOID(*PFN_VERIFY_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T, PUINT_16); ++ ++typedef UINT_32(*PFN_CALCULATE_VAR_ATTRI_LEN_FUNC) (P_ADAPTER_T, P_STA_RECORD_T); ++ ++typedef struct _APPEND_VAR_ATTRI_ENTRY_T { ++ UINT_16 u2EstimatedFixedAttriLen; /* For fixed length */ ++ PFN_CALCULATE_VAR_ATTRI_LEN_FUNC pfnCalculateVariableAttriLen; ++ PFN_APPEND_ATTRI_FUNC pfnAppendAttri; ++} APPEND_VAR_ATTRI_ENTRY_T, *P_APPEND_VAR_ATTRI_ENTRY_T; ++ ++typedef enum _ENUM_CONFIG_METHOD_SEL { ++ ENUM_CONFIG_METHOD_SEL_AUTO, ++ ENUM_CONFIG_METHOD_SEL_USER, ++ ENUM_CONFIG_METHOD_SEL_NUM ++} ENUM_CONFIG_METHOD_SEL, *P_ENUM_CONFIG_METHOD_SEL; ++ ++typedef enum _ENUM_P2P_FORMATION_POLICY { ++ ENUM_P2P_FORMATION_POLICY_AUTO = 0, ++ ENUM_P2P_FORMATION_POLICY_PASSIVE, /* Device would wait GO NEGO REQ instead of sending it actively. */ ++ ENUM_P2P_FORMATION_POLICY_NUM ++} ENUM_P2P_FORMATION_POLICY, P_ENUM_P2P_FORMATION_POLICY; ++ ++typedef enum _ENUM_P2P_INVITATION_POLICY { ++ ENUM_P2P_INVITATION_POLICY_USER = 0, ++ ENUM_P2P_INVITATION_POLICY_ACCEPT_FIRST, ++ ENUM_P2P_INVITATION_POLICY_DENY_ALL, ++ ENUM_P2P_INVITATION_POLICY_NUM ++} ENUM_P2P_INVITATION_POLICY, P_ENUM_P2P_INVITATION_POLICY; ++ ++/* 3 --------------- Data Structure for P2P Operation --------------- */ ++/* 3 Session for CONNECTION SETTINGS of P2P */ ++struct _P2P_CONNECTION_SETTINGS_T { ++ UINT_8 ucDevNameLen; ++ UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; ++ ++ DEVICE_TYPE_T rPrimaryDevTypeBE; ++ ++ ENUM_P2P_FORMATION_POLICY eFormationPolicy; /* Formation Policy. */ ++ ++ /*------------WSC Related Param---------------*/ ++ UINT_16 u2ConfigMethodsSupport; /* Preferred configure method. ++ * Some device may not have keypad. ++ */ ++ ENUM_CONFIG_METHOD_SEL eConfigMethodSelType; ++ UINT_16 u2TargetConfigMethod; /* Configure method selected by user or auto. */ ++ UINT_16 u2LocalConfigMethod; /* Configure method of target. */ ++ BOOLEAN fgIsPasswordIDRdy; ++ /*------------WSC Related Param---------------*/ ++ ++ UINT_8 ucClientConfigTimeout; ++ UINT_8 ucGoConfigTimeout; ++ ++ UINT_8 ucSecondaryDevTypeCount; ++#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT ++ DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT]; ++#endif ++ ++#if 0 ++ UINT_8 ucRfChannelListCount; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT ++ UINT_8 aucChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering ++ depends on 802.11mb Annex J. */ ++ ++#endif ++#else ++ UINT_8 ucRfChannelListSize; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE ++ UINT_8 aucChannelEntriesField[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE]; ++#endif ++#endif ++ ++ /* Go Intent */ ++ UINT_8 ucTieBreaker; ++ UINT_8 ucGoIntent; ++ ++ /* For Device Capability */ ++ BOOLEAN fgSupportServiceDiscovery; ++ BOOLEAN fgSupportClientDiscoverability; ++ BOOLEAN fgSupportConcurrentOperation; ++ BOOLEAN fgSupportInfraManaged; ++ BOOLEAN fgSupportInvitationProcedure; ++ ++ /* For Group Capability */ ++ BOOLEAN fgSupportPersistentP2PGroup; ++ BOOLEAN fgSupportIntraBSSDistribution; ++ BOOLEAN fgSupportCrossConnection; ++ BOOLEAN fgSupportPersistentReconnect; ++ ++ BOOLEAN fgP2pGroupLimit; ++ ++ BOOLEAN fgSupportOppPS; ++ UINT_16 u2CTWindow; ++ ++ BOOLEAN fgIsScanReqIssued; ++ BOOLEAN fgIsServiceDiscoverIssued; ++ ++ /*============ Target Device Connection Settings ============*/ ++ ++ /* Discover Target Device Info. */ ++ BOOLEAN fgIsDevId; ++ BOOLEAN fgIsDevType; ++ ++ /* Encryption mode of Target Device */ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ /* SSID ++ * 1. AP Mode, this is the desired SSID user specified. ++ * 2. Client Mode, this is the target SSID to be connected to. ++ */ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ ++ /* Operating channel requested. */ ++ UINT_8 ucOperatingChnl; ++ ENUM_BAND_T eBand; ++ ++ /* Linten channel requested. */ ++ UINT_8 ucListenChnl; ++ ++ /* For device discover address/type. */ ++ UINT_8 aucTargetDevAddr[MAC_ADDR_LEN]; /* P2P Device Address, for P2P Device Discovery & P2P Connection. */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_DEVICE_DESC_T prTargetP2pDesc; ++#endif ++ ++ UINT_8 ucLastStatus; /* P2P FSM would append status attribute according to this field. */ ++ ++#if !CFG_DISABLE_DELAY_PROVISION_DISCOVERY ++ UINT_8 ucLastDialogToken; ++ UINT_8 aucIndicateDevAddr[MAC_ADDR_LEN]; ++#endif ++ ++#if 0 ++ UINT_8 ucTargetRfChannelListCount; ++#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT ++ UINT_8 aucTargetChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering ++ depends on 802.11mb Annex J. */ ++#endif ++#endif ++ ++}; ++ ++typedef struct _NOA_TIMING_T { ++ BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 ucCount; /* Count */ ++ ++ UINT_8 aucReserved[2]; ++ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} NOA_TIMING_T, *P_NOA_TIMING_T; ++ ++typedef enum _ENUM_P2P_IOCTL_T { ++ P2P_IOCTL_IDLE = 0, ++ P2P_IOCTL_DEV_DISCOVER, ++ P2P_IOCTL_INVITATION_REQ, ++ P2P_IOCTL_SERV_DISCOVER, ++ P2P_IOCTL_WAITING, ++ P2P_IOCTL_NUM ++} ENUM_P2P_IOCTL_T; ++ ++/*---------------- Service Discovery Related -------------------*/ ++typedef enum _ENUM_SERVICE_TX_TYPE_T { ++ ENUM_SERVICE_TX_TYPE_BY_DA, ++ ENUM_SERVICE_TX_TYPE_BY_CHNL, ++ ENUM_SERVICE_TX_TYPE_NUM ++} ENUM_SERVICE_TX_TYPE_T; ++ ++typedef struct _SERVICE_DISCOVERY_FRAME_DATA_T { ++ QUE_ENTRY_T rQueueEntry; ++ P_MSDU_INFO_T prSDFrame; ++ ENUM_SERVICE_TX_TYPE_T eServiceType; ++ UINT_8 ucSeqNum; ++ union { ++ ++ UINT_8 ucChannelNum; ++ UINT_8 aucPeerAddr[MAC_ADDR_LEN]; ++ } uTypeData; ++ BOOLEAN fgIsTxDoneIndicate; ++} SERVICE_DISCOVERY_FRAME_DATA_T, *P_SERVICE_DISCOVERY_FRAME_DATA_T; ++ ++struct _P2P_FSM_INFO_T_DEPRECATED { ++ /* P2P FSM State */ ++ ENUM_P2P_STATE_T eCurrentState; ++ ++ /* Channel */ ++ BOOLEAN fgIsChannelRequested; ++ ++ ENUM_P2P_STATE_T ePreviousState; ++ ++ ENUM_P2P_STATE_T eReturnState; /* Return state after current activity finished or abort. */ ++ ++ UINT_8 aucTargetIfAddr[PARAM_MAC_ADDR_LEN]; ++ P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ ++ ++ P_STA_RECORD_T prTargetStaRec; ++ ++ BOOLEAN fgIsRsponseProbe; /* Indicate if P2P FSM can response probe request frame. */ ++ ++ /* Sequence number of requested message. */ ++ UINT_8 ucSeqNumOfReqMsg; /* Used for SAA FSM request message. */ ++ ++ /* Channel Privilege */ ++ UINT_8 ucSeqNumOfChReq; /* Used for Channel Request message. */ ++ ++ UINT_8 ucSeqNumOfScnMsg; /* Used for SCAN FSM request message. */ ++ UINT_8 ucSeqNumOfCancelMsg; ++ ++ UINT_8 ucDialogToken; ++ UINT_8 ucRxDialogToken; ++ ++ /* Timer */ ++ TIMER_T rDeviceDiscoverTimer; /* For device discovery time of each discovery request from user. */ ++ TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ ++ TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ ++ ++ TIMER_T rRejoinTimer; /* A timer used for Action frame timeout usage. */ ++ ++ /* Flag to indicate Provisioning */ ++ BOOLEAN fgIsConnectionRequested; ++ ++ /* Current IOCTL. */ ++ ENUM_P2P_IOCTL_T eP2pIOCTL; ++ ++ UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ ++ ++ /*--------SERVICE DISCOVERY--------*/ ++ QUE_T rQueueGASRx; /* Input Request/Response. */ ++ QUE_T rQueueGASTx; /* Output Response. */ ++ P_SERVICE_DISCOVERY_FRAME_DATA_T prSDRequest; ++ UINT_8 ucVersionNum; /* GAS packet sequence number for...Action Frame? */ ++ UINT_8 ucGlobalSeqNum; /* Sequence Number of RX SD packet. */ ++ /*--------Service DISCOVERY--------*/ ++ ++ /*--------DEVICE DISCOVERY---------*/ ++ UINT_8 aucTargetGroupID[PARAM_MAC_ADDR_LEN]; ++ UINT_16 u2TargetGroupSsidLen; ++ UINT_8 aucTargetSsid[32]; ++ UINT_8 aucSearchingP2pDevice[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucDLToken; ++ /*----------------------------------*/ ++ ++ /* Indicating Peer Status. */ ++ UINT_32 u4Flags; ++ ++ /*Indicating current running mode. */ ++ BOOLEAN fgIsApMode; ++ ++ /*------------INVITATION------------*/ ++ ENUM_P2P_INVITATION_POLICY eInvitationRspPolicy; ++ /*----------------------------------*/ ++ ++}; ++ ++struct _P2P_SPECIFIC_BSS_INFO_T { ++ /* For GO(AP) Mode - Compose TIM IE */ ++ UINT_16 u2SmallestAID; ++ UINT_16 u2LargestAID; ++ UINT_8 ucBitmapCtrl; ++ /* UINT_8 aucPartialVirtualBitmap[MAX_LEN_TIM_PARTIAL_BMP]; */ ++ ++ /* For GC/GO OppPS */ ++ BOOLEAN fgEnableOppPS; ++ UINT_16 u2CTWindow; ++ ++ /* For GC/GO NOA */ ++ UINT_8 ucNoAIndex; ++ UINT_8 ucNoATimingCount; /* Number of NoA Timing */ ++ NOA_TIMING_T arNoATiming[P2P_MAXIMUM_NOA_COUNT]; ++ ++ BOOLEAN fgIsNoaAttrExisted; ++ ++ /* For P2P Device */ ++ UINT_8 ucRegClass; /* Regulatory Class for channel. */ ++ UINT_8 ucListenChannel; /* Linten Channel only on channels 1, 6 and 11 in the 2.4 GHz. */ ++ ++ UINT_8 ucPreferredChannel; /* Operating Channel, should be one of channel list ++ in p2p connection settings. */ ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_BAND_T eRfBand; ++ ++ /* Extended Listen Timing. */ ++ UINT_16 u2AvailabilityPeriod; ++ UINT_16 u2AvailabilityInterval; ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++ UINT_16 u2IELenForBCN; ++ UINT_8 aucBeaconIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++/* UINT_16 u2IELenForProbeRsp; */ ++/* UINT_8 aucProbeRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; */ ++ ++ UINT_16 u2IELenForAssocRsp; ++ UINT_8 aucAssocRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++#else ++ UINT_16 u2AttributeLen; ++ UINT_8 aucAttributesCache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++ ++ UINT_16 u2WscAttributeLen; ++ UINT_8 aucWscAttributesCache[WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; ++#endif ++ UINT_8 aucGroupID[MAC_ADDR_LEN]; ++ UINT_16 u2GroupSsidLen; ++ UINT_8 aucGroupSsid[ELEM_MAX_LEN_SSID]; ++ ++ PARAM_CUSTOM_NOA_PARAM_STRUCT_T rNoaParam; ++ PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T rOppPsParam; ++ ++ UINT_16 u2WpaIeLen; ++ UINT_8 aucWpaIeBuffer[ELEM_HDR_LEN + ELEM_MAX_LEN_WPA]; ++}; ++ ++typedef struct _MSG_P2P_DEVICE_DISCOVER_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_32 u4DevDiscoverTime; /* 0: Infinite, 1~X: in unit of MS. */ ++ BOOLEAN fgIsSpecificType; ++#if CFG_ENABLE_WIFI_DIRECT ++ P2P_DEVICE_TYPE_T rTargetDeviceType; ++#endif ++ UINT_8 aucTargetDeviceID[MAC_ADDR_LEN]; ++} MSG_P2P_DEVICE_DISCOVER_T, *P_MSG_P2P_DEVICE_DISCOVER_T; ++ ++typedef struct _MSG_P2P_INVITATION_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 aucDeviceID[MAC_ADDR_LEN]; /* Target Device ID to be invited. */ ++} MSG_P2P_INVITATION_REQUEST_T, *P_MSG_P2P_INVITATION_REQUEST_T; ++ ++typedef struct _MSG_P2P_FUNCTION_SWITCH_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ BOOLEAN fgIsFuncOn; ++} MSG_P2P_FUNCTION_SWITCH_T, *P_MSG_P2P_FUNCTION_SWITCH_T; ++ ++typedef struct _MSG_P2P_SERVICE_DISCOVERY_REQUEST_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 aucDeviceID[MAC_ADDR_LEN]; ++ BOOLEAN fgNeedTxDoneIndicate; ++ UINT_8 ucSeqNum; ++} MSG_P2P_SERVICE_DISCOVERY_REQUEST_T, *P_MSG_P2P_SERVICE_DISCOVERY_REQUEST_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define p2pChangeMediaState(_prAdapter, _eNewMediaState) \ ++do { \ ++ (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState = (_eNewMediaState));\ ++ wfdChangeMediaState((_prAdapter), NETWORK_TYPE_P2P_INDEX, (_eNewMediaState)); \ ++} while (0) ++ ++#define ATTRI_ID(_fp) (((P_P2P_ATTRIBUTE_T) _fp)->ucId) ++#define ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[0]) | \ ++ ((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[1] << 8)) ++ ++#define ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + ATTRI_LEN(_fp)) ++ ++#define P2P_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += ATTRI_SIZE(_pucAttriBuf))) ++ ++#define P2P_IE(_fp) ((P_IE_P2P_T) _fp) ++ ++#define WSC_ATTRI_ID(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[1])) ++ ++#define WSC_ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[1])) ++ ++#define WSC_ATTRI_SIZE(_fp) (WSC_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) ++ ++#define WSC_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += WSC_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WSC_ATTRI_SIZE(_pucAttriBuf))) ++ ++#define WSC_IE(_fp) ((P_IE_P2P_T) _fp) ++ ++#define WFD_ATTRI_ID(_fp) (((P_WFD_ATTRIBUTE_T) _fp)->ucElemID) ++ ++#define WFD_ATTRI_LEN(_fp) \ ++ (((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ ++ ((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[1])) ++ ++#define WFD_ATTRI_SIZE(_fp) (WFD_ATTRI_HDR_LEN + WFD_ATTRI_LEN(_fp)) ++ ++#define WFD_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ ++ (_u2Offset) += WFD_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WFD_ATTRI_SIZE(_pucAttriBuf))) ++ ++#if DBG ++#define ASSERT_BREAK(_exp) \ ++ { \ ++ if (!(_exp)) { \ ++ ASSERT(FALSE); \ ++ break; \ ++ } \ ++ } ++ ++#else ++#define ASSERT_BREAK(_exp) ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*======P2P State======*/ ++VOID ++p2pStateInit_LISTEN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prSP2pBssInfo, IN UINT_8 ucListenChannel); ++ ++VOID p2pStateAbort_LISTEN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); ++ ++VOID p2pStateAbort_SEARCH_SCAN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); ++ ++VOID p2pStateAbort_GO_OPERATION(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateAbort_GC_OPERATION(IN P_ADAPTER_T prAdapter); ++ ++VOID ++p2pStateInit_CONFIGURATION(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecBssInfo); ++ ++VOID p2pStateAbort_CONFIGURATION(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateInit_JOIN(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pStateAbort_JOIN(IN P_ADAPTER_T prAdapter); ++ ++/*====== P2P Functions ======*/ ++ ++VOID p2pFuncInitGO(IN P_ADAPTER_T prAdapter); ++ ++VOID ++p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++VOID ++p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW); ++ ++VOID p2pFuncRunEventProvisioningComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++WLAN_STATUS p2pFuncSetGroupID(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucGroupID, IN PUINT_8 pucSsid, IN UINT_8 ucSsidLen); ++ ++WLAN_STATUS ++p2pFuncSendDeviceDiscoverabilityReqFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); ++ ++WLAN_STATUS ++p2pFuncSendDeviceDiscoverabilityRspFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); ++ ++UINT_8 p2pFuncGetVersionNumOfSD(IN P_ADAPTER_T prAdapter); ++ ++/*====== P2P FSM ======*/ ++VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDeviceDiscoveryRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventDeviceDiscoveryAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventRxGroupNegotiationReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationResponseTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventGroupNegotiationConfirmTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventProvisionDiscoveryRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventProvisionDiscoveryResponseTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++WLAN_STATUS ++p2pFsmRunEventInvitationRequestTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if 1 ++#endif ++ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/* //////////////////////////////////////////////////////////////////////// */ ++/*======Mail Box Event Message=====*/ ++ ++VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventConnectionTrigger(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventP2PFunctionSwitch(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventConnectionPause(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID ++p2pIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN UINT_8 aucTargetAddr[]); ++ ++VOID p2pUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++ ++/*======Mail Box Event Message=====*/ ++ ++VOID p2pFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStartGO(IN P_ADAPTER_T prAdapter); ++ ++VOID p2pAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); ++ ++VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID p2pFsmRunEventIOReqTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); ++ ++VOID p2pFsmRunEventSearchPeriodTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); ++ ++VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG u4Param); ++ ++VOID p2pFsmRunEventRejoinTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Parm); ++ ++/*=============== P2P Function Related ================*/ ++ ++/*=============== P2P Function Related ================*/ ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID p2pTest(IN P_ADAPTER_T prAdapter); ++#endif /* CFG_TEST_WIFI_DIRECT_GO */ ++ ++VOID p2pGenerateP2P_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID p2pGenerateP2P_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pCalculateP2P_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pCalculateP2P_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pGenerateWSC_IEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID ++p2pGenerateWSC_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_16 p2pCalculateWSC_IELenForProbeReq(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++UINT_32 ++p2pCalculateWSC_IELenForProbeResp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriStatus(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriGoIntent(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriCfgTimeout(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriGroupBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForBeacon(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceIDForDeviceDiscoveryReq(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriListenChannel(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriIntendP2pIfAddr(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriChannelList(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenChannelList(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriNoA(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriDeviceInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenDeviceInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriGroupInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 p2pCalculateAttriLenGroupInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++p2pAppendAttriP2pGroupID(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriOperatingChannel(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriInvitationFlag(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++VOID ++p2pGenerateWscIE(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++UINT_32 ++p2pAppendAttriWSCConfigMethod(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCVersion(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCGONegReqDevPasswordId(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pAppendAttriWSCGONegRspDevPasswordId(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++WLAN_STATUS ++p2pGetWscAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++WLAN_STATUS ++p2pGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS p2pSendProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN p2pFsmRunEventRxProbeRequestFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc); ++ ++WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxGroupNegotiationRspFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID p2pFsmRunEventRxGroupNegotiationCfmFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#if 0 /* frog */ ++BOOLEAN scanMatchFilterOfP2P(IN P_SW_RFB_T prSWRfb, IN PP_BSS_DESC_T pprBssDesc); ++#endif /* frog */ ++ ++VOID ++p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); ++ ++VOID p2pFuncCompleteIOCTL(IN P_ADAPTER_T prAdapter, IN WLAN_STATUS rWlanStatus); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#ifndef _lint ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID p2pDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(IE_P2P_T) == (2 + 4 + 1)); /* all UINT_8 */ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRIBUTE_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_STATUS_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_REASON_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CAPABILITY_T) == (3 + 2)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_ID_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GO_INTENT_T) == (3 + 1)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CFG_TIMEOUT_T) == (3 + 2)); ++#if CID52_53_54 ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); ++#else ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); ++#endif ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_BSSID_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_EXT_LISTEN_TIMING_T) == (3 + 4)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTENDED_IF_ADDR_T) == (3 + 6)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_MANAGEABILITY_T) == (3 + 1)); ++ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CHANNEL_T) == (3 + 4)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(CHANNEL_ENTRY_FIELD_T) == 3); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_NOA_T) == (3 + 3)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(NOA_DESCRIPTOR_T) == 13); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_TYPE_T) == 8); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_INFO_T) == (3 + 6 + 2 + 8 + 1 + 8)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_NAME_TLV_T) == (4 + 32)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_CLIENT_INFO_DESC_T) == (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_INFO_T) == (3 + (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8))); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_ID_T) == (3 + 38)); ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTERFACE_T) == (3 + 13)); ++#if CID52_53_54 ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); ++#else ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); ++#endif ++ ++} ++#endif /* _lint */ ++ ++#endif /* _P2P_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h +new file mode 100644 +index 000000000000..1ac1770debca +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h +@@ -0,0 +1,155 @@ ++#ifndef _P2P_FUNC_H ++#define _P2P_FUNC_H ++ ++#define P2P_EXT_LISTEN_TIME_MS 600 ++#define P2P_OFF_CHNL_TX_DEFAULT_TIME_MS 1000 ++ ++VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID ++p2pFuncStartGO(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, ++ IN PUINT_8 pucSsidBuf, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP); ++ ++VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo); ++ ++BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo); ++ ++VOID ++p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); ++ ++WLAN_STATUS ++p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); ++ ++WLAN_STATUS ++p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, ++ IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, ++ IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen); ++ ++BOOLEAN ++p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings); ++ ++BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); ++ ++BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen); ++ ++P_BSS_DESC_T ++p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, ++ IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); ++ ++VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID ++p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, ++ IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter); ++ ++VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter); ++ ++VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo); ++ ++BOOLEAN ++p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); ++ ++P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu); ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++UINT_32 ++p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#else ++UINT_32 ++p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++#endif ++UINT_32 ++p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_STA_RECORD_T prStaRec, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++VOID ++p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); ++ ++UINT_32 ++p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++VOID ++p2pFuncDissolve(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++P_IE_HDR_T ++p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore); ++ ++P_ATTRIBUTE_HDR_T ++p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID); ++ ++WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, ++ IN ENUM_PARAM_MEDIA_STATE_T eConnectionState); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h +new file mode 100644 +index 000000000000..efb75855695f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h +@@ -0,0 +1,156 @@ ++#ifndef _P2P_IE_H ++#define _P2P_IE_H ++ ++#if CFG_SUPPORT_WFD ++ ++#define ELEM_MAX_LEN_WFD 62 /* TODO: Move to appropriate place */ ++ ++/*---------------- WFD Data Element Definitions ----------------*/ ++/* WFD 4.1.1 - WFD IE format */ ++#define WFD_OUI_TYPE_LEN 4 ++#define WFD_IE_OUI_HDR (ELEM_HDR_LEN + WFD_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, ++ aucP2PAttributes[0]) */ ++ ++/* WFD 4.1.1 - General WFD Attribute */ ++#define WFD_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ ++ ++/* WFD Attribute Code */ ++#define WFD_ATTRI_ID_DEV_INFO 0 ++#define WFD_ATTRI_ID_ASSOC_BSSID 1 ++#define WFD_ATTRI_ID_COUPLED_SINK_INFO 6 ++#define WFD_ATTRI_ID_EXT_CAPABILITY 7 ++#define WFD_ATTRI_ID_SESSION_INFO 9 ++#define WFD_ATTRI_ID_ALTER_MAC_ADDRESS 10 ++ ++/* Maximum Length of WFD Attributes */ ++#define WFD_ATTRI_MAX_LEN_DEV_INFO 6 /* 0 */ ++#define WFD_ATTRI_MAX_LEN_ASSOC_BSSID 6 /* 1 */ ++#define WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO 7 /* 6 */ ++#define WFD_ATTRI_MAX_LEN_EXT_CAPABILITY 2 /* 7 */ ++#define WFD_ATTRI_MAX_LEN_SESSION_INFO 0 /* 9 */ /* 24 * #Clients */ ++#define WFD_ATTRI_MAX_LEN_ALTER_MAC_ADDRESS 6 /* 10 */ ++ ++/* WFD 1.10 5.1.1 */ ++typedef struct _IE_WFD_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 aucWFDAttributes[1]; /* WFD Subelement */ ++} __KAL_ATTRIB_PACKED__ IE_WFD_T, *P_IE_WFD_T; ++ ++typedef struct _WFD_ATTRIBUTE_T { ++ UINT_8 ucElemID; /* Subelement ID */ ++ UINT_16 u2Length; /* Length */ ++ UINT_8 aucBody[1]; /* Body field */ ++} __KAL_ATTRIB_PACKED__ WFD_ATTRIBUTE_T, *P_WFD_ATTRIBUTE_T; ++ ++typedef struct _WFD_DEVICE_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2SessionMgmtCtrlPort; ++ UINT_16 u2WfdDevMaxSpeed; ++} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_IE_T, *P_WFD_DEVICE_INFORMATION_IE_T; ++ ++typedef struct _WFD_ASSOCIATED_BSSID_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_8 aucAssocBssid[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_ASSOCIATED_BSSID_IE_T, *P_WFD_ASSOCIATED_BSSID_IE_T; ++ ++typedef struct _WFD_COUPLE_SINK_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_8 ucCoupleSinkStatusBp; ++ UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_COUPLE_SINK_INFORMATION_IE_T, *P_WFD_COUPLE_SINK_INFORMATION_IE_T; ++ ++typedef struct _WFD_EXTENDED_CAPABILITY_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ UINT_16 u2WfdExtCapabilityBp; ++} __KAL_ATTRIB_PACKED__ WFD_EXTENDED_CAPABILITY_IE_T, *P_WFD_EXTENDED_CAPABILITY_IE_T; ++ ++typedef struct _WFD_SESSION_INFORMATION_IE_T { ++ UINT_8 ucElemID; ++ UINT_16 u2Length; ++ PUINT_8 pucWfdDevInfoDesc[1]; ++} __KAL_ATTRIB_PACKED__ WFD_SESSION_INFORMATION_IE_T, *P_WFD_SESSION_INFORMATION_IE_T; ++ ++typedef struct _WFD_DEVICE_INFORMATION_DESCRIPTOR_T { ++ UINT_8 ucLength; ++ UINT_8 aucDevAddr[MAC_ADDR_LEN]; ++ UINT_8 aucAssocBssid[MAC_ADDR_LEN]; ++ UINT_16 u2WfdDevInfo; ++ UINT_16 u2WfdDevMaxSpeed; ++ UINT_8 ucCoupleSinkStatusBp; ++ UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_DESCRIPTOR_T, *P_WFD_DEVICE_INFORMATION_DESCRIPTOR_T; ++ ++#endif ++ ++UINT_32 ++p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#if CFG_SUPPORT_WFD ++ ++UINT_32 ++wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_32 ++wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForProbeResp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++VOID wfdFuncGenerateWfdIEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#endif ++ ++UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec); ++ ++VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h +new file mode 100644 +index 000000000000..32bc14c10959 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h +@@ -0,0 +1,74 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm.h#1 ++*/ ++ ++/*! \file "rlm.h" ++ \brief ++*/ ++ ++#ifndef _P2P_RLM_H ++#define _P2P_RLM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); ++ ++VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter); ++ ++VOID ++rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, ++ IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize); ++ ++UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum); ++ ++BOOLEAN ++rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCheckChnl, ++ IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel); ++ ++ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h +new file mode 100644 +index 000000000000..5b6e756f48dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h +@@ -0,0 +1,64 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm_obss.h#1 ++*/ ++ ++/*! \file "rlm_obss.h" ++ \brief ++*/ ++ ++#ifndef _P2P_RLM_OBSS_H ++#define _P2P_RLM_OBSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); ++ ++UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h +new file mode 100644 +index 000000000000..8db6aa5c31e0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h +@@ -0,0 +1,81 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_scan.h#1 ++*/ ++ ++/*! \file "scan.h" ++ \brief ++ ++*/ ++ ++#ifndef _P2P_SCAN_H ++#define _P2P_SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); ++ ++P_P2P_DEVICE_DESC_T ++scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc); ++ ++P_P2P_DEVICE_DESC_T ++scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, ++ IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound); ++ ++P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum); ++ ++BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ++scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); ++ ++VOID scanRemoveAllP2pBssDesc(P_ADAPTER_T prAdapter); ++ ++VOID scanRemoveP2pBssDesc(P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++P_BSS_DESC_T ++scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h +new file mode 100644 +index 000000000000..8f0c4c1564a8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h +@@ -0,0 +1,43 @@ ++#ifndef _P2P_STATE_H ++#define _P2P_STATE_H ++ ++BOOLEAN ++p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState); ++ ++VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++VOID ++p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++VOID ++p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc); ++ ++VOID ++p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h +new file mode 100644 +index 000000000000..c80430ae4eb5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h +@@ -0,0 +1,230 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/privacy.h#1 ++*/ ++ ++/*! \file privacy.h ++ \brief This file contains the function declaration for privacy.c. ++*/ ++ ++/* ++** Log: privacy.h ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * For support the WHQL test, do the remove key code refine. ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the cmd return type ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for auth mode and encryption status setting from build connection command ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for wapi ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the tx done callback handle function ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function declaration for mac header privacy bit setting ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the structure for parsing the EAPoL frame ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the class error function parameter ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security function declaration ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the ap selection structure ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++#ifndef _PRIVACY_H ++#define _PRIVACY_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_KEY_NUM 4 ++#define WEP_40_LEN 5 ++#define WEP_104_LEN 13 ++#define LEGACY_KEY_MAX_LEN 16 ++#define CCMP_KEY_LEN 16 ++#define TKIP_KEY_LEN 32 ++#define MAX_KEY_LEN 32 ++#define MIC_RX_KEY_OFFSET 16 ++#define MIC_TX_KEY_OFFSET 24 ++#define MIC_KEY_LEN 8 ++ ++#define WEP_KEY_ID_FIELD BITS(0, 29) ++#define KEY_ID_FIELD BITS(0, 7) ++ ++#define IS_TRANSMIT_KEY BIT(31) ++#define IS_UNICAST_KEY BIT(30) ++#define IS_AUTHENTICATOR BIT(28) ++ ++#define CIPHER_SUITE_NONE 0 ++#define CIPHER_SUITE_WEP40 1 ++#define CIPHER_SUITE_TKIP 2 ++#define CIPHER_SUITE_TKIP_WO_MIC 3 ++#define CIPHER_SUITE_CCMP 4 ++#define CIPHER_SUITE_WEP104 5 ++#define CIPHER_SUITE_BIP 6 ++#define CIPHER_SUITE_WEP128 7 ++#define CIPHER_SUITE_WPI 8 ++ ++#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ ++#define WPA_KEY_INFO_MIC BIT(8) ++#define WPA_KEY_INFO_SECURE BIT(9) ++ ++#define MASK_2ND_EAPOL (WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _IEEE_802_1X_HDR { ++ UINT_8 ucVersion; ++ UINT_8 ucType; ++ UINT_16 u2Length; ++ /* followed by length octets of data */ ++} IEEE_802_1X_HDR, *P_IEEE_802_1X_HDR; ++ ++typedef struct _EAPOL_KEY { ++ UINT_8 ucType; ++ /* Note: key_info, key_length, and key_data_length are unaligned */ ++ UINT_8 aucKeyInfo[2]; /* big endian */ ++ UINT_8 aucKeyLength[2]; /* big endian */ ++ UINT_8 aucReplayCounter[8]; ++ UINT_8 aucKeyNonce[16]; ++ UINT_8 aucKeyIv[16]; ++ UINT_8 aucKeyRsc[8]; ++ UINT_8 aucKeyId[8]; /* Reserved in IEEE 802.11i/RSN */ ++ UINT_8 aucKeyMic[16]; ++ UINT_8 aucKeyDataLength[2]; /* big endian */ ++ /* followed by key_data_length bytes of key_data */ ++} EAPOL_KEY, *P_EAPOL_KEY; ++ ++/* WPA2 PMKID candicate structure */ ++typedef struct _PMKID_CANDICATE_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_32 u4PreAuthFlags; ++} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; ++ ++#if 0 ++/* WPA2 PMKID cache structure */ ++typedef struct _PMKID_ENTRY_T { ++ PARAM_BSSID_INFO_T rBssidInfo; ++ BOOLEAN fgPmkidExist; ++} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx); ++ ++VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPort); ++ ++BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec); ++ ++BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); ++ ++VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags); ++ ++BOOLEAN ++secProcessEAPOL(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen); ++ ++VOID ++secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T pMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus); ++ ++BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec); ++ ++VOID secClearPmkid(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PRIVACY_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h +new file mode 100644 +index 000000000000..123dbebdacaf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h +@@ -0,0 +1,93 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rate.h#1 ++*/ ++ ++/*! \file rate.h ++ \brief This file contains the rate utility function of ++ IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: rate.h ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++*/ ++ ++#ifndef _RATE_H ++#define _RATE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in rate.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, ++ IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, ++ OUT PUINT_16 pu2OperationalRateSet, ++ OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate); ++ ++VOID ++rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen); ++ ++BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex); ++ ++BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RATE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h +new file mode 100644 +index 000000000000..1af3841ecec2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h +@@ -0,0 +1,396 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm.h#2 ++*/ ++ ++/*! \file "rlm.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Use SCO of BSS_INFO to replace user-defined setting variables ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 18 2010 cm.chang ++ * [WCXRP00000114] [MT6620 Wi-Fi] [Driver] Fix compiling warning in Linux about RLM network index checking ++ * Enum member cannot be used as compiling option decision in Linux ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX HT GF compiling option ++ * ++ * 06 02 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Roll back to remove CFG_SUPPORT_BCM_TEST. ++ * ++ * 06 01 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Update BCM Test and RW configuration. ++ * ++ * 05 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some compiling options to control 11n functions ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 17 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * MT6620 does not support L-SIG TXOP ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Move default value of HT capability to rlm.h ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * ++ * Modify the prototype of rlmRecAssocRspHtInfo() ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add several function prototypes for HT operation ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++#ifndef _RLM_H ++#define _RLM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define ELEM_EXT_CAP_DEFAULT_VAL \ ++ (ELEM_EXT_CAP_20_40_COEXIST_SUPPORT /*| ELEM_EXT_CAP_PSMP_CAP*/) ++ ++#if CFG_SUPPORT_RX_STBC ++#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_1_SS ++#else ++#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_NO_SUPPORTED ++#endif ++ ++#if CFG_SUPPORT_RX_SGI ++#define FIELD_HT_CAP_INFO_SGI_20M HT_CAP_INFO_SHORT_GI_20M ++#define FIELD_HT_CAP_INFO_SGI_40M HT_CAP_INFO_SHORT_GI_40M ++#else ++#define FIELD_HT_CAP_INFO_SGI_20M 0 ++#define FIELD_HT_CAP_INFO_SGI_40M 0 ++#endif ++ ++#if CFG_SUPPORT_RX_HT_GF ++#define FIELD_HT_CAP_INFO_HT_GF HT_CAP_INFO_HT_GF ++#else ++#define FIELD_HT_CAP_INFO_HT_GF 0 ++#endif ++ ++#define HT_CAP_INFO_DEFAULT_VAL \ ++ (HT_CAP_INFO_SUP_CHNL_WIDTH | FIELD_HT_CAP_INFO_HT_GF | \ ++ FIELD_HT_CAP_INFO_SGI_20M | FIELD_HT_CAP_INFO_SGI_40M | \ ++ FIELD_HT_CAP_INFO_RX_STBC | HT_CAP_INFO_DSSS_CCK_IN_40M) ++ ++#define AMPDU_PARAM_DEFAULT_VAL \ ++ (AMPDU_PARAM_MAX_AMPDU_LEN_64K | AMPDU_PARAM_MSS_NO_RESTRICIT) ++ ++#define SUP_MCS_TX_DEFAULT_VAL \ ++ SUP_MCS_TX_SET_DEFINED /* TX defined and TX/RX equal (TBD) */ ++ ++#if CFG_SUPPORT_MFB ++#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_BOTH ++#else ++#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_NO_FB ++#endif ++ ++#if CFG_SUPPORT_RX_RDG ++#define FIELD_HT_EXT_CAP_RDR HT_EXT_CAP_RD_RESPONDER ++#else ++#define FIELD_HT_EXT_CAP_RDR 0 ++#endif ++ ++#if CFG_SUPPORT_MFB || CFG_SUPPORT_RX_RDG ++#define FIELD_HT_EXT_CAP_HTC HT_EXT_CAP_HTC_SUPPORT ++#else ++#define FIELD_HT_EXT_CAP_HTC 0 ++#endif ++ ++#define HT_EXT_CAP_DEFAULT_VAL \ ++ (HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE | \ ++ FIELD_HT_EXT_CAP_MFB | FIELD_HT_EXT_CAP_HTC | \ ++ FIELD_HT_EXT_CAP_RDR) ++ ++#define TX_BEAMFORMING_CAP_DEFAULT_VAL 0 ++#define ASEL_CAP_DEFAULT_VAL 0 ++ ++/* Define bandwidth from user setting */ ++#define CONFIG_BW_20_40M 0 ++#define CONFIG_BW_20M 1 /* 20MHz only */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* It is used for RLM module to judge if specific network is valid ++ * Note: Ad-hoc mode of AIS is not included now. (TBD) ++ */ ++#define RLM_NET_PARAM_VALID(_prBssInfo) \ ++ (IS_BSS_ACTIVE(_prBssInfo) && \ ++ ((_prBssInfo)->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || \ ++ (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT || \ ++ (_prBssInfo)->eCurrentOPMode == OP_MODE_IBSS || \ ++ RLM_NET_IS_BOW(_prBssInfo)) \ ++ ) ++ ++#define RLM_NET_IS_11N(_prBssInfo) \ ++ ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11N) ++#define RLM_NET_IS_11GN(_prBssInfo) \ ++ ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11GN) ++ ++/* This macro is used to sweep all 3 networks */ ++#define RLM_NET_FOR_EACH(_ucNetIdx) \ ++ for ((_ucNetIdx) = 0; \ ++ (_ucNetIdx) < NETWORK_TYPE_INDEX_NUM; \ ++ (_ucNetIdx)++) ++ ++/* This macro is used to sweep all networks excluding BOW */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /* Note: value of enum NETWORK_TYPE_BOW_INDEX is validated in ++ * rlmStuctureCheck(). ++ */ ++#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) \ ++ for ((_ucNetIdx) = 0; \ ++ (_ucNetIdx) < NETWORK_TYPE_BOW_INDEX; \ ++ (_ucNetIdx)++) ++ ++#define RLM_NET_IS_BOW(_prBssInfo) \ ++ ((_prBssInfo)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ ++#else ++#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) RLM_NET_FOR_EACH(_ucNetIdx) ++#define RLM_NET_IS_BOW(_prBssInfo) (FALSE) ++ ++#endif /* end of CFG_ENABLE_BT_OVER_WIFI */ ++ ++/* The bandwidth modes are not used anymore. They represent if AP ++ * can use 20/40 bandwidth, not all modes. (20110411) ++ */ ++#define RLM_AP_IS_BW_40_ALLOWED(_prAdapter, _prBssInfo) \ ++ (((_prBssInfo)->eBand == BAND_2G4 && \ ++ (_prAdapter)->rWifiVar.rConnSettings.uc2G4BandwidthMode \ ++ == CONFIG_BW_20_40M) || \ ++ ((_prBssInfo)->eBand == BAND_5G && \ ++ (_prAdapter)->rWifiVar.rConnSettings.uc5GBandwidthMode \ ++ == CONFIG_BW_20_40M)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID rlmFsmEventInit(P_ADAPTER_T prAdapter); ++ ++VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter); ++ ++VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++UINT32 ++rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, ++ BOOLEAN fgShortGIDisabled, ++ UINT_8 u8SupportRxSgi20, ++ UINT_8 u8SupportRxSgi40, ++ UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf); ++ ++UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme); ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE); ++#endif ++ ++VOID ++rlmTxRateEnhanceConfig( ++ P_ADAPTER_T prAdapter ++ ); ++ ++VOID ++rlmCmd( ++ P_GLUE_INFO_T prGlueInfo, ++ UINT_8 *prInBuf, ++ UINT_32 u4InBufLen ++ ); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#ifndef _lint ++static inline VOID rlmDataTypeCheck(VOID) ++{ ++#if CFG_ENABLE_BT_OVER_WIFI ++ DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_AIS_INDEX < NETWORK_TYPE_BOW_INDEX); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_P2P_INDEX < NETWORK_TYPE_BOW_INDEX); ++#endif ++#endif ++ ++} ++#endif /* _lint */ ++ ++#endif /* _RLM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h +new file mode 100644 +index 000000000000..65e907041a28 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h +@@ -0,0 +1,557 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_domain.h#1 ++*/ ++ ++/*! \file "rlm_domain.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_domain.h ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Provide legal channel function based on domain ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 01 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide query function about full channel list. ++ * ++ * Dec 1 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Declare public rDomainInfo ++ * ++** ++*/ ++ ++#ifndef _RLM_DOMAIN_H ++#define _RLM_DOMAIN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_SUBBAND_NUM 6 ++#define MAX_SUBBAND_NUM_5G 8 ++ ++#define COUNTRY_CODE_NULL ((UINT_16)0x0) ++ ++/* ISO/IEC 3166-1 two-character country codes */ ++ ++#define COUNTRY_CODE_AD (((UINT_16) 'A' << 8) | (UINT_16) 'D') /* Andorra */ ++#define COUNTRY_CODE_AE (((UINT_16) 'A' << 8) | (UINT_16) 'E') /* UAE */ ++#define COUNTRY_CODE_AF (((UINT_16) 'A' << 8) | (UINT_16) 'F') /* Afghanistan */ ++#define COUNTRY_CODE_AG (((UINT_16) 'A' << 8) | (UINT_16) 'G') /* Antigua & Barbuda */ ++#define COUNTRY_CODE_AI (((UINT_16) 'A' << 8) | (UINT_16) 'I') /* Anguilla */ ++#define COUNTRY_CODE_AL (((UINT_16) 'A' << 8) | (UINT_16) 'L') /* Albania */ ++#define COUNTRY_CODE_AM (((UINT_16) 'A' << 8) | (UINT_16) 'M') /* Armenia */ ++#define COUNTRY_CODE_AN (((UINT_16) 'A' << 8) | (UINT_16) 'N') /* Netherlands Antilles */ ++#define COUNTRY_CODE_AO (((UINT_16) 'A' << 8) | (UINT_16) 'O') /* Angola */ ++#define COUNTRY_CODE_AR (((UINT_16) 'A' << 8) | (UINT_16) 'R') /* Argentina */ ++#define COUNTRY_CODE_AS (((UINT_16) 'A' << 8) | (UINT_16) 'S') /* American Samoa (USA) */ ++#define COUNTRY_CODE_AT (((UINT_16) 'A' << 8) | (UINT_16) 'T') /* Austria */ ++#define COUNTRY_CODE_AU (((UINT_16) 'A' << 8) | (UINT_16) 'U') /* Australia */ ++#define COUNTRY_CODE_AW (((UINT_16) 'A' << 8) | (UINT_16) 'W') /* Aruba */ ++#define COUNTRY_CODE_AZ (((UINT_16) 'A' << 8) | (UINT_16) 'Z') /* Azerbaijan */ ++#define COUNTRY_CODE_BA (((UINT_16) 'B' << 8) | (UINT_16) 'A') /* Bosnia and Herzegovina */ ++#define COUNTRY_CODE_BB (((UINT_16) 'B' << 8) | (UINT_16) 'B') /* Barbados */ ++#define COUNTRY_CODE_BD (((UINT_16) 'B' << 8) | (UINT_16) 'D') /* Bangladesh */ ++#define COUNTRY_CODE_BE (((UINT_16) 'B' << 8) | (UINT_16) 'E') /* Belgium */ ++#define COUNTRY_CODE_BF (((UINT_16) 'B' << 8) | (UINT_16) 'F') /* Burkina Faso */ ++#define COUNTRY_CODE_BG (((UINT_16) 'B' << 8) | (UINT_16) 'G') /* Bulgaria */ ++#define COUNTRY_CODE_BH (((UINT_16) 'B' << 8) | (UINT_16) 'H') /* Bahrain */ ++#define COUNTRY_CODE_BI (((UINT_16) 'B' << 8) | (UINT_16) 'I') /* Burundi */ ++#define COUNTRY_CODE_BJ (((UINT_16) 'B' << 8) | (UINT_16) 'J') /* Benin */ ++#define COUNTRY_CODE_BM (((UINT_16) 'B' << 8) | (UINT_16) 'M') /* Bermuda */ ++#define COUNTRY_CODE_BN (((UINT_16) 'B' << 8) | (UINT_16) 'N') /* Brunei */ ++#define COUNTRY_CODE_BO (((UINT_16) 'B' << 8) | (UINT_16) 'O') /* Bolivia */ ++#define COUNTRY_CODE_BR (((UINT_16) 'B' << 8) | (UINT_16) 'R') /* Brazil */ ++#define COUNTRY_CODE_BS (((UINT_16) 'B' << 8) | (UINT_16) 'S') /* Bahamas */ ++#define COUNTRY_CODE_BT (((UINT_16) 'B' << 8) | (UINT_16) 'T') /* Bhutan */ ++#define COUNTRY_CODE_BW (((UINT_16) 'B' << 8) | (UINT_16) 'W') /* Botswana */ ++#define COUNTRY_CODE_BY (((UINT_16) 'B' << 8) | (UINT_16) 'Y') /* Belarus */ ++#define COUNTRY_CODE_BZ (((UINT_16) 'B' << 8) | (UINT_16) 'Z') /* Belize */ ++#define COUNTRY_CODE_CA (((UINT_16) 'C' << 8) | (UINT_16) 'A') /* Canada */ ++#define COUNTRY_CODE_CD (((UINT_16) 'C' << 8) | (UINT_16) 'D') /* Congo. Democratic Republic of the */ ++#define COUNTRY_CODE_CF (((UINT_16) 'C' << 8) | (UINT_16) 'F') /* Central African Republic */ ++#define COUNTRY_CODE_CG (((UINT_16) 'C' << 8) | (UINT_16) 'G') /* Congo. Republic of the */ ++#define COUNTRY_CODE_CH (((UINT_16) 'C' << 8) | (UINT_16) 'H') /* Switzerland */ ++#define COUNTRY_CODE_CI (((UINT_16) 'C' << 8) | (UINT_16) 'I') /* Cote d'lvoire */ ++#define COUNTRY_CODE_CK (((UINT_16) 'C' << 8) | (UINT_16) 'K') /* Cook Island */ ++#define COUNTRY_CODE_CL (((UINT_16) 'C' << 8) | (UINT_16) 'L') /* Chile */ ++#define COUNTRY_CODE_CM (((UINT_16) 'C' << 8) | (UINT_16) 'M') /* Cameroon */ ++#define COUNTRY_CODE_CN (((UINT_16) 'C' << 8) | (UINT_16) 'N') /* China */ ++#define COUNTRY_CODE_CO (((UINT_16) 'C' << 8) | (UINT_16) 'O') /* Columbia */ ++#define COUNTRY_CODE_CR (((UINT_16) 'C' << 8) | (UINT_16) 'R') /* Costa Rica */ ++#define COUNTRY_CODE_CU (((UINT_16) 'C' << 8) | (UINT_16) 'U') /* Cuba */ ++#define COUNTRY_CODE_CV (((UINT_16) 'C' << 8) | (UINT_16) 'V') /* Cape Verde */ ++#define COUNTRY_CODE_CX (((UINT_16) 'C' << 8) | (UINT_16) 'X') /* "Christmas Island(Australia) */ ++#define COUNTRY_CODE_CY (((UINT_16) 'C' << 8) | (UINT_16) 'Y') /* Cyprus */ ++#define COUNTRY_CODE_CZ (((UINT_16) 'C' << 8) | (UINT_16) 'Z') /* Czech */ ++#define COUNTRY_CODE_DE (((UINT_16) 'D' << 8) | (UINT_16) 'E') /* Germany */ ++#define COUNTRY_CODE_DJ (((UINT_16) 'D' << 8) | (UINT_16) 'J') /* Djibouti */ ++#define COUNTRY_CODE_DK (((UINT_16) 'D' << 8) | (UINT_16) 'K') /* Denmark */ ++#define COUNTRY_CODE_DM (((UINT_16) 'D' << 8) | (UINT_16) 'M') /* Dominica */ ++#define COUNTRY_CODE_DO (((UINT_16) 'D' << 8) | (UINT_16) 'O') /* Dominican Republic */ ++#define COUNTRY_CODE_DZ (((UINT_16) 'D' << 8) | (UINT_16) 'Z') /* Algeria */ ++#define COUNTRY_CODE_EC (((UINT_16) 'E' << 8) | (UINT_16) 'C') /* Ecuador */ ++#define COUNTRY_CODE_EE (((UINT_16) 'E' << 8) | (UINT_16) 'E') /* Estonia */ ++#define COUNTRY_CODE_EG (((UINT_16) 'E' << 8) | (UINT_16) 'G') /* Egypt */ ++#define COUNTRY_CODE_EH (((UINT_16) 'E' << 8) | (UINT_16) 'H') /* Western Sahara (Morocco) */ ++#define COUNTRY_CODE_ER (((UINT_16) 'E' << 8) | (UINT_16) 'R') /* Eritrea */ ++#define COUNTRY_CODE_ES (((UINT_16) 'E' << 8) | (UINT_16) 'S') /* Spain */ ++#define COUNTRY_CODE_ET (((UINT_16) 'E' << 8) | (UINT_16) 'T') /* Ethiopia */ ++#define COUNTRY_CODE_EU (((UINT_16) 'E' << 8) | (UINT_16) 'U') /* Europe */ ++#define COUNTRY_CODE_FI (((UINT_16) 'F' << 8) | (UINT_16) 'I') /* Finland */ ++#define COUNTRY_CODE_FJ (((UINT_16) 'F' << 8) | (UINT_16) 'J') /* Fiji */ ++#define COUNTRY_CODE_FK (((UINT_16) 'F' << 8) | (UINT_16) 'K') /* Falkland Island */ ++#define COUNTRY_CODE_FM (((UINT_16) 'F' << 8) | (UINT_16) 'M') /* Micronesia */ ++#define COUNTRY_CODE_FO (((UINT_16) 'F' << 8) | (UINT_16) 'O') /* Faroe Island */ ++#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* France */ ++#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* Wallis and Futuna (France) */ ++#define COUNTRY_CODE_GA (((UINT_16) 'G' << 8) | (UINT_16) 'A') /* Gabon */ ++#define COUNTRY_CODE_GB (((UINT_16) 'G' << 8) | (UINT_16) 'B') /* United Kingdom */ ++#define COUNTRY_CODE_GD (((UINT_16) 'G' << 8) | (UINT_16) 'D') /* Grenada */ ++#define COUNTRY_CODE_GE (((UINT_16) 'G' << 8) | (UINT_16) 'E') /* Georgia */ ++#define COUNTRY_CODE_GF (((UINT_16) 'G' << 8) | (UINT_16) 'F') /* French Guiana */ ++#define COUNTRY_CODE_GG (((UINT_16) 'G' << 8) | (UINT_16) 'G') /* Guernsey */ ++#define COUNTRY_CODE_GH (((UINT_16) 'G' << 8) | (UINT_16) 'H') /* Ghana */ ++#define COUNTRY_CODE_GI (((UINT_16) 'G' << 8) | (UINT_16) 'I') /* Gibraltar */ ++#define COUNTRY_CODE_GM (((UINT_16) 'G' << 8) | (UINT_16) 'M') /* Gambia */ ++#define COUNTRY_CODE_GN (((UINT_16) 'G' << 8) | (UINT_16) 'N') /* Guinea */ ++#define COUNTRY_CODE_GP (((UINT_16) 'G' << 8) | (UINT_16) 'P') /* Guadeloupe */ ++#define COUNTRY_CODE_GQ (((UINT_16) 'G' << 8) | (UINT_16) 'Q') /* Equatorial Guinea */ ++#define COUNTRY_CODE_GR (((UINT_16) 'G' << 8) | (UINT_16) 'R') /* Greece */ ++#define COUNTRY_CODE_GT (((UINT_16) 'G' << 8) | (UINT_16) 'T') /* Guatemala */ ++#define COUNTRY_CODE_GU (((UINT_16) 'G' << 8) | (UINT_16) 'U') /* Guam */ ++#define COUNTRY_CODE_GW (((UINT_16) 'G' << 8) | (UINT_16) 'W') /* Guinea-Bissau */ ++#define COUNTRY_CODE_GY (((UINT_16) 'G' << 8) | (UINT_16) 'Y') /* Guyana */ ++#define COUNTRY_CODE_HK (((UINT_16) 'H' << 8) | (UINT_16) 'K') /* Hong Kong */ ++#define COUNTRY_CODE_HN (((UINT_16) 'H' << 8) | (UINT_16) 'N') /* Honduras */ ++#define COUNTRY_CODE_HR (((UINT_16) 'H' << 8) | (UINT_16) 'R') /* Croatia */ ++#define COUNTRY_CODE_HT (((UINT_16) 'H' << 8) | (UINT_16) 'T') /* Haiti */ ++#define COUNTRY_CODE_HU (((UINT_16) 'H' << 8) | (UINT_16) 'U') /* Hungary */ ++#define COUNTRY_CODE_ID (((UINT_16) 'I' << 8) | (UINT_16) 'D') /* Indonesia */ ++#define COUNTRY_CODE_IE (((UINT_16) 'I' << 8) | (UINT_16) 'E') /* Ireland */ ++#define COUNTRY_CODE_IL (((UINT_16) 'I' << 8) | (UINT_16) 'L') /* Israel */ ++#define COUNTRY_CODE_IM (((UINT_16) 'I' << 8) | (UINT_16) 'M') /* Isle of Man */ ++#define COUNTRY_CODE_IN (((UINT_16) 'I' << 8) | (UINT_16) 'N') /* India */ ++#define COUNTRY_CODE_IQ (((UINT_16) 'I' << 8) | (UINT_16) 'Q') /* Iraq */ ++#define COUNTRY_CODE_IR (((UINT_16) 'I' << 8) | (UINT_16) 'R') /* Iran */ ++#define COUNTRY_CODE_IS (((UINT_16) 'I' << 8) | (UINT_16) 'S') /* Iceland */ ++#define COUNTRY_CODE_IT (((UINT_16) 'I' << 8) | (UINT_16) 'T') /* Italy */ ++#define COUNTRY_CODE_JE (((UINT_16) 'J' << 8) | (UINT_16) 'E') /* Jersey */ ++#define COUNTRY_CODE_JM (((UINT_16) 'J' << 8) | (UINT_16) 'M') /* Jameica */ ++#define COUNTRY_CODE_JO (((UINT_16) 'J' << 8) | (UINT_16) 'O') /* Jordan */ ++#define COUNTRY_CODE_JP (((UINT_16) 'J' << 8) | (UINT_16) 'P') /* Japan */ ++#define COUNTRY_CODE_KE (((UINT_16) 'K' << 8) | (UINT_16) 'E') /* Kenya */ ++#define COUNTRY_CODE_KG (((UINT_16) 'K' << 8) | (UINT_16) 'G') /* Kyrgyzstan */ ++#define COUNTRY_CODE_KH (((UINT_16) 'K' << 8) | (UINT_16) 'H') /* Cambodia */ ++#define COUNTRY_CODE_KI (((UINT_16) 'K' << 8) | (UINT_16) 'I') /* Kiribati */ ++#define COUNTRY_CODE_KM (((UINT_16) 'K' << 8) | (UINT_16) 'M') /* Comoros */ ++#define COUNTRY_CODE_KN (((UINT_16) 'K' << 8) | (UINT_16) 'N') /* Saint Kitts and Nevis */ ++#define COUNTRY_CODE_KP (((UINT_16) 'K' << 8) | (UINT_16) 'P') /* North Korea */ ++#define COUNTRY_CODE_KR (((UINT_16) 'K' << 8) | (UINT_16) 'R') /* South Korea */ ++#define COUNTRY_CODE_KW (((UINT_16) 'K' << 8) | (UINT_16) 'W') /* Kuwait */ ++#define COUNTRY_CODE_KY (((UINT_16) 'K' << 8) | (UINT_16) 'Y') /* Cayman Islands */ ++#define COUNTRY_CODE_KZ (((UINT_16) 'K' << 8) | (UINT_16) 'Z') /* Kazakhstan */ ++#define COUNTRY_CODE_LA (((UINT_16) 'L' << 8) | (UINT_16) 'A') /* Laos */ ++#define COUNTRY_CODE_LB (((UINT_16) 'L' << 8) | (UINT_16) 'B') /* Lebanon */ ++#define COUNTRY_CODE_LC (((UINT_16) 'L' << 8) | (UINT_16) 'C') /* Saint Lucia */ ++#define COUNTRY_CODE_LI (((UINT_16) 'L' << 8) | (UINT_16) 'I') /* Liechtenstein */ ++#define COUNTRY_CODE_LK (((UINT_16) 'L' << 8) | (UINT_16) 'K') /* Sri Lanka */ ++#define COUNTRY_CODE_LR (((UINT_16) 'L' << 8) | (UINT_16) 'R') /* Liberia */ ++#define COUNTRY_CODE_LS (((UINT_16) 'L' << 8) | (UINT_16) 'S') /* Lesotho */ ++#define COUNTRY_CODE_LT (((UINT_16) 'L' << 8) | (UINT_16) 'T') /* Lithuania */ ++#define COUNTRY_CODE_LU (((UINT_16) 'L' << 8) | (UINT_16) 'U') /* Luxemburg */ ++#define COUNTRY_CODE_LV (((UINT_16) 'L' << 8) | (UINT_16) 'V') /* Latvia */ ++#define COUNTRY_CODE_LY (((UINT_16) 'L' << 8) | (UINT_16) 'Y') /* Libya */ ++#define COUNTRY_CODE_MA (((UINT_16) 'M' << 8) | (UINT_16) 'A') /* Morocco */ ++#define COUNTRY_CODE_MC (((UINT_16) 'M' << 8) | (UINT_16) 'C') /* Monaco */ ++#define COUNTRY_CODE_MD (((UINT_16) 'M' << 8) | (UINT_16) 'D') /* Moldova */ ++#define COUNTRY_CODE_ME (((UINT_16) 'M' << 8) | (UINT_16) 'E') /* Montenegro */ ++#define COUNTRY_CODE_MF (((UINT_16) 'M' << 8) | (UINT_16) 'F') /* Saint Martin / Sint Marteen ++ (Added on window's list) */ ++#define COUNTRY_CODE_MG (((UINT_16) 'M' << 8) | (UINT_16) 'G') /* Madagascar */ ++#define COUNTRY_CODE_MH (((UINT_16) 'M' << 8) | (UINT_16) 'H') /* Marshall Islands */ ++#define COUNTRY_CODE_MK (((UINT_16) 'M' << 8) | (UINT_16) 'K') /* Macedonia */ ++#define COUNTRY_CODE_ML (((UINT_16) 'M' << 8) | (UINT_16) 'L') /* Mali */ ++#define COUNTRY_CODE_MM (((UINT_16) 'M' << 8) | (UINT_16) 'M') /* Myanmar */ ++#define COUNTRY_CODE_MN (((UINT_16) 'M' << 8) | (UINT_16) 'N') /* Mongolia */ ++#define COUNTRY_CODE_MO (((UINT_16) 'M' << 8) | (UINT_16) 'O') /* Macao */ ++#define COUNTRY_CODE_MP (((UINT_16) 'M' << 8) | (UINT_16) 'P') /* Northern Mariana Islands (Rota Island. ++ Saipan and Tinian Island) */ ++#define COUNTRY_CODE_MQ (((UINT_16) 'M' << 8) | (UINT_16) 'Q') /* Martinique (France) */ ++#define COUNTRY_CODE_MR (((UINT_16) 'M' << 8) | (UINT_16) 'R') /* Mauritania */ ++#define COUNTRY_CODE_MS (((UINT_16) 'M' << 8) | (UINT_16) 'S') /* Montserrat (UK) */ ++#define COUNTRY_CODE_MT (((UINT_16) 'M' << 8) | (UINT_16) 'T') /* Malta */ ++#define COUNTRY_CODE_MU (((UINT_16) 'M' << 8) | (UINT_16) 'U') /* Mauritius */ ++#define COUNTRY_CODE_MV (((UINT_16) 'M' << 8) | (UINT_16) 'V') /* Maldives */ ++#define COUNTRY_CODE_MW (((UINT_16) 'M' << 8) | (UINT_16) 'W') /* Malawi */ ++#define COUNTRY_CODE_MX (((UINT_16) 'M' << 8) | (UINT_16) 'X') /* Mexico */ ++#define COUNTRY_CODE_MY (((UINT_16) 'M' << 8) | (UINT_16) 'Y') /* Malaysia */ ++#define COUNTRY_CODE_MZ (((UINT_16) 'M' << 8) | (UINT_16) 'Z') /* Mozambique */ ++#define COUNTRY_CODE_NA (((UINT_16) 'N' << 8) | (UINT_16) 'A') /* Namibia */ ++#define COUNTRY_CODE_NC (((UINT_16) 'N' << 8) | (UINT_16) 'C') /* New Caledonia */ ++#define COUNTRY_CODE_NE (((UINT_16) 'N' << 8) | (UINT_16) 'E') /* Niger */ ++#define COUNTRY_CODE_NF (((UINT_16) 'N' << 8) | (UINT_16) 'F') /* Norfolk Island */ ++#define COUNTRY_CODE_NG (((UINT_16) 'N' << 8) | (UINT_16) 'G') /* Nigeria */ ++#define COUNTRY_CODE_NI (((UINT_16) 'N' << 8) | (UINT_16) 'I') /* Nicaragua */ ++#define COUNTRY_CODE_NL (((UINT_16) 'N' << 8) | (UINT_16) 'L') /* Netherlands */ ++#define COUNTRY_CODE_NO (((UINT_16) 'N' << 8) | (UINT_16) 'O') /* Norway */ ++#define COUNTRY_CODE_NP (((UINT_16) 'N' << 8) | (UINT_16) 'P') /* Nepal */ ++#define COUNTRY_CODE_NR (((UINT_16) 'N' << 8) | (UINT_16) 'R') /* Nauru */ ++#define COUNTRY_CODE_NU (((UINT_16) 'N' << 8) | (UINT_16) 'U') /* Niue */ ++#define COUNTRY_CODE_NZ (((UINT_16) 'N' << 8) | (UINT_16) 'Z') /* New Zealand */ ++#define COUNTRY_CODE_OM (((UINT_16) 'O' << 8) | (UINT_16) 'M') /* Oman */ ++#define COUNTRY_CODE_PA (((UINT_16) 'P' << 8) | (UINT_16) 'A') /* Panama */ ++#define COUNTRY_CODE_PE (((UINT_16) 'P' << 8) | (UINT_16) 'E') /* Peru */ ++#define COUNTRY_CODE_PF (((UINT_16) 'P' << 8) | (UINT_16) 'F') /* "French Polynesia */ ++#define COUNTRY_CODE_PG (((UINT_16) 'P' << 8) | (UINT_16) 'G') /* Papua New Guinea */ ++#define COUNTRY_CODE_PH (((UINT_16) 'P' << 8) | (UINT_16) 'H') /* Philippines */ ++#define COUNTRY_CODE_PK (((UINT_16) 'P' << 8) | (UINT_16) 'K') /* Pakistan */ ++#define COUNTRY_CODE_PL (((UINT_16) 'P' << 8) | (UINT_16) 'L') /* Poland */ ++#define COUNTRY_CODE_PM (((UINT_16) 'P' << 8) | (UINT_16) 'M') /* Saint Pierre and Miquelon */ ++#define COUNTRY_CODE_PN (((UINT_16) 'P' << 8) | (UINT_16) 'N') /* Pitcairn Islands */ ++#define COUNTRY_CODE_PR (((UINT_16) 'P' << 8) | (UINT_16) 'R') /* Puerto Rico (USA) */ ++#define COUNTRY_CODE_PS (((UINT_16) 'P' << 8) | (UINT_16) 'S') /* Palestinian Authority */ ++#define COUNTRY_CODE_PT (((UINT_16) 'P' << 8) | (UINT_16) 'T') /* Portugal */ ++#define COUNTRY_CODE_PW (((UINT_16) 'P' << 8) | (UINT_16) 'W') /* Palau */ ++#define COUNTRY_CODE_PY (((UINT_16) 'P' << 8) | (UINT_16) 'Y') /* Paraguay */ ++#define COUNTRY_CODE_QA (((UINT_16) 'Q' << 8) | (UINT_16) 'A') /* Qatar */ ++#define COUNTRY_CODE_RE (((UINT_16) 'R' << 8) | (UINT_16) 'E') /* Reunion (France) */ ++#define COUNTRY_CODE_RKS (((UINT_16) 'R' << 8) | (UINT_16) 'K') /* Kosvo (Added on window's list) */ ++#define COUNTRY_CODE_RO (((UINT_16) 'R' << 8) | (UINT_16) 'O') /* Romania */ ++#define COUNTRY_CODE_RS (((UINT_16) 'R' << 8) | (UINT_16) 'S') /* Serbia */ ++#define COUNTRY_CODE_RU (((UINT_16) 'R' << 8) | (UINT_16) 'U') /* Russia */ ++#define COUNTRY_CODE_RW (((UINT_16) 'R' << 8) | (UINT_16) 'W') /* Rwanda */ ++#define COUNTRY_CODE_SA (((UINT_16) 'S' << 8) | (UINT_16) 'A') /* Saudi Arabia */ ++#define COUNTRY_CODE_SB (((UINT_16) 'S' << 8) | (UINT_16) 'B') /* Solomon Islands */ ++#define COUNTRY_CODE_SC (((UINT_16) 'S' << 8) | (UINT_16) 'C') /* Seychelles */ ++#define COUNTRY_CODE_SD (((UINT_16) 'S' << 8) | (UINT_16) 'D') /* Sudan */ ++#define COUNTRY_CODE_SE (((UINT_16) 'S' << 8) | (UINT_16) 'E') /* Sweden */ ++#define COUNTRY_CODE_SG (((UINT_16) 'S' << 8) | (UINT_16) 'G') /* Singapole */ ++#define COUNTRY_CODE_SI (((UINT_16) 'S' << 8) | (UINT_16) 'I') /* Slovenia */ ++#define COUNTRY_CODE_SK (((UINT_16) 'S' << 8) | (UINT_16) 'K') /* Slovakia */ ++#define COUNTRY_CODE_SL (((UINT_16) 'S' << 8) | (UINT_16) 'L') /* Sierra Leone */ ++#define COUNTRY_CODE_SM (((UINT_16) 'S' << 8) | (UINT_16) 'M') /* San Marino */ ++#define COUNTRY_CODE_SN (((UINT_16) 'S' << 8) | (UINT_16) 'N') /* Senegal */ ++#define COUNTRY_CODE_SO (((UINT_16) 'S' << 8) | (UINT_16) 'O') /* Somalia */ ++#define COUNTRY_CODE_SR (((UINT_16) 'S' << 8) | (UINT_16) 'R') /* Suriname */ ++#define COUNTRY_CODE_SS (((UINT_16) 'S' << 8) | (UINT_16) 'S') /* South_Sudan */ ++#define COUNTRY_CODE_ST (((UINT_16) 'S' << 8) | (UINT_16) 'T') /* Sao Tome and Principe */ ++#define COUNTRY_CODE_SV (((UINT_16) 'S' << 8) | (UINT_16) 'V') /* El Salvador */ ++#define COUNTRY_CODE_SY (((UINT_16) 'S' << 8) | (UINT_16) 'Y') /* Syria */ ++#define COUNTRY_CODE_SZ (((UINT_16) 'S' << 8) | (UINT_16) 'Z') /* Swaziland */ ++#define COUNTRY_CODE_TC (((UINT_16) 'T' << 8) | (UINT_16) 'C') /* Turks and Caicos Islands (UK) */ ++#define COUNTRY_CODE_TD (((UINT_16) 'T' << 8) | (UINT_16) 'D') /* Chad */ ++#define COUNTRY_CODE_TF (((UINT_16) 'T' << 8) | (UINT_16) 'F') /* French Southern and Antarctic Lands */ ++#define COUNTRY_CODE_TG (((UINT_16) 'T' << 8) | (UINT_16) 'G') /* Togo */ ++#define COUNTRY_CODE_TH (((UINT_16) 'T' << 8) | (UINT_16) 'H') /* Thailand */ ++#define COUNTRY_CODE_TJ (((UINT_16) 'T' << 8) | (UINT_16) 'J') /* Tajikistan */ ++#define COUNTRY_CODE_TL (((UINT_16) 'T' << 8) | (UINT_16) 'L') /* East Timor */ ++#define COUNTRY_CODE_TM (((UINT_16) 'T' << 8) | (UINT_16) 'M') /* Turkmenistan */ ++#define COUNTRY_CODE_TN (((UINT_16) 'T' << 8) | (UINT_16) 'N') /* Tunisia */ ++#define COUNTRY_CODE_TO (((UINT_16) 'T' << 8) | (UINT_16) 'O') /* Tonga */ ++#define COUNTRY_CODE_TR (((UINT_16) 'T' << 8) | (UINT_16) 'R') /* Turkey */ ++#define COUNTRY_CODE_TT (((UINT_16) 'T' << 8) | (UINT_16) 'T') /* Trinidad and Tobago */ ++#define COUNTRY_CODE_TV (((UINT_16) 'T' << 8) | (UINT_16) 'V') /* Tuvalu */ ++#define COUNTRY_CODE_TW (((UINT_16) 'T' << 8) | (UINT_16) 'W') /* Taiwan */ ++#define COUNTRY_CODE_TZ (((UINT_16) 'T' << 8) | (UINT_16) 'Z') /* Tanzania */ ++#define COUNTRY_CODE_UA (((UINT_16) 'U' << 8) | (UINT_16) 'A') /* Ukraine */ ++#define COUNTRY_CODE_UG (((UINT_16) 'U' << 8) | (UINT_16) 'G') /* Ugnada */ ++#define COUNTRY_CODE_US (((UINT_16) 'U' << 8) | (UINT_16) 'S') /* US */ ++#define COUNTRY_CODE_UY (((UINT_16) 'U' << 8) | (UINT_16) 'Y') /* Uruguay */ ++#define COUNTRY_CODE_UZ (((UINT_16) 'U' << 8) | (UINT_16) 'Z') /* Uzbekistan */ ++#define COUNTRY_CODE_VA (((UINT_16) 'V' << 8) | (UINT_16) 'A') /* Vatican (Holy See) */ ++#define COUNTRY_CODE_VC (((UINT_16) 'V' << 8) | (UINT_16) 'C') /* Saint Vincent and the Grenadines */ ++#define COUNTRY_CODE_VE (((UINT_16) 'V' << 8) | (UINT_16) 'E') /* Venezuela */ ++#define COUNTRY_CODE_VG (((UINT_16) 'V' << 8) | (UINT_16) 'G') /* British Virgin Islands */ ++#define COUNTRY_CODE_VI (((UINT_16) 'V' << 8) | (UINT_16) 'I') /* US Virgin Islands */ ++#define COUNTRY_CODE_VN (((UINT_16) 'V' << 8) | (UINT_16) 'N') /* Vietnam */ ++#define COUNTRY_CODE_VU (((UINT_16) 'V' << 8) | (UINT_16) 'U') /* Vanuatu */ ++#define COUNTRY_CODE_WS (((UINT_16) 'W' << 8) | (UINT_16) 'S') /* Samoa */ ++#define COUNTRY_CODE_YE (((UINT_16) 'Y' << 8) | (UINT_16) 'E') /* Yemen */ ++#define COUNTRY_CODE_YT (((UINT_16) 'Y' << 8) | (UINT_16) 'T') /* Mayotte (France) */ ++#define COUNTRY_CODE_ZA (((UINT_16) 'Z' << 8) | (UINT_16) 'A') /* South Africa */ ++#define COUNTRY_CODE_ZM (((UINT_16) 'Z' << 8) | (UINT_16) 'M') /* Zambia */ ++#define COUNTRY_CODE_ZW (((UINT_16) 'Z' << 8) | (UINT_16) 'W') /* Zimbabwe */ ++ ++#define COUNTRY_CODE_DF (((UINT_16) 'D' << 8) | (UINT_16) 'F') /* Default country domain */ ++#define COUNTRY_CODE_UDF (((UINT_16) 'U' << 8) | (UINT_16) 'D') /* User defined supported channel list ++ and passive scan channel list */ ++ ++#define COUNTRY_CODE_FF (((UINT_16) 'F' << 8) | (UINT_16) 'F') /* enable open for all channel for Certification */ ++#define COUNTRY_CODE_FE (((UINT_16) 'F' << 8) | (UINT_16) 'E') /* disable open for all channel for Certification */ ++ ++/* dot11RegDomainsSupportValue */ ++#define MIB_REG_DOMAIN_FCC 0x10 /* FCC (US) */ ++#define MIB_REG_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ ++#define MIB_REG_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ ++#define MIB_REG_DOMAIN_SPAIN 0x31 /* Spain */ ++#define MIB_REG_DOMAIN_FRANCE 0x32 /* France */ ++#define MIB_REG_DOMAIN_JAPAN 0x40 /* MPHPT (Japan) */ ++#define MIB_REG_DOMAIN_OTHER 0x00 /* other */ ++ ++/*2.4G*/ ++#define BAND_2G4_LOWER_BOUND 1 ++#define BAND_2G4_UPPER_BOUND 14 ++/*5G SubBand FCC spec*/ ++#define UNII1_LOWER_BOUND 36 ++#define UNII1_UPPER_BOUND 48 ++#define UNII2A_LOWER_BOUND 52 ++#define UNII2A_UPPER_BOUND 64 ++#define UNII2C_LOWER_BOUND 100 ++#define UNII2C_UPPER_BOUND 144 ++#define UNII3_LOWER_BOUND 149 ++#define UNII3_UPPER_BOUND 173 ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++#define POWER_LIMIT_TABLE_NULL 0xFFFF ++#define MAX_TX_POWER 63 ++#define MIN_TX_POWER -64 ++#define MAX_CMD_SUPPORT_CHANNEL_NUM 64 ++ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++typedef enum _ENUM_POWER_LIMIT_T { ++ PWR_LIMIT_CCK, ++ PWR_LIMIT_20M, ++ PWR_LIMIT_40M, ++ PWR_LIMIT_80M, ++ PWR_LIMIT_160M, ++ PWR_LIMIT_NUM ++} ENUM_POWER_LIMIT_T, *P_ENUM_POWER_LIMIT_T; ++ ++#endif ++ ++typedef enum _ENUM_POWER_LIMIT_SUBBAND_T { ++ POWER_LIMIT_2G4, ++ POWER_LIMIT_UNII1, ++ POWER_LIMIT_UNII2A, ++ POWER_LIMIT_UNII2C, ++ POWER_LIMIT_UNII3, ++ POWER_LIMIT_SUBAND_NUM ++} ENUM_POWER_LIMIT_SUBBAND_T, *P_ENUM_POWER_LIMIT_SUBBAND_T; ++ ++/* Define channel offset in unit of 5MHz bandwidth */ ++typedef enum _ENUM_CHNL_SPAN_T { ++ CHNL_SPAN_5 = 1, ++ CHNL_SPAN_10 = 2, ++ CHNL_SPAN_20 = 4, ++ CHNL_SPAN_40 = 8 ++} ENUM_CHNL_SPAN_T, *P_ENUM_CHNL_SPAN_T; ++ ++/* Define BSS operating bandwidth */ ++typedef enum _ENUM_CHNL_BW_T { ++ CHNL_BW_20, ++ CHNL_BW_20_40, ++ CHNL_BW_10, ++ CHNL_BW_5 ++} ENUM_CHNL_BW_T, *P_ENUM_CHNL_BW_T; ++ ++/* In all bands, the first channel will be SCA and the second channel is SCB, ++ * then iteratively. ++ * Note the final channel will not be SCA. ++ */ ++typedef struct _DOMAIN_SUBBAND_INFO { ++ /* Note1: regulation class depends on operation bandwidth and RF band. ++ * For example: 2.4GHz, 1~13, 20MHz ==> regulation class = 81 ++ * 2.4GHz, 1~13, SCA ==> regulation class = 83 ++ * 2.4GHz, 1~13, SCB ==> regulation class = 84 ++ * Note2: TX power limit is not specified here because path loss is unknown ++ */ ++ UINT_8 ucRegClass; /* Regulation class for 20MHz */ ++ UINT_8 ucBand; /* Type: ENUM_BAND_T */ ++ UINT_8 ucChannelSpan; /* Type: ENUM_CHNL_SPAN_T */ ++ UINT_8 ucFirstChannelNum; ++ UINT_8 ucNumChannels; ++ UINT_8 fgDfs; /* Type: BOOLEAN */ ++} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; ++ ++/* Use it as all available channel list for STA */ ++typedef struct _DOMAIN_INFO_ENTRY { ++ PUINT_16 pu2CountryGroup; ++ UINT_32 u4CountryNum; ++ ++ /* If different attributes, put them into different rSubBands. ++ * For example, DFS shall be used or not. ++ */ ++ DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; ++} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; ++ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++typedef struct _CHANNEL_POWER_LIMIT { ++ UINT_8 ucCentralCh; ++ INT_8 cPwrLimitCCK; ++ INT_8 cPwrLimit20; ++ INT_8 cPwrLimit40; ++ INT_8 cPwrLimit80; ++ INT_8 cPwrLimit160; ++ UINT_8 ucFlag; ++ UINT_8 aucReserved[1]; ++} CHANNEL_POWER_LIMIT, *P_CHANNEL_POWER_LIMIT; ++ ++typedef struct _COUNTRY_CHANNEL_POWER_LIMIT { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 ucCountryFlag; ++ UINT_8 ucChannelNum; ++ UINT_8 aucReserved[4]; ++ CHANNEL_POWER_LIMIT rChannelPowerLimit[80]; ++} COUNTRY_CHANNEL_POWER_LIMIT, *P_COUNTRY_CHANNEL_POWER_LIMIT; ++ ++#define CHANNEL_PWR_LIMIT(_channel, _pwrLimit_cck, _pwrLimit_bw20, \ ++ _pwrLimit_bw40, _pwrLimit_bw80, _pwrLimit_bw160, _ucFlag) \ ++ { \ ++ .ucCentralCh = (_channel), \ ++ .cPwrLimitCCK = (_pwrLimit_cck), \ ++ .cPwrLimit20 = (_pwrLimit_bw20), \ ++ .cPwrLimit40 = (_pwrLimit_bw40), \ ++ .cPwrLimit80 = (_pwrLimit_bw80), \ ++ .cPwrLimit160 = (_pwrLimit_bw160), \ ++ .ucFlag = (_ucFlag), \ ++ .aucReserved = {0} \ ++} ++ ++typedef struct _COUNTRY_POWER_LIMIT_TABLE_DEFAULT { ++ UINT_8 aucCountryCode[2]; ++ /* 0: ch 1 ~14 , 1: ch 36 ~48, 2: ch 52 ~64, 3: ch 100 ~144, 4: ch 149 ~165 */ ++ INT_8 aucPwrLimitSubBand[POWER_LIMIT_SUBAND_NUM]; ++ /* bit0: cPwrLimit2G4, bit1: cPwrLimitUnii1; bit2: cPwrLimitUnii2A; ++ * bit3: cPwrLimitUnii2C; bit4: cPwrLimitUnii3; mW: 0, mW\MHz : 1 */ ++ UINT_8 ucPwrUnit; ++} COUNTRY_POWER_LIMIT_TABLE_DEFAULT, *P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT; ++ ++typedef struct _COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 ucCentralCh; ++ INT_8 aucPwrLimit[PWR_LIMIT_NUM]; ++} COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION, *P_COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION; ++ ++typedef struct _SUBBAND_CHANNEL_T { ++ UINT_8 ucStartCh; ++ UINT_8 ucEndCh; ++ UINT_8 ucInterval; ++ UINT_8 ucReserved; ++} SUBBAND_CHANNEL_T, *P_SUBBAND_CHANNEL_T; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define CAL_CH_OFFSET_80M(_PRIMARY_CH, _CENTRAL_CH) \ ++ (((_PRIMARY_CH - _CENTRAL_CH) + 6) >> 2) ++ ++#define CAL_CH_OFFSET_160M(_PRIMARY_CH, _CENTRAL_CH) \ ++ (((_PRIMARY_CH - _CENTRAL_CH) + 14) >> 2) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter); ++ ++VOID ++rlmDomainGetChnlList(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, ++ UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList); ++ ++VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); ++ ++BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel); ++ ++UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf); ++ ++BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh); ++ ++UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++BOOLEAN rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, ++ UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend, ++ ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2); ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++BOOLEAN ++rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, ++ COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, ++ UINT_8 ucPwrLimitNum); ++ ++VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter); ++ ++UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode); ++ ++VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_DOMAIN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h +new file mode 100644 +index 000000000000..7f29dba4ce06 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h +@@ -0,0 +1,150 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_obss.h#1 ++*/ ++ ++/*! \file "rlm_obss.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_obss.h ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ++ * ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++#ifndef _RLM_OBSS_H ++#define _RLM_OBSS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define CHNL_LIST_SZ_2G 14 ++#define CHNL_LIST_SZ_5G 14 ++ ++#define CHNL_LEVEL0 0 ++#define CHNL_LEVEL1 1 ++#define CHNL_LEVEL2 2 ++ ++#define AFFECTED_CHNL_OFFSET 5 ++ ++#define OBSS_SCAN_MIN_INTERVAL 10 /* In unit of sec */ ++ ++#define PUBLIC_ACTION_MAX_LEN 200 /* In unit of byte */ ++ ++/* P2P GO only */ ++/* Define default OBSS Scan parameters (from MIB in spec.) */ ++#define dot11OBSSScanPassiveDwell 20 ++#define dot11OBSSScanActiveDwell 10 ++#define dot11OBSSScanPassiveTotalPerChannel 200 ++#define dot11OBSSScanActiveTotalPerChannel 20 ++#define dot11BSSWidthTriggerScanInterval 300 /* Unit: sec */ ++#define dot11BSSWidthChannelTransitionDelayFactor 5 ++#define dot11OBSSScanActivityThreshold 25 ++ ++#define OBSS_20_40M_TIMEOUT (dot11BSSWidthTriggerScanInterval + 10) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* Control MAC PCO function */ ++typedef enum _ENUM_SYS_PCO_PHASE_T { ++ SYS_PCO_PHASE_DISABLED = 0, ++ SYS_PCO_PHASE_20M, ++ SYS_PCO_PHASE_40M ++} ENUM_SYS_PCO_PHASE_T, *P_ENUM_SYS_PCO_PHASE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID rlmObssInit(P_ADAPTER_T prAdapter); ++ ++VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); ++ ++VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_OBSS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h +new file mode 100644 +index 000000000000..8665e48569ba +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h +@@ -0,0 +1,122 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_protection.h#1 ++*/ ++ ++/*! \file "rlm_protection.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_protection.h ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++#ifndef _RLM_PROTECTION_H ++#define _RLM_PROTECTION_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SYS_PROTECT_MODE_T { ++ SYS_PROTECT_MODE_NONE = 0, /* Mode 0 */ ++ SYS_PROTECT_MODE_ERP, /* Mode 1 */ ++ SYS_PROTECT_MODE_NON_HT, /* Mode 2 */ ++ SYS_PROTECT_MODE_20M, /* Mode 3 */ ++ ++ SYS_PROTECT_MODE_NUM ++} ENUM_SYS_PROTECT_MODE_T, *P_ENUM_SYS_PROTECT_MODE_T; ++ ++/* This definition follows HT Protection field of HT Operation IE */ ++typedef enum _ENUM_HT_PROTECT_MODE_T { ++ HT_PROTECT_MODE_NONE = 0, ++ HT_PROTECT_MODE_NON_MEMBER, ++ HT_PROTECT_MODE_20M, ++ HT_PROTECT_MODE_NON_HT, ++ ++ HT_PROTECT_MODE_NUM ++} ENUM_HT_PROTECT_MODE_T, *P_ENUM_HT_PROTECT_MODE_T; ++ ++typedef enum _ENUM_GF_MODE_T { ++ GF_MODE_NORMAL = 0, ++ GF_MODE_PROTECT, ++ GF_MODE_DISALLOWED, ++ ++ GF_MODE_NUM ++} ENUM_GF_MODE_T, *P_ENUM_GF_MODE_T; ++ ++typedef enum _ENUM_RIFS_MODE_T { ++ RIFS_MODE_NORMAL = 0, ++ RIFS_MODE_DISALLOWED, ++ ++ RIFS_MODE_NUM ++} ENUM_RIFS_MODE_T, *P_ENUM_RIFS_MODE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_PROTECTION_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h +new file mode 100644 +index 000000000000..d01c6e01e83f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h +@@ -0,0 +1,1213 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_txpwr_init.h#1 ++*/ ++ ++/*! \file "rlm_txpwr_init.h" ++ \brief ++*/ ++ ++/* ++** Log: rlm_txpwr_init.h ++*/ ++ ++ ++#ifndef _RLM_TXPWR_INIT_H ++#define _RLM_TXPWR_INIT_H ++ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*Support Tx Power Range : 63~ -64 (unit : 0.5dBm)*/ ++ ++#define PWR_LIMIT_2G4_IN_MW_MHZ BIT(0) ++#define PWR_LIMIT_UNII1_IN_MW_MHZ BIT(1) ++#define PWR_LIMIT_UNII2A_IN_MW_MHZ BIT(2) ++#define PWR_LIMIT_UNII2C_IN_MW_MHZ BIT(3) ++#define PWR_LIMIT_UNII3_IN_MW_MHZ BIT(4) ++ ++#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT ++#define CE_FCC_TXPWR_LIMIT_CCK 30 /* 15 dBm */ ++#define CE_FCC_TXPWR_LIMIT_OFDM 20 /* 10 dBm */ ++#define CE_FCC_TXPWR_LIMIT_HT40 18 /* 9 dBm */ ++#endif ++ ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++COUNTRY_POWER_LIMIT_TABLE_DEFAULT g_rRlmPowerLimitDefault[] = { ++ ++ {{'A', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'Z'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'T'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'B', 'I'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'F'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'D'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'D'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'I'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'D', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'Q'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'E', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'F', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'A'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'N'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'W'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'R', 'K'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'L', 'Y'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'L'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'C'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'T'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'C'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'L'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'B'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'R'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'Z'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'J'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'G'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'O'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'M'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'V'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'V', 'U'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'Y', 'E'} ++ , {40, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'A', 'S'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'A', 'I'} ++ , {60, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'B', 'M'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'C', 'A'} ++ , {60, 46, 48, 48, 60} ++ , 0} ++ , ++ {{'K', 'Y'} ++ , {60, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'G', 'U'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'F', 'M'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'P', 'R'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'U', 'S'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'V', 'I'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'A', 'R'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'A', 'U'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'Z'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'B', 'W'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'K', 'H'} ++ , {40, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'C', 'X'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'O'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'C', 'R'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'E', 'C'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'G', 'D'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'G', 'T'} ++ , {40, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'H', 'K'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'I'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'B'} ++ , {40, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'L', 'R'} ++ , {60, 46, 60, 63, 63} ++ , 0} ++ , ++ {{'M', 'N'} ++ , {46, 32, 46, 46, 58} ++ , 0} ++ , ++ {{'A', 'N'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'N', 'Z'} ++ , {63, 46, 60, 48, 63} ++ , 0} ++ , ++ {{'N', 'I'} ++ , {60, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'P', 'W'} ++ , {60, 60, 60, 60, 60} ++ , 0} ++ , ++ {{'P', 'Y'} ++ , {60, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'P', 'E'} ++ , {54, 46, 48, 42, 48} ++ , 0} ++ , ++ {{'P', 'H'} ++ , {40, 46, 46, 48, 48} ++ , 0} ++ , ++ {{'W', 'S'} ++ , {40, 40, 40, 40, 60} ++ , 0} ++ , ++ {{'S', 'G'} ++ , {46, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'L', 'K'} ++ , {46, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'T', 'H'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'T', 'T'} ++ , {60, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'U', 'Y'} ++ , {63, 46, 46, 46, 46} ++ , 0} ++ , ++ {{'V', 'N'} ++ , {46, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'A', 'W'} ++ , {60, 46, 60, 60, 63} ++ , 0} ++ , ++ {{'L', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'A'} ++ , {40, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'A', 'E'} ++ , {40, 46, 46, 60, 46} ++ , 0} ++ , ++ {{'U', 'G'} ++ , {40, 46, 46, 48, 60} ++ , 0} ++ , ++ {{'M', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'Z'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'D'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'Y'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'V', 'G'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'B', 'G'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'V'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'H', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'Y'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'Z'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'T'} ++ , {40, 40, 40, 40, 63} ++ , 0} ++ , ++ {{'F', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'F', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'D', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'H'} ++ , {40, 34, 48, 60, 63} ++ , 0} ++ , ++ {{'G', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'P'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'H', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'Q'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'I', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'V'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'L', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'Q'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'R'} ++ , {40, 46, 46, 46, 63} ++ , 0} ++ , ++ {{'M', 'U'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'Y', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'D'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'C'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'N', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'N', 'O'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'O', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'L'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'P', 'T'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'R', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'R', 'O'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'M', 'F'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'M'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'N'} ++ , {40, 40, 40, 60, 63} ++ , 0} ++ , ++ {{'R', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'K'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'I'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'Z', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'E', 'S'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'S', 'E'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'C', 'H'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'R'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'T', 'C'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'G', 'B'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'V', 'A'} ++ , {40, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'A', 'M'} ++ , {40, 40, 40, 63, 63} ++ , 0} ++ , ++ {{'I', 'L'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'K', 'W'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'M', 'A'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'N', 'E'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'T', 'N'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'E', 'H'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'N', 'P'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'A', 'F'} ++ , {40, 46, 63, 63, 63} ++ , 0} ++ , ++ {{'A', 'G'} ++ , {40, 46, 48, 63, 54} ++ , 0} ++ , ++ {{'B', 'S'} ++ , {63, 46, 60, 63, 63} ++ , 0} ++ , ++ {{'B', 'H'} ++ , {40, 46, 46, 63, 63} ++ , 0} ++ , ++ {{'B', 'B'} ++ , {40, 46, 48, 63, 54} ++ , 0} ++ , ++ {{'B', 'N'} ++ , {46, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'C', 'L'} ++ , {40, 44, 44, 63, 44} ++ , 0} ++ , ++ {{'C', 'N'} ++ , {40, 46, 46, 63, 54} ++ , 0} ++ , ++ {{'E', 'G'} ++ , {40, 46, 46, 63, 46} ++ , 0} ++ , ++ {{'S', 'V'} ++ , {60, 34, 48, 63, 60} ++ , 0} ++ , ++ {{'I', 'N'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'M', 'Y'} ++ , {54, 60, 60, 63, 60} ++ , 0} ++ , ++ {{'M', 'V'} ++ , {40, 46, 46, 63, 40} ++ , 0} ++ , ++ {{'P', 'A'} ++ , {60, 34, 48, 63, 60} ++ , 0} ++ , ++ {{'V', 'E'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'Z', 'M'} ++ , {60, 46, 46, 63, 60} ++ , 0} ++ , ++ {{'J', 'O'} ++ , {40, 46, 63, 63, 46} ++ , 0} ++ , ++ {{'P', 'G'} ++ , {40, 46, 63, 63, 60} ++ , 0} ++ , ++ {{'B', 'F'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'G', 'Y'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'H', 'T'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'H', 'N'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'J', 'M'} ++ , {54, 63, 63, 63, 57} ++ , 0} ++ , ++ {{'M', 'O'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'M', 'W'} ++ , {60, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'P', 'K'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'Q', 'A'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'R', 'W'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'K', 'N'} ++ , {40, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'T', 'Z'} ++ , {40, 63, 63, 63, 40} ++ , 0} ++ , ++ {{'I', 'D'} ++ , {46, 63, 63, 63, 60} ++ , 0} ++ , ++ {{'N', 'G'} ++ , {40, 63, 46, 63, 60} ++ , 0} ++ , ++ {{'B', 'D'} ++ , {40, 46, 46, 60, 28} ++ , 0} ++ , ++ {{'B', 'R'} ++ , {52, 46, 46, 60, 60} ++ , 0} ++ , ++ {{'D', 'M'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'D', 'O'} ++ , {63, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'F', 'K'} ++ , {40, 46, 46, 60, 28} ++ , 0} ++ , ++ {{'K', 'Z'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'M', 'X'} ++ , {60, 34, 48, 60, 63} ++ , 0} ++ , ++ {{'M', 'Z'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'N', 'A'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'R', 'U'} ++ , {40, 34, 48, 60, 60} ++ , 0} ++ , ++ {{'L', 'C'} ++ , {40, 34, 48, 48, 60} ++ , 0} ++ , ++ {{'V', 'C'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'U', 'A'} ++ , {40, 46, 46, 46, 48} ++ , 0} ++ , ++ {{'U', 'Z'} ++ , {40, 48, 48, 48, 60} ++ , 0} ++ , ++ {{'Z', 'W'} ++ , {40, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'M', 'P'} ++ , {60, 34, 46, 48, 60} ++ , 0} ++ , ++ {{'T', 'W'} ++ , {60, 63, 34, 48, 60} ++ , 0} ++ , ++ {{'C', 'K'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'C', 'U'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'T', 'L'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'F', 'O'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'I'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'G', 'G'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'I', 'R'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'I', 'M'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'J', 'E'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'K', 'P'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'M', 'H'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'U'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'N', 'F'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'S'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'N'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'P', 'M'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'S'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'D'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'S', 'Y'} ++ , {63, 63, 63, 63, 63} ++ , 0} ++ , ++ {{'J', 'P'} ++ , {46, 46, 46, 60, 63} ++ , 0} ++ , ++ {{'K', 'R'} ++ , {46, 34, 46, 46, 46} ++ , PWR_LIMIT_UNII1_IN_MW_MHZ} ++ , ++ ++/*Default*/ ++ {{0, 0} ++ , {63, 63, 63, 63, 63} ++ , 0} ++}; ++ ++COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION g_rRlmPowerLimitConfiguration[] = { ++ ++ {{'A', 'I'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'A', 'Z'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'B', 'W'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'G', 'D'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'L', 'B'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'L', 'R'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'W', 'S'} ++ , 165, {40, 40, 40, 40, 40} ++ } ++ , ++ {{'V', 'N'} ++ , 144, {48, 48, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 1, {38, 30, 60, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 3, {60, 60, 26, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 9, {60, 60, 26, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 11, {38, 30, 60, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 36, {34, 34, 34, 34, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 38, {34, 34, 34, 34, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 42, {34, 34, 34, 31, 34} ++ } ++ , ++ {{'U', 'S'} ++ , 58, {48, 48, 48, 31, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 62, {48, 48, 34, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 64, {37, 37, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 100, {37, 37, 48, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 102, {48, 48, 34, 48, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 106, {48, 48, 48, 31, 48} ++ } ++ , ++ {{'U', 'S'} ++ , 155, {60, 60, 60, 31, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 159, {60, 60, 34, 60, 60} ++ } ++ , ++ {{'U', 'S'} ++ , 165, {37, 37, 60, 60, 60} ++ } ++ , ++ ++/*Default*/ ++ {{0, 0} ++ , 165, {63, 63, 63, 63, 63} ++ } ++}; ++ ++#if 0 ++COUNTRY_CHANNEL_POWER_LIMIT g_rRlmCountryPowerLimitTable[] = { ++ { ++ {'A', 'O'} ++ , 0, 0, {0, 0, 0, 0} ++ , ++ { ++ CHANNEL_PWR_LIMIT(1, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(2, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(3, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(4, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(5, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(6, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(7, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(8, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(9, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(10, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(11, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(12, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(13, 40, 40, 40, 40, 40, 0), ++ CHANNEL_PWR_LIMIT(14, 40, 40, 40, 40, 40, 0), ++ ++ CHANNEL_PWR_LIMIT(36, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(38, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(40, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(42, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(44, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(46, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(48, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(52, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(54, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(56, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(58, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(60, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(62, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(64, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(100, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(102, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(104, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(106, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(108, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(110, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(112, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(114, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(116, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(118, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(120, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(122, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(124, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(126, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(128, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(130, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(132, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(134, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(136, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(138, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(140, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(142, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(144, 63, 63, 63, 63, 63, 0), ++ ++ CHANNEL_PWR_LIMIT(149, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(151, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(153, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(155, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(157, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(159, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(161, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(163, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(165, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(167, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(169, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(171, 63, 63, 63, 63, 63, 0), ++ CHANNEL_PWR_LIMIT(173, 63, 63, 63, 63, 63, 0) ++ } ++ } ++ , ++ { ++ /*Used to check the end of country entry */ ++ {0, 0} ++ , 0, 0, {0, 0, 0, 0} ++ , ++ { ++ /*Used to check the end of channel power limit */ ++ CHANNEL_PWR_LIMIT(ENDCH, 0, 0, 0, 0, 0, 0) ++ } ++ } /*end of CountryTable */ ++}; ++#endif ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RLM_TXPWR_INIT_H */ ++ ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h +new file mode 100644 +index 000000000000..0df4ec3e0828 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h +@@ -0,0 +1,171 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "roaming_fsm.h" ++ \brief This file defines the FSM for Roaming MODULE. ++ ++ This file defines the FSM for Roaming MODULE. ++*/ ++ ++/* ++** Log: roaming_fsm.h ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++*/ ++ ++#ifndef _ROAMING_FSM_H ++#define _ROAMING_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Roaming Discovery interval, SCAN result need to be updated */ ++#define ROAMING_DISCOVERY_TIMEOUT_SEC 5 /* Seconds. */ ++ ++/* #define ROAMING_NO_SWING_RCPI_STEP 5 //rcpi */ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_ROAMING_FAIL_REASON_T { ++ ROAMING_FAIL_REASON_CONNLIMIT = 0, ++ ROAMING_FAIL_REASON_NOCANDIDATE, ++ ROAMING_FAIL_REASON_NUM ++} ENUM_ROAMING_FAIL_REASON_T; ++ ++/* events of roaming between driver and firmware */ ++typedef enum _ENUM_ROAMING_EVENT_T { ++ ROAMING_EVENT_START = 0, ++ ROAMING_EVENT_DISCOVERY, ++ ROAMING_EVENT_ROAM, ++ ROAMING_EVENT_FAIL, ++ ROAMING_EVENT_ABORT, ++ ROAMING_EVENT_NUM ++} ENUM_ROAMING_EVENT_T; ++ ++#define ROAMING_EVENT_REASON_TX_ERR BIT(0) ++#define ROAMING_EVENT_REASON_RCPI BIT(1) ++ ++typedef struct _ROAMING_PARAM_T { ++ UINT_16 u2Event; ++ UINT_16 u2Data; ++ UINT_16 u2Reason; ++} ROAMING_PARAM_T, *P_ROAMING_PARAM_T; ++ ++ /**/ typedef enum _ENUM_ROAMING_STATE_T { ++ ROAMING_STATE_IDLE = 0, ++ ROAMING_STATE_DECISION, ++ ROAMING_STATE_DISCOVERY, ++ ROAMING_STATE_ROAM, ++ ROAMING_STATE_NUM ++} ENUM_ROAMING_STATE_T; ++ ++typedef struct _ROAMING_INFO_T { ++ BOOLEAN fgIsEnableRoaming; ++ ++ ENUM_ROAMING_STATE_T eCurrentState; ++ ++ OS_SYSTIME rRoamingDiscoveryUpdateTime; ++ ++#define ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX 2 ++ UINT_32 RoamingEntryTimeoutSkipCount; ++ ++} ROAMING_INFO_T, *P_ROAMING_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if CFG_SUPPORT_ROAMING ++#define IS_ROAMING_ACTIVE(prAdapter) \ ++ (prAdapter->rWifiVar.rRoamingInfo.eCurrentState == ROAMING_STATE_ROAM) ++#else ++#define IS_ROAMING_ACTIVE(prAdapter) FALSE ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID roamingFsmInit(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState); ++ ++VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter); ++ ++VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Reason); ++ ++VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ROAMING_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h +new file mode 100644 +index 000000000000..20ab14251f65 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h +@@ -0,0 +1,271 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rsn.h#1 ++*/ ++ ++/*! \file rsn.h ++ \brief The wpa/rsn related define, macro and structure are described here. ++*/ ++ ++/* ++** Log: rsn.h ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h ++ * and let the sw structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 wh.su ++ * NULL ++ * remove non-used code. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, and modify ++ * the security related callback function prototype. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function prototype for generate wap/rsn ie ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function input parameter ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some event function declaration ++ * ++ * Nov 26 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * move the internal data structure for pmkid to rsn.h ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the port control and class error function ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the pmkid candidate ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++#ifndef _RSN_H ++#define _RSN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* ----- Definitions for Cipher Suite Selectors ----- */ ++#define RSN_CIPHER_SUITE_USE_GROUP_KEY 0x00AC0F00 ++#define RSN_CIPHER_SUITE_WEP40 0x01AC0F00 ++#define RSN_CIPHER_SUITE_TKIP 0x02AC0F00 ++#define RSN_CIPHER_SUITE_CCMP 0x04AC0F00 ++#define RSN_CIPHER_SUITE_WEP104 0x05AC0F00 ++#if CFG_SUPPORT_802_11W ++#define RSN_CIPHER_SUITE_AES_128_CMAC 0x06AC0F00 ++#endif ++ ++#define WPA_CIPHER_SUITE_NONE 0x00F25000 ++#define WPA_CIPHER_SUITE_WEP40 0x01F25000 ++#define WPA_CIPHER_SUITE_TKIP 0x02F25000 ++#define WPA_CIPHER_SUITE_CCMP 0x04F25000 ++#define WPA_CIPHER_SUITE_WEP104 0x05F25000 ++ ++/* ----- Definitions for Authentication and Key Management Suite Selectors ----- */ ++#define RSN_AKM_SUITE_NONE 0x00AC0F00 ++#define RSN_AKM_SUITE_802_1X 0x01AC0F00 ++#define RSN_AKM_SUITE_PSK 0x02AC0F00 ++#if CFG_SUPPORT_802_11W ++#define RSN_AKM_SUITE_802_1X_SHA256 0x05AC0F00 ++#define RSN_AKM_SUITE_PSK_SHA256 0x06AC0F00 ++#endif ++ ++#define WPA_AKM_SUITE_NONE 0x00F25000 ++#define WPA_AKM_SUITE_802_1X 0x01F25000 ++#define WPA_AKM_SUITE_PSK 0x02F25000 ++ ++#define ELEM_ID_RSN_LEN_FIXED 20 /* The RSN IE len for associate request */ ++ ++#define ELEM_ID_WPA_LEN_FIXED 22 /* The RSN IE len for associate request */ ++ ++#define MASK_RSNIE_CAP_PREAUTH BIT(0) ++ ++#define GET_SELECTOR_TYPE(x) ((UINT_8)(((x) >> 24) & 0x000000FF)) ++#define SET_SELECTOR_TYPE(x, y) {x = (((x) & 0x00FFFFFF) | (((UINT_32)(y) << 24) & 0xFF000000))} ++ ++#define AUTH_CIPHER_CCMP 0x00000008 ++ ++/* Cihpher suite flags */ ++#define CIPHER_FLAG_NONE 0x00000000 ++#define CIPHER_FLAG_WEP40 0x00000001 /* BIT 1 */ ++#define CIPHER_FLAG_TKIP 0x00000002 /* BIT 2 */ ++#define CIPHER_FLAG_CCMP 0x00000008 /* BIT 4 */ ++#define CIPHER_FLAG_WEP104 0x00000010 /* BIT 5 */ ++#define CIPHER_FLAG_WEP128 0x00000020 /* BIT 6 */ ++ ++#define WAIT_TIME_IND_PMKID_CANDICATE_SEC 6 /* seconds */ ++#define TKIP_COUNTERMEASURE_SEC 60 /* seconds */ ++ ++#if CFG_SUPPORT_802_11W ++#define RSN_AUTH_MFP_DISABLED 0 /* MFP disabled */ ++#define RSN_AUTH_MFP_OPTIONAL 1 /* MFP optional */ ++#define RSN_AUTH_MFP_REQUIRED 2 /* MFP required */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* Flags for PMKID Candidate list structure */ ++#define EVENT_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++ ++#define CONTROL_FLAG_UC_MGMT_NO_ENC BIT(5) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define RSN_IE(fp) ((P_RSN_INFO_ELEM_T) fp) ++#define WPA_IE(fp) ((P_WPA_INFO_ELEM_T) fp) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo); ++ ++BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo); ++ ++BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index); ++ ++BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index); ++ ++BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++BOOLEAN ++rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion); ++ ++BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo); ++ ++#if CFG_SUPPORT_AAA ++void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode); ++#endif ++ ++VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType); ++ ++VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex); ++ ++BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter); ++ ++VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter); ++ ++VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++#if CFG_SUPPORT_WPS2 ++VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++#endif ++ ++#if CFG_SUPPORT_802_11W ++UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter); ++ ++void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter); ++ ++void rsnStartSaQuery(IN P_ADAPTER_T prAdapter); ++ ++void rsnStopSaQuery(IN P_ADAPTER_T prAdapter); ++ ++void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype); ++#endif ++BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _RSN_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h +new file mode 100644 +index 000000000000..c08b2244be6c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h +@@ -0,0 +1,988 @@ ++/* ++** Id: @(#) ++*/ ++ ++/*! \file "scan.h" ++ \brief ++ ++*/ ++ ++/* ++** Log: scan.h ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting ++ * preferred band configuration corresponding to network type. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID ++ * in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings ++ * to work around some tricky AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module ++ * with structure miss-align pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix compile error. ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add a functio prototype to find p2p descriptor of a bss descriptor directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add function prototype for return channel. ++ * modify data structure for scan specific device ID or TYPE. (Move from P2P Connection Settings to Scan Param) ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Check-in P2P Device Discovery Feature. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add a option for channel time extension in scan abort command. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Scan status "FIND" is used for P2P FSM find state. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, other request ++ * will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related field in SCAN_PARAM_T. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * ++ * Add new HW CH macro support ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify scanBuildProbeReqFrameCommonIEs() to support P2P SCAN ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver ++ * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Simplify the process of Beacon during SCAN and remove redundant variable in PRE_BSS_DESC_T ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding variable for wapi ap ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove non-used secuirty variavle ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Refine data structure of BSS_DESC_T and PRE_BSS_DESC_T ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add eNetType to rScanParam and revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add ucAvailablePhyTypeSet to BSS_DESC_T ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aucSrcAddress to SCAN_PARAM_T for P2P's Device Address ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security related variable ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security ie filed for scan parsing ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scanSearchBssDescByPolicy() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function declarations of scan_fsm.c ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scan.h to source control ++** ++*/ ++ ++#ifndef _SCAN_H ++#define _SCAN_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_vendor.h" ++ ++/* TDLS test purpose */ ++extern BOOLEAN flgTdlsTestExtCapElm; ++extern UINT8 aucTdlsTestExtCapElm[]; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*! Maximum buffer size of SCAN list */ ++#define SCN_MAX_BUFFER_SIZE (CFG_MAX_NUM_BSS_LIST * ALIGN_4(sizeof(BSS_DESC_T))) ++ ++#define SCN_RM_POLICY_EXCLUDE_CONNECTED BIT(0) /* Remove SCAN result except the connected one. */ ++#define SCN_RM_POLICY_TIMEOUT BIT(1) /* Remove the timeout one */ ++#define SCN_RM_POLICY_OLDEST_HIDDEN BIT(2) /* Remove the oldest one with hidden ssid */ ++#define SCN_RM_POLICY_SMART_WEAKEST BIT(3) /* If there are more than half BSS which has the ++ * same ssid as connection setting, remove the ++ * weakest one from them ++ * Else remove the weakest one. ++ */ ++#define SCN_RM_POLICY_ENTIRE BIT(4) /* Remove entire SCAN result */ ++ ++#define SCN_BSS_DESC_SAME_SSID_THRESHOLD 3 /* This is used by POLICY SMART WEAKEST, ++ * If exceed this value, remove weakest BSS_DESC_T ++ * with same SSID first in large network. ++ */ ++ ++/* the scan time in WFD mode + 2.4G/5G is about 9s so we need to enlarge the value */ ++#define SCN_BSS_DESC_REMOVE_TIMEOUT_SEC 15 /* Second. */ ++ /* This is used by POLICY TIMEOUT, ++ * If exceed this value, remove timeout BSS_DESC_T. ++ */ ++ ++#define SCN_PROBE_DELAY_MSEC 0 ++ ++#define SCN_ADHOC_BSS_DESC_TIMEOUT_SEC 5 /* Second. */ ++ ++#define SCN_NLO_NETWORK_CHANNEL_NUM (4) ++ ++/*----------------------------------------------------------------------------*/ ++/* MSG_SCN_SCAN_REQ */ ++/*----------------------------------------------------------------------------*/ ++#define SCAN_REQ_SSID_WILDCARD BIT(0) ++#define SCAN_REQ_SSID_P2P_WILDCARD BIT(1) ++#define SCAN_REQ_SSID_SPECIFIED BIT(2) ++ ++/*----------------------------------------------------------------------------*/ ++/* Support Multiple SSID SCAN */ ++/*----------------------------------------------------------------------------*/ ++#define SCN_SSID_MAX_NUM CFG_SCAN_SSID_MAX_NUM ++#define SCN_SSID_MATCH_MAX_NUM CFG_SCAN_SSID_MATCH_MAX_NUM ++ ++#define SWC_NUM_BSSID_THRESHOLD_DEFAULT 8 ++#define SWC_RSSI_WINDSIZE_DEFAULT 8 ++#define LOST_AP_WINDOW 16 ++#define MAX_CHANNEL_NUM_PER_BUCKETS 8 ++ ++#define SCN_BSS_JOIN_FAIL_THRESOLD 4 ++#define SCN_BSS_JOIN_FAIL_CNT_RESET_SEC 15 ++#define SCN_BSS_JOIN_FAIL_RESET_STEP 2 ++ ++#if CFG_SUPPORT_BATCH_SCAN ++/*----------------------------------------------------------------------------*/ ++/* SCAN_BATCH_REQ */ ++/*----------------------------------------------------------------------------*/ ++#define SCAN_BATCH_REQ_START BIT(0) ++#define SCAN_BATCH_REQ_STOP BIT(1) ++#define SCAN_BATCH_REQ_RESULT BIT(2) ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SCAN_TYPE_T { ++ SCAN_TYPE_PASSIVE_SCAN = 0, ++ SCAN_TYPE_ACTIVE_SCAN, ++ SCAN_TYPE_NUM ++} ENUM_SCAN_TYPE_T, *P_ENUM_SCAN_TYPE_T; ++ ++typedef enum _ENUM_SCAN_STATE_T { ++ SCAN_STATE_IDLE = 0, ++ SCAN_STATE_SCANNING, ++ SCAN_STATE_NUM ++} ENUM_SCAN_STATE_T; ++ ++typedef enum _ENUM_SCAN_CHANNEL_T { ++ SCAN_CHANNEL_FULL = 0, ++ SCAN_CHANNEL_2G4, ++ SCAN_CHANNEL_5G, ++ SCAN_CHANNEL_P2P_SOCIAL, ++ SCAN_CHANNEL_SPECIFIED, ++ SCAN_CHANNEL_NUM ++} ENUM_SCAN_CHANNEL, *P_ENUM_SCAN_CHANNEL; ++ ++typedef struct _MSG_SCN_FSM_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_32 u4Dummy; ++} MSG_SCN_FSM_T, *P_MSG_SCN_FSM_T; ++ ++typedef enum _ENUM_PSCAN_STATE_T { ++ PSCN_IDLE = 1, ++ PSCN_SCANNING, ++ PSCN_RESET, ++ PSCAN_STATE_T_NUM ++} ENUM_PSCAN_STATE_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* BSS Descriptors */ ++/*----------------------------------------------------------------------------*/ ++struct _BSS_DESC_T { ++ LINK_ENTRY_T rLinkEntry; ++ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ ++ ++ BOOLEAN fgIsConnecting; /* If we are going to connect to this BSS ++ * (JOIN or ROAMING to another BSS), don't ++ * remove this record from BSS List. ++ */ ++ BOOLEAN fgIsConnected; /* If we have connected to this BSS (NORMAL_TR), ++ * don't removed this record from BSS list. ++ */ ++ ++ BOOLEAN fgIsHiddenSSID; /* When this flag is TRUE, means the SSID ++ * of this BSS is not known yet. ++ */ ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ ++ OS_SYSTIME rUpdateTime; ++ ++ ENUM_BSS_TYPE_T eBSSType; ++ ++ UINT_16 u2CapInfo; ++ ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2ATIMWindow; ++ ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ BOOLEAN fgIsERPPresent; ++ BOOLEAN fgIsHTPresent; ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this BSS */ ++ ++ UINT_8 ucChannelNum; ++ ++ ENUM_CHNL_EXT_T eSco; /* Record bandwidth for association process ++ Some AP will send association resp by 40MHz BW */ ++ ENUM_BAND_T eBand; ++ ++ UINT_8 ucDTIMPeriod; ++ ++ BOOLEAN fgIsLargerTSF; /* This BSS's TimeStamp is larger than us(TCL == 1 in RX_STATUS_T) */ ++ ++ UINT_8 ucRCPI; ++ ++ UINT_8 ucWmmFlag; /* A flag to indicate this BSS's WMM capability */ ++ ++ /*! \brief The srbiter Search State will matched the scan result, ++ and saved the selected cipher and akm, and report the score, ++ for arbiter join state, join module will carry this target BSS ++ to rsn generate ie function, for gen wpa/rsn ie */ ++ UINT_32 u4RsnSelectedGroupCipher; ++ UINT_32 u4RsnSelectedPairwiseCipher; ++ UINT_32 u4RsnSelectedAKMSuite; ++ ++ UINT_16 u2RsnCap; ++ ++ RSN_INFO_T rRSNInfo; ++ RSN_INFO_T rWPAInfo; ++#if 1 /* CFG_SUPPORT_WAPI */ ++ WAPI_INFO_T rIEWAPI; ++ BOOLEAN fgIEWAPI; ++#endif ++ BOOLEAN fgIERSN; ++ BOOLEAN fgIEWPA; ++ ++ /*! \brief RSN parameters selected for connection */ ++ /*! \brief The Select score for final AP selection, ++ 0, no sec, 1,2,3 group cipher is WEP, TKIP, CCMP */ ++ UINT_8 ucEncLevel; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2PPresent; ++ BOOLEAN fgIsP2PReport; /* TRUE: report to upper layer */ ++ P_P2P_DEVICE_DESC_T prP2pDesc; ++ ++ UINT_8 aucIntendIfAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ ++/* UINT_8 ucDevCapabilityBitmap; */ /* Device Capability Attribute. (P2P_DEV_CAPABILITY_XXXX) */ ++/* UINT_8 ucGroupCapabilityBitmap; */ /* Group Capability Attribute. (P2P_GROUP_CAPABILITY_XXXX) */ ++ ++ LINK_T rP2pDeviceList; ++ ++/* P_LINK_T prP2pDeviceList; */ ++ ++ /* For ++ * 1. P2P Capability. ++ * 2. P2P Device ID. ( in aucSrcAddr[] ) ++ * 3. NOA (TODO:) ++ * 4. Extend Listen Timing. (Probe Rsp) (TODO:) ++ * 5. P2P Device Info. (Probe Rsp) ++ * 6. P2P Group Info. (Probe Rsp) ++ */ ++#endif ++ ++ BOOLEAN fgIsIEOverflow; /* The received IE length exceed the maximum IE buffer size */ ++ UINT_16 u2RawLength; /* The byte count of aucRawBuf[] */ ++ UINT_16 u2IELength; /* The byte count of aucIEBuf[] */ ++ ++ ULARGE_INTEGER u8TimeStamp; /* Place u8TimeStamp before aucIEBuf[1] to force DW align */ ++ UINT_8 aucRawBuf[CFG_RAW_BUFFER_SIZE]; ++ UINT_8 aucIEBuf[CFG_IE_BUFFER_SIZE]; ++ UINT_8 ucJoinFailureCount; ++ OS_SYSTIME rJoinFailTime; ++}; ++ ++typedef struct _SCAN_PARAM_T { /* Used by SCAN FSM */ ++ /* Active or Passive */ ++ ENUM_SCAN_TYPE_T eScanType; ++ ++ /* Network Type */ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ ++ /* Specified SSID Type */ ++ UINT_8 ucSSIDType; ++ UINT_8 ucSSIDNum; ++ ++ /* Length of Specified SSID */ ++ UINT_8 ucSpecifiedSSIDLen[SCN_SSID_MAX_NUM]; ++ ++ /* Specified SSID */ ++ UINT_8 aucSpecifiedSSID[SCN_SSID_MAX_NUM][ELEM_MAX_LEN_SSID]; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgFindSpecificDev; /* P2P: Discovery Protocol */ ++ UINT_8 aucDiscoverDevAddr[MAC_ADDR_LEN]; ++ BOOLEAN fgIsDevType; ++ P2P_DEVICE_TYPE_T rDiscoverDevType; ++ ++ UINT_16 u2PassiveListenInterval; ++ /* TODO: Find Specific Device Type. */ ++#endif /* CFG_SUPPORT_P2P */ ++ ++ BOOLEAN fgIsObssScan; ++ BOOLEAN fgIsScanV2; ++ ++ /* Run time flags */ ++ UINT_16 u2ProbeDelayTime; ++ ++ /* channel information */ ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ ++ /* Feedback information */ ++ UINT_8 ucSeqNum; ++ ++ /* Information Element */ ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++ ++} SCAN_PARAM_T, *P_SCAN_PARAM_T; ++ ++typedef struct _NLO_PARAM_T { /* Used by SCAN FSM */ ++ SCAN_PARAM_T rScanParam; ++ ++ /* NLO */ ++ BOOLEAN fgStopAfterIndication; ++ UINT_8 ucFastScanIteration; ++ UINT_16 u2FastScanPeriod; ++ UINT_16 u2SlowScanPeriod; ++ ++ /* Match SSID */ ++ UINT_8 ucMatchSSIDNum; ++ UINT_8 ucMatchSSIDLen[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_8 aucMatchSSID[SCN_SSID_MATCH_MAX_NUM][ELEM_MAX_LEN_SSID]; ++ ++ UINT_8 aucCipherAlgo[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_16 au2AuthAlgo[SCN_SSID_MATCH_MAX_NUM]; ++ UINT_8 aucChannelHint[SCN_SSID_MATCH_MAX_NUM][SCN_NLO_NETWORK_CHANNEL_NUM]; ++ P_BSS_DESC_T aprPendingBssDescToInd[SCN_SSID_MATCH_MAX_NUM]; ++} NLO_PARAM_T, *P_NLO_PARAM_T; ++ ++#if 1 ++ ++typedef struct _GSCN_CHANNEL_INFO_T { ++ UINT_8 ucBand; ++ UINT_8 ucChannel; /* frequency */ ++ UINT_8 ucPassive; /* 0 => active, 1 => passive scan; ignored for DFS */ ++ UINT_8 aucReserved[1]; ++ ++ UINT_32 u4DwellTimeMs; /* dwell time hint */ ++ /* Add channel class */ ++} GSCN_CHANNEL_INFO_T, *P_GSCN_CHANNEL_INFO_T; ++ ++typedef struct _GSCAN_CHANNEL_BUCKET_T { ++ ++ UINT_16 u2BucketIndex; /* bucket index, 0 based */ ++ UINT_8 ucBucketFreqMultiple; /* desired period, in millisecond; ++ * if this is too low, the firmware should choose to generate ++ * results as fast as it can instead of failing the command */ ++ /* report_events semantics - ++ * 0 => report only when scan history is % full ++ * 1 => same as 0 + report a scan completion event after scanning this bucket ++ * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL ++ * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to ++ supplicant as well (optional) . */ ++ UINT_8 ucReportFlag; ++ UINT_8 ucNumChannels; ++ UINT_8 aucReserved[3]; ++ WIFI_BAND eBand; /* when UNSPECIFIED, use channel list */ ++ GSCN_CHANNEL_INFO_T arChannelList[GSCAN_MAX_CHANNELS]; /* channels to scan; these may include DFS channels */ ++} GSCAN_CHANNEL_BUCKET_T, *P_GSCAN_CHANNEL_BUCKET_T; ++ ++typedef struct _CMD_GSCN_REQ_T { ++ UINT_8 ucFlags; ++ UINT_8 ucNumScnToCache; ++ UINT_8 aucReserved[2]; ++ UINT_32 u4BufferThreshold; ++ UINT_32 u4BasePeriod; /* base timer period in ms */ ++ UINT_32 u4NumBuckets; ++ UINT_32 u4MaxApPerScan; /* number of APs to store in each scan in the */ ++ /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ ++ ++ GSCAN_CHANNEL_BUCKET_T arChannelBucket[GSCAN_MAX_BUCKETS]; ++} CMD_GSCN_REQ_T, *P_CMD_GSCN_REQ_T; ++ ++#endif ++ ++typedef struct _CMD_GSCN_SCN_COFIG_T { ++ UINT_8 ucNumApPerScn; /* GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN */ ++ UINT_32 u4NumScnToCache; /* GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE */ ++ UINT_32 u4BufferThreshold; /* GSCAN_ATTRIBUTE_REPORT_THRESHOLD */ ++} CMD_GSCN_SCN_COFIG_T, *P_CMD_GSCN_SCN_COFIG_T; ++ ++typedef struct _CMD_GET_GSCAN_RESULT { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[2]; ++ UINT_8 ucFlush; ++ UINT_32 u4Num; ++} CMD_GET_GSCAN_RESULT_T, *P_CMD_GET_GSCAN_RESULT_T; ++ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd like ++ approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++typedef struct _PSCN_PARAM_T { ++ UINT_8 ucVersion; ++ CMD_NLO_REQ rCurrentCmdNloReq; ++ CMD_BATCH_REQ_T rCurrentCmdBatchReq; ++ CMD_GSCN_REQ_T rCurrentCmdGscnReq; ++ BOOLEAN fgNLOScnEnable; ++ BOOLEAN fgBatchScnEnable; ++ BOOLEAN fgGScnEnable; ++ UINT_32 u4BasePeriod; /* GSCAN_ATTRIBUTE_BASE_PERIOD */ ++} PSCN_PARAM_T, *P_PSCN_PARAM_T; ++ ++typedef struct _SCAN_INFO_T { ++ ENUM_SCAN_STATE_T eCurrentState; /* Store the STATE variable of SCAN FSM */ ++ ++ OS_SYSTIME rLastScanCompletedTime; ++ ++ SCAN_PARAM_T rScanParam; ++ NLO_PARAM_T rNloParam; ++ ++ UINT_32 u4NumOfBssDesc; ++ ++ UINT_8 aucScanBuffer[SCN_MAX_BUFFER_SIZE]; ++ ++ LINK_T rBSSDescList; ++ ++ LINK_T rFreeBSSDescList; ++ ++ LINK_T rPendingMsgList; ++ ++ /* Sparse Channel Detection */ ++ BOOLEAN fgIsSparseChannelValid; ++ RF_CHANNEL_INFO_T rSparseChannel; ++ ++ /* NLO scanning state tracking */ ++ BOOLEAN fgNloScanning; ++ BOOLEAN fgPscnOnnning; ++ BOOLEAN fgGScnConfigSet; ++ BOOLEAN fgGScnParamSet; ++ P_PSCN_PARAM_T prPscnParam; ++ ENUM_PSCAN_STATE_T eCurrentPSCNState; ++ ++} SCAN_INFO_T, *P_SCAN_INFO_T; ++ ++/* Incoming Mailbox Messages */ ++typedef struct _MSG_SCN_SCAN_REQ_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_TYPE_T eScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucSSID[PARAM_MAX_LEN_SSID]; ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ ++#endif ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} MSG_SCN_SCAN_REQ, *P_MSG_SCN_SCAN_REQ; ++ ++typedef struct _MSG_SCN_SCAN_REQ_V2_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_TYPE_T eScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDNum; ++ P_PARAM_SSID_T prSsid; ++ UINT_16 u2ProbeDelay; ++ UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ ++ ENUM_SCAN_CHANNEL eScanChannel; ++ UINT_8 ucChannelListNum; ++ RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} MSG_SCN_SCAN_REQ_V2, *P_MSG_SCN_SCAN_REQ_V2; ++ ++typedef struct _MSG_SCN_SCAN_CANCEL_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsChannelExt; ++#endif ++} MSG_SCN_SCAN_CANCEL, *P_MSG_SCN_SCAN_CANCEL; ++ ++/* Outgoing Mailbox Messages */ ++typedef enum _ENUM_SCAN_STATUS_T { ++ SCAN_STATUS_DONE = 0, ++ SCAN_STATUS_CANCELLED, ++ SCAN_STATUS_FAIL, ++ SCAN_STATUS_BUSY, ++ SCAN_STATUS_NUM ++} ENUM_SCAN_STATUS, *P_ENUM_SCAN_STATUS; ++ ++typedef struct _MSG_SCN_SCAN_DONE_T { ++ MSG_HDR_T rMsgHdr; /* Must be the first member */ ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ ENUM_SCAN_STATUS eScanStatus; ++} MSG_SCN_SCAN_DONE, *P_MSG_SCN_SCAN_DONE; ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++typedef enum { ++ AGPS_PHY_A, ++ AGPS_PHY_B, ++ AGPS_PHY_G, ++} AP_PHY_TYPE; ++ ++typedef struct _AGPS_AP_INFO_T { ++ UINT_8 aucBSSID[6]; ++ INT_16 i2ApRssi; /* -127..128 */ ++ UINT_16 u2Channel; /* 0..256 */ ++ AP_PHY_TYPE ePhyType; ++} AGPS_AP_INFO_T, *P_AGPS_AP_INFO_T; ++ ++typedef struct _AGPS_AP_LIST_T { ++ UINT_8 ucNum; ++ AGPS_AP_INFO_T arApInfo[32]; ++} AGPS_AP_LIST_T, *P_AGPS_AP_LIST_T; ++#endif ++ ++typedef struct _CMD_SET_PSCAN_PARAM { ++ UINT_8 ucVersion; ++ CMD_NLO_REQ rCmdNloReq; ++ CMD_BATCH_REQ_T rCmdBatchReq; ++ CMD_GSCN_REQ_T rCmdGscnReq; ++ BOOLEAN fgNLOScnEnable; ++ BOOLEAN fgBatchScnEnable; ++ BOOLEAN fgGScnEnable; ++ UINT_32 u4BasePeriod; ++} CMD_SET_PSCAN_PARAM, *P_CMD_SET_PSCAN_PARAM; ++ ++typedef struct _CMD_SET_PSCAN_ADD_HOTLIST_BSSID { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucFlags; ++ UINT_8 aucReserved[5]; ++} CMD_SET_PSCAN_ADD_HOTLIST_BSSID, *P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID; ++ ++typedef struct _CMD_SET_PSCAN_ADD_SWC_BSSID { ++ INT_32 i4RssiLowThreshold; ++ INT_32 i4RssiHighThreshold; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucReserved[6]; ++} CMD_SET_PSCAN_ADD_SWC_BSSID, *P_CMD_SET_PSCAN_ADD_SWC_BSSID; ++ ++typedef struct _CMD_SET_PSCAN_MAC_ADDR { ++ UINT_8 ucVersion; ++ UINT_8 ucFlags; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucReserved[8]; ++} CMD_SET_PSCAN_MAC_ADDR, *P_CMD_SET_PSCAN_MAC_ADDR; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in scan.c */ ++/*----------------------------------------------------------------------------*/ ++VOID scnInit(IN P_ADAPTER_T prAdapter); ++ ++VOID scnUninit(IN P_ADAPTER_T prAdapter); ++ ++/* BSS-DESC Search */ ++P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++P_BSS_DESC_T ++scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]); ++ ++P_BSS_DESC_T ++scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++#endif ++ ++/* BSS-DESC Search - Alternative */ ++P_BSS_DESC_T ++scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]); ++ ++P_BSS_DESC_T ++scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, ++ IN UINT_8 aucBSSID[], ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); ++ ++/* BSS-DESC Allocation */ ++P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter); ++ ++/* BSS-DESC Removal */ ++VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy); ++ ++VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++VOID ++scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/* BSS-DESC State Change */ ++VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); ++ ++#if 0 ++/* BSS-DESC Insertion */ ++P_BSS_DESC_T scanAddToInternalScanResult(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb, IN P_BSS_DESC_T prBssDesc); ++#endif ++ ++/* BSS-DESC Insertion - ALTERNATIVE */ ++P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); ++ ++VOID ++scanBuildProbeReqFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, ++ IN PUINT_8 pucDesiredSsid, IN UINT_32 u4DesiredSsidLen, IN UINT_16 u2SupportedRateSet); ++ ++WLAN_STATUS scanSendProbeReqFrames(IN P_ADAPTER_T prAdapter, IN P_SCAN_PARAM_T prScanParam); ++ ++VOID scanUpdateBssDescForSearch(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); ++ ++P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); ++ ++VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in scan_fsm.c */ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState); ++ ++/*----------------------------------------------------------------------------*/ ++/* Command Routines */ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReq(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter); ++ ++VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* RX Event Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone); ++ ++VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg); ++ ++VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg); ++ ++VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Generation */ ++/*----------------------------------------------------------------------------*/ ++VOID ++scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Query for sparse channel */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSsidNum, ++ IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval); ++ ++BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct); ++ ++BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++ ++BOOLEAN scnFsmGSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++ ++#if 0 ++ ++BOOLEAN scnFsmGSCNSetRssiSignificatn(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); ++#endif ++ ++BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId); ++ ++BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr); ++ ++#if 1 /* CFG_SUPPORT_GSCN_NONSYNC_BROADCOM */ ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam); ++ ++#else ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_REQ_T prCmdGscnParam); ++ ++#endif ++ ++BOOLEAN ++scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN); ++ ++BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig); ++ ++BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd); ++ ++VOID ++scnPSCNFsm(IN P_ADAPTER_T prAdapter, ++ ENUM_PSCAN_STATE_T eNextPSCNState, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN); ++ ++#endif /* _SCAN_H */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter); ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h +new file mode 100644 +index 000000000000..c6c468e06c4a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h +@@ -0,0 +1,233 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/sec_fsm.h#1 ++*/ ++ ++/*! \file sec_fsm.h ++ \brief Declaration of functions and finite state machine for SECURITY Module. ++ ++ Function declaration for privacy.c and SEC_STATE for SECURITY FSM. ++*/ ++ ++/* ++** Log: sec_fsm.h ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 03 04 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Code refine, and remove non-used code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, and modify the security ++ * related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * fixed the deauth Tx done callback parameter ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the reference function declaration ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * delete non-used code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function prototype ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function declaration ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the security variable ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** \main\maintrunk.MT5921\14 2009-04-06 15:35:47 GMT mtk01088 ++** add the variable to set the disable AP selection for privacy check, for wps open networking. ++** \main\maintrunk.MT5921\13 2008-11-19 11:46:01 GMT mtk01088 ++** rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\12 2008-08-28 20:37:11 GMT mtk01088 ++** remove non-used code ++** ++** \main\maintrunk.MT5921\11 2008-03-18 09:51:52 GMT mtk01088 ++** Add function declaration for timer to indicate pmkid candidate ++** \main\maintrunk.MT5921\10 2008-02-29 15:12:08 GMT mtk01088 ++** add variable for sw port control ++** \main\maintrunk.MT5921\9 2008-02-29 12:37:30 GMT mtk01088 ++** rename the security related function declaration ++** \main\maintrunk.MT5921\8 2007-12-27 13:59:08 GMT mtk01088 ++** adjust the wlan table and sec fsm init timing ++** \main\maintrunk.MT5921\7 2007-11-20 10:39:49 GMT mtk01088 ++** add function timer for wait EAPoL Error timeout ++** \main\maintrunk.MT5921\6 2007-11-06 20:39:08 GMT mtk01088 ++** rename the counter measure timer ++** \main\maintrunk.MT5921\5 2007-11-06 20:14:31 GMT mtk01088 ++** add a abort function ++** Revision 1.5 2007/07/16 02:33:42 MTK01088 ++** change the ENUM declaration structure prefix from r to e ++** ++** Revision 1.4 2007/07/09 06:23:10 MTK01088 ++** update ++** ++** Revision 1.3 2007/07/04 10:09:04 MTK01088 ++** adjust the state for security fsm ++** change function name ++** ++** Revision 1.2 2007/07/03 08:13:22 MTK01088 ++** change the sec fsm state ++** add the event for sec fsm ++** ++** Revision 1.1 2007/06/27 06:20:35 MTK01088 ++** add the sec fsm header file ++** ++** ++*/ ++#ifndef _SEC_FSM_H ++#define _SEC_FSM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* TKIP CounterMeasure interval for Rejoin to Network. */ ++#define COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC 60 ++ ++/* Timeout to wait the EAPoL Error Report frame Send out. */ ++#define EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef UINT_32 SEC_STATUS, *P_SEC_STATUS; ++ ++#if 0 ++/* WPA2 PMKID candicate structure */ ++typedef struct _PMKID_CANDICATE_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; /* MAC address */ ++ UINT_32 u4PreAuthFlags; ++} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; ++#endif ++ ++typedef SEC_STATUS(*PFN_SEC_FSM_STATE_HANDLER) (VOID); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SEC_STATE_TRANSITION_FLAG fgIsTransition ++#define SEC_NEXT_STATE_VAR eNextState ++ ++#define SEC_STATE_TRANSITION(prAdapter, prSta, eFromState, eToState) \ ++ { secFsmTrans_ ## eFromState ## _to_ ## eToState(prAdapter, prSta); \ ++ SEC_NEXT_STATE_VAR = SEC_STATE_ ## eToState; \ ++ SEC_STATE_TRANSITION_FLAG = (BOOLEAN)TRUE; \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle the sec check */ ++/*--------------------------------------------------------------*/ ++/***** Routines in sec_fsm.c *****/ ++VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID ++secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++ ++VOID ++secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); ++ ++VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _SEC_FSM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h +new file mode 100644 +index 000000000000..1c0f9a76e119 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h +@@ -0,0 +1,368 @@ ++/* ++** Id: stats.h#1 ++*/ ++ ++/*! \file stats.h ++ \brief This file includes statistics support. ++*/ ++ ++/* ++** Log: stats.h ++ * ++ * 07 17 2014 samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++extern UINT_64 u8DrvOwnStart, u8DrvOwnEnd; ++extern UINT32 u4DrvOwnMax; ++extern BOOLEAN fgIsUnderSuspend; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* Command to TDLS core module */ ++typedef enum _STATS_CMD_CORE_ID { ++ STATS_CORE_CMD_ENV_REQUEST = 0x00 ++} STATS_CMD_CORE_ID; ++ ++typedef enum _STATS_EVENT_HOST_ID { ++ STATS_HOST_EVENT_ENV_REPORT = 0x00, ++ STATS_HOST_EVENT_RX_DROP ++} STATS_EVENT_HOST_ID; ++ ++#define CFG_ARP BIT(0) ++#define CFG_DNS BIT(1) ++#define CFG_TCP BIT(2) ++#define CFG_UDP BIT(3) ++#define CFG_EAPOL BIT(4) ++#define CFG_DHCP BIT(5) ++#define CFG_ICMP BIT(6) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _STATS_CMD_CORE_T { ++ ++ UINT32 u4Command; /* STATS_CMD_CORE_ID */ ++ ++ UINT8 ucStaRecIdx; ++ UINT8 ucReserved[3]; ++ ++ UINT32 u4Reserved[4]; ++ ++#define STATS_CMD_CORE_RESERVED_SIZE 50 ++ union { ++ UINT8 Reserved[STATS_CMD_CORE_RESERVED_SIZE]; ++ } Content; ++ ++} STATS_CMD_CORE_T; ++ ++typedef struct _STATS_INFO_ENV_T { ++ ++ BOOLEAN fgIsUsed; /* TRUE: used */ ++ ++ /* ------------------- TX ------------------- */ ++ BOOLEAN fgTxIsRtsUsed; /* TRUE: we use RTS/CTS currently */ ++ BOOLEAN fgTxIsRtsEverUsed; /* TRUE: we ever use RTS/CTS */ ++ BOOLEAN fgTxIsCtsSelfUsed; /* TRUE: we use CTS-self */ ++ ++#define STATS_INFO_TX_PARAM_HW_BW40_OFFSET 0 ++#define STATS_INFO_TX_PARAM_HW_SHORT_GI20_OFFSET 1 ++#define STATS_INFO_TX_PARAM_HW_SHORT_GI40_OFFSET 2 ++#define STATS_INFO_TX_PARAM_USE_BW40_OFFSET 3 ++#define STATS_INFO_TX_PARAM_USE_SHORT_GI_OFFSET 4 ++#define STATS_INFO_TX_PARAM_NO_ACK_OFFSET 5 ++ UINT_8 ucTxParam; ++ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucReserved1[2]; ++ ++ UINT32 u4TxDataCntAll; /* total tx count from host */ ++ UINT32 u4TxDataCntOK; /* total tx ok count to air */ ++ UINT32 u4TxDataCntErr; /* total tx err count to air */ ++ ++ /* WLAN_STATUS_BUFFER_RETAINED ~ WLAN_STATUS_PACKET_LIFETIME_ERROR */ ++ UINT32 u4TxDataCntErrType[6]; /* total tx err count for different type to air */ ++ ++ UINT_8 ucTxRate1NonHTMax; ++ UINT_8 ucTxRate1HTMax; ++ UINT32 u4TxRateCntNonHT[16]; /* tx done rate */ ++ UINT32 u4TxRateCntHT[16]; /* tx done rate */ ++ ++ UINT_8 ucTxAggBitmap; /* TX BA sessions TID0 ~ TID7 */ ++ UINT_8 ucTxPeerAggMaxSize; ++ ++ /* ------------------- RX ------------------- */ ++ BOOLEAN fgRxIsRtsUsed; /* TRUE: peer uses RTS/CTS currently */ ++ BOOLEAN fgRxIsRtsEverUsed; /* TRUE: peer ever uses RTS/CTS */ ++ ++ UINT_8 ucRcvRcpi; ++ UINT_8 ucHwChanNum; ++ BOOLEAN fgRxIsShortGI; ++ UINT_8 ucReserved2[1]; ++ ++ UINT32 u4RxDataCntAll; /* total rx count from peer */ ++ UINT32 u4RxDataCntErr; /* total rx err count */ ++ UINT32 u4RxRateCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ ++ ++ UINT_8 ucRxAggBitmap; /* RX BA sessions TID0 ~ TID7 */ ++ UINT_8 ucRxAggMaxSize; ++ ++#define STATS_INFO_PHY_MODE_CCK 0 ++#define STATS_INFO_PHY_MODE_OFDM 1 ++#define STATS_INFO_PHY_MODE_HT 2 ++#define STATS_INFO_PHY_MODE_VHT 3 ++ UINT_8 ucBssSupPhyMode; /* CCK, OFDM, HT, or VHT BSS */ ++ ++ UINT_8 ucVersion; /* the version of statistics info environment */ ++ ++ /* ------------------- Delay ------------------- */ ++#define STATS_AIR_DELAY_INT 500 /* 500 byte */ ++ ++ /* delay in firmware from host to MAC */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxH2M[3], u4StayIntMinH2M[3], u4StayIntAvgH2M[3]; ++ ++ /* delay in firmware from MAC to TX done */ ++ /* unit: 32us, for 500B, 1000B, max */ ++ UINT32 u4AirDelayMax[3], u4AirDelayMin[3], u4AirDelayAvg[3]; ++ ++ /* delay in firmware from host to TX done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMax[3], u4StayIntMin[3], u4StayIntAvg[3]; ++ UINT32 u4StayIntMaxSysTime[3]; ++ ++ /* delay in firmware from driver to TX done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxD2T[3], u4StayIntMinD2T[3], u4StayIntAvgD2T[3]; ++ ++ /* delay count in firmware from host to TX done */ ++ /* u4StayIntByConst: divide 4 fix partitions to count each delay in firmware */ ++#define STATS_STAY_INT_CONST 1 /* 1ms */ ++#define STATS_STAY_INT_CONST_2 5 ++#define STATS_STAY_INT_CONST_3 10 ++#define STATS_STAY_INT_CONST_4 15 ++#define STATS_STAY_INT_CONST_NUM 4 ++ UINT32 u4StayIntByConst[STATS_STAY_INT_CONST_NUM]; ++ ++ /* ++ u4StayIntMaxPast: past maximum delay in firmware ++ u4StayIntCnt[]: divide 4 partitions to count each delay in firmware ++ */ ++#define STATS_STAY_INT_NUM 4 ++ UINT32 u4StayIntMaxPast; ++ UINT32 u4StayIntCnt[STATS_STAY_INT_NUM + 1]; ++ ++ /* delay count in firmware from driver to HIF */ ++ /* u4StayIntD2HByConst: divide 4 fix partitions to count each delay in firmware */ ++#define STATS_STAY_INT_D2H_CONST 10 /* 10ms */ ++#define STATS_STAY_INT_D2H_CONST_2 20 ++#define STATS_STAY_INT_D2H_CONST_3 30 ++#define STATS_STAY_INT_D2H_CONST_4 40 ++#define STATS_STAY_INT_D2H_CONST_NUM 4 ++ UINT32 u4StayIntD2HByConst[STATS_STAY_INT_D2H_CONST_NUM]; ++ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; ++ ++ /* ------------------- Others ------------------- */ ++ UINT32 u4NumOfChanChange; /* total channel change count */ ++ UINT32 u4NumOfRetryCnt; /* total TX retry count */ ++ UINT32 u4RxFifoFullCnt; /* counter of the number of the packets which ++ pass RFCR but are dropped due to FIFO full. */ ++ UINT32 u4PsIntMax; /* maximum time from ps to active */ ++ UINT_8 ucNumOfPsChange; /* peer power save change count */ ++ UINT_8 ucReserved3[3]; ++ ++ UINT32 u4ReportSysTime; /* firmware system time */ ++ UINT32 u4RxDataCntOk; /* total rx count to hif */ ++ ++ /* V4 */ ++ UINT32 u4RxRateRetryCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ ++ UINT32 au4ChanIdleCnt[10]; /* past Channel idle count in unit of slot */ ++ ++ /* V5 */ ++ UINT32 u4BtContUseTime; /* the air time that BT continuous occypy */ ++ ++ /* V6 */ ++ UINT32 u4LastTxOkTime; /* last time we tx ok to the station */ ++ ++ /* V7 */ ++ UINT_8 ucBtWfCoexGrantCnt[8]; /* [0]:WF Rx Grant Cnt[1]: WF Tx Grant Cnt[2]: WF Grant with Priority1 */ ++ /* [4]:BT Rx Grant Cnt[5]: BT Tx Grant Cnt[6]: BT Grant with Priority1 */ ++ ++ /* V8 */ ++ UINT_32 u4RxMacFreeDescCnt[6]; ++ UINT_32 u4RxHifFreeDescCnt[6]; ++ ++ /* V9 */ ++#define STATS_MAX_RX_DROP_TYPE 20 ++ UINT32 u4NumOfRxDrop[STATS_MAX_RX_DROP_TYPE]; ++ ++ /* V10 */ ++ UINT_32 u4NumOfTxDone; /* number of all packets (data/man/ctrl) tx done */ ++ UINT_32 u4NumOfTxDoneFixRate; /* number of done rate = 0 */ ++ UINT_32 u4NumOfTxDoneErrRate; /* number of error done rate */ ++ UINT_32 u4NumOfNullTxDone; /* number of null tx done */ ++ UINT_32 u4NumOfQoSNullTxDone; /* number of QoS-null tx done */ ++ ++ /* V11 */ ++ /* delay in firmware from HIF RX to HIF RX Done */ ++ /* unit: us, for 500B, 1000B, max */ ++ UINT32 u4StayIntMaxHR2HRD[3], u4StayIntMinHR2HRD[3], u4StayIntAvgHR2HRD[3]; ++ ++ /* V12 */ ++ UINT32 u4AirDelayTotal; /* agg all the air delay */ ++ ++ /* V13 */ ++ UINT32 u4CurrChnlInfo; /* add current channel information */ ++ ++ UINT_8 ucReserved_rate[4]; /* the field must be the last one */ ++} STATS_INFO_ENV_T; ++ ++/******************************************************************************* ++* M A C R O D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#if (CFG_SUPPORT_STATISTICS == 1) ++ ++#define STATS_ENV_REPORT_DETECT statsEnvReportDetect ++ ++#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderFallAheadCnt++; \ ++} ++ ++#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderFallBehindCnt++; \ ++} ++ ++#define STATS_RX_REORDER_HOLE_INC(__StaRec__) \ ++{ \ ++ (__StaRec__)->u4RxReorderHoleCnt++; \ ++} ++ ++#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) \ ++{ \ ++ if ((__IsTimeout__) == TRUE) \ ++ (__StaRec__)->u4RxReorderHoleTimeoutCnt++; \ ++} ++ ++#define STATS_RX_ARRIVE_TIME_RECORD(__SwRfb__) \ ++{ \ ++ (__SwRfb__)->rRxTime = StatsEnvTimeGet(); \ ++} ++ ++#define STATS_RX_PASS2OS_INC StatsEnvRxDone ++ ++#define STATS_RX_PKT_INFO_DISPLAY StatsRxPktInfoDisplay ++ ++#define STATS_TX_TIME_ARRIVE(__Skb__) \ ++do { \ ++ UINT_64 __SysTime; \ ++ __SysTime = StatsEnvTimeGet(); /* us */ \ ++ GLUE_SET_PKT_XTIME(__Skb__, __SysTime); \ ++} while (FALSE) ++ ++#define STATS_TX_TIME_TO_HIF StatsEnvTxTime2Hif ++ ++#define STATS_TX_PKT_CALLBACK StatsTxPktCallBack ++#define STATS_TX_PKT_DONE_INFO_DISPLAY StatsTxPktDoneInfoDisplay ++ ++#define STATS_DRIVER_OWN_RESET() \ ++{ \ ++ u4DrvOwnMax = 0; \ ++} ++#define STATS_DRIVER_OWN_START_RECORD() \ ++{ \ ++ u8DrvOwnStart = StatsEnvTimeGet(); \ ++} ++#define STATS_DRIVER_OWN_END_RECORD() \ ++{ \ ++ u8DrvOwnEnd = StatsEnvTimeGet(); \ ++} ++#define STATS_DRIVER_OWN_STOP() \ ++do { \ ++ UINT32 __Diff; \ ++ __Diff = (UINT32)(u8DrvOwnEnd - u8DrvOwnStart); \ ++ if (__Diff > u4DrvOwnMax) \ ++ u4DrvOwnMax = __Diff; \ ++} while (FALSE) ++ ++#else ++ ++#define STATS_ENV_REPORT_DETECT(__Adapter__, __StaRecIndex__) ++ ++#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) ++#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) ++#define STATS_RX_REORDER_HOLE_INC(__StaRec__) ++#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) ++#define STATS_RX_PASS2OS_INC(__StaRec__, __SwRfb__) ++#define STATS_RX_PKT_INFO_DISPLAY(__Pkt__) ++ ++#define STATS_TX_TIME_ARRIVE(__Skb__) ++#define STATS_TX_TIME_TO_HIF(__MsduInfo__, __HwTxHeader__) ++#define STATS_TX_PKT_CALLBACK(__Pkt__, __fgIsNeedAck__) ++#define STATS_TX_PKT_DONE_INFO_DISPLAY(__Adapter__, __Event__) ++ ++#define STATS_DRIVER_OWN_RESET() ++#define STATS_DRIVER_OWN_START_RECORD() ++#define STATS_DRIVER_OWN_END_RECORD() ++#define STATS_DRIVER_OWN_STOP() ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex); ++ ++VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb); ++ ++UINT_64 StatsEnvTimeGet(VOID); ++ ++VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader); ++ ++VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++VOID StatsRxPktInfoDisplay(UINT_8 *pPkt); ++ ++VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo); ++ ++VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf); ++ ++VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet); ++ ++UINT_16 StatsGetCfgTxDone(VOID); ++ ++/* End of stats.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h +new file mode 100644 +index 000000000000..50c4b558c2cd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h +@@ -0,0 +1,187 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/swcr.h#1 ++*/ ++ ++/*! \file "swcr.h" ++ \brief ++*/ ++ ++/* ++ * ++ */ ++ ++#ifndef _SWCR_H ++#define _SWCR_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "nic_cmd_event.h" ++ ++#if 0 ++extern SWCR_MAP_ENTRY_T g_arRlmArSwCrMap[]; ++#endif ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define SWCR_VAR(x) ((VOID *)&x) ++#define SWCR_FUNC(x) ((VOID *)x) ++ ++#define SWCR_T_FUNC BIT(7) ++ ++#define SWCR_L_32 3 ++#define SWCR_L_16 2 ++#define SWCR_L_8 1 ++ ++#define SWCR_READ 0 ++#define SWCR_WRITE 1 ++ ++#define SWCR_MAP_NUM(x) (sizeof(x)/sizeof(x[0])) ++ ++#define SWCR_CR_NUM 7 ++ ++#define SWCR_GET_RW_INDEX(action, rw, index) \ ++do { \ ++ index = action & 0x7F; \ ++ rw = action >> 7; \ ++} while (0) ++ ++extern UINT_32 g_au4SwCr[]; /*: 0: command other: data */ ++ ++typedef VOID(*PFN_SWCR_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++typedef VOID(*PFN_CMD_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++ ++typedef struct _SWCR_MAP_ENTRY_T { ++ UINT_16 u2Type; ++ PVOID u4Addr; ++} SWCR_MAP_ENTRY_T, *P_SWCR_MAP_ENTRY_T; ++ ++typedef struct _SWCR_MOD_MAP_ENTRY_T { ++ UINT_8 ucMapNum; ++ P_SWCR_MAP_ENTRY_T prSwCrMap; ++} SWCR_MOD_MAP_ENTRY_T, *P_SWCR_MOD_MAP_ENTRY_T; ++ ++typedef enum _ENUM_SWCR_DBG_TYPE_T { ++ SWCR_DBG_TYPE_ALL = 0, ++ SWCR_DBG_TYPE_TXRX, ++ SWCR_DBG_TYPE_RX_RATES, ++ SWCR_DBG_TYPE_PS, ++ SWCR_DBG_TYPE_NUM ++} ENUM_SWCR_DBG_TYPE_T; ++ ++typedef enum _ENUM_SWCR_DBG_ALL_T { ++ SWCR_DBG_ALL_TX_CNT = 0, ++ SWCR_DBG_ALL_TX_BCN_CNT, ++ SWCR_DBG_ALL_TX_FAILED_CNT, ++ SWCR_DBG_ALL_TX_RETRY_CNT, ++ SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT, ++ SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT, ++ SWCR_DBG_ALL_TX_MGNT_DROP_CNT, ++ SWCR_DBG_ALL_TX_ERROR_CNT, ++ ++ SWCR_DBG_ALL_RX_CNT, ++ SWCR_DBG_ALL_RX_DROP_CNT, ++ SWCR_DBG_ALL_RX_DUP_DROP_CNT, ++ SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT, ++ ++ SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT, ++ SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT, ++ ++ SWCR_DBG_ALL_RX_FCSERR_CNT, ++ SWCR_DBG_ALL_RX_FIFOFULL_CNT, ++ SWCR_DBG_ALL_RX_PFDROP_CNT, ++ ++ SWCR_DBG_ALL_PWR_PS_POLL_CNT, ++ SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT, ++ SWCR_DBG_ALL_PWR_BCN_IND_CNT, ++ SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT, ++ SWCR_DBG_ALL_PWR_PM_STATE0, ++ SWCR_DBG_ALL_PWR_PM_STATE1, ++ SWCR_DBG_ALL_PWR_CUR_PS_PROF0, ++ SWCR_DBG_ALL_PWR_CUR_PS_PROF1, ++ ++ SWCR_DBG_ALL_AR_STA0_RATE, ++ SWCR_DBG_ALL_AR_STA0_BWGI, ++ SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI, ++ ++ SWCR_DBG_ALL_ROAMING_ENABLE, ++ SWCR_DBG_ALL_ROAMING_ROAM_CNT, ++ SWCR_DBG_ALL_ROAMING_INT_CNT, ++ ++ SWCR_DBG_ALL_BB_RX_MDRDY_CNT, ++ SWCR_DBG_ALL_BB_RX_FCSERR_CNT, ++ SWCR_DBG_ALL_BB_CCK_PD_CNT, ++ SWCR_DBG_ALL_BB_OFDM_PD_CNT, ++ SWCR_DBG_ALL_BB_CCK_SFDERR_CNT, ++ SWCR_DBG_ALL_BB_CCK_SIGERR_CNT, ++ SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT, ++ SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT, ++ ++ SWCR_DBG_ALL_NUM ++} ENUM_SWCR_DBG_ALL_T; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++void testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); ++VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++ ++/* Support Debug */ ++VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl); ++VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); ++ ++/* Debug Support */ ++VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType); ++VOID swCrDebugInit(P_ADAPTER_T prAdapter); ++VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout); ++VOID swCrDebugUninit(P_ADAPTER_T prAdapter); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h +new file mode 100644 +index 000000000000..3b6991131d05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h +@@ -0,0 +1,262 @@ ++/* ++** Id: include/tdls.h#1 ++*/ ++ ++/*! \file "tdls.h" ++ \brief This file contains the internal used in TDLS modules ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: tdls.h ++ * ++ * 11 18 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ * ++ ** ++ */ ++ ++#ifndef _TDLS_H ++#define _TDLS_H ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define TDLS_CFG_CMD_TEST 1 ++#define TDLS_CFG_HT_SUP 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); ++extern BOOLEAN flgTdlsTestExtCapElm; ++extern UINT8 aucTdlsTestExtCapElm[]; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++typedef struct _TDLS_LINK_HIS_OTHERS_T { ++ BOOLEAN fgIsHt; /* TRUE: HT device */ ++ ++} TDLS_LINK_HIS_OTHERS_T; ++ ++/* command */ ++typedef enum _TDLS_CMD_ID { ++ TDLS_CMD_TEST_TX_FRAME = 0x00, ++ TDLS_CMD_TEST_RCV_FRAME = 0x01, ++ TDLS_CMD_TEST_PEER_ADD = 0x02, ++ TDLS_CMD_TEST_PEER_UPDATE = 0x03, ++ TDLS_CMD_TEST_DATA_FRAME = 0x04, ++ TDLS_CMD_TEST_RCV_NULL = 0x05, ++ TDLS_CMD_MIB_UPDATE = 0x06, ++ TDLS_CMD_TEST_SKIP_TX_FAIL = 0x07, ++ TDLS_CMD_UAPSD_CONF = 0x08, ++ TDLS_CMD_CH_SW_CONF = 0x09, ++ TDLS_CMD_TEST_SKIP_KEEP_ALIVE = 0x0a, ++ TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT = 0x0b, ++ TDLS_CMD_TEST_TX_TDLS_FRAME = 0x0c, ++ TDLS_CMD_TEST_PROHIBIT_SET_IN_AP = 0x0d, ++ TDLS_CMD_TEST_SCAN_DISABLE = 0x0e, ++ TDLS_CMD_TEST_DATA_FRAME_CONT = 0x0f, ++ TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP = 0x10, ++ TDLS_CMD_SETUP_CONF = 0x11, ++ TDLS_CMD_INFO = 0x12, ++ TDLS_CMD_TEST_DELAY = 0x13, ++ TDLS_CMD_KEY_INFO = 0x14, ++ TDLS_CMD_TEST_PTI_TX_FAIL = 0x15 ++} TDLS_CMD_ID; ++ ++typedef enum _TDLS_EVENT_HOST_ID { ++ TDLS_HOST_EVENT_TEAR_DOWN = 0x00, /* TDLS_EVENT_HOST_SUBID_TEAR_DOWN */ ++ TDLS_HOST_EVENT_TX_DONE, ++ TDLS_HOST_EVENT_FME_STATUS, /* TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME */ ++ TDLS_HOST_EVENT_STATISTICS ++} TDLS_EVENT_HOST_ID; ++ ++typedef enum _TDLS_EVENT_HOST_SUBID_TEAR_DOWN { ++ TDLS_HOST_EVENT_TD_PTI_TIMEOUT = 0x00, ++ TDLS_HOST_EVENT_TD_AGE_TIMEOUT, ++ TDLS_HOST_EVENT_TD_PTI_SEND_FAIL, ++ TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL, ++ TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX, ++ TDLS_HOST_EVENT_TD_NON_STATE3, ++ TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN ++} TDLS_EVENT_HOST_SUBID_TEAR_DOWN; ++ ++typedef enum _TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME { ++ TDLS_HOST_EVENT_SF_BA, ++ TDLS_HOST_EVENT_SF_BA_OK, ++ TDLS_HOST_EVENT_SF_BA_DECLINE, ++ TDLS_HOST_EVENT_SF_BA_PEER, ++ TDLS_HOST_EVENT_SF_BA_RSP_OK, ++ TDLS_HOST_EVENT_SF_BA_RSP_DECLINE ++} TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME; ++ ++/* payload specific type in the LLC/SNAP header */ ++#define TDLS_FRM_PAYLOAD_TYPE 2 ++ ++#define TDLS_FRM_CATEGORY 12 ++ ++typedef enum _TDLS_FRM_ACTION_ID { ++ TDLS_FRM_ACTION_SETUP_REQ = 0x00, ++ TDLS_FRM_ACTION_SETUP_RSP, ++ TDLS_FRM_ACTION_CONFIRM, ++ TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_FRM_ACTION_PTI, ++ TDLS_FRM_ACTION_CHAN_SWITCH_REQ, ++ TDLS_FRM_ACTION_CHAN_SWITCH_RSP, ++ TDLS_FRM_ACTION_PEER_PSM_REQ, ++ TDLS_FRM_ACTION_PEER_PSM_RSP, ++ TDLS_FRM_ACTION_PTI_RSP, /* 0x09 */ ++ TDLS_FRM_ACTION_DISCOVERY_REQ, ++ ++ TDLS_FRM_ACTION_EVENT_TEAR_DOWN_TO_SUPPLICANT = 0x30, ++ ++ TDLS_FRM_DATA_TEST_DATA = 0x80 ++} TDLS_FRM_ACTION_ID; ++ ++#define TDLS_FRM_ACTION_DISCOVERY_RESPONSE 14 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* 7.3.2.62 Link Identifier element */ ++#define ELEM_ID_LINK_IDENTIFIER 101 ++#define ELEM_LEN_LINK_IDENTIFIER 18 ++ ++typedef struct _IE_LINK_IDENTIFIER_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aBSSID[6]; ++ UINT_8 aInitiator[6]; ++ UINT_8 aResponder[6]; ++} __KAL_ATTRIB_PACKED__ IE_LINK_IDENTIFIER_T; ++ ++#define TDLS_LINK_IDENTIFIER_IE(__ie__) ((IE_LINK_IDENTIFIER_T *)(__ie__)) ++ ++/* test command use */ ++typedef struct _PARAM_CUSTOM_TDLS_CMD_STRUCT_T { ++ ++ UINT_8 ucFmeType; /* TDLS_FRM_ACTION_ID */ ++ ++ UINT_8 ucToken; ++ UINT_16 u2Cap; ++ ++ /* bit0: TDLS, bit1: Peer U-APSD Buffer, bit2: Channel Switching */ ++#define TDLS_EX_CAP_PEER_UAPSD BIT(0) ++#define TDLS_EX_CAP_CHAN_SWITCH BIT(1) ++#define TDLS_EX_CAP_TDLS BIT(2) ++ UINT_8 ucExCap; ++ ++ UINT_8 arSupRate[4]; ++ UINT_8 arSupChan[4]; ++ ++ UINT_32 u4Timeout; ++ ++#define TDLS_FME_MAC_ADDR_LEN 6 ++ UINT_8 arRspAddr[TDLS_FME_MAC_ADDR_LEN]; ++ UINT_8 arBssid[TDLS_FME_MAC_ADDR_LEN]; ++ ++/* ++ Linux Kernel-3.10 ++ struct station_parameters { ++ const u8 *supported_rates; ++ struct net_device *vlan; ++ u32 sta_flags_mask, sta_flags_set; ++ u32 sta_modify_mask; ++ int listen_interval; ++ u16 aid; ++ u8 supported_rates_len; ++ u8 plink_action; ++ u8 plink_state; ++ const struct ieee80211_ht_cap *ht_capa; ++ const struct ieee80211_vht_cap *vht_capa; ++ u8 uapsd_queues; ++ u8 max_sp; ++ enum nl80211_mesh_power_mode local_pm; ++ u16 capability; ++ const u8 *ext_capab; ++ u8 ext_capab_len; ++ }; ++*/ ++ struct ieee80211_ht_cap rHtCapa; ++ struct ieee80211_vht_cap rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ struct station_parameters rPeerInfo; ++ ++} PARAM_CUSTOM_TDLS_CMD_STRUCT_T; ++ ++typedef struct _TDLS_MGMT_TX_INFO { ++ UINT8 aucPeer[6]; ++ UINT8 ucActionCode; ++ UINT8 ucDialogToken; ++ UINT16 u2StatusCode; ++ UINT32 u4SecBufLen; ++ UINT8 aucSecBuf[1000]; ++} TDLS_MGMT_TX_INFO; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* check any TDLS link */ ++#define TDLS_IS_NO_LINK_GOING(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt == 0) ++ ++/* increase TDLS link count */ ++#define TDLS_LINK_INCREASE(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt++) ++ ++/* decrease TDLS link count */ ++#define TDLS_LINK_DECREASE(__GlueInfo__) \ ++do { \ ++ if ((__GlueInfo__)->rTdlsLink.cLinkCnt > 0) \ ++ (__GlueInfo__)->rTdlsLink.cLinkCnt--; \ ++} while (0) ++ ++/* get TDLS link count */ ++#define TDLS_LINK_COUNT(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt) ++ ++/* reset TDLS link count */ ++#define TDLS_LINK_COUNT_RESET(__GlueInfo__) \ ++ ((__GlueInfo__)->rTdlsLink.cLinkCnt = 0) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* Note: these functions are used only in tdls module, not other modules */ ++UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt); ++ ++TDLS_STATUS ++TdlsDataFrameSend(ADAPTER_T *prAdapter, ++ STA_RECORD_T *prStaRec, ++ UINT_8 *pPeerMac, ++ UINT_8 ucActionCode, ++ UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#endif /* _TDLS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h +new file mode 100644 +index 000000000000..12c9359f2e8f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h +@@ -0,0 +1,104 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wapi.h#1 ++*/ ++ ++/*! \file wapi.h ++ \brief The wapi related define, macro and structure are described here. ++*/ ++ ++/* ++** Log: wapi.h ++ * ++ * 07 20 2010 wh.su ++ * ++ * . ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the wapi function name and adding the generate wapi ie function ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some wapi structure define ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** \main\maintrunk.MT5921\1 2009-10-09 17:06:29 GMT mtk01088 ++** ++*/ ++ ++#ifndef _WAPI_H ++#define _WAPI_H ++ ++#if CFG_SUPPORT_WAPI ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define WAPI_CIPHER_SUITE_WPI 0x01721400 /* WPI_SMS4 */ ++#define WAPI_AKM_SUITE_802_1X 0x01721400 /* WAI */ ++#define WAPI_AKM_SUITE_PSK 0x02721400 /* WAI_PSK */ ++ ++#define ELEM_ID_WAPI 68 /* WAPI IE */ ++ ++#define WAPI_IE(fp) ((P_WAPI_INFO_ELEM_T) fp) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo); ++ ++BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); ++ ++/* BOOLEAN */ ++/* wapiUpdateTxKeyIdx ( */ ++/* IN P_STA_RECORD_T prStaRec, */ ++/* IN UINT_8 ucWlanIdx */ ++/* ); */ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif ++#endif /* _WAPI_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h +new file mode 100644 +index 000000000000..5dc969f1cc05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h +@@ -0,0 +1,87 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wlan_typedef.h#1 ++*/ ++ ++/*! \file wlan_typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to all MGMT Protocol Stack. ++*/ ++ ++/* ++** Log: wlan_typedef.h ++*/ ++ ++#ifndef _WLAN_TYPEDEF_H ++#define _WLAN_TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for BSS_INFO_T structure, to describe the attributes used in a ++ * common BSS. ++ */ ++typedef struct _BSS_INFO_T BSS_INFO_T, *P_BSS_INFO_T; ++ ++typedef BSS_INFO_T AIS_BSS_INFO_T, *P_AIS_BSS_INFO_T; ++typedef BSS_INFO_T P2P_BSS_INFO_T, *P_P2P_BSS_INFO_T; ++typedef BSS_INFO_T BOW_BSS_INFO_T, *P_BOW_BSS_INFO_T; ++ ++typedef struct _AIS_SPECIFIC_BSS_INFO_T AIS_SPECIFIC_BSS_INFO_T, *P_AIS_SPECIFIC_BSS_INFO_T; ++typedef struct _P2P_SPECIFIC_BSS_INFO_T P2P_SPECIFIC_BSS_INFO_T, *P_P2P_SPECIFIC_BSS_INFO_T; ++typedef struct _BOW_SPECIFIC_BSS_INFO_T BOW_SPECIFIC_BSS_INFO_T, *P_BOW_SPECIFIC_BSS_INFO_T; ++/* CFG_SUPPORT_WFD */ ++typedef struct _WFD_CFG_SETTINGS_T WFD_CFG_SETTINGS_T, *P_WFD_CFG_SETTINGS_T; ++ ++typedef struct _WFD_DBG_CFG_SETTINGS_T WFD_DBG_CFG_SETTINGS_T, *P_WFD_DBG_CFG_SETTINGS_T; ++ ++/* BSS related structures */ ++/* Type definition for BSS_DESC_T structure, to describe parameter sets of a particular BSS */ ++typedef struct _BSS_DESC_T BSS_DESC_T, *P_BSS_DESC_T, **PP_BSS_DESC_T; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++typedef struct _HS20_INFO_T HS20_INFO_T, *P_HS20_INFO_T; ++#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _WLAN_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h +new file mode 100644 +index 000000000000..09bc0b5d5151 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h +@@ -0,0 +1,95 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/mgmt/wnm.h#1 ++*/ ++ ++/*! \file wnm.h ++ \brief This file contains the IEEE 802.11 family related 802.11v network management ++ for MediaTek 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wnm.h ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * ++*/ ++ ++#ifndef _WNM_H ++#define _WNM_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _TIMINGMSMT_PARAM_T { ++ BOOLEAN fgInitiator; ++ UINT_8 ucTrigger; ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ ++ UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ ++ UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ ++} TIMINGMSMT_PARAM_T, *P_TIMINGMSMT_PARAM_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++WLAN_STATUS ++wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++VOID ++wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); ++ ++VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA); ++ ++#define WNM_UNIT_TEST 1 ++ ++#if WNM_UNIT_TEST ++VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WNM_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h +new file mode 100644 +index 000000000000..d34f2c9c36a8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h +@@ -0,0 +1,1506 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/adapter.h#3 ++*/ ++ ++/*! \file adapter.h ++ \brief Definition of internal data structure for driver manipulation. ++ ++ In this file we define the internal data structure - ADAPTER_T which stands ++ for MiniPort ADAPTER(From Windows point of view) or stands for Network ADAPTER. ++*/ ++ ++/* ++** Log: adapter.h ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have ++** connected to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration ++ * corresponding to network type. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve inorder issue under AP mode. ++ * ++ * data frame may TX before assoc response frame. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Remove ERP member in adapter structure ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * Action frame callback for GO Device Discoverability Req. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically ++ * continuous memory shortage after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce ++ * physically continuous memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 yuche.tsai ++ * [WCXRP00000533] [Volunteer Patch][MT6620][Driver] Provide a P2P function API for Legacy WiFi to query AP mode. ++ * Provide an API for Legacy WiFi to query the operation mode.. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as ++ * initial RSSI right after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid ++ * using a uninitialized MAC-RX RCPI. ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module ++ * with structure miss-align pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to ++ * target station for AAA module. ++ * Provide disconnect function for AAA module. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting ++ * Support CTIA power mode setting. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add CWMin CWMax for AP to generate IE. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a common IE buffer in P2P INFO structure. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * restore configuration as before. ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add an intend mode for BSS info. ++ * It is used to let P2P BSS Info to know which OP Mode it is going to become. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Remove BSS info which is redonedent in Wifi Var.. ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P FSM Info in adapter. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P related field, additional include p2p_fsm.h if p2p is enabled. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * reserve field of privacy filter and RTS threshold setting. ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move ucCmdSeqNum as instance variable ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * 4. correct some HAL implementation ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * and result is retrieved by get ATInfo instead ++ * * * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 28 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate redundant variables for connection_state ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-16 18:02:03 GMT mtk02752 ++** add external reference to avoid compilation error ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:40:26 GMT mtk02752 ++** eliminate unused member ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-08 17:36:08 GMT mtk02752 ++** add RF test data members into P_ADAPTER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:45 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-28 10:29:57 GMT mtk01461 ++** Add read WTSR for SDIO_STATUS_ENHANCE mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:37:35 GMT mtk01461 ++** Add prPendingCmdInfoOfOID for temporarily saving the CMD_INFO_T before en-queue to rCmdQueue ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:57:51 GMT mtk01461 ++** Add MGMT Buffer Info ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:34:12 GMT mtk01461 ++** Add SW pre test CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:41:48 GMT mtk01461 ++** Add fgIsWmmAssoc flag for TC assignment ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:51 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:51:52 GMT mtk01426 ++** Add #if CFG_SDIO_RX_ENHANCE related data structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:17 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _ADAPTER_H ++#define _ADAPTER_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#include "hs20.h" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _ENHANCE_MODE_DATA_STRUCT_T SDIO_CTRL_T, *P_SDIO_CTRL_T; ++ ++typedef struct _WLAN_INFO_T { ++ PARAM_BSSID_EX_T rCurrBssId; ++ ++ /* Scan Result */ ++ PARAM_BSSID_EX_T arScanResult[CFG_MAX_NUM_BSS_LIST]; ++ PUINT_8 apucScanResultIEs[CFG_MAX_NUM_BSS_LIST]; ++ UINT_32 u4ScanResultNum; ++ ++ /* IE pool for Scanning Result */ ++ UINT_8 aucScanIEBuf[CFG_MAX_COMMON_IE_BUF_LEN]; ++ UINT_32 u4ScanIEBufferUsage; ++ ++ OS_SYSTIME u4SysTime; ++ ++ /* connection parameter (for Ad-Hoc) */ ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2AtimWindow; ++ ++ PARAM_RATES eDesiredRates; ++ CMD_LINK_ATTRIB eLinkAttr; ++/* CMD_PS_PROFILE_T ePowerSaveMode; */ ++ CMD_PS_PROFILE_T arPowerSaveMode[NETWORK_TYPE_INDEX_NUM]; ++ ++ /* trigger parameter */ ++ ENUM_RSSI_TRIGGER_TYPE eRssiTriggerType; ++ PARAM_RSSI rRssiTriggerValue; ++ ++ /* Privacy Filter */ ++ ENUM_PARAM_PRIVACY_FILTER_T ePrivacyFilter; ++ ++ /* RTS Threshold */ ++ PARAM_RTS_THRESHOLD eRtsThreshold; ++ ++ /* Network Type */ ++ UINT_8 ucNetworkType; ++ ++ /* Network Type In Use */ ++ UINT_8 ucNetworkTypeInUse; ++ ++} WLAN_INFO_T, *P_WLAN_INFO_T; ++ ++/* Session for CONNECTION SETTINGS */ ++typedef struct _CONNECTION_SETTINGS_T { ++ ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ ++ UINT_8 ucDelayTimeOfDisconnectEvent; ++ ++ BOOLEAN fgIsConnByBssidIssued; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ ++ BOOLEAN fgIsConnReqIssued; ++ BOOLEAN fgIsDisconnectedByNonRequest; ++ ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ ++ ENUM_PARAM_OP_MODE_T eOPMode; ++ ++ ENUM_PARAM_CONNECTION_POLICY_T eConnectionPolicy; ++ ++ ENUM_PARAM_AD_HOC_MODE_T eAdHocMode; ++ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ++ BOOLEAN fgIsScanReqIssued; ++ ++ /* MIB attributes */ ++ UINT_16 u2BeaconPeriod; ++ ++ UINT_16 u2RTSThreshold; /* User desired setting */ ++ ++ UINT_16 u2DesiredNonHTRateSet; /* User desired setting */ ++ ++ UINT_8 ucAdHocChannelNum; /* For AdHoc */ ++ ++ ENUM_BAND_T eAdHocBand; /* For AdHoc */ ++ ++ UINT_32 u4FreqInKHz; /* Center frequency */ ++ ++ /* ATIM windows using for IBSS power saving function */ ++ UINT_16 u2AtimWindow; ++ ++ /* Features */ ++ BOOLEAN fgIsEnableRoaming; ++ ++ BOOLEAN fgIsAdHocQoSEnable; ++ ++ ENUM_PARAM_PHY_CONFIG_T eDesiredPhyConfig; ++ ++ /* Used for AP mode for desired channel and bandwidth */ ++ UINT_16 u2CountryCode; ++ UINT_16 u2CountryCodeBakup; ++ UINT_8 uc2G4BandwidthMode; /* 20/40M or 20M only */ ++ UINT_8 uc5GBandwidthMode; /* 20/40M or 20M only */ ++ ++ BOOLEAN fgTxShortGIDisabled; ++ BOOLEAN fgRxShortGIDisabled; ++ ++#if CFG_SUPPORT_802_11D ++ BOOLEAN fgMultiDomainCapabilityEnabled; ++#endif /* CFG_SUPPORT_802_11D */ ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ BOOLEAN fgWapiMode; ++ UINT_32 u4WapiSelectedGroupCipher; ++ UINT_32 u4WapiSelectedPairwiseCipher; ++ UINT_32 u4WapiSelectedAKMSuite; ++#endif ++ ++ /* CR1486, CR1640 */ ++ /* for WPS, disable the privacy check for AP selection policy */ ++ BOOLEAN fgPrivacyCheckDisable; ++ ++ /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 bmfgApsdEnAc; ++ ++ /* for RSN info store, when upper layer set rsn info */ ++ RSN_INFO_T rRsnInfo; ++ ++} CONNECTION_SETTINGS_T, *P_CONNECTION_SETTINGS_T; ++ ++struct _BSS_INFO_T { ++ ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ ++ ENUM_PARAM_MEDIA_STATE_T eConnectionStateIndicated; /* The Media State that report to HOST */ ++ ++ ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ ++#if CFG_ENABLE_WIFI_DIRECT ++ ENUM_OP_MODE_T eIntendOPMode; ++#endif ++ ++ BOOLEAN fgIsNetActive; /* TRUE if this network has been activated */ ++ ++ UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ ++ ++ UINT_8 ucReasonOfDisconnect; /* Used by media state indication */ ++ ++ UINT_8 ucSSIDLen; /* Length of SSID */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ENUM_HIDDEN_SSID_TYPE_T eHiddenSsidType; /* For Hidden SSID usage. */ ++#endif ++ ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID used in this BSS */ ++ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* The BSSID of the associated BSS */ ++ ++ UINT_8 aucOwnMacAddr[MAC_ADDR_LEN]; /* Owned MAC Address used in this BSS */ ++ ++ P_STA_RECORD_T prStaRecOfAP; /* For Infra Mode, and valid only if ++ * eConnectionState == MEDIA_STATE_CONNECTED ++ */ ++ LINK_T rStaRecOfClientList; /* For IBSS/AP Mode, all known STAs in current BSS */ ++ ++ UINT_16 u2CapInfo; /* Change Detection */ ++ ++ UINT_16 u2BeaconInterval; /* The Beacon Interval of this BSS */ ++ ++ UINT_16 u2ATIMWindow; /* For IBSS Mode */ ++ ++ UINT_16 u2AssocId; /* For Infra Mode, it is the Assoc ID assigned by AP. ++ */ ++ ++ UINT_8 ucDTIMPeriod; /* For Infra/AP Mode */ ++ ++ UINT_8 ucDTIMCount; /* For AP Mode, it is the DTIM value we should carried in ++ * the Beacon of next TBTT. ++ */ ++ ++ UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer ++ * (This is deduced from received BSS_DESC_T) ++ */ ++ ++ UINT_8 ucNonHTBasicPhyType; /* The Basic PHY Type Index, used to setup Phy Capability */ ++ ++ UINT_8 ucConfigAdHocAPMode; /* The configuration of AdHoc/AP Mode. e.g. 11g or 11b */ ++ ++ UINT_8 ucBeaconTimeoutCount; /* For Infra/AP Mode, it is a threshold of Beacon Lost Count to ++ confirm connection was lost */ ++ ++ BOOLEAN fgHoldSameBssidForIBSS; /* For IBSS Mode, to keep use same BSSID to extend the life cycle of an IBSS */ ++ ++ BOOLEAN fgIsBeaconActivated; /* For AP/IBSS Mode, it is used to indicate that Beacon is sending */ ++ ++ P_MSDU_INFO_T prBeacon; /* For AP/IBSS Mode - Beacon Frame */ ++ ++ BOOLEAN fgIsIBSSMaster; /* For IBSS Mode - To indicate that we can reply ProbeResp Frame. ++ In current TBTT interval */ ++ ++ BOOLEAN fgIsShortPreambleAllowed; /* From Capability Info. of AssocResp Frame ++ AND of Beacon/ProbeResp Frame */ ++ BOOLEAN fgUseShortPreamble; /* Short Preamble is enabled in current BSS. */ ++ BOOLEAN fgUseShortSlotTime; /* Short Slot Time is enabled in current BSS. */ ++ ++ UINT_16 u2OperationalRateSet; /* Operational Rate Set of current BSS */ ++ UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of current BSS */ ++ ++ UINT_8 ucAllSupportedRatesLen; /* Used for composing Beacon Frame in AdHoc or AP Mode */ ++ UINT_8 aucAllSupportedRates[RATE_NUM]; ++ ++ UINT_8 ucAssocClientCnt; /* TODO(Kevin): Number of associated clients */ ++ ++ BOOLEAN fgIsProtection; ++ BOOLEAN fgIsQBSS; /* fgIsWmmBSS; *//* For Infra/AP/IBSS Mode, it is used to indicate if we support WMM in ++ * current BSS. */ ++ BOOLEAN fgIsNetAbsent; /* TRUE: BSS is absent, FALSE: BSS is present */ ++ ++ UINT_32 u4RsnSelectedGroupCipher; ++ UINT_32 u4RsnSelectedPairwiseCipher; ++ UINT_32 u4RsnSelectedAKMSuite; ++ UINT_16 u2RsnSelectedCapInfo; ++ ++ /*------------------------------------------------------------------------*/ ++ /* Power Management related information */ ++ /*------------------------------------------------------------------------*/ ++ PM_PROFILE_SETUP_INFO_T rPmProfSetupInfo; ++ ++ /*------------------------------------------------------------------------*/ ++ /* WMM/QoS related information */ ++ /*------------------------------------------------------------------------*/ ++ UINT_8 ucWmmParamSetCount; /* Used to detect the change of EDCA parameters. For AP mode, ++ the value is used in WMM IE */ ++ ++ AC_QUE_PARMS_T arACQueParms[WMM_AC_INDEX_NUM]; ++ ++ UINT_8 aucCWminLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWminLog2 */ ++ UINT_8 aucCWmaxLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWmaxLog2 */ ++ AC_QUE_PARMS_T arACQueParmsForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the value */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* 802.11n HT operation IE when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) */ ++ /* is true. They have the same definition with fields of */ ++ /* information element (CM) */ ++ /*------------------------------------------------------------------------*/ ++ ENUM_BAND_T eBand; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucHtOpInfo1; ++ UINT_16 u2HtOpInfo2; ++ UINT_16 u2HtOpInfo3; ++ ++ /*------------------------------------------------------------------------*/ ++ /* Required protection modes (CM) */ ++ /*------------------------------------------------------------------------*/ ++ BOOLEAN fgErpProtectMode; ++ ENUM_HT_PROTECT_MODE_T eHtProtectMode; ++ ENUM_GF_MODE_T eGfOperationMode; ++ ENUM_RIFS_MODE_T eRifsOperationMode; ++ ++ BOOLEAN fgObssErpProtectMode; /* GO only */ ++ ENUM_HT_PROTECT_MODE_T eObssHtProtectMode; /* GO only */ ++ ENUM_GF_MODE_T eObssGfOperationMode; /* GO only */ ++ BOOLEAN fgObssRifsOperationMode; /* GO only */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* OBSS to decide if 20/40M bandwidth is permitted. */ ++ /* The first member indicates the following channel list length. */ ++ /*------------------------------------------------------------------------*/ ++ BOOLEAN fgAssoc40mBwAllowed; ++ BOOLEAN fg40mBwAllowed; ++ ENUM_CHNL_EXT_T eBssSCO; /* Real setting for HW ++ * 20/40M AP mode will always set 40M, ++ * but its OP IE can be changed. ++ */ ++ UINT_8 auc2G_20mReqChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_NonHtChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_PriChnlList[CHNL_LIST_SZ_2G + 1]; ++ UINT_8 auc2G_SecChnlList[CHNL_LIST_SZ_2G + 1]; ++ ++ UINT_8 auc5G_20mReqChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_NonHtChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_PriChnlList[CHNL_LIST_SZ_5G + 1]; ++ UINT_8 auc5G_SecChnlList[CHNL_LIST_SZ_5G + 1]; ++ ++ TIMER_T rObssScanTimer; ++ UINT_16 u2ObssScanInterval; /* in unit of sec */ ++ ++ BOOLEAN fgObssActionForcedTo20M; /* GO only */ ++ BOOLEAN fgObssBeaconForcedTo20M; /* GO only */ ++ ++ /*------------------------------------------------------------------------*/ ++ /* HW Related Fields (Kevin) */ ++ /*------------------------------------------------------------------------*/ ++ UINT_8 ucHwDefaultFixedRateCode; /* The default rate code copied to MAC TX Desc */ ++ UINT_16 u2HwLPWakeupGuardTimeUsec; ++ ++ UINT_8 ucBssFreeQuota; /* The value is updated from FW */ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ P_IPV4_NETWORK_ADDRESS_LIST prIpV4NetAddrList; ++#endif ++ UINT_16 u2DeauthReason; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ ++ BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ ++#endif /* CFG_SUPPORT_TDLS */ ++}; ++ ++struct _AIS_SPECIFIC_BSS_INFO_T { ++ UINT_8 ucRoamingAuthTypes; /* This value indicate the roaming type used in AIS_JOIN */ ++ ++ BOOLEAN fgIsIBSSActive; ++ ++ /*! \brief Global flag to let arbiter stay at standby and not connect to any network */ ++ BOOLEAN fgCounterMeasure; ++ UINT_8 ucWEPDefaultKeyID; ++ BOOLEAN fgTransmitKeyExist; /* Legacy wep Transmit key exist or not */ ++ ++ /* While Do CounterMeasure procedure, check the EAPoL Error report have send out */ ++ BOOLEAN fgCheckEAPoLTxDone; ++ ++ UINT_32 u4RsnaLastMICFailTime; ++ ++ /* Stored the current bss wpa rsn cap filed, used for roaming policy */ ++ /* UINT_16 u2RsnCap; */ ++ TIMER_T rPreauthenticationTimer; ++ ++ /* By the flow chart of 802.11i, ++ wait 60 sec before associating to same AP ++ or roaming to a new AP ++ or sending data in IBSS, ++ keep a timer for handle the 60 sec counterMeasure */ ++ TIMER_T rRsnaBlockTrafficTimer; ++ TIMER_T rRsnaEAPoLReportTimeoutTimer; ++ ++ /* For Keep the Tx/Rx Mic key for TKIP SW Calculate Mic */ ++ /* This is only one for AIS/AP */ ++ UINT_8 aucTxMicKey[8]; ++ UINT_8 aucRxMicKey[8]; ++ ++ /* Buffer for WPA2 PMKID */ ++ /* The PMKID cache lifetime is expire by media_disconnect_indication */ ++ UINT_32 u4PmkidCandicateCount; ++ PMKID_CANDICATE_T arPmkidCandicate[CFG_MAX_PMKID_CACHE]; ++ UINT_32 u4PmkidCacheCount; ++ PMKID_ENTRY_T arPmkidCache[CFG_MAX_PMKID_CACHE]; ++ BOOLEAN fgIndicatePMKID; ++#if CFG_SUPPORT_802_11W ++ BOOLEAN fgMgmtProtection; ++ UINT_32 u4SaQueryStart; ++ UINT_32 u4SaQueryCount; ++ UINT_8 ucSaQueryTimedOut; ++ PUINT_8 pucSaQueryTransId; ++ TIMER_T rSaQueryTimer; ++ BOOLEAN fgBipKeyInstalled; ++#endif ++}; ++ ++struct _BOW_SPECIFIC_BSS_INFO_T { ++ UINT_16 u2Reserved; /* Reserved for Data Type Check */ ++}; ++ ++#if CFG_SLT_SUPPORT ++typedef struct _SLT_INFO_T { ++ ++ P_BSS_DESC_T prPseudoBssDesc; ++ UINT_16 u2SiteID; ++ UINT_8 ucChannel2G4; ++ UINT_8 ucChannel5G; ++ BOOLEAN fgIsDUT; ++ UINT_32 u4BeaconReceiveCnt; ++ /* ///////Deprecated///////// */ ++ P_STA_RECORD_T prPseudoStaRec; ++} SLT_INFO_T, *P_SLT_INFO_T; ++#endif ++ ++/* Major member variables for WiFi FW operation. ++ Variables within this region will be ready for access after WIFI function is enabled. ++*/ ++typedef struct _WIFI_VAR_T { ++ BOOLEAN fgIsRadioOff; ++ ++ BOOLEAN fgIsEnterD3ReqIssued; ++ ++ BOOLEAN fgDebugCmdResp; ++ ++ CONNECTION_SETTINGS_T rConnSettings; ++ ++ SCAN_INFO_T rScanInfo; ++ ++#if CFG_SUPPORT_ROAMING ++ ROAMING_INFO_T rRoamingInfo; ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ AIS_FSM_INFO_T rAisFsmInfo; ++ ++ ENUM_PWR_STATE_T aePwrState[NETWORK_TYPE_INDEX_NUM]; ++ ++ BSS_INFO_T arBssInfo[NETWORK_TYPE_INDEX_NUM]; ++ ++ AIS_SPECIFIC_BSS_INFO_T rAisSpecificBssInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings; ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo; ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ BOW_SPECIFIC_BSS_INFO_T rBowSpecificBssInfo; ++ BOW_FSM_INFO_T rBowFsmInfo; ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ DEAUTH_INFO_T arDeauthInfo[MAX_DEAUTH_INFO_COUNT]; ++ ++ /* Current Wi-Fi Settings and Flags */ ++ UINT_8 aucPermanentAddress[MAC_ADDR_LEN]; ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ UINT_8 aucDeviceAddress[MAC_ADDR_LEN]; ++ UINT_8 aucInterfaceAddress[MAC_ADDR_LEN]; ++ ++ UINT_8 ucAvailablePhyTypeSet; ++ ++ ENUM_PHY_TYPE_INDEX_T eNonHTBasicPhyType2G4; /* Basic Phy Type used by SCN according ++ * to the set of Available PHY Types ++ */ ++ ++ ENUM_PARAM_PREAMBLE_TYPE_T ePreambleType; ++ ENUM_REGISTRY_FIXED_RATE_T eRateSetting; ++ ++ BOOLEAN fgIsShortSlotTimeOptionEnable; ++ /* User desired setting, but will honor the capability of AP */ ++ ++ BOOLEAN fgEnableJoinToHiddenSSID; ++ BOOLEAN fgSupportWZCDisassociation; ++ ++ BOOLEAN fgSupportQoS; ++ BOOLEAN fgSupportAmpduTx; ++ BOOLEAN fgSupportAmpduRx; ++ BOOLEAN fgSupportTspec; ++ BOOLEAN fgSupportUAPSD; ++ BOOLEAN fgSupportULPSMP; ++ UINT_8 u8SupportRxSgi20; /* 0: default 1: enable 2:disble */ ++ UINT_8 u8SupportRxSgi40; ++ UINT_8 u8SupportRxGf; ++ UINT_8 u8SupportRxSTBC; ++#if CFG_SUPPORT_CFG_FILE ++ UINT_8 ucApWpsMode; ++ UINT_8 ucCert11nMode; ++#endif ++#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT ++ UINT_8 ucCeFccTxPwrLimit; ++ UINT_8 ucCeFccTxPwrLimitCck; ++ UINT_8 ucCeFccTxPwrLimitOfdmHt20; ++ UINT_8 ucCeFccTxPwrLimitHt40; ++#endif ++ ++#if CFG_SLT_SUPPORT ++ SLT_INFO_T rSltInfo; ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ HS20_INFO_T rHS20Info; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ PARAM_GET_CHN_LOAD rChnLoadInfo; ++#endif ++ ++} WIFI_VAR_T, *P_WIFI_VAR_T; /* end of _WIFI_VAR_T */ ++ ++/* cnm_timer module */ ++typedef struct { ++ LINK_T rLinkHead; ++ OS_SYSTIME rNextExpiredSysTime; ++ KAL_WAKE_LOCK_T rWakeLock; ++ BOOLEAN fgWakeLocked; ++} ROOT_TIMER, *P_ROOT_TIMER; ++ ++/* FW/DRV/NVRAM version information */ ++typedef struct { ++ ++ /* NVRAM or Registry */ ++ UINT_16 u2Part1CfgOwnVersion; ++ UINT_16 u2Part1CfgPeerVersion; ++ UINT_16 u2Part2CfgOwnVersion; ++ UINT_16 u2Part2CfgPeerVersion; ++ ++ /* Firmware */ ++ UINT_16 u2FwProductID; ++ UINT_16 u2FwOwnVersion; ++ UINT_16 u2FwPeerVersion; ++ ++} WIFI_VER_INFO_T, *P_WIFI_VER_INFO_T; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/* ++* p2p function pointer structure ++*/ ++ ++typedef struct _P2P_FUNCTION_LINKER { ++ P2P_REMOVE prP2pRemove; ++/* NIC_P2P_MEDIA_STATE_CHANGE prNicP2pMediaStateChange; */ ++/* SCAN_UPDATE_P2P_DEVICE_DESC prScanUpdateP2pDeviceDesc; */ ++/* P2P_FSM_RUN_EVENT_RX_PROBE_RESPONSE_FRAME prP2pFsmRunEventRxProbeResponseFrame; */ ++ P2P_GENERATE_P2P_IE prP2pGenerateWSC_IEForBeacon; ++/* P2P_CALCULATE_WSC_IE_LEN_FOR_PROBE_RSP prP2pCalculateWSC_IELenForProbeRsp; */ ++/* P2P_GENERATE_WSC_IE_FOR_PROBE_RSP prP2pGenerateWSC_IEForProbeRsp; */ ++/* SCAN_REMOVE_P2P_BSS_DESC prScanRemoveP2pBssDesc; */ ++/* P2P_HANDLE_SEC_CHECK_RSP prP2pHandleSecCheckRsp; */ ++ P2P_NET_REGISTER prP2pNetRegister; ++ P2P_NET_UNREGISTER prP2pNetUnregister; ++ P2P_CALCULATE_P2P_IE_LEN prP2pCalculateP2p_IELenForAssocReq; /* All IEs generated from supplicant. */ ++ P2P_GENERATE_P2P_IE prP2pGenerateP2p_IEForAssocReq; /* All IEs generated from supplicant. */ ++} P2P_FUNCTION_LINKER, *P_P2P_FUNCTION_LINKER; ++ ++#endif ++ ++/* ++ *State Machine: ++ *-->STOP: Turn on/off WiFi ++ *-->DISABLE: Screen was off (wlanHandleSystemSuspend) ++ *-->ENABLE: Screen was on (wlanHandleSystemResume) ++ *----->clear DISABLE ++ *-->RUNNING: Screen was on && Tx/Rx was ongoing (wlanHardStartXmit/kalRxIndicatePkts) ++*/ ++struct GL_PER_MON_T { ++ TIMER_T rPerfMonTimer; ++ ULONG ulPerfMonFlag; ++ ULONG ulLastTxBytes; ++ ULONG ulLastRxBytes; ++ ULONG ulP2PLastTxBytes; ++ ULONG ulP2PLastRxBytes; ++ /*in bps*/ ++ ULONG ulThroughput; ++ /*in ms*/ ++ UINT32 u4UpdatePeriod; ++ UINT32 u4TarPerfLevel; ++ UINT32 u4CurrPerfLevel; ++}; ++ ++/* ++ * Major ADAPTER structure ++ * Major data structure for driver operation ++ */ ++struct _ADAPTER_T { ++ UINT_8 ucRevID; ++ ++ UINT_16 u2NicOpChnlNum; ++ ++ BOOLEAN fgIsEnableWMM; ++ BOOLEAN fgIsWmmAssoc; /* This flag is used to indicate that WMM is enable in current BSS */ ++ ++ UINT_32 u4OsPacketFilter; /* packet filter used by OS */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ UINT_32 u4CSUMFlags; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ ENUM_BAND_T aePreferBand[NETWORK_TYPE_INDEX_NUM]; ++ ++ /* ADAPTER flags */ ++ UINT_32 u4Flags; ++ UINT_32 u4HwFlags; ++ ++ BOOLEAN fgIsRadioOff; ++ ++ BOOLEAN fgIsEnterD3ReqIssued; ++ ++ UINT_8 aucMacAddress[MAC_ADDR_LEN]; ++ ++ ENUM_PHY_TYPE_INDEX_T eCurrentPhyType; /* Current selection basing on the set of Available PHY Types */ ++ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ UINT_32 u4CoalescingBufCachedSize; ++ PUINT_8 pucCoalescingBufCached; ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* Buffer for CMD_INFO_T, Mgt packet and mailbox message */ ++ BUF_INFO_T rMgtBufInfo; ++ BUF_INFO_T rMsgBufInfo; ++ PUINT_8 pucMgtBufCached; ++ UINT_32 u4MgtBufCachedSize; ++ UINT_8 aucMsgBuf[MSG_BUFFER_SIZE]; ++#if CFG_DBG_MGT_BUF ++ UINT_32 u4MemAllocDynamicCount; /* Debug only */ ++ UINT_32 u4MemFreeDynamicCount; /* Debug only */ ++#endif ++ ++ STA_RECORD_T arStaRec[CFG_STA_REC_NUM]; ++ ++ /* Element for TX PATH */ ++ TX_CTRL_T rTxCtrl; ++ QUE_T rFreeCmdList; ++ CMD_INFO_T arHifCmdDesc[CFG_TX_MAX_CMD_PKT_NUM]; ++ ++ /* Element for RX PATH */ ++ RX_CTRL_T rRxCtrl; ++ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ /* Element for MT6620 E1 HIFSYS workaround */ ++ BOOLEAN fgIsClockGatingEnabled; ++#endif ++ ++ /* Buffer for Authentication Event */ ++ /* Move to glue layer and refine the kal function */ ++ /* Reference to rsnGeneratePmkidIndication function at rsn.c */ ++ UINT_8 aucIndicationEventBuffer[(CFG_MAX_PMKID_CACHE * 20) + 8]; ++ ++ UINT_32 u4IntStatus; ++ ++ ENUM_ACPI_STATE_T rAcpiState; ++ ++ BOOLEAN fgIsIntEnable; ++ BOOLEAN fgIsIntEnableWithLPOwnSet; ++ ++ BOOLEAN fgIsFwOwn; ++ BOOLEAN fgWiFiInSleepyState; ++ ++ UINT_32 u4PwrCtrlBlockCnt; ++ ++ QUE_T rPendingCmdQueue; ++ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ UINT_8 ucCmdSeqNum; ++ UINT_8 ucTxSeqNum; ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ BOOLEAN fgUseWapi; ++#endif ++ ++ /* RF Test flags */ ++ BOOLEAN fgTestMode; ++ ++ /* WLAN Info for DRIVER_CORE OID query */ ++ WLAN_INFO_T rWlanInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2PRegistered; ++ ENUM_NET_REG_STATE_T rP2PNetRegState; ++ BOOLEAN fgIsWlanLaunched; ++ P_P2P_INFO_T prP2pInfo; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ OS_SYSTIME rP2pLinkQualityUpdateTime; ++ BOOLEAN fgIsP2pLinkQualityValid; ++ EVENT_LINK_QUALITY rP2pLinkQuality; ++#endif ++ ++ /* FSM Timer */ ++ TIMER_T rP2pFsmTimeoutTimer; ++#endif ++ ++ /* Online Scan Option */ ++ BOOLEAN fgEnOnlineScan; ++ ++ /* Online Scan Option */ ++ BOOLEAN fgDisBcnLostDetection; ++ ++ /* MAC address */ ++ PARAM_MAC_ADDRESS rMyMacAddr; ++ ++ /* Wake-up Event for WOL */ ++ UINT_32 u4WakeupEventEnable; ++ ++ /* Event Buffering */ ++ EVENT_STATISTICS rStatStruct; ++ OS_SYSTIME rStatUpdateTime; ++ BOOLEAN fgIsStatValid; ++ ++ EVENT_LINK_QUALITY rLinkQuality; ++ OS_SYSTIME rLinkQualityUpdateTime; ++ BOOLEAN fgIsLinkQualityValid; ++ OS_SYSTIME rLinkRateUpdateTime; ++ BOOLEAN fgIsLinkRateValid; ++ ++ /* WIFI_VAR_T */ ++ WIFI_VAR_T rWifiVar; ++ ++ /* MTK WLAN NIC driver IEEE 802.11 MIB */ ++ IEEE_802_11_MIB_T rMib; ++ ++ /* Mailboxs for inter-module communication */ ++ MBOX_T arMbox[MBOX_ID_TOTAL_NUM]; ++ ++ /* Timers for OID Pending Handling */ ++ TIMER_T rOidTimeoutTimer; ++ ++ TIMER_T rReturnIndicatedRfbListTimer; ++ ++ /* Root Timer for cnm_timer module */ ++ ROOT_TIMER rRootTimer; ++ ++ /* RLM maintenance */ ++ ENUM_CHNL_EXT_T eRfSco; ++ ENUM_SYS_PROTECT_MODE_T eSysProtectMode; ++ ENUM_GF_MODE_T eSysHtGfMode; ++ ENUM_RIFS_MODE_T eSysTxRifsMode; ++ ENUM_SYS_PCO_PHASE_T eSysPcoPhase; ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ /* QM */ ++ QUE_MGT_T rQM; ++ ++ CNM_INFO_T rCnmInfo; ++ ++ UINT_32 u4PowerMode; ++ ++ UINT_32 u4CtiaPowerMode; ++ BOOLEAN fgEnCtiaPowerMode; ++ ++ UINT_32 fgEnArpFilter; ++ ++ UINT_32 u4UapsdAcBmp; ++ ++ UINT_32 u4MaxSpLen; ++ ++ UINT_32 u4PsCurrentMeasureEn; ++ ++ /* Version Information */ ++ WIFI_VER_INFO_T rVerInfo; ++ ++ /* 5GHz support (from F/W) */ ++ BOOLEAN fgIsHw5GBandDisabled; ++ BOOLEAN fgEnable5GBand; ++ BOOLEAN fgIsEepromUsed; ++ BOOLEAN fgIsEfuseValid; ++ BOOLEAN fgIsEmbbededMacAddrValid; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ BOOLEAN fgIsPowerLimitTableValid; ++#endif ++ ++ /* Packet Forwarding Tracking */ ++ INT_32 i4PendingFwdFrameCount; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ UINT_8 ucRddStatus; ++#endif ++ ++ BOOLEAN fgDisStaAgingTimeoutDetection; ++#if CFG_SUPPORT_CFG_FILE ++ P_WLAN_CFG_T prWlanCfg; ++ WLAN_CFG_T rWlanCfg; ++#endif ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ KAL_WAKE_LOCK_T rApWakeLock; ++#endif ++ UINT_32 u4FwCompileFlag0; ++ UINT_32 u4FwCompileFlag1; ++ KAL_WAKE_LOCK_T rTxThreadWakeLock; ++ KAL_WAKE_LOCK_T rAhbIsrWakeLock; ++ ++#if CFG_SUPPORT_ROAMING_ENC ++ BOOLEAN fgIsRoamingEncEnabled; ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ BOOLEAN fgTdlsIsSup; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ UINT_8 ucScanTime; ++ ++#if CFG_SUPPORT_DBG_POWERMODE ++ BOOLEAN fgEnDbgPowerMode; /* dbg privilege power mode, always keep in active */ ++#endif ++ ++ UINT_32 u4AirDelayTotal; /* dbg privilege power mode, always keep in active */ ++ ULONG ulSuspendFlag; ++ struct GL_PER_MON_T rPerMonitor; ++}; /* end of _ADAPTER_T */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define SUSPEND_FLAG_FOR_WAKEUP_REASON (0) ++#define SUSPEND_FLAG_CLEAR_WHEN_RESUME (1) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for BSS_INFO_T - Flag of Net Active */ ++/*----------------------------------------------------------------------------*/ ++#define IS_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive) ++#define IS_BSS_ACTIVE(_prBssInfo) ((_prBssInfo)->fgIsNetActive) ++ ++#define IS_AIS_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_AIS_INDEX) ++#define IS_P2P_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_P2P_INDEX) ++#define IS_BOW_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_BOW_INDEX) ++ ++#define SET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = TRUE; } ++ ++#define UNSET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = FALSE; } ++ ++#define BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ ++ { UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; \ ++ P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ ++ \ ++ _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; \ ++ _prBssInfo->fgIsNetActive = FALSE; \ ++ _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ ++ _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ ++ COPY_MAC_ADDR(_prBssInfo->aucBSSID, _aucZeroMacAddr); \ ++ LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ ++ _prBssInfo->fgIsBeaconActivated = FALSE; \ ++ _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ ++ _prBssInfo->fgIsNetAbsent = FALSE; \ ++ } ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#define BOW_BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ ++ { \ ++ P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ ++ \ ++ _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ ++ _prBssInfo->eCurrentOPMode = OP_MODE_BOW; \ ++ _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ ++ _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ ++ LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ ++ _prBssInfo->fgIsBeaconActivated = TRUE; \ ++ _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ ++ _prBssInfo->fgIsNetAbsent = FALSE; \ ++ } ++#endif ++ ++#define PERF_MON_DISABLE_BIT_OFF (0) ++#define PERF_MON_STOP_BIT_OFF (1) ++#define PERF_MON_RUNNING_BIT_OFF (2) ++ ++#define THROUGHPUT_L1_THRESHOLD (20*1024*1024) ++#define THROUGHPUT_L2_THRESHOLD (60*1024*1024) ++#define THROUGHPUT_L3_THRESHOLD (135*1024*1024) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for Power State */ ++/*----------------------------------------------------------------------------*/ ++#define SET_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_IDLE; } ++ ++#define SET_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_ACTIVE; } ++ ++#define SET_NET_PWR_STATE_PS(_prAdapter, _NetTypeIndex) \ ++ {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_PS; } ++ ++#define IS_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_ACTIVE) ++ ++#define IS_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ ++ (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_IDLE) ++ ++#define IS_SCN_PWR_STATE_ACTIVE(_prAdapter) \ ++ (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_ACTIVE) ++ ++#define IS_SCN_PWR_STATE_IDLE(_prAdapter) \ ++ (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_IDLE) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _ADAPTER_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h +new file mode 100644 +index 000000000000..6c4c1b76622b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h +@@ -0,0 +1,322 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/bow.h#1 ++*/ ++ ++/* ++** Log: bow.h ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 22 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Submit missing BoW header files. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW structure. ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add Activity Report definition. ++ * ++ * 10 18 2010 chinghwa.yu ++ * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size ++ * Fix wrong BoW event size. ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * basic implementation for EVENT_BT_OVER_WIFI ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * sync. with design document for interface change. ++ * ++ * 04 02 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * Wi-Fi driver no longer needs to implement 802.11 PAL, thus replaced by wrapping command/event definitions ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * correct typo. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * update for all command/event needed to be supported by 802.11 PAL. ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++*/ ++ ++#ifndef _BOW_H_ ++#define _BOW_H_ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define BOWDEVNAME "bow0" ++ ++#define MAX_BOW_NUMBER_OF_CHANNEL_2G4 14 ++#define MAX_BOW_NUMBER_OF_CHANNEL_5G 4 ++/* (MAX_BOW_NUMBER_OF_CHANNEL_2G4 + MAX_BOW_NUMBER_OF_CHANNEL_5G) */ ++#define MAX_BOW_NUMBER_OF_CHANNEL 18 ++ ++#define MAX_ACTIVITY_REPORT 2 ++#define MAX_ACTIVITY_REPROT_TIME 660 ++ ++#define ACTIVITY_REPORT_STATUS_SUCCESS 0 ++#define ACTIVITY_REPORT_STATUS_FAILURE 1 ++#define ACTIVITY_REPORT_STATUS_TIME_INVALID 2 ++#define ACTIVITY_REPORT_STATUS_OTHERS 3 ++ ++#define ACTIVITY_REPORT_SCHEDULE_UNKNOWN 0 /* Does not know the schedule of the interference */ ++#define ACTIVITY_REPORT_SCHEDULE_KNOWN 1 ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _BT_OVER_WIFI_COMMAND_HEADER_T { ++ UINT_8 ucCommandId; ++ UINT_8 ucSeqNumber; ++ UINT_16 u2PayloadLength; ++} AMPC_COMMAND_HEADER_T, *P_AMPC_COMMAND_HEADER_T; ++ ++typedef struct _BT_OVER_WIFI_COMMAND { ++ AMPC_COMMAND_HEADER_T rHeader; ++ UINT_8 aucPayload[0]; ++} AMPC_COMMAND, *P_AMPC_COMMAND; ++ ++typedef struct _BT_OVER_WIFI_EVENT_HEADER_T { ++ UINT_8 ucEventId; ++ UINT_8 ucSeqNumber; ++ UINT_16 u2PayloadLength; ++} AMPC_EVENT_HEADER_T, *P_AMPC_EVENT_HEADER_T; ++ ++typedef struct _BT_OVER_WIFI_EVENT { ++ AMPC_EVENT_HEADER_T rHeader; ++ UINT_8 aucPayload[0]; ++} AMPC_EVENT, *P_AMPC_EVENT; ++ ++typedef struct _CHANNEL_DESC_T { ++ UINT_8 ucChannelBand; ++ UINT_8 ucChannelNum; ++} CHANNEL_DESC, P_CHANNEL_DESC; ++ ++/* Command Structures */ ++typedef struct _BOW_SETUP_CONNECTION { ++/* Fixed to 2.4G */ ++ UINT_8 ucChannelNum; ++ UINT_8 ucReserved1; ++ UINT_8 aucPeerAddress[6]; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 ucPAL_Capabilities; ++ INT_8 cMaxTxPower; ++ UINT_8 ucReserved2; ++ ++/* Pending, for future BOW 5G supporting. */ ++/* UINT_8 aucPeerAddress[6]; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 ucPAL_Capabilities; ++ INT_8 cMaxTxPower; ++ UINT_8 ucChannelListNum; ++ CHANNEL_DESC arChannelList[1]; ++*/ ++} BOW_SETUP_CONNECTION, *P_BOW_SETUP_CONNECTION; ++ ++typedef struct _BOW_DESTROY_CONNECTION { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_DESTROY_CONNECTION, *P_BOW_DESTROY_CONNECTION; ++ ++typedef struct _BOW_SET_PTK { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++ UINT_8 aucTemporalKey[16]; ++} BOW_SET_PTK, *P_BOW_SET_PTK; ++ ++typedef struct _BOW_READ_RSSI { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_READ_RSSI, *P_BOW_READ_RSSI; ++ ++typedef struct _BOW_READ_LINK_QUALITY { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 aucReserved[2]; ++} BOW_READ_LINK_QUALITY, *P_BOW_READ_LINK_QUALITY; ++ ++typedef struct _BOW_SHORT_RANGE_MODE { ++ UINT_8 aucPeerAddress[6]; ++ INT_8 cTxPower; ++ UINT_8 ucReserved; ++} BOW_SHORT_RANGE_MODE, *P_BOW_SHORT_RANGE_MODE; ++ ++/* Event Structures */ ++typedef struct _BOW_COMMAND_STATUS { ++ UINT_8 ucStatus; ++ UINT_8 ucReserved[3]; ++} BOW_COMMAND_STATUS, *P_BOW_COMMAND_STATUS; ++ ++typedef struct _BOW_MAC_STATUS { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucAvailability; ++ UINT_8 ucNumOfChannel; ++ CHANNEL_DESC arChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; ++} BOW_MAC_STATUS, *P_BOW_MAC_STATUS; ++ ++typedef struct _BOW_LINK_CONNECTED { ++ CHANNEL_DESC rChannel; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_LINK_CONNECTED, *P_BOW_LINK_CONNECTED; ++ ++typedef struct _BOW_LINK_DISCONNECTED { ++ UINT_8 ucReason; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_LINK_DISCONNECTED, *P_BOW_LINK_DISCONNECTED; ++ ++typedef struct _BOW_RSSI { ++ INT_8 cRssi; ++ UINT_8 aucReserved[3]; ++} BOW_RSSI, *P_BOW_RSSI; ++ ++typedef struct _BOW_LINK_QUALITY { ++ UINT_8 ucLinkQuality; ++ UINT_8 aucReserved[3]; ++} BOW_LINK_QUALITY, *P_BOW_LINK_QUALITY; ++ ++typedef enum _ENUM_BOW_CMD_ID_T { ++ BOW_CMD_ID_GET_MAC_STATUS = 1, ++ BOW_CMD_ID_SETUP_CONNECTION, ++ BOW_CMD_ID_DESTROY_CONNECTION, ++ BOW_CMD_ID_SET_PTK, ++ BOW_CMD_ID_READ_RSSI, ++ BOW_CMD_ID_READ_LINK_QUALITY, ++ BOW_CMD_ID_SHORT_RANGE_MODE, ++ BOW_CMD_ID_GET_CHANNEL_LIST, ++} ENUM_BOW_CMD_ID_T, *P_ENUM_BOW_CMD_ID_T; ++ ++typedef enum _ENUM_BOW_EVENT_ID_T { ++ BOW_EVENT_ID_COMMAND_STATUS = 1, ++ BOW_EVENT_ID_MAC_STATUS, ++ BOW_EVENT_ID_LINK_CONNECTED, ++ BOW_EVENT_ID_LINK_DISCONNECTED, ++ BOW_EVENT_ID_RSSI, ++ BOW_EVENT_ID_LINK_QUALITY, ++ BOW_EVENT_ID_CHANNEL_LIST, ++ BOW_EVENT_ID_CHANNEL_SELECTED, ++} ENUM_BOW_EVENT_ID_T, *P_ENUM_BOW_EVENT_ID_T; ++ ++typedef enum _ENUM_BOW_DEVICE_STATE { ++ BOW_DEVICE_STATE_DISCONNECTED = 0, ++ BOW_DEVICE_STATE_DISCONNECTING, ++ BOW_DEVICE_STATE_ACQUIRING_CHANNEL, ++ BOW_DEVICE_STATE_STARTING, ++ BOW_DEVICE_STATE_SCANNING, ++ BOW_DEVICE_STATE_CONNECTING, ++ BOW_DEVICE_STATE_CONNECTED, ++ BOW_DEVICE_STATE_NUM ++} ENUM_BOW_DEVICE_STATE, *P_ENUM_BOW_DEVICE_STATE; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_BOW_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h +new file mode 100644 +index 000000000000..c1ecb303b877 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h +@@ -0,0 +1,150 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "cmd_buf.h" ++ \brief In this file we define the structure for Command Packet. ++ ++ In this file we define the structure for Command Packet and the control unit ++ of MGMT Memory Pool. ++*/ ++ ++/* ++** Log: cmd_buf.h ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow ++ * under concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Enable change log ++*/ ++ ++#ifndef _CMD_BUF_H ++#define _CMD_BUF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _COMMAND_TYPE { ++ COMMAND_TYPE_GENERAL_IOCTL, ++ COMMAND_TYPE_NETWORK_IOCTL, ++ COMMAND_TYPE_SECURITY_FRAME, ++ COMMAND_TYPE_MANAGEMENT_FRAME, ++ COMMAND_TYPE_NUM ++} COMMAND_TYPE, *P_COMMAND_TYPE; ++ ++typedef VOID(*PFN_CMD_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++typedef VOID(*PFN_CMD_TIMEOUT_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++struct _CMD_INFO_T { ++ QUE_ENTRY_T rQueEntry; ++ ++ COMMAND_TYPE eCmdType; ++ ++ UINT_16 u2InfoBufLen; /* This is actual CMD buffer length */ ++ PUINT_8 pucInfoBuffer; /* May pointer to structure in prAdapter */ ++ P_NATIVE_PACKET prPacket; /* only valid when it's a security frame */ ++ ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkType; ++ UINT_8 ucStaRecIndex; /* only valid when it's a security frame */ ++ ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler; ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler; ++ ++ BOOLEAN fgIsOid; /* Used to check if we need indicate */ ++ ++ UINT_8 ucCID; ++ BOOLEAN fgSetQuery; ++ BOOLEAN fgNeedResp; ++ BOOLEAN fgDriverDomainMCR; /* Access Driver Domain MCR, for CMD_ID_ACCESS_REG only */ ++ UINT_8 ucCmdSeqNum; ++ UINT_32 u4SetInfoLen; /* Indicate how many byte we read for Set OID */ ++ ++ /* information indicating by OID/ioctl */ ++ PVOID pvInformationBuffer; ++ UINT_32 u4InformationBufferLength; ++ ++ /* private data */ ++ UINT_32 u4PrivateData; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter); ++ ++P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); ++ ++VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for CMDs */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); ++VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _CMD_BUF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h +new file mode 100644 +index 000000000000..0fdb9dcadeef +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h +@@ -0,0 +1,618 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hal.h#1 ++*/ ++ ++/*! \file "hal.h" ++ \brief The declaration of hal functions ++ ++ N/A ++*/ ++ ++/* ++** Log: hal.h ++ * ++ * 04 01 2011 tsaiyuan.hsu ++ * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues ++ * fix the klocwork issues, 57500, 57501, 57502 and 57503. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change zero-padding for TX port access to HAL. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * 4. correct some HAL implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-16 18:02:26 GMT mtk02752 ++** include precomp.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:16 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 13:54:15 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-11 10:36:01 GMT mtk01084 ++** modify HAL functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-09 22:56:28 GMT mtk01084 ++** modify HW access routines ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:50:09 GMT mtk01084 ++** add new macro HAL_TX_PORT_WR ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:08:10 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:50 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-05-18 14:28:10 GMT mtk01084 ++** fix issue in HAL_DRIVER_OWN_BY_SDIO_CMD52() ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-11 17:26:33 GMT mtk01084 ++** modify the bit definition to check driver own status ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:30:22 GMT mtk01461 ++** Fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:50:34 GMT mtk01461 ++** Redefine HAL_PORT_RD/WR macro for SW pre test ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-24 09:46:49 GMT mtk01084 ++** fix LINT error ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 16:53:38 GMT mtk01084 ++** add HAL_DRIVER_OWN_BY_SDIO_CMD52() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:53:13 GMT mtk01426 ++** Fixed lint warn ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:20 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _HAL_H ++#define _HAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* Macros for flag operations for the Adapter structure */ ++#define HAL_SET_FLAG(_M, _F) ((_M)->u4HwFlags |= (_F)) ++#define HAL_CLEAR_FLAG(_M, _F) ((_M)->u4HwFlags &= ~(_F)) ++#define HAL_TEST_FLAG(_M, _F) ((_M)->u4HwFlags & (_F)) ++#define HAL_TEST_FLAGS(_M, _F) (((_M)->u4HwFlags & (_F)) == (_F)) ++ ++#if defined(_HIF_SDIO) ++#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ ++do { \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ /* DBGLOG(HAL, ERROR, ("HAL_MCR_RD access fail! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)*_pu4Value)); */ \ ++ } \ ++ } else { \ ++ /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_RD access! 0x%x\n", (UINT32)_u4Offset)); */ \ ++ } \ ++} while (0) ++ ++#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ ++do { \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ /* DBGLOG(HAL, ERROR, ("HAL_MCR_WR access fail! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ ++ } \ ++ } else { \ ++ /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_WR access! 0x%x: 0x%x\n", */ \ ++ /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ ++ } \ ++} while (0) ++ ++#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ /*fgResult = FALSE; */\ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_PORT_RD access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /*fgResult = TRUE;*/ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_PORT_RD access! 0x%x\n", _u4Port); \ ++ } \ ++} ++ ++#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ /*fgResult = FALSE; */\ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_PORT_WR access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /*fgResult = TRUE;*/ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_PORT_WR access! 0x%x\n", _u4Port); \ ++ } \ ++} ++ ++#if 0 /* only for SDIO */ ++#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf) == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "HAL_BYTE_WR access fail! 0x%x\n", _u4Port); \ ++ } \ ++ else { \ ++ /* Todo:: Nothing*/ \ ++ } \ ++ } \ ++ else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_BYTE_WR access! 0x%x\n", _u4Port); \ ++ } \ ++} ++#endif ++ ++#define HAL_DRIVER_OWN_BY_SDIO_CMD52(_prAdapter, _pfgDriverIsOwnReady) \ ++{ \ ++ UINT_8 ucBuf = BIT(1); \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ ++ if (kalDevReadAfterWriteWithSdioCmd52(_prAdapter->prGlueInfo, MCR_WHLPCR_BYTE1, &ucBuf, 1) \ ++ == FALSE) {\ ++ HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ ++ fgIsBusAccessFailed = TRUE; \ ++ DBGLOG(HAL, ERROR, "kalDevReadAfterWriteWithSdioCmd52 access fail!\n"); \ ++ } \ ++ else { \ ++ *_pfgDriverIsOwnReady = (ucBuf & BIT(0)) ? TRUE : FALSE; \ ++ } \ ++ } else { \ ++ DBGLOG(HAL, WARN, "ignore HAL_DRIVER_OWN_BY_SDIO_CMD52 access!\n"); \ ++ } \ ++} ++ ++#else /* #if defined(_HIF_SDIO) */ ++#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++ if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ ++ == FALSE) \ ++ fgIsBusAccessFailed = TRUE; \ ++} ++ ++#if 0 /* only for SDIO */ ++#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ ++{ \ ++ if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ ++ ASSERT(0); \ ++ } \ ++kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf); \ ++} ++#endif ++ ++#endif /* #if defined(_HIF_SDIO) */ ++ ++#define HAL_READ_RX_PORT(prAdapter, u4PortId, u4Len, pvBuf, _u4ValidBufSize) \ ++{ \ ++ ASSERT(u4PortId < 2); \ ++ HAL_PORT_RD(prAdapter, \ ++ ((u4PortId == 0) ? MCR_WRDR0 : MCR_WRDR1), \ ++ u4Len, \ ++ pvBuf, \ ++ _u4ValidBufSize/*temp!!*//*4Kbyte*/); \ ++} ++ ++#define HAL_WRITE_TX_PORT(_prAdapter, _ucTxPortIdx, _u4Len, _pucBuf, _u4ValidBufSize) \ ++{ \ ++ ASSERT(_ucTxPortIdx < 2); \ ++ if ((_u4ValidBufSize - _u4Len) >= sizeof(UINT_32)) { \ ++ /* fill with single dword of zero as TX-aggregation termination */ \ ++ *(PUINT_32) (&((_pucBuf)[ALIGN_4(_u4Len)])) = 0; \ ++ } \ ++ HAL_PORT_WR(_prAdapter, \ ++ (_ucTxPortIdx == 0) ? MCR_WTDR0 : MCR_WTDR1, \ ++ _u4Len, \ ++ _pucBuf, \ ++ _u4ValidBufSize/*temp!!*//*4KByte*/); \ ++} ++ ++/* The macro to read the given MCR several times to check if the wait ++ condition come true. */ ++#define HAL_MCR_RD_AND_WAIT(_pAdapter, _offset, _pReadValue, _waitCondition, _waitDelay, _waitCount, _status) \ ++{ \ ++ UINT_32 count; \ ++ (_status) = FALSE; \ ++ for (count = 0; count < (_waitCount); count++) { \ ++ HAL_MCR_RD((_pAdapter), (_offset), (_pReadValue)); \ ++ if ((_waitCondition)) { \ ++ (_status) = TRUE; \ ++ break; \ ++ } \ ++ kalUdelay((_waitDelay)); \ ++ } \ ++} ++ ++/* The macro to write 1 to a R/S bit and read it several times to check if the ++ command is done */ ++#define HAL_MCR_WR_AND_WAIT(_pAdapter, _offset, _writeValue, _busyMask, _waitDelay, _waitCount, _status) \ ++{ \ ++ UINT_32 u4Temp; \ ++ UINT_32 u4Count = _waitCount; \ ++ (_status) = FALSE; \ ++ HAL_MCR_WR((_pAdapter), (_offset), (_writeValue)); \ ++ do { \ ++ kalUdelay((_waitDelay)); \ ++ HAL_MCR_RD((_pAdapter), (_offset), &u4Temp); \ ++ if (!(u4Temp & (_busyMask))) { \ ++ (_status) = TRUE; \ ++ break; \ ++ } \ ++ u4Count--; \ ++ } while (u4Count); \ ++} ++ ++#define HAL_GET_CHIP_ID_VER(_prAdapter, pu2ChipId, pu2Version) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WCIR, \ ++ &u4Value); \ ++ *pu2ChipId = (UINT_16)(u4Value & WCIR_CHIP_ID); \ ++ *pu2Version = (UINT_16)(u4Value & WCIR_REVISION_ID) >> 16; \ ++} ++ ++#define HAL_WAIT_WIFI_FUNC_READY(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ UINT_32 i; \ ++ for (i = 0; i < 100; i++) { \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WCIR, \ ++ &u4Value); \ ++ if (u4Value & WCIR_WLAN_READY) { \ ++ break; \ ++ } \ ++ NdisMSleep(10); \ ++ } \ ++} ++ ++#define HAL_INTR_DISABLE(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_INT_EN_CLR) ++ ++#define HAL_INTR_ENABLE(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_INT_EN_SET) ++ ++#define HAL_INTR_ENABLE_AND_LP_OWN_SET(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ (WHLPCR_INT_EN_SET | WHLPCR_FW_OWN_REQ_SET)) ++ ++#define HAL_LP_OWN_SET(_prAdapter) \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_FW_OWN_REQ_SET) ++ ++#define HAL_LP_OWN_CLR_OK(_prAdapter, _pfgResult) \ ++{ \ ++ UINT_32 i; \ ++ UINT_32 u4RegValue; \ ++ UINT_32 u4LoopCnt = 2048 / 8; \ ++ *_pfgResult = TRUE; \ ++ /* Software get LP ownership */ \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHLPCR, \ ++ WHLPCR_FW_OWN_REQ_CLR) \ ++ for (i = 0; i < u4LoopCnt; i++) { \ ++ HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ ++ if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ ++ break; \ ++ } \ ++ else { \ ++ kalUdelay(8); \ ++ } \ ++ } \ ++ if (i == u4LoopCnt) { \ ++ *_pfgResult = FALSE; \ ++ /*ERRORLOG(("LP cannot be own back (%ld)", u4LoopCnt));*/ \ ++ /* check the time of LP instructions need to perform from Sleep to On */ \ ++ /*ASSERT(0); */ \ ++ } \ ++} ++ ++#define HAL_GET_ABNORMAL_INTERRUPT_REASON_CODE(_prAdapter, pu4AbnormalReason) \ ++{ \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WASR, \ ++ pu4AbnormalReason); \ ++} ++ ++#define HAL_DISABLE_RX_ENHANCE_MODE(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value & ~WHCR_RX_ENHANCE_MODE_EN); \ ++} ++ ++#define HAL_ENABLE_RX_ENHANCE_MODE(_prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value | WHCR_RX_ENHANCE_MODE_EN); \ ++} ++ ++#define HAL_CFG_MAX_HIF_RX_LEN_NUM(_prAdapter, _ucNumOfRxLen) \ ++{ \ ++ UINT_32 u4Value, ucNum; \ ++ ucNum = ((_ucNumOfRxLen >= 16) ? 0 : _ucNumOfRxLen); \ ++ u4Value = 0; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ u4Value &= ~WHCR_MAX_HIF_RX_LEN_NUM; \ ++ u4Value |= ((((UINT_32)ucNum) << 4) & WHCR_MAX_HIF_RX_LEN_NUM); \ ++ HAL_MCR_WR(_prAdapter, \ ++ MCR_WHCR, \ ++ u4Value); \ ++} ++ ++#define HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(prAdapter, \ ++ MCR_WHCR, \ ++ u4Value & ~WHCR_W_INT_CLR_CTRL); \ ++ prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = TRUE;\ ++} ++ ++#define HAL_SET_INTR_STATUS_WRITE_1_CLEAR(prAdapter) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WHCR, \ ++ &u4Value); \ ++ HAL_MCR_WR(prAdapter, \ ++ MCR_WHCR, \ ++ u4Value | WHCR_W_INT_CLR_CTRL); \ ++ prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = FALSE;\ ++} ++ ++/* Note: enhance mode structure may also carried inside the buffer, ++ if the length of the buffer is long enough */ ++#define HAL_READ_INTR_STATUS(prAdapter, length, pvBuf) \ ++ HAL_PORT_RD(prAdapter, \ ++ MCR_WHISR, \ ++ length, \ ++ pvBuf, \ ++ length) ++ ++#define HAL_READ_TX_RELEASED_COUNT(_prAdapter, aucTxReleaseCount) \ ++{ \ ++ PUINT_32 pu4Value = (PUINT_32)aucTxReleaseCount; \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WTSR0, \ ++ &pu4Value[0]); \ ++ HAL_MCR_RD(_prAdapter, \ ++ MCR_WTSR1, \ ++ &pu4Value[1]); \ ++} ++ ++#define HAL_READ_RX_LENGTH(prAdapter, pu2Rx0Len, pu2Rx1Len) \ ++{ \ ++ UINT_32 u4Value; \ ++ u4Value = 0; \ ++ HAL_MCR_RD(prAdapter, \ ++ MCR_WRPLR, \ ++ &u4Value); \ ++ *pu2Rx0Len = (UINT_16)u4Value; \ ++ *pu2Rx1Len = (UINT_16)(u4Value >> 16); \ ++} ++ ++#define HAL_GET_INTR_STATUS_FROM_ENHANCE_MODE_STRUCT(pvBuf, u2Len, pu4Status) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvBuf; \ ++ *pu4Status = pu4Buf[0]; \ ++} ++ ++#define HAL_GET_TX_STATUS_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4BufOut, u4LenBufOut) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ ASSERT(u4LenBufOut >= 8); \ ++ pu4BufOut[0] = pu4Buf[1]; \ ++ pu4BufOut[1] = pu4Buf[2]; \ ++} ++ ++#define HAL_GET_RX_LENGTH_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu2Rx0Num, au2Rx0Len, pu2Rx1Num, au2Rx1Len) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ ASSERT((sizeof(au2Rx0Len) / sizeof(UINT_16)) >= 16); \ ++ ASSERT((sizeof(au2Rx1Len) / sizeof(UINT_16)) >= 16); \ ++ *pu2Rx0Num = (UINT_16)pu4Buf[3]; \ ++ *pu2Rx1Num = (UINT_16)(pu4Buf[3] >> 16); \ ++ kalMemCopy(au2Rx0Len, &pu4Buf[4], 8); \ ++ kalMemCopy(au2Rx1Len, &pu4Buf[12], 8); \ ++} ++ ++#define HAL_GET_MAILBOX_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4Mailbox0, pu4Mailbox1) \ ++{ \ ++ PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ ++ *pu4Mailbox0 = (UINT_16)pu4Buf[21]; \ ++ *pu4Mailbox1 = (UINT_16)pu4Buf[22]; \ ++} ++ ++#define HAL_IS_TX_DONE_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_TX_DONE_INT) ? TRUE : FALSE) ++ ++#define HAL_IS_RX_DONE_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)) ? TRUE : FALSE) ++ ++#define HAL_IS_ABNORMAL_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_ABNORMAL_INT) ? TRUE : FALSE) ++ ++#define HAL_IS_FW_OWNBACK_INTR(u4IntrStatus) \ ++ ((u4IntrStatus & WHISR_FW_OWN_BACK_INT) ? TRUE : FALSE) ++ ++#define HAL_PUT_MAILBOX(prAdapter, u4MboxId, u4Data) \ ++{ \ ++ ASSERT(u4MboxId < 2); \ ++ HAL_MCR_WR(prAdapter, \ ++ ((u4MboxId == 0) ? MCR_H2DSM0R : MCR_H2DSM1R), \ ++ u4Data); \ ++} ++ ++#define HAL_GET_MAILBOX(prAdapter, u4MboxId, pu4Data) \ ++{ \ ++ ASSERT(u4MboxId < 2); \ ++ HAL_MCR_RD(prAdapter, \ ++ ((u4MboxId == 0) ? MCR_D2HRM0R : MCR_D2HRM1R), \ ++ pu4Data); \ ++} ++ ++#define HAL_SET_MAILBOX_READ_CLEAR(prAdapter, fgEnableReadClear) \ ++{ \ ++ UINT_32 u4Value; \ ++ HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value);\ ++ HAL_MCR_WR(prAdapter, MCR_WHCR, \ ++ (fgEnableReadClear) ? \ ++ (u4Value | WHCR_W_MAILBOX_RD_CLR_EN) : \ ++ (u4Value & ~WHCR_W_MAILBOX_RD_CLR_EN)); \ ++ prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear = fgEnableReadClear;\ ++} ++ ++#define HAL_GET_MAILBOX_READ_CLEAR(prAdapter) (prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _HAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h +new file mode 100644 +index 000000000000..b9aa154b097e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h +@@ -0,0 +1,220 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_rx.h#1 ++*/ ++ ++/*! \file "hif_rx.h" ++ \brief Provide HIF RX Header Information between F/W and Driver ++ ++ N/A ++*/ ++ ++/* ++** Log: hif_rx.h ++ * ++ * 09 01 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * follow-ups for HIF_RX_HEADER_T update: ++ * 1) add TCL ++ * 2) add RCPI ++ * 3) add ChannelNumber ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:44:00 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-09 13:59:20 GMT MTK02468 ++** Added HIF_RX_HDR parsing macros ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 19:54:54 GMT mtk02752 ++** adopt HIF_RX_HEADER_T in new data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-29 19:51:19 GMT mtk01084 ++** modify FW/ driver interface ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:33:58 GMT mtk01461 ++** Add define of HW_APPENED_LEN ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:51:02 GMT mtk01461 ++** Rename ENUM_HIF_RX_PKT_TYPE_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 12:05:03 GMT mtk01426 ++** Remove __KAL_ATTRIB_PACKED__ and add hifDataTypeCheck() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:18:52 GMT mtk01426 ++** Add comment to HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:23 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _HIF_RX_H ++#define _HIF_RX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/*! HIF_RX_HEADER_T */ ++/* DW 0, Byte 1 */ ++#define HIF_RX_HDR_PACKET_TYPE_MASK BITS(0, 1) ++#define HIF_RX_HDR_SEC_MODE_MASK BITS(2, 5) ++#define HIF_RX_HDR_SEC_MODE_OFFSET 2 ++ ++/* DW 1, Byte 0 */ ++#define HIF_RX_HDR_HEADER_LEN BITS(2, 7) ++#define HIF_RX_HDR_HEADER_LEN_OFFSET 2 ++#define HIF_RX_HDR_HEADER_OFFSET_MASK BITS(0, 1) ++ ++/* DW 1, Byte 1 */ ++#define HIF_RX_HDR_80211_HEADER_FORMAT BIT(0) ++#define HIF_RX_HDR_DO_REORDER BIT(1) ++#define HIF_RX_HDR_PAL BIT(2) ++#define HIF_RX_HDR_TCL BIT(3) ++#define HIF_RX_HDR_NETWORK_IDX_MASK BITS(4, 7) ++#define HIF_RX_HDR_NETWORK_IDX_OFFSET 4 ++ ++/* DW 1, Byte 2, 3 */ ++#define HIF_RX_HDR_SEQ_NO_MASK BITS(0, 11) ++#define HIF_RX_HDR_TID_MASK BITS(12, 14) ++#define HIF_RX_HDR_TID_OFFSET 12 ++#define HIF_RX_HDR_BAR_FRAME BIT(15) ++ ++#define HIF_RX_HDR_FLAG_AMP_WDS BIT(0) ++#define HIF_RX_HDR_FLAG_802_11_FORMAT BIT(1) ++#define HIF_RX_HDR_FLAG_BAR_FRAME BIT(2) ++#define HIF_RX_HDR_FLAG_DO_REORDERING BIT(3) ++#define HIF_RX_HDR_FLAG_CTRL_WARPPER_FRAME BIT(4) ++ ++#define HIF_RX_HW_APPENDED_LEN 4 ++ ++/* For DW 2, Byte 3 - ucHwChannelNum */ ++#define HW_CHNL_NUM_MAX_2G4 14 ++#define HW_CHNL_NUM_MAX_4G_5G (255 - HW_CHNL_NUM_MAX_2G4) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef struct _HIF_RX_HEADER_T { ++ UINT_16 u2PacketLen; ++ UINT_16 u2PacketType; ++ UINT_8 ucHerderLenOffset; ++ UINT_8 uc80211_Reorder_PAL_TCL; ++ UINT_16 u2SeqNoTid; ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucRcpi; ++ UINT_8 ucHwChannelNum; ++ UINT_8 ucReserved; ++} HIF_RX_HEADER_T, *P_HIF_RX_HEADER_T; ++ ++typedef enum _ENUM_HIF_RX_PKT_TYPE_T { ++ HIF_RX_PKT_TYPE_DATA = 0, ++ HIF_RX_PKT_TYPE_EVENT, ++ HIF_RX_PKT_TYPE_TX_LOOPBACK, ++ HIF_RX_PKT_TYPE_MANAGEMENT, ++ HIF_RX_PKT_TYPE_NUM ++} ENUM_HIF_RX_PKT_TYPE_T, *P_ENUM_HIF_RX_PKT_TYPE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define HIF_RX_HDR_SIZE sizeof(HIF_RX_HEADER_T) ++ ++#define HIF_RX_HDR_GET_80211_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_80211_HEADER_FORMAT) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_REORDER_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_DO_REORDER) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_PAL_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_PAL) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_TCL_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_TCL) ? TRUE : FALSE)) ++#define HIF_RX_HDR_GET_NETWORK_IDX(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_NETWORK_IDX_MASK)\ ++ >> HIF_RX_HDR_NETWORK_IDX_OFFSET) ++ ++#define HIF_RX_HDR_GET_SEC_MODE(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->u2PacketType) & HIF_RX_HDR_SEC_MODE_MASK) >> HIF_RX_HDR_SEC_MODE_OFFSET) ++ ++#define HIF_RX_HDR_GET_TID(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_TID_MASK)\ ++ >> HIF_RX_HDR_TID_OFFSET) ++#define HIF_RX_HDR_GET_SN(_prHifRxHdr) \ ++ (((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_SEQ_NO_MASK) ++#define HIF_RX_HDR_GET_BAR_FLAG(_prHifRxHdr) \ ++ (((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_BAR_FRAME) ? TRUE : FALSE)) ++ ++#define HIF_RX_HDR_GET_CHNL_NUM(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->ucHwChannelNum) > HW_CHNL_NUM_MAX_4G_5G) ? \ ++ (((_prHifRxHdr)->ucHwChannelNum) - HW_CHNL_NUM_MAX_4G_5G) : \ ++ ((_prHifRxHdr)->ucHwChannelNum)) ++ ++/* To do: support more bands other than 2.4G and 5G */ ++#define HIF_RX_HDR_GET_RF_BAND(_prHifRxHdr) \ ++ ((((_prHifRxHdr)->ucHwChannelNum) <= HW_CHNL_NUM_MAX_2G4) ? \ ++ BAND_2G4 : BAND_5G) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static inline VOID hifDataTypeCheck(VOID); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ * We'll need this for porting driver to different RTOS. ++ */ ++static inline VOID hifDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_RX_HEADER_T) == 12); ++ ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h +new file mode 100644 +index 000000000000..17252f2c7760 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h +@@ -0,0 +1,214 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_tx.h#1 ++*/ ++ ++/* ++** Log: hif_tx.h ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill extra information for revised HIF_TX_HEADER. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate ++ * 2) add packet type for indicating management frames ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 01 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:40 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-24 19:55:11 GMT mtk02752 ++** adopt HIF_TX_HEADER_T in new data path ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-23 17:54:13 GMT mtk02752 ++** CMD_HDR_SIZE = (sizeof(WIFI_CMD_T)) to follow up CM's CMD/EVENT documentation ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-17 22:41:10 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-17 17:34:07 GMT mtk02752 ++** remove HIF_TX_BUFF_COUNT_TC0 (move to nic_tx.h) ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-17 12:14:12 GMT mtk02752 ++** add initial value for HIF_TX_BUFF_COUNT_TC5 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-13 13:54:18 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-04 14:11:14 GMT mtk01084 ++** modify SW TX data format ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-29 19:51:53 GMT mtk01084 ++** modify FW/ driver interface ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-20 12:22:46 GMT mtk01461 ++** Add SeqNum field to CMD Header ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:40:52 GMT mtk01461 ++** Update the Log Sign ++*/ ++ ++#ifndef _HIF_TX_H ++#define _HIF_TX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Maximum buffer size for individual HIF TCQ Buffer */ ++#define HIF_TX_BUFF_MAX_SIZE 1552 /* Reserved field was not included */ ++ ++/* Maximum buffer count for individual HIF TCQ */ ++#define HIF_TX_BUFF_COUNT_TC0 3 ++#define HIF_TX_BUFF_COUNT_TC1 3 ++#define HIF_TX_BUFF_COUNT_TC2 3 ++#define HIF_TX_BUFF_COUNT_TC3 3 ++#define HIF_TX_BUFF_COUNT_TC4 2 ++ ++#define TX_HDR_SIZE sizeof(HIF_TX_HEADER_T) ++ ++#define CMD_HDR_SIZE sizeof(WIFI_CMD_T) ++ ++#define CMD_PKT_SIZE_FOR_IMAGE 2048 /* !< 2048 Bytes CMD payload buffer */ ++ ++/*! NIC_HIF_TX_HEADER_T */ ++/* DW 0, Byte 0,1 */ ++#define HIF_TX_HDR_TX_BYTE_COUNT_MASK BITS(0, 11) ++#define HIF_TX_HDR_USER_PRIORITY_OFFSET 12 ++ ++/* DW 0, Byte 2 */ ++#define HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK BITS(0, 7) ++ ++/* DW 0, Byte 3 */ ++#define HIF_TX_HDR_IP_CSUM BIT(0) ++#define HIF_TX_HDR_TCP_CSUM BIT(1) ++#define HIF_TX_HDR_RESOURCE_MASK BITS(2, 5) ++#define HIF_TX_HDR_RESOURCE_OFFSET 2 ++#define HIF_TX_HDR_PACKET_TYPE_MASK BITS(6, 7) ++#define HIF_TX_HDR_PACKET_TYPE_OFFSET 6 ++ ++/* DW 1, Byte 0 */ ++#define HIF_TX_HDR_WLAN_HEADER_LEN_MASK BITS(0, 5) ++ ++/* DW 1, Byte 1 */ ++#define HIF_TX_HDR_FORMAT_ID_MASK BITS(0, 2) ++#define HIF_TX_HDR_NETWORK_TYPE_MASK BITS(4, 5) ++#define HIF_TX_HDR_NETWORK_TYPE_OFFSET 4 ++#define HIF_TX_HDR_FLAG_1X_FRAME_MASK BIT(6) ++#define HIF_TX_HDR_FLAG_1X_FRAME_OFFSET 6 ++#define HIF_TX_HDR_FLAG_802_11_FORMAT_MASK BIT(7) ++#define HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET 7 ++ ++/* DW2, Byte 3 */ ++#define HIF_TX_HDR_PS_FORWARDING_TYPE_MASK BITS(0, 1) ++#define HIF_TX_HDR_PS_SESSION_ID_MASK BITS(2, 4) ++#define HIF_TX_HDR_PS_SESSION_ID_OFFSET 2 ++#define HIF_TX_HDR_BURST_END_MASK BIT(5) ++#define HIF_TX_HDR_BURST_END_OFFSET 5 ++ ++/* DW3, Byte 1 */ ++#define HIF_TX_HDR_NEED_ACK BIT(0) ++#define HIF_TX_HDR_BIP BIT(1) ++#define HIF_TX_HDR_BASIC_RATE BIT(2) ++#define HIF_TX_HDR_NEED_TX_DONE_STATUS BIT(3) ++#define HIF_TX_HDR_RTS BIT(4) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _HIF_HW_TX_HEADER_T { ++ UINT_16 u2TxByteCount; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucCSflags; ++ UINT_8 aucBuffer[0]; ++} HIF_HW_TX_HEADER_T, *P_HIF_HW_TX_HEADER_T; ++ ++typedef struct _HIF_TX_HEADER_T { ++ UINT_16 u2TxByteCount_UserPriority; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucResource_PktType_CSflags; ++ UINT_8 ucWlanHeaderLength; ++ UINT_8 ucPktFormtId_Flags; ++ UINT_16 u2LLH; /* for BOW */ ++ UINT_16 u2SeqNo; /* for BOW */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucForwardingType_SessionID_Reserved; ++ UINT_8 ucPacketSeqNo; ++ UINT_8 ucAck_BIP_BasicRate; ++ UINT_8 aucReserved[2]; ++} HIF_TX_HEADER_T, *P_HIF_TX_HEADER_T; ++ ++typedef enum _ENUM_HIF_TX_PKT_TYPE_T { ++ HIF_TX_PKT_TYPE_DATA = 0, ++ HIF_TX_PKT_TYPE_CMD, ++ HIF_TX_PKT_TYPE_HIF_LOOPBACK, ++ HIF_TX_PKT_TYPE_MANAGEMENT, ++ HIF_TX_PKT_TYPE_NUM ++} ENUM_HIF_TX_PKT_TYPE_T, *P_ENUM_HIF_TX_PKT_TYPE_T; ++ ++typedef enum _ENUM_HIF_OOB_CTRL_PKT_TYPE_T { ++ HIF_OOB_CTRL_PKT_TYPE_LOOPBACK = 1, ++ HIF_OOB_CTRL_PKT_TYP_NUM ++} ENUM_HIF_OOB_CTRL_PKT_TYPE_T, *P_ENUM_HIF_OOB_CTRL_PKT_TYPE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define TFCB_FRAME_PAD_TO_DW(u2Length) ALIGN_4(u2Length) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* Kevin: we don't have to call following function to inspect the data structure. ++ * It will check automatically while at compile time. ++ */ ++static inline VOID hif_txDataTypeCheck(VOID); ++ ++static inline VOID hif_txDataTypeCheck(VOID) ++{ ++ DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_TX_HEADER_T) == 16); ++ ++} ++ ++#endif /*_HIF_TX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h +new file mode 100644 +index 000000000000..ff38d30c3cf2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h +@@ -0,0 +1,2323 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/mac.h#1 ++*/ ++ ++/*! \file "mac.h" ++ \brief Brief description. ++ ++ Detail description. ++*/ ++ ++/* ++** Log: mac.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h ++ * and let the sw structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 05 06 2011 wh.su ++ * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send ++ * the wrong beacon make driver got incorrect support rate set ++ * Add the length check before access the ie length filed. ++ * ++ * 05 06 2011 wh.su ++ * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send ++ * the wrong beacon make driver got incorrect support rate set ++ * adding the length check before processing next ie.. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discover ability support. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Some action frame define is not belong to P2P. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Add some service discovery MAC define, phase I. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork ++ * suppress warning reported by Klockwork. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * revert to previous revision. (this file is not necessary to be changed) ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * 1. Add P2P MAC define. ++ * 2. Add scan device found event ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add WFA specific OUI. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P IE ID & Vendor OUI TYPE for P2P. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge MAC.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added OFFSET_BAR_SSC_SN ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:00:24 GMT MTK02468 ++** Added offsets and masks for the BA Parameter Set filed ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:26 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _MAC_H ++#define _MAC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* 3 --------------- Constants for Ethernet/802.11 MAC --------------- */ ++/* MAC Address */ ++#define MAC_ADDR_LEN 6 ++ ++#define MAC_ADDR_LOCAL_ADMIN BIT(1) ++ ++#define ETH_P_IPV4 0x0800 ++#define ETH_P_IPX 0x8137 /* Novell IPX */ ++#define ETH_P_AARP 0x80F3 /* AppleTalk Address Resolution Protocol (AARP) */ ++#define ETH_P_IPV6 0x86DD ++ ++#define IP_VERSION_4 4 ++#define IP_VERSION_6 6 ++ ++#define IP_PROTOCOL_TCP 6 ++#define IP_PROTOCOL_UDP 17 ++ ++#define IPV4_HDR_IP_IDENTIFICATION_OFFSET 4 ++#define IPV4_HDR_IP_PROTOCOL_OFFSET 9 ++#define IPV4_HDR_IP_CSUM_OFFSET 10 ++#define IPV4_HDR_IP_SRC_ADDR_OFFSET 12 ++#define IPV4_HDR_IP_DST_ADDR_OFFSET 16 ++ ++#define IPV6_HDR_IP_PROTOCOL_OFFSET 6 ++#define IPV6_HDR_IP_SRC_ADDR_OFFSET 8 ++#define IPV6_HDR_IP_DST_ADDR_OFFSET 24 ++#define IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET 32 ++#define IPV6_HDR_IP_DST_ADDR_MAC_LOW_OFFSET 37 ++#define IPV6_PROTOCOL_ICMPV6 0x3A ++#define IPV6_ADDR_LEN 16 ++#define IPV6_HDR_LEN 40 ++ ++#define ARP_OPERATION_OFFSET 6 ++#define ARP_SNEDER_MAC_OFFSET 8 ++#define ARP_SENDER_IP_OFFSET 14 ++#define ARP_TARGET_MAC_OFFSET 18 ++#define ARP_TARGET_IP_OFFSET 24 ++#define ARP_OPERATION_REQUEST 0x0001 ++#define ARP_OPERATION_RESPONSE 0x0002 ++ ++#define ICMPV6_TYPE_OFFSET 0 ++#define ICMPV6_FLAG_OFFSET 4 ++#define ICMPV6_TARGET_ADDR_OFFSET 8 ++#define ICMPV6_TARGET_LL_ADDR_TYPE_OFFSET 24 ++#define ICMPV6_TARGET_LL_ADDR_LEN_OFFSET 25 ++#define ICMPV6_TARGET_LL_ADDR_TA_OFFSET 26 ++ ++#define ICMPV6_FLAG_ROUTER_BIT BIT(7) ++#define ICMPV6_FLAG_SOLICITED_BIT BIT(6) ++#define ICMPV6_FLAG_OVERWRITE_BIT BIT(5) ++#define ICMPV6_TYPE_NEIGHBOR_SOLICITATION 0x87 ++#define ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT 0x88 ++ ++#define TCP_HDR_TCP_CSUM_OFFSET 16 ++#define UDP_HDR_UDP_CSUM_OFFSET 6 ++ ++#define LLC_LEN 8 /* LLC(3) + SNAP(3) + EtherType(2) */ ++ ++#define NULL_MAC_ADDR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ++#define BC_MAC_ADDR {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} ++ ++/* Ethernet Frame Field Size, in byte */ ++#define ETHER_HEADER_LEN 14 ++#define ETHER_TYPE_LEN 2 ++#define ETHER_MIN_PKT_SZ 60 ++#define ETHER_MAX_PKT_SZ 1514 ++ ++/* IEEE 802.11 WLAN Frame Field Size, in byte */ ++#define WLAN_MAC_HEADER_LEN 24 /* Address 4 excluded */ ++#define WLAN_MAC_HEADER_A4_LEN 30 /* Address 4 included */ ++#define WLAN_MAC_HEADER_QOS_LEN 26 /* QoS Control included */ ++#define WLAN_MAC_HEADER_QOS_HTC_LEN 30 /* QoS Control and HTC included */ ++#define WLAN_MAC_HEADER_A4_QOS_LEN 32 /* Address 4 and QoS Control included */ ++#define WLAN_MAC_HEADER_A4_QOS_HTC_LEN 36 /* Address 4, QoS Control and HTC included */ ++#define WLAN_MAC_MGMT_HEADER_LEN 24 /* Address 4 excluded */ ++#define WLAN_MAC_MGMT_HEADER_HTC_LEN 28 /* HTC included */ ++ ++#define QOS_CTRL_LEN 2 ++#define HT_CTRL_LEN 4 ++ ++#define WLAN_MAC_CTS_ACK_LEN (WLAN_MAC_CTS_ACK_FRAME_HEADER_LEN + FCS_LEN) ++ ++/* 6.2.1.1.2 Semantics of the service primitive */ ++#define MSDU_MAX_LENGTH 2304 ++ ++/* 7.1.3.3.3 Broadcast BSSID */ ++#define BC_BSSID BC_MAC_ADDR ++ ++/* 7.1.3.7 FCS field */ ++#define FCS_LEN 4 ++ ++/* 7.3.1.6 Listen Interval field */ ++#define DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD 2 /* In unit of AP's DTIM interval, */ ++#define DEFAULT_LISTEN_INTERVAL 10 ++ ++/* 7.3.2.1 Broadcast(Wildcard) SSID */ ++#define BC_SSID "" ++#define BC_SSID_LEN 0 ++ ++/* 7.3.2.2 Data Rate Value */ ++#define RATE_1M 2 /* 1M in unit of 500kb/s */ ++#define RATE_2M 4 /* 2M */ ++#define RATE_5_5M 11 /* 5.5M */ ++#define RATE_11M 22 /* 11M */ ++#define RATE_22M 44 /* 22M */ ++#define RATE_33M 66 /* 33M */ ++#define RATE_6M 12 /* 6M */ ++#define RATE_9M 18 /* 9M */ ++#define RATE_12M 24 /* 12M */ ++#define RATE_18M 36 /* 18M */ ++#define RATE_24M 48 /* 24M */ ++#define RATE_36M 72 /* 36M */ ++#define RATE_48M 96 /* 48M */ ++#define RATE_54M 108 /* 54M */ ++/* 7.3.2.14 BSS membership selector */ ++#define RATE_HT_PHY 127 /* BSS Selector - Clause 20. HT PHY */ ++#define RATE_MASK BITS(0, 6) /* mask bits for the rate */ ++#define RATE_BASIC_BIT BIT(7) /* mask bit for the rate belonging to the BSSBasicRateSet */ ++ ++/* 8.3.2.2 TKIP MPDU formats */ ++#define TKIP_MIC_LEN 8 ++ ++/* 9.2.10 DIFS */ ++#define DIFS 2 /* 2 x aSlotTime */ ++ ++/* 11.3 STA Authentication and Association */ ++#define STA_STATE_1 0 /* Accept Class 1 frames */ ++#define STA_STATE_2 1 /* Accept Class 1 & 2 frames */ ++#define STA_STATE_3 2 /* Accept Class 1,2 & 3 frames */ ++ ++/* 15.4.8.5 802.11k RCPI-dBm mapping*/ ++#define NDBM_LOW_BOUND_FOR_RCPI 110 ++#define RCPI_LOW_BOUND 0 ++#define RCPI_HIGH_BOUND 220 ++#define RCPI_MEASUREMENT_NOT_AVAILABLE 255 ++ ++/* PHY characteristics */ ++/* 17.4.4/18.3.3/19.8.4 Slot Time (aSlotTime) */ ++#define SLOT_TIME_LONG 20 /* Long Slot Time */ ++#define SLOT_TIME_SHORT 9 /* Short Slot Time */ ++ ++#define SLOT_TIME_HR_DSSS SLOT_TIME_LONG /* 802.11b aSlotTime */ ++#define SLOT_TIME_OFDM SLOT_TIME_SHORT /* 802.11a aSlotTime(20M Spacing) */ ++#define SLOT_TIME_OFDM_10M_SPACING 13 /* 802.11a aSlotTime(10M Spacing) */ ++#define SLOT_TIME_ERP_LONG SLOT_TIME_LONG /* 802.11g aSlotTime(Long) */ ++#define SLOT_TIME_ERP_SHORT SLOT_TIME_SHORT /* 802.11g aSlotTime(Short) */ ++ ++/* 17.4.4/18.3.3/19.8.4 Contention Window (aCWmin & aCWmax) */ ++#define CWMIN_OFDM 15 /* 802.11a aCWmin */ ++#define CWMAX_OFDM 1023 /* 802.11a aCWmax */ ++ ++#define CWMIN_HR_DSSS 31 /* 802.11b aCWmin */ ++#define CWMAX_HR_DSSS 1023 /* 802.11b aCWmax */ ++ ++#define CWMIN_ERP_0 31 /* 802.11g aCWmin(0) - for only have 1/2/5/11Mbps Rates */ ++#define CWMIN_ERP_1 15 /* 802.11g aCWmin(1) */ ++#define CWMAX_ERP 1023 /* 802.11g aCWmax */ ++ ++/* Short Inter-Frame Space (aSIFSTime) */ ++/* 15.3.3 802.11b aSIFSTime */ ++#define SIFS_TIME_HR_DSSS 10 ++/* 17.4.4 802.11a aSIFSTime */ ++#define SIFS_TIME_OFDM 16 ++/* 19.8.4 802.11g aSIFSTime */ ++#define SIFS_TIME_ERP 10 ++ ++/* 15.4.6.2 Number of operating channels */ ++#define CH_1 0x1 ++#define CH_2 0x2 ++#define CH_3 0x3 ++#define CH_4 0x4 ++#define CH_5 0x5 ++#define CH_6 0x6 ++#define CH_7 0x7 ++#define CH_8 0x8 ++#define CH_9 0x9 ++#define CH_10 0xa ++#define CH_11 0xb ++#define CH_12 0xc ++#define CH_13 0xd ++#define CH_14 0xe ++ ++#define MAXIMUM_OPERATION_CHANNEL_LIST 46 ++ ++/* 3 --------------- IEEE 802.11 PICS --------------- */ ++/* Annex D - dot11OperationEntry 2 */ ++#define DOT11_RTS_THRESHOLD_MIN 0 ++#define DOT11_RTS_THRESHOLD_MAX 2347 /* from Windows DDK */ ++/* #define DOT11_RTS_THRESHOLD_MAX 3000 // from Annex D */ ++ ++#define DOT11_RTS_THRESHOLD_DEFAULT \ ++ DOT11_RTS_THRESHOLD_MAX ++ ++/* Annex D - dot11OperationEntry 5 */ ++#define DOT11_FRAGMENTATION_THRESHOLD_MIN 256 ++#define DOT11_FRAGMENTATION_THRESHOLD_MAX 2346 /* from Windows DDK */ ++/* #define DOT11_FRAGMENTATION_THRESHOLD_MAX 3000 // from Annex D */ ++ ++#define DOT11_FRAGMENTATION_THRESHOLD_DEFAULT \ ++ DOT11_FRAGMENTATION_THRESHOLD_MAX ++ ++/* Annex D - dot11OperationEntry 6 */ ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MIN 1 ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MAX 0xFFFFffff ++#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_DEFAULT 4095 /* 802.11 define 512 */ ++ /* MT5921 only aceept N <= 4095 */ ++ ++/* Annex D - dot11OperationEntry 7 */ ++#define DOT11_RECEIVE_LIFETIME_TU_MIN 1 ++#define DOT11_RECEIVE_LIFETIME_TU_MAX 0xFFFFffff ++#define DOT11_RECEIVE_LIFETIME_TU_DEFAULT 4096 /* 802.11 define 512 */ ++ ++/* Annex D - dot11StationConfigEntry 12 */ ++#define DOT11_BEACON_PERIOD_MIN 1 /* TU. */ ++#define DOT11_BEACON_PERIOD_MAX 0xffff /* TU. */ ++#define DOT11_BEACON_PERIOD_DEFAULT 100 /* TU. */ ++ ++/* Annex D - dot11StationConfigEntry 13 */ ++#define DOT11_DTIM_PERIOD_MIN 1 /* TU. */ ++#define DOT11_DTIM_PERIOD_MAX 255 /* TU. */ ++#define DOT11_DTIM_PERIOD_DEFAULT 1 /* TU. */ ++ ++/* Annex D - dot11RegDomainsSupportValue */ ++#define REGULATION_DOMAIN_FCC 0x10 /* FCC (US) */ ++#define REGULATION_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ ++#define REGULATION_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ ++#define REGULATION_DOMAIN_SPAIN 0x31 /* Spain */ ++#define REGULATION_DOMAIN_FRANCE 0x32 /* France */ ++#define REGULATION_DOMAIN_JAPAN 0x40 /* MKK (Japan) */ ++#define REGULATION_DOMAIN_CHINA 0x50 /* China */ ++#define REGULATION_DOMAIN_OTHER 0x00 /* Other */ ++ ++/* 3 --------------- IEEE 802.11 MAC header fields --------------- */ ++/* 7.1.3.1 Masks for the subfields in the Frame Control field */ ++#define MASK_FC_PROTOCOL_VER BITS(0, 1) ++#define MASK_FC_TYPE BITS(2, 3) ++#define MASK_FC_SUBTYPE BITS(4, 7) ++#define MASK_FC_SUBTYPE_QOS_DATA BIT(7) ++#define MASK_FC_TO_DS BIT(8) ++#define MASK_FC_FROM_DS BIT(9) ++#define MASK_FC_MORE_FRAG BIT(10) ++#define MASK_FC_RETRY BIT(11) ++#define MASK_FC_PWR_MGT BIT(12) ++#define MASK_FC_MORE_DATA BIT(13) ++#define MASK_FC_PROTECTED_FRAME BIT(14) ++#define MASK_FC_ORDER BIT(15) ++ ++#define MASK_FRAME_TYPE (MASK_FC_TYPE | MASK_FC_SUBTYPE) ++#define MASK_TO_DS_FROM_DS (MASK_FC_TO_DS | MASK_FC_FROM_DS) ++ ++#define MAX_NUM_OF_FC_SUBTYPES 16 ++#define OFFSET_OF_FC_SUBTYPE 4 ++ ++/* 7.1.3.1.2 MAC frame types and subtypes */ ++#define MAC_FRAME_TYPE_MGT 0 ++#define MAC_FRAME_TYPE_CTRL BIT(2) ++#define MAC_FRAME_TYPE_DATA BIT(3) ++#define MAC_FRAME_TYPE_QOS_DATA (MAC_FRAME_TYPE_DATA | MASK_FC_SUBTYPE_QOS_DATA) ++ ++#define MAC_FRAME_ASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0000) ++#define MAC_FRAME_ASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0010) ++#define MAC_FRAME_REASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0020) ++#define MAC_FRAME_REASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0030) ++#define MAC_FRAME_PROBE_REQ (MAC_FRAME_TYPE_MGT | 0x0040) ++#define MAC_FRAME_PROBE_RSP (MAC_FRAME_TYPE_MGT | 0x0050) ++#define MAC_FRAME_BEACON (MAC_FRAME_TYPE_MGT | 0x0080) ++#define MAC_FRAME_ATIM (MAC_FRAME_TYPE_MGT | 0x0090) ++#define MAC_FRAME_DISASSOC (MAC_FRAME_TYPE_MGT | 0x00A0) ++#define MAC_FRAME_AUTH (MAC_FRAME_TYPE_MGT | 0x00B0) ++#define MAC_FRAME_DEAUTH (MAC_FRAME_TYPE_MGT | 0x00C0) ++#define MAC_FRAME_ACTION (MAC_FRAME_TYPE_MGT | 0x00D0) ++#define MAC_FRAME_ACTION_NO_ACK (MAC_FRAME_TYPE_MGT | 0x00E0) ++ ++#define MAC_FRAME_CONTRL_WRAPPER (MAC_FRAME_TYPE_CTRL | 0x0070) ++#define MAC_FRAME_BLOCK_ACK_REQ (MAC_FRAME_TYPE_CTRL | 0x0080) ++#define MAC_FRAME_BLOCK_ACK (MAC_FRAME_TYPE_CTRL | 0x0090) ++#define MAC_FRAME_PS_POLL (MAC_FRAME_TYPE_CTRL | 0x00A0) ++#define MAC_FRAME_RTS (MAC_FRAME_TYPE_CTRL | 0x00B0) ++#define MAC_FRAME_CTS (MAC_FRAME_TYPE_CTRL | 0x00C0) ++#define MAC_FRAME_ACK (MAC_FRAME_TYPE_CTRL | 0x00D0) ++#define MAC_FRAME_CF_END (MAC_FRAME_TYPE_CTRL | 0x00E0) ++#define MAC_FRAME_CF_END_CF_ACK (MAC_FRAME_TYPE_CTRL | 0x00F0) ++ ++#define MAC_FRAME_DATA (MAC_FRAME_TYPE_DATA | 0x0000) ++#define MAC_FRAME_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0010) ++#define MAC_FRAME_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0020) ++#define MAC_FRAME_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0030) ++#define MAC_FRAME_NULL (MAC_FRAME_TYPE_DATA | 0x0040) ++#define MAC_FRAME_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0050) ++#define MAC_FRAME_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0060) ++#define MAC_FRAME_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0070) ++#define MAC_FRAME_QOS_DATA (MAC_FRAME_TYPE_DATA | 0x0080) ++#define MAC_FRAME_QOS_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0090) ++#define MAC_FRAME_QOS_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00A0) ++#define MAC_FRAME_QOS_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00B0) ++#define MAC_FRAME_QOS_NULL (MAC_FRAME_TYPE_DATA | 0x00C0) ++#define MAC_FRAME_QOS_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00E0) ++#define MAC_FRAME_QOS_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00F0) ++ ++/* 7.1.3.2 Mask for the AID value in the Duration/ID field */ ++#define MASK_DI_DURATION BITS(0, 14) ++#define MASK_DI_AID BITS(0, 13) ++#define MASK_DI_AID_MSB BITS(14, 15) ++#define MASK_DI_CFP_FIXED_VALUE BIT(15) ++ ++/* 7.1.3.4 Masks for the subfields in the Sequence Control field */ ++#define MASK_SC_SEQ_NUM BITS(4, 15) ++#define MASK_SC_SEQ_NUM_OFFSET 4 ++#define MASK_SC_FRAG_NUM BITS(0, 3) ++#define INVALID_SEQ_CTRL_NUM 0x000F /* According to 6.2.1.1.2 ++ * FRAG_NUM won't equal to 15 ++ */ ++ ++/* 7.1.3.5 QoS Control field */ ++#define TID_NUM 16 ++#define TID_MASK BITS(0, 3) ++#define EOSP BIT(4) ++#define ACK_POLICY BITS(5, 6) ++#define A_MSDU_PRESENT BIT(7) ++ ++#define MASK_QC_TID BITS(0, 3) ++#define MASK_QC_EOSP BIT(4) ++#define MASK_QC_EOSP_OFFSET 4 ++#define MASK_QC_ACK_POLICY BITS(5, 6) ++#define MASK_QC_ACK_POLICY_OFFSET 5 ++#define MASK_QC_A_MSDU_PRESENT BIT(7) ++ ++/* 7.1.3.5a HT Control field */ ++#define HT_CTRL_LINK_ADAPTATION_CTRL BITS(0, 15) ++#define HT_CTRL_CALIBRATION_POSITION BITS(16, 17) ++#define HT_CTRL_CALIBRATION_SEQUENCE BITS(18, 19) ++#define HT_CTRL_CSI_STEERING BITS(22, 23) ++#define HT_CTRL_NDP_ANNOUNCEMENT BIT(24) ++#define HT_CTRL_AC_CONSTRAINT BIT(30) ++#define HT_CTRL_RDG_MORE_PPDU BIT(31) ++ ++#define LINK_ADAPTATION_CTRL_TRQ BIT(1) ++#define LINK_ADAPTATION_CTRL_MAI_MRQ BIT(2) ++#define LINK_ADAPTATION_CTRL_MAI_MSI BITS(3, 5) ++#define LINK_ADAPTATION_CTRL_MFSI BITS(6, 8) ++#define LINK_ADAPTATION_CTRL_MFB_ASELC_CMD BITS(9, 11) ++#define LINK_ADAPTATION_CTRL_MFB_ASELC_DATA BITS(12, 15) ++ ++/* 7.1.3.5.3 Ack Policy subfield*/ ++#define ACK_POLICY_NORMAL_ACK_IMPLICIT_BA_REQ 0 ++#define ACK_POLICY_NO_ACK 1 ++#define ACK_POLICY_NO_EXPLICIT_ACK_PSMP_ACK 2 ++#define ACK_POLICY_BA 3 ++ ++/* 7.1.3.7 FCS field */ ++#define FCS_LEN 4 ++ ++/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ ++#define PSPOLL_FRAME_LEN 16 /* w/o FCS */ ++ ++/* 7.2.7.1 BAR */ ++#define OFFSET_BAR_SSC_SN 4 ++ ++/* 8.3.2.2 TKIP MPDU formats */ ++#define TKIP_MIC_LEN 8 ++ ++/* 2009.11.30 mtk02468: Moved these definitions to the right place */ ++#if 0 ++/* Block Ack Parameter Set field */ ++#define BA_PARM_BA_POLICY BIT(1) ++#define BA_PARM_TID BITS(2, 5) ++#define BA_PARM_BUFFER_SIZE BITS(6, 15) ++#endif ++ ++#define BA_POLICY_IMMEDIATE BIT(1) ++ ++/* Block Ack Starting Sequence Control field */ ++#define BA_START_SEQ_CTL_FRAG_NUM BITS(0, 3) ++#define BA_START_SEQ_CTL_SSN BITS(4, 15) ++ ++/* BAR Control field */ ++#define BAR_CONTROL_NO_ACK_POLICY BIT(0) ++#define BAR_CONTROL_MULTI_TID BIT(1) ++#define BAR_CONTROL_COMPRESSED_BA BIT(2) ++#define BAR_CONTROL_TID_INFO BITS(12, 15) ++#define BAR_CONTROL_TID_INFO_OFFSET 12 ++ ++/* TID Value */ ++#define BAR_INFO_TID_VALUE BITS(12, 15) ++ ++#define BAR_COMPRESSED_VARIANT_FRAME_LEN (16 + 4) ++ ++/* 3 --------------- IEEE 802.11 frame body fields --------------- */ ++/* 3 Management frame body components (I): Fixed Fields. */ ++/* 7.3.1.1 Authentication Algorithm Number field */ ++#define AUTH_ALGORITHM_NUM_FIELD_LEN 2 ++ ++#define AUTH_ALGORITHM_NUM_OPEN_SYSTEM 0 /* Open System */ ++#define AUTH_ALGORITHM_NUM_SHARED_KEY 1 /* Shared Key */ ++#define AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION 2 /* Fast BSS Transition */ ++ ++/* 7.3.1.2 Authentication Transaction Sequence Number field */ ++#define AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN 2 ++#define AUTH_TRANSACTION_SEQ_1 1 ++#define AUTH_TRANSACTION_SEQ_2 2 ++#define AUTH_TRANSACTION_SEQ_3 3 ++#define AUTH_TRANSACTION_SEQ_4 4 ++ ++/* 7.3.1.3 Beacon Interval field */ ++#define BEACON_INTERVAL_FIELD_LEN 2 ++ ++/* 7.3.1.4 Capability Information field */ ++#define CAP_INFO_FIELD_LEN 2 ++#define CAP_INFO_ESS BIT(0) ++#define CAP_INFO_IBSS BIT(1) ++#define CAP_INFO_BSS_TYPE (CAP_INFO_ESS | CAP_INFO_IBSS) ++#define CAP_INFO_CF_POLLABLE BIT(2) ++#define CAP_INFO_CF_POLL_REQ BIT(3) ++#define CAP_INFO_CF (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) ++#define CAP_INFO_PRIVACY BIT(4) ++#define CAP_INFO_SHORT_PREAMBLE BIT(5) ++#define CAP_INFO_PBCC BIT(6) ++#define CAP_INFO_CH_AGILITY BIT(7) ++#define CAP_INFO_SPEC_MGT BIT(8) ++#define CAP_INFO_QOS BIT(9) ++#define CAP_INFO_SHORT_SLOT_TIME BIT(10) ++#define CAP_INFO_APSD BIT(11) ++#define CAP_INFO_RESERVED BIT(12) ++#define CAP_INFO_DSSS_OFDM BIT(13) ++#define CAP_INFO_DELAYED_BLOCK_ACK BIT(14) ++#define CAP_INFO_IMM_BLOCK_ACK BIT(15) ++/* STA usage of CF-Pollable and CF-Poll Request subfields */ ++/* STA: not CF-Pollable */ ++#define CAP_CF_STA_NOT_POLLABLE 0x0000 ++/* STA: CF-Pollable, not requesting on the CF-Polling list */ ++#define CAP_CF_STA_NOT_ON_LIST CAP_INFO_CF_POLL_REQ ++/* STA: CF-Pollable, requesting on the CF-Polling list */ ++#define CAP_CF_STA_ON_LIST CAP_INFO_CF_POLLABLE ++/* STA: CF-Pollable, requesting never to be polled */ ++#define CAP_CF_STA_NEVER_POLLED (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) ++ ++/* AP usage of CF-Pollable and CF-Poll Request subfields */ ++/* AP: No point coordinator (PC) */ ++#define CAP_CF_AP_NO_PC 0x0000 ++/* AP: PC at AP for delivery only (no polling) */ ++#define CAP_CF_AP_DELIVERY_ONLY CAP_INFO_CF_POLL_REQ ++/* AP: PC at AP for delivery and polling */ ++#define CAP_CF_AP_DELIVERY_POLLING CAP_INFO_CF_POLLABLE ++ ++/* 7.3.1.5 Current AP Address field */ ++#define CURR_AP_ADDR_FIELD_LEN MAC_ADDR_LEN ++ ++/* 7.3.1.6 Listen Interval field */ ++#define LISTEN_INTERVAL_FIELD_LEN 2 ++ ++/* 7.3.1.7 Reason Code field */ ++#define REASON_CODE_FIELD_LEN 2 ++ ++#define REASON_CODE_RESERVED 0 /* Reseved */ ++#define REASON_CODE_UNSPECIFIED 1 /* Unspecified reason */ ++#define REASON_CODE_PREV_AUTH_INVALID 2 /* Previous auth no longer valid */ ++#define REASON_CODE_DEAUTH_LEAVING_BSS 3 /* Deauth because sending STA is leaving BSS */ ++#define REASON_CODE_DISASSOC_INACTIVITY 4 /* Disassoc due to inactivity */ ++#define REASON_CODE_DISASSOC_AP_OVERLOAD 5 /* Disassoc because AP is unable to handle all assoc STAs */ ++#define REASON_CODE_CLASS_2_ERR 6 /* Class 2 frame rx from nonauth STA */ ++#define REASON_CODE_CLASS_3_ERR 7 /* Class 3 frame rx from nonassoc STA */ ++#define REASON_CODE_DISASSOC_LEAVING_BSS 8 /* Disassoc because sending STA is leaving BSS */ ++#define REASON_CODE_ASSOC_BEFORE_AUTH 9 /* STA requesting (re)assoc is not auth with responding STA */ ++#define REASON_CODE_DISASSOC_PWR_CAP_UNACCEPTABLE 10 /* Disassoc because the info in Power Capability is ++ unacceptable */ ++#define REASON_CODE_DISASSOC_SUP_CHS_UNACCEPTABLE 11 /* Disassoc because the info in Supported Channels is ++ unacceptable */ ++#define REASON_CODE_INVALID_INFO_ELEM 13 /* Invalid information element */ ++#define REASON_CODE_MIC_FAILURE 14 /* MIC failure */ ++#define REASON_CODE_4_WAY_HANDSHAKE_TIMEOUT 15 /* 4-way handshake timeout */ ++#define REASON_CODE_GROUP_KEY_UPDATE_TIMEOUT 16 /* Group key update timeout */ ++#define REASON_CODE_DIFFERENT_INFO_ELEM 17 /* Info element in 4-way handshake different from ++ (Re-)associate request/Probe response/Beacon */ ++#define REASON_CODE_MULTICAST_CIPHER_NOT_VALID 18 /* Multicast Cipher is not valid */ ++#define REASON_CODE_UNICAST_CIPHER_NOT_VALID 19 /* Unicast Cipher is not valid */ ++#define REASON_CODE_AKMP_NOT_VALID 20 /* AKMP is not valid */ ++#define REASON_CODE_UNSUPPORTED_RSNE_VERSION 21 /* Unsupported RSNE version */ ++#define REASON_CODE_INVALID_RSNE_CAPABILITIES 22 /* Invalid RSNE Capabilities */ ++#define REASON_CODE_IEEE_802_1X_AUTH_FAILED 23 /* IEEE 802.1X Authentication failed */ ++#define REASON_CODE_CIPHER_REJECT_SEC_POLICY 24 /* Cipher suite rejected because of the security policy */ ++#define REASON_CODE_DISASSOC_UNSPECIFIED_QOS 32 /* Disassoc for unspecified, QoS-related reason */ ++#define REASON_CODE_DISASSOC_LACK_OF_BANDWIDTH 33 /* Disassoc because QAP lacks sufficient bandwidth ++ for this QSTA */ ++#define REASON_CODE_DISASSOC_ACK_LOST_POOR_CHANNEL 34 /* Disassoc because of too many ACKs lost for AP transmissions ++ and/or poor channel conditions */ ++#define REASON_CODE_DISASSOC_TX_OUTSIDE_TXOP_LIMIT 35 /* Disassoc because QSTA is transmitting outside the limits of ++ its TXOPs */ ++#define REASON_CODE_PEER_WHILE_LEAVING 36 /* QSTA is leaving the QBSS or resetting */ ++#define REASON_CODE_PEER_REFUSE_DLP 37 /* Peer does not want to use this mechanism */ ++#define REASON_CODE_PEER_SETUP_REQUIRED 38 /* Frames received but a setup is reqired */ ++#define REASON_CODE_PEER_TIME_OUT 39 /* Time out */ ++#define REASON_CODE_PEER_CIPHER_UNSUPPORTED 45 /* Peer does not support the requested cipher suite */ ++#define REASON_CODE_BEACON_TIMEOUT 100 /* for beacon timeout, defined by mediatek */ ++#define REASON_CODE_BSS_SECURITY_CHANGE 101 /* for BSS security change, defined by mediatek */ ++/* 7.3.1.8 AID field */ ++#define AID_FIELD_LEN 2 ++#define AID_MASK BITS(0, 13) ++#define AID_MSB BITS(14, 15) ++#define AID_MIN_VALUE 1 ++#define AID_MAX_VALUE 2007 ++ ++/* 7.3.1.9 Status Code field */ ++#define STATUS_CODE_FIELD_LEN 2 ++ ++#define STATUS_CODE_RESERVED 0 /* Reserved - Used by TX Auth */ ++#define STATUS_CODE_SUCCESSFUL 0 /* Successful */ ++#define STATUS_CODE_UNSPECIFIED_FAILURE 1 /* Unspecified failure */ ++#define STATUS_CODE_CAP_NOT_SUPPORTED 10 /* Cannot support all requested cap in the Cap Info field */ ++#define STATUS_CODE_REASSOC_DENIED_WITHOUT_ASSOC 11 /* Reassoc denied due to inability to confirm that ++ assoc exists */ ++#define STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD 12 /* Assoc denied due to reason outside the scope of this std. */ ++#define STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED 13 /* Responding STA does not support the specified ++ auth algorithm */ ++#define STATUS_CODE_AUTH_OUT_OF_SEQ 14 /* Rx an auth frame with auth transaction seq num ++ out of expected seq */ ++#define STATUS_CODE_AUTH_REJECTED_CHAL_FAIL 15 /* Auth rejected because of challenge failure */ ++#define STATUS_CODE_AUTH_REJECTED_TIMEOUT 16 /* Auth rejected due to timeout waiting for next frame ++ in sequence */ ++#define STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD 17 /* Assoc denied because AP is unable to handle additional ++ assoc STAs */ ++#define STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED 18 /* Assoc denied due to requesting STA not supporting ++ all of basic rates */ ++#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_PREAMBLE 19 /* Assoc denied due to requesting STA not supporting short ++ preamble */ ++#define STATUS_CODE_ASSOC_DENIED_NO_PBCC 20 /* Assoc denied due to requesting STA not supporting PBCC */ ++#define STATUS_CODE_ASSOC_DENIED_NO_CH_AGILITY 21 /* Assoc denied due to requesting STA not supporting channel ++ agility */ ++#define STATUS_CODE_ASSOC_REJECTED_NO_SPEC_MGT 22 /* Assoc rejected because Spectrum Mgt capability is required */ ++#define STATUS_CODE_ASSOC_REJECTED_PWR_CAP 23 /* Assoc rejected because the info in Power Capability ++ is unacceptable */ ++#define STATUS_CODE_ASSOC_REJECTED_SUP_CHS 24 /* Assoc rejected because the info in Supported Channels ++ is unacceptable */ ++#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 /* Assoc denied due to requesting STA not supporting ++ short slot time */ ++#define STATUS_CODE_ASSOC_DENIED_NO_DSSS_OFDM 26 /* Assoc denied due to requesting STA not supporting ++ DSSS-OFDM */ ++#if CFG_SUPPORT_802_11W ++#define STATUS_CODE_ASSOC_REJECTED_TEMPORARILY 30 /* IEEE 802.11w, Assoc denied due to the SA query */ ++#define STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 /* IEEE 802.11w, Assoc denied due to the MFP select ++ policy */ ++#endif ++#define STATUS_CODE_UNSPECIFIED_QOS_FAILURE 32 /* Unspecified, QoS-related failure */ ++#define STATUS_CODE_ASSOC_DENIED_BANDWIDTH 33 /* Assoc denied due to insufficient bandwidth to handle another ++ QSTA */ ++#define STATUS_CODE_ASSOC_DENIED_POOR_CHANNEL 34 /* Assoc denied due to excessive frame loss rates and/or poor ++ channel conditions */ ++#define STATUS_CODE_ASSOC_DENIED_NO_QOS_FACILITY 35 /* Assoc denied due to requesting STA not supporting QoS ++ facility */ ++#define STATUS_CODE_REQ_DECLINED 37 /* Request has been declined */ ++#define STATUS_CODE_REQ_INVALID_PARAMETER_VALUE 38 /* Request has not been successful as one or more parameters ++ have invalid values */ ++#define STATUS_CODE_REQ_NOT_HONORED_TSPEC 39 /* TS not created because request cannot be honored. ++ Suggested TSPEC provided. */ ++#define STATUS_CODE_INVALID_INFO_ELEMENT 40 /* Invalid information element */ ++#define STATUS_CODE_INVALID_GROUP_CIPHER 41 /* Invalid group cipher */ ++#define STATUS_CODE_INVALID_PAIRWISE_CIPHER 42 /* Invalid pairwise cipher */ ++#define STATUS_CODE_INVALID_AKMP 43 /* Invalid AKMP */ ++#define STATUS_CODE_UNSUPPORTED_RSN_IE_VERSION 44 /* Unsupported RSN information element version */ ++#define STATUS_CODE_INVALID_RSN_IE_CAP 45 /* Invalid RSN information element capabilities */ ++#define STATUS_CODE_CIPHER_SUITE_REJECTED 46 /* Cipher suite rejected because of security policy */ ++#define STATUS_CODE_REQ_NOT_HONORED_TS_DELAY 47 /* TS not created because request cannot be honored. ++ Attempt to create a TS later. */ ++#define STATUS_CODE_DIRECT_LINK_NOT_ALLOWED 48 /* Direct Link is not allowed in the BSS by policy */ ++#define STATUS_CODE_DESTINATION_STA_NOT_PRESENT 49 /* Destination STA is not present within this QBSS */ ++#define STATUS_CODE_DESTINATION_STA_NOT_QSTA 50 /* Destination STA is not a QSTA */ ++#define STATUS_CODE_ASSOC_DENIED_LARGE_LIS_INTERVAL 51 /* Association denied because the ListenInterval is too large */ ++ ++/* proprietary definition of reserved field of Status Code */ ++#define STATUS_CODE_JOIN_FAILURE 0xFFF0 /* Join failure */ ++#define STATUS_CODE_JOIN_TIMEOUT 0xFFF1 /* Join timeout */ ++#define STATUS_CODE_AUTH_TIMEOUT 0xFFF2 /* Authentication timeout */ ++#define STATUS_CODE_ASSOC_TIMEOUT 0xFFF3 /* (Re)Association timeout */ ++#define STATUS_CODE_CCX_CCKM_REASSOC_FAILURE 0xFFF4 /* CCX CCKM reassociation failure */ ++ ++/* 7.3.1.10 Timestamp field */ ++#define TIMESTAMP_FIELD_LEN 8 ++ ++/* 7.3.1.11 Category of Action field */ ++#define CATEGORY_SPEC_MGT 0 ++#define CATEGORY_QOS_ACTION 1 /* QoS action */ ++#define CATEGORY_DLS_ACTION 2 /* Direct Link Protocol (DLP) action */ ++#define CATEGORY_BLOCK_ACK_ACTION 3 /* Block ack action */ ++#define CATEGORY_PUBLIC_ACTION 4 /* Public action */ ++#define CATEGORY_RM_ACTION 5 /* Radio measurement action */ ++#define CATEGORY_HT_ACTION 7 ++#if CFG_SUPPORT_802_11W ++#define CATEGORY_SA_QUERT_ACTION 8 ++#endif ++#define CATEGORY_WNM_ACTION 10 /* 802.11v Wireless Network Management */ ++#define CATEGORY_UNPROTECTED_WNM_ACTION 11 /* 802.11v Wireless Network Management */ ++#define CATEGORY_WME_MGT_NOTIFICATION 17 /* WME management notification */ ++#define CATEGORY_VENDOR_SPECIFIC_ACTION 127 ++ ++/* 7.3.1.14 Block Ack Parameter Set field */ ++#define BA_PARAM_SET_ACK_POLICY_MASK BIT(1) ++#define BA_PARAM_SET_ACK_POLICY_MASK_OFFSET 1 ++#define BA_PARAM_SET_TID_MASK BITS(2, 5) ++#define BA_PARAM_SET_TID_MASK_OFFSET 2 ++#define BA_PARAM_SET_BUFFER_SIZE_MASK BITS(6, 15) ++#define BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET 6 ++ ++#define BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA 1 ++#define BA_PARAM_SET_ACK_POLICY_DELAYED_BA 0 ++ ++/* 3 Management frame body components (II): Information Elements. */ ++/* 7.3.2 Element IDs of information elements */ ++#define ELEM_HDR_LEN 2 ++ ++#define ELEM_ID_SSID 0 /* SSID */ ++#define ELEM_ID_SUP_RATES 1 /* Supported rates */ ++#define ELEM_ID_FH_PARAM_SET 2 /* FH parameter set */ ++#define ELEM_ID_DS_PARAM_SET 3 /* DS parameter set */ ++#define ELEM_ID_CF_PARAM_SET 4 /* CF parameter set */ ++#define ELEM_ID_TIM 5 /* TIM */ ++#define ELEM_ID_IBSS_PARAM_SET 6 /* IBSS parameter set */ ++#define ELEM_ID_COUNTRY_INFO 7 /* Country information */ ++#define ELEM_ID_HOPPING_PATTERN_PARAM 8 /* Hopping pattern parameters */ ++#define ELEM_ID_HOPPING_PATTERN_TABLE 9 /* Hopping pattern table */ ++#define ELEM_ID_REQUEST 10 /* Request */ ++#define ELEM_ID_BSS_LOAD 11 /* BSS load */ ++#define ELEM_ID_EDCA_PARAM_SET 12 /* EDCA parameter set */ ++#define ELEM_ID_TSPEC 13 /* Traffic specification (TSPEC) */ ++#define ELEM_ID_TCLAS 14 /* Traffic classification (TCLAS) */ ++#define ELEM_ID_SCHEDULE 15 /* Schedule */ ++#define ELEM_ID_CHALLENGE_TEXT 16 /* Challenge text */ ++ ++#define ELEM_ID_PWR_CONSTRAINT 32 /* Power constraint */ ++#define ELEM_ID_PWR_CAP 33 /* Power capability */ ++#define ELEM_ID_TPC_REQ 34 /* TPC request */ ++#define ELEM_ID_TPC_REPORT 35 /* TPC report */ ++#define ELEM_ID_SUP_CHS 36 /* Supported channels */ ++#define ELEM_ID_CH_SW_ANNOUNCEMENT 37 /* Channel switch announcement */ ++#define ELEM_ID_MEASUREMENT_REQ 38 /* Measurement request */ ++#define ELEM_ID_MEASUREMENT_REPORT 39 /* Measurement report */ ++#define ELEM_ID_QUIET 40 /* Quiet */ ++#define ELEM_ID_IBSS_DFS 41 /* IBSS DFS */ ++#define ELEM_ID_ERP_INFO 42 /* ERP information */ ++#define ELEM_ID_TS_DELAY 43 /* TS delay */ ++#define ELEM_ID_TCLAS_PROCESSING 44 /* TCLAS processing */ ++#define ELEM_ID_HT_CAP 45 /* HT Capabilities subelement */ ++#define ELEM_ID_QOS_CAP 46 /* QoS capability */ ++#define ELEM_ID_RSN 48 /* RSN IE */ ++#define ELEM_ID_EXTENDED_SUP_RATES 50 /* Extended supported rates */ ++#define ELEM_ID_TIMEOUT_INTERVAL 56 /* 802.11w SA Timeout interval */ ++#define ELEM_ID_SUP_OPERATING_CLASS 59 /* Supported Operating Classes */ ++#define ELEM_ID_HT_OP 61 /* HT Operation */ ++#define ELEM_ID_SCO 62 /* Secondary Channel Offset */ ++#define ELEM_ID_RRM_ENABLED_CAP 70 /* Radio Resource Management Enabled Capabilities */ ++#define ELEM_ID_20_40_BSS_COEXISTENCE 72 /* 20/40 BSS Coexistence */ ++#define ELEM_ID_20_40_INTOLERANT_CHNL_REPORT 73 /* 20/40 BSS Intolerant Channel Report */ ++#define ELEM_ID_OBSS_SCAN_PARAMS 74 /* Overlapping BSS Scan Parameters */ ++#define ELEM_ID_INTERWORKING 107 /* Interworking with External Network */ ++#define ELEM_ID_ADVERTISEMENT_PROTOCOL 108 /* Advertisement Protocol */ ++#define ELEM_ID_ROAMING_CONSORTIUM 111 /* Roaming Consortium */ ++#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ ++ ++#define ELEM_ID_VENDOR 221 /* Vendor specific IE */ ++#define ELEM_ID_WPA ELEM_ID_VENDOR /* WPA IE */ ++#define ELEM_ID_WMM ELEM_ID_VENDOR /* WMM IE */ ++#define ELEM_ID_P2P ELEM_ID_VENDOR /* WiFi Direct */ ++#define ELEM_ID_WFD ELEM_ID_VENDOR /* WiFi Direct */ ++#define ELEM_ID_WSC ELEM_ID_VENDOR /* WSC IE */ ++ ++#define ELEM_ID_RESERVED 255 /* Reserved */ ++ ++/* 7.3.2.1 SSID element */ ++#define ELEM_MAX_LEN_SSID 32 ++ ++/* 7.3.2.2 Supported Rates */ ++#define ELEM_MAX_LEN_SUP_RATES 8 ++ ++/* 7.3.2.4 DS Parameter Set */ ++#define ELEM_MAX_LEN_DS_PARAMETER_SET 1 ++ ++/* 7.3.2.5 CF Parameter Set */ ++#define ELEM_CF_PARM_LEN 8 ++ ++/* 7.3.2.6 TIM */ ++#define ELEM_MIX_LEN_TIM 4 ++#define ELEM_MAX_LEN_TIM 254 ++ ++/* 7.3.2.7 IBSS Parameter Set element */ ++#define ELEM_MAX_LEN_IBSS_PARAMETER_SET 2 ++ ++/* 7.3.2.8 Challenge Text element */ ++#define ELEM_MIN_LEN_CHALLENGE_TEXT 1 ++#define ELEM_MAX_LEN_CHALLENGE_TEXT 253 ++ ++/* 7.3.2.9 Country Information element */ ++/* Country IE should contain at least 3-bytes country code string and one subband triplet. */ ++#define ELEM_MIN_LEN_COUNTRY_INFO 6 ++ ++#define ELEM_ID_COUNTRY_INFO_TRIPLET_LEN_FIXED 3 ++#define ELEM_ID_COUNTRY_INFO_SUBBAND_TRIPLET_LEN_FIXED 3 ++#define ELEM_ID_COUNTRY_INFO_REGULATORY_TRIPLET_LEN_FIXED 3 ++ ++/* 7.3.2.13 ERP Information element */ ++#define ELEM_MAX_LEN_ERP 1 ++/* -- bits in the ERP Information element */ ++#define ERP_INFO_NON_ERP_PRESENT BIT(0) /* NonERP_Present bit */ ++#define ERP_INFO_USE_PROTECTION BIT(1) /* Use_Protection bit */ ++#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) /* Barker_Preamble_Mode bit */ ++ ++/* 7.3.2.14 Extended Supported Rates */ ++#define ELEM_MAX_LEN_EXTENDED_SUP_RATES 255 ++ ++#if CFG_SUPPORT_DFS ++/* 7.3.2.19 Supported Channels element */ ++#define ELEM_MAX_LEN_SUPPORTED_CHANNELS 7 ++#endif ++ ++/* 7.3.2.21 Measurement Request element */ ++#define ELEM_RM_TYPE_BASIC_REQ 0 ++#define ELEM_RM_TYPE_CCA_REQ 1 ++#define ELEM_RM_TYPE_RPI_HISTOGRAM_REQ 2 ++#define ELEM_RM_TYPE_CHNL_LOAD_REQ 3 ++#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REQ 4 ++#define ELEM_RM_TYPE_BEACON_REQ 5 ++#define ELEM_RM_TYPE_FRAME_REQ 6 ++#define ELEM_RM_TYPE_STA_STATISTICS_REQ 7 ++#define ELEM_RM_TYPE_LCI_REQ 8 ++#define ELEM_RM_TYPE_TS_REQ 9 ++#define ELEM_RM_TYPE_MEASURE_PAUSE_REQ 255 ++ ++/* 7.3.2.22 Measurement Report element */ ++#define ELEM_RM_TYPE_BASIC_REPORT 0 ++#define ELEM_RM_TYPE_CCA_REPORT 1 ++#define ELEM_RM_TYPE_RPI_HISTOGRAM_REPORT 2 ++#define ELEM_RM_TYPE_CHNL_LOAD_REPORT 3 ++#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REPORT 4 ++#define ELEM_RM_TYPE_BEACON_REPORT 5 ++#define ELEM_RM_TYPE_FRAME_REPORT 6 ++#define ELEM_RM_TYPE_STA_STATISTICS_REPORT 7 ++#define ELEM_RM_TYPE_LCI_REPORT 8 ++#define ELEM_RM_TYPE_TS_REPORT 9 ++/*Auto Channel Selection*/ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++#define ELEM_RM_TYPE_ACS_CHN 1 ++#define ELEM_RM_TYPE_LTE_CHN 2 ++#endif ++ ++/* 7.3.2.25 RSN information element */ ++#define ELEM_MAX_LEN_WPA 34 /* one pairwise, one AKM suite, one PMKID */ ++#define ELEM_MAX_LEN_RSN 38 /* one pairwise, one AKM suite, one PMKID */ ++#define ELEM_MAX_LEN_WAPI 38 /* one pairwise, one AKM suite, one BKID */ ++#define ELEM_MAX_LEN_WSC 200 /* one pairwise, one AKM suite, one BKID */ ++ ++#if CFG_SUPPORT_802_11W ++#define ELEM_WPA_CAP_MFPR BIT(6) ++#define ELEM_WPA_CAP_MFPC BIT(7) ++#endif ++ ++/* 7.3.2.27 Extended Capabilities information element */ ++#define ELEM_EXT_CAP_20_40_COEXIST_SUPPORT BIT(0) ++#define ELEM_EXT_CAP_PSMP_CAP BIT(4) ++#define ELEM_EXT_CAP_SERVICE_INTERVAL_GRANULARITY BIT(5) ++#define ELEM_EXT_CAP_SCHEDULE_PSMP BIT(6) ++ ++#define ELEM_EXT_CAP_BSS_TRANSITION_BIT 19 ++#define ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT 27 ++#define ELEM_EXT_CAP_INTERWORKING_BIT 31 ++#define ELEM_EXT_CAP_WNM_NOTIFICATION_BIT 46 ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#define ELEM_MAX_LEN_EXT_CAP (6) ++#else ++#define ELEM_MAX_LEN_EXT_CAP (3 - ELEM_HDR_LEN) ++#endif ++ ++/* 7.3.2.30 TSPEC element */ ++#define TS_INFO_TRAFFIC_TYPE_MASK BIT(0) /* WMM: 0 (Asynchronous TS of low-duty cycles) */ ++#define TS_INFO_TID_OFFSET 1 ++#define TS_INFO_TID_MASK BITS(1, 4) ++#define TS_INFO_DIRECTION_OFFSET 5 ++#define TS_INFO_DIRECTION_MASK BITS(5, 6) ++#define TS_INFO_ACCESS_POLICY_OFFSET 7 ++#define TS_INFO_ACCESS_POLICY_MASK BITS(7, 8) ++#define TS_INFO_AGGREGATION_MASK BIT(9) /* WMM: 0 */ ++#define TS_INFO_APSD_MASK BIT(10) ++#define TS_INFO_UP_OFFSET 11 ++#define TS_INFO_UP_MASK BITS(11, 13) ++#define TS_INFO_ACK_POLICY_OFFSET 14 ++#define TS_INFO_ACK_POLICY_MASK BITS(14, 15) ++#define TS_INFO_SCHEDULE_MASK 16 ++ ++/* 7.3.2.56 HT capabilities element */ ++#define ELEM_MAX_LEN_HT_CAP (28 - ELEM_HDR_LEN) /* sizeof(IE_HT_CAP_T)-2 */ ++ ++/* 7.3.2.56.2 HT capabilities Info field */ ++#define HT_CAP_INFO_LDPC_CAP BIT(0) ++#define HT_CAP_INFO_SUP_CHNL_WIDTH BIT(1) ++#define HT_CAP_INFO_SM_POWER_SAVE BITS(2, 3) ++#define HT_CAP_INFO_HT_GF BIT(4) ++#define HT_CAP_INFO_SHORT_GI_20M BIT(5) ++#define HT_CAP_INFO_SHORT_GI_40M BIT(6) ++#define HT_CAP_INFO_TX_STBC BIT(7) ++#define HT_CAP_INFO_RX_STBC BITS(8, 9) ++#define HT_CAP_INFO_HT_DELAYED_BA BIT(10) ++#define HT_CAP_INFO_MAX_AMSDU_LEN BIT(11) ++#define HT_CAP_INFO_DSSS_CCK_IN_40M BIT(12) ++#define HT_CAP_INFO_40M_INTOLERANT BIT(14) ++#define HT_CAP_INFO_LSIG_TXOP_SUPPORT BIT(15) ++ ++#define HT_CAP_INFO_RX_STBC_NO_SUPPORTED 0 ++#define HT_CAP_INFO_RX_STBC_1_SS BIT(8) ++#define HT_CAP_INFO_RX_STBC_2_SS BIT(9) ++#define HT_CAP_INFO_RX_STBC_3_SS HT_CAP_INFO_RX_STBC ++ ++/* 7.3.2.56.3 A-MPDU Parameters field */ ++#define AMPDU_PARAM_MAX_AMPDU_LEN_EXP BITS(0, 1) ++#define AMPDU_PARAM_MIN_START_SPACING BITS(2, 4) ++ ++#define AMPDU_PARAM_MAX_AMPDU_LEN_8K 0 ++#define AMPDU_PARAM_MAX_AMPDU_LEN_16K BIT(0) ++#define AMPDU_PARAM_MAX_AMPDU_LEN_32K BIT(1) ++#define AMPDU_PARAM_MAX_AMPDU_LEN_64K BITS(0, 1) ++ ++#define AMPDU_PARAM_MSS_NO_RESTRICIT 0 ++#define AMPDU_PARAM_MSS_1_4_US BIT(2) ++#define AMPDU_PARAM_MSS_1_2_US BIT(3) ++#define AMPDU_PARAM_MSS_1_US BITS(2, 3) ++#define AMPDU_PARAM_MSS_2_US BIT(4) ++#define AMPDU_PARAM_MSS_4_US (BIT(4) | BIT(2)) ++#define AMPDU_PARAM_MSS_8_US (BIT(4) | BIT(3)) ++#define AMPDU_PARAM_MSS_16_US BITS(2, 4) ++ ++/* 7.3.2.56.4 Supported MCS Set field (TX rate: octects 12~15) */ ++#define SUP_MCS_TX_SET_DEFINED BIT(0) ++#define SUP_MCS_TX_RX_SET_NOT_EQUAL BIT(1) ++#define SUP_MCS_TX_MAX_NUM_SS BITS(2, 3) ++#define SUP_MCS_TX_UNEQUAL_MODULATION BIT(4) ++ ++#define SUP_MCS_TX_MAX_NUM_1_SS 0 ++#define SUP_MCS_TX_MAX_NUM_2_SS BIT(2) ++#define SUP_MCS_TX_MAX_NUM_3_SS BIT(3) ++#define SUP_MCS_TX_MAX_NUM_4_SS BITS(2, 3) ++ ++#define SUP_MCS_RX_BITMASK_OCTET_NUM 10 ++#define SUP_MCS_RX_DEFAULT_HIGHEST_RATE 0 /* Not specify */ ++ ++/* 7.3.2.56.5 HT Extended Capabilities field */ ++#define HT_EXT_CAP_PCO BIT(0) ++#define HT_EXT_CAP_PCO_TRANSITION_TIME BITS(1, 2) ++#define HT_EXT_CAP_MCS_FEEDBACK BITS(8, 9) ++#define HT_EXT_CAP_HTC_SUPPORT BIT(10) ++#define HT_EXT_CAP_RD_RESPONDER BIT(11) ++ ++#define HT_EXT_CAP_PCO_TRANS_TIME_NONE 0 ++#define HT_EXT_CAP_PCO_TRANS_TIME_400US BIT(1) ++#define HT_EXT_CAP_PCO_TRANS_TIME_1_5MS BIT(2) ++#define HT_EXT_CAP_PCO_TRANS_TIME_5MS BITS(1, 2) ++ ++#define HT_EXT_CAP_MCS_FEEDBACK_NO_FB 0 ++#define HT_EXT_CAP_MCS_FEEDBACK_UNSOLICITED BIT(9) ++#define HT_EXT_CAP_MCS_FEEDBACK_BOTH BITS(8, 9) ++ ++/* 7.3.2.56.6 Transmit Beamforming Capabilities field */ ++ ++/* 7.3.2.56.7 Antenna Selection Capability field */ ++#define ASEL_CAP_CAPABLE BIT(0) ++#define ASEL_CAP_CSI_FB_BY_TX_ASEL_CAPABLE BIT(1) ++#define ASEL_CAP_ANT_INDICES_FB_BY_TX_ASEL_CAPABLE BIT(2) ++#define ASEL_CAP_EXPLICIT_CSI_FB_CAPABLE BIT(3) ++#define ASEL_CAP_ANT_INDICES_CAPABLE BIT(4) ++#define ASEL_CAP_RX_ASEL_CAPABLE BIT(5) ++#define ASEL_CAP_TX_SOUNDING_CAPABLE BIT(6) ++ ++/* 7.3.2.57 HT Operation element */ ++#define ELEM_MAX_LEN_HT_OP (24 - ELEM_HDR_LEN) /* sizeof(IE_HT_OP_T)-2 */ ++ ++#define HT_OP_INFO1_SCO BITS(0, 1) ++#define HT_OP_INFO1_STA_CHNL_WIDTH BIT(2) ++#define HT_OP_INFO1_RIFS_MODE BIT(3) ++ ++#define HT_OP_INFO2_HT_PROTECTION BITS(0, 1) ++#define HT_OP_INFO2_NON_GF_HT_STA_PRESENT BIT(2) ++#define HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT BIT(4) ++ ++#define HT_OP_INFO3_DUAL_BEACON BIT(6) ++#define HT_OP_INFO3_DUAL_CTS_PROTECTION BIT(7) ++#define HT_OP_INFO3_STBC_BEACON BIT(8) ++#define HT_OP_INFO3_LSIG_TXOP_FULL_SUPPORT BIT(9) ++#define HT_OP_INFO3_PCO_ACTIVE BIT(10) ++#define HT_OP_INFO3_PCO_PHASE BIT(11) ++ ++/* 7.3.2.59 OBSS Scan Parameter element */ ++#define ELEM_MAX_LEN_OBSS_SCAN (16 - ELEM_HDR_LEN) ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++#define ELEM_MAX_LEN_20_40_BSS_COEXIST (3 - ELEM_HDR_LEN) ++ ++#define BSS_COEXIST_INFO_REQ BIT(0) ++#define BSS_COEXIST_40M_INTOLERANT BIT(1) ++#define BSS_COEXIST_20M_REQ BIT(2) ++#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ BIT(3) ++#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_GRANT BIT(4) ++ ++/* 802.11u 7.3.2.92 Interworking IE */ ++#define ELEM_MAX_LEN_INTERWORKING (11 - ELEM_HDR_LEN) ++ ++/* 802.11u 7.3.2.93 Advertisement Protocol IE */ ++#define ELEM_MAX_LEN_ADV_PROTOCOL (4 - ELEM_HDR_LEN) ++ ++/* 802.11u 7.3.2.96 Roaming Consortium IE */ ++#define ELEM_MAX_LEN_ROAMING_CONSORTIUM (19 - ELEM_HDR_LEN) ++ ++#define IW_IE_LENGTH_ANO 1 ++#define IW_IE_LENGTH_ANO_VENUE 3 ++#define IW_IE_LENGTH_ANO_HESSID 7 ++#define IW_IE_LENGTH_ANO_VENUE_HESSID 9 ++ ++/* 3 Management frame body components (III): 7.4 Action frame format details. */ ++/* 7.4.1 Spectrum Measurement Action frame details */ ++#define ACTION_MEASUREMENT_REQ 0 /* Spectrum measurement request */ ++#define ACTION_MEASUREMENT_REPORT 1 /* Spectrum measurement report */ ++#define ACTION_TPC_REQ 2 /* TPC request */ ++#define ACTION_TPC_REPORT 3 /* TPC report */ ++#define ACTION_CHNL_SWITCH 4 /* Channel Switch Announcement */ ++ ++/* 7.4.2 QoS Action frame details */ ++#define ACTION_ADDTS_REQ 0 /* ADDTS request */ ++#define ACTION_ADDTS_RSP 1 /* ADDTS response */ ++#define ACTION_DELTS 2 /* DELTS */ ++#define ACTION_SCHEDULE 3 /* Schedule */ ++ ++#define ACTION_ADDTS_REQ_FRAME_LEN (24+3+63) /* WMM TSPEC IE: 63 */ ++#define ACTION_ADDTS_RSP_FRAME_LEN (24+4+63) /* WMM Status Code: 1; WMM TSPEC IE: 63 */ ++ ++/* 7.4.3 DLS Action frame details */ ++#define ACTION_DLS_REQ 0 /* DLS request */ ++#define ACTION_DLS_RSP 1 /* DLS response */ ++#define ACTION_DLS_TEARDOWN 2 /* DLS teardown */ ++ ++/* 7.4.4 Block ack Action frame details */ ++#define ACTION_ADDBA_REQ 0 /* ADDBA request */ ++#define ACTION_ADDBA_RSP 1 /* ADDBA response */ ++#define ACTION_DELBA 2 /* DELBA */ ++ ++#define ACTION_ADDBA_REQ_FRAME_LEN (24+9) ++#define ACTION_ADDBA_RSP_FRAME_LEN (24+9) ++ ++#define ACTION_DELBA_INITIATOR_MASK BIT(11) ++#define ACTION_DELBA_TID_MASK BITS(12, 15) ++#define ACTION_DELBA_TID_OFFSET 12 ++#define ACTION_DELBA_FRAME_LEN (24+6) ++ ++/* 7.4.6 Radio Measurement Action frame details */ ++#define ACTION_RM_REQ 0 /* Radio measurement request */ ++#define ACTION_RM_REPORT 1 /* Radio measurement report */ ++#define ACTION_LM_REQ 2 /* Link measurement request */ ++#define ACTION_LM_REPORT 3 /* Link measurement report */ ++#define ACTION_NEIGHBOR_REPORT_REQ 4 /* Neighbor report request */ ++#define ACTION_NEIGHBOR_REPORT_RSP 5 /* Neighbor report response */ ++ ++/* 7.4.7 Public Action frame details */ ++#define ACTION_PUBLIC_20_40_COEXIST 0 /* 20/40 BSS coexistence */ ++ ++#if CFG_SUPPORT_802_11W ++/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ ++#define ACTION_SA_QUERY_REQUEST 0 ++#define ACTION_SA_QUERY_RESPONSE 1 ++ ++#define ACTION_SA_QUERY_TR_ID_LEN 2 ++ ++/* Timeout Interval Type */ ++#define ACTION_SA_TIMEOUT_REASSOC_DEADLINE 1 ++#define ACTION_SA_TIMEOUT_KEY_LIFETIME 2 ++#define ACTION_SA_TIMEOUT_ASSOC_COMEBACK 3 ++#endif ++ ++/* 7.4.10.1 HT action frame details */ ++#define ACTION_HT_NOTIFY_CHANNEL_WIDTH 0 /* Notify Channel Width */ ++#define ACTION_HT_SM_POWER_SAVE 1 /* SM Power Save */ ++#define ACTION_HT_PSMP 2 /* PSMP */ ++#define ACTION_HT_SET_PCO_PHASE 3 /* Set PCO Phase */ ++#define ACTION_HT_CSI 4 /* CSI */ ++#define ACTION_HT_NON_COMPRESSED_BEAMFORM 5 /* Non-compressed Beamforming */ ++#define ACTION_HT_COMPRESSED_BEAMFORM 6 /* Compressed Beamforming */ ++#define ACTION_HT_ANT_SEL_INDICES_FB 7 /* Antenna Selection Indices Feedback */ ++ ++/* 802.11v Wireless Network Management */ ++#define ACTION_WNM_TIMING_MEASUREMENT_REQUEST 27 ++ ++#define ACTION_UNPROTECTED_WNM_TIM 0 ++#define ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT 1 ++ ++#define ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN 12 ++ ++/* 3 --------------- WFA frame body fields --------------- */ ++#define VENDOR_OUI_WFA { 0x00, 0x50, 0xF2 } ++#define VENDOR_OUI_WFA_SPECIFIC { 0x50, 0x6F, 0x9A } ++#define VENDOR_OUI_TYPE_WPA 1 ++#define VENDOR_OUI_TYPE_WMM 2 ++#define VENDOR_OUI_TYPE_WPS 4 ++#define VENDOR_OUI_TYPE_P2P 9 ++#define VENDOR_OUI_TYPE_WFD 10 ++#define VENDOR_OUI_TYPE_HS20 16 ++ ++#define VENDOR_OUI_TYPE_LEN 4 /* Length of OUI and Type */ ++ ++/* VERSION(2 octets for WPA) / SUBTYPE(1 octet)-VERSION(1 octet) fields for WMM in WFA IE */ ++#define VERSION_WPA 0x0001 /* Little Endian Format */ ++#define VENDOR_OUI_SUBTYPE_VERSION_WMM_INFO 0x0100 ++#define VENDOR_OUI_SUBTYPE_VERSION_WMM_PARAM 0x0101 ++ ++/* SUBTYPE(1 octet) for WMM */ ++#define VENDOR_OUI_SUBTYPE_WMM_INFO 0x00 /* WMM Spec version 1.1 */ ++#define VENDOR_OUI_SUBTYPE_WMM_PARAM 0x01 ++#define VENDOR_OUI_SUBTYPE_WMM_TSPEC 0x02 ++ ++/* VERSION(1 octet) for WMM */ ++#define VERSION_WMM 0x01 /* WMM Spec version 1.1 */ ++ ++/* WMM-2.1.6 QoS Control Field */ ++#define WMM_QC_UP_MASK BITS(0, 2) ++#define WMM_QC_EOSP BIT(4) ++#define WMM_QC_ACK_POLICY_MASK BITS(5, 6) ++#define WMM_QC_ACK_POLICY_OFFSET 5 ++#define WMM_QC_ACK_POLICY_ACKNOWLEDGE 0 ++#define WMM_QC_ACK_POLICY_NOT_ACKNOWLEDGE (1 << WMM_QC_ACK_POLICY_OFFSET) ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE 6 ++ ++/* HOTSPOT 2.0 Indication IE*/ ++#define ELEM_MAX_LEN_HS20_INDICATION 5 ++#define ELEM_MIN_LEN_HS20_INDICATION 4 ++ ++/* Hotspot Configuration*/ ++#define ELEM_HS_CONFIG_DGAF_DISABLED_MASK BIT(0) /* Downstream Group-Addressed Forwarding */ ++ ++/* 3 Control frame body */ ++/* 7.2.1.7 BlockAckReq */ ++#define CTRL_BAR_BAR_CONTROL_OFFSET 16 ++#define CTRL_BAR_BAR_INFORMATION_OFFSET 18 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack(1) ++#endif ++ ++typedef struct _LLC_SNAP_HEADER_T { ++ UINT_8 ucDSAP; ++ UINT_8 ucSSAP; ++ UINT_8 ucControl; ++ UINT_8 aucCode[3]; ++ UINT_16 u2Type; ++} __KAL_ATTRIB_PACKED__ LLC_SNAP_HEADER_T, *P_LLC_SNAP_HEADER_T; ++ ++/* 3 MAC Header. */ ++/* Ethernet Frame Header */ ++typedef struct _ETH_FRAME_HEADER_T { ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_16 u2TypeLen; ++} __KAL_ATTRIB_PACKED__ ETH_FRAME_HEADER_T, *P_ETH_FRAME_HEADER_T; ++ ++/* Ethernet Frame Structure */ ++typedef struct _ETH_FRAME_T { ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_16 u2TypeLen; ++ UINT_8 aucData[1]; ++} __KAL_ATTRIB_PACKED__ ETH_FRAME_T, *P_ETH_FRAME_T; ++ ++/* IEEE 802.11 WLAN Frame Structure */ ++/* WLAN MAC Header (without Address 4 and QoS Control fields) */ ++typedef struct _WLAN_MAC_HEADER_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_T, *P_WLAN_MAC_HEADER_T; ++ ++/* WLAN MAC Header (QoS Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_QOS_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_16 u2QosCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_QOS_T, *P_WLAN_MAC_HEADER_QOS_T; ++ ++/* WLAN MAC Header (HT Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_16 u2QosCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_HT_T, *P_WLAN_MAC_HEADER_HT_T; ++ ++/* WLAN MAC Header (Address 4 included) */ ++typedef struct _WLAN_MAC_HEADER_A4_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_T, *P_WLAN_MAC_HEADER_A4_T; ++ ++/* WLAN MAC Header (Address 4 and QoS Control fields included) */ ++typedef struct _WLAN_MAC_HEADER_A4_QOS_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++ UINT_16 u2QosCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_QOS_T, *P_WLAN_MAC_HEADER_A4_QOS_T; ++ ++typedef struct _WLAN_MAC_HEADER_A4_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_8 aucAddr4[MAC_ADDR_LEN]; ++ UINT_16 u2QosCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_HT_T, *P_WLAN_MAC_HEADER_A4_HT_T; ++ ++/* 7.2.3 WLAN MAC Header for Management Frame - MMPDU */ ++typedef struct _WLAN_MAC_MGMT_HEADER_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2Duration; ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_T, *P_WLAN_MAC_MGMT_HEADER_T; ++ ++/* WLAN MAC Header for Management Frame (HT Control fields included) */ ++typedef struct _WLAN_MAC_MGMT_HEADER_HT_T { ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2DurationID; ++ UINT_8 aucAddr1[MAC_ADDR_LEN]; ++ UINT_8 aucAddr2[MAC_ADDR_LEN]; ++ UINT_8 aucAddr3[MAC_ADDR_LEN]; ++ UINT_16 u2SeqCtrl; ++ UINT_32 u4HtCtrl; ++} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_HT_T, *P_WLAN_MAC_MGMT_HEADER_HT_T; ++ ++/* 3 WLAN CONTROL Frame */ ++/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ ++typedef struct _CTRL_PSPOLL_FRAME_T { ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2AID; /* AID */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_8 aucTA[MAC_ADDR_LEN]; /* TA */ ++} __KAL_ATTRIB_PACKED__ CTRL_PSPOLL_FRAME_T, *P_CTRL_PSPOLL_FRAME_T; ++ ++/* BAR */ ++typedef struct _CTRL_BAR_FRAME_T { ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* RA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* TA */ ++ UINT_16 u2BarControl; ++ UINT_8 aucBarInfo[2]; /* Variable size */ ++} __KAL_ATTRIB_PACKED__ CTRL_BAR_FRAME_T, *P_CTRL_BAR_FRAME_T; ++ ++/* 3 WLAN Management Frame. */ ++/* 7.2.3.1 WLAN Management Frame - Beacon Frame */ ++typedef struct _WLAN_BEACON_FRAME_T { ++ /* Beacon header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ ++} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_T, *P_WLAN_BEACON_FRAME_T; ++ ++typedef struct _WLAN_BEACON_FRAME_BODY_T { ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ ++} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_BODY_T, *P_WLAN_BEACON_FRAME_BODY_T; ++ ++/* 7.2.3.3 WLAN Management Frame - Disassociation Frame */ ++typedef struct _WLAN_DISASSOC_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Disassociation frame body */ ++ UINT_16 u2ReasonCode; /* Reason code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ ++} __KAL_ATTRIB_PACKED__ WLAN_DISASSOC_FRAME_T, *P_WLAN_DISASSOC_FRAME_T; ++ ++/* 7.2.3.4 WLAN Management Frame - Association Request frame */ ++typedef struct _WLAN_ASSOC_REQ_FRAME_T { ++ /* Association Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Association Request frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2ListenInterval; /* Listen interval */ ++ UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ ++} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_REQ_FRAME_T, *P_WLAN_ASSOC_REQ_FRAME_T; ++ ++/* 7.2.3.5 WLAN Management Frame - Association Response frame */ ++typedef struct _WLAN_ASSOC_RSP_FRAME_T { ++ /* Association Response MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Association Response frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2StatusCode; /* Status code */ ++ UINT_16 u2AssocId; /* Association ID */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ supported rates, and etc. */ ++} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_RSP_FRAME_T, *P_WLAN_ASSOC_RSP_FRAME_T; ++ ++/* 7.2.3.6 WLAN Management Frame - Reassociation Request frame */ ++typedef struct _WLAN_REASSOC_REQ_FRAME_T { ++ /* Reassociation Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Reassociation Request frame body */ ++ UINT_16 u2CapInfo; /* Capability information */ ++ UINT_16 u2ListenInterval; /* Listen interval */ ++ UINT_8 aucCurrentAPAddr[MAC_ADDR_LEN]; /* Current AP address */ ++ UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ ++} __KAL_ATTRIB_PACKED__ WLAN_REASSOC_REQ_FRAME_T, *P_WLAN_REASSOC_REQ_FRAME_T; ++ ++/* 7.2.3.7 WLAN Management Frame - Reassociation Response frame ++ (the same as Association Response frame) */ ++typedef WLAN_ASSOC_RSP_FRAME_T WLAN_REASSOC_RSP_FRAME_T, *P_WLAN_REASSOC_RSP_FRAME_T; ++ ++/* 7.2.3.9 WLAN Management Frame - Probe Response Frame */ ++typedef WLAN_BEACON_FRAME_T WLAN_PROBE_RSP_FRAME_T, *P_WLAN_PROBE_RSP_FRAME_T; ++ ++/* 7.2.3.10 WLAN Management Frame - Authentication Frame */ ++typedef struct _WLAN_AUTH_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Authentication frame body */ ++ UINT_16 u2AuthAlgNum; /* Authentication algorithm number */ ++ UINT_16 u2AuthTransSeqNo; /* Authentication transaction sequence number */ ++ UINT_16 u2StatusCode; /* Status code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs for Fast BSS Transition */ ++} __KAL_ATTRIB_PACKED__ WLAN_AUTH_FRAME_T, *P_WLAN_AUTH_FRAME_T; ++ ++/* 7.2.3.11 WLAN Management Frame - Deauthentication Frame */ ++typedef struct _WLAN_DEAUTH_FRAME_T { ++ /* Authentication MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Deauthentication frame body */ ++ UINT_16 u2ReasonCode; /* Reason code */ ++ UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ ++} __KAL_ATTRIB_PACKED__ WLAN_DEAUTH_FRAME_T, *P_WLAN_DEAUTH_FRAME_T; ++ ++/* 3 Information Elements. */ ++/* 7.3.2 Generic element format */ ++typedef struct _IE_HDR_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucInfo[1]; ++} __KAL_ATTRIB_PACKED__ IE_HDR_T, *P_IE_HDR_T; ++ ++/* 7.3.2.1 SSID element */ ++typedef struct _IE_SSID_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++} __KAL_ATTRIB_PACKED__ IE_SSID_T, *P_IE_SSID_T; ++ ++/* 7.3.2.2 Supported Rates element */ ++typedef struct _IE_SUPPORTED_RATE_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES]; ++} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_T, *P_IE_SUPPORTED_RATE_T; ++ ++/* 7.3.2.4 DS Parameter Set element */ ++typedef struct _IE_DS_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCurrChnl; ++} __KAL_ATTRIB_PACKED__ IE_DS_PARAM_SET_T, *P_IE_DS_PARAM_SET_T; ++ ++/* 7.3.2.5 CF Parameter Set element */ ++typedef struct _IE_CF_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCFPCount; ++ UINT_8 ucCFPPeriod; ++ UINT_16 u2CFPMaxDur; ++ UINT_16 u2DurRemaining; ++} __KAL_ATTRIB_PACKED__ IE_CF_PARAM_SET_T, *P_IE_CF_PARAM_SET_T; ++ ++/* 7.3.2.6 TIM */ ++typedef struct _IE_TIM_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucDTIMCount; ++ UINT_8 ucDTIMPeriod; ++ UINT_8 ucBitmapControl; ++ UINT_8 aucPartialVirtualMap[1]; ++} __KAL_ATTRIB_PACKED__ IE_TIM_T, *P_IE_TIM_T; ++ ++/* 7.3.2.7 IBSS Parameter Set element */ ++typedef struct _IE_IBSS_PARAM_SET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2ATIMWindow; ++} __KAL_ATTRIB_PACKED__ IE_IBSS_PARAM_SET_T, *P_IE_IBSS_PARAM_SET_T; ++ ++/* 7.3.2.8 Challenge Text element */ ++typedef struct _IE_CHALLENGE_TEXT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucChallengeText[ELEM_MAX_LEN_CHALLENGE_TEXT]; ++} __KAL_ATTRIB_PACKED__ IE_CHALLENGE_TEXT_T, *P_IE_CHALLENGE_TEXT_T; ++ ++/* 7.3.2.9 Country information element */ ++#if CFG_SUPPORT_802_11D ++/*! \brief COUNTRY_INFO_TRIPLET is defined for the COUNTRY_INFO_ELEM structure. */ ++typedef struct _COUNTRY_INFO_TRIPLET_T { ++ UINT_8 ucParam1; /*!< If param1 >= 201, this triplet is referred to as ++ Regulatory Triplet in 802_11J. */ ++ UINT_8 ucParam2; ++ UINT_8 ucParam3; ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_TRIPLET_T, *P_COUNTRY_INFO_TRIPLET_T; ++ ++typedef struct _COUNTRY_INFO_SUBBAND_TRIPLET_T { ++ UINT_8 ucFirstChnlNum; /*!< First Channel Number */ ++ UINT_8 ucNumOfChnl; /*!< Number of Channels */ ++ INT_8 cMaxTxPwrLv; /*!< Maximum Transmit Power Level */ ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_SUBBAND_TRIPLET_T, *P_COUNTRY_INFO_SUBBAND_TRIPLET_T; ++ ++typedef struct _COUNTRY_INFO_REGULATORY_TRIPLET_T { ++ UINT_8 ucRegExtId; /*!< Regulatory Extension Identifier, should ++ be greater than or equal to 201 */ ++ UINT_8 ucRegClass; /*!< Regulatory Class */ ++ UINT_8 ucCoverageClass; /*!< Coverage Class, unsigned 1-octet value 0~31 ++ , 32~255 reserved */ ++} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_REGULATORY_TRIPLET_T, *P_COUNTRY_INFO_REGULATORY_TRIPLET_T; ++ ++typedef struct _IE_COUNTRY_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCountryStr[3]; ++ COUNTRY_INFO_SUBBAND_TRIPLET_T arCountryStr[1]; ++} __KAL_ATTRIB_PACKED__ IE_COUNTRY_T, *P_IE_COUNTRY_T; ++#endif /* CFG_SUPPORT_802_11D */ ++ ++/* 7.3.2.13 ERP element */ ++typedef struct _IE_ERP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucERP; ++} __KAL_ATTRIB_PACKED__ IE_ERP_T, *P_IE_ERP_T; ++ ++/* 7.3.2.14 Extended Supported Rates element */ ++typedef struct _IE_EXT_SUPPORTED_RATE_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucExtSupportedRates[ELEM_MAX_LEN_EXTENDED_SUP_RATES]; ++} __KAL_ATTRIB_PACKED__ IE_EXT_SUPPORTED_RATE_T, *P_IE_EXT_SUPPORTED_RATE_T; ++ ++/* 7.3.2.15 Power Constraint element */ ++typedef struct _IE_POWER_CONSTRAINT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucLocalPowerConstraint; /* Unit: dBm */ ++} __KAL_ATTRIB_PACKED__ IE_POWER_CONSTRAINT_T, *P_IE_POWER_CONSTRAINT_T; ++ ++/* 7.3.2.16 Power Capability element */ ++typedef struct _IE_POWER_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ INT_8 cMinTxPowerCap; /* Unit: dBm */ ++ INT_8 cMaxTxPowerCap; /* Unit: dBm */ ++} __KAL_ATTRIB_PACKED__ IE_POWER_CAP_T, *P_IE_POWER_CAP_T; ++ ++/* 7.3.2.17 TPC request element */ ++typedef struct _IE_TPC_REQ_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++} __KAL_ATTRIB_PACKED__ IE_TPC_REQ_T, *P_IE_TPC_REQ_T; ++ ++/* 7.3.2.18 TPC report element */ ++typedef struct _IE_TPC_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ INT_8 cTxPower; /* Unit: dBm */ ++ INT_8 cLinkMargin; /* Unit: dB */ ++} __KAL_ATTRIB_PACKED__ IE_TPC_REPORT_T, *P_IE_TPC_REPORT_T; ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++/* 7.3.2.19 Supported Channels element*/ ++typedef struct _IE_SUPPORTED_CHANNELS_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucChannelNum[ELEM_MAX_LEN_SUPPORTED_CHANNELS * 2]; ++} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_CHANNELS_T, *P_IE_SUPPORTED_CHANNELS_T; ++ ++/* 7.3.2.20 Channel Switch Announcement element*/ ++typedef struct _IE_CHANNEL_SWITCH_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucChannelSwitchMode; ++ UINT_8 ucNewChannelNum; ++ UINT_8 ucChannelSwitchCount; ++} __KAL_ATTRIB_PACKED__ IE_CHANNEL_SWITCH_T, *P_IE_CHANNEL_SWITCH_T; ++#endif ++ ++/* 7.3.2.21 Measurement Request element */ ++typedef struct _IE_MEASUREMENT_REQ_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucToken; ++ UINT_8 ucRequestMode; ++ UINT_8 ucMeasurementType; ++ UINT_8 aucRequestFields[1]; ++} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REQ_T, *P_IE_MEASUREMENT_REQ_T; ++ ++typedef struct _SM_BASIC_REQ_T { ++ UINT_8 ucChannel; ++ UINT_32 au4StartTime[2]; ++ UINT_16 u2Duration; ++} __KAL_ATTRIB_PACKED__ SM_BASIC_REQ_T, *P_SM_BASIC_REQ_T; ++ ++/* SM_COMMON_REQ_T is not specified in Spec. Use it as common structure of SM */ ++typedef SM_BASIC_REQ_T SM_REQ_COMMON_T, *P_SM_REQ_COMMON_T; ++typedef SM_BASIC_REQ_T SM_CCA_REQ_T, *P_SM_CCA_REQ_T; ++typedef SM_BASIC_REQ_T SM_RPI_HISTOGRAM_REQ_T, *P_SM_RPI_HISTOGRAM_REQ_T; ++ ++typedef struct _RM_CHNL_LOAD_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REQ_T, *P_RM_CHNL_LOAD_REQ_T; ++ ++typedef RM_CHNL_LOAD_REQ_T RM_NOISE_HISTOGRAM_REQ_T, *P_RM_NOISE_HISTOGRAM_REQ_T; ++ ++typedef struct _RM_BCN_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucMeasurementMode; ++ UINT_8 aucBssid[6]; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_BCN_REQ_T, *P_RM_BCN_REQ_T; ++ ++typedef struct _RM_FRAME_REQ_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucFrameReqType; ++ UINT_8 aucMacAddr[6]; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_FRAME_REQ_T, *P_RM_FRAME_REQ_T; ++ ++typedef struct _RM_STA_STATS_REQ_T { ++ UINT_8 aucPeerMacAddr[6]; ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 ucGroupID; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_STA_STATS_REQ_T, *P_RM_STA_STATS_REQ_T; ++ ++typedef struct _RM_LCI_REQ_T { ++ UINT_8 ucLocationSubject; ++ UINT_8 ucLatitudeResolution; ++ UINT_8 ucLongitudeResolution; ++ UINT_8 ucAltitudeResolution; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_LCI_REQ_T, *P_RM_LCI_REQ_T; ++ ++typedef struct _RM_TS_MEASURE_REQ_T { ++ UINT_16 u2RandomInterval; ++ UINT_16 u2Duration; ++ UINT_8 aucPeerStaAddr[6]; ++ UINT_8 ucTrafficID; ++ UINT_8 ucBin0Range; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_TS_MEASURE_REQ_T, *P_RM_TS_MEASURE_REQ_T; ++ ++typedef struct _RM_MEASURE_PAUSE_REQ_T { ++ UINT_16 u2PauseTime; ++ UINT_8 aucSubElements[1]; ++} __KAL_ATTRIB_PACKED__ RM_MEASURE_PAUSE_REQ_T, *P_RM_MEASURE_PAUSE_REQ_T; ++ ++/* 7.3.2.22 Measurement Report element */ ++typedef struct _IE_MEASUREMENT_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucToken; ++ UINT_8 ucReportMode; ++ UINT_8 ucMeasurementType; ++ UINT_8 aucReportFields[1]; ++} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REPORT_T, *P_IE_MEASUREMENT_REPORT_T; ++ ++typedef struct _SM_BASIC_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucMap; ++} __KAL_ATTRIB_PACKED__ SM_BASIC_REPORT_T, *P_SM_BASIC_REPORT_T; ++ ++typedef struct _SM_CCA_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucCcaBusyFraction; ++} __KAL_ATTRIB_PACKED__ SM_CCA_REPORT_T, *P_SM_CCA_REPORT_T; ++ ++typedef struct _SM_RPI_REPORT_T { ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 aucRPI[8]; ++} __KAL_ATTRIB_PACKED__ SM_RPI_REPORT_T, *P_SM_RPI_REPORT_T; ++ ++typedef struct _RM_CHNL_LOAD_REPORT_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucChnlLoad; ++} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REPORT_T, *P_RM_CHNL_LOAD_REPORT_T; ++ ++typedef struct _RM_IPI_REPORT_T { ++ UINT_8 ucRegulatoryClass; ++ UINT_8 ucChannel; ++ UINT_32 u4StartTime[2]; ++ UINT_16 u2Duration; ++ UINT_8 ucAntennaId; ++ INT_8 cANPI; ++ UINT_8 aucIPI[11]; ++} __KAL_ATTRIB_PACKED__ RM_IPI_REPORT_T, *P_RM_IPI_REPORT_T; ++ ++/* 7.3.2.23 Quiet element */ ++typedef struct _IE_QUIET_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCount; ++ UINT_8 ucPeriod; ++ UINT_16 u2Duration; ++ UINT_16 u2Offset; ++} __KAL_ATTRIB_PACKED__ IE_QUIET_T, *P_IE_QUIET_T; ++ ++/* 7.3.2.27 Extended Capabilities element */ ++typedef struct _IE_EXT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCapabilities[5]; ++} __KAL_ATTRIB_PACKED__ IE_EXT_CAP_T, *P_EXT_CAP_T; ++ ++/* 7.3.2.27 hs20 Extended Capabilities element */ ++typedef struct _IE_HS20_EXT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCapabilities[6]; ++} __KAL_ATTRIB_PACKED__ IE_HS20_EXT_CAP_T, *P_HS20_EXT_CAP_T; ++ ++ ++/* 7.3.2.27 Extended Capabilities element */ ++typedef struct _IE_RRM_ENABLED_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucCap[5]; ++} __KAL_ATTRIB_PACKED__ IE_RRM_ENABLED_CAP_T, *P_IE_RRM_ENABLED_CAP_T; ++ ++/* 7.3.2.51 Timeout Interval element (TIE) */ ++typedef struct _IE_TIMEOUT_INTERVAL_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++#define IE_TIMEOUT_INTERVAL_TYPE_RESERVED 0 ++#define IE_TIMEOUT_INTERVAL_TYPE_REASSOC 1 ++#define IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME 2 ++#define IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK 3 ++ UINT_8 ucType; ++ UINT_32 u4Value; ++} __KAL_ATTRIB_PACKED__ IE_TIMEOUT_INTERVAL_T; ++ ++/* 7.3.2.56 HT Capabilities element */ ++typedef struct _SUP_MCS_SET_FIELD { ++ UINT_8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; ++ UINT_16 u2RxHighestSupportedRate; ++ UINT_32 u4TxRateInfo; ++} __KAL_ATTRIB_PACKED__ SUP_MCS_SET_FIELD, *P_SUP_MCS_SET_FIELD; ++ ++typedef struct _IE_HT_CAP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2HtCapInfo; ++ UINT_8 ucAmpduParam; ++ SUP_MCS_SET_FIELD rSupMcsSet; ++ UINT_16 u2HtExtendedCap; ++ UINT_32 u4TxBeamformingCap; ++ UINT_8 ucAselCap; ++} __KAL_ATTRIB_PACKED__ IE_HT_CAP_T, *P_IE_HT_CAP_T; ++ ++/* 7.3.2.57 HT Operation element */ ++typedef struct _IE_HT_OP_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucInfo1; ++ UINT_16 u2Info2; ++ UINT_16 u2Info3; ++ UINT_8 aucBasicMcsSet[16]; ++} __KAL_ATTRIB_PACKED__ IE_HT_OP_T, *P_IE_HT_OP_T; ++ ++/* 7.3.2.25 RSN Information element format */ ++typedef struct _RSN_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2PairwiseKeyCipherSuiteCount; ++ UCHAR aucPairwiseKeyCipherSuite1[4]; ++} __KAL_ATTRIB_PACKED__ RSN_INFO_ELEM_T, *P_RSN_INFO_ELEM_T; ++ ++/* 7.3.2.26 WPA Information element format */ ++typedef struct _WPA_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UCHAR aucOui[3]; ++ UCHAR ucOuiType; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2PairwiseKeyCipherSuiteCount; ++ UCHAR aucPairwiseKeyCipherSuite1[4]; ++} __KAL_ATTRIB_PACKED__ WPA_INFO_ELEM_T, *P_WPA_INFO_ELEM_T; ++ ++/* 7.3.2.58 20/40 BSS Intolerant Channel Report element */ ++typedef struct _IE_INTOLERANT_CHNL_REPORT_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucRegulatoryClass; ++ UINT_8 aucChannelList[1]; ++} __KAL_ATTRIB_PACKED__ IE_INTOLERANT_CHNL_REPORT_T, *P_IE_INTOLERANT_CHNL_REPORT_T; ++ ++/* 7.3.2.59 OBSS Scan Parameters element */ ++typedef struct _IE_OBSS_SCAN_PARAM_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_16 u2ScanPassiveDwell; ++ UINT_16 u2ScanActiveDwell; ++ UINT_16 u2TriggerScanInterval; ++ UINT_16 u2ScanPassiveTotalPerChnl; ++ UINT_16 u2ScanActiveTotalPerChnl; ++ UINT_16 u2WidthTransDelayFactor; ++ UINT_16 u2ScanActivityThres; ++} __KAL_ATTRIB_PACKED__ IE_OBSS_SCAN_PARAM_T, *P_IE_OBSS_SCAN_PARAM_T; ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++typedef struct _IE_20_40_COEXIST_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucData; ++} __KAL_ATTRIB_PACKED__ IE_20_40_COEXIST_T, *P_IE_20_40_COEXIST_T; ++ ++/* 7.3.2.60 20/40 BSS Coexistence element */ ++typedef struct _IE_SUP_OPERATING_CLASS_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 ucCur; ++ UINT_8 ucSup[255]; ++} __KAL_ATTRIB_PACKED__ IE_SUP_OPERATING_CLASS_T, *P_IE_SUP_OPERATING_CLASS_T; ++ ++/* 3 7.4 Action Frame. */ ++/* 7.4 Action frame format */ ++typedef struct _WLAN_ACTION_FRAME { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucActionDetails[1]; /* Action details */ ++} __KAL_ATTRIB_PACKED__ WLAN_ACTION_FRAME, *P_WLAN_ACTION_FRAME; ++ ++/* 7.4.1.1 Spectrum Measurement Request frame format */ ++typedef struct _ACTION_SM_REQ_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Information elements */ ++} __KAL_ATTRIB_PACKED__ ACTION_SM_REQ_FRAME, *P_ACTION_SM_REQ_FRAME; ++ ++/* 7.4.1.2 Spectrum Measurement Report frame format */ ++typedef ACTION_SM_REQ_FRAME ACTION_SM_REPORT_FRAME, *P_ACTION_SM_REPORT_FRAME; ++ ++/* 7.4.1.5 Channel Switch Announcement frame format */ ++typedef struct _ACTION_CHANNEL_SWITCH_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 aucInfoElem[5]; /* Information elements */ ++} __KAL_ATTRIB_PACKED__ _ACTION_CHANNEL_SWITCH_FRAME, *P_ACTION_CHANNEL_SWITCH_FRAME; ++ ++/* 7.4.2.1 ADDTS Request frame format */ ++typedef struct _ACTION_ADDTS_REQ_FRAME { ++ /* ADDTS Request MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ TS Delay, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_REQ_FRAME, *P_ACTION_ADDTS_REQ_FRAME; ++ ++/* 7.4.2.2 ADDTS Response frame format */ ++typedef struct _ACTION_ADDTS_RSP_FRAME { ++ /* ADDTS Response MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* ADDTS Response frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucStatusCode; /* WMM Status Code is of one byte */ ++ UINT_8 aucInfoElem[1]; /* Information elements, such as ++ TS Delay, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_RSP_FRAME, *P_ACTION_ADDTS_RSP_FRAME; ++ ++/* 7.4.2.3 DELTS frame format */ ++typedef struct _ACTION_DELTS_FRAME { ++ /* DELTS MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* DELTS frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 aucTsInfo[3]; /* TS Info */ ++} __KAL_ATTRIB_PACKED__ ACTION_DELTS_FRAME, *P_ACTION_DELTS_FRAME; ++ ++/* 7.4.4.1 ADDBA Request frame format */ ++typedef struct _ACTION_ADDBA_REQ_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ ++ UINT_8 aucBATimeoutValue[2]; ++ UINT_8 aucBAStartSeqCtrl[2]; /* SSN */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_FRAME_T, *P_ACTION_ADDBA_REQ_FRAME_T; ++ ++typedef struct _ACTION_ADDBA_REQ_BODY_T { ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++ UINT_16 u2BAStartSeqCtrl; /* SSN */ ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_BODY_T, *P_ACTION_ADDBA_REQ_BODY_T; ++ ++/* 7.4.4.2 ADDBA Response frame format */ ++typedef struct _ACTION_ADDBA_RSP_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_8 aucStatusCode[2]; ++ UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ ++ UINT_8 aucBATimeoutValue[2]; ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_FRAME_T, *P_ACTION_ADDBA_RSP_FRAME_T; ++ ++typedef struct _ACTION_ADDBA_RSP_BODY_T { ++ UINT_16 u2StatusCode; ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_BODY_T, *P_ACTION_ADDBA_RSP_BODY_T; ++ ++/* 7.4.4.3 DELBA frame format */ ++typedef struct _ACTION_DELBA_FRAME_T { ++ /* Action MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2DurationID; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Action frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_16 u2DelBaParameterSet; /* Bit 11 Initiator, Bits 12-15 TID */ ++ UINT_16 u2ReasonCode; /* 7.3.1.7 */ ++} __KAL_ATTRIB_PACKED__ ACTION_DELBA_FRAME_T, *P_ACTION_DELBA_FRAME_T; ++ ++/* 7.4.6.1 Radio Measurement Request frame format */ ++typedef struct _ACTION_RM_REQ_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Radio Measurement Request frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_16 u2Repetitions; /* Number of repetitions */ ++ UINT_8 aucInfoElem[1]; /* Measurement Request elements, such as ++ channel load request, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_RM_REQ_FRAME, *P_ACTION_RM_REQ_FRAME; ++ ++/* 7.4.6.2 Radio Measurement Report frame format */ ++typedef struct _ACTION_RM_REPORT_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Radio Measurement Report frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 aucInfoElem[1]; /* Measurement Report elements, such as ++ channel load report, and etc. */ ++} __KAL_ATTRIB_PACKED__ ACTION_RM_REPORT_FRAME, *P_ACTION_RM_REPORT_FRAME; ++ ++/* 7.4.7.1a 20/40 BSS Coexistence Management frame format */ ++typedef struct _ACTION_20_40_COEXIST_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ ++ IE_20_40_COEXIST_T rBssCoexist; /* 20/40 BSS coexistence element */ ++ IE_INTOLERANT_CHNL_REPORT_T rChnlReport; /* Intolerant channel report */ ++ ++} __KAL_ATTRIB_PACKED__ ACTION_20_40_COEXIST_FRAME, *P_ACTION_20_40_COEXIST_FRAME; ++ ++#if CFG_SUPPORT_802_11W ++/* 7.4.9 SA Query Management frame format */ ++typedef struct _ACTION_SA_QUERY_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ ++ UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; /* Transaction id */ ++ ++} __KAL_ATTRIB_PACKED__ ACTION_SA_QUERY_FRAME, *P_ACTION_SA_QUERY_FRAME; ++#endif ++ ++/* 7.4.10 Notify Channel Width Management frame format */ ++typedef struct _ACTION_NOTIFY_CHNL_WIDTH_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* BSS Coexistence Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucChannelWidth; /* Channel Width */ ++} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHNL_WIDTH_FRAME, *P_ACTION_NOTIFY_CHNL_WIDTH_FRAME; ++ ++/* 802.11v Wireless Network Management: Timing Measurement Request */ ++typedef struct _ACTION_WNM_TIMING_MEAS_REQ_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Timing Measurement Request Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucTrigger; /* Trigger */ ++} __KAL_ATTRIB_PACKED__ ACTION_WNM_TIMING_MEAS_REQ_FRAME, *P_ACTION_WNM_TIMING_MEAS_REQ_FRAME; ++ ++/* 802.11v Wireless Network Management: Timing Measurement */ ++typedef struct _ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* Timing Measurement Management frame body */ ++ UINT_8 ucCategory; /* Category */ ++ UINT_8 ucAction; /* Action Value */ ++ UINT_8 ucDialogToken; /* Dialog Token */ ++ UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ ++ UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ ++ UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ ++ UINT_8 ucMaxToDErr; /* Maximum of ToD Error [10ns] */ ++ UINT_8 ucMaxToAErr; /* Maximum of ToA Error [10ns] */ ++} __KAL_ATTRIB_PACKED__ ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME, *P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME; ++ ++/* 3 Information Elements from WFA. */ ++typedef struct _IE_WFA_T { ++ UINT_8 ucId; ++ UINT_8 ucLength; ++ UINT_8 aucOui[3]; ++ UINT_8 ucOuiType; ++ UINT_8 aucOuiSubTypeVersion[2]; ++ /*!< Please be noted. WPA defines a 16 bit field version ++ instead of one subtype field and one version field */ ++} __KAL_ATTRIB_PACKED__ IE_WFA_T, *P_IE_WFA_T; ++ ++/* HS20 3.1 - HS 2.0 Indication Information Element */ ++typedef struct _IE_HS20_INDICATION_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucType; /* Type */ ++ UINT_8 ucHotspotConfig; /* Hotspot Configuration */ ++} __KAL_ATTRIB_PACKED__ IE_HS20_INDICATION_T, *P_IE_HS20_INDICATION_T; ++ ++/* WAPI Information element format */ ++typedef struct _WAPI_INFO_ELEM_T { ++ UCHAR ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_16 u2AuthKeyMgtSuiteCount; ++ UCHAR aucAuthKeyMgtSuite1[4]; ++} __KAL_ATTRIB_PACKED__ WAPI_INFO_ELEM_T, *P_WAPI_INFO_ELEM_T; ++ ++#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) ++#pragma pack() ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Convert the ECWmin(max) to CWmin(max) */ ++#define ECW_TO_CW(_ECW) ((1 << (_ECW)) - 1) ++ ++/* Convert the RCPI to dBm */ ++#define RCPI_TO_dBm(_rcpi) \ ++ ((PARAM_RSSI)(((_rcpi) > RCPI_HIGH_BOUND ? RCPI_HIGH_BOUND : (_rcpi)) >> 1) - NDBM_LOW_BOUND_FOR_RCPI) ++ ++/* Convert the dBm to RCPI */ ++#define dBm_TO_RCPI(_dbm) \ ++ (RCPI)(((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) > RCPI_HIGH_BOUND) ? RCPI_HIGH_BOUND : \ ++ ((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) < RCPI_LOW_BOUND ? RCPI_LOW_BOUND : \ ++ (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1))) ++ ++/* Convert an unsigned char pointer to an information element pointer */ ++#define IE_ID(fp) (((P_IE_HDR_T) fp)->ucId) ++#define IE_LEN(fp) (((P_IE_HDR_T) fp)->ucLength) ++#define IE_SIZE(fp) (ELEM_HDR_LEN + IE_LEN(fp)) ++ ++#define SSID_IE(fp) ((P_IE_SSID_T) fp) ++ ++#define SUP_RATES_IE(fp) ((P_IE_SUPPORTED_RATE_T) fp) ++ ++#define DS_PARAM_IE(fp) ((P_IE_DS_PARAM_SET_T) fp) ++ ++#define TIM_IE(fp) ((P_IE_TIM_T) fp) ++ ++#define IBSS_PARAM_IE(fp) ((P_IE_IBSS_PARAM_SET_T) fp) ++ ++#define ERP_INFO_IE(fp) ((P_IE_ERP_T) fp) ++ ++#define EXT_SUP_RATES_IE(fp) ((P_IE_EXT_SUPPORTED_RATE_T) fp) ++ ++#define WFA_IE(fp) ((P_IE_WFA_T) fp) ++ ++#if CFG_SUPPORT_802_11D ++#define COUNTRY_IE(fp) ((P_IE_COUNTRY_T) fp) ++#endif ++ ++#define EXT_CAP_IE(fp) ((P_EXT_CAP_T) fp) ++ ++#define HT_CAP_IE(fp) ((P_IE_HT_CAP_T) fp) ++ ++#define HT_OP_IE(fp) ((P_IE_HT_OP_T) fp) ++ ++#define OBSS_SCAN_PARAM_IE(fp) ((P_IE_OBSS_SCAN_PARAM_T) fp) ++ ++#define BSS_20_40_COEXIST_IE(fp) ((P_IE_20_40_COEXIST_T) fp) ++ ++#define SUP_OPERATING_CLASS_IE(fp) ((P_IE_SUP_OPERATING_CLASS_T) fp) ++ ++#define QUIET_IE(fp) ((P_IE_QUIET_T) fp) ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++#define SUPPORTED_CHANNELS_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp) ++#endif ++ ++#define TIMEOUT_INTERVAL_IE(fp) ((IE_TIMEOUT_INTERVAL_T *)fp) ++ ++/* The macro to check if the MAC address is B/MCAST Address */ ++#define IS_BMCAST_MAC_ADDR(_pucDestAddr) \ ++ ((BOOLEAN) (((PUINT_8)(_pucDestAddr))[0] & BIT(0))) ++ ++/* The macro to check if the MAC address is UCAST Address */ ++#define IS_UCAST_MAC_ADDR(_pucDestAddr) \ ++ ((BOOLEAN) !(((PUINT_8)(_pucDestAddr))[0] & BIT(0))) ++ ++/* The macro to copy the MAC address */ ++#define COPY_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ kalMemCopy(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN) ++ ++/* The macro to check if two MAC addresses are equal */ ++#define EQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ (!kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) ++ ++/* The macro to check if two MAC addresses are not equal */ ++#define UNEQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ ++ (kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) ++ ++/* The macro to check whether two SSIDs are equal */ ++#define EQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ ++ ((ucSsidLen1 <= ELEM_MAX_LEN_SSID) && \ ++ (ucSsidLen2 <= ELEM_MAX_LEN_SSID) && \ ++ ((ucSsidLen1) == (ucSsidLen2)) && \ ++ !kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) ++ ++/* The macro to check whether two SSIDs are equal */ ++#define UNEQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ ++ ((ucSsidLen1 > ELEM_MAX_LEN_SSID) || \ ++ (ucSsidLen2 > ELEM_MAX_LEN_SSID) || \ ++ ((ucSsidLen1) != (ucSsidLen2)) || \ ++ kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) ++ ++/* The macro to copy the SSID, the length of pucDestSsid should have at least 32 bytes */ ++#define COPY_SSID(pucDestSsid, ucDestSsidLen, pucSrcSsid, ucSrcSsidLen) \ ++ do { \ ++ ucDestSsidLen = ucSrcSsidLen; \ ++ if (ucSrcSsidLen) { \ ++ ASSERT(ucSrcSsidLen <= ELEM_MAX_LEN_SSID); \ ++ kalMemCopy(pucDestSsid, \ ++ pucSrcSsid, \ ++ ((ucSrcSsidLen > ELEM_MAX_LEN_SSID) ? ELEM_MAX_LEN_SSID : ucSrcSsidLen)); \ ++ } \ ++ } while (FALSE) ++ ++/* The macro to copy the IE */ ++#define COPY_IE(pucDestIE, pucSrcIE) \ ++ do { \ ++ kalMemCopy((PUINT_8)pucDestIE, \ ++ (PUINT_8)pucSrcIE,\ ++ IE_SIZE(pucSrcIE)); \ ++ } while (FALSE) ++ ++#define IE_FOR_EACH(_pucIEsBuf, _u2IEsBufLen, _u2Offset) \ ++ for ((_u2Offset) = 0;\ ++ ((((_u2Offset) + 2) <= (_u2IEsBufLen)) && (((_u2Offset) + IE_SIZE(_pucIEsBuf)) <= (_u2IEsBufLen))); \ ++ (_u2Offset) += IE_SIZE(_pucIEsBuf), (_pucIEsBuf) += IE_SIZE(_pucIEsBuf)) ++ ++#define SET_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ ++ do { \ ++ if ((_ucBit) < ((_ucFieldLength) * 8)) { \ ++ PUINT_8 aucExtCap = (PUINT_8)(_aucField); \ ++ ((aucExtCap)[(_ucBit) / 8]) |= BIT((_ucBit) % 8); \ ++ } \ ++ } while (FALSE) ++ ++#define TEST_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ ++ ((((_ucFieldLength) * 8) > (_ucBit)) && (((_aucField)[(_ucBit) / 8]) & BIT((_ucBit) % 8))) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MAC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h +new file mode 100644 +index 000000000000..583923aed010 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h +@@ -0,0 +1,272 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/nic/mtreg.h#2 ++*/ ++ ++/*! \file "mtreg.h" ++ \brief The common register definition of mt5931 ++ ++ N/A ++*/ ++ ++/* ++** Log: mtreg.h ++ * ++ * 01 28 2013 samp.lin ++ * [WCXRP00000851] [MT6582 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6582-specific definitions. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 07 13 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add initial version for MT6628 driver support. ++ * ++*/ ++ ++#ifndef _MTREG_H ++#define _MTREG_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* 1 MT6628 MCR Definition */ ++ ++/* 2 Host Interface */ ++ ++/* 4 CHIP ID Register */ ++#define MCR_WCIR 0x0000 ++ ++/* 4 HIF Low Power Control Register */ ++#define MCR_WHLPCR 0x0004 ++ ++/* 4 Control Status Register */ ++#define MCR_WSDIOCSR 0x0008 ++#define MCR_WSPICSR 0x0008 ++ ++/* 4 HIF Control Register */ ++#define MCR_WHCR 0x000C ++ ++/* 4 HIF Interrupt Status Register */ ++#define MCR_WHISR 0x0010 ++ ++/* 4 HIF Interrupt Enable Register */ ++#define MCR_WHIER 0x0014 ++ ++/* 4 Abnormal Status Register */ ++#define MCR_WASR 0x0018 ++ ++/* 4 WLAN Software Interrupt Control Register */ ++#define MCR_WSICR 0x001C ++ ++/* 4 WLAN TX Status Register */ ++#define MCR_WTSR0 0x0020 ++ ++/* 4 WLAN TX Status Register */ ++#define MCR_WTSR1 0x0024 ++ ++/* 4 WLAN TX Data Register 0 */ ++#define MCR_WTDR0 0x0028 ++ ++/* 4 WLAN TX Data Register 1 */ ++#define MCR_WTDR1 0x002C ++ ++/* 4 WLAN RX Data Register 0 */ ++#define MCR_WRDR0 0x0030 ++ ++/* 4 WLAN RX Data Register 1 */ ++#define MCR_WRDR1 0x0034 ++ ++/* 4 Host to Device Send Mailbox 0 Register */ ++#define MCR_H2DSM0R 0x0038 ++ ++/* 4 Host to Device Send Mailbox 1 Register */ ++#define MCR_H2DSM1R 0x003c ++ ++/* 4 Device to Host Receive Mailbox 0 Register */ ++#define MCR_D2HRM0R 0x0040 ++ ++/* 4 Device to Host Receive Mailbox 1 Register */ ++#define MCR_D2HRM1R 0x0044 ++ ++/* 4 Device to Host Receive Mailbox 2 Register */ ++#define MCR_D2HRM2R 0x0048 ++ ++/* 4 WLAN RX Packet Length Register */ ++#define MCR_WRPLR 0x0050 ++ ++/* 4 HSIF Transaction Count Register */ ++#define MCR_HSTCR 0x0058 ++ ++/* #if CFG_SDIO_INTR_ENHANCE */ ++typedef struct _ENHANCE_MODE_DATA_STRUCT_T { ++ UINT_32 u4WHISR; ++ union { ++ struct { ++ UINT_8 ucTQ0Cnt; ++ UINT_8 ucTQ1Cnt; ++ UINT_8 ucTQ2Cnt; ++ UINT_8 ucTQ3Cnt; ++ UINT_8 ucTQ4Cnt; ++ UINT_8 ucTQ5Cnt; ++ UINT_16 u2Rsrv; ++ } u; ++ UINT_32 au4WTSR[2]; ++ } rTxInfo; ++ union { ++ struct { ++ UINT_16 u2NumValidRx0Len; ++ UINT_16 u2NumValidRx1Len; ++ UINT_16 au2Rx0Len[16]; ++ UINT_16 au2Rx1Len[16]; ++ } u; ++ UINT_32 au4RxStatusRaw[17]; ++ } rRxInfo; ++ UINT_32 u4RcvMailbox0; ++ UINT_32 u4RcvMailbox1; ++} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; ++/* #endif */ /* ENHANCE_MODE_DATA_STRUCT_T */ ++ ++/* 2 Definition in each register */ ++/* 3 WCIR 0x0000 */ ++#define WCIR_WLAN_READY BIT(21) ++#define WCIR_POR_INDICATOR BIT(20) ++#define WCIR_REVISION_ID BITS(16, 19) ++#define WCIR_CHIP_ID BITS(0, 15) ++ ++#define MTK_CHIP_REV_72 0x00006572 ++#define MTK_CHIP_REV_82 0x00006582 ++#define MTK_CHIP_REV_92 0x00006592 ++#define MTK_CHIP_MP_REVERSION_ID 0x0 ++ ++/* 3 WHLPCR 0x0004 */ ++#define WHLPCR_FW_OWN_REQ_CLR BIT(9) ++#define WHLPCR_FW_OWN_REQ_SET BIT(8) ++#define WHLPCR_IS_DRIVER_OWN BIT(8) ++#define WHLPCR_INT_EN_CLR BIT(1) ++#define WHLPCR_INT_EN_SET BIT(0) ++ ++/* 3 WSDIOCSR 0x0008 */ ++#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) ++ ++/* 3 WSPICSR 0x0008 */ ++#define WCSR_SPI_MODE_SEL BITS(3, 4) ++#define WCSR_SPI_ENDIAN_BIG BIT(2) ++#define WCSR_SPI_INT_OUT_MODE BIT(1) ++#define WCSR_SPI_DATA_OUT_MODE BIT(0) ++ ++/* 3 WHCR 0x000C */ ++#define WHCR_RX_ENHANCE_MODE_EN BIT(16) ++#define WHCR_MAX_HIF_RX_LEN_NUM BITS(4, 7) ++#define WHCR_W_MAILBOX_RD_CLR_EN BIT(2) ++#define WHCR_W_INT_CLR_CTRL BIT(1) ++#define WHCR_MCU_DBG_EN BIT(0) ++#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 4 ++ ++/* 3 WHISR 0x0010 */ ++#define WHISR_D2H_SW_INT BITS(8, 31) ++#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) ++#define WHISR_FW_OWN_BACK_INT BIT(4) ++#define WHISR_ABNORMAL_INT BIT(3) ++#define WHISR_RX1_DONE_INT BIT(2) ++#define WHISR_RX0_DONE_INT BIT(1) ++#define WHISR_TX_DONE_INT BIT(0) ++ ++/* 3 WHIER 0x0014 */ ++#define WHIER_D2H_SW_INT BITS(8, 31) ++#define WHIER_FW_OWN_BACK_INT_EN BIT(4) ++#define WHIER_ABNORMAL_INT_EN BIT(3) ++#define WHIER_RX1_DONE_INT_EN BIT(2) ++#define WHIER_RX0_DONE_INT_EN BIT(1) ++#define WHIER_TX_DONE_INT_EN BIT(0) ++#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ ++ WHIER_RX1_DONE_INT_EN | \ ++ WHIER_TX_DONE_INT_EN | \ ++ WHIER_ABNORMAL_INT_EN | \ ++ WHIER_D2H_SW_INT \ ++ ) ++ ++/* 3 WASR 0x0018 */ ++#define WASR_FW_OWN_INVALID_ACCESS BIT(4) ++#define WASR_RX1_UNDER_FLOW BIT(3) ++#define WASR_RX0_UNDER_FLOW BIT(2) ++#define WASR_TX1_OVER_FLOW BIT(1) ++#define WASR_TX0_OVER_FLOW BIT(0) ++ ++/* 3 WSICR 0x001C */ ++#define WSICR_H2D_SW_INT_SET BITS(16, 31) ++ ++/* 3 WRPLR 0x0050 */ ++#define WRPLR_RX1_PACKET_LENGTH BITS(16, 31) ++#define WRPLR_RX0_PACKET_LENGTH BITS(0, 15) ++ ++/* 3 HSTCR 0x0058 */ ++#define HSTCR_AFF_BURST_LEN BITS(24, 25) ++#define HSTCR_AFF_BURST_LEN_OFFSET 24 ++#define HSTCR_TRANS_TARGET BITS(20, 22) ++#define HSTCR_TRANS_TARGET_OFFSET 20 ++#define HSTCR_HSIF_TRANS_CNT BITS(2, 19) ++#define HSTCR_HSIF_TRANS_CNT_OFFSET 2 ++ ++/* HSTCR_TRANS_TARGET */ ++typedef enum _eTransTarget { ++ TRANS_TARGET_TXD0 = 0, ++ TRANS_TARGET_TXD1, ++ TRANS_TARGET_RXD0, ++ TRANS_TARGET_RXD1, ++ TRANS_TARGET_WHISR, ++ NUM_TRANS_TARGET ++} E_TRANS_TARGET_T; ++ ++typedef enum _E_AFF_BURST_LEN { ++ BURST_1_DW = 0, ++ BURST_4_DW, ++ BURST_8_DW, ++ BURST_RSV, ++ NUM_AFF_BURST_LEN ++} E_AFF_BURST_LEN; ++ ++#endif /* _MTREG_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h +new file mode 100644 +index 000000000000..c059b707aee8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h +@@ -0,0 +1,498 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic.h#1 ++*/ ++ ++/*! \file "nic.h" ++ \brief The declaration of nic functions ++ ++ Detail description. ++*/ ++ ++/* ++** Log: nic.h ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS ++ * cannot do the 4-way handshake to connect to the AP.. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right ++ * after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced ++ * by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test ++ * with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always process TX interrupt first then RX interrupt. ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-10-13 21:58:58 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-24 21:12:55 GMT mtk01104 ++** Add function prototype nicRestoreSpiDefMode() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:54 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:32 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_H ++#define _NIC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++struct _REG_ENTRY_T { ++ UINT_32 u4Offset; ++ UINT_32 u4Value; ++}; ++ ++struct _TABLE_ENTRY_T { ++ P_REG_ENTRY_T pu4TablePtr; ++ UINT_16 u2Size; ++}; ++ ++/*! INT status to event map */ ++typedef struct _INT_EVENT_MAP_T { ++ UINT_32 u4Int; ++ UINT_32 u4Event; ++} INT_EVENT_MAP_T, *P_INT_EVENT_MAP_T; ++ ++enum ENUM_INT_EVENT_T { ++ INT_EVENT_ABNORMAL, ++ INT_EVENT_SW_INT, ++ INT_EVENT_TX, ++ INT_EVENT_RX, ++ INT_EVENT_NUM ++}; ++ ++typedef enum _ENUM_IE_UPD_METHOD_T { ++ IE_UPD_METHOD_UPDATE_RANDOM, ++ IE_UPD_METHOD_UPDATE_ALL, ++ IE_UPD_METHOD_DELETE_ALL, ++} ENUM_IE_UPD_METHOD_T, *P_ENUM_IE_UPD_METHOD_T; ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern BOOLEAN fgIsResetting; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in nic.c */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter); ++ ++VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter); ++ ++VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus); ++ ++WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter); ++ ++VOID nicMCRInit(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_SDIO_INTR_ENHANCE ++VOID nicSDIOInit(IN P_ADAPTER_T prAdapter); ++ ++VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus); ++#endif ++ ++BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter); ++ ++VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt); ++ ++BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter); ++ ++#if defined(_HIF_SPI) ++void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data); ++ ++VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data); ++ ++VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap); ++ ++P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); ++ ++P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); ++ ++P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx); ++ ++VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter); ++ ++UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter); ++ ++/* Media State Change */ ++WLAN_STATUS ++nicMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); ++ ++/* Utility function for channel number conversion */ ++UINT_32 nicChannelNum2Freq(IN UINT_32 u4ChannelNum); ++ ++UINT_32 nicFreq2ChannelNum(IN UINT_32 u4FreqInKHz); ++ ++/* firmware command wrapper */ ++ /* NETWORK (WIFISYS) */ ++WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* BSS-INFO */ ++WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* BSS-INFO Indication (PM) */ ++WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++ /* Beacon Template Update */ ++WLAN_STATUS ++nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, ++ IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen); ++ ++WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam); ++ ++/*----------------------------------------------------------------------------*/ ++/* Calibration Control */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam); ++ ++WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset); ++ ++WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult); ++ ++/*----------------------------------------------------------------------------*/ ++/* PHY configuration */ ++/*----------------------------------------------------------------------------*/ ++VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* MGMT and System Service Control */ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicResetSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter); ++ ++VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent); ++ ++WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent); ++/*----------------------------------------------------------------------------*/ ++/* Scan Result Processing */ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicAddScanResult(IN P_ADAPTER_T prAdapter, ++ IN PARAM_MAC_ADDRESS rMacAddr, ++ IN P_PARAM_SSID_T prSsid, ++ IN UINT_32 u4Privacy, ++ IN PARAM_RSSI rRssi, ++ IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, ++ IN P_PARAM_802_11_CONFIG_T prConfiguration, ++ IN ENUM_PARAM_OP_MODE_T eOpMode, ++ IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf); ++ ++VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx); ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++/*----------------------------------------------------------------------------*/ ++/* Workaround Control */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Fixed Rate Hacking */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateRateParams(IN P_ADAPTER_T prAdapter, ++ IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, ++ IN PUINT_8 pucDesiredPhyTypeSet, ++ IN PUINT_16 pu2DesiredNonHTRateSet, ++ IN PUINT_16 pu2BSSBasicRateSet, ++ IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 u2HtCapInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Write registers */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value); ++ ++/*----------------------------------------------------------------------------*/ ++/* Update auto rate */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4ArSysParam0, ++ IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3); ++ ++/*----------------------------------------------------------------------------*/ ++/* Enable/Disable Roaming */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming); ++ ++VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Link Quality Updating */ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality); ++ ++VOID ++nicUpdateRSSI(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); ++ ++VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed); ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam); ++#endif ++ ++#endif /* _NIC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h +new file mode 100644 +index 000000000000..86e2c84b07ff +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h +@@ -0,0 +1,420 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_rx.h#1 ++*/ ++ ++/*! \file "nic_rx.h" ++ \brief The declaration of the nic rx functions ++ ++*/ ++ ++/* ++** Log: nic_rx.h ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode ++ * and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Change prototype of API of adding P2P device to scan result. ++ * Additional IE buffer is saved. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify data structure for P2P Scan result. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * newly added P2P API should be declared in header file. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * 4) nicRxWaitResponse() revised ++ * * 5) another set of TQ counter default value is added for fw-download state ++ * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * and result is retrieved by get ATInfo instead ++ * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:49:09 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 14:02:37 GMT MTK02468 ++** Added ucStaRecIdx in SW_RFB_T and HALF_SEQ_NO_COUNT definition (to replace HALF_SEQ_NO_CNOUT) ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-27 11:07:54 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 18:18:09 GMT mtk02752 ++** modify nicRxAddScanResult() ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-24 22:42:22 GMT mtk02752 ++** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-24 19:57:06 GMT mtk02752 ++** adopt P_HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 21:43:04 GMT mtk02752 ++** correct ENUM_RX_PKT_DESTINATION_T definitions ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 15:28:25 GMT mtk02752 ++** add ucQueuedPacketNum for indicating how many packet are queued by RX reordering buffer/forwarding path ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 15:05:01 GMT mtk02752 ++** add eTC for SW_RFB_T and structure RX_MAILBOX ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 21:16:57 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-13 16:59:30 GMT mtk02752 ++** add handler for event packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-13 13:45:50 GMT mtk02752 ++** add port param for nicRxEnhanceReadBuffer() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-11 10:12:31 GMT mtk02752 ++** nicSDIOReadIntStatus() always read sizeof(ENHANCE_MODE_DATA_STRUCT_T) for int response, ++** thus the number should be set to 0(:=16) instead of 10 ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-29 19:53:32 GMT mtk01084 ++** modify structure naming ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-23 16:08:23 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:01 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-20 12:23:33 GMT mtk01461 ++** Add u4MaxEventBufferLen parameter to nicRxWaitResponse() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-18 21:00:48 GMT mtk01426 ++** Update SDIO_MAXIMUM_RX_STATUS value ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:36:15 GMT mtk01461 ++** Remove unused define - SDIO_MAXIMUM_TX_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:17 GMT mtk01461 ++** Add function for HIF_LOOPBACK_PRE_TEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:56:19 GMT mtk01426 ++** Add to support CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:19:56 GMT mtk01426 ++** Add nicRxWaitResponse function proto type ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:35 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_RX_H ++#define _NIC_RX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern P_SW_RFB_T g_arGscnResultsTempBuffer[]; ++extern UINT_8 g_GscanResultsTempBufferIndex; ++extern UINT_8 g_arGscanResultsIndicateNumber[]; ++extern UINT_8 g_GetResultsBufferedCnt; ++extern UINT_8 g_GetResultsCmdCnt; ++extern void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define MAX_SEQ_NO 4095 ++#define MAX_SEQ_NO_COUNT 4096 ++#define HALF_SEQ_NO_CNOUT 2048 ++ ++#define HALF_SEQ_NO_COUNT 2048 ++ ++#define MT6620_FIXED_WIN_SIZE 64 ++#define CFG_RX_MAX_BA_ENTRY 4 ++#define CFG_RX_MAX_BA_TID_NUM 8 ++ ++#define RX_STATUS_FLAG_MORE_PACKET BIT(30) ++#define RX_STATUS_CHKSUM_MASK BITS(0, 10) ++ ++#define RX_RFB_LEN_FIELD_LEN 4 ++#define RX_HEADER_OFFSET 2 ++ ++#define RX_RETURN_INDICATED_RFB_TIMEOUT_SEC 3 ++ ++#if defined(_HIF_SDIO) && defined(WINDOWS_DDK) ++/*! On XP, maximum Tx+Rx Statue <= 64-4(HISR)*/ ++#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ ++#else ++#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_RX_STATISTIC_COUNTER_T { ++ RX_MPDU_TOTAL_COUNT = 0, ++ RX_SIZE_ERR_DROP_COUNT, ++ ++ RX_DATA_INDICATION_COUNT, ++ RX_DATA_RETURNED_COUNT, ++ RX_DATA_RETAINED_COUNT, ++ ++ RX_DROP_TOTAL_COUNT, ++ RX_TYPE_ERR_DROP_COUNT, ++ RX_CLASS_ERR_DROP_COUNT, ++ RX_DST_NULL_DROP_COUNT, ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ RX_CSUM_TCP_FAILED_COUNT, ++ RX_CSUM_UDP_FAILED_COUNT, ++ RX_CSUM_IP_FAILED_COUNT, ++ RX_CSUM_TCP_SUCCESS_COUNT, ++ RX_CSUM_UDP_SUCCESS_COUNT, ++ RX_CSUM_IP_SUCCESS_COUNT, ++ RX_CSUM_UNKNOWN_L4_PKT_COUNT, ++ RX_CSUM_UNKNOWN_L3_PKT_COUNT, ++ RX_IP_V6_PKT_CCOUNT, ++#endif ++ RX_STATISTIC_COUNTER_NUM ++} ENUM_RX_STATISTIC_COUNTER_T; ++ ++typedef enum _ENUM_RX_PKT_DESTINATION_T { ++ RX_PKT_DESTINATION_HOST, /* to OS */ ++ RX_PKT_DESTINATION_FORWARD, /* to TX queue for forward, AP mode */ ++ RX_PKT_DESTINATION_HOST_WITH_FORWARD, /* to both TX and OS, AP mode broadcast packet */ ++ RX_PKT_DESTINATION_NULL, /* packet to be freed */ ++ RX_PKT_DESTINATION_NUM ++} ENUM_RX_PKT_DESTINATION_T; ++ ++struct _SW_RFB_T { ++ QUE_ENTRY_T rQueEntry; ++ PVOID pvPacket; /*!< ptr to rx Packet Descriptor */ ++ PUINT_8 pucRecvBuff; /*!< ptr to receive data buffer */ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4HifRxHdrFlag; ++ PVOID pvHeader; ++ UINT_16 u2PacketLen; ++ UINT_16 u2HeaderLen; ++ UINT_16 u2SSN; ++ UINT_8 ucTid; ++ UINT_8 ucWlanIdx; ++ UINT_8 ucPacketType; ++ UINT_8 ucStaRecIdx; ++ ++ ENUM_CSUM_RESULT_T aeCSUM[CSUM_TYPE_NUM]; ++ ENUM_RX_PKT_DESTINATION_T eDst; ++ ENUM_TRAFFIC_CLASS_INDEX_T eTC; /* only valid when eDst == FORWARD */ ++ ++ UINT_64 rRxTime; ++}; ++ ++/*! RX configuration type structure */ ++typedef struct _RX_CTRL_T { ++ UINT_32 u4RxCachedSize; ++ PUINT_8 pucRxCached; ++ QUE_T rFreeSwRfbList; ++ QUE_T rReceivedRfbList; ++ QUE_T rIndicatedRfbList; ++ ++#if CFG_SDIO_RX_AGG ++ PUINT_8 pucRxCoalescingBufPtr; ++#endif ++ ++ PVOID apvIndPacket[CFG_RX_MAX_PKT_NUM]; ++ PVOID apvRetainedPacket[CFG_RX_MAX_PKT_NUM]; ++ ++ UINT_8 ucNumIndPacket; ++ UINT_8 ucNumRetainedPacket; ++ UINT_64 au8Statistics[RX_STATISTIC_COUNTER_NUM]; /*!< RX Counters */ ++ ++#if CFG_HIF_STATISTICS ++ UINT_32 u4TotalRxAccessNum; ++ UINT_32 u4TotalRxPacketNum; ++#endif ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ UINT_32 u4QueuedCnt; ++ UINT_32 u4DequeuedCnt; ++#endif ++ ++#if CFG_RX_PKTS_DUMP ++ UINT_32 u4RxPktsDumpTypeMask; ++#endif ++ ++} RX_CTRL_T, *P_RX_CTRL_T; ++ ++typedef struct _RX_MAILBOX_T { ++ UINT_32 u4RxMailbox[2]; /* for Device-to-Host Mailbox */ ++} RX_MAILBOX_T, *P_RX_MAILBOX_T; ++ ++typedef WLAN_STATUS(*PROCESS_RX_MGT_FUNCTION) (P_ADAPTER_T, P_SW_RFB_T); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define RX_INC_CNT(prRxCtrl, eCounter) \ ++ {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]++; } ++ ++#define RX_ADD_CNT(prRxCtrl, eCounter, u8Amount) \ ++ {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] += (UINT_64)u8Amount; } ++ ++#define RX_GET_CNT(prRxCtrl, eCounter) \ ++ (((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]) ++ ++#define RX_RESET_ALL_CNTS(prRxCtrl) \ ++ {kalMemZero(&prRxCtrl->au8Statistics[0], sizeof(prRxCtrl->au8Statistics)); } ++ ++#define RX_STATUS_TEST_MORE_FLAG(flag) \ ++ ((BOOLEAN)((flag & RX_STATUS_FLAG_MORE_PACKET) ? TRUE : FALSE)) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID nicRxInitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter); ++ ++#if !CFG_SDIO_INTR_ENHANCE ++VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++#else ++VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS ++nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++#if CFG_SDIO_RX_AGG ++VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter); ++#endif ++ ++WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); ++ ++VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); ++ ++VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus); ++ ++VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); ++ ++VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); ++ ++WLAN_STATUS ++nicRxWaitResponse(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length); ++ ++VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter); ++ ++VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++#endif /* _NIC_RX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h +new file mode 100644 +index 000000000000..e516468fcb16 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h +@@ -0,0 +1,642 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_tx.h#1 ++*/ ++ ++/*! \file nic_tx.h ++ \brief Functions that provide TX operation in NIC's point of view. ++ ++ This file provides TX functions which are responsible for both Hardware and ++ Software Resource Management and keep their Synchronization. ++ ++*/ ++ ++/* ++** Log: nic_tx.h ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add log counter for tx ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add TX_DONE status detail information. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing ++ * frame dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 02 16 2011 cp.wu ++ * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking ++ * available count and modify behavior ++ * 1. add new API: nicTxGetFreeCmdCount() ++ * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 12 15 2010 yuche.tsai ++ * NULL ++ * Update SLT Descriptor number configure in driver. ++ * ++ * 11 16 2010 yarco.yang ++ * [WCXRP00000177] [MT5931 F/W] Performance tuning for 1st connection ++ * Update TX buffer count ++ * ++ * 11 03 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * 1) use 8 buffers for MT5931 which is equipped with less memory ++ * 2) modify MT5931 debug level to TRACE when download is successful ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 07 26 2010 cp.wu ++ * ++ * change TC4 initial value from 2 to 4. ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under ++ * concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add MGMT Packet type for HIF_TX_HEADER ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate ++ * 2) add packet type for indicating management frames ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add TX_PACKET_MGMT to indicate the frame is coming from management modules ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 02 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Redistributed the initial TC resources for normal operation ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * 4) nicRxWaitResponse() revised ++ * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * 4. correct some HAL implementation ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * and result is retrieved by get ATInfo instead ++ * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:53:28 GMT mtk02752 ++** remove unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-27 11:08:00 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-24 19:56:49 GMT mtk02752 ++** remove redundant eTC ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 22:01:08 GMT mtk02468 ++** Added MSDU_INFO fields for composing HIF TX header ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:51 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:35:05 GMT mtk02752 ++** + nicTxMsduInfoList() for sending MsduInfoList ++** + NIC_TX_BUFF_COUNT_TC[0~5] ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-17 11:07:00 GMT mtk02752 ++** add nicTxAdjustTcq() API ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 22:28:30 GMT mtk02752 ++** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 21:44:50 GMT mtk02752 ++** + nicTxReturnMsduInfo() ++** + nicTxFillMsduInfo() ++** + rFreeMsduInfoList field in TX_CTRL ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-16 18:00:43 GMT mtk02752 ++** use P_PACKET_INFO_T for prPacket to avoid inventing another new structure for packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-16 15:28:49 GMT mtk02752 ++** add ucQueuedPacketNum for indicating how many packets are queued by per STA/AC queue ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-16 10:52:01 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-14 23:39:24 GMT mtk02752 ++** interface structure redefine ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-13 21:17:03 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-29 19:53:10 GMT mtk01084 ++** remove strange code by Frog ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:04 GMT mtk01084 ++** update for new HW architecture design ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-02 13:53:03 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:36:50 GMT mtk01461 ++** Add declaration of nicTxReleaseResource() ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:58:39 GMT mtk01461 ++** Move CMD_INFO_T related define and function to cmd_buf.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:53 GMT mtk01461 ++** Add function for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:33:27 GMT mtk01461 ++** Define constants for TX PATH and add nicTxPollingResource ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:32 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:38 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _NIC_TX_H ++#define _NIC_TX_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define NIC_TX_RESOURCE_POLLING_TIMEOUT 256 ++#define NIC_TX_RESOURCE_POLLING_DELAY_MSEC 50 ++ ++/* Maximum buffer count for individual HIF TCQ */ ++ ++#if defined(MT6620) ++#if CFG_SLT_SUPPORT ++ /* 20101215 mtk01725 Redistributed the initial TC resources for SLT operation */ ++#define NIC_TX_BUFF_COUNT_TC0 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 16 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 0 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 0 /* First connection: 0 */ ++#else ++ /* 20100302 mtk02468 Redistributed the initial TC resources for normal operation */ ++#define NIC_TX_BUFF_COUNT_TC0 6 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 8 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 8 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 8 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 2 /* First connection: 0 */ ++#endif ++#elif defined(MT6628) ++#if (CFG_SRAM_SIZE_OPTION == 0) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 20 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#elif (CFG_SRAM_SIZE_OPTION == 1) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 36 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#elif (CFG_SRAM_SIZE_OPTION == 2) ++#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC1 48 /* First connection: 32 */ ++#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ ++#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ ++#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ ++#else ++#error "> Set TX_BUFF_COUNT_TC error!" ++#endif ++#endif ++ ++#define NIC_TX_BUFF_SUM (NIC_TX_BUFF_COUNT_TC0 + \ ++ NIC_TX_BUFF_COUNT_TC1 + \ ++ NIC_TX_BUFF_COUNT_TC2 + \ ++ NIC_TX_BUFF_COUNT_TC3 + \ ++ NIC_TX_BUFF_COUNT_TC4 + \ ++ NIC_TX_BUFF_COUNT_TC5) ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++#define NIC_TX_INIT_BUFF_COUNT_TC0 8 ++#define NIC_TX_INIT_BUFF_COUNT_TC1 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC2 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC3 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC4 0 ++#define NIC_TX_INIT_BUFF_COUNT_TC5 0 ++ ++#define NIC_TX_INIT_BUFF_SUM (NIC_TX_INIT_BUFF_COUNT_TC0 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC1 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC2 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC3 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC4 + \ ++ NIC_TX_INIT_BUFF_COUNT_TC5) ++ ++#endif ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#define NIC_TX_TIME_THRESHOLD 100 /* in unit of ms */ ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* 3 Session for TX QUEUES */ ++/* The definition in this ENUM is used to categorize packet's Traffic Class according ++ * to the their TID(User Priority). ++ * In order to achieve QoS goal, a particular TC should not block the process of ++ * another packet with different TC. ++ * In current design we will have 5 categories(TCs) of SW resource. ++ */ ++typedef enum _ENUM_TRAFFIC_CLASS_INDEX_T { ++ TC0_INDEX = 0, /* HIF TX0: AC0 packets */ ++ TC1_INDEX, /* HIF TX0: AC1 packets & non-QoS packets */ ++ TC2_INDEX, /* HIF TX0: AC2 packets */ ++ TC3_INDEX, /* HIF TX0: AC3 packets */ ++ TC4_INDEX, /* HIF TX1: Command packets or 802.1x packets */ ++ TC5_INDEX, /* HIF TX0: BMCAST packets */ ++ TC_NUM /* Maximum number of Traffic Classes. */ ++} ENUM_TRAFFIC_CLASS_INDEX_T; ++ ++typedef enum _ENUM_TX_STATISTIC_COUNTER_T { ++ TX_MPDU_TOTAL_COUNT = 0, ++ TX_INACTIVE_BSS_DROP, ++ TX_INACTIVE_STA_DROP, ++ TX_FORWARD_OVERFLOW_DROP, ++ TX_AP_BORADCAST_DROP, ++ TX_STATISTIC_COUNTER_NUM ++} ENUM_TX_STATISTIC_COUNTER_T; ++ ++typedef struct _TX_TCQ_STATUS_T { ++ UINT_8 aucFreeBufferCount[TC_NUM]; ++ UINT_8 aucMaxNumOfBuffer[TC_NUM]; ++} TX_TCQ_STATUS_T, *P_TX_TCQ_STATUS_T; ++ ++typedef struct _TX_TCQ_ADJUST_T { ++ INT_8 acVariation[TC_NUM]; ++} TX_TCQ_ADJUST_T, *P_TX_TCQ_ADJUST_T; ++ ++typedef struct _TX_CTRL_T { ++ UINT_32 u4TxCachedSize; ++ PUINT_8 pucTxCached; ++ ++/* Elements below is classified according to TC (Traffic Class) value. */ ++ ++ TX_TCQ_STATUS_T rTc; ++ ++ PUINT_8 pucTxCoalescingBufPtr; ++ ++ QUE_T rFreeMsduInfoList; ++ ++ /* Management Frame Tracking */ ++ /* number of management frames to be sent */ ++ INT_32 i4TxMgmtPendingNum; ++ ++ /* to tracking management frames need TX done callback */ ++ QUE_T rTxMgmtTxingQueue; ++ ++#if CFG_HIF_STATISTICS ++ UINT_32 u4TotalTxAccessNum; ++ UINT_32 u4TotalTxPacketNum; ++#endif ++ UINT_32 au4Statistics[TX_STATISTIC_COUNTER_NUM]; ++ ++ /* Number to track forwarding frames */ ++ INT_32 i4PendingFwdFrameCount; ++ ++} TX_CTRL_T, *P_TX_CTRL_T; ++ ++typedef enum _ENUM_TX_PACKET_SRC_T { ++ TX_PACKET_OS, ++ TX_PACKET_OS_OID, ++ TX_PACKET_FORWARDING, ++ TX_PACKET_MGMT, ++ TX_PACKET_NUM ++} ENUM_TX_PACKET_SRC_T; ++ ++typedef enum _ENUM_HIF_TX_PACKET_TYPE_T { ++ HIF_TX_PACKET_TYPE_DATA = 0, ++ HIF_TX_PACKET_TYPE_COMMAND, ++ HIF_TX_PACKET_TYPE_HIF_LB, ++ HIF_TX_PACKET_TYPE_MGMT ++} ENUM_HIF_TX_PACKET_TYPE_T, *P_ENUM_HIF_TX_PACKET_TYPE_T; ++ ++typedef enum _ENUM_TX_RESULT_CODE_T { ++ TX_RESULT_SUCCESS = 0, ++ TX_RESULT_LIFE_TIMEOUT, ++ TX_RESULT_RTS_ERROR, ++ TX_RESULT_MPDU_ERROR, ++ TX_RESULT_AGING_TIMEOUT, ++ TX_RESULT_FLUSHED, ++ TX_RESULT_DROPPED_IN_DRIVER = 32, ++ TX_RESULT_NUM ++} ENUM_TX_RESULT_CODE_T, *P_ENUM_TX_RESULT_CODE_T; ++ ++struct _WLAN_CFG_ENTRY_T { ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++ WLAN_CFG_SET_CB pfSetCb; ++ PVOID pPrivate; ++ UINT_32 u4Flags; ++}; ++ ++struct _WLAN_CFG_T { ++ UINT_32 u4WlanCfgEntryNumMax; ++ UINT_32 u4WlanCfgKeyLenMax; ++ UINT_32 u4WlanCfgValueLenMax; ++ WLAN_CFG_ENTRY_T arWlanCfgBuf[WLAN_CFG_ENTRY_NUM_MAX]; ++}; ++ ++/* TX Call Back Function */ ++typedef WLAN_STATUS(*PFN_TX_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++typedef struct _PKT_PROFILE_T { ++ BOOLEAN fgIsValid; ++#if CFG_PRINT_RTP_PROFILE ++ BOOLEAN fgIsPrinted; ++ UINT_16 u2IpSn; ++ UINT_16 u2RtpSn; ++ UINT_8 ucTcxFreeCount; ++#endif ++ OS_SYSTIME rHardXmitArrivalTimestamp; ++ OS_SYSTIME rEnqueueTimestamp; ++ OS_SYSTIME rDequeueTimestamp; ++ OS_SYSTIME rHifTxDoneTimestamp; ++} PKT_PROFILE_T, *P_PKT_PROFILE_T; ++#endif ++ ++/* TX transactions could be divided into 4 kinds: ++ * ++ * 1) 802.1X / Bluetooth-over-Wi-Fi Security Frames ++ * [CMD_INFO_T] - [prPacket] - in skb or NDIS_PACKET form ++ * ++ * 2) MMPDU ++ * [CMD_INFO_T] - [prPacket] - [MSDU_INFO_T] - [prPacket] - direct buffer for frame body ++ * ++ * 3) Command Packets ++ * [CMD_INFO_T] - [pucInfoBuffer] - direct buffer for content of command packet ++ * ++ * 4) Normal data frame ++ * [MSDU_INFO_T] - [prPacket] - in skb or NDIS_PACKET form ++ */ ++ ++/* PS_FORWARDING_TYPE_NON_PS means that the receiving STA is in Active Mode ++* from the perspective of host driver (maybe not synchronized with FW --> SN is needed) ++*/ ++ ++struct _MSDU_INFO_T { ++ QUE_ENTRY_T rQueEntry; ++ P_NATIVE_PACKET prPacket; ++ ++ ENUM_TX_PACKET_SRC_T eSrc; /* specify OS/FORWARD packet */ ++ UINT_8 ucUserPriority; ++ ++ /* For composing HIF TX header */ ++ UINT_8 ucTC; /* Traffic Class: 0~4 (HIF TX0), 5 (HIF TX1) */ ++ UINT_8 ucPacketType; /* 0: Data, 1: Command, 2: HIF Loopback 3: Management Frame */ ++ UINT_8 ucStaRecIndex; ++ UINT_8 ucNetworkType; /* See ENUM_NETWORK_TYPE_T */ ++ UINT_8 ucFormatID; /* 0: MAUI, Linux, Windows NDIS 5.1 */ ++ BOOLEAN fgIs802_1x; /* TRUE: 802.1x frame */ ++ BOOLEAN fgIs802_11; /* TRUE: 802.11 header is present */ ++ UINT_16 u2PalLLH; /* PAL Logical Link Header (for BOW network) */ ++ UINT_16 u2AclSN; /* ACL Sequence Number (for BOW network) */ ++ UINT_8 ucPsForwardingType; /* See ENUM_PS_FORWARDING_TYPE_T */ ++ UINT_8 ucPsSessionID; /* PS Session ID specified by the FW for the STA */ ++ BOOLEAN fgIsBurstEnd; /* TRUE means this is the last packet of the burst for (STA, TID) */ ++ BOOLEAN fgIsBIP; /* Management Frame Protection */ ++ BOOLEAN fgIsBasicRate; /* Force Basic Rate Transmission */ ++ ++ /* flattened from PACKET_INFO_T */ ++ UINT_8 ucMacHeaderLength; ++ UINT_8 ucLlcLength; /* w/o EtherType */ ++ UINT_16 u2FrameLength; ++ UINT_8 aucEthDestAddr[MAC_ADDR_LEN]; /* Ethernet Destination Address */ ++ ++ /* for TX done tracking */ ++ UINT_8 ucTxSeqNum; ++ PFN_TX_DONE_HANDLER pfTxDoneHandler; ++ BOOLEAN fgNeedTxDoneStatus; ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ PKT_PROFILE_T rPktProfile; ++#endif ++ COMMAND_TYPE eCmdType; ++ UINT_8 ucCID; ++ UINT_32 u4InqueTime; ++}; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define TX_INC_CNT(prTxCtrl, eCounter) \ ++ {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]++; } ++ ++#define TX_ADD_CNT(prTxCtrl, eCounter, u8Amount) \ ++ {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter] += (UINT_32)u8Amount; } ++ ++#define TX_GET_CNT(prTxCtrl, eCounter) \ ++ (((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]) ++ ++#define TX_RESET_ALL_CNTS(prTxCtrl) \ ++ {kalMemZero(&prTxCtrl->au4Statistics[0], sizeof(prTxCtrl->au4Statistics)); } ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#define PRINT_PKT_PROFILE(_pkt_profile, _note) \ ++{ \ ++ if (!(_pkt_profile)->fgIsPrinted) { \ ++ DBGLOG(TX, TRACE, "X[%u] E[%u] D[%u] HD[%u] B[%d] RTP[%d] %s\n", \ ++ (UINT_32)((_pkt_profile)->rHardXmitArrivalTimestamp), \ ++ (UINT_32)((_pkt_profile)->rEnqueueTimestamp), \ ++ (UINT_32)((_pkt_profile)->rDequeueTimestamp), \ ++ (UINT_32)((_pkt_profile)->rHifTxDoneTimestamp), \ ++ (UINT_8)((_pkt_profile)->ucTcxFreeCount), \ ++ (UINT_16)((_pkt_profile)->u2RtpSn), \ ++ (_note)); \ ++ (_pkt_profile)->fgIsPrinted = TRUE; \ ++ } \ ++} ++ ++#define CHK_PROFILES_DELTA(_pkt1, _pkt2, _delta) \ ++ (CHECK_FOR_TIMEOUT((_pkt1)->rHardXmitArrivalTimestamp, (_pkt2)->rHardXmitArrivalTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rEnqueueTimestamp, (_pkt2)->rEnqueueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rDequeueTimestamp, (_pkt2)->rDequeueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt1)->rHifTxDoneTimestamp, (_pkt2)->rHifTxDoneTimestamp, (_delta))) ++ ++#define CHK_PROFILE_DELTA(_pkt, _delta) \ ++ (CHECK_FOR_TIMEOUT((_pkt)->rEnqueueTimestamp, (_pkt)->rHardXmitArrivalTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt)->rDequeueTimestamp, (_pkt)->rEnqueueTimestamp, (_delta)) || \ ++ CHECK_FOR_TIMEOUT((_pkt)->rHifTxDoneTimestamp, (_pkt)->rDequeueTimestamp, (_delta))) ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID nicTxInitialize(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt); ++ ++WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); ++ ++BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN UINT_8 *aucTxRlsCnt); ++ ++WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter); ++ ++UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); ++ ++WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue); ++ ++WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); ++ ++VOID nicTxRelease(IN P_ADAPTER_T prAdapter); ++ ++VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter); ++ ++VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prNdisPacket); ++ ++WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); ++ ++WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter); ++#endif ++ ++WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_TX_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h +new file mode 100644 +index 000000000000..d518aaf10eb5 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h +@@ -0,0 +1,192 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p.h#3 ++*/ ++ ++/* ++** Log: p2p.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * p2p interface revised to be sync. with HAL ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add parameter to control: ++ * 1) auto group owner ++ * 2) P2P-PS parameter (CTWindow, NoA descriptors) ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * correct WPS Device Password ID definition. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * ++*/ ++ ++#ifndef _P2P_H ++#define _P2P_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* refer to 'Config Methods' in WPS */ ++#define WPS_CONFIG_USBA 0x0001 ++#define WPS_CONFIG_ETHERNET 0x0002 ++#define WPS_CONFIG_LABEL 0x0004 ++#define WPS_CONFIG_DISPLAY 0x0008 ++#define WPS_CONFIG_EXT_NFC 0x0010 ++#define WPS_CONFIG_INT_NFC 0x0020 ++#define WPS_CONFIG_NFC 0x0040 ++#define WPS_CONFIG_PBC 0x0080 ++#define WPS_CONFIG_KEYPAD 0x0100 ++ ++/* refer to 'Device Password ID' in WPS */ ++#define WPS_DEV_PASSWORD_ID_PIN 0x0000 ++#define WPS_DEV_PASSWORD_ID_USER 0x0001 ++#define WPS_DEV_PASSWORD_ID_MACHINE 0x0002 ++#define WPS_DEV_PASSWORD_ID_REKEY 0x0003 ++#define WPS_DEV_PASSWORD_ID_PUSHBUTTON 0x0004 ++#define WPS_DEV_PASSWORD_ID_REGISTRAR 0x0005 ++ ++#define P2P_DEVICE_TYPE_NUM 2 ++#define P2P_DEVICE_NAME_LENGTH 32 ++#define P2P_NETWORK_NUM 8 ++#define P2P_MEMBER_NUM 8 ++ ++#define P2P_WILDCARD_SSID "DIRECT-" ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++struct _P2P_INFO_T { ++ UINT_32 u4DeviceNum; ++ EVENT_P2P_DEV_DISCOVER_RESULT_T arP2pDiscoverResult[CFG_MAX_NUM_BSS_LIST]; ++ PUINT_8 pucCurrIePtr; ++ UINT_8 aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]; /* A common pool for IE of all scan results. */ ++}; ++ ++typedef enum { ++ ENUM_P2P_PEER_GROUP, ++ ENUM_P2P_PEER_DEVICE, ++ ENUM_P2P_PEER_NUM ++} ENUM_P2P_PEER_TYPE, *P_ENUM_P2P_PEER_TYPE; ++ ++typedef struct _P2P_DEVICE_INFO { ++ UINT_8 aucDevAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_8 aucIfAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucDevCapabilityBitmap; ++ INT_32 i4ConfigMethod; ++ UINT_8 aucPrimaryDeviceType[8]; ++ UINT_8 aucSecondaryDeviceType[8]; ++ UINT_8 aucDeviceName[P2P_DEVICE_NAME_LENGTH]; ++} P2P_DEVICE_INFO, *P_P2P_DEVICE_INFO; ++ ++typedef struct _P2P_GROUP_INFO { ++ PARAM_SSID_T rGroupID; ++ P2P_DEVICE_INFO rGroupOwnerInfo; ++ UINT_8 ucMemberNum; ++ P2P_DEVICE_INFO arMemberInfo[P2P_MEMBER_NUM]; ++} P2P_GROUP_INFO, *P_P2P_GROUP_INFO; ++ ++typedef struct _P2P_NETWORK_INFO { ++ ENUM_P2P_PEER_TYPE eNodeType; ++ ++ union { ++ P2P_GROUP_INFO rGroupInfo; ++ P2P_DEVICE_INFO rDeviceInfo; ++ } node; ++ ++} P2P_NETWORK_INFO, *P_P2P_NETWORK_INFO; ++ ++typedef struct _P2P_NETWORK_LIST { ++ UINT_8 ucNetworkNum; ++ P2P_NETWORK_INFO rP2PNetworkInfo[P2P_NETWORK_NUM]; ++} P2P_NETWORK_LIST, *P_P2P_NETWORK_LIST; ++ ++typedef struct _P2P_DISCONNECT_INFO { ++ UINT_8 ucRole; ++ UINT_8 ucRsv[3]; ++} P2P_DISCONNECT_INFO, *P_P2P_DISCONNECT_INFO; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_P2P_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h +new file mode 100644 +index 000000000000..7f7a92584c7c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h +@@ -0,0 +1,83 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "p2p_cmd_buf.h" ++ \brief In this file we define the structure for Command Packet. ++ ++ In this file we define the structure for Command Packet and the control unit ++ of MGMT Memory Pool. ++*/ ++ ++/* ++** Log: p2p_cmd_buf.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++*/ ++ ++#ifndef _P2P_CMD_BUF_H ++#define _P2P_CMD_BUF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Firmware Command Packer */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ BOOLEAN fgIsOid, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, ++ PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); ++ ++#endif /* _P2P_CMD_BUF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h +new file mode 100644 +index 000000000000..76115dabe1a1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h +@@ -0,0 +1,207 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_mac.h#2 ++*/ ++ ++/*! \file "p2p_mac.h" ++ \brief Brief description. ++ ++ Detail description. ++*/ ++ ++#ifndef _P2P_MAC_H ++#define _P2P_MAC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define ACTION_PUBLIC_WIFI_DIRECT 9 ++#define ACTION_GAS_INITIAL_REQUEST 10 ++#define ACTION_GAS_INITIAL_RESPONSE 11 ++#define ACTION_GAS_COMEBACK_REQUEST 12 ++#define ACTION_GAS_COMEBACK_RESPONSE 13 ++ ++/* P2P 4.2.8.1 - P2P Public Action Frame Type. */ ++#define P2P_PUBLIC_ACTION_GO_NEGO_REQ 0 ++#define P2P_PUBLIC_ACTION_GO_NEGO_RSP 1 ++#define P2P_PUBLIC_ACTION_GO_NEGO_CFM 2 ++#define P2P_PUBLIC_ACTION_INVITATION_REQ 3 ++#define P2P_PUBLIC_ACTION_INVITATION_RSP 4 ++#define P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ 5 ++#define P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP 6 ++#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ 7 ++#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP 8 ++ ++/* P2P 4.2.9.1 - P2P Action Frame Type */ ++#define P2P_ACTION_NOTICE_OF_ABSENCE 0 ++#define P2P_ACTION_P2P_PRESENCE_REQ 1 ++#define P2P_ACTION_P2P_PRESENCE_RSP 2 ++#define P2P_ACTION_GO_DISCOVER_REQ 3 ++ ++#define P2P_PUBLIC_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+8) ++#define P2P_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+7) ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/* P2P 4.2.8.2 P2P Public Action Frame Format */ ++typedef struct _P2P_PUBLIC_ACTION_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ ++ UINT_8 ucOuiType; /* 0x09 */ ++ UINT_8 ucOuiSubtype; /* GO Nego Req/Rsp/Cfm, P2P Invittion Req/Rsp, Device Discoverability Req/Rsp */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_8 aucInfoElem[1]; /* P2P IE, WSC IE. */ ++} __KAL_ATTRIB_PACKED__ P2P_PUBLIC_ACTION_FRAME_T, *P_P2P_PUBLIC_ACTION_FRAME_T; ++ ++/* P2P 4.2.9.1 - General Action Frame Format. */ ++typedef struct _P2P_ACTION_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Action Frame Body */ ++ UINT_8 ucCategory; /* 0x7F */ ++ UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ ++ UINT_8 ucOuiType; /* 0x09 */ ++ UINT_8 ucOuiSubtype; /* */ ++ UINT_8 ucDialogToken; ++ UINT_8 aucInfoElem[1]; ++} __KAL_ATTRIB_PACKED__ P2P_ACTION_FRAME_T, *P_P2P_ACTION_FRAME_T; ++ ++/* P2P C.1 GAS Public Action Initial Request Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T; ++ ++/* P2P C.2 GAS Public Action Initial Response Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_16 u2StatusCode; /* Initial Response. */ ++ UINT_16 u2ComebackDelay; /* Initial Response. *//* In unit of TU. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T; ++ ++/* P2P C.3-1 GAS Public Action Comeback Request Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T; ++ ++/* P2P C.3-2 GAS Public Action Comeback Response Frame Format */ ++typedef struct _GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T { ++ /* MAC header */ ++ UINT_16 u2FrameCtrl; /* Frame Control */ ++ UINT_16 u2Duration; /* Duration */ ++ UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ ++ UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ ++ UINT_16 u2SeqCtrl; /* Sequence Control */ ++ /* P2P Public Action Frame Body */ ++ UINT_8 ucCategory; /* Category, 0x04 */ ++ UINT_8 ucAction; /* Action Value, 0x09 */ ++ UINT_8 ucDialogToken; /* Dialog Token. */ ++ UINT_16 u2StatusCode; /* Comeback Response. */ ++ UINT_8 ucFragmentID; /*Comeback Response. */ ++ UINT_16 u2ComebackDelay; /* Comeback Response. */ ++ UINT_8 aucInfoElem[1]; /* Advertisement IE. */ ++} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T; ++ ++typedef struct _P2P_SD_VENDER_SPECIFIC_CONTENT_T { ++ /* Service Discovery Vendor-specific Content. */ ++ UINT_8 ucOuiSubtype; /* 0x09 */ ++ UINT_16 u2ServiceUpdateIndicator; ++ UINT_8 aucServiceTLV[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SD_VENDER_SPECIFIC_CONTENT_T, *P_P2P_SD_VENDER_SPECIFIC_CONTENT_T; ++ ++typedef struct _P2P_SERVICE_REQUEST_TLV_T { ++ UINT_16 u2Length; ++ UINT_8 ucServiceProtocolType; ++ UINT_8 ucServiceTransID; ++ UINT_8 aucQueryData[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SERVICE_REQUEST_TLV_T, *P_P2P_SERVICE_REQUEST_TLV_T; ++ ++typedef struct _P2P_SERVICE_RESPONSE_TLV_T { ++ UINT_16 u2Length; ++ UINT_8 ucServiceProtocolType; ++ UINT_8 ucServiceTransID; ++ UINT_8 ucStatusCode; ++ UINT_8 aucResponseData[1]; ++} __KAL_ATTRIB_PACKED__ P2P_SERVICE_RESPONSE_TLV_T, *P_P2P_SERVICE_RESPONSE_TLV_T; ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h +new file mode 100644 +index 000000000000..0a87bd457a92 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h +@@ -0,0 +1,62 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic.h#1 ++*/ ++ ++/*! \file "p2p_nic.h" ++ \brief The declaration of nic functions ++ ++ Detail description. ++*/ ++ ++#ifndef _P2P_NIC_H ++#define _P2P_NIC_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++VOID ++nicP2pMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); ++ ++VOID ++nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, ++ IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h +new file mode 100644 +index 000000000000..cea77414ce35 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h +@@ -0,0 +1,70 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic_cmd_event.h#1 ++*/ ++ ++/*! \file p2p_nic_cmd_event.h ++ \brief ++*/ ++ ++#ifndef _P2P_NIC_CMD_EVENT_H ++#define _P2P_NIC_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++typedef struct _EVENT_P2P_DEV_DISCOVER_RESULT_T { ++/* UINT_8 aucCommunicateAddr[MAC_ADDR_LEN]; // Deprecated. */ ++ UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 ucDeviceCapabilityBitmap; ++ UINT_8 ucGroupCapabilityBitmap; ++ UINT_16 u2ConfigMethod; /* Configure Method. */ ++ P2P_DEVICE_TYPE_T rPriDevType; ++ UINT_8 ucSecDevTypeNum; ++ P2P_DEVICE_TYPE_T arSecDevType[2]; ++ UINT_16 u2NameLength; ++ UINT_8 aucName[32]; ++ PUINT_8 pucIeBuf; ++ UINT_16 u2IELength; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ /* TODO: Service Information or PasswordID valid? */ ++} EVENT_P2P_DEV_DISCOVER_RESULT_T, *P_EVENT_P2P_DEV_DISCOVER_RESULT_T; ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h +new file mode 100644 +index 000000000000..dbfb90d94ee4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h +@@ -0,0 +1,971 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/que_mgt.h#1 ++*/ ++ ++/*! \file "que_mgt.h" ++ \brief TX/RX queues management header file ++ ++ The main tasks of queue management include TC-based HIF TX flow control, ++ adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save ++ forwarding control, RX packet reordering, and RX BA agreement management. ++*/ ++ ++/* ++** Log: que_mgt.h ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 07 26 2011 eddie.chen ++ * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter ++ * API for query the RX reorder queued packets counter. ++ * ++ * 06 14 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Change the parameter for WMM pass. ++ * ++ * 05 31 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Fix the QM quota in MT5931. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW ++ * Fix wmm parameters in beacon for BOW. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) Check Bss if support QoS before adding WMMIE ++ * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 07 22 2010 george.huang ++ * ++ * Update fgIsQoS information in BSS INFO by CMD ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 yarco.yang ++ * ++ * [WPD00003849] ++ * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 30 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled adaptive TC resource control ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 19 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * By default enabling dynamic STA_REC activation and decactivation ++ * ++ * 03 17 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) ++ * ++ * 03 11 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed buffer leak when processing BAR frames ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled multi-STA TX path with fairness ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled dynamically activating and deactivating STA_RECs ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for dynamic activating and deactivating STA_RECs. ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:04:53 GMT MTK02468 ++** Added RX buffer reordering function prototypes ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-02 22:08:44 GMT MTK02468 ++** Added macro QM_INIT_STA_REC for initialize a STA_REC ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 21:58:43 GMT mtk02468 ++** Initial version ++** ++*/ ++ ++#ifndef _QUE_MGT_H ++#define _QUE_MGT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* Queue Manager Features */ ++/* 1: Indicate the last TX packet to the FW for each burst */ ++#define QM_BURST_END_INFO_ENABLED 1 ++/* 1: To fairly share TX resource among active STAs */ ++#define QM_FORWARDING_FAIRNESS 1 ++/* 1: To adaptively adjust resource for each TC */ ++#define QM_ADAPTIVE_TC_RESOURCE_CTRL 1 ++/* 1: To print TC resource adjustment results */ ++#define QM_PRINT_TC_RESOURCE_CTRL 0 ++/* 1: If pkt with SSN is missing, auto advance the RX reordering window */ ++#define QM_RX_WIN_SSN_AUTO_ADVANCING 1 ++/* 1: Indicate the packets falling behind to OS before the frame with SSN is received */ ++#define QM_RX_INIT_FALL_BEHIND_PASS 1 ++/* 1: Count times of TC resource empty happened */ ++#define QM_TC_RESOURCE_EMPTY_COUNTER 1 ++/* Parameters */ ++ ++/* ++ In TDLS or AP mode, peer maybe enter "sleep mode". ++ ++ If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, ++ we need to wait 60 * u4TimeToAdjustTcResource = 180 packets ++ u4TimeToAdjustTcResource = 3, ++ then we will adjust TC resouce for VI or VO. ++ ++ But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, ++ we will to wait about 12 seconds to collect 180 packets. ++ but the test time is only 20 seconds. ++*/ ++#define QM_INIT_TIME_TO_UPDATE_QUE_LEN 60 /* p: Update queue lengths when p TX packets are enqueued */ ++#define QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN 5 ++ ++#define QM_INIT_TIME_TO_ADJUST_TC_RSC 3 /* s: Adjust the TC resource every s updates of queue lengths */ ++#define QM_QUE_LEN_MOVING_AVE_FACTOR 3 /* Factor for Que Len averaging */ ++ ++#define QM_MIN_RESERVED_TC0_RESOURCE 1 ++#define QM_MIN_RESERVED_TC1_RESOURCE 1 ++#define QM_MIN_RESERVED_TC2_RESOURCE 1 ++#define QM_MIN_RESERVED_TC3_RESOURCE 1 ++#define QM_MIN_RESERVED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_MIN_RESERVED_TC5_RESOURCE 1 ++ ++#if defined(MT6620) ++ ++#define QM_GUARANTEED_TC0_RESOURCE 4 ++#define QM_GUARANTEED_TC1_RESOURCE 4 ++#define QM_GUARANTEED_TC2_RESOURCE 9 ++#define QM_GUARANTEED_TC3_RESOURCE 11 ++#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_GUARANTEED_TC5_RESOURCE 4 ++ ++#elif defined(MT6628) ++ ++#define QM_GUARANTEED_TC0_RESOURCE 4 ++#define QM_GUARANTEED_TC1_RESOURCE 4 ++#define QM_GUARANTEED_TC2_RESOURCE 6 ++#define QM_GUARANTEED_TC3_RESOURCE 6 ++#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ ++#define QM_GUARANTEED_TC5_RESOURCE 4 ++ ++#else ++#error ++#endif ++ ++#define QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY 0 ++ ++#define QM_TOTAL_TC_RESOURCE (\ ++ NIC_TX_BUFF_COUNT_TC0 + NIC_TX_BUFF_COUNT_TC1 +\ ++ NIC_TX_BUFF_COUNT_TC2 + NIC_TX_BUFF_COUNT_TC3 +\ ++ NIC_TX_BUFF_COUNT_TC5) ++#define QM_AVERAGE_TC_RESOURCE 6 ++ ++/* Note: QM_INITIAL_RESIDUAL_TC_RESOURCE shall not be less than 0 */ ++/* for 6628: QM_TOTAL_TC_RESOURCE = 28, RESIDUAL = 4 4 6 6 2 4 = 26 */ ++#define QM_INITIAL_RESIDUAL_TC_RESOURCE (QM_TOTAL_TC_RESOURCE - \ ++ (QM_GUARANTEED_TC0_RESOURCE +\ ++ QM_GUARANTEED_TC1_RESOURCE +\ ++ QM_GUARANTEED_TC2_RESOURCE +\ ++ QM_GUARANTEED_TC3_RESOURCE +\ ++ QM_GUARANTEED_TC5_RESOURCE \ ++ )) ++ ++/* Hard-coded network type for Phase 3: NETWORK_TYPE_AIS/P2P/BOW */ ++#define QM_OPERATING_NETWORK_TYPE NETWORK_TYPE_AIS ++ ++#define QM_TEST_MODE 0 ++#define QM_TEST_TRIGGER_TX_COUNT 50 ++#define QM_TEST_STA_REC_DETERMINATION 0 ++#define QM_TEST_STA_REC_DEACTIVATION 0 ++#define QM_TEST_FAIR_FORWARDING 0 ++ ++#define QM_DEBUG_COUNTER 0 ++ ++/* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ ++/* Per-Type Queues: [0] BMCAST */ ++#define NUM_OF_PER_STA_TX_QUEUES 5 ++#define NUM_OF_PER_TYPE_TX_QUEUES 1 ++ ++/* These two constants are also used for FW to verify the STA_REC index */ ++#define STA_REC_INDEX_BMCAST 0xFF ++#define STA_REC_INDEX_NOT_FOUND 0xFE ++ ++/* TX Queue Index */ ++#define TX_QUEUE_INDEX_BMCAST 0 ++#define TX_QUEUE_INDEX_NO_STA_REC 0 ++#define TX_QUEUE_INDEX_AC0 0 ++#define TX_QUEUE_INDEX_AC1 1 ++#define TX_QUEUE_INDEX_AC2 2 ++#define TX_QUEUE_INDEX_AC3 3 ++#define TX_QUEUE_INDEX_802_1X 4 ++#define TX_QUEUE_INDEX_NON_QOS 1 ++ ++/* 1 WMM-related */ ++/* WMM FLAGS */ ++#define WMM_FLAG_SUPPORT_WMM BIT(0) ++#define WMM_FLAG_SUPPORT_WMMSA BIT(1) ++#define WMM_FLAG_AC_PARAM_PRESENT BIT(2) ++#define WMM_FLAG_SUPPORT_UAPSD BIT(3) ++ ++/* WMM Admission Control Mandatory FLAGS */ ++#define ACM_FLAG_ADM_NOT_REQUIRED 0 ++#define ACM_FLAG_ADM_GRANTED BIT(0) ++#define ACM_FLAG_ADM_REQUIRED BIT(1) ++ ++/* WMM Power Saving FLAGS */ ++#define AC_FLAG_TRIGGER_ENABLED BIT(1) ++#define AC_FLAG_DELIVERY_ENABLED BIT(2) ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MAX_LEN_WMM_INFO 7 ++ ++/* WMM-2.2.2 WMM Parameter Element */ ++#define ELEM_MAX_LEN_WMM_PARAM 24 ++ ++/* WMM-2.2.1 WMM QoS Info field */ ++#define WMM_QOS_INFO_PARAM_SET_CNT BITS(0, 3) /* Sent by AP */ ++#define WMM_QOS_INFO_UAPSD BIT(7) ++ ++#define WMM_QOS_INFO_VO_UAPSD BIT(0) /* Sent by non-AP STA */ ++#define WMM_QOS_INFO_VI_UAPSD BIT(1) ++#define WMM_QOS_INFO_BK_UAPSD BIT(2) ++#define WMM_QOS_INFO_BE_UAPSD BIT(3) ++#define WMM_QOS_INFO_MAX_SP_LEN_MASK BITS(5, 6) ++#define WMM_QOS_INFO_MAX_SP_ALL 0 ++#define WMM_QOS_INFO_MAX_SP_2 BIT(5) ++#define WMM_QOS_INFO_MAX_SP_4 BIT(6) ++#define WMM_QOS_INFO_MAX_SP_6 BITS(5, 6) ++ ++/* -- definitions for Max SP length field */ ++#define WMM_MAX_SP_LENGTH_ALL 0 ++#define WMM_MAX_SP_LENGTH_2 2 ++#define WMM_MAX_SP_LENGTH_4 4 ++#define WMM_MAX_SP_LENGTH_6 6 ++ ++/* WMM-2.2.2 WMM ACI/AIFSN field */ ++/* -- subfields in the ACI/AIFSN field */ ++#define WMM_ACIAIFSN_AIFSN BITS(0, 3) ++#define WMM_ACIAIFSN_ACM BIT(4) ++#define WMM_ACIAIFSN_ACI BITS(5, 6) ++#define WMM_ACIAIFSN_ACI_OFFSET 5 ++ ++/* -- definitions for ACI field */ ++#define WMM_ACI_AC_BE 0 ++#define WMM_ACI_AC_BK BIT(5) ++#define WMM_ACI_AC_VI BIT(6) ++#define WMM_ACI_AC_VO BITS(5, 6) ++ ++#define WMM_ACI(_AC) (_AC << WMM_ACIAIFSN_ACI_OFFSET) ++ ++/* -- definitions for ECWmin/ECWmax field */ ++#define WMM_ECW_WMIN_MASK BITS(0, 3) ++#define WMM_ECW_WMAX_MASK BITS(4, 7) ++#define WMM_ECW_WMAX_OFFSET 4 ++ ++#define TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME 0 /* Unit: 64 us */ ++ ++#define QM_RX_BA_ENTRY_MISS_TIMEOUT_MS (1000) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++enum { ++ QM_DBG_CNT_00 = 0, ++ QM_DBG_CNT_01, ++ QM_DBG_CNT_02, ++ QM_DBG_CNT_03, ++ QM_DBG_CNT_04, ++ QM_DBG_CNT_05, ++ QM_DBG_CNT_06, ++ QM_DBG_CNT_07, ++ QM_DBG_CNT_08, ++ QM_DBG_CNT_09, ++ QM_DBG_CNT_10, ++ QM_DBG_CNT_11, ++ QM_DBG_CNT_12, ++ QM_DBG_CNT_13, ++ QM_DBG_CNT_14, ++ QM_DBG_CNT_15, ++ QM_DBG_CNT_16, ++ QM_DBG_CNT_17, ++ QM_DBG_CNT_18, ++ QM_DBG_CNT_19, ++ QM_DBG_CNT_20, ++ QM_DBG_CNT_21, ++ QM_DBG_CNT_22, ++ QM_DBG_CNT_23, ++ QM_DBG_CNT_24, ++ QM_DBG_CNT_25, ++ QM_DBG_CNT_26, ++ QM_DBG_CNT_27, ++ QM_DBG_CNT_28, ++ QM_DBG_CNT_29, ++ QM_DBG_CNT_30, ++ QM_DBG_CNT_31, ++ QM_DBG_CNT_NUM ++}; ++ ++/* Used for MAC TX */ ++typedef enum _ENUM_MAC_TX_QUEUE_INDEX_T { ++ MAC_TX_QUEUE_AC0_INDEX = 0, ++ MAC_TX_QUEUE_AC1_INDEX, ++ MAC_TX_QUEUE_AC2_INDEX, ++ MAC_TX_QUEUE_AC3_INDEX, ++ MAC_TX_QUEUE_AC4_INDEX, ++ MAC_TX_QUEUE_AC5_INDEX, ++ MAC_TX_QUEUE_AC6_INDEX, ++ MAC_TX_QUEUE_BCN_INDEX, ++ MAC_TX_QUEUE_BMC_INDEX, ++ MAC_TX_QUEUE_NUM ++} ENUM_MAC_TX_QUEUE_INDEX_T; ++ ++typedef struct _RX_BA_ENTRY_T { ++ BOOLEAN fgIsValid; ++ QUE_T rReOrderQue; ++ UINT_16 u2WinStart; ++ UINT_16 u2WinEnd; ++ UINT_16 u2WinSize; ++ ++ /* For identifying the RX BA agreement */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucTid; ++ ++ BOOLEAN fgIsWaitingForPktWithSsn; ++ ++ /* UINT_8 ucTxBufferSize; */ ++ /* BOOL fgIsAcConstrain; */ ++ /* BOOL fgIsBaEnabled; */ ++} RX_BA_ENTRY_T, *P_RX_BA_ENTRY_T; ++ ++/* The mailbox message (could be used for Host-To-Device or Device-To-Host Mailbox) */ ++typedef struct _MAILBOX_MSG_T { ++ UINT_32 u4Msg[2]; /* [0]: D2HRM0R or H2DRM0R, [1]: D2HRM1R or H2DRM1R */ ++} MAILBOX_MSG_T, *P_MAILBOX_MSG_T; ++ ++/* Used for adaptively adjusting TC resources */ ++typedef struct _TC_RESOURCE_CTRL_T { ++ /* TC0, TC1, TC2, TC3, TC5 */ ++ UINT_32 au4AverageQueLen[TC_NUM - 1]; ++} TC_RESOURCE_CTRL_T, *P_TC_RESOURCE_CTRL_T; ++ ++typedef struct _QUE_MGT_T { /* Queue Management Control Info */ ++ ++ /* Per-Type Queues: [0] BMCAST or UNKNOWN-STA packets */ ++ QUE_T arTxQueue[NUM_OF_PER_TYPE_TX_QUEUES]; ++ ++#if 0 ++ /* For TX Scheduling */ ++ UINT_8 arRemainingTxOppt[NUM_OF_PER_STA_TX_QUEUES]; ++ UINT_8 arCurrentTxStaIndex[NUM_OF_PER_STA_TX_QUEUES]; ++ ++#endif ++ ++ /* Reordering Queue Parameters */ ++ RX_BA_ENTRY_T arRxBaTable[CFG_NUM_OF_RX_BA_AGREEMENTS]; ++ ++ /* Current number of activated RX BA agreements <= CFG_NUM_OF_RX_BA_AGREEMENTS */ ++ UINT_8 ucRxBaCount; ++ ++#if QM_TEST_MODE ++ UINT_32 u4PktCount; ++ P_ADAPTER_T prAdapter; ++ ++#if QM_TEST_FAIR_FORWARDING ++ UINT_32 u4CurrentStaRecIndexToEnqueue; ++#endif ++ ++#endif ++ ++#if QM_FORWARDING_FAIRNESS ++ /* The current TX count for a STA with respect to a TC index */ ++ UINT_32 au4ForwardCount[NUM_OF_PER_STA_TX_QUEUES]; ++ ++ /* The current serving STA with respect to a TC index */ ++ UINT_32 au4HeadStaRecIndex[NUM_OF_PER_STA_TX_QUEUES]; ++#endif ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ UINT_32 au4AverageQueLen[TC_NUM]; ++ UINT_32 au4CurrentTcResource[TC_NUM]; ++ UINT_32 au4MinReservedTcResource[TC_NUM]; /* The minimum amount of resource no matter busy or idle */ ++ UINT_32 au4GuaranteedTcResource[TC_NUM]; /* The minimum amount of resource when extremely busy */ ++ ++ UINT_32 u4TimeToAdjustTcResource; ++ UINT_32 u4TimeToUpdateQueLen; ++ UINT_32 u4TxNumOfVi, u4TxNumOfVo; /* number of VI/VO packets */ ++ ++ /* Set to TRUE if the last TC adjustment has not been completely applied (i.e., waiting more TX-Done events ++ to align the TC quotas to the TC resource assignment) */ ++ BOOLEAN fgTcResourcePostAnnealing; ++ ++#endif ++ ++#if QM_DEBUG_COUNTER ++ UINT_32 au4QmDebugCounters[QM_DBG_CNT_NUM]; ++#endif ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ UINT_32 au4QmTcResourceEmptyCounter[NET_TYPE_NUM][TC_NUM]; ++ UINT_32 au4QmTcResourceBackCounter[TC_NUM]; ++ UINT_32 au4DequeueNoTcResourceCounter[TC_NUM]; ++ ++ UINT_32 au4ResourceUsedCounter[TC_NUM]; ++ ++ UINT_32 au4ResourceWantedCounter[TC_NUM]; ++ ++ UINT_32 u4EnqeueuCounter; ++ UINT_32 u4DequeueCounter; ++#endif ++} QUE_MGT_T, *P_QUE_MGT_T; ++ ++typedef struct _EVENT_RX_ADDBA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Fields not present in the received ADDBA_REQ */ ++ UINT_8 ucStaRecIdx; ++ ++ /* Fields that are present in the received ADDBA_REQ */ ++ UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ ++ UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ ++ UINT_16 u2BATimeoutValue; ++ UINT_16 u2BAStartSeqCtrl; /* SSN */ ++ ++} EVENT_RX_ADDBA_T, *P_EVENT_RX_ADDBA_T; ++ ++typedef struct _EVENT_RX_DELBA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Fields not present in the received ADDBA_REQ */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucTid; ++} EVENT_RX_DELBA_T, *P_EVENT_RX_DELBA_T; ++ ++typedef struct _EVENT_BSS_ABSENCE_PRESENCE_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucNetTypeIdx; ++ BOOLEAN fgIsAbsent; ++ UINT_8 ucBssFreeQuota; ++ UINT_8 aucReserved[1]; ++} EVENT_BSS_ABSENCE_PRESENCE_T, *P_EVENT_BSS_ABSENCE_PRESENCE_T; ++ ++typedef struct _EVENT_STA_CHANGE_PS_MODE_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucStaRecIdx; ++ BOOLEAN fgIsInPs; ++ UINT_8 ucUpdateMode; ++ UINT_8 ucFreeQuota; ++} EVENT_STA_CHANGE_PS_MODE_T, *P_EVENT_STA_CHANGE_PS_MODE_T; ++ ++/* The free quota is used by PS only now */ ++/* The event may be used by per STA flow conttrol in general */ ++typedef struct _EVENT_STA_UPDATE_FREE_QUOTA_T { ++ /* Event header */ ++ UINT_16 u2Length; ++ UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ /* Event Body */ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucUpdateMode; ++ UINT_8 ucFreeQuota; ++ UINT_8 aucReserved[1]; ++} EVENT_STA_UPDATE_FREE_QUOTA_T, *P_EVENT_STA_UPDATE_FREE_QUOTA_T; ++ ++/* WMM-2.2.1 WMM Information Element */ ++typedef struct _IE_WMM_INFO_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ UINT_8 ucQosInfo; /* QoS Info field */ ++ UINT_8 ucDummy[3]; /* Dummy for pack */ ++} IE_WMM_INFO_T, *P_IE_WMM_INFO_T; ++ ++/* WMM-2.2.2 WMM Parameter Element */ ++typedef struct _IE_WMM_PARAM_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ ++ /* IE Body */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ ++ /* WMM IE Body */ ++ UINT_8 ucQosInfo; /* QoS Info field */ ++ UINT_8 ucReserved; ++ ++ /* AC Parameters */ ++ UINT_8 ucAciAifsn_BE; ++ UINT_8 ucEcw_BE; ++ UINT_8 aucTxopLimit_BE[2]; ++ ++ UINT_8 ucAciAifsn_BG; ++ UINT_8 ucEcw_BG; ++ UINT_8 aucTxopLimit_BG[2]; ++ ++ UINT_8 ucAciAifsn_VI; ++ UINT_8 ucEcw_VI; ++ UINT_8 aucTxopLimit_VI[2]; ++ ++ UINT_8 ucAciAifsn_VO; ++ UINT_8 ucEcw_VO; ++ UINT_8 aucTxopLimit_VO[2]; ++ ++} IE_WMM_PARAM_T, *P_IE_WMM_PARAM_T; ++ ++typedef struct _IE_WMM_TSPEC_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ /* WMM TSPEC body */ ++ UINT_8 aucTsInfo[3]; /* TS Info */ ++ UINT_8 aucTspecBodyPart[1]; /* Note: Utilize PARAM_QOS_TSPEC to fill (memory copy) */ ++} IE_WMM_TSPEC_T, *P_IE_WMM_TSPEC_T; ++ ++typedef struct _IE_WMM_HDR_T { ++ UINT_8 ucId; /* Element ID */ ++ UINT_8 ucLength; /* Length */ ++ UINT_8 aucOui[3]; /* OUI */ ++ UINT_8 ucOuiType; /* OUI Type */ ++ UINT_8 ucOuiSubtype; /* OUI Subtype */ ++ UINT_8 ucVersion; /* Version */ ++ UINT_8 aucBody[1]; /* IE body */ ++} IE_WMM_HDR_T, *P_IE_WMM_HDR_T; ++ ++typedef struct _AC_QUE_PARMS_T { ++ UINT_16 u2CWmin; /*!< CWmin */ ++ UINT_16 u2CWmax; /*!< CWmax */ ++ UINT_16 u2TxopLimit; /*!< TXOP limit */ ++ UINT_16 u2Aifsn; /*!< AIFSN */ ++ UINT_8 ucGuradTime; /*!< GuardTime for STOP/FLUSH. */ ++ BOOLEAN fgIsACMSet; ++} AC_QUE_PARMS_T, *P_AC_QUE_PARMS_T; ++ ++/* WMM ACI (AC index) */ ++typedef enum _ENUM_WMM_ACI_T { ++ WMM_AC_BE_INDEX = 0, ++ WMM_AC_BK_INDEX, ++ WMM_AC_VI_INDEX, ++ WMM_AC_VO_INDEX, ++ WMM_AC_INDEX_NUM ++} ENUM_WMM_ACI_T, *P_ENUM_WMM_ACI_T; ++ ++/* Used for CMD Queue Operation */ ++typedef enum _ENUM_FRAME_ACTION_T { ++ FRAME_ACTION_DROP_PKT = 0, ++ FRAME_ACTION_QUEUE_PKT, ++ FRAME_ACTION_TX_PKT, ++ FRAME_ACTION_NUM ++} ENUM_FRAME_ACTION_T; ++ ++typedef enum _ENUM_FRAME_TYPE_IN_CMD_Q_T { ++ FRAME_TYPE_802_1X = 0, ++ FRAME_TYPE_MMPDU, ++ FRAME_TYPE_NUM ++} ENUM_FRAME_TYPE_IN_CMD_Q_T; ++ ++typedef enum _ENUM_FREE_QUOTA_MODET_T { ++ FREE_QUOTA_UPDATE_MODE_INIT = 0, ++ FREE_QUOTA_UPDATE_MODE_OVERWRITE, ++ FREE_QUOTA_UPDATE_MODE_INCREASE, ++ FREE_QUOTA_UPDATE_MODE_DECREASE ++} ENUM_FREE_QUOTA_MODET_T, *P_ENUM_FREE_QUOTA_MODET_T; ++ ++typedef struct _CMD_UPDATE_WMM_PARMS_T { ++ AC_QUE_PARMS_T arACQueParms[AC_NUM]; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 fgIsQBSS; ++ UINT_8 aucReserved[2]; ++} CMD_UPDATE_WMM_PARMS_T, *P_CMD_UPDATE_WMM_PARMS_T; ++ ++typedef struct _CMD_TX_AMPDU_T { ++ BOOLEAN fgEnable; ++ UINT_8 aucReserved[3]; ++} CMD_TX_AMPDU_T, *P_CMD_TX_AMPDU_T; ++ ++typedef struct _CMD_ADDBA_REJECT { ++ BOOLEAN fgEnable; ++ UINT_8 aucReserved[3]; ++} CMD_ADDBA_REJECT_T, *P_CMD_ADDBA_REJECT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#define QM_TX_SET_NEXT_MSDU_INFO(_prMsduInfoPreceding, _prMsduInfoNext) \ ++ ((((_prMsduInfoPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prMsduInfoNext)) ++ ++#define QM_TX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ ++ ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) ++ ++#define QM_TX_GET_NEXT_MSDU_INFO(_prMsduInfo) \ ++ ((P_MSDU_INFO_T)(((_prMsduInfo)->rQueEntry).prNext)) ++ ++#define QM_RX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ ++ ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) ++ ++#define QM_RX_GET_NEXT_SW_RFB(_prSwRfb) \ ++ ((P_SW_RFB_T)(((_prSwRfb)->rQueEntry).prNext)) ++ ++#if 0 ++#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ ++ ((((_ucIndex) != STA_REC_INDEX_BMCAST) && ((_ucIndex) != STA_REC_INDEX_NOT_FOUND)) ?\ ++ &(_prAdapter->arStaRec[_ucIndex]) : NULL) ++#endif ++ ++#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ ++ cnmGetStaRecByIndex(_prAdapter, _ucIndex) ++ ++#define QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(\ ++ _prMsduInfo,\ ++ _ucTC,\ ++ _ucPacketType,\ ++ _ucFormatID,\ ++ _fgIs802_1x,\ ++ _fgIs802_11,\ ++ _u2PalLLH,\ ++ _u2AclSN,\ ++ _ucPsForwardingType,\ ++ _ucPsSessionID\ ++ ) \ ++{\ ++ ASSERT(_prMsduInfo);\ ++ (_prMsduInfo)->ucTC = (_ucTC);\ ++ (_prMsduInfo)->ucPacketType = (_ucPacketType);\ ++ (_prMsduInfo)->ucFormatID = (_ucFormatID);\ ++ (_prMsduInfo)->fgIs802_1x = (_fgIs802_1x);\ ++ (_prMsduInfo)->fgIs802_11 = (_fgIs802_11);\ ++ (_prMsduInfo)->u2PalLLH = (_u2PalLLH);\ ++ (_prMsduInfo)->u2AclSN = (_u2AclSN);\ ++ (_prMsduInfo)->ucPsForwardingType = (_ucPsForwardingType);\ ++ (_prMsduInfo)->ucPsSessionID = (_ucPsSessionID);\ ++ (_prMsduInfo)->fgIsBurstEnd = (FALSE);\ ++} ++ ++#define QM_INIT_STA_REC(\ ++ _prStaRec,\ ++ _fgIsValid,\ ++ _fgIsQoS,\ ++ _pucMacAddr\ ++ )\ ++{\ ++ ASSERT(_prStaRec);\ ++ (_prStaRec)->fgIsValid = (_fgIsValid);\ ++ (_prStaRec)->fgIsQoS = (_fgIsQoS);\ ++ (_prStaRec)->fgIsInPS = FALSE; \ ++ (_prStaRec)->ucPsSessionID = 0xFF;\ ++ COPY_MAC_ADDR((_prStaRec)->aucMacAddr, (_pucMacAddr));\ ++} ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++#define QM_GET_TX_QUEUE_LEN(_prAdapter, _u4QueIdx) \ ++ ((_prAdapter->rQM.au4AverageQueLen[(_u4QueIdx)] >> QM_QUE_LEN_MOVING_AVE_FACTOR)) ++#endif ++ ++#define WMM_IE_OUI_TYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiType) ++#define WMM_IE_OUI_SUBTYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiSubtype) ++#define WMM_IE_OUI(fp) (((P_IE_WMM_HDR_T)(fp))->aucOui) ++ ++#if QM_DEBUG_COUNTER ++#define QM_DBG_CNT_INC(_prQM, _index) { (_prQM)->au4QmDebugCounters[(_index)]++; } ++#else ++#define QM_DBG_CNT_INC(_prQM, _index) {} ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Queue Management and STA_REC Initialization */ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmInit(IN P_ADAPTER_T prAdapter); ++ ++#if QM_TEST_MODE ++VOID qmTestCases(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++ ++P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); ++ ++P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus); ++ ++VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter); ++ ++VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* RX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter); ++ ++P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); ++ ++VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); ++ ++VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); ++ ++VOID ++qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++BOOLEAN ++qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout); ++ ++VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); ++ ++VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg); ++ ++BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater); ++ ++VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid); ++ ++BOOLEAN ++qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize); ++ ++VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost); ++ ++VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); ++ ++VOID ++mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride); ++ ++VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams); ++ ++VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec); ++ ++/* Utility function: for deciding STA-REC index */ ++UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++UINT_32 ++mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, ++ UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf); ++ ++VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode); ++ ++VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++ENUM_FRAME_ACTION_T ++qmGetFrameAction(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, ++ IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType); ++ ++VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); ++ ++VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); ++ ++VOID ++qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone); ++ ++VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter); ++ ++#if ARP_MONITER_ENABLE ++VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++VOID qmResetArpDetect(VOID); ++VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++#endif ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _QUE_MGT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h +new file mode 100644 +index 000000000000..2804b0387f5f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h +@@ -0,0 +1,1010 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/wlan_def.h#1 ++*/ ++ ++/*! \file "wlan_def.h" ++ \brief This file includes the basic definition of WLAN ++ ++*/ ++ ++/* ++** Log: wlan_def.h ++** ++** 09 02 2013 cp.wu ++** add path to handle reassociation request ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 wh.su ++ * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw ++ * structure not align at byte ++ * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, ++ * Notice needed update P2P.ko. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Resize the Secondary Device Type array when WiFi Direct is enabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Add new station type MACRO. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 11 2010 kevin.huang ++ * [WCXRP00000068] [MT6620 Wi-Fi][Driver][FW] Fix STA RECORD sync issue and remove unused code ++ * Update ENUM_STA_ROLE_INDEX_T by using a fixed base value ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Update OP_MODE_BOW and include bow_fsm.h. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Change P2P Descriptor List to a pointer and allocate it dynamically to avoid structure corrupt by BssDescriptor free. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add a pointer in BSS Descriptor for P2P Descriptor. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add an Interface in BSS Descriptor. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Modify data structure for P2P Scan result. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add an operation mode for P2P device. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * P2P/RSN/WAPI IEs need to be declared with compact structure. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly ++ * dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Add P2P present boolean flag in BSS & Pre-BSS descriptor. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * move bss related data types to wlan_def.h to avoid recursive dependency. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:40 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_DEF_H ++#define _WLAN_DEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* disconnect reason */ ++#define DISCONNECT_REASON_CODE_RESERVED 0 ++#define DISCONNECT_REASON_CODE_RADIO_LOST 1 ++#define DISCONNECT_REASON_CODE_DEAUTHENTICATED 2 ++#define DISCONNECT_REASON_CODE_DISASSOCIATED 3 ++#define DISCONNECT_REASON_CODE_NEW_CONNECTION 4 ++#define DISCONNECT_REASON_CODE_REASSOCIATION 5 ++#define DISCONNECT_REASON_CODE_ROAMING 6 ++ ++/* The rate definitions */ ++#define TX_MODE_CCK 0x00 ++#define TX_MODE_OFDM 0x40 ++#define TX_MODE_HT_MM 0x80 ++#define TX_MODE_HT_GF 0xC0 ++ ++#define RATE_CCK_SHORT_PREAMBLE 0x10 ++#define RATE_OFDM 0x20 ++ ++#define PHY_RATE_1M 0x0 ++#define PHY_RATE_2M 0x1 ++#define PHY_RATE_5_5M 0x2 ++#define PHY_RATE_11M 0x3 ++#define PHY_RATE_6M 0xB ++#define PHY_RATE_9M 0xF ++#define PHY_RATE_12M 0xA ++#define PHY_RATE_18M 0xE ++#define PHY_RATE_24M 0x9 ++#define PHY_RATE_36M 0xD ++#define PHY_RATE_48M 0x8 ++#define PHY_RATE_54M 0xC ++#define PHY_RATE_MCS0 0x0 ++#define PHY_RATE_MCS1 0x1 ++#define PHY_RATE_MCS2 0x2 ++#define PHY_RATE_MCS3 0x3 ++#define PHY_RATE_MCS4 0x4 ++#define PHY_RATE_MCS5 0x5 ++#define PHY_RATE_MCS6 0x6 ++#define PHY_RATE_MCS7 0x7 ++#define PHY_RATE_MCS32 0x20 ++ ++#define RATE_CCK_1M_LONG (TX_MODE_CCK | PHY_RATE_1M) ++#define RATE_CCK_2M_LONG (TX_MODE_CCK | PHY_RATE_2M) ++#define RATE_CCK_5_5M_LONG (TX_MODE_CCK | PHY_RATE_5_5M) ++#define RATE_CCK_11M_LONG (TX_MODE_CCK | PHY_RATE_11M) ++#define RATE_CCK_2M_SHORT (TX_MODE_CCK | PHY_RATE_2M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_CCK_5_5M_SHORT (TX_MODE_CCK | PHY_RATE_5_5M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_CCK_11M_SHORT (TX_MODE_CCK | PHY_RATE_11M | RATE_CCK_SHORT_PREAMBLE) ++#define RATE_OFDM_6M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_6M) ++#define RATE_OFDM_9M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_9M) ++#define RATE_OFDM_12M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_12M) ++#define RATE_OFDM_18M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_18M) ++#define RATE_OFDM_24M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_24M) ++#define RATE_OFDM_36M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_36M) ++#define RATE_OFDM_48M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_48M) ++#define RATE_OFDM_54M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_54M) ++ ++#define RATE_MM_MCS_0 (TX_MODE_HT_MM | PHY_RATE_MCS0) ++#define RATE_MM_MCS_1 (TX_MODE_HT_MM | PHY_RATE_MCS1) ++#define RATE_MM_MCS_2 (TX_MODE_HT_MM | PHY_RATE_MCS2) ++#define RATE_MM_MCS_3 (TX_MODE_HT_MM | PHY_RATE_MCS3) ++#define RATE_MM_MCS_4 (TX_MODE_HT_MM | PHY_RATE_MCS4) ++#define RATE_MM_MCS_5 (TX_MODE_HT_MM | PHY_RATE_MCS5) ++#define RATE_MM_MCS_6 (TX_MODE_HT_MM | PHY_RATE_MCS6) ++#define RATE_MM_MCS_7 (TX_MODE_HT_MM | PHY_RATE_MCS7) ++#define RATE_MM_MCS_32 (TX_MODE_HT_MM | PHY_RATE_MCS32) ++ ++#define RATE_GF_MCS_0 (TX_MODE_HT_GF | PHY_RATE_MCS0) ++#define RATE_GF_MCS_1 (TX_MODE_HT_GF | PHY_RATE_MCS1) ++#define RATE_GF_MCS_2 (TX_MODE_HT_GF | PHY_RATE_MCS2) ++#define RATE_GF_MCS_3 (TX_MODE_HT_GF | PHY_RATE_MCS3) ++#define RATE_GF_MCS_4 (TX_MODE_HT_GF | PHY_RATE_MCS4) ++#define RATE_GF_MCS_5 (TX_MODE_HT_GF | PHY_RATE_MCS5) ++#define RATE_GF_MCS_6 (TX_MODE_HT_GF | PHY_RATE_MCS6) ++#define RATE_GF_MCS_7 (TX_MODE_HT_GF | PHY_RATE_MCS7) ++#define RATE_GF_MCS_32 (TX_MODE_HT_GF | PHY_RATE_MCS32) ++ ++#define RATE_TX_MODE_MASK BITS(6, 7) ++#define RATE_TX_MODE_OFFSET 6 ++#define RATE_CODE_GET_TX_MODE(_ucRateCode) ((_ucRateCode & RATE_TX_MODE_MASK) >> RATE_TX_MODE_OFFSET) ++#define RATE_PHY_RATE_MASK BITS(0, 5) ++#define RATE_PHY_RATE_OFFSET 0 ++#define RATE_CODE_GET_PHY_RATE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_MASK) >> RATE_PHY_RATE_OFFSET) ++#define RATE_PHY_RATE_SHORT_PREAMBLE BIT(4) ++#define RATE_CODE_IS_SHORT_PREAMBLE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_SHORT_PREAMBLE)?TRUE:FALSE) ++ ++#define CHNL_LIST_SZ_2G 14 ++#define CHNL_LIST_SZ_5G 14 ++ ++/*! CNM(STA_RECORD_T) related definition */ ++#define CFG_STA_REC_NUM 20 ++ ++/* PHY TYPE bit definitions */ ++#define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) /* HR/DSSS PHY (clause 18) */ ++#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) /* ERP PHY (clause 19) */ ++#define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) /* OFDM 5 GHz PHY (clause 17) */ ++#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) /* HT PHY (clause 20) */ ++ ++/* PHY TYPE set definitions */ ++#define PHY_TYPE_SET_802_11ABGN (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11BGN (PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11GN (PHY_TYPE_BIT_ERP | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11AN (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HT) ++ ++#define PHY_TYPE_SET_802_11ABG (PHY_TYPE_BIT_OFDM | \ ++ PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11BG (PHY_TYPE_BIT_HR_DSSS | \ ++ PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11A (PHY_TYPE_BIT_OFDM) ++ ++#define PHY_TYPE_SET_802_11G (PHY_TYPE_BIT_ERP) ++ ++#define PHY_TYPE_SET_802_11B (PHY_TYPE_BIT_HR_DSSS) ++ ++#define PHY_TYPE_SET_802_11N (PHY_TYPE_BIT_HT) ++ ++/* Rate set bit definitions */ ++#define RATE_SET_BIT_1M BIT(RATE_1M_INDEX) /* Bit 0: 1M */ ++#define RATE_SET_BIT_2M BIT(RATE_2M_INDEX) /* Bit 1: 2M */ ++#define RATE_SET_BIT_5_5M BIT(RATE_5_5M_INDEX) /* Bit 2: 5.5M */ ++#define RATE_SET_BIT_11M BIT(RATE_11M_INDEX) /* Bit 3: 11M */ ++#define RATE_SET_BIT_22M BIT(RATE_22M_INDEX) /* Bit 4: 22M */ ++#define RATE_SET_BIT_33M BIT(RATE_33M_INDEX) /* Bit 5: 33M */ ++#define RATE_SET_BIT_6M BIT(RATE_6M_INDEX) /* Bit 6: 6M */ ++#define RATE_SET_BIT_9M BIT(RATE_9M_INDEX) /* Bit 7: 9M */ ++#define RATE_SET_BIT_12M BIT(RATE_12M_INDEX) /* Bit 8: 12M */ ++#define RATE_SET_BIT_18M BIT(RATE_18M_INDEX) /* Bit 9: 18M */ ++#define RATE_SET_BIT_24M BIT(RATE_24M_INDEX) /* Bit 10: 24M */ ++#define RATE_SET_BIT_36M BIT(RATE_36M_INDEX) /* Bit 11: 36M */ ++#define RATE_SET_BIT_48M BIT(RATE_48M_INDEX) /* Bit 12: 48M */ ++#define RATE_SET_BIT_54M BIT(RATE_54M_INDEX) /* Bit 13: 54M */ ++#define RATE_SET_BIT_HT_PHY BIT(RATE_HT_PHY_INDEX) /* Bit 14: BSS Selector */ ++ ++/* Rate set definitions */ ++#define RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M) ++ ++#define RATE_SET_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_OFDM (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_18M | \ ++ RATE_SET_BIT_24M | \ ++ RATE_SET_BIT_36M | \ ++ RATE_SET_BIT_48M | \ ++ RATE_SET_BIT_54M) ++ ++#define RATE_SET_HT (RATE_SET_ERP) ++/* #define RATE_SET_HT (RATE_SET_ERP | RATE_SET_BIT_HT_PHY) *//* NOTE(Kevin): TBD */ ++ ++#define RATE_SET_ALL_ABG RATE_SET_ERP ++ ++#define BASIC_RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M) ++ ++#define BASIC_RATE_SET_HR_DSSS_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M) ++ ++#define BASIC_RATE_SET_ERP (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define BASIC_RATE_SET_OFDM (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define BASIC_RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define INITIAL_RATE_SET_RCPI_100 RATE_SET_ALL_ABG ++ ++#define INITIAL_RATE_SET_RCPI_80 (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M | \ ++ RATE_SET_BIT_9M | \ ++ RATE_SET_BIT_12M | \ ++ RATE_SET_BIT_24M) ++ ++#define INITIAL_RATE_SET_RCPI_60 (RATE_SET_BIT_1M | \ ++ RATE_SET_BIT_2M | \ ++ RATE_SET_BIT_5_5M | \ ++ RATE_SET_BIT_11M | \ ++ RATE_SET_BIT_6M) ++ ++#define INITIAL_RATE_SET(_rcpi) (INITIAL_RATE_SET_ ## _rcpi) ++ ++#define RCPI_100 100 /* -60 dBm */ ++#define RCPI_80 80 /* -70 dBm */ ++#define RCPI_60 60 /* -80 dBm */ ++ ++/* The number of RCPI records used to calculate their average value */ ++#define MAX_NUM_RCPI_RECORDS 10 ++ ++/* The number of RCPI records used to calculate their average value */ ++#define NO_RCPI_RECORDS -128 ++#define MAX_RCPI_DBM 0 ++#define MIN_RCPI_DBM -100 ++ ++#define MAC_TX_RESERVED_FIELD 0 /* NOTE(Kevin): Should defined in tx.h */ ++ ++#define MAX_ASSOC_ID (CFG_STA_REC_NUM) /* Available AID: 1 ~ 20(STA_REC_NUM) */ ++ ++#define MAX_DEAUTH_INFO_COUNT 4 /* NOTE(Kevin): Used in auth.c */ ++#define MIN_DEAUTH_INTERVAL_MSEC 500 /* The minimum interval if continuously send Deauth Frame */ ++ ++/* Authentication Type */ ++#define AUTH_TYPE_OPEN_SYSTEM BIT(AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++#define AUTH_TYPE_SHARED_KEY BIT(AUTH_ALGORITHM_NUM_SHARED_KEY) ++#define AUTH_TYPE_FAST_BSS_TRANSITION BIT(AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION) ++ ++/* Authentication Retry Limit */ ++#define TX_AUTH_ASSOCI_RETRY_LIMIT 2 ++#define TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING 1 ++ ++/* WMM-2.2.1 WMM Information Element */ ++#define ELEM_MAX_LEN_WMM_INFO 7 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_16 PHY_TYPE, *P_PHY_TYPE; ++typedef UINT_8 RCPI, *P_RCPI; ++typedef UINT_8 ALC_VAL, *P_ALC_VAL; ++ ++typedef enum _ENUM_HW_BSSID_T { ++ BSSID_0 = 0, ++ BSSID_1, ++ BSSID_NUM ++} ENUM_HW_BSSID_T; ++ ++typedef enum _ENUM_HW_MAC_ADDR_T { ++ MAC_ADDR_0 = 0, ++ MAC_ADDR_1, ++ MAC_ADDR_NUM ++} ENUM_HW_MAC_ADDR_T; ++ ++typedef enum _ENUM_HW_OP_MODE_T { ++ HW_OP_MODE_STA = 0, ++ HW_OP_MODE_AP, ++ HW_OP_MODE_ADHOC, ++ HW_OP_MODE_NUM ++} ENUM_HW_OP_MODE_T; ++ ++typedef enum _ENUM_TSF_T { ++ ENUM_LOCAL_TSF_0, ++ ENUM_LOCAL_TSF_1, ++ ENUM_LOCAL_TSF_NUM ++} ENUM_LOCAL_TSF_T, *P_ENUM_LOCAL_TSF_T; ++ ++typedef enum _HAL_TS_HW_UPDATE_MODE { ++ HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME, ++ HAL_TSF_HW_UPDATE_BY_TICK_ONLY, ++ HAL_TSF_HW_UPDATE_BY_RECEIVED_FRAME_ONLY, ++ HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME_AD_HOC ++} HAL_TSF_HW_UPDATE_MODE; ++ ++typedef enum _ENUM_AC_T { ++ AC0 = 0, ++ AC1, ++ AC2, ++ AC3, ++ AC_NUM ++} ENUM_AC_T, *P_ENUM_AC_T; ++ ++/* The Type of Network been activated */ ++typedef enum _ENUM_NETWORK_TYPE_INDEX_T { ++ NETWORK_TYPE_AIS_INDEX = 0, ++ NETWORK_TYPE_P2P_INDEX, ++ NETWORK_TYPE_BOW_INDEX, ++ NETWORK_TYPE_INDEX_NUM ++} ENUM_NETWORK_TYPE_INDEX_T; ++ ++/* The Type of STA Type. */ ++typedef enum _ENUM_STA_TYPE_INDEX_T { ++ STA_TYPE_LEGACY_INDEX = 0, ++ STA_TYPE_P2P_INDEX, ++ STA_TYPE_BOW_INDEX, ++ STA_TYPE_INDEX_NUM ++} ENUM_STA_TYPE_INDEX_T; ++ ++#define STA_ROLE_BASE_INDEX 4 ++ ++typedef enum _ENUM_STA_ROLE_INDEX_T { ++ STA_ROLE_ADHOC_INDEX = STA_ROLE_BASE_INDEX, /* 4 */ ++ STA_ROLE_CLIENT_INDEX, ++ STA_ROLE_AP_INDEX, ++ STA_ROLE_TDLS_INDEX, ++ STA_ROLE_DLS_INDEX /* Note: need to extend P_CMD_UPDATE_STA_RECORD_T */ ++} ENUM_STA_ROLE_INDEX_T; ++ ++/* The Power State of a specific Network */ ++typedef enum _ENUM_PWR_STATE_T { ++ PWR_STATE_IDLE = 0, ++ PWR_STATE_ACTIVE, ++ PWR_STATE_PS, ++ PWR_STATE_NUM ++} ENUM_PWR_STATE_T; ++ ++typedef enum _ENUM_PHY_TYPE_INDEX_T { ++ /* PHY_TYPE_DSSS_INDEX, *//* DSSS PHY (clause 15) -- Not used anymore */ ++ PHY_TYPE_HR_DSSS_INDEX = 0, /* HR/DSSS PHY (clause 18) */ ++ PHY_TYPE_ERP_INDEX, /* ERP PHY (clause 19) */ ++ PHY_TYPE_ERP_P2P_INDEX, /* ERP PHY (clause 19) w/o HR/DSSS */ ++ PHY_TYPE_OFDM_INDEX, /* OFDM 5 GHz PHY (clause 17) */ ++ PHY_TYPE_HT_INDEX, /* HT PHY (clause 20) */ ++ PHY_TYPE_INDEX_NUM /* 5 */ ++} ENUM_PHY_TYPE_INDEX_T, *P_ENUM_PHY_TYPE_INDEX_T; ++ ++typedef enum _ENUM_ACPI_STATE_T { ++ ACPI_STATE_D0 = 0, ++ ACPI_STATE_D1, ++ ACPI_STATE_D2, ++ ACPI_STATE_D3 ++} ENUM_ACPI_STATE_T; ++ ++/* The operation mode of a specific Network */ ++typedef enum _ENUM_OP_MODE_T { ++ OP_MODE_INFRASTRUCTURE = 0, /* Infrastructure/GC */ ++ OP_MODE_IBSS, /* AdHoc */ ++ OP_MODE_ACCESS_POINT, /* For GO */ ++ OP_MODE_P2P_DEVICE, /* P2P Device */ ++ OP_MODE_BOW, ++ OP_MODE_NUM ++} ENUM_OP_MODE_T, *P_ENUM_OP_MODE_T; ++ ++typedef enum _ENUM_CHNL_EXT_T { ++ CHNL_EXT_SCN = 0, ++ CHNL_EXT_SCA = 1, ++ CHNL_EXT_RES = 2, ++ CHNL_EXT_SCB = 3 ++} ENUM_CHNL_EXT_T, *P_ENUM_CHNL_EXT_T; ++ ++/* This starting freq of the band is unit of kHz */ ++typedef enum _ENUM_BAND_T { ++ BAND_NULL, ++ BAND_2G4, ++ BAND_5G, ++ BAND_NUM ++} ENUM_BAND_T, *P_ENUM_BAND_T; ++ ++/* Provide supported channel list to other components in array format */ ++typedef struct _RF_CHANNEL_INFO_T { ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannelNum; ++} RF_CHANNEL_INFO_T, *P_RF_CHANNEL_INFO_T; ++ ++typedef enum _ENUM_RATE_INDEX_T { ++ RATE_1M_INDEX = 0, /* 1M */ ++ RATE_2M_INDEX, /* 2M */ ++ RATE_5_5M_INDEX, /* 5.5M */ ++ RATE_11M_INDEX, /* 11M */ ++ RATE_22M_INDEX, /* 22M */ ++ RATE_33M_INDEX, /* 33M */ ++ RATE_6M_INDEX, /* 6M */ ++ RATE_9M_INDEX, /* 9M */ ++ RATE_12M_INDEX, /* 12M */ ++ RATE_18M_INDEX, /* 18M */ ++ RATE_24M_INDEX, /* 24M */ ++ RATE_36M_INDEX, /* 36M */ ++ RATE_48M_INDEX, /* 48M */ ++ RATE_54M_INDEX, /* 54M */ ++ RATE_HT_PHY_INDEX, /* BSS Selector - HT PHY */ ++ RATE_NUM /* 15 */ ++} ENUM_RATE_INDEX_T, *P_ENUM_RATE_INDEX_T; ++ ++typedef enum _ENUM_HT_RATE_INDEX_T { ++ HT_RATE_MCS0_INDEX = 0, ++ HT_RATE_MCS1_INDEX, ++ HT_RATE_MCS2_INDEX, ++ HT_RATE_MCS3_INDEX, ++ HT_RATE_MCS4_INDEX, ++ HT_RATE_MCS5_INDEX, ++ HT_RATE_MCS6_INDEX, ++ HT_RATE_MCS7_INDEX, ++ HT_RATE_MCS32_INDEX, ++ HT_RATE_NUM /* 9 */ ++} ENUM_HT_RATE_INDEX_T, *P_ENUM_HT_RATE_INDEX_T; ++ ++typedef enum _ENUM_PREMABLE_OPTION_T { ++ PREAMBLE_DEFAULT_LONG_NONE = 0, /* LONG for PHY_TYPE_HR_DSSS, NONE for PHY_TYPE_OFDM */ ++ PREAMBLE_OPTION_SHORT, /* SHORT mandatory for PHY_TYPE_ERP, SHORT option for PHY_TYPE_HR_DSSS */ ++ PREAMBLE_HT_MIXED_MODE, ++ PREAMBLE_HT_GREEN_FIELD, ++ PREAMBLE_OPTION_NUM ++} ENUM_PREMABLE_OPTION_T, *P_ENUM_PREMABLE_OPTION_T; ++ ++typedef enum _ENUM_CHANNEL_WIDTH_T { ++ CW_20_40MHZ = 0, ++ CW_80MHZ = 1, ++ CW_160MHZ = 2, ++ CW_80P80MHZ = 3 ++} ENUM_CHANNEL_WIDTH_T, *P_ENUM_CHANNEL_WIDTH_P; ++ ++typedef enum _ENUM_MODULATION_SYSTEM_T { ++ MODULATION_SYSTEM_CCK = 0, ++ MODULATION_SYSTEM_OFDM, ++ MODULATION_SYSTEM_HT20, ++ MODULATION_SYSTEM_HT40, ++ MODULATION_SYSTEM_NUM ++} ENUM_MODULATION_SYSTEM_T, *P_ENUM_MODULATION_SYSTEM_T; ++ ++typedef enum _ENUM_MODULATION_TYPE_T { ++ MODULATION_TYPE_CCK_BPSK = 0, ++ MODULATION_TYPE_QPSK, ++ MODULATION_TYPE_16QAM, ++ MODULATION_TYPE_64QAM, ++ MODULATION_TYPE_NUM ++} ENUM_MODULATION_TYPE_T, *P_ENUM_MODULATION_TYPE_T; ++ ++typedef enum _ENUM_PS_FORWARDING_TYPE_T { ++ PS_FORWARDING_TYPE_NON_PS = 0, ++ PS_FORWARDING_TYPE_DELIVERY_ENABLED, ++ PS_FORWARDING_TYPE_NON_DELIVERY_ENABLED, ++ PS_FORWARDING_MORE_DATA_ENABLED, ++ PS_FORWARDING_TYPE_NUM ++} ENUM_PS_FORWARDING_TYPE_T, *P_ENUM_PS_FORWARDING_TYPE_T; ++ ++typedef struct _DEAUTH_INFO_T { ++ UINT_8 aucRxAddr[MAC_ADDR_LEN]; ++ OS_SYSTIME rLastSendTime; ++} DEAUTH_INFO_T, *P_DEAUTH_INFO_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* Information Element (IE) handlers */ ++/*----------------------------------------------------------------------------*/ ++typedef VOID(*PFN_APPEND_IE_FUNC) (P_ADAPTER_T, P_MSDU_INFO_T); ++typedef VOID(*PFN_HANDLE_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T); ++typedef VOID(*PFN_VERIFY_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T, PUINT_16); ++typedef UINT_32(*PFN_CALCULATE_VAR_IE_LEN_FUNC) (P_ADAPTER_T, ENUM_NETWORK_TYPE_INDEX_T, P_STA_RECORD_T); ++ ++typedef struct _APPEND_IE_ENTRY_T { ++ UINT_16 u2EstimatedIELen; ++ PFN_APPEND_IE_FUNC pfnAppendIE; ++} APPEND_IE_ENTRY_T, *P_APPEND_IE_ENTRY_T; ++ ++typedef struct _APPEND_VAR_IE_ENTRY_T { ++ UINT_16 u2EstimatedFixedIELen; /* For Fixed Length */ ++ PFN_CALCULATE_VAR_IE_LEN_FUNC pfnCalculateVariableIELen; ++ PFN_APPEND_IE_FUNC pfnAppendIE; ++} APPEND_VAR_IE_ENTRY_T, *P_APPEND_VAR_IE_ENTRY_T; ++ ++typedef struct _HANDLE_IE_ENTRY_T { ++ UINT_8 ucElemID; ++ PFN_HANDLE_IE_FUNC pfnHandleIE; ++} HANDLE_IE_ENTRY_T, *P_HANDLE_IE_ENTRY_T; ++ ++typedef struct _VERIFY_IE_ENTRY_T { ++ UINT_8 ucElemID; ++ PFN_VERIFY_IE_FUNC pfnVarifyIE; ++} VERIFY_IE_ENTRY_T, *P_VERIFY_IE_ENTRY_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* Parameters of User Configuration */ ++/*----------------------------------------------------------------------------*/ ++typedef enum _ENUM_PARAM_CONNECTION_POLICY_T { ++ CONNECT_BY_SSID_BEST_RSSI = 0, ++ CONNECT_BY_SSID_GOOD_RSSI_MIN_CH_LOAD, ++ CONNECT_BY_SSID_ANY, /* NOTE(Kevin): Needed by WHQL */ ++ CONNECT_BY_BSSID, ++ CONNECT_BY_CUSTOMIZED_RULE /* NOTE(Kevin): TBD */ ++} ENUM_PARAM_CONNECTION_POLICY_T, *P_ENUM_PARAM_CONNECTION_POLICY_T; ++ ++typedef enum _ENUM_PARAM_PREAMBLE_TYPE_T { ++ PREAMBLE_TYPE_LONG = 0, ++ PREAMBLE_TYPE_SHORT, ++ PREAMBLE_TYPE_AUTO /*!< Try preamble short first, if fail tray preamble long. */ ++} ENUM_PARAM_PREAMBLE_TYPE_T, *P_ENUM_PARAM_PREAMBLE_TYPE_T; ++ ++/* This is enum defined for user to select a phy config listed in combo box */ ++typedef enum _ENUM_PARAM_PHY_CONFIG_T { ++ /*!< Can associated with 802.11abg AP but without n capability, Scan dual band. */ ++ PHY_CONFIG_802_11ABG = 0, ++ PHY_CONFIG_802_11BG, /*!< Can associated with 802_11bg AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11G, /*!< Can associated with 802_11g only AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11A, /*!< Can associated with 802_11a only AP, Scan single band and not report 2.4G BSSs. */ ++ PHY_CONFIG_802_11B, /*!< Can associated with 802_11b only AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11ABGN, /*!< Can associated with 802.11abgn AP, Scan dual band. */ ++ PHY_CONFIG_802_11BGN, /*!< Can associated with 802_11bgn AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_802_11AN, /*!< Can associated with 802_11an AP, Scan single band and not report 2.4G BSSs. */ ++ PHY_CONFIG_802_11GN, /*!< Can associated with 802_11gn AP, Scan single band and not report 5G BSSs. */ ++ PHY_CONFIG_NUM /* 9 */ ++} ENUM_PARAM_PHY_CONFIG_T, *P_ENUM_PARAM_PHY_CONFIG_T; ++ ++/* This is enum defined for user to select an AP Mode */ ++typedef enum _ENUM_PARAM_AP_MODE_T { ++ AP_MODE_11B = 0, /*!< Create 11b BSS if we support 802.11abg/802.11bg. */ ++ AP_MODE_MIXED_11BG, /*!< Create 11bg mixed BSS if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11G, /*!< Create 11g only BSS if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11G_P2P, /*!< Create 11g only BSS for P2P if we support 802.11abg/802.11bg/802.11g. */ ++ AP_MODE_11A, /*!< Create 11a only BSS if we support 802.11abg. */ ++ AP_MODE_NUM /* 4 */ ++} ENUM_PARAM_AP_MODE_T, *P_ENUM_PARAM_AP_MODE_T; ++ ++/* Masks for determining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ ++#define NETWORK_TYPE_AIS_MASK BIT(NETWORK_TYPE_AIS_INDEX) ++#define NETWORK_TYPE_P2P_MASK BIT(NETWORK_TYPE_P2P_INDEX) ++#define NETWORK_TYPE_BOW_MASK BIT(NETWORK_TYPE_BOW_INDEX) ++#define STA_TYPE_LEGACY_MASK BIT(STA_TYPE_LEGACY_INDEX) ++#define STA_TYPE_P2P_MASK BIT(STA_TYPE_P2P_INDEX) ++#define STA_TYPE_BOW_MASK BIT(STA_TYPE_BOW_INDEX) ++#define STA_TYPE_ADHOC_MASK BIT(STA_ROLE_ADHOC_INDEX) ++#define STA_TYPE_CLIENT_MASK BIT(STA_ROLE_CLIENT_INDEX) ++#define STA_TYPE_AP_MASK BIT(STA_ROLE_AP_INDEX) ++#define STA_TYPE_DLS_MASK BIT(STA_ROLE_DLS_INDEX) ++#define STA_TYPE_TDLS_MASK BIT(STA_ROLE_TDLS_INDEX) ++ ++/* Macros for obtaining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ ++#define IS_STA_IN_AIS(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++#define IS_STA_IN_P2P(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++#define IS_STA_IN_BOW(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++#define IS_STA_LEGACY_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_LEGACY_MASK) ++#define IS_STA_P2P_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_P2P_MASK) ++#define IS_STA_BOW_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_BOW_MASK) ++#define IS_ADHOC_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_ADHOC_MASK) ++#define IS_CLIENT_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_CLIENT_MASK) ++#define IS_AP_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_AP_MASK) ++#define IS_DLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_DLS_MASK) ++#define IS_TDLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_TDLS_MASK) ++ ++/* The ENUM_STA_TYPE_T accounts for ENUM_NETWORK_TYPE_T and ENUM_STA_ROLE_INDEX_T. ++ * * It is a merged version of Network Type and STA Role. ++ * */ ++typedef enum _ENUM_STA_TYPE_T { ++ STA_TYPE_LEGACY_AP = (STA_TYPE_LEGACY_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_LEGACY_CLIENT = (STA_TYPE_LEGACY_MASK | STA_TYPE_CLIENT_MASK), ++ STA_TYPE_ADHOC_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_ADHOC_MASK), ++#if CFG_ENABLE_WIFI_DIRECT ++ STA_TYPE_P2P_GO = (STA_TYPE_P2P_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_P2P_GC = (STA_TYPE_P2P_MASK | STA_TYPE_CLIENT_MASK), ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ STA_TYPE_BOW_AP = (STA_TYPE_BOW_MASK | STA_TYPE_AP_MASK), ++ STA_TYPE_BOW_CLIENT = (STA_TYPE_BOW_MASK | STA_TYPE_CLIENT_MASK), ++#endif ++ STA_TYPE_DLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_DLS_MASK), ++ STA_TYPE_TDLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_TDLS_MASK) ++} ENUM_STA_TYPE_T, *P_ENUM_STA_TYPE_T; ++ ++/* The type of BSS we discovered */ ++typedef enum _ENUM_BSS_TYPE_T { ++ BSS_TYPE_INFRASTRUCTURE = 1, ++ BSS_TYPE_IBSS, ++ BSS_TYPE_P2P_DEVICE, ++ BSS_TYPE_BOW_DEVICE, ++ BSS_TYPE_NUM ++} ENUM_BSS_TYPE_T, *P_ENUM_BSS_TYPE_T; ++ ++/*----------------------------------------------------------------------------*/ ++/* RSN structures */ ++/*----------------------------------------------------------------------------*/ ++/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ ++/* #pragma pack(1) */ ++/* #endif */ ++ ++#define MAX_NUM_SUPPORTED_CIPHER_SUITES 8 /* max number of supported cipher suites */ ++#if CFG_SUPPORT_802_11W ++#define MAX_NUM_SUPPORTED_AKM_SUITES 8 /* max number of supported AKM suites */ ++#else ++#define MAX_NUM_SUPPORTED_AKM_SUITES 6 /* max number of supported AKM suites */ ++#endif ++ ++/* Structure of RSN Information */ ++typedef struct _RSN_INFO_T { ++ UINT_8 ucElemId; ++ UINT_16 u2Version; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_32 u4PairwiseKeyCipherSuiteCount; ++ UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_CIPHER_SUITES]; ++ UINT_32 u4AuthKeyMgtSuiteCount; ++ UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_AKM_SUITES]; ++ UINT_16 u2RsnCap; ++ BOOLEAN fgRsnCapPresent; ++} /*__KAL_ATTRIB_PACKED__*/ RSN_INFO_T, *P_RSN_INFO_T; ++ ++#define MAX_NUM_SUPPORTED_WAPI_AKM_SUITES 1 /* max number of supported AKM suites */ ++#define MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES 1 /* max number of supported cipher suites */ ++ ++/* Structure of WAPI Information */ ++typedef struct _WAPI_INFO_T { ++ UINT_8 ucElemId; ++ UCHAR ucLength; ++ UINT_16 u2Version; ++ UINT_32 u4AuthKeyMgtSuiteCount; ++ UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_WAPI_AKM_SUITES]; ++ UINT_32 u4PairwiseKeyCipherSuiteCount; ++ UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES]; ++ UINT_32 u4GroupKeyCipherSuite; ++ UINT_16 u2WapiCap; ++ UINT_16 u2Bkid; ++ UINT_8 aucBkid[1][16]; ++} /* __KAL_ATTRIB_PACKED__ */ WAPI_INFO_T, *P_WAPI_INFO_T; ++ ++/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ ++/* #pragma pack() */ ++/* #endif */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++typedef struct _P2P_DEVICE_TYPE_T { ++ UINT_16 u2CategoryID; ++ UINT_16 u2SubCategoryID; ++} P2P_DEVICE_TYPE_T, *P_P2P_DEVICE_TYPE_T; ++ ++typedef struct _P2P_DEVICE_DESC_T { ++ LINK_ENTRY_T rLinkEntry; ++ BOOLEAN fgDevInfoValid; ++ UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ ++ UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Interface Address. */ ++ UINT_8 ucDeviceCapabilityBitmap; ++ UINT_8 ucGroupCapabilityBitmap; ++ UINT_16 u2ConfigMethod; /* Configure Method support. */ ++ P2P_DEVICE_TYPE_T rPriDevType; ++ UINT_8 ucSecDevTypeNum; ++ P2P_DEVICE_TYPE_T arSecDevType[8]; /* Reference to P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT */ ++ UINT_16 u2NameLength; ++ UINT_8 aucName[32]; /* Reference to WPS_ATTRI_MAX_LEN_DEVICE_NAME */ ++ /* TODO: Service Information or PasswordID valid? */ ++} P2P_DEVICE_DESC_T, *P_P2P_DEVICE_DESC_T; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static const UINT_8 aucRateIndex2RateCode[PREAMBLE_OPTION_NUM][RATE_NUM] = { ++ { /* Long Preamble */ ++ RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ ++ RATE_CCK_2M_LONG, /* RATE_2M_INDEX */ ++ RATE_CCK_5_5M_LONG, /* RATE_5_5M_INDEX */ ++ RATE_CCK_11M_LONG, /* RATE_11M_INDEX */ ++ RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ ++ RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ ++ RATE_OFDM_6M, /* RATE_6M_INDEX */ ++ RATE_OFDM_9M, /* RATE_9M_INDEX */ ++ RATE_OFDM_12M, /* RATE_12M_INDEX */ ++ RATE_OFDM_18M, /* RATE_18M_INDEX */ ++ RATE_OFDM_24M, /* RATE_24M_INDEX */ ++ RATE_OFDM_36M, /* RATE_36M_INDEX */ ++ RATE_OFDM_48M, /* RATE_48M_INDEX */ ++ RATE_OFDM_54M, /* RATE_54M_INDEX */ ++ }, ++ { /* Short Preamble */ ++ RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ ++ RATE_CCK_2M_SHORT, /* RATE_2M_INDEX */ ++ RATE_CCK_5_5M_SHORT, /* RATE_5_5M_INDEX */ ++ RATE_CCK_11M_SHORT, /* RATE_11M_INDEX */ ++ RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ ++ RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ ++ RATE_OFDM_6M, /* RATE_6M_INDEX */ ++ RATE_OFDM_9M, /* RATE_9M_INDEX */ ++ RATE_OFDM_12M, /* RATE_12M_INDEX */ ++ RATE_OFDM_18M, /* RATE_18M_INDEX */ ++ RATE_OFDM_24M, /* RATE_24M_INDEX */ ++ RATE_OFDM_36M, /* RATE_36M_INDEX */ ++ RATE_OFDM_48M, /* RATE_48M_INDEX */ ++ RATE_OFDM_54M, /* RATE_54M_INDEX */ ++ }, ++ { /* Mixed Mode(Option) */ ++ RATE_MM_MCS_0, /* RATE_MCS0_INDEX, */ ++ RATE_MM_MCS_1, /* RATE_MCS1_INDEX, */ ++ RATE_MM_MCS_2, /* RATE_MCS2_INDEX, */ ++ RATE_MM_MCS_3, /* RATE_MCS3_INDEX, */ ++ RATE_MM_MCS_4, /* RATE_MCS4_INDEX, */ ++ RATE_MM_MCS_5, /* RATE_MCS5_INDEX, */ ++ RATE_MM_MCS_6, /* RATE_MCS6_INDEX, */ ++ RATE_MM_MCS_7, /* RATE_MCS7_INDEX, */ ++ RATE_MM_MCS_32 /* RATE_MCS32_INDEX, */ ++ }, ++ { /* Green Field(Option) */ ++ RATE_GF_MCS_0, /* RATE_MCS0_INDEX, */ ++ RATE_GF_MCS_1, /* RATE_MCS1_INDEX, */ ++ RATE_GF_MCS_2, /* RATE_MCS2_INDEX, */ ++ RATE_GF_MCS_3, /* RATE_MCS3_INDEX, */ ++ RATE_GF_MCS_4, /* RATE_MCS4_INDEX, */ ++ RATE_GF_MCS_5, /* RATE_MCS5_INDEX, */ ++ RATE_GF_MCS_6, /* RATE_MCS6_INDEX, */ ++ RATE_GF_MCS_7, /* RATE_MCS7_INDEX, */ ++ RATE_GF_MCS_32 /* RATE_MCS32_INDEX, */ ++ } ++}; ++ ++static const UINT_8 aucRateTableSize[PREAMBLE_OPTION_NUM] = { ++ RATE_HT_PHY_INDEX, ++ RATE_HT_PHY_INDEX, ++ HT_RATE_NUM, ++ HT_RATE_NUM ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Macros to get and set the wireless LAN frame fields those are 16/32 bits in ++ length. */ ++#define WLAN_GET_FIELD_16(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_16)(_value_p) = ((UINT_16) __cp[0]) | ((UINT_16) __cp[1] << 8); \ ++ } ++ ++#define WLAN_GET_FIELD_BE16(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_16)(_value_p) = ((UINT_16) __cp[0] << 8) | ((UINT_16) __cp[1]); \ ++ } ++ ++#define WLAN_GET_FIELD_32(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_32)(_value_p) = ((UINT_32) __cp[0]) | ((UINT_32) __cp[1] << 8) | \ ++ ((UINT_32) __cp[2] << 16) | ((UINT_32) __cp[3] << 24); \ ++ } ++ ++#define WLAN_GET_FIELD_64(_memAddr_p, _value_p) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ *(PUINT_64)(_value_p) = \ ++ ((UINT_64) __cp[0]) | ((UINT_64) __cp[1] << 8) | \ ++ ((UINT_64) __cp[2] << 16) | ((UINT_64) __cp[3] << 24) | \ ++ ((UINT_64) __cp[4] << 32) | ((UINT_64) __cp[5] << 40) | \ ++ ((UINT_64) __cp[6] << 48) | ((UINT_64) __cp[7] << 56); \ ++ } ++ ++#define WLAN_SET_FIELD_16(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) (_value); \ ++ __cp[1] = (UINT_8) ((_value) >> 8); \ ++ } ++ ++#define WLAN_SET_FIELD_BE16(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) ((_value) >> 8); \ ++ __cp[1] = (UINT_8) (_value); \ ++ } ++ ++#define WLAN_SET_FIELD_32(_memAddr_p, _value) \ ++ { \ ++ PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ ++ __cp[0] = (UINT_8) (_value); \ ++ __cp[1] = (UINT_8) ((_value) >> 8); \ ++ __cp[2] = (UINT_8) ((_value) >> 16); \ ++ __cp[3] = (UINT_8) ((_value) >> 24); \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _WLAN_DEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h +new file mode 100644 +index 000000000000..aba2e040c194 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h +@@ -0,0 +1,2290 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_cmd_event.h#1 ++*/ ++ ++/*! \file "nic_cmd_event.h" ++ \brief This file contains the declairation file of the WLAN OID processing routines ++ of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: nic_cmd_event.h ++ * ++ * 03 29 2012 eason.tsai ++ * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define ++ * add conditional define. ++ * ++ * 03 04 2012 eason.tsai ++ * NULL ++ * modify the cal fail report code. ++ * ++ * 01 06 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * redefine the CMD_ID_SET_TXPWR_CTRL value. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 11 30 2011 cm.chang ++ * [WCXRP00001128] [MT5931 Wi-Fi][FW] Update BB/RF setting based on RF doc v0.7 for LGE spec ++ * 1. Add a new CMD for driver to set device mode ++ * 2. Update calibration parameters ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add TX_DONE status detail information. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 10 26 2011 cp.wu ++ * [WCXRP00001065] [MT6620 Wi-Fi][MT5931][FW][DRV] Adding parameter for controlling ++ * minimum channel dwell time for scanning ++ * add interface for control minimum channel dwell time for scanning. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * New CMD definition about RLM parameters ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 09 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * add osc stable time command structure ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than ++ * one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID ++ * support as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content ++ * check with firmware for valid MAC address. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 31 2011 chinglan.wang ++ * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. ++ * . ++ * ++ * 03 18 2011 cm.chang ++ * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command ++ * As CR title ++ * ++ * 03 17 2011 yarco.yang ++ * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 02 16 2011 cm.chang ++ * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism ++ * . ++ * ++ * 02 10 2011 cp.wu ++ * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers ++ * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Update cmd format of BSS INFO, always sync OwnMac to FW no matter P2P is enabled or not.. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * Add Stress test ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Sync HT operation element information from host to FW ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * report EEPROM used flag via NIC_CAPABILITY ++ * ++ * 12 28 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for ++ * initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 cp.wu ++ * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition ++ * follow-up for CMD_5G_PWR_OFFSET_T definition change ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 15 2010 cm.chang ++ * NULL ++ * Add new CMD for TX power, 5G power offset and power parameters ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a pointer in P2P SCAN RESULT structure. This pointer ++ * is pointed to a IE buffer for this P2p device. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add new CMD ID definition ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add a field in BSS INFO cmd to change interface address for P2P. (switching between Device Addr & Interface Addr) ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add interface address indication when indicate connection status. ++ * It is requested by supplicant to do 4 way handshake. ++ * ++ * 08 07 2010 wh.su ++ * NULL ++ * adding the privacy related code for P2P network ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Change data structure for P2P Device scan result, all channel time for scan command. ++ * ++ * 08 04 2010 george.huang ++ * NULL ++ * handle change PS mode OID/ CMD ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add P2P Device Found Event. ++ * Channel extension option in scan abort command. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add for P2P Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 george.huang ++ * ++ * DWORD align for the CMD data structure ++ * ++ * 07 20 2010 cp.wu ++ * ++ * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 09 2010 cp.wu ++ * ++ * reorder members of CMD_SET_BSS_INFO. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * update prStaRecOfAP with BSS-INFO. ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add BSS/STA_REC commands for integration. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add TX Done Event handle entry ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sync statistics data structure definition with firmware implementation ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * the frequency is used for adhoc connection only ++ * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list ++ * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 15 2010 kevin.huang ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Add event for activate STA_RECORD_T ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c ++ * 'cause it involves OS dependent data structure handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * 4. correct some HAL implementation ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * OID_802_11_RSSI, ++ * * * OID_802_11_RSSI_TRIGGER, ++ * * * OID_802_11_STATISTICS, ++ * * * OID_802_11_DISASSOCIATE, ++ * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-12-11 18:35:07 GMT mtk02752 ++** add CMD added in CMD/EVEN document v0.8 ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-12-10 16:39:37 GMT mtk02752 ++** eliminate unused definitions ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-12-10 09:55:11 GMT mtk02752 ++** command ID/event ID revised ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-09 13:57:37 GMT MTK02468 ++** Added event ids (EVENT_ID_RX_ADDBA and EVENT_ID_RX_DELBA) ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-08 17:35:39 GMT mtk02752 ++** + add event ID for EVENT_ID_TEST_STATUS (rf test) ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-12-07 23:01:09 GMT mtk02752 ++** add data structure for RF_TEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-12-03 16:22:56 GMT mtk01461 ++** Modify the element - i4RSSI in EVENT of SCAN RESULT ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-30 10:54:44 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T, while 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-26 10:16:58 GMT mtk02752 ++** resync EVENT_CONNECTION_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-25 21:34:01 GMT mtk02752 ++** sync. EVENT_SCAN_RESULT_T with firmware ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-25 21:03:48 GMT mtk02752 ++** refine MGMT_FRAME ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-25 18:17:47 GMT mtk02752 ++** refine GL_WLAN_INFO_T for buffering scan result and presume max. ie length = 600 bytes ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 22:41:20 GMT mtk02752 ++** add EVENT_SCAN_RESULT_T definition ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-11-23 20:29:16 GMT mtk02752 ++** fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-11-23 14:46:01 GMT mtk02752 ++** add new command/event structure upon CM@SD1's documentation ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-13 15:13:40 GMT mtk02752 ++** add command definition for CMD_BUILD_CONNECTION and EVENT_CONNECTION_STATUS ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-20 12:22:22 GMT mtk01461 ++** Add SeqNum field to Event Header ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:11 GMT mtk01461 ++** Update structure of HIF_EVENT_HEADER_T and EVENT_HDR_SIZE ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 12:10:36 GMT mtk01461 ++** Add Common Set CMD Callback for MCR Write and other Set OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:17 GMT mtk01461 ++** Command Done Handler ++*/ ++#ifndef _NIC_CMD_EVENT_H ++#define _NIC_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define CMD_STATUS_SUCCESS 0 ++#define CMD_STATUS_REJECTED 1 ++#define CMD_STATUS_UNKNOWN 2 ++ ++#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) ++ ++#define MAX_IE_LENGTH (600) ++#define MAX_WSC_IE_LENGTH (400) ++ ++/* Action field in structure CMD_CH_PRIVILEGE_T */ ++#define CMD_CH_ACTION_REQ 0 ++#define CMD_CH_ACTION_ABORT 1 ++ ++/* Status field in structure EVENT_CH_PRIVILEGE_T */ ++#define EVENT_CH_STATUS_GRANT 0 ++ ++#define SCN_PSCAN_SWC_RSSI_WIN_MAX 75 ++#define SCN_PSCAN_SWC_MAX_NUM 8 ++#define SCN_PSCAN_HOTLIST_REPORT_MAX_NUM 8 ++ ++typedef enum _ENUM_CMD_ID_T { ++ CMD_ID_TEST_MODE = 1, /* 0x01 (Set) */ ++ CMD_ID_RESET_REQUEST, /* 0x02 (Set) */ ++ CMD_ID_BUILD_CONNECTION, /* 0x03 (Set) */ ++ CMD_ID_SCAN_REQ_V2, /* 0x04 (Set) */ ++ CMD_ID_NIC_POWER_CTRL, /* 0x05 (Set) */ ++ CMD_ID_POWER_SAVE_MODE, /* 0x06 (Set) */ ++ CMD_ID_LINK_ATTRIB, /* 0x07 (Set) */ ++ CMD_ID_ADD_REMOVE_KEY, /* 0x08 (Set) */ ++ CMD_ID_DEFAULT_KEY_ID, /* 0x09 (Set) */ ++ CMD_ID_INFRASTRUCTURE, /* 0x0a (Set) */ ++ CMD_ID_SET_RX_FILTER, /* 0x0b (Set) */ ++ CMD_ID_DOWNLOAD_BUF, /* 0x0c (Set) */ ++ CMD_ID_WIFI_START, /* 0x0d (Set) */ ++ CMD_ID_CMD_BT_OVER_WIFI, /* 0x0e (Set) */ ++ CMD_ID_SET_MEDIA_CHANGE_DELAY_TIME, /* 0x0f (Set) */ ++ CMD_ID_SEND_ADDBA_RSP, /* 0x10 (Set) */ ++ CMD_ID_WAPI_MODE, /* 0x11 (Set) (obsolete) */ ++ CMD_ID_WAPI_ASSOC_INFO, /* 0x12 (Set) (obsolete) */ ++ CMD_ID_SET_DOMAIN_INFO, /* 0x13 (Set) */ ++ CMD_ID_SET_IP_ADDRESS, /* 0x14 (Set) */ ++ CMD_ID_BSS_ACTIVATE_CTRL, /* 0x15 (Set) */ ++ CMD_ID_SET_BSS_INFO, /* 0x16 (Set) */ ++ CMD_ID_UPDATE_STA_RECORD, /* 0x17 (Set) */ ++ CMD_ID_REMOVE_STA_RECORD, /* 0x18 (Set) */ ++ CMD_ID_INDICATE_PM_BSS_CREATED, /* 0x19 (Set) */ ++ CMD_ID_INDICATE_PM_BSS_CONNECTED, /* 0x1a (Set) */ ++ CMD_ID_INDICATE_PM_BSS_ABORT, /* 0x1b (Set) */ ++ CMD_ID_UPDATE_BEACON_CONTENT, /* 0x1c (Set) */ ++ CMD_ID_SET_BSS_RLM_PARAM, /* 0x1d (Set) */ ++ CMD_ID_SCAN_REQ, /* 0x1e (Set) */ ++ CMD_ID_SCAN_CANCEL, /* 0x1f (Set) */ ++ CMD_ID_CH_PRIVILEGE, /* 0x20 (Set) */ ++ CMD_ID_UPDATE_WMM_PARMS, /* 0x21 (Set) */ ++ CMD_ID_SET_WMM_PS_TEST_PARMS, /* 0x22 (Set) */ ++ CMD_ID_TX_AMPDU, /* 0x23 (Set) */ ++ CMD_ID_ADDBA_REJECT, /* 0x24 (Set) */ ++ CMD_ID_SET_PS_PROFILE_ADV, /* 0x25 (Set) */ ++ CMD_ID_SET_RAW_PATTERN, /* 0x26 (Set) */ ++ CMD_ID_CONFIG_PATTERN_FUNC, /* 0x27 (Set) */ ++ CMD_ID_SET_TX_PWR, /* 0x28 (Set) */ ++ CMD_ID_SET_5G_PWR_OFFSET, /* 0x29 (Set) */ ++ CMD_ID_SET_PWR_PARAM, /* 0x2A (Set) */ ++ CMD_ID_P2P_ABORT, /* 0x2B (Set) */ ++#if CFG_STRESS_TEST_SUPPORT ++ CMD_ID_RANDOM_RX_RESET_EN = 0x2C, /* 0x2C (Set ) */ ++ CMD_ID_RANDOM_RX_RESET_DE = 0x2D, /* 0x2D (Set ) */ ++ CMD_ID_SAPP_EN = 0x2E, /* 0x2E (Set ) */ ++ CMD_ID_SAPP_DE = 0x2F, /* 0x2F (Set ) */ ++#endif ++ CMD_ID_ROAMING_TRANSIT = 0x30, /* 0x30 (Set) */ ++ CMD_ID_SET_PHY_PARAM, /* 0x31 (Set) */ ++ CMD_ID_SET_NOA_PARAM, /* 0x32 (Set) */ ++ CMD_ID_SET_OPPPS_PARAM, /* 0x33 (Set) */ ++ CMD_ID_SET_UAPSD_PARAM, /* 0x34 (Set) */ ++ CMD_ID_SET_SIGMA_STA_SLEEP, /* 0x35 (Set) */ ++ CMD_ID_SET_EDGE_TXPWR_LIMIT, /* 0x36 (Set) */ ++ CMD_ID_SET_DEVICE_MODE, /* 0x37 (Set) */ ++ CMD_ID_SET_TXPWR_CTRL, /* 0x38 (Set) */ ++ CMD_ID_SET_AUTOPWR_CTRL, /* 0x39 (Set) */ ++ CMD_ID_SET_WFD_CTRL, /* 0x3A (Set) */ ++ CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, /* 0x3B (Set) */ ++ CMD_ID_SET_RSSI_COMPENSATE, /* 0x3C (Set) */ ++ CMD_ID_SET_BAND_SUPPORT = 0x3D, /* 0x3D (Set) */ ++ CMD_ID_SET_NLO_REQ, /* 0x3E (Set) */ ++ CMD_ID_SET_NLO_CANCEL, /* 0x3F (Set) */ ++ CMD_ID_SET_BATCH_REQ, /* 0x40 (Set) */ ++ CMD_ID_SET_WOWLAN, /* 0x41 (Set) */ /*CFG_SUPPORT_WOWLAN */ ++ CMD_ID_GET_PSCAN_CAPABILITY = 0x42, /* 0x42 (Set) */ ++ CMD_ID_SET_PSCN_ENABLE = 0x43, /* 0x43 (Set) */ ++ CMD_ID_SET_PSCAN_PARAM = 0x44, /* 0x44 (Set) */ ++ CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID = 0x45, /* 0x45 (Set) */ ++ CMD_ID_SET_PSCN_ADD_SW_BSSID = 0x46, /* 0x46 (Set) */ ++ CMD_ID_SET_PSCN_MAC_ADDR = 0x47, /* 0x47 (Set) */ ++ CMD_ID_GET_GSCN_SCN_RESULT = 0x48, /* 0x48 (Get) */ ++ CMD_ID_SET_COUNTRY_POWER_LIMIT = 0x4A, /* 0x4A (Set) */ ++ CMD_ID_SET_SYSTEM_SUSPEND = 0x60, /* 0x60 (Set) */ ++ CMD_ID_GET_NIC_CAPABILITY = 0x80, /* 0x80 (Query) */ ++ CMD_ID_GET_LINK_QUALITY, /* 0x81 (Query) */ ++ CMD_ID_GET_STATISTICS, /* 0x82 (Query) */ ++ CMD_ID_GET_CONNECTION_STATUS, /* 0x83 (Query) */ ++ CMD_ID_GET_ASSOC_INFO, /* 0x84 (Query) (obsolete) */ ++ CMD_ID_GET_STA_STATISTICS = 0x85, /* 0x85 (Query) */ ++ CMD_ID_GET_DEBUG_CODE = 0x86, /* 0x86 (Query) */ ++ CMD_ID_GET_LTE_CHN = 0x87, /* 0x87 (Query) */ ++ CMD_ID_GET_CHN_LOADING = 0x88, /* 0x88 (Query) */ ++ CMD_ID_GET_STATISTICS_PL = 0x89, /* 0x87 (Query) */ ++ CMD_ID_BASIC_CONFIG = 0xc1, /* 0xc1 (Set / Query) */ ++ CMD_ID_ACCESS_REG, /* 0xc2 (Set / Query) */ ++ CMD_ID_MAC_MCAST_ADDR, /* 0xc3 (Set / Query) */ ++ CMD_ID_802_11_PMKID, /* 0xc4 (Set / Query) */ ++ CMD_ID_ACCESS_EEPROM, /* 0xc5 (Set / Query) */ ++ CMD_ID_SW_DBG_CTRL, /* 0xc6 (Set / Query) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ CMD_ID_SEC_CHECK, /* 0xc7 (Set / Query) */ ++#endif ++ CMD_ID_DUMP_MEM, /* 0xc8 (Query) */ ++ ++ CMD_ID_CHIP_CONFIG = 0xCA, /* 0xca (Set / Query) */ ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ CMD_ID_SET_RDD_CH = 0xE1, ++#endif ++ ++ CMD_ID_SET_BWCS = 0xF1, ++ CMD_ID_SET_ROAMING_INFO = 0xF3, ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++ CMD_ID_GET_BUILD_DATE_CODE = 0xF8, ++#endif ++ CMD_ID_GET_BSS_INFO = 0xF9, ++#if 1 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION = 0xFA, /* 0xFA (Set) */ ++#endif ++ ++ CMD_ID_TDLS_CORE = 0xFC, ++ CMD_ID_STATS = 0xFD, ++ CMD_ID_TX_AR_ERR_CONFIG = 0xFF ++} ENUM_CMD_ID_T, *P_ENUM_CMD_ID_T; ++ ++typedef enum _ENUM_EVENT_ID_T { ++ EVENT_ID_CMD_RESULT = 1, /* 0x01 (Query) */ ++ EVENT_ID_NIC_CAPABILITY, /* 0x02 (Query) */ ++ EVENT_ID_CONNECTION_STATUS, /* 0x03 (Query / Unsolicited) (obsolete) */ ++ EVENT_ID_SCAN_RESULT, /* 0x04 (Query / Unsolicited) (obselete) */ ++ EVENT_ID_LINK_QUALITY, /* 0x05 (Query / Unsolicited) */ ++ EVENT_ID_STATISTICS, /* 0x06 (Query) */ ++ EVENT_ID_MIC_ERR_INFO, /* 0x07 (Unsolicited) */ ++ EVENT_ID_ASSOC_INFO, /* 0x08 (Query - CMD_ID_GET_ASSOC_INFO) */ ++ EVENT_ID_BASIC_CONFIG, /* 0x09 (Query - CMD_ID_BASIC_CONFIG) */ ++ EVENT_ID_ACCESS_REG, /* 0x0a (Query - CMD_ID_ACCESS_REG) */ ++ EVENT_ID_MAC_MCAST_ADDR, /* 0x0b (Query - CMD_ID_MAC_MCAST_ADDR) */ ++ EVENT_ID_802_11_PMKID, /* 0x0c (Query - CMD_ID_802_11_PMKID) */ ++ EVENT_ID_ACCESS_EEPROM, /* 0x0d (Query - CMD_ID_ACCESS_EEPROM) */ ++ EVENT_ID_SLEEPY_NOTIFY, /* 0x0e (Query) */ ++ EVENT_ID_BT_OVER_WIFI, /* 0x0f (Unsolicited) */ ++ EVENT_ID_TEST_STATUS, /* 0x10 (Query - CMD_ID_TEST_MODE) */ ++ EVENT_ID_RX_ADDBA, /* 0x11 (Unsolicited) (obsolete) */ ++ EVENT_ID_RX_DELBA, /* 0x12 (Unsolicited) (obsolete) */ ++ EVENT_ID_ACTIVATE_STA_REC_T, /* 0x13 (Unsolicited) */ ++ EVENT_ID_DEACTIVATE_STA_REC_T, /* 0x14 (Unsolicited) */ ++ EVENT_ID_SCAN_DONE, /* 0x15 (Unsoiicited) */ ++ EVENT_ID_RX_FLUSH, /* 0x16 (Unsolicited) */ ++ EVENT_ID_TX_DONE, /* 0x17 (Unsolicited) */ ++ EVENT_ID_CH_PRIVILEGE, /* 0x18 (Unsolicited) */ ++ EVENT_ID_BSS_ABSENCE_PRESENCE = 0x19, /* 0x19 (Unsolicited) */ ++ EVENT_ID_STA_CHANGE_PS_MODE, /* 0x1A (Unsolicited) */ ++ EVENT_ID_BSS_BEACON_TIMEOUT, /* 0x1B (Unsolicited) */ ++ EVENT_ID_UPDATE_NOA_PARAMS, /* 0x1C (Unsolicited) */ ++ EVENT_ID_AP_OBSS_STATUS, /* 0x1D (Unsolicited) */ ++ EVENT_ID_STA_UPDATE_FREE_QUOTA, /* 0x1E (Unsolicited) */ ++ EVENT_ID_SW_DBG_CTRL, /* 0x1F (Query - CMD_ID_SW_DBG_CTRL) */ ++ EVENT_ID_ROAMING_STATUS, /* 0x20 (Unsolicited) */ ++ EVENT_ID_STA_AGING_TIMEOUT, /* 0x21 (Unsolicited) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ EVENT_ID_SEC_CHECK_RSP, /* 0x22 (Unsolicited) */ ++#endif ++ EVENT_ID_SEND_DEAUTH, /* 0x23 (Unsolicited) */ ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ EVENT_ID_UPDATE_RDD_STATUS, /* 0x24 (Unsolicited) */ ++#endif ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ EVENT_ID_UPDATE_BWCS_STATUS = 0x25, /* 0x25 (Unsolicited) */ ++ EVENT_ID_UPDATE_BCM_DEBUG, /* 0x26 (Unsolicited) */ ++#endif ++ EVENT_ID_RX_ERR, ++ EVENT_ID_DUMP_MEM, ++ EVENT_ID_STA_STATISTICS = 0x29, /* 0x29 (Query ) */ ++ EVENT_ID_STA_STATISTICS_UPDATE, /* 0x2A (Unsolicited) */ ++ EVENT_ID_NLO_DONE = 0x2b, ++ ++ EVENT_ID_GSCAN_CAPABILITY = 0x30, ++ EVENT_ID_GSCAN_SCAN_COMPLETE = 0x31, ++ EVENT_ID_GSCAN_FULL_RESULT = 0x32, ++ EVENT_ID_GSCAN_SIGNIFICANT_CHANGE = 0x33, ++ EVENT_ID_GSCAN_GEOFENCE_FOUND = 0x34, ++ EVENT_ID_GSCAN_SCAN_AVAILABLE = 0x35, ++ EVENT_ID_GSCAN_RESULT = 0x36, ++ EVENT_ID_BATCH_RESULT = 0x37, ++ ++ EVENT_ID_TDLS = 0x80, ++ EVENT_ID_STATS_ENV = 0x81, ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++ EVENT_ID_BUILD_DATE_CODE = 0xF8, ++#endif ++ EVENT_ID_GET_AIS_BSS_INFO = 0xF9, ++ EVENT_ID_DEBUG_CODE = 0xFB, ++ EVENT_ID_RFTEST_READY = 0xFC, /* 0xFC */ ++ EVENT_ID_TX_DONE_STATUS = 0xFD, ++ EVENT_ID_FW_LOG_ENV = 0xFE, /* 0xFE, FW real time debug log */ ++} ENUM_EVENT_ID_T, *P_ENUM_EVENT_ID_T; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#ifndef LINUX ++typedef UINT_8 CMD_STATUS; ++#endif ++ ++typedef struct _EVENT_TX_DONE_STATUS_T { ++ UINT_8 ucPacketSeq; ++ UINT_8 ucStatus; ++ UINT_16 u2SequenceNumber; ++ UINT_32 au4Reserved1; ++ UINT_32 au4Reserved2; ++ UINT_32 au4Reserved3; ++ UINT_32 u4PktBufInfo; ++ UINT_8 aucPktBuf[200]; ++} EVENT_TX_DONE_STATUS_T, *P_EVENT_TX_DONE_STATUS_T; ++ ++/* for Event Packet (via HIF-RX) */ ++ /* following CM's documentation v0.7 */ ++typedef struct _WIFI_CMD_T { ++ UINT_16 u2TxByteCount_UserPriority; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucResource_PktType_CSflags; ++ UINT_8 ucCID; ++ UINT_8 ucSetQuery; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2; ++ ++ UINT_8 aucBuffer[0]; ++} WIFI_CMD_T, *P_WIFI_CMD_T; ++ ++/* for Command Packet (via HIF-TX) */ ++ /* following CM's documentation v0.7 */ ++typedef struct _WIFI_EVENT_T { ++ UINT_16 u2PacketLen; ++ UINT_16 u2PacketType; ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved2[2]; ++ ++ UINT_8 aucBuffer[0]; ++} WIFI_EVENT_T, *P_WIFI_EVENT_T; ++ ++/* CMD_ID_TEST_MODE */ ++typedef struct _CMD_TEST_CTRL_T { ++ UINT_8 ucAction; ++ UINT_8 aucReserved[3]; ++ union { ++ UINT_32 u4OpMode; ++ UINT_32 u4ChannelFreq; ++ PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; ++ } u; ++} CMD_TEST_CTRL_T, *P_CMD_TEST_CTRL_T; ++ ++/* EVENT_TEST_STATUS */ ++typedef struct _PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T { ++ UINT_32 u4PktSentStatus; ++ UINT_32 u4PktSentCount; ++ UINT_16 u2AvgAlc; ++ UINT_8 ucCckGainControl; ++ UINT_8 ucOfdmGainControl; ++} PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T { ++ UINT_32 u4IntRxOk; /*!< number of packets that Rx ok from interrupt */ ++ UINT_32 u4IntCrcErr; /*!< number of packets that CRC error from interrupt */ ++ UINT_32 u4IntShort; /*!< number of packets that is short preamble from interrupt */ ++ UINT_32 u4IntLong; /*!< number of packets that is long preamble from interrupt */ ++ UINT_32 u4PauRxPktCount; /*!< number of packets that Rx ok from PAU */ ++ UINT_32 u4PauCrcErrCount; /*!< number of packets that CRC error from PAU */ ++ UINT_32 u4PauRxFifoFullCount; /*!< number of packets that is short preamble from PAU */ ++ UINT_32 u4PauCCACount; /*!< CCA rising edge count */ ++} PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T; ++ ++typedef union _EVENT_TEST_STATUS { ++ PARAM_MTK_WIFI_TEST_STRUCT_T rATInfo; ++/* PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T rTxStatus; */ ++/* PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T rRxStatus; */ ++} EVENT_TEST_STATUS, *P_EVENT_TEST_STATUS; ++ ++/* CMD_BUILD_CONNECTION */ ++typedef struct _CMD_BUILD_CONNECTION { ++ UINT_8 ucInfraMode; ++ UINT_8 ucAuthMode; ++ UINT_8 ucEncryptStatus; ++ UINT_8 ucSsidLen; ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; ++ ++ /* Ad-hoc mode */ ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2ATIMWindow; ++ UINT_8 ucJoinOnly; ++ UINT_8 ucReserved; ++ UINT_32 u4FreqInKHz; ++ ++ /* for faster connection */ ++ UINT_8 aucScanResult[0]; ++} CMD_BUILD_CONNECTION, *P_CMD_BUILD_CONNECTION; ++ ++/* CMD_ADD_REMOVE_KEY */ ++typedef struct _CMD_802_11_KEY { ++ UINT_8 ucAddRemove; ++ UINT_8 ucTxKey; ++ UINT_8 ucKeyType; ++ UINT_8 ucIsAuthenticator; ++ UINT_8 aucPeerAddr[6]; ++ UINT_8 ucNetType; ++ UINT_8 ucAlgorithmId; ++ UINT_8 ucKeyId; ++ UINT_8 ucKeyLen; ++ UINT_8 aucReverved[2]; ++ UINT_8 aucKeyMaterial[32]; ++ UINT_8 aucKeyRsc[16]; ++} CMD_802_11_KEY, *P_CMD_802_11_KEY; ++ ++/* WPA2 PMKID cache structure */ ++typedef struct _PMKID_ENTRY_T { ++ PARAM_BSSID_INFO_T rBssidInfo; ++ BOOLEAN fgPmkidExist; ++} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; ++ ++typedef struct _CMD_802_11_PMKID { ++ ULONG u4BSSIDInfoCount; ++ P_PMKID_ENTRY_T arPMKIDInfo[1]; ++} CMD_802_11_PMKID, *P_CMD_802_11_PMKID; ++ ++/* CMD_BASIC_CONFIG */ ++typedef struct _CMD_CSUM_OFFLOAD { ++ UINT_16 u2RxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ ++ UINT_16 u2TxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ ++} CMD_CSUM_OFFLOAD, *P_CMD_CSUM_OFFLOAD; ++ ++typedef struct _CMD_BASIC_CONFIG { ++ PARAM_MAC_ADDRESS rMyMacAddr; ++ UINT_8 ucNative80211; ++ UINT_8 aucReserved[1]; ++ ++ CMD_CSUM_OFFLOAD rCsumOffload; ++} CMD_BASIC_CONFIG, *P_CMD_BASIC_CONFIG, EVENT_BASIC_CONFIG, *P_EVENT_BASIC_CONFIG; ++ ++/* CMD_MAC_MCAST_ADDR */ ++typedef struct _CMD_MAC_MCAST_ADDR { ++ UINT_32 u4NumOfGroupAddr; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[3]; ++ PARAM_MAC_ADDRESS arAddress[MAX_NUM_GROUP_ADDR]; ++} CMD_MAC_MCAST_ADDR, *P_CMD_MAC_MCAST_ADDR, EVENT_MAC_MCAST_ADDR, *P_EVENT_MAC_MCAST_ADDR; ++ ++/* CMD_ACCESS_EEPROM */ ++typedef struct _CMD_ACCESS_EEPROM { ++ UINT_16 u2Offset; ++ UINT_16 u2Data; ++} CMD_ACCESS_EEPROM, *P_CMD_ACCESS_EEPROM, EVENT_ACCESS_EEPROM, *P_EVENT_ACCESS_EEPROM; ++ ++typedef struct _CMD_CUSTOM_NOA_PARAM_STRUCT_T { ++ UINT_32 u4NoaDurationMs; ++ UINT_32 u4NoaIntervalMs; ++ UINT_32 u4NoaCount; ++} CMD_CUSTOM_NOA_PARAM_STRUCT_T, *P_CMD_CUSTOM_NOA_PARAM_STRUCT_T; ++ ++typedef struct _CMD_CUSTOM_OPPPS_PARAM_STRUCT_T { ++ UINT_32 u4CTwindowMs; ++} CMD_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_CMD_CUSTOM_OPPPS_PARAM_STRUCT_T; ++ ++typedef struct _CMD_CUSTOM_UAPSD_PARAM_STRUCT_T { ++ UINT_8 fgEnAPSD; ++ UINT_8 fgEnAPSD_AcBe; ++ UINT_8 fgEnAPSD_AcBk; ++ UINT_8 fgEnAPSD_AcVo; ++ UINT_8 fgEnAPSD_AcVi; ++ UINT_8 ucMaxSpLen; ++ UINT_8 aucResv[2]; ++} CMD_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_CMD_CUSTOM_UAPSD_PARAM_STRUCT_T; ++ ++/* EVENT_CONNECTION_STATUS */ ++typedef struct _EVENT_CONNECTION_STATUS { ++ UINT_8 ucMediaStatus; ++ UINT_8 ucReasonOfDisconnect; ++ ++ UINT_8 ucInfraMode; ++ UINT_8 ucSsidLen; ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; ++ UINT_8 ucAuthenMode; ++ UINT_8 ucEncryptStatus; ++ UINT_16 u2BeaconPeriod; ++ UINT_16 u2AID; ++ UINT_16 u2ATIMWindow; ++ UINT_8 ucNetworkType; ++ UINT_8 aucReserved[1]; ++ UINT_32 u4FreqInKHz; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 aucInterfaceAddr[PARAM_MAC_ADDR_LEN]; ++#endif ++ ++} EVENT_CONNECTION_STATUS, *P_EVENT_CONNECTION_STATUS; ++ ++/* EVENT_NIC_CAPABILITY */ ++typedef struct _EVENT_NIC_CAPABILITY { ++ UINT_16 u2ProductID; ++ UINT_16 u2FwVersion; ++ UINT_16 u2DriverVersion; ++ UINT_8 ucHw5GBandDisabled; ++ UINT_8 ucEepromUsed; ++ UINT_8 ucEfuseValid; ++ UINT_8 ucMacAddrValid; ++#if CFG_REPORT_RFBB_VERSION ++ UINT_8 ucRfVersion; ++ UINT_8 ucPhyVersion; ++#endif ++#if CFG_ENABLE_CAL_LOG ++ UINT_8 ucRfCalFail; ++ UINT_8 ucBbCalFail; ++#endif ++ ++#define FEATURE_SET_OFFSET_TDLS 0 ++#define FEATURE_SET_OFFSET_5G_SUPPORT 1 ++ UINT_8 ucFeatureSet; /* bit0: TDLS */ ++ ++ UINT_8 aucReserved[1]; ++#if CFG_EMBED_FIRMWARE_BUILD_DATE_CODE ++ UINT_8 aucDateCode[16]; ++#endif ++} EVENT_NIC_CAPABILITY, *P_EVENT_NIC_CAPABILITY; ++ ++/* modified version of WLAN_BEACON_FRAME_BODY_T for simplier buffering */ ++typedef struct _WLAN_BEACON_FRAME_BODY_T_LOCAL { ++ /* Beacon frame body */ ++ UINT_32 au4Timestamp[2]; /* Timestamp */ ++ UINT_16 u2BeaconInterval; /* Beacon Interval */ ++ UINT_16 u2CapInfo; /* Capability */ ++ UINT_8 aucInfoElem[MAX_IE_LENGTH]; /* Various IEs, start from SSID */ ++ UINT_16 u2IELength; /* This field is *NOT* carried by F/W but caculated by nic_rx */ ++} WLAN_BEACON_FRAME_BODY_T_LOCAL, *P_WLAN_BEACON_FRAME_BODY_T_LOCAL; ++ ++/* EVENT_SCAN_RESULT */ ++typedef struct _EVENT_SCAN_RESULT_T { ++ INT_32 i4RSSI; ++ UINT_32 u4LinkQuality; ++ UINT_32 u4DSConfig; /* Center frequency */ ++ UINT_32 u4DomainInfo; /* Require CM opinion */ ++ UINT_32 u4Reserved; ++ UINT_8 ucNetworkType; ++ UINT_8 ucOpMode; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; ++ WLAN_BEACON_FRAME_BODY_T_LOCAL rBeaconFrameBody; ++} EVENT_SCAN_RESULT_T, *P_EVENT_SCAN_RESULT_T; ++ ++/* event of tkip mic error */ ++typedef struct _EVENT_MIC_ERR_INFO { ++ UINT_32 u4Flags; ++} EVENT_MIC_ERR_INFO, *P_EVENT_MIC_ERR_INFO; ++ ++typedef struct _EVENT_PMKID_CANDIDATE_LIST_T { ++ UINT_32 u4Version; /*!< Version */ ++ UINT_32 u4NumCandidates; /*!< How many candidates follow */ ++ PARAM_PMKID_CANDIDATE_T arCandidateList[1]; ++} EVENT_PMKID_CANDIDATE_LIST_T, *P_EVENT_PMKID_CANDIDATE_LIST_T; ++ ++typedef struct _EVENT_CMD_RESULT { ++ UINT_8 ucCmdID; ++ UINT_8 ucStatus; ++ UINT_8 aucReserved[2]; ++} EVENT_CMD_RESULT, *P_EVENT_CMD_RESULT; ++ ++/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ ++typedef struct _CMD_ACCESS_REG { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} CMD_ACCESS_REG, *P_CMD_ACCESS_REG; ++ ++/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++typedef struct _CMD_ACCESS_CHN_LOAD { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++ UINT_16 u2Channel; ++ UINT_8 aucReserved[2]; ++} CMD_ACCESS_CHN_LOAD, *P_ACCESS_CHN_LOAD; ++ ++#endif ++/* CMD_DUMP_MEMORY */ ++typedef struct _CMD_DUMP_MEM { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++} CMD_DUMP_MEM, *P_CMD_DUMP_MEM; ++ ++typedef struct _EVENT_DUMP_MEM_T { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++ UINT_8 aucBuffer[1]; ++} EVENT_DUMP_MEM_T, *P_EVENT_DUMP_MEM_T; ++ ++typedef struct _CMD_SW_DBG_CTRL_T { ++ UINT_32 u4Id; ++ UINT_32 u4Data; ++ /* Debug Support */ ++ UINT_32 u4DebugCnt[64]; ++} CMD_SW_DBG_CTRL_T, *P_CMD_SW_DBG_CTRL_T; ++ ++/* CMD_ID_LINK_ATTRIB */ ++typedef struct _CMD_LINK_ATTRIB { ++ INT_8 cRssiTrigger; ++ UINT_8 ucDesiredRateLen; ++ UINT_16 u2DesiredRate[32]; ++ UINT_8 ucMediaStreamMode; ++ UINT_8 aucReserved[1]; ++} CMD_LINK_ATTRIB, *P_CMD_LINK_ATTRIB; ++ ++/* CMD_ID_NIC_POWER_CTRL */ ++typedef struct _CMD_NIC_POWER_CTRL { ++ UINT_8 ucPowerMode; ++ UINT_8 aucReserved[3]; ++} CMD_NIC_POWER_CTRL, *P_CMD_NIC_POWER_CTRL; ++ ++/* CMD_ID_POWER_SAVE_MODE */ ++typedef struct _CMD_PS_PROFILE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucPsProfile; ++ UINT_8 aucReserved[2]; ++} CMD_PS_PROFILE_T, *P_CMD_PS_PROFILE_T; ++ ++/* EVENT_LINK_QUALITY */ ++typedef struct _EVENT_LINK_QUALITY { ++ INT_8 cRssi; ++ INT_8 cLinkQuality; ++ UINT_16 u2LinkSpeed; ++ UINT_8 ucMediumBusyPercentage; ++} EVENT_LINK_QUALITY, *P_EVENT_LINK_QUALITY; ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++/* EVENT_LINK_QUALITY */ ++typedef struct _EVENT_LINK_QUALITY_EX { ++ INT_8 cRssi; ++ INT_8 cLinkQuality; ++ UINT_16 u2LinkSpeed; ++ UINT_8 ucMediumBusyPercentage; ++ UINT_8 ucIsLQ0Rdy; ++ INT_8 cRssiP2P; /* For P2P Network. */ ++ INT_8 cLinkQualityP2P; ++ UINT_16 u2LinkSpeedP2P; ++ UINT_8 ucMediumBusyPercentageP2P; ++ UINT_8 ucIsLQ1Rdy; ++} EVENT_LINK_QUALITY_EX, *P_EVENT_LINK_QUALITY_EX; ++#endif ++ ++/* EVENT_ID_STATISTICS */ ++typedef struct _EVENT_STATISTICS { ++ LARGE_INTEGER rTransmittedFragmentCount; ++ LARGE_INTEGER rMulticastTransmittedFrameCount; ++ LARGE_INTEGER rFailedCount; ++ LARGE_INTEGER rRetryCount; ++ LARGE_INTEGER rMultipleRetryCount; ++ LARGE_INTEGER rRTSSuccessCount; ++ LARGE_INTEGER rRTSFailureCount; ++ LARGE_INTEGER rACKFailureCount; ++ LARGE_INTEGER rFrameDuplicateCount; ++ LARGE_INTEGER rReceivedFragmentCount; ++ LARGE_INTEGER rMulticastReceivedFrameCount; ++ LARGE_INTEGER rFCSErrorCount; ++} EVENT_STATISTICS, *P_EVENT_STATISTICS; ++ ++/* EVENT_ID_FW_SLEEPY_NOTIFY */ ++typedef struct _EVENT_SLEEPY_NOTIFY { ++ UINT_8 ucSleepyState; ++ UINT_8 aucReserved[3]; ++} EVENT_SLEEPY_NOTIFY, *P_EVENT_SLEEPY_NOTIFY; ++ ++typedef struct _EVENT_ACTIVATE_STA_REC_T { ++ UINT_8 aucMacAddr[6]; ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucNetworkTypeIndex; ++ BOOLEAN fgIsQoS; ++ BOOLEAN fgIsAP; ++ UINT_8 aucReserved[2]; ++} EVENT_ACTIVATE_STA_REC_T, *P_EVENT_ACTIVATE_STA_REC_T; ++ ++typedef struct _EVENT_DEACTIVATE_STA_REC_T { ++ UINT_8 ucStaRecIdx; ++ UINT_8 aucReserved[3]; ++} EVENT_DEACTIVATE_STA_REC_T, *P_EVENT_DEACTIVATE_STA_REC_T; ++ ++/* CMD_BT_OVER_WIFI */ ++typedef struct _CMD_BT_OVER_WIFI { ++ UINT_8 ucAction; /* 0: query, 1: setup, 2: destroy */ ++ UINT_8 ucChannelNum; ++ PARAM_MAC_ADDRESS rPeerAddr; ++ UINT_16 u2BeaconInterval; ++ UINT_8 ucTimeoutDiscovery; ++ UINT_8 ucTimeoutInactivity; ++ UINT_8 ucRole; ++ UINT_8 PAL_Capabilities; ++ UINT_8 cMaxTxPower; ++ UINT_8 ucChannelBand; ++ UINT_8 ucReserved[1]; ++} CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI; ++ ++/* EVENT_BT_OVER_WIFI */ ++typedef struct _EVENT_BT_OVER_WIFI { ++ UINT_8 ucLinkStatus; ++ UINT_8 ucSelectedChannel; ++ INT_8 cRSSI; ++ UINT_8 ucReserved[1]; ++} EVENT_BT_OVER_WIFI, *P_EVENT_BT_OVER_WIFI; ++ ++/* Same with DOMAIN_SUBBAND_INFO */ ++typedef struct _CMD_SUBBAND_INFO { ++ UINT_8 ucRegClass; ++ UINT_8 ucBand; ++ UINT_8 ucChannelSpan; ++ UINT_8 ucFirstChannelNum; ++ UINT_8 ucNumChannels; ++ UINT_8 aucReserved[3]; ++} CMD_SUBBAND_INFO, *P_CMD_SUBBAND_INFO; ++ ++/* CMD_SET_DOMAIN_INFO */ ++typedef struct _CMD_SET_DOMAIN_INFO_T { ++ UINT_16 u2CountryCode; ++ UINT_16 u2IsSetPassiveScan; /* 0: set channel domain; 1: set passive scan channel domain */ ++ CMD_SUBBAND_INFO rSubBand[6]; ++ ++ UINT_8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ ++ UINT_8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ ++ UINT_8 aucReserved[2]; ++} CMD_SET_DOMAIN_INFO_T, *P_CMD_SET_DOMAIN_INFO_T; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++/* CMD_SET_PWR_LIMIT_TABLE */ ++typedef struct _CMD_CHANNEL_POWER_LIMIT { ++ UINT_8 ucCentralCh; ++ INT_8 cPwrLimitCCK; ++ INT_8 cPwrLimit20; ++ INT_8 cPwrLimit40; ++ INT_8 cPwrLimit80; ++ INT_8 cPwrLimit160; ++ UINT_8 ucFlag; ++ UINT_8 aucReserved[1]; ++} CMD_CHANNEL_POWER_LIMIT, *P_CMD_CHANNEL_POWER_LIMIT; ++ ++typedef struct _CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T { ++ UINT_16 u2CountryCode; ++ UINT_8 ucCountryFlag; ++ UINT_8 ucNum; ++ UINT_8 aucReserved[4]; ++ CMD_CHANNEL_POWER_LIMIT rChannelPowerLimit[1]; ++} CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T, *P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T; ++ ++#endif ++ ++/* CMD_SET_IP_ADDRESS */ ++typedef struct _IPV4_NETWORK_ADDRESS { ++ UINT_8 aucIpAddr[4]; ++} IPV4_NETWORK_ADDRESS, *P_IPV4_NETWORK_ADDRESS; ++ ++typedef struct _CMD_SET_NETWORK_ADDRESS_LIST { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucAddressCount; ++ UINT_8 ucReserved[2]; ++ IPV4_NETWORK_ADDRESS arNetAddress[1]; ++} CMD_SET_NETWORK_ADDRESS_LIST, *P_CMD_SET_NETWORK_ADDRESS_LIST; ++ ++typedef struct _PATTERN_DESCRIPTION { ++ UINT_8 fgCheckBcA1; ++ UINT_8 fgCheckMcA1; ++ UINT_8 ePatternHeader; ++ UINT_8 fgAndOp; ++ UINT_8 fgNotOp; ++ UINT_8 ucPatternMask; ++ UINT_16 ucPatternOffset; ++ UINT_8 aucPattern[8]; ++} PATTERN_DESCRIPTION, *P_PATTERN_DESCRIPTION; ++ ++typedef struct _CMD_RAW_PATTERN_CONFIGURATION_T { ++ PATTERN_DESCRIPTION arPatternDesc[4]; ++} CMD_RAW_PATTERN_CONFIGURATION_T, *P_CMD_RAW_PATTERN_CONFIGURATION_T; ++ ++typedef struct _CMD_PATTERN_FUNC_CONFIG { ++ BOOLEAN fgBcA1En; ++ BOOLEAN fgMcA1En; ++ BOOLEAN fgBcA1MatchDrop; ++ BOOLEAN fgMcA1MatchDrop; ++} CMD_PATTERN_FUNC_CONFIG, *P_CMD_PATTERN_FUNC_CONFIG; ++ ++typedef struct _EVENT_TX_DONE_T { ++ UINT_8 ucPacketSeq; ++ UINT_8 ucStatus; ++ UINT_16 u2SequenceNumber; ++ UINT_32 au4Reserved1; ++ UINT_32 au4Reserved2; ++ UINT_32 au4Reserved3; ++} EVENT_TX_DONE_T, *P_EVENT_TX_DONE_T; ++ ++typedef struct _CMD_BSS_ACTIVATE_CTRL { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucActive; ++ UINT_8 aucReserved[2]; ++} CMD_BSS_ACTIVATE_CTRL, *P_CMD_BSS_ACTIVATE_CTRL; ++ ++typedef struct _CMD_SET_BSS_RLM_PARAM_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucRfBand; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucErpProtectMode; ++ UINT_8 ucHtProtectMode; ++ UINT_8 ucGfOperationMode; ++ UINT_8 ucTxRifsMode; ++ UINT_16 u2HtOpInfo3; ++ UINT_16 u2HtOpInfo2; ++ UINT_8 ucHtOpInfo1; ++ UINT_8 ucUseShortPreamble; ++ UINT_8 ucUseShortSlotTime; ++ UINT_8 ucCheckId; /* Fixed value: 0x72 */ ++} CMD_SET_BSS_RLM_PARAM_T, *P_CMD_SET_BSS_RLM_PARAM_T; ++ ++typedef struct _CMD_SET_BSS_INFO { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucConnectionState; ++ UINT_8 ucCurrentOPMode; ++ UINT_8 ucSSIDLen; ++ UINT_8 aucSSID[32]; ++ UINT_8 aucBSSID[6]; ++ UINT_8 ucIsQBSS; ++ UINT_8 ucReserved1; ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ UINT_8 ucStaRecIdxOfAP; ++ UINT_8 ucReserved2; ++ UINT_8 ucReserved3; ++ UINT_8 ucNonHTBasicPhyType; /* For Slot Time and CWmin */ ++ UINT_8 ucAuthMode; ++ UINT_8 ucEncStatus; ++ UINT_8 ucPhyTypeSet; ++ UINT_8 aucOwnMac[6]; ++ UINT_8 fgWapiMode; ++ UINT_8 fgIsApMode; ++ UINT_8 fgHiddenSsidMode; ++ CMD_SET_BSS_RLM_PARAM_T rBssRlmParam; ++} CMD_SET_BSS_INFO, *P_CMD_SET_BSS_INFO; ++ ++typedef struct _CMD_UPDATE_STA_RECORD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucStaType; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_16 u2AssocId; ++ UINT_16 u2ListenInterval; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDesiredPhyTypeSet; ++ UINT_16 u2DesiredNonHTRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ UINT_8 ucIsQoS; ++ UINT_8 ucIsUapsdSupported; ++ UINT_8 ucStaState; ++ UINT_8 ucMcsSet; ++ UINT_8 ucSupMcs32; ++ UINT_8 ucAmpduParam; ++ UINT_16 u2HtCapInfo; ++ UINT_16 u2HtExtendedCap; ++ UINT_32 u4TxBeamformingCap; ++ UINT_8 ucAselCap; ++ UINT_8 ucRCPI; ++ UINT_8 ucNeedResp; ++ UINT_8 ucUapsdAc; /* b0~3: Trigger enabled, b4~7: Delivery enabled */ ++ UINT_8 ucUapsdSp; /* 0: all, 1: max 2, 2: max 4, 3: max 6 */ ++ UINT_8 aucReserved[3]; ++ /* TBD */ ++} CMD_UPDATE_STA_RECORD_T, *P_CMD_UPDATE_STA_RECORD_T; ++ ++typedef struct _CMD_REMOVE_STA_RECORD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucReserved; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++} CMD_REMOVE_STA_RECORD_T, *P_CMD_REMOVE_STA_RECORD_T; ++ ++typedef struct _CMD_INDICATE_PM_BSS_CREATED_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDtimPeriod; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2AtimWindow; ++ UINT_8 aucReserved[2]; ++} CMD_INDICATE_PM_BSS_CREATED, *P_CMD_INDICATE_PM_BSS_CREATED; ++ ++typedef struct _CMD_INDICATE_PM_BSS_CONNECTED_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucDtimPeriod; ++ UINT_16 u2AssocId; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2AtimWindow; ++ UINT_8 fgIsUapsdConnection; ++ UINT_8 ucBmpDeliveryAC; ++ UINT_8 ucBmpTriggerAC; ++ UINT_8 aucReserved[1]; ++} CMD_INDICATE_PM_BSS_CONNECTED, *P_CMD_INDICATE_PM_BSS_CONNECTED; ++ ++typedef struct _CMD_INDICATE_PM_BSS_ABORT { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[3]; ++} CMD_INDICATE_PM_BSS_ABORT, *P_CMD_INDICATE_PM_BSS_ABORT; ++ ++typedef struct _CMD_BEACON_TEMPLATE_UPDATE { ++ UINT_8 ucUpdateMethod; /* 0: update randomly, ++ * 1: update all, ++ * 2: delete all (1 and 2 will update directly without search) ++ */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_16 u2Capability; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_BEACON_TEMPLATE_UPDATE, *P_CMD_BEACON_TEMPLATE_UPDATE; ++ ++typedef struct _CMD_SET_WMM_PS_TEST_STRUCT_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ ++ UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ ++} CMD_SET_WMM_PS_TEST_STRUCT_T, *P_CMD_SET_WMM_PS_TEST_STRUCT_T; ++ ++/* Definition for CHANNEL_INFO.ucBand: ++ * 0: Reserved ++ * 1: BAND_2G4 ++ * 2: BAND_5G ++ * Others: Reserved ++ */ ++typedef struct _CHANNEL_INFO_T { ++ UINT_8 ucBand; ++ UINT_8 ucChannelNum; ++} CHANNEL_INFO_T, *P_CHANNEL_INFO_T; ++ ++typedef struct _CMD_SCAN_REQ_EXT_CH_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucReserved[1]; ++ UINT_16 u2ChannelMinDwellTime; ++ UINT_8 aucSSID[32]; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_EXT_CH, *P_CMD_SCAN_REQ_EXT_CH; ++ ++typedef struct _CMD_SCAN_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ ++ UINT_8 ucSSIDLength; ++ UINT_8 aucReserved[1]; ++ UINT_16 u2ChannelMinDwellTime; ++ UINT_8 aucSSID[32]; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[32]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ, *P_CMD_SCAN_REQ; ++ ++typedef struct _CMD_SCAN_REQ_V2_EXT_CH_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; ++ PARAM_SSID_T arSSID[4]; ++ UINT_16 u2ProbeDelayTime; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_V2_EXT_CH, *P_CMD_SCAN_REQ_V2_EXT_CH; ++ ++typedef struct _CMD_SCAN_REQ_V2_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetworkType; ++ UINT_8 ucScanType; ++ UINT_8 ucSSIDType; ++ PARAM_SSID_T arSSID[4]; ++ UINT_16 u2ProbeDelayTime; ++ UINT_16 u2ChannelDwellTime; /* For P2P */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ CHANNEL_INFO_T arChannelList[32]; ++ UINT_16 u2IELen; ++ UINT_8 aucIE[MAX_IE_LENGTH]; ++} CMD_SCAN_REQ_V2, *P_CMD_SCAN_REQ_V2; ++ ++typedef struct _CMD_SCAN_CANCEL_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucIsExtChannel; /* For P2P channel extension. */ ++ UINT_8 aucReserved[2]; ++} CMD_SCAN_CANCEL, *P_CMD_SCAN_CANCEL; ++ ++typedef struct _EVENT_SCAN_DONE_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucSparseChannelValid; ++ CHANNEL_INFO_T rSparseChannel; ++} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; ++ ++#if CFG_SUPPORT_GET_CH_ENV ++typedef struct _CH_ENV_T { ++ UINT_8 ucChNum; ++ UINT_8 ucApNum; ++} CH_ENV_T, *P_CH_ENV_T; ++#endif ++ ++#if 0 /* CFG_SUPPORT_BATCH_SCAN */ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd ++ like approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++typedef struct _EVENT_BATCH_RESULT_ENTRY_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ INT_8 cRssi; ++ UINT_32 ucFreq; ++ UINT_32 u4Age; ++ UINT_32 u4Dist; ++ UINT_32 u4Distsd; ++} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; ++ ++typedef struct _EVENT_BATCH_RESULT_T { ++ UINT_8 ucScanCount; ++ UINT_8 aucReserved[3]; ++ EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ ++} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; ++#endif ++ ++typedef struct _CMD_CH_PRIVILEGE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucAction; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucRfBand; ++ UINT_8 ucReqType; ++ UINT_8 ucReserved; ++ UINT_32 u4MaxInterval; /* In unit of ms */ ++ UINT_8 aucBSSID[6]; ++ UINT_8 aucReserved[2]; ++} CMD_CH_PRIVILEGE_T, *P_CMD_CH_PRIVILEGE_T; ++ ++typedef struct _CMD_TX_PWR_T { ++ INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ ++#if defined(MT6620) ++ INT_8 acReserved[3]; ++#elif defined(MT6628) ++ INT_8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ ++ INT_8 acReserved[2]; ++#else ++#error "No valid definition!" ++#endif ++ ++ INT_8 cTxPwr2G4OFDM_BPSK; ++ INT_8 cTxPwr2G4OFDM_QPSK; ++ INT_8 cTxPwr2G4OFDM_16QAM; ++ INT_8 cTxPwr2G4OFDM_Reserved; ++ INT_8 cTxPwr2G4OFDM_48Mbps; ++ INT_8 cTxPwr2G4OFDM_54Mbps; ++ ++ INT_8 cTxPwr2G4HT20_BPSK; ++ INT_8 cTxPwr2G4HT20_QPSK; ++ INT_8 cTxPwr2G4HT20_16QAM; ++ INT_8 cTxPwr2G4HT20_MCS5; ++ INT_8 cTxPwr2G4HT20_MCS6; ++ INT_8 cTxPwr2G4HT20_MCS7; ++ ++ INT_8 cTxPwr2G4HT40_BPSK; ++ INT_8 cTxPwr2G4HT40_QPSK; ++ INT_8 cTxPwr2G4HT40_16QAM; ++ INT_8 cTxPwr2G4HT40_MCS5; ++ INT_8 cTxPwr2G4HT40_MCS6; ++ INT_8 cTxPwr2G4HT40_MCS7; ++ ++ INT_8 cTxPwr5GOFDM_BPSK; ++ INT_8 cTxPwr5GOFDM_QPSK; ++ INT_8 cTxPwr5GOFDM_16QAM; ++ INT_8 cTxPwr5GOFDM_Reserved; ++ INT_8 cTxPwr5GOFDM_48Mbps; ++ INT_8 cTxPwr5GOFDM_54Mbps; ++ ++ INT_8 cTxPwr5GHT20_BPSK; ++ INT_8 cTxPwr5GHT20_QPSK; ++ INT_8 cTxPwr5GHT20_16QAM; ++ INT_8 cTxPwr5GHT20_MCS5; ++ INT_8 cTxPwr5GHT20_MCS6; ++ INT_8 cTxPwr5GHT20_MCS7; ++ ++ INT_8 cTxPwr5GHT40_BPSK; ++ INT_8 cTxPwr5GHT40_QPSK; ++ INT_8 cTxPwr5GHT40_16QAM; ++ INT_8 cTxPwr5GHT40_MCS5; ++ INT_8 cTxPwr5GHT40_MCS6; ++ INT_8 cTxPwr5GHT40_MCS7; ++} CMD_TX_PWR_T, *P_CMD_TX_PWR_T; ++ ++typedef struct _CMD_5G_PWR_OFFSET_T { ++ INT_8 cOffsetBand0; /* 4.915-4.980G */ ++ INT_8 cOffsetBand1; /* 5.000-5.080G */ ++ INT_8 cOffsetBand2; /* 5.160-5.180G */ ++ INT_8 cOffsetBand3; /* 5.200-5.280G */ ++ INT_8 cOffsetBand4; /* 5.300-5.340G */ ++ INT_8 cOffsetBand5; /* 5.500-5.580G */ ++ INT_8 cOffsetBand6; /* 5.600-5.680G */ ++ INT_8 cOffsetBand7; /* 5.700-5.825G */ ++} CMD_5G_PWR_OFFSET_T, *P_CMD_5G_PWR_OFFSET_T; ++ ++typedef struct _CMD_PWR_PARAM_T { ++ UINT_32 au4Data[28]; ++ UINT_32 u4RefValue1; ++ UINT_32 u4RefValue2; ++} CMD_PWR_PARAM_T, *P_CMD_PWR_PARAM_T; ++ ++typedef struct _CMD_PHY_PARAM_T { ++ UINT_8 aucData[144]; /* eFuse content */ ++} CMD_PHY_PARAM_T, *P_CMD_PHY_PARAM_T; ++ ++typedef struct _CMD_AUTO_POWER_PARAM_T { ++ UINT_8 ucType; /* 0: Disable 1: Enalbe 0x10: Change parameters */ ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_8 aucLevelRcpiTh[3]; ++ UINT_8 aucReserved2[1]; ++ INT_8 aicLevelPowerOffset[3]; /* signed, in unit of 0.5dBm */ ++ UINT_8 aucReserved3[1]; ++ UINT_8 aucReserved4[8]; ++} CMD_AUTO_POWER_PARAM_T, *P_CMD_AUTO_POWER_PARAM_T; ++ ++typedef struct _EVENT_CH_PRIVILEGE_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucTokenID; ++ UINT_8 ucStatus; ++ UINT_8 ucPrimaryChannel; ++ UINT_8 ucRfSco; ++ UINT_8 ucRfBand; ++ UINT_8 ucReqType; ++ UINT_8 ucReserved; ++ UINT_32 u4GrantInterval; /* In unit of ms */ ++} EVENT_CH_PRIVILEGE_T, *P_EVENT_CH_PRIVILEGE_T; ++ ++typedef enum _ENUM_BEACON_TIMEOUT_TYPE_T { ++ BEACON_TIMEOUT_LOST_BEACON = 0, ++ BEACON_TIMEOUT_AGE, ++ BEACON_TIMEOUT_CONNECT, ++ BEACON_TIMEOUT_BEACON_INTERVAL, ++ BEACON_TIMEOUT_ABORT, ++ BEACON_TIMEOUT_TX_ERROR, ++ BEACON_TIMEOUT_TYPE_NUM ++} ENUM_BEACON_TIMEOUT_TYPE_T, *P_ENUM_BEACON_TIMEOUT_TYPE_T; ++ ++typedef struct _EVENT_BSS_BEACON_TIMEOUT_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucReason; /* ENUM_BEACON_TIMEOUT_TYPE_T */ ++ UINT_8 aucReserved[2]; ++} EVENT_BSS_BEACON_TIMEOUT_T, *P_EVENT_BSS_BEACON_TIMEOUT_T; ++ ++typedef struct _EVENT_STA_AGING_TIMEOUT_T { ++ UINT_8 ucStaRecIdx; ++ UINT_8 aucReserved[3]; ++} EVENT_STA_AGING_TIMEOUT_T, *P_EVENT_STA_AGING_TIMEOUT_T; ++ ++typedef struct _EVENT_NOA_TIMING_T { ++ UINT_8 fgIsInUse; /* Indicate if this entry is in use or not */ ++ UINT_8 ucCount; /* Count */ ++ UINT_8 aucReserved[2]; ++ ++ UINT_32 u4Duration; /* Duration */ ++ UINT_32 u4Interval; /* Interval */ ++ UINT_32 u4StartTime; /* Start Time */ ++} EVENT_NOA_TIMING_T, *P_EVENT_NOA_TIMING_T; ++ ++typedef struct _EVENT_UPDATE_NOA_PARAMS_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 aucReserved[2]; ++ UINT_8 fgEnableOppPS; ++ UINT_16 u2CTWindow; ++ ++ UINT_8 ucNoAIndex; ++ UINT_8 ucNoATimingCount; /* Number of NoA Timing */ ++ EVENT_NOA_TIMING_T arEventNoaTiming[8 /*P2P_MAXIMUM_NOA_COUNT */]; ++} EVENT_UPDATE_NOA_PARAMS_T, *P_EVENT_UPDATE_NOA_PARAMS_T; ++ ++typedef struct _EVENT_AP_OBSS_STATUS_T { ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucObssErpProtectMode; ++ UINT_8 ucObssHtProtectMode; ++ UINT_8 ucObssGfOperationMode; ++ UINT_8 ucObssRifsOperationMode; ++ UINT_8 ucObssBeaconForcedTo20M; ++ UINT_8 aucReserved[2]; ++} EVENT_AP_OBSS_STATUS_T, *P_EVENT_AP_OBSS_STATUS_T; ++ ++typedef struct _CMD_EDGE_TXPWR_LIMIT_T { ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ INT_8 cReserved; ++} CMD_EDGE_TXPWR_LIMIT_T, *P_CMD_EDGE_TXPWR_LIMIT_T; ++ ++typedef struct _CMD_RSSI_COMPENSATE_T { ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 ucRssiCompensationValidbit; ++ UINT_8 cReserved; ++} CMD_RSSI_COMPENSATE_T, *P_CMD_RSSI_COMPENSATE_T; ++ ++typedef struct _CMD_BAND_SUPPORT_T { ++ UINT_8 uc5GBandSupport; ++ UINT_8 cReserved[3]; ++} CMD_BAND_SUPPORT_T, *P_CMD_BAND_SUPPORT_T; ++ ++typedef struct _CMD_TX_PWR_CE_T { ++ INT_8 cTxPwrCckLmt; /* signed, in unit of 0.5dBm */ ++ INT_8 cTxPwrOfdmLmt; /* signed, in unit of 0.5dBm */ ++ INT_8 cTxPwrHt20Lmt; ++ INT_8 cTxPwrHt40Lmt; ++} CMD_TX_PWR_CE_T, *P_CMD_TX_PWR_CE_T; ++ ++typedef struct _CMD_SET_DEVICE_MODE_T { ++ UINT_16 u2ChipID; ++ UINT_16 u2Mode; ++} CMD_SET_DEVICE_MODE_T, *P_CMD_SET_DEVICE_MODE_T; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++typedef struct _CMD_RDD_CH_T { ++ UINT_8 ucRddTestMode; ++ UINT_8 ucRddShutCh; ++ UINT_8 ucRddStartCh; ++ UINT_8 ucRddStopCh; ++ UINT_8 ucRddDfs; ++ UINT_8 ucReserved; ++ UINT_8 ucReserved1; ++ UINT_8 ucReserved2; ++} CMD_RDD_CH_T, *P_CMD_RDD_CH_T; ++ ++typedef struct _EVENT_RDD_STATUS_T { ++ UINT_8 ucRddStatus; ++ UINT_8 aucReserved[3]; ++} EVENT_RDD_STATUS_T, *P_EVENT_RDD_STATUS_T; ++#endif ++ ++typedef struct _EVENT_AIS_BSS_INFO_T { ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ ++ ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ ++ BOOLEAN fgIsNetActive; /* TRUE if this network has been actived */ ++ UINT_8 ucReserved[3]; ++} EVENT_AIS_BSS_INFO_T, *P_EVENT_AIS_BSS_INFO_T; ++ ++typedef struct _CMD_SET_TXPWR_CTRL_T { ++ INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c2GHotspotPwrOffset; ++ INT_8 c2GP2pPwrOffset; ++ INT_8 c2GBowPwrOffset; ++ INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c5GHotspotPwrOffset; ++ INT_8 c5GP2pPwrOffset; ++ INT_8 c5GBowPwrOffset; ++ UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence ++ in the same channel ++ 0: Highest power has priority ++ 1: Lowest power has priority */ ++ INT_8 acReserved1[3]; /* Must be zero */ ++ ++ /* Power limit by channel for all data rates */ ++ INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ ++ INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ ++ INT_8 acReserved2[2]; /* Must be zero */ ++} CMD_SET_TXPWR_CTRL_T, *P_CMD_SET_TXPWR_CTRL_T; ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++typedef struct _CMD_GET_BUILD_DATE_CODE { ++ UINT_8 aucReserved[4]; ++} CMD_GET_BUILD_DATE_CODE, *P_CMD_GET_BUILD_DATE_CODE; ++ ++typedef struct _EVENT_BUILD_DATE_CODE { ++ UINT_8 aucDateCode[16]; ++} EVENT_BUILD_DATE_CODE, *P_EVENT_BUILD_DATE_CODE; ++#endif ++ ++typedef struct _CMD_GET_STA_STATISTICS_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 ucReadClear; ++ UINT_8 aucReserved0[1]; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucReserved2[16]; ++} CMD_GET_STA_STATISTICS_T, *P_CMD_GET_STA_STATISTICS_T; ++ ++/* CFG_SUPPORT_WFD */ ++typedef struct _EVENT_STA_STATISTICS_T { ++ /* Event header */ ++ /* UINT_16 u2Length; */ ++ /* UINT_16 u2Reserved1; *//* Must be filled with 0x0001 (EVENT Packet) */ ++ /* UINT_8 ucEID; */ ++ /* UINT_8 ucSeqNum; */ ++ /* UINT_8 aucReserved2[2]; */ ++ ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ UINT_8 ucStaRecIdx; ++ UINT_8 ucNetworkTypeIndex; ++ UINT_8 ucWTEntry; ++ UINT_8 aucReserved4[1]; ++ ++ UINT_8 ucMacAddr[MAC_ADDR_LEN]; ++ UINT_8 ucPer; /* base: 128 */ ++ UINT_8 ucRcpi; ++ ++ UINT_32 u4PhyMode; /* SGI BW */ ++ UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ ++ UINT_8 ucLinkQuality; ++ UINT_8 ucLinkReserved; ++ ++ UINT_32 u4TxCount; ++ UINT_32 u4TxFailCount; ++ UINT_32 u4TxLifeTimeoutCount; ++ UINT_32 u4TxDoneAirTime; ++ ++ UINT_8 aucReserved[64]; ++} EVENT_STA_STATISTICS_T, *P_EVENT_STA_STATISTICS_T; ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++typedef struct _CMD_HOTSPOT_OPTIMIZATION_CONFIG { ++ UINT_32 fgHotspotOptimizationEn; ++ UINT_32 u4Level; ++} CMD_HOTSPOT_OPTIMIZATION_CONFIG, *P_HOTSPOT_OPTIMIZATION_CONFIG; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++ ++typedef struct _CMD_GET_CHN_LOAD_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 ucReadClear; ++ UINT_8 aucReserved0[1]; ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 aucReserved1[1]; ++ UINT_8 aucReserved2[16]; ++} CMD_GET_CHN_LOAD_T, *P_CMD_GET_CHN_LOAD_T; ++/* 4 Auto Channel Selection */ ++ ++typedef struct _EVENT_CHN_LOAD_T { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 aucReserved4[1]; ++ ++ UINT_8 aucReserved[64]; ++ ++} EVENT_CHN_LOAD_T, *P_EVENT_CHN_LOAD_T; ++typedef struct _CMD_GET_LTE_SAFE_CHN_T { ++ UINT_8 ucIndex; ++ UINT_8 ucFlags; ++ UINT_8 aucReserved0[2]; ++ ++ UINT_8 aucReserved2[16]; ++} CMD_GET_LTE_SAFE_CHN_T, *P_CMD_GET_LTE_SAFE_CHN_T; ++ ++typedef struct _EVENT_LTE_MODE_T { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ LTE_SAFE_CH_INFO_T rLteSafeChn; ++ UINT_8 aucReserved4[3]; ++ ++ UINT_8 aucReserved[4]; ++ ++} EVENT_LTE_MODE_T, *P_EVENT_LTE_MODE_T; ++#endif ++typedef struct _CMD_ROAMING_INFO_T { ++ UINT_32 fgIsFastRoamingApplied; ++ UINT_32 Reserved[9]; ++} CMD_ROAMING_INFO_T; ++ ++typedef struct _CMD_WFD_DEBUG_MODE_INFO_T { ++ UINT_8 ucDebugMode; ++ UINT_16 u2PeriodInteval; ++ UINT_8 Reserved; ++} CMD_WFD_DEBUG_MODE_INFO_T, *P_CMD_WFD_DEBUG_MODE_INFO_T; ++ ++typedef struct _EVENT_FW_LOG_T { ++ UINT_8 fileName[64]; ++ UINT_32 lineNo; ++ UINT_32 WifiUpTime; ++ UINT_8 log[896]; /* total size is aucBuffer in WIFI_EVENT_T */ ++} EVENT_FW_LOG_T, *P_EVENT_FW_LOG_T; ++ ++typedef enum _ENUM_NLO_CIPHER_ALGORITHM { ++ NLO_CIPHER_ALGO_NONE = 0x00, ++ NLO_CIPHER_ALGO_WEP40 = 0x01, ++ NLO_CIPHER_ALGO_TKIP = 0x02, ++ NLO_CIPHER_ALGO_CCMP = 0x04, ++ NLO_CIPHER_ALGO_WEP104 = 0x05, ++ NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, ++ NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, ++ NLO_CIPHER_ALGO_WEP = 0x101, ++} ENUM_NLO_CIPHER_ALGORITHM, *P_ENUM_NLO_CIPHER_ALGORITHM; ++ ++typedef enum _ENUM_NLO_AUTH_ALGORITHM { ++ NLO_AUTH_ALGO_80211_OPEN = 1, ++ NLO_AUTH_ALGO_80211_SHARED_KEY = 2, ++ NLO_AUTH_ALGO_WPA = 3, ++ NLO_AUTH_ALGO_WPA_PSK = 4, ++ NLO_AUTH_ALGO_WPA_NONE = 5, ++ NLO_AUTH_ALGO_RSNA = 6, ++ NLO_AUTH_ALGO_RSNA_PSK = 7, ++} ENUM_NLO_AUTH_ALGORITHM, *P_ENUM_NLO_AUTH_ALGORITHM; ++ ++typedef struct _NLO_NETWORK { ++ UINT_8 ucNumChannelHint[4]; ++ UINT_8 ucSSIDLength; ++ UINT_8 ucCipherAlgo; ++ UINT_16 u2AuthAlgo; ++ UINT_8 aucSSID[32]; ++} NLO_NETWORK, *P_NLO_NETWORK; ++ ++typedef struct _CMD_NLO_REQ { ++ UINT_8 ucSeqNum; ++ UINT_8 ucBssIndex; ++ UINT_8 ucNetworkType; ++ UINT_8 fgStopAfterIndication; ++ UINT_8 ucFastScanIteration; ++ UINT_16 u2FastScanPeriod; ++ UINT_16 u2SlowScanPeriod; ++ UINT_8 ucEntryNum; ++ UINT_8 ucReserved; ++ UINT_16 u2IELen; ++ NLO_NETWORK arNetworkList[16]; ++ UINT_8 aucIE[0]; ++ UINT_8 ucScanType; ++} CMD_NLO_REQ, *P_CMD_NLO_REQ; ++ ++typedef struct _CMD_NLO_CANCEL_T { ++ UINT_8 ucSeqNum; ++ UINT_8 aucReserved[3]; ++} CMD_NLO_CANCEL, *P_CMD_NLO_CANCEL; ++ ++typedef struct _EVENT_NLO_DONE_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucStatus; ++ UINT_8 aucReserved[2]; ++} EVENT_NLO_DONE_T, *P_EVENT_NLO_DONE_T; ++ ++typedef struct _EVENT_GSCAN_CAPABILITY_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4MaxScanCacheSize; ++ UINT_32 u4MaxScanBuckets; ++ UINT_32 u4MaxApCachePerScan; ++ UINT_32 u4MaxRssiSampleSize; ++ UINT_32 u4MaxScanReportingThreshold; ++ UINT_32 u4MaxHotlistAps; ++ UINT_32 u4MaxSignificantWifiChangeAps; ++ UINT_32 au4Reserved[4]; ++} EVENT_GSCAN_CAPABILITY_T, *P_EVENT_GSCAN_CAPABILITY_T; ++ ++typedef struct _EVENT_GSCAN_SCAN_AVAILABLE_T { ++ UINT_16 u2Num; ++ UINT_8 aucReserved[2]; ++} EVENT_GSCAN_SCAN_AVAILABLE_T, *P_EVENT_GSCAN_SCAN_AVAILABLE_T; ++ ++typedef struct _EVENT_GSCAN_SCAN_COMPLETE_T { ++ UINT_8 ucScanState; ++ UINT_8 aucReserved[3]; ++} EVENT_GSCAN_SCAN_COMPLETE_T, *P_EVENT_GSCAN_SCAN_COMPLETE_T; ++ ++typedef struct WIFI_GSCAN_RESULT { ++ UINT_64 u8Ts; /* Time of discovery */ ++ UINT_8 arSsid[ELEM_MAX_LEN_SSID + 1]; /* null terminated */ ++ UINT_8 arMacAddr[6]; /* BSSID */ ++ UINT_32 u4Channel; /* channel frequency in MHz */ ++ INT_32 i4Rssi; /* in db */ ++ UINT_64 u8Rtt; /* in nanoseconds */ ++ UINT_64 u8RttSd; /* standard deviation in rtt */ ++ UINT_16 u2BeaconPeriod; /* units are Kusec */ ++ UINT_16 u2Capability; /* Capability information */ ++ UINT_32 u4IeLength; /* byte length of Information Elements */ ++ UINT_8 ucIeData[1]; /* IE data to follow */ ++} WIFI_GSCAN_RESULT_T, *P_WIFI_GSCAN_RESULT_T; ++ ++typedef struct _EVENT_GSCAN_RESULT_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ UINT_16 u2ScanId; ++ UINT_16 u2ScanFlags; ++ UINT_16 u2NumOfResults; ++ WIFI_GSCAN_RESULT_T rResult[1]; ++} EVENT_GSCAN_RESULT_T, *P_EVENT_GSCAN_RESULT_T; ++ ++typedef struct _EVENT_GSCAN_FULL_RESULT_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ WIFI_GSCAN_RESULT_T rResult; ++} EVENT_GSCAN_FULL_RESULT_T, *P_EVENT_GSCAN_FULL_RESULT_T; ++ ++typedef struct GSCAN_SWC_NET { ++ UINT_16 u2Flags; ++ UINT_16 u2Channel; ++ UINT_8 arBssid[6]; ++ INT_8 aicRssi[SCN_PSCAN_SWC_RSSI_WIN_MAX]; ++} GSCAN_SWC_NET_T, P_GSCAN_SWC_NET_T; ++ ++typedef struct _EVENT_GSCAN_SIGNIFICANT_CHANGE_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ GSCAN_SWC_NET_T arNet[SCN_PSCAN_SWC_MAX_NUM]; ++} EVENT_GSCAN_SIGNIFICANT_CHANGE_T, *P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T; ++ ++typedef struct _EVENT_GSCAN_GEOFENCE_FOUND_T { ++ UINT_8 ucVersion; ++ UINT_8 aucReserved[3]; ++ WIFI_GSCAN_RESULT_T rResult[SCN_PSCAN_HOTLIST_REPORT_MAX_NUM]; ++} EVENT_GSCAN_GEOFENCE_FOUND_T, *P_EVENT_GSCAN_GEOFENCE_FOUND_T; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++#if 0 /* !CFG_SUPPORT_GSCN */ ++typedef struct _CMD_BATCH_REQ_T { ++ UINT_8 ucSeqNum; ++ UINT_8 ucNetTypeIndex; ++ UINT_8 ucCmd; /* Start/ Stop */ ++ UINT_8 ucMScan; /* an integer number of scans per batch */ ++ UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ ++ UINT_8 ucRtt; /* an integer number of highest-strength AP for which ++ we'd like approximate distance reported */ ++ UINT_8 ucChannel; /* channels */ ++ UINT_8 ucChannelType; ++ UINT_8 ucChannelListNum; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ ++ CHANNEL_INFO_T arChannelList[32]; /* channels */ ++} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; ++ ++#endif ++ ++typedef struct _EVENT_BATCH_RESULT_ENTRY_T { ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++ UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; ++ UINT_8 ucSSIDLen; ++ INT_8 cRssi; ++ UINT_32 ucFreq; ++ UINT_32 u4Age; ++ UINT_32 u4Dist; ++ UINT_32 u4Distsd; ++} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; ++ ++typedef struct _EVENT_BATCH_RESULT_T { ++ UINT_8 ucScanCount; ++ UINT_8 aucReserved[3]; ++ EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ ++} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; ++#endif ++ ++typedef struct _CMD_RLM_INFO_T { ++ UINT_32 u4Version; ++ UINT_32 fgIsErrRatioEnhanceApplied; ++ UINT_8 ucErrRatio2LimitMinRate; ++ /* ++ 0:1M, 1:2M, 2:5.5M, 3:11M, 6:6M, 7:9M, 8:12M, 9:18M, 10:24M, 11:36M, 12:48M, 13:54M ++ */ ++ UINT_8 ucMinLegacyRateIdx; ++ INT_8 cMinRssiThreshold; ++ BOOLEAN fgIsRtsApplied; ++ UINT_8 ucRecoverTime; ++ ++ UINT_32 u4Reserved[0]; ++} CMD_RLM_INFO_T; ++ ++typedef struct _WIFI_SYSTEM_SUSPEND_CMD_T { ++ BOOLEAN fgIsSystemSuspend; ++ UINT_8 reserved[3]; ++} WIFI_SYSTEM_SUSPEND_CMD_T, *P_WIFI_SYSTEM_SUSPEND_CMD_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/* Statistics responder */ ++VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/* for timeout check */ ++VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++/* 4 Auto Channel Selection */ ++VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++#if CFG_SUPPORT_BATCH_SCAN ++VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++#endif ++ ++VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_CMD_EVENT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h +new file mode 100644 +index 000000000000..994c589190de +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h +@@ -0,0 +1,177 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_init_cmd_event.h#1 ++*/ ++ ++/*! \file "nic_init_cmd_event.h" ++ \brief This file contains the declairation file of the WLAN initialization routines ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: nic_init_cmd_event.h ++ * ++ * 09 26 2011 cp.wu ++ * [WCXRP00001011] [MT6628 Wi-Fi] Firmware Download Agent: make CRC validation as an optional feature ++ * add definition for disabling CRC32 validation (for MT6628 only) ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 03 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add command/event definitions for initial states ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++*/ ++#ifndef _NIC_INIT_CMD_EVENT_H ++#define _NIC_INIT_CMD_EVENT_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define INIT_CMD_STATUS_SUCCESS 0 ++#define INIT_CMD_STATUS_REJECTED_INVALID_PARAMS 1 ++#define INIT_CMD_STATUS_REJECTED_CRC_ERROR 2 ++#define INIT_CMD_STATUS_REJECTED_DECRYPT_FAIL 3 ++#define INIT_CMD_STATUS_UNKNOWN 4 ++ ++#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) ++ ++typedef enum _ENUM_INIT_CMD_ID { ++ INIT_CMD_ID_DOWNLOAD_BUF = 1, ++ INIT_CMD_ID_WIFI_START, ++ INIT_CMD_ID_ACCESS_REG, ++ INIT_CMD_ID_QUERY_PENDING_ERROR ++} ENUM_INIT_CMD_ID, *P_ENUM_INIT_CMD_ID; ++ ++typedef enum _ENUM_INIT_EVENT_ID { ++ INIT_EVENT_ID_CMD_RESULT = 1, ++ INIT_EVENT_ID_ACCESS_REG, ++ INIT_EVENT_ID_PENDING_ERROR ++} ENUM_INIT_EVENT_ID, *P_ENUM_INIT_EVENT_ID; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_8 CMD_STATUS; ++ ++/* commands */ ++typedef struct _INIT_WIFI_CMD_T { ++ UINT_8 ucCID; ++ UINT_8 ucSeqNum; ++ UINT_16 u2Reserved; ++ UINT_8 aucBuffer[0]; ++} INIT_WIFI_CMD_T, *P_INIT_WIFI_CMD_T; ++ ++typedef struct _INIT_HIF_TX_HEADER_T { ++ UINT_16 u2TxByteCount; ++ UINT_8 ucEtherTypeOffset; ++ UINT_8 ucCSflags; ++ INIT_WIFI_CMD_T rInitWifiCmd; ++} INIT_HIF_TX_HEADER_T, *P_INIT_HIF_TX_HEADER_T; ++ ++#define DOWNLOAD_BUF_ENCRYPTION_MODE BIT(0) ++#define DOWNLOAD_BUF_NO_CRC_CHECKING BIT(30) ++#define DOWNLOAD_BUF_ACK_OPTION BIT(31) ++typedef struct _INIT_CMD_DOWNLOAD_BUF { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4CRC32; ++ UINT_32 u4DataMode; ++ UINT_8 aucBuffer[0]; ++} INIT_CMD_DOWNLOAD_BUF, *P_INIT_CMD_DOWNLOAD_BUF; ++ ++typedef struct _INIT_CMD_WIFI_START { ++ UINT_32 u4Override; ++ UINT_32 u4Address; ++} INIT_CMD_WIFI_START, *P_INIT_CMD_WIFI_START; ++ ++typedef struct _INIT_CMD_ACCESS_REG { ++ UINT_8 ucSetQuery; ++ UINT_8 aucReserved[3]; ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} INIT_CMD_ACCESS_REG, *P_INIT_CMD_ACCESS_REG; ++ ++/* Events */ ++typedef struct _INIT_WIFI_EVENT_T { ++ UINT_16 u2RxByteCount; ++ UINT_8 ucEID; ++ UINT_8 ucSeqNum; ++ UINT_8 aucBuffer[0]; ++} INIT_WIFI_EVENT_T, *P_INIT_WIFI_EVENT_T; ++ ++typedef struct _INIT_HIF_RX_HEADER_T { ++ INIT_WIFI_EVENT_T rInitWifiEvent; ++} INIT_HIF_RX_HEADER_T, *P_INIT_HIF_RX_HEADER_T; ++ ++typedef struct _INIT_EVENT_CMD_RESULT { ++ UINT_8 ucStatus; /* 0: success */ ++ /* 1: rejected by invalid param */ ++ /* 2: rejected by incorrect CRC */ ++ /* 3: rejected by decryption failure */ ++ /* 4: unknown CMD */ ++ UINT_8 aucReserved[3]; ++} INIT_EVENT_CMD_RESULT, *P_INIT_EVENT_CMD_RESULT, INIT_EVENT_PENDING_ERROR, *P_INIT_EVENT_PENDING_ERROR; ++ ++typedef struct _INIT_EVENT_ACCESS_REG { ++ UINT_32 u4Address; ++ UINT_32 u4Data; ++} INIT_EVENT_ACCESS_REG, *P_INIT_EVENT_ACCESS_REG; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _NIC_INIT_CMD_EVENT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h +new file mode 100644 +index 000000000000..85af819f4e62 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h +@@ -0,0 +1,201 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/p2p_precomp.h#1 ++*/ ++ ++/*! \file p2p_precomp.h ++ \brief Collection of most compiler flags for p2p driver are described here. ++ ++ In this file we collect all compiler flags and detail the p2p driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++#ifndef _P2P_PRECOMP_H ++#define _P2P_PRECOMP_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" /* Include "config.h" */ ++ ++#include "gl_p2p_os.h" ++ ++#include "debug.h" ++ ++#include "link.h" ++#include "queue.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++#include "wlan_typedef.h" ++ ++#include "mac.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "wlan_def.h" ++ ++#include "roaming_fsm.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\nic ++ *------------------------------------------------------------------------------ ++ */ ++/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ ++#include "cmd_buf.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "nic_cmd_event.h" ++ ++/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ ++#include "nic.h" ++ ++#include "nic_init_cmd_event.h" ++ ++#include "hif_rx.h" ++#include "hif_tx.h" ++ ++#include "nic_tx.h" ++ ++/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ ++#include "nic_rx.h" ++ ++#include "que_mgt.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_typedef.h" ++#include "p2p_cmd_buf.h" ++#include "p2p_nic_cmd_event.h" ++#include "p2p_mac.h" ++#include "p2p_nic.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++ ++#include "hem_mbox.h" ++ ++#include "scan.h" ++#include "bss.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_bow.h" ++ ++#include "wlan_p2p.h" ++ ++#include "hal.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#endif ++ ++#include "rlm.h" ++#include "rlm_domain.h" ++#include "rlm_protection.h" ++#include "rlm_obss.h" ++#include "rate.h" ++ ++#include "aa_fsm.h" ++ ++#include "cnm_timer.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "bow.h" ++#include "bow_fsm.h" ++#endif ++ ++#include "pwr_mgt.h" ++ ++#include "cnm.h" ++/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ ++#include "cnm_mem.h" ++#include "cnm_scan.h" ++ ++#include "p2p_rlm_obss.h" ++#include "p2p_bss.h" ++#include "p2p.h" ++/* Dependency: cnm_timer.h (TIMER_T) */ ++#include "p2p_fsm.h" ++#include "p2p_scan.h" ++#include "p2p_state.h" ++#include "p2p_func.h" ++#include "p2p_rlm.h" ++#include "p2p_assoc.h" ++#include "p2p_ie.h" ++ ++#include "privacy.h" ++ ++#include "mib.h" ++ ++#include "auth.h" ++#include "assoc.h" ++ ++#include "ais_fsm.h" ++ ++#include "adapter.h" ++ ++#include "que_mgt.h" ++#include "rftest.h" ++ ++#if CFG_RSN_MIGRATION ++#include "rsn.h" ++#include "sec_fsm.h" ++#endif ++ ++#if CFG_SUPPORT_WAPI ++#include "wapi.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * NVRAM structure ++ *------------------------------------------------------------------------------ ++ */ ++#include "CFG_Wifi_File.h" ++ ++#include "gl_p2p_kal.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /*_P2P_PRECOMP_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h +new file mode 100644 +index 000000000000..a02d391d3643 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h +@@ -0,0 +1,165 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/p2p_typedef.h#1 ++*/ ++ ++/*! \file p2p_typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to all MGMT Protocol Stack. ++*/ ++ ++#ifndef _P2P_TYPEDEF_H ++#define _P2P_TYPEDEF_H ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* ++* type definition of pointer to p2p structure ++*/ ++/* typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; */ ++typedef struct _P2P_INFO_T P2P_INFO_T, *P_P2P_INFO_T; ++ ++typedef struct _P2P_FSM_INFO_T P2P_FSM_INFO_T, *P_P2P_FSM_INFO_T; ++ ++typedef struct _P2P_CONNECTION_SETTINGS_T P2P_CONNECTION_SETTINGS_T, *P_P2P_CONNECTION_SETTINGS_T; ++ ++/* Type definition for function pointer to p2p function*/ ++typedef BOOLEAN(*P2P_LAUNCH) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*P2P_REMOVE) (P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsWlanLaunched); ++ ++typedef BOOLEAN(*KAL_P2P_GET_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_TKIP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_CCMP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef BOOLEAN(*KAL_P2P_GET_WSC_MODE) (IN P_GLUE_INFO_T prGlueInfo); ++ ++typedef struct net_device *(*KAL_P2P_GET_DEV_HDLR) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*KAL_P2P_SET_MULTICAST_WORK_ITEM) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*P2P_NET_REGISTER) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*P2P_NET_UNREGISTER) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef VOID(*KAL_P2P_UPDATE_ASSOC_INFO) (IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, ++ IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++typedef BOOLEAN(*P2P_VALIDATE_AUTH) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++typedef BOOLEAN(*P2P_VALIDATE_ASSOC_REQ) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu4ControlFlags); ++ ++typedef VOID(*P2P_RUN_EVENT_AAA_TX_FAIL) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++typedef BOOLEAN(*P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM) (IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); ++ ++typedef WLAN_STATUS(*P2P_RUN_EVENT_AAA_COMPLETE) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++typedef VOID(*P2P_PROCESS_EVENT_UPDATE_NOA_PARAM) (IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, ++ P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); ++ ++typedef VOID(*SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, ++ IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); ++ ++typedef VOID(*P2P_RX_PUBLIC_ACTION_FRAME) (P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_RSP_GENERATE_OBSS_SCAN_IE) (P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); ++ ++typedef VOID(*RLM_UPDATE_BW_BY_CH_LIST_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++typedef VOID(*RLM_PROCESS_PUBLIC_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_PROCESS_HT_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*RLM_UPDATE_PARAMS_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); ++ ++typedef VOID(*RLM_HANDLE_OBSS_STATUS_EVENT_PKT) (P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); ++ ++typedef BOOLEAN(*P2P_FUNC_VALIDATE_PROBE_REQ) (IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++typedef VOID(*RLM_BSS_INIT_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++typedef UINT_32(*P2P_GET_PROB_RSP_IE_TABLE_SIZE) (VOID); ++ ++typedef PUINT_8(*P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES) (IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); ++ ++typedef VOID(*P2P_FUNC_DISCONNECT) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_RX_DEAUTH) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_RX_DISASSOC) (IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++typedef BOOLEAN(*P2P_FUN_IS_AP_MODE) (IN P_P2P_FSM_INFO_T prP2pFsmInfo); ++ ++typedef VOID(*P2P_FSM_RUN_EVENT_BEACON_TIMEOUT) (IN P_ADAPTER_T prAdapter); ++ ++typedef VOID(*P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER) (IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); ++ ++typedef VOID(*P2P_GENERATE_P2P_IE) (IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++typedef UINT_32(*P2P_CALCULATE_P2P_IE_LEN) (IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /*CFG_ENABLE_WIFI_DIRECT */ ++ ++#endif /* _P2P_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h +new file mode 100644 +index 000000000000..1b7e7ede66e1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h +@@ -0,0 +1,388 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/precomp.h#2 ++*/ ++ ++/*! \file precomp.h ++ \brief Collection of most compiler flags are described here. ++ ++ In this file we collect all compiler flags and detail the driver behavior if ++ enable/disable such switch or adjust numeric parameters. ++*/ ++ ++/* ++** Log: precomp.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628-specific definitions. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Fix BOW_FSM_INFO_T dependence. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 28 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * 1st draft code for RLM module ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge cnm_scan.h and hem_mbox.h ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 03 16 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * build up basic data structure and definitions to support BT-over-WiFi ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 11:30:58 GMT mtk02752 ++** add rftest.h for implementing RF test mode in driver land ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-23 22:02:00 GMT mtk02468 ++** Added que_mgt.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-13 21:58:36 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:40:11 GMT mtk01461 ++** Add nic_cmd_event.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 20:00:26 GMT mtk01461 ++** Add cmd_buf.h ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:44 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:25 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:38 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _PRECOMP_H ++#define _PRECOMP_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" /* Include "config.h" */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_os.h" ++#endif ++ ++#include "debug.h" ++ ++#include "link.h" ++#include "queue.h" ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++#include "wlan_typedef.h" ++ ++#include "mac.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "wlan_def.h" ++ ++#if CFG_SUPPORT_SWCR ++#include "swcr.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\nic ++ *------------------------------------------------------------------------------ ++ */ ++/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ ++#include "cmd_buf.h" ++ ++/* Dependency: mac.h (MAC_ADDR_LEN) */ ++#include "nic_cmd_event.h" ++ ++/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ ++#include "nic.h" ++ ++#include "nic_init_cmd_event.h" ++ ++#include "hif_rx.h" ++#include "hif_tx.h" ++ ++#include "nic_tx.h" ++ ++/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ ++#include "nic_rx.h" ++ ++#include "que_mgt.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_typedef.h" ++#include "p2p_cmd_buf.h" ++#include "p2p_nic_cmd_event.h" ++#include "p2p_mac.h" ++#include "p2p_nic.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * .\include\mgmt ++ *------------------------------------------------------------------------------ ++ */ ++ ++#include "hem_mbox.h" ++ ++#include "scan.h" ++#include "bss.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_bow.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "wlan_p2p.h" ++#endif ++ ++#include "hal.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#elif defined(MT6628) ++/* #include "mt6628_reg.h" */ ++#include "mtreg.h" ++#endif ++ ++#include "rlm.h" ++#include "rlm_domain.h" ++#include "rlm_protection.h" ++#include "rlm_obss.h" ++#include "rate.h" ++#if CFG_SUPPORT_802_11V ++#include "wnm.h" ++#endif ++ ++#include "aa_fsm.h" ++ ++#include "cnm_timer.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "bow.h" ++#include "bow_fsm.h" ++#endif ++ ++#include "pwr_mgt.h" ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++#include "stats.h" ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++#include "cnm.h" ++/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ ++#include "cnm_mem.h" ++#include "cnm_scan.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "p2p_rlm_obss.h" ++#include "p2p_bss.h" ++#include "p2p.h" ++#include "p2p_fsm.h" ++#include "p2p_scan.h" ++#include "p2p_state.h" ++#include "p2p_func.h" ++#include "p2p_rlm.h" ++#include "p2p_assoc.h" ++#include "p2p_ie.h" ++#endif ++ ++#include "privacy.h" ++ ++#include "mib.h" ++ ++#include "auth.h" ++#include "assoc.h" ++ ++#if CFG_SUPPORT_ROAMING ++#include "roaming_fsm.h" ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++#include "ais_fsm.h" ++ ++#include "adapter.h" ++ ++#include "que_mgt.h" ++#include "rftest.h" ++ ++#if CFG_RSN_MIGRATION ++#include "rsn.h" ++#include "sec_fsm.h" ++#endif ++ ++#if CFG_SUPPORT_WAPI ++#include "wapi.h" ++#endif ++ ++/*------------------------------------------------------------------------------ ++ * NVRAM structure ++ *------------------------------------------------------------------------------ ++ */ ++#include "CFG_Wifi_File.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_kal.h" ++#endif ++ ++typedef int (*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++typedef void (*set_dbg_level) (unsigned char modules[DBG_MODULE_NUM]); ++ ++extern void wlanRegisterNotifier(void); ++extern void wlanUnregisterNotifier(void); ++extern void register_set_p2p_mode_handler(set_p2p_mode handler); ++extern void register_set_dbg_level_handler(set_dbg_level handler); ++ ++#if CFG_TC1_FEATURE ++#define NIC_INF_NAME_IN_AP_MODE "legacy%d" ++extern volatile int wlan_if_changed; ++#endif ++extern BOOLEAN fgIsResetting; ++ ++extern UINT_8 g_aucBufIpAddr[32]; ++extern UINT_8 aucDebugModule[]; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PRECOMP_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h +new file mode 100644 +index 000000000000..40f52dcc9d68 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h +@@ -0,0 +1,141 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/pwr_mgt.h#1 ++*/ ++ ++/*! \file "pwr_mgt.h" ++ \brief In this file we define the STATE and EVENT for Power Management FSM. ++ ++ The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter ++ ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail ++ description. ++*/ ++ ++/* ++** Log: pwr_mgt.h ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL ++ * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. ++ ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * firmware download load address & start address are now configured from config.h ++ * * * due to the different configurations on FPGA and ASIC ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-10 16:39:10 GMT mtk02752 ++** disable PM macros temporally ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-29 19:48:37 GMT mtk01084 ++** temp remove power management macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-08 16:51:11 GMT mtk01084 ++** update for power management control macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-03 14:59:58 GMT mtk01426 ++** Add #if CFG_HIF_LOOPBACK_PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:53:10 GMT mtk01084 ++** modify ACQUIRE_POWER_CONTROL_FROM_PM() and RECLAIM_POWER_CONTROL_TO_PM() macro ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:32:47 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:20 GMT mtk01084 ++** Initial version ++** ++*/ ++ ++#ifndef _PWR_MGT_H ++#define _PWR_MGT_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define PM_UAPSD_AC0 (BIT(0)) ++#define PM_UAPSD_AC1 (BIT(1)) ++#define PM_UAPSD_AC2 (BIT(2)) ++#define PM_UAPSD_AC3 (BIT(3)) ++ ++#define PM_UAPSD_ALL (PM_UAPSD_AC0 | PM_UAPSD_AC1 | PM_UAPSD_AC2 | PM_UAPSD_AC3) ++#define PM_UAPSD_NONE 0 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _PM_PROFILE_SETUP_INFO_T { ++ /* Profile setup */ ++ UINT_8 ucBmpDeliveryAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ ++ UINT_8 ucBmpTriggerAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ ++ ++ UINT_8 ucUapsdSp; /* Number of triggered packets in UAPSD */ ++ ++} PM_PROFILE_SETUP_INFO_T, *P_PM_PROFILE_SETUP_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if !CFG_ENABLE_FULL_PM ++#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) ++#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) ++#else ++#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) \ ++ { \ ++ if (_prAdapter->fgIsFwOwn) { \ ++ nicpmSetDriverOwn(_prAdapter); \ ++ } \ ++ /* Increase Block to Enter Low Power Semaphore count */ \ ++ GLUE_INC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ ++ } ++ ++#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) \ ++ { \ ++ ASSERT(_prAdapter->u4PwrCtrlBlockCnt != 0); \ ++ /* Decrease Block to Enter Low Power Semaphore count */ \ ++ GLUE_DEC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ ++ if (_prAdapter->fgWiFiInSleepyState && (_prAdapter->u4PwrCtrlBlockCnt == 0)) { \ ++ nicpmSetFWOwn(_prAdapter, _fgEnableGINT_in_IST); \ ++ } \ ++ } ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _PWR_MGT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h +new file mode 100644 +index 000000000000..a9e74b58a8c9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h +@@ -0,0 +1,195 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/queue.h#1 ++*/ ++ ++/*! \file queue.h ++ \brief Definition for singly queue operations. ++ ++ In this file we define the singly queue data structure and its ++ queue operation MACROs. ++*/ ++ ++/* ++** Log: queue.h ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:46 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _QUEUE_H ++#define _QUEUE_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Singly Queue Structures - Entry Part */ ++typedef struct _QUE_ENTRY_T { ++ struct _QUE_ENTRY_T *prNext; ++ struct _QUE_ENTRY_T *prPrev; /* For Rx buffer reordering used only */ ++} QUE_ENTRY_T, *P_QUE_ENTRY_T; ++ ++/* Singly Queue Structures - Queue Part */ ++typedef struct _QUE_T { ++ P_QUE_ENTRY_T prHead; ++ P_QUE_ENTRY_T prTail; ++ UINT_32 u4NumElem; ++} QUE_T, *P_QUE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/* ++ * To resolve compiler warning of address check -Waddress ++ * Redefine a ASSERT dedicate for queue operation ++ */ ++#if DBG ++#define QUE_ASSERT ASSERT ++#else ++#define QUE_ASSERT(_exp) ++#endif ++ ++#define QUEUE_INITIALIZE(prQueue) \ ++ { \ ++ (prQueue)->prHead = (P_QUE_ENTRY_T)NULL; \ ++ (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ ++ (prQueue)->u4NumElem = 0; \ ++ } ++ ++#define QUEUE_IS_EMPTY(prQueue) (((P_QUE_T)(prQueue))->prHead == (P_QUE_ENTRY_T)NULL) ++ ++#define QUEUE_IS_NOT_EMPTY(prQueue) ((prQueue)->u4NumElem > 0) ++ ++#define QUEUE_GET_HEAD(prQueue) ((prQueue)->prHead) ++ ++#define QUEUE_GET_TAIL(prQueue) ((prQueue)->prTail) ++ ++#define QUEUE_GET_NEXT_ENTRY(prQueueEntry) ((prQueueEntry)->prNext) ++ ++#define QUEUE_INSERT_HEAD(prQueue, prQueueEntry) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ QUE_ASSERT(prQueueEntry); \ ++ (prQueueEntry)->prNext = (prQueue)->prHead; \ ++ (prQueue)->prHead = (prQueueEntry); \ ++ if ((prQueue)->prTail == (P_QUE_ENTRY_T)NULL) { \ ++ (prQueue)->prTail = (prQueueEntry); \ ++ } \ ++ ((prQueue)->u4NumElem)++; \ ++ } ++ ++#define QUEUE_INSERT_TAIL(prQueue, prQueueEntry) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ QUE_ASSERT(prQueueEntry); \ ++ (prQueueEntry)->prNext = (P_QUE_ENTRY_T)NULL; \ ++ if ((prQueue)->prTail) { \ ++ ((prQueue)->prTail)->prNext = (prQueueEntry); \ ++ } else { \ ++ (prQueue)->prHead = (prQueueEntry); \ ++ } \ ++ (prQueue)->prTail = (prQueueEntry); \ ++ ((prQueue)->u4NumElem)++; \ ++ } ++ ++/* NOTE: We assume the queue entry located at the beginning of "prQueueEntry Type", ++ * so that we can cast the queue entry to other data type without doubts. ++ * And this macro also decrease the total entry count at the same time. ++ */ ++#define QUEUE_REMOVE_HEAD(prQueue, prQueueEntry, _P_TYPE) \ ++ { \ ++ QUE_ASSERT(prQueue); \ ++ prQueueEntry = (_P_TYPE)((prQueue)->prHead); \ ++ if (prQueueEntry) { \ ++ (prQueue)->prHead = ((P_QUE_ENTRY_T)(prQueueEntry))->prNext; \ ++ if ((prQueue)->prHead == (P_QUE_ENTRY_T)NULL) { \ ++ (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ ++ } \ ++ ((P_QUE_ENTRY_T)(prQueueEntry))->prNext = (P_QUE_ENTRY_T)NULL; \ ++ ((prQueue)->u4NumElem)--; \ ++ } \ ++ } ++ ++#define QUEUE_MOVE_ALL(prDestQueue, prSrcQueue) \ ++ { \ ++ QUE_ASSERT(prDestQueue); \ ++ QUE_ASSERT(prSrcQueue); \ ++ *(P_QUE_T)prDestQueue = *(P_QUE_T)prSrcQueue; \ ++ QUEUE_INITIALIZE(prSrcQueue); \ ++ } ++ ++#define QUEUE_CONCATENATE_QUEUES(prDestQueue, prSrcQueue) \ ++ { \ ++ QUE_ASSERT(prDestQueue); \ ++ QUE_ASSERT(prSrcQueue); \ ++ if (prSrcQueue->u4NumElem > 0) { \ ++ if ((prDestQueue)->prTail) { \ ++ ((prDestQueue)->prTail)->prNext = (prSrcQueue)->prHead; \ ++ } else { \ ++ (prDestQueue)->prHead = (prSrcQueue)->prHead; \ ++ } \ ++ (prDestQueue)->prTail = (prSrcQueue)->prTail; \ ++ ((prDestQueue)->u4NumElem) += ((prSrcQueue)->u4NumElem); \ ++ QUEUE_INITIALIZE(prSrcQueue); \ ++ } \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _QUEUE_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h +new file mode 100644 +index 000000000000..4489e5601302 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h +@@ -0,0 +1,294 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/rftest.h#1 ++*/ ++ ++/*! \file "rftest.h" ++ \brief definitions for RF Productino test ++ ++*/ ++ ++/* ++** Log: rftest.h ++ * ++ * 12 20 2011 cp.wu ++ * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information ++ * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO ++ * to expose version information ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-08 17:35:11 GMT mtk02752 ++** * comment out RF test which is not supported on MT6620 ++** + API decalre for rftest ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-12-08 11:29:07 GMT mtk02752 ++** definitions for RF test mode ++** ++*/ ++#ifndef _RFTEST_H ++#define _RFTEST_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Table Version */ ++#define RF_AUTO_TEST_FUNCTION_TABLE_VERSION 0x01000001 ++ ++/* Power */ ++#define RF_AT_PARAM_POWER_MASK BITS(0, 7) ++#define RF_AT_PARAM_POWER_MAX RF_AT_PARAM_POWER_MASK ++ ++/* Rate */ ++#define RF_AT_PARAM_RATE_MCS_MASK BIT(31) ++#define RF_AT_PARAM_RATE_MASK BITS(0, 7) ++#define RF_AT_PARAM_RATE_CCK_MAX 3 ++#define RF_AT_PARAM_RATE_1M 0 ++#define RF_AT_PARAM_RATE_2M 1 ++#define RF_AT_PARAM_RATE_5_5M 2 ++#define RF_AT_PARAM_RATE_11M 3 ++#define RF_AT_PARAM_RATE_6M 4 ++#define RF_AT_PARAM_RATE_9M 5 ++#define RF_AT_PARAM_RATE_12M 6 ++#define RF_AT_PARAM_RATE_18M 7 ++#define RF_AT_PARAM_RATE_24M 8 ++#define RF_AT_PARAM_RATE_36M 9 ++#define RF_AT_PARAM_RATE_48M 10 ++#define RF_AT_PARAM_RATE_54M 11 ++ ++/* Antenna */ ++#define RF_AT_PARAM_ANTENNA_ID_MASK BITS(0, 7) ++#define RF_AT_PARAM_ANTENNA_ID_MAX 1 ++ ++/* Packet Length */ ++#define RF_AT_PARAM_TX_80211HDR_BYTE_MAX (32) ++#define RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX (2048) ++ ++#define RF_AT_PARAM_TX_PKTLEN_BYTE_DEFAULT 1024 ++#define RF_AT_PARAM_TX_PKTLEN_BYTE_MAX \ ++ ((UINT_16)(RF_AT_PARAM_TX_80211HDR_BYTE_MAX + RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX)) ++ ++/* Packet Count */ ++#define RF_AT_PARAM_TX_PKTCNT_DEFAULT 1000 ++#define RF_AT_PARAM_TX_PKTCNT_UNLIMITED 0 ++ ++/* Packet Interval */ ++#define RF_AT_PARAM_TX_PKT_INTERVAL_US_DEFAULT 50 ++ ++/* ALC */ ++#define RF_AT_PARAM_ALC_DISABLE 0 ++#define RF_AT_PARAM_ALC_ENABLE 1 ++ ++/* TXOP */ ++#define RF_AT_PARAM_TXOP_DEFAULT 0 ++#define RF_AT_PARAM_TXOPQUE_QMASK BITS(16, 31) ++#define RF_AT_PARAM_TXOPQUE_TMASK BITS(0, 15) ++#define RF_AT_PARAM_TXOPQUE_AC0 (0<<16) ++#define RF_AT_PARAM_TXOPQUE_AC1 (1<<16) ++#define RF_AT_PARAM_TXOPQUE_AC2 (2<<16) ++#define RF_AT_PARAM_TXOPQUE_AC3 (3<<16) ++#define RF_AT_PARAM_TXOPQUE_AC4 (4<<16) ++#define RF_AT_PARAM_TXOPQUE_QOFFSET 16 ++ ++/* Retry Limit */ ++#define RF_AT_PARAM_TX_RETRY_DEFAULT 0 ++#define RF_AT_PARAM_TX_RETRY_MAX 6 ++ ++/* QoS Queue */ ++#define RF_AT_PARAM_QOSQUE_AC0 0 ++#define RF_AT_PARAM_QOSQUE_AC1 1 ++#define RF_AT_PARAM_QOSQUE_AC2 2 ++#define RF_AT_PARAM_QOSQUE_AC3 3 ++#define RF_AT_PARAM_QOSQUE_AC4 4 ++#define RF_AT_PARAM_QOSQUE_DEFAULT RF_AT_PARAM_QOSQUE_AC0 ++ ++/* Bandwidth */ ++#define RF_AT_PARAM_BANDWIDTH_20MHZ 0 ++#define RF_AT_PARAM_BANDWIDTH_40MHZ 1 ++#define RF_AT_PARAM_BANDWIDTH_U20_IN_40MHZ 2 ++#define RF_AT_PARAM_BANDWIDTH_D20_IN_40MHZ 3 ++#define RF_AT_PARAM_BANDWIDTH_DEFAULT RF_AT_PARAM_BANDWIDTH_20MHZ ++ ++/* GI (Guard Interval) */ ++#define RF_AT_PARAM_GI_800NS 0 ++#define RF_AT_PARAM_GI_400NS 1 ++#define RF_AT_PARAM_GI_DEFAULT RF_AT_PARAM_GI_800NS ++ ++/* STBC */ ++#define RF_AT_PARAM_STBC_DISABLE 0 ++#define RF_AT_PARAM_STBC_ENABLE 1 ++ ++/* RIFS */ ++#define RF_AT_PARAM_RIFS_DISABLE 0 ++#define RF_AT_PARAM_RIFS_ENABLE 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Function ID List */ ++typedef enum _ENUM_RF_AT_FUNCID_T { ++ RF_AT_FUNCID_VERSION = 0, ++ RF_AT_FUNCID_COMMAND, ++ RF_AT_FUNCID_POWER, ++ RF_AT_FUNCID_RATE, ++ RF_AT_FUNCID_PREAMBLE, ++ RF_AT_FUNCID_ANTENNA, ++ RF_AT_FUNCID_PKTLEN, ++ RF_AT_FUNCID_PKTCNT, ++ RF_AT_FUNCID_PKTINTERVAL, ++ RF_AT_FUNCID_TEMP_COMPEN, ++ RF_AT_FUNCID_TXOPLIMIT, ++ RF_AT_FUNCID_ACKPOLICY, ++ RF_AT_FUNCID_PKTCONTENT, ++ RF_AT_FUNCID_RETRYLIMIT, ++ RF_AT_FUNCID_QUEUE, ++ RF_AT_FUNCID_BANDWIDTH, ++ RF_AT_FUNCID_GI, ++ RF_AT_FUNCID_STBC, ++ RF_AT_FUNCID_CHNL_FREQ, ++ RF_AT_FUNCID_RIFS, ++ RF_AT_FUNCID_TRSW_TYPE, ++ RF_AT_FUNCID_RF_SX_SHUTDOWN, ++ RF_AT_FUNCID_PLL_SHUTDOWN, ++ RF_AT_FUNCID_SLOW_CLK_MODE, ++ RF_AT_FUNCID_ADC_CLK_MODE, ++ RF_AT_FUNCID_MEASURE_MODE, ++ RF_AT_FUNCID_VOLT_COMPEN, ++ RF_AT_FUNCID_DPD_TX_GAIN, ++ RF_AT_FUNCID_DPD_MODE, ++ RF_AT_FUNCID_TSSI_MODE, ++ RF_AT_FUNCID_TX_GAIN_CODE, ++ RF_AT_FUNCID_TX_PWR_MODE, ++ ++ /* Query command */ ++ RF_AT_FUNCID_TXED_COUNT = 32, ++ RF_AT_FUNCID_TXOK_COUNT, ++ RF_AT_FUNCID_RXOK_COUNT, ++ RF_AT_FUNCID_RXERROR_COUNT, ++ RF_AT_FUNCID_RESULT_INFO, ++ RF_AT_FUNCID_TRX_IQ_RESULT, ++ RF_AT_FUNCID_TSSI_RESULT, ++ RF_AT_FUNCID_DPD_RESULT, ++ RF_AT_FUNCID_RXV_DUMP, ++ RF_AT_FUNCID_RX_PHY_STATIS, ++ RF_AT_FUNCID_MEASURE_RESULT, ++ RF_AT_FUNCID_TEMP_SENSOR, ++ RF_AT_FUNCID_VOLT_SENSOR, ++ RF_AT_FUNCID_READ_EFUSE, ++ RF_AT_FUNCID_RX_RSSI, ++ RF_AT_FUNCID_FW_INFO, ++ RF_AT_FUNCID_DRV_INFO, ++ ++ /* Set command */ ++ RF_AT_FUNCID_SET_DPD_RESULT = 64, ++ RF_AT_FUNCID_SET_CW_MODE, ++ RF_AT_FUNCID_SET_JAPAN_CH14_FILTER, ++ RF_AT_FUNCID_WRITE_EFUSE, ++ RF_AT_FUNCID_SET_MAC_ADDRESS ++} ENUM_RF_AT_FUNCID_T; ++ ++/* Command */ ++typedef enum _ENUM_RF_AT_COMMAND_T { ++ RF_AT_COMMAND_STOPTEST = 0, ++ RF_AT_COMMAND_STARTTX, ++ RF_AT_COMMAND_STARTRX, ++ RF_AT_COMMAND_RESET, ++ RF_AT_COMMAND_OUTPUT_POWER, /* Payload */ ++ RF_AT_COMMAND_LO_LEAKAGE, /* Local freq is renamed to Local leakage */ ++ RF_AT_COMMAND_CARRIER_SUPPR, /* OFDM (LTF/STF), CCK (PI,PI/2) */ ++ RF_AT_COMMAND_TRX_IQ_CAL, ++ RF_AT_COMMAND_TSSI_CAL, ++ RF_AT_COMMAND_DPD_CAL, ++ RF_AT_COMMAND_CW, ++ RF_AT_COMMAND_NUM ++} ENUM_RF_AT_COMMAND_T; ++ ++/* Preamble */ ++typedef enum _ENUM_RF_AT_PREAMBLE_T { ++ RF_AT_PREAMBLE_NORMAL = 0, ++ RF_AT_PREAMBLE_CCK_SHORT, ++ RF_AT_PREAMBLE_11N_MM, ++ RF_AT_PREAMBLE_11N_GF, ++ RF_AT_PREAMBLE_NUM ++} ENUM_RF_AT_PREAMBLE_T; ++ ++/* Ack Policy */ ++typedef enum _ENUM_RF_AT_ACK_POLICY_T { ++ RF_AT_ACK_POLICY_NORMAL = 0, ++ RF_AT_ACK_POLICY_NOACK, ++ RF_AT_ACK_POLICY_NOEXPLICTACK, ++ RF_AT_ACK_POLICY_BLOCKACK, ++ RF_AT_ACK_POLICY_NUM ++} ENUM_RF_AT_ACK_POLICY_T; ++ ++typedef enum _ENUM_RF_AUTOTEST_STATE_T { ++ RF_AUTOTEST_STATE_STANDBY = 0, ++ RF_AUTOTEST_STATE_TX, ++ RF_AUTOTEST_STATE_RX, ++ RF_AUTOTEST_STATE_RESET, ++ RF_AUTOTEST_STATE_OUTPUT_POWER, ++ RF_AUTOTEST_STATE_LOCA_FREQUENCY, ++ RF_AUTOTEST_STATE_CARRIER_SUPRRESION, ++ RF_AUTOTEST_STATE_NUM ++} ENUM_RF_AUTOTEST_STATE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData); ++ ++WLAN_STATUS ++rftestQueryATInfo(IN P_ADAPTER_T prAdapter, ++ UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); ++ ++WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen); ++ ++#endif /* _RFTEST_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h +new file mode 100644 +index 000000000000..8ee184591fc2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h +@@ -0,0 +1,427 @@ ++/* ++** Id: include/tdls_extr.h#1 ++*/ ++ ++/*! \file "tdls_extr.h" ++ \brief This file contains the external used in other modules ++ for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: tdls_extr.h ++ * ++ * 11 18 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ * ++ ** ++ */ ++ ++#ifndef _TDLS_EXTR_H ++#define _TDLS_EXTR_H ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#define TDLS_TX_QUOTA_EMPTY_TIMEOUT 10 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* protocol */ ++#define TDLS_FRM_PROT_TYPE 0x890d ++ ++/* TDLS uses Ethertype 89-0d frames. The UP shall be AC_VI, unless otherwise specified. */ ++#define USER_PRIORITY_TDLS 5 ++ ++/* Status code */ ++#define TDLS_STATUS WLAN_STATUS ++ ++#define TDLS_STATUS_SUCCESS WLAN_STATUS_SUCCESS ++#define TDLS_STATUS_FAILURE WLAN_STATUS_FAILURE ++#define TDLS_STATUS_INVALID_LENGTH WLAN_STATUS_INVALID_LENGTH ++#define TDLS_STATUS_RESOURCES WLAN_STATUS_RESOURCES ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#define TDLS_U32 UINT32 ++#define TDLS_U16 UINT16 ++#define TDLS_U8 UINT8 ++ ++typedef enum _TDLS_REASON_CODE { ++ TDLS_REASON_CODE_UNREACHABLE = 25, ++ TDLS_REASON_CODE_UNSPECIFIED = 26, ++ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN = 0x80, /* 128 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WIFI_OFF = 0x81, /* 129 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING = 0x82, /* 130 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT = 0x83, /* 131 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT = 0x84, /* 132 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY = 0x85, /* 133 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL = 0x86, /* 134 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL = 0x87, /* 135 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX = 0x88, /* 136 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3 = 0x89, /* 137 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY = 0x8a, /* 138 */ ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN = 0x8b /* 139 */ ++} TDLS_REASON_CODE; ++ ++/* TDLS FSM */ ++typedef struct _TDLS_CMD_PEER_ADD_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ ++#if 0 ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ UINT_16 u2CapInfo; ++ ++ UINT_16 u2OperationalRateSet; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ UINT_8 ucPhyTypeSet; ++#endif ++} TDLS_CMD_PEER_ADD_T; ++ ++typedef struct _TDLS_CMD_LINK_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ BOOLEAN fgIsEnabled; ++} TDLS_CMD_LINK_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T { ++ TDLS_U8 arRxMask[10]; ++ TDLS_U16 u2RxHighest; ++ TDLS_U8 ucTxParams; ++ TDLS_U8 Reserved[3]; ++} TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_T { ++ TDLS_U16 u2CapInfo; ++ TDLS_U8 ucAmpduParamsInfo; ++ ++ /* 16 bytes MCS information */ ++ TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T rMCS; ++ ++ TDLS_U16 u2ExtHtCapInfo; ++ TDLS_U32 u4TxBfCapInfo; ++ TDLS_U8 ucAntennaSelInfo; ++} TDLS_CMD_PEER_UPDATE_HT_CAP_T; ++ ++typedef struct _TDLS_CMD_PEER_UPDATE_T { ++ ++ TDLS_U8 aucPeerMac[6]; ++ ++#define TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX 50 ++ TDLS_U8 aucSupChan[TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX]; ++ ++ TDLS_U16 u2StatusCode; ++ ++#define TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX 50 ++ TDLS_U8 aucSupRate[TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX]; ++ TDLS_U16 u2SupRateLen; ++ ++ TDLS_U8 UapsdBitmap; ++ TDLS_U8 UapsdMaxSp; /* MAX_SP */ ++ ++ TDLS_U16 u2Capability; ++#define TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN 5 ++ TDLS_U8 aucExtCap[TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN]; ++ TDLS_U16 u2ExtCapLen; ++ ++ TDLS_CMD_PEER_UPDATE_HT_CAP_T rHtCap; ++ BOOLEAN fgIsSupHt; ++ ++} TDLS_CMD_PEER_UPDATE_T; ++ ++/* Command to TDLS core module */ ++typedef enum _TDLS_CMD_CORE_ID { ++ TDLS_CORE_CMD_TEST_NULL_RCV = 0x00, ++ TDLS_CORE_CMD_TEST_PTI_RSP = 0x01, ++ TDLS_CORE_CMD_MIB_UPDATE = 0x02, ++ TDLS_CORE_CMD_TEST_TX_FAIL_SKIP = 0x03, ++ TDLS_CORE_CMD_UAPSD_CONF = 0x04, ++ TDLS_CORE_CMD_TEST_DATA_RCV = 0x05, ++ TDLS_CORE_CMD_TEST_PTI_REQ = 0x06, ++ TDLS_CORE_CMD_TEST_CHSW_REQ = 0x07, ++ TDLS_CORE_CMD_CHSW_CONF = 0x08, ++ TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP = 0x09, ++ TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP = 0x0a, ++ TDLS_CORE_CMD_TEST_CHSW_RSP = 0x0b, ++ TDLS_CORE_CMD_TEST_SCAN_SKIP = 0x0c, ++ TDLS_CORE_CMD_SETUP_CONF = 0x0d, ++ TDLS_CORE_CMD_TEST_TEAR_DOWN = 0x0e, ++ TDLS_CORE_CMD_KEY_INFO = 0x0f, ++ TDLS_CORE_CMD_TEST_PTI_TX_FAIL = 0x10 ++} TDLS_CMD_CORE_ID; ++ ++typedef struct _TDLS_CMD_CORE_TEST_NULL_RCV_T { ++ ++ TDLS_U32 u4PM; ++} TDLS_CMD_CORE_TEST_NULL_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T { ++ ++ TDLS_U32 u4DialogToken; ++} TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T { ++ ++ TDLS_U32 u4DialogToken; ++ TDLS_U32 u4PM; ++} TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T { ++ ++ TDLS_U32 u4ReasonCode; ++} TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T { ++ ++ TDLS_U32 u4Chan; ++ TDLS_U32 u4RegClass; ++ TDLS_U32 u4SecChanOff; ++ TDLS_U32 u4SwitchTime; ++ TDLS_U32 u4SwitchTimeout; ++} TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T { ++ ++ TDLS_U32 u4Chan; ++ TDLS_U32 u4SwitchTime; ++ TDLS_U32 u4SwitchTimeout; ++ TDLS_U32 u4StatusCode; ++} TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_DATA_RCV_T { ++ ++ TDLS_U32 u4PM; ++ TDLS_U32 u4UP; ++ TDLS_U32 u4EOSP; ++ TDLS_U32 u4IsNull; ++} TDLS_CMD_CORE_TEST_DATA_RCV_T; ++ ++typedef struct _TDLS_CMD_CORE_MIB_PARAM_UPDATE_T { ++ ++ BOOLEAN Tdlsdot11TunneledDirectLinkSetupImplemented; ++ BOOLEAN Tdlsdot11TDLSPeerUAPSDBufferSTAActivated; ++ BOOLEAN Tdlsdot11TDLSPeerPSMActivated; ++ TDLS_U16 Tdlsdot11TDLSPeerUAPSDIndicationWindow; ++ BOOLEAN Tdlsdot11TDLSChannelSwitchingActivated; ++ TDLS_U8 Tdlsdot11TDLSPeerSTAMissingAckRetryLimit; ++ TDLS_U8 Tdlsdot11TDLSResponseTimeout; ++ TDLS_U16 Tdlsdot11TDLSProbeDelay; ++ TDLS_U8 Tdlsdot11TDLSDiscoveryRequestWindow; ++ TDLS_U8 Tdlsdot11TDLSACDeterminationInterval; ++} TDLS_CMD_CORE_MIB_PARAM_UPDATE_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_UAPSD_CONFIG_T { ++ ++ BOOLEAN fgIsSpTimeoutSkip; ++ BOOLEAN fgIsPtiTimeoutSkip; ++} TDLS_CMD_CORE_UAPSD_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_SETUP_CONFIG_T { ++ ++ BOOLEAN fgIs2040Supported; ++} TDLS_CMD_CORE_SETUP_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_CHSW_CONFIG_T { ++ ++ TDLS_U8 ucNetTypeIndex; ++ BOOLEAN fgIsChSwEnabled; ++ BOOLEAN fgIsChSwStarted; ++ TDLS_U8 ucRegClass; ++ TDLS_U8 ucTargetChan; ++ TDLS_U8 ucSecChanOff; ++ BOOLEAN fgIsChSwRegular; ++} TDLS_CMD_CORE_CHSW_CONFIG_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PROHIBIT_T { ++ ++ BOOLEAN fgIsEnable; ++ BOOLEAN fgIsSet; ++} TDLS_CMD_CORE_TEST_PROHIBIT_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_SCAN_SKIP_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_SCAN_SKIP_T; ++ ++typedef struct _TDLS_CMD_CORE_INFO_DISPLAY_T { ++ ++ BOOLEAN fgIsToClearAllHistory; ++} TDLS_CMD_CORE_INFO_DISPLAY_T; ++ ++typedef struct _TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T { ++ ++ BOOLEAN fgIsEnable; ++} TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T; ++ ++typedef struct _TDLS_CMD_CORE_T { ++ ++ TDLS_U32 u4Command; /* TDLS_CMD_CORE_ID */ ++ ++ TDLS_U8 aucPeerMac[6]; ++ TDLS_U8 ucNetTypeIndex; ++ ++#define TDLS_CMD_CORE_RESERVED_SIZE 50 ++ union { ++ TDLS_CMD_CORE_TEST_NULL_RCV_T rCmdNullRcv; ++ TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T rCmdPtiReqRcv; ++ TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T rCmdPtiRspRcv; ++ TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T rCmdTearDownRcv; ++ TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T rCmdChStReqRcv; ++ TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T rCmdChStRspRcv; ++ TDLS_CMD_CORE_TEST_DATA_RCV_T rCmdDatRcv; ++ TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T rCmdTxFailSkip; ++ TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T rCmdKeepAliveSkip; ++ TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T rCmdChSwTimeoutSkip; ++ TDLS_CMD_CORE_TEST_PROHIBIT_T rCmdProhibit; ++ TDLS_CMD_CORE_TEST_SCAN_SKIP_T rCmdScanSkip; ++ TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T rCmdPtiTxFail; ++ ++ TDLS_CMD_CORE_MIB_PARAM_UPDATE_T rCmdMibUpdate; ++ TDLS_CMD_CORE_UAPSD_CONFIG_T rCmdUapsdConf; ++ TDLS_CMD_CORE_CHSW_CONFIG_T rCmdChSwConf; ++ TDLS_CMD_CORE_SETUP_CONFIG_T rCmdSetupConf; ++ TDLS_CMD_CORE_INFO_DISPLAY_T rCmdInfoDisplay; ++ TDLS_U8 Reserved[TDLS_CMD_CORE_RESERVED_SIZE]; ++ } Content; ++} TDLS_CMD_CORE_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* ++ assign station record idx for the packet only when STA_STATE_3 ++ Or we will try to send data frame when the TDLS peer's state is STA_STATE_1 ++ EX: ++ 1. mtk_cfg80211_add_station: First create the STA_RECORD_T; ++ 2. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. ++ 3. mtk_cfg80211_add_station: Change state to STA_STATE_1. ++ 4. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. ++*/ ++#define TDLSEX_STA_REC_IDX_GET(__prAdapter__, __MsduInfo__) \ ++{ \ ++ STA_RECORD_T *__StaRec__; \ ++ __MsduInfo__->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; \ ++ __StaRec__ = cnmGetStaRecByAddress(__prAdapter__, \ ++ (UINT_8) NETWORK_TYPE_AIS_INDEX, \ ++ __MsduInfo__->aucEthDestAddr); \ ++ if ((__StaRec__ != NULL) && \ ++ ((__StaRec__)->ucStaState == STA_STATE_3) && \ ++ (IS_TDLS_STA(__StaRec__))) { \ ++ __MsduInfo__->ucStaRecIndex = __StaRec__->ucIndex; \ ++ } \ ++} ++ ++/* fill wiphy flag */ ++#define TDLSEX_WIPHY_FLAGS_INIT(__fgFlag__)\ ++{ \ ++ __fgFlag__ |= (WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP);\ ++} ++ ++/* assign user priority of a TDLS action frame */ ++/* ++ According to 802.11z: Setup req/resp are sent in AC_BK, otherwise we should default ++ to AC_VI. ++*/ ++#define TDLSEX_UP_ASSIGN(__UserPriority__) \ ++{ \ ++ __UserPriority__ = USER_PRIORITY_TDLS; \ ++} ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++int ++TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *buf, size_t len); ++ ++int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, enum nl80211_tdls_operation oper); ++ ++VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE); ++ ++VOID TdlsexEventHandle(P_GLUE_INFO_T prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey); ++ ++VOID TdlsexInit(ADAPTER_T *prAdapter); ++ ++BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter); ++ ++TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++VOID ++TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode); ++ ++TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++TDLS_STATUS TdlsexPeerAdd(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); ++ ++TDLS_STATUS TdlsexPeerUpdate(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); ++ ++BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt); ++ ++VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen); ++ ++TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo); ++ ++VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota); ++ ++VOID TdlsexUninit(ADAPTER_T *prAdapter); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#endif /* _TDLS_EXTR_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h +new file mode 100644 +index 000000000000..7ab62dae8813 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h +@@ -0,0 +1,244 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/typedef.h#1 ++*/ ++ ++/*! \file typedef.h ++ \brief Declaration of data type and return values of internal protocol stack. ++ ++ In this file we declare the data type and return values which will be exported ++ to the GLUE Layer. ++*/ ++ ++/* ++** Log: typedef.h ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add necessary changes to driver data paths. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add definitions for module migration. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add Ethernet destination address information in packet info for TX ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:41:37 GMT mtk01461 ++** Update PACKET_INFO_INIT for TX Path ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:30:17 GMT mtk01461 ++** Add parameter in PACKET_INFO_T for HIF Loopback ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:22 GMT mtk01461 ++** Fix LINT warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:28 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:54 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _TYPEDEF_H ++#define _TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/* ieee80211.h of linux has duplicated definitions */ ++#if defined(WLAN_STATUS_SUCCESS) ++#undef WLAN_STATUS_SUCCESS ++#endif ++ ++#define WLAN_STATUS_SUCCESS ((WLAN_STATUS) 0x00000000L) ++#define WLAN_STATUS_PENDING ((WLAN_STATUS) 0x00000103L) ++#define WLAN_STATUS_NOT_ACCEPTED ((WLAN_STATUS) 0x00010003L) ++ ++#define WLAN_STATUS_MEDIA_CONNECT ((WLAN_STATUS) 0x4001000BL) ++#define WLAN_STATUS_MEDIA_DISCONNECT ((WLAN_STATUS) 0x4001000CL) ++#define WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ((WLAN_STATUS) 0x4001000DL) ++ ++#define WLAN_STATUS_MEDIA_SPECIFIC_INDICATION ((WLAN_STATUS) 0x40010012L) ++ ++#define WLAN_STATUS_SCAN_COMPLETE ((WLAN_STATUS) 0x60010001L) ++#define WLAN_STATUS_MSDU_OK ((WLAN_STATUS) 0x60010002L) ++ ++/* TODO(Kevin): double check if 0x60010001 & 0x60010002 is proprietary */ ++#define WLAN_STATUS_ROAM_OUT_FIND_BEST ((WLAN_STATUS) 0x60010101L) ++#define WLAN_STATUS_ROAM_DISCOVERY ((WLAN_STATUS) 0x60010102L) ++ ++#define WLAN_STATUS_FAILURE ((WLAN_STATUS) 0xC0000001L) ++#define WLAN_STATUS_RESOURCES ((WLAN_STATUS) 0xC000009AL) ++#define WLAN_STATUS_NOT_SUPPORTED ((WLAN_STATUS) 0xC00000BBL) ++ ++#define WLAN_STATUS_MULTICAST_FULL ((WLAN_STATUS) 0xC0010009L) ++#define WLAN_STATUS_INVALID_PACKET ((WLAN_STATUS) 0xC001000FL) ++#define WLAN_STATUS_ADAPTER_NOT_READY ((WLAN_STATUS) 0xC0010011L) ++#define WLAN_STATUS_NOT_INDICATING ((WLAN_STATUS) 0xC0010013L) ++#define WLAN_STATUS_INVALID_LENGTH ((WLAN_STATUS) 0xC0010014L) ++#define WLAN_STATUS_INVALID_DATA ((WLAN_STATUS) 0xC0010015L) ++#define WLAN_STATUS_BUFFER_TOO_SHORT ((WLAN_STATUS) 0xC0010016L) ++ ++#define WLAN_STATUS_BWCS_UPDATE ((WLAN_STATUS) 0xC0010017L) ++ ++#define WLAN_STATUS_CONNECT_INDICATION ((WLAN_STATUS) 0xC0010018L) ++ ++/* NIC status flags */ ++#define ADAPTER_FLAG_HW_ERR 0x00400000 ++ ++/* Type Length */ ++#define TL_IPV4 0x0008 ++#define TL_IPV6 0xDD86 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for GLUE_INFO structure */ ++typedef struct _GLUE_INFO_T GLUE_INFO_T, *P_GLUE_INFO_T; ++ ++/* Type definition for WLAN STATUS */ ++typedef UINT_32 WLAN_STATUS, *P_WLAN_STATUS; ++ ++/* Type definition for ADAPTER structure */ ++typedef struct _ADAPTER_T ADAPTER_T, *P_ADAPTER_T; ++ ++/* Type definition for MESSAGE HEADER structure */ ++typedef struct _MSG_HDR_T MSG_HDR_T, *P_MSG_HDR_T; ++ ++/* Type definition for WLAN configuration */ ++typedef struct _WLAN_CFG_T WLAN_CFG_T, *P_WLAN_CFG_T; ++ ++/* Type definition for WLAN configuration entry */ ++typedef struct _WLAN_CFG_ENTRY_T WLAN_CFG_ENTRY_T, *P_WLAN_CFG_ENTRY_T; ++ ++/* Type definition for WLAN configuration callback */ ++typedef WLAN_STATUS(*WLAN_CFG_SET_CB) (P_ADAPTER_T prAdapter, ++ PUINT_8 pucKey, PUINT_8 pucValue, PVOID pPrivate, UINT_32 u4Flags); ++ ++/* Type definition for Pointer to OS Native Packet */ ++typedef void *P_NATIVE_PACKET; ++ ++/* Type definition for STA_RECORD_T structure to handle the connectivity and packet reception ++ * for a particular STA. ++ */ ++typedef struct _STA_RECORD_T STA_RECORD_T, *P_STA_RECORD_T, **PP_STA_RECORD_T; ++ ++/* CMD_INFO_T is used by Glue Layer to send a cluster of Command(OID) information to ++ * the TX Path to reduce the parameters of a function call. ++ */ ++typedef struct _CMD_INFO_T CMD_INFO_T, *P_CMD_INFO_T; ++ ++/* Following typedef should be removed later, because Glue Layer should not ++ * be aware of following data type. ++ */ ++typedef struct _SW_RFB_T SW_RFB_T, *P_SW_RFB_T, **PP_SW_RFB_T; ++ ++typedef struct _MSDU_INFO_T MSDU_INFO_T, *P_MSDU_INFO_T; ++ ++typedef struct _REG_ENTRY_T REG_ENTRY_T, *P_REG_ENTRY_T; ++ ++/* IST handler definition */ ++typedef VOID(*IST_EVENT_FUNCTION) (P_ADAPTER_T); ++ ++/* Type definition for function pointer of timer handler */ ++typedef VOID(*PFN_TIMER_CALLBACK) (IN P_GLUE_INFO_T); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h +new file mode 100644 +index 000000000000..e8937166dc4f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h +@@ -0,0 +1,352 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_bow.h#1 ++*/ ++ ++/*! \file "wlan_bow.h" ++ \brief This file contains the declairations of 802.11 PAL ++ command processing routines for ++ MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_bow.h ++ * ++ * 05 25 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add BoW Cancel Scan Request and Turn On deactive network function. ++ * ++ * 05 23 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Add some BoW error handling. ++ * ++ * 05 21 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Protect BoW connection establishment. ++ * ++ * 05 17 2011 terry.wu ++ * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting ++ * Send deauth while disconnecting BoW link. ++ * ++ * 05 06 2011 terry.wu ++ * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue ++ * Fix BoW Multiple Physical Link connect/disconnect issue. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW table. ++ * ++ * 02 16 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update bowString and channel grant. ++ * ++ * 01 11 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update BOW Activity Report structure and bug fix. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * 1) all BT physical handles shares the same RSSI/Link Quality. ++ * 2) simplify BT command composing ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++#ifndef _WLAN_BOW_H ++#define _WLAN_BOW_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "nic/bow.h" ++#include "nic/cmd_buf.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++#if CFG_BOW_TEST ++extern UINT_32 g_arBowRevPalPacketTime[32]; ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define BOWCMD_STATUS_SUCCESS 0 ++#define BOWCMD_STATUS_FAILURE 1 ++#define BOWCMD_STATUS_UNACCEPTED 2 ++#define BOWCMD_STATUS_INVALID 3 ++#define BOWCMD_STATUS_TIMEOUT 4 ++ ++#define BOW_WILDCARD_SSID "AMP" ++#define BOW_WILDCARD_SSID_LEN 3 ++#define BOW_SSID_LEN 21 ++ ++ /* 0: query, 1: setup, 2: destroy */ ++#define BOW_QUERY_CMD 0 ++#define BOW_SETUP_CMD 1 ++#define BOW_DESTROY_CMD 2 ++ ++#define BOW_INITIATOR 0 ++#define BOW_RESPONDER 1 ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++typedef struct _BOW_TABLE_T { ++ UINT_8 ucAcquireID; ++ BOOLEAN fgIsValid; ++ ENUM_BOW_DEVICE_STATE eState; ++ UINT_8 aucPeerAddress[6]; ++ /* UINT_8 ucRole; */ ++ /* UINT_8 ucChannelNum; */ ++ UINT_16 u2Reserved; ++} BOW_TABLE_T, *P_BOW_TABLE_T; ++ ++typedef WLAN_STATUS(*PFN_BOW_CMD_HANDLE) (P_ADAPTER_T, P_AMPC_COMMAND); ++ ++typedef struct _BOW_CMD_T { ++ UINT_8 uCmdID; ++ PFN_BOW_CMD_HANDLE pfCmdHandle; ++} BOW_CMD_T, *P_BOW_CMD_T; ++ ++typedef struct _BOW_EVENT_ACTIVITY_REPORT_T { ++ UINT_8 ucReason; ++ UINT_8 aucReserved; ++ UINT_8 aucPeerAddress[6]; ++} BOW_EVENT_ACTIVITY_REPORT_T, *P_BOW_EVENT_ACTIVITY_REPORT_T; ++ ++/* ++ucReason: 0: success ++ 1: general failure ++ 2: too much time (> 2/3 second totally) requested for scheduling. ++ Others: reserved. ++*/ ++ ++typedef struct _BOW_EVENT_SYNC_TSF_T { ++ UINT_64 u4TsfTime; ++ UINT_32 u4TsfSysTime; ++ UINT_32 u4ScoTime; ++ UINT_32 u4ScoSysTime; ++} BOW_EVENT_SYNC_TSF_T, *P_BOW_EVENT_SYNC_TSF_T; ++ ++typedef struct _BOW_ACTIVITY_REPORT_BODY_T { ++ UINT_32 u4StartTime; ++ UINT_32 u4Duration; ++ UINT_32 u4Periodicity; ++} BOW_ACTIVITY_REPORT_BODY_T, *P_BOW_ACTIVITY_REPORT_BODY_T; ++ ++typedef struct _BOW_ACTIVITY_REPORT_T { ++ UINT_8 aucPeerAddress[6]; ++ UINT_8 ucScheduleKnown; ++ UINT_8 ucNumReports; ++ BOW_ACTIVITY_REPORT_BODY_T arBowActivityReportBody[MAX_ACTIVITY_REPORT]; ++} BOW_ACTIVITY_REPORT_T, *P_BOW_ACTIVITY_REPORT_T; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*--------------------------------------------------------------*/ ++/* Firmware Command Packer */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucCID, ++ BOOLEAN fgSetQuery, ++ BOOLEAN fgNeedResp, ++ PFN_CMD_DONE_HANDLER pfCmdDoneHandler, ++ PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, ++ UINT_32 u4SetQueryInfoLen, PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber); ++ ++/*--------------------------------------------------------------*/ ++/* Command Dispatcher */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle command */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); ++ ++VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf); ++ ++/*--------------------------------------------------------------*/ ++/* Callbacks for event indication */ ++/*--------------------------------------------------------------*/ ++VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID bowStopping(IN P_ADAPTER_T prAdapter); ++ ++VOID bowStarting(IN P_ADAPTER_T prAdapter); ++ ++VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); ++ ++BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); ++ ++VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++ ++VOID bowResponderScan(IN P_ADAPTER_T prAdapter); ++ ++VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention); ++ ++VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); ++ ++VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID ++bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); ++ ++VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); ++ ++WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); ++ ++VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); ++ ++BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); ++ ++BOOLEAN ++bowValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); ++ ++VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); ++ ++VOID bowRequestCh(IN P_ADAPTER_T prAdapter); ++ ++VOID bowReleaseCh(IN P_ADAPTER_T prAdapter); ++ ++VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam); ++ ++BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); ++ ++BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable); ++ ++BOOLEAN ++bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx); ++ ++BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx); ++ ++ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); ++ ++BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState); ++ ++BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif ++#endif /* _WLAN_BOW_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h +new file mode 100644 +index 000000000000..87259397a93d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h +@@ -0,0 +1,1001 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_lib.h#1 ++*/ ++ ++/*! \file "wlan_lib.h" ++ \brief The declaration of the functions of the wlanAdpater objects ++ ++ Detail description. ++*/ ++ ++/* ++** Log: wlan_lib.h ++ * ++ * 06 08 2012 eason.tsai ++ * NULL ++ * Nvram context covert from 6620 to 6628 for old 6620 meta tool ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for ++ * preferred band configuration with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for ++ * setting preferred band configuration corresponding to network type. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * eliminate win32 native data types. ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 10 03 2011 cp.wu ++ * [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware downloading aggregated path. ++ * ++ * 09 20 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * change window registry of driver for roaming. ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 25 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add DFS switch. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, ++ * TX deauth to a disconnecting device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 22 2011 jeffrey.chang ++ * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time ++ * modify driver to set OSC stable time after f/w download ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Support current measure mode, assigned by registry (XP only). ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result ++ * in OID handling layer when the corresponding BSS is disconnected due to beacon timeout ++ * remove from scanning result when the BSS is disconnected due to beacon timeout. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to ++ * disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature ++ * Modify online scan as a run-time adjustable option (for Windows, in registry) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add AT GO test configure mode under WinXP. ++ * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * . ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid ++ * descriptor underflow under concurrent network operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * simplify timer usage. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add extra 64 adjustable parameters for CoEX scenario. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * 2) add 2 kal API for later integration ++ * ++ * 04 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change to use WIFI_TCM_ALWAYS_ON as firmware image ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add two option for ACK and ENCRYPTION for firmware download ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * separate wlanProcesQueuePacket() into 2 APIs upon request ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add new API: wlanProcessQueuedPackets() ++ * ++ * 02 11 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. add logic for firmware download ++ * * * 2. firmware image filename and start/load address are now retrieved from registry ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * 4) nicRxWaitResponse() revised ++ * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * 4. correct some HAL implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:39:55 GMT mtk02752 ++** eliminate unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:58:41 GMT mtk01084 ++** update for new macro define ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-19 10:43:06 GMT mtk01461 ++** Add wlanReleasePendingOid() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-13 16:38:44 GMT mtk01084 ++** add WIFI start function ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-08 16:51:14 GMT mtk01084 ++** Update for the image download part ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:57:38 GMT mtk01461 ++** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:31:02 GMT mtk01461 ++** Add declaration of FW Image download reference code ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:31 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:04 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_LIB_H ++#define _WLAN_LIB_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "CFG_Wifi_File.h" ++#include "rlm_domain.h" ++#include "wlan_typedef.h" ++ ++ ++extern BOOLEAN fgIsResetting; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define MAX_NUM_GROUP_ADDR 32 /* max number of group addresses */ ++ ++#define TX_CS_TCP_UDP_GEN BIT(1) ++#define TX_CS_IP_GEN BIT(0) ++ ++#define CSUM_OFFLOAD_EN_TX_TCP BIT(0) ++#define CSUM_OFFLOAD_EN_TX_UDP BIT(1) ++#define CSUM_OFFLOAD_EN_TX_IP BIT(2) ++#define CSUM_OFFLOAD_EN_RX_TCP BIT(3) ++#define CSUM_OFFLOAD_EN_RX_UDP BIT(4) ++#define CSUM_OFFLOAD_EN_RX_IPv4 BIT(5) ++#define CSUM_OFFLOAD_EN_RX_IPv6 BIT(6) ++#define CSUM_OFFLOAD_EN_TX_MASK BITS(0, 2) ++#define CSUM_OFFLOAD_EN_ALL BITS(0, 6) ++ ++/* TCP, UDP, IP Checksum */ ++#define RX_CS_TYPE_UDP BIT(7) ++#define RX_CS_TYPE_TCP BIT(6) ++#define RX_CS_TYPE_IPv6 BIT(5) ++#define RX_CS_TYPE_IPv4 BIT(4) ++ ++#define RX_CS_STATUS_UDP BIT(3) ++#define RX_CS_STATUS_TCP BIT(2) ++#define RX_CS_STATUS_IP BIT(0) ++ ++#define CSUM_NOT_SUPPORTED 0x0 ++ ++#define TXPWR_USE_PDSLOPE 0 ++ ++/* NVRAM error code definitions */ ++#define NVRAM_ERROR_VERSION_MISMATCH BIT(1) ++#define NVRAM_ERROR_INVALID_TXPWR BIT(2) ++#define NVRAM_ERROR_INVALID_DPD BIT(3) ++#define NVRAM_ERROR_INVALID_MAC_ADDR BIT(4) ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++#define NVRAM_POWER_LIMIT_TABLE_INVALID BIT(5) ++#endif ++ ++#define NUM_TC_RESOURCE_TO_STATISTICS 4 ++ ++#define WLAN_CFG_ARGV_MAX 8 ++#define WLAN_CFG_ENTRY_NUM_MAX 128 ++#define WLAN_CFG_KEY_LEN_MAX 32 /* include \x00 EOL */ ++#define WLAN_CFG_VALUE_LEN_MAX 32 /* include \x00 EOL */ ++#define WLAN_CFG_FLAG_SKIP_CB BIT(0) ++#define WLAN_CFG_FILE_BUF_SIZE 2048 ++ ++#define WLAN_CFG_SET_CHIP_LEN_MAX 10 ++#define WLAN_CFG_SET_DEBUG_LEVEL_LEN_MAX 10 ++#define WLAN_CFG_SET_SW_CTRL_LEN_MAX 10 ++ ++#define WLAN_OID_TIMEOUT_THRESHOLD 2000 /* OID timeout (in ms) */ ++#define WLAN_OID_TIMEOUT_THRESHOLD_IN_RESETTING 300 /* OID timeout during chip-resetting (in ms) */ ++ ++#define WLAN_OID_NO_ACK_THRESHOLD 3 ++ ++#define WLAN_TX_THREAD_TASK_PRIORITY 0 /* If not setting the priority, 0 is the default */ ++#define WLAN_TX_THREAD_TASK_NICE (-10) /* If not setting the nice, -10 is the default */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC) (IN P_ADAPTER_T prAdapter, ++ IN PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); ++ ++typedef enum _ENUM_CSUM_TYPE_T { ++ CSUM_TYPE_IPV4, ++ CSUM_TYPE_IPV6, ++ CSUM_TYPE_TCP, ++ CSUM_TYPE_UDP, ++ CSUM_TYPE_NUM ++} ENUM_CSUM_TYPE_T, *P_ENUM_CSUM_TYPE_T; ++ ++typedef enum _ENUM_CSUM_RESULT_T { ++ CSUM_RES_NONE, ++ CSUM_RES_SUCCESS, ++ CSUM_RES_FAILED, ++ CSUM_RES_NUM ++} ENUM_CSUM_RESULT_T, *P_ENUM_CSUM_RESULT_T; ++ ++typedef enum _ENUM_PHY_MODE_T { ++ ENUM_PHY_2G4_CCK, ++ ENUM_PHY_2G4_OFDM_BPSK, ++ ENUM_PHY_2G4_OFDM_QPSK, ++ ENUM_PHY_2G4_OFDM_16QAM, ++ ENUM_PHY_2G4_OFDM_48M, ++ ENUM_PHY_2G4_OFDM_54M, ++ ENUM_PHY_2G4_HT20_BPSK, ++ ENUM_PHY_2G4_HT20_QPSK, ++ ENUM_PHY_2G4_HT20_16QAM, ++ ENUM_PHY_2G4_HT20_MCS5, ++ ENUM_PHY_2G4_HT20_MCS6, ++ ENUM_PHY_2G4_HT20_MCS7, ++ ENUM_PHY_2G4_HT40_BPSK, ++ ENUM_PHY_2G4_HT40_QPSK, ++ ENUM_PHY_2G4_HT40_16QAM, ++ ENUM_PHY_2G4_HT40_MCS5, ++ ENUM_PHY_2G4_HT40_MCS6, ++ ENUM_PHY_2G4_HT40_MCS7, ++ ENUM_PHY_5G_OFDM_BPSK, ++ ENUM_PHY_5G_OFDM_QPSK, ++ ENUM_PHY_5G_OFDM_16QAM, ++ ENUM_PHY_5G_OFDM_48M, ++ ENUM_PHY_5G_OFDM_54M, ++ ENUM_PHY_5G_HT20_BPSK, ++ ENUM_PHY_5G_HT20_QPSK, ++ ENUM_PHY_5G_HT20_16QAM, ++ ENUM_PHY_5G_HT20_MCS5, ++ ENUM_PHY_5G_HT20_MCS6, ++ ENUM_PHY_5G_HT20_MCS7, ++ ENUM_PHY_5G_HT40_BPSK, ++ ENUM_PHY_5G_HT40_QPSK, ++ ENUM_PHY_5G_HT40_16QAM, ++ ENUM_PHY_5G_HT40_MCS5, ++ ENUM_PHY_5G_HT40_MCS6, ++ ENUM_PHY_5G_HT40_MCS7, ++ ENUM_PHY_MODE_NUM ++} ENUM_PHY_MODE_T, *P_ENUM_PHY_MODE_T; ++ ++typedef enum _ENUM_POWER_SAVE_POLL_MODE_T { ++ ENUM_POWER_SAVE_POLL_DISABLE, ++ ENUM_POWER_SAVE_POLL_LEGACY_NULL, ++ ENUM_POWER_SAVE_POLL_QOS_NULL, ++ ENUM_POWER_SAVE_POLL_NUM ++} ENUM_POWER_SAVE_POLL_MODE_T, *P_ENUM_POWER_SAVE_POLL_MODE_T; ++ ++typedef enum _ENUM_AC_TYPE_T { ++ ENUM_AC_TYPE_AC0, ++ ENUM_AC_TYPE_AC1, ++ ENUM_AC_TYPE_AC2, ++ ENUM_AC_TYPE_AC3, ++ ENUM_AC_TYPE_AC4, ++ ENUM_AC_TYPE_AC5, ++ ENUM_AC_TYPE_AC6, ++ ENUM_AC_TYPE_BMC, ++ ENUM_AC_TYPE_NUM ++} ENUM_AC_TYPE_T, *P_ENUM_AC_TYPE_T; ++ ++typedef enum _ENUM_ADV_AC_TYPE_T { ++ ENUM_ADV_AC_TYPE_RX_NSW, ++ ENUM_ADV_AC_TYPE_RX_PTA, ++ ENUM_ADV_AC_TYPE_RX_SP, ++ ENUM_ADV_AC_TYPE_TX_PTA, ++ ENUM_ADV_AC_TYPE_TX_RSP, ++ ENUM_ADV_AC_TYPE_NUM ++} ENUM_ADV_AC_TYPE_T, *P_ENUM_ADV_AC_TYPE_T; ++ ++typedef enum _ENUM_REG_CH_MAP_T { ++ REG_CH_MAP_COUNTRY_CODE, ++ REG_CH_MAP_TBL_IDX, ++ REG_CH_MAP_CUSTOMIZED, ++ REG_CH_MAP_NUM ++} ENUM_REG_CH_MAP_T, *P_ENUM_REG_CH_MAP_T; ++ ++#define CHIP_CONFIG_RESP_SIZE 320 ++enum { ++ CHIP_CONFIG_TYPE_WO_RESPONSE = 0x00, ++ CHIP_CONFIG_TYPE_MEM8 = 0x01, ++ CHIP_CONFIG_TYPE_MEM32 = 0x02, ++ CHIP_CONFIG_TYPE_ASCII = 0x03, ++ CHIP_CONFIG_TYPE_BINARY = 0x04, ++ CHIP_CONFIG_TYPE_DRV_PASSTHROUGH = 0x05, ++ CHIP_CONFIG_TYPE_END ++}; ++ ++typedef struct _SET_TXPWR_CTRL_T { ++ INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c2GHotspotPwrOffset; ++ INT_8 c2GP2pPwrOffset; ++ INT_8 c2GBowPwrOffset; ++ INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ ++ INT_8 c5GHotspotPwrOffset; ++ INT_8 c5GP2pPwrOffset; ++ INT_8 c5GBowPwrOffset; ++ UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence ++ in the same channel ++ 0: Highest power has priority ++ 1: Lowest power has priority */ ++ INT_8 acReserved1[3]; /* Must be zero */ ++ ++ /* Power limit by channel for all data rates */ ++ INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ ++ INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ ++ INT_8 acReserved2[2]; /* Must be zero */ ++} SET_TXPWR_CTRL_T, *P_SET_TXPWR_CTRL_T; ++ ++/* For storing driver initialization value from glue layer */ ++typedef struct _REG_INFO_T { ++ UINT_32 u4SdBlockSize; /* SDIO block size */ ++ UINT_32 u4SdBusWidth; /* SDIO bus width. 1 or 4 */ ++ UINT_32 u4SdClockRate; /* SDIO clock rate. (in unit of HZ) */ ++ UINT_32 u4StartAddress; /* Starting address of Wi-Fi Firmware */ ++ UINT_32 u4LoadAddress; /* Load address of Wi-Fi Firmware */ ++ UINT_16 aucFwImgFilename[65]; /* Firmware filename */ ++ UINT_16 aucFwImgFilenameE6[65]; /* Firmware filename for E6 */ ++ UINT_32 u4StartFreq; /* Start Frequency for Ad-Hoc network : in unit of KHz */ ++ UINT_32 u4AdhocMode; /* Default mode for Ad-Hoc network : ENUM_PARAM_AD_HOC_MODE_T */ ++ UINT_32 u4RddStartFreq; ++ UINT_32 u4RddStopFreq; ++ UINT_32 u4RddTestMode; ++ UINT_32 u4RddShutFreq; ++ UINT_32 u4RddDfs; ++ INT_32 i4HighRssiThreshold; ++ INT_32 i4MediumRssiThreshold; ++ INT_32 i4LowRssiThreshold; ++ INT_32 au4TxPriorityTag[ENUM_AC_TYPE_NUM]; ++ INT_32 au4RxPriorityTag[ENUM_AC_TYPE_NUM]; ++ INT_32 au4AdvPriorityTag[ENUM_ADV_AC_TYPE_NUM]; ++ UINT_32 u4FastPSPoll; ++ UINT_32 u4PTA; /* 0: disable, 1: enable */ ++ UINT_32 u4TXLimit; /* 0: disable, 1: enable */ ++ UINT_32 u4SilenceWindow; /* range: 100 - 625, unit: us */ ++ UINT_32 u4TXLimitThreshold; /* range: 250 - 1250, unit: us */ ++ UINT_32 u4PowerMode; ++ UINT_32 fgEnArpFilter; ++ UINT_32 u4PsCurrentMeasureEn; ++ UINT_32 u4UapsdAcBmp; ++ UINT_32 u4MaxSpLen; ++ UINT_32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online scan */ ++ UINT_32 fgDisBcnLostDetection; /* 0: enable online scan, non-zero: disable online scan */ ++ UINT_32 u4FixedRate; /* 0: automatic, non-zero: fixed rate */ ++ UINT_32 u4ArSysParam0; ++ UINT_32 u4ArSysParam1; ++ UINT_32 u4ArSysParam2; ++ UINT_32 u4ArSysParam3; ++ UINT_32 fgDisRoaming; /* 0:enable roaming 1:disable */ ++ ++ /* NVRAM - MP Data -START- */ ++ UINT_8 aucMacAddr[6]; ++ UINT_16 au2CountryCode[4]; /* Country code (in ISO 3166-1 expression, ex: "US", "TW") */ ++ TX_PWR_PARAM_T rTxPwr; ++ UINT_8 aucEFUSE[144]; ++ UINT_8 ucTxPwrValid; ++ UINT_8 ucSupport5GBand; ++ UINT_8 fg2G4BandEdgePwrUsed; ++ INT_8 cBandEdgeMaxPwrCCK; ++ INT_8 cBandEdgeMaxPwrOFDM20; ++ INT_8 cBandEdgeMaxPwrOFDM40; ++ ENUM_REG_CH_MAP_T eRegChannelListMap; ++ UINT_8 ucRegChannelListIndex; ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ /* NVRAM - MP Data -END- */ ++ ++ /* NVRAM - Functional Data -START- */ ++ UINT_8 uc2G4BwFixed20M; ++ UINT_8 uc5GBwFixed20M; ++ UINT_8 ucEnable5GBand; ++ UINT_8 uc2GRssiCompensation; ++ UINT_8 uc5GRssiCompensation; ++ UINT_8 fgRssiCompensationValidbit; ++ UINT_8 ucRxAntennanumber; ++ /* NVRAM - Functional Data -END- */ ++ ++} REG_INFO_T, *P_REG_INFO_T; ++ ++/* for divided firmware loading */ ++typedef struct _FWDL_SECTION_INFO_T { ++ UINT_32 u4Offset; ++ UINT_32 u4Reserved; ++ UINT_32 u4Length; ++ UINT_32 u4DestAddr; ++} FWDL_SECTION_INFO_T, *P_FWDL_SECTION_INFO_T; ++ ++typedef struct _FIRMWARE_DIVIDED_DOWNLOAD_T { ++ UINT_32 u4Signature; ++ UINT_32 u4CRC; /* CRC calculated without first 8 bytes included */ ++ UINT_32 u4NumOfEntries; ++ UINT_32 u4Reserved; ++ FWDL_SECTION_INFO_T arSection[]; ++} FIRMWARE_DIVIDED_DOWNLOAD_T, *P_FIRMWARE_DIVIDED_DOWNLOAD_T; ++ ++typedef struct _PARAM_MCR_RW_STRUCT_T { ++ UINT_32 u4McrOffset; ++ UINT_32 u4McrData; ++} PARAM_MCR_RW_STRUCT_T, *P_PARAM_MCR_RW_STRUCT_T; ++ ++typedef struct _PARAM_GET_STA_STATISTICS { ++ UINT_8 ucInvalid; ++ UINT_8 ucVersion; ++ /* Per-STA statistic */ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ UINT_32 u4LinkScore; ++ UINT_32 u4Flag; ++ ++ /* From FW */ ++ UINT_8 ucPer; /* base: 128 */ ++ UINT_8 ucRcpi; ++ UINT_32 u4PhyMode; ++ UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ ++ ++ UINT_32 u4TxFailCount; ++ UINT_32 u4TxLifeTimeoutCount; ++ UINT_32 u4TxAverageAirTime; ++ ++ /* From driver */ ++ UINT_32 u4TxTotalCount; ++ UINT_32 u4TxExceedThresholdCount; ++ UINT_32 u4TxAverageProcessTime; ++ ++ UINT_32 u4TxMaxTime; ++ UINT_32 u4TxMaxHifTime; ++ UINT_32 u4TxAverageHifTime; ++ ++ /* ++ * How many packages Enqueue/Deqeue during statistics interval ++ */ ++ UINT_32 u4EnqueueCounter; ++ UINT_32 u4DequeueCounter; ++ ++ UINT_32 u4EnqueueStaCounter; ++ UINT_32 u4DequeueStaCounter; ++ ++ UINT_32 IsrCnt; ++ UINT_32 IsrPassCnt; ++ UINT_32 TaskIsrCnt; ++ ++ UINT_32 IsrAbnormalCnt; ++ UINT_32 IsrSoftWareCnt; ++ UINT_32 IsrRxCnt; ++ UINT_32 IsrTxCnt; ++ ++ UINT_32 au4TcResourceEmptyCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4DequeueNoTcResource[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcResourceBackCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ UINT_32 au4TcResourceUsedCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcResourceWantedCount[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ UINT_32 au4TcQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ /* Global queue management statistic */ ++ UINT_32 au4TcAverageQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ UINT_32 au4TcCurrentQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; ++ ++ /* Reserved fields */ ++ UINT_8 au4Reserved[32]; ++} PARAM_GET_STA_STA_STATISTICS, *P_PARAM_GET_STA_STATISTICS; ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR { ++ NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, ++ NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ ++ NL80211_TESTMODE_AVAILABLE_CHAN_NUM, ++} ENUM_TESTMODE_AVAILABLE_CHAN_ATTR; ++ ++typedef struct _LTE_SAFE_CH_INFO_T { ++ UINT_32 au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1]; ++} LTE_SAFE_CH_INFO_T, *P_CMD_LTE_SAFE_CH_INFO_T; ++ ++ /* Record Each CH Load */ ++typedef struct _PARAM_CHN_LOAD_INFO { ++ /* Per-CHN Load */ ++ UINT_32 u4Flag; ++ ++ UINT_8 ucChannel; ++ UINT_16 u2ChannelLoad; ++ UINT_8 au4Reserved[1]; ++ ++ UINT_16 u2APNum; ++ UINT_16 u2APNumTmpCountingBuf; ++ ++ /* Reserved fields */ ++ UINT_8 au4Reserved1[8]; ++} PARAM_CHN_LOAD_INFO, *P_PARAM_CHN_LOAD_INFO; ++ ++typedef struct _PARAM_GET_CHN_LOAD { ++ LTE_SAFE_CH_INFO_T rLteSafeChnList; ++ PARAM_CHN_LOAD_INFO rEachChnLoad[MAX_AUTO_CHAL_NUM]; ++ BOOLEAN fgDataReadyBit; ++ UINT_8 au4Reserved1[3]; ++} PARAM_GET_CHN_LOAD, *P_PARAM_GET_CHN_LOAD; ++ ++typedef struct _PARAM_PREFER_CHN_INFO { ++ ++ UINT_8 ucChannel; ++ UINT_16 u2APNum; ++ UINT_8 au4Reserved1[1]; ++} PARAM_PREFER_CHN_INFO, *P_PARAM_PREFER_CHN_INFO; ++ ++typedef struct _PARAM_GET_LTE_MODE { ++ /* Event Body */ ++ UINT_8 ucVersion; ++ UINT_8 aucReserved1[3]; ++ UINT_32 u4Flags; /* Bit0: valid */ ++ ++ LTE_SAFE_CH_INFO_T LTE_MODE; ++ UINT_8 aucReserved4[3]; ++ ++ UINT_8 aucReserved[4]; ++ ++} PARAM_GET_LTE_MODE, *P_PARAM_GET_LTE_MODE; ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ ++ ((UINT_32)(UINT_8)(ch0) | ((UINT_32)(UINT_8)(ch1) << 8) | \ ++ ((UINT_32)(UINT_8)(ch2) << 16) | ((UINT_32)(UINT_8)(ch3) << 24)) ++ ++#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanCardEjected(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanIST(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl); ++ ++WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue); ++ ++WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData); ++ ++VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); ++ ++VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket); ++ ++VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData); ++ ++WLAN_STATUS ++wlanQueryInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfOidQryHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen); ++ ++WLAN_STATUS ++wlanSetInformation(IN P_ADAPTER_T prAdapter, ++ IN PFN_OID_HANDLER_FUNC pfOidSetHandler, ++ IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanAdapterStart(IN P_ADAPTER_T prAdapter, ++ IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength); ++ ++WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter); ++ ++#if CFG_SUPPORT_WAPI ++BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter); ++#endif ++ ++VOID wlanReturnRxPacket(IN PVOID pvAdapter, IN PVOID pvPacket); ++ ++VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast); ++ ++BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); ++ ++VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++WLAN_STATUS ++wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); ++#endif ++ ++WLAN_STATUS ++wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); ++ ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter); ++#else ++WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum); ++#endif ++ ++WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress); ++ ++UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len); ++ ++#endif ++ ++WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode); ++ ++BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); ++ ++WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); ++ ++WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); ++ ++BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler); ++ ++VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter); ++ ++BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter); ++ ++/* Security Frame Handling */ ++BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket); ++ ++VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); ++ ++VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID/IOCTL Handling */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID); ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Address Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* NIC Capability Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* NIC Capability Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Compiler Flags Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* PD MCR Retrieve by Polling */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, IN P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo); ++/*----------------------------------------------------------------------------*/ ++/* Loading Manufacture Data */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Media Stream Mode */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Timer Timeout Check (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Mailbox Message Check (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX Pending Packets Handling (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket); ++ ++WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess); ++ ++/*----------------------------------------------------------------------------*/ ++/* Low Power Acquire/Release (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* Pending Packets Number Reporting (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* ACPI state inquiry (for Glue Layer) */ ++/*----------------------------------------------------------------------------*/ ++ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter); ++ ++VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState); ++ ++VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* get ECO version from Revision ID register (for Win32) */ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* set preferred band configuration corresponding to network type */ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* get currently operating channel information */ ++/*----------------------------------------------------------------------------*/ ++UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* get BSS Descriptor information */ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); ++ ++/*----------------------------------------------------------------------------*/ ++/* check for system configuration to generate message on scan list */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter); ++ ++/*----------------------------------------------------------------------------*/ ++/* query sta statistics information from driver and firmware */ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]); ++ ++P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey); ++ ++WLAN_STATUS ++wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags); ++ ++UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef); ++ ++INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef); ++ ++WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value); ++ ++WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags); ++ ++WLAN_STATUS ++wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags); ++ ++#if CFG_SUPPORT_CFG_FILE ++WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags); ++ ++VOID wlanCfgApply(IN P_ADAPTER_T prAdapter); ++#endif /* CFG_SUPPORT_CFG_FILE */ ++ ++extern VOID mtk_wcn_wmt_set_wifi_ver(UINT_32 Value); ++ ++#endif /* _WLAN_LIB_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h +new file mode 100644 +index 000000000000..45919df996e9 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h +@@ -0,0 +1,1715 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_oid.h#2 ++*/ ++ ++/*! \file "wlan_oid.h" ++ \brief This file contains the declairation file of the WLAN OID processing routines ++ of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_oid.h ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 02 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * Support UAPSD/OppPS/NoA parameter setting ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move timer callback to glue layer. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 18 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement Wakeup-on-LAN except firmware integration part ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. ++ * ++ ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add NULL OID implementation for WOL-related OIDs. ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00003830]add OID_802_11_PRIVACY_FILTER support ++ * enable RX filter OID ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) implement timeout mechanism when OID is pending for longer than 1 second ++ * * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * OID_802_11_RSSI, ++ * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * OID_802_11_STATISTICS, ++ * * * * OID_802_11_DISASSOCIATE, ++ * * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-08 11:38:11 GMT mtk02752 ++** add declares for RF test related APIs ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-24 22:41:53 GMT mtk02752 ++** remove u4SysTime, MSDN 10-second will be implemented in FW side ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 20:30:13 GMT mtk02752 ++** add u4SysTime field in PARAM_BSSID_EX_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-12 19:48:35 GMT mtk02752 ++** allow upper layer to set a packet filter with PROMISCUOUS mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:12 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _WLAN_OID_H ++#define _WLAN_OID_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#if DBG ++extern UINT_8 aucDebugModule[DBG_MODULE_NUM]; ++extern UINT_32 u4DebugModule; ++UINT_32 u4DebugModuleTemp; ++#endif /* DBG */ ++extern int sprintf(char *buf, const char *fmt, ...); ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define PARAM_MAX_LEN_SSID 32 ++ ++#define PARAM_MAC_ADDR_LEN 6 ++ ++#define ETHERNET_HEADER_SZ 14 ++#define ETHERNET_MIN_PKT_SZ 60 ++#define ETHERNET_MAX_PKT_SZ 1514 ++ ++#define PARAM_MAX_LEN_RATES 8 ++#define PARAM_MAX_LEN_RATES_EX 16 ++ ++#define PARAM_AUTH_REQUEST_REAUTH 0x01 ++#define PARAM_AUTH_REQUEST_KEYUPDATE 0x02 ++#define PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++#define PARAM_EEPROM_READ_METHOD_READ 1 ++#define PARAM_EEPROM_READ_METHOD_GETSIZE 0 ++ ++#define PARAM_WHQL_RSSI_MAX_DBM (-10) ++#define PARAM_WHQL_RSSI_MIN_DBM (-200) ++ ++#define PARAM_DEVICE_WAKE_UP_ENABLE 0x00000001 ++#define PARAM_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 ++#define PARAM_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 ++ ++#define PARAM_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define PARAM_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define PARAM_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++/* Packet filter bit definitioin (UINT_32 bit-wise definition) */ ++#define PARAM_PACKET_FILTER_DIRECTED 0x00000001 ++#define PARAM_PACKET_FILTER_MULTICAST 0x00000002 ++#define PARAM_PACKET_FILTER_ALL_MULTICAST 0x00000004 ++#define PARAM_PACKET_FILTER_BROADCAST 0x00000008 ++#define PARAM_PACKET_FILTER_PROMISCUOUS 0x00000020 ++#define PARAM_PACKET_FILTER_ALL_LOCAL 0x00000080 ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#define PARAM_PACKET_FILTER_P2P_MASK 0xC0000000 ++#define PARAM_PACKET_FILTER_PROBE_REQ 0x80000000 ++#define PARAM_PACKET_FILTER_ACTION_FRAME 0x40000000 ++#endif ++ ++#if CFG_SLT_SUPPORT ++#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ ++ PARAM_PACKET_FILTER_MULTICAST | \ ++ PARAM_PACKET_FILTER_BROADCAST | \ ++ PARAM_PACKET_FILTER_ALL_MULTICAST) ++#else ++#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ ++ PARAM_PACKET_FILTER_MULTICAST | \ ++ PARAM_PACKET_FILTER_BROADCAST) ++#endif ++ ++#define PARAM_MEM_DUMP_MAX_SIZE 2048 ++ ++#define BT_PROFILE_PARAM_LEN 8 ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Parameters of User Configuration which match to NDIS5.1 */ ++/*----------------------------------------------------------------------------*/ ++/* NDIS_802_11_AUTHENTICATION_MODE */ ++typedef enum _ENUM_PARAM_AUTH_MODE_T { ++ AUTH_MODE_OPEN, /*!< Open system */ ++ AUTH_MODE_SHARED, /*!< Shared key */ ++ AUTH_MODE_AUTO_SWITCH, /*!< Either open system or shared key */ ++ AUTH_MODE_WPA, ++ AUTH_MODE_WPA_PSK, ++ AUTH_MODE_WPA_NONE, /*!< For Ad hoc */ ++ AUTH_MODE_WPA2, ++ AUTH_MODE_WPA2_PSK, ++ AUTH_MODE_NUM /*!< Upper bound, not real case */ ++} ENUM_PARAM_AUTH_MODE_T, *P_ENUM_PARAM_AUTH_MODE_T; ++ ++/* NDIS_802_11_ENCRYPTION_STATUS *//* Encryption types */ ++typedef enum _ENUM_WEP_STATUS_T { ++ ENUM_WEP_ENABLED, ++ ENUM_ENCRYPTION1_ENABLED = ENUM_WEP_ENABLED, ++ ENUM_WEP_DISABLED, ++ ENUM_ENCRYPTION_DISABLED = ENUM_WEP_DISABLED, ++ ENUM_WEP_KEY_ABSENT, ++ ENUM_ENCRYPTION1_KEY_ABSENT = ENUM_WEP_KEY_ABSENT, ++ ENUM_WEP_NOT_SUPPORTED, ++ ENUM_ENCRYPTION_NOT_SUPPORTED = ENUM_WEP_NOT_SUPPORTED, ++ ENUM_ENCRYPTION2_ENABLED, ++ ENUM_ENCRYPTION2_KEY_ABSENT, ++ ENUM_ENCRYPTION3_ENABLED, ++ ENUM_ENCRYPTION3_KEY_ABSENT ++} ENUM_PARAM_ENCRYPTION_STATUS_T, *P_ENUM_PARAM_ENCRYPTION_STATUS_T; ++ ++typedef UINT_8 PARAM_MAC_ADDRESS[PARAM_MAC_ADDR_LEN]; ++ ++typedef UINT_32 PARAM_KEY_INDEX; ++typedef UINT_64 PARAM_KEY_RSC; ++typedef INT_32 PARAM_RSSI; ++ ++typedef UINT_32 PARAM_FRAGMENTATION_THRESHOLD; ++typedef UINT_32 PARAM_RTS_THRESHOLD; ++ ++typedef UINT_8 PARAM_RATES[PARAM_MAX_LEN_RATES]; ++typedef UINT_8 PARAM_RATES_EX[PARAM_MAX_LEN_RATES_EX]; ++ ++typedef enum _ENUM_PARAM_PHY_TYPE_T { ++ PHY_TYPE_802_11ABG = 0, /*!< Can associated with 802.11abg AP, ++ Scan dual band. */ ++ PHY_TYPE_802_11BG, /*!< Can associated with 802_11bg AP, ++ Scan single band and not report 802_11a BSSs. */ ++ PHY_TYPE_802_11G, /*!< Can associated with 802_11g only AP, ++ Scan single band and not report 802_11ab BSSs. */ ++ PHY_TYPE_802_11A, /*!< Can associated with 802_11a only AP, ++ Scan single band and not report 802_11bg BSSs. */ ++ PHY_TYPE_802_11B, /*!< Can associated with 802_11b only AP, ++ Scan single band and not report 802_11ag BSSs. */ ++ PHY_TYPE_NUM /* 5 */ ++} ENUM_PARAM_PHY_TYPE_T, *P_ENUM_PARAM_PHY_TYPE_T; ++ ++typedef enum _ENUM_PARAM_OP_MODE_T { ++ NET_TYPE_IBSS = 0, /*!< Try to merge/establish an AdHoc, do periodic SCAN for merging. */ ++ NET_TYPE_INFRA, /*!< Try to join an Infrastructure, do periodic SCAN for joining. */ ++ NET_TYPE_AUTO_SWITCH, /*!< Try to join an Infrastructure, if fail then try to merge or ++ establish an AdHoc, do periodic SCAN for joining or merging. */ ++ NET_TYPE_DEDICATED_IBSS, /*!< Try to merge an AdHoc first, ++ if fail then establish AdHoc permanently, no more SCAN. */ ++ NET_TYPE_NUM /* 4 */ ++} ENUM_PARAM_OP_MODE_T, *P_ENUM_PARAM_OP_MODE_T; ++ ++typedef struct _PARAM_SSID_T { ++ UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ ++ UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; ++ UINT_32 u4CenterFreq; ++} PARAM_SSID_T, *P_PARAM_SSID_T; ++ ++typedef struct _PARAM_CONNECT_T { ++ UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ ++ UINT_8 *pucSsid; ++ UINT_8 *pucBssid; ++ UINT_32 u4CenterFreq; ++} PARAM_CONNECT_T, *P_PARAM_CONNECT_T; ++ ++/* This is enum defined for user to select an AdHoc Mode */ ++typedef enum _ENUM_PARAM_AD_HOC_MODE_T { ++ AD_HOC_MODE_11B = 0, /*!< Create 11b IBSS if we support 802.11abg/802.11bg. */ ++ AD_HOC_MODE_MIXED_11BG, /*!< Create 11bg mixed IBSS if we support 802.11abg/802.11bg/802.11g. */ ++ AD_HOC_MODE_11G, /*!< Create 11g only IBSS if we support 802.11abg/802.11bg/802.11g. */ ++ AD_HOC_MODE_11A, /*!< Create 11a only IBSS if we support 802.11abg. */ ++ AD_HOC_MODE_NUM /* 4 */ ++} ENUM_PARAM_AD_HOC_MODE_T, *P_ENUM_PARAM_AD_HOC_MODE_T; ++ ++typedef enum _ENUM_PARAM_MEDIA_STATE_T { ++ PARAM_MEDIA_STATE_CONNECTED, ++ PARAM_MEDIA_STATE_DISCONNECTED, ++ PARAM_MEDIA_STATE_TO_BE_INDICATED /* for following MSDN re-association behavior */ ++} ENUM_PARAM_MEDIA_STATE_T, *P_ENUM_PARAM_MEDIA_STATE_T; ++ ++typedef enum _ENUM_PARAM_NETWORK_TYPE_T { ++ PARAM_NETWORK_TYPE_FH, ++ PARAM_NETWORK_TYPE_DS, ++ PARAM_NETWORK_TYPE_OFDM5, ++ PARAM_NETWORK_TYPE_OFDM24, ++ PARAM_NETWORK_TYPE_AUTOMODE, ++ PARAM_NETWORK_TYPE_NUM /*!< Upper bound, not real case */ ++} ENUM_PARAM_NETWORK_TYPE_T, *P_ENUM_PARAM_NETWORK_TYPE_T; ++ ++typedef struct _PARAM_NETWORK_TYPE_LIST { ++ UINT_32 NumberOfItems; /*!< At least 1 */ ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType[1]; ++} PARAM_NETWORK_TYPE_LIST, *PPARAM_NETWORK_TYPE_LIST; ++ ++typedef enum _ENUM_PARAM_PRIVACY_FILTER_T { ++ PRIVACY_FILTER_ACCEPT_ALL, ++ PRIVACY_FILTER_8021xWEP, ++ PRIVACY_FILTER_NUM ++} ENUM_PARAM_PRIVACY_FILTER_T, *P_ENUM_PARAM_PRIVACY_FILTER_T; ++ ++typedef enum _ENUM_RELOAD_DEFAULTS { ++ ENUM_RELOAD_WEP_KEYS ++} PARAM_RELOAD_DEFAULTS, *P_PARAM_RELOAD_DEFAULTS; ++ ++typedef struct _PARAM_PM_PACKET_PATTERN { ++ UINT_32 Priority; /* Importance of the given pattern. */ ++ UINT_32 Reserved; /* Context information for transports. */ ++ UINT_32 MaskSize; /* Size in bytes of the pattern mask. */ ++ UINT_32 PatternOffset; /* Offset from beginning of this */ ++ /* structure to the pattern bytes. */ ++ UINT_32 PatternSize; /* Size in bytes of the pattern. */ ++ UINT_32 PatternFlags; /* Flags (TBD). */ ++} PARAM_PM_PACKET_PATTERN, *P_PARAM_PM_PACKET_PATTERN; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Struct definition to indicate specific event. */ ++/*--------------------------------------------------------------*/ ++typedef enum _ENUM_STATUS_TYPE_T { ++ ENUM_STATUS_TYPE_AUTHENTICATION, ++ ENUM_STATUS_TYPE_MEDIA_STREAM_MODE, ++ ENUM_STATUS_TYPE_CANDIDATE_LIST, ++ ENUM_STATUS_TYPE_NUM /*!< Upper bound, not real case */ ++} ENUM_STATUS_TYPE_T, *P_ENUM_STATUS_TYPE_T; ++ ++typedef struct _PARAM_802_11_CONFIG_FH_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4HopPattern; /*!< Defined as 802.11 */ ++ UINT_32 u4HopSet; /*!< to one if non-802.11 */ ++ UINT_32 u4DwellTime; /*!< In unit of Kusec */ ++} PARAM_802_11_CONFIG_FH_T, *P_PARAM_802_11_CONFIG_FH_T; ++ ++typedef struct _PARAM_802_11_CONFIG_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4BeaconPeriod; /*!< In unit of Kusec */ ++ UINT_32 u4ATIMWindow; /*!< In unit of Kusec */ ++ UINT_32 u4DSConfig; /*!< Channel frequency in unit of kHz */ ++ PARAM_802_11_CONFIG_FH_T rFHConfig; ++} PARAM_802_11_CONFIG_T, *P_PARAM_802_11_CONFIG_T; ++ ++typedef struct _PARAM_STATUS_INDICATION_T { ++ ENUM_STATUS_TYPE_T eStatusType; ++} PARAM_STATUS_INDICATION_T, *P_PARAM_STATUS_INDICATION_T; ++ ++typedef struct _PARAM_AUTH_REQUEST_T { ++ UINT_32 u4Length; /*!< Length of this struct */ ++ PARAM_MAC_ADDRESS arBssid; ++ UINT_32 u4Flags; /*!< Definitions are as follows */ ++} PARAM_AUTH_REQUEST_T, *P_PARAM_AUTH_REQUEST_T; ++ ++typedef struct _PARAM_AUTH_EVENT_T { ++ PARAM_STATUS_INDICATION_T rStatus; ++ PARAM_AUTH_REQUEST_T arRequest[1]; ++} PARAM_AUTH_EVENT_T, *P_PARAM_AUTH_EVENT_T; ++ ++/*! \brief Capabilities, privacy, rssi and IEs of each BSSID */ ++typedef struct _PARAM_BSSID_EX_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ PARAM_MAC_ADDRESS arMacAddress; /*!< BSSID */ ++ UINT_8 Reserved[2]; ++ PARAM_SSID_T rSsid; /*!< SSID */ ++ UINT_32 u4Privacy; /*!< Need WEP encryption */ ++ PARAM_RSSI rRssi; /*!< in dBm */ ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkTypeInUse; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ PARAM_RATES_EX rSupportedRates; ++ UINT_32 u4IELength; ++ UINT_8 aucIEs[1]; ++} PARAM_BSSID_EX_T, *P_PARAM_BSSID_EX_T; ++ ++typedef struct _PARAM_BSSID_LIST_EX { ++ UINT_32 u4NumberOfItems; /*!< at least 1 */ ++ PARAM_BSSID_EX_T arBssid[1]; ++} PARAM_BSSID_LIST_EX_T, *P_PARAM_BSSID_LIST_EX_T; ++ ++typedef struct _PARAM_WEP_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< 0: pairwise key, others group keys */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} PARAM_WEP_T, *P_PARAM_WEP_T; ++ ++/*! \brief Key mapping of BSSID */ ++typedef struct _PARAM_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++ PARAM_KEY_RSC rKeyRSC; ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} PARAM_KEY_T, *P_PARAM_KEY_T; ++ ++typedef struct _PARAM_REMOVE_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++} PARAM_REMOVE_KEY_T, *P_PARAM_REMOVE_KEY_T; ++ ++#if CFG_SUPPORT_WAPI ++typedef enum _ENUM_KEY_TYPE { ++ ENUM_WPI_PAIRWISE_KEY = 0, ++ ENUM_WPI_GROUP_KEY ++} ENUM_KEY_TYPE; ++ ++typedef enum _ENUM_WPI_PROTECT_TYPE { ++ ENUM_WPI_NONE, ++ ENUM_WPI_RX, ++ ENUM_WPI_TX, ++ ENUM_WPI_RX_TX ++} ENUM_WPI_PROTECT_TYPE; ++ ++typedef struct _PARAM_WPI_KEY_T { ++ ENUM_KEY_TYPE eKeyType; ++ ENUM_WPI_PROTECT_TYPE eDirection; ++ UINT_8 ucKeyID; ++ UINT_8 aucRsv[3]; ++ UINT_8 aucAddrIndex[12]; ++ UINT_32 u4LenWPIEK; ++ UINT_8 aucWPIEK[256]; ++ UINT_32 u4LenWPICK; ++ UINT_8 aucWPICK[256]; ++ UINT_8 aucPN[16]; ++} PARAM_WPI_KEY_T, *P_PARAM_WPI_KEY_T; ++#endif ++ ++typedef enum _PARAM_POWER_MODE { ++ Param_PowerModeCAM, ++ Param_PowerModeMAX_PSP, ++ Param_PowerModeFast_PSP, ++#if CFG_SUPPORT_DBG_POWERMODE ++ Param_PowerModeKeepActiveOn, /* privilege mode, always active */ ++ Param_PowerModeKeepActiveOff, /* to leave privilege mode */ ++#endif ++ Param_PowerModeMax /* Upper bound, not real case */ ++} PARAM_POWER_MODE, *PPARAM_POWER_MODE; ++ ++typedef enum _PARAM_DEVICE_POWER_STATE { ++ ParamDeviceStateUnspecified = 0, ++ ParamDeviceStateD0, ++ ParamDeviceStateD1, ++ ParamDeviceStateD2, ++ ParamDeviceStateD3, ++ ParamDeviceStateMaximum ++} PARAM_DEVICE_POWER_STATE, *PPARAM_DEVICE_POWER_STATE; ++ ++#if CFG_SUPPORT_802_11D ++ ++/*! \brief The enumeration definitions for OID_IPN_MULTI_DOMAIN_CAPABILITY */ ++typedef enum _PARAM_MULTI_DOMAIN_CAPABILITY { ++ ParamMultiDomainCapDisabled, ++ ParamMultiDomainCapEnabled ++} PARAM_MULTI_DOMAIN_CAPABILITY, *P_PARAM_MULTI_DOMAIN_CAPABILITY; ++#endif ++ ++typedef struct _COUNTRY_STRING_ENTRY { ++ UINT_8 aucCountryCode[2]; ++ UINT_8 aucEnvironmentCode[2]; ++} COUNTRY_STRING_ENTRY, *P_COUNTRY_STRING_ENTRY; ++ ++/* Power management related definition and enumerations */ ++#define UAPSD_NONE 0 ++#define UAPSD_AC0 (BIT(0) | BIT(4)) ++#define UAPSD_AC1 (BIT(1) | BIT(5)) ++#define UAPSD_AC2 (BIT(2) | BIT(6)) ++#define UAPSD_AC3 (BIT(3) | BIT(7)) ++#define UAPSD_ALL (UAPSD_AC0 | UAPSD_AC1 | UAPSD_AC2 | UAPSD_AC3) ++ ++typedef enum _ENUM_POWER_SAVE_PROFILE_T { ++ ENUM_PSP_CONTINUOUS_ACTIVE = 0, ++ ENUM_PSP_CONTINUOUS_POWER_SAVE, ++ ENUM_PSP_FAST_SWITCH, ++ ENUM_PSP_NUM ++} ENUM_POWER_SAVE_PROFILE_T, *PENUM_POWER_SAVE_PROFILE_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Set/Query testing type. */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_802_11_TEST_T { ++ UINT_32 u4Length; ++ UINT_32 u4Type; ++ union { ++ PARAM_AUTH_EVENT_T AuthenticationEvent; ++ PARAM_RSSI RssiTrigger; ++ } u; ++} PARAM_802_11_TEST_T, *P_PARAM_802_11_TEST_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief Set/Query authentication and encryption capability. */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_AUTH_ENCRYPTION_T { ++ ENUM_PARAM_AUTH_MODE_T eAuthModeSupported; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncryptStatusSupported; ++} PARAM_AUTH_ENCRYPTION_T, *P_PARAM_AUTH_ENCRYPTION_T; ++ ++typedef struct _PARAM_CAPABILITY_T { ++ UINT_32 u4Length; ++ UINT_32 u4Version; ++ UINT_32 u4NoOfPMKIDs; ++ UINT_32 u4NoOfAuthEncryptPairsSupported; ++ PARAM_AUTH_ENCRYPTION_T arAuthenticationEncryptionSupported[1]; ++} PARAM_CAPABILITY_T, *P_PARAM_CAPABILITY_T; ++ ++typedef UINT_8 PARAM_PMKID_VALUE[16]; ++ ++typedef struct _PARAM_BSSID_INFO_T { ++ PARAM_MAC_ADDRESS arBSSID; ++ PARAM_PMKID_VALUE arPMKID; ++} PARAM_BSSID_INFO_T, *P_PARAM_BSSID_INFO_T; ++ ++typedef struct _PARAM_PMKID_T { ++ UINT_32 u4Length; ++ UINT_32 u4BSSIDInfoCount; ++ PARAM_BSSID_INFO_T arBSSIDInfo[1]; ++} PARAM_PMKID_T, *P_PARAM_PMKID_T; ++ ++/*! \brief PMKID candidate lists. */ ++typedef struct _PARAM_PMKID_CANDIDATE_T { ++ PARAM_MAC_ADDRESS arBSSID; ++ UINT_32 u4Flags; ++} PARAM_PMKID_CANDIDATE_T, *P_PARAM_PMKID_CANDIDATE_T; ++ ++/* #ifdef LINUX */ ++typedef struct _PARAM_PMKID_CANDIDATE_LIST_T { ++ UINT_32 u4Version; /*!< Version */ ++ UINT_32 u4NumCandidates; /*!< How many candidates follow */ ++ PARAM_PMKID_CANDIDATE_T arCandidateList[1]; ++} PARAM_PMKID_CANDIDATE_LIST_T, *P_PARAM_PMKID_CANDIDATE_LIST_T; ++/* #endif */ ++ ++typedef struct _PARAM_CUSTOM_MCR_RW_STRUCT_T { ++ UINT_32 u4McrOffset; ++ UINT_32 u4McrData; ++} PARAM_CUSTOM_MCR_RW_STRUCT_T, *P_PARAM_CUSTOM_MCR_RW_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_MEM_DUMP_STRUCT_T { ++ UINT_32 u4Address; ++ UINT_32 u4Length; ++ UINT_32 u4RemainLength; ++ UINT_8 ucFragNum; ++} PARAM_CUSTOM_MEM_DUMP_STRUCT_T, *P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_SW_CTRL_STRUCT_T { ++ UINT_32 u4Id; ++ UINT_32 u4Data; ++} PARAM_CUSTOM_SW_CTRL_STRUCT_T, *P_PARAM_CUSTOM_SW_CTRL_STRUCT_T; ++ ++typedef struct _CMD_CHIP_CONFIG_T { ++ UINT_16 u2Id; ++ UINT_8 ucType; ++ UINT_8 ucRespType; ++ UINT_16 u2MsgSize; ++ UINT_8 aucReserved0[2]; ++ UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; ++} CMD_CHIP_CONFIG_T, *P_CMD_CHIP_CONFIG_T; ++ ++typedef struct _PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T { ++ UINT_16 u2Id; ++ UINT_8 ucType; ++ UINT_8 ucRespType; ++ UINT_16 u2MsgSize; ++ UINT_8 aucReserved0[2]; ++ UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; ++} PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T, *P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_KEY_CFG_STRUCT_T { ++ UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; ++ UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; ++} PARAM_CUSTOM_KEY_CFG_STRUCT_T, *P_PARAM_CUSTOM_KEY_CFG_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_EEPROM_RW_STRUCT_T { ++ UINT_8 ucEepromMethod; /* For read only read: 1, query size: 0 */ ++ UINT_8 ucEepromIndex; ++ UINT_8 reserved; ++ UINT_16 u2EepromData; ++} PARAM_CUSTOM_EEPROM_RW_STRUCT_T, *P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T, ++PARAM_CUSTOM_NVRAM_RW_STRUCT_T, *P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T { ++ UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ ++ UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ ++ UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ ++ UINT_8 reserved; ++} PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T, *P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_NOA_PARAM_STRUCT_T { ++ UINT_32 u4NoaDurationMs; ++ UINT_32 u4NoaIntervalMs; ++ UINT_32 u4NoaCount; ++} PARAM_CUSTOM_NOA_PARAM_STRUCT_T, *P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T { ++ UINT_32 u4CTwindowMs; ++} PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T { ++ UINT_8 fgEnAPSD; ++ UINT_8 fgEnAPSD_AcBe; ++ UINT_8 fgEnAPSD_AcBk; ++ UINT_8 fgEnAPSD_AcVo; ++ UINT_8 fgEnAPSD_AcVi; ++ UINT_8 ucMaxSpLen; ++ UINT_8 aucResv[2]; ++} PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T; ++ ++typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { ++ UINT_32 u4Enable; ++ UINT_32 u4Mode; ++} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; ++ ++typedef enum _ENUM_CFG_SRC_TYPE_T { ++ CFG_SRC_TYPE_EEPROM, ++ CFG_SRC_TYPE_NVRAM, ++ CFG_SRC_TYPE_UNKNOWN, ++ CFG_SRC_TYPE_NUM ++} ENUM_CFG_SRC_TYPE_T, *P_ENUM_CFG_SRC_TYPE_T; ++ ++typedef enum _ENUM_EEPROM_TYPE_T { ++ EEPROM_TYPE_NO, ++ EEPROM_TYPE_PRESENT, ++ EEPROM_TYPE_NUM ++} ENUM_EEPROM_TYPE_T, *P_ENUM_EEPROM_TYPE_T; ++ ++typedef struct _PARAM_QOS_TSINFO { ++ UINT_8 ucTrafficType; /* Traffic Type: 1 for isochronous 0 for asynchronous */ ++ UINT_8 ucTid; /* TSID: must be between 8 ~ 15 */ ++ UINT_8 ucDirection; /* direction */ ++ UINT_8 ucAccessPolicy; /* access policy */ ++ UINT_8 ucAggregation; /* aggregation */ ++ UINT_8 ucApsd; /* APSD */ ++ UINT_8 ucuserPriority; /* user priority */ ++ UINT_8 ucTsInfoAckPolicy; /* TSINFO ACK policy */ ++ UINT_8 ucSchedule; /* Schedule */ ++} PARAM_QOS_TSINFO, *P_PARAM_QOS_TSINFO; ++ ++typedef struct _PARAM_QOS_TSPEC { ++ PARAM_QOS_TSINFO rTsInfo; /* TS info field */ ++ UINT_16 u2NominalMSDUSize; /* nominal MSDU size */ ++ UINT_16 u2MaxMSDUsize; /* maximum MSDU size */ ++ UINT_32 u4MinSvcIntv; /* minimum service interval */ ++ UINT_32 u4MaxSvcIntv; /* maximum service interval */ ++ UINT_32 u4InactIntv; /* inactivity interval */ ++ UINT_32 u4SpsIntv; /* suspension interval */ ++ UINT_32 u4SvcStartTime; /* service start time */ ++ UINT_32 u4MinDataRate; /* minimum Data rate */ ++ UINT_32 u4MeanDataRate; /* mean data rate */ ++ UINT_32 u4PeakDataRate; /* peak data rate */ ++ UINT_32 u4MaxBurstSize; /* maximum burst size */ ++ UINT_32 u4DelayBound; /* delay bound */ ++ UINT_32 u4MinPHYRate; /* minimum PHY rate */ ++ UINT_16 u2Sba; /* surplus bandwidth allowance */ ++ UINT_16 u2MediumTime; /* medium time */ ++} PARAM_QOS_TSPEC, *P_PARAM_QOS_TSPEC; ++ ++typedef struct _PARAM_QOS_ADDTS_REQ_INFO { ++ PARAM_QOS_TSPEC rTspec; ++} PARAM_QOS_ADDTS_REQ_INFO, *P_PARAM_QOS_ADDTS_REQ_INFO; ++ ++typedef struct _PARAM_VOIP_CONFIG { ++ UINT_32 u4VoipTrafficInterval; /* 0: disable VOIP configuration */ ++} PARAM_VOIP_CONFIG, *P_PARAM_VOIP_CONFIG; ++ ++/*802.11 Statistics Struct*/ ++typedef struct _PARAM_802_11_STATISTICS_STRUCT_T { ++ UINT_32 u4Length; /* Length of structure */ ++ LARGE_INTEGER rTransmittedFragmentCount; ++ LARGE_INTEGER rMulticastTransmittedFrameCount; ++ LARGE_INTEGER rFailedCount; ++ LARGE_INTEGER rRetryCount; ++ LARGE_INTEGER rMultipleRetryCount; ++ LARGE_INTEGER rRTSSuccessCount; ++ LARGE_INTEGER rRTSFailureCount; ++ LARGE_INTEGER rACKFailureCount; ++ LARGE_INTEGER rFrameDuplicateCount; ++ LARGE_INTEGER rReceivedFragmentCount; ++ LARGE_INTEGER rMulticastReceivedFrameCount; ++ LARGE_INTEGER rFCSErrorCount; ++ LARGE_INTEGER rTKIPLocalMICFailures; ++ LARGE_INTEGER rTKIPICVErrors; ++ LARGE_INTEGER rTKIPCounterMeasuresInvoked; ++ LARGE_INTEGER rTKIPReplays; ++ LARGE_INTEGER rCCMPFormatErrors; ++ LARGE_INTEGER rCCMPReplays; ++ LARGE_INTEGER rCCMPDecryptErrors; ++ LARGE_INTEGER rFourWayHandshakeFailures; ++ LARGE_INTEGER rWEPUndecryptableCount; ++ LARGE_INTEGER rWEPICVErrorCount; ++ LARGE_INTEGER rDecryptSuccessCount; ++ LARGE_INTEGER rDecryptFailureCount; ++} PARAM_802_11_STATISTICS_STRUCT_T, *P_PARAM_802_11_STATISTICS_STRUCT_T; ++ ++/* Linux Network Device Statistics Struct */ ++typedef struct _PARAM_LINUX_NETDEV_STATISTICS_T { ++ UINT_32 u4RxPackets; ++ UINT_32 u4TxPackets; ++ UINT_32 u4RxBytes; ++ UINT_32 u4TxBytes; ++ UINT_32 u4RxErrors; ++ UINT_32 u4TxErrors; ++ UINT_32 u4Multicast; ++} PARAM_LINUX_NETDEV_STATISTICS_T, *P_PARAM_LINUX_NETDEV_STATISTICS_T; ++ ++typedef struct _PARAM_MTK_WIFI_TEST_STRUCT_T { ++ UINT_32 u4FuncIndex; ++ UINT_32 u4FuncData; ++} PARAM_MTK_WIFI_TEST_STRUCT_T, *P_PARAM_MTK_WIFI_TEST_STRUCT_T; ++ ++/* 802.11 Media stream constraints */ ++typedef enum _ENUM_MEDIA_STREAM_MODE { ++ ENUM_MEDIA_STREAM_OFF, ++ ENUM_MEDIA_STREAM_ON ++} ENUM_MEDIA_STREAM_MODE, *P_ENUM_MEDIA_STREAM_MODE; ++ ++/* for NDIS 5.1 Media Streaming Change */ ++typedef struct _PARAM_MEDIA_STREAMING_INDICATION { ++ PARAM_STATUS_INDICATION_T rStatus; ++ ENUM_MEDIA_STREAM_MODE eMediaStreamMode; ++} PARAM_MEDIA_STREAMING_INDICATION, *P_PARAM_MEDIA_STREAMING_INDICATION; ++ ++#define PARAM_PROTOCOL_ID_DEFAULT 0x00 ++#define PARAM_PROTOCOL_ID_TCP_IP 0x02 ++#define PARAM_PROTOCOL_ID_IPX 0x06 ++#define PARAM_PROTOCOL_ID_NBF 0x07 ++#define PARAM_PROTOCOL_ID_MAX 0x0F ++#define PARAM_PROTOCOL_ID_MASK 0x0F ++ ++/* for NDIS OID_GEN_NETWORK_LAYER_ADDRESSES */ ++typedef struct _PARAM_NETWORK_ADDRESS_IP { ++ UINT_16 sin_port; ++ UINT_32 in_addr; ++ UINT_8 sin_zero[8]; ++} PARAM_NETWORK_ADDRESS_IP, *P_PARAM_NETWORK_ADDRESS_IP; ++ ++typedef struct _PARAM_NETWORK_ADDRESS { ++ UINT_16 u2AddressLength; /* length in bytes of Address[] in this */ ++ UINT_16 u2AddressType; /* type of this address (PARAM_PROTOCOL_ID_XXX above) */ ++ UINT_8 aucAddress[1]; /* actually AddressLength bytes long */ ++} PARAM_NETWORK_ADDRESS, *P_PARAM_NETWORK_ADDRESS; ++ ++/* The following is used with OID_GEN_NETWORK_LAYER_ADDRESSES to set network layer addresses on an interface */ ++ ++typedef struct _PARAM_NETWORK_ADDRESS_LIST { ++ UINT_32 u4AddressCount; /* number of addresses following */ ++ UINT_16 u2AddressType; /* type of this address (NDIS_PROTOCOL_ID_XXX above) */ ++ PARAM_NETWORK_ADDRESS arAddress[1]; /* actually AddressCount elements long */ ++} PARAM_NETWORK_ADDRESS_LIST, *P_PARAM_NETWORK_ADDRESS_LIST; ++ ++#if CFG_SLT_SUPPORT ++ ++#define FIXED_BW_LG20 0x0000 ++#define FIXED_BW_UL20 0x2000 ++#define FIXED_BW_DL40 0x3000 ++ ++#define FIXED_EXT_CHNL_U20 0x4000 /* For AGG register. */ ++#define FIXED_EXT_CHNL_L20 0xC000 /* For AGG regsiter. */ ++ ++typedef enum _ENUM_MTK_LP_TEST_MODE_T { ++ ENUM_MTK_LP_TEST_NORMAL, ++ ENUM_MTK_LP_TEST_GOLDEN_SAMPLE, ++ ENUM_MTK_LP_TEST_DUT, ++ ENUM_MTK_LP_TEST_MODE_NUM ++} ENUM_MTK_LP_TEST_MODE_T, *P_ENUM_MTK_LP_TEST_MODE_T; ++ ++typedef enum _ENUM_MTK_SLT_FUNC_IDX_T { ++ ENUM_MTK_SLT_FUNC_DO_NOTHING, ++ ENUM_MTK_SLT_FUNC_INITIAL, ++ ENUM_MTK_SLT_FUNC_RATE_SET, ++ ENUM_MTK_SLT_FUNC_LP_SET, ++ ENUM_MTK_SLT_FUNC_NUM ++} ENUM_MTK_SLT_FUNC_IDX_T, *P_ENUM_MTK_SLT_FUNC_IDX_T; ++ ++typedef struct _PARAM_MTK_SLT_LP_TEST_STRUCT_T { ++ ENUM_MTK_LP_TEST_MODE_T rLpTestMode; ++ UINT_32 u4BcnRcvNum; ++} PARAM_MTK_SLT_LP_TEST_STRUCT_T, *P_PARAM_MTK_SLT_LP_TEST_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_TR_TEST_STRUCT_T { ++ ENUM_PARAM_NETWORK_TYPE_T rNetworkType; /* Network Type OFDM5G or OFDM2.4G */ ++ UINT_32 u4FixedRate; /* Fixed Rate including BW */ ++} PARAM_MTK_SLT_TR_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TR_TEST_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_INITIAL_STRUCT_T { ++ UINT_8 aucTargetMacAddr[PARAM_MAC_ADDR_LEN]; ++ UINT_16 u2SiteID; ++} PARAM_MTK_SLT_INITIAL_STRUCT_T, *P_PARAM_MTK_SLT_INITIAL_STRUCT_T; ++ ++typedef struct _PARAM_MTK_SLT_TEST_STRUCT_T { ++ ENUM_MTK_SLT_FUNC_IDX_T rSltFuncIdx; ++ UINT_32 u4Length; /* Length of structure, ++ including myself */ ++ UINT_32 u4FuncInfoLen; /* Include following content ++ field and myself */ ++ union { ++ PARAM_MTK_SLT_INITIAL_STRUCT_T rMtkInitTest; ++ PARAM_MTK_SLT_LP_TEST_STRUCT_T rMtkLpTest; ++ PARAM_MTK_SLT_TR_TEST_STRUCT_T rMtkTRTest; ++ } unFuncInfoContent; ++ ++} PARAM_MTK_SLT_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TEST_STRUCT_T; ++ ++#endif ++ ++/*--------------------------------------------------------------*/ ++/*! \brief For Fixed Rate Configuration (Registry) */ ++/*--------------------------------------------------------------*/ ++typedef enum _ENUM_REGISTRY_FIXED_RATE_T { ++ FIXED_RATE_NONE, ++ FIXED_RATE_1M, ++ FIXED_RATE_2M, ++ FIXED_RATE_5_5M, ++ FIXED_RATE_11M, ++ FIXED_RATE_6M, ++ FIXED_RATE_9M, ++ FIXED_RATE_12M, ++ FIXED_RATE_18M, ++ FIXED_RATE_24M, ++ FIXED_RATE_36M, ++ FIXED_RATE_48M, ++ FIXED_RATE_54M, ++ FIXED_RATE_MCS0_20M_800NS, ++ FIXED_RATE_MCS1_20M_800NS, ++ FIXED_RATE_MCS2_20M_800NS, ++ FIXED_RATE_MCS3_20M_800NS, ++ FIXED_RATE_MCS4_20M_800NS, ++ FIXED_RATE_MCS5_20M_800NS, ++ FIXED_RATE_MCS6_20M_800NS, ++ FIXED_RATE_MCS7_20M_800NS, ++ FIXED_RATE_MCS0_20M_400NS, ++ FIXED_RATE_MCS1_20M_400NS, ++ FIXED_RATE_MCS2_20M_400NS, ++ FIXED_RATE_MCS3_20M_400NS, ++ FIXED_RATE_MCS4_20M_400NS, ++ FIXED_RATE_MCS5_20M_400NS, ++ FIXED_RATE_MCS6_20M_400NS, ++ FIXED_RATE_MCS7_20M_400NS, ++ FIXED_RATE_MCS0_40M_800NS, ++ FIXED_RATE_MCS1_40M_800NS, ++ FIXED_RATE_MCS2_40M_800NS, ++ FIXED_RATE_MCS3_40M_800NS, ++ FIXED_RATE_MCS4_40M_800NS, ++ FIXED_RATE_MCS5_40M_800NS, ++ FIXED_RATE_MCS6_40M_800NS, ++ FIXED_RATE_MCS7_40M_800NS, ++ FIXED_RATE_MCS32_800NS, ++ FIXED_RATE_MCS0_40M_400NS, ++ FIXED_RATE_MCS1_40M_400NS, ++ FIXED_RATE_MCS2_40M_400NS, ++ FIXED_RATE_MCS3_40M_400NS, ++ FIXED_RATE_MCS4_40M_400NS, ++ FIXED_RATE_MCS5_40M_400NS, ++ FIXED_RATE_MCS6_40M_400NS, ++ FIXED_RATE_MCS7_40M_400NS, ++ FIXED_RATE_MCS32_400NS, ++ FIXED_RATE_NUM ++} ENUM_REGISTRY_FIXED_RATE_T, *P_ENUM_REGISTRY_FIXED_RATE_T; ++ ++typedef enum _ENUM_BT_CMD_T { ++ BT_CMD_PROFILE = 0, ++ BT_CMD_UPDATE, ++ BT_CMD_NUM ++} ENUM_BT_CMD_T; ++ ++typedef enum _ENUM_BT_PROFILE_T { ++ BT_PROFILE_CUSTOM = 0, ++ BT_PROFILE_SCO, ++ BT_PROFILE_ACL, ++ BT_PROFILE_MIXED, ++ BT_PROFILE_NO_CONNECTION, ++ BT_PROFILE_NUM ++} ENUM_BT_PROFILE_T; ++ ++typedef struct _PTA_PROFILE_T { ++ ENUM_BT_PROFILE_T eBtProfile; ++ union { ++ UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; ++ /* 0: sco reserved slot time, ++ 1: sco idle slot time, ++ 2: acl throughput, ++ 3: bt tx power, ++ 4: bt rssi ++ 5: VoIP interval ++ 6: BIT(0) Use this field, BIT(1) 0 apply single/ 1 dual PTA setting. ++ */ ++ UINT_32 au4Btcr[4]; ++ } u; ++} PTA_PROFILE_T, *P_PTA_PROFILE_T; ++ ++typedef struct _PTA_IPC_T { ++ UINT_8 ucCmd; ++ UINT_8 ucLen; ++ union { ++ PTA_PROFILE_T rProfile; ++ UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; ++ } u; ++} PARAM_PTA_IPC_T, *P_PARAM_PTA_IPC_T, PTA_IPC_T, *P_PTA_IPC_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief CFG80211 Scan Request Container */ ++/*--------------------------------------------------------------*/ ++ ++typedef struct _PARAM_SCAN_REQUEST_EXT_T { ++ PARAM_SSID_T rSsid; ++ UINT_32 u4IELength; ++ PUINT_8 pucIE; ++} PARAM_SCAN_REQUEST_EXT_T, *P_PARAM_SCAN_REQUEST_EXT_T; ++ ++/*--------------------------------------------------------------*/ ++/*! \brief CFG80211 Scheduled Scan Request Container */ ++/*--------------------------------------------------------------*/ ++typedef struct _PARAM_SCHED_SCAN_REQUEST_T { ++ UINT_32 u4SsidNum; ++ PARAM_SSID_T arSsid[CFG_SCAN_SSID_MATCH_MAX_NUM]; ++ UINT_32 u4IELength; ++ PUINT_8 pucIE; ++ UINT_16 u2ScanInterval; /* in milliseconds */ ++} PARAM_SCHED_SCAN_REQUEST, *P_PARAM_SCHED_SCAN_REQUEST; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++typedef struct _PARAM_HS20_SET_BSSID_POOL { ++ BOOLEAN fgIsEnable; ++ UINT_8 ucNumBssidPool; ++ PARAM_MAC_ADDRESS arBSSID[8]; ++} PARAM_HS20_SET_BSSID_POOL, *P_PARAM_HS20_SET_BSSID_POOL; ++ ++#endif ++ ++typedef struct _PARAM_CUSTOM_WFD_DEBUG_STRUCT_T { ++ UINT_8 ucWFDDebugMode; /* 0: Disable ++ 1:Enable but only show inqueue skb ether SN ++ 2.show skb ether SN and the statistics of skb inqueue time */ ++ UINT_16 u2SNPeriod; /* The Ether SN Period */ ++ ++ UINT_8 reserved; ++} PARAM_CUSTOM_WFD_DEBUG_STRUCT_T, *P_PARAM_CUSTOM_WFD_DEBUG_STRUCT_T; ++ ++typedef struct _CMD_GET_PSCAN_CAPABILITY { ++/* TBD */ ++} CMD_GET_GSCAN_CAPABILITY, *P_CMD_GET_GSCAN_CAPABILITY; ++ ++typedef struct _CMD_SET_PSCAN_ENABLE { ++ UINT_8 ucPscanAct; ++ UINT_8 aucReserved[3]; ++} CMD_SET_PSCAN_ENABLE, *P_CMD_SET_PSCAN_ENABLE; ++ ++typedef enum _ENUM_PSCAN_ACT_T { ++ ENABLE, ++ DISABLE, ++ SUSPEND, ++ CLEAR ++} ENUM_PSCAN_ACT_T, *P_ENUM_PSCAN_ACT_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*--------------------------------------------------------------*/ ++/* Routines to set parameters or query information. */ ++/*--------------------------------------------------------------*/ ++/***** Routines in wlan_oid.c *****/ ++WLAN_STATUS ++wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetConnect(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if 0 ++WLAN_STATUS ++wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID prSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRfTestRxStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRfTestTxStatus(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++WLAN_STATUS ++wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#ifdef LINUX ++ ++WLAN_STATUS ++wlanoidQueryStatisticsForLinux(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#endif ++ ++WLAN_STATUS ++wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++WLAN_STATUS ++wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/* RF Test related APIs */ ++WLAN_STATUS ++wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_SUPPORT_WAPI ++WLAN_STATUS ++wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++WLAN_STATUS ++wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_ENABLE_WAKEUP_ON_LAN ++WLAN_STATUS ++wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 u4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); ++ ++#if CFG_SLT_SUPPORT ++ ++WLAN_STATUS ++wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#endif ++ ++#if 0 ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBT(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++WLAN_STATUS ++wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#endif ++ ++/* ++WLAN_STATUS ++wlanoidQueryBtSingleAntenna ( ++ IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, ++ IN UINT_32 u4QueryBufferLen, ++ OUT PUINT_32 pu4QueryInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidSetBtSingleAntenna ( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidSetPta ( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++WLAN_STATUS ++wlanoidQueryPta ( ++ IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, ++ IN UINT_32 u4QueryBufferLen, ++ OUT PUINT_32 pu4QueryInfoLen ++ ); ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++WLAN_STATUS ++wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++#if CFG_SUPPORT_BATCH_SCAN ++WLAN_STATUS ++wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++WLAN_STATUS ++wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetTxRateInfo( ++ IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen ++ ); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++WLAN_STATUS ++wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++WLAN_STATUS ++wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, ++ IN UINT_32 u4SetBufferLen, ++ OUT PUINT_32 pu4SetInfoLen); ++ ++#endif /* _WLAN_OID_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h +new file mode 100644 +index 000000000000..0b558d64034d +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h +@@ -0,0 +1,307 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/wlan_p2p.h#3 ++*/ ++ ++/*! \file "wlan_p2p.h" ++ \brief This file contains the declairations of Wi-Fi Direct command ++ processing routines for MediaTek Inc. 802.11 Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: wlan_p2p.h ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version ++ * query & set support for service discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface ++ * for supporting Wi-Fi Direct Service Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * support wlanoidSetP2pPowerSaveProfile() in P2P ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * Support wlanoidSetNetworkAddress() for P2P ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. ++ * ++ ++ * ++** ++*/ ++ ++#ifndef _WLAN_P2P_H ++#define _WLAN_P2P_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* Service Discovery */ ++typedef struct _PARAM_P2P_SEND_SD_RESPONSE { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucChannelNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_SEND_SD_RESPONSE, *P_PARAM_P2P_SEND_SD_RESPONSE; ++ ++typedef struct _PARAM_P2P_GET_SD_REQUEST { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_REQUEST, *P_PARAM_P2P_GET_SD_REQUEST; ++ ++typedef struct _PARAM_P2P_GET_SD_REQUEST_EX { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 ucChannelNum; /* Channel Number Where SD Request is received. */ ++ UINT_8 ucSeqNum; /* Get SD Request by sequence number. */ ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_REQUEST_EX, *P_PARAM_P2P_GET_SD_REQUEST_EX; ++ ++typedef struct _PARAM_P2P_SEND_SD_REQUEST { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucVersionNum; /* Indicate the Service Discovery Supplicant Version. */ ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_SEND_SD_REQUEST, *P_PARAM_P2P_SEND_SD_REQUEST; ++ ++/* Service Discovery 1.0. */ ++typedef struct _PARAM_P2P_GET_SD_RESPONSE { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_RESPONSE, *P_PARAM_P2P_GET_SD_RESPONSE; ++ ++/* Service Discovery 2.0. */ ++typedef struct _PARAM_P2P_GET_SD_RESPONSE_EX { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 ucSeqNum; /* Get SD Response by sequence number. */ ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} PARAM_P2P_GET_SD_RESPONSE_EX, *P_PARAM_P2P_GET_SD_RESPONSE_EX; ++ ++typedef struct _PARAM_P2P_TERMINATE_SD_PHASE { ++ PARAM_MAC_ADDRESS rPeerAddr; ++} PARAM_P2P_TERMINATE_SD_PHASE, *P_PARAM_P2P_TERMINATE_SD_PHASE; ++ ++/*! \brief Key mapping of BSSID */ ++typedef struct _P2P_PARAM_KEY_T { ++ UINT_32 u4Length; /*!< Length of structure */ ++ UINT_32 u4KeyIndex; /*!< KeyID */ ++ UINT_32 u4KeyLength; /*!< Key length in bytes */ ++ PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ ++ PARAM_KEY_RSC rKeyRSC; ++ UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ ++} P2P_PARAM_KEY_T, *P_P2P_PARAM_KEY_T; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/*--------------------------------------------------------------*/ ++/* Routines to handle command */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/*--------------------------------------------------------------*/ ++/* Service Discovery Subroutines */ ++/*--------------------------------------------------------------*/ ++WLAN_STATUS ++wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 puQueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++WLAN_STATUS ++wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++WLAN_STATUS ++wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++WLAN_STATUS ++wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++WLAN_STATUS ++wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++#endif ++ ++/*--------------------------------------------------------------*/ ++/* Callbacks for event indication */ ++/*--------------------------------------------------------------*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif ++#endif /* _WLAN_P2P_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c +new file mode 100644 +index 000000000000..f2324f13280e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c +@@ -0,0 +1,1303 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/aaa_fsm.c#2 ++*/ ++ ++/*! \file "aaa_fsm.c" ++ \brief This file defines the FSM for AAA MODULE. ++ ++ This file defines the FSM for AAA MODULE. ++*/ ++ ++/* ++** Log: aaa_fsm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 22 2012 yuche.tsai ++ * NULL ++ * Solve sigma test 5.1.3 issue, assoc response should have P2P IE. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Resolve inorder issue under AP mode. ++ * ++ * data frame may TX before assoc response frame. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 06 17 2011 terry.wu ++ * NULL ++ * Add BoW 11N support. ++ * ++ * 06 02 2011 eddie.chen ++ * [WCXRP00000759] [MT6620 Wi-Fi][DRV] Update RCPI in AAA ++ * Update RCPI when receiving Assoc request. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 09 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * Skip to call p2pRunEventAAAComplete to avoid indicate STA connect twice. ++ * ++ * 03 04 2011 terry.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * Remove unused variable. ++ * ++ * 02 16 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Add more check after RX assoc frame under Hot-Spot mode. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 15 2011 puff.wen ++ * NULL ++ * [On behalf of Frog] Add CFG_ENABLE_WIFI_DIRECT to p2pRunEventAAAComplete ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify AAA flow according to CM's comment. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Fix Compile warning, type cast from UINT_32 to UINT_16. ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * In P2P AT GO test mode under WinXP, we would not indicate connected event to host. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix bug while enabling P2P GO. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * modify due to P2P functino call prototype change. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 04 02 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify CFG flags ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * add support of Driver STA_RECORD_T activation ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Event to AIS/BOW/P2P ++* ++* @param[in] rJoinStatus To indicate JOIN success or failure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prSwRfb Pointer to the SW_RFB_T ++ ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS aaaFsmSendEventJoinComplete(WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb) ++{ ++ P_MSG_SAA_JOIN_COMP_T prJoinCompMsg; ++ ++ ASSERT(prStaRec); ++ ++ prJoinCompMsg = cnmMemAlloc(RAM_TYPE_TCM, sizeof(MSG_SAA_JOIN_COMP_T)); ++ if (!prJoinCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ if (IS_STA_IN_AIS(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; ++ else if (IS_STA_IN_P2P(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; ++ else if (IS_STA_IN_BOW(prStaRec)) ++ prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; ++ else ++ ASSERT(0); ++ ++ prJoinCompMsg->rJoinStatus = rJoinStatus; ++ prJoinCompMsg->prStaRec = prStaRec; ++ prJoinCompMsg->prSwRfb = prSwRfb; ++ ++ mboxSendMsg(MBOX_ID_0, (P_MSG_HDR_T) prJoinCompMsg, MSG_SEND_METHOD_BUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of saaFsmSendEventJoinComplete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Start Event to AAA FSM. ++* ++* @param[in] prMsgHdr Message of Join Request for a particular STA. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventStart(IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_JOIN_REQ_T prJoinReqMsg; ++ P_STA_RECORD_T prStaRec; ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prMsgHdr); ++ ++ prJoinReqMsg = (P_MSG_SAA_JOIN_REQ_T) prMsgHdr; ++ prStaRec = prJoinReqMsg->prStaRec; ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM\n"); ++ ++ cnmMemFree(prMsgHdr); ++ ++ /* 4 <1> Validation of SAA Start Event */ ++ if (!IS_AP_STA(prStaRec->eStaType)) { ++ ++ DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); ++ ++ /* Ignore the return value because don't care the prSwRfb */ ++ saaFsmSendEventJoinComplete(WLAN_STATUS_FAILURE, prStaRec, NULL); ++ ++ return; ++ } ++ /* 4 <2> The previous JOIN process is not completed ? */ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ } ++ /* 4 <3> Reset Status Code and Time */ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); ++ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ cnmTimerStopTimer(&prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ prStaRec->ucStaState = STA_STATE_1; ++ ++ /* Trigger SAA MODULE */ ++ saaFsmSteps(prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventStart() */ ++#endif ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Auth Request Frame and then ++* trigger AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ UINT_16 u2StatusCode; ++ BOOLEAN fgReplyAuth = FALSE; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ ++ /* 4 <1> Check P2P network conditions */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prBssInfo->fgIsNetActive) { ++ ++ /* 4 <1.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ if (WLAN_STATUS_SUCCESS == ++ authProcessRxAuth1Frame(prAdapter, ++ prSwRfb, ++ prBssInfo->aucBSSID, ++ AUTH_ALGORITHM_NUM_OPEN_SYSTEM, ++ AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ /* 4 <1.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAuth = p2pFuncValidateAuth(prAdapter, ++ prSwRfb, &prStaRec, &u2StatusCode); ++ } else { ++ fgReplyAuth = TRUE; ++ } ++ eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* 4 <2> Check BOW network conditions */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { ++ ++ /* 4 <2.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ authProcessRxAuth1Frame(prAdapter, ++ prSwRfb, ++ prBssInfo->aucBSSID, ++ AUTH_ALGORITHM_NUM_OPEN_SYSTEM, ++ AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ ++ /* 4 <2.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAuth = ++ bowValidateAuth(prAdapter, prSwRfb, &prStaRec, &u2StatusCode); ++ ++ } else { ++ ++ fgReplyAuth = TRUE; ++ } ++ eNetTypeIndex = NETWORK_TYPE_BOW_INDEX; ++ /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ return; ++ } while (FALSE); ++ ++ if (prStaRec) { ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ } ++ /* 4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame */ ++ if (fgReplyAuth) { ++ ++ if (prStaRec) { ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(AAA, WARN, "Previous AuthAssocState (%d) != IDLE.\n", ++ prStaRec->eAuthAssocState); ++ } ++ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ } else { ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_1 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else { ++ /* NOTE(Kevin): We should have STA_RECORD_T if the status code was successful */ ++ ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL)); ++ } ++ ++ /* NOTE: Ignore the return status for AAA */ ++ /* 4 <4> Reply Auth */ ++ authSendAuthFrame(prAdapter, prStaRec, eNetTypeIndex, prSwRfb, AUTH_TRANSACTION_SEQ_2, u2StatusCode); ++ ++ } ++ ++} /* end of aaaFsmRunEventRxAuth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx (Re)Association Request Frame and then ++* trigger AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ UINT_16 u2StatusCode = STATUS_CODE_RESERVED; ++ BOOLEAN fgReplyAssocResp = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ do { ++ ++ /* 4 <1> Check if we have the STA_RECORD_T for incoming Assoc Req */ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) { ++ ASSERT(0); /* Only for debug phase */ ++ break; ++ } ++ ++ if (!IS_CLIENT_STA(prStaRec)) ++ break; ++ ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ /* Do Reassocation */ ++ } else if ((prStaRec->ucStaState == STA_STATE_2) && ++ (prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2)) { ++ /* Normal case */ ++ } else { ++ DBGLOG(AAA, INFO, "Previous AuthAssocState (%d) != SEND_AUTH2, ucStaState:%d.\n", ++ prStaRec->eAuthAssocState, ++ prStaRec->ucStaState); ++ /* TODO: Why assoc req event is faster than tx done of auth */ ++ if (prStaRec->eAuthAssocState != AAA_STATE_SEND_AUTH2) ++ break; ++ } ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ /* 4 <2> Check P2P network conditions */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prBssInfo->fgIsNetActive) { ++ ++ /* 4 <2.1> Validate Assoc Req Frame and get Status Code */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ /* 4 <2.2> Validate Assoc Req Frame for Network Specific Conditions */ ++ fgReplyAssocResp = p2pFuncValidateAssocReq(prAdapter, ++ prSwRfb, ++ (PUINT_16)&u2StatusCode); ++ } else { ++ fgReplyAssocResp = TRUE; ++ } ++ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* 4 <3> Check BOW network conditions */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); ++ ++ if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { ++ ++ /* 4 <3.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ ++ /* Check if for this BSSID */ ++ if (WLAN_STATUS_SUCCESS == ++ assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { ++ ++ if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { ++ ++ /* 4 <3.2> Validate Auth Frame for Network Specific Conditions */ ++ fgReplyAssocResp = ++ bowValidateAssocReq(prAdapter, prSwRfb, &u2StatusCode); ++ ++ } else { ++ ++ fgReplyAssocResp = TRUE; ++ } ++ ++ /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ ++ break; ++ } ++ } ++ } ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ return WLAN_STATUS_SUCCESS; /* To release the SW_RFB_T */ ++ } while (FALSE); ++ ++ /* 4 <4> Update STA_RECORD_T and reply Assoc Resp Frame */ ++ if (fgReplyAssocResp) { ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ if ((((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->u2FrameCtrl & MASK_FRAME_TYPE) == ++ MAC_FRAME_REASSOC_REQ) { ++ ++ u2IELength = prSwRfb->u2PacketLen - ++ (UINT_16) OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); ++ ++ pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } else { ++ u2IELength = prSwRfb->u2PacketLen - (UINT_16) OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); ++ ++ pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } ++ ++ rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.1> Assign Association ID */ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ if (p2pRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ /* prStaRec->eAuthAssocState = AA_STATE_IDLE; */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2;/* NOTE(Kevin): for TX done */ ++ ++ /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ ++ /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ } else { ++ /* Client List FULL. */ ++ u2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if ((IS_STA_IN_BOW(prStaRec))) { ++ /* if (bowRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { */ ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; /* NOTE(Kevin): for TX done */ ++ ++ /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ ++ /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ } ++#if 0 ++ else { ++ /* Client List FULL. */ ++ u2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ } ++#endif ++#endif ++ } else { ++ prStaRec->u2AssocId = 0; /* Invalid Association ID */ ++ ++ /* If (Re)association fail, the peer can try Association w/o Auth immediately */ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ /* NOTE: Ignore the return status for AAA */ ++ /* 4 <4.2> Reply Assoc Resp */ ++ assocSendReAssocRespFrame(prAdapter, prStaRec); ++ ++} ++ ++return WLAN_STATUS_SUCCESS; ++ ++} /* end of aaaFsmRunEventRxAssoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ DBGLOG(AAA, LOUD, "EVENT-TX DONE: Current Time = %lu\n", (unsigned long)kalGetTimeTick()); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) { ++ DBGLOG(AAA, INFO, "EVENT-TX DONE: Invalid StaRec"); ++ return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ ++ } ++ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ DBGLOG(AAA, INFO, "TX DONE status: %d, AuthAssocState: %d, SeqNo: %d\n", ++ rTxDoneStatus, prStaRec->eAuthAssocState, ++ prMsduInfo->ucTxSeqNum); ++ ++ switch (prStaRec->eAuthAssocState) { ++ case AAA_STATE_SEND_AUTH2: ++ { ++ /* Strictly check the outgoing frame is matched with current AA STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_2) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { ++ if (TX_RESULT_SUCCESS == rTxDoneStatus) { ++ ++ /* NOTE(Kevin): Change to STATE_2 at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ } else { ++ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_1 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ } ++ ++ } ++ /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ ++ ++ } ++ break; ++ ++ case AAA_STATE_SEND_ASSOC2: ++ { ++ /* Strictly check the outgoing frame is matched with current SAA STATE */ ++ if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { ++ if (TX_RESULT_SUCCESS == rTxDoneStatus) { ++ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ ++ /* NOTE(Kevin): Change to STATE_3 at TX Done */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAASuccess(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAAComplete(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ } else { ++ ++ prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; ++ ++ /* NOTE(Kevin): Change to STATE_2 */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ p2pRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventAAATxFail(prAdapter, prStaRec); ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++ } ++ } ++ /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of aaaFsmRunEventTxDone() */ ++#endif /* CFG_SUPPORT_AAA */ ++ ++#if 0 /* TODO(Kevin): for abort event, just reset the STA_RECORD_T. */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send ABORT Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventAbort(IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventAbort"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: ABORT\n"); ++ ++ /* NOTE(Kevin): when reach here, the ARB_STATE should be in ARB_STATE_JOIN. */ ++ ASSERT(prJoinInfo->prBssDesc); ++ ++ /* 4 <1> Update Flags and Elements of JOIN Module. */ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel all JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rJoinTimer); ++ ++ /* 4 <2> Update the associated STA_RECORD_T during JOIN. */ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ if (prStaRec) ++ prStaRec->ucStaState = STA_STATE_1; /* Update Station Record - Class 1 Flag */ ++#if DBG ++ else ++ ASSERT(0); /* Shouldn't happened, because we already add this STA_RECORD_T at JOIN_STATE_INIT */ ++#endif /* DBG */ ++ ++ /* 4 <3> Pull back to IDLE. */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ /* 4 <4> If we are in Roaming, recover the settings of previous BSS. */ ++ /* NOTE: JOIN FAIL - ++ * Restore original setting from current BSS_INFO_T. ++ */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++} /* end of joinFsmRunEventAbort() */ ++#endif ++ ++/* TODO(Kevin): following code will be modified and move to AIS FSM */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send Join Timeout Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventJoinTimeOut"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); ++ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ ++ /* We have renew this Sta Record when in JOIN_STATE_INIT */ ++ ASSERT(prStaRec); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel other JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ /* Restore original setting from current BSS_INFO_T */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++ /* Pull back to IDLE */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ return WLAN_STATUS_FAILURE; ++ ++} /* end of joinFsmRunEventJoinTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from Peer BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ DEBUGFUNC("joinAdoptParametersFromPeerBss"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ ++ /* 4 <1> Adopt Peer BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssDesc->ePhyType; ++ ++ DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", ++ prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); ++ ++ /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); ++ ++ prJoinInfo->fgIsParameterAdopted = TRUE; ++ ++} /* end of joinAdoptParametersFromPeerBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from current associated BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) ++{ ++ /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ prBssInfo = &prAdapter->rBssInfo; ++ ++ /* 4 <1> Adopt current BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssInfo->ePhyType; ++ ++ /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); ++ ++} /* end of joinAdoptParametersFromCurrentBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will update all the SW variables and HW MCR registers after ++* the association with target BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinComplete(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ P_PEER_BSS_INFO_T prPeerBssInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_802_11D ++ P_IE_COUNTRY_T prIECountry; ++#endif ++ ++ DEBUGFUNC("joinComplete"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ prPeerBssInfo = &prAdapter->rPeerBssInfo; ++ prBssInfo = &prAdapter->rBssInfo; ++ prConnSettings = &prAdapter->rConnSettings; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ ++ /* Remove previous AP's Connection Flags if have */ ++ scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); ++ ++ prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ ++ ++ if (prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't ++ * broadcast SSID on its Beacon Frame. ++ */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); ++ ++ if (prBssDesc->ucSSIDLen) ++ prBssDesc->fgIsHiddenSSID = FALSE; ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++ DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); ++ } ++/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ ++ /* 4 <2.A> PHY Type */ ++ prBssInfo->ePhyType = prBssDesc->ePhyType; ++ ++ /* 4 <2.B> BSS Type */ ++ prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ /* 4 <2.C> BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); ++ ++ /* 4 <2.D> SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ /* 4 <2.E> Channel / Band information. */ ++ prBssInfo->eBand = prBssDesc->eBand; ++ prBssInfo->ucChnl = prBssDesc->ucChannelNum; ++ ++ /* 4 <2.F> RSN/WPA information. */ ++ secFsmRunEventStart(prAdapter); ++ prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; ++ prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ if (secRsnKeyHandshakeEnabled()) ++ prBssInfo->fgIsWPAorWPA2Enabled = TRUE; ++ else ++ prBssInfo->fgIsWPAorWPA2Enabled = FALSE; ++ ++ /* 4 <2.G> Beacon interval. */ ++ prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ ++ /* 4 <2.H> DTIM period. */ ++ prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* 4 <2.I> ERP Information */ ++ if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ ++ (prBssDesc->fgIsERPPresent)) { ++ ++ prBssInfo->fgIsERPPresent = TRUE; ++ prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ ++ } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ ++ prBssInfo->fgIsERPPresent = FALSE; ++ prBssInfo->ucERP = 0; ++ } ++ ++#if CFG_SUPPORT_802_11D ++ /* 4 <2.J> Country inforamtion of the associated AP */ ++ if (prConnSettings->fgMultiDomainCapabilityEnabled) { ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ ++ if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { ++ if (prBssDesc->prIECountry) { ++ prIECountry = prBssDesc->prIECountry; ++ ++ domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); ++ ++ /* use the domain get from the BSS info */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); ++ } else { ++ /* use the domain get from the scan result */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); ++ } ++ } ++ } ++#endif ++ ++ /* 4 <2.K> Signal Power of the associated AP */ ++ prBssInfo->rRcpi = prBssDesc->rRcpi; ++ prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); ++ GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); ++ ++ /* 4 <2.L> Capability Field of the associated AP */ ++ prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", ++ prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); ++ ++/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ ++ /* 4 <3.A> Association ID */ ++ prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; ++ ++ /* 4 <3.B> WMM Information */ ++ if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { ++ ++ prBssInfo->fgIsWmmAssoc = TRUE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC3; ++ ++ qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); ++ ++ if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { ++ kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } else { ++ kalMemCopy(&prBssInfo->rWmmInfo, ++ &prPeerBssInfo->rWmmInfo, ++ sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); ++ } ++ } else { ++ prBssInfo->fgIsWmmAssoc = FALSE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC1; ++ ++ kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } ++ ++ /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ ++ prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; ++ prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; ++ ++ /* 4 <3.D> Short Preamble */ ++ if (prBssInfo->fgIsERPPresent) { ++ ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE FALSE(shouldn't have such case, ++ * use the AssocResp) ++ * TRUE FALSE TRUE FALSE ++ * FALSE FALSE FALSE FALSE(shouldn't have such case, ++ * use the AssocResp) ++ * FALSE FALSE TRUE FALSE ++ * TRUE TRUE FALSE TRUE(follow ERP) ++ * TRUE TRUE TRUE FALSE(follow ERP) ++ * FALSE TRUE FALSE FALSE(shouldn't have such case, ++ * and we should set to FALSE) ++ * FALSE TRUE TRUE FALSE(we should set to FALSE) ++ */ ++ if ((prPeerBssInfo->fgIsShortPreambleAllowed) && ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ ++ if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ else ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ } else { ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE ++ * FALSE FALSE FALSE ++ * TRUE TRUE TRUE ++ * FALSE TRUE(status success) TRUE ++ * --> Honor the result of prPeerBssInfo. ++ */ ++ ++ prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = ++ prPeerBssInfo->fgIsShortPreambleAllowed; ++ } ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); ++ ++ /* 4 <3.E> Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); ++ ++ nicSetSlotTime(prAdapter, ++ prBssInfo->ePhyType, ++ ((prConnSettings->fgIsShortSlotTimeOptionEnable && ++ prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); ++ ++ /* 4 <3.F> Update Tx Rate for Control Frame */ ++ bssUpdateTxRateForControlFrame(prAdapter); ++ ++ /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ ++ /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ ++ { ++ ++ if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; ++ else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; ++ ++ prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; ++ ++ /* Set the stable time of the associated BSS. We won't do roaming decision ++ * during the stable time. ++ */ ++ SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, ++ SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); ++ } ++ ++ /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ ++#if CFG_TX_FRAGMENT ++ txFragInfoUpdate(prAdapter); ++#endif /* CFG_TX_FRAGMENT */ ++ ++/* 4 <4> Update STA_RECORD_T */ ++ /* Get a Station Record if possible */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); ++ ++ if (prStaRec) { ++ UINT_16 u2OperationalRateSet, u2DesiredRateSet; ++ ++ /* 4 <4.A> Desired Rate Set */ ++ u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & ++ prBssInfo->u2OperationalRateSet); ++ ++ u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); ++ if (u2DesiredRateSet) { ++ prStaRec->u2DesiredRateSet = u2DesiredRateSet; ++ } else { ++ /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ ++ prStaRec->u2DesiredRateSet = u2OperationalRateSet; ++ } ++ ++ /* Try to set the best initial rate for this entry */ ++ if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, ++ prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { ++ ++ if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) ++ ASSERT(0); ++ } ++ ++ DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); ++ ++ /* 4 <4.B> Preamble Mode */ ++ prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; ++ ++ /* 4 <4.C> QoS Flag */ ++ prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; ++ } ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++/* 4 <5> Update NIC */ ++ /* 4 <5.A> Update BSSID & Operation Mode */ ++ nicSetupBSS(prAdapter, prBssInfo); ++ ++ /* 4 <5.B> Update WLAN Table. */ ++ if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) ++ ASSERT(FALSE); ++ /* 4 <5.C> Update Desired Rate Set for BT. */ ++#if CFG_TX_FRAGMENT ++ if (prConnSettings->fgIsEnableTxAutoFragmentForBT) ++ txRateSetInitForBT(prAdapter, prStaRec); ++#endif /* CFG_TX_FRAGMENT */ ++ ++ /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ ++ if (prBssInfo->fgIsWmmAssoc) { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, FALSE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); ++ } else { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, TRUE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); ++ ++ nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); ++ } ++ ++#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN ++ { ++ prTxCtrl->fgBlockTxDuringJoin = FALSE; ++ ++#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ ++ nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxRetransmitOfSendWaitQue(prAdapter); ++ ++ if (prTxCtrl->fgIsPacketInOsSendQueue) ++ nicTxRetransmitOfOsSendQue(prAdapter); ++#if CFG_SDIO_TX_ENHANCE ++ halTxLeftClusteredMpdu(prAdapter); ++#endif /* CFG_SDIO_TX_ENHANCE */ ++ ++ } ++#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ ++ ++/* 4 <6> Setup CONNECTION flag. */ ++ prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; ++ prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; ++ ++ if (prJoinInfo->fgIsReAssoc) ++ prAdapter->fgBypassPortCtrlForRoaming = TRUE; ++ else ++ prAdapter->fgBypassPortCtrlForRoaming = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); ++ ++} /* end of joinComplete() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c +new file mode 100644 +index 000000000000..7b5a49a5ba63 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c +@@ -0,0 +1,5039 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/ais_fsm.c#1 ++*/ ++ ++/*! \file "aa_fsm.c" ++ \brief This file defines the FSM for SAA and AAA MODULE. ++ ++ This file defines the FSM for SAA and AAA MODULE. ++*/ ++ ++/* ++** Log: ais_fsm.c ++** ++** 09 06 2013 cp.wu ++** always paste SSID information to SAA-FSM ++** ++** 09 06 2013 cp.wu ++** add error handling when reassociation request failed to locate bss descriptor ++** ++** 09 05 2013 cp.wu ++** isolate logic regarding roaming & reassociation ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with ++ * corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration ++ * corresponding to network type. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous ++ * to asynchronous approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state ++ * without join timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED ++ * cases as an explicit trigger for Android framework ++ * correct reference to BSSID field in Association-Response frame. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED ++ * cases as an explicit trigger for Android framework ++ * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. ++ * 2. (Android only) when reassociation-and-non-roaming cases happened, indicate an extra DISCONNECT ++ * indication to Android Wi-Fi framework ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 10 26 2011 tsaiyuan.hsu ++ * [WCXRP00001064] [MT6620 Wi-Fi][DRV]] add code with roaming awareness when disconnecting AIS network ++ * be aware roaming when disconnecting AIS network. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * STA_REC shall be NULL for Beacon's MSDU ++ * ++ * 10 13 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS ++ * 1. short join failure count limit to 2 ++ * 2. treat join timeout as kind of join failure as well ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 20 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * change window registry of driver for roaming. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Handle client mode about preamble type and slot time ++ * ++ * 09 08 2011 tsaiyuan.hsu ++ * [WCXRP00000972] [MT6620 Wi-Fi][DRV]] check if roaming occurs after join failure to avoid state incosistence. ++ * check if roaming occurs after join failure to avoid deactivation of network. ++ * ++ * 08 24 2011 chinghwa.yu ++ * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Update RDD test mode cases. ++ * ++ * 08 16 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * EnableRoaming in registry is deprecated. ++ * ++ * 08 16 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * use registry to enable or disable roaming. ++ * ++ * 07 07 2011 cp.wu ++ * [WCXRP00000840] [MT6620 Wi-Fi][Driver][AIS] Stop timer for joining when channel is released ++ * due to join failure count exceeding limit ++ * stop timer when joining operation is failed due to try count exceeds limitation ++ * ++ * 06 28 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work ++ * around some tricky AP which use space character as hidden SSID ++ * do not handle SCAN request immediately after connected to increase the probability of receiving 1st beacon frame. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * ensure DEAUTH is always sent before establish a new connection ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * typo fix: a right brace is missed. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * When RECONNECT request is identified as disconnected, it is necessary to check for pending scan request. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels ++ * mark fgIsTransition as TRUE for state rolling. ++ * ++ * 06 16 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * always check for pending scan after switched into NORMAL_TR state. ++ * ++ * 06 14 2011 cp.wu ++ * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout ++ * always treat connection request at higher priority over scanning request ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state ++ * when DEAUTH frame is dropped due to bss disconnection ++ * change SCAN handling behavior when followed by a CONNECT/DISCONNECT requests by pending instead of dropping. ++ * ++ * 05 17 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state ++ * when DEAUTH frame is dropped due to bss disconnection ++ * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 13 2011 george.huang ++ * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF ++ * remove assert ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000575] [MT6620 Wi-Fi][Driver][AIS] reduce memory usage when generating mailbox message for scan request ++ * when there is no IE needed for probe request, then request a smaller memory for mailbox message ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 03 11 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel ++ * ++ * 03 09 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * avoid clearing fgIsScanReqIssued so as to add scan results. ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 04 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * reset retry conter of attemp to connect to ap after completion of join. ++ * ++ * 03 04 2011 cp.wu ++ * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection ++ * surpress compile warning occurred when compiled by GNU compiler collection. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right ++ * after connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 02 23 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to ++ * improve response time for scanning request ++ * when handling reconnect request, set fgTryScan as TRUE ++ * ++ * 02 22 2011 cp.wu ++ * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach ++ * to improve response time for scanning request ++ * handle SCAN and RECONNECT with a FIFO approach. ++ * ++ * 02 09 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * Check if prRegInfo is null or not before initializing roaming parameters. ++ * ++ * 02 01 2011 cp.wu ++ * [WCXRP00000416] [MT6620 Wi-Fi][Driver] treat "unable to find BSS" as connection trial ++ * to prevent infinite reconnection trials ++ * treat "unable to find BSS" as connection trial to prevent infinite reconnection trials. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 14 2011 cp.wu ++ * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent ++ * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. ++ * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. ++ * ++ * 01 11 2011 cp.wu ++ * [WCXRP00000307] [MT6620 Wi-Fi][SQA]WHQL test .2c_wlan_adhoc case fail. ++ * [IBSS] when merged in, the bss state should be updated to firmware to pass WHQL adhoc failed item ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer ++ * when the corresponding BSS is disconnected due to beacon timeout ++ * remove from scanning result when the BSS is disconnected due to beacon timeout. ++ * ++ * 01 03 2011 cp.wu ++ * [WCXRP00000337] [MT6620 Wi-FI][Driver] AIS-FSM not to invoke cnmStaRecResetStatus ++ * directly 'cause it frees all belonging STA-RECs ++ * do not invoke cnmStaRecResetStatus() directly, nicUpdateBss will do the things after bss is disconnected ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * do not need to manipulate prStaRec after indicating BSS disconnection to firmware, ++ * 'cause all STA-RECs belongs to BSS has been freed already ++ * ++ * 12 27 2010 cp.wu ++ * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release ++ * add DEBUGFUNC() macro invoking for more detailed debugging information ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 12 17 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update SLT Function for QoS Support and not be affected by fixed rate function. ++ * ++ * 11 25 2010 cp.wu ++ * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM ++ * add scanning with specified SSID facility to AIS-FSM ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with ++ * Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate ++ * from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000097] [MT6620 Wi-Fi] [Driver] Fixed the P2P not setting the fgIsChannelExt value make scan not abort ++ * initial the fgIsChannelExt value. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. ++ * correct erroneous logic: specifying eBand with incompatible eSco ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000049] [MT6620 Wi-Fi][Driver] Adhoc cannot be created successfully. ++ * keep IBSS-ALONE state retrying until further instruction is received ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 09 2010 yuche.tsai ++ * NULL ++ * Fix NULL IE Beacon issue. Sync Beacon Content to FW before enable beacon. ++ * Both in IBSS Create & IBSS Merge ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * frequency is in unit of KHz thus no need to divide 1000 once more. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * 1) initialize for correct parameter even for disassociation. ++ * 2) AIS-FSM should have a limit on trials to build connection ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add option for enabling AIS 5GHz scan ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, ++ * RLM/CNM will handle the channel switching when BSS information is updated ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * check-in missed files. ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 09 2010 cp.wu ++ * NULL ++ * reset fgIsScanReqIssued when abort request is received right after join completion. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * allocate on MGMT packet for IBSS beaconing. ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * [AIS-FSM] fix: when join failed, release channel privilege as well ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * reuse join-abort sub-procedure to reduce code size. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, ++ * just pend it til 5-sec. period finishes ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 26 2010 cp.wu ++ * ++ * re-commit code logic being overwriten. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) enable Ad-Hoc ++ * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * indicate scan done for linux wireless extension ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 21 2010 cp.wu ++ * ++ * separate AIS-FSM states into different cases of channel request. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one ++ * 2) refine disconnection behaviour when issued during BG-SCAN process ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) bugfix: do not stop timer for join after switched into normal_tr state, ++ * for providing chance for DHCP handshasking ++ * 2) modify rsnPerformPolicySelection() invoking ++ * ++ * 07 19 2010 cp.wu ++ * ++ * 1) init AIS_BSS_INFO as channel number = 1 with band = 2.4GHz ++ * 2) correct typo ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * for AIS scanning, driver specifies no extra IE for probe request ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * Remove CFG_MQM_MIGRATION ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Refine AIS-FSM by divided into more states ++ * ++ * 07 13 2010 cm.chang ++ * ++ * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * for first connection, if connecting failed do not enter into scan state. ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * once STA-REC is allocated and updated, invoke cnmStaRecChangeState() to sync. with firmware. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * remove unused definitions. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * RSN/PRIVACY compilation flag awareness correction ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change to enqueue TX frame infinitely. ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 01 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add conditionial compiling flag to choose default available bandwidth ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile error if CFG_CMD_EVENT_VER_009 == 0 for prEventConnStatus->ucNetworkType. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 17 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Call pmAbort() and add ucNetworkType field in EVENT_CONNECTION_STATUS ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile warning - define of MQM_WMM_PARSING was removed ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed the use of compiling flag MQM_WMM_PARSING ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * ++ * Fix typo ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the protected bit at cap info for ad-hoc. ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add new HW CH macro support ++ * ++ * 04 07 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Add TX Power Control RCPI function. ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * move the wlan table alloc / free to change state function. ++ * ++ * 03 25 2010 wh.su ++ * [BORA00000676][MT6620] Support the frequency setting and query at build connection / connection event ++ * modify the build connection and status event structure bu CMD_EVENT doc 0.09 draft, default is disable. ++ * ++ * 03 24 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * fixed some WHQL testing error. ++ * ++ * 03 24 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Set / Unset POWER STATE in AIS Network ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 03 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add PHY_CONFIG to change Phy Type ++ * ++ * 03 03 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Use bcmWiFiNotify to replace wifi_send_msg to pass information to BCM module. ++ * ++ * 03 03 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Remove wmt_task definition and add PTA function. ++ * ++ * 03 02 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Init TXM and MQM testing procedures in aisFsmRunEventJoinComplete() ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Modified aisUpdateBssInfo() to call TXM's functions for setting WTBL TX parameters ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * clear the pmkid cache while indicate media disconnect. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * . ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Enabled MQM parsing WMM IEs for non-AP mode ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * use the Rx0 dor event indicate. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Support dynamic channel selection ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000621][MT6620 Wi-Fi] Add the RSSI indicate to avoid XP stalled for query rssi value ++ * Adding the RSSI event support, ++ * using the HAL function to get the rcpi value and tranlsate to RSSI and indicate to driver ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Set max AMDPU size supported by the peer to 64 KB, ++ * removed mqmInit() and mqmTxSendAddBaReq() function calls in aisUpdateBssInfo() ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 20 2010 kevin.huang ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags ++ * ++ * 01 15 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Configured the AMPDU factor to 3 for the APu1rwduu`wvpghlqg|q`mpdkb+ilp ++ * ++ * 01 14 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Add WiFi BCM module for the 1st time. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Refine JOIN Complete and separate the function of Media State indication ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the sample code to update the wlan table rate, ++ * ++ * Dec 10 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Different function prototype of wifi_send_msg() ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call rlm related function to process HT info when join complete ++ * ++ * Dec 9 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * default the acquired wlan table entry code off ++ * ++ * Dec 9 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to acquired the wlan table entry, and a sample code to update the BA bit at table ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix the problem of prSwRfb overwrited by event packet in aisFsmRunEventJoinComplete() ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to integrate the security related code ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove redundant declaration ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add code for JOIN init and JOIN complete ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename u4RSSI to i4RSSI ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise ENUM_MEDIA_STATE to ENUM_PARAM_MEDIA_STATE ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add fgIsScanReqIssued to CONNECTION_SETTINGS_T ++ * ++ * Nov 26 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise Virtual CMD handler due to structure changed ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Virtual CMD & RESP for testing CMD PATH ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmInitializeConnectionSettings() ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add CFG_TEST_MGMT_FSM flag for aisFsmTest() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define AIS_ROAMING_CONNECTION_TRIAL_LIMIT 2 ++#define AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME 80 ++ ++#define CTIA_MAGIC_SSID "ctia_test_only_*#*#3646633#*#*" ++#define CTIA_MAGIC_SSID_LEN 30 ++ ++#define AIS_JOIN_TIMEOUT 7 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugAisState[AIS_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("AIS_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_SEARCH"), ++ (PUINT_8) DISP_STRING("AIS_STATE_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_ONLINE_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_LOOKING_FOR"), ++ (PUINT_8) DISP_STRING("AIS_STATE_WAIT_FOR_NEXT_SCAN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REQ_CHANNEL_JOIN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_JOIN"), ++ (PUINT_8) DISP_STRING("AIS_STATE_IBSS_ALONE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_IBSS_MERGE"), ++ (PUINT_8) DISP_STRING("AIS_STATE_NORMAL_TR"), ++ (PUINT_8) DISP_STRING("AIS_STATE_DISCONNECTING"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REQ_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("AIS_STATE_REMAIN_ON_CHANNEL") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to initialize the value of the connection settings for ++* AIS network ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucAnyBSSID[] = BC_BSSID; ++ UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; ++ int i = 0; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* Setup default values for operation */ ++ COPY_MAC_ADDR(prConnSettings->aucMacAddress, aucZeroMacAddr); ++ ++ if (prRegInfo) ++ prConnSettings->ucDelayTimeOfDisconnectEvent = ++ (!prAdapter->fgIsHw5GBandDisabled && prRegInfo->ucSupport5GBand) ? ++ AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND : AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; ++ else ++ prConnSettings->ucDelayTimeOfDisconnectEvent = AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; ++ ++ COPY_MAC_ADDR(prConnSettings->aucBSSID, aucAnyBSSID); ++ prConnSettings->fgIsConnByBssidIssued = FALSE; ++ ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ prConnSettings->fgIsDisconnectedByNonRequest = FALSE; ++ ++ prConnSettings->ucSSIDLen = 0; ++ ++ prConnSettings->eOPMode = NET_TYPE_INFRA; ++ ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ ++ if (prRegInfo) { ++ prConnSettings->ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4StartFreq); ++ prConnSettings->eAdHocBand = prRegInfo->u4StartFreq < 5000000 ? BAND_2G4 : BAND_5G; ++ prConnSettings->eAdHocMode = (ENUM_PARAM_AD_HOC_MODE_T) (prRegInfo->u4AdhocMode); ++ } ++ ++ prConnSettings->eAuthMode = AUTH_MODE_OPEN; ++ ++ prConnSettings->eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* MIB attributes */ ++ prConnSettings->u2BeaconPeriod = DOT11_BEACON_PERIOD_DEFAULT; ++ ++ prConnSettings->u2RTSThreshold = DOT11_RTS_THRESHOLD_DEFAULT; ++ ++ prConnSettings->u2DesiredNonHTRateSet = RATE_SET_ALL_ABG; ++ ++ /* prConnSettings->u4FreqInKHz; */ /* Center frequency */ ++ ++ /* Set U-APSD AC */ ++ prConnSettings->bmfgApsdEnAc = PM_UAPSD_NONE; ++ ++ secInit(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* Features */ ++ prConnSettings->fgIsEnableRoaming = FALSE; ++#if CFG_SUPPORT_ROAMING ++ if (prRegInfo) ++ prConnSettings->fgIsEnableRoaming = ((prRegInfo->fgDisRoaming > 0) ? (FALSE) : (TRUE)); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ prConnSettings->fgIsAdHocQoSEnable = FALSE; ++ ++ prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGN; ++ ++ /* Set default bandwidth modes */ ++ prConnSettings->uc2G4BandwidthMode = CONFIG_BW_20M; ++ prConnSettings->uc5GBandwidthMode = CONFIG_BW_20_40M; ++ ++ prConnSettings->rRsnInfo.ucElemId = 0x30; ++ prConnSettings->rRsnInfo.u2Version = 0x0001; ++ prConnSettings->rRsnInfo.u4GroupKeyCipherSuite = 0; ++ prConnSettings->rRsnInfo.u4PairwiseKeyCipherSuiteCount = 0; ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prConnSettings->rRsnInfo.au4PairwiseKeyCipherSuite[i] = 0; ++ prConnSettings->rRsnInfo.u4AuthKeyMgtSuiteCount = 0; ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) ++ prConnSettings->rRsnInfo.au4AuthKeyMgtSuite[i] = 0; ++ prConnSettings->rRsnInfo.u2RsnCap = 0; ++ prConnSettings->rRsnInfo.fgRsnCapPresent = FALSE; ++ ++} /* end of aisFsmInitializeConnectionSettings() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to initialize the value in AIS_FSM_INFO_T for ++* AIS FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ucScanTimeoutTimes = 0; ++VOID aisFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ ++ DEBUGFUNC("aisFsmInit()"); ++ DBGLOG(SW1, TRACE, "->aisFsmInit()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ /* 4 <1> Initiate FSM */ ++ prAisFsmInfo->ePreviousState = AIS_STATE_IDLE; ++ prAisFsmInfo->eCurrentState = AIS_STATE_IDLE; ++ ++ prAisFsmInfo->ucAvailableAuthTypes = 0; ++ ++ prAisFsmInfo->prTargetBssDesc = (P_BSS_DESC_T) NULL; ++ ++ prAisFsmInfo->ucSeqNumOfReqMsg = 0; ++ prAisFsmInfo->ucSeqNumOfChReq = 0; ++ prAisFsmInfo->ucSeqNumOfScanReq = 0; ++ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++#if CFG_SUPPORT_ROAMING ++ prAisFsmInfo->fgIsRoamingScanPending = FALSE; ++#endif /* CFG_SUPPORT_ROAMING */ ++ prAisFsmInfo->fgIsChannelRequested = FALSE; ++ prAisFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 4 <1.1> Initiate FSM - Timer INIT */ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rBGScanTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventBGSleepTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rIbssAloneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventIbssAloneTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rIndicationOfDisconnectTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisPostponedEventOfDisconnTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rJoinTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventJoinTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rScanDoneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventScanDoneTimeOut, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rChannelTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventChannelTimeout, (ULONG) NULL); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisFsmInfo->rDeauthDoneTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventDeauthTimeout, (ULONG) NULL); ++ ++ /* 4 <1.2> Initiate PWR STATE */ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ COPY_MAC_ADDR(prAisBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); ++ ++ /* 4 <3> Initiate BSS_INFO_T - private part */ ++ /* TODO */ ++ prAisBssInfo->eBand = BAND_2G4; ++ prAisBssInfo->ucPrimaryChannel = 1; ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ ++ /* 4 <4> Allocate MSDU_INFO_T for Beacon */ ++ prAisBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prAisBssInfo->prBeacon) { ++ prAisBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prAisBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ ++ } else { ++ ASSERT(0); ++ } ++ ++#if 0 ++ prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++#else ++ if (prAdapter->u4UapsdAcBmp == 0) { ++ prAdapter->u4UapsdAcBmp = CFG_INIT_UAPSD_AC_BMP; ++ /* ASSERT(prAdapter->u4UapsdAcBmp); */ ++ } ++ prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; ++#endif ++ ++ /* request list initialization */ ++ LINK_INITIALIZE(&prAisFsmInfo->rPendingReqList); ++ ++ /* DBGPRINTF("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, */ ++ /* prAisBssInfo->rPmProfSetupInfo.ucUapsdSp); */ ++ ++ /*reset ucScanTimeoutTimes value*/ ++ ucScanTimeoutTimes = 0; ++ ++} /* end of aisFsmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief the function is used to uninitialize the value in AIS_FSM_INFO_T for ++* AIS FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ ++ DEBUGFUNC("aisFsmUninit()"); ++ DBGLOG(SW1, INFO, "->aisFsmUninit()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ /* 4 <1> Stop all timers */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); /* Add by Enlai */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ /* 4 <2> flush pending request */ ++ aisFsmFlushRequest(prAdapter); ++ ++ /* 4 <3> Reset driver-domain BSS-INFO */ ++ if (prAisBssInfo->prBeacon) { ++ cnmMgtPktFree(prAdapter, prAisBssInfo->prBeacon); ++ prAisBssInfo->prBeacon = NULL; ++ } ++#if CFG_SUPPORT_802_11W ++ rsnStopSaQuery(prAdapter); ++#endif ++ ++} /* end of aisFsmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialization of JOIN STATE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ DEBUGFUNC("aisFsmStateInit_JOIN()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> We are going to connect to this BSS. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_LEGACY_AP, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ if (prStaRec == NULL) { ++ DBGLOG(AIS, WARN, "Create station record fail\n"); ++ return; ++ } ++ ++ prAisFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <2.1> sync. to firmware domain */ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ switch (prConnSettings->eAuthMode) { ++ case AUTH_MODE_OPEN: /* Note: Omit break here. */ ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ break; ++ ++ case AUTH_MODE_SHARED: ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; ++ break; ++ ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(AIS, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); ++ prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | AUTH_TYPE_SHARED_KEY); ++ break; ++ ++ default: ++ ASSERT(!(prConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); ++ DBGLOG(AIS, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", ++ prConnSettings->eAuthMode); ++ /* TODO(Kevin): error handling ? */ ++ return; ++ } ++ ++ /* TODO(tyhsu): Assume that Roaming Auth Type is equal to ConnSettings eAuthMode */ ++ prAisSpecificBssInfo->ucRoamingAuthTypes = prAisFsmInfo->ucAvailableAuthTypes; ++ ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ ++ } else { ++ ASSERT(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE); ++ ASSERT(!prBssDesc->fgIsConnected); ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: AUTH TYPE = %d for Roaming\n", ++ prAisSpecificBssInfo->ucRoamingAuthTypes); ++ ++ prStaRec->fgIsReAssoc = TRUE; /* We do roaming while the medium is connected */ ++ ++ /* TODO(Kevin): We may call a sub function to acquire the Roaming Auth Type */ ++ prAisFsmInfo->ucAvailableAuthTypes = prAisSpecificBssInfo->ucRoamingAuthTypes; ++ ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING; ++ } ++ ++ /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ ++ if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { ++ ++ DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ ++ if (prBssDesc->ucSSIDLen) ++ COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ if (1) { ++ int j; ++ P_FRAG_INFO_T prFragInfo; ++ ++ for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { ++ prFragInfo = &prStaRec->rFragInfo[j]; ++ ++ if (prFragInfo->pr1stFrag) { ++ /* nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); */ ++ prFragInfo->pr1stFrag = (P_SW_RFB_T) NULL; ++ } ++ } ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++} /* end of aisFsmInit_JOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval TRUE We will retry JOIN ++* @retval FALSE We will not retry JOIN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_JOIN_REQ_T prJoinReqMsg; ++ ++ DEBUGFUNC("aisFsmStateInit_RetryJOIN()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* Retry other AuthType if possible */ ++ if (!prAisFsmInfo->ucAvailableAuthTypes) ++ return FALSE; ++ ++ if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(AIS, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else { ++ DBGLOG(AIS, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); ++ ASSERT(0); ++ } ++ ++ prAisFsmInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ ++ ++ /* Trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ return FALSE; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ return TRUE; ++ ++} /* end of aisFsmRetryJOIN() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief State Initialization of AIS_STATE_IBSS_ALONE ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Check if IBSS was created before ? */ ++ if (prAisBssInfo->fgIsBeaconActivated) { ++ ++ /* 4 <2> Start IBSS Alone Timer for periodic SCAN and then SEARCH */ ++#if !CFG_SLT_SUPPORT ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); ++#endif ++ } ++ ++ aisFsmCreateIBSS(prAdapter); ++ ++} /* end of aisFsmStateInit_IBSS_ALONE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief State Initialization of AIS_STATE_IBSS_MERGE ++* ++* @param[in] prBssDesc The pointer of BSS_DESC_T which is the IBSS we will try to merge with. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ ASSERT(prBssDesc); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> We will merge with to this BSS immediately. */ ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ if (prStaRec == NULL) { ++ DBGLOG(AIS, WARN, "Create station record fail\n"); ++ return; ++ } ++ ++ prStaRec->fgIsMerging = TRUE; ++ ++ prAisFsmInfo->prTargetStaRec = prStaRec; ++ ++ /* 4 <2.1> sync. to firmware domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* 4 <3> IBSS-Merge */ ++ aisFsmMergeIBSS(prAdapter, prStaRec); ++ ++} /* end of aisFsmStateInit_IBSS_MERGE() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of JOIN Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_JOIN_ABORT_T prJoinAbortMsg; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* 1. Abort JOIN process */ ++ prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); ++ if (!prJoinAbortMsg) { ++ ++ ASSERT(0); /* Can't abort SAA FSM */ ++ return; ++ } ++ ++ prJoinAbortMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_ABORT; ++ prJoinAbortMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfReqMsg; ++ prJoinAbortMsg->prStaRec = prAisFsmInfo->prTargetStaRec; ++ ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ /* 2. Return channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 3.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 3.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++} /* end of aisFsmAbortJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of SCAN Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* Abort JOIN process. */ ++ prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ ++ ASSERT(0); /* Can't abort SCN FSM */ ++ return; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfScanReq; ++ prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ prScanCancelMsg->fgIsChannelExt = FALSE; ++#endif ++ ++ /* unbuffered message to guarantee scan is cancelled in sequence */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_UNBUF); ++ ++} /* end of aisFsmAbortSCAN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of NORMAL_TR Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ DBGLOG(AIS, TRACE, "aisFsmStateAbort_NORMAL_TR\n"); ++ ++ /* TODO(Kevin): Do abort other MGMT func */ ++ ++ /* 1. Release channel to CNM */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 2.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++} /* end of aisFsmAbortNORMAL_TR() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of NORMAL_TR Abort ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* reset BSS-DESC */ ++ if (prAisFsmInfo->prTargetStaRec) { ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); ++ ++ if (prBssDesc) { ++ prBssDesc->fgIsConnected = FALSE; ++ prBssDesc->fgIsConnecting = FALSE; ++ } ++ } ++ /* release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++} ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of AIS(Ad-hoc, Infra STA) ++* ++* @param[in] eNextState Enum value of next AIS STATE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc; ++ P_MSG_CH_REQ_T prMsgChReq; ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ P_AIS_REQ_HDR_T prAisReq; ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannel; ++ UINT_16 u2ScanIELen; ++ ENUM_AIS_STATE_T eOriPreState; ++ ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("aisFsmSteps()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ eOriPreState = prAisFsmInfo->ePreviousState; ++ ++ do { ++ ++ /* Do entering Next State */ ++ prAisFsmInfo->ePreviousState = prAisFsmInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(AIS, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugAisState[prAisFsmInfo->eCurrentState], apucDebugAisState[eNextState]); ++#else ++ DBGLOG(AIS, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_AIS_IDX, prAisFsmInfo->eCurrentState, eNextState); ++#endif ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ prAisFsmInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ /* Do tasks of the State that we just entered */ ++ switch (prAisFsmInfo->eCurrentState) { ++ /* NOTE(Kevin): we don't have to rearrange the sequence of following ++ * switch case. Instead I would like to use a common lookup table of array ++ * of function pointer to speed up state search. ++ */ ++ case AIS_STATE_IDLE: ++ ++ prAisReq = aisFsmGetNextRequest(prAdapter); ++ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ ++ if (prAisReq == NULL || prAisReq->eReqType == AIS_REQUEST_RECONNECT) { ++ if (prConnSettings->fgIsConnReqIssued == TRUE && ++ prConnSettings->fgIsDisconnectedByNonRequest == FALSE) { ++ ++ prAisFsmInfo->fgTryScan = TRUE; ++ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* reset trial count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ eNextState = AIS_STATE_SEARCH; ++ fgIsTransition = TRUE; ++ } else { ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* check for other pending request */ ++ if (prAisReq && ++ (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE)) { ++ ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_SCAN; ++ ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ if (prAisReq) { ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } ++ } else if (prAisReq->eReqType == AIS_REQUEST_SCAN) { ++#if CFG_SUPPORT_ROAMING ++ prAisFsmInfo->fgIsRoamingScanPending = FALSE; ++#endif /* CFG_SUPPORT_ROAMING */ ++ wlanClearScanningResult(prAdapter); ++ ++ eNextState = AIS_STATE_SCAN; ++ fgIsTransition = TRUE; ++ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } else if (prAisReq->eReqType == AIS_REQUEST_ROAMING_CONNECT ++ || prAisReq->eReqType == AIS_REQUEST_ROAMING_SEARCH) { ++ /* ignore */ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } else if (prAisReq->eReqType == AIS_REQUEST_REMAIN_ON_CHANNEL) { ++ eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; ++ fgIsTransition = TRUE; ++ ++ /* free the message */ ++ cnmMemFree(prAdapter, prAisReq); ++ } ++ ++ prAisFsmInfo->u4SleepInterval = AIS_BG_SCAN_INTERVAL_MIN_SEC; ++ ++ break; ++ ++ case AIS_STATE_SEARCH: ++ /* 4 <1> Search for a matched candidate and save it to prTargetBssDesc. */ ++#if CFG_SLT_SUPPORT ++ prBssDesc = prAdapter->rWifiVar.rSltInfo.prPseudoBssDesc; ++#else ++ prBssDesc = scanSearchBssDescByPolicy(prAdapter, NETWORK_TYPE_AIS_INDEX); ++#endif ++ /* every time BSS join failure count is integral multiples of SCN_BSS_JOIN_FAIL_THRESOLD, ++ we need to scan again to find if a new BSS is here in the ESS, ++ this can also avoid too frequency to retry the rejected AP */ ++ if (prAisFsmInfo->ePreviousState == AIS_STATE_LOOKING_FOR || ++ ((eOriPreState == AIS_STATE_ONLINE_SCAN || ++ eOriPreState == AIS_STATE_SCAN) && prAisFsmInfo->ePreviousState != eOriPreState)) { ++ /* if previous state is scan/online scan/looking for, don't try to scan again */ ++ } else if (prBssDesc && prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD && ++ ((prBssDesc->ucJoinFailureCount - SCN_BSS_JOIN_FAIL_THRESOLD) % ++ SCN_BSS_JOIN_FAIL_THRESOLD) == 0) ++ prBssDesc = NULL; ++ ++ /* we are under Roaming Condition. */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ if (prAisFsmInfo->ucConnTrialCount > AIS_ROAMING_CONNECTION_TRIAL_LIMIT) { ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_CONNLIMIT); ++#endif /* CFG_SUPPORT_ROAMING */ ++ /* reset retry count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ /* abort connection trial */ ++ prConnSettings->fgIsConnReqIssued = FALSE; ++ ++ eNextState = AIS_STATE_NORMAL_TR; ++ fgIsTransition = TRUE; ++ ++ break; ++ } ++ } ++ /* 4 <2> We are not under Roaming Condition. */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ /* 4 <2.a> If we have the matched one */ ++ if (prBssDesc) { ++ ++ /* 4
Stored the Selected BSS security cipher. ++ For later asoc req compose IE */ ++ prAisBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prAisBssInfo->u4RsnSelectedPairwiseCipher = ++ prBssDesc->u4RsnSelectedPairwiseCipher; ++ prAisBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ /* 4 Do STATE transition and update current Operation Mode. */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* Transit to channel acquire */ ++ eNextState = AIS_STATE_REQ_CHANNEL_JOIN; ++ fgIsTransition = TRUE; ++ ++ /* increase connection trial count */ ++ prAisFsmInfo->ucConnTrialCount++; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } ++ /* 4 <2.b> If we don't have the matched one */ ++ else { ++ ++ /* increase connection trial count for infrastructure connection */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) ++ prAisFsmInfo->ucConnTrialCount++; ++ /* 4 Try to SCAN */ ++ if (prAisFsmInfo->fgTryScan) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ fgIsTransition = TRUE; ++ break; ++ } ++ /* 4 We've do SCAN already, now wait in some STATE. */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) { ++ ++ /* issue reconnect request, ++ * and retreat to idle state for scheduling */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) ++ || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) ++ || (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ prAisFsmInfo->prTargetBssDesc = NULL; ++ ++ eNextState = AIS_STATE_IBSS_ALONE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } ++ } ++ /* 4 <3> We are under Roaming Condition. */ ++ else { /* prAdapter->eConnectionState == MEDIA_STATE_CONNECTED. */ ++ ++ /* 4 <3.a> This BSS_DESC_T is our AP. */ ++ /* NOTE(Kevin 2008/05/16): Following cases will go back to NORMAL_TR. ++ * CASE I: During Roaming, APP(WZC/NDISTEST) change the connection ++ * settings. That make we can NOT match the original AP, so the ++ * prBssDesc is NULL. ++ * CASE II: The same reason as CASE I. Because APP change the ++ * eOPMode to other network type in connection setting ++ * (e.g. NET_TYPE_IBSS), so the BssDesc become the IBSS node. ++ * (For CASE I/II, before WZC/NDISTEST set the OID_SSID, it will change ++ * other parameters in connection setting first. So if we do roaming ++ * at the same time, it will hit these cases.) ++ * ++ * CASE III: Normal case, we can't find other candidate to roam ++ * out, so only the current AP will be matched. ++ * ++ * CASE IV: Timestamp of the current AP might be reset ++ */ ++ if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION && ++ ((!prBssDesc) || /* CASE I */ ++ (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) || /* CASE II */ ++ (prBssDesc->fgIsConnected) || /* CASE III */ ++ (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID))) /* CASE IV */) { ++#if DBG ++ if ((prBssDesc) && (prBssDesc->fgIsConnected)) ++ ASSERT(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); ++#endif /* DBG */ ++ /* We already associated with it, go back to NORMAL_TR */ ++ /* TODO(Kevin): Roaming Fail */ ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* Retreat to NORMAL_TR state */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ fgIsTransition = TRUE; ++ break; ++ } ++ ++ /* 4 <3.b> Try to roam out for JOIN this BSS_DESC_T. */ ++ if (prBssDesc == NULL) { ++ /* increase connection trial count for infrastructure connection */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) ++ prAisFsmInfo->ucConnTrialCount++; ++ /* 4 Try to SCAN */ ++ if (prAisFsmInfo->fgTryScan) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ fgIsTransition = TRUE; ++ break; ++ } ++ ++ /* 4 We've do SCAN already, now wait in some STATE. */ ++ if (prConnSettings->eOPMode == NET_TYPE_INFRA) { ++ ++ /* issue reconnect request, and retreat to idle state ++ * for scheduling */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } ++#if CFG_SUPPORT_ADHOC ++ else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) ++ || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) ++ || (prConnSettings->eOPMode == ++ NET_TYPE_DEDICATED_IBSS)) { ++ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ prAisFsmInfo->prTargetBssDesc = NULL; ++ ++ eNextState = AIS_STATE_IBSS_ALONE; ++ fgIsTransition = TRUE; ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ else { ++ ASSERT(0); ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ fgIsTransition = TRUE; ++ } ++ } else { ++#if DBG ++ if (prAisBssInfo->ucReasonOfDisconnect != ++ DISCONNECT_REASON_CODE_REASSOCIATION) { ++ ASSERT(UNEQUAL_MAC_ADDR ++ (prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); ++ } ++#endif /* DBG */ ++ ++ /* 4 Record the target BSS_DESC_T for next STATE. */ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* tyhsu: increase connection trial count */ ++ prAisFsmInfo->ucConnTrialCount++; ++ ++ /* Transit to channel acquire */ ++ eNextState = AIS_STATE_REQ_CHANNEL_JOIN; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ break; ++ ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ ++ DBGLOG(AIS, LOUD, "SCAN: Idle Begin - Current Time = %u\n", kalGetTimeTick()); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rBGScanTimer, SEC_TO_MSEC(prAisFsmInfo->u4SleepInterval)); ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prAisFsmInfo->u4SleepInterval < AIS_BG_SCAN_INTERVAL_MAX_SEC) ++ prAisFsmInfo->u4SleepInterval <<= 1; ++ break; ++ ++ case AIS_STATE_SCAN: ++ case AIS_STATE_ONLINE_SCAN: ++ case AIS_STATE_LOOKING_FOR: ++ ++ if (!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) { ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ ++ /* IE length decision */ ++ if (prAisFsmInfo->u4ScanIELength > 0) { ++ u2ScanIELen = (UINT_16) prAisFsmInfo->u4ScanIELength; ++ } else { ++#if CFG_SUPPORT_WPS2 ++ u2ScanIELen = prAdapter->prGlueInfo->u2WSCIELen; ++#else ++ u2ScanIELen = 0; ++#endif ++ } ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ OFFSET_OF(MSG_SCN_SCAN_REQ, ++ aucIE) + u2ScanIELen); ++ if (!prScanReqMsg) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfScanReq; ++ prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; ++#else ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++#endif ++ ++#if CFG_SUPPORT_ROAMING_ENC ++ if (prAdapter->fgIsRoamingEncEnabled == TRUE) { ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR && ++ prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ prScanReqMsg->u2ChannelDwellTime = AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME; ++ } ++ } ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_SCAN ++ || prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { ++ if (prAisFsmInfo->ucScanSSIDLen == 0) { ++ /* Scan for all available SSID */ ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; ++ } else { ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ COPY_SSID(prScanReqMsg->aucSSID, ++ prScanReqMsg->ucSSIDLength, ++ prAisFsmInfo->aucScanSSID, prAisFsmInfo->ucScanSSIDLen); ++ } ++ } else { ++ /* Scan for determined SSID */ ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ COPY_SSID(prScanReqMsg->aucSSID, ++ prScanReqMsg->ucSSIDLength, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ } ++ ++ /* check if tethering is running and need to fix on specific channel */ ++ if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ prScanReqMsg->ucChannelListNum = 1; ++ prScanReqMsg->arChnlInfoList[0].eBand = eBand; ++ prScanReqMsg->arChnlInfoList[0].ucChannelNum = ucChannel; ++ } else { ++#if 0 ++ aisFsmSetChannelInfo(prAdapter, prScanReqMsg, prAisFsmInfo->eCurrentState); ++#endif ++ if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_NULL) { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ else ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_2G4) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_5G) { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ } else { ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ ASSERT(0); ++ } ++ ++ } ++ ++ if (prAisFsmInfo->u4ScanIELength > 0) { ++ kalMemCopy(prScanReqMsg->aucIE, prAisFsmInfo->aucScanIEBuf, ++ prAisFsmInfo->u4ScanIELength); ++ } else { ++#if CFG_SUPPORT_WPS2 ++ if (prAdapter->prGlueInfo->u2WSCIELen > 0) { ++ kalMemCopy(prScanReqMsg->aucIE, &prAdapter->prGlueInfo->aucWSCIE, ++ prAdapter->prGlueInfo->u2WSCIELen); ++ } ++ } ++#endif ++ ++ prScanReqMsg->u2IELen = u2ScanIELen; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ DBGLOG(AIS, TRACE, "SendSR%d\n", prScanReqMsg->ucSeqNum); ++ prAisFsmInfo->fgTryScan = FALSE; /* Will enable background sleep for infrastructure */ ++ ++ prAdapter->ucScanTime++; ++ break; ++ ++ case AIS_STATE_REQ_CHANNEL_JOIN: ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ prMsgChReq->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ ++ if (prAisFsmInfo->prTargetBssDesc != NULL) { ++ prMsgChReq->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; ++ prMsgChReq->eRfSco = prAisFsmInfo->prTargetBssDesc->eSco; ++ prMsgChReq->eRfBand = prAisFsmInfo->prTargetBssDesc->eBand; ++ COPY_MAC_ADDR(prMsgChReq->aucBSSID, prAisFsmInfo->prTargetBssDesc->aucBSSID); ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prAisFsmInfo->fgIsChannelRequested = TRUE; ++ break; ++ ++ case AIS_STATE_JOIN: ++ aisFsmStateInit_JOIN(prAdapter, prAisFsmInfo->prTargetBssDesc); ++ break; ++ ++#if CFG_SUPPORT_ADHOC ++ case AIS_STATE_IBSS_ALONE: ++ aisFsmStateInit_IBSS_ALONE(prAdapter); ++ break; ++ ++ case AIS_STATE_IBSS_MERGE: ++ aisFsmStateInit_IBSS_MERGE(prAdapter, prAisFsmInfo->prTargetBssDesc); ++ break; ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ case AIS_STATE_NORMAL_TR: ++ if (prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { ++ /* Don't do anything when rJoinTimeoutTimer is still ticking */ ++ } else { ++ /* 1. Process for pending scan */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_ONLINE_SCAN; ++ fgIsTransition = TRUE; ++ } ++ /* 2. Process for pending roaming scan */ ++ else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE) == TRUE) { ++ eNextState = AIS_STATE_LOOKING_FOR; ++ fgIsTransition = TRUE; ++ } ++ /* 3. Process for pending roaming scan */ ++ else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE) == TRUE) { ++ eNextState = AIS_STATE_SEARCH; ++ fgIsTransition = TRUE; ++ } else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE) == ++ TRUE) { ++ eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ break; ++ ++ case AIS_STATE_DISCONNECTING: ++ /* send for deauth frame for disconnection */ ++ authSendDeauthFrame(prAdapter, ++ prAisBssInfo->prStaRecOfAP, ++ (P_SW_RFB_T) NULL, REASON_CODE_DEAUTH_LEAVING_BSS, aisDeauthXmitComplete); ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer, 100); ++ break; ++ ++ case AIS_STATE_REQ_REMAIN_ON_CHANNEL: ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ return; ++ } ++ ++ /* zero-ize */ ++ kalMemZero(prMsgChReq, sizeof(MSG_CH_REQ_T)); ++ ++ /* filling */ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ prMsgChReq->u4MaxInterval = prAisFsmInfo->rChReqInfo.u4DurationMs; ++ prMsgChReq->ucPrimaryChannel = prAisFsmInfo->rChReqInfo.ucChannelNum; ++ prMsgChReq->eRfSco = prAisFsmInfo->rChReqInfo.eSco; ++ prMsgChReq->eRfBand = prAisFsmInfo->rChReqInfo.eBand; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prAisFsmInfo->fgIsChannelRequested = TRUE; ++ ++ break; ++ ++ case AIS_STATE_REMAIN_ON_CHANNEL: ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ /* sync with firmware */ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ break; ++ ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ break; ++ ++ } ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of aisFsmSteps() */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState) ++{ ++ /*get scan channel infro from prAdapter->prGlueInfo->prScanRequest*/ ++ struct cfg80211_scan_request *scan_req_t = NULL; ++ struct ieee80211_channel *channel_tmp = NULL; ++ int i = 0; ++ int j = 0; ++ UINT_8 channel_num = 0; ++ UINT_8 channel_counts = 0; ++ ++ if ((prAdapter == NULL) || (ScanReqMsg == NULL)) ++ return; ++ if ((CurrentState == AIS_STATE_SCAN) || (CurrentState == AIS_STATE_ONLINE_SCAN)) { ++ if (prAdapter->prGlueInfo->prScanRequest != NULL) { ++ scan_req_t = prAdapter->prGlueInfo->prScanRequest; ++ if ((scan_req_t != NULL) && (scan_req_t->n_channels != 0) && ++ (scan_req_t->channels != NULL)) { ++ channel_counts = scan_req_t->n_channels; ++ DBGLOG(AIS, TRACE, "channel_counts=%d\n", channel_counts); ++ ++ while (j < channel_counts) { ++ channel_tmp = scan_req_t->channels[j]; ++ if (channel_tmp == NULL) ++ break; ++ ++ DBGLOG(AIS, TRACE, "set channel band=%d\n", channel_tmp->band); ++ if (channel_tmp->band >= IEEE80211_BAND_60GHZ) { ++ j++; ++ continue; ++ } ++ if (i >= MAXIMUM_OPERATION_CHANNEL_LIST) ++ break; ++ if (channel_tmp->band == IEEE80211_BAND_2GHZ) ++ ScanReqMsg->arChnlInfoList[i].eBand = BAND_2G4; ++ else if (channel_tmp->band == IEEE80211_BAND_5GHZ) ++ ScanReqMsg->arChnlInfoList[i].eBand = BAND_5G; ++ ++ DBGLOG(AIS, TRACE, "set channel channel_rer =%d\n", ++ channel_tmp->center_freq); ++ ++ channel_num = (UINT_8)nicFreq2ChannelNum( ++ channel_tmp->center_freq * 1000); ++ ++ DBGLOG(AIS, TRACE, "set channel channel_num=%d\n", ++ channel_num); ++ ScanReqMsg->arChnlInfoList[i].ucChannelNum = channel_num; ++ ++ j++; ++ i++; ++ } ++ } ++ } ++ } ++ ++ DBGLOG(AIS, INFO, "set channel i=%d\n", i); ++ if (i > 0) { ++ ScanReqMsg->ucChannelListNum = i; ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; ++ ++ return; ++ } ++ ++ if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_NULL) { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ else ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_2G4) { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] ++ == BAND_5G) { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; ++ } else { ++ ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; ++ ASSERT(0); ++ } ++ ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ UINT_8 ucSeqNumOfCompMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventScanDone()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ ucScanTimeoutTimes = 0; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ ASSERT(prScanDoneMsg->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ if (ucSeqNumOfCompMsg != prAisFsmInfo->ucSeqNumOfScanReq) { ++ DBGLOG(AIS, WARN, "SEQ NO of AIS SCN DONE MSG is not matched %d %d.\n", ++ ucSeqNumOfCompMsg, prAisFsmInfo->ucSeqNumOfScanReq); ++ } else { ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_SCAN: ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++ ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++ eNextState = AIS_STATE_IDLE; ++#if CFG_SUPPORT_AGPS_ASSIST ++ scanReportScanResultToAgps(prAdapter); ++#endif ++ break; ++ ++ case AIS_STATE_ONLINE_SCAN: ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++ ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_NORMAL_TR; ++#endif /* CFG_SUPPORT_ROAMING */ ++#if CFG_SUPPORT_AGPS_ASSIST ++ scanReportScanResultToAgps(prAdapter); ++#endif ++ break; ++ ++ case AIS_STATE_LOOKING_FOR: ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ scanReportBss2Cfg80211(prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_SEARCH; ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ ++ default: ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ break; ++ ++ } ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventScanDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ UINT_8 ucReasonOfDisconnect; ++ BOOLEAN fgDelayIndication; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventAbort()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Extract information of Abort Message and then free memory. */ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) prMsgHdr; ++ ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; ++ fgDelayIndication = prAisAbortMsg->fgDelayIndication; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if DBG ++ DBGLOG(AIS, STATE, "EVENT-ABORT: Current State %s %d\n", ++ apucDebugAisState[prAisFsmInfo->eCurrentState], ucReasonOfDisconnect); ++#else ++ DBGLOG(AIS, STATE, "[%d] EVENT-ABORT: Current State [%d %d]\n", ++ DBG_AIS_IDX, prAisFsmInfo->eCurrentState, ucReasonOfDisconnect); ++#endif ++ ++ GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); ++ ++ /* 4 <2> clear previous pending connection request and insert new one */ ++ if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DEAUTHENTICATED ++ || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DISASSOCIATED) { ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++ } else { ++ prConnSettings->fgIsDisconnectedByNonRequest = FALSE; ++ } ++ /* to support user space triggered roaming */ ++ if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_ROAMING && ++ prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && ++ prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { ++ aisFsmSteps(prAdapter, AIS_STATE_SEARCH); ++ } else { ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_ROAMING_CONNECT); ++ } ++ return; ++ } ++ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ if (prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { ++ /* 4 <3> invoke abort handler */ ++ aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, fgDelayIndication); ++ } ++ ++} /* end of aisFsmRunEventAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handles AIS-FSM abort event/command ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ucReasonOfDisconnect Reason for disonnection ++* fgDelayIndication Option to delay disconnection indication ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ BOOLEAN fgIsCheckConnected; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ fgIsCheckConnected = FALSE; ++ ++ /* 4 <1> Save information of Abort Message and then free memory. */ ++ prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; ++ ++ /* 4 <2> Abort current job. */ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IDLE: ++ case AIS_STATE_SEARCH: ++ break; ++ ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ /* Do cancel timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_SCAN: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* queue for later handling */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ ++ break; ++ ++ case AIS_STATE_LOOKING_FOR: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_REQ_CHANNEL_JOIN: ++ /* Release channel to CNM */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_JOIN: ++ /* Do abort JOIN */ ++ aisFsmStateAbort_JOIN(prAdapter); ++ ++ /* in case roaming is triggered */ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++#if CFG_SUPPORT_ADHOC ++ case AIS_STATE_IBSS_ALONE: ++ case AIS_STATE_IBSS_MERGE: ++ aisFsmStateAbort_IBSS(prAdapter); ++ break; ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ case AIS_STATE_ONLINE_SCAN: ++ /* Do abort SCAN */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* queue for later handling */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ fgIsCheckConnected = TRUE; ++ break; ++ ++ case AIS_STATE_DISCONNECTING: ++ /* Do abort NORMAL_TR */ ++ aisFsmStateAbort_NORMAL_TR(prAdapter); ++ ++ break; ++ ++ case AIS_STATE_REQ_REMAIN_ON_CHANNEL: ++ /* release channel */ ++ aisFsmReleaseCh(prAdapter); ++ break; ++ ++ case AIS_STATE_REMAIN_ON_CHANNEL: ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2. stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (fgIsCheckConnected && (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState)) { ++ ++ /* switch into DISCONNECTING state for sending DEAUTH if necessary */ ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && ++ prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_NEW_CONNECTION && ++ prAisBssInfo->prStaRecOfAP && prAisBssInfo->prStaRecOfAP->fgIsInUse) { ++ aisFsmSteps(prAdapter, AIS_STATE_DISCONNECTING); ++ ++ return; ++ } ++ /* Do abort NORMAL_TR */ ++ aisFsmStateAbort_NORMAL_TR(prAdapter); ++ ++ } ++ ++ aisFsmDisconnect(prAdapter, fgDelayIndication); ++ ++ ++} /* end of aisFsmStateAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Join Complete Event from SAA FSM for AIS FSM ++* ++* @param[in] prMsgHdr Message of Join Complete of SAA FSM. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_JOIN_COMP_T prJoinCompMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prAssocRspSwRfb; ++ P_BSS_INFO_T prAisBssInfo; ++ UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; ++ OS_SYSTIME rCurrentTime; ++ ++ DEBUGFUNC("aisFsmRunEventJoinComplete()"); ++ ++ ASSERT(prMsgHdr); ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prStaRec = prJoinCompMsg->prStaRec; ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ DBGLOG(AIS, TRACE, "AISOK\n"); ++ ++ /* Check State and SEQ NUM */ ++ do { ++ if (prAisFsmInfo->eCurrentState != AIS_STATE_JOIN) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prAisFsmInfo->ucSeqNumOfReqMsg) { ++ ++ /* 4 <1> JOIN was successful */ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ ++ /* 1. Reset retry count */ ++ prAisFsmInfo->ucConnTrialCount = 0; ++ ++ /* Completion of roaming */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ ++#if CFG_SUPPORT_ROAMING ++ /* 2. Deactivate previous BSS */ ++ aisFsmRoamingDisconnectPrevAP(prAdapter, prStaRec); ++ ++ /* 3. Update bss based on roaming staRec */ ++ aisUpdateBssInfoForRoamingAP(prAdapter, prStaRec, prAssocRspSwRfb); ++#endif /* CFG_SUPPORT_ROAMING */ ++ } else { ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prAisBssInfo->prStaRecOfAP) && ++ (prAisBssInfo->prStaRecOfAP != prStaRec) && ++ (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { ++ ++ cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, ++ STA_STATE_1); ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /* 4 <1.5> Update RSSI if necessary */ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_AIS_INDEX, ++ (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. */ ++ /* from AIS_BSS_INFO_T */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, ++ FALSE); ++ ++ /* add for ctia mode */ ++ if (EQUAL_SSID ++ (aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen)) { ++ nicEnterCtiaMode(prAdapter, TRUE, FALSE); ++ } ++ } ++ ++#if CFG_SUPPORT_ROAMING ++ /* if bssid is given, it means we no need fw roaming */ ++ if (prAdapter->rWifiVar.rConnSettings.eConnectionPolicy != CONNECT_BY_BSSID) ++ roamingFsmRunEventStart(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* 4 <1.7> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ } ++ /* 4 <2> JOIN was not successful */ ++ else { ++ /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ ++ if (aisFsmStateInit_RetryJOIN(prAdapter, prStaRec) == FALSE) { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* 1. Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* 2. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 3.1 stop join timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); ++ ++ /* 3.2 reset local variable */ ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prStaRec->aucMacAddr); ++ ++ if (prBssDesc == NULL) { ++ /* it maybe NULL when wlanRemove */ ++ /* ++ (1) UI does wifi off during SAA does auth/assoc procedure. ++ (2) We will do LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ in nicUninitMGMT(). ++ (3) We will handle prMsduInfo->pfTxDoneHandler ++ in nicTxRelease(). ++ (4) prMsduInfo->pfTxDoneHandler will point to ++ saaFsmRunEventTxDone(). ++ (5) Then jump to saaFsmSteps() -> saaFsmSendEventJoinComplete() ++ (6) Finally mboxSendMsg() -> aisFsmRunEventJoinComplete(). ++ (7) In aisFsmRunEventJoinComplete(), we will check ++ "prBssDesc = scanSearchBssDescByBssid(prAdapter, ++ prStaRec->aucMacAddr);" ++ (8) And prBssDesc will be NULL and hangs in ++ "ASSERT(prBssDesc->fgIsConnecting);" when DBG=0. ++ ASSERT(prBssDesc); ++ ASSERT(prBssDesc->fgIsConnecting); ++ */ ++ break; ++ } ++ /* ASSERT(prBssDesc); */ ++ /* ASSERT(prBssDesc->fgIsConnecting); */ ++ prBssDesc->ucJoinFailureCount++; ++ if (prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { ++ GET_CURRENT_SYSTIME(&prBssDesc->rJoinFailTime); ++ DBGLOG(AIS, INFO, ++ "Bss %pM join fail %d times,temp disable it at time:%u\n", ++ prBssDesc->aucBSSID, ++ SCN_BSS_JOIN_FAIL_THRESOLD, prBssDesc->rJoinFailTime); ++ } ++ ++ if (prBssDesc) ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ /* 3.3 Free STA-REC */ ++ if (prStaRec != prAisBssInfo->prStaRecOfAP) ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++#if CFG_SUPPORT_ROAMING ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++#endif /* CFG_SUPPORT_ROAMING */ ++ } else if (CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, ++ SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { ++ /* abort connection trial */ ++ prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_CONNECT_INDICATION, NULL, 0); ++ ++ eNextState = AIS_STATE_IDLE; ++ } else { ++ /* 4.b send reconnect request */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ ++ eNextState = AIS_STATE_IDLE; ++ } ++ } ++ } ++ } ++#if DBG ++ else ++ DBGLOG(AIS, WARN, "SEQ NO of AIS JOIN COMP MSG is not matched.\n"); ++#endif /* DBG */ ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ } while (FALSE); ++ ++ if (prAssocRspSwRfb) ++ nicRxReturnRFB(prAdapter, prAssocRspSwRfb); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of aisFsmRunEventJoinComplete() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Grant Msg of IBSS Create which was sent by ++* CNM to indicate that channel was changed for creating IBSS. ++* ++* @param[in] prAdapter Pointer of ADAPTER_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ do { ++ /* Check State */ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_IBSS_ALONE) ++ aisUpdateBssInfoForCreateIBSS(prAdapter); ++ } while (FALSE); ++ ++} /* end of aisFsmCreateIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Grant Msg of IBSS Merge which was sent by ++* CNM to indicate that channel was changed for merging IBSS. ++* ++* @param[in] prAdapter Pointer of ADAPTER_T ++* @param[in] prStaRec Pointer of STA_RECORD_T for merge ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ do { ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_MERGE: ++ { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous Peers' STA_RECORD_T in Driver if have. */ ++ bssClearClientList(prAdapter, prAisBssInfo); ++ ++ /* 4 <1.3> Unmark connection flag of previous BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = FALSE; ++ } ++ /* 4 <1.4> Update BSS_INFO_T */ ++ aisUpdateBssInfoForMergeIBSS(prAdapter, prStaRec); ++ ++ /* 4 <1.5> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++ /* 4 <1.6> Activate current Peer's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ /* 4 <1.7> Enable other features */ ++ ++ /* 4 <1.8> Indicate Connected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++ /* 4 <1.9> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ ++ /* 4 <1.10> Release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ ++#if CFG_SLT_SUPPORT ++ prAdapter->rWifiVar.rSltInfo.prPseudoStaRec = prStaRec; ++#endif ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++ } while (FALSE); ++ ++} /* end of aisFsmMergeIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Notification of existing IBSS was found ++* from SCN. ++* ++* @param[in] prMsgHdr Message of Notification of an IBSS was present. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prAisBssInfo; ++ P_BSS_DESC_T prBssDesc; ++ BOOLEAN fgIsMergeIn; ++ ++ ASSERT(prMsgHdr); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) prMsgHdr; ++ ++ ASSERT(prAisIbssPeerFoundMsg->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX); ++ ++ prStaRec = prAisIbssPeerFoundMsg->prStaRec; ++ ASSERT(prStaRec); ++ ++ fgIsMergeIn = prAisIbssPeerFoundMsg->fgIsMergeIn; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_ALONE: ++ { ++ /* 4 <1> An IBSS Peer 'merged in'. */ ++ if (fgIsMergeIn) { ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++#if CFG_SLT_SUPPORT ++ /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ } else { ++ ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ ++ } ++ ++ /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ ++#else ++ /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc != NULL) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ } else { ++ ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ ++ } ++ ++ /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ ++ ++#endif ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ /* 4 <1.6> sync. to firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <1.7> Indicate Connected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++ /* 4 <1.8> indicate PM for connected */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <1.9> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_NORMAL_TR; ++ ++ /* 4 <1.10> Release channel privilege */ ++ aisFsmReleaseCh(prAdapter); ++ } ++ /* 4 <2> We need 'merge out' to this IBSS */ ++ else { ++ ++ /* 4 <2.1> Get corresponding BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* 4 <2.2> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ } ++ } ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ { ++ ++ /* 4 <3> An IBSS Peer 'merged in'. */ ++ if (fgIsMergeIn) { ++ ++ /* 4 <3.1> Add Peers' STA_RECORD_T to Client List */ ++ bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); ++ ++#if CFG_SLT_SUPPORT ++ /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ ++#else ++ /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ ++ prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ ++#endif ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ prStaRec->fgIsMerging = FALSE; ++ ++ } ++ /* 4 <4> We need 'merge out' to this IBSS */ ++ else { ++ ++ /* 4 <4.1> Get corresponding BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ ++ prAisFsmInfo->prTargetBssDesc = prBssDesc; ++ ++ /* 4 <4.2> Set the Next State of AIS FSM */ ++ eNextState = AIS_STATE_IBSS_MERGE; ++ ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventFoundIBSSPeer() */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Media State to HOST ++* ++* @param[in] eConnectionState Current Media State ++* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, ++ ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication) ++{ ++ EVENT_CONNECTION_STATUS rEventConnStatus; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ DEBUGFUNC("aisIndicationOfMediaStateToHost()"); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* NOTE(Kevin): Move following line to aisChangeMediaState() macro per CM's request. */ ++ /* prAisBssInfo->eConnectionState = eConnectionState; */ ++ ++ /* For indicating the Disconnect Event only if current media state is ++ * disconnected and we didn't do indication yet. ++ */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ if (prAisBssInfo->eConnectionStateIndicated == eConnectionState) ++ return; ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <0> Cancel Delay Timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); ++ ++ /* 4 <1> Fill EVENT_CONNECTION_STATUS */ ++ rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; ++ ++ if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; ++ rEventConnStatus.u2AID = prAisBssInfo->u2AssocId; ++ rEventConnStatus.u2ATIMWindow = 0; ++ } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; ++ rEventConnStatus.u2AID = 0; ++ rEventConnStatus.u2ATIMWindow = prAisBssInfo->u2ATIMWindow; ++ } else { ++ ASSERT(0); ++ } ++ ++ COPY_SSID(rEventConnStatus.aucSsid, ++ rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ COPY_MAC_ADDR(rEventConnStatus.aucBssid, prAisBssInfo->aucBSSID); ++ ++ rEventConnStatus.u2BeaconPeriod = prAisBssInfo->u2BeaconInterval; ++ rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prAisBssInfo->ucPrimaryChannel); ++ ++ switch (prAisBssInfo->ucNonHTBasicPhyType) { ++ case PHY_TYPE_HR_DSSS_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ ++ case PHY_TYPE_ERP_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; ++ break; ++ ++ case PHY_TYPE_OFDM_INDEX: ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; ++ break; ++ ++ default: ++ ASSERT(0); ++ rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; ++ break; ++ } ++ } else { ++ /* Deactivate previous Peers' STA_RECORD_T in Driver if have. */ ++ bssClearClientList(prAdapter, prAisBssInfo); ++ ++#if CFG_PRIVACY_MIGRATION ++ /* Clear the pmkid cache while media disconnect */ ++ secClearPmkid(prAdapter); ++#endif ++ ++ rEventConnStatus.ucReasonOfDisconnect = prAisBssInfo->ucReasonOfDisconnect; ++ } ++ ++ /* 4 <2> Indication */ ++ nicMediaStateChange(prAdapter, NETWORK_TYPE_AIS_INDEX, &rEventConnStatus); ++ prAisBssInfo->eConnectionStateIndicated = eConnectionState; ++ } else { ++ /* NOTE: Only delay the Indication of Disconnect Event */ ++ ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ DBGLOG(AIS, INFO, "Postpone the indication of Disconnect for %d seconds\n", ++ prConnSettings->ucDelayTimeOfDisconnectEvent); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rIndicationOfDisconnectTimer, ++ SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); ++ } ++ ++} /* end of aisIndicationOfMediaStateToHost() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Media Disconnect" to HOST ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if (prAisBssInfo->prStaRecOfAP) { ++ /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ ++ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ } ++ /* 4 <2> Remove pending connection request */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++ prAisBssInfo->u2DeauthReason = REASON_CODE_BEACON_TIMEOUT; ++ /* 4 <3> Indicate Disconnected Event to Host immediately. */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, FALSE); ++ ++} /* end of aisPostponedEventOfDisconnTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the association was completed. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ P_BSS_DESC_T prBssDesc; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ DEBUGFUNC("aisUpdateBssInfoForJOIN()"); ++ ++ ASSERT(prStaRec); ++ ASSERT(prAssocRspSwRfb); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ ++ DBGLOG(AIS, TRACE, "Update AIS_BSS_INFO_T and apply settings to MAC\n"); ++ ++ /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Setup Channel, Band */ ++ prAisBssInfo->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; ++ prAisBssInfo->eBand = prAisFsmInfo->prTargetBssDesc->eBand; ++ ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = prStaRec; ++ prAisBssInfo->u2AssocId = prStaRec->u2AssocId; ++ ++ /* 4 <2.2> Setup Capability */ ++ prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) ++ prAisBssInfo->fgIsShortPreambleAllowed = TRUE; ++ else ++ prAisBssInfo->fgIsShortPreambleAllowed = FALSE; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* init the TDLS flags */ ++ prAisBssInfo->fgTdlsIsProhibited = prStaRec->fgTdlsIsProhibited; ++ prAisBssInfo->fgTdlsIsChSwProhibited = prStaRec->fgTdlsIsChSwProhibited; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ /* 4 <3.1> Setup BSSID */ ++ COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ /* 4 <3.2> Parse WMM and setup QBSS flag */ ++ /* Parse WMM related IEs and configure HW CRs accordingly */ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ prAisBssInfo->fgIsQBSS = prStaRec->fgIsQoS; ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAssocRspFrame->aucBSSID); ++ if (prBssDesc) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ prBssDesc->ucJoinFailureCount = 0; ++ ++ /* 4 <4.1> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ } else { ++ /* should never happen */ ++ ASSERT(0); ++ } ++ ++ /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = 0; ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; ++ ++ /* 4 <4.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.3> Sync with firmware for BSS-INFO */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ ++ /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ ++ ++} /* end of aisUpdateBssInfoForJOIN() */ ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will create an Ad-Hoc network and start sending Beacon Frames. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (prAisBssInfo->fgIsBeaconActivated) ++ return; ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prAisBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.4> Setup Channel, Band and Phy Attributes */ ++ prAisBssInfo->ucPrimaryChannel = prConnSettings->ucAdHocChannelNum; ++ prAisBssInfo->eBand = prConnSettings->eAdHocBand; ++ ++ if (prAisBssInfo->eBand == BAND_2G4) { ++ /* Depend on eBand */ ++ prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_MIXED_11BG; ++ } else { ++ /* Depend on eBand */ ++ prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN; ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_11A; ++ } ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prConnSettings->u2BeaconPeriod; ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = prConnSettings->u2AtimWindow; ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; ++ ++#if CFG_PRIVACY_MIGRATION ++ if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED || ++ prConnSettings->eEncStatus == ENUM_ENCRYPTION2_ENABLED || ++ prConnSettings->eEncStatus == ENUM_ENCRYPTION3_ENABLED) { ++ prAisBssInfo->fgIsProtection = TRUE; ++ } else { ++ prAisBssInfo->fgIsProtection = FALSE; ++ } ++#else ++ prAisBssInfo->fgIsProtection = FALSE; ++#endif ++ ++ /* 3 <2> Update BSS_INFO_T common part */ ++ ibssInitForAdHoc(prAdapter, prAisBssInfo); ++ ++ /* 3 <3> Set MAC HW */ ++ /* 4 <3.1> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); ++ ++ /* 4 <3.2> use command packets to inform firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <3.3> enable beaconing */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <3.4> Update AdHoc PM parameter */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 3 <4> Set ACTIVE flag. */ ++ prAisBssInfo->fgIsBeaconActivated = TRUE; ++ prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; ++ ++ /* 3 <5> Start IBSS Alone Timer */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); ++ ++ return; ++ ++} /* end of aisCreateIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the existing IBSS was found. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc; ++ /* UINT_16 u2IELength; */ ++ /* PUINT_8 pucIE; */ ++ ++ ASSERT(prStaRec); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); ++ ++ if (!prAisBssInfo->fgIsBeaconActivated) { ++ ++ /* 3 <1> Update BSS_INFO_T per Network Basis */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prAisBssInfo->u2AssocId = 0; ++ } ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Setup Capability */ ++ prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use Peer's Cap Info as IBSS Cap Info */ ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { ++ prAisBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prAisBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prAisBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prAisBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ ++ prAisBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ ++ prAisBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; ++ ++ if (prAisBssInfo->u2CapInfo & CAP_INFO_PRIVACY) ++ prAisBssInfo->fgIsProtection = TRUE; ++ else ++ prAisBssInfo->fgIsProtection = FALSE; ++ ++ /* 4 <2.2> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ rateGetDataRatesFromRateSet(prAisBssInfo->u2OperationalRateSet, ++ prAisBssInfo->u2BSSBasicRateSet, ++ prAisBssInfo->aucAllSupportedRates, &prAisBssInfo->ucAllSupportedRatesLen); ++ ++ /* 3 <3> X Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); ++ if (prBssDesc) { ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <4.1> Setup BSSID */ ++ COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ /* 4 <4.2> Setup Channel, Band */ ++ prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; ++ prAisBssInfo->eBand = prBssDesc->eBand; ++ ++ /* 4 <4.3> Setup MIB for current BSS */ ++ prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ prAisBssInfo->ucDTIMPeriod = 0; ++ prAisBssInfo->u2ATIMWindow = 0; /* TBD(Kevin) */ ++ ++ prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; ++ } else { ++ /* should never happen */ ++ ASSERT(0); ++ } ++ ++ /* 3 <5> Set MAC HW */ ++ /* 4 <5.1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ { ++ UINT_8 ucLowestBasicRateIndex; ++ ++ if (!rateGetLowestRateIndexFromRateSet(prAisBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex)) { ++ ++ if (prAisBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_OFDM) ++ ucLowestBasicRateIndex = RATE_6M_INDEX; ++ else ++ ucLowestBasicRateIndex = RATE_1M_INDEX; ++ } ++ ++ prAisBssInfo->ucHwDefaultFixedRateCode = ++ aucRateIndex2RateCode[prAisBssInfo->fgUseShortPreamble][ucLowestBasicRateIndex]; ++ } ++ ++ /* 4 <5.2> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); ++ ++ /* 4 <5.3> use command packets to inform firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <5.4> enable beaconing */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 4 <5.5> Update AdHoc PM parameter */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* 3 <6> Set ACTIVE flag. */ ++ prAisBssInfo->fgIsBeaconActivated = TRUE; ++ prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; ++ ++} /* end of aisUpdateBssInfoForMergeIBSS() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ BOOLEAN fgReplyProbeResp = FALSE; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu4ControlFlags); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) prSwRfb->pvHeader + prSwRfb->u2HeaderLen; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_SSID == IE_ID(pucIE)) { ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions */ ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ ++ if ((prIeSsid) && ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, /* CURRENT SSID */ ++ prIeSsid->aucSSID, prIeSsid->ucLength))) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++ ++ return fgReplyProbeResp; ++ ++} /* end of aisValidateProbeReq() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will modify and update necessary information to firmware ++* for disconnection handling ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++#if CFG_SUPPORT_ADHOC ++ if (prAisBssInfo->fgIsBeaconActivated) { ++ nicUpdateBeaconIETemplate(prAdapter, IE_UPD_METHOD_DELETE_ALL, NETWORK_TYPE_AIS_INDEX, 0, NULL, 0); ++ ++ prAisBssInfo->fgIsBeaconActivated = FALSE; ++ } ++#endif ++ ++ rlmBssAborted(prAdapter, prAisBssInfo); ++ ++ /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { ++ /* add for ctia mode */ ++ { ++ UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; ++ ++ if (EQUAL_SSID(aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) ++ nicEnterCtiaMode(prAdapter, FALSE, FALSE); ++ } ++ ++ if (prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_RADIO_LOST) { ++ scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* remove from scanning results as well */ ++ wlanClearBssInScanningResult(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* trials for re-association */ ++ if (fgDelayIndication) { ++ DBGLOG(AIS, INFO, "try to do re-association due to radio lost!\n"); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); ++ } ++ } else { ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ } ++ ++ if (fgDelayIndication) { ++ if (OP_MODE_IBSS != prAisBssInfo->eCurrentOPMode) ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } else { ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } ++ } else { ++ prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; ++ } ++ ++ /* 4 <4> Change Media State immediately. */ ++ if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION) { ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ /* 4 <4.1> sync. with firmware */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ ++ if (!fgDelayIndication) { ++ /* 4 <5> Deactivate previous AP's STA_RECORD_T or all Clients in Driver if have. */ ++ if (prAisBssInfo->prStaRecOfAP) { ++ /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ ++ ++ prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ } ++ } ++#if CFG_SUPPORT_ROAMING ++ roamingFsmRunEventAbort(prAdapter); ++ ++ /* clear pending roaming connection request */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* 4 <6> Indicate Disconnected Event to Host */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, fgDelayIndication); ++ ++ /* 4 <7> Trigger AIS FSM */ ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ ++} /* end of aisFsmDisconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of Scan done Time-Out to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 IsrCnt = 0, IsrPassCnt = 0, TaskIsrCnt = 0; ++VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++#define SCAN_DONE_TIMEOUT_TIMES_LIMIT 20 ++ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4FwCnt; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("aisFsmRunEventScanDoneTimeOut()"); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ ++ DBGLOG(AIS, WARN, "aisFsmRunEventScanDoneTimeOut Current[%d], ucScanTimeoutTimes=%d\n", ++ prAisFsmInfo->eCurrentState, ucScanTimeoutTimes); ++ DBGLOG(AIS, WARN, "Isr/task %u %u %u (0x%x)\n", prGlueInfo->IsrCnt, prGlueInfo->IsrPassCnt, ++ prGlueInfo->TaskIsrCnt, prAdapter->fgIsIntEnable); ++ ++ /* dump firmware program counter */ ++ DBGLOG(AIS, WARN, "CONNSYS FW CPUINFO:\n"); ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(AIS, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ ++ ucScanTimeoutTimes++; ++ if (ucScanTimeoutTimes > SCAN_DONE_TIMEOUT_TIMES_LIMIT) { ++ kalSendAeeWarning("[Scan done timeout more than 20 times!]", __func__); ++ glDoChipReset(); ++ } ++#if 0 /* ALPS02018734: remove trigger assert */ ++ if (prAdapter->fgTestMode == FALSE) { ++ /* Titus - xxx */ ++ /* assert if and only if in normal mode */ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); ++ } ++#endif ++ /* report all scanned frames to upper layer to avoid scanned frame is timeout */ ++ /* must be put before kalScanDone */ ++/* scanReportBss2Cfg80211(prAdapter,BSS_TYPE_INFRASTRUCTURE,NULL); */ ++ ++ prConnSettings->fgIsScanReqIssued = FALSE; ++ kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_SCAN: ++ prAisFsmInfo->u4ScanIELength = 0; ++ eNextState = AIS_STATE_IDLE; ++ break; ++ case AIS_STATE_ONLINE_SCAN: ++ /* reset scan IE buffer */ ++ prAisFsmInfo->u4ScanIELength = 0; ++#if CFG_SUPPORT_ROAMING ++ eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); ++#else ++ eNextState = AIS_STATE_NORMAL_TR; ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ default: ++ break; ++ } ++ ++ /* try to stop scan in CONNSYS */ ++ aisFsmStateAbort_SCAN(prAdapter); ++ ++ /* wlanQueryDebugCode(prAdapter); */ /* display current SCAN FSM in FW, debug use */ ++ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmBGSleepTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Background Scan Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DEBUGFUNC("aisFsmRunEventBGSleepTimeOut()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_WAIT_FOR_NEXT_SCAN: ++ DBGLOG(AIS, LOUD, "EVENT - SCAN TIMER: Idle End - Current Time = %u\n", kalGetTimeTick()); ++ ++ eNextState = AIS_STATE_LOOKING_FOR; ++ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmBGSleepTimeout() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "IBSS ALONE Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DEBUGFUNC("aisFsmRunEventIbssAloneTimeOut()"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_IBSS_ALONE: ++ ++ /* There is no one participate in our AdHoc during this TIMEOUT Interval ++ * so go back to search for a valid IBSS again. ++ */ ++ ++ DBGLOG(AIS, LOUD, "EVENT-IBSS ALONE TIMER: Start pairing\n"); ++ ++ prAisFsmInfo->fgTryScan = TRUE; ++ ++ /* abort timer */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* Pull back to SEARCH to find candidate again */ ++ eNextState = AIS_STATE_SEARCH; ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisIbssAloneTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Join Time-Out" to AIS FSM. ++* ++* @param[in] u4Param Unused timer parameter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ OS_SYSTIME rCurrentTime; ++ ++ DEBUGFUNC("aisFsmRunEventJoinTimeout()"); ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ eNextState = prAisFsmInfo->eCurrentState; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ switch (prAisFsmInfo->eCurrentState) { ++ case AIS_STATE_JOIN: ++ DBGLOG(AIS, LOUD, "EVENT- JOIN TIMEOUT\n"); ++ ++ /* 1. Do abort JOIN */ ++ aisFsmStateAbort_JOIN(prAdapter); ++ ++ /* 2. Increase Join Failure Count */ ++ prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount++; ++/* For JB nl802.11 */ ++ if (prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) { ++ /* 3.1 Retreat to AIS_STATE_SEARCH state for next try */ ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* 3.2 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ } else if (!CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, ++ SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { ++ /* 3.3 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ ++ eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; ++ } else { ++ /* 3.4 Retreat to AIS_STATE_JOIN_FAILURE to terminate join operation */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_CONNECT_INDICATION, NULL, 0); ++ eNextState = AIS_STATE_IDLE; ++ } ++ break; ++ ++ case AIS_STATE_NORMAL_TR: ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ prAisFsmInfo->fgIsInfraChannelFinished = TRUE; ++ ++ /* 2. process if there is pending scan */ ++ if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { ++ wlanClearScanningResult(prAdapter); ++ eNextState = AIS_STATE_ONLINE_SCAN; ++ } ++ ++ break; ++ ++ default: ++ /* release channel */ ++ aisFsmReleaseCh(prAdapter); ++ break; ++ ++ } ++ ++ /* Call aisFsmSteps() when we are going to change AIS STATE */ ++ if (eNextState != prAisFsmInfo->eCurrentState) ++ aisFsmSteps(prAdapter, eNextState); ++ ++} /* end of aisFsmRunEventJoinTimeout() */ ++ ++VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ aisDeauthXmitComplete(prAdapter, NULL, TX_RESULT_LIFE_TIMEOUT); ++} ++ ++#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisTest(VOID) ++{ ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucSSID[] = "pci-11n"; ++ UINT_8 ucSSIDLen = 7; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* Set Connection Request Issued Flag */ ++ prConnSettings->fgIsConnReqIssued = TRUE; ++ prConnSettings->ucSSIDLen = ucSSIDLen; ++ kalMemCopy(prConnSettings->aucSSID, aucSSID, ucSSIDLen); ++ ++ prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) { ++ ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ return; ++ } ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_HEM_AIS_FSM_ABORT; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ wifi_send_msg(INDX_WIFI, MSG_ID_WIFI_IST, 0); ++ ++} ++#endif /* CFG_TEST_MGMT_FSM */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] prSsid Pointer of SSID_T if specified ++* \param[in] pucIe Pointer to buffer of extra information elements to be attached ++* \param[in] u4IeLength Length of information elements ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ DEBUGFUNC("aisFsmScanRequest()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(u4IeLength <= MAX_IE_LENGTH); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (!prConnSettings->fgIsScanReqIssued) { ++ prConnSettings->fgIsScanReqIssued = TRUE; ++ ++ if (prSsid == NULL) { ++ prAisFsmInfo->ucScanSSIDLen = 0; ++ } else { ++ COPY_SSID(prAisFsmInfo->aucScanSSID, ++ prAisFsmInfo->ucScanSSIDLen, prSsid->aucSsid, (UINT_8) prSsid->u4SsidLen); ++ } ++ ++ if (u4IeLength > 0 && u4IeLength <= MAX_IE_LENGTH) { ++ prAisFsmInfo->u4ScanIELength = u4IeLength; ++ kalMemCopy(prAisFsmInfo->aucScanIEBuf, pucIe, u4IeLength); ++ } else { ++ prAisFsmInfo->u4ScanIELength = 0; ++ } ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { ++ if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE ++ && prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { ++ /* 802.1x might not finished yet, pend it for later handling .. */ ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ } else { ++ if (prAisFsmInfo->fgIsChannelGranted == TRUE) { ++ DBGLOG(AIS, WARN, ++ "Scan Request with channel granted for join operation: %d, %d", ++ prAisFsmInfo->fgIsChannelGranted, prAisFsmInfo->fgIsChannelRequested); ++ } ++ ++ /* start online scan */ ++ wlanClearScanningResult(prAdapter); ++ aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); ++ } ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { ++ wlanClearScanningResult(prAdapter); ++ aisFsmSteps(prAdapter, AIS_STATE_SCAN); ++ } else { ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); ++ } ++ } else { ++ DBGLOG(AIS, WARN, "Scan Request dropped. (state: %d)\n", prAisFsmInfo->eCurrentState); ++ } ++ ++} /* end of aisFsmScanRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is invoked when CNM granted channel privilege ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_CH_GRANT_T prMsgChGrant; ++ UINT_8 ucTokenID; ++ UINT_32 u4GrantInterval; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ++ ucTokenID = prMsgChGrant->ucTokenID; ++ u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ /* 1. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN && prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { ++ /* 2. channel privilege has been approved */ ++ prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++ /* 3. state transition to join/ibss-alone/ibss-merge */ ++ /* 3.1 set timeout timer in cases join could not be completed */ ++ cnmTimerStartTimer(prAdapter, ++ &prAisFsmInfo->rJoinTimeoutTimer, ++ prAisFsmInfo->u4ChGrantedInterval - AIS_JOIN_CH_GRANT_THRESHOLD); ++ /* 3.2 set local variable to indicate join timer is ticking */ ++ prAisFsmInfo->fgIsInfraChannelFinished = FALSE; ++ ++ /* 3.3 switch to join state */ ++ aisFsmSteps(prAdapter, AIS_STATE_JOIN); ++ ++ prAisFsmInfo->fgIsChannelGranted = TRUE; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL && ++ prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { ++ /* 2. channel privilege has been approved */ ++ prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; ++ ++ /* 3.1 set timeout timer in cases upper layer cancel_remain_on_channel never comes */ ++ cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer, prAisFsmInfo->u4ChGrantedInterval); ++ ++ /* 3.2 switch to remain_on_channel state */ ++ aisFsmSteps(prAdapter, AIS_STATE_REMAIN_ON_CHANNEL); ++ ++ /* 3.3. indicate upper layer for channel ready */ ++ kalReadyOnChannel(prAdapter->prGlueInfo, ++ prAisFsmInfo->rChReqInfo.u8Cookie, ++ prAisFsmInfo->rChReqInfo.eBand, ++ prAisFsmInfo->rChReqInfo.eSco, ++ prAisFsmInfo->rChReqInfo.ucChannelNum, prAisFsmInfo->rChReqInfo.u4DurationMs); ++ ++ prAisFsmInfo->fgIsChannelGranted = TRUE; ++ } else { /* mismatched grant */ ++ /* 2. return channel privilege to CNM immediately */ ++ aisFsmReleaseCh(prAdapter); ++ } ++ ++} /* end of aisFsmRunEventChGrant() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM that channel privilege ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (prAisFsmInfo->fgIsChannelGranted == TRUE || prAisFsmInfo->fgIsChannelRequested == TRUE) { ++ ++ prAisFsmInfo->fgIsChannelRequested = FALSE; ++ prAisFsmInfo->fgIsChannelGranted = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChAbort) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ return; ++ } ++ ++ prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prMsgChAbort->ucTokenID = prAisFsmInfo->ucSeqNumOfChReq; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); ++ } ++ ++} /* end of aisFsmReleaseCh() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform AIS that corresponding beacon has not ++* been received for a while and probing is not successful ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ BOOLEAN fgDoAbortIndication = FALSE; ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1> Diagnose Connection for Beacon Timeout Event */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { ++ if (OP_MODE_INFRASTRUCTURE == prAisBssInfo->eCurrentOPMode) { ++ P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; ++ ++ if (prStaRec) ++ fgDoAbortIndication = TRUE; ++ } else if (OP_MODE_IBSS == prAisBssInfo->eCurrentOPMode) { ++ fgDoAbortIndication = TRUE; ++ } ++ } ++ /* 4 <2> invoke abort handler */ ++ if (fgDoAbortIndication) { ++#if 0 ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prConnSettings->fgIsDisconnectedByNonRequest = TRUE; ++#endif ++ ++ DBGLOG(AIS, INFO, "Beacon Timeout, Remove BSS [%pM]\n", prAisBssInfo->aucBSSID); ++ scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ ++ /* ++ Note: Cannot change TRUE to FALSE; or you will suffer the problem in ++ ALPS01270257/ ALPS01804173 ++ */ ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, TRUE); ++ } ++ ++} /* end of aisBssBeaconTimeout() */ ++ ++VOID aisBssSecurityChanged(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prAdapter->rWifiVar.rConnSettings.fgIsDisconnectedByNonRequest = TRUE; ++ prAisBssInfo->u2DeauthReason = REASON_CODE_BSS_SECURITY_CHANGE; ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_DEAUTHENTICATED, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform AIS that DEAUTH frame has been ++* sent and thus state machine could go ahead ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] prMsduInfo Pointer of MSDU_INFO_T for DEAUTH frame ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { ++ if (rTxDoneStatus != TX_RESULT_DROPPED_IN_DRIVER) ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_NEW_CONNECTION, FALSE); ++ } else { ++ DBGLOG(AIS, WARN, "DEAUTH frame transmitted without further handling"); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of aisDeauthXmitComplete() */ ++ ++#if CFG_SUPPORT_ROAMING ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate an Event of "Looking for a candidate due to weak signal" to AIS FSM. ++* ++* @param[in] u4ReqScan Requesting Scan or not ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ENUM_AIS_REQUEST_TYPE_T eAisRequest; ++ ++ DBGLOG(AIS, LOUD, "aisFsmRunEventRoamingDiscovery()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* search candidates by best rssi */ ++ prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; ++ ++#if CFG_SUPPORT_WFD ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ /* Check WFD is running */ ++ P_BSS_INFO_T prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered && ++ IS_BSS_ACTIVE(prP2pBssInfo) && ++ (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || ++ prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)) { ++ DBGLOG(ROAMING, INFO, "Handle roaming when P2P is GC or GO.\n"); ++ if (prAdapter->rWifiVar.prP2pFsmInfo) { ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ if ((prWfdCfgSettings->ucWfdEnable == 1) && ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ DBGLOG(ROAMING, INFO, "WFD is running. Stop roaming.\n"); ++ roamingFsmRunEventRoam(prAdapter); ++ roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); ++ return; ++ } ++ } else { ++ ASSERT(0); ++ } ++ } /* fgIsP2PRegistered */ ++ } ++#endif ++#endif ++ ++ /* results are still new */ ++ if (!u4ReqScan) { ++ roamingFsmRunEventRoam(prAdapter); ++ eAisRequest = AIS_REQUEST_ROAMING_CONNECT; ++ } else { ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN ++ || prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { ++ eAisRequest = AIS_REQUEST_ROAMING_CONNECT; ++ } else { ++ eAisRequest = AIS_REQUEST_ROAMING_SEARCH; ++ } ++ } ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { ++ if (eAisRequest == AIS_REQUEST_ROAMING_SEARCH) ++ aisFsmSteps(prAdapter, AIS_STATE_LOOKING_FOR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_SEARCH); ++ } else { ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); ++ ++ aisFsmInsertRequest(prAdapter, eAisRequest); ++ } ++ ++} /* end of aisFsmRunEventRoamingDiscovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the time of ScanDone for roaming and transit to Roam state. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_AIS_STATE_T eNextState; ++ ++ DBGLOG(AIS, LOUD, "->aisFsmRoamingScanResultsUpdate()\n"); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ roamingFsmScanResultsUpdate(prAdapter); ++ ++ eNextState = prAisFsmInfo->eCurrentState; ++ if (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) { ++ roamingFsmRunEventRoam(prAdapter); ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { ++ eNextState = AIS_STATE_SEARCH; ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { ++ eNextState = AIS_STATE_NORMAL_TR; ++ } ++ ++ return eNextState; ++} /* end of aisFsmRoamingScanResultsUpdate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will modify and update necessary information to firmware ++* for disconnection of last AP before switching to roaming bss. ++* ++* @param IN prAdapter Pointer to the Adapter structure. ++* prTargetStaRec Target of StaRec of roaming ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DBGLOG(AIS, LOUD, "aisFsmRoamingDisconnectPrevAP()"); ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ /* Not invoke rlmBssAborted() here to avoid prAisBssInfo->fg40mBwAllowed ++ * to be reset. RLM related parameters will be reset again when handling ++ * association response in rlmProcessAssocRsp(). 20110413 ++ */ ++ /* rlmBssAborted(prAdapter, prAisBssInfo); */ ++ ++ /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ ++ if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) ++ scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ /* 4 <4> Change Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ /* 4 <4.1> sync. with firmware */ ++ prTargetStaRec->ucNetTypeIndex = 0xff; /* Virtial NetType */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ prTargetStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Virtial NetType */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, prAisBssInfo->aucBSSID, ++ TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} /* end of aisFsmRoamingDisconnectPrevAP() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the roaming was completed. ++* ++* @param IN prAdapter Pointer to the Adapter structure. ++* prStaRec StaRec of roaming AP ++* prAssocRspSwRfb ++* ++* @retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DBGLOG(AIS, LOUD, "aisUpdateBssInfoForRoamingAP()"); ++ ++ ASSERT(prAdapter); ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prAisBssInfo->prStaRecOfAP) && ++ (prAisBssInfo->prStaRecOfAP != prStaRec) && (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { ++ cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ ++ aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); ++ ++} /* end of aisFsmRoamingUpdateBss() */ ++ ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Check if there is any pending request and remove it (optional) ++* ++* @param prAdapter ++* eReqType ++* bRemove ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_REQ_HDR_T prPendingReqHdr, prPendingReqHdrNext; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ /* traverse through pending request list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prPendingReqHdr, ++ prPendingReqHdrNext, &(prAisFsmInfo->rPendingReqList), rLinkEntry, AIS_REQ_HDR_T) { ++ /* check for specified type */ ++ if (prPendingReqHdr->eReqType == eReqType) { ++ /* check if need to remove */ ++ if (bRemove == TRUE) { ++ LINK_REMOVE_KNOWN_ENTRY(&(prAisFsmInfo->rPendingReqList), ++ &(prPendingReqHdr->rLinkEntry)); ++ ++ cnmMemFree(prAdapter, prPendingReqHdr); ++ } ++ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get next pending request ++* ++* @param prAdapter ++* ++* @return P_AIS_REQ_HDR_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_REQ_HDR_T prPendingReqHdr; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ LINK_REMOVE_HEAD(&(prAisFsmInfo->rPendingReqList), prPendingReqHdr, P_AIS_REQ_HDR_T); ++ ++ return prPendingReqHdr; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Insert a new request ++* ++* @param prAdapter ++* eReqType ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType) ++{ ++ P_AIS_REQ_HDR_T prAisReq; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ prAisReq = (P_AIS_REQ_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(AIS_REQ_HDR_T)); ++ ++ if (!prAisReq) { ++ ASSERT(0); /* Can't generate new message */ ++ return FALSE; ++ } ++ ++ prAisReq->eReqType = eReqType; ++ ++ /* attach request into pending request list */ ++ LINK_INSERT_TAIL(&prAisFsmInfo->rPendingReqList, &prAisReq->rLinkEntry); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Flush all pending requests ++* ++* @param prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_REQ_HDR_T prAisReq; ++ ++ ASSERT(prAdapter); ++ ++ while ((prAisReq = aisFsmGetNextRequest(prAdapter)) != NULL) ++ cnmMemFree(prAdapter, prAisReq); ++ ++} ++ ++VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_REMAIN_ON_CHANNEL_T prRemainOnChannel; ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prRemainOnChannel = (P_MSG_REMAIN_ON_CHANNEL_T) prMsgHdr; ++ ++ /* record parameters */ ++ prAisFsmInfo->rChReqInfo.eBand = prRemainOnChannel->eBand; ++ prAisFsmInfo->rChReqInfo.eSco = prRemainOnChannel->eSco; ++ prAisFsmInfo->rChReqInfo.ucChannelNum = prRemainOnChannel->ucChannelNum; ++ prAisFsmInfo->rChReqInfo.u4DurationMs = prRemainOnChannel->u4DurationMs; ++ prAisFsmInfo->rChReqInfo.u8Cookie = prRemainOnChannel->u8Cookie; ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE || prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { ++ /* transit to next state */ ++ aisFsmSteps(prAdapter, AIS_STATE_REQ_REMAIN_ON_CHANNEL); ++ } else { ++ aisFsmInsertRequest(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL); ++ } ++ ++ /* free messages */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prCancelRemainOnChannel; ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ prCancelRemainOnChannel = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) prMsgHdr; ++ ++ /* 1. Check the cookie first */ ++ if (prCancelRemainOnChannel->u8Cookie == prAisFsmInfo->rChReqInfo.u8Cookie) { ++ ++ /* 2. release channel privilege/request */ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL) { ++ /* 2.1 elease channel */ ++ aisFsmReleaseCh(prAdapter); ++ } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { ++ /* 2.1 release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2.2 stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ } ++ ++ /* 3. clear pending request of remain_on_channel */ ++ aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE); ++ ++ /* 4. decide which state to retreat */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ } ++ ++ /* 5. free message */ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_MSG_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ /* prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); */ ++ ++ if (prAisFsmInfo == NULL) ++ break; ++ prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) prMsgHdr; ++ ++ aisFuncTxMgmtFrame(prAdapter, ++ &prAisFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* aisFsmRunEventMgmtFrameTx */ ++ ++VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); ++ ++ ASSERT(prAdapter); ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { ++ /* 1. release channel */ ++ aisFsmReleaseCh(prAdapter); ++ ++ /* 2. stop channel timeout timer */ ++ cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); ++ ++ /* 3. expiration indication to upper layer */ ++ kalRemainOnChannelExpired(prAdapter->prGlueInfo, ++ prAisFsmInfo->rChReqInfo.u8Cookie, ++ prAisFsmInfo->rChReqInfo.eBand, ++ prAisFsmInfo->rChReqInfo.eSco, prAisFsmInfo->rChReqInfo.ucChannelNum); ++ ++ /* 4. decide which state to retreat */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); ++ else ++ aisFsmSteps(prAdapter, AIS_STATE_IDLE); ++ } else { ++ DBGLOG(AIS, WARN, "Unexpected remain_on_channel timeout event\n"); ++#if DBG ++ DBGLOG(AIS, STATE, "CURRENT State: [%s]\n", apucDebugAisState[prAisFsmInfo->eCurrentState]); ++#else ++ DBGLOG(AIS, STATE, "[%d] CURRENT State: [%d]\n", DBG_AIS_IDX, prAisFsmInfo->eCurrentState); ++#endif ++ } ++ ++} ++ ++WLAN_STATUS ++aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_AIS_MGMT_TX_REQ_INFO_T) NULL; ++ BOOLEAN fgIsSuccess = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ prMgmtTxReqInfo = &(prAisFsmInfo->rMgmtTxInfo); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(AIS, ERROR, "Mgmt Frame TX Fail, Status:%d.\n", rTxDoneStatus); ++ } else { ++ fgIsSuccess = TRUE; ++ /* printk("Mgmt Frame TX Done.\n"); */ ++ } ++ ++ if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { ++ kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ fgIsSuccess, prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); ++ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* aisFsmRunEventMgmtFrameTxDone */ ++ ++WLAN_STATUS ++aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); ++ ++ if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { ++ ++ /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ ++ /* Packet on driver, not done yet, drop it. */ ++ prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; ++ if (prTxMsduInfo != NULL) { ++ ++ kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ FALSE, ++ prTxMsduInfo->prPacket, (UINT_32) prTxMsduInfo->u2FrameLength); ++ ++ /* Leave it to TX Done handler. */ ++ /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ ++ /* Packet transmitted, wait tx done. (cookie issue) */ ++ } ++ ++ ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanHdr->aucAddr1); ++ prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ ++ prMgmtTxReqInfo->u8Cookie = u8Cookie; ++ prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; ++ prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; ++ ++ prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; ++ prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); ++ if (prStaRec != NULL) { ++ /* Do nothing */ ++ /* printk("Mgmt with station record: %pM .\n", prStaRec->aucMacAddr); */ ++ } ++ ++ prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ ++ prMgmtTxMsdu->fgIs802_1x = FALSE; ++ prMgmtTxMsdu->fgIs802_11 = TRUE; ++ prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMgmtTxMsdu->pfTxDoneHandler = aisFsmRunEventMgmtFrameTxDone; ++ prMgmtTxMsdu->fgIsBasicRate = TRUE; ++ DBGLOG(AIS, TRACE, "Mgmt seq NO. %d .\n", prMgmtTxMsdu->ucTxSeqNum); ++ ++ nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* aisFuncTxMgmtFrame */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Action Frame and indicate to uppoer layer ++* if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("aisFuncValidateRxActionFrame"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); ++ ++ if (1 /* prAisFsmInfo->u4AisPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME */) { ++ /* Leave the action frame to wpa_supplicant. */ ++ kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* aisFuncValidateRxActionFrame */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c +new file mode 100644 +index 000000000000..f02d7c3bb5b2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c +@@ -0,0 +1,1932 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/assoc.c#3 ++*/ ++ ++/*! \file "assoc.c" ++ \brief This file includes the association-related functions. ++ ++ This file includes the association-related functions. ++*/ ++ ++/*\ ++** Log: assoc.c ++** ++** 07 27 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Fix wifi direct connection issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 06 08 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * add a pair of brace for compilation success. ++ * ++ * 06 04 2012 cp.wu ++ * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development ++ * discussed with WH, privacy bit in associate response is not necessary to be checked, ++ * and identified as association failure when mismatching with beacon/probe response ++ * ++ * 03 14 2012 wh.su ++ * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting ++ * Add code from 2.2 ++ * ++ * 03 09 2012 terry.wu ++ * NULL ++ * Fix build error. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 yuche.tsai ++ * NULL ++ * Update Driver for wifi driect gc join IE update issue. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Fix PhyTypeSet in STA_REC in AP mode ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 19 2011 yuche.tsai ++ * NULL ++ * Fix KE when enable hot-spot & any one client connect to this hot-spot. ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 07 15 2011 terry.wu ++ * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment ++ * Update workaround for Kingnet AP. ++ * ++ * 07 15 2011 terry.wu ++ * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment ++ * Workaround for Kingnet 710 AP wrong AID assignment. ++ * ++ * 05 02 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning[WCXRP00000672] [MT6620 Wi-Fi][FW] ++ * Fix the PS event allocation ++ * Check STA when rx assoc. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 03 14 2011 wh.su ++ * [WCXRP00000545] [MT6620 Wi-Fi] [Driver] Fixed the p2p not enable, received a assoc rsp ++ * cause the rx assoc execute a null function ++ * Modify file for avoid assert at BOW receive a assoc response frame but no p2p function. ++ * ++ * 03 08 2011 terry.wu ++ * [WCXRP00000524] [MT6620 Wi-Fi][Driver] Fix p2p assoc request containing wrong IE format ++ * Fix p2p assoc request containing wrong IE format. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix RX disassoc issue under Hot-spot mode. ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Phy Type Set. When legacy client is connected, it can use 11b rate, ++ * but if the P2P device is connected, 11b rate is not allowed. ++ * ++ * 01 11 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Desired Non-HT Rate Set. ++ * ++ * 12 30 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Recover the code that was coverwritted.. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add SSID IE in assoc req frame which is sent by P2P GC. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RSN IE generation by CFG_RSN_MIGRATION compilation flag. ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * revised. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update assocProcessRxAssocReqFrame() to avoid redundant SSID IE {0,0} for IOT. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix compile warning - macro > 10 line, initial value of an array ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * * * * * * and will send Null frame to diagnose connection ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 03 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 28 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * fixed the compiling warning.u1rwduu`wvpghlqg|rm+vp ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update Assoc ID for PS ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Use new constant definition ELEM_MAX_LEN_EXT_CAP ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Modify assoc req IE talbe for HT cap IE ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * update the assocComposeReAssocReqFrameHeader() and fix the u2EstimatedFrameLen in assocSendReAssocReqFrame() ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * remove some space line ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the sending disassoc frame function ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the txassocReq IE table, adding for WPA/RSN ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix eNetType not init in send AssocReq function ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Integrate the send Assoc with TXM ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code to indicate the assoc request and assoc response (now disable) ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove unused variables ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++APPEND_VAR_IE_ENTRY_T txAssocReqIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmReqGenerateHtCapIE} ++ , /* 45 */ ++#if CFG_SUPPORT_WPS2 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WSC), NULL, rsnGenerateWSCIE} ++ , /* 221 */ ++#endif ++#if CFG_RSN_MIGRATION ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} ++ , /* 48 */ ++#endif ++#if CFG_SUPPORT_WAPI ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WAPI), NULL, wapiGenerateWAPIIE} ++ , /* 68 */ ++#endif ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_INTERWORKING), NULL, hs20GenerateInterworkingIE} ++ , /* 107 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ROAMING_CONSORTIUM), NULL, hs20GenerateRoamingConsortiumIE} ++ , /* 111 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmReqGenerateExtCapIE} ++ , /* 127 */ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HS20_INDICATION), NULL, hs20GenerateHS20IE} ++ , /* 221 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO), NULL, mqmGenerateWmmInfoIE} ++ , /* 221 */ ++#if CFG_RSN_MIGRATION ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE} ++ , /* 221 */ ++#endif ++}; ++ ++#if CFG_SUPPORT_AAA ++VERIFY_IE_ENTRY_T rxAssocReqIETable[] = { ++ {ELEM_ID_RESERVED, NULL} /* 255 */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txAssocRespIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} ++ , /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} ++ , /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} ++ , /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} ++ , /* 74 */ ++ {(0), p2pFuncCalculateP2p_IELenForAssocRsp, p2pFuncGenerateP2p_IEForAssocRsp} ++ , /* 221 */ ++#if CFG_SUPPORT_WFD ++ {(0), wfdFuncCalculateWfdIELenForAssocRsp, wfdFuncGenerateWfdIEForAssocRsp} ++ , /* 221 */ ++#endif ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} ++ , /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} ++ , /* 221 */ ++ ++ {(0), p2pFuncCalculateWSC_IELenForAssocRsp, p2pFuncGenerateWSC_IEForAssocRsp} /* 221 */ ++ ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose the Capability Info Field. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval Capability Info Field ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 ++assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ UINT_32 u4NonHTPhyType; ++ UINT_16 u2CapInfo; ++ ++ /* Set up our requested capabilities. */ ++ u2CapInfo = CAP_INFO_ESS; ++ u2CapInfo |= CAP_CF_STA_NOT_POLLABLE; ++ ++ if (prStaRec == NULL) ++ u2CapInfo |= CAP_INFO_PRIVACY; ++ else { ++ if (prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ++ u2CapInfo |= CAP_INFO_PRIVACY; ++ } ++ ++ /* 7.3.1.4 */ ++ if (prStaRec == NULL) { ++ if ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) ||/* ShortPreambleOptionEnable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO)) ++ u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ if (prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) ++ u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ } else if (prStaRec->fgHasBasicPhyType) { ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ if ((rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortPreambleOptionImplemented) && ++ /* Short Preamble Option Enable is TRUE */ ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ /* Case I: Implemented == TRUE and Short Preamble Option Enable == TRUE. ++ * Case II: Implemented == TRUE and Short Preamble == AUTO (depends on ++ * BSS_DESC_T's capability) ++ */ ++ u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ } ++#if CFG_SUPPORT_SPEC_MGMT /*Add by Enlai */ ++ /* Support 802.11h */ ++ if (prStaRec->u2CapInfo & CAP_INFO_SPEC_MGT) { ++ /* ++ 1. The Power Capability element shall be present if ++ dot11SpectrumManagementRequired is true. ++ ++ 2. A STA shall set dot11SpectrumManagementRequired to TRUE before ++ associating with a BSS or IBSS in which the Spectrum Management ++ bit is set to 1 in the Capability Information field in Beacon frames ++ and Probe Response frames received from the BSS or IBSS. ++ */ ++ if (prAdapter->fgEnable5GBand == TRUE) ++ u2CapInfo |= CAP_INFO_SPEC_MGT; ++ } ++#endif ++ ++ if (rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortSlotTimeOptionImplemented && ++ prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) { ++ u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ } ++ } ++ ++ if (prStaRec) { ++ DBGLOG(SAA, LOUD, "ASSOC REQ: Compose Capability = 0x%04x for Target BSS [%pM].\n", ++ u2CapInfo, prStaRec->aucMacAddr); ++ } ++ ++ return u2CapInfo; ++ ++} /* end of assocBuildCapabilityInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Association ++* Request Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID assocBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ PUINT_8 pucBuffer; ++ UINT_16 u2SupportedRateSet; ++ UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; ++ UINT_8 ucAllSupportedRatesLen; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (IS_STA_IN_AIS(prStaRec)) { ++ ++ /* Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) ++ pucBuffer = p2pBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo, pucBuffer); ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) { ++ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++#endif ++ else { ++ /* Do nothing */ ++ /* TODO(Kevin): For other network */ ++ } ++ ++ /* NOTE(Kevin 2008/12/19): 16.3.6.3 MLME-ASSOCIATE.indication - ++ * SupportedRates - The set of data rates that are supported by the STA ++ * that is requesting association. ++ * Original(Portable Driver): Only send the Rates that we'll support. ++ * New: Send the Phy Rates if the result of following & operation == NULL. ++ */ ++ /* rateGetDataRatesFromRateSet((prBssDesc->u2OperationalRateSet & */ ++ /* rPhyAttributes[prBssDesc->ePhyType].u2SupportedRateSet), */ ++ ++ if (prStaRec->fgHasBasicPhyType) { ++ UINT_32 u4NonHTPhyType; ++ ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ u2SupportedRateSet = (prStaRec->u2OperationalRateSet & ++ rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet); ++ ++ ASSERT(u2SupportedRateSet); ++ ++ if (!u2SupportedRateSet) ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ ++ /* TODO(Kevin): For P2P, we shouldn't send support rate set which contains 11b rate */ ++ ++ rateGetDataRatesFromRateSet(u2SupportedRateSet, 0, aucAllSupportedRates, &ucAllSupportedRatesLen); ++ ++ ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? ++ ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); ++ ++ ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; ++ ++ /* Fill the Supported Rates element. */ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* 7.3.2.19 Supported Channels element */ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ if (prAdapter->fgEnable5GBand == TRUE) { ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucId = ELEM_ID_SUP_CHS; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucLength = 8; ++ ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[0] = 36; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[1] = 4; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[2] = 52; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[3] = 4; ++/* Not China --- Start */ ++ /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 100; */ ++ /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 11; */ ++/* Not China --- End */ ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 149; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 4; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[6] = 165; ++ SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[7] = 1; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++#endif ++ } ++ ++} /* end of assocBuildReAssocReqFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the (Re)Association Request frame header and ++* its fixed fields ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in out] pu2PayloadLen Return the length of the composed fixed fields ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeReAssocReqFrameHeaderAndFF(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN OUT PUINT_16 pu2PayloadLen) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ BOOLEAN fgIsReAssoc; ++ ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2CapInfo; ++ UINT_16 u2ListenInterval; ++ ++ ASSERT(prStaRec); ++ ASSERT(pucBuffer); ++ ASSERT(aucMACAddress); ++ ASSERT(pu2PayloadLen); ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) pucBuffer; ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ ++ /* Fill the Frame Control field. */ ++ if (fgIsReAssoc) ++ u2FrameCtrl = MAC_FRAME_REASSOC_REQ; ++ else ++ u2FrameCtrl = MAC_FRAME_ASSOC_REQ; ++ WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prAssocFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prAssocFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prAssocFrame->aucBSSID, prStaRec->aucMacAddr); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prAssocFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); ++ ++ /* Fill the Capability Information field. */ ++ WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); ++ ++ /* Calculate the listen interval for the maximum power mode. Currently, we ++ set it to the value 2 times DTIM period. */ ++ if (prStaRec->ucDTIMPeriod) { ++ u2ListenInterval = prStaRec->ucDTIMPeriod * DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD; ++ } else { ++ DBGLOG(SAA, TRACE, "Use default listen interval\n"); ++ u2ListenInterval = DEFAULT_LISTEN_INTERVAL; ++ } ++ prStaRec->u2ListenInterval = u2ListenInterval; ++ ++ /* Fill the Listen Interval field. */ ++ WLAN_SET_FIELD_16(&prAssocFrame->u2ListenInterval, u2ListenInterval); ++ ++ /* 4 <3> Compose the Current AP Address field for ReAssociation Request frame. */ ++ /* Fill the Current AP Address field. */ ++ if (prStaRec->fgIsReAssoc) { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ ++ P_AIS_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ P_WLAN_REASSOC_REQ_FRAME_T prReAssocFrame = (P_WLAN_REASSOC_REQ_FRAME_T) prAssocFrame; ++ ++ COPY_MAC_ADDR(prReAssocFrame->aucCurrentAPAddr, prAisBssInfo->aucBSSID); ++ } else { ++ ASSERT(0); /* We don't support ReAssociation for other network */ ++ } ++ ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + CURR_AP_ADDR_FIELD_LEN); ++ } else { ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN); ++ } ++ ++} /* end of assocComposeReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the (Re)Association Request frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ BOOLEAN fgIsReAssoc; ++ UINT_32 i; ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ ++ if (fgIsReAssoc) { ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ LISTEN_INTERVAL_FIELD_LEN + ++ CURR_AP_ADDR_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ } else { ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ LISTEN_INTERVAL_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ } ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ u2EstimatedExtraIELen = p2pCalculate_IEForAssocReq(prAdapter, ++ prStaRec->ucNetTypeIndex, prStaRec); ++ } else { ++ DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); ++ ASSERT(FALSE); ++ } ++ } else { ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; ++ } else { ++ u2EstimatedExtraIELen += ++ (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ } ++ } ++#else ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; ++ } else { ++ u2EstimatedExtraIELen += (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ } ++#endif ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Request.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeReAssocReqFrameHeaderAndFF(prAdapter, ++ prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prBssInfo->aucOwnMacAddr, &u2PayloadLen); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ ++ assocBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ p2pGenerate_IEForAssocReq(prAdapter, prMsduInfo); ++ } else { ++ DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); ++ ASSERT(FALSE); ++ } ++ } else { ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].pfnAppendIE) ++ txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ } ++#else ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocReqIETable[i].pfnAppendIE) ++ txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++#endif ++ ++ /* 4 <6> Update the (Re)association request information */ ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++#if CFG_RSN_MIGRATION ++ kalUpdateReAssocReqInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocFrame->u2CapInfo, ++ prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), ++ fgIsReAssoc); ++#endif ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; ++ ++ prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocFrame->u2CapInfo, ++ prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), ++ fgIsReAssoc); ++ } ++#endif ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ ++ DBGLOG(SAA, INFO, "Sending (Re)Assoc Request, network: %d seqNo: %d\n", ++ prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of assocSendReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX (Re)Association Request frame for ++* SAA event handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAssocReqFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2TxFrameCtrl != MAC_FRAME_REASSOC_REQ) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2TxFrameCtrl != MAC_FRAME_ASSOC_REQ) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckTxReAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX (Re)Association Response frame for ++* AAA event handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAssocRspFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAssocFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2TxFrameCtrl != MAC_FRAME_REASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2TxFrameCtrl != MAC_FRAME_ASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckTxReAssocRespFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the incoming (Re)Association Frame and take out ++* the status code. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ UINT_16 u2RxFrameCtrl; ++ UINT_16 u2RxCapInfo; ++ UINT_16 u2RxStatusCode; ++ UINT_16 u2RxAssocId; ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN + AID_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ DBGLOG(SAA, LOUD, "prSwRfb->u2PayloadLength = %d\n", prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* 4 <1> locate the (Re)Association Resp Frame. */ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of (Re)Association Resp Frame. */ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (prStaRec->fgIsReAssoc) { ++ if (u2RxFrameCtrl != MAC_FRAME_REASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } else { ++ if (u2RxFrameCtrl != MAC_FRAME_ASSOC_RSP) ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* 4 <3> Parse the Fixed Fields of (Re)Association Resp Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2CapInfo, &u2RxCapInfo); */ ++ u2RxCapInfo = prAssocRspFrame->u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2StatusCode, &u2RxStatusCode); */ ++ u2RxStatusCode = prAssocRspFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* 4 <4> Check CAP_INFO */ ++ /* NOTE(Kevin): CM suggest to add MGMT workaround for those APs didn't check ++ * the CAP Privacy Bit to overcome a corner case that the Privacy Bit ++ * of our SCAN result didn't consist with AP's Association Resp. ++ */ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { ++ /* WAPI AP allow the customer use WZC to join mode, the privacy bit is 0 */ ++ /* even at WAI & WAPI_PSK mode, but the assoc respose set the privacy bit set 1 */ ++ DBGLOG(SEC, TRACE, "Workaround the WAPI AP allow the customer to use WZC to join\n"); ++ } else ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && 1) { ++ /* Todo:: Fixed this */ ++ } else ++#endif ++ { ++ } ++ ++#if CFG_STRICT_CHECK_CAPINFO_PRIVACY ++ if ((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ^ (u2RxCapInfo & CAP_INFO_PRIVACY)) ++ u2RxStatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; ++#endif ++ } ++ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++#if CFG_RSN_MIGRATION ++ /* Update the information in the structure used to query and set ++ OID_802_11_ASSOCIATION_INFORMATION. */ ++ kalUpdateReAssocRspInfo(prAdapter->prGlueInfo, ++ (PUINT_8) &prAssocRspFrame->u2CapInfo, (UINT_32) (prSwRfb->u2PacketLen)); ++#endif ++ } ++ /* 4 <5> Update CAP_INFO and ASSOC_ID */ ++ if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { ++ prStaRec->u2CapInfo = u2RxCapInfo; ++ ++ /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2AssocId, &u2RxAssocId); */ ++ u2RxAssocId = prAssocRspFrame->u2AssocId; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* 20110715 Workaround for Kingnet 710 AP (Realtek 8186) ++ * This AP raises the bit 6&7 not bit 14&15 in AID field. ++ * It cause wrong AID assignment. ++ * For AID = 2 ++ * Normal case: 0xC002(1100 0000 0000 0010) => 2 ++ * Kingnet 710: 0x00C2(0000 0000 1100 0010) => 194 ++ * workaround: mask bit 6&7 for this AP ++ */ ++ if ((u2RxAssocId & BIT(6)) && (u2RxAssocId & BIT(7)) && !(u2RxAssocId & BITS(8, 15))) { ++ prStaRec->u2AssocId = u2RxAssocId & ~BITS(6, 7); ++ } else { ++ prStaRec->u2AssocId = u2RxAssocId & ~AID_MSB; ++#if CFG_SUPPORT_802_11W ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ prBssSpecInfo->ucSaQueryTimedOut = 0; ++ } ++#endif ++ } ++ } ++#if CFG_SUPPORT_802_11W ++ if (u2RxStatusCode == STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED) { ++ DBGLOG(SAA, INFO, "AP rejected due the authentication algorithm not support\n"); ++ } else if (u2RxStatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { ++ PUINT_8 pucIE, pucTime; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_TIMEOUT_INTERVAL == IE_ID(pucIE) && IE_LEN(pucIE) == 5) { ++ pucTime = ((P_IE_HDR_T) pucIE)->aucInfo; ++ if (pucTime[0] == ACTION_SA_TIMEOUT_ASSOC_COMEBACK) { ++ UINT_32 tu; ++ ++ WLAN_GET_FIELD_32(pucTime + 1, &tu); ++ DBGLOG(SAA, INFO, ++ "AP rejected association temporarily;comeback duration %u TU (%u ms)\n", ++ tu, TU_TO_MSEC(tu)); ++ if (tu > TX_ASSOCIATION_RETRY_TIMEOUT_TU) { ++ DBGLOG(SAA, INFO, "Update timer based on comeback duration\n"); ++ /* ieee80211_reschedule_timer(wpa_s, ms); */ ++ } ++ } ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ } ++#endif ++ *pu2StatusCode = u2RxStatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocCheckRxReAssocRspFrameStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will compose the Disassociation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2ReasonCode The reason code of disassociation ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeDisassocFrame(IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN UINT_16 u2ReasonCode) ++{ ++ P_WLAN_DISASSOC_FRAME_T prDisAssocFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(pucBuffer); ++ ASSERT(aucMACAddress); ++ ++ prDisAssocFrame = (P_WLAN_DISASSOC_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the DisAssociation frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_DISASSOC; ++ ++ WLAN_SET_FIELD_16(&prDisAssocFrame->u2FrameCtrl, u2FrameCtrl); ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prDisAssocFrame->aucBSSID, prStaRec->aucMacAddr); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prDisAssocFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Disassociation frame. */ ++ /* Fill the Reason Code field. */ ++ WLAN_SET_FIELD_16(&prDisAssocFrame->u2ReasonCode, u2ReasonCode); ++ ++} /* end of assocComposeDisassocFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Disassociation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2ReasonCode The reason code of disassociation ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode) ++{ ++ PUINT_8 pucMacAddress; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ /* UINT_32 u4Status = WLAN_STATUS_SUCCESS; */ ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Disassociation Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending DisAssoc.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Disassociation frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ pucMacAddress = prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].aucOwnMacAddr; ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeDisassocFrame(prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucMacAddress, u2ReasonCode); ++ ++#if CFG_SUPPORT_802_11W ++ if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ ++ prDisassocFrame = ++ (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ DBGLOG(TX, WARN, "assocSendDisAssocFrame with protection\n"); ++ } ++#endif ++ ++ u2PayloadLen = REASON_CODE_FIELD_LEN; ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Enqueue the frame to send this (Re)Association request frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of assocSendDisAssocFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Disassociation frame ++* if the given BSSID is matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucBSSID Given BSSID ++* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) ++{ ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ UINT_16 u2RxReasonCode; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucBSSID); ++ ASSERT(pu2ReasonCode); ++ ++ /* 4 <1> locate the Disassociation Frame. */ ++ prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Disassociation Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Check if this Disassoc Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prDisassocFrame->aucBSSID, aucBSSID)) { ++ DBGLOG(SAA, LOUD, "Ignore Disassoc Frame from other BSS [ %pM ]\n", ++ prDisassocFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ ++ WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode); ++ *pu2ReasonCode = u2RxReasonCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocProcessRxDisassocFrame() */ ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Association Req frame ++* and return a Status Code. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode Pointer to store the Status Code for carried in Association Response. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_RSN_INFO_ELEM_T prIeRsn = (P_RSN_INFO_ELEM_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ PUINT_8 pucIE, pucIEStart; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ UINT_16 u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ UINT_16 u2RxFrameCtrl; ++ UINT_16 u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ /* 4 <1> locate the Association Req Frame. */ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Association Req Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Check if this Disassoc Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prAssocReqFrame->aucBSSID, prBssInfo->aucBSSID)) ++ return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ ++ /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (MAC_FRAME_REASSOC_REQ == u2RxFrameCtrl) { ++ prStaRec->fgIsReAssoc = TRUE; ++ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); ++ ++ pucIEStart = pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; ++ } else { ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); ++ ++ pucIEStart = pucIE = prAssocReqFrame->aucInfoElem; ++ } ++ ++ /* 4 <3> Parse the Fixed Fields of Assoc Req Frame Body. */ ++ prStaRec->u2CapInfo = prAssocReqFrame->u2CapInfo; ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ if (((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) && !kalP2PGetCipher(prAdapter->prGlueInfo))) { ++ u2StatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; ++ DBGLOG(RSN, TRACE, "STA Assoc req privacy bit check fail\n"); ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++#endif ++ ++ prStaRec->u2ListenInterval = prAssocReqFrame->u2ListenInterval; ++ prStaRec->ucPhyTypeSet = 0; ++ ++ /* Might be legacy client or p2p gc. */ ++ prStaRec->eStaType = STA_TYPE_LEGACY_CLIENT; ++ ++ /* 4 <4> Parse the IE of Assoc Req Frame Body. */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && /* NOTE(Kevin): Get SSID once */ ++ (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ } ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ if (!prIeExtSupportedRate) ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ case ELEM_ID_HT_CAP: ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ kalMemCopy(&prStaRec->u2HtCapInfo, &(HT_CAP_IE(pucIE)->u2HtCapInfo), 2); ++ break; ++ case ELEM_ID_RSN: ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ prIeRsn = RSN_IE(pucIE); ++ rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, &u2StatusCode); ++ if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ *pu2StatusCode = u2StatusCode; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++#endif ++ break; ++ case ELEM_ID_VENDOR: ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ if ((prAdapter->fgIsP2PRegistered)) { ++ UINT_8 ucOuiType = 0; ++ ++ p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType); ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ DBGLOG(P2P, TRACE, "Target Client is a P2P group client\n"); ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ } ++ } ++ } ++#endif ++ break; ++ default: ++ for (i = 0; i < (sizeof(rxAssocReqIETable) / sizeof(VERIFY_IE_ENTRY_T)); i++) { ++ ++ if ((IE_ID(pucIE)) == rxAssocReqIETable[i].ucElemID) { ++ rxAssocReqIETable[i].pfnVarifyIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIE, ++ &u2StatusCode); ++ ++ if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ *pu2StatusCode = u2StatusCode; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ } ++ ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* parsing for WMM related information (2010/12/21) */ ++ mqmProcessAssocReq(prAdapter, prSwRfb, pucIEStart, u2IELength); ++ ++ do { ++ if (prIeSsid) { ++ if (UNEQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ ++ u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; ++ break; ++ } ++ } else { ++ u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; ++ break; ++ } ++ ++ prStaRec->u2OperationalRateSet = 0; ++ prStaRec->u2BSSBasicRateSet = 0; ++ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, &prStaRec->u2OperationalRateSet, ++ &u2BSSBasicRateSet, /* Ignore any Basic Bit */ ++ &fgIsUnknownBssBasicRate); ++ ++ if ((prBssInfo->u2BSSBasicRateSet & prStaRec->u2OperationalRateSet) != ++ prBssInfo->u2BSSBasicRateSet) { ++ ++ u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ ++ /* Accpet the Sta, update BSSBasicRateSet from Bss */ ++ ++ prStaRec->u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; ++ ++ prStaRec->u2DesiredNonHTRateSet = (prStaRec->u2OperationalRateSet & RATE_SET_ALL_ABG); ++ ++ if (BAND_2G4 == HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr)) { ++#if 0 /* Marked by CMC 20111024 */ ++ /* check if support 11n */ ++ if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ ++ if ((!(u2BSSBasicRateSet & RATE_SET_OFDM)) && ++ (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS)) { ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++ ++ } ++ ++ } ++#else ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++#endif ++ } else { /* (BAND_5G == prBssDesc->eBande) */ ++#if 0 /* Marked by CMC 20111024 */ ++ if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++ ASSERT((prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) == 0); ++#else ++ if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++#endif ++ } ++ ++ } else { ++ ASSERT(0); ++ u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ if (prIeRsn) { ++ if (!kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ u2StatusCode = STATUS_CODE_CIPHER_SUITE_REJECTED; ++ break; ++ } ++ } else { ++ prStaRec->rSecInfo.fgAllowOnly1x = FALSE; ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ /* Only Allow 1x */ ++ prStaRec->rSecInfo.fgAllowOnly1x = TRUE; ++ break; ++ } ++ } ++ } ++#endif ++ ++ } while (FALSE); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++#if 1 /* ICS */ ++ { ++ PUINT_8 cp = (PUINT_8) &prAssocReqFrame->u2CapInfo; ++ P_UINT_8 prNewAssocReqIe = NULL; ++ ++ if (u2IELength) { ++ prNewAssocReqIe = kalMemAlloc(u2IELength, VIR_MEM_TYPE); ++ if (NULL == prNewAssocReqIe) { ++ DBGLOG(AIS, WARN, "allocate memory for (Re)assocReqIe fail!\n"); ++ u2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ if (prStaRec->fgIsReAssoc) ++ cp += 10; ++ else ++ cp += 4; ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ } ++ prStaRec->u2AssocReqIeLen = u2IELength; ++ if (u2IELength) { ++ prStaRec->pucAssocReqIe = prNewAssocReqIe; /* kalMemAlloc(u2IELength, VIR_MEM_TYPE); */ ++ kalMemCopy(prStaRec->pucAssocReqIe, cp, u2IELength); ++ } ++ } ++#endif ++ kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, (PUINT_8) &prAssocReqFrame->u2CapInfo, ++ u2IELength + (prStaRec->fgIsReAssoc ? 10 : 4), prStaRec->fgIsReAssoc); ++ } ++#endif ++ ++ *pu2StatusCode = u2StatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocProcessRxAssocReqFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Association ++* Response Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocBuildReAssocRespFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo) ++{ ++ PUINT_8 pucBuffer; ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { ++ ++ ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; ++ ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; ++ } else { ++ ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; ++ ucExtSupRatesLen = 0; ++ } ++ ++ /* Fill the Supported Rates element. */ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &prBssInfo->aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* end of assocBuildReAssocRespFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the (Re)Association Response frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucBssid Given BSSID. ++* @param[in] u2CapInfo Capability Field of current BSS. ++* @param[in out] pu2PayloadLen Return the length of the composed fixed fields ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++assocComposeReAssocRespFrameHeaderAndFF(IN P_STA_RECORD_T prStaRec, ++ IN PUINT_8 pucBuffer, ++ IN UINT_8 aucBSSID[], IN UINT_16 u2CapInfo, IN OUT PUINT_16 pu2PayloadLen) ++{ ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; ++ BOOLEAN fgIsReAssoc; ++ ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(prStaRec); ++ ASSERT(pucBuffer); ++ ASSERT(aucBSSID); ++ ASSERT(pu2PayloadLen); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) pucBuffer; ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ ++ /* Fill the Frame Control field. */ ++ if (fgIsReAssoc) ++ u2FrameCtrl = MAC_FRAME_REASSOC_RSP; ++ else ++ u2FrameCtrl = MAC_FRAME_ASSOC_RSP; ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prAssocRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target MAC Address. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucDestAddr, prStaRec->aucMacAddr); ++ ++ /* Fill the SA field with current BSSID. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucSrcAddr, aucBSSID); ++ ++ /* Fill the BSSID field with current BSSID. */ ++ COPY_MAC_ADDR(prAssocRspFrame->aucBSSID, aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prAssocRspFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ ++ /* Fill the Capability Information field. */ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); */ ++ prAssocRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2StatusCode, prStaRec->u2StatusCode); */ ++ prAssocRspFrame->u2StatusCode = prStaRec->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* WLAN_SET_FIELD_16(&prAssocFrame->u2AssocId, ((prStaRec->u2AssocId & AID_MASK) | AID_MSB)); */ ++ prAssocRspFrame->u2AssocId = ((prStaRec->u2AssocId & AID_MASK) | AID_MSB); /* NOTE(Kevin): Optimized for ARM */ ++ ++ *pu2PayloadLen = (CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); ++ ++} /* end of assocComposeReAssocRespFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the (Re)Association Resp frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ UINT_16 u2PayloadLen; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ BOOLEAN fgIsReAssoc; ++ UINT_32 i; ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ fgIsReAssoc = prStaRec->fgIsReAssoc; ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN + ++ AID_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocRespIETable[i].u2EstimatedFixedIELen != 0) { ++ u2EstimatedExtraIELen += txAssocRespIETable[i].u2EstimatedFixedIELen; ++ } else if (txAssocRespIETable[i].pfnCalculateVariableIELen != NULL) { ++ u2EstimatedExtraIELen += (UINT_16) txAssocRespIETable[i].pfnCalculateVariableIELen(prAdapter, ++ prStaRec->ucNetTypeIndex, ++ prStaRec); ++ } ++ ++ } ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(AAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Response.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex != NETWORK_TYPE_AIS_INDEX); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and Fixed Field */ ++ assocComposeReAssocRespFrameHeaderAndFF(prStaRec, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prBssInfo->aucBSSID, prBssInfo->u2CapInfo, &u2PayloadLen); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = aaaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ ++ assocBuildReAssocRespFrameCommonIEs(prAdapter, prMsduInfo, prBssInfo); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE */ ++ for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txAssocRespIETable[i].pfnAppendIE) ++ txAssocRespIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ ++ DBGLOG(SAA, INFO, "Sending (Re)Assoc Response, network: %d seqNo: %d\n", ++ prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of assocSendReAssocRespFrame() */ ++#endif /* CFG_SUPPORT_AAA */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c +new file mode 100644 +index 000000000000..43b91d72bd43 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c +@@ -0,0 +1,1211 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/auth.c#1 ++*/ ++ ++/*! \file "auth.c" ++ \brief This file includes the authentication-related functions. ++ ++ This file includes the authentication-related functions. ++*/ ++ ++/* ++** Log: auth.c ++ * ++ * 02 13 2012 cp.wu ++ * NULL ++ * show error message only instead of raise assertion when ++ * received authentication frame is carrying illegal parameters. ++ * ++ * 11 09 2011 yuche.tsai ++ * NULL ++ * Fix a network index & station record index issue when TX deauth frame. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 22 2011 yuche.tsai ++ * NULL ++ * Fix coding error. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000796] [Volunteer Patch][MT6620][Driver] Add BC deauth frame TX feature. ++ * BC deauth support. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * 1. Fix Service Disocvery Logical issue. ++ * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 21 2011 terry.wu ++ * [WCXRP00000381] [MT6620 Wi-Fi][Driver] Kernel panic when replying unaccept Auth in AP mode ++ * In AP mode, use STA_REC_INDEX_NOT_FOUND(0xFE) instead of StaRec index when replying an unaccept Auth frame. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update authSendDeauthFrame() for correct the value of eNetTypeIndex in MSDU_INFO_T ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Check Net is active before sending Deauth frame. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Fix compile warning ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add debug message for abnormal authentication frame from AP ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * Fix the Debug Label ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update the authComposeAuthFrameHeader() ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the send deauth frame function ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Integrate send Auth with TXM ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++APPEND_IE_ENTRY_T txAuthIETable[] = { ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_CHALLENGE_TEXT), authAddIEChallengeText} ++}; ++ ++HANDLE_IE_ENTRY_T rxAuthIETable[] = { ++ {ELEM_ID_CHALLENGE_TEXT, authHandleIEChallengeText} ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Authentication frame header and fixed fields. ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucPeerMACAddress Given Peer MAC Address. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2AuthAlgNum Authentication Algorithm Number ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* @param[in] u2StatusCode Status Code ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++authComposeAuthFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN UINT_8 aucPeerMACAddress[], ++ IN UINT_8 aucMACAddress[], ++ IN UINT_16 u2AuthAlgNum, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(aucPeerMACAddress); ++ ASSERT(aucMACAddress); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Authentication frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_AUTH; ++ ++ /* If this frame is the third frame in the shared key authentication ++ * sequence, it shall be encrypted. ++ */ ++ if ((u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) ++ u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; /* HW will also detect this bit for applying encryption */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prAuthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucDestAddr, aucPeerMACAddress); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prAuthFrame->aucSrcAddr, aucMACAddress); ++ ++ switch (u2TransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucPeerMACAddress); ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ ++ /* Fill the BSSID field with Current BSSID. */ ++ COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ /* Clear the SEQ/FRAG_NO field. */ ++ prAuthFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ ++ /* Fill the Authentication Algorithm Number field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthAlgNum, u2AuthAlgNum); */ ++ prAuthFrame->u2AuthAlgNum = u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Authentication Transaction Sequence Number field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, u2TransactionSeqNum); */ ++ prAuthFrame->u2AuthTransSeqNo = u2TransactionSeqNum; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Status Code field. */ ++ /* WLAN_SET_FIELD_16(&prAuthFrame->u2StatusCode, u2StatusCode); */ ++ prAuthFrame->u2StatusCode = u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of authComposeAuthFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will append Challenge Text IE to the Authentication frame ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TransactionSeqNum; ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) ++ return; ++ ++ ASSERT(prStaRec); ++ ++ /* For Management, frame header and payload are in a continuous buffer */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prMsduInfo->prPacket; ++ ++ WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) ++ ++ /* Only consider SEQ_3 for Challenge Text */ ++ if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3) && ++ (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (prStaRec->prChallengeText != NULL)) { ++ ++ COPY_IE(((ULONG) (prMsduInfo->prPacket) + prMsduInfo->u2FrameLength), (prStaRec->prChallengeText)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prStaRec->prChallengeText); ++ } ++ ++ return; ++ ++} /* end of authAddIEChallengeText() */ ++ ++#if !CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Authenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ UINT_16 u2PayloadLen; ++ UINT_32 i; ++ ++ DBGLOG(SAA, LOUD, "Send Auth Frame\n"); ++ ++ ASSERT(prStaRec); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) ++ u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Compose Header and some Fixed Fields */ ++ authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec->aucMacAddr, ++ prBssInfo->aucOwnMacAddr, ++ prStaRec->ucAuthAlgNum, u2TransactionSeqNum, STATUS_CODE_RESERVED); ++ ++ u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { ++ if (txAuthIETable[i].pfnAppendIE) ++ txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Authentication frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendAuthFrame() */ ++ ++#else ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Authenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authSendAuthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) ++{ ++ PUINT_8 pucReceiveAddr; ++ PUINT_8 pucTransmitAddr; ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ /*get from input parameter */ ++ /* ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; */ ++ PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedExtraIELen; ++ UINT_16 u2PayloadLen; ++ UINT_16 ucAuthAlgNum; ++ UINT_32 i; ++ ++ DBGLOG(SAA, LOUD, "Send Auth Frame %d, Status Code = %d\n", u2TransactionSeqNum, u2StatusCode); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) ++ u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ ++ if (prStaRec) { ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucReceiveAddr = prStaRec->aucMacAddr; ++ ++ ucAuthAlgNum = prStaRec->ucAuthAlgNum; ++ ++ switch (u2TransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++ pfTxDoneHandler = saaFsmRunEventTxDone; ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ pfTxDoneHandler = aaaFsmRunEventTxDone; ++ break; ++ } ++ ++ } else { /* For Error Status Code */ ++ P_WLAN_AUTH_FRAME_T prFalseAuthFrame; ++ ++ ASSERT(prFalseAuthSwRfb); ++ prFalseAuthFrame = (P_WLAN_AUTH_FRAME_T) prFalseAuthSwRfb->pvHeader; ++ ++ ASSERT(u2StatusCode != STATUS_CODE_SUCCESSFUL); ++ ++ pucTransmitAddr = prFalseAuthFrame->aucDestAddr; ++ ++ pucReceiveAddr = prFalseAuthFrame->aucSrcAddr; ++ ++ ucAuthAlgNum = prFalseAuthFrame->u2AuthAlgNum; ++ ++ u2TransactionSeqNum = (prFalseAuthFrame->u2AuthTransSeqNo + 1); ++ } ++ ++ /* Compose Header and some Fixed Fields */ ++ authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucReceiveAddr, ++ pucTransmitAddr, ucAuthAlgNum, u2TransactionSeqNum, u2StatusCode); ++ ++ u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ if (prStaRec) ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ else ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; /* false Auth frame */ ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { ++ if (txAuthIETable[i].pfnAppendIE) ++ txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Authentication frame. */ ++ DBGLOG(SAA, INFO, "network: %d Send Auth Frame %d, Status Code = %d seq num %d\n", ++ eNetTypeIndex, u2TransactionSeqNum, u2StatusCode, prMsduInfo->ucTxSeqNum); ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendAuthFrame() */ ++ ++#endif /* CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will strictly check the TX Authentication frame for SAA/AAA event ++* handling. ++* ++* @param[in] prMsduInfo Pointer of MSDU_INFO_T ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TxFrameCtrl; ++ UINT_16 u2TxAuthAlgNum; ++ UINT_16 u2TxTransactionSeqNum; ++ ++ ASSERT(prMsduInfo); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) (prMsduInfo->prPacket); ++ ASSERT(prAuthFrame); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2FrameCtrl, &u2TxFrameCtrl) */ ++ u2TxFrameCtrl = prAuthFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ u2TxFrameCtrl &= MASK_FRAME_TYPE; ++ if (u2TxFrameCtrl != MAC_FRAME_AUTH) ++ return WLAN_STATUS_FAILURE; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2TxAuthAlgNum) */ ++ u2TxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2TxAuthAlgNum != (UINT_16) (prStaRec->ucAuthAlgNum)) ++ return WLAN_STATUS_FAILURE; ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TxTransactionSeqNum) */ ++ u2TxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2TxTransactionSeqNum != u2TransactionSeqNum) ++ return WLAN_STATUS_FAILURE; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckTxAuthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Auth Frame's Transaction Sequence ++* Number before delivering it to the corresponding SAA or AAA Module. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain authentication frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2RxTransactionSeqNum; ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Authentication Frame. */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (AUTH_ALGORITHM_NUM_FIELD_LEN + ++ AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + ++ STATUS_CODE_FIELD_LEN)) { ++ ASSERT(0); ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 4 <3> Parse the Fixed Fields of Authentication Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ ++ u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ switch (u2RxTransactionSeqNum) { ++ case AUTH_TRANSACTION_SEQ_2: ++ case AUTH_TRANSACTION_SEQ_4: ++ saaFsmRunEventRxAuth(prAdapter, prSwRfb); ++ break; ++ ++ case AUTH_TRANSACTION_SEQ_1: ++ case AUTH_TRANSACTION_SEQ_3: ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAuth(prAdapter, prSwRfb); ++#endif /* CFG_SUPPORT_AAA */ ++ break; ++ ++ default: ++ DBGLOG(SAA, WARN, "Strange Authentication Packet: Auth Trans Seq No = %d, Error Status Code = %d\n", ++ u2RxTransactionSeqNum, prAuthFrame->u2StatusCode); ++ break; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckRxAuthFrameTransSeq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the incoming Authentication Frame and take ++* the status code out. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] u2TransactionSeqNum Transaction Sequence Number ++* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2RxAuthAlgNum; ++ UINT_16 u2RxTransactionSeqNum; ++ /* UINT_16 u2RxStatusCode; // NOTE(Kevin): Optimized for ARM */ ++ ++ ASSERT(prSwRfb); ++ ASSERT(pu2StatusCode); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Fixed Fields of Authentication Frame Body. */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2RxAuthAlgNum); */ ++ u2RxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2RxAuthAlgNum != (UINT_16) prStaRec->ucAuthAlgNum) { ++ DBGLOG(SAA, WARN, "Discard Auth frame with auth type = %d, current = %d\n", ++ u2RxAuthAlgNum, prStaRec->ucAuthAlgNum); ++ *pu2StatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ ++ u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ if (u2RxTransactionSeqNum != u2TransactionSeqNum) { ++ DBGLOG(SAA, WARN, "Discard Auth frame with Transaction Seq No = %d\n", u2RxTransactionSeqNum); ++ *pu2StatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; ++ return WLAN_STATUS_SUCCESS; ++ } ++ /* 4 <3> Get the Status code */ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2StatusCode, &u2RxStatusCode); */ ++ /* *pu2StatusCode = u2RxStatusCode; */ ++ *pu2StatusCode = prAuthFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authCheckRxAuthFrameStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Challenge Text IE from the Authentication frame ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] prIEHdr Pointer to start address of IE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2TransactionSeqNum; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prIEHdr); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ /* For Management, frame header and payload are in a continuous buffer */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) */ ++ u2TransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Only consider SEQ_2 for Challenge Text */ ++ if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_2) && ++ (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY)) { ++ ++ /* Free previous allocated TCM memory */ ++ if (prStaRec->prChallengeText) { ++ ASSERT(0); ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ prStaRec->prChallengeText = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, IE_SIZE(prIEHdr)); ++ if (prStaRec->prChallengeText == NULL) ++ return; ++ ++ /* Save the Challenge Text from Auth Seq 2 Frame, before sending Auth Seq 3 Frame */ ++ COPY_IE(prStaRec->prChallengeText, prIEHdr); ++ } ++ ++ return; ++ ++} /* end of authAddIEChallengeText() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Authentication frame. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ PUINT_8 pucIEsBuffer; ++ UINT_16 u2IEsLen; ++ UINT_16 u2Offset; ++ UINT_8 ucIEID; ++ UINT_32 i; ++ ++ ASSERT(prSwRfb); ++ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ pucIEsBuffer = &prAuthFrame->aucInfoElem[0]; ++ u2IEsLen = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); ++ ++ IE_FOR_EACH(pucIEsBuffer, u2IEsLen, u2Offset) { ++ ucIEID = IE_ID(pucIEsBuffer); ++ ++ for (i = 0; i < (sizeof(rxAuthIETable) / sizeof(HANDLE_IE_ENTRY_T)); i++) { ++ ++ if (ucIEID == rxAuthIETable[i].ucElemID) ++ rxAuthIETable[i].pfnHandleIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIEsBuffer); ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxAuth2_Auth4Frame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Deauthentication frame ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] aucPeerMACAddress Given Peer MAC Address. ++* @param[in] aucMACAddress Given Our MAC Address. ++* @param[in] u2StatusCode Status Code ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID ++authComposeDeauthFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN UINT_8 aucPeerMACAddress[], ++ IN UINT_8 aucMACAddress[], IN UINT_8 aucBssid[], IN UINT_16 u2ReasonCode) ++{ ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(aucPeerMACAddress); ++ ASSERT(aucMACAddress); ++ ASSERT(aucBssid); ++ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Deauthentication frame. */ ++ /* Fill the Frame Control field. */ ++ u2FrameCtrl = MAC_FRAME_DEAUTH; ++ ++ /* WLAN_SET_FIELD_16(&prDeauthFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prDeauthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with Target BSSID. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucDestAddr, aucPeerMACAddress); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucSrcAddr, aucMACAddress); ++ ++ /* Fill the BSSID field with Target BSSID. */ ++ COPY_MAC_ADDR(prDeauthFrame->aucBSSID, aucBssid); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prDeauthFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ ++ /* Fill the Status Code field. */ ++ /* WLAN_SET_FIELD_16(&prDeauthFrame->u2ReasonCode, u2ReasonCode); */ ++ prDeauthFrame->u2ReasonCode = u2ReasonCode; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of authComposeDeauthFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send the Deauthenticiation frame ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prClassErrSwRfb Pointer to the SW_RFB_T which is Class Error. ++* @param[in] u2ReasonCode A reason code to indicate why to leave BSS. ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. ++* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module ++* @retval WLAN_STATUS_FAILURE Didn't send Deauth frame for various reasons. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authSendDeauthFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_WLAN_MAC_HEADER_A4_T prWlanMacHeader = NULL; ++ PUINT_8 pucReceiveAddr; ++ PUINT_8 pucTransmitAddr; ++ PUINT_8 pucBssid = NULL; ++ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2RxFrameCtrl; ++ P_BSS_INFO_T prBssInfo; ++ ++ P_DEAUTH_INFO_T prDeauthInfo; ++ OS_SYSTIME rCurrentTime; ++ INT_32 i4NewEntryIndex, i; ++ UINT_8 ucStaRecIdx = STA_REC_INDEX_NOT_FOUND; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ UINT_8 aucBMC[] = BC_MAC_ADDR; ++#endif ++ ++ /* NOTE(Kevin): The best way to reply the Deauth is according to the incoming data ++ * frame ++ */ ++ /* 4 <1> Find the Receiver Address first. */ ++ if (prClassErrSwRfb) { ++ BOOLEAN fgIsAbleToSendDeauth = FALSE; ++ ++ prWlanMacHeader = (P_WLAN_MAC_HEADER_A4_T) prClassErrSwRfb->pvHeader; ++ ++ /* WLAN_GET_FIELD_16(&prWlanMacHeader->u2FrameCtrl, &u2RxFrameCtrl); */ ++ u2RxFrameCtrl = prWlanMacHeader->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* TODO(Kevin): Currently we won't send Deauth for IBSS node. How about DLS ? */ ++ if ((prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) == 0) ++ return WLAN_STATUS_FAILURE; ++ ++ /* Check if corresponding BSS is able to send Deauth */ ++ for (i = NETWORK_TYPE_AIS_INDEX; i < NETWORK_TYPE_INDEX_NUM; i++) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[i]); ++ ++ if (IS_NET_ACTIVE(prAdapter, i) && ++ (EQUAL_MAC_ADDR(prWlanMacHeader->aucAddr1, prBssInfo->aucOwnMacAddr))) { ++ { ++ fgIsAbleToSendDeauth = TRUE; ++ eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) i; ++ break; ++ } ++ } ++ } ++ ++ if (!fgIsAbleToSendDeauth) ++ return WLAN_STATUS_FAILURE; ++ ++ pucReceiveAddr = prWlanMacHeader->aucAddr2; ++ ++ } else if (prStaRec) { ++ ++ pucReceiveAddr = prStaRec->aucMacAddr; ++ } else { ++#if CFG_ENABLE_WIFI_DIRECT ++ pucReceiveAddr = aucBMC; ++#else ++ return WLAN_STATUS_FAILURE; ++#endif ++ } ++ ++ /* 4 <2> Check if already send a Deauth frame in MIN_DEAUTH_INTERVAL_MSEC */ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ i4NewEntryIndex = -1; ++ for (i = 0; i < MAX_DEAUTH_INFO_COUNT; i++) { ++ prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i]); ++ ++ /* For continuously sending Deauth frame, the minimum interval is ++ * MIN_DEAUTH_INTERVAL_MSEC. ++ */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, ++ prDeauthInfo->rLastSendTime, MSEC_TO_SYSTIME(MIN_DEAUTH_INTERVAL_MSEC))) { ++ ++ i4NewEntryIndex = i; ++ } else if (EQUAL_MAC_ADDR(pucReceiveAddr, prDeauthInfo->aucRxAddr) && (!pfTxDoneHandler)) { ++ ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++ /* 4 <3> Update information. */ ++ if (i4NewEntryIndex > 0) { ++ ++ prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i4NewEntryIndex]); ++ ++ COPY_MAC_ADDR(prDeauthInfo->aucRxAddr, pucReceiveAddr); ++ prDeauthInfo->rLastSendTime = rCurrentTime; ++ } else { ++ /* NOTE(Kevin): for the case of AP mode, we may encounter this case ++ * if deauth all the associated clients. ++ */ ++ DBGLOG(SAA, WARN, "No unused DEAUTH_INFO_T !\n"); ++ } ++ ++ /* 4 <4> Allocate a PKT_INFO_T for Deauthentication Frame */ ++ /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ ++ u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Deauth Request.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <5> Find the Transmitter Address and BSSID. */ ++ if (prClassErrSwRfb) { ++ ++ /* The TA of Deauth is the A1 of RX frame */ ++ pucTransmitAddr = prWlanMacHeader->aucAddr1; ++ ++ switch (prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) { ++ ++ case MASK_FC_FROM_DS: ++ /* The BSSID of Deauth is the A2 of RX frame */ ++ pucBssid = prWlanMacHeader->aucAddr2; ++ break; ++ ++ case MASK_FC_TO_DS: ++ /* The BSSID of Deauth is the A1 of RX frame */ ++ pucBssid = prWlanMacHeader->aucAddr1; ++ break; ++ ++ case MASK_TO_DS_FROM_DS: ++ /* TODO(Kevin): Consider BOW, now we set the BSSID of Deauth ++ * to the A2 of RX frame for temporary solution. ++ */ ++ pucBssid = prWlanMacHeader->aucAddr2; ++ break; ++ ++ /* No Default */ ++ } ++ ++ } else if (prStaRec) { ++ eNetTypeIndex = prStaRec->ucNetTypeIndex; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucBssid = prBssInfo->aucBSSID; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else { ++ if (prAdapter->fgIsP2PRegistered) { ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ ucStaRecIdx = STA_REC_INDEX_BMCAST; ++ ++ pucTransmitAddr = prBssInfo->aucOwnMacAddr; ++ ++ pucBssid = prBssInfo->aucBSSID; ++ ++ eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ } else { ++ /* 20130122: free packet by samplin */ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ return WLAN_STATUS_FAILURE; ++ } ++ } ++ ++#endif ++ ++ /* 4 <6> compose Deauthentication frame header and some fixed fields */ ++ authComposeDeauthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucReceiveAddr, pucTransmitAddr, pucBssid, u2ReasonCode); ++ ++#if CFG_SUPPORT_802_11W ++ if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ ++ prDeauthFrame = ++ (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ DBGLOG(TX, WARN, "authSendDeauthFrame with protection\n"); ++ } ++#endif ++ ++ /* 4 <7> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = ((prStaRec == NULL) ? ucStaRecIdx : prStaRec->ucIndex); ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ DBGLOG(SAA, INFO, "Sending Deauth, network: %d, seqNo %d\n", ++ eNetTypeIndex, prMsduInfo->ucTxSeqNum); ++ ++ /* 4 <8> Inform TXM to send this Deauthentication frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of authSendDeauthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Deauthentication frame ++* if the given BSSID is matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucBSSID Given BSSID ++* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. ++* ++* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) ++{ ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ UINT_16 u2RxReasonCode; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucBSSID); ++ ASSERT(pu2ReasonCode); ++ ++ /* 4 <1> locate the Deauthentication Frame. */ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Parse the Header of Deauthentication Frame. */ ++#if 0 /* Kevin: Seems redundant */ ++ WLAN_GET_FIELD_16(&prDeauthFrame->u2FrameCtrl, &u2RxFrameCtrl) ++ u2RxFrameCtrl &= MASK_FRAME_TYPE; ++ if (u2RxFrameCtrl != MAC_FRAME_DEAUTH) ++ return WLAN_STATUS_FAILURE; ++#endif ++ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Check if this Deauth Frame is coming from Target BSSID */ ++ if (UNEQUAL_MAC_ADDR(prDeauthFrame->aucBSSID, aucBSSID)) { ++ DBGLOG(SAA, LOUD, "Ignore Deauth Frame from other BSS [ %pM ]\n", ++ prDeauthFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ ++ WLAN_GET_FIELD_16(&prDeauthFrame->u2ReasonCode, &u2RxReasonCode); ++ *pu2ReasonCode = u2RxReasonCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxDeauthFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will parse and process the incoming Authentication frame. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] aucExpectedBSSID Given Expected BSSID. ++* @param[in] u2ExpectedAuthAlgNum Given Expected Authentication Algorithm Number ++* @param[in] u2ExpectedTransSeqNum Given Expected Transaction Sequence Number. ++* @param[out] pu2ReturnStatusCode Return Status Code. ++* ++* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. ++* @retval WLAN_STATUS_FAILURE The frame we will ignore. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN UINT_8 aucExpectedBSSID[], ++ IN UINT_16 u2ExpectedAuthAlgNum, ++ IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode) ++{ ++ P_WLAN_AUTH_FRAME_T prAuthFrame; ++ UINT_16 u2ReturnStatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ ASSERT(prSwRfb); ++ ASSERT(aucExpectedBSSID); ++ ASSERT(pu2ReturnStatusCode); ++ ++ /* 4 <1> locate the Authentication Frame. */ ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ /* 4 <2> Check the BSSID */ ++ if (UNEQUAL_MAC_ADDR(prAuthFrame->aucBSSID, aucExpectedBSSID)) ++ return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ ++ /* 4 <3> Check the SA, which should not be MC/BC */ ++ if (prAuthFrame->aucSrcAddr[0] & BIT(0)) { ++ DBGLOG(P2P, WARN, "Invalid STA MAC with MC/BC bit set: %pM\n", ++ prAuthFrame->aucSrcAddr); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 4 <4> Parse the Fixed Fields of Authentication Frame Body. */ ++ if (prAuthFrame->u2AuthAlgNum != u2ExpectedAuthAlgNum) ++ u2ReturnStatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; ++ ++ if (prAuthFrame->u2AuthTransSeqNo != u2ExpectedTransSeqNum) ++ u2ReturnStatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; ++ ++ *pu2ReturnStatusCode = u2ReturnStatusCode; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of authProcessRxAuth1Frame() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c +new file mode 100644 +index 000000000000..160779583655 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c +@@ -0,0 +1,2521 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/bss.c#3 ++*/ ++ ++/*! \file "bss.c" ++ \brief This file contains the functions for creating BSS(AP)/IBSS(AdHoc). ++ ++ This file contains the functions for BSS(AP)/IBSS(AdHoc). We may create a BSS/IBSS ++ network, or merge with exist IBSS network and sending Beacon Frame or reply ++ the Probe Response Frame for received Probe Request Frame. ++*/ ++ ++/* ++** Log: bss.c ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 14 2012 chinglan.wang ++ * NULL ++ * Fix the losing of the HT IE in assoc request.. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 08 2012 yuche.tsai ++ * NULL ++ * Fix FW assert when start Hot-Spot. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 20 2012 chinglan.wang ++ * 03 02 2012 terry.wu ++ * NULL ++ * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug. ++ * ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 15 2012 yuche.tsai ++ * NULL ++ * Fix wrong basic rate issue. ++ * ++ * 01 13 2012 yuche.tsai ++ * NULL ++ * WiFi Hot Spot Tethering for ICS ALPHA testing version. ++ * ++ * 11 03 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Always set short slot time to TRUE initially in AP mode ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 09 14 2011 yuche.tsai ++ * NULL ++ * Add P2P IE in assoc response. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 29 2011 eddie.chen ++ * [WCXRP00000608] [MT6620 Wi-Fi][DRV] Change wmm parameters in beacon ++ * Change wmm parameters in beacon. ++ * ++ * 03 29 2011 yuche.tsai ++ * [WCXRP00000607] [Volunteer Patch][MT6620][Driver] Coding Style Fix for klocwork scan. ++ * Fix klocwork issue. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Make assoc req to append P2P IE if wifi direct is enabled. ++ * ++ * 03 11 2011 chinglan.wang ++ * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. ++ * . ++ * ++ * 03 03 2011 george.huang ++ * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated ++ * . ++ * ++ * 03 03 2011 george.huang ++ * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated ++ * modify to handle if beacon MSDU been released when BSS deactivated ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * Add code to send beacon and probe response WSC IE at Auto GO. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 12 2011 yuche.tsai ++ * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. ++ * bss should create station record type according to callers input. ++ * ++ * 02 11 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * In p2p link function, check networktype before calling p2p function. ++ * ++ * 02 11 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Modify p2p link function to avoid assert. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 25 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Fix the compile error in windows. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 24 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * .Fix typo and missing entry ++ * ++ * 12 30 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Fix prBssInfo->aucCWminLog to prBssInfo->aucCWminLogForBcast ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++ ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * Finish SLT TX/RX & Rate Changing Support. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Before composing Beacon IE, assign network type index for msdu info, ++ * this information is needed by RLM module while composing some RLM related IE field. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Fix undefined pucDestAddr in bssUpdateBeaconContent() ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 08 02 2010 george.huang ++ * NULL ++ * add WMM-PS test related OID/ CMD handlers ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add support to RX probe response for P2P. ++ * ++ * 07 20 2010 cp.wu ++ * ++ * 1) bugfix: do not stop timer for join after switched into normal_tr state, for providing chance for DHCP handshasking ++ * 2) modify rsnPerformPolicySelection() invoking ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * when IBSS is being merged-in, send command packet to PM for connected indication ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error while enable WIFI_DIRECT support. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct when ADHOC support is turned on. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * auth.c is migrated. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fix compilation error when WIFI_DIRECT is turned on ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add bss.c. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update bssProcessProbeRequest() to avoid redundant SSID IE {0,0} for IOT. ++ * ++ * 05 21 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Use TX MGMT Frame API for sending PS NULL frame to avoid the TX Burst Mechanism in TX FW Frame API ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Separate Beacon and ProbeResp IE array ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed the use of compiling flag MQM_WMM_PARSING ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 20 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Fix restart Beacon Timeout Func after connection diagnosis ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the protected bit at cap info for ad-hoc. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename the CFG flags ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Update outgoing beacon's TX data rate ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add DTIM count update while TX Beacon ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify code due to define - BAND_24G and specific BSS_INFO_T was changed ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++APPEND_VAR_IE_ENTRY_T txBcnIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE}, /* 221 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++ {0, p2pFuncCalculateExtra_IELenForBeacon, p2pFuncGenerateExtra_IEForBeacon}, /* 221 */ ++#else ++ {0, p2pFuncCalculateP2p_IELenForBeacon, p2pFuncGenerateP2p_IEForBeacon}, /* 221 */ ++ {0, p2pFuncCalculateWSC_IELenForBeacon, p2pFuncGenerateWSC_IEForBeacon}, /* 221 */ ++ {0, p2pFuncCalculateP2P_IE_NoA, p2pFuncGenerateP2P_IE_NoA}, /* 221 */ ++#endif ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txProbRspIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ ++#if CFG_ENABLE_WIFI_DIRECT ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ ++#endif ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ ++ {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ ++}; ++ ++#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines for all Operation Modes */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will create or reset a STA_RECORD_T by given BSS_DESC_T for ++* Infrastructure or AdHoc Mode. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eStaType Assign STA Type for this STA_RECORD_T ++* @param[in] eNetTypeIndex Assign Net Type Index for this STA_RECORD_T ++* @param[in] prBssDesc Received Beacon/ProbeResp from this STA ++* ++* @retval Pointer to STA_RECORD_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T ++bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_STA_TYPE_T eStaType, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucNonHTPhyTypeSet; ++ ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> Get a valid STA_RECORD_T */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); ++ if (!prStaRec) { ++ ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) eNetTypeIndex); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ ++ if (!prStaRec) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ ASSERT(prStaRec); ++ ++ prStaRec->ucStaState = STA_STATE_1; ++ prStaRec->ucJoinFailureCount = 0; ++ /* TODO(Kevin): If this is an old entry, we may also reset the ucJoinFailureCount to 0. ++ */ ++ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prBssDesc->aucSrcAddr); ++ } ++ /* 4 <2> Setup STA TYPE and NETWORK */ ++ prStaRec->eStaType = eStaType; ++ ++ prStaRec->ucNetTypeIndex = eNetTypeIndex; ++ ++ /* 4 <3> Update information from BSS_DESC_T to current P_STA_RECORD_T */ ++ prStaRec->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ prStaRec->u2OperationalRateSet = prBssDesc->u2OperationalRateSet; ++ prStaRec->u2BSSBasicRateSet = prBssDesc->u2BSSBasicRateSet; ++ ++ prStaRec->ucPhyTypeSet = prBssDesc->ucPhyTypeSet; ++ if (IS_STA_IN_AIS(prStaRec)) { ++ if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) || ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_KEY_ABSENT) || ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION_DISABLED) || ++ (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) || (prAdapter->prGlueInfo->u2WapiAssocInfoIESz))) { ++ DBGLOG(BSS, TRACE, "Ignore the HT Bit for TKIP as pairwise cipher configured!\n"); ++ prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; ++ } ++ } else { ++ DBGLOG(BSS, TRACE, "P2P skip TKIP limitation for HT Hit!\n"); ++ } ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ ++ ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; ++ ++ /* Check for Target BSS's non HT Phy Types */ ++ if (ucNonHTPhyTypeSet) { ++ ++ if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = TRUE; ++ } else { ++ /* Use mandatory for 11N only BSS */ ++ ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); ++ ++ { ++ /* TODO(Kevin): which value should we set for 11n ? ERP ? */ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = FALSE; ++ } ++ ++ /* Update non HT Desired Rate Set */ ++ { ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ prStaRec->u2DesiredNonHTRateSet = ++ (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); ++ } ++ ++ /* 4 <4> Update information from BSS_DESC_T to current P_STA_RECORD_T */ ++ if (IS_AP_STA(prStaRec)) { ++ /* do not need to parse IE for DTIM, ++ * which have been parsed before inserting into BSS_DESC_T ++ */ ++ if (prBssDesc->ucDTIMPeriod) ++ prStaRec->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ else ++ prStaRec->ucDTIMPeriod = 0; /* Means that TIM was not parsed. */ ++ } ++ /* 4 <5> Update default value */ ++ prStaRec->fgDiagnoseConnection = FALSE; ++ ++ /* 4 <6> Update default value for other Modules */ ++ /* Determine fgIsWmmSupported and fgIsUapsdSupported in STA_REC */ ++ mqmProcessScanResult(prAdapter, prBssDesc, prStaRec); ++ ++ return prStaRec; ++ ++} /* end of bssCreateStaRecFromBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Null Data frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec) ++{ ++ P_WLAN_MAC_HEADER_T prNullFrame; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2FrameCtrl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo); ++ ++ prNullFrame = (P_WLAN_MAC_HEADER_T) pucBuffer; ++ ++ /* 4 <1> Decide the Frame Control Field */ ++ u2FrameCtrl = MAC_FRAME_NULL; ++ ++ if (IS_AP_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_TO_DS; ++ ++ if (prStaRec->fgSetPwrMgtBit) ++ u2FrameCtrl |= MASK_FC_PWR_MGT; ++ } else if (IS_CLIENT_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_FROM_DS; ++ } else if (IS_DLS_STA(prStaRec)) { ++ /* TODO(Kevin) */ ++ } else { ++ /* NOTE(Kevin): We won't send Null frame for IBSS */ ++ ASSERT(0); ++ return; ++ } ++ ++ /* 4 <2> Compose the Null frame */ ++ /* Fill the Frame Control field. */ ++ /* WLAN_SET_FIELD_16(&prNullFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Address 1 field with Target Peer Address. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr1, prStaRec->aucMacAddr); ++ ++ /* Fill the Address 2 field with our MAC Address. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); ++ ++ /* Fill the Address 3 field with Target BSSID. */ ++ COPY_MAC_ADDR(prNullFrame->aucAddr3, prBssInfo->aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prNullFrame->u2SeqCtrl = 0; ++ ++ return; ++ ++} /* end of bssComposeNullFrameHeader() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the QoS Null Data frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* @param[in] ucUP User Priority. ++* @param[in] fgSetEOSP Set the EOSP bit. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP) ++{ ++ P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; ++ P_BSS_INFO_T prBssInfo; ++ UINT_16 u2FrameCtrl; ++ UINT_16 u2QosControl; ++ ++ ASSERT(pucBuffer); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo); ++ ++ prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) pucBuffer; ++ ++ /* 4 <1> Decide the Frame Control Field */ ++ u2FrameCtrl = MAC_FRAME_QOS_NULL; ++ ++ if (IS_AP_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_TO_DS; ++ ++ if (prStaRec->fgSetPwrMgtBit) ++ u2FrameCtrl |= MASK_FC_PWR_MGT; ++ } else if (IS_CLIENT_STA(prStaRec)) { ++ u2FrameCtrl |= MASK_FC_FROM_DS; ++ } else if (IS_DLS_STA(prStaRec)) { ++ /* TODO(Kevin) */ ++ } else { ++ /* NOTE(Kevin): We won't send QoS Null frame for IBSS */ ++ ASSERT(0); ++ return; ++ } ++ ++ /* 4 <2> Compose the QoS Null frame */ ++ /* Fill the Frame Control field. */ ++ /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prQoSNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Address 1 field with Target Peer Address. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr1, prStaRec->aucMacAddr); ++ ++ /* Fill the Address 2 field with our MAC Address. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); ++ ++ /* Fill the Address 3 field with Target BSSID. */ ++ COPY_MAC_ADDR(prQoSNullFrame->aucAddr3, prBssInfo->aucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prQoSNullFrame->u2SeqCtrl = 0; ++ ++ u2QosControl = (UINT_16) (ucUP & WMM_QC_UP_MASK); ++ ++ if (fgSetEOSP) ++ u2QosControl |= WMM_QC_EOSP; ++ /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2QosCtrl, u2QosControl); */ ++ prQoSNullFrame->u2QosCtrl = u2QosControl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ return; ++ ++} /* end of bssComposeQoSNullFrameHeader() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the Null Frame ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Succe]ss. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeNullFrame(prAdapter, (PUINT_8) ((ULONG) prMsduInfo->prPacket + MAC_TX_RESERVED_FIELD), prStaRec); ++#if 0 ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ TXM_SET_DATA_PACKET( ++ /* STA_REC ptr */ prStaRec, ++ /* MSDU_INFO ptr */ prMsduInfo, ++ /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), ++ /* MAC HDR length */ WLAN_MAC_HEADER_LEN, ++ /* PAYLOAD ptr */ ++ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN), ++ /* PAYLOAD length */ 0, ++ /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, ++ /* TID */ 0 /* BE: AC1 */ , ++ /* Flag 802.11 */ TRUE, ++ /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , ++ /* Resource TC */ 0 /* Irrelevant */ , ++ /* Flag 802.1x */ FALSE, ++ /* TX-done callback */ pfTxDoneHandler, ++ /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, ++ /* PS Session ID */ 0 /* Irrelevant */ , ++ /* Flag fixed rate */ TRUE, ++ /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, ++ /* Fixed-rate retry */ BSS_DEFAULT_CONN_TEST_NULL_FRAME_RETRY_LIMIT, ++ /* PAL LLH */ 0 /* Irrelevant */ , ++ /* ACL SN */ 0 /* Irrelevant */ , ++ /* Flag No Ack */ FALSE ++ ); ++ ++ /* Terminate with a NULL pointer */ ++ NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* Indicate the packet to TXM */ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ txmSendFwDataPackets(prMsduInfo); ++#endif ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendNullFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the QoS Null Frame ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] pfTxDoneHandler TX Done call back function ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeQoSNullFrame(prAdapter, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec, ucUP, FALSE); ++#if 0 ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ TXM_SET_DATA_PACKET( ++ /* STA_REC ptr */ prStaRec, ++ /* MSDU_INFO ptr */ prMsduInfo, ++ /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), ++ /* MAC HDR length */ WLAN_MAC_HEADER_QOS_LEN, ++ /* PAYLOAD ptr */ ++ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN), ++ /* PAYLOAD length */ 0, ++ /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, ++ /* TID */ 0 /* BE: AC1 */ , ++ /* Flag 802.11 */ TRUE, ++ /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , ++ /* Resource TC */ 0 /* Irrelevant */ , ++ /* Flag 802.1x */ FALSE, ++ /* TX-done callback */ pfTxDoneHandler, ++ /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, ++ /* PS Session ID */ 0 /* Irrelevant */ , ++ /* Flag fixed rate */ TRUE, ++ /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, ++ /* Fixed-rate retry */ TXM_DEFAULT_DATA_FRAME_RETRY_LIMIT, ++ /* PAL LLH */ 0 /* Irrelevant */ , ++ /* ACL SN */ 0 /* Irrelevant */ , ++ /* Flag No Ack */ FALSE ++ ); ++ ++ /* Terminate with a NULL pointer */ ++ NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* Indicate the packet to TXM */ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ txmSendFwDataPackets(prMsduInfo); ++#endif ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendQoSNullFrame() */ ++ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++/*----------------------------------------------------------------------------*/ ++/* Routines for both IBSS(AdHoc) and BSS(AP) */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate Information Elements of Extended ++* Support Rate ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ PUINT_8 pucBuffer; ++ UINT_8 ucExtSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); ++ ASSERT(prBssInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ++ ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; ++ else ++ ucExtSupRatesLen = 0; ++ ++ /* Fill the Extended Supported Rates element. */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, ++ &prBssInfo->aucAllSupportedRates[ELEM_MAX_LEN_SUP_RATES], ucExtSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* end of bssGenerateExtSuppRate_IE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for Beacon ++* or Probe Response Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr) ++{ ++ PUINT_8 pucBuffer; ++ UINT_8 ucSupRatesLen; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prBssInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ASSERT(pucBuffer); ++ ++ /* Compose the frame body of the Probe Response frame. */ ++ /* 4 <1> Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ if (prBssInfo->eHiddenSsidType == ENUM_HIDDEN_SSID_LEN) { ++ if ((!pucDestAddr) && /* For Beacon only */ ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ SSID_IE(pucBuffer)->ucLength = 0; ++ } else { /* Probe response */ ++ SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; ++ if (prBssInfo->ucSSIDLen) ++ kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ } ++ } else { ++ SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; ++ if (prBssInfo->ucSSIDLen) ++ kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ } ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ /* 4 <2> Fill the Supported Rates element. */ ++ if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ++ ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; ++ else ++ ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; ++ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <3> Fill the DS Parameter Set element. */ ++ if (prBssInfo->eBand == BAND_2G4) { ++ DS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_DS_PARAM_SET; ++ DS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_DS_PARAMETER_SET; ++ DS_PARAM_IE(pucBuffer)->ucCurrChnl = prBssInfo->ucPrimaryChannel; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <4> IBSS Parameter Set element, ID: 6 */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ IBSS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_IBSS_PARAM_SET; ++ IBSS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_IBSS_PARAMETER_SET; ++ WLAN_SET_FIELD_16(&(IBSS_PARAM_IE(pucBuffer)->u2ATIMWindow), prBssInfo->u2ATIMWindow); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ } ++ /* 4 <5> TIM element, ID: 5 */ ++ if ((!pucDestAddr) && /* For Beacon only. */ ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*no fgIsP2PRegistered protect */ ++ if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++#if 0 ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ UINT_8 ucBitmapControl = 0; ++ UINT_32 u4N1, u4N2; ++ ++ prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); ++ ++ /* Clear existing value. */ ++ prP2pSpecificBssInfo->ucBitmapCtrl = 0; ++ kalMemZero(prP2pSpecificBssInfo->aucPartialVirtualBitmap, ++ sizeof(prP2pSpecificBssInfo->aucPartialVirtualBitmap)); ++ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucDTIMCount = prBssInfo->ucDTIMCount; ++ TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; ++ ++ /* Setup DTIM Count for next TBTT. */ ++ if (prBssInfo->ucDTIMCount == 0) { ++ /*Do nothing*/ ++ /* 3 *** pmQueryBufferedBCAST(); */ ++ } ++ /* 3 *** pmQueryBufferedPSNode(); */ ++ /* TODO(Kevin): Call PM Module here to loop all STA_RECORD_Ts and it ++ * will call bssSetTIMBitmap to toggle the Bitmap. ++ */ ++ ++ /* Set Virtual Bitmap for UCAST */ ++ u4N1 = (prP2pSpecificBssInfo->u2SmallestAID >> 4) << 1; /* Find the largest even number. */ ++ u4N2 = prP2pSpecificBssInfo->u2LargestAID >> 3; /* Find the smallest number. */ ++ ++ ASSERT(u4N2 >= u4N1); ++ ++ kalMemCopy(TIM_IE(pucBuffer)->aucPartialVirtualMap, ++ &prP2pSpecificBssInfo->aucPartialVirtualBitmap[u4N1], ((u4N2 - u4N1) + 1)); ++ ++ /* Set Virtual Bitmap for BMCAST */ ++ /* BMC bit only indicated when DTIM count == 0. */ ++ if (prBssInfo->ucDTIMCount == 0) ++ ucBitmapControl = prP2pSpecificBssInfo->ucBitmapCtrl; ++ TIM_IE(pucBuffer)->ucBitmapControl = ucBitmapControl | (UINT_8) u4N1; ++ ++ TIM_IE(pucBuffer)->ucLength = ((u4N2 - u4N1) + 4); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++#else ++ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP); /*((u4N2 - u4N1) + 4) */ ++ /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0; /*prBssInfo->ucDTIMCount */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; ++ /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucBitmapControl = 0; /*ucBitmapControl | (UINT_8)u4N1 */ ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ ++#endif ++ ++ } else ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ { ++ /* NOTE(Kevin): 1. AIS - Didn't Support AP Mode. ++ * 2. BOW - Didn't Support BCAST and PS. ++ */ ++ } ++ ++ } ++ ++} /* end of bssBuildBeaconProbeRespFrameCommonIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Beacon/Probe Response frame header and ++* its fixed fields. ++* ++* @param[in] pucBuffer Pointer to the frame buffer. ++* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. ++* @param[in] pucOwnMACAddress Given Our MAC Address. ++* @param[in] pucBSSID Given BSSID of the BSS. ++* @param[in] u2BeaconInterval Given Beacon Interval. ++* @param[in] u2CapInfo Given Capability Info. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, ++ IN PUINT_8 pucDestAddr, ++ IN PUINT_8 pucOwnMACAddress, ++ IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo) ++{ ++ P_WLAN_BEACON_FRAME_T prBcnProbRspFrame; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ UINT_16 u2FrameCtrl; ++ ++ DEBUGFUNC("bssComposeBeaconProbeRespFrameHeaderAndFF"); ++ /* DBGLOG(INIT, LOUD, ("\n")); */ ++ ++ ASSERT(pucBuffer); ++ ASSERT(pucOwnMACAddress); ++ ASSERT(pucBSSID); ++ ++ prBcnProbRspFrame = (P_WLAN_BEACON_FRAME_T) pucBuffer; ++ ++ /* 4 <1> Compose the frame header of the Beacon /ProbeResp frame. */ ++ /* Fill the Frame Control field. */ ++ if (pucDestAddr) { ++ u2FrameCtrl = MAC_FRAME_PROBE_RSP; ++ } else { ++ u2FrameCtrl = MAC_FRAME_BEACON; ++ pucDestAddr = aucBCAddr; ++ } ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2FrameCtrl, u2FrameCtrl); */ ++ prBcnProbRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the DA field with BCAST MAC ADDR or TA of ProbeReq. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucDestAddr, pucDestAddr); ++ ++ /* Fill the SA field with our MAC Address. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucSrcAddr, pucOwnMACAddress); ++ ++ /* Fill the BSSID field with current BSSID. */ ++ COPY_MAC_ADDR(prBcnProbRspFrame->aucBSSID, pucBSSID); ++ ++ /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ ++ prBcnProbRspFrame->u2SeqCtrl = 0; ++ ++ /* 4 <2> Compose the frame body's common fixed field part of the Beacon /ProbeResp frame. */ ++ /* MAC will update TimeStamp field */ ++ ++ /* Fill the Beacon Interval field. */ ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2BeaconInterval, u2BeaconInterval); */ ++ prBcnProbRspFrame->u2BeaconInterval = u2BeaconInterval; /* NOTE(Kevin): Optimized for ARM */ ++ ++ /* Fill the Capability Information field. */ ++ /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2CapInfo, u2CapInfo); */ ++ prBcnProbRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ ++ ++} /* end of bssComposeBeaconProbeRespFrameHeaderAndFF() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the Beacon Frame Template to FW for AIS AdHoc and P2P GO. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eNetTypeIndex Specify which network reply the Probe Response. ++* ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_WLAN_BEACON_FRAME_T prBcnFrame; ++ UINT_32 i; ++ ++ DEBUGFUNC("bssUpdateBeaconContent"); ++ DBGLOG(BSS, LOUD, "\n"); ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Beacon Frame */ ++ /* Allocate a MSDU_INFO_T */ ++ /* For Beacon */ ++ prMsduInfo = prBssInfo->prBeacon; ++ ++ /* beacon prMsduInfo will be NULLify once BSS deactivated, so skip if it is */ ++ if (prMsduInfo == NULL) ++ return WLAN_STATUS_SUCCESS; ++ /* 4 <2> Compose header */ ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ NULL, ++ prBssInfo->aucOwnMacAddr, ++ prBssInfo->aucBSSID, ++ prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); ++ ++ prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); ++ ++ prMsduInfo->ucNetworkType = eNetTypeIndex; ++ ++ /* 4 <3> Compose the frame body's Common IEs of the Beacon frame. */ ++ bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, NULL); ++ ++ /* 4 <4> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE for Beacon */ ++ for (i = 0; i < sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { ++ if (txBcnIETable[i].pfnAppendIE) ++ txBcnIETable[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; ++ ++ return nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ eNetTypeIndex, ++ prBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); ++ ++} /* end of bssUpdateBeaconContent() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send the Beacon Frame(for BOW) or Probe Response Frame according to the given ++* Destination Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eNetTypeIndex Specify which network reply the Probe Response. ++* @param[in] pucDestAddr Pointer to the Destination Address to reply ++* @param[in] u4ControlFlags Control flags for information on Probe Response. ++* ++* @retval WLAN_STATUS_RESOURCE No available resources to send frame. ++* @retval WLAN_STATUS_SUCCESS Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ UINT_16 u2EstimatedFixedIELen; ++ UINT_16 u2EstimatedExtraIELen; ++ P_APPEND_VAR_IE_ENTRY_T prIeArray = NULL; ++ UINT_32 u4IeArraySize = 0; ++ UINT_32 i; ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (!pucDestAddr) { /* For Beacon */ ++ prIeArray = &txBcnIETable[0]; ++ u4IeArraySize = sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ } else { ++ prIeArray = &txProbRspIETable[0]; ++ u4IeArraySize = sizeof(txProbRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ } ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Beacon /Probe Response Frame */ ++ /* Allocate a MSDU_INFO_T */ ++ ++ /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Fields */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + ++ WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + ++ BEACON_INTERVAL_FIELD_LEN + ++ CAP_INFO_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_IBSS_PARAMETER_SET) + (ELEM_HDR_LEN + (3 + MAX_LEN_TIM_PARTIAL_BMP)); ++ ++ /* + Extra IE Length */ ++ u2EstimatedExtraIELen = 0; ++ ++ for (i = 0; i < u4IeArraySize; i++) { ++ u2EstimatedFixedIELen = prIeArray[i].u2EstimatedFixedIELen; ++ ++ if (u2EstimatedFixedIELen) { ++ u2EstimatedExtraIELen += u2EstimatedFixedIELen; ++ } else { ++ ASSERT(prIeArray[i].pfnCalculateVariableIELen); ++ ++ u2EstimatedExtraIELen += (UINT_16) ++ prIeArray[i].pfnCalculateVariableIELen(prAdapter, eNetTypeIndex, NULL); ++ } ++ } ++ ++ u2EstimatedFrameLen += u2EstimatedExtraIELen; ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(BSS, WARN, "No PKT_INFO_T for sending %s.\n", ((!pucDestAddr) ? "Beacon" : "Probe Response")); ++ return WLAN_STATUS_RESOURCES; ++ } ++ /* 4 <2> Compose Beacon/Probe Response frame header and fixed fields in MSDU_INfO_T. */ ++ /* Compose Header and Fixed Field */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (u4ControlFlags & BSS_PROBE_RESP_USE_P2P_DEV_ADDR) { ++ if (prAdapter->fgIsP2PRegistered) { ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prMsduInfo->prPacket) + ++ MAC_TX_RESERVED_FIELD), pucDestAddr, ++ prAdapter->rWifiVar.aucDeviceAddress, ++ prAdapter->rWifiVar.aucDeviceAddress, ++ DOT11_BEACON_PERIOD_DEFAULT, ++ (prBssInfo->u2CapInfo & ++ ~(CAP_INFO_ESS | CAP_INFO_IBSS))); ++ } ++ } else ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ { ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ pucDestAddr, prBssInfo->aucOwnMacAddr, prBssInfo->aucBSSID, ++ prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); ++ } ++ ++ /* 4 <3> Update information of MSDU_INFO_T */ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = 0xFF; ++ prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ /* 4 <4> Compose the frame body's Common IEs of the Beacon/ProbeResp frame. */ ++ bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, pucDestAddr); ++ ++ /* 4 <5> Compose IEs in MSDU_INFO_T */ ++ ++ /* Append IE */ ++ for (i = 0; i < u4IeArraySize; i++) { ++ if (prIeArray[i].pfnAppendIE) ++ prIeArray[i].pfnAppendIE(prAdapter, prMsduInfo); ++ } ++ ++ /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ ++ ++ /* 4 <6> Inform TXM to send this Beacon /Probe Response frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssSendBeaconProbeResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Probe Request Frame and then send ++* back the corresponding Probe Response Frame if the specified conditions ++* were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ BOOLEAN fgIsBcBssid; ++ BOOLEAN fgReplyProbeResp; ++ UINT_32 u4CtrlFlagsForProbeResp = 0; ++ ENUM_BAND_T eBand; ++ UINT_8 ucHwChannelNum; ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> Parse Probe Req and Get BSSID */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ if (EQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID)) ++ fgIsBcBssid = TRUE; ++ else ++ fgIsBcBssid = FALSE; ++ ++ /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ ++ for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { ++ ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ continue; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if ((!fgIsBcBssid) && UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) ++ continue; ++ ++ eBand = HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr); ++ ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); ++ ++ if (prBssInfo->eBand != eBand) ++ continue; ++ ++ if (prBssInfo->ucPrimaryChannel != ucHwChannelNum) ++ continue; ++ ++ fgReplyProbeResp = FALSE; ++ ++ if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { ++ ++#if CFG_SUPPORT_ADHOC ++ fgReplyProbeResp = aisValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++#endif ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex)) { ++ if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { ++ /* Resource margin is enough */ ++ fgReplyProbeResp = ++ p2pFuncValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++ } ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) ++ fgReplyProbeResp = bowValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); ++#endif ++ ++ if (fgReplyProbeResp) { ++ if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { ++ /* Resource margin is enough */ ++ bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr, ++ u4CtrlFlagsForProbeResp); ++ } ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssProcessProbeRequest() */ ++ ++#if 0 /* NOTE(Kevin): condition check should move to P2P_FSM.c */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Probe Request Frame and then send ++* back the corresponding Probe Response Frame if the specified conditions ++* were matched. ++* ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always return success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; ++ P_BSS_INFO_T prBssInfo; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ BOOLEAN fgReplyProbeResp; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgP2PTargetDeviceFound; ++ UINT_8 aucP2PWildcardSSID[] = P2P_WILDCARD_SSID; ++#endif ++ ++ ASSERT(prSwRfb); ++ ++ /* 4 <1> Parse Probe Req and Get SSID IE ptr */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; ++ pucIE = (PUINT_8) ((UINT_32) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); ++ ++ prIeSsid = (P_IE_SSID_T) NULL; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SUP_RATES) { */ ++ if (IE_LEN(pucIE) <= RATE_NUM) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* TODO: P2P IE & WCS IE parsing for P2P. */ ++ case ELEM_ID_P2P: ++ ++ break; ++#endif ++ ++ /* no default */ ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ ++ for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { ++ ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ continue; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (UNEQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID) && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { ++ /* BSSID not Wildcard BSSID. */ ++ continue; ++ } ++ ++ fgReplyProbeResp = FALSE; ++ ++ if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ ++ /* TODO(Kevin): Check if we are IBSS Master. */ ++ if (TRUE && prIeSsid) { ++ if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex) { ++ ++ /* TODO(Kevin): Move following lines to p2p_fsm.c */ ++ ++ if ((prIeSsid) && ++ ((prIeSsid->ucLength == BC_SSID_LEN) || ++ (EQUAL_SSID(aucP2PWildcardSSID, ++ P2P_WILDCARD_SSID_LEN, prIeSsid->aucSSID, prIeSsid->ucLength)))) { ++ /* if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prMgtHdr->aucSrcAddr, ++ pucIE, u2IELength)) { */ ++ if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prSwRfb)) { ++ /* Extand channel request time & cancel scan request. */ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ /* TODO: RX probe request may not caused by LISTEN state. */ ++ /* TODO: It can be GO. */ ++ /* Generally speaking, cancel a non-exist scan request is fine. ++ * We can check P2P FSM here for only LISTEN state. ++ */ ++ ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ /* Abort JOIN process. */ ++ prScanCancelMsg = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ ASSERT(0); /* Can't abort SCN FSM */ ++ continue; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucSeqNum = prP2pFsmInfo->ucSeqNumOfScnMsg; ++ prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ prScanCancelMsg->fgIsChannelExt = TRUE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); ++ } ++ } else { ++ /* 1. Probe Request without SSID. ++ * 2. Probe Request with SSID not Wildcard SSID & not P2P Wildcard SSID. ++ */ ++ continue; ++ } ++ ++#if 0 /* Frog */ ++ if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_LISTEN) { ++ /* P2P 2.4.1 - P2P Devices shall not respond to Probe Request frames ++ which only contain 11b rates only. */ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ UINT_16 u2OperationalRateSet, u2BSSBasicRateSet; ++ BOOLEAN fgIsUnknownBssBasicRate; ++ ++ rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, ++ &u2OperationalRateSet, ++ &u2BSSBasicRateSet, /* Ignore any Basic Bit */ ++ &fgIsUnknownBssBasicRate); ++ ++ if (u2OperationalRateSet & ~RATE_SET_HR_DSSS) ++ continue; ++ } ++ } ++ /* TODO: Check channel time before first check point to: */ ++ /* If Target device is selected: ++ * 1. Send XXXX request frame. ++ * else ++ * 1. Send Probe Response frame. ++ */ ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* TODO(Kevin): During PROVISION state, can we reply Probe Response ? */ ++ ++ /* TODO(Kevin): ++ * If we are GO, accept legacy client --> accept Wildcard SSID ++ * If we are in Listen State, accept only P2P Device --> check P2P IE and WPS IE ++ */ ++ if (TRUE /* We are GO */ && prIeSsid) { ++ UINT_8 aucSSID[] = P2P_WILDCARD_SSID; ++ ++ if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ ++ EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, ++ prIeSsid->aucSSID, prIeSsid->ucLength) || ++ EQUAL_SSID(aucSSID, P2P_WILDCARD_SSID_LEN, ++ prIeSsid->aucSSID, prIeSsid->ucLength)) { ++ fgReplyProbeResp = TRUE; ++ } ++ } ++/* else if (FALSE) { */ /* We are in Listen State */ ++/* } */ ++ ++ /* TODO(Kevin): Check P2P IE and WPS IE */ ++ } ++#endif ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) { ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* Do nothing */ ++ /* TODO(Kevin): TBD */ ++ } ++ } ++#endif ++ else ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ if (fgReplyProbeResp) ++ bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr); ++ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of bssProcessProbeRequest() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to clear the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prPeerStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prPeerStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ cnmStaRecChangeState(prAdapter, prPeerStaRec, STA_STATE_1); ++ } ++ ++ LINK_INITIALIZE(prStaRecOfClientList); ++ } ++ ++} /* end of bssClearClientList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to Add a STA_RECORD_T to the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ ++ if (prCurrStaRec == prStaRec) { ++ DBGLOG(BSS, WARN, ++ "Current Client List already contains that STA_RECORD_T[%pM]\n", ++ prStaRec->aucMacAddr); ++ return; ++ } ++ } ++ } ++ ++ LINK_INSERT_TAIL(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ ++} /* end of bssAddStaRecToClientList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to Remove a STA_RECORD_T from the client list for AdHoc or AP Mode ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ ++#if 0 ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ ++ if (prCurrStaRec == prStaRec) { ++ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ ++ return; ++ } ++ } ++ } ++#endif ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); ++ return; ++ } ++ } ++ } ++ ++ DBGLOG(BSS, INFO, "Current Client List didn't contain that STA_RECORD_T[%pM] before removing.\n", ++ prStaRec->aucMacAddr); ++ ++} /* end of bssRemoveStaRecFromClientList() */ ++#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get station record by Address for AP mode ++* ++* @param[in] prBssInfo Pointer to BSS_INFO_T. ++* @param[in] pucMacAddr Pointer to target mac address ++* ++* @return pointer of STA_RECORD_T if found, otherwise, return NULL ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr) ++{ ++ P_LINK_T prStaRecOfClientList; ++ ++ ASSERT(prBssInfo); ++ ASSERT(pucMacAddr); ++ ++ prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; ++ if (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, pucMacAddr)) ++ return prCurrStaRec; ++ } ++ } ++ return NULL; ++} ++ ++#if CFG_SUPPORT_ADHOC ++/*----------------------------------------------------------------------------*/ ++/* Routines for IBSS(AdHoc) only */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to process Beacons from current Ad-Hoc network peers. ++* We also process Beacons from other Ad-Hoc network during SCAN. If it has ++* the same SSID and we'll decide to merge into it if it has a larger TSF. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] prBSSDesc Pointer to the BSS Descriptor. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI) ++{ ++ P_STA_RECORD_T prStaRec = NULL; ++ ++ BOOLEAN fgIsCheckCapability = FALSE; ++ BOOLEAN fgIsCheckTSF = FALSE; ++ BOOLEAN fgIsGoingMerging = FALSE; ++ BOOLEAN fgIsSameBSSID; ++ ++ ASSERT(prBssInfo); ++ ASSERT(prBssDesc); ++ ++ /* 4 <1> Process IBSS Beacon only after we create or merge with other IBSS. */ ++ if (!prBssInfo->fgIsBeaconActivated) ++ return; ++ /* 4 <2> Get the STA_RECORD_T of TA. */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prBssDesc->aucSrcAddr); ++ ++ fgIsSameBSSID = UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID) ? FALSE : TRUE; ++ ++ /* 4 <3> IBSS Merge Decision Flow for Processing Beacon. */ ++ if (fgIsSameBSSID) { ++ ++ /* Same BSSID: ++ * Case I. This is a new TA and it has decide to merged with us. ++ * a) If fgIsMerging == FALSE - we will send msg to notify AIS. ++ * b) If fgIsMerging == TRUE - already notify AIS. ++ * Case II. This is an old TA and we've already merged together. ++ */ ++ if (!prStaRec) { ++ ++ /* For Case I - Check this IBSS's capability first before adding this Sta Record. */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, then we perform merging with this new IBSS */ ++ fgIsGoingMerging = TRUE; ++ ++ } else { ++ ++ ASSERT((prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) && IS_ADHOC_STA(prStaRec)); ++ ++ if (prStaRec->ucStaState != STA_STATE_3) { ++ ++ if (!prStaRec->fgIsMerging) { ++ ++ /* For Case I - Check this IBSS's capability first ++ * before adding this Sta Record. */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, then we perform merging with this new IBSS */ ++ fgIsGoingMerging = TRUE; ++ } else { ++ /* For Case II - Update rExpirationTime of Sta Record */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ } ++ } else { ++ /* For Case II - Update rExpirationTime of Sta Record */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ } ++ ++ } ++ } else { ++ ++ /* Unequal BSSID: ++ * Case III. This is a new TA and we need to compare the TSF and get the winner. ++ * Case IV. This is an old TA and it merge into a new IBSS before we do the same thing. ++ * We need to compare the TSF to get the winner. ++ * Case V. This is an old TA and it restart a new IBSS. We also need to ++ * compare the TSF to get the winner. ++ */ ++ ++ /* For Case III, IV & V - We'll always check this new IBSS's capability first ++ * before merging into new IBSS. ++ */ ++ fgIsCheckCapability = TRUE; ++ ++ /* If check is passed, we need to perform TSF check to decide the major BSSID */ ++ fgIsCheckTSF = TRUE; ++ ++ /* For Case IV & V - We won't update rExpirationTime of Sta Record */ ++ } ++ ++ /* 4 <7> Check this BSS_DESC_T's capability. */ ++ if (fgIsCheckCapability) { ++ BOOLEAN fgIsCapabilityMatched = FALSE; ++ ++ do { ++ if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Unsupported Phy.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ if (prBssDesc->fgIsUnknownBssBasicRate) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Unknown Basic Rate.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", ++ prBssDesc->aucSrcAddr); ++ ++ break; ++ } ++ ++ fgIsCapabilityMatched = TRUE; ++ } while (FALSE); ++ ++ if (!fgIsCapabilityMatched) { ++ ++ if (prStaRec) { ++ /* For Case II - We merge this STA_RECORD in RX Path. ++ * Case IV & V - They change their BSSID after we merge with them. ++ */ ++ ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", ++ prBssDesc->aucSrcAddr); ++ } ++ ++ return; ++ } ++ ++ DBGLOG(BSS, LOUD, ++ "IBSS MERGE: Peer MAC: %pM - Check capability was passed.\n", ++ prBssDesc->aucSrcAddr); ++ } ++ ++ if (fgIsCheckTSF) { ++#if CFG_SLT_SUPPORT ++ fgIsGoingMerging = TRUE; ++#else ++ if (prBssDesc->fgIsLargerTSF) ++ fgIsGoingMerging = TRUE; ++ else ++ return; ++#endif ++ } ++ ++ if (fgIsGoingMerging) { ++ P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; ++ ++ /* 4 <1> We will merge with to this BSS immediately. */ ++ prBssDesc->fgIsConnecting = TRUE; ++ prBssDesc->fgIsConnected = FALSE; ++ ++ /* 4 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, ++ STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); ++ ++ if (!prStaRec) { ++ /* no memory ? */ ++ return; ++ } ++ ++ prStaRec->fgIsMerging = TRUE; ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = ucRCPI; ++ ++ /* 4 <3> Send Merge Msg to CNM to obtain the channel privilege. */ ++ prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_IBSS_PEER_FOUND_T)); ++ ++ if (!prAisIbssPeerFoundMsg) { ++ ++ ASSERT(0); /* Can't send Merge Msg */ ++ return; ++ } ++ ++ prAisIbssPeerFoundMsg->rMsgHdr.eMsgId = MID_SCN_AIS_FOUND_IBSS; ++ prAisIbssPeerFoundMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; ++ prAisIbssPeerFoundMsg->prStaRec = prStaRec; ++ ++ /* Inform AIS to do STATE TRANSITION ++ * For Case I - If AIS in IBSS_ALONE, let it jump to NORMAL_TR after we know the new member. ++ * For Case III, IV - Now this new BSSID wins the TSF, follow it. ++ */ ++ if (fgIsSameBSSID) { ++ prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; ++ } else { ++#if CFG_SLT_SUPPORT ++ prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; ++#else ++ prAisIbssPeerFoundMsg->fgIsMergeIn = (prBssDesc->fgIsLargerTSF) ? FALSE : TRUE; ++#endif ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisIbssPeerFoundMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++} /* end of ibssProcessMatchedBeacon() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the Capability for Ad-Hoc to decide if we are ++* able to merge with(same capability). ++* ++* @param[in] prBSSDesc Pointer to the BSS Descriptor. ++* ++* @retval WLAN_STATUS_FAILURE Can't pass the check of Capability. ++* @retval WLAN_STATUS_SUCCESS Pass the check of Capability. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ ++ ASSERT(prBssDesc); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ do { ++ /* 4 <1> Check the BSS Basic Rate Set for current AdHoc Mode */ ++ if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11B) && ++ (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_HR_DSSS)) { ++ break; ++ } else if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11A) && ++ (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_OFDM)) { ++ break; ++ } ++ /* 4 <2> Check the Short Slot Time. */ ++#if 0 /* Do not check ShortSlotTime until Wi-Fi define such policy */ ++ if (prConnSettings->eAdHocMode == AD_HOC_MODE_11G) { ++ if (((prConnSettings->fgIsShortSlotTimeOptionEnable) && ++ !(prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) || ++ (!(prConnSettings->fgIsShortSlotTimeOptionEnable) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))) { ++ break; ++ } ++ } ++#endif ++ ++ /* 4 <3> Check the ATIM window setting. */ ++ if (prBssDesc->u2ATIMWindow) { ++ DBGLOG(BSS, INFO, "AdHoc PS was not supported(ATIM Window: %d)\n", prBssDesc->u2ATIMWindow); ++ break; ++ } ++#if CFG_RSN_MIGRATION ++ /* 4 <4> Check the Security setting. */ ++ if (!rsnPerformPolicySelection(prAdapter, prBssDesc)) ++ break; ++#endif ++ ++ rStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rStatus; ++ ++} /* end of ibssCheckCapabilityForAdHocMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial the BSS_INFO_T for IBSS Mode. ++* ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++ UINT_8 ucLowestBasicRateIndex; ++ UINT_8 aucBSSID[MAC_ADDR_LEN]; ++ PUINT_16 pu2BSSID = (PUINT_16) &aucBSSID[0]; ++ UINT_32 i; ++ ++ ASSERT(prBssInfo); ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_IBSS); ++ ++ /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ ++ /* 4 <2> Setup BSSID */ ++ if (!prBssInfo->fgHoldSameBssidForIBSS) { ++ ++ for (i = 0; i < sizeof(aucBSSID) / sizeof(UINT_16); i++) ++ pu2BSSID[i] = (UINT_16) (kalRandomNumber() & 0xFFFF); ++ ++ aucBSSID[0] &= ~0x01; /* 7.1.3.3.3 - The individual/group bit of the address is set to 0. */ ++ aucBSSID[0] |= 0x02; /* 7.1.3.3.3 - The universal/local bit of the address is set to 1. */ ++ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, aucBSSID); ++ } ++ /* 4 <3> Setup Capability - Short Preamble */ ++ if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 4 <4> Setup Capability - Short Slot Time */ ++ /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ ++ prBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ ++ ++ /* 4 <5> Compoase Capability */ ++ prBssInfo->u2CapInfo = CAP_INFO_IBSS; ++ ++ if (prBssInfo->fgIsProtection) ++ prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; ++ ++ if (prBssInfo->fgIsShortPreambleAllowed) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ ++ if (prBssInfo->fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); ++ ++ prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; ++ ++} /* end of ibssInitForAdHoc() */ ++ ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++#if CFG_SUPPORT_AAA ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines for BSS(AP) only */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial the BSS_INFO_T for AP Mode. ++* ++* @param[in] prBssInfo Given related BSS_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate) ++{ ++ UINT_8 ucLowestBasicRateIndex; ++ ++ P_AC_QUE_PARMS_T prACQueParms; ++ ++ ENUM_WMM_ACI_T eAci; ++ ++ UINT_8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; ++ UINT_8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3 }; ++ UINT_8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; ++ UINT_8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ ++ ++ UINT_8 auCWminLog2[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; ++ UINT_8 auCWmaxLog2[WMM_AC_INDEX_NUM] = { 7, 10, 4, 3 }; ++ UINT_8 auAifs[WMM_AC_INDEX_NUM] = { 3, 7, 1, 1 }; ++ UINT_8 auTxop[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ ++ ++ DEBUGFUNC("bssInitForAP"); ++ DBGLOG(BSS, LOUD, "\n"); ++ ++ ASSERT(prBssInfo); ++ ASSERT((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || (prBssInfo->eCurrentOPMode == OP_MODE_BOW)); ++ ++#if 0 ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = CONFIG_BW_20M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = CONFIG_BW_20M; ++#endif ++ ++ /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ if (fgIsRateUpdate) { ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); ++ } ++ /* 4 <2> Setup BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssInfo->aucOwnMacAddr); ++ ++ /* 4 <3> Setup Capability - Short Preamble */ ++ if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && ++ ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ ++ (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ ++ /* 4 <4> Setup Capability - Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = TRUE; ++ ++ /* 4 <5> Compoase Capability */ ++ prBssInfo->u2CapInfo = CAP_INFO_ESS; ++ ++ if (prBssInfo->fgIsProtection) ++ prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; ++ ++ if (prBssInfo->fgIsShortPreambleAllowed) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; ++ ++ if (prBssInfo->fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ ++ rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); ++ ++ prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; ++ ++ /* 4 <7> Fill the EDCA */ ++ ++ prACQueParms = prBssInfo->arACQueParmsForBcast; ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prACQueParms[eAci].fgIsACMSet = FALSE; ++ prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; ++ prACQueParms[eAci].u2CWmin = BIT(auCWminLog2ForBcast[eAci]) - 1; ++ prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2ForBcast[eAci]) - 1; ++ prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; ++ ++ prBssInfo->aucCWminLog2ForBcast[eAci] = auCWminLog2ForBcast[eAci]; /* used to send WMM IE */ ++ prBssInfo->aucCWmaxLog2ForBcast[eAci] = auCWmaxLog2ForBcast[eAci]; ++ ++ DBGLOG(BSS, INFO, "Bcast: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prACQueParms[eAci].fgIsACMSet, ++ prACQueParms[eAci].u2Aifsn, ++ prACQueParms[eAci].u2CWmin, ++ prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); ++ ++ } ++ ++ prACQueParms = prBssInfo->arACQueParms; ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prACQueParms[eAci].fgIsACMSet = FALSE; ++ prACQueParms[eAci].u2Aifsn = auAifs[eAci]; ++ prACQueParms[eAci].u2CWmin = BIT(auCWminLog2[eAci]) - 1; ++ prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2[eAci]) - 1; ++ prACQueParms[eAci].u2TxopLimit = auTxop[eAci]; ++ ++ DBGLOG(BSS, INFO, "eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prACQueParms[eAci].fgIsACMSet, ++ prACQueParms[eAci].u2Aifsn, ++ prACQueParms[eAci].u2CWmin, ++ prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); ++ } ++ ++ /* Note: Caller should update the EDCA setting to HW by nicQmUpdateWmmParms() it there is no AIS network */ ++ /* Note: In E2, only 4 HW queues. The the Edca parameters should be folow by AIS network */ ++ /* Note: In E3, 8 HW queues. the Wmm parameters should be updated to right queues according to BSS */ ++ ++} /* end of bssInitForAP() */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update DTIM Count ++* ++* @param[in] eNetTypeIndex Specify which network to update ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ ++ /* Setup DTIM Count for next TBTT. */ ++ if (prBssInfo->ucDTIMCount > 0) { ++ prBssInfo->ucDTIMCount--; ++ } else { ++ ++ ASSERT(prBssInfo->ucDTIMPeriod > 0); ++ ++ prBssInfo->ucDTIMCount = prBssInfo->ucDTIMPeriod - 1; ++ } ++ } ++ ++} /* end of bssUpdateDTIMIE() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to set the Virtual Bitmap in TIM Information Elements ++* ++* @param[in] prBssInfo Pointer to the BSS_INFO_T. ++* @param[in] u2AssocId The association id to set in Virtual Bitmap. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId) ++{ ++ ++ ASSERT(prBssInfo); ++ ++ if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); ++ ++ /* Use Association ID == 0 for BMCAST indication */ ++ if (u2AssocId == 0) { ++ ++ prP2pSpecificBssInfo->ucBitmapCtrl |= (UINT_8) BIT(0); ++ } else { ++ PUINT_8 pucPartialVirtualBitmap; ++ UINT_8 ucBitmapToSet; ++ ++ /* (u2AssocId / 8) */ ++ pucPartialVirtualBitmap = &prP2pSpecificBssInfo->aucPartialVirtualBitmap[(u2AssocId >> 3)]; ++ ucBitmapToSet = (UINT_8) BIT((u2AssocId % 8)); ++ ++ if (*pucPartialVirtualBitmap & ucBitmapToSet) { ++ /* The virtual bitmap has been set */ ++ return; ++ } ++ ++ *pucPartialVirtualBitmap |= ucBitmapToSet; ++ ++ /* Update u2SmallestAID and u2LargestAID */ ++ if ((u2AssocId < prP2pSpecificBssInfo->u2SmallestAID) || ++ (prP2pSpecificBssInfo->u2SmallestAID == 0)) { ++ prP2pSpecificBssInfo->u2SmallestAID = u2AssocId; ++ } ++ ++ if ((u2AssocId > prP2pSpecificBssInfo->u2LargestAID) || ++ (prP2pSpecificBssInfo->u2LargestAID == 0)) { ++ prP2pSpecificBssInfo->u2LargestAID = u2AssocId; ++ } ++ } ++ } ++ ++} /* end of bssSetTIMBitmap() */ ++#endif ++ ++#endif /* CFG_SUPPORT_AAA */ ++ ++VOID bssCreateStaRecFromAuth(IN P_ADAPTER_T prAdapter) ++{ ++ ++} ++ ++VOID bssUpdateStaRecFromAssocReq(IN P_ADAPTER_T prAdapter) ++{ ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c +new file mode 100644 +index 000000000000..39af02df2af2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c +@@ -0,0 +1,738 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm.c#2 ++*/ ++ ++/*! \file "cnm.c" ++ \brief Module of Concurrent Network Management ++ ++ Module of Concurrent Network Management ++*/ ++ ++/* ++** Log: cnm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix possible wrong message when P2P is unregistered ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Fix large network type index assert in FW issue. ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 01 2011 cm.chang ++ * [WCXRP00001077] [All Wi-Fi][Driver] Fix wrong preferred channel for AP and BOW ++ * Only check AIS channel for P2P and BOW ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Extension channel of some 5G AP will not follow regulation requirement ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * . ++ * ++ * 09 01 2011 cm.chang ++ * [WCXRP00000937] [MT6620 Wi-Fi][Driver][FW] cnm.c line #848 assert when doing monkey test ++ * Print message only in Linux platform for monkey testing ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Limit AIS to fixed channel same with BOW ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Check if P2P network index is Tethering AP ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 02 17 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * When P2P registried, invoke BOW deactivate function ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Provide function to decide if BSS can be activated or not ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 10 13 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when cmd buffer is not available ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Fix wrong message ID for channel grant to requester ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set 20/40M bandwidth of AP HT OP before association process ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 21 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support TCP/UDP/IP Checksum offload feature ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add a new function to send abort message ++ * ++ * 04 27 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * BMC mac address shall be ignored in basic config command ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support change of MAC address by host command ++ * ++ * 04 16 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the wpa-none for ibss beacon. ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix bug for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * use the Rx0 dor event indicate. ++ * ++ * 02 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support partial part about cmd basic configuration ++ * ++ * Dec 10 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove conditional compiling FPGA_V5 ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add function cnmFsmEventInit() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in CNM_INFO_T. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmInit(P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of cnmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in CNM_INFO_T. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmUninit(P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of cnmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Before handle the message from other module, it need to obtain ++* the Channel privilege from Channel Manager ++* ++* @param[in] prMsgHdr The message need to be handled. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_CH_REQ_T prMsgChReq; ++ P_CMD_CH_PRIVILEGE_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prMsgChReq = (P_MSG_CH_REQ_T) prMsgHdr; ++ ++ prCmdBody = (P_CMD_CH_PRIVILEGE_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(CNM, ERROR, "ChReq: fail to get buf (net=%d, token=%d)\n", ++ prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChReq net=%d token=%d b=%d c=%d s=%d\n", ++ prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID, ++ prMsgChReq->eRfBand, prMsgChReq->ucPrimaryChannel, prMsgChReq->eRfSco); ++ ++ prCmdBody->ucNetTypeIndex = prMsgChReq->ucNetTypeIndex; ++ prCmdBody->ucTokenID = prMsgChReq->ucTokenID; ++ prCmdBody->ucAction = CMD_CH_ACTION_REQ; /* Request */ ++ prCmdBody->ucPrimaryChannel = prMsgChReq->ucPrimaryChannel; ++ prCmdBody->ucRfSco = (UINT_8) prMsgChReq->eRfSco; ++ prCmdBody->ucRfBand = (UINT_8) prMsgChReq->eRfBand; ++ prCmdBody->ucReqType = (UINT_8) prMsgChReq->eReqType; ++ prCmdBody->ucReserved = 0; ++ prCmdBody->u4MaxInterval = prMsgChReq->u4MaxInterval; ++ COPY_MAC_ADDR(prCmdBody->aucBSSID, prMsgChReq->aucBSSID); ++ ++ ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ /* For monkey testing 20110901 */ ++ if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) ++ DBGLOG(CNM, ERROR, "CNM: ChReq with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_CH_PRIVILEGE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of cnmChMngrRequestPrivilege() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Before deliver the message to other module, it need to release ++* the Channel privilege to Channel Manager. ++* ++* @param[in] prMsgHdr The message need to be delivered ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_CH_ABORT_T prMsgChAbort; ++ P_CMD_CH_PRIVILEGE_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prMsgChAbort = (P_MSG_CH_ABORT_T) prMsgHdr; ++ ++ prCmdBody = (P_CMD_CH_PRIVILEGE_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(CNM, ERROR, "ChAbort: fail to get buf (net=%d, token=%d)\n", ++ prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChAbort net=%d token=%d\n", prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); ++ ++ prCmdBody->ucNetTypeIndex = prMsgChAbort->ucNetTypeIndex; ++ prCmdBody->ucTokenID = prMsgChAbort->ucTokenID; ++ prCmdBody->ucAction = CMD_CH_ACTION_ABORT; /* Abort */ ++ ++ ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ /* For monkey testing 20110901 */ ++ if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) ++ DBGLOG(CNM, ERROR, "CNM: ChAbort with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_CH_PRIVILEGE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* end of cnmChMngrAbortPrivilege() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_CH_PRIVILEGE_T prEventBody; ++ P_MSG_CH_GRANT_T prChResp; ++ ++ ASSERT(prAdapter); ++ ASSERT(prEvent); ++ ++ prEventBody = (P_EVENT_CH_PRIVILEGE_T) (prEvent->aucBuffer); ++ prChResp = (P_MSG_CH_GRANT_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_GRANT_T)); ++ ASSERT(prChResp); ++ ++ /* To do: exception handle */ ++ if (!prChResp) { ++ DBGLOG(CNM, ERROR, "ChGrant: fail to get buf (net=%d, token=%d)\n", ++ prEventBody->ucNetTypeIndex, prEventBody->ucTokenID); ++ ++ return; ++ } ++ ++ DBGLOG(CNM, INFO, "ChGrant net=%d token=%d ch=%d sco=%d\n", ++ prEventBody->ucNetTypeIndex, prEventBody->ucTokenID, ++ prEventBody->ucPrimaryChannel, prEventBody->ucRfSco); ++ ++ ASSERT(prEventBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ASSERT(prEventBody->ucStatus == EVENT_CH_STATUS_GRANT); ++ ++ /* Decide message ID based on network and response status */ ++ if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_AIS_CH_GRANT; ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (prEventBody->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_P2P_CH_GRANT; ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ prChResp->rMsgHdr.eMsgId = MID_CNM_BOW_CH_GRANT; ++#endif ++ else { ++ cnmMemFree(prAdapter, prChResp); ++ return; ++ } ++ ++ prChResp->ucNetTypeIndex = prEventBody->ucNetTypeIndex; ++ prChResp->ucTokenID = prEventBody->ucTokenID; ++ prChResp->ucPrimaryChannel = prEventBody->ucPrimaryChannel; ++ prChResp->eRfSco = (ENUM_CHNL_EXT_T) prEventBody->ucRfSco; ++ prChResp->eRfBand = (ENUM_BAND_T) prEventBody->ucRfBand; ++ prChResp->eReqType = (ENUM_CH_REQ_TYPE_T) prEventBody->ucReqType; ++ prChResp->u4GrantInterval = prEventBody->u4GrantInterval; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prChResp, MSG_SEND_METHOD_BUF); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked for P2P or BOW networks ++* ++* @param (none) ++* ++* @return TRUE: suggest to adopt the returned preferred channel ++* FALSE: No suggestion. Caller should adopt its preference ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBand); ++ ASSERT(pucPrimaryChannel); ++ ASSERT(prBssSCO); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (RLM_NET_PARAM_VALID(prBssInfo)) { ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ *prBssSCO = prBssInfo->eBssSCO; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: available channel is limited to return value ++* FALSE: no limited ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) ++{ ++#if CFG_ENABLE_WIFI_DIRECT || (CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL) ++ P_BSS_INFO_T prBssInfo; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { ++ ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ ++ return TRUE; ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ *prBand = prBssInfo->eBand; ++ *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ ++ return TRUE; ++ } ++#endif ++ ++ return FALSE; ++} ++ ++#if CFG_P2P_LEGACY_COEX_REVISE ++BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) ++{ ++ P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; ++ P_BSS_INFO_T prP2PBssInfo = &prWifiVar->arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && ++ (prP2PBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || ++ (prP2PBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && prP2PBssInfo->eIntendOPMode == OP_MODE_NUM))) { ++ *prBand = prP2PBssInfo->eBand; ++ *pucPrimaryChannel = prP2PBssInfo->ucPrimaryChannel; ++#if CFG_SUPPORT_MCC ++ if (nicFreq2ChannelNum(prWifiVar->rConnSettings.u4FreqInKHz * 1000) != *pucPrimaryChannel) { ++ DBGLOG(CNM, INFO, "p2p is running on Channel %d, but supplicant try to run as MCC\n", ++ *pucPrimaryChannel); ++ return FALSE; ++ } ++#endif ++ DBGLOG(CNM, INFO, "p2p is running on Channel %d, supplicant try to run as SCC\n", ++ *pucPrimaryChannel); ++ return TRUE; ++ } ++#endif ++ return FALSE; ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter) ++{ ++#if CFG_ENABLE_BT_OVER_WIFI ++ P_BSS_INFO_T prAisBssInfo, prBowBssInfo; ++ ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prBowBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ if (RLM_NET_PARAM_VALID(prAisBssInfo) && RLM_NET_PARAM_VALID(prBowBssInfo)) { ++ if (prAisBssInfo->eBand != prBowBssInfo->eBand || ++ prAisBssInfo->ucPrimaryChannel != prBowBssInfo->ucPrimaryChannel) { ++ ++ /* Notify BOW to do deactivation */ ++ bowNotifyAllLinkDisconnected(prAdapter); ++ } ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter) ++{ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) ++ return FALSE; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) ++ return FALSE; ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) ++ return FALSE; ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { ++ /* Notify BOW to do deactivation */ ++ bowNotifyAllLinkDisconnected(prAdapter); ++ } ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) ++ return FALSE; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) ++ return FALSE; ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param (none) ++* ++* @return TRUE: permitted ++* FALSE: Not permitted ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 i; ++ P_BSS_DESC_T prBssDesc = NULL; ++ ++ /* Note: To support real-time decision instead of current activated-time, ++ * the STA roaming case shall be considered about synchronization ++ * problem. Another variable fgAssoc40mBwAllowed is added to ++ * represent HT capability when association ++ */ ++ for (i = 0; i < NETWORK_TYPE_INDEX_NUM; i++) { ++ if (i != (UINT_8) eNetTypeIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[i]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo) && (prBssInfo->fg40mBwAllowed || prBssInfo->fgAssoc40mBwAllowed)) ++ return FALSE; ++ } ++ } ++ ++ if (eNetTypeIdx == NETWORK_TYPE_AIS_INDEX) ++ prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; ++ else if ((eNetTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->rWifiVar.prP2pFsmInfo)) ++ prBssDesc = prAdapter->rWifiVar.prP2pFsmInfo->prTargetBss; ++ if (prBssDesc) { ++#if (CFG_FORCE_USE_20BW == 1) ++ if (prBssDesc->eBand == BAND_2G4) ++ return FALSE; ++#endif ++ if (prBssDesc->eSco == CHNL_EXT_SCN) ++ return FALSE; ++ } ++ ++ return TRUE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c +new file mode 100644 +index 000000000000..05bd0ff35f7a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c +@@ -0,0 +1,1236 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_mem.c#2 ++*/ ++ ++/*! \file "cnm_mem.c" ++ \brief This file contain the management function of packet buffers and ++ generic memory alloc/free functioin for mailbox message. ++ ++ A data packet has a fixed size of buffer, but a management ++ packet can be equipped with a variable size of buffer. ++*/ ++ ++/* ++** Log: cnm_mem.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 14 2012 wh.su ++ * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting ++ * Add code from 2.2 ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * initialize fgNeedResp. ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 11 29 2010 cm.chang ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * Sync RCPI of STA_REC to FW as reference of initial TX rate ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update SLT Function for QoS Support and not be affected by fixed rate function. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete ++ * and might leads to BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 10 13 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when cmd buffer is not available ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD ++ * when entering RF test with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 07 07 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support state of STA record change from 1 to 1 ++ * ++ * 07 05 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Fix correct structure size in cnmStaSendDeactivateCmd() ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * spin lock target revised ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change inner loop index from i to k. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 05 31 2010 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support checking of duplicated buffer free ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 28 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 28 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Modified some MQM-related data structures (SN counter, TX/RX BA table) ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Added new TX/RX BA tables in STA_REC ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Notify MQM, TXM, and RXM upon disconnection . ++ * ++ * 04 26 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Call mqm, txm, rxm functions upon disconnection ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support ++ * * * * * * * * * * and will send Null frame to diagnose connection ++ * ++ * 04 09 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * [BORA00000644] WiFi phase 4 integration ++ * * Added per-TID SN cache in STA_REC ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * move the wlan table alloc / free to change state function. ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support power control ++ * ++ * 03 03 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Initialize StaRec->arStaWaitQueue ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add debug message when no available pkt buffer ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Fixed STA_REC initialization bug: prStaRec->au2CachedSeqCtrl[k] ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsWmmSupported in STA_RECORD_T. ++ * ++ * 02 26 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added fgIsUapsdSupported in STA_RECORD_T ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * add support of Driver STA_RECORD_T activation ++ * ++ * 02 13 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added arTspecTable in STA_REC for TSPEC management ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable mgmt buffer debug by default ++ * ++ * 02 12 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Added BUFFER_SOURCE_BCN ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 cp.wu ++ * [BORA00000368]Integrate HIF part into BORA ++ * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h ++ * * * * * * * * * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem ++ * * * * * * * * * 3) use cnmMemAlloc() instead to allocate SRAM buffer ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * * * * * * MQM: BA handling ++ * * * * * * * TXM: Macros updates ++ * * * * * * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 24 2009 yarco.yang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * 12 21 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support several data buffer banks. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * .For new FPGA memory size ++ * ++ * Dec 9 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed DBGPRINT ++ * ++ * Dec 9 2009 mtk02752 ++ * [BORA00000368] Integrate HIF part into BORA ++ * add cnmDataPktFree() for emulation loopback purpose ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix warning of null pointer ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add cnmGetStaRecByAddress() and add fgIsInUse flag in STA_RECORD_T ++ * ++ * Nov 23 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Assign ucBufferSource in function cnmMgtPktAlloc() ++ * ++ * Nov 23 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added packet redispatch function calls ++ * ++ * Nov 13 2009 mtk01084 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * enable packet re-usable in current emulation driver ++ * ++ * Nov 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * 1. Add new function cnmGetStaRecByIndex() ++ * 2. Rename STA_REC_T to STA_RECORD_T ++ * ++ * Nov 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call cnmDataPktDispatch() in cnmPktFree() ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove definition of pragma section code ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Oct 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++ * Oct 8 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf); ++ ++static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp); ++ ++static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T cnmMgtPktAlloc(P_ADAPTER_T prAdapter, UINT_32 u4Length) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_QUE_T prQueList; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; ++ ++ /* Get a free MSDU_INFO_T */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(prQueList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo) { ++ prMsduInfo->prPacket = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ ++ if (prMsduInfo->prPacket == NULL) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo = NULL; ++ } ++ if (prMsduInfo) { ++ prMsduInfo->eCmdType = COMMAND_TYPE_NUM; ++ prMsduInfo->ucCID = 0xff; ++ prMsduInfo->u4InqueTime = 0; ++ prMsduInfo->ucPacketType = TX_PACKET_NUM; ++ } ++ } else { ++ P_QUE_T prTxingQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_TX_TCQ_STATUS_T pTc = (P_TX_TCQ_STATUS_T) NULL; ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ pTc = &(prAdapter->rTxCtrl.rTc); ++ ++ DBGLOG(MEM, LOUD, "++dump TxPendingMsdu=%u, Tc0=%d Tc1=%d Tc2=%d Tc3=%d, Tc4=%d Tc5=%d\n", ++ prTxingQue->u4NumElem, pTc->aucFreeBufferCount[TC0_INDEX], ++ pTc->aucFreeBufferCount[TC1_INDEX], pTc->aucFreeBufferCount[TC2_INDEX], ++ pTc->aucFreeBufferCount[TC3_INDEX], pTc->aucFreeBufferCount[TC4_INDEX], ++ pTc->aucFreeBufferCount[TC5_INDEX]); ++ ++ prQueueEntry = QUEUE_GET_HEAD(prTxingQue); ++ ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ DBGLOG(MEM, LOUD, ++ "msdu type=%u, ucid=%u, type=%d, time=%u, seq=%u, sta=%u\n", ++ prMsduInfo->ucPacketType, ++ prMsduInfo->ucCID, ++ prMsduInfo->eCmdType, ++ prMsduInfo->u4InqueTime, prMsduInfo->ucTxSeqNum, prMsduInfo->ucStaRecIndex); ++ prQueueEntry = QUEUE_GET_NEXT_ENTRY(prQueueEntry); ++ } ++ DBGLOG(MEM, LOUD, "--end dump\n"); ++ } ++ ++#if DBG ++ if (prMsduInfo == NULL) { ++ DBGLOG(MEM, WARN, "MgtDesc#=%u\n", prQueList->u4NumElem); ++ ++#if CFG_DBG_MGT_BUF ++ DBGLOG(MEM, WARN, "rMgtBufInfo: alloc#=%u, free#=%u, null#=%u\n", ++ prAdapter->rMgtBufInfo.u4AllocCount, ++ prAdapter->rMgtBufInfo.u4FreeCount, prAdapter->rMgtBufInfo.u4AllocNullCount); ++#endif ++ ++ DBGLOG(MEM, WARN, "\n"); ++ } ++#endif ++ ++ return prMsduInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMgtPktFree(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_QUE_T prQueList; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; ++ ++ ASSERT(prMsduInfo->prPacket); ++ if (prMsduInfo->prPacket) { ++ cnmMemFree(prAdapter, prMsduInfo->prPacket); ++ prMsduInfo->prPacket = NULL; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo->fgIsBasicRate = FALSE; ++ QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry) ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to initial the MGMT/MSG memory pool. ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMemInit(P_ADAPTER_T prAdapter) ++{ ++ P_BUF_INFO_T prBufInfo; ++ ++ /* Initialize Management buffer pool */ ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ kalMemZero(prBufInfo, sizeof(prAdapter->rMgtBufInfo)); ++ prBufInfo->pucBuf = prAdapter->pucMgtBufCached; ++ ++ /* Setup available memory blocks. 1 indicates FREE */ ++ prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); ++ ++ /* Initialize Message buffer pool */ ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ kalMemZero(prBufInfo, sizeof(prAdapter->rMsgBufInfo)); ++ prBufInfo->pucBuf = &prAdapter->aucMsgBuf[0]; ++ ++ /* Setup available memory blocks. 1 indicates FREE */ ++ prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); ++ ++ return; ++ ++} /* end of cnmMemInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate MGMT/MSG memory pool. ++* ++* \param[in] eRamType Target RAM type. ++* TCM blk_sz= 16bytes, BUF blk_sz= 256bytes ++* \param[in] u4Length Length of the buffer to allocate. ++* ++* \retval !NULL Pointer to the start address of allocated memory. ++* \retval NULL Fail to allocat memory ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4MemAllocCnt = 0, u4MemFreeCnt = 0; ++PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length) ++{ ++ P_BUF_INFO_T prBufInfo; ++ BUF_BITMAP rRequiredBitmap; ++ UINT_32 u4BlockNum; ++ UINT_32 i, u4BlkSzInPower; ++ PVOID pvMemory; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(u4Length); ++ ++ u4MemAllocCnt++; ++ ++ if (eRamType == RAM_TYPE_MSG && u4Length <= 256) { ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ u4BlkSzInPower = MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ u4Length += (MSG_BUF_BLOCK_SIZE - 1); ++ u4BlockNum = u4Length >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); ++ } else { ++ eRamType = RAM_TYPE_BUF; ++ ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ u4BlkSzInPower = MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ u4Length += (MGT_BUF_BLOCK_SIZE - 1); ++ u4BlockNum = u4Length >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ++ ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); ++ } ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4AllocCount++; ++#endif ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ if ((u4BlockNum > 0) && (u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS)) { ++ ++ /* Convert number of block into bit cluster */ ++ rRequiredBitmap = BITS(0, u4BlockNum - 1); ++ ++ for (i = 0; i <= (MAX_NUM_OF_BUF_BLOCKS - u4BlockNum); i++) { ++ ++ /* Have available memory blocks */ ++ if ((prBufInfo->rFreeBlocksBitmap & rRequiredBitmap) ++ == rRequiredBitmap) { ++ ++ /* Clear corresponding bits of allocated memory blocks */ ++ prBufInfo->rFreeBlocksBitmap &= ~rRequiredBitmap; ++ ++ /* Store how many blocks be allocated */ ++ prBufInfo->aucAllocatedBlockNum[i] = (UINT_8) u4BlockNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, ++ eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ /* Return the start address of allocated memory */ ++ return (PVOID) (prBufInfo->pucBuf + (i << u4BlkSzInPower)); ++ ++ } ++ ++ rRequiredBitmap <<= 1; ++ } ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ /* cannot move the allocation between spin_lock_irqsave and spin_unlock_irqrestore */ ++#ifdef LINUX ++ pvMemory = (PVOID) kalMemAlloc(u4Length, VIR_MEM_TYPE); ++ if (pvMemory) ++ kalMemZero(pvMemory, u4Length); ++#else ++ pvMemory = (PVOID) NULL; ++#endif ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4AllocNullCount++; ++ ++ if (pvMemory) ++ prAdapter->u4MemAllocDynamicCount++; ++#endif ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ return pvMemory; ++ ++} /* end of cnmMemAlloc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release memory to MGT/MSG memory pool. ++* ++* \param pucMemory Start address of previous allocated memory ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory) ++{ ++ P_BUF_INFO_T prBufInfo; ++ UINT_32 u4BlockIndex; ++ BUF_BITMAP rAllocatedBlocksBitmap; ++ ENUM_RAM_TYPE_T eRamType; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(pvMemory); ++ if (!pvMemory) ++ return; ++ ++ u4MemFreeCnt++; ++ ++ /* Judge it belongs to which RAM type */ ++ if (((ULONG) pvMemory >= (ULONG)&prAdapter->aucMsgBuf[0]) && ++ ((ULONG) pvMemory <= (ULONG)&prAdapter->aucMsgBuf[MSG_BUFFER_SIZE - 1])) { ++ ++ prBufInfo = &prAdapter->rMsgBufInfo; ++ u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) ++ >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); ++ eRamType = RAM_TYPE_MSG; ++ } else if (((ULONG) pvMemory >= (ULONG) prAdapter->pucMgtBufCached) && ++ ((ULONG) pvMemory <= ((ULONG) prAdapter->pucMgtBufCached + MGT_BUFFER_SIZE - 1))) { ++ prBufInfo = &prAdapter->rMgtBufInfo; ++ u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) ++ >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; ++ ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); ++ eRamType = RAM_TYPE_BUF; ++ } else { ++#ifdef LINUX ++ /* For Linux, it is supported because size is not needed */ ++ kalMemFree(pvMemory, VIR_MEM_TYPE, 0); ++#else ++ /* For Windows, it is not supported because of no size argument */ ++ ASSERT(0); ++#endif ++ ++#if CFG_DBG_MGT_BUF ++ prAdapter->u4MemFreeDynamicCount++; ++#endif ++ return; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++#if CFG_DBG_MGT_BUF ++ prBufInfo->u4FreeCount++; ++#endif ++ ++ /* Convert number of block into bit cluster */ ++ ASSERT(prBufInfo->aucAllocatedBlockNum[u4BlockIndex] > 0); ++ ++ rAllocatedBlocksBitmap = BITS(0, prBufInfo->aucAllocatedBlockNum[u4BlockIndex] - 1); ++ rAllocatedBlocksBitmap <<= u4BlockIndex; ++ ++ /* Clear saved block count for this memory segment */ ++ prBufInfo->aucAllocatedBlockNum[u4BlockIndex] = 0; ++ ++ /* Set corresponding bit of released memory block */ ++ prBufInfo->rFreeBlocksBitmap |= rAllocatedBlocksBitmap; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); ++ ++ return; ++ ++} /* end of cnmMemFree() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecInit(P_ADAPTER_T prAdapter) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ prStaRec->ucIndex = (UINT_8) i; ++ prStaRec->fgIsInUse = FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse) ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmStaRecAlloc(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i, k; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (!prStaRec->fgIsInUse) { ++ /*---- Initialize STA_REC_T here ----*/ ++ kalMemZero(prStaRec, sizeof(STA_RECORD_T)); ++ prStaRec->ucIndex = (UINT_8) i; ++ prStaRec->ucNetTypeIndex = ucNetTypeIndex; ++ prStaRec->fgIsInUse = TRUE; ++ ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ prStaRec->u2AssocReqIeLen = 0; ++ } ++ ++ /* Initialize the SN caches for duplicate detection */ ++ for (k = 0; k < TID_NUM + 1; k++) ++ prStaRec->au2CachedSeqCtrl[k] = 0xFFFF; ++ ++ /* Initialize SW TX queues in STA_REC */ ++ for (k = 0; k < STA_WAIT_QUEUE_NUM; k++) ++ LINK_INITIALIZE(&prStaRec->arStaWaitQueue[k]); ++ ++ /* Default enable TX/RX AMPDU */ ++ prStaRec->fgTxAmpduEn = TRUE; ++ prStaRec->fgRxAmpduEn = TRUE; ++ ++#if CFG_ENABLE_PER_STA_STATISTICS && CFG_ENABLE_PKT_LIFETIME_PROFILE ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++#endif ++ ++ for (k = 0; k < NUM_OF_PER_STA_TX_QUEUES; k++) ++ QUEUE_INITIALIZE(&prStaRec->arTxQueue[k]); ++ ++ break; ++ } ++ } ++ ++ return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecFree(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgSyncToChip) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ /* To do: free related resources, e.g. timers, buffers, etc */ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ prStaRec->fgTransmitKeyExist = FALSE; ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ ++ if (prStaRec->pucAssocReqIe) { ++ kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); ++ prStaRec->pucAssocReqIe = NULL; ++ prStaRec->u2AssocReqIeLen = 0; ++ } ++ ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ ++ if (fgSyncToChip) ++ cnmStaSendRemoveCmd(prAdapter, prStaRec); ++ ++ prStaRec->fgIsInUse = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex) ++ cnmStaRecFree(prAdapter, prStaRec, fgSyncToChip); ++ } /* end of for loop */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmGetStaRecByIndex(P_ADAPTER_T prAdapter, UINT_8 ucIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ++ prStaRec = (ucIndex < CFG_STA_REC_NUM) ? &prAdapter->arStaRec[ucIndex] : NULL; ++ ++ if (prStaRec && prStaRec->fgIsInUse == FALSE) ++ prStaRec = NULL; ++ ++ return prStaRec; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). ++* ++* @param[in] pucPeerMacAddr Given Peer MAC Address. ++* ++* @retval Pointer to STA_RECORD_T, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_STA_RECORD_T cnmGetStaRecByAddress(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex, PUINT_8 pucPeerMacAddr) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucPeerMacAddr); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && ++ prStaRec->ucNetTypeIndex == ucNetTypeIndex && ++ EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { ++ break; ++ } ++ } ++ ++ return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Reset the Status and Reason Code Field to 0 of all Station Records for ++* the specified Network Type ++* ++* @param[in] eNetType Specify Network Type ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecResetStatus(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetTypeIndex, FALSE); ++ ++#if 0 ++ P_STA_RECORD_T prStaRec; ++ UINT_16 i; ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse) { ++ if ((NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) && IS_STA_IN_AIS(prStaRec->eStaType)) { ++ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->u2ReasonCode = REASON_CODE_RESERVED; ++ prStaRec->ucJoinFailureCount = 0; ++ prStaRec->fgTransmitKeyExist = FALSE; ++ ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ } ++ ++ /* TODO(Kevin): For P2P and BOW */ ++ } ++ } ++ ++ return; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will change the ucStaState of STA_RECORD_T and also do ++* event indication to HOST to sync the STA_RECORD_T in driver. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] u4NewState New STATE to change. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmStaRecChangeState(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, UINT_8 ucNewState) ++{ ++ BOOLEAN fgNeedResp; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->fgIsInUse); ++ ++ /* Do nothing when following state transitions happen, ++ * other 6 conditions should be sync to FW, including 1-->1, 3-->3 ++ */ ++ if ((ucNewState == STA_STATE_2 && prStaRec->ucStaState != STA_STATE_3) || ++ (ucNewState == STA_STATE_1 && prStaRec->ucStaState == STA_STATE_2)) { ++ prStaRec->ucStaState = ucNewState; ++ return; ++ } ++ ++ fgNeedResp = FALSE; ++ if (ucNewState == STA_STATE_3) { ++ secFsmEventStart(prAdapter, prStaRec); ++ if (ucNewState != prStaRec->ucStaState) ++ fgNeedResp = TRUE; ++ } else { ++ if (ucNewState != prStaRec->ucStaState && prStaRec->ucStaState == STA_STATE_3) ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ fgNeedResp = FALSE; ++ } ++ prStaRec->ucStaState = ucNewState; ++ ++ cnmStaSendUpdateCmd(prAdapter, prStaRec, fgNeedResp); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* To do: Confirm if it is invoked here or other location, but it should ++ * be invoked after state sync of STA_REC ++ * Update system operation parameters for AP mode ++ */ ++ if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); ++ } ++#endif ++} ++ ++P_STA_RECORD_T ++cnmStaTheTypeGet(P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx) ++{ ++ P_STA_RECORD_T prStaRec = NULL; ++ UINT_16 i; ++ ++ for (i = *pu4StartIdx; i < CFG_STA_REC_NUM; i++) { ++ prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; ++ ++ if (prStaRec->fgIsInUse && ++ prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex && prStaRec->eStaType == eStaType) { ++ i++; ++ break; ++ } ++ ++ prStaRec = NULL; /* reset */ ++ } /* end of for loop */ ++ ++ *pu4StartIdx = i; ++ return prStaRec; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf) ++{ ++ P_EVENT_ACTIVATE_STA_REC_T prEventContent; ++ P_STA_RECORD_T prStaRec; ++ ++ prEventContent = (P_EVENT_ACTIVATE_STA_REC_T) pucEventBuf; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prEventContent->ucStaRecIdx); ++ ++ if (prStaRec && prStaRec->ucStaState == STA_STATE_3 && ++ !kalMemCmp(&prStaRec->aucMacAddr[0], &prEventContent->aucMacAddr[0], MAC_ADDR_LEN)) { ++ ++ qmActivateStaRec(prAdapter, prStaRec); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp) ++{ ++ P_CMD_UPDATE_STA_RECORD_T prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prStaRec->fgIsInUse); ++ ++ /* To do: come out a mechanism to limit one STA_REC sync once for AP mode ++ * to avoid buffer empty case when many STAs are associated ++ * simultaneously. ++ */ ++ ++ /* To do: how to avoid 2 times of allocated memory. Use Stack? ++ * One is here, the other is in wlanSendQueryCmd() ++ */ ++ prCmdContent = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_UPDATE_STA_RECORD_T)); ++ ASSERT(prCmdContent); ++ ++ /* To do: exception handle */ ++ if (!prCmdContent) ++ return; ++ ++ prCmdContent->ucIndex = prStaRec->ucIndex; ++ prCmdContent->ucStaType = (UINT_8) prStaRec->eStaType; ++ kalMemCopy(&prCmdContent->aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); ++ prCmdContent->u2AssocId = prStaRec->u2AssocId; ++ prCmdContent->u2ListenInterval = prStaRec->u2ListenInterval; ++ prCmdContent->ucNetTypeIndex = prStaRec->ucNetTypeIndex; ++ ++ prCmdContent->ucDesiredPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ prCmdContent->u2DesiredNonHTRateSet = prStaRec->u2DesiredNonHTRateSet; ++ prCmdContent->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ prCmdContent->ucMcsSet = prStaRec->ucMcsSet; ++ prCmdContent->ucSupMcs32 = (UINT_8) prStaRec->fgSupMcs32; ++ prCmdContent->u2HtCapInfo = prStaRec->u2HtCapInfo; ++ prCmdContent->ucNeedResp = (UINT_8) fgNeedResp; ++ ++#if !CFG_SLT_SUPPORT ++ if (prAdapter->rWifiVar.eRateSetting != FIXED_RATE_NONE) { ++ /* override rate configuration */ ++ nicUpdateRateParams(prAdapter, ++ prAdapter->rWifiVar.eRateSetting, ++ &(prCmdContent->ucDesiredPhyTypeSet), ++ &(prCmdContent->u2DesiredNonHTRateSet), ++ &(prCmdContent->u2BSSBasicRateSet), ++ &(prCmdContent->ucMcsSet), ++ &(prCmdContent->ucSupMcs32), &(prCmdContent->u2HtCapInfo)); ++ } ++#endif ++ ++ prCmdContent->ucIsQoS = prStaRec->fgIsQoS; ++ prCmdContent->ucIsUapsdSupported = prStaRec->fgIsUapsdSupported; ++ prCmdContent->ucStaState = prStaRec->ucStaState; ++ ++ prCmdContent->ucAmpduParam = prStaRec->ucAmpduParam; ++ prCmdContent->u2HtExtendedCap = prStaRec->u2HtExtendedCap; ++ prCmdContent->u4TxBeamformingCap = prStaRec->u4TxBeamformingCap; ++ prCmdContent->ucAselCap = prStaRec->ucAselCap; ++ prCmdContent->ucRCPI = prStaRec->ucRCPI; ++ ++ prCmdContent->ucUapsdAc = prStaRec->ucBmpTriggerAC | (prStaRec->ucBmpDeliveryAC << 4); ++ prCmdContent->ucUapsdSp = prStaRec->ucUapsdSp; ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_UPDATE_STA_RECORD, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ fgNeedResp, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ fgNeedResp ? cnmStaRecHandleEventPkt : NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_UPDATE_STA_RECORD_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdContent); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ CMD_REMOVE_STA_RECORD_T rCmdContent; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ rCmdContent.ucIndex = prStaRec->ucIndex; ++ kalMemCopy(&rCmdContent.aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_REMOVE_STA_RECORD, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_REMOVE_STA_RECORD_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) &rCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c +new file mode 100644 +index 000000000000..8cc9ef9078fe +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c +@@ -0,0 +1,482 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1 ++*/ ++ ++/*! \file "cnm_timer.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: cnm_timer.c ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation ++ * because NdisMSleep() won't sleep long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support sleep notification to host ++ * ++ * 05 19 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some checking assertions ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Return timer token back to COS when entering wait off state ++ * ++ * 01 11 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Remove compiling warning ++ * ++ * 01 08 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb ++ * ++ * 01 06 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix system time is 32KHz instead of 1ms ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer ++ * ++ * Oct 30 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * In cnmTimerInitialize(), just stop timer if it was already created. ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Move the external reference for Lint to precomp.h ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the time to do the time out check. ++* ++* \param[in] rTimeout Time out interval from current time. ++* ++* \retval TRUE Success. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout) ++{ ++ P_ROOT_TIMER prRootTimer; ++ BOOLEAN fgNeedWakeLock; ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ kalSetTimer(prAdapter->prGlueInfo, rTimeout); ++ ++ if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) { ++ fgNeedWakeLock = TRUE; ++ ++ if (!prRootTimer->fgWakeLocked) { ++ KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = TRUE; ++ } ++ } else { ++ fgNeedWakeLock = FALSE; ++ } ++ ++ return fgNeedWakeLock; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to initialize a root timer. ++* ++* \param[in] prAdapter ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ /* Note: glue layer have configured timer */ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ LINK_INITIALIZE(&prRootTimer->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer"); ++ prRootTimer->fgWakeLocked = FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to destroy a root timer. ++* When WIFI is off, the token shall be returned back to system. ++* ++* \param[in] ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ if (prRootTimer->fgWakeLocked) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ LINK_INITIALIZE(&prRootTimer->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ /* Note: glue layer will be responsible for timer destruction */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to initialize a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* \param[in] pfnFunc Pointer to the call back function. ++* \param[in] u4Data Parameter for call back function. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData) ++{ ++ ASSERT(prAdapter); ++ ++ ASSERT(prTimer); ++ ++#if DBG ++ /* Note: NULL function pointer is permitted for HEM POWER */ ++ if (pfFunc == NULL) ++ DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n"); ++#endif ++ ++#if DBG ++ ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); ++ { ++ P_LINK_T prTimerList; ++ P_LINK_ENTRY_T prLinkEntry; ++ P_TIMER_T prPendingTimer; ++ ++ prTimerList = &(prAdapter->rRootTimer.rLinkHead); ++ ++ LINK_FOR_EACH(prLinkEntry, prTimerList) { ++ prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); ++ ASSERT(prPendingTimer); ++ ASSERT(prPendingTimer != prTimer); ++ } ++ } ++#endif ++ ++ LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); ++ ++ prTimer->pfMgmtTimeOutFunc = pfFunc; ++ prTimer->ulData = ulData; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to stop a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock) ++{ ++ P_ROOT_TIMER prRootTimer; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ ++ if (fgAcquireSpinlock) ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ if (timerPendingTimer(prTimer)) { ++ LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry); ++ ++ /* Reduce dummy timeout for power saving, especially HIF activity. ++ * If two or more timers exist and being removed timer is smallest, ++ * this dummy timeout will still happen, but it is OK. ++ */ ++ if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { ++ kalCancelTimer(prAdapter->prGlueInfo); ++ ++ if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ } ++ } ++ ++ if (fgAcquireSpinlock) ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to stop a timer. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to start a timer with wake_lock. ++* ++* \param[in] prTimer Pointer to a timer structure. ++* \param[in] u4TimeoutMs Timeout to issue the timer and call back function ++* (unit: ms). ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs) ++{ ++ P_ROOT_TIMER prRootTimer; ++ P_LINK_T prTimerList; ++ OS_SYSTIME rExpiredSysTime, rTimeoutSystime; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prTimer); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ prTimerList = &prRootTimer->rLinkHead; ++ ++ /* If timeout interval is larger than 1 minute, the mod value is set ++ * to the timeout value first, then per minutue. ++ */ ++ if (u4TimeoutMs > MSEC_PER_MIN) { ++ ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN)); ++ ++ prTimer->u2Minutes = (UINT_16) (u4TimeoutMs / MSEC_PER_MIN); ++ u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN); ++ if (u4TimeoutMs == 0) { ++ u4TimeoutMs = MSEC_PER_MIN; ++ prTimer->u2Minutes--; ++ } ++ } else { ++ prTimer->u2Minutes = 0; ++ } ++ ++ /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */ ++ ASSERT(u4TimeoutMs < (((UINT_32) 0x80000000 - MSEC_PER_SEC) / KAL_HZ)); ++ rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs); ++ rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime; ++ ++ /* If no timer pending or the fast time interval is used. */ ++ if (LINK_IS_EMPTY(prTimerList) || TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { ++ ++ prRootTimer->rNextExpiredSysTime = rExpiredSysTime; ++ cnmTimerSetTimer(prAdapter, rTimeoutSystime); ++ } ++ ++ /* Add this timer to checking list */ ++ prTimer->rExpiredSysTime = rExpiredSysTime; ++ ++ if (!timerPendingTimer(prTimer)) ++ LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routines is called to check the timer list. ++* ++* \param[in] ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROOT_TIMER prRootTimer; ++ P_LINK_T prTimerList; ++ P_LINK_ENTRY_T prLinkEntry; ++ P_TIMER_T prTimer; ++ OS_SYSTIME rCurSysTime; ++ PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; ++ ULONG ulTimeoutData; ++ BOOLEAN fgNeedWakeLock; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* acquire spin lock */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ ++ prRootTimer = &prAdapter->rRootTimer; ++ prTimerList = &prRootTimer->rLinkHead; ++ ++ rCurSysTime = kalGetTimeTick(); ++ ++ /* Set the permitted max timeout value for new one */ ++ prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; ++ ++ LINK_FOR_EACH(prLinkEntry, prTimerList) { ++ prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); ++ ASSERT(prTimer); ++ ++ /* Check if this entry is timeout. */ ++ if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { ++ cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE); ++ ++ pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; ++ ulTimeoutData = prTimer->ulData; ++ ++ if (prTimer->u2Minutes > 0) { ++ prTimer->u2Minutes--; ++ prTimer->rExpiredSysTime = rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN); ++ LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); ++ } else if (pfMgmtTimeOutFunc) { ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ (pfMgmtTimeOutFunc) (prAdapter, ulTimeoutData); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++ } ++ ++ /* Search entire list again because of nest del and add timers ++ * and current MGMT_TIMER could be volatile after stopped ++ */ ++ prLinkEntry = (P_LINK_ENTRY_T) prTimerList; ++ ++ prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; ++ } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { ++ prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime; ++ } ++ } /* end of for loop */ ++ ++ /* Setup the prNext timeout event. It is possible the timer was already ++ * set in the above timeout callback function. ++ */ ++ fgNeedWakeLock = FALSE; ++ if (!LINK_IS_EMPTY(prTimerList)) { ++ ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime)); ++ ++ fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME) ++ ((INT_32) prRootTimer->rNextExpiredSysTime - (INT_32) rCurSysTime)); ++ } ++ ++ if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) { ++ KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); ++ prRootTimer->fgWakeLocked = FALSE; ++ } ++ ++ /* release spin lock */ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c +new file mode 100644 +index 000000000000..c7a23eb018b6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c +@@ -0,0 +1,816 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/hem_mbox.c#3 ++*/ ++ ++/*! \file "hem_mbox.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: hem_mbox.c ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device ++** have connected to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 05 03 2012 cp.wu ++ * [WCXRP00001231] [MT6620 Wi-Fi][MT5931][Driver] Correct SCAN_V2 related debugging facilities within hem_mbox.c ++ * correct for debug message string table by adding missed scan_v2 related definitions. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 17 2012 yuche.tsai ++ * NULL ++ * Update mgmt frame filter setting. ++ * Please also update FW 2.1 ++ * ++ * 01 13 2012 yuche.tsai ++ * NULL ++ * WiFi Hot Spot Tethering for ICS ALPHA testing version. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Add exception handle for NULL function pointer of mailbox message ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support ++ * as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Add invitation support. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation ++ * because NdisMSleep() won't sleep long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update bowString and channel grant. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 12 08 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support concurrent networks. ++ * ++ * 11 08 2010 cm.chang ++ * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID ++ * Remove CNM channel reover message ID ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Remove unused message ID ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add P2P Connection Abort Event Message handler. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 yarco.yang ++ * NULL ++ * Fixed Driver ASSERT at mboxInitMsgMap() ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. ++ * Update saa_fsm for BOW. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Add CFG_ENABLE_BT_OVER_WIFI. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add debug message for newly add P2P message. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some function entry for P2P FSM under provisioning phase.. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add some events to P2P Module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add message box event for P2P device switch on & device discovery. ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * remove unused mailbox message definitions. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * message table should not be commented out by compilation option without modifying header file ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Add wifi direct scan done callback. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * change handler of MID_MNY_CNM_CONNECTION_ABORT from NULL to mboxDummy. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Modify CNM message handler for new flow ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable currently migrated message call-backs. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * restore utility function invoking via hem_mbox to direct calls ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add buildable & linkable ais_fsm.c ++ * ++ * related reference are still waiting to be resolved ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * hem_mbox is migrated. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Fix file merge error ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 04 29 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Removed MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 04 27 2010 tehuang.liu ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Develop partial DPD code ++ * ++ * 02 11 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Updated arMsgMapTable for MID_RXM_MQM_QOS_ACTION_FRAME ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * Dec 9 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add hemRunEventScanDone() to arMsgMapTable[] ++ * ++ * Dec 4 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix mboxDummy() didn't free prMsgHdr ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add saaAisJoinComplete event handler ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Fixed the handler function name in arMsgMapTable for MID_RXM_MQM_BA_ACTION_FRAME ++ * ++ * Dec 2 2009 MTK02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Added MID_RXM_MQM_BA_ACTION_FRAME to MsgMapTable ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MSG Handler (remove dummy and add for SAA) ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add aisFsmRunEventAbort() event handler ++ * ++ * Nov 11 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Nov 10 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add more MSG_HNDL_ENTRY_T to avoid ASSERT() in mboxInitMsgMap() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add SCN message and function entry to arMsgMapTable[] ++ * ++ * Nov 2 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix sorting algorithm in mboxInitMsgMap() ++ * ++ * Oct 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugMsg[] = { ++ (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_ABORT"), ++ (PUINT_8) DISP_STRING("MID_CNM_AIS_CH_GRANT"), ++ (PUINT_8) DISP_STRING("MID_CNM_P2P_CH_GRANT"), ++ (PUINT_8) DISP_STRING("MID_CNM_BOW_CH_GRANT"), ++ ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ_V2"), ++ (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_CANCEL"), ++ (PUINT_8) DISP_STRING("MID_SCN_AIS_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_P2P_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_BOW_SCAN_DONE"), ++ (PUINT_8) DISP_STRING("MID_SCN_RLM_SCAN_DONE"), ++ ++ (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_JOIN_REQ"), ++ (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_AIS_JOIN_COMPLETE"), ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_BOW_JOIN_COMPLETE"), ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_START"), ++ (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_SAA_P2P_JOIN_COMPLETE"), ++ ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_FUN_SWITCH"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_DEVICE_DISCOVERY"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_BEACON_UPDATE"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_STOP_AP"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_REQ"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_TX"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_GROUP_DISSOLVE"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_FRAME_REGISTER"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_NET_DEV_REGISTER"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_START_AP"), ++ (PUINT_8) DISP_STRING("MID_MNY_P2P_UPDATE_IE_BUF"), ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ /* (PUINT_8)DISP_STRING("MID_AIS_CNM_CREATE_IBSS_REQ"), */ ++ /* (PUINT_8)DISP_STRING("MID_CNM_AIS_CREATE_IBSS_GRANT"), */ ++ /* (PUINT_8)DISP_STRING("MID_AIS_CNM_MERGE_IBSS_REQ"), */ ++ /* (PUINT_8)DISP_STRING("MID_CNM_AIS_MERGE_IBSS_GRANT"), */ ++ (PUINT_8) DISP_STRING("MID_SCN_AIS_FOUND_IBSS"), ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ (PUINT_8) DISP_STRING("MID_SAA_AIS_FSM_ABORT"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL"), ++ (PUINT_8) DISP_STRING("MID_MNY_AIS_MGMT_TX") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/* This message entry will be re-ordered based on the message ID order ++ * by invoking mboxInitMsgMap() ++ */ ++static MSG_HNDL_ENTRY_T arMsgMapTable[] = { ++ {MID_MNY_CNM_CH_REQ, cnmChMngrRequestPrivilege}, ++ {MID_MNY_CNM_CH_ABORT, cnmChMngrAbortPrivilege}, ++ {MID_CNM_AIS_CH_GRANT, aisFsmRunEventChGrant}, ++#if CFG_ENABLE_WIFI_DIRECT ++ {MID_CNM_P2P_CH_GRANT, p2pFsmRunEventChGrant}, /*set in gl_p2p_init.c */ ++#else ++ {MID_CNM_P2P_CH_GRANT, mboxDummy}, ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ {MID_CNM_BOW_CH_GRANT, bowRunEventChGrant}, ++#else ++ {MID_CNM_BOW_CH_GRANT, mboxDummy}, ++#endif ++ ++ /*--------------------------------------------------*/ ++ /* SCN Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_AIS_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_AIS_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_AIS_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_P2P_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_P2P_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_P2P_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_BOW_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_BOW_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_BOW_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_RLM_SCN_SCAN_REQ, scnFsmMsgStart}, ++ {MID_RLM_SCN_SCAN_REQ_V2, scnFsmMsgStart}, ++ {MID_RLM_SCN_SCAN_CANCEL, scnFsmMsgAbort}, ++ {MID_SCN_AIS_SCAN_DONE, aisFsmRunEventScanDone}, ++#if CFG_ENABLE_WIFI_DIRECT ++ {MID_SCN_P2P_SCAN_DONE, p2pFsmRunEventScanDone}, /*set in gl_p2p_init.c */ ++#else ++ {MID_SCN_P2P_SCAN_DONE, mboxDummy}, ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ {MID_SCN_BOW_SCAN_DONE, bowResponderScanDone}, ++#else ++ {MID_SCN_BOW_SCAN_DONE, mboxDummy}, ++#endif ++ {MID_SCN_RLM_SCAN_DONE, rlmObssScanDone}, ++ ++ /*--------------------------------------------------*/ ++ /* AIS Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_OID_AIS_FSM_JOIN_REQ, aisFsmRunEventAbort}, ++ {MID_OID_AIS_FSM_ABORT, aisFsmRunEventAbort}, ++ {MID_AIS_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_AIS_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_AIS_JOIN_COMPLETE, aisFsmRunEventJoinComplete}, ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /*--------------------------------------------------*/ ++ /* BOW Module Mailbox Messages */ ++ /*--------------------------------------------------*/ ++ {MID_BOW_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_BOW_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_BOW_JOIN_COMPLETE, bowFsmRunEventJoinComplete}, ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT /*set in gl_p2p_init.c */ ++ {MID_P2P_SAA_FSM_START, saaFsmRunEventStart}, ++ {MID_P2P_SAA_FSM_ABORT, saaFsmRunEventAbort}, ++ {MID_SAA_P2P_JOIN_COMPLETE, p2pFsmRunEventJoinComplete}, /* TODO: p2pFsmRunEventJoinComplete */ ++ ++ {MID_MNY_P2P_FUN_SWITCH, p2pFsmRunEventSwitchOPMode}, ++ {MID_MNY_P2P_DEVICE_DISCOVERY, p2pFsmRunEventScanRequest}, ++ {MID_MNY_P2P_CONNECTION_REQ, p2pFsmRunEventConnectionRequest}, ++ {MID_MNY_P2P_CONNECTION_ABORT, p2pFsmRunEventConnectionAbort}, ++ {MID_MNY_P2P_BEACON_UPDATE, p2pFsmRunEventBeaconUpdate}, ++ {MID_MNY_P2P_STOP_AP, p2pFsmRunEventStopAP}, ++ {MID_MNY_P2P_CHNL_REQ, p2pFsmRunEventChannelRequest}, ++ {MID_MNY_P2P_CHNL_ABORT, p2pFsmRunEventChannelAbort}, ++ {MID_MNY_P2P_MGMT_TX, p2pFsmRunEventMgmtFrameTx}, ++ {MID_MNY_P2P_GROUP_DISSOLVE, p2pFsmRunEventDissolve}, ++ {MID_MNY_P2P_MGMT_FRAME_REGISTER, p2pFsmRunEventMgmtFrameRegister}, ++ {MID_MNY_P2P_NET_DEV_REGISTER, p2pFsmRunEventNetDeviceRegister}, ++ {MID_MNY_P2P_START_AP, p2pFsmRunEventStartAP}, ++ {MID_MNY_P2P_MGMT_FRAME_UPDATE, p2pFsmRunEventUpdateMgmtFrame}, ++ {MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, p2pFsmRunEventExtendListen}, ++#if CFG_SUPPORT_WFD ++ {MID_MNY_P2P_WFD_CFG_UPDATE, p2pFsmRunEventWfdSettingUpdate}, ++#endif ++ ++#endif ++ ++#if CFG_SUPPORT_ADHOC ++ {MID_SCN_AIS_FOUND_IBSS, aisFsmRunEventFoundIBSSPeer}, ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ {MID_SAA_AIS_FSM_ABORT, aisFsmRunEventAbort}, ++ {MID_MNY_AIS_REMAIN_ON_CHANNEL, aisFsmRunEventRemainOnChannel}, ++ {MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, aisFsmRunEventCancelRemainOnChannel}, ++ {MID_MNY_AIS_MGMT_TX, aisFsmRunEventMgmtFrameTx} ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++#if DBG ++#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ ++ ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ ++ if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ ++ DBGLOG(CNM, LOUD, "DO MSG [%d: %s]\n", prMsg->eMsgId, apucDebugMsg[prMsg->eMsgId]); \ ++ arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ ++ } \ ++ else { \ ++ DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ ++ cnmMemFree(prAdapter, prMsg); \ ++ } \ ++} while (0) ++#else ++#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ ++ ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ ++ if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ ++ DBGLOG(CNM, LOUD, "DO MSG [%d]\n", prMsg->eMsgId); \ ++ arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ ++ } \ ++ else { \ ++ DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ ++ cnmMemFree(prAdapter, prMsg); \ ++ } \ ++} while (0) ++#endif ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxInitMsgMap(VOID) ++{ ++ UINT_32 i, idx; ++ MSG_HNDL_ENTRY_T rTempEntry; ++ ++ ASSERT((sizeof(arMsgMapTable) / sizeof(MSG_HNDL_ENTRY_T)) == MID_TOTAL_NUM); ++ ++ for (i = 0; i < MID_TOTAL_NUM; i++) { ++ if (arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i) ++ continue; ++ for (idx = i + 1; idx < MID_TOTAL_NUM; idx++) { ++ if (arMsgMapTable[idx].eMsgId == (ENUM_MSG_ID_T) i) ++ break; ++ } ++ ASSERT(idx < MID_TOTAL_NUM); ++ if (idx >= MID_TOTAL_NUM) ++ continue; ++ ++ /* Swap target entry and current entry */ ++ rTempEntry.eMsgId = arMsgMapTable[idx].eMsgId; ++ rTempEntry.pfMsgHndl = arMsgMapTable[idx].pfMsgHndl; ++ ++ arMsgMapTable[idx].eMsgId = arMsgMapTable[i].eMsgId; ++ arMsgMapTable[idx].pfMsgHndl = arMsgMapTable[i].pfMsgHndl; ++ ++ arMsgMapTable[i].eMsgId = rTempEntry.eMsgId; ++ arMsgMapTable[i].pfMsgHndl = rTempEntry.pfMsgHndl; ++ } ++ ++ /* Verify the correctness of final message map */ ++ for (i = 0; i < MID_TOTAL_NUM; i++) { ++ ASSERT(arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i); ++ while (arMsgMapTable[i].eMsgId != (ENUM_MSG_ID_T) i) ++ ; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId) ++{ ++ P_MBOX_T prMbox; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_INITIALIZE(&prMbox->rLinkHead); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++mboxSendMsg(IN P_ADAPTER_T prAdapter, ++ IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod) ++{ ++ P_MBOX_T prMbox; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prMsg); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ switch (eMethod) { ++ case MSG_SEND_METHOD_BUF: ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_INSERT_TAIL(&prMbox->rLinkHead, &prMsg->rLinkEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ /* to wake up main service thread */ ++ GLUE_SET_EVENT(prAdapter->prGlueInfo); ++ ++ break; ++ ++ case MSG_SEND_METHOD_UNBUF: ++ MBOX_HNDL_MSG(prAdapter, prMsg); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, ENUM_MBOX_ID_T eMboxId) ++{ ++ P_MBOX_T prMbox; ++ P_MSG_HDR_T prMsg; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); ++ ASSERT(prAdapter); ++ ++ prMbox = &(prAdapter->arMbox[eMboxId]); ++ ++ while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ ASSERT(prMsg); ++ MBOX_HNDL_MSG(prAdapter, prMsg); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* Initialize Mailbox */ ++ mboxInitMsgMap(); ++ ++ /* Setup/initialize each mailbox */ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) ++ mboxSetup(prAdapter, i); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxDestroy(IN P_ADAPTER_T prAdapter) ++{ ++ P_MBOX_T prMbox; ++ P_MSG_HDR_T prMsg; ++ UINT_8 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { ++ prMbox = &(prAdapter->arMbox[i]); ++ ++ while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); ++ ++ ASSERT(prMsg); ++ cnmMemFree(prAdapter, prMsg); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This is dummy function to prevent empty arMsgMapTable[] for compiling. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mboxDummy(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ASSERT(prAdapter); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c +new file mode 100644 +index 000000000000..7fb71a199ccf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c +@@ -0,0 +1,498 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/mgmt/hs20.c#2 ++*/ ++ ++/*! \file "hs20.c" ++ \brief This file including the hotspot 2.0 related function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer hotspot 2.0 related function. ++ ++*/ ++ ++/* ++** Log: hs20.c ++ * ++ */ ++ ++ /******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate Interworking IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate Roaming Consortium IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to generate HS2.0 IE for Probe Rsp, Bcn, Assoc Req/Rsp. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] prMsduInfo Pointer of the Msdu Info ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 221 :0xDD */ ++ if (prAdapter->prGlueInfo->u2HS20AssocInfoIELen) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucHS20AssocInfoIE, ++ prAdapter->prGlueInfo->u2HS20AssocInfoIELen); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2HS20AssocInfoIELen; ++ } ++ ++} ++ ++VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_HS20_EXT_CAP_T prExtCap; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_HS20_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ kalPrint("IE_SIZE(prExtCap) = %d, %d %d\n", IE_SIZE(prExtCap), ELEM_HDR_LEN, ELEM_MAX_LEN_EXT_CAP); ++ ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to fill up the content of Ext Cap IE bit 31. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] pucIE Pointer of the IE buffer ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) ++{ ++ P_HS20_EXT_CAP_T prExtCap; ++ ++ ASSERT(prAdapter); ++ ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_HS20_EXT_CAP_T) pucIE; ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to fill up the content of HS2.0 IE. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[out] pucIE Pointer of the IE buffer ++* ++* \return VOID ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) ++{ ++ P_IE_HS20_INDICATION_T prHS20IndicationIe; ++ /* P_HS20_INFO_T prHS20Info; */ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ /* prHS20Info = &(prAdapter->rWifiVar.rHS20Info); */ ++ ++ prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pucIE; ++ ++ prHS20IndicationIe->ucId = ELEM_ID_VENDOR; ++ prHS20IndicationIe->ucLength = sizeof(IE_HS20_INDICATION_T) - ELEM_HDR_LEN; ++ prHS20IndicationIe->aucOui[0] = aucWfaOui[0]; ++ prHS20IndicationIe->aucOui[1] = aucWfaOui[1]; ++ prHS20IndicationIe->aucOui[2] = aucWfaOui[2]; ++ prHS20IndicationIe->ucType = VENDOR_OUI_TYPE_HS20; ++ prHS20IndicationIe->ucHotspotConfig = 0x00; /* prHS20Info->ucHotspotConfig; */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called while calculating length of hotspot 2.0 indication IE for Probe Request. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] pucTargetBSSID Pointer of target HESSID ++* ++* \return the length of composed HS20 IE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID) ++{ ++ UINT_32 u4IeLength; ++ ++ if (0) /* Todo:: Not HS20 STA */ ++ return 0; ++ ++ u4IeLength = ++ sizeof(IE_HS20_INDICATION_T) + /* sizeof(IE_INTERWORKING_T) */ + (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP); ++ ++ if (!pucTargetBSSID) { ++ /* Do nothing */ ++ /* u4IeLength -= MAC_ADDR_LEN; */ ++ } ++ ++ return u4IeLength; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called while composing hotspot 2.0 indication IE for Probe Request. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* \param[in] pucTargetBSSID Pointer of target HESSID ++* \param[out] prIE Pointer of the IE buffer ++* ++* \return the wlan status ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE) ++{ ++ if (0) /* Todo:: Not HS20 STA */ ++ return 0; ++#if 0 ++ P_HS20_INFO_T prHS20Info; ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ ++ /* ++ * Generate 802.11u Interworking IE (107) ++ */ ++ hs20FillInterworkingIE(prAdapter, ++ prHS20Info->ucAccessNetworkOptions, ++ prHS20Info->ucVenueGroup, prHS20Info->ucVenueType, pucTargetBSSID, prIE); ++ prIE += IE_SIZE(prIE); ++#endif ++ /* ++ * Generate Ext Cap IE (127) ++ */ ++ hs20FillProreqExtCapIE(prAdapter, prIE); ++ prIE += IE_SIZE(prIE); ++ ++ /* ++ * Generate HS2.0 Indication IE (221) ++ */ ++ hs20FillHS20IE(prAdapter, prIE); ++ prIE += IE_SIZE(prIE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_8 pucSenderIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SENDER_IP_OFFSET; ++ PUINT_8 pucTargetIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_IP_OFFSET; ++ PUINT_8 pucSenderMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SNEDER_MAC_OFFSET); ++#if CFG_HS20_DEBUG && 0 ++/* UINT_8 aucIpAllZero[4] = {0,0,0,0}; */ ++/* UINT_8 aucMACAllZero[MAC_ADDR_LEN] = {0,0,0,0,0,0}; */ ++ PUINT_8 pucTargetMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_MAC_OFFSET); ++#endif ++ ++#if CFG_HS20_DEBUG && 0 ++ PUINT_16 pu2ArpOper = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_OPERATION_OFFSET); ++ ++ kalPrint("Recv ARP 0x%04X\n", htons(*pu2ArpOper)); ++ kalPrint("SENDER[ %pM ] [%pI4]\n", pucSenderMac, pucSenderIP); ++ kalPrint("TARGET[ %pM ] [%pI4]\n", pucTargetMac, pucTargetIP); ++#endif ++ ++ /* IsGratuitousArp */ ++ if (!kalMemCmp(pucSenderIP, pucTargetIP, 4)) { ++ kalPrint("Drop Gratuitous ARP from [ %pM ] [%pI4]\n", pucSenderMac, pucTargetIP); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_8 pucIpv6Protocol = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_PROTOCOL_OFFSET); ++ ++ /* kalPrint("pucIpv6Protocol [%02X:%02X]\n", *pucIpv6Protocol, IPV6_PROTOCOL_ICMPV6); */ ++ if (*pucIpv6Protocol == IPV6_PROTOCOL_ICMPV6) { ++ PUINT_8 pucICMPv6Type = ++ ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_TYPE_OFFSET); ++ /* kalPrint("pucICMPv6Type [%02X:%02X]\n", *pucICMPv6Type, ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT); */ ++ if (*pucICMPv6Type == ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT) { ++ PUINT_8 pucICMPv6Flag = ++ ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_FLAG_OFFSET); ++ PUINT_8 pucSrcMAC = ((PUINT_8) prCurrSwRfb->pvHeader + MAC_ADDR_LEN); ++ ++#if CFG_HS20_DEBUG ++ kalPrint("NAdv Flag [%02X] [R(%d)\\S(%d)\\O(%d)]\n", ++ *pucICMPv6Flag, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_ROUTER_BIT) >> 7, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT) >> 6, ++ (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_OVERWRITE_BIT) >> 5); ++#endif ++ if (!(*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT)) { ++ kalPrint("Drop Unsolicited Neighbor Advertisement from [%pM]\n", pucSrcMAC); ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ /* ++ P_CONNECTION_SETTINGS_T prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ PUINT_8 pucEthDestAddr = prCurrSwRfb->pvHeader; ++ */ ++ /* 3 TODO: Need to verify this function before enable it */ ++ return FALSE; ++ /* ++ if ((prConnSettings->eEncStatus != ENUM_ENCRYPTION_DISABLED) && IS_BMCAST_MAC_ADDR(pucEthDestAddr)) { ++ UINT_8 ucIdx = 0; ++ PUINT_32 prIpAddr, prPacketDA; ++ PUINT_16 pu2PktIpVer = ++ (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); ++ ++ if (*pu2PktIpVer == htons(ETH_P_IPV4)) { ++ if (!prBssInfo->prIpV4NetAddrList) ++ return FALSE; ++ for (ucIdx = 0; ucIdx < prBssInfo->prIpV4NetAddrList->ucAddrCount; ucIdx++) { ++ prIpAddr = (PUINT_32) &prBssInfo->prIpV4NetAddrList->arNetAddr[ucIdx].aucIpAddr[0]; ++ prPacketDA = ++ (PUINT_32) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ++ IPV4_HDR_IP_DST_ADDR_OFFSET); ++ ++ if (kalMemCmp(prIpAddr, prPacketDA, 4) == 0) { ++ kalPrint("Drop FORGED IPv4 packet\n"); ++ return TRUE; ++ } ++ } ++ } ++#ifdef CONFIG_IPV6 ++ else if (*pu2PktIpVer == htons(ETH_P_IPV6)) { ++ UINT_8 aucIPv6Mac[MAC_ADDR_LEN]; ++ PUINT_8 pucIdx = ++ prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET; ++ ++ kalMemCopy(&aucIPv6Mac[0], pucIdx, 3); ++ pucIdx += 5; ++ kalMemCopy(&aucIPv6Mac[3], pucIdx, 3); ++ kalPrint("Get IPv6 frame Dst IP MAC part %pM\n", aucIPv6Mac); ++ if (EQUAL_MAC_ADDR(aucIPv6Mac, prBssInfo->aucOwnMacAddr)) { ++ kalPrint("Drop FORGED IPv6 packet\n"); ++ return TRUE; ++ } ++ } ++#endif ++ } ++ ++ return FALSE; ++ */ ++} ++#endif ++ ++BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) ++{ ++ PUINT_16 pu2PktIpVer = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); ++ ++ /* kalPrint("IPVER 0x%4X\n", htons(*pu2PktIpVer)); */ ++#if CFG_HS20_DEBUG & 0 ++ UINT_8 i = 0; ++ ++ kalPrint("==============================================="); ++ for (i = 0; i < 96; i++) { ++ if (!(i % 16)) ++ kalPrint("\n"); ++ kalPrint("%02X ", *((PUINT_8) prCurrSwRfb->pvHeader + i)); ++ } ++ kalPrint("\n"); ++#endif ++ ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ if (hs20IsForgedGTKFrame(prAdapter, prBssInfo, prCurrSwRfb)) ++ return TRUE; ++ ++#endif ++ if (*pu2PktIpVer == htons(ETH_P_ARP)) ++ return hs20IsGratuitousArp(prAdapter, prCurrSwRfb); ++ else if (*pu2PktIpVer == htons(ETH_P_IPV6)) ++ return hs20IsUnsolicitedNeighborAdv(prAdapter, prCurrSwRfb); ++ ++ return FALSE; ++} ++ ++BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) ++{ ++#if 1 ++ if (prAdapter->prGlueInfo->fgConnectHS20AP) ++ return TRUE; ++#else ++ PARAM_SSID_T rParamSsid; ++ P_BSS_DESC_T prBssDesc; ++ ++ rParamSsid.u4SsidLen = prBssInfo->ucSSIDLen; ++ COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ ++ prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, prBssInfo->aucBSSID, TRUE, &rParamSsid); ++ if (!prBssDesc) ++ return FALSE; ++ ++ if (prBssDesc->fgIsSupportHS20) { ++ if (!(prBssDesc->ucHotspotConfig & ELEM_HS_CONFIG_DGAF_DISABLED_MASK)) ++ return TRUE; ++ ++ /* Disable frame filter only if DGAF == 1 */ ++ return FALSE; ++ ++ } ++#endif ++ ++ /* For Now, always return true to run hs20 check even for legacy AP */ ++ return TRUE; ++} ++ ++WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) ++{ ++ P_PARAM_HS20_SET_BSSID_POOL prParamBssidPool = (P_PARAM_HS20_SET_BSSID_POOL) pvBuffer; ++ P_HS20_INFO_T prHS20Info; ++ UINT_8 ucIdx; ++ ++ prHS20Info = &(prAdapter->rWifiVar.rHS20Info); ++ kalPrint("[%s]Set Bssid Pool! enable[%d] num[%d]\n", __func__, prParamBssidPool->fgIsEnable, ++ prParamBssidPool->ucNumBssidPool); ++ for (ucIdx = 0; ucIdx < prParamBssidPool->ucNumBssidPool; ucIdx++) { ++ COPY_MAC_ADDR(prHS20Info->arBssidPool[ucIdx].aucBSSID, &prParamBssidPool->arBSSID[ucIdx]); ++ kalPrint("[%s][%d][ %pM ]\n", __func__, ucIdx, (prHS20Info->arBssidPool[ucIdx].aucBSSID)); ++ } ++ prHS20Info->fgIsHS2SigmaMode = prParamBssidPool->fgIsEnable; ++ prHS20Info->ucNumBssidPoolEntry = prParamBssidPool->ucNumBssidPool; ++ ++#if 0 ++ wlanClearScanningResult(prAdapter); ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c +new file mode 100644 +index 000000000000..469a48ebe9c1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c +@@ -0,0 +1,111 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/mib.c#1 ++*/ ++ ++/*! \file "mib.c" ++ \brief This file includes the mib default vale and functions. ++*/ ++ ++/* ++** Log: mib.c ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add mib.c. ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[] = { ++ {RATE_SET_HR_DSSS, TRUE, FALSE} ++ , /* For PHY_TYPE_HR_DSSS_INDEX(0) */ ++ {RATE_SET_ERP, TRUE, TRUE} ++ , /* For PHY_TYPE_ERP_INDEX(1) */ ++ {RATE_SET_ERP_P2P, TRUE, TRUE} ++ , /* For PHY_TYPE_ERP_P2P_INDEX(2) */ ++ {RATE_SET_OFDM, FALSE, FALSE} ++ , /* For PHY_TYPE_OFDM_INDEX(3) */ ++}; ++ ++NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[AD_HOC_MODE_NUM] = { ++ {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} ++ , /* For AD_HOC_MODE_11B(0) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} ++ , /* For AD_HOC_MODE_MIXED_11BG(1) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} ++ , /* For AD_HOC_MODE_11G(2) */ ++ {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} ++ , /* For AD_HOC_MODE_11A(3) */ ++}; ++ ++NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[AP_MODE_NUM] = { ++ {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} ++ , /* For AP_MODE_11B(0) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} ++ , /* For AP_MODE_MIXED_11BG(1) */ ++ {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} ++ , /* For AP_MODE_11G(2) */ ++ {PHY_TYPE_ERP_P2P_INDEX, BASIC_RATE_SET_ERP_P2P} ++ , /* For AP_MODE_11G_P2P(3) */ ++ {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} ++ , /* For AP_MODE_11A(4) */ ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c +new file mode 100644 +index 000000000000..cb5fbebedd49 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c +@@ -0,0 +1,87 @@ ++/* ++** Id: @(#) p2p_assoc.c@@ ++*/ ++ ++/*! \file "p2p_assoc.c" ++ \brief This file includes the Wi-Fi Direct association-related functions. ++ ++ This file includes the association-related functions. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to compose Common Information Elements for P2P Association ++* Request Frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ /* Fill the SSID element. */ ++ SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; ++ ++ /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of ++ * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. ++ */ ++ ++ COPY_SSID(SSID_IE(pucBuffer)->aucSSID, ++ SSID_IE(pucBuffer)->ucLength, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ return pucBuffer; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c +new file mode 100644 +index 000000000000..72a20a322cee +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c +@@ -0,0 +1,58 @@ ++/* ++** Id: @(#) p2p_bss.c@@ ++*/ ++ ++/*! \file "p2p_bss.c" ++ \brief This file contains the functions for creating p2p BSS(AP). ++ ++ This file contains the functions for BSS(AP). We may create a BSS ++ network, or merge with exist IBSS network and sending Beacon Frame or reply ++ the Probe Response Frame for received Probe Request Frame. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c +new file mode 100644 +index 000000000000..f8c09e2aa9de +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c +@@ -0,0 +1,3139 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/mgmt/p2p_fsm.c#61 ++*/ ++ ++/*! \file "p2p_fsm.c" ++ \brief This file defines the FSM for P2P Module. ++ ++ This file defines the FSM for P2P Module. ++*/ ++ ++/* ++** Log: p2p_fsm.c ++** ++** 12 20 2012 yuche.tsai ++** [ALPS00410124] [Rose][Free Test][KE][rlmUpdateParamsForAP]The device reboot automatically ++** and then "Fatal/Kernel" pops up during use data service.(Once) ++** Fix possible NULL station record cause KE under AP mode. ++** May due to variable uninitial. ++** Review: http://mtksap20:8080/go?page=NewReview&reviewid=49970 ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected ++**to AP previously,one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 08 21 2012 yuche.tsai ++** NULL ++** fix disconnect indication. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix p2p bug find on ALPS.JB trunk. ++** ++** 07 27 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update for driver unload KE issue. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Fix the compile flag of enhancement. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000808] [Volunteer Patch][MT6620][Driver/FW] Device discoverability issue fix ++ * Change device discoverability methodology. From driver SCAN to FW lock channel. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Add wifi direct connection enhancement method I, II & VI. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000833] [Volunteer Patch][WiFi Direct][Driver] Service Discovery Frame RX Indicate Issue ++ * Fix Service Discovery Race Condition Issue. ++ * ++ * 06 23 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * change parameter name from PeerAddr to BSSID ++ * ++ * 06 21 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix an issue of accepting connection of GO. ++ * ++ * 06 21 2011 yuche.tsai ++ * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability ++ * Drop GAS frame when SD is not enabled. ++ * ++ * 06 20 2011 yuche.tsai ++ * NULL ++ * Fix compile error. ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. ++ * Fix connection indication twice issue. ++ * ++ * 06 20 2011 cp.wu ++ * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module ++ * 1. specify target's BSSID when requesting channel privilege. ++ * 2. pass BSSID information to firmware domain ++ * ++ * 06 20 2011 yuche.tsai ++ * [WCXRP00000795] [Volunteer Patch][MT6620][Driver] GO can not connect second device issue ++ * Solve P2P GO can not formation with second device issue. ++ * ++ * 06 14 2011 yuche.tsai ++ * NULL ++ * Change disconnect feature. ++ * ++ * 06 10 2011 yuche.tsai ++ * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability[WCXRP00000776] ++ * [Need Patch][MT6620][Driver] MT6620 response probe request of P2P device with P2P IE under Hot Spot mode. ++ * 1. Dynamic enable SD capability after P2P supplicant ready. ++ * 2. Avoid response probe respone with p2p IE when under hot spot mode. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction ++ * eliminate unused parameters for SAA-FSM ++ * ++ * 05 26 2011 yuche.tsai ++ * [WCXRP00000745] Support accepting connection after one Group Connection Lost. ++ ++After Group Formation & lost connection, if MT6620 behave as: ++ ++1. GO: It would keep under GO state until been dissolved by supplicant. ++ ++ At this time, other P2P device can use join method to join this group. ++ ++2. GC: It would keep on searching target GO or target device until been dissolved by supplicant. ++ ++At this time, it would ignore other P2P device formation request. ++ ++-- ++ ++Modification: Make driver to accept GO NEGO REQ at this time, to let user decide to accept new connection or not. ++ ++ * [Volunteer Patch][MT6620][Driver] ++ * Driver would indicate connection request, if password ID is not ready but connection request is issued. ++ * ++ * 05 18 2011 yuche.tsai ++ * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. ++ * A solution for both connection request & IO control. ++ * ++ * 05 16 2011 yuche.tsai ++ * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. ++ * Fix SD request can not send out issue. ++ * ++ * 05 09 2011 terry.wu ++ * [WCXRP00000711] [MT6620 Wi-Fi][Driver] Set Initial value of StaType in StaRec for Hotspot Client ++ * Set initial value of StaType in StaRec for hotspot client. ++ * ++ * 05 04 2011 yuche.tsai ++ * [WCXRP00000697] [Volunteer Patch][MT6620][Driver] ++ * Bug fix for p2p descriptor is NULL if BSS descriptor is found first. ++ * ++ * 05 04 2011 yuche.tsai ++ * NULL ++ * Support partial persistent group function. ++ * ++ * 05 02 2011 yuche.tsai ++ * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. ++ * Clear formation flag after formation timeout. ++ * ++ * 04 20 2011 yuche.tsai ++ * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition ++ * when add scan & query scan result at the same time. ++ * Fix side effect while starting ATGO. ++ * ++ * 04 20 2011 yuche.tsai ++ * NULL ++ * Fix ASSERT issue in FW, side effect of last change. ++ * ++ * 04 19 2011 yuche.tsai ++ * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition ++ * when add scan & query scan result at the same time. ++ * Workaround for multiple device connection, before invitation ready. ++ * ++ * 04 19 2011 yuche.tsai ++ * [WCXRP00000665] [Wifi Direct][MT6620 E4] When use Ralink's dongle to establish wifi direct connection with PBC. ++ * But 6573 always not pop accept option to establish connection. ++ * Support connection indication when GO NEGO REQ doesn't have configure method, instead it has PasswordID. ++ * ++ * 04 18 2011 yuche.tsai ++ * NULL ++ * Fix error. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Fix a connection issue. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Fix the channel issue of AP mode. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Connection flow refine for Sigma test. ++ * ++ * 04 09 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix Device discoverability related issue. ++ * ++ * 04 09 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix bug for Device Discoverability. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Fix compile error. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 03 28 2011 yuche.tsai ++ * NULL ++ * Fix a possible issue for retry join when media status connected. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 24 2011 yuche.tsai ++ * NULL ++ * Assign AID before change STA_REC state to state 3. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix Response Rate Issue when TX Auth Rsp Frame under P2P Mode. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix issue of connection to one GC. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix ASSERT issue when starting Hot-spot. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * When Target Information is not available, change to passive mode. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Fix one connection issue while using Keypad to connect a GO. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1. Fix two issues that may cause kernel panic. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Fix GC connect to other device issue. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * 1.Shorten the LISTEN interval. ++ * 2. Fix IF address issue when we are GO ++ * 3. Fix LISTEN channel issue. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Modify formation policy setting. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Solve Listen State doesn't response probe response issue. ++ * ++ * 03 21 2011 yuche.tsai ++ * NULL ++ * Change P2P Connection Request Flow. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue ++ * Indicate the correct Group SSID when join on Group. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue ++ * Support the third P2P device to join GO/GC group. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue ++ * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000578] [Volunteer Patch][MT6620][Driver] Separate Connection Request from general IOCTL ++ * Separate connection request from general IOCTL. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * When AIS is connect to an AP, Hot Spot would be enabled under fixed same channel. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Solve the Group Info IE in Probe Response incorrect issue. ++ * ++ * 03 17 2011 yuche.tsai ++ * NULL ++ * Release Channel after Join Complete. ++ * ++ * 03 16 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the protected while at P2P start GO, and skip some security check . ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix local configure method issue. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 14 2011 yuche.tsai ++ * NULL ++ * . ++ * ++ * 03 14 2011 yuche.tsai ++ * NULL ++ * Fix password ID issue. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 08 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue[WCXRP00000509] ++ * [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. ++ * . ++ * ++ * 03 07 2011 yuche.tsai ++ * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. ++ * . ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 04 2011 wh.su ++ * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue ++ * fixed the p2p action frame type check for device request indication. ++ * ++ * 03 02 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Service Discovery RX packet buffer pointer. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Update Service Discovery Related wlanoid function. ++ * ++ * 02 21 2011 yuche.tsai ++ * [WCXRP00000481] [Volunteer Patch][MT6620][FW] Scan hang under concurrent case. ++ * Fix all BE issue of WSC or P2P IE. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the wsc config method mapping to driver used config method issue. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000479] [Volunteer Patch][MT6620][Driver] Probe Response of P2P using 11b rate. ++ * Update basic rate to FW, after P2P is initialed. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame during search ++ * phase do not contain P2P wildcard SSID. ++ * Use P2P Wildcard SSID when scan type of P2P_WILDCARD_SSID is set. ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC IE BE format issue. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 16 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * fixed the probe request send out without WSC IE issue (at P2P). ++ * ++ * 02 16 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * If two station connected to the Hot-Spot and one disconnect, FW would get into an infinite loop ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix re-connection issue after RX deauthentication. ++ * ++ * 02 15 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Fix conneciton issue after disconnect with AP. ++ * ++ * 02 12 2011 yuche.tsai ++ * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. ++ * P2P Create Station Type according to Target BSS capability. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Support Disassoc & Deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Indication Related code. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue ++ * Fix Client Limit Issue. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect ++ * to target station for AAA module. ++ * Disconnect every station client when disolve on P2P group. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * 1. Fix Service Disocvery Logical issue. ++ * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect ++ * to target station for AAA module. ++ * Workaround of disable P2P network. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue ++ * 1. Fixed SSID wrong length issue. ++ * 2. Under Hot Spot configuration, there won't be any P2P IE. ++ * 3. Under Hot Spot configuration, P2P FSM won't get into LISTEN state first. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Modify Start GO flow. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix desire phy type set issue. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Add desire phy type set phase I. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix P2P Disconnect Issue. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Add Service Discovery Function. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix compile error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type Definition. ++ * ++ * 01 19 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Add P2P QoS Support. ++ * ++ * 01 19 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Null NOA attribute setting when no related parameters. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify AAA flow according to CM's comment. ++ * ++ * 01 13 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Resolve Channel ZERO issue. (Uninitialized default channel) ++ * ++ * 01 13 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Update P2P State Debug Message. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Fix bug when allocating message buffer. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update ++ * when STA record is created under AP Mode. ++ * Update Phy Type Set. When legacy client is connected, it can use 11b rate, ++ * but if the P2P device is connected, 11b rate is not allowed. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. ++ * 2. Call cnmP2pIsPermit() before active P2P network. ++ * 3. Add channel selection support for AP mode. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix Bug of reference to NULL pointer. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Modify some behavior of AP mode. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix bug of wrong pointer check. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix Compile Error. ++ * ++ * 01 11 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Add station record into client list before change it state from STATE_2 to STATE_3. ++ * ++ * 01 05 2011 yuche.tsai ++ * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, ++ * but the SSID length is still invalid. ++ * Specify SSID Type when issue a scan request. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * correct typo ++ * ++ * 01 05 2011 george.huang ++ * [WCXRP00000343] [MT6620 Wi-Fi] Add TSF reset path for concurrent operation ++ * modify NOA update path for preventing assertion false alarm. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations ++ * to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 01 03 2011 wh.su ++ * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * let the p2p ap mode acept a legacy device join. ++ * ++ * 12 22 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Fix Compile Error. ++ * ++ * 12 15 2010 yuche.tsai ++ * [WCXRP00000245] 1. Invitation Request/Response. ++2. Provision Discovery Request/Response ++ ++ * Refine Connection Flow. ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. ++ * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client ++ * by checking the P2P IE in assoc req frame. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * The order of invoking nicUpdateBss() and rlm functions ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation. ++ * ++ * 12 02 2010 yuche.tsai ++ * NULL ++ * Update P2P Connection Policy for Invitation & Provision Discovery. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Update RCIP value when RX assoc request frame. ++ * ++ * 11 29 2010 yuche.tsai ++ * NULL ++ * Update P2P related function for INVITATION & PROVISION DISCOVERY. ++ * ++ * 11 26 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Update P2P PS for NOA function. ++ * ++ * 11 25 2010 yuche.tsai ++ * NULL ++ * Update Code for Invitation Related Function. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] ++ * Set the Tx lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * fixed the p2p role code error. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * fixed the ASSERT check error ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 19 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state ++ * machine[WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * fixed the compiling error. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android ++ * adding a code to support Direct GO with a compiling flag . ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. ++ * correct erroneous logic: specifying eBand with incompatible eSco ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * fixed the compiling error. ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at WinXP. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Reset Common IE Buffer of P2P INFO when scan request is issued. ++ * If an action frame other than public action frame is received, return direcly. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Add P2P Connection Abort Event Message handler. ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 yuche.tsai ++ * NULL ++ * 1. Fix Interface Address from GO Nego Req/Rsp is not correct. ++ * 2. Fix GO mode does not change media state after station connected. ++ * 3. Fix STA don't response probe request when there is a connection request. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 20 2010 kevin.huang ++ * NULL ++ * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Add Glue Layer indication. ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix compile warning under Linux. ++ * ++ * 08 17 2010 yuche.tsai ++ * NULL ++ * Fix some P2P FSM bug. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add random Interface Address Generation support. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix some P2P FSM bug. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM code for GO Nego. ++ * ++ * 08 16 2010 kevin.huang ++ * NULL ++ * Refine AAA functions ++ * ++ * 08 12 2010 kevin.huang ++ * NULL ++ * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Join complete indication. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add two boolean in connection request. ++ * Based on these two boolean value, P2P FSM should ++ * decide to do invitation or group formation or start a GO directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM, currently P2P Device Discovery is verified. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update P2P FSM for group formation. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * limit build always needs spin-lock declaration. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add P2P FSM code check in. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 yuche.tsai ++ * ++ * Update P2P FSM. ++ * ++ * 07 09 2010 george.huang ++ * ++ * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error while enable WIFI_DIRECT support. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Update P2P Function call. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * First draft for migration P2P FSM from FW to Driver. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Rename CFG flag for P2P ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add code to test P2P GO ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add Wi-Fi Direct SSID and P2P GO Test Mode ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Modify code due to BAND_24G define was changed ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Revise data structure to share the same BSS_INFO_T for avoiding coding error ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugP2pState[P2P_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("P2P_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("P2P_STATE_SCAN"), ++ (PUINT_8) DISP_STRING("P2P_STATE_AP_CHANNEL_DETECT"), ++ (PUINT_8) DISP_STRING("P2P_STATE_REQING_CHANNEL"), ++ (PUINT_8) DISP_STRING("P2P_STATE_CHNL_ON_HAND"), ++ (PUINT_8) DISP_STRING("P2P_STATE_GC_JOIN") ++}; ++ ++/*lint -restore */ ++#else ++static UINT_8 apucDebugP2pState[P2P_STATE_NUM] = { ++ P2P_STATE_IDLE, ++ P2P_STATE_SCAN, ++ P2P_STATE_AP_CHANNEL_DETECT, ++ P2P_STATE_REQING_CHANNEL, ++ P2P_STATE_CHNL_ON_HAND, ++ P2P_STATE_GC_JOIN ++}; ++ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/* p2pStateXXX : Processing P2P FSM related action. ++ * p2pFSMXXX : Control P2P FSM flow. ++ * p2pFuncXXX : Function for doing one thing. ++ */ ++VOID p2pFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ ASSERT_BREAK(prP2pFsmInfo != NULL); ++ ++ LINK_INITIALIZE(&(prP2pFsmInfo->rMsgEventQueue)); ++ LINK_INITIALIZE(&(prP2pBssInfo->rStaRecOfClientList)); ++ ++ prP2pFsmInfo->eCurrentState = prP2pFsmInfo->ePreviousState = P2P_STATE_IDLE; ++ prP2pFsmInfo->prTargetBss = NULL; ++ prP2pFsmInfo->fgIsWPSMode = 0; ++ ++ cnmTimerInitTimer(prAdapter, ++ &(prAdapter->rP2pFsmTimeoutTimer), ++ (PFN_MGMT_TIMEOUT_FUNC) p2pFsmRunEventFsmTimeout, (ULONG) prP2pFsmInfo); ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <2.1> Initiate BSS_INFO_T - Setup HW ID */ ++ prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; ++ prP2pBssInfo->ucHwDefaultFixedRateCode = RATE_OFDM_6M; ++ ++ prP2pBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prP2pBssInfo->u2BSSBasicRateSet = ++ rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ ++ prP2pBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prP2pBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ rateGetDataRatesFromRateSet(prP2pBssInfo->u2OperationalRateSet, ++ prP2pBssInfo->u2BSSBasicRateSet, ++ prP2pBssInfo->aucAllSupportedRates, &prP2pBssInfo->ucAllSupportedRatesLen); ++ ++ prP2pBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, ++ OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prP2pBssInfo->prBeacon) { ++ prP2pBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prP2pBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ ++ prP2pBssInfo->prBeacon->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } else { ++ /* Out of memory. */ ++ ASSERT(FALSE); ++ } ++ ++ prP2pBssInfo->eCurrentOPMode = OP_MODE_NUM; ++ ++ prP2pBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prP2pBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prP2pBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++ prP2pBssInfo->ucPrimaryChannel = P2P_DEFAULT_LISTEN_CHANNEL; ++ prP2pBssInfo->eBand = BAND_2G4; ++ prP2pBssInfo->eBssSCO = CHNL_EXT_SCN; ++ ++ if (prAdapter->rWifiVar.fgSupportQoS) ++ prP2pBssInfo->fgIsQBSS = TRUE; ++ else ++ prP2pBssInfo->fgIsQBSS = FALSE; ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } while (FALSE); ++ ++} /* p2pFsmInit */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function is used to uninitialize the value in P2P_FSM_INFO_T for ++* P2P FSM operation ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ DEBUGFUNC("p2pFsmUninit()"); ++ DBGLOG(P2P, INFO, "->p2pFsmUninit()\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, OP_MODE_P2P_DEVICE, TRUE); ++ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, P2P_STATE_NUM); ++ ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ wlanAcquirePowerControl(prAdapter); ++ ++ /* Release all pending CMD queue. */ ++ DBGLOG(P2P, TRACE, "p2pFsmUninit: wlanProcessCommandQueue, num of element:%d\n", ++ (UINT_32) prAdapter->prGlueInfo->rCmdQueue.u4NumElem); ++ wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); ++ ++ wlanReleasePowerControl(prAdapter); ++ ++ /* Release pending mgmt frame, ++ * mgmt frame may be pending by CMD without resource. ++ */ ++ kalClearMgmtFramesByNetType(prAdapter->prGlueInfo, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Clear PendingCmdQue */ ++ wlanReleasePendingCMDbyNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ if (prP2pBssInfo->prBeacon) { ++ cnmMgtPktFree(prAdapter, prP2pBssInfo->prBeacon); ++ prP2pBssInfo->prBeacon = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* end of p2pFsmUninit() */ ++ ++VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ BOOLEAN fgIsTransOut = (BOOLEAN) FALSE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (!IS_BSS_ACTIVE(prP2pBssInfo)) { ++ if (!cnmP2PIsPermitted(prAdapter)) ++ return; ++ ++ SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ fgIsTransOut = fgIsTransOut ? FALSE : TRUE; ++ ++ if (!fgIsTransOut) { ++#if DBG ++ DBGLOG(P2P, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugP2pState[prP2pFsmInfo->eCurrentState], ++ apucDebugP2pState[eNextState]); ++#else ++ DBGLOG(P2P, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_P2P_IDX, apucDebugP2pState[prP2pFsmInfo->eCurrentState], ++ apucDebugP2pState[eNextState]); ++#endif ++ ++ /* Transition into current state. */ ++ prP2pFsmInfo->ePreviousState = prP2pFsmInfo->eCurrentState; ++ prP2pFsmInfo->eCurrentState = eNextState; ++ } ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_IDLE: ++ if (fgIsTransOut) ++ p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, eNextState); ++ else ++ fgIsTransOut = p2pStateInit_IDLE(prAdapter, prP2pFsmInfo, prP2pBssInfo, &eNextState); ++ break; ++ case P2P_STATE_SCAN: ++ if (fgIsTransOut) { ++ /* Scan done / scan canceled. */ ++ p2pStateAbort_SCAN(prAdapter, prP2pFsmInfo, eNextState); ++ } else { ++ /* Initial scan request. */ ++ p2pStateInit_SCAN(prAdapter, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_AP_CHANNEL_DETECT: ++ if (fgIsTransOut) { ++ /* Scan done */ ++ /* Get sparse channel result. */ ++ p2pStateAbort_AP_CHANNEL_DETECT(prAdapter, ++ prP2pFsmInfo, prP2pSpecificBssInfo, eNextState); ++ } ++ ++ else { ++ /* Initial passive scan request. */ ++ p2pStateInit_AP_CHANNEL_DETECT(prAdapter, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_REQING_CHANNEL: ++ if (fgIsTransOut) { ++ /* Channel on hand / Channel canceled. */ ++ p2pStateAbort_REQING_CHANNEL(prAdapter, prP2pFsmInfo, eNextState); ++ } else { ++ /* Initial channel request. */ ++ p2pFuncAcquireCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ break; ++ case P2P_STATE_CHNL_ON_HAND: ++ if (fgIsTransOut) { ++ p2pStateAbort_CHNL_ON_HAND(prAdapter, prP2pFsmInfo, prP2pBssInfo, eNextState); ++ } else { ++ /* Initial channel ready. */ ++ /* Send channel ready event. */ ++ /* Start a FSM timer. */ ++ p2pStateInit_CHNL_ON_HAND(prAdapter, prP2pBssInfo, prP2pFsmInfo); ++ } ++ ++ break; ++ case P2P_STATE_GC_JOIN: ++ if (fgIsTransOut) { ++ /* Join complete / join canceled. */ ++ p2pStateAbort_GC_JOIN(prAdapter, prP2pFsmInfo, &(prP2pFsmInfo->rJoinInfo), eNextState); ++ } else { ++ if (prP2pFsmInfo->prTargetBss == NULL) { ++ ASSERT(FALSE); ++ } else { ++ /* Send request to SAA module. */ ++ p2pStateInit_GC_JOIN(prAdapter, ++ prP2pFsmInfo, ++ prP2pBssInfo, ++ &(prP2pFsmInfo->rJoinInfo), prP2pFsmInfo->prTargetBss); ++ } ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ } while (fgIsTransOut); ++ ++} /* p2pFsmStateTransition */ ++ ++VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prSwitchOpMode = (P_MSG_P2P_SWITCH_OP_MODE_T) prMsgHdr; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwitchOpMode != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventSwitchOPMode\n"); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prSwitchOpMode->eOpMode >= OP_MODE_NUM) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ /* P2P Device / GC. */ ++ p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, prSwitchOpMode->eOpMode, TRUE); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventSwitchOPMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle scan done event during Device Discovery. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) NULL; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ /* This scan done event is either for "SCAN" phase or "SEARCH" state or "LISTEN" state. ++ * The scan done for SCAN phase & SEARCH state doesn't imply Device ++ * Discovery over. ++ */ ++ DBGLOG(P2P, TRACE, "P2P Scan Done Event\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ ++ if (prScanDoneMsg->ucSeqNum != prScanReqInfo->ucSeqNumOfScnMsg) { ++ /* Scan Done message sequence number mismatch. ++ * Ignore this event. (P2P FSM issue two scan events.) ++ */ ++ /* The scan request has been cancelled. ++ * Ignore this message. It is possible. ++ */ ++ DBGLOG(P2P, TRACE, "P2P Scan Don SeqNum:%d <-> P2P Fsm SCAN Msg:%d\n", ++ prScanDoneMsg->ucSeqNum, prScanReqInfo->ucSeqNumOfScnMsg); ++ ++ break; ++ } ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_SCAN: ++ { ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ prScanReqInfo->fgIsAbort = FALSE; ++ ++ if (prConnReqInfo->fgIsConnRequest) { ++ prP2pFsmInfo->prTargetBss = p2pFuncKeepOnConnection(prAdapter, ++ &prP2pFsmInfo->rConnReqInfo, ++ &prP2pFsmInfo->rChnlReqInfo, ++ &prP2pFsmInfo->rScanReqInfo); ++ if (prP2pFsmInfo->prTargetBss == NULL) ++ eNextState = P2P_STATE_SCAN; ++ else ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ } else { ++ eNextState = P2P_STATE_IDLE; ++ } ++ ++ } ++ break; ++ case P2P_STATE_AP_CHANNEL_DETECT: ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ break; ++ default: ++ /* Unexpected channel scan done event without being chanceled. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanReqInfo->fgIsScanRequest = FALSE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when channel is granted by CNM module from FW. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T) NULL; ++ UINT_8 ucTokenID = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "P2P Run Event Channel Grant\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; ++ ucTokenID = prMsgChGrant->ucTokenID; ++ prP2pFsmInfo->u4GrantInterval = prMsgChGrant->u4GrantInterval; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ if (ucTokenID == prChnlReqInfo->ucSeqNumOfChReq) { ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_REQING_CHANNEL: ++ switch (prChnlReqInfo->eChannelReqType) { ++ case CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL: ++ eNextState = P2P_STATE_CHNL_ON_HAND; ++ break; ++ case CHANNEL_REQ_TYPE_GC_JOIN_REQ: ++ eNextState = P2P_STATE_GC_JOIN; ++ break; ++ case CHANNEL_REQ_TYPE_GO_START_BSS: ++ eNextState = P2P_STATE_IDLE; ++ break; ++ default: ++ break; ++ } ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ break; ++ default: ++ /* Channel is granted under unexpected state. ++ * Driver should cancel channel privileagea before leaving the states. ++ */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } else { ++ /* Channel requsted, but released. */ ++ /* ASSERT(!prChnlReqInfo->fgIsChannelRequested); */ ++ DBGLOG(P2P, TRACE, "Channel requsted, but released\n"); ++ } ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventChGrant */ ++ ++VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_P2P_CHNL_REQUEST_T prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) prMsgHdr; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelRequest\n"); ++ ++ /* Special case of time renewing for same frequency. */ ++ if ((prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) && ++ (prChnlReqInfo->ucReqChnlNum == prP2pChnlReqMsg->rChannelInfo.ucChannelNum) && ++ (prChnlReqInfo->eBand == prP2pChnlReqMsg->rChannelInfo.eBand) && ++ (prChnlReqInfo->eChnlSco == prP2pChnlReqMsg->eChnlSco)) { ++ ++ ASSERT(prChnlReqInfo->fgIsChannelRequested == TRUE); ++ ASSERT(prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL); ++ ++ prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; ++ prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; ++ ++ /* Re-enter the state. */ ++ eNextState = P2P_STATE_CHNL_ON_HAND; ++ } else { ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ /* Cookie can only be assign after abort.(for indication) */ ++ prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; ++ prChnlReqInfo->ucReqChnlNum = prP2pChnlReqMsg->rChannelInfo.ucChannelNum; ++ prChnlReqInfo->eBand = prP2pChnlReqMsg->rChannelInfo.eBand; ++ prChnlReqInfo->eChnlSco = prP2pChnlReqMsg->eChnlSco; ++ prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL; ++ ++ eNextState = P2P_STATE_REQING_CHANNEL; ++ } ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventChannelRequest */ ++ ++VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_CHNL_ABORT_T prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) prMsgHdr; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelAbort\n"); ++ ++ if ((prChnlAbortMsg->u8Cookie == prChnlReqInfo->u8Cookie) && (prChnlReqInfo->fgIsChannelRequested)) { ++ ++ ASSERT((prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL || ++ (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND))); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventChannelAbort */ ++ ++VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) NULL; ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ UINT_32 u4ChnlListSize = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) prMsgHdr; ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventScanRequest\n"); ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ ASSERT(prScanReqInfo->fgIsScanRequest == FALSE); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; ++ ++ /* Channel List */ ++ prScanReqInfo->ucNumChannelList = prP2pScanReqMsg->u4NumChannel; ++ DBGLOG(P2P, TRACE, "Scan Request Channel List Number: %d\n", prScanReqInfo->ucNumChannelList); ++ if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { ++ DBGLOG(P2P, TRACE, "Channel List Number Overloaded: %d, change to: %d\n", ++ prScanReqInfo->ucNumChannelList, MAXIMUM_OPERATION_CHANNEL_LIST); ++ prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; ++ } ++ ++ u4ChnlListSize = sizeof(RF_CHANNEL_INFO_T) * prScanReqInfo->ucNumChannelList; ++ kalMemCopy(prScanReqInfo->arScanChannelList, prP2pScanReqMsg->arChannelListInfo, u4ChnlListSize); ++ ++ /* TODO: I only take the first SSID. Multiple SSID may be needed in the future. */ ++ /* SSID */ ++ if (prP2pScanReqMsg->i4SsidNum >= 1) ++ kalMemCopy(&(prScanReqInfo->rSsidStruct), prP2pScanReqMsg->prSSID, sizeof(P2P_SSID_STRUCT_T)); ++ else ++ prScanReqInfo->rSsidStruct.ucSsidLen = 0; ++ ++ /* IE Buffer */ ++ kalMemCopy(prScanReqInfo->aucIEBuf, prP2pScanReqMsg->pucIEBuf, prP2pScanReqMsg->u4IELen); ++ ++ prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanRequest */ ++ ++VOID p2pFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventScanAbort\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventScanAbort */ ++ ++VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventAbort\n"); ++ ++ if (prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { ++ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->fgIsAbort = TRUE; ++ } else if (prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL) { ++ /* 2012/08/06: frog ++ * Prevent Start GO. ++ */ ++ prP2pBssInfo->eIntendOPMode = OP_MODE_NUM; ++ } ++ /* For other state, is there any special action that should be take before leaving? */ ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } else { ++ /* P2P State IDLE. */ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ if (prChnlReqInfo->fgIsChannelRequested) ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventAbort */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle FSM Timeout. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) ulParam; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ DBGLOG(P2P, TRACE, "P2P FSM Timeout Event\n"); ++ ++ switch (prP2pFsmInfo->eCurrentState) { ++ case P2P_STATE_IDLE: ++ { ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ } else if (IS_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } ++ break; ++ ++/* case P2P_STATE_SCAN: */ ++/* break; */ ++/* case P2P_STATE_AP_CHANNEL_DETECT: */ ++/* break; */ ++/* case P2P_STATE_REQING_CHANNEL: */ ++/* break; */ ++ case P2P_STATE_CHNL_ON_HAND: ++ switch (prP2pFsmInfo->eListenExted) { ++ case P2P_DEV_NOT_EXT_LISTEN: ++ case P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT: ++ DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", ++ prP2pFsmInfo->eListenExted); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ break; ++ case P2P_DEV_EXT_LISTEN_ING: ++ DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", ++ prP2pFsmInfo->eListenExted); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_CHNL_ON_HAND); ++ prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT; ++ break; ++ default: ++ ASSERT(FALSE); ++ DBGLOG(P2P, ERROR, ++ "Current P2P State %d is unexpected for FSM timeout event.\n", ++ prP2pFsmInfo->eCurrentState); ++ } ++ break; ++/* case P2P_STATE_GC_JOIN: */ ++/* break; */ ++ default: ++ break; ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventFsmTimeout */ ++ ++VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_MSG_P2P_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventMgmtFrameTx\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) prMsgHdr; ++ ++ p2pFuncTxMgmtFrame(prAdapter, ++ &prP2pFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventMgmtTx */ ++ ++VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventStartAP\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) prMsgHdr; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (prP2pStartAPMsg->u4BcnInterval) { ++ DBGLOG(P2P, TRACE, "Beacon interval updated to :%u\n", prP2pStartAPMsg->u4BcnInterval); ++ prP2pBssInfo->u2BeaconInterval = (UINT_16) prP2pStartAPMsg->u4BcnInterval; ++ } else if (prP2pBssInfo->u2BeaconInterval == 0) { ++ prP2pBssInfo->u2BeaconInterval = DOT11_BEACON_PERIOD_DEFAULT; ++ } ++ ++ if (prP2pStartAPMsg->u4DtimPeriod) { ++ DBGLOG(P2P, TRACE, "DTIM interval updated to :%u\n", prP2pStartAPMsg->u4DtimPeriod); ++ prP2pBssInfo->ucDTIMPeriod = (UINT_8) prP2pStartAPMsg->u4DtimPeriod; ++ } else if (prP2pBssInfo->ucDTIMPeriod == 0) { ++ prP2pBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ } ++ ++ if (prP2pStartAPMsg->u2SsidLen != 0) { ++ kalMemCopy(prP2pBssInfo->aucSSID, prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen); ++ kalMemCopy(prP2pSpecificBssInfo->aucGroupSsid, prP2pStartAPMsg->aucSsid, ++ prP2pStartAPMsg->u2SsidLen); ++ prP2pBssInfo->ucSSIDLen = prP2pSpecificBssInfo->u2GroupSsidLen = prP2pStartAPMsg->u2SsidLen; ++ } ++ ++ prP2pBssInfo->eHiddenSsidType = prP2pStartAPMsg->ucHiddenSsidType; ++ ++ /* TODO: JB */ ++ /* Privacy & inactive timeout. */ ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { ++ UINT_8 ucPreferedChnl = 0; ++ ENUM_BAND_T eBand = BAND_NULL; ++ ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; ++ ENUM_P2P_STATE_T eNextState = P2P_STATE_SCAN; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prP2pFsmInfo->eCurrentState != P2P_STATE_SCAN && ++ prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ } ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; ++ DBGLOG(P2P, INFO, ++ "NFC:p2pFsmRunEventStartAP,fgIsGOInitialDone[%d]\n", ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); ++ ++ /* 20120118: Moved to p2pFuncSwitchOPMode(). */ ++ /* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Leave IDLE state. */ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* sync with firmware */ ++ /* DBGLOG(P2P, INFO, ("Activate P2P Network.\n")); */ ++ /* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Key to trigger P2P FSM to allocate channel for AP mode. */ ++ prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; ++ ++ /* Sparse Channel to decide which channel to use. */ ++ if ((cnmPreferredChannel(prAdapter, ++ &eBand, ++ &ucPreferedChnl, ++ &eSco) == FALSE) && (prP2pConnSettings->ucOperatingChnl == 0)) { ++ /* Sparse Channel Detection using passive mode. */ ++ eNextState = P2P_STATE_AP_CHANNEL_DETECT; ++ } else { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = ++ prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++#if 1 ++ /* 2012-01-27: frog - Channel set from upper layer is the first priority. */ ++ /* Because the channel & beacon is decided by p2p_supplicant. */ ++ if (prP2pConnSettings->ucOperatingChnl != 0) { ++ prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; ++ prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; ++ } ++ ++ else { ++ ASSERT(ucPreferedChnl != 0); ++ prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prP2pSpecificBssInfo->eRfBand = eBand; ++ } ++#else ++ if (ucPreferedChnl) { ++ prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prP2pSpecificBssInfo->eRfBand = eBand; ++ } else { ++ ASSERT(prP2pConnSettings->ucOperatingChnl != 0); ++ prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; ++ prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; ++ } ++ ++#endif ++ prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel; ++ prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventStartAP GO Scan\n"); ++ } ++ ++ /* If channel is specified, use active scan to shorten the scan time. */ ++ p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, eNextState); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventStartAP */ ++ ++VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_NETDEV_REGISTER_T prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventNetDeviceRegister\n"); ++ ++ prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) prMsgHdr; ++ ++ if (prNetDevRegisterMsg->fgIsEnable) { ++ p2pSetMode((prNetDevRegisterMsg->ucMode == 1) ? TRUE : FALSE); ++ ++ if (p2pLaunch(prAdapter->prGlueInfo)) ++ ASSERT(prAdapter->fgIsP2PRegistered); ++ ++ } else { ++ if (prAdapter->fgIsP2PRegistered) ++ p2pRemove(prAdapter->prGlueInfo); ++ ++ } ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventNetDeviceRegister */ ++ ++VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_MGMT_FRAME_UPDATE_T prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventUpdateMgmtFrame\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) prMsgHdr; ++ ++ switch (prP2pMgmtFrameUpdateMsg->eBufferType) { ++ case ENUM_FRAME_TYPE_EXTRA_IE_BEACON: ++ break; ++ case ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP: ++ break; ++ case ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP: ++ break; ++ case ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE: ++ break; ++ case ENUM_FRAME_TYPE_BEACON_TEMPLATE: ++ break; ++ default: ++ break; ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventUpdateMgmtFrame */ ++ ++VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_BEACON_UPDATE_T prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconUpdate\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) prMsgHdr; ++ ++ p2pFuncBeaconUpdate(prAdapter, ++ prP2pBssInfo, ++ &prP2pFsmInfo->rBcnContentInfo, ++ prBcnUpdateMsg->pucBcnHdr, ++ prBcnUpdateMsg->u4BcnHdrLen, ++ prBcnUpdateMsg->pucBcnBody, prBcnUpdateMsg->u4BcnBodyLen); ++ ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && ++ (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { ++ /* AP is created, Beacon Update. */ ++ /* nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventBeaconUpdate */ ++ ++VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventStopAP\n"); ++ ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ && (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { ++ /* AP is created, Beacon Update. */ ++ ++ p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); ++ ++ DBGLOG(P2P, TRACE, "Stop Beaconing\n"); ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Reset RLM related field of BSSINFO. */ ++ rlmBssAborted(prAdapter, prP2pBssInfo); ++ } ++ /* 20120118: Moved to p2pFuncSwitchOPMode(). */ ++ /* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ /* Enter IDLE state. */ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ DBGLOG(P2P, INFO, "Re activate P2P Network.\n"); ++ nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++#if CFG_SUPPORT_WFD ++ p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); ++#endif ++ ++ /* p2pFsmRunEventAbort(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo); */ ++ p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventStopAP */ ++ ++VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) prMsgHdr; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionRequest\n"); ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ break; ++ ++ SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Make sure the state is in IDLE state. */ ++ p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); ++ ++ /* Update connection request information. */ ++ prConnReqInfo->fgIsConnRequest = TRUE; ++ COPY_MAC_ADDR(prConnReqInfo->aucBssid, prConnReqMsg->aucBssid); ++ kalMemCopy(&(prConnReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); ++ kalMemCopy(prConnReqInfo->aucIEBuf, prConnReqMsg->aucIEBuf, prConnReqMsg->u4IELen); ++ prConnReqInfo->u4BufLength = prConnReqMsg->u4IELen; ++ ++ /* Find BSS Descriptor first. */ ++ prP2pFsmInfo->prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); ++ ++ if (prP2pFsmInfo->prTargetBss == NULL) { ++ /* Update scan parameter... to scan target device. */ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest,Trigger New Scan\n"); ++ ++ prScanReqInfo->ucNumChannelList = 1; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; ++ prScanReqInfo->arScanChannelList[0].ucChannelNum = prConnReqMsg->rChannelInfo.ucChannelNum; ++ kalMemCopy(&(prScanReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); ++ prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ } else { ++ prChnlReqInfo->u8Cookie = 0; ++ prChnlReqInfo->ucReqChnlNum = prConnReqMsg->rChannelInfo.ucChannelNum; ++ prChnlReqInfo->eBand = prConnReqMsg->rChannelInfo.eBand; ++ prChnlReqInfo->eChnlSco = prConnReqMsg->eChnlSco; ++ prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; ++ DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest, Report the Connecting BSS Again.\n"); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_REQING_CHANNEL); ++ } ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventConnectionRequest */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to handle Connection Request from Supplicant. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ /* P_STA_RECORD_T prTargetStaRec = (P_STA_RECORD_T)NULL; */ ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionAbort: Connection Abort.\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) prMsgHdr; ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ { ++ UINT_8 aucBCBSSID[] = BC_BSSID; ++ ++ if (!prP2pBssInfo->prStaRecOfAP) { ++ DBGLOG(P2P, TRACE, "GO's StaRec is NULL\n"); ++ break; ++ } ++ if (UNEQUAL_MAC_ADDR(prP2pBssInfo->prStaRecOfAP->aucMacAddr, prDisconnMsg->aucTargetID) ++ && UNEQUAL_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCBSSID)) { ++ DBGLOG(P2P, TRACE, ++ "Unequal MAC ADDR [ %pM : %pM ]\n", ++ prP2pBssInfo->prStaRecOfAP->aucMacAddr, ++ prDisconnMsg->aucTargetID); ++ break; ++ } ++ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, 0, ++ WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); ++ ++ /* Stop rejoin timer if it is started. */ ++ /* TODO: If it has. */ ++ ++ p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, prDisconnMsg->fgSendDeauth, ++ prDisconnMsg->u2ReasonCode); ++ ++ /* prTargetStaRec = prP2pBssInfo->prStaRecOfAP; */ ++ ++ /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). */ ++ /* hit prStaRecOfAP == NULL. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ /* Search specific client device, and disconnect. */ ++ /* 1. Send deauthentication frame. */ ++ /* 2. Indication: Device disconnect. */ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ DBGLOG(P2P, TRACE, ++ "Disconnecting with Target ID: %pM\n", ++ prDisconnMsg->aucTargetID); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prDisconnMsg->aucTargetID)) { ++ ++ DBGLOG(P2P, TRACE, ++ "Disconnecting: %pM\n", ++ prCurrStaRec->aucMacAddr); ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Glue layer indication. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ ++ ++ /* Send deauth & do indication. */ ++ p2pFuncDisconnect(prAdapter, prCurrStaRec, prDisconnMsg->fgSendDeauth, ++ prDisconnMsg->u2ReasonCode); ++ ++ /* prTargetStaRec = prCurrStaRec; */ ++ ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } while (FALSE); ++ ++ /* 20120830 moved into p2pFuncDisconnect() */ ++ /* if ((!prDisconnMsg->fgSendDeauth) && (prTargetStaRec)) { */ ++ /* cnmStaRecFree(prAdapter, prTargetStaRec, TRUE); */ ++ /* } */ ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventConnectionAbort */ ++ ++VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ ++ /* TODO: */ ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventDissolve\n"); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++WLAN_STATUS ++p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ DBGLOG(P2P, INFO, "Deauth TX Done Status: %d, seqNo %d\n", ++ rTxDoneStatus, prMsduInfo->ucTxSeqNum); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec == NULL) { ++ DBGLOG(P2P, TRACE, "Station Record NULL, Index:%d\n", prMsduInfo->ucStaRecIndex); ++ break; ++ } ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ eOriMediaStatus = prP2pBssInfo->eConnectionState; ++ /* Change station state. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* Reset Station Record Status. */ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ /**/ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { ++ DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ } ++ ++ /* Because the eConnectionState is changed before Deauth TxDone. Dont Check eConnectionState */ ++ /* if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { */ ++ /* Update Disconnected state to FW. */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ /* } */ ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* p2pFsmRunEventDeauthTxDone */ ++ ++WLAN_STATUS ++p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_P2P_MGMT_TX_REQ_INFO_T) NULL; ++ BOOLEAN fgIsSuccess = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prMgmtTxReqInfo = &(prP2pFsmInfo->rMgmtTxInfo); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(P2P, INFO, "Mgmt Frame TX Fail, Status: %d, seq NO. %d, Cookie: 0x%llx\n", ++ rTxDoneStatus, prMsduInfo->ucTxSeqNum, prMgmtTxReqInfo->u8Cookie); ++ } else { ++ fgIsSuccess = TRUE; ++ DBGLOG(P2P, TRACE, "Mgmt Frame TX Done.\n"); ++ } ++ ++ if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { ++ kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ fgIsSuccess, ++ prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); ++ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ } ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* p2pFsmRunEventMgmtFrameTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called when JOIN complete message event is received from SAA. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; ++ P_MSG_JOIN_COMP_T prJoinCompMsg = (P_MSG_JOIN_COMP_T) NULL; ++ P_SW_RFB_T prAssocRspSwRfb = (P_SW_RFB_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ DBGLOG(P2P, TRACE, "P2P Join Complete\n"); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ if (prP2pFsmInfo == NULL) { ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ prJoinInfo = &(prP2pFsmInfo->rJoinInfo); ++ if (prMsgHdr == NULL) ++ return; ++ prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; ++ prAssocRspSwRfb = prJoinCompMsg->prSwRfb; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRec = prJoinCompMsg->prStaRec; ++ ++ /* Check SEQ NUM */ ++ if (prJoinCompMsg->ucSeqNum == prJoinInfo->ucSeqNumOfReqMsg) { ++ ASSERT(prStaRec == prJoinInfo->prTargetStaRec); ++ prJoinInfo->fgIsJoinComplete = TRUE; ++ ++ if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { ++ ++ /* 4 <1.1> Change FW's Media State immediately. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ ++ if ((prP2pBssInfo->prStaRecOfAP) && (prP2pBssInfo->prStaRecOfAP != prStaRec)) { ++ cnmStaRecChangeState(prAdapter, prP2pBssInfo->prStaRecOfAP, ++ STA_STATE_1); ++ ++ cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ } ++ /* 4 <1.3> Update BSS_INFO_T */ ++ p2pFuncUpdateBssInfoForJOIN(prAdapter, prP2pFsmInfo->prTargetBss, prStaRec, ++ prAssocRspSwRfb); ++ ++ /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DBGLOG(P2P, INFO, "P2P GC Join Success\n"); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ /* <1.5> Update RSSI if necessary */ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, ++ (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); ++#endif ++ ++ /* 4 <1.6> Indicate Connected Event to Host immediately. */ ++ /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ ++ /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, */ ++ /* prStaRec->aucMacAddr); */ ++ if (prP2pFsmInfo->prTargetBss) ++ scanReportBss2Cfg80211(prAdapter, OP_MODE_P2P_DEVICE, ++ prP2pFsmInfo->prTargetBss); ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ &prP2pFsmInfo->rConnReqInfo, ++ prJoinInfo->aucIEBuf, prJoinInfo->u4BufLength, ++ prStaRec->u2StatusCode, ++ WLAN_STATUS_MEDIA_CONNECT); ++ ++ } else { ++ /* Join Fail */ ++ /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ ++ if (p2pFuncRetryJOIN(prAdapter, prStaRec, prJoinInfo) == FALSE) { ++ P_BSS_DESC_T prBssDesc; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ prBssDesc = prP2pFsmInfo->prTargetBss; ++ ++ ASSERT(prBssDesc); ++ ASSERT(prBssDesc->fgIsConnecting); ++ ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ if (prStaRec->ucJoinFailureCount >= 3) { ++ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ &prP2pFsmInfo->rConnReqInfo, ++ prJoinInfo->aucIEBuf, ++ prJoinInfo->u4BufLength, ++ prStaRec->u2StatusCode, ++ WLAN_STATUS_MEDIA_CONNECT); ++ } else { ++ /* Sometime the GO is not ready to response auth. */ ++ /* Connect it again */ ++ prP2pFsmInfo->prTargetBss = NULL; ++ } ++ DBGLOG(P2P, INFO, "P2P GC Join Failed\n"); ++ ++ } ++ ++ } ++ } ++ } ++ ++ if (prAssocRspSwRfb) ++ nicRxReturnRFB(prAdapter, prAssocRspSwRfb); ++ ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_GC_JOIN) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ /* Return to IDLE state. */ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } else { ++ /* p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); */ ++ /* one more scan */ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); ++ } ++ } ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} /* p2pFsmRunEventJoinComplete */ ++ ++VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) prMsgHdr; ++ ++ p2pFuncMgmtFrameRegister(prAdapter, ++ prMgmtFrameRegister->u2FrameType, ++ prMgmtFrameRegister->fgIsRegister, &prP2pFsmInfo->u4P2pPacketFilter); ++ ++ } while (FALSE); ++ ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ return; ++ ++} /* p2pFsmRunEventMgmtFrameRegister */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when RX deauthentication frame from the AIR. ++* If we are under STA mode, we would go back to P2P Device. ++* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ UINT_16 u2ReasonCode = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ if (prStaRec == NULL) ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ if (!prStaRec) ++ break; ++ ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ break; ++ ++ DBGLOG(P2P, TRACE, "RX Deauth\n"); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prStaRec->aucMacAddr, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ UINT_16 u2IELength = 0; ++ ++ if (prP2pBssInfo->prStaRecOfAP != prStaRec) ++ break; ++ ++ prStaRec->u2ReasonCode = u2ReasonCode; ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); ++ ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, ++ prDeauthFrame->aucInfoElem, u2IELength, u2ReasonCode, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ DBGLOG(P2P, INFO, "GC RX Deauth Reason: %d\n", u2ReasonCode); ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Delete client from client list. */ ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ ++ ++ /* Indicate disconnect to Host. */ ++ DBGLOG(P2P, INFO, "GO RX Deauth Reason: %d\n", u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ ++ break; ++ } ++ } ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ /* Findout why someone sent deauthentication frame to us. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "Deauth Reason:%d\n", u2ReasonCode); ++ ++ } while (FALSE); ++} /* p2pFsmRunEventRxDeauthentication */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is call when RX deauthentication frame from the AIR. ++* If we are under STA mode, we would go back to P2P Device. ++* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ UINT_16 u2ReasonCode = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo == NULL) ++ break; ++ ++ if (prStaRec == NULL) { ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ break; ++ } ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ break; ++ ++ DBGLOG(P2P, TRACE, "RX Disassoc\n"); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ UINT_16 u2IELength = 0; ++ ++ ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); ++ ++ if (prP2pBssInfo->prStaRecOfAP != prStaRec) ++ break; ++ ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); ++ ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, ++ prDisassocFrame->aucInfoElem, ++ u2IELength, prStaRec->u2ReasonCode, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ DBGLOG(P2P, INFO, "GC RX Disassoc Reason %d\n", prStaRec->u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, prStaRec->u2ReasonCode); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Delete client from client list. */ ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); ++ ++ ASSERT(prCurrStaRec); ++ ++ if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { ++ ++ /* Remove STA from client list. */ ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, ++ &prCurrStaRec->rLinkEntry); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ ++ ++ /* Indicate disconnect to Host. */ ++ DBGLOG(P2P, INFO, "GO RX Disassoc Reason %d\n", u2ReasonCode); ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); ++ ++ break; ++ } ++ } ++ } ++ break; ++ case OP_MODE_P2P_DEVICE: ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } while (FALSE); ++} /* p2pFsmRunEventRxDisassociation */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called when a probe request frame is received. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is accepted & need cancel scan request. ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_WLAN_MAC_MGMT_HEADER_T prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (prBssDesc != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ /* There is a connection request. */ ++ prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; ++ ++ } while (FALSE); ++ ++} /* p2pFsmRunEventRxProbeResponseFrame */ ++ ++VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconTimeout: Beacon Timeout\n"); ++ ++ /* Only client mode would have beacon lost event. */ ++ ASSERT(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); ++ ++ if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* Indicate disconnect to Host. */ ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, REASON_CODE_DISASSOC_INACTIVITY, ++ WLAN_STATUS_MEDIA_DISCONNECT); ++ ++ if (prP2pBssInfo->prStaRecOfAP != NULL) { ++ P_STA_RECORD_T prStaRec = prP2pBssInfo->prStaRecOfAP; ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_DISASSOC_LEAVING_BSS); ++ ++ /* 20120830 moved into p2pFuncDisconnect() */ ++ /* cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); ++ ++ } ++ } ++ } while (FALSE); ++ ++} /* p2pFsmRunEventBeaconTimeout */ ++ ++VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = NULL; ++ struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prExtListenMsg = NULL; ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); ++ ++ prExtListenMsg = (struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *) prMsgHdr; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ASSERT_BREAK(prP2pFsmInfo); ++ ++ if (!prExtListenMsg->wait) { ++ DBGLOG(P2P, INFO, "reset listen interval\n"); ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ if (prP2pFsmInfo && (prP2pFsmInfo->eListenExted == P2P_DEV_NOT_EXT_LISTEN)) { ++ DBGLOG(P2P, INFO, "try to ext listen, p2p state: %d\n", prP2pFsmInfo->eCurrentState); ++ if (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) { ++ DBGLOG(P2P, INFO, "here to ext listen interval\n"); ++ prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_ING; ++ } ++ } ++ if (prMsgHdr) ++ cnmMemFree(prAdapter, prMsgHdr); ++} /* p2pFsmRunEventUpdateMgmtFrame */ ++ ++#if CFG_SUPPORT_WFD ++VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ WLAN_STATUS rStatus; ++ ++ DBGLOG(P2P, INFO, "p2pFsmRunEventWfdSettingUpdate\n"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL)); ++ ++ if (prMsgHdr != NULL) { ++ prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) prMsgHdr; ++ prWfdCfgSettings = prMsgWfdCfgSettings->prWfdCfgSettings; ++ } else { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ } ++ ++ DBGLOG(P2P, INFO, "WFD Enalbe %x info %x state %x flag %x adv %x\n", ++ prWfdCfgSettings->ucWfdEnable, ++ prWfdCfgSettings->u2WfdDevInfo, ++ (UINT_32) prWfdCfgSettings->u4WfdState, ++ (UINT_32) prWfdCfgSettings->u4WfdFlag, ++ (UINT_32) prWfdCfgSettings->u4WfdAdvancedFlag); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_WFD_CTRL, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(WFD_CFG_SETTINGS_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prWfdCfgSettings, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ } while (FALSE); ++ ++ return; ++ ++} ++ ++/* p2pFsmRunEventWfdSettingUpdate */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec != NULL) { ++ if (IS_STA_P2P_TYPE(prStaRec)) { ++ /* Do nothing */ ++ /* TODO: */ ++ } ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* end of p2pGenerateP2P_IEForAssocReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Probe Request frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ /* TODO: */ ++ ++ return; ++ ++} /* end of p2pGenerateP2P_IEForProbReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate P2P IE length for Beacon frame. ++* ++* @param[in] eNetTypeIndex Specify which network ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of P2P IE added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ++p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ /* TODO: */ ++ ++ return 0; ++ ++} /* end of p2pCalculateP2P_IELenForProbeReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Tx Fail of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++ p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_UNSPECIFIED); ++ ++ /* 20120830 moved into p2puUncDisconnect. */ ++ /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ ++ ++} /* p2pRunEventAAATxFail */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaState; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ eOriMediaState = prP2pBssInfo->eConnectionState; ++ ++ if (prStaRec != NULL) ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ else ++ break; ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ rStatus = WLAN_STATUS_RESOURCES; ++ break; ++ } ++ ++ bssAddStaRecToClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ prStaRec->u2AssocId = bssAssignAssocID(prStaRec); ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ rStatus = WLAN_STATUS_RESOURCES; ++ break; ++ } ++ DBGLOG(P2P, INFO, "P2P GO Join Complete\n"); ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); ++ ++ /* Update Connected state to FW. */ ++ if (eOriMediaState != prP2pBssInfo->eConnectionState) ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} /* p2pRunEventAAAComplete */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will indicate the Event of Successful Completion of AAA Module. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ /* Glue layer indication. */ ++ kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, TRUE); ++ ++ } while (FALSE); ++ ++ return rStatus; ++} /* p2pRunEventAAASuccess */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_P2P_PUBLIC_ACTION_FRAME_T prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prAdapter); ++ ++ prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) prSwRfb->pvHeader; ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ DBGLOG(P2P, TRACE, "RX Public Action Frame Token:%d.\n", prPublicActionFrame->ucDialogToken); ++ ++ if (prPublicActionFrame->ucCategory != CATEGORY_PUBLIC_ACTION) ++ return rWlanStatus; ++ ++ switch (prPublicActionFrame->ucAction) { ++ case ACTION_PUBLIC_WIFI_DIRECT: ++ break; ++ case ACTION_GAS_INITIAL_REQUEST: ++ case ACTION_GAS_INITIAL_RESPONSE: ++ case ACTION_GAS_COMEBACK_REQUEST: ++ case ACTION_GAS_COMEBACK_RESPONSE: ++ break; ++ default: ++ break; ++ } ++ ++ return rWlanStatus; ++} /* p2pRxPublicActionFrame */ ++ ++WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_P2P_ACTION_FRAME_T prP2pActionFrame = (P_P2P_ACTION_FRAME_T) NULL; ++ UINT_8 aucOui[3] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pActionFrame = (P_P2P_ACTION_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prP2pActionFrame->ucCategory != CATEGORY_VENDOR_SPECIFIC_ACTION) { ++ DBGLOG(P2P, TRACE, "RX Action Frame but not vendor specific.\n"); ++ break; ++ } ++ ++ if ((prP2pActionFrame->ucOuiType != VENDOR_OUI_TYPE_P2P) || ++ (prP2pActionFrame->aucOui[0] != aucOui[0]) || ++ (prP2pActionFrame->aucOui[1] != aucOui[1]) || (prP2pActionFrame->aucOui[2] != aucOui[2])) { ++ DBGLOG(P2P, TRACE, "RX Vendor Specific Action Frame but not P2P Type or not WFA OUI.\n"); ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pRxActionFrame */ ++ ++VOID ++p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, ++ UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam) ++{ ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ UINT_32 i; ++ BOOLEAN fgNoaAttrExisted = FALSE; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIndex]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ prP2pSpecificBssInfo->fgEnableOppPS = prEventUpdateNoaParam->fgEnableOppPS; ++ prP2pSpecificBssInfo->u2CTWindow = prEventUpdateNoaParam->u2CTWindow; ++ prP2pSpecificBssInfo->ucNoAIndex = prEventUpdateNoaParam->ucNoAIndex; ++ prP2pSpecificBssInfo->ucNoATimingCount = prEventUpdateNoaParam->ucNoATimingCount; ++ ++ fgNoaAttrExisted |= prP2pSpecificBssInfo->fgEnableOppPS; ++ ++ DBGLOG(P2P, INFO, "Update NoA Count=%d.\n", prEventUpdateNoaParam->ucNoATimingCount); ++ ++ ASSERT(prP2pSpecificBssInfo->ucNoATimingCount <= P2P_MAXIMUM_NOA_COUNT); ++ ++ for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { ++ /* in used */ ++ prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse = prEventUpdateNoaParam->arEventNoaTiming[i].fgIsInUse; ++ /* count */ ++ prP2pSpecificBssInfo->arNoATiming[i].ucCount = prEventUpdateNoaParam->arEventNoaTiming[i].ucCount; ++ /* duration */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4Duration = prEventUpdateNoaParam->arEventNoaTiming[i].u4Duration; ++ /* interval */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4Interval = prEventUpdateNoaParam->arEventNoaTiming[i].u4Interval; ++ /* start time */ ++ prP2pSpecificBssInfo->arNoATiming[i].u4StartTime = ++ prEventUpdateNoaParam->arEventNoaTiming[i].u4StartTime; ++ ++ fgNoaAttrExisted |= prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse; ++ } ++ ++ prP2pSpecificBssInfo->fgIsNoaAttrExisted = fgNoaAttrExisted; ++ ++ /* update beacon content by the change */ ++ bssUpdateBeaconContent(prAdapter, ucNetTypeIndex); ++} ++ ++#endif /* CFG_ENABLE_WIFI_DIRECT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c +new file mode 100644 +index 000000000000..586a74721b3b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c +@@ -0,0 +1,3796 @@ ++#include "precomp.h" ++#include ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocRspAttributesTable[] = { ++ {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS), NULL, p2pFuncAppendAttriStatusForAssocRsp} /* 0 */ ++ , {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING), NULL, p2pFuncAppendAttriExtListenTiming} /* 8 */ ++}; ++ ++APPEND_VAR_IE_ENTRY_T txProbeRspIETable[] = { ++ {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE} /* 50 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} /* 42 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} /* 45 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} /* 61 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} /* 48 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} /* 74 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} /* 127 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE} /* 221 */ ++ , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Function for requesting scan. There is an option to do ACTIVE or PASSIVE scan. ++* ++* @param eScanType - Specify the scan type of the scan request. It can be an ACTIVE/PASSIVE ++* Scan. ++* eChannelSet - Specify the preferred channel set. ++* A FULL scan would request a legacy full channel normal scan.(usually ACTIVE). ++* A P2P_SOCIAL scan would scan 1+6+11 channels.(usually ACTIVE) ++* A SPECIFIC scan would only 1/6/11 channels scan. (Passive Listen/Specific Search) ++* ucChannelNum - A specific channel number. (Only when channel is specified) ++* eBand - A specific band. (Only when channel is specified) ++* ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) ++{ ++ ++ P_MSG_SCN_SCAN_REQ prScanReq = (P_MSG_SCN_SCAN_REQ) NULL; ++ /*NFC Beam + Indication */ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsPureAP = FALSE; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++ ++ DEBUGFUNC("p2pFuncRequestScan()"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); ++ ++ if (prScanReqInfo->eChannelSet == SCAN_CHANNEL_SPECIFIED) { ++ ASSERT_BREAK(prScanReqInfo->ucNumChannelList > 0); ++ DBGLOG(P2P, LOUD, ++ "P2P Scan Request Channel:%d\n", prScanReqInfo->arScanChannelList[0].ucChannelNum); ++ } ++ ++ prScanReq = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ if (!prScanReq) { ++ ASSERT(0); /* Can't trigger SCAN FSM */ ++ break; ++ } ++ ++ prScanReq->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_REQ; ++ prScanReq->ucSeqNum = ++prScanReqInfo->ucSeqNumOfScnMsg; ++ prScanReq->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ prScanReq->eScanType = prScanReqInfo->eScanType; ++ prScanReq->eScanChannel = prScanReqInfo->eChannelSet; ++ prScanReq->u2IELen = 0; ++ ++ /* Copy IE for Probe Request. */ ++ if (prScanReqInfo->u4BufLength > MAX_IE_LENGTH) ++ prScanReqInfo->u4BufLength = MAX_IE_LENGTH; ++ kalMemCopy(prScanReq->aucIE, prScanReqInfo->aucIEBuf, prScanReqInfo->u4BufLength); ++ prScanReq->u2IELen = (UINT_16) prScanReqInfo->u4BufLength; ++ ++ prScanReq->u2ChannelDwellTime = prScanReqInfo->u2PassiveDewellTime; ++ ++ switch (prScanReqInfo->eChannelSet) { ++ case SCAN_CHANNEL_SPECIFIED: ++ { ++ UINT_32 u4Idx = 0; ++ P_RF_CHANNEL_INFO_T prDomainInfo = ++ (P_RF_CHANNEL_INFO_T) prScanReqInfo->arScanChannelList; ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ ++ if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ for (u4Idx = 0; u4Idx < prScanReqInfo->ucNumChannelList; u4Idx++) { ++ prScanReq->arChnlInfoList[u4Idx].ucChannelNum = prDomainInfo->ucChannelNum; ++ prScanReq->arChnlInfoList[u4Idx].eBand = prDomainInfo->eBand; ++ prDomainInfo++; ++ } ++ ++ prScanReq->ucChannelListNum = prScanReqInfo->ucNumChannelList; ++ ++ /*NFC Beam + Indication */ ++ prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ if (prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_GO_START_BSS && ++ prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && ++ !fgIsPureAP) { ++ prScanReq->ucChannelListNum = 1; ++ prScanReq->arChnlInfoList[0].ucChannelNum = prChnlReqInfo->ucReqChnlNum; ++ prScanReq->arChnlInfoList[0].eBand = prChnlReqInfo->eBand; ++ ++ DBGLOG(P2P, INFO, ++ "NFC:GO Skip Scan and Only Froce on %s[%d]\n", ++ prChnlReqInfo->eBand == 1 ? "2.4G" : "5G", ++ prChnlReqInfo->ucReqChnlNum); ++ } ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ ++ } ++ break; ++ ++ case SCAN_CHANNEL_FULL: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ ++ case SCAN_CHANNEL_2G4: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ ++ case SCAN_CHANNEL_P2P_SOCIAL: ++ { ++ UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; ++ ++ COPY_SSID(prScanReq->aucSSID, ++ prScanReq->ucSSIDLength, ++ prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); ++ ++ /* For compatible. */ ++ if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, ++ prScanReq->aucSSID, prScanReq->ucSSIDLength)) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; ++ } else if (prScanReq->ucSSIDLength != 0) { ++ prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; ++ } ++ } ++ break; ++ default: ++ /* Currently there is no other scan channel set. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReq, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pFuncRequestScan */ ++ ++VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanInfo) ++{ ++ P_MSG_SCN_SCAN_CANCEL prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prScanInfo != NULL)); ++ ++ if (!prScanInfo->fgIsScanRequest) ++ break; ++ ++ if (prScanInfo->ucSeqNumOfScnMsg) { ++ /* There is a channel privilege on hand. */ ++ DBGLOG(P2P, TRACE, "P2P Cancel Scan\n"); ++ ++ prScanCancelMsg = ++ (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); ++ if (!prScanCancelMsg) { ++ /* Buffer not enough, can not cancel scan request. */ ++ DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; ++ prScanCancelMsg->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prScanCancelMsg->ucSeqNum = prScanInfo->ucSeqNumOfScnMsg++; ++ prScanCancelMsg->fgIsChannelExt = FALSE; ++ prScanInfo->fgIsScanRequest = FALSE; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncCancelScan */ ++ ++VOID ++p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW) ++{ ++ if (!prAdapter) ++ return; ++ if (!prAdapter->prGlueInfo) ++ return; ++ if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) ++ return; ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (eOpMode < OP_MODE_NUM)); ++ ++ if (prP2pBssInfo->eCurrentOPMode != eOpMode) { ++ DBGLOG(P2P, TRACE, ++ "p2pFuncSwitchOPMode: Switch to from %d, to %d.\n", prP2pBssInfo->eCurrentOPMode, ++ eOpMode); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); ++ ++ p2pFsmRunEventStopAP(prAdapter, NULL); ++ break; ++ default: ++ break; ++ } ++ ++ prP2pBssInfo->eIntendOPMode = eOpMode; ++ prP2pBssInfo->eCurrentOPMode = eOpMode; ++ switch (eOpMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to Client.\n"); ++ case OP_MODE_ACCESS_POINT: ++/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ++ /* Change interface address. */ ++ if (eOpMode == OP_MODE_ACCESS_POINT) { ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to AP.\n"); ++ prP2pBssInfo->ucSSIDLen = 0; ++ } ++ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucInterfaceAddress); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucInterfaceAddress); ++ ++ break; ++ case OP_MODE_P2P_DEVICE: ++ { ++ /* Change device address. */ ++ DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch back to P2P Device.\n"); ++ ++/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); ++ ++ } ++ break; ++ default: ++/* if (IS_BSS_ACTIVE(prP2pBssInfo)) { */ ++/* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++/* nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++/* } */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ if (1) { ++ P2P_DISCONNECT_INFO rP2PDisInfo; ++ ++ rP2PDisInfo.ucRole = 2; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_P2P_ABORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(P2P_DISCONNECT_INFO), (PUINT_8)&rP2PDisInfo, NULL, 0); ++ } ++ ++ DBGLOG(P2P, TRACE, ++ "The device address is changed to %pM\n", ++ prP2pBssInfo->aucOwnMacAddr); ++ DBGLOG(P2P, TRACE, "The BSSID is changed to %pM\n", prP2pBssInfo->aucBSSID); ++ ++ /* Update BSS INFO to FW. */ ++ if ((fgSyncToFW) && (eOpMode != OP_MODE_ACCESS_POINT)) ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncSwitchOPMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will start a P2P Group Owner and send Beacon Frames. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncStartGO(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, ++ IN PUINT_8 pucSsidBuf, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP) ++{ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL)); ++ ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 1; ++ DBGLOG(P2P, INFO, ++ "p2pFuncStartGO:NFC Done[%d]\n", ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); ++ /* AP mode started. */ ++ p2pFuncSwitchOPMode(prAdapter, prBssInfo, prBssInfo->eIntendOPMode, FALSE); ++ ++ prBssInfo->eIntendOPMode = OP_MODE_NUM; ++ ++ /* 4 <1.1> Assign SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, pucSsidBuf, ucSsidLen); ++ ++ DBGLOG(P2P, TRACE, "GO SSID:%s\n", prBssInfo->aucSSID); ++ ++ /* 4 <1.2> Clear current AP's STA_RECORD_T and current AID */ ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ prBssInfo->u2AssocId = 0; ++ ++ /* 4 <1.3> Setup Channel, Band and Phy Attributes */ ++ prBssInfo->ucPrimaryChannel = ucChannelNum; ++ prBssInfo->eBand = eBand; ++ prBssInfo->eBssSCO = eSco; ++ ++ DBGLOG(P2P, TRACE, "GO Channel:%d\n", ucChannelNum); ++ ++ if (prBssInfo->eBand == BAND_5G) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; ++ } else if (fgIsPureAP) { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; ++ } else { ++ /* Depend on eBand */ ++ prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11GN); ++ /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; ++ } ++ ++ prBssInfo->ucNonHTBasicPhyType = (UINT_8) ++ rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; ++ prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; ++ prBssInfo->u2OperationalRateSet = ++ rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; ++ ++ if (prBssInfo->ucAllSupportedRatesLen == 0) { ++ rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, ++ prBssInfo->u2BSSBasicRateSet, ++ prBssInfo->aucAllSupportedRates, ++ &prBssInfo->ucAllSupportedRatesLen); ++ } ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2ATIMWindow = 0; ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ ++ /* 3 <2> Update BSS_INFO_T common part */ ++#if CFG_SUPPORT_AAA ++ if (!fgIsPureAP) { ++ prBssInfo->fgIsProtection = TRUE; /* Always enable protection at P2P GO */ ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); ++ } else { ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) ++ prBssInfo->fgIsProtection = TRUE; ++ } ++ ++ /* 20120106 frog: I want separate OP_Mode & Beacon TX Function. */ ++ /* p2pFuncSwitchOPMode(prAdapter, prBssInfo, OP_MODE_ACCESS_POINT, FALSE); */ ++ ++ bssInitForAP(prAdapter, prBssInfo, FALSE); ++ ++ nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_P2P_INDEX); ++#endif /* CFG_SUPPORT_AAA */ ++ ++ /* 3 <3> Set MAC HW */ ++ /* 4 <3.1> Setup channel and bandwidth */ ++ rlmBssInitForAPandIbss(prAdapter, prBssInfo); ++ ++ /* 4 <3.2> Reset HW TSF Update Mode and Beacon Mode */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <3.3> Update Beacon again for network phy type confirmed. */ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++#if 0 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ ++ { ++ CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; ++ ++ arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; ++ arHotspotOptimizationCfg.u4Level = (0x3) << 8 | 0x5; ++ wlanoidSendSetQueryP2PCmd(prAdapter, ++ CMD_ID_SET_HOTSPOT_OPTIMIZATION, ++ TRUE, ++ FALSE, ++ TRUE, ++ NULL, ++ NULL, ++ sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), ++ (PUINT_8)&arHotspotOptimizationCfg, NULL, 0); ++ } ++#endif ++ ++ /* 4 <3.4> Setup BSSID */ ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ } while (FALSE); ++ ++} /* p2pFuncStartGO() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to inform CNM that channel privilege ++* has been released ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ P_MSG_CH_ABORT_T prMsgChRelease = (P_MSG_CH_ABORT_T) NULL; ++ ++ DEBUGFUNC("p2pFuncReleaseCh()"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); ++ ++ if (!prChnlReqInfo->fgIsChannelRequested) ++ break; ++ ++ DBGLOG(P2P, TRACE, "P2P Release Channel\n"); ++ prChnlReqInfo->fgIsChannelRequested = FALSE; ++ ++ /* 1. return channel privilege to CNM immediately */ ++ prMsgChRelease = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); ++ if (!prMsgChRelease) { ++ ASSERT(0); /* Can't release Channel to CNM */ ++ break; ++ } ++ ++ prMsgChRelease->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; ++ prMsgChRelease->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prMsgChRelease->ucTokenID = prChnlReqInfo->ucSeqNumOfChReq++; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChRelease, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pFuncReleaseCh */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of CHANNEL_REQ_JOIN Initial. Enter CHANNEL_REQ_JOIN State. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ P_MSG_CH_REQ_T prMsgChReq = (P_MSG_CH_REQ_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); ++ ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ ++ /* send message to CNM for acquiring channel */ ++ prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); ++ ++ if (!prMsgChReq) { ++ ASSERT(0); /* Can't indicate CNM for channel acquiring */ ++ break; ++ } ++ ++ prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; ++ prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ prMsgChReq->ucTokenID = ++prChnlReqInfo->ucSeqNumOfChReq; ++ prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; ++ if (prChnlReqInfo->u4MaxInterval < P2P_EXT_LISTEN_TIME_MS) ++ prMsgChReq->u4MaxInterval = P2P_EXT_LISTEN_TIME_MS; ++ else ++ prMsgChReq->u4MaxInterval = prChnlReqInfo->u4MaxInterval; ++ ++ prMsgChReq->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; ++ prMsgChReq->eRfSco = prChnlReqInfo->eChnlSco; ++ prMsgChReq->eRfBand = prChnlReqInfo->eBand; ++ ++ kalMemZero(prMsgChReq->aucBSSID, MAC_ADDR_LEN); ++ ++ /* Channel request join BSSID. */ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); ++ ++ prChnlReqInfo->fgIsChannelRequested = TRUE; ++ ++ } while (FALSE); ++ ++} /* p2pFuncAcquireCh */ ++ ++#if 0 ++WLAN_STATUS ++p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBcnHdr, ++ IN UINT_32 u4HdrLen, ++ IN PUINT_8 pucBcnBody, IN UINT_32 u4BodyLen, IN UINT_32 u4DtimPeriod, IN UINT_32 u4BcnInterval) ++{ ++ WLAN_STATUS rResultStatus = WLAN_STATUS_INVALID_DATA; ++ P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucTIMBody = (PUINT_8) NULL; ++ UINT_16 u2FrameLength = 0, UINT_16 u2OldBodyLen = 0; ++ UINT_8 aucIEBuf[MAX_IE_LENGTH]; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prBcnMsduInfo = prP2pBssInfo->prBeacon ASSERT_BREAK(prBcnMsduInfo != NULL); ++ ++ /* TODO: Find TIM IE pointer. */ ++ prBcnFrame = prBcnMsduInfo->prPacket; ++ ++ ASSERT_BREAK(prBcnFrame != NULL); ++ ++ do { ++ /* Ori header. */ ++ UINT_16 u2IELength = 0, u2Offset = 0; ++ PUINT_8 pucIEBuf = prBcnFrame->aucInfoElem; ++ ++ u2IELength = prBcnMsduInfo->u2FrameLength - prBcnMsduInfo->ucMacHeaderLength; ++ ++ IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { ++ if ((IE_ID(pucIEBuf) == ELEM_ID_TIM) || ((IE_ID(pucIEBuf) > ELEM_ID_IBSS_PARAM_SET))) { ++ pucTIMBody = pucIEBuf; ++ break; ++ } ++ u2FrameLength += IE_SIZE(pucIEBuf); ++ } ++ ++ if (pucTIMBody == NULL) ++ pucTIMBody = pucIEBuf; ++ ++ /* Body not change. */ ++ u2OldBodyLen = (UINT_16) ((UINT_32) pucTIMBody - (UINT_32) prBcnFrame->aucInfoElem); ++ /* Move body. */ ++ kalMemCmp(aucIEBuf, pucTIMBody, u2OldBodyLen); ++ } while (FALSE); ++ ++ if (pucBcnHdr) { ++ kalMemCopy(prBcnMsduInfo->prPacket, pucBcnHdr, u4HdrLen); ++ pucTIMBody = (PUINT_8) ((UINT_32) prBcnMsduInfo->prPacket + u4HdrLen); ++ prBcnMsduInfo->ucMacHeaderLength = (WLAN_MAC_MGMT_HEADER_LEN + ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); ++ u2FrameLength = u4HdrLen; /* Header + Partial Body. */ ++ } else { ++ /* Header not change. */ ++ u2FrameLength += prBcnMsduInfo->ucMacHeaderLength; ++ } ++ ++ if (pucBcnBody) { ++ kalMemCopy(pucTIMBody, pucBcnBody, u4BodyLen); ++ u2FrameLength += (UINT_16) u4BodyLen; ++ } else { ++ kalMemCopy(pucTIMBody, aucIEBuf, u2OldBodyLen); ++ u2FrameLength += u2OldBodyLen; ++ } ++ ++ /* Frame Length */ ++ prBcnMsduInfo->u2FrameLength = u2FrameLength; ++ prBcnMsduInfo->fgIs802_11 = TRUE; ++ prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ prP2pBssInfo->u2BeaconInterval = (UINT_16) u4BcnInterval; ++ prP2pBssInfo->ucDTIMPeriod = (UINT_8) u4DtimPeriod; ++ prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; ++ prBcnMsduInfo->ucPacketType = 3; ++ rResultStatus = nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prP2pBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prBcnMsduInfo->u2FrameLength - ++ OFFSET_OF(WLAN_BEACON_FRAME_T, ++ aucInfoElem)); ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ /* AP is created, Beacon Update. */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } while (FALSE); ++ return rResultStatus; ++} /* p2pFuncBeaconUpdate */ ++ ++#else ++WLAN_STATUS ++ p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, ++ IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, ++ IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen) ++{ ++WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; ++PUINT_8 pucIEBuf = (PUINT_8) NULL; ++PUINT_8 paucIEBuf = (PUINT_8) NULL;/*[MAX_IE_LENGTH]; aucIEBuf*/ ++ ++do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (prBcnUpdateInfo != NULL)); ++ ++ prBcnMsduInfo = prP2pBssInfo->prBeacon; ++ ++#if DBG ++ if (prBcnUpdateInfo->pucBcnHdr != NULL) { ++ ASSERT((UINT_32) prBcnUpdateInfo->pucBcnHdr == ++ ((UINT_32) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD)); ++ } ++ ++ if (prBcnUpdateInfo->pucBcnBody != NULL) { ++ ASSERT((UINT_32) prBcnUpdateInfo->pucBcnBody == ++ ((UINT_32) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen)); ++ } ++#endif ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) ((ULONG) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ if (!pucNewBcnBody) { ++ /* Old body. */ ++ pucNewBcnBody = prBcnUpdateInfo->pucBcnBody; ++ ASSERT(u4NewBodyLen == 0); ++ u4NewBodyLen = prBcnUpdateInfo->u4BcnBodyLen; ++ } else { ++ prBcnUpdateInfo->u4BcnBodyLen = u4NewBodyLen; ++ } ++ ++ paucIEBuf = kalMemAlloc(MAX_IE_LENGTH, VIR_MEM_TYPE); ++ if (paucIEBuf == NULL) { ++ DBGLOG(P2P, TRACE, "p2p alloc paucIEBuf fail\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Temp buffer body part. */ ++ kalMemCopy(paucIEBuf, pucNewBcnBody, u4NewBodyLen); ++ ++ if (pucNewBcnHdr) { ++ kalMemCopy(prBcnFrame, pucNewBcnHdr, u4NewHdrLen); ++ prBcnUpdateInfo->pucBcnHdr = (PUINT_8) prBcnFrame; ++ prBcnUpdateInfo->u4BcnHdrLen = u4NewHdrLen; ++ } ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen); ++ kalMemCopy(pucIEBuf, paucIEBuf, u4NewBodyLen); ++ kalMemFree(paucIEBuf, VIR_MEM_TYPE, MAX_IE_LENGTH); ++ prBcnUpdateInfo->pucBcnBody = pucIEBuf; ++ ++ /* Frame Length */ ++ prBcnMsduInfo->u2FrameLength = (UINT_16) (prBcnUpdateInfo->u4BcnHdrLen + prBcnUpdateInfo->u4BcnBodyLen); ++ ++ prBcnMsduInfo->ucPacketType = 3; ++ prBcnMsduInfo->fgIs802_11 = TRUE; ++ prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++ /* Update BSS INFO related information. */ ++ COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prBcnFrame->aucSrcAddr); ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prBcnFrame->aucBSSID); ++ prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; ++ ++ p2pFuncParseBeaconContent(prAdapter, ++ prP2pBssInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); ++ ++#if 1 ++ /* bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++#else ++ nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prBcnFrame->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); ++#endif ++} while (FALSE); ++ ++return rWlanStatus; ++} /* p2pFuncBeaconUpdate */ ++ ++#endif ++ ++/* TODO: We do not apply IE in deauth frame set from upper layer now. */ ++WLAN_STATUS ++p2pFuncDeauth(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucPeerMacAddr, ++ IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDeauth) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsStaFound = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); ++ fgIsStaFound = TRUE; ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_INFRASTRUCTURE: ++ ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); ++ if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) ++ break; ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ fgIsStaFound = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgIsStaFound) ++ p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDeauth, u2ReasonCode); ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncDeauth */ ++ ++/* TODO: We do not apply IE in disassoc frame set from upper layer now. */ ++WLAN_STATUS ++p2pFuncDisassoc(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucPeerMacAddr, ++ IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDisassoc) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; ++ P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ BOOLEAN fgIsStaFound = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_ACCESS_POINT: ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); ++ ++ LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { ++ if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { ++ LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); ++ fgIsStaFound = TRUE; ++ /* p2pFuncDisconnect(prAdapter, prCliStaRec, ++ * fgSendDisassoc, u2ReasonCode); */ ++ break; ++ } ++ } ++ ++ } ++ break; ++ case OP_MODE_INFRASTRUCTURE: ++ ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); ++ if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) ++ break; ++ /* p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); */ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ fgIsStaFound = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgIsStaFound) { ++ ++ p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); ++ /* 20120830 moved into p2pFuncDisconnect(). */ ++ /* cnmStaRecFree(prAdapter, prCliStaRec, TRUE); */ ++ ++ } ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncDisassoc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) ++* 1. GC: Disconnect from AP. (Send Deauth) ++* 2. GO: Disconnect all STA ++* ++* @param[in] prAdapter Pointer to the adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncDissolve(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) ++{ ++ DEBUGFUNC("p2pFuncDissolve()"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); ++ ++ switch (prP2pBssInfo->eCurrentOPMode) { ++ case OP_MODE_INFRASTRUCTURE: ++ /* Reset station record status. */ ++ if (prP2pBssInfo->prStaRecOfAP) { ++ kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, ++ NULL, NULL, 0, REASON_CODE_DEAUTH_LEAVING_BSS, ++ WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); ++ ++ /* 2012/02/14 frog: After formation before join group, prStaRecOfAP is NULL. */ ++ p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, fgSendDeauth, u2ReasonCode); ++ } ++ ++ /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). ++ * hit prStaRecOfAP == NULL. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ prP2pBssInfo->prStaRecOfAP = NULL; ++ ++ break; ++ case OP_MODE_ACCESS_POINT: ++ /* Under AP mode, we would net send deauthentication frame to each STA. ++ * We only stop the Beacon & let all stations timeout. ++ */ ++ { ++ P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; ++ ++ /* Send deauth. */ ++ authSendDeauthFrame(prAdapter, ++ NULL, (P_SW_RFB_T) NULL, u2ReasonCode, (PFN_TX_DONE_HANDLER) NULL); ++ ++ prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; ++ ++ while (!LINK_IS_EMPTY(prStaRecOfClientList)) { ++ P_STA_RECORD_T prCurrStaRec; ++ ++ LINK_REMOVE_HEAD(prStaRecOfClientList, prCurrStaRec, P_STA_RECORD_T); ++ ++ /* Indicate to Host. */ ++ /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ ++ ++ p2pFuncDisconnect(prAdapter, prCurrStaRec, TRUE, u2ReasonCode); ++ ++ } ++ prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; ++ } ++ ++ break; ++ default: ++ return; /* 20110420 -- alreay in Device Mode. */ ++ } ++ ++ /* Make the deauth frame send to FW ASAP. */ ++ wlanAcquirePowerControl(prAdapter); ++ wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); ++ wlanReleasePowerControl(prAdapter); ++ ++ kalMdelay(100); ++ ++ /* Change Connection Status. */ ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ ++ } while (FALSE); ++ ++} /* p2pFuncDissolve */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) ++* 1. GC: Disconnect from AP. (Send Deauth) ++* 2. GO: Disconnect all STA ++* ++* @param[in] prAdapter Pointer to the adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ eOriMediaStatus = prP2pBssInfo->eConnectionState; ++ ++ /* Indicate disconnect. */ ++ /* TODO: */ ++ /* kalP2PGOStationUpdate */ ++ /* kalP2PGCIndicateConnectionStatus */ ++ /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, prStaRec->aucMacAddr); */ ++ DBGLOG(P2P, INFO, "p2pFuncDisconnect, eCurrentOPMode: %d, sendDeauth: %s\n", ++ prP2pBssInfo->eCurrentOPMode, fgSendDeauth ? "True" : "False"); ++ if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); ++ ++ if (fgSendDeauth) { ++ /* Send deauth. */ ++ authSendDeauthFrame(prAdapter, ++ prStaRec, ++ (P_SW_RFB_T) NULL, ++ u2ReasonCode, (PFN_TX_DONE_HANDLER) p2pFsmRunEventDeauthTxDone); ++ } else { ++ /* Change station state. */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* Reset Station Record Status. */ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { ++ DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); ++ p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); ++ } ++ ++ if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { ++ /* Update Disconnected state to FW. */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ } ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { ++ /* GO: It would stop Beacon TX. GC: Stop all BSS related PS function. */ ++ nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* Reset RLM related field of BSSINFO. */ ++ rlmBssAborted(prAdapter, prP2pBssInfo); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncDisconnect */ ++ ++/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ ++#define WLAN_ACTION_SPECTRUM_MGMT 0 ++#define WLAN_ACTION_QOS 1 ++#define WLAN_ACTION_DLS 2 ++#define WLAN_ACTION_BLOCK_ACK 3 ++#define WLAN_ACTION_PUBLIC 4 ++#define WLAN_ACTION_RADIO_MEASUREMENT 5 ++#define WLAN_ACTION_FT 6 ++#define WLAN_ACTION_HT 7 ++#define WLAN_ACTION_SA_QUERY 8 ++#define WLAN_ACTION_PROTECTED_DUAL 9 ++#define WLAN_ACTION_WNM 10 ++#define WLAN_ACTION_UNPROTECTED_WNM 11 ++#define WLAN_ACTION_TDLS 12 ++#define WLAN_ACTION_SELF_PROTECTED 15 ++#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ ++#define WLAN_ACTION_VENDOR_SPECIFIC 127 ++ ++/* Public action codes */ ++#define WLAN_PA_20_40_BSS_COEX 0 ++#define WLAN_PA_VENDOR_SPECIFIC 9 ++#define WLAN_PA_GAS_INITIAL_REQ 10 ++#define WLAN_PA_GAS_INITIAL_RESP 11 ++#define WLAN_PA_GAS_COMEBACK_REQ 12 ++#define WLAN_PA_GAS_COMEBACK_RESP 13 ++#define WLAN_TDLS_DISCOVERY_RESPONSE 14 ++ ++/* P2P public action frames */ ++enum p2p_action_frame_type { ++ P2P_GO_NEG_REQ = 0, ++ P2P_GO_NEG_RESP = 1, ++ P2P_GO_NEG_CONF = 2, ++ P2P_INVITATION_REQ = 3, ++ P2P_INVITATION_RESP = 4, ++ P2P_DEV_DISC_REQ = 5, ++ P2P_DEV_DISC_RESP = 6, ++ P2P_PROV_DISC_REQ = 7, ++ P2P_PROV_DISC_RESP = 8 ++}; ++ ++const char *p2p_to_string(enum p2p_action_frame_type p2p_action) ++{ ++ switch (p2p_action) { ++ case P2P_GO_NEG_REQ: ++ return "GO_NEG_REQ"; ++ case P2P_GO_NEG_RESP: ++ return "GO_NEG_RESP"; ++ case P2P_GO_NEG_CONF: ++ return "GO_NEG_CONF"; ++ case P2P_INVITATION_REQ: ++ return "INVITATION_REQ"; ++ case P2P_INVITATION_RESP: ++ return "INVITATION_RESP"; ++ case P2P_DEV_DISC_REQ: ++ return "DEV_DISC_REQ"; ++ case P2P_DEV_DISC_RESP: ++ return "DEV_DISC_RESP"; ++ case P2P_PROV_DISC_REQ: ++ return "PROV_DISC_REQ"; ++ case P2P_PROV_DISC_RESP: ++ return "PROV_DISC_RESP"; ++ } ++ ++ return "UNKNOWN P2P Public Action"; ++} ++const char *pa_to_string(int pa_action) ++{ ++ switch (pa_action) { ++ case WLAN_PA_20_40_BSS_COEX: ++ return "PA_20_40_BSS_COEX"; ++ case WLAN_PA_VENDOR_SPECIFIC: ++ return "PA_VENDOR_SPECIFIC"; ++ case WLAN_PA_GAS_INITIAL_REQ: ++ return "PA_GAS_INITIAL_REQ"; ++ case WLAN_PA_GAS_INITIAL_RESP: ++ return "PA_GAS_INITIAL_RESP"; ++ case WLAN_PA_GAS_COMEBACK_REQ: ++ return "PA_GAS_COMEBACK_REQ"; ++ case WLAN_PA_GAS_COMEBACK_RESP: ++ return "PA_GAS_COMEBACK_RESP"; ++ case WLAN_TDLS_DISCOVERY_RESPONSE: ++ return "TDLS_DISCOVERY_RESPONSE"; ++ } ++ ++ return "UNKNOWN Public Action"; ++} ++ ++const char *action_to_string(int wlan_action) ++{ ++ switch (wlan_action) { ++ case WLAN_ACTION_SPECTRUM_MGMT: ++ return "SPECTRUM_MGMT"; ++ case WLAN_ACTION_QOS: ++ return "QOS"; ++ case WLAN_ACTION_DLS: ++ return "DLS"; ++ case WLAN_ACTION_BLOCK_ACK: ++ return "BLOCK_ACK"; ++ case WLAN_ACTION_PUBLIC: ++ return "PUBLIC"; ++ case WLAN_ACTION_RADIO_MEASUREMENT: ++ return "RADIO_MEASUREMENT"; ++ case WLAN_ACTION_FT: ++ return "FT"; ++ case WLAN_ACTION_HT: ++ return "HT"; ++ case WLAN_ACTION_SA_QUERY: ++ return "SA_QUERY"; ++ case WLAN_ACTION_PROTECTED_DUAL: ++ return "PROTECTED_DUAL"; ++ case WLAN_ACTION_WNM: ++ return "WNM"; ++ case WLAN_ACTION_UNPROTECTED_WNM: ++ return "UNPROTECTED_WNM"; ++ case WLAN_ACTION_TDLS: ++ return "TDLS"; ++ case WLAN_ACTION_SELF_PROTECTED: ++ return "SELF_PROTECTED"; ++ case WLAN_ACTION_WMM: ++ return "WMM"; ++ case WLAN_ACTION_VENDOR_SPECIFIC: ++ return "VENDOR_SPECIFIC"; ++ } ++ ++ return "UNKNOWN Action Frame"; ++} ++ ++VOID p2pFuncTagActionActionP2PFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ IN P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucP2pAction, IN UINT_64 u8Cookie) ++{ ++ DBGLOG(P2P, INFO, "Found P2P_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNO: %d\n", ++ p2p_to_string(ucP2pAction), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++} ++ ++VOID p2pFuncTagActionActionFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ IN P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucAction, IN UINT_64 u8Cookie) ++{ ++ PUINT_8 pucVendor = NULL; ++ ++ DBGLOG(P2P, INFO, "Found WLAN_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNo: %d\n", ++ pa_to_string(ucAction), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ if (ucAction == WLAN_PA_VENDOR_SPECIFIC) { ++ pucVendor = (PUINT_8)prActFrame + 26; ++ if (*(pucVendor + 0) == 0x50 && ++ *(pucVendor + 1) == 0x6f && ++ *(pucVendor + 2) == 0x9a) { ++ if (*(pucVendor + 3) == 0x09) ++ /* found p2p IE */ ++ p2pFuncTagActionActionP2PFrame(prMgmtTxMsdu, ++ prActFrame, *(pucVendor + 4), u8Cookie); ++ else if (*(pucVendor + 3) == 0x0a) ++ /* found WFD IE */ ++ DBGLOG(P2P, INFO, "Found WFD IE, SA: %pM - DA: %pM\n", ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr); ++ else ++ DBGLOG(P2P, INFO, "Found Other vendor 0x%x, SA: %pM - DA: %pM\n", ++ *(pucVendor + 3), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr); ++ } ++ } ++} ++ ++VOID p2pFuncTagActionCategoryFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, ++ P_WLAN_ACTION_FRAME prActFrame, ++ IN UINT_8 ucCategory, ++ IN UINT_64 u8Cookie) ++{ ++ ++ UINT_8 ucAction = 0; ++ ++ DBGLOG(P2P, INFO, "Found WLAN_ACTION_%s, SA: %pM - DA: %pM, u8Cookie: 0x%llx, SeqNO: %d\n", ++ action_to_string(ucCategory), ++ prActFrame->aucSrcAddr, ++ prActFrame->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ if (ucCategory == WLAN_ACTION_PUBLIC) { ++ ucAction = prActFrame->ucAction; ++ p2pFuncTagActionActionFrame(prMgmtTxMsdu, prActFrame, ucAction, u8Cookie); ++ ++ } ++} ++ ++/* ++ * used to debug p2p mgmt frame: ++ * GO Nego Req ++ * GO Nego Res ++ * GO Nego Confirm ++ * GO Invite Req ++ * GO Invite Res ++ * Device Discoverability Req ++ * Device Discoverability Res ++ * Provision Discovery Req ++ * Provision Discovery Res ++ */ ++ ++VOID ++p2pFuncTagMgmtFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ /* P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; */ ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_WLAN_PROBE_RSP_FRAME_T prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T)NULL; ++ UINT_16 u2TxFrameCtrl; ++ P_WLAN_ACTION_FRAME prActFrame; ++ UINT_8 ucCategory; ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ /* ++ * mgmt frame MASK_FC_TYPE = 0 ++ * use MASK_FRAME_TYPE is oK for frame type/subtype judge ++ */ ++ u2TxFrameCtrl = prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE; ++ ++ switch (u2TxFrameCtrl) { ++ case MAC_FRAME_PROBE_RSP: ++ ++ prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T) prWlanHdr; ++ DBGLOG(P2P, INFO, "TX Probe Response Frame, SA: %pM - DA: %pM, cookie: 0x%llx, seqNo: %d\n", ++ prProbRspHdr->aucSrcAddr, prProbRspHdr->aucDestAddr, ++ u8Cookie, ++ prMgmtTxMsdu->ucTxSeqNum); ++ ++ break; ++ ++ case MAC_FRAME_ACTION: ++ ++ prActFrame = (P_WLAN_ACTION_FRAME)prWlanHdr; ++ ucCategory = prActFrame->ucCategory; ++ p2pFuncTagActionCategoryFrame(prMgmtTxMsdu, prActFrame, ++ ucCategory, u8Cookie); ++ ++ break; ++ default: ++ DBGLOG(P2P, INFO, "MGMT:, un-tagged frame type: 0x%x, A1: %pM, A2: %pM, A3: %pM seqNo: %d\n", ++ u2TxFrameCtrl, ++ prWlanHdr->aucAddr1, ++ prWlanHdr->aucAddr2, ++ prWlanHdr->aucAddr3, ++ prMgmtTxMsdu->ucTxSeqNum); ++ break; ++ } ++} ++ ++WLAN_STATUS ++p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ BOOLEAN fgIsProbrsp = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); ++ ++ if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { ++ ++ /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ ++ /* Packet on driver, not done yet, drop it. */ ++ prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; ++ if (prTxMsduInfo != NULL) { ++ ++ kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, ++ prMgmtTxReqInfo->u8Cookie, ++ FALSE, ++ prTxMsduInfo->prPacket, ++ (UINT_32) prTxMsduInfo->u2FrameLength); ++ ++ /* Leave it to TX Done handler. */ ++ /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ ++ prMgmtTxReqInfo->prMgmtTxMsdu = NULL; ++ DBGLOG(P2P, INFO, "p2pFuncTxMgmtFrame: Drop MGMT cookie: 0x%llx\n", ++ prMgmtTxReqInfo->u8Cookie); ++ } ++ /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ ++ /* Packet transmitted, wait tx done. (cookie issue) */ ++ /* 20120105 frog - use another u8cookie to store this value. */ ++ } ++ ++ ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); ++ ++ prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, prWlanHdr->aucAddr1); ++ prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_P2P_INDEX; ++ ++ switch (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) { ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(P2P, TRACE, "p2pFuncTxMgmtFrame: TX MAC_FRAME_PROBE_RSP\n"); ++ fgIsProbrsp = TRUE; ++ prMgmtTxMsdu = p2pFuncProcessP2pProbeRsp(prAdapter, prMgmtTxMsdu); ++ break; ++ default: ++ break; ++ } ++ ++ prMgmtTxReqInfo->u8Cookie = u8Cookie; ++ prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; ++ prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; ++ ++ prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; ++ prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); ++ if (prStaRec != NULL) ++ DBGLOG(P2P, TRACE, "Mgmt with station record: %pM.\n", prStaRec->aucMacAddr); ++ ++ prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ ++ prMgmtTxMsdu->fgIs802_1x = FALSE; ++ prMgmtTxMsdu->fgIs802_11 = TRUE; ++ prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMgmtTxMsdu->pfTxDoneHandler = p2pFsmRunEventMgmtFrameTxDone; ++ prMgmtTxMsdu->fgIsBasicRate = TRUE; ++ ++ p2pFuncTagMgmtFrame(prMgmtTxMsdu, u8Cookie); ++ ++ nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncTxMgmtFrame */ ++ ++VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prRfChannelInfo != NULL)); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prP2pConnSettings->ucOperatingChnl = prRfChannelInfo->ucChannelNum; ++ prP2pConnSettings->eBand = prRfChannelInfo->eBand; ++ ++ } while (FALSE); ++ ++} ++ ++/* p2pFuncSetChannel */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @retval TRUE We will retry JOIN ++* @retval FALSE We will not retry JOIN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo) ++{ ++ P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; ++ BOOLEAN fgRetValue = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && (prJoinInfo != NULL)); ++ ++ /* Retry other AuthType if possible */ ++ if (!prJoinInfo->ucAvailableAuthTypes) ++ break; ++ ++ if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(P2P, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else { ++ DBGLOG(P2P, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ prJoinInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ ++ ++ /* Trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ if (!prJoinReqMsg) { ++ ASSERT(0); /* Can't trigger SAA FSM */ ++ break; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ fgRetValue = TRUE; ++ } while (FALSE); ++ ++ return fgRetValue; ++ ++} /* end of p2pFuncRetryJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will update the contain of BSS_INFO_T for AIS network once ++* the association was completed. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ UINT_16 u2IELength; ++ PUINT_8 pucIE; ++ ++ DEBUGFUNC("p2pUpdateBssInfoForJOIN()"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prStaRec); ++ ASSERT(prAssocRspSwRfb); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; ++ ++ DBGLOG(P2P, INFO, "Update P2P_BSS_INFO_T and apply settings to MAC\n"); ++ ++ /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ ++ /* 4 <1.1> Setup Operation Mode */ ++ prP2pBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; ++ ++ /* 4 <1.2> Setup SSID */ ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); ++ ++ if (prBssDesc == NULL) { ++ /* Target BSS NULL. */ ++ DBGLOG(P2P, TRACE, "Target BSS NULL\n"); ++ return; ++ } ++ ++ if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAssocRspFrame->aucBSSID)) ++ ASSERT(FALSE); ++ /* 4 <1.3> Setup Channel, Band */ ++ prP2pBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; ++ prP2pBssInfo->eBand = prBssDesc->eBand; ++ ++ /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ ++ /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ ++ prP2pBssInfo->prStaRecOfAP = prStaRec; ++ prP2pBssInfo->u2AssocId = prStaRec->u2AssocId; ++ ++ /* 4 <2.2> Setup Capability */ ++ prP2pBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ ++ ++ if (prP2pBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) ++ prP2pBssInfo->fgIsShortPreambleAllowed = TRUE; ++ else ++ prP2pBssInfo->fgIsShortPreambleAllowed = FALSE; ++ ++ /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ ++ prP2pBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; ++ ++ prP2pBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; ++ ++ prP2pBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; ++ prP2pBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; ++ ++ /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ ++ /* 4 <3.1> Setup BSSID */ ++ COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); ++ ++ u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - ++ (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); ++ pucIE = prAssocRspFrame->aucInfoElem; ++ ++ /* 4 <3.2> Parse WMM and setup QBSS flag */ ++ /* Parse WMM related IEs and configure HW CRs accordingly */ ++ mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ prP2pBssInfo->fgIsQBSS = prStaRec->fgIsQoS; ++ ++ /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ ++ ASSERT(prBssDesc); ++ ++ prBssDesc->fgIsConnecting = FALSE; ++ prBssDesc->fgIsConnected = TRUE; ++ ++ /* 4 <4.1> Setup MIB for current BSS */ ++ prP2pBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ ++ prP2pBssInfo->ucDTIMPeriod = 0; ++ prP2pBssInfo->u2ATIMWindow = 0; ++ ++ prP2pBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; ++ ++ /* 4 <4.2> Update HT information and set channel */ ++ /* Record HT related parameters in rStaRec and rBssInfo ++ * Note: it shall be called before nicUpdateBss() ++ */ ++ rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); ++ ++ /* 4 <4.3> Sync with firmware for BSS-INFO */ ++ nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ ++ /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ ++ ++} /* end of p2pUpdateBssInfoForJOIN() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Auth Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Auth ++* @retval FALSE Don't reply the Auth ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAuth = TRUE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; ++ ++ DBGLOG(P2P, INFO, "p2pValidate Authentication Frame\n"); ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prSwRfb != NULL) && (pprStaRec != NULL) && (pu2StatusCode != NULL)); ++ ++ /* P2P 3.2.8 */ ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; ++ ++ if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ || (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { ++ /* We are not under AP Mode yet. */ ++ fgReplyAuth = FALSE; ++ DBGLOG(P2P, WARN, ++ "Current OP mode is not under AP mode. (%d)\n", prP2pBssInfo->eCurrentOPMode); ++ break; ++ } ++ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX, prAuthFrame->aucSrcAddr); ++ ++ if (!prStaRec) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX); ++ ++ /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for ++ * exhausted case and do removal of unused STA_RECORD_T. ++ */ ++ /* Sent a message event to clean un-used STA_RECORD_T. */ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ DBGLOG(AAA, INFO, "Station Limit Full. Decline a new Authentication.\n"); ++ break; ++ } ++ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); ++ ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ ++ prStaRec->u2BSSBasicRateSet = prP2pBssInfo->u2BSSBasicRateSet; ++ ++ prStaRec->u2DesiredNonHTRateSet = RATE_SET_ERP_P2P; ++ ++ prStaRec->u2OperationalRateSet = RATE_SET_ERP_P2P; ++ prStaRec->ucPhyTypeSet = PHY_TYPE_SET_802_11GN; ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ ++ /* NOTE(Kevin): Better to change state here, not at TX Done */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } else { ++ prSwRfb->ucStaRecIdx = prStaRec->ucIndex; ++ ++ if ((prStaRec->ucStaState > STA_STATE_1) && (IS_STA_IN_P2P(prStaRec))) { ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ p2pFuncResetStaRecStatus(prAdapter, prStaRec); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ } ++ ++ } ++ ++ if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT || ++ kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { ++ /* GROUP limit full. */ ++ /* P2P 3.2.8 */ ++ DBGLOG(P2P, WARN, ++ "Group Limit Full. (%d)\n", (INT_16) prP2pBssInfo->rStaRecOfClientList.u4NumElem); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); ++ ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++ fgReplyAuth = TRUE; ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD; ++ break; ++ } ++ /* Hotspot Blacklist */ ++ if (prAuthFrame->aucSrcAddr) { ++ if (kalP2PCmpBlackList(prAdapter->prGlueInfo, prAuthFrame->aucSrcAddr)) { ++ fgReplyAuth = TRUE; ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD; ++ return fgReplyAuth; ++ } ++ } ++ ++ /* prStaRec->eStaType = STA_TYPE_INFRA_CLIENT; */ ++ prStaRec->eStaType = STA_TYPE_P2P_GC; ++ ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; ++ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ prStaRec->ucJoinFailureCount = 0; ++ ++ *pprStaRec = prStaRec; ++ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ } while (FALSE); ++ ++ return fgReplyAuth; ++ ++} /* p2pFuncValidateAuth */ ++ ++VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ do { ++ if ((prAdapter == NULL) || (prStaRec == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ prStaRec->u2ReasonCode = REASON_CODE_RESERVED; ++ prStaRec->ucJoinFailureCount = 0; ++ prStaRec->fgTransmitKeyExist = FALSE; ++ ++ prStaRec->fgSetPwrMgtBit = FALSE; ++ ++ } while (FALSE); ++ ++} /* p2pFuncResetStaRecStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function is used to initialize the value of the connection settings for ++* P2P network ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings) ++{ ++ P_DEVICE_TYPE_T prDevType; ++ UINT_8 aucDefaultDevName[] = P2P_DEFAULT_DEV_NAME; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++#if CFG_SUPPORT_CFG_FILE ++ P_WIFI_VAR_T prWifiVar = NULL; ++#endif ++ ++ ASSERT(prP2PConnSettings); ++#if CFG_SUPPORT_CFG_FILE ++ prWifiVar = &(prAdapter->rWifiVar); ++ ASSERT(prWifiVar); ++#endif ++ ++ /* Setup Default Device Name */ ++ prP2PConnSettings->ucDevNameLen = P2P_DEFAULT_DEV_NAME_LEN; ++ kalMemCopy(prP2PConnSettings->aucDevName, aucDefaultDevName, sizeof(aucDefaultDevName)); ++ ++ /* Setup Primary Device Type (Big-Endian) */ ++ prDevType = &prP2PConnSettings->rPrimaryDevTypeBE; ++ ++ prDevType->u2CategoryId = HTONS(P2P_DEFAULT_PRIMARY_CATEGORY_ID); ++ prDevType->u2SubCategoryId = HTONS(P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID); ++ ++ prDevType->aucOui[0] = aucWfaOui[0]; ++ prDevType->aucOui[1] = aucWfaOui[1]; ++ prDevType->aucOui[2] = aucWfaOui[2]; ++ prDevType->aucOui[3] = VENDOR_OUI_TYPE_WPS; ++ ++ /* Setup Secondary Device Type */ ++ prP2PConnSettings->ucSecondaryDevTypeCount = 0; ++ ++ /* Setup Default Config Method */ ++ prP2PConnSettings->eConfigMethodSelType = ENUM_CONFIG_METHOD_SEL_AUTO; ++ prP2PConnSettings->u2ConfigMethodsSupport = P2P_DEFAULT_CONFIG_METHOD; ++ prP2PConnSettings->u2TargetConfigMethod = 0; ++ prP2PConnSettings->u2LocalConfigMethod = 0; ++ prP2PConnSettings->fgIsPasswordIDRdy = FALSE; ++ ++ /* For Device Capability */ ++ prP2PConnSettings->fgSupportServiceDiscovery = FALSE; ++ prP2PConnSettings->fgSupportClientDiscoverability = TRUE; ++ prP2PConnSettings->fgSupportConcurrentOperation = TRUE; ++ prP2PConnSettings->fgSupportInfraManaged = FALSE; ++ prP2PConnSettings->fgSupportInvitationProcedure = FALSE; ++ ++ /* For Group Capability */ ++#if CFG_SUPPORT_PERSISTENT_GROUP ++ prP2PConnSettings->fgSupportPersistentP2PGroup = TRUE; ++#else ++ prP2PConnSettings->fgSupportPersistentP2PGroup = FALSE; ++#endif ++ prP2PConnSettings->fgSupportIntraBSSDistribution = TRUE; ++ prP2PConnSettings->fgSupportCrossConnection = TRUE; ++ prP2PConnSettings->fgSupportPersistentReconnect = FALSE; ++ ++ prP2PConnSettings->fgSupportOppPS = FALSE; ++ prP2PConnSettings->u2CTWindow = P2P_CTWINDOW_DEFAULT; ++ ++ /* For Connection Settings. */ ++ prP2PConnSettings->eAuthMode = AUTH_MODE_OPEN; ++ ++ prP2PConnSettings->prTargetP2pDesc = NULL; ++ prP2PConnSettings->ucSSIDLen = 0; ++ ++ /* Misc */ ++ prP2PConnSettings->fgIsScanReqIssued = FALSE; ++ prP2PConnSettings->fgIsServiceDiscoverIssued = FALSE; ++ prP2PConnSettings->fgP2pGroupLimit = FALSE; ++ prP2PConnSettings->ucOperatingChnl = 0; ++ prP2PConnSettings->ucListenChnl = 0; ++ prP2PConnSettings->ucTieBreaker = (UINT_8) (kalRandomNumber() & 0x1); ++ ++ prP2PConnSettings->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; ++#if CFG_SUPPORT_CFG_FILE ++ /* prP2PConnSettings->fgIsWPSMode = prWifiVar->ucApWpsMode; */ ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = prWifiVar->ucApWpsMode; ++#endif ++} /* p2pFuncInitConnectionSettings */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Assoc Req Frame and then return ++* the status code to AAA to indicate if need to perform following actions ++* when the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu2StatusCode The Status Code of Validation Result ++* ++* @retval TRUE Reply the Assoc Resp ++* @retval FALSE Don't reply the Assoc Resp ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) ++{ ++ BOOLEAN fgReplyAssocResp = TRUE; ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_WFD_ATTRIBUTE_T prWfdAttribute = (P_WFD_ATTRIBUTE_T) NULL; ++ BOOLEAN fgNeedFree = FALSE; ++#endif ++ /* UINT_16 u2AttriListLen = 0; */ ++ UINT_16 u2WfdDevInfo = 0; ++ P_WFD_DEVICE_INFORMATION_IE_T prAttriWfdDevInfo; ++ ++ /* TODO(Kevin): Call P2P functions to check .. ++ 2. Check we can accept connection from thsi peer ++ a. If we are in PROVISION state, only accept the peer we do the GO formation previously. ++ b. If we are in OPERATION state, only accept the other peer when P2P_GROUP_LIMIT is 0. ++ 3. Check Black List here. ++ */ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (pu2StatusCode != NULL)); ++ ++ *pu2StatusCode = STATUS_CODE_REQ_DECLINED; ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec == NULL) { ++ /* Station record should be ready while RX AUTH frame. */ ++ fgReplyAssocResp = FALSE; ++ ASSERT(FALSE); ++ break; ++ } ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ prStaRec->u2DesiredNonHTRateSet &= prP2pBssInfo->u2OperationalRateSet; ++ prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prP2pBssInfo->ucPhyTypeSet; ++ ++ if (prStaRec->ucDesiredPhyTypeSet == 0) { ++ /* The station only support 11B rate. */ ++ *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; ++ break; ++ } ++#if CFG_SUPPORT_WFD && 1 ++ /* LOG_FUNC("Skip check WFD IE because some API is not ready\n"); */ ++ if (!prAdapter->rWifiVar.prP2pFsmInfo) { ++ fgReplyAssocResp = FALSE; ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ DBGLOG(P2P, INFO, "AssocReq, wfd_en %u wfd_info 0x%x wfd_policy 0x%x wfd_flag 0x%x\n", ++ prWfdCfgSettings->ucWfdEnable, prWfdCfgSettings->u2WfdDevInfo, ++ prWfdCfgSettings->u4WfdPolicy, prWfdCfgSettings->u4WfdFlag); /* Eddie */ ++ if (prWfdCfgSettings->ucWfdEnable) { ++ if (prWfdCfgSettings->u4WfdPolicy & BIT(6)) { ++ /* Rejected all. */ ++ break; ++ } ++ ++ /* fgNeedFree = p2pFuncGetAttriList(prAdapter, */ ++ /* VENDOR_OUI_TYPE_WFD, */ ++ /* (PUINT_8)prAssocReqFrame->aucInfoElem, */ ++ /* (prSwRfb->u2PacketLen - OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), */ ++ /* (PPUINT_8)&prWfdAttribute, */ ++ /* &u2AttriListLen); */ ++ ++ prAttriWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) ++ p2pFuncGetSpecAttri(prAdapter, ++ VENDOR_OUI_TYPE_WFD, ++ (PUINT_8) prAssocReqFrame->aucInfoElem, ++ (prSwRfb->u2PacketLen - ++ OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), ++ WFD_ATTRI_ID_DEV_INFO); ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(5)) && (prAttriWfdDevInfo != NULL)) { ++ /* Rejected with WFD IE. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(0)) && (prAttriWfdDevInfo == NULL)) { ++ /* Rejected without WFD IE. */ ++ break; ++ } ++ ++ if (prAttriWfdDevInfo == NULL) { ++ /* ++ * Without WFD IE. ++ * Do nothing. Accept the connection request. ++ */ ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ break; ++ } ++ ++ /* prAttriWfdDevInfo = */ ++ /* (P_WFD_DEVICE_INFORMATION_IE_T)p2pFuncGetSpecAttri(prAdapter, */ ++ /* VENDOR_OUI_TYPE_WFD, */ ++ /* (PUINT_8)prWfdAttribute, */ ++ /* u2AttriListLen, */ ++ /* WFD_ATTRI_ID_DEV_INFO); */ ++ /* if (prAttriWfdDevInfo == NULL) { */ ++ /* No such attribute. */ ++ /* break; */ ++ /* } */ ++ ++ WLAN_GET_FIELD_BE16(&prAttriWfdDevInfo->u2WfdDevInfo, &u2WfdDevInfo); ++ DBGLOG(P2P, INFO, "RX Assoc Req WFD Info:0x%x.\n", u2WfdDevInfo); ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(1)) && ((u2WfdDevInfo & 0x3) == 0x0)) { ++ /* Rejected because of SOURCE. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(2)) && ((u2WfdDevInfo & 0x3) == 0x1)) { ++ /* Rejected because of Primary Sink. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(3)) && ((u2WfdDevInfo & 0x3) == 0x2)) { ++ /* Rejected because of Secondary Sink. */ ++ break; ++ } ++ ++ if ((prWfdCfgSettings->u4WfdPolicy & BIT(4)) && ((u2WfdDevInfo & 0x3) == 0x3)) { ++ /* Rejected because of Source & Primary Sink. */ ++ break; ++ } ++ ++ /* Check role */ ++ ++ if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) && ++ ((prWfdCfgSettings->u2WfdDevInfo & BITS(0, 1)) == 0x3)) { ++ /* P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = ++ * (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)NULL; */ ++ UINT_16 u2DevInfo = prWfdCfgSettings->u2WfdDevInfo; ++ ++ /* We may change role here if we are dual role */ ++ ++ if ((u2WfdDevInfo & BITS(0, 1)) == 0x00 /* Peer is Source */) { ++ DBGLOG(P2P, INFO, "WFD: Switch role to primary sink\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ prWfdCfgSettings->u2WfdDevInfo |= 0x1; ++ ++ /* event to annonce the role is chanaged to P-Sink */ ++ ++ } else if ((u2WfdDevInfo & BITS(0, 1)) == 0x01 /* Peer is P-Sink */) { ++ DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ /* event to annonce the role is chanaged to Source */ ++ } else { ++ DBGLOG(P2P, INFO, "WFD: Peer role is wrong type(dev 0x%x)\n", ++ (u2DevInfo)); ++ DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); ++ ++ prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); ++ /* event to annonce the role is chanaged to Source */ ++ } ++ ++ p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); ++ ++ } /* Dual role p2p->wfd_params->WfdDevInfo */ ++ ++ /* WFD_FLAG_DEV_INFO_VALID */ ++ } ++ /* ucWfdEnable */ ++#endif ++ *pu2StatusCode = STATUS_CODE_SUCCESSFUL; ++ } while (FALSE); ++ ++#if CFG_SUPPORT_WFD ++ if ((prWfdAttribute) && (fgNeedFree)) ++ kalMemFree(prWfdAttribute, VIR_MEM_TYPE, WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE); ++#endif ++ ++ return fgReplyAssocResp; ++ ++} /* p2pFuncValidateAssocReq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to check the P2P IE ++* ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType) ++{ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ P_IE_WFA_T prWfaIE = (P_IE_WFA_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pucOuiType != NULL)); ++ ++ prWfaIE = (P_IE_WFA_T) pucBuf; ++ ++ if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { ++ break; ++ } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || ++ prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { ++ break; ++ } ++ ++ *pucOuiType = prWfaIE->ucOuiType; ++ ++ return TRUE; ++ } while (FALSE); ++ ++ return FALSE; ++} /* p2pFuncParseCheckForP2PInfoElem */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) ++{ ++ BOOLEAN fgIsReplyProbeRsp = FALSE; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("p2pFuncValidateProbeReq"); ++ DBGLOG(P2P, TRACE, "p2pFuncValidateProbeReq\n"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ) { ++ ++ DBGLOG(P2P, TRACE, "report probe req to OS\n"); ++ /* Leave the probe response to p2p_supplicant. */ ++ kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return fgIsReplyProbeRsp; ++ ++} /* end of p2pFuncValidateProbeReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will validate the Rx Probe Request Frame and then return ++* result to BSS to indicate if need to send the corresponding Probe Response ++* Frame if the specified conditions were matched. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to SW RFB data structure. ++* @param[out] pu4ControlFlags Control flags for replying the Probe Response ++* ++* @retval TRUE Reply the Probe Response ++* @retval FALSE Don't reply the Probe Response ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ ++ DEBUGFUNC("p2pFuncValidateProbeReq"); ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME) { ++ /* Leave the probe response to p2p_supplicant. */ ++ kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncValidateRxMgmtFrame */ ++ ++BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ if (prP2pFsmInfo) { ++ if (prP2pFsmInfo->fgIsWPSMode == 1) ++ return FALSE; ++ return prP2pFsmInfo->fgIsApMode; ++ } else { ++ return FALSE; ++ } ++} ++ ++/* p2pFuncIsAPMode */ ++ ++VOID ++p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen) ++{ ++ PUINT_8 pucIE = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ BOOLEAN ucNewSecMode = FALSE; ++ BOOLEAN ucOldSecMode = FALSE; ++ UINT_8 ucOuiType; ++ UINT_16 u2SubTypeVersion; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); ++ ++ if (u4IELen == 0) ++ break; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pSpecificBssInfo->u2AttributeLen = 0; ++ ++ ASSERT_BREAK(pucIEInfo != NULL); ++ ++ pucIE = pucIEInfo; ++ ++ ucOldSecMode = kalP2PGetCipher(prAdapter->prGlueInfo); ++ ++ IE_FOR_EACH(pucIE, u4IELen, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ { ++ /* 0 */ /* V */ /* Done */ ++ /* DBGLOG(P2P, TRACE, ("SSID update\n")); */ ++ /* SSID is saved when start AP/GO */ ++ /* SSID IE set in beacon from supplicant will not always be */ ++ /* the true since hidden SSID case */ ++ /* ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, ++ SSID_IE(pucIE)->aucSSID, ++ SSID_IE(pucIE)->ucLength); ++ ++ COPY_SSID(prP2pSpecificBssInfo->aucGroupSsid, ++ prP2pSpecificBssInfo->u2GroupSsidLen, ++ SSID_IE(pucIE)->aucSSID, ++ SSID_IE(pucIE)->ucLength); ++ */ ++ } ++ break; ++ case ELEM_ID_SUP_RATES: ++ { ++ /* 1 */ /* V */ /* Done */ ++ DBGLOG(P2P, TRACE, "Support Rate IE\n"); ++ kalMemCopy(prP2pBssInfo->aucAllSupportedRates, ++ SUP_RATES_IE(pucIE)->aucSupportedRates, ++ SUP_RATES_IE(pucIE)->ucLength); ++ ++ prP2pBssInfo->ucAllSupportedRatesLen = SUP_RATES_IE(pucIE)->ucLength; ++ ++ DBGLOG_MEM8(P2P, TRACE, SUP_RATES_IE(pucIE)->aucSupportedRates, ++ SUP_RATES_IE(pucIE)->ucLength); ++ } ++ break; ++ case ELEM_ID_DS_PARAM_SET: ++ { ++ /* 3 */ /* V */ /* Done */ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = ++ prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "DS PARAM IE\n"); ++ ++ ASSERT(prP2pConnSettings->ucOperatingChnl == DS_PARAM_IE(pucIE)->ucCurrChnl); ++ ++ if (prP2pConnSettings->eBand != BAND_2G4) { ++ ASSERT(FALSE); ++ break; ++ } ++ /* prP2pBssInfo->ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; */ ++ ++ /* prP2pBssInfo->eBand = BAND_2G4; */ ++ } ++ break; ++ case ELEM_ID_TIM: /* 5 */ /* V */ ++ DBGLOG(P2P, TRACE, "TIM IE\n"); ++ TIM_IE(pucIE)->ucDTIMPeriod = prP2pBssInfo->ucDTIMPeriod; ++ break; ++ case ELEM_ID_ERP_INFO: /* 42 */ /* V */ ++ { ++#if 1 ++ /* This IE would dynamic change due to FW detection change is required. */ ++ DBGLOG(P2P, TRACE, "ERP IE will be over write by driver\n"); ++ DBGLOG(P2P, TRACE, " ucERP: %x.\n", ERP_INFO_IE(pucIE)->ucERP); ++ ++#else ++ /* This IE would dynamic change due to FW detection change is required. */ ++ DBGLOG(P2P, TRACE, "ERP IE.\n"); ++ ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11GN; ++ ++ ASSERT(prP2pBssInfo->eBand == BAND_2G4); ++ ++ prP2pBssInfo->fgObssErpProtectMode = ++ ((ERP_INFO_IE(pucIE)->ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE); ++ ++ prP2pBssInfo->fgErpProtectMode = ++ ((ERP_INFO_IE(pucIE)->ucERP & ++ (ERP_INFO_USE_PROTECTION | ERP_INFO_NON_ERP_PRESENT)) ? TRUE : FALSE); ++#endif ++ ++ } ++ break; ++ case ELEM_ID_HT_CAP: /* 45 */ /* V */ ++ { ++#if 1 ++ DBGLOG(P2P, TRACE, "HT CAP IE would be overwritten by driver\n"); ++ ++ DBGLOG(P2P, TRACE, ++ "HT Cap Info:%x, AMPDU Param:%x\n", HT_CAP_IE(pucIE)->u2HtCapInfo, ++ HT_CAP_IE(pucIE)->ucAmpduParam); ++ ++ DBGLOG(P2P, TRACE, ++ "HT Extended Cap Info%x,TX Beamforming Cap Info%x,Ant Selection Cap Info%x\n", ++ HT_CAP_IE(pucIE)->u2HtExtendedCap, HT_CAP_IE(pucIE)->u4TxBeamformingCap, ++ HT_CAP_IE(pucIE)->ucAselCap); ++#else ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ ++ /* u2HtCapInfo */ ++ if ((HT_CAP_IE(pucIE)->u2HtCapInfo & ++ (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | ++ HT_CAP_INFO_DSSS_CCK_IN_40M)) == 0) { ++ prP2pBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } else { ++ prP2pBssInfo->fgAssoc40mBwAllowed = TRUE; ++ } ++ ++ if ((HT_CAP_IE(pucIE)->u2HtCapInfo & ++ (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M)) == 0) { ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; ++ } else { ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = FALSE; ++ } ++ ++ /* ucAmpduParam */ ++ DBGLOG(P2P, TRACE, ++ "AMPDU setting from supplicant:0x%x, & default value:0x%x\n", ++ (UINT_8) HT_CAP_IE(pucIE)->ucAmpduParam, ++ (UINT_8) AMPDU_PARAM_DEFAULT_VAL); ++ ++ /* rSupMcsSet */ ++ /* Can do nothing. the field is default value from other configuration. */ ++ /* HT_CAP_IE(pucIE)->rSupMcsSet; */ ++ ++ /* u2HtExtendedCap */ ++ ASSERT(HT_CAP_IE(pucIE)->u2HtExtendedCap == ++ (HT_EXT_CAP_DEFAULT_VAL & ++ ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE))); ++ ++ /* u4TxBeamformingCap */ ++ ASSERT(HT_CAP_IE(pucIE)->u4TxBeamformingCap == TX_BEAMFORMING_CAP_DEFAULT_VAL); ++ ++ /* ucAselCap */ ++ ASSERT(HT_CAP_IE(pucIE)->ucAselCap == ASEL_CAP_DEFAULT_VAL); ++#endif ++ } ++ break; ++ case ELEM_ID_RSN: /* 48 */ /* V */ ++ { ++ RSN_INFO_T rRsnIe; ++ ++ DBGLOG(P2P, TRACE, "RSN IE\n"); ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); ++ ucNewSecMode = TRUE; ++ ++ if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) { ++ prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++ prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap; ++ } ++ } ++ break; ++ case ELEM_ID_EXTENDED_SUP_RATES: /* 50 */ /* V */ ++ /* Be attention, ++ * ELEM_ID_SUP_RATES should be placed before ELEM_ID_EXTENDED_SUP_RATES. */ ++ DBGLOG(P2P, TRACE, "Ex Support Rate IE\n"); ++ kalMemCopy(&(prP2pBssInfo->aucAllSupportedRates[prP2pBssInfo->ucAllSupportedRatesLen]), ++ EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, ++ EXT_SUP_RATES_IE(pucIE)->ucLength); ++ ++ DBGLOG_MEM8(P2P, TRACE, EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, ++ EXT_SUP_RATES_IE(pucIE)->ucLength); ++ ++ prP2pBssInfo->ucAllSupportedRatesLen += EXT_SUP_RATES_IE(pucIE)->ucLength; ++ break; ++ case ELEM_ID_HT_OP: ++ { ++ /* 61 */ /* V */ /* TODO: */ ++#if 1 ++ DBGLOG(P2P, TRACE, "HT OP IE would be overwritten by driver\n"); ++ ++ DBGLOG(P2P, TRACE, ++ " Primary Channel: %x, Info1: %x, Info2: %x, Info3: %x\n", ++ HT_OP_IE(pucIE)->ucPrimaryChannel, HT_OP_IE(pucIE)->ucInfo1, ++ HT_OP_IE(pucIE)->u2Info2, HT_OP_IE(pucIE)->u2Info3); ++#else ++ UINT_16 u2Info2 = 0; ++ ++ prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ ++ DBGLOG(P2P, TRACE, "HT OP IE\n"); ++ ++ /* ucPrimaryChannel. */ ++ ASSERT(HT_OP_IE(pucIE)->ucPrimaryChannel == prP2pBssInfo->ucPrimaryChannel); ++ ++ /* ucInfo1 */ ++ prP2pBssInfo->ucHtOpInfo1 = HT_OP_IE(pucIE)->ucInfo1; ++ ++ /* u2Info2 */ ++ u2Info2 = HT_OP_IE(pucIE)->u2Info2; ++ ++ if (u2Info2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { ++ ASSERT(prP2pBssInfo->eGfOperationMode != GF_MODE_NORMAL); ++ u2Info2 &= ~HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (u2Info2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) { ++ prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; ++ u2Info2 &= ~HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ switch (u2Info2 & HT_OP_INFO2_HT_PROTECTION) { ++ case HT_PROTECT_MODE_NON_HT: ++ prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NON_HT; ++ break; ++ case HT_PROTECT_MODE_NON_MEMBER: ++ prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; ++ prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; ++ break; ++ default: ++ prP2pBssInfo->eHtProtectMode = HT_OP_IE(pucIE)->u2Info2; ++ break; ++ } ++ ++ /* u2Info3 */ ++ prP2pBssInfo->u2HtOpInfo3 = HT_OP_IE(pucIE)->u2Info3; ++ ++ /* aucBasicMcsSet */ ++ DBGLOG_MEM8(P2P, TRACE, HT_OP_IE(pucIE)->aucBasicMcsSet, 16); ++#endif ++ } ++ break; ++ case ELEM_ID_OBSS_SCAN_PARAMS: /* 74 */ /* V */ ++ { ++ DBGLOG(P2P, TRACE, ++ "ELEM_ID_OBSS_SCAN_PARAMS IE would be replaced by driver\n"); ++ } ++ break; ++ case ELEM_ID_EXTENDED_CAP: /* 127 */ /* V */ ++ { ++ DBGLOG(P2P, TRACE, "ELEM_ID_EXTENDED_CAP IE would be replaced by driver\n"); ++ } ++ break; ++ case ELEM_ID_VENDOR: /* 221 */ /* V */ ++ DBGLOG(P2P, TRACE, "Vender Specific IE\n"); ++ if (rsnParseCheckForWFAInfoElem ++ (prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { ++ if ((ucOuiType == VENDOR_OUI_TYPE_WPA) ++ && (u2SubTypeVersion == VERSION_WPA)) { ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_TKIP); ++ ucNewSecMode = TRUE; ++ kalMemCopy(prP2pSpecificBssInfo->aucWpaIeBuffer, pucIE, ++ IE_SIZE(pucIE)); ++ prP2pSpecificBssInfo->u2WpaIeLen = IE_SIZE(pucIE); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 0, pucIE, ++ IE_SIZE(pucIE)); ++ } ++ /* WMM here. */ ++ } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { ++ /* TODO Store the whole P2P IE & generate later. */ ++ /* Be aware that there may be one or more P2P IE. */ ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ } ++ } else { ++ ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache ++ [prP2pSpecificBssInfo->u2AttributeLen], pucIE, ++ IE_SIZE(pucIE)); ++ ++ prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); ++ DBGLOG(P2P, TRACE, "Driver unprocessed Vender Specific IE\n"); ++ ASSERT(FALSE); ++ } ++ ++ /* TODO: Store other Vender IE except for WMM Param. */ ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Unprocessed element ID:%d\n", IE_ID(pucIE)); ++ break; ++ } ++ } ++ ++ if (!ucNewSecMode && ucOldSecMode) ++ kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_NONE); ++ ++ } while (FALSE); ++ ++} /* p2pFuncParseBeaconContent */ ++ ++P_BSS_DESC_T ++p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, ++ IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) ++{ ++ P_BSS_DESC_T prTargetBss = (P_BSS_DESC_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prConnReqInfo != NULL) && (prChnlReqInfo != NULL) && (prScanReqInfo != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ break; ++ /* Update connection request information. */ ++ ASSERT(prConnReqInfo->fgIsConnRequest == TRUE); ++ ++ /* Find BSS Descriptor first. */ ++ prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); ++ ++ if (prTargetBss == NULL) { ++ /* Update scan parameter... to scan target device. */ ++ prScanReqInfo->ucNumChannelList = 1; ++ prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; ++ prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ } else { ++ prChnlReqInfo->u8Cookie = 0; ++ prChnlReqInfo->ucReqChnlNum = prTargetBss->ucChannelNum; ++ prChnlReqInfo->eBand = prTargetBss->eBand; ++ prChnlReqInfo->eChnlSco = prTargetBss->eSco; ++ prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; ++ } ++ ++ } while (FALSE); ++ ++ return prTargetBss; ++} /* p2pFuncKeepOnConnection */ ++ ++/* Currently Only for ASSOC Response Frame. */ ++VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; ++ P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; ++ INT_16 i2IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); ++ ++ prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prAssocRspFrame->u2FrameCtrl != MAC_FRAME_ASSOC_RSP) ++ break; ++ ++ i2IELen = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + ++ CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); ++ ++ if (i2IELen <= 0) ++ break; ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ prJoinInfo = &(prP2pFsmInfo->rJoinInfo); ++ prJoinInfo->u4BufLength = (UINT_32) i2IELen; ++ ++ kalMemCopy(prJoinInfo->aucIEBuf, prAssocRspFrame->aucInfoElem, prJoinInfo->u4BufLength); ++ ++ } while (FALSE); ++ ++} /* p2pFuncStoreAssocRspIEBuffer */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set Packet Filter. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_SUPPORTED ++* \retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, ++ IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter) ++{ ++ UINT_32 u4NewPacketFilter = 0; ++ ++ DEBUGFUNC("p2pFuncMgmtFrameRegister"); ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ if (pu4P2pPacketFilter) ++ u4NewPacketFilter = *pu4P2pPacketFilter; ++ ++ switch (u2FrameType) { ++ case MAC_FRAME_PROBE_REQ: ++ if (fgIsRegistered) { ++ u4NewPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); ++ } else { ++ u4NewPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (fgIsRegistered) { ++ u4NewPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); ++ } else { ++ u4NewPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Ask frog to add code for mgmt:%x\n", u2FrameType); ++ break; ++ } ++ ++ if (pu4P2pPacketFilter) ++ *pu4P2pPacketFilter = u4NewPacketFilter; ++ ++ /* u4NewPacketFilter |= prAdapter->u4OsPacketFilter; */ ++ ++ prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; ++ prAdapter->u4OsPacketFilter |= u4NewPacketFilter; ++ ++ DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, ++ &u4NewPacketFilter, sizeof(u4NewPacketFilter) ++ ); ++ ++ } while (FALSE); ++ ++} /* p2pFuncMgmtFrameRegister */ ++ ++VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter) ++{ ++ ++ do { ++ ++ prAdapter->rWifiVar.prP2pFsmInfo->u4P2pPacketFilter = u4OsFilter; ++ ++ if ((prAdapter->u4OsPacketFilter & PARAM_PACKET_FILTER_P2P_MASK) ^ u4OsFilter) { ++ ++ prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; ++ ++ prAdapter->u4OsPacketFilter |= (u4OsFilter & PARAM_PACKET_FILTER_P2P_MASK); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RX_FILTER, ++ TRUE, ++ FALSE, ++ FALSE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(UINT_32), ++ (PUINT_8) &prAdapter->u4OsPacketFilter, &u4OsFilter, sizeof(u4OsFilter) ++ ); ++ DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pFuncUpdateMgmtFrameRegister */ ++ ++VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo) ++{ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucMacAddr != NULL) && (prStaInfo != NULL)); ++ ++ prStaInfo->u4InactiveTime = 0; ++ prStaInfo->u4RxBytes = 0; ++ prStaInfo->u4TxBytes = 0; ++ prStaInfo->u4RxPackets = 0; ++ prStaInfo->u4TxPackets = 0; ++ /* TODO: */ ++ ++ } while (FALSE); ++ ++} /* p2pFuncGetStationInfo */ ++ ++BOOLEAN ++p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, ++ IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen) ++{ ++ BOOLEAN fgIsAllocMem = FALSE; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_16 u2Offset = 0; ++ P_IE_P2P_T prIe = (P_IE_P2P_T) NULL; ++ PUINT_8 pucAttriListStart = (PUINT_8) NULL; ++ UINT_16 u2AttriListLen = 0, u2BufferSize = 0; ++ BOOLEAN fgBackupAttributes = FALSE; ++ UINT_16 u2CopyLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucIE); ++ ASSERT(ppucAttriList); ++ ASSERT(pu2AttriListLen); ++ ++ if (ppucAttriList) ++ *ppucAttriList = NULL; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = 0; ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ aucWfaOui[0] = 0x00; ++ aucWfaOui[1] = 0x50; ++ aucWfaOui[2] = 0xF2; ++ } else if ((ucOuiType != VENDOR_OUI_TYPE_P2P) ++#if CFG_SUPPORT_WFD ++ && (ucOuiType != VENDOR_OUI_TYPE_WFD) ++#endif ++ ) { ++ DBGLOG(P2P, INFO, "Not supported OUI Type to parsing 0x%x\n", ucOuiType); ++ return fgIsAllocMem; ++ } ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ if (ELEM_ID_VENDOR != IE_ID(pucIE)) ++ continue; ++ ++ prIe = (P_IE_P2P_T) pucIE; ++ ++ if (prIe->ucLength <= P2P_OUI_TYPE_LEN) ++ continue; ++ ++ if ((prIe->aucOui[0] == aucWfaOui[0]) && ++ (prIe->aucOui[1] == aucWfaOui[1]) && ++ (prIe->aucOui[2] == aucWfaOui[2]) && (ucOuiType == prIe->ucOuiType)) { ++ ++ if (!pucAttriListStart) { ++ pucAttriListStart = &prIe->aucP2PAttributes[0]; ++ if (prIe->ucLength > P2P_OUI_TYPE_LEN) ++ u2AttriListLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); ++ else ++ ASSERT(FALSE); ++ continue; ++ } ++/* More than 2 attributes. */ ++ ++ if (FALSE == fgBackupAttributes) { ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = ++ prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ fgBackupAttributes = TRUE; ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache[0], ++ pucAttriListStart, u2AttriListLen); ++ ++ pucAttriListStart = ++ &prP2pSpecificBssInfo->aucAttributesCache[0]; ++ ++ u2BufferSize = P2P_MAXIMUM_ATTRIBUTE_LEN; ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalMemCopy(&prP2pSpecificBssInfo->aucWscAttributesCache ++ [0], pucAttriListStart, u2AttriListLen); ++ pucAttriListStart = ++ &prP2pSpecificBssInfo->aucWscAttributesCache[0]; ++ ++ u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; ++ } ++#if CFG_SUPPORT_WFD ++ else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ PUINT_8 pucTmpBuf = (PUINT_8) NULL; ++ ++ pucTmpBuf = (PUINT_8) ++ kalMemAlloc(WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE, ++ VIR_MEM_TYPE); ++ ++ if (pucTmpBuf != NULL) { ++ fgIsAllocMem = TRUE; ++ } else { ++ /* Can't alloca memory for WFD IE relocate. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ kalMemCopy(pucTmpBuf, ++ pucAttriListStart, u2AttriListLen); ++ ++ pucAttriListStart = pucTmpBuf; ++ ++ u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; ++ } ++#endif ++ else ++ fgBackupAttributes = FALSE; ++ } ++ ++ u2CopyLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); ++ ++ if ((u2AttriListLen + u2CopyLen) > u2BufferSize) { ++ u2CopyLen = u2BufferSize - u2AttriListLen; ++ DBGLOG(P2P, WARN, ++ "Length of received P2P attributes > maximum cache size.\n"); ++ } ++ ++ if (u2CopyLen) { ++ kalMemCopy((PUINT_8) ++ ((ULONG) pucAttriListStart + ++ (UINT_32) u2AttriListLen), ++ &prIe->aucP2PAttributes[0], u2CopyLen); ++ ++ u2AttriListLen += u2CopyLen; ++ } ++ } /* prIe->aucOui */ ++ } /* IE_FOR_EACH */ ++ ++ if (pucAttriListStart) { ++ PUINT_8 pucAttribute = pucAttriListStart; ++ ++ DBGLOG(P2P, LOUD, "Checking Attribute Length.\n"); ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ P2P_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset); ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ /* Do nothing */ ++ } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ /* Big Endian: WSC, WFD. */ ++ WSC_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset) { ++ DBGLOG(P2P, LOUD, "Attribute ID:%d, Length:%d.\n", ++ WSC_ATTRI_ID(pucAttribute), WSC_ATTRI_LEN(pucAttribute)); ++ } ++ } else { ++ } ++ ++ ASSERT(u2Offset == u2AttriListLen); ++ ++ if (ppucAttriList) ++ *ppucAttriList = pucAttriListStart; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = u2AttriListLen; ++ ++ } else { ++ if (ppucAttriList) ++ *ppucAttriList = (PUINT_8) NULL; ++ if (pu2AttriListLen) ++ *pu2AttriListLen = 0; ++ } ++ ++ return fgIsAllocMem; ++} /* p2pFuncGetAttriList */ ++ ++P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu) ++{ ++ P_MSDU_INFO_T prRetMsduInfo = prMgmtTxMsdu; ++ P_WLAN_PROBE_RSP_FRAME_T prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0, u2IELength = 0, u2ProbeRspHdrLen = 0; ++ BOOLEAN fgIsP2PIE = FALSE, fgIsWSCIE = FALSE; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ UINT_16 u2EstimateSize = 0, u2EstimatedExtraIELen = 0; ++ UINT_32 u4IeArraySize = 0, u4Idx = 0; ++ UINT_8 ucOuiType = 0; ++ UINT_16 u2SubTypeVersion = 0; ++ ++ BOOLEAN fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxMsdu != NULL)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ /* 3 Make sure this is probe response frame. */ ++ prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); ++ ASSERT_BREAK((prProbeRspFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_PROBE_RSP); ++ ++ if (prP2pBssInfo->u2BeaconInterval) ++ prProbeRspFrame->u2BeaconInterval = prP2pBssInfo->u2BeaconInterval; ++ ++ /* 3 Get the importent P2P IE. */ ++ u2ProbeRspHdrLen = ++ (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ pucIEBuf = prProbeRspFrame->aucInfoElem; ++ u2IELength = prMgmtTxMsdu->u2FrameLength - u2ProbeRspHdrLen; ++ ++#if CFG_SUPPORT_WFD ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen = 0; ++#endif ++ ++ IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { ++ switch (IE_ID(pucIEBuf)) { ++ case ELEM_ID_SSID: ++ { ++ ++ COPY_SSID(prP2pBssInfo->aucSSID, ++ prP2pBssInfo->ucSSIDLen, ++ SSID_IE(pucIEBuf)->aucSSID, SSID_IE(pucIEBuf)->ucLength); ++ } ++ break; ++ case ELEM_ID_VENDOR: ++#if !CFG_SUPPORT_WFD ++ if (rsnParseCheckForWFAInfoElem(prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 2, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ fgIsWSCIE = TRUE; ++ } ++ ++ } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIEBuf, &ucOuiType)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ /* 2 Note(frog): I use WSC IE buffer for Probe Request to ++ * store the P2P IE for Probe Response. */ ++ kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 1, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ fgIsP2PIE = TRUE; ++ } ++ ++ } else { ++ if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + ++ IE_SIZE(pucIEBuf)) < 512) { ++ kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, ++ pucIEBuf, IE_SIZE(pucIEBuf)); ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += ++ IE_SIZE(pucIEBuf); ++ } ++ } ++#else ++ /* Eddie May be WFD */ ++ if (rsnParseCheckForWFAInfoElem ++ (prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_WMM) ++ break; ++ ++ } ++ if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + IE_SIZE(pucIEBuf)) < ++ 1024) { ++ kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE + ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen, pucIEBuf, ++ IE_SIZE(pucIEBuf)); ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += IE_SIZE(pucIEBuf); ++ } ++#endif ++ break; ++ default: ++ break; ++ } ++ ++ } ++ ++ /* 3 Check the total size & current frame. */ ++ u2EstimateSize = WLAN_MAC_MGMT_HEADER_LEN + ++ TIMESTAMP_FIELD_LEN + ++ BEACON_INTERVAL_FIELD_LEN + ++ CAP_INFO_FIELD_LEN + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + ++ (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET); ++ ++ u2EstimatedExtraIELen = 0; ++ ++ u4IeArraySize = sizeof(txProbeRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); ++ for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { ++ if (txProbeRspIETable[u4Idx].u2EstimatedFixedIELen) { ++ u2EstimatedExtraIELen += txProbeRspIETable[u4Idx].u2EstimatedFixedIELen; ++ } ++ ++ else { ++ ASSERT(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen); ++ ++ u2EstimatedExtraIELen += ++ (UINT_16) (txProbeRspIETable[u4Idx].pfnCalculateVariableIELen ++ (prAdapter, NETWORK_TYPE_P2P_INDEX, NULL)); ++ } ++ ++ } ++ ++ if (fgIsWSCIE) ++ u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); ++ ++ if (fgIsP2PIE) { ++ u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); ++ u2EstimatedExtraIELen += p2pFuncCalculateP2P_IE_NoA(prAdapter, 0, NULL); ++ } ++#if CFG_SUPPORT_WFD ++ u2EstimatedExtraIELen += prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; ++#endif ++ ++ u2EstimateSize += u2EstimatedExtraIELen; ++ if (u2EstimateSize > (prRetMsduInfo->u2FrameLength)) { ++ prRetMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimateSize); ++ ++ if (prRetMsduInfo == NULL) { ++ DBGLOG(P2P, WARN, "No packet for sending new probe response, use original one\n"); ++ prRetMsduInfo = prMgmtTxMsdu; ++ break; ++ } ++ ++ prRetMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } ++ /* 3 Compose / Re-compose probe response frame. */ ++ bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ++ ((ULONG) (prRetMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prProbeRspFrame->aucDestAddr, prProbeRspFrame->aucSrcAddr, ++ prProbeRspFrame->aucBSSID, prProbeRspFrame->u2BeaconInterval, ++ fgIsPureAP ? prP2pBssInfo-> ++ u2CapInfo : prProbeRspFrame->u2CapInfo); ++ ++ prRetMsduInfo->u2FrameLength = ++ (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); ++ ++ bssBuildBeaconProbeRespFrameCommonIEs(prRetMsduInfo, prP2pBssInfo, prProbeRspFrame->aucDestAddr); ++ ++ for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { ++ if (txProbeRspIETable[u4Idx].pfnAppendIE) ++ txProbeRspIETable[u4Idx].pfnAppendIE(prAdapter, prRetMsduInfo); ++ ++ } ++ ++ if (fgIsWSCIE) { ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, ++ 2, ++ (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + ++ (UINT_32) prRetMsduInfo->u2FrameLength)); ++ ++ prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); ++ } ++ ++ if (fgIsP2PIE) { ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, ++ 1, ++ (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + ++ (UINT_32) prRetMsduInfo->u2FrameLength)); ++ ++ prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); ++ p2pFuncGenerateP2P_IE_NoA(prAdapter, prRetMsduInfo); ++ } ++#if CFG_SUPPORT_WFD ++ if (prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen > 0) { ++ kalMemCopy((PUINT_8) ((ULONG) prRetMsduInfo->prPacket + (UINT_32) prRetMsduInfo->u2FrameLength), ++ prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, ++ prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen); ++ prRetMsduInfo->u2FrameLength += (UINT_16) prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; ++ } ++#endif ++ ++ } while (FALSE); ++ ++ if (prRetMsduInfo != prMgmtTxMsdu) ++ cnmMgtPktFree(prAdapter, prMgmtTxMsdu); ++ ++ return prRetMsduInfo; ++} /* p2pFuncProcessP2pProbeRsp */ ++ ++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++UINT_32 ++p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ UINT_32 u4IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4IELen = prP2pSpeBssInfo->u2IELenForBCN; ++ ++ } while (FALSE); ++ ++ return u4IELen; ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ pucIEBuf = (PUINT_8) ((UINT_32) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucBeaconIECache, prP2pSpeBssInfo->u2IELenForBCN); ++ ++ prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2IELenForBCN; ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateExtra_IEForBeacon */ ++ ++#else ++UINT_32 ++p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ UINT_32 u4IELen = 0; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); ++ ++ if (!prAdapter->fgIsP2PRegistered) ++ break; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4IELen = prP2pSpeBssInfo->u2AttributeLen; ++ ++ } while (FALSE); ++ ++ return u4IELen; ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ if (!prAdapter->fgIsP2PRegistered) ++ break; ++ ++ prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ break; ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucAttributesCache, prP2pSpeBssInfo->u2AttributeLen); ++ ++ prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2AttributeLen; ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateP2p_IEForBeacon */ ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++} /* p2pFuncCalculateP2p_IELenForBeacon */ ++ ++VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ UINT_16 u2IELen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) ++ return; ++ ++ u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* TODO: Check P2P FSM State. */ ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); ++ ++ prMsduInfo->u2FrameLength += u2IELen; ++ ++} /* p2pFuncGenerateP2p_IEForBeacon */ ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate P2P IE length for Beacon frame. ++* ++* @param[in] eNetTypeIndex Specify which network ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of P2P IE added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ++p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return p2pFuncCalculateP2P_IELen(prAdapter, ++ eNetTypeIndex, ++ prStaRec, ++ txAssocRspAttributesTable, ++ sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ ++} /* p2pFuncCalculateP2p_IELenForAssocRsp */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ if (!prStaRec) ++ break; ++ ++ if (IS_STA_P2P_TYPE(prStaRec)) { ++ DBGLOG(P2P, TRACE, "Generate NULL P2P IE for Assoc Rsp.\n"); ++ ++ p2pFuncGenerateP2P_IE(prAdapter, ++ TRUE, ++ &prMsduInfo->u2FrameLength, ++ prMsduInfo->prPacket, ++ 1500, ++ txAssocRspAttributesTable, ++ sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ } else { ++ ++ DBGLOG(P2P, TRACE, "Legacy device, no P2P IE.\n"); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pFuncGenerateP2p_IEForAssocRsp */ ++ ++UINT_32 ++p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ DBGLOG(P2P, TRACE, "p2pFuncCalculateWSC_IELenForAssocRsp\n"); ++ if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) ++ return 0; ++ ++ return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++} /* p2pFuncCalculateP2p_IELenForAssocRsp */ ++ ++VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ UINT_16 u2IELen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) ++ return; ++ DBGLOG(P2P, TRACE, "p2pFuncGenerateWSC_IEForAssocRsp\n"); ++ ++ u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* TODO: Check P2P FSM State. */ ++ kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); ++ ++ prMsduInfo->u2FrameLength += u2IELen; ++ ++} ++ ++/* p2pFuncGenerateP2p_IEForAssocRsp */ ++ ++UINT_32 ++p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN P_STA_RECORD_T prStaRec, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ ++ UINT_32 u4OverallAttriLen, u4Dummy; ++ UINT_16 u2EstimatedFixedAttriLen; ++ UINT_32 i; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ u2EstimatedFixedAttriLen = arAppendAttriTable[i].u2EstimatedFixedAttriLen; ++ ++ if (u2EstimatedFixedAttriLen) { ++ u4OverallAttriLen += u2EstimatedFixedAttriLen; ++ } else { ++ ASSERT(arAppendAttriTable[i].pfnCalculateVariableAttriLen); ++ ++ u4OverallAttriLen += arAppendAttriTable[i].pfnCalculateVariableAttriLen(prAdapter, prStaRec); ++ } ++ } ++ ++ u4Dummy = u4OverallAttriLen; ++ u4OverallAttriLen += P2P_IE_OUI_HDR; ++ ++ for (; (u4Dummy > P2P_MAXIMUM_ATTRIBUTE_LEN);) { ++ u4OverallAttriLen += P2P_IE_OUI_HDR; ++ u4Dummy -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ } ++ ++ return u4OverallAttriLen; ++} /* p2pFuncCalculateP2P_IELen */ ++ ++VOID ++p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ P_IE_P2P_T prIeP2P = (P_IE_P2P_T) NULL; ++ UINT_32 u4OverallAttriLen; ++ UINT_32 u4AttriLen; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; ++ UINT_32 i; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ /* Check buffer length is still enough. */ ++ ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= P2P_IE_OUI_HDR); ++ ++ prIeP2P = (P_IE_P2P_T) pucBuffer; ++ ++ prIeP2P->ucId = ELEM_ID_P2P; ++ ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ (*pu2Offset) += P2P_IE_OUI_HDR; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ ++ if (arAppendAttriTable[i].pfnAppendAttri) { ++ u4AttriLen = ++ arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, ++ u2BufSize); ++ ++ u4OverallAttriLen += u4AttriLen; ++ ++ if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { ++ u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ ++ prIeP2P->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); ++ ++ pucBuffer = ++ (PUINT_8) ((ULONG) prIeP2P + ++ (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ prIeP2P = (P_IE_P2P_T) ((ULONG) prIeP2P + ++ (ELEM_HDR_LEN + ++ (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN))); ++ ++ kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); ++ ++ prIeP2P->ucId = ELEM_ID_P2P; ++ ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ kalMemCopy(prIeP2P->aucP2PAttributes, aucTempBuffer, u4OverallAttriLen); ++ (*pu2Offset) += P2P_IE_OUI_HDR; ++ } ++ ++ } ++ ++ } ++ ++ prIeP2P->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); ++ ++ } while (FALSE); ++ ++} /* p2pFuncGenerateP2P_IE */ ++ ++UINT_32 ++p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ PUINT_8 pucBuffer; ++ P_P2P_ATTRI_STATUS_T prAttriStatus; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 u4AttriLen = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (fgIsAssocFrame) ++ return u4AttriLen; ++ /* TODO: For assoc request P2P IE check in driver & return status in P2P IE. */ ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT(pucBuffer); ++ prAttriStatus = (P_P2P_ATTRI_STATUS_T) pucBuffer; ++ ++ ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); ++ ++ prAttriStatus->ucId = P2P_ATTRI_ID_STATUS; ++ WLAN_SET_FIELD_16(&prAttriStatus->u2Length, P2P_ATTRI_MAX_LEN_STATUS); ++ ++ prAttriStatus->ucStatusCode = P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR; ++ ++ u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} /* p2pFuncAppendAttriStatusForAssocRsp */ ++ ++UINT_32 ++p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ P_P2P_ATTRI_EXT_LISTEN_TIMING_T prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ PUINT_8 pucBuffer = NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(pucBuf); ++ ++ if (fgIsAssocFrame) ++ return u4AttriLen; ++ /* TODO: For extend listen timing. */ ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); ++ ++ ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT(pucBuffer); ++ ++ prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) pucBuffer; ++ ++ prP2pExtListenTiming->ucId = P2P_ATTRI_ID_EXT_LISTEN_TIMING; ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2Length, P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailInterval, prP2pSpecificBssInfo->u2AvailabilityInterval); ++ WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailPeriod, prP2pSpecificBssInfo->u2AvailabilityPeriod); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} /* p2pFuncAppendAttriExtListenTiming */ ++ ++P_IE_HDR_T ++p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore) ++{ ++ P_IE_HDR_T prTargetIE = (P_IE_HDR_T) NULL; ++ PUINT_8 pucIE = (PUINT_8) NULL; ++ UINT_16 u2Offset = 0; ++ ++ if (pfgIsMore) ++ *pfgIsMore = FALSE; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) ++ && (pucIEBuf != NULL)); ++ ++ pucIE = pucIEBuf; ++ ++ IE_FOR_EACH(pucIE, u2BufferLen, u2Offset) { ++ if (IE_ID(pucIE) == ucElemID) { ++ if ((prTargetIE) && (pfgIsMore)) { ++ ++ *pfgIsMore = TRUE; ++ break; ++ } ++ prTargetIE = (P_IE_HDR_T) pucIE; ++ ++ if (pfgIsMore == NULL) ++ break; ++ ++ } ++ } ++ ++ } while (FALSE); ++ ++ return prTargetIE; ++} /* p2pFuncGetSpecIE */ ++ ++P_ATTRIBUTE_HDR_T ++p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID) ++{ ++ P_IE_P2P_T prP2pIE = (P_IE_P2P_T) NULL; ++ P_ATTRIBUTE_HDR_T prTargetAttri = (P_ATTRIBUTE_HDR_T) NULL; ++ BOOLEAN fgIsMore = FALSE; ++ PUINT_8 pucIE = (PUINT_8) NULL, pucAttri = (PUINT_8) NULL; ++ UINT_16 u2OffsetAttri = 0; ++ UINT_16 u2BufferLenLeft = 0; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ ++ DBGLOG(P2P, INFO, "Check AssocReq Oui type %u attri %u for len %u\n", ucOuiType, u2AttriID, u2BufferLen); ++ ++ ASSERT(prAdapter); ++ ASSERT(pucIEBuf); ++ ++ u2BufferLenLeft = u2BufferLen; ++ pucIE = pucIEBuf; ++ do { ++ fgIsMore = FALSE; ++ prP2pIE = (P_IE_P2P_T) p2pFuncGetSpecIE(prAdapter, ++ pucIE, u2BufferLenLeft, ELEM_ID_VENDOR, &fgIsMore); ++ if (prP2pIE == NULL) ++ continue; ++ ++ ASSERT((ULONG) prP2pIE >= (ULONG) pucIE); ++ ++ u2BufferLenLeft = u2BufferLen - (UINT_16) (((ULONG) prP2pIE) - ((ULONG) pucIEBuf)); ++ ++ DBGLOG(P2P, INFO, "Find vendor id %u len %u oui %u more %u LeftLen %u\n", ++ IE_ID(prP2pIE), IE_LEN(prP2pIE), prP2pIE->ucOuiType, fgIsMore, ++ u2BufferLenLeft); ++ ++ if ((IE_LEN(prP2pIE) > P2P_OUI_TYPE_LEN) && (prP2pIE->ucOuiType == ucOuiType)) { ++ switch (ucOuiType) { ++ case VENDOR_OUI_TYPE_WPS: ++ aucWfaOui[0] = 0x00; ++ aucWfaOui[1] = 0x50; ++ aucWfaOui[2] = 0xF2; ++ break; ++ case VENDOR_OUI_TYPE_P2P: ++ break; ++ case VENDOR_OUI_TYPE_WPA: ++ case VENDOR_OUI_TYPE_WMM: ++ case VENDOR_OUI_TYPE_WFD: ++ default: ++ break; ++ } ++ ++ if ((prP2pIE->aucOui[0] != aucWfaOui[0]) ++ || (prP2pIE->aucOui[1] != aucWfaOui[1]) ++ || (prP2pIE->aucOui[2] != aucWfaOui[2])) ++ continue; ++ ++ u2OffsetAttri = 0; ++ pucAttri = prP2pIE->aucP2PAttributes; ++ ++ if (ucOuiType == VENDOR_OUI_TYPE_WPS) { ++ WSC_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* LOG_FUNC("WSC: attri id=%u len=%u\n", ++ * WSC_ATTRI_ID(pucAttri), ++ * WSC_ATTRI_LEN(pucAttri)); */ ++ if (WSC_ATTRI_ID(pucAttri) == u2AttriID) { ++ prTargetAttri = ++ (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ ++ } else if (ucOuiType == VENDOR_OUI_TYPE_P2P) { ++ P2P_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* LOG_FUNC("P2P: attri id=%u len=%u\n", ++ * ATTRI_ID(pucAttri), ATTRI_LEN(pucAttri)); */ ++ if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { ++ prTargetAttri = (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ } ++#if CFG_SUPPORT_WFD ++ else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { ++ WFD_ATTRI_FOR_EACH(pucAttri, ++ (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { ++ /* DBGLOG(P2P, INFO, ("WFD: attri id=%u ++ * len=%u\n",WFD_ATTRI_ID(pucAttri), ++ * WFD_ATTRI_LEN(pucAttri))); */ ++ if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { ++ prTargetAttri = ++ (P_ATTRIBUTE_HDR_T) pucAttri; ++ break; ++ } ++ } ++ } ++#endif ++ /* Do nothing */ ++ /* Possible or else. */ ++ } /* ucOuiType */ ++ /* P2P_OUI_TYPE_LEN */ ++ pucIE = (PUINT_8) (((ULONG) prP2pIE) + IE_SIZE(prP2pIE)); ++ /* prP2pIE */ ++ } while (prP2pIE && fgIsMore && u2BufferLenLeft); ++ ++ return prTargetAttri; ++} ++ ++/* p2pFuncGetSpecAttri */ ++ ++WLAN_STATUS ++p2pFuncGenerateBeaconProbeRsp(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_INFO_T prBssInfo, IN P_MSDU_INFO_T prMsduInfo, IN BOOLEAN fgIsProbeRsp) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++/* P_APPEND_VAR_IE_ENTRY_T prAppendIeTable = (P_APPEND_VAR_IE_ENTRY_T)NULL; */ ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL) && (prMsduInfo != NULL)); ++ ++/* txBcnIETable */ ++ ++/* txProbeRspIETable */ ++ ++ prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; ++ ++ return nicUpdateBeaconIETemplate(prAdapter, ++ IE_UPD_METHOD_UPDATE_ALL, ++ NETWORK_TYPE_P2P_INDEX, ++ prBssInfo->u2CapInfo, ++ (PUINT_8) prBcnFrame->aucInfoElem, ++ prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, ++ aucInfoElem)); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++} /* p2pFuncGenerateBeaconProbeRsp */ ++ ++WLAN_STATUS ++p2pFuncComposeBeaconProbeRspTemplate(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBcnBuffer, ++ IN UINT_32 u4BcnBufLen, ++ IN BOOLEAN fgIsProbeRsp, ++ IN P_P2P_PROBE_RSP_UPDATE_INFO_T prP2pProbeRspInfo, IN BOOLEAN fgSynToFW) ++{ ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ P_WLAN_MAC_HEADER_T prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBcnBuffer != NULL)); ++ ++ prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) pucBcnBuffer; ++ ++ if ((prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_BEACON) && (!fgIsProbeRsp)) { ++ rWlanStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ else if (prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_PROBE_RSP) { ++ rWlanStatus = WLAN_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (fgIsProbeRsp) { ++ ASSERT_BREAK(prP2pProbeRspInfo != NULL); ++ ++ if (prP2pProbeRspInfo->prProbeRspMsduTemplate) ++ cnmMgtPktFree(prAdapter, prP2pProbeRspInfo->prProbeRspMsduTemplate); ++ ++ prP2pProbeRspInfo->prProbeRspMsduTemplate = cnmMgtPktAlloc(prAdapter, u4BcnBufLen); ++ ++ prMsduInfo = prP2pProbeRspInfo->prProbeRspMsduTemplate; ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ prMsduInfo->ucStaRecIndex = 0xFF; ++ prMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++ } else { ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prMsduInfo = prP2pBssInfo->prBeacon; ++ ++ if (prMsduInfo == NULL) { ++ rWlanStatus = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ if (u4BcnBufLen > (OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH)) { ++ /* Unexpected error, buffer overflow. */ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucBuffer, pucBcnBuffer, u4BcnBufLen); ++ ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = (UINT_16) u4BcnBufLen; ++ ++ if (fgSynToFW && prP2pBssInfo) ++ rWlanStatus = p2pFuncGenerateBeaconProbeRsp(prAdapter, prP2pBssInfo, prMsduInfo, fgIsProbeRsp); ++ ++ } while (FALSE); ++ ++ return rWlanStatus; ++ ++} /* p2pFuncComposeBeaconTemplate */ ++ ++#if CFG_SUPPORT_WFD ++WLAN_STATUS wfdAdjustResource(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) ++{ ++#if 1 ++ /* The API shall be called in tx_thread */ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); ++ if (fgEnable) { ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ if (QM_GUARANTEED_TC0_RESOURCE > 2) { ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE - 2; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; ++ } ++ if (QM_GUARANTEED_TC1_RESOURCE > 2) { ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE - 2; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; ++ } ++ } else { ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} ++ ++WLAN_STATUS wfdAdjustThread(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) ++{ ++#define WFD_TX_THREAD_PRIORITY 70 ++ DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); ++ if (prAdapter->prGlueInfo->main_thread != NULL) { ++ if (fgEnable) { ++#ifdef LINUX ++ /* TODO the change schedule API shall be provided by OS glue layer */ ++ /* Or the API shall be put in os glue layer */ ++ struct sched_param param = {.sched_priority = WFD_TX_THREAD_PRIORITY }; ++ ++ sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_RR, ¶m); ++#endif ++ } else { ++#ifdef LINUX ++ /* TODO the change schedule API shall be provided by OS glue layer */ ++ struct sched_param param = {.sched_priority = 0 }; ++ ++ sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_NORMAL, ¶m); ++#endif ++ } ++ } else { ++ ++ DBGLOG(P2P, WARN, "main_thread is null, please check if the wlanRemove is called in advance\n"); ++ } ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif /* CFG_SUPPORT_WFD */ ++ ++WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, ENUM_PARAM_MEDIA_STATE_T eConnectionState) ++{ ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered == FALSE) ++ return WLAN_STATUS_SUCCESS; ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ ++ if ((prWfdCfgSettings->ucWfdEnable) && ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == ++ PARAM_MEDIA_STATE_CONNECTED) { ++ wfdAdjustResource(prAdapter, TRUE); ++ wfdAdjustThread(prAdapter, TRUE); ++ } else { ++ wfdAdjustResource(prAdapter, FALSE); ++ wfdAdjustThread(prAdapter, FALSE); ++ } ++ ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c +new file mode 100644 +index 000000000000..991861f73608 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c +@@ -0,0 +1,612 @@ ++#include "p2p_precomp.h" ++ ++#if CFG_SUPPORT_WFD ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++#if 0 ++APPEND_VAR_ATTRI_ENTRY_T txProbeRspWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_EXT_CAPABILITY), NULL, wfdFuncAppendAttriExtCapability} /* 7 */ ++ , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ ++}; ++ ++APPEND_VAR_ATTRI_ENTRY_T txBeaconWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++}; ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocReqWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++}; ++#endif ++ ++APPEND_VAR_ATTRI_ENTRY_T txAssocRspWFDAttributesTable[] = { ++ {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ ++ , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ ++ , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ ++ ++}; ++ ++#endif ++ ++UINT_32 ++p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ UINT_32 u4RetValue = 0; ++ ++ do { ++ ASSERT_BREAK((eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) && (prAdapter != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ u4RetValue = prConnReqInfo->u4BufLength; ++ ++ /* ADD HT Capability */ ++ u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP); ++ ++ /* ADD WMM Information Element */ ++ u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO); ++ ++ } while (FALSE); ++ ++ return u4RetValue; ++} /* p2pCalculate_IEForAssocReq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to generate P2P IE for Beacon frame. ++* ++* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; ++ PUINT_8 pucIEBuf = (PUINT_8) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); ++ ++ prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); ++ ++ pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ kalMemCopy(pucIEBuf, prConnReqInfo->aucIEBuf, prConnReqInfo->u4BufLength); ++ ++ prMsduInfo->u2FrameLength += prConnReqInfo->u4BufLength; ++ ++ rlmReqGenerateHtCapIE(prAdapter, prMsduInfo); ++ mqmGenerateWmmInfoIE(prAdapter, prMsduInfo); ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pGenerate_IEForAssocReq */ ++ ++UINT_32 ++wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_DEVICE_INFORMATION_IE_T prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdDevInfo->ucElemID = WFD_ATTRI_ID_DEV_INFO; ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevInfo, prWfdCfgSettings->u2WfdDevInfo); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2SessionMgmtCtrlPort, prWfdCfgSettings->u2WfdControlPort); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevMaxSpeed, prWfdCfgSettings->u2WfdMaximumTp); ++ ++ WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2Length, WFD_ATTRI_MAX_LEN_DEV_INFO); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_DEV_INFO + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriDevInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_ASSOCIATED_BSSID_IE_T prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_BSS_INFO_T prAisBssInfo = (P_BSS_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ ++ /* AIS network. */ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if ((!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) || ++ (prAisBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) pucBuffer; ++ ++ prWfdAssocBssid->ucElemID = WFD_ATTRI_ID_ASSOC_BSSID; ++ ++ WLAN_SET_FIELD_BE16(&prWfdAssocBssid->u2Length, WFD_ATTRI_MAX_LEN_ASSOC_BSSID); ++ ++ COPY_MAC_ADDR(prWfdAssocBssid->aucAssocBssid, prAisBssInfo->aucBSSID); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_ASSOC_BSSID + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriAssocBssid */ ++ ++UINT_32 ++wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_COUPLE_SINK_INFORMATION_IE_T prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_SINK_INFO_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdCoupleSinkInfo->ucElemID = WFD_ATTRI_ID_COUPLED_SINK_INFO; ++ ++ WLAN_SET_FIELD_BE16(&prWfdCoupleSinkInfo->u2Length, WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO); ++ ++ COPY_MAC_ADDR(prWfdCoupleSinkInfo->aucCoupleSinkMac, prWfdCfgSettings->aucWfdCoupleSinkAddress); ++ ++ prWfdCoupleSinkInfo->ucCoupleSinkStatusBp = prWfdCfgSettings->ucWfdCoupleSinkStatus; ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriCoupledSinkInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_EXTENDED_CAPABILITY_IE_T prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || ++ ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_EXT_CAPABILITY_VALID) == 0)) { ++ break; ++ } ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) pucBuffer; ++ ++ prWfdExtCapability->ucElemID = WFD_ATTRI_ID_EXT_CAPABILITY; ++ ++ WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2Length, WFD_ATTRI_MAX_LEN_EXT_CAPABILITY); ++ ++ WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2WfdExtCapabilityBp, prWfdCfgSettings->u2WfdExtendCap); ++ ++ u4AttriLen = WFD_ATTRI_MAX_LEN_EXT_CAPABILITY + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriExtCapability */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to calculate length of Channel List Attribute ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return The length of Attribute added ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ UINT_16 u2AttriLen = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ ++ u2AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ return (UINT_32) u2AttriLen; ++ ++} /* wfdFuncCalculateAttriLenSessionInfo */ ++ ++UINT_32 ++wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) ++{ ++ UINT_32 u4AttriLen = 0; ++ PUINT_8 pucBuffer = NULL; ++ P_WFD_SESSION_INFORMATION_IE_T prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) NULL; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ ASSERT_BREAK((prWfdCfgSettings != NULL)); ++ ++ if ((prWfdCfgSettings->ucWfdEnable == 0) || (prWfdCfgSettings->u2WfdSessionInformationIELen == 0)) ++ break; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) pucBuffer; ++ ++ prWfdSessionInfo->ucElemID = WFD_ATTRI_ID_SESSION_INFO; ++ ++ /* TODO: Check endian issue? */ ++ kalMemCopy(prWfdSessionInfo->pucWfdDevInfoDesc, prWfdCfgSettings->aucWfdSessionInformationIE, ++ prWfdCfgSettings->u2WfdSessionInformationIELen); ++ ++ WLAN_SET_FIELD_16(&prWfdSessionInfo->u2Length, prWfdCfgSettings->u2WfdSessionInformationIELen); ++ ++ u4AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; ++ ++ } while (FALSE); ++ ++ (*pu2Offset) += (UINT_16) u4AttriLen; ++ ++ return u4AttriLen; ++} ++ ++/* wfdFuncAppendAttriSessionInfo */ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++VOID ++wfdFuncGenerateWfd_IE(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgIsAssocFrame, ++ IN PUINT_16 pu2Offset, ++ IN PUINT_8 pucBuf, ++ IN UINT_16 u2BufSize, ++ IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) ++{ ++ ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ P_IE_WFD_T prIeWFD = (P_IE_WFD_T) NULL; ++ UINT_32 u4OverallAttriLen; ++ UINT_32 u4AttriLen; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; ++ UINT_32 i; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); ++ ++ ASSERT_BREAK(pucBuffer != NULL); ++ ++ /* Check buffer length is still enough. */ ++ ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= WFD_IE_OUI_HDR); ++ ++ prIeWFD = (P_IE_WFD_T) pucBuffer; ++ ++ prIeWFD->ucId = ELEM_ID_WFD; ++ ++ prIeWFD->aucOui[0] = aucWfaOui[0]; ++ prIeWFD->aucOui[1] = aucWfaOui[1]; ++ prIeWFD->aucOui[2] = aucWfaOui[2]; ++ prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; ++ ++ (*pu2Offset) += WFD_IE_OUI_HDR; ++ ++ /* Overall length of all Attributes */ ++ u4OverallAttriLen = 0; ++ ++ for (i = 0; i < u4AttriTableSize; i++) { ++ ++ if (arAppendAttriTable[i].pfnAppendAttri) { ++ u4AttriLen = ++ arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, ++ u2BufSize); ++ ++ u4OverallAttriLen += u4AttriLen; ++ ++ if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { ++ u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; ++ ++ prIeWFD->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); ++ ++ pucBuffer = ++ (PUINT_8) ((ULONG) prIeWFD + (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ prIeWFD = ++ (P_IE_WFD_T) ((ULONG) prIeWFD + ++ (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); ++ ++ kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); ++ ++ prIeWFD->ucId = ELEM_ID_WFD; ++ ++ prIeWFD->aucOui[0] = aucWfaOui[0]; ++ prIeWFD->aucOui[1] = aucWfaOui[1]; ++ prIeWFD->aucOui[2] = aucWfaOui[2]; ++ prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; ++ ++ kalMemCopy(prIeWFD->aucWFDAttributes, aucTempBuffer, u4OverallAttriLen); ++ (*pu2Offset) += WFD_IE_OUI_HDR; ++ } ++ ++ } ++ ++ } ++ ++ prIeWFD->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); ++ ++ } while (FALSE); ++ ++} /* wfdFuncGenerateWfd_IE */ ++ ++#endif /* CFG_SUPPORT_WFD_COMPOSE_IE */ ++ ++UINT_32 ++wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) ++{ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ if (!IS_STA_P2P_TYPE(prStaRec) || (prWfdCfgSettings->ucWfdEnable == 0)) ++ return 0; ++ ++ return p2pFuncCalculateP2P_IELen(prAdapter, ++ eNetTypeIndex, ++ prStaRec, ++ txAssocRspWFDAttributesTable, ++ sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ ++#else ++ return 0; ++#endif ++} /* wfdFuncCalculateWfdIELenForAssocRsp */ ++ ++VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ ++#if CFG_SUPPORT_WFD_COMPOSE_IE ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_STA_RECORD_T prStaRec; ++ ++ do { ++ ASSERT_BREAK((prMsduInfo != NULL) && (prAdapter != NULL)); ++ ++ prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ ASSERT(FALSE); ++ } else if (IS_STA_P2P_TYPE(prStaRec)) { ++ ++ if (prWfdCfgSettings->ucWfdEnable == 0) ++ break; ++ if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0) ++ break; ++ ++ wfdFuncGenerateWfd_IE(prAdapter, ++ FALSE, ++ &prMsduInfo->u2FrameLength, ++ prMsduInfo->prPacket, ++ 1500, ++ txAssocRspWFDAttributesTable, ++ sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); ++ } ++ } while (FALSE); ++ ++ return; ++#else ++ ++ return; ++#endif ++} /* wfdFuncGenerateWfdIEForAssocRsp */ ++ ++VOID p2pFuncComposeNoaAttribute(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ ++ P_IE_P2P_T prIeP2P; ++ P_P2P_ATTRI_NOA_T prNoaAttr = NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; ++ P_NOA_DESCRIPTOR_T prNoaDesc = NULL; ++ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; ++ UINT_32 u4AttributeLen; ++ UINT_32 u4NumOfNoaDesc = 0; ++ UINT_32 i = 0; ++ /*P2P IE format */ ++ prIeP2P = (P_IE_P2P_T) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ prIeP2P->ucId = ELEM_ID_P2P; ++ prIeP2P->aucOui[0] = aucWfaOui[0]; ++ prIeP2P->aucOui[1] = aucWfaOui[1]; ++ prIeP2P->aucOui[2] = aucWfaOui[2]; ++ prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ /*P2P Attribute--NoA */ ++ prNoaAttr = (P_P2P_ATTRI_NOA_T) prIeP2P->aucP2PAttributes; ++ ++ prNoaAttr->ucId = P2P_ATTRI_ID_NOTICE_OF_ABSENCE; ++ prNoaAttr->ucIndex = prP2pSpecificBssInfo->ucNoAIndex; ++ /*OPP*/ if (prP2pSpecificBssInfo->fgEnableOppPS) { ++ prNoaAttr->ucCTWOppPSParam = P2P_CTW_OPPPS_PARAM_OPPPS_FIELD | ++ (prP2pSpecificBssInfo->u2CTWindow & P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK); ++ } else { ++ prNoaAttr->ucCTWOppPSParam = 0; ++ } ++ /*NoA Description */ ++ DBGLOG(P2P, INFO, "Compose NoA count=%d.\n", prP2pSpecificBssInfo->ucNoATimingCount); ++ for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { ++ if (prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse) { ++ ++ prNoaDesc = (P_NOA_DESCRIPTOR_T) &prNoaAttr->aucNoADesc[u4NumOfNoaDesc]; ++ ++ prNoaDesc->ucCountType = prP2pSpecificBssInfo->arNoATiming[i].ucCount; ++ prNoaDesc->u4Duration = prP2pSpecificBssInfo->arNoATiming[i].u4Duration; ++ prNoaDesc->u4Interval = prP2pSpecificBssInfo->arNoATiming[i].u4Interval; ++ prNoaDesc->u4StartTime = prP2pSpecificBssInfo->arNoATiming[i].u4StartTime; ++ ++ u4NumOfNoaDesc++; ++ } ++ } ++ ++ /* include "index" + "OppPs Params" + "NOA descriptors" */ ++ prNoaAttr->u2Length = 2 + u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T); ++ u4NumOfNoaDesc++; ++ ++ /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ ++ u4AttributeLen = P2P_ATTRI_HDR_LEN + prNoaAttr->u2Length; ++ ++ prIeP2P->ucLength = VENDOR_OUI_TYPE_LEN + u4AttributeLen; ++ prMsduInfo->u2FrameLength += (ELEM_HDR_LEN + prIeP2P->ucLength); ++ ++} ++ ++UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec) ++{ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; ++ UINT_8 ucIdx; ++ UINT_32 u4NumOfNoaDesc = 0; ++ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) ++ return 0; ++ ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ for (ucIdx = 0; ucIdx < prP2pSpecificBssInfo->ucNoATimingCount; ucIdx++) { ++ if (prP2pSpecificBssInfo->arNoATiming[ucIdx].fgIsInUse) ++ u4NumOfNoaDesc++; ++ } ++ ++ /* include "index" + "OppPs Params" + "NOA descriptors" */ ++ /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ ++ ++ return P2P_ATTRI_LEN_NOTICE_OF_ABSENCE + (u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T)); ++} ++ ++VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { /* Hotspot */ ++ return; ++ } ++ ++ /* Compose NoA attribute */ ++ p2pFuncComposeNoaAttribute(prAdapter, ++ prMsduInfo /*prMsduInfo->ucBssIndex, prIeP2P->aucP2PAttributes, &u4AttributeLen */); ++ ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c +new file mode 100644 +index 000000000000..f25df82d9ca7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c +@@ -0,0 +1,905 @@ ++/* ++** Id: @(#) p2p_rlm.c@@ ++*/ ++ ++/*! \file "p2p_rlm.c" ++ \brief ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init AP Bss ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ENUM_BAND_T eBand; ++ UINT_8 ucChannel; ++ ENUM_CHNL_EXT_T eSCO; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ return; ++ ++ /* Operation band, channel shall be ready before invoking this function. ++ * Bandwidth may be ready if other network is connected ++ */ ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ prBssInfo->eBssSCO = CHNL_EXT_SCN; ++ ++ if (RLM_AP_IS_BW_40_ALLOWED(prAdapter, prBssInfo)) { ++ /* In this case, the first BSS's SCO is 40MHz and known, so AP can ++ * apply 40MHz bandwidth, but the first BSS's SCO may be changed ++ * later if its Beacon lost timeout occurs ++ */ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) && ++ eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel && eBand == prBssInfo->eBand) { ++ prBssInfo->eBssSCO = eSCO; ++ } else if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex)) { ++ prBssInfo->eBssSCO = rlmDecideScoForAP(prAdapter, prBssInfo); ++ } ++ ++ if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ prBssInfo->fg40mBwAllowed = TRUE; ++ prBssInfo->fgAssoc40mBwAllowed = TRUE; ++ ++ prBssInfo->ucHtOpInfo1 = (UINT_8) ++ (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); ++ ++ rlmUpdateBwByChListForAP(prAdapter, prBssInfo); ++ } ++ } ++ ++ DBGLOG(RLM, INFO, "WLAN AP SCO=%d\n", prBssInfo->eBssSCO); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_IE_OBSS_SCAN_PARAM_T prObssScanIe; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && !RLM_NET_IS_BOW(prBssInfo) && ++ prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) && ++ prBssInfo->eBand == BAND_2G4 && prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ ++ prObssScanIe = (P_IE_OBSS_SCAN_PARAM_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add 20/40 BSS coexistence IE */ ++ prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS; ++ prObssScanIe->ucLength = sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN; ++ ++ prObssScanIe->u2ScanPassiveDwell = dot11OBSSScanPassiveDwell; ++ prObssScanIe->u2ScanActiveDwell = dot11OBSSScanActiveDwell; ++ prObssScanIe->u2TriggerScanInterval = dot11BSSWidthTriggerScanInterval; ++ prObssScanIe->u2ScanPassiveTotalPerChnl = dot11OBSSScanPassiveTotalPerChannel; ++ prObssScanIe->u2ScanActiveTotalPerChnl = dot11OBSSScanActiveTotalPerChannel; ++ prObssScanIe->u2WidthTransDelayFactor = dot11BSSWidthChannelTransitionDelayFactor; ++ prObssScanIe->u2ScanActivityThres = dot11OBSSScanActivityThreshold; ++ ++ ASSERT(IE_SIZE(prObssScanIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P GO. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ UINT_8 ucLevel; ++ BOOLEAN fgBwChange; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ fgBwChange = FALSE; ++ ++ if (prBssInfo->eBssSCO == CHNL_EXT_SCN) ++ return fgBwChange; ++ ++ ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO); ++ ++ if (ucLevel == CHNL_LEVEL0) { ++ /* Forced to 20MHz, so extended channel is SCN and STA width is zero */ ++ prBssInfo->fgObssActionForcedTo20M = TRUE; ++ ++ if (prBssInfo->ucHtOpInfo1 != (UINT_8) CHNL_EXT_SCN) { ++ prBssInfo->ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; ++ fgBwChange = TRUE; ++ } ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, OBSS_20_40M_TIMEOUT * MSEC_PER_SEC); ++ } ++ ++ /* Clear up all channel lists */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ prBssInfo->auc2G_PriChnlList[0] = 0; ++ prBssInfo->auc2G_SecChnlList[0] = 0; ++ prBssInfo->auc5G_20mReqChnlList[0] = 0; ++ prBssInfo->auc5G_NonHtChnlList[0] = 0; ++ prBssInfo->auc5G_PriChnlList[0] = 0; ++ prBssInfo->auc5G_SecChnlList[0] = 0; ++ ++ return fgBwChange; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_20_40_COEXIST_FRAME prRxFrame; ++ P_IE_20_40_COEXIST_T prCoexist; ++ P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport; ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ PUINT_8 pucIE; ++ UINT_16 u2IELength, u2Offset; ++ UINT_8 i, j; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || ++ !prStaRec || prStaRec->ucStaState != STA_STATE_3 || ++ prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || ++ HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != NETWORK_TYPE_P2P_INDEX) { ++ return; ++ } ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ASSERT(prBssInfo); ++ ++ if (!IS_BSS_ACTIVE(prBssInfo) || ++ prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || prBssInfo->eBssSCO == CHNL_EXT_SCN) { ++ return; ++ } ++ ++ prCoexist = &prRxFrame->rBssCoexist; ++ if (prCoexist->ucData & (BSS_COEXIST_40M_INTOLERANT | BSS_COEXIST_20M_REQ)) { ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_20mReqChnlList[i] == prBssInfo->ucPrimaryChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_20mReqChnlList[i] = prBssInfo->ucPrimaryChannel; ++ prBssInfo->auc2G_20mReqChnlList[0]++; ++ } ++ } ++ ++ /* Process intolerant channel report IE */ ++ pucIE = (PUINT_8) &prRxFrame->rChnlReport; ++ u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5); ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT: ++ prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T) pucIE; ++ ++ if (prChnlReport->ucLength <= 1) ++ break; ++ ++ /* To do: process regulatory class. Now we assume 2.4G band */ ++ ++ for (j = 0; j < prChnlReport->ucLength - 1; j++) { ++ /* Update non-HT channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_NonHtChnlList[i] == prChnlReport->aucChannelList[j]) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_NonHtChnlList[i] = prChnlReport->aucChannelList[j]; ++ prBssInfo->auc2G_NonHtChnlList[0]++; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } /* end of IE_FOR_EACH */ ++ ++ if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) { ++ bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ } ++ ++ /* Check if OBSS scan exemption response should be sent */ ++ if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ) ++ rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_NOTIFY_CHNL_WIDTH_FRAME prRxFrame; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_ACTION_NOTIFY_CHNL_WIDTH_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prRxFrame->ucAction != ACTION_HT_NOTIFY_CHANNEL_WIDTH || ++ !prStaRec || prStaRec->ucStaState != STA_STATE_3 || ++ prSwRfb->u2PacketLen < sizeof(ACTION_NOTIFY_CHNL_WIDTH_FRAME)) { ++ return; ++ } ++ ++ /* To do: depending regulation class 13 and 14 based on spec ++ * Note: (ucChannelWidth==1) shall restored back to original capability, ++ * not current setting to 40MHz BW here ++ */ ++ if (prRxFrame->ucChannelWidth == 0) ++ prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; ++ else if (prRxFrame->ucChannelWidth == 1) ++ prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prObssStatus); ++ ASSERT(prObssStatus->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prObssStatus->ucNetTypeIndex]; ++ ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); ++ ++ prBssInfo->fgObssErpProtectMode = (BOOLEAN) prObssStatus->ucObssErpProtectMode; ++ prBssInfo->eObssHtProtectMode = (ENUM_HT_PROTECT_MODE_T) prObssStatus->ucObssHtProtectMode; ++ prBssInfo->eObssGfOperationMode = (ENUM_GF_MODE_T) prObssStatus->ucObssGfOperationMode; ++ prBssInfo->fgObssRifsOperationMode = (BOOLEAN) prObssStatus->ucObssRifsOperationMode; ++ prBssInfo->fgObssBeaconForcedTo20M = (BOOLEAN) prObssStatus->ucObssBeaconForcedTo20M; ++ ++ /* Check if Beacon content need to be updated */ ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, TRUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon) ++{ ++ P_LINK_T prStaList; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fgErpProtectMode, fgSta40mIntolerant; ++ BOOLEAN fgUseShortPreamble, fgUseShortSlotTime; ++ ENUM_HT_PROTECT_MODE_T eHtProtectMode; ++ ENUM_GF_MODE_T eGfOperationMode; ++ UINT_8 ucHtOpInfo1; ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ P_GLUE_INFO_T prGlueInfo; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ if (!IS_BSS_ACTIVE(prBssInfo) || prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) ++ return; ++ ++ fgErpProtectMode = FALSE; ++ eHtProtectMode = HT_PROTECT_MODE_NONE; ++ eGfOperationMode = GF_MODE_NORMAL; ++ fgSta40mIntolerant = FALSE; ++ fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; ++ fgUseShortSlotTime = TRUE; ++ ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; ++ ++ prStaList = &prBssInfo->rStaRecOfClientList; ++ ++ LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) { ++ /* ASSERT(prStaRec); */ ++ if (!prStaRec) { ++ DBGLOG(P2P, TRACE, "prStaRec is NULL in rlmUpdateParamsForAP()\n"); ++ break; ++ } ++ if (prStaRec->fgIsInUse && prStaRec->ucStaState == STA_STATE_3 && ++ prStaRec->ucNetTypeIndex == prBssInfo->ucNetTypeIndex) { ++ if (!(prStaRec->ucPhyTypeSet & (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) { ++ /* B-only mode, so mode 1 (ERP protection) */ ++ fgErpProtectMode = TRUE; ++ } ++ ++ if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ /* BG-only or A-only */ ++ eHtProtectMode = HT_PROTECT_MODE_NON_HT; ++ } else if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { ++ /* 20MHz-only */ ++ /* ++ The HT Protection field may be set to 20 MHz protection ++ mode only if the following are true: ++ \A1X All STAs detected (by any means) in the primary channel ++ and all STAs detected (by any means) in the secondary ++ channel are HT STAs and all STAs that are members of ++ this BSS are HT STAs, and ++ \A1X This BSS is a 20/40 MHz BSS, and ++ \A1X There is at least one 20 MHz HT STA associated with this BSS. ++ */ ++ if (eHtProtectMode == HT_PROTECT_MODE_NONE && prBssInfo->fgAssoc40mBwAllowed) ++ eHtProtectMode = HT_PROTECT_MODE_20M; ++ } ++ ++ if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF)) ++ eGfOperationMode = GF_MODE_PROTECT; ++ ++ if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) ++ fgUseShortPreamble = FALSE; ++ ++ if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) ++ fgUseShortSlotTime = FALSE; ++ ++ if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) ++ fgSta40mIntolerant = TRUE; ++ } ++ } /* end of LINK_FOR_EACH_ENTRY */ ++ ++ /* Check if HT operation IE about 20/40M bandwidth shall be updated */ ++ if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { ++ if (/*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant && ++ !prBssInfo->fgObssActionForcedTo20M && !prBssInfo->fgObssBeaconForcedTo20M) { ++ ++ ucHtOpInfo1 = (UINT_8) ++ (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); ++ } ++ } ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ prGlueInfo = prAdapter->prGlueInfo; ++ if (prGlueInfo->prP2PInfo->u4PsLevel & BITS(8, 15)) ++ fgErpProtectMode = TRUE; ++#endif ++ ++ /* Check if any new parameter may be updated */ ++ if (prBssInfo->fgErpProtectMode != fgErpProtectMode || ++ prBssInfo->eHtProtectMode != eHtProtectMode || ++ prBssInfo->eGfOperationMode != eGfOperationMode || ++ prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 || ++ prBssInfo->fgUseShortPreamble != fgUseShortPreamble || ++ prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) { ++ ++ prBssInfo->fgErpProtectMode = fgErpProtectMode; ++ prBssInfo->eHtProtectMode = eHtProtectMode; ++ prBssInfo->eGfOperationMode = eGfOperationMode; ++ prBssInfo->ucHtOpInfo1 = ucHtOpInfo1; ++ prBssInfo->fgUseShortPreamble = fgUseShortPreamble; ++ prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime; ++ ++ if (fgUseShortSlotTime) ++ prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; ++ else ++ prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; ++ ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ fgUpdateBeacon = TRUE; ++ } ++ ++ /* Update Beacon content if related IE content is changed */ ++ if (fgUpdateBeacon) ++ bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initial the channel list from the domain information. ++* This function is called after P2P initial and Domain information changed. ++* Make sure the device is disconnected while changing domain information. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_DOMAIN_INFO_ENTRY prDomainInfoEntry = (P_DOMAIN_INFO_ENTRY) NULL; ++ P_DOMAIN_SUBBAND_INFO prDomainSubBand = (P_DOMAIN_SUBBAND_INFO) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_32 u4Idx = 0, u4IdxII = 0; ++ UINT_8 ucBufferSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE; ++#if 0 ++ UINT_8 ucSocialChnlSupport = 0, ucAutoChnl = 0; ++#endif ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++#if 0 ++ ucAutoChnl = prP2pConnSetting->ucOperatingChnl; ++#endif ++ ++ prDomainInfoEntry = rlmDomainGetDomainInfo(prAdapter); ++ ++ ASSERT_BREAK((prDomainInfoEntry != NULL) && (prP2pConnSetting != NULL)); ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ for (u4Idx = 0; u4Idx < MAX_SUBBAND_NUM; u4Idx++) { ++ prDomainSubBand = &prDomainInfoEntry->rSubBand[u4Idx]; ++ ++ if (((prDomainSubBand->ucBand == BAND_5G) && (!prAdapter->fgEnable5GBand)) || ++ (prDomainSubBand->ucBand == BAND_NULL)) { ++ continue; ++ } ++ ++ if (ucBufferSize < (P2P_ATTRI_LEN_CHANNEL_ENTRY + prDomainSubBand->ucNumChannels)) { ++ /* Buffer is not enough to include all supported channels. */ ++ break; /* for */ ++ } ++ ++ prChannelEntryField->ucRegulatoryClass = prDomainSubBand->ucRegClass; ++ prChannelEntryField->ucNumberOfChannels = prDomainSubBand->ucNumChannels; ++ ++ for (u4IdxII = 0; u4IdxII < prDomainSubBand->ucNumChannels; u4IdxII++) { ++ prChannelEntryField->aucChannelList[u4IdxII] = prDomainSubBand->ucFirstChannelNum + ++ (u4IdxII * prDomainSubBand->ucChannelSpan); ++ ++#if 0 ++ switch (prChannelEntryField->aucChannelList[u4IdxII]) { ++ case 1: ++ ucSocialChnlSupport = 1; ++ break; ++ case 6: ++ ucSocialChnlSupport = 6; ++ break; ++ case 11: ++ ucSocialChnlSupport = 11; ++ break; ++ default: ++ break; ++ } ++ ++#endif ++ } ++ ++ if (ucBufferSize >= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels)) ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ else ++ break; ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) ++ prChannelEntryField->ucNumberOfChannels); ++ ++ } ++ ++#if 0 ++ if (prP2pConnSetting->ucListenChnl == 0) { ++ prP2pConnSetting->ucListenChnl = P2P_DEFAULT_LISTEN_CHANNEL; ++ ++ if (ucSocialChnlSupport != 0) { ++ /* 1. User Not Set LISTEN channel. ++ * 2. Social channel is not empty. ++ */ ++ prP2pConnSetting->ucListenChnl = ucSocialChnlSupport; ++ } ++ } ++#endif ++ ++ /* TODO: 20110921 frog - */ ++ /* If LISTEN channel is not set, ++ * a random supported channel would be set. ++ * If no social channel is supported, DEFAULT channel would be set. ++ */ ++ ++ prP2pConnSetting->ucRfChannelListSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE - ucBufferSize; ++ ++#if 0 ++ if (prP2pConnSetting->ucOperatingChnl == 0) { /* User not set OPERATE channel. */ ++ ++ if (scnQuerySparseChannel(prAdapter, NULL, &ucAutoChnl)) ++ break; /* while */ ++ ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while (ucBufferSize != 0) { ++ if (prChannelEntryField->ucNumberOfChannels != 0) { ++ ucAutoChnl = prChannelEntryField->aucChannelList[0]; ++ break; /* while */ ++ } ++ ++ else { ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((UINT_32) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (UINT_32)prChannelEntryField->ucNumberOfChannels); ++ ++ ucBufferSize -= ++ (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ } ++ ++ } ++ ++ } ++#endif ++ /* We assume user would not set a channel not in the channel list. ++ * If so, the operating channel still depends on target device supporting capability. ++ */ ++ ++ /* TODO: 20110921 frog - */ ++ /* If the Operating channel is not set, a channel from supported channel list is set automatically. ++ * If there is no supported channel in channel list, a DEFAULT channel is set. ++ */ ++ ++ } while (FALSE); ++ ++#if 0 ++ prP2pConnSetting->ucOperatingChnl = ucAutoChnl; ++#endif ++ ++} /* rlmFuncInitialChannelList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find a common channel list from the local channel list info & target channel list info. ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return boolean value if probe response frame is ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, ++ IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize) ++{ ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) NULL, prChannelEntryIII = ++ (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_8 aucCommonChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE] = {0}; ++ UINT_8 ucOriChnlSize = 0, ucNewChnlSize = 0; ++ ++ do { ++ ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) aucCommonChannelList; ++ ++ while (ucChannelListSize > 0) { ++ ++ prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ucOriChnlSize = prP2pConnSetting->ucRfChannelListSize; ++ ++ while (ucOriChnlSize > 0) { ++ if (prChannelEntryI->ucRegulatoryClass == prChannelEntryII->ucRegulatoryClass) { ++ prChannelEntryIII->ucRegulatoryClass = prChannelEntryI->ucRegulatoryClass; ++ /* TODO: Currently we assume that the regulatory class the same, ++ * the channels are the same. */ ++ kalMemCopy(prChannelEntryIII->aucChannelList, prChannelEntryII->aucChannelList, ++ prChannelEntryII->ucNumberOfChannels); ++ prChannelEntryIII->ucNumberOfChannels = prChannelEntryII->ucNumberOfChannels; ++ ++ ucNewChnlSize += ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryIII->ucNumberOfChannels; ++ ++ prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryIII + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG)prChannelEntryIII->ucNumberOfChannels); ++ } ++ ++ ucOriChnlSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryI->ucNumberOfChannels); ++ ++ prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryI + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) ++ prChannelEntryI->ucNumberOfChannels); ++ ++ } ++ ++ ucChannelListSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryII->ucNumberOfChannels); ++ ++ prChannelEntryII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryII + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) prChannelEntryII->ucNumberOfChannels); ++ ++ } ++ ++ kalMemCopy(prP2pConnSetting->aucChannelEntriesField, aucCommonChannelList, ucNewChnlSize); ++ prP2pConnSetting->ucRfChannelListSize = ucNewChnlSize; ++ ++ } while (FALSE); ++ ++} /* rlmFuncCommonChannelList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum) ++{ ++ UINT_8 ucRegulatoryClass = 0, ucBufferSize = 0; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ UINT_32 u4Idx = 0; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while (ucBufferSize != 0) { ++ ++ for (u4Idx = 0; u4Idx < prChannelEntryField->ucNumberOfChannels; u4Idx++) { ++ if (prChannelEntryField->aucChannelList[u4Idx] == ucChannelNum) { ++ ucRegulatoryClass = prChannelEntryField->ucRegulatoryClass; ++ break; ++ } ++ ++ } ++ ++ if (ucRegulatoryClass != 0) ++ break; /* while */ ++ ++ prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG)prChannelEntryField->ucNumberOfChannels); ++ ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); ++ ++ } ++ ++ } while (FALSE); ++ ++ return ucRegulatoryClass; ++} /* rlmFuncFindOperatingClass */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucCheckChnl, ++ IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel) ++{ ++ BOOLEAN fgIsResultAvailable = FALSE; ++ P_CHANNEL_ENTRY_FIELD_T prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_8 ucBufferSize = 0, ucIdx = 0, ucChannelSelected = 0; ++ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ if (fgIsDefaultChannel) ++ ucChannelSelected = P2P_DEFAULT_LISTEN_CHANNEL; ++ ++ prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; ++ ucBufferSize = prP2pConnSetting->ucRfChannelListSize; ++ prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; ++ ++ while ((ucBufferSize != 0) && (!fgIsResultAvailable)) { ++ ++ for (ucIdx = 0; ucIdx < prChannelEntry->ucNumberOfChannels; ucIdx++) { ++ if ((!fgIsSocialChannel) || ++ (prChannelEntry->aucChannelList[ucIdx] == 1) || ++ (prChannelEntry->aucChannelList[ucIdx] == 6) || ++ (prChannelEntry->aucChannelList[ucIdx] == 11)) { ++ ++ if (prChannelEntry->aucChannelList[ucIdx] <= 11) { ++ /* 2.4G. */ ++ ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; ++ } else if ((prChannelEntry->aucChannelList[ucIdx] < 52) && ++ (prChannelEntry->aucChannelList[ucIdx] > 14)) { ++ /* 2.4G + 5G. */ ++ ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; ++ } ++ ++ if (ucChannelSelected == ucCheckChnl) { ++ fgIsResultAvailable = TRUE; ++ break; ++ } ++ } ++ ++ } ++ ++ ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntry->ucNumberOfChannels); ++ ++ prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntry + ++ P2P_ATTRI_LEN_CHANNEL_ENTRY + ++ (ULONG) prChannelEntry->ucNumberOfChannels); ++ ++ } ++ ++ if ((!fgIsResultAvailable) && (pucSuggestChannel != NULL)) { ++ DBGLOG(P2P, TRACE, ++ "The request channel %d is not available, sugguested channel:%d\n", ucCheckChnl, ++ ucChannelSelected); ++ /* Given a suggested channel. */ ++ *pucSuggestChannel = ucChannelSelected; ++ } ++ ++ } while (FALSE); ++ ++ return fgIsResultAvailable; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ UINT_8 ucSecondChannel, i, j; ++ ENUM_CHNL_EXT_T eSCO; ++ ++ eSCO = CHNL_EXT_SCN; ++ ++ if (prBssInfo->eBand == BAND_2G4) { ++ if (prBssInfo->ucPrimaryChannel != 14) ++ eSCO = (prBssInfo->ucPrimaryChannel > 7) ? CHNL_EXT_SCB : CHNL_EXT_SCA; ++ } else { ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ if (prSubband->ucBand == prBssInfo->eBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) ++ == prBssInfo->ucPrimaryChannel) { ++ eSCO = (j & 1) ? CHNL_EXT_SCB : CHNL_EXT_SCA; ++ break; ++ } ++ } ++ ++ if (j < prSubband->ucNumChannels) ++ break; /* Found */ ++ } ++ } ++ } ++ ++ /* Check if it is boundary channel and 40MHz BW is permitted */ ++ if (eSCO != CHNL_EXT_SCN) { ++ ucSecondChannel = (eSCO == CHNL_EXT_SCA) ? ++ (prBssInfo->ucPrimaryChannel + 4) : (prBssInfo->ucPrimaryChannel - 4); ++ ++ if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel)) ++ eSCO = CHNL_EXT_SCN; ++ } ++ ++ return eSCO; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c +new file mode 100644 +index 000000000000..154f1e5db0f7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c +@@ -0,0 +1,313 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_cfg80211.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ using cfg80211 interface ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Different concurrent network has itself channel lists, and ++* concurrent networks should have been recorded in channel lists. ++* If role of active P2P is GO, assume associated AP of AIS will ++* record our Beacon for P2P GO because of same channel. ++* ++* Note: If we have scenario of different channel in the future, ++* the internal FW communication channel shall be established. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 ucChannelLevel; ++ ++ ASSERT(prBssInfo); ++ ++ if (eBand == BAND_2G4) { ++ ucChannelLevel = rlmObssChnlLevelIn2G4(prBssInfo, ucPriChannel, eExtend); ++ ++ /* (TBD) If concurrent networks permit different channel, extra ++ * channel judgement should be added. Please refer to ++ * previous version of this file. ++ */ ++ } else if (eBand == BAND_5G) { ++ ucChannelLevel = rlmObssChnlLevelIn5G(prBssInfo, ucPriChannel, eExtend); ++ ++ /* (TBD) If concurrent networks permit different channel, extra ++ * channel judgement should be added. Please refer to ++ * previous version of this file. ++ */ ++ } else { ++ ucChannelLevel = CHNL_LEVEL0; ++ } ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 i, ucChannelLevel; ++ UINT_8 ucSecChannel, ucCenterChannel; ++ UINT_8 ucAffectedChnl_L, ucAffectedChnl_H; ++ ++ ASSERT(prBssInfo); ++ ++ ucChannelLevel = CHNL_LEVEL2; ++ ++ /* Calculate center channel for 2.4G band */ ++ if (eExtend == CHNL_EXT_SCA) { ++ ucCenterChannel = ucPriChannel + 2; ++ ucSecChannel = ucPriChannel + 4; ++ } else if (eExtend == CHNL_EXT_SCB) { ++ ucCenterChannel = ucPriChannel - 2; ++ ucSecChannel = ucPriChannel - 4; ++ } else { ++ return CHNL_LEVEL0; ++ } ++ ASSERT(ucCenterChannel >= 1 && ucCenterChannel <= 14); ++ ++ /* Calculated low/upper channels in affected freq range */ ++ ucAffectedChnl_L = (ucCenterChannel <= AFFECTED_CHNL_OFFSET) ? 1 : (ucCenterChannel - AFFECTED_CHNL_OFFSET); ++ ++ ucAffectedChnl_H = (ucCenterChannel >= (14 - AFFECTED_CHNL_OFFSET)) ? ++ 14 : (ucCenterChannel + AFFECTED_CHNL_OFFSET); ++ ++ /* Check intolerant (Non-HT) channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_NonHtChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_NonHtChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_NonHtChnlList[i] != ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 20M BW request channel list */ ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_20mReqChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_20mReqChnlList[i] <= ucAffectedChnl_H)) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 2.4G primary channel list */ ++ ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_PriChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_PriChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_PriChnlList[i] != ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++ /* Check 2.4G secondary channel list */ ++ ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if ((prBssInfo->auc2G_SecChnlList[i] >= ucAffectedChnl_L && ++ prBssInfo->auc2G_SecChnlList[i] <= ucAffectedChnl_H) && ++ prBssInfo->auc2G_SecChnlList[i] != ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_2G4_level_end; ++ } ++ } ++ ++L_2G4_level_end: ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 i, ucChannelLevel; ++ UINT_8 ucSecChannel; ++ ++ ASSERT(prBssInfo); ++ ++ ucChannelLevel = CHNL_LEVEL2; ++ ++ /* Calculate center channel for 2.4G band */ ++ if (eExtend == CHNL_EXT_SCA) ++ ucSecChannel = ucPriChannel + 4; ++ else if (eExtend == CHNL_EXT_SCB) ++ ucSecChannel = ucPriChannel - 4; ++ else ++ return CHNL_LEVEL0; ++ ASSERT(ucSecChannel >= 36); ++ ++ /* Check 5G primary channel list */ ++ ASSERT(prBssInfo->auc5G_PriChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_PriChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_PriChnlList[i] == ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } else if (prBssInfo->auc5G_PriChnlList[i] == ucPriChannel) { ++ ucChannelLevel = CHNL_LEVEL1; ++ } ++ } ++ ++ /* Check non-HT channel list */ ++ ASSERT(prBssInfo->auc5G_NonHtChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_NonHtChnlList[i] == ucSecChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } else if (prBssInfo->auc5G_NonHtChnlList[i] == ucPriChannel) { ++ ucChannelLevel = CHNL_LEVEL1; ++ } ++ } ++ ++ /* Check secondary channel list */ ++ ASSERT(prBssInfo->auc5G_SecChnlList[0] <= CHNL_LIST_SZ_5G); ++ for (i = 1; i <= prBssInfo->auc5G_SecChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { ++ if (prBssInfo->auc5G_SecChnlList[i] == ucPriChannel) { ++ ++ ucChannelLevel = CHNL_LEVEL0; ++ goto L_5G_level_end; ++ } ++ } ++ ++L_5G_level_end: ++ ++ return ucChannelLevel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_20_40_COEXIST_FRAME prTxFrame; ++ ++ /* To do: need an algorithm to do judgement. Now always reject request */ ++ ++ prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); ++ if (prMsduInfo == NULL) ++ return; ++ ++ DBGLOG(RLM, INFO, "Send 20/40 coexistence rsp frame!\n"); ++ ++ prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) prMsduInfo->prPacket; ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, ((P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader)->aucSrcAddr); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; ++ prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; ++ ++ /* To do: find correct algorithm */ ++ prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ prTxFrame->rBssCoexist.ucLength = 1; ++ prTxFrame->rBssCoexist.ucData = 0; ++ ++ ASSERT((WLAN_MAC_HEADER_LEN + 5) <= PUBLIC_ACTION_MAX_LEN); ++ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfo->ucStaRecIndex = prSwRfb->ucStaRecIdx; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_HTC_LEN + 5; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* Send them to HW queue */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c +new file mode 100644 +index 000000000000..b5bd23965fe3 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c +@@ -0,0 +1,756 @@ ++/* ++** Id: @(#) p2p_scan.c@@ ++*/ ++ ++/*! \file "p2p_scan.c" ++ \brief This file defines the p2p scan profile and the processing function of ++ scan result for SCAN Module. ++ ++ The SCAN Profile selection is part of SCAN MODULE and responsible for defining ++ SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. ++ In this file we also define the process of SCAN Result including adding, searching ++ and removing SCAN record from the list. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++P_P2P_DEVICE_DESC_T ++scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucDeviceID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* 4 <1> The outer loop to search for a candidate. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ /* Loop for each prBssDesc */ ++ prTargetP2pDesc = scanFindP2pDeviceDesc(prAdapter, prBssDesc, aucDeviceID, TRUE, FALSE); ++ ++ if (prTargetP2pDesc != NULL) ++ break; ++ } ++ ++ if ((pprBssDesc) && (prTargetP2pDesc != NULL)) { ++ /* Only valid if prTargetP2pDesc is not NULL. */ ++ *pprBssDesc = prBssDesc; ++ } ++ ++ return prTargetP2pDesc; ++} /* scanSearchTargetP2pDesc */ ++ ++VOID scanInvalidAllP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (prTargetDesc->fgDevInfoValid) ++ prTargetDesc->fgDevInfoValid = FALSE; ++ } ++ ++} /* scanRenewP2pClientDevice */ ++ ++VOID scanRemoveInvalidP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL, prNexEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ LINK_FOR_EACH_SAFE(prLinkEntry, prNexEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (!prTargetDesc->fgDevInfoValid) { ++ LINK_REMOVE_KNOWN_ENTRY(&prBssDesc->rP2pDeviceList, prLinkEntry); ++ if ((prP2pConnSettings) && (prP2pConnSettings->prTargetP2pDesc == prTargetDesc)) ++ prP2pConnSettings->prTargetP2pDesc = NULL; ++ kalMemFree(prTargetDesc, VIR_MEM_TYPE, sizeof(P2P_DEVICE_DESC_T)); ++ } ++ } ++ ++} /* scanRenewP2pClientDevice */ ++ ++P_P2P_DEVICE_DESC_T ++scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, ++ IN P_BSS_DESC_T prBssDesc, ++ IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prBssDesc != NULL) && (aucMacAddr != NULL)); ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ if (fgIsDeviceAddr) { ++ if (EQUAL_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr)) ++ break; ++ } else { ++ if (EQUAL_MAC_ADDR(prTargetDesc->aucInterfaceAddr, aucMacAddr)) ++ break; ++ } ++ ++ prTargetDesc = NULL; ++ } ++ ++ if ((fgAddIfNoFound) && (prTargetDesc == NULL)) { ++ /* Target Not Found. */ ++ /* TODO: Use memory pool in the future. */ ++ prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); ++ ++ if (prTargetDesc) { ++ kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); ++ LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); ++ COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr); ++ LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); ++ prTargetDesc->fgDevInfoValid = TRUE; ++ } else { ++ ASSERT(FALSE); ++ } ++ } ++ ++ } while (FALSE); ++ ++ return prTargetDesc; ++} /* scanFindP2pDeviceDesc */ ++ ++P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssDesc); ++ ++ if (prBssDesc->prP2pDesc == NULL) { ++ ++ prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); ++ ++ if (prTargetDesc) { ++ kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); ++ LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); ++ LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); ++ prTargetDesc->fgDevInfoValid = TRUE; ++ prBssDesc->prP2pDesc = prTargetDesc; ++ /* We are not sure the SrcAddr is Device Address or Interface Address. */ ++ COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, prBssDesc->aucSrcAddr); ++ COPY_MAC_ADDR(prTargetDesc->aucInterfaceAddr, prBssDesc->aucSrcAddr); ++ } else { ++ ++ ASSERT(FALSE); ++ } ++ } else { ++ prTargetDesc = prBssDesc->prP2pDesc; ++ } ++ ++ return prTargetDesc; ++ ++} /* scanFindP2pDeviceDesc */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_P2P_DEVICE_DESC_T prP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; ++ UINT_16 u2AttributeLen = 0; ++ UINT_32 u4Idx = 0; ++ BOOLEAN fgUpdateDevInfo = FALSE; ++ ++ P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; ++ P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; ++ ++ ASSERT(prAdapter); ++ ++ prP2pDesc = scanGetP2pDeviceDesc(prAdapter, prBssDesc); ++ ++ if (!prP2pDesc) { ++ ASSERT(FALSE); ++ return fgUpdateDevInfo; ++ } ++ ++ p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, ++ &u2AttributeLen); ++ ++ while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { ++ switch (prP2pAttribute->ucId) { ++ case P2P_ATTRI_ID_P2P_CAPABILITY: /* Beacon, Probe Response */ ++ { ++ P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; ++ ++ prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; ++ ASSERT(prP2pAttriCapability->u2Length == 2); ++ ++ prP2pDesc->ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; ++ prP2pDesc->ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_ID: /* Beacon */ ++ { ++ P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; ++ ++ prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; ++ ASSERT(prP2pAttriDevID->u2Length == P2P_ATTRI_MAX_LEN_P2P_DEV_ID); ++ ++ kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_INFO: /* Probe Response */ ++ { ++ P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ UINT_16 u2NameLen = 0, u2Id = 0; ++ ++ fgUpdateDevInfo = TRUE; ++ ++ prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; ++ ++ kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevInfo->aucDevAddr, MAC_ADDR_LEN); ++ ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); ++ ++ prP2pDevType = &prP2pDesc->rPriDevType; ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ ++ ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= ++ P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ prP2pDesc->ucSecDevTypeNum = 0; ++ for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { ++ if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { ++ prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> ++ arSecondaryDevTypeListBE[u4Idx].u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> ++ arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ prP2pDesc->ucSecDevTypeNum++; ++ } ++ ++ } ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) ((PUINT_8) prP2pAttriDevInfo->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &u2NameLen); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Id, &u2Id); ++ ASSERT(u2Id == WPS_ATTRI_ID_DEVICE_NAME); ++ if (u2NameLen > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ u2NameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ prP2pDesc->u2NameLength = u2NameLen; ++ kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_GROUP_INFO: /* Probe Response */ ++ prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; ++ break; ++ case P2P_ATTRI_ID_NOTICE_OF_ABSENCE: ++ break; ++ case P2P_ATTRI_ID_EXT_LISTEN_TIMING: ++ /* TODO: Not implement yet. */ ++ /* ASSERT(FALSE); */ ++ break; ++ default: ++ break; ++ } ++ ++ u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); ++ ++ prP2pAttribute = ++ (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); ++ ++ } ++ ++ if (prP2pAttriGroupInfo != NULL) { ++ P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ scanInvalidAllP2pClientDevice(prAdapter, prBssDesc); ++ ++ /* GO/Device itself. */ ++ prP2pDesc->fgDevInfoValid = TRUE; ++ ++ prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) prP2pAttriGroupInfo->arClientDesc; ++ u2AttributeLen = prP2pAttriGroupInfo->u2Length; ++ ++ while (u2AttributeLen > 0) { ++ prP2pDesc = ++ scanFindP2pDeviceDesc(prAdapter, prBssDesc, prClientInfoDesc->aucDevAddr, TRUE, TRUE); ++ ++ if (!prP2pDesc) { ++ ASSERT(FALSE); ++ break; /* while */ ++ } ++ ++ prP2pDesc->fgDevInfoValid = TRUE; ++ ++ /* Basic size for P2P client info descriptor. */ ++ ASSERT(u2AttributeLen >= 25); ++ if (u2AttributeLen < 25) { ++ DBGLOG(P2P, WARN, "Length incorrect warning.\n"); ++ break; ++ } ++ COPY_MAC_ADDR(prP2pDesc->aucInterfaceAddr, prClientInfoDesc->aucIfAddr); ++ ++ prP2pDesc->ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; ++ ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); ++ ++ prP2pDevType = &(prP2pDesc->rPriDevType); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ ++ ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); ++ prP2pDesc->ucSecDevTypeNum = 0; ++ for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { ++ if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { ++ prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc-> ++ arSecondaryDevTypeListBE[u4Idx].u2CategoryId, ++ &prP2pDevType->u2CategoryID); ++ WLAN_GET_FIELD_BE16(&prClientInfoDesc-> ++ arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, ++ &prP2pDevType->u2SubCategoryID); ++ prP2pDesc->ucSecDevTypeNum++; ++ } ++ ++ } ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &prP2pDesc->u2NameLength); ++ if (prP2pDesc->u2NameLength > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ prP2pDesc->u2NameLength = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ ++ kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); ++ ++ u2AttributeLen -= (prClientInfoDesc->ucLength + P2P_CLIENT_INFO_DESC_HDR_LEN); ++ prClientInfoDesc = ++ (P_P2P_CLIENT_INFO_DESC_T) ((UINT_32) prClientInfoDesc + ++ (UINT_32) prClientInfoDesc->ucLength + ++ P2P_CLIENT_INFO_DESC_HDR_LEN); ++ } ++ ++ scanRemoveInvalidP2pClientDevice(prAdapter, prBssDesc); ++ } ++ ++ return fgUpdateDevInfo; ++} /* end of scanAddP2pDeviceInfo() */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) ++{ ++ EVENT_P2P_DEV_DISCOVER_RESULT_T rEventDevInfo; ++#if 1 ++ P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; ++ P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; ++ ++ LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { ++ prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); ++ ++ COPY_MAC_ADDR(rEventDevInfo.aucDeviceAddr, prTargetDesc->aucDeviceAddr); ++ COPY_MAC_ADDR(rEventDevInfo.aucInterfaceAddr, prTargetDesc->aucInterfaceAddr); ++ ++ rEventDevInfo.ucDeviceCapabilityBitmap = prTargetDesc->ucDeviceCapabilityBitmap; ++ rEventDevInfo.ucGroupCapabilityBitmap = prTargetDesc->ucGroupCapabilityBitmap; ++ rEventDevInfo.u2ConfigMethod = prTargetDesc->u2ConfigMethod; ++ ++ kalMemCopy(&rEventDevInfo.rPriDevType, &prTargetDesc->rPriDevType, sizeof(P2P_DEVICE_TYPE_T)); ++ ++ kalMemCopy(rEventDevInfo.arSecDevType, ++ prTargetDesc->arSecDevType, (prTargetDesc->ucSecDevTypeNum * sizeof(P2P_DEVICE_TYPE_T))); ++ ++ rEventDevInfo.ucSecDevTypeNum = prTargetDesc->ucSecDevTypeNum; ++ ++ rEventDevInfo.u2NameLength = prTargetDesc->u2NameLength; ++ kalMemCopy(rEventDevInfo.aucName, prTargetDesc->aucName, prTargetDesc->u2NameLength); ++ ++ COPY_MAC_ADDR(rEventDevInfo.aucBSSID, prBssDesc->aucBSSID); ++ ++ if (prTargetDesc == prBssDesc->prP2pDesc) ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo, prBssDesc->aucIEBuf, prBssDesc->u2IELength); ++ else ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo, NULL, 0); ++ } ++ ++ kalP2PIndicateFound(prAdapter->prGlueInfo); ++ ++#else ++ ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; ++ UINT_16 u2AttributeLen = 0; ++ UINT_32 u4Idx = 0; ++ P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; ++ P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; ++ ++ ASSERT(prAdapter); ++ ++ prP2pSpecificBssInfo = &prAdapter->rWifiVar.rP2pSpecificBssInfo; ++ ++#if 1 ++ p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, ++ &u2AttributeLen); ++#else ++ prP2pAttribute = (P_P2P_ATTRIBUTE_T) &prP2pSpecificBssInfo->aucAttributesCache[0]; ++ u2AttributeLen = prP2pSpecificBssInfo->u2AttributeLen; ++#endif ++ rEventDevInfo.fgDevInfoValid = FALSE; ++ ++ while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { ++ switch (prP2pAttribute->ucId) { ++ case P2P_ATTRI_ID_P2P_CAPABILITY: ++ { ++ P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; ++ ++ prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; ++ ASSERT(prP2pAttriCapability->u2Length == 2); ++ rEventDevInfo.ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; ++ rEventDevInfo.ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_ID: ++ { ++ P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; ++ ++ prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; ++ ASSERT(prP2pAttriDevID->u2Length == 6); ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_DEV_INFO: ++ { ++ P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; ++ rEventDevInfo.fgDevInfoValid = TRUE; ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevInfo->aucDevAddr, ++ MAC_ADDR_LEN); ++ rEventDevInfo.u2ConfigMethod = prP2pAttriDevInfo->u2ConfigMethodsBE; ++ ++ prP2pDevType = &rEventDevInfo.rPriDevType; ++ prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; ++ ++ ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= 2); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { ++ /* TODO: Current sub device type can only support 2. */ ++ prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; ++ prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = ++ prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; ++ } ++ ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prP2pAttriDevInfo->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ ASSERT(prP2pDevName->u2Id == 0x1011); ++ ASSERT(prP2pDevName->u2Length <= 32); ++ /* TODO: Fixme if device name length is longer than 32 bytes. */ ++ kalMemCopy(rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); ++ } ++ break; ++ case P2P_ATTRI_ID_P2P_GROUP_INFO: ++ prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; ++ break; ++ } ++ ++ u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); ++ ++ prP2pAttribute = ++ (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); ++ ++ } ++ ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo); ++ ++ if (prP2pAttriGroupInfo != NULL) { ++ P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; ++ P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; ++ ++ prClientInfoDesc = prP2pAttriGroupInfo->arClientDesc; ++ u2AttributeLen = prP2pAttriGroupInfo->u2Length; ++ ++ while (u2AttributeLen > 0) { ++ /* Basic size for P2P client info descriptor. */ ++ ASSERT(u2AttributeLen >= 25); ++ rEventDevInfo.fgDevInfoValid = TRUE; ++ kalMemCopy(rEventDevInfo.aucCommunicateAddr, prClientInfoDesc->aucIfAddr, MAC_ADDR_LEN); ++ rEventDevInfo.ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; ++ rEventDevInfo.u2ConfigMethod = prClientInfoDesc->u2ConfigMethodsBE; ++ ++ prP2pDevType = &rEventDevInfo.rPriDevType; ++ prP2pDevType->u2CategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId; ++ prP2pDevType->u2SubCategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId; ++ ++ ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= 2); ++ /* TODO: Fixme if secondary device type is more than 2. */ ++ for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { ++ /* TODO: Current sub device type can only support 2. */ ++ prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; ++ prP2pDevType->u2CategoryID = ++ prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2CategoryId; ++ prP2pDevType->u2SubCategoryID = ++ prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId; ++ } ++ ++ prP2pDevName = ++ (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + ++ (u4Idx * sizeof(DEVICE_TYPE_T))); ++ ASSERT(prP2pDevName->u2Id == 0x1011); ++ ASSERT(prP2pDevName->u2Length <= 32); ++ /* TODO: Fixme if device name length is longer than 32 bytes. */ ++ kalMemCopy(&rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); ++ ++ nicRxAddP2pDevice(prAdapter, &rEventDevInfo); ++ ++ u2AttributeLen -= prP2pAttriGroupInfo->u2Length; ++ prP2pAttriGroupInfo = prP2pAttriGroupInfo + prP2pAttriGroupInfo->u2Length + 1; ++ } ++ ++ } ++#endif ++ return WLAN_STATUS_SUCCESS; ++} /* scanSendDeviceDiscoverEvent */ ++ ++VOID ++scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, ++ IN P_WLAN_STATUS prStatus, ++ IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame) ++{ ++ BOOLEAN fgIsSkipThisBeacon; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ fgIsSkipThisBeacon = FALSE; ++ if (prBssDesc->fgIsP2PPresent) { ++ if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && /* P2P GC */ ++ (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && /* Connected */ ++ ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { /* TX Beacon */ ++ ++ fgIsSkipThisBeacon = TRUE; ++ } ++ ++ if ((!prP2pBssInfo->ucDTIMPeriod) && /* First time. */ ++ fgIsSkipThisBeacon && (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen))) { /* SSID Match */ ++ prP2pBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++ ++ do { ++ RF_CHANNEL_INFO_T rChannelInfo; ++ ++ ASSERT_BREAK((prSwRfb != NULL) && (prBssDesc != NULL)); ++ ++ if (((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) != MAC_FRAME_PROBE_RSP)) { ++ /* Only report Probe Response frame to supplicant. */ ++ /* Probe response collect much more information. */ ++ ++ if (fgIsSkipThisBeacon || prBssDesc->eBand == BAND_2G4) ++ break; ++ } ++ ++ rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; ++ rChannelInfo.eBand = prBssDesc->eBand; ++ prBssDesc->fgIsP2PReport = TRUE; ++ ++ DBGLOG(P2P, INFO, "indicate %s [%d]\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, ++ &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ } while (FALSE); ++ } ++} ++ ++VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum) ++{ ++ ++ CMD_SCAN_CANCEL rCmdScanCancel; ++ ++ /* send cancel message to firmware domain */ ++ rCmdScanCancel.ucSeqNum = ucScnSeqNum; ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_CANCEL, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8)&rCmdScanCancel, NULL, 0); ++ ++} /* scnEventReturnChannel */ ++ ++VOID scanRemoveAllP2pBssDesc(IN P_ADAPTER_T prAdapter) ++{ ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prBSSDescNext; ++ ++ ASSERT(prAdapter); ++ ++ prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ scanRemoveP2pBssDesc(prAdapter, prBssDesc); ++ } ++} /* scanRemoveAllP2pBssDesc */ ++ ++VOID scanRemoveP2pBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ ++ ++} /* scanRemoveP2pBssDesc */ ++ ++P_BSS_DESC_T ++scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo) ++{ ++ P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL, prBssDesc = (P_BSS_DESC_T) NULL; ++ P_LINK_T prBssDescList = (P_LINK_T) NULL; ++ ++ do { ++ if ((prAdapter == NULL) || (prP2pBssInfo == NULL) || (prConnReqInfo == NULL)) ++ break; ++ ++ prBssDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); ++ ++ DBGLOG(P2P, LOUD, "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); ++ DBGLOG(P2P, LOUD, "Connecting to SSID:%s, length:%d\n", ++ prConnReqInfo->rSsidStruct.aucSsid, prConnReqInfo->rSsidStruct.ucSsidLen); ++ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBssDescList, rLinkEntry, BSS_DESC_T) { ++ DBGLOG(P2P, LOUD, "Checking BSS: %pM\n", prBssDesc->aucBSSID); ++ ++ if (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) { ++ DBGLOG(P2P, LOUD, "Ignore mismatch BSS type.\n"); ++ continue; ++ } ++ ++ if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnReqInfo->aucBssid)) { ++ DBGLOG(P2P, LOUD, "Ignore mismatch BSSID.\n"); ++ continue; ++ } ++ ++ /* SSID should be the same? SSID is vary for each connection. so... */ ++ if (UNEQUAL_SSID(prConnReqInfo->rSsidStruct.aucSsid, ++ prConnReqInfo->rSsidStruct.ucSsidLen, ++ prBssDesc->aucSSID, prBssDesc->ucSSIDLen)) { ++ ++ DBGLOG(P2P, TRACE, ++ "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); ++ DBGLOG(P2P, TRACE, ++ "Connecting to SSID:%s, length:%d\n", prConnReqInfo->rSsidStruct.aucSsid, ++ prConnReqInfo->rSsidStruct.ucSsidLen); ++ DBGLOG(P2P, TRACE, ++ "Checking SSID:%s, length:%d\n", prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ DBGLOG(P2P, TRACE, "Ignore mismatch SSID, (But BSSID match).\n"); ++ ASSERT(FALSE); ++ continue; ++ } ++ ++ if (!prBssDesc->fgIsP2PPresent) { ++ DBGLOG(P2P, ERROR, "SSID, BSSID, BSSTYPE match, but no P2P IE present.\n"); ++ continue; ++ } ++ ++ /* Final decision. */ ++ prCandidateBssDesc = prBssDesc; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return prCandidateBssDesc; ++} /* scanP2pSearchDesc */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c +new file mode 100644 +index 000000000000..befb9978f473 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c +@@ -0,0 +1,466 @@ ++#include "p2p_precomp.h" ++ ++BOOLEAN ++p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState) ++{ ++ BOOLEAN fgIsTransOut = FALSE; ++/* P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; */ ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prP2pFsmInfo != NULL) && (prP2pBssInfo != NULL) && (peNextState != NULL)); ++ ++ if ((prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) ++ && IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ fgIsTransOut = TRUE; ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pStateInit_IDLE GO Scan\n"); ++ *peNextState = P2P_STATE_REQING_CHANNEL; ++ ++ } else { ++#if 0 ++ else ++ if (IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { ++ ++ ASSERT((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || ++ (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)); ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ /* Start a timer for return channel. */ ++ DBGLOG(P2P, TRACE, "start a GO channel timer.\n"); ++ } ++ ++ } ++#endif ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), 5000); ++ } ++ ++ } while (FALSE); ++ ++ return fgIsTransOut; ++} /* p2pStateInit_IDLE */ ++ ++VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; ++ ++ if (prChnlReqInfo->fgIsChannelRequested) { ++ /* Release channel before timeout. */ ++ p2pFuncReleaseCh(prAdapter, prChnlReqInfo); ++ } ++ ++ /* Stop timer for leaving this state. */ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ } while (FALSE); ++ ++} /* p2pStateAbort_IDLE */ ++ ++VOID p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Store the original channel info. */ ++ prChnlReqInfo->ucOriChnlNum = prP2pBssInfo->ucPrimaryChannel; ++ prChnlReqInfo->eOriBand = prP2pBssInfo->eBand; ++ prChnlReqInfo->eOriChnlSco = prP2pBssInfo->eBssSCO; ++ ++ /* RX Probe Request would check primary channel. */ ++ prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; ++ prP2pBssInfo->eBand = prChnlReqInfo->eBand; ++ prP2pBssInfo->eBssSCO = prChnlReqInfo->eChnlSco; ++ ++ DBGLOG(P2P, TRACE, "start a channel on hand timer.\n"); ++ if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING) { ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), ++ prChnlReqInfo->u4MaxInterval); ++ ++ kalP2PIndicateChannelReady(prAdapter->prGlueInfo, ++ prChnlReqInfo->u8Cookie, ++ prChnlReqInfo->ucReqChnlNum, ++ prChnlReqInfo->eBand, prChnlReqInfo->eChnlSco, prChnlReqInfo->u4MaxInterval); ++ } else ++ cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), ++ (P2P_EXT_LISTEN_TIME_MS - prChnlReqInfo->u4MaxInterval)); ++ } while (FALSE); ++ ++} /* p2pStateInit_CHNL_ON_HAND */ ++ ++VOID ++p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ /* Restore the original channel info. */ ++ prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucOriChnlNum; ++ prP2pBssInfo->eBand = prChnlReqInfo->eOriBand; ++ prP2pBssInfo->eBssSCO = prChnlReqInfo->eOriChnlSco; ++ ++ DBGLOG(P2P, INFO, "p2p state trans abort chann on hand, eListenExted: %d, eNextState: %d\n", ++ prP2pFsmInfo->eListenExted, eNextState); ++ if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING || ++ eNextState != P2P_STATE_CHNL_ON_HAND) { ++ /* Here maybe have a bug, when it's extlistening, a new remain_on_channel ++ was sent to driver? need to verify */ ++ prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; ++ /* Indicate channel return. */ ++ kalP2PIndicateChannelExpired(prAdapter->prGlueInfo, &prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Return Channel. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ } while (FALSE); ++} /* p2pStateAbort_CHNL_ON_HAND */ ++ ++VOID ++p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (eNextState < P2P_STATE_NUM)); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ if (eNextState == P2P_STATE_IDLE) { ++ if (prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) { ++ /* Intend to be AP. */ ++ /* Setup for AP mode. */ ++ p2pFuncStartGO(prAdapter, ++ prP2pBssInfo, ++ prP2pSpecificBssInfo->aucGroupSsid, ++ prP2pSpecificBssInfo->u2GroupSsidLen, ++ prP2pSpecificBssInfo->ucPreferredChannel, ++ prP2pSpecificBssInfo->eRfBand, ++ prP2pSpecificBssInfo->eRfSco, prP2pFsmInfo->fgIsApMode); ++ ++ } else { ++ /* Return Channel. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ } ++ ++ } ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_AP_CHANNEL_DETECT */ ++ ++VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); ++ ++ prScanReqInfo->eScanType = SCAN_TYPE_PASSIVE_SCAN; ++ prScanReqInfo->eChannelSet = SCAN_CHANNEL_2G4; ++ prScanReqInfo->u2PassiveDewellTime = 50; /* 50ms for passive channel load detection */ ++ prScanReqInfo->fgIsAbort = TRUE; ++ prScanReqInfo->fgIsScanRequest = TRUE; ++ prScanReqInfo->ucNumChannelList = 0; ++ prScanReqInfo->u4BufLength = 0; ++ prScanReqInfo->rSsidStruct.ucSsidLen = 0; ++ ++ p2pFuncRequestScan(prAdapter, prScanReqInfo); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_AP_CHANNEL_DETECT */ ++ ++VOID ++p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ++ if (eNextState == P2P_STATE_REQING_CHANNEL) { ++ UINT_8 ucPreferedChnl = 0; ++ ENUM_BAND_T eBand = BAND_NULL; ++ ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; ++ ++ prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); ++ ++ /* Determine the channel for AP. */ ++ if (cnmPreferredChannel(prAdapter, &eBand, &ucPreferedChnl, &eSco) == FALSE) { ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ucPreferedChnl = prP2pConnSettings->ucOperatingChnl; ++ if (ucPreferedChnl == 0) { ++ ++ if (scnQuerySparseChannel(prAdapter, &eBand, &ucPreferedChnl) == FALSE) { ++ ++ /* What to do? */ ++ ASSERT(FALSE); ++ /* TODO: Pick up a valid channel from channel list. */ ++ ucPreferedChnl = 1; ++ eBand = BAND_2G4; ++ } ++ } ++ } ++ ++ prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; ++ ++ DBGLOG(P2P, INFO, "p2pStateAbort_AP_CHANNEL_DETECT GO Scan\n"); ++ prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; ++ prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand = eBand; ++ prChnlReqInfo->eChnlSco = prP2pSpecificBssInfo->eRfSco = eSco; ++ } else { ++ p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); ++ } ++ ++ } while (FALSE); ++ ++} /* p2pStateAbort_AP_CHANNEL_DETECT */ ++ ++VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) ++{ ++ P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; ++ ++ do { ++ ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); ++ ++ prScanReqInfo = &prP2pFsmInfo->rScanReqInfo; ++ ++ prScanReqInfo->fgIsScanRequest = TRUE; ++ ++ p2pFuncRequestScan(prAdapter, prScanReqInfo); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_SCAN */ ++ ++VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ do { ++ ASSERT_BREAK(prAdapter != NULL); ++ ++ /* 1. Scan cancel. (Make sure the scan request is invalid. */ ++ p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); ++ ++ /* Scan done indication. */ ++ kalP2PIndicateScanDone(prAdapter->prGlueInfo, prP2pFsmInfo->rScanReqInfo.fgIsAbort); ++ } while (FALSE); ++ ++} /* p2pStateAbort_SCAN */ ++ ++VOID ++p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, ++ IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && ++ (prP2pFsmInfo != NULL) && ++ (prP2pBssInfo != NULL) && (prJoinInfo != NULL) && (prBssDesc != NULL)); ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prP2pConnSettings->aucSSID, ++ prP2pConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ } ++ /* Setup a join timer. */ ++ DBGLOG(P2P, TRACE, "Start a join init timer\n"); ++ cnmTimerStartTimer(prAdapter, ++ &(prAdapter->rP2pFsmTimeoutTimer), ++ (prP2pFsmInfo->u4GrantInterval - AIS_JOIN_CH_GRANT_THRESHOLD)); ++ ++ /* 2 <1> We are goin to connect to this BSS */ ++ prBssDesc->fgIsConnecting = TRUE; ++ ++ /* 2 <2> Setup corresponding STA_RECORD_T */ ++ prStaRec = bssCreateStaRecFromBssDesc(prAdapter, ++ (prBssDesc->fgIsP2PPresent ? (STA_TYPE_P2P_GO) ++ : (STA_TYPE_LEGACY_AP)), NETWORK_TYPE_P2P_INDEX, prBssDesc); ++ ++ if (prStaRec == NULL) { ++ DBGLOG(P2P, TRACE, "Create station record fail\n"); ++ break; ++ } ++ ++ prJoinInfo->prTargetStaRec = prStaRec; ++ prJoinInfo->fgIsJoinComplete = FALSE; ++ prJoinInfo->u4BufLength = 0; ++ ++ /* 2 <2.1> Sync. to FW domain */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ prStaRec->fgIsReAssoc = FALSE; ++ ++ prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ switch (prP2pConnSettings->eAuthMode) { ++ case AUTH_MODE_OPEN: /* Note: Omit break here. */ ++ case AUTH_MODE_WPA: ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA2: ++ case AUTH_MODE_WPA2_PSK: ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ break; ++ case AUTH_MODE_SHARED: ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; ++ break; ++ case AUTH_MODE_AUTO_SWITCH: ++ DBGLOG(P2P, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); ++ prJoinInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | ++ AUTH_TYPE_SHARED_KEY); ++ break; ++ default: ++ ASSERT(!(prP2pConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); ++ DBGLOG(P2P, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", ++ prP2pConnSettings->eAuthMode); ++ /* TODO(Kevin): error handling ? */ ++ return; ++ } ++ prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; ++ } else { ++ ASSERT(FALSE); ++ /* TODO: Shall we considering ROAMIN case for P2P Device?. */ ++ } ++ ++ /* 2 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes. */ ++ if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { ++ ++ DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; ++ } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { ++ ++ DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; ++ } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { ++ ++ DBGLOG(P2P, TRACE, ++ "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); ++ ++ prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; ++ ++ prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; ++ } else { ++ ASSERT(0); ++ } ++ ++ /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ ++ if (prBssDesc->ucSSIDLen) { ++ COPY_SSID(prJoinInfo->rSsidStruct.aucSsid, ++ prJoinInfo->rSsidStruct.ucSsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ } ++ /* 2 <5> Backup desired channel. */ ++ ++ /* 2 <6> Send a Msg to trigger SAA to start JOIN process. */ ++ prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); ++ ++ if (!prJoinReqMsg) { ++ DBGLOG(P2P, TRACE, "Allocation Join Message Fail\n"); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; ++ prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinReqMsg->prStaRec = prStaRec; ++ ++ /* TODO: Consider fragmentation info in station record. */ ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++} /* p2pStateInit_GC_JOIN */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process of JOIN Abort. Leave JOIN State & Abort JOIN. ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, ++ IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState) ++{ ++ P_MSG_JOIN_ABORT_T prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (prJoinInfo != NULL)); ++ ++ if (prJoinInfo->fgIsJoinComplete == FALSE) { ++ ++ prJoinAbortMsg = ++ (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); ++ if (!prJoinAbortMsg) { ++ DBGLOG(P2P, TRACE, "Fail to allocate join abort message buffer\n"); ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prJoinAbortMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_ABORT; ++ prJoinAbortMsg->ucSeqNum = prJoinInfo->ucSeqNumOfReqMsg; ++ prJoinAbortMsg->prStaRec = prJoinInfo->prTargetStaRec; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ /* Stop Join Timer. */ ++ cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); ++ ++ /* Release channel requested. */ ++ p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* p2pStateAbort_GC_JOIN */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c +new file mode 100644 +index 000000000000..72fa52e761da +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c +@@ -0,0 +1,915 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/privacy.c#1 ++*/ ++ ++/*! \file "privacy.c" ++ \brief This file including the protocol layer privacy function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer security setting from rsn.c and nic_privacy.c ++ ++*/ ++ ++/* ++** Log: privacy.c ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 20 2011 terry.wu ++ * NULL ++ * Fix Hotspot deauth send failed. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 06 28 2011 tsaiyuan.hsu ++ * [WCXRP00000819] [MT6620 Wi-Fi][Driver] check if staRec is NULL or not in secCheckClassError ++ * check if staRec is NULL or not in secCheckClassError. ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 20 2010 wh.su ++ * ++ * adding the wapi code. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * adding the compiling flag for migration. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 04 22 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the wpi same key id rx issue and fixed the remove wep key issue. ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Send Deauth for Class 3 Error and Leave Network Support ++ * ++ * 04 15 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * remove the assert code for allow ad-hoc pkt. ++ * ++ * 04 13 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the Klocwork error and refine the class error message. ++ * ++ * 03 04 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Code refine, and remove non-used code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 26 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * change the waning message shown level, and clear the global transmit flag for CMD INFRASTRUCTURE. ++ * ++ * 02 25 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * For support the WHQL test, do the remove key code refine. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 12 25 2009 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) ++ * * * * * * * * * MQM: BA handling ++ * * * * * * * * * TXM: Macros updates ++ * * * * * * * * * RXM: Macros/Duplicate Removal updates ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 11 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * modify the cmd with result return ++ * ++ * Dec 11 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * fixed the value not initialize issue ++ * ++ * Dec 10 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the cmd return type ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function to update the auth mode and encryption status for cmd build connection ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some code for wapi mode ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the call to check the 4th and eapol error report frame ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the function name ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code for parsing the EAPoL frame, and do some code refine ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the class error check ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the cmd_802_11_pmkid code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * doing some function rename, and adding the code for cmd CMD_ADD_REMOVE_KEY ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the clear pmkid function ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix eStaType check for AIS ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the ap selection related code ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_PRIVACY_MIGRATION ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to initialize the privacy-related ++* parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] ucNetTypeIdx Pointer to netowrk type index ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx) ++{ ++ UINT_8 i; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("secInit"); ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = 0; ++ prBssInfo->u4RsnSelectedPairwiseCipher = 0; ++ prBssInfo->u4RsnSelectedAKMSuite = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; ++ ++ prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; ++#endif ++ ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[0].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP40; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[1].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_TKIP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[2].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_CCMP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[3].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP104; ++ ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[4].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP40; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[5].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_TKIP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[6].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_CCMP; ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[7].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP104; ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[0].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_NONE; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[1].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_802_1X; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[2].dot11RSNAConfigAuthenticationSuite = ++ WPA_AKM_SUITE_PSK; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[3].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_NONE; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[4].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_802_1X; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[5].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_PSK; ++ ++#if CFG_SUPPORT_802_11W ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[6].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_802_1X_SHA256; ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[7].dot11RSNAConfigAuthenticationSuite = ++ RSN_AKM_SUITE_PSK_SHA256; ++#endif ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i].dot11RSNAConfigAuthenticationSuiteEnabled = ++ FALSE; ++ } ++ ++ secClearPmkid(prAdapter); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAisSpecBssInfo->rPreauthenticationTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) rsnIndicatePmkidCand, (ULONG) NULL); ++ ++#if CFG_SUPPORT_802_11W ++ cnmTimerInitTimer(prAdapter, ++ &prAisSpecBssInfo->rSaQueryTimer, (PFN_MGMT_TIMEOUT_FUNC) rsnStartSaQueryTimer, (ULONG) NULL); ++#endif ++ ++ prAisSpecBssInfo->fgCounterMeasure = FALSE; ++ prAisSpecBssInfo->ucWEPDefaultKeyID = 0; ++ ++#if 0 ++ for (i = 0; i < WTBL_SIZE; i++) { ++ g_prWifiVar->arWtbl[i].fgUsed = FALSE; ++ g_prWifiVar->arWtbl[i].prSta = NULL; ++ g_prWifiVar->arWtbl[i].ucNetTypeIdx = NETWORK_TYPE_INDEX_NUM; ++ ++ } ++ nicPrivacyInitialize((UINT_8) NETWORK_TYPE_INDEX_NUM); ++#endif ++} /* secInit */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Rx Class Error" to SEC_FSM for ++* JOIN Module. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSwRfb Pointer to the SW RFB. ++* ++* \return FALSE Class Error ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec) ++{ ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (!prStaRec) ++ return FALSE; ++ ++ eNetTypeIndex = prStaRec->ucNetTypeIndex; ++ if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) ++ return FALSE; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]; ++ if ((STA_STATE_3 != prStaRec->ucStaState) && prBssInfo->fgIsNetAbsent == FALSE) { ++ /*(IS_AP_STA(prStaRec) || IS_CLIENT_STA(prStaRec))) { */ ++ ++#if 0 /* by scott's suggestions, do not put work-around in JB2,we need to find the root cause */ ++ /* work-around for CR ALPS00816361 */ ++ if (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ DBGLOG(RSN, INFO, ++ "p2p> skip to send Deauth to MAC:[%pM] for Rx Class 3.\n", ++ prStaRec->aucMacAddr); ++ return TRUE; ++ } ++#endif ++ ++ if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, ++ prStaRec, ++ NULL, ++ REASON_CODE_CLASS_3_ERR, ++ (PFN_TX_DONE_HANDLER) NULL)) ++ ++ DBGLOG(RSN, INFO, "Send Deauth to [ %pM ] for Rx Class 3 Error.\n", ++ prStaRec->aucMacAddr); ++ else ++ DBGLOG(RSN, INFO, "Host sends Deauth to [ %pM ] for Rx Class 3 fail.\n", ++ prStaRec->aucMacAddr); ++ return FALSE; ++ } ++ ++ return secRxPortControlCheck(prAdapter, prSwRfb); ++} /* end of secCheckClassError() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to setting the sta port status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer to the sta ++* \param[in] fgPortBlock The port status ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPortBlock) ++{ ++ if (prSta == NULL) ++ return; ++ ++ prSta->fgPortBlock = fgPortBlock; ++ ++ DBGLOG(RSN, TRACE, ++ "The STA %pM port %s\n", prSta->aucMacAddr, fgPortBlock == TRUE ? "BLOCK" : " OPEN"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to report the sta port status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer to the sta ++* \param[out] fgPortBlock The port status ++* ++* \return TRUE sta exist, FALSE sta not exist ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secGetPortStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, OUT PBOOLEAN pfgPortStatus) ++{ ++ if (prSta == NULL) ++ return FALSE; ++ ++ *pfgPortStatus = prSta->fgPortBlock; ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle Peer device Tx Security process MSDU. ++* ++* \param[in] prMsduInfo pointer to the packet info pointer ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port blocked ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN /* ENUM_PORT_CONTROL_RESULT */ ++secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ ++ /* Todo:: */ ++ if (prMsduInfo->fgIs802_1x) ++ return TRUE; ++ ++ if (prStaRec->fgPortBlock == TRUE) { ++ DBGLOG(SEC, TRACE, "Drop Tx packet due Port Control!\n"); ++ return FALSE; ++ } ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) ++ return TRUE; ++#endif ++ if (IS_STA_IN_AIS(prStaRec)) { ++ if (!prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist && ++ (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED)) { ++ DBGLOG(SEC, TRACE, "Drop Tx packet due the key is removed!!!\n"); ++ return FALSE; ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle The Rx Security process MSDU. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSWRfb SW rfb pinter ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port control ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb) ++{ ++ ASSERT(prSWRfb); ++ ++#if 0 ++ /* whsu:Todo: Process MGMT and DATA */ ++ if (prSWRfb->prStaRec) { ++ if (prSWRfb->prStaRec->fgPortBlock == TRUE) { ++ if (1 /* prSWRfb->fgIsDataFrame and not 1x */ && ++ (g_prWifiVar->rConnSettings.eAuthMode >= AUTH_MODE_WPA)) { ++ /* DBGLOG(SEC, WARN, ("Drop Rx data due port control !\r\n")); */ ++ return TRUE; /* Todo: whsu FALSE; */ ++ } ++ /* if (!RX_STATUS_IS_PROTECT(prSWRfb->prRxStatus)) { */ ++ /* DBGLOG(RSN, WARN, ("Drop rcv non-encrypted data frame!\n")); */ ++ /* return FALSE; */ ++ /* } */ ++ } ++ } else { ++ } ++#endif ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine will enable/disable the cipher suite ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] u4CipherSuitesFlags flag for cipher suite ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags) ++{ ++ UINT_32 i; ++ P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; ++ P_IEEE_802_11_MIB_T prMib; ++ ++ ASSERT(prAdapter); ++ ++ prMib = &prAdapter->rMib; ++ ++ ASSERT(prMib); ++ ++ if (u4CipherSuitesFlags == CIPHER_FLAG_NONE) { ++ /* Disable all the pairwise cipher suites. */ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) ++ prMib->dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ ++ /* Update the group cipher suite. */ ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; ++ ++ return; ++ } ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { ++ prEntry = &prMib->dot11RSNAConfigPairwiseCiphersTable[i]; ++ ++ switch (prEntry->dot11RSNAConfigPairwiseCipher) { ++ case WPA_CIPHER_SUITE_WEP40: ++ case RSN_CIPHER_SUITE_WEP40: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_WEP40) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_TKIP: ++ case RSN_CIPHER_SUITE_TKIP: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_TKIP) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_CCMP: ++ case RSN_CIPHER_SUITE_CCMP: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_CCMP) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ ++ case WPA_CIPHER_SUITE_WEP104: ++ case RSN_CIPHER_SUITE_WEP104: ++ if (u4CipherSuitesFlags & CIPHER_FLAG_WEP104) ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; ++ else ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Update the group cipher suite. */ ++ if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_CCMP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_TKIP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP104; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP40; ++ else ++ prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; ++ ++} /* secSetCipherSuite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle The 2nd Tx EAPoL Frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prMsduInfo pointer to the packet info pointer ++* \param[in] pucPayload pointer to the 1x hdr ++* \param[in] u2PayloadLen the 1x payload length ++* ++* \retval TRUE Accept the packet ++* \retval FALSE Refuse the MSDU packet due port control ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++secProcessEAPOL(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen) ++{ ++ P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; ++ P_IEEE_802_1X_HDR pr1xHdr; ++ UINT_16 u2KeyInfo; ++ ++ ASSERT(prMsduInfo); ++ ASSERT(prStaRec); ++ ++ /* prStaRec = &(g_arStaRec[prMsduInfo->ucStaRecIndex]); */ ++ ASSERT(prStaRec); ++ ++ if (prStaRec && IS_AP_STA(prStaRec)) { ++ pr1xHdr = (P_IEEE_802_1X_HDR) pucPayload; ++ if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { ++ prEapol = (P_EAPOL_KEY) ((PUINT_32) (pucPayload + 4)); ++ WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); ++ if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { ++ if (u2KeyInfo & WPA_KEY_INFO_SECURE) { ++ /* 4th EAPoL check at secHandleTxDoneCallback() */ ++ /* DBGLOG(RSN, TRACE, ("Tx 4th EAPoL frame\r\n")); */ ++ } else if (u2PayloadLen == 123 /* Not include LLC */) { ++ DBGLOG(RSN, INFO, "Tx 2nd EAPoL frame\r\n"); ++ secFsmEvent2ndEapolTx(prAdapter, prStaRec); ++ } ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will handle the 4th EAPoL Tx done and mic Error Report frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus) ++{ ++ PUINT_8 pucPayload; ++ P_IEEE_802_1X_HDR pr1xHdr = (P_IEEE_802_1X_HDR) NULL; ++ P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; ++ UINT_16 u2KeyInfo; ++ UINT_16 u2PayloadLen; ++ ++ DEBUGFUNC("secHandleTxDoneCallback"); ++ ++ ASSERT(prMsduInfo); ++ /* Todo:: Notice if using the TX free immediate after send to firmware, the payload may not correcttly!!!! */ ++ ++ ASSERT(prStaRec); ++ ++ /* Todo:: This call back may not need because the order of set key and send 4th 1x can be make sure */ ++ /* Todo:: Notice the LLC offset */ ++#if 1 ++ pucPayload = (PUINT_8) prMsduInfo->prPacket; ++ ASSERT(pucPayload); ++ ++ u2PayloadLen = prMsduInfo->u2FrameLength; ++ ++ if (0 /* prMsduInfo->fgIs1xFrame */) { ++ ++ if (prStaRec && IS_AP_STA(prStaRec)) { ++ pr1xHdr = (P_IEEE_802_1X_HDR) (PUINT_32) (pucPayload + 8); ++ if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { ++ prEapol = (P_EAPOL_KEY) (PUINT_32) (pucPayload + 12); ++ WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); ++ if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { ++ if (prStaRec->rSecInfo.fg2nd1xSend == TRUE ++ && u2PayloadLen == ++ 107 /* include LLC *//* u2KeyInfo & WPA_KEY_INFO_SECURE */) { ++ DBGLOG(RSN, INFO, "Tx 4th EAPoL frame\r\n"); ++ secFsmEvent4ndEapolTxDone(prAdapter, prStaRec); ++ } else if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone) { ++ DBGLOG(RSN, INFO, "Tx EAPoL Error report frame\r\n"); ++ /* secFsmEventEapolTxDone(prAdapter, (UINT_32)prMsduInfo->prStaRec); */ ++ } ++ } ++ } ++ } ++ ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to initialize the pmkid parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secClearPmkid(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("secClearPmkid"); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ DBGLOG(RSN, TRACE, "secClearPmkid\n"); ++ prAisSpecBssInfo->u4PmkidCandicateCount = 0; ++ prAisSpecBssInfo->u4PmkidCacheCount = 0; ++ kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCandicate, sizeof(PMKID_CANDICATE_T) * CFG_MAX_PMKID_CACHE); ++ kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether WPA, or WPA2 but not WPA-None is enabled. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ ++ ASSERT(prConnSettings); ++ ++ ASSERT(prConnSettings->eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); ++ ++ if (prConnSettings->eEncStatus == ENUM_ENCRYPTION_DISABLED) ++ return FALSE; ++ ++ ASSERT(prConnSettings->eAuthMode < AUTH_MODE_NUM); ++ if ((prConnSettings->eAuthMode >= AUTH_MODE_WPA) && (prConnSettings->eAuthMode != AUTH_MODE_WPA_NONE)) ++ return TRUE; ++ ++ return FALSE; ++} /* secRsnKeyHandshakeEnabled */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return whether the transmit key alread installed. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prSta Pointer the sta record ++* ++* \retval TRUE Default key or Transmit key installed ++* FALSE Default key or Transmit key not installed ++* ++* \note: ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ASSERT(prSta); ++ ++ if (prSta->fgTransmitKeyExist) ++ return TRUE; ++ else ++ return FALSE; ++} /* secTransmitKeyExist */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether 802.11 privacy is enabled. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter) ++{ ++ DEBUGFUNC("secEnabled"); ++ ++ ASSERT(prAdapter->rWifiVar.rConnSettings.eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); ++ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION_DISABLED: ++ return FALSE; ++ case ENUM_ENCRYPTION1_ENABLED: ++ case ENUM_ENCRYPTION2_ENABLED: ++ case ENUM_ENCRYPTION3_ENABLED: ++ return TRUE; ++ default: ++ DBGLOG(RSN, TRACE, "Unknown encryption setting %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ break; ++ } ++ return FALSE; ++} /* secEnabled */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the privacy bit at mac header for TxM ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] prMsdu the msdu for known the sta record ++* ++* \return TRUE the privacy need to set ++* FALSE the privacy no need to set ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prAdapter); ++ ++ ASSERT(prMsdu); ++ ++ ASSERT(prStaRec); ++ /* prStaRec = &(g_arStaRec[prMsdu->ucStaRecIndex]); */ ++ ++ if (prStaRec == NULL) { ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) ++ return TRUE; ++ return FALSE; /* No privacy bit */ ++ } ++ ++ /* Todo:: */ ++ if (0 /* prMsdu->fgIs1xFrame */) { ++ if (IS_STA_IN_AIS(prStaRec) && prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { ++ DBGLOG(RSN, LOUD, "For AIS Legacy 1x, always not encryped\n"); ++ return FALSE; ++ } else if (!prStaRec->fgTransmitKeyExist) { ++ DBGLOG(RSN, LOUD, "1x Not Protected.\n"); ++ return FALSE; ++ } else if (prStaRec->rSecInfo.fgKeyStored) { ++ DBGLOG(RSN, LOUD, "1x not Protected due key stored!\n"); ++ return FALSE; ++ } ++ DBGLOG(RSN, LOUD, "1x Protected.\n"); ++ return TRUE; ++ } ++ if (!prStaRec->fgTransmitKeyExist) { ++ /* whsu , check for AIS only */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) { ++ DBGLOG(RSN, LOUD, "Protected\n"); ++ return TRUE; ++ } ++ } else { ++ DBGLOG(RSN, LOUD, "Protected.\n"); ++ return TRUE; ++ } ++ ++ /* No sec or key is removed!!! */ ++ return FALSE; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c +new file mode 100644 +index 000000000000..fd0a8772a666 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c +@@ -0,0 +1,497 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rate.c#1 ++*/ ++ ++/*! \file "rate.c" ++ \brief This file contains the transmission rate handling routines. ++ ++ This file contains the transmission rate handling routines for setting up ++ ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do ++ conversion between Rate Set and Data Rates. ++*/ ++ ++/* ++** Log: rate.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add rate.c. ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comments ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix DBGLOG ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++** \main\maintrunk.MT5921\12 2008-12-19 17:19:32 GMT mtk01461 ++** Fix the problem that do not ASSERT the length of Supported Rate IE == 8 ++** \main\maintrunk.MT5921\11 2008-12-01 18:17:42 GMT mtk01088 ++** fixed the lint "possible using null pointer" warning ++** \main\maintrunk.MT5921\10 2008-08-20 00:16:36 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\9 2008-04-13 21:17:13 GMT mtk01461 ++** Revise GEN Link Speed OID ++** \main\maintrunk.MT5921\8 2008-03-28 10:40:13 GMT mtk01461 ++** Add rateGetRateSetFromDataRates() for set desired rate OID ++** \main\maintrunk.MT5921\7 2008-03-26 09:16:20 GMT mtk01461 ++** Add adopt operational rate as ACK rate if BasicRateSet was not found ++** Add comments ++** \main\maintrunk.MT5921\6 2008-02-21 15:01:39 GMT mtk01461 ++** Add initial rate according rx signal quality support ++** \main\maintrunk.MT5921\5 2008-01-07 15:06:44 GMT mtk01461 ++** Fix typo of rate adaptation of CtrlResp Frame ++** \main\maintrunk.MT5921\4 2007-10-25 18:05:12 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* The list of valid data rates. */ ++const UINT_8 aucDataRate[] = { ++ RATE_1M, /* RATE_1M_INDEX = 0 */ ++ RATE_2M, /* RATE_2M_INDEX */ ++ RATE_5_5M, /* RATE_5_5M_INDEX */ ++ RATE_11M, /* RATE_11M_INDEX */ ++ RATE_22M, /* RATE_22M_INDEX */ ++ RATE_33M, /* RATE_33M_INDEX */ ++ RATE_6M, /* RATE_6M_INDEX */ ++ RATE_9M, /* RATE_9M_INDEX */ ++ RATE_12M, /* RATE_12M_INDEX */ ++ RATE_18M, /* RATE_18M_INDEX */ ++ RATE_24M, /* RATE_24M_INDEX */ ++ RATE_36M, /* RATE_36M_INDEX */ ++ RATE_48M, /* RATE_48M_INDEX */ ++ RATE_54M, /* RATE_54M_INDEX */ ++ RATE_HT_PHY /* RATE_HT_PHY_INDEX */ ++}; ++ ++static const UINT_8 aucDefaultAckCtsRateIndex[RATE_NUM] = { ++ RATE_1M_INDEX, /* RATE_1M_INDEX = 0 */ ++ RATE_2M_INDEX, /* RATE_2M_INDEX */ ++ RATE_5_5M_INDEX, /* RATE_5_5M_INDEX */ ++ RATE_11M_INDEX, /* RATE_11M_INDEX */ ++ RATE_1M_INDEX, /* RATE_22M_INDEX - Not supported */ ++ RATE_1M_INDEX, /* RATE_33M_INDEX - Not supported */ ++ RATE_6M_INDEX, /* RATE_6M_INDEX */ ++ RATE_6M_INDEX, /* RATE_9M_INDEX */ ++ RATE_12M_INDEX, /* RATE_12M_INDEX */ ++ RATE_12M_INDEX, /* RATE_18M_INDEX */ ++ RATE_24M_INDEX, /* RATE_24M_INDEX */ ++ RATE_24M_INDEX, /* RATE_36M_INDEX */ ++ RATE_24M_INDEX, /* RATE_48M_INDEX */ ++ RATE_24M_INDEX /* RATE_54M_INDEX */ ++}; ++ ++const BOOLEAN afgIsOFDMRate[RATE_NUM] = { ++ FALSE, /* RATE_1M_INDEX = 0 */ ++ FALSE, /* RATE_2M_INDEX */ ++ FALSE, /* RATE_5_5M_INDEX */ ++ FALSE, /* RATE_11M_INDEX */ ++ FALSE, /* RATE_22M_INDEX - Not supported */ ++ FALSE, /* RATE_33M_INDEX - Not supported */ ++ TRUE, /* RATE_6M_INDEX */ ++ TRUE, /* RATE_9M_INDEX */ ++ TRUE, /* RATE_12M_INDEX */ ++ TRUE, /* RATE_18M_INDEX */ ++ TRUE, /* RATE_24M_INDEX */ ++ TRUE, /* RATE_36M_INDEX */ ++ TRUE, /* RATE_48M_INDEX */ ++ TRUE /* RATE_54M_INDEX */ ++}; ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the given Supported Rate & Extended Supported Rate IE to the ++* Operational Rate Set and Basic Rate Set, and also check if any Basic ++* Rate Code is unknown by driver. ++* ++* @param[in] prIeSupportedRate Pointer to the Supported Rate IE ++* @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE ++* @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set ++* @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set ++* @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that Basic ++* Rate Set has unknown Rate Code ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, ++ IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, ++ OUT PUINT_16 pu2OperationalRateSet, ++ OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate) ++{ ++ UINT_16 u2OperationalRateSet = 0; ++ UINT_16 u2BSSBasicRateSet = 0; ++ BOOLEAN fgIsUnknownBSSBasicRate = FALSE; ++ UINT_8 ucRate; ++ UINT_32 i, j; ++ ++ ASSERT(pu2OperationalRateSet); ++ ASSERT(pu2BSSBasicRateSet); ++ ASSERT(pfgIsUnknownBSSBasicRate); ++ ++ if (prIeSupportedRate) { ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* ASSERT(prIeSupportedRate->ucLength <= ELEM_MAX_LEN_SUP_RATES); */ ++ ASSERT(prIeSupportedRate->ucLength <= RATE_NUM); ++ ++ for (i = 0; i < prIeSupportedRate->ucLength; i++) { ++ ucRate = prIeSupportedRate->aucSupportedRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2OperationalRateSet |= BIT(j); ++ ++ if (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT) ++ u2BSSBasicRateSet |= BIT(j); ++ ++ break; ++ } ++ } ++ ++ if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && ++ (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)) { ++ fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ ++ } ++ } ++ } ++ ++ if (prIeExtSupportedRate) { ++ /* ASSERT(prIeExtSupportedRate->ucLength <= ELEM_MAX_LEN_EXTENDED_SUP_RATES); */ ++ ++ for (i = 0; i < prIeExtSupportedRate->ucLength; i++) { ++ ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2OperationalRateSet |= BIT(j); ++ ++ if (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT) ++ u2BSSBasicRateSet |= BIT(j); ++ ++ break; ++ } ++ } ++ ++ if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && ++ (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)) { ++ fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ ++ } ++ } ++ } ++ ++ *pu2OperationalRateSet = u2OperationalRateSet; ++ *pu2BSSBasicRateSet = u2BSSBasicRateSet; ++ *pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate; ++ ++ return; ++ ++} /* end of rateGetRateSetFromIEs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate Code ++* Format for used in (Ext)Supportec Rate IE. ++* ++* @param[in] u2OperationalRateSet Operational Rate Set ++* @param[in] u2BSSBasicRateSet Basic Rate Set ++* @param[out] pucDataRates Pointer to the Data Rate Buffer ++* @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen) ++{ ++ UINT_32 i, j; ++ ++ ASSERT(pucDataRates); ++ ASSERT(pucDataRatesLen); ++ ++ ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); ++ ++ for (i = RATE_1M_INDEX, j = 0; i < RATE_NUM; i++) { ++ if (u2OperationalRateSet & BIT(i)) { ++ ++ *(pucDataRates + j) = aucDataRate[i]; ++ ++ if (u2BSSBasicRateSet & BIT(i)) ++ *(pucDataRates + j) |= RATE_BASIC_BIT; ++ ++ j++; ++ } ++ } ++ ++ *pucDataRatesLen = (UINT_8) j; ++ ++ return; ++ ++} /* end of rateGetDataRatesFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the highest rate from given Rate Set. ++* ++* \param[in] u2RateSet Rate Set ++* \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index ++* ++* \retval TRUE Highest Rate Index was found ++* \retval FALSE Highest Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex) ++{ ++ INT_32 i; ++ ++ ASSERT(pucHighestRateIndex); ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2RateSet & BIT(i)) { ++ *pucHighestRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetHighestRateIndexFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the lowest rate from given Rate Set. ++* ++* \param[in] u2RateSet Rate Set ++* \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index ++* ++* \retval TRUE Lowest Rate Index was found ++* \retval FALSE Lowest Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex) ++{ ++ UINT_32 i; ++ ++ ASSERT(pucLowestRateIndex); ++ ++ for (i = RATE_1M_INDEX; i <= RATE_54M_INDEX; i++) { ++ if (u2RateSet & BIT(i)) { ++ *pucLowestRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetLowestRateIndexFromRateSet() */ ++ ++#if 0 /* NOTE(Kevin): For reference */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Convert the given Data Rates to the Rate Set. ++* ++* \param[in] pucDataRates Pointer to the Data Rates ++* \param[in] ucDataRatesLen Length of given Data Rates ++* \param[out] pu2RateSet Pointer to the Rate Set ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rateGetRateSetFromDataRates(IN PUINT_8 pucDataRates, IN UINT_8 ucDataRatesLen, OUT PUINT_16 pu2RateSet) ++{ ++ UINT_16 u2RateSet = 0; ++ UINT_8 ucRate; ++ UINT_32 i, j; ++ ++ ASSERT(pucDataRates); ++ ASSERT(pu2RateSet); ++ ++ if (pucDataRates) { ++ for (i = 0; i < ucDataRatesLen; i++) { ++ ucRate = pucDataRates[i] & RATE_MASK; ++ ++ /* Search all valid data rates */ ++ for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { ++ if (ucRate == aucDataRate[j]) { ++ u2RateSet |= BIT(j); ++ break; ++ } ++ } ++ } ++ } ++ ++ *pu2RateSet = u2RateSet; ++ ++ return; ++ ++} /* end of rateGetRateSetFromDataRates() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the Operational Rate Set and Basic Rate Set to get the corresponding ++* ACK/CTS(Respnose) TX Rates. ++* ++* \param[in] u2OperationalRateSet Operational Rate Set ++* \param[in] u2BSSBasicRateSet Basic Rate Set ++* \param[out] aucAckCtsRateIndex Pointer to the Ack/Cts Data Rate Buffer ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rateSetAckCtsDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, ++ IN UINT_16 u2BSSBasicRateSet, IN OUT UINT_8 aucAckCtsRateIndex[]) ++{ ++ INT_32 i, j; ++ ++ ASSERT(aucAckCtsRateIndex); ++ ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); ++ ++ /* Setup default ACK/CTS response rate */ ++ kalMemCopy(aucAckCtsRateIndex, (PVOID) aucDefaultAckCtsRateIndex, sizeof(aucDefaultAckCtsRateIndex)); ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2OperationalRateSet & BIT(i)) { ++ for (j = i; j >= RATE_1M_INDEX; j--) { ++ if (u2BSSBasicRateSet & BIT(j)) { ++ /* Reply ACK Frame at the same Modulation Scheme. */ ++ if ((afgIsOFDMRate[i] && afgIsOFDMRate[j]) || ++ (!afgIsOFDMRate[i] && !afgIsOFDMRate[j])) ++ aucAckCtsRateIndex[i] = (UINT_8) j; ++ break; ++ } ++ } ++ ++ /* NOTE(Kevin 2008/03/25): Following code is used for those AP which has ++ * NULL BasicRateSet. ++ * e.g. If input Operational Rate Set = [18M 12M 9M], Basic Rate Set = NULL. ++ * Originally we'll get Ack Rate for [18M 12M 9M] is [12M 12M "6M"]. ++ * Now we'll get Ack Rate for [18M 12M 9M] is [12M 12M 9M], ++ * The Ack Rate for Tx Rates which are not list in Operational Rate Set is still ++ * use highest mandatory rate as default. ++ */ ++ if (j < RATE_1M_INDEX) { /* The ACK/CTS rate was not found in BasicRateSet */ ++ if (!(BIT(aucAckCtsRateIndex[i]) & u2OperationalRateSet)) ++ aucAckCtsRateIndex[i] = (UINT_8) i; ++ } ++ } ++ } ++ ++ return; ++ ++} /* end of rateSetAckCtsDataRatesFromRateSet() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the proper initial rate from Rate Set according to given RCPI value ++* ++* \param[in] u2RateSet Rate Set ++* \param[in] rRcpi RCPI value from AP or Peer STA ++* \param[out] pucInitialRateIndex Pointer to buffer of the initial Rate Index ++* ++* \retval TRUE Initial Rate Index was found ++* \retval FALSE Initial Rate Index was not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rateGetBestInitialRateIndex(IN UINT_16 u2RateSet, IN RCPI rRcpi, OUT PUINT_8 pucInitialRateIndex) ++{ ++ UINT_16 u2InitRateSet; ++ INT_32 i; ++ ++ ASSERT(pucInitialRateIndex); ++ ++ DBGLOG(MGT, TRACE, "rRcpi = %d\n", rRcpi); ++ ++ if (rRcpi >= RCPI_100) { /* Best Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_100); ++ } else if (rRcpi >= RCPI_80) { /* Better Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_80); ++ } else if (rRcpi >= RCPI_60) { /* Good Signal */ ++ u2InitRateSet = INITIAL_RATE_SET(RCPI_60); ++ } else { /* Worse Signal */ ++ /* NOTE(Kevin): If return FALSE, we should assign the BSS Basic Rate Index ++ * (prBssInfo->ucBasicRateIndex) to the initial rate. It was determined in ++ * function - bssUpdateTxRateForControlFrame(). ++ */ ++ return FALSE; ++ } ++ ++ u2RateSet &= u2InitRateSet; ++ ++ for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { ++ if (u2RateSet & BIT(i)) { ++ *pucInitialRateIndex = (UINT_8) i; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++ ++} /* end of rateGetBestInitialRateIndex() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c +new file mode 100644 +index 000000000000..244346983f40 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c +@@ -0,0 +1,1858 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm.c#2 ++*/ ++ ++/*! \file "rlm.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Check length HT cap IE about RX associate request frame ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 03 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Fix preamble type of STA mode ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Not send ERP IE if peer STA is 802.11b-only ++ * ++ * 10 11 2011 cm.chang ++ * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter ++ * Ignore HT OP IE if its length field is not valid ++ * ++ * 09 28 2011 cm.chang ++ * NULL ++ * Add length check to reduce possibility to adopt wrong IE ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * Handle client mode about preamble type and slot time ++ * ++ * 09 01 2011 cm.chang ++ * [WCXRP00000971] [MT6620 Wi-Fi][Driver][FW] Not set Beacon timeout interval when CPTT ++ * Final channel number only adopts the field from assoc response ++ * ++ * 06 10 2011 cm.chang ++ * [WCXRP00000773] [MT6620 Wi-Fi][Driver] Workaround some AP fill primary channel field with its secondary channel ++ * If DS IE exists, ignore the primary channel field in HT OP IE ++ * ++ * 05 03 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Fix compiling error ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Refine range of valid channel number ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Check if channel is valided before record ing BSS channel ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode ++ * and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 10 15 2010 cm.chang ++ * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. ++ * Add exception handle when no mgmt buffer in free build ++ * ++ * 10 08 2010 cm.chang ++ * NULL ++ * When 20M only setting, ignore OBSS IE ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Temporary add rlmUpdateParamByStaForBow() and rlmBssInitForBow(). ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Add CFG_ENABLE_BT_OVER_WIFI. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * P2P Group Negotiation Code Check in. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Fix compile error while enabling WiFi Direct function. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 06 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix channel ID definition in RFB status to primary channel instead of center channel ++ * ++ * 06 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add TX short GI compiling option ++ * ++ * 06 02 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Roll back to remove CFG_SUPPORT_BCM_TEST. ++ * ++ * 06 01 2010 chinghwa.yu ++ * [BORA00000563]Add WiFi CoEx BCM module ++ * Update BCM Test and RW configuration. ++ * ++ * 05 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add some compiling options to control 11n functions ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set RTS threshold of 2K bytes initially ++ * ++ * 05 18 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Ad-hoc Beacon should not carry HT OP and OBSS IEs ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 04 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Utilize status of swRfb to know channel number and band ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Different invoking order for WTBL entry of associated AP ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 04 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process Beacon only ready for infra STA now ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 24 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * fixed some WHQL testing error. ++ * ++ * 03 15 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide draft measurement and quiet functions ++ * ++ * 03 09 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * If bss is not 11n network, zero WTBL HT parameters ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 03 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Generate HT IE only depending on own phyTypeSet ++ * ++ * 03 02 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not fill HT related IE if BssInfo does not include 11n phySet ++ * ++ * 03 01 2010 tehuang.liu ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * To store field AMPDU Parameters in STA_REC ++ * ++ * 02 26 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable RDG RX, but disable RDG TX for IOT and LongNAV ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 07 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Modify the parameter of rlmRecAssocRspHtInfo function ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix prBssInfo->ucPrimaryChannel handle for assoc resp ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add some function to process HT operation ++ * ++ * Nov 28 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Call rlmStatisticsInit() to handle MIB counters ++ * ++ * Nov 18 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); ++ ++static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static BOOLEAN ++rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static BOOLEAN ++rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); ++ ++static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFsmEventInit(P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* Note: assume TIMER_T structures are reset to zero or stopped ++ * before invoking this function. ++ */ ++ ++ /* Initialize OBSS FSM */ ++ rlmObssInit(prAdapter); ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ rlmDomainCheckCountryPowerLimitTable(prAdapter); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 ucNetIdx; ++ ++ ASSERT(prAdapter); ++ ++ RLM_NET_FOR_EACH(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ /* Note: all RLM timers will also be stopped. ++ * Now only one OBSS scan timer. ++ */ ++ rlmBssReset(prAdapter, prBssInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe request, association request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe request, association request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ else if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ hs20FillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) ++ rlmFillHtOpIE(prAdapter, prBssInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief For probe response (GO, IBSS) and association response ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ P_IE_ERP_T prErpIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; ++ ASSERT(prBssInfo); ++ ++ if (RLM_NET_IS_11GN(prBssInfo) && prBssInfo->eBand == BAND_2G4 && ++ (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11GN))) { ++ prErpIe = (P_IE_ERP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add ERP IE */ ++ prErpIe->ucId = ELEM_ID_ERP_INFO; ++ prErpIe->ucLength = 1; ++ ++ prErpIe->ucERP = prBssInfo->fgObssErpProtectMode ? ERP_INFO_USE_PROTECTION : 0; ++ ++ if (prBssInfo->fgErpProtectMode) ++ prErpIe->ucERP |= (ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION); ++ ++ /* Handle barker preamble */ ++ if (!prBssInfo->fgUseShortPreamble) ++ prErpIe->ucERP |= ERP_INFO_BARKER_PREAMBLE_MODE; ++ ++ ASSERT(IE_SIZE(prErpIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prErpIe); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT32 ++rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, ++ BOOLEAN fgShortGIDisabled, ++ UINT_8 u8SupportRxSgi20, ++ UINT_8 u8SupportRxSgi40, ++ UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf) ++{ ++ P_IE_HT_CAP_T prHtCap; ++ P_SUP_MCS_SET_FIELD prSupMcsSet; ++ ++ ASSERT(pOutBuf); ++ ++ prHtCap = (P_IE_HT_CAP_T) pOutBuf; ++ ++ /* Add HT capabilities IE */ ++ prHtCap->ucId = ELEM_ID_HT_CAP; ++ prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; ++ ++ prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; ++ if (!fg40mAllowed) { ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | ++ HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); ++ } ++ if (fgShortGIDisabled) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ if (u8SupportRxSgi20 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); ++ if (u8SupportRxSgi40 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); ++ if (u8SupportRxGf == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); ++ if (u8SupportRxSTBC == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_RX_STBC_1_SS); ++ prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; ++ ++ prSupMcsSet = &prHtCap->rSupMcsSet; ++ kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); ++ ++ prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); ++ ++ if (fg40mAllowed) ++ prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ ++ prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; ++ prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; ++ ++ prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; ++ if (!fg40mAllowed || eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); ++ ++ prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; ++ ++ prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; ++ ++ ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); ++ ++ return IE_SIZE(prHtCap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_HT_CAP_T prHtCap; ++/* P_SUP_MCS_SET_FIELD prSupMcsSet; */ ++ BOOLEAN fg40mAllowed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(prMsduInfo); ++ ++ fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ ++ prHtCap = (P_IE_HT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ /* Add HT capabilities IE */ ++ prHtCap->ucId = ELEM_ID_HT_CAP; ++ prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; ++ ++ prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; ++ if (!fg40mAllowed) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | ++ HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); ++ if (prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); ++ ++ if (prAdapter->rWifiVar.u8SupportRxSgi20 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); ++ if (prAdapter->rWifiVar.u8SupportRxSgi40 == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); ++ if (prAdapter->rWifiVar.u8SupportRxGf == 2) ++ prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); ++ ++ prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; ++ ++ prSupMcsSet = &prHtCap->rSupMcsSet; ++ kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); ++ ++ prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); ++ ++ if (fg40mAllowed) ++ prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ ++ prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; ++ prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; ++ ++ prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; ++ if (!fg40mAllowed || prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); ++ ++ prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; ++ ++ prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; ++ ++ ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHtCap); ++#else ++ ++ prMsduInfo->u2FrameLength += rlmFillHtCapIEByParams(fg40mAllowed, ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, ++ prAdapter->rWifiVar.u8SupportRxSgi20, ++ prAdapter->rWifiVar.u8SupportRxSgi40, ++ prAdapter->rWifiVar.u8SupportRxGf, ++ prAdapter->rWifiVar.u8SupportRxSTBC, ++ prBssInfo->eCurrentOPMode, (UINT_8 *) prHtCap); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ P_HS20_EXT_CAP_T prHsExtCap; ++#else ++ P_EXT_CAP_T prExtCap; ++#endif ++ BOOLEAN fg40mAllowed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ prHsExtCap = (P_HS20_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ prHsExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) ++ prHsExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; ++ else ++ prHsExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ ++ kalMemZero(prHsExtCap->aucCapabilities, sizeof(prHsExtCap->aucCapabilities)); ++ ++ prHsExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (!fg40mAllowed) ++ prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { ++ SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); ++ ++ /* For R2 WNM-Notification */ ++ SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); ++ } ++ ++ ASSERT(IE_SIZE(prHsExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHsExtCap); ++ ++#else ++ /* Add Extended Capabilities IE */ ++ prExtCap = (P_EXT_CAP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ prExtCap->ucId = ELEM_ID_EXTENDED_CAP; ++ ++ prExtCap->ucLength = 3 - ELEM_HDR_LEN; ++ kalMemZero(prExtCap->aucCapabilities, sizeof(prExtCap->aucCapabilities)); ++ ++ prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; ++ ++ if (!fg40mAllowed) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; ++ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; ++ ++ ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme) ++{ ++ P_IE_HT_OP_T prHtOp; ++ UINT_16 i; ++ ++ prHtOp = (P_IE_HT_OP_T) pFme; ++ ++ /* Add HT operation IE */ ++ prHtOp->ucId = ELEM_ID_HT_OP; ++ prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; ++ ++ /* RIFS and 20/40 bandwidth operations are included */ ++ prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; ++ ++ /* Decide HT protection mode field */ ++ if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; ++ else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; ++ else { ++ /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ ++ prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; ++ } ++ ++ if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { ++ /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED ++ * Note: it will also be set in ad-hoc network ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (0 /* Regulatory class 16 */ && ++ prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { ++ /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection ++ * although it is possible to have no protection by spec. ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ ++ ++ /* No basic MCSx are needed temporarily */ ++ for (i = 0; i < 16; i++) ++ prHtOp->aucBasicMcsSet[i] = 0; ++ ++ return sizeof(IE_HT_OP_T); ++} ++ ++static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) ++{ ++/* P_IE_HT_OP_T prHtOp; */ ++/* UINT_16 i; */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(prMsduInfo); ++ ++ prMsduInfo->u2FrameLength += rlmFillHtOpIeBody(prBssInfo, ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength)); ++#if 0 ++ prHtOp = (P_IE_HT_OP_T) ++ (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); ++ ++ /* Add HT operation IE */ ++ prHtOp->ucId = ELEM_ID_HT_OP; ++ prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; ++ ++ /* RIFS and 20/40 bandwidth operations are included */ ++ prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; ++ ++ /* Decide HT protection mode field */ ++ if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; ++ else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) ++ prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; ++ else { ++ /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ ++ prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; ++ } ++ ++ if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { ++ /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED ++ * Note: it will also be set in ad-hoc network ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; ++ } ++ ++ if (0 /* Regulatory class 16 */ && ++ prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { ++ /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection ++ * although it is possible to have no protection by spec. ++ */ ++ prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; ++ } ++ ++ prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ ++ ++ /* No basic MCSx are needed temporarily */ ++ for (i = 0; i < 16; i++) ++ prHtOp->aucBasicMcsSet[i] = 0; ++ ++ ASSERT(IE_SIZE(prHtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP)); ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(prHtOp); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked to update parameters of associated AP. ++* (Association response and Beacon) ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ UINT_16 u2Offset; ++ P_STA_RECORD_T prStaRec; ++ P_IE_HT_CAP_T prHtCap; ++ P_IE_HT_OP_T prHtOp; ++ P_IE_OBSS_SCAN_PARAM_T prObssScnParam; ++ UINT_8 ucERP, ucPrimaryChannel; ++#if CFG_SUPPORT_QUIET && 0 ++ BOOLEAN fgHasQuietIE = FALSE; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ASSERT(pucIE); ++ ++ prStaRec = prBssInfo->prStaRecOfAP; ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return 0; ++ ++ prBssInfo->fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; ++ ucPrimaryChannel = 0; ++ prObssScnParam = NULL; ++ ++ /* Note: HT-related members in staRec may not be zero before, so ++ * if following IE does not exist, they are still not zero. ++ * These HT-related parameters are valid only when the corresponding ++ * BssInfo supports 802.11n, i.e., RLM_NET_IS_11N() ++ */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ break; ++ ++ case ELEM_ID_HT_OP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ prHtOp = (P_IE_HT_OP_T) pucIE; ++ /* Workaround that some APs fill primary channel field by its ++ * secondary channel, but its DS IE is correct 20110610 ++ */ ++ if (ucPrimaryChannel == 0) ++ ucPrimaryChannel = prHtOp->ucPrimaryChannel; ++ prBssInfo->ucHtOpInfo1 = prHtOp->ucInfo1; ++ prBssInfo->u2HtOpInfo2 = prHtOp->u2Info2; ++ prBssInfo->u2HtOpInfo3 = prHtOp->u2Info3; ++ ++ if (!prBssInfo->fg40mBwAllowed) ++ prBssInfo->ucHtOpInfo1 &= ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); ++ ++ if ((prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) ++ prBssInfo->eBssSCO = (ENUM_CHNL_EXT_T)(prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO); ++ ++ prBssInfo->eHtProtectMode = (ENUM_HT_PROTECT_MODE_T) ++ (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_HT_PROTECTION); ++ ++ /* To do: process regulatory class 16 */ ++ if ((prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) ++ && 0 /* && regulatory class is 16 */) ++ prBssInfo->eGfOperationMode = GF_MODE_DISALLOWED; ++ else if (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) ++ prBssInfo->eGfOperationMode = GF_MODE_PROTECT; ++ else ++ prBssInfo->eGfOperationMode = GF_MODE_NORMAL; ++ ++ prBssInfo->eRifsOperationMode = ++ (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_RIFS_MODE) ? RIFS_MODE_NORMAL : RIFS_MODE_DISALLOWED; ++ ++ break; ++ ++ case ELEM_ID_20_40_BSS_COEXISTENCE: ++ if (!RLM_NET_IS_11N(prBssInfo)) ++ break; ++ /* To do: store if scanning exemption grant to BssInfo */ ++ break; ++ ++ case ELEM_ID_OBSS_SCAN_PARAMS: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_OBSS_SCAN_PARAM_T) - 2)) ++ break; ++ /* Store OBSS parameters to BssInfo */ ++ prObssScnParam = (P_IE_OBSS_SCAN_PARAM_T) pucIE; ++ break; ++ ++ case ELEM_ID_EXTENDED_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo)) ++ break; ++ /* To do: store extended capability (PSMP, coexist) to BssInfo */ ++ break; ++ ++ case ELEM_ID_ERP_INFO: ++ if (IE_LEN(pucIE) != (sizeof(IE_ERP_T) - 2) || prBssInfo->eBand != BAND_2G4) ++ break; ++ ucERP = ERP_INFO_IE(pucIE)->ucERP; ++ prBssInfo->fgErpProtectMode = (ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE; ++ ++ if (ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ break; ++ ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) ++ ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ case ELEM_ID_CH_SW_ANNOUNCEMENT: ++ { ++ rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) pucIE); ++ } ++ break; ++ ++#if CFG_SUPPORT_QUIET && 0 ++ /* Note: RRM code should be moved to independent RRM function by ++ * component design rule. But we attach it to RLM temporarily ++ */ ++ case ELEM_ID_QUIET: ++ rrmQuietHandleQuietIE(prBssInfo, (P_IE_QUIET_T) pucIE); ++ fgHasQuietIE = TRUE; ++ break; ++#endif ++#endif ++ ++ default: ++ break; ++ } /* end of switch */ ++ } /* end of IE_FOR_EACH */ ++ ++ /* Some AP will have wrong channel number (255) when running time. ++ * Check if correct channel number information. 20110501 ++ */ ++ if ((prBssInfo->eBand == BAND_2G4 && ucPrimaryChannel > 14) || ++ (prBssInfo->eBand != BAND_2G4 && (ucPrimaryChannel >= 200 || ucPrimaryChannel <= 14))) ++ ucPrimaryChannel = 0; ++#if CFG_SUPPORT_QUIET && 0 ++ if (!fgHasQuietIE) ++ rrmQuietIeNotExist(prAdapter, prBssInfo); ++#endif ++ ++ /* Check if OBSS scan process will launch */ ++ if (!prAdapter->fgEnOnlineScan || !prObssScnParam || ++ !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH) || ++ prBssInfo->eBand != BAND_2G4 || !prBssInfo->fg40mBwAllowed) { ++ ++ /* Note: it is ok not to stop rObssScanTimer() here */ ++ prBssInfo->u2ObssScanInterval = 0; ++ } else { ++ if (prObssScnParam->u2TriggerScanInterval < OBSS_SCAN_MIN_INTERVAL) ++ prObssScnParam->u2TriggerScanInterval = OBSS_SCAN_MIN_INTERVAL; ++ if (prBssInfo->u2ObssScanInterval != prObssScnParam->u2TriggerScanInterval) { ++ ++ prBssInfo->u2ObssScanInterval = prObssScnParam->u2TriggerScanInterval; ++ ++ /* Start timer to trigger OBSS scanning */ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, ++ prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ } ++ } ++ ++ return ucPrimaryChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief AIS or P2P GC. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN ++rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ UINT_16 u2Offset, i; ++ UINT_8 ucPriChannel, ucSecChannel; ++ ENUM_CHNL_EXT_T eSCO; ++ BOOLEAN fgHtBss, fg20mReq; ++ ++ if ((prAdapter == NULL) ++ || (pucIE == NULL) ++ || (prBssInfo == NULL) ++ || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ /* Record it to channel list to change 20/40 bandwidth */ ++ ucPriChannel = 0; ++ eSCO = CHNL_EXT_SCN; ++ ++ fgHtBss = FALSE; ++ fg20mReq = FALSE; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ { ++ P_IE_HT_CAP_T prHtCap; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ if (prHtCap->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) ++ fg20mReq = TRUE; ++ fgHtBss = TRUE; ++ break; ++ } ++ case ELEM_ID_HT_OP: ++ { ++ P_IE_HT_OP_T prHtOp; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ ++ prHtOp = (P_IE_HT_OP_T) pucIE; ++ /* Workaround that some APs fill primary channel field by its ++ * secondary channel, but its DS IE is correct 20110610 ++ */ ++ if (ucPriChannel == 0) ++ ucPriChannel = prHtOp->ucPrimaryChannel; ++ ++ if ((prHtOp->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) ++ eSCO = (ENUM_CHNL_EXT_T) (prHtOp->ucInfo1 & HT_OP_INFO1_SCO); ++ break; ++ } ++ case ELEM_ID_20_40_BSS_COEXISTENCE: ++ { ++ P_IE_20_40_COEXIST_T prCoexist; ++ ++ if (IE_LEN(pucIE) != (sizeof(IE_20_40_COEXIST_T) - 2)) ++ break; ++ ++ prCoexist = (P_IE_20_40_COEXIST_T) pucIE; ++ if (prCoexist->ucData & BSS_COEXIST_40M_INTOLERANT) ++ fg20mReq = TRUE; ++ break; ++ } ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) != (sizeof(IE_DS_PARAM_SET_T) - 2)) ++ break; ++ ucPriChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ /* To do: Update channel list and 5G band. All channel lists have the same ++ * update procedure. We should give it the entry pointer of desired ++ * channel list. ++ */ ++ if (HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr) != BAND_2G4) ++ return FALSE; ++ ++ if (ucPriChannel == 0 || ucPriChannel > 14) ++ ucPriChannel = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); ++ ++ if (fgHtBss) { ++ ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_PriChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_PriChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_PriChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_PriChnlList[0]++; ++ } ++ ++ /* Update secondary channel */ ++ if (eSCO != CHNL_EXT_SCN) { ++ ucSecChannel = (eSCO == CHNL_EXT_SCA) ? (ucPriChannel + 4) : (ucPriChannel - 4); ++ ++ ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_SecChnlList[i] == ucSecChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_SecChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_SecChnlList[i] = ucSecChannel; ++ prBssInfo->auc2G_SecChnlList[0]++; ++ } ++ } ++ ++ /* Update 20M bandwidth request channels */ ++ if (fg20mReq) { ++ ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_20mReqChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_20mReqChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_20mReqChnlList[0]++; ++ } ++ } ++ } else { ++ /* Update non-HT channel list */ ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { ++ if (prBssInfo->auc2G_NonHtChnlList[i] == ucPriChannel) ++ break; ++ } ++ if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { ++ prBssInfo->auc2G_NonHtChnlList[i] = ucPriChannel; ++ prBssInfo->auc2G_NonHtChnlList[0]++; ++ } ++ ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief AIS or P2P GC. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN ++rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ if ((prAdapter == NULL) ++ || (pucIE == NULL) ++ || (prBssInfo == NULL) ++ || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++#if 0 /* SW migration 2010/8/20 */ ++ /* Note: we shall not update parameters when scanning, otherwise ++ * channel and bandwidth will not be correct or asserted failure ++ * during scanning. ++ * Note: remove channel checking. All received Beacons should be processed ++ * if measurement or other actions are executed in adjacent channels ++ * and Beacon content checking mechanism is not disabled. ++ */ ++ if (IS_SCAN_ACTIVE() ++ /* || prBssInfo->ucPrimaryChannel != CHNL_NUM_BY_SWRFB(prSwRfb) */ ++ ) { ++ return FALSE; ++ } ++#endif ++ ++ /* Handle change of slot time */ ++ prBssInfo->u2CapInfo = ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->u2CapInfo; ++ prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; ++ ++ rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgNewParameter; ++ UINT_8 ucNetIdx; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ fgNewParameter = FALSE; ++ ++ /* When concurrent networks exist, GO shall have the same handle as ++ * the other BSS, so the Beacon shall be processed for bandwidth and ++ * protection mechanism. ++ * Note1: we do not have 2 AP (GO) cases simultaneously now. ++ * Note2: If we are GO, concurrent AIS AP should detect it and reflect ++ * action in its Beacon, so AIS STA just follows Beacon from AP. ++ */ ++ RLM_NET_FOR_EACH_NO_BOW(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ if (IS_BSS_ACTIVE(prBssInfo)) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && ++ prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* P2P client or AIS infra STA */ ++ if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID, ((P_WLAN_MAC_MGMT_HEADER_T) ++ (prSwRfb->pvHeader))->aucBSSID)) { ++ ++ fgNewParameter = rlmRecBcnInfoForClient(prAdapter, ++ prBssInfo, prSwRfb, pucIE, u2IELength); ++ } else { ++ fgNewParameter = rlmRecBcnFromNeighborForClient(prAdapter, ++ prBssInfo, prSwRfb, pucIE, ++ u2IELength); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || ++ prBssInfo->eCurrentOPMode == OP_MODE_P2P_DEVICE)) { ++ /* AP scan to check if 20/40M bandwidth is permitted */ ++ rlmRecBcnFromNeighborForClient(prAdapter, prBssInfo, prSwRfb, pucIE, u2IELength); ++ } ++#endif ++ else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { ++ /* Do nothing */ ++ /* To do: Ad-hoc */ ++ } ++ ++ /* Appy new parameters if necessary */ ++ if (fgNewParameter) { ++ DBGLOG(RLM, TRACE, "rlmProcessBcn\n"); ++ rlmSyncOperationParams(prAdapter, prBssInfo); ++ fgNewParameter = FALSE; ++ } ++ } /* end of IS_BSS_ACTIVE() */ ++ } /* end of RLM_NET_FOR_EACH_NO_BOW */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ UINT_8 ucPriChannel; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prStaRec == prBssInfo->prStaRecOfAP); ++ ++ /* To do: the invoked function is used to clear all members. It may be ++ * done by center mechanism in invoker. ++ */ ++ rlmBssReset(prAdapter, prBssInfo); ++ ++ prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; ++ ++ ucPriChannel = rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); ++ if (ucPriChannel > 0) ++ prBssInfo->ucPrimaryChannel = ucPriChannel; ++ ++ if (!RLM_NET_IS_11N(prBssInfo) || !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) ++ prBssInfo->fg40mBwAllowed = FALSE; ++ ++ /* Note: Update its capabilities to WTBL by cnmStaRecChangeState(), which ++ * shall be invoked afterwards. ++ * Update channel, bandwidth and protection mode by nicUpdateBss() ++ */ ++#if 1 ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ ++ DBGLOG(P2P, WARN, "Force P2P BW to 20\n"); ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prCmdBody && prBssInfo); ++ if (!prCmdBody || !prBssInfo) ++ return; ++ ++ prCmdBody->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; ++ prCmdBody->ucRfBand = (UINT_8) prBssInfo->eBand; ++ prCmdBody->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; ++ prCmdBody->ucRfSco = (UINT_8) prBssInfo->eBssSCO; ++ prCmdBody->ucErpProtectMode = (UINT_8) prBssInfo->fgErpProtectMode; ++ prCmdBody->ucHtProtectMode = (UINT_8) prBssInfo->eHtProtectMode; ++ prCmdBody->ucGfOperationMode = (UINT_8) prBssInfo->eGfOperationMode; ++ prCmdBody->ucTxRifsMode = (UINT_8) prBssInfo->eRifsOperationMode; ++ prCmdBody->u2HtOpInfo3 = prBssInfo->u2HtOpInfo3; ++ prCmdBody->u2HtOpInfo2 = prBssInfo->u2HtOpInfo2; ++ prCmdBody->ucHtOpInfo1 = prBssInfo->ucHtOpInfo1; ++ prCmdBody->ucUseShortPreamble = prBssInfo->fgUseShortPreamble; ++ prCmdBody->ucUseShortSlotTime = prBssInfo->fgUseShortSlotTime; ++ prCmdBody->ucCheckId = 0x72; ++ ++ if (RLM_NET_PARAM_VALID(prBssInfo)) { ++ DBGLOG(RLM, INFO, "N=%d b=%d c=%d s=%d e=%d h=%d I=0x%02x l=%d p=%d\n", ++ prCmdBody->ucNetTypeIndex, prCmdBody->ucRfBand, ++ prCmdBody->ucPrimaryChannel, prCmdBody->ucRfSco, ++ prCmdBody->ucErpProtectMode, prCmdBody->ucHtProtectMode, ++ prCmdBody->ucHtOpInfo1, prCmdBody->ucUseShortSlotTime, ++ prCmdBody->ucUseShortPreamble); ++ } else { ++ DBGLOG(RLM, TRACE, "N=%d closed\n", prCmdBody->ucNetTypeIndex); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will operation parameters based on situations of ++* concurrent networks. Channel, bandwidth, protection mode, supported ++* rate will be modified. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_CMD_SET_BSS_RLM_PARAM_T prCmdBody; ++ WLAN_STATUS rStatus; ++ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ prCmdBody = (P_CMD_SET_BSS_RLM_PARAM_T) ++ cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_BSS_RLM_PARAM_T)); ++ ASSERT(prCmdBody); ++ ++ /* To do: exception handle */ ++ if (!prCmdBody) { ++ DBGLOG(RLM, WARN, "No buf for sync RLM params (Net=%d)\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ rlmFillSyncCmdParam(prCmdBody, prBssInfo); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_BSS_RLM_PARAM, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_BSS_RLM_PARAM_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdBody, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++ cnmMemFree(prAdapter, prCmdBody); ++} ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function should be invoked after judging successful association. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ P_IE_HT_CAP_T prHtCap; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_HT_CAP: ++ if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) ++ break; ++ prHtCap = (P_IE_HT_CAP_T) pucIE; ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ break; ++ ++ default: ++ break; ++ } /* end of switch */ ++ } /* end of IE_FOR_EACH */ ++} ++#endif /* CFG_SUPPORT_AAA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is for both STA and AP modes ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) ++ rlmBssInitForAP(prAdapter, prBssInfo); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief It is for both STA and AP modes ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ rlmBssReset(prAdapter, prBssInfo); ++ ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ ++ /* Assume FW state is updated by CMD_ID_SET_BSS_INFO, so ++ * the sync CMD is not needed here. ++ */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief All RLM timers will also be stopped. ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prBssInfo); ++ ++ /* HT related parameters */ ++ prBssInfo->ucHtOpInfo1 = 0; /* RIFS disabled. 20MHz */ ++ prBssInfo->u2HtOpInfo2 = 0; ++ prBssInfo->u2HtOpInfo3 = 0; ++ ++ prBssInfo->eBssSCO = 0; ++ prBssInfo->fgErpProtectMode = 0; ++ prBssInfo->eHtProtectMode = 0; ++ prBssInfo->eGfOperationMode = 0; ++ prBssInfo->eRifsOperationMode = 0; ++ ++ /* OBSS related parameters */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ prBssInfo->auc2G_PriChnlList[0] = 0; ++ prBssInfo->auc2G_SecChnlList[0] = 0; ++ prBssInfo->auc5G_20mReqChnlList[0] = 0; ++ prBssInfo->auc5G_NonHtChnlList[0] = 0; ++ prBssInfo->auc5G_PriChnlList[0] = 0; ++ prBssInfo->auc5G_SecChnlList[0] = 0; ++ ++ /* All RLM timers will also be stopped */ ++ cnmTimerStopTimer(prAdapter, &prBssInfo->rObssScanTimer); ++ prBssInfo->u2ObssScanInterval = 0; ++ ++ prBssInfo->fgObssErpProtectMode = 0; /* GO only */ ++ prBssInfo->eObssHtProtectMode = 0; /* GO only */ ++ prBssInfo->eObssGfOperationMode = 0; /* GO only */ ++ prBssInfo->fgObssRifsOperationMode = 0; /* GO only */ ++ prBssInfo->fgObssActionForcedTo20M = 0; /* GO only */ ++ prBssInfo->fgObssBeaconForcedTo20M = 0; /* GO only */ ++} ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function handle spectrum management action frame ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_CHANNEL_SWITCH_FRAME prRxFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ DBGLOG(RLM, INFO, "[5G DFS]rlmProcessSpecMgtAction \r\n"); ++ ++ prRxFrame = (P_ACTION_CHANNEL_SWITCH_FRAME) prSwRfb->pvHeader; ++ DBGLOG(RLM, INFO, "[5G DFS]prRxFrame->ucAction[%d] \r\n", prRxFrame->ucAction); ++ if (prRxFrame->ucAction == ACTION_CHNL_SWITCH) ++ rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) prRxFrame->aucInfoElem); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function process Channel Switch IE ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE) ++{ ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prChannelSwitchIE); ++ ++ DBGLOG(RLM, INFO, "[5G DFS] rlmProcessChannelSwitchIE \r\n"); ++ DBGLOG(RLM, INFO, "[5G DFS] ucChannelSwitchMode[%d], ucChannelSwitchCount[%d], ucNewChannelNum[%d] \r\n", ++ prChannelSwitchIE->ucChannelSwitchMode, ++ prChannelSwitchIE->ucChannelSwitchCount, prChannelSwitchIE->ucNewChannelNum); ++ if (prChannelSwitchIE->ucChannelSwitchMode == 1) { ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ DBGLOG(RLM, INFO, "[5G DFS] switch channel [%d]->[%d] \r\n", prAisBssInfo->ucPrimaryChannel, ++ prChannelSwitchIE->ucNewChannelNum); ++ prAisBssInfo->ucPrimaryChannel = prChannelSwitchIE->ucNewChannelNum; ++ nicUpdateBss(prAdapter, prAisBssInfo->ucNetTypeIndex); ++ } ++ ++} ++ ++#endif ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++VOID ++rlmTxRateEnhanceConfig( ++ P_ADAPTER_T prAdapter ++ ) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_RLM_INFO_T rTxRInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* suggestion from Tsaiyuan.Hsu */ ++ kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); ++ rTxRInfo.fgIsErrRatioEnhanceApplied = TRUE; ++ rTxRInfo.ucErrRatio2LimitMinRate = 3; ++ rTxRInfo.ucMinLegacyRateIdx = 2; ++ rTxRInfo.cMinRssiThreshold = -60; ++ rTxRInfo.fgIsRtsApplied = TRUE; ++ rTxRInfo.ucRecoverTime = 60; ++ ++ DBGLOG(RLM, INFO, "Enable tx rate enhance function\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxRateInfo, ++ &rTxRInfo, ++ sizeof(rTxRInfo), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(RLM, WARN, "set tx rate advance info fail 0x%lx\n", rStatus); ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TX Auto Rate module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT_32 u4Subcmd; ++ ++ ++ /* parse TAR sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(RLM, INFO, " sub command = %u\n", (UINT32)u4Subcmd); ++ ++ /* handle different sub-command */ ++ switch (u4Subcmd) { ++ case 0x00: /* configure */ ++ /* iwpriv wlan0 set_str_cmd 1_0_0_1_3_2_60_1_60 */ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_RLM_INFO_T rTxRInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); ++ rTxRInfo.u4Version = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.fgIsErrRatioEnhanceApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucErrRatio2LimitMinRate = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucMinLegacyRateIdx = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.cMinRssiThreshold = 0 - CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.fgIsRtsApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rTxRInfo.ucRecoverTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(RLM, INFO, " rlmCmd = %u %u %u %u %d %u %u\n", ++ rTxRInfo.u4Version, ++ rTxRInfo.fgIsErrRatioEnhanceApplied, ++ rTxRInfo.ucErrRatio2LimitMinRate, ++ rTxRInfo.ucMinLegacyRateIdx, ++ rTxRInfo.cMinRssiThreshold, ++ rTxRInfo.fgIsRtsApplied, ++ rTxRInfo.ucRecoverTime)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxRateInfo, ++ &rTxRInfo, ++ sizeof(rTxRInfo), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ break; ++ ++ default: ++ break; ++ } ++} ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c +new file mode 100644 +index 000000000000..5e127488ea49 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c +@@ -0,0 +1,1791 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_domain.c#1 ++*/ ++ ++/*! \file "rlm_domain.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_domain.c ++ * ++ * 11 10 2011 cm.chang ++ * NULL ++ * Modify debug message for XLOG ++ * ++ * 09 29 2011 cm.chang ++ * NULL ++ * Change the function prototype of rlmDomainGetChnlList() ++ * ++ * 09 23 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Let channel number to zero if band is illegal ++ * ++ * 09 22 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Exclude channel list with illegal band ++ * ++ * 09 15 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use defined country group to have a change to add new group ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 06 01 2011 cm.chang ++ * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function ++ * Provide legal channel function based on domain ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 02 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Export rlmDomainGetDomainInfo for p2p driver. ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 03 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Filter out not supported RF freq when reporting available chnl list ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Provide query function about full channel list. ++ * ++ * Dec 1 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++#include "rlm_txpwr_init.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* The following country or domain shall be set from host driver. ++ * And host driver should pass specified DOMAIN_INFO_ENTRY to MT6620 as ++ * the channel list of being a STA to do scanning/searching AP or being an ++ * AP to choose an adequate channel if auto-channel is set. ++ */ ++ ++/* Define mapping tables between country code and its channel set ++ */ ++static const UINT_16 g_u2CountryGroup0[] = { ++ COUNTRY_CODE_AO, COUNTRY_CODE_BZ, COUNTRY_CODE_BJ, COUNTRY_CODE_BT, ++ COUNTRY_CODE_BO, COUNTRY_CODE_BI, COUNTRY_CODE_CM, COUNTRY_CODE_CF, ++ COUNTRY_CODE_TD, COUNTRY_CODE_KM, COUNTRY_CODE_CD, COUNTRY_CODE_CG, ++ COUNTRY_CODE_CI, COUNTRY_CODE_DJ, COUNTRY_CODE_GQ, COUNTRY_CODE_ER, ++ COUNTRY_CODE_FJ, COUNTRY_CODE_GA, COUNTRY_CODE_GM, COUNTRY_CODE_GN, ++ COUNTRY_CODE_GW, COUNTRY_CODE_RKS, COUNTRY_CODE_KG, COUNTRY_CODE_LY, ++ COUNTRY_CODE_MG, COUNTRY_CODE_ML, COUNTRY_CODE_NR, COUNTRY_CODE_NC, ++ COUNTRY_CODE_ST, COUNTRY_CODE_SC, COUNTRY_CODE_SL, COUNTRY_CODE_SB, ++ COUNTRY_CODE_SO, COUNTRY_CODE_SR, COUNTRY_CODE_SZ, COUNTRY_CODE_TJ, ++ COUNTRY_CODE_TG, COUNTRY_CODE_TO, COUNTRY_CODE_TM, COUNTRY_CODE_TV, ++ COUNTRY_CODE_VU, COUNTRY_CODE_YE ++}; ++ ++static const UINT_16 g_u2CountryGroup1[] = { ++ COUNTRY_CODE_AS, COUNTRY_CODE_AI, COUNTRY_CODE_BM, COUNTRY_CODE_CA, ++ COUNTRY_CODE_KY, COUNTRY_CODE_GU, COUNTRY_CODE_FM, COUNTRY_CODE_PR, ++ COUNTRY_CODE_US, COUNTRY_CODE_VI ++}; ++ ++static const UINT_16 g_u2CountryGroup2[] = { ++ COUNTRY_CODE_AR, COUNTRY_CODE_AU, COUNTRY_CODE_AZ, COUNTRY_CODE_BW, ++ COUNTRY_CODE_KH, COUNTRY_CODE_CX, COUNTRY_CODE_CO, COUNTRY_CODE_CR, ++#if (CFG_CN_SUPPORT_CLASS121 == 1) ++ COUNTRY_CODE_CN, ++#endif ++ COUNTRY_CODE_EC, COUNTRY_CODE_GD, COUNTRY_CODE_GT, COUNTRY_CODE_HK, ++ COUNTRY_CODE_KI, COUNTRY_CODE_LB, COUNTRY_CODE_LR, COUNTRY_CODE_MN, ++ COUNTRY_CODE_AN, COUNTRY_CODE_NZ, COUNTRY_CODE_NI, COUNTRY_CODE_PW, ++ COUNTRY_CODE_PY, COUNTRY_CODE_PE, COUNTRY_CODE_PH, COUNTRY_CODE_WS, ++ COUNTRY_CODE_SG, COUNTRY_CODE_LK, COUNTRY_CODE_TH, COUNTRY_CODE_TT, ++ COUNTRY_CODE_UY, COUNTRY_CODE_VN ++}; ++ ++static const UINT_16 g_u2CountryGroup3[] = { ++ COUNTRY_CODE_AW, COUNTRY_CODE_LA, COUNTRY_CODE_SA, COUNTRY_CODE_AE, ++ COUNTRY_CODE_UG ++}; ++ ++static const UINT_16 g_u2CountryGroup4[] = { COUNTRY_CODE_MM }; ++ ++static const UINT_16 g_u2CountryGroup5[] = { ++ COUNTRY_CODE_AL, COUNTRY_CODE_DZ, COUNTRY_CODE_AD, COUNTRY_CODE_AT, ++ COUNTRY_CODE_BY, COUNTRY_CODE_BE, COUNTRY_CODE_BA, COUNTRY_CODE_VG, ++ COUNTRY_CODE_BG, COUNTRY_CODE_CV, COUNTRY_CODE_HR, COUNTRY_CODE_CY, ++ COUNTRY_CODE_CZ, COUNTRY_CODE_DK, COUNTRY_CODE_EE, COUNTRY_CODE_ET, ++ COUNTRY_CODE_FI, COUNTRY_CODE_FR, COUNTRY_CODE_GF, COUNTRY_CODE_PF, ++ COUNTRY_CODE_TF, COUNTRY_CODE_GE, COUNTRY_CODE_DE, COUNTRY_CODE_GH, ++ COUNTRY_CODE_GR, COUNTRY_CODE_GP, COUNTRY_CODE_HU, COUNTRY_CODE_IS, ++ COUNTRY_CODE_IQ, COUNTRY_CODE_IE, COUNTRY_CODE_IT, COUNTRY_CODE_KE, ++ COUNTRY_CODE_LV, COUNTRY_CODE_LS, COUNTRY_CODE_LI, COUNTRY_CODE_LT, ++ COUNTRY_CODE_LU, COUNTRY_CODE_MK, COUNTRY_CODE_MT, COUNTRY_CODE_MQ, ++ COUNTRY_CODE_MR, COUNTRY_CODE_MU, COUNTRY_CODE_YT, COUNTRY_CODE_MD, ++ COUNTRY_CODE_MC, COUNTRY_CODE_ME, COUNTRY_CODE_MS, COUNTRY_CODE_NL, ++ COUNTRY_CODE_NO, COUNTRY_CODE_OM, COUNTRY_CODE_PL, COUNTRY_CODE_PT, ++ COUNTRY_CODE_RE, COUNTRY_CODE_RO, COUNTRY_CODE_MF, COUNTRY_CODE_SM, ++ COUNTRY_CODE_SN, COUNTRY_CODE_RS, COUNTRY_CODE_SK, COUNTRY_CODE_SI, ++ COUNTRY_CODE_ZA, COUNTRY_CODE_ES, COUNTRY_CODE_SE, COUNTRY_CODE_CH, ++ COUNTRY_CODE_TR, COUNTRY_CODE_TC, COUNTRY_CODE_GB, COUNTRY_CODE_VA, ++ COUNTRY_CODE_EU ++}; ++ ++static const UINT_16 g_u2CountryGroup6[] = { COUNTRY_CODE_JP }; ++ ++static const UINT_16 g_u2CountryGroup7[] = { ++ COUNTRY_CODE_AM, COUNTRY_CODE_IL, COUNTRY_CODE_KW, COUNTRY_CODE_MA, ++ COUNTRY_CODE_NE, COUNTRY_CODE_TN, COUNTRY_CODE_MA ++}; ++ ++static const UINT_16 g_u2CountryGroup8[] = { COUNTRY_CODE_NP }; ++ ++static const UINT_16 g_u2CountryGroup9[] = { COUNTRY_CODE_AF }; ++ ++static const UINT_16 g_u2CountryGroup10[] = { ++ COUNTRY_CODE_AG, COUNTRY_CODE_BS, COUNTRY_CODE_BH, COUNTRY_CODE_BB, ++ COUNTRY_CODE_BN, COUNTRY_CODE_CL, COUNTRY_CODE_EG, ++#if (CFG_CN_SUPPORT_CLASS121 == 0) ++ COUNTRY_CODE_CN, ++#endif ++ COUNTRY_CODE_SV, COUNTRY_CODE_IN, COUNTRY_CODE_MY, COUNTRY_CODE_MV, ++ COUNTRY_CODE_PA, COUNTRY_CODE_VE, COUNTRY_CODE_ZM ++}; ++ ++static const UINT_16 g_u2CountryGroup11[] = { COUNTRY_CODE_JO, COUNTRY_CODE_PG }; ++ ++static const UINT_16 g_u2CountryGroup12[] = { ++ COUNTRY_CODE_BF, COUNTRY_CODE_GY, COUNTRY_CODE_HT, COUNTRY_CODE_HN, ++ COUNTRY_CODE_JM, COUNTRY_CODE_MO, COUNTRY_CODE_MW, COUNTRY_CODE_PK, ++ COUNTRY_CODE_QA, COUNTRY_CODE_RW, COUNTRY_CODE_KN, COUNTRY_CODE_TZ ++}; ++ ++static const UINT_16 g_u2CountryGroup13[] = { COUNTRY_CODE_ID }; ++ ++static const UINT_16 g_u2CountryGroup14[] = { COUNTRY_CODE_KR }; ++ ++static const UINT_16 g_u2CountryGroup15[] = { COUNTRY_CODE_NG }; ++ ++static const UINT_16 g_u2CountryGroup16[] = { ++ COUNTRY_CODE_BD, COUNTRY_CODE_BR, COUNTRY_CODE_DM, COUNTRY_CODE_DO, ++ COUNTRY_CODE_FK, COUNTRY_CODE_KZ, COUNTRY_CODE_MX, COUNTRY_CODE_MZ, ++ COUNTRY_CODE_NA, COUNTRY_CODE_RU, COUNTRY_CODE_LC, COUNTRY_CODE_VC, ++ COUNTRY_CODE_UA, COUNTRY_CODE_UZ, COUNTRY_CODE_ZW ++}; ++ ++static const UINT_16 g_u2CountryGroup17[] = { COUNTRY_CODE_MP }; ++ ++static const UINT_16 g_u2CountryGroup18[] = { COUNTRY_CODE_TW }; ++ ++static const UINT_16 g_u2CountryGroup19[] = { ++ COUNTRY_CODE_CK, COUNTRY_CODE_CU, COUNTRY_CODE_TL, COUNTRY_CODE_FO, ++ COUNTRY_CODE_GI, COUNTRY_CODE_GG, COUNTRY_CODE_IR, COUNTRY_CODE_IM, ++ COUNTRY_CODE_JE, COUNTRY_CODE_KP, COUNTRY_CODE_MH, COUNTRY_CODE_NU, ++ COUNTRY_CODE_NF, COUNTRY_CODE_PS, COUNTRY_CODE_PN, COUNTRY_CODE_PM, ++ COUNTRY_CODE_SS, COUNTRY_CODE_SD, COUNTRY_CODE_SY ++}; ++ ++static const UINT_16 g_u2CountryGroup20[] = { ++ COUNTRY_CODE_DF, COUNTRY_CODE_FF ++ /* When country code is not found and no matched NVRAM setting, ++ * this domain info will be used. ++ */ ++}; ++ ++static const UINT_16 g_u2CountryGroup21[] = { ++ COUNTRY_CODE_UDF ++}; ++ ++DOMAIN_INFO_ENTRY arSupportedRegDomains[] = { ++ { ++ (PUINT_16) g_u2CountryGroup0, sizeof(g_u2CountryGroup0) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup1, sizeof(g_u2CountryGroup1) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup2, sizeof(g_u2CountryGroup2) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup3, sizeof(g_u2CountryGroup3) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup4, sizeof(g_u2CountryGroup4) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup5, sizeof(g_u2CountryGroup5) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup6, sizeof(g_u2CountryGroup6) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 14, 1, FALSE} ++ , /* CH_SET_2G4_14_14 */ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup7, sizeof(g_u2CountryGroup7) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup8, sizeof(g_u2CountryGroup8) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup9, sizeof(g_u2CountryGroup9) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_UPPER_NA */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup10, sizeof(g_u2CountryGroup10) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup11, sizeof(g_u2CountryGroup11) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup12, sizeof(g_u2CountryGroup12) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup13, sizeof(g_u2CountryGroup13) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_NA */ ++ {118, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_MID_NA */ ++ {121, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_WW_NA */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup14, sizeof(g_u2CountryGroup14) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 8, FALSE} ++ , /* CH_SET_UNII_WW_100_128 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} ++ , /* CH_SET_UNII_UPPER_149_161 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup15, sizeof(g_u2CountryGroup15) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_NULL, 0, 0, 0, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup16, sizeof(g_u2CountryGroup16) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup17, sizeof(g_u2CountryGroup17) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup18, sizeof(g_u2CountryGroup18) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} ++ , /* CH_SET_2G4_1_11 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE} ++ , /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ (PUINT_16) g_u2CountryGroup19, sizeof(g_u2CountryGroup19) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ /* Note: Default group if no matched country code */ ++ (PUINT_16) g_u2CountryGroup20, sizeof(g_u2CountryGroup20) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} ++ , /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} ++ , /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} ++ , /* CH_SET_UNII_WW_100_144 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} ++ , /* CH_SET_UNII_UPPER_149_165 */ ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++ , ++ { ++ /* Note: for customer configured their own scanning list and passive scan list */ ++ (PUINT_16) g_u2CountryGroup21, sizeof(g_u2CountryGroup21) / 2, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 1, 12, FALSE} ++ , /* CH_SET_2G4_1_13 */ ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, FALSE} ++ , ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, FALSE} ++ , ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, FALSE} ++ , ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, FALSE} ++ , ++ {0, BAND_NULL, 0, 0, 0, FALSE} ++ } ++ } ++}; ++ ++static UINT_16 g_u2CountryGroup0_Passive[] = { ++ COUNTRY_CODE_UDF ++}; ++ ++DOMAIN_INFO_ENTRY arSupportedRegDomains_Passive[] = { ++ { ++ /* Default passive scan channel table is empty */ ++ COUNTRY_CODE_NULL, 0, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 11, 0, 0}, /* CH_SET_2G4_1_14 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ ++ } ++ }, ++ { ++ /* User Defined passive scan channel table */ ++ g_u2CountryGroup0_Passive, 0, ++ { ++ {81, BAND_2G4, CHNL_SPAN_5, 12, 1, 0}, /* CH_SET_2G4_1_14 */ ++ {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, ++ ++ {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ ++ {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ ++ {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ ++ {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ ++ } ++ } ++}; ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++SUBBAND_CHANNEL_T g_rRlmSubBand[] = { ++ ++ {BAND_2G4_LOWER_BOUND, BAND_2G4_UPPER_BOUND, 1, 0} ++ , /* 2.4G */ ++ {UNII1_LOWER_BOUND, UNII1_UPPER_BOUND, 2, 0} ++ , /* ch36,38,40,..,48 */ ++ {UNII2A_LOWER_BOUND, UNII2A_UPPER_BOUND, 2, 0} ++ , /* ch52,54,56,..,64 */ ++ {UNII2C_LOWER_BOUND, UNII2C_UPPER_BOUND, 2, 0} ++ , /* ch100,102,104,...,144 */ ++ {UNII3_LOWER_BOUND, UNII3_UPPER_BOUND, 2, 0} ++ /* ch149,151,153,....,173 */ ++}; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter) ++{ ++#define REG_DOMAIN_DEF_IDX 20 /* Default country domain */ ++#define REG_DOMAIN_GROUP_NUM \ ++ (sizeof(arSupportedRegDomains) / sizeof(DOMAIN_INFO_ENTRY)) ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_REG_INFO_T prRegInfo; ++ UINT_16 u2TargetCountryCode; ++ UINT_16 i, j; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->prDomainInfo) ++ return prAdapter->prDomainInfo; ++ ++ prRegInfo = &prAdapter->prGlueInfo->rRegInfo; ++ ++ DBGLOG(RLM, TRACE, "eRegChannelListMap=%d, u2CountryCode=0x%04x\n", ++ prRegInfo->eRegChannelListMap, ++ prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ /* ++ * Domain info can be specified by given idx of arSupportedRegDomains table, ++ * customized, or searched by country code, ++ * only one is set among these three methods in NVRAM. ++ */ ++ if (prRegInfo->eRegChannelListMap == REG_CH_MAP_TBL_IDX && ++ prRegInfo->ucRegChannelListIndex < REG_DOMAIN_GROUP_NUM) { ++ /* by given table idx */ ++ DBGLOG(RLM, TRACE, "ucRegChannelListIndex=%d\n", prRegInfo->ucRegChannelListIndex); ++ prDomainInfo = &arSupportedRegDomains[prRegInfo->ucRegChannelListIndex]; ++ } else if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { ++ /* by customized */ ++ prDomainInfo = &prRegInfo->rDomainInfo; ++ } else { ++ /* by country code */ ++ u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ ++ for (i = 0; i < REG_DOMAIN_GROUP_NUM; i++) { ++ prDomainInfo = &arSupportedRegDomains[i]; ++ ++ if ((prDomainInfo->u4CountryNum && prDomainInfo->pu2CountryGroup) || ++ prDomainInfo->u4CountryNum == 0) { ++ for (j = 0; j < prDomainInfo->u4CountryNum; j++) { ++ if (prDomainInfo->pu2CountryGroup[j] == u2TargetCountryCode) ++ break; ++ } ++ if (j < prDomainInfo->u4CountryNum) ++ break; /* Found */ ++ } ++ } ++ ++ /* If no matched country code, use the default country domain */ ++ if (i >= REG_DOMAIN_GROUP_NUM) { ++ DBGLOG(RLM, INFO, "No matched country code, use the default country domain\n"); ++ prDomainInfo = &arSupportedRegDomains[REG_DOMAIN_DEF_IDX]; ++ } ++ } ++ ++ prAdapter->prDomainInfo = prDomainInfo; ++ return prDomainInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] The input variable pointed by pucNumOfChannel is the max ++* arrary size. The return value indciates meaning list size. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++rlmDomainGetChnlList(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, ++ UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ UINT_8 i, j, ucNum; ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(paucChannelList); ++ ASSERT(pucNumOfChannel); ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ ucNum = 0; ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ ++ if (prSubband->ucBand == BAND_NULL || prSubband->ucBand >= BAND_NUM || ++ (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand)) ++ continue; ++ ++ if (fgNoDfs == TRUE && prSubband->fgDfs == TRUE) ++ continue; ++ ++ if (eSpecificBand == BAND_NULL || prSubband->ucBand == eSpecificBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if (ucNum >= ucMaxChannelNum) ++ break; ++ paucChannelList[ucNum].eBand = prSubband->ucBand; ++ paucChannelList[ucNum].ucChannelNum = ++ prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan; ++ ucNum++; ++ } ++ } ++ } ++ ++ *pucNumOfChannel = ucNum; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++ rlmDomainSendDomainInfoCmd(prAdapter, fgIsOid); ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ rlmDomainSendPwrLimitCmd(prAdapter); ++#endif ++ rlmDomainSendPassiveScanInfoCmd(prAdapter, fgIsOid); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_CMD_SET_DOMAIN_INFO_T prCmd; ++ P_DOMAIN_SUBBAND_INFO prSubBand; ++ UINT_8 i; ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); ++ return; ++ } ++ kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ ++ prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ prCmd->u2IsSetPassiveScan = 0; ++ prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; ++ prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; ++ prCmd->aucReserved[0] = 0; ++ prCmd->aucReserved[1] = 0; ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubBand = &prDomainInfo->rSubBand[i]; ++ ++ prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; ++ prCmd->rSubBand[i].ucBand = prSubBand->ucBand; ++ ++ if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { ++ prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; ++ prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; ++ prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; ++ } ++ } ++ ++ /* Set domain info to chip */ ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_DOMAIN_INFO, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ fgIsOid, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ ++ (PUINT_8)prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ cnmMemFree(prAdapter, prCmd); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) ++{ ++#define REG_DOMAIN_PASSIVE_DEF_IDX 0 ++#define REG_DOMAIN_PASSIVE_UDF_IDX 1 ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ P_CMD_SET_DOMAIN_INFO_T prCmd; ++ P_DOMAIN_SUBBAND_INFO prSubBand; ++ UINT_8 i; ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); ++ return; ++ } ++ kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); ++ ++ prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; ++ prCmd->u2IsSetPassiveScan = 1; ++ prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; ++ prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; ++ prCmd->aucReserved[0] = 0; ++ prCmd->aucReserved[1] = 0; ++ ++ DBGLOG(RLM, TRACE, "u2CountryCode=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ if (prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_UDF) ++ prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_UDF_IDX]; ++ else ++ prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_DEF_IDX]; ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubBand = &prDomainInfo->rSubBand[i]; ++ ++ prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; ++ prCmd->rSubBand[i].ucBand = prSubBand->ucBand; ++ ++ if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { ++ prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; ++ prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; ++ prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; ++ } ++ } ++ ++ /* Set passive scan channel info to chip */ ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_DOMAIN_INFO, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ fgIsOid, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ cnmMemFree(prAdapter, prCmd); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return TRUE Legal channel ++* FALSE Illegal channel for current regulatory domain ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel) ++{ ++ UINT_8 i, j; ++ P_DOMAIN_SUBBAND_INFO prSubband; ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prAdapter); ++ ASSERT(prDomainInfo); ++ ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ prSubband = &prDomainInfo->rSubBand[i]; ++ ++ if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) ++ continue; ++ ++ if (prSubband->ucBand == eBand) { ++ for (j = 0; j < prSubband->ucNumChannels; j++) { ++ if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) ++ == ucChannel) { ++ return TRUE; ++ } ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in/out] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf) ++{ ++ /* ++ The Country element should only be included for Status Code 0 (Successful). ++ */ ++ UINT_32 u4IeLen; ++ UINT_8 aucClass[12] = { 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, ++ 0x1c, 0x1e, 0x20, 0x21 ++ }; ++ ++ /* ++ The Supported Operating Classes element is used by a STA to advertise the ++ operating classes that it is capable of operating with in this country. ++ ++ The Country element (see 8.4.2.10) allows a STA to configure its PHY and MAC ++ for operation when the operating triplet of Operating Extension Identifier, ++ Operating Class, and Coverage Class fields is present. ++ */ ++ SUP_OPERATING_CLASS_IE(pBuf)->ucId = ELEM_ID_SUP_OPERATING_CLASS; ++ SUP_OPERATING_CLASS_IE(pBuf)->ucLength = 1 + sizeof(aucClass); ++ SUP_OPERATING_CLASS_IE(pBuf)->ucCur = 0x0c; /* 0x51 */ ++ kalMemCopy(SUP_OPERATING_CLASS_IE(pBuf)->ucSup, aucClass, sizeof(aucClass)); ++ u4IeLen = (SUP_OPERATING_CLASS_IE(pBuf)->ucLength + 2); ++ pBuf += u4IeLen; ++ ++ COUNTRY_IE(pBuf)->ucId = ELEM_ID_COUNTRY_INFO; ++ COUNTRY_IE(pBuf)->ucLength = 6; ++ COUNTRY_IE(pBuf)->aucCountryStr[0] = 0x55; ++ COUNTRY_IE(pBuf)->aucCountryStr[1] = 0x53; ++ COUNTRY_IE(pBuf)->aucCountryStr[2] = 0x20; ++ COUNTRY_IE(pBuf)->arCountryStr[0].ucFirstChnlNum = 1; ++ COUNTRY_IE(pBuf)->arCountryStr[0].ucNumOfChnl = 11; ++ COUNTRY_IE(pBuf)->arCountryStr[0].cMaxTxPwrLv = 0x1e; ++ u4IeLen += (COUNTRY_IE(pBuf)->ucLength + 2); ++ ++ return u4IeLen; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (fgValid) : 0 -> inValid, 1 -> Valid ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh) ++{ ++ BOOLEAN fgValid = FALSE; ++ UINT_8 ucTemp = 0; ++ UINT_8 i; ++ /*Check Power limit table channel efficient or not */ ++ ++ for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { ++ if ((ucCentralCh >= g_rRlmSubBand[i].ucStartCh) && (ucCentralCh <= g_rRlmSubBand[i].ucEndCh)) ++ ucTemp = (ucCentralCh - g_rRlmSubBand[i].ucStartCh) % g_rRlmSubBand[i].ucInterval; ++ } ++ ++#if 0 ++ /*2.4G, ex 1, 2, 3 */ ++ if (ucCentralCh >= BAND_2G4_LOWER_BOUND && ucCentralCh <= BAND_2G4_UPPER_BOUND) ++ ucTemp = 0; ++ /*FCC- Spec : Band UNII-1, ex 36, 38, 40.... */ ++ else if (ucCentralCh >= UNII1_LOWER_BOUND && ucCentralCh <= UNII1_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII1_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-2A, ex 52, 54, 56.... */ ++ else if (ucCentralCh >= UNII2A_LOWER_BOUND && ucCentralCh <= UNII2A_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII2A_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-2C, ex 100, 102, 104.... */ ++ else if (ucCentralCh >= UNII2C_LOWER_BOUND && ucCentralCh <= UNII2C_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII2C_LOWER_BOUND) % 2; ++ /*FCC- Spec : Band UNII-3, ex 149, 151, 153... */ ++ else if (ucCentralCh >= UNII3_LOWER_BOUND && ucCentralCh <= UNII3_UPPER_BOUND) ++ ucTemp = (ucCentralCh - UNII3_LOWER_BOUND) % 2; ++#endif ++ if (ucTemp == 0) ++ fgValid = TRUE; ++ return fgValid; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) ++{ ++ UINT_8 ucCenterChannel; ++ ++ if (eExtend == CHNL_EXT_SCA) ++ ucCenterChannel = ucPriChannel + 2; ++ else if (eExtend == CHNL_EXT_SCB) ++ ucCenterChannel = ucPriChannel - 2; ++ else ++ ucCenterChannel = ucPriChannel; ++ ++ return ucCenterChannel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ++ ENUM_BAND_T eBand, ++ UINT_8 ucPriChannel, ++ ENUM_CHNL_EXT_T eExtend, ++ ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2) ++{ ++ UINT_8 ucCenterChannel; ++ BOOLEAN fgValidChannel = TRUE; ++ BOOLEAN fgValidBW = TRUE; ++ BOOLEAN fgValidRfSetting = TRUE; ++ UINT_32 u4PrimaryOffset; ++ ++ /*DBG msg for Channel InValid */ ++ if (eChannelWidth == CW_20_40MHZ) { ++ ucCenterChannel = rlmDomainGetCenterChannel(eBand, ucPriChannel, eExtend); ++ ++ /* Check Central Channel Valid or Not */ ++ fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); ++ if (fgValidChannel == FALSE) ++ DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); ++ } else if (eChannelWidth == CW_80MHZ) { ++ ucCenterChannel = ucChannelS1; ++ ++ /* Check Central Channel Valid or Not */ ++ fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); ++ if (fgValidChannel == FALSE) ++ DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); ++ } else if (eChannelWidth == CW_160MHZ) { ++ ucCenterChannel = ucChannelS2; ++ ++ /* Check Central Channel Valid or Not */ ++ /*TODo */ ++ } ++ ++ /* Check BW Setting Correct or Not */ ++ if (eBand == BAND_2G4) { ++ if (eChannelWidth != CW_20_40MHZ) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: B=%d, W=%d\n", eBand, eChannelWidth); ++ } ++ } else { ++ if (eChannelWidth == CW_80MHZ) { ++ u4PrimaryOffset = CAL_CH_OFFSET_80M(ucPriChannel, ucCenterChannel); ++ if (u4PrimaryOffset > 4) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); ++ } ++ } else if (eChannelWidth == CW_160MHZ) { ++ u4PrimaryOffset = CAL_CH_OFFSET_160M(ucPriChannel, ucCenterChannel); ++ if (u4PrimaryOffset > 8) { ++ fgValidBW = FALSE; ++ DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); ++ } ++ } ++ } ++ ++ if ((fgValidBW == FALSE) || (fgValidChannel == FALSE)) ++ fgValidRfSetting = FALSE; ++ ++ return fgValidRfSetting; ++ ++} ++ ++#if CFG_SUPPORT_PWR_LIMIT_COUNTRY ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (fgValid) : 0 -> inValid, 1 -> Valid ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, ++ COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, ++ UINT_8 ucPwrLimitNum) ++{ ++ UINT_8 i; ++ BOOLEAN fgValid = TRUE; ++ PINT_8 prPwrLimit; ++ ++ prPwrLimit = &rPowerLimitTableConfiguration.aucPwrLimit[0]; ++ ++ for (i = 0; i < ucPwrLimitNum; i++, prPwrLimit++) { ++ if (*prPwrLimit > MAX_TX_POWER || *prPwrLimit < MIN_TX_POWER) { ++ fgValid = FALSE; ++ break; /*Find out Wrong Power limit */ ++ } ++ } ++ return fgValid; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter) ++{ ++ UINT_8 i, j; ++ UINT_16 u2CountryCodeTable, u2CountryCodeCheck; ++ BOOLEAN fgChannelValid = FALSE; ++ BOOLEAN fgPowerLimitValid = FALSE; ++ BOOLEAN fgEntryRepetetion = FALSE; ++ BOOLEAN fgTableValid = TRUE; ++ ++ /*Configuration Table Check */ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { ++ /*Table Country Code */ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ /*Repetition Entry Check */ ++ for (j = i + 1; ++ j < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); ++ j++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[j].aucCountryCode[0], &u2CountryCodeCheck); ++ if (((g_rRlmPowerLimitConfiguration[i].ucCentralCh) == ++ g_rRlmPowerLimitConfiguration[j].ucCentralCh) ++ && (u2CountryCodeTable == u2CountryCodeCheck)) { ++ fgEntryRepetetion = TRUE; ++ DBGLOG(RLM, LOUD, "Domain: Configuration Repetition CC=%c%c, Ch=%d\n", ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ } ++ } ++ ++ /*Channel Number Check */ ++ fgChannelValid = ++ rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ ++ /*Power Limit Check */ ++ fgPowerLimitValid = ++ rlmDomainCheckPowerLimitValid(prAdapter, g_rRlmPowerLimitConfiguration[i], PWR_LIMIT_NUM); ++ ++ if (fgChannelValid == FALSE || fgPowerLimitValid == FALSE) { ++ fgTableValid = FALSE; ++ DBGLOG(RLM, LOUD, "Domain: CC=%c%c, Ch=%d, Limit: %d,%d,%d,%d,%d\n", ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], ++ g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh, ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M], ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]); ++ } ++ ++ if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ DBGLOG(RLM, LOUD, "Domain: Full search down\n"); ++ break; /*End of country table entry */ ++ } ++ ++ } ++ ++ if (fgEntryRepetetion == FALSE) ++ DBGLOG(RLM, TRACE, "Domain: Configuration Table no Repetiton.\n"); ++ ++ /*Configuration Table no error */ ++ if (fgTableValid == TRUE) ++ prAdapter->fgIsPowerLimitTableValid = TRUE; ++ else ++ prAdapter->fgIsPowerLimitTableValid = FALSE; ++ ++ /*Default Table Check */ ++ fgEntryRepetetion = FALSE; ++ for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ for (j = i + 1; j < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); j++) { ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[j].aucCountryCode[0], &u2CountryCodeCheck); ++ if (u2CountryCodeTable == u2CountryCodeCheck) { ++ fgEntryRepetetion = TRUE; ++ DBGLOG(RLM, LOUD, ++ "Domain: Default Repetition CC=%c%c\n", ++ g_rRlmPowerLimitDefault[j].aucCountryCode[0], ++ g_rRlmPowerLimitDefault[j].aucCountryCode[1]); ++ } ++ } ++ } ++ if (fgEntryRepetetion == FALSE) ++ DBGLOG(RLM, TRACE, "Domain: Default Table no Repetiton.\n"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (u2TableIndex) : if 0xFFFF -> No Table Match ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode) ++{ ++ ++ UINT_16 i; ++ UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; ++ UINT_16 u2TableIndex = POWER_LIMIT_TABLE_NULL; /* No Table Match */ ++ ++ /*Default Table Index */ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ if (u2CountryCodeTable == u2CountryCode) { ++ u2TableIndex = i; ++ break; /*match country code */ ++ } else if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ u2TableIndex = i; ++ break; /*find last one country- Default */ ++ } ++ } ++ ++ DBGLOG(RLM, TRACE, "Domain: Default Table Index = %d\n", u2TableIndex); ++ ++ return u2TableIndex; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainBuildCmdByDefaultTable(P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd, UINT_16 u2DefaultTableIndex) ++{ ++ UINT_8 i, k; ++ P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT prPwrLimitSubBand; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; ++ ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ prPwrLimitSubBand = &g_rRlmPowerLimitDefault[u2DefaultTableIndex]; ++ ++ /*Build power limit cmd by default table information */ ++ ++ for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[i] < MAX_TX_POWER) { ++ for (k = g_rRlmSubBand[i].ucStartCh; k <= g_rRlmSubBand[i].ucEndCh; ++ k += g_rRlmSubBand[i].ucInterval) { ++ if ((prPwrLimitSubBand->ucPwrUnit & BIT(i)) == 0) { ++ prCmdPwrLimit->ucCentralCh = k; ++ prCmdPwrLimit->cPwrLimitCCK = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit20 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit40 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit80 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit160 = ++ prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ ++ } else { ++ /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 ++ * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ ++ prCmdPwrLimit->ucCentralCh = k; ++ prCmdPwrLimit->cPwrLimitCCK = prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit20 = prPwrLimitSubBand->aucPwrLimitSubBand[i]; ++ prCmdPwrLimit->cPwrLimit40 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 6; ++ if (prCmdPwrLimit->cPwrLimit40 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit40 = MAX_TX_POWER; ++ prCmdPwrLimit->cPwrLimit80 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 12; ++ if (prCmdPwrLimit->cPwrLimit80 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit80 = MAX_TX_POWER; ++ prCmdPwrLimit->cPwrLimit160 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 18; ++ if (prCmdPwrLimit->cPwrLimit160 > MAX_TX_POWER) ++ prCmdPwrLimit->cPwrLimit160 = MAX_TX_POWER; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ } ++ } ++ ++#if 0 ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4] < MAX_TX_POWER) { ++ for (i = BAND_2G4_LOWER_BOUND; i <= BAND_2G4_UPPER_BOUND; i++) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4], ++ PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1] < MAX_TX_POWER) { ++ if (prCmd->u2CountryCode != COUNTRY_CODE_KR) { ++ for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } else { ++ for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { ++ /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 ++ * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ ++ prCmdPwrLimit->ucCentralCh = i; ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 6; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 12; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 18; ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A] < MAX_TX_POWER) { ++ for (i = UNII2A_LOWER_BOUND; i <= UNII2A_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C] < MAX_TX_POWER) { ++ for (i = UNII2C_LOWER_BOUND; i <= UNII2C_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++ if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3] < MAX_TX_POWER) { ++ for (i = UNII3_LOWER_BOUND; i <= UNII3_UPPER_BOUND; i += 2) { ++ prCmdPwrLimit->ucCentralCh = i; ++ kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, ++ prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3], PWR_LIMIT_NUM); ++ prCmdPwrLimit++; ++ prCmd->ucNum++; ++ } ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainBuildCmdByConfigTable(P_ADAPTER_T prAdapter, P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd) ++{ ++ UINT_8 i, k; ++ UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; ++ BOOLEAN fgChannelValid; ++ ++ /*Build power limit cmd by configuration table information */ ++ ++ for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); ++ ++ fgChannelValid = ++ rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); ++ ++ if (u2CountryCodeTable == COUNTRY_CODE_NULL) { ++ DBGLOG(RLM, TRACE, "Domain: full search configuration table done.\n"); ++ break; /*end of configuration table */ ++ } else if ((u2CountryCodeTable == prCmd->u2CountryCode) && (fgChannelValid == TRUE)) { ++ ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ ++ if (prCmd->ucNum != 0) { ++ for (k = 0; k < prCmd->ucNum; k++) { ++ if (prCmdPwrLimit->ucCentralCh == ++ g_rRlmPowerLimitConfiguration[i].ucCentralCh) { ++ ++ /*Cmd setting (Default table information) and ++ Configuration table has repetition channel entry, ++ ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, ++ Configuration table (ex: ch1, limit = 22dBm) --> ch 1 = 22 dBm ++ Cmd final setting --> ch1 = 22dBm, ch12~14 = 20dBm ++ */ ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ ++ DBGLOG(RLM, LOUD, ++ "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, ++ prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, ++ prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ ++ break; ++ } ++ prCmdPwrLimit++; ++ } ++ if (k == prCmd->ucNum) { ++ ++ /*Full search cmd (Default table setting) no match channey, ++ ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, ++ Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm ++ Cmd final setting --> ch1~14 = 20dBm, ch36= 22dBm ++ */ ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ prCmd->ucNum++; ++ ++ DBGLOG(RLM, LOUD, ++ "Domain: Full CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), (prCmd->u2CountryCode & 0x00ff), ++ prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, ++ prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, ++ prCmdPwrLimit->ucFlag); ++ ++ } ++ } else { ++ ++ /*Default table power limit value are 63--> cmd table no channel entry ++ ex : Default table (ex: 2.4G, limit = 63Bm) --> no channel entry in cmd, ++ Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm ++ Cmd final setting --> ch36= 22dBm ++ */ ++ prCmdPwrLimit->ucCentralCh = g_rRlmPowerLimitConfiguration[i].ucCentralCh; ++ prCmdPwrLimit->cPwrLimitCCK = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; ++ prCmdPwrLimit->cPwrLimit20 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; ++ prCmdPwrLimit->cPwrLimit40 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; ++ prCmdPwrLimit->cPwrLimit80 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; ++ prCmdPwrLimit->cPwrLimit160 = ++ g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; ++ prCmd->ucNum++; ++ ++ DBGLOG(RLM, LOUD, "Domain: Default table power limit value are 63.\n"); ++ DBGLOG(RLM, LOUD, "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, ++ prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, ++ prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param[in] ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter) ++{ ++ P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd; ++ UINT_8 i; ++ UINT_16 u2DefaultTableIndex; ++ UINT_32 u4SetCmdTableMaxSize; ++ UINT_32 u4SetQueryInfoLen; ++ P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; /* for print usage */ ++ ++ u4SetCmdTableMaxSize = ++ sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + ++ MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); ++ ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); ++ return; ++ } ++ kalMemZero(prCmd, u4SetCmdTableMaxSize); ++ ++ u2DefaultTableIndex = ++ rlmDomainPwrLimitDefaultTableDecision(prAdapter, prAdapter->rWifiVar.rConnSettings.u2CountryCode); ++ ++ if (u2DefaultTableIndex != POWER_LIMIT_TABLE_NULL) { ++ ++ WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[u2DefaultTableIndex].aucCountryCode[0], ++ &prCmd->u2CountryCode); ++ ++ prCmd->ucNum = 0; ++ ++ if (prCmd->u2CountryCode != COUNTRY_CODE_NULL) { ++ /*Command - default table information */ ++ rlmDomainBuildCmdByDefaultTable(prCmd, u2DefaultTableIndex); ++ ++ /*Command - configuration table information */ ++ rlmDomainBuildCmdByConfigTable(prAdapter, prCmd); ++ } ++ } ++#if 0 ++ u4SetCmdTableMaxSize = ++ sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + ++ MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); ++ ++ prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); ++ ASSERT(prCmd); ++ ++ /* To do: exception handle */ ++ if (!prCmd) { ++ DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); ++ return; ++ } ++ kalMemZero(prCmd, u4SetCmdTableMaxSize); /* TODO memzero */ ++ ++ if (u2TableIndex != POWER_LIMIT_TABLE_NULL && u2TableIndex < MAX_DEFAULT_TABLE_COUNTRY_NUM) { ++ ++ prCmd->u2CountryCode = (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[0]) << 8) | ++ (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[1]) & BITS(0, 7)); ++ prChPwrLimit = &g_rRlmCountryPowerLimitTable[u2TableIndex].rChannelPowerLimit[0]; ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ prCmd->ucNum = 0; ++ for (i = 0; i < MAX_CMD_SUPPORT_CHANNEL_NUM; i++) { ++ ++ if (prChPwrLimit->ucCentralCh != ENDCH) { ++ ++ /*Check Power limit table channel efficient or not */ ++ fgChannelValid = rlmDomainCheckChannelEntryValid(prAdapter, prChPwrLimit->ucCentralCh); ++ ++ /*Cmd set up */ ++ if (fgChannelValid) { ++ kalMemCopy(prCmdPwrLimit, prChPwrLimit, sizeof(CMD_CHANNEL_POWER_LIMIT)); ++ DBGLOG(RLM, INFO, ++ "Domain: ValidCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, ++ prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, ++ prCmdPwrLimit->ucFlag); ++ prCmd->ucNum++; ++ prCmdPwrLimit++; ++ } else { ++ DBGLOG(RLM, INFO, ++ "Domain: Non-Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", ++ prChPwrLimit->ucCentralCh, prChPwrLimit->cPwrLimitCCK, ++ prChPwrLimit->cPwrLimit20, prChPwrLimit->cPwrLimit40, ++ prChPwrLimit->cPwrLimit80, prChPwrLimit->cPwrLimit160, ++ prChPwrLimit->ucFlag); ++ } ++ prChPwrLimit++; ++ } else { ++ /*End of the chanel entry */ ++ break; ++ } ++ }; ++ } ++#endif ++ ++ if (prCmd->u2CountryCode != 0) { ++ DBGLOG(RLM, INFO, ++ "Domain: ValidCC =%c%c, ChNum=%d\n", ((prCmd->u2CountryCode & 0xff00) >> 8), ++ (prCmd->u2CountryCode & 0x00ff), prCmd->ucNum); ++ } else { ++ DBGLOG(RLM, INFO, "Domain: ValidCC =0x%04x, ucNum=%d\n", prCmd->u2CountryCode, prCmd->ucNum); ++ } ++ prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; ++ ++ for (i = 0; i < prCmd->ucNum; i++) { ++ DBGLOG(RLM, TRACE, "Domain: Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", prCmdPwrLimit->ucCentralCh, ++ prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, ++ prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); ++ prCmdPwrLimit++; ++ } ++ ++ u4SetQueryInfoLen = ++ (sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + (prCmd->ucNum) * sizeof(CMD_CHANNEL_POWER_LIMIT)); ++ ++ /* Update domain info to chip */ ++ if (prCmd->ucNum <= MAX_CMD_SUPPORT_CHANNEL_NUM) { ++ wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_COUNTRY_POWER_LIMIT, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ u4SetQueryInfoLen, /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmd, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ } else ++ DBGLOG(RLM, ERROR, "Domain: illegal power limit table"); ++ ++ cnmMemFree(prAdapter, prCmd); ++ ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c +new file mode 100644 +index 000000000000..8450124a3f38 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c +@@ -0,0 +1,436 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_obss.c#2 ++*/ ++ ++/*! \file "rlm_obss.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_obss.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Avoid possible OBSS scan when BSS is switched ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * Regulation class is changed to 81 in 20_40_coexistence action frame ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 29 2011 cm.chang ++ * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning ++ * As CR title ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame ++ * in AP mode and stop ampdu timer when sta_rec is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Refine function when rcv a 20/40M public action frame ++ * ++ * 01 13 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * Use SCO of BSS_INFO to replace user-defined setting variables ++ * ++ * 01 12 2011 cm.chang ++ * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting ++ * User-defined bandwidth is for 2.4G and 5G individually ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * use definition macro to replace hard-coded constant ++ * ++ * 09 16 2010 cm.chang ++ * NULL ++ * Change conditional compiling options for BOW ++ * ++ * 09 10 2010 cm.chang ++ * NULL ++ * Always update Beacon content if FW sync OBSS info ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Fix compile error while enabling WiFi Direct function. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 05 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Process 20/40 coexistence public action frame in AP mode ++ * ++ * 05 05 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft support for 20/40M bandwidth for AP mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add more ASSERT to check exception ++ * ++ * 04 07 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add virtual test for OBSS scan ++ * ++ * 03 30 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support 2.4G OBSS scan ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 02 05 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssInit(P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 ucNetIdx; ++ ++ RLM_NET_FOR_EACH(ucNetIdx) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; ++ ASSERT(prBssInfo); ++ ++ cnmTimerInitTimer(prAdapter, &prBssInfo->rObssScanTimer, rlmObssScanTimeout, (ULONG) prBssInfo); ++ } /* end of RLM_NET_FOR_EACH */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rlmObssUpdateChnlLists(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_20_40_COEXIST_FRAME prTxFrame; ++ UINT_16 i, u2PayloadLen; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prScanDoneMsg->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ DBGLOG(RLM, INFO, "OBSS Scan Done (NetIdx=%d, Mode=%d)\n", ++ prScanDoneMsg->ucNetTypeIndex, prBssInfo->eCurrentOPMode); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* AP mode */ ++ if ((prAdapter->fgIsP2PRegistered) && ++ (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex)) && ++ (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { ++ return; ++ } ++#endif ++ ++ /* STA mode */ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || ++ !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { ++ DBGLOG(RLM, WARN, "OBSS Scan Done (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ /* To do: check 2.4G channel list to decide if obss mgmt should be ++ * sent to associated AP. Note: how to handle concurrent network? ++ * To do: invoke rlmObssChnlLevel() to decide if 20/40 BSS coexistence ++ * management frame is needed. ++ */ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ if ((prBssInfo->auc2G_20mReqChnlList[0] > 0 || prBssInfo->auc2G_NonHtChnlList[0] > 0) && prMsduInfo != NULL) { ++ DBGLOG(RLM, INFO, "Send 20/40 coexistence mgmt(20mReq=%d, NonHt=%d)\n", ++ prBssInfo->auc2G_20mReqChnlList[0], prBssInfo->auc2G_NonHtChnlList[0]); ++ ++ prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; ++ prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; ++ ++ /* To do: find correct algorithm */ ++ prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ prTxFrame->rBssCoexist.ucLength = 1; ++ prTxFrame->rBssCoexist.ucData = (prBssInfo->auc2G_20mReqChnlList[0] > 0) ? BSS_COEXIST_20M_REQ : 0; ++ ++ u2PayloadLen = 2 + 3; ++ ++ if (prBssInfo->auc2G_NonHtChnlList[0] > 0) { ++ ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); ++ ++ prTxFrame->rChnlReport.ucId = ELEM_ID_20_40_INTOLERANT_CHNL_REPORT; ++ prTxFrame->rChnlReport.ucLength = prBssInfo->auc2G_NonHtChnlList[0] + 1; ++ prTxFrame->rChnlReport.ucRegulatoryClass = 81; /* 2.4GHz, ch1~13 */ ++ for (i = 0; i < prBssInfo->auc2G_NonHtChnlList[0] && i < CHNL_LIST_SZ_2G; i++) ++ prTxFrame->rChnlReport.aucChannelList[i] = prBssInfo->auc2G_NonHtChnlList[i + 1]; ++ ++ u2PayloadLen += IE_SIZE(&prTxFrame->rChnlReport); ++ } ++ ASSERT((WLAN_MAC_HEADER_LEN + u2PayloadLen) <= PUBLIC_ACTION_MAX_LEN); ++ ++ /* Clear up channel lists in 2.4G band */ ++ prBssInfo->auc2G_20mReqChnlList[0] = 0; ++ prBssInfo->auc2G_NonHtChnlList[0] = 0; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ } ++ /* end of prMsduInfo != NULL */ ++ if (prBssInfo->u2ObssScanInterval > 0) { ++ DBGLOG(RLM, INFO, "Set OBSS timer (NetIdx=%d, %d sec)\n", ++ prBssInfo->ucNetTypeIndex, prBssInfo->u2ObssScanInterval); ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ prBssInfo = (P_BSS_INFO_T) ulData; ++ ASSERT(prBssInfo); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex))) { ++ ++ /* AP mode */ ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ ++ prBssInfo->fgObssActionForcedTo20M = FALSE; ++ ++ /* Check if Beacon content need to be updated */ ++ rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); ++ ++ return; ++ } ++#if CFG_SUPPORT_WFD ++ /* WFD streaming */ ++ else { ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = ++ &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ P_BSS_INFO_T prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; ++ ++ /* If WFD is enabled & connected */ ++ if (prWfdCfgSettings->ucWfdEnable && ++ (prWfdCfgSettings->u4WfdFlag & BIT(0)) && RLM_NET_PARAM_VALID(prP2pBssInfo)) { ++ ++ /* Skip OBSS scan */ ++ prBssInfo->u2ObssScanInterval = 0; ++ ++ DBGLOG(RLM, INFO, "WFD is running. Stop net[%u] OBSS scan.\n", ++ (UINT_32) prBssInfo->ucNetTypeIndex); ++ ++ return; ++ } ++ } ++#endif ++ } ++#endif /* end of CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* STA mode */ ++ if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || ++ !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { ++ DBGLOG(RLM, WARN, "OBSS Scan timeout (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); ++ return; ++ } ++ ++ rlmObssTriggerScan(prAdapter, prBssInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ P_MSG_SCN_SCAN_REQ prScanReqMsg; ++ ++ ASSERT(prBssInfo); ++ ++ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) ++ cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); ++ ASSERT(prScanReqMsg); ++ ++ if (!prScanReqMsg) { ++ DBGLOG(RLM, WARN, "No buf for OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); ++ ++ cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); ++ return; ++ } ++ ++ /* It is ok that ucSeqNum is set to fixed value because the same network ++ * OBSS scan interval is limited to OBSS_SCAN_MIN_INTERVAL (min 10 sec) ++ * and scan module don't care seqNum of OBSS scanning ++ */ ++ prScanReqMsg->rMsgHdr.eMsgId = MID_RLM_SCN_SCAN_REQ; ++ prScanReqMsg->ucSeqNum = 0x33; ++ prScanReqMsg->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; ++ prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; ++ prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; ++ prScanReqMsg->ucSSIDLength = 0; ++ prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; ++ prScanReqMsg->u2IELen = 0; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); ++ ++ DBGLOG(RLM, INFO, "Timeout to trigger OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c +new file mode 100644 +index 000000000000..d3c513397095 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c +@@ -0,0 +1,105 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_protection.c#1 ++*/ ++ ++/*! \file "rlm_protection.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: rlm_protection.c ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Check draft RLM code for HT cap ++ * ++ * 05 28 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Set RTS threshold of 2K bytes initially ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * First draft code to support protection in AP mode ++ * ++ * 03 31 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Enable RTS threshold temporarily for AMPDU ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 03 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * To support CFG_SUPPORT_BCM_STP ++ * ++ * 02 13 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support PCO in STA mode ++ * ++ * 02 12 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Use bss info array for concurrent handle ++ * ++ * 01 25 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c +new file mode 100644 +index 000000000000..3f088c283993 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c +@@ -0,0 +1,539 @@ ++/* ++** Id: ++*/ ++ ++/*! \file "roaming_fsm.c" ++ \brief This file defines the FSM for Roaming MODULE. ++ ++ This file defines the FSM for Roaming MODULE. ++*/ ++ ++/* ++** Log: roaming_fsm.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 03 16 2011 tsaiyuan.hsu ++ * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming ++ * remove obsolete definition and unused variables. ++ * ++ * 02 26 2011 tsaiyuan.hsu ++ * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support ++ * not send disassoc or deauth to leaving AP so as to improve performace of roaming. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_ROAMING ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugRoamingState[ROAMING_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("ROAMING_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_DECISION"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_DISCOVERY"), ++ (PUINT_8) DISP_STRING("ROAMING_STATE_ROAM") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* ++#define ROAMING_ENABLE_CHECK(_roam) \ ++{ \ ++ if (!(_roam->fgIsEnableRoaming)) \ ++ return; \ ++} ++*/ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the value in ROAMING_FSM_INFO_T for ROAMING FSM operation ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmInit(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ /* 4 <1> Initiate FSM */ ++ prRoamingFsmInfo->fgIsEnableRoaming = prConnSettings->fgIsEnableRoaming; ++ prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; ++ prRoamingFsmInfo->rRoamingDiscoveryUpdateTime = 0; ++ ++} /* end of roamingFsmInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Uninitialize the value in AIS_FSM_INFO_T for AIS FSM operation ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmUninit(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; ++ ++} /* end of roamingFsmUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Send commands to firmware ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN P_ROAMING_PARAM_T] prParam ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ WLAN_STATUS rStatus; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmSendCmd(): Current Time = %u\n", kalGetTimeTick()); ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_ROAMING_TRANSIT, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(ROAMING_PARAM_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prParam, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++} /* end of roamingFsmSendCmd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Update the recent time when ScanDone occurred ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, LOUD, "->roamingFsmScanResultsUpdate(): Current Time = %u", kalGetTimeTick()); ++ ++ GET_CURRENT_SYSTIME(&prRoamingFsmInfo->rRoamingDiscoveryUpdateTime); ++ ++} /* end of roamingFsmScanResultsUpdate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of ROAMING for AIS Infra. ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN ENUM_ROAMING_STATE_T] eNextState Enum value of next AIS STATE ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T ePreviousState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ do { ++ ++ /* Do entering Next State */ ++#if DBG ++ DBGLOG(ROAMING, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugRoamingState[prRoamingFsmInfo->eCurrentState], ++ apucDebugRoamingState[eNextState]); ++#else ++ DBGLOG(ROAMING, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_ROAMING_IDX, prRoamingFsmInfo->eCurrentState, eNextState); ++#endif ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ ePreviousState = prRoamingFsmInfo->eCurrentState; ++ prRoamingFsmInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ /* Do tasks of the State that we just entered */ ++ switch (prRoamingFsmInfo->eCurrentState) { ++ /* NOTE(Kevin): we don't have to rearrange the sequence of following ++ * switch case. Instead I would like to use a common lookup table of array ++ * of function pointer to speed up state search. ++ */ ++ case ROAMING_STATE_IDLE: ++ case ROAMING_STATE_DECISION: ++ break; ++ ++ case ROAMING_STATE_DISCOVERY: ++ { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prRoamingFsmInfo->rRoamingDiscoveryUpdateTime, ++ SEC_TO_SYSTIME(ROAMING_DISCOVERY_TIMEOUT_SEC))) { ++ DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Timeout"); ++ aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); ++ } else { ++ DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Updated"); ++#if CFG_SUPPORT_ROAMING_ENC ++ if (prAdapter->fgIsRoamingEncEnabled == TRUE) ++ aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); ++ else ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ aisFsmRunEventRoamingDiscovery(prAdapter, FALSE); ++ } ++ } ++ break; ++ ++ case ROAMING_STATE_ROAM: ++ break; ++ ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ } ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of roamingFsmSteps() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Decision state after join completion ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ P_BSS_INFO_T prAisBssInfo; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prAisBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING START: Current Time = %u\n", kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as DECISION, DISCOVERY -> DECISION */ ++ if (!(prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE || ++ prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) ++ return; ++ ++ eNextState = ROAMING_STATE_DECISION; ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_START; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventStart() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Discovery state when deciding to find a candidate ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING DISCOVERY: Current Time = %u Reason = %u\n", ++ kalGetTimeTick(), prParam->u2Reason); ++ ++ /* DECISION -> DISCOVERY */ ++ /* Errors as IDLE, DISCOVERY, ROAM -> DISCOVERY */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DECISION) ++ return; ++#if CFG_SUPPORT_ROAMING_ENC ++ prRoamingFsmInfo->RoamingEntryTimeoutSkipCount = 0; ++#endif ++ ++ eNextState = ROAMING_STATE_DISCOVERY; ++ /* DECISION -> DISCOVERY */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ P_BSS_INFO_T prAisBssInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ /* sync. rcpi with firmware */ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); ++ if (prBssDesc) ++ prBssDesc->ucRCPI = (UINT_8) (prParam->u2Data & 0xff); ++ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventDiscovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Roam state after Scan Done ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ROAM: Current Time = %u\n", kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as IDLE, DECISION, ROAM -> ROAM */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DISCOVERY) ++ return; ++ ++ eNextState = ROAMING_STATE_ROAM; ++ /* DISCOVERY -> ROAM */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_ROAM; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventRoam() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Decision state as being failed to find out any candidate ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ /* Check Roaming Conditions */ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING FAIL: reason %x Current Time = %u\n", u4Param, kalGetTimeTick()); ++ ++ /* IDLE, ROAM -> DECISION */ ++ /* Errors as IDLE, DECISION, DISCOVERY -> DECISION */ ++ if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_ROAM) ++ return; ++ ++ eNextState = ROAMING_STATE_DECISION; ++ /* ROAM -> DECISION */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_FAIL; ++ rParam.u2Data = (UINT_16) (u4Param & 0xffff); ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventFail() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Transit to Idle state as beging aborted by other moduels, AIS ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter) ++{ ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ENUM_ROAMING_STATE_T eNextState; ++ ROAMING_PARAM_T rParam; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ ++ if (!(prRoamingFsmInfo->fgIsEnableRoaming)) ++ return; ++ ++ DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ABORT: Current Time = %u\n", kalGetTimeTick()); ++ ++ eNextState = ROAMING_STATE_IDLE; ++ /* IDLE, DECISION, DISCOVERY, ROAM -> IDLE */ ++ if (eNextState != prRoamingFsmInfo->eCurrentState) { ++ rParam.u2Event = ROAMING_EVENT_ABORT; ++ roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); ++ ++ /* Step to next state */ ++ roamingFsmSteps(prAdapter, eNextState); ++ } ++ ++} /* end of roamingFsmRunEventAbort() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process events from firmware ++* ++* @param [IN P_ADAPTER_T] prAdapter ++* [IN P_ROAMING_PARAM_T] prParam ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) ++{ ++ DBGLOG(ROAMING, LOUD, "ROAMING Process Events: Current Time = %u\n", kalGetTimeTick()); ++ ++ if (ROAMING_EVENT_DISCOVERY == prParam->u2Event) ++ roamingFsmRunEventDiscovery(prAdapter, prParam); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c +new file mode 100644 +index 000000000000..eedd8d12f2fd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c +@@ -0,0 +1,2533 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rsn.c#2 ++*/ ++ ++/*! \file "rsn.c" ++ \brief This file including the 802.11i, wpa and wpa2(rsn) related function. ++ ++ This file provided the macros and functions library support the wpa/rsn ie parsing, ++ cipher and AKM check to help the AP seleced deciding, tkip mic error handler and rsn PMKID support. ++*/ ++ ++/* ++** Log: rsn.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 09 2012 chinglan.wang ++ * NULL ++ * Fix the condition error. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode ++ * adding the code for check STA privacy bit at AP mode, . ++ * ++ * 12 24 2010 chinglan.wang ++ * NULL ++ * [MT6620][Wi-Fi] Modify the key management in the driver for WPS function. ++ * ++ * 12 13 2010 cp.wu ++ * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver ++ * create branch for Wi-Fi driver v1.1 ++ * ++ * 11 05 2010 wh.su ++ * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value ++ * fixed the.pmkid value mismatch issue ++ * ++ * 11 03 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Refine the HT rate disallow TKIP pairwise cipher . ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T ++ * and replaced by ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 29 2010 yuche.tsai ++ * NULL ++ * Fix compile error, remove unused pointer in rsnGenerateRSNIE(). ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 08 30 2010 wh.su ++ * NULL ++ * remove non-used code. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * enable RX management frame handling. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * [WPD00003840] [MT6620 5931] Security migration ++ * migration from firmware. ++ * ++ * 05 27 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * not indicate pmkid candidate while no new one scanned. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * change the name ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * using the Rx0 port to indicate event ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine the code for generate the WPA/RSN IE for assoc req ++ * ++ * Dec 3 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust code for pmkid event ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the code for event (mic error and pmkid indicate) and do some function rename ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security function ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding some security feature, including pmkid ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_RSN_MIGRATION ++ ++/* extern PHY_ATTRIBUTE_T rPhyAttributes[]; */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse RSN IE. ++* ++* \param[in] prInfoElem Pointer to the RSN IE ++* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the ++** RSN information from the given RSN IE ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainRsnIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUINT_8 pucPairSuite = NULL; ++ PUINT_8 pucAuthSuite = NULL; ++ PUINT_8 cp; ++ ++ DEBUGFUNC("rsnParseRsnIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prRsnInfo); ++ ++ /* Verify the length of the RSN IE. */ ++ if (prInfoElem->ucLength < 2) { ++ DBGLOG(RSN, TRACE, "RSN IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check RSN version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(RSN, TRACE, "Unsupported RSN IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) & prInfoElem->u4GroupKeyCipherSuite; ++ u4RemainRsnIeLen = (INT_32) prInfoElem->ucLength - 2; ++ ++ do { ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainRsnIeLen < 4) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainRsnIeLen -= 4; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainRsnIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainRsnIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainRsnIeLen -= (INT_32) i; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainRsnIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainRsnIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainRsnIeLen -= (INT_32) i; ++ ++ if (u4RemainRsnIeLen == 0) ++ break; ++ ++ /* Parse the RSN u2Capabilities field. */ ++ if (u4RemainRsnIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ } while (FALSE); ++ ++ /* Save the RSN information for the BSS. */ ++ prRsnInfo->ucElemId = ELEM_ID_RSN; ++ ++ prRsnInfo->u2Version = u2Version; ++ ++ prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(RSN, LOUD, "RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; ++ ++ prRsnInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prRsnInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for RSN: CCMP. */ ++ prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP; ++ ++ DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; ++ ++ prRsnInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for RSN. */ ++ prRsnInfo->u4AuthKeyMgtSuiteCount = 1; ++ prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X; ++ ++ DBGLOG(RSN, LOUD, "RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ prRsnInfo->u2RsnCap = u2Cap; ++#if CFG_SUPPORT_802_11W ++ prRsnInfo->fgRsnCapPresent = TRUE; ++#endif ++ DBGLOG(RSN, LOUD, "RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap); ++ ++ return TRUE; ++} /* rsnParseRsnIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse WPA IE. ++* ++* \param[in] prInfoElem Pointer to the WPA IE. ++* \param[out] prWpaInfo Pointer to the BSSDescription structure to store the ++* WPA information from the given WPA IE. ++* ++* \retval TRUE Succeeded. ++* \retval FALSE Failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainWpaIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUCHAR pucPairSuite = NULL; ++ PUCHAR pucAuthSuite = NULL; ++ PUCHAR cp; ++ BOOLEAN fgCapPresent = FALSE; ++ ++ DEBUGFUNC("rsnParseWpaIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prWpaInfo); ++ ++ /* Verify the length of the WPA IE. */ ++ if (prInfoElem->ucLength < 6) { ++ DBGLOG(RSN, TRACE, "WPA IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check WPA version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(RSN, TRACE, "Unsupported WPA IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite; ++ u4RemainWpaIeLen = (INT_32) prInfoElem->ucLength - 6; ++ ++ do { ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* WPA_OUI : 4 ++ Version : 2 ++ GroupSuite : 4 ++ PairwiseCount: 2 ++ PairwiseSuite: 4 * pairSuiteCount ++ AuthCount : 2 ++ AuthSuite : 4 * authSuiteCount ++ Cap : 2 */ ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainWpaIeLen < 4) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainWpaIeLen -= 4; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainWpaIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainWpaIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainWpaIeLen -= (INT_32) i; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count ++ field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainWpaIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainWpaIeLen < (INT_32) i) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainWpaIeLen -= (INT_32) i; ++ ++ if (u4RemainWpaIeLen == 0) ++ break; ++ ++ /* Parse the WPA u2Capabilities field. */ ++ if (u4RemainWpaIeLen < 2) { ++ DBGLOG(RSN, TRACE, "Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ fgCapPresent = TRUE; ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ u4RemainWpaIeLen -= 2; ++ } while (FALSE); ++ ++ /* Save the WPA information for the BSS. */ ++ ++ prWpaInfo->ucElemId = ELEM_ID_WPA; ++ ++ prWpaInfo->u2Version = u2Version; ++ ++ prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(RSN, LOUD, "WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; ++ ++ prWpaInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prWpaInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for WPA: TKIP. */ ++ prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP; ++ ++ DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; ++ ++ prWpaInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(RSN, LOUD, "WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for WPA. */ ++ prWpaInfo->u4AuthKeyMgtSuiteCount = 1; ++ prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X; ++ ++ DBGLOG(RSN, LOUD, "WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (fgCapPresent) { ++ prWpaInfo->fgRsnCapPresent = TRUE; ++ prWpaInfo->u2RsnCap = u2Cap; ++ DBGLOG(RSN, LOUD, "WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap); ++ } else { ++ prWpaInfo->fgRsnCapPresent = FALSE; ++ prWpaInfo->u2RsnCap = 0; ++ } ++ ++ return TRUE; ++} /* rsnParseWpaIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search the desired pairwise ++* cipher suite from the MIB Pairwise Cipher Suite ++* configuration table. ++* ++* \param[in] u4Cipher The desired pairwise cipher suite to be searched ++* \param[out] pu4Index Pointer to the index of the desired pairwise cipher in ++* the table ++* ++* \retval TRUE - The desired pairwise cipher suite is found in the table. ++* \retval FALSE - The desired pairwise cipher suite is not found in the ++* table. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index) ++{ ++ UINT_8 i; ++ P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; ++ ++ DEBUGFUNC("rsnSearchSupportedCipher"); ++ ++ ASSERT(pu4Index); ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i]; ++ if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher && ++ prEntry->dot11RSNAConfigPairwiseCipherEnabled) { ++ *pu4Index = i; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} /* rsnSearchSupportedCipher */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Whether BSS RSN is matched from upper layer set. ++* ++* \param[in] prAdapter Pointer to the Adapter structure, BSS RSN Information ++* ++* \retval BOOLEAN ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo) ++{ ++ UINT_8 i = 0; ++ ++ DEBUGFUNC("rsnIsSuitableBSS"); ++ ++ do { ++ ++ if ((prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite)) { ++ DBGLOG(RSN, TRACE, "Break by GroupKeyCipherSuite\n"); ++ break; ++ } ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])) ++ && (i == prBssRsnInfo->u4PairwiseKeyCipherSuiteCount - 1)) { ++ DBGLOG(RSN, TRACE, "Break by PairwiseKeyCipherSuite\n"); ++ break; ++ } ++ } ++ for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { ++ if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] & 0x000000FF) != ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4AuthKeyMgtSuite[0])) ++ && (i == prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1)) { ++ DBGLOG(RSN, TRACE, "Break by AuthKeyMgtSuite\n"); ++ break; ++ } ++ } ++ return TRUE; ++ } while (FALSE); ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to search the desired ++* authentication and key management (AKM) suite from the ++* MIB Authentication and Key Management Suites table. ++* ++* \param[in] u4AkmSuite The desired AKM suite to be searched ++* \param[out] pu4Index Pointer to the index of the desired AKM suite in the ++* table ++* ++* \retval TRUE The desired AKM suite is found in the table. ++* \retval FALSE The desired AKM suite is not found in the table. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index) ++{ ++ UINT_8 i; ++ P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; ++ ++ DEBUGFUNC("rsnSearchAKMSuite"); ++ ++ ASSERT(pu4Index); ++ ++ for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { ++ prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; ++ if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite && ++ prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) { ++ *pu4Index = i; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} /* rsnSearchAKMSuite */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to perform RSNA or TSN policy ++* selection for a given BSS. ++* ++* \param[in] prBss Pointer to the BSS description ++* ++* \retval TRUE - The RSNA/TSN policy selection for the given BSS is ++* successful. The selected pairwise and group cipher suites ++* are returned in the BSS description. ++* \retval FALSE - The RSNA/TSN policy selection for the given BSS is failed. ++* The driver shall not attempt to join the given BSS. ++* ++* \note The Encrypt status matched score will save to bss for final ap select. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++#if CFG_SUPPORT_802_11W ++ INT_32 i; ++ UINT_32 j; ++#else ++ UINT_32 i, j; ++#endif ++ BOOLEAN fgSuiteSupported; ++ UINT_32 u4PairwiseCipher = 0; ++ UINT_32 u4GroupCipher = 0; ++ UINT_32 u4AkmSuite = 0; ++ P_RSN_INFO_T prBssRsnInfo; ++ ENUM_NETWORK_TYPE_INDEX_T eNetwotkType; ++ BOOLEAN fgIsWpsActive = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("rsnPerformPolicySelection"); ++ ++ ASSERT(prBss); ++ ++ DBGLOG(RSN, TRACE, "rsnPerformPolicySelection\n"); ++ /* Todo:: */ ++ eNetwotkType = NETWORK_TYPE_AIS_INDEX; ++ ++ prBss->u4RsnSelectedPairwiseCipher = 0; ++ prBss->u4RsnSelectedGroupCipher = 0; ++ prBss->u4RsnSelectedAKMSuite = 0; ++ prBss->ucEncLevel = 0; ++ ++#if CFG_SUPPORT_WPS ++ fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo); ++ ++ /* CR1640, disable the AP select privacy check */ ++ if (fgIsWpsActive && ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) && ++ (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) { ++ DBGLOG(RSN, TRACE, "-- Skip the Protected BSS check\n"); ++ return TRUE; ++ } ++#endif ++ ++ /* Protection is not required in this BSS. */ ++ if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0) { ++ ++ if (secEnabledInAis(prAdapter) == FALSE) { ++ DBGLOG(RSN, TRACE, "-- No Protected BSS\n"); ++ return TRUE; ++ } ++ DBGLOG(RSN, TRACE, "-- Protected BSS\n"); ++ return FALSE; ++ ++ } ++ ++ /* Protection is required in this BSS. */ ++ if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) { ++ if (secEnabledInAis(prAdapter) == FALSE) { ++ DBGLOG(RSN, TRACE, "-- Protected BSS\n"); ++ return FALSE; ++ } ++ } ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { ++ ++ if (prBss->fgIEWPA) { ++ prBssRsnInfo = &prBss->rWPAInfo; ++ } else { ++ DBGLOG(RSN, TRACE, "WPA Information Element does not exist.\n"); ++ return FALSE; ++ } ++ } else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 || ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) { ++ ++ if (prBss->fgIERSN) { ++ prBssRsnInfo = &prBss->rRSNInfo; ++ } else { ++ DBGLOG(RSN, TRACE, "RSN Information Element does not exist.\n"); ++ return FALSE; ++ } ++ } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != ENUM_ENCRYPTION1_ENABLED) { ++ /* If the driver is configured to use WEP only, ignore this BSS. */ ++ DBGLOG(RSN, TRACE, "-- Not WEP-only legacy BSS %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ return FALSE; ++ } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) { ++ /* If the driver is configured to use WEP only, use this BSS. */ ++ DBGLOG(RSN, TRACE, "-- WEP-only legacy BSS, fgIERSN %d, fgIEWPA %d\n", ++ prBss->fgIERSN, prBss->fgIEWPA); ++ /* if this BSS was configured to WPA/WPA2, don't select this AP */ ++ return (prBss->fgIERSN || prBss->fgIEWPA) ? FALSE : TRUE; ++ } ++ ++ if (!rsnIsSuitableBSS(prAdapter, prBssRsnInfo)) { ++ DBGLOG(RSN, TRACE, "RSN info check no matched\n"); ++ return FALSE; ++ } ++ ++ if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 && ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == CIPHER_SUITE_NONE) { ++ /* Since the pairwise cipher use the same cipher suite as the group ++ cipher in the BSS, we check the group cipher suite against the ++ current encryption status. */ ++ fgSuiteSupported = FALSE; ++ ++ switch (prBssRsnInfo->u4GroupKeyCipherSuite) { ++ case WPA_CIPHER_SUITE_CCMP: ++ case RSN_CIPHER_SUITE_CCMP: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ ++ case WPA_CIPHER_SUITE_TKIP: ++ case RSN_CIPHER_SUITE_TKIP: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ ++ case WPA_CIPHER_SUITE_WEP40: ++ case WPA_CIPHER_SUITE_WEP104: ++ if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) ++ fgSuiteSupported = TRUE; ++ break; ++ } ++ ++ if (fgSuiteSupported) { ++ u4PairwiseCipher = WPA_CIPHER_SUITE_NONE; ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ } ++#if DBG ++ else { ++ DBGLOG(RSN, TRACE, "Inproper encryption status %d for group-key-only BSS\n", ++ prAdapter->rWifiVar.rConnSettings.eEncStatus); ++ } ++#endif ++ } else { ++ fgSuiteSupported = FALSE; ++ ++ DBGLOG(RSN, TRACE, "eEncStatus %d %d 0x%x\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, ++ (UINT_32) prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, ++ (UINT_32) prBssRsnInfo->au4PairwiseKeyCipherSuite[0]); ++ /* Select pairwise/group ciphers */ ++ switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { ++ case ENUM_ENCRYPTION3_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_CCMP) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ break; ++ ++ case ENUM_ENCRYPTION2_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_TKIP) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_CCMP) ++ DBGLOG(RSN, TRACE, "Cannot join CCMP BSS\n"); ++ else ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ break; ++ ++ case ENUM_ENCRYPTION1_ENABLED: ++ for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_WEP40 || ++ GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ == CIPHER_SUITE_WEP104) { ++ u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == ++ CIPHER_SUITE_CCMP || ++ GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_TKIP) { ++ DBGLOG(RSN, TRACE, "Cannot join CCMP/TKIP BSS\n"); ++ } else { ++ u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ /* Exception handler */ ++ /* If we cannot find proper pairwise and group cipher suites to join the ++ BSS, do not check the supported AKM suites. */ ++ if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { ++ DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((prAdapter->fgIsP2PRegistered) && (eNetwotkType == NETWORK_TYPE_P2P_INDEX)) { ++ if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || ++ u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { ++ DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher for P2P network (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (eNetwotkType == NETWORK_TYPE_BOW_INDEX) { ++ if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || ++ u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { ++ /* Do nothing */ ++ } ++ DBGLOG(RSN, TRACE, ++ "Failed to select pairwise/group cipher for BT over Wi-Fi network (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++#endif ++ ++ /* Verify if selected pairwisse cipher is supported */ ++ fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i); ++ ++ /* Verify if selected group cipher is supported */ ++ if (fgSuiteSupported) ++ fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i); ++ ++ if (!fgSuiteSupported) { ++ DBGLOG(RSN, TRACE, "Failed to support selected pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ ++ /* Select AKM */ ++ /* If the driver cannot support any authentication suites advertised in ++ the given BSS, we fail to perform RSNA policy selection. */ ++ /* Attempt to find any overlapping supported AKM suite. */ ++#if CFG_SUPPORT_802_11W ++ if (i != 0) ++ for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) { ++#else ++ for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { ++#endif ++ if (rsnSearchAKMSuite(prAdapter, prBssRsnInfo->au4AuthKeyMgtSuite[i], &j)) { ++ u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i]; ++ break; ++ } ++ } ++ ++ if (u4AkmSuite == 0) { ++ DBGLOG(RSN, TRACE, "Cannot support any AKM suites\n"); ++ return FALSE; ++ } ++ ++ DBGLOG(RSN, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4PairwiseCipher & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), ++ (UINT_8) (u4GroupCipher & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); ++ ++ DBGLOG(RSN, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4AkmSuite & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); ++ ++#if CFG_SUPPORT_802_11W ++ DBGLOG(RSN, TRACE, "MFP setting = %d\n ", kalGetMfpSetting(prAdapter->prGlueInfo)); ++ ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { ++ if (!prBssRsnInfo->fgRsnCapPresent) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability.\n"); ++ return FALSE; ++ } else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required\n"); ++ return FALSE; ++ } ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ } else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) { ++ if (prBssRsnInfo->u2RsnCap && ((prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR) || ++ (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC))) { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; ++ } else { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ } ++ } else { ++ if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { ++ DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability\n"); ++ return FALSE; ++ } ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; ++ } ++ DBGLOG(RSN, TRACE, "fgMgmtProtection = %d\n ", prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection); ++#endif ++ ++ if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP) { ++ prBss->ucEncLevel = 3; ++ } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP) { ++ prBss->ucEncLevel = 2; ++ } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 || ++ GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) { ++ prBss->ucEncLevel = 1; ++ } else { ++ ASSERT(FALSE); ++ } ++ prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher; ++ prBss->u4RsnSelectedGroupCipher = u4GroupCipher; ++ prBss->u4RsnSelectedAKMSuite = u4AkmSuite; ++ ++ return TRUE; ++ ++} /* rsnPerformPolicySelection */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate WPA IE for beacon frame. ++* ++* \param[in] pucIeStartAddr Pointer to put the generated WPA IE. ++* ++* \return The append WPA-None IE length ++* \note ++* Called by: JOIN module, compose beacon IE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 i; ++ P_WPA_INFO_ELEM_T prWpaIE; ++ UINT_32 u4Suite; ++ UINT_16 u2SuiteCount; ++ PUINT_8 cp, cp2; ++ UINT_8 ucExpendedLen = 0; ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ ++ DEBUGFUNC("rsnGenerateWpaNoneIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE) ++ return; ++ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ ++ if (eNetworkId != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ prWpaIE = (P_WPA_INFO_ELEM_T) (pucBuffer); ++ ++ /* Start to construct a WPA IE. */ ++ /* Fill the Element ID field. */ ++ prWpaIE->ucElemId = ELEM_ID_WPA; ++ ++ /* Fill the OUI and OUI Type fields. */ ++ prWpaIE->aucOui[0] = 0x00; ++ prWpaIE->aucOui[1] = 0x50; ++ prWpaIE->aucOui[2] = 0xF2; ++ prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA; ++ ++ /* Fill the Version field. */ ++ WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */ ++ ucExpendedLen = 6; ++ ++ /* Fill the Pairwise Key Cipher Suite List field. */ ++ u2SuiteCount = 0; ++ cp = (PUINT_8) &prWpaIE->aucPairwiseKeyCipherSuite1[0]; ++ ++ if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) ++ u4Suite = WPA_CIPHER_SUITE_CCMP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) ++ u4Suite = WPA_CIPHER_SUITE_TKIP; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) ++ u4Suite = WPA_CIPHER_SUITE_WEP104; ++ else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) ++ u4Suite = WPA_CIPHER_SUITE_WEP40; ++ else ++ u4Suite = WPA_CIPHER_SUITE_TKIP; ++ ++ WLAN_SET_FIELD_32(cp, u4Suite); ++ u2SuiteCount++; ++ ucExpendedLen += 4; ++ cp += 4; ++ ++ /* Fill the Group Key Cipher Suite field as the same in pair-wise key. */ ++ WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite); ++ ucExpendedLen += 4; ++ ++ /* Fill the Pairwise Key Cipher Suite Count field. */ ++ WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount); ++ ucExpendedLen += 2; ++ ++ cp2 = cp; ++ ++ /* Fill the Authentication and Key Management Suite List field. */ ++ u2SuiteCount = 0; ++ cp += 2; ++ ++ if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i)) ++ u4Suite = WPA_AKM_SUITE_802_1X; ++ else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i)) ++ u4Suite = WPA_AKM_SUITE_PSK; ++ else ++ u4Suite = WPA_AKM_SUITE_NONE; ++ ++ /* This shall be the only available value for current implementation */ ++ ASSERT(u4Suite == WPA_AKM_SUITE_NONE); ++ ++ WLAN_SET_FIELD_32(cp, u4Suite); ++ u2SuiteCount++; ++ ucExpendedLen += 4; ++ cp += 4; ++ ++ /* Fill the Authentication and Key Management Suite Count field. */ ++ WLAN_SET_FIELD_16(cp2, u2SuiteCount); ++ ucExpendedLen += 2; ++ ++ /* Fill the Length field. */ ++ prWpaIE->ucLength = (UINT_8) ucExpendedLen; ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ ++} /* rsnGenerateWpaNoneIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WPA IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WPA IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUCHAR cp; ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; ++ ++ DEBUGFUNC("rsnGenerateWPAIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ /* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */ ++ /* return; */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if ((1 /* prCurrentBss->fgIEWPA */ && ++ ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkId == NETWORK_TYPE_P2P_INDEX) && ++ (kalP2PGetTkipCipher(prAdapter->prGlueInfo)))) || ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) { ++#else ++ if ((1 /* prCurrentBss->fgIEWPA */ && ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK)))) { ++#endif ++ if (prP2pSpecificBssInfo->u2WpaIeLen != 0) { ++ kalMemCopy(pucBuffer, prP2pSpecificBssInfo->aucWpaIeBuffer, prP2pSpecificBssInfo->u2WpaIeLen); ++ prMsduInfo->u2FrameLength += prP2pSpecificBssInfo->u2WpaIeLen; ++ return; ++ } ++ ++ /* Construct a WPA IE for association request frame. */ ++ WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA; ++ WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; ++ WPA_IE(pucBuffer)->aucOui[0] = 0x00; ++ WPA_IE(pucBuffer)->aucOui[1] = 0x50; ++ WPA_IE(pucBuffer)->aucOui[2] = 0xF2; ++ WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA; ++ WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, WPA_CIPHER_SUITE_TKIP); ++ } else ++#endif ++ WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, ++ prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedGroupCipher); ++ ++ cp = (PUCHAR) &WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; ++ ++ WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP); ++ } else ++#endif ++ WLAN_SET_FIELD_32(cp, ++ prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedPairwiseCipher); ++ cp += 4; ++ ++ WLAN_SET_FIELD_16(cp, 1); ++ cp += 2; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { ++ WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK); ++ } else ++#endif ++ WLAN_SET_FIELD_32(cp, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedAKMSuite); ++ cp += 4; ++ ++ WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; ++ ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* rsnGenerateWPAIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate RSN IE for ++* associate request frame. ++* ++* \param[in] prMsduInfo The Selected BSS description ++* ++* \retval The append RSN IE length ++* ++* \note ++* Called by: AIS module, P2P module, BOW module Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 u4Entry; ++ PUCHAR cp; ++ /* UINT_8 ucExpendedLen = 0; */ ++ PUINT_8 pucBuffer; ++ ENUM_NETWORK_TYPE_INDEX_T eNetworkId; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("rsnGenerateRSNIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ ASSERT(pucBuffer); ++ ++ /* Todo:: network id */ ++ eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; ++ ++ if ( ++#if CFG_ENABLE_WIFI_DIRECT ++ ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkId == NETWORK_TYPE_P2P_INDEX) && (kalP2PGetCcmpCipher(prAdapter->prGlueInfo))) || ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ (eNetworkId == NETWORK_TYPE_BOW_INDEX) || ++#endif ++ (eNetworkId == NETWORK_TYPE_AIS_INDEX /* prCurrentBss->fgIERSN */ && ++ ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) || ++ (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK)))) { ++ /* Construct a RSN IE for association request frame. */ ++ RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN; ++ RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED; ++ WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); /* Version */ ++ WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite, ++ prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedGroupCipher); /* Group key suite */ ++ cp = (PUCHAR) &RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; ++ WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); ++ WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedPairwiseCipher); ++ cp += 4; ++ WLAN_SET_FIELD_16(cp, 1); /* AKM suite count */ ++ cp += 2; ++ WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedAKMSuite); /* AKM suite */ ++ cp += 4; ++ WLAN_SET_FIELD_16(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u2RsnSelectedCapInfo);/* Capabilities */ ++#if CFG_SUPPORT_802_11W ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection) { ++ if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) ++ WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); /* Capabilities */ ++ else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) ++ WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); /* Capabilities */ ++ } ++#endif ++ cp += 2; ++ ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX) { ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ if (!prStaRec) { ++ DBGLOG(RSN, TRACE, "rsnGenerateRSNIE: prStaRec is NULL\n"); ++ return; ++ } ++ } ++ ++ if (eNetworkId == NETWORK_TYPE_AIS_INDEX && ++ rsnSearchPmkidEntry(prAdapter, prStaRec->aucMacAddr, &u4Entry)) { ++ /* DBGLOG(RSN, TRACE, ("Add Pmk at assoc req\n")); */ ++ /* DBGLOG(RSN, TRACE, ("addr %pM PMKID %pM\n", */ ++ /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arBSSID),*/ ++ /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID))); */ ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].fgPmkidExist) { ++ RSN_IE(pucBuffer)->ucLength = 38; ++ WLAN_SET_FIELD_16(cp, 1); /* PMKID count */ ++ cp += 2; ++ DBGLOG(RSN, TRACE, ++ "BSSID %pM ind=%d\n", prStaRec->aucMacAddr, (UINT_32) u4Entry); ++ DBGLOG(RSN, TRACE, "use PMKID %pM\n", ++ (prAdapter->rWifiVar.rAisSpecificBssInfo. ++ arPmkidCache[u4Entry].rBssidInfo.arPMKID)); ++ kalMemCopy(cp, ++ (PVOID) prAdapter->rWifiVar.rAisSpecificBssInfo. ++ arPmkidCache[u4Entry].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); ++ /* ucExpendedLen = 40; */ ++ } else { ++ WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ ++ /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ ++#if CFG_SUPPORT_802_11W ++ cp += 2; ++ RSN_IE(pucBuffer)->ucLength += 2; ++#endif ++ } ++ } else { ++ WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ ++ /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ ++#if CFG_SUPPORT_802_11W ++ cp += 2; ++ RSN_IE(pucBuffer)->ucLength += 2; ++#endif ++ } ++ ++#if CFG_SUPPORT_802_11W ++ if ((eNetworkId == NETWORK_TYPE_AIS_INDEX) ++ && (kalGetMfpSetting(prAdapter->prGlueInfo) != ++ RSN_AUTH_MFP_DISABLED) /* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */) { ++ WLAN_SET_FIELD_32(cp, RSN_CIPHER_SUITE_AES_128_CMAC); ++ cp += 4; ++ RSN_IE(pucBuffer)->ucLength += 4; ++ } ++#endif ++ prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); ++ } ++ ++} /* rsnGenerateRSNIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the given IE buffer and check if it is WFA IE and return Type and ++* SubType for further process. ++* ++* \param[in] pucBuf Pointer to the buffer of WFA Information Element. ++* \param[out] pucOuiType Pointer to the storage of OUI Type. ++* \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and Version. ++ ++* \retval TRUE Parse IE ok ++* \retval FALSE Parse IE fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, ++ IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion) ++{ ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_IE_WFA_T prWfaIE; ++ ++ ASSERT(pucBuf); ++ ASSERT(pucOuiType); ++ ASSERT(pu2SubTypeVersion); ++ prWfaIE = (P_IE_WFA_T) pucBuf; ++ ++ do { ++ if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { ++ break; ++ } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || ++ prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { ++ break; ++ } ++ ++ *pucOuiType = prWfaIE->ucOuiType; ++ WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion); ++ ++ return TRUE; ++ } while (FALSE); ++ ++ return FALSE; ++ ++} /* end of rsnParseCheckForWFAInfoElem() */ ++ ++#if CFG_SUPPORT_AAA ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK ++* ++* \param[in] prAdapter Pointer to Adapter ++* \param[in] prSwRfb Pointer to the rx buffer ++* \param[in] pIE Pointer rthe buffer of Information Element. ++* \param[out] prStatusCode Pointer to the return status code. ++ ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode) ++{ ++ ++ RSN_INFO_T rRsnIe; ++ ++ ASSERT(prAdapter); ++ ASSERT(prIe); ++ ASSERT(pu2StatusCode); ++ ++ *pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; ++ ++ if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) { ++ if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1) ++ || (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) { ++ *pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER; ++ return; ++ } ++ if (rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP) { ++ *pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER; ++ return; ++ } ++ if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1) || (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) { ++ *pu2StatusCode = STATUS_CODE_INVALID_AKMP; ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n"); ++ *pu2StatusCode = WLAN_STATUS_SUCCESS; ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate an authentication event to NDIS. ++* ++* \param[in] u4Flags Authentication event: \n ++* PARAM_AUTH_REQUEST_REAUTH 0x01 \n ++* PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n ++* PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n ++* PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgFlags) ++{ ++ P_PARAM_AUTH_EVENT_T prAuthEvent; ++ ++ DEBUGFUNC("rsnGenMicErrorEvent"); ++ ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: Authentication Event */ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; ++ ++ /* Authentication request */ ++ prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); ++ kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, ++ (PVOID) prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucBSSID, MAC_ADDR_LEN); ++ ++ if (fgFlags == TRUE) ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; ++ else ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); ++ ++} /* rsnGenMicErrorEvent */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to handle TKIP MIC failures. ++* ++* \param[in] adapter_p Pointer to the adapter object data area. ++* \param[in] prSta Pointer to the STA which occur MIC Error ++* \param[in] fgErrorKeyType type of error key ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType) ++{ ++ /* UINT_32 u4RsnaCurrentMICFailTime; */ ++ /* P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; */ ++ ++ DEBUGFUNC("rsnTkipHandleMICFailure"); ++ ++ ASSERT(prAdapter); ++#if 1 ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ ++ nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, Param_PowerModeCAM, FALSE); ++ ++ /* Generate authentication request event. */ ++ DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); ++#else ++ ASSERT(prSta); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* Record the MIC error occur time. */ ++ GET_CURRENT_SYSTIME(&u4RsnaCurrentMICFailTime); ++ ++ /* Generate authentication request event. */ ++ DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); ++ ++ /* If less than 60 seconds have passed since a previous TKIP MIC failure, ++ disassociate from the AP and wait for 60 seconds before (re)associating ++ with the same AP. */ ++ if (prAisSpecBssInfo->u4RsnaLastMICFailTime != 0 && ++ !CHECK_FOR_TIMEOUT(u4RsnaCurrentMICFailTime, ++ prAisSpecBssInfo->u4RsnaLastMICFailTime, SEC_TO_SYSTIME(TKIP_COUNTERMEASURE_SEC))) { ++ /* If less than 60 seconds expired since last MIC error, we have to ++ block traffic. */ ++ ++ DBGLOG(RSN, INFO, "Start blocking traffic!\n"); ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ ++ secFsmEventStartCounterMeasure(prAdapter, prSta); ++ } else { ++ rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); ++ DBGLOG(RSN, INFO, "First TKIP MIC error!\n"); ++ } ++ ++ COPY_SYSTIME(prAisSpecBssInfo->u4RsnaLastMICFailTime, u4RsnaCurrentMICFailTime); ++#endif ++} /* rsnTkipHandleMICFailure */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to select a list of BSSID from ++* the scan results for PMKID candidate list. ++* ++* \param[in] prBssDesc the BSS Desc at scan result list ++* \param[out] pu4CandidateCount Pointer to the number of selected candidates. ++* It is set to zero if no BSSID matches our requirement. ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("rsnSelectPmkidCandidateList"); ++ ++ ASSERT(prBssDesc); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ++ /* Search a BSS with the same SSID from the given BSS description set. */ ++ /* DBGLOG(RSN, TRACE, ("Check scan result [%pM]\n", */ ++ /* prBssDesc->aucBSSID)); */ ++ ++ if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ DBGLOG(RSN, TRACE, "-- SSID not matched\n"); ++ return; ++ } ++#if 0 ++ if ((prBssDesc->u2BSSBasicRateSet & ++ ~(rPhyAttributes[prAisBssInfo->ePhyType].u2SupportedRateSet)) || prBssDesc->fgIsUnknownBssBasicRate) { ++ DBGLOG(RSN, TRACE, "-- Rate set not matched\n"); ++ return; ++ } ++ ++ if (/* prBssDesc->u4RsnSelectedPairwiseCipher != prAisBssInfo->u4RsnSelectedPairwiseCipher || */ ++ prBssDesc->u4RsnSelectedGroupCipher != prAisBssInfo->u4RsnSelectedGroupCipher /*|| ++ prBssDesc->u4RsnSelectedAKMSuite != prAisBssInfo->u4RsnSelectedAKMSuite */) { ++ DBGLOG(RSN, TRACE, "-- Encrypt status not matched for PMKID\n"); ++ return; ++ } ++#endif ++ ++ rsnUpdatePmkidCandidateList(prAdapter, prBssDesc); ++ ++} /* rsnSelectPmkidCandidateList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to select a list of BSSID from ++* the scan results for PMKID candidate list. ++* ++* \param[in] prBssDesc the BSS DESC at scan result list ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) ++{ ++ UINT_32 i; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("rsnUpdatePmkidCandidateList"); ++ ++ ASSERT(prBssDesc); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ DBGLOG(RSN, TRACE, "-- SSID not matched\n"); ++ return; ++ } ++ ++ for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) { ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)) ++ return; ++ } ++ ++ /* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16), ++ then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache */ ++ if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE) ++ prAisSpecBssInfo->u4PmkidCandicateCount--; ++ ++ i = prAisSpecBssInfo->u4PmkidCandicateCount; ++ ++ COPY_MAC_ADDR((PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, (PVOID) prBssDesc->aucBSSID); ++ ++ if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) { ++ prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1; ++ DBGLOG(RSN, TRACE, "Add %pM with pre-auth to candidate list\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ } else { ++ prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0; ++ DBGLOG(RSN, TRACE, "Add %pM without pre-auth to candidate list\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ } ++ ++ prAisSpecBssInfo->u4PmkidCandicateCount++; ++ ++} /* rsnUpdatePmkidCandidateList */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search the desired entry in ++* PMKID cache according to the BSSID ++* ++* \param[in] pucBssid Pointer to the BSSID ++* \param[out] pu4EntryIndex Pointer to place the found entry index ++* ++* \retval TRUE, if found one entry for specified BSSID ++* \retval FALSE, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex) ++{ ++ UINT_32 i; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ DEBUGFUNC("rsnSearchPmkidEntry"); ++ ++ ASSERT(pucBssid); ++ ASSERT(pu4EntryIndex); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE) ++ return FALSE; ++ ++ ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE); ++ ++ /* Search for desired BSSID */ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { ++ if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, pucBssid, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ /* If desired BSSID is found, then set the PMKID */ ++ if (i < prAisSpecBssInfo->u4PmkidCacheCount) { ++ *pu4EntryIndex = i; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} /* rsnSearchPmkidEntry */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check if there is difference ++* between PMKID candicate list and PMKID cache. If there ++* is new candicate that no cache entry is available, then ++* add a new entry for the new candicate in the PMKID cache ++* and set the PMKID indication flag to TRUE. ++* ++* \retval TRUE, if new member in the PMKID candicate list ++* \retval FALSe, if no new member in the PMKID candicate list ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ UINT_32 i; /* Index for PMKID candicate */ ++ UINT_32 j; /* Indix for PMKID cache */ ++ BOOLEAN status = FALSE; ++ ++ DEBUGFUNC("rsnCheckPmkidCandicate"); ++ ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ /* Check for each candicate */ ++ for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) { ++ for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) { ++ if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN)) { ++ /* DBGLOG(RSN, TRACE, ("%pM at PMKID cache!!\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); */ ++ break; ++ } ++ } ++ ++ /* No entry found in PMKID cache for the candicate, add new one */ ++ if (j == prAisSpecBssInfo->u4PmkidCacheCount ++ && prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) { ++ DBGLOG(RSN, TRACE, ++ "Add %pM to PMKID cache!!\n", ++ (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); ++ kalMemCopy((PVOID) prAisSpecBssInfo-> ++ arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.arBSSID, ++ (PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN); ++ prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].fgPmkidExist = FALSE; ++ prAisSpecBssInfo->u4PmkidCacheCount++; ++ ++ status = TRUE; ++ } ++ } ++ ++ return status; ++} /* rsnCheckPmkidCandicate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to wait a duration to indicate the pre-auth AP candicate ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) ++{ ++ DBGLOG(RSN, EVENT, "Security - Time to indicate the PMKID cand.\n"); ++ ++ /* If the authentication mode is WPA2 and indication PMKID flag ++ is available, then we indicate the PMKID candidate list to NDIS and ++ clear the flag, indicatePMKID */ ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED && ++ prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnGeneratePmkidIndication(prAdapter); ++ } ++ ++} /* end of rsnIndicatePmkidCand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check the BSS Desc at scan result ++* with pre-auth cap at wpa2 mode. If there ++* is candicate that no cache entry is available, then ++* add a new entry for the new candicate in the PMKID cache ++* and set the PMKID indication flag to TRUE. ++* ++* \param[in] prBss The BSS Desc at scan result ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ DEBUGFUNC("rsnCheckPmkidCandicate"); ++ ++ ASSERT(prBss); ++ ++ prConnSettings = &prAdapter->rWifiVar.rConnSettings; ++ prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && ++ (prConnSettings->eAuthMode == AUTH_MODE_WPA2)) { ++ rsnSelectPmkidCandidateList(prAdapter, prBss); ++ ++ /* Set indication flag of PMKID to TRUE, and then connHandleNetworkConnection() ++ will indicate this later */ ++ if (rsnCheckPmkidCandicate(prAdapter)) { ++ DBGLOG(RSN, TRACE, "Prepare a timer to indicate candidate PMKID Candidate\n"); ++ cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to generate an PMKID candidate list ++* indication to NDIS. ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] u4Flags PMKID candidate list event: ++* PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter) ++{ ++ P_PARAM_STATUS_INDICATION_T prStatusEvent; ++ P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; ++ UINT_8 i, j = 0, count = 0; ++ UINT_32 u4LenOfUsedBuffer; ++ ++ DEBUGFUNC("rsnGeneratePmkidIndication"); ++ ++ ASSERT(prAdapter); ++ ++ prStatusEvent = (P_PARAM_STATUS_INDICATION_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: PMKID Candidatelist Event */ ++ prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; ++ ASSERT(prStatusEvent); ++ ++ prPmkidEvent = (P_PARAM_PMKID_CANDIDATE_LIST_T) (&prStatusEvent->eStatusType + 1); ++ ASSERT(prPmkidEvent); ++ ++ prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prAisSpecificBssInfo); ++ ++ for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) { ++ for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) { ++ if (EQUAL_MAC_ADDR(prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, ++ prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) && ++ (prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == TRUE)) { ++ break; ++ } ++ } ++ if (count >= CFG_MAX_PMKID_CACHE) ++ break; ++ ++ if (j == prAisSpecificBssInfo->u4PmkidCacheCount) { ++ kalMemCopy((PVOID) prPmkidEvent->arCandidateList[count].arBSSID, ++ (PVOID) prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, PARAM_MAC_ADDR_LEN); ++ prPmkidEvent->arCandidateList[count].u4Flags = ++ prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags; ++ DBGLOG(RSN, TRACE, "%pM %d\n", (prPmkidEvent->arCandidateList[count].arBSSID), ++ (UINT_32) prPmkidEvent->arCandidateList[count].u4Flags); ++ count++; ++ } ++ } ++ ++ /* PMKID Candidate List */ ++ prPmkidEvent->u4Version = 1; ++ prPmkidEvent->u4NumCandidates = count; ++ DBGLOG(RSN, TRACE, "rsnGeneratePmkidIndication #%d\n", (UINT_32) prPmkidEvent->u4NumCandidates); ++ u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(UINT_32)) + ++ (count * sizeof(PARAM_PMKID_CANDIDATE_T)); ++ /* dumpMemory8((PUINT_8)prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); */ ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); ++ ++} /* rsnGeneratePmkidIndication */ ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WSC IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WSC IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 221 :0xDD */ ++ if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE, ++ prAdapter->prGlueInfo->u2WSCAssocInfoIELen); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen; ++ } ++ ++} ++#endif ++ ++#if CFG_SUPPORT_802_11W ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the Bip Key installed or not ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ if (prStaRec && prStaRec->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX) ++ return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to check the Sa query timeout. ++* ++* ++* \note ++* Called by: AIS module, Handle by Sa Quert timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ UINT_32 now; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ GET_CURRENT_SYSTIME(&now); ++ ++ if (CHECK_FOR_TIMEOUT(now, prBssSpecInfo->u4SaQueryStart, TU_TO_MSEC(1000))) { ++ LOG_FUNC("association SA Query timed out\n"); ++ ++ prBssSpecInfo->ucSaQueryTimedOut = 1; ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ prBssSpecInfo->pucSaQueryTransId = NULL; ++ prBssSpecInfo->u4SaQueryCount = 0; ++ cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); ++ /* Re-connect */ ++ DBGLOG(RSN, TRACE, "DisBy11w\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to start the 802.11w sa query timer. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_SA_QUERY_FRAME prTxFrame; ++ UINT_16 u2PayloadLen; ++ PUINT_8 pucTmp = NULL; ++ UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ASSERT(prBssInfo); ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ LOG_FUNC("MFP: Start Sa Query\n"); ++ ++ if (prBssSpecInfo->u4SaQueryCount > 0 && rsnCheckSaQueryTimeout(prAdapter)) { ++ LOG_FUNC("MFP: u4SaQueryCount count =%d\n", prBssSpecInfo->u4SaQueryCount); ++ return; ++ } ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_SA_QUERY_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; ++ prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; ++ ++ if (prBssSpecInfo->u4SaQueryCount == 0) ++ GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart); ++ ++ if (prBssSpecInfo->u4SaQueryCount) { ++ pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); ++ if (!pucTmp) { ++ DBGLOG(RSN, ERROR, "MFP: Fail to alloc tmp buffer for backup sa query id\n"); ++ return; ++ } ++ kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ } ++ ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ ++ ucTransId[0] = (UINT_8) (kalRandomNumber() & 0xFF); ++ ucTransId[1] = (UINT_8) (kalRandomNumber() & 0xFF); ++ ++ kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ prBssSpecInfo->u4SaQueryCount++; ++ ++ prBssSpecInfo->pucSaQueryTransId = ++ kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); ++ if (!prBssSpecInfo->pucSaQueryTransId) { ++ DBGLOG(RSN, ERROR, "MFP: Fail to alloc buffer for sa query id list\n"); ++ return; ++ } ++ ++ if (pucTmp) { ++ kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp, ++ (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); ++ kalMemCopy(&prBssSpecInfo->pucSaQueryTransId ++ [(prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN], ucTransId, ++ ACTION_SA_QUERY_TR_ID_LEN); ++ kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); ++ } else { ++ kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ } ++ ++ u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ DBGLOG(RSN, TRACE, ++ "Set SA Query timer %d (%d sec)\n", prBssSpecInfo->u4SaQueryCount, prBssInfo->u2ObssScanInterval); ++ ++ cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, TU_TO_MSEC(201)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to start the 802.11w sa query. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStartSaQuery(IN P_ADAPTER_T prAdapter) ++{ ++ rsnStartSaQueryTimer(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to stop the 802.11w sa query. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnStopSaQuery(IN P_ADAPTER_T prAdapter) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); ++ kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, ++ prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); ++ prBssSpecInfo->pucSaQueryTransId = NULL; ++ prBssSpecInfo->u4SaQueryCount = 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w sa query action frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; ++ UINT_16 u2PayloadLen; ++ P_STA_RECORD_T prStaRec; ++ P_ACTION_SA_QUERY_FRAME prTxFrame; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; ++ ASSERT(prBssInfo); ++ ++ prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; ++ if (!prRxFrame) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Request from %pM\n", prStaRec->aucMacAddr); ++ ++ DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Ignore SA Query Request from unassociated STA %pM\n", ++ prStaRec->aucMacAddr); ++ return; ++ } ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Sending SA Query Response to %pM\n", prStaRec->aucMacAddr); ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_SA_QUERY_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ /* SA Query always with protected */ ++ prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; ++ prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; ++ ++ kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w sa query action frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; ++ P_ACTION_SA_QUERY_FRAME prRxFrame; ++ P_STA_RECORD_T prStaRec; ++ UINT_32 i; ++ ++ prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ASSERT(prBssSpecInfo); ++ ++ prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Too short SA Query Action frame (len=%u)\n", ++ prSwRfb->u2PacketLen); ++ return; ++ } ++ ++ if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { ++ rsnSaQueryRequest(prAdapter, prSwRfb); ++ return; ++ } ++ ++ if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Unexpected SA Query " "Action %d\n", prRxFrame->ucAction); ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Response from %pM\n", prStaRec->aucMacAddr); ++ ++ DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); ++ ++ /* MLME-SAQuery.confirm */ ++ ++ for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) { ++ if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId + ++ i * ACTION_SA_QUERY_TR_ID_LEN, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) ++ break; ++ } ++ ++ if (i >= prBssSpecInfo->u4SaQueryCount) { ++ DBGLOG(RSN, TRACE, "IEEE 802.11: No matching SA Query " "transaction identifier found\n"); ++ return; ++ } ++ ++ DBGLOG(RSN, TRACE, "Reply to pending SA Query received\n"); ++ ++ rsnStopSaQuery(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11w mgmt frame. ++* ++* ++* \note ++* Called by: AIS module, Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype) ++{ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ BOOLEAN fgUnicast = TRUE; ++ BOOLEAN fgRobustAction = FALSE; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) && ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { ++ ++ P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; ++ ++ prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; ++ ++ if (prAssocReqFrame->aucDestAddr[0] & BIT(0)) ++ fgUnicast = FALSE; ++ ++ LOG_FUNC("QM RX MGT: rsnCheckRxMgmt = %d 0x%x %d ucSubtype=%x\n", fgUnicast, prHifRxHdr->ucReserved, ++ (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC), ucSubtype); ++ ++ if (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC) { ++ /* "Dropped unprotected Robust Action frame from an MFP STA" */ ++ /* exclude Public Action */ ++ if (ucSubtype == 13 /* 0x1011: MAC_FRAME_ACTION */) { ++ UINT_8 ucAction = *prSwRfb->pucRecvBuff; ++ ++ if (ucAction != CATEGORY_PUBLIC_ACTION && ucAction != CATEGORY_HT_ACTION) { ++#if DBG && CFG_RX_PKTS_DUMP ++ LOG_FUNC("QM RX MGT: UnProtected Robust Action frame = %d\n", ucAction); ++#endif ++ fgRobustAction = TRUE; ++ return TRUE; ++ } ++ } ++ if (fgUnicast && ((ucSubtype == 10 /* 0x1010: MAC_FRAME_DISASSOC */) ++ || (ucSubtype == 12 /* 0x1100: MAC_FRAME_DEAUTH */))) { ++ LOG_FUNC("QM RX MGT: rsnStartSaQuery\n"); ++ /* MFP test plan 5.3.3.5 */ ++ rsnStartSaQuery(prAdapter); ++ return TRUE; ++ } ++ } ++#if 0 ++ else { ++ if (fgUnicast && ((ucSubtype == MAC_FRAME_DISASSOC) || (ucSubtype == MAC_FRAME_DEAUTH))) { ++ /* This done by function handler */ ++ /* kalIndicateStatusAndComplete(prAdapter->prGlueInfo, */ ++ /* WLAN_STATUS_MEDIA_DISCONNECT, */ ++ /* NULL, */ ++ /* 0); */ ++ } ++ } ++#endif ++ } ++ return FALSE; ++} ++#endif ++ ++#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE ++static BOOLEAN rsnCheckWpaRsnInfo(P_BSS_INFO_T prBss, P_RSN_INFO_T prWpaRsnInfo) ++{ ++ UINT_32 i = 0; ++ ++ if (prWpaRsnInfo->u4GroupKeyCipherSuite != prBss->u4RsnSelectedGroupCipher) { ++ DBGLOG(RSN, INFO, "GroupCipherSuite change, old=0x%04x, new=0x%04x\n", ++ prBss->u4RsnSelectedGroupCipher, prWpaRsnInfo->u4GroupKeyCipherSuite); ++ return TRUE; ++ } ++ for (; i < prWpaRsnInfo->u4AuthKeyMgtSuiteCount; i++) ++ if (prBss->u4RsnSelectedAKMSuite == prWpaRsnInfo->au4AuthKeyMgtSuite[i]) ++ break; ++ if (i == prWpaRsnInfo->u4AuthKeyMgtSuiteCount) { ++ DBGLOG(RSN, INFO, "KeyMgmt change, not find 0x%04x in new beacon\n", prBss->u4RsnSelectedAKMSuite); ++ return TRUE; ++ } ++ ++ for (i = 0; i < prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) ++ if (prBss->u4RsnSelectedPairwiseCipher == prWpaRsnInfo->au4PairwiseKeyCipherSuite[i]) ++ break; ++ if (i == prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount) { ++ DBGLOG(RSN, INFO, "Pairwise Cipher change, not find 0x%04x in new beacon\n", ++ prBss->u4RsnSelectedPairwiseCipher); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc) ++{ ++ ENUM_PARAM_AUTH_MODE_T eAuthMode = prAdapter->rWifiVar.rConnSettings.eAuthMode; ++ ++ switch (eAuthMode) { ++ case AUTH_MODE_OPEN: /* original is open system */ ++ if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) && !prAdapter->prGlueInfo->rWpaInfo.fgPrivacyInvoke) { ++ DBGLOG(RSN, INFO, "security change, open->privacy\n"); ++ return TRUE; ++ } ++ break; ++ case AUTH_MODE_SHARED: /* original is WEP */ ++ case AUTH_MODE_AUTO_SWITCH: ++ if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) == 0) { ++ DBGLOG(RSN, INFO, "security change, WEP->open\n"); ++ return TRUE; ++ } else if (prBssDesc->fgIERSN || prBssDesc->fgIEWPA) { ++ DBGLOG(RSN, INFO, "security change, WEP->WPA/WPA2\n"); ++ return TRUE; ++ } ++ break; ++ case AUTH_MODE_WPA: /*original is WPA */ ++ case AUTH_MODE_WPA_PSK: ++ case AUTH_MODE_WPA_NONE: ++ if (prBssDesc->fgIEWPA) ++ return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rWPAInfo); ++ DBGLOG(RSN, INFO, "security change, WPA->%s\n", ++ prBssDesc->fgIERSN ? "WPA2" : ++ (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); ++ return TRUE; ++ case AUTH_MODE_WPA2: /*original is WPA2 */ ++ case AUTH_MODE_WPA2_PSK: ++ if (prBssDesc->fgIERSN) ++ return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rRSNInfo); ++ DBGLOG(RSN, INFO, "security change, WPA2->%s\n", ++ prBssDesc->fgIEWPA ? "WPA" : ++ (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); ++ return TRUE; ++ default: ++ DBGLOG(RSN, WARN, "unknowned eAuthMode=%d\n", eAuthMode); ++ break; ++ } ++ /*DBGLOG(RSN, INFO, ("rsnCheckSecurityModeChanged, eAuthMode=%d, u2CapInfo=0x%02x, fgIEWPA=%d, fgIERSN=%d\n", ++ eAuthMode, prBssDesc->u2CapInfo, prBssDesc->fgIEWPA, prBssDesc->fgIERSN)); */ ++ return FALSE; ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c +new file mode 100644 +index 000000000000..596ede60d788 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c +@@ -0,0 +1,1788 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/saa_fsm.c#2 ++*/ ++ ++/*! \file "saa_fsm.c" ++ \brief This file defines the FSM for SAA MODULE. ++ ++ This file defines the FSM for SAA MODULE. ++*/ ++ ++/* ++** Log: saa_fsm.c ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 04 20 2012 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * correct macro ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT ++ * for REASSOCIATED cases as an explicit trigger for Android framework ++ * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. ++ * 2. (Android only) when reassociation-and-non-roaming cases happened, ++ * indicate an extra DISCONNECT indication to Android Wi-Fi framework ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 09 30 2011 cm.chang ++ * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band ++ * Add debug message about 40MHz bandwidth allowed ++ * ++ * 05 12 2011 cp.wu ++ * [WCXRP00000720] [MT6620 Wi-Fi][Driver] Do not do any further operation in case STA-REC ++ * has been invalidated before SAA-FSM starts to roll ++ * check for valid STA-REC before SAA-FSM starts to roll. ++ * ++ * 04 21 2011 terry.wu ++ * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame ++ * Add network type parameter to authSendAuthFrame. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 03 31 2011 puff.wen ++ * NULL ++ * . ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix compile error of after Station Type Macro modification. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete ++ * and might leads to BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. ++ * Update saa_fsm for BOW. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * Add support for P2P join event start. ++ * ++ * 07 12 2010 cp.wu ++ * ++ * SAA will take a record for tracking request sequence number. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * AIS-FSM integration with CNM channel request messages ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with main branch for resetting to state 1 when associating with another AP ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration the security related function from firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error when enable WiFi Direct function. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * ++ * * * Add Connection Policy - Any and Rx Burst Deauth Support for WHQL ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support of Driver STA_RECORD_T activation ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 12 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Fix compile warning due to declared but not used ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Refine Debug Label ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update comment ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * rename the function ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugAAState[AA_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("AA_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH1"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH2"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH3"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH4"), ++ (PUINT_8) DISP_STRING("SAA_STATE_SEND_ASSOC1"), ++ (PUINT_8) DISP_STRING("SAA_STATE_WAIT_ASSOC2"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH2"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH4"), ++ (PUINT_8) DISP_STRING("AAA_STATE_SEND_ASSOC2"), ++ (PUINT_8) DISP_STRING("AA_STATE_RESOURCE") ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The Core FSM engine of SAA Module. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] eNextState The value of Next State ++* @param[in] prRetainedSwRfb Pointer to the retained SW_RFB_T for JOIN Success ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++saaFsmSteps(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb) ++{ ++ ENUM_AA_STATE_T ePreviousState; ++ BOOLEAN fgIsTransition; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ return; ++ } ++ ++ do { ++ ++#if DBG ++ DBGLOG(SAA, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugAAState[prStaRec->eAuthAssocState], apucDebugAAState[eNextState]); ++#else ++ DBGLOG(SAA, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_SAA_IDX, prStaRec->eAuthAssocState, eNextState); ++#endif ++ ePreviousState = prStaRec->eAuthAssocState; ++ ++ /* NOTE(Kevin): This is the only place to change the eAuthAssocState(except initial) */ ++ prStaRec->eAuthAssocState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ switch (prStaRec->eAuthAssocState) { ++ case AA_STATE_IDLE: ++ if (ePreviousState != prStaRec->eAuthAssocState) { /* Only trigger this event once */ ++ ++ if (prRetainedSwRfb) { ++ if (saaFsmSendEventJoinComplete(prAdapter, ++ WLAN_STATUS_SUCCESS, ++ prStaRec, ++ prRetainedSwRfb) == WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ } else { ++ eNextState = AA_STATE_RESOURCE; ++ fgIsTransition = TRUE; ++ } ++ } else { ++ if (saaFsmSendEventJoinComplete(prAdapter, ++ WLAN_STATUS_FAILURE, ++ prStaRec, ++ NULL) == WLAN_STATUS_RESOURCES) { ++ eNextState = AA_STATE_RESOURCE; ++ fgIsTransition = TRUE; ++ } ++ } ++ ++ } ++ ++ /* Free allocated TCM memory */ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH1: ++ { ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++ /* Update Station Record - Class 1 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++#if !CFG_SUPPORT_AAA ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) { ++#else ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, ++ prStaRec->ucNetTypeIndex, ++ NULL, ++ AUTH_TRANSACTION_SEQ_1, ++ STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { ++#endif /* CFG_SUPPORT_AAA */ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ } ++ break; ++ ++ case SAA_STATE_WAIT_AUTH2: ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ { ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++#if !CFG_SUPPORT_AAA ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) { ++#else ++ if (authSendAuthFrame(prAdapter, ++ prStaRec, ++ prStaRec->ucNetTypeIndex, ++ NULL, ++ AUTH_TRANSACTION_SEQ_3, ++ STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { ++#endif /* CFG_SUPPORT_AAA */ ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ } ++ break; ++ ++ case SAA_STATE_WAIT_AUTH4: ++ break; ++ ++ case SAA_STATE_SEND_ASSOC1: ++ /* Do tasks in INIT STATE */ ++ if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; ++ ++ eNextState = AA_STATE_IDLE; ++ fgIsTransition = TRUE; ++ } else { ++ prStaRec->ucTxAuthAssocRetryCount++; ++ ++ if (assocSendReAssocReqFrame(prAdapter, prStaRec) != WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(TX_ASSOCIATION_RETRY_TIMEOUT_TU)); ++ } ++ } ++ ++ break; ++ ++ case SAA_STATE_WAIT_ASSOC2: ++ break; ++ ++ case AA_STATE_RESOURCE: ++ /* TODO(Kevin) Can setup a timer and send message later */ ++ break; ++ ++ default: ++ DBGLOG(SAA, ERROR, "Unknown AA STATE\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ } while (fgIsTransition); ++ ++ return; ++ ++} /* end of saaFsmSteps() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Event to AIS/BOW/P2P ++* ++* @param[in] rJoinStatus To indicate JOIN success or failure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* @param[in] prSwRfb Pointer to the SW_RFB_T ++ ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, ++ IN WLAN_STATUS rJoinStatus, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return WLAN_STATUS_INVALID_PACKET; ++ ++ /* Store limitation about 40Mhz bandwidth capability during association */ ++ if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if (rJoinStatus == WLAN_STATUS_SUCCESS) ++ prBssInfo->fg40mBwAllowed = prBssInfo->fgAssoc40mBwAllowed; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { ++ /* @TODO: BOW handler */ ++ ++ P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; ++ ++ prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); ++ if (!prSaaFsmCompMsg) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; ++ prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; ++ prSaaFsmCompMsg->rJoinStatus = rJoinStatus; ++ prSaaFsmCompMsg->prStaRec = prStaRec; ++ prSaaFsmCompMsg->prSwRfb = prSwRfb; ++ ++ /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); ++ ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ else { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++} /* end of saaFsmSendEventJoinComplete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Start Event to SAA FSM. ++* ++* @param[in] prMsgHdr Message of Join Request for a particular STA. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_FSM_START_T prSaaFsmStartMsg; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsgHdr); ++ ++ prSaaFsmStartMsg = (P_MSG_SAA_FSM_START_T) prMsgHdr; ++ prStaRec = prSaaFsmStartMsg->prStaRec; ++ ++ if ((!prStaRec) || (prStaRec->fgIsInUse == FALSE)) { ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM.\n"); ++ ++ /* record sequence number of request message */ ++ prStaRec->ucAuthAssocReqSeqNum = prSaaFsmStartMsg->ucSeqNum; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ /* 4 <1> Validation of SAA Start Event */ ++ if (!IS_AP_STA(prStaRec)) { ++ ++ DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); ++ ++ /* Ignore the return value because don't care the prSwRfb */ ++ saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, prStaRec, NULL); ++ ++ return; ++ } ++ /* 4 <2> The previous JOIN process is not completed ? */ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++ DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++ } ++ /* 4 <3> Reset Status Code and Time */ ++ /* Update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; ++ ++ /* Update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); ++ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ if (prStaRec->prChallengeText) { ++ cnmMemFree(prAdapter, prStaRec->prChallengeText); ++ prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; ++ } ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++#if CFG_PRIVACY_MIGRATION ++ /* 4 <4> Init the sec fsm */ ++ secFsmInit(prAdapter, prStaRec); ++#endif ++ ++ /* 4 <5> Reset the STA STATE */ ++ /* Update Station Record - Class 1 Flag */ ++ /* NOTE(Kevin): Moved to AIS FSM for Reconnect issue - ++ * We won't deactivate the same STA_RECORD_T and then activate it again for the ++ * case of reconnection. ++ */ ++ /* cnmStaRecChangeState(prStaRec, STA_STATE_1); */ ++ ++ /* 4 <6> Decide if this BSS 20/40M bandwidth is allowed */ ++ if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ++ if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) ++ && (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ prBssInfo->fgAssoc40mBwAllowed = cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex); ++ } else { ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ DBGLOG(RLM, INFO, "STA 40mAllowed=%d\n", prBssInfo->fgAssoc40mBwAllowed); ++ } ++ /* 4 <7> Trigger SAA FSM */ ++ if (prStaRec->ucStaState == STA_STATE_1) ++ saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); ++ else if (prStaRec->ucStaState == STA_STATE_2 || prStaRec->ucStaState == STA_STATE_3) ++ saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_ASSOC1, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventStart() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(Auth1/Auth3/AssocReq) Event of SAA FSM. ++* ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ ENUM_AA_STATE_T eNextState; ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ DBGLOG(SAA, INFO, "EVENT-TX DONE: Status %d, Invalid StaRec\n", rTxDoneStatus); ++ return WLAN_STATUS_INVALID_PACKET; ++ } ++ ++ ASSERT(prStaRec); ++ ++ DBGLOG(SAA, INFO, "EVENT-TX DONE: Status: %d, eAuthAssocState: %d , SeqNO: %d ", ++ rTxDoneStatus, prStaRec->eAuthAssocState, ++ prMsduInfo->ucTxSeqNum); ++ ++ eNextState = prStaRec->eAuthAssocState; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ { ++ /* Strictly check the outgoing frame is matched with current AA STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_AUTH2; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); ++ } ++ ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ { ++ /* Strictly check the outgoing frame is matched with current JOIN STATE */ ++ if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_AUTH4; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); ++ } ++ ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_ASSOC1: ++ { ++ /* Strictly check the outgoing frame is matched with current SAA STATE */ ++ if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) ++ break; ++ ++ if (rTxDoneStatus == TX_RESULT_SUCCESS) { ++ eNextState = SAA_STATE_WAIT_ASSOC2; ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prStaRec->rTxReqDoneOrRxRespTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, ++ (ULONG) prStaRec); ++ ++ cnmTimerStartTimer(prAdapter, ++ &(prStaRec->rTxReqDoneOrRxRespTimer), ++ TU_TO_MSEC(DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU)); ++ } ++ /* if TX was successful, change to next state. ++ * if TX was failed, do retry if possible. ++ */ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of saaFsmRunEventTxDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Tx Request Timeout Event to SAA FSM. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ++ DBGLOG(SAA, LOUD, "EVENT-TIMER: TX REQ TIMEOUT, Current Time = %u\n", kalGetTimeTick()); ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ case SAA_STATE_SEND_AUTH3: ++ case SAA_STATE_SEND_ASSOC1: ++ saaFsmSteps(prAdapter, prStaRec, prStaRec->eAuthAssocState, (P_SW_RFB_T) NULL); ++ break; ++ ++ default: ++ return; ++ } ++ ++} /* end of saaFsmRunEventTxReqTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will send Rx Response Timeout Event to SAA FSM. ++* ++* @param[in] prStaRec Pointer to the STA_RECORD_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ENUM_AA_STATE_T eNextState; ++ ++ DBGLOG(SAA, LOUD, "EVENT-TIMER: RX RESP TIMEOUT, Current Time = %u\n", kalGetTimeTick()); ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) ++ return; ++ ++ eNextState = prStaRec->eAuthAssocState; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_WAIT_AUTH2: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_AUTH1; ++ break; ++ ++ case SAA_STATE_WAIT_AUTH4: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_AUTH3; ++ break; ++ ++ case SAA_STATE_WAIT_ASSOC2: ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; ++ ++ /* Pull back to earlier state to do retry */ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ if (eNextState != prStaRec->eAuthAssocState) ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ ++} /* end of saaFsmRunEventRxRespTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx Auth Response Frame and then ++* trigger SAA FSM. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2StatusCode; ++ ENUM_AA_STATE_T eNextState; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if (!prStaRec) { ++ /* Peter: we can handle the packet without station record */ ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ if (!IS_AP_STA(prStaRec)) ++ return; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_AUTH1: ++ case SAA_STATE_WAIT_AUTH2: ++ /* Check if the incoming frame is what we are waiting for */ ++ if (authCheckRxAuthFrameStatus(prAdapter, ++ prSwRfb, AUTH_TRANSACTION_SEQ_2, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); ++ ++ if (prStaRec->ucAuthAlgNum == (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY) { ++ ++ eNextState = SAA_STATE_SEND_AUTH3; ++ } else { ++ /* Update Station Record - Class 2 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ } ++ } else { ++ DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ ++ eNextState = AA_STATE_IDLE; ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ case SAA_STATE_SEND_AUTH3: ++ case SAA_STATE_WAIT_AUTH4: ++ /* Check if the incoming frame is what we are waiting for */ ++ if (authCheckRxAuthFrameStatus(prAdapter, ++ prSwRfb, AUTH_TRANSACTION_SEQ_4, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); /* Add for 802.11r handling */ ++ ++ /* Update Station Record - Class 2 Flag */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ eNextState = SAA_STATE_SEND_ASSOC1; ++ } else { ++ DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ ++ eNextState = AA_STATE_IDLE; ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++} /* end of saaFsmRunEventRxAuth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will process the Rx (Re)Association Response Frame and then ++* trigger SAA FSM. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS if the status code was not success ++* @retval WLAN_STATUS_BUFFER_RETAINED if the status code was success ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2StatusCode; ++ ENUM_AA_STATE_T eNextState; ++ P_SW_RFB_T prRetainedSwRfb = (P_SW_RFB_T) NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ /* We should have the corresponding Sta Record. */ ++ if (!prStaRec) { ++ ASSERT(0); ++ return rStatus; ++ } ++ ++ if (!IS_AP_STA(prStaRec)) ++ return rStatus; ++ ++ switch (prStaRec->eAuthAssocState) { ++ case SAA_STATE_SEND_ASSOC1: ++ case SAA_STATE_WAIT_ASSOC2: ++ /* TRUE if the incoming frame is what we are waiting for */ ++ if (assocCheckRxReAssocRspFrameStatus(prAdapter, prSwRfb, &u2StatusCode) == WLAN_STATUS_SUCCESS) { ++ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = u2StatusCode; ++ ++ if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { ++ ++ /* Update Station Record - Class 3 Flag */ ++ /* NOTE(Kevin): Moved to AIS FSM for roaming issue - ++ * We should deactivate the STA_RECORD_T of previous AP before ++ * activate new one in Driver. ++ */ ++ /* cnmStaRecChangeState(prStaRec, STA_STATE_3); */ ++ ++ prStaRec->ucJoinFailureCount = 0; /* Clear history. */ ++ ++ prRetainedSwRfb = prSwRfb; ++ rStatus = WLAN_STATUS_PENDING; ++ } else { ++ DBGLOG(SAA, INFO, "Assoc Req was rejected by [ %pM ], Status Code = %d\n", ++ (prStaRec->aucMacAddr), u2StatusCode); ++ } ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ /* update RCPI */ ++ prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; ++ ++ eNextState = AA_STATE_IDLE; ++ ++ saaFsmSteps(prAdapter, prStaRec, eNextState, prRetainedSwRfb); ++ } ++ break; ++ ++ default: ++ break; /* Ignore other cases */ ++ } ++ ++ return rStatus; ++ ++} /* end of saaFsmRunEventRxAssoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Deauth Frame. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain deauthentication frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_DEAUTH_FRAME_T prDeauthFrame; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; ++ DBGLOG(SAA, INFO, "Rx Deauth frame from BSSID=[ %pM ].\n", prDeauthFrame->aucBSSID); ++ ++ do { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ if (!IS_AP_STA(prStaRec)) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prStaRec->ucStaState <= STA_STATE_1) ++ break; ++ ++ /* Check if this is the AP we are associated or associating with */ ++ if (authProcessRxDeauthFrame(prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ ++ DBGLOG(SAA, INFO, "Deauth reason = %d\n", prStaRec->u2ReasonCode); ++ ++ if (STA_STATE_2 <= prStaRec->ucStaState) { ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ ++ /* NOTE(Kevin): Change state immediately to avoid starvation of ++ * MSG buffer because of too many deauth frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ prAisAbortMsg = ++ (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) ++ break; ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; ++ prAisAbortMsg->ucReasonOfDisconnect = ++ DISCONNECT_REASON_CODE_DEAUTHENTICATED; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, ++ (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ } else { ++ ++ /* TODO(Kevin): Joining Abort */ ++ } ++ prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; ++ ++ } ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ /* TODO(Kevin) */ ++ p2pFsmRunEventRxDeauthentication(prAdapter, prStaRec, prSwRfb); ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) ++ bowRunEventRxDeAuth(prAdapter, prStaRec, prSwRfb); ++#endif ++ else ++ ASSERT(0); ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of saaFsmRunEventRxDeauth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will check the incoming Disassociation Frame. ++* ++* @param[in] prSwRfb Pointer to the SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS Always not retain disassociation frames ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_DISASSOC_FRAME_T prDisassocFrame; ++ ++ ASSERT(prSwRfb); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if (prStaRec == NULL) ++ return WLAN_STATUS_FAILURE; ++ ++ prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; ++ DBGLOG(SAA, INFO, "Rx Disassoc frame from BSSID=[ %pM ].\n", (prDisassocFrame->aucBSSID)); ++ ++ do { ++ if (IS_STA_IN_AIS(prStaRec)) { ++ P_AIS_BSS_INFO_T prAisBssInfo; ++ ++ if (!IS_AP_STA(prStaRec)) ++ break; ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prStaRec->ucStaState <= STA_STATE_1) ++ break; ++ ++ /* Check if this is the AP we are associated or associating with */ ++ if (assocProcessRxDisassocFrame(prAdapter, ++ prSwRfb, ++ prStaRec->aucMacAddr, ++ &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { ++ ++ DBGLOG(SAA, INFO, "Disassoc reason = %d\n", prStaRec->u2ReasonCode); ++ ++ if (STA_STATE_3 <= prStaRec->ucStaState) { ++ P_MSG_AIS_ABORT_T prAisAbortMsg; ++ /* NOTE(Chaozhong): Change state immediately to avoid starvation of ++ * MSG buffer because of too many disassoc frames before changing ++ * the STA state. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); ++ ++ prAisAbortMsg = ++ (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_AIS_ABORT_T)); ++ if (!prAisAbortMsg) ++ break; ++ ++ prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; ++ prAisAbortMsg->ucReasonOfDisconnect = ++ DISCONNECT_REASON_CODE_DISASSOCIATED; ++ prAisAbortMsg->fgDelayIndication = FALSE; ++ ++ mboxSendMsg(prAdapter, ++ MBOX_ID_0, ++ (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); ++ } else { ++ ++ /* TODO(Kevin): Joining Abort */ ++ } ++ prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; ++ ++ } ++ ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { ++ /* TODO(Kevin) */ ++ p2pFsmRunEventRxDisassociation(prAdapter, prStaRec, prSwRfb); ++ } ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (IS_STA_IN_BOW(prStaRec)) { ++ /* Do nothing */ ++ /* TODO(Kevin) */ ++ } ++#endif ++ else ++ ASSERT(0); ++ ++ } while (FALSE); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of saaFsmRunEventRxDisassoc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle the Abort Event to SAA FSM. ++* ++* @param[in] prMsgHdr Message of Abort Request for a particular STA. ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SAA_FSM_ABORT_T prSaaFsmAbortMsg; ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prMsgHdr); ++ ++ prSaaFsmAbortMsg = (P_MSG_SAA_FSM_ABORT_T) prMsgHdr; ++ prStaRec = prSaaFsmAbortMsg->prStaRec; ++ ++ ASSERT(prStaRec); ++ if (!prStaRec) { ++ cnmMemFree(prAdapter, prMsgHdr); ++ return; ++ } ++ ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Stop SAA FSM.\n"); ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prStaRec->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel JOIN relative Timer */ ++ cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); ++ ++ if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { ++#if DBG ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %s.\n", ++ apucDebugAAState[prStaRec->eAuthAssocState]); ++#else ++ DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %d.\n", prStaRec->eAuthAssocState); ++#endif ++ } ++#if 0 ++ /* For the Auth/Assoc State to IDLE */ ++ prStaRec->eAuthAssocState = AA_STATE_IDLE; ++#else ++ /* Free this StaRec */ ++ cnmStaRecFree(prAdapter, prStaRec, FALSE); ++#endif ++ ++} /* end of saaFsmRunEventAbort() */ ++ ++/* TODO(Kevin): following code will be modified and move to AIS FSM */ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will send Join Timeout Event to JOIN FSM. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("joinFsmRunEventJoinTimeOut"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ ++ DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); ++ ++ /* Get a Station Record if possible, TA == BSSID for AP */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); ++ ++ /* We have renew this Sta Record when in JOIN_STATE_INIT */ ++ ASSERT(prStaRec); ++ ++ /* Record the Status Code of Authentication Request */ ++ prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; ++ ++ /* Increase Failure Count */ ++ prStaRec->ucJoinFailureCount++; ++ ++ /* Reset Send Auth/(Re)Assoc Frame Count */ ++ prJoinInfo->ucTxAuthAssocRetryCount = 0; ++ ++ /* Cancel other JOIN relative Timer */ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); ++ ++ ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); ++ ++ /* Restore original setting from current BSS_INFO_T */ ++ if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) ++ joinAdoptParametersFromCurrentBss(prAdapter); ++ ++ /* Pull back to IDLE */ ++ joinFsmSteps(prAdapter, JOIN_STATE_IDLE); ++ ++ return WLAN_STATUS_FAILURE; ++ ++} /* end of joinFsmRunEventJoinTimeOut() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from Peer BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ ++ DEBUGFUNC("joinAdoptParametersFromPeerBss"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ ++ /* 4 <1> Adopt Peer BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssDesc->ePhyType; ++ ++ DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", ++ prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); ++ ++ /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); ++ ++ prJoinInfo->fgIsParameterAdopted = TRUE; ++ ++} /* end of joinAdoptParametersFromPeerBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will adopt the parameters from current associated BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) ++{ ++ /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ prBssInfo = &prAdapter->rBssInfo; ++ ++ /* 4 <1> Adopt current BSS' PHY TYPE */ ++ prAdapter->eCurrentPhyType = prBssInfo->ePhyType; ++ ++ /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ ++ DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); ++ ++ nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); ++} /* end of joinAdoptParametersFromCurrentBss() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will update all the SW variables and HW MCR registers after ++* the association with target BSS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID joinComplete(IN P_ADAPTER_T prAdapter) ++{ ++ P_JOIN_INFO_T prJoinInfo; ++ P_BSS_DESC_T prBssDesc; ++ P_PEER_BSS_INFO_T prPeerBssInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_STA_RECORD_T prStaRec; ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_802_11D ++ P_IE_COUNTRY_T prIECountry; ++#endif ++ ++ DEBUGFUNC("joinComplete"); ++ ++ ASSERT(prAdapter); ++ prJoinInfo = &prAdapter->rJoinInfo; ++ prBssDesc = prJoinInfo->prBssDesc; ++ prPeerBssInfo = &prAdapter->rPeerBssInfo; ++ prBssInfo = &prAdapter->rBssInfo; ++ prConnSettings = &prAdapter->rConnSettings; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ ++ /* Remove previous AP's Connection Flags if have */ ++ scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); ++ ++ prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ ++ ++ if (prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't ++ * broadcast SSID on its Beacon Frame. ++ */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); ++ ++ if (prBssDesc->ucSSIDLen) ++ prBssDesc->fgIsHiddenSSID = FALSE; ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++ DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); ++ } ++/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ ++ /* 4 <2.A> PHY Type */ ++ prBssInfo->ePhyType = prBssDesc->ePhyType; ++ ++ /* 4 <2.B> BSS Type */ ++ prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ /* 4 <2.C> BSSID */ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); ++ ++ DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); ++ ++ /* 4 <2.D> SSID */ ++ COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ /* 4 <2.E> Channel / Band information. */ ++ prBssInfo->eBand = prBssDesc->eBand; ++ prBssInfo->ucChnl = prBssDesc->ucChannelNum; ++ ++ /* 4 <2.F> RSN/WPA information. */ ++ secFsmRunEventStart(prAdapter); ++ prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; ++ prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; ++ prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; ++ ++ if (secRsnKeyHandshakeEnabled()) ++ prBssInfo->fgIsWPAorWPA2Enabled = TRUE; ++ else ++ prBssInfo->fgIsWPAorWPA2Enabled = FALSE; ++ ++ /* 4 <2.G> Beacon interval. */ ++ prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; ++ ++ /* 4 <2.H> DTIM period. */ ++ prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* 4 <2.I> ERP Information */ ++ if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ ++ (prBssDesc->fgIsERPPresent)) { ++ ++ prBssInfo->fgIsERPPresent = TRUE; ++ prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ ++ } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ ++ prBssInfo->fgIsERPPresent = FALSE; ++ prBssInfo->ucERP = 0; ++ } ++ ++#if CFG_SUPPORT_802_11D ++ /* 4 <2.J> Country inforamtion of the associated AP */ ++ if (prConnSettings->fgMultiDomainCapabilityEnabled) { ++ DOMAIN_INFO_ENTRY rDomainInfo; ++ ++ if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { ++ if (prBssDesc->prIECountry) { ++ prIECountry = prBssDesc->prIECountry; ++ ++ domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); ++ ++ /* use the domain get from the BSS info */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); ++ } else { ++ /* use the domain get from the scan result */ ++ prBssInfo->fgIsCountryInfoPresent = TRUE; ++ nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); ++ } ++ } ++ } ++#endif ++ ++ /* 4 <2.K> Signal Power of the associated AP */ ++ prBssInfo->rRcpi = prBssDesc->rRcpi; ++ prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); ++ GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); ++ ++ /* 4 <2.L> Capability Field of the associated AP */ ++ prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; ++ ++ DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", ++ prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); ++ ++/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ ++ /* 4 <3.A> Association ID */ ++ prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; ++ ++ /* 4 <3.B> WMM Information */ ++ if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { ++ ++ prBssInfo->fgIsWmmAssoc = TRUE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC3; ++ ++ qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); ++ ++ if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { ++ kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } else { ++ kalMemCopy(&prBssInfo->rWmmInfo, ++ &prPeerBssInfo->rWmmInfo, ++ sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); ++ } ++ } else { ++ prBssInfo->fgIsWmmAssoc = FALSE; ++ prTxCtrl->rTxQForVoipAccess = TXQ_AC1; ++ ++ kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); ++ } ++ ++ /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ ++ prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; ++ prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; ++ ++ /* 4 <3.D> Short Preamble */ ++ if (prBssInfo->fgIsERPPresent) { ++ ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) ++ * TRUE FALSE TRUE FALSE ++ * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) ++ * FALSE FALSE TRUE FALSE ++ * TRUE TRUE FALSE TRUE(follow ERP) ++ * TRUE TRUE TRUE FALSE(follow ERP) ++ * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) ++ * FALSE TRUE TRUE FALSE(we should set to FALSE) ++ */ ++ if ((prPeerBssInfo->fgIsShortPreambleAllowed) && ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || ++ ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && ++ (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { ++ ++ prBssInfo->fgIsShortPreambleAllowed = TRUE; ++ ++ if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) ++ prBssInfo->fgUseShortPreamble = FALSE; ++ else ++ prBssInfo->fgUseShortPreamble = TRUE; ++ } else { ++ prBssInfo->fgIsShortPreambleAllowed = FALSE; ++ prBssInfo->fgUseShortPreamble = FALSE; ++ } ++ } else { ++ /* NOTE(Kevin 2007/12/24): Truth Table. ++ * Short Preamble Bit in ++ * Final Driver Setting(Short) ++ * TRUE FALSE FALSE ++ * FALSE FALSE FALSE ++ * TRUE TRUE TRUE ++ * FALSE TRUE(status success) TRUE ++ * --> Honor the result of prPeerBssInfo. ++ */ ++ ++ prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = ++ prPeerBssInfo->fgIsShortPreambleAllowed; ++ } ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); ++ ++ /* 4 <3.E> Short Slot Time */ ++ prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ ++ ++ DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); ++ ++ nicSetSlotTime(prAdapter, ++ prBssInfo->ePhyType, ++ ((prConnSettings->fgIsShortSlotTimeOptionEnable && ++ prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); ++ ++ /* 4 <3.F> Update Tx Rate for Control Frame */ ++ bssUpdateTxRateForControlFrame(prAdapter); ++ ++ /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ ++ /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ ++ { ++ ++ if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; ++ else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) ++ prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; ++ ++ prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; ++ ++ /* Set the stable time of the associated BSS. We won't do roaming decision ++ * during the stable time. ++ */ ++ SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, ++ SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); ++ } ++ ++ /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ ++#if CFG_TX_FRAGMENT ++ txFragInfoUpdate(prAdapter); ++#endif /* CFG_TX_FRAGMENT */ ++ ++/* 4 <4> Update STA_RECORD_T */ ++ /* Get a Station Record if possible */ ++ prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); ++ ++ if (prStaRec) { ++ UINT_16 u2OperationalRateSet, u2DesiredRateSet; ++ ++ /* 4 <4.A> Desired Rate Set */ ++ u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & ++ prBssInfo->u2OperationalRateSet); ++ ++ u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); ++ if (u2DesiredRateSet) { ++ prStaRec->u2DesiredRateSet = u2DesiredRateSet; ++ } else { ++ /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ ++ prStaRec->u2DesiredRateSet = u2OperationalRateSet; ++ } ++ ++ /* Try to set the best initial rate for this entry */ ++ if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, ++ prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { ++ ++ if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) ++ ASSERT(0); ++ } ++ ++ DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); ++ ++ /* 4 <4.B> Preamble Mode */ ++ prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; ++ ++ /* 4 <4.C> QoS Flag */ ++ prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; ++ } ++#if DBG ++ else ++ ASSERT(0); ++#endif /* DBG */ ++ ++/* 4 <5> Update NIC */ ++ /* 4 <5.A> Update BSSID & Operation Mode */ ++ nicSetupBSS(prAdapter, prBssInfo); ++ ++ /* 4 <5.B> Update WLAN Table. */ ++ if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) ++ ASSERT(FALSE); ++ /* 4 <5.C> Update Desired Rate Set for BT. */ ++#if CFG_TX_FRAGMENT ++ if (prConnSettings->fgIsEnableTxAutoFragmentForBT) ++ txRateSetInitForBT(prAdapter, prStaRec); ++#endif /* CFG_TX_FRAGMENT */ ++ ++ /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ ++ if (prBssInfo->fgIsWmmAssoc) { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, FALSE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); ++ } else { ++ ++#if CFG_TX_AGGREGATE_HW_FIFO ++ nicTxAggregateTXQ(prAdapter, TRUE); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); ++ ++ nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); ++ } ++ ++#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN ++ { ++ prTxCtrl->fgBlockTxDuringJoin = FALSE; ++ ++#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ ++ nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); ++#endif /* CFG_TX_AGGREGATE_HW_FIFO */ ++ ++ nicTxRetransmitOfSendWaitQue(prAdapter); ++ ++ if (prTxCtrl->fgIsPacketInOsSendQueue) ++ nicTxRetransmitOfOsSendQue(prAdapter); ++#if CFG_SDIO_TX_ENHANCE ++ halTxLeftClusteredMpdu(prAdapter); ++#endif /* CFG_SDIO_TX_ENHANCE */ ++ ++ } ++#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ ++ ++/* 4 <6> Setup CONNECTION flag. */ ++ prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; ++ prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; ++ ++ if (prJoinInfo->fgIsReAssoc) ++ prAdapter->fgBypassPortCtrlForRoaming = TRUE; ++ else ++ prAdapter->fgBypassPortCtrlForRoaming = FALSE; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); ++ ++} /* end of joinComplete() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c +new file mode 100644 +index 000000000000..2c9ccbe82dd1 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c +@@ -0,0 +1,3103 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan.c#3 ++*/ ++ ++/*! \file "scan.c" ++ \brief This file defines the scan profile and the processing function of ++ scan result for SCAN Module. ++ ++ The SCAN Profile selection is part of SCAN MODULE and responsible for defining ++ SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. ++ In this file we also define the process of SCAN Result including adding, searching ++ and removing SCAN record from the list. ++*/ ++ ++/* ++** Log: scan.c ++** ++** 01 30 2013 yuche.tsai ++** [ALPS00451578] [JB2][WFD][Case Fail][JE][MR1]?????????[Java (JE),660,-1361051648,99, ++** /data/core/,0,system_server_crash,system_server]JE happens when try to connect WFD.(4/5) ++** Fix possible old scan result indicate to supplicant after formation. ++** ++** 01 16 2013 yuche.tsai ++** [ALPS00431980] [WFD]Aupus one ?play game 10 minitues?wfd connection automaticlly disconnect ++** Fix possible FW assert issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 25 2012 cp.wu ++ * [WCXRP00001258] [MT6620][MT5931][MT6628][Driver] Do not use stale scan result for deciding connection target ++ * drop off scan result which is older than 5 seconds when choosing which BSS to join ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 16 2012 cp.wu ++ * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band ++ * configuration with corresponding network configuration ++ * correct typo. ++ * ++ * 01 16 2012 cp.wu ++ * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration ++ * with corresponding network configuration ++ * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred ++ * band configuration corresponding to network type. ++ * ++ * 12 05 2011 cp.wu ++ * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path ++ * add CONNECT_BY_BSSID policy ++ * ++ * 11 23 2011 cp.wu ++ * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection ++ * add compile option to disable beacon content change detection. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001085] [MT6628 Wi-Fi][Driver] deprecate old BSS-DESC if timestamp ++ * is reset with received beacon/probe response frames ++ * deprecate old BSS-DESC when timestamp in received beacon/probe response frames showed a smaller value than before ++ * ++ * 10 11 2011 cm.chang ++ * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter ++ * Ignore HT OP IE if its length field is not valid ++ * ++ * 09 30 2011 cp.wu ++ * [WCXRP00001021] [MT5931][Driver] Correct scan result generation for conversion between BSS type and operation mode ++ * correct type casting issue. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 10 2011 cp.wu ++ * [WCXRP00000922] [MT6620 Wi-Fi][Driver] traverse whole BSS-DESC list for removing ++ * traverse whole BSS-DESC list because BSSID is not unique anymore. ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * for multiple BSS descriptior detecting issue: ++ * 1) check BSSID for infrastructure network ++ * 2) check SSID for AdHoc network ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * check for BSSID for beacons used to update DTIM ++ * ++ * 07 12 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * do not check BSS descriptor for connected flag due to linksys's hidden ++ * SSID will use another BSS descriptor and never connected ++ * ++ * 07 11 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * just pass beacons with the same BSSID. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define ++ * for make sure the value is initialize, for customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 28 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * Do not check for SSID as beacon content change due to the existence of ++ * single BSSID with multiple SSID AP configuration ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple ++ * SSID settings to work around some tricky AP which use space character as hidden SSID ++ * 1. correct logic ++ * 2. replace only BSS-DESC which doesn't have a valid SSID. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID ++ * settings to work around some tricky AP which use space character as hidden SSID ++ * remove unused temporal variable reference. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID ++ * settings to work around some tricky AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 06 02 2011 cp.wu ++ * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels ++ * filter out BSS in disallowed channel by ++ * 1. do not add to scan result array if BSS is at disallowed channel ++ * 2. do not allow to search for BSS-DESC in disallowed channels ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Refine range of valid channel number ++ * ++ * 05 02 2011 cp.wu ++ * [MT6620 Wi-Fi][Driver] Take parsed result for channel information instead of ++ * hardware channel number passed from firmware domain ++ * take parsed result for generating scanning result with channel information. ++ * ++ * 05 02 2011 cm.chang ++ * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number ++ * Check if channel is valided before record ing BSS channel ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Always update Bss Type, for Bss Type for P2P Network is changing every time. ++ * ++ * 03 23 2011 yuche.tsai ++ * NULL ++ * Fix concurrent issue when AIS scan result would overwrite p2p scan result. ++ * ++ * 03 14 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * filtering out other BSS coming from adjacent channels ++ * ++ * 03 11 2011 chinglan.wang ++ * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. ++ * . ++ * ++ * 03 11 2011 cp.wu ++ * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently ++ * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() ++ * won't sleep long enough for specified interval such as 500ms ++ * implement beacon change detection by checking SSID and supported rate. ++ * ++ * 02 22 2011 yuche.tsai ++ * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue ++ * Fix WSC big endian issue. ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix scan channel extension issue when p2p module is not registered. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 21 2011 cp.wu ++ * [WCXRP00000380] [MT6620 Wi-Fi][Driver] SSID information should come from buffered ++ * BSS_DESC_T rather than using beacon-carried information ++ * SSID should come from buffered prBssDesc rather than beacon-carried information ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Fix compile error. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Memfree for P2P Descriptor & P2P Descriptor List. ++ * ++ * 01 14 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * Free P2P Descriptor List & Descriptor under BSS Descriptor. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc ++ * and vmalloc implementations to ease physically continuous memory demands ++ * 1) correct typo in scan.c ++ * 2) TX descriptors, RX descriptos and management buffer should use virtually ++ * continuous buffer instead of physically continuous one ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc ++ * and vmalloc implementations to ease physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * while being unloaded, clear all pending interrupt then set LP-own to firmware ++ * ++ * 12 21 2010 cp.wu ++ * [WCXRP00000280] [MT6620 Wi-Fi][Driver] Enable BSS selection with best RCPI policy in SCN module ++ * SCN: enable BEST RSSI selection policy support ++ * ++ * 11 29 2010 cp.wu ++ * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC ++ * for initial TX rate selection of auto-rate algorithm ++ * update ucRcpi of STA_RECORD_T for AIS when ++ * 1) Beacons for IBSS merge is received ++ * 2) Associate Response for a connecting peer is received ++ * ++ * 11 03 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Refine the HT rate disallow TKIP pairwise cipher . ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out ++ * beacons which is received on the folding frequency ++ * trust HT IE if available for 5GHz band ++ * ++ * 10 11 2010 cp.wu ++ * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out ++ * beacons which is received on the folding frequency ++ * add timing and strenght constraint for filtering out beacons with same SSID/TA but received on different channels ++ * ++ * 10 08 2010 wh.su ++ * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine ++ * update the frog's new p2p state machine. ++ * ++ * 10 01 2010 yuche.tsai ++ * NULL ++ * [MT6620 P2P] Fix Big Endian Issue when parse P2P device name TLV. ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate unused variables which lead gcc to argue ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * When indicate scan result, append IE buffer information in the scan result. ++ * ++ * 09 03 2010 yuche.tsai ++ * NULL ++ * 1. Update Beacon RX count when running SLT. ++ * 2. Ignore Beacon when running SLT, would not update information from Beacon. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 29 2010 yuche.tsai ++ * NULL ++ * 1. Fix P2P Descriptor List to be a link list, to avoid link corrupt after Bss Descriptor Free. ++ * 2.. Fix P2P Device Name Length BE issue. ++ * ++ * 08 23 2010 yuche.tsai ++ * NULL ++ * Add P2P Device Found Indication to supplicant ++ * ++ * 08 20 2010 cp.wu ++ * NULL ++ * reset BSS_DESC_T variables before parsing IE due to peer might have been reconfigured. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Workaround for P2P Descriptor Infinite loop issue. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Modify code of processing Probe Resonse frame for P2P. ++ * ++ * 08 12 2010 yuche.tsai ++ * NULL ++ * Add function to get P2P descriptor of BSS descriptor directly. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Modify Scan result processing for P2P module. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update P2P Device Discovery result add function. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add support for Probe Request & Response parsing. ++ * ++ * 07 21 2010 cp.wu ++ * ++ * 1) change BG_SCAN to ONLINE_SCAN for consistent term ++ * 2) only clear scanning result when scan is permitted to do ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Fix compile error for SCAN module while disabling P2P feature. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 wh.su ++ * ++ * update for security supporting. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct BSS_DESC_T initialization after allocated. ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan uninitialization procedure ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * if beacon/probe-resp is received in 2.4GHz bands and there is ELEM_ID_DS_PARAM_SET IE available, ++ * trust IE instead of RMAC information ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 28 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * send MMPDU in basic rate. ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * modify Beacon/ProbeResp to complete parsing, ++ * because host software has looser memory usage restriction ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * integrate . ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 21 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Update P2P Function call. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * RSN/PRIVACY compilation flag awareness correction ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * specify correct value for management frames. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 18 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * migration from MT6620 firmware. ++ * ++ * 06 17 2010 yuche.tsai ++ * [WPD00003839][MT6620 5931][P2P] Feature migration ++ * Fix compile error when enable P2P function. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct when ADHOC support is turned on. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan.c. ++ * ++ * 06 04 2010 george.huang ++ * [BORA00000678][MT6620]WiFi LP integration ++ * [PM] Support U-APSD for STA mode ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * adding the TKIP disallow join a HT AP code. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add more chance of JOIN retry for BG_SCAN ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 04 29 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * adjsut the pre-authentication code. ++ * ++ * 04 27 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 19 2010 kevin.huang ++ * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support ++ * Add Beacon Timeout Support and will send Null frame to diagnose connection ++ * ++ * 04 13 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add new HW CH macro support ++ * ++ * 04 06 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the firmware return the broadcast frame at wrong tc. ++ * ++ * 03 29 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * let the rsn wapi IE always parsing. ++ * ++ * 03 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Not carry HT cap when being associated with b/g only AP ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Solve the compile warning for 'return non-void' function ++ * ++ * 03 16 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Add AdHoc Mode ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * ++ * * * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Fix No PKT_INFO_T issue ++ * ++ * 02 26 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Update outgoing ProbeRequest Frame's TX data rate ++ * ++ * 02 23 2010 wh.su ++ * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver ++ * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 02 04 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 22 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Support protection and bandwidth switch ++ * ++ * 01 20 2010 kevin.huang ++ * [BORA00000569][WIFISYS] Phase 2 Integration Test ++ * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags ++ * ++ * 01 11 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add Deauth and Disassoc Handler ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * ++ * Refine Beacon processing, add read RF channel from RX Status ++ * ++ * 01 04 2010 tehuang.liu ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * For working out the first connection Chariot-verified version ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 12 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Modify u2EstimatedExtraIELen for probe request ++ * ++ * Dec 9 2009 mtk01104 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add HT cap IE to probe request ++ * ++ * Dec 7 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix lint warning ++ * ++ * ++ * Dec 3 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update the process of SCAN Result by adding more Phy Attributes ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function and code for meet the new define ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Rename u4RSSI to i4RSSI ++ * ++ * Nov 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Report event of scan result to host ++ * ++ * Nov 26 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix SCAN Record update ++ * ++ * Nov 24 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Revise MGMT Handler with Retain Status and Integrate with TXM ++ * ++ * Nov 23 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add (Ext)Support Rate Set IE to ProbeReq ++ * ++ * Nov 20 2009 mtk02468 ++ * [BORA00000337] To check in codes for FPGA emulation ++ * Removed the use of SW_RFB->u2FrameLength ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix uninitial aucMacAddress[] for ProbeReq ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add scanSearchBssDescByPolicy() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Add Send Probe Request Frame ++ * ++ * Oct 30 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define REPLICATED_BEACON_TIME_THRESHOLD (3000) ++#define REPLICATED_BEACON_FRESH_PERIOD (10000) ++#define REPLICATED_BEACON_STRENGTH_THRESHOLD (32) ++ ++#define ROAMING_NO_SWING_RCPI_STEP (10) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used by SCN to initialize its variables ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnInit(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_BSS_DESC_T prBSSDesc; ++ PUINT_8 pucBSSBuff; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ pucBSSBuff = &prScanInfo->aucScanBuffer[0]; ++ ++ DBGLOG(SCN, INFO, "->scnInit()\n"); ++ ++ /* 4 <1> Reset STATE and Message List */ ++ prScanInfo->eCurrentState = SCAN_STATE_IDLE; ++ ++ prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; ++ ++ LINK_INITIALIZE(&prScanInfo->rPendingMsgList); ++ ++ /* 4 <2> Reset link list of BSS_DESC_T */ ++ kalMemZero((PVOID) pucBSSBuff, SCN_MAX_BUFFER_SIZE); ++ ++ LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); ++ LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ ++ for (i = 0; i < CFG_MAX_NUM_BSS_LIST; i++) { ++ ++ prBSSDesc = (P_BSS_DESC_T) pucBSSBuff; ++ ++ LINK_INSERT_TAIL(&prScanInfo->rFreeBSSDescList, &prBSSDesc->rLinkEntry); ++ ++ pucBSSBuff += ALIGN_4(sizeof(BSS_DESC_T)); ++ } ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT(((ULONG) pucBSSBuff - (ULONG)&prScanInfo->aucScanBuffer[0]) == SCN_MAX_BUFFER_SIZE); ++ ++ /* reset freest channel information */ ++ prScanInfo->fgIsSparseChannelValid = FALSE; ++ ++ /* reset NLO state */ ++ prScanInfo->fgNloScanning = FALSE; ++ prScanInfo->fgPscnOnnning = FALSE; ++ ++ prScanInfo->prPscnParam = kalMemAlloc(sizeof(PSCN_PARAM_T), VIR_MEM_TYPE); ++ if (prScanInfo->prPscnParam) ++ kalMemZero(prScanInfo->prPscnParam, sizeof(PSCN_PARAM_T)); ++ ++} /* end of scnInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used by SCN to uninitialize its variables ++* ++* @param (none) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnUninit(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ DBGLOG(SCN, INFO, "->scnUninit()\n"); ++ ++ /* 4 <1> Reset STATE and Message List */ ++ prScanInfo->eCurrentState = SCAN_STATE_IDLE; ++ ++ prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; ++ ++ /* NOTE(Kevin): Check rPendingMsgList ? */ ++ ++ /* 4 <2> Reset link list of BSS_DESC_T */ ++ LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); ++ LINK_INITIALIZE(&prScanInfo->rBSSDescList); ++ ++ kalMemFree(prScanInfo->prPscnParam, VIR_MEM_TYPE, sizeof(PSCN_PARAM_T)); ++ ++} /* end of scnUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ return scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ if (fgCheckSsid == FALSE || prSsid == NULL) ++ return prBssDesc; ++ ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { ++ return prBssDesc; ++ } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { ++ prDstBssDesc = prBssDesc; ++ } else { ++ /* 20120206 frog: Equal BSSID but not SSID, SSID not hidden, ++ * SSID must be updated. */ ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen); ++ return prBssDesc; ++ } ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucSrcAddr Given Source Address(TA). ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]) ++{ ++ return scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucSrcAddr Given Source Address(TA). ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucSrcAddr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucSrcAddr, aucSrcAddr)) { ++ if (fgCheckSsid == FALSE || prSsid == NULL) ++ return prBssDesc; ++ ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { ++ return prBssDesc; ++ } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { ++ prDstBssDesc = prBssDesc; ++ } ++ ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByTA() */ ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to given BSSID ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; ++ OS_SYSTIME rLatestUpdateTime = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ if (!rLatestUpdateTime || CHECK_FOR_EXPIRATION(prBssDesc->rUpdateTime, rLatestUpdateTime)) { ++ prDstBssDesc = prBssDesc; ++ COPY_SYSTIME(rLatestUpdateTime, prBssDesc->rUpdateTime); ++ } ++ } ++ } ++ ++ return prDstBssDesc; ++ ++} /* end of scanSearchBssDescByBssid() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to ++* given eBSSType, BSSID and Transmitter Address ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. ++* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. ++* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]) ++{ ++ return scanSearchExistingBssDescWithSsid(prAdapter, eBSSType, aucBSSID, aucSrcAddr, FALSE, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Find the corresponding BSS Descriptor according to ++* given eBSSType, BSSID and Transmitter Address ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. ++* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. ++* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. ++* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) ++* @param[in] prSsid Specified SSID ++* ++* @return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T ++scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BSS_TYPE_T eBSSType, ++ IN UINT_8 aucBSSID[], ++ IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_BSS_DESC_T prBssDesc, prIBSSBssDesc; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ ++ ++ ASSERT(prAdapter); ++ ASSERT(aucSrcAddr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ switch (eBSSType) { ++ case BSS_TYPE_P2P_DEVICE: ++ fgCheckSsid = FALSE; ++ case BSS_TYPE_INFRASTRUCTURE: ++ case BSS_TYPE_BOW_DEVICE: ++ { ++ prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); ++ ++ /* if (eBSSType == prBssDesc->eBSSType) */ ++ ++ return prBssDesc; ++ } ++ ++ case BSS_TYPE_IBSS: ++ { ++ prIBSSBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); ++ prBssDesc = scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, fgCheckSsid, prSsid); ++ ++ /* NOTE(Kevin): ++ * Rules to maintain the SCAN Result: ++ * For AdHoc - ++ * CASE I We have TA1(BSSID1), but it change its BSSID to BSSID2 ++ * -> Update TA1 entry's BSSID. ++ * CASE II We have TA1(BSSID1), and get TA1(BSSID1) again ++ * -> Update TA1 entry's contain. ++ * CASE III We have a SCAN result TA1(BSSID1), and TA2(BSSID2). Sooner or ++ * later, TA2 merge into TA1, we get TA2(BSSID1) ++ * -> Remove TA2 first and then replace TA1 entry's TA with TA2, ++ * Still have only one entry of BSSID. ++ * CASE IV We have a SCAN result TA1(BSSID1), and another TA2 also merge into BSSID1. ++ * -> Replace TA1 entry's TA with TA2, Still have only one entry. ++ * CASE V New IBSS ++ * -> Add this one to SCAN result. ++ */ ++ if (prBssDesc) { ++ if ((!prIBSSBssDesc) || /* CASE I */ ++ (prBssDesc == prIBSSBssDesc)) { /* CASE II */ ++ ++ return prBssDesc; ++ } /* CASE III */ ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ ++ return prIBSSBssDesc; ++ } ++ ++ if (prIBSSBssDesc) { /* CASE IV */ ++ ++ return prIBSSBssDesc; ++ } ++ /* CASE V */ ++ break; /* Return NULL; */ ++ } ++ ++ default: ++ break; ++ } ++ ++ return (P_BSS_DESC_T) NULL; ++ ++} /* end of scanSearchExistingBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given Remove Policy. ++* ++* @param[in] u4RemovePolicy Remove Policy. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* DBGLOG(SCN, TRACE, ("Before Remove - Number Of SCAN Result = %ld\n", */ ++ /* prBSSDescList->u4NumElem)); */ ++ ++ if (u4RemovePolicy & SCN_RM_POLICY_TIMEOUT) { ++ P_BSS_DESC_T prBSSDescNext; ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove TIMEOUT BSS DESC(%#x): ++ * MAC: %pM, Current Time = %08lx, Update Time = %08lx\n", */ ++ /* prBssDesc, prBssDesc->aucBSSID, rCurrentTime, prBssDesc->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_OLDEST_HIDDEN) { ++ P_BSS_DESC_T prBssDescOldest = (P_BSS_DESC_T) NULL; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if (!prBssDesc->fgIsHiddenSSID) ++ continue; ++ ++ if (!prBssDescOldest) { /* 1st element */ ++ prBssDescOldest = prBssDesc; ++ continue; ++ } ++ ++ if (TIME_BEFORE(prBssDesc->rUpdateTime, prBssDescOldest->rUpdateTime)) ++ prBssDescOldest = prBssDesc; ++ } ++ ++ if (prBssDescOldest) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove OLDEST HIDDEN BSS DESC(%#x): ++ * MAC: %pM, Update Time = %08lx\n", */ ++ /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescOldest); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescOldest->rLinkEntry); ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_SMART_WEAKEST) { ++ P_BSS_DESC_T prBssDescWeakest = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBssDescWeakestSameSSID = (P_BSS_DESC_T) NULL; ++ UINT_32 u4SameSSIDCount = 0; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ if ((!prBssDesc->fgIsHiddenSSID) && ++ (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen))) { ++ ++ u4SameSSIDCount++; ++ ++ if (!prBssDescWeakestSameSSID) ++ prBssDescWeakestSameSSID = prBssDesc; ++ else if (prBssDesc->ucRCPI < prBssDescWeakestSameSSID->ucRCPI) ++ prBssDescWeakestSameSSID = prBssDesc; ++ } ++ ++ if (!prBssDescWeakest) { /* 1st element */ ++ prBssDescWeakest = prBssDesc; ++ continue; ++ } ++ ++ if (prBssDesc->ucRCPI < prBssDescWeakest->ucRCPI) ++ prBssDescWeakest = prBssDesc; ++ ++ } ++ ++ if ((u4SameSSIDCount >= SCN_BSS_DESC_SAME_SSID_THRESHOLD) && (prBssDescWeakestSameSSID)) ++ prBssDescWeakest = prBssDescWeakestSameSSID; ++ ++ if (prBssDescWeakest) { ++ ++ /* DBGLOG(SCN, TRACE, ("Remove WEAKEST BSS DESC(%#x): MAC: %pM, Update Time = %08lx\n", */ ++ /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescWeakest); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescWeakest->rLinkEntry); ++ } ++ } else if (u4RemovePolicy & SCN_RM_POLICY_ENTIRE) { ++ P_BSS_DESC_T prBSSDescNext; ++ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && ++ (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { ++ /* Don't remove the one currently we are connected. */ ++ continue; ++ } ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ ++ } ++ ++ return; ++ ++} /* end of scanRemoveBssDescsByPolicy() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given BSSID. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] aucBSSID Given BSSID. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBSSDescNext; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ /* Check if such BSS Descriptor exists in a valid list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ ++ /* BSSID is not unique, so need to traverse whols link-list */ ++ } ++ } ++ ++} /* end of scanRemoveBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Delete BSS Descriptors from current list according to given band configuration ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] eBand Given band ++* @param[in] eNetTypeIndex AIS - Remove IBSS/Infrastructure BSS ++* BOW - Remove BOW BSS ++* P2P - Remove P2P BSS ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, ++ IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prBSSDescNext; ++ BOOLEAN fgToRemove; ++ ++ ASSERT(prAdapter); ++ ASSERT(eBand <= BAND_NUM); ++ ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ if (eBand == BAND_NULL) ++ return; /* no need to do anything, keep all scan result */ ++ ++ /* Check if such BSS Descriptor exists in a valid list */ ++ LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ fgToRemove = FALSE; ++ ++ if (prBssDesc->eBand == eBand) { ++ switch (eNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS)) { ++ fgToRemove = TRUE; ++ } ++ break; ++ ++ case NETWORK_TYPE_P2P_INDEX: ++ if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) ++ fgToRemove = TRUE; ++ break; ++ ++ case NETWORK_TYPE_BOW_INDEX: ++ if (prBssDesc->eBSSType == BSS_TYPE_BOW_DEVICE) ++ fgToRemove = TRUE; ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ if (fgToRemove == TRUE) { ++ /* Remove this BSS Desc from the BSS Desc list */ ++ LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); ++ ++ /* Return this BSS Desc to the free BSS Desc list. */ ++ LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ } ++ ++} /* end of scanRemoveBssDescByBand() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Clear the CONNECTION FLAG of a specified BSS Descriptor. ++* ++* @param[in] aucBSSID Given BSSID. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ ++ ASSERT(prAdapter); ++ ASSERT(aucBSSID); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { ++ prBssDesc->fgIsConnected = FALSE; ++ prBssDesc->fgIsConnecting = FALSE; ++ ++ /* BSSID is not unique, so need to traverse whols link-list */ ++ } ++ } ++ ++ return; ++ ++} /* end of scanRemoveConnectionFlagOfBssDescByBssid() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Allocate new BSS_DESC_T ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* ++* @return Pointer to BSS Descriptor, if has free space. NULL, if has no space. ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prFreeBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; ++ ++ LINK_REMOVE_HEAD(prFreeBSSDescList, prBssDesc, P_BSS_DESC_T); ++ ++ if (prBssDesc) { ++ P_LINK_T prBSSDescList; ++ ++ kalMemZero(prBssDesc, sizeof(BSS_DESC_T)); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ LINK_INITIALIZE(&(prBssDesc->rP2pDeviceList)); ++ prBssDesc->fgIsP2PPresent = FALSE; ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ /* NOTE(Kevin): In current design, this new empty BSS_DESC_T will be ++ * inserted to BSSDescList immediately. ++ */ ++ LINK_INSERT_TAIL(prBSSDescList, &prBssDesc->rLinkEntry); ++ } ++ ++ return prBssDesc; ++ ++} /* end of scanAllocateBssDesc() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This API parses Beacon/ProbeResp frame and insert extracted BSS_DESC_T ++* with IEs into prAdapter->rWifiVar.rScanInfo.aucScanBuffer ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prSwRfb Pointer to the receiving frame buffer. ++* ++* @return Pointer to BSS Descriptor ++* NULL if the Beacon/ProbeResp frame is invalid ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_BSS_DESC_T prBssDesc = NULL; ++ UINT_16 u2CapInfo; ++ ENUM_BSS_TYPE_T eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset = 0; ++ ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++ P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; ++ P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; ++ P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_8 ucHwChannelNum = 0; ++ UINT_8 ucIeDsChannelNum = 0; ++ UINT_8 ucIeHtChannelNum = 0; ++ BOOLEAN fgIsValidSsid = FALSE, fgEscape = FALSE; ++ PARAM_SSID_T rSsid; ++ UINT_64 u8Timestamp; ++ BOOLEAN fgIsNewBssDesc = FALSE; ++ ++ UINT_32 i; ++ UINT_8 ucSSIDChar; ++ ++ UINT_8 ucOuiType; ++ UINT_16 u2SubTypeVersion; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ ++ WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2CapInfo, &u2CapInfo); ++ WLAN_GET_FIELD_64(&prWlanBeaconFrame->au4Timestamp[0], &u8Timestamp); ++ ++ /* decide BSS type */ ++ switch (u2CapInfo & CAP_INFO_BSS_TYPE) { ++ case CAP_INFO_ESS: ++ /* It can also be Group Owner of P2P Group. */ ++ eBSSType = BSS_TYPE_INFRASTRUCTURE; ++ break; ++ ++ case CAP_INFO_IBSS: ++ eBSSType = BSS_TYPE_IBSS; ++ break; ++ case 0: ++ /* The P2P Device shall set the ESS bit of the Capabilities field ++ * in the Probe Response fame to 0 and IBSS bit to 0. (3.1.2.1.1) */ ++ eBSSType = BSS_TYPE_P2P_DEVICE; ++ break; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ /* @TODO: add rule to identify BOW beacons */ ++#endif ++ ++ default: ++ DBGLOG(SCN, ERROR, "wrong bss type %d\n", (INT_32)(u2CapInfo & CAP_INFO_BSS_TYPE)); ++ return NULL; ++ } ++ ++ /* 4 <1.1> Pre-parse SSID IE */ ++ pucIE = prWlanBeaconFrame->aucInfoElem; ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); ++ ++ if (u2IELength > CFG_IE_BUFFER_SIZE) ++ u2IELength = CFG_IE_BUFFER_SIZE; ++ kalMemZero(&rSsid, sizeof(rSsid)); ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID) { ++ ucSSIDChar = '\0'; ++ ++ /* D-Link DWL-900AP+ */ ++ if (IE_LEN(pucIE) == 0) ++ fgIsValidSsid = FALSE; ++ /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ ++ /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && ++ * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ ++ else { ++ for (i = 0; i < IE_LEN(pucIE); i++) ++ ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; ++ ++ if (ucSSIDChar) ++ fgIsValidSsid = TRUE; ++ } ++ ++ /* Update SSID to BSS Descriptor only if SSID is not hidden. */ ++ if (fgIsValidSsid == TRUE) { ++ COPY_SSID(rSsid.aucSsid, ++ rSsid.u4SsidLen, SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); ++ } ++ } ++ fgEscape = TRUE; ++ break; ++ default: ++ break; ++ } ++ ++ if (fgEscape == TRUE) ++ break; ++ } ++ if (fgIsValidSsid) ++ DBGLOG(SCN, EVENT, "%s %pM channel %d\n", rSsid.aucSsid, prWlanBeaconFrame->aucBSSID, ++ HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); ++ else ++ DBGLOG(SCN, EVENT, "hidden ssid, %pM channel %d\n", prWlanBeaconFrame->aucBSSID, ++ HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); ++ /* 4 <1.2> Replace existing BSS_DESC_T or allocate a new one */ ++ prBssDesc = scanSearchExistingBssDescWithSsid(prAdapter, ++ eBSSType, ++ (PUINT_8) prWlanBeaconFrame->aucBSSID, ++ (PUINT_8) prWlanBeaconFrame->aucSrcAddr, ++ fgIsValidSsid, fgIsValidSsid == TRUE ? &rSsid : NULL); ++ ++ if (prBssDesc == (P_BSS_DESC_T) NULL) { ++ fgIsNewBssDesc = TRUE; ++ ++ do { ++ /* 4 <1.2.1> First trial of allocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.2> Hidden is useless, remove the oldest hidden ssid. (for passive scan) */ ++ scanRemoveBssDescsByPolicy(prAdapter, ++ (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_OLDEST_HIDDEN)); ++ ++ /* 4 <1.2.3> Second tail of allocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.4> Remove the weakest one */ ++ /* If there are more than half of BSS which has the same ssid as connection ++ * setting, remove the weakest one from them. ++ * Else remove the weakest one. ++ */ ++ scanRemoveBssDescsByPolicy(prAdapter, ++ (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_SMART_WEAKEST)); ++ ++ /* 4 <1.2.5> reallocation */ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (prBssDesc) ++ break; ++ /* 4 <1.2.6> no space, should not happen */ ++ DBGLOG(SCN, ERROR, "no bss desc available after remove policy\n"); ++ return NULL; ++ ++ } while (FALSE); ++ ++ } else { ++ OS_SYSTIME rCurrentTime; ++ ++ /* WCXRP00000091 */ ++ /* if the received strength is much weaker than the original one, */ ++ /* ignore it due to it might be received on the folding frequency */ ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ if (prBssDesc->eBSSType != eBSSType) { ++ prBssDesc->eBSSType = eBSSType; ++ } else if (HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr) != prBssDesc->ucChannelNum && ++ prBssDesc->ucRCPI > prSwRfb->prHifRxHdr->ucRcpi) { ++ /* for signal strength is too much weaker and previous beacon is not stale */ ++ if ((prBssDesc->ucRCPI - prSwRfb->prHifRxHdr->ucRcpi) >= REPLICATED_BEACON_STRENGTH_THRESHOLD && ++ (rCurrentTime - prBssDesc->rUpdateTime) <= REPLICATED_BEACON_FRESH_PERIOD) { ++ DBGLOG(SCN, EVENT, "rssi is too much weaker and previous one is fresh\n"); ++ return prBssDesc; ++ } ++ /* for received beacons too close in time domain */ ++ else if (rCurrentTime - prBssDesc->rUpdateTime <= REPLICATED_BEACON_TIME_THRESHOLD) { ++ DBGLOG(SCN, EVENT, "receive beacon/probe reponses too close\n"); ++ return prBssDesc; ++ } ++ } ++ ++ /* if Timestamp has been reset, re-generate BSS DESC 'cause AP should have reset itself */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && u8Timestamp < prBssDesc->u8TimeStamp.QuadPart) { ++ BOOLEAN fgIsConnected, fgIsConnecting; ++ ++ /* set flag for indicating this is a new BSS-DESC */ ++ fgIsNewBssDesc = TRUE; ++ ++ /* backup 2 flags for APs which reset timestamp unexpectedly */ ++ fgIsConnected = prBssDesc->fgIsConnected; ++ fgIsConnecting = prBssDesc->fgIsConnecting; ++ scanRemoveBssDescByBssid(prAdapter, prBssDesc->aucBSSID); ++ ++ prBssDesc = scanAllocateBssDesc(prAdapter); ++ if (!prBssDesc) ++ return NULL; ++ ++ /* restore */ ++ prBssDesc->fgIsConnected = fgIsConnected; ++ prBssDesc->fgIsConnecting = fgIsConnecting; ++ } ++ } ++#if 1 ++ ++ prBssDesc->u2RawLength = prSwRfb->u2PacketLen; ++ if (prBssDesc->u2RawLength > CFG_RAW_BUFFER_SIZE) ++ prBssDesc->u2RawLength = CFG_RAW_BUFFER_SIZE; ++ kalMemCopy(prBssDesc->aucRawBuf, prWlanBeaconFrame, prBssDesc->u2RawLength); ++#endif ++ ++ /* NOTE: Keep consistency of Scan Record during JOIN process */ ++ if ((fgIsNewBssDesc == FALSE) && prBssDesc->fgIsConnecting) { ++ DBGLOG(SCN, INFO, "we're connecting this BSS(%pM) now, don't update it\n", ++ prBssDesc->aucBSSID); ++ return prBssDesc; ++ } ++ /* 4 <2> Get information from Fixed Fields */ ++ prBssDesc->eBSSType = eBSSType; /* Update the latest BSS type information. */ ++ ++ COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prWlanBeaconFrame->aucSrcAddr); ++ ++ COPY_MAC_ADDR(prBssDesc->aucBSSID, prWlanBeaconFrame->aucBSSID); ++ ++ prBssDesc->u8TimeStamp.QuadPart = u8Timestamp; ++ ++ WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2BeaconInterval, &prBssDesc->u2BeaconInterval); ++ ++ prBssDesc->u2CapInfo = u2CapInfo; ++ ++ /* 4 <2.1> Retrieve IEs for later parsing */ ++ u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); ++ ++ if (u2IELength > CFG_IE_BUFFER_SIZE) { ++ u2IELength = CFG_IE_BUFFER_SIZE; ++ prBssDesc->fgIsIEOverflow = TRUE; ++ } else { ++ prBssDesc->fgIsIEOverflow = FALSE; ++ } ++ prBssDesc->u2IELength = u2IELength; ++ ++ kalMemCopy(prBssDesc->aucIEBuf, prWlanBeaconFrame->aucInfoElem, u2IELength); ++ ++ /* 4 <2.2> reset prBssDesc variables in case that AP has been reconfigured */ ++ prBssDesc->fgIsERPPresent = FALSE; ++ prBssDesc->fgIsHTPresent = FALSE; ++ prBssDesc->eSco = CHNL_EXT_SCN; ++ prBssDesc->fgIEWAPI = FALSE; ++#if CFG_RSN_MIGRATION ++ prBssDesc->fgIERSN = FALSE; ++#endif ++#if CFG_PRIVACY_MIGRATION ++ prBssDesc->fgIEWPA = FALSE; ++#endif ++ ++ /* 4 <3.1> Full IE parsing on SW_RFB_T */ ++ pucIE = prWlanBeaconFrame->aucInfoElem; ++ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_SSID: ++ if ((!prIeSsid) && /* NOTE(Kevin): for Atheros IOT #1 */ ++ (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { ++ BOOLEAN fgIsHiddenSSID = FALSE; ++ ++ ucSSIDChar = '\0'; ++ ++ prIeSsid = (P_IE_SSID_T) pucIE; ++ ++ /* D-Link DWL-900AP+ */ ++ if (IE_LEN(pucIE) == 0) ++ fgIsHiddenSSID = TRUE; ++ /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ ++ /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && ++ * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ ++ else { ++ for (i = 0; i < IE_LEN(pucIE); i++) ++ ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; ++ ++ if (!ucSSIDChar) ++ fgIsHiddenSSID = TRUE; ++ } ++ ++ /* Update SSID to BSS Descriptor only if SSID is not hidden. */ ++ if (!fgIsHiddenSSID) { ++ COPY_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); ++ } ++#if 0 ++ /* ++ After we connect to a hidden SSID, prBssDesc->aucSSID[] will ++ not be empty and prBssDesc->ucSSIDLen will not be 0, ++ so maybe we need to empty prBssDesc->aucSSID[] and set ++ prBssDesc->ucSSIDLen to 0 in prBssDesc to avoid that ++ UI still displays hidden SSID AP in scan list after ++ we disconnect the hidden SSID AP. ++ */ ++ else { ++ prBssDesc->aucSSID[0] = '\0'; ++ prBssDesc->ucSSIDLen = 0; ++ } ++#endif ++ ++ } ++ break; ++ ++ case ELEM_ID_SUP_RATES: ++ /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. ++ * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), ++ * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" ++ */ ++ /* TP-LINK will set extra and incorrect ie with ELEM_ID_SUP_RATES */ ++ if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) ++ prIeSupportedRate = SUP_RATES_IE(pucIE); ++ break; ++ ++ case ELEM_ID_DS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) ++ ucIeDsChannelNum = DS_PARAM_IE(pucIE)->ucCurrChnl; ++ break; ++ ++ case ELEM_ID_TIM: ++ if (IE_LEN(pucIE) <= ELEM_MAX_LEN_TIM) ++ prBssDesc->ucDTIMPeriod = TIM_IE(pucIE)->ucDTIMPeriod; ++ break; ++ ++ case ELEM_ID_IBSS_PARAM_SET: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_IBSS_PARAMETER_SET) ++ prBssDesc->u2ATIMWindow = IBSS_PARAM_IE(pucIE)->u2ATIMWindow; ++ break; ++ ++#if 0 /* CFG_SUPPORT_802_11D */ ++ case ELEM_ID_COUNTRY_INFO: ++ prBssDesc->prIECountry = (P_IE_COUNTRY_T) pucIE; ++ break; ++#endif ++ ++ case ELEM_ID_ERP_INFO: ++ if (IE_LEN(pucIE) == ELEM_MAX_LEN_ERP) ++ prBssDesc->fgIsERPPresent = TRUE; ++ break; ++ ++ case ELEM_ID_EXTENDED_SUP_RATES: ++ if (!prIeExtSupportedRate) ++ prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); ++ break; ++ ++#if CFG_RSN_MIGRATION ++ case ELEM_ID_RSN: ++ if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &prBssDesc->rRSNInfo)) { ++ prBssDesc->fgIERSN = TRUE; ++ prBssDesc->u2RsnCap = prBssDesc->rRSNInfo.u2RsnCap; ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) ++ rsnCheckPmkidCache(prAdapter, prBssDesc); ++ } ++ break; ++#endif ++ ++ case ELEM_ID_HT_CAP: ++ prBssDesc->fgIsHTPresent = TRUE; ++ break; ++ ++ case ELEM_ID_HT_OP: ++ if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) ++ break; ++ ++ if ((((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { ++ prBssDesc->eSco = (ENUM_CHNL_EXT_T) ++ (((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO); ++ } ++ ucIeHtChannelNum = ((P_IE_HT_OP_T) pucIE)->ucPrimaryChannel; ++ ++ break; ++ ++#if CFG_SUPPORT_WAPI ++ case ELEM_ID_WAPI: ++ if (wapiParseWapiIE(WAPI_IE(pucIE), &prBssDesc->rIEWAPI)) ++ prBssDesc->fgIEWAPI = TRUE; ++ break; ++#endif ++ ++ case ELEM_ID_VENDOR: /* ELEM_ID_P2P, ELEM_ID_WMM */ ++#if CFG_PRIVACY_MIGRATION ++ if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { ++ if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && (u2SubTypeVersion == VERSION_WPA)) { ++ ++ if (rsnParseWpaIE(prAdapter, WPA_IE(pucIE), &prBssDesc->rWPAInfo)) ++ prBssDesc->fgIEWPA = TRUE; ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { ++ if (ucOuiType == VENDOR_OUI_TYPE_P2P) ++ prBssDesc->fgIsP2PPresent = TRUE; ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ break; ++ ++ /* no default */ ++ } ++ } ++ ++ /* 4 <3.2> Save information from IEs - SSID */ ++ /* Update Flag of Hidden SSID for used in SEARCH STATE. */ ++ ++ /* NOTE(Kevin): in current driver, the ucSSIDLen == 0 represent ++ * all cases of hidden SSID. ++ * If the fgIsHiddenSSID == TRUE, it means we didn't get the ProbeResp with ++ * valid SSID. ++ */ ++ if (prBssDesc->ucSSIDLen == 0) ++ prBssDesc->fgIsHiddenSSID = TRUE; ++ else ++ prBssDesc->fgIsHiddenSSID = FALSE; ++ ++ /* 4 <3.3> Check rate information in related IEs. */ ++ if (prIeSupportedRate || prIeExtSupportedRate) { ++ rateGetRateSetFromIEs(prIeSupportedRate, ++ prIeExtSupportedRate, ++ &prBssDesc->u2OperationalRateSet, ++ &prBssDesc->u2BSSBasicRateSet, &prBssDesc->fgIsUnknownBssBasicRate); ++ } ++ /* 4 <4> Update information from HIF RX Header */ ++ { ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ ASSERT(prHifRxHdr); ++ ++ /* 4 <4.1> Get TSF comparison result */ ++ prBssDesc->fgIsLargerTSF = HIF_RX_HDR_GET_TCL_FLAG(prHifRxHdr); ++ ++ /* 4 <4.2> Get Band information */ ++ prBssDesc->eBand = HIF_RX_HDR_GET_RF_BAND(prHifRxHdr); ++ ++ /* 4 <4.2> Get channel and RCPI information */ ++ ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prHifRxHdr); ++ ++ if (BAND_2G4 == prBssDesc->eBand) { ++ ++ /* Update RCPI if in right channel */ ++ if (ucIeDsChannelNum >= 1 && ucIeDsChannelNum <= 14) { ++ ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeDsChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeDsChannelNum; ++ } else if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum <= 14) { ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeHtChannelNum; ++ } else { ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ ++ prBssDesc->ucChannelNum = ucHwChannelNum; ++ } ++ } ++ /* 5G Band */ ++ else { ++ if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum < 200) { ++ /* Receive Beacon/ProbeResp frame from adjacent channel. */ ++ if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ /* trust channel information brought by IE */ ++ prBssDesc->ucChannelNum = ucIeHtChannelNum; ++ } else { ++ /* Always update RCPI */ ++ prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; ++ ++ prBssDesc->ucChannelNum = ucHwChannelNum; ++ } ++ } ++ } ++ ++ /* 4 <5> PHY type setting */ ++ prBssDesc->ucPhyTypeSet = 0; ++ ++ if (BAND_2G4 == prBssDesc->eBand) { ++ /* check if support 11n */ ++ if (prBssDesc->fgIsHTPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ ++ /* if not 11n only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ /* check if support 11g */ ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || prBssDesc->fgIsERPPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; ++ ++ /* if not 11g only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)) { ++ /* check if support 11b */ ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; ++ } ++ } ++ } else { /* (BAND_5G == prBssDesc->eBande) */ ++ /* check if support 11n */ ++ if (prBssDesc->fgIsHTPresent) ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; ++ ++ /* if not 11n only */ ++ if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { ++ /* Support 11a definitely */ ++ prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; ++ ++ ASSERT(!(prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)); ++ } ++ } ++ ++ /* 4 <6> Update BSS_DESC_T's Last Update TimeStamp. */ ++ GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); ++ ++ return prBssDesc; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to scan result for query ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. ++* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame; ++ PARAM_MAC_ADDRESS rMacAddr; ++ PARAM_SSID_T rSsid; ++ ENUM_PARAM_NETWORK_TYPE_T eNetworkType; ++ PARAM_802_11_CONFIG_T rConfiguration; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ UINT_8 ucRateLen = 0; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prBssDesc->eBand == BAND_2G4) { ++ if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) ++ || prBssDesc->fgIsERPPresent) { ++ eNetworkType = PARAM_NETWORK_TYPE_OFDM24; ++ } else { ++ eNetworkType = PARAM_NETWORK_TYPE_DS; ++ } ++ } else { ++ ASSERT(prBssDesc->eBand == BAND_5G); ++ eNetworkType = PARAM_NETWORK_TYPE_OFDM5; ++ } ++ ++ if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { ++ /* NOTE(Kevin): Not supported by WZC(TBD) */ ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ COPY_MAC_ADDR(rMacAddr, prWlanBeaconFrame->aucBSSID); ++ COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); ++ ++ rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ rConfiguration.u4BeaconPeriod = (UINT_32) prWlanBeaconFrame->u2BeaconInterval; ++ rConfiguration.u4ATIMWindow = prBssDesc->u2ATIMWindow; ++ rConfiguration.u4DSConfig = nicChannelNum2Freq(prBssDesc->ucChannelNum); ++ rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ rateGetDataRatesFromRateSet(prBssDesc->u2OperationalRateSet, 0, aucRatesEx, &ucRateLen); ++ ++ /* NOTE(Kevin): Set unused entries, if any, at the end of the array to 0. ++ * from OID_802_11_BSSID_LIST ++ */ ++ for (i = ucRateLen; i < sizeof(aucRatesEx) / sizeof(aucRatesEx[0]); i++) ++ aucRatesEx[i] = 0; ++ ++ switch (prBssDesc->eBSSType) { ++ case BSS_TYPE_IBSS: ++ eOpMode = NET_TYPE_IBSS; ++ break; ++ ++ case BSS_TYPE_INFRASTRUCTURE: ++ case BSS_TYPE_P2P_DEVICE: ++ case BSS_TYPE_BOW_DEVICE: ++ default: ++ eOpMode = NET_TYPE_INFRA; ++ break; ++ } ++ ++ DBGLOG(SCN, TRACE, "ind %s %d\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ { ++ if (flgTdlsTestExtCapElm == TRUE) { ++ /* only for RALINK AP */ ++ UINT8 *pucElm = (UINT8 *) (prSwRfb->pvHeader + prSwRfb->u2PacketLen); ++ ++ kalMemCopy(pucElm - 9, aucTdlsTestExtCapElm, 7); ++ prSwRfb->u2PacketLen -= 2; ++/* prSwRfb->u2PacketLen += 7; */ ++ ++ DBGLOG(TDLS, INFO, ++ " %s: append ext cap element to %pM\n", ++ __func__, prBssDesc->aucBSSID); ++ } ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ if (prAdapter->rWifiVar.rScanInfo.fgNloScanning && ++ test_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag)) { ++ UINT_8 i = 0; ++ P_BSS_DESC_T *pprPendBssDesc = &prScanInfo->rNloParam.aprPendingBssDescToInd[0]; ++ ++ for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { ++ if (pprPendBssDesc[i]) ++ continue; ++ DBGLOG(SCN, INFO, ++ "indicate bss[%pM] before wiphy resume, need to indicate again after wiphy resume\n", ++ prBssDesc->aucBSSID); ++ pprPendBssDesc[i] = prBssDesc; ++ break; ++ } ++ } ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prSwRfb->pvHeader, ++ prSwRfb->u2PacketLen, prBssDesc->ucChannelNum, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ nicAddScanResult(prAdapter, ++ rMacAddr, ++ &rSsid, ++ prWlanBeaconFrame->u2CapInfo & CAP_INFO_PRIVACY ? 1 : 0, ++ RCPI_TO_dBm(prBssDesc->ucRCPI), ++ eNetworkType, ++ &rConfiguration, ++ eOpMode, ++ aucRatesEx, ++ prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen, ++ (PUINT_8) ((ULONG) (prSwRfb->pvHeader) + WLAN_MAC_MGMT_HEADER_LEN)); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of scanAddScanResult() */ ++ ++#if 1 ++ ++BOOLEAN scanCheckBssIsLegal(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) ++{ ++ BOOLEAN fgAddToScanResult = FALSE; ++ ENUM_BAND_T eBand = 0; ++ UINT_8 ucChannel = 0; ++ ++ ASSERT(prAdapter); ++ /* check the channel is in the legal doamin */ ++ if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == TRUE) { ++ /* check ucChannelNum/eBand for adjacement channel filtering */ ++ if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE && ++ (eBand != prBssDesc->eBand || ucChannel != prBssDesc->ucChannelNum)) { ++ fgAddToScanResult = FALSE; ++ } else { ++ fgAddToScanResult = TRUE; ++ } ++ } ++ return fgAddToScanResult; ++ ++} ++ ++VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc) ++{ ++ P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; ++ P_LINK_T prBSSDescList = (P_LINK_T) NULL; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ DBGLOG(SCN, TRACE, "scanReportBss2Cfg80211\n"); ++ ++ if (SpecificprBssDesc) { ++ { ++ /* check BSSID is legal channel */ ++ if (!scanCheckBssIsLegal(prAdapter, SpecificprBssDesc)) { ++ DBGLOG(SCN, TRACE, "Remove specific SSID[%s %d]\n", ++ SpecificprBssDesc->aucSSID, SpecificprBssDesc->ucChannelNum); ++ return; ++ } ++ ++ DBGLOG(SCN, TRACE, "Report Specific SSID[%s]\n", SpecificprBssDesc->aucSSID); ++ if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) SpecificprBssDesc->aucRawBuf, ++ SpecificprBssDesc->u2RawLength, ++ SpecificprBssDesc->ucChannelNum, ++ RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); ++ } else { ++ ++ rChannelInfo.ucChannelNum = SpecificprBssDesc->ucChannelNum; ++ rChannelInfo.eBand = SpecificprBssDesc->eBand; ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) SpecificprBssDesc->aucRawBuf, ++ SpecificprBssDesc->u2RawLength, ++ &rChannelInfo, RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); ++ ++ } ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ SpecificprBssDesc->fgIsP2PReport = FALSE; ++#endif ++ } ++ } else { ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ /* 4 Auto Channel Selection:Record the AP Number */ ++ P_PARAM_CHN_LOAD_INFO prChnLoad; ++ UINT_8 ucIdx = 0; ++ ++ if (((prBssDesc->ucChannelNum > 0) && (prBssDesc->ucChannelNum <= 48)) ++ || (prBssDesc->ucChannelNum >= 147) /*non-DFS Channel */) { ++ if (prBssDesc->ucChannelNum <= HW_CHNL_NUM_MAX_2G4) { ++ ucIdx = prBssDesc->ucChannelNum - 1; ++ } else if (prBssDesc->ucChannelNum <= 48) { ++ ucIdx = (UINT_8) (HW_CHNL_NUM_MAX_2G4 + (prBssDesc->ucChannelNum - 34) / 4); ++ } else { ++ ucIdx = ++ (UINT_8) (HW_CHNL_NUM_MAX_2G4 + 4 + (prBssDesc->ucChannelNum - 149) / 4); ++ } ++ ++ if (ucIdx < MAX_AUTO_CHAL_NUM) { ++ prChnLoad = (P_PARAM_CHN_LOAD_INFO) & ++ (prAdapter->rWifiVar.rChnLoadInfo.rEachChnLoad[ucIdx]); ++ prChnLoad->ucChannel = prBssDesc->ucChannelNum; ++ prChnLoad->u2APNum++; ++ } else { ++ DBGLOG(SCN, WARN, "ACS: ChIdx > MAX_AUTO_CHAL_NUM\n"); ++ } ++ ++ } ++#endif ++ /* check BSSID is legal channel */ ++ if (!scanCheckBssIsLegal(prAdapter, prBssDesc)) { ++ DBGLOG(SCN, TRACE, "Remove SSID[%s %d]\n", ++ prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ continue; ++ } ++ ++ if ((prBssDesc->eBSSType == eBSSType) ++#if CFG_ENABLE_WIFI_DIRECT ++ || ((eBSSType == BSS_TYPE_P2P_DEVICE) && (prBssDesc->fgIsP2PReport == TRUE)) ++#endif ++ ) { ++ ++ DBGLOG(SCN, TRACE, "Report ALL SSID[%s %d]\n", ++ prBssDesc->aucSSID, prBssDesc->ucChannelNum); ++ ++ if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++ if (prBssDesc->u2RawLength != 0) { ++ kalIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBssDesc->aucRawBuf, ++ prBssDesc->u2RawLength, ++ prBssDesc->ucChannelNum, ++ RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); ++ prBssDesc->u2RawLength = 0; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssDesc->fgIsP2PReport = FALSE; ++#endif ++ } ++ } else { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssDesc->fgIsP2PReport == TRUE) { ++#endif ++ rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; ++ rChannelInfo.eBand = prBssDesc->eBand; ++ ++ kalP2PIndicateBssInfo(prAdapter->prGlueInfo, ++ (PUINT_8) prBssDesc->aucRawBuf, ++ prBssDesc->u2RawLength, ++ &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); ++ ++ /* do not clear it then we can pass the bss in Specific report */ ++ /* kalMemZero(prBssDesc->aucRawBuf,CFG_RAW_BUFFER_SIZE); */ ++ ++ /* ++ the BSS entry will not be cleared after scan done. ++ So if we dont receive the BSS in next scan, we cannot ++ pass it. We use u2RawLength for the purpose. ++ */ ++ /* prBssDesc->u2RawLength=0; */ ++#if CFG_ENABLE_WIFI_DIRECT ++ prBssDesc->fgIsP2PReport = FALSE; ++ } ++#endif ++ } ++ } ++ ++ } ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = TRUE; ++#endif ++ ++ } ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse the content of given Beacon or ProbeResp Frame. ++* ++* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. ++* ++* @retval WLAN_STATUS_SUCCESS if not report this SW_RFB_T to host ++* @retval WLAN_STATUS_PENDING if report this SW_RFB_T to host as scan result ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_BSS_INFO_T prAisBssInfo; ++ P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; ++#if CFG_SLT_SUPPORT ++ P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ /* 4 <0> Ignore invalid Beacon Frame */ ++ if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < ++ (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)) { ++ /* to debug beacon length too small issue */ ++ UINT_32 u4MailBox0; ++ ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ DBGLOG(SCN, WARN, "if conn sys also get less length (0x5a means yes) %x\n", (UINT_32) u4MailBox0); ++ DBGLOG(SCN, WARN, "u2PacketLen %d, u2HeaderLen %d, payloadLen %d\n", ++ prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen, ++ prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); ++ /* dumpMemory8(prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ ++#ifndef _lint ++ ASSERT(0); ++#endif /* _lint */ ++ return rStatus; ++ } ++#if CFG_SLT_SUPPORT ++ prSltInfo = &prAdapter->rWifiVar.rSltInfo; ++ ++ if (prSltInfo->fgIsDUT) { ++ DBGLOG(SCN, INFO, "\n\rBCN: RX\n"); ++ prSltInfo->u4BeaconReceiveCnt++; ++ return WLAN_STATUS_SUCCESS; ++ } else { ++ return WLAN_STATUS_SUCCESS; ++ } ++#endif ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; ++ ++ /*ALPS01475157: don't show SSID on scan list for multicast MAC AP */ ++ if (IS_BMCAST_MAC_ADDR(prWlanBeaconFrame->aucSrcAddr)) { ++ DBGLOG(SCN, WARN, "received beacon/probe response from multicast AP\n"); ++ return rStatus; ++ } ++ ++ /* 4 <1> Parse and add into BSS_DESC_T */ ++ prBssDesc = scanAddToBssDesc(prAdapter, prSwRfb); ++ ++ if (prBssDesc) { ++ /* 4 <1.1> Beacon Change Detection for Connected BSS */ ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED && ++ ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA)) && ++ EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && ++ EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, prAisBssInfo->aucSSID, ++ prAisBssInfo->ucSSIDLen)) { ++ BOOLEAN fgNeedDisconnect = FALSE; ++ ++#if CFG_SUPPORT_BEACON_CHANGE_DETECTION ++ /* <1.1.2> check if supported rate differs */ ++ if (prAisBssInfo->u2OperationalRateSet != prBssDesc->u2OperationalRateSet) ++ fgNeedDisconnect = TRUE; ++#endif ++#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE ++ if ( ++#if CFG_SUPPORT_WAPI ++ (prAdapter->rWifiVar.rConnSettings.fgWapiMode == TRUE && ++ !wapiPerformPolicySelection(prAdapter, prBssDesc)) || ++#endif ++ rsnCheckSecurityModeChanged(prAdapter, prAisBssInfo, prBssDesc)) { ++ DBGLOG(SCN, INFO, "Beacon security mode change detected\n"); ++ fgNeedDisconnect = FALSE; ++ aisBssSecurityChanged(prAdapter); ++ } ++#endif ++ ++ /* <1.1.3> beacon content change detected, disconnect immediately */ ++ if (fgNeedDisconnect == TRUE) ++ aisBssBeaconTimeout(prAdapter); ++ } ++ /* 4 <1.1> Update AIS_BSS_INFO */ ++ if (((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) ++ || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA))) { ++ if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* *not* checking prBssDesc->fgIsConnected anymore, ++ * due to Linksys AP uses " " as hidden SSID, and would have different BSS descriptor */ ++ if ((!prAisBssInfo->ucDTIMPeriod) && ++ EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && ++ (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && ++ ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { ++ ++ prAisBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; ++ ++ /* sync with firmware for beacon information */ ++ nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); ++ } ++ } ++#if CFG_SUPPORT_ADHOC ++ if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, ++ prConnSettings->ucSSIDLen) && ++ (prBssDesc->eBSSType == BSS_TYPE_IBSS) && (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { ++ ibssProcessMatchedBeacon(prAdapter, prAisBssInfo, prBssDesc, ++ prSwRfb->prHifRxHdr->ucRcpi); ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ } ++ ++ rlmProcessBcn(prAdapter, ++ prSwRfb, ++ ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem, ++ (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - ++ (UINT_16) (OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); ++ ++ /* 4 <3> Send SW_RFB_T to HIF when we perform SCAN for HOST */ ++ if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE || prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ /* for AIS, send to host */ ++ if (prConnSettings->fgIsScanReqIssued || prAdapter->rWifiVar.rScanInfo.fgNloScanning) { ++ BOOLEAN fgAddToScanResult; ++ ++ fgAddToScanResult = scanCheckBssIsLegal(prAdapter, prBssDesc); ++ ++ if (fgAddToScanResult == TRUE) ++ rStatus = scanAddScanResult(prAdapter, prBssDesc, prSwRfb); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ scanP2pProcessBeaconAndProbeResp(prAdapter, prSwRfb, &rStatus, prBssDesc, prWlanBeaconFrame); ++#endif ++ } ++ ++ return rStatus; ++ ++} /* end of scanProcessBeaconAndProbeResp() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Search the Candidate of BSS Descriptor for JOIN(Infrastructure) or ++* MERGE(AdHoc) according to current Connection Policy. ++* ++* \return Pointer to BSS Descriptor, if found. NULL, if not found ++*/ ++/*----------------------------------------------------------------------------*/ ++P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ P_BSS_INFO_T prBssInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ P_SCAN_INFO_T prScanInfo; ++ ++ P_LINK_T prBSSDescList; ++ ++ P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prPrimaryBssDesc = (P_BSS_DESC_T) NULL; ++ P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL; ++ ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ P_STA_RECORD_T prPrimaryStaRec; ++ P_STA_RECORD_T prCandidateStaRec = (P_STA_RECORD_T) NULL; ++ ++ OS_SYSTIME rCurrentTime; ++ ++ /* The first one reach the check point will be our candidate */ ++ BOOLEAN fgIsFindFirst = (BOOLEAN) FALSE; ++ ++ BOOLEAN fgIsFindBestRSSI = (BOOLEAN) FALSE; ++ BOOLEAN fgIsFindBestEncryptionLevel = (BOOLEAN) FALSE; ++ /* BOOLEAN fgIsFindMinChannelLoad = (BOOLEAN)FALSE; */ ++ ++ /* TODO(Kevin): Support Min Channel Load */ ++ /* UINT_8 aucChannelLoad[CHANNEL_NUM] = {0}; */ ++ ++ BOOLEAN fgIsFixedChannel; ++ ENUM_BAND_T eBand = 0; ++ UINT_8 ucChannel = 0; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); ++ ++ prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ ++ /* check for fixed channel operation */ ++ if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++#if CFG_P2P_LEGACY_COEX_REVISE ++ fgIsFixedChannel = cnmAisDetectP2PChannel(prAdapter, &eBand, &ucChannel); ++#else ++ fgIsFixedChannel = cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel); ++#endif ++ } else { ++ fgIsFixedChannel = FALSE; ++ } ++ ++#if DBG ++ if (prConnSettings->ucSSIDLen < ELEM_MAX_LEN_SSID) ++ prConnSettings->aucSSID[prConnSettings->ucSSIDLen] = '\0'; ++#endif ++ ++ DBGLOG(SCN, INFO, "SEARCH: Bss Num: %d, Look for SSID: %s, %pM Band=%d, channel=%d\n", ++ (UINT_32) prBSSDescList->u4NumElem, prConnSettings->aucSSID, ++ (prConnSettings->aucBSSID), eBand, ucChannel); ++ ++ /* 4 <1> The outer loop to search for a candidate. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ ++ /* TODO(Kevin): Update Minimum Channel Load Information here */ ++ ++ DBGLOG(SCN, TRACE, "SEARCH: [ %pM ], SSID:%s\n", ++ prBssDesc->aucBSSID, prBssDesc->aucSSID); ++ ++ /* 4 <2> Check PHY Type and attributes */ ++ /* 4 <2.1> Check Unsupported BSS PHY Type */ ++ if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { ++ DBGLOG(SCN, TRACE, "SEARCH: Ignore unsupported ucPhyTypeSet = %x\n", prBssDesc->ucPhyTypeSet); ++ continue; ++ } ++ /* 4 <2.2> Check if has unknown NonHT BSS Basic Rate Set. */ ++ if (prBssDesc->fgIsUnknownBssBasicRate) ++ continue; ++ /* 4 <2.3> Check if fixed operation cases should be aware */ ++ if (fgIsFixedChannel == TRUE && (prBssDesc->eBand != eBand || prBssDesc->ucChannelNum != ucChannel)) ++ continue; ++ /* 4 <2.4> Check if the channel is legal under regulatory domain */ ++ if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == FALSE) ++ continue; ++ /* 4 <2.5> Check if this BSS_DESC_T is stale */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { ++ ++ BOOLEAN fgIsNeedToCheckTimeout = TRUE; ++ ++#if CFG_SUPPORT_ROAMING ++ P_ROAMING_INFO_T prRoamingFsmInfo; ++ ++ prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); ++ if ((prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) || ++ (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) { ++ if (++prRoamingFsmInfo->RoamingEntryTimeoutSkipCount < ++ ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX) { ++ fgIsNeedToCheckTimeout = FALSE; ++ DBGLOG(SCN, INFO, "SEARCH: Romaing skip SCN_BSS_DESC_REMOVE_TIMEOUT_SEC\n"); ++ } ++ } ++#endif ++ ++ if (fgIsNeedToCheckTimeout == TRUE) { ++ DBGLOG(SCN, TRACE, "Ignore stale bss %pM\n", prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ /* 4 <3> Check if reach the excessive join retry limit */ ++ /* NOTE(Kevin): STA_RECORD_T is recorded by TA. */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); ++ ++ if (prStaRec) { ++ /* NOTE(Kevin): ++ * The Status Code is the result of a Previous Connection Request, ++ * we use this as SCORE for choosing a proper ++ * candidate (Also used for compare see <6>) ++ * The Reason Code is an indication of the reason why AP reject us, ++ * we use this Code for "Reject" ++ * a SCAN result to become our candidate(Like a blacklist). ++ */ ++#if 0 /* TODO(Kevin): */ ++ if (prStaRec->u2ReasonCode != REASON_CODE_RESERVED) { ++ DBGLOG(SCN, INFO, "SEARCH: Ignore BSS with previous Reason Code = %d\n", ++ prStaRec->u2ReasonCode); ++ continue; ++ } else ++#endif ++ if (prStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ /* NOTE(Kevin): greedy association - after timeout, we'll still ++ * try to associate to the AP whose STATUS of conection attempt ++ * was not success. ++ * We may also use (ucJoinFailureCount x JOIN_RETRY_INTERVAL_SEC) for ++ * time bound. ++ */ ++ if ((prStaRec->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) || ++ (CHECK_FOR_TIMEOUT(rCurrentTime, ++ prStaRec->rLastJoinTime, ++ SEC_TO_SYSTIME(JOIN_RETRY_INTERVAL_SEC)))) { ++ ++ /* NOTE(Kevin): Every JOIN_RETRY_INTERVAL_SEC interval, we can retry ++ * JOIN_MAX_RETRY_FAILURE_COUNT times. ++ */ ++ if (prStaRec->ucJoinFailureCount >= JOIN_MAX_RETRY_FAILURE_COUNT) ++ prStaRec->ucJoinFailureCount = 0; ++ DBGLOG(SCN, INFO, ++ "SEARCH: Try to join BSS again,Status Code=%d (Curr=%u/Last Join=%u)\n", ++ prStaRec->u2StatusCode, rCurrentTime, prStaRec->rLastJoinTime); ++ } else { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Ignore BSS which reach maximum Join Retry Count = %d\n", ++ JOIN_MAX_RETRY_FAILURE_COUNT); ++ continue; ++ } ++ ++ } ++ } ++ /* 4 <4> Check for various NETWORK conditions */ ++ if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ ++ /* 4 <4.1> Check BSS Type for the corresponding Operation Mode in Connection Setting */ ++ /* NOTE(Kevin): For NET_TYPE_AUTO_SWITCH, we will always pass following check. */ ++ if (((prConnSettings->eOPMode == NET_TYPE_INFRA) && ++ (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE)) ++#if CFG_SUPPORT_ADHOC ++ || ((prConnSettings->eOPMode == NET_TYPE_IBSS ++ || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) ++ && (prBssDesc->eBSSType != BSS_TYPE_IBSS)) ++#endif ++ ) { ++ ++ DBGLOG(SCN, TRACE, "Cur OPMode %d, Ignore eBSSType = %d\n", ++ prConnSettings->eOPMode, prBssDesc->eBSSType); ++ continue; ++ } ++ /* 4 <4.2> Check AP's BSSID if OID_802_11_BSSID has been set. */ ++ if ((prConnSettings->fgIsConnByBssidIssued) && ++ (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE)) { ++ ++ if (UNEQUAL_MAC_ADDR(prConnSettings->aucBSSID, prBssDesc->aucBSSID)) { ++ ++ DBGLOG(SCN, TRACE, "SEARCH: Ignore due to BSSID was not matched!\n"); ++ continue; ++ } ++ } ++#if CFG_SUPPORT_ADHOC ++ /* 4 <4.3> Check for AdHoc Mode */ ++ if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ OS_SYSTIME rCurrentTime; ++ ++ /* 4 <4.3.1> Check if this SCAN record has been updated recently for IBSS. */ ++ /* NOTE(Kevin): Because some STA may change its BSSID frequently after it ++ * create the IBSS - e.g. IPN2220, so we need to make sure we get the new one. ++ * For BSS, if the old record was matched, however it won't be able to pass ++ * the Join Process later. ++ */ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(SCN_ADHOC_BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCN, LOUD, ++ "SEARCH: Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ /* 4 <4.3.2> Check Peer's capability */ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { ++ ++ if (prPrimaryBssDesc) ++ DBGLOG(SCN, INFO, ++ "SEARCH: BSS DESC MAC: %pM, not supported AdHoc Mode.\n", ++ prPrimaryBssDesc->aucBSSID); ++ ++ continue; ++ } ++ /* 4 <4.3.3> Compare TSF */ ++ if (prBssInfo->fgIsBeaconActivated && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID)) { ++ ++ DBGLOG(SCN, LOUD, ++ "SEARCH: prBssDesc->fgIsLargerTSF = %d\n", prBssDesc->fgIsLargerTSF); ++ ++ if (!prBssDesc->fgIsLargerTSF) { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Ignore BSS DESC MAC: [ %pM ], Smaller TSF\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ } ++#endif /* CFG_SUPPORT_ADHOC */ ++ ++ } ++#if 0 /* TODO(Kevin): For IBSS */ ++ /* 4 <2.c> Check if this SCAN record has been updated recently for IBSS. */ ++ /* NOTE(Kevin): Because some STA may change its BSSID frequently after it ++ * create the IBSS, so we need to make sure we get the new one. ++ * For BSS, if the old record was matched, however it won't be able to pass ++ * the Join Process later. ++ */ ++ if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ prBssDesc->aucBSSID); ++ continue; ++ } ++ } ++ ++ if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) && ++ (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED)) { ++ OS_SYSTIME rCurrentTime; ++ ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, ++ SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { ++ DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", ++ (prBssDesc->aucBSSID)); ++ continue; ++ } ++ } ++ /* 4 <4B> Check for IBSS AdHoc Mode. */ ++ /* Skip if one or more BSS Basic Rate are not supported by current AdHocMode */ ++ if (prPrimaryBssDesc->eBSSType == BSS_TYPE_IBSS) { ++ /* 4 <4B.1> Check if match the Capability of current IBSS AdHoc Mode. */ ++ if (ibssCheckCapabilityForAdHocMode(prAdapter, prPrimaryBssDesc) == WLAN_STATUS_FAILURE) { ++ ++ DBGLOG(SCAN, TRACE, ++ "Ignore BSS DESC MAC: %pM, Capability not supported for AdHoc Mode.\n", ++ prPrimaryBssDesc->aucBSSID); ++ ++ continue; ++ } ++ /* 4 <4B.2> IBSS Merge Decision Flow for SEARCH STATE. */ ++ if (prAdapter->fgIsIBSSActive && ++ UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prPrimaryBssDesc->aucBSSID)) { ++ ++ if (!fgIsLocalTSFRead) { ++ NIC_GET_CURRENT_TSF(prAdapter, &rCurrentTsf); ++ ++ DBGLOG(SCAN, TRACE, ++ "\n\nCurrent TSF : %08lx-%08lx\n\n", ++ rCurrentTsf.u.HighPart, rCurrentTsf.u.LowPart); ++ } ++ ++ if (rCurrentTsf.QuadPart > prPrimaryBssDesc->u8TimeStamp.QuadPart) { ++ DBGLOG(SCAN, TRACE, ++ "Ignore BSS DESC MAC: [%pM], Current BSSID: [%pM].\n", ++ prPrimaryBssDesc->aucBSSID, prBssInfo->aucBSSID); ++ ++ DBGLOG(SCAN, TRACE, ++ "\n\nBSS's TSF : %08lx-%08lx\n\n", ++ prPrimaryBssDesc->u8TimeStamp.u.HighPart, ++ prPrimaryBssDesc->u8TimeStamp.u.LowPart); ++ ++ prPrimaryBssDesc->fgIsLargerTSF = FALSE; ++ continue; ++ } else { ++ prPrimaryBssDesc->fgIsLargerTSF = TRUE; ++ } ++ ++ } ++ } ++ /* 4 <5> Check the Encryption Status. */ ++ if (rsnPerformPolicySelection(prPrimaryBssDesc)) { ++ ++ if (prPrimaryBssDesc->ucEncLevel > 0) { ++ fgIsFindBestEncryptionLevel = TRUE; ++ ++ fgIsFindFirst = FALSE; ++ } ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ continue; ++ } ++ ++ /* For RSN Pre-authentication, update the PMKID canidate list for ++ same SSID and encrypt status */ ++ /* Update PMKID candicate list. */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnUpdatePmkidCandidateList(prPrimaryBssDesc); ++ if (prAdapter->rWifiVar.rAisBssInfo.u4PmkidCandicateCount) ++ prAdapter->rWifiVar.rAisBssInfo.fgIndicatePMKID = rsnCheckPmkidCandicate(); ++ } ++#endif ++ ++ prPrimaryBssDesc = (P_BSS_DESC_T) NULL; ++ ++ /* 4 <6> Check current Connection Policy. */ ++ switch (prConnSettings->eConnectionPolicy) { ++ case CONNECT_BY_SSID_BEST_RSSI: ++ /* Choose Hidden SSID to join only if the `fgIsEnableJoin...` is TRUE */ ++ if (prAdapter->rWifiVar.fgEnableJoinToHiddenSSID && prBssDesc->fgIsHiddenSSID) { ++ /* NOTE(Kevin): following if () statement means that ++ * If Target is hidden, then we won't connect when user specify SSID_ANY policy. ++ */ ++ if (prConnSettings->ucSSIDLen) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindBestRSSI = TRUE; ++ } ++ ++ } else if (EQUAL_SSID(prBssDesc->aucSSID, ++ prBssDesc->ucSSIDLen, ++ prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindBestRSSI = TRUE; ++ ++ DBGLOG(SCN, TRACE, "SEARCH: fgIsFindBestRSSI=TRUE, %d, prPrimaryBssDesc=[ %pM ]\n", ++ prBssDesc->ucRCPI, prPrimaryBssDesc->aucBSSID); ++ } ++ break; ++ ++ case CONNECT_BY_SSID_ANY: ++ /* NOTE(Kevin): In this policy, we don't know the desired ++ * SSID from user, so we should exclude the Hidden SSID from scan list. ++ * And because we refuse to connect to Hidden SSID node at the beginning, so ++ * when the JOIN Module deal with a BSS_DESC_T which has fgIsHiddenSSID == TRUE, ++ * then the Connection Settings must be valid without doubt. ++ */ ++ if (!prBssDesc->fgIsHiddenSSID) { ++ prPrimaryBssDesc = prBssDesc; ++ fgIsFindFirst = TRUE; ++ } ++ break; ++ ++ case CONNECT_BY_BSSID: ++ if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnSettings->aucBSSID)) ++ prPrimaryBssDesc = prBssDesc; ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Primary Candidate was not found */ ++ if (prPrimaryBssDesc == NULL) ++ continue; ++ /* 4 <7> Check the Encryption Status. */ ++ if (prPrimaryBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { ++#if CFG_SUPPORT_WAPI ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { ++ DBGLOG(SCN, TRACE, "SEARCH: fgWapiMode == 1\n"); ++ ++ if (wapiPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { ++ fgIsFindFirst = TRUE; ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ DBGLOG(SCN, TRACE, "SEARCH: WAPI cannot pass the Encryption Status Check!\n"); ++ continue; ++ } ++ } else ++#endif ++#if CFG_RSN_MIGRATION ++ if (rsnPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { ++ if (prAisSpecBssInfo->fgCounterMeasure) { ++ DBGLOG(RSN, INFO, "Skip while at counter measure period!!!\n"); ++ continue; ++ } ++ ++ if (prPrimaryBssDesc->ucEncLevel > 0) { ++ fgIsFindBestEncryptionLevel = TRUE; ++ fgIsFindFirst = FALSE; ++ } ++#if 0 ++ /* Update PMKID candicate list. */ ++ if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { ++ rsnUpdatePmkidCandidateList(prPrimaryBssDesc); ++ if (prAisSpecBssInfo->u4PmkidCandicateCount) { ++ if (rsnCheckPmkidCandicate()) { ++ DBGLOG(RSN, WARN, ++ "Prepare a timer to indicate candidate %pM\n", ++ (prAisSpecBssInfo->arPmkidCache ++ [prAisSpecBssInfo->u4PmkidCacheCount]. ++ rBssidInfo.aucBssid))); ++ cnmTimerStopTimer(&prAisSpecBssInfo->rPreauthenticationTimer); ++ cnmTimerStartTimer(&prAisSpecBssInfo->rPreauthenticationTimer, ++ SEC_TO_MSEC ++ (WAIT_TIME_IND_PMKID_CANDICATE_SEC)); ++ } ++ } ++ } ++#endif ++ } else { ++ /* Can't pass the Encryption Status Check, get next one */ ++ continue; ++ } ++#endif ++ } else { ++ /* Todo:: P2P and BOW Policy Selection */ ++ } ++ ++ prPrimaryStaRec = prStaRec; ++ ++ /* 4 <8> Compare the Candidate and the Primary Scan Record. */ ++ if (!prCandidateBssDesc) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ ++ /* 4 <8.1> Condition - Get the first matched one. */ ++ if (fgIsFindFirst) ++ break; ++ } else { ++#if 0 /* TODO(Kevin): For security(TBD) */ ++ /* 4 <6B> Condition - Choose the one with best Encryption Score. */ ++ if (fgIsFindBestEncryptionLevel) { ++ if (prCandidateBssDesc->ucEncLevel < prPrimaryBssDesc->ucEncLevel) { ++ ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ ++ /* If reach here, that means they have the same Encryption Score. ++ */ ++ ++ /* 4 <6C> Condition - Give opportunity to the one we didn't connect before. */ ++ /* For roaming, only compare the candidates other than current associated BSSID. */ ++ if (!prCandidateBssDesc->fgIsConnected && !prPrimaryBssDesc->fgIsConnected) { ++ if ((prCandidateStaRec != (P_STA_RECORD_T) NULL) && ++ (prCandidateStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { ++ ++ DBGLOG(SCAN, TRACE, ++ "So far -BSS DESC MAC: %pM has nonzero Status Code = %d\n", ++ prCandidateBssDesc->aucBSSID, ++ prCandidateStaRec->u2StatusCode); ++ ++ if (prPrimaryStaRec != (P_STA_RECORD_T) NULL) { ++ if (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { ++ ++ /* Give opportunity to the one with smaller rLastJoinTime */ ++ if (TIME_BEFORE(prCandidateStaRec->rLastJoinTime, ++ prPrimaryStaRec->rLastJoinTime)) { ++ continue; ++ } ++ /* We've connect to CANDIDATE recently, ++ * let us try PRIMARY now */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ /* PRIMARY's u2StatusCode = 0 */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++ /* PRIMARY has no StaRec - We didn't connet to PRIMARY before */ ++ else { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else { ++ if ((prPrimaryStaRec != (P_STA_RECORD_T) NULL) && ++ (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { ++ continue; ++ } ++ } ++ } ++#endif ++ ++ /* 4 <6D> Condition - Visible SSID win Hidden SSID. */ ++ if (prCandidateBssDesc->fgIsHiddenSSID) { ++ if (!prPrimaryBssDesc->fgIsHiddenSSID) { ++ prCandidateBssDesc = prPrimaryBssDesc; /* The non Hidden SSID win. */ ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else { ++ if (prPrimaryBssDesc->fgIsHiddenSSID) ++ continue; ++ } ++ ++ /* 4 <6E> Condition - Choose the one with better RCPI(RSSI). */ ++ if (fgIsFindBestRSSI) { ++ /* TODO(Kevin): We shouldn't compare the actual value, we should ++ * allow some acceptable tolerance of some RSSI percentage here. ++ */ ++ DBGLOG(SCN, TRACE, ++ "Candidate [%pM]: RCPI = %d, joinFailCnt=%d, Primary [%pM]: RCPI = %d, joinFailCnt=%d\n", ++ prCandidateBssDesc->aucBSSID, ++ prCandidateBssDesc->ucRCPI, prCandidateBssDesc->ucJoinFailureCount, ++ prPrimaryBssDesc->aucBSSID, ++ prPrimaryBssDesc->ucRCPI, prPrimaryBssDesc->ucJoinFailureCount); ++ ++ ASSERT(!(prCandidateBssDesc->fgIsConnected && prPrimaryBssDesc->fgIsConnected)); ++ if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { ++ /* give a chance to do join if join fail before ++ * SCN_BSS_DECRASE_JOIN_FAIL_CNT_SEC seconds ++ */ ++ if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rJoinFailTime, ++ SEC_TO_SYSTIME(SCN_BSS_JOIN_FAIL_CNT_RESET_SEC))) { ++ prBssDesc->ucJoinFailureCount = SCN_BSS_JOIN_FAIL_THRESOLD - ++ SCN_BSS_JOIN_FAIL_RESET_STEP; ++ DBGLOG(SCN, INFO, ++ "decrease join fail count for Bss %pM to %u, timeout second %d\n", ++ prBssDesc->aucBSSID, prBssDesc->ucJoinFailureCount, ++ SCN_BSS_JOIN_FAIL_CNT_RESET_SEC); ++ } ++ } ++ ++ /* NOTE: To prevent SWING, ++ * we do roaming only if target AP has at least 5dBm larger than us. */ ++ if (prCandidateBssDesc->fgIsConnected) { ++ if (prCandidateBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP <= ++ prPrimaryBssDesc->ucRCPI && ++ prPrimaryBssDesc->ucJoinFailureCount < SCN_BSS_JOIN_FAIL_THRESOLD) { ++ ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else if (prPrimaryBssDesc->fgIsConnected) { ++ if (prCandidateBssDesc->ucRCPI < ++ (prPrimaryBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP) || ++ (prCandidateBssDesc->ucJoinFailureCount >= ++ SCN_BSS_JOIN_FAIL_THRESOLD)) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } else if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) ++ continue; ++ else if (prCandidateBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD || ++ prCandidateBssDesc->ucRCPI < prPrimaryBssDesc->ucRCPI) { ++ prCandidateBssDesc = prPrimaryBssDesc; ++ prCandidateStaRec = prPrimaryStaRec; ++ continue; ++ } ++ } ++#if 0 ++ /* If reach here, that means they have the same Encryption Score, and ++ * both RSSI value are close too. ++ */ ++ /* 4 <6F> Seek the minimum Channel Load for less interference. */ ++ if (fgIsFindMinChannelLoad) { ++ /* Do nothing */ ++ /* TODO(Kevin): Check which one has minimum channel load in its channel */ ++ } ++#endif ++ } ++ } ++ ++ ++ if (prCandidateBssDesc != NULL) { ++ DBGLOG(SCN, INFO, ++ "SEARCH: Candidate BSS: %pM\n", prCandidateBssDesc->aucBSSID); ++ } ++ ++ return prCandidateBssDesc; ++ ++} /* end of scanSearchBssDescByPolicy() */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter) ++{ ++ P_LINK_T prBSSDescList = &prAdapter->rWifiVar.rScanInfo.rBSSDescList; ++ P_BSS_DESC_T prBssDesc = NULL; ++ P_AGPS_AP_LIST_T prAgpsApList; ++ P_AGPS_AP_INFO_T prAgpsInfo; ++ P_SCAN_INFO_T prScanInfo = &prAdapter->rWifiVar.rScanInfo; ++ UINT_8 ucIndex = 0; ++ ++ prAgpsApList = kalMemAlloc(sizeof(AGPS_AP_LIST_T), VIR_MEM_TYPE); ++ if (!prAgpsApList) ++ return; ++ ++ prAgpsInfo = &prAgpsApList->arApInfo[0]; ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->rUpdateTime < prScanInfo->rLastScanCompletedTime) ++ continue; ++ COPY_MAC_ADDR(prAgpsInfo->aucBSSID, prBssDesc->aucBSSID); ++ prAgpsInfo->ePhyType = AGPS_PHY_G; ++ prAgpsInfo->u2Channel = prBssDesc->ucChannelNum; ++ prAgpsInfo->i2ApRssi = RCPI_TO_dBm(prBssDesc->ucRCPI); ++ prAgpsInfo++; ++ ucIndex++; ++ if (ucIndex == 32) ++ break; ++ } ++ prAgpsApList->ucNum = ucIndex; ++ GET_CURRENT_SYSTIME(&prScanInfo->rLastScanCompletedTime); ++ /* DBGLOG(SCN, INFO, ("num of scan list:%d\n", ucIndex)); */ ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_AP_LIST, (PUINT_8) prAgpsApList, sizeof(AGPS_AP_LIST_T)); ++ kalMemFree(prAgpsApList, VIR_MEM_TYPE, sizeof(AGPS_AP_LIST_T)); ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c +new file mode 100644 +index 000000000000..fac9f94428dd +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c +@@ -0,0 +1,2136 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan_fsm.c#1 ++*/ ++ ++/*! \file "scan_fsm.c" ++ \brief This file defines the state transition function for SCAN FSM. ++ ++ The SCAN FSM is part of SCAN MODULE and responsible for performing basic SCAN ++ behavior as metioned in IEEE 802.11 2007 11.1.3.1 & 11.1.3.2 . ++*/ ++ ++/* ++** Log: scan_fsm.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001095] [Volunteer Patch][Driver] Always Scan before enable Hot-Spot. ++ * Fix bug when unregister P2P network.. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * free mailbox message afte parsing is completed. ++ * ++ * 07 18 2011 cp.wu ++ * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search ++ * for more than one SSID in a single scanning request ++ * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support ++ * as well as uProbeDelay in NDIS 6.x driver model ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning ++ * surpress klock warning with code path rewritten ++ * ++ * 03 18 2011 cm.chang ++ * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command ++ * As CR title ++ * ++ * 02 18 2011 yuche.tsai ++ * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame ++ * during search phase do not contain P2P wildcard SSID. ++ * Take P2P wildcard SSID into consideration. ++ * ++ * 01 27 2011 yuche.tsai ++ * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. ++ * Fix scan channel extension issue when p2p module is not registered. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add interface for RLM to trigger OBSS-SCAN. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Fix bug for processing queued scan request. ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add a function for returning channel. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Update SCAN FSM for support P2P Device discovery scan. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Add option of channel extension while cancelling scan request. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 20 2010 cp.wu ++ * ++ * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * due to FW/DRV won't be sync. precisely, some strict assertions should be eased. ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * SCN module is now able to handle multiple concurrent scanning requests ++ * ++ * 07 16 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * bugfix for SCN migration ++ * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue ++ * 2) before AIS issues scan request, network(BSS) needs to be activated first ++ * 3) only invoke COPY_SSID when using specified SSID for scan ++ * ++ * 07 15 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * driver no longer generates probe request frames ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * pass band with channel number information as scan parameter ++ * ++ * 07 14 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * remove timer in DRV-SCN. ++ * ++ * 07 09 2010 cp.wu ++ * ++ * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) ++ * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass ++ * 3) implment DRV-SCN module, currently only accepts single scan request, ++ * other request will be directly dropped by returning BUSY ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * take use of RLM module for parsing/generating HT IEs for 11n capability ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * when returning to SCAN_IDLE state, send a correct message to source FSM. ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * comment out RLM APIs by CFG_RLM_MIGRATION. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add scan_fsm into building. ++ * ++ * 05 14 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine the order of Stop TX Queue and Switch Channel ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Update pause/resume/flush API to new Bitmap API ++ * ++ * 05 12 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Add Power Management - Legacy PS-POLL support. ++ * ++ * 03 18 2010 kevin.huang ++ * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support ++ * Ignore the PROBE_DELAY state if the value of Probe Delay == 0 ++ * ++ * 03 10 2010 kevin.huang ++ * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support ++ * Add Channel Manager for arbitration of JOIN and SCAN Req ++ * ++ * 02 23 2010 kevin.huang ++ * [BORA00000603][WIFISYS] [New Feature] AAA Module Support ++ * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb ++ * ++ * 01 08 2010 kevin.huang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * Add set RX Filter to receive BCN from different BSSID during SCAN ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Nov 25 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Remove flag of CFG_TEST_MGMT_FSM ++ * ++ * Nov 20 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Change parameter of scanSendProbeReqFrames() ++ * ++ * Nov 16 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Update scnFsmSteps() ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * Fix typo ++ * ++ * Nov 5 2009 mtk01461 ++ * [BORA00000018] Integrate WIFI part into BORA for the 1st time ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugScanState[SCAN_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("SCAN_STATE_IDLE"), ++ (PUINT_8) DISP_STRING("SCAN_STATE_SCANNING"), ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++#define CURRENT_PSCN_VERSION 1 ++#define RSSI_MARGIN_DEFAULT 5 ++#define MAX_PERIOD 200000 ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_HDR_T prMsgHdr; ++ ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ do { ++ ++#if DBG ++ DBGLOG(SCN, STATE, "TRANSITION: [%s] -> [%s]\n", ++ apucDebugScanState[prScanInfo->eCurrentState], apucDebugScanState[eNextState]); ++#else ++ DBGLOG(SCN, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", ++ DBG_SCN_IDX, prScanInfo->eCurrentState, eNextState); ++#endif ++ ++ /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ ++ prScanInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++ ++ switch (prScanInfo->eCurrentState) { ++ case SCAN_STATE_IDLE: ++ /* check for pending scanning requests */ ++ if (!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { ++ /* load next message from pending list as scan parameters */ ++ LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, P_MSG_HDR_T); ++ ++ if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); ++ } else { ++ scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); ++ } ++ ++ /* switch to next state */ ++ eNextState = SCAN_STATE_SCANNING; ++ fgIsTransition = TRUE; ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ } ++ break; ++ ++ case SCAN_STATE_SCANNING: ++ if (prScanParam->fgIsScanV2 == FALSE) ++ scnSendScanReq(prAdapter); ++ else ++ scnSendScanReqV2(prAdapter); ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ ++ } ++ } while (fgIsTransition); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_EXT_CH rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_EXT_CH prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_EXT_CH), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) ++ return; ++ ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_EXT_CH)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ if (prScanParam->ucSSIDNum == 1) { ++ COPY_SSID(prCmdScanReq->aucSSID, ++ prCmdScanReq->ucSSIDLength, ++ prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); ++ } ++ ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_EXT_CH, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ else if (prCmdScanReq->ucSSIDLength > 32) ++ kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_EXT_CH)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReq(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ rCmdScanReq;*/ ++ P_CMD_SCAN_REQ prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanParam->ucChannelListNum > 32) { ++ scnSendScanReqExtCh(prAdapter); ++ } else { ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdScanReq fail"); ++ return; ++ } ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ if (prScanParam->ucSSIDNum == 1) { ++ COPY_SSID(prCmdScanReq->aucSSID, ++ prCmdScanReq->ucSSIDLength, ++ prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); ++ } ++ ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. ++ * (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++#if CFG_ENABLE_FAST_SCAN ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = CFG_FAST_SCAN_DWELL_TIME; ++#endif ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ else if (prCmdScanReq->ucSSIDLength > 32) ++ kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ_V2 command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_V2_EXT_CH rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_V2_EXT_CH prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2_EXT_CH), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) ++ return; ++ ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ for (i = 0; i < prScanParam->ucSSIDNum; i++) { ++ COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, ++ prCmdScanReq->arSSID[i].u4SsidLen, ++ prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); ++ } ++ ++ prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ_V2, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_V2_EXT_CH, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Generate CMD_ID_SCAN_REQ_V2 command ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ /*CMD_SCAN_REQ_V2 rCmdScanReq;*/ ++ P_CMD_SCAN_REQ_V2 prCmdScanReq; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanParam->ucChannelListNum > 32) { ++ scnSendScanReqV2ExtCh(prAdapter); ++ } else { ++ prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2), VIR_MEM_TYPE); ++ if (prCmdScanReq == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdScanReq v2 fail"); ++ return; ++ } ++ /* send command packet for scan */ ++ kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2)); ++ ++ prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; ++ prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; ++ prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; ++ ++ for (i = 0; i < prScanParam->ucSSIDNum; i++) { ++ COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, ++ prCmdScanReq->arSSID[i].u4SsidLen, ++ prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); ++ } ++ ++ prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; ++ prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; ++ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ /* P2P would use: ++ * 1. Specified Listen Channel of passive scan for LISTEN state. ++ * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. ++ * (Target != NULL) ++ */ ++ prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; ++ ++ for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { ++ prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; ++ ++ prCmdScanReq->arChannelList[i].ucChannelNum = ++ (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; ++#endif ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdScanReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdScanReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_REQ_V2, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ OFFSET_OF(CMD_SCAN_REQ_V2, aucIE) + prCmdScanReq->u2IELen, ++ (PUINT_8) prCmdScanReq, NULL, 0); ++ /* sanity check for some scan parameters */ ++ if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) ++ kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); ++ else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) ++ kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); ++ else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && ++ prCmdScanReq->ucChannelListNum != 0) ++ kalSendAeeWarning("wlan", ++ "channel list is not NULL but channel type is not specified"); ++ else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) ++ kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); ++ else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ ++ kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); ++ ++ kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2)); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanInfo->eCurrentState == SCAN_STATE_IDLE) { ++ if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); ++ } else if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 ++ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { ++ scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); ++ } else { ++ /* should not deliver to this function */ ++ ASSERT(0); ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ scnFsmSteps(prAdapter, SCAN_STATE_SCANNING); ++ } else { ++ LINK_INSERT_TAIL(&prScanInfo->rPendingMsgList, &prMsgHdr->rLinkEntry); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) ++{ ++ P_MSG_SCN_SCAN_CANCEL prScanCancel; ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ CMD_SCAN_CANCEL rCmdScanCancel; ++ ++ ASSERT(prMsgHdr); ++ ++ prScanCancel = (P_MSG_SCN_SCAN_CANCEL) prMsgHdr; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ if (prScanInfo->eCurrentState != SCAN_STATE_IDLE) { ++ if (prScanCancel->ucSeqNum == prScanParam->ucSeqNum && ++ prScanCancel->ucNetTypeIndex == (UINT_8) prScanParam->eNetTypeIndex) { ++ /* send cancel message to firmware domain */ ++ rCmdScanCancel.ucSeqNum = prScanParam->ucSeqNum; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) prScanCancel->fgIsChannelExt; ++ else ++ rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; ++#endif ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SCAN_CANCEL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8) &rCmdScanCancel, NULL, 0); ++ ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ++ prScanParam->ucSeqNum, ++ (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_CANCELLED); ++ ++ /* switch to next pending scan */ ++ scnFsmSteps(prAdapter, SCAN_STATE_IDLE); ++ } else { ++ scnFsmRemovePendingMsg(prAdapter, prScanCancel->ucSeqNum, prScanCancel->ucNetTypeIndex); ++ } ++ } ++ ++ cnmMemFree(prAdapter, prMsgHdr); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Scan Message Parsing (Legacy) ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prScanReqMsg); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prScanParam->eScanType = prScanReqMsg->eScanType; ++ prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; ++ prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; ++ if (prScanParam->ucSSIDType & (SCAN_REQ_SSID_SPECIFIED | SCAN_REQ_SSID_P2P_WILDCARD)) { ++ prScanParam->ucSSIDNum = 1; ++ ++ COPY_SSID(prScanParam->aucSpecifiedSSID[0], ++ prScanParam->ucSpecifiedSSIDLen[0], prScanReqMsg->aucSSID, prScanReqMsg->ucSSIDLength); ++ ++ /* reset SSID length to zero for rest array entries */ ++ for (i = 1; i < SCN_SSID_MAX_NUM; i++) ++ prScanParam->ucSpecifiedSSIDLen[i] = 0; ++ } else { ++ prScanParam->ucSSIDNum = 0; ++ ++ for (i = 0; i < SCN_SSID_MAX_NUM; i++) ++ prScanParam->ucSpecifiedSSIDLen[i] = 0; ++ } ++ ++ prScanParam->u2ProbeDelayTime = 0; ++ prScanParam->eScanChannel = prScanReqMsg->eScanChannel; ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; ++ else ++ prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ kalMemCopy(prScanParam->arChnlInfoList, ++ prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); ++ } ++ ++ if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) ++ prScanParam->u2IELen = prScanReqMsg->u2IELen; ++ else ++ prScanParam->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; ++#endif ++ prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; ++ ++ if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) ++ prScanParam->fgIsObssScan = TRUE; ++ else ++ prScanParam->fgIsObssScan = FALSE; ++ ++ prScanParam->fgIsScanV2 = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Scan Message Parsing - V2 with multiple SSID support ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ASSERT(prScanReqMsg); ++ ASSERT(prScanReqMsg->ucSSIDNum <= SCN_SSID_MAX_NUM); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ prScanParam->eScanType = prScanReqMsg->eScanType; ++ prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; ++ prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; ++ prScanParam->ucSSIDNum = prScanReqMsg->ucSSIDNum; ++ ++ for (i = 0; i < prScanReqMsg->ucSSIDNum; i++) { ++ COPY_SSID(prScanParam->aucSpecifiedSSID[i], ++ prScanParam->ucSpecifiedSSIDLen[i], ++ prScanReqMsg->prSsid[i].aucSsid, (UINT_8) prScanReqMsg->prSsid[i].u4SsidLen); ++ } ++ ++ prScanParam->u2ProbeDelayTime = prScanReqMsg->u2ProbeDelay; ++ prScanParam->eScanChannel = prScanReqMsg->eScanChannel; ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { ++ if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) ++ prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; ++ else ++ prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; ++ ++ kalMemCopy(prScanParam->arChnlInfoList, ++ prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); ++ } ++ ++ if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) ++ prScanParam->u2IELen = prScanReqMsg->u2IELen; ++ else ++ prScanParam->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) ++ prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; ++#endif ++ prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; ++ ++ if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) ++ prScanParam->fgIsObssScan = TRUE; ++ else ++ prScanParam->fgIsObssScan = FALSE; ++ ++ prScanParam->fgIsScanV2 = TRUE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Remove pending scan request ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_HDR_T prPendingMsgHdr, prPendingMsgHdrNext, prRemoveMsgHdr = NULL; ++ P_LINK_ENTRY_T prRemoveLinkEntry = NULL; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ /* traverse through rPendingMsgList for removal */ ++ LINK_FOR_EACH_ENTRY_SAFE(prPendingMsgHdr, ++ prPendingMsgHdrNext, &(prScanInfo->rPendingMsgList), rLinkEntry, MSG_HDR_T) { ++ if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ ++ || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { ++ P_MSG_SCN_SCAN_REQ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) prPendingMsgHdr; ++ ++ if (ucSeqNum == prScanReqMsg->ucSeqNum && ucNetTypeIndex == prScanReqMsg->ucNetTypeIndex) { ++ prRemoveLinkEntry = &(prScanReqMsg->rMsgHdr.rLinkEntry); ++ prRemoveMsgHdr = prPendingMsgHdr; ++ } ++ } else if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 ++ || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { ++ P_MSG_SCN_SCAN_REQ_V2 prScanReqMsgV2 = (P_MSG_SCN_SCAN_REQ_V2) prPendingMsgHdr; ++ ++ if (ucSeqNum == prScanReqMsgV2->ucSeqNum && ucNetTypeIndex == prScanReqMsgV2->ucNetTypeIndex) { ++ prRemoveLinkEntry = &(prScanReqMsgV2->rMsgHdr.rLinkEntry); ++ prRemoveMsgHdr = prPendingMsgHdr; ++ } ++ } ++ ++ if (prRemoveLinkEntry) { ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ucSeqNum, ucNetTypeIndex, SCAN_STATUS_CANCELLED); ++ ++ /* remove from pending list */ ++ LINK_REMOVE_KNOWN_ENTRY(&(prScanInfo->rPendingMsgList), prRemoveLinkEntry); ++ cnmMemFree(prAdapter, prRemoveMsgHdr); ++ ++ break; ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ /* buffer empty channel information */ ++ if (prScanParam->eScanChannel == SCAN_CHANNEL_FULL || prScanParam->eScanChannel == SCAN_CHANNEL_2G4) { ++ if (prScanDone->ucSparseChannelValid) { ++ prScanInfo->fgIsSparseChannelValid = TRUE; ++ prScanInfo->rSparseChannel.eBand = (ENUM_BAND_T) prScanDone->rSparseChannel.ucBand; ++ prScanInfo->rSparseChannel.ucChannelNum = prScanDone->rSparseChannel.ucChannelNum; ++ } else { ++ prScanInfo->fgIsSparseChannelValid = FALSE; ++ } ++ } ++ ++ if (prScanInfo->eCurrentState == SCAN_STATE_SCANNING && prScanDone->ucSeqNum == prScanParam->ucSeqNum) { ++ /* generate scan-done event for caller */ ++ scnFsmGenerateScanDoneMsg(prAdapter, ++ prScanParam->ucSeqNum, (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_DONE); ++ ++ /* switch to next pending scan */ ++ scnFsmSteps(prAdapter, SCAN_STATE_IDLE); ++ } else { ++ DBGLOG(SCN, WARN, "Unexpected SCAN-DONE event: SeqNum = %d, Current State = %d\n", ++ prScanDone->ucSeqNum, prScanInfo->eCurrentState); ++ } ++ ++} /* end of scnEventScanDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_SCAN_PARAM_T prScanParam; ++ P_MSG_SCN_SCAN_DONE prScanDoneMsg; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prScanParam = &prScanInfo->rScanParam; ++ ++ DBGLOG(SCN, INFO, "Rcv Scan Done, NetIdx %d, Obss %d, Status %d, Seq %d\n", ++ ucNetTypeIndex, prScanParam->fgIsObssScan, eScanStatus, ucSeqNum); ++ prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_DONE)); ++ if (!prScanDoneMsg) { ++ ASSERT(0); /* Can't indicate SCAN FSM Complete */ ++ return; ++ } ++ ++ if (prScanParam->fgIsObssScan == TRUE) { ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_RLM_SCAN_DONE; ++ } else { ++ switch ((ENUM_NETWORK_TYPE_INDEX_T) ucNetTypeIndex) { ++ case NETWORK_TYPE_AIS_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_AIS_SCAN_DONE; ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case NETWORK_TYPE_P2P_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_P2P_SCAN_DONE; ++ break; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ case NETWORK_TYPE_BOW_INDEX: ++ prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_BOW_SCAN_DONE; ++ break; ++#endif ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ prScanDoneMsg->ucSeqNum = ucSeqNum; ++ prScanDoneMsg->ucNetTypeIndex = ucNetTypeIndex; ++ prScanDoneMsg->eScanStatus = eScanStatus; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanDoneMsg, MSG_SEND_METHOD_BUF); ++ ++} /* end of scnFsmGenerateScanDoneMsg() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Query for most sparse channel ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prScanInfo->fgIsSparseChannelValid == TRUE) { ++ if (prSparseBand) ++ *prSparseBand = prScanInfo->rSparseChannel.eBand; ++ ++ if (pucSparseChannel) ++ *pucSparseChannel = prScanInfo->rSparseChannel.ucChannelNum; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Event handler for NLO done event ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ if (prScanInfo->fgNloScanning == TRUE) { ++ DBGLOG(SCN, INFO, "scnEventNloDone Current State = %d\n", prScanInfo->eCurrentState); ++ ++ kalSchedScanResults(prAdapter->prGlueInfo); ++ ++ if (prNloParam->fgStopAfterIndication == TRUE) ++ prScanInfo->fgNloScanning = FALSE; ++ ++ kalMemZero(&prNloParam->aprPendingBssDescToInd[0], ++ CFG_SCAN_SSID_MATCH_MAX_NUM * sizeof(P_BSS_DESC_T)); ++ } else { ++ DBGLOG(SCN, INFO, "Unexpected NLO-DONE event\n"); ++ } ++ ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for starting scheduled scan ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucSsidNum, ++ IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ P_CMD_NLO_REQ prCmdNloReq; ++ UINT_32 i, j; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ if (prScanInfo->fgNloScanning) { ++ DBGLOG(SCN, INFO, "prScanInfo->fgNloScanning == TRUE already scanning\n"); ++ return TRUE; ++ } ++ ++ prScanInfo->fgNloScanning = TRUE; ++ ++ /* 1. load parameters */ ++ prScanParam->ucSeqNum++; ++ /* prScanParam->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; */ ++ ++ prNloParam->fgStopAfterIndication = TRUE; ++ prNloParam->ucFastScanIteration = 0; ++ prNloParam->u2FastScanPeriod = u2Interval; ++ prNloParam->u2SlowScanPeriod = u2Interval; ++ ++ if (prScanParam->ucSSIDNum > CFG_SCAN_SSID_MAX_NUM) ++ prScanParam->ucSSIDNum = CFG_SCAN_SSID_MAX_NUM; ++ else ++ prScanParam->ucSSIDNum = ucSsidNum; ++ ++ if (prNloParam->ucMatchSSIDNum > CFG_SCAN_SSID_MATCH_MAX_NUM) ++ prNloParam->ucMatchSSIDNum = CFG_SCAN_SSID_MATCH_MAX_NUM; ++ else ++ prNloParam->ucMatchSSIDNum = ucSsidNum; ++ ++ for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { ++ if (i < CFG_SCAN_SSID_MAX_NUM) { ++ COPY_SSID(prScanParam->aucSpecifiedSSID[i], ++ prScanParam->ucSpecifiedSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); ++ } ++ ++ COPY_SSID(prNloParam->aucMatchSSID[i], ++ prNloParam->ucMatchSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); ++ ++ prNloParam->aucCipherAlgo[i] = 0; ++ prNloParam->au2AuthAlgo[i] = 0; ++ ++ for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) ++ prNloParam->aucChannelHint[i][j] = 0; ++ } ++ ++ /* 2. prepare command for sending */ ++ prCmdNloReq = (P_CMD_NLO_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_NLO_REQ) + prScanParam->u2IELen); ++ ++ if (!prCmdNloReq) { ++ ASSERT(0); /* Can't initiate NLO operation */ ++ return FALSE; ++ } ++ ++ /* 3. send command packet for NLO operation */ ++ kalMemZero(prCmdNloReq, sizeof(CMD_NLO_REQ)); ++ ++ prCmdNloReq->ucSeqNum = prScanParam->ucSeqNum; ++ /* prCmdNloReq->ucBssIndex = prScanParam->ucBssIndex; */ ++ ++ prCmdNloReq->ucNetworkType = prScanParam->eNetTypeIndex; ++ prCmdNloReq->ucScanType = (UINT_8) prScanParam->eScanType; ++ ++ prCmdNloReq->fgStopAfterIndication = prNloParam->fgStopAfterIndication; ++ prCmdNloReq->ucFastScanIteration = prNloParam->ucFastScanIteration; ++ prCmdNloReq->u2FastScanPeriod = prNloParam->u2FastScanPeriod; ++ prCmdNloReq->u2SlowScanPeriod = prNloParam->u2SlowScanPeriod; ++ prCmdNloReq->ucEntryNum = prNloParam->ucMatchSSIDNum; ++ for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { ++ COPY_SSID(prCmdNloReq->arNetworkList[i].aucSSID, ++ prCmdNloReq->arNetworkList[i].ucSSIDLength, ++ prNloParam->aucMatchSSID[i], prNloParam->ucMatchSSIDLen[i]); ++ ++ prCmdNloReq->arNetworkList[i].ucCipherAlgo = prNloParam->aucCipherAlgo[i]; ++ prCmdNloReq->arNetworkList[i].u2AuthAlgo = prNloParam->au2AuthAlgo[i]; ++ ++ for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) ++ prCmdNloReq->arNetworkList[i].ucNumChannelHint[j] = prNloParam->aucChannelHint[i][j]; ++ } ++ ++ if (prScanParam->u2IELen <= MAX_IE_LENGTH) ++ prCmdNloReq->u2IELen = prScanParam->u2IELen; ++ else ++ prCmdNloReq->u2IELen = MAX_IE_LENGTH; ++ ++ if (prScanParam->u2IELen) ++ kalMemCopy(prCmdNloReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdNloReq->u2IELen); ++#if !CFG_SUPPORT_GSCN ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NLO_REQ, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetCommon, ++ nicOidCmdTimeoutCommon, ++ sizeof(CMD_NLO_REQ) + prCmdNloReq->u2IELen, (PUINT_8) prCmdNloReq, NULL, 0); ++ ++#else ++ scnPSCNFsm(prAdapter, PSCN_RESET, prCmdNloReq, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE); ++#endif ++ cnmMemFree(prAdapter, (PVOID) prCmdNloReq); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for stopping scheduled scan ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ P_NLO_PARAM_T prNloParam; ++ P_SCAN_PARAM_T prScanParam; ++ CMD_NLO_CANCEL rCmdNloCancel; ++ ++ ASSERT(prAdapter); ++ ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prNloParam = &prScanInfo->rNloParam; ++ prScanParam = &prNloParam->rScanParam; ++ ++ /* send cancel message to firmware domain */ ++ rCmdNloCancel.ucSeqNum = prScanParam->ucSeqNum; ++ ++#if !CFG_SUPPORT_GSCN ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_NLO_CANCEL, ++ TRUE, ++ FALSE, ++ TRUE, ++ nicCmdEventSetStopSchedScan, ++ nicOidCmdTimeoutCommon, sizeof(CMD_NLO_CANCEL), (PUINT_8)(&rCmdNloCancel), NULL, 0); ++#else ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, TRUE, FALSE, FALSE, FALSE); ++#endif ++ ++ prScanInfo->fgNloScanning = FALSE; ++ ++ return TRUE; ++} ++ ++#if CFG_SUPPORT_GSCN ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set PSCN action ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct) ++{ ++ CMD_SET_PSCAN_ENABLE rCmdPscnAction; ++ P_SCAN_INFO_T prScanInfo; ++ ++ DBGLOG(SCN, TRACE, "scnFsmPSCNAction Act = %d\n", ucPscanAct); ++ ++ rCmdPscnAction.ucPscanAct = ucPscanAct; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (ucPscanAct == DISABLE) ++ prScanInfo->fgPscnOnnning = FALSE; ++ if (ucPscanAct == ENABLE) ++ prScanInfo->fgPscnOnnning = TRUE; ++ ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ENABLE, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_ENABLE), (PUINT_8) &rCmdPscnAction, NULL, 0); ++ ++ DBGLOG(SCN, INFO, "scnFsmPSCNAction Act = %d is Set to FW\n", ucPscanAct); ++ return TRUE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set PSCN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ UINT_8 i, j; ++ ++ i = 0; ++ j = 0; ++ ++ ASSERT(prAdapter); ++ /*prCmdPscnParam->u4BasePeriod = prCmdPscnParam->u4BasePeriod;*/ ++#if 0 ++ DBGLOG(SCN, TRACE, ++ "rCmdPscnParam: Period[%u],NumCache[%u],Threshold[%u],NumBkts[%u],fgGSCN[%d] fgNLO[%d] fgBatch[%d]\n", ++ prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, ++ prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, prCmdPscnParam->fgBatchScnEnable)); ++ ++ for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { ++ DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); ++ DBGLOG(SCN, TRACE, ++ "band[%u], Index[%u] NumChannels[%u], ucBktFreqMultiple[%u] Flag[%u]\n", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); ++ for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) ++ DBGLOG(SCN, TRACE, ++ " %d, ", prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); ++ DBGLOG(SCN, TRACE, "\n"); ++ } ++#endif ++ ++ if (1 /*prScanInfo->fgPscnOnnning == FALSE */) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCAN_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_PARAM), (PUINT_8) prCmdPscnParam, NULL, 0); ++ ++ DBGLOG(SCN, TRACE, "CMD_ID_SET_PSCAN_PARAM is set to FW !!!!!!!!!!\n"); ++ return TRUE; ++ } ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set hotlist ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID prCmdPscnAddHotlist) ++{ ++ CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ memcpy(&rCmdPscnAddHotlist.aucMacAddr, &(prCmdPscnAddHotlist->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ /* rCmdPscnAddHotlist.aucMacAddr = prCmdPscnAddHotlist->aucMacAddr; */ ++ rCmdPscnAddHotlist.ucFlags = prCmdPscnAddHotlist->ucFlags; ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_SET_PSCAN_ADD_HOTLIST_BSSID), (PUINT_8) &rCmdPscnAddHotlist, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_ADD_SW_BSSID ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId) ++{ ++ CMD_SET_PSCAN_ADD_SWC_BSSID rCmdPscnAddSWCBssId; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ memcpy(&rCmdPscnAddSWCBssId.aucMacAddr, &(prCmdPscnAddSWCBssId->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ /* rCmdPscnAddSWCBssId.aucMacAddr = prCmdPscnAddSWCBssId->aucMacAddr; */ ++ rCmdPscnAddSWCBssId.i4RssiHighThreshold = prCmdPscnAddSWCBssId->i4RssiHighThreshold; ++ rCmdPscnAddSWCBssId.i4RssiLowThreshold = prCmdPscnAddSWCBssId->i4RssiLowThreshold; ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_ADD_SW_BSSID, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_SET_PSCAN_ADD_SWC_BSSID), (PUINT_8) &rCmdPscnAddSWCBssId, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr) ++{ ++ CMD_SET_PSCAN_MAC_ADDR rCmdPscnSetMacAddr; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ /* rCmdPscnSetMacAddr.aucMacAddr = prCmdPscnSetMacAddr->aucMacAddr; */ ++ memcpy(&rCmdPscnSetMacAddr.aucMacAddr, &(prCmdPscnSetMacAddr->aucMacAddr), sizeof(MAC_ADDR_LEN)); ++ ++ rCmdPscnSetMacAddr.ucFlags = prCmdPscnSetMacAddr->ucFlags; ++ rCmdPscnSetMacAddr.ucVersion = prCmdPscnSetMacAddr->ucVersion; ++ ++ if (1 /* (prScanInfo->fgPscnOnnning == TRUE */) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PSCN_MAC_ADDR, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_SET_PSCAN_MAC_ADDR), (PUINT_8) &rCmdPscnSetMacAddr, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set GSCN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam) ++{ ++ /*CMD_GSCN_REQ_T rCmdGscnParam;*/ ++ P_CMD_GSCN_REQ_T rCmdGscnParamp; ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 ucChannelBuckIndex; ++ UINT_8 i; ++ ++ ASSERT(prAdapter); ++ rCmdGscnParamp = kalMemAlloc(sizeof(CMD_GSCN_REQ_T), VIR_MEM_TYPE); ++ if (rCmdGscnParamp == NULL) { ++ DBGLOG(SCN, INFO, "alloc CmdGscnParam fail\n"); ++ return TRUE; ++ } ++ kalMemZero(rCmdGscnParamp, sizeof(CMD_GSCN_REQ_T)); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ rCmdGscnParamp->u4NumBuckets = prCmdGscnParam->num_buckets; ++ rCmdGscnParamp->u4BasePeriod = prCmdGscnParam->base_period; ++ DBGLOG(SCN, INFO, ++ "u4BasePeriod[%d], u4NumBuckets[%d]\n", rCmdGscnParamp->u4BasePeriod, rCmdGscnParamp->u4NumBuckets); ++ for (ucChannelBuckIndex = 0; ucChannelBuckIndex < prCmdGscnParam->num_buckets; ucChannelBuckIndex++) { ++ DBGLOG(SCN, TRACE, "assign channels to bucket[%d]\n", ucChannelBuckIndex); ++ for (i = 0; i < prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; i++) { ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel = ++ (UINT_8) nicFreq2ChannelNum(prCmdGscnParam->buckets[ucChannelBuckIndex]. ++ channels[i].channel * 1000); ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive = ++ (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].passive; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs = ++ (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].dwellTimeMs; ++ ++ DBGLOG(SCN, TRACE, "[ucChannel %d, ucPassive %d, u4DwellTimeMs %d\n", ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel, ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive, ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs); ++ ++ } ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].u2BucketIndex = ++ (UINT_16) prCmdGscnParam->buckets[ucChannelBuckIndex].bucket; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].eBand = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].band; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucBucketFreqMultiple = ++ (prCmdGscnParam->buckets[ucChannelBuckIndex].period / prCmdGscnParam->base_period); ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucNumChannels = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; ++ rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucReportFlag = ++ prCmdGscnParam->buckets[ucChannelBuckIndex].report_events; ++ ++ /* printk("\n"); */ ++ } ++ ++ DBGLOG(SCN, INFO, "scnSetGSCNParam ---> scnPSCNFsm PSCN_RESET\n"); ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, rCmdGscnParamp, NULL, FALSE, FALSE, FALSE, FALSE); ++ kalMemFree(rCmdGscnParamp, VIR_MEM_TYPE, sizeof(CMD_GSCN_REQ_T)); ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine PNO Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineNLOtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prNewCmdNloReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prNewCmdNloReq) { ++ prCmdPscnParam->fgNLOScnEnable = TRUE; ++ memcpy(&prCmdPscnParam->rCmdNloReq, prNewCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } else if (prScanInfo->prPscnParam->fgNLOScnEnable) { ++ memcpy(&prCmdPscnParam->rCmdNloReq, &prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } else ++ prCmdPscnParam->fgNLOScnEnable = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine Batcht Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineBatchSCNtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ if (prNewCmdBatchReq) { ++ prCmdPscnParam->fgBatchScnEnable = TRUE; ++ memcpy(&prCmdPscnParam->rCmdBatchReq, prNewCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ } else if (prScanInfo->prPscnParam->fgBatchScnEnable) { ++ memcpy(&prCmdPscnParam->rCmdBatchReq, &prScanInfo->prPscnParam->rCurrentCmdBatchReq, ++ sizeof(CMD_BATCH_REQ_T)); ++ } else ++ prCmdPscnParam->fgBatchScnEnable = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnSubCombineGSCNtoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_32 ucPeriodMin = MAX_PERIOD; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prCmdPscnParam->fgGScnEnable = FALSE; ++ ++ DBGLOG(SCN, TRACE, "scnSubCombineGSCNtoPSCN fgGScnParamSet %d fgGScnConfigSet %d\n", ++ prScanInfo->fgGScnParamSet, prScanInfo->fgGScnConfigSet); ++ ++ if (prNewCmdGscnReq) { ++ DBGLOG(SCN, INFO, "setup prNewCmdGscnReq\n"); ++ prScanInfo->fgGScnParamSet = TRUE; ++ memcpy(&prCmdPscnParam->rCmdGscnReq, prNewCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ if (ucPeriodMin > prNewCmdGscnReq->u4BasePeriod) ++ prCmdPscnParam->u4BasePeriod = prNewCmdGscnReq->u4BasePeriod; ++ } else if (prScanInfo->fgGScnParamSet) { ++ DBGLOG(SCN, INFO, "no new prNewCmdGscnReq but there is a old one\n"); ++ memcpy(&prCmdPscnParam->rCmdGscnReq, &prScanInfo->prPscnParam->rCurrentCmdGscnReq, ++ sizeof(CMD_GSCN_REQ_T)); ++ prCmdPscnParam->u4BasePeriod = prScanInfo->prPscnParam->u4BasePeriod; ++ } else ++ prScanInfo->fgGScnParamSet = FALSE; ++ ++ if (prNewCmdGscnConfig) { ++ DBGLOG(SCN, INFO, "set up prNewCmdGscnConfig\n"); ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prScanInfo->fgGScnConfigSet = TRUE; ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = prNewCmdGscnConfig->u4BufferThreshold; ++ prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = (UINT_8) prNewCmdGscnConfig->u4NumScnToCache; ++ } else if (prScanInfo->fgGScnConfigSet) { ++ DBGLOG(SCN, INFO, "no new prNewCmdGscnConfig but there is a old one\n"); ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = ++ prScanInfo->prPscnParam->rCurrentCmdGscnReq.u4BufferThreshold; ++ prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = ++ (UINT_8) prScanInfo->prPscnParam->rCurrentCmdGscnReq.ucNumScnToCache; ++ } else ++ prScanInfo->fgGScnConfigSet = FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID ++scnRemoveFromPSCN(IN P_ADAPTER_T prAdapter, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, ++ IN BOOLEAN fgRemoveGSCNfromPSCN, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ UINT_8 ucPscanAct = DISABLE; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ { ++ DBGLOG(SCN, INFO, "remove NLO or Batch or GSCN from PSCN--->NLO=%d, BSN=%d, GSN=%d\n", ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); ++ ++ if (fgRemoveNLOfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgNLOScnEnable = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdNloReq, sizeof(CMD_NLO_REQ)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); ++ } ++ if (fgRemoveBatchSCNfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgBatchScnEnable = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); ++ } ++ if (fgRemoveGSCNfromPSCN) { ++ memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ prCmdPscnParam->fgGScnEnable = FALSE; ++ prScanInfo->fgGScnParamSet = FALSE; ++ kalMemZero(&prCmdPscnParam->rCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); ++ } ++ ++ if (!fgRemoveNLOfromPSCN && !fgRemoveBatchSCNfromPSCN && !fgRemoveGSCNfromPSCN) { ++ /* prCmdPscnParam->fgIsPeriodicallyScn = FALSE; */ ++ prScanInfo->fgPscnOnnning = FALSE; ++ scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); ++ scnFsmPSCNAction(prAdapter, ucPscanAct); ++ } else { ++ /* prCmdPscnParam->fgIsPeriodicallyScn = TRUE; */ ++ scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); ++ DBGLOG(SCN, INFO, " disable NLO or GSCN or Batch but fgIsPeriodicallyScn = TRUE <-----\n"); ++ } ++ } ++ ++} ++ ++#if 1 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Combine GSCN , Batch, PNO Scan params into PSCAN param ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN ++scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, ++ IN P_CMD_NLO_REQ prNewCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ /* CMD_SET_PSCAN_PARAM rCmdPscnParam; */ ++ P_CMD_SET_PSCAN_PARAM prCmdPscnParam; ++ /* UINT_8 i, j = 0; */ ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ prCmdPscnParam = (P_CMD_SET_PSCAN_PARAM) kalMemAlloc(sizeof(CMD_SET_PSCAN_PARAM), VIR_MEM_TYPE); ++ if (!prCmdPscnParam) { ++ DBGLOG(SCN, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); ++ return -ENOMEM; ++ } ++ kalMemZero(prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ ++ prCmdPscnParam->ucVersion = CURRENT_PSCN_VERSION; ++ ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ scnRemoveFromPSCN(prAdapter, ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN, prCmdPscnParam); ++ } else { ++ DBGLOG(SCN, INFO, "combine GSCN or Batch or NLO to PSCN --->\n"); ++ ++ scnSubCombineNLOtoPSCN(prAdapter, prNewCmdNloReq, prCmdPscnParam); ++ scnSubCombineBatchSCNtoPSCN(prAdapter, prNewCmdBatchReq, prCmdPscnParam); ++ if (prNewCmdGscnReq) ++ scnSubCombineGSCNtoPSCN(prAdapter, prNewCmdGscnReq, NULL, prCmdPscnParam); ++ if (prNewCmdGscnConfig) ++ scnSubCombineGSCNtoPSCN(prAdapter, NULL, prNewCmdGscnConfig, prCmdPscnParam); ++ /* scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); */ ++ ++#if 0 ++ DBGLOG(SCN, TRACE, "combine GSCN or Batch or NLO to PSCN <--- rCmdPscnParam\n"); ++ DBGLOG(SCN, TRACE, ++ "Period[%u], NumCache[%u], Threshold[%u], NumBuckets[%u],GSCNEn[%d] NLOEn[%d] BatchEn[%d]\n", ++ prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, ++ prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, ++ prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, ++ prCmdPscnParam->fgBatchScnEnable)); ++ ++ for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { ++ DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); ++ DBGLOG(SCN, TRACE, ++ "band[%u], ChnBkt[%u] NumChns[%u], BktFreqMltpl[%u] Flag[%u]\n", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); ++ for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) { ++ DBGLOG(SCN, TRACE, " %d, ", ++ prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); ++ } ++ DBGLOG(SCN, TRACE, "\n"); ++ } ++#endif ++ } ++ ++ memcpy(prScanInfo->prPscnParam, prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); ++ kalMemFree(prCmdPscnParam, VIR_MEM_TYPE, sizeof(CMD_SET_PSCAN_PARAM)); ++ return TRUE; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig) ++{ ++ CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; ++ ++ ASSERT(prAdapter); ++ memcpy(&rCmdGscnScnConfig, prCmdGscnScnConfig, sizeof(CMD_GSCN_SCN_COFIG_T)); ++ DBGLOG(SCN, TRACE, "rCmdGscnScnConfig: u4BufferThreshold; [%d] ucNumApPerScn [%d] ucNumScnToCache [%d]\n", ++ rCmdGscnScnConfig.u4BufferThreshold, ++ rCmdGscnScnConfig.ucNumApPerScn, ++ rCmdGscnScnConfig.u4NumScnToCache); ++ ++ scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, &rCmdGscnScnConfig, FALSE, FALSE, FALSE, FALSE); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR ++* ++* \param[in] ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd) ++{ ++ CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; ++ P_SCAN_INFO_T prScanInfo; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultCmd, sizeof(CMD_GET_GSCAN_RESULT_T)); ++ DBGLOG(SCN, INFO, "rGetGscnScnResultCmd: ucGetNum [%d] fgFlush [%d]\n", ++ rGetGscnScnResultCmd.u4Num, rGetGscnScnResultCmd.ucFlush); ++ ++ if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_GET_GSCN_SCN_RESULT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_GET_GSCAN_RESULT_T), (PUINT_8) &rGetGscnScnResultCmd, NULL, 0); ++ return TRUE; ++ } ++ /* debug msg, No PSCN, Sched SCAN GSCN ongoing ??? */ ++ return FALSE; ++ ++} ++ ++VOID ++scnPSCNFsm(IN P_ADAPTER_T prAdapter, ++ ENUM_PSCAN_STATE_T eNextPSCNState, ++ IN P_CMD_NLO_REQ prCmdNloReq, ++ IN P_CMD_BATCH_REQ_T prCmdBatchReq, ++ IN P_CMD_GSCN_REQ_T prCmdGscnReq, ++ IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, ++ IN BOOLEAN fgRemoveNLOfromPSCN, ++ IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN) ++{ ++ P_SCAN_INFO_T prScanInfo; ++ BOOLEAN fgTransitionState = FALSE; ++ ++ ASSERT(prAdapter); ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ ++ do { ++ fgTransitionState = FALSE; ++ ++ DBGLOG(SCN, STATE, "eCurrentPSCNState=%d, eNextPSCNState=%d\n", ++ prScanInfo->eCurrentPSCNState, eNextPSCNState); ++ ++ switch (prScanInfo->eCurrentPSCNState) { ++ case PSCN_IDLE: ++ if (eNextPSCNState == PSCN_RESET) { ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ DBGLOG(SCN, TRACE, "Unexpected remove NLO/BATCH/GSCN request\n"); ++ eNextPSCNState = PSCN_IDLE; ++ break; ++ } ++ ++ if (prCmdNloReq || prCmdBatchReq) { ++ DBGLOG(SCN, TRACE, "PSCN_IDLE->PSCN_RESET,.... scnFsmPSCNActionDISABLE\n"); ++ /*TBD check PSCAN is ongoing */ ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ } else if (eNextPSCNState == PSCN_SCANNING) { ++ if (fgEnableGSCN) { ++ if (prScanInfo->fgPscnOnnning) ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ if (prScanInfo->fgGScnParamSet) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_IDLE->PSCN_SCANNING,.... scnFsmPSCNActionENABLE\n"); ++ prScanInfo->prPscnParam->fgGScnEnable = TRUE; ++ scnFsmPSCNSetParam(prAdapter, ++ (P_CMD_SET_PSCAN_PARAM)prScanInfo->prPscnParam); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ eNextPSCNState = PSCN_SCANNING; ++ } ++ } ++ } ++ break; ++ ++ case PSCN_RESET: ++ scnCombineParamsIntoPSCN(prAdapter, ++ prCmdNloReq, ++ prCmdBatchReq, ++ prCmdGscnReq, ++ prNewCmdGscnConfig, ++ fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); ++ ++ if (!prScanInfo->prPscnParam->fgNLOScnEnable && !prScanInfo->prPscnParam->fgBatchScnEnable ++ && !prScanInfo->prPscnParam->fgGScnEnable) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_RESET->PSCN_IDLE,.... fgNLOScnEnable/fgBatchScnEnable/fgGScnEnable false\n"); ++ eNextPSCNState = PSCN_IDLE; ++ } else { ++ if (prScanInfo->prPscnParam->fgNLOScnEnable ++ || prScanInfo->prPscnParam->fgBatchScnEnable) { ++ scnFsmPSCNSetParam(prAdapter, (P_CMD_SET_PSCAN_PARAM) prScanInfo->prPscnParam); ++ scnFsmPSCNAction(prAdapter, ENABLE); ++ eNextPSCNState = PSCN_SCANNING; ++ DBGLOG(SCN, TRACE, ++ "PSCN_RESET->PSCN_SCANNING,.... fgNLOScnEnable/fgBatchScnEnable ENABLE\n"); ++ } ++ } ++ break; ++ ++ case PSCN_SCANNING: ++ if (eNextPSCNState == PSCN_RESET) { ++ if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_RESET,.... fgRemoveNLOfromPSCN/fgRemoveBatchSCNfromPSCN/fgRemoveGSCNfromPSCN\n"); ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ if (prCmdNloReq || prCmdBatchReq || prCmdGscnReq || prNewCmdGscnConfig) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_RESET,.... prCmdNloReq/prCmdBatchReq/prCmdGscnReq/prNewCmdGscnConfig\n"); ++ scnFsmPSCNAction(prAdapter, DISABLE); ++ break; ++ } ++ ++ } else if (eNextPSCNState == PSCN_SCANNING) { ++ if (fgEnableGSCN) { ++ if (prScanInfo->prPscnParam->fgGScnEnable && (!prScanInfo->fgPscnOnnning)) { ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); ++ /* scnFsmPSCNAction(prAdapter, ENABLE); */ ++ eNextPSCNState = PSCN_SCANNING; ++ } else { ++ ++ DBGLOG(SCN, TRACE, ++ "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); ++ } ++ } ++ } ++ eNextPSCNState = PSCN_SCANNING; ++ break; ++ ++ default: ++ DBGLOG(SCN, WARN, "Unexpected state\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ DBGLOG(SCN, STATE, "eCurrentState %d , eNextPSCNState %d\n", ++ prScanInfo->eCurrentPSCNState, eNextPSCNState); ++ if (prScanInfo->eCurrentPSCNState != eNextPSCNState) ++ fgTransitionState = TRUE; ++ ++ prScanInfo->eCurrentPSCNState = eNextPSCNState; ++ } while (fgTransitionState); ++ ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c +new file mode 100644 +index 000000000000..29eb8d4e7d92 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c +@@ -0,0 +1,1112 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/sec_fsm.c#1 ++*/ ++ ++/*! \file "sec_fsm.c" ++ \brief This is the file implement security check state machine. ++ ++ In security module, do the port control check after success join to an AP, ++ and the path to NORMAL TR, the state machine handle these state transition. ++*/ ++ ++/* ++** Log: sec_fsm.c ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Adjust code for DBG and CONFIG_XLOG. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error ++ * fixed the kclocwork error. ++ * ++ * 01 26 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * . ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Fix Compile Error when DBG is disabled. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 19 2010 wh.su ++ * NULL ++ * adding the tx pkt call back handle for countermeasure. ++ * ++ * 07 19 2010 wh.su ++ * ++ * fixed the compilng error at debug mode. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * modify some code for concurrent network. ++ * ++ * 06 19 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * consdier the concurrent network setting. ++ * ++ * 05 28 2010 wh.su ++ * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing ++ * fixed the ad-hoc wpa-none send non-encrypted frame issue. ++ * ++ * 05 24 2010 kevin.huang ++ * [BORA00000794][WIFISYS][New Feature]Power Management Support ++ * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. ++ * ++ * 04 24 2010 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW ++ * ++ * 04 13 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the Klocwork error and refine the class error message. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * Fixed the pre-authentication timer not correctly init issue, ++ * and modify the security related callback function prototype. ++ * ++ * 03 01 2010 wh.su ++ * [BORA00000605][WIFISYS] Phase3 Integration ++ * Refine the variable and parameter for security. ++ * ++ * 01 27 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * add and fixed some security function. ++ * ++ * 01 13 2010 wh.su ++ * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code ++ * fixed the compiling warning ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine some code ++ * ++ * Dec 4 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * refine the code ++ * ++ * Dec 1 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * code refine ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the function name ++ * ++ * Nov 19 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adjust the state machine, to meet the firmware security design v1.1 ++ * ++ * Nov 18 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_RSN_MIGRATION ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if DBG ++/*lint -save -e64 Type mismatch */ ++static PUINT_8 apucDebugSecState[SEC_STATE_NUM] = { ++ (PUINT_8) DISP_STRING("SEC_STATE_INIT"), ++ (PUINT_8) DISP_STRING("SEC_STATE_INITIATOR_PORT_BLOCKED"), ++ (PUINT_8) DISP_STRING("SEC_STATE_RESPONDER_PORT_BLOCKED"), ++ (PUINT_8) DISP_STRING("SEC_STATE_CHECK_OK"), ++ (PUINT_8) DISP_STRING("SEC_STATE_SEND_EAPOL"), ++ (PUINT_8) DISP_STRING("SEC_STATE_SEND_DEAUTH"), ++ (PUINT_8) DISP_STRING("SEC_STATE_COUNTERMEASURE"), ++}; ++ ++/*lint -restore */ ++#endif /* DBG */ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do initialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the STA record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++#if 1 /* MT6620 */ ++ /* At MT5921, is ok, but at MT6620, firmware base ASIC, the firmware */ ++ /* will lost these data, thus, driver have to keep the wep material and */ ++ /* setting to firmware while awake from D3. */ ++#endif ++ ++ prSecInfo->eCurrentState = SEC_STATE_INIT; ++ ++ prSecInfo->fg2nd1xSend = FALSE; ++ prSecInfo->fgKeyStored = FALSE; ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ prAisSpecBssInfo->u4RsnaLastMICFailTime = 0; ++ prAisSpecBssInfo->fgCheckEAPoLTxDone = FALSE; ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEapolTxTimeout, (ULONG) prSta); ++ ++ cnmTimerInitTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEndOfCounterMeasure, (ULONG) prSta); ++ ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do uninitialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the STA record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID /* whsu:Todo: */ ++secFsmUnInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++ prSecInfo->fg2nd1xSend = FALSE; ++ prSecInfo->fgKeyStored = FALSE; ++ ++ /* nicPrivacyRemoveWlanTable(prSta->ucWTEntry); */ ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); ++ cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* STANDBY to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INIT to INITIATOR_PORT_BLOCKED. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_INITIATOR_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INIT to RESPONDER_PORT_BLOCKED. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INIT_to_RESPONDER_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* INITIATOR_PORT_BLOCKED to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_INITIATOR_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* RESPONDER_PORT_BLOCKED to CHECK_OK. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_RESPONDER_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ secSetPortBlocked(prAdapter, prSta, FALSE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* CHECK_OK to SEND_EAPOL ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_CHECK_OK_to_SEND_EAPOL(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(prSta); ++ ++ prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ ASSERT(prAisBssInfo); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prAisBssInfo->fgCheckEAPoLTxDone = TRUE; ++ ++ /* cnmTimerStartTimer(prAdapter, */ ++ /* &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer, */ ++ /* SEC_TO_MSEC(EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC)); */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_EAPOL to SEND_DEAUTH. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_SEND_EAPOL_to_SEND_DEAUTH(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Compose deauth frame to AP, a call back function for tx done */ ++ if (authSendDeauthFrame(prAdapter, ++ prSta, ++ (P_SW_RFB_T) NULL, ++ REASON_CODE_MIC_FAILURE, ++ (PFN_TX_DONE_HANDLER) secFsmEventDeauthTxDone) != WLAN_STATUS_SUCCESS) { ++ ASSERT(FALSE); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_DEAUTH to COUNTERMEASURE. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_SEND_DEAUTH_to_COUNTERMEASURE(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ /* Start the 60 sec timer */ ++ cnmTimerStartTimer(prAdapter, ++ &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, ++ SEC_TO_MSEC(COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do action part while in STATE transition of ++* SEND_DEAUTH to COUNTERMEASURE. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline VOID secFsmTrans_COUNTERMEASURE_to_INIT(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ ++ /* Clear the counter measure flag */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The Core FSM engine of security module. ++* ++* \param[in] prSta Pointer to the Sta record ++* \param[in] eNextState Enum value of next sec STATE ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmSteps(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN ENUM_SEC_STATE_T eNextState) ++{ ++ P_SEC_INFO_T prSecInfo; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ ASSERT(prSecInfo); ++ ++ DEBUGFUNC("secFsmSteps"); ++ do { ++ /* Do entering Next State */ ++ prSecInfo->ePreviousState = prSecInfo->eCurrentState; ++ ++ /* Do entering Next State */ ++#if DBG ++ DBGLOG(RSN, STATE, "\n %pM TRANSITION: [%s] -> [%s]\n\n", ++ prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState], apucDebugSecState[eNextState]); ++#else ++ DBGLOG(RSN, STATE, "\n %pM [%d] TRANSITION: [%d] -> [%d]\n\n", ++ prSta->aucMacAddr, DBG_RSN_IDX, prSecInfo->eCurrentState, eNextState); ++#endif ++ prSecInfo->eCurrentState = eNextState; ++ ++ fgIsTransition = (BOOLEAN) FALSE; ++#if 0 ++ /* Do tasks of the State that we just entered */ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INIT: ++ break; ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ break; ++ case SEC_STATE_RESPONDER_PORT_BLOCKED: ++ break; ++ case SEC_STATE_CHECK_OK: ++ break; ++ case SEC_STATE_SEND_EAPOL: ++ break; ++ case SEC_STATE_SEND_DEAUTH: ++ break; ++ case SEC_STATE_COUNTERMEASURE: ++ break; ++ default: ++ ASSERT(0); /* Make sure we have handle all STATEs */ ++ break; ++ } ++#endif ++ } while (fgIsTransition); ++ ++ return; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do initialization of Security FSM and all variables in ++* SEC_INFO_T. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ENUM_SEC_STATE_T eNextState; ++ ++ DBGLOG(RSN, TRACE, "secFsmRunEventStart\n"); ++ ++ ASSERT(prSta); ++ ++ if (!prSta) ++ return; ++ ++ if (!IS_STA_IN_AIS(prSta)) ++ return; ++ ++ DBGLOG(RSN, TRACE, "secFsmRunEventStart for sta %pM network %d\n", ++ prSta->aucMacAddr, prSta->ucNetTypeIndex); ++ ++ prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++ secSetPortBlocked(prAdapter, prSta, TRUE); ++ ++ /* prSta->fgTransmitKeyExist = FALSE; */ ++ /* whsu:: nicPrivacySetStaDefaultWTIdx(prSta); */ ++ ++#if 1 /* Since the 1x and key can set to firmware in order, always enter the check ok state */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); ++#else ++ if (IS_STA_IN_AIS(prSta->eStaType)) { ++ if (secRsnKeyHandshakeEnabled(prAdapter) == TRUE ++#if CFG_SUPPORT_WAPI ++ || (prAdapter->rWifiVar.rConnSettings.fgWapiMode) ++#endif ++ ) { ++ prSta->fgTransmitKeyExist = FALSE; ++ /* nicPrivacyInitialize(prSta->ucNetTypeIndex); */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); ++ } else { ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT || CFG_ENABLE_BT_OVER_WIFI ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_BT_OVER_WIFI ++ else if ((prSta->eStaType == STA_TYPE_BOW_CLIENT) || (prSta->eStaType == STA_TYPE_P2P_GC)) { ++#elif CFG_ENABLE_WIFI_DIRECT ++ else if (prSta->eStaType == STA_TYPE_P2P_GC) { ++#elif CFG_ENABLE_BT_OVER_WIFI ++ else if (prSta->eStaType == STA_TYPE_BOW_CLIENT) { ++#endif ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, RESPONDER_PORT_BLOCKED); ++ } ++#endif ++ else ++ SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); ++#endif ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++} /* secFsmRunEventStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function called by reset procedure to force the sec fsm enter ++* idle state ++* ++* \param[in] ucNetTypeIdx The Specific Network type index ++* \param[in] prSta Pointer to the Sta record ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ++ DBGLOG(RSN, TRACE, "secFsmEventAbort for sta %pM network %d\n", ++ prSta->aucMacAddr, prSta->ucNetTypeIndex); ++ ++ ASSERT(prSta); ++ ++ if (!prSta) ++ return; ++ ++ if (!IS_STA_IN_AIS(prSta)) ++ return; ++ ++ prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; ++ ++ prSta->fgTransmitKeyExist = FALSE; ++ ++ secSetPortBlocked(prAdapter, prSta, TRUE); ++ ++ if (prSecInfo == NULL) ++ return; ++ ++ if (IS_STA_IN_AIS(prSta)) { ++ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; ++ ++ if (prSecInfo->eCurrentState == SEC_STATE_SEND_EAPOL) { ++ if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone == FALSE) { ++ DBGLOG(RSN, TRACE, "EAPOL STATE not match the flag\n"); ++ /* cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar. ++ * rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); */ ++ } ++ } ++ } ++ prSecInfo->eCurrentState = SEC_STATE_INIT; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "2nd EAPoL Tx is sending" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ /* BOOLEAN fgIsTransition = (BOOLEAN)FALSE; */ ++ ++ DEBUGFUNC("secFsmRunEvent2ndEapolTx"); ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ case SEC_STATE_CHECK_OK: ++ prSecInfo->fg2nd1xSend = TRUE; ++ break; ++ default: ++#if DBG ++ DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at [%d]\n", prSecInfo->eCurrentState); ++#endif ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEvent2ndEapolTx */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "4th EAPoL Tx is Tx done" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ P_CMD_802_11_KEY prStoredKey; ++ ++ DEBUGFUNC("secFsmRunEvent4ndEapolTx"); ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ case SEC_STATE_CHECK_OK: ++ prSecInfo->fg2nd1xSend = FALSE; ++ if (prSecInfo->fgKeyStored) { ++ prStoredKey = (P_CMD_802_11_KEY) prSecInfo->aucStoredKey; ++ ++ /* prSta = rxmLookupStaRecIndexFromTA(prStoredKey->aucPeerAddr); */ ++ /* if (nicPrivacySetKeyEntry(prStoredKey, prSta->ucWTEntry) == FALSE) */ ++ /* DBGLOG(RSN, WARN, ("nicPrivacySetKeyEntry() fail,..\n")); */ ++ ++ /* key update */ ++ prSecInfo->fgKeyStored = FALSE; ++ prSta->fgTransmitKeyExist = TRUE; ++ } ++ if (prSecInfo->eCurrentState == SEC_STATE_INITIATOR_PORT_BLOCKED) ++ SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); ++ break; ++ default: ++ ++#if DBG ++ DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at [%d]\n", prSecInfo->eCurrentState); ++#endif ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEvent4ndEapolTx */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Pairwise key installed" to SEC FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \retval TRUE The key can be installed to HW ++* \retval FALSE The kay conflict with the current key, abort it ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgStatus = TRUE; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ ASSERT(prSta); ++ ++ prSecInfo = &prSta->rSecInfo; ++ if (prSecInfo == NULL) ++ return TRUE; /* Not PTK */ ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAdd), ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_INIT: ++ /* Legacy wep, wpa-none */ ++ break; ++ ++ case SEC_STATE_INITIATOR_PORT_BLOCKED: ++ if (prSecInfo->fg2nd1xSend) ++ ; ++ else ++ SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); ++ break; ++ ++ case SEC_STATE_RESPONDER_PORT_BLOCKED: ++ SEC_STATE_TRANSITION(prAdapter, prSta, RESPONDER_PORT_BLOCKED, CHECK_OK); ++ break; ++ ++ case SEC_STATE_CHECK_OK: ++ break; ++ ++ default: ++ fgStatus = FALSE; ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return fgStatus; ++ ++} /* end of secFsmRunEventPTKInstalled() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Counter Measure" to SEC FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventStartCounterMeasure"); ++ ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = &prSta->rSecInfo; ++ ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ prAdapter->rWifiVar.rAisSpecificBssInfo.u4RsnaLastMICFailTime = 0; ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_CHECK_OK: ++ { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = TRUE; ++ ++ /* dls port control */ ++ SEC_STATE_TRANSITION(prAdapter, prSta, CHECK_OK, SEND_EAPOL); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Call arbFsmSteps() when we are going to change ARB STATE */ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++ return; ++ ++} /* secFsmRunEventStartCounterMeasure */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "802.1x EAPoL Tx Done" to Sec FSM. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; ++ ++ DEBUGFUNC("secFsmRunEventEapolTxDone"); ++ ++ ASSERT(prStaRec); ++ ++ if (rTxDoneStatus != TX_RESULT_SUCCESS) { ++ DBGLOG(RSN, INFO, "Error EAPoL fram fail to send!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ if (!IS_STA_IN_AIS(prStaRec)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; ++ ++ ASSERT(prAisBssInfo); ++ ++ prSecInfo = &prStaRec->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_EAPOL: ++ if (prAisBssInfo->fgCheckEAPoLTxDone == FALSE) ++ ASSERT(0); ++ ++ prAisBssInfo->fgCheckEAPoLTxDone = FALSE; ++ /* cnmTimerStopTimer(prAdapter, &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer); */ ++ ++ SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_EAPOL, SEND_DEAUTH); ++ break; ++ default: ++ break; ++ } ++ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prStaRec, eNextState); ++ ++ return; ++ ++} /* secFsmRunEventEapolTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will indicate an Event of "Deauth frame Tx Done" to Sec FSM. ++* ++* \param[in] pMsduInfo Pointer to the Msdu Info ++* \param[in] rStatus The Tx done status ++* ++* \return - ++* ++* \note after receive deauth frame, callback function call this ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventDeauthTxDone"); ++ ++ ASSERT(prMsduInfo); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ ASSERT(prStaRec); ++ ++ if (!prStaRec) ++ return; ++ ++ if (!IS_STA_IN_AIS(prStaRec)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = (P_SEC_INFO_T) &prStaRec->rSecInfo; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_DEAUTH: ++ ++ DBGLOG(RSN, TRACE, "Set timer %d\n", COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC); ++ ++ SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_DEAUTH, COUNTERMEASURE); ++ ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++} /* secFsmRunEventDeauthTxDone */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will check the eapol error frame fail to send issue. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("secFsmRunEventEapolTxTimeout"); ++ ++ prStaRec = (P_STA_RECORD_T) ulParm; ++ ++ ASSERT(prStaRec); ++ ++ /* Todo:: How to handle the Eapol Error fail to send case? */ ++ ASSERT(0); ++ ++ return; ++ ++} /* secFsmEventEapolTxTimeout */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will stop the counterMeasure duration. ++* ++* \param[in] prSta Pointer to the Sta record ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, ULONG ulParm) ++{ ++ P_STA_RECORD_T prSta; ++ P_SEC_INFO_T prSecInfo; ++ ENUM_SEC_STATE_T eNextState; ++ BOOLEAN fgIsTransition = (BOOLEAN) FALSE; ++ ++ DEBUGFUNC("secFsmRunEventEndOfCounterMeasure"); ++ ++ prSta = (P_STA_RECORD_T) ulParm; ++ ++ ASSERT(prSta); ++ ++ if (!IS_STA_IN_AIS(prSta)) { ++ DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ prSecInfo = &prSta->rSecInfo; ++ eNextState = prSecInfo->eCurrentState; ++ ++#if DBG ++ DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, ++ apucDebugSecState[prSecInfo->eCurrentState]); ++#else ++ DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); ++#endif ++ ++ switch (prSecInfo->eCurrentState) { ++ case SEC_STATE_SEND_DEAUTH: ++ { ++ prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = FALSE; ++ ++ SEC_STATE_TRANSITION(prAdapter, prSta, COUNTERMEASURE, INIT); ++ } ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ /* Call arbFsmSteps() when we are going to change ARB STATE */ ++ if (prSecInfo->eCurrentState != eNextState) ++ secFsmSteps(prAdapter, prSta, eNextState); ++ ++} /* end of secFsmRunEventEndOfCounterMeasure */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c +new file mode 100644 +index 000000000000..ab3fcc028375 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c +@@ -0,0 +1,1342 @@ ++/* ++** Id: stats.c#1 ++*/ ++ ++/*! \file stats.c ++ \brief This file includes statistics support. ++*/ ++ ++/* ++** Log: stats.c ++ * ++ * 07 17 2014 samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++#include "precomp.h" ++ ++enum EVENT_TYPE { ++ EVENT_RX, ++ EVENT_TX, ++ EVENT_TX_DONE ++}; ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++static WLAN_STATUS ++statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++UINT_64 u8DrvOwnStart, u8DrvOwnEnd; ++UINT32 u4DrvOwnMax = 0; ++#define CFG_USER_LOAD 0 ++static UINT_16 su2TxDoneCfg = CFG_DHCP | CFG_ICMP | CFG_EAPOL; ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display all environment log. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4NumOfInfo, u4InfoId; ++ UINT32 u4RxErrBitmap; ++ STATS_INFO_ENV_T *prInfo; ++ UINT32 u4Total, u4RateId; ++ ++/* ++[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 ++[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) ++ TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, ++ bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) ++ RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) ++ BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) ++ OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) ++ ERR (1st: total number of tx err, 2nd ~ 7st: total number of ++ WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, ++ WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) ++ TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) ++ RX (1st: latest RCPI, 2nd: chan num) ++ BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) ++ OK (number of rx packets without error, number of rx packets to OS) ++ ERR (number of rx packets with error) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ CCK MODE (1 2 5.5 11M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) ++ MIXED MODE (number of rx packets with MCS0 ~ MCS15) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) ++ delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) ++ delay from MAC start TX to MAC TX done ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) ++ delay from HIF to MAC TX done (min, avg, max_system time for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) ++ delay from driver to MAC TX done (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) ++ delay from MAC to HIF (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) ++ delay from HIF to Driver OS (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) ++ delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) ++ delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) ++ delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) ++ Channel idle time, scan count, channel change count, empty tx quota count, ++ power save change count from active to PS, maximum delay from PS to active ++*/ ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ /*prInfo = &rStatsInfoEnv;*/ ++ prInfo = kalMemAlloc(sizeof(STATS_INFO_ENV_T), VIR_MEM_TYPE); ++ if (prInfo == NULL) { ++ DBGLOG(RX, INFO, "prInfo alloc fail"); ++ return; ++ } ++ ++ kalMemZero(prInfo, sizeof(STATS_INFO_ENV_T)); ++ ++ if (u4InBufLen > sizeof(STATS_INFO_ENV_T)) ++ u4InBufLen = sizeof(STATS_INFO_ENV_T); ++ ++ /* parse */ ++ u4NumOfInfo = *(UINT32 *) prInBuf; ++ u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); ++ ++ /* print */ ++ for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { ++ /* ++ use u4InBufLen, not sizeof(rStatsInfoEnv) ++ because the firmware version maybe not equal to driver version ++ */ ++ kalMemCopy(prInfo, prInBuf + 8, u4InBufLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prInfo->ucStaRecIdx); ++ if (prStaRec == NULL) ++ continue; ++ ++ DBGLOG(RX, INFO, " Display stats for [%pM]: %uB\n", ++ prStaRec->aucMacAddr, (UINT32) sizeof(STATS_INFO_ENV_T)); ++ ++ if (prStaRec->ucStatsGenDisplayCnt++ > 10) { ++ /* display general statistics information every 10 * (5 or 10s) */ ++ DBGLOG(RX, INFO, " TBA(0x%x %u) RBA(0x%x %u)\n", ++ prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, ++ prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize); ++ prStaRec->ucStatsGenDisplayCnt = 0; ++ } ++ ++ if (prInfo->u4TxDataCntErr == 0) { ++ DBGLOG(RX, INFO, " TOS(%u) OK(%u %u)\n", ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK); ++ } else { ++ DBGLOG(RX, INFO, " TOS(%u) OK(%u %u) ERR(%u)\n", ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, prInfo->u4TxDataCntErr); ++ DBGLOG(RX, INFO, " ERR type(%u %u %u %u %u %u)\n", ++ prInfo->u4TxDataCntErrType[0], prInfo->u4TxDataCntErrType[1], ++ prInfo->u4TxDataCntErrType[2], prInfo->u4TxDataCntErrType[3], ++ prInfo->u4TxDataCntErrType[4], prInfo->u4TxDataCntErrType[5]); ++ } ++ ++ for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4TxRateCntNonHT[u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " non-HT TRATE (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], ++ prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], ++ prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], ++ prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], ++ prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], ++ prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], ++ prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], ++ prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15]); ++ } ++ if (prInfo->u4TxRateCntNonHT[0] > 0) { ++ DBGLOG(RX, INFO, " HT TRATE (1M %u) (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); ++ } else { ++ DBGLOG(RX, INFO, " HT TRATE (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); ++ } ++ ++ if ((prStaRec->u4RxReorderFallAheadCnt != 0) || ++ (prStaRec->u4RxReorderFallBehindCnt != 0) || (prStaRec->u4RxReorderHoleCnt != 0)) { ++ DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", ++ prStaRec->u4RxReorderFallAheadCnt, ++ prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); ++ } ++ ++ if (prInfo->u4RxDataCntErr == 0) { ++ DBGLOG(RX, INFO, " ROK(%u %u)\n", ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt); ++ } else { ++ DBGLOG(RX, INFO, " ROK(%u %u) ERR(%u)\n", ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, ++ prInfo->u4RxDataCntErr); ++ } ++ ++ for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[0][u4RateId] + prInfo->u4RxRateRetryCnt[0][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[0][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, ++ " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], ++ prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15]); ++ } else { ++ DBGLOG(RX, INFO, " RCCK (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateCnt[0][15]); ++ } ++ } else { ++ if ((prInfo->u4RxRateCnt[0][0] + prInfo->u4RxRateRetryCnt[0][0]) > 0) { ++ DBGLOG(RX, INFO, " RCCK (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0]); ++ } ++ } ++ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[1][u4RateId] + prInfo->u4RxRateRetryCnt[1][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[1][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, ++ " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], ++ prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15]); ++ } else { ++ DBGLOG(RX, INFO, " ROFDM (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateCnt[1][15]); ++ } ++ } ++ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateCnt[2][u4RateId] + prInfo->u4RxRateRetryCnt[2][u4RateId]; ++ if (u4Total > 0) { ++ for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) ++ u4Total += prInfo->u4RxRateRetryCnt[2][u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " RHT\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], ++ prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7]); ++ } else { ++ DBGLOG(RX, INFO, " RHT (%u %u %u %u %u %u %u %u)\n", ++ prInfo->u4RxRateCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateCnt[2][7]); ++ } ++ } ++ ++ /* RX drop counts */ ++ for (u4RateId = 0, u4Total = 0; u4RateId < 20; u4RateId++) ++ u4Total += prInfo->u4NumOfRxDrop[u4RateId]; ++ if (u4Total > 0) { ++ DBGLOG(RX, INFO, " RX Drop Count: (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n" ++ " (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", ++ prInfo->u4NumOfRxDrop[0], prInfo->u4NumOfRxDrop[1], ++ prInfo->u4NumOfRxDrop[2], prInfo->u4NumOfRxDrop[3], ++ prInfo->u4NumOfRxDrop[4], prInfo->u4NumOfRxDrop[5], ++ prInfo->u4NumOfRxDrop[6], prInfo->u4NumOfRxDrop[7], ++ prInfo->u4NumOfRxDrop[8], prInfo->u4NumOfRxDrop[9], ++ prInfo->u4NumOfRxDrop[10], prInfo->u4NumOfRxDrop[11], ++ prInfo->u4NumOfRxDrop[12], prInfo->u4NumOfRxDrop[13], ++ prInfo->u4NumOfRxDrop[14], prInfo->u4NumOfRxDrop[15], ++ prInfo->u4NumOfRxDrop[16], prInfo->u4NumOfRxDrop[17], ++ prInfo->u4NumOfRxDrop[18], prInfo->u4NumOfRxDrop[19]); ++ } ++ ++ /* delay from HIF RX to HIF RX Done */ ++ if (((prInfo->u4StayIntMinHR2HRD[1] + prInfo->u4StayIntAvgHR2HRD[1] + ++ prInfo->u4StayIntMaxHR2HRD[1]) > 0) || ++ ((prInfo->u4StayIntMinHR2HRD[2] + prInfo->u4StayIntAvgHR2HRD[2] + ++ prInfo->u4StayIntMaxHR2HRD[2]) > 0)) { ++ DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], ++ prInfo->u4StayIntMaxHR2HRD[0], ++ prInfo->u4StayIntMinHR2HRD[1], prInfo->u4StayIntAvgHR2HRD[1], ++ prInfo->u4StayIntMaxHR2HRD[1], ++ prInfo->u4StayIntMinHR2HRD[2], prInfo->u4StayIntAvgHR2HRD[2], ++ prInfo->u4StayIntMaxHR2HRD[2]); ++ } else { ++ DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u)\n", ++ prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], ++ prInfo->u4StayIntMaxHR2HRD[0]); ++ } ++ ++ /* others */ ++ DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%x)\n", ++ prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, ++ prInfo->u4NumOfChanChange, prInfo->u4CurrChnlInfo); ++#if CFG_SUPPORT_THERMO_THROTTLING ++ prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; ++#endif ++ /* reset */ ++ kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); ++ kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); ++ kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); ++ prStaRec->u4StatsRxPassToOsCnt = 0; ++ prStaRec->u4RxReorderFallAheadCnt = 0; ++ prStaRec->u4RxReorderFallBehindCnt = 0; ++ prStaRec->u4RxReorderHoleCnt = 0; ++ } ++ ++ STATS_DRIVER_OWN_RESET(); ++ kalMemFree(prInfo, VIR_MEM_TYPE, sizeof(STATS_INFO_ENV_T)); ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display all environment log. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4NumOfInfo, u4InfoId; ++ UINT32 u4RxErrBitmap; ++ STATS_INFO_ENV_T rStatsInfoEnv, *prInfo; ++ ++/* ++[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event ++[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 ++[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) ++ TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, ++ bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) ++ RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) ++ BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) ++ OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) ++ ERR (1st: total number of tx err, 2nd ~ 7st: total number of ++ WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, ++ WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) ++ TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) ++ RX (1st: latest RCPI, 2nd: chan num) ++ BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) ++ OK (number of rx packets without error, number of rx packets to OS) ++ ERR (number of rx packets with error) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ CCK MODE (1 2 5.5 11M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ++ OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) ++[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) ++ MIXED MODE (number of rx packets with MCS0 ~ MCS15) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) ++ delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) ++ delay from MAC start TX to MAC TX done ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) ++ delay from HIF to MAC TX done (min, avg, max_system time for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) ++ delay from driver to MAC TX done (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) ++ delay from MAC to HIF (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) ++ delay from HIF to Driver OS (min, avg, max for 500B) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) ++ delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) ++ delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) ++ delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) ++ ++[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) ++ Channel idle time, scan count, channel change count, empty tx quota count, ++ power save change count from active to PS, maximum delay from PS to active ++*/ ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ prInfo = &rStatsInfoEnv; ++ kalMemZero(&rStatsInfoEnv, sizeof(rStatsInfoEnv)); ++ ++ if (u4InBufLen > sizeof(rStatsInfoEnv)) ++ u4InBufLen = sizeof(rStatsInfoEnv); ++ ++ /* parse */ ++ u4NumOfInfo = *(UINT32 *) prInBuf; ++ u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); ++ ++ /* print */ ++ for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { ++ /* ++ use u4InBufLen, not sizeof(rStatsInfoEnv) ++ because the firmware version maybe not equal to driver version ++ */ ++ kalMemCopy(&rStatsInfoEnv, prInBuf + 8, u4InBufLen); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, rStatsInfoEnv.ucStaRecIdx); ++ if (prStaRec == NULL) ++ continue; ++ ++ DBGLOG(RX, INFO, " Display stats V%d.%d for [%pM]: %uB %ums\n", ++ prInfo->ucFwVer[0], prInfo->ucFwVer[1], ++ (prStaRec->aucMacAddr), (UINT32) sizeof(STATS_INFO_ENV_T), ++ prInfo->u4ReportSysTime); ++ DBGLOG(RX, INFO, "TPAM(0x%x)RTS(%u %u)BA(0x%x %u)OS(%u)OK(%u %u)ERR(%u %u %u %u %u %u %u)\n", ++ prInfo->ucTxParam, ++ prInfo->fgTxIsRtsUsed, prInfo->fgTxIsRtsEverUsed, ++ prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, ++ (UINT32) prGlueInfo->rNetDevStats.tx_packets, ++ prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, ++ prInfo->u4TxDataCntErr, prInfo->u4TxDataCntErrType[0], ++ prInfo->u4TxDataCntErrType[1], prInfo->u4TxDataCntErrType[2], ++ prInfo->u4TxDataCntErrType[3], prInfo->u4TxDataCntErrType[4], ++ prInfo->u4TxDataCntErrType[5])); ++ ++ DBGLOG(RX, INFO, "TRATE(%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", ++ prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], ++ prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], ++ prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], ++ prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], ++ prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], ++ prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], ++ prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], ++ prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15], ++ prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], ++ prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], ++ prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], ++ prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7])); ++ ++ DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", ++ prStaRec->u4RxReorderFallAheadCnt, ++ prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); ++ ++ DBGLOG(RX, INFO, " RX(%u %u %u) BA(0x%x %u) OK(%u %u) ERR(%u)\n", ++ prInfo->ucRcvRcpi, prInfo->ucHwChanNum, prInfo->fgRxIsShortGI, ++ prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize, ++ prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, prInfo->u4RxDataCntErr); ++ ++ DBGLOG(RX, INFO, " RX Free MAC DESC(%u %u %u %u %u %u) Free HIF DESC(%u %u %u %u %u %u)\n", ++ prInfo->u4RxMacFreeDescCnt[0], prInfo->u4RxMacFreeDescCnt[1], ++ prInfo->u4RxMacFreeDescCnt[2], prInfo->u4RxMacFreeDescCnt[3], ++ prInfo->u4RxMacFreeDescCnt[4], prInfo->u4RxMacFreeDescCnt[5], ++ prInfo->u4RxHifFreeDescCnt[0], prInfo->u4RxHifFreeDescCnt[1], ++ prInfo->u4RxHifFreeDescCnt[2], prInfo->u4RxHifFreeDescCnt[3], ++ prInfo->u4RxHifFreeDescCnt[4], prInfo->u4RxHifFreeDescCnt[5])); ++ ++ DBGLOG(RX, INFO, " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], ++ prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], ++ prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], ++ prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], ++ prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], ++ prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], ++ prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], ++ prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], ++ prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], ++ prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], ++ prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], ++ prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], ++ prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], ++ prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], ++ prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], ++ prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15])); ++ DBGLOG(RX, INFO, " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], ++ prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], ++ prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], ++ prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], ++ prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], ++ prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], ++ prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], ++ prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], ++ prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], ++ prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], ++ prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], ++ prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], ++ prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], ++ prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], ++ prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], ++ prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15])); ++ DBGLOG(RX, INFO, " RHT (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" ++ "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", ++ prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], ++ prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], ++ prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], ++ prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], ++ prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], ++ prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], ++ prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], ++ prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7], ++ prInfo->u4RxRateCnt[2][8], prInfo->u4RxRateRetryCnt[2][8], ++ prInfo->u4RxRateCnt[2][9], prInfo->u4RxRateRetryCnt[2][9], ++ prInfo->u4RxRateCnt[2][10], prInfo->u4RxRateRetryCnt[2][10], ++ prInfo->u4RxRateCnt[2][11], prInfo->u4RxRateRetryCnt[2][11], ++ prInfo->u4RxRateCnt[2][12], prInfo->u4RxRateRetryCnt[2][12], ++ prInfo->u4RxRateCnt[2][13], prInfo->u4RxRateRetryCnt[2][13], ++ prInfo->u4RxRateCnt[2][14], prInfo->u4RxRateRetryCnt[2][14], ++ prInfo->u4RxRateCnt[2][15], prInfo->u4RxRateRetryCnt[2][15])); ++ ++ /* delay from HIF to MAC */ ++ DBGLOG(RX, INFO, " StayIntH2M us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinH2M[0], prInfo->u4StayIntAvgH2M[0], ++ prInfo->u4StayIntMaxH2M[0], ++ prInfo->u4StayIntMinH2M[1], prInfo->u4StayIntAvgH2M[1], ++ prInfo->u4StayIntMaxH2M[1], ++ prInfo->u4StayIntMinH2M[2], prInfo->u4StayIntAvgH2M[2], ++ prInfo->u4StayIntMaxH2M[2])); ++ /* delay from MAC to TXDONE */ ++ DBGLOG(RX, INFO, " AirTime us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4AirDelayMin[0] << 5, prInfo->u4AirDelayAvg[0] << 5, ++ prInfo->u4AirDelayMax[0] << 5, ++ prInfo->u4AirDelayMin[1] << 5, prInfo->u4AirDelayAvg[1] << 5, ++ prInfo->u4AirDelayMax[1] << 5, ++ prInfo->u4TxDataCntAll, (prInfo->u4AirDelayAvg[2] << 5) / (prInfo->u4TxDataCntAll), ++ (prInfo->u4AirDelayAvg[2] << 5) / 400000)); ++ prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; ++ /* delay from HIF to TXDONE */ ++ DBGLOG(RX, INFO, " StayInt us (%u %u %u_%u) (%u %u %u_%u) (%u %u %u_%u)\n", ++ prInfo->u4StayIntMin[0], prInfo->u4StayIntAvg[0], ++ prInfo->u4StayIntMax[0], prInfo->u4StayIntMaxSysTime[0], ++ prInfo->u4StayIntMin[1], prInfo->u4StayIntAvg[1], ++ prInfo->u4StayIntMax[1], prInfo->u4StayIntMaxSysTime[1], ++ prInfo->u4StayIntMin[2], prInfo->u4StayIntAvg[2], ++ prInfo->u4StayIntMax[2], prInfo->u4StayIntMaxSysTime[2])); ++ /* delay from Driver to TXDONE */ ++ DBGLOG(RX, INFO, " StayIntD2T us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinD2T[0], prInfo->u4StayIntAvgD2T[0], ++ prInfo->u4StayIntMaxD2T[0], ++ prInfo->u4StayIntMinD2T[1], prInfo->u4StayIntAvgD2T[1], ++ prInfo->u4StayIntMaxD2T[1], ++ prInfo->u4StayIntMinD2T[2], prInfo->u4StayIntAvgD2T[2], ++ prInfo->u4StayIntMaxD2T[2])); ++ ++ /* delay from RXDONE to HIF */ ++ DBGLOG(RX, INFO, " StayIntR_M2H us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prInfo->u4StayIntMinRx[0], prInfo->u4StayIntAvgRx[0], ++ prInfo->u4StayIntMaxRx[0], ++ prInfo->u4StayIntMinRx[1], prInfo->u4StayIntAvgRx[1], ++ prInfo->u4StayIntMaxRx[1], ++ prInfo->u4StayIntMinRx[2], prInfo->u4StayIntAvgRx[2], prInfo->u4StayIntMaxRx[2])); ++ /* delay from HIF to OS */ ++ DBGLOG(RX, INFO, " StayIntR_H2D us (%u %u %u) (%u %u %u) (%u %u %u)\n", ++ prStaRec->u4StayIntMinRx[0], prStaRec->u4StayIntAvgRx[0], ++ prStaRec->u4StayIntMaxRx[0], ++ prStaRec->u4StayIntMinRx[1], prStaRec->u4StayIntAvgRx[1], ++ prStaRec->u4StayIntMaxRx[1], ++ prStaRec->u4StayIntMinRx[2], prStaRec->u4StayIntAvgRx[2], ++ prStaRec->u4StayIntMaxRx[2])); ++ ++ /* count based on delay from OS to HIF */ ++ DBGLOG(RX, INFO, " StayCntD2H unit:%dms (%d %d %d %d)\n", ++ STATS_STAY_INT_D2H_CONST, ++ prInfo->u4StayIntD2HByConst[0], prInfo->u4StayIntD2HByConst[1], ++ prInfo->u4StayIntD2HByConst[2], prInfo->u4StayIntD2HByConst[3]); ++ ++ /* count based on different delay from HIF to TX DONE */ ++ DBGLOG(RX, INFO, " StayCnt unit:%dms (%d %d %d %d)\n", ++ STATS_STAY_INT_CONST, ++ prInfo->u4StayIntByConst[0], prInfo->u4StayIntByConst[1], ++ prInfo->u4StayIntByConst[2], prInfo->u4StayIntByConst[3]); ++ DBGLOG(RX, INFO, " StayCnt (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~:%d)\n", ++ 0, prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntCnt[0], ++ prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntCnt[1], ++ prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntMaxPast * 3 / 4, ++ prInfo->u4StayIntCnt[2], prInfo->u4StayIntMaxPast * 3 / 4, prInfo->u4StayIntMaxPast, ++ prInfo->u4StayIntCnt[3], prInfo->u4StayIntMaxPast, prInfo->u4StayIntCnt[4])); ++ ++ /* channel idle time */ ++ DBGLOG(RX, INFO, " Idle Time (slot): (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", ++ prInfo->au4ChanIdleCnt[0], prInfo->au4ChanIdleCnt[1], ++ prInfo->au4ChanIdleCnt[2], prInfo->au4ChanIdleCnt[3], ++ prInfo->au4ChanIdleCnt[4], prInfo->au4ChanIdleCnt[5], ++ prInfo->au4ChanIdleCnt[6], prInfo->au4ChanIdleCnt[7], ++ prInfo->au4ChanIdleCnt[8], prInfo->au4ChanIdleCnt[9])); ++ ++ /* BT coex */ ++ DBGLOG(RX, INFO, " BT coex (0x%x)\n", prInfo->u4BtContUseTime); ++ ++ /* others */ ++ DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%u) (%u) (%ums) (%uus)\n", ++ prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, ++ prInfo->u4NumOfChanChange, prStaRec->u4NumOfNoTxQuota, ++ prInfo->ucNumOfPsChange, prInfo->u4PsIntMax, u4DrvOwnMax / 1000); ++ ++ /* reset */ ++ kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); ++ kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); ++ kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); ++ prStaRec->u4StatsRxPassToOsCnt = 0; ++ prStaRec->u4RxReorderFallAheadCnt = 0; ++ prStaRec->u4RxReorderFallBehindCnt = 0; ++ prStaRec->u4RxReorderHoleCnt = 0; ++ } ++ ++ STATS_DRIVER_OWN_RESET(); ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to request firmware to feedback statistics. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ STATS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* sanity check */ ++ if (fgIsUnderSuspend == true) ++ return WLAN_STATUS_SUCCESS; /* do not request stats after early suspend */ ++ ++ /* init command buffer */ ++ prCmdContent = (STATS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = STATS_CORE_CMD_ENV_REQUEST; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_STATS, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(STATS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(RX, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return WLAN_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(RX, INFO, "%s cmd ok.\n", __func__); ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle any statistics event. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ UINT32 u4EventId; ++ ++ /* sanity check */ ++/* DBGLOG(RX, INFO, */ ++/* (" %s: Rcv a event\n", __FUNCTION__)); */ ++ ++ if ((prGlueInfo == NULL) || (prInBuf == NULL)) ++ return; /* shall not be here */ ++ ++ /* handle */ ++ u4EventId = *(UINT32 *) prInBuf; ++ u4InBufLen -= 4; ++ ++/* DBGLOG(RX, INFO, */ ++/* (" %s: Rcv a event: %d\n", __FUNCTION__, u4EventId)); */ ++ ++ switch (u4EventId) { ++ case STATS_HOST_EVENT_ENV_REPORT: ++ statsInfoEnvDisplay(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to detect if we can request firmware to feedback statistics. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] ucStaRecIndex The station index ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex) ++{ ++ STA_RECORD_T *prStaRec; ++ OS_SYSTIME rCurTime; ++ STATS_CMD_CORE_T rCmd; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->u4StatsEnvTxCnt++; ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (prStaRec->rStatsEnvTxPeriodLastTime == 0) { ++ prStaRec->rStatsEnvTxLastTime = rCurTime; ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ return; ++ } ++ ++ if (prStaRec->u4StatsEnvTxCnt > STATS_ENV_TX_CNT_REPORT_TRIGGER) { ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxLastTime, ++ SEC_TO_SYSTIME(STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC))) { ++ rCmd.ucStaRecIdx = ucStaRecIndex; ++ statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); ++ ++ prStaRec->rStatsEnvTxLastTime = rCurTime; ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ prStaRec->u4StatsEnvTxCnt = 0; ++ return; ++ } ++ } ++ ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxPeriodLastTime, SEC_TO_SYSTIME(STATS_ENV_TIMEOUT_SEC))) { ++ rCmd.ucStaRecIdx = ucStaRecIndex; ++ statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); ++ ++ prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure ++* \param[in] prSwRfb Pointer to the received packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb) ++{ ++ UINT32 u4LenId; ++ UINT32 u4CurTime, u4DifTime; ++ ++ /* sanity check */ ++ if (prStaRec == NULL) ++ return; ++ ++ /* stats: rx done count */ ++ prStaRec->u4StatsRxPassToOsCnt++; ++ ++ /* get length partition ID */ ++ u4LenId = 0; ++ if (prSwRfb->u2PacketLen < STATS_STAY_INT_BYTE_THRESHOLD) { ++ u4LenId = 0; ++ } else { ++ if ((STATS_STAY_INT_BYTE_THRESHOLD <= prSwRfb->u2PacketLen) && ++ (prSwRfb->u2PacketLen < (STATS_STAY_INT_BYTE_THRESHOLD << 1))) { ++ u4LenId = 1; ++ } else ++ u4LenId = 2; ++ } ++ ++ /* stats: rx delay */ ++ u4CurTime = kalGetTimeTick(); ++ ++ if ((u4CurTime > prSwRfb->rRxTime) && (prSwRfb->rRxTime != 0)) { ++ u4DifTime = u4CurTime - prSwRfb->rRxTime; ++ ++ if (prStaRec->u4StayIntMinRx[u4LenId] == 0) /* impossible */ ++ prStaRec->u4StayIntMinRx[u4LenId] = 0xffffffff; ++ ++ if (u4DifTime > prStaRec->u4StayIntMaxRx[u4LenId]) ++ prStaRec->u4StayIntMaxRx[u4LenId] = u4DifTime; ++ else if (u4DifTime < prStaRec->u4StayIntMinRx[u4LenId]) ++ prStaRec->u4StayIntMinRx[u4LenId] = u4DifTime; ++ ++ prStaRec->u4StayIntAvgRx[u4LenId] += u4DifTime; ++ if (prStaRec->u4StayIntAvgRx[u4LenId] != u4DifTime) ++ prStaRec->u4StayIntAvgRx[u4LenId] >>= 1; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_64 StatsEnvTimeGet(VOID) ++{ ++ /* TODO: use better API to get time to save time, jiffies unit is 10ms, too large */ ++ ++/* struct timeval tv; */ ++ ++/* do_gettimeofday(&tv); */ ++/* return tv.tv_usec + tv.tv_sec * (UINT_64)1000000; */ ++ ++ UINT_64 u8Clk; ++/* UINT32 *pClk = &u8Clk; */ ++ ++ u8Clk = sched_clock(); /* unit: naro seconds */ ++/* printk(" sched_clock() = %x %x %u\n", pClk[0], pClk[1], sizeof(jiffies)); */ ++ ++ return (UINT_64) u8Clk; /* sched_clock *//* jiffies size = 4B */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle rx done. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader) ++{ ++ UINT_64 u8SysTime, u8SysTimeIn; ++ UINT32 u4TimeDiff; ++ ++ u8SysTime = StatsEnvTimeGet(); ++ u8SysTimeIn = GLUE_GET_PKT_XTIME(prMsduInfo->prPacket); ++ ++/* printk(" hif: 0x%x %u %u %u\n", */ ++/* prMsduInfo->prPacket, StatsEnvTimeGet(), u8SysTime, GLUE_GET_PKT_XTIME(prMsduInfo->prPacket)); */ ++ ++ if ((u8SysTimeIn > 0) && (u8SysTime > u8SysTimeIn)) { ++ u8SysTime = u8SysTime - u8SysTimeIn; ++ u4TimeDiff = (UINT32) u8SysTime; ++ u4TimeDiff = u4TimeDiff / 1000; /* ns to us */ ++ ++ /* pass the delay between OS to us and we to HIF */ ++ if (u4TimeDiff > 0xFFFF) ++ *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) 0xFFFF; /* 65535 us */ ++ else ++ *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) u4TimeDiff; ++ ++/* printk(" u4TimeDiff: %u\n", u4TimeDiff); */ ++ } else { ++ prHwTxHeader->aucReserved[0] = 0; ++ prHwTxHeader->aucReserved[1] = 0; ++ } ++} ++ ++static VOID statsParsePktInfo(PUINT_8 pucPkt, UINT_8 status, UINT_8 eventType, P_MSDU_INFO_T prMsduInfo) ++{ ++ /* get ethernet protocol */ ++ UINT_16 u2EtherType = (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ PUINT_8 pucEthBody = &pucPkt[ETH_HLEN]; ++ ++ switch (u2EtherType) { ++ case ETH_P_ARP: ++ { ++ UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; ++ if (eventType == EVENT_TX) ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ if ((su2TxDoneCfg & CFG_ARP) == 0) ++ break; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(RX, INFO, " Arp Req From IP: %d.%d.%d.%d\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(RX, INFO, " Arp Rsp from IP: %d.%d.%d.%d\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ break; ++ case EVENT_TX: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", status, ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", status, ++ pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); ++ break; ++ } ++ break; ++ } ++ case ETH_P_IP: ++ { ++ UINT_8 ucIpProto = pucEthBody[9]; /* IP header without options */ ++ UINT_8 ucIpVersion = (pucEthBody[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ UINT_16 u2IpId = pucEthBody[4]<<8 | pucEthBody[5]; ++ ++ if (ucIpVersion != IPVERSION) ++ break; ++ ++ switch (ucIpProto) { ++ case IP_PRO_ICMP: ++ { ++ /* the number of ICMP packets is seldom so we print log here */ ++ UINT_8 ucIcmpType; ++ UINT_16 u2IcmpId, u2IcmpSeq; ++ PUINT_8 pucIcmp = &pucEthBody[20]; ++ ++ ucIcmpType = pucIcmp[0]; ++ /* don't log network unreachable packet */ ++ if (((su2TxDoneCfg & CFG_ICMP) == 0) || ucIcmpType == 3) ++ break; ++ u2IcmpId = *(UINT_16 *) &pucIcmp[4]; ++ u2IcmpSeq = *(UINT_16 *) &pucIcmp[6]; ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " ICMP: Type %d, Id BE 0x%04x, Seq BE 0x%04x\n", ++ ucIcmpType, u2IcmpId, u2IcmpSeq); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " ICMP: Type %d, Id 0x04%x, Seq BE 0x%04x\n", ++ ucIcmpType, u2IcmpId, u2IcmpSeq); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " Type %d, Id 0x%04x, Seq 0x%04x\n", ++ status, ucIcmpType, u2IcmpId, u2IcmpSeq); ++ break; ++ } ++ break; ++ } ++ case IP_PRO_UDP: ++ { ++ /* the number of DHCP packets is seldom so we print log here */ ++ PUINT_8 pucUdp = &pucEthBody[20]; ++ PUINT_8 pucUdpPayload = &pucUdp[8]; ++ UINT_16 u2UdpDstPort; ++ UINT_16 u2UdpSrcPort; ++ ++ u2UdpDstPort = (pucUdp[2] << 8) | pucUdp[3]; ++ u2UdpSrcPort = (pucUdp[0] << 8) | pucUdp[1]; ++ /* dhcp */ ++ if ((u2UdpDstPort == UDP_PORT_DHCPS) || (u2UdpDstPort == UDP_PORT_DHCPC)) { ++ UINT_32 u4TransID = pucUdpPayload[4]<<24 | pucUdpPayload[5]<<16 | ++ pucUdpPayload[6]<<8 | pucUdpPayload[7]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ u2IpId, pucUdpPayload[0], u4TransID); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ u2IpId, pucUdpPayload[0], u4TransID); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, ++ " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", ++ status, u2IpId, pucUdpPayload[0], u4TransID); ++ break; ++ } ++ } else if (u2UdpDstPort == UDP_PORT_DNS) { /* tx dns */ ++ UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; ++ if (eventType == EVENT_TX) ++ prMsduInfo->fgIsBasicRate = TRUE; ++ ++ if ((su2TxDoneCfg & CFG_DNS) == 0) ++ break; ++ if (eventType == EVENT_TX) { ++ DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ } else if (eventType == EVENT_TX_DONE) ++ DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", ++ status, u2IpId, u2TransId); ++ } else if (u2UdpSrcPort == UDP_PORT_DNS && eventType == EVENT_RX) { /* rx dns */ ++ UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; ++ ++ if ((su2TxDoneCfg & CFG_DNS) == 0) ++ break; ++ DBGLOG(RX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); ++ } else if ((su2TxDoneCfg & CFG_UDP) != 0) { ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " UDP: IPID 0x%04x\n", u2IpId); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", u2IpId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", status, u2IpId); ++ break; ++ } ++ } ++ break; ++ } ++ case IP_PRO_TCP: ++ if ((su2TxDoneCfg & CFG_TCP) == 0) ++ break; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " TCP: IPID 0x%04x\n", u2IpId); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", u2IpId); ++ prMsduInfo->fgNeedTxDoneStatus = TRUE; ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", status, u2IpId); ++ break; ++ } ++ break; ++ } ++ break; ++ } ++ case ETH_P_PRE_1X: ++ DBGLOG(RX, INFO, "pre-1x\n"); ++ case ETH_P_1X: ++ { ++ PUINT_8 pucEapol = pucEthBody; ++ UINT_8 ucEapolType = pucEapol[1]; ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", ++ status, pucEapol[4], pucEapol[5], pucEapol[7]); ++ break; ++ } ++ break; ++ case 1: /* eapol start */ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " EAPOL: start\n"); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " EAPOL: start\n"); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " EAPOL: start\n", status); ++ break; ++ } ++ break; ++ case 3: /* key */ ++ { ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ u2KeyInfo, ++ pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", ++ status, u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], ++ pucEapol[20], pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); ++ break; ++ } ++ ++ break; ++ } ++ } ++ break; ++ } ++ case ETH_WPI_1X: ++ { ++ UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ ++ UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; ++ UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; ++ ++ switch (eventType) { ++ case EVENT_RX: ++ DBGLOG(RX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ break; ++ case EVENT_TX: ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ break; ++ case EVENT_TX_DONE: ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ status, ucSubType, u2Length, u2Seq); ++ break; ++ } ++ break; ++ } ++ } ++} ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display rx packet information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsRxPktInfoDisplay(UINT_8 *pPkt) ++{ ++ statsParsePktInfo(pPkt, 0, EVENT_RX, NULL); ++#if 0 /* carefully! too many ARP */ ++ if (pucIpHdr[0] == 0x00) { /* ARP */ ++ UINT_8 *pucDstIp = (UINT_8 *) pucIpHdr; ++ ++ if (pucDstIp[7] == ARP_PRO_REQ) { ++ DBGLOG(RX, TRACE, " OS rx a arp req from %d.%d.%d.%d\n", ++ pucDstIp[14], pucDstIp[15], pucDstIp[16], pucDstIp[17]); ++ } else if (pucDstIp[7] == ARP_PRO_RSP) { ++ DBGLOG(RX, TRACE, " OS rx a arp rsp from %d.%d.%d.%d\n", ++ pucDstIp[24], pucDstIp[25], pucDstIp[26], pucDstIp[27]); ++ } ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display tx packet information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_16 u2EtherTypeLen; ++ ++ u2EtherTypeLen = (pPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pPkt[ETH_TYPE_LEN_OFFSET + 1]); ++ statsParsePktInfo(pPkt, 0, EVENT_TX, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to handle display tx packet tx done information. ++* ++* \param[in] pPkt Pointer to the packet ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf) ++{ ++ EVENT_TX_DONE_STATUS_T *prTxDone; ++ ++ prTxDone = (EVENT_TX_DONE_STATUS_T *) pucEvtBuf; ++ /* ++ * Why 65 Bytes: ++ * 8B + wlanheader(40B) + hif_tx_header(16B) + 6B + 6B(LLC) - 12B ++ */ ++ statsParsePktInfo(&prTxDone->aucPktBuf[64], prTxDone->ucStatus, EVENT_TX_DONE, NULL); ++} ++ ++VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet) ++{ ++ if (fgSet) ++ su2TxDoneCfg |= u2Cfg; ++ else ++ su2TxDoneCfg &= ~u2Cfg; ++} ++ ++UINT_16 StatsGetCfgTxDone(VOID) ++{ ++ return su2TxDoneCfg; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c +new file mode 100644 +index 000000000000..67eccbda9fa8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c +@@ -0,0 +1,1170 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/swcr.c#1 ++*/ ++ ++/*! \file "swcr.c" ++ \brief ++ ++*/ ++ ++/* ++** Log: swcr.c ++ * ++ * 06 04 2012 tsaiyuan.hsu ++ * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" ++ * resolve build waring for "WNM_UNIT_TEST not defined". ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 22 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * keep debug counter setting after wake up. ++ * ++ * 11 15 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * fix debug counters of rx in driver. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters, eCurPsProf, for PS. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 08 31 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * remove obsolete code. ++ * ++ * 08 15 2011 tsaiyuan.hsu ++ * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver ++ * add swcr in driver reg, 0x9fxx0000, to disable roaming . ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Fix Klockwork warning. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add swcr for test. ++ * ++* ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_SWCR ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if 0 ++SWCR_MOD_MAP_ENTRY_T g_arSwCrAllMaps[] = { ++ {SWCR_MAP_NUM(g_arRlmArSwCrMap), g_arRlmArSwCrMap}, /* 0x00nn */ ++ {0, NULL} ++}; ++#endif ++ ++UINT_32 g_au4SwCr[SWCR_CR_NUM]; /*: 0: command other: data */ ++ ++/* JB mDNS Filter*/ ++UINT_32 g_u4mDNSRXFilter = 0; /* [31] 0: stop 1: start, [3] IPv6 [2] IPv4 */ ++ ++static TIMER_T g_rSwcrDebugTimer; ++static BOOLEAN g_fgSwcrDebugTimer = FALSE; ++static UINT_32 g_u4SwcrDebugCheckTimeout; ++static ENUM_SWCR_DBG_TYPE_T g_ucSwcrDebugCheckType; ++static UINT_32 g_u4SwcrDebugFrameDumpType; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#define TEST_PS 1 ++ ++static const PFN_CMD_RW_T g_arSwCtrlCmd[] = { ++ swCtrlCmdCategory0, ++ swCtrlCmdCategory1 ++#if TEST_PS ++ , testPsCmdCategory0, testPsCmdCategory1 ++#endif ++#if CFG_SUPPORT_802_11V ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) ++ , testWNMCmdCategory0 ++#endif ++#endif ++}; ++ ++const PFN_SWCR_RW_T g_arSwCrModHandle[] = { ++ swCtrlSwCr, ++ NULL ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++enum { ++ SWCTRL_MAGIC, ++ SWCTRL_DEBUG, ++ SWCTRL_WIFI_VAR, ++ SWCTRL_ENABLE_INT, ++ SWCTRL_DISABLE_INT, ++ SWCTRL_TXM_INFO, ++ SWCTRL_RXM_INFO, ++ SWCTRL_DUMP_BSS, ++ SWCTRL_QM_INFO, ++ SWCTRL_DUMP_ALL_QUEUE_LEN, ++ SWCTRL_DUMP_MEM, ++ SWCTRL_TX_CTRL_INFO, ++ SWCTRL_DUMP_QUEUE, ++ SWCTRL_DUMP_QM_DBG_CNT, ++ SWCTRL_QM_DBG_CNT, ++ SWCTRL_RX_PKTS_DUMP, ++ SWCTRL_RX_MDNS_FILTER, ++ SWCTRL_CATA0_INDEX_NUM ++}; ++ ++enum { ++ SWCTRL_STA_INFO, ++ SWCTRL_DUMP_STA, ++ SWCTRL_STA_QUE_INFO, ++ SWCTRL_CATA1_INDEX_NUM ++}; ++ ++/* JB mDNS Filter*/ ++#define RX_MDNS_FILTER_START (1<<31) ++#define RX_MDNS_FILTER_IPV4 (1<<2) ++#define RX_MDNS_FILTER_IPV6 (1<<3) ++typedef enum _ENUM_SWCR_RX_MDNS_FILTER_CMD_T { ++ SWCR_RX_MDNS_FILTER_CMD_STOP = 0, ++ SWCR_RX_MDNS_FILTER_CMD_START, ++ SWCR_RX_MDNS_FILTER_CMD_ADD, ++ SWCR_RX_MDNS_FILTER_CMD_REMOVE, ++ SWCR_RX_MDNS_FILTER_NUM ++} ENUM_SWCR_RX_MDNS_FILTER_CMD_T; ++ ++#if TEST_PS ++enum { ++ TEST_PS_MAGIC, ++ TEST_PS_SETUP_BSS, ++ TEST_PS_ENABLE_BEACON, ++ TEST_PS_TRIGGER_BMC, ++ TEST_PS_SEND_NULL, ++ TEST_PS_BUFFER_BMC, ++ TEST_PS_UPDATE_BEACON, ++ TEST_PS_CATA0_INDEX_NUM ++}; ++ ++enum { ++ TEST_PS_STA_PS, ++ TEST_PS_STA_ENTER_PS, ++ TEST_PS_STA_EXIT_PS, ++ TEST_PS_STA_TRIGGER_PSPOLL, ++ TEST_PS_STA_TRIGGER_FRAME, ++ TEST_PS_CATA1_INDEX_NUM ++}; ++#endif ++ ++#if CFG_SUPPORT_802_11V ++#if WNM_UNIT_TEST ++enum { ++ TEST_WNM_TIMING_MEAS, ++ TEST_WNM_CATA0_INDEX_NUM ++}; ++#endif ++#endif ++ ++#define _SWCTRL_MAGIC 0x66201642 ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++void dumpQueue(P_ADAPTER_T prAdapter) ++{ ++ ++ P_TX_CTRL_T prTxCtrl; ++ P_QUE_MGT_T prQM; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 i; ++ UINT_32 j; ++ ++ DEBUGFUNC("dumpQueue"); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prQM = &prAdapter->rQM; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ for (i = TC0_INDEX; i <= TC5_INDEX; i++) { ++ DBGLOG(SW4, INFO, "TC %u\n", i); ++ DBGLOG(SW4, INFO, "Max %u Free %u\n", ++ prTxCtrl->rTc.aucMaxNumOfBuffer[i], prTxCtrl->rTc.aucFreeBufferCount[i]); ++ ++ DBGLOG(SW4, INFO, "Average %u minReserved %u CurrentTcResource %u GuaranteedTcResource %u\n", ++ QM_GET_TX_QUEUE_LEN(prAdapter, i), ++ prQM->au4MinReservedTcResource[i], ++ prQM->au4CurrentTcResource[i], prQM->au4GuaranteedTcResource[i]); ++ ++ } ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { ++ DBGLOG(SW4, INFO, ++ "TC %u HeadStaIdx %u ForwardCount %u\n", i, prQM->au4HeadStaRecIndex[i], ++ prQM->au4ForwardCount[i]); ++ } ++ ++ DBGLOG(SW4, INFO, "BMC or unknown TxQueue Len %u\n", prQM->arTxQueue[0].u4NumElem); ++ DBGLOG(SW4, INFO, "Pending %d\n", prGlueInfo->i4TxPendingFrameNum); ++ DBGLOG(SW4, INFO, "Pending Security %d\n", prGlueInfo->i4TxPendingSecurityFrameNum); ++#if defined(LINUX) ++ for (i = 0; i < 4; i++) { ++ for (j = 0; j < CFG_MAX_TXQ_NUM; j++) { ++ DBGLOG(SW4, INFO, ++ "Pending Q[%u][%u] %d\n", i, j, prGlueInfo->ai4TxPendingFrameNumPerQueue[i][j]); ++ } ++ } ++#endif ++ ++ DBGLOG(SW4, INFO, " rFreeSwRfbList %u\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " rReceivedRfbList %u\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " rIndicatedRfbList %u\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem); ++ DBGLOG(SW4, INFO, " ucNumIndPacket %u\n", prAdapter->rRxCtrl.ucNumIndPacket); ++ DBGLOG(SW4, INFO, " ucNumRetainedPacket %u\n", prAdapter->rRxCtrl.ucNumRetainedPacket); ++ ++} ++ ++void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) ++{ ++ UINT_8 ucWTEntry; ++ UINT_32 i; ++ P_BSS_INFO_T prBssInfo; ++ ++ DEBUGFUNC("dumpSTA"); ++ ++ ASSERT(prStaRec); ++ ucWTEntry = prStaRec->ucWTEntry; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ DBGLOG(SW4, INFO, "Mac address: %pM Rcpi %u" "\n", prStaRec->aucMacAddr, prStaRec->ucRCPI); ++ ++ DBGLOG(SW4, INFO, "Idx %u Wtbl %u Used %u State %u Bss Phy 0x%x Sta DesiredPhy 0x%x\n", ++ prStaRec->ucIndex, ucWTEntry, ++ prStaRec->fgIsInUse, prStaRec->ucStaState, ++ prBssInfo->ucPhyTypeSet, prStaRec->ucDesiredPhyTypeSet); ++ ++ DBGLOG(SW4, INFO, "Sta Operation 0x%x DesiredNontHtRateSet 0x%x Mcs 0x%x u2HtCapInfo 0x%x\n", ++ prStaRec->u2OperationalRateSet, prStaRec->u2DesiredNonHTRateSet, prStaRec->ucMcsSet, ++ prStaRec->u2HtCapInfo); ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) ++ DBGLOG(SW4, INFO, "TC %u Queue Len %u\n", i, prStaRec->arTxQueue[i].u4NumElem); ++ ++ DBGLOG(SW4, INFO, "BmpDeliveryAC %x\n", prStaRec->ucBmpDeliveryAC); ++ DBGLOG(SW4, INFO, "BmpTriggerAC %x\n", prStaRec->ucBmpTriggerAC); ++ DBGLOG(SW4, INFO, "UapsdSpSupproted %u\n", prStaRec->fgIsUapsdSupported); ++ DBGLOG(SW4, INFO, "IsQoS %u\n", prStaRec->fgIsQoS); ++ DBGLOG(SW4, INFO, "AssocId %u\n", prStaRec->u2AssocId); ++ ++ DBGLOG(SW4, INFO, "fgIsInPS %u\n", prStaRec->fgIsInPS); ++ DBGLOG(SW4, INFO, "ucFreeQuota %u\n", prStaRec->ucFreeQuota); ++ DBGLOG(SW4, INFO, "ucFreeQuotaForDelivery %u\n", prStaRec->ucFreeQuotaForDelivery); ++ DBGLOG(SW4, INFO, "ucFreeQuotaForNonDelivery %u\n", prStaRec->ucFreeQuotaForNonDelivery); ++ ++#if 0 ++ DBGLOG(SW4, INFO, "IsQmmSup %u\n", prStaRec->fgIsWmmSupported); ++ DBGLOG(SW4, INFO, "IsUapsdSup %u\n", prStaRec->fgIsUapsdSupported); ++ DBGLOG(SW4, INFO, "AvailabaleDeliverPkts %u\n", prStaRec->ucAvailableDeliverPkts); ++ DBGLOG(SW4, INFO, "BmpDeliverPktsAC %u\n", prStaRec->u4BmpDeliverPktsAC); ++ DBGLOG(SW4, INFO, "BmpBufferAC %u\n", prStaRec->u4BmpBufferAC); ++ DBGLOG(SW4, INFO, "BmpNonDeliverPktsAC %u\n", prStaRec->u4BmpNonDeliverPktsAC); ++#endif ++ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { ++ if (prStaRec->aprRxReorderParamRefTbl[i]) { ++ DBGLOG(SW4, INFO, ++ "RxReorder fgIsValid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid); ++ DBGLOG(SW4, INFO, "RxReorder Tid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->ucTid); ++ DBGLOG(SW4, INFO, ++ "RxReorder rReOrderQue Len: %u\n", ++ prStaRec->aprRxReorderParamRefTbl[i]->rReOrderQue.u4NumElem); ++ DBGLOG(SW4, INFO, ++ "RxReorder WinStart: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart); ++ DBGLOG(SW4, INFO, "RxReorder WinEnd: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd); ++ DBGLOG(SW4, INFO, "RxReorder WinSize: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize); ++ } ++ } ++ ++} ++ ++VOID dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) ++{ ++ ++ DBGLOG(SW4, INFO, "SSID %s\n", prBssInfo->aucSSID); ++ DBGLOG(SW4, INFO, "OWN %pM\n", prBssInfo->aucOwnMacAddr); ++ DBGLOG(SW4, INFO, "BSSID %pM\n", prBssInfo->aucBSSID); ++ DBGLOG(SW4, INFO, "ucNetTypeIndex %u\n", prBssInfo->ucNetTypeIndex); ++ DBGLOG(SW4, INFO, "eConnectionState %u\n", prBssInfo->eConnectionState); ++ DBGLOG(SW4, INFO, "eCurrentOPMode %u\n", prBssInfo->eCurrentOPMode); ++ DBGLOG(SW4, INFO, "fgIsQBSS %u\n", prBssInfo->fgIsQBSS); ++ DBGLOG(SW4, INFO, "fgIsShortPreambleAllowed %u\n", prBssInfo->fgIsShortPreambleAllowed); ++ DBGLOG(SW4, INFO, "fgUseShortPreamble %u\n", prBssInfo->fgUseShortPreamble); ++ DBGLOG(SW4, INFO, "fgUseShortSlotTime %u\n", prBssInfo->fgUseShortSlotTime); ++ DBGLOG(SW4, INFO, "ucNonHTBasicPhyType %x\n", prBssInfo->ucNonHTBasicPhyType); ++ DBGLOG(SW4, INFO, "u2OperationalRateSet %x\n", prBssInfo->u2OperationalRateSet); ++ DBGLOG(SW4, INFO, "u2BSSBasicRateSet %x\n", prBssInfo->u2BSSBasicRateSet); ++ DBGLOG(SW4, INFO, "ucPhyTypeSet %x\n", prBssInfo->ucPhyTypeSet); ++ DBGLOG(SW4, INFO, "rStaRecOfClientList %d\n", prBssInfo->rStaRecOfClientList.u4NumElem); ++ DBGLOG(SW4, INFO, "u2CapInfo %x\n", prBssInfo->u2CapInfo); ++ DBGLOG(SW4, INFO, "u2ATIMWindow %x\n", prBssInfo->u2ATIMWindow); ++ DBGLOG(SW4, INFO, "u2AssocId %x\n", prBssInfo->u2AssocId); ++ DBGLOG(SW4, INFO, "ucDTIMPeriod %x\n", prBssInfo->ucDTIMPeriod); ++ DBGLOG(SW4, INFO, "ucDTIMCount %x\n", prBssInfo->ucDTIMCount); ++ DBGLOG(SW4, INFO, "fgIsNetAbsent %x\n", prBssInfo->fgIsNetAbsent); ++ DBGLOG(SW4, INFO, "eBand %d\n", prBssInfo->eBand); ++ DBGLOG(SW4, INFO, "ucPrimaryChannel %d\n", prBssInfo->ucPrimaryChannel); ++ DBGLOG(SW4, INFO, "ucHtOpInfo1 %d\n", prBssInfo->ucHtOpInfo1); ++ DBGLOG(SW4, INFO, "ucHtOpInfo2 %d\n", prBssInfo->u2HtOpInfo2); ++ DBGLOG(SW4, INFO, "ucHtOpInfo3 %d\n", prBssInfo->u2HtOpInfo3); ++ DBGLOG(SW4, INFO, "fgErpProtectMode %d\n", prBssInfo->fgErpProtectMode); ++ DBGLOG(SW4, INFO, "eHtProtectMode %d\n", prBssInfo->eHtProtectMode); ++ DBGLOG(SW4, INFO, "eGfOperationMode %d\n", prBssInfo->eGfOperationMode); ++ DBGLOG(SW4, INFO, "eRifsOperationMode %d\n", prBssInfo->eRifsOperationMode); ++ DBGLOG(SW4, INFO, "fgObssErpProtectMode %d\n", prBssInfo->fgObssErpProtectMode); ++ DBGLOG(SW4, INFO, "eObssHtProtectMode %d\n", prBssInfo->eObssHtProtectMode); ++ DBGLOG(SW4, INFO, "eObssGfProtectMode %d\n", prBssInfo->eObssGfOperationMode); ++ DBGLOG(SW4, INFO, "fgObssRifsOperationMode %d\n", prBssInfo->fgObssRifsOperationMode); ++ DBGLOG(SW4, INFO, "fgAssoc40mBwAllowed %d\n", prBssInfo->fgAssoc40mBwAllowed); ++ DBGLOG(SW4, INFO, "fg40mBwAllowed %d\n", prBssInfo->fg40mBwAllowed); ++ DBGLOG(SW4, INFO, "eBssSCO %d\n", prBssInfo->eBssSCO); ++ ++} ++ ++VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_32 i; ++ ++ DEBUGFUNC("swCtrlCmdCategory0"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ i = 0; ++ ++ if (ucIndex >= SWCTRL_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case SWCTRL_DEBUG: ++#if DBG ++ aucDebugModule[ucOpt0] = (UINT_8) g_au4SwCr[1]; ++#endif ++ break; ++ case SWCTRL_WIFI_VAR: ++ break; ++ ++#if QM_DEBUG_COUNTER ++ case SWCTRL_DUMP_QM_DBG_CNT: ++ for (i = 0; i < QM_DBG_CNT_NUM; i++) ++ prAdapter->rQM.au4QmDebugCounters[i] = 0; ++ break; ++ case SWCTRL_QM_DBG_CNT: ++ prAdapter->rQM.au4QmDebugCounters[ucOpt0] = g_au4SwCr[1]; ++ ++ break; ++#endif ++#if CFG_RX_PKTS_DUMP ++ case SWCTRL_RX_PKTS_DUMP: ++ /* DBGLOG(SW4, INFO,("SWCTRL_RX_PKTS_DUMP: mask %x\n", g_au4SwCr[1])); */ ++ prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = g_au4SwCr[1]; ++ break; ++#endif ++ case SWCTRL_RX_MDNS_FILTER: ++ { ++ UINT_32 u4rxfilter; ++ BOOLEAN fgUpdate = FALSE; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_STOP) { ++ g_u4mDNSRXFilter &= ~(RX_MDNS_FILTER_START); ++ ++ u4rxfilter = prAdapter->u4OsPacketFilter; ++ fgUpdate = TRUE; ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_START) { ++ g_u4mDNSRXFilter |= (RX_MDNS_FILTER_START); ++ ++ u4rxfilter = prAdapter->u4OsPacketFilter; ++ if ((g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV4) || ++ (g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV6)) { ++ u4rxfilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } ++ fgUpdate = TRUE; ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_ADD) { ++ if (ucOpt1 < 31) ++ g_u4mDNSRXFilter |= (1 << ucOpt1); ++ } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_REMOVE) { ++ if (ucOpt1 < 31) ++ g_u4mDNSRXFilter &= ~(1 << ucOpt1); ++ } ++ ++ if (fgUpdate == TRUE) { ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SET_RX_FILTER, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, /* pfCmdDoneHandler */ ++ NULL, /* pfCmdTimeoutHandler */ ++ sizeof(UINT_32), /* u4SetQueryInfoLen */ ++ (PUINT_8)&u4rxfilter, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* un4SetQueryBufferLen */ ++ ); ++ } ++/* DBGLOG(SW4, INFO,("SWCTRL_RX_MDNS_FILTER: g_u4mDNSRXFilter %x ucOpt0 %x ucOpt1 %x fgUpdate %x u4rxfilter %x, */ ++/* rStatus %x\n", g_u4mDNSRXFilter, ucOpt0, ucOpt1, fgUpdate, u4rxfilter, rStatus)); */ ++ } ++ break; ++ default: ++ break; ++ } ++ } else { ++ switch (ucIndex) { ++ case SWCTRL_DEBUG: ++#if DBG ++ g_au4SwCr[1] = aucDebugModule[ucOpt0]; ++#endif ++ break; ++ case SWCTRL_MAGIC: ++ g_au4SwCr[1] = _SWCTRL_MAGIC; ++ /* DBGLOG(SW4, INFO, "BUILD TIME: %s %s\n", __DATE__, __TIME__); */ ++ break; ++ case SWCTRL_QM_INFO: ++ { ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ switch (ucOpt0) { ++ case 0: ++ g_au4SwCr[1] = (QM_GET_TX_QUEUE_LEN(prAdapter, ucOpt1)); ++ g_au4SwCr[2] = prQM->au4MinReservedTcResource[ucOpt1]; ++ g_au4SwCr[3] = prQM->au4CurrentTcResource[ucOpt1]; ++ g_au4SwCr[4] = prQM->au4GuaranteedTcResource[ucOpt1]; ++ break; ++ ++ case 1: ++ g_au4SwCr[1] = prQM->au4ForwardCount[ucOpt1]; ++ g_au4SwCr[2] = prQM->au4HeadStaRecIndex[ucOpt1]; ++ break; ++ ++ case 2: ++ g_au4SwCr[1] = prQM->arTxQueue[ucOpt1].u4NumElem; /* only one */ ++ ++ break; ++ } ++ ++ } ++ break; ++ case SWCTRL_TX_CTRL_INFO: ++ { ++ P_TX_CTRL_T prTxCtrl; ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ switch (ucOpt0) { ++ case 0: ++ g_au4SwCr[1] = prAdapter->rTxCtrl.rTc.aucFreeBufferCount[ucOpt1]; ++ g_au4SwCr[2] = prAdapter->rTxCtrl.rTc.aucMaxNumOfBuffer[ucOpt1]; ++ break; ++ } ++ ++ } ++ break; ++ case SWCTRL_DUMP_QUEUE: ++ dumpQueue(prAdapter); ++ ++ break; ++#if QM_DEBUG_COUNTER ++ case SWCTRL_DUMP_QM_DBG_CNT: ++ for (i = 0; i < QM_DBG_CNT_NUM; i++) ++ DBGLOG(SW4, INFO, "QM:DBG %u %u\n", i, prAdapter->rQM.au4QmDebugCounters[i]); ++ break; ++ ++ case SWCTRL_QM_DBG_CNT: ++ g_au4SwCr[1] = prAdapter->rQM.au4QmDebugCounters[ucOpt0]; ++ break; ++#endif ++ case SWCTRL_DUMP_BSS: ++ { ++ dumpBss(prAdapter, &(prAdapter->rWifiVar.arBssInfo[ucOpt0])); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ } ++} ++ ++VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_8 ucWTEntry; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("swCtrlCmdCategory1"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ if (ucOpt0 >= CFG_STA_REC_NUM) ++ return; ++ ++ /* prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); */ ++ prStaRec = &prAdapter->arStaRec[ucOpt0]; ++ ucWTEntry = prStaRec->ucWTEntry; ++ if (ucRead == SWCR_WRITE) { ++ /* Do nothing */ ++ } else { ++ /* Read */ ++ switch (ucIndex) { ++ case SWCTRL_STA_QUE_INFO: ++ { ++ g_au4SwCr[1] = prStaRec->arTxQueue[ucOpt1].u4NumElem; ++ } ++ break; ++ case SWCTRL_STA_INFO: ++ switch (ucOpt1) { ++ case 0: ++ g_au4SwCr[1] = prStaRec->fgIsInPS; ++ break; ++ } ++ ++ break; ++ ++ case SWCTRL_DUMP_STA: ++ { ++ dumpSTA(prAdapter, prStaRec); ++ } ++ break; ++ ++ default: ++ ++ break; ++ } ++ } ++ ++} ++ ++#if TEST_PS ++ ++VOID ++testPsSendQoSNullFrame(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, ++ IN UINT_8 ucUP, ++ IN UINT_8 ucNetTypeIndex, ++ IN BOOLEAN fgBMC, ++ IN BOOLEAN fgIsBurstEnd, IN BOOLEAN ucPacketType, IN BOOLEAN ucPsSessionID, IN BOOLEAN fgSetEOSP) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_16 u2EstimatedFrameLen; ++ P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; ++ ++ DEBUGFUNC("testPsSendQoSNullFrame"); ++ DBGLOG(SW4, LOUD, "\n"); ++ ++ /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ ++ /* Init with MGMT Header Length */ ++ u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; ++ ++ /* Allocate a MSDU_INFO_T */ ++ prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); ++ if (prMsduInfo == NULL) { ++ DBGLOG(SW4, WARN, "No PKT_INFO_T for sending Null Frame.\n"); ++ return; ++ } ++ /* 4 <2> Compose Null frame in MSDU_INfO_T. */ ++ bssComposeQoSNullFrame(prAdapter, ++ (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), ++ prStaRec, ucUP, fgSetEOSP); ++ ++ prMsduInfo->eSrc = TX_PACKET_MGMT; ++ /* prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; */ ++ prMsduInfo->ucPacketType = ucPacketType; ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = NULL; ++ prMsduInfo->fgIsBasicRate = TRUE; ++ prMsduInfo->fgIsBurstEnd = fgIsBurstEnd; ++ prMsduInfo->ucUserPriority = ucUP; ++ prMsduInfo->ucPsSessionID = ucPsSessionID /* 0~7 Test 7 means NOACK */; ++ ++ prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) (((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD)); ++ ++ if (fgBMC) ++ prQoSNullFrame->aucAddr1[0] = 0xfd; ++ else ++ prQoSNullFrame->aucAddr1[5] = 0xdd; ++ ++ /* 4 <4> Inform TXM to send this Null frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++} ++ ++VOID testPsSetupBss(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetworkTypeIndex) ++{ ++ P_BSS_INFO_T prBssInfo; ++ UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; ++ ++ DEBUGFUNC("testPsSetupBss()"); ++ DBGLOG(SW4, INFO, "index %d\n", ucNetworkTypeIndex); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetworkTypeIndex]); ++ ++ /* 4 <1.2> Initiate PWR STATE */ ++ /* SET_NET_PWR_STATE_IDLE(prAdapter, ucNetworkTypeIndex); */ ++ ++ /* 4 <2> Initiate BSS_INFO_T - common part */ ++ BSS_INFO_INIT(prAdapter, ucNetworkTypeIndex); ++ ++ prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; ++ prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ prBssInfo->eCurrentOPMode = OP_MODE_ACCESS_POINT; ++ prBssInfo->fgIsNetActive = TRUE; ++ prBssInfo->ucNetTypeIndex = (ucNetworkTypeIndex); ++ prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; ++ ++ prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ ++ prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ ++ prBssInfo->u2BSSBasicRateSet = RATE_SET_ERP; ++ prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; ++ prBssInfo->fgErpProtectMode = FALSE; ++ prBssInfo->fgIsQBSS = TRUE; ++ ++ /* 4 <1.5> Setup MIB for current BSS */ ++ prBssInfo->u2BeaconInterval = 100; ++ prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; ++ prBssInfo->u2ATIMWindow = 0; ++ ++ prBssInfo->ucBeaconTimeoutCount = 0; ++ ++ bssInitForAP(prAdapter, prBssInfo, TRUE); ++ ++ COPY_MAC_ADDR(prBssInfo->aucBSSID, _aucZeroMacAddr); ++ LINK_INITIALIZE(&prBssInfo->rStaRecOfClientList); ++ prBssInfo->fgIsBeaconActivated = TRUE; ++ prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; ++ ++ COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); ++ ++ /* 4 <3> Initiate BSS_INFO_T - private part */ ++ /* TODO */ ++ prBssInfo->eBand = BAND_2G4; ++ prBssInfo->ucPrimaryChannel = 1; ++ prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; ++ ++ /* prBssInfo->fgErpProtectMode = eErpProectMode; */ ++ /* prBssInfo->eHtProtectMode = eHtProtectMode; */ ++ /* prBssInfo->eGfOperationMode = eGfOperationMode; */ ++ ++ /* 4 <4> Allocate MSDU_INFO_T for Beacon */ ++ prBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); ++ ++ if (prBssInfo->prBeacon) { ++ prBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; ++ prBssInfo->prBeacon->ucNetworkType = ucNetworkTypeIndex; ++ } else { ++ DBGLOG(SW4, INFO, "prBeacon allocation fail\n"); ++ } ++ ++#if 0 ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; ++ prBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; ++#else ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; ++ prBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; ++#endif ++ ++#if 0 ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prBssInfo->arACQueParms[eAci].fgIsACMSet = FALSE; ++ prBssInfo->arACQueParms[eAci].u2Aifsn = (UINT_16) eAci; ++ prBssInfo->arACQueParms[eAci].u2CWmin = 7; ++ prBssInfo->arACQueParms[eAci].u2CWmax = 31; ++ prBssInfo->arACQueParms[eAci].u2TxopLimit = eAci + 1; ++ DBGLOG(SW4, INFO, "MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", ++ eAci, prBssInfo->arACQueParms[eAci].fgIsACMSet, ++ prBssInfo->arACQueParms[eAci].u2Aifsn, ++ prBssInfo->arACQueParms[eAci].u2CWmin, ++ prBssInfo->arACQueParms[eAci].u2CWmax, prBssInfo->arACQueParms[eAci].u2TxopLimit)); ++ ++ } ++#endif ++ ++ DBGLOG(SW4, INFO, "[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", ++ prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, ++ prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, prBssInfo->rPmProfSetupInfo.ucUapsdSp); ++ ++} ++ ++VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testPsCmdCategory0"); ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ DBGLOG(SW4, LOUD, "Read %u Index %u\n", ucRead, ucIndex); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, 0); ++ ++ if (ucIndex >= TEST_PS_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case TEST_PS_SETUP_BSS: ++ testPsSetupBss(prAdapter, ucOpt0); ++ break; ++ ++ case TEST_PS_ENABLE_BEACON: ++ break; ++ ++ case TEST_PS_TRIGGER_BMC: ++ /* txmForwardQueuedBmcPkts (ucOpt0); */ ++ break; ++ case TEST_PS_SEND_NULL: ++ { ++ ++ testPsSendQoSNullFrame(prAdapter, prStaRec, (UINT_8) (g_au4SwCr[1] & 0xFF), /* UP */ ++ ucOpt0, (BOOLEAN) ((g_au4SwCr[1] >> 8) & 0xFF), /* BMC */ ++ (BOOLEAN) ((g_au4SwCr[1] >> 16) & 0xFF), /* BurstEnd */ ++ (BOOLEAN) ((g_au4SwCr[1] >> 24) & 0xFF), /* Packet type */ ++ (UINT_8) ((g_au4SwCr[2]) & 0xFF), /* PS sesson ID 7: NOACK */ ++ FALSE /* EOSP */ ++ ); ++ } ++ break; ++ case TEST_PS_BUFFER_BMC: ++ /* g_aprBssInfo[ucOpt0]->fgApToBufferBMC = (g_au4SwCr[1] & 0xFF); */ ++ break; ++ case TEST_PS_UPDATE_BEACON: ++ bssUpdateBeaconContent(prAdapter, ucOpt0 /*networktype */); ++ break; ++ ++ default: ++ break; ++ } ++ } else { ++ switch (ucIndex) { ++ ++ case TEST_PS_MAGIC: ++ g_au4SwCr[1] = 0x88660011; ++ break; ++ ++ } ++ } ++} ++ ++#endif /* TEST_PS */ ++ ++#if TEST_PS ++ ++VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ UINT_8 ucWTEntry; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testPsCmdCategory1"); ++ ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ if (ucOpt0 >= CFG_STA_REC_NUM) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucOpt0); ++ if (!prStaRec) ++ return; ++ ucWTEntry = prStaRec->ucWTEntry; ++ if (ucRead == SWCR_WRITE) { ++ ++ switch (ucIndex) { ++ case TEST_PS_STA_PS: ++ prStaRec->fgIsInPS = (BOOLEAN) (g_au4SwCr[1] & 0x1); ++ prStaRec->fgIsQoS = (BOOLEAN) (g_au4SwCr[1] >> 8 & 0xFF); ++ prStaRec->fgIsUapsdSupported = (BOOLEAN) (g_au4SwCr[1] >> 16 & 0xFF); ++ prStaRec->ucBmpDeliveryAC = (BOOLEAN) (g_au4SwCr[1] >> 24 & 0xFF); ++ break; ++ ++ } ++ ++ } else { ++ /* Read */ ++ switch (ucIndex) { ++ default: ++ break; ++ } ++ } ++ ++} ++ ++#endif /* TEST_PS */ ++ ++#if CFG_SUPPORT_802_11V ++#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) ++VOID testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) ++{ ++ UINT_8 ucIndex, ucRead; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("testWNMCmdCategory0"); ++ SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); ++ ++ DBGLOG(SW4, INFO, "Read %u Index %u\n", ucRead, ucIndex); ++ ++ if (ucIndex >= TEST_WNM_CATA0_INDEX_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ switch (ucIndex) { ++ case TEST_WNM_TIMING_MEAS: ++ wnmTimingMeasUnitTest1(prAdapter, ucOpt0); ++ break; ++ ++ default: ++ break; ++ } ++ } ++} ++#endif /* TEST_WNM */ ++#endif /* CFG_SUPPORT_802_11V */ ++ ++VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) ++{ ++ /* According other register STAIDX */ ++ UINT_8 ucOffset; ++ ++ ucOffset = (u2Addr >> 2) & 0x3F; ++ ++ if (ucOffset >= SWCR_CR_NUM) ++ return; ++ ++ if (ucRead == SWCR_WRITE) { ++ g_au4SwCr[ucOffset] = *pu4Data; ++ if (ucOffset == 0x0) { ++ /* Commmand [31:24]: Category */ ++ /* Commmand [23:23]: 1(W) 0(R) */ ++ /* Commmand [22:16]: Index */ ++ /* Commmand [15:08]: Option0 */ ++ /* Commmand [07:00]: Option1 */ ++ UINT_8 ucCate; ++ UINT_32 u4Cmd; ++ ++ u4Cmd = g_au4SwCr[0]; ++ ucCate = (UINT_8) (u4Cmd >> 24); ++ if (ucCate < sizeof(g_arSwCtrlCmd) / sizeof(g_arSwCtrlCmd[0])) { ++ if (g_arSwCtrlCmd[ucCate] != NULL) { ++ g_arSwCtrlCmd[ucCate] (prAdapter, ucCate, (UINT_8) (u4Cmd >> 16 & 0xFF), ++ (UINT_8) ((u4Cmd >> 8) & 0xFF), (UINT_8) (u4Cmd & 0xFF)); ++ } ++ } ++ } ++ } else { ++ *pu4Data = g_au4SwCr[ucOffset]; ++ } ++} ++ ++VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) ++{ ++ UINT_8 ucMod; ++ ++ ucMod = u2Addr >> 8; ++ /* Address [15:8] MOD ID */ ++ /* Address [7:0] OFFSET */ ++ ++ DEBUGFUNC("swCrReadWriteCmd"); ++ DBGLOG(SW4, TRACE, "%u addr 0x%x data 0x%x\n", ucRead, u2Addr, *pu4Data); ++ ++ if (ucMod < (sizeof(g_arSwCrModHandle) / sizeof(g_arSwCrModHandle[0]))) { ++ ++ if (g_arSwCrModHandle[ucMod] != NULL) ++ g_arSwCrModHandle[ucMod] (prAdapter, ucRead, u2Addr, pu4Data); ++ } /* ucMod */ ++} ++ ++/* Debug Support */ ++VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType) ++{ ++ g_u4SwcrDebugFrameDumpType = u4DumpType; ++ prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = u4DumpType; ++} ++ ++VOID swCrDebugInit(P_ADAPTER_T prAdapter) ++{ ++ /* frame dump */ ++ if (g_u4SwcrDebugFrameDumpType) ++ swCrFrameCheckEnable(prAdapter, g_u4SwcrDebugFrameDumpType); ++ /* debug counter */ ++ g_fgSwcrDebugTimer = FALSE; ++ ++ cnmTimerInitTimer(prAdapter, &g_rSwcrDebugTimer, (PFN_MGMT_TIMEOUT_FUNC) swCrDebugCheckTimeout, (ULONG) NULL); ++ ++ if (g_u4SwcrDebugCheckTimeout) ++ swCrDebugCheckEnable(prAdapter, TRUE, g_ucSwcrDebugCheckType, g_u4SwcrDebugCheckTimeout); ++} ++ ++VOID swCrDebugUninit(P_ADAPTER_T prAdapter) ++{ ++ cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); ++ ++ g_fgSwcrDebugTimer = FALSE; ++} ++ ++VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout) ++{ ++ if (fgIsEnable) { ++ g_ucSwcrDebugCheckType = ucType; ++ g_u4SwcrDebugCheckTimeout = u4Timeout; ++ if (g_fgSwcrDebugTimer == FALSE) ++ swCrDebugCheckTimeout(prAdapter, 0); ++ } else { ++ cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); ++ g_u4SwcrDebugCheckTimeout = 0; ++ } ++ ++ g_fgSwcrDebugTimer = fgIsEnable; ++} ++ ++VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* dump counters */ ++ if (prCmdSwCtrl) { ++ if (prCmdSwCtrl->u4Data == SWCR_DBG_TYPE_ALL) { ++ ++ /* TX Counter from fw */ ++ DBGLOG(SW4, INFO, "TX0\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_BCN_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_FAILED_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_RETRY_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_MGNT_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_ERROR_CNT]); ++#if 1 ++ /* TX Counter from drv */ ++ DBGLOG(SW4, INFO, "TX1\n" ++ "%08x %08x %08x %08x\n", ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_BSS_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_STA_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_FORWARD_OVERFLOW_DROP), ++ (UINT_32) TX_GET_CNT(prTxCtrl, TX_AP_BORADCAST_DROP)); ++#endif ++ ++ /* RX Counter */ ++ DBGLOG(SW4, INFO, "RX0\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DUP_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FCSERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FIFOFULL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_PFDROP_CNT]); ++ ++ DBGLOG(SW4, INFO, "RX1\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT), ++ (UINT_32) RX_GET_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT)); ++ ++ DBGLOG(SW4, INFO, "PWR\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PS_POLL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_IND_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE0], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE1], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF0], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF1]); ++ ++ DBGLOG(SW4, INFO, "ARM\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RATE], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_BWGI], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ENABLE], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ROAM_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_INT_CNT]); ++ ++ DBGLOG(SW4, INFO, "BB\n" ++ "%08x %08x %08x %08x\n" ++ "%08x %08x %08x %08x\n", ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_MDRDY_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_FCSERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_PD_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_PD_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SFDERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SIGERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT], ++ prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT]); ++ ++ } ++ } ++ /* start the next check */ ++ if (g_u4SwcrDebugCheckTimeout) ++ cnmTimerStartTimer(prAdapter, &g_rSwcrDebugTimer, g_u4SwcrDebugCheckTimeout * MSEC_PER_SEC); ++} ++ ++VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ WLAN_STATUS rStatus; ++ ++ rCmdSwCtrl.u4Id = (0xb000 << 16) + g_ucSwcrDebugCheckType; ++ rCmdSwCtrl.u4Data = 0; ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_SW_DBG_CTRL, /* ucCID */ ++ FALSE, /* fgSetQuery */ ++ TRUE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ swCrDebugQuery, /* pfCmdDoneHandler */ ++ swCrDebugQueryTimeout, /* pfCmdTimeoutHandler */ ++ sizeof(CMD_SW_DBG_CTRL_T), /* u4SetQueryInfoLen */ ++ (PUINT_8)&rCmdSwCtrl, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ ASSERT(rStatus == WLAN_STATUS_PENDING); ++ ++} ++ ++VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ++ swCrDebugCheck(prAdapter, (P_CMD_SW_DBG_CTRL_T) (pucEventBuf)); ++} ++ ++VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ swCrDebugCheck(prAdapter, NULL); ++} ++ ++#endif /* CFG_SUPPORT_SWCR */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c +new file mode 100644 +index 000000000000..96293c57e2b0 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c +@@ -0,0 +1,5199 @@ ++/* ++** Id: tdls.c#1 ++*/ ++ ++/*! \file tdls.c ++ \brief This file includes IEEE802.11z TDLS support. ++*/ ++ ++/* ++** Log: tdls.c ++ * ++ * 11 13 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++#include "precomp.h" ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "gl_wext.h" ++#include "tdls.h" ++#include "gl_cfg80211.h" ++#include ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb); ++ ++#if TDLS_CFG_CMD_TEST ++static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static TDLS_STATUS ++TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd); ++ ++static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param); ++ ++static TDLS_STATUS ++TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++ ++static TDLS_STATUS ++TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static VOID ++TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, ++ UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers); ++ ++static VOID ++TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, ++ UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo); ++ ++static TDLS_STATUS ++TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static TDLS_STATUS ++TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); ++ ++static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); ++ ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static BOOLEAN fgIsPtiTimeoutSkip = FALSE; ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to indicate packets to upper layer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prSkb A pointer to the received packet ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb) ++{ ++ struct net_device *prNetDev; ++ ++ /* init */ ++ prNetDev = prGlueInfo->prDevHandler; ++ prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.rx_packets++; ++ ++ /* pass to upper layer */ ++ //prNetDev->last_rx = jiffies; ++ prSkb->protocol = eth_type_trans(prSkb, prNetDev); ++ prSkb->dev = prNetDev; ++ ++ if (!in_interrupt()) ++ netif_rx_ni(prSkb); /* only in non-interrupt context */ ++ else ++ netif_rx(prSkb); ++} ++ ++#if TDLS_CFG_CMD_TEST ++ ++#define LR_TDLS_FME_FIELD_FILL(__Len) \ ++do { \ ++ pPkt += __Len; \ ++ u4PktLen += __Len; \ ++} while (0) ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to add a TDLS peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_2_[Responder MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_2_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ struct wireless_dev *prWdev; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ /* init */ ++ rCmd.rPeerInfo.supported_rates = NULL; ++ rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; ++ rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); ++ ++ /* send command to wifi task to handle */ ++ prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; ++ mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_16_[Enable/Disable]_[Set/Clear] ++ ++ iwpriv wlan0 set_str_cmd 0_16_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ TDLS_CMD_CORE_T rCmd; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); ++ ++ /* command to do this */ ++ flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; ++ ++ aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; ++ aucTdlsTestExtCapElm[1] = 5; ++ aucTdlsTestExtCapElm[2] = 0; ++ aucTdlsTestExtCapElm[3] = 0; ++ aucTdlsTestExtCapElm[4] = 0; ++ aucTdlsTestExtCapElm[5] = 0; ++ aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 7); /* bit39 */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a channel switch request from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_5_[TDLS Peer MAC]_[Chan]_[RegulatoryClass]_ ++ [SecondaryChannelOffset]_[SwitchTime]_[SwitchTimeout] ++ ++ iwpriv wlan0 set_str_cmd 0_1_5_00:11:22:33:44:01_1_255_0_15000_30000 ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChStReqRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4RegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s:[%pM]u4Chan=%u u4RegClass=%u u4SecChanOff=%u u4SwitchTime=%u u4SwitchTimeout=%u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4Chan, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4RegClass, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SecChanOff, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTime, ++ (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestChStReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a channel switch response from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_6_[TDLS Peer MAC]_[Chan]_ ++ [SwitchTime]_[SwitchTimeout]_[StatusCode] ++ ++ iwpriv wlan0 set_str_cmd 0_1_6_00:11:22:33:44:01_11_15000_30000_0 ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChStRspRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChStRspRcv.u4StatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [ %pM ] u4Chan=%u u4SwitchTime=%u u4SwitchTimeout=%u u4StatusCode=%u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4Chan, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTime, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout, ++ (UINT32) rCmd.Content.rCmdChStRspRcv.u4StatusCode); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestChStRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip channel switch timeout function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_11_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestChSwTimeoutSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer periodically. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TIMER_T rTdlsTimerTestDataSend; ++static UINT_8 aucTdlsTestDataSPeerMac[6]; ++static UINT_16 u2TdlsTestDataSInterval; ++ ++static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ BOOLEAN fgIsEnabled; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucTdlsTestDataSPeerMac); ++ u2TdlsTestDataSInterval = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ fgIsEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); ++ ++ if (fgIsEnabled == FALSE) { ++ /* stop test timer */ ++ return; ++ } ++ ++ /* re-init test timer */ ++ cnmTimerInitTimer(prAdapter, ++ &rTdlsTimerTestDataSend, (PFN_MGMT_TIMEOUT_FUNC) TdlsTimerTestDataContSend, (ULONG) NULL); ++ ++ cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a data frame from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_x80_[TDLS Peer MAC]_[PM]_[UP]_[EOSP]_[IsNull] ++ ++ iwpriv wlan0 set_str_cmd 0_1_x80_00:11:22:33:44:01_0_0_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.Content.rCmdDatRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4UP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4EOSP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdDatRcv.u4IsNull = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: [%pM] PM(%u) UP(%u) EOSP(%u) NULL(%u)\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4PM, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4UP, ++ (UINT32) rCmd.Content.rCmdDatRcv.u4EOSP, (UINT32) rCmd.Content.rCmdDatRcv.u4IsNull); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestDataRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_4_[Responder MAC]_[tx status] ++ ++ iwpriv wlan0 set_str_cmd 0_4_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ P_ADAPTER_T prAdapter; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *prPkt; ++ UINT_8 MAC[6]; ++ UINT_8 ucTxStatus; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, MAC); ++ ucTxStatus = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ /* allocate a data frame */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); ++ return; ++ } ++ ++ /* init dev */ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* init packet */ ++ prMsduInfo->len = 1000; ++ kalMemZero(prMsduInfo->data, 100); /* for QoS field */ ++ kalMemCopy(prMsduInfo->data, MAC, 6); ++ kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); ++ *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; ++ ++ /* simulate OS to send the packet */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_16_[mili seconds] ++ ++ iwpriv wlan0 set_str_cmd 0_19_1000 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT32 u4Delay; ++ ++ u4Delay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, "%s: Delay = %d\n", __func__, u4Delay); ++ ++ kalMdelay(u4Delay); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test discovery request frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_10_[DialogToken]_[Peer MAC]_[BSSID] ++ ++ iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01 ++ iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01_00:22:33:44:11:22 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ kalMemZero(aucBSSID, sizeof(aucBSSID)); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_DISCOVERY_REQ; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; ++ ++ if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ else ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip keep alive function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_10_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_10_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestKeepAliveSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable]_[Set/Clear] ++ ++ iwpriv wlan0 set_str_cmd 0_13_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ TDLS_CMD_CORE_T rCmd; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); ++ ++ /* command to do this */ ++ flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; ++ ++ aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; ++ aucTdlsTestExtCapElm[1] = 5; ++ aucTdlsTestExtCapElm[2] = 0; ++ aucTdlsTestExtCapElm[3] = 0; ++ aucTdlsTestExtCapElm[4] = 0; ++ aucTdlsTestExtCapElm[5] = 0; ++ aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 6); /* bit38 */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI request from the AP. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_4_[TDLS Peer MAC]_[Dialog Token] ++ ++ iwpriv wlan0 set_str_cmd 0_1_4_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [ %pM ] u4DialogToken = %u\n", ++ __func__, rCmd.aucPeerMac, (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI response from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_9_[TDLS Peer MAC]_[Dialog Token]_[PM] ++ ++ iwpriv wlan0 set_str_cmd 0_1_9_00:11:22:33:44:01_0_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdPtiRspRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [%pM] u4DialogToken = %u %u\n", ++ __func__, rCmd.aucPeerMac, ++ (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken, ++ (UINT32) rCmd.Content.rCmdPtiRspRcv.u4PM); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to simulate PTI tx done fail case. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_21_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_21_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdPtiTxFail.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdPtiTxFail.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestPtiTxFail, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test frame. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++/* PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; */ ++/* TDLS_STATUS u4Status; */ ++ UINT_32 u4Subcmd; ++/* UINT_32 u4BufLen; */ ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test rv frame sub command = %u\n", (UINT32) u4Subcmd); ++ ++ /* parse command arguments */ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ /* simulate to receive a setup request frame */ ++ TdlsCmdTestSetupReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ /* simulate to receive a setup response frame */ ++ TdlsCmdTestSetupRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CONFIRM: ++ /* simulate to receive a setup confirm frame */ ++ TdlsCmdTestSetupConfirmRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_TEARDOWN: ++ /* simulate to receive a tear down frame */ ++ TdlsCmdTestTearDownRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_PTI: ++ /* simulate to receive a PTI request frame */ ++ TdlsCmdTestPtiReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_PTI_RSP: ++ /* simulate to receive a PTI response frame */ ++ TdlsCmdTestPtiRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_DATA_TEST_DATA: ++ /* simulate to receive a DATA frame */ ++ TdlsCmdTestDataRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CHAN_SWITCH_REQ: ++ /* simulate to receive a channel switch request frame */ ++ TdlsCmdTestChSwReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_CHAN_SWITCH_RSP: ++ /* simulate to receive a channel switch response frame */ ++ TdlsCmdTestChSwRspRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ case TDLS_FRM_ACTION_DISCOVERY_REQ: ++ /* simulate to receive a discovery request frame */ ++ TdlsCmdTestDiscoveryReqRecv(prGlueInfo, prInBuf, u4InBufLen); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test rv frame sub command\n"); ++ return; ++ } ++ ++/* if (u4Status != TDLS_STATUS_SUCCESS) */ ++ { ++/* DBGLOG(TDLS, ERROR, (" command parse fail\n")); */ ++/* return; */ ++ } ++ ++ /* send command to wifi task to handle */ ++#if 0 ++ kalIoctl(prGlueInfo, ++ TdlsTestFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup confirm frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_2_[DialogToken]_[StatusCode]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_1_2_1_0_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d StatusCode=%d from %pM\n", ++ __func__, ucDialogToken, ucStatusCode, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_CONFIRM; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Status Code */ ++ *pPkt = ucStatusCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (4) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (17) WMM Information element */ ++ if (prAdapter->rWifiVar.fgSupportQoS) { ++ u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup request frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_0_[DialogToken]_[Peer MAC]_[BSSID] ++ ++ iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01 ++ iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01_00:22:33:44:11:22 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; ++ UINT_16 u2CapInfo; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ kalMemZero(aucBSSID, sizeof(aucBSSID)); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_SETUP_REQ; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (4) Capability */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* TDLS_EX_CAP_PEER_UAPSD */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* TDLS_EX_CAP_CHAN_SWITCH */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* TDLS_EX_CAP_TDLS */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; ++ ++ if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ else ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test setup response frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_1_[DialogToken]_[StatusCode]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_1_1_1_0_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; ++ UINT_16 u2CapInfo; ++ ++ /* parse arguments */ ++ ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: DialogToken=%d StatusCode=%d from %pM\n", ++ __func__, ucDialogToken, ucStatusCode, aucPeerMac); ++ ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_SETUP_RSP; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Status Code */ ++ *pPkt = ucStatusCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (4) Dialog token */ ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (5) Capability */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* TDLS_EX_CAP_PEER_UAPSD */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* TDLS_EX_CAP_CHAN_SWITCH */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* TDLS_EX_CAP_TDLS */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip channel switch timeout function. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_14_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_14_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdScanSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdScanSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestScanSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a test tear down frame command. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_1_3_[IsInitiator]_[ReasonCode]_[Peer MAC]_[Where] ++ ++ Where 0 (From driver) or 1 (From FW) ++ ++ iwpriv wlan0 set_str_cmd 0_1_3_1_26_00:11:22:33:44:01_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ ADAPTER_T *prAdapter; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ BOOLEAN fgIsInitiator; ++ UINT_8 ucReasonCode, aucPeerMac[6]; ++ BOOLEAN fgIsFromWhich; ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ fgIsInitiator = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ucReasonCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); ++ fgIsFromWhich = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, ++ " %s: ReasonCode=%d from %pM %d\n", ++ __func__, ucReasonCode, aucPeerMac, fgIsFromWhich); ++ ++ if (fgIsFromWhich == 0) { ++ /* allocate/init packet */ ++ prAdapter = prGlueInfo->prAdapter; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = TDLS_FRM_ACTION_TEARDOWN; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Reason Code */ ++ *pPkt = ucReasonCode; ++ *(pPkt + 1) = 0x00; ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ if (fgIsInitiator == 1) { ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); ++ } else { ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); ++ } ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* pass to OS */ ++ TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); ++ } else { ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ kalMemCopy(rCmd.aucPeerMac, aucPeerMac, 6); ++ rCmd.Content.rCmdTearDownRcv.u4ReasonCode = (UINT32) ucReasonCode; ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsTestTearDownRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to inform firmware to skip tx fail case. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_7_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_7_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ rCmd.Content.rCmdTxFailSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdTxFailSkip.fgIsEnable); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestTxFailSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a test frame command to wifi task. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_2_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_2_0_1_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ UINT32 u4Subcmd; ++ UINT_32 u4BufLen; ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test tx tdls frame sub command = %u\n", u4Subcmd); ++ ++ /* parse command arguments */ ++ rCmd.ucFmeType = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); ++ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ rCmd.ucToken = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ DBGLOG(TDLS, INFO, " setup FmeType=%d Token=%d to [%pM]\n", ++ rCmd.ucFmeType, rCmd.ucToken, rCmd.arRspAddr); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); ++ return; ++ } ++ ++ /* send command to wifi task to handle */ ++ kalIoctl(prGlueInfo, ++ TdlsTestTdlsFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a test frame command to wifi task. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ ++ [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ ++ [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ ++ [Timeout]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ TDLS_STATUS u4Status; ++ UINT_32 u4Subcmd; ++ UINT_32 u4BufLen; ++ ++ /* parse sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " test tx frame sub command = %u\n", (UINT32) u4Subcmd); ++ ++ /* parse command arguments */ ++ switch (u4Subcmd) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ u4Status = TdlsCmdTestTxFmeSetupReqBufTranslate(prInBuf, u4InBufLen, &rCmd); ++ break; ++ ++ default: ++ DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); ++ return; ++ } ++ ++ if (u4Status != TDLS_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, " command parse fail\n"); ++ return; ++ } ++ ++ /* send command to wifi task to handle */ ++ kalIoctl(prGlueInfo, ++ TdlsTestFrameSend, ++ (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse the TDLS test frame command, setup request ++* ++* @param CmdBuf Pointer to the buffer. ++* @param BufLen Record buffer length. ++* @param CmdTspec Pointer to the structure. ++* ++* @retval WLAN_STATUS_SUCCESS: Translate OK. ++* @retval WLAN_STATUS_FAILURE: Translate fail. ++* @usage iwpriv wlan0 set_str_cmd [tdls]_[command] ++* ++* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ ++ [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ ++ [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ ++ [Timeout]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd) ++{ ++/* dumpMemory8(ANDROID_LOG_INFO, pCmdBuf, u4BufLen); */ ++ ++ prCmd->ucFmeType = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->ucToken = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->u2Cap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->ucExCap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupRate[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->arSupChan[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ prCmd->u4Timeout = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); ++ CmdStringMacParse(pCmdBuf, &pCmdBuf, &u4BufLen, prCmd->arRspAddr); ++ ++ DBGLOG(TDLS, INFO, " command content =\n"); ++ DBGLOG(TDLS, INFO, "\tPeer MAC = %pM\n", (prCmd->arRspAddr)); ++ DBGLOG(TDLS, INFO, "\tToken = %u, Cap = 0x%x, ExCap = 0x%x, Timeout = %us FrameType = %u\n", ++ (UINT32) prCmd->ucToken, prCmd->u2Cap, prCmd->ucExCap, ++ (UINT32) prCmd->u4Timeout, (UINT32) prCmd->ucFmeType); ++ DBGLOG(TDLS, INFO, "\tSupRate = 0x%x %x %x %x\n", ++ prCmd->arSupRate[0], prCmd->arSupRate[1], prCmd->arSupRate[2], prCmd->arSupRate[3]); ++ DBGLOG(TDLS, INFO, "\tSupChan = %d %d %d %d\n", ++ prCmd->arSupChan[0], prCmd->arSupChan[1], prCmd->arSupChan[2], prCmd->arSupChan[3]); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update a TDLS peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_3_[Responder MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_3_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; ++ struct wireless_dev *prWdev; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); ++ ++ /* init */ ++ rCmd.rPeerInfo.supported_rates = rCmd.arSupRate; ++ rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; ++ rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ ++ rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); ++ rCmd.rPeerInfo.uapsd_queues = 0xf; /* all AC */ ++ rCmd.rPeerInfo.max_sp = 0; /* delivery all packets */ ++ ++ /* send command to wifi task to handle */ ++ prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; ++ mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); ++ ++ /* update */ ++ TdlsexCfg80211TdlsOper(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, NL80211_TDLS_ENABLE_LINK); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Null frame from the peer. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* EX: iwpriv wlan0 set_str_cmd 0_5_[Responder MAC]_[PM bit] ++ ++ iwpriv wlan0 set_str_cmd 0_5_00:11:22:33:44:01_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.Content.rCmdNullRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: [%pM] u4PM = %u\n", ++ __func__, (rCmd.aucPeerMac), (UINT32) rCmd.Content.rCmdNullRcv.u4PM); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsTestNullRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a data frame to the peer periodically. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] u4Param no use ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_15_[Responder MAC]_[Interval: ms]_[Enable/Disable] ++ ++ iwpriv wlan0 set_str_cmd 0_15_00:11:22:33:44:01_5000_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *prPkt; ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* allocate a data frame */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); ++ return; ++ } ++ ++ /* init dev */ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return; ++ } ++ ++ /* init packet */ ++ prMsduInfo->len = 1000; ++ kalMemCopy(prMsduInfo->data, aucTdlsTestDataSPeerMac, 6); ++ kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); ++ *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; ++ ++ DBGLOG(TDLS, INFO, " %s try to send a data frame to %pM\n", ++ __func__, aucTdlsTestDataSPeerMac); ++ ++ /* simulate OS to send the packet */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ ++ /* restart test timer */ ++ cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Channel Switch Request frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_REQ; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Channel Switch Response frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_RSP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a test frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; ++ P_BSS_INFO_T prBssInfo; ++ struct sk_buff *prMsduInfo; ++ UINT_8 *pPkt; ++ UINT_32 u4PktLen, u4IeLen; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if (u4SetBufferLen == 0) ++ return TDLS_STATUS_INVALID_LENGTH; ++ ++ /* allocate/init packet */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ *pu4SetInfoLen = u4SetBufferLen; ++ u4PktLen = 0; ++ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* make up frame content */ ++ /* 1. 802.3 header */ ++ kalMemCopy(pPkt, prCmd->arRspAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = prCmd->ucFmeType; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ *pPkt = prCmd->ucToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (4) Capability */ ++ WLAN_SET_FIELD_16(pPkt, prCmd->u2Cap); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (10) Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */ ++ TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; ++ TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; ++ ++ TIMEOUT_INTERVAL_IE(pPkt)->ucType = IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; ++ TIMEOUT_INTERVAL_IE(pPkt)->u4Value = htonl(prCmd->u4Timeout); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 3. Frame Formation - (16) Link identifier element */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prCmd->arRspAddr, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 4. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ /* 5. send the data frame */ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a NULL frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_NULL_RCV; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_REQ; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a PTI response frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_RSP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a Tear Down frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TEAR_DOWN; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to receive a data frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_DATA_RCV; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip PTI tx fail status. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_TX_FAIL; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a TDLS action frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] ++ ++ iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; ++ struct wireless_dev *prWdev; ++ ++ /* sanity check */ ++ ASSERT(prAdapter); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if (u4SetBufferLen == 0) ++ return TDLS_STATUS_INVALID_LENGTH; ++ ++ /* allocate/init packet */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; ++ prWdev = (struct wireless_dev *)prGlueInfo->prDevHandler->ieee80211_ptr; ++ ++ TdlsexCfg80211TdlsMgmt(prWdev->wiphy, NULL, ++ prCmd->arRspAddr, prCmd->ucFmeType, 1, ++ 0, 0, /* open/none */ ++ FALSE, NULL, 0); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip tx fail status. So always success in tx done in firmware. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TX_FAIL_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip to do keep alive function in firmware. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip channel switch timeout. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to skip scan request. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_TEST_SCAN_SKIP; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure channel switch parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_CHSW_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update channel switch parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_9_[TDLS Peer MAC]_ ++ [NetworkTypeIndex]_[1 (Enable) or (0) Disable]_[1 (Start) or 0 (Stop)]_ ++ [RegClass]_[Chan]_[SecChanOff]_[1 (Reqular) or (0) One Shot] ++ ++ RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) ++ Secondary Channel Offset: 0 (SCN - no secondary channel) ++ 1 (SCA - secondary channel above) ++ 2 (SCB - secondary channel below) ++ SwitchTime: units of microseconds ++ ++ iwpriv wlan0 set_str_cmd 0_9_00:11:22:33:44:01_0_1_0_0_1_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwStarted = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucRegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucTargetChan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.ucSecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdChSwConf.fgIsChSwRegular = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: %pM ucNetTypeIndex=%d, fgIsChSwEnabled=%d, fgIsChSwStarted=%d", ++ __func__, (rCmd.aucPeerMac), ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex, ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled, ++ rCmd.Content.rCmdChSwConf.fgIsChSwStarted); ++ DBGLOG(TDLS, INFO, " RegClass=%d, TargetChan=%d, SecChanOff=%d, Regular=%d\n", ++ rCmd.Content.rCmdChSwConf.ucRegClass, ++ rCmd.Content.rCmdChSwConf.ucTargetChan, ++ rCmd.Content.rCmdChSwConf.ucSecChanOff, rCmd.Content.rCmdChSwConf.fgIsChSwRegular); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsChSwConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display TDLS related information. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_18_[Peer MAC]_[Network Interface ID]_[IsClear] ++ ++ Network Interface ID: reference to ENUM_NETWORK_TYPE_INDEX_T ++ ++ typedef enum _ENUM_NETWORK_TYPE_INDEX_T { ++ NETWORK_TYPE_AIS_INDEX = 0, ++ NETWORK_TYPE_P2P_INDEX, ++ NETWORK_TYPE_BOW_INDEX, ++ NETWORK_TYPE_INDEX_NUM ++ } ENUM_NETWORK_TYPE_INDEX_T; ++ ++ iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); ++ rCmd.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdInfoDisplay.fgIsToClearAllHistory = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, " %s: Command PeerMac=%pM in BSS%u\n", ++ __func__, (rCmd.aucPeerMac), rCmd.ucNetTypeIndex); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display key related information. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_20 ++ ++ iwpriv wlan0 set_str_cmd 0_20 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsKeyInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update MIB parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_6_[TdlsEn]_[UapsdEn]_[PsmEn]_[PtiWin]_[CWCap]_ ++ [AckMisRetry]_[RspTimeout]_[CWPbDelay]_[DRWin]_[LowestAcInt] ++ ++ iwpriv wlan0 set_str_cmd 0_6_1_1_0_1_1_3_5_1000_2_1 ++ ++ reference to TDLS_CMD_CORE_MIB_PARAM_UPDATE_T ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* reset */ ++ kalMemZero(&rCmd, sizeof(rCmd)); ++ ++ /* parse arguments */ ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval = ++ CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, " MIB param = %d %d %d %d %d %d %d %d %d %d\n", ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow, ++ rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsMibParamUpdate, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update setup parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_17_[20/40 Support] ++ ++ iwpriv wlan0 set_str_cmd 0_17_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ ++ rCmd.Content.rCmdSetupConf.fgIs2040Supported = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ ++ DBGLOG(TDLS, INFO, "%s: rCmdSetupConf=%d\n", __func__, rCmd.Content.rCmdSetupConf.fgIs2040Supported); ++ ++ /* command to do this */ ++ prGlueInfo->rTdlsLink.fgIs2040Sup = rCmd.Content.rCmdSetupConf.fgIs2040Supported; ++ ++ rStatus = kalIoctl(prGlueInfo, TdlsSetupConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update UAPSD parameters. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++* EX: iwpriv wlan0 set_str_cmd 0_8_[SP timeout skip]_[PTI timeout skip] ++ ++ iwpriv wlan0 set_str_cmd 0_8_1_1 ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ WLAN_STATUS rStatus; ++ TDLS_CMD_CORE_T rCmd; ++ UINT_32 u4BufLen; ++ ++ /* parse arguments */ ++ kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); ++ ++ /* UAPSD Service Period */ ++ rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ /* PTI Service Period */ ++ fgIsPtiTimeoutSkip = rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip; ++ ++ DBGLOG(TDLS, INFO, "%s: fgIsSpTimeoutSkip=%d, fgIsPtiTimeoutSkip=%d\n", ++ __func__, rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip, fgIsPtiTimeoutSkip); ++ ++ /* command to do this */ ++ rStatus = kalIoctl(prGlueInfo, TdlsUapsdConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); ++ return; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display TDLS all information. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++* iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_CORE_T *prCmdContent; ++ STA_RECORD_T *prStaRec; ++ TDLS_INFO_LINK_T *prLink; ++ UINT32 u4StartIdx; ++ UINT32 u4PeerNum; ++ BOOLEAN fgIsListAll; ++ UINT8 ucMacZero[6]; ++ UINT32 u4HisIdx; ++ UINT8 ucNetTypeIndex; ++ ++ /* init */ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ u4StartIdx = 0; ++ u4PeerNum = 1; ++ fgIsListAll = TRUE; ++ kalMemZero(ucMacZero, sizeof(ucMacZero)); ++ ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ /* display common information */ ++ DBGLOG(TDLS, TRACE, "TDLS common:\n"); ++ DBGLOG(TDLS, TRACE, "\t\trFreeSwRfbList=%u\n", (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ DBGLOG(TDLS, TRACE, "\t\tjiffies=%u %ums (HZ=%d)\n", (UINT32) jiffies, (UINT32) kalGetTimeTick(), HZ); ++ ++ /* display disconnection history information */ ++ DBGLOG(TDLS, TRACE, "TDLS link history: %d\n", prGlueInfo->rTdlsLink.u4LinkIdx); ++ ++ for (u4HisIdx = prGlueInfo->rTdlsLink.u4LinkIdx + 1; u4HisIdx < TDLS_LINK_HISTORY_MAX; u4HisIdx++) { ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; ++ ++ if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) ++ continue; /* skip all zero */ ++ ++ DBGLOG(TDLS, TRACE, ++ "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", ++ u4HisIdx, prLink->aucPeerMac, ++ prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), ++ prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), ++ prLink->ucReasonCode, ++ prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); ++ ++ if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { ++ DBGLOG(TDLS, TRACE, ++ "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", ++ prLink->ucHtBa[0], prLink->ucHtBa[1], ++ prLink->ucHtBa[2], prLink->ucHtBa[3], ++ prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); ++ } ++ } ++ for (u4HisIdx = 0; u4HisIdx <= prGlueInfo->rTdlsLink.u4LinkIdx; u4HisIdx++) { ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; ++ ++ if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) ++ continue; /* skip all zero, use continue, not break */ ++ ++ DBGLOG(TDLS, TRACE, ++ "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", ++ u4HisIdx, (prLink->aucPeerMac), ++ prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), ++ prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), ++ prLink->ucReasonCode, ++ prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); ++ ++ if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { ++ DBGLOG(TDLS, TRACE, ++ "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", ++ prLink->ucHtBa[0], prLink->ucHtBa[1], ++ prLink->ucHtBa[2], prLink->ucHtBa[3], ++ prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); ++ } ++ } ++ DBGLOG(TDLS, TRACE, "\n"); ++ ++ /* display link information */ ++ if (prCmdContent != NULL) { ++ if (kalMemCmp(prCmdContent->aucPeerMac, ucMacZero, 6) != 0) { ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ prCmdContent->ucNetTypeIndex, prCmdContent->aucPeerMac); ++ if (prStaRec == NULL) ++ fgIsListAll = TRUE; ++ } ++ ++ ucNetTypeIndex = prCmdContent->ucNetTypeIndex; ++ } ++ ++ while (1) { ++ if (fgIsListAll == TRUE) { ++ /* list all TDLS peers */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, ucNetTypeIndex, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ if (prStaRec == NULL) ++ break; ++ } ++ ++ DBGLOG(TDLS, TRACE, "-------- TDLS %d: 0x %pM\n", u4PeerNum, (prStaRec->aucMacAddr)); ++ DBGLOG(TDLS, TRACE, "\t\t\t State %d, PM %d, Cap 0x%x\n", ++ prStaRec->ucStaState, prStaRec->fgIsInPS, prStaRec->u2CapInfo); ++ DBGLOG(TDLS, TRACE, "\t\t\t SetupDisable %d, ChSwDisable %d\n", ++ prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); ++ ++ if (fgIsListAll == FALSE) ++ break; /* only list one */ ++ } ++ ++ /* check if we need to clear all histories */ ++ if ((prCmdContent != NULL) && (prCmdContent->Content.rCmdInfoDisplay.fgIsToClearAllHistory == TRUE)) { ++ kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); ++ prGlueInfo->rTdlsLink.u4LinkIdx = TDLS_LINK_HISTORY_MAX - 1; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to display key information. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_KEY_INFO; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to record a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] fgIsTearDown TRUE: the link is torn down ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] fgIsFromUs TRUE: tear down is from us ++* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, ++ UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers) ++{ ++ TDLS_INFO_LINK_T *prLink; ++ ++ DBGLOG(TDLS, INFO, ++ " %s: record history for %pM %d %d %d %d\n", ++ __func__, pucPeerMac, prGlueInfo->rTdlsLink.u4LinkIdx, ++ fgIsTearDown, fgIsFromUs, u2ReasonCode); ++ ++ /* check duplicate one */ ++ if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) { ++ DBGLOG(TDLS, ERROR, " %s: u4LinkIdx >= TDLS_LINK_HISTORY_MAX\n", __func__); ++ ++ /* reset to 0 */ ++ prGlueInfo->rTdlsLink.u4LinkIdx = 0; ++ } ++ ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; ++ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) == 0) { ++ if ((prLink->ucReasonCode == u2ReasonCode) && (prLink->fgIsFromUs == fgIsFromUs)) { ++ /* same Peer MAC, Reason Code, Trigger source */ ++ if (fgIsTearDown == TRUE) { ++ if (prLink->jiffies_end != 0) { ++ /* already torn down */ ++ prLink->ucDupCount++; ++ return; ++ } ++ } else { ++ /* already built */ ++ prLink->ucDupCount++; ++ return; ++ } ++ } ++ } ++ ++ /* search old entry */ ++ if (fgIsTearDown == TRUE) { ++ /* TODO: need to search all entries to find it if we support multiple TDLS link design */ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { ++ /* error! can not find the link entry */ ++ DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); ++ return; ++ } ++ ++ prLink->jiffies_end = jiffies; ++ prLink->ucReasonCode = (UINT8) u2ReasonCode; ++ prLink->fgIsFromUs = fgIsFromUs; ++ } else { ++ /* record new one */ ++ prGlueInfo->rTdlsLink.u4LinkIdx++; ++ if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) ++ prGlueInfo->rTdlsLink.u4LinkIdx = 0; ++ ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; ++ ++ prLink->jiffies_start = jiffies; ++ prLink->jiffies_end = 0; ++ kalMemCopy(&prLink->aucPeerMac, pucPeerMac, 6); ++ prLink->ucReasonCode = 0; ++ prLink->fgIsFromUs = (UINT8) fgIsFromUs; ++ prLink->ucDupCount = 0; ++ ++ if (prOthers != NULL) { ++ /* record other parameters */ ++ TDLS_LINK_HIS_OTHERS_T *prHisOthers; ++ ++ prHisOthers = (TDLS_LINK_HIS_OTHERS_T *) prOthers; ++ if (prHisOthers->fgIsHt == TRUE) ++ prLink->ucHtCap |= TDLS_INFO_LINK_HT_CAP_SUP; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] eFmeStatus TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME ++* \param[in] pInfo other information ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, ++ UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo) ++{ ++ TDLS_INFO_LINK_T *prLink; ++ UINT32 u4LinkIdx; ++ UINT32 u4Tid; ++ ++ /* sanity check */ ++ if ((eFmeStatus < TDLS_HOST_EVENT_SF_BA) || (eFmeStatus > TDLS_HOST_EVENT_SF_BA_RSP_DECLINE)) { ++ /* do not care these frames */ ++ return; ++ } ++ ++ DBGLOG(TDLS, INFO, ++ " %s: update history for %pM %d %d\n", ++ __func__, (pucPeerMac), prGlueInfo->rTdlsLink.u4LinkIdx, eFmeStatus); ++ ++ /* init */ ++ u4LinkIdx = prGlueInfo->rTdlsLink.u4LinkIdx; ++ prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4LinkIdx]; ++ ++ /* TODO: need to search all entries to find it if we support multiple TDLS link design */ ++ if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { ++ /* error! can not find the link entry */ ++ DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); ++ return; ++ } ++ ++ /* update */ ++ u4Tid = *(UINT32 *) pInfo; ++ switch (eFmeStatus) { ++ case TDLS_HOST_EVENT_SF_BA: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_OK: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_OK; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_DECLINE: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_DECLINE; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_PEER: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_PEER; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_RSP_OK: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_OK; ++ break; ++ ++ case TDLS_HOST_EVENT_SF_BA_RSP_DECLINE: ++ prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_DECLINE; ++ break; ++ } ++ ++ /* display TDLS link history */ ++ TdlsInfoDisplay(prGlueInfo->prAdapter, NULL, 0, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure TDLS MIB parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_MIB_UPDATE; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure TDLS SETUP parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_SETUP_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to configure UAPSD parameters. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static TDLS_STATUS ++TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ TDLS_CMD_CORE_T *prCmdContent; ++ WLAN_STATUS rStatus; ++ ++ /* init command buffer */ ++ prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; ++ prCmdContent->u4Command = TDLS_CORE_CMD_UAPSD_CONF; ++ ++ /* send the command */ ++ rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ ++ CMD_ID_TDLS_CORE, /* ucCID */ ++ TRUE, /* fgSetQuery */ ++ FALSE, /* fgNeedResp */ ++ FALSE, /* fgIsOid */ ++ NULL, NULL, /* pfCmdTimeoutHandler */ ++ sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ ++ (PUINT_8) prCmdContent, /* pucInfoBuffer */ ++ NULL, /* pvSetQueryBuffer */ ++ 0 /* u4SetQueryBufferLen */ ++ ); ++ ++ if (rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to update frame status. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventFmeStatus(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus; ++ STA_RECORD_T *prStaRec; ++ UINT32 u4Tid; ++ ++ /* init */ ++ u4Tid = *(UINT32 *) prInBuf; ++ prInBuf += 4; /* skip u4EventSubId */ ++ ++ /* sanity check */ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); ++ if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) ++ return; ++ prInBuf++; ++ ++ /* update status */ ++ eFmeStatus = *prInBuf; ++ TdlsLinkHistoryRecordUpdate(prGlueInfo, prStaRec->aucMacAddr, eFmeStatus, &u4Tid); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to collect TDLS statistics from firmware. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ STA_RECORD_T *prStaRec; ++ STAT_CNT_INFO_FW_T *prStat; ++ UINT32 u4RateId; ++ ++ /* init */ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); ++ if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) ++ return; ++ ++ prInBuf += 4; /* skip prStaRec->ucIndex */ ++ ++ /* update statistics */ ++ kalMemCopy(&prStaRec->rTdlsStatistics.rFw, prInBuf, sizeof(prStaRec->rTdlsStatistics.rFw)); ++ ++ /* display statistics */ ++ prStat = &prStaRec->rTdlsStatistics.rFw; ++ ++ DBGLOG(TDLS, TRACE, " peer [%pM] statistics:\n", (prStaRec->aucMacAddr)); ++ DBGLOG(TDLS, TRACE, "\t\tT%d %d %d (P%d %d) (%dus) - E%d 0x%x - R%d (P%d)\n", ++ prStat->u4NumOfTx, prStat->u4NumOfTxOK, prStat->u4NumOfTxRetry, ++ prStat->u4NumOfPtiRspTxOk, prStat->u4NumOfPtiRspTxErr, ++ prStat->u4TxDoneAirTimeMax, ++ prStat->u4NumOfTxErr, prStat->u4TxErrBitmap, prStat->u4NumOfRx, prStat->u4NumOfPtiRspRx); ++ ++ DBGLOG(TDLS, TRACE, "\t\t"); ++ ++ for (u4RateId = prStat->u4TxRateOkHisId; u4RateId < STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM; u4RateId++) ++ DBGLOG(TDLS, TRACE, ++ "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); ++ for (u4RateId = 0; u4RateId < prStat->u4TxRateOkHisId; u4RateId++) ++ DBGLOG(TDLS, TRACE, ++ "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); ++ ++ DBGLOG(TDLS, TRACE, "\n\n"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to do tear down. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ STA_RECORD_T *prStaRec; ++ UINT16 u2ReasonCode; ++ UINT32 u4TearDownSubId; ++ UINT8 *pMac, aucZeroMac[6]; ++ ++ /* init */ ++ u4TearDownSubId = *(UINT32 *) prInBuf; ++ kalMemZero(aucZeroMac, sizeof(aucZeroMac)); ++ pMac = aucZeroMac; ++ ++ prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *(prInBuf + 4)); ++ if (prStaRec != NULL) ++ pMac = prStaRec->aucMacAddr; ++ ++ /* handle */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=PTI timeout\n", ++ __func__, pMac); ++ } else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=AGE timeout\n", ++ __func__, pMac); ++ } else { ++ DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=%d\n", ++ __func__, pMac, u4TearDownSubId); ++ } ++ ++ /* sanity check */ ++ if (prStaRec == NULL) ++ return; ++ ++ if (fgIsPtiTimeoutSkip == TRUE) { ++ /* skip PTI timeout event */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { ++ DBGLOG(TDLS, WARN, " %s: skip PTI timeout\n", __func__); ++ return; ++ } ++ } ++ ++ /* record history */ ++ if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_FAIL) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_NON_STATE3) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3; ++ else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN) ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN; ++ else { ++ /* shall not be here */ ++ u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN; ++ } ++ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, TRUE, u2ReasonCode, NULL); ++ ++ /* correct correct reason code for PTI or AGE timeout to supplicant */ ++ if ((u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT) || ++ (u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT)) { ++ u2ReasonCode = TDLS_REASON_CODE_UNREACHABLE; ++ } ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, NL80211_TDLS_TEARDOWN, u2ReasonCode, GFP_ATOMIC); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to do tx down. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static void TdlsEventTxDone(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ /* UINT32 u4FmeIdx; */ ++ UINT8 *pucFmeHdr; ++ UINT8 ucErrStatus; ++ ++ ucErrStatus = *(UINT32 *) prInBuf; ++ ++ pucFmeHdr = prInBuf + 4; /* skip ucErrStatus */ ++ ++ if (ucErrStatus == 0) ++ DBGLOG(TDLS, TRACE, " %s: OK to tx a TDLS action:", __func__); ++ else ++ DBGLOG(TDLS, TRACE, " %s: fail to tx a TDLS action (err=0x%x):", __func__, ucErrStatus); ++ #if 0 ++ /* dump TX packet content from wlan header */ ++ for (u4FmeIdx = 0; u4FmeIdx < (u4InBufLen - 4); u4FmeIdx++) { ++ if ((u4FmeIdx % 16) == 0) ++ DBGLOG(TDLS, TRACE, "\n"); ++ ++ DBGLOG(TDLS, TRACE, "%02x ", *pucFmeHdr++); ++ } ++ DBGLOG(TDLS, TRACE, "\n\n"); ++ #endif ++} ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to parse TDLS Extended Capabilities element. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE) ++{ ++ UINT_8 *pucIeExtCap; ++ ++ /* sanity check */ ++ if ((prStaRec == NULL) || (pucIE == NULL)) ++ return; ++ ++ if (IE_ID(pucIE) != ELEM_ID_EXTENDED_CAP) ++ return; ++ ++ /* ++ from bit0 ~ ++ ++ bit 38: TDLS Prohibited ++ The TDLS Prohibited subfield indicates whether the use of TDLS is prohibited. The ++ field is set to 1 to indicate that TDLS is prohibited and to 0 to indicate that TDLS is ++ allowed. ++ */ ++ if (IE_LEN(pucIE) < 5) ++ return; /* we need 39/8 = 5 bytes */ ++ ++ /* init */ ++ prStaRec->fgTdlsIsProhibited = FALSE; ++ prStaRec->fgTdlsIsChSwProhibited = FALSE; ++ ++ /* parse */ ++ pucIeExtCap = pucIE + 2; ++ pucIeExtCap += 4; /* shift to the byte we care about */ ++ ++ if ((*pucIeExtCap) & BIT(38 - 32)) ++ prStaRec->fgTdlsIsProhibited = TRUE; ++ if ((*pucIeExtCap) & BIT(39 - 32)) ++ prStaRec->fgTdlsIsChSwProhibited = TRUE; ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: AP [%pM] tdls prohibit bit=%d %d\n", ++ __func__, ++ prStaRec->aucMacAddr, prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to transmit a TDLS data frame from nl80211. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] ++* \param[in] ++* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *buf, size_t len) ++{ ++ ADAPTER_T *prAdapter; ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prAisBssInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ TDLS_MGMT_TX_INFO *prMgmtTxInfo; ++ ++ /* ++ Have correct behavior for STAUT receiving TDLS Setup Request after sending TDLS ++ Set Request and before receiving TDLS Setup Response: ++ -- Source Address of received Request is higher than own MAC address ++ -- Source Address of received Request is lower than own MAC address ++ ++ ==> STA with larger MAC address will send the response frame. ++ ++ Supplicant will do this in wpa_tdls_process_tpk_m1(). ++ */ ++ ++ /* sanity check */ ++ if ((wiphy == NULL) || (peer == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: wrong 0x%p 0x%p!\n", __func__, wiphy, peer); ++ return -EINVAL; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] %d %d %d 0x%p %u\n", ++ __func__, peer, action_code, dialog_token, status_code, buf, (UINT32) len); ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); ++ return -EINVAL; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ if (prAdapter->fgTdlsIsSup == FALSE) { ++ DBGLOG(TDLS, ERROR, " %s: firmware TDLS is not supported!\n", __func__); ++ return -EBUSY; ++ } ++ ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prAisBssInfo->fgTdlsIsProhibited == TRUE) { ++ /* do not send anything if TDLS is prohibited in the BSS */ ++ return 0; ++ } ++ ++ prMgmtTxInfo = kalMemAlloc(sizeof(TDLS_MGMT_TX_INFO), VIR_MEM_TYPE); ++ if (prMgmtTxInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate fail!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); ++ ++ if (peer != NULL) ++ kalMemCopy(prMgmtTxInfo->aucPeer, peer, 6); ++ prMgmtTxInfo->ucActionCode = action_code; ++ prMgmtTxInfo->ucDialogToken = dialog_token; ++ prMgmtTxInfo->u2StatusCode = status_code; ++ ++ if (buf != NULL) { ++ if (len > sizeof(prMgmtTxInfo->aucSecBuf)) { ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return -EINVAL; ++ } ++ prMgmtTxInfo->u4SecBufLen = len; ++ kalMemCopy(prMgmtTxInfo->aucSecBuf, buf, len); ++ } ++ ++ /* send the TDLS action data frame */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexMgmtCtrl, ++ prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* ++ clear all content to avoid any bug if we dont yet execute TdlsexMgmtCtrl() ++ then kalIoctl finishes ++ */ ++ kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return -EINVAL; ++ } ++ ++ kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to enable or disable TDLS link from upper layer. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] ++* \param[in] ++* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, ++ const u8 *peer, enum nl80211_tdls_operation oper) ++{ ++ ADAPTER_T *prAdapter; ++ GLUE_INFO_T *prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ TDLS_CMD_LINK_T rCmdLink; ++ ++ /* sanity check */ ++ if (peer == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: peer == NULL!\n", __func__); ++ return -EINVAL; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] %d %d\n", ++ __func__, peer, oper, (wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)); ++ ++ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) ++ return -ENOTSUPP; ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); ++ return -EINVAL; ++ } ++ prAdapter = prGlueInfo->prAdapter; ++ kalMemCopy(rCmdLink.aucPeerMac, peer, sizeof(rCmdLink.aucPeerMac)); ++ rCmdLink.fgIsEnabled = FALSE; ++ ++ /* ++ enum nl80211_tdls_operation { ++ NL80211_TDLS_DISCOVERY_REQ, ++ NL80211_TDLS_SETUP, ++ NL80211_TDLS_TEARDOWN, ++ NL80211_TDLS_ENABLE_LINK, ++ NL80211_TDLS_DISABLE_LINK, ++ }; ++ */ ++ ++ switch (oper) { ++ case NL80211_TDLS_ENABLE_LINK: ++ rCmdLink.fgIsEnabled = TRUE; ++ break; ++ ++ case NL80211_TDLS_DISABLE_LINK: ++ rCmdLink.fgIsEnabled = FALSE; ++ break; ++ ++ case NL80211_TDLS_TEARDOWN: ++ case NL80211_TDLS_SETUP: ++ case NL80211_TDLS_DISCOVERY_REQ: ++ /* we do not support setup/teardown/discovery from driver */ ++ return -ENOTSUPP; ++ ++ default: ++ return -ENOTSUPP; ++ } ++ ++ /* enable or disable TDLS link */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexLinkCtrl, &rCmdLink, sizeof(TDLS_CMD_LINK_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TDLS module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) ++{ ++ UINT_32 u4Subcmd; ++ static void (*TdlsCmdTestFunc)(P_GLUE_INFO_T, UINT_8 *, UINT_32); ++ ++ /* parse TDLS sub-command */ ++ u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); ++ DBGLOG(TDLS, INFO, " sub command = %u\n", (UINT32) u4Subcmd); ++ TdlsCmdTestFunc = NULL; ++ ++ /* handle different sub-command */ ++ switch (u4Subcmd) { ++#if TDLS_CFG_CMD_TEST /* only for unit test */ ++ case TDLS_CMD_TEST_TX_FRAME: ++ /* simulate to send a TDLS frame */ ++ /* TdlsCmdTestTxFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxFrame; ++ break; ++ ++ case TDLS_CMD_TEST_TX_TDLS_FRAME: ++ /* simulate to send a TDLS frame from supplicant */ ++ /* TdlsCmdTestTxTdlsFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxTdlsFrame; ++ break; ++ ++ case TDLS_CMD_TEST_RCV_FRAME: ++ /* simulate to receive a TDLS frame */ ++ /* TdlsCmdTestRvFrame(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestRvFrame; ++ break; ++ ++ case TDLS_CMD_TEST_PEER_ADD: ++ /* simulate to add a TDLS peer */ ++ /* TdlsCmdTestAddPeer(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestAddPeer; ++ break; ++ ++ case TDLS_CMD_TEST_PEER_UPDATE: ++ /* simulate to update a TDLS peer */ ++ /* TdlsCmdTestUpdatePeer(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestUpdatePeer; ++ break; ++ ++ case TDLS_CMD_TEST_DATA_FRAME: ++ /* simulate to send a data frame to the peer */ ++ /* TdlsCmdTestDataSend(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDataSend; ++ break; ++ ++ case TDLS_CMD_TEST_RCV_NULL: ++ /* simulate to receive a QoS null frame from the peer */ ++ /* TdlsCmdTestNullRecv(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestNullRecv; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_TX_FAIL: ++ /* command firmware to skip tx fail case */ ++ /* TdlsCmdTestTxFailSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestTxFailSkip; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_KEEP_ALIVE: ++ /* command firmware to skip keep alive function */ ++ /* TdlsCmdTestKeepAliveSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestKeepAliveSkip; ++ break; ++ ++ case TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT: ++ /* command firmware to skip channel switch timeout function */ ++ /* TdlsCmdTestChSwTimeoutSkip(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestChSwTimeoutSkip; ++ break; ++ ++ case TDLS_CMD_TEST_PROHIBIT_SET_IN_AP: ++ /* simulate to set Prohibited Bit in AP */ ++ /* TdlsCmdTestProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestProhibitedBitSet; ++ break; ++ ++ case TDLS_CMD_TEST_SCAN_DISABLE: ++ /* command to disable scan request to do channel switch */ ++ /* TdlsCmdTestScanCtrl(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestScanCtrl; ++ break; ++ ++ case TDLS_CMD_TEST_DATA_FRAME_CONT: ++ /* simulate to send a data frame to the peer periodically */ ++ /* TdlsCmdTestDataContSend(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDataContSend; ++ break; ++ ++ case TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP: ++ /* simulate to set channel switch Prohibited Bit in AP */ ++ /* TdlsCmdTestChSwProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestChSwProhibitedBitSet; ++ break; ++ ++ case TDLS_CMD_TEST_DELAY: ++ /* delay a where */ ++ /* TdlsCmdTestDelay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestDelay; ++ break; ++ ++ case TDLS_CMD_TEST_PTI_TX_FAIL: ++ /* simulate the tx done fail for PTI */ ++ /* TdlsCmdTestPtiTxDoneFail(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdTestPtiTxDoneFail; ++ break; ++#endif /* TDLS_CFG_CMD_TEST */ ++ ++ case TDLS_CMD_MIB_UPDATE: ++ /* update MIB parameters */ ++ /* TdlsCmdMibParamUpdate(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdMibParamUpdate; ++ break; ++ ++ case TDLS_CMD_UAPSD_CONF: ++ /* config UAPSD parameters */ ++ /* TdlsCmdUapsdConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdUapsdConf; ++ break; ++ ++ case TDLS_CMD_CH_SW_CONF: ++ /* enable or disable or start or stop channel switch function */ ++ /* TdlsCmdChSwConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdChSwConf; ++ break; ++ ++ case TDLS_CMD_SETUP_CONF: ++ /* config setup parameters */ ++ /* TdlsCmdSetupConf(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdSetupConf; ++ break; ++ ++ case TDLS_CMD_INFO: ++ /* display all TDLS information */ ++ /* TdlsCmdInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdInfoDisplay; ++ break; ++ ++ case TDLS_CMD_KEY_INFO: ++ /* display key information */ ++ /* TdlsCmdKeyInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ ++ TdlsCmdTestFunc = TdlsCmdKeyInfoDisplay; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (TdlsCmdTestFunc != NULL) ++ TdlsCmdTestFunc(prGlueInfo, prInBuf, u4InBufLen); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to record a disconnection event. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure ++* \param[in] fgIsTearDown TRUE: tear down ++* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] fgIsFromUs TRUE: tear down is from us ++* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, ++ BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode) ++{ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (pucPeerMac == NULL)) ++ return; ++ ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a inform from %pM %d %d\n", ++ __func__, pucPeerMac, fgIsFromUs, u2ReasonCode); ++ ++ /* record */ ++ TdlsLinkHistoryRecord(prGlueInfo, fgIsTearDown, pucPeerMac, fgIsFromUs, u2ReasonCode, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to send a command to TDLS module. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) ++{ ++ UINT32 u4EventId; ++ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (prInBuf == NULL)) ++ return; /* shall not be here */ ++ ++ /* handle */ ++ u4EventId = *(UINT32 *) prInBuf; ++ u4InBufLen -= 4; ++ ++ DBGLOG(TDLS, INFO, " %s: Rcv a event: %d\n", __func__, u4EventId); ++ ++ switch (u4EventId) { ++ case TDLS_HOST_EVENT_TEAR_DOWN: ++ TdlsEventTearDown(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_TX_DONE: ++ TdlsEventTxDone(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_FME_STATUS: ++ TdlsEventFmeStatus(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ ++ case TDLS_HOST_EVENT_STATISTICS: ++ TdlsEventStatistics(prGlueInfo, prInBuf + 4, u4InBufLen); ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return TDLS_STATUS_SUCCESS: do not set key and key infor. is queued ++ TDLS_STATUS_FAILURE: set key ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey) ++{ ++ STA_RECORD_T *prStaRec; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (prNewKey == NULL)) ++ return TDLS_STATUS_FAILURE; ++ ++ /* ++ supplicant will set key before updating station & enabling the link so we need to ++ backup the key information and set key when link is enabled ++ */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prNewKey->arBSSID); ++ if ((prStaRec != NULL) && IS_TDLS_STA(prStaRec)) { ++ DBGLOG(TDLS, TRACE, " %s: [%pM] queue key (len=%d) until link is enabled\n", ++ __func__, prNewKey->arBSSID, (UINT32) prNewKey->u4KeyLength); ++ ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ DBGLOG(TDLS, TRACE, " %s: [%pM] tear down the link due to STA_STATE_3\n", ++ __func__, prNewKey->arBSSID); ++ ++ /* re-key */ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, ++ prStaRec->aucMacAddr, TRUE, ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ /* backup the key */ ++ kalMemCopy(&prStaRec->rTdlsKeyTemp, prNewKey, sizeof(prStaRec->rTdlsKeyTemp)); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ return TDLS_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexInit(ADAPTER_T *prAdapter) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ ++ /* reset */ ++ kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to get any peer is in power save. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \retval TRUE (at least one peer is in power save) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter) ++{ ++ STA_RECORD_T *prStaRec; ++ UINT32 u4StaId, u4StartIdx; ++ ++ for (u4StaId = 0, u4StartIdx = 0; u4StaId < CFG_STA_REC_NUM; u4StaId++) { ++ /* list all TDLS peers */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ if (prStaRec == NULL) ++ break; ++ ++ if (prStaRec->fgIsInPS == TRUE) { ++ DBGLOG(TDLS, TRACE, " yes, at least one peer is in ps\n"); ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to enable or disable a TDLS link. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_LINK_T *prCmd; ++ BSS_INFO_T *prBssInfo; ++ STA_RECORD_T *prStaRec; ++ TDLS_LINK_HIS_OTHERS_T rHisOthers; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_LINK_T); ++ prCmd = (TDLS_CMD_LINK_T *) pvSetBuffer; ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ if (prStaRec == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer! %pM\n", ++ __func__, prCmd->aucPeerMac); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ if (prCmd->fgIsEnabled == TRUE) { ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); ++ DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_ENABLE_LINK\n", __func__); ++ ++ /* update key information after cnmStaRecChangeState(STA_STATE_3) */ ++ prStaRec->fgTdlsInSecurityMode = FALSE; ++ ++ if (prStaRec->rTdlsKeyTemp.u4Length > 0) { ++ UINT_32 u4BufLen; /* no use */ ++ ++ DBGLOG(TDLS, INFO, " %s: key len=%d\n", ++ __func__, (UINT32) prStaRec->rTdlsKeyTemp.u4Length); ++ ++ /* ++ reminder the function that we are CIPHER_SUITE_CCMP, ++ do not change cipher type to CIPHER_SUITE_WEP128 ++ */ ++ _wlanoidSetAddKey(prAdapter, &prStaRec->rTdlsKeyTemp, ++ prStaRec->rTdlsKeyTemp.u4Length, FALSE, CIPHER_SUITE_CCMP, &u4BufLen); ++ ++ /* clear the temp key */ ++ prStaRec->fgTdlsInSecurityMode = TRUE; ++ kalMemZero(&prStaRec->rTdlsKeyTemp, sizeof(prStaRec->rTdlsKeyTemp)); ++ } ++ ++ /* check if we need to disable channel switch function */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ if (prBssInfo->fgTdlsIsChSwProhibited == TRUE) { ++ TDLS_CMD_CORE_T rCmd; ++ ++ kalMemZero(&rCmd, sizeof(TDLS_CMD_CORE_T)); ++ rCmd.Content.rCmdChSwConf.ucNetTypeIndex = prStaRec->ucNetTypeIndex; ++ rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = FALSE; ++ kalMemCopy(rCmd.aucPeerMac, prStaRec->aucMacAddr, 6); ++ TdlsChSwConf(prAdapter, &rCmd, 0, 0); ++ ++ DBGLOG(TDLS, INFO, " %s: disable channel switch\n", __func__); ++ } ++ ++ TDLS_LINK_INCREASE(prGlueInfo); ++ ++ /* record link */ ++ if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) ++ rHisOthers.fgIsHt = TRUE; ++ else ++ rHisOthers.fgIsHt = FALSE; ++ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, FALSE, ++ prStaRec->aucMacAddr, !prStaRec->flgTdlsIsInitiator, 0, &rHisOthers); ++ } else { ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); /* release to other TDLS peers */ ++ DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_DISABLE_LINK\n", __func__); ++ ++ TDLS_LINK_DECREASE(prGlueInfo); ++/* while(1); //sample debug */ ++ } ++ ++ /* work-around link count */ ++ if ((TDLS_LINK_COUNT(prGlueInfo) < 0) || (TDLS_LINK_COUNT(prGlueInfo) > 1)) { ++ /* ERROR case: work-around to recount by searching all station records */ ++ UINT32 u4Idx; ++ ++ TDLS_LINK_COUNT_RESET(prGlueInfo); ++ ++ for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { ++ prStaRec = &prAdapter->arStaRec[u4Idx]; ++ ++ if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) ++ TDLS_LINK_INCREASE(prGlueInfo); ++ } ++ ++ if (TDLS_LINK_COUNT(prGlueInfo) > 1) { ++ /* number of links is still > 1 */ ++ DBGLOG(TDLS, INFO, " %s: cTdlsLinkCnt %d > 1?\n", ++ __func__, TDLS_LINK_COUNT(prGlueInfo)); ++ ++ TDLS_LINK_COUNT_RESET(prGlueInfo); ++ ++ /* free all TDLS links */ ++ for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { ++ prStaRec = &prAdapter->arStaRec[u4Idx]; ++ ++ if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ } ++ ++ /* maybe inform supplicant ? */ ++ } ++ } ++ ++ /* display TDLS link history */ ++ TdlsInfoDisplay(prAdapter, NULL, 0, NULL); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to send a TDLS action data frame. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_MGMT_TX_INFO *prMgmtTxInfo; ++ STA_RECORD_T *prStaRec; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_MGMT_TX_INFO); ++ prMgmtTxInfo = (TDLS_MGMT_TX_INFO *) pvSetBuffer; ++ ++ switch (prMgmtTxInfo->ucActionCode) { ++ case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: ++ prStaRec = NULL; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); ++ if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3)) { ++ /* rekey? we reject re-setup link currently */ ++ /* TODO: Still can setup link during rekey */ ++ ++ /* ++ return success to avoid supplicant clear TDLS entry; ++ Or we cannot send out any TDLS tear down frame to the peer ++ */ ++ DBGLOG(TDLS, TRACE, " %s: skip new setup on the exist link!\n", __func__); ++ return TDLS_STATUS_SUCCESS; ++ } ++ ++ prStaRec = NULL; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ case TDLS_FRM_ACTION_TEARDOWN: ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); ++#if 0 /* in some cases, the prStaRec is still NULL */ ++ /* ++ EX: if a peer sends us a TDLS setup request with wrong BSSID, ++ supplicant will not call TdlsexPeerAdd() to create prStaRec and ++ supplicant will send a TDLS setup response with status code 7. ++ ++ So in the case, prStaRec will be NULL. ++ */ ++ if (prStaRec == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); ++ return -EINVAL; ++ } ++#endif ++ break; ++ ++ /* ++ TODO: Discovery response frame ++ Note that the TDLS Discovery Response frame is not a TDLS frame but a 11 ++ Public Action frame. ++ In WiFi TDLS Tech Minutes June 8 2010.doc, ++ a public action frame (i.e. it is no longer an encapsulated data frame) ++ */ ++ ++ default: ++ DBGLOG(TDLS, ERROR, ++ " %s: wrong action_code %d!\n", __func__, prMgmtTxInfo->ucActionCode); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* send the TDLS data frame */ ++ if (prStaRec != NULL) { ++ DBGLOG(TDLS, INFO, " %s: [%pM] ps=%d status=%d\n", ++ __func__, prStaRec->aucMacAddr, ++ prStaRec->fgIsInPS, prMgmtTxInfo->u2StatusCode); ++ ++ if (prMgmtTxInfo->ucActionCode == TDLS_FRM_ACTION_TEARDOWN) { ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prMgmtTxInfo->aucPeer, ++ TRUE, prMgmtTxInfo->u2StatusCode, NULL); ++ } ++ } ++ ++ return TdlsDataFrameSend(prAdapter, ++ prStaRec, ++ prMgmtTxInfo->aucPeer, ++ prMgmtTxInfo->ucActionCode, ++ prMgmtTxInfo->ucDialogToken, ++ prMgmtTxInfo->u2StatusCode, ++ (UINT_8 *) prMgmtTxInfo->aucSecBuf, prMgmtTxInfo->u4SecBufLen); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to add a peer record. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexPeerAdd(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_PEER_ADD_T *prCmd; ++ BSS_INFO_T *prAisBssInfo; ++ STA_RECORD_T *prStaRec; ++ UINT_8 ucNonHTPhyTypeSet; ++ UINT32 u4StartIdx; ++ OS_SYSTIME rCurTime; ++ ++ /* sanity check */ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); ++ prCmd = (TDLS_CMD_PEER_ADD_T *) pvSetBuffer; ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ u4StartIdx = 0; ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ ++ /* check if any TDLS link exists because we only support one TDLS link currently */ ++ if (prStaRec == NULL) { ++ /* the MAC is new peer */ ++ prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); ++ ++ if (prStaRec != NULL) { ++ /* a building TDLS link exists */ ++ DBGLOG(TDLS, ERROR, ++ " %s: one TDLS link setup [%pM] is going...\n", ++ __func__, prStaRec->aucMacAddr); ++ ++ if (prStaRec->ucStaState != STA_STATE_3) { ++ /* check timeout */ ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsSetupStartTime, ++ SEC_TO_SYSTIME(TDLS_SETUP_TIMEOUT_SEC))) { ++ /* free the StaRec */ ++ cnmStaRecFree(prAdapter, prStaRec, TRUE); ++ ++ DBGLOG(TDLS, ERROR, ++ " %s: free going TDLS link setup [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ /* handle new setup */ ++ prStaRec = NULL; ++ } else ++ return TDLS_STATUS_FAILURE; ++ } else { ++ /* the TDLS is built and works fine, reject new one */ ++ return TDLS_STATUS_FAILURE; ++ } ++ } ++ } else { ++ if (prStaRec->ucStaState == STA_STATE_3) { ++ /* the peer exists, maybe TPK lifetime expired, supplicant wants to renew key */ ++ TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, ++ prStaRec->aucMacAddr, TRUE, ++ TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); ++ ++ /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ ++ cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: re-setup link for [%pM] maybe re-key?\n", ++ __func__, (prStaRec->aucMacAddr)); ++ return TDLS_STATUS_FAILURE; ++ } ++ } ++ ++ /* ++ create new entry if not exist ++ ++ 1. we are initiator ++ (1) send TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) got TDLS setup response and send TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ ++ 2. we are responder ++ (1) got TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) send TDLS setup response ++ (3) got TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ */ ++ if (prStaRec == NULL) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ if (prStaRec == NULL) { ++ /* shall not be here */ ++ DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ /* init the prStaRec */ ++ /* prStaRec will be zero first in cnmStaRecAlloc() */ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, prCmd->aucPeerMac); ++ ++/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); */ ++ } else { ++#if 0 ++ if ((prStaRec->ucStaState > STA_STATE_1) && (IS_TDLS_STA(prStaRec))) { ++ /* ++ test plan: The STAUT should locally tear down existing TDLS direct link and ++ respond with Set up Response frame. ++ */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++#endif ++ } ++ ++ /* reference to bssCreateStaRecFromBssDesc() and use our best capability */ ++ /* reference to assocBuildReAssocReqFrameCommonIEs() to fill elements */ ++ ++ /* prStaRec->u2CapInfo */ ++ /* TODO: Need to parse elements from setup request frame */ ++ prStaRec->u2OperationalRateSet = prAisBssInfo->u2OperationalRateSet; ++ prStaRec->u2BSSBasicRateSet = prAisBssInfo->u2BSSBasicRateSet; ++ prStaRec->u2DesiredNonHTRateSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ prStaRec->ucPhyTypeSet = prAisBssInfo->ucPhyTypeSet; ++ prStaRec->eStaType = STA_TYPE_TDLS_PEER; ++ ++ prStaRec->ucDesiredPhyTypeSet = /*prStaRec->ucPhyTypeSet & */ ++ prAdapter->rWifiVar.ucAvailablePhyTypeSet; ++ ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; ++ ++ /* check for Target BSS's non HT Phy Types */ ++ if (ucNonHTPhyTypeSet) { ++ if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; ++ } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; ++ } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++ prStaRec->fgHasBasicPhyType = TRUE; ++ } else { ++ /* use mandatory for 11N only BSS */ ++/* ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); */ ++ ++ prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; ++ prStaRec->fgHasBasicPhyType = FALSE; ++ } ++ ++ /* update non HT Desired Rate Set */ ++ { ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prStaRec->u2DesiredNonHTRateSet = ++ (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); ++ } ++ ++#if 0 /* TdlsexPeerAdd() will be called before we receive setup rsp in TdlsexRxFrameHandle() */ ++ /* check if the add is from the same peer in the 1st unhandled setup request frame */ ++ DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", ++ __func__, prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac); ++ ++ if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { ++ /* copy the HT capability from its setup request */ ++ kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); ++ ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); ++ ++ /* reset backup */ ++ kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); ++ kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); ++ ++ DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); ++ } ++#endif ++ ++ /* update WMM: must support due to UAPSD in TDLS link */ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = TRUE; ++ ++ /* update station record to firmware */ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ ++ /* update time */ ++ GET_CURRENT_SYSTIME(&prStaRec->rTdlsSetupStartTime); ++ ++ DBGLOG(TDLS, INFO, " %s: create a peer [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to update a peer record. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexPeerUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ TDLS_CMD_PEER_UPDATE_T *prCmd; ++ BSS_INFO_T *prAisBssInfo; ++ STA_RECORD_T *prStaRec; ++ IE_HT_CAP_T *prHtCap; ++ ++ /* sanity check */ ++ DBGLOG(TDLS, INFO, " %s\n", __func__); ++ ++ if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { ++ DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); ++ prCmd = (TDLS_CMD_PEER_UPDATE_T *) pvSetBuffer; ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ /* search old entry */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); ++ ++ /* ++ create new entry if not exist ++ ++ 1. we are initiator ++ (1) send TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) got TDLS setup response and send TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ ++ 2. we are responder ++ (1) got TDLS setup request ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); ++ create a station record with STA_STATE_1. ++ (2) send TDLS setup response ++ (3) got TDLS setup confirm ++ wpa_tdls_enable_link() ++ update a station record with STA_STATE_3. ++ */ ++ if ((prStaRec == NULL) || (prStaRec->fgIsInUse == 0)) { ++ DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ DBGLOG(TDLS, INFO, " %s: update a peer [%pM] %d -> %d, 0x%x\n", ++ __func__, (prStaRec->aucMacAddr), ++ prStaRec->ucStaState, STA_STATE_3, prStaRec->eStaType); ++ ++ if (!IS_TDLS_STA(prStaRec)) { ++ DBGLOG(TDLS, ERROR, " %s: peer is not TDLS one!\n", __func__); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* check if the add is from the same peer in the 1st unhandled setup request frame */ ++ DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", ++ __func__, (prGlueInfo->aucTdlsHtPeerMac), (prCmd->aucPeerMac)); ++ ++ if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { ++ /* copy the HT capability from its setup request */ ++ kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); ++ ++ prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); ++ ++ /* reset backup */ ++ kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); ++ kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); ++ ++ DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); ++ } ++ ++ /* update the record join time. */ ++ GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); ++ ++ /* update Station Record - Status/Reason Code */ ++ prStaRec->u2StatusCode = prCmd->u2StatusCode; ++ ++ /* prStaRec->ucStaState shall be STA_STATE_1 */ ++ ++ prStaRec->u2CapInfo = prCmd->u2Capability; ++/* prStaRec->u2OperationalRateSet */ ++ prStaRec->u2AssocId = 0; /* no use */ ++ prStaRec->u2ListenInterval = 0; /* unknown */ ++/* prStaRec->ucDesiredPhyTypeSet */ ++/* prStaRec->u2DesiredNonHTRateSet */ ++/* prStaRec->u2BSSBasicRateSet */ ++/* prStaRec->ucMcsSet */ ++/* prStaRec->fgSupMcs32 */ ++/* prStaRec->u2HtCapInfo */ ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsUapsdSupported = (prCmd->UapsdBitmap == 0) ? FALSE : TRUE; ++/* prStaRec->ucAmpduParam */ ++/* prStaRec->u2HtExtendedCap */ ++ prStaRec->u4TxBeamformingCap = 0; /* no use */ ++ prStaRec->ucAselCap = 0; /* no use */ ++ prStaRec->ucRCPI = 0; ++ prStaRec->ucBmpTriggerAC = prCmd->UapsdBitmap; ++ prStaRec->ucBmpDeliveryAC = prCmd->UapsdBitmap; ++ prStaRec->ucUapsdSp = prCmd->UapsdMaxSp; ++ ++ /* update HT */ ++#if (TDLS_CFG_HT_SUP == 1) ++ if (prCmd->fgIsSupHt == FALSE) { ++ /* no HT IE is from supplicant so we use the backup */ ++ prHtCap = (IE_HT_CAP_T *) &prStaRec->rTdlsHtCap; ++ ++ DBGLOG(TDLS, INFO, " %s: [%pM] update ht ie 0x%x\n", ++ __func__, (prStaRec->aucMacAddr), prHtCap->ucId); ++ ++ if (prHtCap->ucId == ELEM_ID_HT_CAP) { ++ prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; ++ prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; ++ ++ prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; ++ prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; ++ prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; ++ prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; ++ prStaRec->ucAselCap = prHtCap->ucAselCap; ++ prStaRec->ucDesiredPhyTypeSet |= PHY_TYPE_SET_802_11N; ++ } ++ } else { ++ /* TODO: use the HT IE from supplicant */ ++ } ++#endif /* TDLS_CFG_HT_SUP */ ++ ++ DBGLOG(TDLS, INFO, " %s: UAPSD 0x%x %d MCS=0x%x\n", ++ __func__, prCmd->UapsdBitmap, prCmd->UapsdMaxSp, prStaRec->ucMcsSet); ++ ++/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ ++ ++ DBGLOG(TDLS, INFO, " %s: update a peer [%pM]\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to check if we need to drop a TDLS action frame. ++* ++* \param[in] *pPkt Pointer to the struct sk_buff->data. ++* \param[in] ++* \param[in] ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt) ++{ ++ ADAPTER_T *prAdapter; ++ UINT8 ucActionId; ++ ++ /* sanity check */ ++ if ((pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) ++ return FALSE; /* not TDLS data frame htons(0x890d) */ ++ ++#if 0 /* supplicant handles this check */ ++ if (prStaRec == NULL) ++ return FALSE; /* shall not be here */ ++ ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a TDLS action frame (id=%d) %d %d\n", ++ __func__, *(pPkt + 13 + 4), prStaRec->fgTdlsIsProhibited, fgIsPtiTimeoutSkip); ++ ++ /* check if TDLS Prohibited bit is set in AP's beacon */ ++ if (prStaRec->fgTdlsIsProhibited == TRUE) ++ return TRUE; ++#endif ++ ++ ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ ++ ++ if (fgIsPtiTimeoutSkip == TRUE) { ++ /* also skip any tear down frame from the peer */ ++ if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) ++ return TRUE; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ DBGLOG(TDLS, INFO, ++ " %s: Rcv a TDLS action frame %d (%u)\n", ++ __func__, ucActionId, (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ ++ if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) { ++ DBGLOG(TDLS, WARN, " %s: Rcv a TDLS tear down frame %d, will DISABLE link\n", ++ __func__, *(pPkt + 13 + 4)); /* reason code */ ++ ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, pPkt + 6, FALSE, *(pPkt + 13 + 4), NULL); ++ ++ /* inform tear down to supplicant only in OPEN/NONE mode */ ++ /* ++ we need to tear down the link manually; or supplicant will display ++ "No FTIE in TDLS Teardown" and it will not tear down the link ++ */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ pPkt + 6, TDLS_FRM_ACTION_TEARDOWN, *(pPkt + 13 + 4), GFP_ATOMIC); ++ } ++#if 0 /* pass all to supplicant except same thing is handled in supplicant */ ++ if (((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_REQ) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_RSP) || ++ ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI_RSP)) { ++ return TRUE; ++ } ++#endif ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to parse some IEs in the setup frame from the peer. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] pPkt Pointer to the ethernet packet ++* ++* \retval None ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen) ++{ ++ ADAPTER_T *prAdapter; ++ STA_RECORD_T *prStaRec; ++ UINT8 ucActionId; ++ UINT8 *pucPeerMac, ucElmId, ucElmLen; ++ INT16 s2FmeLen; ++ ++ /* sanity check */ ++ if ((prGlueInfo == NULL) || (pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) ++ return; ++ ++ ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ ++ ++ if ((ucActionId != TDLS_FRM_ACTION_SETUP_REQ) && (ucActionId != TDLS_FRM_ACTION_SETUP_RSP)) ++ return; ++ ++ /* init */ ++ prAdapter = prGlueInfo->prAdapter; ++ pucPeerMac = pPkt + 6; ++ s2FmeLen = (INT16) u2PktLen; ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: get a setup frame %d from %pM\n", ++ __func__, ucActionId, (pucPeerMac)); ++ ++ if (ucActionId == TDLS_FRM_ACTION_SETUP_REQ) ++ pPkt += 12 + 2 + 2 + 1 + 1 + 2; /* skip action, dialog token, capability */ ++ else ++ pPkt += 12 + 2 + 2 + 1 + 2 + 1 + 2; /* skip action, status code, dialog token, capability */ ++ ++ /* check station record */ ++ prStaRec = cnmGetStaRecByAddress(prGlueInfo->prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, pucPeerMac); ++ ++ if (prStaRec == NULL) { ++ prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); ++ ++ if (prStaRec == NULL) { ++ /* TODO: only one TDLS entry, need to free old one if timeout */ ++ DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); ++ return; ++ } ++ ++ /* init the prStaRec */ ++ /* prStaRec will be zero first in cnmStaRecAlloc() */ ++ COPY_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMac); ++ ++ cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); ++ } ++ ++ /* backup HT IE to station record */ ++ /* TODO: Maybe our TDLS only supports non-11n */ ++ while (s2FmeLen > 0) { ++ ucElmId = *pPkt++; ++ ucElmLen = *pPkt++; ++ ++ switch (ucElmId) { ++ case ELEM_ID_HT_CAP: /* 0x2d */ ++ /* backup the HT IE of 1st unhandled setup request frame */ ++ if (prGlueInfo->rTdlsHtCap.ucId == 0x00) { ++ kalMemCopy(prGlueInfo->aucTdlsHtPeerMac, pucPeerMac, 6); ++ kalMemCopy(&prGlueInfo->rTdlsHtCap, pPkt - 2, ucElmLen + 2); ++ ++ /* ++ cannot backup in prStaRec; or ++ ++ 1. we build a TDLS link ++ 2. peer re-sends setup req ++ 3. we backup HT cap element ++ 4. supplicant disables the link ++ 5. we clear the prStaRec ++ */ ++ ++ DBGLOG(TDLS, TRACE, ++ " %s: %pM: find a HT IE\n", ++ __func__, (pucPeerMac)); ++ } ++ return; ++ ++ case ELEM_ID_EXTENDED_CAP: ++ /* TODO: backup the extended capability IE */ ++ break; ++ } ++ ++ pPkt += ucElmLen; ++ s2FmeLen -= (2 + ucElmLen); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! \brief This routine is called to get the TDLS station record. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure ++* \param[in] prInBuf A pointer to the command string buffer ++* \param[in] u4InBufLen The length of the buffer ++* \param[out] None ++* ++* \retval TDLS_STATUS_SUCCESS: this is TDLS packet ++* TDLS_STATUS_FAILURE: this is not TDLS packet ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo) ++{ ++ BSS_INFO_T *prBssInfo; ++ STA_RECORD_T *prStaRec; ++ TDLS_STATUS Status; ++ ++ /* sanity check */ ++ if ((prAdapter == NULL) || (prMsduInfo == NULL)) ++ return TDLS_STATUS_FAILURE; ++ ++ if (prAdapter->prGlueInfo == NULL) ++ return TDLS_STATUS_FAILURE; ++ if (TDLS_IS_NO_LINK_GOING(prAdapter->prGlueInfo)) ++ return TDLS_STATUS_FAILURE; ++ ++ /* init */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ Status = TDLS_STATUS_SUCCESS; ++ ++ /* get record by ether dest */ ++ prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMsduInfo->aucEthDestAddr); ++ ++ /* ++ TDLS Setup Request frames, TDLS Setup Response frames and TDLS Setup Confirm ++ frames shall be transmitted through the AP and shall not be transmitted to a group ++ address. ++ ++ 1. In first time, prStaRec == NULL or prStaRec->ucStaState != STA_STATE_3, ++ we will send them to AP; ++ 2. When link is still on, if you command to send TDLS setup from supplicant, ++ supplicant will DISABLE LINK first, prStaRec will be NULL then send TDLS ++ setup frame to the peer. ++ */ ++ ++ do { ++ if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3) && (IS_TDLS_STA(prStaRec))) { ++ /* ++ TDLS Test Case 5.3 Tear Down ++ Automatically sends TDLS Teardown frame to STA 2 via AP ++ ++ 11.21.5 TDLS Direct Link Teardown ++ The TDLS Teardown frame shall be sent over the direct path and the reason ++ code shall be set to "TDLS 40 direct link teardown for unspecified reason", ++ except when the TDLS peer STA is unreachable via the TDLS direct link, ++ in which case, the TDLS Teardown frame shall be sent through the AP and ++ the reason code shall be set to "TDLS direct link teardown due to TDLS peer ++ STA unreachable via the TDLS direct link". ++ */ ++ /* if (prStaRec->fgIsInPS == TRUE) */ ++ /* ++ check if the packet is tear down: ++ we do not want to use PTI to indicate the tear down and ++ we want to send the tear down to AP then AP help us to send it ++ */ ++ struct sk_buff *prSkb; ++ UINT8 *pEth; ++ UINT_16 u2EtherTypeLen; ++ ++ prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ if (prSkb != NULL) { ++ UINT8 ucActionCode, ucReasonCode; ++ ++ /* init */ ++ pEth = prSkb->data; ++ u2EtherTypeLen = (pEth[ETH_TYPE_LEN_OFFSET] << 8) | ++ (pEth[ETH_TYPE_LEN_OFFSET + 1]); ++ ucActionCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 3]; ++ ucReasonCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] | ++ (pEth[ETH_TYPE_LEN_OFFSET + 1 + 5] << 8); ++ ++ /* TDLS_REASON_CODE_UNREACHABLE: keep alive fail or PTI timeout */ ++ if ((u2EtherTypeLen == TDLS_FRM_PROT_TYPE) && ++ (ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && ++ (ucReasonCode == TDLS_REASON_CODE_UNREACHABLE)) { ++ /* ++ when we cannot reach the peer, ++ we need AP's help to send the tear down frame ++ */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prStaRec = prBssInfo->prStaRecOfAP; ++ if (prStaRec == NULL) { ++ Status = TDLS_STATUS_FAILURE; ++ break; ++ } ++#if 0 ++ /* change status code */ ++ pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] = TDLS_REASON_CODE_UNREACHABLE; ++#endif ++ } ++ } ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ } ++ } while (FALSE); ++ ++ DBGLOG(TDLS, INFO, " %s: (Status=%x) [%pM] ucStaRecIndex = %d!\n", ++ __func__, (INT32) Status, (prMsduInfo->aucEthDestAddr), ++ prMsduInfo->ucStaRecIndex); ++ return Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to check if we suffer timeout for TX quota empty case. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota) ++{ ++ OS_SYSTIME rCurTime; ++ ++ /* sanity check */ ++ if (!IS_TDLS_STA(prStaRec)) ++ return; ++ ++ if (FreeQuota != 0) { ++ /* reset timeout */ ++ prStaRec->rTdlsTxQuotaEmptyTime = 0; ++ return; ++ } ++ ++ /* work-around: check if the no free quota case is too long */ ++ GET_CURRENT_SYSTIME(&rCurTime); ++ ++ if (prStaRec->rTdlsTxQuotaEmptyTime == 0) { ++ prStaRec->rTdlsTxQuotaEmptyTime = rCurTime; ++ } else { ++ if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsTxQuotaEmptyTime, ++ SEC_TO_SYSTIME(TDLS_TX_QUOTA_EMPTY_TIMEOUT))) { ++ /* tear down the link */ ++ DBGLOG(TDLS, WARN, ++ " %s: [%pM] TX quota empty timeout!\n", ++ __func__, (prStaRec->aucMacAddr)); ++ ++ /* record disconnect history */ ++ TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, ++ TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY, NULL); ++ ++ /* inform tear down to supplicant only in OPEN/NONE mode */ ++ /* ++ we need to tear down the link manually; or supplicant will display ++ "No FTIE in TDLS Teardown" and it will not tear down the link ++ */ ++ cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, ++ prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, ++ TDLS_REASON_CODE_UNREACHABLE, GFP_ATOMIC); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to un-initialize variables in TDLS. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID TdlsexUninit(ADAPTER_T *prAdapter) ++{ ++#if TDLS_CFG_CMD_TEST ++ cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); ++#endif /* TDLS_CFG_CMD_TEST */ ++} ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++/* End of tdls.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c +new file mode 100644 +index 000000000000..5450cbb65183 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c +@@ -0,0 +1,741 @@ ++/* ++** Id: tdls_com.c#1 ++*/ ++ ++/*! \file tdls_com.c ++ \brief This file includes IEEE802.11z TDLS main support. ++*/ ++ ++/* ++** Log: tdls_com.c ++ * ++ * 11 13 2013 vend_samp.lin ++ * NULL ++ * Initial version. ++ */ ++ ++/******************************************************************************* ++ * C O M P I L E R F L A G S ++ ******************************************************************************** ++ */ ++ ++/******************************************************************************* ++ * E X T E R N A L R E F E R E N C E S ++ ******************************************************************************** ++ */ ++ ++#include "precomp.h" ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "tdls.h" ++ ++ /******************************************************************************* ++ * C O N S T A N T S ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * F U N C T I O N D E C L A R A T I O N S ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * P R I V A T E D A T A ++ ******************************************************************************** ++ */ ++ ++ /******************************************************************************* ++ * P R I V A T E F U N C T I O N S ++ ******************************************************************************** ++ */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to append general IEs. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure. ++* \param[in] u2StatusCode Status code. ++* \param[in] pPkt Pointer to the frame body ++* ++* \retval append length ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt) ++{ ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ UINT_32 u4NonHTPhyType; ++ UINT_16 u2SupportedRateSet; ++ UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; ++ UINT_8 ucAllSupportedRatesLen; ++ UINT_8 ucSupRatesLen; ++ UINT_8 ucExtSupRatesLen; ++ UINT_32 u4PktLen, u4IeLen; ++ BOOLEAN fg40mAllowed; ++ ++ /* reference to assocBuildReAssocReqFrameCommonIEs() */ ++ ++ /* init */ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ ++ /* 3. Frame Formation - (5) Supported Rates element */ ++ /* use all sup rate we can support */ ++ if (prStaRec != NULL) ++ u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; ++ else ++ u4NonHTPhyType = PHY_TYPE_ERP_INDEX; /* default */ ++ ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ ++ if (prStaRec != NULL) { ++ u2SupportedRateSet &= prStaRec->u2OperationalRateSet; ++ ++ if (u2SupportedRateSet == 0) ++ u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; ++ } ++ ++ rateGetDataRatesFromRateSet(u2SupportedRateSet, ++ prBssInfo->u2BSSBasicRateSet, aucAllSupportedRates, &ucAllSupportedRatesLen); ++ ++ ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? ++ ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); ++ ++ ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; ++ ++ if (ucSupRatesLen) { ++ SUP_RATES_IE(pPkt)->ucId = ELEM_ID_SUP_RATES; ++ SUP_RATES_IE(pPkt)->ucLength = ucSupRatesLen; ++ kalMemCopy(SUP_RATES_IE(pPkt)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (7) Extended sup rates element */ ++ if (ucExtSupRatesLen) { ++ ++ EXT_SUP_RATES_IE(pPkt)->ucId = ELEM_ID_EXTENDED_SUP_RATES; ++ EXT_SUP_RATES_IE(pPkt)->ucLength = ucExtSupRatesLen; ++ ++ kalMemCopy(EXT_SUP_RATES_IE(pPkt)->aucExtSupportedRates, ++ &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (8) Supported channels element */ ++ /* ++ The Supported channels element is included in Request frame and also in Response ++ frame if Status Code 0 (successful). ++ */ ++ if (u2StatusCode == 0) { ++ SUPPORTED_CHANNELS_IE(pPkt)->ucId = ELEM_ID_SUP_CHS; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 2; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[0] = 1; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[1] = 11; ++ ++#if CFG_SUPPORT_DFS ++ if (prAdapter->fgEnable5GBand == TRUE) { ++ /* 5G support */ ++ SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 10; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[2] = 36; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[3] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[4] = 52; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[5] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[6] = 149; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[7] = 4; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[8] = 165; ++ SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[9] = 4; ++ } ++#endif /* CFG_SUPPORT_DFS */ ++ ++ u4IeLen = IE_SIZE(pPkt); ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (14) HT capabilities element */ ++ ++ /* no need to check AP capability */ ++/* if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && */ ++ ++ /* ++ after we set ucPhyTypeSet to PHY_TYPE_SET_802_11N in TdlsexRxFrameHandle(), ++ supplicant will disable link if exists and we will clear prStaRec. ++ ++ finally, prStaRec->ucPhyTypeSet will also be 0 ++ ++ so we have a fix in TdlsexPeerAdd(). ++ */ ++ if (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { ++ /* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */ ++#if 0 /* always support */ ++ if (prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode == CONFIG_BW_20M) ++ fg40mAllowed = FALSE; ++ else ++#endif ++ fg40mAllowed = TRUE; ++ ++ u4IeLen = rlmFillHtCapIEByParams(fg40mAllowed, ++ prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, ++ prAdapter->rWifiVar.u8SupportRxSgi20, ++ prAdapter->rWifiVar.u8SupportRxSgi40, ++ prAdapter->rWifiVar.u8SupportRxGf, ++ prAdapter->rWifiVar.u8SupportRxSTBC, prBssInfo->eCurrentOPMode, pPkt); ++ ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ /* 3. Frame Formation - (17) WMM Information element */ ++ ++ /* always support */ ++/* if (prAdapter->rWifiVar.fgSupportQoS) */ ++ ++ { ++ /* force to support all UAPSD in TDLS link */ ++ u4IeLen = mqmGenerateWmmInfoIEByParam(TRUE /*prAdapter->rWifiVar.fgSupportUAPSD */ , ++ 0xf /*prPmProfSetupInfo->ucBmpDeliveryAC */ , ++ 0xf /*prPmProfSetupInfo->ucBmpTriggerAC */ , ++ WMM_MAX_SP_LENGTH_ALL /*prPmProfSetupInfo->ucUapsdSp */ , ++ pPkt); ++ ++ pPkt += u4IeLen; ++ u4PktLen += u4IeLen; ++ } ++ ++ return u4PktLen; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to transmit a TDLS data frame (setup req/rsp/confirm and tear down). ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* \param[in] prStaRec Pointer to the STA_RECORD_T structure. ++* \param[in] pPeerMac Pointer to the MAC of the TDLS peer ++* \param[in] ucActionCode TDLS Action ++* \param[in] ucDialogToken Dialog token ++* \param[in] u2StatusCode Status code ++* \param[in] pAppendIe Others IEs (here are security IEs from supplicant) ++* \param[in] AppendIeLen IE length of others IEs ++* ++* \retval TDLS_STATUS_xx ++*/ ++/*----------------------------------------------------------------------------*/ ++TDLS_STATUS ++TdlsDataFrameSend(ADAPTER_T *prAdapter, ++ STA_RECORD_T *prStaRec, ++ UINT_8 *pPeerMac, ++ UINT_8 ucActionCode, ++ UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen) ++{ ++#define LR_TDLS_FME_FIELD_FILL(__Len) \ ++do { \ ++ pPkt += __Len; \ ++ u4PktLen += __Len; \ ++} while (0) ++ ++ GLUE_INFO_T *prGlueInfo; ++ BSS_INFO_T *prBssInfo; ++ PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; ++ struct sk_buff *prMsduInfo; ++ MSDU_INFO_T *prMsduInfoMgmt; ++ UINT8 *pPkt, *pucInitiator, *pucResponder; ++ UINT32 u4PktLen, u4IeLen; ++ UINT16 u2CapInfo; ++/* UINT8 *pPktTemp; */ ++ ++ prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; ++ ++ DBGLOG(TDLS, INFO, " %s: 2040=%d\n", __func__, prGlueInfo->rTdlsLink.fgIs2040Sup); ++ ++ /* sanity check */ ++ if (prStaRec != NULL) { ++ if (prStaRec->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { ++ DBGLOG(TDLS, ERROR, ++ " %s: net index %d fail\n", __func__, prStaRec->ucNetTypeIndex); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ } else { ++ /* prStaRec maybe NULL in setup request */ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ } ++ ++ /* allocate/init packet */ ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ u4PktLen = 0; ++ prMsduInfo = NULL; ++ prMsduInfoMgmt = NULL; ++ ++ /* make up frame content */ ++ if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { ++ /* ++ The STAUT will not respond to a TDLS Discovery Request Frame with different BSSID. ++ Supplicant will check this in wpa_tdls_process_discovery_request(). ++ */ ++ ++ /* TODO: reduce 1600 to correct size */ ++ prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); ++ if (prMsduInfo == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ prMsduInfo->dev = prGlueInfo->prDevHandler; ++ if (prMsduInfo->dev == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); ++ kalPacketFree(prGlueInfo, prMsduInfo); ++ return TDLS_STATUS_FAILURE; ++ } ++ ++ /* 1. 802.3 header */ ++/* pPktTemp = pPkt; */ ++ kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); ++ *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 2. payload type */ ++ *pPkt = TDLS_FRM_PAYLOAD_TYPE; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - (1) Category */ ++ *pPkt = TDLS_FRM_CATEGORY; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } else { ++ /* discovery response */ ++ WLAN_MAC_HEADER_T *prHdr; ++ ++ prMsduInfoMgmt = (MSDU_INFO_T *) ++ cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); ++ if (prMsduInfoMgmt == NULL) { ++ DBGLOG(TDLS, ERROR, " %s: allocate mgmt pkt fail\n", __func__); ++ return TDLS_STATUS_RESOURCES; ++ } ++ ++ pPkt = (UINT8 *) prMsduInfoMgmt->prPacket; ++ prHdr = (WLAN_MAC_HEADER_T *) pPkt; ++ ++ /* 1. 802.11 header */ ++ prHdr->u2FrameCtrl = MAC_FRAME_ACTION; ++ prHdr->u2DurationID = 0; ++ kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); ++ kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, TDLS_FME_MAC_ADDR_LEN); ++ prHdr->u2SeqCtrl = 0; ++ LR_TDLS_FME_FIELD_FILL(sizeof(WLAN_MAC_HEADER_T)); ++ ++ /* Frame Formation - (1) Category */ ++ *pPkt = CATEGORY_PUBLIC_ACTION; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } ++ ++ /* 3. Frame Formation - (2) Action */ ++ *pPkt = ucActionCode; ++ LR_TDLS_FME_FIELD_FILL(1); ++ ++ /* 3. Frame Formation - Status Code */ ++ switch (ucActionCode) { ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_CONFIRM: ++ case TDLS_FRM_ACTION_TEARDOWN: ++ WLAN_SET_FIELD_16(pPkt, u2StatusCode); ++ LR_TDLS_FME_FIELD_FILL(2); ++ break; ++ } ++ ++ /* 3. Frame Formation - (3) Dialog token */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ *pPkt = ucDialogToken; ++ LR_TDLS_FME_FIELD_FILL(1); ++ } ++ ++ /* Fill elements */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* ++ Capability ++ ++ Support Rates ++ Extended Support Rates ++ Supported Channels ++ HT Capabilities ++ WMM Information Element ++ ++ Extended Capabilities ++ Link Identifier ++ ++ RSNIE ++ FTIE ++ Timeout Interval ++ */ ++ if (ucActionCode != TDLS_FRM_ACTION_CONFIRM) { ++ /* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be set */ ++ u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); ++ WLAN_SET_FIELD_16(pPkt, u2CapInfo); ++ LR_TDLS_FME_FIELD_FILL(2); ++ ++ /* 4. Append general IEs */ ++ /* ++ TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode ++ must be CONFIG_BW_20_40M. ++ ++ TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if ++ Tdls 20/40 is enabled. ++ */ ++ u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, u2StatusCode, pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 5. Frame Formation - Extended capabilities element */ ++ EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; ++ EXT_CAP_IE(pPkt)->ucLength = 5; ++ ++ EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ ++ ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); ++ /* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */ ++ EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } else { ++ /* 5. Frame Formation - WMM Parameter element */ ++ if (prAdapter->rWifiVar.fgSupportQoS) { ++ u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, ++ prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); ++ ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ } ++ } ++ ++ /* 6. Frame Formation - 20/40 BSS Coexistence */ ++ /* ++ Follow WiFi test plan, add 20/40 element to request/response/confirm. ++ */ ++/* if (prGlueInfo->rTdlsLink.fgIs2040Sup == TRUE) */ /* force to enable */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* ++ bit0 = 1: The Information Request field is used to indicate that a ++ transmitting STA is requesting the recipient to transmit a 20/40 BSS ++ Coexistence Management frame with the transmitting STA as the ++ recipient. ++ ++ bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP ++ that receives this information or reports of this information from ++ operating a 20/40 MHz BSS. ++ ++ bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit ++ a receiving AP from operating its BSS as a 20/40 MHz BSS. ++ */ ++ BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE; ++ BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; ++ BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; ++ LR_TDLS_FME_FIELD_FILL(3); ++ } ++ ++ /* 6. Frame Formation - HT Operation element */ ++/* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */ ++/* LR_TDLS_FME_FIELD_FILL(u4IeLen); */ ++ ++ /* 7. Frame Formation - Link identifier element */ ++ /* Note1: Link ID sequence must be correct; Or the calculated MIC will be error */ ++ /* ++ Note2: When we receive a setup request with link ID, Marvell will send setup response ++ to the peer in link ID, not the SA in the WLAN header. ++ */ ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; ++ TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); ++ ++ switch (ucActionCode) { ++ case TDLS_FRM_ACTION_SETUP_REQ: ++ case TDLS_FRM_ACTION_CONFIRM: ++ default: ++ /* we are initiator */ ++ pucInitiator = prBssInfo->aucOwnMacAddr; ++ pucResponder = pPeerMac; ++ ++ if (prStaRec != NULL) ++ prStaRec->flgTdlsIsInitiator = TRUE; ++ break; ++ ++ case TDLS_FRM_ACTION_SETUP_RSP: ++ case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ ++ if (prStaRec != NULL) ++ prStaRec->flgTdlsIsInitiator = FALSE; ++ break; ++ ++ case TDLS_FRM_ACTION_TEARDOWN: ++ if (prStaRec != NULL) { ++ if (prStaRec->flgTdlsIsInitiator == TRUE) { ++ /* we are initiator */ ++ pucInitiator = prBssInfo->aucOwnMacAddr; ++ pucResponder = pPeerMac; ++ } else { ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ } ++ } else { ++ /* peer is initiator */ ++ pucInitiator = pPeerMac; ++ pucResponder = prBssInfo->aucOwnMacAddr; ++ } ++ break; ++ } ++ ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pucInitiator, 6); ++ kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pucResponder, 6); ++ ++ u4IeLen = IE_SIZE(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ ++ /* 8. Append security IEs */ ++ /* ++ 11.21.5 TDLS Direct Link Teardown ++ If the STA has security enabled on the link 37 with the AP, then the FTIE shall be ++ included in the TDLS Teardown frame. ++ ++ For ralink station, it can accept our tear down without FTIE but marvell station. ++ */ ++/* if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) && (pAppendIe != NULL)) */ ++ if (pAppendIe != NULL) { ++ if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || ++ ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && ++ (prStaRec != NULL) && (prStaRec->fgTdlsInSecurityMode == TRUE))) { ++ kalMemCopy(pPkt, pAppendIe, AppendIeLen); ++ LR_TDLS_FME_FIELD_FILL(AppendIeLen); ++ } ++ } ++ ++ /* 7. Append Supported Operating Classes IE */ ++ if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { ++ /* Note: if we do not put the IE, Marvell STA will decline our TDLS setup request */ ++ u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); ++ LR_TDLS_FME_FIELD_FILL(u4IeLen); ++ } ++ ++ /* 11. send the data or management frame */ ++ if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { ++#if 0 ++ /* ++ Note1: remember to modify our MAC & AP MAC & peer MAC in LINK ID ++ Note2: dialog token in rsp & confirm must be same as sender. ++ */ ++ ++#if 1 ++ /* example for Ralink's and Broadcom's TDLS setup request frame in open/none */ ++ if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { ++#if 0 ++ /* mediatek */ ++ char buffer[] = { 0x31, 0x04, ++ 0x01, 0x08, 0x02, 0x04, 0x0b, 0x16, 0xc, 0x12, 0x18, 0x24, ++ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, ++ 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, ++ 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e ++ }; ++#endif ++ ++#if 1 ++ /* ralink *//* from capability */ ++ char buffer[] = { 0x21, 0x04, ++ 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, ++ 0x32, 0x04, 0x0c, 0x18, 0x30, 0x60, ++ 0x24, 0x06, 0x01, 0x0b, 0x24, 0x08, 0x95, 0x04, ++ 0x7f, 0x05, 0x01, 0x00, 0x00, 0x50, 0x20, ++ 0x3b, 0x10, 0x20, 0x01, 0x02, 0x03, 0x04, 0x0c, 0x16, 0x17, 0x18, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f ++ }; ++#endif ++#if 0 ++ /* 6630 */ ++ char buffer[] = { 0x01, 0x01, ++ 0x01, 0x04, 0x02, 0x04, 0x0b, 0x16, ++ 0x24, 0x02, 0x01, 0x0d, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0xff, ++ 0x2d, 0x1a, 0x61, 0x01, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00, ++ 0xbf, 0x0c, 0x30, 0x01, 0x80, 0x03, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, ++ 0x00, 0x00 ++ }; ++#endif ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++ ++#if 1 ++ if (ucActionCode == TDLS_FRM_ACTION_CONFIRM) { ++ /* Note: dialog token must be same as request */ ++#if 1 ++ /* ralink */ ++ char buffer[] = { 0x00, ++ 0x01, 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x00, 0x03, ++ 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, ++ 0x62, 0x32, 0x2f, 0x00 ++ }; ++#endif ++ ++#if 0 ++ /* 6630 */ ++ char buffer[] = { 0x00, ++ 0x01, ++ 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, ++ 0x48, 0x01, 0x01, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x3f, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00 ++ }; ++#endif ++ ++#if 0 ++ /* A/D die */ ++ char buffer[] = { 0x00, ++ 0x01, ++ 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x6b, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, ++ 0x00, 0x00, 0x00 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x38, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, ++ 0x1c, 0x1e, 0x20, 0x21, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e ++ }; ++#endif ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++ ++#else ++ ++#if 0 ++ /* for test in open/none */ ++ if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { ++ char buffer[] = { 0x01, 0x04, ++ 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, ++ 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, ++ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, ++ 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, ++ 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, ++ 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, ++ 0x48, 0x01, 0x01, ++ 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, ++ 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, ++ 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, ++ 0x1b, 0x1c, 0x1e, 0x20, 0x21 ++ }; ++ ++ pPktTemp += 18; ++ memcpy(pPktTemp, buffer, sizeof(buffer)); ++ u4PktLen = 18 + sizeof(buffer); ++ } ++#endif ++#endif /* 0 */ ++ ++ /* 9. Update packet length */ ++ prMsduInfo->len = u4PktLen; ++ dumpMemory8(prMsduInfo->data, u4PktLen); ++ ++ wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); ++ } else { ++ /* ++ A TDLS capable STA that receives a TDLS Discovery Request frame is required to ++ send the response "to the requesting STA, via the direct path." ++ However, prior to establishment of the direct link, the responding STA may not ++ know the rate capabilities of the requesting STA. In this case, the responding ++ STA shall send the TDLS Discovery Response frame using a rate from the ++ BSSBasicRateSet of the BSS to which the STA is currently associated. ++ */ ++ prMsduInfoMgmt->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; ++ prMsduInfoMgmt->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; ++ prMsduInfoMgmt->ucNetworkType = prBssInfo->ucNetTypeIndex; ++ prMsduInfoMgmt->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfoMgmt->fgIs802_1x = FALSE; ++ prMsduInfoMgmt->fgIs802_11 = TRUE; ++ prMsduInfoMgmt->u2FrameLength = u4PktLen; ++ prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfoMgmt->pfTxDoneHandler = NULL; ++ prMsduInfoMgmt->fgIsBasicRate = TRUE; /* use basic rate */ ++ ++ /* Send them to HW queue */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt); ++ } ++ ++ return TDLS_STATUS_SUCCESS; ++} ++ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* End of tdls_com.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c +new file mode 100644 +index 000000000000..af66ef95d17c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c +@@ -0,0 +1,491 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/wapi.c#1 ++*/ ++ ++/*! \file "wapi.c" ++ \brief This file including the WAPI related function. ++ ++ This file provided the macros and functions library support the wapi ie parsing, ++ cipher and AKM check to help the AP seleced deciding. ++*/ ++ ++/* ++** Log: wapi.c ++** ++** 10 24 2012 wh.su ++** [ALPS00376392] [klocwork 9.1] in wapi.c, line 344 ++** Use MAX_NUM_SUPPORTED_WAPI_AKM_SUITESfor avoid Klocwork warning. ++** ++** 10 24 2012 wh.su ++** [ALPS00376391] [klocwork 9.1] in wapi.c, line 311 ++** Use the MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES for avoid Klccwork waring. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the debug module level. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * fixed the network type ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 07 20 2010 wh.su ++ * ++ * . ++ * ++ * 04 06 2010 wh.su ++ * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query ++ * fixed the firmware return the broadcast frame at wrong tc. ++ * ++ * 03 03 2010 wh.su ++ * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize ++ * move the AIS specific variable for security to AIS specific structure. ++ * ++ * 12 18 2009 cm.chang ++ * [BORA00000018]Integrate WIFI part into BORA for the 1st time ++ * . ++ * ++ * Dec 8 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the function to check and update the default wapi tx ++ * ++ * Dec 7 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * adding the generate wapi ie function, and replace the tabe by space ++ * ++ * Nov 23 2009 mtk01088 ++ * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++#if CFG_SUPPORT_WAPI ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to generate WPA IE for ++* associate request frame. ++* ++* \param[in] prCurrentBss The Selected BSS description ++* ++* \retval The append WPA IE length ++* ++* \note ++* Called by: AIS module, Associate request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ PUINT_8 pucBuffer; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) ++ return; ++ ++ pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++ /* ASSOC INFO IE ID: 68 :0x44 */ ++ if (/* prWlanInfo->fgWapiMode && */ prAdapter->prGlueInfo->u2WapiAssocInfoIESz) { ++ kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWapiAssocInfoIEs, ++ prAdapter->prGlueInfo->u2WapiAssocInfoIESz); ++ prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WapiAssocInfoIESz; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to parse WAPI IE. ++* ++* \param[in] prInfoElem Pointer to the RSN IE ++* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the ++** WAPI information from the given WAPI IE ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo) ++{ ++ UINT_32 i; ++ INT_32 u4RemainWapiIeLen; ++ UINT_16 u2Version; ++ UINT_16 u2Cap = 0; ++ UINT_32 u4GroupSuite = WAPI_CIPHER_SUITE_WPI; ++ UINT_16 u2PairSuiteCount = 0; ++ UINT_16 u2AuthSuiteCount = 0; ++ PUCHAR pucPairSuite = NULL; ++ PUCHAR pucAuthSuite = NULL; ++ PUCHAR cp; ++ ++ DEBUGFUNC("wapiParseWapiIE"); ++ ++ ASSERT(prInfoElem); ++ ASSERT(prWapiInfo); ++ ++ /* Verify the length of the WAPI IE. */ ++ if (prInfoElem->ucLength < 6) { ++ DBGLOG(SEC, TRACE, "WAPI IE length too short (length=%d)\n", prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ /* Check WAPI version: currently, we only support version 1. */ ++ WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); ++ if (u2Version != 1) { ++ DBGLOG(SEC, TRACE, "Unsupported WAPI IE version: %d\n", u2Version); ++ return FALSE; ++ } ++ ++ cp = (PUCHAR) &prInfoElem->u2AuthKeyMgtSuiteCount; ++ u4RemainWapiIeLen = (INT_32) prInfoElem->ucLength - 2; ++ ++ do { ++ if (u4RemainWapiIeLen == 0) ++ break; ++ ++ /* ++ AuthCount : 2 ++ AuthSuite : 4 * authSuiteCount ++ PairwiseCount: 2 ++ PairwiseSuite: 4 * pairSuiteCount ++ GroupSuite : 4 ++ Cap : 2 */ ++ ++ /* Parse the Authentication and Key Management Cipher Suite Count ++ field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); ++ cp += 2; ++ u4RemainWapiIeLen -= 2; ++ ++ /* Parse the Authentication and Key Management Cipher Suite List ++ field. */ ++ i = (UINT_32) u2AuthSuiteCount * 4; ++ if (u4RemainWapiIeLen < (INT_32) i) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucAuthSuite = cp; ++ ++ cp += i; ++ u4RemainWapiIeLen -= (INT_32) i; ++ ++ if (u4RemainWapiIeLen == 0) ++ break; ++ ++ /* Parse the Pairwise Key Cipher Suite Count field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite count (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); ++ cp += 2; ++ u4RemainWapiIeLen -= 2; ++ ++ /* Parse the Pairwise Key Cipher Suite List field. */ ++ i = (UINT_32) u2PairSuiteCount * 4; ++ if (u4RemainWapiIeLen < (INT_32) i) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite list (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ pucPairSuite = cp; ++ ++ cp += i; ++ u4RemainWapiIeLen -= (INT_32) i; ++ ++ /* Parse the Group Key Cipher Suite field. */ ++ if (u4RemainWapiIeLen < 4) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in group cipher suite (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_32(cp, &u4GroupSuite); ++ cp += 4; ++ u4RemainWapiIeLen -= 4; ++ ++ /* Parse the WAPI u2Capabilities field. */ ++ if (u4RemainWapiIeLen < 2) { ++ DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in WAPI capabilities (IE len: %d)\n", ++ prInfoElem->ucLength); ++ return FALSE; ++ } ++ ++ WLAN_GET_FIELD_16(cp, &u2Cap); ++ u4RemainWapiIeLen -= 2; ++ ++ /* Todo:: BKID support */ ++ } while (FALSE); ++ ++ /* Save the WAPI information for the BSS. */ ++ ++ prWapiInfo->ucElemId = ELEM_ID_WAPI; ++ ++ prWapiInfo->u2Version = u2Version; ++ ++ prWapiInfo->u4GroupKeyCipherSuite = u4GroupSuite; ++ ++ DBGLOG(SEC, LOUD, "WAPI: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", ++ u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), ++ (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); ++ ++ if (pucPairSuite) { ++ /* The information about the pairwise key cipher suites is present. */ ++ if (u2PairSuiteCount > MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES) ++ u2PairSuiteCount = MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES; ++ ++ prWapiInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucPairSuite, &prWapiInfo->au4PairwiseKeyCipherSuite[i]); ++ pucPairSuite += 4; ++ ++ DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the pairwise key cipher suites is not present. ++ Use the default chipher suite for WAPI: WPI. */ ++ prWapiInfo->u4PairwiseKeyCipherSuiteCount = 1; ++ prWapiInfo->au4PairwiseKeyCipherSuite[0] = WAPI_CIPHER_SUITE_WPI; ++ ++ DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ if (pucAuthSuite) { ++ /* The information about the authentication and key management suites ++ is present. */ ++ if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_WAPI_AKM_SUITES) ++ u2AuthSuiteCount = MAX_NUM_SUPPORTED_WAPI_AKM_SUITES; ++ ++ prWapiInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; ++ ++ for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { ++ WLAN_GET_FIELD_32(pucAuthSuite, &prWapiInfo->au4AuthKeyMgtSuite[i]); ++ pucAuthSuite += 4; ++ ++ DBGLOG(SEC, LOUD, "WAPI: AKM suite [%d]: %02x-%02x-%02x-%02x\n", ++ (UINT_8) i, (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); ++ } ++ } else { ++ /* The information about the authentication and key management suites ++ is not present. Use the default AKM suite for WAPI. */ ++ prWapiInfo->u4AuthKeyMgtSuiteCount = 1; ++ prWapiInfo->au4AuthKeyMgtSuite[0] = WAPI_AKM_SUITE_802_1X; ++ ++ DBGLOG(SEC, LOUD, "WAPI: AKM suite: %02x-%02x-%02x-%02x (default)\n", ++ (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), ++ (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); ++ } ++ ++ prWapiInfo->u2WapiCap = u2Cap; ++ DBGLOG(SEC, LOUD, "WAPI: cap: 0x%04x\n", prWapiInfo->u2WapiCap); ++ ++ return TRUE; ++} /* wapiParseWapiIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to perform WAPI policy selection for a given BSS. ++* ++* \param[in] prAdapter Pointer to the adapter object data area. ++* \param[in] prBss Pointer to the BSS description ++* ++* \retval TRUE - The WAPI policy selection for the given BSS is ++* successful. The selected pairwise and group cipher suites ++* are returned in the BSS description. ++* \retval FALSE - The WAPI policy selection for the given BSS is failed. ++* The driver shall not attempt to join the given BSS. ++* ++* \note The Encrypt status matched score will save to bss for final ap select. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) ++{ ++ UINT_32 i; ++ UINT_32 u4PairwiseCipher = 0; ++ UINT_32 u4GroupCipher = 0; ++ UINT_32 u4AkmSuite = 0; ++ P_WAPI_INFO_T prBssWapiInfo; ++ P_WLAN_INFO_T prWlanInfo; ++ ++ DEBUGFUNC("wapiPerformPolicySelection"); ++ ++ ASSERT(prBss); ++ ++ /* Notice!!!! WAPI AP not set the privacy bit for WAI and WAI-PSK at WZC configuration mode */ ++ prWlanInfo = &prAdapter->rWlanInfo; ++ ++ if (prBss->fgIEWAPI) { ++ prBssWapiInfo = &prBss->rIEWAPI; ++ } else { ++ if (prAdapter->rWifiVar.rConnSettings.fgWapiMode == FALSE) { ++ DBGLOG(SEC, TRACE, "-- No Protected BSS\n"); ++ return TRUE; ++ } ++ DBGLOG(SEC, TRACE, "WAPI Information Element does not exist.\n"); ++ return FALSE; ++ } ++ ++ /* Select pairwise/group ciphers */ ++ for (i = 0; i < prBssWapiInfo->u4PairwiseKeyCipherSuiteCount; i++) { ++ if (prBssWapiInfo->au4PairwiseKeyCipherSuite[i] == ++ prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher) { ++ u4PairwiseCipher = prBssWapiInfo->au4PairwiseKeyCipherSuite[i]; ++ } ++ } ++ if (prBssWapiInfo->u4GroupKeyCipherSuite == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher) ++ u4GroupCipher = prBssWapiInfo->u4GroupKeyCipherSuite; ++ ++ /* Exception handler */ ++ /* If we cannot find proper pairwise and group cipher suites to join the ++ BSS, do not check the supported AKM suites. */ ++ if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { ++ DBGLOG(SEC, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", ++ u4PairwiseCipher, u4GroupCipher); ++ return FALSE; ++ } ++ ++ /* Select AKM */ ++ /* If the driver cannot support any authentication suites advertised in ++ the given BSS, we fail to perform RSNA policy selection. */ ++ /* Attempt to find any overlapping supported AKM suite. */ ++ for (i = 0; i < prBssWapiInfo->u4AuthKeyMgtSuiteCount; i++) { ++ if (prBssWapiInfo->au4AuthKeyMgtSuite[i] == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite) { ++ u4AkmSuite = prBssWapiInfo->au4AuthKeyMgtSuite[i]; ++ break; ++ } ++ } ++ ++ if (u4AkmSuite == 0) { ++ DBGLOG(SEC, TRACE, "Cannot support any AKM suites\n"); ++ return FALSE; ++ } ++ ++ DBGLOG(SEC, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4PairwiseCipher & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), ++ (UINT_8) (u4GroupCipher & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), ++ (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); ++ ++ DBGLOG(SEC, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", ++ (UINT_8) (u4AkmSuite & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), ++ (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); ++ ++ return TRUE; ++} /* wapiPerformPolicySelection */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is use for wapi mode, to update the current wpi tx idx ? 0 :1 . ++* ++* \param[in] prStaRec Pointer to the Sta record ++* \param[out] ucWlanIdx The Rx status->wlanidx field ++* ++* \retval TRUE - Succeeded ++* \retval FALSE - Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wapiUpdateTxKeyIdx(IN P_STA_RECORD_T prStaRec, IN UINT_8 ucWlanIdx) ++{ ++ UINT_8 ucKeyId; ++ ++ if ((ucWlanIdx & BITS(0, 3)) == CIPHER_SUITE_WPI) { ++ ++ ucKeyId = ((ucWlanIdx & BITS(4, 5)) >> 4); ++ ++ if (ucKeyId != g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey) { ++ DBGLOG(RSN, STATE, ++ "Change wapi key index from %d->%d\n", ++ g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey, ucKeyId); ++ g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey = ucKeyId; ++ ++ prStaRec->ucWTEntry = ++ (ucKeyId == ++ WTBL_AIS_BSSID_WAPI_IDX_0) ? WTBL_AIS_BSSID_WAPI_IDX_0 : WTBL_AIS_BSSID_WAPI_IDX_1; ++ } ++ } ++} ++#endif ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c +new file mode 100644 +index 000000000000..f54d22941148 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c +@@ -0,0 +1,301 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/mgmt/wnm.c#1 ++*/ ++ ++/*! \file "wnm.c" ++ \brief This file includes the 802.11v default vale and functions. ++*/ ++ ++/* ++** Log: wnm.c ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_802_11V ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define WNM_MAX_TOD_ERROR 0 ++#define WNM_MAX_TOA_ERROR 0 ++#define MICRO_TO_10NANO(x) ((x)*100) ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++static UINT_8 ucTimingMeasToken; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11v wnm category action frame. ++* ++* ++* \note ++* Called by: Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_ACTION_FRAME prRxFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ if (prRxFrame->ucAction == ACTION_WNM_TIMING_MEASUREMENT_REQUEST) { ++ wnmTimingMeasRequest(prAdapter, prSwRfb); ++ return; ++ } ++#endif ++ ++ DBGLOG(WNM, TRACE, "Unsupport WNM action frame: %d\n", prRxFrame->ucAction); ++} ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to report timing measurement data. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, TRACE, "wnmReportTimingMeas: u4ToD %x u4ToA %x", u4ToD, u4ToA); ++ ++ if (!prStaRec->rWNMTimingMsmt.ucTrigger) ++ return; ++ ++ prStaRec->rWNMTimingMsmt.u4ToD = MICRO_TO_10NANO(u4ToD); ++ prStaRec->rWNMTimingMsmt.u4ToA = MICRO_TO_10NANO(u4ToA); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will handle TxDone(TimingMeasurement) Event. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. ++* @param[in] rTxDoneStatus Return TX status of the Timing Measurement frame. ++* ++* @retval WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ DBGLOG(WNM, LOUD, "EVENT-TX DONE: Current Time = %u\n", kalGetTimeTick()); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ ++ ++ DBGLOG(WNM, TRACE, "wnmRunEventTimgingMeasTxDone: ucDialog %d ucFollowUp %d u4ToD %x u4ToA %x", ++ prStaRec->rWNMTimingMsmt.ucDialogToken, ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken, ++ prStaRec->rWNMTimingMsmt.u4ToD, prStaRec->rWNMTimingMsmt.u4ToA); ++ ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, NULL); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of wnmRunEventTimgingMeasTxDone() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will compose the Timing Measurement frame. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] prStaRec Pointer to the STA_RECORD_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME prTxFrame; ++ UINT_16 u2PayloadLen; ++ ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; ++ ASSERT(prBssInfo); ++ ++ prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); ++ ++ if (!prMsduInfo) ++ return; ++ ++ prTxFrame = (P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME) ++ ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); ++ ++ prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; ++ ++ COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); ++ COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); ++ ++ prTxFrame->ucCategory = CATEGORY_UNPROTECTED_WNM_ACTION; ++ prTxFrame->ucAction = ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT; ++ ++ /* 3 Compose the frame body's frame. */ ++ prTxFrame->ucDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; ++ prTxFrame->ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken; ++ prTxFrame->u4ToD = prStaRec->rWNMTimingMsmt.u4ToD; ++ prTxFrame->u4ToA = prStaRec->rWNMTimingMsmt.u4ToA; ++ prTxFrame->ucMaxToDErr = WNM_MAX_TOD_ERROR; ++ prTxFrame->ucMaxToAErr = WNM_MAX_TOA_ERROR; ++ ++ u2PayloadLen = 2 + ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN; ++ ++ /* 4 Update information of MSDU_INFO_T */ ++ prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ ++ prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; ++ prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; ++ prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; ++ prMsduInfo->fgIs802_1x = FALSE; ++ prMsduInfo->fgIs802_11 = TRUE; ++ prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; ++ prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); ++ prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; ++ prMsduInfo->fgIsBasicRate = FALSE; ++ ++ DBGLOG(WNM, TRACE, "wnmComposeTimingMeasFrame: ucDialogToken %d ucFollowUpDialogToken %d u4ToD %x u4ToA %x\n", ++ prTxFrame->ucDialogToken, prTxFrame->ucFollowUpDialogToken, ++ prTxFrame->u4ToD, prTxFrame->u4ToA); ++ ++ /* 4 Enqueue the frame to send this action frame. */ ++ nicTxEnqueueMsdu(prAdapter, prMsduInfo); ++ ++ return; ++ ++} /* end of wnmComposeTimingMeasFrame() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* ++* \brief This routine is called to process the 802.11v timing measurement request. ++* ++* ++* \note ++* Handle Rx mgmt request ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_ACTION_WNM_TIMING_MEAS_REQ_FRAME prRxFrame = NULL; ++ P_STA_RECORD_T prStaRec; ++ ++ prRxFrame = (P_ACTION_WNM_TIMING_MEAS_REQ_FRAME) prSwRfb->pvHeader; ++ if (!prRxFrame) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, TRACE, "IEEE 802.11: Received Timing Measuremen Request from %pM\n" ++ prStaRec->aucMacAdd); ++ ++ /* reset timing msmt */ ++ prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; ++ prStaRec->rWNMTimingMsmt.ucTrigger = prRxFrame->ucTrigger; ++ if (!prRxFrame->ucTrigger) ++ return; ++ ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); ++} ++ ++#if WNM_UNIT_TEST ++VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex) ++{ ++ P_STA_RECORD_T prStaRec; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); ++ if ((!prStaRec) || (!prStaRec->fgIsInUse)) ++ return; ++ ++ DBGLOG(WNM, INFO, "IEEE 802.11v: Test Timing Measuremen Request from %pM\n", ++ prStaRec->aucMacAddr); ++ ++ prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; ++ prStaRec->rWNMTimingMsmt.ucTrigger = 1; ++ ++ prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; ++ prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; ++ ++ wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); ++} ++#endif ++ ++#endif /* CFG_SUPPORT_802_11V_TIMING_MEASUREMENT */ ++ ++#endif /* CFG_SUPPORT_802_11V */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c +new file mode 100644 +index 000000000000..6f1bb6fd771e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c +@@ -0,0 +1,254 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/cmd_buf.c#1 ++*/ ++ ++/*! \file "cmd_buf.c" ++ \brief This file contain the management function of internal Command Buffer ++ for CMD_INFO_T. ++ ++ We'll convert the OID into Command Packet and then send to FW. Thus we need ++ to copy the OID information to Command Buffer for following reasons. ++ 1. The data structure of OID information may not equal to the data structure of ++ Command, we cannot use the OID buffer directly. ++ 2. If the Command was not generated by driver we also need a place to store the ++ information. ++ 3. Because the CMD is NOT FIFO when doing memory allocation (CMD will be generated ++ from OID or interrupt handler), thus we'll use the Block style of Memory Allocation ++ here. ++*/ ++ ++/* ++** Log: cmd_buf.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 02 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. clear prPendingCmdInfo properly ++ * * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-13 21:59:08 GMT mtk01084 ++** remove un-neceasary spaces ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-05-20 12:24:26 GMT mtk01461 ++** Increase CMD Buffer - HIF_RX_HW_APPENDED_LEN when doing CMD_INFO_T allocation ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 09:41:08 GMT mtk01461 ++** Add init of Driver Domain MCR flag and fix lint MTK WARN ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-17 19:51:45 GMT mtk01461 ++** allocation function of CMD_INFO_T ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static BOOLEAN fgCmdDumpIsDone = FALSE; ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to initial the MGMT memory pool for CMD Packet. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ QUEUE_INITIALIZE(&prAdapter->rFreeCmdList); ++ ++ for (i = 0; i < CFG_TX_MAX_CMD_PKT_NUM; i++) { ++ prCmdInfo = &prAdapter->arHifCmdDesc[i]; ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ } ++ fgCmdDumpIsDone = FALSE; ++} /* end of cmdBufInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief dump CMD queue and print to trace, for debug use only ++* @param[in] prQueue Pointer to the command Queue to be dumped ++* @param[in] quename Name of the queue ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName) ++{ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_HEAD(prQueue); ++ ++ DBGLOG(NIC, INFO, "Dump CMD info for %s, Elem number:%u\n", queName, prQueue->u4NumElem); ++ while (prCmdInfo) { ++ P_CMD_INFO_T prCmdInfo1, prCmdInfo2, prCmdInfo3; ++ ++ prCmdInfo1 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo); ++ if (!prCmdInfo1) { ++ DBGLOG(NIC, INFO, "CID:%d SEQ:%d\n", prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum); ++ break; ++ } ++ prCmdInfo2 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo1); ++ if (!prCmdInfo2) { ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, ++ prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum); ++ break; ++ } ++ prCmdInfo3 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo2); ++ if (!prCmdInfo3) { ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, ++ prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum, ++ prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum); ++ break; ++ } ++ DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", ++ prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, ++ prCmdInfo1->ucCmdSeqNum, prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum, ++ prCmdInfo3->ucCID, prCmdInfo3->ucCmdSeqNum); ++ prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo3); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Allocate CMD_INFO_T from a free list and MGMT memory pool. ++* ++* @param[in] prAdapter Pointer to the Adapter structure. ++* @param[in] u4Length Length of the frame buffer to allocate. ++* ++* @retval NULL Pointer to the valid CMD Packet handler ++* @retval !NULL Fail to allocat CMD Packet ++*/ ++/*----------------------------------------------------------------------------*/ ++P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("cmdBufAllocateCmdInfo"); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ /* Setup initial value in CMD_INFO_T */ ++ /* Start address of allocated memory */ ++ prCmdInfo->pucInfoBuffer = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); ++ ++ if (prCmdInfo->pucInfoBuffer == NULL) { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ prCmdInfo = NULL; ++ ++ DBGLOG(NIC, ERROR, "Allocate prCmdInfo->pucInfoBuffer fail!\n"); ++ } else { ++ prCmdInfo->u2InfoBufLen = 0; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ } ++ fgCmdDumpIsDone = FALSE; ++ } else if (!fgCmdDumpIsDone) { ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ P_QUE_T prCmdQue = &prGlueInfo->rCmdQueue; ++ P_QUE_T prPendingCmdQue = &prAdapter->rPendingCmdQueue; ++ P_TX_TCQ_STATUS_T prTc = &prAdapter->rTxCtrl.rTc; ++ ++ fgCmdDumpIsDone = TRUE; ++ cmdBufDumpCmdQueue(prCmdQue, "waiting Tx CMD queue"); ++ cmdBufDumpCmdQueue(prPendingCmdQue, "waiting response CMD queue"); ++ DBGLOG(NIC, INFO, "Tc4 number:%d\n", prTc->aucFreeBufferCount[TC4_INDEX]); ++ if (prTc->aucFreeBufferCount[TC4_INDEX] != 0) ++ glDoChipReset(); ++ } ++ ++ return prCmdInfo; ++ ++} /* end of cmdBufAllocateCmdInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to free the CMD Packet to the MGMT memory pool. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo CMD Packet handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("cmdBufFreeCmdInfo"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo) { ++ if (prCmdInfo->pucInfoBuffer) { ++ cnmMemFree(prAdapter, prCmdInfo->pucInfoBuffer); ++ prCmdInfo->pucInfoBuffer = NULL; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ } ++ ++ return; ++ ++} /* end of cmdBufFreeCmdPacket() */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c +new file mode 100644 +index 000000000000..dfaaedd118bf +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c +@@ -0,0 +1,4062 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic.c#2 ++*/ ++ ++/*! \file nic.c ++ \brief Functions that provide operation in NIC's (Network Interface Card) point of view. ++ ++ This file includes functions which unite multiple hal(Hardware) operations ++ and also take the responsibility of Software Resource Management in order ++ to keep the synchronization with Hardware Manipulation. ++*/ ++ ++/* ++** Log: nic.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 05 02 2012 terry.wu ++ * NULL ++ * Set the default value of AP StaRec index to "STA_REC_INDEX_NOT_FOUND" in update firmware bss command. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when ++ * returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 11 22 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * keep debug counter setting after wake up. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 04 2011 cp.wu ++ * [WCXRP00001079] [MT5931][Driver] Release pending MMPDU only when BSS is being deactivated ++ * pre-check for NULL before calling MMPDU free function ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to ++ * the AP.. ++ * ++ * 10 11 2011 terry.wu ++ * NULL ++ * Rewrite Assert Dump Function for Portability. ++ * ++ * 09 20 2011 cm.chang ++ * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time ++ * New CMD definition about RLM parameters ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 03 2011 terry.wu ++ * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode ++ * Reply Probe Rsp in FW for Hotspot Mode. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device ++ * issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 07 11 2011 wh.su ++ * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for ++ * customer not enable WAPI ++ * For make sure wapi initial value is set. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky ++ * AP which use space character as hidden SSID ++ * 1. correct logic ++ * 2. replace only BSS-DESC which doesn't have a valid SSID. ++ * ++ * 06 27 2011 cp.wu ++ * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky ++ * AP which use space character as hidden SSID ++ * allow to have a single BSSID with multiple SSID to be presented in scanning result ++ * ++ * 05 12 2011 puff.wen ++ * NULL ++ * FW Assert information dump to driver ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 15 2011 cp.wu ++ * [WCXRP00000651] [MT6620 Wi-Fi][Driver] Refine RSSI buffering mechanism ++ * ROLLBACK due to the special design is to workaround incorrect initial RCPI value coming from firmware domain. ++ * ++ * 04 14 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 14 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected ++ * 2. add dummy function for both Win32 and Linux part. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for ++ * dedicated network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 12 2011 wh.su ++ * NULL ++ * enable the p2p check the cipher to set the bssInfo auth mode. ++ * ++ * 04 12 2011 wh.su ++ * NULL ++ * prepare the code for sync the auth mode and encryption status for P2P and BOW. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 04 10 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * Fix compiler issue. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 04 07 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside ++ * wlanAdapterStart ++ * . ++ * ++ * 04 07 2011 cp.wu ++ * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside ++ * wlanAdapterStart ++ * implementation of internal error handling of nicAllocateAdapterMemory. ++ * ++ * 03 31 2011 chinglan.wang ++ * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. ++ * . ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 10 2011 cm.chang ++ * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module ++ * Add some functions to let AIS/Tethering or AIS/BOW be the same channel ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 08 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * Use kalPrint to print firmware assert info. ++ * ++ * 02 01 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * . ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 31 2011 terry.wu ++ * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log ++ * Print firmware ASSERT info at Android kernel log, driver side ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000372] [MT6620 Wi-Fi][Driver] Check bus access failure inside nicProcessIST() ++ * check bus error and/or card removal when retrieving interrupt status from HAL ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * 1) correct typo in scan.c ++ * 2) TX descriptors, RX descriptos and management buffer should use virtually continuous buffer instead of ++ * physically contineous one ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 12 17 2010 cp.wu ++ * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged ++ * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk ++ * 1. BSSINFO include RLM parameter ++ * 2. free all sta records when network is disconnected ++ * ++ * 12 02 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Add more control value but dont use it now. ++ * ++ * 11 30 2010 eddie.chen ++ * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry ++ * Add auto rate check window in registry ++ * ++ * 11 10 2010 eddie.chen ++ * [WCXRP00000156] [MT6620][FW] Change Auto rate window to 64 and add throughput swcr ++ * Use autorate parameter 1 as phy rate mask. ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 10 26 2010 eddie.chen ++ * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB ++ * Add auto rate parameter in registry. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to ++ * BSOD when entering RF test with AIS associated ++ * 1. remove redundant variables in STA_REC structure ++ * 2. add STA-REC uninitialization routine for clearing pending events ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A ++ * reset ptrs when IEs are going to be dropped ++ * ++ * 10 12 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * add HT (802.11n) fixed rate support. ++ * ++ * 10 08 2010 cp.wu ++ * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test ++ * adding fixed rate support for distance test. (from registry setting) ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test ++ * with AIS associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 26 2010 yuche.tsai ++ * NULL ++ * Fix someones coding error while enable WIFI_DIRECT. ++ * ++ * 08 25 2010 george.huang ++ * NULL ++ * update OID/ registry control path for PM related settings ++ * ++ * 08 24 2010 cm.chang ++ * NULL ++ * Support RLM initail channel of Ad-hoc, P2P and BOW ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 08 23 2010 chinghwa.yu ++ * NULL ++ * Update for BOW. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Add state change indication. ++ * ++ * 08 16 2010 yuche.tsai ++ * NULL ++ * Add support for P2P BSS update info. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [removing debugging] not to dump beacon content. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 04 2010 yarco.yang ++ * NULL ++ * Add TX_AMPDU and ADDBA_REJECT command ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo ++ * 2) change nicMediaStateChange() API prototype ++ * ++ * 07 28 2010 cp.wu ++ * NULL ++ * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * FIX: structure of CMD_SET_BSS_INFO has been changed but no follow-ups are done. ++ * ++ * 07 22 2010 george.huang ++ * ++ * . ++ * ++ * 07 22 2010 george.huang ++ * ++ * Update fgIsQoS information in BSS INFO by CMD ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * update prStaRecOfAP with BSS-INFO. ++ * ++ * 07 06 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Update arguments for nicUpdateBeaconIETemplate() ++ * ++ * 07 06 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * STA-REC is maintained by CNM only. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) ignore RSN checking when RSN is not turned on. ++ * 2) set STA-REC deactivation callback as NULL ++ * 3) add variable initialization API based on PHY configuration ++ * ++ * 07 01 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Support sync command of STA_REC ++ * ++ * 06 30 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync. with CMD/EVENT document ver0.07. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. ++ * ++ * 06 29 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) sync to. CMD/EVENT document v0.03 ++ * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. ++ * 3) send command packet to indicate FW-PM after ++ * a) 1st beacon is received after AIS has connected to an AP ++ * b) IBSS-ALONE has been created ++ * c) IBSS-MERGE has occurred ++ * ++ * 06 25 2010 george.huang ++ * [WPD00001556]Basic power managemenet function ++ * Create beacon update path, with expose bssUpdateBeaconContent() ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill fgIsUapsdConnection when indicating BSS-CREATE with AIS-STA mode. ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver ++ * correct nicProcessIST_impl() for interrupt status brought up by RX enhanced response ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response ++ * ++ * 03 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always process TX interrupt first then RX interrupt. ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add checksum offloading support. ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-16 18:03:43 GMT mtk02752 ++** handling enhanced response which fields are fetched at different moments ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-15 17:00:29 GMT mtk02752 ++** if RX enhanced response is used, D2H interrupt status should be coming from buffered result as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-15 12:01:55 GMT mtk02752 ++** if TX_DONE bit is not set but WTSR0/WTSR1 is non-zero, then set TX_DONE ++** bit due to time latency of interrupt status enhanced response ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:52:52 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-24 20:51:01 GMT mtk02752 ++** integrate with SD1 by invoking qmHandleMailboxRxMessage() ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-16 17:32:33 GMT mtk02752 ++** prepare code for invoking rxHandleMailboxRxMessage() ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:08 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-09 22:56:41 GMT mtk01084 ++** modify HW access routines ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:20 GMT mtk01084 ++** prevent warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:54:57 GMT mtk01084 ++** init HIF ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:30 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:12 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-09-09 17:26:15 GMT mtk01084 ++** modify for CFG_TEST_WITH_MT5921 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-19 10:55:22 GMT mtk01461 ++** Unmask the unused HISR ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-18 15:59:13 GMT mtk01084 ++** remove debug purpose code ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 14:05:02 GMT mtk01084 ++** update for WIFI ownback part on initial ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-04 21:32:57 GMT mtk01084 ++** add temporarily code to set driver own on adapter initialization ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:35:41 GMT mtk01461 ++** Add init of TX aggregation and fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-24 21:12:10 GMT mtk01104 ++** Add function nicRestoreSpiDefMode() ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:43:31 GMT mtk01461 ++** Revise for MTK coding style - nicInitializeAdapter() ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:52:47 GMT mtk01461 ++** Update allocate Adapter Memory for MGMT Memory pool ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:57:08 GMT mtk01461 ++** Refine the order of release memory from pucRxCoalescingBufCached ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-19 18:32:57 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:00:14 GMT mtk01426 ++** Add CFG_SDIO_RX_ENHANCE support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:27 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:25:59 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++const UINT_8 aucPhyCfg2PhyTypeSet[PHY_CONFIG_NUM] = { ++ PHY_TYPE_SET_802_11ABG, /* PHY_CONFIG_802_11ABG */ ++ PHY_TYPE_SET_802_11BG, /* PHY_CONFIG_802_11BG */ ++ PHY_TYPE_SET_802_11G, /* PHY_CONFIG_802_11G */ ++ PHY_TYPE_SET_802_11A, /* PHY_CONFIG_802_11A */ ++ PHY_TYPE_SET_802_11B, /* PHY_CONFIG_802_11B */ ++ PHY_TYPE_SET_802_11ABGN, /* PHY_CONFIG_802_11ABGN */ ++ PHY_TYPE_SET_802_11BGN, /* PHY_CONFIG_802_11BGN */ ++ PHY_TYPE_SET_802_11AN, /* PHY_CONFIG_802_11AN */ ++ PHY_TYPE_SET_802_11GN /* PHY_CONFIG_802_11GN */ ++}; ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++#define REQ_GATING_ENABLE_H2D_INT BIT(31) ++#define REQ_GATING_DISABLE_H2D_INT BIT(30) ++#define ACK_GATING_ENABLE_D2H_INT BIT(31) ++#define ACK_GATING_DISABLE_D2H_INT BIT(30) ++ ++#define GATING_CONTROL_POLL_LIMIT 64 ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++static INT_EVENT_MAP_T arIntEventMapTable[] = { ++ {WHISR_ABNORMAL_INT, INT_EVENT_ABNORMAL}, ++ {WHISR_D2H_SW_INT, INT_EVENT_SW_INT}, ++ {WHISR_TX_DONE_INT, INT_EVENT_TX}, ++ {(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT), INT_EVENT_RX} ++}; ++ ++static const UINT_8 ucIntEventMapSize = (sizeof(arIntEventMapTable) / sizeof(INT_EVENT_MAP_T)); ++ ++static IST_EVENT_FUNCTION apfnEventFuncTable[] = { ++ nicProcessAbnormalInterrupt, /*!< INT_EVENT_ABNORMAL */ ++ nicProcessSoftwareInterrupt, /*!< INT_EVENT_SW_INT */ ++ nicProcessTxInterrupt, /*!< INT_EVENT_TX */ ++ nicProcessRxInterrupt, /*!< INT_EVENT_RX */ ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/*! This macro is used to reduce coding errors inside nicAllocateAdapterMemory() ++ * and also enhance the readability. ++ */ ++#define LOCAL_NIC_ALLOCATE_MEMORY(pucMem, u4Size, eMemType, pucComment) \ ++ { \ ++ DBGLOG(NIC, INFO, "Allocating %u bytes for %s.\n", u4Size, pucComment); \ ++ pucMem = (PUINT_8)kalMemAlloc(u4Size, eMemType); \ ++ if (pucMem == (PUINT_8)NULL) { \ ++ DBGLOG(NIC, ERROR, "Could not allocate %u bytes for %s.\n", u4Size, pucComment); \ ++ break; \ ++ } \ ++ ASSERT(((ULONG)pucMem % 4) == 0); \ ++ DBGLOG(NIC, TRACE, "Virtual Address = %p for %s.\n", pucMem, pucComment); \ ++ } ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter) ++{ ++ dumpMemory32((PUINT_32)prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++} ++ ++VOID HifRegDump(P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ UINT_32 RegVal = 0; ++ ++ for (i = 0; i <= 0x58; i += 4) { ++ if ((i != MCR_WTDR0) && (i != MCR_WTDR1) && (i != MCR_WRDR0) && ++ (i != MCR_WRDR1) && (i != MCR_WSDIOCSR) && (i != MCR_WRPLR)) { ++ HAL_MCR_RD(prAdapter, i, &RegVal); ++ DBGLOG(NIC, WARN, "HIF Reg 0x%x = 0x%x\n", i, RegVal); ++ } ++ } ++ DBGLOG(NIC, WARN, "\n\n"); ++} ++ ++BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter) ++{ ++ return prAdapter->fgIsFwOwn; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is responsible for the allocation of the data structures ++* inside the Adapter structure, include: ++* 1. SW_RFB_Ts ++* 2. Common coalescing buffer for TX PATH. ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @retval WLAN_STATUS_SUCCESS - Has enough memory. ++* @retval WLAN_STATUS_RESOURCES - Memory is not enough. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS status = WLAN_STATUS_RESOURCES; ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ ++ DEBUGFUNC("nicAllocateAdapterMemory"); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ do { ++ /* 4 <0> Reset all Memory Handler */ ++#if CFG_DBG_MGT_BUF ++ prAdapter->u4MemFreeDynamicCount = 0; ++ prAdapter->u4MemAllocDynamicCount = 0; ++#endif ++ prAdapter->pucMgtBufCached = (PUINT_8) NULL; ++ prRxCtrl->pucRxCached = (PUINT_8) NULL; ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; ++ ++ /* 4 <1> Memory for Management Memory Pool and CMD_INFO_T */ ++ /* Allocate memory for the CMD_INFO_T and its MGMT memory pool. */ ++ prAdapter->u4MgtBufCachedSize = MGT_BUFFER_SIZE; ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prAdapter->pucMgtBufCached, ++ prAdapter->u4MgtBufCachedSize, VIR_MEM_TYPE, "COMMON MGMT MEMORY POOL"); ++ ++ /* 4 <2> Memory for RX Descriptor */ ++ /* Initialize the number of rx buffers we will have in our queue. */ ++ /* We may setup ucRxPacketDescriptors by GLUE Layer, and using ++ * this variable directly. ++ */ ++ /* Allocate memory for the SW receive structures. */ ++ prRxCtrl->u4RxCachedSize = CFG_RX_MAX_PKT_NUM * ALIGN_4(sizeof(SW_RFB_T)); ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize, VIR_MEM_TYPE, "SW_RFB_T"); ++ ++ /* 4 <3> Memory for TX DEscriptor */ ++ prTxCtrl->u4TxCachedSize = CFG_TX_MAX_PKT_NUM * ALIGN_4(sizeof(MSDU_INFO_T)); ++ ++ LOCAL_NIC_ALLOCATE_MEMORY(prTxCtrl->pucTxCached, prTxCtrl->u4TxCachedSize, VIR_MEM_TYPE, "MSDU_INFO_T"); ++ ++ /* 4 <4> Memory for Common Coalescing Buffer */ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; ++ ++ /* Allocate memory for the common coalescing buffer. */ ++ prAdapter->u4CoalescingBufCachedSize = CFG_COALESCING_BUFFER_SIZE > CFG_RX_COALESCING_BUFFER_SIZE ? ++ CFG_COALESCING_BUFFER_SIZE : CFG_RX_COALESCING_BUFFER_SIZE; ++ ++ prAdapter->pucCoalescingBufCached = kalAllocateIOBuffer(prAdapter->u4CoalescingBufCachedSize); ++ ++ if (prAdapter->pucCoalescingBufCached == NULL) { ++ DBGLOG(NIC, ERROR, ++ "Could not allocate %u bytes for coalescing buffer.\n", ++ prAdapter->u4CoalescingBufCachedSize); ++ break; ++ } ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* 4 <5> Memory for enhanced interrupt response */ ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) ++ kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ if (prAdapter->prSDIOCtrl == NULL) { ++ DBGLOG(NIC, ERROR, ++ "Could not allocate %zu bytes for interrupt response.\n", ++ sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ break; ++ } ++ ++ status = WLAN_STATUS_SUCCESS; ++ ++ } while (FALSE); ++ ++ if (status != WLAN_STATUS_SUCCESS) ++ nicReleaseAdapterMemory(prAdapter); ++ ++ return status; ++ ++} /* end of nicAllocateAdapterMemory() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is responsible for releasing the allocated memory by ++* nicAllocatedAdapterMemory(). ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* 4 <5> Memory for enhanced interrupt response */ ++ if (prAdapter->prSDIOCtrl) { ++ kalReleaseIOBuffer((PVOID) prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; ++ } ++ /* 4 <4> Memory for Common Coalescing Buffer */ ++#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG ++ if (prAdapter->pucCoalescingBufCached) { ++ kalReleaseIOBuffer((PVOID) prAdapter->pucCoalescingBufCached, prAdapter->u4CoalescingBufCachedSize); ++ prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; ++ } ++#endif /* CFG_COALESCING_BUFFER_SIZE */ ++ ++ /* 4 <3> Memory for TX Descriptor */ ++ if (prTxCtrl->pucTxCached) { ++ kalMemFree((PVOID) prTxCtrl->pucTxCached, VIR_MEM_TYPE, prTxCtrl->u4TxCachedSize); ++ prTxCtrl->pucTxCached = (PUINT_8) NULL; ++ } ++ /* 4 <2> Memory for RX Descriptor */ ++ if (prRxCtrl->pucRxCached) { ++ kalMemFree((PVOID) prRxCtrl->pucRxCached, VIR_MEM_TYPE, prRxCtrl->u4RxCachedSize); ++ prRxCtrl->pucRxCached = (PUINT_8) NULL; ++ } ++ /* 4 <1> Memory for Management Memory Pool */ ++ if (prAdapter->pucMgtBufCached) { ++ kalMemFree((PVOID) prAdapter->pucMgtBufCached, VIR_MEM_TYPE, prAdapter->u4MgtBufCachedSize); ++ prAdapter->pucMgtBufCached = (PUINT_8) NULL; ++ } ++#if CFG_DBG_MGT_BUF ++ /* Check if all allocated memories are free */ ++ ASSERT(prAdapter->u4MemFreeDynamicCount == prAdapter->u4MemAllocDynamicCount); ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief disable global interrupt ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ prAdapter->fgIsIntEnable = FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief enable global interrupt ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ BOOLEAN fgIsIntEnableCache; ++ ++ ASSERT(prAdapter); ++ fgIsIntEnableCache = prAdapter->fgIsIntEnable; ++ ++ prAdapter->fgIsIntEnable = TRUE; /* NOTE(Kevin): It must be placed before MCR GINT write. */ ++ ++ /* If need enable INT and also set LPOwn at the same time. */ ++ if (prAdapter->fgIsIntEnableWithLPOwnSet) { ++ prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; /* NOTE(Kevin): It's better to place it ++ * before MCR GINT write. ++ */ ++ /* If INT was enabled, only set LPOwn */ ++ if (fgIsIntEnableCache) { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++ /* If INT was not enabled, enable it and also set LPOwn now */ ++ else { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET | WHLPCR_INT_EN_SET); ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++ } ++ /* If INT was not enabled, enable it now */ ++ else if (!fgIsIntEnableCache) ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++} /* end of nicEnableInterrupt() */ ++ ++#if CFG_SDIO_INTR_ENHANCE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief For SDIO enhance mode, set the max rx len and tx status ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* @return - none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSDIOInit(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Value = 0; ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <1> Check STATUS Buffer is DW alignment. */ ++ ASSERT(IS_ALIGN_4((ULONG)&prAdapter->prSDIOCtrl->u4WHISR)); ++ ++ /* 4 <2> Setup STATUS count. */ ++ { ++ HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); ++ ++ /* 4 <2.1> Setup the number of maximum RX length to be report */ ++ u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); ++ u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); ++ ++ /* 4 <2.2> Setup RX enhancement mode */ ++#if CFG_SDIO_RX_ENHANCE ++ u4Value |= WHCR_RX_ENHANCE_MODE_EN; ++#else ++ u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; ++#endif /* CFG_SDIO_RX_AGG */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); ++ } ++ ++ return; ++ ++} /* end of nicSDIOInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read interrupt status from hardware ++* ++* @param prAdapter pointer to the Adapter handler ++* @param the interrupts ++* ++* @return N/A ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus) ++{ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ ++ DEBUGFUNC("nicSDIOReadIntStatus"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pu4IntStatus); ++ ++ /* ++ prSDIOCtrl is from IO buffer. ++ prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) ++ kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ */ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ASSERT(prSDIOCtrl); ++ ++ HAL_PORT_RD(prAdapter, ++ MCR_WHISR, ++ sizeof(ENHANCE_MODE_DATA_STRUCT_T), (PUINT_8) prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ *pu4IntStatus = 0; ++ return; ++ } ++ ++ /* workaround */ ++ if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && ++ (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { ++ prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; ++ } ++ ++ if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && ++ HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && ++ (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { ++ prSDIOCtrl->u4WHISR |= BIT(31); ++ } ++ ++ *pu4IntStatus = prSDIOCtrl->u4WHISR; ++ ++} /* end of nicSDIOReadIntStatus() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function used to read interrupt status and then invoking ++* dispatching procedure for the appropriate functions ++* corresponding to specific interrupt bits ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 u4IntStatus = 0; ++ UINT_32 i; ++ ++ DEBUGFUNC("nicProcessIST"); ++ /* DBGLOG(NIC, LOUD, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->rAcpiState == ACPI_STATE_D3) { ++ DBGLOG(REQ, WARN, "Fail in set nicProcessIST! (Adapter not ready). ACPI=D%d, Radio=%d\n", ++ prAdapter->rAcpiState, prAdapter->fgIsRadioOff); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ nicDisableClockGating(prAdapter); ++#endif ++ ++ for (i = 0; i < CFG_IST_LOOP_COUNT; i++) { /* CFG_IST_LOOP_COUNT = 1 */ ++ ++#if CFG_SDIO_INTR_ENHANCE ++ nicSDIOReadIntStatus(prAdapter, &u4IntStatus); ++#else ++ HAL_MCR_RD(prAdapter, MCR_WHISR, &u4IntStatus); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++/* DBGLOG(NIC, TRACE, ("u4IntStatus: 0x%x\n", u4IntStatus)); */ ++ ++ if (u4IntStatus & ~(WHIER_DEFAULT | WHIER_FW_OWN_BACK_INT_EN)) { ++ DBGLOG(INTR, WARN, "Un-handled HISR %#x, HISR = %#x (HIER:0x%x)\n", ++ (UINT_32) (u4IntStatus & ~WHIER_DEFAULT), u4IntStatus, ++ (UINT_32) WHIER_DEFAULT); ++ u4IntStatus &= WHIER_DEFAULT; ++ } ++ ++ nicProcessIST_impl(prAdapter, u4IntStatus); ++ ++ if (u4IntStatus == 0) { ++ if (i == 0) ++ u4Status = WLAN_STATUS_NOT_INDICATING; ++ break; ++ } ++ } ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ nicEnableClockGating(prAdapter); ++#endif ++ ++ return u4Status; ++} /* end of nicProcessIST() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief The function used to dispatch the appropriate functions for specific ++* interrupt bits ++* ++* @param prAdapter pointer to the Adapter handler ++* u4IntStatus interrupt status bits ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_ADAPTER_NOT_READY ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus) ++{ ++ UINT_32 u4IntCount = 0; ++ P_INT_EVENT_MAP_T prIntEventMap = NULL; ++ ++ ASSERT(prAdapter); ++ ++ prAdapter->u4IntStatus = u4IntStatus; ++ ++ /* Process each of the interrupt status consequently */ ++ prIntEventMap = &arIntEventMapTable[0]; ++ for (u4IntCount = 0; u4IntCount < ucIntEventMapSize; prIntEventMap++, u4IntCount++) { ++ if (prIntEventMap->u4Int & prAdapter->u4IntStatus) { ++ if (prIntEventMap->u4Event == INT_EVENT_RX && prAdapter->fgIsEnterD3ReqIssued == TRUE) { ++ /* ignore */ ++ } else if (apfnEventFuncTable[prIntEventMap->u4Event] != NULL) { ++ apfnEventFuncTable[prIntEventMap->u4Event] (prAdapter); ++ } else { ++ DBGLOG(INTR, WARN, ++ "Empty INTR handler! ISAR bit#: %u, event:%u, func: %p\n", ++ prIntEventMap->u4Int, prIntEventMap->u4Event, ++ apfnEventFuncTable[prIntEventMap->u4Event]); ++ ++ ASSERT(0); /* to trap any NULL interrupt handler */ ++ } ++ prAdapter->u4IntStatus &= ~prIntEventMap->u4Int; ++ } ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of nicProcessIST_impl() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Verify the CHIP ID ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* ++* @retval TRUE CHIP ID is the same as the setting compiled ++* @retval FALSE CHIP ID is different from the setting compiled ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4CIR = 0; ++ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR); ++ ++ DBGLOG(NIC, TRACE, "Chip ID: 0x%x\n", (UINT_32) (u4CIR & WCIR_CHIP_ID)); ++ DBGLOG(NIC, TRACE, "Revision ID: 0x%x\n", (UINT_32) ((u4CIR & WCIR_REVISION_ID) >> 16)); ++ ++#if 0 ++ if (((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_72) && ((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_82)) ++ return FALSE; ++#endif ++ ++ prAdapter->ucRevID = (UINT_8) (((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the MCR to the appropriate init value, and verify the init ++* value ++* ++* @param prAdapter a pointer to adapter private data structure. ++* ++* @return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicMCRInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <0> Initial value */ ++} ++ ++VOID nicHifInit(IN P_ADAPTER_T prAdapter) ++{ ++ ++ ASSERT(prAdapter); ++#if 0 ++ /* reset event */ ++ nicPutMailbox(prAdapter, 0, 0x52455345); /* RESE */ ++ nicPutMailbox(prAdapter, 1, 0x545F5746); /* T_WF */ ++ nicSetSwIntr(prAdapter, BIT(16)); ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the Adapter soft variable ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prAdapter); ++ ++ prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; ++ ++ do { ++ if (!nicVerifyChipID(prAdapter)) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ /* 4 <1> MCR init */ ++ nicMCRInit(prAdapter); ++ ++#if CFG_SDIO_INTR_ENHANCE ++ nicSDIOInit(prAdapter); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); ++ ++ /* 4 <2> init FW HIF */ ++ nicHifInit(prAdapter); ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++#if defined(_HIF_SPI) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Restore the SPI Mode Select to default mode, ++* this is important while driver is unload, and this must be last mcr ++* since the operation will let the hif use 8bit mode access ++* ++* \param[in] prAdapter a pointer to adapter private data structure. ++* \param[in] eGPIO2_Mode GPIO2 operation mode ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ HAL_MCR_WR(prAdapter, MCR_WCSR, SPICSR_8BIT_MODE_DATA); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process rx interrupt. When the rx ++* Interrupt is asserted, it means there are frames in queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Value = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ prGlueInfo->IsrAbnormalCnt++; ++ HAL_MCR_RD(prAdapter, MCR_WASR, &u4Value); ++ DBGLOG(REQ, WARN, "MCR_WASR: 0x%x\n", u4Value); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief . ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessFwOwnBackInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ ++} /* end of nicProcessFwOwnBackInterrupt() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief . ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4IntrBits; ++ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); ++ ++ prGlueInfo->IsrSoftWareCnt++; ++ ++ if ((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { ++ nicPrintFirmwareAssertInfo(prAdapter); ++#if CFG_CHIP_RESET_SUPPORT ++ glSendResetRequest(); ++#endif ++ } ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++ ASSERT((u4IntrBits & (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)) ++ != (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)); ++ ++ if (u4IntrBits & ACK_GATING_ENABLE_D2H_INT) ++ prAdapter->fgIsClockGatingEnabled = TRUE; ++ ++ if (u4IntrBits & ACK_GATING_DISABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++ ++ /* Indicate Service Thread for TX */ ++ if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++#endif ++ ++ DBGLOG(REQ, WARN, "u4IntrBits: 0x%x\n", u4IntrBits); ++} /* end of nicProcessSoftwareInterrupt() */ ++ ++VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data) ++{ ++ if (u4MailboxNum == 0) { ++ /* HAL_MCR_WR */ ++ HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); ++ } else if (u4MailboxNum == 1) { ++ /* HAL_MCR_WR */ ++ HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); ++ } else { ++ ASSERT(0); ++ } ++} ++ ++VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data) ++{ ++ if (u4MailboxNum == 0) { ++ /* HAL_MCR_RD */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); ++ } else if (u4MailboxNum == 1) { ++ /* HAL_MCR_RD */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); ++ } else { ++ ASSERT(0); ++ } ++} ++ ++VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap) ++{ ++ /* NOTE: ++ * SW interrupt in HW bit 16 is mapping to SW bit 0 (shift 16bit in HW transparancy) ++ * SW interrupt valid from b0~b15 ++ */ ++ ASSERT((u4SwIntrBitmap & BITS(0, 15)) == 0); ++/* DBGLOG(NIC, TRACE, ("u4SwIntrBitmap: 0x%08x\n", u4SwIntrBitmap)); */ ++ ++ HAL_MCR_WR(prAdapter, MCR_WSICR, u4SwIntrBitmap); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to dequeue from prAdapter->rPendingCmdQueue ++* with specified sequential number ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ucSeqNum Sequential Number ++* ++* @retval - P_CMD_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ prCmdQue = &prAdapter->rPendingCmdQueue; ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->ucCmdSeqNum == ucSeqNum) ++ break; ++ ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ ++ prCmdInfo = NULL; ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); ++ ++ return prCmdInfo; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to dequeue from prAdapter->rTxCtrl.rTxMgmtTxingQueue ++* with specified sequential number ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ucSeqNum Sequential Number ++* ++* @retval - P_MSDU_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) ++{ ++ P_QUE_T prTxingQue; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if (prMsduInfo->ucTxSeqNum == ucSeqNum) ++ break; ++ ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ return prMsduInfo; ++} ++ ++P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx) ++{ ++ P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; ++ P_QUE_T prTxingQue = (P_QUE_T) NULL; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if (prAdapter == NULL) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ do { ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if ((prMsduInfo->ucStaRecIndex == ucStaRecIdx) && (prMsduInfo->pfTxDoneHandler != NULL)) { ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfo, prMsduInfoListHead); ++ prMsduInfoListHead = prMsduInfo; ++ } else { ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ } while (FALSE); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ return prMsduInfoListHead; ++} /* nicGetPendingStaMMPDU */ ++ ++VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ P_QUE_T prTxingQue; ++ QUE_T rTempQue; ++ P_QUE_T prTempQue = &rTempQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; ++ P_MSDU_INFO_T prMsduInfoListTail = (P_MSDU_INFO_T) NULL; ++ P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); ++ QUEUE_MOVE_ALL(prTempQue, prTxingQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; ++ ++ if ((ENUM_NETWORK_TYPE_INDEX_T) (prMsduInfo->ucNetworkType) == eNetworkType) { ++ if (prMsduInfoListHead == NULL) { ++ prMsduInfoListHead = prMsduInfoListTail = prMsduInfo; ++ } else { ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, prMsduInfo); ++ prMsduInfoListTail = prMsduInfo; ++ } ++ } else { ++ QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); ++ ++ prMsduInfo = NULL; ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ /* free */ ++ if (prMsduInfoListHead) ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); ++ ++ return; ++ ++} /* end of nicFreePendingTxMsduInfoByNetwork() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to retrieve a CMD sequence number atomically ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval - UINT_8 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucRetval; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); ++ ++ prAdapter->ucCmdSeqNum++; ++ ucRetval = prAdapter->ucCmdSeqNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); ++ ++ return ucRetval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This procedure is used to retrieve a TX sequence number atomically ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval - UINT_8 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucRetval; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); ++ ++ prAdapter->ucTxSeqNum++; ++ ucRetval = prAdapter->ucTxSeqNum; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); ++ ++ return ucRetval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to handle ++* media state change event ++* ++* @param ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicMediaStateChange(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ ASSERT(prAdapter); ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ switch (eNetworkType) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { /* disconnected */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ DBGLOG(NIC, TRACE, "DisByMC\n"); ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++ ++ /* reset buffered link quality information */ ++ prAdapter->fgIsLinkQualityValid = FALSE; ++ prAdapter->fgIsLinkRateValid = FALSE; ++ } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { /* connected */ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ ++ /* fill information for association result */ ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prConnectionStatus->aucBssid, MAC_ADDR_LEN); ++ prAdapter->rWlanInfo.rCurrBssId.u4Privacy ++ = prConnectionStatus->ucEncryptStatus; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse ++ = PARAM_NETWORK_TYPE_AUTOMODE; /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod ++ = prConnectionStatus->u2BeaconPeriod; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow = prConnectionStatus->u2ATIMWindow; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig = prConnectionStatus->u4FreqInKHz; ++ prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode ++ = (ENUM_PARAM_OP_MODE_T) prConnectionStatus->ucInfraMode; ++ ++ /* always indicate to OS according to MSDN (re-association/roaming) */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); ++ } else { ++ /* connected -> connected : roaming ? */ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_ROAM_OUT_FIND_BEST, NULL, 0); ++ } ++ } ++ break; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ case NETWORK_TYPE_BOW_INDEX: ++ break; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case NETWORK_TYPE_P2P_INDEX: ++ break; ++#endif ++ default: ++ ASSERT(0); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} /* nicMediaStateChange */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to convert between ++* frequency and channel number ++* ++* @param u4ChannelNum ++* ++* @retval - Frequency in unit of KHz, 0 for invalid channel number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicChannelNum2Freq(UINT_32 u4ChannelNum) ++{ ++ UINT_32 u4ChannelInMHz; ++ ++ if (u4ChannelNum >= 1 && u4ChannelNum <= 13) ++ u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; ++ else if (u4ChannelNum == 14) ++ u4ChannelInMHz = 2484; ++ else if (u4ChannelNum == 133) ++ u4ChannelInMHz = 3665; /* 802.11y */ ++ else if (u4ChannelNum == 137) ++ u4ChannelInMHz = 3685; /* 802.11y */ ++ else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) ++ u4ChannelInMHz = 5000 + u4ChannelNum * 5; ++ else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) ++ u4ChannelInMHz = 4000 + u4ChannelNum * 5; ++ else ++ u4ChannelInMHz = 0; ++ ++ return 1000 * u4ChannelInMHz; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to convert between ++* frequency and channel number ++* ++* @param u4FreqInKHz ++* ++* @retval - Frequency Number, 0 for invalid freqency ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicFreq2ChannelNum(UINT_32 u4FreqInKHz) ++{ ++ switch (u4FreqInKHz) { ++ case 2412000: ++ return 1; ++ case 2417000: ++ return 2; ++ case 2422000: ++ return 3; ++ case 2427000: ++ return 4; ++ case 2432000: ++ return 5; ++ case 2437000: ++ return 6; ++ case 2442000: ++ return 7; ++ case 2447000: ++ return 8; ++ case 2452000: ++ return 9; ++ case 2457000: ++ return 10; ++ case 2462000: ++ return 11; ++ case 2467000: ++ return 12; ++ case 2472000: ++ return 13; ++ case 2484000: ++ return 14; ++ case 3665000: ++ return 133; /* 802.11y */ ++ case 3685000: ++ return 137; /* 802.11y */ ++ case 4915000: ++ return 183; ++ case 4920000: ++ return 184; ++ case 4925000: ++ return 185; ++ case 4930000: ++ return 186; ++ case 4935000: ++ return 187; ++ case 4940000: ++ return 188; ++ case 4945000: ++ return 189; ++ case 4960000: ++ return 192; ++ case 4980000: ++ return 196; ++ case 5170000: ++ return 34; ++ case 5180000: ++ return 36; ++ case 5190000: ++ return 38; ++ case 5200000: ++ return 40; ++ case 5210000: ++ return 42; ++ case 5220000: ++ return 44; ++ case 5230000: ++ return 46; ++ case 5240000: ++ return 48; ++ case 5250000: ++ return 50; ++ case 5260000: ++ return 52; ++ case 5270000: ++ return 54; ++ case 5280000: ++ return 56; ++ case 5290000: ++ return 58; ++ case 5300000: ++ return 60; ++ case 5320000: ++ return 64; ++ case 5500000: ++ return 100; ++ case 5520000: ++ return 104; ++ case 5540000: ++ return 108; ++ case 5560000: ++ return 112; ++ case 5580000: ++ return 116; ++ case 5600000: ++ return 120; ++ case 5620000: ++ return 124; ++ case 5640000: ++ return 128; ++ case 5660000: ++ return 132; ++ case 5680000: ++ return 136; ++ case 5700000: ++ return 140; ++ case 5745000: ++ return 149; ++ case 5765000: ++ return 153; ++ case 5785000: ++ return 157; ++ case 5805000: ++ return 161; ++ case 5825000: ++ return 165; ++ case 5845000: ++ return 169; ++ case 5865000: ++ return 173; ++ default: ++ return 0; ++ } ++} ++ ++/* firmware command wrapper */ ++/* NETWORK (WIFISYS) */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to activate WIFISYS for specified network ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of network type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; ++ P_BSS_INFO_T prBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdActivateCtrl.ucActive = 1; ++ ++ if (((UINT_8) eNetworkTypeIdx) < NETWORK_TYPE_INDEX_NUM) { ++ prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]; ++ prBssInfo->fg40mBwAllowed = FALSE; ++ prBssInfo->fgAssoc40mBwAllowed = FALSE; ++ } ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BSS_ACTIVATE_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to deactivate WIFISYS for specified network ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of network type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ WLAN_STATUS u4Status; ++ CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdActivateCtrl.ucActive = 0; ++ ++ u4Status = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_BSS_ACTIVATE_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); ++ ++ /* free all correlated station records */ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); ++ qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); ++ nicFreePendingTxMsduInfoByNetwork(prAdapter, eNetworkTypeIdx); ++ kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); ++ ++ return u4Status; ++} ++ ++/* BSS-INFO */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to sync bss info with firmware ++* when a new BSS has been connected or disconnected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO type ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ WLAN_STATUS u4Status; ++ P_BSS_INFO_T prBssInfo; ++ CMD_SET_BSS_INFO rCmdSetBssInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ kalMemZero(&rCmdSetBssInfo, sizeof(CMD_SET_BSS_INFO)); ++ ++ rCmdSetBssInfo.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdSetBssInfo.ucConnectionState = (UINT_8) prBssInfo->eConnectionState; ++ rCmdSetBssInfo.ucCurrentOPMode = (UINT_8) prBssInfo->eCurrentOPMode; ++ rCmdSetBssInfo.ucSSIDLen = (UINT_8) prBssInfo->ucSSIDLen; ++ kalMemCopy(rCmdSetBssInfo.aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); ++ COPY_MAC_ADDR(rCmdSetBssInfo.aucBSSID, prBssInfo->aucBSSID); ++ rCmdSetBssInfo.ucIsQBSS = (UINT_8) prBssInfo->fgIsQBSS; ++ rCmdSetBssInfo.ucNonHTBasicPhyType = prBssInfo->ucNonHTBasicPhyType; ++ rCmdSetBssInfo.u2OperationalRateSet = prBssInfo->u2OperationalRateSet; ++ rCmdSetBssInfo.u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; ++ rCmdSetBssInfo.ucPhyTypeSet = prBssInfo->ucPhyTypeSet; ++ rCmdSetBssInfo.fgHiddenSsidMode = prBssInfo->eHiddenSsidType; ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ COPY_MAC_ADDR(rCmdSetBssInfo.aucOwnMac, prBssInfo->aucOwnMacAddr); ++#endif ++ ++ rlmFillSyncCmdParam(&rCmdSetBssInfo.rBssRlmParam, prBssInfo); ++ ++ rCmdSetBssInfo.fgWapiMode = (UINT_8) FALSE; ++ ++ if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) prConnSettings->eAuthMode; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) prConnSettings->eEncStatus; ++ rCmdSetBssInfo.fgWapiMode = (UINT_8) prConnSettings->fgWapiMode; ++ } ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { ++ /* P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); */ ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++ } ++#endif ++ else { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ if (kalP2PGetCipher(prAdapter->prGlueInfo)) { ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++ } else { ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_OPEN; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION_DISABLED; ++ } ++ /* Need the probe response to detect the PBC overlap */ ++ rCmdSetBssInfo.fgIsApMode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); ++ } ++#else ++ rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; ++ rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; ++#endif ++ } ++ ++ if (eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX && ++ prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && prBssInfo->prStaRecOfAP != NULL) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ ++ cnmAisInfraConnectNotify(prAdapter); ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && ++ (eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && ++ (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && (prBssInfo->prStaRecOfAP != NULL)) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ else if (eNetworkTypeIdx == NETWORK_TYPE_BOW_INDEX && ++ prBssInfo->eCurrentOPMode == OP_MODE_BOW && prBssInfo->prStaRecOfAP != NULL) { ++ rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; ++ } ++#endif ++ else ++ rCmdSetBssInfo.ucStaRecIdxOfAP = STA_REC_INDEX_NOT_FOUND; ++ ++ u4Status = wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_BSS_INFO, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_SET_BSS_INFO), (PUINT_8)&rCmdSetBssInfo, NULL, 0); ++ ++ /* if BSS-INFO is going to be disconnected state, free all correlated station records */ ++ if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /* clear client list */ ++ bssClearClientList(prAdapter, prBssInfo); ++ ++ /* free all correlated station records */ ++ cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); ++ qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); ++ kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); ++#if CFG_ENABLE_GTK_FRAME_FILTER ++ if (prBssInfo->prIpV4NetAddrList) ++ FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); ++#endif ++ } ++ ++ return u4Status; ++} ++ ++/* BSS-INFO Indication (PM) */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been created. (for AdHoc / P2P-GO) ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_INDICATE_PM_BSS_CREATED rCmdIndicatePmBssCreated; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ rCmdIndicatePmBssCreated.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdIndicatePmBssCreated.ucDtimPeriod = prBssInfo->ucDTIMPeriod; ++ rCmdIndicatePmBssCreated.u2BeaconInterval = prBssInfo->u2BeaconInterval; ++ rCmdIndicatePmBssCreated.u2AtimWindow = prBssInfo->u2ATIMWindow; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_CREATED, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_CREATED), (PUINT_8)&rCmdIndicatePmBssCreated, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been connected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_INDICATE_PM_BSS_CONNECTED rCmdIndicatePmBssConnected; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ ++ rCmdIndicatePmBssConnected.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ rCmdIndicatePmBssConnected.ucDtimPeriod = prBssInfo->ucDTIMPeriod; ++ rCmdIndicatePmBssConnected.u2AssocId = prBssInfo->u2AssocId; ++ rCmdIndicatePmBssConnected.u2BeaconInterval = prBssInfo->u2BeaconInterval; ++ rCmdIndicatePmBssConnected.u2AtimWindow = prBssInfo->u2ATIMWindow; ++ ++ rCmdIndicatePmBssConnected.ucBmpDeliveryAC = prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC; ++ rCmdIndicatePmBssConnected.ucBmpTriggerAC = prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC; ++ ++ /* DBGPRINTF("nicPmIndicateBssConnected: ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x", */ ++ /* rCmdIndicatePmBssConnected.ucBmpDeliveryAC, */ ++ /* rCmdIndicatePmBssConnected.ucBmpTriggerAC); */ ++ ++ if ((eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX) ++#if CFG_ENABLE_WIFI_DIRECT ++ || ((eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->fgIsP2PRegistered)) ++#endif ++ ) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = ++ (UINT_8) prBssInfo->prStaRecOfAP->fgIsUapsdSupported; ++ } else { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; /* @FIXME */ ++ } ++ } else { ++ rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; ++ } ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_CONNECTED, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_CONNECTED), ++ (PUINT_8)&rCmdIndicatePmBssConnected, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate PM that ++* a BSS has been disconnected ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ CMD_INDICATE_PM_BSS_ABORT rCmdIndicatePmBssAbort; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ rCmdIndicatePmBssAbort.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_INDICATE_PM_BSS_ABORT, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, ++ NULL, ++ sizeof(CMD_INDICATE_PM_BSS_ABORT), (PUINT_8)&rCmdIndicatePmBssAbort, NULL, 0); ++} ++ ++WLAN_STATUS ++nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, ++ ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent) ++{ ++ DEBUGFUNC("nicConfigPowerSaveProfile"); ++ DBGLOG(NIC, TRACE, "eNetTypeIndex:%d, ePwrMode:%d, fgEnCmdEvent:%d\n", ++ eNetTypeIndex, ePwrMode, fgEnCmdEvent); ++ ++ ASSERT(prAdapter); ++ ++ if (eNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { ++ ASSERT(0); ++ return WLAN_STATUS_NOT_SUPPORTED; ++ } ++/* prAdapter->rWlanInfo.ePowerSaveMode.ucNetTypeIndex = eNetTypeIndex; */ ++/* prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile = (UINT_8)ePwrMode; */ ++ prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucNetTypeIndex = eNetTypeIndex; ++ prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucPsProfile = (UINT_8) ePwrMode; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_POWER_SAVE_MODE, ++ TRUE, ++ FALSE, ++ (fgEnCmdEvent ? TRUE : FALSE), ++ (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), ++ (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), ++ sizeof(CMD_PS_PROFILE_T), ++ (PUINT_8)&(prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex]), ++ NULL, sizeof(PARAM_POWER_MODE) ++ ); ++ ++} /* end of wlanoidSetAcpiDevicePowerStateMode() */ ++ ++WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent) ++{ ++ CMD_SW_DBG_CTRL_T rCmdSwCtrl; ++ CMD_ACCESS_REG rCmdAccessReg; ++ WLAN_STATUS rWlanStatus; ++ ++ DEBUGFUNC("nicEnterCtiaMode"); ++ DBGLOG(NIC, TRACE, "nicEnterCtiaMode: %d\n", fgEnterCtia); ++ ++ ASSERT(prAdapter); ++ ++ rWlanStatus = WLAN_STATUS_SUCCESS; ++ ++ if (fgEnterCtia) { ++ /* 1. Disable On-Lin Scan */ ++ prAdapter->fgEnOnlineScan = FALSE; ++ ++ /* 3. Disable FIFO FULL no ack */ ++ rCmdAccessReg.u4Address = 0x60140028; ++ rCmdAccessReg.u4Data = 0x904; ++ wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ ++ FALSE, /* TRUE, */ ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); ++ ++ /* 4. Disable Roaming */ ++ rCmdSwCtrl.u4Id = 0x90000204; ++ rCmdSwCtrl.u4Data = 0x0; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ rCmdSwCtrl.u4Id = 0x90000200; ++ rCmdSwCtrl.u4Data = 0x820000; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* Disalbe auto tx power */ ++ rCmdSwCtrl.u4Id = 0xa0100003; ++ rCmdSwCtrl.u4Data = 0x0; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* 2. Keep at CAM mode */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ prAdapter->u4CtiaPowerMode = 0; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ ePowerMode = Param_PowerModeCAM; ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); ++ } ++ ++ /* 5. Disable Beacon Timeout Detection */ ++ prAdapter->fgDisBcnLostDetection = TRUE; ++ } else { ++ /* 1. Enaable On-Lin Scan */ ++ prAdapter->fgEnOnlineScan = TRUE; ++ ++ /* 3. Enable FIFO FULL no ack */ ++ rCmdAccessReg.u4Address = 0x60140028; ++ rCmdAccessReg.u4Data = 0x905; ++ wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ ++ FALSE, /* TRUE, */ ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); ++ ++ /* 4. Enable Roaming */ ++ rCmdSwCtrl.u4Id = 0x90000204; ++ rCmdSwCtrl.u4Data = 0x1; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ rCmdSwCtrl.u4Id = 0x90000200; ++ rCmdSwCtrl.u4Data = 0x820000; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* Enable auto tx power */ ++ /* */ ++ ++ rCmdSwCtrl.u4Id = 0xa0100003; ++ rCmdSwCtrl.u4Data = 0x1; ++ wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SW_DBG_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); ++ ++ /* 2. Keep at Fast PS */ ++ { ++ PARAM_POWER_MODE ePowerMode; ++ ++ prAdapter->u4CtiaPowerMode = 2; ++ prAdapter->fgEnCtiaPowerMode = TRUE; ++ ++ ePowerMode = Param_PowerModeFast_PSP; ++ rWlanStatus = nicConfigPowerSaveProfile(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); ++ } ++ ++ /* 5. Enable Beacon Timeout Detection */ ++ prAdapter->fgDisBcnLostDetection = FALSE; ++ ++ } ++ ++ return rWlanStatus; ++} /* end of nicEnterCtiaMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to indicate firmware domain ++* for beacon generation parameters ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eIeUpdMethod, Update Method ++* eNetTypeIndex Index of Network ++* u2Capability Capability ++* aucIe Pointer to buffer of IEs ++* u2IELen Length of IEs ++* ++* @retval - WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* WLAN_STATUS_PENDING ++* WLAN_STATUS_INVALID_DATA ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, ++ IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ++ IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen) ++{ ++ P_CMD_BEACON_TEMPLATE_UPDATE prCmdBcnUpdate; ++ UINT_16 u2CmdBufLen = 0; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_INFO_T prCmdInfo; ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_8 ucCmdSeqNum; ++ ++ DEBUGFUNC("wlanUpdateBeaconIETemplate"); ++ ++ DBGLOG(NIC, LOUD, "\nnicUpdateBeaconIETemplate\n"); ++ ++ ASSERT(prAdapter); ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (u2IELen > MAX_IE_LENGTH) ++ return WLAN_STATUS_INVALID_DATA; ++ ++ if (eIeUpdMethod == IE_UPD_METHOD_UPDATE_RANDOM || eIeUpdMethod == IE_UPD_METHOD_UPDATE_ALL) { ++ u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, aucIE) + u2IELen; ++ } else if (eIeUpdMethod == IE_UPD_METHOD_DELETE_ALL) { ++ u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, u2IELen); ++ } else { ++ ASSERT(0); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* prepare command info */ ++ prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u2CmdBufLen)); ++ if (!prCmdInfo) { ++ DBGLOG(NIC, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* increase command sequence number */ ++ ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); ++ DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); ++ ++ /* Setup common CMD Info Packet */ ++ prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; ++ prCmdInfo->eNetworkType = eNetTypeIndex; ++ prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u2CmdBufLen); ++ prCmdInfo->pfCmdDoneHandler = NULL; /* @FIXME */ ++ prCmdInfo->pfCmdTimeoutHandler = NULL; /* @FIXME */ ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->ucCID = CMD_ID_UPDATE_BEACON_CONTENT; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ prCmdInfo->fgDriverDomainMCR = FALSE; ++ prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; ++ prCmdInfo->u4SetInfoLen = u2CmdBufLen; ++ prCmdInfo->pvInformationBuffer = NULL; ++ prCmdInfo->u4InformationBufferLength = 0; ++ ++ /* Setup WIFI_CMD_T (no payload) */ ++ prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); ++ prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; ++ prWifiCmd->ucCID = prCmdInfo->ucCID; ++ prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; ++ prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; ++ ++ prCmdBcnUpdate = (P_CMD_BEACON_TEMPLATE_UPDATE) (prWifiCmd->aucBuffer); ++ ++ /* fill beacon updating command */ ++ prCmdBcnUpdate->ucUpdateMethod = (UINT_8) eIeUpdMethod; ++ prCmdBcnUpdate->ucNetTypeIndex = (UINT_8) eNetTypeIndex; ++ prCmdBcnUpdate->u2Capability = u2Capability; ++ prCmdBcnUpdate->u2IELen = u2IELen; ++ if (u2IELen > 0) ++ kalMemCopy(prCmdBcnUpdate->aucIE, aucIe, u2IELen); ++ ++ /* insert into prCmdQueue */ ++ kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ ++ /* wakeup txServiceThread later */ ++ GLUE_SET_EVENT(prGlueInfo); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to initialization PHY related ++* varaibles ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prAdapter); ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ ++ if (prConnSettings->eDesiredPhyConfig >= PHY_CONFIG_NUM) { ++ ASSERT(0); ++ return; ++ } ++ ++ prAdapter->rWifiVar.ucAvailablePhyTypeSet = aucPhyCfg2PhyTypeSet[prConnSettings->eDesiredPhyConfig]; ++ ++ if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_BIT_ERP) ++ prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_ERP_INDEX; ++ /* NOTE(Kevin): Because we don't have N only mode, TBD */ ++ else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ ++ ++ prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_HR_DSSS_INDEX; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* eNetworkTypeIdx Index of BSS-INFO ++* ++* @retval - ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_BSS_INFO_T prBssInfo; ++ CMD_UPDATE_WMM_PARMS_T rCmdUpdateWmmParms; ++ ++ ASSERT(prAdapter); ++ ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ DBGLOG(QM, EVENT, "sizeof(AC_QUE_PARMS_T): %zu\n", sizeof(AC_QUE_PARMS_T)); ++ DBGLOG(QM, EVENT, "sizeof(CMD_UPDATE_WMM_PARMS): %zu\n", sizeof(CMD_UPDATE_WMM_PARMS_T)); ++ DBGLOG(QM, EVENT, "sizeof(WIFI_CMD_T): %zu\n", sizeof(WIFI_CMD_T)); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); ++ rCmdUpdateWmmParms.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; ++ kalMemCopy(&rCmdUpdateWmmParms.arACQueParms[0], &prBssInfo->arACQueParms[0], (sizeof(AC_QUE_PARMS_T) * AC_NUM)); ++ ++ rCmdUpdateWmmParms.fgIsQBSS = prBssInfo->fgIsQBSS; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_UPDATE_WMM_PARMS, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_UPDATE_WMM_PARMS_T), (PUINT_8)&rCmdUpdateWmmParms, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update TX power gain corresponding to ++* each band/modulation combination ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) ++{ ++ DEBUGFUNC("nicUpdateTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_TX_PWR, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to set auto tx power parameter ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of Auto TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam) ++{ ++ DEBUGFUNC("nicSetAutoTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_AUTOPWR_CTRL, ++ TRUE, ++ FALSE, ++ FALSE, ++ NULL, NULL, sizeof(CMD_AUTO_POWER_PARAM_T), (PUINT_8) prAutoPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update TX power gain corresponding to ++* each band/modulation combination ++* ++* @param prAdapter Pointer of ADAPTER_T ++* prTxPwrParam Pointer of TX power parameters ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicSetAutoTxPowerControl(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) ++{ ++ DEBUGFUNC("nicUpdateTxPower"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_TX_PWR, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update power offset around 5GHz band ++* ++* @param prAdapter Pointer of ADAPTER_T ++* pr5GPwrOffset Pointer of 5GHz power offset parameter ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset) ++{ ++ DEBUGFUNC("nicUpdate5GOffset"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_5G_PWR_OFFSET, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_5G_PWR_OFFSET_T), (PUINT_8) pr5GPwrOffset, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update DPD calibration result ++* ++* @param prAdapter Pointer of ADAPTER_T ++* pr5GPwrOffset Pointer of parameter for DPD calibration result ++* ++* @retval WLAN_STATUS_PENDING ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult) ++{ ++ DEBUGFUNC("nicUpdateDPD"); ++ ++ ASSERT(prAdapter); ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_PWR_PARAM, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_PWR_PARAM_T), (PUINT_8) prDpdCalResult, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function starts system service such as timer and ++* memory pools ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* <1> Initialize MGMT Memory pool and STA_REC */ ++ cnmMemInit(prAdapter); ++ cnmStaRecInit(prAdapter); ++ cmdBufInitialize(prAdapter); ++ ++ /* <2> Mailbox Initialization */ ++ mboxInitialize(prAdapter); ++ ++ /* <3> Timer Initialization */ ++ cnmTimerInitialize(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function reset some specific system service, ++* such as STA-REC ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicResetSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ /* Timer Destruction */ ++ cnmTimerDestroy(prAdapter); ++ ++ /* Mailbox Destruction */ ++ mboxDestroy(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) ++{ ++ ASSERT(prAdapter); ++ ++ /* CNM Module - initialization */ ++ cnmInit(prAdapter); ++ ++ /* RLM Module - initialization */ ++ rlmFsmEventInit(prAdapter); ++ ++ /* SCN Module - initialization */ ++ scnInit(prAdapter); ++ ++ /* AIS Module - intiailization */ ++ aisInitializeConnectionSettings(prAdapter, prRegInfo); ++ aisFsmInit(prAdapter); ++ ++#if CFG_SUPPORT_ROAMING ++ /* Roaming Module - intiailization */ ++ roamingFsmInit(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++#if CFG_SUPPORT_SWCR ++ swCrDebugInit(prAdapter); ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexInit(prAdapter); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to update WMM Parms ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++#if CFG_SUPPORT_SWCR ++ swCrDebugUninit(prAdapter); ++#endif /* CFG_SUPPORT_SWCR */ ++ ++#if CFG_SUPPORT_ROAMING ++ /* Roaming Module - unintiailization */ ++ roamingFsmUninit(prAdapter); ++#endif /* CFG_SUPPORT_ROAMING */ ++ ++ /* AIS Module - unintiailization */ ++ aisFsmUninit(prAdapter); ++ ++ /* SCN Module - unintiailization */ ++ scnUninit(prAdapter); ++ ++ /* RLM Module - uninitialization */ ++ rlmFsmEventUninit(prAdapter); ++ ++ /* CNM Module - uninitialization */ ++ cnmUninit(prAdapter); ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexUninit(prAdapter); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++} ++ ++#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is to inform firmware to enable MCU clock gating ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4WHISR = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsClockGatingEnabled == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ ++ nicSetSwIntr(prAdapter, REQ_GATING_ENABLE_H2D_INT); ++ ++ i = 0; ++ while (i < GATING_CONTROL_POLL_LIMIT) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) ++ return WLAN_STATUS_FAILURE; ++ ++ HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); ++ ++ if (u4WHISR & ACK_GATING_ENABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = TRUE; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ ++ ASSERT(0); ++ return WLAN_STATUS_PENDING; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is to inform firmware to disable MCU clock gating ++* ++* @param prAdapter Pointer of ADAPTER_T ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4WHISR = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsClockGatingEnabled == FALSE) ++ return WLAN_STATUS_SUCCESS; ++ ++ nicSetSwIntr(prAdapter, REQ_GATING_DISABLE_H2D_INT); ++ ++ i = 0; ++ while (i < GATING_CONTROL_POLL_LIMIT) { ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) ++ return WLAN_STATUS_FAILURE; ++ ++ HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); ++ ++ if (u4WHISR & ACK_GATING_DISABLE_D2H_INT) { ++ prAdapter->fgIsClockGatingEnabled = FALSE; ++ return WLAN_STATUS_SUCCESS; ++ } ++ } ++ ++ ASSERT(0); ++ return WLAN_STATUS_PENDING; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked to buffer scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param rMacAddr BSSID ++* @param prSsid Pointer to SSID ++* @param u4Privacy Privacy settings (0: Open / 1: WEP/WPA/WPA2 enabled) ++* @param rRssi Received Strength (-10 ~ -200 dBm) ++* @param eNetworkType Network Type (a/b/g) ++* @param prConfiguration Network Parameter ++* @param eOpMode Infra/Ad-Hoc ++* @param rSupportedRates Supported basic rates ++* @param u2IELength IE Length ++* @param pucIEBuf Pointer to Information Elements(IEs) ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicAddScanResult(IN P_ADAPTER_T prAdapter, ++ IN PARAM_MAC_ADDRESS rMacAddr, ++ IN P_PARAM_SSID_T prSsid, ++ IN UINT_32 u4Privacy, ++ IN PARAM_RSSI rRssi, ++ IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, ++ IN P_PARAM_802_11_CONFIG_T prConfiguration, ++ IN ENUM_PARAM_OP_MODE_T eOpMode, ++ IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf) ++{ ++ BOOLEAN bReplace; ++ UINT_32 i; ++ UINT_32 u4IdxWeakest = 0; ++ PARAM_RSSI rWeakestRssi; ++ UINT_32 u4BufferSize; ++ ++ ASSERT(prAdapter); ++ ++ rWeakestRssi = (PARAM_RSSI) INT_MAX; ++ u4BufferSize = sizeof(prAdapter->rWlanInfo.aucScanIEBuf) / sizeof(prAdapter->rWlanInfo.aucScanIEBuf[0]); ++ ++ bReplace = FALSE; ++ ++ /* decide to replace or add */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ /* find weakest entry && not connected one */ ++ if (UNEQUAL_MAC_ADDR ++ (prAdapter->rWlanInfo.arScanResult[i].arMacAddress, prAdapter->rWlanInfo.rCurrBssId.arMacAddress) ++ && prAdapter->rWlanInfo.arScanResult[i].rRssi < rWeakestRssi) { ++ u4IdxWeakest = i; ++ rWeakestRssi = prAdapter->rWlanInfo.arScanResult[i].rRssi; ++ } ++ ++ if (prAdapter->rWlanInfo.arScanResult[i].eOpMode == eOpMode && ++ EQUAL_MAC_ADDR(&(prAdapter->rWlanInfo.arScanResult[i].arMacAddress), rMacAddr) && ++ (EQUAL_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen) ++ || prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen == 0)) { ++ /* replace entry */ ++ bReplace = TRUE; ++ ++ /* free IE buffer then zero */ ++ nicFreeScanResultIE(prAdapter, i); ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ /* IE - allocate buffer and update pointer */ ++ if (u2IELength > 0) { ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ ++ break; ++ } ++ } ++ ++ if (bReplace == FALSE) { ++ if (prAdapter->rWlanInfo.u4ScanResultNum < (CFG_MAX_NUM_BSS_LIST - 1)) { ++ i = prAdapter->rWlanInfo.u4ScanResultNum; ++ ++ /* zero */ ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ /* IE - allocate buffer and update pointer */ ++ if (u2IELength > 0) { ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ ++ prAdapter->rWlanInfo.u4ScanResultNum++; ++ } else if (rWeakestRssi != (PARAM_RSSI) INT_MAX) { ++ /* replace weakest one */ ++ i = u4IdxWeakest; ++ ++ /* free IE buffer then zero */ ++ nicFreeScanResultIE(prAdapter, i); ++ kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); ++ ++ /* then fill buffer */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length = ++ OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; ++ COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); ++ COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, ++ prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, ++ prSsid->aucSsid, prSsid->u4SsidLen); ++ prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; ++ prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; ++ prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; ++ kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), ++ prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); ++ prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; ++ kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), ++ rSupportedRates, sizeof(PARAM_RATES_EX)); ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; ++ ++ if (u2IELength > 0) { ++ /* IE - allocate buffer and update pointer */ ++ if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { ++ kalMemCopy(& ++ (prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), ++ pucIEBuf, u2IELength); ++ ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ &(prAdapter-> ++ rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); ++ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); ++ } else { ++ /* buffer is not enough */ ++ prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; ++ prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } else { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is invoked to free IE buffer for dedicated scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param u4Idx Index of Scan Result ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx) ++{ ++ UINT_32 i; ++ PUINT_8 pucPivot, pucMovePivot; ++ UINT_32 u4MoveSize, u4FreeSize, u4ReserveSize; ++ ++ ASSERT(prAdapter); ++ ASSERT(u4Idx < CFG_MAX_NUM_BSS_LIST); ++ ++ if (prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength == 0 ++ || prAdapter->rWlanInfo.apucScanResultIEs[u4Idx] == NULL) { ++ return; ++ } ++ ++ u4FreeSize = ALIGN_4(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength); ++ ++ pucPivot = prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]; ++ pucMovePivot = (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]) + u4FreeSize); ++ ++ u4ReserveSize = ((ULONG) pucPivot) - (ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])); ++ u4MoveSize = prAdapter->rWlanInfo.u4ScanIEBufferUsage - u4ReserveSize - u4FreeSize; ++ ++ /* 1. rest of buffer to move forward */ ++ kalMemCopy(pucPivot, pucMovePivot, u4MoveSize); ++ ++ /* 1.1 modify pointers */ ++ for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { ++ if (i != u4Idx) { ++ if (prAdapter->rWlanInfo.apucScanResultIEs[i] >= pucMovePivot) { ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = ++ (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[i]) - u4FreeSize); ++ } ++ } ++ } ++ ++ /* 1.2 reset the freed one */ ++ prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength = 0; ++ prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; ++ ++ /* 2. reduce IE buffer usage */ ++ prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4FreeSize; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is to hack parameters for WLAN TABLE for ++* fixed rate settings ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param eRateSetting ++* @param pu2DesiredNonHTRateSet, ++* @param pu2BSSBasicRateSet, ++* @param pucMcsSet ++* @param pucSupMcs32 ++* @param pu2HtCapInfo ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicUpdateRateParams(IN P_ADAPTER_T prAdapter, ++ IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, ++ IN PUINT_8 pucDesiredPhyTypeSet, ++ IN PUINT_16 pu2DesiredNonHTRateSet, ++ IN PUINT_16 pu2BSSBasicRateSet, ++ IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 pu2HtCapInfo) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eRateSetting > FIXED_RATE_NONE && eRateSetting < FIXED_RATE_NUM); ++ ++ switch (prAdapter->rWifiVar.eRateSetting) { ++ case FIXED_RATE_1M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_1M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_1M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_2M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_2M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_2M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_5_5M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_5_5M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_5_5M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_11M: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_11M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_11M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_6M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_6M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_6M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_9M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_9M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_9M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_12M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_12M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_12M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_18M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_18M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_18M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_24M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_24M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_24M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_36M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_36M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_36M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_48M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_48M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_48M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_54M: ++ if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; ++ else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; ++ ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_54M; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_54M; ++ *pucMcsSet = 0; ++ *pucSupMcs32 = 0; ++ *pu2HtCapInfo = 0; ++ break; ++ ++ case FIXED_RATE_MCS0_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS1_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS2_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS3_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS4_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS5_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS6_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS7_20M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH ++ | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ break; ++ ++ case FIXED_RATE_MCS0_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS1_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS2_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS3_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS4_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS5_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS6_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS7_20M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; ++ break; ++ ++ case FIXED_RATE_MCS0_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS1_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS2_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS3_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS4_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS5_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS6_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS7_40M_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS32_800NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS32_INDEX; ++ *pucSupMcs32 = 1; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; ++ break; ++ ++ case FIXED_RATE_MCS0_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS0_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS1_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS1_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS2_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS2_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS3_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS3_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS4_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS4_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS5_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS5_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS6_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS6_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS7_40M_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS7_INDEX; ++ *pucSupMcs32 = 0; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ case FIXED_RATE_MCS32_400NS: ++ *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; ++ *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; ++ *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; ++ *pucMcsSet = HT_RATE_MCS32_INDEX; ++ *pucSupMcs32 = 1; ++ (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); ++ (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to write the register ++* ++* @param u4Address Register address ++* u4Value the value to be written ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value) ++{ ++ CMD_ACCESS_REG rCmdAccessReg; ++ ++ rCmdAccessReg.u4Address = u4Address; ++ rCmdAccessReg.u4Data = u4Value; ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_ACCESS_REG, ++ TRUE, ++ FALSE, ++ FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8) &rCmdAccessReg, NULL, 0); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to modify the auto rate parameters ++* ++* @param u4ArSysParam0 see description below ++* u4ArSysParam1 ++* u4ArSysParam2 ++* u4ArSysParam3 ++* ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* ++* @note ++* ArSysParam0[0:3] -> auto rate version (0:disable 1:version1 2:version2) ++* ArSysParam0[4:5]-> auto bw version (0:disable 1:version1 2:version2) ++* ArSysParam0[6:7]-> auto gi version (0:disable 1:version1 2:version2) ++* ArSysParam0[8:15]-> HT rate clear mask ++* ArSysParam0[16:31]-> Legacy rate clear mask ++* ArSysParam1[0:7]-> Auto Rate check weighting window ++* ArSysParam1[8:15]-> Auto Rate v1 Force Rate down ++* ArSysParam1[16:23]-> Auto Rate v1 PerH ++* ArSysParam1[24:31]-> Auto Rate v1 PerL ++* ++* Examples ++* ArSysParam0 = 1, ++* Enable auto rate version 1 ++* ++* ArSysParam0 = 983041, ++* Enable auto rate version 1 ++* Remove CCK 1M, 2M, 5.5M, 11M ++* ++* ArSysParam0 = 786433 ++* Enable auto rate version 1 ++* Remove CCK 5.5M 11M ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4ArSysParam0, ++ IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3) ++{ ++ UINT_8 ucArVer, ucAbwVer, ucAgiVer; ++ UINT_16 u2HtClrMask; ++ UINT_16 u2LegacyClrMask; ++ UINT_8 ucArCheckWindow; ++ UINT_8 ucArPerL; ++ UINT_8 ucArPerH; ++ UINT_8 ucArPerForceRateDownPer; ++ ++ ucArVer = (UINT_8) (u4ArSysParam0 & BITS(0, 3)); ++ ucAbwVer = (UINT_8) ((u4ArSysParam0 & BITS(4, 5)) >> 4); ++ ucAgiVer = (UINT_8) ((u4ArSysParam0 & BITS(6, 7)) >> 6); ++ u2HtClrMask = (UINT_16) ((u4ArSysParam0 & BITS(8, 15)) >> 8); ++ u2LegacyClrMask = (UINT_16) ((u4ArSysParam0 & BITS(16, 31)) >> 16); ++ ++#if 0 ++ ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); ++ ucArPerForceRateDownPer = (UINT_8) ((u4ArSysParam1 & BITS(8, 15) >> 8)); ++ ucArPerH = (UINT_8) ((u4ArSysParam1 & BITS(16, 23)) >> 16); ++ ucArPerL = (UINT_8) ((u4ArSysParam1 & BITS(24, 31)) >> 24); ++#endif ++ ++ ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); ++ ucArPerForceRateDownPer = (UINT_8) (((u4ArSysParam1 >> 8) & BITS(0, 7))); ++ ucArPerH = (UINT_8) (((u4ArSysParam1 >> 16) & BITS(0, 7))); ++ ucArPerL = (UINT_8) (((u4ArSysParam1 >> 24) & BITS(0, 7))); ++ ++ DBGLOG(NIC, INFO, "ArParam %u %u %u %u\n", u4ArSysParam0, u4ArSysParam1, u4ArSysParam2, u4ArSysParam3); ++ DBGLOG(NIC, INFO, "ArVer %u AbwVer %u AgiVer %u\n", ucArVer, ucAbwVer, ucAgiVer); ++ DBGLOG(NIC, INFO, "HtMask %x LegacyMask %x\n", u2HtClrMask, u2LegacyClrMask); ++ DBGLOG(NIC, INFO, ++ "CheckWin %u RateDownPer %u PerH %u PerL %u\n", ucArCheckWindow, ucArPerForceRateDownPer, ucArPerH, ++ ucArPerL); ++ ++#define SWCR_DATA_ADDR(MOD, ADDR) (0x90000000+(MOD<<8)+(ADDR)) ++#define SWCR_DATA_CMD(CATE, WRITE, INDEX, OPT0, OPT1) ((CATE<<24) | (WRITE<<23) | (INDEX<<16) | (OPT0 << 8) | OPT1) ++#define SWCR_DATA0 0x0 ++#define SWCR_DATA1 0x4 ++#define SWCR_DATA2 0x8 ++#define SWCR_DATA3 0xC ++#define SWCR_DATA4 0x10 ++#define SWCR_WRITE 1 ++#define SWCR_READ 0 ++ ++ if (ucArVer > 0) { ++ /* dummy = WiFi.WriteMCR(&h90000104, &h00000001) */ ++ /* dummy = WiFi.WriteMCR(&h90000100, &h00850000) */ ++ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 1); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); ++ } else { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 0); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); ++ } ++ ++ /* ucArVer 0: none 1:PER 2:Rcpi */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArVer); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 7, 0, 0)); ++ ++ /* Candidate rate Ht mask */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2HtClrMask); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1c, 0, 0)); ++ ++ /* Candidate rate legacy mask */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2LegacyClrMask); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1d, 0, 0)); ++ ++#if 0 ++ if (ucArCheckWindow != 0) { ++ /* TX DONE MCS INDEX CHECK STA RATE DOWN TH */ ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x14, 0, 0)); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0xc, 0, 0)); ++ } ++ ++ if (ucArPerForceRateDownPer != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerForceRateDownPer); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x18, 0, 0)); ++ } ++ if (ucArPerH != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerH); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1, 0, 0)); ++ } ++ if (ucArPerL != 0) { ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerL); ++ nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x2, 0, 0)); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This utility function is used to enable roaming ++* ++* @param u4EnableRoaming ++* ++* ++* @retval WLAN_STATUS_SUCCESS ++* WLAN_STATUS_FAILURE ++* ++* @note ++* u4EnableRoaming -> Enable Romaing ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming) ++{ ++ P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ prConnSettings = &(prAdapter->rWifiVar.rConnSettings); ++ prConnSettings->fgIsEnableRoaming = ((u4EnableRoaming > 0) ? (TRUE) : (FALSE)); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief dump firmware Assert message ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4MailBox0, u4MailBox1; ++ UINT_32 line = 0; ++ UINT_8 aucAssertFile[7]; ++ UINT_32 u4ChipId; ++ ++#if CFG_SDIO_INTR_ENHANCE ++ u4MailBox0 = prAdapter->prSDIOCtrl->u4RcvMailbox0; ++ u4MailBox1 = prAdapter->prSDIOCtrl->u4RcvMailbox1; ++#else ++ nicGetMailbox(prAdapter, 0, &u4MailBox0); ++ nicGetMailbox(prAdapter, 1, &u4MailBox1); ++#endif ++ ++ line = u4MailBox0 & 0x0000FFFF; ++ ++ u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); ++ ++ kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); ++ kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); ++ ++ aucAssertFile[6] = '\0'; ++ ++#if defined(MT6620) ++ u4ChipId = 6620; ++#elif defined(MT6628) ++ u4ChipId = 6582; ++#endif ++ ++ kalPrint("\n[MT%u][wifi][Firmware] Assert at \"%s\" #%u\n\n", u4ChipId, aucAssertFile, line); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* prEventLinkQuality ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ASSERT(prEventLinkQuality); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* check is to prevent RSSI to be updated by incorrect initial RSSI from hardware */ ++ /* buffer statistics for further query */ ++ if (prAdapter->fgIsLinkQualityValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ nicUpdateRSSI(prAdapter, eNetTypeIdx, prEventLinkQuality->cRssi, ++ prEventLinkQuality->cLinkQuality); ++ } ++ ++ if (prAdapter->fgIsLinkRateValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ nicUpdateLinkSpeed(prAdapter, eNetTypeIdx, prEventLinkQuality->u2LinkSpeed); ++ } ++ } ++ break; ++#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY ++ case NETWORK_TYPE_P2P_INDEX: ++ if (prAdapter->fgIsP2pLinkQualityValid == FALSE ++ || (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { ++ P_EVENT_LINK_QUALITY_EX prEventLQEx = (P_EVENT_LINK_QUALITY_EX) prEventLinkQuality; ++ ++ nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, prEventLQEx->cRssiP2P, ++ prEventLQEx->cLinkQualityP2P); ++ } ++ break; ++#endif ++ default: ++ break; ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update RSSI and Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicUpdateRSSI(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ prAdapter->fgIsLinkQualityValid = TRUE; ++ prAdapter->rLinkQualityUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rLinkQuality.cRssi = cRssi; ++ prAdapter->rLinkQuality.cLinkQuality = cLinkQuality; ++ ++ /* indicate to glue layer */ ++ kalUpdateRSSI(prAdapter->prGlueInfo, ++ KAL_NETWORK_TYPE_AIS_INDEX, ++ prAdapter->rLinkQuality.cRssi, prAdapter->rLinkQuality.cLinkQuality); ++ } ++ ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case NETWORK_TYPE_P2P_INDEX: ++ prAdapter->fgIsP2pLinkQualityValid = TRUE; ++ prAdapter->rP2pLinkQualityUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rP2pLinkQuality.cRssi = cRssi; ++ prAdapter->rP2pLinkQuality.cLinkQuality = cLinkQuality; ++ ++ kalUpdateRSSI(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_P2P_INDEX, cRssi, cLinkQuality); ++ break; ++#endif ++#endif ++ default: ++ break; ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called to update Link Quality information ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* eNetTypeIdx ++* prEventLinkQuality ++* cRssi ++* cLinkQuality ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed) ++{ ++ ASSERT(prAdapter); ++ ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); ++ ++ switch (eNetTypeIdx) { ++ case NETWORK_TYPE_AIS_INDEX: ++ if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ /* buffer statistics for further query */ ++ prAdapter->fgIsLinkRateValid = TRUE; ++ prAdapter->rLinkRateUpdateTime = kalGetTimeTick(); ++ ++ prAdapter->rLinkQuality.u2LinkSpeed = u2LinkSpeed; ++ } ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++} ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam) ++{ ++ DEBUGFUNC("nicUpdateRddTestMode.\n"); ++ ++ ASSERT(prAdapter); ++ ++/* aisFsmScanRequest(prAdapter, NULL); */ ++ ++ return wlanSendSetQueryCmd(prAdapter, ++ CMD_ID_SET_RDD_CH, ++ TRUE, ++ FALSE, FALSE, NULL, NULL, sizeof(CMD_RDD_CH_T), (PUINT_8) prRddChParam, NULL, 0); ++} ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c +new file mode 100644 +index 000000000000..3c9c24f9542b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c +@@ -0,0 +1,1636 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_cmd_event.c#1 ++*/ ++ ++/*! \file nic_cmd_event.c ++ \brief Callback functions for Command packets. ++ ++ Various Event packet handlers which will be setup in the callback function of ++ a command packet. ++*/ ++ ++/* ++** Log: nic_cmd_event.c ++ * ++ * 04 10 2012 yuche.tsai ++ * NULL ++ * Update address for wifi direct connection issue. ++ * ++ * 06 15 2011 cm.chang ++ * [WCXRP00000785] [MT6620 Wi-Fi][Driver][FW] P2P/BOW MAC address is XOR with AIS MAC address ++ * P2P/BOW mac address XOR with local bit instead of OR ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000493] [MT6620 Wi-Fi][Driver] Do not indicate redundant disconnection to host when entering into RF ++ * test mode ++ * only indicate DISCONNECTION to host when entering RF test if necessary (connected -> disconnected cases) ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to ++ * system scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 01 2010 cp.wu ++ * [WCXRP00000223] MT6620 Wi-Fi][Driver][FW] Adopt NVRAM parameters when enter/exit RF test mode ++ * reload NVRAM settings before entering RF test mode and leaving from RF test mode. ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 20 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * use OID_CUSTOM_TEST_MODE as indication for driver reset ++ * by dropping pending TX packets ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 15 2010 yuche.tsai ++ * NULL ++ * Start to test AT GO only when P2P state is not IDLE. ++ * ++ * 09 09 2010 yuche.tsai ++ * NULL ++ * Add AT GO Test mode after MAC address available. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. ++ * There is no CFG_SUPPORT_BOW in driver domain source. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 11 2010 yuche.tsai ++ * NULL ++ * Add support for P2P Device Address query from FW. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 08 02 2010 cp.wu ++ * NULL ++ * reset FSMs before entering RF test mode. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 05 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. ++ * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change upon request: indicate as disconnected in driver domain when leaving from RF test mode ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * do not clear scanning list array after disassociation ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. ++ * 2) finish statistics OIDs ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * change OID behavior to meet WHQL requirement. ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct OID_802_11_DISASSOCIATE handling. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * are done in adapter layer. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glude code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sync statistics data structure definition with firmware implementation ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * statistics information OIDs are now handled by querying from firmware domain ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * indicate media stream mode after set is done ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement custom OID: EEPROM read/write access ++ * ++ * 03 03 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_3_MULTICAST_LIST oid handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * limit RSSI return value to micxxsoft defined range. ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * block until firmware finished RF test enter/leave then indicate completion to upper layer ++ * ++ * 01 29 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when entering RF test mode and leaving from RF test mode, wait for W_FUNC_RDY bit to be asserted forever until it ++ * is set or card is removed. ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * * 4. correct some HAL implementation ++ * ++ * 01 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * * OID_802_11_RSSI, ++ * * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * * OID_802_11_STATISTICS, ++ * * * * * OID_802_11_DISASSOCIATE, ++ * * * * * OID_802_11_POWER_MODE ++ * ++ * 01 21 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement OID_802_11_MEDIA_STREAM_MODE ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:47:47 GMT mtk02752 ++** only handle MCR read when accessing FW domain register ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 17:37:28 GMT mtk02752 ++** * refine nicCmdEventQueryMcrRead ++** + add TxStatus/RxStatus for RF test QueryInformation OIDs ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 22:05:45 GMT mtk02752 ++** kalOidComplete() will decrease i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-01 23:02:57 GMT mtk02752 ++** remove unnecessary spin locks ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-01 22:51:18 GMT mtk02752 ++** maintein i4OidPendingCount ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-30 10:55:03 GMT mtk02752 ++** modify for compatibility ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 14:46:32 GMT mtk02752 ++** add another version of command-done handler upon new event structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:33 GMT mtk01461 ++** Add comment ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 19:32:42 GMT mtk01461 ++** Add nicCmdEventSetCommon() for general set OID ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:35 GMT mtk01461 ++** Command Done Handler ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_ACCESS_REG prCmdAccessReg; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdAccessReg = (P_CMD_ACCESS_REG) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); ++ ++ prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prMcrRdInfo->u4McrOffset = prCmdAccessReg->u4Address; ++ prMcrRdInfo->u4McrData = prCmdAccessReg->u4Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_CMD_SW_DBG_CTRL_T prCmdSwCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prCmdSwCtrl = (P_CMD_SW_DBG_CTRL_T) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); ++ ++ prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prSwCtrlInfo->u4Id = prCmdSwCtrl->u4Id; ++ prSwCtrlInfo->u4Data = prCmdSwCtrl->u4Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4InformationBufferLength, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ } ++ ++ DBGLOG(NIC, TRACE, "DisByCmdE\n"); ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++#if !defined(LINUX) ++ prAdapter->fgIsRadioOff = TRUE; ++#endif ++ ++} ++ ++VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4Count; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ u4Count = (prCmdInfo->u4SetInfoLen - OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress)) ++ / sizeof(IPV4_NETWORK_ADDRESS); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress) + u4Count * ++ (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP)), ++ WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_TEST_STATUS prTestStatus, prQueryBuffer; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTestStatus = (P_EVENT_TEST_STATUS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prQueryBuffer = (P_EVENT_TEST_STATUS) prCmdInfo->pvInformationBuffer; ++ ++ kalMemCopy(prQueryBuffer, prTestStatus, sizeof(EVENT_TEST_STATUS)); ++ ++ u4QueryInfoLen = sizeof(EVENT_TEST_STATUS); ++ ++ /* Update Query Information Length */ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ PARAM_RSSI rRssi, *prRssi; ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ rRssi = (PARAM_RSSI) prLinkQuality->cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ ++ DBGLOG(NIC, INFO, " %s: rRssi = %d\n", __func__, rRssi); ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { ++ if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) ++ rRssi = PARAM_WHQL_RSSI_MAX_DBM; ++ else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ } else { ++ rRssi = PARAM_WHQL_RSSI_MIN_DBM; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prRssi = (PARAM_RSSI *) prCmdInfo->pvInformationBuffer; ++ ++ kalMemCopy(prRssi, &rRssi, sizeof(PARAM_RSSI)); ++ u4QueryInfoLen = sizeof(PARAM_RSSI); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is in response of OID_GEN_LINK_SPEED query request ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the pending command info ++* @param pucEventBuf ++* ++* @retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_LINK_QUALITY prLinkQuality; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4LinkSpeed; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ pu4LinkSpeed = (PUINT_32) (prCmdInfo->pvInformationBuffer); ++ ++ *pu4LinkSpeed = prLinkQuality->u2LinkSpeed * 5000; ++ ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ u4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ ++ prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); ++ prStatistics->rTransmittedFragmentCount = prEventStatistics->rTransmittedFragmentCount; ++ prStatistics->rMulticastTransmittedFrameCount = prEventStatistics->rMulticastTransmittedFrameCount; ++ prStatistics->rFailedCount = prEventStatistics->rFailedCount; ++ prStatistics->rRetryCount = prEventStatistics->rRetryCount; ++ prStatistics->rMultipleRetryCount = prEventStatistics->rMultipleRetryCount; ++ prStatistics->rRTSSuccessCount = prEventStatistics->rRTSSuccessCount; ++ prStatistics->rRTSFailureCount = prEventStatistics->rRTSFailureCount; ++ prStatistics->rACKFailureCount = prEventStatistics->rACKFailureCount; ++ prStatistics->rFrameDuplicateCount = prEventStatistics->rFrameDuplicateCount; ++ prStatistics->rReceivedFragmentCount = prEventStatistics->rReceivedFragmentCount; ++ prStatistics->rMulticastReceivedFrameCount = prEventStatistics->rMulticastReceivedFrameCount; ++ prStatistics->rFCSErrorCount = prEventStatistics->rFCSErrorCount; ++ prStatistics->rTKIPLocalMICFailures.QuadPart = 0; ++ prStatistics->rTKIPICVErrors.QuadPart = 0; ++ prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; ++ prStatistics->rTKIPReplays.QuadPart = 0; ++ prStatistics->rCCMPFormatErrors.QuadPart = 0; ++ prStatistics->rCCMPReplays.QuadPart = 0; ++ prStatistics->rCCMPDecryptErrors.QuadPart = 0; ++ prStatistics->rFourWayHandshakeFailures.QuadPart = 0; ++ prStatistics->rWEPUndecryptableCount.QuadPart = 0; ++ prStatistics->rWEPICVErrorCount.QuadPart = 0; ++ prStatistics->rDecryptSuccessCount.QuadPart = 0; ++ prStatistics->rDecryptFailureCount.QuadPart = 0; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++#define WAIT_FW_READY_RETRY_CNT 200 ++ ++ UINT_32 u4WHISR = 0, u4Value = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_16 u2RetryCnt = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* [driver-land] */ ++ prAdapter->fgTestMode = TRUE; ++ ++ /* 0. always indicate disconnection */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ /* 1. Remove pending TX */ ++ nicTxRelease(prAdapter); ++ ++ /* 1.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 1.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 2. Reset driver-domain FSMs */ ++ nicUninitMGMT(prAdapter); ++ ++ nicResetSystemService(prAdapter); ++ nicInitMGMT(prAdapter, NULL); ++ ++ /* 3. Disable Interrupt */ ++ HAL_INTR_DISABLE(prAdapter); ++ ++ /* 4. Block til firmware completed entering into RF test mode */ ++ kalMsleep(500); ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || ++ kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); ++ ++ } ++ return; ++ } ++ kalMsleep(10); ++ u2RetryCnt++; ++ } ++ ++ /* 5. Clear Interrupt Status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ /* 6. Reset TX Counter */ ++ nicTxResetResource(prAdapter); ++ ++ /* 7. Re-enable Interrupt */ ++ HAL_INTR_ENABLE(prAdapter); ++ ++ /* 8. completion indication */ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++#if CFG_SUPPORT_NVRAM ++ /* 9. load manufacture data */ ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ ++} ++ ++VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++#define WAIT_FW_READY_RETRY_CNT 200 ++ ++ UINT_32 u4WHISR = 0, u4Value = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_16 u2RetryCnt = 0; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ /* 1. Disable Interrupt */ ++ HAL_INTR_DISABLE(prAdapter); ++ ++ /* 2. Block til firmware completed leaving from RF test mode */ ++ kalMsleep(500); ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || ++ kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, ++ prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); ++ ++ } ++ return; ++ } ++ kalMsleep(10); ++ u2RetryCnt++; ++ } ++ ++ /* 3. Clear Interrupt Status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ /* 4. Reset TX Counter */ ++ nicTxResetResource(prAdapter); ++ ++ /* 5. Re-enable Interrupt */ ++ HAL_INTR_ENABLE(prAdapter); ++ ++ /* 6. set driver-land variable */ ++ prAdapter->fgTestMode = FALSE; ++ ++ /* 7. completion indication */ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ /* 8. Indicate as disconnected */ ++ if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++#if CFG_SUPPORT_NVRAM ++ /* 9. load manufacture data */ ++ wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); ++#endif ++ ++ /* 10. Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++} ++ ++VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_BASIC_CONFIG prEventBasicConfig; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (pucEventBuf); ++ ++ /* copy to adapter */ ++ kalMemCopy(&(prAdapter->rMyMacAddr), &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ kalMemCopy(prCmdInfo->pvInformationBuffer, &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); ++ u4QueryInfoLen = MAC_ADDR_LEN; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ /* 4 <3> Update new MAC address and all 3 networks */ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, prAdapter->rMyMacAddr); ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucDeviceAddress, prAdapter->rMyMacAddr); ++ prAdapter->rWifiVar.aucDeviceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.aucInterfaceAddress, prAdapter->rMyMacAddr); ++ prAdapter->rWifiVar.aucInterfaceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; ++ ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucOwnMacAddr, prAdapter->rMyMacAddr); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].aucOwnMacAddr, ++ prAdapter->rWifiVar.aucDeviceAddress); ++#endif ++ ++#if CFG_TEST_WIFI_DIRECT_GO ++ if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_IDLE) { ++ wlanEnableP2pFunction(prAdapter); ++ ++ wlanEnableATGO(prAdapter); ++ } ++#endif ++ ++ kalUpdateMACAddress(prAdapter->prGlueInfo, prAdapter->rWifiVar.aucMacAddress); ++ ++} ++ ++VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_MAC_MCAST_ADDR prEventMacMcastAddr; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventMacMcastAddr = (P_EVENT_MAC_MCAST_ADDR) (pucEventBuf); ++ ++ u4QueryInfoLen = prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN; ++ ++ /* buffer length check */ ++ if (prCmdInfo->u4InformationBufferLength < u4QueryInfoLen) { ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_BUFFER_TOO_SHORT); ++ } else { ++ kalMemCopy(prCmdInfo->pvInformationBuffer, ++ prEventMacMcastAddr->arAddress, ++ prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ } ++} ++ ++VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRdInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_ACCESS_EEPROM prEventAccessEeprom; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventAccessEeprom = (P_EVENT_ACCESS_EEPROM) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); ++ ++ prEepromRdInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prEepromRdInfo->ucEepromIndex = (UINT_8) (prEventAccessEeprom->u2Offset); ++ prEepromRdInfo->u2EepromData = prEventAccessEeprom->u2Data; ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ return; ++ ++} ++ ++VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ PARAM_MEDIA_STREAMING_INDICATION rParamMediaStreamIndication; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ if (prCmdInfo->fgIsOid) { ++ /* Update Set Information Length */ ++ kalOidComplete(prAdapter->prGlueInfo, ++ prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++ rParamMediaStreamIndication.rStatus.eStatusType = ENUM_STATUS_TYPE_MEDIA_STREAM_MODE; ++ rParamMediaStreamIndication.eMediaStreamMode = ++ prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&rParamMediaStreamIndication, sizeof(PARAM_MEDIA_STREAMING_INDICATION)); ++} ++ ++/* Statistics responder */ ++VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rTransmittedFragmentCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rTransmittedFragmentCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rReceivedFragmentCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rReceivedFragmentCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; ++ /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = 0; /* @FIXME? */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = 0; /* @FIXME? */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) 0; /* @FIXME */ ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = 0; /* @FIXME */ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = ++ (UINT_32) (prEventStatistics->rMultipleRetryCount.QuadPart - ++ prEventStatistics->rRetryCount.QuadPart); ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = ++ (UINT_64) (prEventStatistics->rMultipleRetryCount.QuadPart - ++ prEventStatistics->rRetryCount.QuadPart); ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rMultipleRetryCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rMultipleRetryCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ P_EVENT_STATISTICS prEventStatistics; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4QueryInfoLen; ++ PUINT_32 pu4Data; ++ PUINT_64 pu8Data; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { ++ u4QueryInfoLen = sizeof(UINT_32); ++ ++ pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; ++ *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; ++ } else { ++ u4QueryInfoLen = sizeof(UINT_64); ++ ++ pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; ++ *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command by OID/ioctl has been timeout ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* ++* @return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is a generic command timeout handler ++* ++* @param pfnOidHandler Pointer to the OID handler ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command for entering RF test has ++* failed sending due to timeout (highly possibly by firmware crash) ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) ++{ ++ ASSERT(prAdapter); ++ ++ /* 1. Remove pending TX frames */ ++ nicTxRelease(prAdapter); ++ ++ /* 1.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 1.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 2. indicate for OID failure */ ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when command for memory dump has ++* replied a event. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; ++ P_GLUE_INFO_T prGlueInfo; ++ P_EVENT_DUMP_MEM_T prEventDumpMem; ++ static UINT_8 aucPath[256]; ++ static UINT_32 u4CurTimeTick; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventDumpMem = (P_EVENT_DUMP_MEM_T) (pucEventBuf); ++ ++ u4QueryInfoLen = sizeof(P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T); ++ ++ prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) prCmdInfo->pvInformationBuffer; ++ prMemDumpInfo->u4Address = prEventDumpMem->u4Address; ++ prMemDumpInfo->u4Length = prEventDumpMem->u4Length; ++ prMemDumpInfo->u4RemainLength = prEventDumpMem->u4RemainLength; ++ prMemDumpInfo->ucFragNum = prEventDumpMem->ucFragNum; ++ ++#if 0 ++ do { ++ UINT_32 i = 0; ++ ++ DBGLOG(REQ, TRACE, "Rx dump address 0x%X, Length %d, FragNum %d, remain %d\n", ++ prEventDumpMem->u4Address, ++ prEventDumpMem->u4Length, prEventDumpMem->ucFragNum, prEventDumpMem->u4RemainLength); ++#if 0 ++ for (i = 0; i < prEventDumpMem->u4Length; i++) { ++ DBGLOG(REQ, TRACE, "%02X ", prEventDumpMem->aucBuffer[i]); ++ if (i % 32 == 31) ++ DBGLOG(REQ, TRACE, "\n"); ++ } ++#endif ++ } while (FALSE); ++#endif ++ ++ if (prEventDumpMem->ucFragNum == 1) { ++ /* Store memory dump into sdcard, ++ * path /sdcard/dump___.hex ++ */ ++ u4CurTimeTick = kalGetTimeTick(); ++ sprintf(aucPath, "/sdcard/dump_%d_0x%08X_%d.hex", ++ u4CurTimeTick, ++ prEventDumpMem->u4Address, prEventDumpMem->u4Length + prEventDumpMem->u4RemainLength); ++ kalWriteToFile(aucPath, FALSE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); ++ } else { ++ /* Append current memory dump to the hex file */ ++ kalWriteToFile(aucPath, TRUE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); ++ } ++ ++ if (prEventDumpMem->u4RemainLength == 0 || prEventDumpMem->u4Address == 0xFFFFFFFF) { ++ /* The request is finished or firmware response a error */ ++ /* Reply time tick to iwpriv */ ++ *((PUINT_32) prCmdInfo->pvInformationBuffer) = u4CurTimeTick; ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } else { ++ /* The memory dump request is not finished, Send next command */ ++ wlanSendMemDumpCmd(prAdapter, ++ prCmdInfo->pvInformationBuffer, prCmdInfo->u4InformationBufferLength); ++ } ++ } ++ ++ return; ++ ++} ++ ++#if CFG_SUPPORT_BATCH_SCAN ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for SUPPORT_BATCH_SCAN ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_BATCH_RESULT_T prEventBatchResult; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DBGLOG(SCN, TRACE, "nicCmdEventBatchScanResult"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEventBatchResult, sizeof(EVENT_BATCH_RESULT_T)); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++ ++#if CFG_SUPPORT_BUILD_DATE_CODE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for build date code information ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_BUILD_DATE_CODE prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_BUILD_DATE_CODE) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(UINT_8) * 16; ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent->aucDateCode, sizeof(UINT_8) * 16); ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query STA link status ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_STA_STATISTICS_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_STA_STATISTICS prStaStatistics; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_STA_STATISTICS_T) pucEventBuf; ++ prStaStatistics = (P_PARAM_GET_STA_STATISTICS) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ prStaStatistics->ucPer = prEvent->ucPer; ++ prStaStatistics->ucRcpi = prEvent->ucRcpi; ++ prStaStatistics->u4PhyMode = prEvent->u4PhyMode; ++ prStaStatistics->u2LinkSpeed = prEvent->u2LinkSpeed; ++ ++ prStaStatistics->u4TxFailCount = prEvent->u4TxFailCount; ++ prStaStatistics->u4TxLifeTimeoutCount = prEvent->u4TxLifeTimeoutCount; ++ ++ if (prEvent->u4TxCount) { ++ UINT_32 u4TxDoneAirTimeMs = USEC_TO_MSEC(prEvent->u4TxDoneAirTime * 32); ++ ++ prStaStatistics->u4TxAverageAirTime = (u4TxDoneAirTimeMs / prEvent->u4TxCount); ++ } else { ++ prStaStatistics->u4TxAverageAirTime = 0; ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++/* 4 Auto Channel Selection */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query STA link status ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_CHN_LOAD_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_CHN_LOAD prChnLoad; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_CHN_LOAD_T) pucEventBuf; /* 4 The firmware responsed data */ ++ /* 4 Fill the firmware data in and send it back to host */ ++ prChnLoad = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ prChnLoad->rEachChnLoad[0].ucChannel = prEvent->ucChannel; ++ prChnLoad->rEachChnLoad[0].u2ChannelLoad = prEvent->u2ChannelLoad; ++ DBGLOG(P2P, INFO, "CHN[%d]=%d\n", prEvent->ucChannel, prEvent->u2ChannelLoad); ++ ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++ ++VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_8 ucIdx = 0; ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_LTE_MODE_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_PARAM_GET_CHN_LOAD prLteSafeChnInfo; ++ ++ if ((prAdapter == NULL) ++ || (prCmdInfo == NULL) ++ || (pucEventBuf == NULL) ++ || (prCmdInfo->pvInformationBuffer == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_LTE_MODE_T) pucEventBuf; /* 4 The firmware responsed data */ ++ ++ prLteSafeChnInfo = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; ++ ++ u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); ++ ++ /* Statistics from FW is valid */ ++ if (prEvent->u4Flags & BIT(0)) { ++ for (ucIdx = 0; ucIdx < (NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1); ucIdx++) { ++ prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx] = ++ prEvent->rLteSafeChn.au4SafeChannelBitmask[ucIdx]; ++ ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]LTE safe channels [%d]=[%x]\n", ucIdx, ++ (UINT32) prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx]); ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is called when event for query FW bss info ++* has been retrieved ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prCmdInfo Pointer to the command information ++* @param pucEventBuf Pointer to the event buffer ++* ++* @return none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) ++{ ++ UINT_32 u4QueryInfoLen; ++ P_EVENT_AIS_BSS_INFO_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ P_BSS_INFO_T prAisBssInfo; ++ ++ ASSERT(prAdapter); ++ ++ ASSERT(prCmdInfo); ++ ASSERT(pucEventBuf); ++ ++ /* 4 <2> Update information of OID */ ++ if (prCmdInfo->fgIsOid) { ++ prGlueInfo = prAdapter->prGlueInfo; ++ prEvent = (P_EVENT_AIS_BSS_INFO_T) pucEventBuf; ++ ++ u4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); ++ kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent, sizeof(EVENT_AIS_BSS_INFO_T)); ++ prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ ++ if (prEvent->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { ++ if (prEvent->eConnectionState != prAisBssInfo->eConnectionState) { ++ DBGLOG(NIC, ERROR, "driver[%d] & FW[%d] status didn't sync !!!\n", ++ prAisBssInfo->eConnectionState, prEvent->eCurrentOPMode); ++ aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, FALSE); ++ } ++ } ++ ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); ++ } ++ ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c +new file mode 100644 +index 000000000000..cf80fd999a24 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c +@@ -0,0 +1,669 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_pwr_mgt.c#1 ++*/ ++ ++/*! \file "nic_pwr_mgt.c" ++ \brief In this file we define the STATE and EVENT for Power Management FSM. ++ ++ The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter ++ ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail ++ description. ++*/ ++ ++/* ++** Log: nic_pwr_mgt.c ++ * ++ * 11 28 2011 cp.wu ++ * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when ++ * returining to ROM code ++ * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware ++ * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not ++ * ++ * 10 03 2011 cp.wu ++ * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality ++ * add firmware download path in divided scatters. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * reuse firmware download logic of MT6620 for MT6628. ++ * ++ * 05 11 2011 cp.wu ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. ++ * ++ * 04 29 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * fix for compilation error when applied with FW_DOWNLOAD = 0 ++ * ++ * 04 18 2011 cp.wu ++ * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) ++ * 1) add API for glue layer to query ACPI state ++ * 2) Windows glue should not access to hardware after switched into D3 state ++ * ++ * 04 13 2011 cp.wu ++ * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete ++ * refine for MT5931/MT6620 logic separation. ++ * ++ * 04 13 2011 cp.wu ++ * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete ++ * bugfix: firmware download procedure for ACPI state transition is not complete. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * check success or failure for setting fw-own ++ * ++ * 12 30 2010 cp.wu ++ * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side ++ * host driver not to set FW-own when there is still pending interrupts ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * add firmware download for MT5931. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * reset ACPI power state before waking up MT6620 Wi-Fi firmware. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * Centralize mgmt/system service procedures into independent calls. ++ * ++ * 07 22 2010 cp.wu ++ * ++ * 1) refine AIS-FSM indent. ++ * 2) when entering RF Test mode, flush 802.1X frames as well ++ * 3) when entering D3 state, flush 802.1X frames as well ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll ++ * 2) correct address list parsing ++ * ++ * 05 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * sleepy notify is only used for sleepy state, ++ * while wake-up state is automatically set when host needs to access device ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct hibernation problem. ++ * ++ * 04 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) surpress compiler warning ++ * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when acquiring driver-own, wait for up to 8 seconds. ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove redundant firmware image unloading ++ * * 2) use compile-time macros to separate logic related to accquiring own ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * are now handled in glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * ePowerCtrl is not necessary as a glue variable. ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * always send CMD_NIC_POWER_CTRL packet when nic is being halted ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct typo. ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX ++ * response ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-13 21:59:15 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-09-09 17:26:36 GMT mtk01084 ++** remove CMD52 access ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-18 14:50:29 GMT mtk01084 ++** modify lines in nicpmSetDriverOwn() ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:55:37 GMT mtk01084 ++** modify nicpmSetDriverOwn() ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:33:00 GMT mtk01084 ++** update for basic power management functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:32 GMT mtk01084 ++** Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to process the POWER ON procedure. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt) ++{ ++ UINT_32 u4RegValue = 0; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsFwOwn == TRUE) ++ return; ++ ++ if (nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ /* pending interrupts */ ++ return; ++ } ++ ++ if (fgEnableGlobalInt) { ++ prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; ++ } else { ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); ++ ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ /* if set firmware own not successful (possibly pending interrupts), */ ++ /* indicate an own clear event */ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ ++ return; ++ } ++ ++ prAdapter->fgIsFwOwn = TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to process the POWER OFF procedure. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4OriRegValue = 0; ++BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter) ++{ ++#define LP_OWN_BACK_TOTAL_DELAY_MS 2000 /* exponential of 2 */ ++#define LP_OWN_BACK_LOOP_DELAY_MS 1 /* exponential of 2 */ ++#define LP_OWN_BACK_CLR_OWN_ITERATION 256 /* exponential of 2 */ ++ ++ BOOLEAN fgStatus = TRUE; ++ UINT_32 i, u4CurrTick; ++ UINT_32 u4RegValue = 0; ++ GL_HIF_INFO_T *HifInfo; ++ ++ ASSERT(prAdapter); ++ ++ if (prAdapter->fgIsFwOwn == FALSE) ++ return fgStatus; ++ ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ ++ u4CurrTick = kalGetTimeTick(); ++ STATS_DRIVER_OWN_START_RECORD(); ++ i = 0; ++ ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); ++ prAdapter->fgIsFwOwn = FALSE; ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE ++ || fgIsBusAccessFailed == TRUE ++ || (kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS || fgIsResetting == TRUE) { ++ /* ERRORLOG(("LP cannot be own back (for %ld ms)", kalGetTimeTick() - u4CurrTick)); */ ++ fgStatus = FALSE; ++ if (fgIsResetting != TRUE) { ++ UINT_32 u4FwCnt; ++ static unsigned int u4OwnCnt; ++ /* MCR_D2HRM2R: low 4 bit means interrupt times, ++ * high 4 bit means firmware response times. ++ * ORI_MCR_D2HRM2R: the last successful value. ++ * for example: ++ * MCR_D2HRM2R = 0x44, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware no receive interrupt form hardware. ++ * MCR_D2HRM2R = 0x45, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware no send response. ++ * MCR_D2HRM2R = 0x55, ORI_MCR_D2HRM2R = 0x44 ++ * means firmware send response, but driver no receive. */ ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); ++ DBGLOG(NIC, WARN, " [1]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", ++ u4RegValue, u4OriRegValue); ++ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); ++ if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); ++ prAdapter->fgIsFwOwn = FALSE; ++ break; ++ } ++ HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); ++ DBGLOG(NIC, WARN, " [2]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", ++ u4RegValue, u4OriRegValue); ++ DBGLOG(NIC, WARN, ++ " Fatal error! Driver own fail!!!!!!!!!!!! %d, fgIsBusAccessFailed: %d\n", ++ u4OwnCnt++, fgIsBusAccessFailed); ++ ++ DBGLOG(NIC, WARN, "CONNSYS FW CPUINFO:\n"); ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(NIC, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ ++ kalSendAeeWarning("[Fatal error! Driver own fail!]", __func__); ++ glDoChipReset(); ++ } ++ break; ++ } ++ if ((i & (LP_OWN_BACK_CLR_OWN_ITERATION - 1)) == 0) { ++ /* Software get LP ownership - per 256 iterations */ ++ HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); ++ } ++ ++ /* Delay for LP engine to complete its operation. */ ++ kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); ++ i++; ++ } ++ ++ STATS_DRIVER_OWN_END_RECORD(); ++ STATS_DRIVER_OWN_STOP(); ++ ++ return fgStatus; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set ACPI power mode to D0. ++* ++* \param[in] pvAdapter Pointer to the Adapter structure. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter) ++{ ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ UINT_32 u4Value = 0, u4WHISR = 0; ++ UINT_8 aucTxCount[8]; ++ UINT_32 i; ++#if CFG_ENABLE_FW_DOWNLOAD ++ UINT_32 u4FwImgLength, u4FwLoadAddr, u4ImgSecSize; ++ PVOID prFwMappingHandle; ++ PVOID pvFwImageMapFile = NULL; ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ UINT_32 j; ++ P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; ++ BOOLEAN fgValidHead; ++ const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); ++#endif ++#endif ++ ++ DEBUGFUNC("nicpmSetAcpiPowerD0"); ++ ASSERT(prAdapter); ++ ++ do { ++ /* 0. Reset variables in ADAPTER_T */ ++ prAdapter->fgIsFwOwn = TRUE; ++ prAdapter->fgWiFiInSleepyState = FALSE; ++ prAdapter->rAcpiState = ACPI_STATE_D0; ++ prAdapter->fgIsEnterD3ReqIssued = FALSE; ++ ++ /* 1. Request Ownership to enter F/W download state */ ++ ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); ++#if !CFG_ENABLE_FULL_PM ++ nicpmSetDriverOwn(prAdapter); ++#endif ++ ++ /* 2. Initialize the Adapter */ ++ u4Status = nicInitializeAdapter(prAdapter); ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "nicInitializeAdapter failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ prFwMappingHandle = kalFirmwareImageMapping(prAdapter->prGlueInfo, &pvFwImageMapFile, &u4FwImgLength); ++ if (!prFwMappingHandle) { ++ DBGLOG(NIC, ERROR, "Fail to load FW image from file!\n"); ++ pvFwImageMapFile = NULL; ++ } ++ ++ if (pvFwImageMapFile == NULL) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ ++ /* 3.1 disable interrupt, download is done by polling mode only */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 3.2 Initialize Tx Resource to fw download state */ ++ nicTxInitResetResource(prAdapter); ++ ++ /* 3.3 FW download here */ ++ u4FwLoadAddr = kalGetFwLoadAddress(prAdapter->prGlueInfo); ++ ++#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD ++ /* 3a. parse file header for decision of divided firmware download or not */ ++ prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; ++ ++ if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && ++ prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, ++ u4FwImgLength - u4CRCOffset)) { ++ fgValidHead = TRUE; ++ } else { ++ fgValidHead = FALSE; ++ } ++ ++ /* 3b. engage divided firmware downloading */ ++ if (fgValidHead == TRUE) { ++ for (i = 0; i < prFwHead->u4NumOfEntries; i++) { ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ prFwHead->arSection[i].u4DestAddr, ++ prFwHead->arSection[i].u4Length, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset) != ++ WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = prFwHead->arSection[i].u4Length - j; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ prFwHead->arSection[i].u4DestAddr + j, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + ++ prFwHead->arSection[i].u4Offset + j) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ /* escape from loop if any pending error occurs */ ++ if (u4Status == WLAN_STATUS_FAILURE) ++ break; ++ } ++ } else ++#endif ++#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION ++ if (wlanImageSectionDownloadAggregated(prAdapter, ++ u4FwLoadAddr, ++ u4FwImgLength, ++ (PUINT_8) pvFwImageMapFile) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ } ++#else ++ for (i = 0; i < u4FwImgLength; i += CMD_PKT_SIZE_FOR_IMAGE) { ++ if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImgLength) ++ u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; ++ else ++ u4ImgSecSize = u4FwImgLength - i; ++ ++ if (wlanImageSectionDownload(prAdapter, ++ u4FwLoadAddr + i, ++ u4ImgSecSize, ++ (PUINT_8) pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(NIC, ERROR, "wlanImageSectionDownload failed!\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ } ++#endif ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) { ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ break; ++ } ++#if !CFG_ENABLE_FW_DOWNLOAD_ACK ++ /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ ++ if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++#endif ++ kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); ++ ++ /* 4. send Wi-Fi Start command */ ++#if CFG_OVERRIDE_FW_START_ADDRESS ++ wlanConfigWifiFunc(prAdapter, TRUE, kalGetFwStartAddress(prAdapter->prGlueInfo)); ++#else ++ wlanConfigWifiFunc(prAdapter, FALSE, 0); ++#endif ++#endif /* if CFG_ENABLE_FW_DOWNLOAD */ ++ ++ /* 5. check Wi-Fi FW asserts ready bit */ ++ DBGLOG(NIC, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); ++ i = 0; ++ while (1) { ++ HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); ++ ++ if (u4Value & WCIR_WLAN_READY) { ++ DBGLOG(NIC, TRACE, "Ready bit asserted\n"); ++ break; ++ } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { ++ DBGLOG(NIC, ERROR, "Waiting for Ready bit: Timeout\n"); ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } ++ i++; ++ kalMsleep(10); ++ } ++ ++ if (u4Status == WLAN_STATUS_SUCCESS) { ++ /* 6.1 reset interrupt status */ ++ HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)(&u4WHISR)); ++ if (HAL_IS_TX_DONE_INTR(u4WHISR)) ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); ++ ++ /* 6.2 reset TX Resource for normal operation */ ++ nicTxResetResource(prAdapter); ++ ++ /* 6.3 Enable interrupt */ ++ nicEnableInterrupt(prAdapter); ++ ++ /* 6.4 Override network address */ ++ wlanUpdateNetworkAddress(prAdapter); ++ ++ /* 6.5 indicate disconnection as default status */ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ } ++ ++ RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); ++ ++ /* MGMT Initialization */ ++ nicInitMGMT(prAdapter, NULL); ++ ++ } while (FALSE); ++ ++ if (u4Status != WLAN_STATUS_SUCCESS) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is used to set ACPI power mode to D3. ++* ++* @param prAdapter pointer to the Adapter handler ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ ++ ASSERT(prAdapter); ++ ++ /* 1. MGMT - unitialization */ ++ nicUninitMGMT(prAdapter); ++ ++ /* 2. Disable Interrupt */ ++ nicDisableInterrupt(prAdapter); ++ ++ /* 3. emit CMD_NIC_POWER_CTRL command packet */ ++ wlanSendNicPowerCtrlCmd(prAdapter, 1); ++ ++ /* 4. Clear Interrupt Status */ ++ i = 0; ++ while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { ++ i++; ++ }; ++ ++ /* 5. Remove pending TX */ ++ nicTxRelease(prAdapter); ++ ++ /* 5.1 clear pending Security / Management Frames */ ++ kalClearSecurityFrames(prAdapter->prGlueInfo); ++ kalClearMgmtFrames(prAdapter->prGlueInfo); ++ ++ /* 5.2 clear pending TX packet queued in glue layer */ ++ kalFlushPendingTxPackets(prAdapter->prGlueInfo); ++ ++ /* 6. Set Onwership to F/W */ ++ nicpmSetFWOwn(prAdapter, FALSE); ++ ++ /* 7. Set variables */ ++ prAdapter->rAcpiState = ACPI_STATE_D3; ++ ++ return TRUE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +new file mode 100644 +index 000000000000..ba4840414da8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +@@ -0,0 +1,3782 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_rx.c#3 ++*/ ++ ++/*! \file nic_rx.c ++ \brief Functions that provide many rx-related functions ++ ++ This file includes the functions used to process RFB and dispatch RFBs to ++ the appropriate related rx functions for protocols. ++*/ ++ ++/* ++** Log: nic_rx.c ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, ++** one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 14 2012 cp.wu ++ * NULL ++ * remove another assertion by error message dump ++ * ++ * 01 05 2012 tsaiyuan.hsu ++ * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v ++ * add timing measurement support for 802.11v. ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Update RSSI for P2P. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 09 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for beacon timeout and sta aging timeout. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 10 21 2011 eddie.chen ++ * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout ++ * Add switch to ignore the STA aging timeout. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 08 26 2011 cp.wu ++ * [WCXRP00000958] [MT6620 Wi-Fi][Driver] Extend polling timeout from 25ms to 1sec due to RF calibration might took ++ * up to 600ms ++ * extend polling RX response timeout period from 25ms to 1000ms. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 27 2011 cp.wu ++ * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count ++ * correct comment. ++ * ++ * 07 27 2011 cp.wu ++ * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count ++ * take use of QUE_MGT exported function to estimate currently RX buffer usage count. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 09 2011 tsaiyuan.hsu ++ * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size ++ * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 05 05 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add delay after whole-chip resetting for MT5931 E1 ASIC. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support for GO. ++ * ++ * 04 01 2011 tsaiyuan.hsu ++ * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues ++ * fix the klocwork issues, 57500, 57501, 57502 and 57503. ++ * ++ * 03 19 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Add beacon timeout support for WiFi Direct Network. ++ * ++ * 03 18 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * enable the Anti_piracy check at driver . ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA ++ * module. ++ * Remove Station Record after Aging timeout. ++ * ++ * 02 10 2011 cp.wu ++ * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers ++ * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add MLME deauthentication support for Hot-Spot mode. ++ * ++ * 02 09 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Adjust variable order. ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * . ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Remove comments. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 24 2011 cm.chang ++ * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec ++ * is freed ++ * Process received 20/40 coexistence action frame for AP mode ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * update beacon for NoA ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 27 2010 george.huang ++ * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB ++ * Support registry option for disable beacon lost detection. ++ * ++ * 10 20 2010 wh.su ++ * NULL ++ * add a cmd to reset the p2p key ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * fixed compilier error. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * release RX packet to packet pool when in RF test mode ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ @ associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 08 2010 cp.wu ++ * NULL ++ * use static memory pool for storing IEs of scanning result. ++ * ++ * 09 07 2010 yuche.tsai ++ * NULL ++ * Add a common buffer, store the IE of a P2P device in this common buffer. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 20 2010 cm.chang ++ * NULL ++ * Migrate RLM code to host from FW ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * When enable WiFi Direct function, check each packet to tell which interface to indicate. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * Add P2P Device Discovery Function. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 george.huang ++ * NULL ++ * handle event for updating NOA parameters indicated from FW ++ * ++ * 08 02 2010 yuche.tsai ++ * NULL ++ * Add support API for RX public action frame. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 30 2010 cp.wu ++ * NULL ++ * 1) BoW wrapper: use definitions instead of hard-coded constant for error code ++ * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead ++ * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames ++ * ++ * 07 26 2010 yuche.tsai ++ * ++ * Update Device Capability Bitmap & Group Capability Bitmap from 16 bits to 8 bits. ++ * ++ * 07 24 2010 wh.su ++ * ++ * .support the Wi-Fi RSN ++ * ++ * 07 23 2010 cp.wu ++ * ++ * add AIS-FSM handling for beacon timeout event. ++ * ++ * 07 21 2010 yuche.tsai ++ * ++ * Add P2P Scan & Scan Result Parsing & Saving. ++ * ++ * 07 19 2010 cm.chang ++ * ++ * Set RLM parameters and enable CNM channel manager ++ * ++ * 07 19 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration. ++ * Add Ad-Hoc support to AIS-FSM ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 15 2010 cp.wu ++ * ++ * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill ucStaRecIdx into SW_RFB_T. ++ * ++ * 07 02 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) for event packet, no need to fill RFB. ++ * 2) when wlanAdapterStart() failed, no need to initialize state machines ++ * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed ++ * ++ * 07 01 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implementation of DRV-SCN and related mailbox message handling. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * refine TX-DONE callback. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * implement TX_DONE callback path. ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add TX Done Event handle entry ++ * ++ * 06 21 2010 wh.su ++ * [WPD00003840][MT6620 5931] Security migration ++ * remove duplicate variable for migration. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * saa_fsm.c is migrated. ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add management dispatching function table. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 ++ * 2) when disconnected, indicate nic directly (no event is needed) ++ * ++ * 06 08 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * cnm_timer has been migrated. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * merge wlan_def.h. ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * sync with MT6620 driver for scan result replacement policy ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS ++ * 2) buffer statistics data for 2 seconds ++ * 3) use default value for adhoc parameters instead of 0 ++ * ++ * 05 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) do not take timeout mechanism for power mode oids ++ * 2) retrieve network type from connection status ++ * 3) after disassciation, set radio state to off ++ * 4) TCP option over IPv6 is supported ++ * ++ * 04 29 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * fixing the PMKID candicate indicate code. ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * basic implementation for EVENT_BT_OVER_WIFI ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 16 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * treat BUS access failure as kind of card removal. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * nicRxProcessEvent packet doesn't access spin-lock directly from now on. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * do not need to release the spin lock due to it is done inside nicGetPendingCmdInfo() ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add channel frequency <-> number conversion ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * 2) add KAPI for handling association info ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve Linux supplicant compliance ++ * ++ * 03 31 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl which may cause cmdinfo memory leak ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * rWlanInfo is modified before data is indicated to OS ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * rWlanInfo is modified before data is indicated to OS ++ * ++ * 03 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a temporary flag for integration with CMD/EVENT v0.9. ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * * the frequency is used for adhoc connection only ++ * * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * . ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * * ++ * ++ * 03 19 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add ACPI D0/D3 state switching support ++ * * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX ++ * response ++ * ++ * 03 15 2010 kevin.huang ++ * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test ++ * Add event for activate STA_RECORD_T ++ * ++ * 03 12 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct fgSetQuery/fgNeedResp check ++ * ++ * 03 11 2010 cp.wu ++ * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 ++ * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING ++ * ++ * 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) the use of prPendingOid revised, all accessing are now protected by spin lock ++ * * * * 2) ensure wlanReleasePendingOid will clear all command queues ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c ++ * * 'cause it involves OS dependent data structure handling ++ * ++ * 02 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Updated API interfaces for qmHandleEventRxAddBa() and qmHandleEventRxDelBa() ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement host-side firmware download logic ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * * 4) nicRxWaitResponse() revised ++ * * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 01 27 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * . ++ * ++ * 01 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * implement following 802.11 OIDs: ++ * * * * * * OID_802_11_RSSI, ++ * * * * * * OID_802_11_RSSI_TRIGGER, ++ * * * * * * OID_802_11_STATISTICS, ++ * * * * * * OID_802_11_DISASSOCIATE, ++ * * * * * * OID_802_11_POWER_MODE ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * * 2) add 4 counter for recording aggregation statistics ++ * ++ * 12 23 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add a precheck: if free sw rfb is not enough, do not invoke read transactionu1rwduu`wvpghlqg|fu+rp ++ * ++ * 12 22 2009 cp.wu ++ * [WPD00003809][Bug] Host driver will crash when processing reordered MSDUs ++ * The root cause is pointer accessing by mistake. After dequeued from reordering-buffer, handling logic should access ++ * returned pointer instead of pointer which has been passed in before. ++** \main\maintrunk.MT6620WiFiDriver_Prj\58 2009-12-17 13:40:33 GMT mtk02752 ++** always update prAdapter->rSDIOCtrl when enhanced response is read by RX ++** \main\maintrunk.MT6620WiFiDriver_Prj\57 2009-12-16 18:01:38 GMT mtk02752 ++** if interrupt enhanced response is fetched by RX enhanced response, RX needs to invoke interrupt handlers too ++** \main\maintrunk.MT6620WiFiDriver_Prj\56 2009-12-16 14:16:52 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\55 2009-12-15 20:03:12 GMT mtk02752 ++** ASSERT when RX FreeSwRfb is not enough ++** \main\maintrunk.MT6620WiFiDriver_Prj\54 2009-12-15 17:01:29 GMT mtk02752 ++** when CFG_SDIO_RX_ENHANCE is enabled, after enhanced response is read, rx procedure should process ++** 1) TX_DONE_INT 2) D2H INT as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\53 2009-12-14 20:45:28 GMT mtk02752 ++** when CFG_SDIO_RX_ENHANCE is set, TC counter must be updated each time RX enhance response is read ++** ++** \main\maintrunk.MT6620WiFiDriver_Prj\52 2009-12-14 11:34:16 GMT mtk02752 ++** correct a trivial logic issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\51 2009-12-14 10:28:25 GMT mtk02752 ++** add a protection to avoid out-of-boundary access ++** \main\maintrunk.MT6620WiFiDriver_Prj\50 2009-12-10 16:55:18 GMT mtk02752 ++** code clean ++** \main\maintrunk.MT6620WiFiDriver_Prj\49 2009-12-09 14:06:47 GMT MTK02468 ++** Added parsing event packets with EVENT_ID_RX_ADDBA or EVENT_ID_RX_DELBA ++** \main\maintrunk.MT6620WiFiDriver_Prj\48 2009-12-08 17:37:51 GMT mtk02752 ++** handle EVENT_ID_TEST_STATUS as well ++** \main\maintrunk.MT6620WiFiDriver_Prj\47 2009-12-04 17:59:11 GMT mtk02752 ++** to pass free-build compilation check ++** \main\maintrunk.MT6620WiFiDriver_Prj\46 2009-12-04 12:09:52 GMT mtk02752 ++** correct trivial mistake ++** \main\maintrunk.MT6620WiFiDriver_Prj\45 2009-12-04 11:53:37 GMT mtk02752 ++** all API should be compilable under SD1_SD3_DATAPATH_INTEGRATION == 0 ++** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-03 16:19:48 GMT mtk01461 ++** Fix the Connected Event ++** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-11-30 10:56:18 GMT mtk02752 ++** 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-11-30 10:11:27 GMT mtk02752 ++** implement replacement for bss scan result ++** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-11-27 11:08:05 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-11-26 09:38:59 GMT mtk02752 ++** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-11-26 09:29:40 GMT mtk02752 ++** enable packet forwarding path (for AP mode) ++** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-11-25 21:37:00 GMT mtk02752 ++** sync. with EVENT_SCAN_RESULT_T change, and add an assert for checking event size ++** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-25 20:17:41 GMT mtk02752 ++** fill HIF_TX_HEADER_T.u2SeqNo ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-25 18:18:57 GMT mtk02752 ++** buffer scan result to prGlueInfo->rWlanInfo.arScanResult directly. ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-24 22:42:45 GMT mtk02752 ++** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event (not implemented yet) ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-24 20:51:41 GMT mtk02752 ++** integrate with SD1's data path API ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-24 19:56:17 GMT mtk02752 ++** adopt P_HIF_RX_HEADER_T in new path ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-23 20:31:21 GMT mtk02752 ++** payload to send into pfCmdDoneHandler() will not include WIFI_EVENT_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-23 17:51:34 GMT mtk02752 ++** when event packet corresponding to some pendingOID is received, pendingOID should be cleared ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 14:46:54 GMT mtk02752 ++** implement nicRxProcessEventPacket() ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-17 22:40:54 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-16 21:48:22 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION data path handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-16 15:41:18 GMT mtk01084 ++** modify the length to be read in emu mode ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-13 17:00:12 GMT mtk02752 ++** add blank function for event packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-13 13:54:24 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 14:41:51 GMT mtk02752 ++** fix typo ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-11 14:33:46 GMT mtk02752 ++** add protection when there is no packet avilable ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 12:33:36 GMT mtk02752 ++** add RX1 read path for aggregated/enhanced/normal packet read procedures ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:18 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-04 14:11:08 GMT mtk01084 ++** modify lines in RX aggregation ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:23 GMT mtk01084 ++** modify RX aggregation handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:56:12 GMT mtk01084 ++** modify HAL part ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:34 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:20 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-02 13:59:08 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-21 23:39:05 GMT mtk01461 ++** Fix the paste error of RX STATUS in OOB of HIF Loopback CTRL ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-20 12:25:32 GMT mtk01461 ++** Fix process of Read Done, and add u4MaxEventBufferLen to nicRxWaitResponse() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 21:13:18 GMT mtk01426 ++** Fixed compiler error ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:05:29 GMT mtk01426 ++** Fixed nicRxSDIOAggReceiveRFBs() ASSERT issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:38:43 GMT mtk01461 ++** Fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode and refine nicRxSDIOAggeceiveRFBs() for RX Aggregation ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-22 09:12:17 GMT mtk01461 ++** Fix nicRxProcessHIFLoopbackPacket(), the size of HIF CTRL LENGTH field is 1 byte ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-14 15:51:26 GMT mtk01426 ++** Update RX OOB Setting ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-03 14:58:58 GMT mtk01426 ++** Fixed logical error ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:58:31 GMT mtk01461 ++** Rename the HIF_PKT_TYPE_DATA ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:51:18 GMT mtk01461 ++** Fix u4HeaderOffset in nicRxProcessHIFLoopbackPacket() ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:02:58 GMT mtk01426 ++** Add CFG_SDIO_RX_ENHANCE and CFG_HIF_LOOPBACK support ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:20:59 GMT mtk01426 ++** Add nicRxWaitResponse function ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:01 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#ifndef LINUX ++#include ++#else ++#include ++#endif ++ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include ++#include ++#include ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define RX_RESPONSE_TIMEOUT (1000) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_MGMT_FRAME_HANDLING ++static PROCESS_RX_MGT_FUNCTION apfnProcessRxMgtFrame[MAX_NUM_OF_FC_SUBTYPES] = { ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAssoc, /* subtype 0000: Association request */ ++#else ++ NULL, /* subtype 0000: Association request */ ++#endif /* CFG_SUPPORT_AAA */ ++ saaFsmRunEventRxAssoc, /* subtype 0001: Association response */ ++#if CFG_SUPPORT_AAA ++ aaaFsmRunEventRxAssoc, /* subtype 0010: Reassociation request */ ++#else ++ NULL, /* subtype 0010: Reassociation request */ ++#endif /* CFG_SUPPORT_AAA */ ++ saaFsmRunEventRxAssoc, /* subtype 0011: Reassociation response */ ++#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) ++ bssProcessProbeRequest, /* subtype 0100: Probe request */ ++#else ++ NULL, /* subtype 0100: Probe request */ ++#endif /* CFG_SUPPORT_ADHOC */ ++ scanProcessBeaconAndProbeResp, /* subtype 0101: Probe response */ ++ NULL, /* subtype 0110: reserved */ ++ NULL, /* subtype 0111: reserved */ ++ scanProcessBeaconAndProbeResp, /* subtype 1000: Beacon */ ++ NULL, /* subtype 1001: ATIM */ ++ saaFsmRunEventRxDisassoc, /* subtype 1010: Disassociation */ ++ authCheckRxAuthFrameTransSeq, /* subtype 1011: Authentication */ ++ saaFsmRunEventRxDeauth, /* subtype 1100: Deauthentication */ ++ nicRxProcessActionFrame, /* subtype 1101: Action */ ++ NULL, /* subtype 1110: reserved */ ++ NULL /* subtype 1111: reserved */ ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Initialize the RFBs ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucMemHandle; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 i; ++ ++ DEBUGFUNC("nicRxInitialize"); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ /* 4 <0> Clear allocated memory. */ ++ kalMemZero((PVOID) prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize); ++ ++ /* 4 <1> Initialize the RFB lists */ ++ QUEUE_INITIALIZE(&prRxCtrl->rFreeSwRfbList); ++ QUEUE_INITIALIZE(&prRxCtrl->rReceivedRfbList); ++ QUEUE_INITIALIZE(&prRxCtrl->rIndicatedRfbList); ++ ++ pucMemHandle = prRxCtrl->pucRxCached; ++ for (i = CFG_RX_MAX_PKT_NUM; i != 0; i--) { ++ prSwRfb = (P_SW_RFB_T) pucMemHandle; ++ ++ nicRxSetupRFB(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ pucMemHandle += ALIGN_4(sizeof(SW_RFB_T)); ++ } ++ ++ ASSERT(prRxCtrl->rFreeSwRfbList.u4NumElem == CFG_RX_MAX_PKT_NUM); ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT((ULONG) (pucMemHandle - prRxCtrl->pucRxCached) == prRxCtrl->u4RxCachedSize); ++ ++ /* 4 <2> Clear all RX counters */ ++ RX_RESET_ALL_CNTS(prRxCtrl); ++ ++#if CFG_SDIO_RX_AGG ++ prRxCtrl->pucRxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; ++ HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, CFG_SDIO_MAX_RX_AGG_NUM); ++#else ++ HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, 1); ++#endif ++ ++#if CFG_HIF_STATISTICS ++ prRxCtrl->u4TotalRxAccessNum = 0; ++ prRxCtrl->u4TotalRxPacketNum = 0; ++#endif ++ ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4QueuedCnt = 0; ++ prRxCtrl->u4DequeuedCnt = 0; ++#endif ++ ++} /* end of nicRxInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Uninitialize the RFBs ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ nicRxFlush(prAdapter); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (prSwRfb) { ++ if (prSwRfb->pvPacket) ++ kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); ++ prSwRfb->pvPacket = NULL; ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ if (prSwRfb) { ++ if (prSwRfb->pvPacket) ++ kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); ++ prSwRfb->pvPacket = NULL; ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++} /* end of nicRxUninitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Fill RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb specify the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ UINT_32 u4PktLen = 0; ++ UINT_32 u4MacHeaderLen; ++ UINT_32 u4HeaderOffset; ++ ++ DEBUGFUNC("nicRxFillRFB"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ u4PktLen = prHifRxHdr->u2PacketLen; ++ ++ u4HeaderOffset = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ u4MacHeaderLen = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_LEN) ++ >> HIF_RX_HDR_HEADER_LEN_OFFSET; ++ ++ /* DBGLOG(RX, TRACE, ("u4HeaderOffset = %d, u4MacHeaderLen = %d\n", */ ++ /* u4HeaderOffset, u4MacHeaderLen)); */ ++ ++ prSwRfb->u2HeaderLen = (UINT_16) u4MacHeaderLen; ++ prSwRfb->pvHeader = (PUINT_8) prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ prSwRfb->u2PacketLen = (UINT_16) (u4PktLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); ++ ++ /* DBGLOG(RX, TRACE, ("Dump Rx packet, u2PacketLen = %d\n", prSwRfb->u2PacketLen)); */ ++ /* DBGLOG_MEM8(RX, TRACE, prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ ++#if 0 ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_80211_HEADER_FORMAT) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_802_11_FORMAT; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_802_11_FORMAT\n"); ++ } ++ ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_DO_REORDER) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_DO_REORDERING; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_DO_REORDERING\n"); ++ ++ /* Get Seq. No and TID, Wlan Index info */ ++ if (prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_BAR_FRAME) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_BAR_FRAME; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_BAR_FRAME\n"); ++ } ++ ++ prSwRfb->u2SSN = prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_SEQ_NO_MASK; ++ prSwRfb->ucTid = (UINT_8) ((prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_TID_MASK) ++ >> HIF_RX_HDR_TID_OFFSET); ++ DBGLOG(RX, TRACE, "u2SSN = %d, ucTid = %d\n", prSwRfb->u2SSN, prSwRfb->ucTid); ++ } ++ ++ if (prHifRxHdr->ucReorder & HIF_RX_HDR_WDS) { ++ prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_AMP_WDS; ++ DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_AMP_WDS\n"); ++ } ++#endif ++} ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Fill checksum status in RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* @param u4TcpUdpIpCksStatus specify the Checksum status ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus) ++{ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (prAdapter->u4CSUMFlags != CSUM_NOT_SUPPORTED) { ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv4) { /* IPv4 packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_IP) { /* IP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_SUCCESS; ++ } ++ ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv6) { /* IPv6 packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_SUCCESS; ++ ++ if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; ++ } ++ } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; ++ } ++ } else { ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; ++ prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; ++ } ++ } ++ ++} ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process packet doesn't need to do buffer reordering ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_TX_CTRL_T prTxCtrl; ++ BOOLEAN fgIsRetained = FALSE; ++ UINT_32 u4CurrentRxBufferCount; ++ P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; ++ ++ DEBUGFUNC("nicRxProcessPktWithoutReorder"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ u4CurrentRxBufferCount = prRxCtrl->rFreeSwRfbList.u4NumElem; ++ /* QM USED = $A, AVAILABLE COUNT = $B, INDICATED TO OS = $C ++ * TOTAL = $A + $B + $C ++ * ++ * Case #1 (Retain) ++ * ------------------------------------------------------- ++ * $A + $B < THRESHOLD := $A + $B + $C < THRESHOLD + $C := $TOTAL - THRESHOLD < $C ++ * => $C used too much, retain ++ * ++ * Case #2 (Non-Retain) ++ * ------------------------------------------------------- ++ * $A + $B > THRESHOLD := $A + $B + $C > THRESHOLD + $C := $TOTAL - THRESHOLD > $C ++ * => still available for $C to use ++ * ++ */ ++ fgIsRetained = (((u4CurrentRxBufferCount + ++ qmGetRxReorderQueuedBufferCount(prAdapter) + ++ prTxCtrl->i4PendingFwdFrameCount) < CFG_RX_RETAINED_PKT_THRESHOLD) ? TRUE : FALSE); ++ ++ /* DBGLOG(RX, INFO, ("fgIsRetained = %d\n", fgIsRetained)); */ ++ ++ if (kalProcessRxPacket(prAdapter->prGlueInfo, ++ prSwRfb->pvPacket, ++ prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, fgIsRetained, prSwRfb->aeCSUM) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(RX, ERROR, "kalProcessRxPacket return value != WLAN_STATUS_SUCCESS\n"); ++ ASSERT(0); ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ return; ++ } ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ++ if (prStaRec) { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX && prAdapter->fgIsP2PRegistered == TRUE) ++ GLUE_SET_PKT_FLAG_P2P(prSwRfb->pvPacket); ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) ++ GLUE_SET_PKT_FLAG_PAL(prSwRfb->pvPacket); ++#endif ++ ++ /* record the count to pass to os */ ++ STATS_RX_PASS2OS_INC(prStaRec, prSwRfb); ++ } ++ prRxCtrl->apvIndPacket[prRxCtrl->ucNumIndPacket] = prSwRfb->pvPacket; ++ prRxCtrl->ucNumIndPacket++; ++ ++ if (fgIsRetained) { ++ prRxCtrl->apvRetainedPacket[prRxCtrl->ucNumRetainedPacket] = prSwRfb->pvPacket; ++ prRxCtrl->ucNumRetainedPacket++; ++ /* TODO : error handling of nicRxSetupRFB */ ++ nicRxSetupRFB(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } else { ++ prSwRfb->pvPacket = NULL; ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process forwarding data packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_MSDU_INFO_T prMsduInfo, prRetMsduInfoList; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessForwardPkt"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ if (prMsduInfo && kalProcessRxPacket(prAdapter->prGlueInfo, ++ prSwRfb->pvPacket, ++ prSwRfb->pvHeader, ++ (UINT_32) prSwRfb->u2PacketLen, ++ prRxCtrl->rFreeSwRfbList.u4NumElem < ++ CFG_RX_RETAINED_PKT_THRESHOLD ? TRUE : FALSE, ++ prSwRfb->aeCSUM) == WLAN_STATUS_SUCCESS) { ++ ++ prMsduInfo->eSrc = TX_PACKET_FORWARDING; ++ /* pack into MSDU_INFO_T */ ++ nicTxFillMsduInfo(prAdapter, prMsduInfo, (P_NATIVE_PACKET) (prSwRfb->pvPacket)); ++ /* Overwrite the ucNetworkType */ ++ prMsduInfo->ucNetworkType = HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr); ++ ++ /* release RX buffer (to rIndicatedRfbList) */ ++ prSwRfb->pvPacket = NULL; ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ /* increase forward frame counter */ ++ GLUE_INC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ ++ /* send into TX queue */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prRetMsduInfoList = qmEnqueueTxPackets(prAdapter, prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prRetMsduInfoList != NULL) { /* TX queue refuses queuing the packet */ ++ nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfoList); ++ nicTxReturnMsduInfo(prAdapter, prRetMsduInfoList); ++ } ++ /* indicate service thread for sending */ ++ if (prTxCtrl->i4PendingFwdFrameCount > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } else /* no TX resource */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process broadcast data packet for both host and forwarding ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_SW_RFB_T prSwRfbDuplicated; ++ P_TX_CTRL_T prTxCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessGOBroadcastPkt"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ ASSERT(CFG_NUM_OF_QM_RX_PKT_NUM >= 16); ++ ++ if (prRxCtrl->rFreeSwRfbList.u4NumElem ++ >= (CFG_RX_MAX_PKT_NUM - (CFG_NUM_OF_QM_RX_PKT_NUM - 16 /* Reserved for others */))) { ++ ++ /* 1. Duplicate SW_RFB_T */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfbDuplicated, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfbDuplicated) { ++ kalMemCopy(prSwRfbDuplicated->pucRecvBuff, ++ prSwRfb->pucRecvBuff, ALIGN_4(prHifRxHdr->u2PacketLen + HIF_RX_HW_APPENDED_LEN)); ++ ++ prSwRfbDuplicated->ucPacketType = HIF_RX_PKT_TYPE_DATA; ++ prSwRfbDuplicated->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ nicRxFillRFB(prAdapter, prSwRfbDuplicated); ++ ++ /* 2. Modify eDst */ ++ prSwRfbDuplicated->eDst = RX_PKT_DESTINATION_FORWARD; ++ ++ /* 4. Forward */ ++ nicRxProcessForwardPkt(prAdapter, prSwRfbDuplicated); ++ } ++ } else { ++ DBGLOG(RX, WARN, "Stop to forward BMC packet due to less free Sw Rfb %u\n", ++ prRxCtrl->rFreeSwRfbList.u4NumElem); ++ } ++ ++ /* 3. Indicate to host */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_HOST; ++ nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF data packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prRetSwRfb, prNextSwRfb; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fIsDummy = FALSE; ++ ++ DEBUGFUNC("nicRxProcessDataPacket"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ++ fIsDummy = (prHifRxHdr->u2PacketLen >= 12) ? FALSE : TRUE; ++ ++ nicRxFillRFB(prAdapter, prSwRfb); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ { ++ UINT_32 u4TcpUdpIpCksStatus; ++ ++ u4TcpUdpIpCksStatus = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); ++ nicRxFillChksumStatus(prAdapter, prSwRfb, u4TcpUdpIpCksStatus); ++ ++ } ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prHifRxHdr->ucStaRecIdx); ++ if (secCheckClassError(prAdapter, prSwRfb, prStaRec) == TRUE && prAdapter->fgTestMode == FALSE) { ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4QueuedCnt++; ++#endif ++ prRetSwRfb = qmHandleRxPackets(prAdapter, prSwRfb); ++ if (prRetSwRfb != NULL) { ++ do { ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prRetSwRfb); ++ if (fIsDummy == TRUE) { ++ nicRxReturnRFB(prAdapter, prRetSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ DBGLOG(RX, WARN, "Drop Dummy Packets"); ++ ++ } else { ++ switch (prRetSwRfb->eDst) { ++ case RX_PKT_DESTINATION_HOST: ++#if ARP_MONITER_ENABLE ++ if (IS_STA_IN_AIS(prStaRec)) ++ qmHandleRxArpPackets(prAdapter, prRetSwRfb); ++#endif ++ nicRxProcessPktWithoutReorder(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_FORWARD: ++ nicRxProcessForwardPkt(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_HOST_WITH_FORWARD: ++ nicRxProcessGOBroadcastPkt(prAdapter, prRetSwRfb); ++ break; ++ ++ case RX_PKT_DESTINATION_NULL: ++ nicRxReturnRFB(prAdapter, prRetSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ break; ++ ++ default: ++ break; ++ } ++ } ++#if CFG_HIF_RX_STARVATION_WARNING ++ prRxCtrl->u4DequeuedCnt++; ++#endif ++ prRetSwRfb = prNextSwRfb; ++ } while (prRetSwRfb); ++ } ++ } else { ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF event packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_8 nicRxProcessGSCNEvent(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_WIFI_EVENT_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ struct sk_buff *skb; ++ struct wiphy *wiphy; ++ ++ UINT_32 real_num = 0; ++ ++ P_EVENT_GSCAN_SCAN_AVAILABLE_T prEventGscnAvailable; ++ P_EVENT_GSCAN_RESULT_T prEventBuffer; ++ P_WIFI_GSCAN_RESULT_T prEventGscnResult; ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_32 scan_id; ++ UINT_8 scan_flag; ++ P_EVENT_GSCAN_CAPABILITY_T prEventGscnCapbiblity; ++ P_EVENT_GSCAN_SCAN_COMPLETE_T prEventGscnScnDone; ++ P_WIFI_GSCAN_RESULT_T prEventGscnFullResult; ++ P_PARAM_WIFI_GSCAN_RESULT prParamGscnFullResult; ++ P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnSignificantChange; ++ P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnGeofenceFound; ++ ++ P_PARAM_WIFI_GSCAN_RESULT prResults; ++ ++ DEBUGFUNC("nicRxProcessGSCNEvent"); ++ /* DBGLOG(RX, TRACE, ("\n")); */ ++ ++ DBGLOG(SCN, INFO, "nicRxProcessGSCNEvent\n"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* Push the data to the skb */ ++ wiphy = priv_to_wiphy(prGlueInfo); ++ ++ /* prGlueInfo-> */ ++ ++ /* Event Handling */ ++ switch (prEvent->ucEID) { ++ case EVENT_ID_GSCAN_SCAN_AVAILABLE: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_AVAILABLE\n"); ++ ++ prEventGscnAvailable = (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnAvailable, (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SCAN_AVAILABLE_T)); ++ ++ mtk_cfg80211_vendor_event_scan_results_available(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnAvailable->u2Num); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_RESULT: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_RESULT 2\n"); ++ ++ prEventBuffer = (P_EVENT_GSCAN_RESULT_T) (prEvent->aucBuffer); ++ prEventGscnResult = prEventBuffer->rResult; ++/* ++ the following event struct should moved to kal and use the kal api to avoid future porting effort ++ ++*/ ++ scan_id = prEventBuffer->u2ScanId; ++ scan_flag = prEventBuffer->u2ScanFlags; ++ real_num = prEventBuffer->u2NumOfResults; ++ ++ DBGLOG(SCN, INFO, "scan_id=%d, scan_flag =%d, real_num=%d\r\n", scan_id, scan_flag, real_num); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num); ++ if (!skb) { ++ DBGLOG(RX, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ attr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); ++ /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_SCAN_ID, scan_id);*/ ++ { ++ unsigned int __tmp = scan_id; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_ID, sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, 1);*/ ++ { ++ unsigned char __tmp = 1; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, sizeof(u8), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, real_num);*/ ++ { ++ unsigned int __tmp = real_num; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ prResults = (P_PARAM_WIFI_GSCAN_RESULT) prEventGscnResult; ++ if (prResults) ++ DBGLOG(SCN, INFO, "ssid=%s, rssi=%d, channel=%d \r\n", ++ prResults->ssid, prResults->rssi, prResults->channel); ++ /*NLA_PUT(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num, ++ prResults);*/ ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, ++ sizeof(PARAM_WIFI_GSCAN_RESULT)*real_num, prResults) < 0)) ++ goto nla_put_failure; ++ ++ DBGLOG(SCN, INFO, "NLA_PUT scan results over\t"); ++ ++ if (attr) ++ nla_nest_end(skb, attr); ++ /* report_events=1 */ ++ /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, 1);*/ ++ { ++ unsigned char __tmp = 1; ++ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ skb = NULL; ++ DBGLOG(SCN, INFO, " i4Status %d\n", i4Status); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_CAPABILITY: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_CAPABILITY\n"); ++ ++ prEventGscnCapbiblity = (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnCapbiblity, (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_CAPABILITY_T)); ++ ++ mtk_cfg80211_vendor_get_gscan_capabilities(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnCapbiblity, sizeof(EVENT_GSCAN_CAPABILITY_T)); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_SCAN_COMPLETE: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_COMPLETE\n"); ++ prEventGscnScnDone = (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnScnDone, (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SCAN_COMPLETE_T)); ++ ++ mtk_cfg80211_vendor_event_complete_scan(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, ++ prEventGscnScnDone->ucScanState); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_FULL_RESULT: ++ { ++ DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_FULL_RESULT\n"); ++ ++ prEventGscnFullResult = kalMemAlloc(sizeof(WIFI_GSCAN_RESULT_T), VIR_MEM_TYPE); ++ if (prEventGscnFullResult) ++ memcpy(prEventGscnFullResult, (P_WIFI_GSCAN_RESULT_T) (prEvent->aucBuffer), ++ sizeof(WIFI_GSCAN_RESULT_T)); ++ ++ prParamGscnFullResult = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_RESULT), VIR_MEM_TYPE); ++ if (prEventGscnFullResult && prParamGscnFullResult) { ++ kalMemZero(prParamGscnFullResult, sizeof(PARAM_WIFI_GSCAN_RESULT)); ++ memcpy(prParamGscnFullResult, prEventGscnFullResult, sizeof(WIFI_GSCAN_RESULT_T)); ++ ++ mtk_cfg80211_vendor_event_full_scan_results(wiphy, ++ prGlueInfo->prDevHandler->ieee80211_ptr, ++ prParamGscnFullResult, ++ sizeof(PARAM_WIFI_GSCAN_RESULT)); ++ } ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: ++ { ++ prEventGscnSignificantChange = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnSignificantChange, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); ++ } ++ break; ++ ++ case EVENT_ID_GSCAN_GEOFENCE_FOUND: ++ { ++ prEventGscnGeofenceFound = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); ++ memcpy(prEventGscnGeofenceFound, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), ++ sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); ++ } ++ break; ++ ++ default: ++ DBGLOG(SCN, INFO, "not GSCN event ????\n"); ++ break; ++ } ++ ++ DBGLOG(SCN, INFO, "Done with GSCN event handling\n"); ++ return real_num; /* cfg80211_vendor_cmd_reply(skb); */ ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ DBGLOG(SCN, INFO, "nla_put_failure\n"); ++ return 0; /* cfg80211_vendor_cmd_reply(skb); */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process HIF event packet ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ P_WIFI_EVENT_T prEvent; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DEBUGFUNC("nicRxProcessEventPacket"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ prGlueInfo = prAdapter->prGlueInfo; ++ ++ DBGLOG(RX, EVENT, "prEvent->ucEID = 0x%02x\n", prEvent->ucEID); ++ /* Event Handling */ ++ switch (prEvent->ucEID) { ++ case EVENT_ID_CMD_RESULT: ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ P_EVENT_CMD_RESULT prCmdResult; ++ ++ prCmdResult = (P_EVENT_CMD_RESULT) ((PUINT_8) prEvent + EVENT_HDR_SIZE); ++ ++ /* CMD_RESULT should be only in response to Set commands */ ++ ASSERT(prCmdInfo->fgSetQuery == FALSE || prCmdInfo->fgNeedResp == TRUE); ++ ++ if (prCmdResult->ucStatus == 0) { /* success */ ++ if (prCmdInfo->pfCmdDoneHandler) { ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ } else if (prCmdInfo->fgIsOid == TRUE) { ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_SUCCESS); ++ } ++ } else if (prCmdResult->ucStatus == 1) { /* reject */ ++ if (prCmdInfo->fgIsOid == TRUE) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_FAILURE); ++ } else if (prCmdResult->ucStatus == 2) { /* unknown CMD */ ++ if (prCmdInfo->fgIsOid == TRUE) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, ++ WLAN_STATUS_NOT_SUPPORTED); ++ } ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++#if 0 ++ case EVENT_ID_CONNECTION_STATUS: ++ /* OBSELETE */ ++ { ++ P_EVENT_CONNECTION_STATUS prConnectionStatus; ++ ++ prConnectionStatus = (P_EVENT_CONNECTION_STATUS) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_CONNECTION_STATUS = %d\n", prConnectionStatus->ucMediaStatus); ++ if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /* disconnected */ ++ if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { ++ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); ++ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ } ++ } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { ++ /* connected */ ++ prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); ++ ++ /* fill information for association result */ ++ prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, ++ prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); ++ ++ kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ prConnectionStatus->aucBssid, MAC_ADDR_LEN); ++ ++ /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.u4Privacy = prConnectionStatus->ucEncryptStatus; ++ prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ ++ /* @FIXME */ ++ prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse = PARAM_NETWORK_TYPE_AUTOMODE; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod ++ = prConnectionStatus->u2BeaconPeriod; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow ++ = prConnectionStatus->u2ATIMWindow; ++ prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig ++ = prConnectionStatus->u4FreqInKHz; ++ prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; ++ ++ switch (prConnectionStatus->ucInfraMode) { ++ case 0: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_IBSS; ++ break; ++ case 1: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_INFRA; ++ break; ++ case 2: ++ default: ++ prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_AUTO_SWITCH; ++ break; ++ } ++ /* always indicate to OS according to MSDN (re-association/roaming) */ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); ++ } ++ } ++ break; ++ ++ case EVENT_ID_SCAN_RESULT: ++ /* OBSELETE */ ++ break; ++#endif ++ ++ case EVENT_ID_RX_ADDBA: ++ /* The FW indicates that an RX BA agreement will be established */ ++ qmHandleEventRxAddBa(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_RX_DELBA: ++ /* The FW indicates that an RX BA agreement has been deleted */ ++ qmHandleEventRxDelBa(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_LINK_QUALITY: ++#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY ++ if (prEvent->u2PacketLen == EVENT_HDR_SIZE + sizeof(EVENT_LINK_QUALITY_EX)) { ++ P_EVENT_LINK_QUALITY_EX prLqEx = (P_EVENT_LINK_QUALITY_EX) (prEvent->aucBuffer); ++ ++ if (prLqEx->ucIsLQ0Rdy) ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); ++ if (prLqEx->ucIsLQ1Rdy) ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_P2P_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); ++ } else { ++ /* For old FW, P2P may invoke link quality query, and make driver flag becone TRUE. */ ++ DBGLOG(P2P, WARN, "Old FW version, not support P2P RSSI query.\n"); ++ ++ /* Must not use NETWORK_TYPE_P2P_INDEX, cause the structure is mismatch. */ ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, ++ (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); ++ } ++#else ++ nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); ++#endif ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++#ifndef LINUX ++ if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_GREATER && ++ prAdapter->rWlanInfo.rRssiTriggerValue >= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), ++ sizeof(PARAM_RSSI)); ++ } else if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_LESS ++ && prAdapter->rWlanInfo.rRssiTriggerValue <= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { ++ prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; ++ ++ kalIndicateStatusAndComplete(prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), ++ sizeof(PARAM_RSSI)); ++ } ++#endif ++ ++ break; ++ ++ case EVENT_ID_MIC_ERR_INFO: ++ { ++ P_EVENT_MIC_ERR_INFO prMicError; ++ /* P_PARAM_AUTH_EVENT_T prAuthEvent; */ ++ P_STA_RECORD_T prStaRec; ++ ++ DBGLOG(RSN, EVENT, "EVENT_ID_MIC_ERR_INFO\n"); ++ ++ prMicError = (P_EVENT_MIC_ERR_INFO) (prEvent->aucBuffer); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ (UINT_8) NETWORK_TYPE_AIS_INDEX, ++ prAdapter->rWlanInfo.rCurrBssId.arMacAddress); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) ++ rsnTkipHandleMICFailure(prAdapter, prStaRec, (BOOLEAN) prMicError->u4Flags); ++ else ++ DBGLOG(RSN, WARN, "No STA rec!!\n"); ++#if 0 ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ /* Status type: Authentication Event */ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; ++ ++ /* Authentication request */ ++ prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); ++ kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, ++ (PVOID) prAdapter->rWlanInfo.rCurrBssId.arMacAddress, ++ /* whsu:Todo? */PARAM_MAC_ADDR_LEN); ++ ++ if (prMicError->u4Flags != 0) ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; ++ else ++ prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); ++#endif ++ } ++ break; ++ ++ case EVENT_ID_ASSOC_INFO: ++ { ++ P_EVENT_ASSOC_INFO prAssocInfo; ++ ++ prAssocInfo = (P_EVENT_ASSOC_INFO) (prEvent->aucBuffer); ++ ++ kalHandleAssocInfo(prAdapter->prGlueInfo, prAssocInfo); ++ } ++ break; ++ ++ case EVENT_ID_802_11_PMKID: ++ { ++ P_PARAM_AUTH_EVENT_T prAuthEvent; ++ PUINT_8 cp; ++ UINT_32 u4LenOfUsedBuffer; ++ ++ prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; ++ ++ prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; ++ ++ u4LenOfUsedBuffer = (UINT_32) (prEvent->u2PacketLen - 8); ++ ++ prAuthEvent->arRequest[0].u4Length = u4LenOfUsedBuffer; ++ ++ cp = (PUINT_8) &prAuthEvent->arRequest[0]; ++ ++ /* Status type: PMKID Candidatelist Event */ ++ kalMemCopy(cp, (P_EVENT_PMKID_CANDIDATE_LIST_T) (prEvent->aucBuffer), prEvent->u2PacketLen - 8); ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, ++ (PVOID) prAuthEvent, ++ sizeof(PARAM_STATUS_INDICATION_T) + u4LenOfUsedBuffer); ++ } ++ break; ++ ++#if 0 ++ case EVENT_ID_ACTIVATE_STA_REC_T: ++ { ++ P_EVENT_ACTIVATE_STA_REC_T prActivateStaRec; ++ ++ prActivateStaRec = (P_EVENT_ACTIVATE_STA_REC_T) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_ACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", ++ prActivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); ++ ++ qmActivateStaRec(prAdapter, ++ (UINT_32) prActivateStaRec->ucStaRecIdx, ++ ((prActivateStaRec->fgIsQoS) ? TRUE : FALSE), ++ prActivateStaRec->ucNetworkTypeIndex, ++ ((prActivateStaRec->fgIsAP) ? TRUE : FALSE), prActivateStaRec->aucMacAddr); ++ ++ } ++ break; ++ ++ case EVENT_ID_DEACTIVATE_STA_REC_T: ++ { ++ P_EVENT_DEACTIVATE_STA_REC_T prDeactivateStaRec; ++ ++ prDeactivateStaRec = (P_EVENT_DEACTIVATE_STA_REC_T) (prEvent->aucBuffer); ++ ++ DbgPrint("RX EVENT: EVENT_ID_DEACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", ++ prDeactivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); ++ ++ qmDeactivateStaRec(prAdapter, prDeactivateStaRec->ucStaRecIdx); ++ } ++ break; ++#endif ++ ++ case EVENT_ID_SCAN_DONE: ++ scnEventScanDone(prAdapter, (P_EVENT_SCAN_DONE) (prEvent->aucBuffer)); ++ break; ++ ++ case EVENT_ID_TX_DONE_STATUS: ++ STATS_TX_PKT_DONE_INFO_DISPLAY(prAdapter, prEvent->aucBuffer); ++ break; ++ ++ case EVENT_ID_TX_DONE: ++ { ++ P_EVENT_TX_DONE_T prTxDone; ++ ++ prTxDone = (P_EVENT_TX_DONE_T) (prEvent->aucBuffer); ++ if (prTxDone->ucStatus) ++ DBGLOG(RX, INFO, "EVENT_ID_TX_DONE PacketSeq:%u ucStatus: %u SN: %u\n", ++ prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->u2SequenceNumber); ++ ++ /* call related TX Done Handler */ ++ prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucPacketSeq); ++ ++#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT ++ DBGLOG(RX, TRACE, "EVENT_ID_TX_DONE u4TimeStamp = %x u2AirDelay = %x\n", ++ prTxDone->au4Reserved1, prTxDone->au4Reserved2); ++ ++ wnmReportTimingMeas(prAdapter, prMsduInfo->ucStaRecIndex, ++ prTxDone->au4Reserved1, prTxDone->au4Reserved1 + prTxDone->au4Reserved2); ++#endif ++ ++ if (prMsduInfo) { ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, ++ (ENUM_TX_RESULT_CODE_T) (prTxDone->ucStatus)); ++ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } ++ } ++ break; ++ case EVENT_ID_SLEEPY_NOTIFY: ++ { ++ P_EVENT_SLEEPY_NOTIFY prEventSleepyNotify; ++ ++ prEventSleepyNotify = (P_EVENT_SLEEPY_NOTIFY) (prEvent->aucBuffer); ++ ++ /* DBGLOG(RX, INFO, ("ucSleepyState = %d\n", prEventSleepyNotify->ucSleepyState)); */ ++ ++ prAdapter->fgWiFiInSleepyState = (BOOLEAN) (prEventSleepyNotify->ucSleepyState); ++ } ++ break; ++ case EVENT_ID_BT_OVER_WIFI: ++#if CFG_ENABLE_BT_OVER_WIFI ++ { ++ UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; ++ P_EVENT_BT_OVER_WIFI prEventBtOverWifi; ++ P_AMPC_EVENT prBowEvent; ++ P_BOW_LINK_CONNECTED prBowLinkConnected; ++ P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; ++ ++ prEventBtOverWifi = (P_EVENT_BT_OVER_WIFI) (prEvent->aucBuffer); ++ ++ /* construct event header */ ++ prBowEvent = (P_AMPC_EVENT) aucTmp; ++ ++ if (prEventBtOverWifi->ucLinkStatus == 0) { ++ /* Connection */ ++ prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; ++ prBowEvent->rHeader.ucSeqNumber = 0; ++ prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); ++ ++ /* fill event body */ ++ prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prBowEvent->aucPayload); ++ prBowLinkConnected->rChannel.ucChannelNum = prEventBtOverWifi->ucSelectedChannel; ++ kalMemZero(prBowLinkConnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); ++ } else { ++ /* Disconnection */ ++ prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; ++ prBowEvent->rHeader.ucSeqNumber = 0; ++ prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); ++ ++ /* fill event body */ ++ prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prBowEvent->aucPayload); ++ prBowLinkDisconnected->ucReason = 0; /* @FIXME */ ++ kalMemZero(prBowLinkDisconnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ ++ ++ kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); ++ } ++ } ++ break; ++#endif ++ case EVENT_ID_STATISTICS: ++ /* buffer statistics for further query */ ++ prAdapter->fgIsStatValid = TRUE; ++ prAdapter->rStatUpdateTime = kalGetTimeTick(); ++ kalMemCopy(&prAdapter->rStatStruct, prEvent->aucBuffer, sizeof(EVENT_STATISTICS)); ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++ case EVENT_ID_CH_PRIVILEGE: ++ cnmChMngrHandleChEvent(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_BSS_ABSENCE_PRESENCE: ++ qmHandleEventBssAbsencePresence(prAdapter, prEvent); ++ break; ++ ++ case EVENT_ID_STA_CHANGE_PS_MODE: ++ qmHandleEventStaChangePsMode(prAdapter, prEvent); ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++ case EVENT_ID_STA_UPDATE_FREE_QUOTA: ++ qmHandleEventStaUpdateFreeQuota(prAdapter, prEvent); ++ break; ++#endif ++ case EVENT_ID_BSS_BEACON_TIMEOUT: ++ if (prAdapter->fgDisBcnLostDetection == FALSE) { ++ P_EVENT_BSS_BEACON_TIMEOUT_T prEventBssBeaconTimeout; ++ ++ prEventBssBeaconTimeout = (P_EVENT_BSS_BEACON_TIMEOUT_T) (prEvent->aucBuffer); ++ ++ DBGLOG(RX, INFO, "Beacon Timeout Reason = %u\n", prEventBssBeaconTimeout->ucReason); ++ ++ if (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { ++ /* Request stats report before beacon timeout */ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (prBssInfo) { ++ prStaRec = cnmGetStaRecByAddress(prAdapter, ++ NETWORK_TYPE_AIS_INDEX, ++ prBssInfo->aucBSSID); ++ if (prStaRec) ++ STATS_ENV_REPORT_DETECT(prAdapter, prStaRec->ucIndex); ++ } ++ aisBssBeaconTimeout(prAdapter); ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ else if ((prAdapter->fgIsP2PRegistered) && ++ (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) ++ ++ p2pFsmRunEventBeaconTimeout(prAdapter); ++#endif ++ else { ++ DBGLOG(RX, ERROR, "EVENT_ID_BSS_BEACON_TIMEOUT: (ucNetTypeIdx = %d)\n", ++ prEventBssBeaconTimeout->ucNetTypeIndex); ++ } ++ } ++ ++ break; ++ case EVENT_ID_UPDATE_NOA_PARAMS: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) { ++ P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam; ++ ++ prEventUpdateNoaParam = (P_EVENT_UPDATE_NOA_PARAMS_T) (prEvent->aucBuffer); ++ ++ if (prEventUpdateNoaParam->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { ++ p2pProcessEvent_UpdateNOAParam(prAdapter, ++ prEventUpdateNoaParam->ucNetTypeIndex, ++ prEventUpdateNoaParam); ++ } else { ++ ASSERT(0); ++ } ++ } ++#else ++ ASSERT(0); ++#endif ++ break; ++ ++ case EVENT_ID_STA_AGING_TIMEOUT: ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ if (prAdapter->fgDisStaAgingTimeoutDetection == FALSE) { ++ P_EVENT_STA_AGING_TIMEOUT_T prEventStaAgingTimeout; ++ P_STA_RECORD_T prStaRec; ++ P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; ++ ++ prEventStaAgingTimeout = (P_EVENT_STA_AGING_TIMEOUT_T) (prEvent->aucBuffer); ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prEventStaAgingTimeout->ucStaRecIdx); ++ if (prStaRec == NULL) ++ break; ++ ++ DBGLOG(RX, INFO, "EVENT_ID_STA_AGING_TIMEOUT %u %pM\n", ++ prEventStaAgingTimeout->ucStaRecIdx, ++ prStaRec->aucMacAddr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); ++ ++ /* Call False Auth */ ++ if (prAdapter->fgIsP2PRegistered) ++ p2pFuncDisconnect(prAdapter, prStaRec, TRUE, REASON_CODE_DISASSOC_INACTIVITY); ++ ++ } ++ /* gDisStaAgingTimeoutDetection */ ++ } ++#endif ++ break; ++ ++ case EVENT_ID_AP_OBSS_STATUS: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ rlmHandleObssStatusEventPkt(prAdapter, (P_EVENT_AP_OBSS_STATUS_T) prEvent->aucBuffer); ++#endif ++ break; ++ ++ case EVENT_ID_ROAMING_STATUS: ++#if CFG_SUPPORT_ROAMING ++ { ++ P_ROAMING_PARAM_T prParam; ++ ++ prParam = (P_ROAMING_PARAM_T) (prEvent->aucBuffer); ++ roamingFsmProcessEvent(prAdapter, prParam); ++ } ++#endif /* CFG_SUPPORT_ROAMING */ ++ break; ++ case EVENT_ID_SEND_DEAUTH: ++ { ++ P_WLAN_MAC_HEADER_T prWlanMacHeader; ++ P_STA_RECORD_T prStaRec; ++ ++ prWlanMacHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; ++ DBGLOG(RSN, INFO, "nicRx: aucAddr1: %pM, nicRx: aucAddr2: %pM\n", ++ prWlanMacHeader->aucAddr1, prWlanMacHeader->aucAddr2); ++ prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanMacHeader->aucAddr2); ++ if (prStaRec != NULL && prStaRec->ucStaState == STA_STATE_3) { ++ DBGLOG(RSN, WARN, "Ignore Deauth for Rx Class 3 error!\n"); ++ } else { ++ /* receive packets without StaRec */ ++ prSwRfb->pvHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; ++ if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, ++ NULL, ++ prSwRfb, ++ REASON_CODE_CLASS_3_ERR, ++ (PFN_TX_DONE_HANDLER) NULL)) ++ DBGLOG(RSN, INFO, "Send Deauth for Rx Class3 Error\n"); ++ else ++ DBGLOG(RSN, WARN, "failed to send deauth for Rx class3 error\n"); ++ } ++ } ++ break; ++ ++#if CFG_SUPPORT_RDD_TEST_MODE ++ case EVENT_ID_UPDATE_RDD_STATUS: ++ { ++ P_EVENT_RDD_STATUS_T prEventRddStatus; ++ ++ prEventRddStatus = (P_EVENT_RDD_STATUS_T) (prEvent->aucBuffer); ++ ++ prAdapter->ucRddStatus = prEventRddStatus->ucRddStatus; ++ } ++ ++ break; ++#endif ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ case EVENT_ID_UPDATE_BWCS_STATUS: ++ { ++ P_PTA_IPC_T prEventBwcsStatus; ++ ++ prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); ++ ++#if CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(RSN, INFO, ++ "BCM BWCS Event: %02x%02x%02x%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++ ++ DBGLOG(RSN, INFO, ++ "BCM BWCS Event: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++#endif ++ ++ kalIndicateStatusAndComplete(prAdapter->prGlueInfo, ++ WLAN_STATUS_BWCS_UPDATE, ++ (PVOID) prEventBwcsStatus, sizeof(PTA_IPC_T)); ++ } ++ ++ break; ++ ++ case EVENT_ID_UPDATE_BCM_DEBUG: ++ { ++ P_PTA_IPC_T prEventBwcsStatus; ++ ++ prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); ++ ++#if CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(RSN, INFO, ++ "BCM FW status: %02x%02x%02x%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); ++ ++ DBGLOG(RSN, INFO, ++ "BCM FW status: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", ++ prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], ++ prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]; ++#endif ++ } ++ ++ break; ++#endif ++ ++ case EVENT_ID_DEBUG_CODE: /* only for debug */ ++ { ++ UINT_32 u4CodeId; ++ ++ DBGLOG(RSN, INFO, "[wlan-fw] function sequence: "); ++ for (u4CodeId = 0; u4CodeId < 1000; u4CodeId++) ++ DBGLOG(RSN, INFO, "%d ", prEvent->aucBuffer[u4CodeId]); ++ DBGLOG(RSN, INFO, "\n\n"); ++ } ++ break; ++ ++ case EVENT_ID_RFTEST_READY: ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ ++ case EVENT_ID_GSCAN_SCAN_AVAILABLE: ++ case EVENT_ID_GSCAN_CAPABILITY: ++ case EVENT_ID_GSCAN_SCAN_COMPLETE: ++ case EVENT_ID_GSCAN_FULL_RESULT: ++ case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: ++ case EVENT_ID_GSCAN_GEOFENCE_FOUND: ++ nicRxProcessGSCNEvent(prAdapter, prSwRfb); ++ break; ++ ++ case EVENT_ID_GSCAN_RESULT: ++ { ++ ++ UINT_8 realnum = 0; ++ ++ DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent ----->\n"); ++ realnum = nicRxProcessGSCNEvent(prAdapter, prSwRfb); ++ DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent <-----\n"); ++ ++#if 0 /* workaround for FW events cnt mis-match with the actual reqirements from wifi_hal */ ++ if (g_GetResultsCmdCnt == 0) { ++ DBGLOG(SCN, INFO, ++ "FW report events more than the wifi_hal asked number, buffer the results\n"); ++ UINT_8 i = 0; ++ ++ for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { ++#if 1 ++ if (!g_arGscanResultsIndicateNumber[i]) { ++ DBGLOG(SCN, INFO, ++ "found available index %d to insert results number %d into buffer\r\n", ++ i, realnum); ++ ++ g_arGscnResultsTempBuffer[i] = prSwRfb; ++ g_arGscanResultsIndicateNumber[i] = realnum; ++ g_GetResultsBufferedCnt++; ++ fgKeepprSwRfb = TRUE; ++ DBGLOG(SCN, INFO, "results buffered in index[%d] \r\n", i); ++ break; ++ } ++#endif ++ } ++ if (i == MAX_BUFFERED_GSCN_RESULTS) ++ DBGLOG(SCN, INFO, ++ "Gscn results buffer is full(all valid), no space to buffer result\r\n"); ++ } else if (g_GetResultsCmdCnt > 0) { ++ DBGLOG(SCN, INFO, "FW report events match the wifi_hal asked number\n"); ++ g_GetResultsCmdCnt--; ++ } else ++ DBGLOG(SCN, INFO, "g_GetResultsCmdCnt < 0 ??? unexpected case\n"); ++#endif ++ /* end of workaround */ ++ ++ } ++ break; ++ ++ case EVENT_ID_NLO_DONE: ++ prAdapter->rWifiVar.rScanInfo.fgPscnOnnning = FALSE; ++ ++ DBGLOG(INIT, INFO, "EVENT_ID_NLO_DONE\n"); ++ scnEventNloDone(prAdapter, (P_EVENT_NLO_DONE_T) (prEvent->aucBuffer)); ++ ++ break; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ case EVENT_ID_BATCH_RESULT: ++ DBGLOG(SCN, TRACE, "Got EVENT_ID_BATCH_RESULT"); ++ ++ /* command response handling */ ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++#endif /* CFG_SUPPORT_BATCH_SCAN */ ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ case EVENT_ID_TDLS: ++ TdlsexEventHandle(prAdapter->prGlueInfo, ++ (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_STATISTICS == 1) ++ case EVENT_ID_STATS_ENV: ++ statsEventHandle(prAdapter->prGlueInfo, ++ (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); ++ break; ++#endif /* CFG_SUPPORT_STATISTICS */ ++ ++ case EVENT_ID_FW_LOG_ENV: ++ { ++ P_EVENT_FW_LOG_T prEventLog; ++ ++ prEventLog = (P_EVENT_FW_LOG_T) (prEvent->aucBuffer); ++ DBGLOG(RX, INFO, "[F-L]%s\n", prEventLog->log); ++ } ++ break; ++ ++ default: ++ prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); ++ ++ if (prCmdInfo != NULL) { ++ if (prCmdInfo->pfCmdDoneHandler) ++ prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); ++ else if (prCmdInfo->fgIsOid) ++ kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); ++ /* return prCmdInfo */ ++ cmdBufFreeCmdInfo(prAdapter, prCmdInfo); ++ } ++ ++ break; ++ } ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief nicRxProcessMgmtPacket is used to dispatch management frames ++* to corresponding modules ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSWRfb the RFB to receive rx data ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ UINT_8 ucSubtype; ++#if CFG_SUPPORT_802_11W ++ BOOLEAN fgMfgDrop = FALSE; ++#endif ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ nicRxFillRFB(prAdapter, prSwRfb); ++ ++ ucSubtype = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FC_SUBTYPE) >> OFFSET_OF_FC_SUBTYPE; ++ ++#if 0 /* CFG_RX_PKTS_DUMP */ ++ { ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_16 u2TxFrameCtrl; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ u2TxFrameCtrl = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FRAME_TYPE); ++ /* if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_MANAGEMENT)) { */ ++ /* if (u2TxFrameCtrl == MAC_FRAME_BEACON || */ ++ /* u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { */ ++ ++ DBGLOG(RX, INFO, "QM RX MGT: net %u sta idx %u wlan idx %u ssn %u ptype %u subtype %u 11 %u\n", ++ (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), prHifRxHdr->ucStaRecIdx, ++ prSwRfb->ucWlanIdx, (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr),/* The new SN of the frame */ ++ prSwRfb->ucPacketType, ucSubtype, HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); ++ ++ /* DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ ++ /* } */ ++ /* } */ ++ } ++#endif ++ ++ if ((prAdapter->fgTestMode == FALSE) && (prAdapter->prGlueInfo->fgIsRegistered == TRUE)) { ++#if CFG_MGMT_FRAME_HANDLING ++#if CFG_SUPPORT_802_11W ++ fgMfgDrop = rsnCheckRxMgmt(prAdapter, prSwRfb, ucSubtype); ++ if (fgMfgDrop) { ++#if DBG ++ LOG_FUNC("QM RX MGT: Drop Unprotected Mgmt frame!!!\n"); ++#endif ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ return; ++ } ++#endif ++ if (apfnProcessRxMgtFrame[ucSubtype]) { ++ switch (apfnProcessRxMgtFrame[ucSubtype] (prAdapter, prSwRfb)) { ++ case WLAN_STATUS_PENDING: ++ return; ++ case WLAN_STATUS_SUCCESS: ++ case WLAN_STATUS_FAILURE: ++ break; ++ ++ default: ++ DBGLOG(RX, WARN, ++ "Unexpected MMPDU(0x%02X) returned with abnormal status\n", ucSubtype); ++ break; ++ } ++ } ++#endif ++ } ++ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++} ++ ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++static VOID nicRxCheckWakeupReason(P_SW_RFB_T prSwRfb) ++{ ++ PUINT_8 pvHeader = NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_16 u2PktLen = 0; ++ UINT_32 u4HeaderOffset; ++ ++ if (!prSwRfb) ++ return; ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ if (!prHifRxHdr) ++ return; ++ ++ switch (prSwRfb->ucPacketType) { ++ case HIF_RX_PKT_TYPE_DATA: ++ { ++ UINT_16 u2Temp = 0; ++ ++ if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { ++ DBGLOG(RX, INFO, "BAR frame[SSN:%d, TID:%d] wakeup host\n", ++ (UINT_16)HIF_RX_HDR_GET_SN(prHifRxHdr), (UINT_8)HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ break; ++ } ++ u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ u2PktLen = (UINT_16)(prHifRxHdr->u2PacketLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); ++ if (!pvHeader) { ++ DBGLOG(RX, ERROR, "data packet but pvHeader is NULL!\n"); ++ break; ++ } ++ u2Temp = (pvHeader[ETH_TYPE_LEN_OFFSET] << 8) | (pvHeader[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ switch (u2Temp) { ++ case ETH_P_IPV4: ++ u2Temp = *(UINT_16 *) &pvHeader[ETH_HLEN + 4]; ++ DBGLOG(RX, INFO, "IP Packet from:%d.%d.%d.%d, IP ID 0x%04x wakeup host\n", ++ pvHeader[ETH_HLEN + 12], pvHeader[ETH_HLEN + 13], ++ pvHeader[ETH_HLEN + 14], pvHeader[ETH_HLEN + 15], u2Temp); ++ break; ++ case ETH_P_ARP: ++ { ++ PUINT_8 pucEthBody = &pvHeader[ETH_HLEN]; ++ UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; ++ ++ if (u2OpCode == ARP_PRO_REQ) ++ DBGLOG(RX, INFO, "Arp Req From IP: %d.%d.%d.%d wakeup host\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ else if (u2OpCode == ARP_PRO_RSP) ++ DBGLOG(RX, INFO, "Arp Rsp from IP: %d.%d.%d.%d wakeup host\n", ++ pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); ++ break; ++ } ++ case ETH_P_1X: ++ case ETH_P_PRE_1X: ++#if CFG_SUPPORT_WAPI ++ case ETH_WPI_1X: ++#endif ++ case ETH_P_AARP: ++ case ETH_P_IPV6: ++ case ETH_P_IPX: ++ case 0x8100: /* VLAN */ ++ case 0x890d: /* TDLS */ ++ DBGLOG(RX, INFO, "Data Packet, EthType 0x%04x wakeup host\n", u2Temp); ++ break; ++ default: ++ DBGLOG(RX, WARN, "maybe abnormal data packet, EthType 0x%04x wakeup host, dump it\n", ++ u2Temp); ++ DBGLOG_MEM8(RX, INFO, pvHeader, u2PktLen > 50 ? 50:u2PacketLen); ++ break; ++ } ++ break; ++ } ++ case HIF_RX_PKT_TYPE_EVENT: ++ { ++ P_WIFI_EVENT_T prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; ++ ++ DBGLOG(RX, INFO, "Event 0x%02x wakeup host\n", prEvent->ucEID); ++ break; ++ } ++ case HIF_RX_PKT_TYPE_MANAGEMENT: ++ { ++ UINT_8 ucSubtype; ++ P_WLAN_MAC_MGMT_HEADER_T prWlanMgmtHeader; ++ ++ u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); ++ pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; ++ if (!pvHeader) { ++ DBGLOG(RX, ERROR, "Mgmt Frame but pvHeader is NULL!\n"); ++ break; ++ } ++ prWlanMgmtHeader = (P_WLAN_MAC_MGMT_HEADER_T)pvHeader; ++ ucSubtype = (prWlanMgmtHeader->u2FrameCtrl & MASK_FC_SUBTYPE) >> ++ OFFSET_OF_FC_SUBTYPE; ++ DBGLOG(RX, INFO, "MGMT frame subtype: %d SeqCtrl %d wakeup host\n", ++ ucSubtype, prWlanMgmtHeader->u2SeqCtrl); ++ break; ++ } ++ default: ++ DBGLOG(RX, WARN, "Unknown Packet %d wakeup host\n", prSwRfb->ucPacketType); ++ break; ++ } ++} ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief nicProcessRFBs is used to process RFBs in the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxProcessRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ prRxCtrl->ucNumIndPacket = 0; ++ prRxCtrl->ucNumRetainedPacket = 0; ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfb) { ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++ if (kalIsWakeupByWlan(prAdapter)) ++ nicRxCheckWakeupReason(prSwRfb); ++#endif ++ switch (prSwRfb->ucPacketType) { ++ case HIF_RX_PKT_TYPE_DATA: ++ nicRxProcessDataPacket(prAdapter, prSwRfb); ++ break; ++ ++ case HIF_RX_PKT_TYPE_EVENT: ++ nicRxProcessEventPacket(prAdapter, prSwRfb); ++ break; ++ ++ case HIF_RX_PKT_TYPE_TX_LOOPBACK: ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ { ++ kalDevLoopbkRxHandle(prAdapter, prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ } ++#else ++ DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ break; ++ ++ case HIF_RX_PKT_TYPE_MANAGEMENT: ++ nicRxProcessMgmtPacket(prAdapter, prSwRfb); ++ break; ++ ++ default: ++ RX_INC_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT); ++ RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); ++ DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++ nicRxReturnRFB(prAdapter, prSwRfb); /* need to free it */ ++ break; ++ } ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++ if (prRxCtrl->ucNumIndPacket > 0) { ++ RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, prRxCtrl->ucNumIndPacket); ++ RX_ADD_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT, prRxCtrl->ucNumRetainedPacket); ++ ++ /* DBGLOG(RX, INFO, ("%d packets indicated, Retained cnt = %d\n", */ ++ /* prRxCtrl->ucNumIndPacket, prRxCtrl->ucNumRetainedPacket)); */ ++#if CFG_NATIVE_802_11 ++ kalRxIndicatePkts(prAdapter->prGlueInfo, (UINT_32) prRxCtrl->ucNumIndPacket, ++ (UINT_32) prRxCtrl->ucNumRetainedPacket); ++#else ++ kalRxIndicatePkts(prAdapter->prGlueInfo, prRxCtrl->apvIndPacket, (UINT_32) prRxCtrl->ucNumIndPacket); ++#endif ++ } ++ ++} /* end of nicRxProcessRFBs() */ ++ ++#if !CFG_SDIO_INTR_ENHANCE ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read the rx data from data port and setup RFB ++* ++* @param prAdapter pointer to the Adapter handler ++* @param prSWRfb the RFB to receive rx data ++* ++* @retval WLAN_STATUS_SUCCESS: SUCCESS ++* @retval WLAN_STATUS_FAILURE: FAILURE ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucBuf; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4PktLen = 0, u4ReadBytes; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgResult = TRUE; ++ UINT_32 u4RegValue; ++ UINT_32 rxNum; ++ ++ DEBUGFUNC("nicRxReadBuffer"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ pucBuf = prSwRfb->pucRecvBuff; ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(pucBuf); ++ DBGLOG(RX, TRACE, "pucBuf= 0x%x, prHifRxHdr= 0x%x\n", pucBuf, prHifRxHdr); ++ ++ do { ++ /* Read the RFB DW length and packet length */ ++ HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ /* 20091021 move the line to get the HIF RX header (for RX0/1) */ ++ if (u4RegValue == 0) { ++ DBGLOG(RX, ERROR, "No RX packet\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ u4PktLen = u4RegValue & BITS(0, 15); ++ if (u4PktLen != 0) { ++ rxNum = 0; ++ } else { ++ rxNum = 1; ++ u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; ++ } ++ ++ DBGLOG(RX, TRACE, "RX%d: u4PktLen = %d\n", rxNum, u4PktLen); ++ ++ /* 4 <4> Read Entire RFB and packet, include HW appended DW (Checksum Status) */ ++ u4ReadBytes = ALIGN_4(u4PktLen) + 4; ++ HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, CFG_RX_MAX_PKT_SIZE); ++ ++ /* 20091021 move the line to get the HIF RX header */ ++ /* u4PktLen = (UINT_32)prHifRxHdr->u2PacketLen; */ ++ if (u4PktLen != (UINT_32) prHifRxHdr->u2PacketLen) { ++ DBGLOG(RX, ERROR, "Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", ++ u4PktLen, prHifRxHdr->u2PacketLen); ++#if DBG ++ dumpMemory8((PUINT_8) prHifRxHdr, ++ (prHifRxHdr->u2PacketLen > 4096) ? 4096 : prHifRxHdr->u2PacketLen); ++#endif ++ ASSERT(0); ++ } ++ /* u4PktLen is byte unit, not inlude HW appended DW */ ++ ++ prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ /* fgResult will be updated in MACRO */ ++ if (!fgResult) ++ return WLAN_STATUS_FAILURE; ++ ++ DBGLOG(RX, TRACE, "Dump RX buffer, length = 0x%x\n", u4ReadBytes); ++ DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); ++ } while (FALSE); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port, fill RFB ++* and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ UINT_32 u4HwAppendDW; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (!prSwRfb) { ++ DBGLOG(RX, TRACE, "No More RFB\n"); ++ break; ++ } ++ /* need to consider */ ++ if (nicRxReadBuffer(prAdapter, prSwRfb) == WLAN_STATUS_FAILURE) { ++ DBGLOG(RX, TRACE, "halRxFillRFB failed\n"); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ } ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ u4HwAppendDW = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); ++ DBGLOG(RX, TRACE, "u4HwAppendDW = 0x%x\n", u4HwAppendDW); ++ DBGLOG(RX, TRACE, "u2PacketLen = 0x%x\n", prHifRxHdr->u2PacketLen); ++ } while (FALSE); /* while (RX_STATUS_TEST_MORE_FLAG(u4HwAppendDW)); */ ++ ++ return; ++ ++} /* end of nicReceiveRFBs() */ ++ ++#else ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port, fill RFB ++* and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param u4DataPort Specify which port to read ++* @param u2RxLength Specify to the the rx packet length in Byte. ++* @param prSwRfb the RFB to receive rx data. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS ++nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, ++ IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucBuf; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ UINT_32 u4PktLen = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; ++ BOOLEAN fgResult = TRUE; ++ ++ DEBUGFUNC("nicRxEnhanceReadBuffer"); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ pucBuf = prSwRfb->pucRecvBuff; ++ ASSERT(pucBuf); ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ /* DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); */ ++ ++ do { ++ /* 4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW */ ++ HAL_READ_RX_PORT(prAdapter, ++ u4DataPort, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), pucBuf, CFG_RX_MAX_PKT_SIZE); ++ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); ++ break; ++ } ++ ++ u4PktLen = (UINT_32) (prHifRxHdr->u2PacketLen); ++ /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ ++ ++ prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ /* 4 <2> if the RFB dw size or packet size is zero */ ++ if (u4PktLen == 0) { ++ DBGLOG(RX, ERROR, "Packet Length = %u\n", u4PktLen); ++ ASSERT(0); ++ break; ++ } ++ /* 4 <3> if the packet is too large or too small */ ++ if (u4PktLen > CFG_RX_MAX_PKT_SIZE) { ++ DBGLOG(RX, TRACE, "Read RX Packet Lentgh Error (%u)\n", u4PktLen); ++ ASSERT(0); ++ break; ++ } ++ ++ u4Status = WLAN_STATUS_SUCCESS; ++ } while (FALSE); ++ ++ DBGLOG_MEM8(RX, TRACE, pucBuf, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port for SDIO ++* I/F, fill RFB and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_SDIO_CTRL_T prSDIOCtrl; ++ P_RX_CTRL_T prRxCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 i, rxNum; ++ UINT_16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxSDIOReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ASSERT(prSDIOCtrl); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ for (rxNum = 0; rxNum < 2; rxNum++) { ++ u2RxPktNum = ++ (rxNum == 0 ? prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); ++ ++ if (u2RxPktNum == 0) ++ continue; ++ ++ for (i = 0; i < u2RxPktNum; i++) { ++ if (rxNum == 0) { ++ /* HAL_READ_RX_LENGTH */ ++ HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, &u2Tmp); ++ } else if (rxNum == 1) { ++ /* HAL_READ_RX_LENGTH */ ++ HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, &u2RxLength); ++ } ++ ++ if (!u2RxLength) ++ break; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (!prSwRfb) { ++ DBGLOG(RX, TRACE, "No More RFB\n"); ++ break; ++ } ++ ASSERT(prSwRfb); ++ ++ if (nicRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, prSwRfb) == WLAN_STATUS_FAILURE) { ++ DBGLOG(RX, TRACE, "nicRxEnhanceRxReadBuffer failed\n"); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ break; ++ } ++ /* prSDIOCtrl->au4RxLength[i] = 0; */ ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ } ++ } ++ ++ prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; ++ prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; ++ ++} /* end of nicRxSDIOReceiveRFBs() */ ++ ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++#if CFG_SDIO_RX_AGG ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read frames from the data port for SDIO with Rx aggregation enabled ++* I/F, fill RFB and put each frame into the rReceivedRFBList queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter) ++{ ++ P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; ++ P_RX_CTRL_T prRxCtrl; ++ P_SDIO_CTRL_T prSDIOCtrl; ++ P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; ++ UINT_32 u4RxLength; ++ UINT_32 i, rxNum; ++ UINT_32 u4RxAggCount = 0, u4RxAggLength = 0; ++ UINT_32 u4RxAvailAggLen, u4CurrAvailFreeRfbCnt; ++ PUINT_8 pucSrcAddr; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ BOOLEAN fgResult = TRUE; ++ BOOLEAN fgIsRxEnhanceMode; ++ UINT_16 u2RxPktNum; ++#if CFG_SDIO_RX_ENHANCE ++ UINT_32 u4MaxLoopCount = CFG_MAX_RX_ENHANCE_LOOP_COUNT; ++#endif ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicRxSDIOAggReceiveRFBs"); ++ ++ ASSERT(prAdapter); ++ prEnhDataStr = prAdapter->prSDIOCtrl; ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++ ++#if CFG_SDIO_RX_ENHANCE ++ fgIsRxEnhanceMode = TRUE; ++#else ++ fgIsRxEnhanceMode = FALSE; ++#endif ++ ++ do { ++#if CFG_SDIO_RX_ENHANCE ++ /* to limit maximum loop for RX */ ++ u4MaxLoopCount--; ++ if (u4MaxLoopCount == 0) ++ break; ++#endif ++ ++ if (prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) ++ break; ++ ++ for (rxNum = 0; rxNum < 2; rxNum++) { ++ u2RxPktNum = ++ (rxNum == ++ 0 ? prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); ++ ++ /* if this assertion happened, it is most likely a F/W bug */ ++ ASSERT(u2RxPktNum <= 16); ++ ++ if (u2RxPktNum > 16) ++ continue; ++ ++ if (u2RxPktNum == 0) ++ continue; ++ ++#if CFG_HIF_STATISTICS ++ prRxCtrl->u4TotalRxAccessNum++; ++ prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; ++#endif ++ ++ u4CurrAvailFreeRfbCnt = prRxCtrl->rFreeSwRfbList.u4NumElem; ++ ++ /* if SwRfb is not enough, abort reading this time */ ++ if (u4CurrAvailFreeRfbCnt < u2RxPktNum) { ++#if CFG_HIF_RX_STARVATION_WARNING ++ DbgPrint("FreeRfb is not enough: %d available, need %d\n", u4CurrAvailFreeRfbCnt, ++ u2RxPktNum); ++ DbgPrint("Queued Count: %d / Dequeud Count: %d\n", prRxCtrl->u4QueuedCnt, ++ prRxCtrl->u4DequeuedCnt); ++#endif ++ continue; ++ } ++#if CFG_SDIO_RX_ENHANCE ++ u4RxAvailAggLen = ++ CFG_RX_COALESCING_BUFFER_SIZE - (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + ++ 4 /* extra HW padding */); ++#else ++ u4RxAvailAggLen = CFG_RX_COALESCING_BUFFER_SIZE; ++#endif ++ u4RxAggCount = 0; ++ ++ for (i = 0; i < u2RxPktNum; i++) { ++ u4RxLength = (rxNum == 0 ? ++ (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : ++ (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); ++ ++ if (!u4RxLength) { ++ ASSERT(0); ++ break; ++ } ++ ++ if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < u4RxAvailAggLen) { ++ if (u4RxAggCount < u4CurrAvailFreeRfbCnt) { ++ u4RxAvailAggLen -= ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN); ++ u4RxAggCount++; ++ } else { ++ /* no FreeSwRfb for rx packet */ ++ ASSERT(0); ++ break; ++ } ++ } else { ++ /* CFG_RX_COALESCING_BUFFER_SIZE is not large enough */ ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ u4RxAggLength = (CFG_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); ++ /* DBGLOG(RX, INFO, ("u4RxAggCount = %d, u4RxAggLength = %d\n", */ ++ /* u4RxAggCount, u4RxAggLength)); */ ++ ++ HAL_READ_RX_PORT(prAdapter, ++ rxNum, ++ u4RxAggLength, prRxCtrl->pucRxCoalescingBufPtr, CFG_RX_COALESCING_BUFFER_SIZE); ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read RX Agg Packet Error\n"); ++ continue; ++ } ++ ++ pucSrcAddr = prRxCtrl->pucRxCoalescingBufPtr; ++ for (i = 0; i < u4RxAggCount; i++) { ++ UINT_16 u2PktLength; ++ ++ u2PktLength = (rxNum == 0 ? ++ prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : ++ prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ ASSERT(prSwRfb); ++ kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, ++ ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); ++ ++ /* record the rx time */ ++ STATS_RX_ARRIVE_TIME_RECORD(prSwRfb); /* ms */ ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ASSERT(prHifRxHdr); ++ ++ prSwRfb->ucPacketType = ++ (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); ++ /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ ++ ++ prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); ++ RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); ++ /* prEnhDataStr->au4RxLength[i] = 0; */ ++ } ++ ++#if CFG_SDIO_RX_ENHANCE ++ kalMemCopy(prAdapter->prSDIOCtrl, (pucSrcAddr + 4), sizeof(ENHANCE_MODE_DATA_STRUCT_T)); ++ ++ /* do the same thing what nicSDIOReadIntStatus() does */ ++ if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && ++ (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { ++ prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; ++ } ++ ++ if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && ++ HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && ++ (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { ++ prSDIOCtrl->u4WHISR |= BIT(31); ++ } ++ ++ /* dispatch to interrupt handler with RX bits masked */ ++ nicProcessIST_impl(prAdapter, ++ prSDIOCtrl->u4WHISR & (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))); ++#endif ++ } ++ ++#if !CFG_SDIO_RX_ENHANCE ++ prEnhDataStr->rRxInfo.u.u2NumValidRx0Len = 0; ++ prEnhDataStr->rRxInfo.u.u2NumValidRx1Len = 0; ++#endif ++ } while ((prEnhDataStr->rRxInfo.u.u2NumValidRx0Len || prEnhDataStr->rRxInfo.u.u2NumValidRx1Len) ++ && fgIsRxEnhanceMode); ++ ++} ++#endif /* CFG_SDIO_RX_AGG */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Setup a RFB and allocate the os packet to the RFB ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSwRfb Pointer to the RFB ++* ++* @retval WLAN_STATUS_SUCCESS ++* @retval WLAN_STATUS_RESOURCES ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ PVOID pvPacket; ++ PUINT_8 pucRecvBuff; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (!prSwRfb->pvPacket) { ++ kalMemZero(prSwRfb, sizeof(SW_RFB_T)); ++ pvPacket = kalPacketAlloc(prAdapter->prGlueInfo, CFG_RX_MAX_PKT_SIZE, &pucRecvBuff); ++ if (pvPacket == NULL) ++ return WLAN_STATUS_RESOURCES; ++ ++ prSwRfb->pvPacket = pvPacket; ++ prSwRfb->pucRecvBuff = (PVOID) pucRecvBuff; ++ } else { ++ kalMemZero(((PUINT_8) prSwRfb + OFFSET_OF(SW_RFB_T, prHifRxHdr)), ++ (sizeof(SW_RFB_T) - OFFSET_OF(SW_RFB_T, prHifRxHdr))); ++ } ++ ++ prSwRfb->prHifRxHdr = (P_HIF_RX_HEADER_T) (prSwRfb->pucRecvBuff); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} /* end of nicRxSetupRFB() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is called to put a RFB back onto the "RFB with Buffer" list ++* or "RFB without buffer" list according to pvPacket. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prSwRfb Pointer to the RFB ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ P_QUE_ENTRY_T prQueEntry; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ prQueEntry = &prSwRfb->rQueEntry; ++ ++ ASSERT(prQueEntry); ++ ++ /* The processing on this RFB is done, so put it back on the tail of ++ our list */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++ ++ if (prSwRfb->pvPacket) { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(&prRxCtrl->rFreeSwRfbList, prQueEntry); ++ } else { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(&prRxCtrl->rIndicatedRfbList, prQueEntry); ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); ++} /* end of nicRxReturnRFB() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process rx interrupt. When the rx ++* Interrupt is asserted, it means there are frames in queue. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ prGlueInfo->IsrRxCnt++; ++#if CFG_SDIO_INTR_ENHANCE ++#if CFG_SDIO_RX_AGG ++ nicRxSDIOAggReceiveRFBs(prAdapter); ++#else ++ nicRxSDIOReceiveRFBs(prAdapter); ++#endif ++#else ++ nicRxReceiveRFBs(prAdapter); ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ nicRxProcessRFBs(prAdapter); ++ ++ return; ++ ++} /* end of nicProcessRxInterrupt() */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Used to update IP/TCP/UDP checksum statistics of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param aeCSUM The array of checksum result. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(aeCSUM); ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS) || ++ (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_IP_SUCCESS_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) || (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_FAILED)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_IP_FAILED_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L3_PKT_COUNT); ++ } else { ++ ASSERT(0); ++ } ++ ++ if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) { ++ /* count success num */ ++ RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_SUCCESS_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_FAILED_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_SUCCESS_COUNT); ++ } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_FAILED_COUNT); ++ } else if ((aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_NONE)) { ++ RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L4_PKT_COUNT); ++ } else { ++ ASSERT(0); ++ } ++ ++} /* end of nicRxUpdateCSUMStatistics() */ ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to query current status of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pucBuffer Pointer to the message buffer. ++* @param pu4Count Pointer to the buffer of message length count. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucCurrBuf = pucBuffer; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ ++ ASSERT(pu4Count); ++ ++ SPRINTF(pucCurrBuf, ("\n\nRX CTRL STATUS:")); ++ SPRINTF(pucCurrBuf, ("\n===============")); ++ SPRINTF(pucCurrBuf, ("\nFREE RFB w/i BUF LIST :%9u", prRxCtrl->rFreeSwRfbList.u4NumElem)); ++ SPRINTF(pucCurrBuf, ("\nFREE RFB w/o BUF LIST :%9u", prRxCtrl->rIndicatedRfbList.u4NumElem)); ++ SPRINTF(pucCurrBuf, ("\nRECEIVED RFB LIST :%9u", prRxCtrl->rReceivedRfbList.u4NumElem)); ++ ++ SPRINTF(pucCurrBuf, ("\n\n")); ++ ++ /* *pu4Count = (UINT_32)((UINT_32)pucCurrBuf - (UINT_32)pucBuffer); */ ++ ++} /* end of nicRxQueryStatus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Clear RX related counters ++* ++* @param prAdapter Pointer of Adapter Data Structure ++* ++* @return - (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ RX_RESET_ALL_CNTS(prRxCtrl); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to query current statistics of RX Module. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param pucBuffer Pointer to the message buffer. ++* @param pu4Count Pointer to the buffer of message length count. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) ++{ ++ P_RX_CTRL_T prRxCtrl; ++ PUINT_8 pucCurrBuf = pucBuffer; ++ ++ ASSERT(prAdapter); ++ prRxCtrl = &prAdapter->rRxCtrl; ++ ASSERT(prRxCtrl); ++ ++ /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ ++ ASSERT(pu4Count); ++ ++#define SPRINTF_RX_COUNTER(eCounter) \ ++ SPRINTF(pucCurrBuf, ("%-30s : %u\n", #eCounter, (UINT_32)prRxCtrl->au8Statistics[eCounter])) ++ ++ SPRINTF_RX_COUNTER(RX_MPDU_TOTAL_COUNT); ++ SPRINTF_RX_COUNTER(RX_SIZE_ERR_DROP_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_INDICATION_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_RETURNED_COUNT); ++ SPRINTF_RX_COUNTER(RX_DATA_RETAINED_COUNT); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 ++ SPRINTF_RX_COUNTER(RX_CSUM_TCP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UDP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_IP_FAILED_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_TCP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UDP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_IP_SUCCESS_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L4_PKT_COUNT); ++ SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L3_PKT_COUNT); ++ SPRINTF_RX_COUNTER(RX_IP_V6_PKT_CCOUNT); ++#endif ++ ++ /* *pu4Count = (UINT_32)(pucCurrBuf - pucBuffer); */ ++ ++ nicRxClearStatistics(prAdapter); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Read the Response data from data port ++* ++* @param prAdapter pointer to the Adapter handler ++* @param pucRspBuffer pointer to the Response buffer ++* ++* @retval WLAN_STATUS_SUCCESS: Response packet has been read ++* @retval WLAN_STATUS_FAILURE: Read Response packet timeout or error occurred ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++nicRxWaitResponse(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length) ++{ ++ UINT_32 u4Value = 0, u4PktLen = 0; ++ UINT_32 i = 0; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgResult = TRUE; ++ UINT_32 u4Time, u4Current; ++ ++ DEBUGFUNC("nicRxWaitResponse"); ++ ++ ASSERT(prAdapter); ++ ASSERT(pucRspBuffer); ++ ASSERT(ucPortIdx < 2); ++ ++ u4Time = kalGetTimeTick(); ++ ++ do { ++ /* Read the packet length */ ++ HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); ++ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read Response Packet Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ if (ucPortIdx == 0) ++ u4PktLen = u4Value & 0xFFFF; ++ else ++ u4PktLen = (u4Value >> 16) & 0xFFFF; ++ ++/* DBGLOG(RX, TRACE, ("i = %d, u4PktLen = %d\n", i, u4PktLen)); */ ++ ++ if (u4PktLen == 0) { ++ /* timeout exceeding check */ ++ u4Current = kalGetTimeTick(); ++ ++ if ((u4Current > u4Time) && ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) { ++ DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT1 %u %d %u\n", u4PktLen, i, u4Current); ++ return WLAN_STATUS_FAILURE; ++ } else if (u4Current < u4Time && ((u4Current + (0xFFFFFFFF - u4Time)) > RX_RESPONSE_TIMEOUT)) { ++ DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT2 %u %d %u\n", u4PktLen, i, u4Current); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* Response packet is not ready */ ++ kalUdelay(50); ++ ++ i++; ++ continue; ++ } ++ if (u4PktLen > u4MaxRespBufferLen) { ++ /* ++ TO: buffer is not enough but we still need to read all data from HIF to avoid ++ HIF crazy. ++ */ ++ DBGLOG(RX, ERROR, ++ "Not enough Event Buffer: required length = 0x%x, available buffer length = %d\n", ++ u4PktLen, u4MaxRespBufferLen); ++ DBGLOG(RX, ERROR, "i = %d, u4PktLen = %u\n", i, u4PktLen); ++ return WLAN_STATUS_FAILURE; ++ } ++ HAL_PORT_RD(prAdapter, ++ ucPortIdx == 0 ? MCR_WRDR0 : MCR_WRDR1, u4PktLen, pucRspBuffer, u4MaxRespBufferLen); ++ ++ /* fgResult will be updated in MACRO */ ++ if (!fgResult) { ++ DBGLOG(RX, ERROR, "Read Response Packet Error\n"); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ DBGLOG(RX, TRACE, "Dump Response buffer, length = 0x%x\n", u4PktLen); ++ DBGLOG_MEM8(RX, TRACE, pucRspBuffer, u4PktLen); ++ ++ *pu4Length = u4PktLen; ++ break; ++ } while (TRUE); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Set filter to enable Promiscuous Mode ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++} /* end of nicRxEnablePromiscuousMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Set filter to disable Promiscuous Mode ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++} /* end of nicRxDisablePromiscuousMode() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function flushes all packets queued in reordering module ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Flushed successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter) ++{ ++ P_SW_RFB_T prSwRfb; ++ ++ ASSERT(prAdapter); ++ ++ prSwRfb = qmFlushRxQueues(prAdapter); ++ if (prSwRfb != NULL) { ++ do { ++ P_SW_RFB_T prNextSwRfb; ++ ++ /* save next first */ ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ ++ /* free */ ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief ++* ++* @param ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) ++{ ++ P_WLAN_ACTION_FRAME prActFrame; ++ ++ ASSERT(prAdapter); ++ ASSERT(prSwRfb); ++ ++ if (prSwRfb->u2PacketLen < sizeof(WLAN_ACTION_FRAME) - 1) ++ return WLAN_STATUS_INVALID_PACKET; ++ prActFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; ++ DBGLOG(RX, INFO, "Category %u\n", prActFrame->ucCategory); ++ ++ switch (prActFrame->ucCategory) { ++ case CATEGORY_PUBLIC_ACTION: ++ if (HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) ++ aisFuncValidateRxActionFrame(prAdapter, prSwRfb); ++#if CFG_ENABLE_WIFI_DIRECT ++ else if (prAdapter->fgIsP2PRegistered) { ++ rlmProcessPublicAction(prAdapter, prSwRfb); ++ ++ p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); ++ ++ } ++#endif ++ break; ++ ++ case CATEGORY_HT_ACTION: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ rlmProcessHtAction(prAdapter, prSwRfb); ++#endif ++ break; ++ case CATEGORY_VENDOR_SPECIFIC_ACTION: ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prAdapter->fgIsP2PRegistered) ++ p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); ++#endif ++ break; ++#if CFG_SUPPORT_802_11W ++ case CATEGORY_SA_QUERT_ACTION: ++ { ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ ++ if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) ++ && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { ++ if (!(prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC)) { ++ /* MFP test plan 5.3.3.4 */ ++ rsnSaQueryAction(prAdapter, prSwRfb); ++ } else { ++ DBGLOG(RSN, TRACE, "Un-Protected SA Query, do nothing\n"); ++ } ++ } ++ } ++ break; ++#endif ++#if CFG_SUPPORT_802_11V ++ case CATEGORY_WNM_ACTION: ++ { ++ wnmWNMAction(prAdapter, prSwRfb); ++ } ++ break; ++#endif ++ ++#if CFG_SUPPORT_DFS /* Add by Enlai */ ++ case CATEGORY_SPEC_MGT: ++ { ++ if (prAdapter->fgEnable5GBand == TRUE) ++ rlmProcessSpecMgtAction(prAdapter, prSwRfb); ++ } ++ break; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ case 12: /* shall not be here */ ++ /* ++ A received TDLS Action frame with the Type field set to Management shall ++ be discarded. Note that the TDLS Discovery Response frame is not a TDLS ++ frame but a Public Action frame. ++ */ ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ default: ++ break; ++ } /* end of switch case */ ++ ++ return WLAN_STATUS_SUCCESS; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c +new file mode 100644 +index 000000000000..024bd9507603 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c +@@ -0,0 +1,2350 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_tx.c#1 ++*/ ++ ++/*! \file nic_tx.c ++ \brief Functions that provide TX operation in NIC Layer. ++ ++ This file provides TX functions which are responsible for both Hardware and ++ Software Resource Management and keep their Synchronization. ++*/ ++ ++/* ++** Log: nic_tx.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add log counter for tx ++ * ++ * 11 09 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for beacon timeout and sta aging timeout. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 05 17 2011 cp.wu ++ * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss ++ * disconnection ++ * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame ++ * dropping cases for TC4 path ++ * remove unused variables. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame ++ * dropping cases for TC4 path ++ * 1. add nicTxGetResource() API for QM to make decisions. ++ * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 02 16 2011 cp.wu ++ * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking available count ++ * and modify behavior ++ * 1. add new API: nicTxGetFreeCmdCount() ++ * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore ++ * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion ++ * 2. shorten polling count for shorter response time ++ * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 09 29 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * since the u2TxByteCount_UserPriority will or another setting, keep the overall buffer for avoid error ++ * ++ * 09 24 2010 wh.su ++ * NULL ++ * [WCXRP000000058][MT6620 Wi-Fi][Driver] Fail to handshake with WAPI AP due the 802.1x frame send to fw with extra ++ * bytes padding. ++ * ++ * 09 01 2010 cp.wu ++ * NULL ++ * HIFSYS Clock Source Workaround ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * eliminate klockwork errors ++ * ++ * 08 20 2010 wh.su ++ * NULL ++ * adding the eapol callback setting. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 05 2010 yuche.tsai ++ * NULL ++ * . ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 13 2010 cp.wu ++ * ++ * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets ++ * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending ++ * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network ++ * operation ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 24 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 22 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) add command warpper for STA-REC/BSS-INFO sync. ++ * 2) enhance command packet sending procedure for non-oid part ++ * 3) add command packet definitions for STA-REC/BSS-INFO sync. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add checking for TX descriptor poll. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * TX descriptors are now allocated once for reducing allocation overhead ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change zero-padding for TX port access to HAL. ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 15 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * . ++ * ++ * 06 14 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * fill extra information for revised HIF_TX_HEADER. ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 10 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change to enqueue TX frame infinitely. ++ * ++ * 06 09 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add TX_PACKET_MGMT to indicate the frame is coming from management modules ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Tag the packet for QoS on Tx path ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove driver-land statistics. ++ * ++ * 03 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++ * 03 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK ++ * * * * * ++ * ++* 03 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code clean: removing unused variables and structure definitions ++ * ++ * 03 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. ++ * * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds ++ * ++ * 03 02 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add mutex to avoid multiple access to qmTxQueue simultaneously. ++ * ++ * 02 26 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * avoid referring to NDIS-specific data structure directly from non-glue layer. ++ * ++ * 02 24 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add Ethernet destination address information in packet info for TX ++ * ++ * 02 10 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] ++ * * * * * * 2) firmware image length is now retrieved via NdisFileOpen ++ * * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore ++ * * * * * * 4) nicRxWaitResponse() revised ++ * * * * * * 5) another set of TQ counter default value is added for fw-download state ++ * * * * * * 6) Wi-Fi load address is now retrieved from registry too ++ * ++ * 02 09 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address ++ * * * * * * * * * 2. follow MSDN defined behavior when associates to another AP ++ * * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes ++ * ++ * 02 08 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * prepare for implementing fw download logic ++ * ++ * 01 27 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. eliminate improper variable in rHifInfo ++ * * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged ++ * * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode ++ * * * * * * * * * 4. correct some HAL implementation ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++ * ++ * 01 13 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo ++ * ++ * 12 30 2009 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) According to CMD/EVENT documentation v0.8, ++ * * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, ++ * * * * * * * * * * and result is retrieved by get ATInfo instead ++ * * * * * * * * * * 2) add 4 counter for recording aggregation statistics ++** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-10 16:52:15 GMT mtk02752 ++** remove unused API ++** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-12-07 22:44:24 GMT mtk02752 ++** correct assertion criterion ++** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-12-07 21:15:52 GMT mtk02752 ++** correct trivial mistake ++** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-12-04 15:47:21 GMT mtk02752 ++** + always append a dword of zero on TX path to avoid TX aggregation to triggered on uninitialized data ++** + add more assertion for packet size check ++** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-12-04 14:51:55 GMT mtk02752 ++** nicTxMsduInfo(): save ptr for next entry before attaching to qDataPort ++** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-12-04 11:54:54 GMT mtk02752 ++** add 2 assertion for size check ++** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-12-03 16:20:35 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-30 10:57:10 GMT mtk02752 ++** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T ++** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-30 09:20:43 GMT mtk02752 ++** use TC4 instead of TC5 for command packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-27 11:08:11 GMT mtk02752 ++** add flush for reset ++** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-26 20:31:22 GMT mtk02752 ++** fill prMsduInfo->ucUserPriority ++** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-25 21:04:33 GMT mtk02752 ++** fill u2SeqNo ++** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-24 20:52:12 GMT mtk02752 ++** integration with SD1's data path API ++** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-24 19:54:25 GMT mtk02752 ++** nicTxRetransmitOfOsSendQue & nicTxData but changed to use nicTxMsduInfoList ++** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 17:53:18 GMT mtk02752 ++** add nicTxCmd() for SD1_SD3_DATAPATH_INTEGRATION, which will append only HIF_TX_HEADER. seqNum, ++** WIFI_CMD_T will be created inside oid handler ++** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-20 15:10:24 GMT mtk02752 ++** use TxAccquireResource instead of accessing TCQ directly. ++** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-17 22:40:57 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-17 17:35:40 GMT mtk02752 ++** add nicTxMsduInfoList () implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-17 11:07:10 GMT mtk02752 ++** add nicTxAdjustTcq() implementation ++** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-16 22:28:38 GMT mtk02752 ++** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-16 21:45:32 GMT mtk02752 ++** add SD1_SD3_DATAPATH_INTEGRATION data path handling ++** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-13 13:29:56 GMT mtk01084 ++** modify TX hdr format, fix tx retransmission issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 10:36:21 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-04 14:11:11 GMT mtk01084 ++** modify TX SW data structure ++** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-10-29 19:56:17 GMT mtk01084 ++** modify HAL part ++** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-13 21:59:23 GMT mtk01084 ++** update for new HW design ++** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-02 14:00:18 GMT mtk01725 ++** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-05-20 12:26:06 GMT mtk01461 ++** Assign SeqNum to CMD Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-05-19 10:54:04 GMT mtk01461 ++** Add debug message ++** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-05-12 09:41:55 GMT mtk01461 ++** Fix Query Command need resp issue ++** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-29 15:44:38 GMT mtk01461 ++** Move OS dependent code to kalQueryTxOOBData() ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-28 10:40:03 GMT mtk01461 ++** Add nicTxReleaseResource() for SDIO_STATUS_ENHANCE, and also fix the TX aggregation issue for 1x packet to TX1 port ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-21 09:50:47 GMT mtk01461 ++** Update nicTxCmd() for moving wait RESP function call to wlanSendCommand() ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-17 19:56:32 GMT mtk01461 ++** Move the CMD_INFO_T related function to cmd_buf.c ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-17 18:14:40 GMT mtk01426 ++** Update OOB query for TX packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:51:32 GMT mtk01426 ++** Support PKGUIO ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-02 17:26:40 GMT mtk01461 ++** Add virtual OOB for HIF LOOPBACK SW PRETEST ++** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:54:43 GMT mtk01461 ++** Add function for SDIO_TX_ENHANCE ++** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:53:47 GMT mtk01461 ++** Add code for retransmit of rOsSendQueue, mpSendPacket(), and add code for TX Checksum offload, Loopback Test. ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:33:51 GMT mtk01461 ++** Add code for TX Data & Cmd Packet ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:40 GMT mtk01461 ++** Fix LINT warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:30 GMT mtk01461 ++** Update TX PATH API ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:04 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will initial all variables in regard to SW TX Queues and ++* all free lists of MSDU_INFO_T and SW_TFCB_T. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxInitialize(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ PUINT_8 pucMemHandle; ++ P_MSDU_INFO_T prMsduInfo; ++ UINT_32 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicTxInitialize"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ /* 4 <1> Initialization of Traffic Class Queue Parameters */ ++ nicTxResetResource(prAdapter); ++ ++#if CFG_SDIO_TX_AGG ++ prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; ++#endif /* CFG_SDIO_TX_AGG */ ++ ++ /* allocate MSDU_INFO_T and link it into rFreeMsduInfoList */ ++ QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); ++ ++ pucMemHandle = prTxCtrl->pucTxCached; ++ for (i = 0; i < CFG_TX_MAX_PKT_NUM; i++) { ++ prMsduInfo = (P_MSDU_INFO_T) pucMemHandle; ++ kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ ++ pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); ++ } ++ ++ ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); ++ /* Check if the memory allocation consist with this initialization function */ ++ ASSERT((UINT_32) (pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize); ++ ++ QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); ++ prTxCtrl->i4TxMgmtPendingNum = 0; ++ ++#if CFG_HIF_STATISTICS ++ prTxCtrl->u4TotalTxAccessNum = 0; ++ prTxCtrl->u4TotalTxPacketNum = 0; ++#endif ++ ++ prTxCtrl->i4PendingFwdFrameCount = 0; ++ ++ qmInit(prAdapter); ++ ++ TX_RESET_ALL_CNTS(prTxCtrl); ++ ++} /* end of nicTxInitialize() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will check if has enough TC Buffer for incoming ++* packet and then update the value after promise to provide the resources. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] ucTC Specify the resource of TC ++* ++* \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. ++* \retval WLAN_STATUS_RESOURCES Resource is not available. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 u4CurrTick = 0; ++WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt) ++{ ++#define TC4_NO_RESOURCE_DELAY_MS 5 /* exponential of 5s */ ++ ++ P_TX_CTRL_T prTxCtrl; ++ WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; ++ P_QUE_MGT_T prQM; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ prQM = &prAdapter->rQM; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++/* DbgPrint("nicTxAcquireResource prTxCtrl->rTc.aucFreeBufferCount[%d]=%d\n", ++ ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); */ ++ do { ++ if (pfgIsSecOrMgmt && (ucTC == TC4_INDEX)) { ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] < 2) { ++ DBGLOG(TX, EVENT, " aucFreeBufferCount = %d\n", ++ prTxCtrl->rTc.aucFreeBufferCount[ucTC]); ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) ++ u4CurrTick = 0; ++ ++ break; ++ } ++ } ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) { ++ ++ if (ucTC == TC4_INDEX) ++ u4CurrTick = 0; ++ /* get a available TX entry */ ++ prTxCtrl->rTc.aucFreeBufferCount[ucTC]--; ++ ++ prQM->au4ResourceUsedCounter[ucTC]++; ++ ++ DBGLOG(TX, EVENT, "Acquire: TC = %d aucFreeBufferCount = %d\n", ++ ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); ++ ++ u4Status = WLAN_STATUS_SUCCESS; ++ } ++ } while (FALSE); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ if (ucTC == TC4_INDEX) { ++ if (u4CurrTick == 0) ++ u4CurrTick = kalGetTimeTick(); ++ if (CHECK_FOR_TIMEOUT(kalGetTimeTick(), u4CurrTick, ++ SEC_TO_SYSTIME(TC4_NO_RESOURCE_DELAY_MS))) { ++ wlanDumpTcResAndTxedCmd(NULL, 0); ++ cmdBufDumpCmdQueue(&prAdapter->rPendingCmdQueue, "waiting response CMD queue"); ++ glDumpConnSysCpuInfo(prAdapter->prGlueInfo); ++ kalSendAeeWarning("[TC4 no resource delay 5s!]", __func__); ++ glDoChipReset(); ++ u4CurrTick = 0; ++ } ++ } ++ return u4Status; ++ ++} /* end of nicTxAcquireResourceAndTFCBs() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will do polling if FW has return the resource. ++* Used when driver start up before enable interrupt. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Resource is available. ++* @retval WLAN_STATUS_FAILURE Resource is not available. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; ++ INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; ++ UINT_32 au4WTSR[2]; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (ucTC >= TC_NUM) ++ return WLAN_STATUS_FAILURE; ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) ++ return WLAN_STATUS_SUCCESS; ++ ++ while (i-- > 0) { ++ HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); ++ ++ if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { ++ u4Status = WLAN_STATUS_FAILURE; ++ break; ++ } else if (nicTxReleaseResource(prAdapter, (PUINT_8) au4WTSR)) { ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) { ++ u4Status = WLAN_STATUS_SUCCESS; ++ break; ++ } ++ kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); ++ ++ } else { ++ kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); ++ } ++ } ++ ++ if (i <= 0 && ucTC == TC4_INDEX) { ++ DBGLOG(TX, ERROR, "polling Tx resource for Tc4 timeout\n"); ++ glDumpConnSysCpuInfo(prAdapter->prGlueInfo); ++ } ++#if DBG ++ { ++ INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i + 1); ++ ++ if (i4Times) { ++ DBGLOG(TX, TRACE, "Polling MCR_WTSR delay %d times, %d msec\n", ++ i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)); ++ } ++ } ++#endif /* DBG */ ++ ++ return u4Status; ++ ++} /* end of nicTxPollingResource() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will release TC Buffer count according to ++* the given TX_STATUS COUNTER after TX Done. ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* \param[in] u4TxStatusCnt Value of TX STATUS ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN unsigned char *aucTxRlsCnt) ++{ ++ PUINT_32 pu4Tmp = (PUINT_32) aucTxRlsCnt; ++ P_TX_CTRL_T prTxCtrl; ++ BOOLEAN bStatus = FALSE; ++ UINT_32 i; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (pu4Tmp[0] | pu4Tmp[1]) { ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ for (i = 0; i < TC_NUM; i++) ++ prTxCtrl->rTc.aucFreeBufferCount[i] += aucTxRlsCnt[i]; ++ for (i = 0; i < TC_NUM; i++) ++ prQM->au4QmTcResourceBackCounter[i] += aucTxRlsCnt[i]; ++ if (aucTxRlsCnt[TC4_INDEX] != 0) ++ wlanTraceReleaseTcRes(prAdapter, aucTxRlsCnt, prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX]); ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++#if 0 ++ for (i = 0; i < TC_NUM; i++) { ++ DBGLOG(TX, TRACE, "aucFreeBufferCount[%d]: %d, aucMaxNumOfBuffer[%d]: %d\n", ++ i, prTxCtrl->rTc.aucFreeBufferCount[i], i, ++ prTxCtrl->rTc.aucMaxNumOfBuffer[i]); ++ } ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[0]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[0]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[1]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[1]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[2]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[2]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[3]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[3]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[4]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[4]); ++ DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[5]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[5]); ++#endif ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX]); ++ ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX]); ++ bStatus = TRUE; ++ } ++ ++ return bStatus; ++} /* end of nicTxReleaseResource() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reset TC Buffer Count to initialized value ++* ++* \param[in] prAdapter Pointer to the Adapter structure. ++* ++* @return WLAN_STATUS_SUCCESS ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ DEBUGFUNC("nicTxResetResource"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; ++ prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Driver maintain a variable that is synchronous with the usage of individual ++* TC Buffer Count. This function will return the value for other component ++* which needs this information for making decisions ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucTC Specify the resource of TC ++* ++* @retval UINT_8 The number of corresponding TC number ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ ASSERT(prTxCtrl); ++ ++ if (ucTC >= TC_NUM) ++ return 0; ++ else ++ return prTxCtrl->rTc.aucFreeBufferCount[ucTC]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief In this function, we'll aggregate frame(PACKET_INFO_T) ++* corresponding to HIF TX port ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoListHead a link list of P_MSDU_INFO_T ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; ++ QUE_T qDataPort0, qDataPort1; ++ WLAN_STATUS status; ++ BOOLEAN pfgIsSecOrMgmt = FALSE; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ prMsduInfo = prMsduInfoListHead; ++ ++ QUEUE_INITIALIZE(&qDataPort0); ++ QUEUE_INITIALIZE(&qDataPort1); ++ ++ /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++#if DBG && 0 ++ LOG_FUNC("nicTxMsduInfoList Acquire TC %d net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prMsduInfo->ucTC, ++ prMsduInfo->ucNetworkType, ++ prMsduInfo->ucMacHeaderLength, ++ prMsduInfo->u2FrameLength, ++ prMsduInfo->ucPacketType, prMsduInfo->fgIs802_1x, prMsduInfo->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prMsduInfo->aucEthDestAddr); ++#endif ++ ++ /* double-check available TX resouce (need to sync with CONNSYS FW) */ ++ /* caller must guarantee that the TX resource is enough in the func; OR assert here */ ++ switch (prMsduInfo->ucTC) { ++ case TC0_INDEX: ++ case TC1_INDEX: ++ case TC2_INDEX: ++ case TC3_INDEX: ++ case TC5_INDEX: /* Broadcast/multicast data packets */ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); ++ status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, FALSE); ++ ASSERT(status == WLAN_STATUS_SUCCESS) ++ ++ break; ++ ++ case TC4_INDEX: /* Command or 802.1x packets */ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); ++ ++ if ((prMsduInfo->fgIs802_1x == TRUE) || ++ (prMsduInfo->fgIs802_11 == TRUE)) ++ pfgIsSecOrMgmt = TRUE; ++ ++ status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, pfgIsSecOrMgmt); ++ ASSERT(status == WLAN_STATUS_SUCCESS) ++ ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++ /* send packets to HIF port0 or port1 here */ ++ if (qDataPort0.u4NumElem > 0) ++ nicTxMsduQueue(prAdapter, 0, &qDataPort0); ++ ++ if (qDataPort1.u4NumElem > 0) ++ nicTxMsduQueue(prAdapter, 1, &qDataPort1); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ ++#if CFG_PRINT_RTP_PROFILE ++PKT_PROFILE_T rPrevRoundLastPkt; ++ ++BOOLEAN ++nicTxLifetimePrintCheckRTP(IN P_MSDU_INFO_T prPrevProfileMsduInfo, ++ IN P_PKT_PROFILE_T prPrevRoundLastPkt, ++ IN P_PKT_PROFILE_T prPktProfile, ++ IN OUT PBOOLEAN pfgGotFirst, IN UINT_32 u4MaxDeltaTime, IN UINT_8 ucSnToBePrinted) ++{ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ ++ if (u4MaxDeltaTime) { ++ /* 4 1. check delta between current round first pkt and prevous round last pkt */ ++ if (!*pfgGotFirst) { ++ *pfgGotFirst = TRUE; ++ ++ if (prPrevRoundLastPkt->fgIsValid) { ++ if (CHK_PROFILES_DELTA(prPktProfile, prPrevRoundLastPkt, u4MaxDeltaTime)) { ++ PRINT_PKT_PROFILE(prPrevRoundLastPkt, "PR"); ++ fgPrintCurPkt = TRUE; ++ } ++ } ++ } ++ /* 4 2. check delta between current pkt and previous pkt */ ++ if (prPrevProfileMsduInfo) { ++ if (CHK_PROFILES_DELTA(prPktProfile, &prPrevProfileMsduInfo->rPktProfile, u4MaxDeltaTime)) { ++ PRINT_PKT_PROFILE(&prPrevProfileMsduInfo->rPktProfile, "P"); ++ fgPrintCurPkt = TRUE; ++ } ++ } ++ /* 4 3. check delta of current pkt lifetime */ ++ if (CHK_PROFILE_DELTA(prPktProfile, u4MaxDeltaTime)) ++ fgPrintCurPkt = TRUE; ++ } ++ /* 4 4. print every X RTP packets */ ++#if CFG_SUPPORT_WFD ++ if ((ucSnToBePrinted != 0) && (prPktProfile->u2RtpSn % ucSnToBePrinted) == 0) ++ fgPrintCurPkt = TRUE; ++#endif ++ ++ return fgPrintCurPkt; ++} ++ ++BOOLEAN ++nicTxLifetimePrintCheckSnOrder(IN P_MSDU_INFO_T prPrevProfileMsduInfo, ++ IN P_PKT_PROFILE_T prPrevRoundLastPkt, ++ IN P_PKT_PROFILE_T prPktProfile, IN OUT PBOOLEAN pfgGotFirst, IN UINT_8 ucLayer) ++{ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ P_PKT_PROFILE_T prTarPktProfile = NULL; ++ UINT_16 u2PredictSn = 0; ++ UINT_16 u2CurrentSn = 0; ++ UINT_8 aucNote[8]; ++ ++ /* 4 1. Get the target packet profile to compare */ ++ ++ /* 4 1.1 check SN between current round first pkt and prevous round last pkt */ ++ if ((!*pfgGotFirst) && (prPrevRoundLastPkt->fgIsValid)) { ++ *pfgGotFirst = TRUE; ++ prTarPktProfile = prPrevRoundLastPkt; ++ kalMemCopy(aucNote, "PR\0", 3); ++ } ++ /* 4 1.2 check SN between current pkt and previous pkt */ ++ else if (prPrevProfileMsduInfo) { ++ prTarPktProfile = &prPrevProfileMsduInfo->rPktProfile; ++ kalMemCopy(aucNote, "P\0", 2); ++ } ++ ++ if (!prTarPktProfile) ++ return FALSE; ++ /* 4 2. Check IP or RTP SN */ ++ switch (ucLayer) { ++ /* Check IP SN */ ++ case 0: ++ u2PredictSn = prTarPktProfile->u2IpSn + 1; ++ u2CurrentSn = prPktProfile->u2IpSn; ++ break; ++ /* Check RTP SN */ ++ case 1: ++ default: ++ u2PredictSn = prTarPktProfile->u2RtpSn + 1; ++ u2CurrentSn = prPktProfile->u2RtpSn; ++ break; ++ ++ } ++ /* 4 */ ++ /* 4 3. Compare SN */ ++ if (u2CurrentSn != u2PredictSn) { ++ PRINT_PKT_PROFILE(prTarPktProfile, aucNote); ++ fgPrintCurPkt = TRUE; ++ } ++ ++ return fgPrintCurPkt; ++} ++#endif ++ ++VOID nicTxReturnMsduInfoProfiling(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; ++ P_PKT_PROFILE_T prPktProfile; ++ UINT_16 u2MagicCode = 0; ++ ++ UINT_8 ucDebugtMode = 0; ++#if CFG_PRINT_RTP_PROFILE ++ P_MSDU_INFO_T prPrevProfileMsduInfo = NULL; ++ P_PKT_PROFILE_T prPrevRoundLastPkt = &rPrevRoundLastPkt; ++ ++ BOOLEAN fgPrintCurPkt = FALSE; ++ BOOLEAN fgGotFirst = FALSE; ++ UINT_8 ucSnToBePrinted = 0; ++ ++ UINT_32 u4MaxDeltaTime = 50; /* in ms */ ++#endif ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ UINT_32 u4PktPrintPeriod = 0; ++#endif ++ ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ u2MagicCode = prWfdCfgSettings->u2WfdMaximumTp; ++ ucDebugtMode = prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode; ++ /* if(prWfdCfgSettings->ucWfdEnable && (prWfdCfgSettings->u4WfdFlag & BIT(0))) { */ ++ /* u2MagicCode = 0xE040; */ ++ /* } */ ++ } ++#endif ++ ++#if CFG_PRINT_RTP_PROFILE ++ if ((u2MagicCode >= 0xF000)) { ++ ucSnToBePrinted = (UINT_8) (u2MagicCode & BITS(0, 7)); ++ u4MaxDeltaTime = (UINT_8) (((u2MagicCode & BITS(8, 11)) >> 8) * 10); ++ } else { ++ ucSnToBePrinted = 0; ++ u4MaxDeltaTime = 0; ++ } ++ ++#endif ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ if ((u2MagicCode >= 0xE000) && (u2MagicCode < 0xF000)) ++ u4PktPrintPeriod = (UINT_32) ((u2MagicCode & BITS(0, 7)) * 32); ++ else ++ u4PktPrintPeriod = 0; ++#endif ++ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ prPktProfile = &prMsduInfo->rPktProfile; ++ ++ if (prPktProfile->fgIsValid) { ++ ++ prPktProfile->rHifTxDoneTimestamp = kalGetTimeTick(); ++ if (ucDebugtMode > 1) { ++ ++#if CFG_PRINT_RTP_PROFILE ++#if CFG_PRINT_RTP_SN_SKIP ++ fgPrintCurPkt = nicTxLifetimePrintCheckSnOrder(prPrevProfileMsduInfo, ++ prPrevRoundLastPkt, ++ prPktProfile, &fgGotFirst, 0); ++#else ++ fgPrintCurPkt = nicTxLifetimePrintCheckRTP(prPrevProfileMsduInfo, ++ prPrevRoundLastPkt, ++ prPktProfile, ++ &fgGotFirst, ++ u4MaxDeltaTime, ucSnToBePrinted); ++#endif ++ ++ /* Print current pkt profile */ ++ if (fgPrintCurPkt && ucDebugtMode > 1) ++ PRINT_PKT_PROFILE(prPktProfile, "C"); ++ ++ prPrevProfileMsduInfo = prMsduInfo; ++ fgPrintCurPkt = FALSE; ++#endif ++ } ++#if CFG_ENABLE_PER_STA_STATISTICS ++ { ++ P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ UINT_32 u4DeltaTime; ++ UINT_32 u4DeltaHifTime; ++#if 0 ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++#endif ++ UINT_8 ucNetIndex; ++ ++ if (prStaRec) { ++ ucNetIndex = prStaRec->ucNetTypeIndex; ++ u4DeltaTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - ++ prPktProfile->rHardXmitArrivalTimestamp); ++ u4DeltaHifTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - ++ prPktProfile->rDequeueTimestamp); ++ prStaRec->u4TotalTxPktsNumber++; ++ ++ prStaRec->u4TotalTxPktsTime += u4DeltaTime; ++ prStaRec->u4TotalTxPktsHifTime += u4DeltaHifTime; ++ ++ if (u4DeltaTime > prStaRec->u4MaxTxPktsTime) ++ prStaRec->u4MaxTxPktsTime = u4DeltaTime; ++ ++ if (u4DeltaHifTime > prStaRec->u4MaxTxPktsHifTime) ++ prStaRec->u4MaxTxPktsHifTime = u4DeltaHifTime; ++ ++ ++ if (u4DeltaTime >= NIC_TX_TIME_THRESHOLD) ++ prStaRec->u4ThresholdCounter++; ++#if 0 ++ if (u4PktPrintPeriod && (prStaRec->u4TotalTxPktsNumber >= u4PktPrintPeriod)) { ++ ++ DBGLOG(TX, TRACE, "[%u]N[%4u]A[%5u]M[%4u]T[%4u]E[%4u]\n", ++ prStaRec->ucIndex, ++ prStaRec->u4TotalTxPktsNumber, ++ prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber, ++ prStaRec->u4MaxTxPktsTime, ++ prStaRec->u4ThresholdCounter, ++ prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX]); ++ ++ prStaRec->u4TotalTxPktsNumber = 0; ++ prStaRec->u4TotalTxPktsTime = 0; ++ prStaRec->u4MaxTxPktsTime = 0; ++ prStaRec->u4ThresholdCounter = 0; ++ prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX] = 0; ++ } ++#endif ++ } ++ ++ } ++#endif ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ }; ++ ++#if CFG_PRINT_RTP_PROFILE ++ /* 4 4. record the lifetime of current round last pkt */ ++ if (prPrevProfileMsduInfo) { ++ prPktProfile = &prPrevProfileMsduInfo->rPktProfile; ++ prPrevRoundLastPkt->u2IpSn = prPktProfile->u2IpSn; ++ prPrevRoundLastPkt->u2RtpSn = prPktProfile->u2RtpSn; ++ prPrevRoundLastPkt->rHardXmitArrivalTimestamp = prPktProfile->rHardXmitArrivalTimestamp; ++ prPrevRoundLastPkt->rEnqueueTimestamp = prPktProfile->rEnqueueTimestamp; ++ prPrevRoundLastPkt->rDequeueTimestamp = prPktProfile->rDequeueTimestamp; ++ prPrevRoundLastPkt->rHifTxDoneTimestamp = prPktProfile->rHifTxDoneTimestamp; ++ prPrevRoundLastPkt->ucTcxFreeCount = prPktProfile->ucTcxFreeCount; ++ prPrevRoundLastPkt->fgIsPrinted = prPktProfile->fgIsPrinted; ++ prPrevRoundLastPkt->fgIsValid = TRUE; ++ } ++#endif ++ ++ nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); ++ ++} ++ ++VOID nicTxLifetimeRecordEn(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) ++{ ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* Enable packet lifetime profiling */ ++ prPktProfile->fgIsValid = TRUE; ++ ++ /* Packet arrival time at kernel Hard Xmit */ ++ prPktProfile->rHardXmitArrivalTimestamp = GLUE_GET_PKT_ARRIVAL_TIME(prPacket); ++ ++ /* Packet enqueue time */ ++ prPktProfile->rEnqueueTimestamp = (OS_SYSTIME) kalGetTimeTick(); ++ ++} ++ ++#if CFG_PRINT_RTP_PROFILE ++/* ++ in: ++ data RTP packet pointer ++ size RTP size ++ return ++ 0:audio 1: video, -1:none ++*/ ++UINT8 checkRtpAV(PUINT_8 data, UINT_32 size) ++{ ++ PUINT_8 buf = data + 12; ++ ++ while (buf + 188 <= data + size) { ++ int pid = ((buf[1] << 8) & 0x1F00) | (buf[2] & 0xFF); ++ ++ if (pid == 0 || pid == 0x100 || pid == 0x1000) ++ buf += 188; ++ else if (pid == 0x1100) ++ return 0; ++ else if (pid == 0x1011) ++ return 1; ++ } ++ return -1; ++} ++ ++VOID ++nicTxLifetimeCheckRTP(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_NATIVE_PACKET prPacket, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) ++{ ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ UINT_16 u2EtherTypeLen; ++ PUINT_8 aucLookAheadBuf = NULL; ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* UINT_8 ucRtpHdrOffset = 28; */ ++ UINT_8 ucRtpSnOffset = 30; ++ /* UINT_32 u4RtpSrcPort = 15550; */ ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SUPPORT_WFD ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_WFD_DBG_CFG_SETTINGS_T prWfdDbgSettings = (P_WFD_DBG_CFG_SETTINGS_T) NULL; ++ ++ BOOLEAN fgEnProfiling = FALSE; ++ ++ if (prAdapter->fgIsP2PRegistered) { ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ prWfdDbgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting; ++#if CFG_PRINT_RTP_SN_SKIP ++ if (ucNetworkType == NETWORK_TYPE_P2P_INDEX) { ++ fgEnProfiling = TRUE; ++ } else ++#endif ++ if (((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000) || ++ (prWfdDbgSettings->ucWfdDebugMode > 0)) && (ucNetworkType == NETWORK_TYPE_P2P_INDEX)) { ++ fgEnProfiling = TRUE; ++ } ++ } ++ ++ if (fgEnProfiling == FALSE) { ++ /* prPktProfile->fgIsValid = FALSE; */ ++ return; ++ } ++#endif ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ /* prPktProfile->fgIsValid = FALSE; */ ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { ++ PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_16 u2tmpIpSN = 0; ++ UINT_8 ucIpVersion; ++ ++ ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if (ucIpVersion == IPVERSION) { ++ if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { ++ ++ /* if(checkRtpAV(&pucIpHdr[ucRtpHdrOffset], ++ (u4PacketLen - ETH_HLEN - ucRtpHdrOffset)) == 0) { */ ++ ++ if (prPktProfile->fgIsValid == FALSE) ++ nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); ++ ++ prPktProfile->fgIsPrinted = FALSE; ++ ++ prPktProfile->ucTcxFreeCount = prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX]; ++ ++ /* RTP SN */ ++ prPktProfile->u2RtpSn = pucIpHdr[ucRtpSnOffset] << 8 | pucIpHdr[ucRtpSnOffset + 1]; ++ ++ /* IP SN */ ++ prPktProfile->u2IpSn = pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET] << 8 | ++ pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET + 1]; ++ u2tmpIpSN = prPktProfile->u2IpSn; ++ if (prWfdDbgSettings->ucWfdDebugMode == 1) { ++ if ((u2tmpIpSN & (prWfdDbgSettings->u2WfdSNShowPeiroid)) == 0) ++ DBGLOG(TX, TRACE, ++ "RtpSn=%d IPId=%d j=%lu\n", prPktProfile->u2RtpSn, ++ prPktProfile->u2IpSn, jiffies); ++ } ++ /* } */ ++ } ++ } ++ } ++ ++} ++#endif ++#if CFG_ENABLE_PER_STA_STATISTICS ++VOID ++nicTxLifetimeCheckByAC(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket, IN UINT_8 ucPriorityParam) ++{ ++ switch (ucPriorityParam) { ++ /* BK */ ++ /* case 1: */ ++ /* case 2: */ ++ ++ /* BE */ ++ /* case 0: */ ++ /* case 3: */ ++ ++ /* VI */ ++ case 4: ++ case 5: ++ ++ /* VO */ ++ case 6: ++ case 7: ++ nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); ++ break; ++ default: ++ break; ++ } ++} ++ ++#endif ++ ++VOID ++nicTxLifetimeCheck(IN P_ADAPTER_T prAdapter, ++ IN P_MSDU_INFO_T prMsduInfo, ++ IN P_NATIVE_PACKET prPacket, ++ IN UINT_8 ucPriorityParam, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) ++{ ++ P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; ++ ++ /* Reset packet profile */ ++ prPktProfile->fgIsValid = FALSE; ++ ++#if CFG_ENABLE_PER_STA_STATISTICS ++ nicTxLifetimeCheckByAC(prAdapter, prMsduInfo, prPacket, ucPriorityParam); ++#endif ++ ++#if CFG_PRINT_RTP_PROFILE ++ nicTxLifetimeCheckRTP(prAdapter, prMsduInfo, prPacket, u4PacketLen, ucNetworkType); ++#endif ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param ucPortIdx Port Number ++* @param prQue a link list of P_MSDU_INFO_T ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue) ++{ ++ P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; ++ HIF_TX_HEADER_T rHwTxHeader; ++ P_NATIVE_PACKET prNativePacket; ++ UINT_16 u2OverallBufferLength; ++ UINT_8 ucEtherTypeOffsetInWord; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 u4TxHdrSize; ++ UINT_32 u4ValidBufSize; ++ UINT_32 u4TotalLength; ++ P_TX_CTRL_T prTxCtrl; ++ QUE_T rFreeQueue; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ UINT_8 ucChksumFlag; ++#endif ++ ++ ASSERT(prAdapter); ++ ASSERT(ucPortIdx < 2); ++ ASSERT(prQue); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ u4ValidBufSize = prAdapter->u4CoalescingBufCachedSize; ++ ++#if CFG_HIF_STATISTICS ++ prTxCtrl->u4TotalTxAccessNum++; ++ prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; ++#endif ++ ++ QUEUE_INITIALIZE(&rFreeQueue); ++ ++ if (prQue->u4NumElem > 0) { ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_HEAD(prQue); ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ u4TotalLength = 0; ++ ++ while (prMsduInfo) { ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(TX, TRACE, " %d\n", u2Identifier); ++ } ++ } ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetProfilingFinish(prAdapter, prMsduInfo); ++#endif ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ prNativePacket = prMsduInfo->prPacket; ++ ++ ASSERT(prNativePacket); ++ ++ u4TxHdrSize = TX_HDR_SIZE; ++ ++ u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & ++ (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ /* init TX header */ ++ rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; ++ rHwTxHeader.u2TxByteCount_UserPriority |= ++ ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); ++ ++ if (prMsduInfo->fgIs802_11) { ++ ucEtherTypeOffsetInWord = ++ (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; ++ } else { ++ ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; ++ } ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; ++ rHwTxHeader.ucResource_PktType_CSflags |= ++ (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & ++ (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ if (prAdapter->u4CSUMFlags & ++ (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP)) { ++ kalQueryTxChksumOffloadParam(prNativePacket, &ucChksumFlag); ++ ++ if (ucChksumFlag & TX_CS_IP_GEN) ++ rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_IP_CSUM; ++ ++ if (ucChksumFlag & TX_CS_TCP_UDP_GEN) ++ rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_TCP_CSUM; ++ } ++ } ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; ++ rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = ++ (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << ++ HIF_TX_HDR_PS_SESSION_ID_OFFSET) ++ | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); ++ ++ rHwTxHeader.ucWlanHeaderLength = ++ (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) ++ | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & ++ HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & ++ HIF_TX_HDR_FLAG_1X_FRAME_MASK) ++ | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & ++ HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); ++ ++ rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; ++ ++ if (prMsduInfo->pfTxDoneHandler) { ++ rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; ++ } else { ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = 0; ++ } ++ ++ if (prMsduInfo->fgNeedTxDoneStatus == TRUE) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_NEED_TX_DONE_STATUS; ++ ++ if (prMsduInfo->fgIsBIP) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; ++ ++ if (prMsduInfo->fgIsBasicRate) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ if (prMsduInfo->rPktProfile.fgIsValid) ++ prMsduInfo->rPktProfile.rDequeueTimestamp = kalGetTimeTick(); ++#endif ++ ++ /* record the queue time in driver */ ++ STATS_TX_TIME_TO_HIF(prMsduInfo, &rHwTxHeader); ++ ++#if CFG_SDIO_TX_AGG ++ /* attach to coalescing buffer */ ++ kalMemCopy(pucOutputBuf + u4TotalLength, &rHwTxHeader, u4TxHdrSize); ++ u4TotalLength += u4TxHdrSize; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TotalLength); ++ else if (prMsduInfo->eSrc == TX_PACKET_MGMT) ++ kalMemCopy(pucOutputBuf + u4TotalLength, prNativePacket, prMsduInfo->u2FrameLength); ++ else ++ ASSERT(0); ++ ++ u4TotalLength += ALIGN_4(prMsduInfo->u2FrameLength); ++ ++#else ++ kalMemCopy(pucOutputBuf, &rHwTxHeader, u4TxHdrSize); ++ ++ /* Copy Frame Body */ ++ if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TxHdrSize); ++ else if (prMsduInfo->eSrc == TX_PACKET_MGMT) ++ kalMemCopy(pucOutputBuf + u4TxHdrSize, prNativePacket, prMsduInfo->u2FrameLength); ++ else ++ ASSERT(0); ++ ++ ASSERT(u2OverallBufferLength <= u4ValidBufSize); ++ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); ++ ++ /* send immediately */ ++#endif ++ prNextMsduInfo = (P_MSDU_INFO_T) ++ QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry); ++ ++ if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ if (prMsduInfo->pfTxDoneHandler == NULL) { ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ KAL_SPIN_LOCK_DECLARATION(); ++ DBGLOG(TX, TRACE, "Wait TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ } ++ } else { ++ /* only free MSDU when it is not a MGMT frame */ ++ QUEUE_INSERT_TAIL(&rFreeQueue, (P_QUE_ENTRY_T) prMsduInfo); ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS) ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_SUCCESS); ++ else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) ++ GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++#if CFG_SDIO_TX_AGG ++ ASSERT(u4TotalLength <= u4ValidBufSize); ++ ++#if CFG_DBG_GPIO_PINS ++ { ++ /* Start port write */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_LOW); ++ kalUdelay(1); ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_HIGH); ++ } ++#endif ++ ++ /* send coalescing buffer */ ++ HAL_WRITE_TX_PORT(prAdapter, ucPortIdx, u4TotalLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); ++#endif ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++#if CFG_SUPPORT_WFD && CFG_PRINT_RTP_PROFILE && !CFG_ENABLE_PER_STA_STATISTICS ++ do { ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ ++ prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; ++ ++ if ((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000)) { ++ /* Enable profiling */ ++ nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++ } else { ++ /* Skip profiling */ ++ nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++ } ++ } while (FALSE); ++#else ++ nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++#endif ++#else ++ /* return */ ++ nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); ++#endif ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prPacketInfo Pointer of CMD_INFO_T ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) ++{ ++ P_WIFI_CMD_T prWifiCmd; ++ UINT_16 u2OverallBufferLength; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_8 ucPortIdx; ++ HIF_TX_HEADER_T rHwTxHeader; ++ P_NATIVE_PACKET prNativePacket; ++ UINT_8 ucEtherTypeOffsetInWord; ++ P_MSDU_INFO_T prMsduInfo; ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ ++ /* <1> Assign Data Port */ ++ if (ucTC != TC4_INDEX) { ++ ucPortIdx = 0; ++ } else { ++ /* Broadcast/multicast data frames, 1x frames, command packets, MMPDU */ ++ ucPortIdx = 1; ++ } ++ wlanTraceTxCmd(prCmdInfo); ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ /* <2> Compose HIF_TX_HEADER */ ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ prNativePacket = prCmdInfo->prPacket; ++ ++ ASSERT(prNativePacket); ++ ++ u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) ++ & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ rHwTxHeader.u2TxByteCount_UserPriority = ((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) ++ & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET); ++ ++ rHwTxHeader.ucStaRecIdx = prCmdInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = HIF_TX_HDR_BURST_END_MASK; ++ ++ rHwTxHeader.ucWlanHeaderLength = (ETH_HLEN & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = ++ (((UINT_8) (prCmdInfo->eNetworkType) << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & ++ HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((1 << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK); ++ ++ rHwTxHeader.u2SeqNo = 0; ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_TX_DONE_STATUS; ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE /* | HIF_TX_HDR_RTS */; ++ ++ /* <2.3> Copy HIF TX HEADER */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); ++ ++ /* <3> Copy Frame Body Copy */ ++ kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + TX_HDR_SIZE); ++ } else if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; ++ ++ ASSERT(prMsduInfo->fgIs802_11 == TRUE); ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ /* <2> Compose HIF_TX_HEADER */ ++ kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); ++ ++ u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & ++ (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; ++ rHwTxHeader.u2TxByteCount_UserPriority |= ++ ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); ++ ++ ucEtherTypeOffsetInWord = (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; ++ ++ rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; ++ ++ rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; ++ rHwTxHeader.ucResource_PktType_CSflags |= ++ (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & ++ (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++ rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; ++ rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; ++ rHwTxHeader.ucForwardingType_SessionID_Reserved = ++ (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET) ++ | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); ++ ++ rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); ++ rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) ++ | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) ++ | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK) ++ | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & ++ HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); ++ ++ rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; ++ ++ if (prMsduInfo->pfTxDoneHandler) { ++ rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; ++ rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; ++ } else { ++ rHwTxHeader.ucPacketSeqNo = 0; ++ rHwTxHeader.ucAck_BIP_BasicRate = 0; ++ } ++ ++ if (prMsduInfo->fgIsBIP) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; ++ ++ if (prMsduInfo->fgIsBasicRate) ++ rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; ++ /* <2.3> Copy HIF TX HEADER */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); ++ ++ /* <3> Copy Frame Body */ ++ kalMemCopy(pucOutputBuf + TX_HDR_SIZE, prMsduInfo->prPacket, prMsduInfo->u2FrameLength); ++ ++ /* <4> Management Frame Post-Processing */ ++ GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ if (prMsduInfo->pfTxDoneHandler == NULL) { ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ ++ DBGLOG(TX, TRACE, "Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ } ++ } else { ++ prWifiCmd = (P_WIFI_CMD_T) prCmdInfo->pucInfoBuffer; ++ ++ /* <2> Compose the Header of Transmit Data Structure for CMD Packet */ ++ u2OverallBufferLength = ++ TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ prWifiCmd->u2TxByteCount_UserPriority = u2OverallBufferLength; ++ prWifiCmd->ucEtherTypeOffset = 0; ++ prWifiCmd->ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET) ++ | (UINT_8) ((HIF_TX_PKT_TYPE_CMD << HIF_TX_HDR_PACKET_TYPE_OFFSET) & (HIF_TX_HDR_PACKET_TYPE_MASK)); ++ ++ /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); ++ ++ ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); ++ ++ if ((prCmdInfo->ucCID == CMD_ID_SCAN_REQ) || ++ (prCmdInfo->ucCID == CMD_ID_SCAN_CANCEL) || ++ (prCmdInfo->ucCID == CMD_ID_SCAN_REQ_V2)) ++ DBGLOG(TX, INFO, "ucCmdSeqNum =%d, ucCID =%d\n", prCmdInfo->ucCmdSeqNum, prCmdInfo->ucCID); ++ } ++ ++ /* <4> Write frame to data port */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, ++ (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} /* end of nicTxCmd() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function will clean up all the pending frames in internal SW Queues ++* by return the pending TX packet to the system. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxRelease(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ nicTxFlush(prAdapter); ++ ++ /* free MSDU_INFO_T from rTxMgmtMsduInfoList */ ++ do { ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); ++ ++ if (prMsduInfo) { ++ /* the packet must be mgmt frame with tx done callback */ ++ ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); ++ ++ /* invoke done handler */ ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_LIFE_TIMEOUT); ++ ++ cnmMgtPktFree(prAdapter, prMsduInfo); ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++} /* end of nicTxRelease() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Process the TX Done interrupt and pull in more pending frames in SW ++* Queues for transmission. ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++#if CFG_SDIO_INTR_ENHANCE ++ P_SDIO_CTRL_T prSDIOCtrl; ++#else ++ UINT_32 au4TxCount[2]; ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ prGlueInfo->IsrTxCnt++; ++ ++ /* Get the TX STATUS */ ++#if CFG_SDIO_INTR_ENHANCE ++ ++ prSDIOCtrl = prAdapter->prSDIOCtrl; ++#if DBG ++ /* dumpMemory8((PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T)); */ ++#endif ++ ++ nicTxReleaseResource(prAdapter, (PUINT_8) &prSDIOCtrl->rTxInfo); ++ kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); ++ ++#else ++ ++ HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); ++ HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); ++ DBGLOG(EMU, TRACE, "MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1]); ++ ++ nicTxReleaseResource(prAdapter, (PUINT_8) au4TxCount); ++ ++#endif /* CFG_SDIO_INTR_ENHANCE */ ++ ++ nicTxAdjustTcq(prAdapter); ++ ++ /* Indicate Service Thread */ ++ if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ ++} /* end of nicProcessTxInterrupt() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function frees packet of P_MSDU_INFO_T linked-list ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoList a link list of P_MSDU_INFO_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_NATIVE_PACKET prNativePacket; ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfoListHead); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ while (prMsduInfo) { ++ prNativePacket = prMsduInfo->prPacket; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_OS) { ++ kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_FAILURE); ++ } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ P_MSDU_INFO_T prTempMsduInfo = prMsduInfo; ++ ++ if (prMsduInfo->pfTxDoneHandler) ++ prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ cnmMgtPktFree(prAdapter, prTempMsduInfo); ++ continue; ++ } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); ++ } ++ ++ prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfoList a link list of P_MSDU_INFO_T ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ ++ switch (prMsduInfo->eSrc) { ++ case TX_PACKET_FORWARDING: ++ wlanReturnPacket(prAdapter, prMsduInfo->prPacket); ++ break; ++ case TX_PACKET_OS: ++ case TX_PACKET_OS_OID: ++ case TX_PACKET_MGMT: ++ default: ++ break; ++ } ++ ++ /* Reset MSDU_INFO fields */ ++ kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); ++ prMsduInfo = prNextMsduInfo; ++ }; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function fills packet information to P_MSDU_INFO_T ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prMsduInfo P_MSDU_INFO_T ++* @param prPacket P_NATIVE_PACKET ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_8 ucPriorityParam; ++ UINT_8 ucMacHeaderLen; ++ UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; ++ BOOLEAN fgIs1x = FALSE; ++ BOOLEAN fgIsPAL = FALSE; ++ UINT_32 u4PacketLen; ++ ULONG u4SysTime; ++ UINT_8 ucNetworkType; ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ ++ ASSERT(prAdapter); ++ ++ prGlueInfo = prAdapter->prGlueInfo; ++ ASSERT(prGlueInfo); ++ ++ if (kalQoSFrameClassifierAndPacketInfo(prGlueInfo, ++ prPacket, ++ &ucPriorityParam, ++ &u4PacketLen, ++ aucEthDestAddr, ++ &fgIs1x, &fgIsPAL, &ucNetworkType, ++ NULL) == FALSE) { ++ return FALSE; ++ } ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ nicTxLifetimeCheck(prAdapter, prMsduInfo, prPacket, ucPriorityParam, u4PacketLen, ucNetworkType); ++#endif ++ ++ /* Save the value of Priority Parameter */ ++ GLUE_SET_PKT_TID(prPacket, ucPriorityParam); ++ ++ if (fgIs1x) ++ GLUE_SET_PKT_FLAG_1X(prPacket); ++ ++ if (fgIsPAL) ++ GLUE_SET_PKT_FLAG_PAL(prPacket); ++ ++ ucMacHeaderLen = ETH_HLEN; ++ ++ /* Save the value of Header Length */ ++ GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen); ++ ++ /* Save the value of Frame Length */ ++ GLUE_SET_PKT_FRAME_LEN(prPacket, (UINT_16) u4PacketLen); ++ ++ /* Save the value of Arrival Time */ ++ u4SysTime = (OS_SYSTIME) kalGetTimeTick(); ++ GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); ++ ++ prMsduInfo->prPacket = prPacket; ++ prMsduInfo->fgIs802_1x = fgIs1x; ++ prMsduInfo->fgIs802_11 = FALSE; ++ prMsduInfo->ucNetworkType = ucNetworkType; ++ prMsduInfo->ucUserPriority = ucPriorityParam; ++ prMsduInfo->ucMacHeaderLength = ucMacHeaderLen; ++ prMsduInfo->u2FrameLength = (UINT_16) u4PacketLen; ++ COPY_MAC_ADDR(prMsduInfo->aucEthDestAddr, aucEthDestAddr); ++ ++ if (prSkb->len > ETH_HLEN) ++ STATS_TX_PKT_CALLBACK(prSkb->data, prMsduInfo); ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function update TCQ values by passing current status to txAdjustTcQuotas ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Updated successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4Num; ++ TX_TCQ_ADJUST_T rTcqAdjust; ++ P_TX_CTRL_T prTxCtrl; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ for (u4Num = 0; u4Num < TC_NUM; u4Num++) { ++ prTxCtrl->rTc.aucFreeBufferCount[u4Num] += rTcqAdjust.acVariation[u4Num]; ++ prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] += rTcqAdjust.acVariation[u4Num]; ++ } ++ ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief this function flushes all packets queued in STA/AC queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Flushed successfully ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter) ++{ ++ P_MSDU_INFO_T prMsduInfo; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ++ /* ask Per STA/AC queue to be fllushed and return all queued packets */ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prMsduInfo = qmFlushTxQueues(prAdapter); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ if (prMsduInfo != NULL) { ++ nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); ++ nicTxReturnMsduInfo(prAdapter, prMsduInfo); ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. ++* However this function is used for INIT_CMD. ++* ++* In order to avoid further maintenance issues, these 2 functions are separated ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prPacketInfo Pointer of CMD_INFO_T ++* @param ucTC Specify the resource of TC ++* ++* @retval WLAN_STATUS_SUCCESS Bus access ok. ++* @retval WLAN_STATUS_FAILURE Bus access fail. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) ++{ ++ P_INIT_HIF_TX_HEADER_T prInitTxHeader; ++ UINT_16 u2OverallBufferLength; ++ PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ ++ UINT_32 ucPortIdx; ++ P_TX_CTRL_T prTxCtrl; ++ ++ ASSERT(prAdapter); ++ ASSERT(prCmdInfo); ++ ASSERT(ucTC == TC0_INDEX); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; ++ prInitTxHeader = (P_INIT_HIF_TX_HEADER_T) prCmdInfo->pucInfoBuffer; ++ ++ /* <1> Compose the Header of Transmit Data Structure for CMD Packet */ ++ u2OverallBufferLength = ++ TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); ++ ++ prInitTxHeader->u2TxByteCount = u2OverallBufferLength; ++ prInitTxHeader->ucEtherTypeOffset = 0; ++ prInitTxHeader->ucCSflags = 0; ++ ++ /* <2> Assign Data Port */ ++ if (ucTC != TC4_INDEX) { ++ ucPortIdx = 0; ++ } else { /* Broadcast/multicast data packets */ ++ ucPortIdx = 1; ++ } ++ ++ /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ ++ kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); ++ ++ ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); ++ ++ /* <4> Write frame to data port */ ++ HAL_WRITE_TX_PORT(prAdapter, ++ ucPortIdx, ++ (UINT_32) u2OverallBufferLength, ++ (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief In this function, we'll reset TX resource counter to initial value used ++* in F/W download state ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ ++ DEBUGFUNC("nicTxInitResetResource"); ++ ++ ASSERT(prAdapter); ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; ++ prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; ++ prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; ++ prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; ++ prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; ++ prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; ++ ++ prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; ++ prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; ++ ++ return WLAN_STATUS_SUCCESS; ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function enqueues MSDU_INFO_T into queue management, ++* or command queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* prMsduInfo Pointer to MSDU ++* ++* @retval WLAN_STATUS_SUCCESS Reset is done successfully. ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_TX_CTRL_T prTxCtrl; ++ P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; ++ QUE_T qDataPort0, qDataPort1; ++ P_CMD_INFO_T prCmdInfo; ++ WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; ++ ++ KAL_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prAdapter); ++ ASSERT(prMsduInfo); ++ ++ prTxCtrl = &prAdapter->rTxCtrl; ++ ASSERT(prTxCtrl); ++ ++ QUEUE_INITIALIZE(&qDataPort0); ++ QUEUE_INITIALIZE(&qDataPort1); ++ ++ /* check how many management frame are being queued */ ++ while (prMsduInfo) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); ++ ++ QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; ++ ++ if (prMsduInfo->eSrc == TX_PACKET_MGMT) { ++ /* MMPDU: force stick to TC4 */ ++ prMsduInfo->ucTC = TC4_INDEX; ++ ++ QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); ++ } else { ++ QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++ prMsduInfo = prNextMsduInfo; ++ } ++ ++ if (qDataPort0.u4NumElem) { ++ /* send to QM: queue the packet to different TX queue by policy */ ++ KAL_SPIN_LOCK_DECLARATION(); ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort0)); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); ++ ++ /* post-process for "dropped" packets */ ++ if (prRetMsduInfo != NULL) { /* unable to enqueue */ ++ nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); ++ nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); ++ } ++ } ++ ++ if (qDataPort1.u4NumElem) { ++ prMsduInfoHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort1); ++ ++ if (qDataPort1.u4NumElem > nicTxGetFreeCmdCount(prAdapter)) { ++ /* not enough descriptors for sending */ ++ u4Status = WLAN_STATUS_FAILURE; ++ ++ /* free all MSDUs */ ++ while (prMsduInfoHead) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); ++ ++ if (prMsduInfoHead->pfTxDoneHandler != NULL) { ++ prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, ++ TX_RESULT_DROPPED_IN_DRIVER); ++ } ++ ++ cnmMgtPktFree(prAdapter, prMsduInfoHead); ++ ++ prMsduInfoHead = prNextMsduInfo; ++ } ++ } else { ++ /* send to command queue */ ++ while (prMsduInfoHead) { ++ prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); ++ ++ KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); ++ KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); ++ ++ if (prCmdInfo) { ++ GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); ++ ++ kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); ++ ++ prCmdInfo->eCmdType = COMMAND_TYPE_MANAGEMENT_FRAME; ++ prCmdInfo->u2InfoBufLen = prMsduInfoHead->u2FrameLength; ++ prCmdInfo->pucInfoBuffer = NULL; ++ prCmdInfo->prPacket = (P_NATIVE_PACKET) prMsduInfoHead; ++ prCmdInfo->ucStaRecIndex = prMsduInfoHead->ucStaRecIndex; ++ prCmdInfo->eNetworkType = prMsduInfoHead->ucNetworkType; ++ prCmdInfo->pfCmdDoneHandler = NULL; ++ prCmdInfo->pfCmdTimeoutHandler = NULL; ++ prCmdInfo->fgIsOid = FALSE; ++ prCmdInfo->fgSetQuery = TRUE; ++ prCmdInfo->fgNeedResp = FALSE; ++ ++ kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); ++ } else { ++ /* Cmd free count is larger than expected, but allocation fail. */ ++ ASSERT(0); ++ ++ u4Status = WLAN_STATUS_FAILURE; ++ cnmMgtPktFree(prAdapter, prMsduInfoHead); ++ } ++ ++ prMsduInfoHead = prNextMsduInfo; ++ } ++ } ++ } ++ ++ /* indicate service thread for sending */ ++ if (prTxCtrl->i4TxMgmtPendingNum > 0 || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) ++ kalSetEvent(prAdapter->prGlueInfo); ++ ++ return u4Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief this function returns available count in command queue ++* ++* @param prAdapter Pointer to the Adapter structure. ++* ++* @retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter) ++{ ++ ASSERT(prAdapter); ++ ++ return prAdapter->rFreeCmdList.u4NumElem; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c +new file mode 100644 +index 000000000000..38e4569bc04f +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c +@@ -0,0 +1,192 @@ ++/* ++** Id: @(#) p2p_nic.c@@ ++*/ ++ ++/*! \file p2p_nic.c ++ \brief Wi-Fi Direct Functions that provide operation in NIC's (Network Interface Card) point of view. ++ ++ This file includes functions which unite multiple hal(Hardware) operations ++ and also take the responsibility of Software Resource Management in order ++ to keep the synchronization with Hardware Manipulation. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief When Probe Rsp & Beacon frame is received and decide a P2P device, ++* this function will be invoked to buffer scan result ++* ++* @param prAdapter Pointer to the Adapter structure. ++* @param prEventScanResult Pointer of EVENT_SCAN_RESULT_T. ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, ++ IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength) ++{ ++ P_P2P_INFO_T prP2pInfo = (P_P2P_INFO_T) NULL; ++ P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; ++ UINT_32 u4Idx = 0; ++ BOOLEAN bUpdate = FALSE; ++ ++ PUINT_8 pucIeBuf = (PUINT_8) NULL; ++ UINT_16 u2IELength = 0; ++ UINT_8 zeroMac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; ++ ++ ASSERT(prAdapter); ++ ++ prP2pInfo = prAdapter->prP2pInfo; ++ ++ for (u4Idx = 0; u4Idx < prP2pInfo->u4DeviceNum; u4Idx++) { ++ prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; ++ ++ if (EQUAL_MAC_ADDR(prTargetResult->aucDeviceAddr, prP2pResult->aucDeviceAddr)) { ++ bUpdate = TRUE; ++ ++ /* Backup OLD buffer result. */ ++ pucIeBuf = prTargetResult->pucIeBuf; ++ u2IELength = prTargetResult->u2IELength; ++ ++ /* Update Device Info. */ ++ /* zero */ ++ kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* then buffer */ ++ kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* See if new IE length is longer or not. */ ++ if ((u2RxIELength > u2IELength) && (u2IELength != 0)) { ++ /* Buffer is not enough. */ ++ u2RxIELength = u2IELength; ++ } else if ((u2IELength == 0) && (u2RxIELength != 0)) { ++ /* RX new IE buf. */ ++ ASSERT(pucIeBuf == NULL); ++ pucIeBuf = prP2pInfo->pucCurrIePtr; ++ ++ if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > ++ (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { ++ /* Common Buffer is no enough. */ ++ u2RxIELength = ++ (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - ++ (ULONG) prP2pInfo->pucCurrIePtr); ++ } ++ ++ /* Step to next buffer address. */ ++ prP2pInfo->pucCurrIePtr = ++ (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength); ++ } ++ ++ /* Restore buffer pointer. */ ++ prTargetResult->pucIeBuf = pucIeBuf; ++ ++ if (pucRxIEBuf) { ++ /* If new received IE is available. ++ * Replace the old one & update new IE length. ++ */ ++ kalMemCopy(pucIeBuf, pucRxIEBuf, u2RxIELength); ++ prTargetResult->u2IELength = u2RxIELength; ++ } else { ++ /* There is no new IE information, keep the old one. */ ++ prTargetResult->u2IELength = u2IELength; ++ } ++ } ++ } ++ ++ if (!bUpdate) { ++ /* We would flush the whole scan result after each scan request is issued. ++ * If P2P device is too many, it may over the scan list. ++ */ ++ if ((u4Idx < CFG_MAX_NUM_BSS_LIST) && (UNEQUAL_MAC_ADDR(zeroMac, prP2pResult->aucDeviceAddr))) { ++ /* whsu:XXX */ ++ prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; ++ ++ /* zero */ ++ kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* then buffer */ ++ kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); ++ ++ /* printk("DVC FND %d %pM, %pM\n", ++ prP2pInfo->u4DeviceNum, ++ prP2pResult->aucDeviceAddr, ++ prTargetResult->aucDeviceAddr); */ ++ ++ if (u2RxIELength) { ++ prTargetResult->pucIeBuf = prP2pInfo->pucCurrIePtr; ++ ++ if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > ++ (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { ++ /* Common Buffer is no enough. */ ++ u2IELength = ++ (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - ++ (ULONG) prP2pInfo->pucCurrIePtr); ++ } else { ++ u2IELength = u2RxIELength; ++ } ++ ++ prP2pInfo->pucCurrIePtr = ++ (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2IELength); ++ ++ kalMemCopy((PVOID) prTargetResult->pucIeBuf, (PVOID) pucRxIEBuf, (UINT_32) u2IELength); ++ prTargetResult->u2IELength = u2IELength; ++ } else { ++ prTargetResult->pucIeBuf = NULL; ++ prTargetResult->u2IELength = 0; ++ } ++ ++ prP2pInfo->u4DeviceNum++; ++ ++ } else { ++ /* TODO: Fixme to replace an old one. (?) */ ++ ASSERT(FALSE); ++ } ++ } ++} /* nicRxAddP2pDevice */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +new file mode 100644 +index 000000000000..dd00859d4608 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +@@ -0,0 +1,5038 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 ++*/ ++ ++/*! \file "que_mgt.c" ++ \brief TX/RX queues management ++ ++ The main tasks of queue management include TC-based HIF TX flow control, ++ adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save ++ forwarding control, RX packet reordering, and RX BA agreement management. ++*/ ++ ++/* ++** Log: que_mgt.c ++** ++** 04 11 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Drop the probe response packet when absent. ++** ++** 04 09 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Fix CMD buffer short issue. ++** ++** 04 09 2013 yuche.tsai ++** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. ++** Fix CMD buffer short issue. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 02 23 2012 eddie.chen ++ * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule ++ * Change the enqueue policy when ACM = 1. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Code refine, remove one #if 0 code. ++ * ++ * 11 19 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog for tx ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 18 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Fix xlog format to hex format ++ * ++ * 11 17 2011 tsaiyuan.hsu ++ * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. ++ * avoid deactivating staRec when changing state from 3 to 3. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug msg for xlog. ++ * ++ * 11 11 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters of bb and ar for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Use short name for xlog. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 10 2011 chinglan.wang ++ * NULL ++ * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP. ++ * ++ * 11 09 2011 chinglan.wang ++ * NULL ++ * [WiFi direct]Can't make P2P connect via PBC. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. ++ * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to ++ * the AP.. ++ * ++ * 10 25 2011 wh.su ++ * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check ++ * un-expect ++ * let the Rx BA accept even the sta not valid. ++ * ++ * 09 28 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * enlarge window size only by 4. ++ * ++ * 09 01 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * set rx window size as twice buffer size. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue. ++ * ++ * 08 03 2011 tsaiyuan.hsu ++ * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX ++ * force window size at least 16. ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device ++ * issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 26 2011 eddie.chen ++ * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter ++ * API for query the RX reorder queued packets counter. ++ * ++ * 07 07 2011 eddie.chen ++ * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. ++ * Add setEvent when free quota is updated. ++ * ++ * 07 05 2011 eddie.chen ++ * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. ++ * Send 1x when peer STA is in PS. ++ * ++ * 05 31 2011 eddie.chen ++ * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 ++ * Fix the QM quota in MT5931. ++ * ++ * 05 11 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Fix dest type when GO packet copying. ++ * ++ * 05 09 2011 yuche.tsai ++ * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved) ++ * Deauthentication frame is not bound to network active status. ++ * ++ * 05 09 2011 eddie.chen ++ * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet ++ * Check free number before copying broadcast packet. ++ * ++ * 04 14 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Check the SW RFB free. Fix the compile warning.. ++ * ++ * 04 12 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix the sta index in processing security frame ++ * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 ++ * Add debug message. ++ * ++ * 04 11 2011 yuche.tsai ++ * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. ++ * Fix kernel panic issue when MMPDU of P2P is pending in driver. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Fix Klockwork warning. ++ * ++ * 03 28 2011 eddie.chen ++ * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW ++ * Fix wmm parameters in beacon for BOW. ++ * ++ * 03 15 2011 eddie.chen ++ * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter ++ * Add sw debug counter for QM. ++ * ++ * 02 23 2011 eddie.chen ++ * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap ++ * Fix parsing WMM INFO and bmp delivery bitmap definition. ++ * ++ * 02 17 2011 eddie.chen ++ * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel ++ * 1) Change GetFrameAction decision when BSS is absent. ++ * 2) Check channel and resource in processing ProbeRequest ++ * ++ * 02 08 2011 eddie.chen ++ * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode ++ * Add event STA agint timeout ++ * ++ * 01 27 2011 tsaiyuan.hsu ++ * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support ++ * add roaming fsm ++ * 1. not support 11r, only use strength of signal to determine roaming. ++ * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. ++ * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw ++ * 4. assume that change of link quality in smooth way. ++ * ++ * 01 25 2011 yuche.tsai ++ * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. ++ * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Remove comments. ++ * ++ * 01 24 2011 eddie.chen ++ * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets ++ * Add destination decision in AP mode. ++ * ++ * 01 14 2011 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] ++ * [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! ++ * Allow 802.1x can be send even the net is not active due the drver / fw sync issue. ++ * ++ * 01 13 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * Fix typo and compile error. ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * Fix WMM parameter condition for STA ++ * ++ * 01 12 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ * 1) Check Bss if support QoS before adding WMMIE ++ * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control ++ * ++ * 01 12 2011 george.huang ++ * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability ++ * Update MQM for WMM IE generation method ++ * ++ * 01 11 2011 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add per STA flow control when STA is in PS mode ++ * ++ * 01 03 2011 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * update prStaRec->fgIsUapsdSupported flag. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * Add WMM parameter for broadcast. ++ * ++ * 12 29 2010 eddie.chen ++ * [WCXRP00000322] Add WMM IE in beacon, ++Add per station flow control when STA is in PS ++ ++ * 1) PS flow control event ++ * ++ * 2) WMM IE in beacon, assoc resp, probe resp ++ * ++ * 12 23 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * 1. update WMM IE parsing, with ASSOC REQ handling ++ * 2. extend U-APSD parameter passing from driver to FW ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * use the #14 and modify the add code for check MMPDU. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * only MMPDU not check the netActive flag. ++ * ++ * 10 14 2010 wh.su ++ * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out ++ * not check the netActive flag for mgmt . ++ * ++ * 10 04 2010 cp.wu ++ * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ++ * ENUM_NETWORK_TYPE_INDEX_T only ++ * remove ENUM_NETWORK_TYPE_T definitions ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 08 30 2010 yarco.yang ++ * NULL ++ * Fixed klockwork error message ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 10 2010 yarco.yang ++ * NULL ++ * Code refine ++ * ++ * 08 06 2010 yarco.yang ++ * NULL ++ * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action ++ * ++ * 07 26 2010 cp.wu ++ * ++ * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet ++ * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found ++ * ++ * 07 20 2010 yarco.yang ++ * ++ * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake ++ * ++ * 07 16 2010 yarco.yang ++ * ++ * 1. Support BSS Absence/Presence Event ++ * 2. Support STA change PS mode Event ++ * 3. Support BMC forwarding for AP mode. ++ * ++ * 07 14 2010 yarco.yang ++ * ++ * 1. Remove CFG_MQM_MIGRATION ++ * 2. Add CMD_UPDATE_WMM_PARMS command ++ * ++ * 07 13 2010 yarco.yang ++ * ++ * [WPD00003849] ++ * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing ++ * ++ * 07 09 2010 yarco.yang ++ * ++ * [MT6620 and MT5931] SW Migration: Add ADDBA support ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 07 08 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * . ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Use fgInUse instead of fgIsValid for De-queue judgement ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * For MMPDU, STA_REC will be decided by caller module ++ * ++ * 07 06 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Add MGMT Packet type for HIF_TX_HEADER ++ * ++ * 06 29 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * replace g_rQM with Adpater->rQM ++ * ++ * 06 25 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * add API in que_mgt to retrieve sta-rec index for security frames. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Support CFG_MQM_MIGRATION flag ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Refined the debug msg ++ * ++ * 03 30 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * comment out one assertion which refer to undefined data member. ++ * ++ * 03 30 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled adaptive TC resource control ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++ * ++* 03 17 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) ++ * ++ * 03 11 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed buffer leak when processing BAR frames ++ * ++ * 03 02 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5 ++ * ++ * 03 01 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Fixed STA_REC index determination bug (fgIsValid shall be checked) ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Refined function qmDetermineStaRecIndex() for BMCAST packets ++ * ++ * 02 25 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled multi-STA TX path with fairness ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled dynamically activating and deactivating STA_RECs ++ * ++ * 02 24 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Added code for dynamic activating and deactivating STA_RECs. ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the 802.1x path ++ * ++ * 01 13 2010 tehuang.liu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * Enabled the Burst_End Indication mechanism ++** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468 ++** Fixed casting for qmAddRxBaEntry() ++** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752 ++** remove SD1_SD3.. flag ++** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468 ++** Added RX buffer reordering functions ++** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468 ++** Modified Flush Queue function to let queues be reinitialized ++** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468 ++** Added flushing per-Type queues code ++** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468 ++** Added Debug msgs and fixed incorrect assert ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468 ++** Bug fixing (qmDequeueTxPackets local variable initialization) ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752 ++** correct and surpress PREfast warning ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468 ++** Used SD1_SD3_DATAPATH_INTEGRATION ++** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468 ++** Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM]; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if ARP_MONITER_ENABLE ++static UINT_16 arpMoniter; ++static UINT_8 apIp[4]; ++#endif ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static inline VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++ ++static inline VOID ++qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, ++ OUT P_QUE_T prQue, ++ IN UINT_8 ucTC, IN UINT_8 ucCurrentAvailableQuota, IN UINT_8 ucTotalQuota); ++ ++static inline VOID ++qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init Queue Management for TX ++* ++* \param[in] (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmInit(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 u4QueArrayIdx; ++ UINT_32 i; ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* DbgPrint("QM: Enter qmInit()\n"); */ ++#if CFG_SUPPORT_QOS ++ prAdapter->rWifiVar.fgSupportQoS = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportQoS = FALSE; ++#endif ++ ++#if CFG_SUPPORT_AMPDU_RX ++ prAdapter->rWifiVar.fgSupportAmpduRx = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportAmpduRx = FALSE; ++#endif ++ ++#if CFG_SUPPORT_AMPDU_TX ++ prAdapter->rWifiVar.fgSupportAmpduTx = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportAmpduTx = FALSE; ++#endif ++ ++#if CFG_SUPPORT_TSPEC ++ prAdapter->rWifiVar.fgSupportTspec = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportTspec = FALSE; ++#endif ++ ++#if CFG_SUPPORT_UAPSD ++ prAdapter->rWifiVar.fgSupportUAPSD = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportUAPSD = FALSE; ++#endif ++ ++#if CFG_SUPPORT_UL_PSMP ++ prAdapter->rWifiVar.fgSupportULPSMP = TRUE; ++#else ++ prAdapter->rWifiVar.fgSupportULPSMP = FALSE; ++#endif ++ ++#if CFG_SUPPORT_RX_SGI ++ prAdapter->rWifiVar.u8SupportRxSgi20 = 0; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = 0; ++#else ++ prAdapter->rWifiVar.u8SupportRxSgi20 = 2; ++ prAdapter->rWifiVar.u8SupportRxSgi40 = 2; ++#endif ++ ++#if CFG_SUPPORT_RX_HT_GF ++ prAdapter->rWifiVar.u8SupportRxGf = 0; ++#else ++ prAdapter->rWifiVar.u8SupportRxGf = 2; ++#endif ++ ++ /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */ ++ for (u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++) ++ QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx])); ++ ++ /* 4 <3> Initialize the RX BA table and RX queues */ ++ /* Initialize the RX Reordering Parameters and Queues */ ++ for (u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++) { ++ prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE; ++ QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue)); ++ prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF; ++ prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF; ++ ++ prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE; ++ ++ } ++ prQM->ucRxBaCount = 0; ++ ++ kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout)); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ /* 4 <4> Initialize TC resource control variables */ ++ for (i = 0; i < TC_NUM; i++) ++ prQM->au4AverageQueLen[i] = 0; ++ prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; ++ prQM->u4TxNumOfVi = 0; ++ prQM->u4TxNumOfVo = 0; ++ ++/* ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); */ ++ ++ /* 1 20 1 1 4 1 */ ++ prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; ++ prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; ++ prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; ++ prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; ++ prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1) */ ++ prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC0 = %d\n", NIC_TX_BUFF_COUNT_TC0); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC1 = %d\n", NIC_TX_BUFF_COUNT_TC1); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC2 = %d\n", NIC_TX_BUFF_COUNT_TC2); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC3 = %d\n", NIC_TX_BUFF_COUNT_TC3); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC4 = %d\n", NIC_TX_BUFF_COUNT_TC4); ++ DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC5 = %d\n", NIC_TX_BUFF_COUNT_TC5); ++ ++ /* 1 1 1 1 2 1 */ ++ prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE; ++ prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE; ++ prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; ++ prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE; ++ prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1) */ ++ prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE; ++ ++ /* 4 4 6 6 2 4 */ ++ prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE; ++ prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE; ++ ++ prQM->fgTcResourcePostAnnealing = FALSE; ++ ++ ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64); ++#endif ++ ++#if QM_TEST_MODE ++ prQM->u4PktCount = 0; ++ ++#if QM_TEST_FAIR_FORWARDING ++ ++ prQM->u4CurrentStaRecIndexToEnqueue = 0; ++ { ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ P_STA_RECORD_T prStaRec; ++ ++ /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ ++ aucMacAddr[0] = 0x11; ++ aucMacAddr[1] = 0x22; ++ aucMacAddr[2] = 0xAA; ++ aucMacAddr[3] = 0xBB; ++ aucMacAddr[4] = 0xCC; ++ aucMacAddr[5] = 0xDD; ++ ++ prStaRec = &prAdapter->arStaRec[1]; ++ ASSERT(prStaRec); ++ ++ prStaRec->fgIsValid = TRUE; ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsInPS = FALSE; ++ prStaRec->ucPsSessionID = 0xFF; ++ prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ prStaRec->fgIsAp = TRUE; ++ COPY_MAC_ADDR((prStaRec)->aucMacAddr, aucMacAddr); ++ ++ } ++ ++#endif ++ ++#endif ++ ++#if QM_FORWARDING_FAIRNESS ++ { ++ UINT_32 i; ++ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { ++ prQM->au4ForwardCount[i] = 0; ++ prQM->au4HeadStaRecIndex[i] = 0; ++ } ++ } ++#endif ++ ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ kalMemZero(prQM->au4QmTcResourceEmptyCounter, sizeof(prQM->au4QmTcResourceEmptyCounter)); ++#endif ++ ++} ++ ++#if QM_TEST_MODE ++VOID qmTestCases(IN P_ADAPTER_T prAdapter) ++{ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DbgPrint("QM: ** TEST MODE **\n"); ++ ++ if (QM_TEST_STA_REC_DETERMINATION) { ++ if (prAdapter->arStaRec[0].fgIsValid) { ++ prAdapter->arStaRec[0].fgIsValid = FALSE; ++ DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); ++ } else { ++ prAdapter->arStaRec[0].fgIsValid = TRUE; ++ DbgPrint("QM: (Test) Activate STA_REC[0]\n"); ++ } ++ } ++ ++ if (QM_TEST_STA_REC_DEACTIVATION) { ++ /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */ ++ ++ if (prAdapter->arStaRec[0].fgIsValid) { ++ ++ DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); ++ qmDeactivateStaRec(prAdapter, 0); ++ } else { ++ ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++ ++ /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ ++ aucMacAddr[0] = 0x11; ++ aucMacAddr[1] = 0x22; ++ aucMacAddr[2] = 0xAA; ++ aucMacAddr[3] = 0xBB; ++ aucMacAddr[4] = 0xCC; ++ aucMacAddr[5] = 0xDD; ++ ++ DbgPrint("QM: (Test) Activate STA_REC[0]\n"); ++ qmActivateStaRec(prAdapter, /* Adapter pointer */ ++ 0, /* STA_REC index from FW */ ++ TRUE, /* fgIsQoS */ ++ NETWORK_TYPE_AIS_INDEX, /* Network type */ ++ TRUE, /* fgIsAp */ ++ aucMacAddr /* MAC address */ ++ ); ++ } ++ } ++ ++ if (QM_TEST_FAIR_FORWARDING) { ++ if (prAdapter->arStaRec[1].fgIsValid) { ++ prQM->u4CurrentStaRecIndexToEnqueue++; ++ prQM->u4CurrentStaRecIndexToEnqueue %= 2; ++ DbgPrint("QM: (Test) Switch to STA_REC[%u]\n", prQM->u4CurrentStaRecIndexToEnqueue); ++ } ++ } ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Activate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the STA_REC ++* \param[in] fgIsQoS Set to TRUE if this is a QoS STA ++* \param[in] pucMacAddr The MAC address of the STA ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) ++{ ++ ++ /* 4 <1> Deactivate first */ ++ ASSERT(prStaRec); ++ ++ if (prStaRec->fgIsValid) { /* The STA_REC has been activated */ ++ DBGLOG(QM, WARN, "QM: (WARNING) Activating a STA_REC which has been activated\n"); ++ DBGLOG(QM, WARN, "QM: (WARNING) Deactivating a STA_REC before re-activating\n"); ++ /* To flush TX/RX queues and del RX BA agreements */ ++ qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); ++ } ++ /* 4 <2> Activate the STA_REC */ ++ /* Init the STA_REC */ ++ prStaRec->fgIsValid = TRUE; ++ prStaRec->fgIsInPS = FALSE; ++ prStaRec->ucPsSessionID = 0xFF; ++ prStaRec->fgIsAp = (IS_AP_STA(prStaRec)) ? TRUE : FALSE; ++ ++ /* Done in qmInit() or qmDeactivateStaRec() */ ++#if 0 ++ /* At the beginning, no RX BA agreements have been established */ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) ++ (prStaRec->aprRxReorderParamRefTbl)[i] = NULL; ++#endif ++ ++ DBGLOG(QM, TRACE, "QM: +STA[%u]\n", (UINT_32) prStaRec->ucIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Deactivate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the STA_REC ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_32 i; ++ P_MSDU_INFO_T prFlushedTxPacketList = NULL; ++ ++ ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* 4<1> Flush TX queues */ ++ prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx); ++ ++ if (prFlushedTxPacketList) ++ wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList); ++ /* 4 <2> Flush RX queues and delete RX BA agreements */ ++ for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { ++ /* Delete the RX BA entry with TID = i */ ++ qmDelRxBaEntry(prAdapter, (UINT_8) u4StaRecIdx, (UINT_8) i, FALSE); ++ } ++ ++ /* 4 <3> Deactivate the STA_REC */ ++ prStaRec->fgIsValid = FALSE; ++ prStaRec->fgIsInPS = FALSE; ++ ++ /* To reduce printk for IOT sta to connect all the time, */ ++ /* DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx)); */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Deactivate a STA_REC ++* ++* \param[in] prAdapter Pointer to the Adapter instance ++* \param[in] u4StaRecIdx The index of the network ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ ++ P_QUE_MGT_T prQM; ++ P_QUE_T prQue; ++ QUE_T rNeedToFreeQue; ++ QUE_T rTempQue; ++ P_QUE_T prNeedToFreeQue; ++ P_QUE_T prTempQue; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ prQM = &prAdapter->rQM; ++ prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ++ QUEUE_INITIALIZE(&rNeedToFreeQue); ++ QUEUE_INITIALIZE(&rTempQue); ++ ++ prNeedToFreeQue = &rNeedToFreeQue; ++ prTempQue = &rTempQue; ++ ++ QUEUE_MOVE_ALL(prTempQue, prQue); ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); ++ while (prMsduInfo) { ++ ++ if (prMsduInfo->ucNetworkType == eNetworkTypeIdx) { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T) prMsduInfo); ++ } else { ++ /* QUEUE_INSERT_TAIL */ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); ++ } ++ if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) ++ wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush all TX queues ++* ++* \param[in] (none) ++* ++* \return The flushed packets (in a list of MSDU_INFOs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_8 ucStaArrayIdx; ++ UINT_8 ucQueArrayIdx; ++ ++ P_MSDU_INFO_T prMsduInfoListHead; ++ P_MSDU_INFO_T prMsduInfoListTail; ++ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushTxQueues()\n"); ++ ++ prMsduInfoListHead = NULL; ++ prMsduInfoListTail = NULL; ++ ++ /* Concatenate all MSDU_INFOs in per-STA queues */ ++ for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++) { ++ ++ /* Always check each STA_REC when flushing packets no matter it is inactive or active */ ++#if 0 ++ if (!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid) ++ continue; /* Continue to check the next STA_REC */ ++#endif ++ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { ++ if (QUEUE_IS_EMPTY(&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))) ++ continue; /* Continue to check the next TX queue of the same STA */ ++ ++ if (!prMsduInfoListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, ++ QUEUE_GET_HEAD(&prAdapter-> ++ arStaRec[ucStaArrayIdx].arTxQueue ++ [ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); ++ } ++ } ++ ++ /* Flush per-Type queues */ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++) { ++ ++ if (QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))) ++ continue; /* Continue to check the next TX queue of the same STA */ ++ ++ if (!prMsduInfoListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]); ++ ++ } ++ ++ if (prMsduInfoListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL); ++ } ++ ++ return prMsduInfoListHead; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush TX packets for a particular STA ++* ++* \param[in] u4StaRecIdx STA_REC index ++* ++* \return The flushed packets (in a list of MSDU_INFOs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) ++{ ++ UINT_8 ucQueArrayIdx; ++ P_MSDU_INFO_T prMsduInfoListHead; ++ P_MSDU_INFO_T prMsduInfoListTail; ++ P_STA_RECORD_T prStaRec; ++ ++ /* To reduce printk for IOT sta to connect all the time, */ ++ /* DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx)); */ ++ ++ ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prMsduInfoListHead = NULL; ++ prMsduInfoListTail = NULL; ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* No matter whether this is an activated STA_REC, do flush */ ++#if 0 ++ if (!prStaRec->fgIsValid) ++ return NULL; ++#endif ++ ++ /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */ ++ for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { ++ if (QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))) ++ continue; ++ ++ if (!prMsduInfoListHead) { ++ /* The first MSDU_INFO is found */ ++ prMsduInfoListHead = (P_MSDU_INFO_T) ++ QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ prMsduInfoListTail = (P_MSDU_INFO_T) ++ QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, ++ QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx])); ++ ++ prMsduInfoListTail = (P_MSDU_INFO_T) QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ } ++ ++ QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]); ++ ++ } ++ ++#if 0 ++ if (prMsduInfoListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx)); ++ } else { ++ prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx); ++ } ++#endif ++ ++ return prMsduInfoListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush RX packets ++* ++* \param[in] (none) ++* ++* \return The flushed packets (in a list of SW_RFBs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i; ++ P_SW_RFB_T prSwRfbListHead; ++ P_SW_RFB_T prSwRfbListTail; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ prSwRfbListHead = prSwRfbListTail = NULL; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushRxQueues()\n"); ++ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) { ++ if (!prSwRfbListHead) { ++ ++ /* The first MSDU_INFO is found */ ++ prSwRfbListHead = (P_SW_RFB_T) ++ QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue)); ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); ++ } else { ++ /* Concatenate the MSDU_INFO list with the existing list */ ++ QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail, ++ QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue))); ++ ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); ++ } ++ ++ QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue)); ++ ++ } else { ++ continue; ++ } ++ } ++ ++ if (prSwRfbListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); ++ } ++ return prSwRfbListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Flush RX packets with respect to a particular STA ++* ++* \param[in] u4StaRecIdx STA_REC index ++* \param[in] u4Tid TID ++* ++* \return The flushed packets (in a list of SW_RFBs) ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx, IN UINT_32 u4Tid) ++{ ++ /* UINT_32 i; */ ++ P_SW_RFB_T prSwRfbListHead; ++ P_SW_RFB_T prSwRfbListTail; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ P_STA_RECORD_T prStaRec; ++ ++ DBGLOG(QM, TRACE, "QM: Enter qmFlushStaRxQueues(%u)\n", u4StaRecIdx); ++ ++ prSwRfbListHead = prSwRfbListTail = NULL; ++ ++ prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* No matter whether this is an activated STA_REC, do flush */ ++#if 0 ++ if (!prStaRec->fgIsValid) ++ return NULL; ++#endif ++ ++ /* Obtain the RX BA Entry pointer */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]); ++ ++ /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */ ++ if (prReorderQueParm) { ++ ++ if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) { ++ ++ prSwRfbListHead = (P_SW_RFB_T) ++ QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue)); ++ prSwRfbListTail = (P_SW_RFB_T) ++ QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue)); ++ ++ QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue)); ++ ++ } ++ } ++ ++ if (prSwRfbListTail) { ++ /* Terminate the MSDU_INFO list with a NULL pointer */ ++ QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); ++ } ++ return prSwRfbListHead; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Enqueue TX packets ++* ++* \param[in] prMsduInfoListHead Pointer to the list of TX packets ++* ++* \return The freed packets, which are not enqueued ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) ++{ ++ P_MSDU_INFO_T prMsduInfoReleaseList; ++ P_MSDU_INFO_T prCurrentMsduInfo; ++ P_MSDU_INFO_T prNextMsduInfo; ++ ++ P_STA_RECORD_T prStaRec; ++ QUE_T rNotEnqueuedQue; ++ P_QUE_T prTxQue = &rNotEnqueuedQue; ++ ++ UINT_8 ucPacketType; ++ UINT_8 ucTC; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ UINT_8 aucNextUP[WMM_AC_INDEX_NUM] = { 1 /* BEtoBK */ , 1 /*na */ , 0 /*VItoBE */ , 4 /*VOtoVI */ }; ++ ++ DBGLOG(QM, LOUD, "Enter qmEnqueueTxPackets\n"); ++ ++ ASSERT(prMsduInfoListHead); ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ { ++ /* UINT_32 i; */ ++ /* 4 <0> Update TC resource control related variables */ ++ /* Keep track of the queue length */ ++ if (--prQM->u4TimeToUpdateQueLen == 0) { /* -- only here */ ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; ++ qmUpdateAverageTxQueLen(prAdapter); ++ } ++ } ++#endif ++ ++ /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */ ++ prStaRec = NULL; ++ prMsduInfoReleaseList = NULL; ++ prCurrentMsduInfo = NULL; ++ QUEUE_INITIALIZE(&rNotEnqueuedQue); ++ prNextMsduInfo = prMsduInfoListHead; ++ ++ do { ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgCheckACMAgain; ++ ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; ++ ++ prCurrentMsduInfo = prNextMsduInfo; ++ prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo); ++ ucTC = TC1_INDEX; ++ ++ /* 4 <1> Lookup the STA_REC index */ ++ /* The ucStaRecIndex will be set in this function */ ++ qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo); ++ ucPacketType = HIF_TX_PACKET_TYPE_DATA; ++ ++ STATS_ENV_REPORT_DETECT(prAdapter, prCurrentMsduInfo->ucStaRecIndex); ++ ++ DBGLOG(QM, LOUD, "***** ucStaRecIndex = %d *****\n", prCurrentMsduInfo->ucStaRecIndex); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 0) ++ if (IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) { ++#else ++ /* force to send the loopback test packet */ ++ if (1) { ++ SET_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType); ++ prCurrentMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; ++ ucPacketType = HIF_TX_PKT_TYPE_HIF_LOOPBACK; ++#endif /* End of CONF_HIF_LOOPBACK_AUTO */ ++ ++ switch (prCurrentMsduInfo->ucStaRecIndex) { ++ case STA_REC_INDEX_BMCAST: ++ prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ucTC = TC5_INDEX; ++#if 0 ++ if (prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX ++ && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT) { ++ if (LINK_IS_EMPTY ++ (&prAdapter->rWifiVar. ++ arBssInfo[NETWORK_TYPE_P2P_INDEX].rStaRecOfClientList)) { ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_AP_BORADCAST_DROP); ++ } ++ } ++#endif ++ ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); ++ break; ++ ++ case STA_REC_INDEX_NOT_FOUND: ++ ucTC = TC5_INDEX; ++ ++ if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ ++ /* if the packet is the forward type. the packet should be freed */ ++ DBGLOG(QM, TRACE, "Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"); ++ /* prTxQue = &rNotEnqueuedQue; */ ++ } ++ prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC]; ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); ++ ++ break; ++ ++ default: ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prCurrentMsduInfo->ucStaRecIndex); ++ ++ if (!prStaRec) { ++ DBGLOG(QM, ERROR, "prStaRec is NULL\n"); ++ break; ++ } ++ ASSERT(prStaRec->fgIsValid); ++ ++ if (prCurrentMsduInfo->ucUserPriority < 8) { ++ QM_DBG_CNT_INC(prQM, prCurrentMsduInfo->ucUserPriority + 15); ++ /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */ ++ /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */ ++ } ++ ++ eAci = WMM_AC_BE_INDEX; ++ do { ++ fgCheckACMAgain = FALSE; ++ if (!prStaRec->fgIsQoS) { ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ break; ++ } ++ ++ switch (prCurrentMsduInfo->ucUserPriority) { ++ case 1: ++ case 2: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC0]; ++ ucTC = TC0_INDEX; ++ eAci = WMM_AC_BK_INDEX; ++ break; ++ case 0: ++ case 3: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ eAci = WMM_AC_BE_INDEX; ++ break; ++ case 4: ++ case 5: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC2]; ++ ucTC = TC2_INDEX; ++ eAci = WMM_AC_VI_INDEX; ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ prQM->u4TxNumOfVi++; ++#endif ++ break; ++ case 6: ++ case 7: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC3]; ++ ucTC = TC3_INDEX; ++ eAci = WMM_AC_VO_INDEX; ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ prQM->u4TxNumOfVo++; ++#endif ++ break; ++ default: ++ prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; ++ ucTC = TC1_INDEX; ++ eAci = WMM_AC_BE_INDEX; ++ ASSERT(0); ++ break; ++ } ++ if (prBssInfo->arACQueParms[eAci].fgIsACMSet && eAci ++ != WMM_AC_BK_INDEX) { ++ prCurrentMsduInfo->ucUserPriority = aucNextUP[eAci]; ++ fgCheckACMAgain = TRUE; ++ } ++ } while (fgCheckACMAgain); ++ ++ /* LOG_FUNC ("QoS %u UP %u TC %u", */ ++ /* prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); */ ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ /* ++ In TDLS or AP mode, peer maybe enter "sleep mode". ++ ++ If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, ++ we need to wait 60 * u4TimeToAdjustTcResource = 180 packets ++ u4TimeToAdjustTcResource = 3, ++ then we will adjust TC resouce for VI or VO. ++ ++ But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, ++ we will to wait about 12 seconds to collect 180 packets. ++ but the test time is only 20 seconds. ++ */ ++ if ((prQM->u4TxNumOfVi == 10) || (prQM->u4TxNumOfVo == 10)) { ++ /* force to do TC resouce update */ ++ prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN; ++ prQM->u4TimeToAdjustTcResource = 1; ++ } ++#endif ++#if ARP_MONITER_ENABLE ++ if (IS_STA_IN_AIS(prStaRec) && prCurrentMsduInfo->eSrc == TX_PACKET_OS) ++ qmDetectArpNoResponse(prAdapter, prCurrentMsduInfo); ++#endif ++ ++ break; /*default */ ++ } /* switch (prCurrentMsduInfo->ucStaRecIndex) */ ++ ++ if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { ++ if (prTxQue->u4NumElem > 32) { ++ DBGLOG(QM, WARN, ++ "Drop the Packet for full Tx queue (forwarding) Bss %u\n", ++ prCurrentMsduInfo->ucNetworkType); ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_FORWARD_OVERFLOW_DROP); ++ } ++ } ++ ++ } else { ++ ++ DBGLOG(QM, WARN, "Drop the Packet for inactive Bss %u\n", prCurrentMsduInfo->ucNetworkType); ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); ++ prTxQue = &rNotEnqueuedQue; ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); ++ } ++ ++ /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */ ++ ++ /* TODO: Fill MSDU_INFO according to the network type, ++ * EtherType, and STA status (for PS forwarding control). ++ */ ++ ++ /* Note that the Network Type Index and STA_REC index are determined in ++ * qmDetermineStaRecIndex(prCurrentMsduInfo). ++ */ ++ QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(prCurrentMsduInfo, /* MSDU_INFO ptr */ ++ ucTC, /* TC tag */ ++ ucPacketType, /* Packet Type */ ++ 0, /* Format ID */ ++ prCurrentMsduInfo->fgIs802_1x, /* Flag 802.1x */ ++ prCurrentMsduInfo->fgIs802_11, /* Flag 802.11 */ ++ 0, /* PAL LLH */ ++ 0, /* ACL SN */ ++ PS_FORWARDING_TYPE_NON_PS, /* PS Forwarding Type */ ++ 0 /* PS Session ID */ ++ ); ++ ++ /* 4 <4> Enqueue the packet to different AC queue (max 5 AC queues) */ ++ QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T) prCurrentMsduInfo); ++ ++ if (prTxQue != &rNotEnqueuedQue) { ++ prQM->u4EnqeueuCounter++; ++ prQM->au4ResourceWantedCounter[ucTC]++; ++ } ++ if (prStaRec) ++ prStaRec->u4EnqeueuCounter++; ++ ++#if QM_TC_RESOURCE_EMPTY_COUNTER ++ { ++ P_TX_CTRL_T prTxCtrl = &prAdapter->rTxCtrl; ++ ++ if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] == 0) { ++ prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC]++; ++ /* ++ DBGLOG(QM, TRACE, ("TC%d Q Empty Count: [%d]%ld\n", ++ ucTC, ++ prCurrentMsduInfo->ucNetworkType, ++ prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC])); ++ */ ++ } ++ ++ } ++#endif ++ ++#if QM_TEST_MODE ++ if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) { ++ prQM->u4PktCount = 0; ++ qmTestCases(prAdapter); ++ } ++#endif ++ ++ DBGLOG(QM, LOUD, "Current queue length = %u\n", prTxQue->u4NumElem); ++ } while (prNextMsduInfo); ++ ++ if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue)) { ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL); ++ prMsduInfoReleaseList = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rNotEnqueuedQue); ++ } ++ ++ return prMsduInfoReleaseList; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Determine the STA_REC index for a packet ++* ++* \param[in] prMsduInfo Pointer to the packet ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_32 i; ++ ++ P_STA_RECORD_T prTempStaRec; ++ /* P_QUE_MGT_T prQM = &prAdapter->rQM; */ ++ ++ prTempStaRec = NULL; ++ ++ ASSERT(prMsduInfo); ++ ++ /* 4 <1> DA = BMCAST */ ++ if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) { ++ /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP. ++ * FW shall take care of this. The host driver is not able to distinguish these cases. */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; ++ DBGLOG(QM, LOUD, "TX with DA = BMCAST\n"); ++ return; ++ } ++#if (CFG_SUPPORT_TDLS == 1) ++ /* Check if the peer is TDLS one */ ++ if (TdlsexStaRecIdxGet(prAdapter, prMsduInfo) == TDLS_STATUS_SUCCESS) ++ return; /* find a TDLS record */ ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* 4 <2> Check if an AP STA is present */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ ++ if ((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType) ++ && (prTempStaRec->fgIsAp) ++ && (prTempStaRec->fgIsValid)) { ++ prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; ++ return; ++ } ++ } ++ ++ /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if (prTempStaRec->fgIsValid) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)) { ++ prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; ++ return; ++ } ++ } ++ } ++ ++ /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ ++ prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; ++ DBGLOG(QM, LOUD, "QM: TX with STA_REC_INDEX_NOT_FOUND\n"); ++ ++#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING) ++ prMsduInfo->ucStaRecIndex = (UINT_8) prQM->u4CurrentStaRecIndexToEnqueue; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets from a STA_REC for a particular TC ++* ++* \param[out] prQue The queue to put the dequeued packets ++* \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX) ++* \param[in] ucMaxNum The maximum amount of dequeued packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, ++ OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucCurrentQuota, IN UINT_8 ucTotalQuota) ++{ ++ ++#if QM_FORWARDING_FAIRNESS ++ UINT_32 i; /* Loop for */ ++ ++ PUINT_32 pu4HeadStaRecIndex; /* The Head STA index */ ++ PUINT_32 pu4HeadStaRecForwardCount; /* The total forwarded packets for the head STA */ ++ ++ P_STA_RECORD_T prStaRec; /* The current focused STA */ ++ P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */ ++ P_QUE_T prCurrQueue; /* The current TX queue to dequeue */ ++ P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */ ++ ++ UINT_32 u4ForwardCount; /* To remember the total forwarded packets for a STA */ ++ UINT_32 u4MaxForwardCount; /* The maximum number of packets a STA can forward */ ++ UINT_32 u4Resource; /* The TX resource amount */ ++ ++ BOOLEAN fgChangeHeadSta; /* Whether a new head STA shall be determined at the end of the function */ ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ PUINT_8 pucFreeQuota = NULL; ++#if CFG_ENABLE_WIFI_DIRECT ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ /*NFC Beam + Indication */ ++#endif ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); ++ ++ ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); ++ ++ if (!ucCurrentQuota) { ++ prQM->au4DequeueNoTcResourceCounter[ucTC]++; ++ DBGLOG(TX, LOUD, "@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n", ucTC, ucCurrentQuota); ++ return; ++ } ++ ++ u4Resource = ucCurrentQuota; ++ ++ /* 4 <1> Determine the head STA */ ++ /* The head STA shall be an active STA */ ++ ++ pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]); ++ pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]); ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Init Head STA = %u Resource = %u\n", ++ ucTC, *pu4HeadStaRecIndex, u4Resource); ++ ++ /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD + 1; i++) { ++ prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)]; ++ ASSERT(prStaRec); ++ ++ /* Only Data frame (1x was not included) will be queued in */ ++ if (prStaRec->fgIsValid) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ ++ /* Determine how many packets the head STA is allowed to send in a round */ ++ ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25); ++ u4MaxForwardCount = ucTotalQuota; ++#if CFG_ENABLE_WIFI_DIRECT ++ ++ pucFreeQuota = NULL; ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ ++ /* u4MaxForwardCount = ucTotalQuota; */ ++ /* Per STA flow control when STA in PS mode */ ++ /* The PHASE 1: only update from ucFreeQuota (now) */ ++ /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ ++ /* aucFreeQuotaPerQueue[] */ ++ /* NOTE: other method to set u4Resource */ ++ ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ ++ if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; ++ } else { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } else { ++ ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } /* fgIsInPS */ ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++ /*NFC Beam + Indication */ ++ ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { ++ if ((prChnlReqInfo->NFC_BEAM != 1) && ++ (u4MaxForwardCount > prBssInfo->ucBssFreeQuota)) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } else { ++ if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ /* Determine whether the head STA can continue to forward packets in this round */ ++ if ((*pu4HeadStaRecForwardCount) < u4MaxForwardCount) ++ break; ++ ++ } /* prStaRec->fgIsValid */ ++ else { ++ /* The current Head STA has been deactivated, so search for a new head STA */ ++ prStaRec = NULL; ++ prBssInfo = NULL; ++ (*pu4HeadStaRecIndex)++; ++ (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; ++ ++ /* Reset the forwarding count before searching (since this is for a new selected STA) */ ++ (*pu4HeadStaRecForwardCount) = 0; ++ } ++ } /* i < CFG_NUM_OF_STA_RECORD + 1 */ ++ ++ /* All STA_RECs are inactive, so exit */ ++ if (!prStaRec) { ++ /* Under concurrent, it is possible that there is no candidcated STA. */ ++ /* DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); */ ++ return; ++ } ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Round Head STA = %u\n", ucTC, *pu4HeadStaRecIndex); ++ ++ /* 4 <2> Dequeue packets from the head STA */ ++ ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ prDequeuedPkt = NULL; ++ fgChangeHeadSta = FALSE; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ if (pucFreeQuota != NULL) ++ TdlsexTxQuotaCheck(prAdapter->prGlueInfo, prStaRec, *pucFreeQuota); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ while (prCurrQueue) { ++ ++#if QM_DEBUG_COUNTER ++ ++ if (ucTC <= TC4_INDEX) { ++ if (QUEUE_IS_EMPTY(prCurrQueue)) { ++ QM_DBG_CNT_INC(prQM, ucTC); ++ /* QM_DBG_CNT_00 *//* QM_DBG_CNT_01 *//* QM_DBG_CNT_02 */ ++ /* QM_DBG_CNT_03 *//* QM_DBG_CNT_04 */ ++ } ++ if (u4Resource == 0) { ++ QM_DBG_CNT_INC(prQM, ucTC + 5); ++ /* QM_DBG_CNT_05 *//* QM_DBG_CNT_06 *//* QM_DBG_CNT_07 */ ++ /* QM_DBG_CNT_08 *//* QM_DBG_CNT_09 */ ++ } ++ if (((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { ++ QM_DBG_CNT_INC(prQM, ucTC + 10); ++ /* QM_DBG_CNT_10 *//* QM_DBG_CNT_11 *//* QM_DBG_CNT_12 */ ++ /* QM_DBG_CNT_13 *//* QM_DBG_CNT_14 */ ++ } ++ } ++#endif ++ ++ /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ ++ if (QUEUE_IS_EMPTY(prCurrQueue) || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { ++ fgChangeHeadSta = TRUE; ++ break; ++ } else if (u4Resource == 0) { ++#if (CFG_SUPPORT_STATISTICS == 1) ++ prStaRec->u4NumOfNoTxQuota++; ++#endif /* CFG_SUPPORT_STATISTICS */ ++ break; ++ } ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ prStaRec->u4DeqeueuCounter++; ++ prQM->u4DequeueCounter++; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ if (prDequeuedPkt != NULL) { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(QM, LOUD, " %d\n", u2Identifier); ++ } ++ } ++#endif ++#if DBG && 0 ++ LOG_FUNC("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, ++ prCurrQueue->u4NumElem, ++ prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, ++ prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ if (!QUEUE_IS_EMPTY(prCurrQueue)) { ++ /* XXX: check all queues for STA */ ++ prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; ++ } ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ u4Resource--; ++ (*pu4HeadStaRecForwardCount)++; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ if ((pucFreeQuota) && (*pucFreeQuota > 0)) ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->ucBssFreeQuota > 0) ++ prBssInfo->ucBssFreeQuota--; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ } ++ ++ if (*pu4HeadStaRecForwardCount) { ++ DBGLOG(QM, LOUD, ++ "TC = %u Round Head STA = %u, u4HeadStaRecForwardCount = %u\n", ucTC, *pu4HeadStaRecIndex, ++ (*pu4HeadStaRecForwardCount)); ++ } ++#if QM_BURST_END_INFO_ENABLED ++ /* Let FW know which packet is the last one dequeued from the STA */ ++ if (prDequeuedPkt) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ ++ /* 4 <3> Dequeue from the other STAs if there is residual TX resource */ ++ ++ /* Check all of the STAs to continue forwarding packets (including the head STA) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ /* Break in case no reasource is available */ ++ if (u4Resource == 0) { ++ prQM->au4DequeueNoTcResourceCounter[ucTC]++; ++ break; ++ } ++ ++ /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */ ++ prStaRec = &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD]; ++ ASSERT(prStaRec); ++ ++ if (prStaRec->fgIsValid) { ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Sharing STA = %u Resource = %u\n", ++ ucTC, prStaRec->ucIndex, u4Resource); ++ ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ u4ForwardCount = 0; ++ u4MaxForwardCount = ucTotalQuota; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ pucFreeQuota = NULL; ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ ++ /* u4MaxForwardCount = ucTotalQuota; */ ++ /* Per STA flow control when STA in PS mode */ ++ /* The PHASE 1: only update from ucFreeQuota (now) */ ++ /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ ++ /* aucFreeQuotaPerQueue[] */ ++ /* NOTE: other method to set u4Resource */ ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ ++ if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; ++ } else { ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } else { ++ ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); ++ u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; ++ pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; ++ } ++ ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) ++ u4MaxForwardCount = prBssInfo->ucBssFreeQuota; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ } /* prStaRec->fgIsValid */ ++ else { ++ prBssInfo = NULL; ++ /* Invalid STA, so check the next STA */ ++ continue; ++ } ++ ++ while (prCurrQueue) { ++ /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ ++ if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue) || (u4ForwardCount >= u4MaxForwardCount)) ++ break; ++ ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ ++#if DBG && 0 ++ DBGLOG(QM, LOUD, "Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, ++ prCurrQueue->u4NumElem, ++ prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, ++ prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, ++ prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11)); ++ ++ DBGLOG(QM, LOUD, "Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ if (!QUEUE_IS_EMPTY(prCurrQueue)) ++ /* more data field ? */ ++ prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ if (prStaRec) ++ prStaRec->u4DeqeueuCounter++; ++ prQM->u4DequeueCounter++; ++ u4Resource--; ++ u4ForwardCount++; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ ++ if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { ++ ASSERT(pucFreeQuota); ++ ASSERT(*pucFreeQuota > 0); ++ if (*pucFreeQuota > 0) ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); ++ if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { ++ if (prBssInfo->ucBssFreeQuota > 0) ++ prBssInfo->ucBssFreeQuota--; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT */ ++ ++ } ++ ++#if QM_BURST_END_INFO_ENABLED ++ /* Let FW know which packet is the last one dequeued from the STA */ ++ if (u4ForwardCount) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ } ++ ++ if (fgChangeHeadSta) { ++ (*pu4HeadStaRecIndex)++; ++ (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; ++ (*pu4HeadStaRecForwardCount) = 0; ++ DBGLOG(QM, LOUD, "(Fairness) TID = %u Scheduled Head STA = %u Left Resource = %u\n", ++ ucTC, (*pu4HeadStaRecIndex), u4Resource); ++ } ++ ++/***************************************************************************************/ ++#else ++ UINT_8 ucStaRecIndex; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_T prCurrQueue; ++ UINT_8 ucPktCount; ++ P_MSDU_INFO_T prDequeuedPkt; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); ++ ++ if (ucCurrentQuota == 0) ++ return; ++ /* 4 <1> Determine the queue index and the head STA */ ++ ++ /* The head STA */ ++ ucStaRecIndex = 0; /* TODO: Get the current head STA */ ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ /* The queue to pull out packets */ ++ ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); ++ prCurrQueue = &prStaRec->arTxQueue[ucTC]; ++ ++ ucPktCount = ucCurrentQuota; ++ prDequeuedPkt = NULL; ++ ++ /* 4 <2> Dequeue packets for the head STA */ ++ while (TRUE) { ++ if (!(prStaRec->fgIsValid) || ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) { ++ break; ++ ++ } else { ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ /* DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); */ ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ ucPktCount--; ++ } ++ } ++ ++ /* DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); */ ++ ++#if QM_BURST_END_INFO_ENABLED ++ if (prDequeuedPkt) ++ prDequeuedPkt->fgIsBurstEnd = TRUE; ++#endif ++ ++ /* 4 <3> Update scheduling info */ ++ /* TODO */ ++ ++ /* 4 <4> Utilize the remainaing TX opportunities for non-head STAs */ ++ /* TODO */ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets from a per-Type-based Queue for a particular TC ++* ++* \param[out] prQue The queue to put the dequeued packets ++* \param[in] ucTC The TC index (Shall always be TC5_INDEX) ++* \param[in] ucMaxNum The maximum amount of dequeued packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID ++qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum) ++{ ++ /* UINT_8 ucQueIndex; */ ++ /* UINT_8 ucStaRecIndex; */ ++ P_BSS_INFO_T prBssInfo; ++ P_BSS_INFO_T parBssInfo; ++ P_QUE_T prCurrQueue; ++ UINT_8 ucPktCount; ++ P_MSDU_INFO_T prDequeuedPkt; ++ P_MSDU_INFO_T prBurstEndPkt; ++ QUE_T rMergeQue; ++ P_QUE_T prMergeQue; ++ P_QUE_MGT_T prQM; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum); ++ ++ /* TC5: Broadcast/Multicast data packets */ ++ ASSERT(ucTC == TC5_INDEX); ++ ++ if (ucMaxNum == 0) ++ return; ++ ++ prQM = &prAdapter->rQM; ++ /* 4 <1> Determine the queue */ ++ ++ prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; ++ ucPktCount = ucMaxNum; ++ prDequeuedPkt = NULL; ++ prBurstEndPkt = NULL; ++ ++ parBssInfo = prAdapter->rWifiVar.arBssInfo; ++ ++ QUEUE_INITIALIZE(&rMergeQue); ++ prMergeQue = &rMergeQue; ++ ++ /* 4 <2> Dequeue packets */ ++ while (TRUE) { ++ if (ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) ++ break; ++ ++ QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); ++ ASSERT(prDequeuedPkt->ucTC == ucTC); ++ ++ ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM); ++ ++ prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType]; ++ ++ if (IS_BSS_ACTIVE(prBssInfo)) { ++ if (!prBssInfo->fgIsNetAbsent) { ++ QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ prQM->u4DequeueCounter++; ++ prBurstEndPkt = prDequeuedPkt; ++ ucPktCount--; ++ QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26); ++#if DBG && 0 ++ LOG_FUNC ++ ("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", ++ prDequeuedPkt->ucTC, prCurrQueue->u4NumElem, prDequeuedPkt->ucNetworkType, ++ prDequeuedPkt->ucMacHeaderLength, prDequeuedPkt->u2FrameLength, ++ prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, ++ prDequeuedPkt->fgIs802_11); ++ ++ LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); ++ ++#if LINUX ++ { ++ struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; ++ ++ dumpMemory8((PUINT_8) prSkb->data, prSkb->len); ++ } ++#endif ++ ++#endif ++ } else { ++ QUEUE_INSERT_TAIL(prMergeQue, (P_QUE_ENTRY_T) prDequeuedPkt); ++ } ++ } else { ++ QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL); ++ wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt); ++ } ++ } ++ ++ if (QUEUE_IS_NOT_EMPTY(prMergeQue)) { ++ QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue); ++ QUEUE_MOVE_ALL(prCurrQueue, prMergeQue); ++ if (QUEUE_GET_TAIL(prCurrQueue)) ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(prCurrQueue), NULL); ++ } ++#if QM_BURST_END_INFO_ENABLED ++ if (prBurstEndPkt) ++ prBurstEndPkt->fgIsBurstEnd = TRUE; ++#endif ++} /* qmDequeueTxPacketsFromPerTypeQueues */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dequeue TX packets to send to HIF TX ++* ++* \param[in] prTcqStatus Info about the maximum amount of dequeued packets ++* ++* \return The list of dequeued TX packets ++*/ ++/*----------------------------------------------------------------------------*/ ++P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus) ++{ ++ ++ INT32 i; ++ P_MSDU_INFO_T prReturnedPacketListHead; ++ QUE_T rReturnedQue; ++ ++ DBGLOG(QM, LOUD, "Enter qmDequeueTxPackets\n"); ++ ++ QUEUE_INITIALIZE(&rReturnedQue); ++ ++ prReturnedPacketListHead = NULL; ++ ++ /* dequeue packets from different AC queue based on available aucFreeBufferCount */ ++ /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */ ++ for (i = TC4_INDEX; i >= TC0_INDEX; i--) { ++ DBGLOG(QM, LOUD, "Dequeue packets from Per-STA queue[%d]\n", i); ++ ++ /* ++ in the function, we will re-calculate the ucFreeQuota. ++ If any packet with any priority for the station will be sent, ucFreeQuota -- ++ ++ Note1: ucFreeQuota will be decrease only when station is in power save mode. ++ In active mode, we will sent the packet to the air directly. ++ ++ if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { ++ ASSERT(pucFreeQuota); ++ ASSERT(*pucFreeQuota>0); ++ if ((pucFreeQuota) && (*pucFreeQuota>0)) { ++ *pucFreeQuota = *pucFreeQuota - 1; ++ } ++ } ++ ++ Note2: maximum queued number for a station is 10, TXM_MAX_BUFFER_PER_STA_DEF in fw ++ i.e. default prStaRec->ucFreeQuota = 10 ++ ++ Note3: In qmUpdateFreeQuota(), we will adjust ++ ucFreeQuotaForNonDelivery = ucFreeQuota>>1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ */ ++ qmDequeueTxPacketsFromPerStaQueues(prAdapter, ++ &rReturnedQue, ++ (UINT_8) i, ++ prTcqStatus->aucFreeBufferCount[i], /* maximum dequeue number */ ++ prTcqStatus->aucMaxNumOfBuffer[i]); ++ ++ /* The aggregate number of dequeued packets */ ++ DBGLOG(QM, LOUD, "DQA)[%u](%u)\n", i, rReturnedQue.u4NumElem); ++ } ++ ++ /* TC5 (BMCAST or STA-NOT-FOUND packets) */ ++ qmDequeueTxPacketsFromPerTypeQueues(prAdapter, ++ &rReturnedQue, TC5_INDEX, prTcqStatus->aucFreeBufferCount[TC5_INDEX] ++ ); ++ ++ DBGLOG(QM, LOUD, "Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem); ++ ++ if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) { ++ prReturnedPacketListHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rReturnedQue); ++ QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); ++ } ++ ++ return prReturnedPacketListHead; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Adjust the TC quotas according to traffic demands ++* ++* \param[out] prTcqAdjust The resulting adjustment ++* \param[in] prTcqStatus Info about the current TC quotas and counters ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus) ++{ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++ UINT_32 i; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* Must reset */ ++ for (i = 0; i < TC_NUM; i++) ++ prTcqAdjust->acVariation[i] = 0; ++ ++ /* 4 <1> If TC resource is not just adjusted, exit directly */ ++ if (!prQM->fgTcResourcePostAnnealing) ++ return; ++ /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */ ++ else { ++ INT_32 i4TotalExtraQuota = 0; ++ INT_32 ai4ExtraQuota[TC_NUM]; ++ BOOLEAN fgResourceRedistributed = TRUE; ++ ++ /* Obtain the free-to-distribute resource */ ++ for (i = 0; i < TC_NUM; i++) { ++ ai4ExtraQuota[i] = ++ (INT_32) prTcqStatus->aucMaxNumOfBuffer[i] - (INT_32) prQM->au4CurrentTcResource[i]; ++ ++ if (ai4ExtraQuota[i] > 0) { /* The resource shall be reallocated to other TCs */ ++ ++ if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]) { ++ /* ++ we have residunt TC resources for the TC: ++ EX: aucMaxNumOfBuffer[] = 20, au4CurrentTcResource[] = 5 ++ ai4ExtraQuota[] = 15, aucFreeBufferCount[] = 10 ++ ++ so ai4ExtraQuota[] = aucFreeBufferCount[] = 10 ++ because we available TC resources actually is 10, not 20 ++ */ ++ ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i]; ++ ++ /* ++ FALSE means we can re-do TC resource adjustment in tx done ++ at next time, maybe more tx done is finished ++ */ ++ fgResourceRedistributed = FALSE; ++ } ++ ++ /* accumulate current all available TC resources */ ++ i4TotalExtraQuota += ai4ExtraQuota[i]; ++ ++ /* deduce unused TC resources for the TC */ ++ prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); ++ } ++ } ++ ++ /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */ ++ for (i = 0; i < TC_NUM; i++) { ++ if (ai4ExtraQuota[i] < 0) { ++ ++ /* The TC needs extra resources */ ++ if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) { ++ /* the number of needed extra resources is larger than total available */ ++ ai4ExtraQuota[i] = (-i4TotalExtraQuota); ++ ++ /* wait for next tx done to do adjustment */ ++ fgResourceRedistributed = FALSE; ++ } ++ ++ /* decrease the total available */ ++ i4TotalExtraQuota += ai4ExtraQuota[i]; ++ ++ /* mark to increase TC resources for the TC */ ++ prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); ++ } ++ } ++ ++ /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */ ++ ++ /* ++ if fgResourceRedistributed == TRUE, it means we will adjust at this time so ++ we need to re-adjust TC resources (fgTcResourcePostAnnealing = FALSE). ++ */ ++ prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); ++ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ DBGLOG(QM, LOUD, "QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n", ++ prTcqStatus->aucFreeBufferCount[0], ++ prTcqStatus->aucFreeBufferCount[1], ++ prTcqStatus->aucFreeBufferCount[2], ++ prTcqStatus->aucFreeBufferCount[3], ++ prTcqStatus->aucFreeBufferCount[4], prTcqStatus->aucFreeBufferCount[5] ++ )); ++#endif ++ } ++ ++#else ++ UINT_32 i; ++ ++ for (i = 0; i < TC_NUM; i++) ++ prTcqAdjust->acVariation[i] = 0; ++ ++#endif ++} ++ ++#if QM_ADAPTIVE_TC_RESOURCE_CTRL ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update the average TX queue length for the TC resource control mechanism ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter) ++{ ++ INT_32 u4CurrQueLen, i, k; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ ++ /* use moving average algorithm to calculate au4AverageQueLen for every TC queue */ ++ for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++) { ++ u4CurrQueLen = 0; ++ ++ for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++) { ++ prStaRec = &prAdapter->arStaRec[k]; ++ ASSERT(prStaRec); ++ ++ /* If the STA is activated, get the queue length */ ++ if (prStaRec->fgIsValid && ++ (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent) ++ ) { ++ ++ u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem); ++ } ++ } ++ ++ if (prQM->au4AverageQueLen[i] == 0) { ++ prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); /* *8 */ ++ } else { ++ /* len => len - len/8 = 7/8 * len + new len */ ++ prQM->au4AverageQueLen[i] -= (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR); ++ prQM->au4AverageQueLen[i] += (u4CurrQueLen); ++ } ++ ++ } ++ ++ /* Update the queue length for TC5 (BMCAST) */ ++ u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem; ++ ++ if (prQM->au4AverageQueLen[TC_NUM - 1] == 0) { ++ prQM->au4AverageQueLen[TC_NUM - 1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); ++ } else { ++ prQM->au4AverageQueLen[TC_NUM - 1] -= ++ (prQM->au4AverageQueLen[TC_NUM - 1] >> QM_QUE_LEN_MOVING_AVE_FACTOR); ++ prQM->au4AverageQueLen[TC_NUM - 1] += (u4CurrQueLen); ++ } ++ ++ /* 4 <2> Adjust TC resource assignment every 3 times */ ++ /* Check whether it is time to adjust the TC resource assignment */ ++ if (--prQM->u4TimeToAdjustTcResource == 0) { /* u4TimeToAdjustTcResource = 3 */ ++ ++ /* The last assignment has not been completely applied */ ++ if (prQM->fgTcResourcePostAnnealing) { ++ /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */ ++ ++ /* wait for next time to do qmReassignTcResource */ ++ prQM->u4TimeToAdjustTcResource = 1; ++ } else { /* The last assignment has been applied */ ++ prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; ++ qmReassignTcResource(prAdapter); ++ } ++ } ++ ++ /* Debug */ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ for (i = 0; i < TC_NUM; i++) { ++ if (QM_GET_TX_QUEUE_LEN(prAdapter, i) >= 100) { ++ DBGLOG(QM, LOUD, "QM: QueLen [%u %u %u %u %u %u]\n", ++ QM_GET_TX_QUEUE_LEN(prAdapter, 0), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 1), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 2), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 3), ++ QM_GET_TX_QUEUE_LEN(prAdapter, 4), QM_GET_TX_QUEUE_LEN(prAdapter, 5) ++ )); ++ break; ++ } ++ } ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Assign TX resource for each TC according to TX queue length and current assignment ++* ++* \param (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter) ++{ ++ INT_32 i4TotalResourceDemand = 0; ++ UINT_32 u4ResidualResource = 0; ++ UINT_32 i; ++ INT_32 ai4PerTcResourceDemand[TC_NUM]; ++ UINT_32 u4ShareCount = 0; ++ UINT_32 u4Share = 0; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to ++ * start the TC-quota adjusting procedure, which will be invoked upon every TX Done ++ */ ++ /* tx done -> nicProcessTxInterrupt() -> nicTxAdjustTcq() ++ * -> qmAdjustTcQuotas() -> check fgTcResourcePostAnnealing */ ++ ++ /* 4 <1> Determine the demands */ ++ /* Determine the amount of extra resource to fulfill all of the demands */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4, which is not adjustable */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* ++ Define: extra_demand = average que_length (includes all station records) + ++ min_reserved_quota - ++ current available TC resources ++ ++ extra_demand means we need extra TC resources to transmit; other TCs can ++ borrow their resources to us? ++ */ ++ ai4PerTcResourceDemand[i] = ++ ((UINT_32) (QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ++ /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */ ++ if (QM_GET_TX_QUEUE_LEN(prAdapter, i)) ++ ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY; /* 0 */ ++ ++ /* ++ accumulate all needed extra TC resources ++ maybe someone need + resource, maybe someone need - resource ++ */ ++ i4TotalResourceDemand += ai4PerTcResourceDemand[i]; ++ } ++ ++ /* 4 <2> Case 1: Demand <= Total Resource */ ++ if (i4TotalResourceDemand <= 0) { ++ /* 4 <2.1> Satisfy every TC */ ++ /* total TC resources are enough, no extra TC resources is needed */ ++ ++ /* adjust used TC resources to average TC resources + min reserve TC resources */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* ++ the number of resources that one TC releases can be used for ++ other TCs ++ ++ EX: TC0 au4CurrentTcResource[0] = 10 ai4PerTcResourceDemand[0] = -5 ++ TC1 au4CurrentTcResource[1] = 5 ai4PerTcResourceDemand[0] = +5 ++ => TC0 au4CurrentTcResource[0] = 10 + (-5) = 5 ++ TC1 au4CurrentTcResource[1] = 5 + (+5) = 10 ++ */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ } ++ ++ /* 4 <2.2> Share the residual resource evenly */ ++ u4ShareCount = (TC_NUM - 1); /* 5, excluding TC4 */ ++ ++ /* ++ EX: i4TotalResourceDemand = -10 ++ means we have 10 available resources can be used. ++ */ ++ u4ResidualResource = (UINT_32) (-i4TotalResourceDemand); ++ u4Share = (u4ResidualResource / u4ShareCount); ++ ++ /* share available TC resources to all TCs averagely */ ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ /* allocate residual average resources to the TC */ ++ prQM->au4CurrentTcResource[i] += u4Share; ++ ++ /* Every TC is fully satisfied so no need extra resources */ ++ ai4PerTcResourceDemand[i] = 0; ++ ++ /* decrease the allocated resources */ ++ u4ResidualResource -= u4Share; ++ } ++ ++ /* if still have available resources, we decide to give them to VO (TC3) queue */ ++ /* 4 <2.3> Allocate the left resource to TC3 (VO) */ ++ prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource); ++ ++ } ++ /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */ ++ else { ++ /* ++ u4ResidualResource means we at least need to keep ++ QM_INITIAL_RESIDUAL_TC_RESOURCE available TC resources ++ ++ in 6628, u4ResidualResource = 26, max 28 ++ */ ++ u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE; ++ ++ /* 4 <3.1> Allocated resource amount = minimum of (guaranteed, total demand) */ ++ for (i = 0; i < TC_NUM; i++) { ++ ++ if (i == TC4_INDEX) ++ continue; /* Skip TC4 (not adjustable) */ ++ ++ /* The demand can be fulfilled with the guaranteed resource amount 4 4 6 6 2 4 */ ++ ++ /* ++ ai4PerTcResourceDemand[i] = ++ ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] - ++ prQM->au4CurrentTcResource[i]); ++ ++ so au4CurrentTcResource + ai4PerTcResourceDemand = ++ ++ ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ++ prQM->au4MinReservedTcResource[i] = ++ ++ current average queue len + min TC resources ++ */ ++ if (prQM->au4CurrentTcResource[i] + ai4PerTcResourceDemand[i] < ++ prQM->au4GuaranteedTcResource[i]) { ++ ++ /* avg queue len + min reserve still smaller than guarantee so enough */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ ++ /* accumulate available TC resources from the TC */ ++ u4ResidualResource += ++ (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ai4PerTcResourceDemand[i] = 0; ++ } ++ ++ /* The demand can not be fulfilled with the guaranteed resource amount */ ++ else { ++ ++ /* means even we use all guarantee resources for the TC is still not enough */ ++ ++ /* ++ guarantee number is always for the TC so extra resource number cannot ++ include the guarantee number. ++ ++ EX: au4GuaranteedTcResource = 10, au4CurrentTcResource = 5 ++ ai4PerTcResourceDemand = 6 ++ ++ ai4PerTcResourceDemand -= (10 - 5) ==> 1 ++ only need extra 1 TC resouce is enough. ++ */ ++ ai4PerTcResourceDemand[i] -= ++ (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); ++ ++ /* update current avg TC resource to guarantee number */ ++ prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i]; ++ ++ /* count how many TC queues need to get extra resources */ ++ u4ShareCount++; ++ } ++ } ++ ++ /* 4 <3.2> Allocate the residual resource */ ++ do { ++ /* If there is no resource left, exit directly */ ++ if (u4ResidualResource == 0) ++ break; ++ ++ /* This shall not happen */ ++ if (u4ShareCount == 0) { ++ prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource; ++ DBGLOG(QM, ERROR, "QM: (Error) u4ShareCount = 0\n"); ++ break; ++ } ++ ++ /* Share the residual resource evenly */ ++ u4Share = (u4ResidualResource / u4ShareCount); ++ ++ if (u4Share) { ++ for (i = 0; i < TC_NUM; i++) { ++ /* Skip TC4 (not adjustable) */ ++ if (i == TC4_INDEX) ++ continue; ++ ++ if (ai4PerTcResourceDemand[i] == 0) ++ continue; ++ ++ if (ai4PerTcResourceDemand[i] - u4Share) { ++ /* still not enough but we just can give it u4Share resources */ ++ prQM->au4CurrentTcResource[i] += u4Share; ++ u4ResidualResource -= u4Share; ++ ai4PerTcResourceDemand[i] -= u4Share; ++ } else { ++ /* enough */ ++ prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; ++ u4ResidualResource -= ai4PerTcResourceDemand[i]; ++ ai4PerTcResourceDemand[i] = 0; ++ } ++ } ++ } ++ ++ if (u4ResidualResource == 0) ++ break; ++ /* By priority, allocate the left resource that is not divisible by u4Share */ ++ ++ if (ai4PerTcResourceDemand[TC3_INDEX]) { /* VO */ ++ prQM->au4CurrentTcResource[TC3_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC2_INDEX]) { /* VI */ ++ prQM->au4CurrentTcResource[TC2_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC5_INDEX]) { /* BMCAST */ ++ prQM->au4CurrentTcResource[TC5_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC1_INDEX]) { /* BE */ ++ prQM->au4CurrentTcResource[TC1_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ if (ai4PerTcResourceDemand[TC0_INDEX]) { /* BK */ ++ prQM->au4CurrentTcResource[TC0_INDEX]++; ++ if (--u4ResidualResource == 0) ++ break; ++ } ++ ++ /* Allocate the left resource */ ++ prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource; ++ ++ } while (FALSE); ++ } ++ ++ /* mark the flag that we can start to do TC resource adjustment after TX done handle */ ++ prQM->fgTcResourcePostAnnealing = TRUE; ++ ++#if QM_PRINT_TC_RESOURCE_CTRL ++ /* Debug print */ ++ DBGLOG(QM, LOUD, "QM: TC Rsc %u %u %u %u %u %u\n", ++ prQM->au4CurrentTcResource[0], ++ prQM->au4CurrentTcResource[1], ++ prQM->au4CurrentTcResource[2], ++ prQM->au4CurrentTcResource[3], prQM->au4CurrentTcResource[4], prQM->au4CurrentTcResource[5] ++ )); ++#endif ++ ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* RX-Related Queue Management */ ++/*----------------------------------------------------------------------------*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Init Queue Management for RX ++* ++* \param[in] (none) ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter) ++{ ++ /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */ ++ /* TODO */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle RX packets (buffer reordering) ++* ++* \param[in] prSwRfbListHead The list of RX packets ++* ++* \return The list of packets which are not buffered for reordering ++*/ ++/*----------------------------------------------------------------------------*/ ++P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) ++{ ++ ++#if CFG_RX_REORDERING_ENABLED ++ /* UINT_32 i; */ ++ P_SW_RFB_T prCurrSwRfb; ++ P_SW_RFB_T prNextSwRfb; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ QUE_T rReturnedQue; ++ PUINT_8 pucEthDestAddr; ++ BOOLEAN fgIsBMC; ++ ++ /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ ++ ++ DEBUGFUNC("qmHandleRxPackets"); ++ ++ ASSERT(prSwRfbListHead); ++ ++ QUEUE_INITIALIZE(&rReturnedQue); ++ prNextSwRfb = prSwRfbListHead; ++ ++ do { ++ prCurrSwRfb = prNextSwRfb; ++ prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb); ++ ++ prHifRxHdr = prCurrSwRfb->prHifRxHdr; /* TODO: (Tehuang) Use macro to obtain the pointer */ ++ ++ /* TODO: (Tehuang) Check if relaying */ ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST; ++ ++ /* Decide the Destination */ ++#if CFG_RX_PKTS_DUMP ++ if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) { ++ DBGLOG(SW4, INFO, "QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", ++ (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), ++ prHifRxHdr->ucStaRecIdx, prCurrSwRfb->ucWlanIdx, ++ (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */ ++ (UINT_32) HIF_RX_HDR_GET_TID(prHifRxHdr), ++ prCurrSwRfb->ucPacketType, ++ (UINT_32) HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); ++ ++ DBGLOG_MEM8(SW4, TRACE, (PUINT_8) prCurrSwRfb->pvHeader, prCurrSwRfb->u2PacketLen); ++ } ++#endif ++ ++ fgIsBMC = FALSE; ++ if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { ++ ++ UINT_8 ucNetTypeIdx; ++ P_BSS_INFO_T prBssInfo; ++ ++ pucEthDestAddr = prCurrSwRfb->pvHeader; ++ ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); ++ /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */ ++ /* */ ++ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) ++ fgIsBMC = TRUE; ++ ++ if (prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem > ++ (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM)) { ++ ++ if (!IS_BSS_ACTIVE(prBssInfo)) { ++ DBGLOG(QM, WARN, "Mark NULL the Packet for inactive Bss %u\n", ucNetTypeIdx); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ ++ if (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) { ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; ++ else if (UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr, pucEthDestAddr) && ++ bssGetClientByAddress(prBssInfo, pucEthDestAddr)) ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD; ++ /* TODO : need to check the dst mac is valid */ ++ /* If src mac is invalid, the packet will be freed in fw */ ++ } /* OP_MODE_ACCESS_POINT */ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ else if (hs20IsFrameFilterEnabled(prAdapter, prBssInfo) && ++ hs20IsUnsecuredFrame(prAdapter, prBssInfo, prCurrSwRfb)) { ++ DBGLOG(QM, WARN, ++ "Mark NULL the Packet for Dropped Packet %u\n", ucNetTypeIdx); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++#endif ++ } else { ++ /* Dont not occupy other SW RFB */ ++ DBGLOG(QM, WARN, "Mark NULL the Packet for less Free Sw Rfb\n"); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ ++ } ++#if CFG_SUPPORT_WAPI ++ if (prCurrSwRfb->u2PacketLen > ETHER_HEADER_LEN) { ++ PUINT_8 pc = (PUINT_8) prCurrSwRfb->pvHeader; ++ UINT_16 u2Etype = 0; ++ ++ u2Etype = (pc[ETH_TYPE_LEN_OFFSET] << 8) | (pc[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ /* for wapi integrity test. WPI_1x packet should be always in non-encrypted mode. ++ if we received any WPI(0x88b4) packet that is encrypted, drop here. */ ++ if (u2Etype == ETH_WPI_1X && HIF_RX_HDR_GET_SEC_MODE(prHifRxHdr) != 0) { ++ DBGLOG(QM, INFO, "drop wpi packet with sec mode\n"); ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ continue; ++ } ++ } ++#endif ++ /* BAR frame */ ++ if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue); ++ } ++ /* Reordering is not required for this packet, return it without buffering */ ++ else if (!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr) || fgIsBMC) { ++#if 0 ++ if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { ++ UINT_8 ucNetTypeIdx; ++ P_BSS_INFO_T prBssInfo; ++ ++ pucEthDestAddr = prCurrSwRfb->pvHeader; ++ ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); ++ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) ++ && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)) { ++ prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; ++ } ++ } ++#endif ++ QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); ++ } ++ /* Reordering is required for this packet */ ++ else { ++ /* If this packet should dropped or indicated to the host immediately, ++ * it should be enqueued into the rReturnedQue with specific flags. If ++ * this packet should be buffered for reordering, it should be enqueued ++ * into the reordering queue in the STA_REC rather than into the ++ * rReturnedQue. ++ */ ++ qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue); ++ ++ } ++ } while (prNextSwRfb); ++ ++ /* RX_PKT_DESTINATION_HOST_WITH_FORWARD or RX_PKT_DESTINATION_FORWARD */ ++ /* The returned list of SW_RFBs must end with a NULL pointer */ ++ if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) ++ QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); ++ ++ return (P_SW_RFB_T) QUEUE_GET_HEAD(&rReturnedQue); ++ ++#else ++ ++ /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ ++ return prSwRfbListHead; ++ ++#endif ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reorder the received packet ++* ++* \param[in] prSwRfb The RX packet to process ++* \param[out] prReturnedQue The queue for indicating packets ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ ++ UINT_32 u4SeqNo; ++ UINT_32 u4WinStart; ++ UINT_32 u4WinEnd; ++ P_QUE_T prReorderQue; ++ /* P_SW_RFB_T prReorderedSwRfb; */ ++ BOOLEAN fgIsBaTimeout; ++ ++ DEBUGFUNC("qmProcessPktWithReordering"); ++ ++ if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; ++ prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */ ++ prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ ++ ++ /* Incorrect STA_REC index */ ++ if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Check whether the STA_REC is activated */ ++ prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++#endif ++ ++ /* Check whether the BA agreement exists */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); ++ if (!prReorderQueParm) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ DBGLOG(QM, WARN, "Reordering for a NULL ReorderQueParm\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Start to reorder packets */ ++ u4SeqNo = (UINT_32) (prSwRfb->u2SSN); ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); ++ u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); ++ ++ /* Debug */ ++ /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ ++ /* Case 1: Fall within */ ++ if /* 0 - start - sn - end - 4095 */ ++ (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd)) ++ /* 0 - end - start - sn - 4095 */ ++ || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo)) ++ /* 0 - sn - end - start - 4095 */ ++ || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) { ++ ++ qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) { ++ /* Let the first received packet pass the reorder check */ ++ DBGLOG(QM, LOUD, "QM:(A)[%d](%u){%u,%u}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); ++ ++ prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo; ++ prReorderQueParm->u2WinEnd = ++ ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; ++ prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; ++ } ++#endif ++ ++ if (qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue, &fgIsBaTimeout) == FALSE) ++ STATS_RX_REORDER_HOLE_INC(prStaRec); /* record hole count */ ++ STATS_RX_REORDER_HOLE_TIMEOUT_INC(prStaRec, fgIsBaTimeout); ++ } ++ /* Case 2: Fall ahead */ ++ else if ++ /* 0 - start - end - sn - (start+2048) - 4095 */ ++ (((u4WinStart < u4WinEnd) ++ && (u4WinEnd < u4SeqNo) ++ && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT))) ++ /* 0 - sn - (start+2048) - start - end - 4095 */ ++ || ((u4SeqNo < u4WinStart) ++ && (u4WinStart < u4WinEnd) ++ && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT))) ++ /* 0 - end - sn - (start+2048) - start - 4095 */ ++ || ((u4WinEnd < u4SeqNo) ++ && (u4SeqNo < u4WinStart) ++ && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) { ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) ++ prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; ++#endif ++ ++ qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); ++ ++ /* Advance the window after inserting a new tail */ ++ prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo; ++ prReorderQueParm->u2WinStart = ++ (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1) ++ % MAX_SEQ_NO_COUNT); ++ ++ qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); ++ ++ STATS_RX_REORDER_FALL_AHEAD_INC(prStaRec); ++ ++ } ++ /* Case 3: Fall behind */ ++ else { ++ ++#if QM_RX_WIN_SSN_AUTO_ADVANCING ++#if QM_RX_INIT_FALL_BEHIND_PASS ++ if (prReorderQueParm->fgIsWaitingForPktWithSsn) { ++ /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ return; ++ } ++#endif ++#endif ++ ++ STATS_RX_REORDER_FALL_BEHIND_INC(prStaRec); ++ /* An erroneous packet */ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ ++ return; ++ } ++ ++ return; ++ ++} ++ ++VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) ++{ ++ ++ P_STA_RECORD_T prStaRec; ++ P_HIF_RX_HEADER_T prHifRxHdr; ++ P_RX_BA_ENTRY_T prReorderQueParm; ++ ++ UINT_32 u4SSN; ++ UINT_32 u4WinStart; ++ UINT_32 u4WinEnd; ++ P_QUE_T prReorderQue; ++ /* P_SW_RFB_T prReorderedSwRfb; */ ++ ++ if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prHifRxHdr = prSwRfb->prHifRxHdr; ++ prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; ++ prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */ ++ prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); ++ ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ ++ /* Incorrect STA_REC index */ ++ if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ /* Check whether the STA_REC is activated */ ++ prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++#endif ++ ++ /* Check whether the BA agreement exists */ ++ prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); ++ if (!prReorderQueParm) { ++ /* TODO: (Tehuang) Handle the Host-FW sync issue. */ ++ DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL ReorderQueParm\n"); ++ /* ASSERT(0); */ ++ return; ++ } ++ ++ u4SSN = (UINT_32) (prSwRfb->u2SSN); ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); ++ u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); ++ ++ if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) { ++ prReorderQueParm->u2WinStart = (UINT_16) u4SSN; ++ prReorderQueParm->u2WinEnd = ++ ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; ++ DBGLOG(QM, TRACE, ++ "QM:(BAR)[%d](%u){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, ++ prReorderQueParm->u2WinEnd); ++ qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); ++ } else { ++ DBGLOG(QM, TRACE, "QM:(BAR)(%d)(%u){%u,%u}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd); ++ } ++} ++ ++VOID qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_SW_RFB_T prExaminedQueuedSwRfb; ++ P_QUE_T prReorderQue; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prReorderQueParm); ++ ASSERT(prReturnedQue); ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ ++ /* There are no packets queued in the Reorder Queue */ ++ if (prExaminedQueuedSwRfb == NULL) { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->u4NumElem++; ++ } ++ ++ /* Determine the insert position */ ++ else { ++ do { ++ /* Case 1: Terminate. A duplicate packet */ ++ if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) { ++ prSwRfb->eDst = RX_PKT_DESTINATION_NULL; ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); ++ return; ++ } ++ ++ /* Case 2: Terminate. The insert point is found */ ++ else if (qmCompareSnIsLessThan((prSwRfb->u2SSN), (prExaminedQueuedSwRfb->u2SSN))) ++ break; ++ ++ /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */ ++ else ++ prExaminedQueuedSwRfb = (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext); ++ } while (prExaminedQueuedSwRfb); ++ ++ /* Update the Reorder Queue Parameters according to the found insert position */ ++ if (prExaminedQueuedSwRfb == NULL) { ++ /* The received packet shall be placed at the tail */ ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); ++ prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb); ++ } else { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb; ++ if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) { ++ /* The received packet will become the head */ ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ } else { ++ (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T) prSwRfb; ++ } ++ ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb; ++ } ++ ++ prReorderQue->u4NumElem++; ++ ++ } ++ ++} ++ ++VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_QUE_T prReorderQue; ++ ++ ASSERT(prSwRfb); ++ ASSERT(prReorderQueParm); ++ ASSERT(prReturnedQue); ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ /* There are no packets queued in the Reorder Queue */ ++ if (QUEUE_IS_EMPTY(prReorderQue)) { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; ++ } else { ++ ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; ++ ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; ++ (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); ++ } ++ prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; ++ prReorderQue->u4NumElem++; ++ ++} ++ ++BOOLEAN ++qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout) ++{ ++ P_SW_RFB_T prReorderedSwRfb; ++ P_QUE_T prReorderQue; ++ BOOLEAN fgDequeuHead, fgMissing; ++ OS_SYSTIME rCurrentTime, *prMissTimeout; ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ *fgIsTimeout = FALSE; ++ fgMissing = FALSE; ++ rCurrentTime = 0; ++ prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]); ++ if ((*prMissTimeout)) { ++ fgMissing = TRUE; ++ GET_CURRENT_SYSTIME(&rCurrentTime); ++ } ++ ++ /* Check whether any packet can be indicated to the higher layer */ ++ while (TRUE) { ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ break; ++ ++ /* Always examine the head packet */ ++ prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ fgDequeuHead = FALSE; ++ ++ /* SN == WinStart, so the head packet shall be indicated (advance the window) */ ++ if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { ++ ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ } ++ /* SN > WinStart, break to update WinEnd */ ++ else { ++ if ((fgMissing == TRUE) && ++ CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout), ++ MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) { ++ DBGLOG(QM, TRACE, ++ "QM:RX BA Timout Next Tid %d SSN %d\n", prReorderQueParm->ucTid, ++ prReorderedSwRfb->u2SSN); ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ ++ fgMissing = FALSE; ++ *fgIsTimeout = TRUE; ++ } else ++ break; ++ } ++ ++ /* Dequeue the head packet */ ++ if (fgDequeuHead) { ++ ++ if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { ++ prReorderQue->prHead = NULL; ++ prReorderQue->prTail = NULL; ++ } else { ++ prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; ++ (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; ++ } ++ prReorderQue->u4NumElem--; ++ /* DbgPrint("QM: [%d] %d (%d)\n", ++ prReorderQueParm->ucTid, ++ prReorderedSwRfb->u2PacketLen, ++ prReorderedSwRfb->u2SSN); */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); ++ } ++ } ++ ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ *prMissTimeout = 0; ++ else { ++ if (fgMissing == FALSE) ++ GET_CURRENT_SYSTIME(prMissTimeout); ++ } ++ ++ /* After WinStart has been determined, update the WinEnd */ ++ prReorderQueParm->u2WinEnd = ++ (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); ++ return QUEUE_IS_EMPTY(prReorderQue); ++} ++ ++VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) ++{ ++ P_SW_RFB_T prReorderedSwRfb; ++ P_QUE_T prReorderQue; ++ BOOLEAN fgDequeuHead; ++ ++ prReorderQue = &(prReorderQueParm->rReOrderQue); ++ ++ /* Check whether any packet can be indicated to the higher layer */ ++ while (TRUE) { ++ if (QUEUE_IS_EMPTY(prReorderQue)) ++ break; ++ ++ /* Always examine the head packet */ ++ prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); ++ fgDequeuHead = FALSE; ++ ++ /* SN == WinStart, so the head packet shall be indicated (advance the window) */ ++ if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { ++ ++ fgDequeuHead = TRUE; ++ prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); ++ } ++ ++ /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */ ++ else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN), ++ (UINT_32) (prReorderQueParm->u2WinStart))) ++ fgDequeuHead = TRUE; ++ ++ /* SN > WinStart, break to update WinEnd */ ++ else ++ break; ++ ++ /* Dequeue the head packet */ ++ if (fgDequeuHead) { ++ ++ if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { ++ prReorderQue->prHead = NULL; ++ prReorderQue->prTail = NULL; ++ } else { ++ prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; ++ (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; ++ } ++ prReorderQue->u4NumElem--; ++ /* DbgPrint("QM: [%d] %d (%d)\n", */ ++ /* prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */ ++ QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); ++ } ++ } ++ ++ /* After WinStart has been determined, update the WinEnd */ ++ prReorderQueParm->u2WinEnd = ++ (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); ++ ++} ++ ++BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater) ++{ ++ /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */ ++ if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) /* Shall be <= */ ++ return FALSE; ++ ++ /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */ ++ else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) ++ return TRUE; ++ ++ /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */ ++ /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */ ++ else if (u4SnLess < u4SnGreater) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle Mailbox RX messages ++* ++* \param[in] prMailboxRxMsg The received Mailbox message from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg) ++{ ++ /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */ ++ /* TODO */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle ADD RX BA Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_RX_ADDBA_T prEventRxAddBa; ++ P_STA_RECORD_T prStaRec; ++ UINT_32 u4Tid; ++ UINT_32 u4WinSize; ++ ++ DBGLOG(QM, INFO, "QM:Event +RxBa\n"); ++ ++ prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx); ++ ++ if (!prStaRec) { ++ /* Invalid STA_REC index, discard the event packet */ ++ /* ASSERT(0); */ ++ DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"); ++ return; ++ } ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ ++ DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"); ++ /* ASSERT(0); */ ++ /* return; */ ++ } ++#endif ++ ++ u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK) ++ >> BA_PARAM_SET_TID_MASK_OFFSET); ++ ++ u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK) ++ >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET); ++ ++ if (!qmAddRxBaEntry(prAdapter, ++ prStaRec->ucIndex, ++ (UINT_8) u4Tid, ++ (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN), (UINT_16) u4WinSize)) { ++ ++ /* FW shall ensure the availabiilty of the free-to-use BA entry */ ++ DBGLOG(QM, ERROR, "QM: (Error) qmAddRxBaEntry() failure\n"); ++ ASSERT(0); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle DEL RX BA Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_RX_DELBA_T prEventRxDelBa; ++ P_STA_RECORD_T prStaRec; ++ ++ /* DbgPrint("QM:Event -RxBa\n"); */ ++ ++ prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx); ++ ++ if (!prStaRec) ++ /* Invalid STA_REC index, discard the event packet */ ++ /* ASSERT(0); */ ++ return; ++#if 0 ++ if (!(prStaRec->fgIsValid)) ++ /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ ++ /* ASSERT(0); */ ++ return; ++#endif ++ ++ qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE); ++ ++} ++ ++P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid) ++{ ++ int i; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */ ++ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (prQM->arRxBaTable[i].fgIsValid) { ++ if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) && (prQM->arRxBaTable[i].ucTid == ucTid)) ++ return &prQM->arRxBaTable[i]; ++ } ++ } ++ return NULL; ++} ++ ++BOOLEAN ++qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, ++ IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize) ++{ ++ int i; ++ P_RX_BA_ENTRY_T prRxBaEntry = NULL; ++ P_STA_RECORD_T prStaRec; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { ++ /* Invalid STA_REC index, discard the event packet */ ++ DBGLOG(QM, WARN, "QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx); ++ return FALSE; ++ } ++ ++ prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; ++ ASSERT(prStaRec); ++ ++ /* if(!(prStaRec->fgIsValid)){ */ ++ /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */ ++ /* return FALSE; */ ++ /* } */ ++ ++ /* 4 <1> Delete before adding */ ++ /* Remove the BA entry for the same (STA, TID) tuple if it exists */ ++ if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) ++ qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */ ++ /* 4 <2> Add a new BA entry */ ++ /* No available entry to store the BA agreement info. Retrun FALSE. */ ++ if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) { ++ DBGLOG(QM, ERROR, "QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount); ++ return FALSE; ++ } ++ /* Find the free-to-use BA entry */ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ if (!prQM->arRxBaTable[i].fgIsValid) { ++ prRxBaEntry = &(prQM->arRxBaTable[i]); ++ prQM->ucRxBaCount++; ++ DBGLOG(QM, LOUD, "QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); ++ break; ++ } ++ } ++ /* If a free-to-use entry is found, configure it and associate it with the STA_REC */ ++ u2WinSize += CFG_RX_BA_INC_SIZE; ++ if (prRxBaEntry) { ++ prRxBaEntry->ucStaRecIdx = ucStaRecIdx; ++ prRxBaEntry->ucTid = ucTid; ++ prRxBaEntry->u2WinStart = u2WinStart; ++ prRxBaEntry->u2WinSize = u2WinSize; ++ prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT); ++ prRxBaEntry->fgIsValid = TRUE; ++ prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE; ++ ++ g_arMissTimeout[ucStaRecIdx][ucTid] = 0; ++ ++ DBGLOG(QM, INFO, "QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n", ++ ucStaRecIdx, ucTid, ++ prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize); ++ ++ /* Update the BA entry reference table for per-packet lookup */ ++ prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry; ++ } else { ++ /* This shall not happen because FW should keep track of the usage of RX BA entries */ ++ DBGLOG(QM, ERROR, "QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost) ++{ ++ P_RX_BA_ENTRY_T prRxBaEntry; ++ P_STA_RECORD_T prStaRec; ++ P_SW_RFB_T prFlushedPacketList = NULL; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); ++ ++ prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; ++ ASSERT(prStaRec); ++ ++#if 0 ++ if (!(prStaRec->fgIsValid)) { ++ DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n"); ++ return; ++ } ++#endif ++ ++ /* Remove the BA entry for the same (STA, TID) tuple if it exists */ ++ prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid]; ++ ++ if (prRxBaEntry) { ++ ++ prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid); ++ ++ if (prFlushedPacketList) { ++ ++ if (fgFlushToHost) { ++ wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList); ++ } else { ++ ++ P_SW_RFB_T prSwRfb; ++ P_SW_RFB_T prNextSwRfb; ++ ++ prSwRfb = prFlushedPacketList; ++ ++ do { ++ prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); ++ nicRxReturnRFB(prAdapter, prSwRfb); ++ prSwRfb = prNextSwRfb; ++ } while (prSwRfb); ++ ++ } ++ ++ } ++#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0)) ++ /* Update RX BA entry state. Note that RX queue flush is not done here */ ++ prRxBaEntry->fgIsValid = FALSE; ++ prQM->ucRxBaCount--; ++ ++ /* Debug */ ++#if 0 ++ DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); ++#endif ++ ++ /* Update STA RX BA table */ ++ prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL; ++#endif ++ ++ DBGLOG(QM, INFO, "QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid); ++ ++ } ++ ++ /* Debug */ ++#if CFG_HIF_RX_STARVATION_WARNING ++ { ++ P_RX_CTRL_T prRxCtrl; ++ ++ prRxCtrl = &prAdapter->rRxCtrl; ++ DBGLOG(QM, TRACE, ++ "QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, ++ prRxCtrl->u4DequeuedCnt); ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To process WMM related IEs in ASSOC_RSP ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ PUINT_8 pucIEStart; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ UINT_8 ucQosInfo; ++ UINT_8 ucQosInfoAC; ++ UINT_8 ucBmpAC; ++ ++ DEBUGFUNC("mqmProcessAssocReq"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->fgIsQoS = FALSE; ++ prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; ++ ++ pucIEStart = pucIE; ++ ++ /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ /* Determine whether QoS is enabled with the association */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ prStaRec->fgIsWmmSupported = TRUE; ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE; ++ ucQosInfo = prIeWmmInfo->ucQosInfo; ++ ucQosInfoAC = ucQosInfo & BITS(0, 3); ++ ++ prStaRec->fgIsUapsdSupported = ((ucQosInfoAC) ? TRUE : FALSE) & ++ prAdapter->rWifiVar.fgSupportUAPSD; ++ ++ ucBmpAC = 0; ++ ++ if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) ++ ucBmpAC |= BIT(ACI_VO); ++ if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) ++ ucBmpAC |= BIT(ACI_VI); ++ if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) ++ ucBmpAC |= BIT(ACI_BE); ++ if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) ++ ucBmpAC |= BIT(ACI_BK); ++ ++ prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC; ++ ++ prStaRec->ucUapsdSp = ++ (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5; ++ break; ++ default: ++ /* Other WMM QoS IEs. Ignore any */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ ++ ++ break; ++ ++ case ELEM_ID_HT_CAP: ++ /* Some client won't put the WMM IE if client is 802.11n */ ++ if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ DBGLOG(QM, TRACE, "MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To process WMM related IEs in ASSOC_RSP ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ PUINT_8 pucIEStart; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ DEBUGFUNC("mqmProcessAssocRsp"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ prStaRec->fgIsQoS = FALSE; ++ ++ pucIEStart = pucIE; ++ ++ DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n", ++ prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS); ++ ++ /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ ++ /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */ ++ if ((!prAdapter->rWifiVar.fgSupportQoS)) ++ return; ++ ++ /* Determine whether QoS is enabled with the association */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ ++ default: ++ /* Other WMM QoS IEs. Ignore any */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ ++ break; ++ ++ case ELEM_ID_HT_CAP: ++ /* Some AP won't put the WMM IE if client is 802.11n */ ++ if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) ++ prStaRec->fgIsQoS = TRUE; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Parse AC parameters and write to HW CRs */ ++ if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) { ++ mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE); ++#if ARP_MONITER_ENABLE ++ qmResetArpDetect(); ++#endif ++ } ++ ++ DBGLOG(QM, TRACE, "MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); ++ if (prStaRec->fgIsWmmSupported) ++ nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp) ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prSwRfb The received frame ++* \param[in] pucIE The pointer to the first IE in the frame ++* \param[in] u2IELength The total length of IEs in the frame ++* \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs. ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, ++ IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride) ++{ ++ P_STA_RECORD_T prStaRec; ++ UINT_16 u2Offset; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ P_BSS_INFO_T prBssInfo; ++ P_AC_QUE_PARMS_T prAcQueParams; ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ ENUM_WMM_ACI_T eAci; ++ PUINT_8 pucWmmParamSetCount; ++ ++ DEBUGFUNC("mqmParseEdcaParameters"); ++ ++ ASSERT(prSwRfb); ++ ASSERT(pucIE); ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); ++ ASSERT(prStaRec); ++ if (prStaRec == NULL) ++ return; ++ ++ DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n", prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS); ++ ++ if ((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)) ++ return; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ /* Goal: Obtain the EDCA parameters */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) != VENDOR_OUI_TYPE_WMM) || ++ (kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) ++ break; ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Param IE with a wrong length */ ++ ++ pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount); ++ prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE; ++ ++ /* Check the Parameter Set Count to determine whether EDCA parameters */ ++ /* have been changed */ ++ if (!fgForceOverride && (*pucWmmParamSetCount ++ == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT))) ++ break; /* Ignore the IE without updating HW CRs */ ++ ++ /* Update Parameter Set Count */ ++ *pucWmmParamSetCount = ++ (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* Update EDCA parameters */ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ prAcQueParams = &prBssInfo->arACQueParms[eAci]; ++ mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams); ++ ++ prAcQueParams->fgIsACMSet = ++ (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE; ++ prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN; ++ ++ DBGLOG(QM, LOUD, ++ "eAci:%d, ACM:%d, Aifsn:%d, CWmin:%d, CWmax:%d, TxopLmt:%d\n", ++ eAci, prAcQueParams->fgIsACMSet, prAcQueParams->u2Aifsn, ++ prAcQueParams->u2CWmin, prAcQueParams->u2CWmax, ++ prAcQueParams->u2TxopLimit); ++ } ++ break; ++ default: ++ /* Other WMM QoS IEs. Ignore */ ++ break; ++ } ++ ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prIeWmmParam The pointer to the WMM Parameter IE ++* \param[in] u4AcOffset The offset specifying the AC queue for parsing ++* \param[in] prHwAcParams The parameter structure used to configure the HW CRs ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams) ++{ ++ prAcQueParams->u2Aifsn = *((PUINT_8) (&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4)); ++ ++ prAcQueParams->u2CWmax = BIT(((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK) ++ >> WMM_ECW_WMAX_OFFSET) - 1; ++ ++ prAcQueParams->u2CWmin = ++ BIT((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK) - 1; ++ ++ WLAN_GET_FIELD_16(((PUINT_8) (&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)), ++ &(prAcQueParams->u2TxopLimit)); ++ ++ prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To parse WMM/11n related IEs in scan results (only for AP peers) ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prScanResult The scan result which shall be parsed to obtain needed info ++* \param[out] prStaRec The obtained info is stored in the STA_REC ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++#if (CFG_SUPPORT_TDLS == 1) /* for test purpose */ ++BOOLEAN flgTdlsTestExtCapElm = FALSE; ++UINT8 aucTdlsTestExtCapElm[7]; ++#endif /* CFG_SUPPORT_TDLS */ ++VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec) ++{ ++ PUINT_8 pucIE; ++ UINT_16 u2IELength; ++ UINT_16 u2Offset; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ DEBUGFUNC("mqmProcessScanResult"); ++ ++ ASSERT(prScanResult); ++ ASSERT(prStaRec); ++ ++ /* Reset the flag before parsing */ ++ prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; ++ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ u2IELength = prScanResult->u2IELength; ++ pucIE = prScanResult->aucIEBuf; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* TDLS test purpose */ ++ if (flgTdlsTestExtCapElm == TRUE) ++ TdlsexBssExtCapParse(prStaRec, aucTdlsTestExtCapElm); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */ ++ IE_FOR_EACH(pucIE, u2IELength, u2Offset) { ++ switch (IE_ID(pucIE)) { ++ case ELEM_ID_EXTENDED_CAP: ++#if (CFG_SUPPORT_TDLS == 1) ++ TdlsexBssExtCapParse(prStaRec, pucIE); ++#endif /* CFG_SUPPORT_TDLS */ ++ break; ++ ++ case ELEM_ID_WMM: ++ if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && ++ (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { ++ ++ switch (WMM_IE_OUI_SUBTYPE(pucIE)) { ++ case VENDOR_OUI_SUBTYPE_WMM_PARAM: ++ if (IE_LEN(pucIE) != 24) ++ break; /* WMM Param IE with a wrong length */ ++ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = ++ (((((P_IE_WMM_PARAM_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? ++ TRUE : FALSE); ++ break; ++ ++ case VENDOR_OUI_SUBTYPE_WMM_INFO: ++ if (IE_LEN(pucIE) != 7) ++ break; /* WMM Info IE with a wrong length */ ++ ++ prStaRec->fgIsWmmSupported = TRUE; ++ prStaRec->fgIsUapsdSupported = ++ (((((P_IE_WMM_INFO_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? ++ TRUE : FALSE); ++ break; ++ ++ default: ++ /* A WMM QoS IE that doesn't matter. Ignore it. */ ++ break; ++ } ++ } ++ /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ ++ ++ break; ++ ++ default: ++ /* A WMM IE that doesn't matter. Ignore it. */ ++ break; ++ } ++ } ++ DBGLOG(QM, LOUD, "MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n", ++ prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported); ++ ++} ++ ++UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) ++{ ++ UINT_32 i; ++ P_STA_RECORD_T prTempStaRec; ++ ++ prTempStaRec = NULL; ++ ++ ASSERT(prAdapter); ++ ++ /* 4 <1> DA = BMCAST */ ++ if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) ++ return STA_REC_INDEX_BMCAST; ++ /* 4 <2> Check if an AP STA is present */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if ((prTempStaRec->ucNetTypeIndex == eNetworkType) ++ && (prTempStaRec->fgIsAp) ++ && (prTempStaRec->fgIsValid)) { ++ return prTempStaRec->ucIndex; ++ } ++ } ++ ++ /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ ++ for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { ++ prTempStaRec = &(prAdapter->arStaRec[i]); ++ if (prTempStaRec->fgIsValid) { ++ if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)) ++ return prTempStaRec->ucIndex; ++ } ++ } ++ ++ /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ ++ return STA_REC_INDEX_NOT_FOUND; ++} ++ ++UINT_32 ++mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, ++ UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf) ++{ ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ UINT_32 ucUapsd[] = { ++ WMM_QOS_INFO_BE_UAPSD, ++ WMM_QOS_INFO_BK_UAPSD, ++ WMM_QOS_INFO_VI_UAPSD, ++ WMM_QOS_INFO_VO_UAPSD ++ }; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ ASSERT(pOutBuf); ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) pOutBuf; ++ ++ prIeWmmInfo->ucId = ELEM_ID_WMM; ++ prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmInfo->aucOui[0] = aucWfaOui[0]; ++ prIeWmmInfo->aucOui[1] = aucWfaOui[1]; ++ prIeWmmInfo->aucOui[2] = aucWfaOui[2]; ++ prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; ++ ++ prIeWmmInfo->ucVersion = VERSION_WMM; ++ prIeWmmInfo->ucQosInfo = 0; ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (fgSupportUAPSD) { ++ ++ UINT_8 ucQosInfo = 0; ++ UINT_8 i; ++ ++ /* Static U-APSD setting */ ++ for (i = ACI_BE; i <= ACI_VO; i++) { ++ if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) ++ ucQosInfo |= (UINT_8) ucUapsd[i]; ++ } ++ ++ if (ucBmpDeliveryAC & ucBmpTriggerAC) { ++ switch (ucUapsdSp) { ++ case WMM_MAX_SP_LENGTH_ALL: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_2: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_4: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_6: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; ++ break; ++ ++ default: ++ DBGLOG(QM, WARN, "MQM: Incorrect SP length\n"); ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ } ++ } ++ prIeWmmInfo->ucQosInfo = ucQosInfo; ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ return IE_SIZE(prIeWmmInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Generate the WMM Info IE ++* ++* \param[in] prAdapter Adapter pointer ++* @param prMsduInfo The TX MMPDU ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_WMM_INFO_T prIeWmmInfo; ++ P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("mqmGenerateWmmInfoIE"); ++ ++ ASSERT(prMsduInfo); ++ ++ /* In case QoS is not turned off, exit directly */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ASSERT(prStaRec); ++ ++ if (prStaRec == NULL) ++ return; ++ ++ if (!prStaRec->fgIsWmmSupported) ++ return; ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); ++ ++ prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; ++ ++ prIeWmmInfo = (P_IE_WMM_INFO_T) ++ ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ prIeWmmInfo->ucId = ELEM_ID_WMM; ++ prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmInfo->aucOui[0] = aucWfaOui[0]; ++ prIeWmmInfo->aucOui[1] = aucWfaOui[1]; ++ prIeWmmInfo->aucOui[2] = aucWfaOui[2]; ++ prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; ++ ++ prIeWmmInfo->ucVersion = VERSION_WMM; ++ prIeWmmInfo->ucQosInfo = 0; ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++/* if(prAdapter->rWifiVar.fgSupportUAPSD){ */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported) { ++ ++ UINT_8 ucQosInfo = 0; ++ UINT_8 i; ++ ++ /* Static U-APSD setting */ ++ for (i = ACI_BE; i <= ACI_VO; i++) { ++ if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)) ++ ucQosInfo |= (UINT_8) ucUapsd[i]; ++ } ++ ++ if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) { ++ switch (prPmProfSetupInfo->ucUapsdSp) { ++ case WMM_MAX_SP_LENGTH_ALL: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_2: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_4: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; ++ break; ++ ++ case WMM_MAX_SP_LENGTH_6: ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; ++ break; ++ ++ default: ++ DBGLOG(QM, INFO, "MQM: Incorrect SP length\n"); ++ ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; ++ break; ++ } ++ } ++ prIeWmmInfo->ucQosInfo = ucQosInfo; ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo); ++#else ++ ++ prMsduInfo->u2FrameLength += mqmGenerateWmmInfoIEByParam((prAdapter->rWifiVar.fgSupportUAPSD ++ && prStaRec->fgIsUapsdSupported), ++ prPmProfSetupInfo->ucBmpDeliveryAC, ++ prPmProfSetupInfo->ucBmpTriggerAC, ++ prPmProfSetupInfo->ucUapsdSp, (UINT_8 *) prIeWmmInfo); ++#endif ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief log2 calculation for CW ++* ++* @param[in] val value ++* ++* @return log2(val) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++UINT_32 cwlog2(UINT_32 val) ++{ ++ ++ UINT_32 n; ++ ++ n = 0; ++ ++ while (val >= 512) { ++ n += 9; ++ val = val >> 9; ++ } ++ while (val >= 16) { ++ n += 4; ++ val >>= 4; ++ } ++ while (val >= 2) { ++ n += 1; ++ val >>= 1; ++ } ++ return n; ++} ++#endif ++ ++UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, ++ P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode) ++{ ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ UINT_8 aucACI[] = { ++ WMM_ACI_AC_BE, ++ WMM_ACI_AC_BK, ++ WMM_ACI_AC_VI, ++ WMM_ACI_AC_VO ++ }; ++ ENUM_WMM_ACI_T eAci; ++ UCHAR *pucAciAifsn, *pucEcw, *pucTxopLimit; ++ ++ ASSERT(pOutBuf); ++ ++ prIeWmmParam = (P_IE_WMM_PARAM_T) pOutBuf; ++ ++ prIeWmmParam->ucId = ELEM_ID_WMM; ++ prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmParam->aucOui[0] = aucWfaOui[0]; ++ prIeWmmParam->aucOui[1] = aucWfaOui[1]; ++ prIeWmmParam->aucOui[2] = aucWfaOui[2]; ++ prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; ++ ++ prIeWmmParam->ucVersion = VERSION_WMM; ++ prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD) { ++ if (ucOpMode == OP_MODE_INFRASTRUCTURE) ++ prIeWmmParam->ucQosInfo = 0xf; ++ else ++ prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; ++ } ++ ++ /* EDCA parameter */ ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ /* DBGLOG(QM, LOUD, */ ++ /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ ++ /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ ++ ++#if 0 ++ *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].fgIsACMSet ? ++ WMM_ACIAIFSN_ACM : 0) ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].u2Aifsn & ++ (WMM_ACIAIFSN_AIFSN))); ++#else ++ /* avoid compile warnings in Klockwork tool */ ++ if (eAci == WMM_AC_BE_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_BE; ++ pucEcw = &prIeWmmParam->ucEcw_BE; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_BE; ++ } else if (eAci == WMM_AC_BK_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_BG; ++ pucEcw = &prIeWmmParam->ucEcw_BG; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_BG; ++ } else if (eAci == WMM_AC_VI_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_VI; ++ pucEcw = &prIeWmmParam->ucEcw_VI; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_VI; ++ } else if (eAci == WMM_AC_VO_INDEX) { ++ pucAciAifsn = &prIeWmmParam->ucAciAifsn_VO; ++ pucEcw = &prIeWmmParam->ucEcw_VO; ++ pucTxopLimit = prIeWmmParam->aucTxopLimit_VO; ++ } ++ ++ *pucAciAifsn = (UINT_8) (aucACI[eAci] ++ | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM : 0) ++ | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN))); ++#endif ++ ++#if 1 ++/* *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0 */ ++ *pucEcw = (UINT_8) (0 | (((prBssInfo->aucCWminLog2ForBcast[eAci])) & WMM_ECW_WMIN_MASK) ++ | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci])) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#else ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmin + ++ 1)) & WMM_ECW_WMIN_MASK) ++ | ++ ((cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmax + ++ 1)) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#endif ++ ++#if 0 ++ WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) ++ , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++#else ++ WLAN_SET_FIELD_16(pucTxopLimit, prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++#endif ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ return IE_SIZE(prIeWmmParam); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Generate the WMM Param IE ++* ++* \param[in] prAdapter Adapter pointer ++* @param prMsduInfo The TX MMPDU ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ P_IE_WMM_PARAM_T prIeWmmParam; ++ ++#if 0 ++ UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; ++ ++ UINT_8 aucACI[] = { ++ WMM_ACI_AC_BE, ++ WMM_ACI_AC_BK, ++ WMM_ACI_AC_VI, ++ WMM_ACI_AC_VO ++ }; ++ ENUM_WMM_ACI_T eAci; ++#endif ++ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ ++ DEBUGFUNC("mqmGenerateWmmParamIE"); ++ DBGLOG(QM, LOUD, "\n"); ++ ++ ASSERT(prMsduInfo); ++ ++ /* In case QoS is not turned off, exit directly */ ++ if (!prAdapter->rWifiVar.fgSupportQoS) ++ return; ++ ++ prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); ++ ++ if (prStaRec) { ++ if (!prStaRec->fgIsQoS) ++ return; ++ } ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); ++ ++ if (!prBssInfo->fgIsQBSS) ++ return; ++/* 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. */ ++#if 0 ++ if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT && prBssInfo->eCurrentOPMode != OP_MODE_BOW) ++ return; ++#endif ++ ++ prIeWmmParam = (P_IE_WMM_PARAM_T) ++ ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); ++ ++#if 0 ++ prIeWmmParam->ucId = ELEM_ID_WMM; ++ prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; ++ ++ /* WMM-2.2.1 WMM Information Element Field Values */ ++ prIeWmmParam->aucOui[0] = aucWfaOui[0]; ++ prIeWmmParam->aucOui[1] = aucWfaOui[1]; ++ prIeWmmParam->aucOui[2] = aucWfaOui[2]; ++ prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; ++ prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; ++ ++ prIeWmmParam->ucVersion = VERSION_WMM; ++ prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); ++ ++ /* UAPSD initial queue configurations (delivery and trigger enabled) */ ++ if (prAdapter->rWifiVar.fgSupportUAPSD) ++ prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; ++ ++ /* EDCA parameter */ ++ ++ for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { ++ ++ /* DBGLOG(QM, LOUD, */ ++ /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ ++ /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ ++ /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ ++ ++ *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].fgIsACMSet ? ++ WMM_ACIAIFSN_ACM : 0) ++ | ++ (prBssInfo->arACQueParmsForBcast ++ [eAci].u2Aifsn & ++ (WMM_ACIAIFSN_AIFSN))); ++#if 1 ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (((prBssInfo->aucCWminLog2ForBcast ++ [eAci])) & WMM_ECW_WMIN_MASK) ++ | ++ ((((prBssInfo->aucCWmaxLog2ForBcast ++ [eAci])) << WMM_ECW_WMAX_OFFSET) ++ & WMM_ECW_WMAX_MASK) ++ ); ++#else ++ *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 ++ | ++ (cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmin + ++ 1)) & WMM_ECW_WMIN_MASK) ++ | ++ ((cwlog2 ++ ((prBssInfo->arACQueParmsForBcast ++ [eAci].u2CWmax + ++ 1)) << WMM_ECW_WMAX_OFFSET) & ++ WMM_ECW_WMAX_MASK) ++ ); ++#endif ++ ++ WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) ++ , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); ++ ++ } ++ ++ /* Increment the total IE length for the Element ID and Length fields. */ ++ prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam); ++#else ++ ++ prMsduInfo->u2FrameLength += mqmGenerateWmmParamIEByParam(prAdapter, ++ prBssInfo, (UINT_8 *) prIeWmmParam, OP_MODE_ACCESS_POINT); ++#endif ++} ++ ++ENUM_FRAME_ACTION_T ++qmGetFrameAction(IN P_ADAPTER_T prAdapter, ++ IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, ++ IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType) ++{ ++ P_BSS_INFO_T prBssInfo; ++ P_STA_RECORD_T prStaRec; ++ P_WLAN_MAC_HEADER_T prWlanFrame; ++ UINT_16 u2TxFrameCtrl; ++ ++ DEBUGFUNC("qmGetFrameAction"); ++ ++#if (NIC_TX_BUFF_COUNT_TC4 > 2) ++#define QM_MGMT_QUUEUD_THRESHOLD 2 ++#else ++#define QM_MGMT_QUUEUD_THRESHOLD 1 ++#endif ++ ++ DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4)); ++ DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0); ++ ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]); ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx); ++ ++ /* XXX Check BOW P2P AIS time ot set active */ ++ if (!IS_BSS_ACTIVE(prBssInfo)) { ++ if (eFrameType == FRAME_TYPE_MMPDU) { ++ prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; ++ u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ ++ if (((u2TxFrameCtrl == MAC_FRAME_DEAUTH) ++ && (prMsduInfo->pfTxDoneHandler == NULL)) ++ || (u2TxFrameCtrl == MAC_FRAME_ACTION)) /* whsu */ ++ return FRAME_ACTION_TX_PKT; ++ } ++ ++ DBGLOG(QM, WARN, "Drop packets Action, eFrameType: %d (Bss Index %u).\n", ++ eFrameType, prBssInfo->ucNetTypeIndex); ++ TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); ++ return FRAME_ACTION_DROP_PKT; ++ } ++ ++ /* TODO Handle disconnect issue */ ++ ++ /* P2P probe Request frame */ ++ do { ++ if (eFrameType == FRAME_TYPE_MMPDU) { ++ prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; ++ u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ ++ ++ if (u2TxFrameCtrl == MAC_FRAME_BEACON) { ++ if (prBssInfo->fgIsNetAbsent) ++ return FRAME_ACTION_DROP_PKT; ++ } else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { ++ if (prBssInfo->fgIsNetAbsent) ++ return FRAME_ACTION_DROP_PKT; ++ } else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) { ++ if (prBssInfo->fgIsNetAbsent) ++ break; ++ DBGLOG(P2P, LOUD, "Sending DEAUTH Frame\n"); ++ return FRAME_ACTION_TX_PKT; ++ } ++ /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */ ++ else if (u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ ++ || u2TxFrameCtrl == MAC_FRAME_AUTH ++ || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ ++ || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ || u2TxFrameCtrl == MAC_FRAME_ACTION) { ++ ++ if ((prStaRec) && (prStaRec->fgIsInPS)) { ++ if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) ++ return FRAME_ACTION_TX_PKT; ++ else ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ return FRAME_ACTION_TX_PKT; ++ } ++ ++ if (!prStaRec) ++ return FRAME_ACTION_TX_PKT; ++ ++ if (!prStaRec->fgIsInUse) ++ return FRAME_ACTION_DROP_PKT; ++ ++ } /* FRAME_TYPE_MMPDU */ ++ else if (eFrameType == FRAME_TYPE_802_1X) { ++ ++ if (!prStaRec) ++ return FRAME_ACTION_TX_PKT; ++ ++ if (!prStaRec->fgIsInUse) ++ return FRAME_ACTION_DROP_PKT; ++ if (prStaRec->fgIsInPS) { ++ if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) ++ return FRAME_ACTION_TX_PKT; ++ else ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ ++ } /* FRAME_TYPE_802_1X */ ++ else if ((!IS_BSS_ACTIVE(prBssInfo)) ++ || (!prStaRec) ++ || (!prStaRec->fgIsInUse)) { ++ return FRAME_ACTION_DROP_PKT; ++ } ++ } while (0); ++ ++ if (prBssInfo->fgIsNetAbsent) { ++ DBGLOG(QM, LOUD, "Queue packets (Absent %u).\n", prBssInfo->ucNetTypeIndex); ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ ++ if (prStaRec && prStaRec->fgIsInPS) { ++ DBGLOG(QM, LOUD, "Queue packets (PS %u).\n", prStaRec->fgIsInPS); ++ return FRAME_ACTION_QUEUE_PKT; ++ } ++ switch (eFrameType) { ++ case FRAME_TYPE_802_1X: ++ if (!prStaRec->fgIsValid) ++ return FRAME_ACTION_QUEUE_PKT; ++ break; ++ ++ case FRAME_TYPE_MMPDU: ++ break; ++ ++ default: ++ ASSERT(0); ++ } ++ ++ return FRAME_ACTION_TX_PKT; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle BSS change operation Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus; ++ P_BSS_INFO_T prBssInfo; ++ BOOLEAN fgIsNetAbsentOld; ++ ++ prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent; ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]); ++ fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent; ++ prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent; ++ prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota; ++ ++ /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */ ++ /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */ ++ ++ DBGLOG(QM, INFO, "NAF=%d,%d,%d\n", ++ prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota); ++ ++ if (!prBssInfo->fgIsNetAbsent) { ++ /* QM_DBG_CNT_27 */ ++ QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27); ++ } else { ++ /* QM_DBG_CNT_28 */ ++ QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28); ++ } ++ /* From Absent to Present */ ++ if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) ++ kalSetEvent(prAdapter->prGlueInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Handle STA change PS mode Event from the FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode; ++ P_STA_RECORD_T prStaRec; ++ BOOLEAN fgIsInPSOld; ++ ++ /* DbgPrint("QM:Event -RxBa\n"); */ ++ ++ prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ ++ fgIsInPSOld = prStaRec->fgIsInPS; ++ prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs; ++ ++ qmUpdateFreeQuota(prAdapter, ++ prStaRec, ++ prEventStaChangePsMode->ucUpdateMode, prEventStaChangePsMode->ucFreeQuota, 0); ++ ++ /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */ ++ /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */ ++ ++ DBGLOG(QM, TRACE, "PS=%d,%d\n", prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS); ++ ++ /* From PS to Awake */ ++ if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update STA free quota Event from FW ++* ++* \param[in] prAdapter Adapter pointer ++* \param[in] prEvent The event packet from the FW ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) ++{ ++ P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota; ++ P_STA_RECORD_T prStaRec; ++ ++ prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent; ++ prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx); ++ ASSERT(prStaRec); ++ ++ if (prStaRec) { ++ if (prStaRec->fgIsInPS) { ++ qmUpdateFreeQuota(prAdapter, ++ prStaRec, ++ prEventStaUpdateFreeQuota->ucUpdateMode, ++ prEventStaUpdateFreeQuota->ucFreeQuota, ++ prEventStaUpdateFreeQuota->aucReserved[0]); ++ ++ kalSetEvent(prAdapter->prGlueInfo); ++ } ++#if 0 ++ DBGLOG(QM, TRACE, ++ "qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n", ++ prEventStaUpdateFreeQuota->ucStaRecIdx, prEventStaUpdateFreeQuota->ucUpdateMode, ++ prEventStaUpdateFreeQuota->ucFreeQuota); ++#endif ++ ++ DBGLOG(QM, TRACE, "UFQ=%d,%d,%d\n", ++ prEventStaUpdateFreeQuota->ucStaRecIdx, ++ prEventStaUpdateFreeQuota->ucUpdateMode, prEventStaUpdateFreeQuota->ucFreeQuota); ++ ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Update STA free quota ++* ++* \param[in] prStaRec the STA ++* \param[in] ucUpdateMode the method to update free quota ++* \param[in] ucFreeQuota the value for update ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, ++ IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone) ++{ ++ ++ UINT_8 ucFreeQuotaForNonDelivery; ++ UINT_8 ucFreeQuotaForDelivery; ++ BOOLEAN flgIsUpdateForcedToDelivery; ++ ++ ASSERT(prStaRec); ++ DBGLOG(QM, LOUD, "qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n", ++ prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota); ++ ++ if (!prStaRec->fgIsInPS) ++ return; ++ ++ flgIsUpdateForcedToDelivery = FALSE; ++ ++ if (ucNumOfTxDone > 0) { ++ /* ++ update free quota by ++ num of tx done + resident free quota (delivery + non-delivery) ++ */ ++ UINT_8 ucAvailQuota; ++ ++ ucAvailQuota = ucNumOfTxDone + prStaRec->ucFreeQuotaForDelivery + prStaRec->ucFreeQuotaForNonDelivery; ++ if (ucAvailQuota > ucFreeQuota) /* sanity check */ ++ ucAvailQuota = ucFreeQuota; ++ ++ /* update current free quota */ ++ ucFreeQuota = ucAvailQuota; ++ ++ /* check if the update is from last packet */ ++ if (ucFreeQuota == (prStaRec->ucFreeQuota + 1)) { ++ /* just add the extra quota to delivery queue */ ++ ++ /* ++ EX: ++ 1. TDLS peer enters power save ++ 2. When the last 2 VI packets are tx done, we will receive 2 update events ++ 3. 1st update event: ucFreeQuota = 9 ++ 4. We will correct new quota for delivey and non-delivery to 7:2 ++ 5. 2rd update event: ucFreeQuota = 10 ++ 6. We will re-correct new quota for delivery and non-delivery to 5:5 ++ ++ But non-delivery queue is not busy. ++ So in the case, we will have wrong decision, i.e. higher queue always quota 5 ++ ++ Solution: skip the 2rd update event and just add the extra quota to delivery. ++ */ ++ ++ flgIsUpdateForcedToDelivery = TRUE; ++ } ++ } ++ ++ switch (ucUpdateMode) { ++ case FREE_QUOTA_UPDATE_MODE_INIT: ++ case FREE_QUOTA_UPDATE_MODE_OVERWRITE: ++ prStaRec->ucFreeQuota = ucFreeQuota; ++ break; ++ case FREE_QUOTA_UPDATE_MODE_INCREASE: ++ prStaRec->ucFreeQuota += ucFreeQuota; ++ break; ++ case FREE_QUOTA_UPDATE_MODE_DECREASE: ++ prStaRec->ucFreeQuota -= ucFreeQuota; ++ break; ++ default: ++ ASSERT(0); ++ } ++ ++ DBGLOG(QM, LOUD, "qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota); ++ ++ ucFreeQuota = prStaRec->ucFreeQuota; ++ ++ ucFreeQuotaForNonDelivery = 0; ++ ucFreeQuotaForDelivery = 0; ++ ++ if (ucFreeQuota > 0) { ++ if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported ++ /* && prAdapter->rWifiVar.fgSupportQoS ++ && prAdapter->rWifiVar.fgSupportUAPSD */) { ++ /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */ ++ ++ if (flgIsUpdateForcedToDelivery == FALSE) { ++ if (prStaRec->ucFreeQuotaForNonDelivery > 0 && prStaRec->ucFreeQuotaForDelivery > 0) { ++ ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else if (prStaRec->ucFreeQuotaForNonDelivery == 0 ++ && prStaRec->ucFreeQuotaForDelivery == 0) { ++ ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) { ++ /* NonDelivery is not busy */ ++ if (ucFreeQuota >= 3) { ++ ucFreeQuotaForNonDelivery = 2; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } else { ++ ucFreeQuotaForDelivery = ucFreeQuota; ++ ucFreeQuotaForNonDelivery = 0; ++ } ++ } else if (prStaRec->ucFreeQuotaForDelivery > 0) { ++ /* Delivery is not busy */ ++ if (ucFreeQuota >= 3) { ++ ucFreeQuotaForDelivery = 2; ++ ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery; ++ } else { ++ ucFreeQuotaForNonDelivery = ucFreeQuota; ++ ucFreeQuotaForDelivery = 0; ++ } ++ } ++ } else { ++ ucFreeQuotaForNonDelivery = 2; ++ ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; ++ } ++ } else { ++ /* no use ? */ ++ /* !prStaRec->fgIsUapsdSupported */ ++ ucFreeQuotaForNonDelivery = ucFreeQuota; ++ ucFreeQuotaForDelivery = 0; ++ } ++ } ++ /* ucFreeQuota > 0 */ ++ prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery; ++ prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ if (IS_TDLS_STA(prStaRec)) ++ DBGLOG(QM, LOUD, " quota %d %d %d\n", ++ ucFreeQuota, ucFreeQuotaForDelivery, ucFreeQuotaForNonDelivery); ++#endif ++ ++ DBGLOG(QM, LOUD, "new QuotaForDelivery = %d QuotaForNonDelivery = %d\n", ++ prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Return the reorder queued RX packets ++* ++* \param[in] (none) ++* ++* \return The number of queued RX packets ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter) ++{ ++ UINT_32 i, u4Total; ++ P_QUE_MGT_T prQM = &prAdapter->rQM; ++ ++ u4Total = 0; ++ /* XXX The summation may impact the performance */ ++ for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { ++ u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem; ++#if DBG && 0 ++ if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) ++ ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0); ++#endif ++ } ++ ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2)); ++ return u4Total; ++} ++ ++#if ARP_MONITER_ENABLE ++VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) ++{ ++ struct sk_buff *prSkb = NULL; ++ PUINT_8 pucData = NULL; ++ UINT_16 u2EtherType = 0; ++ int arpOpCode = 0; ++ ++ prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ ++ if (!prSkb || (prSkb->len <= ETHER_HEADER_LEN)) ++ return; ++ ++ pucData = prSkb->data; ++ if (!pucData) ++ return; ++ u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if (u2EtherType != ETH_P_ARP || (apIp[0] | apIp[1] | apIp[2] | apIp[3]) == 0) ++ return; ++ ++ if (strncmp(apIp, &pucData[ETH_TYPE_LEN_OFFSET + 26], sizeof(apIp))) /* dest ip address */ ++ return; ++ ++ arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); ++ if (arpOpCode == ARP_PRO_REQ) { ++ arpMoniter++; ++ if (arpMoniter > 20) { ++ DBGLOG(INIT, WARN, "IOT Critical issue, arp no resp, check AP!\n"); ++ aisBssBeaconTimeout(prAdapter); ++ arpMoniter = 0; ++ kalMemZero(apIp, sizeof(apIp)); ++ } ++ } ++} ++ ++VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) ++{ ++ PUINT_8 pucData = NULL; ++ UINT_16 u2EtherType = 0; ++ int arpOpCode = 0; ++ P_BSS_INFO_T prBssInfo = NULL; ++ ++ if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN) ++ return; ++ ++ pucData = (PUINT_8)prSwRfb->pvHeader; ++ if (!pucData) ++ return; ++ u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if (u2EtherType != ETH_P_ARP) ++ return; ++ ++ arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); ++ prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); ++ if (arpOpCode == ARP_PRO_RSP) { ++ arpMoniter = 0; ++ if (prBssInfo && prBssInfo->prStaRecOfAP && prBssInfo->prStaRecOfAP->aucMacAddr) { ++ if (EQUAL_MAC_ADDR(&(pucData[ETH_TYPE_LEN_OFFSET + 10]), /* source hardware address */ ++ prBssInfo->prStaRecOfAP->aucMacAddr)) { ++ strncpy(apIp, &(pucData[ETH_TYPE_LEN_OFFSET + 16]), sizeof(apIp)); /* src ip address */ ++ DBGLOG(INIT, TRACE, "get arp response from AP %d.%d.%d.%d\n", ++ apIp[0], apIp[1], apIp[2], apIp[3]); ++ } ++ } ++ } ++} ++ ++VOID qmResetArpDetect(VOID) ++{ ++ arpMoniter = 0; ++ kalMemZero(apIp, sizeof(apIp)); ++} ++#endif ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c +new file mode 100644 +index 000000000000..6f5c0bcdd90b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c +@@ -0,0 +1,1177 @@ ++/* ++** Id: @(#) gl_bow.c@@ ++*/ ++ ++/*! \file gl_bow.c ++ \brief Main routines of Linux driver interface for 802.11 PAL (BT 3.0 + HS) ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_bow.c ++ * ++ * 02 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00235223] [Rose][ICS][Cross Feature][AEE-IPANIC]The device reboot automatically and then the "KE" pops up ++ * after you turn on the "Airplane mode".(once) ++ * ++ * [Root Cause] ++ * PAL operates BOW char dev poll after BOW char dev is registered. ++ * ++ * [Solution] ++ * Rejects PAL char device operation after BOW is unregistered or when wlan GLUE_FLAG_HALT is set. ++ * ++ * This is a workaround for BOW driver robustness, happens only in ICS. ++ * ++ * Root cause should be fixed by CR [ALPS00231570] ++ * ++ * 02 03 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * [ALPS00118114] [Rose][ICS][Free Test][Bluetooth]The "KE" pops up after you turn on the airplane mode.(5/5) ++ * ++ * [Root Cause] ++ * PAL operates BOW char dev poll after BOW char dev is registered. ++ * ++ * [Solution] ++ * Rejects PAL char device operation after BOW is unregistered. ++ * ++ * Happens only in ICS. ++ * ++ * Notified PAL owener to reivew MTKBT/PAL closing BOW char dev procedure. ++ * ++ * [Side Effect] ++ * None. ++ * ++ * 01 16 2012 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support BOW for 5GHz band. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 25 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Modify ampc0 char device for major number 151 for all MT6575 projects. ++ * ++ * 07 28 2011 cp.wu ++ * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl ++ * unlocked_ioctl returns as long instead of int. ++ * ++ * 07 28 2011 cp.wu ++ * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl ++ * migrate to unlocked ioctl interface ++ * ++ * 04 12 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add WMM IE for BOW initiator data. ++ * ++ * 04 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. ++ * ++ * 04 09 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Change Link connection event procedure and change skb length check to 1512 bytes. ++ * ++ * 03 27 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Support multiple physical link. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * replace alloc_netdev to alloc_netdev_mq for BoW ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 02 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Update net register and BOW for concurrent features. ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 ++ * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 ++ * with BOW and P2P enabled as default ++ * ++ * 02 08 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. ++ * Update BOW get MAC status, remove returning event for AIS network type. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 11 11 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix BoW timer assert issue. ++ * ++ * 09 14 2010 chinghwa.yu ++ * NULL ++ * Add bowRunEventAAAComplete. ++ * ++ * 09 14 2010 cp.wu ++ * NULL ++ * correct typo: POLLOUT instead of POLL_OUT ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * add waitq for poll() and read(). ++ * ++ * 08 24 2010 chinghwa.yu ++ * NULL ++ * Update BOW for the 1st time. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change variable names for multiple physical link to match with coding convention ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * multiple BoW interfaces need to compare with peer address ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * fix kalIndicateBOWEvent. ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability ++ * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include ++#include "bss.h" ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* @FIXME if there is command/event with payload length > 28 */ ++#define MAX_BUFFER_SIZE (64) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_BOW_TEST ++UINT_32 g_u4PrevSysTime = 0; ++UINT_32 g_u4CurrentSysTime = 0; ++UINT_32 g_arBowRevPalPacketTime[11]; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* forward declarations */ ++static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos); ++ ++static ssize_t ++mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos); ++ ++static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg); ++ ++static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait); ++ ++static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp); ++ ++static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp); ++ ++/* character file operations */ ++static const struct file_operations mt6620_ampc_fops = { ++ /* .owner = THIS_MODULE, */ ++ .read = mt6620_ampc_read, ++ .write = mt6620_ampc_write, ++ .unlocked_ioctl = mt6620_ampc_ioctl, ++ .poll = mt6620_ampc_poll, ++ .open = mt6620_ampc_open, ++ .release = mt6620_ampc_release, ++}; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register for character device to communicate with 802.11 PAL ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glRegisterAmpc(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->rBowInfo.fgIsRegistered == TRUE) ++ return FALSE; ++ ++#if 0 ++ /* 1. allocate major number dynamically */ ++ ++ if (alloc_chrdev_region(&(prGlueInfo->rBowInfo.u4DeviceNumber), 0, /* first minor number */ ++ 1, /* number */ ++ GLUE_BOW_DEVICE_NAME) != 0) ++ ++ return FALSE; ++#endif ++ ++#if 1 ++ ++#if defined(CONFIG_AMPC_CDEV_NUM) ++ prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(CONFIG_AMPC_CDEV_NUM, 0); ++#else ++ prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(226, 0); ++#endif ++ ++ if (register_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1, /* number */ ++ GLUE_BOW_DEVICE_NAME) != 0) ++ ++ return FALSE; ++#endif ++ ++ /* 2. spin-lock initialization */ ++ /* spin_lock_init(&(prGlueInfo->rBowInfo.rSpinLock)); */ ++ ++ /* 3. initialize kfifo */ ++/* prGlueInfo->rBowInfo.prKfifo = kfifo_alloc(GLUE_BOW_KFIFO_DEPTH, ++ GFP_KERNEL, ++ &(prGlueInfo->rBowInfo.rSpinLock));*/ ++ if ((kfifo_alloc((struct kfifo *)&(prGlueInfo->rBowInfo.rKfifo), GLUE_BOW_KFIFO_DEPTH, GFP_KERNEL))) ++ goto fail_kfifo_alloc; ++ ++/* if(prGlueInfo->rBowInfo.prKfifo == NULL) */ ++ if (&(prGlueInfo->rBowInfo.rKfifo) == NULL) ++ goto fail_kfifo_alloc; ++ ++ /* 4. initialize cdev */ ++ cdev_init(&(prGlueInfo->rBowInfo.cdev), &mt6620_ampc_fops); ++ /* prGlueInfo->rBowInfo.cdev.owner = THIS_MODULE; */ ++ prGlueInfo->rBowInfo.cdev.ops = &mt6620_ampc_fops; ++ ++ /* 5. add character device */ ++ if (cdev_add(&(prGlueInfo->rBowInfo.cdev), prGlueInfo->rBowInfo.u4DeviceNumber, 1)) ++ goto fail_cdev_add; ++ ++ /* 6. in queue initialization */ ++ init_waitqueue_head(&(prGlueInfo->rBowInfo.outq)); ++ ++ /* 7. finish */ ++ prGlueInfo->rBowInfo.fgIsRegistered = TRUE; ++ return TRUE; ++ ++fail_cdev_add: ++ kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); ++/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ ++fail_kfifo_alloc: ++ unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); ++ return FALSE; ++} /* end of glRegisterAmpc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister character device for communicating with 802.11 PAL ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glUnregisterAmpc(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->rBowInfo.fgIsRegistered == FALSE) ++ return FALSE; ++ ++ prGlueInfo->rBowInfo.fgIsRegistered = FALSE; ++ ++ /* 1. free netdev if necessary */ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ kalUninitBowDevice(prGlueInfo); ++#endif ++ ++ /* 2. removal of character device */ ++ cdev_del(&(prGlueInfo->rBowInfo.cdev)); ++ ++ /* 3. free kfifo */ ++/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ ++ kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); ++/* prGlueInfo->rBowInfo.prKfifo = NULL; */ ++/* prGlueInfo->rBowInfo.rKfifo = NULL; */ ++ ++ /* 4. free device number */ ++ unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); ++ ++ return TRUE; ++} /* end of glUnregisterAmpc */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief read handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos) ++{ ++ UINT_8 aucBuffer[MAX_BUFFER_SIZE]; ++ ssize_t retval; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ /* size check */ ++/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) >= size) */ ++ if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) >= size) ++ retval = size; ++ else ++ retval = kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); ++/* retval = kfifo_len(prGlueInfo->rBowInfo.prKfifo); */ ++ ++/* kfifo_get(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ ++/* kfifo_out(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ ++ if (!(kfifo_out(&(prGlueInfo->rBowInfo.rKfifo), aucBuffer, retval))) { ++ retval = -EIO; ++ return retval; ++ } ++ ++ if (copy_to_user(buf, aucBuffer, retval)) ++ retval = -EIO; ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief write handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t ++mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos) ++{ ++#if CFG_BOW_TEST ++ UINT_8 i; ++#endif ++ ++ UINT_8 aucBuffer[MAX_BUFFER_SIZE]; ++ P_AMPC_COMMAND prCmd; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ ++ if (size > MAX_BUFFER_SIZE) ++ return -EINVAL; ++ else if (copy_from_user(aucBuffer, buf, size)) ++ return -EIO; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "AMP driver CMD buffer size : %d.\n", size); ++ ++ for (i = 0; i < MAX_BUFFER_SIZE; i++) ++ DBGLOG(BOW, EVENT, "AMP write content : 0x%x.\n", aucBuffer[i]); ++ ++ DBGLOG(BOW, EVENT, "BoW CMD write.\n"); ++#endif ++ ++ prCmd = (P_AMPC_COMMAND) aucBuffer; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "AMP write content payload length : %d.\n", prCmd->rHeader.u2PayloadLength); ++ ++ DBGLOG(BOW, EVENT, "AMP write content header length : %d.\n", sizeof(AMPC_COMMAND_HEADER_T)); ++#endif ++ ++ /* size check */ ++ if (prCmd->rHeader.u2PayloadLength + sizeof(AMPC_COMMAND_HEADER_T) != size) { ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "Wrong CMD total length.\n"); ++#endif ++ ++ return -EINVAL; ++ } ++ ++ if (wlanbowHandleCommand(prGlueInfo->prAdapter, prCmd) == WLAN_STATUS_SUCCESS) ++ return size; ++ else ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg) ++{ ++ int err = 0; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ /* permission check */ ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); ++ else if (_IOC_DIR(cmd) & _IOC_WRITE) ++ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); ++ if (err) ++ return -EFAULT; ++ ++ /* no ioctl is implemented yet */ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait) ++{ ++ unsigned int retval; ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return -EFAULT; ++ ++ poll_wait(filp, &prGlueInfo->rBowInfo.outq, wait); ++ ++ retval = (POLLOUT | POLLWRNORM); /* always accepts incoming command packets */ ++ ++/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLOUT | POLLWRNORM, %x\n", retval)); */ ++ ++/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) > 0) */ ++ if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) > 0) { ++ retval |= (POLLIN | POLLRDNORM); ++ ++/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLIN | POLLRDNORM, %x\n", retval)); */ ++ ++ } ++ ++ return retval; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief open handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ P_GL_BOW_INFO prBowInfo; ++ ++ prBowInfo = container_of(inodep->i_cdev, GL_BOW_INFO, cdev); ++ ASSERT(prBowInfo); ++ ++ prGlueInfo = container_of(prBowInfo, GLUE_INFO_T, rBowInfo); ++ ASSERT(prGlueInfo); ++ ++ /* set-up private data */ ++ filp->private_data = prGlueInfo; ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief close handler for character device to communicate with 802.11 PAL ++* ++* \param[in] ++* \return ++* Follows Linux Character Device Interface ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); ++ ++ ASSERT(prGlueInfo); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to indicate event for Bluetooth over Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* prEvent ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent) ++{ ++ size_t u4AvailSize, u4EventSize; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prEvent); ++ ++ /* check device */ ++ if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) ++ return; ++ ++/* u4AvailSize = ++ GLUE_BOW_KFIFO_DEPTH - kfifo_len(prGlueInfo->rBowInfo.prKfifo);*/ ++ ++ u4AvailSize = GLUE_BOW_KFIFO_DEPTH - kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); ++ ++ u4EventSize = prEvent->rHeader.u2PayloadLength + sizeof(AMPC_EVENT_HEADER_T); ++ ++ /* check kfifo availability */ ++ if (u4AvailSize < u4EventSize) { ++ DBGLOG(BOW, EVENT, "[bow] no space for event: %zu/%zu\n", u4EventSize, u4AvailSize); ++ return; ++ } ++ /* queue into kfifo */ ++/* kfifo_put(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ ++/* kfifo_in(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ ++ kfifo_in(&(prGlueInfo->rBowInfo.rKfifo), (PUINT_8) prEvent, u4EventSize); ++ wake_up_interruptible(&(prGlueInfo->rBowInfo.outq)); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 i; ++ ++ ASSERT(prGlueInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalGetBowState.\n"); ++#endif ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalGetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalGetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, ++ prGlueInfo->rBowInfo.aeState[i]); ++ ++#endif ++ ++ return prGlueInfo->rBowInfo.aeState[i]; ++ } ++ } ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Bluetooth-over-Wi-Fi state in glue layer ++* ++* \param[in] ++* prGlueInfo ++* eBowState ++* rPeerAddr ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, IN UINT_8 aucPeerAddress[6]) ++{ ++ UINT_8 i; ++ ++ ASSERT(prGlueInfo); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalSetBowState.\n"); ++ ++ DBGLOG(BOW, EVENT, "kalSetBowState, prGlueInfo->rBowInfo.arPeerAddr, %x:%x:%x:%x:%x:%x.\n", ++ prGlueInfo->rBowInfo.arPeerAddr[0], ++ prGlueInfo->rBowInfo.arPeerAddr[1], ++ prGlueInfo->rBowInfo.arPeerAddr[2], ++ prGlueInfo->rBowInfo.arPeerAddr[3], ++ prGlueInfo->rBowInfo.arPeerAddr[4], prGlueInfo->rBowInfo.arPeerAddr[5])); ++ ++ DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5]); ++#endif ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { ++ prGlueInfo->rBowInfo.aeState[i] = eBowState; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, ++ aucPeerAddress[0], ++ aucPeerAddress[1], ++ aucPeerAddress[2], ++ aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); ++ ++ DBGLOG(BOW, EVENT, ++ "kalSetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, ++ prGlueInfo->rBowInfo.aeState[i]); ++#endif ++ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi global state ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* BOW_DEVICE_STATE_DISCONNECTED ++* in case there is no BoW connection or ++* BoW connection under initialization ++* ++* BOW_DEVICE_STATE_STARTING ++* in case there is no BoW connection but ++* some BoW connection under initialization ++* ++* BOW_DEVICE_STATE_CONNECTED ++* in case there is any BoW connection available ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ++/* Henry, can reduce this logic to indentify state change */ ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_CONNECTED) ++ return BOW_DEVICE_STATE_CONNECTED; ++ } ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_STARTING) ++ return BOW_DEVICE_STATE_STARTING; ++ } ++ ++ return BOW_DEVICE_STATE_DISCONNECTED; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi operating frequency ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* in unit of KHz ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rBowInfo.u4FreqInKHz; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* 0: Responder ++* 1: Initiator ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) ++ return prGlueInfo->rBowInfo.aucRole[i]; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ucRole ++* 0: Responder ++* 1: Initiator ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr) ++{ ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ucRole <= 1); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) ++ prGlueInfo->rBowInfo.aucRole[i] = ucRole; /* Henry, 0 : Responder, 1 : Initiator */ ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get available Bluetooth-over-Wi-Fi physical link number ++* ++* \param[in] ++* prGlueInfo ++* \return ++* UINT_32 ++* how many physical links are aviailable ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 i; ++ UINT_8 ucLinkCount = 0; ++ ++ ASSERT(prGlueInfo); ++ ++ for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { ++ if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_DISCONNECTED) ++ ucLinkCount++; ++ } ++ ++#if 0 /* CFG_BOW_TEST */ ++ DBGLOG(BOW, EVENT, "kalGetBowAvailablePhysicalLinkCount, ucLinkCount, %c.\n", ucLinkCount); ++#endif ++ ++ return ucLinkCount; ++} ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ ++/* Net Device Hooks */ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device open (ifup) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowOpen(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 2. carrier on & start TX queue */ ++ netif_carrier_on(prDev); ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device stop (ifdown) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowStop(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prDev); ++ ++ /* 2. turn of carrier */ ++ if (netif_carrier_ok(prDev)) ++ netif_carrier_off(prDev); ++ ++ return 0; ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function is TX entry point of NET DEVICE. ++ * ++ * \param[in] prSkb Pointer of the sk_buff to be sent ++ * \param[in] prDev Pointer to struct net_device ++ * ++ * \retval NETDEV_TX_OK - on success. ++ * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int bowHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ UINT_16 u2QueueIdx = 0; ++ UINT_8 ucDSAP, ucSSAP, ucControl; ++ UINT_8 aucOUI[3]; ++ PUINT_8 aucLookAheadBuf = NULL; ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; ++ ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; ++ ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; ++ aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; ++ aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; ++ aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; ++ prGlueInfo->u8SkbToDriver++; ++ ++ if (!(ucDSAP == ETH_LLC_DSAP_SNAP && ++ ucSSAP == ETH_LLC_SSAP_SNAP && ++ ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && ++ aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && ++ aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) || (prSkb->len > 1514)) { ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Invalid BOW packet, skip tx\n"); ++#endif ++ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(BOW, TRACE, "GLUE_FLAG_HALT skip tx\n"); ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Tx sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "Tx sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "Tx sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"; ++#endif ++#if CFG_BOW_TEST ++/* g_u4CurrentSysTime = (OS_SYSTIME)kalGetTimeTick(; */ ++ g_u4CurrentSysTime = (OS_SYSTIME) jiffies_to_usecs(jiffies); ++ i = g_u4CurrentSysTime - g_u4PrevSysTime; ++ if ((i >> 10) > 0) ++ i = 10; ++ else ++ i = i >> 7; ++ g_arBowRevPalPacketTime[i]++; ++ g_u4PrevSysTime = g_u4CurrentSysTime; ++#endif ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) ++ DBGLOG(TX, INFO, "netif_stop_subqueue for BOW, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); ++ ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ } else { ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ kalSetEvent(prGlueInfo); ++ /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ ++ return NETDEV_TX_OK; ++} ++ ++/* callbacks for netdevice */ ++static const struct net_device_ops bow_netdev_ops = { ++ .ndo_open = bowOpen, .ndo_stop = bowStop, .ndo_start_xmit = bowHardStartXmit,}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief initialize net device for Bluetooth-over-Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* prDevName ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName) ++{ ++ P_ADAPTER_T prAdapter; ++ P_GL_HIF_INFO_T prHif; ++ PARAM_MAC_ADDRESS rMacAddr; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ prHif = &prGlueInfo->rHifInfo; ++ ASSERT(prHif); ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered == FALSE) { ++ prGlueInfo->rBowInfo.prDevHandler = ++ alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prGlueInfo->rBowInfo.prDevHandler) ++ return FALSE; ++ ++ /* 1. setup netdev */ ++ /* 1.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->rBowInfo.prDevHandler)) = prGlueInfo; ++ /* 1.2 fill hardware address */ ++ COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] |= 0x2; ++ /* change to local administrated address */ ++ ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->dev_addr, rMacAddr); ++ ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->perm_addr, ++ prGlueInfo->rBowInfo.prDevHandler->dev_addr); ++ /* 1.3 register callback functions */ ++ prGlueInfo->rBowInfo.prDevHandler->netdev_ops = &bow_netdev_ops; ++#if (MTK_WCN_HIF_SDIO == 0) ++ SET_NETDEV_DEV(prGlueInfo->rBowInfo.prDevHandler, prHif->Dev); ++#endif ++ register_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ /* 2. net device initialize */ ++ netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); ++ /* 3. finish */ ++ prGlueInfo->rBowInfo.fgIsNetRegistered = TRUE; ++ } ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief uninitialize net device for Bluetooth-over-Wi-Fi ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ /* ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); */ ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered == TRUE) { ++ prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; ++ if (netif_carrier_ok(prGlueInfo->rBowInfo.prDevHandler)) ++ netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); ++ ++ netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); ++ /* netdevice unregistration & free */ ++ unregister_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ free_netdev(prGlueInfo->rBowInfo.prDevHandler); ++ prGlueInfo->rBowInfo.prDevHandler = NULL; ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++#endif /* CFG_BOW_SEPARATE_DATA_PATH */ ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c +new file mode 100644 +index 000000000000..1fed65ebc60e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c +@@ -0,0 +1,3110 @@ ++/* ++** Id: @(#) gl_cfg80211.c@@ ++*/ ++ ++/*! \file gl_cfg80211.c ++ \brief Main routines for supporintg MT6620 cfg80211 control interface ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_cfg80211.c ++** ++** 09 05 2013 cp.wu ++** correct length to pass to wlanoidSetBssid() ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 11 23 2012 yuche.tsai ++** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely ++** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "debug.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include ++#include ++#include ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/* workaround for some ANR CRs. if suppliant is blocked longer than 10s, wifi hal will tell wifiMonitor ++to teminate. for the case which can block supplicant 10s is to del key more than 5 times. the root cause ++is that there is no resource in TC4, so del key command was not able to set, and then oid ++timeout was happed. if we found the root cause why fw couldn't release TC resouce, we will remove this ++workaround */ ++static UINT_8 gucKeyIndex = 255; ++ ++P_SW_RFB_T g_arGscnResultsTempBuffer[MAX_BUFFERED_GSCN_RESULTS]; ++UINT_8 g_GscanResultsTempBufferIndex = 0; ++UINT_8 g_arGscanResultsIndicateNumber[MAX_BUFFERED_GSCN_RESULTS] = { 0, 0, 0, 0, 0 }; ++ ++UINT_8 g_GetResultsBufferedCnt = 0; ++UINT_8 g_GetResultsCmdCnt = 0; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for change STA type between ++ * 1. Infrastructure Client (Non-AP STA) ++ * 2. Ad-Hoc IBSS ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, enum nl80211_iftype type, /*u32 *flags,*/ struct vif_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (type == NL80211_IFTYPE_STATION) ++ eOpMode = NET_TYPE_INFRA; ++ else if (type == NL80211_IFTYPE_ADHOC) ++ eOpMode = NET_TYPE_IBSS; ++ else ++ return -EINVAL; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set infrastructure mode error:%x\n", rStatus); ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding key ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) ++{ ++ PARAM_KEY_T rKey; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Rslt = -EINVAL; ++ UINT_32 u4BufLen = 0; ++ UINT_8 tmp1[8]; ++ UINT_8 tmp2[8]; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(&rKey, sizeof(PARAM_KEY_T)); ++ ++ rKey.u4KeyIndex = key_index; ++ ++ if (mac_addr) { ++ COPY_MAC_ADDR(rKey.arBSSID, mac_addr); ++ if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && ++ (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ } ++ if (rKey.arBSSID[0] != 0xFF) { ++ rKey.u4KeyIndex |= BIT(31); ++ if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || ++ (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) ++ rKey.u4KeyIndex |= BIT(30); ++ } ++ } else { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ /* rKey.u4KeyIndex |= BIT(31);//Enable BIT 31 will make tx use bc key id,should use pairwise key id 0 */ ++ } ++ ++ if (params->key) { ++ /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ ++ kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); ++ if (params->key_len == 32) { ++ kalMemCopy(tmp1, ¶ms->key[16], 8); ++ kalMemCopy(tmp2, ¶ms->key[24], 8); ++ kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8); ++ kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8); ++ } ++ } ++ ++ rKey.u4KeyLength = params->key_len; ++ rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for getting key for specified STA ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *)) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for removing key for specified STA ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ PARAM_REMOVE_KEY_T rRemoveKey; ++ UINT_32 u4BufLen = 0; ++ INT_32 i4Rslt = -EINVAL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); ++ if (mac_addr) ++ COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); ++ else if (key_index <= gucKeyIndex) { /* new operation, reset gucKeyIndex */ ++ gucKeyIndex = 255; ++ } else { /* bypass the next remove key operation */ ++ gucKeyIndex = key_index; ++ return -EBUSY; ++ } ++ rRemoveKey.u4KeyIndex = key_index; ++ rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveKey, &rRemoveKey, rRemoveKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "remove key error:%x\n", rStatus); ++ if (WLAN_STATUS_FAILURE == rStatus && mac_addr) { ++ i4Rslt = -EBUSY; ++ gucKeyIndex = key_index; ++ } ++ } else { ++ gucKeyIndex = 255; ++ i4Rslt = 0; ++ } ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for setting default key on an interface ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for setting set_default_mgmt_ke on an interface ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for getting station information such as RSSI ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) ++{ ++#define LINKSPEED_MAX_RANGE_11BGN 3000 ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ PARAM_MAC_ADDRESS arBssid; ++ UINT_32 u4BufLen; ++ UINT_32 u4Rate = 0; ++ UINT_32 u8diffTxBad, u8diffRetry; ++ INT_32 i4Rssi = 0; ++ PARAM_802_11_STATISTICS_STRUCT_T rStatistics; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); ++ ++ /* 1. check BSSID */ ++ if (UNEQUAL_MAC_ADDR(arBssid, mac)) { ++ /* wrong MAC address */ ++ DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", ++ mac, arBssid); ++ return -ENOENT; ++ } ++ ++ /* 2. fill TX rate */ ++ if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { ++ /* not connected */ ++ DBGLOG(REQ, WARN, "not yet connected\n"); ++ } else { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); ++ ++ if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) { ++ /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n")); */ ++ DBGLOG(REQ, WARN, "last link speed\n"); ++ sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; ++ } else { ++ /* sinfo->filled |= STATION_INFO_TX_BITRATE; */ ++ sinfo->txrate.legacy = u4Rate / 1000; /* convert from 100bps to 100kbps */ ++ prGlueInfo->u4LinkSpeedCache = u4Rate / 1000; ++ } ++ } ++ ++ /* 3. fill RSSI */ ++ if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { ++ /* not connected */ ++ DBGLOG(REQ, WARN, "not yet connected\n"); ++ } else { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS || (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) ++ || (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { ++ /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n"); */ ++ DBGLOG(REQ, WARN, "last rssi\n"); ++ sinfo->signal = prGlueInfo->i4RssiCache; ++ } else { ++ /* in the cfg80211 layer, the signal is a signed char variable. */ ++ sinfo->signal = i4Rssi; /* dBm */ ++ prGlueInfo->i4RssiCache = i4Rssi; ++ } ++ sinfo->rx_packets = prGlueInfo->rNetDevStats.rx_packets; ++ ++ /* 4. Fill Tx OK and Tx Bad */ ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); ++ { ++ WLAN_STATUS rStatus; ++ ++ kalMemZero(&rStatistics, sizeof(rStatistics)); ++ /* Get Tx OK/Fail cnt from AIS statistic counter */ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatisticsPL, ++ &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "unable to retrieive statistic\n"); ++ } else { ++ INT_32 i4RssiThreshold = -85; /* set rssi threshold -85dBm */ ++ UINT_32 u4LinkspeedThreshold = 55; /* set link speed threshold 5.5Mbps */ ++ BOOLEAN fgWeighted = 0; ++ ++ /* calculate difference */ ++ u8diffTxBad = rStatistics.rFailedCount.QuadPart - prGlueInfo->u8Statistic[0]; ++ u8diffRetry = rStatistics.rRetryCount.QuadPart - prGlueInfo->u8Statistic[1]; ++ /* restore counters */ ++ prGlueInfo->u8Statistic[0] = rStatistics.rFailedCount.QuadPart; ++ prGlueInfo->u8Statistic[1] = rStatistics.rRetryCount.QuadPart; ++ ++ /* check threshold is valid */ ++ if (prGlueInfo->fgPoorlinkValid) { ++ if (prGlueInfo->i4RssiThreshold) ++ i4RssiThreshold = prGlueInfo->i4RssiThreshold; ++ if (prGlueInfo->u4LinkspeedThreshold) ++ u4LinkspeedThreshold = prGlueInfo->u4LinkspeedThreshold; ++ } ++ /* add weighted to fail counter */ ++ if (sinfo->txrate.legacy < u4LinkspeedThreshold || sinfo->signal < i4RssiThreshold) { ++ prGlueInfo->u8TotalFailCnt += (u8diffTxBad * 16 + u8diffRetry); ++ fgWeighted = 1; ++ } else { ++ prGlueInfo->u8TotalFailCnt += u8diffTxBad; ++ } ++ /* report counters */ ++ prGlueInfo->rNetDevStats.tx_packets = rStatistics.rTransmittedFragmentCount.QuadPart; ++ prGlueInfo->rNetDevStats.tx_errors = prGlueInfo->u8TotalFailCnt; ++ ++ sinfo->tx_packets = prGlueInfo->rNetDevStats.tx_packets; ++ sinfo->tx_failed = prGlueInfo->rNetDevStats.tx_errors; ++ /* Good Fail Bad Difference retry difference Linkspeed Rate Weighted */ ++ DBGLOG(REQ, TRACE, ++ "Poorlink State TxOK(%d) TxFail(%d) Bad(%d) Retry(%d)", ++ sinfo->tx_packets, ++ sinfo->tx_failed, ++ (int)u8diffTxBad, ++ (int)u8diffRetry); ++ DBGLOG(REQ, TRACE, ++ "Rate(%d) Signal(%d) Weight(%d) QuadPart(%d)\n", ++ sinfo->txrate.legacy, ++ sinfo->signal, ++ (int)fgWeighted, ++ (int)rStatistics.rMultipleRetryCount.QuadPart); ++ } ++ } ++ ++ } ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params) ++{ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* ++ EX: In supplicant, ++ (Supplicant) wpa_tdls_process_tpk_m3() -> ++ (Supplicant) wpa_tdls_enable_link() -> ++ (Supplicant) wpa_sm_tdls_peer_addset() -> ++ (Supplicant) ..tdls_peer_addset() -> ++ (Supplicant) wpa_supplicant_tdls_peer_addset() -> ++ (Supplicant) wpa_drv_sta_add() -> ++ (Supplicant) ..sta_add() -> ++ (Supplicant) wpa_driver_nl80211_sta_add() -> ++ (NL80211) nl80211_set_station() -> ++ (Driver) mtk_cfg80211_change_station() ++ ++ if nl80211_set_station fails, supplicant will tear down the link. ++ */ ++ P_GLUE_INFO_T prGlueInfo; ++ TDLS_CMD_PEER_UPDATE_T rCmdUpdate; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen, u4Temp; ++ ++ /* sanity check */ ++ if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) ++ return -EINVAL; ++ ++ DBGLOG(TDLS, INFO, "%s: 0x%p 0x%x\n", __func__, params->supported_rates, params->sta_flags_set); ++ ++ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) ++ return -EOPNOTSUPP; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) ++ return -EINVAL; ++ ++ /* TODO: check if we are station mode, not AP mode */ ++ ++ /* init */ ++ kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); ++ kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); ++ ++ if (params->supported_rates != NULL) { ++ u4Temp = params->supported_rates_len; ++ if (u4Temp > TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX) { ++ u4Temp = TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX; ++ DBGLOG(TDLS, ERROR, "%s sup rate too long: %d\n", __func__, params->supported_rates_len); ++ } ++ kalMemCopy(rCmdUpdate.aucSupRate, params->supported_rates, u4Temp); ++ rCmdUpdate.u2SupRateLen = u4Temp; ++ } ++ ++ /* ++ In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM ++ So force to support UAPSD here. ++ */ ++ rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */ ++ rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */ ++ ++ DBGLOG(TDLS, INFO, "%s: UapsdBitmap=0x%x UapsdMaxSp=%d\n", ++ __func__, rCmdUpdate.UapsdBitmap, rCmdUpdate.UapsdMaxSp); ++ ++ rCmdUpdate.u2Capability = params->capability; ++ ++ if (params->ext_capab != NULL) { ++ u4Temp = params->ext_capab_len; ++ if (u4Temp > TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN) { ++ u4Temp = TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN; ++ DBGLOG(TDLS, ERROR, "%s ext_capab too long: %d\n", __func__, params->ext_capab_len); ++ } ++ kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp); ++ rCmdUpdate.u2ExtCapLen = u4Temp; ++ } ++ ++ if (params->ht_capa != NULL) { ++ DBGLOG(TDLS, INFO, "%s: peer is 11n device\n", __func__); ++ ++ rCmdUpdate.rHtCap.u2CapInfo = params->ht_capa->cap_info; ++ rCmdUpdate.rHtCap.ucAmpduParamsInfo = params->ht_capa->ampdu_params_info; ++ rCmdUpdate.rHtCap.u2ExtHtCapInfo = params->ht_capa->extended_ht_cap_info; ++ rCmdUpdate.rHtCap.u4TxBfCapInfo = params->ht_capa->tx_BF_cap_info; ++ rCmdUpdate.rHtCap.ucAntennaSelInfo = params->ht_capa->antenna_selection_info; ++ kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask, ++ params->ht_capa->mcs.rx_mask, sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask)); ++ rCmdUpdate.rHtCap.rMCS.u2RxHighest = params->ht_capa->mcs.rx_highest; ++ rCmdUpdate.rHtCap.rMCS.ucTxParams = params->ht_capa->mcs.tx_params; ++ rCmdUpdate.fgIsSupHt = TRUE; ++ } ++ ++ /* update a TDLS peer record */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexPeerUpdate, ++ &rCmdUpdate, sizeof(TDLS_CMD_PEER_UPDATE_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s update error:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for adding a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params) ++{ ++#if (CFG_SUPPORT_TDLS == 1) ++ /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ ++ P_GLUE_INFO_T prGlueInfo; ++ TDLS_CMD_PEER_ADD_T rCmdCreate; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) ++ return -EINVAL; ++ ++ /* ++ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, ++ NULL, 0); ++ ++ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, ++ u16 aid, u16 capability, const u8 *supp_rates, ++ size_t supp_rates_len, ++ const struct ieee80211_ht_capabilities *ht_capab, ++ const struct ieee80211_vht_capabilities *vht_capab, ++ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) ++ ++ Only MAC address of the peer is valid. ++ */ ++ ++ DBGLOG(TDLS, INFO, "%s: 0x%p %d\n", __func__, params->supported_rates, params->supported_rates_len); ++ ++ /* sanity check */ ++ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) ++ return -EOPNOTSUPP; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (prGlueInfo == NULL) ++ return -EINVAL; ++ ++ /* TODO: check if we are station mode, not AP mode */ ++ ++ /* init */ ++ kalMemZero(&rCmdCreate, sizeof(rCmdCreate)); ++ kalMemCopy(rCmdCreate.aucPeerMac, mac, 6); ++ ++#if 0 ++ rCmdCreate.eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; ++ ++ rCmdCreate.u2CapInfo = params->capability; ++ ++ DBGLOG(TDLS, INFO, " %s: capability = 0x%x\n", __func__, rCmdCreate.u2CapInfo); ++ ++ if ((params->supported_rates != NULL) && (params->supported_rates_len != 0)) { ++ UINT32 u4Idx; ++ ++ DBGLOG(TDLS, INFO, " %s: sup rate = 0x", __func__); ++ ++ rIeSup.ucId = ELEM_ID_SUP_RATES; ++ rIeSup.ucLength = params->supported_rates_len; ++ for (u4Idx = 0; u4Idx < rIeSup.ucLength; u4Idx++) { ++ rIeSup.aucSupportedRates[u4Idx] = params->supported_rates[u4Idx]; ++ DBGLOG(TDLS, INFO, "%x ", rIeSup.aucSupportedRates[u4Idx]); ++ } ++ DBGLOG(TDLS, INFO, "\n"); ++ ++ rateGetRateSetFromIEs(&rIeSup, ++ NULL, ++ &rCmdCreate.u2OperationalRateSet, ++ &rCmdCreate.u2BSSBasicRateSet, &rCmdCreate.fgIsUnknownBssBasicRate); ++ } ++ ++ /* phy type */ ++#endif ++ ++ /* create a TDLS peer record */ ++ rStatus = kalIoctl(prGlueInfo, ++ TdlsexPeerAdd, ++ &rCmdCreate, sizeof(TDLS_CMD_PEER_ADD_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(TDLS, ERROR, "%s create error:%x\n", __func__, rStatus); ++ return -EINVAL; ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for deleting a station information ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ * ++ * @other ++ * must implement if you have add_station(). ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params) ++//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to do a scan ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++static PARAM_SCAN_REQUEST_EXT_T rScanRequest; ++int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++/* PARAM_SCAN_REQUEST_EXT_T rScanRequest; */ ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "mtk_cfg80211_scan\n"); ++ kalMemZero(&rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T)); ++ ++ /* check if there is any pending scan not yet finished */ ++ if (prGlueInfo->prScanRequest != NULL) { ++ DBGLOG(REQ, ERROR, "prGlueInfo->prScanRequest != NULL\n"); ++ return -EBUSY; ++ } ++ ++ if (request->n_ssids == 0) { ++ rScanRequest.rSsid.u4SsidLen = 0; ++ } else if (request->n_ssids == 1) { ++ COPY_SSID(rScanRequest.rSsid.aucSsid, rScanRequest.rSsid.u4SsidLen, request->ssids[0].ssid, ++ request->ssids[0].ssid_len); ++ } else { ++ DBGLOG(REQ, ERROR, "request->n_ssids:%d\n", request->n_ssids); ++ return -EINVAL; ++ } ++ ++ if (request->ie_len > 0) { ++ rScanRequest.u4IELength = request->ie_len; ++ rScanRequest.pucIE = (PUINT_8) (request->ie); ++ } else { ++ rScanRequest.u4IELength = 0; ++ } ++#if 0 ++ prGlueInfo->prScanRequest = request; ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScanExt, ++ &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); ++ prGlueInfo->prScanRequest = NULL; ++ return -EINVAL; ++ } ++ ++ /*prGlueInfo->prScanRequest = request;*/ ++#endif ++ ++ prGlueInfo->prScanRequest = request; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScanExt, ++ &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ prGlueInfo->prScanRequest = NULL; ++ DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static UINT_8 wepBuf[48]; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to connect to ++ * the ESS with the specified parameters ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ UINT_32 cipher; ++ PARAM_CONNECT_T rNewSsid; ++ BOOLEAN fgCarryWPSIE = FALSE; ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "[wlan] mtk_cfg80211_connect %p %zu\n", sme->ie, sme->ie_len); ++ ++ if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode > NET_TYPE_AUTO_SWITCH) ++ eOpMode = NET_TYPE_AUTO_SWITCH; ++ else ++ eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetInfrastructureMode fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* after set operation mode, key table are cleared */ ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA; ++ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2; ++ else ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ ++ switch (sme->auth_type) { ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ default: ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY; ++ break; ++ } ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] = ++ sme->crypto.ciphers_pairwise[0]; ++ switch (sme->crypto.ciphers_pairwise[0]) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP40; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_TKIP; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ } ++ ++ if (sme->crypto.cipher_group) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite = sme->crypto.cipher_group; ++ switch (sme->crypto.cipher_group) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP40; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_TKIP; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ if (sme->crypto.n_akm_suites) { ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] = ++ sme->crypto.akm_suites[0]; ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ eAuthMode = AUTH_MODE_WPA; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ eAuthMode = AUTH_MODE_WPA_PSK; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } else if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ eAuthMode = AUTH_MODE_WPA2; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ eAuthMode = AUTH_MODE_WPA2_PSK; ++ break; ++ default: ++ DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? ++ AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; ++ } ++ ++ prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy; ++ ++ prGlueInfo->fgWpsActive = FALSE; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ prGlueInfo->fgConnectHS20AP = FALSE; ++#endif ++ ++ if (sme->ie && sme->ie_len > 0) { ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ PUINT_8 prDesiredIE = NULL; ++ PUINT_8 pucIEStart = (PUINT_8)sme->ie; ++ ++#if CFG_SUPPORT_WAPI ++ if (wextSrchDesiredWAPIIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiAssocInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(SEC, WARN, "[wapi] set wapi assoc info error:%x\n", rStatus); ++ } ++#endif ++ ++ DBGLOG(REQ, TRACE, "[wlan] wlanoidSetWapiAssocInfo: .fgWapiMode = %d\n", ++ prGlueInfo->prAdapter->rWifiVar.rConnSettings.fgWapiMode); ++ ++#if CFG_SUPPORT_WPS2 ++ if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ prGlueInfo->fgWpsActive = TRUE; ++ fgCarryWPSIE = TRUE; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWSCAssocInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(SEC, WARN, "WSC] set WSC assoc info error:%x\n", rStatus); ++ } ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (wextSrchDesiredHS20IE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetHS20Info, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ if (wextSrchDesiredInterworkingIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInterworkingInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ if (wextSrchDesiredRoamingConsortiumIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingConsortiumIEInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++ } ++ ++ /* clear WSC Assoc IE buffer in case WPS IE is not detected */ ++ if (fgCarryWPSIE == FALSE) { ++ kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); ++ prGlueInfo->u2WSCAssocInfoIELen = 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus); ++ ++ cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; ++ ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { ++ if (cipher & IW_AUTH_CIPHER_CCMP) { ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_TKIP) { ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_NONE) { ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } else { ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ } else { ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "set encryption mode error:%x\n", rStatus); ++ ++ if (sme->key_len != 0 && prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ prWepKey->u4Length = 12 + sme->key_len; ++ prWepKey->u4KeyLength = (UINT_32) sme->key_len; ++ prWepKey->u4KeyIndex = (UINT_32) sme->key_idx; ++ prWepKey->u4KeyIndex |= BIT(31); ++ if (prWepKey->u4KeyLength > 32) { ++ DBGLOG(REQ, ERROR, "Too long key length (%u)\n", prWepKey->u4KeyLength); ++ return -EINVAL; ++ } ++ kalMemCopy(prWepKey->aucKeyMaterial, sme->key, prWepKey->u4KeyLength); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ } ++ ++ if (sme->channel) ++ rNewSsid.u4CenterFreq = sme->channel->center_freq; ++ else ++ rNewSsid.u4CenterFreq = 0; ++ rNewSsid.pucBssid = (UINT_8 *)sme->bssid; ++ rNewSsid.pucSsid = (UINT_8 *)sme->ssid; ++ rNewSsid.u4SsidLen = sme->ssid_len; ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetConnect, ++ (PVOID)(&rNewSsid), sizeof(PARAM_CONNECT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "set SSID:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to disconnect from ++ * currently connected ESS ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to join an IBSS group ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) ++{ ++ PARAM_SSID_T rNewSsid; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4ChnlFreq; /* Store channel or frequency information */ ++ UINT_32 u4BufLen = 0; ++ WLAN_STATUS rStatus; ++ struct ieee80211_channel *channel = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* set channel */ ++ if (params->chandef.chan) ++ channel = params->chandef.chan; ++ if (channel) { ++ u4ChnlFreq = nicChannelNum2Freq(channel->hw_value); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetFrequency, ++ &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ } ++ ++ /* set SSID */ ++ kalMemCopy(rNewSsid.aucSsid, params->ssid, params->ssid_len); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetSsid, ++ (PVOID)(&rNewSsid), sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to leave from IBSS group ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to configure ++ * WLAN power managemenet ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ PARAM_POWER_MODE ePowerMode; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (enabled) { ++ if (timeout == -1) ++ ePowerMode = Param_PowerModeFast_PSP; ++ else ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else { ++ ePowerMode = Param_PowerModeCAM; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSet802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set_power_mgmt error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cache ++ * a PMKID for a BSSID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); ++ return -ENOMEM; ++ } ++ ++ prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); ++ prPmkid->u4BSSIDInfoCount = 1; ++ kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, pmksa->bssid, 6); ++ kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, pmksa->pmkid, IW_PMKID_LEN); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "add pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to remove ++ * a cached PMKID for a BSSID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) ++{ ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to flush ++ * all cached PMKID ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_FLUSH\n"); ++ return -ENOMEM; ++ } ++ ++ prPmkid->u4Length = 8; ++ prPmkid->u4BSSIDInfoCount = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, WARN, "flush pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8); ++ ++ return 0; ++} ++ ++void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ IN struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg) ++{ ++#if 0 ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++#endif ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ ++ DBGLOG(REQ, LOUD, "mtk_cfg80211_mgmt_frame_register\n"); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ switch (frame_type) { ++ case MAC_FRAME_PROBE_REQ: ++ if (reg) { ++ prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(REQ, LOUD, "Open packet filer probe request\n"); ++ } else { ++ prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(REQ, LOUD, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (reg) { ++ prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(REQ, LOUD, "Open packet filer action frame.\n"); ++ } else { ++ prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(REQ, LOUD, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(REQ, TRACE, "Ask frog to add code for mgmt:%x\n", frame_type); ++ break; ++ } ++ ++ if (prGlueInfo->prAdapter != NULL) { ++ /* prGlueInfo->ulFlag |= GLUE_FLAG_FRAME_FILTER_AIS; */ ++ set_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ if (in_interrupt()) ++ DBGLOG(REQ, TRACE, "It is in interrupt level\n"); ++ } ++#if 0 ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof ++ (MSG_P2P_MGMT_FRAME_REGISTER_T)); ++ ++ if (prMgmtFrameRegister == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; ++ ++ prMgmtFrameRegister->u2FrameType = frame_type; ++ prMgmtFrameRegister->fgIsRegister = reg; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); ++ ++#endif ++ ++ } while (FALSE); ++ ++} /* mtk_cfg80211_mgmt_frame_register */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to stay on a ++ * specified channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_REMAIN_ON_CHANNEL_T prMsgChnlReq = (P_MSG_REMAIN_ON_CHANNEL_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ *cookie = prGlueInfo->u8Cookie++; ++ ++ prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_REMAIN_ON_CHANNEL_T)); ++ ++ if (prMsgChnlReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ kalMemZero(prMsgChnlReq, sizeof(MSG_REMAIN_ON_CHANNEL_T)); ++ ++ prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_AIS_REMAIN_ON_CHANNEL; ++ prMsgChnlReq->u8Cookie = *cookie; ++ prMsgChnlReq->u4DurationMs = duration; ++ ++ prMsgChnlReq->ucChannelNum = nicFreq2ChannelNum(chan->center_freq * 1000); ++ ++ switch (chan->band) { ++ case NL80211_BAND_2GHZ: ++ prMsgChnlReq->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prMsgChnlReq->eBand = BAND_5G; ++ break; ++ default: ++ prMsgChnlReq->eBand = BAND_2G4; ++ break; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cancel staying ++ * on a specified channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prMsgChnlAbort = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ prMsgChnlAbort = ++ cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_CANCEL_REMAIN_ON_CHANNEL_T)); ++ ++ if (prMsgChnlAbort == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL; ++ prMsgChnlAbort->u8Cookie = cookie; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to send a management frame ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T) NULL; ++ P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucFrameBuf = (PUINT_8) NULL; ++ ++ do { ++#if 1 ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ *cookie = prGlueInfo->u8Cookie++; ++ ++ /* Channel & Channel Type & Wait time are ignored. */ ++ prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_MGMT_TX_REQUEST_T)); ++ ++ if (prMsgTxReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->fgNoneCckRate = FALSE; ++ prMsgTxReq->fgIsWaitRsp = TRUE; ++ ++ prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); ++ prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; ++ if (prMsgTxReq->prMgmtMsduInfo == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->u8Cookie = *cookie; ++ prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX; ++ ++ pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucFrameBuf, params->buf, params->len); ++ ++ prMgmtFrame->u2FrameLength = params->len; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { ++ if (prMsgTxReq->prMgmtMsduInfo != NULL) ++ cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); ++ ++ cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); ++ } ++ ++ return i4Rslt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for requesting to cancel the wait time ++ * from transmitting a management frame on another channel ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ /* not implemented */ ++ ++ return -EINVAL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for handling sched_scan start/stop request ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++ ++int ++mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 i, u4BufLen; ++ P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ ASSERT(prGlueInfo); ++ ++ /* check if there is any pending scan/sched_scan not yet finished */ ++ if (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL) { ++ DBGLOG(SCN, ERROR, "(prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)\n"); ++ return -EBUSY; ++ } else if (request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM) { ++ DBGLOG(SCN, ERROR, "(request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM)\n"); ++ /* invalid scheduled scan request */ ++ return -EINVAL; ++ } else if (/* !request->n_ssids || */!request->n_match_sets) { ++ /* invalid scheduled scan request */ ++ return -EINVAL; ++ } ++ ++ prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) kalMemAlloc(sizeof(PARAM_SCHED_SCAN_REQUEST), VIR_MEM_TYPE); ++ if (prSchedScanRequest == NULL) { ++ DBGLOG(SCN, ERROR, "(prSchedScanRequest == NULL) kalMemAlloc fail\n"); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST)); ++ ++ prSchedScanRequest->u4SsidNum = request->n_match_sets; ++ for (i = 0; i < request->n_match_sets; i++) { ++ if (request->match_sets == NULL || &(request->match_sets[i]) == NULL) { ++ prSchedScanRequest->arSsid[i].u4SsidLen = 0; ++ } else { ++ COPY_SSID(prSchedScanRequest->arSsid[i].aucSsid, ++ prSchedScanRequest->arSsid[i].u4SsidLen, ++ request->match_sets[i].ssid.ssid, request->match_sets[i].ssid.ssid_len); ++ } ++ } ++ ++ prSchedScanRequest->u4IELength = request->ie_len; ++ if (request->ie_len > 0) ++ prSchedScanRequest->pucIE = (PUINT_8) (request->ie); ++ ++ prSchedScanRequest->u2ScanInterval = (UINT_16) (request->scan_plans[0].interval); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetStartSchedScan, ++ prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ kalMemFree(prSchedScanRequest, VIR_MEM_TYPE, sizeof(PARAM_SCHED_SCAN_REQUEST)); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(SCN, ERROR, "scheduled scan error:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ prGlueInfo->prSchedScanRequest = request; ++ ++ return 0; ++} ++ ++int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev, u64 reqid) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* check if there is any pending scan/sched_scan not yet finished */ ++ if (prGlueInfo->prSchedScanRequest == NULL) { ++ DBGLOG(SCN, ERROR, "prGlueInfo->prSchedScanRequest == NULL\n"); ++ return -EBUSY; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(SCN, ERROR, "scheduled scan error, rStatus: %d\n", rStatus); ++ return -EINVAL; ++ } ++ ++ /* 1. reset first for newly incoming request */ ++ /* GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ ++ if (prGlueInfo->prSchedScanRequest != NULL) ++ prGlueInfo->prSchedScanRequest = NULL; ++ /* GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ ++ ++ DBGLOG(SCN, TRACE, "start work queue to send event\n"); ++ schedule_delayed_work(&sched_workq, 0); ++ DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for handling association request ++ * ++ * @param ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_MAC_ADDRESS arBssid; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ PUINT_8 prDesiredIE = NULL; ++#endif ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); ++ ++ /* 1. check BSSID */ ++ if (UNEQUAL_MAC_ADDR(arBssid, req->bss->bssid)) { ++ /* wrong MAC address */ ++ DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", ++ req->bss->bssid, arBssid); ++ return -ENOENT; ++ } ++ ++ if (req->ie && req->ie_len > 0) { ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (wextSrchDesiredHS20IE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetHS20Info, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ ++ if (wextSrchDesiredInterworkingIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInterworkingInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ ++ } ++ } ++ ++ if (wextSrchDesiredRoamingConsortiumIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingConsortiumIEInfo, ++ prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssid, ++ (PVOID) req->bss->bssid, MAC_ADDR_LEN, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++#if CONFIG_NL80211_TESTMODE ++/* ++#define NLA_PUT(skb, attrtype, attrlen, data) \ ++do { \ ++ if (unlikely(nla_put(skb, attrtype, attrlen, data) < 0)) \ ++ goto nla_put_failure; \ ++} while (0) ++ ++#define NLA_PUT_TYPE(skb, type, attrtype, value) \ ++do { \ ++ type __tmp = value; \ ++ NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \ ++} while (0) ++ ++#define NLA_PUT_U8(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u8, attrtype, value) ++ ++#define NLA_PUT_U16(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u16, attrtype, value) ++ ++#define NLA_PUT_U32(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u32, attrtype, value) ++ ++#define NLA_PUT_U64(skb, attrtype, value) \ ++ NLA_PUT_TYPE(skb, u64, attrtype, value) ++*/ ++#if CFG_SUPPORT_WAPI ++int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SET_KEY_EXTS prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) NULL; ++ struct iw_encode_exts *prIWEncExt = (struct iw_encode_exts *)NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4BufLen = 0; ++ ++ P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_key_ext, data is NULL\n"); ++ return -EINVAL; ++ } ++ ++ if (prParams) ++ prIWEncExt = (struct iw_encode_exts *)&prParams->ext; ++ ++ if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { ++ /* KeyID */ ++ prWpiKey->ucKeyID = prParams->key_index; ++ prWpiKey->ucKeyID--; ++ if (prWpiKey->ucKeyID > 1) { ++ /* key id is out of range */ ++ /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ ++ return -EINVAL; ++ } ++ ++ if (prIWEncExt->key_len != 32) { ++ /* key length not valid */ ++ /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ ++ return -EINVAL; ++ } ++ /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ ++ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX; ++ } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX_TX; ++ } ++/* #if CFG_SUPPORT_WAPI */ ++ /* handle_sec_msg_final(prIWEncExt->key, 32, prIWEncExt->key, NULL); */ ++/* #endif */ ++ /* PN */ ++ memcpy(prWpiKey->aucPN, prIWEncExt->tx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ memcpy(prWpiKey->aucPN + IW_ENCODE_SEQ_MAX_SIZE, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ ++ ++ /* BSSID */ ++ memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr, 6); ++ ++ memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); ++ prWpiKey->u4LenWPIEK = 16; ++ ++ memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); ++ prWpiKey->u4LenWPICK = 16; ++ ++ rstatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiKey, ++ prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rstatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ ++ fgIsValid = -EFAULT; ++ } ++ ++ } ++ return fgIsValid; ++} ++#endif ++ ++int ++mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen; ++ UINT_32 u4LinkScore; ++ UINT_32 u4TotalError; ++ UINT_32 u4TxExceedThresholdCount; ++ UINT_32 u4TxTotalCount; ++ ++ P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; ++ PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS) data; ++ } else { ++ DBGLOG(QM, ERROR, "mtk_cfg80211_testmode_get_sta_statistics, data is NULL\n"); ++ return -EINVAL; ++ } ++/* ++ if (!prParams->aucMacAddr) { ++ DBGLOG(QM, INFO, "%s MAC Address is NULL\n", __func__); ++ return -EINVAL; ++ } ++*/ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); ++ ++ if (!skb) { ++ DBGLOG(QM, ERROR, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(QM, TRACE, "Get [ %pM ] STA statistics\n", prParams->aucMacAddr); ++ ++ kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); ++ COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, prParams->aucMacAddr); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStaStatistics, ++ &rQueryStaStatistics, sizeof(rQueryStaStatistics), TRUE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ /* Calcute Link Score */ ++ u4TxExceedThresholdCount = rQueryStaStatistics.u4TxExceedThresholdCount; ++ u4TxTotalCount = rQueryStaStatistics.u4TxTotalCount; ++ u4TotalError = rQueryStaStatistics.u4TxFailCount + rQueryStaStatistics.u4TxLifeTimeoutCount; ++ ++ /* u4LinkScore 10~100 , ExceedThreshold ratio 0~90 only */ ++ /* u4LinkScore 0~9 , Drop packet ratio 0~9 and all packets exceed threshold */ ++ if (u4TxTotalCount) { ++ if (u4TxExceedThresholdCount <= u4TxTotalCount) ++ u4LinkScore = (90 - ((u4TxExceedThresholdCount * 90) / u4TxTotalCount)); ++ else ++ u4LinkScore = 0; ++ } else { ++ u4LinkScore = 90; ++ } ++ ++ u4LinkScore += 10; ++ ++ if (u4LinkScore == 10) { ++ ++ if (u4TotalError <= u4TxTotalCount) ++ u4LinkScore = (10 - ((u4TotalError * 10) / u4TxTotalCount)); ++ else ++ u4LinkScore = 0; ++ ++ } ++ ++ if (u4LinkScore > 100) ++ u4LinkScore = 100; ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, NL80211_DRIVER_TESTMODE_VERSION);*/ ++ { ++ unsigned char __tmp = NL80211_DRIVER_TESTMODE_VERSION; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, u4LinkScore); */ ++ { ++ unsigned int __tmp = u4LinkScore; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, prParams->aucMacAddr);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, &prParams->aucMacAddr) < 0)) ++ goto nla_put_failure; ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, rQueryStaStatistics.u4Flag);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4Flag; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ /* FW part STA link status */ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_PER, rQueryStaStatistics.ucPer);*/ ++ { ++ unsigned char __tmp = rQueryStaStatistics.ucPer; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PER, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, rQueryStaStatistics.ucRcpi);*/ ++ { ++ unsigned char __tmp = rQueryStaStatistics.ucRcpi; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, rQueryStaStatistics.u4PhyMode);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4PhyMode; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U16(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, rQueryStaStatistics.u2LinkSpeed);*/ ++ { ++ unsigned short __tmp = rQueryStaStatistics.u2LinkSpeed; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, ++ sizeof(unsigned short), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, rQueryStaStatistics.u4TxFailCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxFailCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, rQueryStaStatistics.u4TxLifeTimeoutCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxLifeTimeoutCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, rQueryStaStatistics.u4TxAverageAirTime);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageAirTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* Driver part link status */ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, rQueryStaStatistics.u4TxTotalCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxTotalCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ rQueryStaStatistics.u4TxExceedThresholdCount);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxExceedThresholdCount; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ rQueryStaStatistics.u4TxAverageProcessTime);*/ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageProcessTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxMaxTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxAverageHifTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4TxMaxHifTime; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, rQueryStaStatistics.u4EnqueueCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4EnqueueCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, rQueryStaStatistics.u4DequeueCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4DequeueCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, rQueryStaStatistics.u4EnqueueStaCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4EnqueueStaCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, rQueryStaStatistics.u4DequeueStaCounter); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.u4DequeueStaCounter; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, rQueryStaStatistics.IsrCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, rQueryStaStatistics.IsrPassCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrPassCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, rQueryStaStatistics.TaskIsrCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.TaskIsrCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, rQueryStaStatistics.IsrAbnormalCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrAbnormalCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, rQueryStaStatistics.IsrSoftWareCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrSoftWareCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, rQueryStaStatistics.IsrTxCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrTxCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* ++ *NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, rQueryStaStatistics.IsrRxCnt); ++ */ ++ { ++ unsigned int __tmp = rQueryStaStatistics.IsrRxCnt; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /* Network counter */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), rQueryStaStatistics.au4TcResourceEmptyCount);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), &rQueryStaStatistics.au4TcResourceEmptyCount) < 0)) ++ goto nla_put_failure; ++ /* ++ NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ sizeof(rQueryStaStatistics.au4DequeueNoTcResource), rQueryStaStatistics.au4DequeueNoTcResource); ++ */ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ sizeof(rQueryStaStatistics.au4DequeueNoTcResource), &rQueryStaStatistics.au4DequeueNoTcResource) < 0)) ++ goto nla_put_failure; ++ /* ++ NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceBackCount), rQueryStaStatistics.au4TcResourceBackCount); ++ */ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceBackCount), &rQueryStaStatistics.au4TcResourceBackCount) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceUsedCount), &rQueryStaStatistics.au4TcResourceUsedCount) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcResourceWantedCount), ++ &rQueryStaStatistics.au4TcResourceWantedCount) < 0)) ++ goto nla_put_failure; ++ ++ /* Sta queue length */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcQueLen), rQueryStaStatistics.au4TcQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcQueLen), &rQueryStaStatistics.au4TcQueLen) < 0)) ++ goto nla_put_failure; ++ ++ ++ /* Global QM counter */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcAverageQueLen), rQueryStaStatistics.au4TcAverageQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcAverageQueLen), &rQueryStaStatistics.au4TcAverageQueLen) < 0)) ++ goto nla_put_failure; ++ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcCurrentQueLen), rQueryStaStatistics.au4TcCurrentQueLen);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ sizeof(rQueryStaStatistics.au4TcCurrentQueLen), &rQueryStaStatistics.au4TcCurrentQueLen) < 0)) ++ goto nla_put_failure; ++ ++ ++ /* Reserved field */ ++ /*NLA_PUT(skb, ++ NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ sizeof(rQueryStaStatistics.au4Reserved), rQueryStaStatistics.au4Reserved);*/ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ sizeof(rQueryStaStatistics.au4Reserved), &rQueryStaStatistics.au4Reserved) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int ++mtk_cfg80211_testmode_get_link_detection(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen; ++ ++ PARAM_802_11_STATISTICS_STRUCT_T rStatistics; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); ++ ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rStatistics, sizeof(rStatistics)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, rStatistics.rFailedCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFailedCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, rStatistics.rRetryCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFailedCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, rStatistics.rMultipleRetryCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rMultipleRetryCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, rStatistics.rACKFailureCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rACKFailureCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, rStatistics.rFCSErrorCount.QuadPart);*/ ++ { ++ u64 __tmp = rStatistics.rFCSErrorCount.QuadPart; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, ++ sizeof(u64), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if (prParams) { ++ if (prParams->set == 1) { ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, ++ &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct wpa_driver_hs20_data_s *prParams = NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ DBGLOG(REQ, TRACE, "--> %s()\n", __func__); ++ ++ if (data && len) { ++ prParams = (struct wpa_driver_hs20_data_s *)data; ++ ++ DBGLOG(REQ, TRACE, "[%s] Cmd Type (%d)\n", __func__, prParams->CmdType); ++ } ++ ++ if (prParams) { ++ int i; ++ ++ switch (prParams->CmdType) { ++ case HS20_CMD_ID_SET_BSSID_POOL: ++ DBGLOG(REQ, TRACE, "fgBssidPoolIsEnable=%d, ucNumBssidPool=%d\n", ++ prParams->hs20_set_bssid_pool.fgBssidPoolIsEnable, ++ prParams->hs20_set_bssid_pool.ucNumBssidPool); ++ for (i = 0; i < prParams->hs20_set_bssid_pool.ucNumBssidPool; i++) { ++ DBGLOG(REQ, TRACE, "[%d][ %pM ]\n", i, ++ (prParams->hs20_set_bssid_pool.arBssidPool[i])); ++ } ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetHS20BssidPool, ++ &prParams->hs20_set_bssid_pool, ++ sizeof(struct param_hs20_set_bssid_pool), ++ FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ break; ++ default: ++ DBGLOG(REQ, TRACE, "[%s] Unknown Cmd Type (%d)\n", __func__, prParams->CmdType); ++ rstatus = WLAN_STATUS_FAILURE; ++ ++ } ++ ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#endif ++int ++mtk_cfg80211_testmode_set_poorlink_param(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++ int fgIsValid = 0; ++ P_NL80211_DRIVER_POORLINK_PARAMS prParams = NULL; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_POORLINK_PARAMS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_poorlink_param, data is NULL\n"); ++ return -EINVAL; ++ } ++ if (prParams->ucLinkSpeed) ++ prGlueInfo->u4LinkspeedThreshold = prParams->ucLinkSpeed * 10; ++ if (prParams->cRssi) ++ prGlueInfo->i4RssiThreshold = prParams->cRssi; ++ if (!prGlueInfo->fgPoorlinkValid) ++ prGlueInfo->fgPoorlinkValid = 1; ++#if 0 ++ DBGLOG(REQ, TRACE, "poorlink set param valid(%d)rssi(%d)linkspeed(%d)\n", ++ prGlueInfo->fgPoorlinkValid, prGlueInfo->i4RssiThreshold, prGlueInfo->u4LinkspeedThreshold); ++#endif ++ ++ return fgIsValid; ++ ++} ++ ++int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) NULL; ++ INT_32 i4Status = -EINVAL; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ BOOLEAN fgIsValid = 0; ++#endif ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) data; ++ } else { ++ DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd, data is NULL\n"); ++ return i4Status; ++ } ++ ++ /* Clear the version byte */ ++ prParams->index = prParams->index & ~BITS(24, 31); ++ ++ if (prParams) { ++ switch (prParams->index) { ++ case TESTMODE_CMD_ID_SW_CMD: /* SW cmd */ ++ i4Status = mtk_cfg80211_testmode_sw_cmd(wiphy, data, len); ++ break; ++ case TESTMODE_CMD_ID_WAPI: /* WAPI */ ++#if CFG_SUPPORT_WAPI ++ i4Status = mtk_cfg80211_testmode_set_key_ext(wiphy, data, len); ++#endif ++ break; ++ case TESTMODE_CMD_ID_SUSPEND: ++ { ++ P_NL80211_DRIVER_SUSPEND_PARAMS prParams = (P_NL80211_DRIVER_SUSPEND_PARAMS) data; ++ ++ if (prParams->suspend == 1) { ++ wlanHandleSystemSuspend(); ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pHandleSystemSuspend(); ++ i4Status = 0; ++ } else if (prParams->suspend == 0) { ++ wlanHandleSystemResume(); ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pHandleSystemResume(); ++ i4Status = 0; ++ } ++ break; ++ } ++ case TESTMODE_CMD_ID_STATISTICS: ++ i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); ++ break; ++ case TESTMODE_CMD_ID_LINK_DETECT: ++ i4Status = mtk_cfg80211_testmode_get_link_detection(wiphy, data, len, prGlueInfo); ++ break; ++ case TESTMODE_CMD_ID_POORLINK: ++ i4Status = mtk_cfg80211_testmode_set_poorlink_param(wiphy, data, len, prGlueInfo); ++ break; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ case TESTMODE_CMD_ID_HS20: ++ if (mtk_cfg80211_testmode_hs20_cmd(wiphy, data, len)) ++ fgIsValid = TRUE; ++ break; ++#endif ++ default: ++ i4Status = -EINVAL; ++ break; ++ } ++ } ++ ++ return i4Status; ++} ++ ++int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++#define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0 ++#define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1 ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ INT_32 i4Status = -EINVAL, READY_TO_BEAM = 0; ++ ++/* P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; */ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(UINT_32)); ++ READY_TO_BEAM = ++ (UINT_32) (prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo. ++ fgIsGOInitialDone) & ++ (!prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); ++ DBGLOG(QM, TRACE, ++ "NFC:GOInitialDone[%d] and P2PScanning[%d]\n", ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone, ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); ++ ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, READY_TO_BEAM);*/ ++ { ++ unsigned int __tmp = READY_TO_BEAM; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ skb = NULL; ++ ++nla_put_failure: ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++int ++mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) ++{ ++#define MAXMUN_2_4G_CHA_NUM 14 ++#define CHN_DIRTY_WEIGHT_UPPERBOUND 4 ++ ++ BOOLEAN fgIsReady = FALSE, fgIsFistRecord = TRUE; ++ BOOLEAN fgIsPureAP, fgIsLteSafeChn = FALSE; ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_8 ucIdx = 0, ucMax_24G_Chn_List = 11, ucDefaultIdx = 0, ucArrayIdx = 0; ++ UINT_16 u2APNumScore = 0, u2UpThreshold = 0, u2LowThreshold = 0, ucInnerIdx = 0; ++ INT_32 i4Status = -EINVAL; ++ UINT_32 u4BufLen, u4LteSafeChnBitMask_2_4G = 0; ++ UINT32 AcsChnReport[4]; ++ /*RF_CHANNEL_INFO_T aucChannelList[MAXMUN_2_4G_CHA_NUM];*/ ++ ++ struct sk_buff *skb; ++ ++ /*PARAM_GET_CHN_LOAD rQueryLTEChn;*/ ++ P_PARAM_GET_CHN_LOAD prQueryLTEChn; ++ PARAM_PREFER_CHN_INFO rPreferChannels[2], ar2_4G_ChannelLoadingWeightScore[MAXMUN_2_4G_CHA_NUM]; ++ P_PARAM_CHN_LOAD_INFO prChnLoad; ++ P_PARAM_GET_CHN_LOAD prGetChnLoad; ++ ++ P_DOMAIN_INFO_ENTRY prDomainInfo; ++ ++/* ++ P_PARAM_GET_CHN_LOAD prParams = NULL; ++*/ ++ ASSERT(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemZero(rPreferChannels, sizeof(rPreferChannels)); ++ fgIsPureAP = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; ++#if 0 ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_GET_LTE_PARAMS) data; ++#endif ++ skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(AcsChnReport) + sizeof(UINT8) + 1); ++ if (!skb) { ++ DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]Get LTE Channels\n"); ++ prQueryLTEChn = kalMemAlloc(sizeof(PARAM_GET_CHN_LOAD), VIR_MEM_TYPE); ++ if (prQueryLTEChn == NULL) { ++ DBGLOG(QM, TRACE, "alloc QueryLTEChn fail\n"); ++ kalMemFree(skb, VIR_MEM_TYPE, sizeof(struct sk_buff)); ++ return -ENOMEM; ++ } ++ kalMemZero(prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD)); ++ ++ /* Query LTE Safe Channels */ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] ++ = 0xFFFFFFFF; ++ ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = ++ 0xFFFFFFFF; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryACSChannelList, prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD), ++ TRUE, FALSE, TRUE, TRUE, &u4BufLen); ++#if 0 ++ if (fgIsPureAP) { ++ ++ AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = 0x20; /* Channel 6 */ ++ } else ++#endif ++ { ++ fgIsReady = prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit; ++ rPreferChannels[0].u2APNum = 0xFFFF; ++ rPreferChannels[1].u2APNum = 0xFFFF; ++ ++ /* 4 In LTE Mode, Hotspot pick up channels from ch4. */ ++ ucDefaultIdx = 0; ++ /* ++ if (fgIsPureAP) { ++ ucDefaultIdx=3; //SKIP LTE Channels 1~3 ++ } ++ */ ++ ++ /* 4 Get the Maximun channel List in 2.4G Bands */ ++ ++ prDomainInfo = rlmDomainGetDomainInfo(prGlueInfo->prAdapter); ++ ASSERT(prDomainInfo); ++ ++ /* 4 ToDo: Enable Step 2 only if we could get Country Code from framework */ ++ /* 4 2. Get current domain channel list */ ++ ++#if 0 ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, ++ BAND_2G4, MAXMUN_2_4G_CHA_NUM, &ucMax_24G_Chn_List, aucChannelList); ++#endif ++ ++ prGetChnLoad = (P_PARAM_GET_CHN_LOAD) &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); ++ for (ucIdx = 0; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ DBGLOG(P2P, INFO, ++ "[Auto Channel] ch[%d]=%d\n", ucIdx, ++ prGetChnLoad->rEachChnLoad[ucIdx + ucInnerIdx].u2APNum); ++ } ++ ++ /*Calculate Each Channel Direty Score */ ++ for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ ++#if 1 ++ u2APNumScore = prGetChnLoad->rEachChnLoad[ucIdx].u2APNum * CHN_DIRTY_WEIGHT_UPPERBOUND; ++ u2UpThreshold = u2LowThreshold = 3; ++ ++ if (ucIdx < 3) { ++ u2UpThreshold = ucIdx; ++ u2LowThreshold = 3; ++ } else if (ucIdx >= (ucMax_24G_Chn_List - 3)) { ++ u2UpThreshold = 3; ++ u2LowThreshold = ucMax_24G_Chn_List - (ucIdx + 1); ++ ++ } ++ ++ /*Calculate Lower Channel Dirty Score */ ++ for (ucInnerIdx = 0; ucInnerIdx < u2LowThreshold; ucInnerIdx++) { ++ ucArrayIdx = ucIdx + ucInnerIdx + 1; ++ if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { ++ u2APNumScore += ++ (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * ++ (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); ++ } ++ } ++ ++ /*Calculate Upper Channel Dirty Score */ ++ for (ucInnerIdx = 0; ucInnerIdx < u2UpThreshold; ucInnerIdx++) { ++ ucArrayIdx = ucIdx - ucInnerIdx - 1; ++ if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { ++ u2APNumScore += ++ (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * ++ (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); ++ } ++ } ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ ++ DBGLOG(P2P, INFO, "[Auto Channel]chn=%d score=%d\n", ucIdx, u2APNumScore); ++#else ++ if (ucIdx == 0) { ++ /* ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = ++ (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ++ prGetChnLoad->rEachChnLoad[ucIdx+1].u2APNum*0.75); */ ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) ++ ((3 * ++ (prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 1]. ++ u2APNum + ++ prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 2]. ++ u2APNum)) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum)); ++ } ++ if ((ucIdx > 0) && (ucIdx < (MAXMUN_2_4G_CHA_NUM - 1))) { ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) ++ ((3 * ++ (prGetChnLoad-> ++ rEachChnLoad[ucIdx + ++ 1]. ++ u2APNum + ++ prGetChnLoad-> ++ rEachChnLoad[ucIdx - ++ 1]. ++ u2APNum)) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); ++ } ++ ++ if (ucIdx == (MAXMUN_2_4G_CHA_NUM - 1)) { ++ u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ++ ((UINT_16) ((3 * prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum) / 4))); ++ ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, ++ ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, ++ prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); ++ } ++#endif ++ ++ } ++ ++ u4LteSafeChnBitMask_2_4G = ++ prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; ++ ++ /*Find out the best channel */ ++ for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { ++ /* 4 Skip LTE Unsafe Channel */ ++ fgIsLteSafeChn = ((u4LteSafeChnBitMask_2_4G & BIT(ucIdx + 1)) >> ucIdx); ++ if (!fgIsLteSafeChn) ++ continue; ++ ++ prChnLoad = ++ (P_PARAM_CHN_LOAD_INFO) &(prGlueInfo->prAdapter->rWifiVar. ++ rChnLoadInfo.rEachChnLoad[ucIdx]); ++ if (rPreferChannels[0].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum) { ++ rPreferChannels[1].ucChannel = rPreferChannels[0].ucChannel; ++ rPreferChannels[1].u2APNum = rPreferChannels[0].u2APNum; ++ ++ rPreferChannels[0].ucChannel = ucIdx; ++ rPreferChannels[0].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; ++ } else { ++ if (rPreferChannels[1].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum ++ || fgIsFistRecord == 1) { ++ fgIsFistRecord = FALSE; ++ rPreferChannels[1].ucChannel = ucIdx; ++ rPreferChannels[1].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; ++ } ++ } ++ } ++ /* AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1-1] = ++ BITS((rQueryLTEChn.rLteSafeChnList.ucChannelLow-1),(rQueryLTEChn.rLteSafeChnList.ucChannelHigh-1)); */ ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = fgIsReady ? BIT(31) : 0; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] |= BIT(rPreferChannels[0].ucChannel); ++ } ++ ++ /* ToDo: Support 5G Channel Selection */ ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] = 0x11223344; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] = 0x55667788; ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = 0x99AABBCC; ++ ++ /*NLA_PUT_U8(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, 0);*/ ++ { ++ unsigned char __tmp = 0; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, sizeof(unsigned char), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ ++ /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]);*/ ++ { ++ unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]; ++ ++ if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ DBGLOG(P2P, INFO, ++ "[Auto Channel]Relpy AcsChanInfo[%x:%x:%x:%x]\n", AcsChnReport[0], AcsChnReport[1], AcsChnReport[2], ++ AcsChnReport[3]); ++ ++ i4Status = cfg80211_testmode_reply(skb); ++ /*need confirm cfg80211_testmode_reply will free skb*/ ++ skb = NULL; ++ /*kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD));*/ ++ ++nla_put_failure: ++ kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD)); ++ if (skb != NULL) ++ kfree_skb(skb); ++ return i4Status; ++ ++} ++#endif ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief cfg80211 suspend callback, will be invoked in wiphy_suspend ++ * ++ * @param wiphy: pointer to wiphy ++ * wow: pointer to cfg80211_wowlan ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (kalHaltTryLock()) ++ return 0; ++ ++ if (kalIsHalted() || !wiphy) ++ goto end; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ set_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prGlueInfo->prAdapter->ulSuspendFlag); ++ set_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prGlueInfo->prAdapter->ulSuspendFlag); ++end: ++ kalHaltUnlock(); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief cfg80211 resume callback, will be invoked in wiphy_resume. ++ * ++ * @param wiphy: pointer to wiphy ++ * ++ * @retval 0: successful ++ * others: failure ++ */ ++/*----------------------------------------------------------------------------*/ ++int mtk_cfg80211_resume(struct wiphy *wiphy) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_BSS_DESC_T *pprBssDesc = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ UINT_8 i = 0; ++ ++ if (kalHaltTryLock()) ++ return 0; ++ ++ if (kalIsHalted() || !wiphy) ++ goto end; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ prAdapter = prGlueInfo->prAdapter; ++ clear_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag); ++ pprBssDesc = &prAdapter->rWifiVar.rScanInfo.rNloParam.aprPendingBssDescToInd[0]; ++ for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { ++ if (pprBssDesc[i] == NULL) ++ break; ++ if (pprBssDesc[i]->u2RawLength == 0) ++ continue; ++ kalIndicateBssInfo(prGlueInfo, ++ (PUINT_8) pprBssDesc[i]->aucRawBuf, ++ pprBssDesc[i]->u2RawLength, ++ pprBssDesc[i]->ucChannelNum, ++ RCPI_TO_dBm(pprBssDesc[i]->ucRCPI)); ++ } ++ DBGLOG(SCN, INFO, "pending %d sched scan results\n", i); ++ if (i > 0) ++ kalMemZero(&pprBssDesc[0], i * sizeof(P_BSS_DESC_T)); ++end: ++ kalHaltUnlock(); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c +new file mode 100644 +index 000000000000..95ca7546b1bb +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c +@@ -0,0 +1,3502 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_init.c#7 ++*/ ++ ++/*! \file gl_init.c ++ \brief Main routines of Linux driver ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_init.c ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 05 25 2012 yuche.tsai ++ * NULL ++ * Fix reset KE issue. ++ * ++ * 05 11 2012 cp.wu ++ * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience ++ * show MAC address & source while initiliazation ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * EXPORT_SYMBOL(rsnParseCheckForWFAInfoElem);. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Sync CFG80211 modification from branch 2,2. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 12 22 2011 george.huang ++ * [WCXRP00000905] [MT6628 Wi-Fi][FW] Code refinement for ROM/ RAM module dependency ++ * using global variable instead of stack for setting wlanoidSetNetworkAddress(), due to buffer may be released before ++ * TX thread handling ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 14 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Fix large network type index assert in FW issue. ++ * ++ * 11 14 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 06 2011 eddie.chen ++ * [WCXRP00001027] [MT6628 Wi-Fi][Firmware/Driver] Tx fragmentation ++ * Add rlmDomainGetChnlList symbol. ++ * ++ * 09 22 2011 cm.chang ++ * NULL ++ * Safer writng stype to avoid unitialized regitry structure ++ * ++ * 09 21 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Avoid possible structure alignment problem ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 09 08 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM ++ * ++ * 08 31 2011 cm.chang ++ * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code ++ * . ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * expose scnQuerySparseChannel() for P2P-FSM. ++ * ++ * 08 11 2011 cp.wu ++ * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time ++ * sparse channel detection: ++ * driver: collect sparse channel information with scan-done event ++ * ++ * 08 02 2011 yuche.tsai ++ * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting ++ * device issue. ++ * Fix GO send deauth frame issue. ++ * ++ * 07 07 2011 wh.su ++ * [WCXRP00000839] [MT6620 Wi-Fi][Driver] Add the dumpMemory8 and dumpMemory32 EXPORT_SYMBOL ++ * Add the dumpMemory8 symbol export for debug mode. ++ * ++ * 07 06 2011 terry.wu ++ * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment ++ * Improve BoW connection establishment speed. ++ * ++ * 07 05 2011 yuche.tsai ++ * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue ++ * Export one symbol for enhancement. ++ * ++ * 06 13 2011 eddie.chen ++ * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni ++ * Add tx rx statistics and netif_rx_ni. ++ * ++ * 05 27 2011 cp.wu ++ * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM ++ * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain ++ * pass PHY_PARAM in NVRAM from driver to firmware. ++ * ++ * 05 09 2011 jeffrey.chang ++ * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change ++ * support ARP filter through kernel notifier ++ * ++ * 05 03 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. ++ * ++ * 04 27 2011 george.huang ++ * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter ++ * Support P2P ARP filter setting on early suspend/ late resume ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Modify some driver connection flow or behavior to pass Sigma test more easier.. ++ * ++ * 04 12 2011 cm.chang ++ * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency ++ * . ++ * ++ * 04 11 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * export wlan functions to p2p ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * glBusFreeIrq() should use the same pvCookie as glBusSetIrq() or request_irq()/free_irq() won't work as a pair. ++ * ++ * 04 08 2011 eddie.chen ++ * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma ++ * Fix for sigma ++ * ++ * 04 06 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port ++ * 2. update perm_addr as well for MAC address ++ * 3. not calling check_mem_region() anymore for eHPI ++ * 4. correct MSC_CS macro for 0-based notation ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * fix typo. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 23 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * apply multi-queue operation only for linux kernel > 2.6.26 ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability for compatible with linux 2.6.12. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 18 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * remove early suspend functions ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * reverse order to prevent probing racing. ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 jeffrey.chang ++ * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM ++ * refine the queue_select function ++ * ++ * 03 10 2011 cp.wu ++ * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 ++ * deprecate configuration used by MT6620 E2 ++ * ++ * 03 10 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Remove unnecessary assert and message. ++ * ++ * 03 08 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Export nicQmUpdateWmmParms. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 02 24 2011 george.huang ++ * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames ++ * Support ARP filter during suspended ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 02 17 2011 terry.wu ++ * [WCXRP00000459] [MT6620 Wi-Fi][Driver] Fix deference null pointer problem in wlanRemove ++ * Fix deference a null pointer problem in wlanRemove. ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * fix compilig error ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * Add query ipv4 and ipv6 address during early suspend and late resume ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 02 11 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add one more export symbol. ++ * ++ * 02 10 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add RX deauthentication & disassociation process under Hot-Spot mode. ++ * ++ * 02 09 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Halt p2p module init and exit until TxThread finished p2p register and unregister. ++ * ++ * 02 08 2011 george.huang ++ * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler ++ * Support querying power mode OID. ++ * ++ * 02 08 2011 yuche.tsai ++ * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue ++ * Export Deactivation Network. ++ * ++ * 02 01 2011 jeffrey.chang ++ * [WCXRP00000414] KAL Timer is not unregistered when driver not loaded ++ * Unregister the KAL timer during driver unloading ++ * ++ * 01 26 2011 cm.chang ++ * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument ++ * Allocate system RAM if fixed message or mgmt buffer is not available ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 ++ * add compile option to check linux version 2.6.35 for different usage of system API to improve portability ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 15 2010 cp.wu ++ * [WCXRP00000265] [MT6620 Wi-Fi][Driver] Remove set_mac_address routine from legacy Wi-Fi Android driver ++ * remove set MAC address. MAC address is always loaded from NVRAM instead. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 21 2010 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * . ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000106] [MT6620 Wi-Fi][Driver] Enable setting multicast callback in Android ++ * . ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 27 2010 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings ++ * Update BCM/BoW design and settings. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item ++ * use firmware reported mac address right after wlanAdapterStart() as permanent address ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 16 2010 yarco.yang ++ * NULL ++ * Support Linux x86 ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 jeffrey.chang ++ * NULL ++ * fix memory leak for module unloading ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * bug fix: allocate regInfo when disabling firmware download ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * use glue layer api to decrease or increase counter atomically ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Query statistics from firmware ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * modify tcp/ip checksum offload flags ++ * ++ * 04 16 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix tcp/ip checksum offload bug ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set MAC address from firmware ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)improve none-glue code portability ++ * * (2) disable set Multicast address during atomic context ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding debug module ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix f/w download start and load address by using config.h ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download support ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\52 2009-10-27 22:49:59 GMT mtk01090 ++** Fix compile error for Linux EHPI driver ++** \main\maintrunk.MT5921\51 2009-10-20 17:38:22 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\50 2009-10-08 10:33:11 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\49 2009-09-28 20:19:05 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\48 2009-09-03 13:58:46 GMT mtk01088 ++** remove non-used code ++** \main\maintrunk.MT5921\47 2009-09-03 11:40:25 GMT mtk01088 ++** adding the module parameter for wapi ++** \main\maintrunk.MT5921\46 2009-08-18 22:56:41 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\45 2009-07-06 20:53:00 GMT mtk01088 ++** adding the code to check the wapi 1x frame ++** \main\maintrunk.MT5921\44 2009-06-23 23:18:55 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\43 2009-02-16 23:46:51 GMT mtk01461 ++** Revise the order of increasing u4TxPendingFrameNum because of CFG_TX_RET_TX_CTRL_EARLY ++** \main\maintrunk.MT5921\42 2009-01-22 13:11:59 GMT mtk01088 ++** set the tid and 1x value at same packet reserved field ++** \main\maintrunk.MT5921\41 2008-10-20 22:43:53 GMT mtk01104 ++** Fix wrong variable name "prDev" in wlanStop() ++** \main\maintrunk.MT5921\40 2008-10-16 15:37:10 GMT mtk01461 ++** add handle WLAN_STATUS_SUCCESS in wlanHardStartXmit() for CFG_TX_RET_TX_CTRL_EARLY ++** \main\maintrunk.MT5921\39 2008-09-25 15:56:21 GMT mtk01461 ++** Update driver for Code review ++** \main\maintrunk.MT5921\38 2008-09-05 17:25:07 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\37 2008-09-02 10:57:06 GMT mtk01461 ++** Update driver for code review ++** \main\maintrunk.MT5921\36 2008-08-05 01:53:28 GMT mtk01461 ++** Add support for linux statistics ++** \main\maintrunk.MT5921\35 2008-08-04 16:52:58 GMT mtk01461 ++** Fix ASSERT if removing module in BG_SSID_SCAN state ++** \main\maintrunk.MT5921\34 2008-06-13 22:52:24 GMT mtk01461 ++** Revise status code handling in wlanHardStartXmit() for WLAN_STATUS_SUCCESS ++** \main\maintrunk.MT5921\33 2008-05-30 18:56:53 GMT mtk01461 ++** Not use wlanoidSetCurrentAddrForLinux() ++** \main\maintrunk.MT5921\32 2008-05-30 14:39:40 GMT mtk01461 ++** Remove WMM Assoc Flag ++** \main\maintrunk.MT5921\31 2008-05-23 10:26:40 GMT mtk01084 ++** modify wlanISR interface ++** \main\maintrunk.MT5921\30 2008-05-03 18:52:36 GMT mtk01461 ++** Fix Unset Broadcast filter when setMulticast ++** \main\maintrunk.MT5921\29 2008-05-03 15:17:26 GMT mtk01461 ++** Move Query Media Status to GLUE ++** \main\maintrunk.MT5921\28 2008-04-24 22:48:21 GMT mtk01461 ++** Revise set multicast function by using windows oid style for LP own back ++** \main\maintrunk.MT5921\27 2008-04-24 12:00:08 GMT mtk01461 ++** Fix multicast setting in Linux and add comment ++** \main\maintrunk.MT5921\26 2008-03-28 10:40:22 GMT mtk01461 ++** Fix set mac address func in Linux ++** \main\maintrunk.MT5921\25 2008-03-26 15:37:26 GMT mtk01461 ++** Add set MAC Address ++** \main\maintrunk.MT5921\24 2008-03-26 14:24:53 GMT mtk01461 ++** For Linux, set net_device has feature with checksum offload by default ++** \main\maintrunk.MT5921\23 2008-03-11 14:50:52 GMT mtk01461 ++** Fix typo ++** \main\maintrunk.MT5921\22 2008-02-29 15:35:20 GMT mtk01088 ++** add 1x decide code for sw port control ++** \main\maintrunk.MT5921\21 2008-02-21 15:01:54 GMT mtk01461 ++** Rearrange the set off place of GLUE spin lock in HardStartXmit ++** \main\maintrunk.MT5921\20 2008-02-12 23:26:50 GMT mtk01461 ++** Add debug option - Packet Order for Linux and add debug level - Event ++** \main\maintrunk.MT5921\19 2007-12-11 00:11:12 GMT mtk01461 ++** Fix SPIN_LOCK protection ++** \main\maintrunk.MT5921\18 2007-11-30 17:02:25 GMT mtk01425 ++** 1. Set Rx multicast packets mode before setting the address list ++** \main\maintrunk.MT5921\17 2007-11-26 19:44:24 GMT mtk01461 ++** Add OS_TIMESTAMP to packet ++** \main\maintrunk.MT5921\16 2007-11-21 15:47:20 GMT mtk01088 ++** fixed the unload module issue ++** \main\maintrunk.MT5921\15 2007-11-07 18:37:38 GMT mtk01461 ++** Fix compile warnning ++** \main\maintrunk.MT5921\14 2007-11-02 01:03:19 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\13 2007-10-30 10:42:33 GMT mtk01425 ++** 1. Refine for multicast list ++** \main\maintrunk.MT5921\12 2007-10-25 18:08:13 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++** Revision 1.4 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:50 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "gl_cfg80211.h" ++#include "precomp.h" ++#if CFG_SUPPORT_AGPS_ASSIST ++#include "gl_kal.h" ++#endif ++#if defined(CONFIG_MTK_TC1_FEATURE) ++#include ++#endif ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* #define MAX_IOREQ_NUM 10 */ ++ ++BOOLEAN fgIsUnderSuspend = false; ++ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++spinlock_t g_p2p_lock; ++int g_u4P2PEnding = 0; ++int g_u4P2POnOffing = 0; ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Tasklet mechanism is like buttom-half in Linux. We just want to ++ * send a signal to OS for interrupt defer processing. All resources ++ * are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty. ++ */ ++typedef struct _WLANDEV_INFO_T { ++ struct net_device *prDev; ++} WLANDEV_INFO_T, *P_WLANDEV_INFO_T; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#define CHAN2G(_channel, _freq, _flags) \ ++{ \ ++ .band = NL80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_channel mtk_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0), ++}; ++ ++#define CHAN5G(_channel, _flags) \ ++{ \ ++ .band = NL80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_channel mtk_5ghz_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0), ++ CHAN5G(169, 0), CHAN5G(173, 0), ++ CHAN5G(184, 0), CHAN5G(188, 0), ++ CHAN5G(192, 0), CHAN5G(196, 0), ++ CHAN5G(200, 0), CHAN5G(204, 0), ++ CHAN5G(208, 0), CHAN5G(212, 0), ++ CHAN5G(216, 0), ++}; ++ ++#define RATETAB_ENT(_rate, _rateid, _flags) \ ++{ \ ++ .bitrate = (_rate), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++} ++ ++/* for cfg80211 - rate table */ ++static struct ieee80211_rate mtk_rates[] = { ++ RATETAB_ENT(10, 0x1000, 0), ++ RATETAB_ENT(20, 0x1001, 0), ++ RATETAB_ENT(55, 0x1002, 0), ++ RATETAB_ENT(110, 0x1003, 0), /* 802.11b */ ++ RATETAB_ENT(60, 0x2000, 0), ++ RATETAB_ENT(90, 0x2001, 0), ++ RATETAB_ENT(120, 0x2002, 0), ++ RATETAB_ENT(180, 0x2003, 0), ++ RATETAB_ENT(240, 0x2004, 0), ++ RATETAB_ENT(360, 0x2005, 0), ++ RATETAB_ENT(480, 0x2006, 0), ++ RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */ ++}; ++ ++#define mtk_a_rates (mtk_rates + 4) ++#define mtk_a_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 4) ++#define mtk_g_rates (mtk_rates + 0) ++#define mtk_g_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 0) ++ ++#define WLAN_MCS_INFO \ ++{ \ ++ .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},\ ++ .rx_highest = 0, \ ++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ ++} ++ ++#define WLAN_HT_CAP \ ++{ \ ++ .ht_supported = true, \ ++ .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \ ++ | IEEE80211_HT_CAP_SM_PS \ ++ | IEEE80211_HT_CAP_GRN_FLD \ ++ | IEEE80211_HT_CAP_SGI_20 \ ++ | IEEE80211_HT_CAP_SGI_40, \ ++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ ++ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \ ++ .mcs = WLAN_MCS_INFO, \ ++} ++ ++/********************************************************** ++* Public for both legacy Wi-Fi and P2P to access ++**********************************************************/ ++struct ieee80211_supported_band mtk_band_2ghz = { ++ .band = NL80211_BAND_2GHZ, ++ .channels = mtk_2ghz_channels, ++ .n_channels = ARRAY_SIZE(mtk_2ghz_channels), ++ .bitrates = mtk_g_rates, ++ .n_bitrates = mtk_g_rates_size, ++ .ht_cap = WLAN_HT_CAP, ++}; ++ ++struct ieee80211_supported_band mtk_band_5ghz = { ++ .band = NL80211_BAND_5GHZ, ++ .channels = mtk_5ghz_channels, ++ .n_channels = ARRAY_SIZE(mtk_5ghz_channels), ++ .bitrates = mtk_a_rates, ++ .n_bitrates = mtk_a_rates_size, ++ .ht_cap = WLAN_HT_CAP, ++}; ++ ++const UINT_32 mtk_cipher_suites[5] = { ++ /* keep WEP first, it may be removed below */ ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ ++ /* keep last -- depends on hw flags! */ ++ WLAN_CIPHER_SUITE_AES_CMAC ++}; ++ ++/*********************************************************/ ++ ++#define NIC_INF_NAME "wlan%d" /* interface name */ ++#if CFG_TC1_FEATURE ++#define NIC_INF_NAME_IN_AP_MODE "legacy%d" ++#endif ++ ++/* support to change debug module info dynamically */ ++UINT_8 aucDebugModule[DBG_MODULE_NUM]; ++UINT_32 u4DebugModule = 0; ++ ++/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan device to 1 */ ++static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { {0} }; ++ ++static UINT_32 u4WlanDevNum; /* How many NICs coexist now */ ++ ++/**20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan dead loack**/ ++struct delayed_work sched_workq; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++#if CFG_ENABLE_WIFI_DIRECT ++static SUB_MODULE_HANDLER rSubModHandler[SUB_MODULE_NUM] = { {NULL} }; ++#endif ++ ++static struct cfg80211_ops mtk_wlan_ops = { ++ .suspend = mtk_cfg80211_suspend, ++ .resume = mtk_cfg80211_resume, ++ .change_virtual_intf = mtk_cfg80211_change_iface, ++ .add_key = mtk_cfg80211_add_key, ++ .get_key = mtk_cfg80211_get_key, ++ .del_key = mtk_cfg80211_del_key, ++ .set_default_key = mtk_cfg80211_set_default_key, ++ .set_default_mgmt_key = mtk_cfg80211_set_default_mgmt_key, ++ .get_station = mtk_cfg80211_get_station, ++ .change_station = mtk_cfg80211_change_station, ++ .add_station = mtk_cfg80211_add_station, ++ .del_station = mtk_cfg80211_del_station, ++ .scan = mtk_cfg80211_scan, ++ .connect = mtk_cfg80211_connect, ++ .disconnect = mtk_cfg80211_disconnect, ++ .join_ibss = mtk_cfg80211_join_ibss, ++ .leave_ibss = mtk_cfg80211_leave_ibss, ++ .set_power_mgmt = mtk_cfg80211_set_power_mgmt, ++ .set_pmksa = mtk_cfg80211_set_pmksa, ++ .del_pmksa = mtk_cfg80211_del_pmksa, ++ .flush_pmksa = mtk_cfg80211_flush_pmksa, ++ .assoc = mtk_cfg80211_assoc, ++ /* Action Frame TX/RX */ ++ .remain_on_channel = mtk_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = mtk_cfg80211_mgmt_tx, ++/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */ ++ .mgmt_frame_register = mtk_cfg80211_mgmt_frame_register, ++#ifdef CONFIG_NL80211_TESTMODE ++ .testmode_cmd = mtk_cfg80211_testmode_cmd, ++#endif ++#if (CFG_SUPPORT_TDLS == 1) ++ .tdls_mgmt = TdlsexCfg80211TdlsMgmt, ++ .tdls_oper = TdlsexCfg80211TdlsOper, ++#endif /* CFG_SUPPORT_TDLS */ ++#if 1 /* Remove schedule_scan because we need more verification for NLO */ ++ .sched_scan_start = mtk_cfg80211_sched_scan_start, ++ .sched_scan_stop = mtk_cfg80211_sched_scan_stop, ++#endif ++}; ++ ++static const struct wiphy_vendor_command mtk_wlan_vendor_ops[] = { ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_channel_list ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_country_code ++ }, ++ /* GSCAN */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_gscan_capabilities ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_config ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV, ++ .doit = mtk_cfg80211_vendor_set_scan_config ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_enable_scan ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_enable_full_scan_results ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_scan_results ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_significant_change ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_SUBCMD_SET_HOTLIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_hotlist ++ }, ++ /* RTT */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = RTT_SUBCMD_GETCAPABILITY ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_rtt_capabilities ++ }, ++ /* Link Layer Statistics */ ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = LSTATS_SUBCMD_GET_INFO ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_llstats_get_info ++ }, ++ ++}; ++ ++static const struct nl80211_vendor_cmd_info mtk_wlan_vendor_events[] = { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_FOUND ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_SCAN_RESULTS_AVAILABLE ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_FULL_SCAN_RESULTS ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = RTT_EVENT_COMPLETE ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_COMPLETE_SCAN ++ }, ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_LOST ++ }, ++}; ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++ mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = { ++ .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Override the implementation of select queue ++* ++* \param[in] dev Pointer to struct net_device ++* \param[in] skb Pointer to struct skb_buff ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++unsigned int _cfg80211_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp = 0; ++ ++ /* skb->priority values from 256->263 are magic values ++ * directly indicate a specific 802.1d priority. This is ++ * to allow 802.1d priority to be passed directly in from ++ * tags ++ */ ++ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ } ++ return dscp >> 5; ++} ++ ++static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++ ++static UINT_16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, ++ struct net_device *sb_dev, ++ select_queue_fallback_t fallback) ++{ ++ skb->priority = _cfg80211_classify8021d(skb); ++ ++ return au16Wlan1dToQueueIdx[skb->priority]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Load NVRAM data and translate it into REG_INFO_T ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* \param[out] prRegInfo Pointer to struct REG_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void glLoadNvram(IN P_GLUE_INFO_T prGlueInfo, OUT P_REG_INFO_T prRegInfo) ++{ ++ UINT_32 i, j; ++ UINT_8 aucTmp[2]; ++ PUINT_8 pucDest; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prRegInfo); ++ ++ if ((!prGlueInfo) || (!prRegInfo)) ++ return; ++ ++ if (kalCfgDataRead16(prGlueInfo, sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(UINT_16), (PUINT_16) aucTmp) == TRUE) { ++ prGlueInfo->fgNvramAvailable = TRUE; ++ ++ /* load MAC Address */ ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ for (i = 0; i < PARAM_MAC_ADDR_LEN; i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, ++ (PUINT_16) (((PUINT_8) prRegInfo->aucMacAddr) + i)); ++ } ++#else ++ TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prRegInfo->aucMacAddr); ++#endif ++ ++ /* load country code */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), (PUINT_16) aucTmp); ++ ++ /* cast to wide characters */ ++ prRegInfo->au2CountryCode[0] = (UINT_16) aucTmp[0]; ++ prRegInfo->au2CountryCode[1] = (UINT_16) aucTmp[1]; ++ ++ /* load default normal TX power */ ++ for (i = 0; i < sizeof(TX_PWR_PARAM_T); i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i, ++ (PUINT_16) (((PUINT_8) &(prRegInfo->rTxPwr)) + i)); ++ } ++ ++ /* load feature flags */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), (PUINT_16) aucTmp); ++ prRegInfo->ucTxPwrValid = aucTmp[0]; ++ prRegInfo->ucSupport5GBand = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), (PUINT_16) aucTmp); ++ prRegInfo->uc2G4BwFixed20M = aucTmp[0]; ++ prRegInfo->uc5GBwFixed20M = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), (PUINT_16) aucTmp); ++ prRegInfo->ucEnable5GBand = aucTmp[0]; ++ ++ /* load EFUSE overriding part */ ++ for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i, ++ (PUINT_16) (((PUINT_8) &(prRegInfo->aucEFUSE)) + i)); ++ } ++ ++ /* load band edge tx power control */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), (PUINT_16) aucTmp); ++ prRegInfo->fg2G4BandEdgePwrUsed = (BOOLEAN) aucTmp[0]; ++ if (aucTmp[0]) { ++ prRegInfo->cBandEdgeMaxPwrCCK = (INT_8) aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, cBandEdgeMaxPwrOFDM20), (PUINT_16) aucTmp); ++ prRegInfo->cBandEdgeMaxPwrOFDM20 = (INT_8) aucTmp[0]; ++ prRegInfo->cBandEdgeMaxPwrOFDM40 = (INT_8) aucTmp[1]; ++ } ++ ++ /* load regulation subbands */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), (PUINT_16) aucTmp); ++ prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T) aucTmp[0]; ++ prRegInfo->ucRegChannelListIndex = aucTmp[1]; ++ ++ if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { ++ for (i = 0; i < MAX_SUBBAND_NUM; i++) { ++ pucDest = (PUINT_8) &prRegInfo->rDomainInfo.rSubBand[i]; ++ for (j = 0; j < 6; j += sizeof(UINT_16)) { ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) ++ + (i * 6 + j), (PUINT_16) aucTmp); ++ ++ *pucDest++ = aucTmp[0]; ++ *pucDest++ = aucTmp[1]; ++ } ++ } ++ } ++ /* load RSSI compensation */ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2GRssiCompensation), (PUINT_16) aucTmp); ++ prRegInfo->uc2GRssiCompensation = aucTmp[0]; ++ prRegInfo->uc5GRssiCompensation = aucTmp[1]; ++ ++ kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fgRssiCompensationValidbit), (PUINT_16) aucTmp); ++ prRegInfo->fgRssiCompensationValidbit = aucTmp[0]; ++ prRegInfo->ucRxAntennanumber = aucTmp[1]; ++ } else { ++ prGlueInfo->fgNvramAvailable = FALSE; ++ } ++ ++} ++ ++#if CFG_ENABLE_WIFI_DIRECT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief called by txthread, run sub module init function ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /*now, we only have p2p module */ ++ if (rSubModHandler[P2P_MODULE].fgIsInited == FALSE) { ++ rSubModHandler[P2P_MODULE].subModInit(prGlueInfo); ++ rSubModHandler[P2P_MODULE].fgIsInited = TRUE; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief called by txthread, run sub module exit function ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /*now, we only have p2p module */ ++ if (rSubModHandler[P2P_MODULE].fgIsInited == TRUE) { ++ rSubModHandler[P2P_MODULE].subModExit(prGlueInfo); ++ rSubModHandler[P2P_MODULE].fgIsInited = FALSE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set sub module init flag, force TxThread to run sub modle init ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo) ++{ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++ prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_INIT; ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread finish sub module INIT */ ++ wait_for_completion_interruptible(&prGlueInfo->rSubModComp); ++ ++#if 0 ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pNetRegister(prGlueInfo); ++#endif ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set sub module exit flag, force TxThread to run sub modle exit ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo) ++{ ++#if 0 ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ p2pNetUnregister(prGlueInfo); ++#endif ++ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++ prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_EXIT; ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread finish sub module EXIT */ ++ wait_for_completion_interruptible(&prGlueInfo->rSubModComp); ++ ++ return TRUE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set by sub module, indicate sub module is already inserted ++* ++* \param[in] rSubModInit, function pointer point to sub module init function ++* \param[in] rSubModExit, function pointer point to sub module exit function ++* \param[in] eSubModIdx, sub module index ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx) ++{ ++ rSubModHandler[eSubModIdx].subModInit = rSubModInit; ++ rSubModHandler[eSubModIdx].subModExit = rSubModExit; ++ rSubModHandler[eSubModIdx].fgIsInited = FALSE; ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief check wlan is launched or not ++* ++* \param[in] (none) ++* ++* \return TRUE, wlan is already started ++* FALSE, wlan is not started yet ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wlanIsLaunched(VOID) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ /* 4 <0> Sanity check */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (0 == u4WlanDevNum) ++ return FALSE; ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ ++ ASSERT(prDev); ++ if (NULL == prDev) ++ return FALSE; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (NULL == prGlueInfo) ++ return FALSE; ++ ++ return prGlueInfo->prAdapter->fgIsWlanLaunched; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Export wlan GLUE_INFO_T pointer to p2p module ++* ++* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T ++* ++* \return TRUE: get GlueInfo pointer successfully ++* FALSE: wlan is not started yet ++*/ ++/*---------------------------------------------------------------------------*/ ++BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (0 == u4WlanDevNum) ++ return FALSE; ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ if (NULL == prDev) ++ return FALSE; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (NULL == prGlueInfo) ++ return FALSE; ++ ++ if (FALSE == prGlueInfo->prAdapter->fgIsWlanLaunched) ++ return FALSE; ++ ++ *prGlueInfoExpAddr = prGlueInfo; ++ return TRUE; ++} ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release prDev from wlandev_array and free tasklet object related to it. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void wlanClearDevIdx(struct net_device *prDev) ++{ ++ int i; ++ ++ ASSERT(prDev); ++ ++ for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { ++ if (arWlanDevInfo[i].prDev == prDev) { ++ arWlanDevInfo[i].prDev = NULL; ++ u4WlanDevNum--; ++ } ++ } ++ ++} /* end of wlanClearDevIdx() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate an unique interface index, net_device::ifindex member for this ++* wlan device. Store the net_device in wlandev_array, and initialize ++* tasklet object related to it. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \retval >= 0 The device number. ++* \retval -1 Fail to get index. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanGetDevIdx(struct net_device *prDev) ++{ ++ int i; ++ ++ ASSERT(prDev); ++ ++ for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { ++ if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) { ++ /* Reserve 2 bytes space to store one digit of ++ * device number and NULL terminator. ++ */ ++ arWlanDevInfo[i].prDev = prDev; ++ u4WlanDevNum++; ++ return i; ++ } ++ } ++ ++ return -1; ++} /* end of wlanGetDevIdx() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, a primary SOCKET interface to configure ++* the interface lively. Handle an ioctl call on one of our devices. ++* Everything Linux ioctl specific is done here. Then we pass the contents ++* of the ifr->data to the request message handler. ++* ++* \param[in] prDev Linux kernel netdevice ++* ++* \param[in] prIfReq Our private ioctl request structure, typed for the generic ++* struct ifreq so we can use ptr to function ++* ++* \param[in] cmd Command ID ++* ++* \retval 0 The IOCTL command is executed successfully. ++* \retval <0 The execution of IOCTL command is failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ ++ /* Verify input parameters for the following functions */ ++ ASSERT(prDev && prIfReq); ++ if (!prDev || !prIfReq) { ++ DBGLOG(INIT, ERROR, "Invalid input data\n"); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (!prGlueInfo) { ++ DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); ++ return -EFAULT; ++ } ++ ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ DBGLOG(INIT, ERROR, "Adapter is not ready\n"); ++ return -EINVAL; ++ } ++ ++ if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) { ++ /* 0x8B00 ~ 0x8BDF, wireless extension region */ ++ ret = wext_support_ioctl(prDev, prIfReq, i4Cmd); ++ } else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) { ++ /* 0x8BE0 ~ 0x8BFF, private ioctl region */ ++ ret = priv_support_ioctl(prDev, prIfReq, i4Cmd); ++ } else if (i4Cmd == SIOCDEVPRIVATE + 1) { ++ ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); ++ } else { ++ DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} /* end of wlanDoIOCTL() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is to set multicast list and set rx mode. ++* ++* \param[in] prDev Pointer to struct net_device ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static struct delayed_work workq; ++static struct net_device *gPrDev; ++static BOOLEAN fgIsWorkMcStart = FALSE; ++static BOOLEAN fgIsWorkMcEverInit = FALSE; ++static struct wireless_dev *gprWdev; ++ ++static void createWirelessDevice(void) ++{ ++ struct wiphy *prWiphy = NULL; ++ struct wireless_dev *prWdev = NULL; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ struct net_device *prNetDev = NULL; ++#endif ++ ++ /* <1.1> Create wireless_dev */ ++ prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); ++ return; ++ } ++ ++ ++ /* <1.2> Create wiphy */ ++ prWiphy = wiphy_new(&mtk_wlan_ops, sizeof(GLUE_INFO_T)); ++ if (!prWiphy) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wiphy device failed\n"); ++ goto free_wdev; ++ } ++ ++ /* <1.3> configure wireless_dev & wiphy */ ++ prWdev->iftype = NL80211_IFTYPE_STATION; ++ prWiphy->max_scan_ssids = 1; /* FIXME: for combo scan */ ++ prWiphy->max_scan_ie_len = 512; ++ ++ prWiphy->max_sched_scan_ssids = CFG_SCAN_SSID_MAX_NUM; ++ prWiphy->max_match_sets = CFG_SCAN_SSID_MATCH_MAX_NUM; ++ prWiphy->max_sched_scan_ie_len = CFG_CFG80211_IE_BUF_LEN; ++ prWiphy->max_sched_scan_reqs = 1; ++ ++ prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); ++ prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; ++ /* always assign 5Ghz bands here, if the chip is not support 5Ghz, ++ bands[IEEE80211_BAND_5GHZ] will be assign to NULL */ ++ prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; ++ prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ prWiphy->cipher_suites = mtk_cipher_suites; ++ prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); ++ prWiphy->flags = WIPHY_FLAG_SUPPORTS_FW_ROAM ++ | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ++ prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; ++#if CFG_SUPPORT_TDLS ++ TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags); ++#endif /* CFG_SUPPORT_TDLS */ ++ prWiphy->max_remain_on_channel_duration = 5000; ++ prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes; ++ prWiphy->vendor_commands = mtk_wlan_vendor_ops; ++ prWiphy->n_vendor_commands = sizeof(mtk_wlan_vendor_ops) / sizeof(struct wiphy_vendor_command); ++ prWiphy->vendor_events = mtk_wlan_vendor_events; ++ prWiphy->n_vendor_events = ARRAY_SIZE(mtk_wlan_vendor_events); ++ ++ /* <1.4> wowlan support */ ++#ifdef CONFIG_PM ++ prWiphy->wowlan = &mtk_wlan_wowlan_support; ++#endif ++#ifdef CONFIG_CFG80211_WEXT ++ /* <1.5> Use wireless extension to replace IOCTL */ ++ prWiphy->wext = &wext_handler_def; ++#endif ++ ++ if (wiphy_register(prWiphy) < 0) { ++ DBGLOG(INIT, ERROR, "wiphy_register error\n"); ++ goto free_wiphy; ++ } ++ prWdev->wiphy = prWiphy; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* <2> allocate and register net_device */ ++#if CFG_TC1_FEATURE ++ if (wlan_if_changed) ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ else ++#else ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++#endif ++ if (!prNetDev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); ++ goto unregister_wiphy; ++ } ++ ++ *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = (P_GLUE_INFO_T) wiphy_priv(prWiphy); ++ ++ prNetDev->netdev_ops = &wlan_netdev_ops; ++#ifdef CONFIG_WIRELESS_EXT ++ prNetDev->wireless_handlers = &wext_handler_def; ++#endif ++ netif_carrier_off(prNetDev); ++ netif_tx_stop_all_queues(prNetDev); ++ ++ /* <2.1> co-relate with wireless_dev bi-directionally */ ++ prNetDev->ieee80211_ptr = prWdev; ++ prWdev->netdev = prNetDev; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prNetDev->features = NETIF_F_HW_CSUM; ++#endif ++ ++ /* <2.2> co-relate net device & device tree */ ++ SET_NETDEV_DEV(prNetDev, wiphy_dev(prWiphy)); ++ ++ /* <2.3> register net_device */ ++ if (register_netdev(prWdev->netdev) < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); ++ goto unregister_wiphy; ++ } ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ gprWdev = prWdev; ++ DBGLOG(INIT, INFO, "create wireless device success\n"); ++ return; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++unregister_wiphy: ++ wiphy_unregister(prWiphy); ++#endif ++free_wiphy: ++ wiphy_free(prWiphy); ++free_wdev: ++ kfree(prWdev); ++} ++ ++static void destroyWirelessDevice(void) ++{ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(gprWdev->netdev); ++ free_netdev(gprWdev->netdev); ++#endif ++ wiphy_unregister(gprWdev->wiphy); ++ wiphy_free(gprWdev->wiphy); ++ kfree(gprWdev); ++ gprWdev = NULL; ++} ++ ++static void wlanSetMulticastList(struct net_device *prDev) ++{ ++ gPrDev = prDev; ++ schedule_delayed_work(&workq, 0); ++} ++ ++/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange ++ * another workqueue for sleeping. We don't want to block ++ * tx_thread, so we can't let tx_thread to do this */ ++ ++static void wlanSetMulticastListWorkQueue(struct work_struct *work) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4PacketFilter = 0; ++ UINT_32 u4SetInfoLen; ++ struct net_device *prDev = gPrDev; ++ ++ fgIsWorkMcStart = TRUE; ++ ++ if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) ++ return; ++ if (kalIsHalted()) { ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ return; ++ } ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(INIT, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ return; ++ } ++ ++ if (prDev->flags & IFF_PROMISC) ++ u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; ++ ++ if (prDev->flags & IFF_BROADCAST) ++ u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; ++ ++ if (prDev->flags & IFF_MULTICAST) { ++ if ((prDev->flags & IFF_ALLMULTI) || ++ (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { ++ ++ u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } else { ++ u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; ++ } ++ } ++ ++ kalHaltUnlock(); ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetCurrentPacketFilter, ++ &u4PacketFilter, ++ sizeof(u4PacketFilter), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen) != WLAN_STATUS_SUCCESS) { ++ fgIsWorkMcStart = FALSE; ++ DBGLOG(INIT, ERROR, "wlanSetMulticastListWorkQueue kalIoctl u4PacketFilter=%d\n", u4PacketFilter); ++ return; ++ } ++ ++ if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { ++ /* Prepare multicast address list */ ++ struct netdev_hw_addr *ha; ++ PUINT_8 prMCAddrList = NULL; ++ UINT_32 i = 0; ++ ++ if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) ++ return; ++ if (kalIsHalted()) { ++ fgIsWorkMcStart = FALSE; ++ kalHaltUnlock(); ++ /*DBGLOG(INIT, WARN, "wlanSetMulticastListWorkQueue g_u4HaltFlag=%d\n", g_u4HaltFlag);*/ ++ return; ++ } ++ ++ prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE); ++ ++ netdev_for_each_mc_addr(ha, prDev) { ++ if (i < MAX_NUM_GROUP_ADDR) { ++ memcpy((prMCAddrList + i * ETH_ALEN), ha->addr, ETH_ALEN); ++ i++; ++ } ++ } ++ ++ kalHaltUnlock(); ++ ++ kalIoctl(prGlueInfo, ++ wlanoidSetMulticastList, ++ prMCAddrList, (i * ETH_ALEN), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN); ++ } ++ ++ fgIsWorkMcStart = FALSE; ++ ++} /* end of wlanSetMulticastList() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan has been stopped ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID wlanSchedScanStoppedWorkQueue(struct work_struct *work) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct net_device *prDev = gPrDev; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ if (!prGlueInfo) { ++ DBGLOG(SCN, ERROR, "prGlueInfo == NULL unexpected\n"); ++ return; ++ } ++ ++ /* 2. indication to cfg80211 */ ++ /* 20150205 change cfg80211_sched_scan_stopped to work queue due to sched_scan_mtx dead lock issue */ ++ cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo),0); ++ DBGLOG(SCN, INFO, ++ "cfg80211_sched_scan_stopped event send done\n"); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is TX entry point of NET DEVICE. ++* ++* \param[in] prSkb Pointer of the sk_buff to be sent ++* \param[in] prDev Pointer to struct net_device ++* ++* \retval NETDEV_TX_OK - on success. ++* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++*/ ++/*----------------------------------------------------------------------------*/ ++int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ UINT_16 u2QueueIdx = 0; ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ UINT16 u2Identifier = 0; ++#endif ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ prGlueInfo->u8SkbToDriver++; ++ ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ { ++ UINT8 *pkt = prSkb->data; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ /* u2TdlsTxSeq[u4TdlsTxSeqId ++] = u2Identifier; */ ++ DBGLOG(INIT, INFO, " %d\n", u2Identifier); ++ } ++ } ++#endif ++ /* check if WiFi is halt */ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "GLUE_FLAG_HALT skip tx\n"); ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ if (prGlueInfo->fgIsDad) { ++ /* kalPrint("[Passpoint R2] Due to ipv4_dad...TX is forbidden\n"); */ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++ if (prGlueInfo->fgIs6Dad) { ++ /* kalPrint("[Passpoint R2] Due to ipv6_dad...TX is forbidden\n"); */ ++ dev_kfree_skb(prSkb); ++ prGlueInfo->u8SkbFreed++; ++ return NETDEV_TX_OK; ++ } ++#endif ++ ++ STATS_TX_TIME_ARRIVE(prSkb); ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"); ++#endif ++ ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ ++ /* non-1x packets */ ++ ++#if CFG_DBG_GPIO_PINS ++ { ++ /* TX request from OS */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_LOW); ++ kalUdelay(1); ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_HIGH); ++ } ++#endif ++ ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); ++#endif ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++/* GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); */ ++/* GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); */ ++ ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) { ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_stop_subqueue for wlan0, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); ++ ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ prGlueInfo->rHifInfo.HifLoopbkFlg |= 0x01; ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ } ++ } ++ } else { ++ /* printk("is security frame\n"); */ ++ ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ DBGLOG(TX, EVENT, "\n+++++ pending frame %d len = %d +++++\n", prGlueInfo->i4TxPendingFrameNum, prSkb->len); ++ prGlueInfo->rNetDevStats.tx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.tx_packets++; ++ kalPerMonStart(prGlueInfo); ++ ++ /* set GLUE_FLAG_TXREQ_BIT */ ++ ++ /* pr->u4Flag |= GLUE_FLAG_TXREQ; */ ++ /* wake_up_interruptible(&prGlueInfo->waitq); */ ++ kalSetEvent(prGlueInfo); ++ ++ /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ ++ return NETDEV_TX_OK; ++} /* end of wlanHardStartXmit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, to get the network interface statistical ++* information. ++* ++* Whenever an application needs to get statistics for the interface, this method ++* is called. This happens, for example, when ifconfig or netstat -i is run. ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return net_device_stats buffer pointer. ++*/ ++/*----------------------------------------------------------------------------*/ ++struct net_device_stats *wlanGetStats(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++#if 0 ++ WLAN_STATUS rStatus; ++ UINT_32 u4XmitError = 0; ++ UINT_32 u4XmitOk = 0; ++ UINT_32 u4RecvError = 0; ++ UINT_32 u4RecvOk = 0; ++ UINT_32 u4BufLen; ++ ++ ASSERT(prDev); ++ ++ /* @FIX ME: need a more clear way to do this */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryXmitError, &u4XmitError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryXmitOk, &u4XmitOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryRcvOk, &u4RecvOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRcvError, &u4RecvError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); ++ prGlueInfo->rNetDevStats.rx_packets = u4RecvOk; ++ prGlueInfo->rNetDevStats.tx_packets = u4XmitOk; ++ prGlueInfo->rNetDevStats.tx_errors = u4XmitError; ++ prGlueInfo->rNetDevStats.rx_errors = u4RecvError; ++ /* prGlueInfo->rNetDevStats.rx_bytes = rCustomNetDevStats.u4RxBytes; */ ++ /* prGlueInfo->rNetDevStats.tx_bytes = rCustomNetDevStats.u4TxBytes; */ ++ /* prGlueInfo->rNetDevStats.rx_errors = rCustomNetDevStats.u4RxErrors; */ ++ /* prGlueInfo->rNetDevStats.multicast = rCustomNetDevStats.u4Multicast; */ ++#endif ++ /* prGlueInfo->rNetDevStats.rx_packets = 0; */ ++ /* prGlueInfo->rNetDevStats.tx_packets = 0; */ ++ prGlueInfo->rNetDevStats.tx_errors = 0; ++ prGlueInfo->rNetDevStats.rx_errors = 0; ++ /* prGlueInfo->rNetDevStats.rx_bytes = 0; */ ++ /* prGlueInfo->rNetDevStats.tx_bytes = 0; */ ++ prGlueInfo->rNetDevStats.rx_errors = 0; ++ prGlueInfo->rNetDevStats.multicast = 0; ++ ++ return &prGlueInfo->rNetDevStats; ++ ++} /* end of wlanGetStats() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->init ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanInit succeeds. ++* \retval -ENXIO No such device. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanInit(struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (fgIsWorkMcEverInit == FALSE) { ++ if (!prDev) ++ return -ENXIO; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue); ++ ++ /* 20150205 work queue for sched_scan */ ++ INIT_DELAYED_WORK(&sched_workq, wlanSchedScanStoppedWorkQueue); ++ ++ fgIsWorkMcEverInit = TRUE; ++ } ++ ++ return 0; /* success */ ++} /* end of wlanInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->uninit ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void wlanUninit(struct net_device *prDev) ++{ ++ ++} /* end of wlanUninit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->open ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanOpen succeeds. ++* \retval < 0 The execution of wlanOpen failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanOpen(struct net_device *prDev) ++{ ++ ASSERT(prDev); ++ ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of wlanOpen() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->stop ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanStop succeeds. ++* \retval < 0 The execution of wlanStop failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wlanStop(struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ /* CFG80211 down */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueInfo->prScanRequest; ++ prGlueInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (prScanRequest) ++ cfg80211_scan_done(prScanRequest, &info); ++ netif_tx_stop_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of wlanStop() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief Update channel table for cfg80211 based on current country domain ++ * ++ * \param[in] prGlueInfo Pointer to glue info ++ * ++ * \return none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 i, j; ++ UINT_8 ucNumOfChannel; ++ RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels)]; ++ ++ /* 1. Disable all channels */ ++ for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) { ++ mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; ++ mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) { ++ mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; ++ mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; ++ } ++ ++ /* 2. Get current domain channel list */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, ++ BAND_NULL, FALSE, ++ ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels), ++ &ucNumOfChannel, aucChannelList); ++ ++ /* 3. Enable specific channel based on domain channel list */ ++ for (i = 0; i < ucNumOfChannel; i++) { ++ switch (aucChannelList[i].eBand) { ++ case BAND_2G4: ++ for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) { ++ if (mtk_2ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { ++ mtk_2ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; ++ mtk_2ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; ++ break; ++ } ++ } ++ break; ++ ++ case BAND_5G: ++ for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) { ++ if (mtk_5ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { ++ mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; ++ mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; ++ break; ++ } ++ } ++ break; ++ ++ default: ++ DBGLOG(INIT, WARN, "Unknown band %d\n", aucChannelList[i].eBand); ++ break; ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register the device to the kernel and return the index. ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanNetRegister succeeds. ++* \retval < 0 The execution of wlanNetRegister failed. ++*/ ++/*----------------------------------------------------------------------------*/ ++static INT_32 wlanNetRegister(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ INT_32 i4DevIdx = -1; ++ ++ ASSERT(prWdev); ++ ++ do { ++ if (!prWdev) ++ break; ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ i4DevIdx = wlanGetDevIdx(prWdev->netdev); ++ if (i4DevIdx < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device number exceeds.\n"); ++ break; ++ } ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ if (register_netdev(prWdev->netdev) < 0) { ++ DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); ++ ++ wiphy_unregister(prWdev->wiphy); ++ wlanClearDevIdx(prWdev->netdev); ++ i4DevIdx = -1; ++ } ++#endif ++ if (i4DevIdx != -1) ++ prGlueInfo->fgIsRegistered = TRUE; ++ ++ } while (FALSE); ++ ++ return i4DevIdx; /* success */ ++} /* end of wlanNetRegister() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister the device from the kernel ++* ++* \param[in] prWdev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanNetUnregister(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "wlanNetUnregister: The device context is NULL\n"); ++ return; ++ } ++ DBGLOG(INIT, TRACE, "unregister net_dev(0x%p)\n", prWdev->netdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ wlanClearDevIdx(prWdev->netdev); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(prWdev->netdev); ++#endif ++ prGlueInfo->fgIsRegistered = FALSE; ++ ++ DBGLOG(INIT, INFO, "unregister wireless_dev(0x%p), ifindex=%d\n", prWdev, prWdev->netdev->ifindex); ++ ++} /* end of wlanNetUnregister() */ ++ ++static const struct net_device_ops wlan_netdev_ops = { ++ .ndo_open = wlanOpen, ++ .ndo_stop = wlanStop, ++ .ndo_set_rx_mode = wlanSetMulticastList, ++ .ndo_get_stats = wlanGetStats, ++ .ndo_do_ioctl = wlanDoIOCTL, ++ .ndo_start_xmit = wlanHardStartXmit, ++ .ndo_init = wlanInit, ++ .ndo_uninit = wlanUninit, ++ .ndo_select_queue = wlanSelectQueue, ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method for creating Linux NET4 struct net_device object and the ++* private data(prGlueInfo and prAdapter). Setup the IO address to the HIF. ++* Assign the function pointer to the net_device object ++* ++* \param[in] pvData Memory address for the device ++* ++* \retval Not null The wireless_dev object. ++* \retval NULL Fail to create wireless_dev object ++*/ ++/*----------------------------------------------------------------------------*/ ++static struct lock_class_key rSpinKey[SPIN_LOCK_NUM]; ++static struct wireless_dev *wlanNetCreate(PVOID pvData) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct wireless_dev *prWdev = gprWdev; ++ UINT_32 i; ++ struct device *prDev; ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); ++ return NULL; ++ } ++ /* 4 <1> co-relate wiphy & prDev */ ++#if MTK_WCN_HIF_SDIO ++ mtk_wcn_hif_sdio_get_dev(*((MTK_WCN_HIF_SDIO_CLTCTX *) pvData), &prDev); ++#else ++/* prDev = &((struct sdio_func *) pvData)->dev; //samp */ ++ prDev = pvData; /* samp */ ++#endif ++ if (!prDev) ++ DBGLOG(INIT, WARN, "unable to get struct dev for wlan\n"); ++ /* don't set prDev as parent of wiphy->dev, because we have done device_add ++ in driver init. if we set parent here, parent will be not able to know this child, ++ and may occurs a KE in device_shutdown, to free wiphy->dev, because his parent ++ has been freed. */ ++ /*set_wiphy_dev(prWdev->wiphy, prDev);*/ ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ /* 4 <3> Initial Glue structure */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ kalMemZero(prGlueInfo, sizeof(GLUE_INFO_T)); ++ /* 4 <3.1> Create net device */ ++#if CFG_TC1_FEATURE ++ if (wlan_if_changed) { ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, ++ NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ } else { ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ } ++#else ++ prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++#endif ++ if (!prGlueInfo->prDevHandler) { ++ DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); ++ return NULL; ++ } ++ DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated ifindex=%d\n", ++ prGlueInfo->prDevHandler, prGlueInfo->prDevHandler->ifindex); ++ ++ /* 4 <3.1.1> initialize net device varaiables */ ++ *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prDevHandler)) = prGlueInfo; ++ ++ prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops; ++#ifdef CONFIG_WIRELESS_EXT ++ prGlueInfo->prDevHandler->wireless_handlers = &wext_handler_def; ++#endif ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prDevHandler); ++ ++ /* 4 <3.1.2> co-relate with wiphy bi-directionally */ ++ prGlueInfo->prDevHandler->ieee80211_ptr = prWdev; ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prGlueInfo->prDevHandler->features = NETIF_F_HW_CSUM; ++#endif ++ prWdev->netdev = prGlueInfo->prDevHandler; ++ ++ /* 4 <3.1.3> co-relate net device & prDev */ ++ /*SET_NETDEV_DEV(prGlueInfo->prDevHandler, wiphy_dev(prWdev->wiphy));*/ ++ SET_NETDEV_DEV(prGlueInfo->prDevHandler, prDev); ++#else /* CFG_SUPPORT_PERSIST_NETDEV */ ++ prGlueInfo->prDevHandler = gprWdev->netdev; ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ ++ /* 4 <3.2> initiali glue variables */ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ prGlueInfo->ePowerState = ParamDeviceStateD0; ++ prGlueInfo->fgIsMacAddrOverride = FALSE; ++ prGlueInfo->fgIsRegistered = FALSE; ++ prGlueInfo->prScanRequest = NULL; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* Init DAD */ ++ prGlueInfo->fgIsDad = FALSE; ++ prGlueInfo->fgIs6Dad = FALSE; ++ kalMemZero(prGlueInfo->aucDADipv4, 4); ++ kalMemZero(prGlueInfo->aucDADipv6, 16); ++#endif ++ ++ init_completion(&prGlueInfo->rScanComp); ++ init_completion(&prGlueInfo->rHaltComp); ++ init_completion(&prGlueInfo->rPendComp); ++#if CFG_ENABLE_WIFI_DIRECT ++ init_completion(&prGlueInfo->rSubModComp); ++#endif ++ ++ /* initialize timer for OID timeout checker */ ++ kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler); ++ ++ for (i = 0; i < SPIN_LOCK_NUM; i++) { ++ spin_lock_init(&prGlueInfo->rSpinLock[i]); ++ lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]); ++ } ++ ++ /* initialize semaphore for ioctl */ ++ sema_init(&prGlueInfo->ioctl_sem, 1); ++ ++ glSetHifInfo(prGlueInfo, (ULONG) pvData); ++ ++ /* 4 <8> Init Queues */ ++ init_waitqueue_head(&prGlueInfo->waitq); ++ QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue); ++ QUEUE_INITIALIZE(&prGlueInfo->rTxQueue); ++ ++ /* 4 <4> Create Adapter structure */ ++ prGlueInfo->prAdapter = (P_ADAPTER_T) wlanAdapterCreate(prGlueInfo); ++ ++ if (!prGlueInfo->prAdapter) { ++ DBGLOG(INIT, ERROR, "Allocating memory to adapter failed\n"); ++ return NULL; ++ } ++ KAL_WAKE_LOCK_INIT(prAdapter, &prGlueInfo->rAhbIsrWakeLock, "WLAN AHB ISR"); ++#if CFG_SUPPORT_PERSIST_NETDEV ++ dev_open(prGlueInfo->prDevHandler); ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prDevHandler); ++#endif ++ ++ return prWdev; ++} /* end of wlanNetCreate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Destroying the struct net_device object and the private data. ++* ++* \param[in] prWdev Pointer to struct wireless_dev. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanNetDestroy(struct wireless_dev *prWdev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prWdev); ++ ++ if (!prWdev) { ++ DBGLOG(INIT, ERROR, "wlanNetDestroy: The device context is NULL\n"); ++ return; ++ } ++ ++ /* prGlueInfo is allocated with net_device */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ ASSERT(prGlueInfo); ++ ++ /* destroy kal OS timer */ ++ kalCancelTimer(prGlueInfo); ++ ++ glClearHifInfo(prGlueInfo); ++ ++ wlanAdapterDestroy(prGlueInfo->prAdapter); ++ prGlueInfo->prAdapter = NULL; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* take the net_device to down state */ ++ dev_close(prGlueInfo->prDevHandler); ++#else ++ /* Free net_device and private data prGlueInfo, which are allocated by alloc_netdev(). */ ++ free_netdev(prWdev->netdev); ++#endif ++ ++} /* end of wlanNetDestroy() */ ++ ++#ifndef CONFIG_X86 ++UINT_8 g_aucBufIpAddr[32] = { 0 }; ++static void wlanNotifyFwSuspend(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgSuspend) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidNotifyFwSuspend, ++ (PVOID)&fgSuspend, ++ sizeof(fgSuspend), ++ FALSE, ++ FALSE, ++ TRUE, ++ FALSE, ++ &u4SetInfoLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, INFO, "wlanNotifyFwSuspend fail\n"); ++} ++ ++void wlanHandleSystemSuspend(void) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ ++ /* <1> Sanity check and acquire the net_device */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (u4WlanDevNum == 0) { ++ DBGLOG(INIT, ERROR, "wlanEarlySuspend u4WlanDevNum==0 invalid!!\n"); ++ return; ++ } ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ ++ fgIsUnderSuspend = true; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ kalPerMonDisable(prGlueInfo); ++ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ goto notify_suspend; ++ } ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++#ifdef CONFIG_IPV6 ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ goto notify_suspend; ++ } ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ++ ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] ++ ); ++ ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) { ++ /* Do nothing */ ++ /* u4NumIPv6++; */ ++ } ++#endif ++ ++ /* <7> set up the ARP filter */ ++ { ++ UINT_32 u4SetInfoLen = 0; ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#ifdef CONFIG_IPV6 ++ prParamNetAddrList->u4AddressCount += u4NumIPv6; ++#endif ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ prParamNetAddr = ++ (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); ++ } ++#ifdef CONFIG_IPV6 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(ip6)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ ++notify_suspend: ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ wlanNotifyFwSuspend(prGlueInfo, TRUE); ++} ++ ++void wlanHandleSystemResume(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_8 ip[4] = { 0 }; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++#endif ++ EVENT_AIS_BSS_INFO_T rParam; ++ UINT_32 u4BufLen = 0; ++ ++ /* <1> Sanity check and acquire the net_device */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (u4WlanDevNum == 0) { ++ DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n"); ++ return; ++ } ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ /* ASSERT(prDev); */ ++ ++ fgIsUnderSuspend = false; ++ ++ if (!prDev) { ++ DBGLOG(INIT, INFO, "prDev == NULL!!!\n"); ++ return; ++ } ++ /* <3> acquire the prGlueInfo */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ kalPerMonEnable(prGlueInfo); ++ ++ /* ++ We will receive the event in rx, we will check if the status is the same in driver ++ and FW, if not the same, trigger disconnetion procedure. ++ */ ++ ++ kalMemZero(&rParam, sizeof(EVENT_AIS_BSS_INFO_T)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBSSInfo, ++ &rParam, sizeof(EVENT_AIS_BSS_INFO_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "Query BSSinfo fail 0x%x!!\n", rStatus); ++ } ++ ++ /* <2> get the IPv4 address */ ++ if (!(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ goto notify_resume; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ goto notify_resume; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ++ ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] ++ ); ++#endif ++ /* <7> clear the ARP filter */ ++ { ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = 0; ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ ++notify_resume: ++ DBGLOG(INIT, INFO, "Query BSS result: %d %d %d, IP: %d.%d.%d.%d, rStatus: %u\n", ++ rParam.eConnectionState, rParam.eCurrentOPMode, rParam.fgIsNetActive, ++ ip[0], ip[1], ip[2], ip[3], rStatus); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ wlanNotifyFwSuspend(prGlueInfo, FALSE); ++ } ++} ++#endif /* ! CONFIG_X86 */ ++ ++int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode) ++{ ++#if 0 ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ rSetP2P.u4Enable = p2pmode.u4Enable; ++ rSetP2P.u4Mode = p2pmode.u4Mode; ++ ++ if (!rSetP2P.u4Enable) ++ p2pNetUnregister(prGlueInfo, TRUE); ++ ++ rWlanStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pMode, ++ (PVOID) &rSetP2P, ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(INIT, INFO, "ret = %d\n", rWlanStatus); ++ if (rSetP2P.u4Enable) ++ p2pNetRegister(prGlueInfo, TRUE); ++ ++ return 0; ++ ++#else ++ ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgIsP2PEnding; ++ UINT_32 u4BufLen = 0; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ DBGLOG(INIT, INFO, "%u %u\n", (UINT_32) p2pmode.u4Enable, (UINT_32) p2pmode.u4Mode); ++ ++ /* avoid remove & p2p off command simultaneously */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2PEnding = g_u4P2PEnding; ++ g_u4P2POnOffing = 1; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ if (fgIsP2PEnding == 1) { ++ /* skip the command if we are removing */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ return 0; ++ } ++ ++ rSetP2P.u4Enable = p2pmode.u4Enable; ++ rSetP2P.u4Mode = p2pmode.u4Mode; ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ if ((!rSetP2P.u4Enable) && (fgIsResetting == FALSE)) ++ p2pNetUnregister(prGlueInfo, TRUE); ++#endif ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ /* ++ Scenario: ++ 1. System enters suspend/resume but not yet enter wlanearlysuspend() ++ or wlanlateresume(); ++ ++ 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() ++ and get g_halt_sem then do glRegisterEarlySuspend() or ++ glUnregisterEarlySuspend(); ++ ++ But system suspend/resume procedure is not yet finished so we ++ suspend; ++ ++ 3. System switches back to do suspend/resume procedure and execute ++ kalIoctl(). But driver does not yet release g_halt_sem so system ++ suspend in wlanearlysuspend() or wlanlateresume(); ++ ++ ==> deadlock occurs. ++ */ ++ ++ rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, (PVOID) &rSetP2P,/* pu4IntBuf[0]is used as input SubCmd */ ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ /* Need to check fgIsP2PRegistered, in case of whole chip reset. ++ * in this case, kalIOCTL return success always, ++ * and prGlueInfo->prP2pInfo may be NULL */ ++ if ((rSetP2P.u4Enable) && (prGlueInfo->prAdapter->fgIsP2PRegistered) && (fgIsResetting == FALSE)) ++ p2pNetRegister(prGlueInfo, TRUE); ++#endif ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ return 0; ++#endif ++} ++ ++static void set_dbg_level_handler(unsigned char dbg_lvl[DBG_MODULE_NUM]) ++{ ++ kalMemCopy(aucDebugModule, dbg_lvl, sizeof(aucDebugModule)); ++ kalPrint("[wlan] change debug level"); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Wlan probe function. This function probes and initializes the device. ++* ++* \param[in] pvData data passed by bus driver init function ++* _HIF_EHPI: NULL ++* _HIF_SDIO: sdio bus driver handle ++* ++* \retval 0 Success ++* \retval negative value Failed ++*/ ++/*----------------------------------------------------------------------------*/ ++static INT_32 wlanProbe(PVOID pvData) ++{ ++ struct wireless_dev *prWdev = NULL; ++ enum probe_fail_reason { ++ BUS_INIT_FAIL, ++ NET_CREATE_FAIL, ++ BUS_SET_IRQ_FAIL, ++ ADAPTER_START_FAIL, ++ NET_REGISTER_FAIL, ++ PROC_INIT_FAIL, ++ FAIL_REASON_NUM ++ } eFailReason; ++ P_WLANDEV_INFO_T prWlandevInfo = NULL; ++ INT_32 i4DevIdx = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ INT_32 i4Status = 0; ++ BOOLEAN bRet = FALSE; ++ ++ eFailReason = FAIL_REASON_NUM; ++ do { ++ /* 4 <1> Initialize the IO port of the interface */ ++ /* GeorgeKuo: pData has different meaning for _HIF_XXX: ++ * _HIF_EHPI: pointer to memory base variable, which will be ++ * initialized by glBusInit(). ++ * _HIF_SDIO: bus driver handle ++ */ ++ ++ bRet = glBusInit(pvData); ++ wlanDebugInit(); ++ /* Cannot get IO address from interface */ ++ if (FALSE == bRet) { ++ DBGLOG(INIT, ERROR, KERN_ALERT "wlanProbe: glBusInit() fail\n"); ++ i4Status = -EIO; ++ eFailReason = BUS_INIT_FAIL; ++ break; ++ } ++ /* 4 <2> Create network device, Adapter, KalInfo, prDevHandler(netdev) */ ++ prWdev = wlanNetCreate(pvData); ++ if (prWdev == NULL) { ++ DBGLOG(INIT, ERROR, "wlanProbe: No memory for dev and its private\n"); ++ i4Status = -ENOMEM; ++ eFailReason = NET_CREATE_FAIL; ++ break; ++ } ++ /* 4 <2.5> Set the ioaddr to HIF Info */ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); ++ gPrDev = prGlueInfo->prDevHandler; ++ ++ /* 4 <4> Setup IRQ */ ++ prWlandevInfo = &arWlanDevInfo[i4DevIdx]; ++ ++ i4Status = glBusSetIrq(prWdev->netdev, NULL, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ ++ if (i4Status != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n"); ++ eFailReason = BUS_SET_IRQ_FAIL; ++ break; ++ } ++ ++ prGlueInfo->i4DevIdx = i4DevIdx; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ prGlueInfo->u4ReadyFlag = 0; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prAdapter->u4CSUMFlags = (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP); ++#endif ++#if CFG_SUPPORT_CFG_FILE ++ { ++ PUINT_8 pucConfigBuf; ++ UINT_32 u4ConfigReadLen; ++ ++ wlanCfgInit(prAdapter, NULL, 0, 0); ++ pucConfigBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE); ++ u4ConfigReadLen = 0; ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read File...\n"); ++ if (pucConfigBuf) { ++ kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE); ++ if (kalReadToFile("/data/misc/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi.cfg\n"); ++ ++ } else if (kalReadToFile("/data/misc/wifi/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi/wifi.cfg\n"); ++ } else if (kalReadToFile("/etc/firmware/wifi.cfg", ++ pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { ++ DBGLOG(INIT, LOUD, "CFG_FILE: Read /etc/firmware/wifi.cfg\n"); ++ } ++ ++ if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0) ++ wlanCfgInit(prAdapter, pucConfigBuf, u4ConfigReadLen, 0); ++ kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE); ++ } /* pucConfigBuf */ ++ } ++#endif ++ /* 4 <5> Start Device */ ++ /* */ ++#if CFG_ENABLE_FW_DOWNLOAD ++ DBGLOG(INIT, TRACE, "start to download firmware...\n"); ++ ++ /* before start adapter, we need to open and load firmware */ ++ { ++ UINT_32 u4FwSize = 0; ++ PVOID prFwBuffer = NULL; ++ P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; ++ ++ /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ ++ kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T)); ++ prRegInfo->u4StartAddress = CFG_FW_START_ADDRESS; ++ prRegInfo->u4LoadAddress = CFG_FW_LOAD_ADDRESS; ++ ++ /* Load NVRAM content to REG_INFO_T */ ++ glLoadNvram(prGlueInfo, prRegInfo); ++#if CFG_SUPPORT_CFG_FILE ++ wlanCfgApply(prAdapter); ++#endif ++ ++ /* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); */ ++ ++ prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; ++ prRegInfo->fgEnArpFilter = TRUE; ++ ++ if (kalFirmwareImageMapping(prGlueInfo, &prFwBuffer, &u4FwSize) == NULL) { ++ i4Status = -EIO; ++ DBGLOG(INIT, ERROR, "kalFirmwareImageMapping fail!\n"); ++ goto bailout; ++ } else { ++ ++ if (wlanAdapterStart(prAdapter, prRegInfo, prFwBuffer, ++ u4FwSize) != WLAN_STATUS_SUCCESS) { ++ i4Status = -EIO; ++ } ++ } ++ ++ kalFirmwareImageUnmapping(prGlueInfo, NULL, prFwBuffer); ++ ++bailout: ++ /* kfree(prRegInfo); */ ++ ++ DBGLOG(INIT, TRACE, "download firmware status = %d\n", i4Status); ++ ++ if (i4Status < 0) { ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4FwCnt; ++ ++ DBGLOG(INIT, WARN, "CONNSYS FW CPUINFO:\n"); ++ HifInfo = &prAdapter->prGlueInfo->rHifInfo; ++ for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) ++ DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); ++ /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ ++ ++ /* dump HIF/DMA registers, if fgIsBusAccessFailed is FALSE, otherwise, */ ++ /* dump HIF register may be hung */ ++ if (!fgIsBusAccessFailed) ++ HifRegDump(prGlueInfo->prAdapter); ++/* if (prGlueInfo->rHifInfo.DmaOps->DmaRegDump != NULL) */ ++/* prGlueInfo->rHifInfo.DmaOps->DmaRegDump(&prGlueInfo->rHifInfo); */ ++ eFailReason = ADAPTER_START_FAIL; ++ break; ++ } ++ } ++#else ++ /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ ++ kalMemSet(&prGlueInfo->rRegInfo, 0, sizeof(REG_INFO_T)); ++ P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; ++ ++ /* Load NVRAM content to REG_INFO_T */ ++ glLoadNvram(prGlueInfo, prRegInfo); ++ ++ prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; ++ ++ if (wlanAdapterStart(prAdapter, prRegInfo, NULL, 0) != WLAN_STATUS_SUCCESS) { ++ i4Status = -EIO; ++ eFailReason = ADAPTER_START_FAIL; ++ break; ++ } ++#endif ++ if (FALSE == prAdapter->fgEnable5GBand) ++ prWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; ++ ++ prGlueInfo->main_thread = kthread_run(tx_thread, prGlueInfo->prDevHandler, "tx_thread"); ++ kalSetHalted(FALSE); ++#if CFG_SUPPORT_ROAMING_ENC ++ /* adjust roaming threshold */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ CMD_ROAMING_INFO_T rRoamingInfo; ++ UINT_32 u4SetInfoLen = 0; ++ ++ prAdapter->fgIsRoamingEncEnabled = TRUE; ++ ++ /* suggestion from Tsaiyuan.Hsu */ ++ kalMemZero(&rRoamingInfo, sizeof(CMD_ROAMING_INFO_T)); ++ rRoamingInfo.fgIsFastRoamingApplied = TRUE; ++ ++ DBGLOG(INIT, TRACE, "Enable roaming enhance function\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRoamingInfo, ++ &rRoamingInfo, sizeof(rRoamingInfo), TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, ERROR, "set roaming advance info fail 0x%x\n", rStatus); ++ } ++#endif /* CFG_SUPPORT_ROAMING_ENC */ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++ /* adjust tx rate switch threshold */ ++ rlmTxRateEnhanceConfig(prGlueInfo->prAdapter); ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++ /* set MAC address */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ struct sockaddr MacAddr; ++ UINT_32 u4SetInfoLen = 0; ++ ++ kalMemZero(MacAddr.sa_data, sizeof(MacAddr.sa_data)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryCurrentAddr, ++ &MacAddr.sa_data, ++ PARAM_MAC_ADDR_LEN, TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, WARN, "set MAC addr fail 0x%x\n", rStatus); ++ prGlueInfo->u4ReadyFlag = 0; ++ } else { ++ ether_addr_copy(prGlueInfo->prDevHandler->dev_addr, (const u8 *)&(MacAddr.sa_data)); ++ ether_addr_copy(prGlueInfo->prDevHandler->perm_addr, ++ prGlueInfo->prDevHandler->dev_addr); ++ ++ /* card is ready */ ++ prGlueInfo->u4ReadyFlag = 1; ++#if CFG_SHOW_MACADDR_SOURCE ++ DBGLOG(INIT, INFO, "MAC address: %pM ", (&MacAddr.sa_data)); ++#endif ++ } ++ } ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ /* set HW checksum offload */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; ++ UINT_32 u4SetInfoLen = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetCSUMOffload, ++ (PVOID) &u4CSUMFlags, ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(INIT, WARN, "set HW checksum offload fail 0x%x\n", rStatus); ++ } ++#endif ++ ++ /* 4 <3> Register the card */ ++ DBGLOG(INIT, TRACE, "wlanNetRegister...\n"); ++ i4DevIdx = wlanNetRegister(prWdev); ++ if (i4DevIdx < 0) { ++ i4Status = -ENXIO; ++ DBGLOG(INIT, ERROR, "wlanProbe: Cannot register the net_device context to the kernel\n"); ++ eFailReason = NET_REGISTER_FAIL; ++ break; ++ } ++ ++ wlanRegisterNotifier(); ++ /* 4 <6> Initialize /proc filesystem */ ++#ifdef WLAN_INCLUDE_PROC ++ DBGLOG(INIT, TRACE, "init procfs...\n"); ++ i4Status = procCreateFsEntry(prGlueInfo); ++ if (i4Status < 0) { ++ DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n"); ++ eFailReason = PROC_INIT_FAIL; ++ break; ++ } ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; ++ prGlueInfo->rBowInfo.fgIsRegistered = FALSE; ++ glRegisterAmpc(prGlueInfo); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ DBGLOG(INIT, TRACE, "wlanSubModInit...\n"); ++ ++ /* wlan is launched */ ++ prGlueInfo->prAdapter->fgIsWlanLaunched = TRUE; ++ /* if p2p module is inserted, notify tx_thread to init p2p network */ ++ if (rSubModHandler[P2P_MODULE].subModInit) ++ wlanSubModInit(prGlueInfo); ++ /* register set_p2p_mode handler to mtk_wmt_wifi */ ++ register_set_p2p_mode_handler(set_p2p_mode_handler); ++#endif ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock, "WLAN AP"); ++#endif ++ } while (FALSE); ++ ++ if (i4Status != WLAN_STATUS_SUCCESS) { ++ switch (eFailReason) { ++ case PROC_INIT_FAIL: ++ wlanNetUnregister(prWdev); ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ wlanAdapterStop(prAdapter); ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case NET_REGISTER_FAIL: ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); ++ wlanAdapterStop(prAdapter); ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case ADAPTER_START_FAIL: ++ glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case BUS_SET_IRQ_FAIL: ++ KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ wlanNetDestroy(prWdev); ++ break; ++ case NET_CREATE_FAIL: ++ break; ++ case BUS_INIT_FAIL: ++ break; ++ default: ++ break; ++ } ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ { ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2PEnding = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ } ++#endif ++#if CFG_SUPPORT_AGPS_ASSIST ++ if (i4Status == WLAN_STATUS_SUCCESS) ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL, 0); ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ { ++ int iMetInitRet = WLAN_STATUS_FAILURE; ++ ++ if (i4Status == WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, TRACE, "init MET procfs...\n"); ++ iMetInitRet = kalMetInitProcfs(prGlueInfo); ++ if (iMetInitRet < 0) ++ DBGLOG(INIT, ERROR, "wlanProbe: init MET procfs failed\n"); ++ } ++ } ++#endif ++ if (i4Status == WLAN_STATUS_SUCCESS) { ++ /*Init performance monitor structure */ ++ kalPerMonInit(prGlueInfo); ++ /* probe ok */ ++ DBGLOG(INIT, TRACE, "wlanProbe ok\n"); ++ } else { ++ /* we don't care the return value of mtk_wcn_set_connsys_power_off_flag, ++ * because even this function returns ++ * error, we can also call core dump but only core dump failed. */ ++ if (g_IsNeedDoChipReset) ++ mtk_wcn_set_connsys_power_off_flag(0); ++ /* probe failed */ ++ DBGLOG(INIT, ERROR, "wlanProbe failed\n"); ++ } ++ ++ return i4Status; ++} /* end of wlanProbe() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method to stop driver operation and release all resources. Following ++* this call, no frame should go up or down through this interface. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID wlanRemove(VOID) ++{ ++#define KAL_WLAN_REMOVE_TIMEOUT_MSEC 3000 ++ struct net_device *prDev = NULL; ++ P_WLANDEV_INFO_T prWlandevInfo = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ ++ DBGLOG(INIT, LOUD, "Remove wlan!\n"); ++ ++ /* 4 <0> Sanity check */ ++ ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); ++ if (0 == u4WlanDevNum) { ++ DBGLOG(INIT, ERROR, "0 == u4WlanDevNum\n"); ++ return; ++ } ++ /* unregister set_p2p_mode handler to mtk_wmt_wifi */ ++ register_set_p2p_mode_handler(NULL); ++ ++ prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; ++ prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1]; ++ ++ ASSERT(prDev); ++ if (NULL == prDev) { ++ DBGLOG(INIT, ERROR, "NULL == prDev\n"); ++ return; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (NULL == prGlueInfo) { ++ DBGLOG(INIT, ERROR, "NULL == prGlueInfo\n"); ++ free_netdev(prDev); ++ return; ++ } ++ ++ kalPerMonDestroy(prGlueInfo); ++#if CFG_ENABLE_WIFI_DIRECT ++ /* avoid remove & p2p off command simultaneously */ ++ { ++ BOOLEAN fgIsP2POnOffing; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2PEnding = 1; ++ fgIsP2POnOffing = g_u4P2POnOffing; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ DBGLOG(INIT, TRACE, "waiting for fgIsP2POnOffing...\n"); ++ ++ /* History: cannot use down() here, sometimes we cannot come back here */ ++ /* waiting for p2p off command finishes, we cannot skip the remove */ ++ while (1) { ++ if (fgIsP2POnOffing == 0) ++ break; ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2POnOffing = g_u4P2POnOffing; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ } ++ } ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered) { ++ bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter); ++ /* wait 300ms for BoW module to send deauth */ ++ kalMsleep(300); ++ } ++#endif ++ ++ /* 4 <1> Stopping handling interrupt and free IRQ */ ++ DBGLOG(INIT, TRACE, "free IRQ...\n"); ++ glBusFreeIrq(prDev, *((P_GLUE_INFO_T *) netdev_priv(prDev))); ++ ++ kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); ++ ++ kalSetHalted(TRUE); /* before flush_delayed_work() */ ++ if (fgIsWorkMcStart == TRUE) { ++ DBGLOG(INIT, TRACE, "flush_delayed_work...\n"); ++ flush_delayed_work(&workq); /* flush_delayed_work_sync is deprecated */ ++ } ++ ++ flush_delayed_work(&sched_workq); ++ ++ DBGLOG(INIT, INFO, "down g_halt_sem...\n"); ++ kalHaltLock(KAL_WLAN_REMOVE_TIMEOUT_MSEC); ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ ++/* flush_delayed_work_sync(&workq); */ ++/* flush_delayed_work(&workq); */ /* flush_delayed_work_sync is deprecated */ ++ ++ /* 4 <2> Mark HALT, notify main thread to stop, and clean up queued requests */ ++/* prGlueInfo->u4Flag |= GLUE_FLAG_HALT; */ ++ set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); ++ DBGLOG(INIT, TRACE, "waiting for tx_thread stop...\n"); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ DBGLOG(INIT, TRACE, "wait_for_completion_interruptible\n"); ++ ++ /* wait main thread stops */ ++ wait_for_completion_interruptible(&prGlueInfo->rHaltComp); ++ ++ DBGLOG(INIT, TRACE, "mtk_sdiod stopped\n"); ++ ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rTxThreadWakeLock); ++ KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->rAhbIsrWakeLock); ++ ++ /* prGlueInfo->rHifInfo.main_thread = NULL; */ ++ prGlueInfo->main_thread = NULL; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (prGlueInfo->rBowInfo.fgIsRegistered) ++ glUnregisterAmpc(prGlueInfo); ++#endif ++ ++ /* 4 <3> Remove /proc filesystem. */ ++#ifdef WLAN_INCLUDE_PROC ++ procRemoveProcfs(); ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetRemoveProcfs(); ++#endif ++ ++ /* Force to do DMA reset */ ++ DBGLOG(INIT, TRACE, "glResetHif\n"); ++ glResetHif(prGlueInfo); ++ ++ /* 4 <4> wlanAdapterStop */ ++ prAdapter = prGlueInfo->prAdapter; ++#if CFG_SUPPORT_AGPS_ASSIST ++ kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL, 0); ++#endif ++ ++ wlanAdapterStop(prAdapter); ++ DBGLOG(INIT, TRACE, "Number of Stalled Packets = %d\n", prGlueInfo->i4TxPendingFrameNum); ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ prGlueInfo->prAdapter->fgIsWlanLaunched = FALSE; ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) { ++ DBGLOG(INIT, TRACE, "p2pNetUnregister...\n"); ++#if !CFG_SUPPORT_PERSIST_NETDEV ++ p2pNetUnregister(prGlueInfo, FALSE); ++#endif ++ DBGLOG(INIT, INFO, "p2pRemove...\n"); ++ p2pRemove(prGlueInfo); ++ } ++#endif ++ ++ /* 4 <5> Release the Bus */ ++ glBusRelease(prDev); ++ ++ kalHaltUnlock(); ++ wlanDebugUninit(); ++ /* 4 <6> Unregister the card */ ++ wlanNetUnregister(prDev->ieee80211_ptr); ++ ++ /* 4 <7> Destroy the device */ ++ wlanNetDestroy(prDev->ieee80211_ptr); ++ prDev = NULL; ++ ++ DBGLOG(INIT, LOUD, "wlanUnregisterNotifier...\n"); ++ wlanUnregisterNotifier(); ++ ++ DBGLOG(INIT, INFO, "wlanRemove ok\n"); ++} /* end of wlanRemove() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver entry point when the driver is configured as a Linux Module, and ++* is called once at module load time, by the user-level modutils ++* application: insmod or modprobe. ++* ++* \retval 0 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Entry Point */ ++static int initWlan(void) ++{ ++ int ret = 0, i; ++#if DBG ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = DBG_CLASS_MASK; /* enable all */ ++#else ++ /* Initial debug level is D1 */ ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = DBG_CLASS_ERROR | DBG_CLASS_WARN | DBG_CLASS_INFO | DBG_CLASS_STATE; ++#endif /* DBG */ ++ DBGLOG(INIT, INFO, "initWlan\n"); ++ ++ spin_lock_init(&g_p2p_lock); ++ ++ /* memory pre-allocation */ ++ kalInitIOBuffer(); ++ procInitFs(); ++ createWirelessDevice(); ++ if (gprWdev) ++ glP2pCreateWirelessDevice((P_GLUE_INFO_T) wiphy_priv(gprWdev->wiphy)); ++ ++ ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0 : -EIO); ++ ++ if (ret == -EIO) { ++ kalUninitIOBuffer(); ++ return ret; ++ } ++#if (CFG_CHIP_RESET_SUPPORT) ++ glResetInit(); ++#endif ++ ++ /* register set_dbg_level handler to mtk_wmt_wifi */ ++ register_set_dbg_level_handler(set_dbg_level_handler); ++ ++ /* Set the initial DEBUG CLASS of each module */ ++ return ret; ++} /* end of initWlan() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver exit point when the driver as a Linux Module is removed. Called ++* at module unload time, by the user level modutils application: rmmod. ++* This is our last chance to clean up after ourselves. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Leave Point */ ++static VOID exitWlan(void) ++{ ++ DBGLOG(INIT, INFO, "exitWlan\n"); ++ ++ /* unregister set_dbg_level handler to mtk_wmt_wifi */ ++ register_set_dbg_level_handler(NULL); ++ ++#if CFG_CHIP_RESET_SUPPORT ++ glResetUninit(); ++#endif ++ destroyWirelessDevice(); ++ glP2pDestroyWirelessDevice(); ++ ++ glUnregisterBus(wlanRemove); ++ ++ /* free pre-allocated memory */ ++ kalUninitIOBuffer(); ++ ++ DBGLOG(INIT, INFO, "exitWlan\n"); ++ procUninitProcFs(); ++ ++} /* end of exitWlan() */ ++ ++#ifdef MTK_WCN_BUILT_IN_DRIVER ++ ++int mtk_wcn_wlan_gen2_init(void) ++{ ++ return initWlan(); ++} ++EXPORT_SYMBOL(mtk_wcn_wlan_gen2_init); ++ ++void mtk_wcn_wlan_gen2_exit(void) ++{ ++ return exitWlan(); ++} ++EXPORT_SYMBOL(mtk_wcn_wlan_gen2_exit); ++ ++#else ++ ++module_init(initWlan); ++module_exit(exitWlan); ++ ++#endif ++ ++MODULE_AUTHOR(NIC_AUTHOR); ++MODULE_DESCRIPTION(NIC_DESC); ++MODULE_SUPPORTED_DEVICE(NIC_NAME); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +new file mode 100644 +index 000000000000..3a257c9f85c4 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +@@ -0,0 +1,4799 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_kal.c#3 ++*/ ++ ++/*! \file gl_kal.c ++ \brief GLUE Layer will export the required procedures here for internal driver stack. ++ ++ This file contains all routines which are exported from GLUE Layer to internal ++ driver stack. ++*/ ++ ++/* ++** Log: gl_kal.c ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 05 31 2012 terry.wu ++ * NULL ++ * . ++ * ++ * 03 26 2012 cp.wu ++ * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist ++ * invoke put_cred() after get_current_cred() calls. ++ * ++ * 03 07 2012 yuche.tsai ++ * NULL ++ * Fix compile error when WiFi Direct is off. ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 02 20 2012 cp.wu ++ * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist ++ * do not need to invoke free() while firmware image file doesn't exist ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 21 2011 cp.wu ++ * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing ++ * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer ++ * add more checking for such cases ++ * ++ * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. ++ * add some tweaking to protect such cases because that net device has become invalid. ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 16 2011 yuche.tsai ++ * NULL ++ * Avoid using work thread. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 23 2011 yuche.tsai ++ * [WCXRP00000998] [Volunteer Patch][WiFi Direct][FW] P2P Social Channel & country domain issue ++ * Regulation domain feature check in. ++ * ++ * 08 12 2011 cp.wu ++ * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC ++ * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 06 13 2011 eddie.chen ++ * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni ++ * Add tx rx statistics and netif_rx_ni. ++ * ++ * 04 15 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW short range mode. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 08 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * correct i4TxPendingFrameNum decreasing. ++ * ++ * 03 23 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * apply multi-queue operation only for linux kernel > 2.6.26 ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability for compatible with linux 2.6.12. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * refix ... ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * correct compiling warning/error. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * add more robust fault tolerance design when pre-allocation failed. (rarely happen) ++ * ++ * 03 17 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * use pre-allocated buffer for storing enhanced interrupt response as well ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 14 2011 jeffrey.chang ++ * [WCXRP00000546] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] fix kernel build warning message ++ * fix kernel build warning message ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 01 24 2011 cp.wu ++ * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving ++ * 1. add an extra counter for tracking pending forward frames. ++ * 2. notify TX service thread as well when there is pending forward frame ++ * 3. correct build errors leaded by introduction of Wi-Fi direct separation module ++ * ++ * 01 19 2011 cp.wu ++ * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 ++ * add compile option to check linux version 2.6.35 for different usage of system API to improve portability ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field ++ * checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used ++ * to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 11 02 2010 jeffrey.chang ++ * [WCXRP00000145] [MT6620 Wi-Fi][Driver] fix issue of byte endian in packet classifier which discards BoW packets ++ * . ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 26 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] ++ * Support NIC capability query command ++ * 1) update NVRAM content template to ver 1.02 ++ * 2) add compile option for querying NIC capability (default: off) ++ * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting ++ * 4) correct auto-rate compiler error under linux (treat warning as error) ++ * 5) simplify usage of NVRAM and REG_INFO_T ++ * 6) add version checking between driver and firmware ++ * ++ * 10 25 2010 jeffrey.chang ++ * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform ++ * Remove redundant code which cause mismatch of power control release ++ * ++ * 10 25 2010 jeffrey.chang ++ * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform ++ * Remove redundant GLUE_HALT condfition to avoid unmatched release of power control ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue ++ * refine the scan ioctl to prevent hanging of Android UI ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * if there is NVRAM, then use MAC address on NVRAM as default MAC address. ++ * ++ * 10 06 2010 cp.wu ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * code reorganization to improve isolation between GLUE and CORE layers. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 30 2010 cp.wu ++ * NULL ++ * API added: nicTxPendingPackets(), for simplifying porting layer ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Support second interface indicate when enabling P2P. ++ * ++ * 08 18 2010 yarco.yang ++ * NULL ++ * 1. Fixed HW checksum offload function not work under Linux issue. ++ * 2. Add debug message. ++ * ++ * 08 16 2010 jeffrey.chang ++ * NULL ++ * remove redundant code which cause kernel panic ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * add new KAL api ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * bug fix: allocate regInfo when disabling firmware download ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * use glue layer api to decrease or increase counter atomically ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * modify tx thread and remove some spinlock ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * use different spin lock for security frame ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add spinlock for pending security frame count ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * adjust the timer unit to microsecond ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * timer should return value greater than zero ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add new kal api ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * for linux driver migration ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 yarco.yang ++ * [WPD00003837][MT6620]Data Path Refine ++ * Merge g_arStaRec[] into adapter->arStaRec[] ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * remove unused files. ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix private ioctl for rftest ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * workaround for fixing request_firmware() failure on android 2.1 ++ * ++ * 05 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix kernel panic when debug mode enabled ++ * ++ * 05 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) Modify set mac address code ++ * 2) remove power management macro ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Disable network interface after disassociation ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 15 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * change firmware name ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * flush pending TX packets while unloading driver ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set driver own before handling cmd queue ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used ++ * 2) fix ioctl ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add spinlock for i4TxPendingFrameNum access ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * * 2) add KAPI for handling association info ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix spinlock usage ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 04 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Set MAC address from firmware ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1. free cmdinfo after command is emiited. ++ * 2. for BoW frames, user priority is extracted from sk_buff directly. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)deliver the kalOidComplete status to upper layer ++ * (2) fix spin lock ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * * 2) add 2 kal API for later integration ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * raising the priority of processing interrupt ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Bug fix: the tx thread will cause starvation of MMC thread, and the interrupt will never come in ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding secondary command queue for improving non-glue code portability ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download kal api ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add Bluetooth-over-Wifi frame header check ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\50 2009-09-28 20:19:08 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\49 2009-08-18 22:56:44 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\48 2009-06-23 23:18:58 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\47 2008-11-19 11:55:43 GMT mtk01088 ++** fixed some lint warning, and rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\46 2008-09-02 21:07:42 GMT mtk01461 ++** Remove ASSERT(pvBuf) in kalIndicateStatusAndComplete(), this parameter can be NULL ++** \main\maintrunk.MT5921\45 2008-08-29 16:03:21 GMT mtk01088 ++** remove non-used code for code review, add assert check ++** \main\maintrunk.MT5921\44 2008-08-21 00:32:49 GMT mtk01461 ++** \main\maintrunk.MT5921\43 2008-05-30 20:27:02 GMT mtk01461 ++** Rename KAL function ++** \main\maintrunk.MT5921\42 2008-05-30 15:47:29 GMT mtk01461 ++** \main\maintrunk.MT5921\41 2008-05-30 15:13:04 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\40 2008-05-29 14:15:14 GMT mtk01084 ++** remove un-used KAL function ++** \main\maintrunk.MT5921\39 2008-05-03 15:17:30 GMT mtk01461 ++** Move Query Media Status to GLUE ++** \main\maintrunk.MT5921\38 2008-04-24 11:59:44 GMT mtk01461 ++** change awake queue threshold and remove code which mark #if 0 ++** \main\maintrunk.MT5921\37 2008-04-17 23:06:35 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\36 2008-04-08 15:38:56 GMT mtk01084 ++** add KAL function to setting pattern search function enable/ disable ++** \main\maintrunk.MT5921\35 2008-04-01 23:53:13 GMT mtk01461 ++** Add comment ++** \main\maintrunk.MT5921\34 2008-03-26 15:36:48 GMT mtk01461 ++** Add update MAC Address for Linux ++** \main\maintrunk.MT5921\33 2008-03-18 11:49:34 GMT mtk01084 ++** update function for initial value access ++** \main\maintrunk.MT5921\32 2008-03-18 10:25:22 GMT mtk01088 ++** use kal update associate request at linux ++** \main\maintrunk.MT5921\31 2008-03-06 23:43:08 GMT mtk01385 ++** 1. add Query Registry Mac address function. ++** \main\maintrunk.MT5921\30 2008-02-26 09:47:57 GMT mtk01084 ++** modify KAL set network address/ checksum offload part ++** \main\maintrunk.MT5921\29 2008-02-12 23:26:53 GMT mtk01461 ++** Add debug option - Packet Order for Linux ++** \main\maintrunk.MT5921\28 2008-01-09 17:54:43 GMT mtk01084 ++** modify the argument of kalQueryPacketInfo() ++** \main\maintrunk.MT5921\27 2007-12-24 16:02:03 GMT mtk01425 ++** 1. Revise csum offload ++** \main\maintrunk.MT5921\26 2007-11-30 17:03:36 GMT mtk01425 ++** 1. Fix bugs ++** ++** \main\maintrunk.MT5921\25 2007-11-29 01:57:17 GMT mtk01461 ++** Fix Windows RX multiple packet retain problem ++** \main\maintrunk.MT5921\24 2007-11-20 11:24:07 GMT mtk01088 ++** CR90, not doing the netif_carrier_off to let supplicant 1x pkt can be rcv at hardstattXmit ++** \main\maintrunk.MT5921\23 2007-11-09 16:36:44 GMT mtk01425 ++** 1. Modify for CSUM offloading with Tx Fragment ++** \main\maintrunk.MT5921\22 2007-11-07 18:37:39 GMT mtk01461 ++** Add Tx Fragmentation Support ++** \main\maintrunk.MT5921\21 2007-11-06 19:34:06 GMT mtk01088 ++** add the WPS code, indicate the mgmt frame to upper layer ++** \main\maintrunk.MT5921\20 2007-11-02 01:03:21 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\19 2007-10-30 11:59:38 GMT MTK01425 ++** 1. Update wlanQueryInformation ++** \main\maintrunk.MT5921\18 2007-10-30 10:44:57 GMT mtk01425 ++** 1. Refine multicast list code ++** 2. Refine TCP/IP csum offload code ++** ++** Revision 1.5 2007/07/17 13:01:18 MTK01088 ++** add associate req and rsp function ++** ++** Revision 1.4 2007/07/13 05:19:19 MTK01084 ++** provide timer set functions ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include "gl_os.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#if defined(CONFIG_MTK_TC1_FEATURE) ++#include ++#endif ++#if CFG_SUPPORT_AGPS_ASSIST ++#include ++#endif ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++#include ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++#if DBG ++int allocatedMemSize = 0; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++/* #define MTK_DMA_BUF_MEMCPY_SUP */ ++static PVOID pvIoBuffer; ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++static PVOID pvIoPhyBuf; ++static PVOID pvDmaBuffer; ++static PVOID pvDmaPhyBuf; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++static UINT_32 pvIoBufferSize; ++static UINT_32 pvIoBufferUsage; ++static struct KAL_HALT_CTRL_T rHaltCtrl = { ++ .lock = __SEMAPHORE_INITIALIZER(rHaltCtrl.lock, 1), ++ .owner = NULL, ++ .fgHalt = TRUE, ++ .fgHeldByKalIoctl = FALSE, ++ .u4HoldStart = 0, ++}; ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT ++typedef enum _ENUM_WMTHWVER_TYPE_T { ++ WMTHWVER_MT6620_E1 = 0x0, ++ WMTHWVER_MT6620_E2 = 0x1, ++ WMTHWVER_MT6620_E3 = 0x2, ++ WMTHWVER_MT6620_E4 = 0x3, ++ WMTHWVER_MT6620_E5 = 0x4, ++ WMTHWVER_MT6620_E6 = 0x5, ++ WMTHWVER_MT6620_MAX, ++ WMTHWVER_INVALID = 0xff ++} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &(prGlueInfo->rAhbIsrWakeLock), (HZ / 10)); /* 100ms */ ++} ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++static struct file *filp; ++static uid_t orgfsuid; ++static gid_t orgfsgid; ++static mm_segment_t orgfs; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* open firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_8 aucFilePath[50]; ++ ++ /* FIX ME: since we don't have hotplug script in the filesystem ++ * , so the request_firmware() KAPI can not work properly ++ */ ++ ++ /* save uid and gid used for filesystem access. ++ * set user and group to 0(root) */ ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ orgfsuid = cred->fsuid.val; ++ orgfsgid = cred->fsgid.val; ++ cred->fsuid.val = cred->fsgid.val = 0; ++ ++ ASSERT(prGlueInfo); ++ ++ orgfs = get_fs(); ++ set_fs(get_ds()); ++ ++ /* open the fw file */ ++#if defined(MT6620) & CFG_MULTI_ECOVER_SUPPORT ++ switch (mtk_wcn_wmt_hwver_get()) { ++ case WMTHWVER_MT6620_E1: ++ case WMTHWVER_MT6620_E2: ++ case WMTHWVER_MT6620_E3: ++ case WMTHWVER_MT6620_E4: ++ case WMTHWVER_MT6620_E5: ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); ++ break; ++ ++ case WMTHWVER_MT6620_E6: ++ default: ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME "_E6", O_RDONLY, 0); ++ break; ++ } ++#elif defined(MT6628) ++/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6628", O_RDONLY, 0); */ ++/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6582", O_RDONLY, 0); */ ++#if 0 /* new wifi ram code mechanism, waiting firmware ready, then we can enable these code */ ++ kalMemZero(aucFilePath, sizeof(aucFilePath)); ++ kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_AD", sizeof("/etc/firmware/" CFG_FW_FILENAME "_AD")); ++ filp = filp_open(aucFilePath, O_RDONLY, 0); ++ if (!IS_ERR(filp)) ++ goto open_success; ++#endif ++ kalMemZero(aucFilePath, sizeof(aucFilePath)); ++ kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_", strlen("/etc/firmware/" CFG_FW_FILENAME "_")); ++ glGetChipInfo(prGlueInfo, &aucFilePath[strlen("/etc/firmware/" CFG_FW_FILENAME "_")]); ++ ++ DBGLOG(INIT, INFO, "open file: %s\n", aucFilePath); ++ ++ filp = filp_open(aucFilePath, O_RDONLY, 0); ++#else ++ filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); ++#endif ++ if (IS_ERR(filp)) { ++ DBGLOG(INIT, ERROR, "Open FW image: %s failed\n", CFG_FW_FILENAME); ++ goto error_open; ++ } ++#if 0 ++open_success: ++#endif ++ DBGLOG(INIT, TRACE, "Open FW image: %s done\n", CFG_FW_FILENAME); ++ return WLAN_STATUS_SUCCESS; ++ ++error_open: ++ /* restore */ ++ set_fs(orgfs); ++ cred->fsuid.val = orgfsuid; ++ cred->fsgid.val = orgfsgid; ++ put_cred(cred); ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* release firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ if ((filp != NULL) && !IS_ERR(filp)) { ++ /* close firmware file */ ++ filp_close(filp, NULL); ++ ++ /* restore */ ++ set_fs(orgfs); ++ { ++ struct cred *cred = (struct cred *)get_current_cred(); ++ ++ cred->fsuid.val = orgfsuid; ++ cred->fsgid.val = orgfsgid; ++ put_cred(cred); ++ } ++ filp = NULL; ++ } ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* load firmware image in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, OUT PVOID prBuf, IN UINT_32 u4Offset, OUT PUINT_32 pu4Size) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Size); ++ ASSERT(prBuf); ++ ++ /* l = filp->f_path.dentry->d_inode->i_size; */ ++#if 0 ++ /* the object must have a read method */ ++ if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) || (filp->f_op->read == NULL)) { ++ goto error_read; ++ } else { ++ filp->f_pos = u4Offset; ++ *pu4Size = filp->f_op->read(filp, prBuf, *pu4Size, &filp->f_pos); ++ } ++#else ++ /* the object must have a read method */ ++ if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) ) { ++ goto error_read; ++ } else { ++ filp->f_pos = u4Offset; ++ *pu4Size = vfs_read(filp, prBuf, *pu4Size, &filp->f_pos); ++ } ++#endif ++ ++ return WLAN_STATUS_SUCCESS; ++ ++error_read: ++ return WLAN_STATUS_FAILURE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to ++* query firmware image size in kernel space ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_32 pu4Size) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Size); ++ ++ //*pu4Size = filp->f_path.dentry->d_inode->i_size; ++ *pu4Size = filp->f_op->llseek(filp, 0, 2); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to load firmware image ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image ++* \param pu4FileLength File length and memory mapped length as well ++ ++* \retval Map File Handle, used for unammping ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) ++{ ++ UINT_32 u4FwSize = 0; ++ PVOID prFwBuffer = NULL; ++ ++ DEBUGFUNC("kalFirmwareImageMapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ppvMapFileBuf); ++ ASSERT(pu4FileLength); ++ ++ do { ++ /* <1> Open firmware */ ++ if (kalFirmwareOpen(prGlueInfo) != WLAN_STATUS_SUCCESS) { ++ DBGLOG(INIT, TRACE, "kalFirmwareOpen fail!\n"); ++ break; ++ } ++ ++ /* <2> Query firmare size */ ++ kalFirmwareSize(prGlueInfo, &u4FwSize); ++ printk(KERN_ERR "%s firmware size %d\n", __FUNCTION__, u4FwSize); ++ /* <3> Use vmalloc for allocating large memory trunk */ ++ prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); ++ /* <4> Load image binary into buffer */ ++ if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, &u4FwSize) != WLAN_STATUS_SUCCESS) { ++ vfree(prFwBuffer); ++ kalFirmwareClose(prGlueInfo); ++ DBGLOG(INIT, TRACE, "kalFirmwareLoad fail!\n"); ++ break; ++ } ++ /* <5> write back info */ ++ *pu4FileLength = u4FwSize; ++ *ppvMapFileBuf = prFwBuffer; ++ ++ return prFwBuffer; ++ ++ } while (FALSE); ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to unload firmware image mapped memory ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param pvFwHandle Pointer to mapping handle ++* \param pvMapFileBuf Pointer to memory-mapped firmware image ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) ++{ ++ DEBUGFUNC("kalFirmwareImageUnmapping"); ++ ++ ASSERT(prGlueInfo); ++ ++ /* pvMapFileBuf might be NULL when file doesn't exist */ ++ if (pvMapFileBuf) ++ vfree(pvMapFileBuf); ++ ++ kalFirmwareClose(prGlueInfo); ++} ++ ++#endif ++ ++#if 0 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to load firmware image ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image ++* \param pu4FileLength File length and memory mapped length as well ++ ++* \retval Map File Handle, used for unammping ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) ++{ ++ INT_32 i4Ret = 0; ++ ++ DEBUGFUNC("kalFirmwareImageMapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ppvMapFileBuf); ++ ASSERT(pu4FileLength); ++ ++ do { ++ GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; ++ ++ prGlueInfo->prFw = NULL; ++ ++ /* <1> Open firmware */ ++ i4Ret = request_firmware(&prGlueInfo->prFw, CFG_FW_FILENAME, prHifInfo->Dev); ++ ++ if (i4Ret) { ++ DBGLOG(INIT, TRACE, "fw %s:request failed %d\n", CFG_FW_FILENAME, i4Ret); ++ break; ++ } ++ *pu4FileLength = prGlueInfo->prFw->size; ++ *ppvMapFileBuf = prGlueInfo->prFw->data; ++ return prGlueInfo->prFw->data; ++ ++ } while (FALSE); ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to unload firmware image mapped memory ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* \param pvFwHandle Pointer to mapping handle ++* \param pvMapFileBuf Pointer to memory-mapped firmware image ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) ++{ ++ DEBUGFUNC("kalFirmwareImageUnmapping"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pvMapFileBuf); ++ ++ release_firmware(prGlueInfo->prFw); ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to acquire ++* OS SPIN_LOCK. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags) ++{ ++ unsigned long u4Flags = 0; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4Flags); ++ ++ if (rLockCategory < SPIN_LOCK_NUM) { ++ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++ spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++ *pu4Flags = u4Flags; ++/* DBGLOG(INIT, TRACE, ("A+%d\n", rLockCategory)); */ ++ } ++ ++} /* end of kalAcquireSpinLock() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to release ++* OS SPIN_LOCK. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[in] u4Flags Saved IRQ flags ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (rLockCategory < SPIN_LOCK_NUM) { ++ /* DBGLOG(INIT, TRACE, ("A-%d %d %d\n", rLockCategory, u4MemAllocCnt, u4MemFreeCnt)); */ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++ spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++ } ++ ++} /* end of kalReleaseSpinLock() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is provided by GLUE Layer for internal driver stack to update ++* current MAC address. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pucMacAddr Pointer of current MAC address ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr) ++{ ++ ASSERT(prGlueInfo); ++ ASSERT(pucMacAddr); ++ ++ if (UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) ++ memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, PARAM_MAC_ADDR_LEN); ++ ++} ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To query the packet information for offload related parameters. ++* ++* \param[in] pvPacket Pointer to the packet descriptor. ++* \param[in] pucFlag Points to the offload related parameter. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag) ++{ ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ UINT_8 ucFlag = 0; ++ ++ ASSERT(pvPacket); ++ ASSERT(pucFlag); ++ ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++#if DBG ++ /* Kevin: do double check, we can remove this part in Normal Driver. ++ * Because we register NIC feature with NETIF_F_IP_CSUM for MT5912B MAC, so ++ * we'll process IP packet only. ++ */ ++ if (skb->protocol != htons(ETH_P_IP)) { ++ /* printk("Wrong skb->protocol( = %08x) for TX Checksum Offload.\n", skb->protocol); */ ++ } else ++#endif ++ ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); ++ } ++ ++ *pucFlag = ucFlag; ++ ++} /* kalQueryChksumOffloadParam */ ++ ++/* 4 2007/10/8, mikewu, this is rewritten by Mike */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To update the checksum offload status to the packet to be indicated to OS. ++* ++* \param[in] pvPacket Pointer to the packet descriptor. ++* \param[in] pucFlag Points to the offload related parameter. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T aeCSUM[]) ++{ ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ ++ ASSERT(pvPacket); ++ ++ if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS) && ++ ((aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) || (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS))) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++#if DBG ++ if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) ++ DBGLOG(RX, TRACE, "RX: \"non-IPv4/IPv6\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad IP Checksum\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad TCP Checksum\" Packet\n"); ++ else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) ++ DBGLOG(RX, TRACE, "RX: \"bad UDP Checksum\" Packet\n"); ++ else ++ /* Do nothing */ ++#endif ++ } ++ ++} /* kalUpdateRxCSUMOffloadParam */ ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called to free packet allocated from kalPacketAlloc. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of the packet descriptor ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) ++{ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ if (prGlueInfo) ++ prGlueInfo->u8SkbFreed++; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Only handles driver own creating packet (coalescing buffer). ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* \param u4Size Pointer of Packet Handle ++* \param ppucData Status Code for OS upper layer ++* ++* \return NULL: Failed to allocate skb, Not NULL get skb ++*/ ++/*----------------------------------------------------------------------------*/ ++PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData) ++{ ++ struct sk_buff *prSkb = dev_alloc_skb(u4Size); ++ ++ if (prSkb) ++ *ppucData = (PUINT_8) (prSkb->data); ++#if DBG ++ { ++ PUINT_32 pu4Head = (PUINT_32) &prSkb->cb[0]; ++ *pu4Head = (UINT_32) prSkb->head; ++ DBGLOG(RX, TRACE, "prSkb->head = %#x, prSkb->cb = %#x\n", (UINT_32) prSkb->head, *pu4Head); ++ } ++#endif ++ return (PVOID) prSkb; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Process the received packet for indicating to OS. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure. ++* \param[in] pvPacket Pointer of the packet descriptor ++* \param[in] pucPacketStart The starting address of the buffer of Rx packet. ++* \param[in] u4PacketLen The packet length. ++* \param[in] pfgIsRetain Is the packet to be retained. ++* \param[in] aerCSUM The result of TCP/ IP checksum offload. ++* ++* \retval WLAN_STATUS_SUCCESS. ++* \retval WLAN_STATUS_FAILURE. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS ++kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, ++ /* IN PBOOLEAN pfgIsRetain, */ ++ IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aerCSUM[]) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ struct sk_buff *skb = (struct sk_buff *)pvPacket; ++ ++ skb->data = pucPacketStart; ++ skb_reset_tail_pointer(skb); /* reset tail pointer first, for 64bit kernel,we should call linux kernel API */ ++ skb_trim(skb, 0); /* only if skb->len > len, then skb_trim has effect */ ++ skb_put(skb, u4PacketLen); /* shift tail and skb->len to correct value */ ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ kalUpdateRxCSUMOffloadParam(skb, aerCSUM); ++#endif ++ ++ return rStatus; ++} ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Do HIF loopback test. ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++unsigned int testmode = 0; ++unsigned int testlen = 64; ++ ++void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo) ++{ ++#define HIF_LOOPBK_AUTO_TEST_LEN 1600 ++/* GL_HIF_INFO_T *HifInfo; */ ++ static unsigned int txcnt; ++ struct sk_buff *MsduInfo; ++ UINT_8 *Pkt; ++ UINT_32 RegVal; ++ UINT_32 PktLen = 16; ++ ++ /* Init */ ++ if (testmode != 0) { ++ PktLen = kalRandomNumber() % 1520; ++ if (PktLen < 64) ++ PktLen = 64; ++ } else { ++ PktLen = testlen++; ++ if (PktLen > 1520) { ++ testmode = 1; ++ PktLen = 64; ++ } ++ } ++ ++/* PktLen = 100; */ ++ DBGLOG(INIT, INFO, "kalDevLoopbkAuto> Send a packet to HIF (len = %d) (total = %d)...\n", PktLen, ++txcnt); ++/* HifInfo = &GlueInfo->rHifInfo; */ ++ ++ /* Allocate a MSDU_INFO_T */ ++ MsduInfo = kalPacketAlloc(GlueInfo, HIF_LOOPBK_AUTO_TEST_LEN, &Pkt); ++ if (MsduInfo == NULL) { ++ DBGLOG(INIT, WARN, "No PKT_INFO_T for sending loopback packet!\n"); ++ return; ++ } ++ ++ /* Init the packet */ ++ MsduInfo->dev = GlueInfo->prDevHandler; ++ if (MsduInfo->dev == NULL) { ++ DBGLOG(INIT, WARN, "MsduInfo->dev == NULL!!\n"); ++ kalPacketFree(GlueInfo, MsduInfo); ++ return; ++ } ++ ++ MsduInfo->len = PktLen; ++ kalMemSet(MsduInfo->data, 0xff, 6); ++ kalMemSet(MsduInfo->data + 6, 0x5a, PktLen - 6); ++ ++ /* Simulate OS to send the packet */ ++ wlanHardStartXmit(MsduInfo, MsduInfo->dev); ++ ++#if 0 ++ PktLen += 4; ++ if (PktLen >= 1600) ++ PktLen = 16; ++#endif ++ ++ /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ ++/* HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(1000); */ ++/* add_timer(&(HifInfo->HifTmrLoopbkFn)); */ ++} ++ ++int kalDevLoopbkThread(IN void *data) ++{ ++ struct net_device *dev = data; ++ P_GLUE_INFO_T GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); ++ GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; ++ int ret; ++ static int test; ++ ++ while (TRUE) { ++ ret = wait_event_interruptible(HifInfo->HifWaitq, (HifInfo->HifLoopbkFlg != 0)); ++ ++ if (HifInfo->HifLoopbkFlg == 0xFFFFFFFF) ++ break; ++ ++ while (TRUE) { ++ /* if ((HifInfo->HifLoopbkFlg & 0x01) == 0) */ ++ if (GlueInfo->i4TxPendingFrameNum < 64) { ++ DBGLOG(INIT, INFO, "GlueInfo->i4TxPendingFrameNum = %d\n", ++ GlueInfo->i4TxPendingFrameNum); ++ kalDevLoopbkAuto(GlueInfo); ++ ++ if (testmode == 0) ++ kalMsleep(3000); ++ } else ++ kalMsleep(1); ++ } ++ } ++} ++ ++void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) ++{ ++ static unsigned int rxcnt; ++ UINT_32 i; ++ UINT_8 *Buf = prSwRfb->pucRecvBuff + sizeof(HIF_TX_HEADER_T); ++ P_HIF_RX_HEADER_T prHifRxHdr = prSwRfb->prHifRxHdr; ++ UINT_32 len = prHifRxHdr->u2PacketLen - sizeof(HIF_TX_HEADER_T); ++ ++ if (len > 1600) { ++ while (1) ++ DBGLOG(INIT, ERROR, "HIF> Loopback len > 1600!!! error!!!\n"); ++ } ++ ++ for (i = 0; i < 6; i++) { ++ if (Buf[i] != 0xff) { ++ while (1) { ++ DBGLOG(INIT, ERROR, "HIF> Loopbk dst addr error (len = %d)!\n", len); ++ dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); ++ } ++ } ++ } ++ ++ for (i = 6; i < len; i++) { ++ if (Buf[i] != 0x5a) { ++ while (1) { ++ DBGLOG(INIT, ERROR, "HIF> Loopbk error (len = %d)!\n", len); ++ dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); ++ } ++ } ++ } ++ ++ DBGLOG(INIT, INFO, "HIF> Loopbk OK (len = %d) (total = %d)!\n", len, ++rxcnt); ++} ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate an array of received packets is available for higher ++* level protocol uses. ++* ++* \param[in] prGlueInfo Pointer to the Adapter structure. ++* \param[in] apvPkts The packet array to be indicated ++* \param[in] ucPktNum The number of packets to be indicated ++* ++* \retval TRUE Success. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum) ++{ ++ UINT_8 ucIdx = 0; ++ struct net_device *prNetDev = prGlueInfo->prDevHandler; ++ struct sk_buff *prSkb = NULL; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(apvPkts); ++ ++#if CFG_BOW_TEST ++ UINT_32 i; ++#endif ++ ++ for (ucIdx = 0; ucIdx < ucPktNum; ucIdx++) { ++ prSkb = apvPkts[ucIdx]; ++#if DBG ++ do { ++ PUINT_8 pu4Head = (PUINT_8) &prSkb->cb[0]; ++ UINT_32 u4HeadValue = 0; ++ ++ kalMemCopy(&u4HeadValue, pu4Head, sizeof(u4HeadValue)); ++ DBGLOG(RX, TRACE, "prSkb->head = %p, prSkb->cb = 0x%x\n", pu4Head, u4HeadValue); ++ } while (0); ++#endif ++ ++ if (GLUE_GET_PKT_IS_P2P(prSkb)) { ++ /* P2P */ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ prNetDev = kalP2PGetDevHdlr(prGlueInfo); ++ /* prNetDev->stats.rx_bytes += prSkb->len; */ ++ /* prNetDev->stats.rx_packets++; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_packets++; ++ ++#else ++ prNetDev = prGlueInfo->prDevHandler; ++#endif ++ } else if (GLUE_GET_PKT_IS_PAL(prSkb)) { ++ /* BOW */ ++#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_SEPARATE_DATA_PATH ++ if (prGlueInfo->rBowInfo.fgIsNetRegistered) ++ prNetDev = prGlueInfo->rBowInfo.prDevHandler; ++#else ++ prNetDev = prGlueInfo->prDevHandler; ++#endif ++ } else { ++ /* AIS */ ++ prNetDev = prGlueInfo->prDevHandler; ++ prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; ++ prGlueInfo->rNetDevStats.rx_packets++; ++ ++ } ++ ++ /* check if the "unicast" packet is from us */ ++ if (kalMemCmp(prSkb->data, prSkb->data + 6, 6) == 0) { ++ /* we will filter broadcast/multicast packet sent from us in hardware */ ++ /* source address = destination address ? */ ++ DBGLOG(RX, EVENT, ++ "kalRxIndicatePkts got from us!!! Drop it! ([ %pM ] len %d)\n", ++ prSkb->data, prSkb->len); ++ wlanReturnPacket(prGlueInfo->prAdapter, prSkb); ++ continue; ++ } ++#if (CFG_SUPPORT_TDLS == 1) ++ if (TdlsexRxFrameDrop(prGlueInfo, prSkb->data) == TRUE) { ++ /* drop the received TDLS action frame */ ++ DBGLOG(TDLS, WARN, ++ " %s: drop a received packet from %pM %u\n", ++ __func__, prSkb->data, ++ (UINT32) ((P_ADAPTER_T) (prGlueInfo->prAdapter))->rRxCtrl.rFreeSwRfbList.u4NumElem); ++ wlanReturnPacket(prGlueInfo->prAdapter, prSkb); ++ continue; ++ } ++ ++ /* ++ get a TDLS request/response/confirm, we need to parse the HT IE ++ because older supplicant does not pass HT IE to us ++ */ ++ TdlsexRxFrameHandle(prGlueInfo, prSkb->data, prSkb->len); ++#endif /* CFG_SUPPORT_TDLS */ ++ ++ STATS_RX_PKT_INFO_DISPLAY(prSkb->data); ++ ++ //prNetDev->last_rx = jiffies; ++ prSkb->protocol = eth_type_trans(prSkb, prNetDev); ++ prSkb->dev = prNetDev; ++ /* DBGLOG_MEM32(RX, TRACE, (PUINT_32)prSkb->data, prSkb->len); */ ++ DBGLOG(RX, TRACE, "kalRxIndicatePkts len = %d\n", prSkb->len); ++ ++#if CFG_BOW_TEST ++ DBGLOG(BOW, TRACE, "Rx sk_buff->len: %d\n", prSkb->len); ++ DBGLOG(BOW, TRACE, "Rx sk_buff->data_len: %d\n", prSkb->data_len); ++ DBGLOG(BOW, TRACE, "Rx sk_buff->data:\n"); ++ ++ for (i = 0; i < prSkb->len; i++) { ++ DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); ++ ++ if ((i + 1) % 16 == 0) ++ DBGLOG(BOW, TRACE, "\n"); ++ } ++ ++ DBGLOG(BOW, TRACE, "\n"); ++#endif ++ ++ if (!in_interrupt()) ++ netif_rx_ni(prSkb); /* only in non-interrupt context */ ++ else ++ netif_rx(prSkb); ++ ++ wlanReturnPacket(prGlueInfo->prAdapter, NULL); ++ } ++ ++ kalPerMonStart(prGlueInfo); ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Called by driver to indicate event to upper layer, for example, the wpa ++* supplicant or wireless tools. ++* ++* \param[in] pvAdapter Pointer to the adapter descriptor. ++* \param[in] eStatus Indicated status. ++* \param[in] pvBuf Indicated message buffer. ++* \param[in] u4BufLen Indicated message buffer size. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 ScanCnt = 0, ScanDoneFailCnt = 0; ++VOID ++kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen) ++{ ++ UINT_32 bufLen; ++ P_PARAM_STATUS_INDICATION_T pStatus = (P_PARAM_STATUS_INDICATION_T) pvBuf; ++ P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T) pStatus; ++ P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = (P_PARAM_PMKID_CANDIDATE_LIST_T) (pStatus + 1); ++ PARAM_MAC_ADDRESS arBssid; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ PARAM_SSID_T ssid; ++ struct ieee80211_channel *prChannel = NULL; ++ struct cfg80211_bss *bss; ++ UINT_8 ucChannelNum; ++ P_BSS_DESC_T prBssDesc = NULL; ++ struct cfg80211_scan_info info = { ++ .aborted = false, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ kalMemZero(arBssid, MAC_ADDR_LEN); ++ ++ ASSERT(prGlueInfo); ++ ++ switch (eStatus) { ++ case WLAN_STATUS_ROAM_OUT_FIND_BEST: ++ case WLAN_STATUS_MEDIA_CONNECT: ++ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; ++ ++ /* indicate assoc event */ ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &bufLen); ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); ++ ++ /* switch netif on */ ++ netif_carrier_on(prGlueInfo->prDevHandler); ++ ++ do { ++ /* print message on console */ ++ wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQuerySsid, &ssid, sizeof(ssid), &bufLen); ++ ++ ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? ++ (PARAM_MAX_LEN_SSID - 1) : ssid.u4SsidLen] = '\0'; ++ DBGLOG(AIS, INFO, " %s netif_carrier_on [ssid:%s %pM ]\n", ++ prGlueInfo->prDevHandler->name, ssid.aucSsid, arBssid); ++ } while (0); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ struct cfg80211_bss *bss_others = NULL; ++ UINT_8 ucLoopCnt = 15; /* only loop 15 times to avoid dead loop */ ++ ++ /* retrieve channel */ ++ ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, ++ NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, ++ NL80211_BAND_5GHZ)); ++ } ++ ++ /* ensure BSS exists */ ++ bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), prChannel, arBssid, ++ ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ ++ if (bss == NULL) { ++ /* create BSS on-the-fly */ ++ prBssDesc = ++ wlanGetTargetBssDescByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prBssDesc != NULL) { ++ bss = cfg80211_inform_bss(priv_to_wiphy(prGlueInfo), prChannel, ++ CFG80211_BSS_FTYPE_PRESP, ++ arBssid, 0, /* TSF */ ++ WLAN_CAPABILITY_ESS, ++ prBssDesc->u2BeaconInterval, /* beacon interval */ ++ prBssDesc->aucIEBuf, /* IE */ ++ prBssDesc->u2IELength, /* IE Length */ ++ RCPI_TO_dBm(prBssDesc->ucRCPI) * 100, /* MBM */ ++ GFP_KERNEL); ++ } ++ } ++ /* remove all bsses that before and only channel different with the current connected one ++ if without this patch, UI will show channel A is connected even if AP has change channel ++ from A to B */ ++ while (ucLoopCnt--) { ++ bss_others = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), NULL, arBssid, ++ ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ if (bss && bss_others && bss_others != bss) { ++ DBGLOG(SCN, INFO, "remove BSSes that only channel different\n"); ++ cfg80211_unlink_bss(priv_to_wiphy(prGlueInfo), bss_others); ++ } else ++ break; ++ } ++ ++ /* CFG80211 Indication */ ++ if (eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { ++ /*cfg80211_roamed_bss(prGlueInfo->prDevHandler, ++ bss, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, prGlueInfo->u4RspIeLength, GFP_KERNEL); ++ */ ++ struct cfg80211_roam_info roam_info = { ++ .bss = bss, ++ .req_ie = prGlueInfo->aucReqIe, ++ .req_ie_len = prGlueInfo->u4ReqIeLength, ++ .resp_ie = prGlueInfo->aucRspIe, ++ .resp_ie_len = prGlueInfo->u4RspIeLength ++ }; ++ cfg80211_roamed(prGlueInfo->prDevHandler, ++ &roam_info, ++ GFP_KERNEL); ++ } else { ++ /* to support user space roaming, cfg80211 will change the sme_state to connecting ++ before reassociate */ ++ cfg80211_connect_result(prGlueInfo->prDevHandler, ++ arBssid, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, ++ prGlueInfo->u4RspIeLength, WLAN_STATUS_SUCCESS, GFP_KERNEL); ++ } ++ } ++ ++ break; ++ ++ case WLAN_STATUS_MEDIA_DISCONNECT: ++ case WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY: ++ /* indicate disassoc event */ ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); ++ /* For CR 90 and CR99, While supplicant do reassociate, driver will do netif_carrier_off first, ++ after associated success, at joinComplete(), do netif_carier_on, ++ but for unknown reason, the supplicant 1x pkt will not called the driver ++ hardStartXmit, for template workaround these bugs, add this compiling flag ++ */ ++ /* switch netif off */ ++ ++ DBGLOG(AIS, INFO, "[wifi] %s netif_carrier_off\n", ++ prGlueInfo->prDevHandler->name); ++ ++ netif_carrier_off(prGlueInfo->prDevHandler); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ P_WIFI_VAR_T prWifiVar = &prGlueInfo->prAdapter->rWifiVar; ++ UINT_16 u2DeauthReason = prWifiVar->arBssInfo[NETWORK_TYPE_AIS_INDEX].u2DeauthReason; ++ /* CFG80211 Indication */ ++ DBGLOG(AIS, INFO, "[wifi] %s cfg80211_disconnected\n", prGlueInfo->prDevHandler->name); ++ cfg80211_disconnected(prGlueInfo->prDevHandler, u2DeauthReason, NULL, 0, false, GFP_KERNEL); ++ } ++ ++ prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ break; ++ ++ case WLAN_STATUS_SCAN_COMPLETE: ++ /* indicate scan complete event */ ++ wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); ++ ++ /* 1. reset first for newly incoming request */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueInfo->prScanRequest; ++ prGlueInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ /* 2. then CFG80211 Indication */ ++ DBGLOG(SCN, TRACE, "[ais] scan complete %p %d %d\n", prScanRequest, ScanCnt, ScanDoneFailCnt); ++ ++ if (prScanRequest != NULL) ++ cfg80211_scan_done(prScanRequest, &info); ++ break; ++ case WLAN_STATUS_CONNECT_INDICATION: ++ /* indicate AIS Jion fail event ++ if (prGlueInfo->prDevHandler->ieee80211_ptr->sme_state == CFG80211_SME_CONNECTING) */ ++ cfg80211_connect_result(prGlueInfo->prDevHandler, ++ prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc->aucBSSID, ++ prGlueInfo->aucReqIe, ++ prGlueInfo->u4ReqIeLength, ++ prGlueInfo->aucRspIe, ++ prGlueInfo->u4RspIeLength, WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); ++ break; ++ ++#if 0 ++ case WLAN_STATUS_MSDU_OK: ++ if (netif_running(prGlueInfo->prDevHandler)) ++ netif_wake_queue(prGlueInfo->prDevHandler); ++ break; ++#endif ++ ++ case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: ++ if (pStatus) { ++ switch (pStatus->eStatusType) { ++ case ENUM_STATUS_TYPE_AUTHENTICATION: ++ /* ++ printk(KERN_NOTICE "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [ %pM ] F:%lx\n", ++ pAuth->Request[0].Length, ++ pAuth->Request[0].Bssid, ++ pAuth->Request[0].Flags); ++ */ ++ /* indicate (UC/GC) MIC ERROR event only */ ++ if ((pAuth->arRequest[0].u4Flags == ++ PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || ++ (pAuth->arRequest[0].u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR)) { ++ cfg80211_michael_mic_failure(prGlueInfo->prDevHandler, NULL, ++ (pAuth->arRequest[0].u4Flags == ++ PARAM_AUTH_REQUEST_PAIRWISE_ERROR) ? ++ NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP, ++ 0, NULL, GFP_KERNEL); ++ wext_indicate_wext_event(prGlueInfo, IWEVMICHAELMICFAILURE, ++ (unsigned char *)&pAuth->arRequest[0], ++ pAuth->arRequest[0].u4Length); ++ } ++ break; ++ ++ case ENUM_STATUS_TYPE_CANDIDATE_LIST: ++ /* ++ printk(KERN_NOTICE "Param_StatusType_PMKID_CandidateList: Ver(%ld) Num(%ld)\n", ++ pPmkid->u2Version, ++ pPmkid->u4NumCandidates); ++ if (pPmkid->u4NumCandidates > 0) { ++ printk(KERN_NOTICE "candidate[ %pM ] preAuth Flag:%lx\n", ++ pPmkid->arCandidateList[0].rBSSID, ++ pPmkid->arCandidateList[0].fgFlags); ++ } ++ */ ++ { ++ UINT_32 i = 0; ++ /*struct net_device *prDev = prGlueInfo->prDevHandler; */ ++ P_PARAM_PMKID_CANDIDATE_T prCand = NULL; ++ /* indicate pmk candidate via cfg80211 to supplicant, ++ the second parameter is 1000 for ++ cfg80211_pmksa_candidate_notify, because wpa_supplicant defined it. */ ++ for (i = 0; i < pPmkid->u4NumCandidates; i++) { ++ prCand = &pPmkid->arCandidateList[i]; ++ cfg80211_pmksa_candidate_notify(prGlueInfo->prDevHandler, 1000, ++ prCand->arBSSID, prCand->u4Flags, ++ GFP_KERNEL); ++ ++ wext_indicate_wext_event(prGlueInfo, ++ IWEVPMKIDCAND, ++ (unsigned char *)prCand, ++ pPmkid->u4NumCandidates); ++ } ++ } ++ break; ++ ++ default: ++ /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ ++ /* ++ printk(KERN_NOTICE "unknown media specific indication type:%x\n", ++ pStatus->StatusType); ++ */ ++ break; ++ } ++ } else { ++ /* ++ printk(KERN_WARNING "media specific indication buffer NULL\n"); ++ */ ++ } ++ break; ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ case WLAN_STATUS_BWCS_UPDATE: ++ { ++ wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, sizeof(PTA_IPC_T)); ++ } ++ ++ break; ++ ++#endif ++ ++ default: ++ /* ++ printk(KERN_WARNING "unknown indication:%lx\n", eStatus); ++ */ ++ break; ++ } ++} /* kalIndicateStatusAndComplete */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to update the (re)association request ++* information to the structure used to query and set ++* OID_802_11_ASSOCIATION_INFORMATION. ++* ++* \param[in] prGlueInfo Pointer to the Glue structure. ++* \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association ++* Request frame from the AP. ++* \param[in] u4FrameBodyLen The length of the frame body of the last ++* (Re)Association Request frame. ++* \param[in] fgReassocRequest TRUE, if it is a Reassociation Request frame. ++* ++* \return (none) ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) ++{ ++ PUINT_8 cp; ++ ++ ASSERT(prGlueInfo); ++ ++ /* reset */ ++ prGlueInfo->u4ReqIeLength = 0; ++ ++ if (fgReassocRequest) { ++ if (u4FrameBodyLen < 15) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } else { ++ if (u4FrameBodyLen < 9) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } ++ ++ cp = pucFrameBody; ++ ++ if (fgReassocRequest) { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ /* Current AP address 6 */ ++ cp += 10; ++ u4FrameBodyLen -= 10; ++ } else { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ cp += 4; ++ u4FrameBodyLen -= 4; ++ } ++ ++ wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, u4FrameBodyLen); ++ ++ if (u4FrameBodyLen <= CFG_CFG80211_IE_BUF_LEN) { ++ prGlueInfo->u4ReqIeLength = u4FrameBodyLen; ++ kalMemCopy(prGlueInfo->aucReqIe, cp, u4FrameBodyLen); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This routine is called to update the (re)association ++* response information to the structure used to reply with ++* cfg80211_connect_result ++* ++* @param prGlueInfo Pointer to adapter descriptor ++* @param pucFrameBody Pointer to the frame body of the last (Re)Association ++* Response frame from the AP ++* @param u4FrameBodyLen The length of the frame body of the last ++* (Re)Association Response frame ++* ++* @return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen) ++{ ++ UINT_32 u4IEOffset = 6; /* cap_info, status_code & assoc_id */ ++ UINT_32 u4IELength = u4FrameBodyLen - u4IEOffset; ++ ++ ASSERT(prGlueInfo); ++ ++ /* reset */ ++ prGlueInfo->u4RspIeLength = 0; ++ ++ if (u4IELength <= CFG_CFG80211_IE_BUF_LEN) { ++ prGlueInfo->u4RspIeLength = u4IELength; ++ kalMemCopy(prGlueInfo->aucRspIe, pucFrameBody + u4IEOffset, u4IELength); ++ } ++ ++} /* kalUpdateReAssocRspInfo */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Notify OS with SendComplete event of the specific packet. Linux should ++* free packets here. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] status Status Code for OS upper layer ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) ++{ ++ ++ struct net_device *prDev = NULL; ++ struct sk_buff *prSkb = NULL; ++ UINT_16 u2QueueIdx = 0; ++ UINT_8 ucNetworkType = 0; ++ BOOLEAN fgIsValidDevice = TRUE; ++ ++ ASSERT(pvPacket); ++ ASSERT(prGlueInfo->i4TxPendingFrameNum); ++ ++ prSkb = (struct sk_buff *)pvPacket; ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++ if (GLUE_GET_PKT_IS_PAL(prSkb)) { ++ ucNetworkType = NETWORK_TYPE_BOW_INDEX; ++ } else if (GLUE_GET_PKT_IS_P2P(prSkb)) { ++ ucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /* in case packet was sent after P2P device is unregistered */ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) ++ fgIsValidDevice = FALSE; ++#endif ++ } else { ++ ucNetworkType = NETWORK_TYPE_AIS_INDEX; ++ } ++ ++ GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ if (u2QueueIdx < CFG_MAX_TXQ_NUM) ++ GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); ++ prDev = prSkb->dev; ++ ++ ASSERT(prDev); ++ ++ if ((fgIsValidDevice == TRUE) && (u2QueueIdx < CFG_MAX_TXQ_NUM)) { ++ if (netif_subqueue_stopped(prDev, prSkb) && ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx] <= ++ CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_wake_subqueue for bss: %d. Queue len: %d\n", ++ ucNetworkType, ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); ++ netif_wake_subqueue(prDev, u2QueueIdx); ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ prGlueInfo->rHifInfo.HifLoopbkFlg &= ~0x01; ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ } ++ } ++ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ prGlueInfo->u8SkbFreed++; ++ ++ DBGLOG(TX, EVENT, "----- pending frame %d -----\n", prGlueInfo->i4TxPendingFrameNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Copy Mac Address setting from registry. It's All Zeros in Linux. ++* ++* \param[in] prAdapter Pointer to the Adapter structure ++* ++* \param[out] paucMacAddr Pointer to the Mac Address buffer ++* ++* \retval WLAN_STATUS_SUCCESS ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_8 paucMacAddr) ++{ ++ UINT_8 aucZeroMac[MAC_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 } ++ ++ DEBUGFUNC("kalQueryRegistryMacAddr"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(paucMacAddr); ++ ++ kalMemCopy((PVOID) paucMacAddr, (PVOID) aucZeroMac, MAC_ADDR_LEN); ++ ++} /* end of kalQueryRegistryMacAddr() */ ++ ++#if CFG_SUPPORT_EXT_CONFIG ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read external configuration, ex. NVRAM or file ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ /* External data is given from user space by ioctl or /proc, not read by ++ driver. ++ */ ++ if (0 != prGlueInfo->u4ExtCfgLength) ++ DBGLOG(INIT, TRACE, "Read external configuration data -- OK\n"); ++ else ++ DBGLOG(INIT, TRACE, "Read external configuration data -- fail\n"); ++ ++ return prGlueInfo->u4ExtCfgLength; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This inline function is to extract some packet information, including ++* user priority, packet length, destination address, 802.1x and BT over Wi-Fi ++* or not. ++* ++* @param prGlueInfo Pointer to the glue structure ++* @param prNdisPacket Packet descriptor ++* @param pucPriorityParam User priority ++* @param pu4PacketLen Packet length ++* @param pucEthDestAddr Destination address ++* @param pfgIs1X 802.1x packet or not ++* @param pfgIsPAL BT over Wi-Fi packet or not ++* @prGenUse General used param ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++BOOLEAN ++kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_NATIVE_PACKET prPacket, ++ OUT PUINT_8 pucPriorityParam, ++ OUT PUINT_32 pu4PacketLen, ++ OUT PUINT_8 pucEthDestAddr, ++ OUT PBOOLEAN pfgIs1X, ++ OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, ++ OUT PVOID prGenUse) ++{ ++ ++ UINT_32 u4PacketLen; ++ ++ UINT_8 ucUserPriority = USER_PRIORITY_DEFAULT; /* Default */ ++ UINT_16 u2EtherTypeLen; ++ struct sk_buff *prSkb = (struct sk_buff *)prPacket; ++ PUINT_8 aucLookAheadBuf = NULL; ++ ++ DEBUGFUNC("kalQoSFrameClassifierAndPacketInfo"); ++ ++ u4PacketLen = prSkb->len; ++ ++ if (u4PacketLen < ETH_HLEN) { ++ DBGLOG(TX, WARN, "Invalid Ether packet length: %u\n", (UINT_32) u4PacketLen); ++ return FALSE; ++ } ++ ++ aucLookAheadBuf = prSkb->data; ++ ++ *pfgIs1X = FALSE; ++ *pfgIsPAL = FALSE; ++ ++ /* 4 <3> Obtain the User Priority for WMM */ ++ u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); ++ ++ if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { ++ PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucIpVersion; ++ ++ ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if (ucIpVersion == IPVERSION) { ++ UINT_8 ucIpTos; ++ /* Get the DSCP value from the header of IP packet. */ ++ ucIpTos = pucIpHdr[1]; ++ ucUserPriority = ((ucIpTos & IPTOS_PREC_MASK) >> IPTOS_PREC_OFFSET); ++ } ++ ++ /* TODO(Kevin): Add TSPEC classifier here */ ++ } else if (u2EtherTypeLen == ETH_P_1X || u2EtherTypeLen == ETH_P_PRE_1X) { /* For Port Control */ ++ PUINT_8 pucEapol = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucEapolType = pucEapol[1]; ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ /* ++ * generate a seq number used to trace security frame TX ++ */ ++ if (prGenUse) ++ *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 1: /* eapol start */ ++ DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 3: /* key */ ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x... seqNo %d\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ } ++ *pfgIs1X = TRUE; ++ } ++#if CFG_SUPPORT_WAPI ++ else if (u2EtherTypeLen == ETH_WPI_1X) { ++ PUINT_8 pucEthBody = &aucLookAheadBuf[ETH_HLEN]; ++ UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ ++ UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; ++ UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; ++ ++ DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", ++ ucSubType, u2Length, u2Seq); ++ *pfgIs1X = TRUE; ++ } ++#endif ++#if (CFG_SUPPORT_TDLS == 1) ++ else if (u2EtherTypeLen == TDLS_FRM_PROT_TYPE) { ++ /* TDLS case */ ++ TDLSEX_UP_ASSIGN(ucUserPriority); ++ } ++#endif /* CFG_SUPPORT_TDLS */ ++ else if (u2EtherTypeLen <= 1500) { /* 802.3 Frame */ ++ UINT_8 ucDSAP, ucSSAP, ucControl; ++ UINT_8 aucOUI[3]; ++ ++ ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; ++ ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; ++ ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; ++ ++ aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; ++ aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; ++ aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; ++ ++ if (ucDSAP == ETH_LLC_DSAP_SNAP && ++ ucSSAP == ETH_LLC_SSAP_SNAP && ++ ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && ++ aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && ++ aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) { ++ ++ UINT_16 tmp = ++ ((aucLookAheadBuf[ETH_SNAP_OFFSET + 3] << 8) | aucLookAheadBuf[ETH_SNAP_OFFSET + 4]); ++ ++ *pfgIsPAL = TRUE; ++ ucUserPriority = (UINT_8) prSkb->priority; ++ ++ if (tmp == BOW_PROTOCOL_ID_SECURITY_FRAME) { ++ PUINT_8 pucEapol = &aucLookAheadBuf[ETH_SNAP_OFFSET + 5]; ++ UINT_8 ucEapolType = pucEapol[1]; ++ UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; ++ if (prGenUse) ++ *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); ++ ++ switch (ucEapolType) { ++ case 0: /* eap packet */ ++ DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", ++ pucEapol[4], pucEapol[5], pucEapol[7], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 1: /* eapol start */ ++ DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ case 3: /* key */ ++ DBGLOG(TX, INFO, ++ " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x seqNo %d\n", ++ u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], ++ pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], ++ prGenUse ? *(UINT_8 *)prGenUse : 0); ++ break; ++ } ++ *pfgIs1X = TRUE; ++ } ++ } ++ } ++ /* 4 <4> Return the value of Priority Parameter. */ ++ *pucPriorityParam = ucUserPriority; ++ ++ /* 4 <5> Retrieve Packet Information - DA */ ++ /* Packet Length/ Destination Address */ ++ *pu4PacketLen = u4PacketLen; ++ ++ kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); ++ ++ /* <6> Network type */ ++#if CFG_ENABLE_BT_OVER_WIFI ++ if (*pfgIsPAL == TRUE) { ++ *pucNetworkType = NETWORK_TYPE_BOW_INDEX; ++ } else ++#endif ++ { ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered && GLUE_GET_PKT_IS_P2P(prPacket)) { ++ *pucNetworkType = NETWORK_TYPE_P2P_INDEX; ++ } else ++#endif ++ { ++ *pucNetworkType = NETWORK_TYPE_AIS_INDEX; ++ } ++ } ++ return TRUE; ++} /* end of kalQoSFrameClassifier() */ ++ ++VOID ++kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, ++ IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus) ++{ ++ ++ ASSERT(prGlueInfo); ++ /* remove timeout check timer */ ++ wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); ++ ++ /* if (prGlueInfo->u4TimeoutFlag != 1) { */ ++ prGlueInfo->rPendStatus = rOidStatus; ++ DBGLOG(OID, TEMP, "kalOidComplete, caller: %p\n", __builtin_return_address(0)); ++ complete(&prGlueInfo->rPendComp); ++ prGlueInfo->u4OidCompleteFlag = 1; ++ /* } */ ++ /* else let it timeout on kalIoctl entry */ ++} ++ ++VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ /* if (prGlueInfo->u4TimeoutFlag != 1) { */ ++ /* clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag); */ ++ if (prGlueInfo->u4OidCompleteFlag != 1) { ++ DBGLOG(OID, TEMP, "kalOidClearance, caller: %p\n", __builtin_return_address(0)); ++ complete(&prGlueInfo->rPendComp); ++ } ++ /* } */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is used to transfer linux ioctl to OID, and we ++* need to specify the behavior of the OID by ourself ++* ++* @param prGlueInfo Pointer to the glue structure ++* @param pvInfoBuf Data buffer ++* @param u4InfoBufLen Data buffer length ++* @param fgRead Is this a read OID ++* @param fgWaitResp does this OID need to wait for values ++* @param fgCmd does this OID compose command packet ++* @param pu4QryInfoLen The data length of the return values ++* ++* @retval TRUE Success to extract information ++* @retval FALSE Fail to extract correct information ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++/* todo: enqueue the i/o requests for multiple processes access */ ++/* */ ++/* currently, return -1 */ ++/* */ ++ ++/* static GL_IO_REQ_T OidEntry; */ ++ ++WLAN_STATUS ++kalIoctl(IN P_GLUE_INFO_T prGlueInfo, ++ IN PFN_OID_HANDLER_FUNC pfnOidHandler, ++ IN PVOID pvInfoBuf, ++ IN UINT_32 u4InfoBufLen, ++ IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen) ++{ ++ P_GL_IO_REQ_T prIoReq = NULL; ++ WLAN_STATUS ret = WLAN_STATUS_SUCCESS; ++ ++ if (fgIsResetting == TRUE) ++ return WLAN_STATUS_SUCCESS; ++ ++ /* GLUE_SPIN_LOCK_DECLARATION(); */ ++ ASSERT(prGlueInfo); ++ ++ /* <1> Check if driver is halt */ ++ /* if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { */ ++ /* return WLAN_STATUS_ADAPTER_NOT_READY; */ ++ /* } */ ++ ++ /* if wait longer than double OID timeout timer, then will show backtrace who held halt lock. ++ at this case, we will return kalIoctl failure because tx_thread may be hung */ ++ if (kalHaltLock(2 * WLAN_OID_TIMEOUT_THRESHOLD)) ++ return WLAN_STATUS_FAILURE; ++ ++ if (kalIsHalted()) { ++ kalHaltUnlock(); ++ return WLAN_STATUS_ADAPTER_NOT_READY; ++ } ++ ++ if (down_interruptible(&prGlueInfo->ioctl_sem)) { ++ kalHaltUnlock(); ++ return WLAN_STATUS_FAILURE; ++ } ++ ++ /* <2> TODO: thread-safe */ ++ ++ /* <3> point to the OidEntry of Glue layer */ ++ ++ prIoReq = &(prGlueInfo->OidEntry); ++ ++ ASSERT(prIoReq); ++ ++ /* <4> Compose the I/O request */ ++ prIoReq->prAdapter = prGlueInfo->prAdapter; ++ prIoReq->pfnOidHandler = pfnOidHandler; ++ prIoReq->pvInfoBuf = pvInfoBuf; ++ prIoReq->u4InfoBufLen = u4InfoBufLen; ++ prIoReq->pu4QryInfoLen = pu4QryInfoLen; ++ prIoReq->fgRead = fgRead; ++ prIoReq->fgWaitResp = fgWaitResp; ++ prIoReq->rStatus = WLAN_STATUS_FAILURE; ++#if CFG_ENABLE_WIFI_DIRECT ++ prIoReq->fgIsP2pOid = fgIsP2pOid; ++#endif ++ ++ /* <5> Reset the status of pending OID */ ++ prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; ++ /* prGlueInfo->u4TimeoutFlag = 0; */ ++ /* prGlueInfo->u4OidCompleteFlag = 0; */ ++ ++ /* <6> Check if we use the command queue */ ++ prIoReq->u4Flag = fgCmd; ++ ++ /* <7> schedule the OID bit */ ++ set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); ++ ++ /* <8> Wake up tx thread to handle kick start the I/O request */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ /* <9> Block and wait for event or timeout, current the timeout is 5 secs */ ++ /* if (wait_for_completion_interruptible_timeout(&prGlueInfo->rPendComp, 5 * KAL_HZ)) { */ ++ /* if (!wait_for_completion_interruptible(&prGlueInfo->rPendComp)) { */ ++ DBGLOG(OID, TEMP, "kalIoctl: before wait, caller: %p\n", __builtin_return_address(0)); ++ wait_for_completion(&prGlueInfo->rPendComp); { ++ /* Case 1: No timeout. */ ++ /* if return WLAN_STATUS_PENDING, the status of cmd is stored in prGlueInfo */ ++ if (prIoReq->rStatus == WLAN_STATUS_PENDING) ++ ret = prGlueInfo->rPendStatus; ++ else ++ ret = prIoReq->rStatus; ++ } ++#if 0 ++ else { ++ /* Case 2: timeout */ ++ /* clear pending OID's cmd in CMD queue */ ++ if (fgCmd) { ++ prGlueInfo->u4TimeoutFlag = 1; ++ wlanReleasePendingOid(prGlueInfo->prAdapter, 0); ++ } ++ ret = WLAN_STATUS_FAILURE; ++ } ++#endif ++ DBGLOG(OID, TEMP, "kalIoctl: done\n"); ++ up(&prGlueInfo->ioctl_sem); ++ kalHaltUnlock(); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending security frames ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending security frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear pending security frames ++* belongs to dedicated network type ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* \param eNetworkTypeIdx Network Type Index ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending security frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && prCmdInfo->eNetworkType == eNetworkTypeIdx) { ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending management frames ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending management frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear all pending management frames ++* belongs to dedicated network type ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Clear pending management frames in prGlueInfo->rCmdQueue */ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ ++ if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && ++ prCmdInfo->eNetworkType == eNetworkTypeIdx) { ++ wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } else { ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ } ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} /* kalClearMgmtFramesByNetType */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief This function is a kernel thread function for handling command packets ++* Tx requests and interrupt events ++* ++* @param data data pointer to private data of tx_thread ++* ++* @retval If the function succeeds, the return value is 0. ++* Otherwise, an error code is returned. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++int tx_thread(void *data) ++{ ++ struct net_device *dev = data; ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); ++ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_GL_IO_REQ_T prIoReq = NULL; ++ P_QUE_T prTxQueue = NULL; ++ P_QUE_T prCmdQue = NULL; ++ ++ int ret = 0; ++ ++ BOOLEAN fgNeedHwAccess = FALSE; ++ ++ struct sk_buff *prSkb = NULL; ++ ++ /* for spin lock acquire and release */ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ prTxQueue = &prGlueInfo->rTxQueue; ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ current->flags |= PF_NOFREEZE; ++ ++ DBGLOG(INIT, INFO, "tx_thread starts running...\n"); ++ ++ while (TRUE) { ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ /*run p2p multicast list work. */ ++ if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) ++ p2pSetMulticastListWorkQueueWrapper(prGlueInfo); ++#endif ++ ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ DBGLOG(INIT, INFO, "tx_thread should stop now...\n"); ++ break; ++ } ++ ++ /* ++ * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT ++ * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT ++ * ++ */ ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ ++ ret = wait_event_interruptible(prGlueInfo->waitq, (prGlueInfo->ulFlag != 0)); ++ ++ KAL_WAKE_LOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ ++/* #if (CONF_HIF_LOOPBACK_AUTO == 1) */ ++/* if (test_and_clear_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &prGlueInfo->u4Flag)) { */ ++/* kalDevLoopbkAuto(prGlueInfo); */ ++/* } */ ++/* #endif */ /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if CFG_DBG_GPIO_PINS ++ /* TX thread Wake up */ ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_LOW); ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++ /*run p2p multicast list work. */ ++ if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) ++ p2pSetMulticastListWorkQueueWrapper(prGlueInfo); ++ ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag)) { ++ p2pFuncUpdateMgmtFrameRegister(prGlueInfo->prAdapter, ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter); ++ } ++#endif ++ if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { ++ P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; ++ /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; ++ } ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); ++ DBGLOG(INIT, INFO, "<1>tx_thread should stop now...\n"); ++ break; ++ } ++ ++ fgNeedHwAccess = FALSE; ++ ++ /* Handle Interrupt */ ++ if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->ulFlag)) { ++ if (fgNeedHwAccess == FALSE) { ++ fgNeedHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prGlueInfo->prAdapter); ++ } ++ ++ /* the Wi-Fi interrupt is already disabled in mmc thread, ++ so we set the flag only to enable the interrupt later */ ++ prGlueInfo->prAdapter->fgIsIntEnable = FALSE; ++ /* wlanISR(prGlueInfo->prAdapter, TRUE); */ ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ /* Should stop now... skip pending interrupt */ ++ DBGLOG(INIT, INFO, "ignore pending interrupt\n"); ++ } else { ++ prGlueInfo->TaskIsrCnt++; ++ wlanIST(prGlueInfo->prAdapter); ++ } ++ } ++ ++ /* transfer ioctl to OID request */ ++#if 0 ++ if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "<2>tx_thread should stop now...\n"); ++ break; ++ } ++#endif ++ ++ do { ++ if (test_and_clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag)) { ++ /* get current prIoReq */ ++ prGlueInfo->u4OidCompleteFlag = 0; ++ ++ prIoReq = &(prGlueInfo->OidEntry); ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE && prIoReq->fgIsP2pOid == TRUE) { ++ /* if this Oid belongs to p2p and p2p module is removed ++ * do nothing, ++ */ ++ } else ++#endif ++ { ++ if (FALSE == prIoReq->fgRead) { ++ prIoReq->rStatus = wlanSetInformation(prIoReq->prAdapter, ++ prIoReq->pfnOidHandler, ++ prIoReq->pvInfoBuf, ++ prIoReq->u4InfoBufLen, ++ prIoReq->pu4QryInfoLen); ++ } else { ++ prIoReq->rStatus = wlanQueryInformation(prIoReq->prAdapter, ++ prIoReq->pfnOidHandler, ++ prIoReq->pvInfoBuf, ++ prIoReq->u4InfoBufLen, ++ prIoReq->pu4QryInfoLen); ++ } ++ ++ if (prIoReq->rStatus != WLAN_STATUS_PENDING) { ++ DBGLOG(OID, TEMP, "tx_thread, complete\n"); ++ complete(&prGlueInfo->rPendComp); ++ } else { ++ wlanoidTimeoutCheck(prGlueInfo->prAdapter, prIoReq->pfnOidHandler); ++ } ++ } ++ } ++ ++ } while (FALSE); ++ ++ /* ++ * ++ * if TX request, clear the TXREQ flag. TXREQ set by kalSetEvent/GlueSetEvent ++ * indicates the following requests occur ++ * ++ */ ++#if 0 ++ if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { ++ DBGLOG(INIT, INFO, "<3>tx_thread should stop now...\n"); ++ break; ++ } ++#endif ++ ++ if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, &prGlueInfo->ulFlag)) { ++ /* Process Mailbox Messages */ ++ wlanProcessMboxMessage(prGlueInfo->prAdapter); ++ ++ /* Process CMD request */ ++ do { ++ if (prCmdQue->u4NumElem > 0) { ++ if (fgNeedHwAccess == FALSE) { ++ fgNeedHwAccess = TRUE; ++ ++ wlanAcquirePowerControl(prGlueInfo->prAdapter); ++ } ++ wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); ++ } ++ } while (FALSE); ++ ++ /* Handle Packet Tx */ ++ { ++ while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_REMOVE_HEAD(prTxQueue, prQueueEntry, P_QUE_ENTRY_T); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ ASSERT(prQueueEntry); ++ if (NULL == prQueueEntry) ++ break; ++ ++ prSkb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); ++ ASSERT(prSkb); ++ if (NULL == prSkb) { ++ DBGLOG(INIT, ERROR, "prSkb == NULL!\n"); ++ continue; ++ } ++#if (CFG_SUPPORT_TDLS_DBG == 1) ++ UINT8 *pkt = prSkb->data; ++ UINT16 u2Identifier; ++ ++ if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { ++ /* ip */ ++ u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); ++ DBGLOG(INIT, LOUD, " %d\n", u2Identifier); ++ } ++#endif ++ if (wlanEnqueueTxPacket(prGlueInfo->prAdapter, ++ (P_NATIVE_PACKET) prSkb) == WLAN_STATUS_RESOURCES) { ++ /* no available entry in rFreeMsduInfoList */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_HEAD(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ break; ++ } ++ } ++ ++ if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) { ++ /* send packets to HIF here */ ++ wlanTxPendingPackets(prGlueInfo->prAdapter, &fgNeedHwAccess); ++ } ++ } ++ ++ } ++ ++ /* Process RX, In linux, we don't need to free sk_buff by ourself */ ++ ++ /* In linux, we don't need to free sk_buff by ourself */ ++ ++ /* In linux, we don't do reset */ ++ if (fgNeedHwAccess == TRUE) ++ wlanReleasePowerControl(prGlueInfo->prAdapter); ++ ++ /* handle cnmTimer time out */ ++ if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag)) ++ wlanTimerTimeoutCheck(prGlueInfo->prAdapter); ++#if CFG_DBG_GPIO_PINS ++ /* TX thread go to sleep */ ++ if (!prGlueInfo->ulFlag) ++ mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_HIGH); ++#endif ++ } ++ ++#if 0 ++ if (fgNeedHwAccess == TRUE) ++ wlanReleasePowerControl(prGlueInfo->prAdapter); ++#endif ++ ++ /* exit while loop, tx thread is closed so we flush all pending packets */ ++ /* flush the pending TX packets */ ++ if (prGlueInfo->i4TxPendingFrameNum > 0) ++ kalFlushPendingTxPackets(prGlueInfo); ++ ++ /* flush pending security frames */ ++ if (prGlueInfo->i4TxPendingSecurityFrameNum > 0) ++ kalClearSecurityFrames(prGlueInfo); ++ ++ /* remove pending oid */ ++ wlanReleasePendingOid(prGlueInfo->prAdapter, 0); ++ ++ /* In linux, we don't need to free sk_buff by ourself */ ++ ++ DBGLOG(INIT, INFO, "mtk_sdiod stops\n"); ++ complete(&prGlueInfo->rHaltComp); ++ ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to check if card is removed ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval TRUE: card is removed ++* FALSE: card is still attached ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return FALSE; ++ /* Linux MMC doesn't have removal notification yet */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This routine is used to send command to firmware for overriding netweork address ++ * ++ * \param pvGlueInfo Pointer of GLUE Data Structure ++ ++ * \retval TRUE ++ * FALSE ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr) ++{ ++ ASSERT(prGlueInfo); ++ ++ if (prGlueInfo->fgIsMacAddrOverride == FALSE) { ++#if !defined(CONFIG_X86) ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ UINT_32 i; ++#endif ++ BOOLEAN fgIsReadError = FALSE; ++ ++#if !defined(CONFIG_MTK_TC1_FEATURE) ++ for (i = 0; i < MAC_ADDR_LEN; i += 2) { ++ if (kalCfgDataRead16(prGlueInfo, ++ OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, ++ (PUINT_16) (((PUINT_8) prMacAddr) + i)) == FALSE) { ++ fgIsReadError = TRUE; ++ break; ++ } ++ } ++#else ++ TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prMacAddr); ++#endif ++ ++ if (fgIsReadError == TRUE) ++ return FALSE; ++ else ++ return TRUE; ++#else ++ /* x86 Linux doesn't need to override network address so far */ ++ return FALSE; ++#endif ++ } else { ++ COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); ++ ++ return TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to flush pending TX packets in glue layer ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prTxQue; ++ P_QUE_ENTRY_T prQueueEntry; ++ PVOID prPacket; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ prTxQue = &(prGlueInfo->rTxQueue); ++ ++ if (prGlueInfo->i4TxPendingFrameNum) { ++ while (TRUE) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ if (prQueueEntry == NULL) ++ break; ++ ++ prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); ++ ++ kalSendComplete(prGlueInfo, prPacket, WLAN_STATUS_NOT_ACCEPTED); ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is get indicated media state ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->eParamMediaStateIndicated; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to set indicated media state ++* ++* \param pvGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate) ++{ ++ ASSERT(prGlueInfo); ++ ++ prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to clear pending OID staying in command queue ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ QUE_T rTempCmdQue; ++ P_QUE_T prTempCmdQue = &rTempCmdQue; ++ P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; ++ P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ while (prQueueEntry) { ++ ++ if (((P_CMD_INFO_T) prQueueEntry)->fgIsOid) { ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ break; ++ } ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ ++ QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); ++ } ++ ++ QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ ++ if (prCmdInfo) { ++ if (prCmdInfo->pfCmdTimeoutHandler) ++ prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); ++ else ++ kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_NOT_ACCEPTED); ++ ++ prGlueInfo->u4OidCompleteFlag = 1; ++ cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to insert command into prCmdQueue ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* prQueueEntry Pointer of queue entry to be inserted ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry) ++{ ++ P_QUE_T prCmdQue; ++ P_CMD_INFO_T prCmdInfo; ++ P_MSDU_INFO_T prMsduInfo; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prQueueEntry); ++ ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ prCmdInfo = (P_CMD_INFO_T) prQueueEntry; ++ if (prCmdInfo->prPacket && prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { ++ prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); ++ prMsduInfo->eCmdType = prCmdInfo->eCmdType; ++ prMsduInfo->ucCID = prCmdInfo->ucCID; ++ prMsduInfo->u4InqueTime = kalGetTimeTick(); ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++ QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Handle EVENT_ID_ASSOC_INFO event packet by indicating to OS with ++* proper information ++* ++* @param pvGlueInfo Pointer of GLUE Data Structure ++* @param prAssocInfo Pointer of EVENT_ID_ASSOC_INFO Packet ++* ++* @return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo) ++{ ++ /* to do */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to get firmware load address from registry ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rRegInfo.u4LoadAddress; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to get firmware start address from registry ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rRegInfo.u4StartAddress; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * * @brief Notify OS with SendComplete event of the specific packet. Linux should ++ * * free packets here. ++ * * ++ * * @param pvGlueInfo Pointer of GLUE Data Structure ++ * * @param pvPacket Pointer of Packet Handle ++ * * @param status Status Code for OS upper layer ++ * * ++ * * @return none ++ * */ ++/*----------------------------------------------------------------------------*/ ++ ++/* / Todo */ ++VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus) ++{ ++ ASSERT(pvPacket); ++ ++ dev_kfree_skb((struct sk_buff *)pvPacket); ++ if (prGlueInfo) ++ prGlueInfo->u8SkbFreed++; ++ GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++} ++ ++UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return (UINT_32) (prGlueInfo->i4TxPendingFrameNum); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to retrieve the number of pending commands ++* (including MMPDU, 802.1X and command packets) ++* ++* \param prGlueInfo Pointer of GLUE Data Structure ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_QUE_T prCmdQue; ++ ++ ASSERT(prGlueInfo); ++ prCmdQue = &prGlueInfo->rCmdQueue; ++ ++ return prCmdQue->u4NumElem; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Timer Initialization Procedure ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* \param[in] prTimerHandler Pointer to timer handling function, whose only ++* argument is "prAdapter" ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++/* static struct timer_list tickfn; */ ++ ++VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler) ++{ ++ ++ ASSERT(prGlueInfo); ++ ++ timer_setup(&(prGlueInfo->tickfn), prTimerHandler, 0); ++} ++ ++/* Todo */ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the time to do the time out check. ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* \param[in] rInterval Time out interval from current time. ++* ++* \retval TRUE Success. ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval) ++{ ++ ASSERT(prGlueInfo); ++ del_timer_sync(&(prGlueInfo->tickfn)); ++ ++ prGlueInfo->tickfn.expires = jiffies + u4Interval * HZ / MSEC_PER_SEC; ++ add_timer(&(prGlueInfo->tickfn)); ++ ++ return TRUE; /* success */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to cancel ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* ++* \retval TRUE : Timer has been canceled ++* FALAE : Timer doens't exist ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); ++ ++ if (del_timer_sync(&(prGlueInfo->tickfn)) >= 0) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is a callback function for scanning done ++* ++* \param[in] prGlueInfo Pointer to GLUE Data Structure ++* ++* \retval none ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status) ++{ ++ P_AIS_FSM_INFO_T prAisFsmInfo; ++ ++ ASSERT(prGlueInfo); ++ ++ prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); ++ /* report all queued beacon/probe response frames to upper layer */ ++ scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); ++ cnmTimerStopTimer(prGlueInfo->prAdapter, &prAisFsmInfo->rScanDoneTimer); ++ ++ /* check for system configuration for generating error message on scan list */ ++ wlanCheckSystemConfiguration(prGlueInfo->prAdapter); ++ ++ kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is used to generate a random number ++* ++* \param none ++* ++* \retval UINT_32 ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalRandomNumber(VOID) ++{ ++ UINT_32 number = 0; ++ ++ get_random_bytes(&number, 4); ++ ++ return number; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief command timeout call-back function ++ * ++ * \param[in] prGlueInfo Pointer to the GLUE data structure. ++ * ++ * \retval (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID kalTimeoutHandler(struct timer_list *t) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = from_timer(prGlueInfo, t, tickfn); ++ ++ ASSERT(prGlueInfo); ++ ++ /* Notify tx thread for timeout event */ ++ set_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++} ++ ++VOID kalSetEvent(P_GLUE_INFO_T pr) ++{ ++ set_bit(GLUE_FLAG_TXREQ_BIT, &pr->ulFlag); ++ wake_up_interruptible(&pr->waitq); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if configuration file (NVRAM/Registry) exists ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo) ++{ ++#if !defined(CONFIG_X86) ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->fgNvramAvailable; ++#else ++ /* there is no configuration data for x86-linux */ ++ return FALSE; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Registry information ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* Pointer of REG_INFO_T ++*/ ++/*----------------------------------------------------------------------------*/ ++P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return &(prGlueInfo->rRegInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve version information of corresponding configuration file ++* ++* \param[in] ++* prGlueInfo ++* ++* \param[out] ++* pu2Part1CfgOwnVersion ++* pu2Part1CfgPeerVersion ++* pu2Part2CfgOwnVersion ++* pu2Part2CfgPeerVersion ++* ++* \return ++* NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PUINT_16 pu2Part1CfgOwnVersion, ++ OUT PUINT_16 pu2Part1CfgPeerVersion, ++ OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion) ++{ ++ ASSERT(prGlueInfo); ++ ++ ASSERT(pu2Part1CfgOwnVersion); ++ ASSERT(pu2Part1CfgPeerVersion); ++ ASSERT(pu2Part2CfgOwnVersion); ++ ASSERT(pu2Part2CfgPeerVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion), pu2Part1CfgOwnVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1PeerVersion), pu2Part1CfgPeerVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion), pu2Part2CfgOwnVersion); ++ ++ kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2PeerVersion), pu2Part2CfgPeerVersion); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the WPS is active or not ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->fgWpsActive; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief update RSSI and LinkQuality to GLUE layer ++* ++* \param[in] ++* prGlueInfo ++* eNetTypeIdx ++* cRssi ++* cLinkQuality ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) ++{ ++ struct iw_statistics *pStats = (struct iw_statistics *)NULL; ++ ++ ASSERT(prGlueInfo); ++ ++ switch (eNetTypeIdx) { ++ case KAL_NETWORK_TYPE_AIS_INDEX: ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); ++ break; ++#if CFG_ENABLE_WIFI_DIRECT ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case KAL_NETWORK_TYPE_P2P_INDEX: ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ break; ++#endif ++#endif ++ default: ++ break; ++ ++ } ++ ++ if (pStats) { ++ pStats->qual.qual = cLinkQuality; ++ pStats->qual.noise = 0; ++ pStats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; ++ pStats->qual.level = 0x100 + cRssi; ++ pStats->qual.updated |= IW_QUAL_LEVEL_UPDATED; ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Pre-allocate I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitIOBuffer(VOID) ++{ ++ UINT_32 u4Size; ++ ++ if (CFG_COALESCING_BUFFER_SIZE >= CFG_RX_COALESCING_BUFFER_SIZE) ++ u4Size = CFG_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); ++ else ++ u4Size = CFG_RX_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ pvDmaBuffer = dma_alloc_coherent(NULL, CFG_RX_MAX_PKT_SIZE, &pvDmaPhyBuf, GFP_KERNEL); ++ if (pvDmaBuffer == NULL) ++ return FALSE; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ pvIoBuffer = kmalloc(u4Size, GFP_KERNEL); ++/* pvIoBuffer = dma_alloc_coherent(NULL, u4Size, &pvIoPhyBuf, GFP_KERNEL); */ ++ if (pvIoBuffer) { ++ pvIoBufferSize = u4Size; ++ pvIoBufferUsage = 0; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free pre-allocated I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalUninitIOBuffer(VOID) ++{ ++ kfree(pvIoBuffer); ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ dma_free_coherent(NULL, CFG_RX_MAX_PKT_SIZE, pvDmaBuffer, pvDmaPhyBuf); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ /* dma_free_coherent(NULL, pvIoBufferSize, pvIoBuffer, pvIoPhyBuf); */ ++ ++ pvIoBuffer = (PVOID) NULL; ++ pvIoBufferSize = 0; ++ pvIoBufferUsage = 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dispatch pre-allocated I/O buffer ++* ++* \param[in] ++* u4AllocSize ++* ++* \return ++* PVOID for pointer of pre-allocated I/O buffer ++*/ ++/*----------------------------------------------------------------------------*/ ++PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize) ++{ ++ PVOID ret = (PVOID) NULL; ++ ++ if (pvIoBuffer) { ++ if (u4AllocSize <= (pvIoBufferSize - pvIoBufferUsage)) { ++ ret = (PVOID) &(((PUINT_8) (pvIoBuffer))[pvIoBufferUsage]); ++ pvIoBufferUsage += u4AllocSize; ++ } ++ } else { ++ /* fault tolerance */ ++ ret = (PVOID) kalMemAlloc(u4AllocSize, PHY_MEM_TYPE); ++ } ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Release all dispatched I/O buffer ++* ++* \param[in] ++* none ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size) ++{ ++ if (pvIoBuffer) { ++ pvIoBufferUsage -= u4Size; ++ } else { ++ /* fault tolerance */ ++ kalMemFree(pvAddr, PHY_MEM_TYPE, u4Size); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, ++ pucNumOfChannel, paucChannelList); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo) ++{ ++#if CFG_ENABLE_WIFI_DIRECT ++ if (IS_NET_ACTIVE(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX) && ++ p2pFuncIsAPMode(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo)) ++ return TRUE; ++#endif ++ ++ return FALSE; ++} ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the physical address for Pre-allocate I/O buffer. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return physical addr ++*/ ++/*----------------------------------------------------------------------------*/ ++ULONG kalIOPhyAddrGet(IN ULONG VirtAddr) ++{ ++ ULONG PhyAddr; ++ ++ if ((VirtAddr >= (ULONG) pvIoBuffer) && (VirtAddr <= ((ULONG) (pvIoBuffer) + pvIoBufferSize))) { ++ PhyAddr = (ULONG) pvIoPhyBuf; ++ PhyAddr += (VirtAddr - (ULONG) (pvIoBuffer)); ++ return PhyAddr; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the physical address for Pre-allocate I/O buffer. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] rLockCategory Specify which SPIN_LOCK ++* \param[out] pu4Flags Pointer of a variable for saving IRQ flags ++* ++* \return physical addr ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr) ++{ ++ *VirtAddr = pvDmaBuffer; ++ *PhyAddr = pvDmaPhyBuf; ++} ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++#if CFG_SUPPORT_802_11W ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to check if the MFP is active or not ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->rWpaInfo.u4Mfp; ++} ++#endif ++ ++struct file *kalFileOpen(const char *path, int flags, int rights) ++{ ++ struct file *filp = NULL; ++ mm_segment_t oldfs; ++ int err = 0; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ filp = filp_open(path, flags, rights); ++ set_fs(oldfs); ++ if (IS_ERR(filp)) { ++ err = PTR_ERR(filp); ++ return NULL; ++ } ++ return filp; ++} ++ ++VOID kalFileClose(struct file *file) ++{ ++ filp_close(file, NULL); ++} ++ ++UINT_32 kalFileRead(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) ++{ ++ mm_segment_t oldfs; ++ INT_32 ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ++ ret = vfs_read(file, data, size, &offset); ++ ++ set_fs(oldfs); ++ return ret; ++} ++ ++UINT_32 kalFileWrite(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) ++{ ++ mm_segment_t oldfs; ++ INT_32 ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ++ ret = vfs_write(file, data, size, &offset); ++ ++ set_fs(oldfs); ++ return ret; ++} ++ ++UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size) ++{ ++ struct file *file = NULL; ++ UINT_32 ret = -1; ++ UINT_32 u4Flags = 0; ++ ++ if (fgDoAppend) ++ u4Flags = O_APPEND; ++ ++ file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); ++ if (file) { ++ ret = kalFileWrite(file, 0, pucData, u4Size); ++ kalFileClose(file); ++ } ++ ++ return ret; ++} ++ ++INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize) ++{ ++ struct file *file = NULL; ++ INT_32 ret = -1; ++ UINT_32 u4ReadSize = 0; ++ ++ DBGLOG(INIT, LOUD, "kalReadToFile() path %s\n", pucPath); ++ ++ file = kalFileOpen(pucPath, O_RDONLY, 0); ++ ++ if ((file != NULL) && !IS_ERR(file)) { ++ u4ReadSize = kalFileRead(file, 0, pucData, u4Size); ++ kalFileClose(file); ++ if (pu4ReadSize) ++ *pu4ReadSize = u4ReadSize; ++ ret = 0; ++ } ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate BSS-INFO to NL80211 as scanning result ++* ++* \param[in] ++* prGlueInfo ++* pucBeaconProbeResp ++* u4FrameLen ++* ++* ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucBeaconProbeResp, ++ IN UINT_32 u4FrameLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength) ++{ ++ struct wiphy *wiphy; ++ struct ieee80211_channel *prChannel = NULL; ++ ++ ASSERT(prGlueInfo); ++ wiphy = priv_to_wiphy(prGlueInfo); ++ ++ /* search through channel entries */ ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ if (prChannel != NULL && (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)) { ++ struct cfg80211_bss *bss; ++#if CFG_SUPPORT_TSF_USING_BOOTTIME ++ struct ieee80211_mgmt *prMgmtFrame = (struct ieee80211_mgmt *)pucBeaconProbeResp; ++ ++ prMgmtFrame->u.beacon.timestamp = kalGetBootTime(); ++#endif ++ ScanCnt++; ++ ++ /* indicate to NL80211 subsystem */ ++ bss = cfg80211_inform_bss_frame(wiphy, ++ prChannel, ++ (struct ieee80211_mgmt *)pucBeaconProbeResp, ++ u4FrameLen, i4SignalStrength * 100, GFP_KERNEL); ++ ++ if (!bss) { ++ ScanDoneFailCnt++; ++ DBGLOG(SCN, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", ++ ucChannelNum, i4SignalStrength); ++ } else { ++ cfg80211_put_bss(wiphy, bss); ++ DBGLOG(SCN, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", ++ ucChannelNum, i4SignalStrength); ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate channel ready ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs) ++{ ++ struct ieee80211_channel *prChannel = NULL; ++ enum nl80211_channel_type rChannelType; ++ ++ /* ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); */ ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ switch (eSco) { ++ case CHNL_EXT_SCN: ++ rChannelType = NL80211_CHAN_NO_HT; ++ break; ++ ++ case CHNL_EXT_SCA: ++ rChannelType = NL80211_CHAN_HT40MINUS; ++ break; ++ ++ case CHNL_EXT_SCB: ++ rChannelType = NL80211_CHAN_HT40PLUS; ++ break; ++ ++ case CHNL_EXT_RES: ++ default: ++ rChannelType = NL80211_CHAN_HT20; ++ break; ++ } ++ ++ cfg80211_ready_on_channel(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, u4DurationMs, ++ GFP_KERNEL); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate channel expiration ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum) ++{ ++ struct ieee80211_channel *prChannel = NULL; ++ enum nl80211_channel_type rChannelType; ++ ++ ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); ++ ++ if (prGlueInfo->fgIsRegistered == TRUE) { ++ if (ucChannelNum <= 14) { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); ++ } else { ++ prChannel = ++ ieee80211_get_channel(priv_to_wiphy(prGlueInfo), ++ ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); ++ } ++ ++ switch (eSco) { ++ case CHNL_EXT_SCN: ++ rChannelType = NL80211_CHAN_NO_HT; ++ break; ++ ++ case CHNL_EXT_SCA: ++ rChannelType = NL80211_CHAN_HT40MINUS; ++ break; ++ ++ case CHNL_EXT_SCB: ++ rChannelType = NL80211_CHAN_HT40PLUS; ++ break; ++ ++ case CHNL_EXT_RES: ++ default: ++ rChannelType = NL80211_CHAN_HT20; ++ break; ++ } ++ ++ cfg80211_remain_on_channel_expired(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, ++ GFP_KERNEL); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate Mgmt tx status ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) ++{ ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { ++ DBGLOG(AIS, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", ++ prGlueInfo, pucFrameBuf, u4FrameLen); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ cfg80211_mgmt_tx_status(prGlueInfo->prDevHandler->ieee80211_ptr, ++ u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalIndicateMgmtTxStatus */ ++ ++VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) ++{ ++#define DBG_MGMT_FRAME_INDICATION 1 ++ INT_32 i4Freq = 0; ++ UINT_8 ucChnlNum = 0; ++#if DBG_MGMT_FRAME_INDICATION ++ P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; ++#endif ++ ++ do { ++ if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; ++ ++#if DBG_MGMT_FRAME_INDICATION ++ prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; ++ ++ switch (prWlanHeader->u2FrameCtrl) { ++ case MAC_FRAME_PROBE_REQ: ++ DBGLOG(AIS, TRACE, "RX Probe Req at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(AIS, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_ACTION: ++ DBGLOG(AIS, TRACE, "RX Action frame at channel %d ", ucChnlNum); ++ break; ++ default: ++ DBGLOG(AIS, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); ++ break; ++ } ++ ++#endif ++ i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; ++ ++ cfg80211_rx_mgmt(prGlueInfo->prDevHandler->ieee80211_ptr, /* struct net_device * dev, */ ++ i4Freq, ++ RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), ++ prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalIndicateRxMgmtFrame */ ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen) ++{ ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ struct sk_buff *skb = cfg80211_testmode_alloc_event_skb(priv_to_wiphy(prGlueInfo), ++ dataLen, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(AIS, ERROR, "kalIndicateAgpsNotify: alloc skb failed\n"); ++ return FALSE; ++ } ++ ++ /* DBGLOG(CCX, INFO, ("WLAN_STATUS_AGPS_NOTIFY, cmd=%d\n", cmd)); */ ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_CMD, sizeof(cmd), &cmd) < 0)) ++ goto nla_put_failure; ++ if (dataLen > 0 && data && unlikely(nla_put(skb, MTK_ATTR_AGPS_DATA, dataLen, data) < 0)) ++ goto nla_put_failure; ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFINDEX, sizeof(UINT_32), &prGlueInfo->prDevHandler->ifindex) < 0)) ++ goto nla_put_failure; ++ /* currently, the ifname maybe wlan0, p2p0, so the maximum name length will be 5 bytes */ ++ if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFNAME, 5, prGlueInfo->prDevHandler->name) < 0)) ++ goto nla_put_failure; ++ cfg80211_testmode_event(skb, GFP_KERNEL); ++ return TRUE; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return FALSE; ++} ++#endif ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++#define PROC_MET_PROF_CTRL "met_ctrl" ++#define PROC_MET_PROF_PORT "met_port" ++ ++struct proc_dir_entry *pMetProcDir; ++void *pMetGlobalData = NULL; ++static unsigned long __read_mostly tracing_mark_write_addr; ++ ++static inline void __mt_update_tracing_mark_write_addr(void) ++{ ++ if (unlikely(0 == tracing_mark_write_addr)) ++ tracing_mark_write_addr = kallsyms_lookup_name("tracing_mark_write"); ++} ++ ++VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb) ++{ ++ UINT_8 ucIpVersion; ++ UINT_16 u2UdpSrcPort; ++ UINT_16 u2RtpSn; ++ PUINT_8 pucEthHdr = prSkb->data; ++ PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; ++ ++ /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ ++ /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ ++ /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ ++ /* printk("MET_PROF: MET enable=%d(HardXmit)\n", prGlueInfo->u8MetProfEnable); */ ++ if (prGlueInfo->u8MetProfEnable == 1) { ++ u2UdpSrcPort = prGlueInfo->u16MetUdpPort; ++ if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { ++ /* IP */ ++ pucIpHdr = pucEthHdr + ETH_HLEN; ++ ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { ++ /* UDP */ ++ pucUdpHdr = pucIpHdr + IP_HEADER_LEN; ++ /* check UDP port number */ ++ if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { ++ /* RTP */ ++ pucRtpHdr = pucUdpHdr + 8; ++ u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; ++ /* trace_printk("S|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); ++ //frm_sequence); */ ++#ifdef CONFIG_TRACING ++ __mt_update_tracing_mark_write_addr(); ++ if (tracing_mark_write_addr != 0) { ++ event_trace_printk(tracing_mark_write_addr, "S|%d|%s|%d\n", ++ current->tgid, "WIFI-CHIP", u2RtpSn); ++ } ++#endif ++ } ++ } ++ } ++ } ++} ++ ++VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) ++{ ++ UINT_8 ucIpVersion; ++ UINT_16 u2UdpSrcPort; ++ UINT_16 u2RtpSn; ++ struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; ++ PUINT_8 pucEthHdr = prSkb->data; ++ PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ ++ /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ ++ /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ ++ /* printk("MET_PROF: MET enable=%d(TxMsdu)\n", prGlueInfo->u8MetProfEnable); */ ++ if (prGlueInfo->u8MetProfEnable == 1) { ++ u2UdpSrcPort = prGlueInfo->u16MetUdpPort; ++ if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { ++ /* IP */ ++ pucIpHdr = pucEthHdr + ETH_HLEN; ++ ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; ++ if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { ++ /* UDP */ ++ pucUdpHdr = pucIpHdr + IP_HEADER_LEN; ++ /* check UDP port number */ ++ if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { ++ /* RTP */ ++ pucRtpHdr = pucUdpHdr + 8; ++ u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; ++ /* trace_printk("F|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); ++ //frm_sequence); */ ++#ifdef CONFIG_TRACING ++ __mt_update_tracing_mark_write_addr(); ++ if (tracing_mark_write_addr != 0) { ++ event_trace_printk(tracing_mark_write_addr, "F|%d|%s|%d\n", ++ current->tgid, "WIFI-CHIP", u2RtpSn); ++ } ++#endif ++ } ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t kalMetCtrlWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) ++{ ++ char acBuf[128 + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ int u8MetProfEnable; ++ ++ IN P_GLUE_INFO_T prGlueInfo; ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, u4CopySize)) ++ return -1; ++ acBuf[u4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, " %d", &u8MetProfEnable) == 1) ++ DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC Enable=%d\n", u8MetProfEnable); ++ if (pMetGlobalData != NULL) { ++ prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; ++ prGlueInfo->u8MetProfEnable = (UINT_8) u8MetProfEnable; ++ } ++ return count; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static ssize_t kalMetPortWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) ++{ ++ char acBuf[128 + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ int u16MetUdpPort; ++ ++ IN P_GLUE_INFO_T prGlueInfo; ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, u4CopySize)) ++ return -1; ++ acBuf[u4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, " %d", &u16MetUdpPort) == 1) ++ DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC UDP_PORT=%d\n", u16MetUdpPort); ++ if (pMetGlobalData != NULL) { ++ prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; ++ prGlueInfo->u16MetUdpPort = (UINT_16) u16MetUdpPort; ++ } ++ return count; ++} ++ ++const struct file_operations rMetProcCtrlFops = { ++.write = kalMetCtrlWriteProcfs ++}; ++ ++const struct file_operations rMetProcPortFops = { ++.write = kalMetPortWriteProcfs ++}; ++ ++int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ /* struct proc_dir_entry *pMetProcDir; */ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ DBGLOG(INIT, INFO, "init proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ /* ++ * Directory: Root (/proc/net/wlan0) ++ */ ++ pMetProcDir = proc_mkdir("wlan0", init_net.proc_net); ++ if (pMetProcDir == NULL) ++ return -ENOENT; ++ /* ++ /proc/net/wlan0 ++ |-- met_ctrl (PROC_MET_PROF_CTRL) ++ |-- met_port (PROC_MET_PROF_PORT) ++ */ ++ /* proc_create(PROC_MET_PROF_CTRL, 0x0644, pMetProcDir, &rMetProcFops); */ ++ proc_create(PROC_MET_PROF_CTRL, 0, pMetProcDir, &rMetProcCtrlFops); ++ proc_create(PROC_MET_PROF_PORT, 0, pMetProcDir, &rMetProcPortFops); ++ ++ pMetGlobalData = (void *)prGlueInfo; ++ ++ return 0; ++} ++ ++int kalMetRemoveProcfs(void) ++{ ++ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ DBGLOG(INIT, WARN, "remove proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ remove_proc_entry(PROC_MET_PROF_CTRL, pMetProcDir); ++ remove_proc_entry(PROC_MET_PROF_PORT, pMetProcDir); ++ /* remove root directory (proc/net/wlan0) */ ++ remove_proc_entry("wlan0", init_net.proc_net); ++ /* clear MetGlobalData */ ++ pMetGlobalData = NULL; ++ ++ return 0; ++} ++#endif ++UINT_64 kalGetBootTime(void) ++{ ++ struct timespec ts; ++ UINT_64 bootTime = 0; ++ ++ get_monotonic_boottime(&ts); ++ /* we assign ts.tv_sec to bootTime first, then multiply USEC_PER_SEC ++ this will prevent multiply result turn to a negative value on 32bit system */ ++ bootTime = ts.tv_sec; ++ bootTime *= USEC_PER_SEC; ++ bootTime += ts.tv_nsec / NSEC_PER_USEC; ++ return bootTime; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan results are avilable ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ cfg80211_sched_scan_results(priv_to_wiphy(prGlueInfo),0); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To indicate scheduled scan has been stopped ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* None ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prGlueInfo); ++ ++ /* 1. reset first for newly incoming request */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prSchedScanRequest != NULL) ++ prGlueInfo->prSchedScanRequest = NULL; ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ DBGLOG(SCN, INFO, "cfg80211_sched_scan_stopped send event\n"); ++ ++ /* 2. indication to cfg80211 */ ++ /* 20150205 change cfg80211_sched_scan_stopped to work queue to use K thread to send event instead of Tx thread ++ due to sched_scan_mtx dead lock issue by Tx thread serves oid cmds and send event in the same time */ ++ DBGLOG(SCN, TRACE, "start work queue to send event\n"); ++ schedule_delayed_work(&sched_workq, 0); ++ DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); ++ ++} ++ ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++/* if SPM is not implement this function, we will use this default one */ ++wake_reason_t __weak slp_get_wake_reason(VOID) ++{ ++ return WR_NONE; ++} ++/* if SPM is not implement this function, we will use this default one */ ++UINT_32 __weak spm_get_last_wakeup_src(VOID) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To check if device if wake up by wlan ++* ++* \param[in] ++* prAdapter ++* ++* \return ++* TRUE: wake up by wlan; otherwise, FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter) ++{ ++ /* SUSPEND_FLAG_FOR_WAKEUP_REASON is set means system has suspended, but may be failed ++ duo to some driver suspend failed. so we need help of function slp_get_wake_reason */ ++ if (test_and_clear_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prAdapter->ulSuspendFlag) == 0) ++ return FALSE; ++ /* if slp_get_wake_reason or spm_get_last_wakeup_src is NULL, it means SPM module didn't implement ++ it. then we should return FALSE always. otherwise, if slp_get_wake_reason returns WR_WAKE_SRC, ++ then it means the host is suspend successfully. */ ++ if (slp_get_wake_reason() != WR_WAKE_SRC) ++ return FALSE; ++ /* spm_get_last_wakeup_src will returns the last wakeup source, ++ WAKE_SRC_CONN2AP is connsys */ ++ return !!(spm_get_last_wakeup_src() & WAKE_SRC_CONN2AP); ++} ++#endif ++ ++INT_32 kalHaltLock(UINT_32 waitMs) ++{ ++ INT_32 i4Ret = 0; ++ ++ if (waitMs) { ++ i4Ret = down_timeout(&rHaltCtrl.lock, MSEC_TO_JIFFIES(waitMs)); ++ if (!i4Ret) ++ goto success; ++ if (i4Ret != -ETIME) ++ return i4Ret; ++ if (rHaltCtrl.fgHeldByKalIoctl) { ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ wlanExportGlueInfo(&prGlueInfo); ++ ++ DBGLOG(INIT, ERROR, ++ "kalIoctl was executed longer than %u ms, show backtrace of tx_thread!\n", ++ kalGetTimeTick() - rHaltCtrl.u4HoldStart); ++ if (prGlueInfo) ++ show_stack(prGlueInfo->main_thread, NULL); ++ } else { ++ DBGLOG(INIT, ERROR, "halt lock held by %s pid %d longer than %u ms!\n", ++ rHaltCtrl.owner->comm, rHaltCtrl.owner->pid, ++ kalGetTimeTick() - rHaltCtrl.u4HoldStart); ++ show_stack(rHaltCtrl.owner, NULL); ++ } ++ return i4Ret; ++ } ++ down(&rHaltCtrl.lock); ++success: ++ rHaltCtrl.owner = current; ++ rHaltCtrl.u4HoldStart = kalGetTimeTick(); ++ return 0; ++} ++ ++INT_32 kalHaltTryLock(VOID) ++{ ++ INT_32 i4Ret = 0; ++ ++ i4Ret = down_trylock(&rHaltCtrl.lock); ++ if (i4Ret) ++ return i4Ret; ++ rHaltCtrl.owner = current; ++ rHaltCtrl.u4HoldStart = kalGetTimeTick(); ++ return 0; ++} ++ ++VOID kalHaltUnlock(VOID) ++{ ++ if (kalGetTimeTick() - rHaltCtrl.u4HoldStart > WLAN_OID_TIMEOUT_THRESHOLD * 2 && ++ rHaltCtrl.owner) ++ DBGLOG(INIT, ERROR, "process %s pid %d hold halt lock longer than 4s!\n", ++ rHaltCtrl.owner->comm, rHaltCtrl.owner->pid); ++ rHaltCtrl.owner = NULL; ++ up(&rHaltCtrl.lock); ++} ++ ++VOID kalSetHalted(BOOLEAN fgHalt) ++{ ++ rHaltCtrl.fgHalt = fgHalt; ++} ++ ++BOOLEAN kalIsHalted(VOID) ++{ ++ return rHaltCtrl.fgHalt; ++} ++VOID kalPerMonDump(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, WARN, "ulPerfMonFlag:0x%lx\n", prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "ulLastTxBytes:%ld\n", prPerMonitor->ulLastTxBytes); ++ DBGLOG(SW4, WARN, "ulLastRxBytes:%ld\n", prPerMonitor->ulLastRxBytes); ++ DBGLOG(SW4, WARN, "ulP2PLastTxBytes:%ld\n", prPerMonitor->ulP2PLastTxBytes); ++ DBGLOG(SW4, WARN, "ulP2PLastRxBytes:%ld\n", prPerMonitor->ulP2PLastRxBytes); ++ DBGLOG(SW4, WARN, "ulThroughput:%ld\n", prPerMonitor->ulThroughput); ++ DBGLOG(SW4, WARN, "u4UpdatePeriod:%d\n", prPerMonitor->u4UpdatePeriod); ++ DBGLOG(SW4, WARN, "u4TarPerfLevel:%d\n", prPerMonitor->u4TarPerfLevel); ++ DBGLOG(SW4, WARN, "u4CurrPerfLevel:%d\n", prPerMonitor->u4CurrPerfLevel); ++ DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.tx_bytes); ++ DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.rx_bytes); ++ DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes); ++ DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes); ++} ++ ++inline INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) ++ DBGLOG(SW4, WARN, "abnormal, perf monitory already running\n"); ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ prPerMonitor->u4UpdatePeriod = 1000; ++ cnmTimerInitTimer(prGlueInfo->prAdapter, ++ &prPerMonitor->rPerfMonTimer, ++ (PFN_MGMT_TIMEOUT_FUNC) kalPerMonHandler, (ULONG) NULL); ++ DBGLOG(SW4, INFO, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "need to stop before disable\n"); ++ kalPerMonStop(prGlueInfo); ++ } ++ KAL_SET_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ ++ DBGLOG(SW4, INFO, "enter %s\n", __func__); ++ KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter %s\n", __func__); ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) ++ return 0; ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitor already running\n"); ++ return 0; ++ } ++ cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); ++ KAL_SET_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ KAL_CLR_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, INFO, "perf monitor started\n"); ++ return 0; ++} ++ ++inline INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter %s\n", __func__); ++ ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitory disabled\n"); ++ return 0; ++ } ++ ++ if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ DBGLOG(SW4, TRACE, "perf monitory already stopped\n"); ++ return 0; ++ } ++ ++ KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ cnmTimerStopTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer); ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ prPerMonitor->ulLastRxBytes = 0; ++ prPerMonitor->ulLastTxBytes = 0; ++ prPerMonitor->ulP2PLastRxBytes = 0; ++ prPerMonitor->ulP2PLastTxBytes = 0; ++ prPerMonitor->ulThroughput = 0; ++ prPerMonitor->u4CurrPerfLevel = 0; ++ prPerMonitor->u4TarPerfLevel = 0; ++ /*Cancel CPU performance mode request*/ ++ kalBoostCpu(0); ++ } ++ DBGLOG(SW4, TRACE, "exit %s\n", __func__); ++ return 0; ++} ++ ++inline INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ kalPerMonDisable(prGlueInfo); ++ return 0; ++} ++ ++VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam) ++{ ++ /*Calculate current throughput*/ ++ struct GL_PER_MON_T *prPerMonitor; ++ ++ LONG latestTxBytes, latestRxBytes, txDiffBytes, rxDiffBytes; ++ LONG p2pLatestTxBytes, p2pLatestRxBytes, p2pTxDiffBytes, p2pRxDiffBytes; ++ P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; ++ ++ if ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) || (!prAdapter->fgIsP2PRegistered)) ++ return; ++ ++ prPerMonitor = &prAdapter->rPerMonitor; ++ DBGLOG(SW4, TRACE, "enter kalPerMonHandler\n"); ++ if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "perf monitory disabled, omit timeout event\n"); ++ return; ++ } ++ ++ if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { ++ KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); ++ DBGLOG(SW4, WARN, "perf monitory stopped, omit timeout event\n"); ++ return; ++ } ++ latestTxBytes = prGlueInfo->rNetDevStats.tx_bytes; ++ latestRxBytes = prGlueInfo->rNetDevStats.rx_bytes; ++ p2pLatestTxBytes = prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes; ++ p2pLatestRxBytes = prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes; ++ if (0 == prPerMonitor->ulLastRxBytes && ++ 0 == prPerMonitor->ulLastTxBytes && ++ 0 == prPerMonitor->ulP2PLastRxBytes && ++ 0 == prPerMonitor->ulP2PLastTxBytes) { ++ prPerMonitor->ulThroughput = 0; ++ } else { ++ txDiffBytes = latestTxBytes - prPerMonitor->ulLastTxBytes; ++ rxDiffBytes = latestRxBytes - prPerMonitor->ulLastRxBytes; ++ if (0 > txDiffBytes) ++ txDiffBytes = -(txDiffBytes); ++ if (0 > rxDiffBytes) ++ rxDiffBytes = -(rxDiffBytes); ++ ++ p2pTxDiffBytes = p2pLatestTxBytes - prPerMonitor->ulP2PLastTxBytes; ++ p2pRxDiffBytes = p2pLatestRxBytes - prPerMonitor->ulP2PLastRxBytes; ++ if (0 > p2pTxDiffBytes) ++ p2pTxDiffBytes = -(p2pTxDiffBytes); ++ if (0 > p2pRxDiffBytes) ++ p2pRxDiffBytes = -(p2pRxDiffBytes); ++ ++ prPerMonitor->ulThroughput = txDiffBytes + rxDiffBytes + p2pTxDiffBytes + p2pRxDiffBytes; ++ prPerMonitor->ulThroughput *= 1000; ++ prPerMonitor->ulThroughput /= prPerMonitor->u4UpdatePeriod; ++ prPerMonitor->ulThroughput <<= 3; ++ } ++ /*start the timer again to make sure we can cancel performance mode request in the end*/ ++ cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); ++ ++ prPerMonitor->ulLastTxBytes = latestTxBytes; ++ prPerMonitor->ulLastRxBytes = latestRxBytes; ++ prPerMonitor->ulP2PLastTxBytes = p2pLatestTxBytes; ++ prPerMonitor->ulP2PLastRxBytes = p2pLatestRxBytes; ++ ++ if (prPerMonitor->ulThroughput < THROUGHPUT_L1_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 0; ++ else if (prPerMonitor->ulThroughput < THROUGHPUT_L2_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 1; ++ else if (prPerMonitor->ulThroughput < THROUGHPUT_L3_THRESHOLD) ++ prPerMonitor->u4TarPerfLevel = 2; ++ else ++ prPerMonitor->u4TarPerfLevel = 3; ++ if (prPerMonitor->u4TarPerfLevel != prPerMonitor->u4CurrPerfLevel) { ++ if (0 == prPerMonitor->u4TarPerfLevel) { ++ /*cancel CPU performance mode request*/ ++ kalPerMonStop(prGlueInfo); ++ } else{ ++ DBGLOG(SW4, TRACE, "throughput:%ld bps\n", prPerMonitor->ulThroughput); ++ /*adjust CPU core number to prPerMonitor->u4TarPerfLevel+1*/ ++ kalBoostCpu(prPerMonitor->u4TarPerfLevel+1); ++ /*start the timer again to make sure we can cancel performance mode request in the end*/ ++ cnmTimerStartTimer(prGlueInfo->prAdapter, ++ &prPerMonitor->rPerfMonTimer, ++ prPerMonitor->u4UpdatePeriod); ++ } ++ } ++ prPerMonitor->u4CurrPerfLevel = prPerMonitor->u4TarPerfLevel; ++ DBGLOG(SW4, TRACE, "exit kalPerMonHandler\n"); ++} ++ ++INT32 __weak kalBoostCpu(UINT_32 core_num) ++{ ++ DBGLOG(SW4, WARN, "enter weak kalBoostCpu, core_num:%d\n", core_num); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c +new file mode 100644 +index 000000000000..945a6c03978b +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c +@@ -0,0 +1,4672 @@ ++/* ++** Id: @(#) gl_p2p.c@@ ++*/ ++ ++/*! \file gl_p2p.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_p2p.c ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 17 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** FPB from ALPS.JB to phase 2 release. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 01 09 2012 terry.wu ++ * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork ++ * cfg80211 integration for p2p network. ++ * ++ * 12 19 2011 terry.wu ++ * [WCXRP00001142] [Wi-Fi] [P2P Driver] XOR local admin bit to generate p2p net device MAC ++ * XOR local administrated bit to generate net device MAC of p2p network. ++ * ++ * 12 02 2011 yuche.tsai ++ * NULL ++ * Fix possible KE when unload p2p. ++ * ++ * 11 24 2011 yuche.tsai ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 16 2011 yuche.tsai ++ * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. ++ * Avoid using work thread in set p2p multicast address callback. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix default device name issue. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 11 07 2011 yuche.tsai ++ * NULL ++ * [ALPS 00087243] KE in worker thread. ++ * The multicast address list is scheduled in worker thread. ++ * Before the worker thread is excuted, if P2P is unloaded, a KE may occur. ++ * ++ * 10 26 2011 terry.wu ++ * [WCXRP00001066] [MT6620 Wi-Fi] [P2P Driver] Fix P2P Oid Issue ++ * Fix some P2P OID functions didn't raise its flag "fgIsP2pOid" issue. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * . ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * Support Channel Query. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 26 2011 yuche.tsai ++ * NULL ++ * Fix bug of parsing secondary device list type issue. ++ * ++ * 08 24 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Abort. ++ * ++ * 08 23 2011 yuche.tsai ++ * NULL ++ * Fix multicast address list issue of P2P. ++ * ++ * 08 22 2011 chinglan.wang ++ * NULL ++ * Fix invitation indication bug.. ++ * ++ * 08 16 2011 cp.wu ++ * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence ++ * auto channel decision for 2.4GHz hot spot mode ++ * ++ * 08 16 2011 chinglan.wang ++ * NULL ++ * Add the group id information in the invitation indication. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 08 05 2011 yuche.tsai ++ * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. ++ * Add Password ID check for quick connection. ++ * Also modify some connection policy. ++ * ++ * 07 18 2011 chinglan.wang ++ * NULL ++ * Add IOC_P2P_GO_WSC_IE (p2p capability). ++ * ++ * 06 14 2011 yuche.tsai ++ * NULL ++ * Add compile flag to disable persistent group support. ++ * ++ * 05 04 2011 chinglan.wang ++ * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver ++ * . ++ * ++ * 05 02 2011 yuche.tsai ++ * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. ++ * Clear formation flag after formation timeout. ++ * ++ * 04 22 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * . ++ * ++ * 04 21 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * 1. Revise P2P power mode setting. ++ * 2. Revise fast-PS for concurrent ++ * ++ * 04 19 2011 wh.su ++ * NULL ++ * Adding length check before doing WPA RSN IE parsing for scan results indicate. ++ * ++ * 04 14 2011 yuche.tsai ++ * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. ++ * Connection flow refine for Sigma test. ++ * ++ * 04 08 2011 yuche.tsai ++ * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. ++ * Add device discoverability support. ++ * ++ * 04 08 2011 george.huang ++ * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode ++ * separate settings of P2P and AIS ++ * ++ * 04 07 2011 terry.wu ++ * [WCXRP00000619] [MT6620 Wi-Fi][Driver] fix kernel panic may occur when removing wlan ++ * Fix kernel panic may occur when removing wlan driver. ++ * ++ * 03 31 2011 wh.su ++ * [WCXRP00000614] [MT6620 Wi-Fi][Driver] P2P: Update beacon content while setting WSC IE ++ * Update the wsc ie to beacon content. ++ * ++ * 03 25 2011 wh.su ++ * NULL ++ * add the sample code for set power mode and get power mode. ++ * ++ * 03 25 2011 yuche.tsai ++ * NULL ++ * Improve some error handleing. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 22 2011 yuche.tsai ++ * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. ++ * Modify formation policy. ++ * ++ * 03 22 2011 yuche.tsai ++ * NULL ++ * Modify formation policy setting. ++ * ++ * 03 18 2011 yuche.tsai ++ * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow ++ * Modify connection flow after Group Formation Complete, or device connect to a GO. ++ * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. ++ * ++ * 03 15 2011 wh.su ++ * [WCXRP00000563] [MT6620 Wi-Fi] [P2P] Set local config method while set password Id ready ++ * set lccal config method method while set password Id ready. ++ * ++ * 03 15 2011 yuche.tsai ++ * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue ++ * Fix some configure method issue. ++ * ++ * 03 15 2011 jeffrey.chang ++ * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM ++ * refine queue_select function ++ * ++ * 03 13 2011 wh.su ++ * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done ++ * add code for avoid compiling warning. ++ * ++ * 03 10 2011 yuche.tsai ++ * NULL ++ * Add P2P API. ++ * ++ * 03 10 2011 terry.wu ++ * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration ++ * Remove unnecessary assert and message. ++ * ++ * 03 08 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * support the power save related p2p setting. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify P2P's netdevice functions to support multiple H/W queues ++ * ++ * 03 03 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * for get request, the buffer length to be copied is header + payload. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add code to let the beacon and probe response for Auto GO WSC . ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * add a missed break. ++ * ++ * 03 01 2011 yuche.tsai ++ * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation ++ * Update channel issue when doing GO formation.. ++ * ++ * 02 25 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * add the Operation channel setting. ++ * ++ * 02 23 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * fixed the set int ioctl set index and value map to driver issue. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int from supplicant, and can used to set the p2p parameters ++ * ++ * 02 21 2011 terry.wu ++ * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P ++ * Clean P2P scan list while removing P2P. ++ * ++ * 02 18 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * fixed the ioctl setting that index not map to spec defined config method. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE ++ * append the WSC IE config method attribute at provision discovery request. ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * modify the structure pointer for set WSC IE. ++ * ++ * 02 16 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * fixed the probe request send out without WSC IE issue (at P2P). ++ * ++ * 02 09 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * fix typo ++ * ++ * 02 09 2011 yuche.tsai ++ * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. ++ * Add Support for MLME deauthentication for Hot-Spot. ++ * ++ * 01 25 2011 terry.wu ++ * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter ++ * Add a new module parameter to indicate current runnig mode, P2P or AP. ++ * ++ * 01 12 2011 yuche.tsai ++ * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue ++ * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. ++ * 2. Call cnmP2pIsPermit() before active P2P network. ++ * 3. Add channel selection support for AP mode. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() ++ * ++ * 12 08 2010 yuche.tsai ++ * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in ++ * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 17 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx ++ * lowest rate at wlan table for normal operation ++ * fixed some ASSERT check. ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 10 2010 george.huang ++ * NULL ++ * update iwpriv LP related ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at win XP. ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add netdev_ops(NDO) for linux kernel 2.6.31 or greater ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 20 2010 cp.wu ++ * NULL ++ * correct typo. ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Invert Connection request provision status parameter. ++ * ++ * 08 19 2010 cp.wu ++ * NULL ++ * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. ++ * ++ * 08 18 2010 cp.wu ++ * NULL ++ * modify pwp ioctls attribution by removing FIXED_SIZE. ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * correct p2p net device registration with NULL pointer access issue. ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * add subroutines for P2P to set multicast list. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add wext handlers to link P2P set PS profile/ network address function (TBD) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * follow-up with ioctl interface update for Wi-Fi Direct application ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * add basic support for ioctl of getting scan result. (only address and SSID are reporterd though) ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * surpress compilation warning. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 23 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * p2p interface revised to be sync. with HAL ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement private io controls for Wi-Fi Direct ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * 1) add timeout handler mechanism for pending command packets ++ * 2) add p2p add/removal key ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement wireless extension ioctls in iw_handler form. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "gl_p2p_os.h" ++#include "gl_p2p_ioctl.h" ++#include "gl_vendor.h" ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define ARGV_MAX_NUM (4) ++ ++/*For CFG80211 - wiphy parameters*/ ++#define MAX_SCAN_LIST_NUM (1) ++#define MAX_SCAN_IE_LEN (512) ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++static struct cfg80211_ops mtk_p2p_ops = { ++ .change_virtual_intf = mtk_p2p_cfg80211_change_iface, /* 1st */ ++ .change_bss = mtk_p2p_cfg80211_change_bss, ++ .scan = mtk_p2p_cfg80211_scan, ++ .remain_on_channel = mtk_p2p_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = mtk_p2p_cfg80211_mgmt_tx, ++ .connect = mtk_p2p_cfg80211_connect, ++ .disconnect = mtk_p2p_cfg80211_disconnect, ++ .deauth = mtk_p2p_cfg80211_deauth, ++ .disassoc = mtk_p2p_cfg80211_disassoc, ++ .start_ap = mtk_p2p_cfg80211_start_ap, ++ .change_beacon = mtk_p2p_cfg80211_change_beacon, ++ .stop_ap = mtk_p2p_cfg80211_stop_ap, ++ .set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params, ++ .del_station = mtk_p2p_cfg80211_del_station, ++ .set_monitor_channel = mtk_p2p_cfg80211_set_channel, ++ .set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask, ++ .mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register, ++ .get_station = mtk_p2p_cfg80211_get_station, ++ .add_key = mtk_p2p_cfg80211_add_key, ++ .get_key = mtk_p2p_cfg80211_get_key, ++ .del_key = mtk_p2p_cfg80211_del_key, ++ .set_default_key = mtk_p2p_cfg80211_set_default_key, ++ .join_ibss = mtk_p2p_cfg80211_join_ibss, ++ .leave_ibss = mtk_p2p_cfg80211_leave_ibss, ++ .set_tx_power = mtk_p2p_cfg80211_set_txpower, ++ .get_tx_power = mtk_p2p_cfg80211_get_txpower, ++ .set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt, ++#ifdef CONFIG_NL80211_TESTMODE ++ .testmode_cmd = mtk_p2p_cfg80211_testmode_cmd, ++#endif ++}; ++ ++static const struct wiphy_vendor_command mtk_p2p_vendor_ops[] = { ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_get_channel_list ++ }, ++ { ++ { ++ .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE ++ }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = mtk_cfg80211_vendor_set_country_code ++ }, ++}; ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++ mtk_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++#endif ++ ++/* the legacy wireless extension stuff */ ++static const iw_handler rP2PIwStandardHandler[] = { ++ [SIOCGIWPRIV - SIOCIWFIRST] = mtk_p2p_wext_get_priv, ++ [SIOCGIWSCAN - SIOCIWFIRST] = mtk_p2p_wext_discovery_results, ++ [SIOCSIWESSID - SIOCIWFIRST] = mtk_p2p_wext_reconnect, ++ [SIOCSIWAUTH - SIOCIWFIRST] = mtk_p2p_wext_set_auth, ++ [SIOCSIWENCODEEXT - SIOCIWFIRST] = mtk_p2p_wext_set_key, ++ [SIOCSIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_set_powermode, ++ [SIOCGIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_get_powermode, ++ [SIOCSIWTXPOW - SIOCIWFIRST] = mtk_p2p_wext_set_txpow, ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ [SIOCGIWSTATS - SIOCIWFIRST] = mtk_p2p_wext_get_rssi, ++#endif ++ [SIOCSIWMLME - SIOCIWFIRST] = mtk_p2p_wext_mlme_handler, ++}; ++ ++static const iw_handler rP2PIwPrivHandler[] = { ++ [IOC_P2P_CFG_DEVICE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_local_dev_info, ++ [IOC_P2P_PROVISION_COMPLETE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_provision_complete, ++ [IOC_P2P_START_STOP_DISCOVERY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_start_stop_discovery, ++ [IOC_P2P_DISCOVERY_RESULTS - SIOCIWFIRSTPRIV] = mtk_p2p_wext_discovery_results, ++ [IOC_P2P_WSC_BEACON_PROBE_RSP_IE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_wsc_ie, ++ [IOC_P2P_CONNECT_DISCONNECT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_connect_disconnect, ++ [IOC_P2P_PASSWORD_READY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_password_ready, ++/* [IOC_P2P_SET_PWR_MGMT_PARAM - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_pm_param, */ ++ [IOC_P2P_SET_INT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_int, ++ [IOC_P2P_GET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_get_struct, ++ [IOC_P2P_SET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_struct, ++ [IOC_P2P_GET_REQ_DEVICE_INFO - SIOCIWFIRSTPRIV] = mtk_p2p_wext_request_dev_info, ++}; ++ ++static const struct iw_priv_args rP2PIwPrivTable[] = { ++ { ++ .cmd = IOC_P2P_CFG_DEVICE, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CFG_DEVICE_TYPE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_CFG_DEVICE"} ++ , ++ { ++ .cmd = IOC_P2P_START_STOP_DISCOVERY, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_REQ_DEVICE_TYPE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_DISCOVERY"} ++ , ++ { ++ .cmd = IOC_P2P_DISCOVERY_RESULTS, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_RESULT"} ++ , ++ { ++ .cmd = IOC_P2P_WSC_BEACON_PROBE_RSP_IE, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_HOSTAPD_PARAM), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_WSC_IE"} ++ , ++ { ++ .cmd = IOC_P2P_CONNECT_DISCONNECT, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CONNECT_DEVICE), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_CONNECT"} ++ , ++ { ++ .cmd = IOC_P2P_PASSWORD_READY, ++ .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_PASSWORD_READY), ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_PASSWD_RDY"} ++ , ++ { ++ .cmd = IOC_P2P_GET_STRUCT, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = 256, ++ .name = "P2P_GET_STRUCT"} ++ , ++ { ++ .cmd = IOC_P2P_SET_STRUCT, ++ .set_args = 256, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "P2P_SET_STRUCT"} ++ , ++ { ++ .cmd = IOC_P2P_GET_REQ_DEVICE_INFO, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_DEVICE_REQ), ++ .name = "P2P_GET_REQDEV"} ++ , ++ { ++ /* SET STRUCT sub-ioctls commands */ ++ .cmd = PRIV_CMD_OID, ++ .set_args = 256, ++ .get_args = IW_PRIV_TYPE_NONE, ++ .name = "set_oid"} ++ , ++ { ++ /* GET STRUCT sub-ioctls commands */ ++ .cmd = PRIV_CMD_OID, ++ .set_args = IW_PRIV_TYPE_NONE, ++ .get_args = 256, ++ .name = "get_oid"} ++}; ++ ++const struct iw_handler_def mtk_p2p_wext_handler_def = { ++ .num_standard = (__u16) sizeof(rP2PIwStandardHandler) / sizeof(iw_handler), ++ .num_private = (__u16) sizeof(rP2PIwPrivHandler) / sizeof(iw_handler), ++ .num_private_args = (__u16) sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args), ++ .standard = rP2PIwStandardHandler, ++ .private = rP2PIwPrivHandler, ++ .private_args = rP2PIwPrivTable, ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ .get_wireless_stats = mtk_p2p_wext_get_wireless_stats, ++#else ++ .get_wireless_stats = NULL, ++#endif ++}; ++ ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support p2p_wowlan_support = { ++ .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, ++}; ++#endif ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* for IE Searching */ ++extern BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++extern BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++/* Net Device Hooks */ ++static int p2pOpen(IN struct net_device *prDev); ++ ++static int p2pStop(IN struct net_device *prDev); ++ ++static struct net_device_stats *p2pGetStats(IN struct net_device *prDev); ++ ++static void p2pSetMulticastList(IN struct net_device *prDev); ++ ++static int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev); ++ ++static int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd); ++ ++static int p2pSetMACAddress(IN struct net_device *prDev, void *addr); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Override the implementation of select queue ++* ++* \param[in] dev Pointer to struct net_device ++* \param[in] skb Pointer to struct skb_buff ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++unsigned int _p2p_cfg80211_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp = 0; ++ ++ /* skb->priority values from 256->263 are magic values ++ * directly indicate a specific 802.1d priority. This is ++ * to allow 802.1d priority to be passed directly in from ++ * tags ++ */ ++ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ } ++ return dscp >> 5; ++} ++ ++static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++ ++static UINT_16 p2pSelectQueue(struct net_device *dev, struct sk_buff *skb, ++ struct net_device *sb_dev, ++ select_queue_fallback_t fallback) ++{ ++ skb->priority = _p2p_cfg80211_classify8021d(skb); ++ ++ return au16Wlan1dToQueueIdx[skb->priority]; ++} ++ ++static struct net_device *g_P2pPrDev; ++static struct wireless_dev *gprP2pWdev; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->init ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \retval 0 The execution of wlanInit succeeds. ++* \retval -ENXIO No such device. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int p2pInit(struct net_device *prDev) ++{ ++/* P_GLUE_INFO_T prGlueInfo; */ ++ if (!prDev) ++ return -ENXIO; ++ ++ DBGLOG(P2P, INFO, "dev name=%s\n", prDev->name); ++ return 0; /* success */ ++} /* end of p2pInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A function for prDev->uninit ++* ++* \param[in] prDev Pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++static void p2pUninit(IN struct net_device *prDev) ++{ ++ ++} /* end of p2pUninit() */ ++ ++static const struct net_device_ops p2p_netdev_ops = { ++ .ndo_open = p2pOpen, ++ .ndo_stop = p2pStop, ++ .ndo_set_mac_address = p2pSetMACAddress, ++ .ndo_set_rx_mode = p2pSetMulticastList, ++ .ndo_get_stats = p2pGetStats, ++ .ndo_do_ioctl = p2pDoIOCTL, ++ .ndo_start_xmit = p2pHardStartXmit, ++ .ndo_select_queue = p2pSelectQueue, ++ .ndo_init = p2pInit, ++ .ndo_uninit = p2pUninit, ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS ++* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_WIFI_VAR_T prWifiVar = NULL; ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ prWifiVar = &(prAdapter->rWifiVar); ++ ++ if (!prWifiVar) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ do { ++ if (prGlueInfo->prP2PInfo == NULL) { ++ /*alloc memory for p2p info */ ++ prGlueInfo->prP2PInfo = kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); ++ prAdapter->prP2pInfo = kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); ++ prWifiVar->prP2PConnSettings = kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T), VIR_MEM_TYPE); ++ prWifiVar->prP2pFsmInfo = kalMemAlloc(sizeof(P2P_FSM_INFO_T), VIR_MEM_TYPE); ++ prWifiVar->prP2pSpecificBssInfo = kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T), VIR_MEM_TYPE); ++ } else { ++ ASSERT(prAdapter->prP2pInfo != NULL); ++ ASSERT(prWifiVar->prP2PConnSettings != NULL); ++ ASSERT(prWifiVar->prP2pFsmInfo != NULL); ++ ASSERT(prWifiVar->prP2pSpecificBssInfo != NULL); ++ } ++ /*MUST set memory to 0 */ ++ if (prGlueInfo->prP2PInfo) ++ kalMemZero(prGlueInfo->prP2PInfo, sizeof(GL_P2P_INFO_T)); ++ if (prAdapter->prP2pInfo) ++ kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); ++ if (prWifiVar->prP2PConnSettings) ++ kalMemZero(prWifiVar->prP2PConnSettings, sizeof(P2P_CONNECTION_SETTINGS_T)); ++ if (prWifiVar->prP2pFsmInfo) ++ kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); ++ if (prWifiVar->prP2pSpecificBssInfo) ++ kalMemZero(prWifiVar->prP2pSpecificBssInfo, sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ } while (FALSE); ++ ++ /* chk if alloc successful or not */ ++ if (prGlueInfo->prP2PInfo && ++ prAdapter->prP2pInfo && ++ prWifiVar->prP2PConnSettings && prWifiVar->prP2pFsmInfo && prWifiVar->prP2pSpecificBssInfo) { ++ return TRUE; ++ } ++ ++ if (prWifiVar->prP2pSpecificBssInfo) { ++ kalMemFree(prWifiVar->prP2pSpecificBssInfo, VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ prWifiVar->prP2pSpecificBssInfo = NULL; ++ } ++ if (prWifiVar->prP2pFsmInfo) { ++ kalMemFree(prWifiVar->prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); ++ ++ prWifiVar->prP2pFsmInfo = NULL; ++ } ++ if (prWifiVar->prP2PConnSettings) { ++ kalMemFree(prWifiVar->prP2PConnSettings, VIR_MEM_TYPE, sizeof(P2P_CONNECTION_SETTINGS_T)); ++ ++ prWifiVar->prP2PConnSettings = NULL; ++ } ++ if (prGlueInfo->prP2PInfo) { ++ kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); ++ ++ prGlueInfo->prP2PInfo = NULL; ++ } ++ if (prAdapter->prP2pInfo) { ++ kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); ++ ++ prAdapter->prP2pInfo = NULL; ++ } ++ return FALSE; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS ++* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ /* free memory after p2p module is ALREADY unregistered */ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { ++ ++ kalMemFree(prGlueInfo->prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); ++ kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings, VIR_MEM_TYPE, ++ sizeof(P2P_CONNECTION_SETTINGS_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); ++ kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo, VIR_MEM_TYPE, ++ sizeof(P2P_SPECIFIC_BSS_INFO_T)); ++ ++ /*Reomve p2p bss scan list */ ++ scanRemoveAllP2pBssDesc(prGlueInfo->prAdapter); ++ ++ /*reset all pointer to NULL */ ++ prGlueInfo->prP2PInfo = NULL; ++ prGlueInfo->prAdapter->prP2pInfo = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo = NULL; ++ prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo = NULL; ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++ ++} ++ ++#if !CFG_SUPPORT_PERSIST_NETDEV ++BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) ++{ ++ BOOLEAN fgDoRegister = FALSE; ++/* BOOLEAN fgRollbackRtnlLock = FALSE; */ ++ BOOLEAN ret; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_UNREGISTERED) { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERING; ++ fgDoRegister = TRUE; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (!fgDoRegister) ++ return TRUE; ++ ++ /* net device initialize */ ++ netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ /* register for net device */ ++ if (register_netdev(prGlueInfo->prP2PInfo->prDevHandler) < 0) { ++ DBGLOG(P2P, WARN, "unable to register netdevice for p2p\n"); ++ ++ free_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ ret = FALSE; ++ } else { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED; ++ ret = TRUE; ++ } ++ return ret; ++} ++ ++BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) ++{ ++ BOOLEAN fgDoUnregister = FALSE; ++/* BOOLEAN fgRollbackRtnlLock = FALSE; */ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED) { ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERING; ++ fgDoUnregister = TRUE; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (!fgDoUnregister) ++ return TRUE; ++ ++ /* prepare for removal */ ++ if (netif_carrier_ok(prGlueInfo->prP2PInfo->prDevHandler)) ++ netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ DBGLOG(P2P, INFO, "P2P unregister_netdev 0x%p\n", prGlueInfo->prP2PInfo->prDevHandler); ++ unregister_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ ++ prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; ++ ++ return TRUE; ++} ++#endif ++ ++BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo) ++{ ++ struct wiphy *prWiphy = NULL; ++ struct wireless_dev *prWdev = NULL; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ struct net_device *prNetDev = NULL; ++#endif ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); ++ if (!prWdev) { ++ DBGLOG(P2P, ERROR, "allocate p2p wireless device fail, no memory\n"); ++ return FALSE; ++ } ++ /* 1. allocate WIPHY */ ++ prWiphy = wiphy_new(&mtk_p2p_ops, sizeof(P_GLUE_INFO_T)); ++ if (!prWiphy) { ++ DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n"); ++ goto free_wdev; ++ } ++ ++ prWiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION); ++ ++ prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; ++ prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; ++ ++ prWiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes; ++ prWiphy->max_remain_on_channel_duration = 5000; ++ prWiphy->cipher_suites = mtk_cipher_suites; ++ prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); ++ prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME; ++ prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; ++ prWiphy->ap_sme_capa = 1; ++ ++ prWiphy->max_scan_ssids = MAX_SCAN_LIST_NUM; ++ prWiphy->max_scan_ie_len = MAX_SCAN_IE_LEN; ++ prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ prWiphy->vendor_commands = mtk_p2p_vendor_ops; ++ prWiphy->n_vendor_commands = sizeof(mtk_p2p_vendor_ops) / sizeof(struct wiphy_vendor_command); ++ ++#ifdef CONFIG_PM ++ prWiphy->wowlan = &p2p_wowlan_support; ++#endif ++ ++ /* 2.1 set priv as pointer to glue structure */ ++ *((P_GLUE_INFO_T *) wiphy_priv(prWiphy)) = prGlueInfo; ++ if (wiphy_register(prWiphy) < 0) { ++ DBGLOG(P2P, ERROR, "fail to register wiphy for p2p\n"); ++ goto free_wiphy; ++ } ++ prWdev->wiphy = prWiphy; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* 3. allocate netdev */ ++ prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), P2P_MODE_INF_NAME, NET_NAME_PREDICTABLE, ++ ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prNetDev) { ++ DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); ++ goto unregister_wiphy; ++ } ++ ++ /* 4. setup netdev */ ++ /* 4.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = prGlueInfo; ++ ++ /* 4.2 fill hardware address */ ++ /* COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] ^= 0x2; // change to local administrated address ++ memcpy(prGlueInfo->prP2PInfo->prDevHandler->dev_addr, rMacAddr, ETH_ALEN); ++ memcpy(prGlueInfo->prP2PInfo->prDevHandler->perm_addr, ++ prGlueInfo->prP2PInfo->prDevHandler->dev_addr, ETH_ALEN);*/ ++ ++ /* 4.3 register callback functions */ ++ prNetDev->netdev_ops = &p2p_netdev_ops; ++ /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def;*/ ++ ++ prNetDev->ieee80211_ptr = prWdev; ++ prWdev->netdev = prNetDev; ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prNetDev->features = NETIF_F_IP_CSUM; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ /* net device initialize */ ++ netif_carrier_off(prNetDev); ++ netif_tx_stop_all_queues(prNetDev); ++ ++ /* register for net device */ ++ if (register_netdev(prNetDev) < 0) { ++ DBGLOG(P2P, ERROR, "unable to register netdevice for p2p\n"); ++ free_netdev(prNetDev); ++ goto unregister_wiphy; ++ } ++#endif ++ gprP2pWdev = prWdev; ++ return TRUE; ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++unregister_wiphy: ++ wiphy_unregister(prWiphy); ++#endif ++free_wiphy: ++ wiphy_free(prWiphy); ++free_wdev: ++ kfree(prWdev); ++#endif ++ return FALSE; ++} ++ ++void glP2pDestroyWirelessDevice(VOID) ++{ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#if CFG_SUPPORT_PERSIST_NETDEV ++ unregister_netdev(gprP2pWdev->netdev); ++ free_netdev(gprP2pWdev->netdev); ++#endif ++ wiphy_unregister(gprP2pWdev->wiphy); ++ wiphy_free(gprP2pWdev->wiphy); ++ kfree(gprP2pWdev); ++ gprP2pWdev = NULL; ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Register for cfg80211 for Wi-Fi Direct ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GL_HIF_INFO_T prHif = NULL; ++ PARAM_MAC_ADDRESS rMacAddr; ++ struct net_device *prDevHandler = NULL; ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ struct device *prDev; ++#endif ++ ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prHif = &prGlueInfo->rHifInfo; ++ ASSERT(prHif); ++ ++ DBGLOG(P2P, TRACE, "glRegisterP2P\n"); ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ if (!gprP2pWdev) { ++ DBGLOG(P2P, ERROR, "gl_p2p, wireless device is not exist\n"); ++ return FALSE; ++ } ++#endif ++ /*0. allocate p2pinfo */ ++ if (!p2PAllocInfo(prGlueInfo)) { ++ DBGLOG(P2P, ERROR, "Allocate memory for p2p FAILED\n"); ++ ASSERT(0); ++ return FALSE; ++ } ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prGlueInfo->prP2PInfo->prWdev = gprP2pWdev; ++ /* 1. fill wiphy parameters */ ++#if MTK_WCN_HIF_SDIO ++ mtk_wcn_hif_sdio_get_dev(prHif->cltCtx, &prDev); ++ if (!prDev) ++ DBGLOG(P2P, WARN, "unable to get struct dev for p2p\n"); ++#else ++ prDev = prHif->Dev; ++#endif ++ /*set_wiphy_dev(gprP2pWdev->wiphy, prDev);*/ ++ if (!prGlueInfo->prAdapter->fgEnable5GBand) ++ gprP2pWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; ++ ++ /* 2 set priv as pointer to glue structure */ ++ *(P_GLUE_INFO_T *) wiphy_priv(gprP2pWdev->wiphy) = prGlueInfo; ++ ++ if (fgIsApMode) { ++ gprP2pWdev->iftype = NL80211_IFTYPE_AP; ++#if CFG_SUPPORT_PERSIST_NETDEV ++ if (kalStrnCmp(gprP2pWdev->netdev->name, AP_MODE_INF_NAME, 2)) { ++ rtnl_lock(); ++ dev_change_name(gprP2pWdev->netdev->name, AP_MODE_INF_NAME); ++ rtnl_unlock(); ++ } ++#endif ++ } else { ++#if CFG_SUPPORT_PERSIST_NETDEV ++ if (kalStrnCmp(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME, 3)) { ++ rtnl_lock(); ++ dev_change_name(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME); ++ rtnl_unlock(); ++ } ++#endif ++ gprP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT; ++ } ++#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ prP2PInfo->prDevHandler = gprP2pWdev->netdev; ++#else /* CFG_SUPPORT_PERSIST_NETDEV */ ++ /* 3. allocate netdev */ ++ prDevHandler = ++ alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); ++ if (!prDevHandler) { ++ DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); ++ return FALSE; ++ } ++ prGlueInfo->prP2PInfo->prDevHandler = prDevHandler; ++ /* 4. setup netdev */ ++ /* 4.1 Point to shared glue structure */ ++ *((P_GLUE_INFO_T *) netdev_priv(prDevHandler)) = prGlueInfo; ++ ++ /* 4.2 fill hardware address */ ++ COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); ++ rMacAddr[0] ^= 0x2; /* change to local administrated address */ ++ ether_addr_copy(prDevHandler->dev_addr, rMacAddr); ++ ether_addr_copy(prDevHandler->perm_addr, prDevHandler->dev_addr); ++ ++ /* 4.3 register callback functions */ ++ prDevHandler->netdev_ops = &p2p_netdev_ops; ++ /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; */ ++ ++#if (MTK_WCN_HIF_SDIO == 0) ++ SET_NETDEV_DEV(prDevHandler, prHif->Dev); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ prDevHandler->ieee80211_ptr = gprP2pWdev; ++ gprP2pWdev->netdev = prDevHandler; ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ prDevHandler->features = NETIF_F_IP_CSUM; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++#endif /* CFG_SUPPORT_PERSIST_NETDEV */ ++ ++ /* 5. set p2p net device register state */ ++ prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; ++ ++ /* 6. setup running mode */ ++ prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = fgIsApMode; ++ ++ /* 7. finish */ ++ p2pFsmInit(prAdapter); ++ ++ p2pFuncInitConnectionSettings(prAdapter, prAdapter->rWifiVar.prP2PConnSettings); ++ ++ /* Active network too early would cause HW not able to sleep. ++ * Defer the network active time. ++ */ ++/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ ++ ++ return TRUE; ++} /* end of glRegisterP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Unregister Net Device for Wi-Fi Direct ++* ++* \param[in] prGlueInfo Pointer to glue info ++* ++* \return TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ /* normal flow: this func will called first before wlanRemove, and it can do fsmUninit/deactivateNetwork ++ gracefully. */ ++ /* when reset: because tx_thread with fw has stopped, so it can't do these job and the recovery will be ++ dependent on chip system reset. */ ++ /* if so, just skip it by flag GLUE_FLAG_HALT(warning: when tx_thread was stop, this flag was not cleared, ++ and NEED TO KEEP IT NOT CLEARED!). */ ++ if (!(prGlueInfo->ulFlag & GLUE_FLAG_HALT)) { ++ p2pFsmUninit(prGlueInfo->prAdapter); ++ nicDeactivateNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); ++ } ++#if CFG_SUPPORT_PERSIST_NETDEV ++ dev_close(prGlueInfo->prP2PInfo->prDevHandler); ++#else ++ free_netdev(prGlueInfo->prP2PInfo->prDevHandler); ++ prGlueInfo->prP2PInfo->prDevHandler = NULL; ++#endif ++ /* Free p2p memory */ ++ if (!p2PFreeInfo(prGlueInfo)) { ++ DBGLOG(P2P, ERROR, "Free memory for p2p FAILED\n"); ++ ASSERT(0); ++ return FALSE; ++ } ++ return TRUE; ++} /* end of glUnregisterP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for stop p2p fsm immediate ++ * ++ * \param[in] prGlueInfo Pointer to struct P_GLUE_INFO_T. ++ * ++ * \retval TRUE The execution succeeds. ++ * \retval FALSE The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo) ++{ ++/* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ ++ ASSERT(prGlueInfo); ++ ++/* prAdapter = prGlueInfo->prAdapter; */ ++/* ASSERT(prAdapter); */ ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); ++ ++#if 0 ++ /* 2. switch P2P-FSM off */ ++ /* 2.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ DBGLOG(P2P, ERROR, "Allocate for p2p mesasage FAILED\n"); ++ /* return -ENOMEM; */ ++ } ++ ++ /* 2.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = FALSE; ++ ++ /* 2.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_UNBUF); ++ ++#endif ++ ++ /* 3. stop queue and turn off carrier */ ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ return TRUE; ++} /* end of p2pStop() */ ++ ++/* Net Device Hooks */ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device open (ifup) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int p2pOpen(IN struct net_device *prDev) ++{ ++/* P_GLUE_INFO_T prGlueInfo = NULL; */ ++/* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ ++ ASSERT(prDev); ++ ++#if 0 /* Move after device name set. (mtk_p2p_set_local_dev_info) */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* 1. switch P2P-FSM on */ ++ /* 1.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = TRUE; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++ /* 2. carrier on & start TX queue */ ++ netif_carrier_on(prDev); ++ netif_tx_start_all_queues(prDev); ++ ++ return 0; /* success */ ++} /* end of p2pOpen() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A function for net_device stop (ifdown) ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \retval 0 The execution succeeds. ++ * \retval < 0 The execution failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++static int p2pStop(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ /* P_ADAPTER_T prAdapter = NULL; */ ++/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ASSERT(prGlueP2pInfo); ++ ++ /* CFG80211 down */ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueP2pInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueP2pInfo->prScanRequest; ++ prGlueP2pInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ if (prScanRequest) ++ cfg80211_scan_done(prScanRequest, &info); ++#if 0 ++ ++ /* 1. stop TX queue */ ++ netif_tx_stop_all_queues(prDev); ++ ++ /* 2. switch P2P-FSM off */ ++ /* 2.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 2.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = FALSE; ++ ++ /* 2.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ /* 3. stop queue and turn off carrier */ ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; ++ ++ netif_tx_stop_all_queues(prDev); ++ if (netif_carrier_ok(prDev)) ++ netif_carrier_off(prDev); ++ ++ return 0; ++} /* end of p2pStop() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A method of struct net_device, to get the network interface statistical ++ * information. ++ * ++ * Whenever an application needs to get statistics for the interface, this method ++ * is called. This happens, for example, when ifconfig or netstat -i is run. ++ * ++ * \param[in] prDev Pointer to struct net_device. ++ * ++ * \return net_device_stats buffer pointer. ++ */ ++/*----------------------------------------------------------------------------*/ ++struct net_device_stats *p2pGetStats(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++#if CFG_SUPPORT_PERSIST_NETDEV ++ /* @FIXME */ ++ /* prDev->stats.rx_packets = 0; */ ++ /* prDev->stats.tx_packets = 0; */ ++ prDev->stats.tx_errors = 0; ++ prDev->stats.rx_errors = 0; ++ /* prDev->stats.rx_bytes = 0; */ ++ /* prDev->stats.tx_bytes = 0; */ ++ prDev->stats.multicast = 0; ++ ++ return &prDev->stats; ++ ++#else ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_packets = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.tx_packets = 0; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_errors = 0; ++ prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes = 0; */ ++ /* prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; */ ++ prGlueInfo->prP2PInfo->rNetDevStats.multicast = 0; ++ ++ return &prGlueInfo->prP2PInfo->rNetDevStats; ++#endif ++} /* end of p2pGetStats() */ ++ ++static void p2pSetMulticastList(IN struct net_device *prDev) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ return; ++ } ++ ++ g_P2pPrDev = prDev; ++ ++ /* 4 Mark HALT, notify main thread to finish current job */ ++/* prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_MULTICAST; */ ++ set_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++} /* p2pSetMulticastList */ ++ ++/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange ++ * another workqueue for sleeping. We don't want to block ++ * tx_thread, so we can't let tx_thread to do this */ ++ ++void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo) ++{ ++ if (!prGlueInfo) { ++ DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); ++ return; ++ } ++#if CFG_ENABLE_WIFI_DIRECT ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered) ++ mtk_p2p_wext_set_Multicastlist(prGlueInfo); ++#endif ++} /* end of p2pSetMulticastListWorkQueueWrapper() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief This function is to set multicast list and set rx mode. ++ * ++ * \param[in] prDev Pointer to struct net_device ++ * ++ * \return (none) ++ */ ++/*----------------------------------------------------------------------------*/ ++void mtk_p2p_wext_set_Multicastlist(P_GLUE_INFO_T prGlueInfo) ++{ ++ UINT_32 u4SetInfoLen = 0; ++ struct net_device *prDev = g_P2pPrDev; ++ ++ prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; ++ ++ ASSERT(prDev); ++ ASSERT(prGlueInfo); ++ if (!prDev || !prGlueInfo) { ++ DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); ++ return; ++ } ++ ++ if (prDev->flags & IFF_PROMISC) ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; ++ ++ if (prDev->flags & IFF_BROADCAST) ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; ++ ++ if (prDev->flags & IFF_MULTICAST) { ++ if ((prDev->flags & IFF_ALLMULTI) || ++ (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; ++ } else { ++ prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; ++ } ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { ++ /* Prepare multicast address list */ ++ struct netdev_hw_addr *ha; ++ UINT_32 i = 0; ++ ++ netdev_for_each_mc_addr(ha, prDev) { ++ if (i < MAX_NUM_GROUP_ADDR) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucMCAddrList[i]), ha->addr); ++ i++; ++ } ++ } ++ ++ DBGLOG(P2P, TRACE, "SEt Multicast Address List\n"); ++ ++ if (i >= MAX_NUM_GROUP_ADDR) ++ return; ++ wlanoidSetP2PMulticastList(prGlueInfo->prAdapter, ++ &(prGlueInfo->prP2PInfo->aucMCAddrList[0]), (i * ETH_ALEN), &u4SetInfoLen); ++ ++ } ++ ++} /* end of mtk_p2p_wext_set_Multicastlist */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * * \brief This function is TX entry point of NET DEVICE. ++ * * ++ * * \param[in] prSkb Pointer of the sk_buff to be sent ++ * * \param[in] prDev Pointer to struct net_device ++ * * ++ * * \retval NETDEV_TX_OK - on success. ++ * * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. ++ * */ ++/*----------------------------------------------------------------------------*/ ++int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) ++{ ++ P_QUE_ENTRY_T prQueueEntry = NULL; ++ P_QUE_T prTxQueue = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_16 u2QueueIdx = 0; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(prSkb); ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prGlueInfo->u8SkbToDriver++; ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ DBGLOG(P2P, ERROR, "GLUE_FLAG_HALT skip tx\n"); ++ prGlueInfo->u8SkbFreed++; ++ dev_kfree_skb(prSkb); ++ return NETDEV_TX_OK; ++ } ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ kalMetProfilingStart(prGlueInfo, prSkb); ++#endif ++ ++ /* mark as P2P packets */ ++ GLUE_SET_PKT_FLAG_P2P(prSkb); ++#if CFG_ENABLE_PKT_LIFETIME_PROFILE ++ GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); ++#endif ++ ++ STATS_TX_TIME_ARRIVE(prSkb); ++ prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); ++ prTxQueue = &prGlueInfo->rTxQueue; ++ ++ if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { ++ ++ u2QueueIdx = skb_get_queue_mapping(prSkb); ++ ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); ++ ++ if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { ++ DBGLOG(P2P, ERROR, "Incorrect queue index, skip this frame\n"); ++ prGlueInfo->u8SkbFreed++; ++ dev_kfree_skb(prSkb); ++ return NETDEV_TX_OK; ++ } ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); ++ ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); ++ GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); ++ ++ if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx] >= ++ CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { ++ DBGLOG(TX, INFO, "netif_stop_subqueue for p2p0, Queue len: %d\n", ++ prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); ++ netif_stop_subqueue(prDev, u2QueueIdx); ++ } ++ } else { ++ GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); ++ } ++ ++ kalSetEvent(prGlueInfo); ++ ++ /* Statistic usage. */ ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes += prSkb->len; ++ prGlueInfo->prP2PInfo->rNetDevStats.tx_packets++; ++ /* prDev->stats.tx_packets++; */ ++ kalPerMonStart(prGlueInfo); ++ return NETDEV_TX_OK; ++} /* end of p2pHardStartXmit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief A method of struct net_device, a primary SOCKET interface to configure ++ * the interface lively. Handle an ioctl call on one of our devices. ++ * Everything Linux ioctl specific is done here. Then we pass the contents ++ * of the ifr->data to the request message handler. ++ * ++ * \param[in] prDev Linux kernel netdevice ++ * ++ * \param[in] prIfReq Our private ioctl request structure, typed for the generic ++ * struct ifreq so we can use ptr to function ++ * ++ * \param[in] cmd Command ID ++ * ++ * \retval 0 The IOCTL command is executed successfully. ++ * \retval <0 The execution of IOCTL command is failed. ++ */ ++/*----------------------------------------------------------------------------*/ ++int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ struct iwreq *prIwReq = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ ++ ASSERT(prDev && prIfReq); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ if (!prGlueInfo) { ++ DBGLOG(P2P, ERROR, "prGlueInfo is NULL\n"); ++ return -EFAULT; ++ } ++ ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ DBGLOG(P2P, ERROR, "Adapter is not ready\n"); ++ return -EINVAL; ++ } ++ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case SIOCSIWENCODEEXT: ++ /* Set Encryption Material after 4-way handshaking is done */ ++ if (prIwReq->u.encoding.pointer) { ++ u4ExtraSize = prIwReq->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, prIwReq->u.encoding.pointer, prIwReq->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (prIwReq->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = mtk_p2p_wext_set_key(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCSIWMLME: ++ /* IW_MLME_DISASSOC used for disconnection */ ++ if (prIwReq->u.data.length != sizeof(struct iw_mlme)) { ++ DBGLOG(P2P, WARN, "MLME buffer strange:%d\n", prIwReq->u.data.length); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (!prIwReq->u.data.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, prIwReq->u.data.pointer, sizeof(struct iw_mlme))) ++ ret = -EFAULT; ++ else ++ ret = mtk_p2p_wext_mlme_handler(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCGIWPRIV: ++ /* This ioctl is used to list all IW privilege ioctls */ ++ ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case SIOCGIWSCAN: ++ ret = mtk_p2p_wext_discovery_results(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case SIOCSIWAUTH: ++ ret = mtk_p2p_wext_set_auth(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++ ++ case IOC_P2P_CFG_DEVICE: ++ case IOC_P2P_PROVISION_COMPLETE: ++ case IOC_P2P_START_STOP_DISCOVERY: ++ case IOC_P2P_DISCOVERY_RESULTS: ++ case IOC_P2P_WSC_BEACON_PROBE_RSP_IE: ++ case IOC_P2P_CONNECT_DISCONNECT: ++ case IOC_P2P_PASSWORD_READY: ++ case IOC_P2P_GET_STRUCT: ++ case IOC_P2P_SET_STRUCT: ++ case IOC_P2P_GET_REQ_DEVICE_INFO: ++ ret = ++ rP2PIwPrivHandler[i4Cmd - SIOCIWFIRSTPRIV] (prDev, &rIwReqInfo, &(prIwReq->u), ++ (char *)&(prIwReq->u)); ++ break; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ case SIOCGIWSTATS: ++ ret = mtk_p2p_wext_get_rssi(prDev, &rIwReqInfo, &(prIwReq->u), NULL); ++ break; ++#endif ++ case IOC_GET_PRIVATE_IOCTL_CMD: ++ ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); ++ ++ break; ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} /* end of p2pDoIOCTL() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To report the iw private args table to user space. ++ * ++ * \param[in] prDev Net device requested. ++ * \param[in] info Pointer to iw_request_info. ++ * \param[inout] wrqu Pointer to iwreq_data. ++ * \param[inout] extra ++ * ++ * \retval 0 For success. ++ * \retval -E2BIG For user's buffer size is too small. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_priv(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ UINT_16 u2BufferSize = prData->length; ++ ++ /* Update our private args table size */ ++ prData->length = (__u16)sizeof(rP2PIwPrivTable); ++ if (u2BufferSize < prData->length) ++ return -E2BIG; ++ ++ if (prData->length) { ++ if (copy_to_user(prData->pointer, rP2PIwPrivTable, sizeof(rP2PIwPrivTable))) ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_get_priv() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To indicate P2P-FSM for re-associate to the connecting device ++ * ++ * \param[in] prDev Net device requested. ++ * \param[inout] wrqu Pointer to iwreq_data ++ * ++ * \retval 0 For success. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_reconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_HDR_T prMsgHdr; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_reconnect: P2P Reconnect\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_reconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief MLME command handler ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_mlme *mlme = (struct iw_mlme *)extra; ++ P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_mlme_handler:\n"); ++ ++ switch (mlme->cmd) { ++ case IW_MLME_DISASSOC: ++ prMsgP2PConnAbt = ++ (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ if (!prMsgP2PConnAbt) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, mlme->addr.sa_data); ++ ++ prMsgP2PConnAbt->u2ReasonCode = mlme->reason_code; ++ ++ if (EQUAL_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prP2pBssInfo->aucOwnMacAddr)) { ++ DBGLOG(P2P, TRACE, "P2P Connection Abort:\n"); ++ ++ /* 1.2 fill message */ ++ prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ } else { ++ DBGLOG(P2P, TRACE, "P2P Connection Pause:\n"); ++ ++ /* 1.2 fill message */ ++ } ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_mlme_handler() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_PROVISION_COMPLETE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_MSG_HDR_T prMsgHdr; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ switch (prData->flags) { ++ case P2P_PROVISIONING_SUCCESS: ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ ++ prGlueInfo->prP2PInfo->u4CipherPairwise = IW_AUTH_CIPHER_CCMP; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++ ++ break; ++ ++ case P2P_PROVISIONING_FAIL: ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ ++ return 0; ++} /* end of mtk_p2p_wext_set_provision_complete() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_START_STOP_DISCOVERY) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++#if 0 ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_REQ_DEVICE_TYPE prReqDeviceType = (P_IW_P2P_REQ_DEVICE_TYPE) extra; ++ UINT_8 au4IeBuf[MAX_IE_LENGTH]; ++ P_MSG_HDR_T prMsgHdr; ++ P_MSG_P2P_DEVICE_DISCOVER_T prDiscoverMsg; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ if (prData->flags == P2P_STOP_DISCOVERY) { ++ prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); ++ ++ if (!prMsgHdr) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); ++ } else if (prData->flags == P2P_START_DISCOVERY) { ++ ++ /* retrieve IE for Probe Response */ ++ if (prReqDeviceType->probe_rsp_len > 0) { ++ if (prReqDeviceType->probe_rsp_len <= MAX_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prReqDeviceType->probe_rsp_ie, ++ prReqDeviceType->probe_rsp_len)) { ++ return -EFAULT; ++ } ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prReqDeviceType->probe_rsp_len; ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ /* retrieve IE for Probe Request */ ++ if (prReqDeviceType->probe_req_len > 0) { ++ if (prReqDeviceType->probe_req_len <= MAX_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[1], prReqDeviceType->probe_req_ie, ++ prReqDeviceType->probe_req_len)) { ++ return -EFAULT; ++ } ++ prGlueInfo->prP2PInfo->u2WSCIELen[1] = prReqDeviceType->probe_req_len; ++ } else { ++ return -E2BIG; ++ } ++ } ++ /* update IE for Probe Request */ ++ ++ if (prReqDeviceType->scan_type == P2P_LISTEN) { ++ /* update listening parameter */ ++ ++ /* @TODO: update prConnSettings for Probe Response IE */ ++ } else { ++ /* indicate P2P-FSM with MID_MNY_P2P_DEVICE_DISCOVERY */ ++ prDiscoverMsg = (P_MSG_P2P_DEVICE_DISCOVER_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_DEVICE_DISCOVER_T)); ++ ++ if (!prDiscoverMsg) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ prDiscoverMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; ++ prDiscoverMsg->u4DevDiscoverTime = 0; /* unlimited */ ++ prDiscoverMsg->fgIsSpecificType = TRUE; ++ prDiscoverMsg->rTargetDeviceType.u2CategoryID = ++ *(PUINT_16) (&(prReqDeviceType->pri_device_type[0])); ++ prDiscoverMsg->rTargetDeviceType.u2SubCategoryID = ++ *(PUINT_16) (&(prReqDeviceType->pri_device_type[6])); ++ COPY_MAC_ADDR(prDiscoverMsg->aucTargetDeviceID, aucNullAddr); ++ ++ /* @FIXME: parameter to be refined, where to pass IE buffer ? */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDiscoverMsg, MSG_SEND_METHOD_BUF); ++ } ++ } else { ++ return -EINVAL; ++ } ++#endif ++ ++ return 0; ++} /* end of mtk_p2p_wext_start_stop_discovery() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++#if 0 ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_IOCTL_INVITATION_STRUCT prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) NULL; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ if (prIoctlInvitation->ucReinvoke == 1) { ++ /* TODO: Set Group ID */ ++ p2pFuncSetGroupID(prAdapter, prIoctlInvitation->aucGroupID, prIoctlInvitation->aucSsid, ++ prIoctlInvitation->u4SsidLen); ++ } ++ ++ else { ++ P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationReq = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; ++ ++ /* TODO: Do Invitation. */ ++ prMsgP2PInvitationReq = ++ (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_INVITATION_REQUEST_T)); ++ if (!prMsgP2PInvitationReq) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ i4Status = -ENOMEM; ++ break; ++ } ++ ++ /* 1.2 fill message */ ++ kalMemCopy(prMsgP2PInvitationReq->aucDeviceID, prIoctlInvitation->aucDeviceID, MAC_ADDR_LEN); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationReq, MSG_SEND_METHOD_BUF); ++ ++ } ++ ++ } while (FALSE); ++#endif ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_invitation_request */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_abort(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++#if 0 ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ P_IW_P2P_IOCTL_ABORT_INVITATION prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) NULL; ++ ++ UINT_8 bssid[MAC_ADDR_LEN]; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationAbort = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; ++ ++ prMsgP2PInvitationAbort = ++ (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_INVITATION_REQUEST_T)); ++ ++ if (!prMsgP2PInvitationAbort) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ i4Status = -ENOMEM; ++ break; ++ } ++ ++ /* 1.2 fill message */ ++ kalMemCopy(prMsgP2PInvitationAbort->aucDeviceID, prIoctlInvitationAbort->dev_addr, ++ MAC_ADDR_LEN); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationAbort, MSG_SEND_METHOD_BUF); ++ ++ ++ } while (FALSE); ++#endif ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_invitation_abort */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief To override p2p interface address ++ * ++ * \param[in] prDev Net device requested. ++ * \param[in] addr Pointer to address ++ * ++ * \retval 0 For success. ++ * \retval -E2BIG For user's buffer size is too small. ++ * \retval -EFAULT For fail. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++int p2pSetMACAddress(IN struct net_device *prDev, void *addr) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @FIXME */ ++ return eth_mac_addr(prDev, addr); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher suite ++* ++* \param[in] prDev Net device requested. ++* \param[out] ++* ++* \retval 0 Success. ++* \retval -EINVAL Invalid parameter ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_auth(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_param *prAuth = (struct iw_param *)wrqu; ++ ++ ASSERT(prDev); ++ ASSERT(prAuth); ++ if (FALSE == GLUE_CHK_PR2(prDev, prAuth)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ /* Save information to glue info and process later when ssid is set. */ ++ switch (prAuth->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ prGlueInfo->prP2PInfo->u4CipherPairwise = prAuth->value; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ case IW_AUTH_DROP_UNENCRYPTED: ++ case IW_AUTH_80211_AUTH_ALG: ++ case IW_AUTH_WPA_ENABLED: ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ case IW_AUTH_ROAMING_CONTROL: ++ case IW_AUTH_PRIVACY_INVOKED: ++ default: ++ /* @TODO */ ++ break; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_set_auth() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[out] prIfReq Pointer to ifreq structure, content is copied back to ++* user space buffer in gl_iwpriv_table. ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_key(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int ret = 0; ++ struct iw_encode_ext *prIWEncExt; ++ struct iw_point *prEnc; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ UINT_8 keyStructBuf[100]; ++ P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; ++ P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ do { ++ if (wrqu->encoding.pointer) { ++ u4ExtraSize = wrqu->encoding.length; ++ /*need confirm u4ExtraSize > 0 but is not very large*/ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ /* here should set prExtraBuf default value */ ++ memset(prExtraBuf, 0, u4ExtraSize); ++ if (copy_from_user(prExtraBuf, wrqu->encoding.pointer, wrqu->encoding.length)) { ++ ret = -EFAULT; ++ break; ++ } ++ } else if (wrqu->encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prEnc = &wrqu->encoding; ++ /* here, need confirm (struct iw_encode_ext) < u4ExtraSize */ ++ prIWEncExt = (struct iw_encode_ext *)prExtraBuf; ++ ++ if (GLUE_CHK_PR3(prDev, prEnc, prExtraBuf) != TRUE) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { /* Key Removal */ ++ prRemoveKey->u4Length = sizeof(*prRemoveKey); ++ memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveP2PKey, ++ prRemoveKey, ++ prRemoveKey->u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ ret = -EFAULT; ++ } else { ++ if (prIWEncExt->alg == IW_ENCODE_ALG_CCMP) { ++ /* KeyID */ ++ prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ ((prEnc->flags & IW_ENCODE_INDEX) - 1) : 0; ++ if (prKey->u4KeyIndex <= 3) { ++ /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ ++ /* Tx Key Bit(31) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ prKey->u4KeyIndex |= 0x1UL << 31; ++ ++ /* Pairwise Key Bit(30) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* group key */ ++ } else { ++ /* pairwise key */ ++ prKey->u4KeyIndex |= 0x1UL << 30; ++ } ++ ++ /* Rx SC Bit(29) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ prKey->u4KeyIndex |= 0x1UL << 29; ++ memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, ++ IW_ENCODE_SEQ_MAX_SIZE); ++ } ++ ++ /* BSSID */ ++ memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ ++ prKey->u4KeyLength = prIWEncExt->key_len; ++ prKey->u4Length = ++ ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + ++ prKey->u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddP2PKey, ++ prKey, ++ prKey->u4Length, ++ FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ ret = -EFAULT; ++ } else { ++ ret = -EINVAL; ++ } ++ } else { ++ ret = -EINVAL; ++ } ++ } ++ ++ } while (FALSE); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ ++ return ret; ++} /* end of mtk_p2p_wext_set_key() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief set the p2p gc power mode ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_powermode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ /* printk("set_powermode = %d, value = %d\n", wrqu->power.disabled, wrqu->power.value); */ ++ struct iw_param *prPower = (struct iw_param *)&wrqu->power; ++#if 1 ++ PARAM_POWER_MODE ePowerMode; ++ INT_32 i4PowerValue; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ if (prPower->disabled) { ++ ePowerMode = Param_PowerModeCAM; ++ } else { ++ i4PowerValue = prPower->value; ++#if WIRELESS_EXT < 21 ++ i4PowerValue /= 1000000; ++#endif ++ if (i4PowerValue == 0) { ++ ePowerMode = Param_PowerModeCAM; ++ } else if (i4PowerValue == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (i4PowerValue == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } else { ++ DBGLOG(P2P, ERROR, "%s(): unsupported power management mode value = %d.\n", ++ __func__, prPower->value); ++ ++ return -EINVAL; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief get the p2p gc power mode ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_powermode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ /* printk("mtk_p2p_wext_get_powermode\n"); */ ++ /* wrqu->power.disabled = 0; */ ++ /* wrqu->power.value = 1; */ ++ ++ struct iw_param *prPower = (struct iw_param *)&wrqu->power; ++ PARAM_POWER_MODE ePowerMode = Param_PowerModeMax; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ ++#if 1 ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pPowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), TRUE, FALSE, FALSE, TRUE, &u4BufLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryP2pPowerSaveProfile, &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++ ++ prPower->value = 0; ++ prPower->disabled = 1; ++ ++ if (Param_PowerModeCAM == ePowerMode) { ++ prPower->value = 0; ++ prPower->disabled = 1; ++ } else if (Param_PowerModeMAX_PSP == ePowerMode) { ++ prPower->value = 1; ++ prPower->disabled = 0; ++ } else if (Param_PowerModeFast_PSP == ePowerMode) { ++ prPower->value = 2; ++ prPower->disabled = 0; ++ } ++ ++ prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; ++#if WIRELESS_EXT < 21 ++ prPower->value *= 1000000; ++#endif ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_CFG_DEVICE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_CFG_DEVICE_TYPE prDeviceCfg = (P_IW_P2P_CFG_DEVICE_TYPE) extra; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ /* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; */ ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ ++ /* update connection settings for P2P-FSM */ ++ /* 1. update SSID */ ++ if (prDeviceCfg->ssid_len > ELEM_MAX_LEN_SSID) ++ prConnSettings->ucSSIDLen = ELEM_MAX_LEN_SSID; ++ else ++ prConnSettings->ucSSIDLen = prDeviceCfg->ssid_len; ++ ++ if (copy_from_user(prConnSettings->aucSSID, prDeviceCfg->ssid, prConnSettings->ucSSIDLen)) ++ return -EFAULT; ++ /* 2. update device type (WPS IE) */ ++ kalMemCopy(&(prConnSettings->rPrimaryDevTypeBE), &(prDeviceCfg->pri_device_type), sizeof(DEVICE_TYPE_T)); ++#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT ++ kalMemCopy(&(prConnSettings->arSecondaryDevTypeBE[0]), &(prDeviceCfg->snd_device_type), sizeof(DEVICE_TYPE_T)); ++#endif ++ ++ /* 3. update device name */ ++ if (prDeviceCfg->device_name_len > WPS_ATTRI_MAX_LEN_DEVICE_NAME) ++ prConnSettings->ucDevNameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; ++ else ++ prConnSettings->ucDevNameLen = prDeviceCfg->device_name_len; ++ if (copy_from_user(prConnSettings->aucDevName, prDeviceCfg->device_name, prConnSettings->ucDevNameLen)) ++ return -EFAULT; ++ /* 4. update GO intent */ ++ prConnSettings->ucGoIntent = prDeviceCfg->intend; ++ ++ /* Preferred channel bandwidth */ ++ prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; ++ prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; ++ ++#if 0 ++ /* 1. switch P2P-FSM on */ ++ /* 1.1 allocate for message */ ++ prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ ++ if (!prFuncSwitch) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ /* 1.2 fill message */ ++ prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ prFuncSwitch->fgIsFuncOn = TRUE; ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ return 0; ++} /* end of mtk_p2p_wext_set_local_dev_info() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * \brief I/O Control handler for both ++ * IOC_P2P_START_STOP_DISCOVERY & SIOCGIWSCAN ++ * ++ * \param[in] prDev Net device requested. ++ * \param[inout] wrqu Pointer to iwreq_data ++ * ++ * \retval 0 Success. ++ * \retval -EFAULT Setting parameters to driver fail. ++ * \retval -EOPNOTSUPP Key size not supported. ++ * ++ * \note ++ */ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_discovery_results(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ struct iw_event iwe; ++ char *current_ev = extra; ++ UINT_32 i; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ P_P2P_INFO_T prP2PInfo = (P_P2P_INFO_T) NULL; ++ P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; ++ P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prP2PInfo = prAdapter->prP2pInfo; ++ ++ for (i = 0; i < prP2PInfo->u4DeviceNum; i++) { ++ prTargetResult = &prP2PInfo->arP2pDiscoverResult[i]; ++ ++ /* SIOCGIWAP */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, prTargetResult->aucInterfaceAddr, 6); ++ ++ current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SIOCGIWESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = prTargetResult->u2NameLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, prTargetResult->aucName); ++ ++ /* IWEVGENIE for WPA IE */ ++ if (prTargetResult->u2IELength <= 600 && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++#if CFG_SUPPORT_WPS ++ ++ /* IWEVGENIE for WPS IE */ ++ if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPSIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++#endif ++ ++ /* IWEVGENIE for RSN IE */ ++ if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, ++ prTargetResult->u2IELength, ++ 0x30, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); ++ } ++ ++ /* IOC_P2P_GO_WSC_IE */ ++#if 1 ++ /* device capability */ ++ if (1) { ++ UINT_8 data[40]; ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 9 + sizeof("p2p_cap="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_cap=%02x%02x%02x%02x%c", ++ prTargetResult->ucDeviceCapabilityBitmap, prTargetResult->ucGroupCapabilityBitmap, ++ (UINT_8) prTargetResult->u2ConfigMethod, ++ (UINT_8) (prTargetResult->u2ConfigMethod >> 8), '\0'); ++ current_ev = ++ iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ ++ /* printk("%s\n", data); */ ++ kalMemZero(data, 40); ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 13 + sizeof("p2p_dev_type="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_dev_type=%02x%02x%02x%02x%02x%02x%c", ++ (UINT_8) prTargetResult->rPriDevType.u2CategoryID, ++ (UINT_8) prTargetResult->rPriDevType.u2SubCategoryID, ++ (UINT_8) prTargetResult->arSecDevType[0].u2CategoryID, ++ (UINT_8) prTargetResult->arSecDevType[0].u2SubCategoryID, ++ (UINT_8) prTargetResult->arSecDevType[1].u2CategoryID, ++ (UINT_8) prTargetResult->arSecDevType[1].u2SubCategoryID, '\0'); ++ current_ev = ++ iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ /* printk("%s\n", data); */ ++ ++ kalMemZero(data, 40); ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.flags = 0; ++ iwe.u.data.length = 17 + sizeof("p2p_grp_bssid="); ++ if (iwe.u.data.length > 40) ++ iwe.u.data.length = 40; ++ ++ snprintf(data, iwe.u.data.length, "p2p_grp_bssid= %pM %c", ++ prTargetResult->aucBSSID, '\0'); ++ current_ev = iwe_stream_add_point(info, current_ev, ++ extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); ++ /* printk("%s\n", data); */ ++ ++ } ++#endif ++ } ++ ++ /* Length of data */ ++ wrqu->data.length = (current_ev - extra); ++ wrqu->data.flags = 0; ++ ++ return 0; ++} /* end of mtk_p2p_wext_discovery_results() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_WSC_BEACON_PROBE_RSP_IE) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_HOSTAPD_PARAM prHostapdParam = (P_IW_P2P_HOSTAPD_PARAM) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ if (prHostapdParam->len > 0) { ++ if (prHostapdParam->len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[0], prHostapdParam->data, prHostapdParam->len)) { ++ return -EFAULT; ++ } ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prHostapdParam->data, prHostapdParam->len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[0] = prHostapdParam->len; ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prHostapdParam->len; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); ++ ++ /* @TODO: send message to P2P-FSM */ ++ ++ return 0; ++} /* end of mtk_p2p_wext_wsc_ie() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_CONNECT_DISCONNECT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++/* P_IW_P2P_CONNECT_DEVICE prConnectDevice = (P_IW_P2P_CONNECT_DEVICE)extra; */ ++/* P_MSG_HDR_T prMsgHdr; */ ++/* P_MSG_P2P_CONNECTION_REQUEST_T prMsgP2PConnReq; */ ++/* P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt; */ ++/* UINT_8 aucBCAddr[] = BC_MAC_ADDR; */ ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ if (prData->flags == P2P_CONNECT) { ++#if 0 ++ /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_REQ */ ++ prMsgP2PConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ if (!prMsgP2PConnReq) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnReq, MSG_SEND_METHOD_BUF); ++#endif ++ } else if (prData->flags == P2P_DISCONNECT) { ++#if 0 ++ /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_ABORT */ ++ prMsgP2PConnAbt = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (!prMsgP2PConnAbt) { ++ ASSERT(0); /* Can't trigger P2P FSM */ ++ return -ENOMEM; ++ } ++ ++ COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prConnectDevice->sta_addr); ++ ++ prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); ++#endif ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} /* end of mtk_p2p_wext_connect_disconnect() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_PASSWORD_READY) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_password_ready(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_PASSWORD_READY prPasswordReady = (P_IW_P2P_PASSWORD_READY) extra; ++ P_P2P_CONNECTION_SETTINGS_T prConnSettings; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; ++ ++ /* retrieve IE for Probe Request */ ++ if (prPasswordReady->probe_req_len > 0) { ++ if (prPasswordReady->probe_req_len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[1], prPasswordReady->probe_req_ie, ++ prPasswordReady->probe_req_len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[1] = prPasswordReady->probe_req_len; ++ ++ /* retrieve IE for Probe Response */ ++ if (prPasswordReady->probe_rsp_len > 0) { ++ if (prPasswordReady->probe_rsp_len <= MAX_WSC_IE_LENGTH) { ++ if (copy_from_user ++ (prGlueInfo->prP2PInfo->aucWSCIE[2], prPasswordReady->probe_rsp_ie, ++ prPasswordReady->probe_rsp_len)) { ++ return -EFAULT; ++ } ++ } else { ++ return -E2BIG; ++ } ++ } ++ ++ prGlueInfo->prP2PInfo->u2WSCIELen[2] = prPasswordReady->probe_rsp_len; ++ ++ switch (prPasswordReady->active_config_method) { ++ case 1: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_PUSH_BUTTON; ++ break; ++ case 2: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_KEYPAD; ++ break; ++ case 3: ++ prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_DISPLAY; ++ break; ++ default: ++ break; ++ } ++ ++ prConnSettings->fgIsPasswordIDRdy = TRUE; ++ return 0; ++} /* end of mtk_p2p_wext_password_ready() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_REQ_DEVICE_INFO) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_DEVICE_REQ prDeviceReq = (P_IW_P2P_DEVICE_REQ) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_DEVICE_REQ); ++ ++ /* copy to upper-layer supplied buffer */ ++ kalMemCopy(prDeviceReq->name, prGlueInfo->prP2PInfo->aucConnReqDevName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ prDeviceReq->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; ++ prDeviceReq->name[prDeviceReq->name_len] = '\0'; ++ COPY_MAC_ADDR(prDeviceReq->device_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); ++ prDeviceReq->device_type = prGlueInfo->prP2PInfo->ucConnReqDevType; ++ prDeviceReq->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; ++ prDeviceReq->active_config_method = prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod; ++ ++ return 0; ++} /* end of mtk_p2p_wext_request_dev_info() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_IOCTL_INVITATION_INDICATE prInvIndicate = (P_IW_P2P_IOCTL_INVITATION_INDICATE) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_INDICATE); ++ ++ /* copy to upper-layer supplied buffer */ ++ kalMemCopy(prInvIndicate->dev_name, prGlueInfo->prP2PInfo->aucConnReqDevName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ kalMemCopy(prInvIndicate->group_bssid, prGlueInfo->prP2PInfo->rConnReqGroupAddr, MAC_ADDR_LEN); ++ prInvIndicate->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; ++ prInvIndicate->dev_name[prInvIndicate->name_len] = '\0'; ++ COPY_MAC_ADDR(prInvIndicate->dev_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); ++ prInvIndicate->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; ++ prInvIndicate->operating_channel = prGlueInfo->prP2PInfo->ucOperatingChnl; ++ prInvIndicate->invitation_type = prGlueInfo->prP2PInfo->ucInvitationType; ++ ++ return 0; ++} /* end of mtk_p2p_wext_invitation_indicate() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_invitation_status(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_IOCTL_INVITATION_STATUS prInvStatus = (P_IW_P2P_IOCTL_INVITATION_STATUS) extra; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* specify data length */ ++ wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_STATUS); ++ ++ /* copy to upper-layer supplied buffer */ ++ prInvStatus->status_code = prGlueInfo->prP2PInfo->u4InvStatus; ++ ++ return 0; ++} /* end of mtk_p2p_wext_invitation_status() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief indicate an event to supplicant for device found ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval TRUE Success. ++* \retval FALSE Failure ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_FND"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PDVCFND event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++ return FALSE; ++} /* end of kalP2PIndicateFound() */ ++ ++int ++mtk_p2p_wext_set_network_address(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pNetworkAddress, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++int ++mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++int ++mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ASSERT(prAdapter); ++ ++ /* @TODO: invoke wlan_p2p functions */ ++#if 0 ++ rStatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); ++#endif ++ ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_start_formation(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int i4Status = 0; ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++/* struct iw_point *prData = (struct iw_point*)&wrqu->data; */ ++ P_IW_P2P_IOCTL_START_FORMATION prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) NULL; ++ ++ do { ++ if ((prDev == NULL) || (extra == NULL)) { ++ ASSERT(FALSE); ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) extra; ++ ++ if (prGlueInfo == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++ ++ if (prAdapter == NULL) { ++ i4Status = -EINVAL; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return i4Status; ++ ++} ++ ++/* mtk_p2p_wext_start_formation */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Setting parameters not support. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_int(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 index; ++ INT_32 value; ++ PUINT_32 pu4IntBuf; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; ++ UINT_32 u4Leng; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ /* printk("mtk_p2p_wext_set_int\n"); */ ++ pu4IntBuf = (PUINT_32) extra; ++ ++ if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ prP2pFsmInfo = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo; ++ ++ u4SubCmd = (UINT_32) wrqu->mode; ++ index = pu4IntBuf[1]; ++ value = pu4IntBuf[2]; ++ ++ DBGLOG(P2P, INFO, "set parameter, u4SubCmd=%d idx=%d value=%d\n", (INT_16) u4SubCmd, (INT_16) index, value); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_INT_P2P_SET: ++ switch (index) { ++ case 0: /* Listen CH */ ++ { ++ UINT_8 ucSuggestChnl = 0; ++ ++ prP2pConnSettings->ucListenChnl = value; ++ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ if (rlmFuncFindAvailableChannel ++ (prGlueInfo->prAdapter, value, &ucSuggestChnl, TRUE, TRUE)) { ++ prP2pSpecificBssInfo->ucListenChannel = value; ++ } else { ++ prP2pSpecificBssInfo->ucListenChannel = ucSuggestChnl; ++ } ++ ++ break; ++ } ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, ++ (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, ++ (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ status = ++ mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ prP2pConnSettings->ucOperatingChnl = value; ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ /* prP2pConnSettings->u2LocalConfigMethod; */ ++ break; ++ case 102: /* Sigma P2p reset */ ++ kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ status = ++ mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rOppPsParam); ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, ++ &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_SET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ u4SubCmd = (UINT_32) wrqu->data.flags; ++ ++ kalMemZero(&prGlueInfo->prP2PInfo->aucOidBuf[0], sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEND_SD_RESPONSE: ++ status = mtk_p2p_wext_send_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_SEND_SD_REQUEST: ++ status = mtk_p2p_wext_send_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_TERMINATE_SD_PHASE: ++ status = mtk_p2p_wext_terminate_service_discovery_phase(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_INVITATION: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_INVITATION_STRUCT)) { ++ /* Do nothing */ ++ /* status = mtk_p2p_wext_invitation_request(prDev, info, wrqu, ++ (char *)(prP2PReq->aucBuffer)); */ ++ } ++ break; ++ ++ case P2P_CMD_ID_INVITATION_ABORT: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_ABORT_INVITATION)) { ++ /* Do nothing */ ++ /* status = mtk_p2p_wext_invitation_abort(prDev, info, wrqu, ++ (char *)(prP2PReq->aucBuffer)); */ ++ } ++ break; ++ ++ case P2P_CMD_ID_START_FORMATION: ++ if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_START_FORMATION)) ++ status = mtk_p2p_wext_start_formation(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ break; ++#if CFG_SUPPORT_ANTI_PIRACY ++ case PRIV_SEC_CHECK_OID: ++ if (wrqu->data.length > 256) { ++ status = -EOPNOTSUPP; ++ break; ++ } ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEC_CHECK: ++ status = mtk_p2p_wext_set_sec_check_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ break; ++#endif ++ case PRIV_CMD_P2P_VERSION: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ ++ if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) ++ DBGLOG(P2P, INFO, "extra buffer is valid\n"); ++ else ++ DBGLOG(P2P, INFO, "extra 0x%p\n", extra); ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_P2P_VERSION: ++ status = mtk_p2p_wext_set_p2p_version(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ int status = 0; ++ UINT_32 u4SubCmd = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; ++ ++ ASSERT(prDev); ++ ASSERT(wrqu); ++ ++ if (!prDev || !wrqu) { ++ DBGLOG(P2P, WARN, "%s(): invalid param(0x%p, 0x%p)\n", __func__, prDev, wrqu); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ u4SubCmd = (UINT_32) wrqu->data.flags; ++ ++ kalMemZero(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_GET_SD_REQUEST: ++ status = mtk_p2p_wext_get_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_GET_SD_RESPONSE: ++ status = mtk_p2p_wext_get_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ ++ case P2P_CMD_ID_INVITATION_INDICATE: ++ { ++ status = ++ mtk_p2p_wext_invitation_indicate(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ prP2PReq->outBufferLength = wrqu->data.length; ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ case P2P_CMD_ID_INVITATION_STATUS: ++ { ++ status = ++ mtk_p2p_wext_invitation_status(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); ++ prP2PReq->outBufferLength = wrqu->data.length; ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ case P2P_CMD_ID_GET_CH_LIST: ++ { ++ UINT_16 i; ++ UINT_8 NumOfChannel = 50; ++ RF_CHANNEL_INFO_T aucChannelList[50]; ++ UINT_8 ucMaxChannelNum = 50; ++ PUINT_8 pucChnlList = (PUINT_8) prP2PReq->aucBuffer; ++ ++ kalGetChnlList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); ++ if (NumOfChannel > 50) ++ NumOfChannel = 50; ++ prP2PReq->outBufferLength = NumOfChannel; ++ /*here must confirm NumOfChannel < 16, for prP2PReq->aucBuffer 16 byte*/ ++ if (NumOfChannel >= 15) { ++ /*DBGLOG(P2P, ERROR, "channel num > 15\n", __func__);*/ ++ ASSERT(FALSE); ++ } ++ ++ for (i = 0; i < NumOfChannel; i++) { ++#if 0 ++ /* 20120208 frog: modify to avoid clockwork warning. */ ++ prP2PReq->aucBuffer[i] = aucChannelList[i].ucChannelNum; ++#else ++ *pucChnlList = aucChannelList[i].ucChannelNum; ++ pucChnlList++; ++#endif ++ } ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ NumOfChannel + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++ break; ++ } ++ ++ case P2P_CMD_ID_GET_OP_CH: ++ { ++ prP2PReq->inBufferLength = 4; ++ ++ status = wlanoidQueryP2pOpChannel(prGlueInfo->prAdapter, ++ prP2PReq->aucBuffer, ++ prP2PReq->inBufferLength, &prP2PReq->outBufferLength); ++ ++ if (status == 0) { /* WLAN_STATUS_SUCCESS */ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, ++ aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } else { ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ break; ++ } ++ ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ break; ++#if CFG_SUPPORT_ANTI_PIRACY ++ case PRIV_SEC_CHECK_OID: ++ if (wrqu->data.length > 256) { ++ status = -EOPNOTSUPP; ++ break; ++ } ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_SEC_CHECK: ++ status = mtk_p2p_wext_get_sec_check_response(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ break; ++#endif ++ case PRIV_CMD_P2P_VERSION: ++ if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { ++ DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); ++ ++ switch (prP2PReq->u4CmdId) { ++ case P2P_CMD_ID_P2P_VERSION: ++ status = mtk_p2p_wext_get_p2p_version(prDev, info, wrqu, (char *)prP2PReq); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ break; ++ } ++ ++ /* Copy queried data to user. */ ++ if (status == 0) { /* WLAN_STATUS_SUCCESS */ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ ++ else { ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ } ++ ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* getting service discovery request frame from driver ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetP2PSDRequest, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* getting service discovery response frame from driver ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetP2PSDResponse, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ &(prGlueInfo->prP2PInfo->aucOidBuf[0]), ++ u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ return 0; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* sending service discovery request frame ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSendP2PSDRequest, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* sending service discovery response frame ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSendP2PSDResponse, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetSecCheckRequest, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_get_sec_check_response\n"); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidGetSecCheckResponse, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prP2PReq->outBufferLength = u4QueryInfoLen; ++ ++ if (copy_to_user(wrqu->data.pointer, ++ prP2PReq->aucBuffer, u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { ++ DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); ++ return -EIO; ++ } ++ return 0; ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* terminating service discovery phase ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2PTerminateSDPhase, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++ /* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ ++ P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_set_noa_param\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetNoaParam, prNoaParam, /* prP2PReq->aucBuffer, */ ++ sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ ++ FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief P2P Private I/O Control handler for ++* ++* \param[in] prDev Net device requested. ++* \param[inout] wrqu Pointer to iwreq_data ++* ++* \retval 0 Success. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4SetInfoLen; ++/* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ ++ P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_wext_set_oppps_param\n"); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetOppPsParam, prOppPsParam, /* prP2PReq->aucBuffer, */ ++ sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ ++ FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return 0; ++} ++ ++int ++mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ UINT_32 u4SetInfoLen; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSupplicantVersion, ++ prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} ++ ++/* mtk_p2p_wext_set_p2p_version */ ++ ++int ++mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen; ++ P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pVersion, ++ prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} /* mtk_p2p_wext_get_p2p_version */ ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ ++int ++mtk_p2p_wext_get_rssi(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen; ++ struct iw_point *prData = (struct iw_point *)&wrqu->data; ++ UINT_16 u2BufferSize = 0; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rssi; ++ struct iw_statistics *pStats = NULL; ++ ++ ASSERT(prDev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ ++ if (!prGlueInfo) { ++ rStatus = WLAN_STATUS_FAILURE; ++ goto stat_out; ++ } ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &u4QueryInfoLen); ++ ++ u2BufferSize = prData->length; ++ ++ if (u2BufferSize < sizeof(struct iw_statistics)) ++ return -E2BIG; ++ ++ if (copy_to_user(prData->pointer, pStats, sizeof(struct iw_statistics))) ++ rStatus = WLAN_STATUS_FAILURE; ++ ++stat_out: ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ else ++ return rStatus; ++ ++} /* mtk_p2p_wext_get_rssi */ ++ ++struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_statistics *pStats = NULL; ++ INT_32 i4Rssi; ++ UINT_32 bufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) ++ goto stat_out; ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); ++ ++ if (!prDev || !netif_carrier_ok(prDev)) { ++ /* network not connected */ ++ goto stat_out; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &bufLen); ++ ++stat_out: ++ return pStats; ++} /* mtk_p2p_wext_get_wireless_stats */ ++ ++#endif /* CFG_SUPPORT_P2P_RSSI_QUERY */ ++ ++int ++mtk_p2p_wext_set_txpow(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; ++#if 0 ++ P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; ++#endif ++ int i4Ret = 0; ++ ++ ASSERT(prDev); ++ ASSERT(prTxPow); ++ ++ do { ++ if ((!prDev) || (!prTxPow)) { ++ i4Ret = -EINVAL; ++ break; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ if (!prGlueInfo) { ++ i4Ret = -EINVAL; ++ break; ++ } ++ ++ prAdapter = prGlueInfo->prAdapter; ++#if 0 ++ prMsgFuncSwitch = ++ (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_FUNCTION_SWITCH_T)); ++ if (!prMsgFuncSwitch) { ++ ASSERT(0); ++ return -ENOMEM; ++ } ++ ++ prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ ++ if (prTxPow->disabled) { ++ /* Dissolve. */ ++ prMsgFuncSwitch->fgIsFuncOn = FALSE; ++ } else { ++ ++ /* Re-enable function. */ ++ prMsgFuncSwitch->fgIsFuncOn = TRUE; ++ } ++ ++ /* 1.3 send message */ ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); ++#endif ++ ++ } while (FALSE); ++ ++ return i4Ret; ++} /* mtk_p2p_wext_set_txpow */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c +new file mode 100644 +index 000000000000..4d71e0c59b05 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c +@@ -0,0 +1,1935 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_cfg80211.c ++ \brief Main routines of Linux driver interface for Wi-Fi Direct ++ using cfg80211 interface ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_p2p_cfg80211.c ++** ++** 01 30 2013 yuche.tsai ++** [ALPS00455459] [GN_WIFI]??wifi direct??????????? ++** Fix possible race condition under GO mode. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 09 05 2012 wh.su ++** [ALPS00351547] [6577JB][WiFi direct]The 3rd device fail to establish p2p connection with GO sometimes ++** sync with the ICS code. ++** ++** 08 31 2012 yuche.tsai ++** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, ++** one device reboots automatically with KE ++** Fix possible KE when concurrent & disconnect. ++** ++** 08 21 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++** ++** 08 17 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 16 2012 yuche.tsai ++** NULL ++** Fix compile warning. ++** ++** 08 14 2012 yuche.tsai ++** NULL ++** Fix p2p bug find on ALPS.JB trunk. ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Fix compile error for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "config.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "precomp.h" ++#include "gl_cfg80211.h" ++#include "gl_p2p_ioctl.h" ++ ++#ifdef __GNUC__ ++#pragma GCC diagnostic ignored "-Wformat" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++BOOLEAN ++mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, ++ IN enum nl80211_channel_type channel_type, ++ IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Rslt = -EINVAL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ P2P_PARAM_KEY_T rKey; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ kalMemZero(&rKey, sizeof(P2P_PARAM_KEY_T)); ++ ++ rKey.u4KeyIndex = key_index; ++ if (mac_addr) { ++ ether_addr_copy(rKey.arBSSID, mac_addr); ++ if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && ++ (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ } ++ if (rKey.arBSSID[0] != 0xFF) { ++ rKey.u4KeyIndex |= BIT(31); ++ if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || ++ (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) ++ rKey.u4KeyIndex |= BIT(30); ++ } else { ++ rKey.u4KeyIndex |= BIT(31); ++ } ++ } else { ++ rKey.arBSSID[0] = 0xff; ++ rKey.arBSSID[1] = 0xff; ++ rKey.arBSSID[2] = 0xff; ++ rKey.arBSSID[3] = 0xff; ++ rKey.arBSSID[4] = 0xff; ++ rKey.arBSSID[5] = 0xff; ++ rKey.u4KeyIndex |= BIT(31); /* ???? */ ++ } ++ if (params->key) { ++ /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ ++ kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); ++ } ++ rKey.u4KeyLength = params->key_len; ++ rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetAddP2PKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_REMOVE_KEY_T prRemoveKey; ++ INT_32 i4Rslt = -EINVAL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ i4Rslt = 0; ++ return i4Rslt; ++ } ++ ++ kalMemZero(&prRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); ++ if (mac_addr) ++ memcpy(prRemoveKey.arBSSID, mac_addr, PARAM_MAC_ADDR_LEN); ++ prRemoveKey.u4KeyIndex = key_index; ++ prRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveP2PKey, ++ &prRemoveKey, prRemoveKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_SUCCESS) ++ i4Rslt = 0; ++ ++ return i4Rslt; ++} ++ ++int ++mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, ++ struct net_device *netdev, u8 key_index, bool unicast, bool multicast) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_info *sinfo) ++{ ++ INT_32 i4RetRslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ P2P_STATION_INFO_T rP2pStaInfo; ++ ++ ASSERT(wiphy); ++ ++ do { ++ if ((wiphy == NULL) || (ndev == NULL) || (sinfo == NULL) || (mac == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_get_station\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ sinfo->filled = 0; ++ ++ /* Get station information. */ ++ /* 1. Inactive time? */ ++ p2pFuncGetStationInfo(prGlueInfo->prAdapter, (PUINT_8)mac, &rP2pStaInfo); ++ ++ /* Inactive time. */ ++ sinfo->filled |= NL80211_STA_INFO_INACTIVE_TIME; ++ sinfo->inactive_time = rP2pStaInfo.u4InactiveTime; ++ sinfo->generation = prP2pGlueInfo->i4Generation; ++ ++ i4RetRslt = 0; ++ } while (FALSE); ++ ++ return i4RetRslt; ++} ++ ++int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ P_MSG_P2P_SCAN_REQUEST_T prMsgScanRequest = (P_MSG_P2P_SCAN_REQUEST_T) NULL; ++ UINT_32 u4MsgSize = 0, u4Idx = 0; ++ INT_32 i4RetRslt = -EINVAL; ++ P_RF_CHANNEL_INFO_T prRfChannelInfo = (P_RF_CHANNEL_INFO_T) NULL; ++ P_P2P_SSID_STRUCT_T prSsidStruct = (P_P2P_SSID_STRUCT_T) NULL; ++ struct ieee80211_channel *prChannel = NULL; ++ struct cfg80211_ssid *prSsid = NULL; ++ ++ /* [---------Channel---------] [---------SSID---------][---------IE---------] */ ++ DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan\n"); ++ ++ do { ++ if ((wiphy == NULL) || (request == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ if (prP2pGlueInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_scan.\n"); ++ ++ if (prP2pGlueInfo->prScanRequest != NULL) { ++ /* There have been a scan request on-going processing. */ ++ DBGLOG(P2P, TRACE, "There have been a scan request on-going processing.\n"); ++ break; ++ } ++ ++ prP2pGlueInfo->prScanRequest = request; ++ ++ /* Should find out why the n_channels so many? */ ++ if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { ++ request->n_channels = MAXIMUM_OPERATION_CHANNEL_LIST; ++ DBGLOG(P2P, TRACE, "Channel list exceed the maximun support.\n"); ++ } ++ ++ u4MsgSize = sizeof(MSG_P2P_SCAN_REQUEST_T) + ++ (request->n_channels * sizeof(RF_CHANNEL_INFO_T)) + ++ (request->n_ssids * sizeof(PARAM_SSID_T)) + request->ie_len; ++ ++ prMsgScanRequest = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, u4MsgSize); ++ ++ if (prMsgScanRequest == NULL) { ++ ASSERT(FALSE); ++ i4RetRslt = -ENOMEM; ++ prP2pGlueInfo->prScanRequest = NULL; ++ DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan Allocate Mem failed\n"); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "Generating scan request message.\n"); ++ ++ prMsgScanRequest->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; ++ ++ DBGLOG(P2P, INFO, "Requesting channel number:%d.\n", request->n_channels); ++ ++ for (u4Idx = 0; u4Idx < request->n_channels; u4Idx++) { ++ /* Translate Freq from MHz to channel number. */ ++ prRfChannelInfo = &(prMsgScanRequest->arChannelListInfo[u4Idx]); ++ prChannel = request->channels[u4Idx]; ++ ++ prRfChannelInfo->ucChannelNum = nicFreq2ChannelNum(prChannel->center_freq * 1000); ++ DBGLOG(P2P, TRACE, "Scanning Channel:%d, freq: %d\n", ++ prRfChannelInfo->ucChannelNum, prChannel->center_freq); ++ switch (prChannel->band) { ++ case NL80211_BAND_2GHZ: ++ prRfChannelInfo->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prRfChannelInfo->eBand = BAND_5G; ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "UNKNOWN Band info from supplicant\n"); ++ prRfChannelInfo->eBand = BAND_NULL; ++ break; ++ } ++ ++ /* Iteration. */ ++ prRfChannelInfo++; ++ } ++ prMsgScanRequest->u4NumChannel = request->n_channels; ++ ++ DBGLOG(P2P, TRACE, "Finish channel list.\n"); ++ ++ /* SSID */ ++ prSsid = request->ssids; ++ prSsidStruct = (P_P2P_SSID_STRUCT_T) prRfChannelInfo; ++ if (prSsidStruct) { ++ if (request->n_ssids) { ++ ASSERT((ULONG) prSsidStruct == (ULONG)&(prMsgScanRequest->arChannelListInfo[u4Idx])); ++ prMsgScanRequest->prSSID = prSsidStruct; ++ } ++ ++ for (u4Idx = 0; u4Idx < request->n_ssids; u4Idx++) { ++ COPY_SSID(prSsidStruct->aucSsid, ++ prSsidStruct->ucSsidLen, request->ssids->ssid, request->ssids->ssid_len); ++ ++ prSsidStruct++; ++ prSsid++; ++ } ++ ++ prMsgScanRequest->i4SsidNum = request->n_ssids; ++ ++ DBGLOG(P2P, TRACE, "Finish SSID list:%d.\n", request->n_ssids); ++ ++ /* IE BUFFERS */ ++ prMsgScanRequest->pucIEBuf = (PUINT_8) prSsidStruct; ++ if (request->ie_len) { ++ kalMemCopy(prMsgScanRequest->pucIEBuf, request->ie, request->ie_len); ++ prMsgScanRequest->u4IELen = request->ie_len; ++ } ++ } ++ ++ DBGLOG(P2P, TRACE, "Finish IE Buffer.\n"); ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = FALSE; ++#endif ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgScanRequest, MSG_SEND_METHOD_BUF); ++ ++ i4RetRslt = 0; ++ } while (FALSE); ++ ++ return i4RetRslt; ++} /* mtk_p2p_cfg80211_scan */ ++ ++int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_wiphy_params\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (changed & WIPHY_PARAM_RETRY_SHORT) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY short param is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_RETRY_LONG) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY long param is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY fragmentation threshold is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The RETRY RTS threshold is changed.\n"); ++ } ++ ++ if (changed & WIPHY_PARAM_COVERAGE_CLASS) { ++ /* TODO: */ ++ DBGLOG(P2P, TRACE, "The coverage class is changed???\n"); ++ } ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_set_wiphy_params */ ++ ++int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ enum nl80211_tx_power_setting type, int mbm) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ int *dbm) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} ++ ++int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 value; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ if (enabled) ++ value = 2; ++ else ++ value = 0; ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_power_mgmt ps=%d.\n", enabled); ++ ++ /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ return 0; ++} ++ ++/* &&&&&&&&&&&&&&&&&&&&&&&&&& Add for ICS Wi-Fi Direct Support. &&&&&&&&&&&&&&&&&&&&&&& */ ++int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ /* P_IE_SSID_T prSsidIE = (P_IE_SSID_T)NULL; */ ++ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct cfg80211_chan_def *chandef = &wdev->preset_chandef; ++ ++ do { ++ if ((wiphy == NULL) || (settings == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_ap.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++#if 1 ++ mtk_p2p_cfg80211_set_channel(wiphy, chandef); ++#else ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->ucOperatingChnl = ++ (chandef->chan->center_freq - 2407) / 5; ++ prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->eBand = BAND_2G4; ++#endif ++ ++ prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_BEACON_UPDATE_T) + ++ settings->beacon.head_len + ++ settings->beacon.tail_len)); ++ ++ if (prP2pBcnUpdateMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; ++ pucBuffer = prP2pBcnUpdateMsg->aucBuffer; ++ ++ if (settings->beacon.head_len != 0) { ++ kalMemCopy(pucBuffer, settings->beacon.head, settings->beacon.head_len); ++ ++ prP2pBcnUpdateMsg->u4BcnHdrLen = settings->beacon.head_len; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) settings->beacon.head_len); ++ } else { ++ prP2pBcnUpdateMsg->u4BcnHdrLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = NULL; ++ } ++ ++ if (settings->beacon.tail_len != 0) { ++ UINT_32 ucLen = settings->beacon.tail_len; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; ++ ++ /*Add TIM IE */ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = 1; ++ TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; ++ /* will be overwrite by FW */ ++ ucLen += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ kalMemCopy(pucBuffer, settings->beacon.tail, settings->beacon.tail_len); ++ ++ prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; ++ } else { ++ prP2pBcnUpdateMsg->u4BcnBodyLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = NULL; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); ++ ++ prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, sizeof(MSG_P2P_START_AP_T)); ++ ++ if (prP2pStartAPMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pStartAPMsg->rMsgHdr.eMsgId = MID_MNY_P2P_START_AP; ++ ++ prP2pStartAPMsg->fgIsPrivacy = settings->privacy; ++ ++ prP2pStartAPMsg->u4BcnInterval = settings->beacon_interval; ++ ++ prP2pStartAPMsg->u4DtimPeriod = settings->dtim_period; ++ ++ /* Copy NO SSID. */ ++ prP2pStartAPMsg->ucHiddenSsidType = settings->hidden_ssid; ++ ++ COPY_SSID(prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen, settings->ssid, settings->ssid_len); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pStartAPMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_LOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++/* /////////////////////// */ ++ /** ++ * struct cfg80211_ap_settings - AP configuration ++ * ++ * Used to configure an AP interface. ++ * ++ * @beacon: beacon data ++ * @beacon_interval: beacon interval ++ * @dtim_period: DTIM period ++ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from ++ * user space) ++ * @ssid_len: length of @ssid ++ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames ++ * @crypto: crypto settings ++ * @privacy: the BSS uses privacy ++ * @auth_type: Authentication type (algorithm) ++ * @inactivity_timeout: time in seconds to determine station's inactivity. ++ */ ++/* struct cfg80211_ap_settings { */ ++/* struct cfg80211_beacon_data beacon; */ ++/* */ ++/* int beacon_interval, dtim_period; */ ++/* const u8 *ssid; */ ++/* size_t ssid_len; */ ++/* enum nl80211_hidden_ssid hidden_ssid; */ ++/* struct cfg80211_crypto_settings crypto; */ ++/* bool privacy; */ ++/* enum nl80211_auth_type auth_type; */ ++/* int inactivity_timeout; */ ++/* }; */ ++/* ////////////////// */ ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_start_ap */ ++ ++int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; ++ PUINT_8 pucBuffer = (PUINT_8) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (info == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_beacon.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_BEACON_UPDATE_T) + ++ info->head_len + info->tail_len)); ++ ++ if (prP2pBcnUpdateMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; ++ pucBuffer = prP2pBcnUpdateMsg->aucBuffer; ++ ++ if (info->head_len != 0) { ++ kalMemCopy(pucBuffer, info->head, info->head_len); ++ ++ prP2pBcnUpdateMsg->u4BcnHdrLen = info->head_len; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; ++ ++ pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) info->head_len); ++ } else { ++ prP2pBcnUpdateMsg->u4BcnHdrLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnHdr = NULL; ++ } ++ ++ if (info->tail_len != 0) { ++ UINT_32 ucLen = info->tail_len; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; ++ ++ /*Add TIM IE */ ++ /* IEEE 802.11 2007 - 7.3.2.6 */ ++ TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; ++ TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; ++ /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ ++ TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ ++ TIM_IE(pucBuffer)->ucDTIMPeriod = 1; ++ TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; ++ /* will be overwrite by FW */ ++ ucLen += IE_SIZE(pucBuffer); ++ pucBuffer += IE_SIZE(pucBuffer); ++ ++ kalMemCopy(pucBuffer, info->tail, info->tail_len); ++ ++ prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; ++ } else { ++ prP2pBcnUpdateMsg->u4BcnBodyLen = 0; ++ ++ prP2pBcnUpdateMsg->pucBcnBody = NULL; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); ++ ++/* ////////////////////////// */ ++/** ++ * struct cfg80211_beacon_data - beacon data ++ * @head: head portion of beacon (before TIM IE) ++ * or %NULL if not changed ++ * @tail: tail portion of beacon (after TIM IE) ++ * or %NULL if not changed ++ * @head_len: length of @head ++ * @tail_len: length of @tail ++ * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL ++ * @beacon_ies_len: length of beacon_ies in octets ++ * @proberesp_ies: extra information element(s) to add into Probe Response ++ * frames or %NULL ++ * @proberesp_ies_len: length of proberesp_ies in octets ++ * @assocresp_ies: extra information element(s) to add into (Re)Association ++ * Response frames or %NULL ++ * @assocresp_ies_len: length of assocresp_ies in octets ++ * @probe_resp_len: length of probe response template (@probe_resp) ++ * @probe_resp: probe response template (AP mode only) ++ */ ++/* struct cfg80211_beacon_data { */ ++/* const u8 *head, *tail; */ ++/* const u8 *beacon_ies; */ ++/* const u8 *proberesp_ies; */ ++/* const u8 *assocresp_ies; */ ++/* const u8 *probe_resp; */ ++ ++/* size_t head_len, tail_len; */ ++/* size_t beacon_ies_len; */ ++/* size_t proberesp_ies_len; */ ++/* size_t assocresp_ies_len; */ ++/* size_t probe_resp_len; */ ++/* }; */ ++ ++/* ////////////////////////// */ ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_change_beacon */ ++ ++int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_stop_ap.\n"); ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* Switch OP MOde. */ ++ prP2pSwitchMode = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_SWITCH_OP_MODE_T)); ++ ++ if (prP2pSwitchMode == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prP2pSwitchMode->rMsgHdr.eMsgId = MID_MNY_P2P_STOP_AP; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pSwitchMode, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++ if (glIsChipNeedWakelock(prGlueInfo)) ++ KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); ++#endif ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_stop_ap */ ++ ++/* TODO: */ ++int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* not implemented yet */ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_deauth.\n"); ++ ++ return -EINVAL; ++} /* mtk_p2p_cfg80211_deauth */ ++ ++/* TODO: */ ++int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_disassoc.\n"); ++ ++ /* not implemented yet */ ++ ++ return -EINVAL; ++} /* mtk_p2p_cfg80211_disassoc */ ++ ++int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ P_MSG_P2P_CHNL_REQUEST_T prMsgChnlReq = (P_MSG_P2P_CHNL_REQUEST_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ *cookie = prGlueP2pInfo->u8Cookie++; ++ ++ prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_REQUEST_T)); ++ ++ if (prMsgChnlReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_remain_on_channel\n"); ++ ++ prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; ++ prMsgChnlReq->u8Cookie = *cookie; ++ prMsgChnlReq->u4Duration = duration; ++ ++ mtk_p2p_cfg80211func_channel_format_switch(chan, NL80211_CHAN_HT20, /* 4 KH Need Check */ ++ &prMsgChnlReq->rChannelInfo, &prMsgChnlReq->eChnlSco); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} ++ ++/* mtk_p2p_cfg80211_remain_on_channel */ ++int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u64 cookie) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_MSG_P2P_CHNL_ABORT_T prMsgChnlAbort = (P_MSG_P2P_CHNL_ABORT_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_ABORT_T)); ++ ++ if (prMsgChnlAbort == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_cancel_remain_on_channel\n"); ++ ++ prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_ABORT; ++ prMsgChnlAbort->u8Cookie = cookie; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_cancel_remain_on_channel */ ++ ++int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prMsgExtListenReq = NULL; ++ P_MSG_P2P_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; ++ P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; ++ PUINT_8 pucFrameBuf = (PUINT_8) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) ++ break; ++ /* DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_mgmt_tx\n")); */ ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ *cookie = prGlueP2pInfo->u8Cookie++; ++ ++ /* Channel & Channel Type & Wait time are ignored. */ ++ prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_TX_REQUEST_T)); ++ ++ if (prMsgTxReq == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ /* Here need to extend the listen interval */ ++ prMsgExtListenReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T)); ++ if (prMsgExtListenReq) { ++ prMsgExtListenReq->rMsgHdr.eMsgId = MID_MNY_P2P_EXTEND_LISTEN_INTERVAL; ++ prMsgExtListenReq->wait = params->wait; ++ DBGLOG(P2P, INFO, "ext listen, wait: %d\n", prMsgExtListenReq->wait); ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgExtListenReq, ++ MSG_SEND_METHOD_BUF); ++ } ++ ++ prMsgTxReq->fgNoneCckRate = FALSE; ++ prMsgTxReq->fgIsWaitRsp = TRUE; ++ ++ prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); ++ ++ prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; ++ if (prMsgTxReq->prMgmtMsduInfo == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prMsgTxReq->u8Cookie = *cookie; ++ prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_TX; ++ ++ pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); ++ ++ kalMemCopy(pucFrameBuf, params->buf, params->len); ++ ++ prMgmtFrame->u2FrameLength = params->len; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { ++ if (prMsgTxReq->prMgmtMsduInfo != NULL) ++ cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); ++ ++ cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); ++ } ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_mgmt_tx */ ++ ++int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ switch (params->use_cts_prot) { ++ case -1: ++ DBGLOG(P2P, TRACE, "CTS protection no change\n"); ++ break; ++ case 0: ++ DBGLOG(P2P, TRACE, "CTS protection disable.\n"); ++ break; ++ case 1: ++ DBGLOG(P2P, TRACE, "CTS protection enable\n"); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "CTS protection unknown\n"); ++ break; ++ } ++ ++ switch (params->use_short_preamble) { ++ case -1: ++ DBGLOG(P2P, TRACE, "Short prreamble no change\n"); ++ break; ++ case 0: ++ DBGLOG(P2P, TRACE, "Short prreamble disable.\n"); ++ break; ++ case 1: ++ DBGLOG(P2P, TRACE, "Short prreamble enable\n"); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Short prreamble unknown\n"); ++ break; ++ } ++ ++#if 0 ++ /* not implemented yet */ ++ p2pFuncChangeBssParam(prGlueInfo->prAdapter, ++ prBssInfo->fgIsProtection, ++ prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortSlotTime, ++ /* Basic rates */ ++ /* basic rates len */ ++ /* ap isolate */ ++ /* ht opmode. */ ++ ); ++#else ++ i4Rslt = 0; ++#endif ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_change_bss */ ++ ++int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params) ++//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ UINT_8 aucBcMac[] = BC_MAC_ADDR; ++ const UINT_8 *mac = NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL)) ++ break; ++ ++ if (params->mac == NULL) ++ mac = aucBcMac; ++ else ++ mac = params->mac; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_del_station.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(MSG_P2P_CONNECTION_ABORT_T), ++ VIR_MEM_TYPE); */ ++ prDisconnectMsg = ++ (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (prDisconnectMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prDisconnectMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ COPY_MAC_ADDR(prDisconnectMsg->aucTargetID, mac); ++ prDisconnectMsg->u2ReasonCode = REASON_CODE_UNSPECIFIED; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnectMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} /* mtk_p2p_cfg80211_del_station */ ++ ++int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL) || (sme == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_connect.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prConnReqMsg = ++ (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ (sizeof(MSG_P2P_CONNECTION_REQUEST_T) + sme->ie_len)); ++ ++ if (prConnReqMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prConnReqMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ COPY_SSID(prConnReqMsg->rSsid.aucSsid, prConnReqMsg->rSsid.ucSsidLen, sme->ssid, sme->ssid_len); ++ ++ COPY_MAC_ADDR(prConnReqMsg->aucBssid, sme->bssid); ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_connect to %pM, IE len: %d\n", ++ prConnReqMsg->aucBssid, sme->ie_len); ++ ++ DBGLOG(P2P, TRACE, "Assoc Req IE Buffer Length:%d\n", sme->ie_len); ++ kalMemCopy(prConnReqMsg->aucIEBuf, sme->ie, sme->ie_len); ++ prConnReqMsg->u4IELen = sme->ie_len; ++ ++ mtk_p2p_cfg80211func_channel_format_switch(sme->channel, ++ NL80211_CHAN_NO_HT, ++ &prConnReqMsg->rChannelInfo, &prConnReqMsg->eChnlSco); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prConnReqMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_connect */ ++ ++int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; ++ UINT_8 aucBCAddr[] = BC_MAC_ADDR; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL)) ++ break; ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++/* prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(P_MSG_P2P_CONNECTION_ABORT_T), VIR_MEM_TYPE); */ ++ prDisconnMsg = ++ (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_ABORT_T)); ++ ++ if (prDisconnMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.Allocate Memory Failed.\n"); ++ break; ++ } ++ ++ prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; ++ prDisconnMsg->u2ReasonCode = reason_code; ++ prDisconnMsg->fgSendDeauth = TRUE; ++ COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_disconnect */ ++ ++int ++mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, ++ IN enum nl80211_iftype type,/* IN u32 *flags,*/ IN struct vif_params *params) ++{ ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ INT_32 i4Rslt = -EINVAL; ++ P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (ndev == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_iface.\n"); ++ ++ if (ndev->ieee80211_ptr) ++ ndev->ieee80211_ptr->iftype = type; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* Switch OP MOde. */ ++ prSwitchModeMsg = ++ (P_MSG_P2P_SWITCH_OP_MODE_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, ++ sizeof(MSG_P2P_SWITCH_OP_MODE_T)); ++ ++ if (prSwitchModeMsg == NULL) { ++ ASSERT(FALSE); ++ i4Rslt = -ENOMEM; ++ break; ++ } ++ ++ prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; ++ ++ switch (type) { ++ case NL80211_IFTYPE_P2P_CLIENT: ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_CLIENT.\n"); ++ case NL80211_IFTYPE_STATION: ++ if (type == NL80211_IFTYPE_STATION) ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_STATION.\n"); ++ prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; ++ break; ++ case NL80211_IFTYPE_AP: ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_AP.\n"); ++ case NL80211_IFTYPE_P2P_GO: ++ if (type == NL80211_IFTYPE_P2P_GO) ++ DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_GO not AP.\n"); ++ prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "Other type :%d .\n", type); ++ prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; ++ break; ++ } ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSwitchModeMsg, MSG_SEND_METHOD_BUF); ++ ++ i4Rslt = 0; ++ ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} /* mtk_p2p_cfg80211_change_iface */ ++ ++int mtk_p2p_cfg80211_set_channel(IN struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ RF_CHANNEL_INFO_T rRfChnlInfo; ++ ++ do { ++ if (wiphy == NULL) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_channel.\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ mtk_p2p_cfg80211func_channel_format_switch(chandef->chan, chandef->width, &rRfChnlInfo, NULL); ++ p2pFuncSetChannel(prGlueInfo->prAdapter, &rRfChnlInfo); ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++ ++} ++ ++/* mtk_p2p_cfg80211_set_channel */ ++ ++int ++mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, ++ IN struct net_device *dev, ++ IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask) ++{ ++ INT_32 i4Rslt = -EINVAL; ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (dev == NULL) || (mask == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_bitrate_mask\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ /* TODO: Set bitrate mask of the peer? */ ++ ++ i4Rslt = 0; ++ } while (FALSE); ++ ++ return i4Rslt; ++} /* mtk_p2p_cfg80211_set_bitrate_mask */ ++ ++void mtk_p2p_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg) ++{ ++#if 0 ++ P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; ++#endif ++ P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; ++ ++ do { ++ if ((wiphy == NULL) || (wdev == NULL)) ++ break; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_mgmt_frame_register\n"); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ switch (frame_type) { ++ case MAC_FRAME_PROBE_REQ: ++ if (reg) { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); ++ } else { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; ++ DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); ++ } ++ break; ++ case MAC_FRAME_ACTION: ++ if (reg) { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); ++ } else { ++ prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; ++ DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); ++ } ++ break; ++ default: ++ DBGLOG(P2P, ERROR, "Ask frog to add code for mgmt:%x\n", frame_type); ++ break; ++ } ++ ++ if ((prGlueInfo->prAdapter != NULL) && (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE)) { ++ ++ /* prGlueInfo->u4Flag |= GLUE_FLAG_FRAME_FILTER; */ ++ set_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag); ++ ++ /* wake up main thread */ ++ wake_up_interruptible(&prGlueInfo->waitq); ++ ++ if (in_interrupt()) ++ DBGLOG(P2P, TRACE, "It is in interrupt level\n"); ++ } ++#if 0 ++ ++ prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof ++ (MSG_P2P_MGMT_FRAME_REGISTER_T)); ++ ++ if (prMgmtFrameRegister == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; ++ ++ prMgmtFrameRegister->u2FrameType = frame_type; ++ prMgmtFrameRegister->fgIsRegister = reg; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); ++ ++#endif ++ ++ } while (FALSE); ++ ++} /* mtk_p2p_cfg80211_mgmt_frame_register */ ++ ++BOOLEAN ++mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, ++ IN enum nl80211_channel_type channel_type, ++ IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco) ++{ ++ BOOLEAN fgIsValid = FALSE; ++ ++ do { ++ if (channel == NULL) ++ break; ++ ++ if (prRfChnlInfo) { ++ prRfChnlInfo->ucChannelNum = nicFreq2ChannelNum(channel->center_freq * 1000); ++ ++ switch (channel->band) { ++ case NL80211_BAND_2GHZ: ++ prRfChnlInfo->eBand = BAND_2G4; ++ break; ++ case NL80211_BAND_5GHZ: ++ prRfChnlInfo->eBand = BAND_5G; ++ break; ++ default: ++ prRfChnlInfo->eBand = BAND_2G4; ++ break; ++ } ++ ++ } ++ ++ if (prChnlSco) { ++ ++ switch (channel_type) { ++ case NL80211_CHAN_NO_HT: ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ case NL80211_CHAN_HT20: ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ case NL80211_CHAN_HT40MINUS: ++ *prChnlSco = CHNL_EXT_SCA; ++ break; ++ case NL80211_CHAN_HT40PLUS: ++ *prChnlSco = CHNL_EXT_SCB; ++ break; ++ default: ++ ASSERT(FALSE); ++ *prChnlSco = CHNL_EXT_SCN; ++ break; ++ } ++ } ++ ++ fgIsValid = TRUE; ++ } while (FALSE); ++ ++ return fgIsValid; ++} ++ ++/* mtk_p2p_cfg80211func_channel_format_switch */ ++ ++#if CONFIG_NL80211_TESTMODE ++int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_TEST_PARAMS prParams = (P_NL80211_DRIVER_TEST_PARAMS) NULL; ++ INT_32 i4Status = -EINVAL; ++ P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = NULL; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_cmd\n"); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_TEST_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_cmd, data is NULL\n"); ++ return i4Status; ++ } ++ ++ if (prParams->index >> 24 == 0x01) { ++ /* New version */ ++ } else { ++ /* Old version */ ++ mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(wiphy, data, len); ++ i4Status = 0; ++ return i4Status; ++ } ++ ++ /* Clear the version byte */ ++ prParams->index = prParams->index & ~BITS(24, 31); ++ ++ if (prParams) { ++ switch (prParams->index) { ++ case 1: /* P2P Simga */ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ { ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParamsCmd; ++ ++ prParamsCmd = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if ((prParamsCmd->adr & 0xffff0000) == 0xffff0000) { ++ i4Status = mtk_p2p_cfg80211_testmode_sw_cmd(wiphy, data, len); ++ break; ++ } ++ } ++#endif ++ i4Status = mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(wiphy, data, len); ++ break; ++#if CFG_SUPPORT_WFD ++ case 2: /* WFD */ ++ i4Status = mtk_p2p_cfg80211_testmode_wfd_update_cmd(wiphy, data, len); ++ break; ++#endif ++ case 3: /* Hotspot Client Management */ ++ i4Status = mtk_p2p_cfg80211_testmode_hotspot_block_cmd(wiphy, data, len); ++ break; ++ case 0x10: ++ i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); ++ break; ++#if 1 ++ case 0x11: /*NFC Beam + Indication */ ++ prChnlReqInfo = &prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; ++ if (data && len) { ++ P_NL80211_DRIVER_SET_NFC_PARAMS prParams = (P_NL80211_DRIVER_SET_NFC_PARAMS) data; ++ ++ prChnlReqInfo->NFC_BEAM = prParams->NFC_Enable; ++ DBGLOG(P2P, INFO, "NFC: BEAM[%d]\n", prChnlReqInfo->NFC_BEAM); ++ } ++ break; ++ case 0x12: /*NFC Beam + Indication */ ++ DBGLOG(P2P, INFO, "NFC: Polling\n"); ++ i4Status = mtk_cfg80211_testmode_get_scan_done(wiphy, data, len, prGlueInfo); ++ break; ++#endif ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ case 0x30: ++ i4Status = mtk_cfg80211_testmode_get_lte_channel(wiphy, data, len, prGlueInfo); ++ break; ++#endif ++ ++ default: ++ i4Status = -EINVAL; ++ break; ++ } ++ } ++ ++ return i4Status; ++} ++ ++int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ NL80211_DRIVER_TEST_PRE_PARAMS rParams; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 index_mode; ++ UINT_32 index; ++ INT_32 value; ++ int status = 0; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ kalMemZero(&rParams, sizeof(NL80211_DRIVER_TEST_PRE_PARAMS)); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd\n"); ++ ++ if (data && len) ++ memcpy(&rParams, data, len); ++ ++ DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA,idx_mode=%d idx=%d value=%u\n", ++ (INT_16) rParams.idx_mode, (INT_16) rParams.idx, rParams.value); ++ ++ index_mode = rParams.idx_mode; ++ index = rParams.idx; ++ value = rParams.value; ++ ++ switch (index) { ++ case 0: /* Listen CH */ ++ break; ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ /* prP2pConnSettings->ucOperatingChnl = value; */ ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ prP2pConnSettings->u2LocalConfigMethod = value; ++ break; ++ case 102: /* Sigma P2p reset */ ++ /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ p2pFsmUninit(prGlueInfo->prAdapter); ++ p2pFsmInit(prGlueInfo->prAdapter); ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++ ++} ++ ++int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_P2P_SIGMA_PARAMS prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ UINT_32 index; ++ INT_32 value; ++ int status = 0; ++ UINT_32 u4Leng; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd\n"); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd, data is NULL or len is 0\n"); ++ return -EINVAL; ++ } ++ ++ index = (INT_32) prParams->idx; ++ value = (INT_32) prParams->value; ++ ++ DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA, idx=%d value=%d\n", ++ (INT_32) prParams->idx, (INT_32) prParams->value); ++ ++ switch (index) { ++ case 0: /* Listen CH */ ++ break; ++ case 1: /* P2p mode */ ++ break; ++ case 4: /* Noa duration */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 5: /* Noa interval */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; ++ /* only to apply setting when setting NOA count */ ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 6: /* Noa count */ ++ prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; ++ /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ ++ break; ++ case 100: /* Oper CH */ ++ /* 20110920 - frog: User configurations are placed in ConnSettings. */ ++ /* prP2pConnSettings->ucOperatingChnl = value; */ ++ break; ++ case 101: /* Local config Method, for P2P SDK */ ++ prP2pConnSettings->u2LocalConfigMethod = value; ++ break; ++ case 102: /* Sigma P2p reset */ ++ /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ ++ /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ ++ break; ++ case 103: /* WPS MODE */ ++ kalP2PSetWscMode(prGlueInfo, value); ++ break; ++ case 104: /* P2p send persence, duration */ ++ break; ++ case 105: /* P2p send persence, interval */ ++ break; ++ case 106: /* P2P set sleep */ ++ value = 1; ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ case 107: /* P2P set opps, CTWindowl */ ++ prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; ++ /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ ++ break; ++ case 108: /* p2p_set_power_save */ ++ kalIoctl(prGlueInfo, ++ wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ ++ break; ++ case 109: /* Max Clients */ ++ kalP2PSetMaxClients(prGlueInfo, value); ++ break; ++ case 110: /* Hotspot WPS mode */ ++ kalIoctl(prGlueInfo, wlanoidSetP2pWPSmode, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); ++ break; ++ default: ++ break; ++ } ++ ++ return status; ++ ++} ++ ++#if CFG_SUPPORT_WFD ++int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_WFD_PARAMS prParams = (P_NL80211_DRIVER_WFD_PARAMS) NULL; ++ int status = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ static UINT_8 prevWfdEnable; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ prParams = (P_NL80211_DRIVER_WFD_PARAMS) data; ++ ++ DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_testmode_wfd_update_cmd\n"); ++ ++ /* to reduce log, print when state changed */ ++ if (prevWfdEnable != prParams->WfdEnable) { ++ prevWfdEnable = prParams->WfdEnable; ++ DBGLOG(P2P, INFO, "WFD Enable:%x\n", prParams->WfdEnable); ++ DBGLOG(P2P, INFO, "WFD Session Available:%x\n", prParams->WfdSessionAvailable); ++ DBGLOG(P2P, INFO, "WFD Couple Sink Status:%x\n", prParams->WfdCoupleSinkStatus); ++ /* aucReserved0[2] */ ++ DBGLOG(P2P, INFO, "WFD Device Info:%x\n", prParams->WfdDevInfo); ++ DBGLOG(P2P, INFO, "WFD Control Port:%x\n", prParams->WfdControlPort); ++ DBGLOG(P2P, INFO, "WFD Maximum Throughput:%x\n", prParams->WfdMaximumTp); ++ DBGLOG(P2P, INFO, "WFD Extend Capability:%x\n", prParams->WfdExtendCap); ++ DBGLOG(P2P, INFO, "WFD Couple Sink Addr %pM\n", prParams->WfdCoupleSinkAddress); ++ DBGLOG(P2P, INFO, "WFD Associated BSSID %pM\n", prParams->WfdAssociatedBssid); ++ /* UINT_8 aucVideolp[4]; */ ++ /* UINT_8 aucAudiolp[4]; */ ++ DBGLOG(P2P, INFO, "WFD Video Port:%x\n", prParams->WfdVideoPort); ++ DBGLOG(P2P, INFO, "WFD Audio Port:%x\n", prParams->WfdAudioPort); ++ DBGLOG(P2P, INFO, "WFD Flag:%x\n", prParams->WfdFlag); ++ DBGLOG(P2P, INFO, "WFD Policy:%x\n", prParams->WfdPolicy); ++ DBGLOG(P2P, INFO, "WFD State:%x\n", prParams->WfdState); ++ /* UINT_8 aucWfdSessionInformationIE[24*8]; */ ++ DBGLOG(P2P, INFO, "WFD Session Info Length:%x\n", prParams->WfdSessionInformationIELen); ++ /* UINT_8 aucReserved1[2]; */ ++ DBGLOG(P2P, INFO, "WFD Primary Sink Addr %pM\n", prParams->aucWfdPrimarySinkMac); ++ DBGLOG(P2P, INFO, "WFD Secondary Sink Addr %pM\n", prParams->aucWfdSecondarySinkMac); ++ DBGLOG(P2P, INFO, "WFD Advanced Flag:%x\n", prParams->WfdAdvanceFlag); ++ DBGLOG(P2P, INFO, "WFD Sigma mode:%x\n", prParams->WfdSigmaMode); ++ /* UINT_8 aucReserved2[64]; */ ++ /* UINT_8 aucReserved3[64]; */ ++ /* UINT_8 aucReserved4[64]; */ ++ } ++ ++ prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ ++ kalMemCopy(&prWfdCfgSettings->u4WfdCmdType, &prParams->WfdCmdType, sizeof(WFD_CFG_SETTINGS_T)); ++ ++ prMsgWfdCfgUpdate = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); ++ ++ if (prMsgWfdCfgUpdate == NULL) { ++ ASSERT(FALSE); ++ return status; ++ } ++ ++ prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; ++ prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); ++#if 0 /* Test Only */ ++/* prWfdCfgSettings->ucWfdEnable = 1; */ ++/* prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; */ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; ++ prWfdCfgSettings->u2WfdDevInfo = 123; ++ prWfdCfgSettings->u2WfdControlPort = 456; ++ prWfdCfgSettings->u2WfdMaximumTp = 789; ++ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_SINK_INFO_VALID; ++ prWfdCfgSettings->ucWfdCoupleSinkStatus = 0xAB; ++ { ++ UINT_8 aucTestAddr[MAC_ADDR_LEN] = { 0x77, 0x66, 0x55, 0x44, 0x33, 0x22 }; ++ ++ COPY_MAC_ADDR(prWfdCfgSettings->aucWfdCoupleSinkAddress, aucTestAddr); ++ } ++ ++ prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_EXT_CAPABILITY_VALID; ++ prWfdCfgSettings->u2WfdExtendCap = 0xCDE; ++ ++#endif ++ ++ return status; ++ ++} ++#endif /* CFG_SUPPORT_WFD */ ++ ++int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) NULL; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++ if (data && len) { ++ prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) data; ++ } else { ++ DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd, data is NULL or len is 0\n"); ++ return -EINVAL; ++ } ++ ++ DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd\n"); ++ ++ return kalP2PSetBlackList(prGlueInfo, prParams->aucBssid, prParams->ucblocked); ++} ++ ++int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; ++ WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; ++ int fgIsValid = 0; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(wiphy); ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); ++ ++#if 1 ++ DBGLOG(P2P, TRACE, "--> %s()\n", __func__); ++#endif ++ ++ if (data && len) ++ prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; ++ ++ if (prParams) { ++ if (prParams->set == 1) { ++ rstatus = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, ++ &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } ++ } ++ ++ if (WLAN_STATUS_SUCCESS != rstatus) ++ fgIsValid = -EFAULT; ++ ++ return fgIsValid; ++} ++ ++#endif ++ ++#endif /* CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c +new file mode 100644 +index 000000000000..d0f2d25a4529 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c +@@ -0,0 +1,433 @@ ++/* ++* Copyright (C) 2011-2014 MediaTek Inc. ++* ++* 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. ++* ++* 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, see . ++*/ ++ ++/* ++** Id: @(#) gl_p2p_init.c@@ ++*/ ++ ++/*! \file gl_p2p_init.c ++ \brief init and exit routines of Linux driver interface for Wi-Fi Direct ++ ++ This file contains the main routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define P2P_MODE_INF_NAME "p2p%d" ++#if CFG_TC1_FEATURE ++#define AP_MODE_INF_NAME "wlan%d" ++#else ++#define AP_MODE_INF_NAME "ap%d" ++#endif ++/* #define MAX_INF_NAME_LEN 15 */ ++/* #define MIN_INF_NAME_LEN 1 */ ++ ++#define RUNNING_P2P_MODE 0 ++#define RUNNING_AP_MODE 1 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* Get interface name and running mode from module insertion parameter ++* Usage: insmod p2p.ko mode=1 ++* default: interface name is p2p%d ++* running mode is P2P ++*/ ++static PUCHAR ifname = P2P_MODE_INF_NAME; ++static UINT_16 mode = RUNNING_P2P_MODE; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief check interface name parameter is valid or not ++* if invalid, set ifname to P2P_MODE_INF_NAME ++* ++* ++* \retval ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID p2pCheckInterfaceName(VOID) ++{ ++ ++ if (mode) { ++ mode = RUNNING_AP_MODE; ++ ifname = AP_MODE_INF_NAME; ++ } ++#if 0 ++ UINT_32 ifLen = 0; ++ ++ if (ifname) { ++ ifLen = strlen(ifname); ++ ++ if (ifLen > MAX_INF_NAME_LEN) ++ ifname[MAX_INF_NAME_LEN] = '\0'; ++ else if (ifLen < MIN_INF_NAME_LEN) ++ ifname = P2P_MODE_INF_NAME; ++ } else { ++ ifname = P2P_MODE_INF_NAME; ++ } ++#endif ++} ++ ++void p2pHandleSystemSuspend(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ ++ ++ if (!wlanExportGlueInfo(&prGlueInfo)) { ++ DBGLOG(P2P, INFO, "No glue info\n"); ++ return; ++ } ++ ++ ASSERT(prGlueInfo); ++ /* <1> Sanity check and acquire the net_device */ ++ prDev = prGlueInfo->prP2PInfo->prDevHandler; ++ ASSERT(prDev); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ip is not available.\n"); ++ return; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ipv6 is not available.\n"); ++ return; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) ++ ; /* Do nothing */ ++#endif ++ /* <7> set up the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#ifdef CONFIG_IPV6 ++ prParamNetAddrList->u4AddressCount += u4NumIPv6; ++#endif ++ ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++#if 0 ++ kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prParamNetAddr + sizeof(ip)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); ++#else ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ ++/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++// TODO: frog. The pointer is not right. */ ++ ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + ++ (ULONG) (prParamNetAddr->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP); ++#endif ++ } ++#ifdef CONFIG_IPV6 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); */ ++ ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + ++ (ULONG) (prParamNetAddr->u2AddressLength + ++ OFFSET_OF(PARAM_NETWORK_ADDRESS, ++ aucAddress))); ++ ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ } ++} ++ ++void p2pHandleSystemResume(void) ++{ ++ struct net_device *prDev = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_8 ip[4] = { 0 }; ++#ifdef CONFIG_IPV6 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++#endif ++ ++ if (!wlanExportGlueInfo(&prGlueInfo)) { ++ DBGLOG(P2P, WARN, "no glue info\n"); ++ return; ++ } ++ ++ ASSERT(prGlueInfo); ++ /* <1> Sanity check and acquire the net_device */ ++ prDev = prGlueInfo->prP2PInfo->prDevHandler; ++ ASSERT(prDev); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ip is not available.\n"); ++ return; ++ } ++ /* <4> copy the IPv4 address */ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ ++#ifdef CONFIG_IPV6 ++ /* <5> get the IPv6 address */ ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(P2P, INFO, "ipv6 is not available.\n"); ++ return; ++ } ++ /* <6> copy the IPv6 address */ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++#endif ++ /* <7> clear the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++/* UINT_8 aucBuf[32] = {0}; */ ++ UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; ++ /* aucBuf; */ ++ ++ kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); ++ ++ prParamNetAddrList->u4AddressCount = 0; ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ ++ ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetP2pSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); ++ ++ DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* run p2p init procedure, include register pointer to wlan ++* glue register p2p ++* set p2p registered flag ++* \retval 1 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo) ++{ ++ ++ DBGLOG(P2P, TRACE, "p2pLaunch\n"); ++ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE) { ++ DBGLOG(P2P, INFO, "p2p already registered\n"); ++ return FALSE; ++ } else if (glRegisterP2P(prGlueInfo, ifname, (BOOLEAN) mode)) { ++ prGlueInfo->prAdapter->fgIsP2PRegistered = TRUE; ++ ++ DBGLOG(P2P, TRACE, "Launch success, fgIsP2PRegistered TRUE.\n"); ++ return TRUE; ++ } ++ DBGLOG(P2P, ERROR, "Launch Fail\n"); ++ ++ return FALSE; ++} ++ ++VOID p2pSetMode(IN BOOLEAN fgIsAPMOde) ++{ ++ if (fgIsAPMOde) { ++ mode = RUNNING_AP_MODE; ++ ifname = AP_MODE_INF_NAME; ++ } else { ++ mode = RUNNING_P2P_MODE; ++ ifname = P2P_MODE_INF_NAME; ++ } ++ ++} /* p2pSetMode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* run p2p exit procedure, include unregister pointer to wlan ++* glue unregister p2p ++* set p2p registered flag ++ ++* \retval 1 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo) ++{ ++ if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { ++ DBGLOG(P2P, INFO, "p2p is not Registered.\n"); ++ return FALSE; ++ } ++ /*Check p2p fsm is stop or not. If not then stop now */ ++ if (IS_P2P_ACTIVE(prGlueInfo->prAdapter)) ++ p2pStopImmediate(prGlueInfo); ++ prGlueInfo->prAdapter->fgIsP2PRegistered = FALSE; ++ glUnregisterP2P(prGlueInfo); ++ /*p2p is removed successfully */ ++ return TRUE; ++ ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver entry point when the driver is configured as a Linux Module, and ++* is called once at module load time, by the user-level modutils ++* application: insmod or modprobe. ++* ++* \retval 0 Success ++*/ ++/*----------------------------------------------------------------------------*/ ++static int initP2P(void) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ /*check interface name validation */ ++ p2pCheckInterfaceName(); ++ ++ DBGLOG(P2P, INFO, "InitP2P, Ifname: %s, Mode: %s\n", ifname, mode ? "AP" : "P2P"); ++ ++ /*register p2p init & exit function to wlan sub module handler */ ++ wlanSubModRegisterInitExit(p2pLaunch, p2pRemove, P2P_MODULE); ++ ++ /*if wlan is not start yet, do nothing ++ * p2pLaunch will be called by txthread while wlan start ++ */ ++ /*if wlan is not started yet, return FALSE */ ++ if (wlanExportGlueInfo(&prGlueInfo)) { ++ wlanSubModInit(prGlueInfo); ++ return prGlueInfo->prAdapter->fgIsP2PRegistered ? 0 : -EIO; ++ } ++ ++ return 0; ++} /* end of initP2P() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Driver exit point when the driver as a Linux Module is removed. Called ++* at module unload time, by the user level modutils application: rmmod. ++* This is our last chance to clean up after ourselves. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++/* 1 Module Leave Point */ ++static VOID __exit exitP2P(void) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ ++ DBGLOG(P2P, INFO, KERN_INFO DRV_NAME "ExitP2P\n"); ++ ++ /*if wlan is not started yet, return FALSE */ ++ if (wlanExportGlueInfo(&prGlueInfo)) ++ wlanSubModExit(prGlueInfo); ++ /*UNregister p2p init & exit function to wlan sub module handler */ ++ wlanSubModRegisterInitExit(NULL, NULL, P2P_MODULE); ++} /* end of exitP2P() */ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c +new file mode 100644 +index 000000000000..11a417e4c74c +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c +@@ -0,0 +1,1314 @@ ++/* ++** Id: @(#) gl_p2p_cfg80211.c@@ ++*/ ++ ++/*! \file gl_p2p_kal.c ++ \brief ++ ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "net/cfg80211.h" ++#include "precomp.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Wi-Fi Direct state from glue layer ++* ++* \param[in] ++* prGlueInfo ++* rPeerAddr ++* \return ++* ENUM_BOW_DEVICE_STATE ++*/ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->eState; ++} /* end of kalP2PGetState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to update the assoc req to p2p ++* ++* \param[in] ++* prGlueInfo ++* pucFrameBody ++* u4FrameBodyLen ++* fgReassocRequest ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) ++{ ++ union iwreq_data wrqu; ++ unsigned char *pucExtraInfo = NULL; ++ unsigned char *pucDesiredIE = NULL; ++/* unsigned char aucExtraInfoBuf[200]; */ ++ PUINT_8 cp; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ if (fgReassocRequest) { ++ if (u4FrameBodyLen < 15) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } else { ++ if (u4FrameBodyLen < 9) { ++ /* ++ printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); ++ */ ++ return; ++ } ++ } ++ ++ cp = pucFrameBody; ++ ++ if (fgReassocRequest) { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ /* Current AP address 6 */ ++ cp += 10; ++ u4FrameBodyLen -= 10; ++ } else { ++ /* Capability information field 2 */ ++ /* Listen interval field 2 */ ++ cp += 4; ++ u4FrameBodyLen -= 4; ++ } ++ ++ /* do supplicant a favor, parse to the start of WPA/RSN IE */ ++ if (wextSrchDesiredWPSIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPSIE!!\n"); */ ++ /* WPS IE found */ ++ } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0x30, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPAIE!!\n"); */ ++ /* RSN IE found */ ++ } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { ++ /* printk("wextSrchDesiredWPAIE!!\n"); */ ++ /* WPA IE found */ ++ } else { ++ /* no WPA/RSN IE found, skip this event */ ++ goto skip_indicate_event; ++ } ++ ++ /* IWEVASSOCREQIE, indicate binary string */ ++ pucExtraInfo = pucDesiredIE; ++ wrqu.data.length = pucDesiredIE[1] + 2; ++ ++ /* Send event to user space */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVASSOCREQIE, &wrqu, pucExtraInfo); ++ ++skip_indicate_event: ++ return; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Wi-Fi Direct state in glue layer ++* ++* \param[in] ++* prGlueInfo ++* eBowState ++* rPeerAddr ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ if (eState == PARAM_MEDIA_STATE_CONNECTED) { ++ prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_CONNECTED; ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_CONNECT=%pM ", rPeerAddr); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++ } else if (eState == PARAM_MEDIA_STATE_DISCONNECTED) { ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_DISCONNECT=%pM ", rPeerAddr); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ } else { ++ ASSERT(0); ++ } ++ ++} /* end of kalP2PSetState() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Wi-Fi Direct operating frequency ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* in unit of KHz ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->u4FreqInKHz; ++} /* end of kalP2PGetFreqInKHz() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to retrieve Bluetooth-over-Wi-Fi role ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* 0: P2P Device ++* 1: Group Client ++* 2: Group Owner ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ ASSERT(prGlueInfo); ++ ++ return prGlueInfo->prP2PInfo->ucRole; ++} /* end of kalP2PGetRole() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set Wi-Fi Direct role ++* ++* \param[in] ++* prGlueInfo ++* ucResult ++* 0: successful ++* 1: error ++* ucRole ++* 0: P2P Device ++* 1: Group Client ++* 2: Group Owner ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(ucRole <= 2); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ if (ucResult == 0) ++ prGlueInfo->prP2PInfo->ucRole = ucRole; ++ ++ if (pucSSID) ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, ++ 1 /* persistence or not */ , pucSSID[7], pucSSID[8]); ++ else ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, ++ 1 /* persistence or not */ , '0', '0'); ++ ++ evt.data.length = strlen(aucBuffer); ++ ++ /* if (pucSSID) */ ++ /* printk("P2P GO SSID DIRECT-%c%c\n", pucSSID[7], pucSSID[8]); */ ++ ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PSetRole() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the cipher for p2p ++* ++* \param[in] ++* prGlueInfo ++* u4Cipher ++* ++* \return ++* none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prGlueInfo->prP2PInfo->u4CipherPairwise = u4Cipher; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the cipher, return for cipher is ccmp ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* TRUE: cipher is ccmp ++* FALSE: cipher is none ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return TRUE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return TRUE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return FALSE; ++ ++ return FALSE; ++} ++ ++BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) ++ return FALSE; ++ ++ if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the status of WSC ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ prGlueInfo->prP2PInfo->ucWSCRunning = ucWscMode; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the status of WSC ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return 0; ++ } ++ ++ return prGlueInfo->prP2PInfo->ucWSCRunning; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to get the wsc ie length ++* ++* \param[in] ++* prGlueInfo ++* ucType : 0 for beacon, 1 for probe req, 2 for probe resp ++* ++* \return ++* The WSC IE length ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType) ++{ ++ ASSERT(prGlueInfo); ++ ++ ASSERT(ucType < 3); ++ ++ return prGlueInfo->prP2PInfo->u2WSCIELen[ucType]; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to copy the wsc ie setting from p2p supplicant ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++* The WPS IE length ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer) ++{ ++ P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (ucType >= 3) || (pucBuffer == NULL)) ++ break; ++ ++ prGlP2pInfo = prGlueInfo->prP2PInfo; ++ ++ kalMemCopy(pucBuffer, prGlP2pInfo->aucWSCIE[ucType], prGlP2pInfo->u2WSCIELen[ucType]); ++ ++ } while (FALSE); ++ ++} ++ ++VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength) ++{ ++ P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (ucType >= 3) || ((u2BufferLength > 0) && (pucBuffer == NULL))) ++ break; ++ ++ if (u2BufferLength > 400) { ++ DBGLOG(P2P, ERROR, ++ "Buffer length is not enough, GLUE only 400 bytes but %d received\n", u2BufferLength); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlP2pInfo = prGlueInfo->prP2PInfo; ++ ++ kalMemCopy(prGlP2pInfo->aucWSCIE[ucType], pucBuffer, u2BufferLength); ++ ++ prGlP2pInfo->u2WSCIELen[ucType] = u2BufferLength; ++ ++ } while (FALSE); ++ ++} /* kalP2PUpdateWSC_IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief indicate an event to supplicant for device connection request ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, ++ IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ ++ IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_REQ_DEVICE_INFO access */ ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength = u4NameLength > 32 ? 32 : u4NameLength; ++ kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, pucDevName, prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, rPeerAddr); ++ prGlueInfo->prP2PInfo->ucConnReqDevType = ucDevType; ++ prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = i4ConfigMethod; ++ prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod = i4ActiveConfigMethod; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_REQ"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateConnReq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for device connection request from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* \param[in] pucGroupBssid Only valid when invitation Type equals to 0. ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_DEVICE_DESC_T prP2pDevDesc, ++ IN PUINT_8 pucSsid, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid) ++{ ++#if 1 ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_STRUCT access */ ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength = ++ (UINT_32) ((prP2pDevDesc->u2NameLength > 32) ? 32 : prP2pDevDesc->u2NameLength); ++ kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, prP2pDevDesc->aucName, ++ prGlueInfo->prP2PInfo->u4ConnReqNameLength); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, prP2pDevDesc->aucDeviceAddr); ++ COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqGroupAddr, pucGroupBssid); ++ prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = (INT_32) (prP2pDevDesc->u2ConfigMethod); ++ prGlueInfo->prP2PInfo->ucOperatingChnl = ucOperatingChnl; ++ prGlueInfo->prP2PInfo->ucInvitationType = ucInvitationType; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_INDICATE"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ return; ++ ++#else ++ P_MSG_P2P_CONNECTION_REQUEST_T prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; ++ P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; ++ P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; ++ ++ do { ++ ASSERT_BREAK((prGlueInfo != NULL) && (prP2pDevDesc != NULL)); ++ ++ /* Not a real solution */ ++ ++ prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; ++ prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; ++ ++ prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, ++ RAM_TYPE_MSG, ++ sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ if (prP2pConnReq == NULL) ++ break; ++ ++ kalMemZero(prP2pConnReq, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); ++ ++ prP2pConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; ++ ++ prP2pConnReq->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; ++ ++ COPY_MAC_ADDR(prP2pConnReq->aucDeviceID, prP2pDevDesc->aucDeviceAddr); ++ ++ prP2pConnReq->u2ConfigMethod = prP2pDevDesc->u2ConfigMethod; ++ ++ if (ucInvitationType == P2P_INVITATION_TYPE_INVITATION) { ++ prP2pConnReq->fgIsPersistentGroup = FALSE; ++ prP2pConnReq->fgIsTobeGO = FALSE; ++ ++ } ++ ++ else if (ucInvitationType == P2P_INVITATION_TYPE_REINVOKE) { ++ DBGLOG(P2P, TRACE, "Re-invoke Persistent Group\n"); ++ prP2pConnReq->fgIsPersistentGroup = TRUE; ++ prP2pConnReq->fgIsTobeGO = (prGlueInfo->prP2PInfo->ucRole == 2) ? TRUE : FALSE; ++ ++ } ++ ++ p2pFsmRunEventDeviceDiscoveryAbort(prGlueInfo->prAdapter, NULL); ++ ++ if (ucOperatingChnl != 0) ++ prP2pSpecificBssInfo->ucPreferredChannel = ucOperatingChnl; ++ ++ if ((ucSsidLen < 32) && (pucSsid != NULL)) ++ COPY_SSID(prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen, pucSsid, ucSsidLen); ++ ++ mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pConnReq, MSG_SEND_METHOD_BUF); ++ ++ } while (FALSE); ++ ++ /* frog add. */ ++ /* TODO: Invitation Indication */ ++ ++ return; ++#endif ++ ++} /* kalP2PInvitationIndication */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an status to supplicant for device invitation status. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ /* buffer peer information for later IOC_P2P_GET_STRUCT access */ ++ prGlueInfo->prP2PInfo->u4InvStatus = u4InvStatus; ++ ++ /* prepare event structure */ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_STATUS"); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate in IWEVCUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* kalP2PInvitationStatus */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery request from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_REQ %d", ucSeqNum); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDRequest() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery response ++* from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_RESP %d", ucSeqNum); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDResponse() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Indicate an event to supplicant for Service Discovery TX Done ++* from other device. ++* ++* \param[in] prGlueInfo Pointer of GLUE_INFO_T ++* \param[in] ucSeqNum Sequence number of the frame ++* \param[in] ucStatus Status code for TX ++* ++* \retval none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_XMITTED: %d %d", ucSeqNum, ucStatus); ++ evt.data.length = strlen(aucBuffer); ++ ++ /* indicate IWEVP2PSDREQ event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++ ++} /* end of kalP2PIndicateSDResponse() */ ++ ++struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return NULL; ++ } ++ ++ return prGlueInfo->prP2PInfo->prDevHandler; ++} ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen) ++{ ++ union iwreq_data evt; ++ UINT_8 aucBuffer[IW_CUSTOM_MAX]; ++ ++ ASSERT(prGlueInfo); ++ ++ memset(&evt, 0, sizeof(evt)); ++ snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SEC_CHECK_RSP="); ++ ++ kalMemCopy(prGlueInfo->prP2PInfo->aucSecCheckRsp, pucRsp, u2RspLen); ++ evt.data.length = strlen(aucBuffer); ++ ++#if DBG ++ DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u2RspLen); ++#endif ++ /* indicate in IWECUSTOM event */ ++ wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); ++} /* p2pFsmRunEventRxDisassociation */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ++* ++* \param[in] prAdapter Pointer of ADAPTER_T ++* ++* \return none ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) ++{ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, ++ pucNumOfChannel, paucChannelList); ++} /* kalGetChnlList */ ++ ++/* ////////////////////////////////////ICS SUPPORT////////////////////////////////////// */ ++ ++VOID ++kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8SeqNum, ++ IN UINT_32 u4ChannelNum, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration) ++{ ++ struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; ++ RF_CHANNEL_INFO_T rChannelInfo; ++ enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; ++ ++ do { ++ if (prGlueInfo == NULL) ++ break; ++ ++ kalMemZero(&rChannelInfo, sizeof(RF_CHANNEL_INFO_T)); ++ ++ rChannelInfo.ucChannelNum = u4ChannelNum; ++ rChannelInfo.eBand = eBand; ++ ++ prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueInfo->prP2PInfo, &rChannelInfo); ++ ++ kalP2pFuncGetChannelType(eSco, &eChnlType); ++ ++ cfg80211_ready_on_channel(prGlueInfo->prP2PInfo->prWdev, /* struct wireless_dev, */ ++ u8SeqNum, /* u64 cookie, */ ++ prIEEE80211ChnlStruct, /* struct ieee80211_channel * chan, */ ++ u4Duration, /* unsigned int duration, */ ++ GFP_KERNEL); /* gfp_t gfp */ /* allocation flags */ ++ } while (FALSE); ++ ++} /* kalP2PIndicateChannelReady */ ++ ++VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) ++{ ++ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; ++ enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; ++ RF_CHANNEL_INFO_T rRfChannelInfo; ++ ++ do { ++ if ((prGlueInfo == NULL) || (prChnlReqInfo == NULL)) { ++ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "kalP2PIndicateChannelExpired\n"); ++ ++ rRfChannelInfo.eBand = prChnlReqInfo->eBand; ++ rRfChannelInfo.ucChannelNum = prChnlReqInfo->ucReqChnlNum; ++ ++ prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueP2pInfo, &rRfChannelInfo); ++ ++ kalP2pFuncGetChannelType(prChnlReqInfo->eChnlSco, &eChnlType); ++ ++ cfg80211_remain_on_channel_expired(prGlueP2pInfo->prWdev, /* struct wireless_dev, */ ++ prChnlReqInfo->u8Cookie, prIEEE80211ChnlStruct, GFP_KERNEL); ++ } while (FALSE); ++ ++} /* kalP2PIndicateChannelExpired */ ++ ++VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct cfg80211_scan_request *prScanRequest = NULL; ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ do { ++ if (prGlueInfo == NULL) { ++ ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ DBGLOG(INIT, TRACE, "[p2p] scan complete %p\n", prGlueP2pInfo->prScanRequest); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ if (prGlueP2pInfo->prScanRequest != NULL) { ++ prScanRequest = prGlueP2pInfo->prScanRequest; ++ prGlueP2pInfo->prScanRequest = NULL; ++ } ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); ++ ++ /* 2. then CFG80211 Indication */ ++ ++ if (prScanRequest != NULL) { ++ ++ /* report all queued beacon/probe response frames to upper layer */ ++ scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_P2P_DEVICE, NULL); ++ ++ info.aborted = fgIsAbort; ++ DBGLOG(INIT, TRACE, "DBG:p2p_cfg_scan_done\n"); ++ cfg80211_scan_done(prScanRequest, &info); ++ } ++ ++ } while (FALSE); ++ ++} /* kalP2PIndicateScanDone */ ++ ++VOID ++kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, ++ IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ struct ieee80211_channel *prChannelEntry = (struct ieee80211_channel *)NULL; ++ struct ieee80211_mgmt *prBcnProbeRspFrame = (struct ieee80211_mgmt *)pucFrameBuf; ++ struct cfg80211_bss *prCfg80211Bss = (struct cfg80211_bss *)NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (prChannelInfo == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prGlueP2pInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prChannelEntry = kalP2pFuncGetChannelEntry(prGlueP2pInfo, prChannelInfo); ++ ++ if (prChannelEntry == NULL) { ++ DBGLOG(P2P, WARN, "Unknown channel info\n"); ++ break; ++ } ++ /* rChannelInfo.center_freq = nicChannelNum2Freq((UINT_32)prChannelInfo->ucChannelNum) / 1000; */ ++ ++ prCfg80211Bss = cfg80211_inform_bss_frame(prGlueP2pInfo->prWdev->wiphy, /* struct wiphy * wiphy, */ ++ prChannelEntry, ++ prBcnProbeRspFrame, u4BufLen, i4SignalStrength, GFP_KERNEL); ++ ++ /* Return this structure. */ ++ if (!prCfg80211Bss) { ++ DBGLOG(P2P, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", ++ prChannelInfo->ucChannelNum, i4SignalStrength); ++ } else { ++ cfg80211_put_bss(prGlueP2pInfo->prWdev->wiphy, prCfg80211Bss); ++ DBGLOG(P2P, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", ++ prChannelInfo->ucChannelNum, i4SignalStrength); ++ } ++ } while (FALSE); ++ ++} /* kalP2PIndicateBssInfo */ ++ ++VOID ++kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { ++ DBGLOG(P2P, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", ++ prGlueInfo, pucFrameBuf, u4FrameLen); ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ cfg80211_mgmt_tx_status(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ ++ u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); ++ ++ } while (FALSE); ++ ++} /* kalP2PIndicateMgmtTxStatus */ ++ ++VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) ++{ ++#define DBG_P2P_MGMT_FRAME_INDICATION 0 ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ INT_32 i4Freq = 0; ++ UINT_8 ucChnlNum = 0; ++#if DBG_P2P_MGMT_FRAME_INDICATION ++ P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; ++#endif ++ ++ do { ++ if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; ++ ++#if DBG_P2P_MGMT_FRAME_INDICATION ++ ++ prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; ++ ++ switch (prWlanHeader->u2FrameCtrl) { ++ case MAC_FRAME_PROBE_REQ: ++ DBGLOG(P2P, TRACE, "RX Probe Req at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_PROBE_RSP: ++ DBGLOG(P2P, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); ++ break; ++ case MAC_FRAME_ACTION: ++ DBGLOG(P2P, TRACE, "RX Action frame at channel %d ", ucChnlNum); ++ break; ++ default: ++ DBGLOG(P2P, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); ++ break; ++ } ++ ++ DBGLOG(P2P, TRACE, "from: %pM\n", prWlanHeader->aucAddr2); ++#endif ++ i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; ++ ++ cfg80211_rx_mgmt(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ ++ i4Freq, ++ RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), ++ prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_ATOMIC); ++ } while (FALSE); ++ ++} /* kalP2PIndicateRxMgmtFrame */ ++ ++VOID ++kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, ++ IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, ++ IN WLAN_STATUS eStatus) ++{ ++ P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; ++ ++ do { ++ if (prGlueInfo == NULL) { ++ ASSERT(FALSE); ++ break; ++ } ++ ++ prGlueP2pInfo = prGlueInfo->prP2PInfo; ++ ++ if (prP2pConnInfo) { ++ cfg80211_connect_result(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ ++ prP2pConnInfo->aucBssid, prP2pConnInfo->aucIEBuf, ++ prP2pConnInfo->u4BufLength, ++ pucRxIEBuf, u2RxIELen, u2StatusReason, GFP_KERNEL); ++ /* gfp_t gfp */ /* allocation flags */ ++ prP2pConnInfo->fgIsConnRequest = FALSE; ++ } else { ++ /* Disconnect, what if u2StatusReason == 0? */ ++ cfg80211_disconnected(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ ++ u2StatusReason, pucRxIEBuf, u2RxIELen, ++ eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ? true : false, ++ GFP_KERNEL); ++ } ++ ++ } while (FALSE); ++ ++} /* kalP2PGCIndicateConnectionStatus */ ++ ++VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew) ++{ ++ P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; ++ struct station_info rStationInfo; ++ ++ memset(&rStationInfo, 0, sizeof(struct station_info)); ++ ++ do { ++ if ((prGlueInfo == NULL) || (prCliStaRec == NULL)) ++ break; ++ ++ prP2pGlueInfo = prGlueInfo->prP2PInfo; ++ ++ if (fgIsNew) { ++ //rStationInfo.filled = STATION_INFO_ASSOC_REQ_IES; ++ rStationInfo.generation = ++prP2pGlueInfo->i4Generation; ++ ++ rStationInfo.assoc_req_ies = prCliStaRec->pucAssocReqIe; ++ rStationInfo.assoc_req_ies_len = prCliStaRec->u2AssocReqIeLen; ++/* rStationInfo.filled |= STATION_INFO_ASSOC_REQ_IES; */ ++ ++ cfg80211_new_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ ++ prCliStaRec->aucMacAddr, &rStationInfo, GFP_KERNEL); ++ } else { ++ ++prP2pGlueInfo->i4Generation; ++ ++ cfg80211_del_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ ++ prCliStaRec->aucMacAddr, GFP_KERNEL); ++ } ++ ++ } while (FALSE); ++ ++ return; ++ ++} /* kalP2PGOStationUpdate */ ++ ++BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type) ++{ ++ BOOLEAN fgIsValid = FALSE; ++ ++ do { ++ if (channel_type) { ++ ++ switch (rChnlSco) { ++ case CHNL_EXT_SCN: ++ *channel_type = NL80211_CHAN_NO_HT; ++ break; ++ case CHNL_EXT_SCA: ++ *channel_type = NL80211_CHAN_HT40MINUS; ++ break; ++ case CHNL_EXT_SCB: ++ *channel_type = NL80211_CHAN_HT40PLUS; ++ break; ++ default: ++ ASSERT(FALSE); ++ *channel_type = NL80211_CHAN_NO_HT; ++ break; ++ } ++ ++ } ++ ++ fgIsValid = TRUE; ++ } while (FALSE); ++ ++ return fgIsValid; ++} /* kalP2pFuncGetChannelType */ ++ ++struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo) ++{ ++ struct ieee80211_channel *prTargetChannelEntry = (struct ieee80211_channel *)NULL; ++ UINT_32 u4TblSize = 0, u4Idx = 0; ++ struct ieee80211_supported_band **bands; ++ ++ do { ++ if ((prP2pInfo == NULL) || (prChannelInfo == NULL)) ++ break; ++ bands = &prP2pInfo->prWdev->wiphy->bands[0]; ++ switch (prChannelInfo->eBand) { ++ case BAND_2G4: ++ prTargetChannelEntry = bands[NL80211_BAND_2GHZ]->channels; ++ u4TblSize = bands[NL80211_BAND_2GHZ]->n_channels; ++ break; ++ case BAND_5G: ++ prTargetChannelEntry = bands[NL80211_BAND_5GHZ]->channels; ++ u4TblSize = bands[NL80211_BAND_5GHZ]->n_channels; ++ break; ++ default: ++ break; ++ } ++ ++ if (prTargetChannelEntry == NULL) ++ break; ++ ++ for (u4Idx = 0; u4Idx < u4TblSize; u4Idx++, prTargetChannelEntry++) { ++ if (prTargetChannelEntry->hw_value == prChannelInfo->ucChannelNum) ++ break; ++ } ++ ++ if (u4Idx == u4TblSize) { ++ prTargetChannelEntry = NULL; ++ break; ++ } ++ ++ } while (FALSE); ++ ++ return prTargetChannelEntry; ++} /* kalP2pFuncGetChannelEntry */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to set the block list of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock) ++{ ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->prP2PInfo); ++ ++ if (EQUAL_MAC_ADDR(rbssid, aucNullAddr)) ++ return -EINVAL; ++ ++ if (fgIsblock) { ++ for (i = 0; i < 8; i++) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ break; ++ } else if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr)) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid); ++ break; ++ } ++ } ++ if (i >= 8) { ++ DBGLOG(P2P, ERROR, "AP black list is full, cannot block more STA!!\n"); ++ return -ENOBUFS; ++ } ++ } else { ++ for (i = 0; i < 8; i++) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr); ++ break; ++ } ++ } ++ if (i >= 8) ++ DBGLOG(P2P, ERROR, "The STA is not found in black list!!\n"); ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to compare the black list of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid) ++{ ++ UINT_8 aucNullAddr[] = NULL_MAC_ADDR; ++ BOOLEAN fgIsExsit = FALSE; ++ UINT_32 i; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(prGlueInfo->prP2PInfo); ++ ++ for (i = 0; i < 8; i++) { ++ if (UNEQUAL_MAC_ADDR(rbssid, aucNullAddr)) { ++ if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { ++ fgIsExsit = TRUE; ++ return fgIsExsit; ++ } ++ } ++ } ++ ++ return fgIsExsit; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to return the max clients of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return; ++ } ++ ++ if (u4MaxClient == 0 || prGlueInfo->prP2PInfo->ucMaxClients >= P2P_MAXIMUM_CLIENT_COUNT) ++ prGlueInfo->prP2PInfo->ucMaxClients = P2P_MAXIMUM_CLIENT_COUNT; ++ else ++ prGlueInfo->prP2PInfo->ucMaxClients = u4MaxClient; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief to return the max clients of Hotspot ++* ++* \param[in] ++* prGlueInfo ++* ++* \return ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient) ++{ ++ if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { ++ ASSERT(FALSE); ++ return FALSE; ++ } ++ ++ if (prGlueInfo->prP2PInfo->ucMaxClients) { ++ if ((UINT_8) u4NumClient > prGlueInfo->prP2PInfo->ucMaxClients) ++ return TRUE; ++ else ++ return FALSE; ++ } ++ ++ return FALSE; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c +new file mode 100644 +index 000000000000..075045f547b7 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c +@@ -0,0 +1,1020 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_proc.c#1 ++*/ ++ ++/*! \file "gl_proc.c" ++ \brief This file defines the interface which can interact with users in /proc fs. ++ ++ Detail description. ++*/ ++ ++/* ++** Log: gl_proc.c ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++** \main\maintrunk.MT5921\19 2008-09-02 21:08:37 GMT mtk01461 ++** Fix the compile error of SPRINTF() ++** \main\maintrunk.MT5921\18 2008-08-10 18:48:28 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\17 2008-08-04 16:52:01 GMT mtk01461 ++** Add proc dbg print message of DOMAIN_INDEX level ++** \main\maintrunk.MT5921\16 2008-07-10 00:45:16 GMT mtk01461 ++** Remove the check of MCR offset, we may use the MCR address which is not align to DW boundary or proprietary usage. ++** \main\maintrunk.MT5921\15 2008-06-03 20:49:44 GMT mtk01461 ++** \main\maintrunk.MT5921\14 2008-06-02 22:56:00 GMT mtk01461 ++** Rename some functions for linux proc ++** \main\maintrunk.MT5921\13 2008-06-02 20:23:18 GMT mtk01461 ++** Revise PROC mcr read / write for supporting TELNET ++** \main\maintrunk.MT5921\12 2008-03-28 10:40:25 GMT mtk01461 ++** Remove temporary set desired rate in linux proc ++** \main\maintrunk.MT5921\11 2008-01-07 15:07:29 GMT mtk01461 ++** Add User Update Desired Rate Set for QA in Linux ++** \main\maintrunk.MT5921\10 2007-12-11 00:11:14 GMT mtk01461 ++** Fix SPIN_LOCK protection ++** \main\maintrunk.MT5921\9 2007-12-04 18:07:57 GMT mtk01461 ++** Add additional debug category to proc ++** \main\maintrunk.MT5921\8 2007-11-02 01:03:23 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** \main\maintrunk.MT5921\7 2007-10-25 18:08:14 GMT mtk01461 ++** Add VOIP SCAN Support & Refine Roaming ++** Revision 1.3 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.2 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "precomp.h" ++ ++/* #include "wlan_lib.h" */ ++/* #include "debug.h" */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#define PROC_WLAN_THERMO "wlanThermo" ++#define PROC_DRV_STATUS "status" ++#define PROC_RX_STATISTICS "rx_statistics" ++#define PROC_TX_STATISTICS "tx_statistics" ++#define PROC_DBG_LEVEL_NAME "dbgLevel" ++#define PROC_NEED_TX_DONE "TxDoneCfg" ++#define PROC_AUTO_PER_CFG "autoPerCfg" ++#define PROC_ROOT_NAME "wlan" ++#define PROC_CMD_DEBUG_NAME "cmdDebug" ++ ++#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20 ++#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10 ++#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10 ++#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN (20*10) ++#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 8 ++ ++#define PROC_UID_SHELL 2000 ++#define PROC_GID_WIFI 1010 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++/* static UINT_32 u4McrOffset; */ ++#if CFG_SUPPORT_THERMO_THROTTLING ++static P_GLUE_INFO_T g_prGlueInfo_proc; ++#endif ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading MCR register to User Space, the offset of ++* the MCR is specified in u4McrOffset. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++#if 0 ++static int procMCRRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; ++ UINT_32 u4BufLen; ++ char *p = page; ++ UINT_32 u4Count; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); ++ ++ rMcrInfo.u4McrOffset = u4McrOffset; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryMcrRead, ++ (PVOID)&rMcrInfo, sizeof(rMcrInfo), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ ++ /* SPRINTF(p, ("MCR (0x%08lxh): 0x%08lx\n", */ ++ /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData)); */ ++ ++ u4Count = (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procMCRRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for writing MCR register to HW or update u4McrOffset ++* for reading MCR later. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procMCRWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ int i4CopySize; ++ PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(data); ++ ++ i4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ if (copy_from_user(acBuf, buffer, i4CopySize)) ++ return 0; ++ acBuf[i4CopySize] = '\0'; ++ ++ if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 2) { ++ /* NOTE: Sometimes we want to test if bus will still be ok, after accessing ++ * the MCR which is not align to DW boundary. ++ */ ++ /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); ++ ++ u4McrOffset = rMcrInfo.u4McrOffset; ++ ++ /* printk("Write 0x%lx to MCR 0x%04lx\n", */ ++ /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetMcrWrite, ++ (PVOID)&rMcrInfo, sizeof(rMcrInfo), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ ++ if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 1) { ++ /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ ++ u4McrOffset = rMcrInfo.u4McrOffset; ++ } ++ ++ return count; ++ ++} /* end of procMCRWrite() */ ++#endif ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver Status to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procDrvStatusRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("GLUE LAYER STATUS:")); ++ SPRINTF(p, ("\n==================")); ++ ++ SPRINTF(p, ("\n* Number of Pending Frames: %ld\n", prGlueInfo->u4TxPendingFrameNum)); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryDrvStatusForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procDrvStatusRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver RX Statistic Counters to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procRxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("RX STATISTICS (Write 1 to clear):")); ++ SPRINTF(p, ("\n=================================\n")); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryRxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procRxStatisticsRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reset Driver RX Statistic Counters. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procRxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ UINT_32 u4ClearCounter; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ copy_from_user(acBuf, buffer, u4CopySize); ++ acBuf[u4CopySize] = '\0'; ++ ++ if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { ++ if (u4ClearCounter == 1) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidSetRxStatisticsForLinuxProc(prGlueInfo->prAdapter); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ } ++ } ++ ++ return count; ++ ++} /* end of procRxStatisticsWrite() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reading Driver TX Statistic Counters to User Space. ++* ++* \param[in] page Buffer provided by kernel. ++* \param[in out] start Start Address to read(3 methods). ++* \param[in] off Offset. ++* \param[in] count Allowable number to read. ++* \param[out] eof End of File indication. ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters print to the buffer from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procTxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char *p = page; ++ UINT_32 u4Count; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ /* Kevin: Apply PROC read method 1. */ ++ if (off != 0) ++ return 0; /* To indicate end of file. */ ++ ++ SPRINTF(p, ("TX STATISTICS (Write 1 to clear):")); ++ SPRINTF(p, ("\n=================================\n")); ++ ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidQueryTxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ u4Count += (UINT_32) (p - page); ++ ++ *eof = 1; ++ ++ return (int)u4Count; ++ ++} /* end of procTxStatisticsRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The PROC function for reset Driver TX Statistic Counters. ++* ++* \param[in] file pointer to file. ++* \param[in] buffer Buffer from user space. ++* \param[in] count Number of characters to write ++* \param[in] data Pointer to the private data structure. ++* ++* \return number of characters write from User Space. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int procTxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; ++ char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ ++ UINT_32 u4CopySize; ++ UINT_32 u4ClearCounter; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ ASSERT(data); ++ ++ u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); ++ copy_from_user(acBuf, buffer, u4CopySize); ++ acBuf[u4CopySize] = '\0'; ++ ++ if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { ++ if (u4ClearCounter == 1) { ++ GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ ++ wlanoidSetTxStatisticsForLinuxProc(prGlueInfo->prAdapter); ++ ++ GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); ++ } ++ } ++ ++ return count; ++ ++} /* end of procTxStatisticsWrite() */ ++#endif ++static struct proc_dir_entry *gprProcRoot; ++static UINT_8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = { ++ "INIT", "HAL", "INTR", "REQ", "TX", "RX", "RFTEST", "EMU", "SW1", "SW2", ++ "SW3", "SW4", "HEM", "AIS", "RLM", "MEM", "CNM", "RSN", "BSS", "SCN", ++ "SAA", "AAA", "P2P", "QM", "SEC", "BOW", "WAPI", "ROAMING", "TDLS", "OID", ++ "NIC" ++}; ++static UINT_8 aucProcBuf[1536]; ++static ssize_t procDbgLevelRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ UINT_16 i; ++ UINT_16 u2ModuleNum = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ kalStrCpy(temp, "\nTEMP |LOUD |INFO |TRACE|EVENT|STATE|WARN |ERROR\n" ++ "bit7 |bit6 |bit5 |bit4 |bit3 |bit2 |bit1 |bit0\n\n" ++ "Debug Module\tIndex\tLevel\tDebug Module\tIndex\tLevel\n\n"); ++ temp += kalStrLen(temp); ++ ++ u2ModuleNum = (sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0xfe; ++ for (i = 0; i < u2ModuleNum; i += 2) ++ SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\tDBG_%s_IDX\t(0x%02x):\t0x%02x\n", ++ &aucDbModuleName[i][0], i, aucDebugModule[i], ++ &aucDbModuleName[i+1][0], i+1, aucDebugModule[i+1])); ++ ++ if ((sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0x1) ++ SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\n", ++ &aucDbModuleName[u2ModuleNum][0], u2ModuleNum, aucDebugModule[u2ModuleNum])); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procDbgLevelWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++ UINT_32 u4NewDbgModule, u4NewDbgLevel; ++ UINT_8 i = 0; ++ UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); ++ UINT_8 *temp = &aucProcBuf[0]; ++ ++ if (u4CopySize >= count + 1) ++ u4CopySize = count; ++ ++ kalMemSet(aucProcBuf, 0, u4CopySize); ++ ++ if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { ++ kalPrint("error of copy from user\n"); ++ return -EFAULT; ++ } ++ aucProcBuf[u4CopySize] = '\0'; ++ ++ while (temp) { ++ if (sscanf(temp, "0x%x:0x%x", &u4NewDbgModule, &u4NewDbgLevel) != 2) { ++ kalPrint("debug module and debug level should be one byte in length\n"); ++ break; ++ } ++ if (u4NewDbgModule == 0xFF) { ++ for (i = 0; i < DBG_MODULE_NUM; i++) ++ aucDebugModule[i] = u4NewDbgLevel & DBG_CLASS_MASK; ++ ++ break; ++ } else if (u4NewDbgModule >= DBG_MODULE_NUM) { ++ kalPrint("debug module index should less than %d\n", DBG_MODULE_NUM); ++ break; ++ } ++ aucDebugModule[u4NewDbgModule] = u4NewDbgLevel & DBG_CLASS_MASK; ++ temp = kalStrChr(temp, ','); ++ if (!temp) ++ break; ++ temp++; /* skip ',' */ ++ } ++ return count; ++} ++ ++ ++static const struct file_operations dbglevel_ops = { ++ .owner = THIS_MODULE, ++ .read = procDbgLevelRead, ++ .write = procDbgLevelWrite, ++}; ++ ++static ssize_t procTxDoneCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ UINT_16 u2TxDoneCfg = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ u2TxDoneCfg = StatsGetCfgTxDone(); ++ SPRINTF(temp, ("Tx Done Configure:\nARP %d\tDNS %d\nTCP %d\tUDP %d\nEAPOL %d\tDHCP %d\nICMP %d\n", ++ !!(u2TxDoneCfg & CFG_ARP), !!(u2TxDoneCfg & CFG_DNS), !!(u2TxDoneCfg & CFG_TCP), ++ !!(u2TxDoneCfg & CFG_UDP), !!(u2TxDoneCfg & CFG_EAPOL), !!(u2TxDoneCfg & CFG_DHCP), ++ !!(u2TxDoneCfg & CFG_ICMP))); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procTxDoneCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++#define MODULE_NAME_LENGTH 6 ++ ++ UINT_8 i = 0; ++ UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_16 u2SetTxDoneCfg = 0; ++ UINT_16 u2ClsTxDoneCfg = 0; ++ UINT_8 aucModule[MODULE_NAME_LENGTH]; ++ UINT_32 u4Enabled; ++ UINT_8 aucModuleArray[][MODULE_NAME_LENGTH] = {"ARP", "DNS", "TCP", "UDP", "EAPOL", "DHCP", "ICMP"}; ++ ++ if (u4CopySize >= count + 1) ++ u4CopySize = count; ++ ++ kalMemSet(aucProcBuf, 0, u4CopySize); ++ if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { ++ kalPrint("error of copy from user\n"); ++ return -EFAULT; ++ } ++ aucProcBuf[u4CopySize] = '\0'; ++ temp = &aucProcBuf[0]; ++ while (temp) { ++ /* pick up a string and teminated after meet : */ ++ if (sscanf(temp, "%s %d", aucModule, &u4Enabled) != 2) { ++ kalPrint("read param fail, aucModule=%s\n", aucModule); ++ break; ++ } ++ for (i = 0; i < sizeof(aucModuleArray)/MODULE_NAME_LENGTH; i++) { ++ if (kalStrniCmp(aucModule, aucModuleArray[i], MODULE_NAME_LENGTH) == 0) { ++ if (u4Enabled) ++ u2SetTxDoneCfg |= 1 << i; ++ else ++ u2ClsTxDoneCfg |= 1 << i; ++ break; ++ } ++ } ++ temp = kalStrChr(temp, ','); ++ if (!temp) ++ break; ++ temp++; /* skip ',' */ ++ } ++ if (u2SetTxDoneCfg) ++ StatsSetCfgTxDone(u2SetTxDoneCfg, TRUE); ++ ++ if (u2ClsTxDoneCfg) ++ StatsSetCfgTxDone(u2ClsTxDoneCfg, FALSE); ++ return count; ++} ++ ++static const struct file_operations proc_txdone_ops = { ++ .owner = THIS_MODULE, ++ .read = procTxDoneCfgRead, ++ .write = procTxDoneCfgWrite, ++}; ++ ++static ssize_t procAutoPerCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_8 *temp = &aucProcBuf[0]; ++ UINT_32 u4CopySize = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ SPRINTF(temp, ("Auto Performance Configure:\nperiod\tL1\nL2\tL3\n")); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static ssize_t procAutoPerCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) ++{ ++ DBGLOG(INIT, WARN, "%s\n", __func__); ++ return 0; ++} ++ ++static const struct file_operations auto_per_ops = { ++ .owner = THIS_MODULE, ++ .read = procAutoPerCfgRead, ++ .write = procAutoPerCfgWrite, ++}; ++ ++ ++static ssize_t procCmdDebug(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ UINT_32 u4CopySize = 0; ++ ++ /* if *f_ops>0, we should return 0 to make cat command exit */ ++ if (*f_pos > 0) ++ return 0; ++ ++ wlanDumpTcResAndTxedCmd(aucProcBuf, sizeof(aucProcBuf)); ++ ++ u4CopySize = kalStrLen(aucProcBuf); ++ if (u4CopySize > count) ++ u4CopySize = count; ++ if (copy_to_user(buf, aucProcBuf, u4CopySize)) { ++ kalPrint("copy to user failed\n"); ++ return -EFAULT; ++ } ++ ++ *f_pos += u4CopySize; ++ return (ssize_t)u4CopySize; ++} ++ ++static const struct file_operations proc_CmdDebug_ops = { ++ .owner = THIS_MODULE, ++ .read = procCmdDebug, ++}; ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function create a PROC fs in linux /proc/net subdirectory. ++* ++* \param[in] prDev Pointer to the struct net_device. ++* \param[in] pucDevName Pointer to the name of net_device. ++* ++* \return N/A ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++#if CFG_SUPPORT_THERMO_THROTTLING ++ ++/** ++ * This function is called then the /proc file is read ++ * ++ */ ++typedef struct _COEX_BUF1 { ++ UINT8 buffer[128]; ++ INT32 availSize; ++} COEX_BUF1, *P_COEX_BUF1; ++ ++COEX_BUF1 gCoexBuf1; ++ ++static ssize_t procfile_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ ++ INT32 retval = 0; ++ INT32 i_ret = 0; ++ CHAR *warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; ++ ++ if (*f_pos > 0) { ++ retval = 0; ++ } else { ++ /*len = sprintf(page, "%d\n", g_psm_enable); */ ++#if 1 ++ if (gCoexBuf1.availSize <= 0) { ++ DBGLOG(INIT, WARN, "no data available\n"); ++ retval = strlen(warn_msg) + 1; ++ if (count < retval) ++ retval = count; ++ i_ret = copy_to_user(buf, warn_msg, retval); ++ if (i_ret) { ++ DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } else ++#endif ++ { ++ INT32 i = 0; ++ INT32 len = 0; ++ CHAR msg_info[128]; ++ INT32 max_num = 0; ++ /*we do not check page buffer, because there are only 100 bytes in g_coex_buf, no reason page ++ buffer is not enough, a bomb is placed here on unexpected condition */ ++ ++ DBGLOG(INIT, TRACE, "%d bytes available\n", gCoexBuf1.availSize); ++ max_num = ((sizeof(msg_info) > count ? sizeof(msg_info) : count) - 1) / 5; ++ ++ if (max_num > gCoexBuf1.availSize) ++ max_num = gCoexBuf1.availSize; ++ else ++ DBGLOG(INIT, TRACE, ++ "round to %d bytes due to local buffer size limitation\n", max_num); ++ ++ for (i = 0; i < max_num; i++) ++ len += sprintf(msg_info + len, "%d", gCoexBuf1.buffer[i]); ++ ++ len += sprintf(msg_info + len, "\n"); ++ retval = len; ++ ++ i_ret = copy_to_user(buf, msg_info, retval); ++ if (i_ret) { ++ DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); ++ retval = -EFAULT; ++ goto err_exit; ++ } ++ *f_pos += retval; ++ } ++ } ++ gCoexBuf1.availSize = 0; ++err_exit: ++ ++ return retval; ++} ++ ++#if 1 ++typedef INT32 (*WLAN_DEV_DBG_FUNC)(void); ++static INT32 wlan_get_thermo_power(void); ++static INT32 wlan_get_link_mode(void); ++ ++static const WLAN_DEV_DBG_FUNC wlan_dev_dbg_func[] = { ++ [0] = wlan_get_thermo_power, ++ [1] = wlan_get_link_mode, ++ ++}; ++ ++INT32 wlan_get_thermo_power(void) ++{ ++ P_ADAPTER_T prAdapter; ++ ++ prAdapter = g_prGlueInfo_proc->prAdapter; ++ ++ if (prAdapter->u4AirDelayTotal > 100) ++ gCoexBuf1.buffer[0] = 100; ++ else ++ gCoexBuf1.buffer[0] = prAdapter->u4AirDelayTotal; ++ gCoexBuf1.availSize = 1; ++ DBGLOG(RLM, TRACE, "PROC %s thrmo_power(%d)\n", __func__, gCoexBuf1.buffer[0]); ++ ++ return 0; ++} ++ ++INT32 wlan_get_link_mode(void) ++{ ++ UINT_8 ucLinkMode = 0; ++ P_ADAPTER_T prAdapter; ++ BOOLEAN fgIsAPmode; ++ ++ prAdapter = g_prGlueInfo_proc->prAdapter; ++ fgIsAPmode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); ++ ++ DBGLOG(RLM, TRACE, "PROC %s AIS(%d)P2P(%d)AP(%d)\n", ++ __func__, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState, ++ prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState, fgIsAPmode); ++ ++#if 1 ++ ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ ucLinkMode |= BIT(0); ++ if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) ++ ucLinkMode |= BIT(1); ++ if (fgIsAPmode) ++ ucLinkMode |= BIT(2); ++ ++#endif ++ gCoexBuf1.buffer[0] = ucLinkMode; ++ gCoexBuf1.availSize = 1; ++ ++ return 0; ++} ++ ++static ssize_t procfile_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) ++{ ++ char buf[256]; ++ char *pBuf; ++ ULONG len = count; ++ INT32 x = 0, y = 0, z = 0; ++ char *pToken = NULL; ++ char *pDelimiter = " \t"; ++ INT32 i4Ret = 0; ++ ++ if (copy_from_user(gCoexBuf1.buffer, buffer, count)) ++ return -EFAULT; ++ /* gCoexBuf1.availSize = count; */ ++ ++ /* return gCoexBuf1.availSize; */ ++#if 1 ++ DBGLOG(INIT, TRACE, "write parameter len = %d\n\r", (INT32) len); ++ if (len >= sizeof(buf)) { ++ DBGLOG(INIT, ERROR, "input handling fail!\n"); ++ len = sizeof(buf) - 1; ++ return -1; ++ } ++ ++ if (copy_from_user(buf, buffer, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ DBGLOG(INIT, TRACE, "write parameter data = %s\n\r", buf); ++ ++ pBuf = buf; ++ pToken = strsep(&pBuf, pDelimiter); ++ ++ if (pToken) /* x = NULL != pToken ? simple_strtol(pToken, NULL, 16) : 0; */ ++ i4Ret = kalkStrtos32(pToken, 16, &x); ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "x = 0x%x\n", x); ++ ++#if 1 ++ pToken = strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ i4Ret = kalkStrtos32(pToken, 16, &y); /* y = simple_strtol(pToken, NULL, 16); */ ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "y = 0x%08x\n\r", y); ++ } else { ++ y = 3000; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ y = 0x80000000; ++ } ++ ++ pToken = strsep(&pBuf, "\t\n "); ++ if (pToken != NULL) { ++ i4Ret = kalkStrtos32(pToken, 16, &z); /* z = simple_strtol(pToken, NULL, 16); */ ++ if (!i4Ret) ++ DBGLOG(INIT, TRACE, "z = 0x%08x\n\r", z); ++ } else { ++ z = 10; ++ /*efuse, register read write default value */ ++ if (0x11 == x || 0x12 == x || 0x13 == x) ++ z = 0xffffffff; ++ } ++ ++ DBGLOG(INIT, TRACE, " x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); ++#endif ++ ++ if (((sizeof(wlan_dev_dbg_func) / sizeof(wlan_dev_dbg_func[0])) > x) && NULL != wlan_dev_dbg_func[x]) ++ (*wlan_dev_dbg_func[x]) (); ++ else ++ DBGLOG(INIT, ERROR, "no handler defined for command id(0x%08x)\n\r", x); ++#endif ++ ++ /* len = gCoexBuf1.availSize; */ ++ return len; ++} ++#endif ++ static const struct file_operations proc_fops = { ++ .owner = THIS_MODULE, ++ .read = procfile_read, ++ .write = procfile_write, ++ }; ++#endif ++ ++INT_32 procInitFs(VOID) ++{ ++ struct proc_dir_entry *prEntry; ++ ++ if (init_net.proc_net == (struct proc_dir_entry *)NULL) { ++ kalPrint("init proc fs fail: proc_net == NULL\n"); ++ return -ENOENT; ++ } ++ ++ /* ++ * Directory: Root (/proc/net/wlan0) ++ */ ++ ++ gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net); ++ if (!gprProcRoot) { ++ kalPrint("gprProcRoot == NULL\n"); ++ return -ENOENT; ++ } ++ proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_NEED_TX_DONE, 0664, gprProcRoot, &proc_txdone_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ prEntry = proc_create(PROC_AUTO_PER_CFG, 0664, gprProcRoot, &auto_per_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry autoPerCfg\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ ++ return 0; ++} /* end of procInitProcfs() */ ++ ++INT_32 procUninitProcFs(VOID) ++{ ++ remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot); ++ remove_proc_subtree(PROC_ROOT_NAME, init_net.proc_net); ++ remove_proc_entry(PROC_AUTO_PER_CFG, gprProcRoot); ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clean up a PROC fs created by procInitProcfs(). ++* ++* \param[in] prDev Pointer to the struct net_device. ++* \param[in] pucDevName Pointer to the name of net_device. ++* ++* \return N/A ++*/ ++/*----------------------------------------------------------------------------*/ ++INT_32 procRemoveProcfs(VOID) ++{ ++ /* remove root directory (proc/net/wlan0) */ ++ /* remove_proc_entry(pucDevName, init_net.proc_net); */ ++ remove_proc_entry(PROC_WLAN_THERMO, gprProcRoot); ++ remove_proc_entry(PROC_CMD_DEBUG_NAME, gprProcRoot); ++#if CFG_SUPPORT_THERMO_THROTTLING ++ g_prGlueInfo_proc = NULL; ++#endif ++ return 0; ++} /* end of procRemoveProcfs() */ ++ ++INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo) ++{ ++ struct proc_dir_entry *prEntry; ++ ++ DBGLOG(INIT, TRACE, "[%s]\n", __func__); ++ ++#if CFG_SUPPORT_THERMO_THROTTLING ++ g_prGlueInfo_proc = prGlueInfo; ++#endif ++ ++ prGlueInfo->pProcRoot = gprProcRoot; ++ ++ prEntry = proc_create(PROC_WLAN_THERMO, 0664, gprProcRoot, &proc_fops); ++ if (prEntry == NULL) { ++ DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r"); ++ return -1; ++ } ++ ++ prEntry = proc_create(PROC_CMD_DEBUG_NAME, 0444, gprProcRoot, &proc_CmdDebug_ops); ++ if (prEntry == NULL) { ++ kalPrint("Unable to create /proc entry dbgLevel\n\r"); ++ return -1; ++ } ++ proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); ++ return 0; ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +new file mode 100644 +index 000000000000..f97db8a69fd2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +@@ -0,0 +1,228 @@ ++/* ++** Id: @(#) gl_rst.c@@ ++*/ ++ ++/*! \file gl_rst.c ++ \brief Main routines for supporintg MT6620 whole-chip reset mechanism ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_rst.c ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 04 22 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * skip power-off handshaking when RESET indication is received. ++ * ++ * 04 14 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected ++ * 2. add dummy function for both Win32 and Linux part. ++ * ++ * 03 30 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * use netlink unicast instead of broadcast ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++ ++#include "precomp.h" ++#include "gl_rst.h" ++ ++#if CFG_CHIP_RESET_SUPPORT ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++BOOLEAN fgIsResetting = FALSE; ++UINT_32 g_IsNeedDoChipReset = 0; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static RESET_STRUCT_T wifi_rst; ++ ++static void mtk_wifi_reset(struct work_struct *work); ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, ++ ENUM_WMTDRV_TYPE_T eDstType, ++ ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for ++ * 1. register wifi reset callback ++ * 2. initialize wifi reset work ++ * ++ * @param none ++ * ++ * @retval none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glResetInit(VOID) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ /* 1. Register reset callback */ ++ mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_WIFI, (PF_WMT_CB) glResetCallback); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++ /* 2. Initialize reset work */ ++ INIT_WORK(&(wifi_rst.rst_work), mtk_wifi_reset); ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is responsible for ++ * 1. deregister wifi reset callback ++ * ++ * @param none ++ * ++ * @retval none ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glResetUninit(VOID) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ /* 1. Deregister reset callback */ ++ mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_WIFI); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is invoked when there is reset messages indicated ++ * ++ * @param eSrcType ++ * eDstType ++ * eMsgType ++ * prMsgBody ++ * u4MsgLength ++ * ++ * @retval ++ */ ++/*----------------------------------------------------------------------------*/ ++static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, ++ ENUM_WMTDRV_TYPE_T eDstType, ++ ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength) ++{ ++ switch (eMsgType) { ++ case WMTMSG_TYPE_RESET: ++ if (u4MsgLength == sizeof(ENUM_WMTRSTMSG_TYPE_T)) { ++ P_ENUM_WMTRSTMSG_TYPE_T prRstMsg = (P_ENUM_WMTRSTMSG_TYPE_T) prMsgBody; ++ ++ switch (*prRstMsg) { ++ case WMTRSTMSG_RESET_START: ++ DBGLOG(INIT, WARN, "Whole chip reset start!\n"); ++ fgIsResetting = TRUE; ++ wifi_reset_start(); ++ break; ++ ++ case WMTRSTMSG_RESET_END: ++ DBGLOG(INIT, WARN, "Whole chip reset end!\n"); ++ fgIsResetting = FALSE; ++ wifi_rst.rst_data = RESET_SUCCESS; ++ schedule_work(&(wifi_rst.rst_work)); ++ break; ++ ++ case WMTRSTMSG_RESET_END_FAIL: ++ DBGLOG(INIT, WARN, "Whole chip reset fail!\n"); ++ fgIsResetting = FALSE; ++ wifi_rst.rst_data = RESET_FAIL; ++ schedule_work(&(wifi_rst.rst_work)); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for wifi reset ++ * ++ * @param skb ++ * info ++ * ++ * @retval 0 ++ * nonzero ++ */ ++/*----------------------------------------------------------------------------*/ ++static void mtk_wifi_reset(struct work_struct *work) ++{ ++ RESET_STRUCT_T *rst = container_of(work, RESET_STRUCT_T, rst_work); ++ ++ wifi_reset_end(rst->rst_data); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for generating reset request to WMT ++ * ++ * @param None ++ * ++ * @retval None ++ */ ++/*----------------------------------------------------------------------------*/ ++VOID glSendResetRequest(VOID) ++{ ++ /* WMT thread would trigger whole chip reset itself */ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++ * @brief This routine is called for checking if connectivity chip is resetting ++ * ++ * @param None ++ * ++ * @retval TRUE ++ * FALSE ++ */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsResetting(VOID) ++{ ++ return fgIsResetting; ++} ++ ++#endif /* CFG_CHIP_RESET_SUPPORT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c +new file mode 100644 +index 000000000000..862d011a43df +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c +@@ -0,0 +1,1220 @@ ++/* ++** Id: @(#) gl_cfg80211.c@@ ++*/ ++ ++/*! \file gl_cfg80211.c ++ \brief Main routines for supporintg MT6620 cfg80211 control interface ++ ++ This file contains the support routines of Linux driver for MediaTek Inc. 802.11 ++ Wireless LAN Adapters. ++*/ ++ ++/* ++** Log: gl_cfg80211.c ++** ++** 09 05 2013 cp.wu ++** correct length to pass to wlanoidSetBssid() ++** ++** 09 04 2013 cp.wu ++** fix typo ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 11 23 2012 yuche.tsai ++** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely ++** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++ ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "gl_wext.h" ++#include "precomp.h" ++#include "gl_cfg80211.h" ++#include "gl_vendor.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++static struct nla_policy nla_parse_policy[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1] = { ++ [GSCAN_ATTRIBUTE_NUM_BUCKETS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BASE_PERIOD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKETS_BAND] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_ID] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_PERIOD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BUCKET_CHANNELS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_REPORT_THRESHOLD] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_REPORT_EVENTS] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_BSSID] = {.type = NLA_UNSPEC}, ++ [GSCAN_ATTRIBUTE_RSSI_LOW] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_RSSI_HIGH] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE] = {.type = NLA_U32}, ++ [GSCAN_ATTRIBUTE_MIN_BREACHING] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_NUM_AP] = {.type = NLA_U16}, ++ [GSCAN_ATTRIBUTE_HOTLIST_FLUSH] = {.type = NLA_U8}, ++ [GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH] = {.type = NLA_U8}, ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ struct nlattr *attr; ++ UINT_32 band = 0; ++ UINT_8 ucNumOfChannel, i, j; ++ RF_CHANNEL_INFO_T aucChannelList[64]; ++ UINT_32 num_channels; ++ wifi_channel channels[64]; ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy && wdev); ++ if ((data == NULL) || !data_len) ++ return -EINVAL; ++ ++ DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == WIFI_ATTRIBUTE_BAND) ++ band = nla_get_u32(attr); ++ ++ DBGLOG(REQ, INFO, "Get channel list for band: %d\n", band); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (!prGlueInfo) ++ return -EFAULT; ++ ++ if (band == 0) { /* 2.4G band */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, TRUE, ++ 64, &ucNumOfChannel, aucChannelList); ++ } else { /* 5G band */ ++ rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, TRUE, ++ 64, &ucNumOfChannel, aucChannelList); ++ } ++ ++ kalMemZero(channels, sizeof(channels)); ++ for (i = 0, j = 0; i < ucNumOfChannel; i++) { ++ /* We need to report frequency list to HAL */ ++ channels[j] = nicChannelNum2Freq(aucChannelList[i].ucChannelNum) / 1000; ++ if (channels[j] == 0) ++ continue; ++ else if ((prGlueInfo->prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_TW) && ++ (channels[j] >= 5180 && channels[j] <= 5260)) { ++ /* Taiwan NCC has resolution to follow FCC spec to support 5G Band 1/2/3/4 ++ * (CH36~CH48, CH52~CH64, CH100~CH140, CH149~CH165) ++ * Filter CH36~CH52 for compatible with some old devices. ++ */ ++ continue; ++ } else { ++ DBGLOG(REQ, INFO, "channels[%d] = %d\n", j, channels[j]); ++ j++; ++ } ++ } ++ num_channels = j; ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(channels)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "Allocate skb failed\n"); ++ return -ENOMEM; ++ } ++ ++ if (unlikely(nla_put_u32(skb, WIFI_ATTRIBUTE_NUM_CHANNELS, num_channels) < 0)) ++ goto nla_put_failure; ++ ++ if (unlikely(nla_put(skb, WIFI_ATTRIBUTE_CHANNEL_LIST, ++ (sizeof(wifi_channel) * num_channels), channels) < 0)) ++ goto nla_put_failure; ++ ++ return cfg80211_vendor_cmd_reply(skb); ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -EFAULT; ++} ++ ++int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ struct nlattr *attr; ++ UINT_8 country[2] = {0, 0}; ++ ++ ASSERT(wiphy && wdev); ++ if ((data == NULL) || (data_len == 0)) ++ return -EINVAL; ++ ++ DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == WIFI_ATTRIBUTE_COUNTRY_CODE) { ++ country[0] = *((PUINT_8)nla_data(attr)); ++ country[1] = *((PUINT_8)nla_data(attr) + 1); ++ } ++ ++ DBGLOG(REQ, INFO, "Set country code: %c%c\n", country[0], country[1]); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ if (!prGlueInfo) ++ return -EFAULT; ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, country, 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, ++ struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Status = -EINVAL; ++ PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T rGscanCapabilities; ++ struct sk_buff *skb; ++ /* UINT_32 u4BufLen; */ ++ ++ DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rGscanCapabilities)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rGscanCapabilities, sizeof(rGscanCapabilities)); ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rGscanCapabilities, ++ sizeof(rGscanCapabilities), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ rGscanCapabilities.max_scan_cache_size = PSCAN_MAX_SCAN_CACHE_SIZE; ++ rGscanCapabilities.max_scan_buckets = GSCAN_MAX_BUCKETS; ++ rGscanCapabilities.max_ap_cache_per_scan = PSCAN_MAX_AP_CACHE_PER_SCAN; ++ rGscanCapabilities.max_rssi_sample_size = 10; ++ rGscanCapabilities.max_scan_reporting_threshold = GSCAN_MAX_REPORT_THRESHOLD; ++ rGscanCapabilities.max_hotlist_aps = MAX_HOTLIST_APS; ++ rGscanCapabilities.max_significant_wifi_change_aps = MAX_SIGNIFICANT_CHANGE_APS; ++ rGscanCapabilities.max_bssid_history_entries = PSCAN_MAX_AP_CACHE_PER_SCAN * PSCAN_MAX_SCAN_CACHE_SIZE; ++ ++ /* NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0); */ ++ /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_ID, GOOGLE_OUI); */ ++ /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_SUBCMD, GSCAN_SUBCMD_GET_CAPABILITIES); */ ++ /*NLA_PUT(skb, GSCAN_ATTRIBUTE_CAPABILITIES, sizeof(rGscanCapabilities), &rGscanCapabilities);*/ ++ if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_CAPABILITIES, ++ sizeof(rGscanCapabilities), &rGscanCapabilities) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ return i4Status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ /* CMD_GSCN_REQ_T rCmdGscnParam; */ ++ ++ /* INT_32 i4Status = -EINVAL; */ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; ++ struct nlattr *attr[GSCAN_ATTRIBUTE_REPORT_EVENTS + 1]; ++ struct nlattr *pbucket, *pchannel; ++ UINT_32 len_basic, len_bucket, len_channel; ++ int i, j, k; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ ++ prWifiScanCmd = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); ++ if (!prWifiScanCmd) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); ++ return -ENOMEM; ++ } ++ ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_REPORT_EVENTS + 1)); ++ ++ nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL); ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BASE_PERIOD: ++ prWifiScanCmd->base_period = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_BUCKETS: ++ prWifiScanCmd->num_buckets = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_buckets=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiScanCmd->num_buckets, attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ pbucket = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d pbucket=%p\r\n", len_basic, pbucket); ++ ++ for (i = 0; i < prWifiScanCmd->num_buckets; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)pbucket, ++ nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_bucket = 0; ++ for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BUCKETS_BAND: ++ prWifiScanCmd->buckets[i].band = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_ID: ++ prWifiScanCmd->buckets[i].bucket = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_PERIOD: ++ prWifiScanCmd->buckets[i].period = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_REPORT_EVENTS: ++ prWifiScanCmd->buckets[i].report_events = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: ++ prWifiScanCmd->buckets[i].num_channels = nla_get_u32(attr[k]); ++ len_bucket += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "bucket%d: attr=0x%x, num_channels=%d nla_len = %d, \r\n", ++ i, *(UINT_32 *) attr[k], nla_get_u32(attr[k]), attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ pbucket = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ DBGLOG(REQ, TRACE, "+++pure bucket size=%d pbucket=%p \r\n", len_bucket, pbucket); ++ pbucket = (struct nlattr *)((UINT_8 *) pbucket + len_bucket); ++ /* pure bucket payload, not include channels */ ++ ++ /*don't need to use nla_parse_nested to parse channels */ ++ /* the header of channel in bucket i */ ++ pchannel = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); ++ for (j = 0; j < prWifiScanCmd->buckets[i].num_channels; j++) { ++ prWifiScanCmd->buckets[i].channels[j].channel = nla_get_u32(pchannel); ++ len_channel = NLA_ALIGN(pchannel->nla_len); ++ DBGLOG(REQ, TRACE, ++ "attr=0x%x, channel=%d, \r\n", *(UINT_32 *) pchannel, nla_get_u32(pchannel)); ++ ++ pchannel = (struct nlattr *)((UINT_8 *) pchannel + len_channel); ++ } ++ pbucket = pchannel; ++ } ++ ++ DBGLOG(REQ, TRACE, "base_period=%d, num_buckets=%d, bucket0: %d %d %d %d", ++ prWifiScanCmd->base_period, prWifiScanCmd->num_buckets, ++ prWifiScanCmd->buckets[0].bucket, prWifiScanCmd->buckets[0].period, ++ prWifiScanCmd->buckets[0].band, prWifiScanCmd->buckets[0].report_events); ++ ++ DBGLOG(REQ, TRACE, "num_channels=%d, channel0=%d, channel1=%d; num_channels=%d, channel0=%d, channel1=%d", ++ prWifiScanCmd->buckets[0].num_channels, ++ prWifiScanCmd->buckets[0].channels[0].channel, prWifiScanCmd->buckets[0].channels[1].channel, ++ prWifiScanCmd->buckets[1].num_channels, ++ prWifiScanCmd->buckets[1].channels[0].channel, prWifiScanCmd->buckets[1].channels[1].channel); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAParam, ++ prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiScanCmd != NULL) ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ INT_32 i4Status = -EINVAL; ++ /*PARAM_WIFI_GSCAN_CMD_PARAMS rWifiScanCmd;*/ ++ P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; ++ struct nlattr *attr[GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1]; ++ /* UINT_32 num_scans = 0; */ /* another attribute */ ++ int k; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ /*kalMemZero(&rWifiScanCmd, sizeof(rWifiScanCmd));*/ ++ prWifiScanCmd = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); ++ if (prWifiScanCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, ++ (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ for (k = GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN; k <= GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: ++ prWifiScanCmd->max_ap_per_scan = nla_get_u32(attr[k]); ++ break; ++ case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: ++ prWifiScanCmd->report_threshold = nla_get_u32(attr[k]); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: ++ prWifiScanCmd->num_scans = nla_get_u32(attr[k]); ++ break; ++ } ++ } ++ } ++ DBGLOG(REQ, TRACE, "attr=0x%x, attr2=0x%x ", *(UINT_32 *) attr[GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN], ++ *(UINT_32 *) attr[GSCAN_ATTRIBUTE_REPORT_THRESHOLD]); ++ ++ DBGLOG(REQ, TRACE, "max_ap_per_scan=%d, report_threshold=%d num_scans=%d \r\n", ++ prWifiScanCmd->max_ap_per_scan, prWifiScanCmd->report_threshold, prWifiScanCmd->num_scans); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAConfig, ++ prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiScanCmd != NULL) ++ kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ P_PARAM_WIFI_SIGNIFICANT_CHANGE prWifiChangeCmd = NULL; ++ UINT_8 flush = 0; ++ /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ ++ struct nlattr **attr = NULL; ++ struct nlattr *paplist; ++ int i, k; ++ UINT_32 len_basic, len_aplist; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 6; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", ++ *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), ++ *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); ++ prWifiChangeCmd = kalMemAlloc(sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE), VIR_MEM_TYPE); ++ if (prWifiChangeCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiChangeCmd, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); ++ if (attr == NULL) ++ goto nla_put_failure; ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, ++ (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE; k <= GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: ++ prWifiChangeCmd->rssi_sample_size = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: ++ prWifiChangeCmd->lost_ap_sample_size = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_MIN_BREACHING: ++ prWifiChangeCmd->min_breaching = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_AP: ++ prWifiChangeCmd->num_ap = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiChangeCmd->num_ap, attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: ++ flush = nla_get_u8(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ paplist = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); ++ ++ if (paplist->nla_type == GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS) ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ ++ for (i = 0; i < prWifiChangeCmd->num_ap; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ len_aplist = 0; ++ for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BSSID: ++ kalMemCopy(prWifiChangeCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_LOW: ++ prWifiChangeCmd->ap[i].low = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_HIGH: ++ prWifiChangeCmd->ap[i].high = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ if (((i + 1) % 4 == 0) || (i == prWifiChangeCmd->num_ap - 1)) ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); ++ else ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); ++ paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); ++ } ++ ++ DBGLOG(REQ, TRACE, ++ "flush=%d, rssi_sample_size=%d lost_ap_sample_size=%d min_breaching=%d", ++ flush, prWifiChangeCmd->rssi_sample_size, prWifiChangeCmd->lost_ap_sample_size, ++ prWifiChangeCmd->min_breaching); ++ DBGLOG(REQ, TRACE, ++ "ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", ++ prWifiChangeCmd->ap[0].channel, prWifiChangeCmd->ap[0].low, prWifiChangeCmd->ap[0].high, ++ prWifiChangeCmd->ap[1].channel, prWifiChangeCmd->ap[1].low, prWifiChangeCmd->ap[1].high); ++ kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiChangeCmd) ++ kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); ++ if (attr) ++ kalMemFree(attr, VIR_MEM_TYPE, ++ sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ /*WLAN_STATUS rStatus;*/ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; ++ ++ INT_32 i4Status = -EINVAL; ++ P_PARAM_WIFI_BSSID_HOTLIST prWifiHotlistCmd = NULL; ++ UINT_8 flush = 0; ++ /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ ++ struct nlattr **attr = NULL; ++ struct nlattr *paplist; ++ int i, k; ++ UINT_32 len_basic, len_aplist; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 5; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", ++ *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), ++ *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); ++ prWifiHotlistCmd = kalMemAlloc(sizeof(PARAM_WIFI_BSSID_HOTLIST), VIR_MEM_TYPE); ++ if (prWifiHotlistCmd == NULL) ++ goto nla_put_failure; ++ kalMemZero(prWifiHotlistCmd, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); ++ if (attr == NULL) ++ goto nla_put_failure; ++ kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_AP, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ len_basic = 0; ++ for (k = GSCAN_ATTRIBUTE_HOTLIST_FLUSH; k <= GSCAN_ATTRIBUTE_NUM_AP; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: ++ prWifiHotlistCmd->lost_ap_sample_size = nla_get_u32(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_NUM_AP: ++ prWifiHotlistCmd->num_ap = nla_get_u16(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", ++ *(UINT_32 *) attr[k], prWifiHotlistCmd->num_ap, attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: ++ flush = nla_get_u8(attr[k]); ++ len_basic += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ paplist = (struct nlattr *)((UINT_8 *) data + len_basic); ++ DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); ++ ++ if (paplist->nla_type == GSCAN_ATTRIBUTE_HOTLIST_BSSIDS) ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ ++ for (i = 0; i < prWifiHotlistCmd->num_ap; i++) { ++ if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) ++ goto nla_put_failure; ++ paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); ++ /* request.attr_start(i) as nested attribute */ ++ len_aplist = 0; ++ for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { ++ if (attr[k]) { ++ switch (k) { ++ case GSCAN_ATTRIBUTE_BSSID: ++ kalMemCopy(prWifiHotlistCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_LOW: ++ prWifiHotlistCmd->ap[i].low = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ case GSCAN_ATTRIBUTE_RSSI_HIGH: ++ prWifiHotlistCmd->ap[i].high = nla_get_u32(attr[k]); ++ len_aplist += NLA_ALIGN(attr[k]->nla_len); ++ break; ++ } ++ } ++ } ++ if (((i + 1) % 4 == 0) || (i == prWifiHotlistCmd->num_ap - 1)) ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); ++ else ++ DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); ++ paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); ++ } ++ ++ DBGLOG(REQ, TRACE, ++ "flush=%d, lost_ap_sample_size=%d, Hotlist:ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", ++ flush, prWifiHotlistCmd->lost_ap_sample_size, ++ prWifiHotlistCmd->ap[0].channel, prWifiHotlistCmd->ap[0].low, prWifiHotlistCmd->ap[0].high, ++ prWifiHotlistCmd->ap[1].channel, prWifiHotlistCmd->ap[1].low, prWifiHotlistCmd->ap[1].high); ++ ++ memcpy(&(rCmdPscnAddHotlist.aucMacAddr), &(prWifiHotlistCmd->ap[0].bssid), 6 * sizeof(UINT_8)); ++ rCmdPscnAddHotlist.ucFlags = (UINT_8) TRUE; ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return 0; ++ ++nla_put_failure: ++ if (prWifiHotlistCmd) ++ kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); ++ if (attr) ++ kalMemFree(attr, VIR_MEM_TYPE, ++ sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS rWifiScanActionCmd; ++ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_8 gGScanEn = 0; ++ ++ static UINT_8 k; /* only for test */ ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", ++ __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) ++ gGScanEn = nla_get_u32(attr); ++ DBGLOG(REQ, INFO, "gGScanEn=%d, \r\n", gGScanEn); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ if (gGScanEn == TRUE) ++ rWifiScanActionCmd.ucPscanAct = ENABLE; ++ else ++ rWifiScanActionCmd.ucPscanAct = DISABLE; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetGSCNAction, ++ &rWifiScanActionCmd, ++ sizeof(PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ /* mtk_cfg80211_vendor_get_scan_results(wiphy, wdev, data, data_len ); */ ++ ++ return 0; ++ ++ /* only for test */ ++ if (k % 3 == 1) { ++ mtk_cfg80211_vendor_event_significant_change_results(wiphy, wdev, NULL, 0); ++ mtk_cfg80211_vendor_event_hotlist_ap_found(wiphy, wdev, NULL, 0); ++ mtk_cfg80211_vendor_event_hotlist_ap_lost(wiphy, wdev, NULL, 0); ++ } ++ k++; ++ ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_8 gFullScanResultsEn = 0; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", ++ __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ENABLE_FULL_SCAN_RESULTS) ++ gFullScanResultsEn = nla_get_u32(attr); ++ DBGLOG(REQ, INFO, "gFullScanResultsEn=%d, \r\n", gFullScanResultsEn); ++ ++ return 0; ++ ++ /* only for test */ ++ mtk_cfg80211_vendor_event_complete_scan(wiphy, wdev, WIFI_SCAN_COMPLETE); ++ mtk_cfg80211_vendor_event_scan_results_available(wiphy, wdev, 4); ++ if (gFullScanResultsEn == TRUE) ++ mtk_cfg80211_vendor_event_full_scan_results(wiphy, wdev, NULL, 0); ++ ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ /*WLAN_STATUS rStatus;*/ ++ UINT_32 u4BufLen; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ PARAM_WIFI_GSCAN_GET_RESULT_PARAMS rGSscnResultParm; ++ ++ INT_32 i4Status = -EINVAL; ++ struct nlattr *attr; ++ UINT_32 get_num = 0, real_num = 0; ++ UINT_8 flush = 0; ++ /*PARAM_WIFI_GSCAN_RESULT result[4], *pResult; ++ struct sk_buff *skb;*/ ++ int i; /*int j;*/ ++ /*UINT_32 scan_id;*/ ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ if ((data == NULL) || !data_len) ++ goto nla_put_failure; ++ DBGLOG(REQ, TRACE, "%s for vendor command: data_len=%d \r\n", __func__, data_len); ++ for (i = 0; i < 2; i++) ++ DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", *((UINT_32 *) data + i * 4), ++ *((UINT_32 *) data + i * 4 + 1), *((UINT_32 *) data + i * 4 + 2), ++ *((UINT_32 *) data + i * 4 + 3)); ++ ++ attr = (struct nlattr *)data; ++ if (attr->nla_type == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { ++ get_num = nla_get_u32(attr); ++ attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); ++ } ++ if (attr->nla_type == GSCAN_ATTRIBUTE_FLUSH_RESULTS) { ++ flush = nla_get_u8(attr); ++ attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); ++ } ++ DBGLOG(REQ, TRACE, "number=%d, flush=%d \r\n", get_num, flush); ++ ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ASSERT(prGlueInfo); ++ ++ real_num = (get_num < PSCAN_MAX_SCAN_CACHE_SIZE) ? get_num : PSCAN_MAX_SCAN_CACHE_SIZE; ++ get_num = real_num; ++ ++#if 0 /* driver buffer FW results and reports by buffer workaround for FW mismatch with hal results numbers */ ++ g_GetResultsCmdCnt++; ++ DBGLOG(REQ, INFO, ++ "(g_GetResultsCmdCnt [%d], g_GetResultsBufferedCnt [%d]\n", g_GetResultsCmdCnt, ++ g_GetResultsBufferedCnt); ++ ++ BOOLEAN fgIsGetResultFromBuffer = FALSE; ++ UINT_8 BufferedResultReportIndex = 0; ++ ++ if (g_GetResultsBufferedCnt > 0) { ++ ++ DBGLOG(REQ, INFO, ++ "(g_GetResultsBufferedCnt > 0), report buffered results instead of ask from FW\n"); ++ ++ /* reply the results to wifi_hal */ ++ for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { ++ ++ if (g_arGscanResultsIndicateNumber[i] > 0) { ++ real_num = g_arGscanResultsIndicateNumber[i]; ++ get_num = real_num; ++ g_arGscanResultsIndicateNumber[i] = 0; ++ fgIsGetResultFromBuffer = TRUE; ++ BufferedResultReportIndex = i; ++ break; ++ } ++ } ++ if (i == MAX_BUFFERED_GSCN_RESULTS) ++ DBGLOG(REQ, TRACE, "all buffered results are invalid, unexpected case \r\n"); ++ DBGLOG(REQ, TRACE, "BufferedResultReportIndex[%d] i = %d real_num[%d] get_num[%d] \r\n", ++ BufferedResultReportIndex, i, real_num, get_num); ++ } ++#endif ++ ++ rGSscnResultParm.get_num = get_num; ++ rGSscnResultParm.flush = flush; ++#if 0/* //driver buffer FW results and reports by buffer workaround for FW results mismatch with hal results number */ ++ if (fgIsGetResultFromBuffer) { ++ nicRxProcessGSCNEvent(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); ++ g_GetResultsBufferedCnt--; ++ g_GetResultsCmdCnt--; ++ nicRxReturnRFB(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); ++ } else ++#endif ++ { ++ kalIoctl(prGlueInfo, ++ wlanoidGetGSCNResult, ++ &rGSscnResultParm, ++ sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ return 0; ++ ++nla_put_failure: ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, ++ struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4Status = -EINVAL; ++ PARAM_WIFI_RTT_CAPABILITIES rRttCapabilities; ++ struct sk_buff *skb; ++ ++ DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rRttCapabilities)); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&rRttCapabilities, sizeof(rRttCapabilities)); ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rRttCapabilities, ++ sizeof(rRttCapabilities), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ rRttCapabilities.rtt_one_sided_supported = 0; ++ rRttCapabilities.rtt_ftm_supported = 0; ++ rRttCapabilities.lci_support = 0; ++ rRttCapabilities.lcr_support = 0; ++ rRttCapabilities.preamble_support = 0; ++ rRttCapabilities.bw_support = 0; ++ ++ if (unlikely(nla_put(skb, RTT_ATTRIBUTE_CAPABILITIES, ++ sizeof(rRttCapabilities), &rRttCapabilities) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ return i4Status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) ++{ ++ INT_32 i4Status = -EINVAL; ++ WIFI_RADIO_STAT *pRadioStat; ++ struct sk_buff *skb; ++ UINT_32 u4BufLen; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ ++ u4BufLen = sizeof(WIFI_RADIO_STAT) + sizeof(WIFI_IFACE_STAT); ++ pRadioStat = kalMemAlloc(u4BufLen, VIR_MEM_TYPE); ++ if (!pRadioStat) { ++ DBGLOG(REQ, ERROR, "%s kalMemAlloc pRadioStat failed\n", __func__); ++ return -ENOMEM; ++ } ++ kalMemZero(pRadioStat, u4BufLen); ++ ++ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, u4BufLen); ++ if (!skb) { ++ DBGLOG(REQ, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); ++ return -ENOMEM; ++ } ++ ++ /*rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryStatistics, ++ &rRadioStat, ++ sizeof(rRadioStat), ++ TRUE, ++ TRUE, ++ TRUE, ++ FALSE, ++ &u4BufLen); */ ++ /* only for test */ ++ pRadioStat->radio = 10; ++ pRadioStat->on_time = 11; ++ pRadioStat->tx_time = 12; ++ pRadioStat->num_channels = 4; ++ ++ /*NLA_PUT(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat);*/ ++ if (unlikely(nla_put(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat) < 0)) ++ goto nla_put_failure; ++ ++ i4Status = cfg80211_vendor_cmd_reply(skb); ++ kalMemFree(pRadioStat, VIR_MEM_TYPE, u4BufLen); ++ return -1; /* not support LLS now*/ ++ /* return i4Status; */ ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return i4Status; ++} ++ ++int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete) ++{ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ /* WIFI_SCAN_EVENT complete_scan; */ ++ ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(complete), GSCAN_EVENT_COMPLETE_SCAN, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ /* complete_scan = WIFI_SCAN_COMPLETE; */ ++ /*NLA_PUT_U32(skb, GSCAN_EVENT_COMPLETE_SCAN, complete);*/ ++ { ++ unsigned int __tmp = complete; ++ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_COMPLETE_SCAN, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num) ++{ ++ struct sk_buff *skb; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ /* UINT_32 scan_result; */ ++ ++ DBGLOG(REQ, INFO, "%s for vendor command %d \r\n", __func__, num); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(num), GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ /* scan_result = 2; */ ++ /*NLA_PUT_U32(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, num);*/ ++ { ++ unsigned int __tmp = num; ++ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, ++ sizeof(unsigned int), &__tmp) < 0)) ++ goto nla_put_failure; ++ } ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(result), GSCAN_EVENT_FULL_SCAN_RESULTS, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ kalMemZero(&result, sizeof(result)); ++ kalMemCopy(result.ssid, "Gscan_full_test", sizeof("Gscan_full_test")); ++ result.channel = 2437; ++ ++ /* kalMemCopy(&result, pdata, sizeof(PARAM_WIFI_GSCAN_RESULT); */ ++ /*NLA_PUT(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, sizeof(result), &result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, ++ sizeof(result), &result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_CHANGE_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_CHANGE_RESULT), ++ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "213123", sizeof(mac_addr)); ++ presult->channel = 2437; ++ presult->rssi[0] = -45; ++ presult->rssi[1] = -46; ++ presult++; ++ presult->channel = 2439; ++ presult->rssi[0] = -47; ++ presult->rssi[1] = -48; ++ /*NLA_PUT(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, ++ (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), ++ GSCAN_EVENT_HOTLIST_RESULTS_FOUND, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "123123", sizeof(mac_addr)); ++ presult->channel = 2441; ++ presult->rssi = -45; ++ presult++; ++ presult->channel = 2443; ++ presult->rssi = -47; ++ /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, ++ (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) ++{ ++ struct sk_buff *skb; ++ PARAM_WIFI_GSCAN_RESULT result[2], *presult; ++ ++ ASSERT(wiphy); ++ ASSERT(wdev); ++ DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); ++ ++ skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), ++ GSCAN_EVENT_HOTLIST_RESULTS_LOST, GFP_KERNEL); ++ if (!skb) { ++ DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ presult = result; ++ kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); ++ /* only for test */ ++ kalMemCopy(presult->bssid, "321321", sizeof(mac_addr)); ++ presult->channel = 2445; ++ presult->rssi = -46; ++ presult++; ++ presult->channel = 2447; ++ presult->rssi = -48; ++ /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ ++ if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, ++ (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) ++ goto nla_put_failure; ++ ++ cfg80211_vendor_event(skb, GFP_KERNEL); ++ return 0; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -1; ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c +new file mode 100644 +index 000000000000..1793742e9802 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c +@@ -0,0 +1,4158 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext.c#3 ++*/ ++ ++/*! \file gl_wext.c ++ \brief ioctl() (mostly Linux Wireless Extensions) routines for STA driver. ++*/ ++ ++/* ++** Log: gl_wext.c ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 23 2011 tsaiyuan.hsu ++ * [WCXRP00000979] [MT6620 Wi-Fi][DRV]] stop attempting to connect to config AP after D3 state ++ * avoid entering D3 state after deep sleep. ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 27 2011 wh.su ++ * [WCXRP00000877] [MT6620 Wi-Fi][Driver] Remove the netif_carry_ok check for avoid the wpa_supplicant fail to query ++ * the ap address ++ * Remove the netif check while query bssid and ssid ++ * ++ * 07 26 2011 chinglan.wang ++ * NULL ++ * [MT6620][WiFi Driver] Do not include the WSC IE in the association info packet when not do the wps connection.. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 05 17 2011 eddie.chen ++ * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning ++ * Initialize the vairlabes. ++ * ++ * 05 11 2011 jeffrey.chang ++ * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power ++ * modify set_tx_pow ioctl ++ * ++ * 03 29 2011 terry.wu ++ * [WCXRP00000610] [MT 6620 Wi-Fi][Driver] Fix klocwork waring ++ * [MT6620 Wi-Fi][Driver] Fix klocwork warning. Add Null pointer check on wext_get_essid. Limit the upper bound of ++ * essid storage array. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 02 21 2011 wh.su ++ * [WCXRP00000483] [MT6620 Wi-Fi][Driver] Check the kalIoctl return value before doing the memory copy at linux get ++ * essid ++ * fixed the potential error to do a larget memory copy while wlanoid get essid not actually running. ++ * ++ * 02 08 2011 george.huang ++ * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler ++ * Support querying power mode OID. ++ * ++ * 01 29 2011 wh.su ++ * [WCXRP00000408] [MT6620 Wi-Fi][Driver] Not doing memory alloc while ioctl set ie with length 0 ++ * not doing mem alloc. while set ie length already 0 ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Remove debug text. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Adjust OID order. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish ++ * successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. . ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous types ++ * to ease slab system pressure ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Support set PS profile and set WMM-PS related iwpriv. ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Allow change PS profile function (through wext_set_power()). ++ * ++ * 12 14 2010 jeffrey.chang ++ * [WCXRP00000262] [MT6620 Wi-Fi][Driver] modify the scan request ioctl to handle hidden SSID ++ * handle hidden SSID ++ * ++ * 12 13 2010 chinglan.wang ++ * NULL ++ * Add WPS 1.0 feature flag to enable the WPS 1.0 function. ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * Fix compiling error ++ * ++ * 12 07 2010 cm.chang ++ * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant ++ * 1. Country code is from NVRAM or supplicant ++ * 2. Change band definition in CMD/EVENT. ++ * ++ * 11 30 2010 cp.wu ++ * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 ++ * . ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000121] [MT6620 Wi-Fi][Driver] Temporarily disable set power mode ioctl which may cause 6620 to enter power ++ * saving ++ * Temporarily disable set power mode ioctl which may cause MT6620 to enter power saving ++ * ++ * 10 18 2010 jeffrey.chang ++ * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue ++ * refine the scan ioctl to prevent hanging of Android UI ++ * ++ * 10 01 2010 wh.su ++ * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function ++ * add the scan result with wapi ie. ++ * ++ * 09 30 2010 wh.su ++ * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue ++ * fixed the wapi ie assigned issue. ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 09 2010 cp.wu ++ * NULL ++ * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. ++ * ++ * 09 06 2010 cp.wu ++ * NULL ++ * Androi/Linux: return current operating channel information ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * enable remove key ioctl ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) enable encyption ioctls ++ * 2) temporarily disable remove keys ioctl to prevent TX1 busy ++ * ++ * 07 28 2010 jeffrey.chang ++ * NULL ++ * 1) remove unused spinlocks ++ * 2) enable encyption ioctls ++ * 3) fix scan ioctl which may cause supplicant to hang ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * for linux driver migration ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove unused macro and debug messages ++ * ++ * 05 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add dissassoication support for wpa supplicant ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Add ioctl of power management ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug message ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used ++ * * 2) fix ioctl ++ * ++ * 04 12 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug messages for pre-release ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * are done in adapter layer. ++ * ++ * 04 02 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl type ++ * ++ * 04 01 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * enable pmksa cache operation ++ * ++ * 03 31 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix ioctl which may cause cmdinfo memory leak ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\38 2009-10-08 10:33:22 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). ++** Add more checking for input parameters and pointers. ++** \main\maintrunk.MT5921\37 2009-09-29 16:49:48 GMT mtk01090 ++** Remove unused variables ++** \main\maintrunk.MT5921\36 2009-09-28 20:19:11 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\35 2009-09-03 11:42:30 GMT mtk01088 ++** adding the wapi ioctl support ++** \main\maintrunk.MT5921\34 2009-08-18 22:56:50 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\33 2009-05-14 22:43:47 GMT mtk01089 ++** fix compiling warning ++** \main\maintrunk.MT5921\32 2009-05-07 22:26:18 GMT mtk01089 ++** Add mandatory and private IO control for Linux BWCS ++** \main\maintrunk.MT5921\31 2009-02-07 15:11:14 GMT mtk01088 ++** fixed the compiling error ++** \main\maintrunk.MT5921\30 2009-02-07 14:46:51 GMT mtk01088 ++** add the privacy setting from linux supplicant ap selection ++** \main\maintrunk.MT5921\29 2008-11-19 15:18:50 GMT mtk01088 ++** fixed the compling error ++** \main\maintrunk.MT5921\28 2008-11-19 11:56:18 GMT mtk01088 ++** rename some variable with pre-fix to avoid the misunderstanding ++** \main\maintrunk.MT5921\27 2008-08-29 16:59:43 GMT mtk01088 ++** fixed compiling error ++** \main\maintrunk.MT5921\26 2008-08-29 14:55:53 GMT mtk01088 ++** adjust the code for meet the coding style, and add assert check ++** \main\maintrunk.MT5921\25 2008-06-02 11:15:19 GMT mtk01461 ++** Update after wlanoidSetPowerMode changed ++** \main\maintrunk.MT5921\24 2008-05-30 15:13:12 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\23 2008-03-28 10:40:28 GMT mtk01461 ++** Add set desired rate in Linux STD IOCTL ++** \main\maintrunk.MT5921\22 2008-03-18 10:31:24 GMT mtk01088 ++** add pmkid ioctl and indicate ++** \main\maintrunk.MT5921\21 2008-03-11 15:21:24 GMT mtk01461 ++** \main\maintrunk.MT5921\20 2008-03-11 14:50:55 GMT mtk01461 ++** Refine WPS related priv ioctl for unified interface ++** ++** \main\maintrunk.MT5921\19 2008-03-06 16:30:41 GMT mtk01088 ++** move the configuration code from set essid function, ++** remove the non-used code ++** \main\maintrunk.MT5921\18 2008-02-21 15:47:09 GMT mtk01461 ++** Fix CR[489] ++** \main\maintrunk.MT5921\17 2008-02-12 23:38:31 GMT mtk01461 ++** Add Set Frequency & Channel oid support for Linux ++** \main\maintrunk.MT5921\16 2008-01-24 12:07:34 GMT mtk01461 ++** \main\maintrunk.MT5921\15 2008-01-24 12:00:10 GMT mtk01461 ++** Modify the wext_essid for set up correct information for IBSS, and fix the wrong input ptr for prAdapter ++** \main\maintrunk.MT5921\14 2007-12-06 09:30:12 GMT mtk01425 ++** 1. Branch Test ++** \main\maintrunk.MT5921\13 2007-12-04 18:07:59 GMT mtk01461 ++** fix typo ++** \main\maintrunk.MT5921\12 2007-11-30 17:10:21 GMT mtk01425 ++** 1. Fix compiling erros ++** ++** \main\maintrunk.MT5921\11 2007-11-27 10:43:22 GMT mtk01425 ++** 1. Add WMM-PS setting ++** \main\maintrunk.MT5921\10 2007-11-06 20:33:32 GMT mtk01088 ++** fixed the compiler error ++** \main\maintrunk.MT5921\9 2007-11-06 19:33:15 GMT mtk01088 ++** add WPS code ++** \main\maintrunk.MT5921\8 2007-10-30 12:00:44 GMT MTK01425 ++** 1. Update wlanQueryInformation ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#include "gl_os.h" ++ ++#include "config.h" ++#include "wlan_oid.h" ++ ++#include "gl_wext.h" ++#include "gl_wext_priv.h" ++ ++#include "precomp.h" ++ ++#if CFG_SUPPORT_WAPI ++#include "gl_sec.h" ++#endif ++ ++/* compatibility to wireless extensions */ ++#ifdef WIRELESS_EXT ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++const long channel_freq[] = { ++ 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 ++}; ++ ++ ++#define NUM_CHANNELS (sizeof(channel_freq) / sizeof(channel_freq[0])) ++ ++#define MAX_SSID_LEN 32 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++/* NOTE: name in iwpriv_args only have 16 bytes */ ++static const struct iw_priv_args rIwPrivTable[] = { ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, ""}, ++ {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, ""}, ++ ++ {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, ++ ++ {IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, ""}, ++ {IOCTL_GET_INT, 0, IW_PRIV_TYPE_CHAR | 16, ""}, ++ ++ {IOCTL_SET_STRING, IW_PRIV_TYPE_CHAR | 256, 0, ""}, ++ ++ /* added for set_oid and get_oid */ ++ {IOCTL_SET_STRUCT, 256, 0, ""}, ++ {IOCTL_GET_STRUCT, 0, 256, ""}, ++ ++ /* sub-ioctl definitions */ ++#if 0 ++ {PRIV_CMD_REG_DOMAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_reg_domain"}, ++ {PRIV_CMD_REG_DOMAIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_reg_domain"}, ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ {PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_tcp_csum"}, ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ {PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power_mode"}, ++ {PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_power_mode"}, ++ ++ {PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_wmm_ps"}, ++ ++ {PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_test_mode"}, ++ {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_test_cmd"}, ++ {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_test_result"}, ++#if CFG_SUPPORT_PRIV_MCR_RW ++ {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_mcr"}, ++ {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_mcr"}, ++#endif ++ {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_sw_ctrl"}, ++ {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_sw_ctrl"}, ++ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_bwcs"}, ++ /* GET STRUCT sub-ioctls commands */ ++ {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_bwcs"}, ++#endif ++ ++ /* SET STRUCT sub-ioctls commands */ ++ {PRIV_CMD_OID, 256, 0, "set_oid"}, ++ /* GET STRUCT sub-ioctls commands */ ++ {PRIV_CMD_OID, 0, 256, "get_oid"}, ++ ++ {PRIV_CMD_BAND_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_band"}, ++ {PRIV_CMD_BAND_CONFIG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_band"}, ++ ++ {PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower"}, ++ {PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list"}, ++ {PRIV_CMD_DUMP_MEM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ "get_mem"}, ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ {PRIV_CMD_P2P_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_p2p_mode"}, ++#endif ++ {PRIV_CMD_GET_BUILD_DATE_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_date_code"}, ++ {PRIV_CMD_GET_DEBUG_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_dbg_code"}, ++ /* handle any command with many input parameters */ ++ {PRIV_CMD_OTHER, IW_PRIV_TYPE_CHAR | 256, 0, "set_str_cmd"}, ++ ++ {PRIV_CMD_WFD_DEBUG_CODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_wfd_dbg_code"}, ++}; ++ ++static const iw_handler rIwPrivHandler[] = { ++ [IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int, ++ [IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int, ++ [IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL, ++ [IOCTL_SET_STRUCT - SIOCIWFIRSTPRIV] = priv_set_struct, ++ [IOCTL_GET_STRUCT - SIOCIWFIRSTPRIV] = priv_get_struct, ++ [IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct, ++ [IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints, ++ [IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints, ++ [IOCTL_SET_STRING - SIOCIWFIRSTPRIV] = priv_set_string, ++}; ++ ++const struct iw_handler_def wext_handler_def = { ++ .num_standard = 0, ++ .num_private = (__u16) sizeof(rIwPrivHandler) / sizeof(iw_handler), ++ .num_private_args = (__u16) sizeof(rIwPrivTable) / sizeof(struct iw_priv_args), ++ .standard = (iw_handler *) NULL, ++ .private = rIwPrivHandler, ++ .private_args = rIwPrivTable, ++ .get_wireless_stats = wext_get_wireless_stats, ++}; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WPA/RSN Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { ++ if (ucDesiredElemId != 0xDD) { ++ /* Non 0xDD, OK! */ ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ /* EID == 0xDD, check WPA IE */ ++ if (pucIEStart[1] >= 4) { ++ if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } /* check WPA IE length */ ++ /* check EID == 0xDD */ ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* parseSearchDesiredWPAIE */ ++ ++#if CFG_SUPPORT_WAPI ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WAPI Information Element . ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_WAPI && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredWAPIIE */ ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired HS2.0 Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredHS20IE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { ++ if (pucCurIE[1] >= ELEM_MIN_LEN_HS20_INDICATION) { ++ if (memcmp(&pucCurIE[2], "\x50\x6f\x9a\x10", 4) == 0) ++ return TRUE; ++ } ++ } ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredHS20IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired interworking Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredInterworkingIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { ++ switch (pucCurIE[1]) { ++ case IW_IE_LENGTH_ANO: ++ case IW_IE_LENGTH_ANO_HESSID: ++ case IW_IE_LENGTH_ANO_VENUE: ++ case IW_IE_LENGTH_ANO_VENUE_HESSID: ++ return TRUE; ++ ++ default: ++ break; ++ } ++ ++ } ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredInterworkingIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired Adv Protocol Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredAdvProtocolIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) ++ return TRUE; ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredAdvProtocolIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Check if exist the desired Roaming Consortium Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextIsDesiredRoamingConsortiumIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucCurIE); ++ ++ i4InfoElemLen = (INT_32) pucCurIE[1] + 2; ++ ++ if (pucCurIE[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) ++ return TRUE; ++ /* check desired EID */ ++ return FALSE; ++} /* wextIsDesiredRoamingConsortiumIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired HS2.0 Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { ++ if (pucIEStart[1] >= ELEM_MIN_LEN_HS20_INDICATION) { ++ if (memcmp(&pucIEStart[2], "\x50\x6f\x9a\x10", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredHS20IE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired interworking Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredInterworkingIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired Adv Protocol Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredAdvProtocolIE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired Roaming Consortium Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* wextSrchDesiredRoamingConsortiumIE */ ++#endif ++ ++#if CFG_SUPPORT_WPS ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Find the desired WPS Information Element according to desiredElemID. ++* ++* \param[in] pucIEStart IE starting address. ++* \param[in] i4TotalIeLen Total length of all the IE. ++* \param[in] ucDesiredElemId Desired element ID. ++* \param[out] ppucDesiredIE Pointer to the desired IE. ++* ++* \retval TRUE Find the desired IE. ++* \retval FALSE Desired IE not found. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) ++{ ++ INT_32 i4InfoElemLen; ++ ++ ASSERT(pucIEStart); ++ ASSERT(ppucDesiredIE); ++ ++ while (i4TotalIeLen >= 2) { ++ i4InfoElemLen = (INT_32) pucIEStart[1] + 2; ++ ++ if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { ++ if (ucDesiredElemId != 0xDD) { ++ /* Non 0xDD, OK! */ ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ /* EID == 0xDD, check WPS IE */ ++ if (pucIEStart[1] >= 4) { ++ if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", 4) == 0) { ++ *ppucDesiredIE = &pucIEStart[0]; ++ return TRUE; ++ } ++ } /* check WPS IE length */ ++ /* check EID == 0xDD */ ++ } ++ ++ /* check desired EID */ ++ /* Select next information element. */ ++ i4TotalIeLen -= i4InfoElemLen; ++ pucIEStart += i4InfoElemLen; ++ } ++ ++ return FALSE; ++} /* parseSearchDesiredWPSIE */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Get the name of the protocol used on the air. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] pcName Buffer to store protocol name string ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* ++* \note If netif_carrier_ok, protocol name is returned; ++* otherwise, "disconnected" is returned. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_name(IN struct net_device *prNetDev, IN struct iw_request_info *prIwrInfo, OUT char *pcName, IN char *pcExtra) ++{ ++ ENUM_PARAM_NETWORK_TYPE_T eNetWorkType = PARAM_NETWORK_TYPE_NUM; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcName); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcName)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (netif_carrier_ok(prNetDev)) { ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryNetworkTypeInUse, ++ &eNetWorkType, sizeof(eNetWorkType), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eNetWorkType) { ++ case PARAM_NETWORK_TYPE_DS: ++ strcpy(pcName, "IEEE 802.11b"); ++ break; ++ case PARAM_NETWORK_TYPE_OFDM24: ++ strcpy(pcName, "IEEE 802.11bgn"); ++ break; ++ case PARAM_NETWORK_TYPE_AUTOMODE: ++ case PARAM_NETWORK_TYPE_OFDM5: ++ strcpy(pcName, "IEEE 802.11abgn"); ++ break; ++ case PARAM_NETWORK_TYPE_FH: ++ default: ++ strcpy(pcName, "IEEE 802.11"); ++ break; ++ } ++ } else { ++ strcpy(pcName, "Disconnected"); ++ } ++ ++ return 0; ++} /* wext_get_name */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set the operating channel in the wireless device. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL ++* \param[in] prFreq Buffer to store frequency information ++* \param[in] pcExtra NULL ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS. ++* \retval -EINVAL Invalid channel frequency. ++* ++* \note If infrastructure mode is IBSS, new channel frequency is set to device. ++* The range of channel number depends on different regulatory domain. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_freq(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_freq *prIwFreq, IN char *pcExtra) ++{ ++ ++#if 0 ++ UINT_32 u4ChnlFreq; /* Store channel or frequency information */ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwFreq); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* ++ printk("set m:%d, e:%d, i:%d, flags:%d\n", ++ prIwFreq->m, prIwFreq->e, prIwFreq->i, prIwFreq->flags); ++ */ ++ ++ /* If setting by frequency, convert to a channel */ ++ if ((prIwFreq->e == 1) && (prIwFreq->m >= (int)2.412e8) && (prIwFreq->m <= (int)2.484e8)) { ++ ++ /* Change to KHz format */ ++ u4ChnlFreq = (UINT_32) (prIwFreq->m / (KILO / 10)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetFrequency, ++ &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ return -EINVAL; ++ } ++ /* Setting by channel number */ ++ else if ((prIwFreq->m > KILO) || (prIwFreq->e > 0)) ++ return -EOPNOTSUPP; ++ ++ /* Change to channel number format */ ++ u4ChnlFreq = (UINT_32) prIwFreq->m; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetChannel, &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ return -EINVAL; ++ ++#endif ++ ++ return 0; ++ ++} /* wext_set_freq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get the operating channel in the wireless device. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prFreq Buffer to store frequency information. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise ++* ++* \note If netif_carrier_ok, channel frequency information is stored in pFreq. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_freq(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_freq *prIwFreq, IN char *pcExtra) ++{ ++ UINT_32 u4Channel = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwFreq); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* GeorgeKuo: TODO skip checking in IBSS mode */ ++ if (!netif_carrier_ok(prNetDev)) ++ return -ENOTCONN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryFrequency, &u4Channel, sizeof(u4Channel), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prIwFreq->m = (int)u4Channel; /* freq in KHz */ ++ prIwFreq->e = 3; ++ ++ return 0; ++ ++} /* wext_get_freq */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set operating mode. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] pu4Mode Pointer to new operation mode. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If new mode is not supported. ++* ++* \note Device will run in new operation mode if it is valid. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_mode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN unsigned int *pu4Mode, IN char *pcExtra) ++{ ++ ENUM_PARAM_OP_MODE_T eOpMode; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pu4Mode); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ switch (*pu4Mode) { ++ case IW_MODE_AUTO: ++ eOpMode = NET_TYPE_AUTO_SWITCH; ++ break; ++ ++ case IW_MODE_ADHOC: ++ eOpMode = NET_TYPE_IBSS; ++ break; ++ ++ case IW_MODE_INFRA: ++ eOpMode = NET_TYPE_INFRA; ++ break; ++ ++ default: ++ DBGLOG(REQ, ERROR, "%s(): Set UNSUPPORTED Mode = %d.\n", __func__, *pu4Mode); ++ return -EOPNOTSUPP; ++ } ++ ++ /* printk("%s(): Set Mode = %d\n", __FUNCTION__, *pu4Mode); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ /* after set operation mode, key table are cleared */ ++ ++ /* reset wpa info */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ return 0; ++} /* wext_set_mode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get operating mode. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo NULL. ++* \param[out] pu4Mode Buffer to store operating mode information. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If data is valid. ++* \retval -EINVAL Otherwise. ++* ++* \note If netif_carrier_ok, operating mode information is stored in pu4Mode. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_mode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, OUT unsigned int *pu4Mode, IN char *pcExtra) ++{ ++ ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_NUM; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pu4Mode); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryInfrastructureMode, ++ &eOpMode, sizeof(eOpMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eOpMode) { ++ case NET_TYPE_IBSS: ++ *pu4Mode = IW_MODE_ADHOC; ++ break; ++ ++ case NET_TYPE_INFRA: ++ *pu4Mode = IW_MODE_INFRA; ++ break; ++ ++ case NET_TYPE_AUTO_SWITCH: ++ *pu4Mode = IW_MODE_AUTO; ++ break; ++ ++ default: ++ DBGLOG(REQ, ERROR, "%s(): Get UNKNOWN Mode.\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} /* wext_get_mode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get the valid range for each configurable STA setting value. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData Pointer to iw_point structure, not used. ++* \param[out] pcExtra Pointer to buffer which is allocated by caller of this ++* function, wext_support_ioctl() or ioctl_standard_call() in ++* wireless.c. ++* ++* \retval 0 If data is valid. ++* ++* \note The extra buffer (pcExtra) is filled with information from driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_range(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, OUT char *pcExtra) ++{ ++ struct iw_range *prRange = NULL; ++ PARAM_RATES_EX aucSuppRate = { 0 }; /* data buffers */ ++ int i = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ prRange = (struct iw_range *)pcExtra; ++ ++ memset(prRange, 0, sizeof(*prRange)); ++ prRange->throughput = 20000000; /* 20Mbps */ ++ prRange->min_nwid = 0; /* not used */ ++ prRange->max_nwid = 0; /* not used */ ++ ++ /* scan_capa not implemented */ ++ ++ /* event_capa[6]: kernel + driver capabilities */ ++ prRange->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) ++ | IW_EVENT_CAPA_MASK(SIOCGIWSCAN) ++ /* can't display meaningful string in iwlist ++ | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW) ++ | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE) ++ | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE) ++ | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND) ++ */ ++ ); ++ prRange->event_capa[1] = IW_EVENT_CAPA_K_1; ++ ++ /* report 2.4G channel and frequency only */ ++ prRange->num_channels = (__u16) NUM_CHANNELS; ++ prRange->num_frequency = (__u8) NUM_CHANNELS; ++ for (i = 0; i < NUM_CHANNELS; i++) { ++ /* iwlib takes this number as channel number */ ++ prRange->freq[i].i = i + 1; ++ prRange->freq[i].m = channel_freq[i]; ++ prRange->freq[i].e = 6; /* Values in table in MHz */ ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQuerySupportedRates, ++ &aucSuppRate, sizeof(aucSuppRate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX; i++) { ++ if (aucSuppRate[i] == 0) ++ break; ++ prRange->bitrate[i] = (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps */ ++ } ++ prRange->num_bitrates = i; ++ ++ prRange->min_rts = 0; ++ prRange->max_rts = 2347; ++ prRange->min_frag = 256; ++ prRange->max_frag = 2346; ++ ++ prRange->min_pmp = 0; /* power management by driver */ ++ prRange->max_pmp = 0; /* power management by driver */ ++ prRange->min_pmt = 0; /* power management by driver */ ++ prRange->max_pmt = 0; /* power management by driver */ ++ prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */ ++ prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */ ++ prRange->pm_capa = IW_POWER_ON; /* power management by driver */ ++ ++ prRange->encoding_size[0] = 5; /* wep40 */ ++ prRange->encoding_size[1] = 16; /* tkip */ ++ prRange->encoding_size[2] = 16; /* ckip */ ++ prRange->encoding_size[3] = 16; /* ccmp */ ++ prRange->encoding_size[4] = 13; /* wep104 */ ++ prRange->encoding_size[5] = 16; /* wep128 */ ++ prRange->num_encoding_sizes = 6; ++ prRange->max_encoding_tokens = 6; /* token? */ ++ ++#if WIRELESS_EXT < 17 ++ prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */ ++#else ++ prRange->txpower_capa = IW_TXPOW_RELATIVE; ++#endif ++ prRange->num_txpower = 5; ++ prRange->txpower[0] = 0; /* minimum */ ++ prRange->txpower[1] = 25; /* 25% */ ++ prRange->txpower[2] = 50; /* 50% */ ++ prRange->txpower[3] = 100; /* 100% */ ++ ++ prRange->we_version_compiled = WIRELESS_EXT; ++ prRange->we_version_source = WIRELESS_EXT; ++ ++ prRange->retry_capa = IW_RETRY_LIMIT; ++ prRange->retry_flags = IW_RETRY_LIMIT; ++ prRange->min_retry = 7; ++ prRange->max_retry = 7; ++ prRange->r_time_flags = IW_RETRY_ON; ++ prRange->min_r_time = 0; ++ prRange->max_r_time = 0; ++ ++ /* signal strength and link quality */ ++ /* Just define range here, reporting value moved to wext_get_stats() */ ++ prRange->sensitivity = -83; /* fixed value */ ++ prRange->max_qual.qual = 100; /* max 100% */ ++ prRange->max_qual.level = (__u8) (0x100 - 0); /* max 0 dbm */ ++ prRange->max_qual.noise = (__u8) (0x100 - 0); /* max 0 dbm */ ++ ++ /* enc_capa */ ++#if WIRELESS_EXT > 17 ++ prRange->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ /* min_pms; Minimal PM saving */ ++ /* max_pms; Maximal PM saving */ ++ /* pms_flags; How to decode max/min PM saving */ ++ ++ /* modul_capa; IW_MODUL_* bit field */ ++ /* bitrate_capa; Types of bitrates supported */ ++ ++ return 0; ++} /* wext_get_range */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set BSSID of AP to connect. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* ++* \note Desired AP's BSSID is set to driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_ap(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN struct sockaddr *prAddr, IN char *pcExtra) ++{ ++ return 0; ++} /* wext_set_ap */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get AP MAC address. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_ap(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct sockaddr *prAddr, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prAddr); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prAddr)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* if (!netif_carrier_ok(prNetDev)) { */ ++ /* return -ENOTCONN; */ ++ /* } */ ++ ++ if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED) { ++ /*memset(prAddr, 0, 6);*/ ++ memset(prAddr, 0, sizeof(struct sockaddr)); ++ return 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssid, prAddr->sa_data, ETH_ALEN, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ return 0; ++} /* wext_get_ap */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set mlme operation request. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData Pointer of iw_point header. ++* \param[in] pcExtra Pointer to iw_mlme structure mlme request information. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP unsupported IW_MLME_ command. ++* \retval -EINVAL Set MLME Fail, different bssid. ++* ++* \note Driver will start mlme operation if valid. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_mlme(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, IN char *pcExtra) ++{ ++ struct iw_mlme *prMlme = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ prMlme = (struct iw_mlme *)pcExtra; ++ if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) { ++ if (!netif_carrier_ok(prNetDev)) { ++ DBGLOG(REQ, WARN, "[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n"); ++ return 0; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ return 0; ++ } ++ DBGLOG(REQ, WARN, "[wifi] unsupported IW_MLME_ command :%d\n", prMlme->cmd); ++ return -EOPNOTSUPP; ++ ++} /* wext_set_mlme */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To issue scan request. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prData NULL. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EFAULT Tx power is off. ++* ++* \note Device will start scanning. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_scan(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN union iwreq_data *prData, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ int essid_len = 0; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_DEV(prNetDev)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++#if WIRELESS_EXT > 17 ++ /* retrieve SSID */ ++ if (prData) ++ essid_len = ((struct iw_scan_req *)(((struct iw_point *)prData)->pointer))->essid_len; ++#endif ++ ++ init_completion(&prGlueInfo->rScanComp); ++ ++ /* TODO: parse flags and issue different scan requests? */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetBssidListScan, pcExtra, essid_len, FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * KAL_HZ); */ ++ /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ ++ ++ return 0; ++} /* wext_set_scan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To write the ie to buffer ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) ++{ ++ size_t i; ++ char *pos = buf, *end = buf + buf_size; ++ int ret; ++ ++ if (buf_size == 0) ++ return 0; ++ ++ for (i = 0; i < len; i++) { ++ ret = snprintf(pos, end - pos, "%02x", data[i]); ++ if (ret < 0 || ret >= end - pos) { ++ end[-1] = '\0'; ++ return pos - buf; ++ } ++ pos += ret; ++ } ++ end[-1] = '\0'; ++ return pos - buf; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get scan results, transform results from driver's format to WE's. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prData Pointer to iw_point structure, pData->length is the size of ++* pcExtra buffer before used, and is updated after filling scan ++* results. ++* \param[out] pcExtra Pointer to buffer which is allocated by caller of this ++* function, wext_support_ioctl() or ioctl_standard_call() in ++* wireless.c. ++* ++* \retval 0 For success. ++* \retval -ENOMEM If dynamic memory allocation fail. ++* \retval -E2BIG Invalid length. ++* ++* \note Scan results is filled into pcExtra buffer, data size is updated in ++* pData->length. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_scan(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT struct iw_point *prData, IN char *pcExtra) ++{ ++ UINT_32 i = 0; ++ UINT_32 j = 0; ++ P_PARAM_BSSID_LIST_EX_T prList = NULL; ++ P_PARAM_BSSID_EX_T prBss = NULL; ++ P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; ++ struct iw_event iwEvent; /* local iw_event buffer */ ++ ++ /* write pointer of extra buffer */ ++ char *pcCur = NULL; ++ /* pointer to the end of last full entry in extra buffer */ ++ char *pcValidEntryEnd = NULL; ++ char *pcEnd = NULL; /* end of extra buffer */ ++ ++ UINT_32 u4AllocBufLen = 0; ++ ++ /* arrange rate information */ ++ UINT_32 u4HighestRate = 0; ++ char aucRatesBuf[64]; ++ UINT_32 u4BufIndex; ++ ++ /* return value */ ++ int ret = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* Initialize local variables */ ++ pcCur = pcExtra; ++ pcValidEntryEnd = pcExtra; ++ pcEnd = pcExtra + prData->length; /* end of extra buffer */ ++ ++ /* Allocate another query buffer with the same size of extra buffer */ ++ u4AllocBufLen = prData->length; ++ prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); ++ if (prList == NULL) { ++ DBGLOG(REQ, ERROR, "[wifi] no memory for scan list:%d\n", prData->length); ++ ret = -ENOMEM; ++ goto error; ++ } ++ prList->u4NumberOfItems = 0; ++ ++ /* wait scan done */ ++ /* printk ("wait for scan results\n"); */ ++ /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * KAL_HZ); */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_INVALID_LENGTH) { ++ /* Buffer length is not large enough. */ ++ /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ ++ ++#if WIRELESS_EXT >= 17 ++ /* This feature is supported in WE-17 or above, limited by iwlist. ++ ** Return -E2BIG and iwlist will request again with a larger buffer. ++ */ ++ ret = -E2BIG; ++ /* Update length to give application a hint on result length */ ++ prData->length = (__u16) u4BufLen; ++ goto error; ++#else ++ /* Realloc a larger query buffer here, but don't write too much to extra ++ ** buffer when filling it later. ++ */ ++ kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); ++ ++ u4AllocBufLen = u4BufLen; ++ prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); ++ if (prList == NULL) { ++ DBGLOG(REQ, ERROR, "[wifi] no memory for larger scan list :%u\n", u4BufLen); ++ ret = -ENOMEM; ++ goto error; ++ } ++ prList->NumberOfItems = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus == WLAN_STATUS_INVALID_LENGTH) { ++ DBGLOG(REQ, ERROR, "[wifi] larger buf:%u result:%u\n", u4AllocBufLen, u4BufLen); ++ ret = -E2BIG; ++ prData->length = (__u16) u4BufLen; ++ goto error; ++ } ++#endif /* WIRELESS_EXT >= 17 */ ++ ++ } ++ ++ if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) { ++ DBGLOG(REQ, WARN, "[wifi] strange scan result count:%u\n", prList->u4NumberOfItems); ++ goto error; ++ } ++ ++ /* Copy required data from pList to pcExtra */ ++ prBss = &prList->arBssid[0]; /* set to the first entry */ ++ for (i = 0; i < prList->u4NumberOfItems; ++i) { ++ /* BSSID */ ++ iwEvent.cmd = SIOCGIWAP; ++ iwEvent.len = IW_EV_ADDR_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER; ++ ether_addr_copy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress); ++ memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN); ++ pcCur += IW_EV_ADDR_LEN; ++ ++ /* SSID */ ++ iwEvent.cmd = SIOCGIWESSID; ++ /* Modification to user space pointer(essid.pointer) is not needed. */ ++ iwEvent.u.essid.length = (__u16) prBss->rSsid.u4SsidLen; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length; ++ ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.essid.flags = 1; ++ iwEvent.u.essid.pointer = NULL; ++ ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, iwEvent.len); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, iwEvent.u.essid.length); ++ pcCur += iwEvent.len; ++ /* Frequency */ ++ iwEvent.cmd = SIOCGIWFREQ; ++ iwEvent.len = IW_EV_FREQ_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig; ++ iwEvent.u.freq.e = 3; /* (in KHz) */ ++ iwEvent.u.freq.i = 0; ++ memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN); ++ pcCur += IW_EV_FREQ_LEN; ++ ++ /* Operation Mode */ ++ iwEvent.cmd = SIOCGIWMODE; ++ iwEvent.len = IW_EV_UINT_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ if (prBss->eOpMode == NET_TYPE_IBSS) ++ iwEvent.u.mode = IW_MODE_ADHOC; ++ else if (prBss->eOpMode == NET_TYPE_INFRA) ++ iwEvent.u.mode = IW_MODE_INFRA; ++ else ++ iwEvent.u.mode = IW_MODE_AUTO; ++ memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN); ++ pcCur += IW_EV_UINT_LEN; ++ ++ /* Quality */ ++ iwEvent.cmd = IWEVQUAL; ++ iwEvent.len = IW_EV_QUAL_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.qual.qual = 0; /* Quality not available now */ ++ /* -100 < Rssi < -10, normalized by adding 0x100 */ ++ iwEvent.u.qual.level = 0x100 + prBss->rRssi; ++ iwEvent.u.qual.noise = 0; /* Noise not available now */ ++ iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; ++ memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN); ++ pcCur += IW_EV_QUAL_LEN; ++ ++ /* Security Mode */ ++ iwEvent.cmd = SIOCGIWENCODE; ++ iwEvent.len = IW_EV_POINT_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.pointer = NULL; ++ iwEvent.u.data.flags = 0; ++ iwEvent.u.data.length = 0; ++ if (!prBss->u4Privacy) ++ iwEvent.u.data.flags |= IW_ENCODE_DISABLED; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ pcCur += IW_EV_POINT_LEN; ++ ++ /* rearrange rate information */ ++ u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):"); ++ u4HighestRate = 0; ++ for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) { ++ UINT_8 curRate = prBss->rSupportedRates[j] & 0x7F; ++ ++ if (curRate == 0) ++ break; ++ ++ if (curRate > u4HighestRate) ++ u4HighestRate = curRate; ++ ++ if (curRate == RATE_5_5M) ++ u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " 5.5"); ++ else ++ u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " %d", curRate / 2); ++#if DBG ++ if (u4BufIndex > sizeof(aucRatesBuf)) { ++ /* printk("rate info too long\n"); */ ++ break; ++ } ++#endif ++ } ++ /* Report Highest Rates */ ++ iwEvent.cmd = SIOCGIWRATE; ++ iwEvent.len = IW_EV_PARAM_LEN; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.bitrate.value = u4HighestRate * 500000; ++ iwEvent.u.bitrate.fixed = 0; ++ iwEvent.u.bitrate.disabled = 0; ++ iwEvent.u.bitrate.flags = 0; ++ memcpy(pcCur, &iwEvent, iwEvent.len); ++ pcCur += iwEvent.len; ++ ++#if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */ ++ /* Report Residual Rates */ ++ iwEvent.cmd = IWEVCUSTOM; ++ iwEvent.u.data.length = u4BufIndex; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.flags = 0; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex); ++ pcCur += iwEvent.len; ++#endif /* WIRELESS_EXT >= 15 */ ++ ++ if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */ ++ if (wextSrchDesiredWPSIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#endif ++ ++ /* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */ ++ /* pBss->IEs starts from timestamp */ ++ if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), ++ 0x30, (PUINT_8 *) &prDesiredIE)) { ++ ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++ } ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ if (wextSrchDesiredWAPIIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], ++ prBss->u4IELength - sizeof(PARAM_FIXED_IEs), (PUINT_8 *) &prDesiredIE)) { ++ ++#if 0 ++ iwEvent.cmd = IWEVGENIE; ++ iwEvent.u.data.flags = 1; ++ iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++#if WIRELESS_EXT <= 18 ++ memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); ++#else ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++#endif ++ memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); ++ pcCur += iwEvent.len; ++#else ++ iwEvent.cmd = IWEVCUSTOM; ++ iwEvent.u.data.length = (2 + prDesiredIE->ucLength) * 2 + 8 /* wapi_ie= */; ++ iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; ++ if ((pcCur + iwEvent.len) > pcEnd) ++ break; ++ iwEvent.u.data.flags = 1; ++ ++ memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); ++ memcpy(pcCur + IW_EV_LCP_LEN, ++ &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); ++ ++ pcCur += (IW_EV_POINT_LEN); ++ ++ pcCur += sprintf(pcCur, "wapi_ie="); ++ ++ snprintf_hex(pcCur, pcEnd - pcCur, (UINT_8 *) prDesiredIE, prDesiredIE->ucLength + 2); ++ ++ pcCur += (2 + prDesiredIE->ucLength) * 2 /* iwEvent.len */; ++#endif ++ } ++#endif ++ /* Complete an entry. Update end of valid entry */ ++ pcValidEntryEnd = pcCur; ++ /* Extract next bss */ ++ prBss = (P_PARAM_BSSID_EX_T) ((char *)prBss + prBss->u4Length); ++ } ++ ++ /* Update valid data length for caller function and upper layer ++ * applications. ++ */ ++ prData->length = (pcValidEntryEnd - pcExtra); ++ /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ ++ ++ /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ ++ ++error: ++ /* free local query buffer */ ++ if (prList) ++ kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); ++ ++ return ret; ++} /* wext_get_scan */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set desired network name ESSID. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEssid Pointer of iw_point header. ++* \param[in] pcExtra Pointer to buffer srtoring essid string. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -E2BIG Essid string length is too big. ++* \retval -EINVAL pcExtra is null pointer. ++* \retval -EFAULT Driver fail to set new essid. ++* ++* \note If string length is ok, device will try connecting to the new network. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_essid(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, IN char *pcExtra) ++{ ++ PARAM_SSID_T rNewSsid; ++ UINT_32 cipher; ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEssid); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prEssid->length > IW_ESSID_MAX_SIZE) ++ return -E2BIG; ++ ++ /* set auth mode */ ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { ++ eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? ++ AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; ++ /* printk(KERN_INFO "IW_AUTH_WPA_VERSION_DISABLED->Param_AuthMode%s\n", */ ++ /* (eAuthMode == AUTH_MODE_OPEN) ? "Open" : "Shared"); */ ++ } else { ++ /* set auth mode */ ++ switch (prGlueInfo->rWpaInfo.u4KeyMgmt) { ++ case IW_AUTH_KEY_MGMT_802_1X: ++ eAuthMode = ++ (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? ++ AUTH_MODE_WPA : AUTH_MODE_WPA2; ++ /* printk("IW_AUTH_KEY_MGMT_802_1X->AUTH_MODE_WPA%s\n", */ ++ /* (eAuthMode == AUTH_MODE_WPA) ? "" : "2"); */ ++ break; ++ case IW_AUTH_KEY_MGMT_PSK: ++ eAuthMode = ++ (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? ++ AUTH_MODE_WPA_PSK : AUTH_MODE_WPA2_PSK; ++ /* printk("IW_AUTH_KEY_MGMT_PSK->AUTH_MODE_WPA%sPSK\n", */ ++ /* (eAuthMode == AUTH_MODE_WPA_PSK) ? "" : "2"); */ ++ break; ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ case IW_AUTH_KEY_MGMT_WAPI_PSK: ++ break; ++ case IW_AUTH_KEY_MGMT_WAPI_CERT: ++ break; ++#endif ++ ++/* #if defined (IW_AUTH_KEY_MGMT_WPA_NONE) */ ++/* case IW_AUTH_KEY_MGMT_WPA_NONE: */ ++/* eAuthMode = AUTH_MODE_WPA_NONE; */ ++/* //printk("IW_AUTH_KEY_MGMT_WPA_NONE->AUTH_MODE_WPA_NONE\n"); */ ++/* break; */ ++/* #endif */ ++#if CFG_SUPPORT_802_11W ++ case IW_AUTH_KEY_MGMT_802_1X_SHA256: ++ eAuthMode = AUTH_MODE_WPA2; ++ break; ++ case IW_AUTH_KEY_MGMT_PSK_SHA256: ++ eAuthMode = AUTH_MODE_WPA2_PSK; ++ break; ++#endif ++ default: ++ /* printk(KERN_INFO DRV_NAME"strange IW_AUTH_KEY_MGMT : %ld set auto switch\n", */ ++ /* prGlueInfo->rWpaInfo.u4KeyMgmt); */ ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ break; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ /* set encryption status */ ++ cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; ++ if (cipher & IW_AUTH_CIPHER_CCMP) { ++ /* printk("IW_AUTH_CIPHER_CCMP->ENUM_ENCRYPTION3_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION3_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_TKIP) { ++ /* printk("IW_AUTH_CIPHER_TKIP->ENUM_ENCRYPTION2_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION2_ENABLED; ++ } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { ++ /* printk("IW_AUTH_CIPHER_WEPx->ENUM_ENCRYPTION1_ENABLED\n"); */ ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ } else if (cipher & IW_AUTH_CIPHER_NONE) { ++ /* printk("IW_AUTH_CIPHER_NONE->ENUM_ENCRYPTION_DISABLED\n"); */ ++ if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) ++ eEncStatus = ENUM_ENCRYPTION1_ENABLED; ++ else ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } else { ++ /* printk("unknown IW_AUTH_CIPHER->Param_EncryptionDisabled\n"); */ ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++#if WIRELESS_EXT < 21 ++ /* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel before ++ ** 2.6.19. Cut the trailing '\0'. ++ */ ++ rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0; ++#else ++ rNewSsid.u4SsidLen = prEssid->length; ++#endif ++ kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen); ++ ++ /* ++ rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0'; ++ printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid); ++ */ ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetSsid, ++ (PVOID)&rNewSsid, ++ sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen) != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_WARNING "Fail to set ssid\n"); */ ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* wext_set_essid */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get current network name ESSID. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEssid Pointer to iw_point structure containing essid information. ++* \param[out] pcExtra Pointer to buffer srtoring essid string. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, network essid is stored in pcExtra. ++*/ ++/*----------------------------------------------------------------------------*/ ++/* static PARAM_SSID_T ssid; */ ++static int ++wext_get_essid(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, OUT char *pcExtra) ++{ ++ /* PARAM_SSID_T ssid; */ ++ ++ P_PARAM_SSID_T prSsid; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEssid); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* if (!netif_carrier_ok(prNetDev)) { */ ++ /* return -ENOTCONN; */ ++ /* } */ ++ ++ prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE); ++ ++ if (!prSsid) ++ return -ENOMEM; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQuerySsid, prSsid, sizeof(PARAM_SSID_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if ((rStatus == WLAN_STATUS_SUCCESS) && (prSsid->u4SsidLen <= MAX_SSID_LEN)) { ++ kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen); ++ prEssid->length = prSsid->u4SsidLen; ++ prEssid->flags = 1; ++ } ++ ++ kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T)); ++ ++ return 0; ++} /* wext_get_essid */ ++ ++#if 0 ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set tx desired bit rate. Three cases here ++* iwconfig wlan0 auto -> Set to origianl supported rate set. ++* iwconfig wlan0 18M -> Imply "fixed" case, set to 18Mbps as desired rate. ++* iwconfig wlan0 18M auto -> Set to auto rate lower and equal to 18Mbps ++* ++* \param[in] prNetDev Pointer to the net_device handler. ++* \param[in] prIwReqInfo Pointer to the Request Info. ++* \param[in] prRate Pointer to the Rate Parameter. ++* \param[in] pcExtra Pointer to the extra buffer. ++* ++* \retval 0 Update desired rate. ++* \retval -EINVAL Wrong parameter ++*/ ++/*----------------------------------------------------------------------------*/ ++int ++wext_set_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra) ++{ ++ PARAM_RATES_EX aucSuppRate = { 0 }; ++ PARAM_RATES_EX aucNewRate = { 0 }; ++ UINT_32 u4NewRateLen = 0; ++ UINT_32 i; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRate); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* ++ printk("value = %d, fixed = %d, disable = %d, flags = %d\n", ++ prRate->value, prRate->fixed, prRate->disabled, prRate->flags); ++ */ ++ ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuerySupportedRates, &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); ++ ++ /* Case: AUTO */ ++ if (prRate->value < 0) { ++ if (prRate->fixed == 0) { ++ /* iwconfig wlan0 rate auto */ ++ ++ /* set full supported rate to device */ ++ /* printk("wlanoidQuerySupportedRates():u4BufLen = %ld\n", u4BufLen); */ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetDesiredRates, ++ &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); ++ return 0; ++ } ++ /* iwconfig wlan0 rate fixed */ ++ ++ /* fix rate to what? DO NOTHING */ ++ return -EINVAL; ++ } ++ ++ aucNewRate[0] = prRate->value / 500000; /* In unit of 500k */ ++ ++ for (i = 0; i < PARAM_MAX_LEN_RATES_EX; i++) { ++ /* check the given value is supported */ ++ if (aucSuppRate[i] == 0) ++ break; ++ ++ if (aucNewRate[0] == aucSuppRate[i]) { ++ u4NewRateLen = 1; ++ break; ++ } ++ } ++ ++ if (u4NewRateLen == 0) { ++ /* the given value is not supported */ ++ /* return error or use given rate as upper bound? */ ++ return -EINVAL; ++ } ++ ++ if (prRate->fixed == 0) { ++ /* add all rates lower than desired rate */ ++ for (i = 0; i < PARAM_MAX_LEN_RATES_EX; ++i) { ++ if (aucSuppRate[i] == 0) ++ break; ++ ++ if (aucSuppRate[i] < aucNewRate[0]) ++ aucNewRate[u4NewRateLen++] = aucSuppRate[i]; ++ } ++ } ++ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetDesiredRates, &aucNewRate, sizeof(aucNewRate), &u4BufLen); ++ return 0; ++} /* wext_set_rate */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get current tx bit rate. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prRate Pointer to iw_param structure to store current tx rate. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 If netif_carrier_ok. ++* \retval -ENOTCONN Otherwise. ++* ++* \note If netif_carrier_ok, current tx rate is stored in pRate. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRate, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ UINT_32 u4Rate = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRate); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (!netif_carrier_ok(prNetDev)) ++ return -ENOTCONN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */ ++ prRate->fixed = 0; ++ ++ return 0; ++} /* wext_get_rate */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set RTS/CTS theshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prRts Pointer to iw_param structure containing rts threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 For success. ++* \retval -EINVAL Given value is out of range. ++* ++* \note If given value is valid, device will follow the new setting. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_rts(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prRts, IN char *pcExtra) ++{ ++ PARAM_RTS_THRESHOLD u4RtsThresh; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRts); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prRts->disabled == 1) ++ u4RtsThresh = 2347; ++ else if (prRts->value < 0 || prRts->value > 2347) ++ return -EINVAL; ++ ++ u4RtsThresh = (PARAM_RTS_THRESHOLD) prRts->value; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRtsThreshold, ++ &u4RtsThresh, sizeof(u4RtsThresh), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prRts->value = (typeof(prRts->value)) u4RtsThresh; ++ prRts->disabled = (prRts->value > 2347) ? 1 : 0; ++ prRts->fixed = 1; ++ ++ return 0; ++} /* wext_set_rts */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get RTS/CTS theshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prRts Pointer to iw_param structure containing rts threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note RTS threshold is stored in pRts. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_rts(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRts, IN char *pcExtra) ++{ ++ PARAM_RTS_THRESHOLD u4RtsThresh = 0; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prRts); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryRtsThreshold, ++ &u4RtsThresh, sizeof(u4RtsThresh), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ prRts->value = (typeof(prRts->value)) u4RtsThresh; ++ prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0; ++ prRts->fixed = 1; ++ ++ return 0; ++} /* wext_get_rts */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get fragmentation threshold. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prFrag Pointer to iw_param structure containing frag threshold. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note RTS threshold is stored in pFrag. Fragmentation is disabled. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_frag(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prFrag, IN char *pcExtra) ++{ ++ ASSERT(prFrag); ++ ++ prFrag->value = 2346; ++ prFrag->fixed = 1; ++ prFrag->disabled = 1; ++ return 0; ++} /* wext_get_frag */ ++ ++#if 1 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set TX power, or enable/disable the radio. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prTxPow Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used ++* to enable/disable the radio. ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static int ++wext_set_txpow(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prTxPow, IN char *pcExtra) ++{ ++ int ret = 0; ++ /* PARAM_DEVICE_POWER_STATE ePowerState; */ ++ ENUM_ACPI_STATE_T ePowerState; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prTxPow); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (prTxPow->disabled) { ++ /* <1> disconnect */ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "######set disassoc failed\n"); ++ else ++ DBGLOG(REQ, TRACE, "######set assoc ok\n"); ++ /* <2> mark to power state flag */ ++ ePowerState = ACPI_STATE_D0; ++ DBGLOG(REQ, INFO, "set to acpi d3(0)\n"); ++ wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); ++ ++ } else { ++ ePowerState = ACPI_STATE_D0; ++ DBGLOG(REQ, INFO, "set to acpi d0\n"); ++ wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); ++ } ++ ++ prGlueInfo->ePowerState = ePowerState; ++ ++ return ret; ++} /* wext_set_txpow */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get TX power. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prTxPow Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Tx power is stored in pTxPow. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_txpow(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prTxPow, IN char *pcExtra) ++{ ++ /* PARAM_DEVICE_POWER_STATE ePowerState; */ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prTxPow); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not ++ * current state. Use GLUE_INFO_T to store state. ++ */ ++ /* ePowerState = prGlueInfo->ePowerState; */ ++ ++ /* TxPow parameters: Fixed at relative 100% */ ++#if WIRELESS_EXT < 17 ++ prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */ ++#else ++ prTxPow->flags = IW_TXPOW_RELATIVE; ++#endif ++ prTxPow->value = 100; ++ prTxPow->fixed = 1; ++ /* prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? FALSE : TRUE; */ ++ prTxPow->disabled = TRUE; ++ ++ return 0; ++} /* wext_get_txpow */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Buffer to store key content. ++* ++* \retval 0 Success. ++* ++* \note Securiry information is stored in pEnc except key content. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_encode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_point *prEnc, IN char *pcExtra) ++{ ++#if 1 ++ /* ENUM_ENCRYPTION_STATUS_T eEncMode; */ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode = ENUM_WEP_ENABLED; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prEnc)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidQueryEncryptionStatus, ++ &eEncMode, sizeof(eEncMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ switch (eEncMode) { ++ case ENUM_WEP_DISABLED: ++ prEnc->flags = IW_ENCODE_DISABLED; ++ break; ++ case ENUM_WEP_ENABLED: ++ prEnc->flags = IW_ENCODE_ENABLED; ++ break; ++ case ENUM_WEP_KEY_ABSENT: ++ prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ break; ++ default: ++ prEnc->flags = IW_ENCODE_ENABLED; ++ break; ++ } ++ ++ /* Cipher, Key Content, Key ID can't be queried */ ++ prEnc->flags |= IW_ENCODE_NOKEY; ++#endif ++ return 0; ++} /* wext_get_encode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_8 wepBuf[48]; ++ ++static int ++wext_set_encode(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) ++{ ++#if 1 ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ /* UINT_8 wepBuf[48]; */ ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* reset to default mode */ ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4KeyMgmt = 0; ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++#if CFG_SUPPORT_802_11W ++ prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; ++#endif ++ ++ /* iwconfig wlan0 key off */ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { ++ eAuthMode = AUTH_MODE_OPEN; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ eEncStatus = ENUM_ENCRYPTION_DISABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ return 0; ++ } ++ ++ /* iwconfig wlan0 key 0123456789 */ ++ /* iwconfig wlan0 key s:abcde */ ++ /* iwconfig wlan0 key 0123456789 [1] */ ++ /* iwconfig wlan0 key 01234567890123456789012345 [1] */ ++ /* check key size for WEP */ ++ if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) { ++ /* prepare PARAM_WEP key structure */ ++ prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++ if (prWepKey->u4KeyIndex > 3) { ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ prWepKey->u4KeyIndex |= 0x80000000; ++ prWepKey->u4Length = 12 + prEnc->length; ++ prWepKey->u4KeyLength = prEnc->length; ++ kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* change to auto switch */ ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSetAuthMode fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++ ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ ++ eEncStatus = ENUM_WEP_ENABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, ++ sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++ ++ return 0; ++ } ++#endif ++ return -EOPNOTSUPP; ++} /* wext_set_encode */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set power management. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prPower Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note New Power Management Mode is set to driver. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_power(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prPower, IN char *pcExtra) ++{ ++#if 1 ++ ++ PARAM_POWER_MODE ePowerMode; ++ INT_32 i4PowerValue; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ if (prPower->disabled) { ++ ePowerMode = Param_PowerModeCAM; ++ } else { ++ i4PowerValue = prPower->value; ++#if WIRELESS_EXT < 21 ++ i4PowerValue /= 1000000; ++#endif ++ if (i4PowerValue == 0) { ++ ePowerMode = Param_PowerModeCAM; ++ } else if (i4PowerValue == 1) { ++ ePowerMode = Param_PowerModeMAX_PSP; ++ } else if (i4PowerValue == 2) { ++ ePowerMode = Param_PowerModeFast_PSP; ++ } else { ++ DBGLOG(REQ, ERROR, "%s(): unsupported power management mode value = %d.\n", ++ __func__, prPower->value); ++ ++ return -EINVAL; ++ } ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSet802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ ++ return -EFAULT; ++ } ++#endif ++ return 0; ++} /* wext_set_power */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To get power management. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[out] prPower Pointer to iw_param structure containing tx power setting. ++* \param[in] pcExtra NULL. ++* ++* \retval 0 Success. ++* ++* \note Power management mode is stored in pTxPow->value. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_get_power(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prPower, IN char *pcExtra) ++{ ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM; ++ ++ ASSERT(prNetDev); ++ ASSERT(prPower); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++#if 0 ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), TRUE, TRUE, &u4BufLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ &ePowerMode, sizeof(ePowerMode), &u4BufLen); ++#endif ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return -EFAULT; ++ ++ prPower->value = 0; ++ prPower->disabled = 1; ++ ++ if (Param_PowerModeCAM == ePowerMode) { ++ prPower->value = 0; ++ prPower->disabled = 1; ++ } else if (Param_PowerModeMAX_PSP == ePowerMode) { ++ prPower->value = 1; ++ prPower->disabled = 0; ++ } else if (Param_PowerModeFast_PSP == ePowerMode) { ++ prPower->value = 2; ++ prPower->disabled = 0; ++ } ++ ++ prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; ++#if WIRELESS_EXT < 21 ++ prPower->value *= 1000000; ++#endif ++ ++ /* printk(KERN_INFO "wext_get_power value(%d) disabled(%d) flag(0x%x)\n", */ ++ /* prPower->value, prPower->disabled, prPower->flags); */ ++ ++ return 0; ++} /* wext_get_power */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set authentication parameters. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] rpAuth Pointer to iw_param structure containing authentication information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++wext_set_auth(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_param *prAuth, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prAuth); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prAuth)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ /* Save information to glue info and process later when ssid is set. */ ++ switch (prAuth->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++#if CFG_SUPPORT_WAPI ++ if (wlanQueryWapiMode(prGlueInfo->prAdapter)) { ++ prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; ++ } else { ++ prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; ++ } ++#else ++ prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; ++#endif ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value; ++ break; ++ ++ case IW_AUTH_CIPHER_GROUP: ++ prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value; ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value; ++#if CFG_SUPPORT_WAPI ++ if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_PSK || ++ prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_CERT) { ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiMode, ++ &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); ++ } ++#endif ++ if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS) ++ prGlueInfo->fgWpsActive = TRUE; ++ else ++ prGlueInfo->fgWpsActive = FALSE; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value; ++ break; ++#if CFG_SUPPORT_802_11W ++ case IW_AUTH_MFP: ++ /* printk("wext_set_auth IW_AUTH_MFP=%d\n", prAuth->value); */ ++ prGlueInfo->rWpaInfo.u4Mfp = prAuth->value; ++ break; ++#endif ++#if CFG_SUPPORT_WAPI ++ case IW_AUTH_WAPI_ENABLED: ++ { ++ UINT_32 u4BufLen; ++ WLAN_STATUS rStatus; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiMode, ++ &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); ++ break; ++#endif ++ default: ++ /* ++ printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", prAuth->flags); ++ */ ++ break; ++ } ++ return 0; ++} /* wext_set_auth */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To set encryption cipher and key. ++* ++* \param[in] prDev Net device requested. ++* \param[in] prIwrInfo NULL. ++* \param[in] prEnc Pointer to iw_point structure containing securiry information. ++* \param[in] pcExtra Pointer to key string buffer. ++* ++* \retval 0 Success. ++* \retval -EINVAL Key ID error for WEP. ++* \retval -EFAULT Setting parameters to driver fail. ++* \retval -EOPNOTSUPP Key size not supported. ++* ++* \note Securiry information is stored in pEnc. ++*/ ++/*----------------------------------------------------------------------------*/ ++#if CFG_SUPPORT_WAPI ++UINT_8 keyStructBuf[320]; /* add/remove key shared buffer */ ++#else ++UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ ++#endif ++ ++static int ++wext_set_encode_ext(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) ++{ ++ P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; ++ P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; ++ ++ P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; ++ ++ struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *)pcExtra; ++ ++ ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; ++ ENUM_PARAM_AUTH_MODE_T eAuthMode; ++ /* ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; */ ++ ++#if CFG_SUPPORT_WAPI ++ P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; ++#endif ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prEnc); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ memset(keyStructBuf, 0, sizeof(keyStructBuf)); ++ ++#if CFG_SUPPORT_WAPI ++ if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { ++ if (prEnc->flags & IW_ENCODE_DISABLED) { ++ /* printk(KERN_INFO "[wapi] IW_ENCODE_DISABLED\n"); */ ++ return 0; ++ } ++ /* KeyID */ ++ prWpiKey->ucKeyID = (prEnc->flags & IW_ENCODE_INDEX); ++ prWpiKey->ucKeyID--; ++ if (prWpiKey->ucKeyID > 1) { ++ /* key id is out of range */ ++ /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ ++ return -EINVAL; ++ } ++ ++ if (prIWEncExt->key_len != 32) { ++ /* key length not valid */ ++ /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ ++ return -EINVAL; ++ } ++ /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ ++ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX; ++ } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; ++ prWpiKey->eDirection = ENUM_WPI_RX_TX; ++ } ++ ++ /* PN */ ++ { ++ UINT_32 i; ++ ++ for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) ++ prWpiKey->aucPN[i] = prIWEncExt->tx_seq[i]; ++ for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) ++ prWpiKey->aucPN[IW_ENCODE_SEQ_MAX_SIZE + i] = prIWEncExt->rx_seq[i]; ++ } ++ ++ /* BSSID */ ++ memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr.sa_data, 6); ++ ++ memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); ++ prWpiKey->u4LenWPIEK = 16; ++ ++ memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); ++ prWpiKey->u4LenWPICK = 16; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiKey, ++ prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* Do nothing */ ++ /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ ++ } ++ } else ++#endif ++ { ++ ++ if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { ++ prRemoveKey->u4Length = sizeof(*prRemoveKey); ++ memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ /* ++ printk("IW_ENCODE_DISABLED: ID:%d, Addr:[ %pM ]\n", ++ prRemoveKey->KeyIndex, prRemoveKey->BSSID); ++ */ ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetRemoveKey, ++ prRemoveKey, prRemoveKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, INFO, "remove key error:%x\n", rStatus); ++ return 0; ++ } ++ /* return 0; */ ++ /* printk ("alg %x\n", prIWEncExt->alg); */ ++ ++ switch (prIWEncExt->alg) { ++ case IW_ENCODE_ALG_NONE: ++ break; ++ case IW_ENCODE_ALG_WEP: ++ /* iwconfig wlan0 key 0123456789 */ ++ /* iwconfig wlan0 key s:abcde */ ++ /* iwconfig wlan0 key 0123456789 [1] */ ++ /* iwconfig wlan0 key 01234567890123456789012345 [1] */ ++ /* check key size for WEP */ ++ if (prIWEncExt->key_len == 5 || prIWEncExt->key_len == 13 || prIWEncExt->key_len == 16) { ++ /* prepare PARAM_WEP key structure */ ++ prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++ if (prWepKey->u4KeyIndex > 3) { ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ prWepKey->u4KeyIndex |= 0x80000000; ++ prWepKey->u4Length = 12 + prIWEncExt->key_len; ++ prWepKey->u4KeyLength = prIWEncExt->key_len; ++ /* kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prIWEncExt->key_len); */ ++ kalMemCopy(prWepKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddWep, ++ prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ /* change to auto switch */ ++ prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; ++ eAuthMode = AUTH_MODE_AUTO_SWITCH; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAuthMode, ++ &eAuthMode, ++ sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetAuthMode fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; ++ ++ eEncStatus = ENUM_WEP_ENABLED; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetEncryptionStatus, ++ &eEncStatus, ++ sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), ++ FALSE, FALSE, FALSE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "wlanoidSetEncryptionStatus fail 0x%x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ } else { ++ DBGLOG(REQ, INFO, "key length %x\n", prIWEncExt->key_len); ++ DBGLOG(REQ, INFO, "key error\n"); ++ } ++ ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ case IW_ENCODE_ALG_CCMP: ++#if CFG_SUPPORT_802_11W ++ case IW_ENCODE_ALG_AES_CMAC: ++#endif ++ { ++ ++ /* KeyID */ ++ prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? ++ (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; ++#if CFG_SUPPORT_802_11W ++ if (prKey->u4KeyIndex > 5) { ++#else ++ if (prKey->u4KeyIndex > 3) { ++#endif ++ DBGLOG(REQ, ERROR, "key index error:0x%x\n", prKey->u4KeyIndex); ++ /* key id is out of range */ ++ return -EINVAL; ++ } ++ ++ /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ ++ /* Tx Key Bit(31) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ prKey->u4KeyIndex |= 0x1UL << 31; ++ /* Code style */ ++ } ++ /* Pairwise Key Bit(30) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* Do nothing */ ++ /* group key */ ++ } else { ++ /* pairwise key */ ++ prKey->u4KeyIndex |= 0x1UL << 30; ++ } ++ } ++ /* Rx SC Bit(29) */ ++ if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ prKey->u4KeyIndex |= 0x1UL << 29; ++ memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); ++ } ++ ++ /* BSSID */ ++ memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); ++ ++ /* switch tx/rx MIC key for sta */ ++ if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && prIWEncExt->key_len == 32) { ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, 16); ++ memcpy(((PUINT_8) prKey->aucKeyMaterial) + 16, prIWEncExt->key + 24, 8); ++ memcpy((prKey->aucKeyMaterial) + 24, prIWEncExt->key + 16, 8); ++ } else { ++ memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); ++ } ++ ++ prKey->u4KeyLength = prIWEncExt->key_len; ++ prKey->u4Length = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + prKey->u4KeyLength; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetAddKey, ++ prKey, prKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "add key error:%x\n", rStatus); ++ return -EFAULT; ++ } ++ break; ++ } ++ } ++ ++ return 0; ++} /* wext_set_encode_ext */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Set country code ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prData iwreq.u.data carries country code value. ++* ++* \retval 0 For success. ++* \retval -EEFAULT For fail. ++* ++* \note Country code is stored and channel list is updated based on current country domain. ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wext_set_country(IN struct net_device *prNetDev, IN struct iw_point *prData) ++{ ++ P_GLUE_INFO_T prGlueInfo; ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ UINT_8 aucCountry[2]; ++ ++ ASSERT(prNetDev); ++ ++ /* prData->pointer should be like "COUNTRY US", "COUNTRY EU" ++ * and "COUNTRY JP" ++ */ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prData) || !prData->pointer || prData->length < 10) ++ return -EINVAL; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ aucCountry[0] = *((PUINT_8)prData->pointer + 8); ++ aucCountry[1] = *((PUINT_8)prData->pointer + 9); ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To report the iw private args table to user space. ++* ++* \param[in] prNetDev Net device requested. ++* \param[out] prData iwreq.u.data to carry the private args table. ++* ++* \retval 0 For success. ++* \retval -E2BIG For user's buffer size is too small. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData) ++{ ++ UINT_16 u2BufferSize = prData->length; ++ ++ /* Update our private args table size */ ++ prData->length = (__u16)sizeof(rIwPrivTable); ++ if (u2BufferSize < prData->length) ++ return -E2BIG; ++ ++ if (prData->length) { ++ if (copy_to_user(prData->pointer, rIwPrivTable, sizeof(rIwPrivTable))) ++ return -EFAULT; ++ } ++ ++ return 0; ++} /* wext_get_priv */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief ioctl() (Linux Wireless Extensions) routines ++* ++* \param[in] prDev Net device requested. ++* \param[in] ifr The ifreq structure for seeting the wireless extension. ++* \param[in] i4Cmd The wireless extension ioctl command. ++* ++* \retval zero On success. ++* \retval -EOPNOTSUPP If the cmd is not supported. ++* \retval -EFAULT If copy_to_user goes wrong. ++* \retval -EINVAL If any value's out of range. ++* ++* \note ++*/ ++/*----------------------------------------------------------------------------*/ ++int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd) ++{ ++ struct iwreq *iwr = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ int ret = 0; ++ char *prExtraBuf = NULL; ++ UINT_32 u4ExtraSize = 0; ++ P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ WLAN_STATUS rStatus; ++ UINT_32 u4BufLen; ++ P_PARAM_PMKID_T prPmkid; ++ ++ /* printk("%d CMD:0x%x\n", jiffies_to_msecs(jiffies), i4Cmd); */ ++ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */ ++ ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, NULL); ++ break; ++ ++ /* case SIOCSIWNWID: 0x8B02, deprecated */ ++ /* case SIOCGIWNWID: 0x8B03, deprecated */ ++ ++ case SIOCSIWFREQ: /* 0x8B04, set channel */ ++ ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL); ++ break; ++ ++ case SIOCGIWFREQ: /* 0x8B05, get channel */ ++ ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL); ++ break; ++ ++ case SIOCSIWMODE: /* 0x8B06, set operation mode */ ++ ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL); ++ /* ret = 0; */ ++ break; ++ ++ case SIOCGIWMODE: /* 0x8B07, get operation mode */ ++ ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL); ++ break; ++ ++ /* case SIOCSIWSENS: 0x8B08, unsupported */ ++ /* case SIOCGIWSENS: 0x8B09, unsupported */ ++ ++ /* case SIOCSIWRANGE: 0x8B0A, unused */ ++ case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */ ++ if (iwr->u.data.pointer != NULL) { ++ /* Buffer size should be large enough */ ++ if (iwr->u.data.length < sizeof(struct iw_range)) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_range), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* reset all fields */ ++ memset(prExtraBuf, 0, sizeof(struct iw_range)); ++ iwr->u.data.length = sizeof(struct iw_range); ++ ++ ret = wext_get_range(prDev, NULL, &iwr->u.data, prExtraBuf); ++ /* Push up to the caller */ ++ if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) ++ ret = -EFAULT; ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_range)); ++ prExtraBuf = NULL; ++ } else { ++ ret = -EINVAL; ++ } ++ break; ++ ++ case SIOCSIWPRIV: /* 0x8B0C, set country code */ ++ ret = wext_set_country(prDev, &iwr->u.data); ++ break; ++ ++ case SIOCGIWPRIV: /* 0x8B0D, get private args table */ ++ ret = wext_get_priv(prDev, &iwr->u.data); ++ break; ++ ++ /* case SIOCSIWSTATS: 0x8B0E, unused */ ++ /* case SIOCGIWSTATS: ++ get statistics, intercepted by wireless_process_ioctl() in wireless.c, ++ redirected to dev_iwstats(), dev->get_wireless_stats(). ++ */ ++ /* case SIOCSIWSPY: 0x8B10, unsupported */ ++ /* case SIOCGIWSPY: 0x8B11, unsupported */ ++ /* case SIOCSIWTHRSPY: 0x8B12, unsupported */ ++ /* case SIOCGIWTHRSPY: 0x8B13, unsupported */ ++ ++ case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */ ++ if (iwr->u.ap_addr.sa_data[0] == 0 && ++ iwr->u.ap_addr.sa_data[1] == 0 && ++ iwr->u.ap_addr.sa_data[2] == 0 && ++ iwr->u.ap_addr.sa_data[3] == 0 && ++ iwr->u.ap_addr.sa_data[4] == 0 && iwr->u.ap_addr.sa_data[5] == 0) { ++ /* WPA Supplicant will set 000000000000 in ++ ** wpa_driver_wext_deinit(), do nothing here or disassoc again? ++ */ ++ ret = 0; ++ break; ++ } ++ ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL); ++ ++ break; ++ ++ case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */ ++ ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL); ++ break; ++ ++ case SIOCSIWMLME: /* 0x8B16, request MLME operation */ ++ /* Fixed length structure */ ++ if (iwr->u.data.length != sizeof(struct iw_mlme)) { ++ DBGLOG(REQ, ERROR, "MLME buffer strange:%d\n", iwr->u.data.length); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (!iwr->u.data.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_mlme))) ++ ret = -EFAULT; ++ else ++ ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), prExtraBuf); ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); ++ prExtraBuf = NULL; ++ break; ++ ++ /* case SIOCGIWAPLIST: 0x8B17, deprecated */ ++ case SIOCSIWSCAN: /* 0x8B18, scan request */ ++ if (iwr->u.data.pointer == NULL) ++ ret = wext_set_scan(prDev, NULL, NULL, NULL); ++#if WIRELESS_EXT > 17 ++ else if (iwr->u.data.length == sizeof(struct iw_scan_req)) { ++ prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(prExtraBuf, ((struct iw_scan_req *)(iwr->u.data.pointer))->essid, ++ ((struct iw_scan_req *)(iwr->u.data.pointer))->essid_len)) { ++ ret = -EFAULT; ++ } else { ++ ret = wext_set_scan(prDev, NULL, (union iwreq_data *)&(iwr->u.data), prExtraBuf); ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN); ++ prExtraBuf = NULL; ++ } ++#endif ++ else ++ ret = -EINVAL; ++ break; ++#if 1 ++ case SIOCGIWSCAN: /* 0x8B19, get scan results */ ++ if (!iwr->u.data.pointer || !iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ u4ExtraSize = iwr->u.data.length; ++ /* allocate the same size of kernel buffer to store scan results. */ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* iwr->u.data.length may be updated by wext_get_scan() */ ++ ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf); ++ if (ret != 0) { ++ if (ret == -E2BIG) ++ DBGLOG(REQ, WARN, "[wifi] wext_get_scan -E2BIG\n"); ++ } else { ++ /* check updated length is valid */ ++ ASSERT(iwr->u.data.length <= u4ExtraSize); ++ if (iwr->u.data.length > u4ExtraSize) { ++ DBGLOG(REQ, INFO, "Updated result length is larger than allocated (%d > %u)\n", ++ iwr->u.data.length, u4ExtraSize); ++ iwr->u.data.length = u4ExtraSize; ++ } ++ ++ if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) ++ ret = -EFAULT; ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ ++ break; ++ ++#endif ++ ++#if 1 ++ case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */ ++ if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) { ++ ret = -E2BIG; ++ break; ++ } ++ if (!iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.essid.pointer, iwr->u.essid.length)) { ++ ret = -EFAULT; ++ } else { ++ /* Add trailing '\0' for printk */ ++ /* prExtraBuf[iwr->u.essid.length] = 0; */ ++ /* printk(KERN_INFO "wext_set_essid: %s (%d)\n", prExtraBuf, iwr->u.essid.length); */ ++ ret = wext_set_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); ++ /* printk ("set essid %d\n", ret); */ ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4); ++ prExtraBuf = NULL; ++ break; ++ ++#endif ++ ++ case SIOCGIWESSID: /* 0x8B1B, get SSID */ ++ if (!iwr->u.essid.pointer) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (iwr->u.essid.length < IW_ESSID_MAX_SIZE) { ++ DBGLOG(REQ, ERROR, "[wifi] iwr->u.essid.length:%d too small\n", iwr->u.essid.length); ++ ret = -E2BIG; /* let caller try larger buffer */ ++ break; ++ } ++ ++ prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ /* iwr->u.essid.length is updated by wext_get_essid() */ ++ ++ ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); ++ if (ret == 0) { ++ if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, iwr->u.essid.length)) ++ ret = -EFAULT; ++ } ++ ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE); ++ prExtraBuf = NULL; ++ ++ break; ++ ++ /* case SIOCSIWNICKN: 0x8B1C, not supported */ ++ /* case SIOCGIWNICKN: 0x8B1D, not supported */ ++ ++ case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */ ++ /* ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, NULL); */ ++ break; ++ ++ case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */ ++ ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL); ++ break; ++ ++ case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */ ++ ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL); ++ break; ++ ++ case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */ ++ ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL); ++ break; ++ ++ /* case SIOCSIWFRAG: 0x8B24, unsupported */ ++ case SIOCGIWFRAG: /* 0x8B25, get frag threshold */ ++ ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL); ++ break; ++ ++ case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */ ++ ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL); ++ break; ++ ++ case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */ ++ ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL); ++ break; ++ ++ /* case SIOCSIWRETRY: 0x8B28, unsupported */ ++ /* case SIOCGIWRETRY: 0x8B29, unsupported */ ++ ++#if 1 ++ case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */ ++ /* Only DISABLED case has NULL pointer and length == 0 */ ++ if (iwr->u.encoding.pointer) { ++ if (iwr->u.encoding.length > 16) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ u4ExtraSize = iwr->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (iwr->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, prExtraBuf); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ break; ++ ++ case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */ ++ /* check pointer */ ++ ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL); ++ break; ++ ++ case SIOCSIWPOWER: /* 0x8B2C, set power management */ ++ ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL); ++ break; ++ ++ case SIOCGIWPOWER: /* 0x8B2D, get power management */ ++ ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL); ++ break; ++ ++#if WIRELESS_EXT > 17 ++ case SIOCSIWGENIE: /* 0x8B30, set gen ie */ ++ if (iwr->u.data.pointer == NULL) ++ break; ++ ++ if (0 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */) ++ break; ++ ++ /* Fixed length structure */ ++#if CFG_SUPPORT_WAPI ++ if (iwr->u.data.length > 42 /* The max wapi ie buffer */) { ++ ret = -EINVAL; ++ break; ++ } ++#endif ++ u4ExtraSize = iwr->u.data.length; ++ if (u4ExtraSize == 0) ++ break; ++ ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, iwr->u.data.length)) { ++ ret = -EFAULT; ++ } else { ++#if CFG_SUPPORT_WAPI ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWapiAssocInfo, ++ prExtraBuf, ++ u4ExtraSize, FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[wapi] set wapi assoc info error:%lx\n", ++ rStatus); */ ++#endif ++#if CFG_SUPPORT_WPS2 ++ PUINT_8 prDesiredIE = NULL; ++ ++ if (wextSrchDesiredWPSIE(prExtraBuf, ++ u4ExtraSize, ++ 0xDD, (PUINT_8 *) &prDesiredIE)) { ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetWSCAssocInfo, ++ prDesiredIE, ++ IE_SIZE(prDesiredIE), ++ FALSE, ++ FALSE, TRUE, FALSE, &u4BufLen); ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ /* printk(KERN_INFO "[WSC] set WSC assoc info ++ error:%lx\n", rStatus); */ ++ } ++ } ++#endif ++#if CFG_SUPPORT_WAPI ++ } ++#endif ++ } ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ break; ++ ++ case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */ ++ break; ++ ++#endif ++ ++ case SIOCSIWAUTH: /* 0x8B32, set auth mode params */ ++ ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL); ++ break; ++ ++ /* case SIOCGIWAUTH: 0x8B33, unused? */ ++ case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */ ++ if (iwr->u.encoding.pointer) { ++ u4ExtraSize = iwr->u.encoding.length; ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) ++ ret = -EFAULT; ++ } else if (iwr->u.encoding.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret == 0) ++ ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, prExtraBuf); ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ break; ++ ++ /* case SIOCGIWENCODEEXT: 0x8B35, unused? */ ++ ++ case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */ ++#if 1 ++ if (iwr->u.data.pointer) { ++ /* Fixed length structure */ ++ if (iwr->u.data.length != sizeof(struct iw_pmksa)) { ++ ret = -EINVAL; ++ break; ++ } ++ ++ u4ExtraSize = sizeof(struct iw_pmksa); ++ prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); ++ if (!prExtraBuf) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_pmksa))) { ++ ret = -EFAULT; ++ } else { ++ switch (((struct iw_pmksa *)prExtraBuf)->cmd) { ++ case IW_PMKSA_ADD: ++ /* ++ printk(KERN_INFO "IW_PMKSA_ADD [ %pM ]\n", ++ (((struct iw_pmksa *)pExtraBuf)->bssid.sa_data)); ++ */ ++ prPmkid = ++ (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), ++ VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); ++ ret = -ENOMEM; ++ break; ++ } ++ ++ prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); ++ prPmkid->u4BSSIDInfoCount = 1; ++ kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, ++ ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, 6); ++ kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, ++ ((struct iw_pmksa *)prExtraBuf)->pmkid, IW_PMKID_LEN); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, ++ prPmkid, ++ sizeof(PARAM_PMKID_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "add pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); ++ break; ++ case IW_PMKSA_REMOVE: ++ /* ++ printk(KERN_INFO "IW_PMKSA_REMOVE [ %pM ]\n", ++ (((struct iw_pmksa *)buf)->bssid.sa_data)); ++ */ ++ break; ++ case IW_PMKSA_FLUSH: ++ /* ++ printk(KERN_INFO "IW_PMKSA_FLUSH\n"); ++ */ ++ prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); ++ if (!prPmkid) { ++ DBGLOG(REQ, ERROR, ++ "Can not alloc memory for IW_PMKSA_FLUSH\n"); ++ ret = -ENOMEM; ++ break; ++ } ++ ++ prPmkid->u4Length = 8; ++ prPmkid->u4BSSIDInfoCount = 0; ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetPmkid, ++ prPmkid, ++ sizeof(PARAM_PMKID_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "flush pmkid error:%x\n", rStatus); ++ kalMemFree(prPmkid, VIR_MEM_TYPE, 8); ++ break; ++ default: ++ DBGLOG(REQ, WARN, "UNKNOWN iw_pmksa command:%d\n", ++ ((struct iw_pmksa *)prExtraBuf)->cmd); ++ ret = -EFAULT; ++ break; ++ } ++ } ++ ++ if (prExtraBuf) { ++ kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); ++ prExtraBuf = NULL; ++ } ++ } else if (iwr->u.data.length != 0) { ++ ret = -EINVAL; ++ break; ++ } ++#endif ++ break; ++ ++#endif ++ ++ default: ++ /* printk(KERN_NOTICE "unsupported IOCTL: 0x%x\n", i4Cmd); */ ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ /* printk("%ld CMD:0x%x ret:%d\n", jiffies_to_msecs(jiffies), i4Cmd, ret); */ ++ ++ return ret; ++} /* wext_support_ioctl */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief To send an event (RAW socket pacekt) to user process actively. ++* ++* \param[in] prGlueInfo Glue layer info. ++* \param[in] u4cmd Whcih event command we want to indicate to user process. ++* \param[in] pData Data buffer to be indicated. ++* \param[in] dataLen Available data size in pData. ++* ++* \return (none) ++* ++* \note Event is indicated to upper layer if cmd is supported and data is valid. ++* Using of kernel symbol wireless_send_event(), which is defined in ++* after WE-14 (2.4.20). ++*/ ++/*----------------------------------------------------------------------------*/ ++void ++wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, ++ IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4dataLen) ++{ ++ union iwreq_data wrqu; ++ unsigned char *pucExtraInfo = NULL; ++#if WIRELESS_EXT >= 15 ++ unsigned char *pucDesiredIE = NULL; ++ unsigned char aucExtraInfoBuf[200]; ++#endif ++#if WIRELESS_EXT < 18 ++ int i; ++#endif ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ switch (u4Cmd) { ++ case SIOCGIWTXPOW: ++ memcpy(&wrqu.power, pucData, u4dataLen); ++ break; ++ case SIOCGIWSCAN: ++ complete_all(&prGlueInfo->rScanComp); ++ break; ++ ++ case SIOCGIWAP: ++ if (pucData) ++ ether_addr_copy((u8 *)&(wrqu.ap_addr.sa_data), pucData); ++ /*memcpy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN);*/ ++ else ++ memset(&wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ break; ++ ++ case IWEVASSOCREQIE: ++#if WIRELESS_EXT < 15 ++ /* under WE-15, no suitable Event can be used */ ++ goto skip_indicate_event; ++#else ++ /* do supplicant a favor, parse to the start of WPA/RSN IE */ ++ if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, &pucDesiredIE)) { ++ /* RSN IE found */ ++ /* Do nothing */ ++#if 0 ++ } else if (wextSrchDesiredWPSIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { ++ /* WPS IE found */ ++ /* Do nothing */ ++#endif ++ } else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { ++ /* WPA IE found */ ++ /* Do nothing*/ ++#if CFG_SUPPORT_WAPI /* Android+ */ ++ } else if (wextSrchDesiredWAPIIE(pucData, u4dataLen, &pucDesiredIE)) { ++ /* WAPI IE found */ ++ /* printk("wextSrchDesiredWAPIIE!!\n"); */ ++#endif ++ } else { ++ /* no WPA/RSN IE found, skip this event */ ++ goto skip_indicate_event; ++ } ++#if WIRELESS_EXT < 18 ++ /* under WE-18, only IWEVCUSTOM can be used */ ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ pucExtraInfo += sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs="); ++ /* printk(KERN_DEBUG "assoc info buffer size needed:%d\n", infoElemLen * 2 + 17); */ ++ /* translate binary string to hex string, requirement of IWEVCUSTOM */ ++ for (i = 0; i < pucDesiredIE[1] + 2; ++i) ++ pucExtraInfo += sprintf(pucExtraInfo, "%02x", pucDesiredIE[i]); ++ pucExtraInfo = aucExtraInfoBuf; ++ wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2; ++#else ++ /* IWEVASSOCREQIE, indicate binary string */ ++ pucExtraInfo = pucDesiredIE; ++ wrqu.data.length = pucDesiredIE[1] + 2; ++#endif ++#endif /* WIRELESS_EXT < 15 */ ++ break; ++ ++ case IWEVMICHAELMICFAILURE: ++#if WIRELESS_EXT < 15 ++ /* under WE-15, no suitable Event can be used */ ++ goto skip_indicate_event; ++#else ++ if (pucData) { ++ P_PARAM_AUTH_REQUEST_T pAuthReq = (P_PARAM_AUTH_REQUEST_T) pucData; ++ /* under WE-18, only IWEVCUSTOM can be used */ ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ pucExtraInfo += sprintf(pucExtraInfo, "MLME-MICHAELMICFAILURE.indication "); ++ pucExtraInfo += sprintf(pucExtraInfo, ++ "%s", ++ (pAuthReq->u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR) ? ++ "groupcast " : "unicast "); ++ ++ wrqu.data.length = pucExtraInfo - aucExtraInfoBuf; ++ pucExtraInfo = aucExtraInfoBuf; ++ } ++#endif /* WIRELESS_EXT < 15 */ ++ break; ++ ++ case IWEVPMKIDCAND: ++ if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2 && ++ prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) { ++ ++ /* only used in WPA2 */ ++#if WIRELESS_EXT >= 18 ++ P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T) pucData; ++ ++ struct iw_pmkid_cand rPmkidCand; ++ ++ pucExtraInfo = aucExtraInfoBuf; ++ ++ rPmkidCand.flags = prPmkidCand->u4Flags; ++ rPmkidCand.index = 0; ++ rPmkidCand.bssid.sa_family = 0; ++ kalMemCopy(rPmkidCand.bssid.sa_data, prPmkidCand->arBSSID, 6); ++ ++ kalMemCopy(pucExtraInfo, (PUINT_8) &rPmkidCand, sizeof(struct iw_pmkid_cand)); ++ wrqu.data.length = sizeof(struct iw_pmkid_cand); ++ ++ /* pmkid canadidate list is supported after WE-18 */ ++ /* indicate struct iw_pmkid_cand */ ++#else ++ /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, WE < 18\n"); */ ++ goto skip_indicate_event; ++#endif ++ } else { ++ /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, NOT WPA2\n"); */ ++ goto skip_indicate_event; ++ } ++ break; ++ ++ case IWEVCUSTOM: ++ u4Cmd = IWEVCUSTOM; ++ pucExtraInfo = aucExtraInfoBuf; ++ kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T)); ++ wrqu.data.length = sizeof(PTA_IPC_T); ++ break; ++ ++ default: ++ /* printk(KERN_INFO "Unsupported wext event:%x\n", cmd); */ ++ goto skip_indicate_event; ++ } ++ ++ /* Send event to user space */ ++ wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, pucExtraInfo); ++ ++skip_indicate_event: ++ return; ++} /* wext_indicate_wext_event */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief A method of struct net_device, to get the network interface statistical ++* information. ++* ++* Whenever an application needs to get statistics for the interface, this method ++* is called. This happens, for example, when ifconfig or netstat -i is run. ++* ++* \param[in] pDev Pointer to struct net_device. ++* ++* \return net_device_stats buffer pointer. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev) ++{ ++ ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ struct iw_statistics *pStats = NULL; ++ INT_32 i4Rssi; ++ UINT_32 bufLen = 0; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) ++ goto stat_out; ++ ++ pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); ++ ++ if (!prDev || !netif_carrier_ok(prDev)) { ++ /* network not connected */ ++ goto stat_out; ++ } ++ ++ rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, FALSE, &bufLen); ++ ++stat_out: ++ return pStats; ++} /* wlan_get_wireless_stats */ ++ ++ ++#endif /* WIRELESS_EXT */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c +new file mode 100644 +index 000000000000..2b6c3df84594 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c +@@ -0,0 +1,3142 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext_priv.c#4 ++*/ ++ ++/*! \file gl_wext_priv.c ++ \brief This file includes private ioctl support. ++*/ ++ ++/* ++** Log: gl_wext_priv.c ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Let netdev bring up. ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 03 20 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * [WCXRP00001202] [MT6628 Wi-Fi][FW] Adding the New PN init code ++ * use return to avoid the ioctl return not supported ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 11 02 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Fixed typo. ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 07 28 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings ++ * Add BWCS cmd and event. ++ * ++ * 07 18 2011 chinghwa.yu ++ * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm ++ * Add CMD/Event for RDD and BWCS. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 26 2011 wh.su ++ * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux ++ * adding the SW cmd ioctl support, use set/get structure ioctl. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Adjust OID order. ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 12 15 2010 george.huang ++ * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function ++ * Support set PS profile and set WMM-PS related iwpriv. ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 24 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * correct typo for NVRAM access. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * enable OID_CUSTOM_MTK_WIFI_TEST for RFTest & META tool ++ * ++ * 05 29 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * fix private ioctl for rftest ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++** \main\maintrunk.MT5921\32 2009-10-08 10:33:25 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\31 2009-09-29 16:46:21 GMT mtk01090 ++** Remove unused functions ++** \main\maintrunk.MT5921\30 2009-09-29 14:46:47 GMT mtk01090 ++** Fix compile warning ++** \main\maintrunk.MT5921\29 2009-09-29 14:28:48 GMT mtk01090 ++** Fix compile warning ++** \main\maintrunk.MT5921\28 2009-09-28 22:21:38 GMT mtk01090 ++** Refine lines to suppress compile warning ++** \main\maintrunk.MT5921\27 2009-09-28 20:19:14 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\26 2009-08-18 22:56:53 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\25 2009-05-07 22:26:15 GMT mtk01089 ++** Add mandatory and private IO control for Linux BWCS ++** \main\maintrunk.MT5921\24 2009-04-29 10:07:05 GMT mtk01088 ++** fixed the compiling error at linux ++** \main\maintrunk.MT5921\23 2009-04-24 09:09:45 GMT mtk01088 ++** mark the code not used at linux supplicant v0.6.7 ++** \main\maintrunk.MT5921\22 2008-11-24 21:03:51 GMT mtk01425 ++** 1. Add PTA_ENABLED flag ++** \main\maintrunk.MT5921\21 2008-08-29 14:55:59 GMT mtk01088 ++** adjust the code for meet the coding style, and add assert check ++** \main\maintrunk.MT5921\20 2008-07-16 15:23:20 GMT mtk01104 ++** Support GPIO2 mode ++** \main\maintrunk.MT5921\19 2008-07-15 17:43:11 GMT mtk01084 ++** modify variable name ++** \main\maintrunk.MT5921\18 2008-07-14 14:37:58 GMT mtk01104 ++** Add exception handle about length in function priv_set_struct() ++** \main\maintrunk.MT5921\17 2008-07-14 13:55:32 GMT mtk01104 ++** Support PRIV_CMD_BT_COEXIST ++** \main\maintrunk.MT5921\16 2008-07-09 00:20:15 GMT mtk01461 ++** Add priv oid to support WMM_PS_TEST ++** \main\maintrunk.MT5921\15 2008-06-02 11:15:22 GMT mtk01461 ++** Update after wlanoidSetPowerMode changed ++** \main\maintrunk.MT5921\14 2008-05-30 19:31:07 GMT mtk01461 ++** Add IOCTL for Power Mode ++** \main\maintrunk.MT5921\13 2008-05-30 18:57:15 GMT mtk01461 ++** Not use wlanoidSetCSUMOffloadForLinux() ++** \main\maintrunk.MT5921\12 2008-05-30 15:13:18 GMT mtk01084 ++** rename wlanoid ++** \main\maintrunk.MT5921\11 2008-05-29 14:16:31 GMT mtk01084 ++** rename for wlanoidSetBeaconIntervalForLinux ++** \main\maintrunk.MT5921\10 2008-04-17 23:06:37 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\9 2008-03-31 21:00:55 GMT mtk01461 ++** Add priv IOCTL for VOIP setting ++** \main\maintrunk.MT5921\8 2008-03-31 13:49:43 GMT mtk01461 ++** Add priv ioctl to turn on / off roaming ++** \main\maintrunk.MT5921\7 2008-03-26 15:35:14 GMT mtk01461 ++** Add CSUM offload priv ioctl for Linux ++** \main\maintrunk.MT5921\6 2008-03-11 14:50:59 GMT mtk01461 ++** Unify priv ioctl ++** \main\maintrunk.MT5921\5 2007-11-06 19:32:30 GMT mtk01088 ++** add WPS code ++** \main\maintrunk.MT5921\4 2007-10-30 12:01:39 GMT MTK01425 ++** 1. Update wlanQueryInformation and wlanSetInformation ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "precomp.h" ++ ++#include "gl_os.h" ++#include "gl_wext_priv.h" ++#if CFG_SUPPORT_WAPI ++#include "gl_sec.h" ++#endif ++#if CFG_ENABLE_WIFI_DIRECT ++#include "gl_p2p_os.h" ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define NUM_SUPPORTED_OIDS (sizeof(arWlanOidReqTable) / sizeof(WLAN_REQ_ENTRY)) ++#define CMD_START "START" ++#define CMD_STOP "STOP" ++#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" ++#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" ++#define CMD_RSSI "RSSI" ++#define CMD_LINKSPEED "LINKSPEED" ++#define CMD_RXFILTER_START "RXFILTER-START" ++#define CMD_RXFILTER_STOP "RXFILTER-STOP" ++#define CMD_RXFILTER_ADD "RXFILTER-ADD" ++#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" ++#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" ++#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" ++#define CMD_BTCOEXMODE "BTCOEXMODE" ++#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" ++#define CMD_SETFWPATH "SETFWPATH" ++#define CMD_SETBAND "SETBAND" ++#define CMD_GETBAND "GETBAND" ++#define CMD_COUNTRY "COUNTRY" ++#define CMD_P2P_SET_NOA "P2P_SET_NOA" ++#define CMD_P2P_GET_NOA "P2P_GET_NOA" ++#define CMD_P2P_SET_PS "P2P_SET_PS" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETROAMMODE "SETROAMMODE" ++#define CMD_MIRACAST "MIRACAST" ++ ++#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" ++#define CMD_PNOSETUP_SET "PNOSETUP " ++#define CMD_PNOENABLE_SET "PNOFORCE" ++#define CMD_PNODEBUG_SET "PNODEBUG" ++#define CMD_WLS_BATCHING "WLS_BATCHING" ++ ++#define CMD_OKC_SET_PMK "SET_PMK" ++#define CMD_OKC_ENABLE "OKC_ENABLE" ++ ++/* miracast related definition */ ++#define MIRACAST_MODE_OFF 0 ++#define MIRACAST_MODE_SOURCE 1 ++#define MIRACAST_MODE_SINK 2 ++ ++#ifndef MIRACAST_AMPDU_SIZE ++#define MIRACAST_AMPDU_SIZE 8 ++#endif ++ ++#ifndef MIRACAST_MCHAN_ALGO ++#define MIRACAST_MCHAN_ALGO 1 ++#endif ++ ++#ifndef MIRACAST_MCHAN_BW ++#define MIRACAST_MCHAN_BW 25 ++#endif ++ ++#define CMD_BAND_AUTO 0 ++#define CMD_BAND_5G 1 ++#define CMD_BAND_2G 2 ++#define CMD_BAND_ALL 3 ++ ++/* Mediatek private command */ ++ ++#define CMD_SET_SW_CTRL "SET_SW_CTRL" ++#define CMD_GET_SW_CTRL "GET_SW_CTRL" ++#define CMD_SET_CFG "SET_CFG" ++#define CMD_GET_CFG "GET_CFG" ++#define CMD_SET_CHIP "SET_CHIP" ++#define CMD_GET_CHIP "GET_CHIP" ++#define CMD_SET_DBG_LEVEL "SET_DBG_LEVEL" ++#define CMD_GET_DBG_LEVEL "GET_DBG_LEVEL" ++#define PRIV_CMD_SIZE 512 ++ ++static UINT_32 g_ucMiracastMode = MIRACAST_MODE_OFF; ++ ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subver; ++ char reserved; ++} cmd_tlv_t; ++ ++typedef struct priv_driver_cmd_s { ++ char buf[PRIV_CMD_SIZE]; ++ int used_len; ++ int total_len; ++} priv_driver_cmd_t; ++ ++#if CFG_SUPPORT_BATCH_SCAN ++#define CMD_BATCH_SET "WLS_BATCHING SET" ++#define CMD_BATCH_GET "WLS_BATCHING GET" ++#define CMD_BATCH_STOP "WLS_BATCHING STOP" ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static int ++priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); ++ ++static int ++priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); ++ ++#if 0 /* CFG_SUPPORT_WPS */ ++static int ++priv_set_appie(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); ++ ++static int ++priv_set_filter(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); ++#endif /* CFG_SUPPORT_WPS */ ++ ++static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY * ppWlanReqEntry); ++ ++#if 0 ++static WLAN_STATUS ++reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++static WLAN_STATUS ++reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++#endif ++ ++static WLAN_STATUS ++reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++static UINT_8 aucOidBuf[4096] = { 0 }; ++ ++/* OID processing table */ ++/* Order is important here because the OIDs should be in order of ++ increasing value for binary searching. */ ++static WLAN_REQ_ENTRY arWlanOidReqTable[] = { ++ /* ++ {(NDIS_OID)rOid, ++ (PUINT_8)pucOidName, ++ fgQryBufLenChecking, fgSetBufLenChecking, fgIsHandleInGlueLayerOnly, u4InfoBufLen, ++ pfOidQueryHandler, ++ pfOidSetHandler} ++ */ ++ /* General Operational Characteristics */ ++ ++ /* Ethernet Operational Characteristics */ ++ {OID_802_3_CURRENT_ADDRESS, ++ DISP_STRING("OID_802_3_CURRENT_ADDRESS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 6, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCurrentAddr, ++ NULL}, ++ ++ /* OID_802_3_MULTICAST_LIST */ ++ /* OID_802_3_MAXIMUM_LIST_SIZE */ ++ /* Ethernet Statistics */ ++ ++ /* NDIS 802.11 Wireless LAN OIDs */ ++ {OID_802_11_SUPPORTED_RATES, ++ DISP_STRING("OID_802_11_SUPPORTED_RATES"), ++ TRUE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_RATES_EX), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySupportedRates, ++ NULL} ++ , ++ /* ++ {OID_802_11_CONFIGURATION, ++ DISP_STRING("OID_802_11_CONFIGURATION"), ++ TRUE, TRUE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_802_11_CONFIG_T), ++ (PFN_OID_HANDLER_FUNC_REQ)reqExtQueryConfiguration, ++ (PFN_OID_HANDLER_FUNC_REQ)reqExtSetConfiguration}, ++ */ ++ {OID_PNP_SET_POWER, ++ DISP_STRING("OID_PNP_SET_POWER"), ++ TRUE, FALSE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_DEVICE_POWER_STATE), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) reqExtSetAcpiDevicePowerState} ++ , ++ ++ /* Custom OIDs */ ++ {OID_CUSTOM_OID_INTERFACE_VERSION, ++ DISP_STRING("OID_CUSTOM_OID_INTERFACE_VERSION"), ++ TRUE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryOidInterfaceVersion, ++ NULL} ++ , ++ ++ /* ++ #if PTA_ENABLED ++ {OID_CUSTOM_BT_COEXIST_CTRL, ++ DISP_STRING("OID_CUSTOM_BT_COEXIST_CTRL"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_BT_COEXIST_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtCoexistCtrl}, ++ #endif ++ */ ++ ++ /* ++ {OID_CUSTOM_POWER_MANAGEMENT_PROFILE, ++ DISP_STRING("OID_CUSTOM_POWER_MANAGEMENT_PROFILE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPwrMgmtProfParam, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPwrMgmtProfParam}, ++ {OID_CUSTOM_PATTERN_CONFIG, ++ DISP_STRING("OID_CUSTOM_PATTERN_CONFIG"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_PATTERN_SEARCH_CONFIG_STRUCT_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPatternConfig}, ++ {OID_CUSTOM_BG_SSID_SEARCH_CONFIG, ++ DISP_STRING("OID_CUSTOM_BG_SSID_SEARCH_CONFIG"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBgSsidParam}, ++ {OID_CUSTOM_VOIP_SETUP, ++ DISP_STRING("OID_CUSTOM_VOIP_SETUP"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryVoipConnectionStatus, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetVoipConnectionStatus}, ++ {OID_CUSTOM_ADD_TS, ++ DISP_STRING("OID_CUSTOM_ADD_TS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidAddTS}, ++ {OID_CUSTOM_DEL_TS, ++ DISP_STRING("OID_CUSTOM_DEL_TS"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidDelTS}, ++ */ ++ ++ /* ++ #if CFG_LP_PATTERN_SEARCH_SLT ++ {OID_CUSTOM_SLT, ++ DISP_STRING("OID_CUSTOM_SLT"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySltResult, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSltMode}, ++ #endif ++ ++ {OID_CUSTOM_ROAMING_EN, ++ DISP_STRING("OID_CUSTOM_ROAMING_EN"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRoamingFunction, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetRoamingFunction}, ++ {OID_CUSTOM_WMM_PS_TEST, ++ DISP_STRING("OID_CUSTOM_WMM_PS_TEST"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWiFiWmmPsTest}, ++ {OID_CUSTOM_COUNTRY_STRING, ++ DISP_STRING("OID_CUSTOM_COUNTRY_STRING"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentCountry, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetCurrentCountry}, ++ ++ #if CFG_SUPPORT_802_11D ++ {OID_CUSTOM_MULTI_DOMAIN_CAPABILITY, ++ DISP_STRING("OID_CUSTOM_MULTI_DOMAIN_CAPABILITY"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMultiDomainCap, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMultiDomainCap}, ++ #endif ++ ++ {OID_CUSTOM_GPIO2_MODE, ++ DISP_STRING("OID_CUSTOM_GPIO2_MODE"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_PARAM_GPIO2_MODE_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetGPIO2Mode}, ++ {OID_CUSTOM_CONTINUOUS_POLL, ++ DISP_STRING("OID_CUSTOM_CONTINUOUS_POLL"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CONTINUOUS_POLL_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryContinuousPollInterval, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetContinuousPollProfile}, ++ {OID_CUSTOM_DISABLE_BEACON_DETECTION, ++ DISP_STRING("OID_CUSTOM_DISABLE_BEACON_DETECTION"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryDisableBeaconDetectionFunc, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisableBeaconDetectionFunc}, ++ */ ++ ++ /* WPS */ ++ /* ++ {OID_CUSTOM_DISABLE_PRIVACY_CHECK, ++ DISP_STRING("OID_CUSTOM_DISABLE_PRIVACY_CHECK"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisablePriavcyCheck}, ++ */ ++ ++ {OID_CUSTOM_MCR_RW, ++ DISP_STRING("OID_CUSTOM_MCR_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMcrRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetMcrWrite} ++ , ++ ++ {OID_CUSTOM_EEPROM_RW, ++ DISP_STRING("OID_CUSTOM_EEPROM_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetEepromWrite} ++ , ++ ++ {OID_CUSTOM_SW_CTRL, ++ DISP_STRING("OID_CUSTOM_SW_CTRL"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySwCtrlRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetSwCtrlWrite} ++ , ++ ++ {OID_CUSTOM_MEM_DUMP, ++ DISP_STRING("OID_CUSTOM_MEM_DUMP"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMemDump, ++ NULL} ++ , ++ ++ {OID_CUSTOM_TEST_MODE, ++ DISP_STRING("OID_CUSTOM_TEST_MODE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetTestMode} ++ , ++ ++ /* ++ {OID_CUSTOM_TEST_RX_STATUS, ++ DISP_STRING("OID_CUSTOM_TEST_RX_STATUS"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestRxStatus, ++ NULL}, ++ {OID_CUSTOM_TEST_TX_STATUS, ++ DISP_STRING("OID_CUSTOM_TEST_TX_STATUS"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestTxStatus, ++ NULL}, ++ */ ++ {OID_CUSTOM_ABORT_TEST_MODE, ++ DISP_STRING("OID_CUSTOM_ABORT_TEST_MODE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAbortTestMode} ++ , ++ {OID_CUSTOM_MTK_WIFI_TEST, ++ DISP_STRING("OID_CUSTOM_MTK_WIFI_TEST"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestQueryAutoTest, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAutoTest} ++ , ++ ++ /* OID_CUSTOM_EMULATION_VERSION_CONTROL */ ++ ++ /* BWCS */ ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS ++ {OID_CUSTOM_BWCS_CMD, ++ DISP_STRING("OID_CUSTOM_BWCS_CMD"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PTA_IPC_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryBT, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetBT} ++ , ++#endif ++ ++/* {OID_CUSTOM_SINGLE_ANTENNA, ++ DISP_STRING("OID_CUSTOM_SINGLE_ANTENNA"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBtSingleAntenna, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtSingleAntenna}, ++ {OID_CUSTOM_SET_PTA, ++ DISP_STRING("OID_CUSTOM_SET_PTA"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPta, ++ (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPta}, ++ */ ++ ++ {OID_CUSTOM_MTK_NVRAM_RW, ++ DISP_STRING("OID_CUSTOM_MTK_NVRAM_RW"), ++ TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryNvramRead, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetNvramWrite} ++ , ++ ++ {OID_CUSTOM_CFG_SRC_TYPE, ++ DISP_STRING("OID_CUSTOM_CFG_SRC_TYPE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_CFG_SRC_TYPE_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCfgSrcType, ++ NULL} ++ , ++ ++ {OID_CUSTOM_EEPROM_TYPE, ++ DISP_STRING("OID_CUSTOM_EEPROM_TYPE"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_EEPROM_TYPE_T), ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromType, ++ NULL} ++ , ++ ++#if CFG_SUPPORT_WAPI ++ {OID_802_11_WAPI_MODE, ++ DISP_STRING("OID_802_11_WAPI_MODE"), ++ FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiMode} ++ , ++ {OID_802_11_WAPI_ASSOC_INFO, ++ DISP_STRING("OID_802_11_WAPI_ASSOC_INFO"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiAssocInfo} ++ , ++ {OID_802_11_SET_WAPI_KEY, ++ DISP_STRING("OID_802_11_SET_WAPI_KEY"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_WPI_KEY_T), ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiKey} ++ , ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++ {OID_802_11_WSC_ASSOC_INFO, ++ DISP_STRING("OID_802_11_WSC_ASSOC_INFO"), ++ FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, ++ NULL, ++ (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWSCAssocInfo} ++ , ++#endif ++}; ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dispatching function for private ioctl region (SIOCIWFIRSTPRIV ~ ++* SIOCIWLASTPRIV). ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIfReq Pointer to ifreq structure. ++* \param[in] i4Cmd Command ID between SIOCIWFIRSTPRIV and SIOCIWLASTPRIV. ++* ++* \retval 0 for success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++int priv_support_ioctl(IN struct net_device *prNetDev, IN OUT struct ifreq *prIfReq, IN int i4Cmd) ++{ ++ /* prIfReq is verified in the caller function wlanDoIOCTL() */ ++ struct iwreq *prIwReq = (struct iwreq *)prIfReq; ++ struct iw_request_info rIwReqInfo; ++ ++ /* prDev is verified in the caller function wlanDoIOCTL() */ ++ ++ /* Prepare the call */ ++ rIwReqInfo.cmd = (__u16) i4Cmd; ++ rIwReqInfo.flags = 0; ++ ++ switch (i4Cmd) { ++ case IOCTL_SET_INT: ++ /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ ++ return priv_set_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); ++ ++ case IOCTL_GET_INT: ++ /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ ++ return priv_get_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); ++ ++ case IOCTL_SET_STRUCT: ++ case IOCTL_SET_STRUCT_FOR_EM: ++ return priv_set_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); ++ ++ case IOCTL_GET_STRUCT: ++ return priv_get_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); ++ ++ default: ++ return -EOPNOTSUPP; ++ ++ } /* end of switch */ ++ ++} /* priv_support_ioctl */ ++ ++#if CFG_SUPPORT_BATCH_SCAN ++ ++EVENT_BATCH_RESULT_T g_rEventBatchResult[CFG_BATCH_MAX_MSCAN]; ++ ++UINT_32 batchChannelNum2Freq(UINT_32 u4ChannelNum) ++{ ++ UINT_32 u4ChannelInMHz; ++ ++ if (u4ChannelNum >= 1 && u4ChannelNum <= 13) ++ u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; ++ else if (u4ChannelNum == 14) ++ u4ChannelInMHz = 2484; ++ else if (u4ChannelNum == 133) ++ u4ChannelInMHz = 3665; /* 802.11y */ ++ else if (u4ChannelNum == 137) ++ u4ChannelInMHz = 3685; /* 802.11y */ ++ else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) ++ u4ChannelInMHz = 5000 + u4ChannelNum * 5; ++ else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) ++ u4ChannelInMHz = 4000 + u4ChannelNum * 5; ++ else ++ u4ChannelInMHz = 0; ++ ++ return u4ChannelInMHz; ++} ++ ++#define TMP_TEXT_LEN_S 40 ++#define TMP_TEXT_LEN_L 60 ++static UCHAR text1[TMP_TEXT_LEN_S], text2[TMP_TEXT_LEN_L], text3[TMP_TEXT_LEN_L]; /* A safe len */ ++ ++WLAN_STATUS ++batchConvertResult(IN P_EVENT_BATCH_RESULT_T prEventBatchResult, ++ OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) ++{ ++ CHAR *p = pvBuffer; ++ CHAR ssid[ELEM_MAX_LEN_SSID + 1]; ++ INT_32 nsize = 0, nsize1, nsize2, nsize3, scancount; ++ INT_32 i, j, nleft; ++ UINT_32 freq; ++ ++ P_EVENT_BATCH_RESULT_ENTRY_T prEntry; ++ P_EVENT_BATCH_RESULT_T pBr; ++ ++ nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ ++ ++ pBr = prEventBatchResult; ++ scancount = 0; ++ for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { ++ scancount += pBr->ucScanCount; ++ pBr++; ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "scancount=%x\nnextcount=%x\n", scancount, scancount); ++ if (nsize1 < nleft) { ++ p += nsize1 = kalSprintf(p, "%s", text1); ++ nleft -= nsize1; ++ } else ++ goto short_buf; ++ ++ pBr = prEventBatchResult; ++ for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { ++ DBGLOG(SCN, TRACE, "convert mscan = %d, apcount=%d, nleft=%d\n", j, pBr->ucScanCount, nleft); ++ ++ if (pBr->ucScanCount == 0) { ++ pBr++; ++ continue; ++ } ++ ++ nleft -= 5; /* -5 for "####\n" */ ++ ++ /* We only support one round scan result now. */ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "apcount=%d\n", pBr->ucScanCount); ++ if (nsize1 < nleft) { ++ p += nsize1 = kalSprintf(p, "%s", text1); ++ nleft -= nsize1; ++ } else ++ goto short_buf; ++ ++ for (i = 0; i < pBr->ucScanCount; i++) { ++ prEntry = &pBr->arBatchResult[i]; ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "bssid=" MACSTR "\n", ++ prEntry->aucBssid[0], ++ prEntry->aucBssid[1], ++ prEntry->aucBssid[2], ++ prEntry->aucBssid[3], ++ prEntry->aucBssid[4], prEntry->aucBssid[5]); ++ ++ kalMemCopy(ssid, ++ prEntry->aucSSID, ++ (prEntry->ucSSIDLen < ELEM_MAX_LEN_SSID ? prEntry->ucSSIDLen : ELEM_MAX_LEN_SSID)); ++ ssid[(prEntry->ucSSIDLen < ++ (ELEM_MAX_LEN_SSID - 1) ? prEntry->ucSSIDLen : (ELEM_MAX_LEN_SSID - 1))] = '\0'; ++ nsize2 = kalSnprintf(text2, TMP_TEXT_LEN_L, "ssid=%s\n", ssid); ++ ++ freq = batchChannelNum2Freq(prEntry->ucFreq); ++ nsize3 = ++ kalSnprintf(text3, TMP_TEXT_LEN_L, ++ "freq=%u\nlevel=%d\ndist=%u\ndistSd=%u\n====\n", freq, ++ prEntry->cRssi, prEntry->u4Dist, prEntry->u4Distsd); ++ ++ nsize = nsize1 + nsize2 + nsize3; ++ if (nsize < nleft) { ++ ++ kalStrnCpy(p, text1, TMP_TEXT_LEN_S); ++ p += nsize1; ++ ++ kalStrnCpy(p, text2, TMP_TEXT_LEN_L); ++ p += nsize2; ++ ++ kalStrnCpy(p, text3, TMP_TEXT_LEN_L); ++ p += nsize3; ++ ++ nleft -= nsize; ++ } else { ++ DBGLOG(SCN, TRACE, "Warning: Early break! (%d)\n", i); ++ break; /* discard following entries, TODO: apcount? */ ++ } ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "####\n"); ++ p += kalSprintf(p, "%s", text1); ++ ++ pBr++; ++ } ++ ++ nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "----\n"); ++ kalSprintf(p, "%s", text1); ++ ++ *pu4RetLen = u4MaxBufferLen - nleft; ++ DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++short_buf: ++ DBGLOG(SCN, TRACE, ++ "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), ++ u4MaxBufferLen, (char *)pvBuffer); ++ return WLAN_STATUS_INVALID_LENGTH; ++} ++#endif ++ ++#if CFG_SUPPORT_GET_CH_ENV ++WLAN_STATUS ++scanEnvResult(P_GLUE_INFO_T prGlueInfo, OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ CHAR *p = pvBuffer; ++ INT_32 nsize; ++ INT_32 i, nleft; ++ P_SCAN_INFO_T prScanInfo; ++ P_LINK_T prBSSDescList; ++ P_BSS_DESC_T prBssDesc; ++ CH_ENV_T chEnvInfo[54]; /* 54: from FW define; TODO: sync MAXIMUM_OPERATION_CHANNEL_LIST */ ++ UINT_32 i4GetCh = 0; ++ INT_32 i4Argc = 0; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; ++ UINT_8 ucTextLen = 40; ++ UCHAR text[ucTextLen]; ++ INT_32 u4Ret; ++ ++ prAdapter = prGlueInfo->prAdapter; ++ prScanInfo = &(prAdapter->rWifiVar.rScanInfo); ++ prBSSDescList = &prScanInfo->rBSSDescList; ++ ++ kalMemZero(chEnvInfo, sizeof(chEnvInfo)); ++ ++ DBGLOG(SCN, TRACE, "pvBuffer:%s, pu4RetLen:%d\n", (char *)pvBuffer, *pu4RetLen); ++ ++ wlanCfgParseArgument(pvBuffer, &i4Argc, apcArgv); ++ DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); ++ ++ if (i4Argc >= 2) { ++ u4Ret = kalkStrtou32(apcArgv[1], 0, &i4GetCh); ++ if (u4Ret) ++ DBGLOG(SCN, TRACE, "parse pvBuffer error u4Ret=%d\n", u4Ret); ++ /* i4GetCh = kalStrtoul(apcArgv[1], NULL, 0); */ ++ } ++ ++ nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ ++ ++ nsize = kalSnprintf(text, ucTextLen, "%s", "scanEnvResult\nResult:1\n");/* Always return 1 for alpha version. */ ++ ++ if (nsize < nleft) { ++ p += nsize = kalSnprintf(p, ucTextLen, "%s", text); ++ nleft -= nsize; ++ } else ++ goto short_buf; ++ ++ /* Search BSS Desc from current SCAN result list. */ ++ LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { ++ if (prBssDesc->ucChannelNum > 0) { ++ if (prBssDesc->ucChannelNum <= 14) { /* 1~14 */ ++ chEnvInfo[prBssDesc->ucChannelNum - 1].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum - 1].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 64) { /* 15~22 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 116) { /* 23~27 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 140) { /* 28~30 */ ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucApNum++; ++ } else if (prBssDesc->ucChannelNum <= 165) { /* 31~35 */ ++ chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucChNum = prBssDesc->ucChannelNum; ++ chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucApNum++; ++ } ++ } ++ } ++ ++ for (i = 0; i < 54; i++) { ++ if (chEnvInfo[i].ucChNum != 0) { ++ if (i4GetCh == 0 || (chEnvInfo[i].ucChNum == (UINT_8)i4GetCh)) { ++ DBGLOG(SCN, TRACE, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, chEnvInfo[i].ucApNum); ++ p += nsize = ++ kalSnprintf(p, ucTextLen, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, ++ chEnvInfo[i].ucApNum); ++ nleft -= nsize; ++ } ++ } ++ } ++ ++ p += nsize = kalSnprintf(p, ucTextLen, "%s", "----\n"); ++ nleft -= nsize; ++ ++ *pu4RetLen = u4MaxBufferLen - nleft; ++ DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); ++ ++ return WLAN_STATUS_SUCCESS; ++ ++short_buf: ++ DBGLOG(SCN, TRACE, "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), u4MaxBufferLen, p); ++ return WLAN_STATUS_INVALID_LENGTH; ++} ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set int handler. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. ++* \param[in] pcExtra The buffer with input value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ PUINT_32 pu4IntBuf; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4BufLen = 0; ++ int status = 0; ++ P_PTA_IPC_T prPtaIpc; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->mode; ++ pu4IntBuf = (PUINT_32) pcExtra; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_TEST_MODE: ++ /* printk("TestMode=%ld\n", pu4IntBuf[1]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY) { ++ prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_MODE; ++ } else if (pu4IntBuf[1] == 0) { ++ prNdisReq->ndisOidCmd = OID_CUSTOM_ABORT_TEST_MODE; ++ } else { ++ status = 0; ++ break; ++ } ++ prNdisReq->inNdisOidlength = 0; ++ prNdisReq->outNdisOidLength = 0; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++ case PRIV_CMD_TEST_CMD: ++ /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++#if CFG_SUPPORT_PRIV_MCR_RW ++ case PRIV_CMD_ACCESS_MCR: ++ /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) ++ prGlueInfo->fgMcrAccessAllowed = TRUE; ++ status = 0; ++ break; ++ } ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++#endif ++ ++ case PRIV_CMD_SW_CTRL: ++ /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++#if 0 ++ case PRIV_CMD_BEACON_PERIOD: ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetBeaconInterval, ++ (PVOID)&pu4IntBuf[1],/* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), &u4BufLen); ++ break; ++#endif ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++ case PRIV_CMD_CSUM_OFFLOAD: ++ { ++ UINT_32 u4CSUMFlags; ++ ++ if (pu4IntBuf[1] == 1) ++ u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; ++ else if (pu4IntBuf[1] == 0) ++ u4CSUMFlags = 0; ++ else ++ return -EINVAL; ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidSetCSUMOffload, ++ (PVOID)&u4CSUMFlags, ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { ++ if (pu4IntBuf[1] == 1) ++ prNetDev->features |= NETIF_F_HW_CSUM; ++ else if (pu4IntBuf[1] == 0) ++ prNetDev->features &= ~NETIF_F_HW_CSUM; ++ } ++ } ++ break; ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++ case PRIV_CMD_POWER_MODE: ++ kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, ++ (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ break; ++ ++ case PRIV_CMD_WMM_PS: ++ { ++ PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T rWmmPsTest; ++ ++ rWmmPsTest.bmfgApsdEnAc = (UINT_8) pu4IntBuf[1]; ++ rWmmPsTest.ucIsEnterPsAtOnce = (UINT_8) pu4IntBuf[2]; ++ rWmmPsTest.ucIsDisableUcTrigger = (UINT_8) pu4IntBuf[3]; ++ rWmmPsTest.reserved = 0; ++ ++ kalIoctl(prGlueInfo, ++ wlanoidSetWiFiWmmPsTest, ++ (PVOID)&rWmmPsTest, ++ sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ } ++ break; ++ ++#if 0 ++ case PRIV_CMD_ADHOC_MODE: ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetAdHocMode, ++ (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(UINT_32), &u4BufLen); ++ break; ++#endif ++ ++ case PRIV_CUSTOM_BWCS_CMD: ++ ++ DBGLOG(REQ, INFO, "pu4IntBuf[1] = %x, size of PTA_IPC_T = %zu.\n", ++ pu4IntBuf[1], sizeof(PARAM_PTA_IPC_T)); ++ ++ prPtaIpc = (P_PTA_IPC_T) aucOidBuf; ++ prPtaIpc->u.aucBTPParams[0] = (UINT_8) (pu4IntBuf[1] >> 24); ++ prPtaIpc->u.aucBTPParams[1] = (UINT_8) (pu4IntBuf[1] >> 16); ++ prPtaIpc->u.aucBTPParams[2] = (UINT_8) (pu4IntBuf[1] >> 8); ++ prPtaIpc->u.aucBTPParams[3] = (UINT_8) (pu4IntBuf[1]); ++ ++ DBGLOG(REQ, INFO, ++ "BCM BWCS CMD : BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", ++ prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], ++ prPtaIpc->u.aucBTPParams[3]); ++ ++#if 0 ++ status = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++ status = wlanoidSetBT(prGlueInfo->prAdapter, ++ (PVOID)&aucOidBuf[0], sizeof(PARAM_PTA_IPC_T), &u4BufLen); ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ status = -EFAULT; ++ ++ break; ++ ++ case PRIV_CMD_BAND_CONFIG: ++ { ++ DBGLOG(REQ, INFO, "CMD set_band=%u\n", (UINT_32) pu4IntBuf[1]); ++ } ++ break; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ case PRIV_CMD_P2P_MODE: ++ { ++ /* no use, move to set_p2p_mode_handler() */ ++ PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; ++ ++ p2pmode.u4Enable = pu4IntBuf[1]; ++ p2pmode.u4Mode = pu4IntBuf[2]; ++ set_p2p_mode_handler(prNetDev, p2pmode); ++#if 0 ++ PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; ++ WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; ++ BOOLEAN fgIsP2PEnding; ++ ++ GLUE_SPIN_LOCK_DECLARATION(); ++ ++ /* avoid remove & p2p off command simultaneously */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ fgIsP2PEnding = g_u4P2PEnding; ++ g_u4P2POnOffing = 1; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ ++ if (fgIsP2PEnding == 1) { ++ /* skip the command if we are removing */ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++ break; ++ } ++ rSetP2P.u4Enable = pu4IntBuf[1]; ++ rSetP2P.u4Mode = pu4IntBuf[2]; ++ ++ if (!rSetP2P.u4Enable) ++ p2pNetUnregister(prGlueInfo, TRUE); ++ ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ /* ++ Scenario: ++ 1. System enters suspend/resume but not yet enter wlanearlysuspend() ++ or wlanlateresume(); ++ ++ 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() ++ and get g_halt_sem then do glRegisterEarlySuspend() or ++ glUnregisterEarlySuspend(); ++ ++ But system suspend/resume procedure is not yet finished so we ++ suspend; ++ ++ 3. System switches back to do suspend/resume procedure and execute ++ kalIoctl(). But driver does not yet release g_halt_sem so system ++ suspend in wlanearlysuspend() or wlanlateresume(); ++ ++ ==> deadlock occurs. ++ */ ++ if ((!rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { ++ /* fgIsP2PRegistered == TRUE means P2P is enabled */ ++ DBGLOG(P2P, INFO, "p2pEalySuspendReg\n"); ++ p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p remove */ ++ } ++ ++ DBGLOG(P2P, INFO, ++ "wlanoidSetP2pMode 0x%p %d %d\n", &rSetP2P, rSetP2P.u4Enable, rSetP2P.u4Mode); ++ rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, ++ (PVOID)&rSetP2P, /* pu4IntBuf[0] is used as input SubCmd */ ++ sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), ++ FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ DBGLOG(P2P, INFO, "wlanoidSetP2pMode ok\n"); ++ ++ /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ ++ if ((rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { ++ /* fgIsP2PRegistered == TRUE means P2P on successfully */ ++ p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p on */ ++ } ++ ++ if (rSetP2P.u4Enable) ++ p2pNetRegister(prGlueInfo, TRUE); ++ ++ GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); ++ g_u4P2POnOffing = 0; ++ GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); ++#endif ++ } ++ break; ++#endif ++ ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ case PRIV_CMD_MET_PROFILING: ++ { ++ /* PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; */ ++ /* rWfdDebugModeInfo.ucWFDDebugMode=(UINT_8)pu4IntBuf[1]; */ ++ /* rWfdDebugModeInfo.u2SNPeriod=(UINT_16)pu4IntBuf[2]; */ ++ /* DBGLOG(REQ, INFO,("WFD Debug Mode:%d Period:%d\n", ++ rWfdDebugModeInfo.ucWFDDebugMode,rWfdDebugModeInfo.u2SNPeriod)); */ ++ prGlueInfo->u8MetProfEnable = (UINT_8) pu4IntBuf[1]; ++ prGlueInfo->u16MetUdpPort = (UINT_16) pu4IntBuf[2]; ++ DBGLOG(REQ, INFO, "MET_PROF: Enable=%d UDP_PORT=%d\n", prGlueInfo->u8MetProfEnable, ++ prGlueInfo->u16MetUdpPort); ++ ++ } ++ break; ++ ++#endif ++ case PRIV_CMD_WFD_DEBUG_CODE: ++ { ++ PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; ++ ++ rWfdDebugModeInfo.ucWFDDebugMode = (UINT_8) pu4IntBuf[1]; ++ rWfdDebugModeInfo.u2SNPeriod = (UINT_16) pu4IntBuf[2]; ++ DBGLOG(REQ, INFO, "WFD Debug Mode:%d Period:%d\n", rWfdDebugModeInfo.ucWFDDebugMode, ++ rWfdDebugModeInfo.u2SNPeriod); ++ kalIoctl(prGlueInfo, wlanoidSetWfdDebugMode, (PVOID)&rWfdDebugModeInfo, ++ sizeof(PARAM_CUSTOM_WFD_DEBUG_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); ++ ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get int handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. ++* \param[out] pcExtra The buffer with put the return value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_8 gucBufDbgCode[1000]; ++ ++static int ++_priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ PUINT_32 pu4IntBuf; ++ P_GLUE_INFO_T prGlueInfo; ++ UINT_32 u4BufLen = 0; ++ int status = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->mode; ++ pu4IntBuf = (PUINT_32) pcExtra; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_TEST_CMD: ++ /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ /* ++ if (copy_to_user(prIwReqData->data.pointer, ++ &prNdisReq->ndisOidContent[4], 4)) { ++ printk(KERN_NOTICE "priv_get_int() copy_to_user oidBuf fail(3)\n"); ++ return -EFAULT; ++ } ++ */ ++ } ++ return status; ++ ++#if CFG_SUPPORT_PRIV_MCR_RW ++ case PRIV_CMD_ACCESS_MCR: ++ /* printk("addr=0x%08lx\n", pu4IntBuf[1]); */ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ status = 0; ++ return status; ++ } ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ } ++ return status; ++#endif ++ ++ case PRIV_CMD_DUMP_MEM: ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++#if 1 ++ if (!prGlueInfo->fgMcrAccessAllowed) { ++ status = 0; ++ return status; ++ } ++#endif ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_MEM_DUMP; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[0]; ++ return status; ++ ++ case PRIV_CMD_SW_CTRL: ++ /* printk(" addr=0x%08lx\n", pu4IntBuf[1]); */ ++ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; ++ } ++ return status; ++ ++#if 0 ++ case PRIV_CMD_BEACON_PERIOD: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryBeaconInterval, ++ (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++ ++ case PRIV_CMD_POWER_MODE: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQuery802dot11PowerSaveProfile, ++ (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++ ++ case PRIV_CMD_ADHOC_MODE: ++ status = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryAdHocMode, (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); ++ return status; ++#endif ++ ++ case PRIV_CMD_BAND_CONFIG: ++ DBGLOG(REQ, INFO, "CMD get_band=\n"); ++ prIwReqData->mode = 0; ++ return status; ++ ++ default: ++ break; ++ } ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_GET_CH_LIST: ++ { ++ UINT_16 i, j = 0; ++ UINT_8 NumOfChannel = 50; ++ UINT_8 ucMaxChannelNum = 50; ++ INT_32 ch[50]; ++ /*RF_CHANNEL_INFO_T aucChannelList[50];*/ ++ P_RF_CHANNEL_INFO_T paucChannelList; ++ P_RF_CHANNEL_INFO_T ChannelList_t; ++ ++ paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); ++ if (paucChannelList == NULL) { ++ DBGLOG(REQ, INFO, "alloc ChannelList fail\n"); ++ return -EFAULT; ++ } ++ kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); ++ kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); ++ if (NumOfChannel > 50) { ++ ASSERT(0); ++ NumOfChannel = 50; ++ } ++ ++ ChannelList_t = paucChannelList; ++ if (kalIsAPmode(prGlueInfo)) { ++ for (i = 0; i < NumOfChannel; i++) { ++ if ((ChannelList_t->ucChannelNum <= 13) ++ || (ChannelList_t->ucChannelNum == 36 ++ || ChannelList_t->ucChannelNum == 40 ++ || ChannelList_t->ucChannelNum == 44 ++ || ChannelList_t->ucChannelNum == 48)) { ++ ch[j] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ j++; ++ } ++ } ++ } else { ++ for (j = 0; j < NumOfChannel; j++) { ++ ch[j] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ } ++ } ++ ++ kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); ++ ++ prIwReqData->data.length = j; ++ if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) ++ return -EFAULT; ++ else ++ return status; ++ } ++ ++ case PRIV_CMD_GET_BUILD_DATE_CODE: ++ { ++ UINT_8 aucBuffer[16]; ++ ++ if (kalIoctl(prGlueInfo, ++ wlanoidQueryBuildDateCode, ++ (PVOID) aucBuffer, ++ sizeof(UINT_8) * 16, TRUE, TRUE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { ++ prIwReqData->data.length = sizeof(UINT_8) * 16; ++ ++ if (copy_to_user(prIwReqData->data.pointer, aucBuffer, prIwReqData->data.length)) ++ return -EFAULT; ++ else ++ return status; ++ } else { ++ return -EFAULT; ++ } ++ } ++ ++ case PRIV_CMD_GET_DEBUG_CODE: ++ { ++ wlanQueryDebugCode(prGlueInfo->prAdapter); ++ ++ kalMemSet(gucBufDbgCode, '.', sizeof(gucBufDbgCode)); ++ if (copy_to_user(prIwReqData->data.pointer, gucBufDbgCode, prIwReqData->data.length)) ++ return -EFAULT; ++ else ++ return status; ++ } ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} /* priv_get_int */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set int array handler. ++* ++* \param[in] prNetDev Net device requested. ++* \param[in] prIwReqInfo Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. ++* \param[in] pcExtra The buffer with input value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd, u4BufLen; ++ P_GLUE_INFO_T prGlueInfo; ++ int status = 0; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_SET_TXPWR_CTRL_T prTxpwr; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_SET_TX_POWER: ++ { ++ INT_32 *setting = prIwReqData->data.pointer; ++ UINT_16 i; ++ ++#if 0 ++ DBGLOG(REQ, INFO, "Tx power num = %d\n", prIwReqData->data.length); ++ ++ DBGLOG(REQ, INFO, "Tx power setting = %d %d %d %d\n", ++ setting[0], setting[1], setting[2], setting[3]); ++#endif ++ prTxpwr = &prGlueInfo->rTxPwr; ++ if (setting[0] == 0 && prIwReqData->data.length == 4 /* argc num */) { ++ /* 0 (All networks), 1 (legacy STA), 2 (Hotspot AP), 3 (P2P), 4 (BT over Wi-Fi) */ ++ if (setting[1] == 1 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GLegacyStaPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GLegacyStaPwrOffset = setting[3]; ++ } ++ if (setting[1] == 2 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GHotspotPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GHotspotPwrOffset = setting[3]; ++ } ++ if (setting[1] == 3 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GP2pPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GP2pPwrOffset = setting[3]; ++ } ++ if (setting[1] == 4 || setting[1] == 0) { ++ if (setting[2] == 0 || setting[2] == 1) ++ prTxpwr->c2GBowPwrOffset = setting[3]; ++ if (setting[2] == 0 || setting[2] == 2) ++ prTxpwr->c5GBowPwrOffset = setting[3]; ++ } ++ } else if (setting[0] == 1 && prIwReqData->data.length == 2) { ++ prTxpwr->ucConcurrencePolicy = setting[1]; ++ } else if (setting[0] == 2 && prIwReqData->data.length == 3) { ++ if (setting[1] == 0) { ++ for (i = 0; i < 14; i++) ++ prTxpwr->acTxPwrLimit2G[i] = setting[2]; ++ } else if (setting[1] <= 14) ++ prTxpwr->acTxPwrLimit2G[setting[1] - 1] = setting[2]; ++ } else if (setting[0] == 3 && prIwReqData->data.length == 3) { ++ if (setting[1] == 0) { ++ for (i = 0; i < 4; i++) ++ prTxpwr->acTxPwrLimit5G[i] = setting[2]; ++ } else if (setting[1] <= 4) ++ prTxpwr->acTxPwrLimit5G[setting[1] - 1] = setting[2]; ++ } else if (setting[0] == 4 && prIwReqData->data.length == 2) { ++ if (setting[1] == 0) ++ wlanDefTxPowerCfg(prGlueInfo->prAdapter); ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetTxPower, ++ prTxpwr, ++ sizeof(SET_TXPWR_CTRL_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); ++ } else ++ return -EFAULT; ++ } ++ return status; ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get int array handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. ++* \param[out] pcExtra The buffer with put the return value ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EFAULT For fail. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd; ++ P_GLUE_INFO_T prGlueInfo; ++ int status = 0; ++ INT_32 ch[50]; ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_GET_CH_LIST: ++ { ++ UINT_16 i; ++ UINT_8 NumOfChannel = 50; ++ UINT_8 ucMaxChannelNum = 50; ++ /*RF_CHANNEL_INFO_T aucChannelList[50];*/ ++ P_RF_CHANNEL_INFO_T paucChannelList; ++ P_RF_CHANNEL_INFO_T ChannelList_t; ++ ++ paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); ++ if (paucChannelList == NULL) { ++ DBGLOG(REQ, INFO, "alloc fail\n"); ++ return -EINVAL; ++ } ++ kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); ++ ++ kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); ++ if (NumOfChannel > 50) ++ NumOfChannel = 50; ++ ++ ChannelList_t = paucChannelList; ++ for (i = 0; i < NumOfChannel; i++) { ++ ch[i] = (INT_32) ChannelList_t->ucChannelNum; ++ ChannelList_t++; ++ } ++ ++ kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); ++ prIwReqData->data.length = NumOfChannel; ++ if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) ++ return -EFAULT; ++ else ++ return status; ++ } ++ default: ++ break; ++ } ++ ++ return status; ++} /* priv_get_int */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl set structure handler. ++* ++* \param[in] pDev Net device requested. ++* \param[in] prIwReqData Pointer to iwreq_data structure. ++* ++* \retval 0 For success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL If a value is out of range. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ UINT_32 u4SubCmd = 0; ++ int status = 0; ++ /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ ++ UINT_32 u4CmdLen = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq; ++ PUINT_32 pu4IntBuf = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4BufLen = 0; ++ ++ ASSERT(prNetDev); ++ /* ASSERT(prIwReqInfo); */ ++ ASSERT(prIwReqData); ++ /* ASSERT(pcExtra); */ ++ ++ kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); ++ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, prIwReqData)) ++ return -EINVAL; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++#endif ++ ++ switch (u4SubCmd) { ++#if 0 /* PTA_ENABLED */ ++ case PRIV_CMD_BT_COEXIST: ++ u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); ++ ASSERT(sizeof(PARAM_CUSTOM_BT_COEXIST_T) >= u4CmdLen); ++ if (sizeof(PARAM_CUSTOM_BT_COEXIST_T) < u4CmdLen) ++ return -EFAULT; ++ ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { ++ status = -EFAULT; /* return -EFAULT; */ ++ break; ++ } ++ ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBtCoexistCtrl, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++ if (WLAN_STATUS_SUCCESS != rStatus) ++ status = -EFAULT; ++ break; ++#endif ++ ++ case PRIV_CUSTOM_BWCS_CMD: ++ u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); ++ ASSERT(sizeof(PARAM_PTA_IPC_T) >= u4CmdLen); ++ if (sizeof(PARAM_PTA_IPC_T) < u4CmdLen) ++ return -EFAULT; ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(REQ, INFO, ++ "ucCmdLen = %d, size of PTA_IPC_T = %d, prIwReqData->data = 0x%x.\n", u4CmdLen, ++ sizeof(PARAM_PTA_IPC_T), prIwReqData->data); ++ ++ DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%u)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++ ++ DBGLOG(REQ, INFO, "*pcExtra = 0x%x\n", *pcExtra); ++#endif ++ ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { ++ status = -EFAULT; /* return -EFAULT; */ ++ break; ++ } ++#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG ++ DBGLOG(REQ, INFO, "priv_set_struct(): BWCS CMD = %02x%02x%02x%02x\n", ++ aucOidBuf[2], aucOidBuf[3], aucOidBuf[4], aucOidBuf[5]); ++#endif ++ ++#if 0 ++ status = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++#if 1 ++ status = wlanoidSetBT(prGlueInfo->prAdapter, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); ++#endif ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ status = -EFAULT; ++ ++ break; ++ ++#if CFG_SUPPORT_WPS2 ++ case PRIV_CMD_WSC_PROBE_REQ: ++ { ++ /* retrieve IE for Probe Request */ ++ if (prIwReqData->data.length > 0) { ++ if (copy_from_user(prGlueInfo->aucWSCIE, prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ prGlueInfo->u2WSCIELen = prIwReqData->data.length; ++ } else { ++ prGlueInfo->u2WSCIELen = 0; ++ } ++ } ++ break; ++#endif ++ case PRIV_CMD_OID: ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ if (!kalMemCmp(&aucOidBuf[0], pcExtra, prIwReqData->data.length)) ++ DBGLOG(REQ, INFO, "pcExtra buffer is valid\n"); ++ else ++ DBGLOG(REQ, INFO, "pcExtra 0x%p\n", pcExtra); ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0], &u4BufLen); ++ /* Copy result to user space */ ++ ((P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0])->outNdisOidLength = u4BufLen; ++ ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { ++ DBGLOG(REQ, INFO, "copy_to_user oidBuf fail\n"); ++ status = -EFAULT; ++ } ++ ++ break; ++ ++ case PRIV_CMD_SW_CTRL: ++ pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ /* kalMemCopy(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, 8); */ ++ if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ status = -EFAULT; ++ break; ++ } ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ /* Execute this OID */ ++ status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Private ioctl get struct handler. ++* ++* \param[in] pDev Net device requested. ++* \param[out] pIwReq Pointer to iwreq structure. ++* \param[in] cmd Private sub-command. ++* ++* \retval 0 For success. ++* \retval -EFAULT If copy from user space buffer fail. ++* \retval -EOPNOTSUPP Parameter "cmd" not recognized. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ UINT_32 u4SubCmd = 0; ++ P_NDIS_TRANSPORT_STRUCT prNdisReq = NULL; ++ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4BufLen = 0; ++ PUINT_32 pu4IntBuf = NULL; ++ int status = 0; ++ ++ kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); ++ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqData); ++ if (!prNetDev || !prIwReqData) { ++ DBGLOG(REQ, INFO, "priv_get_struct(): invalid param(0x%p, 0x%p)\n", prNetDev, prIwReqData); ++ return -EINVAL; ++ } ++ ++ u4SubCmd = (UINT_32) prIwReqData->data.flags; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_get_struct(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", ++ prIwReqInfo->cmd, u4SubCmd); ++#endif ++ memset(aucOidBuf, 0, sizeof(aucOidBuf)); ++ ++ switch (u4SubCmd) { ++ case PRIV_CMD_OID: ++ if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, sizeof(NDIS_TRANSPORT_STRUCT))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); ++ return -EFAULT; ++ } ++ ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++#if 0 ++ DBGLOG(REQ, INFO, "\n priv_get_struct cmd 0x%02x len:%d OID:0x%08x OID Len:%d\n", ++ cmd, pIwReq->u.data.length, ndisReq->ndisOidCmd, ndisReq->inNdisOidlength); ++#endif ++ if (priv_get_ndis(prNetDev, prNdisReq, &u4BufLen) == 0) { ++ prNdisReq->outNdisOidLength = u4BufLen; ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], ++ u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - ++ sizeof(prNdisReq->ndisOidContent))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(1)\n"); ++ return -EFAULT; ++ } ++ return 0; ++ } ++ prNdisReq->outNdisOidLength = u4BufLen; ++ if (copy_to_user(prIwReqData->data.pointer, ++ &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); ++ } ++ return -EFAULT; ++ ++ case PRIV_CMD_SW_CTRL: ++ pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; ++ prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; ++ ++ if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, ++ prIwReqData->data.length)) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); ++ return -EFAULT; ++ } ++ ++ prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; ++ prNdisReq->inNdisOidlength = 8; ++ prNdisReq->outNdisOidLength = 8; ++ ++ status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); ++ if (status == 0) { ++ prNdisReq->outNdisOidLength = u4BufLen; ++ /* printk("len=%d Result=%08lx\n", u4BufLen, *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ ++ ++ if (copy_to_user(prIwReqData->data.pointer, ++ &prNdisReq->ndisOidContent[4], ++ 4 /* OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent) */)) { ++ DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); ++ } ++ } ++ return 0; ++ ++ default: ++ DBGLOG(REQ, WARN, "get struct cmd:0x%x\n", u4SubCmd); ++ return -EOPNOTSUPP; ++ } ++} /* priv_get_struct */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a set operation for a single OID. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) ++{ ++ P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 u4SetInfoLen = 0; ++ ++ ASSERT(prNetDev); ++ ASSERT(prNdisReq); ++ ASSERT(pu4OutputLen); ++ ++ if (!prNetDev || !prNdisReq || !pu4OutputLen) { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", ++ prNetDev, prNdisReq, pu4OutputLen); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); ++#endif ++ ++ if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { ++ /* WARNLOG(("Set OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ ++ return -EOPNOTSUPP; ++ } ++ ++ if (NULL == prWlanReqEntry->pfOidSetHandler) { ++ /* WARNLOG(("Set %s: Null set handler\n", prWlanReqEntry->pucOidName)); */ ++ return -EOPNOTSUPP; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_set_ndis(): %s\n", prWlanReqEntry->pucOidName); ++#endif ++ ++ if (prWlanReqEntry->fgSetBufLenChecking) { ++ if (prNdisReq->inNdisOidlength != prWlanReqEntry->u4InfoBufLen) { ++ DBGLOG(REQ, WARN, "Set %s: Invalid length (current=%u, needed=%u)\n", ++ prWlanReqEntry->pucOidName, ++ prNdisReq->inNdisOidlength, prWlanReqEntry->u4InfoBufLen); ++ ++ *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; ++ return -EINVAL; ++ } ++ } ++ ++ if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { ++ /* GLUE sw info only */ ++ status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4SetInfoLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { ++ /* multiple sw operations */ ++ status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4SetInfoLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { ++ /* driver core */ ++ ++ status = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidSetHandler, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ } else { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); ++ return -EOPNOTSUPP; ++ } ++ ++ *pu4OutputLen = u4SetInfoLen; ++ ++ switch (status) { ++ case WLAN_STATUS_SUCCESS: ++ break; ++ ++ case WLAN_STATUS_INVALID_LENGTH: ++ /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* u4SetInfoLen)); */ ++ break; ++ } ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ return -EFAULT; ++ ++ return 0; ++} /* priv_set_ndis */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a query operation for a single OID. Basically we ++* return information about the current state of the OID in question. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* \retval -EINVAL invalid input parameters ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) ++{ ++ P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; ++ UINT_32 u4BufLen = 0; ++ WLAN_STATUS status = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ ASSERT(prNetDev); ++ ASSERT(prNdisReq); ++ ASSERT(pu4OutputLen); ++ ++ if (!prNetDev || !prNdisReq || !pu4OutputLen) { ++ DBGLOG(REQ, INFO, "priv_get_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", ++ prNetDev, prNdisReq, pu4OutputLen); ++ return -EINVAL; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ASSERT(prGlueInfo); ++ if (!prGlueInfo) { ++ DBGLOG(REQ, INFO, "priv_get_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", ++ prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); ++ return -EINVAL; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); ++#endif ++ ++ if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { ++ /* WARNLOG(("Query OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ ++ return -EOPNOTSUPP; ++ } ++ ++ if (NULL == prWlanReqEntry->pfOidQueryHandler) { ++ /* WARNLOG(("Query %s: Null query handler\n", prWlanReqEntry->pucOidName)); */ ++ return -EOPNOTSUPP; ++ } ++#if 0 ++ DBGLOG(REQ, INFO, "priv_get_ndis(): %s\n", prWlanReqEntry->pucOidName); ++#endif ++ ++ if (prWlanReqEntry->fgQryBufLenChecking) { ++ if (prNdisReq->inNdisOidlength < prWlanReqEntry->u4InfoBufLen) { ++ /* Not enough room in InformationBuffer. Punt */ ++ /* WARNLOG(("Query %s: Buffer too short (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* prWlanReqEntry->u4InfoBufLen)); */ ++ ++ *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; ++ ++ status = WLAN_STATUS_INVALID_LENGTH; ++ return -EINVAL; ++ } ++ } ++ ++ if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { ++ /* GLUE sw info only */ ++ status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4BufLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { ++ /* multiple sw operations */ ++ status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, &u4BufLen); ++ } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { ++ /* driver core */ ++ ++ status = kalIoctl(prGlueInfo, ++ (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidQueryHandler, ++ prNdisReq->ndisOidContent, ++ prNdisReq->inNdisOidlength, TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ } else { ++ DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); ++ return -EOPNOTSUPP; ++ } ++ ++ *pu4OutputLen = u4BufLen; ++ ++ switch (status) { ++ case WLAN_STATUS_SUCCESS: ++ break; ++ ++ case WLAN_STATUS_INVALID_LENGTH: ++ /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ ++ /* prWlanReqEntry->pucOidName, */ ++ /* prNdisReq->inNdisOidlength, */ ++ /* u4BufLen)); */ ++ break; ++ } ++ ++ if (WLAN_STATUS_SUCCESS != status) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} /* priv_get_ndis */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse command value in a string. ++* ++* @param InStr Pointer to the string buffer. ++* @param OutStr Pointer to the next command value. ++* @param OutLen Record the resident buffer length. ++* ++* @retval Command value. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen) ++{ ++ unsigned char Charc, *Buf; ++ unsigned int Num; ++ int Maxloop; ++ int ReadId; ++ int TotalLen; ++ ++ /* init */ ++ Num = 0; ++ Maxloop = 0; ++ ReadId = 0; ++ Buf = (unsigned char *)InStr; ++ TotalLen = *OutLen; ++ *OutStr = Buf; ++ ++ /* sanity check */ ++ if (Buf[0] == 0x00) ++ return 0; ++ ++ /* check the value is decimal or hex */ ++ if ((Buf[ReadId] == 'x') || ((Buf[ReadId] == '0') && (Buf[ReadId + 1] == 'x'))) { ++ /* skip x or 0x */ ++ if (Buf[ReadId] == 'x') ++ ReadId++; ++ else ++ ReadId += 2; ++ ++ /* translate the hex number */ ++ while (Maxloop++ < 10) { ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc -= 'a'; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc -= 'A'; ++ else ++ break; /* exit the parsing */ ++ Num = Num * 16 + Charc + 10; ++ ReadId++; ++ TotalLen--; ++ } ++ } else { ++ /* translate the decimal number */ ++ while (Maxloop++ < 10) { ++ Charc = Buf[ReadId]; ++ if ((Charc < 0x30) || (Charc > 0x39)) ++ break; /* exit the parsing */ ++ Charc -= 0x30; ++ Num = Num * 10 + Charc; ++ ReadId++; ++ TotalLen--; ++ } ++ } ++ ++ if (Buf[ReadId] == 0x00) ++ *OutStr = &Buf[ReadId]; ++ else ++ *OutStr = &Buf[ReadId + 1]; /* skip the character: _ */ ++ ++ *OutLen = TotalLen - 1; /* skip the character: _ */ ++ return Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* @brief Parse command MAC address in a string. ++* ++* @param InStr Pointer to the string buffer. ++* @param OutStr Pointer to the next command value. ++* @param OutLen Record the resident buffer length. ++* ++* @retval Command value. ++*/ ++/*----------------------------------------------------------------------------*/ ++UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac) ++{ ++ unsigned char Charc, *Buf; ++ unsigned int Num; ++ int Maxloop; ++ int ReadId; ++ int TotalLen; ++ ++ /* init */ ++ Num = 0; ++ Maxloop = 0; ++ ReadId = 0; ++ Buf = (unsigned char *)InStr; ++ TotalLen = *OutLen; ++ *OutStr = Buf; ++ ++ /* sanity check */ ++ if (Buf[0] == 0x00) ++ return 0; ++ ++ /* parse MAC */ ++ while (Maxloop < 6) { ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc = Charc - 'a' + 10; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc = Charc - 'A' + 10; ++ else ++ return -1; /* error, exit the parsing */ ++ ++ Num = Charc; ++ ReadId++; ++ TotalLen--; ++ ++ Charc = Buf[ReadId]; ++ if ((Charc >= 0x30) && (Charc <= 0x39)) ++ Charc -= 0x30; ++ else if ((Charc >= 'a') && (Charc <= 'f')) ++ Charc = Charc - 'a' + 10; ++ else if ((Charc >= 'A') && (Charc <= 'F')) ++ Charc = Charc - 'A' + 10; ++ else ++ return -1; /* error, exit the parsing */ ++ ++ Num = Num * 16 + Charc; ++ ReadId += 2; /* skip the character and ':' */ ++ TotalLen -= 2; ++ ++ OutMac[Maxloop] = Num; ++ Maxloop++; ++ } ++ ++ *OutStr = &Buf[ReadId]; /* skip the character: _ */ ++ *OutLen = TotalLen; /* skip the character: _ */ ++ return Num; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief The routine handles a set operation for a single OID. ++* ++* \param[in] pDev Net device requested. ++* \param[in] ndisReq Ndis request OID information copy from user. ++* \param[out] outputLen_p If the call is successful, returns the number of ++* bytes written into the query buffer. If the ++* call failed due to invalid length of the query ++* buffer, returns the amount of storage needed.. ++* ++* \retval 0 On success. ++* \retval -EOPNOTSUPP If cmd is not supported. ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static int ++_priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ P_GLUE_INFO_T GlueInfo; ++ INT_32 Status; ++ UINT_32 Subcmd; ++ UINT_8 *InBuf; ++ UINT_32 InBufLen; ++ ++ /* sanity check */ ++ ASSERT(prNetDev); ++ ASSERT(prIwReqInfo); ++ ASSERT(prIwReqData); ++ ASSERT(pcExtra); ++ ++ /* init */ ++ DBGLOG(REQ, INFO, "priv_set_string (%s)(%d)\n", ++ (UINT8 *) prIwReqData->data.pointer, (INT32) prIwReqData->data.length); ++ ++ if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) ++ return -EINVAL; ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ InBuf = aucOidBuf; ++ InBufLen = prIwReqData->data.length; ++ Status = 0; ++ ++ if (copy_from_user(InBuf, prIwReqData->data.pointer, prIwReqData->data.length)) ++ return -EFAULT; ++ ++ Subcmd = CmdStringDecParse(prIwReqData->data.pointer, &InBuf, &InBufLen); ++ DBGLOG(REQ, INFO, "priv_set_string> command = %u\n", (UINT32) Subcmd); ++ ++ /* handle the command */ ++ switch (Subcmd) { ++#if (CFG_SUPPORT_TDLS == 1) ++ case PRIV_CMD_OTHER_TDLS: ++ TdlsexCmd(GlueInfo, InBuf, InBufLen); ++ break; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++ case PRIV_CMD_OTHER_TAR: ++ { ++ rlmCmd(GlueInfo, InBuf, InBufLen); ++ break; ++ } ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ default: ++ break; ++ } ++ ++ return Status; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to search desired OID. ++* ++* \param rOid[in] Desired NDIS_OID ++* \param ppWlanReqEntry[out] Found registered OID entry ++* ++* \retval TRUE: Matched OID is found ++* \retval FALSE: No matched OID is found ++*/ ++/*----------------------------------------------------------------------------*/ ++static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry) ++{ ++ INT_32 i, j, k; ++ ++ i = 0; ++ j = NUM_SUPPORTED_OIDS - 1; ++ ++ while (i <= j) { ++ k = (i + j) / 2; ++ ++ if (rOid == arWlanOidReqTable[k].rOid) { ++ *ppWlanReqEntry = &arWlanOidReqTable[k]; ++ return TRUE; ++ } else if (rOid < arWlanOidReqTable[k].rOid) { ++ j = k - 1; ++ } else { ++ i = k + 1; ++ } ++ } ++ ++ return FALSE; ++} /* reqSearchSupportedOidEntry */ ++ ++#if 0 ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to query the radio configuration used in IBSS ++* mode and RF test mode. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[out] pvQueryBuffer Pointer to the buffer that holds the result of the query. ++* \param[in] u4QueryBufferLen The length of the query buffer. ++* \param[out] pu4QueryInfoLen If the call is successful, returns the number of ++* bytes written into the query buffer. If the call ++* failed due to invalid length of the query buffer, ++* returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) ++{ ++ P_PARAM_802_11_CONFIG_T prQueryConfig = (P_PARAM_802_11_CONFIG_T) pvQueryBuffer; ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ UINT_32 u4QueryInfoLen = 0; ++ ++ DEBUGFUNC("wlanoidQueryConfiguration"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4QueryInfoLen); ++ ++ *pu4QueryInfoLen = sizeof(PARAM_802_11_CONFIG_T); ++ if (u4QueryBufferLen < sizeof(PARAM_802_11_CONFIG_T)) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ ASSERT(pvQueryBuffer); ++ ++ kalMemZero(prQueryConfig, sizeof(PARAM_802_11_CONFIG_T)); ++ ++ /* Update the current radio configuration. */ ++ prQueryConfig->u4Length = sizeof(PARAM_802_11_CONFIG_T); ++ ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetBeaconInterval, ++ &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryBeaconInterval, ++ &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQueryAtimWindow, ++ &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryAtimWindow, ++ &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidQueryFrequency, ++ &prQueryConfig->u4DSConfig, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); ++#else ++ rStatus = wlanQueryInformation(prGlueInfo->prAdapter, ++ wlanoidQueryFrequency, ++ &prQueryConfig->u4DSConfig, sizeof(UINT_32), &u4QueryInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++ ++ prQueryConfig->rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); ++ ++ return rStatus; ++ ++} /* end of reqExtQueryConfiguration() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set the radio configuration used in IBSS ++* mode. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. ++* \param[in] u4SetBufferLen The length of the set buffer. ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed ++* due to invalid length of the set buffer, returns ++* the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_LENGTH ++* \retval WLAN_STATUS_NOT_ACCEPTED ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_PARAM_802_11_CONFIG_T prNewConfig = (P_PARAM_802_11_CONFIG_T) pvSetBuffer; ++ UINT_32 u4SetInfoLen = 0; ++ ++ DEBUGFUNC("wlanoidSetConfiguration"); ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pu4SetInfoLen); ++ ++ *pu4SetInfoLen = sizeof(PARAM_802_11_CONFIG_T); ++ ++ if (u4SetBufferLen < *pu4SetInfoLen) ++ return WLAN_STATUS_INVALID_LENGTH; ++ ++ /* OID_802_11_CONFIGURATION. If associated, NOT_ACCEPTED shall be returned. */ ++ if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) ++ return WLAN_STATUS_NOT_ACCEPTED; ++ ++ ASSERT(pvSetBuffer); ++ ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetBeaconInterval, ++ &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetBeaconInterval, ++ &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetAtimWindow, ++ &prNewConfig->u4ATIMWindow, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetAtimWindow, &prNewConfig->u4ATIMWindow, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++#if defined(_HIF_SDIO) ++ rStatus = sdio_io_ctrl(prGlueInfo, ++ wlanoidSetFrequency, ++ &prNewConfig->u4DSConfig, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); ++#else ++ rStatus = wlanSetInformation(prGlueInfo->prAdapter, ++ wlanoidSetFrequency, &prNewConfig->u4DSConfig, sizeof(UINT_32), &u4SetInfoLen); ++#endif ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ return rStatus; ++ ++ return rStatus; ++ ++} /* end of reqExtSetConfiguration() */ ++ ++#endif ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This routine is called to set beacon detection function enable/disable state ++* This is mainly designed for usage under BT inquiry state (disable function). ++* ++* \param[in] pvAdapter Pointer to the Adapter structure ++* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set ++* \param[in] u4SetBufferLen The length of the set buffer ++* \param[out] pu4SetInfoLen If the call is successful, returns the number of ++* bytes read from the set buffer. If the call failed due to invalid length of ++* the set buffer, returns the amount of storage needed. ++* ++* \retval WLAN_STATUS_SUCCESS ++* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. ++* \retval WLAN_STATUS_INVALID_LENGTH ++* ++*/ ++/*----------------------------------------------------------------------------*/ ++static WLAN_STATUS ++reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ ++ ASSERT(prGlueInfo); ++ ASSERT(pvSetBuffer); ++ ASSERT(pu4SetInfoLen); ++ ++ /* WIFI is enabled, when ACPI is D0 (ParamDeviceStateD0 = 1). And vice versa */ ++ ++ /* rStatus = wlanSetInformation(prGlueInfo->prAdapter, */ ++ /* wlanoidSetAcpiDevicePowerState, */ ++ /* pvSetBuffer, */ ++ /* u4SetBufferLen, */ ++ /* pu4SetInfoLen); */ ++ return rStatus; ++} ++ ++int priv_driver_set_chip_config(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) ++{ ++ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ P_ADAPTER_T prAdapter = NULL; ++ UINT_32 u4BufLen = 0; ++ INT_32 i4BytesWritten = 0; ++ UINT_32 u4CmdLen = 0; ++ UINT_32 u4PrefixLen = 0; ++ /* INT_32 i4Argc = 0; */ ++ /* PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = {0}; */ ++ ++ PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ prAdapter = prGlueInfo->prAdapter; ++ DBGLOG(REQ, INFO, "priv_driver_set_chip_config command is %s\n", pcCommand); ++ /* wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); */ ++ /* DBGLOG(REQ, LOUD,("argc is %i\n",i4Argc)); */ ++ /* */ ++ u4CmdLen = kalStrnLen(pcCommand, i4TotalLen); ++ u4PrefixLen = kalStrLen(CMD_SET_CHIP) + 1 /*space */; ++ ++ kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); ++ ++ /* if(i4Argc >= 2) { */ ++ if (u4CmdLen > u4PrefixLen) { ++ ++ rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; ++ /* rChipConfigInfo.u2MsgSize = kalStrnLen(apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ ++ rChipConfigInfo.u2MsgSize = u4CmdLen - u4PrefixLen; ++ /* kalStrnCpy(rChipConfigInfo.aucCmd,apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ ++ if (u4PrefixLen <= CHIP_CONFIG_RESP_SIZE) { ++ kalStrnCpy(rChipConfigInfo.aucCmd, pcCommand + u4PrefixLen, ++ CHIP_CONFIG_RESP_SIZE - u4PrefixLen); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetChipConfig, ++ &rChipConfigInfo, ++ sizeof(rChipConfigInfo), FALSE, FALSE, TRUE, TRUE, &u4BufLen); ++ } else { ++ ++ DBGLOG(REQ, INFO, "%s: kalIoctl Command Len > %d\n", __func__, CHIP_CONFIG_RESP_SIZE); ++ rStatus = WLAN_STATUS_FAILURE; ++ } ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) { ++ DBGLOG(REQ, INFO, "%s: kalIoctl ret=%d\n", __func__, rStatus); ++ i4BytesWritten = -1; ++ } ++ } ++ ++ return i4BytesWritten; ++ ++} ++ ++int priv_driver_set_miracast(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) ++{ ++ P_ADAPTER_T prAdapter = NULL; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ UINT_32 i4BytesWritten = 0; ++ /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ ++ /* UINT_32 u4BufLen = 0; */ ++ INT_32 i4Argc = 0; ++ UINT_32 ucMode = 0; ++ P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; ++ P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; ++ PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; ++ INT_32 u4Ret; ++ ++ ASSERT(prNetDev); ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); ++ wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); ++ DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); ++ ++ prAdapter = prGlueInfo->prAdapter; ++ if (i4Argc >= 2) { ++ u4Ret = kalkStrtou32(apcArgv[1], 0, &ucMode); /* ucMode = kalStrtoul(apcArgv[1], NULL, 0); */ ++ if (u4Ret) ++ DBGLOG(REQ, LOUD, "parse pcCommand error u4Ret=%d\n", u4Ret); ++ ++ if (g_ucMiracastMode == ucMode) ++ ; ++ /* XXX: continue or skip */ ++ ++ g_ucMiracastMode = ucMode; ++ prMsgWfdCfgUpdate = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); ++ ++ if (prMsgWfdCfgUpdate != NULL) { ++ ++ prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); ++ prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; ++ prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; ++ ++ if (ucMode == MIRACAST_MODE_OFF) { ++ prWfdCfgSettings->ucWfdEnable = 0; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); ++ } else if (ucMode == MIRACAST_MODE_SOURCE) { ++ prWfdCfgSettings->ucWfdEnable = 1; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 1"); ++ } else if (ucMode == MIRACAST_MODE_SINK) { ++ prWfdCfgSettings->ucWfdEnable = 2; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 2"); ++ } else { ++ prWfdCfgSettings->ucWfdEnable = 0; ++ snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); ++ } ++ mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); ++ ++ priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); ++ ++ } /* prMsgWfdCfgUpdate */ ++ else { ++ ASSERT(FALSE); ++ i4BytesWritten = -1; ++ } ++ } ++ ++ /* i4Argc */ ++ return i4BytesWritten; ++} ++ ++int priv_support_driver_cmd(IN struct net_device *prNetDev, IN OUT struct ifreq *prReq, IN int i4Cmd) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ int ret = 0; ++ char *pcCommand = NULL; ++ priv_driver_cmd_t *priv_cmd = NULL; ++ int i4BytesWritten = 0; ++ int i4TotalLen = 0; ++ ++ if (!prReq->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (!prGlueInfo) { ++ DBGLOG(REQ, WARN, "No glue info\n"); ++ ret = -EFAULT; ++ goto exit; ++ } ++ if (prGlueInfo->u4ReadyFlag == 0) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ priv_cmd = kzalloc(sizeof(priv_driver_cmd_t), GFP_KERNEL); ++ if (!priv_cmd) { ++ DBGLOG(REQ, WARN, "%s, alloc mem failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(priv_cmd, prReq->ifr_data, sizeof(priv_driver_cmd_t))) { ++ DBGLOG(REQ, INFO, "%s: copy_from_user fail\n", __func__); ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ i4TotalLen = priv_cmd->total_len; ++ ++ if (i4TotalLen <= 0) { ++ ret = -EINVAL; ++ DBGLOG(REQ, INFO, "%s: i4TotalLen invalid\n", __func__); ++ goto exit; ++ } ++ ++ pcCommand = priv_cmd->buf; ++ ++ DBGLOG(REQ, INFO, "%s: driver cmd \"%s\" on %s\n", __func__, pcCommand, prReq->ifr_name); ++ ++ i4BytesWritten = priv_driver_cmds(prNetDev, pcCommand, i4TotalLen); ++ ++ if (i4BytesWritten < 0) { ++ DBGLOG(REQ, INFO, "%s: command %s failed; Written is %d\n", ++ __func__, pcCommand, i4BytesWritten); ++ ret = -EFAULT; ++ } ++ ++exit: ++ kfree(priv_cmd); ++ ++ return ret; ++} ++ ++#if CFG_SUPPORT_BATCH_SCAN ++#define CMD_BATCH_SET "WLS_BATCHING SET" ++#define CMD_BATCH_GET "WLS_BATCHING GET" ++#define CMD_BATCH_STOP "WLS_BATCHING STOP" ++#endif ++ ++#if CFG_SUPPORT_GET_CH_ENV ++#define CMD_CH_ENV_GET "CH_ENV_GET" ++#endif ++ ++INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen) ++{ ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ INT_32 i4BytesWritten = 0; ++ INT_32 i4CmdFound = 0; ++ ++ if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) ++ return -1; ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); ++ ++ if (i4CmdFound == 0) { ++ i4CmdFound = 1; ++ ++ if (strnicmp(pcCommand, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) ++ i4BytesWritten = priv_driver_set_miracast(prNetDev, pcCommand, i4TotalLen); ++#if CFG_SUPPORT_BATCH_SCAN ++ else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); ++ } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { ++ /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ ++ /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ ++ /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ ++ ++ UINT_32 u4BufLen; ++ int i; ++ /* int rlen=0; */ ++ ++ for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { ++ g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ ++ kalIoctl(prGlueInfo, ++ wlanoidQueryBatchScanResult, ++ (PVOID)&g_rEventBatchResult[i], ++ sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); ++ } ++ ++#if 0 ++ DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); ++ for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { ++ prEntry = &g_rEventBatchResult.arBatchResult[i]; ++ DBGLOG(SCN, INFO, "Entry %u\n", i); ++ DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); ++ DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); ++ DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); ++ DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); ++ DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); ++ } ++#endif ++ ++ batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); ++ ++ /* Dump for debug */ ++ /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, ++ i4BytesWritten, TRUE); */ ++ ++ } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); ++ } ++#endif ++#if CFG_SUPPORT_GET_CH_ENV ++ else if (strnicmp(pcCommand, CMD_CH_ENV_GET, strlen(CMD_CH_ENV_GET)) == 0) ++ scanEnvResult(prGlueInfo, pcCommand, i4TotalLen, &i4BytesWritten); ++#endif ++ ++#if 0 ++ ++ else if (strnicmp(pcCommand, CMD_RSSI, strlen(CMD_RSSI)) == 0) { ++ /* i4BytesWritten = wl_android_get_rssi(net, command, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { ++ i4BytesWritten = priv_driver_get_linkspeed(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { ++ /* Do nothing */ ++ } else if (strnicmp(pcCommand, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { ++ /* i4BytesWritten = wl_android_set_suspendopt(net, pcCommand, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { ++ i4BytesWritten = priv_driver_set_suspend_mode(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { ++ i4BytesWritten = priv_driver_set_band(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { ++ /* i4BytesWritten = wl_android_get_band(net, pcCommand, i4TotalLen); */ ++ } else if (strnicmp(pcCommand, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { ++ i4BytesWritten = priv_driver_set_country(prNetDev, pcCommand, i4TotalLen); ++ } ++ /* Mediatek private command */ ++ else if (strnicmp(pcCommand, CMD_SET_SW_CTRL, strlen(CMD_SET_SW_CTRL)) == 0) { ++ i4BytesWritten = priv_driver_set_sw_ctrl(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_SW_CTRL, strlen(CMD_GET_SW_CTRL)) == 0) { ++ i4BytesWritten = priv_driver_get_sw_ctrl(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_CFG, strlen(CMD_SET_CFG)) == 0) { ++ i4BytesWritten = priv_driver_set_cfg(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_CFG, strlen(CMD_GET_CFG)) == 0) { ++ i4BytesWritten = priv_driver_get_cfg(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_CHIP, strlen(CMD_SET_CHIP)) == 0) { ++ i4BytesWritten = priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_CHIP, strlen(CMD_GET_CHIP)) == 0) { ++ i4BytesWritten = priv_driver_get_chip_config(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_SET_DBG_LEVEL, strlen(CMD_SET_DBG_LEVEL)) == 0) { ++ i4BytesWritten = priv_driver_set_dbg_level(prNetDev, pcCommand, i4TotalLen); ++ } else if (strnicmp(pcCommand, CMD_GET_DBG_LEVEL, strlen(CMD_GET_DBG_LEVEL)) == 0) { ++ i4BytesWritten = priv_driver_get_dbg_level(prNetDev, pcCommand, i4TotalLen); ++ } ++#if CFG_SUPPORT_BATCH_SCAN ++ else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); ++ } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { ++ /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ ++ /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ ++ /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ ++ ++ UINT_32 u4BufLen; ++ int i; ++ /* int rlen=0; */ ++ ++ for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { ++ g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ ++ kalIoctl(prGlueInfo, ++ wlanoidQueryBatchScanResult, ++ (PVOID)&g_rEventBatchResult[i], ++ sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, &u4BufLen); ++ } ++ ++#if 0 ++ DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); ++ for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { ++ prEntry = &g_rEventBatchResult.arBatchResult[i]; ++ DBGLOG(SCN, INFO, "Entry %u\n", i); ++ DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); ++ DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); ++ DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); ++ DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); ++ DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); ++ } ++#endif ++ ++ batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); ++ ++ /* Dump for debug */ ++ /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, i4BytesWritten, ++ TRUE); */ ++ ++ } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { ++ kalIoctl(prGlueInfo, ++ wlanoidSetBatchScanReq, ++ (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); ++ } ++#endif ++ ++#endif ++ ++ else ++ i4CmdFound = 0; ++ } ++ ++ /* i4CmdFound */ ++ if (i4CmdFound == 0) ++ DBGLOG(REQ, TRACE, "Unknown driver command %s - ignored\n", pcCommand); ++ ++ if (i4BytesWritten >= 0) { ++ if ((i4BytesWritten == 0) && (i4TotalLen > 0)) { ++ /* reset the command buffer */ ++ pcCommand[0] = '\0'; ++ } ++ ++ if (i4BytesWritten >= i4TotalLen) { ++ DBGLOG(REQ, INFO, ++ "%s: i4BytesWritten %d > i4TotalLen < %d\n", __func__, i4BytesWritten, i4TotalLen); ++ i4BytesWritten = i4TotalLen; ++ } else { ++ pcCommand[i4BytesWritten] = '\0'; ++ i4BytesWritten++; ++ } ++ } ++ ++ return i4BytesWritten; ++ ++} ++ ++static int compat_priv(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra, ++ int (*priv_func)(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra)) ++{ ++ struct iw_point *prIwp; ++ int ret = 0; ++#ifdef CONFIG_COMPAT ++ struct compat_iw_point *iwp_compat = NULL; ++ struct iw_point iwp; ++#endif ++ ++ if (!prIwReqData) ++ return -EINVAL; ++ ++#ifdef CONFIG_COMPAT ++ if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { ++ iwp_compat = (struct compat_iw_point *) &prIwReqData->data; ++ iwp.pointer = compat_ptr(iwp_compat->pointer); ++ iwp.length = iwp_compat->length; ++ iwp.flags = iwp_compat->flags; ++ prIwp = &iwp; ++ } else ++#endif ++ prIwp = &prIwReqData->data; ++ ++ ++ ret = priv_func(prNetDev, prIwReqInfo, (union iwreq_data *)prIwp, pcExtra); ++ ++#ifdef CONFIG_COMPAT ++ if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { ++ iwp_compat->pointer = ptr_to_compat(iwp.pointer); ++ iwp_compat->length = iwp.length; ++ iwp_compat->flags = iwp.flags; ++ } ++#endif ++ return ret; ++} ++ ++int ++priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_int); ++} ++ ++int ++priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_int); ++} ++ ++int ++priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_ints); ++} ++ ++int ++priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_ints); ++} ++ ++int ++priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_struct); ++} ++ ++int ++priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_struct); ++} ++ ++int ++priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) ++{ ++ return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_string); ++} ++ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c +new file mode 100644 +index 000000000000..c13d24906bf8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c +@@ -0,0 +1,1643 @@ ++/****************************************************************************** ++*[File] ahb.c ++*[Version] v1.0 ++*[Revision Date] 2013-01-16 ++*[Author] ++*[Description] ++* The program provides AHB HIF driver ++*[Copyright] ++* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: ahb.c ++ * ++ * 01 16 2013 vend_samp.lin ++ * Port sdio.c to ahb.c on MT6572/MT6582 ++ * 1) Initial version ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ * ++ * 02 14 2012 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * include correct header file upon setting. ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 09 20 2011 cp.wu ++ * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized ++ * 1. always show error message for SDIO bus errors. ++ * 2. reset bus error flag when re-initialization ++ * ++ * 08 17 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * add MT6628 related definitions for Linux/Android driver. ++ * ++ * 05 18 2011 cp.wu ++ * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC ++ * add device ID for MT5931. ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 18 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK. ++ * ++ * 03 15 2011 cp.wu ++ * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous ++ * memory consumption ++ * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK ++ * 2. Use common coalescing buffer for both TX/RX directions ++ * ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 11 15 2010 jeffrey.chang ++ * [WCXRP00000181] [MT6620 Wi-Fi][Driver] fix the driver message "GLUE_FLAG_HALT skip INT" during unloading ++ * Fix GLUE_FALG_HALT message which cause driver to hang ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * correct typo ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add code to run WlanIST in SDIO callback. ++ * ++ * 10 19 2010 cp.wu ++ * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration ++ * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 08 21 2010 jeffrey.chang ++ * NULL ++ * 1) add sdio two setting ++ * 2) bug fix of sdio glue ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 18 2010 cp.wu ++ * NULL ++ * #if defined(__X86__) is not working, change to use #ifdef CONFIG_X86. ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * add ENE SDIO host workaround for x86 linux platform. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Fix hotplug bug ++ * ++ * 03 28 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * clear sdio interrupt ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++/* #include */ ++#include ++/* #include */ ++#include ++/* #include */ ++/* #include */ ++/* #include */ ++ ++#include ++#ifndef CONFIG_X86 ++#include ++#endif ++ ++#ifdef CONFIG_OF ++#include ++#include ++#include ++#else ++ ++#endif ++ ++/* #include ++#include */ ++ ++#include "gl_os.h" ++ ++#if defined(MT6620) ++#include "mt6620_reg.h" ++#elif defined(MT6628) ++#include "mtreg.h" ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++#include ++#endif ++ ++/* #define MTK_DMA_BUF_MEMCPY_SUP */ /* no virt_to_phys() use */ ++/* #define HIF_DEBUG_SUP */ ++/* #define HIF_DEBUG_SUP_TX */ ++ ++#ifdef HIF_DEBUG_SUP ++#define HIF_DBG(msg) (printk msg) ++#else ++#define HIF_DBG(msg) ++#endif /* HIF_DEBUG_SUP */ ++ ++#ifdef HIF_DEBUG_SUP_TX ++#define HIF_DBG_TX(msg) (printk msg) ++#else ++#define HIF_DBG_TX(msg) ++#endif /* HIF_DEBUG_SUP */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++static UINT_32 ++HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T *GlueInfo, IN UINT_32 BurstLen, IN UINT_32 PortId, IN UINT_32 TransByte); ++ ++static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg); ++ ++static int HifAhbProbe(VOID); ++ ++static int HifAhbRemove(VOID); ++ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++static int HifAhbBusCntGet(VOID); ++ ++static int HifAhbBusCntClr(VOID); ++ ++static int HifTxCnt; ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++#if (CONF_HIF_DEV_MISC == 1) ++static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos); ++ ++static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos); ++ ++static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg); ++ ++static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp); ++ ++static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp); ++#else ++ ++static int HifAhbPltmProbe(IN struct platform_device *PDev); ++ ++static int __exit HifAhbPltmRemove(IN struct platform_device *PDev); ++ ++#ifdef CONFIG_PM ++static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message); ++ ++static int HifAhbPltmResume(IN struct platform_device *PDev); ++#endif /* CONFIG_PM */ ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ ++static VOID HifAhbLoopbkAuto(IN unsigned long arg); ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg); ++#endif /* CONF_HIF_DMA_INT */ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/* initialiation function from other module */ ++static probe_card pfWlanProbe; ++ ++/* release function from other module */ ++static remove_card pfWlanRemove; ++ ++static BOOLEAN WlanDmaFatalErr; ++ ++#if (CONF_HIF_DEV_MISC == 1) ++static const struct file_operations MtkAhbOps = { ++ .owner = THIS_MODULE, ++ .read = HifAhbMiscRead, ++ .write = HifAhbMiscWrite, ++ .unlocked_ioctl = HifAhbMiscIoctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = HifAhbMiscIoctl, ++#endif ++ .open = HifAhbMiscOpen, ++ .release = HifAhbMiscClose, ++}; ++ ++static struct miscdevice MtkAhbDriver = { ++ .minor = MISC_DYNAMIC_MINOR, /* any minor number */ ++ .name = HIF_MOD_NAME, ++ .fops = &MtkAhbOps, ++}; ++#else ++ ++#ifdef CONFIG_OF ++static const struct of_device_id apwifi_of_ids[] = { ++ {.compatible = "mediatek,wifi", .data = (void *)0}, ++ {.compatible = "mediatek,mt7623-wifi", .data = (void *)0x7623}, ++ {} ++}; ++#endif ++ ++struct platform_driver MtkPltmAhbDriver = { ++ .driver = { ++ .name = "mt-wifi", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_OF ++ .of_match_table = apwifi_of_ids, ++#endif ++ }, ++ .probe = HifAhbPltmProbe, ++#ifdef CONFIG_PM ++ .suspend = HifAhbPltmSuspend, ++ .resume = HifAhbPltmResume, ++#else ++ .suspend = NULL, ++ .resume = NULL, ++#endif /* CONFIG_PM */ ++ .remove = __exit_p(HifAhbPltmRemove), ++}; ++ ++static struct platform_device *HifAhbPDev; ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will register sdio bus to the os ++* ++* \param[in] pfProbe Function pointer to detect card ++* \param[in] pfRemove Function pointer to remove card ++* ++* \return The result of registering HIF driver (WLAN_STATUS_SUCCESS = 0) ++*/ ++/*----------------------------------------------------------------------------*/ ++WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove) ++{ ++ WLAN_STATUS Ret; ++ ++ ASSERT(pfProbe); ++ ASSERT(pfRemove); ++ ++ pfWlanProbe = pfProbe; /* wlan card initialization in other modules = wlanProbe() */ ++ pfWlanRemove = pfRemove; ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ Ret = misc_register(&MtkAhbDriver); ++ if (Ret != 0) ++ return Ret; ++ HifAhbProbe(); ++#else ++ Ret = platform_driver_register(&MtkPltmAhbDriver); ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ return Ret; ++ ++} /* end of glRegisterBus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will unregister sdio bus to the os ++* ++* \param[in] pfRemove Function pointer to remove card ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glUnregisterBus(remove_card pfRemove) ++{ ++ ASSERT(pfRemove); ++ ++ pfRemove(); ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ HifAhbRemove(); ++ ++ if ((misc_deregister(&MtkAhbDriver)) != 0) ++ ; ++#else ++ ++ platform_driver_unregister(&MtkPltmAhbDriver); ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ return; ++ ++} /* end of glUnregisterBus() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will inform us whole chip reset start event. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glResetHif(GLUE_INFO_T *GlueInfo) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ if (HifInfo->DmaOps) ++ HifInfo->DmaOps->DmaReset(HifInfo); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function stores hif related info, which is initialized before. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* \param[in] u4Cookie Pointer to UINT_32 memory base variable for _HIF_HPI ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glSetHifInfo(GLUE_INFO_T *GlueInfo, ULONG ulCookie) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ const struct of_device_id *of_id; ++ ++ /* Init HIF */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++#if (CONF_HIF_DEV_MISC == 1) ++ HifInfo->Dev = MtkAhbDriver.this_device; ++#else ++ HifInfo->Dev = &HifAhbPDev->dev; ++#endif /* CONF_HIF_DEV_MISC */ ++ SET_NETDEV_DEV(GlueInfo->prDevHandler, HifInfo->Dev); ++ ++ HifInfo->HifRegBaseAddr = ioremap(HIF_DRV_BASE, HIF_DRV_LENGTH); ++ HifInfo->McuRegBaseAddr = ioremap(CONN_MCU_DRV_BASE, CONN_MCU_REG_LENGTH); ++ DBGLOG(INIT, INFO, "[WiFi/HIF]HifInfo->HifRegBaseAddr=0x%p, HifInfo->McuRegBaseAddr=0x%p\n", ++ HifInfo->HifRegBaseAddr, HifInfo->McuRegBaseAddr); ++ ++ /* default disable DMA */ ++ HifInfo->fgDmaEnable = FALSE; ++ HifInfo->DmaRegBaseAddr = 0; ++ HifInfo->DmaOps = NULL; ++ of_id = of_match_node(apwifi_of_ids, HifAhbPDev->dev.of_node); ++ if (of_id && of_id->data) { ++ HifInfo->ChipID = (UINT_32)(unsigned long)of_id->data; ++ } else { ++ /* read chip ID */ ++ HifInfo->ChipID = HIF_REG_READL(HifInfo, MCR_WCIR) & 0xFFFF; ++ if (HifInfo->ChipID == 0x0321 || HifInfo->ChipID == 0x0335 || HifInfo->ChipID == 0x0337) ++ HifInfo->ChipID = 0x6735; /* Denali ChipID transition */ ++ if (HifInfo->ChipID == 0x0326) ++ HifInfo->ChipID = 0x6755; ++ } ++ DBGLOG(INIT, INFO, "[WiFi/HIF] ChipID = 0x%x\n", HifInfo->ChipID); ++#ifdef CONFIG_OF ++#if !defined(CONFIG_MTK_CLKMGR) ++ HifInfo->clk_wifi_dma = devm_clk_get(&HifAhbPDev->dev, "wifi-dma"); ++ if (IS_ERR(HifInfo->clk_wifi_dma)) ++ DBGLOG(INIT, ERROR, "[WiFi/HIF][CCF]cannot get HIF clk_wifi_dma clock.\n"); ++ DBGLOG(INIT, TRACE, "[WiFi/HIF][CCF]HIF clk_wifi_dma=0x%p\n", HifInfo->clk_wifi_dma); ++#endif ++#endif ++ ++ /* Init DMA */ ++ WlanDmaFatalErr = 0; /* reset error flag */ ++ ++#if (CONF_MTK_AHB_DMA == 1) ++ spin_lock_init(&HifInfo->DdmaLock); ++ ++ HifPdmaInit(HifInfo); ++#endif /* CONF_MTK_AHB_DMA */ ++ ++ /* Start loopback test after 10 seconds */ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ ++ { ++ init_timer(&(HifInfo->HifTmrLoopbkFn)); ++ HifInfo->HifTmrLoopbkFn.function = HifAhbLoopbkAuto; ++ HifInfo->HifTmrLoopbkFn.data = (unsigned long)GlueInfo; ++ ++ init_waitqueue_head(&HifInfo->HifWaitq); ++ HifInfo->HifTaskLoopbkFn = kthread_run(kalDevLoopbkThread, GlueInfo->prDevHandler, "LoopbkThread"); ++ HifInfo->HifLoopbkFlg = 0; ++ ++ /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ ++ HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(30000); ++ add_timer(&(HifInfo->HifTmrLoopbkFn)); ++ ++ HIF_DBG(("[WiFi/HIF] Start loopback test after 10 seconds (jiffies = %u)...\n", jiffies)); ++ } ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++ init_waitqueue_head(&HifInfo->HifDmaWaitq); ++ HifInfo->HifDmaWaitFlg = 0; ++#endif /* CONF_HIF_DMA_INT */ ++ ++} /* end of glSetHifInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clears hif related info. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glClearHifInfo(GLUE_INFO_T *GlueInfo) ++{ ++ iounmap(GlueInfo->rHifInfo.HifRegBaseAddr); ++ iounmap(GlueInfo->rHifInfo.DmaRegBaseAddr); ++ iounmap(GlueInfo->rHifInfo.McuRegBaseAddr); ++ return; ++ ++} /* end of glClearHifInfo() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function clears hif related info. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ DBGLOG(INIT, TRACE, "glGetChipInfo ChipID = 0x%x\n", HifInfo->ChipID); ++ switch (HifInfo->ChipID) { ++ case MTK_CHIP_ID_6571: ++ case MTK_CHIP_ID_8127: ++ case MTK_CHIP_ID_6752: ++ case MTK_CHIP_ID_8163: ++ case MTK_CHIP_ID_6735: ++ case MTK_CHIP_ID_6580: ++ case MTK_CHIP_ID_6755: ++ case MTK_CHIP_ID_7623: ++ kalSprintf(pucChipBuf, "%04x", HifInfo->ChipID); ++ break; ++ default: ++ kalMemCopy(pucChipBuf, "SOC", strlen("SOC")); ++ } ++} /* end of glGetChipInfo() */ ++ ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function to check if we need wakelock under Hotspot mode. ++* ++* \param[in] GlueInfo Pointer to glue info structure ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ if (HifInfo->ChipID == MTK_CHIP_ID_6572 || HifInfo->ChipID == MTK_CHIP_ID_6582) ++ return TRUE; ++ else ++ return FALSE; ++} /* end of glIsChipNeedWakelock() */ ++#endif /* CFG_SPM_WORKAROUND_FOR_HOTSPOT */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Initialize bus operation and hif related information, request resources. ++* ++* \param[out] pvData A pointer to HIF-specific data type buffer. ++* For eHPI, pvData is a pointer to UINT_32 type and stores a ++* mapped base address. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN glBusInit(PVOID pvData) ++{ ++ return TRUE; ++} /* end of glBusInit() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop bus operation and release resources. ++* ++* \param[in] pvData A pointer to struct net_device. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glBusRelease(PVOID pvData) ++{ ++} /* end of glBusRelease() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Setup bus interrupt operation and interrupt handler for os. ++* ++* \param[in] pvData A pointer to struct net_device. ++* \param[in] pfnIsr A pointer to interrupt handler function. ++* \param[in] pvCookie Private data for pfnIsr function. ++* ++* \retval WLAN_STATUS_SUCCESS if success ++* NEGATIVE_VALUE if fail ++*/ ++/*----------------------------------------------------------------------------*/ ++#ifdef CONFIG_OF ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++ /* unsigned int phy_base; */ ++ unsigned int irq_id = 0; ++ unsigned int irq_flags = 0; ++ ++ struct net_device *prNetDevice; ++ ++ ASSERT(pvData); ++ if (!pvData) ++ return -1; ++ prNetDevice = (struct net_device *)pvData; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); ++ if (node) { ++ irq_id = irq_of_parse_and_map(node, 0); ++ DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); ++ } else { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); ++ } else { ++ irq_flags = irq_info[2]; ++ DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); ++ } ++ ++ /* Register AHB IRQ */ ++ if (request_irq(irq_id, HifAhbISR, irq_flags, HIF_MOD_NAME, prNetDevice)) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: request irq %d fail!\n", irq_id); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) ++{ ++ struct device_node *node = NULL; ++ unsigned int irq_info[3] = { 0, 0, 0 }; ++ /* unsigned int phy_base; */ ++ unsigned int irq_id = 0; ++ unsigned int irq_flags = 0; ++ ++ struct net_device *prNetDevice; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return; ++ prNetDevice = (struct net_device *)pvData; ++ ++ node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); ++ if (node) { ++ irq_id = irq_of_parse_and_map(node, 0); ++ DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); ++ } else { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); ++ } ++ ++ /* get the interrupt line behaviour */ ++ if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { ++ DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); ++ } else { ++ irq_flags = irq_info[2]; ++ DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); ++ } ++ ++ /* Free the IRQ */ ++ free_irq(irq_id, prNetDevice); ++ return; ++ ++} ++#else ++/* the name is different in 72 and 82 */ ++#ifndef MT_WF_HIF_IRQ_ID /* for MT6572/82/92 */ ++#define MT_WF_HIF_IRQ_ID WF_HIF_IRQ_ID ++#endif /* MT_WF_HIF_IRQ_ID */ ++ ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) ++{ ++ int ret = 0; ++ struct net_device *prNetDevice; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return -1; ++ ++ prNetDevice = (struct net_device *)pvData; ++ GlueInfo = (GLUE_INFO_T *) pvCookie; ++ ASSERT(GlueInfo); ++ if (!GlueInfo) { ++ DBGLOG(INIT, ERROR, "GlueInfo == NULL!\n"); ++ return -1; ++ } ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* Register AHB IRQ */ ++ if (request_irq(MT_WF_HIF_IRQ_ID, HifAhbISR, IRQF_TRIGGER_LOW, HIF_MOD_NAME, prNetDevice)) { ++ DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_WF_HIF_IRQ_ID); ++ return -1; ++ } ++#if (CONF_HIF_DMA_INT == 1) ++ if (request_irq(MT_GDMA2_IRQ_ID, HifDmaISR, IRQF_TRIGGER_LOW, "AHB_DMA", prNetDevice)) { ++ DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_GDMA2_IRQ_ID); ++ free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); ++ return -1; ++ } ++#endif /* CONF_HIF_DMA_INT */ ++ ++ return ret; ++ ++} /* end of glBusSetIrq() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop bus interrupt operation and disable interrupt handling for os. ++* ++* \param[in] pvData A pointer to struct net_device. ++* \param[in] pvCookie Private data for pfnIsr function. ++* ++* \return (none) ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) ++{ ++ struct net_device *prNetDevice; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(pvData); ++ if (!pvData) ++ return; ++ ++ prNetDevice = (struct net_device *)pvData; ++ GlueInfo = (GLUE_INFO_T *) pvCookie; ++ ASSERT(GlueInfo); ++ if (!GlueInfo) ++ return; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* Free the IRQ */ ++ free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); ++ return; ++ ++} /* end of glBusreeIrq() */ ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read a 32-bit device register ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] RegOffset Register offset ++* \param[in] pu4Value Pointer to variable used to store read value ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegRead(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, OUT UINT_32 *pu4Value) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* sanity check and init */ ++ ASSERT(GlueInfo); ++ ASSERT(pu4Value); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* use PIO mode to read register */ ++ if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) ++ return FALSE; ++ *pu4Value = HIF_REG_READL(HifInfo, RegOffset); ++ ++ if ((RegOffset == MCR_WRDR0) || (RegOffset == MCR_WRDR1)) ++ HIF_DBG(("[WiFi/HIF] kalDevRegRead from Data Port 0 or 1\n")); ++ ++ return TRUE; ++ ++} /* end of kalDevRegRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Write a 32-bit device register ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] RegOffset Register offset ++* \param[in] RegValue RegValue to be written ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegWrite(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, IN UINT_32 RegValue) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* sanity check and init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* use PIO mode to write register */ ++ if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) ++ return FALSE; ++ HIF_REG_WRITEL(HifInfo, RegOffset, RegValue); ++ ++ if ((RegOffset == MCR_WTDR0) || (RegOffset == MCR_WTDR1)) ++ HIF_DBG(("[WiFi/HIF] kalDevRegWrite to Data Port 0 or 1\n")); ++ ++ return TRUE; ++ ++} /* end of kalDevRegWrite() */ ++ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Read device I/O port ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Port I/O port offset ++* \param[in] Size Length to be read ++* \param[out] Buf Pointer to read buffer ++* \param[in] MaxBufSize Length of the buffer valid to be accessed ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++kalDevPortRead(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, OUT PUINT_8 Buf, IN UINT_32 MaxBufSize) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4HSTCRValue = 0; ++ UINT_32 RegWHLPCR = 0; ++ ++ /* sanity check */ ++ if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { ++ DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", ++ WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); ++ return FALSE; ++ } ++ /* Init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(Buf); ++ ASSERT(Size <= MaxBufSize); ++ ++ /* Note: burst length should be equal to the one used in DMA */ ++ if (Port == MCR_WRDR0) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD0, Size); ++ else if (Port == MCR_WRDR1) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD1, Size); ++ else if (Port == MCR_WHISR) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_WHISR, Size); ++ ++ RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* Read */ ++#if (CONF_MTK_AHB_DMA == 1) ++ if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) ++ && ((Port == MCR_WRDR0) || (Port == MCR_WRDR1))) { ++ /* only for data port */ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ VOID *DmaVBuf = NULL, *DmaPBuf = NULL; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; ++ MTK_WCN_HIF_DMA_CONF DmaConf; ++ UINT_32 LoopCnt; ++ unsigned long PollTimeout; ++#if (CONF_HIF_DMA_INT == 1) ++ INT_32 RtnVal = 0; ++#endif ++ /* config DMA, Port = MCR_WRDR0 or MCR_WRDR1 */ ++ DmaConf.Count = Size; ++ DmaConf.Dir = HIF_DMA_DIR_RX; ++ DmaConf.Src = HIF_DRV_BASE + Port; /* must be physical addr */ ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ DmaConf.Dst = kalIOPhyAddrGet(Buf); /* must be physical addr */ ++ ++ /* TODO: use virt_to_phys() */ ++ if (DmaConf.Dst == NULL) { ++ HIF_DBG(("[WiFi/HIF] Use Dma Buffer to RX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); ++ ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); ++ ++ kalDmaBufGet(&DmaVBuf, &DmaPBuf); ++ DmaConf.Dst = (ULONG) DmaPBuf; ++ } ++#else ++ /* ++ http://kernelnewbies.org/KernelMemoryAllocation ++ Since the cache-coherent mapping may be expensive, also a streaming allocation exists. ++ ++ This is a buffer for one-way communication, which means coherency is limited to ++ flushing the data from the cache after a write finishes. The buffer has to be ++ pre-allocated (e.g. using kmalloc()). DMA for it is set up with dma_map_single(). ++ ++ When the DMA is finished (e.g. when the device has sent an interrupt signaling end of ++ DMA), call dma_unmap_single(). Between map and unmap, the device is in control of the ++ buffer: if you write to the device, do it before dma_map_single(), if you read from ++ it, do it after dma_unmap_single(). ++ */ ++ /* DMA_FROM_DEVICE invalidated (without writeback) the cache */ ++ /* TODO: if dst_off was not cacheline aligned */ ++ DmaConf.Dst = dma_map_single(HifInfo->Dev, Buf, Size, DMA_FROM_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ /* start to read data */ ++ AP_DMA_HIF_LOCK(HifInfo); /* lock to avoid other codes config GDMA */ ++ ++ prDmaOps->DmaClockCtrl(TRUE); ++ prDmaOps->DmaConfig(HifInfo, &DmaConf); ++ prDmaOps->DmaStart(HifInfo); ++ ++#if (CONF_HIF_DMA_INT == 1) ++ RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); ++ if (RtnVal <= 0) ++ DBGLOG(RX, ERROR, "fatal error1! reset DMA!\n"); ++ HifInfo->HifDmaWaitFlg = 0; ++#else ++ PollTimeout = jiffies + HZ * 5; ++ ++ do { ++ if (time_before(jiffies, PollTimeout)) ++ continue; ++ DBGLOG(RX, INFO, "RX DMA Timeout, HSTCR: 0x%08x, and dump WHISR EnhanceMode data\n", ++ u4HSTCRValue); ++ HifDumpEnhanceModeData(GlueInfo->prAdapter); ++ if (prDmaOps->DmaRegDump != NULL) ++ prDmaOps->DmaRegDump(HifInfo); ++ WlanDmaFatalErr = 1; ++ /* we still need complete dma progress even dma timeout */ ++ break; ++ } while (!prDmaOps->DmaPollIntr(HifInfo)); ++#endif /* CONF_HIF_DMA_INT */ ++ /* we should disable dma interrupt then clear dma interrupt, otherwise, ++ for dma timeout case, interrupt may be set after we clear it */ ++ prDmaOps->DmaStop(HifInfo); ++ prDmaOps->DmaAckIntr(HifInfo); ++ ++ LoopCnt = 0; ++ do { ++ if (LoopCnt++ > 100000) { ++ /* TODO: impossible! reset DMA */ ++ DBGLOG(RX, ERROR, "fatal error2! reset DMA!\n"); ++ break; ++ } ++ } while (prDmaOps->DmaPollStart(HifInfo) != 0); ++ ++ prDmaOps->DmaClockCtrl(FALSE); ++ ++ AP_DMA_HIF_UNLOCK(HifInfo); ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ if (DmaVBuf != NULL) ++ kalMemCopy(Buf, DmaVBuf, Size); ++#else ++ dma_unmap_single(HifInfo->Dev, DmaConf.Dst, Size, DMA_FROM_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ if (WlanDmaFatalErr) { ++ if (!fgIsResetting) ++ glDoChipReset(); ++ return FALSE; ++ } ++ HIF_DBG(("[WiFi/HIF] DMA RX OK!\n")); ++ } else ++#endif /* CONF_MTK_AHB_DMA */ ++ { ++ UINT_32 IdLoop, MaxLoop; ++ UINT_32 *LoopBuf; ++ ++ /* default PIO mode */ ++ MaxLoop = Size >> 2; ++ if (Size & 0x3) ++ MaxLoop++; ++ LoopBuf = (UINT_32 *) Buf; ++ ++ for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { ++ ++ *LoopBuf = HIF_REG_READL(HifInfo, Port); ++ LoopBuf++; ++ } ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ } ++ ++ return TRUE; ++ ++} /* end of kalDevPortRead() */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Write device I/O port ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Port I/O port offset ++* \param[in] Size Length to be write ++* \param[in] Buf Pointer to write buffer ++* \param[in] MaxBufSize Length of the buffer valid to be accessed ++* ++* \retval TRUE operation success ++* \retval FALSE operation fail ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN ++kalDevPortWrite(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, IN PUINT_8 Buf, IN UINT_32 MaxBufSize) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 u4HSTCRValue = 0; ++ UINT_32 RegWHLPCR = 0; ++ ++ /* sanity check */ ++ if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { ++ DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", ++ WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); ++ return FALSE; ++ } ++ ++ /* Init */ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(Buf); ++ ASSERT(Size <= MaxBufSize); ++ ++ HifTxCnt++; ++ ++ /* Note: burst length should be equal to the one used in DMA */ ++ if (Port == MCR_WTDR0) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD0, Size); ++ else if (Port == MCR_WTDR1) ++ u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD1, Size); ++ /* else other non-data port */ ++ ++ RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* Write */ ++#if (CONF_MTK_AHB_DMA == 1) ++ if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) && ((Port == MCR_WTDR0) || ++ (Port == MCR_WTDR1))) { ++ /* only for data port */ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ VOID *DmaVBuf = NULL, *DmaPBuf = NULL; ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; ++ MTK_WCN_HIF_DMA_CONF DmaConf; ++ UINT_32 LoopCnt; ++ unsigned long PollTimeout; ++#if (CONF_HIF_DMA_INT == 1) ++ INT_32 RtnVal = 0; ++#endif ++ ++ /* config GDMA */ ++ HIF_DBG_TX(("[WiFi/HIF/DMA] Prepare to send data...\n")); ++ DmaConf.Count = Size; ++ DmaConf.Dir = HIF_DMA_DIR_TX; ++ DmaConf.Dst = HIF_DRV_BASE + Port; /* must be physical addr */ ++ ++#ifdef MTK_DMA_BUF_MEMCPY_SUP ++ DmaConf.Src = kalIOPhyAddrGet(Buf); /* must be physical addr */ ++ ++ /* TODO: use virt_to_phys() */ ++ if (DmaConf.Src == NULL) { ++ HIF_DBG_TX(("[WiFi/HIF] Use Dma Buffer to TX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); ++ ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); ++ ++ kalDmaBufGet(&DmaVBuf, &DmaPBuf); ++ DmaConf.Src = (ULONG) DmaPBuf; ++ ++ kalMemCopy(DmaVBuf, Buf, Size); ++ } ++#else ++ ++ /* DMA_TO_DEVICE writeback the cache */ ++ DmaConf.Src = dma_map_single(HifInfo->Dev, Buf, Size, DMA_TO_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ /* start to write */ ++ AP_DMA_HIF_LOCK(HifInfo); ++ ++ prDmaOps->DmaClockCtrl(TRUE); ++ prDmaOps->DmaConfig(HifInfo, &DmaConf); ++ prDmaOps->DmaStart(HifInfo); ++ ++#if (CONF_HIF_DMA_INT == 1) ++ RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); ++ if (RtnVal <= 0) ++ DBGLOG(TX, ERROR, "fatal error1! reset DMA!\n"); ++ HifInfo->HifDmaWaitFlg = 0; ++#else ++ ++ LoopCnt = 0; ++ PollTimeout = jiffies + HZ * 5; ++ ++ do { ++ if (time_before(jiffies, PollTimeout)) ++ continue; ++ DBGLOG(TX, INFO, "TX DMA Timeout, HSTCR: 0x%08x\n", u4HSTCRValue); ++ if (prDmaOps->DmaRegDump != NULL) ++ prDmaOps->DmaRegDump(HifInfo); ++ WlanDmaFatalErr = 1; ++ /* we still need complete dma progress even dma timeout */ ++ break; ++ } while (!prDmaOps->DmaPollIntr(HifInfo)); ++#endif /* CONF_HIF_DMA_INT */ ++ /* we should disable dma interrupt then clear dma interrupt, otherwise, ++ for dma timeout case, interrupt may be set after we clear it */ ++ prDmaOps->DmaStop(HifInfo); ++ prDmaOps->DmaAckIntr(HifInfo); ++ ++ LoopCnt = 0; ++ do { ++ if (LoopCnt++ > 100000) { ++ DBGLOG(TX, ERROR, "fatal error2! reset DMA!\n"); ++ break; ++ } ++ } while (prDmaOps->DmaPollStart(HifInfo) != 0); ++ ++ prDmaOps->DmaClockCtrl(FALSE); ++ ++ AP_DMA_HIF_UNLOCK(HifInfo); ++ ++#ifndef MTK_DMA_BUF_MEMCPY_SUP ++ dma_unmap_single(HifInfo->Dev, DmaConf.Src, Size, DMA_TO_DEVICE); ++#endif /* MTK_DMA_BUF_MEMCPY_SUP */ ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ if (WlanDmaFatalErr) { ++ if (!fgIsResetting) ++ glDoChipReset(); ++ return FALSE; ++ } ++ HIF_DBG_TX(("[WiFi/HIF] DMA TX OK!\n")); ++ } else ++#endif /* CONF_MTK_AHB_DMA */ ++ { ++ UINT_32 IdLoop, MaxLoop; ++ UINT_32 *LoopBuf; ++ ++ /* PIO mode */ ++ MaxLoop = Size >> 2; ++ LoopBuf = (UINT_32 *) Buf; ++ ++ HIF_DBG_TX(("[WiFi/HIF/PIO] Prepare to send data (%d 0x%p-0x%p)...\n", ++ Size, LoopBuf, (((UINT8 *) LoopBuf) + (Size & (~0x03))))); ++ ++ if (Size & 0x3) ++ MaxLoop++; ++ ++ for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { ++ HIF_REG_WRITEL(HifInfo, Port, *LoopBuf); ++ LoopBuf++; ++ } ++ ++ if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); ++ ++ HIF_DBG_TX(("\n\n")); ++ } ++ ++ return TRUE; ++ ++} /* end of kalDevPortWrite() */ ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO interrupt callback function ++* ++* \param[in] func pointer to SDIO handle ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg) ++{ ++ struct net_device *prNetDevice = (struct net_device *)Arg; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ IsrCnt++; ++ ASSERT(prNetDevice); ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); ++ ASSERT(GlueInfo); ++ ++ if (!GlueInfo) ++ return IRQ_HANDLED; ++ ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ GlueInfo->IsrCnt++; ++ ++ if (GlueInfo->ulFlag & GLUE_FLAG_HALT) { ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ return IRQ_HANDLED; ++ } ++ ++ HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); ++ ++ /* lock 100ms to avoid suspend */ ++ kalHifAhbKalWakeLockTimeout(GlueInfo); ++ ++ /* Wake up main thread */ ++ set_bit(GLUE_FLAG_INT_BIT, &GlueInfo->ulFlag); ++ ++ /* when we got sdio interrupt, we wake up the tx servie thread */ ++ wake_up_interruptible(&GlueInfo->waitq); ++ ++ IsrPassCnt++; ++ GlueInfo->IsrPassCnt++; ++ return IRQ_HANDLED; ++ ++} ++ ++#if (CONF_HIF_DMA_INT == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO interrupt callback function ++* ++* \param[in] func pointer to SDIO handle ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++ ++static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg) ++{ ++ struct net_device *prNetDevice = (struct net_device *)Arg; ++ GLUE_INFO_T *GlueInfo; ++ GL_HIF_INFO_T *HifInfo; ++ ++ /* Init */ ++ ASSERT(prNetDevice); ++ GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); ++ ASSERT(GlueInfo); ++ ++ if (!GlueInfo) ++ return IRQ_HANDLED; ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ /* disable interrupt */ ++ HifInfo->DmaOps->DmaAckIntr(HifInfo); ++ ++ /* Wake up main thread */ ++ set_bit(1, &HifInfo->HifDmaWaitFlg); ++ ++ /* when we got sdio interrupt, we wake up the tx servie thread */ ++ wake_up_interruptible(&HifInfo->HifDmaWaitq); ++ ++ return IRQ_HANDLED; ++ ++} ++#endif /* CONF_HIF_DMA_INT */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is a SDIO probe function ++* ++* \param[in] func pointer to SDIO handle ++* \param[in] id pointer to SDIO device id table ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++#if defined(CONFIG_MTK_CLKMGR) ++#if defined(MTK_EXTERNAL_LDO) || defined(MTK_ALPS_BOX_SUPPORT) ++#include ++#endif ++#endif ++ ++static int HifAhbProbe(VOID) ++{ ++ int Ret = 0; ++ ++ DBGLOG(INIT, INFO, "HifAhbProbe()\n"); ++ ++ /* power on WiFi TX PA 3.3V and HIF GDMA clock */ ++ { ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#if defined(CONFIG_MTK_CLKMGR) ++#ifdef MTK_EXTERNAL_LDO ++ /* for 8127 tablet */ ++ mt_set_gpio_mode(GPIO51, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO51, GPIO_PULL_UP); ++#elif defined(MTK_ALPS_BOX_SUPPORT) ++ /* for 8127 box */ ++ mt_set_gpio_mode(GPIO89, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO89, GPIO_PULL_UP); ++#else ++ hwPowerOn(MT65XX_POWER_LDO_VGP4, VOL_3300, "WLAN"); ++#endif ++#endif ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++ mtk_wcn_consys_hw_wifi_paldo_ctrl(1); /* switch to HW mode */ ++#else /*for MT6572/82/92 */ ++ hwPowerOn(MT6323_POWER_LDO_VCN33_WIFI, VOL_3300, "WLAN"); ++ upmu_set_vcn33_on_ctrl_wifi(1); /* switch to HW mode */ ++#endif ++#endif ++ ++ } ++ ++#if (CONF_HIF_DEV_MISC == 1) ++ if (pfWlanProbe((PVOID) &MtkAhbDriver.this_device) != WLAN_STATUS_SUCCESS) { ++#else ++ if (pfWlanProbe((PVOID) &HifAhbPDev->dev) != WLAN_STATUS_SUCCESS) { ++#endif /* CONF_HIF_DEV_MISC */ ++ ++ pfWlanRemove(); ++ Ret = -1; ++ } ++ ++ return Ret; ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function will do module remove. ++* ++* \param[in] None ++* ++* \return The result of remove (WLAN_STATUS_SUCCESS = 0) ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbRemove(VOID) ++{ ++ DBGLOG(INIT, INFO, "HifAhbRemove()\n"); ++ ++ pfWlanRemove(); ++ ++ { ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#if defined(CONFIG_MTK_CLKMGR) ++#ifdef MTK_EXTERNAL_LDO ++ /* for 8127 tablet */ ++ mt_set_gpio_mode(GPIO51, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO51, GPIO_PULL_DOWN); ++#elif defined(MTK_ALPS_BOX_SUPPORT) ++ /* for 8127 box */ ++ mt_set_gpio_mode(GPIO89, GPIO_MODE_04); ++ mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); ++ mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); ++ mt_set_gpio_pull_select(GPIO89, GPIO_PULL_DOWN); ++#else ++ hwPowerDown(MT65XX_POWER_LDO_VGP4, "WLAN"); ++#endif ++#endif ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++ mtk_wcn_consys_hw_wifi_paldo_ctrl(0); /* switch to SW mode */ ++#else /*for MT6572/82/92 */ ++ upmu_set_vcn33_on_ctrl_wifi(0); /* switch to SW mode */ ++ hwPowerDown(MT6323_POWER_LDO_VCN33_WIFI, "WLAN"); ++#endif ++#endif ++ ++ } ++ ++ return 0; ++} ++ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function gets the TX count pass through HIF AHB bus. ++* ++* \param[in] None ++* ++* \return TX count ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbBusCntGet(VOID) ++{ ++ return HifTxCnt; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function resets the TX count pass through HIF AHB bus. ++* ++* \param[in] None ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbBusCntClr(VOID) ++{ ++ HifTxCnt = 0; ++ return 0; ++} ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function configs the DMA TX/RX settings before any real TX/RX. ++* ++* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] BurstLen 0(1DW), 1(4DW), 2(8DW), Others(Reserved) ++* \param[in] PortId 0(TXD0), 1(TXD1), 2(RXD0), 3(RXD1), 4(WHISR enhance) ++* \param[in] TransByte Should be 4-byte align. ++* ++* \return void ++*/ ++/*----------------------------------------------------------------------------*/ ++static UINT_32 HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T * GlueInfo, UINT_32 BurstLen, UINT_32 PortId, UINT_32 TransByte) ++{ ++ GL_HIF_INFO_T *HifInfo; ++ UINT_32 RegHSTCR; ++ ++ ASSERT(GlueInfo); ++ HifInfo = &GlueInfo->rHifInfo; ++ ++ RegHSTCR = HIF_REG_READL(HifInfo, MCR_WHIER); ++ ++ RegHSTCR = HIF_REG_READL(HifInfo, MCR_HSTCR); ++ RegHSTCR = ++ ((BurstLen << HSTCR_AFF_BURST_LEN_OFFSET) & HSTCR_AFF_BURST_LEN) | ++ ((PortId << HSTCR_TRANS_TARGET_OFFSET) & HSTCR_TRANS_TARGET) | ++ (((TransByte & 0x3) == 0) ? (TransByte & HSTCR_HSIF_TRANS_CNT) : ((TransByte + 4) & HSTCR_HSIF_TRANS_CNT)); ++ HIF_REG_WRITEL(HifInfo, MCR_HSTCR, RegHSTCR); ++ return RegHSTCR; ++} ++ ++VOID glSetPowerState(IN GLUE_INFO_T *GlueInfo, IN UINT_32 ePowerMode) ++{ ++ ++} ++ ++#if (CONF_HIF_DEV_MISC == 1) ++/* no use */ ++static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos) ++{ ++ return 0; ++} ++ ++static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp) ++{ ++ return 0; ++} ++ ++static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp) ++{ ++ return 0; ++} ++#else ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmProbe(IN struct platform_device *PDev) ++{ ++ HifAhbPDev = PDev; ++ ++ DBGLOG(INIT, INFO, "HifAhbPltmProbe\n"); ++ ++#if (CONF_HIF_PMIC_TEST == 1) ++ wmt_set_jtag_for_mcu(); ++ wmt_set_jtag_for_gps(); ++ ++#endif /* CONF_HIF_PMIC_TEST */ ++ ++#if (MTK_WCN_SINGLE_MODULE == 1) ++ HifAhbProbe(); /* only for test purpose without WMT module */ ++ ++#else ++ ++ /* register WiFi function to WMT */ ++ DBGLOG(INIT, INFO, "mtk_wcn_wmt_wlan_reg\n"); ++ { ++ MTK_WCN_WMT_WLAN_CB_INFO WmtCb; ++ ++ WmtCb.wlan_probe_cb = HifAhbProbe; ++ WmtCb.wlan_remove_cb = HifAhbRemove; ++ WmtCb.wlan_bus_cnt_get_cb = HifAhbBusCntGet; ++ WmtCb.wlan_bus_cnt_clr_cb = HifAhbBusCntClr; ++ mtk_wcn_wmt_wlan_reg(&WmtCb); ++ } ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int __exit HifAhbPltmRemove(IN struct platform_device *PDev) ++{ ++#if (MTK_WCN_SINGLE_MODULE == 0) ++ mtk_wcn_wmt_wlan_unreg(); ++#endif /* MTK_WCN_SINGLE_MODULE */ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* \param[in] Message ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message) ++{ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is called by OS platform device module. ++* ++* \param[in] PDev Pointer to the platform device structure. ++* ++* \return 0 ++*/ ++/*----------------------------------------------------------------------------*/ ++static int HifAhbPltmResume(IN struct platform_device *PDev) ++{ ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++#endif /* CONF_HIF_DEV_MISC */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Trigger to do HIF loopback test. ++* ++* \param[in] arg Pointer to the GLUE_INFO_T structure. ++* ++* \retval None ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifAhbLoopbkAuto(IN unsigned long arg) ++{ ++ ++ P_GLUE_INFO_T GlueInfo = (P_GLUE_INFO_T) arg; ++ GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; ++ ++ ASSERT(GlueInfo); ++ ++ HIF_DBG(("[WiFi/HIF] Trigger to do loopback test...\n")); ++ ++ set_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &HifInfo->HifLoopbkFlg); ++ wake_up_interruptible(&HifInfo->HifWaitq); ++ ++} ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo) ++{ ++ GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; ++ unsigned short j; ++ ++ for (j = 0; j < 512; j++) { ++ DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(prHifInfo, CONN_MCU_CPUPCR)); ++ if ((j + 1) % 16 == 0) ++ DBGLOG(INIT, WARN, "\n"); ++ } ++} ++ ++/* End of ahb.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c +new file mode 100644 +index 000000000000..6b719028ae93 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++*[File] mt6516-evb.c ++*[Version] v1.0 ++*[Revision Date] 2010-03-01 ++*[Author] ++*[Description] ++* dummy file for build system ++*[Copyright] ++* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: mt6516-evb.c ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * remove debug message ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** ++*/ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h +new file mode 100644 +index 000000000000..1507d5560040 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h +@@ -0,0 +1,340 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif.h" ++ \brief Functions for the driver to register bus and setup the IRQ ++ ++ Functions for the driver to register bus and setup the IRQ ++*/ ++ ++/* ++** Log: hif.h ++ * ++ * 11 01 2010 yarco.yang ++ * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform ++ * Add GPIO debug function ++ * ++ * 10 19 2010 jeffrey.chang ++ * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK ++ * HIF by default ++ * Refine linux kernel module to the license of MTK and enable MTK HIF ++ * ++ * 08 18 2010 jeffrey.chang ++ * NULL ++ * support multi-function sdio ++ * ++ * 08 17 2010 cp.wu ++ * NULL ++ * add ENE SDIO host workaround for x86 linux platform. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\4 2009-10-20 17:38:28 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\3 2009-09-28 20:19:20 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\2 2009-08-18 22:57:05 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\2 2008-09-22 23:18:17 GMT mtk01461 ++** Update driver for code review ++** Revision 1.1 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++*/ ++ ++#ifndef _HIF_H ++#define _HIF_H ++ ++#include "gl_typedef.h" ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++#define CONF_MTK_AHB_DMA 1 /* PIO mode is default mode if DMA is disabled */ ++ ++#define CONF_HIF_DEV_MISC 0 /* register as misc device */ ++#define CONF_HIF_LOOPBACK_AUTO 0 /* hif loopback test triggered by open() */ ++ /* only for development test */ ++ ++#define CONF_HIF_PMIC_TEST 0 /* test purpose: power on CONNSYS */ ++ ++#define CONF_HIF_DMA_INT 0 /* DMA interrupt mode */ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++extern phys_addr_t gConEmiPhyBase; ++extern BOOLEAN fgIsResetting; ++extern UINT_32 IsrCnt, IsrPassCnt; ++extern int kalDevLoopbkThread(IN void *data); ++ ++#ifdef CONFIG_MTK_PMIC_MT6397 ++#else ++#ifdef CONFIG_OF /*for MT6752 */ ++extern INT_32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT_32 enable); ++#else /*for MT6572/82/92 */ ++extern void upmu_set_vcn33_on_ctrl_wifi(UINT_32 val); ++#endif ++#endif ++ ++#if (CONF_HIF_DEV_MISC == 1) ++#else ++/* extern INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_en); */ ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#ifndef CONN_MCU_CONFIG_BASE ++#define CONN_MCU_CONFIG_BASE 0xF8070000 /* MT6572 */ ++#endif /* CONN_MCU_CONFIG_BASE */ ++ ++#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) ++#define CONSYS_REG_READ(addr) (*((volatile unsigned int *)(addr))) ++ ++#define CONN_MCU_DRV_BASE 0x18070000 ++#define CONN_MCU_REG_LENGTH 0x0200 ++#define CONN_MCU_CPUPCR 0x0160 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/* host interface's private data structure, which is attached to os glue ++** layer info structure. ++ */ ++typedef struct _GL_HIF_DMA_OPS_T { /* DMA Operators */ ++ VOID (*DmaConfig)(IN VOID *HifInfo, IN VOID *Conf); ++ ++ VOID (*DmaStart)(IN VOID *HifInfo); ++ ++ VOID (*DmaStop)(IN VOID *HifInfo); ++ ++ MTK_WCN_BOOL (*DmaPollStart)(IN VOID *HifInfo); ++ ++ MTK_WCN_BOOL (*DmaPollIntr)(IN VOID *HifInfo); ++ ++ VOID (*DmaAckIntr)(IN VOID *HifInfo); ++ ++ VOID (*DmaClockCtrl)(IN UINT_32 FlgIsEnabled); ++ ++ VOID (*DmaRegDump)(IN VOID *HifInfo); ++ ++ VOID (*DmaReset)(IN VOID *HifInfo); ++ ++} GL_HIF_DMA_OPS_T; ++ ++typedef struct _GL_HIF_INFO_T { ++ ++ /* General */ ++ VOID *Dev; /* struct device */ ++ ++#define MTK_CHIP_ID_6571 0x6571 ++#define MTK_CHIP_ID_6572 0x6572 ++#define MTK_CHIP_ID_6582 0x6582 ++#define MTK_CHIP_ID_8127 0x8127 ++#define MTK_CHIP_ID_6752 0x6752 ++#define MTK_CHIP_ID_8163 0x8163 ++#define MTK_CHIP_ID_6735 0x6735 ++#define MTK_CHIP_ID_6580 0x6580 ++#define MTK_CHIP_ID_6755 0x6755 ++#define MTK_CHIP_ID_7623 0x7623 ++ ++ UINT_32 ChipID; ++ ++ /* Control flag */ ++ BOOLEAN fgIntReadClear; ++ BOOLEAN fgMbxReadClear; ++ BOOLEAN fgDmaEnable; /* TRUE: DMA mode is used (default) */ ++ ++ /* HIF related */ ++ UINT_8 *HifRegBaseAddr; /* HIF register base */ ++ UINT_8 *McuRegBaseAddr; /* CONN MCU register base */ ++ ++#if (CONF_HIF_LOOPBACK_AUTO == 1) ++ struct timer_list HifTmrLoopbkFn; /* HIF loopback test trigger timer */ ++ wait_queue_head_t HifWaitq; ++ UINT_32 HifLoopbkFlg; ++ struct task_struct *HifTaskLoopbkFn; /* HIF loopback test task */ ++#endif /* CONF_HIF_LOOPBACK_AUTO */ ++ ++#if (CONF_HIF_DMA_INT == 1) ++ wait_queue_head_t HifDmaWaitq; ++ UINT_32 HifDmaWaitFlg; ++#endif /* CONF_HIF_DMA_INT */ ++ ++ /* DMA related */ ++#define AP_DMA_HIF_LOCK(_lock) /* spin_lock_bh(&(_lock)->DdmaLock) */ ++#define AP_DMA_HIF_UNLOCK(_lock) /* spin_unlock_bh(&(_lock)->DdmaLock) */ ++ spinlock_t DdmaLock; /* protect DMA access */ ++ ++ UINT_8 *DmaRegBaseAddr; /* DMA register base */ ++ GL_HIF_DMA_OPS_T *DmaOps; /* DMA Operators */ ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ struct clk *clk_wifi_dma; ++#endif ++} GL_HIF_INFO_T, *P_GL_HIF_INFO_T; ++ ++#define HIF_MOD_NAME "AHB_SLAVE_HIF" ++ ++#define HIF_DRV_BASE 0x180F0000 ++#define HIF_DRV_LENGTH 0x005c ++ ++typedef enum _MTK_WCN_HIF_BURST_LEN { ++ HIF_BURST_1DW = 0, ++ HIF_BURST_4DW, ++ HIF_BURST_8DW ++} MTK_WCN_HIF_BURST_LEN; ++ ++typedef enum _MTK_WCN_HIF_TXRX_TARGET { ++ HIF_TARGET_TXD0 = 0, ++ HIF_TARGET_TXD1, ++ HIF_TARGET_RXD0, ++ HIF_TARGET_RXD1, ++ HIF_TARGET_WHISR ++} MTK_WCN_HIF_TXRX_TARGET; ++ ++typedef enum _MTK_WCN_HIF_DMA_DIR { ++ HIF_DMA_DIR_TX = 0, ++ HIF_DMA_DIR_RX ++} MTK_WCN_HIF_DMA_DIR; ++ ++typedef struct _MTK_WCN_HIF_DMA_CONF { ++ UINT_32 Count; ++ MTK_WCN_HIF_DMA_DIR Dir; ++ UINT_32 Burst; ++ UINT_32 Wsize; ++ UINT_32 Ratio; ++ UINT_32 Connect; ++ UINT_32 Fix_en; ++ ULONG Src; ++ ULONG Dst; ++} MTK_WCN_HIF_DMA_CONF; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define MCU_REG_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->McuRegBaseAddr + _addr)) ++ ++/* PIO mode HIF register read/write */ ++#define HIF_REG_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr)) ++ ++#define HIF_REG_WRITEL(_hif, _addr, _val) \ ++ writel(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) ++ ++#define HIF_REG_WRITEB(_hif, _addr, _val) \ ++ writeb(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) ++ ++/* PIO mode DMA register read/write */ ++#define HIF_DMAR_READL(_hif, _addr) \ ++ readl((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr)) ++ ++#define HIF_DMAR_WRITEL(_hif, _addr, _val) \ ++ writel(_val, ((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr))) ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#ifndef MODULE_AHB_DMA ++VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter); ++ ++VOID HifRegDump(P_ADAPTER_T prAdapter); ++ ++BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter); ++ ++WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove); ++ ++VOID glUnregisterBus(remove_card pfRemove); ++ ++VOID glResetHif(GLUE_INFO_T *GlueInfo); ++ ++VOID glSetHifInfo(P_GLUE_INFO_T prGlueInfo, ULONG ulCookie); ++ ++VOID glClearHifInfo(P_GLUE_INFO_T prGlueInfo); ++ ++VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf); ++ ++#if CFG_SPM_WORKAROUND_FOR_HOTSPOT ++BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo); ++#endif ++ ++BOOLEAN glBusInit(PVOID pvData); ++ ++VOID glBusRelease(PVOID pData); ++ ++INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie); ++ ++VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie); ++ ++VOID glSetPowerState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 ePowerMode); ++ ++VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo); ++ ++#endif /* MODULE_AHB_DMA */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config GDMA TX/RX. ++* ++* \param[in] DmaRegBaseAddr Pointer to the IO register base. ++* \param[in] Conf Pointer to the DMA operator. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifGdmaInit(GL_HIF_INFO_T *HifInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] DmaRegBaseAddr Pointer to the IO register base. ++* \param[in] Conf Pointer to the DMA operator. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h +new file mode 100644 +index 000000000000..094c07f98eff +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h +@@ -0,0 +1,154 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif_gdma.h" ++ \brief MARCO, definition, structure for GDMA. ++ ++ MARCO, definition, structure for GDMA. ++*/ ++ ++/* ++** Log: hif_gdma.h ++ * ++ * 01 16 2013 vend_samp.lin ++ * Add AHB GDMA support ++ * 1) Initial version ++** ++*/ ++ ++#ifndef _HIF_GDMA_H ++#define _HIF_GDMA_H ++ ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _MTK_WCN_HIF_GDMA_BURST_LEN { ++ HIF_GDMA_BURST_1_8 = 0, ++ HIF_GDMA_BURST_2_8, ++ HIF_GDMA_BURST_3_8, ++ HIF_GDMA_BURST_4_8, ++ HIF_GDMA_BURST_5_8, ++ HIF_GDMA_BURST_6_8, ++ HIF_GDMA_BURST_7_8, ++ HIF_GDMA_BURST_8_8 /* same as HIF_GDMA_BURST_7_8 */ ++} MTK_WCN_HIF_GDMA_BURST_LEN; ++ ++typedef enum _MTK_WCN_HIF_GDMA_WRITE_LEN { ++ HIF_GDMA_WRITE_0 = 0, /* transaction size is 1 byte */ ++ HIF_GDMA_WRITE_1, /* transaction size is 2 byte */ ++ HIF_GDMA_WRITE_2, /* transaction size is 4 byte */ ++ HIF_GDMA_WRITE_3 /* transaction size is 1 byte */ ++} MTK_WCN_HIF_GDMA_WRITE_LEN; ++ ++typedef enum _MTK_WCN_HIF_GDMA_RATIO { ++ HIF_GDMA_RATIO_0 = 0, /* 1/2 */ ++ HIF_GDMA_RATIO_1 /* 1/1 */ ++} MTK_WCN_HIF_GDMA_RATIO; ++ ++typedef enum _MTK_WCN_HIF_GDMA_CONNECT { ++ HIF_GDMA_CONNECT_NO = 0, /* no connect */ ++ HIF_GDMA_CONNECT_SET1, /* connect set1 (req/ack) */ ++ HIF_GDMA_CONNECT_SET2, /* connect set2 (req/ack) */ ++ HIF_GDMA_CONNECT_SET3 /* connect set3 (req/ack) */ ++} MTK_WCN_HIF_GDMA_CONNECT; ++ ++/* reference to MT6572_AP_P_DMA_Spec.doc */ ++#define AP_DMA_HIF_BASE 0x11000100 ++ ++#define AP_P_DMA_G_DMA_2_INT_FLAG (0x0000) ++#define AP_P_DMA_G_DMA_2_CON (0x0018) ++#define AP_P_DMA_G_DMA_2_CONNECT (0x0034) ++#define AP_P_DMA_G_DMA_2_LEN1 (0x0024) ++#define AP_P_DMA_G_DMA_2_SRC_ADDR (0x001C) ++#define AP_P_DMA_G_DMA_2_DST_ADDR (0x0020) ++#define AP_P_DMA_G_DMA_2_INT_EN (0x0004) ++#define AP_P_DMA_G_DMA_2_EN (0x0008) ++#define AP_P_DMA_G_DMA_2_RST (0x000C) ++#define AP_P_DMA_G_DMA_2_STOP (0x0010) ++ ++#define AP_DMA_HIF_0_LENGTH 0x0038 ++ ++/* AP_DMA_HIF_0_INT_FLAG */ ++#define ADH_CR_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_INT_EN */ ++#define ADH_CR_INTEN_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_EN */ ++#define ADH_CR_EN BIT(0) ++#define ADH_CR_CONN_BUR_EN BIT(1) ++ ++/* AP_DMA_HIF_0_STOP */ ++#define ADH_CR_PAUSE BIT(1) ++#define ADH_CR_STOP BIT(0) ++ ++/* AP_P_DMA_G_DMA_2_CON */ ++#define ADH_CR_FLAG_FINISH BIT(30) ++#define ADH_CR_RSIZE BITS(28, 29) ++#define ADH_CR_RSIZE_OFFSET 28 ++#define ADH_CR_WSIZE BITS(24, 25) ++#define ADH_CR_WSIZE_OFFSET 24 ++#define ADH_CR_BURST_LEN BITS(16, 18) ++#define ADH_CR_BURST_LEN_OFFSET 16 ++#define ADH_CR_WADDR_FIX_EN BIT(3) ++#define ADH_CR_WADDR_FIX_EN_OFFSET 3 ++#define ADH_CR_RADDR_FIX_EN BIT(4) ++#define ADH_CR_RADDR_FIX_EN_OFFSET 4 ++ ++/* AP_P_DMA_G_DMA_2_CONNECT */ ++#define ADH_CR_RATIO BIT(3) ++#define ADH_CR_RATIO_OFFSET 3 ++#define ADH_CR_DIR BIT(2) ++#define ADH_CR_DIR_OFFSET 2 ++#define ADH_CR_CONNECT BITS(0, 1) ++ ++/* AP_DMA_HIF_0_LEN */ ++#define ADH_CR_LEN BITS(0, 19) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_GDMA_H */ ++ ++/* End of hif_gdma.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h +new file mode 100644 +index 000000000000..32224e8f17d8 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h +@@ -0,0 +1,141 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 ++*/ ++ ++/*! \file "hif_pdma.h" ++ \brief MARCO, definition, structure for PDMA. ++ ++ MARCO, definition, structure for PDMA. ++*/ ++ ++/* ++** Log: hif_pdma.h ++ * ++ * 01 16 2013 vend_samp.lin ++ * Add AHB PDMA support ++ * 1) Initial version ++** ++*/ ++ ++#ifndef _HIF_PDMA_H ++#define _HIF_PDMA_H ++ ++#include "mtk_porting.h" ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++typedef enum _MTK_WCN_HIF_PDMA_BURST_LEN { ++ HIF_PDMA_BURST_1_4 = 0, ++ HIF_PDMA_BURST_2_4, ++ HIF_PDMA_BURST_3_4, ++ HIF_PDMA_BURST_4_4 ++} MTK_WCN_HIF_PDMA_BURST_LEN; ++ ++/* reference to MT6572_AP_P_DMA_Spec.doc */ ++#ifdef CONFIG_OF ++/*for MT6752*/ ++#define AP_DMA_HIF_BASE 0x11000080 ++#else ++/*for MT6572/82/92*/ ++#define AP_DMA_HIF_BASE 0x11000180 ++#endif ++ ++#define AP_DMA_HIF_0_INT_FLAG (0x0000) ++#define AP_DMA_HIF_0_INT_EN (0x0004) ++#define AP_DMA_HIF_0_EN (0x0008) ++#define AP_DMA_HIF_0_RST (0x000C) ++#define AP_DMA_HIF_0_STOP (0x0010) ++#define AP_DMA_HIF_0_FLUSH (0x0014) ++#define AP_DMA_HIF_0_CON (0x0018) ++#define AP_DMA_HIF_0_SRC_ADDR (0x001C) ++#define AP_DMA_HIF_0_DST_ADDR (0x0020) ++#define AP_DMA_HIF_0_LEN (0x0024) ++#define AP_DMA_HIF_0_INT_BUF_SIZE (0x0038) ++#define AP_DMA_HIF_0_DEBUG_STATUS (0x0050) ++#define AP_DMA_HIF_0_SRC_ADDR2 (0x0054) ++#define AP_DMA_HIF_0_DST_ADDR2 (0x0058) ++ ++#define AP_DMA_HIF_0_LENGTH 0x0080 ++ ++/* AP_DMA_HIF_0_INT_FLAG */ ++#define ADH_CR_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_INT_EN */ ++#define ADH_CR_INTEN_FLAG_0 BIT(0) ++ ++/* AP_DMA_HIF_0_EN */ ++#define ADH_CR_EN BIT(0) ++ ++/* AP_DMA_HIF_0_RST */ ++#define ADH_CR_HARD_RST BIT(1) ++#define ADH_CR_WARM_RST BIT(0) ++ ++/* AP_DMA_HIF_0_STOP */ ++#define ADH_CR_PAUSE BIT(1) ++#define ADH_CR_STOP BIT(0) ++ ++/* AP_DMA_HIF_0_FLUSH */ ++#define ADH_CR_FLUSH BIT(0) ++ ++/* AP_DMA_HIF_0_CON */ ++#define ADH_CR_BURST_LEN BITS(16, 17) ++#define ADH_CR_BURST_LEN_OFFSET 16 ++#define ADH_CR_SLOW_CNT BITS(5, 14) ++#define ADH_CR_SLOW_EN BIT(2) ++#define ADH_CR_FIX_EN BIT(1) ++#define ADH_CR_FIX_EN_OFFSET 1 ++#define ADH_CR_DIR BIT(0) ++ ++/* AP_DMA_HIF_0_LEN */ ++#define ADH_CR_LEN BITS(0, 19) ++ ++/* AP_DMA_HIF_0_SRC_ADDR2 */ ++#define ADH_CR_SRC_ADDR2 BIT(0) ++/* AP_DMA_HIF_0_DST_ADDR2 */ ++#define ADH_CR_DST_ADDR2 BIT(0) ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++#endif /* _HIF_PDMA_H */ ++ ++/* End of hif_gdma.h */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h +new file mode 100644 +index 000000000000..91557137af9a +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h +@@ -0,0 +1,91 @@ ++/* porting layer */ ++/* Android */ ++ ++#ifndef _MTK_PORTING_H_ ++#define _MTK_PORTING_H_ ++ ++#include /* include stddef.h for NULL */ ++ ++#define CONF_MTK_AHB_DMA 1 ++ ++/* Type definition for signed integers */ ++/*typedef signed char INT8, *PINT8; ++typedef signed short INT16, *PINT16; ++typedef signed int INT_32, *PINT32;*/ ++ ++/* Type definition for unsigned integers */ ++/*typedef unsigned char UINT8, *PUINT8; ++typedef unsigned short UINT16, *PUINT16; ++typedef unsigned int UINT32, *PUINT32;*/ ++ ++#ifndef VOID ++/*typedef void VOID, *PVOID;*/ ++#endif ++ ++#ifndef IN ++#define IN ++#endif ++ ++#ifndef OUT ++#define OUT ++#endif ++ ++#ifndef INTOUT ++#define INOUT ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef BIT ++#define BIT(n) ((UINT_32) 1U << (n)) ++#endif /* BIT */ ++ ++#ifndef BITS ++/* bits range: for example BITS(16,23) = 0xFF0000 ++ * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 ++ * ==> (BIT(n+1)-1) = 0x00FFFFFF ++ */ ++#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) ++#endif /* BIT */ ++ ++#ifndef BOOLEAN ++#define BOOLEAN unsigned char ++#endif ++ ++typedef int MTK_WCN_BOOL; ++#ifndef MTK_WCN_BOOL_TRUE ++#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) ++#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) ++#endif ++ ++typedef int MTK_WCN_MUTEX; ++ ++typedef int MTK_WCN_TIMER; ++ ++/* system APIs */ ++/* mutex */ ++typedef MTK_WCN_MUTEX(*MUTEX_CREATE) (const char *const name); ++typedef INT_32(*MUTEX_DESTROY) (MTK_WCN_MUTEX mtx); ++typedef INT_32(*MUTEX_LOCK) (MTK_WCN_MUTEX mtx); ++typedef INT_32(*MUTEX_UNLOCK) (MTK_WCN_MUTEX mtx, unsigned long flags); ++/* debug */ ++typedef INT_32(*DBG_PRINT) (const char *str, ...); ++typedef INT_32(*DBG_ASSERT) (INT_32 expr, const char *file, INT_32 line); ++/* timer */ ++typedef void (*MTK_WCN_TIMER_CB) (void); ++typedef MTK_WCN_TIMER(*TIMER_CREATE) (const char *const name); ++typedef INT_32(*TIMER_DESTROY) (MTK_WCN_TIMER tmr); ++typedef INT_32(*TIMER_START) (MTK_WCN_TIMER tmr, UINT_32 timeout, MTK_WCN_TIMER_CB tmr_cb, void *param); ++typedef INT_32(*TIMER_STOP) (MTK_WCN_TIMER tmr); ++/* kernel lib */ ++typedef void *(*SYS_MEMCPY) (void *dest, const void *src, UINT_32 n); ++typedef void *(*SYS_MEMSET) (void *s, INT_32 c, UINT_32 n); ++typedef INT_32(*SYS_SPRINTF) (char *str, const char *format, ...); ++ ++#endif /* _MTK_PORTING_H_ */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c +new file mode 100644 +index 000000000000..94cc05ba3224 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c +@@ -0,0 +1,480 @@ ++/****************************************************************************** ++*[File] ahb_pdma.c ++*[Version] v1.0 ++*[Revision Date] 2013-03-13 ++*[Author] ++*[Description] ++* The program provides AHB PDMA driver ++*[Copyright] ++* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. ++******************************************************************************/ ++ ++/* ++** Log: ahb_pdma.c ++ * ++ * 03 13 2013 vend_samp.lin ++ * Add AHB PDMA support ++ * 1) Initial version ++** ++*/ ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#define MODULE_AHB_DMA ++ ++#include /* constant of kernel version */ ++ ++#include /* bitops.h */ ++ ++#include /* struct timer_list */ ++#include /* jiffies */ ++#include /* udelay and mdelay macro */ ++ ++#if 0 ++#if CONFIG_ANDROID ++#include ++#endif ++#endif ++ ++#include /* IRQT_FALLING */ ++ ++#include /* struct net_device, struct net_device_stats */ ++#include /* for eth_type_trans() function */ ++#include /* struct iw_statistics */ ++#include ++#include /* struct in_device */ ++ ++#include /* struct iphdr */ ++ ++#include /* for memcpy()/memset() function */ ++#include /* for offsetof() macro */ ++ ++#include /* The proc filesystem constants/structures */ ++ ++#include /* for rtnl_lock() and rtnl_unlock() */ ++#include /* kthread_should_stop(), kthread_run() */ ++#include /* for copy_from_user() */ ++#include /* for firmware download */ ++#include ++ ++#include /* for kfifo interface */ ++#include /* for cdev interface */ ++ ++#include /* for firmware download */ ++ ++#include ++ ++#include /* readw and writew */ ++ ++#include ++ ++#if defined(CONFIG_MTK_CLKMGR) ++#include ++#else ++#include ++#endif /* defined(CONFIG_MTK_CLKMGR) */ ++ ++#include "hif.h" ++#include "hif_pdma.h" ++#include "gl_os.h" ++ ++/* #include */ ++ ++/* #if (CONF_MTK_AHB_DMA == 1) */ ++ ++/* #define PDMA_DEBUG_SUP */ ++ ++#ifdef PDMA_DEBUG_SUP ++#define PDMA_DBG pr_debug ++#else ++#define PDMA_DBG(_fmt, ...) ++#endif /* PDMA_DEBUG_SUP */ ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++struct clk *g_clk_wifi_pdma; ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Conf); ++ ++static VOID HifPdmaStart(IN void *HifInfoSrc); ++ ++static VOID HifPdmaStop(IN void *HifInfoSrc); ++ ++static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc); ++ ++static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc); ++ ++static VOID HifPdmaAckIntr(IN void *HifInfoSrc); ++ ++static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled); ++ ++static VOID HifPdmaRegDump(IN void *HifInfoSrc); ++ ++static VOID HifPdmaReset(IN void *HifInfoSrc); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++GL_HIF_DMA_OPS_T HifPdmaOps = { ++ .DmaConfig = HifPdmaConfig, ++ .DmaStart = HifPdmaStart, ++ .DmaStop = HifPdmaStop, ++ .DmaPollStart = HifPdmaPollStart, ++ .DmaPollIntr = HifPdmaPollIntr, ++ .DmaAckIntr = HifPdmaAckIntr, ++ .DmaClockCtrl = HifPdmaClockCtrl, ++ .DmaRegDump = HifPdmaRegDump, ++ .DmaReset = HifPdmaReset ++}; ++ ++/******************************************************************************* ++* P U B L I C F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. ++* \param[in] Conf Pointer to the settings. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo) ++{ ++ /* IO remap PDMA register memory */ ++#ifdef AP_DMA_HIF_BASE ++#undef AP_DMA_HIF_BASE ++#define AP_DMA_HIF_BASE 0x11000180 ++#endif ++ HifInfo->DmaRegBaseAddr = ioremap(AP_DMA_HIF_BASE, AP_DMA_HIF_0_LENGTH); ++ ++ /* assign PDMA operators */ ++ HifInfo->DmaOps = &HifPdmaOps; ++ ++ /* enable PDMA mode */ ++ HifInfo->fgDmaEnable = TRUE; ++ ++ /* Set EMI protection here */ ++#if 0 ++#ifdef MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT ++ DBGLOG(INIT, INFO, "WIFI set EMI MPU for TEE project\n"); ++ emi_mpu_set_region_protection(gConEmiPhyBase, ++ gConEmiPhyBase + SZ_1M / 2, ++ 5, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); ++#else ++ DBGLOG(INIT, INFO, "WIFI set EMI MPU for non-TEE project\n"); ++ emi_mpu_set_region_protection(gConEmiPhyBase, ++ gConEmiPhyBase + SZ_1M / 2, ++ 4, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); ++#endif ++#endif ++ ++#if !defined(CONFIG_MTK_CLKMGR) ++ g_clk_wifi_pdma = HifInfo->clk_wifi_dma; ++#endif ++ ++ PDMA_DBG("PDMA> HifPdmaInit ok!\n"); ++} ++ ++/******************************************************************************* ++* P R I V A T E F U N C T I O N S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Config PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* \param[in] Param Pointer to the settings. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Param) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ MTK_WCN_HIF_DMA_CONF *Conf = (MTK_WCN_HIF_DMA_CONF *) Param; ++ UINT32 RegVal; ++ ++ /* Assign fixed value */ ++ Conf->Burst = HIF_PDMA_BURST_4_4; /* vs. HIF_BURST_4DW */ ++ Conf->Fix_en = FALSE; ++ ++ /* AP_P_DMA_G_DMA_2_CON */ ++ PDMA_DBG("PDMA> Conf->Dir = %d\n", Conf->Dir); ++ ++ /* AP_DMA_HIF_0_CON */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_CON); ++ RegVal &= ~(ADH_CR_BURST_LEN | ADH_CR_FIX_EN | ADH_CR_DIR); ++ RegVal |= (((Conf->Burst << ADH_CR_BURST_LEN_OFFSET) & ADH_CR_BURST_LEN) | ++ (Conf->Fix_en << ADH_CR_FIX_EN_OFFSET) | (Conf->Dir)); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_CON, RegVal); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_CON = 0x%08x\n", RegVal); ++ ++ /* AP_DMA_HIF_0_SRC_ADDR */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_SRC_ADDR, Conf->Src); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_SRC_ADDR = 0x%08lx\n", Conf->Src); ++ ++ /* AP_DMA_HIF_0_DST_ADDR */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_DST_ADDR, Conf->Dst); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_DST_ADDR = 0x%08lx\n", Conf->Dst); ++ ++ /* AP_DMA_HIF_0_LEN */ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_LEN, (Conf->Count & ADH_CR_LEN)); ++ PDMA_DBG("PDMA> AP_DMA_HIF_0_LEN = %u\n", (UINT_32)(Conf->Count & ADH_CR_LEN)); ++ ++} /* End of HifPdmaConfig */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Start PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaStart(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ /* Enable interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal | ADH_CR_INTEN_FLAG_0)); ++ ++ /* Start DMA */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_EN, (RegVal | ADH_CR_EN)); ++ ++ PDMA_DBG("PDMA> HifPdmaStart...\n"); ++ ++} /* End of HifPdmaStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Stop PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaStop(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++/* UINT32 pollcnt; */ ++ ++ /* Disable interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal & ~(ADH_CR_INTEN_FLAG_0))); ++ ++#if 0 /* DE says we donot need to do it */ ++ /* Stop DMA */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_STOP); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_STOP, (RegVal | ADH_CR_STOP)); ++ ++ /* Polling START bit turn to 0 */ ++ pollcnt = 0; ++ do { ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ if (pollcnt++ > 100000) ++ ; /* TODO: warm reset PDMA */ ++ } while (RegVal & ADH_CR_EN); ++#endif ++ ++} /* End of HifPdmaStop */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Enable PDMA TX/RX. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); ++ return ((RegVal & ADH_CR_EN) != 0) ? TRUE : FALSE; ++ ++} /* End of HifPdmaPollStart */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Poll PDMA TX/RX done. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); ++ return ((RegVal & ADH_CR_FLAG_0) != 0) ? TRUE : FALSE; ++ ++} /* End of HifPdmaPollIntr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Acknowledge PDMA TX/RX done. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaAckIntr(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegVal; ++ ++ /* Write 0 to clear interrupt */ ++ RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_FLAG, (RegVal & ~ADH_CR_FLAG_0)); ++ ++} /* End of HifPdmaAckIntr */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Acknowledge PDMA TX/RX done. ++* ++* \param[in] FlgIsEnabled TRUE: enable; FALSE: disable ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled) ++{ ++#if !defined(CONFIG_MTK_CLKMGR) ++ int ret = 0; ++#endif ++#if defined(CONFIG_MTK_CLKMGR) ++ if (FlgIsEnabled == TRUE) ++ enable_clock(MT_CG_INFRA_APDMA, "WLAN"); ++ else ++ disable_clock(MT_CG_INFRA_APDMA, "WLAN"); ++#else ++ if (FlgIsEnabled == TRUE) { ++ ret = clk_prepare_enable(g_clk_wifi_pdma); ++ if (ret) ++ DBGLOG(INIT, TRACE, "[CCF]clk_prepare_enable ret= %d\n", ret); ++ } else { ++ clk_disable_unprepare(g_clk_wifi_pdma); ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Dump PDMA related registers. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaRegDump(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 RegId, RegVal; ++ UINT32 RegNum = 0; ++ ++ DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE); ++ for (RegId = 0; RegId < AP_DMA_HIF_0_LENGTH; RegId += 4) { ++ RegVal = HIF_DMAR_READL(HifInfo, RegId); ++ DBGLOG(INIT, INFO, "0x%08x ", RegVal); ++ ++ if (RegNum++ >= 3) { ++ DBGLOG(INIT, INFO, "\n"); ++ DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE + RegId + 4); ++ RegNum = 0; ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Reset DMA. ++* ++* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. ++* ++* \retval NONE ++*/ ++/*----------------------------------------------------------------------------*/ ++static VOID HifPdmaReset(IN void *HifInfoSrc) ++{ ++ GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; ++ UINT32 LoopCnt; ++ ++ /* do warm reset: DMA will wait for current traction finished */ ++ DBGLOG(INIT, INFO, "\nDMA> do warm reset...\n"); ++ ++ /* normally, we need to sure that bit0 of AP_P_DMA_G_DMA_2_EN is 1 here */ ++ ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x01); ++ ++ for (LoopCnt = 0; LoopCnt < 10000; LoopCnt++) { ++ if (!HifPdmaPollStart(HifInfo)) ++ break; /* reset ok */ ++ } ++ ++ if (HifPdmaPollStart(HifInfo)) { ++ /* do hard reset because warm reset fails */ ++ DBGLOG(INIT, INFO, "\nDMA> do hard reset...\n"); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x02); ++ mdelay(1); ++ HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x00); ++ } ++} ++ ++/* #endif */ /* CONF_MTK_AHB_DMA */ ++ ++/* End of ahb_pdma.c */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h +new file mode 100644 +index 000000000000..ec9f46bdab2e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h +@@ -0,0 +1,341 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_cfg80211.h#1 ++*/ ++ ++/*! \file gl_cfg80211.h ++ \brief This file is for Portable Driver linux cfg80211 support. ++*/ ++ ++/* ++** Log: gl_cfg80211.h ++** ++** 09 03 2013 cp.wu ++** add path for reassociation ++** ++** 09 12 2012 wcpadmin ++** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages ++** . ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++*/ ++ ++#ifndef _GL_CFG80211_H ++#define _GL_CFG80211_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include "gl_os.h" ++extern void wlanHandleSystemResume(void); ++extern void wlanHandleSystemSuspend(void); ++extern void p2pHandleSystemResume(void); ++extern void p2pHandleSystemSuspend(void); ++ ++#if CFG_SUPPORT_WAPI ++extern UINT_8 keyStructBuf[1024]; /* add/remove key shared buffer */ ++#else ++extern UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ ++#endif ++ ++extern struct delayed_work sched_workq; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#if CONFIG_NL80211_TESTMODE ++#define NL80211_DRIVER_TESTMODE_VERSION 2 ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++#if CONFIG_NL80211_TESTMODE ++ ++typedef struct _NL80211_DRIVER_GET_STA_STATISTICS_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4Version; ++ UINT_32 u4Flag; ++ UINT_8 aucMacAddr[MAC_ADDR_LEN]; ++} NL80211_DRIVER_GET_STA_STATISTICS_PARAMS, *P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS; ++ ++typedef struct _NL80211_DRIVER_POORLINK_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ INT_8 cRssi; /* cRssi=0 means it is a invalid value. */ ++ UINT_8 ucLinkSpeed; /* ucLinkSpeed=0 means it is a invalid value */ ++ UINT_16 u2Reserved; ++} NL80211_DRIVER_POORLINK_PARAMS, *P_NL80211_DRIVER_POORLINK_PARAMS; ++ ++typedef enum _ENUM_TESTMODE_STA_STATISTICS_ATTR { ++ NL80211_TESTMODE_STA_STATISTICS_INVALID = 0, ++ NL80211_TESTMODE_STA_STATISTICS_VERSION, ++ NL80211_TESTMODE_STA_STATISTICS_MAC, ++ NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, ++ NL80211_TESTMODE_STA_STATISTICS_FLAG, ++ ++ NL80211_TESTMODE_STA_STATISTICS_PER, ++ NL80211_TESTMODE_STA_STATISTICS_RSSI, ++ NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, ++ NL80211_TESTMODE_STA_STATISTICS_TX_RATE, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, ++ ++ NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, ++ NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, ++ ++ NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, ++ ++ /* ++ * how many packages TX during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, ++ ++ /* ++ * how many packages this TX during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, ++ ++ /* ++ * how many packages dequeue during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, ++ ++ /* ++ * how many packages this sta dequeue during statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, ++ ++ /* ++ * how many TC[0-3] resource back from firmware during ++ * statistics interval ++ */ ++ NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, ++ NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, ++ NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, ++ ++ NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, ++ ++ NL80211_TESTMODE_STA_STATISTICS_NUM ++} ENUM_TESTMODE_STA_STATISTICS_ATTR; ++typedef struct _NL80211_DRIVER_SET_NFC_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 NFC_Enable; ++ ++} NL80211_DRIVER_SET_NFC_PARAMS, *P_NL80211_DRIVER_SET_NFC_PARAMS; ++typedef struct _NL80211_DRIVER_GET_SCANDONE_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4ScanDone; ++ ++} NL80211_DRIVER_GET_SCANDONE_PARAMS, *P_NL80211_DRIVER_GET_SCANDONE_PARAMS; ++ ++typedef enum _ENUM_TESTMODE_LINK_DETECTION_ATTR { ++ NL80211_TESTMODE_LINK_INVALID = 0, ++ NL80211_TESTMODE_LINK_TX_FAIL_CNT, ++ NL80211_TESTMODE_LINK_TX_RETRY_CNT, ++ NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, ++ NL80211_TESTMODE_LINK_ACK_FAIL_CNT, ++ NL80211_TESTMODE_LINK_FCS_ERR_CNT, ++ ++ NL80211_TESTMODE_LINK_DETECT_NUM, ++} ENUM_TESTMODE_LINK_DETECTION_ATTR; ++ ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++ ++typedef struct _NL80211_DRIVER_GET_LTE_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_32 u4Version; ++ UINT_32 u4Flag; ++ ++} NL80211_DRIVER_GET_LTE_PARAMS, *P_NL80211_DRIVER_GET_LTE_PARAMS; ++ ++/*typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR{ ++ NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, ++ NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, ++ NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, ++ ++ NL80211_TESTMODE_AVAILABLE_CHAN_NUM, ++}ENUM_TESTMODE_AVAILABLE_CHAN_ATTR;*/ ++ ++#endif ++#endif ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* cfg80211 hooks */ ++int ++mtk_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); ++ ++int ++mtk_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); ++ ++int ++mtk_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++); ++ ++int ++mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); ++ ++int ++mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast); ++ ++int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); ++ ++int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo); ++ ++int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params); ++ ++int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params); ++ ++int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params); ++//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac); ++ ++int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); ++ ++int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme); ++ ++int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code); ++ ++int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params); ++ ++int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev); ++ ++int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout); ++ ++int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); ++ ++int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); ++ ++int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev); ++ ++int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie); ++ ++int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int ++mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie); ++ ++void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, ++ IN struct wireless_dev *wdev, ++ IN u16 frame_type, IN bool reg); ++ ++int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req); ++ ++int ++mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, ++ IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request); ++ ++int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev,u64 reqid); ++ ++#if CONFIG_NL80211_TESTMODE ++#if CFG_AUTO_CHANNEL_SEL_SUPPORT ++WLAN_STATUS ++wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, ++ IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); ++ ++int ++mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++#endif ++int ++mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, ++ IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++ ++int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); ++ ++int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); ++ ++int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#if CFG_SUPPORT_WAPI ++int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++#else ++#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" ++#endif ++int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); ++int mtk_cfg80211_resume(struct wiphy *wiphy); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_CFG80211_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +new file mode 100644 +index 000000000000..1406905095e6 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +@@ -0,0 +1,1565 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_kal.h#1 ++*/ ++ ++/*! \file gl_kal.h ++ \brief Declaration of KAL functions - kal*() which is provided by GLUE Layer. ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/* ++** Log: gl_kal.h ++ * ++ * 06 13 2012 yuche.tsai ++ * NULL ++ * Update maintrunk driver. ++ * Add support for driver compose assoc request frame. ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Snc CFG80211 modification for ICS migration from branch 2.2. ++ * ++ * 02 06 2012 wh.su ++ * [WCXRP00001177] [MT6620 Wi-Fi][Driver][2.2] Adding the query channel filter for AP mode ++ * adding the channel query filter for AP mode. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 11 24 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adjust the code for Non-DBG and no XLOG. ++ * ++ * 11 22 2011 cp.wu ++ * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous ++ * approach to avoid incomplete state termination ++ * 1. change RDD related compile option brace position. ++ * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join ++ * timeout timer ticking ++ * 3. otherwise, insert AIS_REQUEST into pending request queue ++ * ++ * 11 11 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * modify the xlog related code. ++ * ++ * 11 10 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Modify the QM xlog level and remove LOG_FUNC. ++ * ++ * 11 10 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Using the new XLOG define for dum Memory. ++ * ++ * 11 08 2011 eddie.chen ++ * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) ++ * Add xlog function. ++ * ++ * 11 08 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters, eCurPsProf, for PS. ++ * ++ * 11 08 2011 cm.chang ++ * NULL ++ * Add RLM and CNM debug message for XLOG ++ * ++ * 11 07 2011 tsaiyuan.hsu ++ * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered ++ * add debug counters and periodically dump counters for debugging. ++ * ++ * 11 03 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * Add dumpMemory8 at XLOG support. ++ * ++ * 11 02 2011 wh.su ++ * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG ++ * adding the code for XLOG. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * include link.h for linux's port. ++ * ++ * 04 12 2011 cp.wu ++ * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated ++ * network type ++ * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected ++ * ++ * 04 01 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface ++ * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR ++ * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 ++ * ++ * 03 16 2011 cp.wu ++ * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage ++ * after system running for a long period ++ * 1. pre-allocate physical continuous buffer while module is being loaded ++ * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer ++ * ++ * The windows part remained the same as before, but added similar APIs to hide the difference. ++ * ++ * 03 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Add BOW table. ++ * ++ * 03 07 2011 terry.wu ++ * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message ++ * Toggle non-standard debug messages to comments. ++ * ++ * 03 06 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Sync BOW Driver to latest person development branch version.. ++ * ++ * 03 02 2011 cp.wu ++ * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after ++ * connection is built. ++ * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. ++ * ++ * 02 24 2011 cp.wu ++ * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep ++ * long enough for specified interval such as 500ms ++ * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 04 2011 cp.wu ++ * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease ++ * physically continuous memory demands ++ * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure ++ * ++ * 12 31 2010 cp.wu ++ * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system ++ * scheduling ++ * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being ++ * loaded ++ * ++ * 12 31 2010 jeffrey.chang ++ * [WCXRP00000332] [MT6620 Wi-Fi][Driver] add kal sleep function for delay which use blocking call ++ * modify the implementation of kalDelay to msleep ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 11 30 2010 yuche.tsai ++ * NULL ++ * Invitation & Provision Discovery Indication. ++ * ++ * 11 26 2010 cp.wu ++ * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field ++ * checking ++ * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used ++ * to indicate user is attached ++ * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown ++ * ++ * 11 08 2010 cp.wu ++ * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period ++ * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * add a kal function for set cipher. ++ * ++ * 10 04 2010 wh.su ++ * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P ++ * fixed compiling error while enable p2p. ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 21 2010 cp.wu ++ * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS ++ * associated ++ * Do a complete reset with STA-REC null checking for RF test re-entry ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning ++ * Eliminate Linux Compile Warning ++ * ++ * 09 10 2010 wh.su ++ * NULL ++ * fixed the compiling error at win XP. ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * modify kalSetEvent declaration ++ * ++ * 07 29 2010 cp.wu ++ * NULL ++ * simplify post-handling after TX_DONE interrupt is handled. ++ * ++ * 07 23 2010 cp.wu ++ * ++ * 1) re-enable AIS-FSM beacon timeout handling. ++ * 2) scan done API revised ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * fix kal header file ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * use different spin lock for security frame ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * add new spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add kal api for scanning done ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * modify cmd/data path for new design ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add new kal api ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * Linux port modification ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 21 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * change MAC address updating logic. ++ * ++ * 06 18 2010 cm.chang ++ * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver ++ * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf ++ * ++ * 06 11 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * 1) migrate assoc.c. ++ * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness ++ * 3) add configuration options for CNM_MEM and RSN modules ++ * 4) add data path for management frames ++ * 5) eliminate rPacketInfo of MSDU_INFO_T ++ * ++ * 06 07 2010 cp.wu ++ * [WPD00003833][MT6620 and MT5931] Driver migration ++ * gl_kal merged ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic handling framework for wireless extension ioctls. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * fill network type field while doing frame identification. ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * modify kalMemAlloc method ++ * ++ * 04 28 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change prefix for data structure used to communicate with 802.11 PAL ++ * to avoid ambiguous naming with firmware interface ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 22 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * when acquiring driver-own, wait for up to 8 seconds. ++ * ++ * 04 22 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * ++ * 1) modify rx path code for supporting Wi-Fi direct ++ * 2) modify config.h since Linux dont need to consider retaining packet ++ * ++ * 04 21 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add for private ioctl support ++ * ++ * 04 20 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL ++ * * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. ++ * ++ * 04 14 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * information buffer for query oid/ioctl is now buffered in prCmdInfo ++ * * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler ++ * * * * * * * * * * * * * * * * * * * capability ++ * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) add spinlock ++ * * * 2) add KAPI for handling association info ++ * ++ * 04 09 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * finish non-glue layer access to glue variables ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * accessing to firmware load/start address, and access to OID handling information ++ * * * * are now handled in glue layer ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * * are done in adapter layer. ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * add KAL API: kalFlushPendingTxPackets(), and take use of the API ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) for some OID, never do timeout expiration ++ * * * * 2) add 2 kal API for later integration ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download KAPI ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\41 2009-09-28 20:19:23 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\40 2009-08-18 22:57:09 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\39 2009-06-23 23:19:15 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\38 2009-02-09 14:03:17 GMT mtk01090 ++** Add KAL function kalDevSetPowerState(). It is not implemented yet. Only add an empty macro. ++** ++** \main\maintrunk.MT5921\37 2009-01-22 13:05:59 GMT mtk01088 ++** new defeine to got 1x value at packet reserved field ++** \main\maintrunk.MT5921\36 2008-12-08 16:15:02 GMT mtk01461 ++** Add kalQueryValidBufferLength() macro ++** \main\maintrunk.MT5921\35 2008-11-13 20:33:15 GMT mtk01104 ++** Remove lint warning ++** \main\maintrunk.MT5921\34 2008-10-22 11:05:52 GMT mtk01461 ++** Remove unused macro ++** \main\maintrunk.MT5921\33 2008-10-16 15:48:17 GMT mtk01461 ++** Update driver to fix lint warning ++** \main\maintrunk.MT5921\32 2008-09-02 11:50:51 GMT mtk01461 ++** SPIN_LOCK_SDIO_DDK_TX_QUE ++** \main\maintrunk.MT5921\31 2008-08-29 15:58:30 GMT mtk01088 ++** remove non-used function for code refine ++** \main\maintrunk.MT5921\30 2008-08-21 00:33:29 GMT mtk01461 ++** Update for Driver Review ++** \main\maintrunk.MT5921\29 2008-06-19 13:29:14 GMT mtk01425 ++** 1. Add declaration of SPIN_LOCK_SDIO_DDK_TX_QUE and SPIN_LOCK_SDIO_DDK_RX_QUE ++** \main\maintrunk.MT5921\28 2008-05-30 20:27:34 GMT mtk01461 ++** Rename KAL function ++** \main\maintrunk.MT5921\27 2008-05-30 14:42:05 GMT mtk01461 ++** Remove WMM Assoc Flag in KAL ++** \main\maintrunk.MT5921\26 2008-05-29 14:15:18 GMT mtk01084 ++** remove un-used function ++** \main\maintrunk.MT5921\25 2008-04-23 14:02:20 GMT mtk01084 ++** modify KAL port access function prototype ++** \main\maintrunk.MT5921\24 2008-04-17 23:06:41 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\23 2008-04-08 15:38:50 GMT mtk01084 ++** add KAL function to setting pattern search function enable/ disable ++** \main\maintrunk.MT5921\22 2008-03-26 15:34:48 GMT mtk01461 ++** Add update MAC address func ++** \main\maintrunk.MT5921\21 2008-03-18 15:56:15 GMT mtk01084 ++** update ENUM_NIC_INITIAL_PARAM_E ++** \main\maintrunk.MT5921\20 2008-03-18 11:49:28 GMT mtk01084 ++** update function for initial value access ++** \main\maintrunk.MT5921\19 2008-03-18 10:21:31 GMT mtk01088 ++** use kal update associate request at linux ++** \main\maintrunk.MT5921\18 2008-03-14 18:03:41 GMT mtk01084 ++** refine register and port access function ++** \main\maintrunk.MT5921\17 2008-03-11 14:51:02 GMT mtk01461 ++** Add copy_to(from)_user macro ++** \main\maintrunk.MT5921\16 2008-03-06 23:42:21 GMT mtk01385 ++** 1. add Query Registry Mac address function. ++** \main\maintrunk.MT5921\15 2008-02-26 09:48:04 GMT mtk01084 ++** modify KAL set network address/ checksum offload part ++** \main\maintrunk.MT5921\14 2008-01-09 17:54:58 GMT mtk01084 ++** Modify the argument of kalQueryPacketInfo ++** \main\maintrunk.MT5921\13 2007-11-29 02:05:20 GMT mtk01461 ++** Fix Windows RX multiple packet retain problem ++** \main\maintrunk.MT5921\12 2007-11-26 19:43:45 GMT mtk01461 ++** Add OS_TIMESTAMP macro ++** ++** \main\maintrunk.MT5921\11 2007-11-09 16:36:15 GMT mtk01425 ++** 1. Modify for CSUM offloading with Tx Fragment ++** \main\maintrunk.MT5921\10 2007-11-07 18:38:37 GMT mtk01461 ++** Add Tx Fragmentation Support ++** \main\maintrunk.MT5921\9 2007-11-06 19:36:50 GMT mtk01088 ++** add the WPS related code ++** \main\maintrunk.MT5921\8 2007-11-02 01:03:57 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** Revision 1.4 2007/07/05 07:25:33 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:50 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:23 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_KAL_H ++#define _GL_KAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "config.h" ++#include "gl_typedef.h" ++#include "gl_os.h" ++#include "link.h" ++#include "nic/mac.h" ++#include "nic/wlan_def.h" ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "gl_wext_priv.h" ++#include ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++#include "nic/bow.h" ++#endif ++ ++#if DBG ++extern int allocatedMemSize; ++#endif ++ ++#if CFG_SUPPORT_MET_PROFILING ++#include "linux/kallsyms.h" ++#include ++#endif ++ ++extern BOOLEAN fgIsUnderSuspend; ++extern UINT_32 TaskIsrCnt; ++extern BOOLEAN fgIsResetting; ++extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); ++extern UINT_32 u4MemAllocCnt, u4MemFreeCnt; ++ ++ ++extern struct delayed_work sched_workq; ++ ++#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT ++extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* #define USEC_PER_MSEC (1000) */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum _ENUM_SPIN_LOCK_CATEGORY_E { ++ SPIN_LOCK_FSM = 0, ++ ++ /* FIX ME */ ++ SPIN_LOCK_RX_QUE, ++ SPIN_LOCK_TX_QUE, ++ SPIN_LOCK_CMD_QUE, ++ SPIN_LOCK_TX_RESOURCE, ++ SPIN_LOCK_CMD_RESOURCE, ++ SPIN_LOCK_QM_TX_QUEUE, ++ SPIN_LOCK_CMD_PENDING, ++ SPIN_LOCK_CMD_SEQ_NUM, ++ SPIN_LOCK_TX_MSDU_INFO_LIST, ++ SPIN_LOCK_TXING_MGMT_LIST, ++ SPIN_LOCK_TX_SEQ_NUM, ++ SPIN_LOCK_TX_COUNT, ++ SPIN_LOCK_TXS_COUNT, ++ /* end */ ++ SPIN_LOCK_TX, ++ SPIN_LOCK_IO_REQ, ++ SPIN_LOCK_INT, ++ ++ SPIN_LOCK_MGT_BUF, ++ SPIN_LOCK_MSG_BUF, ++ SPIN_LOCK_STA_REC, ++ ++ SPIN_LOCK_MAILBOX, ++ SPIN_LOCK_TIMER, ++ ++ SPIN_LOCK_BOW_TABLE, ++ ++ SPIN_LOCK_EHPI_BUS, /* only for EHPI */ ++ SPIN_LOCK_NET_DEV, ++ SPIN_LOCK_NUM ++} ENUM_SPIN_LOCK_CATEGORY_E; ++ ++/* event for assoc information update */ ++typedef struct _EVENT_ASSOC_INFO { ++ UINT_8 ucAssocReq; /* 1 for assoc req, 0 for assoc rsp */ ++ UINT_8 ucReassoc; /* 0 for assoc, 1 for reassoc */ ++ UINT_16 u2Length; ++ PUINT_8 pucIe; ++} EVENT_ASSOC_INFO, *P_EVENT_ASSOC_INFO; ++ ++typedef enum _ENUM_KAL_NETWORK_TYPE_INDEX_T { ++ KAL_NETWORK_TYPE_AIS_INDEX = 0, ++#if CFG_ENABLE_WIFI_DIRECT ++ KAL_NETWORK_TYPE_P2P_INDEX, ++#endif ++#if CFG_ENABLE_BT_OVER_WIFI ++ KAL_NETWORK_TYPE_BOW_INDEX, ++#endif ++ KAL_NETWORK_TYPE_INDEX_NUM ++} ENUM_KAL_NETWORK_TYPE_INDEX_T; ++ ++typedef enum _ENUM_KAL_MEM_ALLOCATION_TYPE_E { ++ PHY_MEM_TYPE, /* physically continuous */ ++ VIR_MEM_TYPE, /* virtually continuous */ ++ MEM_TYPE_NUM ++} ENUM_KAL_MEM_ALLOCATION_TYPE; ++ ++#if CONFIG_ANDROID /* Defined in Android kernel source */ ++typedef struct wake_lock KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; ++#else ++typedef UINT_32 KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; ++#endif ++ ++#if CFG_SUPPORT_AGPS_ASSIST ++typedef enum _ENUM_MTK_AGPS_ATTR { ++ MTK_ATTR_AGPS_INVALID, ++ MTK_ATTR_AGPS_CMD, ++ MTK_ATTR_AGPS_DATA, ++ MTK_ATTR_AGPS_IFINDEX, ++ MTK_ATTR_AGPS_IFNAME, ++ MTK_ATTR_AGPS_MAX ++} ENUM_MTK_CCX_ATTR; ++ ++typedef enum _ENUM_AGPS_EVENT { ++ AGPS_EVENT_WLAN_ON, ++ AGPS_EVENT_WLAN_OFF, ++ AGPS_EVENT_WLAN_AP_LIST, ++ WIFI_EVENT_CHIP_RESET, ++} ENUM_CCX_EVENT; ++BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen); ++#endif ++ ++struct KAL_HALT_CTRL_T { ++ struct semaphore lock; ++ struct task_struct *owner; ++ BOOLEAN fgHalt; ++ BOOLEAN fgHeldByKalIoctl; ++ OS_SYSTIME u4HoldStart; ++}; ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of bit operation */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_SET_BIT(bitOffset, value) set_bit(bitOffset, &value) ++#define KAL_CLR_BIT(bitOffset, value) clear_bit(bitOffset, &value) ++#define KAL_TEST_AND_CLEAR_BIT(bitOffset, value) test_and_clear_bit(bitOffset, &value) ++#define KAL_TEST_BIT(bitOffset, value) test_bit(bitOffset, &value) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of SPIN LOCK operations for using in Driver Layer */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_SPIN_LOCK_DECLARATION() unsigned long __u4Flags ++ ++#define KAL_ACQUIRE_SPIN_LOCK(_prAdapter, _rLockCategory) \ ++ kalAcquireSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, &__u4Flags) ++ ++#define KAL_RELEASE_SPIN_LOCK(_prAdapter, _rLockCategory) \ ++ kalReleaseSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, __u4Flags) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for accessing Reserved Fields of native packet */ ++/*----------------------------------------------------------------------------*/ ++#define KAL_GET_PKT_QUEUE_ENTRY(_p) GLUE_GET_PKT_QUEUE_ENTRY(_p) ++#define KAL_GET_PKT_DESCRIPTOR(_prQueueEntry) GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) ++#define KAL_GET_PKT_TID(_p) GLUE_GET_PKT_TID(_p) ++#define KAL_GET_PKT_IS1X(_p) GLUE_GET_PKT_IS1X(_p) ++#define KAL_GET_PKT_HEADER_LEN(_p) GLUE_GET_PKT_HEADER_LEN(_p) ++#define KAL_GET_PKT_PAYLOAD_LEN(_p) GLUE_GET_PKT_PAYLOAD_LEN(_p) ++#define KAL_GET_PKT_ARRIVAL_TIME(_p) GLUE_GET_PKT_ARRIVAL_TIME(_p) ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros of wake_lock operations for using in Driver Layer */ ++/*----------------------------------------------------------------------------*/ ++#if CONFIG_ANDROID /* Defined in Android kernel source */ ++#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) \ ++ wake_lock_init(_prWakeLock, WAKE_LOCK_SUSPEND, _pcName) ++ ++#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) \ ++ wake_lock_destroy(_prWakeLock) ++ ++#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) \ ++ wake_lock(_prWakeLock) ++ ++#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) \ ++ wake_lock_timeout(_prWakeLock, _u4Timeout) ++ ++#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) \ ++ wake_unlock(_prWakeLock) ++ ++#else ++#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) ++#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) ++#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) ++#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) ++#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Cache memory allocation ++* ++* \param[in] u4Size Required memory size. ++* \param[in] eMemType Memory allocation type ++* ++* \return Pointer to allocated memory ++* or NULL ++*/ ++/*----------------------------------------------------------------------------*/ ++#if DBG ++#define kalMemAlloc(u4Size, eMemType) ({ \ ++ void *pvAddr; \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ pvAddr = kmalloc(u4Size, GFP_KERNEL); \ ++ } \ ++ else { \ ++ pvAddr = vmalloc(u4Size); \ ++ } \ ++ if (pvAddr) { \ ++ allocatedMemSize += u4Size; \ ++ DBGLOG(INIT, INFO, "%p(%u) allocated (%s:%s)\n", \ ++ pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ ++ } \ ++ pvAddr; \ ++}) ++#else ++#define kalMemAlloc(u4Size, eMemType) ({ \ ++ void *pvAddr; \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ pvAddr = kmalloc(u4Size, GFP_KERNEL); \ ++ } \ ++ else { \ ++ pvAddr = vmalloc(u4Size); \ ++ } \ ++ pvAddr; \ ++}) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Free allocated cache memory ++* ++* \param[in] pvAddr Required memory size. ++* \param[in] eMemType Memory allocation type ++* \param[in] u4Size Allocated memory size. ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#if DBG ++#define kalMemFree(pvAddr, eMemType, u4Size) \ ++{ \ ++ if (pvAddr) { \ ++ allocatedMemSize -= u4Size; \ ++ DBGLOG(INIT, INFO, "%p(%u) freed (%s:%s)\n", \ ++ pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ ++ } \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ kfree(pvAddr); \ ++ } \ ++ else { \ ++ vfree(pvAddr); \ ++ } \ ++} ++#else ++#define kalMemFree(pvAddr, eMemType, u4Size) \ ++{ \ ++ if (eMemType == PHY_MEM_TYPE) { \ ++ kfree(pvAddr); \ ++ } \ ++ else { \ ++ vfree(pvAddr); \ ++ } \ ++} ++#endif ++ ++#define kalUdelay(u4USec) udelay(u4USec) ++ ++#define kalMdelay(u4MSec) mdelay(u4MSec) ++#define kalMsleep(u4MSec) msleep(u4MSec) ++ ++/* Copy memory from user space to kernel space */ ++#define kalMemCopyFromUser(_pvTo, _pvFrom, _u4N) copy_from_user(_pvTo, _pvFrom, _u4N) ++ ++/* Copy memory from kernel space to user space */ ++#define kalMemCopyToUser(_pvTo, _pvFrom, _u4N) copy_to_user(_pvTo, _pvFrom, _u4N) ++ ++/* Copy memory block with specific size */ ++#define kalMemCopy(pvDst, pvSrc, u4Size) memcpy(pvDst, pvSrc, u4Size) ++ ++/* Set memory block with specific pattern */ ++#define kalMemSet(pvAddr, ucPattern, u4Size) memset(pvAddr, ucPattern, u4Size) ++ ++/* Compare two memory block with specific length. ++ * Return zero if they are the same. ++ */ ++#define kalMemCmp(pvAddr1, pvAddr2, u4Size) memcmp(pvAddr1, pvAddr2, u4Size) ++ ++/* Zero specific memory block */ ++#define kalMemZero(pvAddr, u4Size) memset(pvAddr, 0, u4Size) ++ ++/* string operation */ ++#define kalStrCpy(dest, src) strcpy(dest, src) ++#define kalStrnCpy(dest, src, n) strncpy(dest, src, n) ++#define kalStrCmp(ct, cs) strcmp(ct, cs) ++#define kalStrnCmp(ct, cs, n) strncmp(ct, cs, n) ++#define kalStrChr(s, c) strchr(s, c) ++#define kalStrrChr(s, c) strrchr(s, c) ++#define kalStrnChr(s, n, c) strnchr(s, n, c) ++#define kalStrLen(s) strlen(s) ++#define kalStrnLen(s, b) strnlen(s, b) ++//#define kalStrniCmp(s1, s2, n) strnicmp(s1, s2, n) ++#define kalStrniCmp(s1, s2, n) strncasecmp(s1, s2, n) ++#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n) ++/* #define kalStrtoul(cp, endp, base) simple_strtoul(cp, endp, base) ++#define kalStrtol(cp, endp, base) simple_strtol(cp, endp, base) */ ++#define kalkStrtou32(cp, base, resp) kstrtou32(cp, base, resp) ++#define kalkStrtos32(cp, base, resp) kstrtos32(cp, base, resp) ++#define kalSnprintf(buf, size, fmt, ...) snprintf(buf, size, fmt, __VA_ARGS__) ++#define kalSprintf(buf, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) ++/* remove for AOSP */ ++/* #define kalSScanf(buf, fmt, ...) sscanf(buf, fmt, __VA_ARGS__) */ ++#define kalStrStr(ct, cs) strstr(ct, cs) ++#define kalStrSep(s, ct) strsep(s, ct) ++#define kalStrCat(dest, src) strcat(dest, src) ++ ++/* defined for wince sdio driver only */ ++#if defined(_HIF_SDIO) ++#define kalDevSetPowerState(prGlueInfo, ePowerMode) glSetPowerState(prGlueInfo, ePowerMode) ++#else ++#define kalDevSetPowerState(prGlueInfo, ePowerMode) ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Notify OS with SendComplete event of the specific packet. Linux should ++* free packets here. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] status Status Code for OS upper layer ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalSendComplete(prGlueInfo, pvPacket, status) \ ++ kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to locate the starting address of incoming ethernet ++* frame for skb. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* ++* \return starting address of ethernet frame buffer. ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalQueryBufferPointer(prGlueInfo, pvPacket) \ ++ ((PUINT_8)((struct sk_buff *)pvPacket)->data) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to query the length of valid buffer which is accessible during ++* port read/write. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* ++* \return starting address of ethernet frame buffer. ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalQueryValidBufferLength(prGlueInfo, pvPacket) \ ++ ((UINT_32)((struct sk_buff *)pvPacket)->end - \ ++ (UINT_32)((struct sk_buff *)pvPacket)->data) ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief This function is used to copy the entire frame from skb to the destination ++* address in the input parameter. ++* ++* \param[in] prGlueInfo Pointer of GLUE Data Structure ++* \param[in] pvPacket Pointer of Packet Handle ++* \param[in] pucDestBuffer Destination Address ++* ++* \return - ++*/ ++/*----------------------------------------------------------------------------*/ ++#define kalCopyFrame(prGlueInfo, pvPacket, pucDestBuffer) \ ++ do {struct sk_buff *skb = (struct sk_buff *)pvPacket; \ ++ memcpy(pucDestBuffer, skb->data, skb->len); } while (0) ++ ++#define kalGetTimeTick() jiffies_to_msecs(jiffies) ++ ++#define kalPrint pr_debug ++ ++#if !DBG ++#define AIS_ERROR_LOGFUNC(_Fmt...) ++#define AIS_WARN_LOGFUNC(_Fmt...) ++#define AIS_INFO_LOGFUNC(_Fmt...) ++#define AIS_STATE_LOGFUNC(_Fmt...) ++#define AIS_EVENT_LOGFUNC(_Fmt...) ++#define AIS_TRACE_LOGFUNC(_Fmt...) ++#define AIS_LOUD_LOGFUNC(_Fmt...) ++#define AIS_TEMP_LOGFUNC(_Fmt...) ++ ++#define INTR_ERROR_LOGFUNC(_Fmt...) ++#define INTR_WARN_LOGFUNC(_Fmt...) ++#define INTR_INFO_LOGFUNC(_Fmt...) ++#define INTR_STATE_LOGFUNC(_Fmt...) ++#define INTR_EVENT_LOGFUNC(_Fmt...) ++#define INTR_TRACE_LOGFUNC(_Fmt...) ++#define INTR_LOUD_LOGFUNC(_Fmt...) ++#define INTR_TEMP_LOGFUNC(_Fmt...) ++ ++#define INIT_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define INIT_TRACE_LOGFUNC(_Fmt...) ++#define INIT_LOUD_LOGFUNC(_Fmt...) ++#define INIT_TEMP_LOGFUNC(_Fmt...) ++ ++#define AAA_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define AAA_LOUD_LOGFUNC(_Fmt...) ++#define AAA_TEMP_LOGFUNC(_Fmt...) ++ ++#define ROAMING_ERROR_LOGFUNC(_Fmt...) ++#define ROAMING_WARN_LOGFUNC(_Fmt...) ++#define ROAMING_INFO_LOGFUNC(_Fmt...) ++#define ROAMING_STATE_LOGFUNC(_Fmt...) ++#define ROAMING_EVENT_LOGFUNC(_Fmt...) ++#define ROAMING_TRACE_LOGFUNC(_Fmt...) ++#define ROAMING_LOUD_LOGFUNC(_Fmt...) ++#define ROAMING_TEMP_LOGFUNC(_Fmt...) ++ ++#define REQ_ERROR_LOGFUNC(_Fmt...) ++#define REQ_WARN_LOGFUNC(_Fmt...) ++#define REQ_INFO_LOGFUNC(_Fmt...) ++#define REQ_STATE_LOGFUNC(_Fmt...) ++#define REQ_EVENT_LOGFUNC(_Fmt...) ++#define REQ_TRACE_LOGFUNC(_Fmt...) ++#define REQ_LOUD_LOGFUNC(_Fmt...) ++#define REQ_TEMP_LOGFUNC(_Fmt...) ++ ++#define TX_ERROR_LOGFUNC(_Fmt...) ++#define TX_WARN_LOGFUNC(_Fmt...) ++#define TX_INFO_LOGFUNC(_Fmt...) ++#define TX_STATE_LOGFUNC(_Fmt...) ++#define TX_EVENT_LOGFUNC(_Fmt...) ++#define TX_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TX_LOUD_LOGFUNC(_Fmt...) ++#define TX_TEMP_LOGFUNC(_Fmt...) ++ ++#define RX_ERROR_LOGFUNC(_Fmt...) ++#define RX_WARN_LOGFUNC(_Fmt...) ++#define RX_INFO_LOGFUNC(_Fmt...) ++#define RX_STATE_LOGFUNC(_Fmt...) ++#define RX_EVENT_LOGFUNC(_Fmt...) ++#define RX_TRACE_LOGFUNC(_Fmt...) ++#define RX_LOUD_LOGFUNC(_Fmt...) ++#define RX_TEMP_LOGFUNC(_Fmt...) ++ ++#define RFTEST_ERROR_LOGFUNC(_Fmt...) ++#define RFTEST_WARN_LOGFUNC(_Fmt...) ++#define RFTEST_INFO_LOGFUNC(_Fmt...) ++#define RFTEST_STATE_LOGFUNC(_Fmt...) ++#define RFTEST_EVENT_LOGFUNC(_Fmt...) ++#define RFTEST_TRACE_LOGFUNC(_Fmt...) ++#define RFTEST_LOUD_LOGFUNC(_Fmt...) ++#define RFTEST_TEMP_LOGFUNC(_Fmt...) ++ ++#define EMU_ERROR_LOGFUNC(_Fmt...) ++#define EMU_WARN_LOGFUNC(_Fmt...) ++#define EMU_INFO_LOGFUNC(_Fmt...) ++#define EMU_STATE_LOGFUNC(_Fmt...) ++#define EMU_EVENT_LOGFUNC(_Fmt...) ++#define EMU_TRACE_LOGFUNC(_Fmt...) ++#define EMU_LOUD_LOGFUNC(_Fmt...) ++#define EMU_TEMP_LOGFUNC(_Fmt...) ++ ++#define HEM_ERROR_LOGFUNC(_Fmt...) ++#define HEM_WARN_LOGFUNC(_Fmt...) ++#define HEM_INFO_LOGFUNC(_Fmt...) ++#define HEM_STATE_LOGFUNC(_Fmt...) ++#define HEM_EVENT_LOGFUNC(_Fmt...) ++#define HEM_TRACE_LOGFUNC(_Fmt...) ++#define HEM_LOUD_LOGFUNC(_Fmt...) ++#define HEM_TEMP_LOGFUNC(_Fmt...) ++ ++#define RLM_ERROR_LOGFUNC(_Fmt...) ++#define RLM_WARN_LOGFUNC(_Fmt...) ++#define RLM_INFO_LOGFUNC(_Fmt...) ++#define RLM_STATE_LOGFUNC(_Fmt...) ++#define RLM_EVENT_LOGFUNC(_Fmt...) ++#define RLM_TRACE_LOGFUNC(_Fmt...) ++#define RLM_LOUD_LOGFUNC(_Fmt...) ++#define RLM_TEMP_LOGFUNC(_Fmt...) ++ ++#define MEM_ERROR_LOGFUNC(_Fmt...) ++#define MEM_WARN_LOGFUNC(_Fmt...) ++#define MEM_INFO_LOGFUNC(_Fmt...) ++#define MEM_STATE_LOGFUNC(_Fmt...) ++#define MEM_EVENT_LOGFUNC(_Fmt...) ++#define MEM_TRACE_LOGFUNC(_Fmt...) ++#define MEM_LOUD_LOGFUNC(_Fmt...) ++#define MEM_TEMP_LOGFUNC(_Fmt...) ++ ++#define CNM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define CNM_STATE_LOGFUNC(_Fmt...) ++#define CNM_EVENT_LOGFUNC(_Fmt...) ++#define CNM_TRACE_LOGFUNC(_Fmt...) ++#define CNM_LOUD_LOGFUNC(_Fmt...) ++#define CNM_TEMP_LOGFUNC(_Fmt...) ++ ++#define RSN_ERROR_LOGFUNC(_Fmt...) ++#define RSN_WARN_LOGFUNC(_Fmt...) ++#define RSN_INFO_LOGFUNC(_Fmt...) ++#define RSN_STATE_LOGFUNC(_Fmt...) ++#define RSN_EVENT_LOGFUNC(_Fmt...) ++#define RSN_TRACE_LOGFUNC(_Fmt...) ++#define RSN_LOUD_LOGFUNC(_Fmt...) ++#define RSN_TEMP_LOGFUNC(_Fmt...) ++ ++#define BSS_ERROR_LOGFUNC(_Fmt...) ++#define BSS_WARN_LOGFUNC(_Fmt...) ++#define BSS_INFO_LOGFUNC(_Fmt...) ++#define BSS_STATE_LOGFUNC(_Fmt...) ++#define BSS_EVENT_LOGFUNC(_Fmt...) ++#define BSS_TRACE_LOGFUNC(_Fmt...) ++#define BSS_LOUD_LOGFUNC(_Fmt...) ++#define BSS_TEMP_LOGFUNC(_Fmt...) ++ ++#define SCN_ERROR_LOGFUNC(_Fmt...) ++#define SCN_WARN_LOGFUNC(_Fmt...) ++#define SCN_INFO_LOGFUNC(_Fmt...) ++#define SCN_STATE_LOGFUNC(_Fmt...) ++#define SCN_EVENT_LOGFUNC(_Fmt...) ++#define SCN_TRACE_LOGFUNC(_Fmt...) ++#define SCN_LOUD_LOGFUNC(_Fmt...) ++#define SCN_TEMP_LOGFUNC(_Fmt...) ++ ++#define SAA_ERROR_LOGFUNC(_Fmt...) ++#define SAA_WARN_LOGFUNC(_Fmt...) ++#define SAA_INFO_LOGFUNC(_Fmt...) ++#define SAA_STATE_LOGFUNC(_Fmt...) ++#define SAA_EVENT_LOGFUNC(_Fmt...) ++#define SAA_TRACE_LOGFUNC(_Fmt...) ++#define SAA_LOUD_LOGFUNC(_Fmt...) ++#define SAA_TEMP_LOGFUNC(_Fmt...) ++ ++#define P2P_ERROR_LOGFUNC(_Fmt...) ++#define P2P_WARN_LOGFUNC(_Fmt...) ++#define P2P_INFO_LOGFUNC(_Fmt...) ++#define P2P_STATE_LOGFUNC(_Fmt...) ++#define P2P_EVENT_LOGFUNC(_Fmt...) ++#define P2P_TRACE_LOGFUNC(_Fmt...) ++#define P2P_LOUD_LOGFUNC(_Fmt...) ++#define P2P_TEMP_LOGFUNC(_Fmt...) ++ ++#define QM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_STATE_LOGFUNC(_Fmt...) ++#define QM_EVENT_LOGFUNC(_Fmt...) ++#define QM_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define QM_LOUD_LOGFUNC(_Fmt...) ++#define QM_TEMP_LOGFUNC(_Fmt...) ++ ++#define SEC_ERROR_LOGFUNC(_Fmt...) ++#define SEC_WARN_LOGFUNC(_Fmt...) ++#define SEC_INFO_LOGFUNC(_Fmt...) ++#define SEC_STATE_LOGFUNC(_Fmt...) ++#define SEC_EVENT_LOGFUNC(_Fmt...) ++#define SEC_TRACE_LOGFUNC(_Fmt...) ++#define SEC_LOUD_LOGFUNC(_Fmt...) ++#define SEC_TEMP_LOGFUNC(_Fmt...) ++ ++#define BOW_ERROR_LOGFUNC(_Fmt...) ++#define BOW_WARN_LOGFUNC(_Fmt...) ++#define BOW_INFO_LOGFUNC(_Fmt...) ++#define BOW_STATE_LOGFUNC(_Fmt...) ++#define BOW_EVENT_LOGFUNC(_Fmt...) ++#define BOW_TRACE_LOGFUNC(_Fmt...) ++#define BOW_LOUD_LOGFUNC(_Fmt...) ++#define BOW_TEMP_LOGFUNC(_Fmt...) ++ ++#define HAL_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define HAL_WARN_LOGFUNC(_Fmt...) ++#define HAL_INFO_LOGFUNC(_Fmt...) ++#define HAL_STATE_LOGFUNC(_Fmt...) ++#define HAL_EVENT_LOGFUNC(_Fmt...) ++#define HAL_TRACE_LOGFUNC(_Fmt...) ++#define HAL_LOUD_LOGFUNC(_Fmt...) ++#define HAL_TEMP_LOGFUNC(_Fmt...) ++ ++#define WAPI_ERROR_LOGFUNC(_Fmt...) ++#define WAPI_WARN_LOGFUNC(_Fmt...) ++#define WAPI_INFO_LOGFUNC(_Fmt...) ++#define WAPI_STATE_LOGFUNC(_Fmt...) ++#define WAPI_EVENT_LOGFUNC(_Fmt...) ++#define WAPI_TRACE_LOGFUNC(_Fmt...) ++#define WAPI_LOUD_LOGFUNC(_Fmt...) ++#define WAPI_TEMP_LOGFUNC(_Fmt...) ++ ++#define TDLS_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) ++#define TDLS_STATE_LOGFUNC(_Fmt...) ++#define TDLS_EVENT_LOGFUNC(_Fmt...) ++#define TDLS_TRACE_LOGFUNC(_Fmt...) ++#define TDLS_LOUD_LOGFUNC(_Fmt...) ++#define TDLS_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW1_ERROR_LOGFUNC(_Fmt...) ++#define SW1_WARN_LOGFUNC(_Fmt...) ++#define SW1_INFO_LOGFUNC(_Fmt...) ++#define SW1_STATE_LOGFUNC(_Fmt...) ++#define SW1_EVENT_LOGFUNC(_Fmt...) ++#define SW1_TRACE_LOGFUNC(_Fmt...) ++#define SW1_LOUD_LOGFUNC(_Fmt...) ++#define SW1_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW2_ERROR_LOGFUNC(_Fmt...) ++#define SW2_WARN_LOGFUNC(_Fmt...) ++#define SW2_INFO_LOGFUNC(_Fmt...) ++#define SW2_STATE_LOGFUNC(_Fmt...) ++#define SW2_EVENT_LOGFUNC(_Fmt...) ++#define SW2_TRACE_LOGFUNC(_Fmt...) ++#define SW2_LOUD_LOGFUNC(_Fmt...) ++#define SW2_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW3_ERROR_LOGFUNC(_Fmt...) ++#define SW3_WARN_LOGFUNC(_Fmt...) ++#define SW3_INFO_LOGFUNC(_Fmt...) ++#define SW3_STATE_LOGFUNC(_Fmt...) ++#define SW3_EVENT_LOGFUNC(_Fmt...) ++#define SW3_TRACE_LOGFUNC(_Fmt...) ++#define SW3_LOUD_LOGFUNC(_Fmt...) ++#define SW3_TEMP_LOGFUNC(_Fmt...) ++ ++#define SW4_ERROR_LOGFUNC(_Fmt...) ++#define SW4_WARN_LOGFUNC(_Fmt...) ++#define SW4_INFO_LOGFUNC(_Fmt...) ++#define SW4_STATE_LOGFUNC(_Fmt...) ++#define SW4_EVENT_LOGFUNC(_Fmt...) ++#define SW4_TRACE_LOGFUNC(_Fmt...) ++#define SW4_LOUD_LOGFUNC(_Fmt...) ++#define SW4_TEMP_LOGFUNC(_Fmt...) ++#endif ++ ++#define kalBreakPoint() \ ++do { \ ++ BUG(); \ ++ panic("Oops"); \ ++} while (0) ++ ++#if CFG_ENABLE_AEE_MSG ++#define kalSendAeeException aee_kernel_exception ++#define kalSendAeeWarning aee_kernel_warning ++#define kalSendAeeReminding aee_kernel_reminding ++#else ++#define kalSendAeeException(_module, _desc, ...) ++#define kalSendAeeWarning(_module, _desc, ...) ++#define kalSendAeeReminding(_module, _desc, ...) ++#endif ++ ++#define PRINTF_ARG(...) __VA_ARGS__ ++#define SPRINTF(buf, arg) {buf += sprintf((char *)(buf), PRINTF_ARG arg); } ++ ++#define USEC_TO_SYSTIME(_usec) ((_usec) / USEC_PER_MSEC) ++#define MSEC_TO_SYSTIME(_msec) (_msec) ++ ++#define MSEC_TO_JIFFIES(_msec) msecs_to_jiffies(_msec) ++ ++#define KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE 3000 /* 3s */ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Routines in gl_kal.c */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags); ++ ++VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags); ++ ++VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr); ++ ++VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); ++ ++PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData); ++ ++VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler); ++ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN OS_SYSTIME rInterval); ++ ++WLAN_STATUS ++kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, ++ /* IN PBOOLEAN pfgIsRetain, */ ++ IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aeCSUM[] ++); ++ ++WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum); ++ ++VOID ++kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen); ++ ++VOID ++kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen); ++ ++#if CFG_TX_FRAGMENT ++BOOLEAN ++kalQueryTxPacketHeader(IN P_GLUE_INFO_T prGlueInfo, ++ IN PVOID pvPacket, OUT PUINT_16 pu2EtherTypeLen, OUT PUINT_8 pucEthDestAddr); ++#endif /* CFG_TX_FRAGMENT */ ++ ++VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag); ++ ++VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T eCSUM[] ++); ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr); ++ ++VOID ++kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs); ++ ++VOID ++kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum); ++ ++VOID ++kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); ++ ++VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); ++ ++/*----------------------------------------------------------------------------*/ ++/* Routines in interface - ehpi/sdio.c */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalDevRegRead(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, OUT PUINT_32 pu4Value); ++ ++BOOLEAN kalDevRegWrite(P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, IN UINT_32 u4Value); ++ ++BOOLEAN ++kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_16 u2Port, IN UINT_32 u2Len, OUT PUINT_8 pucBuf, IN UINT_32 u2ValidOutBufSize); ++ ++BOOLEAN ++kalDevPortWrite(P_GLUE_INFO_T prGlueInfo, ++ IN UINT_16 u2Port, IN UINT_32 u2Len, IN PUINT_8 pucBuf, IN UINT_32 u2ValidInBufSize); ++ ++BOOLEAN kalDevWriteWithSdioCmd52(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Addr, IN UINT_8 ucData); ++ ++void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo); ++ ++#if CFG_SUPPORT_EXT_CONFIG ++UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++BOOLEAN ++kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_NATIVE_PACKET prPacket, ++ OUT PUINT_8 pucPriorityParam, ++ OUT PUINT_32 pu4PacketLen, ++ OUT PUINT_8 pucEthDestAddr, ++ OUT PBOOLEAN pfgIs1X, ++ OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, ++ OUT PVOID prGenUse); ++ ++VOID ++kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, ++ IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus); ++ ++WLAN_STATUS ++kalIoctl(IN P_GLUE_INFO_T prGlueInfo, ++ IN PFN_OID_HANDLER_FUNC pfnOidHandler, ++ IN PVOID pvInfoBuf, ++ IN UINT_32 u4InfoBufLen, ++ IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen); ++ ++VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo); ++ ++#if CFG_ENABLE_FW_DOWNLOAD ++ ++PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength); ++ ++VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf); ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* Card Removal Check */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* TX */ ++/*----------------------------------------------------------------------------*/ ++VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Media State Indication */ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate); ++ ++/*----------------------------------------------------------------------------*/ ++/* OID handling */ ++/*----------------------------------------------------------------------------*/ ++VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry); ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++/*----------------------------------------------------------------------------*/ ++/* Bluetooth over Wi-Fi handling */ ++/*----------------------------------------------------------------------------*/ ++VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent); ++ ++ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, PARAM_MAC_ADDRESS rPeerAddr); ++ ++ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr); ++ ++UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++/*----------------------------------------------------------------------------*/ ++/* Bluetooth over Wi-Fi Net Device Init/Uninit */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName); ++ ++BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo); ++#endif /* CFG_BOW_SEPARATE_DATA_PATH */ ++#endif /* CFG_ENABLE_BT_OVER_WIFI */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Firmware Download Handling */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* Security Frame Clearance */ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Management Frame Clearance */ ++/*----------------------------------------------------------------------------*/ ++VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); ++ ++UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval); ++ ++BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status); ++ ++UINT_32 kalRandomNumber(VOID); ++ ++VOID kalTimeoutHandler(struct timer_list *t); ++ ++VOID kalSetEvent(P_GLUE_INFO_T pr); ++ ++/*----------------------------------------------------------------------------*/ ++/* NVRAM/Registry Service */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo); ++ ++P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, ++ OUT PUINT_16 pu2Part1CfgOwnVersion, ++ OUT PUINT_16 pu2Part1CfgPeerVersion, ++ OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion); ++ ++BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data); ++ ++BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, IN UINT_16 u2Data); ++ ++/*----------------------------------------------------------------------------*/ ++/* WSC Connection */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo); ++ ++/*----------------------------------------------------------------------------*/ ++/* RSSI Updating */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); ++ ++/*----------------------------------------------------------------------------*/ ++/* I/O Buffer Pre-allocation */ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalInitIOBuffer(VOID); ++ ++VOID kalUninitIOBuffer(VOID); ++ ++PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize); ++ ++VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size); ++ ++VOID ++kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); ++ ++BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo); ++ ++ULONG kalIOPhyAddrGet(IN ULONG VirtAddr); ++ ++VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr); ++ ++#if CFG_SUPPORT_802_11W ++/*----------------------------------------------------------------------------*/ ++/* 802.11W */ ++/*----------------------------------------------------------------------------*/ ++UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size); ++ ++/*----------------------------------------------------------------------------*/ ++/* NL80211 */ ++/*----------------------------------------------------------------------------*/ ++VOID ++kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, IN UINT_32 u4BufLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength); ++ ++/*----------------------------------------------------------------------------*/ ++/* PNO Support */ ++/*----------------------------------------------------------------------------*/ ++VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++int tx_thread(void *data); ++ ++VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo); ++VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb); ++VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); ++int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo); ++int kalMetRemoveProcfs(void); ++ ++UINT_64 kalGetBootTime(void); ++ ++INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize); ++#if CFG_SUPPORT_WAKEUP_REASON_DEBUG ++BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter); ++#endif ++INT_32 kalHaltLock(UINT_32 waitMs); ++INT_32 kalHaltTryLock(VOID); ++VOID kalHaltUnlock(VOID); ++VOID kalSetHalted(BOOLEAN fgHalt); ++BOOLEAN kalIsHalted(VOID); ++ ++INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo); ++INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo); ++VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam); ++INT32 kalBoostCpu(UINT_32 core_num); ++ ++#endif /* _GL_KAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h +new file mode 100644 +index 000000000000..a4321e7f9a11 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h +@@ -0,0 +1,1270 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_os.h#2 ++*/ ++ ++/*! \file gl_os.h ++ \brief List the external reference to OS for GLUE Layer. ++ ++ In this file we define the data structure - GLUE_INFO_T to store those objects ++ we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the ++ external reference (header file, extern func() ..) to OS for GLUE Layer should ++ also list down here. ++*/ ++ ++/* ++** Log: gl_os.h ++** ++** 08 20 2012 yuche.tsai ++** NULL ++** Fix possible KE issue. ++** ++** 08 20 2012 yuche.tsai ++** [ALPS00339327] [Rose][6575JB][BSP Package][Free Test][KE][WIFI]There is no response when you tap the turn off/on ++** button,wait a minutes, the device will reboot automatically and "KE" will pop up. ++** Fix possible KE when netlink operate mgmt frame register. ++ * ++ * 04 12 2012 terry.wu ++ * NULL ++ * Add AEE message support ++ * 1) Show AEE warning(red screen) if SDIO access error occurs ++ ++ * ++ * 03 02 2012 terry.wu ++ * NULL ++ * Enable CFG80211 Support. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 12 13 2011 cm.chang ++ * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer ++ * Add wake lock if timer timeout value is smaller than 5 seconds ++ * ++ * 11 18 2011 yuche.tsai ++ * NULL ++ * CONFIG P2P support RSSI query, default turned off. ++ * ++ * 11 16 2011 yuche.tsai ++ * NULL ++ * Avoid using work thread. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 29 2011 terry.wu ++ * NULL ++ * Show DRV_NAME by chip id. ++ * ++ * 04 18 2011 terry.wu ++ * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED ++ * Remove flag CFG_WIFI_DIRECT_MOVED. ++ * ++ * 03 29 2011 cp.wu ++ * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for ++ * RESET_START and RESET_END events ++ * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * support concurrent network ++ * ++ * 03 03 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * modify net device relative functions to support multiple H/W queues ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 02 21 2011 cp.wu ++ * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain ++ * simplify logic for checking NVRAM existence only once. ++ * ++ * 02 16 2011 jeffrey.chang ++ * NULL ++ * Add query ipv4 and ipv6 address during early suspend and late resume ++ * ++ * 02 10 2011 chinghwa.yu ++ * [WCXRP00000065] Update BoW design and settings ++ * Fix kernel API change issue. ++ * Before ALPS 2.2 (2.2 included), kfifo_alloc() is ++ * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); ++ * After ALPS 2.3, kfifo_alloc() is changed to ++ * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); ++ * ++ * 02 09 2011 wh.su ++ * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align ++ * pointer issue ++ * always pre-allio WAPI related structure for align p2p module. ++ * ++ * 02 09 2011 terry.wu ++ * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules ++ * Halt p2p module init and exit until TxThread finished p2p register and unregister. ++ * ++ * 02 01 2011 cm.chang ++ * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode ++ * . ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP ++ * implementation of separate BT_OVER_WIFI data path. ++ * ++ * 01 12 2011 cp.wu ++ * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation ++ * needs such information ++ * fill mac header length information for 802.1x frames. ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish ++ * successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. ++ * ++ * 01 10 2011 cp.wu ++ * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues ++ * due to multiple access ++ * use mutex to protect kalIoctl() for thread safe. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 28 2010 wh.su ++ * NULL ++ * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 09 13 2010 cp.wu ++ * NULL ++ * add waitq for poll() and read(). ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 09 06 2010 wh.su ++ * NULL ++ * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. ++ * ++ * 09 03 2010 kevin.huang ++ * NULL ++ * Refine #include sequence and solve recursive/nested #include issue ++ * ++ * 09 01 2010 wh.su ++ * NULL ++ * adding the wapi support for integration test. ++ * ++ * 08 31 2010 kevin.huang ++ * NULL ++ * Use LINK LIST operation to process SCAN result ++ * ++ * 08 23 2010 cp.wu ++ * NULL ++ * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * P2P packets are now marked when being queued into driver, and identified later without checking MAC address ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 11 2010 cp.wu ++ * NULL ++ * 1) do not use in-stack variable for beacon updating. (for MAUI porting) ++ * 2) extending scanning result to 64 instead of 48 ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 08 02 2010 jeffrey.chang ++ * NULL ++ * 1) modify tx service thread to avoid busy looping ++ * 2) add spin lock declartion for linux build ++ * ++ * 07 23 2010 jeffrey.chang ++ * ++ * add new KAL api ++ * ++ * 07 22 2010 jeffrey.chang ++ * ++ * modify tx thread and remove some spinlock ++ * ++ * 07 19 2010 jeffrey.chang ++ * ++ * add security frame pending count ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++ * 05 10 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement basic wi-fi direct framework ++ * ++ * 05 07 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * prevent supplicant accessing driver during resume ++ * ++ * 05 07 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add basic framework for implementating P2P driver hook. ++ * ++ * 05 05 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * change variable names for multiple physical link to match with coding convention ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame ++ * ++ * 04 27 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add multiple physical link support ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * 1) fix firmware download bug ++ * 2) remove query statistics for acelerating firmware download ++ * ++ * 04 27 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * follow Linux's firmware framework, and remove unused kal API ++ * ++ * 04 23 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * surpress compiler warning ++ * ++ * 04 19 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * supporting power management ++ * ++ * 04 14 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * pvInformationBuffer and u4InformationBufferLength are no longer in glue ++ * ++ * 04 13 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add framework for BT-over-Wi-Fi support. ++ * * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple ++ * * * * * * * * * * * * * * * * * * * * handler capability ++ * * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically ++ * * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other ++ * * * * * * * * * * * * * * * * * * * * purpose ++ * ++ * 04 07 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * rWlanInfo should be placed at adapter rather than glue due to most operations ++ * * * * * * * * * * are done in adapter layer. ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * Tag the packet for QoS on Tx path ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * (1)deliver the kalOidComplete status to upper layer ++ * * (2) fix spin lock ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * add timeout check in the kalOidComplete ++ * ++ * 04 06 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * improve none-glue code portability ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved ++ * ++ * 04 06 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer ++ * ++ * 03 30 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * emulate NDIS Pending OID facility ++ * ++ * 03 26 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * [WPD00003826] Initial import for Linux port ++ * adding firmware download related data type ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00001943]Create WiFi test driver framework on WinXP ++ * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. ++ * * * * the frequency is used for adhoc connection only ++ * * * * 2) update with SD1 v0.9 CMD/EVENT documentation ++ * ++ * 03 25 2010 cp.wu ++ * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support ++ * add Bluetooth-over-Wifi frame header check ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\30 2009-10-20 17:38:31 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\29 2009-10-08 10:33:33 GMT mtk01090 ++** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input ++** parameters and pointers. ++** \main\maintrunk.MT5921\28 2009-09-28 20:19:26 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\27 2009-08-18 22:57:12 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\26 2009-07-06 21:42:25 GMT mtk01088 ++** fixed the compiling error at linux ++** \main\maintrunk.MT5921\25 2009-07-06 20:51:46 GMT mtk01088 ++** adding the wapi 1x ether type define ++** \main\maintrunk.MT5921\24 2009-06-23 23:19:18 GMT mtk01090 ++** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support ++** \main\maintrunk.MT5921\23 2009-02-07 15:05:06 GMT mtk01088 ++** add the privacy flag to ingo driver the supplicant selected ap's security ++** \main\maintrunk.MT5921\22 2009-02-05 15:34:09 GMT mtk01088 ++** fixed the compiling error for using bits marco for only one parameter ++** \main\maintrunk.MT5921\21 2009-01-22 13:02:13 GMT mtk01088 ++** data frame is or not 802.1x value share with tid, using the same reserved byte, provide the function to set and get ++** \main\maintrunk.MT5921\20 2008-10-24 12:04:16 GMT mtk01088 ++** move the config.h from precomp.h to here for lint check ++** \main\maintrunk.MT5921\19 2008-09-22 23:19:02 GMT mtk01461 ++** Update driver for code review ++** \main\maintrunk.MT5921\18 2008-09-05 17:25:13 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\17 2008-08-01 13:32:47 GMT mtk01084 ++** Prevent redundent driver assertion in driver logic when BUS is detached ++** \main\maintrunk.MT5921\16 2008-05-30 14:41:43 GMT mtk01461 ++** Remove WMM Assoc Flag in KAL ++** \main\maintrunk.MT5921\15 2008-05-29 14:16:25 GMT mtk01084 ++** remoev un-used variable ++** \main\maintrunk.MT5921\14 2008-05-03 15:17:14 GMT mtk01461 ++** Add Media Status variable in Glue Layer ++** \main\maintrunk.MT5921\13 2008-04-24 11:58:41 GMT mtk01461 ++** change threshold to 256 ++** \main\maintrunk.MT5921\12 2008-03-11 14:51:05 GMT mtk01461 ++** Remove redundant GL_CONN_INFO_T ++** \main\maintrunk.MT5921\11 2008-01-07 15:07:41 GMT mtk01461 ++** Adjust the netif stop threshold to 150 ++** \main\maintrunk.MT5921\10 2007-11-26 19:43:46 GMT mtk01461 ++** Add OS_TIMESTAMP macro ++** ++** \main\maintrunk.MT5921\9 2007-11-07 18:38:38 GMT mtk01461 ++** Move definition ++** \main\maintrunk.MT5921\8 2007-11-02 01:04:00 GMT mtk01461 ++** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning ++** Revision 1.5 2007/07/12 11:04:28 MTK01084 ++** update macro to delay for ms order ++** ++** Revision 1.4 2007/07/05 07:25:34 MTK01461 ++** Add Linux initial code, modify doc, add 11BB, RF init code ++** ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_OS_H ++#define _GL_OS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++/*------------------------------------------------------------------------------ ++ * Flags for LINUX(OS) dependent ++ *------------------------------------------------------------------------------ ++ */ ++#define CFG_MAX_WLAN_DEVICES 1 /* number of wlan card will coexist */ ++ ++#define CFG_MAX_TXQ_NUM 4 /* number of tx queue for support multi-queue h/w */ ++ ++#define CFG_USE_SPIN_LOCK_BOTTOM_HALF 0 /* 1: Enable use of SPIN LOCK Bottom Half for LINUX ++ 0: Disable - use SPIN LOCK IRQ SAVE instead */ ++ ++#define CFG_TX_PADDING_SMALL_ETH_PACKET 0 /* 1: Enable - Drop ethernet packet if it < 14 bytes. ++ And pad ethernet packet with dummy 0 if it < 60 bytes. ++ 0: Disable */ ++ ++#define CFG_TX_STOP_NETIF_QUEUE_THRESHOLD 256 /* packets */ ++ ++#define CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD 256 /* packets */ ++#define CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD 128 /* packets */ ++ ++#define ETH_P_1X 0x888E ++#define IPTOS_PREC_OFFSET 5 ++#define USER_PRIORITY_DEFAULT 0 ++ ++#define ETH_WPI_1X 0x88B4 ++ ++#define ETH_HLEN 14 ++#define ETH_TYPE_LEN_OFFSET 12 ++#define ETH_P_IP 0x0800 ++#define ETH_P_1X 0x888E ++#define ETH_P_PRE_1X 0x88C7 ++#define ETH_P_ARP 0x0806 ++ ++#define ARP_PRO_REQ 1 ++#define ARP_PRO_RSP 2 ++ ++#define IPVERSION 4 ++#define IP_HEADER_LEN 20 ++ ++#define IP_PRO_ICMP 0x01 ++#define IP_PRO_UDP 0x11 ++#define IP_PRO_TCP 0x06 ++ ++#define UDP_PORT_DHCPS 0x43 ++#define UDP_PORT_DHCPC 0x44 ++#define UDP_PORT_DNS 0x35 ++ ++#define IPVH_VERSION_OFFSET 4 /* For Little-Endian */ ++#define IPVH_VERSION_MASK 0xF0 ++#define IPTOS_PREC_OFFSET 5 ++#define IPTOS_PREC_MASK 0xE0 ++ ++#define SOURCE_PORT_LEN 2 ++/* NOTE(Kevin): Without IP Option Length */ ++#define LOOK_AHEAD_LEN (ETH_HLEN + IP_HEADER_LEN + SOURCE_PORT_LEN) ++ ++/* 802.2 LLC/SNAP */ ++#define ETH_LLC_OFFSET (ETH_HLEN) ++#define ETH_LLC_LEN 3 ++#define ETH_LLC_DSAP_SNAP 0xAA ++#define ETH_LLC_SSAP_SNAP 0xAA ++#define ETH_LLC_CONTROL_UNNUMBERED_INFORMATION 0x03 ++ ++/* Bluetooth SNAP */ ++#define ETH_SNAP_OFFSET (ETH_HLEN + ETH_LLC_LEN) ++#define ETH_SNAP_LEN 5 ++#define ETH_SNAP_BT_SIG_OUI_0 0x00 ++#define ETH_SNAP_BT_SIG_OUI_1 0x19 ++#define ETH_SNAP_BT_SIG_OUI_2 0x58 ++ ++#define BOW_PROTOCOL_ID_SECURITY_FRAME 0x0003 ++ ++#if defined(MT6620) ++#define CHIP_NAME "MT6620" ++#elif defined(MT6628) ++#define CHIP_NAME "MT6582" ++#endif ++ ++#define DRV_NAME "["CHIP_NAME"]: " ++ ++#define CONFIG_ANDROID 1 ++/* Define if target platform is Android. ++ * It should already be defined in Android kernel source ++ */ ++ ++/* for CFG80211 IE buffering mechanism */ ++#define CFG_CFG80211_IE_BUF_LEN (512) ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include /* constant of kernel version */ ++ ++#include /* bitops.h */ ++ ++#include /* struct timer_list */ ++#include /* jiffies */ ++#include /* udelay and mdelay macro */ ++ ++#if CONFIG_ANDROID ++#include ++#endif ++ ++#include /* IRQT_FALLING */ ++ ++#include /* struct net_device, struct net_device_stats */ ++#include /* for eth_type_trans() function */ ++#include /* struct iw_statistics */ ++#include ++#include /* struct in_device */ ++ ++#include /* struct iphdr */ ++ ++#include /* for memcpy()/memset() function */ ++#include /* for offsetof() macro */ ++ ++#include /* The proc filesystem constants/structures */ ++ ++#include /* for rtnl_lock() and rtnl_unlock() */ ++#include /* kthread_should_stop(), kthread_run() */ ++#include /* for copy_from_user() */ ++#include /* for firmware download */ ++#include ++ ++#include /* for kfifo interface */ ++#include /* for cdev interface */ ++ ++#include /* for firmware download */ ++ ++#if defined(_HIF_SDIO) ++#include ++#include ++#endif ++ ++#include ++ ++#include ++#include ++ ++#include /* readw and writew */ ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++#include "version.h" ++#include "config.h" ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#endif ++ ++#include ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++#include ++#endif ++ ++#include "gl_typedef.h" ++#include "typedef.h" ++#include "queue.h" ++#include "gl_kal.h" ++#include "hif.h" ++#if CFG_CHIP_RESET_SUPPORT ++#include "gl_rst.h" ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++#include "tdls_extr.h" ++#endif ++#include "debug.h" ++ ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++ ++#if CFG_ENABLE_AEE_MSG ++#include ++#endif ++ ++extern BOOLEAN fgIsBusAccessFailed; ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define GLUE_FLAG_HALT BIT(0) ++#define GLUE_FLAG_INT BIT(1) ++#define GLUE_FLAG_OID BIT(2) ++#define GLUE_FLAG_TIMEOUT BIT(3) ++#define GLUE_FLAG_TXREQ BIT(4) ++#define GLUE_FLAG_SUB_MOD_INIT BIT(5) ++#define GLUE_FLAG_SUB_MOD_EXIT BIT(6) ++#define GLUE_FLAG_SUB_MOD_MULTICAST BIT(7) ++#define GLUE_FLAG_FRAME_FILTER BIT(8) ++#define GLUE_FLAG_FRAME_FILTER_AIS BIT(9) ++#define GLUE_FLAG_HIF_LOOPBK_AUTO BIT(10) ++#define GLUE_FLAG_HALT_BIT (0) ++#define GLUE_FLAG_INT_BIT (1) ++#define GLUE_FLAG_OID_BIT (2) ++#define GLUE_FLAG_TIMEOUT_BIT (3) ++#define GLUE_FLAG_TXREQ_BIT (4) ++#define GLUE_FLAG_SUB_MOD_INIT_BIT (5) ++#define GLUE_FLAG_SUB_MOD_EXIT_BIT (6) ++#define GLUE_FLAG_SUB_MOD_MULTICAST_BIT (7) ++#define GLUE_FLAG_FRAME_FILTER_BIT (8) ++#define GLUE_FLAG_FRAME_FILTER_AIS_BIT (9) ++#define GLUE_FLAG_HIF_LOOPBK_AUTO_BIT (10) ++ ++#define GLUE_BOW_KFIFO_DEPTH (1024) ++/* #define GLUE_BOW_DEVICE_NAME "MT6620 802.11 AMP" */ ++#define GLUE_BOW_DEVICE_NAME "ampc0" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _GL_WPA_INFO_T { ++ UINT_32 u4WpaVersion; ++ UINT_32 u4KeyMgmt; ++ UINT_32 u4CipherGroup; ++ UINT_32 u4CipherPairwise; ++ UINT_32 u4AuthAlg; ++ BOOLEAN fgPrivacyInvoke; ++#if CFG_SUPPORT_802_11W ++ UINT_32 u4Mfp; ++#endif ++} GL_WPA_INFO_T, *P_GL_WPA_INFO_T; ++ ++typedef enum _ENUM_RSSI_TRIGGER_TYPE { ++ ENUM_RSSI_TRIGGER_NONE, ++ ENUM_RSSI_TRIGGER_GREATER, ++ ENUM_RSSI_TRIGGER_LESS, ++ ENUM_RSSI_TRIGGER_TRIGGERED, ++ ENUM_RSSI_TRIGGER_NUM ++} ENUM_RSSI_TRIGGER_TYPE; ++ ++#if CFG_ENABLE_WIFI_DIRECT ++typedef enum _ENUM_SUB_MODULE_IDX_T { ++ P2P_MODULE = 0, ++ SUB_MODULE_NUM ++} ENUM_SUB_MODULE_IDX_T; ++ ++typedef enum _ENUM_NET_REG_STATE_T { ++ ENUM_NET_REG_STATE_UNREGISTERED, ++ ENUM_NET_REG_STATE_REGISTERING, ++ ENUM_NET_REG_STATE_REGISTERED, ++ ENUM_NET_REG_STATE_UNREGISTERING, ++ ENUM_NET_REG_STATE_NUM ++} ENUM_NET_REG_STATE_T; ++ ++#endif ++ ++typedef struct _GL_IO_REQ_T { ++ QUE_ENTRY_T rQueEntry; ++ /* wait_queue_head_t cmdwait_q; */ ++ BOOLEAN fgRead; ++ BOOLEAN fgWaitResp; ++#if CFG_ENABLE_WIFI_DIRECT ++ BOOLEAN fgIsP2pOid; ++#endif ++ P_ADAPTER_T prAdapter; ++ PFN_OID_HANDLER_FUNC pfnOidHandler; ++ PVOID pvInfoBuf; ++ UINT_32 u4InfoBufLen; ++ PUINT_32 pu4QryInfoLen; ++ WLAN_STATUS rStatus; ++ UINT_32 u4Flag; ++} GL_IO_REQ_T, *P_GL_IO_REQ_T; ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++typedef struct _GL_BOW_INFO { ++ BOOLEAN fgIsRegistered; ++ dev_t u4DeviceNumber; /* dynamic device number */ ++/* struct kfifo *prKfifo; */ /* for buffering indicated events */ ++ struct kfifo rKfifo; /* for buffering indicated events */ ++ spinlock_t rSpinLock; /* spin lock for kfifo */ ++ struct cdev cdev; ++ UINT_32 u4FreqInKHz; /* frequency */ ++ ++ UINT_8 aucRole[CFG_BOW_PHYSICAL_LINK_NUM]; /* 0: Responder, 1: Initiator */ ++ ENUM_BOW_DEVICE_STATE aeState[CFG_BOW_PHYSICAL_LINK_NUM]; ++ PARAM_MAC_ADDRESS arPeerAddr[CFG_BOW_PHYSICAL_LINK_NUM]; ++ ++ wait_queue_head_t outq; ++ ++#if CFG_BOW_SEPARATE_DATA_PATH ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ BOOLEAN fgIsNetRegistered; ++#endif ++ ++} GL_BOW_INFO, *P_GL_BOW_INFO; ++#endif ++ ++#if (CFG_SUPPORT_TDLS == 1) ++typedef struct _TDLS_INFO_LINK_T { ++ /* start time when link is built, end time when link is broken */ ++ unsigned long jiffies_start, jiffies_end; ++ ++ /* the peer MAC */ ++ UINT8 aucPeerMac[6]; ++ ++ /* broken reason */ ++ UINT8 ucReasonCode; ++ ++ /* TRUE: torn down is triggerred by us */ ++ UINT8 fgIsFromUs; ++ ++ /* duplicate count; same reason */ ++ UINT8 ucDupCount; ++ ++ /* HT capability */ ++#define TDLS_INFO_LINK_HT_CAP_SUP 0x01 ++ UINT8 ucHtCap; ++#define TDLS_INFO_LINK_HT_BA_SETUP 0x01 ++#define TDLS_INFO_LINK_HT_BA_SETUP_OK 0x02 ++#define TDLS_INFO_LINK_HT_BA_SETUP_DECLINE 0x04 ++#define TDLS_INFO_LINK_HT_BA_PEER 0x10 ++#define TDLS_INFO_LINK_HT_BA_RSP_OK 0x20 ++#define TDLS_INFO_LINK_HT_BA_RSP_DECLINE 0x40 ++ UINT8 ucHtBa[8]; /* TID0 ~ TID7 */ ++} TDLS_INFO_LINK_T; ++ ++typedef struct _TDLS_INFO_T { ++ /* link history */ ++#define TDLS_LINK_HISTORY_MAX 30 ++ TDLS_INFO_LINK_T rLinkHistory[TDLS_LINK_HISTORY_MAX]; ++ UINT32 u4LinkIdx; ++ ++ /* TRUE: support 20/40 bandwidth in TDLS link */ ++ BOOLEAN fgIs2040Sup; ++ ++ /* total TDLS link count */ ++ INT8 cLinkCnt; ++} TDLS_INFO_T; ++#endif /* CFG_SUPPORT_TDLS */ ++ ++/* ++* type definition of pointer to p2p structure ++*/ ++typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; ++ ++struct _GLUE_INFO_T { ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ ++ /* Device Index(index of arWlanDevInfo[]) */ ++ INT_32 i4DevIdx; ++ ++ /* Device statistics */ ++ struct net_device_stats rNetDevStats; ++ ++ /* Wireless statistics struct net_device */ ++ struct iw_statistics rIwStats; ++ ++ /* spinlock to sync power save mechanism */ ++ spinlock_t rSpinLock[SPIN_LOCK_NUM]; ++ ++ /* semaphore for ioctl */ ++ struct semaphore ioctl_sem; ++ ++ UINT_64 u8Cookie; ++ ++ ULONG ulFlag; /* GLUE_FLAG_XXX */ ++ UINT_32 u4PendFlag; ++ /* UINT_32 u4TimeoutFlag; */ ++ UINT_32 u4OidCompleteFlag; ++ UINT_32 u4ReadyFlag; /* check if card is ready */ ++ ++ UINT_32 u4OsMgmtFrameFilter; ++ ++ /* Number of pending frames, also used for debuging if any frame is ++ * missing during the process of unloading Driver. ++ * ++ * NOTE(Kevin): In Linux, we also use this variable as the threshold ++ * for manipulating the netif_stop(wake)_queue() func. ++ */ ++ INT_32 ai4TxPendingFrameNumPerQueue[4][CFG_MAX_TXQ_NUM]; ++ INT_32 i4TxPendingFrameNum; ++ INT_32 i4TxPendingSecurityFrameNum; ++ ++ /* current IO request for kalIoctl */ ++ GL_IO_REQ_T OidEntry; ++ ++ /* registry info */ ++ REG_INFO_T rRegInfo; ++ ++ /* firmware */ ++ struct firmware *prFw; ++ ++ /* Host interface related information */ ++ /* defined in related hif header file */ ++ GL_HIF_INFO_T rHifInfo; ++ ++ /*! \brief wext wpa related information */ ++ GL_WPA_INFO_T rWpaInfo; ++ ++ /* Pointer to ADAPTER_T - main data structure of internal protocol stack */ ++ P_ADAPTER_T prAdapter; ++ ++#ifdef WLAN_INCLUDE_PROC ++ struct proc_dir_entry *pProcRoot; ++#endif /* WLAN_INCLUDE_PROC */ ++ ++ /* Indicated media state */ ++ ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicated; ++ ++ /* Device power state D0~D3 */ ++ PARAM_DEVICE_POWER_STATE ePowerState; ++ ++ struct completion rScanComp; /* indicate scan complete */ ++ struct completion rHaltComp; /* indicate main thread halt complete */ ++ struct completion rPendComp; /* indicate main thread halt complete */ ++#if CFG_ENABLE_WIFI_DIRECT ++ struct completion rSubModComp; /*indicate sub module init or exit complete */ ++#endif ++ WLAN_STATUS rPendStatus; ++ ++ QUE_T rTxQueue; ++ ++ /* OID related */ ++ QUE_T rCmdQueue; ++ /* PVOID pvInformationBuffer; */ ++ /* UINT_32 u4InformationBufferLength; */ ++ /* PVOID pvOidEntry; */ ++ /* PUINT_8 pucIOReqBuff; */ ++ /* QUE_T rIOReqQueue; */ ++ /* QUE_T rFreeIOReqQueue; */ ++ ++ wait_queue_head_t waitq; ++ struct task_struct *main_thread; ++ ++ struct timer_list tickfn; ++ ++#if CFG_SUPPORT_EXT_CONFIG ++ UINT_16 au2ExtCfg[256]; /* NVRAM data buffer */ ++ UINT_32 u4ExtCfgLength; /* 0 means data is NOT valid */ ++#endif ++ ++#if 1 /* CFG_SUPPORT_WAPI */ ++ /* Should be large than the PARAM_WAPI_ASSOC_INFO_T */ ++ UINT_8 aucWapiAssocInfoIEs[42]; ++ UINT_16 u2WapiAssocInfoIESz; ++#endif ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++ GL_BOW_INFO rBowInfo; ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ P_GL_P2P_INFO_T prP2PInfo; ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++ /* Wireless statistics struct net_device */ ++ struct iw_statistics rP2pIwStats; ++#endif ++#endif ++ BOOLEAN fgWpsActive; ++ UINT_8 aucWSCIE[500]; /*for probe req */ ++ UINT_16 u2WSCIELen; ++ UINT_8 aucWSCAssocInfoIE[200]; /*for Assoc req */ ++ UINT_16 u2WSCAssocInfoIELen; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ UINT_8 aucHS20AssocInfoIE[200]; /*for Assoc req */ ++ UINT_16 u2HS20AssocInfoIELen; ++ UINT_8 ucHotspotConfig; ++ BOOLEAN fgConnectHS20AP; ++#endif ++ ++ /* NVRAM availability */ ++ BOOLEAN fgNvramAvailable; ++ ++ BOOLEAN fgMcrAccessAllowed; ++ ++ /* MAC Address Overridden by IOCTL */ ++ BOOLEAN fgIsMacAddrOverride; ++ PARAM_MAC_ADDRESS rMacAddrOverride; ++ ++ SET_TXPWR_CTRL_T rTxPwr; ++ ++ /* for cfg80211 scan done indication */ ++ struct cfg80211_scan_request *prScanRequest; ++ ++ /* for cfg80211 scheduled scan */ ++ struct cfg80211_sched_scan_request *prSchedScanRequest; ++ ++ /* to indicate registered or not */ ++ BOOLEAN fgIsRegistered; ++ ++ /* for cfg80211 connected indication */ ++ UINT_32 u4RspIeLength; ++ UINT_8 aucRspIe[CFG_CFG80211_IE_BUF_LEN]; ++ ++ UINT_32 u4ReqIeLength; ++ UINT_8 aucReqIe[CFG_CFG80211_IE_BUF_LEN]; ++ ++ KAL_WAKE_LOCK_T rAhbIsrWakeLock; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ BOOLEAN fgIsDad; ++ UINT_8 aucDADipv4[4]; ++ BOOLEAN fgIs6Dad; ++ UINT_8 aucDADipv6[16]; ++#endif ++#if (CFG_SUPPORT_MET_PROFILING == 1) ++ UINT_8 u8MetProfEnable; ++ INT_16 u16MetUdpPort; ++#endif ++ BOOLEAN fgPoorlinkValid; ++ UINT_64 u8Statistic[2]; ++ UINT_64 u8TotalFailCnt; ++ UINT_32 u4LinkspeedThreshold; ++ INT_32 i4RssiThreshold; ++ INT_32 i4RssiCache; ++ UINT_32 u4LinkSpeedCache; ++ ++#if (CFG_SUPPORT_TDLS == 1) ++ TDLS_INFO_T rTdlsLink; ++ ++ UINT8 aucTdlsHtPeerMac[6]; ++ IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ ++ ++ /* ++ [0~7]: jiffies ++ [8~13]: Peer MAC ++ [14]: Reason Code ++ [15]: From us or peer ++ [16]: Duplicate Count ++ */ ++/* UINT8 aucTdlsDisconHistory[TDLS_DISCON_HISTORY_MAX][20]; */ ++/* UINT32 u4TdlsDisconIdx; */ ++#endif /* CFG_SUPPORT_TDLS */ ++ UINT_32 IsrCnt; ++ UINT_32 IsrPassCnt; ++ UINT_32 TaskIsrCnt; ++ ++ UINT_32 IsrPreCnt; ++ UINT_32 IsrPrePassCnt; ++ UINT_32 TaskPreIsrCnt; ++ ++ UINT_32 IsrAbnormalCnt; ++ UINT_32 IsrSoftWareCnt; ++ UINT_32 IsrTxCnt; ++ UINT_32 IsrRxCnt; ++ UINT_64 u8SkbToDriver; ++ UINT_64 u8SkbFreed; ++}; ++ ++typedef irqreturn_t(*PFN_WLANISR) (int irq, void *dev_id, struct pt_regs *regs); ++ ++typedef void (*PFN_LINUX_TIMER_FUNC) (unsigned long); ++ ++/* generic sub module init/exit handler ++* now, we only have one sub module, p2p ++*/ ++#if CFG_ENABLE_WIFI_DIRECT ++typedef BOOLEAN(*SUB_MODULE_INIT) (P_GLUE_INFO_T prGlueInfo); ++typedef BOOLEAN(*SUB_MODULE_EXIT) (P_GLUE_INFO_T prGlueInfo); ++ ++typedef struct _SUB_MODULE_HANDLER { ++ SUB_MODULE_INIT subModInit; ++ SUB_MODULE_EXIT subModExit; ++ BOOLEAN fgIsInited; ++} SUB_MODULE_HANDLER, *P_SUB_MODULE_HANDLER; ++ ++#endif ++ ++ ++#ifdef CONFIG_NL80211_TESTMODE ++enum TestModeCmdType { ++ /* old test mode command id, compatible with exist testmode command */ ++ TESTMODE_CMD_ID_SW_CMD = 1, ++ TESTMODE_CMD_ID_WAPI = 2, ++ TESTMODE_CMD_ID_HS20 = 3, ++ TESTMODE_CMD_ID_POORLINK = 4, ++ TESTMODE_CMD_ID_STATISTICS = 0x10, ++ TESTMODE_CMD_ID_LINK_DETECT = 0x20, ++ /* old test mode command id, compatible with exist testmode command */ ++ ++ /* all new added test mode command should great than TESTMODE_CMD_ID_NEW_BEGIN */ ++ TESTMODE_CMD_ID_NEW_BEGIN = 100, ++ TESTMODE_CMD_ID_SUSPEND = 101, ++}; ++#if CFG_SUPPORT_HOTSPOT_2_0 ++enum Hs20CmdType { ++ HS20_CMD_ID_SET_BSSID_POOL = 0, ++ NUM_OF_HS20_CMD_ID ++}; ++#endif ++ ++typedef struct _NL80211_DRIVER_TEST_MODE_PARAMS { ++ UINT_32 index; ++ UINT_32 buflen; ++} NL80211_DRIVER_TEST_MODE_PARAMS, *P_NL80211_DRIVER_TEST_MODE_PARAMS; ++ ++/*SW CMD */ ++typedef struct _NL80211_DRIVER_SW_CMD_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 set; ++ UINT_32 adr; ++ UINT_32 data; ++} NL80211_DRIVER_SW_CMD_PARAMS, *P_NL80211_DRIVER_SW_CMD_PARAMS; ++ ++typedef struct _NL80211_DRIVER_SUSPEND_PARAMS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 suspend; ++} NL80211_DRIVER_SUSPEND_PARAMS, *P_NL80211_DRIVER_SUSPEND_PARAMS; ++struct iw_encode_exts { ++ __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ ++ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 addr[MAC_ADDR_LEN]; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast ++ * (group) keys or unicast address for ++ * individual keys */ ++ __u16 alg; /*!< IW_ENCODE_ALG_* */ ++ __u16 key_len; ++ __u8 key[32]; ++}; ++ ++/*SET KEY EXT */ ++typedef struct _NL80211_DRIVER_SET_KEY_EXTS { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ UINT_8 key_index; ++ UINT_8 key_len; ++ struct iw_encode_exts ext; ++} NL80211_DRIVER_SET_KEY_EXTS, *P_NL80211_DRIVER_SET_KEY_EXTS; ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ ++struct param_hs20_set_bssid_pool { ++ u8 fgBssidPoolIsEnable; ++ u8 ucNumBssidPool; ++ u8 arBssidPool[8][ETH_ALEN]; ++}; ++ ++struct wpa_driver_hs20_data_s { ++ NL80211_DRIVER_TEST_MODE_PARAMS hdr; ++ enum Hs20CmdType CmdType; ++ struct param_hs20_set_bssid_pool hs20_set_bssid_pool; ++}; ++ ++#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Macros of SPIN LOCK operations for using in Glue Layer */ ++/*----------------------------------------------------------------------------*/ ++#if CFG_USE_SPIN_LOCK_BOTTOM_HALF ++#define GLUE_SPIN_LOCK_DECLARATION() ++#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_lock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ ++ } ++#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_unlock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ ++ } ++#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ ++ spin_lock_bh(prLock) ++#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ ++ spin_unlock_bh(prLock) ++ ++#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++#define GLUE_SPIN_LOCK_DECLARATION() unsigned long __u4Flags = 0 ++#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_lock_irqsave(&(prGlueInfo)->rSpinLock[rLockCategory], __u4Flags); \ ++ } ++#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ ++ { \ ++ if (rLockCategory < SPIN_LOCK_NUM) \ ++ spin_unlock_irqrestore(&(prGlueInfo->rSpinLock[rLockCategory]), __u4Flags); \ ++ } ++#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ ++ spin_lock_irqsave(prLock, __u4Flags) ++#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ ++ spin_unlock_irqrestore(prLock, __u4Flags) ++#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ ++ ++/*----------------------------------------------------------------------------*/ ++/* Macros for accessing Reserved Fields of native packet */ ++/*----------------------------------------------------------------------------*/ ++#define GLUE_CB_OFFSET 4 /* For 64-bit platform, avoiding that the cb ++ isoverwrited by "(prQueueEntry)->prNext = ++ (P_QUE_ENTRY_T)NULL;" in QUEUE_INSERT_TAIL */ ++#define GLUE_GET_PKT_QUEUE_ENTRY(_p) \ ++ (&(((struct sk_buff *)(_p))->cb[0])) ++ ++#define GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) \ ++ ((P_NATIVE_PACKET) ((ULONG)_prQueueEntry - offsetof(struct sk_buff, cb[0]))) ++ ++#define GLUE_SET_PKT_FLAG_802_11(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(7)) ++ ++#define GLUE_SET_PKT_FLAG_1X(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(6)) ++ ++#define GLUE_SET_PKT_FLAG_PAL(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(5)) ++ ++#define GLUE_SET_PKT_FLAG_P2P(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(4)) ++ ++#define GLUE_SET_PKT_TID(_p, _tid) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= (((UINT_8)((_tid) & (BITS(0, 3)))))) ++ ++#define GLUE_SET_PKT_FRAME_LEN(_p, _u2PayloadLen) \ ++ (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6])) = (UINT_16)(_u2PayloadLen)) ++ ++#define GLUE_GET_PKT_FRAME_LEN(_p) \ ++ (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6]))) ++ ++#define GLUE_GET_PKT_IS_802_11(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(7))) ++ ++#define GLUE_GET_PKT_IS_1X(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(6))) ++ ++#define GLUE_GET_PKT_TID(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BITS(0, 3))) ++ ++#define GLUE_GET_PKT_IS_PAL(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(5))) ++ ++#define GLUE_GET_PKT_IS_P2P(_p) \ ++ ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(4))) ++ ++#define GLUE_SET_PKT_HEADER_LEN(_p, _ucMacHeaderLen) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5])) = (UINT_8)(_ucMacHeaderLen)) ++ ++#define GLUE_GET_PKT_HEADER_LEN(_p) \ ++ (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5]))) ++ ++#define GLUE_SET_PKT_ARRIVAL_TIME(_p, _rSysTime) \ ++ (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8])) = (OS_SYSTIME)(_rSysTime)) ++ ++#define GLUE_GET_PKT_ARRIVAL_TIME(_p) \ ++ (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8]))) ++ ++#define GLUE_SET_PKT_XTIME(_p, _rSysTime) \ ++ (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16])) = (UINT_64)(_rSysTime)) ++ ++#define GLUE_GET_PKT_XTIME(_p) \ ++ (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16]))) ++ ++/* Check validity of prDev, private data, and pointers */ ++#define GLUE_CHK_DEV(prDev) \ ++ ((prDev && *((P_GLUE_INFO_T *) netdev_priv(prDev))) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR2(prDev, pr2) \ ++ ((GLUE_CHK_DEV(prDev) && pr2) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR3(prDev, pr2, pr3) \ ++ ((GLUE_CHK_PR2(prDev, pr2) && pr3) ? TRUE : FALSE) ++ ++#define GLUE_CHK_PR4(prDev, pr2, pr3, pr4) \ ++ ((GLUE_CHK_PR3(prDev, pr2, pr3) && pr4) ? TRUE : FALSE) ++ ++#define GLUE_SET_EVENT(pr) \ ++ kalSetEvent(pr) ++ ++#define GLUE_INC_REF_CNT(_refCount) atomic_inc((atomic_t *)&(_refCount)) ++#define GLUE_DEC_REF_CNT(_refCount) atomic_dec((atomic_t *)&(_refCount)) ++ ++#define DbgPrint(...) ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++#ifdef WLAN_INCLUDE_PROC ++INT_32 procRemoveProcfs(VOID); ++ ++INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo); ++INT_32 procInitFs(VOID); ++INT_32 procUninitProcFs(VOID); ++ ++#endif /* WLAN_INCLUDE_PROC */ ++ ++#if CFG_ENABLE_BT_OVER_WIFI ++BOOLEAN glRegisterAmpc(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN glUnregisterAmpc(P_GLUE_INFO_T prGlueInfo); ++#endif ++ ++#if CFG_ENABLE_WIFI_DIRECT ++ ++VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo); ++ ++VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx); ++ ++BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr); ++ ++BOOLEAN wlanIsLaunched(VOID); ++ ++VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo); ++ ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_OS_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h +new file mode 100644 +index 000000000000..a27294e33500 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h +@@ -0,0 +1,743 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_ioctl.h#9 ++*/ ++ ++/*! \file gl_p2p_ioctl.h ++ \brief This file is for custom ioctls for Wi-Fi Direct only ++*/ ++ ++/* ++** Log: gl_p2p_ioctl.h ++** ++** 07 26 2012 yuche.tsai ++** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot ++** Update driver code of ALPS.JB for hot-spot. ++** ++** 07 19 2012 yuche.tsai ++** NULL ++** Code update for JB. ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 06 07 2011 yuche.tsai ++ * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue ++ * Fix RX SD request under AP mode issue. ++ * ++ * 03 25 2011 wh.su ++ * NULL ++ * Fix P2P IOCTL of multicast address bug, add low power driver stop control. ++ * ++ * 11 22 2011 yuche.tsai ++ * NULL ++ * Update RSSI link quality of P2P Network query method. (Bug fix) ++ * ++ * 11 19 2011 yuche.tsai ++ * NULL ++ * Add RSSI support for P2P network. ++ * ++ * 11 11 2011 yuche.tsai ++ * NULL ++ * Fix work thread cancel issue. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add support for driver version query & p2p supplicant verseion set. ++ * For new service discovery mechanism sync. ++ * ++ * 10 25 2011 cm.chang ++ * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode ++ * . ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 16 2011 chinglan.wang ++ * NULL ++ * Add the group id information in the invitation indication. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 05 04 2011 chinglan.wang ++ * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver ++ * . ++ * ++ * 03 29 2011 wh.su ++ * [WCXRP00000095] [MT6620 Wi-Fi] [FW] Refine the P2P GO send broadcast protected code ++ * add the set power and get power function sample. ++ * ++ * 03 22 2011 george.huang ++ * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command ++ * link with supplicant commands ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 03 01 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * fixed the ioctl sumcmd to meet the p2p_supplicant setting. ++ * ++ * 02 23 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int define for p2p parameter. ++ * ++ * 02 22 2011 wh.su ++ * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver ++ * adding the ioctl set int from supplicant, and can used to set the p2p parameters ++ * ++ * 02 17 2011 wh.su ++ * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request ++ * adjust the set wsc ie structure. ++ * ++ * 01 05 2011 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * ioctl implementations for P2P Service Discovery ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++ * 12 15 2010 cp.wu ++ * NULL ++ * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() ++ * ++ * 12 07 2010 cp.wu ++ * [WCXRP00000237] [MT6620 Wi-Fi][Wi-Fi Direct][Driver] Add interface for supporting service discovery ++ * define a pair of i/o control for multiplexing layer ++ * ++ * 11 04 2010 wh.su ++ * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID ++ * adding the p2p random ssid support. ++ * ++ * 10 20 2010 wh.su ++ * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group ++ * Add the code to support disconnect p2p group ++ * ++ * 09 21 2010 kevin.huang ++ * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface ++ * Isolate P2P related function for Hardware Software Bundle ++ * ++ * 09 10 2010 george.huang ++ * NULL ++ * update iwpriv LP related ++ * ++ * 09 07 2010 wh.su ++ * NULL ++ * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. ++ * ++ * 08 25 2010 cp.wu ++ * NULL ++ * add netdev_ops(NDO) for linux kernel 2.6.31 or greater ++ * ++ * 08 20 2010 yuche.tsai ++ * NULL ++ * Refine a function parameter name. ++ * ++ * 08 19 2010 cp.wu ++ * NULL ++ * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. ++ * ++ * 08 16 2010 george.huang ++ * NULL ++ * add wext handlers to link P2P set PS profile/ network address function (TBD) ++ * ++ * 08 16 2010 cp.wu ++ * NULL ++ * revised implementation of Wi-Fi Direct io controls. ++ * ++ * 08 12 2010 cp.wu ++ * NULL ++ * follow-up with ioctl interface update for Wi-Fi Direct application ++ * ++ * 08 06 2010 cp.wu ++ * NULL ++ * driver hook modifications corresponding to ioctl interface change. ++ * ++ * 08 03 2010 cp.wu ++ * NULL ++ * [Wi-Fi Direct] add framework for driver hooks ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 06 01 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl to configure scan mode for p2p connection ++ * ++ * 05 31 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add cfg80211 interface, which is to replace WE, for further extension ++ * ++ * 05 17 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement get scan result. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * implement wireless extension ioctls in iw_handler form. ++ * ++ * 05 14 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * p2p ioctls revised. ++ * ++ * 05 11 2010 cp.wu ++ * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support ++ * add ioctl for controlling p2p scan phase parameters ++ * ++*/ ++ ++#ifndef _GL_P2P_IOCTL_H ++#define _GL_P2P_IOCTL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#include ++#endif ++ ++#include "wlan_oid.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Device private ioctl calls */ ++/* #define SIOCDEVPRIVATE 0x89F0*/ ++#define IOC_GET_PRIVATE_IOCTL_CMD (SIOCDEVPRIVATE+1) ++ ++/* (WirelessExtension) Private I/O Controls */ ++#define IOC_P2P_CFG_DEVICE (SIOCIWFIRSTPRIV+0) ++#define IOC_P2P_PROVISION_COMPLETE (SIOCIWFIRSTPRIV+2) ++#define IOC_P2P_START_STOP_DISCOVERY (SIOCIWFIRSTPRIV+4) ++#define IOC_P2P_DISCOVERY_RESULTS (SIOCIWFIRSTPRIV+5) ++#define IOC_P2P_WSC_BEACON_PROBE_RSP_IE (SIOCIWFIRSTPRIV+6) ++#define IOC_P2P_GO_WSC_IE IOC_P2P_WSC_BEACON_PROBE_RSP_IE ++#define IOC_P2P_CONNECT_DISCONNECT (SIOCIWFIRSTPRIV+8) ++#define IOC_P2P_PASSWORD_READY (SIOCIWFIRSTPRIV+10) ++/* #define IOC_P2P_SET_PWR_MGMT_PARAM (SIOCIWFIRSTPRIV+12) */ ++#define IOC_P2P_SET_INT (SIOCIWFIRSTPRIV+12) ++#define IOC_P2P_GET_STRUCT (SIOCIWFIRSTPRIV+13) ++#define IOC_P2P_SET_STRUCT (SIOCIWFIRSTPRIV+14) ++#define IOC_P2P_GET_REQ_DEVICE_INFO (SIOCIWFIRSTPRIV+15) ++ ++#define PRIV_CMD_INT_P2P_SET 0 ++ ++/* IOC_P2P_PROVISION_COMPLETE (iw_point . flags) */ ++#define P2P_PROVISIONING_SUCCESS 0 ++#define P2P_PROVISIONING_FAIL 1 ++ ++/* IOC_P2P_START_STOP_DISCOVERY (iw_point . flags) */ ++#define P2P_STOP_DISCOVERY 0 ++#define P2P_START_DISCOVERY 1 ++ ++/* IOC_P2P_CONNECT_DISCONNECT (iw_point . flags) */ ++#define P2P_CONNECT 0 ++#define P2P_DISCONNECT 1 ++ ++/* IOC_P2P_START_STOP_DISCOVERY (scan_type) */ ++#define P2P_SCAN_FULL_AND_FIND 0 ++#define P2P_SCAN_FULL 1 ++#define P2P_SCAN_SEARCH_AND_LISTEN 2 ++#define P2P_LISTEN 3 ++ ++/* IOC_P2P_GET_STRUCT/IOC_P2P_SET_STRUCT */ ++#define P2P_SEND_SD_RESPONSE 0 ++#define P2P_GET_SD_REQUEST 1 ++#define P2P_SEND_SD_REQUEST 2 ++#define P2P_GET_SD_RESPONSE 3 ++#define P2P_TERMINATE_SD_PHASE 4 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/*----------------------------------------------------------------------------*/ ++/* Wireless Extension: Private I/O Control */ ++/*----------------------------------------------------------------------------*/ ++typedef struct iw_p2p_cfg_device_type { ++ void __user *ssid; ++ UINT_8 ssid_len; ++ UINT_8 pri_device_type[8]; ++ UINT_8 snd_device_type[8]; ++ void __user *device_name; ++ UINT_8 device_name_len; ++ UINT_8 intend; ++ UINT_8 persistence; ++ UINT_8 sec_mode; ++ UINT_8 ch; ++ UINT_8 ch_width; /* 0: 20 Mhz 1:20/40 Mhz auto */ ++ UINT_8 max_scb; ++} IW_P2P_CFG_DEVICE_TYPE, *P_IW_P2P_CFG_DEVICE_TYPE; ++ ++typedef struct iw_p2p_hostapd_param { ++ UINT_8 cmd; ++ UINT_8 rsv[3]; ++ UINT_8 sta_addr[6]; ++ void __user *data; ++ UINT_16 len; ++} IW_P2P_HOSTAPD_PARAM, *P_IW_P2P_HOSTAPD_PARAM; ++ ++typedef struct iw_p2p_req_device_type { ++ UINT_8 scan_type; /* 0: Full scan + Find ++ * 1: Full scan ++ * 2: Scan (Search +Listen) ++ * 3: Listen ++ * other : reserved ++ */ ++ UINT_8 pri_device_type[8]; ++ void __user *probe_req_ie; ++ UINT_16 probe_req_len; ++ void __user *probe_rsp_ie; ++ UINT_16 probe_rsp_len; ++} IW_P2P_REQ_DEVICE_TYPE, *P_IW_P2P_REQ_DEVICE_TYPE; ++ ++typedef struct iw_p2p_connect_device { ++ UINT_8 sta_addr[6]; ++ UINT_8 p2pRole; /* 0: P2P Device, 1:GC, 2: GO */ ++ UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ ++ UINT_8 authPeer; /* 1: auth peer invitation request */ ++ UINT_8 intend_config_method; /* Request Peer Device used config method */ ++} IW_P2P_CONNECT_DEVICE, *P_IW_P2P_CONNECT_DEVICE; ++ ++typedef struct iw_p2p_password_ready { ++ UINT_8 active_config_method; ++ void __user *probe_req_ie; ++ UINT_16 probe_req_len; ++ void __user *probe_rsp_ie; ++ UINT_16 probe_rsp_len; ++} IW_P2P_PASSWORD_READY, *P_IW_P2P_PASSWORD_READY; ++ ++typedef struct iw_p2p_device_req { ++ UINT_8 name[33]; ++ UINT_32 name_len; ++ UINT_8 device_addr[6]; ++ UINT_8 device_type; ++ INT_32 config_method; ++ INT_32 active_config_method; ++} IW_P2P_DEVICE_REQ, *P_IW_P2P_DEVICE_REQ; ++ ++typedef struct iw_p2p_transport_struct { ++ UINT_32 u4CmdId; ++ UINT_32 inBufferLength; ++ UINT_32 outBufferLength; ++ UINT_8 aucBuffer[16]; ++} IW_P2P_TRANSPORT_STRUCT, *P_IW_P2P_TRANSPORT_STRUCT; ++ ++/* For Invitation */ ++typedef struct iw_p2p_ioctl_invitation_struct { ++ UINT_8 aucDeviceID[6]; ++ UINT_8 aucGroupID[6]; /* BSSID */ ++ UINT_8 aucSsid[32]; ++ UINT_32 u4SsidLen; ++ UINT_8 ucReinvoke; ++} IW_P2P_IOCTL_INVITATION_STRUCT, *P_IW_P2P_IOCTL_INVITATION_STRUCT; ++ ++typedef struct iw_p2p_ioctl_abort_invitation { ++ UINT_8 dev_addr[6]; ++} IW_P2P_IOCTL_ABORT_INVITATION, *P_IW_P2P_IOCTL_ABORT_INVITATION; ++ ++typedef struct iw_p2p_ioctl_invitation_indicate { ++ UINT_8 dev_addr[6]; ++ UINT_8 group_bssid[6]; ++ INT_32 config_method; /* peer device supported config method */ ++ UINT_8 dev_name[32]; /* for reinvoke */ ++ UINT_32 name_len; ++ UINT_8 operating_channel; /* for re-invoke, target operating channel */ ++ UINT_8 invitation_type; /* invitation or re-invoke */ ++} IW_P2P_IOCTL_INVITATION_INDICATE, *P_IW_P2P_IOCTL_INVITATION_INDICATE; ++ ++typedef struct iw_p2p_ioctl_invitation_status { ++ UINT_32 status_code; ++} IW_P2P_IOCTL_INVITATION_STATUS, *P_IW_P2P_IOCTL_INVITATION_STATUS; ++ ++/* For Formation */ ++typedef struct iw_p2p_ioctl_start_formation { ++ UINT_8 dev_addr[6]; /* bssid */ ++ UINT_8 role; /* 0: P2P Device, 1:GC, 2: GO */ ++ UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ ++ UINT_8 auth; /* 1: auth peer invitation request */ ++ UINT_8 config_method; /* Request Peer Device used config method */ ++} IW_P2P_IOCTL_START_FORMATION, *P_IW_P2P_IOCTL_START_FORMATION; ++ ++/* SET_STRUCT / GET_STRUCT */ ++typedef enum _ENUM_P2P_CMD_ID_T { ++ P2P_CMD_ID_SEND_SD_RESPONSE = 0, /* 0x00 (Set) */ ++ P2P_CMD_ID_GET_SD_REQUEST, /* 0x01 (Get) */ ++ P2P_CMD_ID_SEND_SD_REQUEST, /* 0x02 (Set) */ ++ P2P_CMD_ID_GET_SD_RESPONSE, /* 0x03 (Get) */ ++ P2P_CMD_ID_TERMINATE_SD_PHASE, /* 0x04 (Set) */ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ P2P_CMD_ID_SEC_CHECK, /* 0x05(Set) */ ++#endif ++ P2P_CMD_ID_INVITATION, /* 0x06 (Set) */ ++ P2P_CMD_ID_INVITATION_INDICATE, /* 0x07 (Get) */ ++ P2P_CMD_ID_INVITATION_STATUS, /* 0x08 (Get) */ ++ P2P_CMD_ID_INVITATION_ABORT, /* 0x09 (Set) */ ++ P2P_CMD_ID_START_FORMATION, /* 0x0A (Set) */ ++ P2P_CMD_ID_P2P_VERSION, /* 0x0B (Set/Get) */ ++ P2P_CMD_ID_GET_CH_LIST = 12, /* 0x0C (Get) */ ++ P2P_CMD_ID_GET_OP_CH = 14 /* 0x0E (Get) */ ++} ENUM_P2P_CMD_ID_T, *P_ENUM_P2P_CMD_ID_T; ++ ++/* Service Discovery */ ++typedef struct iw_p2p_cmd_send_sd_response { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucSeqNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_SEND_SD_RESPONSE, *P_IW_P2P_CMD_SEND_SD_RESPONSE; ++ ++typedef struct iw_p2p_cmd_get_sd_request { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_GET_SD_REQUEST, *P_IW_P2P_CMD_GET_SD_REQUEST; ++ ++typedef struct iw_p2p_cmd_send_service_discovery_request { ++ PARAM_MAC_ADDRESS rReceiverAddr; ++ UINT_8 fgNeedTxDoneIndication; ++ UINT_8 ucSeqNum; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_SEND_SD_REQUEST, *P_IW_P2P_CMD_SEND_SD_REQUEST; ++ ++typedef struct iw_p2p_cmd_get_sd_response { ++ PARAM_MAC_ADDRESS rTransmitterAddr; ++ UINT_16 u2PacketLength; ++ UINT_8 aucPacketContent[0]; /*native 802.11 */ ++} IW_P2P_CMD_GET_SD_RESPONSE, *P_IW_P2P_CMD_GET_SD_RESPONSE; ++ ++typedef struct iw_p2p_cmd_terminate_sd_phase { ++ PARAM_MAC_ADDRESS rPeerAddr; ++} IW_P2P_CMD_TERMINATE_SD_PHASE, *P_IW_P2P_CMD_TERMINATE_SD_PHASE; ++ ++typedef struct iw_p2p_version { ++ UINT_32 u4Version; ++} IW_P2P_VERSION, *P_IW_P2P_VERSION; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++extern struct ieee80211_supported_band mtk_band_2ghz; ++extern struct ieee80211_supported_band mtk_band_5ghz; ++extern UINT_32 mtk_cipher_suites[5]; ++#endif ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++int mtk_p2p_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, ++ enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); ++ ++int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); ++ ++int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 key_index, ++ bool pairwise, ++ const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) ++); ++ ++int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); ++ ++int ++mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, ++ struct net_device *netdev, u8 key_index, bool unicast, bool multicast); ++ ++int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_info *sinfo); ++ ++int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); ++ ++int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); ++ ++int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); ++ ++int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); ++ ++int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev); ++ ++int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); ++ ++int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params); ++ ++int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, unsigned int duration, u64 *cookie); ++ ++int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); ++ ++int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); ++ ++int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm); ++ ++int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); ++ ++int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req); ++ ++int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req); ++ ++int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings); ++ ++int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); ++ ++int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie); ++ ++int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev); ++ ++int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params); ++//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac); ++ ++int mtk_p2p_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef); ++ ++void mtk_p2p_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg); ++ ++int ++mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, ++ IN struct net_device *dev, ++ IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask); ++ ++#ifdef CONFIG_NL80211_TESTMODE ++int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); ++int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++ ++#if CFG_SUPPORT_WFD ++int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#endif ++ ++int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); ++#else ++#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" ++#endif ++ ++#endif ++ ++/* I/O control handlers */ ++ ++int ++mtk_p2p_wext_get_priv(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_reconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_auth(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_key(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_powermode(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_powermode(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* Private Wireless I/O Controls takes use of iw_handler */ ++int ++mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_discovery_results(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_password_ready(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_invitation_status(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_network_address(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_int(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* Private Wireless I/O Controls for IOC_SET_STRUCT/IOC_GET_STRUCT */ ++int ++mtk_p2p_wext_set_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_struct(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++/* IOC_SET_STRUCT/IOC_GET_STRUCT: Service Discovery */ ++int ++mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, ++ IN struct iw_request_info *info, ++ IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++int ++mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++#endif ++ ++int ++mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++int ++mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++void mtk_p2p_wext_set_Multicastlist(IN P_GLUE_INFO_T prGlueInfo); ++ ++#if CFG_SUPPORT_P2P_RSSI_QUERY ++int ++mtk_p2p_wext_get_rssi(IN struct net_device *prDev, ++ IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); ++ ++struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev); ++ ++#endif ++ ++int ++mtk_p2p_wext_set_txpow(IN struct net_device *prDev, ++ IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_P2P_IOCTL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h +new file mode 100644 +index 000000000000..bf9d8871ef48 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h +@@ -0,0 +1,243 @@ ++/* ++** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_kal.h#2 ++*/ ++ ++/*! \file gl_p2p_kal.h ++ \brief Declaration of KAL functions for Wi-Fi Direct support ++ - kal*() which is provided by GLUE Layer. ++ ++ Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++/* ++** Log: gl_p2p_kal.h ++** ++** 08 30 2012 chinglan.wang ++** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only ++** . ++ * ++ * 07 17 2012 yuche.tsai ++ * NULL ++ * Compile no error before trial run. ++ * ++ * 10 18 2011 yuche.tsai ++ * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. ++ * New 2.1 branch ++ ++ * ++ * 08 15 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Add group BSSID in invitation request indication. ++ * The BSSID is used for APP to decide the configure method. ++ * ++ * 08 09 2011 yuche.tsai ++ * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. ++ * Invitation Feature add on. ++ * ++ * 03 19 2011 terry.wu ++ * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver ++ * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. ++ * ++ * 03 07 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * rename the define to anti_pviracy. ++ * ++ * 03 05 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * add the code to get the check rsponse and indicate to app. ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add Security check related code. ++ * ++ * 12 22 2010 cp.wu ++ * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service ++ * Discovery ++ * 1. header file restructure for more clear module isolation ++ * 2. add function interface definition for implementing Service Discovery callbacks ++ * ++*/ ++ ++#ifndef _GL_P2P_KAL_H ++#define _GL_P2P_KAL_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "config.h" ++#include "gl_typedef.h" ++#include "gl_os.h" ++#include "wlan_lib.h" ++#include "wlan_oid.h" ++#include "wlan_p2p.h" ++#include "gl_kal.h" ++#include "gl_wext_priv.h" ++#include "nic/p2p.h" ++ ++#if DBG ++extern int allocatedMemSize; ++#endif ++ ++extern BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++extern BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type); ++struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo); ++ ++/* Service Discovery */ ++VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); ++ ++void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); ++ ++VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus); ++ ++/*----------------------------------------------------------------------------*/ ++/* Wi-Fi Direct handling */ ++/*----------------------------------------------------------------------------*/ ++ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole); ++ ++VOID ++kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); ++ ++UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole); ++ ++VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher); ++ ++BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode); ++ ++UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo); ++ ++UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType); ++ ++VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer); ++ ++VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength); ++ ++BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo); ++ ++VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, ++ IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ ++ IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod); ++ ++VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus); ++ ++VOID ++kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_DEVICE_DESC_T prP2pDevDesc, ++ IN PUINT_8 pucSsid, ++ IN UINT_8 ucSsidLen, ++ IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid); ++ ++struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo); ++ ++VOID ++kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, ++ IN ENUM_BAND_T eSpecificBand, ++ IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); ++ ++#if CFG_SUPPORT_ANTI_PIRACY ++VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID ++kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8SeqNum, ++ IN UINT_32 u4ChannelNum, ++ IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration); ++ ++VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort); ++ ++VOID ++kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, ++ IN PUINT_8 pucFrameBuf, ++ IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength); ++ ++VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); ++ ++VOID ++kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); ++ ++VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); ++ ++VOID ++kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, ++ IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, ++ IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, ++ IN WLAN_STATUS eStatus); ++ ++VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew); ++ ++INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock); ++ ++BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid); ++ ++VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient); ++ ++BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient); ++ ++#endif /* _GL_P2P_KAL_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h +new file mode 100644 +index 000000000000..e5026e7e6eec +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h +@@ -0,0 +1,242 @@ ++/* ++** Id: ++//Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/os/linux/include/gl_p2p_os.h#28 ++*/ ++ ++/*! \file gl_p2p_os.h ++ \brief List the external reference to OS for p2p GLUE Layer. ++ ++ In this file we define the data structure - GLUE_INFO_T to store those objects ++ we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the ++ external reference (header file, extern func() ..) to OS for GLUE Layer should ++ also list down here. ++*/ ++ ++#ifndef _GL_P2P_OS_H ++#define _GL_P2P_OS_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++#include ++#endif ++ ++#include "wlan_oid.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++struct _GL_P2P_INFO_T { ++ ++ /* Device handle */ ++ struct net_device *prDevHandler; ++ ++#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 ++ /* cfg80211 */ ++ struct wireless_dev *prWdev; ++ ++ struct cfg80211_scan_request *prScanRequest; ++ ++ UINT_64 u8Cookie; ++ ++ /* Generation for station list update. */ ++ INT_32 i4Generation; ++ ++ UINT_32 u4OsMgmtFrameFilter; ++ ++#endif ++ ++ /* Device statistics */ ++ struct net_device_stats rNetDevStats; ++ ++ /* glue layer variables */ ++ UINT_32 u4FreqInKHz; /* frequency */ ++ UINT_8 ucRole; /* 0: P2P Device, 1: Group Client, 2: Group Owner */ ++ UINT_8 ucIntent; /* range: 0-15 */ ++ UINT_8 ucScanMode; /* 0: Search & Listen, 1: Scan without probe response */ ++ ++ ENUM_PARAM_MEDIA_STATE_T eState; ++ UINT_32 u4PacketFilter; ++ PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR]; ++ ++ /* connection-requested peer information */ ++ UINT_8 aucConnReqDevName[32]; ++ INT_32 u4ConnReqNameLength; ++ PARAM_MAC_ADDRESS rConnReqPeerAddr; ++ PARAM_MAC_ADDRESS rConnReqGroupAddr; /* For invitation group. */ ++ UINT_8 ucConnReqDevType; ++ INT_32 i4ConnReqConfigMethod; ++ INT_32 i4ConnReqActiveConfigMethod; ++ ++ UINT_32 u4CipherPairwise; ++ UINT_8 ucWSCRunning; ++ ++ UINT_8 aucWSCIE[3][400]; /* 0 for beacon, 1 for probe req, 2 for probe response */ ++ UINT_16 u2WSCIELen[3]; ++ ++#if CFG_SUPPORT_WFD ++ UINT_8 aucVenderIE[1024]; /* Save the other IE for prove resp */ ++ UINT_16 u2VenderIELen; ++#endif ++ ++ UINT_8 ucOperatingChnl; ++ UINT_8 ucInvitationType; ++ ++ UINT_32 u4InvStatus; ++ ++ /* For SET_STRUCT/GET_STRUCT */ ++ UINT_8 aucOidBuf[4096]; ++ ++#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ ++ UINT_8 aucSecCheck[256]; ++ UINT_8 aucSecCheckRsp[256]; ++#endif ++ ++ /* Hotspot Client Management */ ++ PARAM_MAC_ADDRESS aucblackMACList[8]; ++ UINT_8 ucMaxClients; ++ ++#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION ++ UINT_32 u4PsLevel; ++#endif ++}; ++ ++#ifdef CONFIG_NL80211_TESTMODE ++typedef struct _NL80211_DRIVER_TEST_PRE_PARAMS { ++ UINT_16 idx_mode; ++ UINT_16 idx; ++ UINT_32 value; ++} NL80211_DRIVER_TEST_PRE_PARAMS, *P_NL80211_DRIVER_TEST_PRE_PARAMS; ++ ++typedef struct _NL80211_DRIVER_TEST_PARAMS { ++ UINT_32 index; ++ UINT_32 buflen; ++} NL80211_DRIVER_TEST_PARAMS, *P_NL80211_DRIVER_TEST_PARAMS; ++ ++/* P2P Sigma*/ ++typedef struct _NL80211_DRIVER_P2P_SIGMA_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_32 idx; ++ UINT_32 value; ++} NL80211_DRIVER_P2P_SIGMA_PARAMS, *P_NL80211_DRIVER_P2P_SIGMA_PARAMS; ++ ++/* Hotspot Client Management */ ++typedef struct _NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_8 ucblocked; ++ UINT_8 aucBssid[MAC_ADDR_LEN]; ++} NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS, *P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS; ++ ++#if CFG_SUPPORT_WFD ++typedef struct _NL80211_DRIVER_WFD_PARAMS { ++ NL80211_DRIVER_TEST_PARAMS hdr; ++ UINT_32 WfdCmdType; ++ UINT_8 WfdEnable; ++ UINT_8 WfdCoupleSinkStatus; ++ UINT_8 WfdSessionAvailable; ++ UINT_8 WfdSigmaMode; ++ UINT_16 WfdDevInfo; ++ UINT_16 WfdControlPort; ++ UINT_16 WfdMaximumTp; ++ UINT_16 WfdExtendCap; ++ UINT_8 WfdCoupleSinkAddress[MAC_ADDR_LEN]; ++ UINT_8 WfdAssociatedBssid[MAC_ADDR_LEN]; ++ UINT_8 WfdVideoIp[4]; ++ UINT_8 WfdAudioIp[4]; ++ UINT_16 WfdVideoPort; ++ UINT_16 WfdAudioPort; ++ UINT_32 WfdFlag; ++ UINT_32 WfdPolicy; ++ UINT_32 WfdState; ++ UINT_8 WfdSessionInformationIE[24 * 8]; /* Include Subelement ID, length */ ++ UINT_16 WfdSessionInformationIELen; ++ UINT_8 aucReserved1[2]; ++ UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; ++ UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; ++ UINT_32 WfdAdvanceFlag; ++ /* Group 1 64 bytes */ ++ UINT_8 aucWfdLocalIp[4]; ++ UINT_16 WfdLifetimeAc2; /* Unit is 2 TU */ ++ UINT_16 WfdLifetimeAc3; /* Unit is 2 TU */ ++ UINT_16 WfdCounterThreshold; /* Unit is ms */ ++ UINT_8 aucReserved2[54]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReserved3[64]; ++ /* Group 3 64 bytes */ ++ UINT_8 aucReserved4[64]; ++} NL80211_DRIVER_WFD_PARAMS, *P_NL80211_DRIVER_WFD_PARAMS; ++#endif ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo); ++ ++VOID p2pSetMode(IN BOOLEAN fgIsAPMOde); ++ ++BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode); ++ ++VOID p2pEalySuspendReg(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsEnable); ++ ++BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); ++ ++BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); ++ ++BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo); ++ ++BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo); ++ ++VOID glP2pDestroyWirelessDevice(VOID); ++ ++VOID p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo); ++ ++#endif +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h +new file mode 100644 +index 000000000000..f24ceee9e921 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h +@@ -0,0 +1,133 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_rst.h#1 ++*/ ++ ++/*! \file gl_rst.h ++ \brief Declaration of functions and finite state machine for ++ MT6620 Whole-Chip Reset Mechanism ++*/ ++ ++#ifndef _GL_RST_H ++#define _GL_RST_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include "gl_typedef.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++#if 1 ++typedef INT_32(*wmt_wlan_probe_cb) (VOID); ++typedef INT_32(*wmt_wlan_remove_cb) (VOID); ++typedef INT_32(*wmt_wlan_bus_cnt_get_cb) (VOID); ++typedef INT_32(*wmt_wlan_bus_cnt_clr_cb) (VOID); ++ ++typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { ++ wmt_wlan_probe_cb wlan_probe_cb; ++ wmt_wlan_remove_cb wlan_remove_cb; ++ wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; ++ wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; ++} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; ++ ++extern INT_32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); ++extern INT_32 mtk_wcn_wmt_wlan_unreg(VOID); ++#endif ++ ++typedef enum _ENUM_RESET_STATUS_T { ++ RESET_FAIL, ++ RESET_SUCCESS ++} ENUM_RESET_STATUS_T; ++ ++typedef struct _RESET_STRUCT_T { ++ ENUM_RESET_STATUS_T rst_data; ++ struct work_struct rst_work; ++} RESET_STRUCT_T; ++ ++typedef enum _ENUM_WMTRSTMSG_TYPE_T { ++ WMTRSTMSG_RESET_START = 0x0, ++ WMTRSTMSG_RESET_END = 0x1, ++ WMTRSTMSG_RESET_END_FAIL = 0x2, ++ WMTRSTMSG_RESET_MAX, ++ WMTRSTMSG_RESET_INVALID = 0xff ++} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; ++ ++typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ ++ ENUM_WMTDRV_TYPE_T, /* Destination driver type */ ++ ENUM_WMTMSG_TYPE_T, /* Message type */ ++ void *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client ++ can't touch this buffer after this function return. */ ++ unsigned int /* Buffer size in unit of byte */ ++); ++ ++/******************************************************************************* ++* E X T E R N A L F U N C T I O N S ++******************************************************************************** ++*/ ++#define glDoChipReset() \ ++ do { \ ++ if (!kalStrnCmp(current->comm, "mtk_wmtd", 8)) { \ ++ g_IsNeedDoChipReset = 1; \ ++ DBGLOG(INIT, ERROR, "forbid core dump in mtk_wmtd %s line %d\n", __func__, __LINE__); \ ++ break; \ ++ } \ ++ DBGLOG(INIT, ERROR, "Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ ++ mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 0x40); \ ++ } while (0) ++ ++#if CFG_CHIP_RESET_SUPPORT ++extern int mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); ++extern int mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); ++extern int wifi_reset_start(void); ++extern int wifi_reset_end(ENUM_RESET_STATUS_T); ++#endif ++extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); ++extern BOOLEAN mtk_wcn_set_connsys_power_off_flag(BOOLEAN value); ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern UINT_32 g_IsNeedDoChipReset; ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++VOID glResetInit(VOID); ++ ++VOID glResetUninit(VOID); ++ ++VOID glSendResetRequest(VOID); ++ ++BOOLEAN kalIsResetting(VOID); ++ ++#endif /* _GL_RST_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h +new file mode 100644 +index 000000000000..3cc57780f201 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h +@@ -0,0 +1,21 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_sec.h#1 ++*/ ++ ++/*! \file p2p_fsm.h ++ \brief Declaration of functions and finite state machine for P2P Module. ++ ++ Declaration of functions and finite state machine for P2P Module. ++*/ ++ ++#ifndef _GL_SEC_H ++#define _GL_SEC_H ++ ++extern void handle_sec_msg_1(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_2(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_3(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_4(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_5(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++extern void handle_sec_msg_final(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); ++ ++#endif /* _GL_SEC_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h +new file mode 100644 +index 000000000000..e9aa3e849eb2 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h +@@ -0,0 +1,298 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_typedef.h#1 ++*/ ++ ++/*! \file gl_typedef.h ++ \brief Definition of basic data type(os dependent). ++ ++ In this file we define the basic data type. ++*/ ++ ++/* ++** Log: gl_typedef.h ++ * ++ * 06 22 2012 cp.wu ++ * [WCXRP00001257] [MT6620][MT5931][MT6628][Driver][Linux] Modify KAL_HZ to align ms accuracy ++ * modify KAL_HZ to (1000) for correct definition. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * portability improvement ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\6 2009-08-18 22:57:14 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\5 2008-09-22 23:19:30 GMT mtk01461 ++** Update comment for code review ++** \main\maintrunk.MT5921\4 2008-09-05 17:25:16 GMT mtk01461 ++** Update Driver for Code Review ++** \main\maintrunk.MT5921\3 2007-11-09 11:00:50 GMT mtk01425 ++** 1. Use macro to unify network-to-host and host-to-network related functions ++** Revision 1.3 2007/06/27 02:18:51 MTK01461 ++** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API ++** ++** Revision 1.2 2007/06/25 06:16:24 MTK01461 ++** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API ++** ++*/ ++ ++#ifndef _GL_TYPEDEF_H ++#define _GL_TYPEDEF_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* Define HZ of timer tick for function kalGetTimeTick() */ ++#define KAL_HZ (1000) ++ ++/* Miscellaneous Equates */ ++#ifndef FALSE ++#define FALSE ((BOOLEAN) 0) ++#define TRUE ((BOOLEAN) 1) ++#endif /* FALSE */ ++ ++#ifndef NULL ++#if defined(__cplusplus) ++#define NULL 0 ++#else ++#define NULL ((void *) 0) ++#endif ++#endif ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* Type definition for void */ ++/*mach/mt_typedefs.h define _TYPEDEFS_H, to avoid compile error*/ ++#ifndef _TYPEDEFS_H ++typedef void VOID; ++#endif ++typedef void *PVOID, **PPVOID; ++ ++/* Type definition for Boolean */ ++typedef unsigned char BOOLEAN, *PBOOLEAN; ++ ++/* Type definition for signed integers */ ++typedef signed char CHAR, *PCHAR, **PPCHAR; ++typedef signed char INT_8, *PINT_8, **PPINT_8; ++typedef signed short INT_16, *PINT_16, **PPINT_16; ++typedef signed int INT_32, *PINT_32, **PPINT_32; ++typedef long LONG, *PLONG, **PPLONG; ++typedef signed long long INT_64, *PINT_64, **PPINT_64; ++ ++/* Type definition for unsigned integers */ ++typedef unsigned char UCHAR, *PUCHAR, **PPUCHAR; ++typedef unsigned char UINT_8, *PUINT_8, **PPUINT_8, *P_UINT_8; ++typedef unsigned short UINT_16, *PUINT_16, **PPUINT_16; ++typedef unsigned int UINT32, *PUINT32; ++typedef unsigned int UINT_32, *PUINT_32, **PPUINT_32; ++typedef unsigned long ULONG, *PULONG, **PPULONG; ++typedef unsigned long long UINT_64, *PUINT_64, **PPUINT_64; ++ ++typedef unsigned int OS_SYSTIME, *POS_SYSTIME, **PPOS_SYSTIME; ++ ++#ifndef _TYPEDEFS_H ++typedef signed char INT8, *PINT8; ++typedef signed short INT16, *PINT16; ++typedef signed int INT32, *PINT32; ++typedef unsigned char UINT8, *PUINT8; ++typedef unsigned short UINT16, *PUINT16; ++typedef unsigned int UINT32, *PUINT32; ++#endif ++ ++/* Type definition of large integer (64bits) union to be comptaible with ++ * Windows definition, so we won't apply our own coding style to these data types. ++ * NOTE: LARGE_INTEGER must NOT be floating variable. ++ * : Check for big-endian compatibility. ++ */ ++typedef union _LARGE_INTEGER { ++ struct { ++ UINT_32 LowPart; ++ INT_32 HighPart; ++ } u; ++ INT_64 QuadPart; ++} LARGE_INTEGER, *PLARGE_INTEGER; ++ ++typedef union _ULARGE_INTEGER { ++ struct { ++ UINT_32 LowPart; ++ UINT_32 HighPart; ++ } u; ++ UINT_64 QuadPart; ++} ULARGE_INTEGER, *PULARGE_INTEGER; ++ ++typedef INT_32(*probe_card) (PVOID pvData); ++typedef VOID(*remove_card) (VOID); ++ ++/* duplicated from wmt_exp.h for better driver isolation */ ++typedef enum _ENUM_WMTDRV_TYPE_T { ++ WMTDRV_TYPE_BT = 0, ++ WMTDRV_TYPE_FM = 1, ++ WMTDRV_TYPE_GPS = 2, ++ WMTDRV_TYPE_WIFI = 3, ++ WMTDRV_TYPE_WMT = 4, ++ WMTDRV_TYPE_STP = 5, ++ WMTDRV_TYPE_SDIO1 = 6, ++ WMTDRV_TYPE_SDIO2 = 7, ++ WMTDRV_TYPE_LPBK = 8, ++ WMTDRV_TYPE_MAX ++} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; ++ ++typedef enum _ENUM_WMTMSG_TYPE_T { ++ WMTMSG_TYPE_POWER_ON = 0, ++ WMTMSG_TYPE_POWER_OFF = 1, ++ WMTMSG_TYPE_RESET = 2, ++ WMTMSG_TYPE_STP_RDY = 3, ++ WMTMSG_TYPE_HW_FUNC_ON = 4, ++ WMTMSG_TYPE_MAX ++} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; ++ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++#define IN /* volatile */ ++#define OUT /* volatile */ ++ ++#define __KAL_ATTRIB_PACKED__ __attribute__((__packed__)) ++#define __KAL_ATTRIB_ALIGN_4__ __aligned(4) ++ ++#ifndef BIT ++#define BIT(n) ((UINT_32) 1U << (n)) ++#endif /* BIT */ ++ ++#ifndef BITS ++/* bits range: for example BITS(16,23) = 0xFF0000 ++ * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 ++ * ==> (BIT(n+1)-1) = 0x00FFFFFF ++ */ ++#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) ++#endif /* BIT */ ++ ++/* This macro returns the byte offset of a named field in a known structure ++ type. ++ _type - structure name, ++ _field - field name of the structure */ ++#ifndef OFFSET_OF ++#define OFFSET_OF(_type, _field) ((ULONG)&(((_type *)0)->_field)) ++#endif /* OFFSET_OF */ ++ ++/* This macro returns the base address of an instance of a structure ++ * given the type of the structure and the address of a field within the ++ * containing structure. ++ * _addrOfField - address of current field of the structure, ++ * _type - structure name, ++ * _field - field name of the structure ++ */ ++#ifndef ENTRY_OF ++#define ENTRY_OF(_addrOfField, _type, _field) \ ++ ((_type *)((PINT_8)(_addrOfField) - (PINT_8)OFFSET_OF(_type, _field))) ++#endif /* ENTRY_OF */ ++ ++/* This macro align the input value to the DW boundary. ++ * _value - value need to check ++ */ ++#ifndef ALIGN_4 ++#define ALIGN_4(_value) (((_value) + 3) & ~3u) ++#endif /* ALIGN_4 */ ++ ++/* This macro check the DW alignment of the input value. ++ * _value - value of address need to check ++ */ ++#ifndef IS_ALIGN_4 ++#define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE) ++#endif /* IS_ALIGN_4 */ ++ ++#ifndef IS_NOT_ALIGN_4 ++#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE) ++#endif /* IS_NOT_ALIGN_4 */ ++ ++/* This macro evaluate the input length in unit of Double Word(4 Bytes). ++ * _value - value in unit of Byte, output will round up to DW boundary. ++ */ ++#ifndef BYTE_TO_DWORD ++#define BYTE_TO_DWORD(_value) ((_value + 3) >> 2) ++#endif /* BYTE_TO_DWORD */ ++ ++/* This macro evaluate the input length in unit of Byte. ++ * _value - value in unit of DW, output is in unit of Byte. ++ */ ++#ifndef DWORD_TO_BYTE ++#define DWORD_TO_BYTE(_value) ((_value) << 2) ++#endif /* DWORD_TO_BYTE */ ++ ++#if 1 /* Little-Endian */ ++#define CONST_NTOHS(_x) ntohs(_x) ++ ++#define CONST_HTONS(_x) htons(_x) ++ ++#define NTOHS(_x) ntohs(_x) ++ ++#define HTONS(_x) htons(_x) ++ ++#define NTOHL(_x) ntohl(_x) ++ ++#define HTONL(_x) htonl(_x) ++ ++#else /* Big-Endian */ ++ ++#define CONST_NTOHS(_x) ++ ++#define CONST_HTONS(_x) ++ ++#define NTOHS(_x) ++ ++#define HTONS(_x) ++ ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_TYPEDEF_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h +new file mode 100644 +index 000000000000..d8d5b0fb6740 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h +@@ -0,0 +1,619 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_vendor.h#1 ++*/ ++ ++/*! \file gl_vendor.h ++ \brief This file is for Portable Driver linux gl_vendor support. ++*/ ++ ++/* ++** Log: gl_vendor.h ++** ++** 10 14 2014 ++** add vendor declaration ++** ++ * ++*/ ++ ++#ifndef _GL_VENDOR_H ++#define _GL_VENDOR_H ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "gl_os.h" ++ ++#include "wlan_lib.h" ++#include "gl_wext.h" ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define GOOGLE_OUI 0x001A11 ++ ++typedef enum { ++ /* Don't use 0 as a valid subcommand */ ++ ANDROID_NL80211_SUBCMD_UNSPECIFIED, ++ ++ /* Define all vendor startup commands between 0x0 and 0x0FFF */ ++ ANDROID_NL80211_SUBCMD_WIFI_RANGE_START = 0x0001, ++ ANDROID_NL80211_SUBCMD_WIFI_RANGE_END = 0x0FFF, ++ ++ /* Define all GScan related commands between 0x1000 and 0x10FF */ ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, ++ ++ /* Define all RTT related commands between 0x1100 and 0x11FF */ ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, ++ ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, ++ ++ /* Define all Logger related commands between 0x1400 and 0x14FF */ ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400, ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF, ++ ++ /* Define all wifi offload related commands between 0x1600 and 0x16FF */ ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, ++ ++ /* This is reserved for future usage */ ++ ++} ANDROID_VENDOR_SUB_COMMAND; ++ ++typedef enum { ++ WIFI_SUBCMD_GET_CHANNEL_LIST = ANDROID_NL80211_SUBCMD_WIFI_RANGE_START, ++ ++ WIFI_SUBCMD_GET_FEATURE_SET, /* 0x0001 */ ++ WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x0002 */ ++ WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x0003 */ ++ WIFI_SUBCMD_NODFS_SET, /* 0x0004 */ ++ WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x0005 */ ++ /* Add more sub commands here */ ++ ++} WIFI_SUB_COMMAND; ++ ++typedef enum { ++ GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, ++ ++ GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */ ++ GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */ ++ GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */ ++ GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */ ++ GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */ ++ ++ GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */ ++ ++ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */ ++ GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */ ++ /* Add more sub commands here */ ++ ++} GSCAN_SUB_COMMAND; ++ ++typedef enum { ++ RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, ++ RTT_SUBCMD_CANCEL_CONFIG, ++ RTT_SUBCMD_GETCAPABILITY, ++} RTT_SUB_COMMAND; ++ ++typedef enum { ++ LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, ++} LSTATS_SUB_COMMAND; ++ ++typedef enum { ++ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, ++ GSCAN_EVENT_HOTLIST_RESULTS_FOUND, ++ GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, ++ GSCAN_EVENT_FULL_SCAN_RESULTS, ++ RTT_EVENT_COMPLETE, ++ GSCAN_EVENT_COMPLETE_SCAN, ++ GSCAN_EVENT_HOTLIST_RESULTS_LOST ++} WIFI_VENDOR_EVENT; ++ ++typedef enum { ++ WIFI_ATTRIBUTE_BAND, ++ WIFI_ATTRIBUTE_NUM_CHANNELS, ++ WIFI_ATTRIBUTE_CHANNEL_LIST, ++ ++ WIFI_ATTRIBUTE_NUM_FEATURE_SET, ++ WIFI_ATTRIBUTE_FEATURE_SET, ++ WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, ++ WIFI_ATTRIBUTE_NODFS_VALUE, ++ WIFI_ATTRIBUTE_COUNTRY_CODE ++ ++} WIFI_ATTRIBUTE; ++ ++typedef enum { ++ GSCAN_ATTRIBUTE_CAPABILITIES = 1, ++ ++ GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, ++ GSCAN_ATTRIBUTE_BASE_PERIOD, ++ GSCAN_ATTRIBUTE_BUCKETS_BAND, ++ GSCAN_ATTRIBUTE_BUCKET_ID, ++ GSCAN_ATTRIBUTE_BUCKET_PERIOD, ++ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, ++ GSCAN_ATTRIBUTE_BUCKET_CHANNELS, ++ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, ++ GSCAN_ATTRIBUTE_REPORT_THRESHOLD, ++ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, ++ ++ GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, ++ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ ++ GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ ++ GSCAN_ENABLE_FULL_SCAN_RESULTS, ++ GSCAN_ATTRIBUTE_REPORT_EVENTS, ++ ++ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, ++ GSCAN_ATTRIBUTE_FLUSH_RESULTS, ++ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ ++ GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ ++ GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ ++ GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ ++ ++ GSCAN_ATTRIBUTE_SSID = 40, ++ GSCAN_ATTRIBUTE_BSSID, ++ GSCAN_ATTRIBUTE_CHANNEL, ++ GSCAN_ATTRIBUTE_RSSI, ++ GSCAN_ATTRIBUTE_TIMESTAMP, ++ GSCAN_ATTRIBUTE_RTT, ++ GSCAN_ATTRIBUTE_RTTSD, ++ ++ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, ++ GSCAN_ATTRIBUTE_RSSI_LOW, ++ GSCAN_ATTRIBUTE_RSSI_HIGH, ++ GSCAN_ATTRIBUTE_HOTLIST_ELEM, ++ GSCAN_ATTRIBUTE_HOTLIST_FLUSH, ++ ++ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, ++ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, ++ GSCAN_ATTRIBUTE_MIN_BREACHING, ++ GSCAN_ATTRIBUTE_NUM_AP, ++ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, ++ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH ++ ++} GSCAN_ATTRIBUTE; ++ ++typedef enum { ++ RTT_ATTRIBUTE_CAPABILITIES = 1, ++ ++ RTT_ATTRIBUTE_TARGET_CNT = 10, ++ RTT_ATTRIBUTE_TARGET_INFO, ++ RTT_ATTRIBUTE_TARGET_MAC, ++ RTT_ATTRIBUTE_TARGET_TYPE, ++ RTT_ATTRIBUTE_TARGET_PEER, ++ RTT_ATTRIBUTE_TARGET_CHAN, ++ RTT_ATTRIBUTE_TARGET_PERIOD, ++ RTT_ATTRIBUTE_TARGET_NUM_BURST, ++ RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, ++ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, ++ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, ++ RTT_ATTRIBUTE_TARGET_LCI, ++ RTT_ATTRIBUTE_TARGET_LCR, ++ RTT_ATTRIBUTE_TARGET_BURST_DURATION, ++ RTT_ATTRIBUTE_TARGET_PREAMBLE, ++ RTT_ATTRIBUTE_TARGET_BW, ++ RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, ++ RTT_ATTRIBUTE_RESULTS_PER_TARGET, ++ RTT_ATTRIBUTE_RESULT_CNT, ++ RTT_ATTRIBUTE_RESULT ++} RTT_ATTRIBUTE; ++ ++typedef enum { ++ LSTATS_ATTRIBUTE_STATS = 2, ++} LSTATS_ATTRIBUTE; ++ ++typedef enum { ++ WIFI_BAND_UNSPECIFIED, ++ WIFI_BAND_BG = 1, /* 2.4 GHz */ ++ WIFI_BAND_A = 2, /* 5 GHz without DFS */ ++ WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ ++ WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ ++ WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ ++ WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ ++} WIFI_BAND; ++ ++typedef enum { ++ WIFI_SCAN_BUFFER_FULL, ++ WIFI_SCAN_COMPLETE, ++} WIFI_SCAN_EVENT; ++ ++#define GSCAN_MAX_REPORT_THRESHOLD 1024000 ++#define GSCAN_MAX_CHANNELS 8 ++#define GSCAN_MAX_BUCKETS 8 ++#define MAX_HOTLIST_APS 16 ++#define MAX_SIGNIFICANT_CHANGE_APS 16 ++#define PSCAN_MAX_SCAN_CACHE_SIZE 16 ++#define PSCAN_MAX_AP_CACHE_PER_SCAN 16 ++#define PSCAN_VERSION 1 ++ ++#define MAX_BUFFERED_GSCN_RESULTS 5 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef UINT_64 wifi_timestamp; /* In microseconds (us) */ ++typedef UINT_64 wifi_timespan; /* In nanoseconds (ns) */ ++ ++typedef UINT_8 mac_addr[6]; ++typedef UINT_32 wifi_channel; /* Indicates channel frequency in MHz */ ++typedef INT_32 wifi_rssi; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++typedef struct _PARAM_WIFI_GSCAN_GET_RESULT_PARAMS { ++ UINT_32 get_num; ++ UINT_8 flush; ++} PARAM_WIFI_GSCAN_GET_RESULT_PARAMS, *P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS { ++ UINT_8 ucPscanAct; ++ UINT_8 aucReserved[3]; ++} PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T { ++ UINT_32 max_scan_cache_size; /* total space allocated for scan (in bytes) */ ++ UINT_32 max_scan_buckets; /* maximum number of channel buckets */ ++ UINT_32 max_ap_cache_per_scan; /* maximum number of APs that can be stored per scan */ ++ UINT_32 max_rssi_sample_size; /* number of RSSI samples used for averaging RSSI */ ++ UINT_32 max_scan_reporting_threshold; /* max possible report_threshold as described */ ++ /* in wifi_scan_cmd_params */ ++ UINT_32 max_hotlist_aps; /* maximum number of entries for hotlist APs */ ++ UINT_32 max_significant_wifi_change_aps; /* maximum number of entries for */ ++ /* significant wifi change APs */ ++ UINT_32 max_bssid_history_entries; /* number of BSSID/RSSI entries that device can hold */ ++} PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T, *P_PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T; ++ ++typedef struct _PARAM_WIFI_GSCAN_CHANNEL_SPEC { ++ UINT_32 channel; /* frequency */ ++ UINT_32 dwellTimeMs; /* dwell time hint */ ++ UINT_32 passive; /* 0 => active, 1 => passive scan; ignored for DFS */ ++ /* Add channel class */ ++} PARAM_WIFI_GSCAN_CHANNEL_SPEC, *P_PARAM_WIFI_GSCAN_CHANNEL_SPEC; ++ ++typedef struct _PARAM_WIFI_GSCAN_BUCKET_SPEC { ++ UINT_32 bucket; /* bucket index, 0 based */ ++ WIFI_BAND band; /* when UNSPECIFIED, use channel list */ ++ UINT_32 period; /* desired period, in millisecond; if this is too */ ++ /* low, the firmware should choose to generate results as */ ++ /* fast as it can instead of failing the command */ ++ /* report_events semantics - ++ * 0 => report only when scan history is % full ++ * 1 => same as 0 + report a scan completion event after scanning this bucket ++ * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL ++ * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to ++ supplicant as well (optional) . */ ++ UINT_8 report_events; ++ ++ UINT_32 num_channels; ++ PARAM_WIFI_GSCAN_CHANNEL_SPEC channels[GSCAN_MAX_CHANNELS]; /* channels to scan; ++ these may include DFS channels */ ++} PARAM_WIFI_GSCAN_BUCKET_SPEC, *P_PARAM_WIFI_GSCAN_BUCKET_SPEC; ++ ++typedef struct _PARAM_WIFI_GSCAN_CMD_PARAMS { ++ UINT_32 base_period; /* base timer period in ms */ ++ UINT_32 max_ap_per_scan; /* number of APs to store in each scan in the */ ++ /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ ++ UINT_32 report_threshold; /* in %, when scan buffer is this much full, wake up AP */ ++ UINT_32 num_scans; ++ UINT_32 num_buckets; ++ PARAM_WIFI_GSCAN_BUCKET_SPEC buckets[GSCAN_MAX_BUCKETS]; ++} PARAM_WIFI_GSCAN_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_CMD_PARAMS; ++ ++typedef struct _PARAM_WIFI_GSCAN_RESULT { ++ wifi_timestamp ts; /* time since boot (in microsecond) when the result was */ ++ /* retrieved */ ++ UINT_8 ssid[32 + 1]; /* null terminated */ ++ mac_addr bssid; ++ wifi_channel channel; /* channel frequency in MHz */ ++ wifi_rssi rssi; /* in db */ ++ wifi_timespan rtt; /* in nanoseconds */ ++ wifi_timespan rtt_sd; /* standard deviation in rtt */ ++ UINT_16 beacon_period; /* period advertised in the beacon */ ++ UINT_16 capability; /* capabilities advertised in the beacon */ ++ UINT_32 ie_length; /* size of the ie_data blob */ ++ UINT_8 ie_data[1]; /* blob of all the information elements found in the */ ++ /* beacon; this data should be a packed list of */ ++ /* wifi_information_element objects, one after the other. */ ++ /* other fields */ ++} PARAM_WIFI_GSCAN_RESULT, *P_PARAM_WIFI_GSCAN_RESULT; ++ ++/* Significant wifi change*/ ++/*typedef struct _PARAM_WIFI_CHANGE_RESULT{ ++ mac_addr bssid; // BSSID ++ wifi_channel channel; // channel frequency in MHz ++ UINT_32 num_rssi; // number of rssi samples ++ wifi_rssi rssi[8]; // RSSI history in db ++} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT;*/ ++ ++typedef struct _PARAM_WIFI_CHANGE_RESULT { ++ UINT_16 flags; ++ UINT_16 channel; ++ mac_addr bssid; /* BSSID */ ++ INT_8 rssi[8]; /* RSSI history in db */ ++} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT; ++ ++typedef struct _PARAM_AP_THRESHOLD { ++ mac_addr bssid; /* AP BSSID */ ++ wifi_rssi low; /* low threshold */ ++ wifi_rssi high; /* high threshold */ ++ wifi_channel channel; /* channel hint */ ++} PARAM_AP_THRESHOLD, *P_PARAM_AP_THRESHOLD; ++ ++typedef struct _PARAM_WIFI_BSSID_HOTLIST { ++ UINT_32 lost_ap_sample_size; ++ UINT_32 num_ap; /* number of hotlist APs */ ++ PARAM_AP_THRESHOLD ap[MAX_HOTLIST_APS]; /* hotlist APs */ ++} PARAM_WIFI_BSSID_HOTLIST, *P_PARAM_WIFI_BSSID_HOTLIST; ++ ++typedef struct _PARAM_WIFI_SIGNIFICANT_CHANGE { ++ UINT_16 rssi_sample_size; /* number of samples for averaging RSSI */ ++ UINT_16 lost_ap_sample_size; /* number of samples to confirm AP loss */ ++ UINT_16 min_breaching; /* number of APs breaching threshold */ ++ UINT_16 num_ap; /* max 64 */ ++ PARAM_AP_THRESHOLD ap[MAX_SIGNIFICANT_CHANGE_APS]; ++} PARAM_WIFI_SIGNIFICANT_CHANGE, *P_PARAM_WIFI_SIGNIFICANT_CHANGE; ++ ++/* RTT Capabilities */ ++typedef struct _PARAM_WIFI_RTT_CAPABILITIES { ++ UINT_8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ ++ UINT_8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ ++ UINT_8 lci_support; /* if initiator supports LCI request. Applies to 2-sided RTT */ ++ UINT_8 lcr_support; /* if initiator supports LCR request. Applies to 2-sided RTT */ ++ UINT_8 preamble_support; /* bit mask indicates what preamble is supported by initiator */ ++ UINT_8 bw_support; /* bit mask indicates what BW is supported by initiator */ ++} PARAM_WIFI_RTT_CAPABILITIES, *P_PARAM_WIFI_RTT_CAPABILITIES; ++ ++/* channel operating width */ ++typedef enum { ++ WIFI_CHAN_WIDTH_20 = 0, ++ WIFI_CHAN_WIDTH_40 = 1, ++ WIFI_CHAN_WIDTH_80 = 2, ++ WIFI_CHAN_WIDTH_160 = 3, ++ WIFI_CHAN_WIDTH_80P80 = 4, ++ WIFI_CHAN_WIDTH_5 = 5, ++ WIFI_CHAN_WIDTH_10 = 6, ++ WIFI_CHAN_WIDTH_INVALID = -1 ++} WIFI_CHANNEL_WIDTH; ++ ++/* channel information */ ++typedef struct { ++ WIFI_CHANNEL_WIDTH width; /* channel width (20, 40, 80, 80+80, 160) */ ++ UINT_32 center_freq; /* primary 20 MHz channel */ ++ UINT_32 center_freq0; /* center frequency (MHz) first segment */ ++ UINT_32 center_freq1; /* center frequency (MHz) second segment */ ++} WIFI_CHANNEL_INFO; ++ ++/* channel statistics */ ++typedef struct { ++ WIFI_CHANNEL_INFO channel; /* channel */ ++ UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ ++ UINT_32 cca_busy_time; /* msecs the CCA register is busy (32 bits number accruing over time) */ ++} WIFI_CHANNEL_STAT; ++ ++/* radio statistics */ ++typedef struct { ++ UINT_32 radio; /* wifi radio (if multiple radio supported) */ ++ UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ ++ UINT_32 tx_time; /* msecs the radio is transmitting (32 bits number accruing over time) */ ++ UINT_32 rx_time; /* msecs the radio is in active receive (32 bits number accruing over time) */ ++ UINT_32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits number accruing over time) */ ++ UINT_32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits number accruing over time) */ ++ UINT_32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits number accruing over time) */ ++ UINT_32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan ++ (32 bits number accruing over time) */ ++ UINT_32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan ++ (32 bits number accruing over time) */ ++ UINT_32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and GAS exchange ++ 32 bits number accruing over time) */ ++ UINT_32 num_channels; /* number of channels */ ++ WIFI_CHANNEL_STAT channels[]; /* channel statistics */ ++} WIFI_RADIO_STAT; ++ ++/* wifi rate */ ++typedef struct { ++ UINT_32 preamble:3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ ++ UINT_32 nss:2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ ++ UINT_32 bw:3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ ++ UINT_32 rateMcsIdx:8; /* OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps */ ++ /* HT/VHT it would be mcs index */ ++ UINT_32 reserved:16; /* reserved */ ++ UINT_32 bitrate; /* units of 100 Kbps */ ++} WIFI_RATE; ++ ++/* per rate statistics */ ++typedef struct { ++ WIFI_RATE rate; /* rate information */ ++ UINT_32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ ++ UINT_32 rx_mpdu; /* number of received data pkts */ ++ UINT_32 mpdu_lost; /* number of data packet losses (no ACK) */ ++ UINT_32 retries; /* total number of data pkt retries */ ++ UINT_32 retries_short; /* number of short data pkt retries */ ++ UINT_32 retries_long; /* number of long data pkt retries */ ++} WIFI_RATE_STAT; ++ ++/*wifi_interface_link_layer_info*/ ++typedef enum { ++ WIFI_DISCONNECTED = 0, ++ WIFI_AUTHENTICATING = 1, ++ WIFI_ASSOCIATING = 2, ++ WIFI_ASSOCIATED = 3, ++ WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ ++ WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ ++} WIFI_CONNECTION_STATE; ++ ++typedef enum { ++ WIFI_ROAMING_IDLE = 0, ++ WIFI_ROAMING_ACTIVE = 1, ++} WIFI_ROAM_STATE; ++ ++typedef enum { ++ WIFI_INTERFACE_STA = 0, ++ WIFI_INTERFACE_SOFTAP = 1, ++ WIFI_INTERFACE_IBSS = 2, ++ WIFI_INTERFACE_P2P_CLIENT = 3, ++ WIFI_INTERFACE_P2P_GO = 4, ++ WIFI_INTERFACE_NAN = 5, ++ WIFI_INTERFACE_MESH = 6, ++ WIFI_INTERFACE_UNKNOWN = -1 ++} WIFI_INTERFACE_MODE; ++ ++typedef struct { ++ WIFI_INTERFACE_MODE mode; /* interface mode */ ++ u8 mac_addr[6]; /* interface mac address (self) */ ++ WIFI_CONNECTION_STATE state; /* connection state (valid for STA, CLI only) */ ++ WIFI_ROAM_STATE roaming; /* roaming state */ ++ u32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ ++ u8 ssid[33]; /* null terminated SSID */ ++ u8 bssid[6]; /* bssid */ ++ u8 ap_country_str[3]; /* country string advertised by AP */ ++ u8 country_str[3]; /* country string for this association */ ++} WIFI_INTERFACE_LINK_LAYER_INFO; ++ ++/* access categories */ ++typedef enum { ++ WIFI_AC_VO = 0, ++ WIFI_AC_VI = 1, ++ WIFI_AC_BE = 2, ++ WIFI_AC_BK = 3, ++ WIFI_AC_MAX = 4, ++} WIFI_TRAFFIC_AC; ++ ++/* wifi peer type */ ++typedef enum { ++ WIFI_PEER_STA, ++ WIFI_PEER_AP, ++ WIFI_PEER_P2P_GO, ++ WIFI_PEER_P2P_CLIENT, ++ WIFI_PEER_NAN, ++ WIFI_PEER_TDLS, ++ WIFI_PEER_INVALID, ++} WIFI_PEER_TYPE; ++ ++/* per peer statistics */ ++typedef struct { ++ WIFI_PEER_TYPE type; /* peer type (AP, TDLS, GO etc.) */ ++ UINT_8 peer_mac_address[6]; /* mac address */ ++ UINT_32 capabilities; /* peer WIFI_CAPABILITY_XXX */ ++ UINT_32 num_rate; /* number of rates */ ++ WIFI_RATE_STAT rate_stats[]; /* per rate statistics, number of entries = num_rate */ ++} WIFI_PEER_INFO; ++ ++/* per access category statistics */ ++typedef struct { ++ WIFI_TRAFFIC_AC ac; /* access category (VI, VO, BE, BK) */ ++ UINT_32 tx_mpdu; /* number of successfully transmitted unicast data pkts (ACK rcvd) */ ++ UINT_32 rx_mpdu; /* number of received unicast mpdus */ ++ UINT_32 tx_mcast; /* number of successfully transmitted multicast data packets */ ++ /* STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent */ ++ UINT_32 rx_mcast; /* number of received multicast data packets */ ++ UINT_32 rx_ampdu; /* number of received unicast a-mpdus */ ++ UINT_32 tx_ampdu; /* number of transmitted unicast a-mpdus */ ++ UINT_32 mpdu_lost; /* number of data pkt losses (no ACK) */ ++ UINT_32 retries; /* total number of data pkt retries */ ++ UINT_32 retries_short; /* number of short data pkt retries */ ++ UINT_32 retries_long; /* number of long data pkt retries */ ++ UINT_32 contention_time_min; /* data pkt min contention time (usecs) */ ++ UINT_32 contention_time_max; /* data pkt max contention time (usecs) */ ++ UINT_32 contention_time_avg; /* data pkt avg contention time (usecs) */ ++ UINT_32 contention_num_samples; /* num of data pkts used for contention statistics */ ++} WIFI_WMM_AC_STAT; ++ ++/* interface statistics */ ++typedef struct { ++ /* wifi_interface_handle iface; // wifi interface */ ++ WIFI_INTERFACE_LINK_LAYER_INFO info; /* current state of the interface */ ++ UINT_32 beacon_rx; /* access point beacon received count from connected AP */ ++ UINT_32 mgmt_rx; /* access point mgmt frames received count from connected AP (including Beacon) */ ++ UINT_32 mgmt_action_rx; /* action frames received count */ ++ UINT_32 mgmt_action_tx; /* action frames transmit count */ ++ wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI (averaged) */ ++ wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from connected AP */ ++ wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from connected AP */ ++ WIFI_WMM_AC_STAT ac[WIFI_AC_MAX]; /* per ac data packet statistics */ ++ UINT_32 num_peers; /* number of peers */ ++ WIFI_PEER_INFO peer_info[]; /* per peer statistics */ ++} WIFI_IFACE_STAT; ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, ++ const void *data, int data_len); ++ ++int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete); ++ ++int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num); ++ ++int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, ++ P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); ++ ++#endif /* _GL_VENDOR_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h +new file mode 100644 +index 000000000000..827ff92b1581 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h +@@ -0,0 +1,357 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext.h#1 ++*/ ++ ++/*! \file gl_wext.h ++ \brief This file is for Portable Driver linux wireless extension support. ++*/ ++ ++/* ++** Log: gl_wext.h ++ * ++ * 10 12 2011 wh.su ++ * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP ++ * adding the 802.11w related function and define . ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 09 20 2011 chinglan.wang ++ * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. ++ * . ++ * ++ * 01 11 2011 chinglan.wang ++ * NULL ++ * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. ++ * Connection establish successfully. ++ * Use the WPS function to connect AP, the privacy bit always is set to 1. . ++ * ++ * 09 27 2010 wh.su ++ * NULL ++ * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\12 2009-10-20 17:38:33 GMT mtk01090 ++** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, ++** and then stop hw. ++** \main\maintrunk.MT5921\11 2009-09-28 20:19:28 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\10 2009-09-03 12:12:35 GMT mtk01088 ++** adding the function declaration ++** \main\maintrunk.MT5921\9 2009-08-18 22:57:17 GMT mtk01090 ++** Add Linux SDIO (with mmc core) support. ++** Add Linux 2.6.21, 2.6.25, 2.6.26. ++** Fix compile warning in Linux. ++** \main\maintrunk.MT5921\8 2008-08-29 16:59:07 GMT mtk01088 ++** fixed compiling error ++** \main\maintrunk.MT5921\7 2008-08-29 14:13:28 GMT mtk01088 ++** adjust the header file for code refine ++** \main\maintrunk.MT5921\6 2008-03-28 10:40:31 GMT mtk01461 ++** Add set desired rate in Linux STD IOCTL ++** \main\maintrunk.MT5921\5 2008-03-11 14:51:08 GMT mtk01461 ++** Refine private IOCTL functions ++** \main\maintrunk.MT5921\4 2008-02-12 23:45:45 GMT mtk01461 ++** Add Set Frequency & Channel oid support for Linux ++** \main\maintrunk.MT5921\3 2007-11-06 19:36:19 GMT mtk01088 ++** add the WPS related code ++*/ ++ ++#ifndef _GL_WEXT_H ++#define _GL_WEXT_H ++ ++#ifdef WIRELESS_EXT ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define KILO 1000 ++#define RATE_5_5M 11 /* 5.5M */ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef struct _PARAM_FIXED_IEs { ++ UINT_8 aucTimestamp[8]; ++ UINT_16 u2BeaconInterval; ++ UINT_16 u2Capabilities; ++} PARAM_FIXED_IEs; ++ ++typedef struct _PARAM_VARIABLE_IE_T { ++ UINT_8 ucElementID; ++ UINT_8 ucLength; ++ UINT_8 aucData[1]; ++} PARAM_VARIABLE_IE_T, *P_PARAM_VARIABLE_IE_T; ++ ++#if WIRELESS_EXT < 18 ++ ++#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses struct iw_mlme */ ++/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ ++#define IW_MLME_DEAUTH 0 ++#define IW_MLME_DISASSOC 1 ++ ++/*! \brief SIOCSIWMLME data */ ++struct iw_mlme { ++ __u16 cmd; /*!< IW_MLME_* */ ++ __u16 reason_code; ++ struct sockaddr addr; ++}; ++ ++#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ ++#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ ++/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ ++#define IW_AUTH_INDEX 0x0FFF ++#define IW_AUTH_FLAGS 0xF000 ++/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) ++ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the ++ * parameter that is being set/get to; value will be read/written to ++ * struct iw_param value field) */ ++#define IW_AUTH_WPA_VERSION 0 ++#define IW_AUTH_CIPHER_PAIRWISE 1 ++#define IW_AUTH_CIPHER_GROUP 2 ++#define IW_AUTH_KEY_MGMT 3 ++#define IW_AUTH_TKIP_COUNTERMEASURES 4 ++#define IW_AUTH_DROP_UNENCRYPTED 5 ++#define IW_AUTH_80211_AUTH_ALG 6 ++#define IW_AUTH_WPA_ENABLED 7 ++#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 ++#define IW_AUTH_ROAMING_CONTROL 9 ++#define IW_AUTH_PRIVACY_INVOKED 10 ++#if CFG_SUPPORT_802_11W ++#define IW_AUTH_MFP 12 ++ ++#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ ++#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ ++#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ ++#endif ++ ++/* IW_AUTH_WPA_VERSION values (bit field) */ ++#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 ++#define IW_AUTH_WPA_VERSION_WPA 0x00000002 ++#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 ++ ++/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ ++#define IW_AUTH_CIPHER_NONE 0x00000001 ++#define IW_AUTH_CIPHER_WEP40 0x00000002 ++#define IW_AUTH_CIPHER_TKIP 0x00000004 ++#define IW_AUTH_CIPHER_CCMP 0x00000008 ++#define IW_AUTH_CIPHER_WEP104 0x00000010 ++ ++/* IW_AUTH_KEY_MGMT values (bit field) */ ++#define IW_AUTH_KEY_MGMT_802_1X 1 ++#define IW_AUTH_KEY_MGMT_PSK 2 ++#define IW_AUTH_KEY_MGMT_WPA_NONE 4 ++ ++/* IW_AUTH_80211_AUTH_ALG values (bit field) */ ++#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 ++#define IW_AUTH_ALG_SHARED_KEY 0x00000002 ++#define IW_AUTH_ALG_LEAP 0x00000004 ++ ++/* IW_AUTH_ROAMING_CONTROL values */ ++#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ ++#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming ++ * control */ ++ ++#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ ++#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ ++/* SIOCSIWENCODEEXT definitions */ ++#define IW_ENCODE_SEQ_MAX_SIZE 8 ++/* struct iw_encode_ext ->alg */ ++#define IW_ENCODE_ALG_NONE 0 ++#define IW_ENCODE_ALG_WEP 1 ++#define IW_ENCODE_ALG_TKIP 2 ++#define IW_ENCODE_ALG_CCMP 3 ++#if CFG_SUPPORT_802_11W ++#define IW_ENCODE_ALG_AES_CMAC 5 ++#endif ++ ++/* struct iw_encode_ext ->ext_flags */ ++#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 ++#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 ++#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 ++#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 ++ ++struct iw_encode_ext { ++ __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ ++ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ ++ struct sockaddr addr; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast ++ * (group) keys or unicast address for ++ * individual keys */ ++ __u16 alg; /*!< IW_ENCODE_ALG_* */ ++ __u16 key_len; ++ __u8 key[0]; ++}; ++ ++#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ ++#define IW_PMKSA_ADD 1 ++#define IW_PMKSA_REMOVE 2 ++#define IW_PMKSA_FLUSH 3 ++ ++#define IW_PMKID_LEN 16 ++ ++struct iw_pmksa { ++ __u32 cmd; /*!< IW_PMKSA_* */ ++ struct sockaddr bssid; ++ __u8 pmkid[IW_PMKID_LEN]; ++}; ++ ++#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) ++ * (scan results); This includes id and ++ * length fields. One IWEVGENIE may ++ * contain more than one IE. Scan ++ * results may contain one or more ++ * IWEVGENIE events. */ ++#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure ++ * (struct iw_michaelmicfailure) ++ */ ++#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. ++ * The data includes id and length ++ * fields and may contain more than one ++ * IE. This event is required in ++ * Managed mode if the driver ++ * generates its own WPA/RSN IE. This ++ * should be sent just before ++ * IWEVREGISTERED event for the ++ * association. */ ++#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association ++ * Response. The data includes id and ++ * length fields and may contain more ++ * than one IE. This may be sent ++ * between IWEVASSOCREQIE and ++ * IWEVREGISTERED events for the ++ * association. */ ++#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN ++ * pre-authentication ++ * (struct iw_pmkid_cand) */ ++ ++#endif /* WIRELESS_EXT < 18 */ ++ ++#if WIRELESS_EXT < 17 ++/* Statistics flags (bitmask in updated) */ ++#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */ ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#endif ++ ++enum { ++ IEEE80211_FILTER_TYPE_BEACON = 1 << 0, ++ IEEE80211_FILTER_TYPE_PROBE_REQ = 1 << 1, ++ IEEE80211_FILTER_TYPE_PROBE_RESP = 1 << 2, ++ IEEE80211_FILTER_TYPE_ASSOC_REQ = 1 << 3, ++ IEEE80211_FILTER_TYPE_ASSOC_RESP = 1 << 4, ++ IEEE80211_FILTER_TYPE_AUTH = 1 << 5, ++ IEEE80211_FILTER_TYPE_DEAUTH = 1 << 6, ++ IEEE80211_FILTER_TYPE_DISASSOC = 1 << 7, ++ IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */ ++}; ++ ++#if CFG_SUPPORT_WAPI ++#define IW_AUTH_WAPI_ENABLED 0x20 ++#define IW_ENCODE_ALG_SMS4 0x20 ++#endif ++ ++#if CFG_SUPPORT_WAPI /* Android+ */ ++#define IW_AUTH_KEY_MGMT_WAPI_PSK 3 ++#define IW_AUTH_KEY_MGMT_WAPI_CERT 4 ++#endif ++#define IW_AUTH_KEY_MGMT_WPS 5 ++ ++#if CFG_SUPPORT_802_11W ++#define IW_AUTH_KEY_MGMT_802_1X_SHA256 7 ++#define IW_AUTH_KEY_MGMT_PSK_SHA256 8 ++#endif ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++extern const struct iw_handler_def wext_handler_def; ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++/* wireless extensions' ioctls */ ++int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd); ++ ++int ++wext_set_rate(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra); ++ ++void ++wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, ++ IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4DataLen); ++ ++struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev); ++ ++BOOLEAN ++wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++ ++#if CFG_SUPPORT_WPS ++BOOLEAN ++wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, ++ IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++ ++BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++#if CFG_SUPPORT_WAPI ++BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); ++#endif ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* WIRELESS_EXT */ ++ ++#endif /* _GL_WEXT_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h +new file mode 100644 +index 000000000000..31933fc6a461 +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h +@@ -0,0 +1,402 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext_priv.h#3 ++*/ ++ ++/*! \file gl_wext_priv.h ++ \brief This file includes private ioctl support. ++*/ ++ ++/* ++** Log: gl_wext_priv.h ++ * ++ * 01 16 2012 wh.su ++ * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl ++ * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. ++ * ++ * 01 05 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the related ioctl / wlan oid function to set the Tx power cfg. ++ * ++ * 01 02 2012 wh.su ++ * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function ++ * Adding the proto type function for set_int set_tx_power and get int get_ch_list. ++ * ++ * 11 08 2011 yuche.tsai ++ * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service ++ * discovery version check. ++ * Add a CMD ID for P2P driver version query. ++ * ++ * 03 17 2011 chinglan.wang ++ * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature ++ * . ++ * ++ * 03 02 2011 wh.su ++ * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code ++ * Add security check code. ++ * ++ * 01 27 2011 cm.chang ++ * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default ++ * . ++ * ++ * 01 20 2011 eddie.chen ++ * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control ++ * Add Oid for sw control debug command ++ * ++ * 01 07 2011 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add a new compiling option to control if MCR read/write is permitted ++ * ++ * 12 31 2010 cm.chang ++ * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation ++ * Add some iwpriv commands to support test mode operation ++ * ++ * 11 08 2010 wh.su ++ * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 ++ * add the message check code from mt5921. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 09 23 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * add skeleton for NVRAM integration ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * revert changelist #15371, efuse read/write access will be done by RF test approach ++ * ++ * 08 04 2010 cp.wu ++ * NULL ++ * add OID definitions for EFUSE read/write access. ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++ * ++ * 03 31 2010 wh.su ++ * [WPD00003816][MT6620 Wi-Fi] Adding the security support ++ * modify the wapi related code for new driver's design. ++ * ++ * 03 24 2010 jeffrey.chang ++ * [WPD00003826]Initial import for Linux port ++ * initial import for Linux port ++** \main\maintrunk.MT5921\16 2009-09-29 16:47:23 GMT mtk01090 ++** Remove unused functions ++** \main\maintrunk.MT5921\15 2009-09-28 20:19:31 GMT mtk01090 ++** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. ++** \main\maintrunk.MT5921\14 2009-05-07 22:26:06 GMT mtk01089 ++** add private IO control for Linux BWCS ++** \main\maintrunk.MT5921\13 2008-08-29 14:55:20 GMT mtk01088 ++** adjust the code to meet coding style ++** \main\maintrunk.MT5921\12 2008-07-16 15:23:45 GMT mtk01104 ++** Support GPIO2 mode ++** \main\maintrunk.MT5921\11 2008-07-14 13:55:58 GMT mtk01104 ++** Support PRIV_CMD_BT_COEXIST ++** \main\maintrunk.MT5921\10 2008-07-09 00:20:24 GMT mtk01461 ++** Add priv oid to support WMM_PS_TEST ++** \main\maintrunk.MT5921\9 2008-05-30 20:27:24 GMT mtk01461 ++** Add POWER_MODE Private IOCTL cmd ++** \main\maintrunk.MT5921\8 2008-04-17 23:06:44 GMT mtk01461 ++** Add iwpriv support for AdHocMode setting ++** \main\maintrunk.MT5921\7 2008-03-31 21:01:24 GMT mtk01461 ++** Add priv IOCTL for VOIP settings ++** \main\maintrunk.MT5921\6 2008-03-31 13:49:47 GMT mtk01461 ++** add priv ioctl arg definition for turning on / off roaming ++** \main\maintrunk.MT5921\5 2008-03-26 15:35:09 GMT mtk01461 ++** Add CSUM offload priv ioctl for Linux ++** \main\maintrunk.MT5921\4 2008-03-11 14:51:11 GMT mtk01461 ++** Refine private IOCTL functions ++** \main\maintrunk.MT5921\3 2007-11-06 19:36:25 GMT mtk01088 ++** add the WPS related code ++*/ ++ ++#ifndef _GL_WEXT_PRIV_H ++#define _GL_WEXT_PRIV_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++/* If it is set to 1, iwpriv will support register read/write */ ++#define CFG_SUPPORT_PRIV_MCR_RW 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++#if CFG_ENABLE_WIFI_DIRECT ++extern int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); ++#if 0 ++extern BOOLEAN fgIsResetting; ++extern BOOLEAN g_u4HaltFlag; ++extern spinlock_t g_p2p_lock; ++extern int g_u4P2PEnding; ++extern int g_u4P2POnOffing; ++#endif ++#endif ++ ++ ++#if (CFG_SUPPORT_TXR_ENC == 1) ++extern VOID rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); ++#endif /* CFG_SUPPORT_TXR_ENC */ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++/* New wireless extensions API - SET/GET convention (even ioctl numbers are ++ * root only) ++ */ ++#define IOCTL_SET_INT (SIOCIWFIRSTPRIV + 0) ++#define IOCTL_GET_INT (SIOCIWFIRSTPRIV + 1) ++ ++#define IOCTL_SET_ADDRESS (SIOCIWFIRSTPRIV + 2) ++#define IOCTL_GET_ADDRESS (SIOCIWFIRSTPRIV + 3) ++#define IOCTL_SET_STR (SIOCIWFIRSTPRIV + 4) ++#define IOCTL_GET_STR (SIOCIWFIRSTPRIV + 5) ++#define IOCTL_SET_KEY (SIOCIWFIRSTPRIV + 6) ++#define IOCTL_GET_KEY (SIOCIWFIRSTPRIV + 7) ++#define IOCTL_SET_STRUCT (SIOCIWFIRSTPRIV + 8) ++#define IOCTL_GET_STRUCT (SIOCIWFIRSTPRIV + 9) ++#define IOCTL_SET_STRUCT_FOR_EM (SIOCIWFIRSTPRIV + 11) ++#define IOCTL_SET_INTS (SIOCIWFIRSTPRIV + 12) ++#define IOCTL_GET_INTS (SIOCIWFIRSTPRIV + 13) ++#define IOCTL_SET_STRING (SIOCIWFIRSTPRIV + 14) ++ ++#define PRIV_CMD_REG_DOMAIN 0 ++#define PRIV_CMD_BEACON_PERIOD 1 ++#define PRIV_CMD_ADHOC_MODE 2 ++ ++#if CFG_TCP_IP_CHKSUM_OFFLOAD ++#define PRIV_CMD_CSUM_OFFLOAD 3 ++#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ ++ ++#define PRIV_CMD_ROAMING 4 ++#define PRIV_CMD_VOIP_DELAY 5 ++#define PRIV_CMD_POWER_MODE 6 ++ ++#define PRIV_CMD_WMM_PS 7 ++#define PRIV_CMD_BT_COEXIST 8 ++#define PRIV_GPIO2_MODE 9 ++ ++#define PRIV_CUSTOM_SET_PTA 10 ++#define PRIV_CUSTOM_CONTINUOUS_POLL 11 ++#define PRIV_CUSTOM_SINGLE_ANTENNA 12 ++#define PRIV_CUSTOM_BWCS_CMD 13 ++#define PRIV_CUSTOM_DISABLE_BEACON_DETECTION 14 /* later */ ++#define PRIV_CMD_OID 15 ++#define PRIV_SEC_MSG_OID 16 ++ ++#define PRIV_CMD_TEST_MODE 17 ++#define PRIV_CMD_TEST_CMD 18 ++#define PRIV_CMD_ACCESS_MCR 19 ++#define PRIV_CMD_SW_CTRL 20 ++ ++#if 1 /* ANTI_PRIVCY */ ++#define PRIV_SEC_CHECK_OID 21 ++#endif ++ ++#define PRIV_CMD_WSC_PROBE_REQ 22 ++ ++#define PRIV_CMD_P2P_VERSION 23 ++ ++#define PRIV_CMD_GET_CH_LIST 24 ++ ++#define PRIV_CMD_SET_TX_POWER 25 ++ ++#define PRIV_CMD_BAND_CONFIG 26 ++ ++#define PRIV_CMD_DUMP_MEM 27 ++ ++#define PRIV_CMD_P2P_MODE 28 ++ ++#define PRIV_CMD_GET_BUILD_DATE_CODE 29 ++ ++#define PRIV_CMD_GET_DEBUG_CODE 30 ++ ++#define PRIV_CMD_OTHER 31 ++ ++#define PRIV_CMD_WFD_DEBUG_CODE 32 ++ ++#define PRIV_CMD_MET_PROFILING 33 ++ ++/* other string command ID */ ++#define PRIV_CMD_OTHER_TDLS 0x00 ++#define PRIV_CMD_OTHER_TAR 0x01 /* TX auto rate */ ++ ++/* 802.3 Objects (Ethernet) */ ++#define OID_802_3_CURRENT_ADDRESS 0x01010102 ++ ++/* IEEE 802.11 OIDs */ ++#define OID_802_11_SUPPORTED_RATES 0x0D01020E ++#define OID_802_11_CONFIGURATION 0x0D010211 ++ ++/* PnP and PM OIDs, NDIS default OIDS */ ++#define OID_PNP_SET_POWER 0xFD010101 ++ ++#define OID_CUSTOM_OID_INTERFACE_VERSION 0xFFA0C000 ++ ++/* MT5921 specific OIDs */ ++#define OID_CUSTOM_BT_COEXIST_CTRL 0xFFA0C580 ++#define OID_CUSTOM_POWER_MANAGEMENT_PROFILE 0xFFA0C581 ++#define OID_CUSTOM_PATTERN_CONFIG 0xFFA0C582 ++#define OID_CUSTOM_BG_SSID_SEARCH_CONFIG 0xFFA0C583 ++#define OID_CUSTOM_VOIP_SETUP 0xFFA0C584 ++#define OID_CUSTOM_ADD_TS 0xFFA0C585 ++#define OID_CUSTOM_DEL_TS 0xFFA0C586 ++#define OID_CUSTOM_SLT 0xFFA0C587 ++#define OID_CUSTOM_ROAMING_EN 0xFFA0C588 ++#define OID_CUSTOM_WMM_PS_TEST 0xFFA0C589 ++#define OID_CUSTOM_COUNTRY_STRING 0xFFA0C58A ++#define OID_CUSTOM_MULTI_DOMAIN_CAPABILITY 0xFFA0C58B ++#define OID_CUSTOM_GPIO2_MODE 0xFFA0C58C ++#define OID_CUSTOM_CONTINUOUS_POLL 0xFFA0C58D ++#define OID_CUSTOM_DISABLE_BEACON_DETECTION 0xFFA0C58E ++ ++/* CR1460, WPS privacy bit check disable */ ++#define OID_CUSTOM_DISABLE_PRIVACY_CHECK 0xFFA0C600 ++ ++/* Precedent OIDs */ ++#define OID_CUSTOM_MCR_RW 0xFFA0C801 ++#define OID_CUSTOM_EEPROM_RW 0xFFA0C803 ++#define OID_CUSTOM_SW_CTRL 0xFFA0C805 ++#define OID_CUSTOM_MEM_DUMP 0xFFA0C807 ++ ++/* RF Test specific OIDs */ ++#define OID_CUSTOM_TEST_MODE 0xFFA0C901 ++#define OID_CUSTOM_TEST_RX_STATUS 0xFFA0C903 ++#define OID_CUSTOM_TEST_TX_STATUS 0xFFA0C905 ++#define OID_CUSTOM_ABORT_TEST_MODE 0xFFA0C906 ++#define OID_CUSTOM_MTK_WIFI_TEST 0xFFA0C911 ++ ++/* BWCS */ ++#define OID_CUSTOM_BWCS_CMD 0xFFA0C931 ++#define OID_CUSTOM_SINGLE_ANTENNA 0xFFA0C932 ++#define OID_CUSTOM_SET_PTA 0xFFA0C933 ++ ++/* NVRAM */ ++#define OID_CUSTOM_MTK_NVRAM_RW 0xFFA0C941 ++#define OID_CUSTOM_CFG_SRC_TYPE 0xFFA0C942 ++#define OID_CUSTOM_EEPROM_TYPE 0xFFA0C943 ++ ++#if CFG_SUPPORT_WAPI ++#define OID_802_11_WAPI_MODE 0xFFA0CA00 ++#define OID_802_11_WAPI_ASSOC_INFO 0xFFA0CA01 ++#define OID_802_11_SET_WAPI_KEY 0xFFA0CA02 ++#endif ++ ++#if CFG_SUPPORT_WPS2 ++#define OID_802_11_WSC_ASSOC_INFO 0xFFA0CB00 ++#endif ++ ++/* Define magic key of test mode (Don't change it for future compatibity) */ ++#define PRIV_CMD_TEST_MAGIC_KEY 2011 ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++/* NIC BBCR configuration entry structure */ ++typedef struct _PRIV_CONFIG_ENTRY { ++ UINT_8 ucOffset; ++ UINT_8 ucValue; ++} PRIV_CONFIG_ENTRY, *PPRIV_CONFIG_ENTRY; ++ ++typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC_REQ) (IN PVOID prAdapter, ++ IN OUT PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); ++ ++typedef enum _ENUM_OID_METHOD_T { ++ ENUM_OID_GLUE_ONLY, ++ ENUM_OID_GLUE_EXTENSION, ++ ENUM_OID_DRIVER_CORE ++} ENUM_OID_METHOD_T, *P_ENUM_OID_METHOD_T; ++ ++/* OID set/query processing entry */ ++typedef struct _WLAN_REQ_ENTRY { ++ UINT_32 rOid; /* OID */ ++ PUINT_8 pucOidName; /* OID name text */ ++ BOOLEAN fgQryBufLenChecking; ++ BOOLEAN fgSetBufLenChecking; ++ ENUM_OID_METHOD_T eOidMethod; ++ UINT_32 u4InfoBufLen; ++ PFN_OID_HANDLER_FUNC_REQ pfOidQueryHandler; /* PFN_OID_HANDLER_FUNC */ ++ PFN_OID_HANDLER_FUNC_REQ pfOidSetHandler; /* PFN_OID_HANDLER_FUNC */ ++} WLAN_REQ_ENTRY, *P_WLAN_REQ_ENTRY; ++ ++typedef struct _NDIS_TRANSPORT_STRUCT { ++ UINT_32 ndisOidCmd; ++ UINT_32 inNdisOidlength; ++ UINT_32 outNdisOidLength; ++ UINT_8 ndisOidContent[16]; ++} NDIS_TRANSPORT_STRUCT, *P_NDIS_TRANSPORT_STRUCT; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++int ++priv_set_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_int(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++int ++priv_set_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_ints(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++int ++priv_set_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int ++priv_get_struct(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); ++ ++UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen); ++ ++UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac); ++ ++int ++priv_set_string(IN struct net_device *prNetDev, ++ IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); ++ ++int priv_support_ioctl(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); ++ ++int priv_support_driver_cmd(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); ++ ++INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen); ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _GL_WEXT_PRIV_H */ +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c +new file mode 100644 +index 000000000000..fba854cfd68e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c +@@ -0,0 +1,542 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/platform.c#1 ++*/ ++ ++/*! \file "platform.c" ++ \brief This file including the protocol layer privacy function. ++ ++ This file provided the macros and functions library support for the ++ protocol layer security setting from wlan_oid.c and for parse.c and ++ rsn.c and nic_privacy.c ++ ++*/ ++ ++/* ++** Log: platform.c ++ * ++ * 11 14 2011 cm.chang ++ * NULL ++ * Fix compiling warning ++ * ++ * 11 10 2011 cp.wu ++ * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer ++ * 1. eliminaite direct calls to printk in porting layer. ++ * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. ++ * ++ * 09 13 2011 jeffrey.chang ++ * [WCXRP00000983] [MT6620][Wi-Fi Driver] invalid pointer casting causes kernel panic during p2p connection ++ * fix the pointer casting ++ * ++ * 06 29 2011 george.huang ++ * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 ++ * . ++ * ++ * 06 28 2011 george.huang ++ * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 ++ * remove un-used code ++ * ++ * 05 11 2011 jeffrey.chang ++ * NULL ++ * fix build error ++ * ++ * 05 09 2011 jeffrey.chang ++ * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change ++ * support ARP filter through kernel notifier ++ * ++ * 04 08 2011 pat.lu ++ * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver ++ * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver ++ * ++ * 03 22 2011 pat.lu ++ * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build ++ * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. ++ * ++ * 03 21 2011 cp.wu ++ * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer ++ * improve portability for awareness of early version of linux kernel and wireless extension. ++ * ++ * 03 18 2011 jeffrey.chang ++ * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue ++ * remove early suspend functions ++ * ++ * 03 03 2011 jeffrey.chang ++ * NULL ++ * add the ARP filter callback ++ * ++ * 02 15 2011 jeffrey.chang ++ * NULL ++ * to support early suspend in android ++ * ++ * 02 01 2011 cp.wu ++ * [WCXRP00000413] [MT6620 Wi-Fi][Driver] Merge 1103 changes on NVRAM file path change to DaVinci main trunk and V1.1 ++ * branch ++ * upon Jason Zhang(NVRAM owner)'s change, ALPS has modified its NVRAM storage from /nvram/... to /data/nvram/... ++ * ++ * 11 01 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] ++ * Add implementation for querying current TX rate from firmware auto rate module ++ * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead ++ * 2) Remove CNM CH-RECOVER event handling ++ * 3) cfg read/write API renamed with kal prefix for unified naming rules. ++ * ++ * 10 18 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] ++ * The mac address is all zero at android ++ * complete implementation of Android NVRAM access ++ * ++ * 10 05 2010 cp.wu ++ * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check ++ * 1) add NVRAM access API ++ * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) ++ * 3) add OID implementation for NVRAM read/write service ++ * ++** ++*/ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "gl_os.h" ++ ++#ifndef CONFIG_X86 ++#if defined(CONFIG_HAS_EARLY_SUSPEND) ++#include ++#endif ++#endif ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++#define WIFI_NVRAM_FILE_NAME "/etc/firmware/nvram/WIFI" ++#define WIFI_NVRAM_CUSTOM_NAME "/etc/firmware/nvram/WIFI_CUSTOM" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++static int netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) ++{ ++ UINT_8 ip[4] = { 0 }; ++ UINT_32 u4NumIPv4 = 0; ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ ++ UINT_32 u4NumIPv6 = 0; ++#endif ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net_device *prDev = ifa->ifa_dev->dev; ++ UINT_32 i; ++ P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (prDev == NULL) { ++ DBGLOG(REQ, ERROR, "netdev_event: device is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ DBGLOG(REQ, INFO, "netdev_event, addr=%x, notification=%lx, dev_name=%s\n", ++ ifa->ifa_address, notification, prDev->name); ++ if (!fgIsUnderSuspend) ++ return NOTIFY_DONE; ++ if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { ++ DBGLOG(REQ, WARN, "netdev_event: not our device\n"); ++ return NOTIFY_DONE; ++ } ++#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ ++ { ++ /* printk(KERN_INFO "[netdev_event] IPV4_DAD is unlock now!!\n"); */ ++ prGlueInfo->fgIsDad = FALSE; ++ } ++#endif ++ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ ++ if (prGlueInfo == NULL) { ++ DBGLOG(REQ, ERROR, "netdev_event: prGlueInfo is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ ASSERT(prGlueInfo); ++ ++ /* <3> get the IPv4 address */ ++ if (!prDev || !(prDev->ip_ptr) || ++ !((struct in_device *)(prDev->ip_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(REQ, INFO, "ip is not available.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); ++ DBGLOG(REQ, INFO, "ip is %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); ++ ++ /* todo: traverse between list to find whole sets of IPv4 addresses */ ++ if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) ++ u4NumIPv4++; ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ if (!prDev || !(prDev->ip6_ptr) || ++ !((struct in_device *)(prDev->ip6_ptr))->ifa_list || ++ !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { ++ DBGLOG(REQ, INFO, "ipv6 is not available.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); ++ DBGLOG(REQ, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", ++ ip6[0], ip6[1], ip6[2], ip6[3], ++ ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); ++ ++ /* todo: traverse between list to find whole sets of IPv6 addresses */ ++ if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) ++ /* u4NumIPv6++; */ ++#endif ++ ++ /* here we can compare the dev with other network's netdev to */ ++ /* set the proper arp filter */ ++ /* */ ++ /* IMPORTANT: please make sure if the context can sleep, if the context can't sleep */ ++ /* we should schedule a kernel thread to do this for us */ ++ ++ /* <7> set up the ARP filter */ ++ { ++ WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; ++ UINT_32 u4SetInfoLen = 0; ++ UINT_8 aucBuf[32] = { 0 }; ++ UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); ++ P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) aucBuf; ++ P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; ++ ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; ++#else ++ prParamNetAddrList->u4AddressCount = u4NumIPv4; ++#endif ++ prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ for (i = 0; i < u4NumIPv4; i++) { ++ prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++#if 0 ++ kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); ++#else ++ prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; ++ kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); ++ prParamNetAddr = ++ (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); ++#endif ++ } ++/* #ifdef CONFIG_IPV6 */ ++#if 0 ++ for (i = 0; i < u4NumIPv6; i++) { ++ prParamNetAddr->u2AddressLength = 6; ++ prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; ++ kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); ++ prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip6)); ++ u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); ++ } ++#endif ++ ASSERT(u4Len <= sizeof(aucBuf)); ++ ++ DBGLOG(REQ, INFO, "kalIoctl (0x%p, 0x%p)\n", prGlueInfo, prParamNetAddrList); ++ ++ rStatus = kalIoctl(prGlueInfo, ++ wlanoidSetNetworkAddress, ++ (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); ++ ++ if (rStatus != WLAN_STATUS_SUCCESS) ++ DBGLOG(REQ, ERROR, "set HW pattern filter fail 0x%x\n", rStatus); ++ } ++ ++ return NOTIFY_DONE; ++ ++} ++ ++/* #if CFG_SUPPORT_HOTSPOT_2_0 */ ++#if 0 ++static int net6dev_event(struct notifier_block *nb, unsigned long notification, void *ptr) ++{ ++ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; ++ struct net_device *prDev = ifa->idev->dev; ++ P_GLUE_INFO_T prGlueInfo = NULL; ++ ++ if (prDev == NULL) { ++ DBGLOG(REQ, INFO, "net6dev_event: device is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ ++ if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { ++ DBGLOG(REQ, INFO, "net6dev_event: xxx\n"); ++ return NOTIFY_DONE; ++ } ++ ++ if (strncmp(prDev->name, "p2p", 3) == 0) { ++ /* because we store the address of prGlueInfo in p2p's private date of net device */ ++ /* *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; */ ++ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); ++ } else { /* wlan0 */ ++ prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); ++ } ++ ++ if (prGlueInfo == NULL) { ++ DBGLOG(REQ, INFO, "netdev_event: prGlueInfo is empty.\n"); ++ return NOTIFY_DONE; ++ } ++ /* printk(KERN_INFO "[net6dev_event] IPV6_DAD is unlock now!!\n"); */ ++ prGlueInfo->fgIs6Dad = FALSE; ++ ++ return NOTIFY_DONE; ++} ++#endif ++ ++static struct notifier_block inetaddr_notifier = { ++ .notifier_call = netdev_event, ++}; ++ ++#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ ++static struct notifier_block inet6addr_notifier = { ++ .notifier_call = net6dev_event, ++}; ++#endif ++ ++void wlanRegisterNotifier(void) ++{ ++ register_inetaddr_notifier(&inetaddr_notifier); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* register_inet6addr_notifier(&inet6addr_notifier); */ ++#endif ++} ++ ++/* EXPORT_SYMBOL(wlanRegisterNotifier); */ ++ ++void wlanUnregisterNotifier(void) ++{ ++ unregister_inetaddr_notifier(&inetaddr_notifier); ++ ++#if CFG_SUPPORT_HOTSPOT_2_0 ++ /* unregister_inetaddr_notifier(&inet6addr_notifier); */ ++#endif ++} ++ ++/* EXPORT_SYMBOL(wlanUnregisterNotifier); */ ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Utility function for reading data from files on NVRAM-FS ++* ++* \param[in] ++* filename ++* len ++* offset ++* \param[out] ++* buf ++* \return ++* actual length of data being read ++*/ ++/*----------------------------------------------------------------------------*/ ++static int nvram_read(char *filename, char *buf, ssize_t len, int offset) ++{ ++#if CFG_SUPPORT_NVRAM ++ struct file *fd; ++ int retLen = -1; ++ ++ mm_segment_t old_fs = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ fd = filp_open(filename, O_RDONLY, 0644); ++ ++ if (IS_ERR(fd)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to open!!\n"); ++ return -1; ++ } ++ ++ do { ++ //if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) { ++ if ( fd->f_op == NULL ) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : file can not be read!!\n"); ++ break; ++ } ++ ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to seek!!\n"); ++ break; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ retLen = vfs_read(fd, buf, len, &fd->f_pos); ++ ++ } while (FALSE); ++ ++ filp_close(fd, NULL); ++ ++ set_fs(old_fs); ++ ++ return retLen; ++ ++#else /* !CFG_SUPPORT_NVRAM */ ++ ++ return -EIO; ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief Utility function for writing data to files on NVRAM-FS ++* ++* \param[in] ++* filename ++* buf ++* len ++* offset ++* \return ++* actual length of data being written ++*/ ++/*----------------------------------------------------------------------------*/ ++static int nvram_write(char *filename, char *buf, ssize_t len, int offset) ++{ ++#if CFG_SUPPORT_NVRAM ++ struct file *fd; ++ int retLen = -1; ++ ++ mm_segment_t old_fs = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ fd = filp_open(filename, O_WRONLY | O_CREAT, 0644); ++ ++ if (IS_ERR(fd)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to open!!\n"); ++ return -1; ++ } ++ ++ do { ++ if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : file can not be write!!\n"); ++ break; ++ } ++ /* End of if */ ++ if (fd->f_pos != offset) { ++ if (fd->f_op->llseek) { ++ if (fd->f_op->llseek(fd, offset, 0) != offset) { ++ DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to seek!!\n"); ++ break; ++ } ++ } else { ++ fd->f_pos = offset; ++ } ++ } ++ ++ retLen = vfs_write(fd, buf, len, &fd->f_pos); ++ ++ } while (FALSE); ++ ++ filp_close(fd, NULL); ++ ++ set_fs(old_fs); ++ ++ return retLen; ++ ++#else /* !CFG_SUPPORT_NVRAMS */ ++ ++ return -EIO; ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief API for reading data on NVRAM ++* ++* \param[in] ++* prGlueInfo ++* u4Offset ++* \param[out] ++* pu2Data ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data) ++{ ++ if (pu2Data == NULL) ++ return FALSE; ++ ++ if (nvram_read(WIFI_NVRAM_FILE_NAME, ++ (char *)pu2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { ++ return FALSE; ++ } else { ++ return TRUE; ++ } ++} ++ ++/*----------------------------------------------------------------------------*/ ++/*! ++* \brief API for writing data on NVRAM ++* ++* \param[in] ++* prGlueInfo ++* u4Offset ++* u2Data ++* \return ++* TRUE ++* FALSE ++*/ ++/*----------------------------------------------------------------------------*/ ++BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, UINT_32 u4Offset, UINT_16 u2Data) ++{ ++ if (nvram_write(WIFI_NVRAM_FILE_NAME, ++ (char *)&u2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { ++ return FALSE; ++ } else { ++ return TRUE; ++ } ++} +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h +new file mode 100644 +index 000000000000..9444d415c60e +--- /dev/null ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h +@@ -0,0 +1,190 @@ ++/* ++** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/version.h#1 ++*/ ++ ++/*! \file "version.h" ++ \brief Driver's version definition ++ ++*/ ++ ++/* ++** Log: version.h ++ * ++ * 11 01 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.1.1. ++ * ++ * 08 26 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.9.. ++ * ++ * 08 23 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.8. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * correct typo. ++ * ++ * 08 15 2011 cp.wu ++ * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree ++ * for building MT6628 Win32 driver environment ++ * ++ * 08 03 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.7. ++ * ++ * 07 24 2011 puff.wen ++ * NULL ++ * [MT5931][Beta 5]Change the version number to v0.2.2.0 ++ * ++ * 06 01 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.6.. ++ * ++ * 05 09 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.5.. ++ * ++ * 04 19 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.4. ++ * ++ * 04 18 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.3. ++ * ++ * 03 25 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.2. ++ * ++ * 03 21 2011 chinglan.wang ++ * NULL ++ * Change the version number to 2.0.0.1. ++ * ++ * 03 18 2011 chinglan.wang ++ * NULL ++ * Change the version number to v2.0.0.0. ++ * ++ * 02 11 2011 chinglan.wang ++ * NULL ++ * Change to the version 1.2.0.2. ++ * ++ * 02 10 2011 chinglan.wang ++ * NULL ++ * Change the version to 1.2.0.1. ++ * ++ * 02 08 2011 cp.wu ++ * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number ++ * change version number to v1.2.0.0 for preparing v1.2 software package release. ++ * ++ * 12 10 2010 kevin.huang ++ * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check ++ * Add Linux Proc Support ++ * ++ * 10 07 2010 cp.wu ++ * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection ++ * [WINDDK] build system changes for MT5931 ++ * ++ * 07 08 2010 cp.wu ++ * ++ * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. ++ * ++ * 06 06 2010 kevin.huang ++ * [WPD00003832][MT6620 5931] Create driver base ++ * [MT6620 5931] Create driver base ++** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-12-14 14:10:55 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-17 22:41:00 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-13 16:20:33 GMT mtk01084 ++** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:27:13 GMT mtk01426 ++** Init for develop ++** ++*/ ++ ++#ifndef _VERSION_H ++#define _VERSION_H ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++#ifndef NIC_AUTHOR ++#define NIC_AUTHOR "NIC_AUTHOR" ++#endif ++#ifndef NIC_DESC ++#define NIC_DESC "NIC_DESC" ++#endif ++ ++#ifndef NIC_NAME ++#if defined(MT6620) ++#define NIC_NAME "MT6620" ++#define NIC_DEVICE_ID "MT6620" ++#define NIC_DEVICE_ID_LOW "mt6620" ++#elif defined(MT6628) ++#define NIC_NAME "MT6582" ++#define NIC_DEVICE_ID "MT6582" ++#define NIC_DEVICE_ID_LOW "mt6582" ++#endif ++#endif ++ ++/* NIC driver information */ ++#define NIC_VENDOR "MediaTek Inc." ++#define NIC_VENDOR_OUI {0x00, 0x0C, 0xE7} ++ ++#if defined(MT6620) ++#define NIC_PRODUCT_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter" ++#define NIC_DRIVER_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter Driver" ++#elif defined(MT6628) ++/* #define NIC_PRODUCT_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter" */ ++/* #define NIC_DRIVER_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter Driver" */ ++#define NIC_PRODUCT_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter" ++#define NIC_DRIVER_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter Driver" ++#endif ++ ++/* Define our driver version */ ++#define NIC_DRIVER_MAJOR_VERSION 2 ++#define NIC_DRIVER_MINOR_VERSION 0 ++#define NIC_DRIVER_VERSION (2, 0, 1, 1) ++#define NIC_DRIVER_VERSION_STRING "2.0.1.1" ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _VERSION_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/aee.h b/drivers/misc/mediatek/include/mt-plat/aee.h +new file mode 100644 +index 000000000000..d1cf448dafb2 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/aee.h +@@ -0,0 +1,284 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#if !defined(__AEE_H__) ++#define __AEE_H__ ++ ++#include ++#include ++ ++#define AEE_MODULE_NAME_LENGTH 64 ++#define AEE_PROCESS_NAME_LENGTH 256 ++#define AEE_BACKTRACE_LENGTH 3072 ++ ++typedef enum { ++ AE_DEFECT_FATAL, ++ AE_DEFECT_EXCEPTION, ++ AE_DEFECT_WARNING, ++ AE_DEFECT_REMINDING, ++ AE_DEFECT_ATTR_END ++} AE_DEFECT_ATTR; ++ ++typedef enum { ++ AE_KE = 0, /* Fatal Exception */ ++ AE_HWT, ++ AE_REBOOT, ++ AE_NE, ++ AE_JE, ++ AE_SWT, ++ AE_EE, ++ AE_EXP_ERR_END, ++ AE_ANR, /* Error or Warning or Defect */ ++ AE_RESMON, ++ AE_MODEM_WARNING, ++ AE_WTF, ++ AE_WRN_ERR_END, ++ AE_MANUAL, /* Manual Raise */ ++ AE_EXP_CLASS_END, ++ ++ AE_KERNEL_PROBLEM_REPORT = 1000, ++ AE_SYSTEM_JAVA_DEFECT, ++ AE_SYSTEM_NATIVE_DEFECT, ++ AE_MANUAL_MRDUMP_KEY, ++} AE_EXP_CLASS; /* General Program Exception Class */ ++ ++typedef enum { ++ AEE_REBOOT_MODE_NORMAL = 0, ++ AEE_REBOOT_MODE_KERNEL_OOPS, ++ AEE_REBOOT_MODE_KERNEL_PANIC, ++ AEE_REBOOT_MODE_NESTED_EXCEPTION, ++ AEE_REBOOT_MODE_WDT, ++ AEE_REBOOT_MODE_MANUAL_KDUMP, ++} AEE_REBOOT_MODE; ++ ++#define AEE_SZ_SYMBOL_L 140 ++#define AEE_SZ_SYMBOL_S 80 ++struct aee_bt_frame { ++ __u64 pc; ++ __u64 lr; ++ __u32 pad[5]; ++ char pc_symbol[AEE_SZ_SYMBOL_S]; /* Now we use different symbol length for PC &LR */ ++ char lr_symbol[AEE_SZ_SYMBOL_L]; ++}; ++ ++/* aee_process_info struct should strictly small than ipanic_buffer, now 4KB */ ++struct aee_process_info { ++ char process_path[AEE_PROCESS_NAME_LENGTH]; ++ char backtrace[AEE_BACKTRACE_LENGTH]; ++ struct aee_bt_frame ke_frame; ++}; ++ ++struct aee_process_bt { ++ __u32 pid; ++ __u32 nr_entries; ++ struct aee_bt_frame *entries; ++}; ++ ++ ++struct aee_thread_reg { ++ pid_t tid; ++ struct pt_regs regs; ++}; ++ ++struct aee_user_thread_stack { ++ pid_t tid; ++ int StackLength; ++ unsigned char *Userthread_Stack; /*8k stack ,define to char only for match 64bit/32bit*/ ++}; ++ ++struct aee_user_thread_maps { ++ pid_t tid; ++ int Userthread_mapsLength; ++ unsigned char *Userthread_maps; /*8k stack ,define to char only for match 64bit/32bit*/ ++}; ++ ++ ++ ++struct aee_oops { ++ struct list_head list; ++ AE_DEFECT_ATTR attr; ++ AE_EXP_CLASS clazz; ++ ++ char module[AEE_MODULE_NAME_LENGTH]; ++ /* consist with struct aee_process_info */ ++ char process_path[AEE_PROCESS_NAME_LENGTH]; ++ char backtrace[AEE_BACKTRACE_LENGTH]; ++ struct aee_bt_frame ke_frame; ++ ++ char *detail; ++ int detail_len; ++ ++ char *console; ++ int console_len; ++ ++ char *android_main; ++ int android_main_len; ++ char *android_radio; ++ int android_radio_len; ++ char *android_system; ++ int android_system_len; ++ ++ char *userspace_info; ++ int userspace_info_len; ++ ++ char *mmprofile; ++ int mmprofile_len; ++ ++ char *mini_rdump; ++ int mini_rdump_len; ++ ++ ++ struct aee_user_thread_stack userthread_stack; ++ struct aee_thread_reg userthread_reg; ++ struct aee_user_thread_maps userthread_maps; ++ ++ int dump_option; ++}; ++ ++struct aee_kernel_api { ++ void (*kernel_reportAPI)(const AE_DEFECT_ATTR attr, const int db_opt, const char *module, ++ const char *msg); ++ void (*md_exception)(const char *assert_type, const int *log, int log_size, const int *phy, ++ int phy_size, const char *detail, const int db_opt); ++ void (*md32_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++ void (*combo_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++ void (*scp_exception)(const char *assert_type, const int *log, int log_size, ++ const int *phy, int phy_size, const char *detail, const int db_opt); ++}; ++ ++void aee_sram_printk(const char *fmt, ...); ++int aee_nested_printf(const char *fmt, ...); ++void aee_wdt_irq_info(void); ++void aee_wdt_fiq_info(void *arg, void *regs, void *svc_sp); ++void aee_trigger_kdb(void); ++struct aee_oops *aee_oops_create(AE_DEFECT_ATTR attr, AE_EXP_CLASS clazz, const char *module); ++void aee_oops_set_backtrace(struct aee_oops *oops, const char *backtrace); ++void aee_oops_set_process_path(struct aee_oops *oops, const char *process_path); ++void aee_oops_free(struct aee_oops *oops); ++/* powerkey press,modules use bits */ ++#define AE_WDT_Powerkey_DEVICE_PATH "/dev/kick_powerkey" ++#define WDT_SETBY_DEFAULT (0) ++#define WDT_SETBY_Backlight (1<<0) ++#define WDT_SETBY_Display (1<<1) ++#define WDT_SETBY_SF (1<<2) ++#define WDT_SETBY_PM (1<<3) ++#define WDT_SETBY_WMS_DISABLE_PWK_MONITOR (0xAEEAEE00) ++#define WDT_SETBY_WMS_ENABLE_PWK_MONITOR (0xAEEAEE01) ++#define WDT_PWK_HANG_FORCE_HWT (0xAEE0FFFF) ++ ++/* QHQ RT Monitor */ ++#define AEEIOCTL_RT_MON_Kick _IOR('p', 0x0A, int) ++#define AE_WDT_DEVICE_PATH "/dev/RT_Monitor" ++/* QHQ RT Monitor end */ ++ ++/* DB dump option bits, set relative bit to 1 to include related file in db */ ++#define DB_OPT_DEFAULT (0) ++#define DB_OPT_FTRACE (1<<0) ++#define DB_OPT_PRINTK_TOO_MUCH (1<<1) ++#define DB_OPT_NE_JBT_TRACES (1<<2) ++#define DB_OPT_SWT_JBT_TRACES (1<<3) ++#define DB_OPT_VM_TRACES (1<<4) ++#define DB_OPT_DUMPSYS_ACTIVITY (1<<5) ++#define DB_OPT_DUMPSYS_WINDOW (1<<6) ++#define DB_OPT_DUMPSYS_GFXINFO (1<<7) ++#define DB_OPT_DUMPSYS_SURFACEFLINGER (1<<8) ++#define DB_OPT_DISPLAY_HANG_DUMP (1<<9) ++#define DB_OPT_LOW_MEMORY_KILLER (1<<10) ++#define DB_OPT_PROC_MEM (1<<11) ++#define DB_OPT_FS_IO_LOG (1<<12) ++#define DB_OPT_PROCESS_COREDUMP (1<<13) ++#define DB_OPT_VM_HPROF (1<<14) ++#define DB_OPT_PROCMEM (1<<15) ++#define DB_OPT_DUMPSYS_INPUT (1<<16) ++#define DB_OPT_MMPROFILE_BUFFER (1<<17) ++#define DB_OPT_BINDER_INFO (1<<18) ++#define DB_OPT_WCN_ISSUE_INFO (1<<19) ++#define DB_OPT_DUMMY_DUMP (1<<20) ++#define DB_OPT_PID_MEMORY_INFO (1<<21) ++#define DB_OPT_VM_OOME_HPROF (1<<22) ++#define DB_OPT_PID_SMAPS (1<<23) ++#define DB_OPT_PROC_CMDQ_INFO (1<<24) ++#define DB_OPT_PROC_USKTRK (1<<25) ++#define DB_OPT_SF_RTT_DUMP (1<<26) ++#define DB_OPT_PAGETYPE_INFO (1<<27) ++#define DB_OPT_DUMPSYS_PROCSTATS (1<<28) ++#define DB_OPT_DUMP_DISPLAY (1<<29) ++#define DB_OPT_NATIVE_BACKTRACE (1<<30) ++#define DB_OPT_AARCH64 (1<<31) ++ ++#define aee_kernel_exception(module, msg...) \ ++ aee_kernel_exception_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_warning(module, msg...) \ ++ aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_reminding(module, msg...) \ ++ aee_kernel_reminding_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) ++#define aee_kernel_dal_show(msg) \ ++ aee_kernel_dal_api(__FILE__, __LINE__, msg) ++ ++#define aed_md_exception(log, log_size, phy, phy_size, detail) \ ++ aed_md_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_md32_exception(log, log_size, phy, phy_size, detail) \ ++ aed_md32_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_scp_exception(log, log_size, phy, phy_size, detail) \ ++ aed_scp_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++#define aed_combo_exception(log, log_size, phy, phy_size, detail) \ ++ aed_combo_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) ++ ++void aee_kernel_exception_api(const char *file, const int line, const int db_opt, ++ const char *module, const char *msg, ...); ++void aee_kernel_warning_api(const char *file, const int line, const int db_opt, const char *module, ++ const char *msg, ...); ++void aee_kernel_reminding_api(const char *file, const int line, const int db_opt, ++ const char *module, const char *msg, ...); ++void aee_kernel_dal_api(const char *file, const int line, const char *msg); ++ ++void aed_md_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_md32_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_scp_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++void aed_combo_exception_api(const int *log, int log_size, const int *phy, int phy_size, ++ const char *detail, const int db_opt); ++ ++void aee_kernel_wdt_kick_Powkey_api(const char *module, int msg); ++int aee_kernel_wdt_kick_api(int kinterval); ++void aee_powerkey_notify_press(unsigned long pressed); ++int aee_kernel_Powerkey_is_press(void); ++ ++void ipanic_recursive_ke(struct pt_regs *regs, struct pt_regs *excp_regs, int cpu); ++ ++/* QHQ RT Monitor */ ++void aee_kernel_RT_Monitor_api(int lParam); ++/* QHQ RT Monitor end */ ++void mt_fiq_printf(const char *fmt, ...); ++void aee_register_api(struct aee_kernel_api *aee_api); ++int aee_in_nested_panic(void); ++void aee_stop_nested_panic(struct pt_regs *regs); ++void aee_wdt_dump_info(void); ++void aee_wdt_printf(const char *fmt, ...); ++ ++void aee_fiq_ipi_cpu_stop(void *arg, void *regs, void *svc_sp); ++ ++#if defined(CONFIG_MTK_AEE_DRAM_CONSOLE) ++void aee_dram_console_reserve_memory(void); ++#else ++static inline void aee_dram_console_reserve_memory(void) ++{ ++} ++#endif ++ ++extern void *aee_excp_regs; /* To store latest exception, in case of stack corruption */ ++#endif /* __AEE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mrdump.h b/drivers/misc/mediatek/include/mt-plat/mrdump.h +new file mode 100644 +index 000000000000..b6bdfa2f7617 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mrdump.h +@@ -0,0 +1,204 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#if !defined(__MRDUMP_H__) ++#define __MRDUMP_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __aarch64__ ++#define reg_pc pc ++#define reg_lr regs[30] ++#define reg_sp sp ++#define reg_fp regs[29] ++#else ++#define reg_pc ARM_pc ++#define reg_lr ARM_lr ++#define reg_sp ARM_sp ++#define reg_ip ARM_ip ++#define reg_fp ARM_fp ++#endif ++ ++#define MRDUMP_CPU_MAX 16 ++ ++#define MRDUMP_DEV_NULL 0 ++#define MRDUMP_DEV_SDCARD 1 ++#define MRDUMP_DEV_EMMC 2 ++ ++#define MRDUMP_FS_NULL 0 ++#define MRDUMP_FS_VFAT 1 ++#define MRDUMP_FS_EXT4 2 ++ ++#define MRDUMP_GO_DUMP "MRDUMP04" ++ ++typedef uint32_t arm32_gregset_t[18]; ++typedef uint64_t aarch64_gregset_t[34]; ++ ++struct mrdump_crash_record { ++ int reboot_mode; ++ ++ char msg[128]; ++ char backtrace[512]; ++ ++ uint32_t fault_cpu; ++ ++ union { ++ arm32_gregset_t arm32_regs; ++ aarch64_gregset_t aarch64_regs; ++ } cpu_regs[MRDUMP_CPU_MAX]; ++}; ++ ++struct mrdump_machdesc { ++ uint32_t crc; ++ ++ uint32_t output_device; ++ ++ uint32_t nr_cpus; ++ ++ uint64_t page_offset; ++ uint64_t high_memory; ++ ++ uint64_t vmalloc_start; ++ uint64_t vmalloc_end; ++ ++ uint64_t modules_start; ++ uint64_t modules_end; ++ ++ uint64_t phys_offset; ++ uint64_t master_page_table; ++ ++ uint32_t output_fstype; ++ uint32_t output_lbaooo; ++}; ++ ++struct mrdump_control_block { ++ char sig[8]; ++ ++ struct mrdump_machdesc machdesc; ++ struct mrdump_crash_record crash_record; ++}; ++ ++/* NOTE!! any change to this struct should be compatible in aed */ ++struct mrdump_mini_reg_desc { ++ unsigned long reg; /* register value */ ++ unsigned long kstart; /* start kernel addr of memory dump */ ++ unsigned long kend; /* end kernel addr of memory dump */ ++ unsigned long pos; /* next pos to dump */ ++ int valid; /* 1: valid regiser, 0: invalid regiser */ ++ int pad; /* reserved */ ++ loff_t offset; /* offset in buffer */ ++}; ++ ++/* it should always be smaller than MRDUMP_MINI_HEADER_SIZE */ ++struct mrdump_mini_header { ++ struct mrdump_mini_reg_desc reg_desc[ELF_NGREG]; ++}; ++ ++#define MRDUMP_MINI_NR_SECTION 60 ++#define MRDUMP_MINI_SECTION_SIZE (32 * 1024) ++#define NT_IPANIC_MISC 4095 ++#define MRDUMP_MINI_NR_MISC 20 ++ ++struct mrdump_mini_elf_misc { ++ unsigned long vaddr; ++ unsigned long paddr; ++ unsigned long start; ++ unsigned long size; ++}; ++ ++#define NOTE_NAME_SHORT 12 ++#define NOTE_NAME_LONG 20 ++ ++struct mrdump_mini_elf_psinfo { ++ struct elf_note note; ++ char name[NOTE_NAME_SHORT]; ++ struct elf_prpsinfo data; ++}; ++ ++struct mrdump_mini_elf_prstatus { ++ struct elf_note note; ++ char name[NOTE_NAME_SHORT]; ++ struct elf_prstatus data; ++}; ++ ++struct mrdump_mini_elf_note { ++ struct elf_note note; ++ char name[NOTE_NAME_LONG]; ++ struct mrdump_mini_elf_misc data; ++}; ++ ++struct mrdump_mini_elf_header { ++ struct elfhdr ehdr; ++ struct elf_phdr phdrs[MRDUMP_MINI_NR_SECTION]; ++ struct mrdump_mini_elf_psinfo psinfo; ++ struct mrdump_mini_elf_prstatus prstatus[NR_CPUS + 1]; ++ struct mrdump_mini_elf_note misc[MRDUMP_MINI_NR_MISC]; ++}; ++ ++typedef struct mrdump_rsvmem_block { ++ phys_addr_t start_addr; ++ phys_addr_t size; ++} mrdump_rsvmem_block_t; ++ ++ ++#define MRDUMP_MINI_HEADER_SIZE ALIGN(sizeof(struct mrdump_mini_elf_header), PAGE_SIZE) ++#define MRDUMP_MINI_DATA_SIZE (MRDUMP_MINI_NR_SECTION * MRDUMP_MINI_SECTION_SIZE) ++#define MRDUMP_MINI_BUF_SIZE (MRDUMP_MINI_HEADER_SIZE + MRDUMP_MINI_DATA_SIZE) ++ ++#ifdef CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR ++#define MRDUMP_MINI_BUF_PADDR (CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR + 0xf0000) ++#else ++#define MRDUMP_MINI_BUF_PADDR 0 ++#endif ++ ++int mrdump_init(void); ++void __mrdump_create_oops_dump(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, ++ ...); ++#if defined(CONFIG_MTK_AEE_IPANIC) ++void mrdump_rsvmem(void); ++#else ++static inline void mrdump_rsvmem(void) ++{ ++} ++#endif ++ ++#if defined(CONFIG_MTK_AEE_MRDUMP) ++void aee_kdump_reboot(AEE_REBOOT_MODE, const char *msg, ...); ++#else ++static inline void aee_kdump_reboot(AEE_REBOOT_MODE reboot_mode, const char *msg, ...) ++{ ++} ++#endif ++ ++typedef int (*mrdump_write)(void *buf, int off, int len, int encrypt); ++#if defined(CONFIG_MTK_AEE_IPANIC) ++int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, ++ loff_t sd_offset, const char *msg, va_list ap); ++void mrdump_mini_reserve_memory(void); ++#else ++static inline int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, ++ loff_t sd_offset, const char *msg, va_list ap) ++{ ++ return 0; ++} ++ ++static inline void mrdump_mini_reserve_memory(void) ++{ ++} ++#endif ++ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h +new file mode 100644 +index 000000000000..1b60f007d0fd +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++ ++#ifndef _MT8167_THERMAL_H ++#define _MT8167_THERMAL_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "sync_write.h" ++ ++extern void __iomem *thermal_base; ++extern void __iomem *auxadc_ts_base; ++extern void __iomem *apmixed_base; ++extern void __iomem *pericfg_base; ++extern int auxadc_ts_phy_base; ++extern int apmixed_phy_base; ++ ++#define THERM_CTRL_BASE_2 thermal_base ++#define AUXADC_BASE_2 auxadc_ts_base ++#define PERICFG_BASE pericfg_base ++#define APMIXED_BASE_2 apmixed_base ++ ++#define MT6752_EVB_BUILD_PASS /*Jerry fix build error FIX_ME*/ ++ ++/******************************************************************************* ++* AUXADC Register Definition ++******************************************************************************/ ++/*AUXADC_BASE: 0xF1001000 from Vincent Liang 2014.5.8*/ ++ ++#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /*yes, 0x11003000*/ ++#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) ++#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) ++#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) ++#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) ++/*#define AUXADC_CON3_V (AUXADC_BASE_2 + 0x014)*/ ++#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) ++#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) ++#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) ++#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) ++#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) ++#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) ++#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) ++#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) ++#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) ++#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) ++#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) ++#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) ++#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) ++ ++#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) ++#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) ++#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) ++#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) ++#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) ++/*#define AUXADC_CON3_P (auxadc_ts_phy_base + 0x014)*/ ++#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) ++#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) ++#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) ++#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) ++#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) ++#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) ++#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) ++#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) ++#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) ++#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) ++#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) ++#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) ++ ++#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) ++ ++/******************************************************************************* ++* Peripheral Configuration Register Definition ++******************************************************************************/ ++/*#define PERICFG_BASE (0x10002000)*/ ++#define PERI_GLOBALCON_RST0 (pericfg_base + 0x000) /*yes, 0x10002000*/ ++/******************************************************************************* ++ * APMixedSys Configuration Register Definition ++ ******************************************************************************/ ++#define TS_CON0 (APMIXED_BASE_2 + 0x600) /*yes 0x10209000*/ ++#define TS_CON1 (APMIXED_BASE_2 + 0x604) ++#define TS_CON0_TM (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ ++#define TS_CON1_TM (APMIXED_BASE_2 + 0x604) ++#define TS_CON0_P (apmixed_phy_base + 0x600) ++#define TS_CON1_P (apmixed_phy_base + 0x604) ++ ++/******************************************************************************* ++ * Thermal Controller Register Definition ++ ******************************************************************************/ ++#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /*yes 0x1100B000*/ ++#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) ++#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) ++#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) ++#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) ++#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) ++#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) ++#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) ++#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) ++#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) ++#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) ++#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) ++#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) ++#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) ++#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) ++#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) ++#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) ++#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) ++#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) ++#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) ++#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) ++ ++#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) ++#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) ++#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) ++#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) ++#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) ++#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) ++#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) ++#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) ++#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) ++#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) ++#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) ++#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) ++#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) ++#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) ++#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) ++#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) ++#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) ++#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) ++#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) ++ ++#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) ++#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) ++#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) ++#define TEMPIMMD3 (THERM_CTRL_BASE_2 + 0x0BC) ++ ++ ++#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) ++#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) ++#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) ++#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) ++ ++#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) ++#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) ++#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) ++#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) ++ ++#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) ++#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) ++#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) ++#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) ++#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) ++#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) ++#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) ++#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /*Only for DE debug*/ ++#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) ++#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) ++#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) ++#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) ++#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) ++ ++ ++#define PTPSPARE0_P (thermal_phy_base + 0x420) ++#define PTPSPARE1_P (thermal_phy_base + 0x424) ++#define PTPSPARE2_P (thermal_phy_base + 0x428) ++#define PTPSPARE3_P (thermal_phy_base + 0x42C) ++ ++/******************************************************************************* ++ * Thermal Controller Register Mask Definition ++ ******************************************************************************/ ++#define THERMAL_ENABLE_SEN0 0x1 ++#define THERMAL_ENABLE_SEN1 0x2 ++#define THERMAL_ENABLE_SEN2 0x4 ++#define THERMAL_MONCTL0_MASK 0x00000007 ++ ++#define THERMAL_PUNT_MASK 0x00000FFF ++#define THERMAL_FSINTVL_MASK 0x03FF0000 ++#define THERMAL_SPINTVL_MASK 0x000003FF ++#define THERMAL_MON_INT_MASK 0x0007FFFF ++ ++#define THERMAL_MON_CINTSTS0 0x000001 ++#define THERMAL_MON_HINTSTS0 0x000002 ++#define THERMAL_MON_LOINTSTS0 0x000004 ++#define THERMAL_MON_HOINTSTS0 0x000008 ++#define THERMAL_MON_NHINTSTS0 0x000010 ++#define THERMAL_MON_CINTSTS1 0x000020 ++#define THERMAL_MON_HINTSTS1 0x000040 ++#define THERMAL_MON_LOINTSTS1 0x000080 ++#define THERMAL_MON_HOINTSTS1 0x000100 ++#define THERMAL_MON_NHINTSTS1 0x000200 ++#define THERMAL_MON_CINTSTS2 0x000400 ++#define THERMAL_MON_HINTSTS2 0x000800 ++#define THERMAL_MON_LOINTSTS2 0x001000 ++#define THERMAL_MON_HOINTSTS2 0x002000 ++#define THERMAL_MON_NHINTSTS2 0x004000 ++#define THERMAL_MON_TOINTSTS 0x008000 ++#define THERMAL_MON_IMMDINTSTS0 0x010000 ++#define THERMAL_MON_IMMDINTSTS1 0x020000 ++#define THERMAL_MON_IMMDINTSTS2 0x040000 ++#define THERMAL_MON_FILTINTSTS0 0x080000 ++#define THERMAL_MON_FILTINTSTS1 0x100000 ++#define THERMAL_MON_FILTINTSTS2 0x200000 ++ ++ ++#define THERMAL_tri_SPM_State0 0x20000000 ++#define THERMAL_tri_SPM_State1 0x40000000 ++#define THERMAL_tri_SPM_State2 0x80000000 ++ ++ ++#define THERMAL_MSRCTL0_MASK 0x00000007 ++#define THERMAL_MSRCTL1_MASK 0x00000038 ++#define THERMAL_MSRCTL2_MASK 0x000001C0 ++ ++enum thermal_sensor_name { ++ THERMAL_SENSOR1 = 0,/*TS_MCU1*/ ++ THERMAL_SENSOR_NUM ++}; ++ ++enum thermal_bank_name { ++ THERMAL_BANK0 = 0, /*CPU (TS_MCU1) (TS1)*/ ++ THERMAL_BANK_NUM ++}; ++ ++struct TS_SVS { ++ unsigned int ts_MTS; ++ unsigned int ts_BTS; ++}; ++ ++struct mtk_gpu_power_info { ++ unsigned int gpufreq_khz; ++ unsigned int gpufreq_power; ++}; ++ ++/* svs driver need this function */ ++extern void get_thermal_slope_intercept(struct TS_SVS *ts_info, enum thermal_bank_name ts_bank); ++ ++/* mtk_thermal_platform.c need this */ ++extern void set_taklking_flag(bool flag); ++ ++#define THERMAL_WRAP_WR32(val, addr) mt_reg_sync_writel((val), ((void *)addr)) ++ ++enum MTK_THERMAL_SENSOR_CPU_ID_MET { ++ MTK_THERMAL_SENSOR_TS1 = 0, ++ MTK_THERMAL_SENSOR_TS2, ++ MTK_THERMAL_SENSOR_TS3, ++ MTK_THERMAL_SENSOR_TS4, ++ MTK_THERMAL_SENSOR_TSABB, ++ ++ ATM_CPU_LIMIT, ++ ATM_GPU_LIMIT, ++ ++ MTK_THERMAL_SENSOR_CPU_COUNT ++}; ++ ++extern int tscpu_get_cpu_temp_met(enum MTK_THERMAL_SENSOR_CPU_ID_MET id); ++extern int mtk_gpufreq_register(struct mtk_gpu_power_info *freqs, int num); ++ ++typedef void (*met_thermalsampler_funcMET)(void); ++void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); ++ ++void tscpu_start_thermal(void); ++void tscpu_stop_thermal(void); ++void tscpu_cancel_thermal_timer(void); ++void tscpu_start_thermal_timer(void); ++int mtkts_bts_get_hw_temp(void); ++ ++extern int get_immediate_ts1_wrap(void); ++extern int get_immediate_ts2_wrap(void); ++extern int get_immediate_ts3_wrap(void); ++ ++extern int is_cpu_power_unlimit(void); /* in mtk_ts_cpu.c */ ++extern int is_cpu_power_min(void); /* in mtk_ts_cpu.c */ ++extern int get_cpu_target_tj(void); ++extern int get_cpu_target_offset(void); ++ ++extern int mtktscpu_debug_log; ++ ++#endif ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h +new file mode 100644 +index 000000000000..142a007805b9 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright (C) 2011 MediaTek, Inc. ++ * ++ * Author: Holmes Chiou ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef __MT_FREQHOPPING_H__ ++#define __MT_FREQHOPPING_H__ ++ ++#define MT_FHPLL_MAX 6 ++#define MT_SSC_NR_PREDEFINE_SETTING 10 /* TODO: is 10 a good number ? */ ++ ++#define MEMPLL_SSC 0 ++#define MAINPLL_SSC 1 ++ ++#define FHTAG "[FH]" ++ ++#define VERBOSE_DEBUG 0 ++ ++#if VERBOSE_DEBUG ++#define FH_MSG(fmt, args...) \ ++ pr_debug(FHTAG""fmt" <- %s(): L<%d> PID<%s><%d>\n", ##args, __func__, __LINE__, current->comm, current->pid) ++#else ++ ++#if 1 /* log level is 6 xlog */ ++#define FH_MSG(fmt, args...) pr_debug(fmt, ##args) ++#else /* log level is 4 (printk) */ ++#define FH_MSG(fmt, args...) printk(FHTAG""fmt"\n", ##args) ++#endif ++ ++#endif ++ ++/* not support at mt2701 yet */ ++/* DRAMC */ ++#define FULLY_VERSION_FHCTL 0 ++ ++enum FH_FH_STATUS { ++ FH_FH_DISABLE = 0, ++ FH_FH_ENABLE_SSC, ++ FH_FH_ENABLE_DFH, ++ FH_FH_ENABLE_DVFS, ++}; ++ ++enum FH_PLL_STATUS { ++ FH_PLL_DISABLE = 0, ++ FH_PLL_ENABLE = 1 ++}; ++ ++/* TODO: FREQ_MODIFIED should not be here */ ++/* FH_PLL_STATUS_FREQ_MODIFIED = 3 */ ++ ++ ++enum FH_CMD { ++ FH_CMD_ENABLE = 1, ++ FH_CMD_DISABLE, ++ FH_CMD_ENABLE_USR_DEFINED, ++ FH_CMD_DISABLE_USR_DEFINED, ++ FH_CMD_INTERNAL_MAX_CMD, ++/* TODO: do we need these cmds ? ++ * FH_CMD_PLL_ENABLE, ++ * FH_CMD_PLL_DISABLE, ++ * FH_CMD_EXT_ALL_FULL_RANGE_CMD, ++ * FH_CMD_EXT_ALL_HALF_RANGE_CMD, ++ * FH_CMD_EXT_DISABLE_ALL_CMD, ++ * FH_CMD_EXT_DESIGNATED_PLL_FULL_RANGE_CMD, ++ * FH_CMD_EXT_DESIGNATED_PLL_AND_SETTING_CMD ++*/ ++}; ++ ++/* ++ * enum FH_OPCODE{ ++ * FH_OPCODE_ENABLE_WITH_ID = 1, ++ * FH_OPCODE_ENABLE_WITHOUT_ID, ++ * FH_OPCODE_DISABLE, ++ * }; ++*/ ++ ++enum FH_PLL_ID { ++ MT658X_FH_MINIMUMM_PLL = 0, ++ MT658X_FH_ARM_PLL = MT658X_FH_MINIMUMM_PLL, ++ MT658X_FH_MAIN_PLL = 1, ++ MT658X_FH_MEM_PLL = 2, ++ MT658X_FH_MSDC_PLL = 3, ++ MT658X_FH_MM_PLL = 4, /* MT658X_FH_TVD_PLL = 4, */ ++ MT658X_FH_VENC_PLL = 5, /* MT658X_FH_LVDS_PLL = 5, */ ++ /* 8127 FHCTL MB */ ++ MT658X_FH_TVD_PLL = 6, /* MT658X_FH_TVD_PLL = 6, */ ++ MT658X_FH_MAXIMUMM_PLL = MT658X_FH_TVD_PLL, ++ /* 8127 FHCTL ME */ ++ MT658X_FH_PLL_TOTAL_NUM ++}; ++ ++/* keep track the status of each PLL */ ++/* TODO: do we need another "uint mode" for Dynamic FH */ ++typedef struct { ++ unsigned int fh_status; ++ unsigned int pll_status; ++ unsigned int setting_id; ++ unsigned int curr_freq; ++ unsigned int user_defined; ++} fh_pll_t; ++ ++ ++/* Record the owner of enable freq hopping <==TBD */ ++struct freqhopping_pll { ++ union { ++ int mt_pll[MT_FHPLL_MAX]; ++ struct { ++ int mt_arm_fhpll; ++ int mt_main_fhpll; ++ int mt_mem_fhpll; ++ int mt_msdc_fhpll; ++ int mt_mm_fhpll; ++ int mt_venc_fhpll; ++ }; ++ }; ++}; ++ ++struct freqhopping_ssc { ++ unsigned int freq; ++ unsigned int dt; ++ unsigned int df; ++ unsigned int upbnd; ++ unsigned int lowbnd; ++ unsigned int dds; ++}; ++ ++struct freqhopping_ioctl { ++ unsigned int pll_id; ++ struct freqhopping_ssc ssc_setting; /* used only when user-define */ ++ int result; ++}; ++ ++int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable); ++void mt_freqhopping_init(void); ++void mt_freqhopping_pll_init(void); ++int mt_h2l_mempll(void); ++int mt_l2h_mempll(void); ++int mt_h2l_dvfs_mempll(void); ++int mt_l2h_dvfs_mempll(void); ++int mt_dfs_armpll(unsigned int current_freq, unsigned int target_freq); ++int mt_is_support_DFS_mode(void); ++void mt_fh_popod_save(void); ++void mt_fh_popod_restore(void); ++int mt_fh_dram_overclock(int clk); ++int mt_fh_get_dramc(void); ++unsigned int mt_get_emi_freq(void); ++ ++#endif /* !__MT_FREQHOPPING_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h +new file mode 100644 +index 000000000000..0c049db9aa97 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2015 MediaTek Inc. ++ * ++ * 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. ++ */ ++ ++#include ++ ++#define STA_POWER_DOWN 0 ++#define STA_POWER_ON 1 ++ ++/* ++ * 1. for CPU MTCMOS: CPU0, CPU1, CPU2, CPU3, DBG0, CPU4, CPU5, CPU6, CPU7, DBG1, CPUSYS1 ++ * 2. call spm_mtcmos_cpu_lock/unlock() before/after any operations ++ */ ++extern int spm_mtcmos_cpu_init(void); ++extern void spm_mtcmos_cpu_lock(unsigned long *flags); ++extern void spm_mtcmos_cpu_unlock(unsigned long *flags); ++extern int spm_mtcmos_ctrl_cpu(unsigned int cpu, int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu0(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu1(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu2(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu3(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu4(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu5(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu6(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpu7(int state, int chkWfiBeforePdn); ++extern int spm_mtcmos_ctrl_cpusys0(int state, int chkWfiBeforePdn); ++extern bool spm_cpusys0_can_power_down(void); +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h +new file mode 100644 +index 000000000000..28176b3cd9af +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2015 MediaTek Inc. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_BOOT_SHARE_PAGE_H__ ++#define __MTK_BOOT_SHARE_PAGE_H__ ++ ++#define BOOT_SHARE_BASE (0xC0002000) /* address in linux kernel */ ++#define BOOT_SHARE_SIZE (0x1000) /* page size 4K bytes */ ++ ++#define BOOT_SHARE_MAGIC (0x4545544D) /* MTEE */ ++ ++/* Memory map & defines for boot share page */ ++/* ++ * Note: ++ * 1. BOOT_SHARE_XXXXX_OFST is the address offset related to BOOT_SHARE_BASE ++ */ ++#define BOOT_SHARE_MAGIC1_OFST (0) ++#define BOOT_SHARE_MAGIC1_SIZE (4) ++ ++#define BOOT_SHARE_DEV_INFO_OFST (BOOT_SHARE_MAGIC1_OFST+BOOT_SHARE_MAGIC1_SIZE) ++#define BOOT_SHARE_DEV_INFO_SIZE (16) ++ ++#define BOOT_SHARE_HOTPLUG_OFST (1008) /* 16 bytes for hotplug/jump-reg */ ++#define BOOT_SHARE_HOTPLUG_SIZE (32) ++ ++#define BOOT_SHARE_MAGIC2_OFST (4092) ++#define BOOT_SHARE_MAGIC2_SIZE (4) ++ ++#endif /* __MTK_BOOT_SHARE_PAGE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h +new file mode 100644 +index 000000000000..eefdaad4aaa5 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h +@@ -0,0 +1,301 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#ifndef _MT8127_THERMAL_H ++#define _MT8127_THERMAL_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "mt-plat/sync_write.h" ++#include ++ ++/* #include */ ++/* #include "../../../../../thermal/mt8127/inc/mt_gpufreq.h" */ ++ ++#if 1 ++extern void __iomem *thermal_base; ++extern void __iomem *auxadc_ts_base; ++extern void __iomem *pericfg_base; ++extern void __iomem *apmixed_ts_base; ++ ++extern int mtktscpu_limited_dmips; ++ ++void __attribute__ ((weak)) mt_gpufreq_thermal_protect(unsigned int limited_power) { ++} ++ ++unsigned int __attribute__ ((weak)) mt_gpufreq_get_cur_freq(void) { ++ return 0; ++} ++ ++u32 __attribute__ ((weak)) get_devinfo_with_index(u32 index) { ++ return 0; ++} ++ ++extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); ++extern int IMM_IsAdcInitReady(void); ++extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); ++extern int thermal_phy_base; ++extern int auxadc_ts_phy_base; ++extern int apmixed_phy_base; ++extern int pericfg_phy_base; ++ ++/* extern int last_abb_t; */ ++/* extern int last_CPU2_t; */ ++extern int get_immediate_temp2_wrap(void); ++extern void mtkts_dump_cali_info(void); ++extern u32 get_devinfo_with_index(u32 index); ++extern int bts_cur_temp; ++ ++#define THERM_CTRL_BASE_2 thermal_base ++#define AUXADC_BASE_2 auxadc_ts_base ++#define PERICFG_BASE_2 pericfg_base ++#define APMIXED_BASE_2 apmixed_ts_base ++#endif ++ ++/******************************************************************************* ++ * AUXADC Register Definition ++ ******************************************************************************/ ++#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /* yes, 0x11001000 */ ++#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) ++#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) ++#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) ++#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) ++#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) ++#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) ++#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) ++#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) ++#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) ++#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) ++#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) ++#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) ++#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) ++#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) ++#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) ++#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) ++#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) ++#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) ++#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) ++#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) ++#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) ++#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) ++#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) ++#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) ++#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) ++#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) ++#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) ++#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) ++#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) ++#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) ++#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) ++#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) ++#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) ++#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) ++#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) ++ ++/******************************************************************************* ++ * Peripheral Configuration Register Definition ++ ******************************************************************************/ ++#define PERI_GLOBALCON_RST0 (PERICFG_BASE_2 + 0x000) /* yes, 0x10003000 */ ++ ++/******************************************************************************* ++ * APMixedSys Configuration Register Definition ++ ******************************************************************************/ ++#define TS_CON0 (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ ++#define TS_CON1 (APMIXED_BASE_2 + 0x604) ++/******************************************************************************* ++ * Thermal Controller Register Definition ++ ******************************************************************************/ ++#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /* yes 0x1100B000 */ ++#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) ++#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) ++#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) ++#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) ++#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) ++#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) ++#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) ++#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) ++#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) ++#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) ++#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) ++#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) ++#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) ++#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) ++#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) ++#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) ++#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) ++#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) ++#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) ++#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) ++ ++#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) ++#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) ++#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) ++#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) ++#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) ++#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) ++#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) ++#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) ++#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) ++#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) ++#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) ++#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) ++#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) ++#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) ++#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) ++#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) ++#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) ++#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) ++#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) ++ ++#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) ++#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) ++#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) ++ ++#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) ++#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) ++#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) ++#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) ++ ++#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) ++#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) ++#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) ++#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) ++ ++#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) ++#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) ++#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) ++#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) ++#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) ++#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) ++#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) ++#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /* Only for DE debug */ ++#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) ++#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) ++#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) ++#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) ++#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) ++ ++/******************************************************************************* ++ * Thermal Controller Register Mask Definition ++ ******************************************************************************/ ++#define THERMAL_ENABLE_SEN0 0x1 ++#define THERMAL_ENABLE_SEN1 0x2 ++#define THERMAL_ENABLE_SEN2 0x4 ++#define THERMAL_MONCTL0_MASK 0x00000007 ++ ++#define THERMAL_PUNT_MASK 0x00000FFF ++#define THERMAL_FSINTVL_MASK 0x03FF0000 ++#define THERMAL_SPINTVL_MASK 0x000003FF ++#define THERMAL_MON_INT_MASK 0x0007FFFF ++ ++#define THERMAL_MON_CINTSTS0 0x000001 ++#define THERMAL_MON_HINTSTS0 0x000002 ++#define THERMAL_MON_LOINTSTS0 0x000004 ++#define THERMAL_MON_HOINTSTS0 0x000008 ++#define THERMAL_MON_NHINTSTS0 0x000010 ++#define THERMAL_MON_CINTSTS1 0x000020 ++#define THERMAL_MON_HINTSTS1 0x000040 ++#define THERMAL_MON_LOINTSTS1 0x000080 ++#define THERMAL_MON_HOINTSTS1 0x000100 ++#define THERMAL_MON_NHINTSTS1 0x000200 ++#define THERMAL_MON_CINTSTS2 0x000400 ++#define THERMAL_MON_HINTSTS2 0x000800 ++#define THERMAL_MON_LOINTSTS2 0x001000 ++#define THERMAL_MON_HOINTSTS2 0x002000 ++#define THERMAL_MON_NHINTSTS2 0x004000 ++#define THERMAL_MON_TOINTSTS 0x008000 ++#define THERMAL_MON_IMMDINTSTS0 0x010000 ++#define THERMAL_MON_IMMDINTSTS1 0x020000 ++#define THERMAL_MON_IMMDINTSTS2 0x040000 ++#define THERMAL_MON_FILTINTSTS0 0x080000 ++#define THERMAL_MON_FILTINTSTS1 0x100000 ++#define THERMAL_MON_FILTINTSTS2 0x200000 ++ ++ ++#define THERMAL_tri_SPM_State0 0x20000000 ++#define THERMAL_tri_SPM_State1 0x40000000 ++#define THERMAL_tri_SPM_State2 0x80000000 ++ ++ ++#define THERMAL_MSRCTL0_MASK 0x00000007 ++#define THERMAL_MSRCTL1_MASK 0x00000038 ++#define THERMAL_MSRCTL2_MASK 0x000001C0 ++ ++/* extern int thermal_one_shot_handler(int times); */ ++ ++typedef enum { ++ THERMAL_SENSOR1 = 0, /* TS1 */ ++ THERMAL_SENSOR_NUM ++} thermal_sensor_name; ++ ++struct TS_PTPOD { ++ unsigned int ts_MTS; ++ unsigned int ts_BTS; ++}; ++ ++extern void get_thermal_slope_intercept(struct TS_PTPOD *ts_info); ++extern void set_taklking_flag(bool flag); ++extern int tscpu_get_cpu_temp(void); ++ ++/*5 thermal sensors*/ ++typedef enum { ++ MTK_THERMAL_SENSOR_TS1 = 0, ++ ATM_CPU_LIMIT, ++ ATM_GPU_LIMIT, ++ MTK_THERMAL_SENSOR_CPU_COUNT ++} MTK_THERMAL_SENSOR_CPU_ID_MET; ++ ++struct mtk_cpu_power_info { ++ unsigned int cpufreq_khz; ++ unsigned int cpufreq_ncpu; ++ unsigned int cpufreq_power; ++}; ++extern int mtk_cpufreq_register(struct mtk_cpu_power_info *freqs, int num); ++ ++extern int tscpu_get_cpu_temp_met(MTK_THERMAL_SENSOR_CPU_ID_MET id); ++ ++ ++typedef void (*met_thermalsampler_funcMET) (void); ++void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); ++ ++void tscpu_start_thermal(void); ++void tscpu_stop_thermal(void); ++void tscpu_cancel_thermal_timer(void); ++void tscpu_start_thermal_timer(void); ++int mtkts_AP_get_hw_temp(void); ++ ++extern int amddulthro_backoff(int level); ++/* extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); */ ++/* extern int IMM_IsAdcInitReady(void); */ ++extern int get_immediate_temp2_wrap(void); ++extern void mtkts_dump_cali_info(void); ++extern unsigned int read_dram_temperature(void); ++extern int mtk_thermal_get_cpu_load_sum(void); ++ ++/********************************** ++ * Power table struct for thermal ++ **********************************/ ++struct mt_gpufreq_power_table_info { ++ unsigned int gpufreq_khz; ++ unsigned int gpufreq_volt; ++ unsigned int gpufreq_power; ++}; ++ ++extern int mtk_gpufreq_register(struct mt_gpufreq_power_table_info *freqs, int num); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mt_sched.h b/drivers/misc/mediatek/include/mt-plat/mt_sched.h +new file mode 100644 +index 000000000000..71206f080548 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mt_sched.h +@@ -0,0 +1,34 @@ ++/* ++* Copyright (C) 2016 MediaTek Inc. ++* ++* 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. ++* ++* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++*/ ++ ++#ifdef CONFIG_MTK_SCHED_RQAVG_US ++/* ++ * @cpu: cpu id ++ * @reset: reset the statistic start time after this time query ++ * @use_maxfreq: caculate cpu loading with max cpu max frequency ++ * return: cpu loading as percentage (0~100) ++ */ ++extern unsigned int sched_get_percpu_load(int cpu, bool reset, bool use_maxfreq); ++ ++/* ++ * return: heavy task(loading>90%) number in the system ++ */ ++extern unsigned int sched_get_nr_heavy_task(void); ++ ++/* ++ * @threshold: heavy task loading threshold (0~1023) ++ * return: heavy task(loading>threshold) number in the system ++ */ ++extern unsigned int sched_get_nr_heavy_task_by_threshold(unsigned int threshold); ++#endif /* CONFIG_MTK_SCHED_RQAVG_US */ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_io.h b/drivers/misc/mediatek/include/mt-plat/mtk_io.h +new file mode 100644 +index 000000000000..de17db505d3e +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_io.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MT_IO_H__ ++#define __MT_IO_H__ ++ ++/* only for arm64 */ ++#ifdef CONFIG_ARM64 ++#define IOMEM(a) ((void __force __iomem *)((a))) ++#endif ++ ++#endif /* !__MT_IO_H__ */ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h +new file mode 100644 +index 000000000000..d679c5a1ce73 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_LPAE_H__ ++#define __MTK_LPAE_H__ ++#ifdef CONFIG_MTK_LM_MODE ++ ++#include ++ ++#define INTERAL_MAPPING_OFFSET (0x40000000) ++#define INTERAL_MAPPING_LIMIT (INTERAL_MAPPING_OFFSET + 0x80000000) ++ ++#define MT_OVERFLOW_ADDR_START 0x100000000ULL ++ ++unsigned int __attribute__((weak)) enable_4G(void) ++{ ++ return 0; ++} ++ ++/* For HW modules which support 33-bit address setting */ ++#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) \ ++ do { \ ++ ret = 0; \ ++ if (enable_4G()) {\ ++ if (((phys_addr_t)phy_addr < MT_OVERFLOW_ADDR_START)\ ++ && (((phys_addr_t)phy_addr + size) >= MT_OVERFLOW_ADDR_START)) \ ++ ret = MT_OVERFLOW_ADDR_START - phy_addr; \ ++ } \ ++ } while (0) \ ++ ++/* For SPM and MD32 only in ROME */ ++#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) \ ++ do { \ ++ if (enable_4G()) {\ ++ if (phy_addr >= INTERAL_MAPPING_OFFSET && phy_addr < INTERAL_MAPPING_LIMIT) \ ++ phy_addr += INTERAL_MAPPING_OFFSET; \ ++ } \ ++ } while (0)\ ++ ++#else /* !CONFIG_ARM_LPAE */ ++ ++#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) ++#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) ++#define MT_OVERFLOW_ADDR_START 0 ++ ++static inline unsigned int enable_4G(void) ++{ ++ return 0; ++} ++ ++#endif ++#endif /*!__MTK_LPAE_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h +new file mode 100644 +index 000000000000..7baafc4329bf +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_MDM_MONITOR_H ++#define _MTK_MDM_MONITOR_H ++ ++struct md_info { ++ char *attribute; ++ int value; ++ char *unit; ++ int invalid_value; ++ int index; ++}; ++ ++extern ++int mtk_mdm_get_md_info(struct md_info **p_inf, int *size); ++ ++extern ++int mtk_mdm_start_query(void); ++ ++extern ++int mtk_mdm_stop_query(void); ++ ++extern ++int mtk_mdm_set_signal_period(int second); ++ ++extern ++int mtk_mdm_set_md1_signal_period(int second); ++ ++extern ++int mtk_mdm_set_md2_signal_period(int second); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h +new file mode 100644 +index 000000000000..8f20f38b75d6 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2016 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_PLATFORM_DEBUG_H__ ++#define __MTK_PLATFORM_DEBUG_H__ ++ ++#ifdef CONFIG_MTK_PLAT_SRAM_FLAG ++/* plat_sram_flag */ ++extern int set_sram_flag_lastpc_valid(void); ++extern int set_sram_flag_dfd_valid(void); ++extern int set_sram_flag_etb_user(unsigned int etb_id, unsigned int user_id); ++#endif ++ ++#ifdef CONFIG_MTK_DFD_INTERNAL_DUMP ++extern int dfd_setup(void); ++#endif ++ ++#endif /* __MTK_PLATFORM_DEBUG_H__ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h +new file mode 100644 +index 000000000000..3a94a1bbcd24 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h +@@ -0,0 +1,162 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __MTK_RAM_CONSOLE_H__ ++#define __MTK_RAM_CONSOLE_H__ ++ ++#include ++#include ++ ++typedef enum { ++ AEE_FIQ_STEP_FIQ_ISR_BASE = 1, ++ AEE_FIQ_STEP_WDT_FIQ_INFO = 4, ++ AEE_FIQ_STEP_WDT_FIQ_STACK, ++ AEE_FIQ_STEP_WDT_FIQ_LOOP, ++ AEE_FIQ_STEP_WDT_FIQ_DONE, ++ AEE_FIQ_STEP_WDT_IRQ_INFO = 8, ++ AEE_FIQ_STEP_WDT_IRQ_KICK, ++ AEE_FIQ_STEP_WDT_IRQ_SMP_STOP, ++ AEE_FIQ_STEP_WDT_IRQ_TIME, ++ AEE_FIQ_STEP_WDT_IRQ_STACK, ++ AEE_FIQ_STEP_WDT_IRQ_GIC, ++ AEE_FIQ_STEP_WDT_IRQ_LOCALTIMER, ++ AEE_FIQ_STEP_WDT_IRQ_IDLE, ++ AEE_FIQ_STEP_WDT_IRQ_SCHED, ++ AEE_FIQ_STEP_WDT_IRQ_DONE, ++ AEE_FIQ_STEP_KE_WDT_INFO = 20, ++ AEE_FIQ_STEP_KE_WDT_PERCPU, ++ AEE_FIQ_STEP_KE_WDT_LOG, ++ AEE_FIQ_STEP_KE_SCHED_DEBUG, ++ AEE_FIQ_STEP_KE_EINT_DEBUG, ++ AEE_FIQ_STEP_KE_WDT_DONE, ++ AEE_FIQ_STEP_KE_IPANIC_DIE = 32, ++ AEE_FIQ_STEP_KE_IPANIC_START, ++ AEE_FIQ_STEP_KE_IPANIC_OOP_HEADER, ++ AEE_FIQ_STEP_KE_IPANIC_DETAIL, ++ AEE_FIQ_STEP_KE_IPANIC_CONSOLE, ++ AEE_FIQ_STEP_KE_IPANIC_USERSPACE, ++ AEE_FIQ_STEP_KE_IPANIC_ANDROID, ++ AEE_FIQ_STEP_KE_IPANIC_MMPROFILE, ++ AEE_FIQ_STEP_KE_IPANIC_HEADER, ++ AEE_FIQ_STEP_KE_IPANIC_DONE, ++ AEE_FIQ_STEP_KE_NESTED_PANIC = 64, ++} AEE_FIQ_STEP_NUM; ++ ++#ifdef CONFIG_MTK_RAM_CONSOLE ++extern int aee_rr_curr_fiq_step(void); ++extern void aee_rr_rec_fiq_step(u8 i); ++extern void aee_rr_rec_reboot_mode(u8 mode); ++extern void aee_rr_rec_kdump_params(void *params); ++extern void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j); ++extern void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j); ++extern void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm); ++extern void aee_sram_fiq_log(const char *msg); ++extern void ram_console_write(struct console *console, const char *s, unsigned int count); ++extern void aee_sram_fiq_save_bin(const char *buffer, size_t len); ++extern void aee_rr_rec_hotplug_footprint(int cpu, u8 fp); ++extern void aee_rr_rec_hotplug_cpu_event(u8 val); ++extern void aee_rr_rec_hotplug_cb_index(u8 val); ++extern void aee_rr_rec_hotplug_cb_fp(unsigned long val); ++#ifdef CONFIG_MTK_EMMC_SUPPORT ++extern void last_kmsg_store_to_emmc(void); ++#endif ++ ++#else ++static inline void aee_rr_rec_hotplug_footprint(int cpu, u8 fp) ++{ ++} ++static inline void aee_rr_rec_hotplug_cpu_event(u8 val) ++{ ++} ++static inline void aee_rr_rec_hotplug_cb_index(u8 val) ++{ ++} ++static inline void aee_rr_rec_hotplug_cb_fp(unsigned long val) ++{ ++} ++static inline int aee_rr_curr_fiq_step(void) ++{ ++ return 0; ++} ++ ++static inline void aee_rr_rec_fiq_step(u8 i) ++{ ++} ++ ++static inline unsigned int aee_rr_curr_exp_type(void) ++{ ++ return 0; ++} ++ ++static inline void aee_rr_rec_exp_type(unsigned int type) ++{ ++} ++ ++static inline void aee_rr_rec_reboot_mode(u8 mode) ++{ ++} ++ ++static inline void aee_rr_rec_kdump_params(void *params) ++{ ++} ++ ++static inline void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j) ++{ ++} ++ ++static inline void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j) ++{ ++} ++ ++static inline void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm) ++{ ++} ++ ++static inline void aee_sram_fiq_log(const char *msg) ++{ ++} ++ ++static inline void ram_console_write(struct console *console, const char *s, unsigned int count) ++{ ++} ++ ++static inline void aee_sram_fiq_save_bin(unsigned char *buffer, size_t len) ++{ ++} ++ ++#ifdef CONFIG_MTK_EMMC_SUPPORT ++static inline void last_kmsg_store_to_emmc(void) ++{ ++} ++#endif ++ ++#endif /* CONFIG_MTK_RAM_CONSOLE */ ++ ++#ifdef CONFIG_MTK_AEE_IPANIC ++extern int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size); ++extern int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, ++ char **buf, struct pstore_info *psi); ++#else ++static inline int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size) ++{ ++ return 0; ++} ++ ++static inline int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, ++ char **buf, struct pstore_info *psi) ++{ ++ return 0; ++} ++#endif /* CONFIG_MTK_AEE_IPANIC */ ++ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h +new file mode 100644 +index 000000000000..2181e9989593 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef MTK_RTC_H ++#define MTK_RTC_H ++ ++#include ++#include ++#include ++ ++typedef enum { ++ RTC_GPIO_USER_WIFI = 8, ++ RTC_GPIO_USER_GPS = 9, ++ RTC_GPIO_USER_BT = 10, ++ RTC_GPIO_USER_FM = 11, ++ RTC_GPIO_USER_PMIC = 12, ++} rtc_gpio_user_t; ++ ++#ifdef CONFIG_MTK_RTC ++ ++/* ++ * NOTE: ++ * 1. RTC_GPIO always exports 32K enabled by some user even if the phone is powered off ++ */ ++ ++extern unsigned long rtc_read_hw_time(void); ++extern void rtc_gpio_enable_32k(rtc_gpio_user_t user); ++extern void rtc_gpio_disable_32k(rtc_gpio_user_t user); ++extern bool rtc_gpio_32k_status(void); ++ ++/* for AUDIOPLL (deprecated) */ ++extern void rtc_enable_abb_32k(void); ++extern void rtc_disable_abb_32k(void); ++ ++/* NOTE: used in Sleep driver to workaround Vrtc-Vore level shifter issue */ ++extern void rtc_enable_writeif(void); ++extern void rtc_disable_writeif(void); ++ ++extern void rtc_mark_recovery(void); ++#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) ++extern void rtc_mark_kpoc(void); ++#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ ++extern void rtc_mark_fast(void); ++extern u16 rtc_rdwr_uart_bits(u16 *val); ++extern void rtc_bbpu_power_down(void); ++extern void rtc_read_pwron_alarm(struct rtc_wkalrm *alm); ++extern int get_rtc_spare_fg_value(void); ++extern int set_rtc_spare_fg_value(int val); ++extern void rtc_irq_handler(void); ++extern bool crystal_exist_status(void); ++extern void mt_power_off(void); ++#else/*ifdef CONFIG_MTK_RTC*/ ++#define rtc_read_hw_time() ({ 0; }) ++#define rtc_gpio_enable_32k(user) do {} while (0) ++#define rtc_gpio_disable_32k(user) do {} while (0) ++#define rtc_gpio_32k_status() do {} while (0) ++#define rtc_enable_abb_32k() do {} while (0) ++#define rtc_disable_abb_32k() do {} while (0) ++#define rtc_enable_writeif() do {} while (0) ++#define rtc_disable_writeif() do {} while (0) ++#define rtc_mark_recovery() do {} while (0) ++#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) ++#define rtc_mark_kpoc() do {} while (0) ++#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ ++#define rtc_mark_fast() do {} while (0) ++#define rtc_rdwr_uart_bits(val) ({ 0; }) ++#define rtc_bbpu_power_down() do {} while (0) ++#define rtc_read_pwron_alarm(alm) do {} while (0) ++#define get_rtc_spare_fg_value() ({ 0; }) ++#define set_rtc_spare_fg_value(val) ({ 0; }) ++#define rtc_irq_handler() do {} while (0) ++#define crystal_exist_status() do {} while (0) ++__weak void mt_power_off(void); ++#endif/*ifdef CONFIG_MTK_RTC*/ ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h +new file mode 100644 +index 000000000000..eac6bc713c98 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (c) 2009 Travis Geiselbrecht ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, ++ * including without limitation the rights to use, copy, modify, merge, ++ * publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, ++ * subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _MTK_THERMAL_EXT_CONTROL_H ++#define _MTK_THERMAL_EXT_CONTROL_H ++ ++#define THERMAL_MD32_IPI_MSG_BASE 0x1F00 ++#define THERMAL_AP_IPI_MSG_BASE 0x2F00 ++ ++typedef enum { ++ THERMAL_AP_IPI_MSG_SET_TZ_THRESHOLD = THERMAL_AP_IPI_MSG_BASE, ++ THERMAL_AP_IPI_MSG_MD32_START, ++ ++ THERMAL_MD32_IPI_MSG_READY = THERMAL_MD32_IPI_MSG_BASE, ++ THERMAL_MD32_IPI_MSG_MD32_START_ACK, ++ THERMAL_MD32_IPI_MSG_REACH_THRESHOLD, ++} thermal_ipi_msg_id; ++ ++typedef enum { ++/* MTK_THERMAL_EXT_SENSOR_CPU = 0, */ ++ MTK_THERMAL_EXT_SENSOR_ABB = 0, ++ MTK_THERMAL_EXT_SENSOR_PMIC, ++ MTK_THERMAL_EXT_SENSOR_BATTERY, ++ MTK_THERMAL_EXT_SENSOR_COUNT ++} MTK_THERMAL_EXT_SENSOR_ID; ++ ++typedef struct { ++ int id; /* id of this tz */ ++ int polling_delay; /* polling delay of this tz */ ++ long high_trip_point; /* high threshold of this tz */ ++ long low_trip_point; /* low threshold of this tz */ ++} thermal_zone_data; ++ ++typedef struct { ++ int id; /* id of this tz */ ++ long high_trip_point; /* high threshold of this tz */ ++ long low_trip_point; /* low threshold of this tz */ ++ long temperature; /* Current temperature gotten from TS */ ++} thermal_zone_status; ++ ++typedef struct { ++ short id; ++ union { ++ thermal_zone_data tz; ++ thermal_zone_status tz_status; ++ } data; ++} thermal_ipi_msg; ++ ++#endif /* _MTK_THERMAL_EXT_CONTROL_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h +new file mode 100644 +index 000000000000..7903b49dc419 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_THERMAL_MONITOR_H ++#define _MTK_THERMAL_MONITOR_H ++ ++#include ++ ++/* ++ * MTK_THERMAL_WRAPPER_BYPASS = 1 (use original Linux Thermal API) ++ * MTK_THERMAL_WRAPPER_BYPASS = 0 (use MTK Thermal API Monitor) ++ */ ++#define MTK_THERMAL_WRAPPER_BYPASS 0 ++ ++#if MTK_THERMAL_WRAPPER_BYPASS ++/* Original LTF API */ ++#define mtk_thermal_zone_device_register thermal_zone_device_register ++#define mtk_thermal_zone_device_unregister thermal_zone_device_unregister ++#define mtk_thermal_cooling_device_unregister thermal_cooling_device_unregister ++#define mtk_thermal_cooling_device_register thermal_cooling_device_register ++#define mtk_thermal_zone_bind_cooling_device thermal_zone_bind_cooling_device ++ ++#else ++ ++struct thermal_cooling_device_ops_extra { ++ int (*set_cur_temp)(struct thermal_cooling_device *, unsigned long); ++}; ++ ++extern ++struct thermal_zone_device *mtk_thermal_zone_device_register_wrapper ++(char *type, int trips, void *devdata, const struct thermal_zone_device_ops *ops, ++int tc1, int tc2, int passive_delay, int polling_delay); ++ ++extern ++void mtk_thermal_zone_device_unregister_wrapper(struct thermal_zone_device *tz); ++ ++extern ++struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper ++(char *type, void *devdata, const struct thermal_cooling_device_ops *ops); ++ ++extern ++struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper_extra ++(char *type, void *devdata, const struct thermal_cooling_device_ops *ops, ++const struct thermal_cooling_device_ops_extra *ops_ext); ++ ++extern ++int mtk_thermal_cooling_device_add_exit_point ++(struct thermal_cooling_device *cdev, int exit_point); ++ ++extern ++void mtk_thermal_cooling_device_unregister_wrapper(struct thermal_cooling_device *cdev); ++ ++extern int mtk_thermal_zone_bind_cooling_device_wrapper ++(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev); ++ ++extern int mtk_thermal_zone_bind_trigger_trip(struct thermal_zone_device *tz, int trip, int mode); ++#define mtk_thermal_zone_device_register mtk_thermal_zone_device_register_wrapper ++#define mtk_thermal_zone_device_unregister mtk_thermal_zone_device_unregister_wrapper ++#define mtk_thermal_cooling_device_unregister mtk_thermal_cooling_device_unregister_wrapper ++#define mtk_thermal_cooling_device_register mtk_thermal_cooling_device_register_wrapper ++#define mtk_thermal_zone_bind_cooling_device mtk_thermal_zone_bind_cooling_device_wrapper ++ ++#endif ++ ++typedef enum { ++ MTK_THERMAL_SENSOR_CPU = 0, ++ MTK_THERMAL_SENSOR_ABB, ++ MTK_THERMAL_SENSOR_PMIC, ++ MTK_THERMAL_SENSOR_BATTERY, ++ MTK_THERMAL_SENSOR_MD1, ++ MTK_THERMAL_SENSOR_MD2, ++ MTK_THERMAL_SENSOR_WIFI, ++ MTK_THERMAL_SENSOR_BATTERY2, ++ MTK_THERMAL_SENSOR_BUCK, ++ MTK_THERMAL_SENSOR_AP, ++ MTK_THERMAL_SENSOR_PCB1, ++ MTK_THERMAL_SENSOR_PCB2, ++ MTK_THERMAL_SENSOR_SKIN, ++ MTK_THERMAL_SENSOR_XTAL, ++ MTK_THERMAL_SENSOR_MD_PA, ++ ++ MTK_THERMAL_SENSOR_COUNT ++} MTK_THERMAL_SENSOR_ID; ++ ++extern int mtk_thermal_get_temp(MTK_THERMAL_SENSOR_ID id); ++extern struct proc_dir_entry *mtk_thermal_get_proc_drv_therm_dir_entry(void); ++ ++/* This API function is implemented in mediatek/kernel/drivers/leds/leds.c */ ++extern int setMaxbrightness(int max_level, int enable); ++ ++extern void machine_power_off(void); ++#endif +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h +new file mode 100644 +index 000000000000..305574031196 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MTK_THERMAL_PLATFORM_H ++#define _MTK_THERMAL_PLATFORM_H ++ ++#include ++#include ++ ++extern ++int mtk_thermal_get_cpu_info(int *nocores, int **cpufreq, int **cpuloading); ++ ++extern ++int mtk_thermal_get_gpu_info(int *nocores, int **gpufreq, int **gpuloading); ++ ++extern ++int mtk_thermal_get_batt_info(int *batt_voltage, int *batt_current, int *batt_temp); ++ ++extern ++int mtk_thermal_get_extra_info(int *no_extra_attr, ++ char ***attr_names, int **attr_values, char ***attr_unit); ++ ++extern ++int mtk_thermal_force_get_batt_temp(void); ++ ++ ++enum { ++ MTK_THERMAL_SCEN_CALL = 0x1 ++}; ++ ++extern ++unsigned int mtk_thermal_set_user_scenarios(unsigned int mask); ++ ++extern ++unsigned int mtk_thermal_clear_user_scenarios(unsigned int mask); ++ ++ ++#if defined(CONFIG_MTK_SMART_BATTERY) ++/* global variable from battery driver... */ ++extern kal_bool gFG_Is_Charging; ++#endif ++ ++extern int force_get_tbat(void); ++#endif /* _MTK_THERMAL_PLATFORM_H */ ++ ++ ++typedef enum { ++ TA_DAEMON_CMD_GET_INIT_FLAG = 0, ++ TA_DAEMON_CMD_SET_DAEMON_PID, ++ TA_DAEMON_CMD_NOTIFY_DAEMON, ++ TA_DAEMON_CMD_NOTIFY_DAEMON_CATMINIT, ++ TA_DAEMON_CMD_SET_TTJ, ++ TA_DAEMON_CMD_GET_TPCB, ++ ++ TA_DAEMON_CMD_TO_KERNEL_NUMBER ++} TA_DAEMON_CTRL_CMD_TO_KERNEL; /*must sync userspace/kernel: TA_DAEMON_CTRL_CMD_FROM_USER*/ ++ ++#define TAD_NL_MSG_T_HDR_LEN 12 ++#define TAD_NL_MSG_MAX_LEN 2048 ++ ++struct tad_nl_msg_t { ++ unsigned int tad_cmd; ++ unsigned int tad_data_len; ++ unsigned int tad_ret_data_len; ++ char tad_data[TAD_NL_MSG_MAX_LEN]; ++}; ++ ++enum { ++ TA_CATMPLUS = 1, ++ TA_CONTINUOUS = 2, ++ TA_CATMPLUS_TTJ = 3 ++}; ++ ++ ++struct cATM_params_t { ++ int CATM_ON; ++ int K_TT; ++ int K_SUM_TT_LOW; ++ int K_SUM_TT_HIGH; ++ int MIN_SUM_TT; ++ int MAX_SUM_TT; ++ int MIN_TTJ; ++ int CATMP_STEADY_TTJ_DELTA; ++}; ++struct continuetm_params_t { ++ int STEADY_TARGET_TJ; ++ int MAX_TARGET_TJ; ++ int TRIP_TPCB; ++ int STEADY_TARGET_TPCB; ++}; ++ ++ ++struct CATM_T { ++ struct cATM_params_t t_catm_par; ++ struct continuetm_params_t t_continuetm_par; ++}; ++extern struct CATM_T thermal_atm_t; ++int wakeup_ta_algo(int flow_state); ++int ta_get_ttj(void); ++ ++extern int mtk_thermal_get_tpcb_target(void); ++extern int tsatm_thermal_get_catm_type(void); ++ ++ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h +new file mode 100644 +index 000000000000..1c23a9f4a862 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM thermal ++ ++#if !defined(_MTK_THERMAL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _MTK_THERMAL_TRACE_H ++ ++#include ++ ++TRACE_EVENT(cooling_device_state, ++ TP_PROTO(int device, unsigned long state), ++ TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) ++ __field(unsigned long, state) ++ ), ++ TP_fast_assign(__entry->device = device; ++ __entry->state = state;), ++ TP_printk("cooling_device=%d, state=%lu\n", __entry->device, __entry->state) ++); ++ ++TRACE_EVENT(thermal_zone_state, ++ TP_PROTO(int device, int state), ++ TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) ++ __field(int, state) ++ ), ++ TP_fast_assign(__entry->device = device; ++ __entry->state = state;), ++ TP_printk("thermal_zone=%d, state=%d\n", __entry->device, __entry->state) ++); ++#endif /* _MTK_THERMAL_TRACE_H */ ++ ++/* This part must be outside protection */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#define TRACE_INCLUDE_FILE mach/mtk_thermal_trace ++#include +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h +new file mode 100644 +index 000000000000..dfcef3d952fc +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h +@@ -0,0 +1,241 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _TYPEDEFS_H ++#define _TYPEDEFS_H ++ ++#include ++ ++/* --------------------------------------------------------------------------- */ ++/* Basic Type Definitions */ ++/* --------------------------------------------------------------------------- */ ++ ++typedef volatile unsigned char *P_kal_uint8; ++typedef volatile unsigned short *P_kal_uint16; ++typedef volatile unsigned int *P_kal_uint32; ++ ++typedef long LONG; ++typedef unsigned char UBYTE; ++typedef short SHORT; ++ ++typedef signed char kal_int8; ++typedef signed short kal_int16; ++typedef signed int kal_int32; ++typedef long long kal_int64; ++typedef unsigned char kal_uint8; ++typedef unsigned short kal_uint16; ++typedef unsigned int kal_uint32; ++typedef unsigned long long kal_uint64; ++typedef char kal_char; ++ ++typedef unsigned int *UINT32P; ++typedef volatile unsigned short *UINT16P; ++typedef volatile unsigned char *UINT8P; ++typedef unsigned char *U8P; ++ ++typedef volatile unsigned char *P_U8; ++typedef volatile signed char *P_S8; ++typedef volatile unsigned short *P_U16; ++typedef volatile signed short *P_S16; ++typedef volatile unsigned int *P_U32; ++typedef volatile signed int *P_S32; ++typedef unsigned long long *P_U64; ++typedef signed long long *P_S64; ++ ++typedef unsigned char U8; ++typedef signed char S8; ++typedef unsigned short U16; ++typedef signed short S16; ++typedef unsigned int U32; ++typedef signed int S32; ++typedef unsigned long long U64; ++typedef signed long long S64; ++/* typedef unsigned char bool; */ ++ ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++typedef unsigned short USHORT; ++typedef signed char INT8; ++typedef signed short INT16; ++typedef signed int INT32; ++typedef unsigned int DWORD; ++typedef void VOID; ++typedef unsigned char BYTE; ++typedef float FLOAT; ++ ++typedef char *LPCSTR; ++typedef short *LPWSTR; ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Constants */ ++/* --------------------------------------------------------------------------- */ ++ ++#ifndef FALSE ++#define FALSE (0) ++#endif ++ ++#ifndef TRUE ++#define TRUE (1) ++#endif ++ ++#ifndef NULL ++#define NULL (0) ++#endif ++ ++/* enum boolean {false, true}; */ ++enum { RX, TX, NONE }; ++ ++#ifndef BOOL ++typedef unsigned char BOOL; ++#endif ++ ++#ifndef BATTERY_BOOL ++#define BATTERY_BOOL ++typedef enum { ++ KAL_FALSE = 0, ++ KAL_TRUE = 1, ++} kal_bool; ++#endif ++ ++/* --------------------------------------------------------------------------- */ ++/* Type Casting */ ++/* --------------------------------------------------------------------------- */ ++ ++#define AS_INT32(x) (*(INT32 *)((void *)x)) ++#define AS_INT16(x) (*(INT16 *)((void *)x)) ++#define AS_INT8(x) (*(INT8 *)((void *)x)) ++ ++#define AS_UINT32(x) (*(UINT32 *)((void *)x)) ++#define AS_UINT16(x) (*(UINT16 *)((void *)x)) ++#define AS_UINT8(x) (*(UINT8 *)((void *)x)) ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Register Manipulations */ ++/* --------------------------------------------------------------------------- */ ++ ++#define READ_REGISTER_UINT32(reg) \ ++ (*(volatile UINT32 * const)(reg)) ++ ++#define WRITE_REGISTER_UINT32(reg, val) \ ++ ((*(volatile UINT32 * const)(reg)) = (val)) ++ ++#define READ_REGISTER_UINT16(reg) \ ++ ((*(volatile UINT16 * const)(reg))) ++ ++#define WRITE_REGISTER_UINT16(reg, val) \ ++ ((*(volatile UINT16 * const)(reg)) = (val)) ++ ++#define READ_REGISTER_UINT8(reg) \ ++ ((*(volatile UINT8 * const)(reg))) ++ ++#define WRITE_REGISTER_UINT8(reg, val) \ ++ ((*(volatile UINT8 * const)(reg)) = (val)) ++ ++#define INREG8(x) READ_REGISTER_UINT8((UINT8 *)((void *)(x))) ++#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8 *)((void *)(x)), (UINT8)(y)) ++#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) ++#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) ++#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) ++ ++#define INREG16(x) READ_REGISTER_UINT16((UINT16 *)((void *)(x))) ++#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16 *)((void *)(x)), (UINT16)(y)) ++#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) ++#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) ++#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) ++ ++#define INREG32(x) READ_REGISTER_UINT32((UINT32 *)((void *)(x))) ++#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32 *)((void *)(x)), (UINT32)(y)) ++#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) ++#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) ++#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) ++ ++ ++#define DRV_Reg8(addr) INREG8(addr) ++#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) ++#define DRV_SetReg8(addr, data) SETREG8(addr, data) ++#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) ++ ++#define DRV_Reg16(addr) INREG16(addr) ++#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) ++#define DRV_SetReg16(addr, data) SETREG16(addr, data) ++#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) ++ ++#define DRV_Reg32(addr) INREG32(addr) ++#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) ++#define DRV_SetReg32(addr, data) SETREG32(addr, data) ++#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) ++ ++/* !!! DEPRECATED, WILL BE REMOVED LATER !!! */ ++#define DRV_Reg(addr) DRV_Reg16(addr) ++#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) ++#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) ++#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Compiler Time Deduction Macros */ ++/* --------------------------------------------------------------------------- */ ++ ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Assertions */ ++/* --------------------------------------------------------------------------- */ ++ ++/* ++*#ifndef ASSERT ++*#define ASSERT(expr) BUG_ON(!(expr)) ++*#endif ++* ++*#ifndef NOT_IMPLEMENTED ++*#define NOT_IMPLEMENTED() BUG_ON(1) ++*#endif ++*/ ++#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) ++#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) ++#define STATIC_ASSERT_XX(pred, line) \ ++extern char assertion_failed_at_##line[(pred) ? 1 : -1] ++ ++/* --------------------------------------------------------------------------- */ ++/* Resolve Compiler Warnings */ ++/* --------------------------------------------------------------------------- */ ++ ++#define NOT_REFERENCED(x) { (x) = (x); } ++ ++ ++/* --------------------------------------------------------------------------- */ ++/* Utilities */ ++/* --------------------------------------------------------------------------- */ ++ ++#define MAXIMUM(A, B) (((A) > (B))?(A):(B)) ++#define MINIMUM(A, B) (((A) < (B))?(A):(B)) ++ ++#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) ++#define DVT_DELAYMACRO(u4Num) \ ++{ \ ++ UINT32 u4Count = 0; \ ++ for (u4Count = 0; u4Count < u4Num; u4Count++) \ ++ ; \ ++} \ ++ ++#define A68351B 0 ++#define B68351B 1 ++#define B68351D 2 ++#define B68351E 3 ++#define UNKNOWN_IC_VERSION 0xFF ++ ++ ++#endif /* _TYPEDEFS_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h +new file mode 100644 +index 000000000000..0a4fda191654 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++/*! \file ++ * \brief Declaration of library functions ++ * ++ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. ++*/ ++ ++#ifndef _MTK_WCN_CMB_STUB_H_ ++#define _MTK_WCN_CMB_STUB_H_ ++ ++#include ++ ++/******************************************************************************* ++* C O M P I L E R F L A G S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* M A C R O S ++******************************************************************************** ++*/ ++/* Audio GPIO naming style for 73/75/77 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_0 1 */ ++/* Audio GPIO naming style for 89/8135 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_1 1 */ ++/* Audio GPIO naming style for 6592 */ ++/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_2 1 */ ++/* Audio GPIO naming style for 6595 */ ++#define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_3 1 ++#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 1 ++ ++/******************************************************************************* ++* E X T E R N A L R E F E R E N C E S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* C O N S T A N T S ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* D A T A T Y P E S ++******************************************************************************** ++*/ ++typedef enum { ++ CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ ++ CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ ++ CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ ++ CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ ++ CMB_STUB_AIF_4 = 4, /* 0100: BT_I2S & FM disable in special projects, e.g. protea*/ ++ CMB_STUB_AIF_MAX = 5, ++} CMB_STUB_AIF_X; ++ ++/*COMBO_CHIP_AUDIO_PIN_CTRL*/ ++typedef enum { ++ CMB_STUB_AIF_CTRL_DIS = 0, ++ CMB_STUB_AIF_CTRL_EN = 1, ++ CMB_STUB_AIF_CTRL_MAX = 2, ++} CMB_STUB_AIF_CTRL; ++ ++typedef enum { ++ COMBO_FUNC_TYPE_BT = 0, ++ COMBO_FUNC_TYPE_FM = 1, ++ COMBO_FUNC_TYPE_GPS = 2, ++ COMBO_FUNC_TYPE_WIFI = 3, ++ COMBO_FUNC_TYPE_WMT = 4, ++ COMBO_FUNC_TYPE_STP = 5, ++ COMBO_FUNC_TYPE_NUM = 6 ++} COMBO_FUNC_TYPE; ++ ++typedef enum { ++ COMBO_IF_UART = 0, ++ COMBO_IF_MSDC = 1, ++ COMBO_IF_BTIF = 2, ++ COMBO_IF_MAX, ++} COMBO_IF; ++ ++typedef void (*wmt_bgf_eirq_cb) (void); ++typedef int (*wmt_aif_ctrl_cb) (CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); ++typedef void (*wmt_func_ctrl_cb) (unsigned int, unsigned int); ++typedef signed long (*wmt_thermal_query_cb) (void); ++typedef int (*wmt_deep_idle_ctrl_cb) (unsigned int); ++typedef int (*wmt_func_do_reset) (unsigned int); ++ ++/* for DVFS driver do 1v autok */ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++typedef unsigned int (*wmt_get_drv_status)(unsigned int); ++#endif ++ ++typedef void (*msdc_sdio_irq_handler_t) (void *); /* external irq handler */ ++typedef void (*pm_callback_t) (pm_message_t state, void *data); ++ ++struct sdio_ops { ++ void (*sdio_request_eirq)(msdc_sdio_irq_handler_t irq_handler, void *data); ++ void (*sdio_enable_eirq)(void); ++ void (*sdio_disable_eirq)(void); ++ void (*sdio_register_pm)(pm_callback_t pm_cb, void *data); ++}; ++ ++typedef struct _CMB_STUB_CB_ { ++ unsigned int size; /* structure size */ ++ /*wmt_bgf_eirq_cb bgf_eirq_cb; *//* remove bgf_eirq_cb from stub. handle it in platform */ ++ wmt_aif_ctrl_cb aif_ctrl_cb; ++ wmt_func_ctrl_cb func_ctrl_cb; ++ wmt_thermal_query_cb thermal_query_cb; ++ wmt_deep_idle_ctrl_cb deep_idle_ctrl_cb; ++ wmt_func_do_reset wmt_do_reset_cb; ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++ wmt_get_drv_status get_drv_status_cb; ++#endif ++} CMB_STUB_CB, *P_CMB_STUB_CB; ++ ++/******************************************************************************* ++* P U B L I C D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* P R I V A T E D A T A ++******************************************************************************** ++*/ ++ ++/******************************************************************************* ++* F U N C T I O N D E C L A R A T I O N S ++******************************************************************************** ++*/ ++ ++extern struct sdio_ops mt_sdio_ops[4]; ++ ++extern int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb); ++extern int mtk_wcn_cmb_stub_unreg(void); ++ ++extern int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); ++ ++static inline int mtk_wcn_cmb_stub_audio_ctrl(CMB_STUB_AIF_X state) ++{ ++/* return mtk_wcn_cmb_stub_aif_ctrl(state, 1); */ ++ return 0; ++} ++ ++extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); ++extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); ++ ++/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control ++ * function on/off. ++ */ ++extern void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on); ++extern int mtk_wcn_cmb_stub_query_ctrl(void); ++extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); ++extern int mtk_wcn_sdio_irq_flag_set(int falg); ++ ++#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK ++extern int mtk_wcn_cmb_stub_1vautok_for_dvfs(void); ++#endif ++ ++extern int mtk_wcn_wmt_chipid_query(void); ++extern void mtk_wcn_wmt_set_chipid(int chipid); ++ ++/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver ++ * ++ * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" ++ * @ enable - "1", enable deep idle; "0", disable deep idle ++ * ++ * Return 0 if success, else -1 ++ */ ++extern unsigned int mtk_uart_pdn_enable(char *port, int enable); ++/******************************************************************************* ++* F U N C T I O N S ++******************************************************************************** ++*/ ++ ++#endif /* _MTK_WCN_CMB_STUB_H_ */ +diff --git a/drivers/misc/mediatek/include/mt-plat/rt-regmap.h b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h +new file mode 100644 +index 000000000000..9a45e23005ca +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h +@@ -0,0 +1,291 @@ ++/* drivers/misc/mediatek/include/mt-plat/rt-regmap.h ++ * Header of Richtek regmap with debugfs Driver ++ * ++ * Copyright (C) 2014 Richtek Technology Corp. ++ * Jeff Chang ++ * ++ * 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. ++ */ ++ ++#ifndef MISC_MEDIATEK_RT_REGMAP_H ++#define MISC_MEDIATEK_RT_REGMAP_H ++ ++#include ++#include ++ ++/* #define RT_REGMAP_VERSION "1.1.11_G" */ ++ ++enum rt_access_mode { ++ RT_1BYTE_MODE = 1, ++ RT_2BYTE_MODE = 2, ++ RT_4BYTE_MODE = 4, ++}; ++ ++/* start : the start address of group ++ * end : the end address of group ++ * mode : access mode (1,2,4 bytes) ++ */ ++struct rt_access_group { ++ u32 start; ++ u32 end; ++ enum rt_access_mode mode; ++}; ++ ++/* rt_reg_type ++ * RT_NORMAL : Write data without mask ++ * Read from cache ++ * RT_WBITS : Write data with mask ++ * Read from cache ++ * RT_VOLATILE : Write data to chip directly ++ * Read data from chip ++ * RT_RESERVE : Reserve registers (Write/Read as RT_NORMAL) ++ */ ++ ++#define RT_REG_TYPE_MASK (0x03) ++#define RT_NORMAL (0x00) ++#define RT_WBITS (0x01) ++#define RT_VOLATILE (0x02) ++#define RT_RESERVE (0x03) ++ ++/* RT_WR_ONCE : write once will check write data and cache data, ++ * if write data = cache data, data will not be writen. ++ */ ++#define RT_WR_ONCE (0x08) ++#define RT_NORMAL_WR_ONCE (RT_NORMAL|RT_WR_ONCE) ++#define RT_WBITS_WR_ONCE (RT_WBITS|RT_WR_ONCE) ++ ++enum rt_data_format { ++ RT_LITTLE_ENDIAN, ++ RT_BIG_ENDIAN, ++}; ++ ++/* rt_regmap_mode ++ * 0 0 0 0 0 0 0 0 ++ * | | | | | | ++ * | | | |__| byte_mode ++ * | |__| || ++ * | || Cache_mode ++ * | Block_mode ++ * Debug_mode ++ */ ++ ++#define RT_BYTE_MODE_MASK (0x01) ++/* 1 byte for each register*/ ++#define RT_SINGLE_BYTE (0 << 0) ++/* multi bytes for each regiseter*/ ++#define RT_MULTI_BYTE (1 << 0) ++ ++#define RT_CACHE_MODE_MASK (0x06) ++/* write to cache and chip synchronously */ ++#define RT_CACHE_WR_THROUGH (0 << 1) ++/* write to cache and chip asynchronously */ ++#define RT_CACHE_WR_BACK (1 << 1) ++/* disable cache */ ++#define RT_CACHE_DISABLE (2 << 1) ++ ++#define RT_IO_BLK_MODE_MASK (0x18) ++/* pass through all write function */ ++#define RT_IO_PASS_THROUGH (0 << 3) ++/* block all write function */ ++#define RT_IO_BLK_ALL (1 << 3) ++/* block cache write function */ ++#define RT_IO_BLK_CACHE (2 << 3) ++/* block chip write function */ ++#define RT_IO_BLK_CHIP (3 << 3) ++ ++#define DBG_MODE_MASK (0x20) ++/* create general debugfs for register map */ ++#define RT_DBG_GENERAL (0 << 5) ++/* create node for each regisetr map by register address*/ ++#define RT_DBG_SPECIAL (1 << 5) ++ ++ ++/* struct rt_register ++ * ++ * Ricktek register map structure for store mapping data ++ * @addr: register address. ++ * @name: register name. ++ * @size: register byte size. ++ * @reg_type: register R/W type ( RT_NORMAL, RT_WBITS, RT_VOLATILE, RT_RESERVE) ++ * @wbit_mask: register writeable bits mask; ++ * @cache_data: cache data for store cache value. ++ */ ++struct rt_register { ++ u32 addr; ++ const char *name; ++ unsigned int size; ++ unsigned char reg_type; ++ unsigned char *wbit_mask; ++ unsigned char *cache_data; ++}; ++ ++/* Declare a rt_register by RT_REG_DECL ++ * @_addr: regisetr address. ++ * @_reg_length: register data length. ++ * @_reg_type: register type (rt_reg_type). ++ * @_mask: register writealbe mask. ++ */ ++#define RT_REG_DECL(_addr, _reg_length, _reg_type, _mask_...) \ ++ static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ ++ static struct rt_register rt_register_##_addr = { \ ++ .addr = _addr, \ ++ .size = _reg_length,\ ++ .reg_type = _reg_type,\ ++ .wbit_mask = rt_writable_mask_##_addr,\ ++ } ++ ++/* Declare a rt_register by RT_NAMED_REG_DECL ++ * @_name: a name for a rt_register. ++ */ ++#define RT_NAMED_REG_DECL(_addr, _name, _reg_length, _reg_type, _mask_...) \ ++ static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ ++ static struct rt_register rt_register_##_addr = { \ ++ .addr = _addr, \ ++ .name = _name, \ ++ .size = _reg_length,\ ++ .reg_type = _reg_type,\ ++ .wbit_mask = rt_writable_mask_##_addr,\ ++ } ++ ++#define RT_REG(_addr) (&rt_register_##_addr) ++ ++/* rt_regmap_properties ++ * @name: the name of debug node. ++ * @aliases: alisis name of rt_regmap_device. ++ * @register_num: the number of rt_register_map registers. ++ * @rm: rt_regiseter_map pointer array. ++ * @group: register map access group. ++ * @rt_format: default is little endian. ++ * @rt_regmap_mode: rt_regmap_device mode. ++ * @io_log_en: enable/disable io log ++ */ ++struct rt_regmap_properties { ++ const char *name; ++ const char *aliases; ++ int register_num; ++ struct rt_register **rm; ++ struct rt_access_group *group; ++ enum rt_data_format rt_format; ++ unsigned char rt_regmap_mode; ++ unsigned char io_log_en:1; ++}; ++ ++/* A passing struct for rt_regmap_reg_read and rt_regmap_reg_write function ++ * reg: regmap addr. ++ * mask: mask for update bits. ++ * rt_data: register value. ++ */ ++struct rt_reg_data { ++ u32 reg; ++ u32 mask; ++ union { ++ u32 data_u32; ++ u16 data_u16; ++ u8 data_u8; ++ u8 data[4]; ++ } rt_data; ++}; ++ ++struct rt_regmap_device; ++ ++struct rt_debug_st { ++ void *info; ++ int id; ++}; ++ ++/* basic chip read/write function */ ++struct rt_regmap_fops { ++ int (*read_device)(void *client, u32 addr, int leng, void *dst); ++ int (*write_device)(void *client, u32 addr, int leng, const void *src); ++}; ++ ++/* with slave address */ ++extern struct rt_regmap_device* ++ rt_regmap_device_register_ex(struct rt_regmap_properties *props, ++ struct rt_regmap_fops *rops, ++ struct device *parent, ++ void *client, int slv_addr, void *drvdata); ++ ++static inline struct rt_regmap_device* ++ rt_regmap_device_register(struct rt_regmap_properties *props, ++ struct rt_regmap_fops *rops, ++ struct device *parent, ++ struct i2c_client *client, void *drvdata) ++{ ++ return rt_regmap_device_register_ex(props, rops, parent, ++ client, client->addr, drvdata); ++} ++ ++extern void rt_regmap_device_unregister(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_cache_init(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_cache_reload(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg, ++ int bytes, const void *rc); ++extern int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg, ++ int bytes, const void *rc); ++extern int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg, ++ int bytes, void *dst); ++ ++extern int _rt_regmap_reg_read(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++extern int _rt_regmap_update_bits(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd); ++ ++static inline int rt_regmap_reg_read(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg) ++{ ++ rrd->reg = reg; ++ return _rt_regmap_reg_read(rd, rrd); ++}; ++ ++static inline int rt_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, const u32 data) ++{ ++ rrd->reg = reg; ++ rrd->rt_data.data_u32 = data; ++ return _rt_regmap_reg_write(rd, rrd); ++}; ++ ++static inline int rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, const u32 data) ++{ ++ rrd->reg = reg; ++ rrd->rt_data.data_u32 = data; ++ return _rt_asyn_regmap_reg_write(rd, rrd); ++}; ++ ++static inline int rt_regmap_update_bits(struct rt_regmap_device *rd, ++ struct rt_reg_data *rrd, u32 reg, u32 mask, u32 data) ++{ ++ rrd->reg = reg; ++ rrd->mask = mask; ++ rrd->rt_data.data_u32 = data; ++ return _rt_regmap_update_bits(rd, rrd); ++} ++ ++extern void rt_regmap_cache_backup(struct rt_regmap_device *rd); ++ ++extern void rt_regmap_cache_sync(struct rt_regmap_device *rd); ++extern void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg); ++ ++extern int rt_is_reg_readable(struct rt_regmap_device *rd, u32 reg); ++extern int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg); ++extern int rt_get_regsize(struct rt_regmap_device *rd, u32 reg); ++extern void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf); ++extern void rt_cache_clrlasterror(struct rt_regmap_device *rd); ++ ++extern int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name, ++ umode_t mode, void *data, const struct file_operations *fops); ++ ++#define to_rt_regmap_device(obj) container_of(obj, struct rt_regmap_device, dev) ++ ++#endif /*MISC_MEDIATEK_RT_REGMAP_H*/ +diff --git a/drivers/misc/mediatek/include/mt-plat/sync_write.h b/drivers/misc/mediatek/include/mt-plat/sync_write.h +new file mode 100644 +index 000000000000..f9e5fe4c23e1 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/sync_write.h +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _MT_SYNC_WRITE_H ++#define _MT_SYNC_WRITE_H ++ ++#if defined(__KERNEL__) ++ ++#include ++#include ++ ++/* ++ * Define macros. ++ */ ++#define mt_reg_sync_writel(v, a) \ ++ do { \ ++ __raw_writel((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#define mt_reg_sync_writew(v, a) \ ++ do { \ ++ __raw_writew((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#define mt_reg_sync_writeb(v, a) \ ++ do { \ ++ __raw_writeb((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++ ++#ifdef CONFIG_64BIT ++#define mt_reg_sync_writeq(v, a) \ ++ do { \ ++ __raw_writeq((v), (void __force __iomem *)((a))); \ ++ mb(); \ ++ } while (0) ++#endif ++ ++#else /* __KERNEL__ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define mt_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) ++#define mt_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) ++#define mt_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) ++ ++#define mb() \ ++ { \ ++ __asm__ __volatile__ ("dsb" : : : "memory"); \ ++ } ++ ++#define mt65xx_reg_sync_writel(v, a) \ ++ do { \ ++ *(volatile unsigned int *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#define mt65xx_reg_sync_writew(v, a) \ ++ do { \ ++ *(volatile unsigned short *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#define mt65xx_reg_sync_writeb(v, a) \ ++ do { \ ++ *(volatile unsigned char *)(a) = (v); \ ++ mb(); \ ++ } while (0) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* !_MT_SYNC_WRITE_H */ +diff --git a/drivers/misc/mediatek/include/mt-plat/wakelock.h b/drivers/misc/mediatek/include/mt-plat/wakelock.h +new file mode 100644 +index 000000000000..f4a698a22880 +--- /dev/null ++++ b/drivers/misc/mediatek/include/mt-plat/wakelock.h +@@ -0,0 +1,67 @@ ++/* include/linux/wakelock.h ++ * ++ * Copyright (C) 2007-2012 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LINUX_WAKELOCK_H ++#define _LINUX_WAKELOCK_H ++ ++#include ++#include ++ ++/* A wake_lock prevents the system from entering suspend or other low power ++ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock ++ * prevents a full system suspend. ++ */ ++ ++enum { ++ WAKE_LOCK_SUSPEND, /* Prevent suspend */ ++ WAKE_LOCK_TYPE_COUNT ++}; ++ ++struct wake_lock { ++ struct wakeup_source ws; ++}; ++ ++static inline void wake_lock_init(struct wake_lock *lock, int type, ++ const char *name) ++{ ++ wakeup_source_init(&lock->ws, name); ++} ++ ++static inline void wake_lock_destroy(struct wake_lock *lock) ++{ ++ wakeup_source_trash(&lock->ws); ++} ++ ++static inline void wake_lock(struct wake_lock *lock) ++{ ++ __pm_stay_awake(&lock->ws); ++} ++ ++static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) ++{ ++ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); ++} ++ ++static inline void wake_unlock(struct wake_lock *lock) ++{ ++ __pm_relax(&lock->ws); ++} ++ ++static inline int wake_lock_active(struct wake_lock *lock) ++{ ++ return lock->ws.active; ++} ++ ++#endif +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0007-wifi-adding-wifi-related-changes-outside-driver-dire.patch b/root/target/linux/mediatek/patches-4.19/0007-wifi-adding-wifi-related-changes-outside-driver-dire.patch new file mode 100644 index 00000000..c4e0a903 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0007-wifi-adding-wifi-related-changes-outside-driver-dire.patch @@ -0,0 +1,846 @@ +From 83ffbaceffed1cd47a6f67fb20e39737dfb2d01a Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 28 Aug 2018 18:14:56 +0200 +Subject: [PATCH 07/77] [wifi] adding wifi-related changes outside + driver-directory + +--- + arch/arm/boot/dts/mt7623.dtsi | 41 +- + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 42 ++ + drivers/soc/mediatek/mtk-pmic-wrap.c | 12 + + drivers/watchdog/mtk_wdt.c | 377 +++++++++++++++++- + include/linux/wakelock.h | 67 ++++ + include/net/genetlink.h | 44 ++ + include/soc/mediatek/pmic_wrap.h | 19 + + include/uapi/linux/genetlink.h | 1 + + 8 files changed, 588 insertions(+), 15 deletions(-) + create mode 100644 include/linux/wakelock.h + create mode 100644 include/soc/mediatek/pmic_wrap.h + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 04228cf9ddbb..af6b6228f8a8 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -266,6 +266,8 @@ + compatible = "mediatek,mt7623-wdt", + "mediatek,mt6589-wdt"; + reg = <0 0x10007000 0 0x100>; ++ interrupts = ; ++ #reset-cells = <1>; + }; + + timer: timer@10008000 { +@@ -494,13 +496,26 @@ + "mediatek,mtk-btif"; + reg = <0 0x1100c000 0 0x1000>; + interrupts = ; +- clocks = <&pericfg CLK_PERI_BTIF>; +- clock-names = "main"; ++ clocks = <&pericfg CLK_PERI_BTIF>, <&pericfg CLK_PERI_AP_DMA>; ++ clock-names = "main", "apdmac"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + ++ btif_tx: btif_tx@11000780 { ++ compatible = "mediatek,btif_tx"; ++ reg = <0 0x11000780 0 0x80>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ btif_rx: btif_rx@11000800 { ++ compatible = "mediatek,btif_rx"; ++ reg = <0 0x11000800 0 0x80>; ++ interrupts = ; ++ status = "okay"; ++ }; ++ + nandc: nfi@1100d000 { + compatible = "mediatek,mt7623-nfc", + "mediatek,mt2701-nfc"; +@@ -683,6 +698,28 @@ + status = "disabled"; + }; + ++ consys: consys@18070000 { ++ compatible = "mediatek,mt7623-consys"; ++ reg = <0 0x18070000 0 0x0200>, /*CONN_MCU_CONFIG_BASE */ ++ <0 0x10001000 0 0x1600>; /*TOPCKGEN_BASE */ ++ clocks = <&infracfg CLK_INFRA_CONNMCU>; ++ clock-names = "consysbus"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_CONN>; ++ interrupts = , /* BGF_EINT */ ++ ; /* WDT_EINT */ ++ resets = <&watchdog MT2701_TOPRGU_CONN_MCU_RST>; ++ reset-names = "connsys"; ++ status="disabled"; ++ }; ++ wifi:wifi@180f0000 { ++ compatible = "mediatek,mt7623-wifi", ++ "mediatek,wifi"; ++ reg = <0 0x180f0000 0 0x005c>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_AP_DMA>; ++ clock-names = "wifi-dma"; ++ }; ++ + hifsys: syscon@1a000000 { + compatible = "mediatek,mt7623-hifsys", + "mediatek,mt2701-hifsys", +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 2b760f90f38c..465fb887b2ca 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -84,6 +84,18 @@ + }; + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ consys-reserve-memory { ++ compatible = "mediatek,consys-reserve-memory"; ++ no-map; ++ size = <0 0x100000>; ++ alignment = <0 0x100000>; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +@@ -259,6 +271,36 @@ + }; + }; + ++&pio { ++ consys_pins_default: consys_pins_default { ++ adie { ++ pinmux = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ bias-disable; ++ }; ++ }; ++}; ++&consys { ++ mediatek,pwrap-regmap = <&pwrap>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&consys_pins_default>; ++ vcn18-supply = <&mt6323_vcn18_reg>; ++ vcn28-supply = <&mt6323_vcn28_reg>; ++ vcn33_bt-supply = <&mt6323_vcn33_bt_reg>; ++ vcn33_wifi-supply = <&mt6323_vcn33_wifi_reg>; ++ status = "okay"; ++}; ++ + &pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_default>; +diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c +index 4e931fdf4d09..6600396ee299 100644 +--- a/drivers/soc/mediatek/mtk-pmic-wrap.c ++++ b/drivers/soc/mediatek/mtk-pmic-wrap.c +@@ -1530,6 +1530,18 @@ static const struct of_device_id of_pwrap_match_tbl[] = { + }; + MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); + ++struct regmap *pwrap_node_to_regmap(struct device_node *np) ++{ ++ struct platform_device *pdev; ++ struct pmic_wrapper *wrp; ++ pdev = of_find_device_by_node(np); ++ if (!pdev) ++ return ERR_PTR(-ENODEV); ++ wrp = platform_get_drvdata(pdev); ++ return wrp->regmap; ++} ++EXPORT_SYMBOL_GPL(pwrap_node_to_regmap); ++ + static int pwrap_probe(struct platform_device *pdev) + { + int ret, irq; +diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c +index 4baf64f21aa1..6a361f808aed 100644 +--- a/drivers/watchdog/mtk_wdt.c ++++ b/drivers/watchdog/mtk_wdt.c +@@ -1,4 +1,3 @@ +-// SPDX-License-Identifier: GPL-2.0+ + /* + * Mediatek Watchdog Driver + * +@@ -6,20 +5,51 @@ + * + * Matthias Brugger + * ++ * 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. ++ * + * Based on sunxi_wdt.c + */ + + #include + #include + #include ++#include + #include + #include + #include ++#include ++#include ++#include + #include ++#include + #include ++#ifdef CONFIG_FIQ_GLUE ++#include ++#include ++#endif + #include + #include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_MT6397_MISC ++#include ++#endif + + #define WDT_MAX_TIMEOUT 31 + #define WDT_MIN_TIMEOUT 1 +@@ -38,37 +68,167 @@ + #define WDT_MODE_EXRST_EN (1 << 2) + #define WDT_MODE_IRQ_EN (1 << 3) + #define WDT_MODE_AUTO_START (1 << 4) ++#define WDT_MODE_IRQ_LVL (1 << 5) + #define WDT_MODE_DUAL_EN (1 << 6) + #define WDT_MODE_KEY 0x22000000 + ++#define WDT_STATUS 0x0c ++#define WDT_NONRST_REG 0x20 ++#define WDT_NONRST_REG2 0x24 ++ + #define WDT_SWRST 0x14 + #define WDT_SWRST_KEY 0x1209 + ++#define WDT_SWSYSRST 0x18 ++#define WDT_SWSYSRST_KEY 0x88000000 ++ ++#define WDT_REQ_MODE 0x30 ++#define WDT_REQ_MODE_KEY 0x33000000 ++#define WDT_REQ_IRQ_EN 0x34 ++#define WDT_REQ_IRQ_KEY 0x44000000 ++#define WDT_REQ_MODE_DEBUG_EN 0x80000 ++ ++ + #define DRV_NAME "mtk-wdt" +-#define DRV_VERSION "1.0" ++#define DRV_VERSION "2.0" + + static bool nowayout = WATCHDOG_NOWAYOUT; +-static unsigned int timeout; ++static unsigned int timeout = WDT_MAX_TIMEOUT; ++ ++struct toprgu_reset { ++ spinlock_t lock; ++ void __iomem *toprgu_swrst_base; ++ int regofs; ++ struct reset_controller_dev rcdev; ++}; + + struct mtk_wdt_dev { + struct watchdog_device wdt_dev; + void __iomem *wdt_base; ++ int wdt_irq_id; ++ struct notifier_block restart_handler; ++ struct toprgu_reset reset_controller; + }; + +-static int mtk_wdt_restart(struct watchdog_device *wdt_dev, +- unsigned long action, void *data) ++static void __iomem *toprgu_base; ++static struct watchdog_device *wdt_dev; ++ ++static int toprgu_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) + { +- struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); ++ unsigned int tmp; ++ unsigned long flags; ++ struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); ++ tmp |= BIT(id); ++ tmp |= WDT_SWSYSRST_KEY; ++ writel(tmp, data->toprgu_swrst_base + data->regofs); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int toprgu_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ unsigned int tmp; ++ unsigned long flags; ++ struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); ++ tmp &= ~BIT(id); ++ tmp |= WDT_SWSYSRST_KEY; ++ writel(tmp, data->toprgu_swrst_base + data->regofs); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int toprgu_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = toprgu_reset_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return toprgu_reset_deassert(rcdev, id); ++} ++ ++static struct reset_control_ops toprgu_reset_ops = { ++ .assert = toprgu_reset_assert, ++ .deassert = toprgu_reset_deassert, ++ .reset = toprgu_reset, ++}; ++ ++static void toprgu_register_reset_controller(struct platform_device *pdev, int regofs) ++{ ++ int ret; ++ struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); ++ ++ spin_lock_init(&mtk_wdt->reset_controller.lock); ++ ++ mtk_wdt->reset_controller.toprgu_swrst_base = mtk_wdt->wdt_base; ++ mtk_wdt->reset_controller.regofs = regofs; ++ mtk_wdt->reset_controller.rcdev.owner = THIS_MODULE; ++ mtk_wdt->reset_controller.rcdev.nr_resets = 15; ++ mtk_wdt->reset_controller.rcdev.ops = &toprgu_reset_ops; ++ mtk_wdt->reset_controller.rcdev.of_node = pdev->dev.of_node; ++ ++ ret = reset_controller_register(&mtk_wdt->reset_controller.rcdev); ++ if (ret) ++ pr_err("could not register toprgu reset controller: %d\n", ret); ++} ++ ++static int mtk_reset_handler(struct notifier_block *this, unsigned long mode, ++ void *cmd) ++{ ++ struct mtk_wdt_dev *mtk_wdt; + void __iomem *wdt_base; ++ u32 reg; + ++ mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler); + wdt_base = mtk_wdt->wdt_base; + +- while (1) { +- writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); +- mdelay(5); ++ /* WDT_STATUS will be cleared to zero after writing to WDT_MODE, so we backup it in WDT_NONRST_REG, ++ * and then print it out in mtk_wdt_probe() after reset ++ */ ++ writel(__raw_readl(wdt_base + WDT_STATUS), wdt_base + WDT_NONRST_REG); ++ ++ reg = ioread32(wdt_base + WDT_MODE); ++ reg &= ~(WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EN); ++ reg |= WDT_MODE_KEY; ++ iowrite32(reg, wdt_base + WDT_MODE); ++ ++ if (cmd && !strcmp(cmd, "rpmbpk")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 0), wdt_base + WDT_NONRST_REG2); ++ } else if (cmd && !strcmp(cmd, "recovery")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 1), wdt_base + WDT_NONRST_REG2); ++ #ifdef CONFIG_MT6397_MISC ++ mtk_misc_mark_recovery(); ++ #endif ++ } else if (cmd && !strcmp(cmd, "bootloader")) { ++ iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 2), wdt_base + WDT_NONRST_REG2); ++ #ifdef CONFIG_MT6397_MISC ++ mtk_misc_mark_fast(); ++ #endif + } + +- return 0; ++ if (!arm_pm_restart) { ++ while (1) { ++ writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); ++ mdelay(5); ++ } ++ } ++ return NOTIFY_DONE; + } + + static int mtk_wdt_ping(struct watchdog_device *wdt_dev) +@@ -77,6 +237,7 @@ static int mtk_wdt_ping(struct watchdog_device *wdt_dev) + void __iomem *wdt_base = mtk_wdt->wdt_base; + + iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); ++ printk_deferred("[WDK]: kick Ex WDT\n"); + + return 0; + } +@@ -128,7 +289,8 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev) + return ret; + + reg = ioread32(wdt_base + WDT_MODE); +- reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); ++ reg |= (WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EXRST_EN); ++ reg &= ~(WDT_MODE_IRQ_LVL | WDT_MODE_EXT_POL_HIGH); + reg |= (WDT_MODE_EN | WDT_MODE_KEY); + iowrite32(reg, wdt_base + WDT_MODE); + +@@ -148,13 +310,56 @@ static const struct watchdog_ops mtk_wdt_ops = { + .stop = mtk_wdt_stop, + .ping = mtk_wdt_ping, + .set_timeout = mtk_wdt_set_timeout, +- .restart = mtk_wdt_restart, + }; + ++#ifdef CONFIG_FIQ_GLUE ++static void wdt_fiq(void *arg, void *regs, void *svc_sp) ++{ ++ unsigned int wdt_mode_val; ++ void __iomem *wdt_base = ((struct mtk_wdt_dev *)arg)->wdt_base; ++ ++ wdt_mode_val = __raw_readl(wdt_base + WDT_STATUS); ++ writel(wdt_mode_val, wdt_base + WDT_NONRST_REG); ++ ++ aee_wdt_fiq_info(arg, regs, svc_sp); ++} ++#else ++static void wdt_report_info(void) ++{ ++ struct task_struct *task; ++ ++ task = &init_task; ++ pr_debug("Qwdt: -- watchdog time out\n"); ++ ++ for_each_process(task) { ++ if (task->state == 0) { ++ pr_debug("PID: %d, name: %s\n backtrace:\n", task->pid, task->comm); ++ show_stack(task, NULL); ++ pr_debug("\n"); ++ } ++ } ++ ++ pr_debug("backtrace of current task:\n"); ++ show_stack(NULL, NULL); ++ pr_debug("Qwdt: -- watchdog time out\n"); ++} ++ ++static irqreturn_t mtk_wdt_isr(int irq, void *dev_id) ++{ ++ pr_err("fwq mtk_wdt_isr\n"); ++ ++ wdt_report_info(); ++ BUG(); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ + static int mtk_wdt_probe(struct platform_device *pdev) + { + struct mtk_wdt_dev *mtk_wdt; + struct resource *res; ++ unsigned int tmp; + int err; + + mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL); +@@ -165,9 +370,32 @@ static int mtk_wdt_probe(struct platform_device *pdev) + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); ++ + if (IS_ERR(mtk_wdt->wdt_base)) + return PTR_ERR(mtk_wdt->wdt_base); + ++ pr_err("MTK_WDT_NONRST_REG(%x)\n", __raw_readl(mtk_wdt->wdt_base + WDT_NONRST_REG)); ++ ++ mtk_wdt->wdt_irq_id = irq_of_parse_and_map(pdev->dev.of_node, 0); ++ if (!mtk_wdt->wdt_irq_id) { ++ pr_err("RGU get IRQ ID failed\n"); ++ return -ENODEV; ++ } ++ ++#ifndef CONFIG_FIQ_GLUE ++ err = request_irq(mtk_wdt->wdt_irq_id, (irq_handler_t)mtk_wdt_isr, IRQF_TRIGGER_NONE, DRV_NAME, mtk_wdt); ++#else ++ mtk_wdt->wdt_irq_id = get_hardware_irq(mtk_wdt->wdt_irq_id); ++ err = request_fiq(mtk_wdt->wdt_irq_id, wdt_fiq, IRQF_TRIGGER_FALLING, mtk_wdt); ++#endif ++ if (err != 0) { ++ pr_err("mtk_wdt_probe : failed to request irq (%d)\n", err); ++ return err; ++ } ++ ++ toprgu_base = mtk_wdt->wdt_base; ++ wdt_dev = &mtk_wdt->wdt_dev; ++ + mtk_wdt->wdt_dev.info = &mtk_wdt_info; + mtk_wdt->wdt_dev.ops = &mtk_wdt_ops; + mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT; +@@ -177,7 +405,6 @@ static int mtk_wdt_probe(struct platform_device *pdev) + + watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev); + watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout); +- watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128); + + watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt); + +@@ -187,9 +414,40 @@ static int mtk_wdt_probe(struct platform_device *pdev) + if (unlikely(err)) + return err; + ++ mtk_wdt->restart_handler.notifier_call = mtk_reset_handler; ++ mtk_wdt->restart_handler.priority = 128; ++ ++ if (arm_pm_restart) { ++ dev_info(&pdev->dev, "register restart_handler on reboot_notifier_list for psci reset\n"); ++ err = register_reboot_notifier(&mtk_wdt->restart_handler); ++ if (err != 0) ++ dev_warn(&pdev->dev, ++ "cannot register reboot notifier (err=%d)\n", err); ++ } else { ++ err = register_restart_handler(&mtk_wdt->restart_handler); ++ if (err) ++ dev_warn(&pdev->dev, ++ "cannot register restart handler (err=%d)\n", err); ++ } ++ + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n", + mtk_wdt->wdt_dev.timeout, nowayout); + ++ writel(WDT_REQ_MODE_KEY | (__raw_readl(mtk_wdt->wdt_base + WDT_REQ_MODE) & ++ (~WDT_REQ_MODE_DEBUG_EN)), mtk_wdt->wdt_base + WDT_REQ_MODE); ++ ++ toprgu_register_reset_controller(pdev, WDT_SWSYSRST); ++ ++ /* enable scpsys thermal and thermal_controller request, and set to reset directly mode */ ++ tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_MODE) | (1 << 18) | (1 << 0); ++ tmp |= WDT_REQ_MODE_KEY; ++ iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_MODE); ++ ++ tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); ++ tmp &= ~((1 << 18) | (1 << 0)); ++ tmp |= WDT_REQ_IRQ_KEY; ++ iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); ++ + return 0; + } + +@@ -205,8 +463,12 @@ static int mtk_wdt_remove(struct platform_device *pdev) + { + struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); + ++ unregister_restart_handler(&mtk_wdt->restart_handler); ++ + watchdog_unregister_device(&mtk_wdt->wdt_dev); + ++ reset_controller_unregister(&mtk_wdt->reset_controller.rcdev); ++ + return 0; + } + +@@ -258,6 +520,95 @@ static struct platform_driver mtk_wdt_driver = { + + module_platform_driver(mtk_wdt_driver); + ++static int wk_proc_cmd_read(struct seq_file *s, void *v) ++{ ++ unsigned int enabled = 1; ++ ++ if (!(ioread32(toprgu_base + WDT_MODE) & WDT_MODE_EN)) ++ enabled = 0; ++ ++ seq_printf(s, "enabled timeout\n%-4d %-8d\n", enabled, wdt_dev->timeout); ++ ++ return 0; ++} ++ ++static int wk_proc_cmd_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, wk_proc_cmd_read, NULL); ++} ++ ++static ssize_t wk_proc_cmd_write(struct file *file, const char *buf, size_t count, loff_t *data) ++{ ++ int ret; ++ int enable; ++ int timeout; ++ char wk_cmd_buf[256]; ++ ++ if (count == 0) ++ return -1; ++ ++ if (count > 255) ++ count = 255; ++ ++ ret = copy_from_user(wk_cmd_buf, buf, count); ++ if (ret < 0) ++ return -1; ++ ++ wk_cmd_buf[count] = '\0'; ++ ++ pr_debug("Write %s\n", wk_cmd_buf); ++ ++ ret = sscanf(wk_cmd_buf, "%d %d", &enable, &timeout); ++ if (ret != 2) ++ pr_debug("%s: expect 2 numbers\n", __func__); ++ ++ pr_debug("[WDK] enable=%d timeout=%d\n", enable, timeout); ++ ++ if (timeout > 20 && timeout <= WDT_MAX_TIMEOUT) { ++ wdt_dev->timeout = timeout; ++ mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout); ++ } else { ++ pr_err("[WDK] The timeout(%d) should bigger than 20 and not bigger than %d\n", ++ timeout, WDT_MAX_TIMEOUT); ++ ++ } ++ ++ if (enable == 1) { ++ mtk_wdt_start(wdt_dev); ++ set_bit(WDOG_ACTIVE, &wdt_dev->status); ++ pr_err("[WDK] enable wdt\n"); ++ } else if (enable == 0) { ++ mtk_wdt_stop(wdt_dev); ++ clear_bit(WDOG_ACTIVE, &wdt_dev->status); ++ pr_err("[WDK] disable wdt\n"); ++ } ++ ++ return count; ++} ++ ++static const struct file_operations wk_proc_cmd_fops = { ++ .owner = THIS_MODULE, ++ .open = wk_proc_cmd_open, ++ .read = seq_read, ++ .write = wk_proc_cmd_write, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init wk_proc_init(void) ++{ ++ struct proc_dir_entry *de = proc_create("wdk", 0660, NULL, &wk_proc_cmd_fops); ++ ++ if (!de) ++ pr_err("[wk_proc_init]: create /proc/wdk failed\n"); ++ ++ pr_debug("[WDK] Initialize proc\n"); ++ ++ return 0; ++} ++ ++late_initcall(wk_proc_init); ++ + module_param(timeout, uint, 0); + MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); + +diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h +new file mode 100644 +index 000000000000..f4a698a22880 +--- /dev/null ++++ b/include/linux/wakelock.h +@@ -0,0 +1,67 @@ ++/* include/linux/wakelock.h ++ * ++ * Copyright (C) 2007-2012 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LINUX_WAKELOCK_H ++#define _LINUX_WAKELOCK_H ++ ++#include ++#include ++ ++/* A wake_lock prevents the system from entering suspend or other low power ++ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock ++ * prevents a full system suspend. ++ */ ++ ++enum { ++ WAKE_LOCK_SUSPEND, /* Prevent suspend */ ++ WAKE_LOCK_TYPE_COUNT ++}; ++ ++struct wake_lock { ++ struct wakeup_source ws; ++}; ++ ++static inline void wake_lock_init(struct wake_lock *lock, int type, ++ const char *name) ++{ ++ wakeup_source_init(&lock->ws, name); ++} ++ ++static inline void wake_lock_destroy(struct wake_lock *lock) ++{ ++ wakeup_source_trash(&lock->ws); ++} ++ ++static inline void wake_lock(struct wake_lock *lock) ++{ ++ __pm_stay_awake(&lock->ws); ++} ++ ++static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) ++{ ++ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); ++} ++ ++static inline void wake_unlock(struct wake_lock *lock) ++{ ++ __pm_relax(&lock->ws); ++} ++ ++static inline int wake_lock_active(struct wake_lock *lock) ++{ ++ return lock->ws.active; ++} ++ ++#endif +diff --git a/include/net/genetlink.h b/include/net/genetlink.h +index decf6012a401..6471da92334a 100644 +--- a/include/net/genetlink.h ++++ b/include/net/genetlink.h +@@ -144,6 +144,50 @@ struct genl_ops { + }; + + int genl_register_family(struct genl_family *family); ++ ++/** ++ * genl_register_family_with_ops - register a generic netlink family with ops ++ * @family: generic netlink family ++ * @ops: operations to be registered ++ * @n_ops: number of elements to register ++ * ++ * Registers the specified family and operations from the specified table. ++ * Only one family may be registered with the same family name or identifier. ++ * ++ * The family id may equal GENL_ID_GENERATE causing an unique id to ++ * be automatically generated and assigned. ++ * ++ * Either a doit or dumpit callback must be specified for every registered ++ * operation or the function will fail. Only one operation structure per ++ * command identifier may be registered. ++ * ++ * See include/net/genetlink.h for more documenation on the operations ++ * structure. ++ * ++ * Return 0 on success or a negative error code. ++ */ ++static inline int ++_genl_register_family_with_ops_grps(struct genl_family *family, ++ const struct genl_ops *ops, size_t n_ops, ++ const struct genl_multicast_group *mcgrps, ++ size_t n_mcgrps) ++{ ++ family->module = THIS_MODULE; ++ family->ops = ops; ++ family->n_ops = n_ops; ++ family->mcgrps = mcgrps; ++ family->n_mcgrps = n_mcgrps; ++ return genl_register_family(family); ++} ++#define genl_register_family_with_ops(family, ops) \ ++ _genl_register_family_with_ops_grps((family), \ ++ (ops), ARRAY_SIZE(ops), \ ++ NULL, 0) ++#define genl_register_family_with_ops_groups(family, ops, grps) \ ++ _genl_register_family_with_ops_grps((family), \ ++ (ops), ARRAY_SIZE(ops), \ ++ (grps), ARRAY_SIZE(grps)) ++ + int genl_unregister_family(const struct genl_family *family); + void genl_notify(const struct genl_family *family, struct sk_buff *skb, + struct genl_info *info, u32 group, gfp_t flags); +diff --git a/include/soc/mediatek/pmic_wrap.h b/include/soc/mediatek/pmic_wrap.h +new file mode 100644 +index 000000000000..5b5c85272c58 +--- /dev/null ++++ b/include/soc/mediatek/pmic_wrap.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef __SOC_MEDIATEK_PMIC_WRAP_H ++#define __SOC_MEDIATEK_PMIC_WRAP_H ++ ++extern struct regmap *pwrap_node_to_regmap(struct device_node *np); ++ ++#endif /* __SOC_MEDIATEK_PMIC_WRAP_H */ +diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h +index 877f7fa95466..6a176b3d43f9 100644 +--- a/include/uapi/linux/genetlink.h ++++ b/include/uapi/linux/genetlink.h +@@ -27,6 +27,7 @@ struct genlmsghdr { + /* + * List of reserved static generic netlink identifiers: + */ ++#define GENL_ID_GENERATE 0 + #define GENL_ID_CTRL NLMSG_MIN_TYPE + #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) + #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0008-gcc-gcc8-fixes-by-Dominik-Koch-nic_rx-patch-from-htt.patch b/root/target/linux/mediatek/patches-4.19/0008-gcc-gcc8-fixes-by-Dominik-Koch-nic_rx-patch-from-htt.patch new file mode 100644 index 00000000..ed80e2bb --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0008-gcc-gcc8-fixes-by-Dominik-Koch-nic_rx-patch-from-htt.patch @@ -0,0 +1,78 @@ +From 203a5a7727a80ab519ea00181a909e415c5567ab Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Wed, 29 Aug 2018 19:17:00 +0200 +Subject: [PATCH 08/77] [gcc] gcc8-fixes by Dominik Koch + nic_rx-patch from + https://bugs.linaro.org/show_bug.cgi?id=3823 + +--- + .../misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c | 10 ++++++---- + .../misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c | 2 +- + .../connectivity/wlan/gen2/os/linux/include/gl_kal.h | 2 +- + 3 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +index ba4840414da8..65823023cec0 100644 +--- a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c +@@ -2061,7 +2061,6 @@ VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb + case EVENT_ID_BT_OVER_WIFI: + #if CFG_ENABLE_BT_OVER_WIFI + { +- UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; + P_EVENT_BT_OVER_WIFI prEventBtOverWifi; + P_AMPC_EVENT prBowEvent; + P_BOW_LINK_CONNECTED prBowLinkConnected; +@@ -2069,11 +2068,11 @@ VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb + + prEventBtOverWifi = (P_EVENT_BT_OVER_WIFI) (prEvent->aucBuffer); + +- /* construct event header */ +- prBowEvent = (P_AMPC_EVENT) aucTmp; +- + if (prEventBtOverWifi->ucLinkStatus == 0) { + /* Connection */ ++ UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED)]; ++ /* construct event header */ ++ prBowEvent = (P_AMPC_EVENT) aucTmp; + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); +@@ -2086,6 +2085,9 @@ VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb + kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); + } else { + /* Disconnection */ ++ UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; ++ /* construct event header */ ++ prBowEvent = (P_AMPC_EVENT) aucTmp; + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +index dd00859d4608..ad7107b1d9a4 100644 +--- a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c +@@ -5021,7 +5021,7 @@ VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) + if (prBssInfo && prBssInfo->prStaRecOfAP && prBssInfo->prStaRecOfAP->aucMacAddr) { + if (EQUAL_MAC_ADDR(&(pucData[ETH_TYPE_LEN_OFFSET + 10]), /* source hardware address */ + prBssInfo->prStaRecOfAP->aucMacAddr)) { +- strncpy(apIp, &(pucData[ETH_TYPE_LEN_OFFSET + 16]), sizeof(apIp)); /* src ip address */ ++ memcpy(apIp, &(pucData[ETH_TYPE_LEN_OFFSET + 16]), sizeof(apIp)); /* src ip address */ + DBGLOG(INIT, TRACE, "get arp response from AP %d.%d.%d.%d\n", + apIp[0], apIp[1], apIp[2], apIp[3]); + } +diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +index 1406905095e6..b1386918c08d 100644 +--- a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h +@@ -852,7 +852,7 @@ struct KAL_HALT_CTRL_T { + + /* string operation */ + #define kalStrCpy(dest, src) strcpy(dest, src) +-#define kalStrnCpy(dest, src, n) strncpy(dest, src, n) ++#define kalStrnCpy(dest, src, n) memcpy(dest, src, n) + #define kalStrCmp(ct, cs) strcmp(ct, cs) + #define kalStrnCmp(ct, cs, n) strncmp(ct, cs, n) + #define kalStrChr(s, c) strchr(s, c) +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0009-wifi-activated-wifi-options.patch b/root/target/linux/mediatek/patches-4.19/0009-wifi-activated-wifi-options.patch new file mode 100644 index 00000000..02d55f18 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0009-wifi-activated-wifi-options.patch @@ -0,0 +1,52 @@ +From b3bf5911a5d9f6eb8112d294ffaf5f474dccc686 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 23 Oct 2018 13:31:20 +0200 +Subject: [PATCH 09/77] [wifi] activated wifi-options + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 09df75013c09..fe7532886ccc 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -141,8 +141,8 @@ CONFIG_NF_LOG_IPV6=m + CONFIG_NF_REJECT_IPV6=m + CONFIG_IP_NF_NAT=m + CONFIG_IP6_NF_NAT=m +-CONFIG_NF_NAT_MASQUERADE_IPV4=m +-CONFIG_NF_NAT_MASQUERADE_IPV6=m ++CONFIG_NF_NAT_MASQUERADE_IPV4=y ++CONFIG_NF_NAT_MASQUERADE_IPV6=y + CONFIG_IP_NF_FILTER=m + CONFIG_IP6_NF_FILTER=m + CONFIG_IP_NF_TARGET_MASQUERADE=m +@@ -376,17 +376,17 @@ CONFIG_CFG80211=y + + #internal wlan (not working yet) + # CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set +-#CONFIG_MTK_COMBO=y +-#CONFIG_MTK_COMBO_CHIP_CONSYS_7623=y ++CONFIG_MTK_COMBO=y ++CONFIG_MTK_COMBO_CHIP_CONSYS_7623=y + #used in 4.4, but should be set in Kconfig by selecting mt7623 COMBO +-#CONFIG_MTK_PLATFORM="mt7623" ++CONFIG_MTK_PLATFORM="mt7623" + +-#CONFIG_MTK_COMBO_COMM=y +-#CONFIG_MTK_COMBO_WIFI=y +-#CONFIG_NL80211_TESTMODE=y ++CONFIG_MTK_COMBO_COMM=y ++CONFIG_MTK_COMBO_WIFI=y ++CONFIG_NL80211_TESTMODE=y + + #internal Bluetooth (also not working yet) +-#CONFIG_BT=y ++CONFIG_BT=y + #CONFIG_MTK_COMBO_BT=y + #CONFIG_MTK_COMBO_BT_HCI=y + #needed for BT? +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0012-defconfig-add-missing-CONFIG_PCI_MSI-needed-for-pcie.patch b/root/target/linux/mediatek/patches-4.19/0012-defconfig-add-missing-CONFIG_PCI_MSI-needed-for-pcie.patch new file mode 100644 index 00000000..829e2c89 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0012-defconfig-add-missing-CONFIG_PCI_MSI-needed-for-pcie.patch @@ -0,0 +1,34 @@ +From ec64b17f37390c32cd88ebddbabd423f438335fc Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 Nov 2018 09:52:44 +0100 +Subject: [PATCH 12/77] [defconfig] add missing CONFIG_PCI_MSI (needed for pcie + and maybe sata) and EARLY_PRINTK + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index d7741650941f..fe1edaa7680f 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -1,6 +1,8 @@ + CONFIG_LOCALVERSION="-bpi-r2" + CONFIG_LOCALVERSION_AUTO=n + ++CONFIG_EARLY_PRINTK=y ++ + #spectre/meltdown + CONFIG_PAGE_TABLE_ISOLATION=y + +@@ -58,6 +60,7 @@ CONFIG_PL310_ERRATA_753970=y + CONFIG_PL310_ERRATA_769419=y + + CONFIG_PCI=y ++CONFIG_PCI_MSI=y + CONFIG_SMP=y + CONFIG_HAVE_ARM_ARCH_TIMER=y + CONFIG_NR_CPUS=16 +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0014-dts-set-mac-address-eth0.patch b/root/target/linux/mediatek/patches-4.19/0014-dts-set-mac-address-eth0.patch new file mode 100644 index 00000000..33a9e095 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0014-dts-set-mac-address-eth0.patch @@ -0,0 +1,34 @@ +From 961d318c99fb0019f0fa571a160af09e859d63e8 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Mon, 31 Dec 2018 17:00:56 +0100 +Subject: [PATCH 14/77] [dts] set mac-address (eth0) + +can be overwritten by uboot (ethaddr) if using separated fdt +or devicetree-overlay +--- + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 465fb887b2ca..a47022765326 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -15,6 +15,7 @@ + + aliases { + serial2 = &uart2; ++ ethernet0 = &gmac0; + }; + + chosen { +@@ -147,6 +148,7 @@ + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "trgmii"; ++ mac-address = [02 02 02 02 02 02]; + + fixed-link { + speed = <1000>; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0016-build.sh-dts-added-devicetree-Overlay.patch b/root/target/linux/mediatek/patches-4.19/0016-build.sh-dts-added-devicetree-Overlay.patch new file mode 100644 index 00000000..92638e53 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0016-build.sh-dts-added-devicetree-Overlay.patch @@ -0,0 +1,40 @@ +From d226d27f0419a6d1f2fa42abbf67eb4315223372 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 5 Jan 2019 10:11:41 +0100 +Subject: [PATCH 16/77] [build.sh,dts] added devicetree-Overlay + +compile bpi-r2-mac.dts like this: + +dtc -@ -I dts -O dtb -o bpi-r2-mac.dtb bpi-r2-mac.dts + +in uboot you can load DTO with this (after loading base ftd): +loaddto=echo "loaddto:${dto}";fdt addr ${dtaddr};fdt resize 8192; setexpr fdtovaddr ${dtaddr} + F000; + fatload ${device} ${partition} ${fdtovaddr} ${bpi}/${board}/${service}/dtb/${dto} && fdt apply ${fdtovaddr} + +uboot needs option CONFIG_OF_LIBFDT_OVERLAY=y +--- + bpi-r2-mac.dts | 12 ++++++++++++ + 1 files changed, 12 insertions(+) + create mode 100644 bpi-r2-mac.dts + +diff --git a/bpi-r2-mac.dts b/bpi-r2-mac.dts +new file mode 100644 +index 000000000000..f4eed976e158 +--- /dev/null ++++ b/bpi-r2-mac.dts +@@ -0,0 +1,12 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ fragment@0 { ++ /*target = <&gmac0>;*/ ++ target-path = "/eth/gmac0"; ++ __overlay__ { ++ mac-address = [02 01 02 03 04 05]; ++ }; ++ }; ++}; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0019-net-dsa-adding-fields-for-holding-information-about-.patch b/root/target/linux/mediatek/patches-4.19/0019-net-dsa-adding-fields-for-holding-information-about-.patch new file mode 100644 index 00000000..f8e8812a --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0019-net-dsa-adding-fields-for-holding-information-about-.patch @@ -0,0 +1,60 @@ +From 329ff45aafea77cd9f5c97d2988e7c399ef05d6d Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 29 Nov 2018 11:34:09 +0100 +Subject: [PATCH 19/77] net: dsa: adding fields for holding information about + upstream-port + +for multiple cpu-Ports aech port needs storing the the cpu-port to be used +this Patch adds the needed fields for this + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0033-dsa-multi-cpu.patch + +Signed-off-by: Frank Wunderlich +--- + include/net/dsa.h | 4 ++++ + net/dsa/dsa_priv.h | 5 +++++ + 2 files changed, 9 insertions(+) + +diff --git a/include/net/dsa.h b/include/net/dsa.h +index 461e8a7661b7..6e0c95625a21 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -202,6 +202,10 @@ struct dsa_port { + struct net_device *bridge_dev; + struct devlink_port devlink_port; + struct phylink *pl; ++ ++ struct net_device *ethernet; ++ int upstream; ++ + /* + * Original copy of the master netdev ethtool_ops + */ +diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h +index 3964c6f7a7c0..559a3a250c88 100644 +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -81,6 +81,8 @@ struct dsa_slave_priv { + + /* TC context */ + struct list_head mall_tc_list; ++ ++ struct net_device *master; + }; + + /* dsa.c */ +@@ -187,7 +189,10 @@ static inline struct net_device * + dsa_slave_to_master(const struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct dsa_slave_priv *p = netdev_priv(dev); + ++ if (p->master) ++ return p->master; + return dp->cpu_dp->master; + } + +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0020-net-dsa-add-helper-functions.patch b/root/target/linux/mediatek/patches-4.19/0020-net-dsa-add-helper-functions.patch new file mode 100644 index 00000000..feb001f8 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0020-net-dsa-add-helper-functions.patch @@ -0,0 +1,86 @@ +From 90adf38283688d8c25feeb7e3989cc2da3d58122 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 29 Nov 2018 11:27:12 +0100 +Subject: [PATCH 20/77] net: dsa: add helper functions + +for using mutliple cpu-Ports 3 additional functions are defined to read +dts-option (dsa_user_parse) and check if current port is a upstream-port +(dsa_port_upstream_port, dsa_is_upstream_port) + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0033-dsa-multi-cpu.patch + +Signed-off-by: Frank Wunderlich +--- + include/net/dsa.h | 18 ++++++++++++++++++ + net/dsa/dsa2.c | 18 ++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/include/net/dsa.h b/include/net/dsa.h +index 6e0c95625a21..36db2ee83da6 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -318,6 +318,12 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, + return ds->rtable[device]; + } + ++ ++static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p) ++{ ++ return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p); ++} ++ + /* Return the local port used to reach the dedicated CPU port */ + static inline unsigned int dsa_upstream_port(struct dsa_switch *ds, int port) + { +@@ -330,6 +336,18 @@ static inline unsigned int dsa_upstream_port(struct dsa_switch *ds, int port) + return dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index); + } + ++static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port) ++{ ++ /* ++ * If this port has a specific upstream cpu port, use it, ++ * otherwise use the switch default. ++ */ ++ if (ds->ports[port].upstream) ++ return ds->ports[port].upstream; ++ else ++ return dsa_upstream_port(ds, port); ++} ++ + typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, + bool is_static, void *data); + struct dsa_switch_ops { +diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c +index a1917025e155..b7c6da2f1f08 100644 +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -255,6 +255,24 @@ static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst) + dst->cpu_dp = NULL; + } + ++static int dsa_user_parse(struct dsa_port *port, u32 index, ++ struct dsa_switch *ds) ++{ ++ struct device_node *cpu_port; ++ const unsigned int *cpu_port_reg; ++ int cpu_port_index; ++ ++ cpu_port = of_parse_phandle(port->dn, "default_cpu", 0); ++ if (cpu_port) { ++ cpu_port_reg = of_get_property(cpu_port, "reg", NULL); ++ if (!cpu_port_reg) ++ return -EINVAL; ++ cpu_port_index = be32_to_cpup(cpu_port_reg); ++ ds->ports[index].upstream = cpu_port_index; ++ } ++ return 0; ++} ++ + static int dsa_port_setup(struct dsa_port *dp) + { + struct dsa_switch *ds = dp->ds; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0021-net-dsa-adding-handling-of-second-CPU-Port.patch b/root/target/linux/mediatek/patches-4.19/0021-net-dsa-adding-handling-of-second-CPU-Port.patch new file mode 100644 index 00000000..8b5a9730 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0021-net-dsa-adding-handling-of-second-CPU-Port.patch @@ -0,0 +1,102 @@ +From 8325a7cbf9648725163a7596ba3381775039fe69 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 29 Nov 2018 11:38:27 +0100 +Subject: [PATCH 21/77] net: dsa: adding handling of second CPU-Port + +this patch adds the core-functionality of multiple cpu-ports + +currently it uses definition in dts to make connection between cpu and user-port + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0033-dsa-multi-cpu.patch + +Signed-off-by: Frank Wunderlich +--- + net/dsa/dsa2.c | 18 ++++++++++++++++++ + net/dsa/slave.c | 3 ++- + 2 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c +index b7c6da2f1f08..8f64535fd2a0 100644 +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -303,6 +303,8 @@ static int dsa_port_setup(struct dsa_port *dp) + ds->index, dp->index); + return err; + } ++ if (dp->master) ++ dp->master->dsa_ptr = dp; + break; + case DSA_PORT_TYPE_DSA: + /* dp->index is used now as port_number. However +@@ -323,12 +325,17 @@ static int dsa_port_setup(struct dsa_port *dp) + devlink_port_attrs_set(&dp->devlink_port, + DEVLINK_PORT_FLAVOUR_PHYSICAL, + dp->index, false, 0); ++ err = dsa_user_parse(dp, dp->index, ds); ++ if (err) ++ return err; ++ + err = dsa_slave_create(dp); + if (err) + dev_err(ds->dev, "failed to create slave for port %d.%d\n", + ds->index, dp->index); + else + devlink_port_type_eth_set(&dp->devlink_port, dp->slave); ++ + break; + } + +@@ -344,6 +351,14 @@ static void dsa_port_teardown(struct dsa_port *dp) + case DSA_PORT_TYPE_UNUSED: + break; + case DSA_PORT_TYPE_CPU: ++ dsa_port_link_unregister_of(dp); ++ if (dp->master) ++ dp->master->dsa_ptr = NULL; ++ if (dp->ethernet) { ++ dev_put(dp->ethernet); ++ dp->ethernet = NULL; ++ } ++ break; + case DSA_PORT_TYPE_DSA: + dsa_port_link_unregister_of(dp); + break; +@@ -598,6 +613,9 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master) + dp->master = master; + dp->dst = dst; + ++ dev_hold(master); ++ ds->ports[dp->index].ethernet = master; ++ + return 0; + } + +diff --git a/net/dsa/slave.c b/net/dsa/slave.c +index 1c45c1d6d241..3bdbd53d3420 100644 +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1291,11 +1291,11 @@ static void dsa_slave_notify(struct net_device *dev, unsigned long val) + int dsa_slave_create(struct dsa_port *port) + { + const struct dsa_port *cpu_dp = port->cpu_dp; +- struct net_device *master = cpu_dp->master; + struct dsa_switch *ds = port->ds; + const char *name = port->name; + struct net_device *slave_dev; + struct dsa_slave_priv *p; ++ struct net_device *master = ds->ports[port->upstream].ethernet; + int ret; + + if (!ds->num_tx_queues) +@@ -1334,6 +1334,7 @@ int dsa_slave_create(struct dsa_port *port) + p->dp = port; + INIT_LIST_HEAD(&p->mall_tc_list); + p->xmit = cpu_dp->tag_ops->xmit; ++ p->master = master; + port->slave = slave_dev; + + netif_carrier_off(slave_dev); +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0022-net-dsa-add-support-for-GMAC2-wired-to-ext.patch b/root/target/linux/mediatek/patches-4.19/0022-net-dsa-add-support-for-GMAC2-wired-to-ext.patch new file mode 100644 index 00000000..ade0497f --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0022-net-dsa-add-support-for-GMAC2-wired-to-ext.patch @@ -0,0 +1,34 @@ +From a80c992c93729c817267ea5575faa089a278e593 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 8 Dec 2018 19:22:22 +0100 +Subject: [PATCH 22/77] net: dsa: add support for GMAC2 wired to ext + +cpu-ports of mt7530 need some special flags to be set + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch + +Signed-off-by: Frank Wunderlich +--- + drivers/net/dsa/mt7530.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 62e486652e62..8ed0af6abe7d 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1281,6 +1281,11 @@ mt7530_setup(struct dsa_switch *ds) + val = mt7530_read(priv, MT7530_MHWTRAP); + val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; + val |= MHWTRAP_MANUAL; ++ if (!dsa_is_cpu_port(ds, 5)) { ++ val |= MHWTRAP_P5_DIS; ++ val |= MHWTRAP_P5_MAC_SEL; ++ val |= MHWTRAP_P5_RGMII_MODE; ++ } + mt7530_write(priv, MT7530_MHWTRAP, val); + + /* Enable and reset MIB counters */ +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0023-net-dsa-dsa-multi-cpu-mt7530.c.patch b/root/target/linux/mediatek/patches-4.19/0023-net-dsa-dsa-multi-cpu-mt7530.c.patch new file mode 100644 index 00000000..5a08b31e --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0023-net-dsa-dsa-multi-cpu-mt7530.c.patch @@ -0,0 +1,121 @@ +From 954b359077f770bdbb376db571a4710965684dc9 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 8 Dec 2018 19:25:57 +0100 +Subject: [PATCH 23/77] net: dsa: dsa multi cpu (mt7530.c) + +implementing changes to mt7530 switch driver for supporting multiple (2) +cpu-ports + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0033-dsa-multi-cpu.patch + +Signed-off-by: Frank Wunderlich +--- + drivers/net/dsa/mt7530.c | 34 +++++++++++++++++++--------------- + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 8ed0af6abe7d..fda1b67dfeac 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -678,6 +678,9 @@ static int + mt7530_cpu_port_enable(struct mt7530_priv *priv, + int port) + { ++ u8 port_mask = 0; ++ int i; ++ + /* Enable Mediatek header mode on the cpu port */ + mt7530_write(priv, MT7530_PVC_P(port), + PORT_SPEC_TAG); +@@ -694,8 +697,14 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv, + /* CPU port gets connected to all user ports of + * the switch + */ ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ if ((priv->ds->ports[port].type == DSA_PORT_TYPE_USER) && ++ (dsa_port_upstream_port(priv->ds, i) == port)) ++ port_mask |= BIT(i); ++ + mt7530_write(priv, MT7530_PCR_P(port), +- PCR_MATRIX(dsa_user_ports(priv->ds))); ++ PCR_MATRIX(port_mask)); + + return 0; + } +@@ -705,6 +714,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) + { + struct mt7530_priv *priv = ds->priv; ++ u8 upstream = dsa_port_upstream_port(ds, port); + + mutex_lock(&priv->reg_mutex); + +@@ -715,7 +725,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port, + * restore the port matrix if the port is the member of a certain + * bridge. + */ +- priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ priv->ports[port].pm |= PCR_MATRIX(BIT(upstream)); + priv->ports[port].enable = true; + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, + priv->ports[port].pm); +@@ -778,7 +788,8 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port, + struct net_device *bridge) + { + struct mt7530_priv *priv = ds->priv; +- u32 port_bitmap = BIT(MT7530_CPU_PORT); ++ u8 upstream = dsa_port_upstream_port(ds, port); ++ u32 port_bitmap = BIT(upstream); + int i; + + mutex_lock(&priv->reg_mutex); +@@ -879,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *bridge) + { + struct mt7530_priv *priv = ds->priv; ++ u8 upstream = dsa_port_upstream_port(ds, port); + int i; + + mutex_lock(&priv->reg_mutex); +@@ -906,8 +918,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, + */ + if (priv->ports[port].enable) + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, +- PCR_MATRIX(BIT(MT7530_CPU_PORT))); +- priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ PCR_MATRIX(BIT(upstream))); ++ priv->ports[port].pm = PCR_MATRIX(BIT(upstream)); + + mt7530_port_set_vlan_unaware(ds, port); + +@@ -1198,15 +1210,7 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, + static enum dsa_tag_protocol + mtk_get_tag_protocol(struct dsa_switch *ds, int port) + { +- struct mt7530_priv *priv = ds->priv; +- +- if (port != MT7530_CPU_PORT) { +- dev_warn(priv->dev, +- "port not matched with tagging CPU port\n"); +- return DSA_TAG_PROTO_NONE; +- } else { +- return DSA_TAG_PROTO_MTK; +- } ++ return DSA_TAG_PROTO_MTK; + } + + static int +@@ -1279,7 +1283,7 @@ mt7530_setup(struct dsa_switch *ds) + + /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ + val = mt7530_read(priv, MT7530_MHWTRAP); +- val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; ++ val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; + val |= MHWTRAP_MANUAL; + if (!dsa_is_cpu_port(ds, 5)) { + val |= MHWTRAP_P5_DIS; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0024-net-dsa-tell-GDMA-when-we-are-turning-on-the-special.patch b/root/target/linux/mediatek/patches-4.19/0024-net-dsa-tell-GDMA-when-we-are-turning-on-the-special.patch new file mode 100644 index 00000000..00e6a555 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0024-net-dsa-tell-GDMA-when-we-are-turning-on-the-special.patch @@ -0,0 +1,54 @@ +From 943ed2bae585cd595d8264a1f37fa3f3d5a5715b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 8 Dec 2018 20:59:09 +0100 +Subject: [PATCH 24/77] net: dsa: tell GDMA when we are turning on the special + tag + +Enabling this bit will make the RX DMA descriptor enable the SP bit for +all ingress traffic inside the return descriptor. The PPE needs this to +know that a SP is present. + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch + +Signed-off-by: Frank Wunderlich +--- + drivers/net/dsa/mt7530.c | 6 ++++++ + drivers/net/dsa/mt7530.h | 4 ++++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index fda1b67dfeac..9690a9b59fce 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -685,6 +685,12 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv, + mt7530_write(priv, MT7530_PVC_P(port), + PORT_SPEC_TAG); + ++ /* Enable Mediatek header mode on the GMAC that the cpu port ++ * connects to ++ */ ++ regmap_write_bits(priv->ethernet, MTK_GDMA_FWD_CFG(port), ++ GDMA_SPEC_TAG, GDMA_SPEC_TAG); ++ + /* Setup the MAC by default for the cpu port */ + mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); + +diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h +index d9b407a22a58..310f2536175b 100644 +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -23,6 +23,10 @@ + + #define TRGMII_BASE(x) (0x10000 + (x)) + ++/* Registers for GDMA configuration access */ ++#define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000)) ++#define GDMA_SPEC_TAG BIT(24) ++ + /* Registers to ethsys access */ + #define ETHSYS_CLKCFG0 0x2c + #define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0025-net-dsa-mt7530-add-linking-to-mdio.patch b/root/target/linux/mediatek/patches-4.19/0025-net-dsa-mt7530-add-linking-to-mdio.patch new file mode 100644 index 00000000..117dd7b5 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0025-net-dsa-mt7530-add-linking-to-mdio.patch @@ -0,0 +1,47 @@ +From 0f5ff06adcb20916acaf55976975a8b8844e785a Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 8 Dec 2018 20:59:40 +0100 +Subject: [PATCH 25/77] net: dsa: mt7530 add linking to mdio + +switch (7530) needs to to be linked to mdio-bus + +based on +https://github.com/openwrt/openwrt/blob/master/target/linux/mediatek/patches-4.14/0045-net-dsa-mediatek-turn-into-platform-driver.patch + +Signed-off-by: Frank Wunderlich +--- + drivers/net/dsa/mt7530.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 9690a9b59fce..8f95e22a33f6 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1349,7 +1349,7 @@ static int + mt7530_probe(struct mdio_device *mdiodev) + { + struct mt7530_priv *priv; +- struct device_node *dn; ++ struct device_node *dn, *mdio; + + dn = mdiodev->dev.of_node; + +@@ -1396,8 +1396,14 @@ mt7530_probe(struct mdio_device *mdiodev) + return PTR_ERR(priv->reset); + } + } ++ mdio = of_get_parent(dn); ++ if (!mdio) ++ return -EINVAL; ++ ++ priv->bus = of_mdio_find_bus(mdio); ++ if (!priv->bus) ++ return -EPROBE_DEFER; + +- priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + priv->ds->priv = priv; + priv->ds->ops = &mt7530_switch_ops; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0026-net-dsa-changes-to-dts.patch b/root/target/linux/mediatek/patches-4.19/0026-net-dsa-changes-to-dts.patch new file mode 100644 index 00000000..e3d37c86 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0026-net-dsa-changes-to-dts.patch @@ -0,0 +1,81 @@ +From 52365639697e10f1b641d25460c10d9ccc56a6d6 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 29 Nov 2018 10:53:44 +0100 +Subject: [PATCH 26/77] net: dsa: changes to dts + +--- + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 29 ++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index a47022765326..4c6e53d9e736 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -157,6 +157,18 @@ + }; + }; + ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; +@@ -175,29 +187,44 @@ + port@0 { + reg = <0>; + label = "wan"; ++ default_cpu = <&cpu_port1>; + }; + + port@1 { + reg = <1>; + label = "lan0"; ++ default_cpu = <&cpu_port0>; + }; + + port@2 { + reg = <2>; + label = "lan1"; ++ default_cpu = <&cpu_port0>; + }; + + port@3 { + reg = <3>; + label = "lan2"; ++ default_cpu = <&cpu_port0>; + }; + + port@4 { + reg = <4>; + label = "lan3"; ++ default_cpu = <&cpu_port0>; + }; + +- port@6 { ++ cpu_port1: port@5 { ++ reg = <5>; ++ label = "cpu"; ++ ethernet = <&gmac1>; ++ phy-mode = "trgmii"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ cpu_port0: port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0027-drm-mediatek-add-refcount-for-DPI-power-on-off.patch b/root/target/linux/mediatek/patches-4.19/0027-drm-mediatek-add-refcount-for-DPI-power-on-off.patch new file mode 100644 index 00000000..375741bc --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0027-drm-mediatek-add-refcount-for-DPI-power-on-off.patch @@ -0,0 +1,171 @@ +From 49f64db56f05dc7ccb1d8836c19243b5620fc93d Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:41 +0800 +Subject: [PATCH 27/77] drm/mediatek: add refcount for DPI power on/off + +After the kernel 4.4, the DRM disable flow was changed, if DPI was +disableed before CRTC, it will cause warning message as following: + +------------[ cut here ]------------ +WARNING: CPU: 0 PID: 1339 at ../../linux/linux-4.4.24-mtk/drivers/gpu/drm/drm_irq.c:1326 drm_wait_one_vblank+0x188/0x18c() +vblank wait timed out on crtc 0 +Modules linked in: bridge mt8521p_ir_shim(O) i2c_eeprom(O) mtk_m4(O) fuse_ctrl(O) virtual_block(O) caamkeys(PO) chk(PO) amperctl(O) ledctl(O) apple_auth(PO) micctl(O) sensors(PO) lla(O) sdd(PO) ice40_fpga(O) psmon(O) event_queue(PO) utils(O) blackbox(O) +CPU: 0 PID: 1339 Comm: kworker/0:1 Tainted: P W O 4.4.24 #1 +Hardware name: Mediatek Cortex-A7 (Device Tree) +Workqueue: events drm_mode_rmfb_work_fn +[] (unwind_backtrace) from [] (show_stack+0x20/0x24) +[] (show_stack) from [] (dump_stack+0x98/0xac) +[] (dump_stack) from [] (warn_slowpath_common+0x94/0xc4) +[] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x40/0x48) +[] (warn_slowpath_fmt) from [] (drm_wait_one_vblank+0x188/0x18c) +[] (drm_wait_one_vblank) from [] (drm_crtc_wait_one_vblank+0x28/0x2c) +[] (drm_crtc_wait_one_vblank) from [] (mtk_drm_crtc_disable+0x78/0x240) +[] (mtk_drm_crtc_disable) from [] (drm_atomic_helper_commit_modeset_disables+0x128/0x3b8) +[] (drm_atomic_helper_commit_modeset_disables) from [] (mtk_atomic_complete+0x74/0xb4) +[] (mtk_atomic_complete) from [] (mtk_atomic_commit+0x68/0x98) +[] (mtk_atomic_commit) from [] (drm_atomic_commit+0x54/0x74) +[] (drm_atomic_commit) from [] (drm_atomic_helper_set_config+0x7c/0xa0) +[] (drm_atomic_helper_set_config) from [] (drm_mode_set_config_internal+0x68/0xe4) +[] (drm_mode_set_config_internal) from [] (drm_framebuffer_remove+0xe4/0x120) +[] (drm_framebuffer_remove) from [] (drm_mode_rmfb_work_fn+0x48/0x58) +[] (drm_mode_rmfb_work_fn) from [] (process_one_work+0x154/0x50c) +[] (process_one_work) from [] (worker_thread+0x284/0x568) +[] (worker_thread) from [] (kthread+0xec/0x104) +[] (kthread) from [] (ret_from_fork+0x14/0x3c) +---[ end trace 12ae5358e992abd5 ]--- + +so, we add refcount for DPI power on/off to protect the flow. + +Signed-off-by: Bibby Hsieh +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 43 +++++++++--------------------- + 1 file changed, 13 insertions(+), 30 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 6c0ea39d5739..5ede1ddbaa1a 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -76,8 +76,7 @@ struct mtk_dpi { + enum mtk_dpi_out_yc_map yc_map; + enum mtk_dpi_out_bit_num bit_num; + enum mtk_dpi_out_channel_swap channel_swap; +- bool power_sta; +- u8 power_ctl; ++ int refcount; + }; + + static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e) +@@ -90,11 +89,6 @@ enum mtk_dpi_polarity { + MTK_DPI_POLARITY_FALLING, + }; + +-enum mtk_dpi_power_ctl { +- DPI_POWER_START = BIT(0), +- DPI_POWER_ENABLE = BIT(1), +-}; +- + struct mtk_dpi_polarities { + enum mtk_dpi_polarity de_pol; + enum mtk_dpi_polarity ck_pol; +@@ -367,40 +361,30 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, + } + } + +-static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) ++static void mtk_dpi_power_off(struct mtk_dpi *dpi) + { +- dpi->power_ctl &= ~pctl; +- +- if ((dpi->power_ctl & DPI_POWER_START) || +- (dpi->power_ctl & DPI_POWER_ENABLE)) ++ if (WARN_ON(dpi->refcount == 0)) + return; + +- if (!dpi->power_sta) ++ if (--dpi->refcount != 0) + return; + + mtk_dpi_disable(dpi); + clk_disable_unprepare(dpi->pixel_clk); + clk_disable_unprepare(dpi->engine_clk); +- dpi->power_sta = false; + } + +-static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) ++static int mtk_dpi_power_on(struct mtk_dpi *dpi) + { + int ret; + +- dpi->power_ctl |= pctl; +- +- if (!(dpi->power_ctl & DPI_POWER_START) && +- !(dpi->power_ctl & DPI_POWER_ENABLE)) +- return 0; +- +- if (dpi->power_sta) ++ if (++dpi->refcount != 1) + return 0; + + ret = clk_prepare_enable(dpi->engine_clk); + if (ret) { + dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret); +- goto err_eng; ++ goto err_refcount; + } + + ret = clk_prepare_enable(dpi->pixel_clk); +@@ -410,13 +394,12 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) + } + + mtk_dpi_enable(dpi); +- dpi->power_sta = true; + return 0; + + err_pixel: + clk_disable_unprepare(dpi->engine_clk); +-err_eng: +- dpi->power_ctl &= ~pctl; ++err_refcount: ++ dpi->refcount--; + return ret; + } + +@@ -552,14 +535,14 @@ static void mtk_dpi_encoder_disable(struct drm_encoder *encoder) + { + struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); + +- mtk_dpi_power_off(dpi, DPI_POWER_ENABLE); ++ mtk_dpi_power_off(dpi); + } + + static void mtk_dpi_encoder_enable(struct drm_encoder *encoder) + { + struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); + +- mtk_dpi_power_on(dpi, DPI_POWER_ENABLE); ++ mtk_dpi_power_on(dpi); + mtk_dpi_set_display_mode(dpi, &dpi->mode); + } + +@@ -582,14 +565,14 @@ static void mtk_dpi_start(struct mtk_ddp_comp *comp) + { + struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); + +- mtk_dpi_power_on(dpi, DPI_POWER_START); ++ mtk_dpi_power_on(dpi); + } + + static void mtk_dpi_stop(struct mtk_ddp_comp *comp) + { + struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); + +- mtk_dpi_power_off(dpi, DPI_POWER_START); ++ mtk_dpi_power_off(dpi); + } + + static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = { +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0028-drm-mediatek-move-hardware-register-to-node-data.patch b/root/target/linux/mediatek/patches-4.19/0028-drm-mediatek-move-hardware-register-to-node-data.patch new file mode 100644 index 00000000..fc67fb41 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0028-drm-mediatek-move-hardware-register-to-node-data.patch @@ -0,0 +1,101 @@ +From c2b3363773bfc93b3e4082ccfa99cda18ea980be Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:42 +0800 +Subject: [PATCH 28/77] drm/mediatek: move hardware register to node data + +The address of register DPI_H_FRE_CON is different in different IC. +Using of_node data to find this address. + +Reviewed-by: CK Hu +Signed-off-by: chunhui dai +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 19 ++++++++++++++++--- + drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 1 - + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 5ede1ddbaa1a..72aa43187731 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -72,6 +73,7 @@ struct mtk_dpi { + struct clk *tvd_clk; + int irq; + struct drm_display_mode mode; ++ const struct mtk_dpi_conf *conf; + enum mtk_dpi_out_color_format color_format; + enum mtk_dpi_out_yc_map yc_map; + enum mtk_dpi_out_bit_num bit_num; +@@ -110,6 +112,10 @@ struct mtk_dpi_yc_limit { + u16 c_bottom; + }; + ++struct mtk_dpi_conf { ++ u32 reg_h_fre_con; ++}; ++ + static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) + { + u32 tmp = readl(dpi->regs + offset) & ~mask; +@@ -335,7 +341,7 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) + + static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) + { +- mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N); ++ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); + } + + static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, +@@ -639,6 +645,10 @@ static const struct component_ops mtk_dpi_component_ops = { + .unbind = mtk_dpi_unbind, + }; + ++static const struct mtk_dpi_conf mt8173_conf = { ++ .reg_h_fre_con = 0xe0, ++}; ++ + static int mtk_dpi_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -653,6 +663,7 @@ static int mtk_dpi_probe(struct platform_device *pdev) + return -ENOMEM; + + dpi->dev = dev; ++ dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dpi->regs = devm_ioremap_resource(dev, mem); +@@ -732,8 +743,10 @@ static int mtk_dpi_remove(struct platform_device *pdev) + } + + static const struct of_device_id mtk_dpi_of_ids[] = { +- { .compatible = "mediatek,mt8173-dpi", }, +- {} ++ { .compatible = "mediatek,mt8173-dpi", ++ .data = &mt8173_conf, ++ }, ++ { }, + }; + + struct platform_driver mtk_dpi_driver = { +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +index 4b6ad4751a31..040444d7718d 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h ++++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +@@ -223,6 +223,5 @@ + #define ESAV_CODE2 (0xFFF << 0) + #define ESAV_CODE3_MSB BIT(16) + +-#define DPI_H_FRE_CON 0xE0 + #define H_FRE_2N BIT(25) + #endif /* __MTK_DPI_REGS_H */ +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0029-drm-mediatek-adjust-EDGE-to-match-clock-and-data.patch b/root/target/linux/mediatek/patches-4.19/0029-drm-mediatek-adjust-EDGE-to-match-clock-and-data.patch new file mode 100644 index 00000000..71118456 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0029-drm-mediatek-adjust-EDGE-to-match-clock-and-data.patch @@ -0,0 +1,62 @@ +From d0b9bb15fad38e8328f9436501e36697e4e1a89d Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:43 +0800 +Subject: [PATCH 29/77] drm/mediatek: adjust EDGE to match clock and data + +The default timing of DPI data and clock is not match. +We could adjust this bit to make them match. + +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++++++++ + drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 72aa43187731..0ce4b61efaeb 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -114,6 +114,7 @@ struct mtk_dpi_yc_limit { + + struct mtk_dpi_conf { + u32 reg_h_fre_con; ++ bool edge_sel_en; + }; + + static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) +@@ -344,6 +345,12 @@ static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) + mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); + } + ++static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi) ++{ ++ if (dpi->conf->edge_sel_en) ++ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN); ++} ++ + static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, + enum mtk_dpi_out_color_format format) + { +@@ -507,6 +514,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, + mtk_dpi_config_yc_map(dpi, dpi->yc_map); + mtk_dpi_config_color_format(dpi, dpi->color_format); + mtk_dpi_config_2n_h_fre(dpi); ++ mtk_dpi_config_disable_edge(dpi); + mtk_dpi_sw_reset(dpi, false); + + return 0; +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +index 040444d7718d..d9db8c4cacd7 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h ++++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +@@ -223,5 +223,6 @@ + #define ESAV_CODE2 (0xFFF << 0) + #define ESAV_CODE3_MSB BIT(16) + ++#define EDGE_SEL_EN BIT(5) + #define H_FRE_2N BIT(25) + #endif /* __MTK_DPI_REGS_H */ +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0030-drm-mediatek-add-clock-factor-for-different-IC.patch b/root/target/linux/mediatek/patches-4.19/0030-drm-mediatek-add-clock-factor-for-different-IC.patch new file mode 100644 index 00000000..8977fbe6 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0030-drm-mediatek-add-clock-factor-for-different-IC.patch @@ -0,0 +1,68 @@ +From 0a8f36a231341ac5d66c186bcb1600a5abc00132 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:44 +0800 +Subject: [PATCH 30/77] drm/mediatek: add clock factor for different IC + +different IC has different clock designed in HDMI, the factor for +calculate clock should be different. Usinng the data in of_node +to find this factor. + +Reviewed-by: CK Hu +Signed-off-by: chunhui dai +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 0ce4b61efaeb..0dbe9345fa2e 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -113,6 +113,7 @@ struct mtk_dpi_yc_limit { + }; + + struct mtk_dpi_conf { ++ unsigned int (*cal_factor)(int clock); + u32 reg_h_fre_con; + bool edge_sel_en; + }; +@@ -431,15 +432,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, + unsigned int factor; + + /* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */ +- +- if (mode->clock <= 27000) +- factor = 3 << 4; +- else if (mode->clock <= 84000) +- factor = 3 << 3; +- else if (mode->clock <= 167000) +- factor = 3 << 2; +- else +- factor = 3 << 1; ++ factor = dpi->conf->cal_factor(mode->clock); + drm_display_mode_to_videomode(mode, &vm); + pll_rate = vm.pixelclock * factor; + +@@ -653,7 +646,20 @@ static const struct component_ops mtk_dpi_component_ops = { + .unbind = mtk_dpi_unbind, + }; + ++static unsigned int mt8173_calculate_factor(int clock) ++{ ++ if (clock <= 27000) ++ return 3 << 4; ++ else if (clock <= 84000) ++ return 3 << 3; ++ else if (clock <= 167000) ++ return 3 << 2; ++ else ++ return 3 << 1; ++} ++ + static const struct mtk_dpi_conf mt8173_conf = { ++ .cal_factor = mt8173_calculate_factor, + .reg_h_fre_con = 0xe0, + }; + +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0031-drm-mediatek-convert-dpi-driver-to-use-drm_of_find_p.patch b/root/target/linux/mediatek/patches-4.19/0031-drm-mediatek-convert-dpi-driver-to-use-drm_of_find_p.patch new file mode 100644 index 00000000..25bd3912 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0031-drm-mediatek-convert-dpi-driver-to-use-drm_of_find_p.patch @@ -0,0 +1,66 @@ +From ef9b74fc6412b2402f882b012f78bfb3031aa4c6 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:45 +0800 +Subject: [PATCH 31/77] drm/mediatek: convert dpi driver to use + drm_of_find_panel_or_bridge + +Convert dpi driver to use drm_of_find_panel_or_bridge. +This changes some error messages to debug messages (in the graph core). +Graph connections are often "no connects" depending on the particular +board, so we want to avoid spurious messages. Plus the kernel is not a +DT validator. +related links: +[1] https://lkml.org/lkml/2017/2/3/716 +[2] https://lkml.org/lkml/2017/2/3/719 + +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 0dbe9345fa2e..08915e1765f8 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -668,7 +669,6 @@ static int mtk_dpi_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct mtk_dpi *dpi; + struct resource *mem; +- struct device_node *bridge_node; + int comp_id; + int ret; + +@@ -714,16 +714,12 @@ static int mtk_dpi_probe(struct platform_device *pdev) + return -EINVAL; + } + +- bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0); +- if (!bridge_node) +- return -ENODEV; +- +- dev_info(dev, "Found bridge node: %pOF\n", bridge_node); ++ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, ++ NULL, &dpi->bridge); ++ if (ret) ++ return ret; + +- dpi->bridge = of_drm_find_bridge(bridge_node); +- of_node_put(bridge_node); +- if (!dpi->bridge) +- return -EPROBE_DEFER; ++ dev_info(dev, "Found bridge node: %pOF\n", dpi->bridge->of_node); + + comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI); + if (comp_id < 0) { +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0032-drm-mediatek-add-dpi-driver-for-mt2701-and-mt7623.patch b/root/target/linux/mediatek/patches-4.19/0032-drm-mediatek-add-dpi-driver-for-mt2701-and-mt7623.patch new file mode 100644 index 00000000..2aa37a7d --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0032-drm-mediatek-add-dpi-driver-for-mt2701-and-mt7623.patch @@ -0,0 +1,76 @@ +From 5750b7268c5412e18a476482f92425eb0228564b Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:46 +0800 +Subject: [PATCH 32/77] drm/mediatek: add dpi driver for mt2701 and mt7623 + +This patch adds dpi dirver suppot for both mt2701 and mt7623. +And also support other (existing or future) chips that use +the same binding and driver. + +Reviewed-by: CK Hu +Signed-off-by: chunhui dai +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++++++++++ + drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 ++ + 2 files changed, 23 insertions(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 08915e1765f8..62a9d47df948 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -659,11 +659,29 @@ static unsigned int mt8173_calculate_factor(int clock) + return 3 << 1; + } + ++static unsigned int mt2701_calculate_factor(int clock) ++{ ++ if (clock <= 64000) ++ return 16; ++ else if (clock <= 128000) ++ return 8; ++ else if (clock <= 256000) ++ return 4; ++ else ++ return 2; ++} ++ + static const struct mtk_dpi_conf mt8173_conf = { + .cal_factor = mt8173_calculate_factor, + .reg_h_fre_con = 0xe0, + }; + ++static const struct mtk_dpi_conf mt2701_conf = { ++ .cal_factor = mt2701_calculate_factor, ++ .reg_h_fre_con = 0xb0, ++ .edge_sel_en = true, ++}; ++ + static int mtk_dpi_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -753,6 +771,9 @@ static int mtk_dpi_remove(struct platform_device *pdev) + } + + static const struct of_device_id mtk_dpi_of_ids[] = { ++ { .compatible = "mediatek,mt2701-dpi", ++ .data = &mt2701_conf, ++ }, + { .compatible = "mediatek,mt8173-dpi", + .data = &mt8173_conf, + }, +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +index 47ec604289b7..6422e99952fe 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +@@ -424,6 +424,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { + .data = (void *)MTK_DSI }, + { .compatible = "mediatek,mt8173-dsi", + .data = (void *)MTK_DSI }, ++ { .compatible = "mediatek,mt2701-dpi", ++ .data = (void *)MTK_DPI }, + { .compatible = "mediatek,mt8173-dpi", + .data = (void *)MTK_DPI }, + { .compatible = "mediatek,mt2701-disp-mutex", +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0033-drm-mediatek-separate-hdmi-phy-to-different-file.patch b/root/target/linux/mediatek/patches-4.19/0033-drm-mediatek-separate-hdmi-phy-to-different-file.patch new file mode 100644 index 00000000..1c769415 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0033-drm-mediatek-separate-hdmi-phy-to-different-file.patch @@ -0,0 +1,641 @@ +From 186643bd86d33f0a773139deb5af6e12354b5907 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:47 +0800 +Subject: [PATCH 33/77] drm/mediatek: separate hdmi phy to different file + +Different IC has different phy setting of HDMI. +This patch separates the phy hardware relate part for mt8173. + +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/Makefile | 6 +- + drivers/gpu/drm/mediatek/mtk_hdmi.c | 1 + + drivers/gpu/drm/mediatek/mtk_hdmi.h | 2 +- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 232 ++++++++++++++++++ + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 58 +++++ + .../gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 226 +---------------- + 6 files changed, 302 insertions(+), 223 deletions(-) + create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c + create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.h + +diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile +index ce83c396a742..61cf0d2ab28a 100644 +--- a/drivers/gpu/drm/mediatek/Makefile ++++ b/drivers/gpu/drm/mediatek/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++ + mediatek-drm-y := mtk_disp_color.o \ + mtk_disp_ovl.o \ + mtk_disp_rdma.o \ +@@ -18,6 +19,7 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o + mediatek-drm-hdmi-objs := mtk_cec.o \ + mtk_hdmi.o \ + mtk_hdmi_ddc.o \ +- mtk_mt8173_hdmi_phy.o ++ mtk_mt8173_hdmi_phy.o \ ++ mtk_hdmi_phy.o + +-obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o ++obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o +\ No newline at end of file +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c +index 643f5edd68fe..29bd2a144b19 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c +@@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) + static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) + { + struct arm_smccc_res res; ++ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy); + + /* + * MT8173 HDMI hardware has an output control bit to enable/disable HDMI +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h +index 6371b3de1ff6..3e9fb8d19802 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi.h ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h +@@ -13,11 +13,11 @@ + */ + #ifndef _MTK_HDMI_CTRL_H + #define _MTK_HDMI_CTRL_H ++#include "mtk_hdmi_phy.h" + + struct platform_driver; + + extern struct platform_driver mtk_cec_driver; + extern struct platform_driver mtk_hdmi_ddc_driver; +-extern struct platform_driver mtk_hdmi_phy_driver; + + #endif /* _MTK_HDMI_CTRL_H */ +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +new file mode 100644 +index 000000000000..514f3e9a8767 +--- /dev/null ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2018 MediaTek Inc. ++ * Author: Jie Qiu ++ */ ++ ++#include "mtk_hdmi_phy.h" ++ ++static int mtk_hdmi_phy_power_on(struct phy *phy); ++static int mtk_hdmi_phy_power_off(struct phy *phy); ++ ++static const struct phy_ops mtk_hdmi_phy_dev_ops = { ++ .power_on = mtk_hdmi_phy_power_on, ++ .power_off = mtk_hdmi_phy_power_off, ++ .owner = THIS_MODULE, ++}; ++ ++long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ hdmi_phy->pll_rate = rate; ++ if (rate <= 74250000) ++ *parent_rate = rate; ++ else ++ *parent_rate = rate / 2; ++ ++ return rate; ++} ++ ++unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ return hdmi_phy->pll_rate; ++} ++ ++void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 bits) ++{ ++ void __iomem *reg = hdmi_phy->regs + offset; ++ u32 tmp; ++ ++ tmp = readl(reg); ++ tmp &= ~bits; ++ writel(tmp, reg); ++} ++ ++void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 bits) ++{ ++ void __iomem *reg = hdmi_phy->regs + offset; ++ u32 tmp; ++ ++ tmp = readl(reg); ++ tmp |= bits; ++ writel(tmp, reg); ++} ++ ++void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 val, u32 mask) ++{ ++ void __iomem *reg = hdmi_phy->regs + offset; ++ u32 tmp; ++ ++ tmp = readl(reg); ++ tmp = (tmp & ~mask) | (val & mask); ++ writel(tmp, reg); ++} ++ ++inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) ++{ ++ return container_of(hw, struct mtk_hdmi_phy, pll_hw); ++} ++ ++static int mtk_hdmi_phy_power_on(struct phy *phy) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); ++ int ret; ++ ++ ret = clk_prepare_enable(hdmi_phy->pll); ++ if (ret < 0) ++ return ret; ++ ++ hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy); ++ return 0; ++} ++ ++static int mtk_hdmi_phy_power_off(struct phy *phy) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); ++ ++ hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); ++ clk_disable_unprepare(hdmi_phy->pll); ++ ++ return 0; ++} ++ ++static const struct phy_ops * ++mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy) ++{ ++ if (hdmi_phy && hdmi_phy->conf && ++ hdmi_phy->conf->hdmi_phy_enable_tmds && ++ hdmi_phy->conf->hdmi_phy_disable_tmds) ++ return &mtk_hdmi_phy_dev_ops; ++ ++ dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n"); ++ return NULL; ++} ++ ++static void mtk_hdmi_phy_clk_get_ops(struct mtk_hdmi_phy *hdmi_phy, ++ const struct clk_ops **ops) ++{ ++ if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops) ++ *ops = hdmi_phy->conf->hdmi_phy_clk_ops; ++ else ++ dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n"); ++} ++ ++static int mtk_hdmi_phy_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_hdmi_phy *hdmi_phy; ++ struct resource *mem; ++ struct clk *ref_clk; ++ const char *ref_clk_name; ++ struct clk_init_data clk_init = { ++ .num_parents = 1, ++ .parent_names = (const char * const *)&ref_clk_name, ++ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, ++ }; ++ ++ struct phy *phy; ++ struct phy_provider *phy_provider; ++ int ret; ++ ++ hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); ++ if (!hdmi_phy) ++ return -ENOMEM; ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ hdmi_phy->regs = devm_ioremap_resource(dev, mem); ++ if (IS_ERR(hdmi_phy->regs)) { ++ ret = PTR_ERR(hdmi_phy->regs); ++ dev_err(dev, "Failed to get memory resource: %d\n", ret); ++ return ret; ++ } ++ ++ ref_clk = devm_clk_get(dev, "pll_ref"); ++ if (IS_ERR(ref_clk)) { ++ ret = PTR_ERR(ref_clk); ++ dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", ++ ret); ++ return ret; ++ } ++ ref_clk_name = __clk_get_name(ref_clk); ++ ++ ret = of_property_read_string(dev->of_node, "clock-output-names", ++ &clk_init.name); ++ if (ret < 0) { ++ dev_err(dev, "Failed to read clock-output-names: %d\n", ret); ++ return ret; ++ } ++ ++ hdmi_phy->dev = dev; ++ hdmi_phy->conf = ++ (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev); ++ mtk_hdmi_phy_clk_get_ops(hdmi_phy, &clk_init.ops); ++ hdmi_phy->pll_hw.init = &clk_init; ++ hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); ++ if (IS_ERR(hdmi_phy->pll)) { ++ ret = PTR_ERR(hdmi_phy->pll); ++ dev_err(dev, "Failed to register PLL: %d\n", ret); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "mediatek,ibias", ++ &hdmi_phy->ibias); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", ++ &hdmi_phy->ibias_up); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); ++ return ret; ++ } ++ ++ dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); ++ hdmi_phy->drv_imp_clk = 0x30; ++ hdmi_phy->drv_imp_d2 = 0x30; ++ hdmi_phy->drv_imp_d1 = 0x30; ++ hdmi_phy->drv_imp_d0 = 0x30; ++ ++ phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy)); ++ if (IS_ERR(phy)) { ++ dev_err(dev, "Failed to create HDMI PHY\n"); ++ return PTR_ERR(phy); ++ } ++ phy_set_drvdata(phy, hdmi_phy); ++ ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ if (IS_ERR(phy_provider)) { ++ dev_err(dev, "Failed to register HDMI PHY\n"); ++ return PTR_ERR(phy_provider); ++ } ++ ++ return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, ++ hdmi_phy->pll); ++} ++ ++static const struct of_device_id mtk_hdmi_phy_match[] = { ++ { .compatible = "mediatek,mt8173-hdmi-phy", ++ .data = &mtk_hdmi_phy_8173_conf, ++ }, ++ {}, ++}; ++ ++struct platform_driver mtk_hdmi_phy_driver = { ++ .probe = mtk_hdmi_phy_probe, ++ .driver = { ++ .name = "mediatek-hdmi-phy", ++ .of_match_table = mtk_hdmi_phy_match, ++ }, ++}; ++ ++MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +new file mode 100644 +index 000000000000..09b8f525e6b8 +--- /dev/null ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +@@ -0,0 +1,58 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2018 MediaTek Inc. ++ * Author: Chunhui Dai ++ */ ++ ++#ifndef _MTK_HDMI_PHY_H ++#define _MTK_HDMI_PHY_H ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct mtk_hdmi_phy; ++ ++struct mtk_hdmi_phy_conf { ++ const struct clk_ops *hdmi_phy_clk_ops; ++ void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); ++ void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); ++}; ++ ++struct mtk_hdmi_phy { ++ void __iomem *regs; ++ struct device *dev; ++ struct mtk_hdmi_phy_conf *conf; ++ struct clk *pll; ++ struct clk_hw pll_hw; ++ unsigned long pll_rate; ++ unsigned char drv_imp_clk; ++ unsigned char drv_imp_d2; ++ unsigned char drv_imp_d1; ++ unsigned char drv_imp_d0; ++ unsigned int ibias; ++ unsigned int ibias_up; ++}; ++ ++void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 bits); ++void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 bits); ++void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, ++ u32 val, u32 mask); ++struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); ++long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate); ++unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate); ++ ++extern struct platform_driver mtk_hdmi_phy_driver; ++extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; ++ ++#endif /* _MTK_HDMI_PHY_H */ +diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +index 51cb9cfb6646..ed5916b27658 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +@@ -12,15 +12,7 @@ + * GNU General Public License for more details. + */ + +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include "mtk_hdmi_phy.h" + + #define HDMI_CON0 0x00 + #define RG_HDMITX_PLL_EN BIT(31) +@@ -123,20 +115,6 @@ + #define RGS_HDMITX_5T1_EDG (0xf << 4) + #define RGS_HDMITX_PLUG_TST BIT(0) + +-struct mtk_hdmi_phy { +- void __iomem *regs; +- struct device *dev; +- struct clk *pll; +- struct clk_hw pll_hw; +- unsigned long pll_rate; +- u8 drv_imp_clk; +- u8 drv_imp_d2; +- u8 drv_imp_d1; +- u8 drv_imp_d0; +- u32 ibias; +- u32 ibias_up; +-}; +- + static const u8 PREDIV[3][4] = { + {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */ + {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */ +@@ -185,44 +163,6 @@ static const u8 HTPLLBR[3][4] = { + {0x1, 0x2, 0x2, 0x1} /* 148Mhz */ + }; + +-static void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, +- u32 bits) +-{ +- void __iomem *reg = hdmi_phy->regs + offset; +- u32 tmp; +- +- tmp = readl(reg); +- tmp &= ~bits; +- writel(tmp, reg); +-} +- +-static void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, +- u32 bits) +-{ +- void __iomem *reg = hdmi_phy->regs + offset; +- u32 tmp; +- +- tmp = readl(reg); +- tmp |= bits; +- writel(tmp, reg); +-} +- +-static void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, +- u32 val, u32 mask) +-{ +- void __iomem *reg = hdmi_phy->regs + offset; +- u32 tmp; +- +- tmp = readl(reg); +- tmp = (tmp & ~mask) | (val & mask); +- writel(tmp, reg); +-} +- +-static inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) +-{ +- return container_of(hw, struct mtk_hdmi_phy, pll_hw); +-} +- + static int mtk_hdmi_pll_prepare(struct clk_hw *hw) + { + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); +@@ -345,29 +285,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + +-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long *parent_rate) +-{ +- struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); +- +- hdmi_phy->pll_rate = rate; +- if (rate <= 74250000) +- *parent_rate = rate; +- else +- *parent_rate = rate / 2; +- +- return rate; +-} +- +-static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); +- +- return hdmi_phy->pll_rate; +-} +- +-static const struct clk_ops mtk_hdmi_pll_ops = { ++static const struct clk_ops mtk_hdmi_phy_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, + .set_rate = mtk_hdmi_pll_set_rate, +@@ -390,142 +308,10 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) + RG_HDMITX_SER_EN); + } + +-static int mtk_hdmi_phy_power_on(struct phy *phy) +-{ +- struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); +- int ret; +- +- ret = clk_prepare_enable(hdmi_phy->pll); +- if (ret < 0) +- return ret; +- +- mtk_hdmi_phy_enable_tmds(hdmi_phy); +- +- return 0; +-} +- +-static int mtk_hdmi_phy_power_off(struct phy *phy) +-{ +- struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); +- +- mtk_hdmi_phy_disable_tmds(hdmi_phy); +- clk_disable_unprepare(hdmi_phy->pll); +- +- return 0; +-} +- +-static const struct phy_ops mtk_hdmi_phy_ops = { +- .power_on = mtk_hdmi_phy_power_on, +- .power_off = mtk_hdmi_phy_power_off, +- .owner = THIS_MODULE, +-}; +- +-static int mtk_hdmi_phy_probe(struct platform_device *pdev) +-{ +- struct device *dev = &pdev->dev; +- struct mtk_hdmi_phy *hdmi_phy; +- struct resource *mem; +- struct clk *ref_clk; +- const char *ref_clk_name; +- struct clk_init_data clk_init = { +- .ops = &mtk_hdmi_pll_ops, +- .num_parents = 1, +- .parent_names = (const char * const *)&ref_clk_name, +- .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, +- }; +- struct phy *phy; +- struct phy_provider *phy_provider; +- int ret; +- +- hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); +- if (!hdmi_phy) +- return -ENOMEM; +- +- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- hdmi_phy->regs = devm_ioremap_resource(dev, mem); +- if (IS_ERR(hdmi_phy->regs)) { +- ret = PTR_ERR(hdmi_phy->regs); +- dev_err(dev, "Failed to get memory resource: %d\n", ret); +- return ret; +- } +- +- ref_clk = devm_clk_get(dev, "pll_ref"); +- if (IS_ERR(ref_clk)) { +- ret = PTR_ERR(ref_clk); +- dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", +- ret); +- return ret; +- } +- ref_clk_name = __clk_get_name(ref_clk); +- +- ret = of_property_read_string(dev->of_node, "clock-output-names", +- &clk_init.name); +- if (ret < 0) { +- dev_err(dev, "Failed to read clock-output-names: %d\n", ret); +- return ret; +- } +- +- hdmi_phy->pll_hw.init = &clk_init; +- hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); +- if (IS_ERR(hdmi_phy->pll)) { +- ret = PTR_ERR(hdmi_phy->pll); +- dev_err(dev, "Failed to register PLL: %d\n", ret); +- return ret; +- } +- +- ret = of_property_read_u32(dev->of_node, "mediatek,ibias", +- &hdmi_phy->ibias); +- if (ret < 0) { +- dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); +- return ret; +- } +- +- ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", +- &hdmi_phy->ibias_up); +- if (ret < 0) { +- dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); +- return ret; +- } +- +- dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); +- hdmi_phy->drv_imp_clk = 0x30; +- hdmi_phy->drv_imp_d2 = 0x30; +- hdmi_phy->drv_imp_d1 = 0x30; +- hdmi_phy->drv_imp_d0 = 0x30; +- +- phy = devm_phy_create(dev, NULL, &mtk_hdmi_phy_ops); +- if (IS_ERR(phy)) { +- dev_err(dev, "Failed to create HDMI PHY\n"); +- return PTR_ERR(phy); +- } +- phy_set_drvdata(phy, hdmi_phy); +- +- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); +- if (IS_ERR(phy_provider)) +- return PTR_ERR(phy_provider); +- +- hdmi_phy->dev = dev; +- return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, +- hdmi_phy->pll); +-} +- +-static int mtk_hdmi_phy_remove(struct platform_device *pdev) +-{ +- return 0; +-} +- +-static const struct of_device_id mtk_hdmi_phy_match[] = { +- { .compatible = "mediatek,mt8173-hdmi-phy", }, +- {}, +-}; +- +-struct platform_driver mtk_hdmi_phy_driver = { +- .probe = mtk_hdmi_phy_probe, +- .remove = mtk_hdmi_phy_remove, +- .driver = { +- .name = "mediatek-hdmi-phy", +- .of_match_table = mtk_hdmi_phy_match, +- }, ++struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { ++ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, ++ .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, ++ .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, + }; + + MODULE_AUTHOR("Jie Qiu "); +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0034-drm-mediatek-add-support-for-SPDIF-audio-in-HDMI.patch b/root/target/linux/mediatek/patches-4.19/0034-drm-mediatek-add-support-for-SPDIF-audio-in-HDMI.patch new file mode 100644 index 00000000..8c3d0162 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0034-drm-mediatek-add-support-for-SPDIF-audio-in-HDMI.patch @@ -0,0 +1,32 @@ +From 93440802592c9acbec41645809dcae5eb350d966 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:48 +0800 +Subject: [PATCH 34/77] drm/mediatek: add support for SPDIF audio in HDMI + +add support for SPDIF audio in HDMI + +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_hdmi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c +index 29bd2a144b19..90e1139f02f8 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c +@@ -1577,6 +1577,11 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data, + hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT; + hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS; + break; ++ case HDMI_SPDIF: ++ hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM; ++ hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16; ++ hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF; ++ break; + default: + dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__, + daifmt->fmt); +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0035-drm-mediatek-add-hdmi-driver-for-MT2701-and-MT7623.patch b/root/target/linux/mediatek/patches-4.19/0035-drm-mediatek-add-hdmi-driver-for-MT2701-and-MT7623.patch new file mode 100644 index 00000000..b56c6315 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0035-drm-mediatek-add-hdmi-driver-for-MT2701-and-MT7623.patch @@ -0,0 +1,309 @@ +From 7ced4ebd71acd0677a73976bf6be399c2362ca6e Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 3 Oct 2018 11:41:49 +0800 +Subject: [PATCH 35/77] drm/mediatek: add hdmi driver for MT2701 and MT7623 + +This patch adds hdmi dirver suppot for both MT2701 and MT7623. +And also support other (existing or future) chips that use +the same binding and driver. + +Signed-off-by: chunhui dai +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/Makefile | 3 +- + drivers/gpu/drm/mediatek/mtk_hdmi.c | 9 +- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 3 + + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 2 + + .../gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 212 ++++++++++++++++++ + 5 files changed, 226 insertions(+), 3 deletions(-) + create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c + +diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile +index 61cf0d2ab28a..82ae49c64221 100644 +--- a/drivers/gpu/drm/mediatek/Makefile ++++ b/drivers/gpu/drm/mediatek/Makefile +@@ -19,7 +19,8 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o + mediatek-drm-hdmi-objs := mtk_cec.o \ + mtk_hdmi.o \ + mtk_hdmi_ddc.o \ ++ mtk_mt2701_hdmi_phy.o \ + mtk_mt8173_hdmi_phy.o \ + mtk_hdmi_phy.o + +-obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o +\ No newline at end of file ++obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c +index 90e1139f02f8..862f3ec22131 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c +@@ -241,8 +241,13 @@ static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) + * The ARM trusted firmware provides an API for the HDMI driver to set + * this control bit to enable HDMI output in supervisor mode. + */ +- arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, 0x80000000, +- 0, 0, 0, 0, 0, &res); ++ if (hdmi_phy->conf && hdmi_phy->conf->tz_disabled) ++ regmap_update_bits(hdmi->sys_regmap, ++ hdmi->sys_offset + HDMI_SYS_CFG20, ++ 0x80008005, enable ? 0x80000005 : 0x8000); ++ else ++ arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, ++ 0x80000000, 0, 0, 0, 0, 0, &res); + + regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG20, + HDMI_PCLK_FREE_RUN, enable ? HDMI_PCLK_FREE_RUN : 0); +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +index 514f3e9a8767..4ef9c57ffd44 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +@@ -214,6 +214,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) + } + + static const struct of_device_id mtk_hdmi_phy_match[] = { ++ { .compatible = "mediatek,mt2701-hdmi-phy", ++ .data = &mtk_hdmi_phy_2701_conf, ++ }, + { .compatible = "mediatek,mt8173-hdmi-phy", + .data = &mtk_hdmi_phy_8173_conf, + }, +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +index 09b8f525e6b8..f39b1fc66612 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +@@ -20,6 +20,7 @@ + struct mtk_hdmi_phy; + + struct mtk_hdmi_phy_conf { ++ bool tz_disabled; + const struct clk_ops *hdmi_phy_clk_ops; + void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); + void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); +@@ -54,5 +55,6 @@ unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + + extern struct platform_driver mtk_hdmi_phy_driver; + extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; ++extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf; + + #endif /* _MTK_HDMI_PHY_H */ +diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +new file mode 100644 +index 000000000000..fcc42dc6ea7f +--- /dev/null ++++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2018 MediaTek Inc. ++ * Author: Chunhui Dai ++ */ ++ ++#include "mtk_hdmi_phy.h" ++ ++#define HDMI_CON0 0x00 ++#define RG_HDMITX_DRV_IBIAS 0 ++#define RG_HDMITX_DRV_IBIAS_MASK (0x3f << 0) ++#define RG_HDMITX_EN_SER 12 ++#define RG_HDMITX_EN_SER_MASK (0x0f << 12) ++#define RG_HDMITX_EN_SLDO 16 ++#define RG_HDMITX_EN_SLDO_MASK (0x0f << 16) ++#define RG_HDMITX_EN_PRED 20 ++#define RG_HDMITX_EN_PRED_MASK (0x0f << 20) ++#define RG_HDMITX_EN_IMP 24 ++#define RG_HDMITX_EN_IMP_MASK (0x0f << 24) ++#define RG_HDMITX_EN_DRV 28 ++#define RG_HDMITX_EN_DRV_MASK (0x0f << 28) ++ ++#define HDMI_CON1 0x04 ++#define RG_HDMITX_PRED_IBIAS 18 ++#define RG_HDMITX_PRED_IBIAS_MASK (0x0f << 18) ++#define RG_HDMITX_PRED_IMP (0x01 << 22) ++#define RG_HDMITX_DRV_IMP 26 ++#define RG_HDMITX_DRV_IMP_MASK (0x3f << 26) ++ ++#define HDMI_CON2 0x08 ++#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0) ++#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1) ++#define RG_HDMITX_TX_POSDIV 3 ++#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3) ++#define RG_HDMITX_EN_MBIAS (0x01 << 6) ++#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7) ++ ++#define HDMI_CON4 0x10 ++#define RG_HDMITX_RESERVE_MASK (0xffffffff << 0) ++ ++#define HDMI_CON6 0x18 ++#define RG_HTPLL_BR 0 ++#define RG_HTPLL_BR_MASK (0x03 << 0) ++#define RG_HTPLL_BC 2 ++#define RG_HTPLL_BC_MASK (0x03 << 2) ++#define RG_HTPLL_BP 4 ++#define RG_HTPLL_BP_MASK (0x0f << 4) ++#define RG_HTPLL_IR 8 ++#define RG_HTPLL_IR_MASK (0x0f << 8) ++#define RG_HTPLL_IC 12 ++#define RG_HTPLL_IC_MASK (0x0f << 12) ++#define RG_HTPLL_POSDIV 16 ++#define RG_HTPLL_POSDIV_MASK (0x03 << 16) ++#define RG_HTPLL_PREDIV 18 ++#define RG_HTPLL_PREDIV_MASK (0x03 << 18) ++#define RG_HTPLL_FBKSEL 20 ++#define RG_HTPLL_FBKSEL_MASK (0x03 << 20) ++#define RG_HTPLL_RLH_EN (0x01 << 22) ++#define RG_HTPLL_FBKDIV 24 ++#define RG_HTPLL_FBKDIV_MASK (0x7f << 24) ++#define RG_HTPLL_EN (0x01 << 31) ++ ++#define HDMI_CON7 0x1c ++#define RG_HTPLL_AUTOK_EN (0x01 << 23) ++#define RG_HTPLL_DIVEN 28 ++#define RG_HTPLL_DIVEN_MASK (0x07 << 28) ++ ++static int mtk_hdmi_pll_prepare(struct clk_hw *hw) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); ++ usleep_range(80, 100); ++ return 0; ++} ++ ++static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); ++ usleep_range(80, 100); ++} ++ ++static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ u32 pos_div; ++ ++ if (rate <= 64000000) ++ pos_div = 3; ++ else if (rate <= 12800000) ++ pos_div = 1; ++ else ++ pos_div = 1; ++ ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_PREDIV_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC), ++ RG_HTPLL_IC_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR), ++ RG_HTPLL_IR_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV), ++ RG_HDMITX_TX_POSDIV_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL), ++ RG_HTPLL_FBKSEL_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV), ++ RG_HTPLL_FBKDIV_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN), ++ RG_HTPLL_DIVEN_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP), ++ RG_HTPLL_BP_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC), ++ RG_HTPLL_BC_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR), ++ RG_HTPLL_BR_MASK); ++ ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PRED_IMP); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS), ++ RG_HDMITX_PRED_IBIAS_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_IMP_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP), ++ RG_HDMITX_DRV_IMP_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK); ++ mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS), ++ RG_HDMITX_DRV_IBIAS_MASK); ++ return 0; ++} ++ ++static const struct clk_ops mtk_hdmi_phy_pll_ops = { ++ .prepare = mtk_hdmi_pll_prepare, ++ .unprepare = mtk_hdmi_pll_unprepare, ++ .set_rate = mtk_hdmi_pll_set_rate, ++ .round_rate = mtk_hdmi_pll_round_rate, ++ .recalc_rate = mtk_hdmi_pll_recalc_rate, ++}; ++ ++static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) ++{ ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); ++ mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); ++ usleep_range(80, 100); ++} ++ ++static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) ++{ ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); ++ usleep_range(80, 100); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); ++ mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); ++ usleep_range(80, 100); ++} ++ ++struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = { ++ .tz_disabled = true, ++ .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, ++ .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, ++ .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, ++}; ++ ++MODULE_AUTHOR("Chunhui Dai "); ++MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0036-drm-mediatek-implement-connection-from-BLS-to-DPI0.patch b/root/target/linux/mediatek/patches-4.19/0036-drm-mediatek-implement-connection-from-BLS-to-DPI0.patch new file mode 100644 index 00000000..ba5d1160 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0036-drm-mediatek-implement-connection-from-BLS-to-DPI0.patch @@ -0,0 +1,58 @@ +From 2ac94b8b6a664bb66404b595da4789687f13bcc4 Mon Sep 17 00:00:00 2001 +From: Bibby Hsieh +Date: Wed, 3 Oct 2018 11:41:50 +0800 +Subject: [PATCH 36/77] drm/mediatek: implement connection from BLS to DPI0 + +Modify display driver to support connection from BLS to DPI. + +Signed-off-by: Bibby Hsieh +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +index 546b3e3b300b..579ce28d801d 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +@@ -39,6 +39,7 @@ + #define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 + #define DISP_REG_CONFIG_OUT_SEL 0x04c + #define DISP_REG_CONFIG_DSI_SEL 0x050 ++#define DISP_REG_CONFIG_DPI_SEL 0x064 + + #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) + #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) +@@ -136,7 +137,10 @@ + + #define OVL_MOUT_EN_RDMA 0x1 + #define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 ++#define BLS_TO_DPI_RDMA1_TO_DSI 0x2 + #define DSI_SEL_IN_BLS 0x0 ++#define DPI_SEL_IN_BLS 0x0 ++#define DSI_SEL_IN_RDMA 0x1 + + struct mtk_disp_mutex { + int id; +@@ -339,9 +343,17 @@ static void mtk_ddp_sout_sel(void __iomem *config_regs, + enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next) + { +- if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) ++ if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { + writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1, + config_regs + DISP_REG_CONFIG_OUT_SEL); ++ } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) { ++ writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI, ++ config_regs + DISP_REG_CONFIG_OUT_SEL); ++ writel_relaxed(DSI_SEL_IN_RDMA, ++ config_regs + DISP_REG_CONFIG_DSI_SEL); ++ writel_relaxed(DPI_SEL_IN_BLS, ++ config_regs + DISP_REG_CONFIG_DPI_SEL); ++ } + } + + void mtk_ddp_add_comp_to_path(void __iomem *config_regs, +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0037-drm-mediatek-add-a-error-return-value-when-clock-dri.patch b/root/target/linux/mediatek/patches-4.19/0037-drm-mediatek-add-a-error-return-value-when-clock-dri.patch new file mode 100644 index 00000000..0693a2d9 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0037-drm-mediatek-add-a-error-return-value-when-clock-dri.patch @@ -0,0 +1,32 @@ +From 4a50f2d17feb0b95488cb3f0769972f01e60209f Mon Sep 17 00:00:00 2001 +From: Bibby Hsieh +Date: Wed, 3 Oct 2018 11:41:51 +0800 +Subject: [PATCH 37/77] drm/mediatek: add a error return value when clock + driver has been prepared + +DRM driver get the comp->clk by of_clk_get(), we only +assign NULL to comp->clk when error happened, but do +not return the error number. + +Signed-off-by: Bibby Hsieh +Reviewed-by: CK Hu +--- + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index ff974d82a4a6..54ca794db3e9 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -294,7 +294,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, + comp->irq = of_irq_get(node, 0); + comp->clk = of_clk_get(node, 0); + if (IS_ERR(comp->clk)) +- comp->clk = NULL; ++ return PTR_ERR(comp->clk); + + /* Only DMA capable components need the LARB property */ + comp->larb_dev = NULL; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0038-drm-mediatek-config-component-output-by-device-node-.patch b/root/target/linux/mediatek/patches-4.19/0038-drm-mediatek-config-component-output-by-device-node-.patch new file mode 100644 index 00000000..831180aa --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0038-drm-mediatek-config-component-output-by-device-node-.patch @@ -0,0 +1,142 @@ +From 9712ba59916d5a7cf568e8ba73d4fba4f2ebfd5f Mon Sep 17 00:00:00 2001 +From: Bibby Hsieh +Date: Fri, 21 Sep 2018 11:28:22 +0800 +Subject: [PATCH 38/77] drm/mediatek: config component output by device node + port + +We can select output component by decive node port. +Main path default output component is DSI. +External path default output component is DPI. + +Signed-off-by: Bibby Hsieh +Signed-off-by: Frank Wunderlich +--- + drivers/gpu/drm/mediatek/mtk_drm_drv.c | 41 ++++++++++++++++++++++---- + drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 +-- + 2 files changed, 37 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +index 6422e99952fe..188b83d63c87 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +@@ -21,7 +21,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + +@@ -133,7 +135,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { + .atomic_commit = mtk_atomic_commit, + }; + +-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_RDMA0, + DDP_COMPONENT_COLOR0, +@@ -141,12 +143,12 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { + DDP_COMPONENT_DSI0, + }; + +-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { + DDP_COMPONENT_RDMA1, + DDP_COMPONENT_DPI0, + }; + +-static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_AAL0, +@@ -156,7 +158,7 @@ static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { + DDP_COMPONENT_PWM0, + }; + +-static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = { + DDP_COMPONENT_OVL1, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_AAL1, +@@ -172,7 +174,7 @@ static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = { + DDP_COMPONENT_PWM2, + }; + +-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_AAL0, +@@ -183,7 +185,7 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { + DDP_COMPONENT_PWM0, + }; + +-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = { + DDP_COMPONENT_OVL1, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_GAMMA, +@@ -472,6 +474,7 @@ static int mtk_drm_probe(struct platform_device *pdev) + + /* Iterate over sibling DISP function blocks */ + for_each_child_of_node(dev->of_node->parent, node) { ++ struct device_node *port, *ep, *remote; + const struct of_device_id *of_id; + enum mtk_ddp_comp_type comp_type; + int comp_id; +@@ -531,6 +534,32 @@ static int mtk_drm_probe(struct platform_device *pdev) + + private->ddp_comp[comp_id] = comp; + } ++ ++ if (comp_type != MTK_DSI && comp_type != MTK_DPI) { ++ port = of_graph_get_port_by_id(node, 0); ++ if (!port) ++ continue; ++ ep = of_get_child_by_name(port, "endpoint"); ++ of_node_put(port); ++ if (!ep) ++ continue; ++ remote = of_graph_get_remote_port_parent(ep); ++ of_node_put(ep); ++ if (!remote) ++ continue; ++ of_id = of_match_node(mtk_ddp_comp_dt_ids, remote); ++ if (!of_id) ++ continue; ++ comp_type = (enum mtk_ddp_comp_type)of_id->data; ++ for (i = 0; i < private->data->main_len - 1; i++) ++ if (private->data->main_path[i] == comp_id) ++ private->data->main_path[i + 1] = ++ mtk_ddp_comp_get_id(node, comp_type); ++ for (i = 0; i < private->data->ext_len - 1; i++) ++ if (private->data->ext_path[i] == comp_id) ++ private->data->ext_path[i + 1] = ++ mtk_ddp_comp_get_id(node, comp_type); ++ } + } + + if (!private->mutex_node) { +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h +index ecc00ca3221d..256a3ff2e66e 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h +@@ -29,9 +29,9 @@ struct drm_property; + struct regmap; + + struct mtk_mmsys_driver_data { +- const enum mtk_ddp_comp_id *main_path; ++ enum mtk_ddp_comp_id *main_path; + unsigned int main_len; +- const enum mtk_ddp_comp_id *ext_path; ++ enum mtk_ddp_comp_id *ext_path; + unsigned int ext_len; + const enum mtk_ddp_comp_id *third_path; + unsigned int third_len; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0039-arm-dts-mt7623-add-a-performance-counter-unit-device.patch b/root/target/linux/mediatek/patches-4.19/0039-arm-dts-mt7623-add-a-performance-counter-unit-device.patch new file mode 100644 index 00000000..8d61ae13 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0039-arm-dts-mt7623-add-a-performance-counter-unit-device.patch @@ -0,0 +1,36 @@ +From 687aeb6d2f7e36d8fffc23b5d767110b79beda59 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 18:22:17 +0800 +Subject: [PATCH 39/77] arm: dts: mt7623: add a performance counter unit device + node + +Add ARM PMU device node to enable hardware perf events. + +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index af6b6228f8a8..d009b50f917e 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -121,6 +121,15 @@ + }; + }; + ++ pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ + system_clk: dummy13m { + compatible = "fixed-clock"; + clock-frequency = <13000000>; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0040-arm-dts-mt7623-update-subsystem-clock-controller-dev.patch b/root/target/linux/mediatek/patches-4.19/0040-arm-dts-mt7623-update-subsystem-clock-controller-dev.patch new file mode 100644 index 00000000..aa075e99 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0040-arm-dts-mt7623-update-subsystem-clock-controller-dev.patch @@ -0,0 +1,76 @@ +From 63b2249cb5ccf8ff0625cd707f243b3e882bc366 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 18:22:18 +0800 +Subject: [PATCH 40/77] arm: dts: mt7623: update subsystem clock controller + device nodes + +Update MT7623 subsystem clock controllers, inlcuding mmsys, imgsys, +vdecsys, g3dsys and bdpsys. + +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 41 +++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index d009b50f917e..35b0fa4112b0 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -729,6 +729,39 @@ + clock-names = "wifi-dma"; + }; + ++ g3dsys: syscon@13000000 { ++ compatible = "mediatek,mt7623-g3dsys", ++ "mediatek,mt2701-g3dsys", ++ "syscon"; ++ reg = <0 0x13000000 0 0x200>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ mmsys: syscon@14000000 { ++ compatible = "mediatek,mt7623-mmsys", ++ "mediatek,mt2701-mmsys", ++ "syscon"; ++ reg = <0 0x14000000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ ++ imgsys: syscon@15000000 { ++ compatible = "mediatek,mt7623-imgsys", ++ "mediatek,mt2701-imgsys", ++ "syscon"; ++ reg = <0 0x15000000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ ++ vdecsys: syscon@16000000 { ++ compatible = "mediatek,mt7623-vdecsys", ++ "mediatek,mt2701-vdecsys", ++ "syscon"; ++ reg = <0 0x16000000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ + hifsys: syscon@1a000000 { + compatible = "mediatek,mt7623-hifsys", + "mediatek,mt2701-hifsys", +@@ -983,6 +1016,14 @@ + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + status = "disabled"; + }; ++ ++ bdpsys: syscon@1c000000 { ++ compatible = "mediatek,mt7623-bdpsys", ++ "mediatek,mt2701-bdpsys", ++ "syscon"; ++ reg = <0 0x1c000000 0 0x1000>; ++ #clock-cells = <1>; ++ }; + }; + + &pio { +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0041-arm-dts-mt7623-add-iommu-smi-device-nodes.patch b/root/target/linux/mediatek/patches-4.19/0041-arm-dts-mt7623-add-iommu-smi-device-nodes.patch new file mode 100644 index 00000000..5a485788 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0041-arm-dts-mt7623-add-iommu-smi-device-nodes.patch @@ -0,0 +1,120 @@ +From d6515baf44e1f6aa4809edf0d0ca314ce9e35a66 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 18:22:19 +0800 +Subject: [PATCH 41/77] arm: dts: mt7623: add iommu/smi device nodes + +Add iommu/smi device nodes for MT7623. + +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 59 +++++++++++++++++++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 35b0fa4112b0..7864c3804377 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -288,6 +289,17 @@ + clock-names = "system-clk", "rtc-clk"; + }; + ++ smi_common: smi@1000c000 { ++ compatible = "mediatek,mt7623-smi-common", ++ "mediatek,mt2701-smi-common"; ++ reg = <0 0x1000c000 0 0x1000>; ++ clocks = <&infracfg CLK_INFRA_SMI>, ++ <&mmsys CLK_MM_SMI_COMMON>, ++ <&infracfg CLK_INFRA_SMI>; ++ clock-names = "apb", "smi", "async"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; ++ }; ++ + pwrap: pwrap@1000d000 { + compatible = "mediatek,mt7623-pwrap", + "mediatek,mt2701-pwrap"; +@@ -319,6 +331,17 @@ + reg = <0 0x10200100 0 0x1c>; + }; + ++ iommu: mmsys_iommu@10205000 { ++ compatible = "mediatek,mt7623-m4u", ++ "mediatek,mt2701-m4u"; ++ reg = <0 0x10205000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_M4U>; ++ clock-names = "bclk"; ++ mediatek,larbs = <&larb0 &larb1 &larb2>; ++ #iommu-cells = <1>; ++ }; ++ + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", + "mediatek,mt8173-efuse"; +@@ -746,6 +769,18 @@ + #clock-cells = <1>; + }; + ++ larb0: larb@14010000 { ++ compatible = "mediatek,mt7623-smi-larb", ++ "mediatek,mt2701-smi-larb"; ++ reg = <0 0x14010000 0 0x1000>; ++ mediatek,smi = <&smi_common>; ++ mediatek,larb-id = <0>; ++ clocks = <&mmsys CLK_MM_SMI_LARB0>, ++ <&mmsys CLK_MM_SMI_LARB0>; ++ clock-names = "apb", "smi"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; ++ }; ++ + imgsys: syscon@15000000 { + compatible = "mediatek,mt7623-imgsys", + "mediatek,mt2701-imgsys", +@@ -754,6 +789,18 @@ + #clock-cells = <1>; + }; + ++ larb2: larb@15001000 { ++ compatible = "mediatek,mt7623-smi-larb", ++ "mediatek,mt2701-smi-larb"; ++ reg = <0 0x15001000 0 0x1000>; ++ mediatek,smi = <&smi_common>; ++ mediatek,larb-id = <2>; ++ clocks = <&imgsys CLK_IMG_SMI_COMM>, ++ <&imgsys CLK_IMG_SMI_COMM>; ++ clock-names = "apb", "smi"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>; ++ }; ++ + vdecsys: syscon@16000000 { + compatible = "mediatek,mt7623-vdecsys", + "mediatek,mt2701-vdecsys", +@@ -762,6 +809,18 @@ + #clock-cells = <1>; + }; + ++ larb1: larb@16010000 { ++ compatible = "mediatek,mt7623-smi-larb", ++ "mediatek,mt2701-smi-larb"; ++ reg = <0 0x16010000 0 0x1000>; ++ mediatek,smi = <&smi_common>; ++ mediatek,larb-id = <1>; ++ clocks = <&vdecsys CLK_VDEC_CKGEN>, ++ <&vdecsys CLK_VDEC_LARB>; ++ clock-names = "apb", "smi"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>; ++ }; ++ + hifsys: syscon@1a000000 { + compatible = "mediatek,mt7623-hifsys", + "mediatek,mt2701-hifsys", +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0042-arm-dts-mt7623-add-jpeg-decoder-device-node.patch b/root/target/linux/mediatek/patches-4.19/0042-arm-dts-mt7623-add-jpeg-decoder-device-node.patch new file mode 100644 index 00000000..66edb33f --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0042-arm-dts-mt7623-add-jpeg-decoder-device-node.patch @@ -0,0 +1,41 @@ +From bd988dc66763555c2aa6509b060fa5b3ceb682a6 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 18:22:20 +0800 +Subject: [PATCH 42/77] arm: dts: mt7623: add jpeg decoder device node + +Add a jpeg decoder device node for MT7623. + +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 7864c3804377..ce9fb23eb5cb 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -801,6 +801,21 @@ + power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>; + }; + ++ jpegdec: jpegdec@15004000 { ++ compatible = "mediatek,mt7623-jpgdec", ++ "mediatek,mt2701-jpgdec"; ++ reg = <0 0x15004000 0 0x1000>; ++ interrupts = ; ++ clocks = <&imgsys CLK_IMG_JPGDEC_SMI>, ++ <&imgsys CLK_IMG_JPGDEC>; ++ clock-names = "jpgdec-smi", ++ "jpgdec"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>; ++ mediatek,larb = <&larb2>; ++ iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>, ++ <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>; ++ }; ++ + vdecsys: syscon@16000000 { + compatible = "mediatek,mt7623-vdecsys", + "mediatek,mt2701-vdecsys", +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0043-arm-dts-mt7623-add-display-subsystem-related-device-.patch b/root/target/linux/mediatek/patches-4.19/0043-arm-dts-mt7623-add-display-subsystem-related-device-.patch new file mode 100644 index 00000000..de1842b4 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0043-arm-dts-mt7623-add-display-subsystem-related-device-.patch @@ -0,0 +1,493 @@ +From c7dbe108de2c9f47f952910f424d1fa9a3470a5b Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 22:09:27 +0800 +Subject: [PATCH 43/77] arm: dts: mt7623: add display subsystem related device + nodes + +Add display subsystem related device nodes for MT7623. + +Cc: CK Hu +Signed-off-by: chunhui dai +Signed-off-by: Bibby Hsieh +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 177 ++++++++++++++++++ + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 85 +++++++++ + arch/arm/boot/dts/mt7623n-rfb-emmc.dts | 85 +++++++++ + 3 files changed, 347 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index ce9fb23eb5cb..619843514d74 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -23,6 +23,11 @@ + #address-cells = <2>; + #size-cells = <2>; + ++ aliases { ++ rdma0 = &rdma0; ++ rdma1 = &rdma1; ++ }; ++ + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; +@@ -313,6 +318,25 @@ + clock-names = "spi", "wrap"; + }; + ++ mipi_tx0: mipi-dphy@10010000 { ++ compatible = "mediatek,mt7623-mipi-tx", ++ "mediatek,mt2701-mipi-tx"; ++ reg = <0 0x10010000 0 0x90>; ++ clocks = <&clk26m>; ++ clock-output-names = "mipi_tx0_pll"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; ++ }; ++ ++ cec: cec@10012000 { ++ compatible = "mediatek,mt7623-cec", ++ "mediatek,mt8173-cec"; ++ reg = <0 0x10012000 0 0xbc>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_CEC>; ++ status = "disabled"; ++ }; ++ + cir: cir@10013000 { + compatible = "mediatek,mt7623-cir"; + reg = <0 0x10013000 0 0x1000>; +@@ -361,6 +385,18 @@ + #clock-cells = <1>; + }; + ++ hdmi_phy: phy@10209100 { ++ compatible = "mediatek,mt7623-hdmi-phy", ++ "mediatek,mt2701-hdmi-phy"; ++ reg = <0 0x10209100 0 0x24>; ++ clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>; ++ clock-names = "pll_ref"; ++ clock-output-names = "hdmitx_dig_cts"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + rng: rng@1020f000 { + compatible = "mediatek,mt7623-rng"; + reg = <0 0x1020f000 0 0x1000>; +@@ -573,6 +609,16 @@ + status = "disabled"; + }; + ++ hdmiddc0: i2c@11013000 { ++ compatible = "mediatek,mt7623-hdmi-ddc", ++ "mediatek,mt8173-hdmi-ddc"; ++ interrupts = ; ++ reg = <0 0x11013000 0 0x1C>; ++ clocks = <&pericfg CLK_PERI_I2C3>; ++ clock-names = "ddc-i2c"; ++ status = "disabled"; ++ }; ++ + nor_flash: spi@11014000 { + compatible = "mediatek,mt7623-nor", + "mediatek,mt8173-nor"; +@@ -769,6 +815,84 @@ + #clock-cells = <1>; + }; + ++ display_components: dispsys@14000000 { ++ compatible = "mediatek,mt7623-mmsys", ++ "mediatek,mt2701-mmsys"; ++ reg = <0 0x14000000 0 0x1000>; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; ++ }; ++ ++ ovl@14007000 { ++ compatible = "mediatek,mt7623-disp-ovl", ++ "mediatek,mt2701-disp-ovl"; ++ reg = <0 0x14007000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_OVL>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_OVL_0>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ rdma0: rdma@14008000 { ++ compatible = "mediatek,mt7623-disp-rdma", ++ "mediatek,mt2701-disp-rdma"; ++ reg = <0 0x14008000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_RDMA>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ wdma@14009000 { ++ compatible = "mediatek,mt7623-disp-wdma", ++ "mediatek,mt2701-disp-wdma"; ++ reg = <0 0x14009000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_WDMA>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_WDMA>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ bls: pwm@1400a000 { ++ compatible = "mediatek,mt7623-disp-pwm", ++ "mediatek,mt2701-disp-pwm"; ++ reg = <0 0x1400a000 0 0x1000>; ++ #pwm-cells = <2>; ++ clocks = <&mmsys CLK_MM_MDP_BLS_26M>, ++ <&mmsys CLK_MM_DISP_BLS>; ++ clock-names = "main", "mm"; ++ status = "disabled"; ++ }; ++ ++ color@1400b000 { ++ compatible = "mediatek,mt7623-disp-color", ++ "mediatek,mt2701-disp-color"; ++ reg = <0 0x1400b000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_COLOR>; ++ }; ++ ++ dsi: dsi@1400c000 { ++ compatible = "mediatek,mt7623-dsi", ++ "mediatek,mt2701-dsi"; ++ reg = <0 0x1400c000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DSI_ENGINE>, ++ <&mmsys CLK_MM_DSI_DIG>, ++ <&mipi_tx0>; ++ clock-names = "engine", "digital", "hs"; ++ phys = <&mipi_tx0>; ++ phy-names = "dphy"; ++ status = "disabled"; ++ }; ++ ++ mutex: mutex@1400e000 { ++ compatible = "mediatek,mt7623-disp-mutex", ++ "mediatek,mt2701-disp-mutex"; ++ reg = <0 0x1400e000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_MUTEX_32K>; ++ }; ++ + larb0: larb@14010000 { + compatible = "mediatek,mt7623-smi-larb", + "mediatek,mt2701-smi-larb"; +@@ -781,6 +905,44 @@ + power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; + }; + ++ rdma1: rdma@14012000 { ++ compatible = "mediatek,mt7623-disp-rdma", ++ "mediatek,mt2701-disp-rdma"; ++ reg = <0 0x14012000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_RDMA1>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA1>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ dpi0: dpi@14014000 { ++ compatible = "mediatek,mt7623-dpi", ++ "mediatek,mt2701-dpi"; ++ reg = <0 0x14014000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DPI1_DIGL>, ++ <&mmsys CLK_MM_DPI1_ENGINE>, ++ <&topckgen CLK_TOP_TVDPLL>; ++ clock-names = "pixel", "engine", "pll"; ++ status = "disabled"; ++ }; ++ ++ hdmi0: hdmi@14015000 { ++ compatible = "mediatek,mt7623-hdmi", ++ "mediatek,mt8173-hdmi"; ++ reg = <0 0x14015000 0 0x400>; ++ clocks = <&mmsys CLK_MM_HDMI_PIXEL>, ++ <&mmsys CLK_MM_HDMI_PLL>, ++ <&mmsys CLK_MM_HDMI_AUDIO>, ++ <&mmsys CLK_MM_HDMI_SPDIF>; ++ clock-names = "pixel", "pll", "bclk", "spdif"; ++ phys = <&hdmi_phy>; ++ phy-names = "hdmi"; ++ mediatek,syscon-hdmi = <&mmsys 0x900>; ++ cec = <&cec>; ++ status = "disabled"; ++ }; ++ + imgsys: syscon@15000000 { + compatible = "mediatek,mt7623-imgsys", + "mediatek,mt2701-imgsys", +@@ -1108,6 +1270,21 @@ + }; + }; + ++ hdmi_pins_a: hdmi-default { ++ pins-hdmi { ++ pinmux = ; ++ input-enable; ++ bias-pull-down; ++ }; ++ }; ++ ++ hdmi_ddc_pins_a: hdmi_ddc-default { ++ pins-hdmi-ddc { ++ pinmux = , ++ ; ++ }; ++ }; ++ + i2c0_pins_a: i2c0-default { + pins-i2c0 { + pinmux = , +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 4c6e53d9e736..d97edde586ad 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -22,6 +22,19 @@ + stdout-path = "serial2:115200n8"; + }; + ++ connector { ++ compatible = "hdmi-connector"; ++ label = "hdmi"; ++ type = "d"; ++ ddc-i2c-bus = <&hdmiddc0>; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi0_out>; ++ }; ++ }; ++ }; ++ + cpus { + cpu@0 { + proc-supply = <&mt6323_vproc_reg>; +@@ -127,10 +140,24 @@ + }; + }; + ++&bls { ++ status = "okay"; ++ ++ port { ++ bls_out: endpoint { ++ remote-endpoint = <&dpi0_in>; ++ }; ++ }; ++}; ++ + &btif { + status = "okay"; + }; + ++&cec { ++ status = "okay"; ++}; ++ + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&cir_pins_a>; +@@ -141,6 +168,28 @@ + status = "okay"; + }; + ++&dpi0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ dpi0_out: endpoint { ++ remote-endpoint = <&hdmi0_in>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dpi0_in: endpoint { ++ remote-endpoint = <&bls_out>; ++ }; ++ }; ++ }; ++}; ++ + ð { + status = "okay"; + +@@ -240,6 +289,42 @@ + }; + }; + ++&hdmi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_pins_a>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ hdmi0_in: endpoint { ++ remote-endpoint = <&dpi0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ hdmi0_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmiddc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_ddc_pins_a>; ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ mediatek,ibias = <0xa>; ++ mediatek,ibias_up = <0x1c>; ++ status = "okay"; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; +diff --git a/arch/arm/boot/dts/mt7623n-rfb-emmc.dts b/arch/arm/boot/dts/mt7623n-rfb-emmc.dts +index b7606130ade9..3e5911d8d6bc 100644 +--- a/arch/arm/boot/dts/mt7623n-rfb-emmc.dts ++++ b/arch/arm/boot/dts/mt7623n-rfb-emmc.dts +@@ -24,6 +24,19 @@ + stdout-path = "serial2:115200n8"; + }; + ++ connector { ++ compatible = "hdmi-connector"; ++ label = "hdmi"; ++ type = "d"; ++ ddc-i2c-bus = <&hdmiddc0>; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi0_out>; ++ }; ++ }; ++ }; ++ + cpus { + cpu@0 { + proc-supply = <&mt6323_vproc_reg>; +@@ -106,10 +119,24 @@ + }; + }; + ++&bls { ++ status = "okay"; ++ ++ port { ++ bls_out: endpoint { ++ remote-endpoint = <&dpi0_in>; ++ }; ++ }; ++}; ++ + &btif { + status = "okay"; + }; + ++&cec { ++ status = "okay"; ++}; ++ + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&cir_pins_a>; +@@ -120,6 +147,28 @@ + status = "okay"; + }; + ++&dpi0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ dpi0_out: endpoint { ++ remote-endpoint = <&hdmi0_in>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dpi0_in: endpoint { ++ remote-endpoint = <&bls_out>; ++ }; ++ }; ++ }; ++}; ++ + ð { + status = "okay"; + +@@ -202,6 +251,42 @@ + }; + }; + ++&hdmi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_pins_a>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ hdmi0_in: endpoint { ++ remote-endpoint = <&dpi0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ hdmi0_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmiddc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_ddc_pins_a>; ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ mediatek,ibias = <0xa>; ++ mediatek,ibias_up = <0x1c>; ++ status = "okay"; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0044-fix-boot-up-for-720-and-480-but-1080.patch b/root/target/linux/mediatek/patches-4.19/0044-fix-boot-up-for-720-and-480-but-1080.patch new file mode 100644 index 00000000..71dfebd4 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0044-fix-boot-up-for-720-and-480-but-1080.patch @@ -0,0 +1,72 @@ +From fa095b2751309a70d42d9d2f2f0881731b090d18 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 31 Oct 2018 16:59:34 +0800 +Subject: [PATCH 44/77] fix boot up for 720 and 480 but 1080 + +1080 plg in/out with ng/ok + +[ALPSxxxxxxxx] + +[Detail] + +[Solution] + +Change-Id: Icd395eaf635a6cfe03f8f0508ed97ab40cbf6632 +CR-Id: +Feature: +--- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 3 +++ + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 1 + + drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 3 ++- + 3 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +index 4ef9c57ffd44..40e08df57f48 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +@@ -209,6 +209,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) + return PTR_ERR(phy_provider); + } + ++ if (hdmi_phy->conf->pll_default_off) ++ hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); ++ + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, + hdmi_phy->pll); + } +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +index f39b1fc66612..a173a27d7a40 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +@@ -21,6 +21,7 @@ struct mtk_hdmi_phy; + + struct mtk_hdmi_phy_conf { + bool tz_disabled; ++ bool pll_default_off; + const struct clk_ops *hdmi_phy_clk_ops; + void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); + void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); +diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +index fcc42dc6ea7f..534bcbc9f3b7 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +@@ -116,7 +116,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + + if (rate <= 64000000) + pos_div = 3; +- else if (rate <= 12800000) ++ else if (rate <= 128000000) + pos_div = 1; + else + pos_div = 1; +@@ -202,6 +202,7 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) + + struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = { + .tz_disabled = true, ++ .pll_default_off = true, + .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, + .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, + .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0045-using-different-round-rate-for-mt7623.patch b/root/target/linux/mediatek/patches-4.19/0045-using-different-round-rate-for-mt7623.patch new file mode 100644 index 00000000..5b2214a5 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0045-using-different-round-rate-for-mt7623.patch @@ -0,0 +1,103 @@ +From 4501501b8f55b277f219eaf7e863d91ddb1d8af7 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 31 Oct 2018 17:59:50 +0800 +Subject: [PATCH 45/77] using different round rate for mt7623 + +Change-Id: Ifac315b09d691fe2c056212dd59ae50212417d58 +CR-Id: +Feature: +--- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 14 -------------- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 2 -- + drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 11 +++++++++++ + drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 14 ++++++++++++++ + 4 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +index 40e08df57f48..f014d65fa5ad 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +@@ -15,20 +15,6 @@ static const struct phy_ops mtk_hdmi_phy_dev_ops = { + .owner = THIS_MODULE, + }; + +-long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long *parent_rate) +-{ +- struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); +- +- hdmi_phy->pll_rate = rate; +- if (rate <= 74250000) +- *parent_rate = rate; +- else +- *parent_rate = rate / 2; +- +- return rate; +-} +- + unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +index a173a27d7a40..76e352d088d0 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +@@ -49,8 +49,6 @@ void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 val, u32 mask); + struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); +-long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long *parent_rate); + unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); + +diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +index 534bcbc9f3b7..2f87d0320882 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +@@ -154,6 +154,17 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + ++static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ hdmi_phy->pll_rate = rate; ++ *parent_rate = rate; ++ ++ return rate; ++} ++ + static const struct clk_ops mtk_hdmi_phy_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, +diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +index ed5916b27658..d8cb252c6781 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +@@ -285,6 +285,20 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + ++static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); ++ ++ hdmi_phy->pll_rate = rate; ++ if (rate <= 74250000) ++ *parent_rate = rate; ++ else ++ *parent_rate = rate / 2; ++ ++ return rate; ++} ++ + static const struct clk_ops mtk_hdmi_phy_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0046-hdmi-fix-possible_crtcs.patch b/root/target/linux/mediatek/patches-4.19/0046-hdmi-fix-possible_crtcs.patch new file mode 100644 index 00000000..284ced83 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0046-hdmi-fix-possible_crtcs.patch @@ -0,0 +1,26 @@ +From 1c978fae6f6112b46d4815c0054fbeab0274a363 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Fri, 16 Nov 2018 16:33:00 +0100 +Subject: [PATCH 46/77] [hdmi] fix possible_crtcs + +source: http://forum.banana-pi.org/t/kernel-4-19-rc1-for-testers/6618/52 +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 62a9d47df948..a066b0755119 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -610,7 +610,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) + drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs); + + /* Currently DPI0 is fixed to be driven by OVL1 */ +- dpi->encoder.possible_crtcs = BIT(1); ++ dpi->encoder.possible_crtcs = BIT(0)|BIT(1); + + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL); + if (ret) { +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0047-hdmi-added-options-to-defconfig.patch b/root/target/linux/mediatek/patches-4.19/0047-hdmi-added-options-to-defconfig.patch new file mode 100644 index 00000000..4e173116 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0047-hdmi-added-options-to-defconfig.patch @@ -0,0 +1,31 @@ +From 88aa4bffe7e5b38e8596e5f09e7b40e8bc112a24 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 16 Nov 2018 16:40:16 +0100 +Subject: [PATCH 47/77] [hdmi] added options to defconfig + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index f5e7a0edda0e..5932b552f2ea 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -652,3 +652,14 @@ CONFIG_POWER_RESET_MT6397_RTC=y + + #CONFIG_NET_MEDIATEK_HW_QOS=m + ++#Graphic ++CONFIG_DRM=y ++CONFIG_DRM_MEDIATEK=y ++CONFIG_DRM_MEDIATEK_HDMI=y ++CONFIG_DRM_ARM=y ++CONFIG_DRM_MALI_DISPLAY=y ++CONFIG_COMMON_CLK_MT2701_MMSYS=y ++CONFIG_COMMON_CLK_MT2701_IMGSYS=y ++CONFIG_COMMON_CLK_MT2701_VDECSYS=y ++#CONFIG_FRAMEBUFFER_CONSOLE=y ++#CONFIG_DRM_FBDEV_EMULATION=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0049-hdmi-added-fbdev-options.patch b/root/target/linux/mediatek/patches-4.19/0049-hdmi-added-fbdev-options.patch new file mode 100644 index 00000000..4ca5483f --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0049-hdmi-added-fbdev-options.patch @@ -0,0 +1,24 @@ +From 7d0222b1fd42f22f0590b71c0e42660974c492d2 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 16 Nov 2018 17:27:50 +0100 +Subject: [PATCH 49/77] [hdmi] added fbdev-options + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 5932b552f2ea..668a6c45177d 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -661,5 +661,5 @@ CONFIG_DRM_MALI_DISPLAY=y + CONFIG_COMMON_CLK_MT2701_MMSYS=y + CONFIG_COMMON_CLK_MT2701_IMGSYS=y + CONFIG_COMMON_CLK_MT2701_VDECSYS=y +-#CONFIG_FRAMEBUFFER_CONSOLE=y +-#CONFIG_DRM_FBDEV_EMULATION=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_DRM_FBDEV_EMULATION=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0050-BT-fix-Bluetooth.patch b/root/target/linux/mediatek/patches-4.19/0050-BT-fix-Bluetooth.patch new file mode 100644 index 00000000..e3f7ee41 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0050-BT-fix-Bluetooth.patch @@ -0,0 +1,69 @@ +From c0603006d7f020bbcb42bed36127fbfe94b1b512 Mon Sep 17 00:00:00 2001 +From: Oleksii Shevchuk +Date: Fri, 11 Jan 2019 18:34:01 +0100 +Subject: [PATCH 50/77] [BT] fix Bluetooth +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +- first call wifi.sh or at least call + wmt_loader + stp-uart-launcher +- then load BT-module “modprobe stp_chrdev_bt” +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 4 ++-- + .../common/common_detect/drv_init/bluetooth_drv_init.c | 3 ++- + .../connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c | 3 ++- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 668a6c45177d..343800fc24d6 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -390,8 +390,8 @@ CONFIG_NL80211_TESTMODE=y + + #internal Bluetooth (also not working yet) + CONFIG_BT=y +-#CONFIG_MTK_COMBO_BT=y +-#CONFIG_MTK_COMBO_BT_HCI=y ++CONFIG_MTK_COMBO_BT=m ++CONFIG_MTK_COMBO_BT_HCI=y + #needed for BT? + #Bluetooth Classic (BR/EDR) features + CONFIG_BT_BREDR=y +diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +index 47b055433443..82b799f256b4 100644 +--- a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c ++++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c +@@ -23,13 +23,14 @@ + int do_bluetooth_drv_init(int chip_id) + { + int i_ret = -1; +- ++#if 0 + #if defined(CONFIG_MTK_COMBO_BT) || defined(CONFIG_MTK_COMBO_BT_HCI) + WMT_DETECT_INFO_FUNC("start to do bluetooth driver init\n"); + i_ret = mtk_wcn_stpbt_drv_init(); + WMT_DETECT_INFO_FUNC("finish bluetooth driver init, i_ret:%d\n", i_ret); + #else + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_BT is not defined\n"); ++#endif + #endif + return i_ret; + } +diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +index 190fa3944d80..5a85f68b092f 100644 +--- a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c ++++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c +@@ -877,7 +877,8 @@ static void BT_exit(void) + BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); + } + +-#ifdef MTK_WCN_REMOVE_KERNEL_MODULE ++#if 0 ++//#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + + int mtk_wcn_stpbt_drv_init(void) + { +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0053-defconfig-disable-some-debug-messages-evbug-gpio.patch b/root/target/linux/mediatek/patches-4.19/0053-defconfig-disable-some-debug-messages-evbug-gpio.patch new file mode 100644 index 00000000..7e2e22d2 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0053-defconfig-disable-some-debug-messages-evbug-gpio.patch @@ -0,0 +1,34 @@ +From 32d96a7e0127ae64f4c091e8c14f2961619f4fa2 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 20 Jan 2019 13:23:22 +0100 +Subject: [PATCH 53/77] [defconfig] disable some debug-messages (evbug,gpio) + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 343800fc24d6..2a9696b249e9 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -223,7 +223,7 @@ CONFIG_NET_MEDIATEK_SOC=y + + CONFIG_ICPLUS_PHY=y + CONFIG_INPUT_EVDEV=y +-CONFIG_INPUT_EVBUG=m ++#CONFIG_INPUT_EVBUG=m + CONFIG_KEYBOARD_MATRIX=y + CONFIG_KEYBOARD_SAMSUNG=y + CONFIG_KEYBOARD_MTK_PMIC=m +@@ -370,7 +370,7 @@ CONFIG_BTRFS_FS=m + + #GPIO + CONFIG_DEBUG_FS=y +-CONFIG_DEBUG_GPIO=y ++#CONFIG_DEBUG_GPIO=y + CONFIG_GPIO_SYSFS=y + + #wlan +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0058-defconfig-add-multiple-routing-tables-for-IPv4.patch b/root/target/linux/mediatek/patches-4.19/0058-defconfig-add-multiple-routing-tables-for-IPv4.patch new file mode 100644 index 00000000..56f9cd2d --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0058-defconfig-add-multiple-routing-tables-for-IPv4.patch @@ -0,0 +1,25 @@ +From 04b3085371657fe44d7949168de9a080c61b1607 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 25 Jan 2019 15:08:26 +0100 +Subject: [PATCH 58/77] [defconfig] add multiple routing-tables for IPv4 + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 2a9696b249e9..16fbafbea0c3 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -101,6 +101,8 @@ CONFIG_DUMMY=m + CONFIG_PACKET=y + CONFIG_UNIX=y + CONFIG_INET=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y + CONFIG_IP_PNP=y + CONFIG_IP_PNP_DHCP=y + CONFIG_IP_PNP_BOOTP=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0059-defconfig-added-options-for-Traffic-Shaping.patch b/root/target/linux/mediatek/patches-4.19/0059-defconfig-added-options-for-Traffic-Shaping.patch new file mode 100644 index 00000000..22ade4c8 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0059-defconfig-added-options-for-Traffic-Shaping.patch @@ -0,0 +1,33 @@ +From 4ca583e03d89abdab30393529e048d5fadcffb2b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 25 Jan 2019 15:53:58 +0100 +Subject: [PATCH 59/77] [defconfig] added options for Traffic Shaping + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 16fbafbea0c3..cd86a013b161 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -98,6 +98,7 @@ CONFIG_APM_EMULATION=y + + CONFIG_NET=y + CONFIG_DUMMY=m ++CONFIG_IFB=m + CONFIG_PACKET=y + CONFIG_UNIX=y + CONFIG_INET=y +@@ -525,6 +526,8 @@ CONFIG_NET_SCH_GRED=m + CONFIG_NET_SCH_DSMARK=m + CONFIG_NET_SCH_INGRESS=m + CONFIG_NET_SCH_NETEM=m ++CONFIG_NET_SCH_FQ_CODEL=m ++CONFIG_NET_ACT_MIRRED=m + CONFIG_NET_QOS=y + CONFIG_NET_ESTIMATOR=y + CONFIG_NET_CLS=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0061-defconfig-add-nftables.patch b/root/target/linux/mediatek/patches-4.19/0061-defconfig-add-nftables.patch new file mode 100644 index 00000000..f3a725b3 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0061-defconfig-add-nftables.patch @@ -0,0 +1,60 @@ +From ac6c3841de57124c49f95da9f50448a82070cce3 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 8 Feb 2019 16:27:44 +0100 +Subject: [PATCH 61/77] [defconfig] add nftables + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 37 ++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index cd86a013b161..6ec6625102b3 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -179,6 +179,43 @@ CONFIG_IP_VS=m + CONFIG_NETFILTER_XT_MATCH_IPVS=m + CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m + ++CONFIG_NF_TABLES=m ++CONFIG_NF_TABLES_IPV4=y ++CONFIG_NF_TABLES_IPV6=y ++CONFIG_NF_TABLES_INET=y ++CONFIG_NF_TABLES_NETDEV=y ++CONFIG_NFT_NUMGEN=m ++CONFIG_NFT_CT=m ++CONFIG_NFT_COUNTER=m ++CONFIG_NFT_CONNLIMIT=m ++CONFIG_NFT_LOG=m ++CONFIG_NFT_LIMIT=m ++CONFIG_NFT_MASQ=m ++CONFIG_NFT_MASQ_IPV4=m ++CONFIG_NFT_REDIR=m ++CONFIG_NFT_NAT=m ++CONFIG_NFT_CHAIN_NAT_IPV4=m ++CONFIG_NFT_TUNNEL=m ++CONFIG_NFT_OBJREF=m ++CONFIG_NFT_QUOTA=m ++CONFIG_NFT_REJECT=m ++CONFIG_NFT_COMPAT=m ++CONFIG_NFT_HASH=m ++CONFIG_NFT_SOCKET=m ++CONFIG_NFT_OSF=m ++CONFIG_NFT_TPROXY=m ++CONFIG_NFT_QUEUE=m ++CONFIG_NFT_FIB_IPV4=m ++CONFIG_NFT_FIB_IPV6=m ++CONFIG_NFT_FIB_INET=m ++CONFIG_NFT_FIB_NETDEV=m ++CONFIG_NFT_FLOW_OFFLOAD=m ++CONFIG_NFT_FWD_NETDEV=m ++CONFIG_NFT_REDIR_IPV4=m ++CONFIG_NFT_REDIR_IPV6=m ++CONFIG_NFT_CHAIN_ROUTE_IPV4=m ++CONFIG_NFT_CHAIN_ROUTE_IPV6=m ++ + CONFIG_NET_MEDIATEK_HNAT=m + CONFIG_DEBUG_SECTION_MISMATCH=y + +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0063-defconfig-add-all-XT-matches-targets.patch b/root/target/linux/mediatek/patches-4.19/0063-defconfig-add-all-XT-matches-targets.patch new file mode 100644 index 00000000..e6532ba2 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0063-defconfig-add-all-XT-matches-targets.patch @@ -0,0 +1,100 @@ +From 56aa779864c232422984341490eb1bb96259efe0 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 16 Feb 2019 09:39:43 +0100 +Subject: [PATCH 63/77] [defconfig] add all XT-matches/targets + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 71 +++++++++++++++++++--- + 1 file changed, 62 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 6ec6625102b3..660b4c234ad2 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -163,21 +163,74 @@ CONFIG_NETFILTER_SYNPROXY=m + CONFIG_IP_NF_TARGET_SYNPROXY=m + CONFIG_IP6_NF_TARGET_SYNPROXY=m + ++CONFIG_IP_VS=m ++ + CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +-CONFIG_NETFILTER_XT_MATCH_LIMIT=m +-CONFIG_NETFILTER_XT_MATCH_STATE=m ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m ++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m ++CONFIG_NETFILTER_XT_TARGET_DSCP=m ++CONFIG_NETFILTER_XT_TARGET_HL=m ++CONFIG_NETFILTER_XT_TARGET_HMARK=m ++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m ++CONFIG_NETFILTER_XT_TARGET_LED=m + CONFIG_NETFILTER_XT_TARGET_LOG=m ++CONFIG_NETFILTER_XT_TARGET_MARK=m ++CONFIG_NETFILTER_XT_TARGET_NETMAP=m ++CONFIG_NETFILTER_XT_TARGET_NFLOG=m ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m ++CONFIG_NETFILTER_XT_TARGET_RATEEST=m ++CONFIG_NETFILTER_XT_TARGET_REDIRECT=m ++CONFIG_NETFILTER_XT_TARGET_TEE=m ++CONFIG_NETFILTER_XT_TARGET_TPROXY=m ++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m + CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m ++# Xtables matches ++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m ++CONFIG_NETFILTER_XT_MATCH_BPF=m ++CONFIG_NETFILTER_XT_MATCH_CGROUP=m ++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m ++CONFIG_NETFILTER_XT_MATCH_COMMENT=m ++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m ++CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m + CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +-CONFIG_NETFILTER_XT_MATCH_MAC=m +-CONFIG_NETFILTER_XT_MATCH_RECENT=m ++CONFIG_NETFILTER_XT_MATCH_CPU=m ++CONFIG_NETFILTER_XT_MATCH_DCCP=m ++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m ++CONFIG_NETFILTER_XT_MATCH_DSCP=m ++CONFIG_NETFILTER_XT_MATCH_ECN=m ++CONFIG_NETFILTER_XT_MATCH_ESP=m ++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_HELPER=m ++CONFIG_NETFILTER_XT_MATCH_HL=m ++CONFIG_NETFILTER_XT_MATCH_IPCOMP=m + CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +-CONFIG_NETFILTER_XT_MARK=m +-CONFIG_NETFILTER_XT_CONNMARK=m +-CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +-CONFIG_IP_VS=m + CONFIG_NETFILTER_XT_MATCH_IPVS=m +-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_L2TP=m ++CONFIG_NETFILTER_XT_MATCH_LENGTH=m ++CONFIG_NETFILTER_XT_MATCH_LIMIT=m ++CONFIG_NETFILTER_XT_MATCH_MAC=m ++CONFIG_NETFILTER_XT_MATCH_MARK=m ++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m ++CONFIG_NETFILTER_XT_MATCH_NFACCT=m ++CONFIG_NETFILTER_XT_MATCH_OSF=m ++CONFIG_NETFILTER_XT_MATCH_OWNER=m ++CONFIG_NETFILTER_XT_MATCH_POLICY=m ++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m ++CONFIG_NETFILTER_XT_MATCH_QUOTA=m ++CONFIG_NETFILTER_XT_MATCH_RATEEST=m ++CONFIG_NETFILTER_XT_MATCH_REALM=m ++CONFIG_NETFILTER_XT_MATCH_RECENT=m ++CONFIG_NETFILTER_XT_MATCH_SCTP=m ++CONFIG_NETFILTER_XT_MATCH_STATE=m ++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m ++CONFIG_NETFILTER_XT_MATCH_STRING=m ++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m ++CONFIG_NETFILTER_XT_MATCH_TIME=m ++CONFIG_NETFILTER_XT_MATCH_U32=m ++ + + CONFIG_NF_TABLES=m + CONFIG_NF_TABLES_IPV4=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0064-dsa-fix-oops-in-br_vlan_enabled.patch b/root/target/linux/mediatek/patches-4.19/0064-dsa-fix-oops-in-br_vlan_enabled.patch new file mode 100644 index 00000000..ff38a894 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0064-dsa-fix-oops-in-br_vlan_enabled.patch @@ -0,0 +1,34 @@ +From 769d236f61e884cc24897f23ede001744a77a469 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 16 Feb 2019 17:26:51 +0100 +Subject: [PATCH 64/77] [dsa] fix oops in br_vlan_enabled + +--- + net/dsa/port.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/dsa/port.c b/net/dsa/port.c +index ed0595459df1..0891c6f554dc 100644 +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -255,7 +255,7 @@ int dsa_port_vlan_add(struct dsa_port *dp, + if (netif_is_bridge_master(vlan->obj.orig_dev)) + return -EOPNOTSUPP; + +- if (br_vlan_enabled(dp->bridge_dev)) ++ if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev)) + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); + + return 0; +@@ -273,7 +273,7 @@ int dsa_port_vlan_del(struct dsa_port *dp, + if (netif_is_bridge_master(vlan->obj.orig_dev)) + return -EOPNOTSUPP; + +- if (br_vlan_enabled(dp->bridge_dev)) ++ if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev)) + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); + + return 0; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0066-defconfig-enable-mt76x2.patch b/root/target/linux/mediatek/patches-4.19/0066-defconfig-enable-mt76x2.patch new file mode 100644 index 00000000..329d9bd2 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0066-defconfig-enable-mt76x2.patch @@ -0,0 +1,25 @@ +From b0ff7f6f16836ac39eb8a66f3cee3d7cee7cd3fc Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 17 Feb 2019 18:02:51 +0100 +Subject: [PATCH 66/77] [defconfig] enable mt76x2 + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 660b4c234ad2..44b34cac3614 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -506,7 +506,7 @@ CONFIG_RFKILL_INPUT=y + CONFIG_RFKILL_GPIO=y + + #if you use a mt76x2 or mt76x3 pcie-card +-#CONFIG_MT76=m ++CONFIG_MT76x2E=m + + #pcie + CONFIG_PCIEPORTBUS=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0067-dsa-fix-from-florian.patch b/root/target/linux/mediatek/patches-4.19/0067-dsa-fix-from-florian.patch new file mode 100644 index 00000000..383766be --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0067-dsa-fix-from-florian.patch @@ -0,0 +1,34 @@ +From 4b2f75faab7f63d9cbddd99080632a8767cda28c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 19 Feb 2019 17:25:57 +0100 +Subject: [PATCH 67/77] [dsa] fix from florian + +--- + net/dsa/port.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/dsa/port.c b/net/dsa/port.c +index 0891c6f554dc..792a13068c50 100644 +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -255,7 +255,7 @@ int dsa_port_vlan_add(struct dsa_port *dp, + if (netif_is_bridge_master(vlan->obj.orig_dev)) + return -EOPNOTSUPP; + +- if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev)) ++ if (dp->bridge_dev && br_vlan_enabled(dp->bridge_dev)) + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); + + return 0; +@@ -273,7 +273,7 @@ int dsa_port_vlan_del(struct dsa_port *dp, + if (netif_is_bridge_master(vlan->obj.orig_dev)) + return -EOPNOTSUPP; + +- if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev)) ++ if (dp->bridge_dev && br_vlan_enabled(dp->bridge_dev)) + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); + + return 0; +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0068-defconfig-add-atheros-wireless-lan-9k-10k-support.patch b/root/target/linux/mediatek/patches-4.19/0068-defconfig-add-atheros-wireless-lan-9k-10k-support.patch new file mode 100644 index 00000000..442b9c5a --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0068-defconfig-add-atheros-wireless-lan-9k-10k-support.patch @@ -0,0 +1,35 @@ +From 9cbdef979d2119a250d4b8724b247f2a4cad899c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Wed, 20 Feb 2019 17:29:38 +0100 +Subject: [PATCH 68/77] [defconfig] add atheros wireless lan 9k/10k support + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index 44b34cac3614..ad85e0d37e3f 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -630,9 +630,17 @@ CONFIG_NET_CLS_RSVP=m + CONFIG_NET_CLS_RSVP6=m + CONFIG_NET_CLS_POLICE=y + ++CONFIG_WLAN_VENDOR_ATH=y ++CONFIG_ATH9K=m ++CONFIG_ATH9K_PCI=y ++CONFIG_ATH9K_RFKILL=y ++CONFIG_ATH9K_HWRNG=y ++CONFIG_ATH10K=m ++CONFIG_ATH10K_PCI=m ++ ++ + #unused drivers which are set by default + CONFIG_WLAN_VENDOR_ADMTEK=n +-CONFIG_WLAN_VENDOR_ATH=n + CONFIG_WLAN_VENDOR_ATMEL=n + CONFIG_WLAN_VENDOR_BROADCOM=n + CONFIG_WLAN_VENDOR_CISCO=n +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0072-defconfig-add-ebtables.patch b/root/target/linux/mediatek/patches-4.19/0072-defconfig-add-ebtables.patch new file mode 100644 index 00000000..43390eae --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0072-defconfig-add-ebtables.patch @@ -0,0 +1,47 @@ +From e5c7c5e17a52863ff61fa7f8cdee9c8c4ae036ec Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 8 Mar 2019 17:17:41 +0100 +Subject: [PATCH 72/77] [defconfig] add ebtables + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 24 ++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index ad85e0d37e3f..b49b5feee3eb 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -269,6 +269,30 @@ CONFIG_NFT_REDIR_IPV6=m + CONFIG_NFT_CHAIN_ROUTE_IPV4=m + CONFIG_NFT_CHAIN_ROUTE_IPV6=m + ++#ebtables ++CONFIG_NF_TABLES_BRIDGE=y ++CONFIG_BRIDGE_NF_EBTABLES=m ++CONFIG_BRIDGE_EBT_BROUTE=m ++CONFIG_BRIDGE_EBT_T_FILTER=m ++CONFIG_BRIDGE_EBT_T_NAT=m ++CONFIG_BRIDGE_EBT_802_3=m ++CONFIG_BRIDGE_EBT_AMONG=m ++CONFIG_BRIDGE_EBT_ARP=m ++CONFIG_BRIDGE_EBT_IP=m ++CONFIG_BRIDGE_EBT_IP6=m ++CONFIG_BRIDGE_EBT_LIMIT=m ++CONFIG_BRIDGE_EBT_MARK=m ++CONFIG_BRIDGE_EBT_PKTTYPE=m ++CONFIG_BRIDGE_EBT_STP=m ++CONFIG_BRIDGE_EBT_VLAN=m ++CONFIG_BRIDGE_EBT_ARPREPLY=m ++CONFIG_BRIDGE_EBT_DNAT=m ++CONFIG_BRIDGE_EBT_MARK_T=m ++CONFIG_BRIDGE_EBT_REDIRECT=m ++CONFIG_BRIDGE_EBT_SNAT=m ++CONFIG_BRIDGE_EBT_LOG=m ++CONFIG_BRIDGE_EBT_NFLOG=m ++ + CONFIG_NET_MEDIATEK_HNAT=m + CONFIG_DEBUG_SECTION_MISMATCH=y + +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0074-add-compiler-gcc8.h.patch b/root/target/linux/mediatek/patches-4.19/0074-add-compiler-gcc8.h.patch new file mode 100644 index 00000000..7d993c37 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0074-add-compiler-gcc8.h.patch @@ -0,0 +1,78 @@ +From f290d46885f04adeed948a332ff333e258fb6868 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Wed, 20 Mar 2019 17:29:14 +0100 +Subject: [PATCH 74/77] add compiler-gcc8.h + +--- + include/linux/compiler-gcc8.h | 59 +++++++++++++++++++++++++++++++++++ + 1 file changed, 59 insertions(+) + create mode 100644 include/linux/compiler-gcc8.h + +diff --git a/include/linux/compiler-gcc8.h b/include/linux/compiler-gcc8.h +new file mode 100644 +index 000000000000..eecd5e1fd781 +--- /dev/null ++++ b/include/linux/compiler-gcc8.h +@@ -0,0 +1,59 @@ ++#ifndef __LINUX_COMPILER_H ++#error "Please don't include directly, include instead." ++#endif ++ ++#define __used __attribute__((__used__)) ++#define __must_check __attribute__((warn_unused_result)) ++#define __compiler_offsetof(a, b) __builtin_offsetof(a, b) ++ ++/* Mark functions as cold. gcc will assume any path leading to a call ++ to them will be unlikely. This means a lot of manual unlikely()s ++ are unnecessary now for any paths leading to the usual suspects ++ like BUG(), printk(), panic() etc. [but let's keep them for now for ++ older compilers] ++ ++ gcc also has a __attribute__((__hot__)) to move hot functions into ++ a special section, but I don't see any sense in this right now in ++ the kernel context */ ++#define __cold __attribute__((__cold__)) ++ ++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) ++ ++#ifndef __CHECKER__ ++# define __compiletime_warning(message) __attribute__((warning(message))) ++# define __compiletime_error(message) __attribute__((error(message))) ++#endif /* __CHECKER__ */ ++ ++/* ++ * Mark a position in code as unreachable. This can be used to ++ * suppress control flow warnings after asm blocks that transfer ++ * control elsewhere. ++ */ ++#define unreachable() __builtin_unreachable() ++ ++/* Mark a function definition as prohibited from being cloned. */ ++#define __noclone __attribute__((__noclone__)) ++ ++/* ++ * Tell the optimizer that something else uses this function or variable. ++ */ ++#define __visible __attribute__((externally_visible)) ++ ++/* ++ * GCC 'asm goto' miscompiles certain code sequences: ++ * ++ * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 ++ * ++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. ++ * ++ * (asm goto is automatically volatile - the naming reflects this.) ++ */ ++#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) ++ ++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP ++#define __HAVE_BUILTIN_BSWAP32__ ++#define __HAVE_BUILTIN_BSWAP64__ ++#define __HAVE_BUILTIN_BSWAP16__ ++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ ++ ++#define KASAN_ABI_VERSION 6 +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0076-defconfig-add-mqueue-and-seccomp-for-docker.patch b/root/target/linux/mediatek/patches-4.19/0076-defconfig-add-mqueue-and-seccomp-for-docker.patch new file mode 100644 index 00000000..a733d587 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0076-defconfig-add-mqueue-and-seccomp-for-docker.patch @@ -0,0 +1,37 @@ +From f78e2765e6588afd6264c128a060642ed0f6b323 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 12 Apr 2019 11:43:37 +0200 +Subject: [PATCH 76/77] [defconfig] add mqueue and seccomp for docker + +--- + arch/arm/configs/mt7623n_evb_fwu_defconfig | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig +index b49b5feee3eb..314a07cf92fd 100644 +--- a/arch/arm/configs/mt7623n_evb_fwu_defconfig ++++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig +@@ -22,7 +22,6 @@ CONFIG_CGROUP_SCHED=y + CONFIG_CPUSETS=y + #some options for docker + CONFIG_CGROUP_FREEZER=y +-CONFIG_POSIX_MQUEUE=y + CONFIG_OVERLAY_FS=y + CONFIG_MEMCG_SWAP=y + CONFIG_MEMCG_SWAP_ENABLED=y +@@ -131,6 +130,12 @@ CONFIG_IP_PIMSM_V2=y + CONFIG_UNIX_DIAG=m + CONFIG_PACKET_DIAG=m + ++#added for docker ++CONFIG_POSIX_MQUEUE=y ++CONFIG_POSIX_MQUEUE_SYSCTL=y ++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y ++CONFIG_SECCOMP_FILTER=y ++CONFIG_SECCOMP=y + + CONFIG_IPV6=m + CONFIG_NETFILTER=y +-- +2.19.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch b/root/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch new file mode 100644 index 00000000..348035d1 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch @@ -0,0 +1,397 @@ +From 004eb24e939b5b31f828333f37fb5cb2a877d6f2 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +Date: Sun, 17 Jun 2018 14:41:47 +0200 +Subject: [PATCH] arm: dts: Add Unielec U7623 DTS + +--- + arch/arm/boot/dts/Makefile | 1 + + .../dts/mt7623a-unielec-u7623-02-emmc-512M.dts | 18 + + .../boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi | 366 +++++++++++++++++++++ + 3 files changed, 385 insertions(+) + create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512M.dts + create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -1062,7 +1062,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt6589-aquaris5.dtb \ + mt6592-evb.dtb \ + mt7623a-rfb-emmc.dtb \ ++ mt7623a-unielec-u7623-02-emmc-512M.dtb \ + mt7623a-rfb-nand.dtb \ + mt7623n-rfb-emmc.dtb \ + mt7623n-bananapi-bpi-r2.dtb \ + mt8127-moose.dtb \ +--- /dev/null ++++ b/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512M.dts +@@ -0,0 +1,18 @@ ++/* ++ * Copyright 2018 Kristian Evensen ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ */ ++ ++/dts-v1/; ++#include "mt7623a-unielec-u7623-02-emmc.dtsi" ++ ++/ { ++ model = "UniElec U7623-02 eMMC (512M RAM)"; ++ compatible = "unielec,u7623-02-emmc-512m", "unielec,u7623-02-emmc", "mediatek,mt7623"; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x20000000>; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi +@@ -0,0 +1,349 @@ ++/* ++ * Copyright 2018 Kristian Evensen ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ */ ++ ++#include ++#include "mt7623.dtsi" ++#include "mt6323.dtsi" ++ ++/ { ++ compatible = "unielec,u7623-02-emmc", "mediatek,mt7623"; ++ ++ aliases { ++ serial2 = &uart2; ++ }; ++ ++ chosen { ++ bootargs = "root=/dev/mmcblk0p2 rootfstype=squashfs,f2fs"; ++ stdout-path = "serial2:115200n8"; ++ }; ++ ++ cpus { ++ cpu@0 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@1 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@2 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@3 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&key_pins_a>; ++ ++ factory { ++ label = "factory"; ++ linux,code = ; ++ gpios = <&pio 256 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&led_pins_unielec>; ++ ++ led3 { ++ label = "u7623-01:green:led3"; ++ gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ led4 { ++ label = "u7623-01:green:led4"; ++ gpios = <&pio 15 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ ++ mt7530: switch@0 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ ++ mdio: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ phy-mode = "rgmii-rxid"; ++ }; ++ }; ++}; ++ ++&mt7530 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ pinctrl-names = "default"; ++ mediatek,mcm; ++ resets = <ðsys 2>; ++ reset-names = "mcm"; ++ core-supply = <&mt6323_vpa_reg>; ++ io-supply = <&mt6323_vemc3v3_reg>; ++ ++ dsa,mii-bus = <&mdio>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "lan0"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "wan"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ cpu_port0: port@6 { ++ reg = <6>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ pinctrl-1 = <&mmc0_pins_uhs>; ++ status = "okay"; ++ bus-width = <8>; ++ max-frequency = <50000000>; ++ cap-mmc-highspeed; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_1p8v>; ++ non-removable; ++}; ++ ++&pio { ++ key_pins_a: keys-alt { ++ pins-keys { ++ pinmux = , ++ ; ++ input-enable; ++ }; ++ }; ++ ++ led_pins_unielec: leds-unielec { ++ pins-leds { ++ pinmux = , ++ ; ++ }; ++ }; ++ ++ mmc0_pins_default: mmc0default { ++ pins_cmd_dat { ++ pinmux = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ input-enable; ++ bias-pull-up; ++ }; ++ ++ pins_clk { ++ pinmux = ; ++ bias-pull-down; ++ }; ++ ++ pins_rst { ++ pinmux = ; ++ bias-pull-up; ++ }; ++ }; ++ ++ mmc0_pins_uhs: mmc0 { ++ pins_cmd_dat { ++ pinmux = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ input-enable; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ pins_clk { ++ pinmux = ; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ ++ pins_rst { ++ pinmux = ; ++ bias-pull-up; ++ }; ++ }; ++ ++ pcie_default: pcie_pin_default { ++ pins_cmd_dat { ++ pinmux = , ++ ; ++ bias-disable; ++ }; ++ }; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins_a>; ++ status = "okay"; ++}; ++ ++&pwrap { ++ mt6323 { ++ mt6323led: led { ++ compatible = "mediatek,mt6323-led"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ label = "led0"; ++ default-state = "off"; ++ }; ++ }; ++ }; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pins_b>; ++ status = "okay"; ++}; ++ ++&usb1 { ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&u3phy1 { ++ status = "okay"; ++}; ++ ++&u3phy2 { ++ status = "okay"; ++ mediatek,phy-switch = <&hifsys>; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_default>; ++ status = "okay"; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++ ++ pcie@2,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pcie1_phy { ++ status = "okay"; ++}; ++ diff --git a/root/target/linux/mediatek/patches-4.19/0233-revert-unexport-vfs_read-write.patch b/root/target/linux/mediatek/patches-4.19/0233-revert-unexport-vfs_read-write.patch new file mode 100644 index 00000000..5b8e6131 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0233-revert-unexport-vfs_read-write.patch @@ -0,0 +1,35 @@ +From 16c20209050ce9dc0d67e256c3dfba902868c3ed Mon Sep 17 00:00:00 2001 +From: Nikolay Amiantov +Date: Tue, 3 Jul 2018 12:40:04 +0000 +Subject: [PATCH] Revert "fs: unexport vfs_read and vfs_write" + +This reverts commit bd8df82be66698042d11e7919e244c8d72b042ca. +--- + fs/read_write.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/read_write.c b/fs/read_write.c +index 0046d72efe94..62b9c341afa9 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -455,6 +455,8 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) + return ret; + } + ++EXPORT_SYMBOL(vfs_read); ++ + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { + struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; +@@ -553,6 +555,8 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + return ret; + } + ++EXPORT_SYMBOL(vfs_write); ++ + static inline loff_t file_pos_read(struct file *file) + { + return file->f_pos; +-- +2.17.1 + diff --git a/root/target/linux/mediatek/patches-4.19/0234-fix-mtk-wlan_gen2-module.patch b/root/target/linux/mediatek/patches-4.19/0234-fix-mtk-wlan_gen2-module.patch new file mode 100644 index 00000000..bc957ee1 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0234-fix-mtk-wlan_gen2-module.patch @@ -0,0 +1,127 @@ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c +@@ -519,6 +519,9 @@ INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl( + } + + #endif ++ ++EXPORT_SYMBOL(mtk_wcn_consys_hw_wifi_paldo_ctrl); ++ + INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) + { + if (enable) { +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c +@@ -4530,13 +4530,10 @@ INT_32 kalHaltLock(UINT_32 waitMs) + DBGLOG(INIT, ERROR, + "kalIoctl was executed longer than %u ms, show backtrace of tx_thread!\n", + kalGetTimeTick() - rHaltCtrl.u4HoldStart); +- if (prGlueInfo) +- show_stack(prGlueInfo->main_thread, NULL); + } else { + DBGLOG(INIT, ERROR, "halt lock held by %s pid %d longer than %u ms!\n", + rHaltCtrl.owner->comm, rHaltCtrl.owner->pid, + kalGetTimeTick() - rHaltCtrl.u4HoldStart); +- show_stack(rHaltCtrl.owner, NULL); + } + return i4Ret; + } +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c +@@ -58,7 +58,6 @@ + ******************************************************************************** + */ + BOOLEAN fgIsResetting = FALSE; +-UINT_32 g_IsNeedDoChipReset = 0; + + /******************************************************************************* + * P R I V A T E D A T A +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -44,6 +44,9 @@ MODULE_LICENSE("Dual BSD/GPL"); + #define WIFI_LOG_WARN 1 + #define WIFI_LOG_ERR 0 + ++UINT32 g_IsNeedDoChipReset = 0; ++EXPORT_SYMBOL(g_IsNeedDoChipReset); ++ + UINT32 gDbgLevel = WIFI_LOG_DBG; + + #define WIFI_DBG_FUNC(fmt, arg...)\ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile +@@ -21,7 +21,11 @@ endif + obj-y += osal.o \ + bgw_desense.o \ + wmt_idc.o +-obj-$(CONFIG_MTK_COMBO_BT) += stp_chrdev_bt.o +-obj-$(CONFIG_MTK_COMBO_WIFI) += wmt_chrdev_wifi.o ++ifneq ($(CONFIG_MTK_COMBO_BT),) ++ obj-y += stp_chrdev_bt.o ++endif ++ifneq ($(CONFIG_MTK_COMBO_WIFI),) ++ obj-y += wmt_chrdev_wifi.o ++endif + + endif +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c +@@ -25,7 +25,7 @@ int do_wlan_drv_init(int chip_id) + { + int i_ret = 0; + +-#ifdef CONFIG_MTK_COMBO_WIFI ++#ifdef MTK_WIFI_ENABLED + int ret = 0; + + WMT_DETECT_INFO_FUNC("start to do wlan module init 0x%x\n", chip_id); +@@ -35,6 +35,7 @@ int do_wlan_drv_init(int chip_id) + WMT_DETECT_INFO_FUNC("WMT-WIFI char dev init, ret:%d\n", ret); + i_ret += ret; + ++#ifdef CONFIG_MTK_COMBO_WIFI + switch (chip_id) { + case 0x6630: + case 0x6797: +@@ -61,13 +62,10 @@ int do_wlan_drv_init(int chip_id) + #endif + break; + } +- ++#endif + WMT_DETECT_INFO_FUNC("finish wlan module init\n"); +- + #else +- + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_WIFI is not defined\n"); +- + #endif + + return i_ret; +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile +@@ -11,6 +11,10 @@ else ifneq ($(filter "CONSYS_%",$(CONFIG + ccflags-y += -D MTK_WCN_WLAN_GEN2 + endif + ++ifneq ($(CONFIG_MTK_COMBO_WIFI),) ++ ccflags-y += -D MTK_WIFI_ENABLED ++endif ++ + obj-y += conn_drv_init.o + obj-y += common_drv_init.o + obj-y += bluetooth_drv_init.o diff --git a/root/target/linux/mediatek/patches-4.19/0235-mtk_wdt-remove-debug-printk.patch b/root/target/linux/mediatek/patches-4.19/0235-mtk_wdt-remove-debug-printk.patch new file mode 100644 index 00000000..a9f2078c --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0235-mtk_wdt-remove-debug-printk.patch @@ -0,0 +1,12 @@ +Index: linux-4.14.51/drivers/watchdog/mtk_wdt.c +=================================================================== +--- linux-4.14.51.orig/drivers/watchdog/mtk_wdt.c ++++ linux-4.14.51/drivers/watchdog/mtk_wdt.c +@@ -236,7 +236,6 @@ static int mtk_wdt_ping(struct watchdog_ + void __iomem *wdt_base = mtk_wdt->wdt_base; + + iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); +- printk_deferred("[WDK]: kick Ex WDT\n"); + + return 0; + } diff --git a/root/target/linux/mediatek/patches-4.19/0236-mt6625l-rename-wlan.patch b/root/target/linux/mediatek/patches-4.19/0236-mt6625l-rename-wlan.patch new file mode 100644 index 00000000..e1691fd3 --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0236-mt6625l-rename-wlan.patch @@ -0,0 +1,13 @@ +Index: linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +=================================================================== +--- linux-4.14.51.orig/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c ++++ linux-4.14.51/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c +@@ -62,7 +62,7 @@ UINT32 gDbgLevel = WIFI_LOG_DBG; + + #define VERSION "1.0" + +-#define WLAN_IFACE_NAME "wlan0" ++#define WLAN_IFACE_NAME "mtkwlan0" + #if CFG_TC1_FEATURE + #define LEGACY_IFACE_NAME "legacy0" + #endif diff --git a/root/target/linux/mediatek/patches-4.19/0999-wlan-memcpy-fix.patch b/root/target/linux/mediatek/patches-4.19/0999-wlan-memcpy-fix.patch new file mode 100644 index 00000000..4239690c --- /dev/null +++ b/root/target/linux/mediatek/patches-4.19/0999-wlan-memcpy-fix.patch @@ -0,0 +1,20 @@ +--- a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c 2019-11-19 10:19:47.020273630 +0100 ++++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c 2019-11-19 10:20:52.819020893 +0100 +@@ -1544,7 +1544,7 @@ + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_AVAILABLE\n"); + + prEventGscnAvailable = (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer); +- memcpy(prEventGscnAvailable, (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer), ++ memmove(prEventGscnAvailable, (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SCAN_AVAILABLE_T)); + + mtk_cfg80211_vendor_event_scan_results_available(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, +@@ -1647,7 +1647,7 @@ + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_COMPLETE\n"); + prEventGscnScnDone = (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer); +- memcpy(prEventGscnScnDone, (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer), ++ memmove(prEventGscnScnDone, (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SCAN_COMPLETE_T)); + + mtk_cfg80211_vendor_event_complete_scan(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, diff --git a/root/target/linux/mediatek/patches-5.4/0004-mediatek-fix-packet-corruption-on-bridged-interface.patch b/root/target/linux/mediatek/patches-5.4/0004-mediatek-fix-packet-corruption-on-bridged-interface.patch new file mode 100644 index 00000000..6c1c2764 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0004-mediatek-fix-packet-corruption-on-bridged-interface.patch @@ -0,0 +1,51 @@ +From 0593f719ca873722c6ac66604f027a63663c9b64 Mon Sep 17 00:00:00 2001 +From: Alexey Loukianov +Date: Fri, 7 Jun 2019 12:33:45 +0300 +Subject: [PATCH 04/12] mediatek: fix packet corruption on bridged interface + + This fixes problem that was reported here: + http://forum.banana-pi.org/t/openwrt-18-06-malformed-ip-packets-at-bridged-interface/ + + Fix is to set both gmacs to use trgmii mode. + This fix is not technically correct as second gmac + does not support trgmii mode but current driver + implementation seems to handle it somehow and + it is the only way to have both gmacs enabled + and avoid corruption of the packets on brigded + lanX interfaces. + + Signed-off-by: Alexey Loukianov +--- + .../0067-dts-bpi-r2-fix-second-gmac.patch | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + create mode 100644 target/linux/mediatek/patches-4.14/0067-dts-bpi-r2-fix-second-gmac.patch + +diff --git a/target/linux/mediatek/patches-4.14/0067-dts-bpi-r2-fix-second-gmac.patch b/target/linux/mediatek/patches-4.14/0067-dts-bpi-r2-fix-second-gmac.patch +new file mode 100644 +index 0000000000..145c188972 +--- /dev/null ++++ b/target/linux/mediatek/patches-4.14/0067-dts-bpi-r2-fix-second-gmac.patch +@@ -0,0 +1,20 @@ ++--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++@@ -141,7 +141,7 @@ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++- phy-mode = "rgmii"; +++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++@@ -206,7 +206,7 @@ ++ reg = <5>; ++ label = "cpu"; ++ ethernet = <&gmac1>; ++- phy-mode = "rgmii"; +++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; +-- +2.23.0 + diff --git a/root/target/linux/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch b/root/target/linux/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch new file mode 100644 index 00000000..be378827 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch @@ -0,0 +1,10 @@ +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -19,6 +19,7 @@ + + chosen { + stdout-path = "serial2:115200n8"; ++ bootargs = "console=ttyS2,115200n8 root=/dev/mmcblk1p2 rootfstype=ext4 rootwait vmalloc=496M"; + }; + + cpus { diff --git a/root/target/linux/mediatek/patches-5.4/0100-dts-add-second-gmac.patch b/root/target/linux/mediatek/patches-5.4/0100-dts-add-second-gmac.patch new file mode 100644 index 00000000..d985a929 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0100-dts-add-second-gmac.patch @@ -0,0 +1,54 @@ +From 97fdec52fff8079d3af104e8723602a3cb9d2a11 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 20 Jun 2019 23:06:41 +0200 +Subject: [PATCH] net: dts: add second gmac for bananapi r2 + +--- + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 2b760f90f38c..fad09608b86c 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -143,13 +143,25 @@ + }; + }; + ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ label = "wan"; ++ phy-mode = "rgmii"; ++ phy-handle = <&ephy0>; ++ }; ++ + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + +- switch@0 { +- compatible = "mediatek,mt7530"; ++ ephy0: ethernet-phy@0 { + reg = <0>; ++ }; ++ ++ switch@1f { ++ compatible = "mediatek,mt7530"; ++ reg = <0x1f>; + reset-gpios = <&pio 33 0>; + core-supply = <&mt6323_vpa_reg>; + io-supply = <&mt6323_vemc3v3_reg>; +@@ -158,10 +170,12 @@ + #address-cells = <1>; + #size-cells = <0>; + ++/* Disabled, is now handled by gmac1 (eth1/wan) via phy-handle! + port@0 { + reg = <0>; + label = "wan"; + }; ++*/ + + port@1 { + reg = <1>; diff --git a/root/target/linux/mediatek/patches-5.4/0103-net-support-net-labels.patch b/root/target/linux/mediatek/patches-5.4/0103-net-support-net-labels.patch new file mode 100644 index 00000000..1c58130b --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0103-net-support-net-labels.patch @@ -0,0 +1,39 @@ +From 934747eba782050ba87a29a3a59f805e36410685 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= +Date: Fri, 21 Jun 2019 10:04:05 +0200 +Subject: [PATCH] net: ethernet: mediatek: support net-labels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With this patch, device name can be set within dts file in the same way as dsa +port can. +Add: label = "wan"; to GMAC node. + +Signed-off-by: René van Dorst +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c61069340f4f..87ced6269411 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2756,6 +2756,7 @@ static const struct net_device_ops mtk_netdev_ops = { + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + { ++ const char *name = of_get_property(np, "label", NULL); + const __be32 *_id = of_get_property(np, "reg", NULL); + struct phylink *phylink; + int phy_mode, id, err; +@@ -2846,6 +2847,9 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + eth->netdev[id]->irq = eth->irq[0]; + eth->netdev[id]->dev.of_node = np; + ++ if (name) ++ strlcpy(eth->netdev[id]->name, name, IFNAMSIZ); ++ + return 0; + + free_netdev: diff --git a/root/target/linux/mediatek/patches-5.4/0104-dts-add-pause-to-port6.patch b/root/target/linux/mediatek/patches-5.4/0104-dts-add-pause-to-port6.patch new file mode 100644 index 00000000..a8bc7979 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0104-dts-add-pause-to-port6.patch @@ -0,0 +1,22 @@ +From 3a466fd3d5b921c085fd3c863cab3f1afdb90c9c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 12 Jan 2020 16:46:33 +0100 +Subject: [PATCH] arm: dts: add pause to port6 of switch + +to be same as gmac0 +--- + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 52343bd76fe5..7b8383af87e0 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -253,6 +253,7 @@ + fixed-link { + speed = <1000>; + full-duplex; ++ pause; + }; + }; + }; diff --git a/root/target/linux/mediatek/patches-5.4/0110-rtc-mt6397.patch b/root/target/linux/mediatek/patches-5.4/0110-rtc-mt6397.patch new file mode 100644 index 00000000..bbb478e7 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0110-rtc-mt6397.patch @@ -0,0 +1,249 @@ +--- a/drivers/rtc/rtc-mt6397.c 2020-03-05 23:43:52.000000000 +0800 ++++ b/drivers/rtc/rtc-mt6397.c 2020-03-18 00:54:20.445907453 +0800 +@@ -4,48 +4,18 @@ + * Author: Tianping.Fang + */ + +-#include +-#include ++#include ++#include ++#include + #include ++#include ++#include + #include + #include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define RTC_BBPU 0x0000 +-#define RTC_BBPU_CBUSY BIT(6) +- +-#define RTC_WRTGR 0x003c ++#include ++#include + +-#define RTC_IRQ_STA 0x0002 +-#define RTC_IRQ_STA_AL BIT(0) +-#define RTC_IRQ_STA_LP BIT(3) +- +-#define RTC_IRQ_EN 0x0004 +-#define RTC_IRQ_EN_AL BIT(0) +-#define RTC_IRQ_EN_ONESHOT BIT(2) +-#define RTC_IRQ_EN_LP BIT(3) +-#define RTC_IRQ_EN_ONESHOT_AL (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL) +- +-#define RTC_AL_MASK 0x0008 +-#define RTC_AL_MASK_DOW BIT(4) +- +-#define RTC_TC_SEC 0x000a +-/* Min, Hour, Dom... register offset to RTC_TC_SEC */ +-#define RTC_OFFSET_SEC 0 +-#define RTC_OFFSET_MIN 1 +-#define RTC_OFFSET_HOUR 2 +-#define RTC_OFFSET_DOM 3 +-#define RTC_OFFSET_DOW 4 +-#define RTC_OFFSET_MTH 5 +-#define RTC_OFFSET_YEAR 6 +-#define RTC_OFFSET_COUNT 7 +- +-#define RTC_AL_SEC 0x0018 ++#include + + #define RTC_AL_SEC_MASK 0x003f + #define RTC_AL_MIN_MASK 0x003f +@@ -55,26 +25,8 @@ + #define RTC_AL_MTH_MASK 0x000f + #define RTC_AL_YEA_MASK 0x007f + +-#define RTC_PDN2 0x002e +-#define RTC_PDN2_PWRON_ALARM BIT(4) +- +-#define RTC_MIN_YEAR 1968 +-#define RTC_BASE_YEAR 1900 +-#define RTC_NUM_YEARS 128 +-#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR) +- +-struct mt6397_rtc { +- struct device *dev; +- struct rtc_device *rtc_dev; +- struct mutex lock; +- struct regmap *regmap; +- int irq; +- u32 addr_base; +-}; +- + static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) + { +- unsigned long timeout = jiffies + HZ; + int ret; + u32 data; + +@@ -82,19 +34,13 @@ static int mtk_rtc_write_trigger(struct + if (ret < 0) + return ret; + +- while (1) { +- ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_BBPU, +- &data); +- if (ret < 0) +- break; +- if (!(data & RTC_BBPU_CBUSY)) +- break; +- if (time_after(jiffies, timeout)) { +- ret = -ETIMEDOUT; +- break; +- } +- cpu_relax(); +- } ++ ret = regmap_read_poll_timeout(rtc->regmap, ++ rtc->addr_base + RTC_BBPU, data, ++ !(data & RTC_BBPU_CBUSY), ++ MTK_RTC_POLL_DELAY_US, ++ MTK_RTC_POLL_TIMEOUT); ++ if (ret < 0) ++ dev_err(rtc->dev, "failed to write WRTGE: %d\n", ret); + + return ret; + } +@@ -338,19 +284,19 @@ static int mtk_rtc_probe(struct platform + return rtc->irq; + + rtc->regmap = mt6397_chip->regmap; +- rtc->dev = &pdev->dev; + mutex_init(&rtc->lock); + + platform_set_drvdata(pdev, rtc); + +- rtc->rtc_dev = devm_rtc_allocate_device(rtc->dev); ++ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + +- ret = request_threaded_irq(rtc->irq, NULL, +- mtk_rtc_irq_handler_thread, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- "mt6397-rtc", rtc); ++ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, ++ mtk_rtc_irq_handler_thread, ++ IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ "mt6397-rtc", rtc); ++ + if (ret) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + rtc->irq, ret); +@@ -372,15 +318,6 @@ out_free_irq: + return ret; + } + +-static int mtk_rtc_remove(struct platform_device *pdev) +-{ +- struct mt6397_rtc *rtc = platform_get_drvdata(pdev); +- +- free_irq(rtc->irq, rtc); +- +- return 0; +-} +- + #ifdef CONFIG_PM_SLEEP + static int mt6397_rtc_suspend(struct device *dev) + { +@@ -407,6 +344,7 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, + mt6397_rtc_resume); + + static const struct of_device_id mt6397_rtc_of_match[] = { ++ { .compatible = "mediatek,mt6323-rtc", }, + { .compatible = "mediatek,mt6397-rtc", }, + { } + }; +@@ -419,7 +357,6 @@ static struct platform_driver mtk_rtc_dr + .pm = &mt6397_pm_ops, + }, + .probe = mtk_rtc_probe, +- .remove = mtk_rtc_remove, + }; + + module_platform_driver(mtk_rtc_driver); +diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h +new file mode 100644 +index 000000000000..f84b9163c0ee +--- /dev/null ++++ b/include/linux/mfd/mt6397/rtc.h +@@ -0,0 +1,71 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2014-2019 MediaTek Inc. ++ * ++ * Author: Tianping.Fang ++ * Sean Wang ++ */ ++ ++#ifndef _LINUX_MFD_MT6397_RTC_H_ ++#define _LINUX_MFD_MT6397_RTC_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define RTC_BBPU 0x0000 ++#define RTC_BBPU_CBUSY BIT(6) ++#define RTC_BBPU_KEY (0x43 << 8) ++ ++#define RTC_WRTGR 0x003c ++ ++#define RTC_IRQ_STA 0x0002 ++#define RTC_IRQ_STA_AL BIT(0) ++#define RTC_IRQ_STA_LP BIT(3) ++ ++#define RTC_IRQ_EN 0x0004 ++#define RTC_IRQ_EN_AL BIT(0) ++#define RTC_IRQ_EN_ONESHOT BIT(2) ++#define RTC_IRQ_EN_LP BIT(3) ++#define RTC_IRQ_EN_ONESHOT_AL (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL) ++ ++#define RTC_AL_MASK 0x0008 ++#define RTC_AL_MASK_DOW BIT(4) ++ ++#define RTC_TC_SEC 0x000a ++/* Min, Hour, Dom... register offset to RTC_TC_SEC */ ++#define RTC_OFFSET_SEC 0 ++#define RTC_OFFSET_MIN 1 ++#define RTC_OFFSET_HOUR 2 ++#define RTC_OFFSET_DOM 3 ++#define RTC_OFFSET_DOW 4 ++#define RTC_OFFSET_MTH 5 ++#define RTC_OFFSET_YEAR 6 ++#define RTC_OFFSET_COUNT 7 ++ ++#define RTC_AL_SEC 0x0018 ++ ++#define RTC_PDN2 0x002e ++#define RTC_PDN2_PWRON_ALARM BIT(4) ++ ++#define RTC_MIN_YEAR 1968 ++#define RTC_BASE_YEAR 1900 ++#define RTC_NUM_YEARS 128 ++#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR) ++ ++#define MTK_RTC_POLL_DELAY_US 10 ++#define MTK_RTC_POLL_TIMEOUT (jiffies_to_usecs(HZ)) ++ ++struct mt6397_rtc { ++ struct device *dev; ++ struct rtc_device *rtc_dev; ++ ++ /* Protect register access from multiple tasks */ ++ struct mutex lock; ++ struct regmap *regmap; ++ int irq; ++ u32 addr_base; ++}; ++ ++#endif /* _LINUX_MFD_MT6397_RTC_H_ */ + diff --git a/root/target/linux/mediatek/patches-5.4/0111-mt6323-poweroff.patch b/root/target/linux/mediatek/patches-5.4/0111-mt6323-poweroff.patch new file mode 100644 index 00000000..b8552824 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0111-mt6323-poweroff.patch @@ -0,0 +1,160 @@ +From 559614ab0ae2c85596218226f095be36c12cf0fa Mon Sep 17 00:00:00 2001 +From: Josef Friedl +Date: Wed, 3 Jul 2019 12:24:52 +0200 +Subject: [PATCH] power: reset: add driver for mt6323 poweroff + +add poweroff driver for mt6323 and make Makefile and Kconfig-Entries + +Suggested-by: Frank Wunderlich +Signed-off-by: Josef Friedl +Signed-off-by: Frank Wunderlich +Acked-by: Sebastian Reichel +--- +changes since v6: none +changes since v5: split out mfd/mt6397/core.h +changes since v4: none +changes since v3: none +changes since v2: none (=v2 part 5) +--- + drivers/power/reset/Kconfig | 10 +++ + drivers/power/reset/Makefile | 1 + + drivers/power/reset/mt6323-poweroff.c | 97 +++++++++++++++++++++++++++ + 3 files changed, 108 insertions(+) + create mode 100644 drivers/power/reset/mt6323-poweroff.c + +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index a564237278ff..c721939767eb 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -140,6 +140,16 @@ config POWER_RESET_LTC2952 + This driver supports an external powerdown trigger and board power + down via the LTC2952. Bindings are made in the device tree. + ++config POWER_RESET_MT6323 ++ bool "MediaTek MT6323 power-off driver" ++ depends on MFD_MT6397 ++ help ++ The power-off driver is responsible for externally shutdown down ++ the power of a remote MediaTek SoC MT6323 is connected to through ++ controlling a tiny circuit BBPU inside MT6323 RTC. ++ ++ Say Y if you have a board where MT6323 could be found. ++ + config POWER_RESET_QNAP + bool "QNAP power-off driver" + depends on OF_GPIO && PLAT_ORION +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index 85da3198e4e0..da37f8b851dc 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o + obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o + obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o + obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o ++obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o + obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o + obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o + obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o +diff --git a/drivers/power/reset/mt6323-poweroff.c b/drivers/power/reset/mt6323-poweroff.c +new file mode 100644 +index 000000000000..1caf43d9e46d +--- /dev/null ++++ b/drivers/power/reset/mt6323-poweroff.c +@@ -0,0 +1,97 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Power off through MediaTek PMIC ++ * ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * Author: Sean Wang ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct mt6323_pwrc { ++ struct device *dev; ++ struct regmap *regmap; ++ u32 base; ++}; ++ ++static struct mt6323_pwrc *mt_pwrc; ++ ++static void mt6323_do_pwroff(void) ++{ ++ struct mt6323_pwrc *pwrc = mt_pwrc; ++ unsigned int val; ++ int ret; ++ ++ regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY); ++ regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR, 1); ++ ++ ret = regmap_read_poll_timeout(pwrc->regmap, ++ pwrc->base + RTC_BBPU, val, ++ !(val & RTC_BBPU_CBUSY), ++ MTK_RTC_POLL_DELAY_US, ++ MTK_RTC_POLL_TIMEOUT); ++ if (ret) ++ dev_err(pwrc->dev, "failed to write BBPU: %d\n", ret); ++ ++ /* Wait some time until system down, otherwise, notice with a warn */ ++ mdelay(1000); ++ ++ WARN_ONCE(1, "Unable to power off system\n"); ++} ++ ++static int mt6323_pwrc_probe(struct platform_device *pdev) ++{ ++ struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent); ++ struct mt6323_pwrc *pwrc; ++ struct resource *res; ++ ++ pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL); ++ if (!pwrc) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pwrc->base = res->start; ++ pwrc->regmap = mt6397_chip->regmap; ++ pwrc->dev = &pdev->dev; ++ mt_pwrc = pwrc; ++ ++ pm_power_off = &mt6323_do_pwroff; ++ ++ return 0; ++} ++ ++static int mt6323_pwrc_remove(struct platform_device *pdev) ++{ ++ if (pm_power_off == &mt6323_do_pwroff) ++ pm_power_off = NULL; ++ ++ return 0; ++} ++ ++static const struct of_device_id mt6323_pwrc_dt_match[] = { ++ { .compatible = "mediatek,mt6323-pwrc" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match); ++ ++static struct platform_driver mt6323_pwrc_driver = { ++ .probe = mt6323_pwrc_probe, ++ .remove = mt6323_pwrc_remove, ++ .driver = { ++ .name = "mt6323-pwrc", ++ .of_match_table = mt6323_pwrc_dt_match, ++ }, ++}; ++ ++module_platform_driver(mt6323_pwrc_driver); ++ ++MODULE_DESCRIPTION("Poweroff driver for MT6323 PMIC"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_LICENSE("GPL v2"); diff --git a/root/target/linux/mediatek/patches-5.4/0112-dts-mt6323-add-key-rtc-power.patch b/root/target/linux/mediatek/patches-5.4/0112-dts-mt6323-add-key-rtc-power.patch new file mode 100644 index 00000000..41a4305c --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0112-dts-mt6323-add-key-rtc-power.patch @@ -0,0 +1,57 @@ +From c3db4c1163cc20ab0a456086a15c00acb022a67d Mon Sep 17 00:00:00 2001 +From: Josef Friedl +Date: Thu, 20 Dec 2018 18:27:17 +0100 +Subject: [PATCH] arm: dts: mt6323: add keys, power-controller, rtc and codec + +support poweroff and power-related keys on bpi-r2 + +Suggested-by: Frank Wunderlich +Signed-off-by: Josef Friedl +Signed-off-by: Frank Wunderlich +--- +changes since v6: none +changes since v5: none +changes since v4: none +changes since v3: none +changes since v2: none (=v2 part 7) +--- + arch/arm/boot/dts/mt6323.dtsi | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm/boot/dts/mt6323.dtsi b/arch/arm/boot/dts/mt6323.dtsi +index ba397407c1dd..7fda40ab5fe8 100644 +--- a/arch/arm/boot/dts/mt6323.dtsi ++++ b/arch/arm/boot/dts/mt6323.dtsi +@@ -238,5 +238,32 @@ + regulator-enable-ramp-delay = <216>; + }; + }; ++ ++ mt6323keys: mt6323keys { ++ compatible = "mediatek,mt6323-keys"; ++ mediatek,long-press-mode = <1>; ++ power-off-time-sec = <0>; ++ ++ power { ++ linux,keycodes = <116>; ++ wakeup-source; ++ }; ++ ++ home { ++ linux,keycodes = <114>; ++ }; ++ }; ++ ++ codec: mt6397codec { ++ compatible = "mediatek,mt6397-codec"; ++ }; ++ ++ power-controller { ++ compatible = "mediatek,mt6323-pwrc"; ++ }; ++ ++ rtc { ++ compatible = "mediatek,mt6323-rtc"; ++ }; + }; + }; diff --git a/root/target/linux/mediatek/patches-5.4/0170-dts-mt7623-add-display.patch b/root/target/linux/mediatek/patches-5.4/0170-dts-mt7623-add-display.patch new file mode 100644 index 00000000..36c38786 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0170-dts-mt7623-add-display.patch @@ -0,0 +1,500 @@ +From ae7a8d61a108bb58af8c3ecb16d8e95aad0b1975 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Wed, 5 Sep 2018 22:09:27 +0800 +Subject: [PATCH] arm: dts: mt7623: add display subsystem related device nodes + +Add display subsystem related device nodes for MT7623. + +Cc: CK Hu +Signed-off-by: chunhui dai +Signed-off-by: Bibby Hsieh +Signed-off-by: Ryder Lee + +additional fixes: + +[hdmi,dts] fixed dts-warnings +author: Bibby Hsieh + +[dtsi] fix dpi0-node +author: Ryder Lee + +Signed-off-by: Frank Wunderlich +Tested-by: Frank Wunderlich +--- + arch/arm/boot/dts/mt7623.dtsi | 177 ++++++++++++++++++ + arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 85 +++++++++ + arch/arm/boot/dts/mt7623n-rfb-emmc.dts | 85 +++++++++ + 3 files changed, 347 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 59e69f3dffa2..f1880ff04193 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -23,6 +23,11 @@ + #address-cells = <2>; + #size-cells = <2>; + ++ aliases { ++ rdma0 = &rdma0; ++ rdma1 = &rdma1; ++ }; ++ + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; +@@ -320,6 +325,25 @@ + clock-names = "spi", "wrap"; + }; + ++ mipi_tx0: mipi-dphy@10010000 { ++ compatible = "mediatek,mt7623-mipi-tx", ++ "mediatek,mt2701-mipi-tx"; ++ reg = <0 0x10010000 0 0x90>; ++ clocks = <&clk26m>; ++ clock-output-names = "mipi_tx0_pll"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; ++ }; ++ ++ cec: cec@10012000 { ++ compatible = "mediatek,mt7623-cec", ++ "mediatek,mt8173-cec"; ++ reg = <0 0x10012000 0 0xbc>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_CEC>; ++ status = "disabled"; ++ }; ++ + cir: cir@10013000 { + compatible = "mediatek,mt7623-cir"; + reg = <0 0x10013000 0 0x1000>; +@@ -368,6 +392,18 @@ + #clock-cells = <1>; + }; + ++ hdmi_phy: phy@10209100 { ++ compatible = "mediatek,mt7623-hdmi-phy", ++ "mediatek,mt2701-hdmi-phy"; ++ reg = <0 0x10209100 0 0x24>; ++ clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>; ++ clock-names = "pll_ref"; ++ clock-output-names = "hdmitx_dig_cts"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + rng: rng@1020f000 { + compatible = "mediatek,mt7623-rng"; + reg = <0 0x1020f000 0 0x1000>; +@@ -567,6 +603,16 @@ + status = "disabled"; + }; + ++ hdmiddc0: i2c@11013000 { ++ compatible = "mediatek,mt7623-hdmi-ddc", ++ "mediatek,mt8173-hdmi-ddc"; ++ interrupts = ; ++ reg = <0 0x11013000 0 0x1C>; ++ clocks = <&pericfg CLK_PERI_I2C3>; ++ clock-names = "ddc-i2c"; ++ status = "disabled"; ++ }; ++ + nor_flash: spi@11014000 { + compatible = "mediatek,mt7623-nor", + "mediatek,mt8173-nor"; +@@ -741,6 +787,84 @@ + #clock-cells = <1>; + }; + ++ display_components: dispsys@14000000 { ++ compatible = "mediatek,mt7623-mmsys", ++ "mediatek,mt2701-mmsys"; ++ reg = <0 0x14000000 0 0x1000>; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; ++ }; ++ ++ ovl@14007000 { ++ compatible = "mediatek,mt7623-disp-ovl", ++ "mediatek,mt2701-disp-ovl"; ++ reg = <0 0x14007000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_OVL>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_OVL_0>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ rdma0: rdma@14008000 { ++ compatible = "mediatek,mt7623-disp-rdma", ++ "mediatek,mt2701-disp-rdma"; ++ reg = <0 0x14008000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_RDMA>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ wdma@14009000 { ++ compatible = "mediatek,mt7623-disp-wdma", ++ "mediatek,mt2701-disp-wdma"; ++ reg = <0 0x14009000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_WDMA>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_WDMA>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ bls: pwm@1400a000 { ++ compatible = "mediatek,mt7623-disp-pwm", ++ "mediatek,mt2701-disp-pwm"; ++ reg = <0 0x1400a000 0 0x1000>; ++ #pwm-cells = <2>; ++ clocks = <&mmsys CLK_MM_MDP_BLS_26M>, ++ <&mmsys CLK_MM_DISP_BLS>; ++ clock-names = "main", "mm"; ++ status = "disabled"; ++ }; ++ ++ color@1400b000 { ++ compatible = "mediatek,mt7623-disp-color", ++ "mediatek,mt2701-disp-color"; ++ reg = <0 0x1400b000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_COLOR>; ++ }; ++ ++ dsi: dsi@1400c000 { ++ compatible = "mediatek,mt7623-dsi", ++ "mediatek,mt2701-dsi"; ++ reg = <0 0x1400c000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DSI_ENGINE>, ++ <&mmsys CLK_MM_DSI_DIG>, ++ <&mipi_tx0>; ++ clock-names = "engine", "digital", "hs"; ++ phys = <&mipi_tx0>; ++ phy-names = "dphy"; ++ status = "disabled"; ++ }; ++ ++ mutex: mutex@1400e000 { ++ compatible = "mediatek,mt7623-disp-mutex", ++ "mediatek,mt2701-disp-mutex"; ++ reg = <0 0x1400e000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_MUTEX_32K>; ++ }; ++ + larb0: larb@14010000 { + compatible = "mediatek,mt7623-smi-larb", + "mediatek,mt2701-smi-larb"; +@@ -753,6 +877,44 @@ + power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; + }; + ++ rdma1: rdma@14012000 { ++ compatible = "mediatek,mt7623-disp-rdma", ++ "mediatek,mt2701-disp-rdma"; ++ reg = <0 0x14012000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DISP_RDMA1>; ++ iommus = <&iommu MT2701_M4U_PORT_DISP_RDMA1>; ++ mediatek,larb = <&larb0>; ++ }; ++ ++ dpi0: dpi@14014000 { ++ compatible = "mediatek,mt7623-dpi", ++ "mediatek,mt2701-dpi"; ++ reg = <0 0x14014000 0 0x1000>; ++ interrupts = ; ++ clocks = <&mmsys CLK_MM_DPI1_DIGL>, ++ <&mmsys CLK_MM_DPI1_ENGINE>, ++ <&apmixedsys CLK_APMIXED_TVDPLL>; ++ clock-names = "pixel", "engine", "pll"; ++ status = "disabled"; ++ }; ++ ++ hdmi0: hdmi@14015000 { ++ compatible = "mediatek,mt7623-hdmi", ++ "mediatek,mt8173-hdmi"; ++ reg = <0 0x14015000 0 0x400>; ++ clocks = <&mmsys CLK_MM_HDMI_PIXEL>, ++ <&mmsys CLK_MM_HDMI_PLL>, ++ <&mmsys CLK_MM_HDMI_AUDIO>, ++ <&mmsys CLK_MM_HDMI_SPDIF>; ++ clock-names = "pixel", "pll", "bclk", "spdif"; ++ phys = <&hdmi_phy>; ++ phy-names = "hdmi"; ++ mediatek,syscon-hdmi = <&mmsys 0x900>; ++ cec = <&cec>; ++ status = "disabled"; ++ }; ++ + imgsys: syscon@15000000 { + compatible = "mediatek,mt7623-imgsys", + "mediatek,mt2701-imgsys", +@@ -1077,6 +1239,21 @@ + }; + }; + ++ hdmi_pins_a: hdmi-default { ++ pins-hdmi { ++ pinmux = ; ++ input-enable; ++ bias-pull-down; ++ }; ++ }; ++ ++ hdmi_ddc_pins_a: hdmi_ddc-default { ++ pins-hdmi-ddc { ++ pinmux = , ++ ; ++ }; ++ }; ++ + i2c0_pins_a: i2c0-default { + pins-i2c0 { + pinmux = , +diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +index 2b760f90f38c..7a1763472018 100644 +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -21,6 +21,19 @@ + stdout-path = "serial2:115200n8"; + }; + ++ connector { ++ compatible = "hdmi-connector"; ++ label = "hdmi"; ++ type = "d"; ++ ddc-i2c-bus = <&hdmiddc0>; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi0_out>; ++ }; ++ }; ++ }; ++ + cpus { + cpu@0 { + proc-supply = <&mt6323_vproc_reg>; +@@ -114,10 +127,24 @@ + }; + }; + ++&bls { ++ status = "okay"; ++ ++ port { ++ bls_out: endpoint { ++ remote-endpoint = <&dpi0_in>; ++ }; ++ }; ++}; ++ + &btif { + status = "okay"; + }; + ++&cec { ++ status = "okay"; ++}; ++ + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&cir_pins_a>; +@@ -128,6 +155,28 @@ + status = "okay"; + }; + ++&dpi0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ dpi0_out: endpoint { ++ remote-endpoint = <&hdmi0_in>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dpi0_in: endpoint { ++ remote-endpoint = <&bls_out>; ++ }; ++ }; ++ }; ++}; ++ + ð { + status = "okay"; + +@@ -199,6 +248,42 @@ + }; + }; + ++&hdmi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_pins_a>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ hdmi0_in: endpoint { ++ remote-endpoint = <&dpi0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ hdmi0_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmiddc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_ddc_pins_a>; ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ mediatek,ibias = <0xa>; ++ mediatek,ibias_up = <0x1c>; ++ status = "okay"; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; +diff --git a/arch/arm/boot/dts/mt7623n-rfb-emmc.dts b/arch/arm/boot/dts/mt7623n-rfb-emmc.dts +index b7606130ade9..3e5911d8d6bc 100644 +--- a/arch/arm/boot/dts/mt7623n-rfb-emmc.dts ++++ b/arch/arm/boot/dts/mt7623n-rfb-emmc.dts +@@ -24,6 +24,19 @@ + stdout-path = "serial2:115200n8"; + }; + ++ connector { ++ compatible = "hdmi-connector"; ++ label = "hdmi"; ++ type = "d"; ++ ddc-i2c-bus = <&hdmiddc0>; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi0_out>; ++ }; ++ }; ++ }; ++ + cpus { + cpu@0 { + proc-supply = <&mt6323_vproc_reg>; +@@ -106,10 +119,24 @@ + }; + }; + ++&bls { ++ status = "okay"; ++ ++ port { ++ bls_out: endpoint { ++ remote-endpoint = <&dpi0_in>; ++ }; ++ }; ++}; ++ + &btif { + status = "okay"; + }; + ++&cec { ++ status = "okay"; ++}; ++ + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&cir_pins_a>; +@@ -120,6 +147,28 @@ + status = "okay"; + }; + ++&dpi0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ dpi0_out: endpoint { ++ remote-endpoint = <&hdmi0_in>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dpi0_in: endpoint { ++ remote-endpoint = <&bls_out>; ++ }; ++ }; ++ }; ++}; ++ + ð { + status = "okay"; + +@@ -202,6 +251,42 @@ + }; + }; + ++&hdmi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_pins_a>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ hdmi0_in: endpoint { ++ remote-endpoint = <&dpi0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ hdmi0_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmiddc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_ddc_pins_a>; ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ mediatek,ibias = <0xa>; ++ mediatek,ibias_up = <0x1c>; ++ status = "okay"; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; diff --git a/root/target/linux/mediatek/patches-5.4/0171-dts-mt7623-add-mali450.patch b/root/target/linux/mediatek/patches-5.4/0171-dts-mt7623-add-mali450.patch new file mode 100644 index 00000000..c49690c5 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0171-dts-mt7623-add-mali450.patch @@ -0,0 +1,77 @@ +From 6468d187f12604f38f0a3acde430fdc5c5390771 Mon Sep 17 00:00:00 2001 +From: Ryder Lee +Date: Tue, 23 Jul 2019 11:32:50 +0800 +Subject: [PATCH] arm: dts: mt7623: add Mali-450 device nodes + +Add nodes for Mali-450 and iommu larb3. + +Signed-off-by: Sean Wang +Signed-off-by: Ryder Lee +--- + arch/arm/boot/dts/mt7623.dtsi | 39 ++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 8d0807fd9460..f7905561b30e 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -3,6 +3,7 @@ + * Copyright (c) 2017-2018 MediaTek Inc. + * Author: John Crispin + * Sean Wang ++ * Ryder Lee + * + */ + +@@ -371,7 +372,7 @@ + interrupts = ; + clocks = <&infracfg CLK_INFRA_M4U>; + clock-names = "bclk"; +- mediatek,larbs = <&larb0 &larb1 &larb2>; ++ mediatek,larbs = <&larb0 &larb1 &larb2 &larb3>; + #iommu-cells = <1>; + }; + +@@ -794,6 +795,42 @@ + #reset-cells = <1>; + }; + ++ larb3: larb@13010000 { ++ compatible = "mediatek,mt7623-smi-larb", ++ "mediatek,mt2701-smi-larb"; ++ reg = <0 0x13010000 0 0x1000>; ++ mediatek,smi = <&smi_common>; ++ mediatek,larb-id = <3>; ++ clocks = <&clk26m>, <&clk26m>; ++ clock-names = "apb", "smi"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_MFG>; ++ }; ++ ++ mali: gpu@13040000 { ++ compatible = "mediatek,mt7623-mali", "arm,mali-450"; ++ reg = <0 0x13040000 0 0x30000>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "gp", "gpmmu", "pp0", "ppmmu0", "pp1", ++ "ppmmu1", "pp2", "ppmmu2", "pp3", "ppmmu3", ++ "pp"; ++ clocks = <&topckgen CLK_TOP_MMPLL>, ++ <&g3dsys CLK_G3DSYS_CORE>; ++ clock-names = "bus", "core"; ++ power-domains = <&scpsys MT2701_POWER_DOMAIN_MFG>; ++ mediatek,larb = <&larb3>; ++ resets = <&g3dsys MT2701_G3DSYS_CORE_RST>; ++ }; ++ + mmsys: syscon@14000000 { + compatible = "mediatek,mt7623-mmsys", + "mediatek,mt2701-mmsys", diff --git a/root/target/linux/mediatek/patches-5.4/0180-lima-power-on-off.patch b/root/target/linux/mediatek/patches-5.4/0180-lima-power-on-off.patch new file mode 100644 index 00000000..fe4b742c --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0180-lima-power-on-off.patch @@ -0,0 +1,68 @@ +From d87e1a23e51158f9c2923f6213a42d5e942a4091 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Thu, 23 Jan 2020 07:16:30 +0100 +Subject: [PATCH] lima: power on/off via register (function) + +--- + drivers/gpu/drm/lima/lima_device.c | 31 ++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c +index d86b8d81a483..7d5d45e176f2 100644 +--- a/drivers/gpu/drm/lima/lima_device.c ++++ b/drivers/gpu/drm/lima/lima_device.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #include "lima_device.h" + #include "lima_gp.h" +@@ -287,11 +288,33 @@ static void lima_fini_pp_pipe(struct lima_device *dev) + lima_sched_pipe_fini(pipe); + } + ++void mtk_set_power(bool on) ++{ ++ if (on) { ++ void __iomem *wakeup_register; ++ wakeup_register = ioremap(0x10003014 , 0x04); ++ writel(0x00000001,wakeup_register); // this may be wrong, may need bitbang 0th bit to 1 ++ iounmap(wakeup_register); ++ }else { ++ void __iomem *powerdown_register; ++ powerdown_register = ioremap(0x1000300C , 0x04); // powerdown register ++ writel(0x00000001,powerdown_register); // this may be wrong, may need bitbang 0th bit to 1 ++ iounmap(powerdown_register); ++ } ++} ++ + int lima_device_init(struct lima_device *ldev) + { + int err, i; + struct resource *res; + ++ #ifdef CONFIG_MTK_COMBO_CHIP_CONSYS_7623 ++ mtk_set_power(true); ++ pm_runtime_enable(ldev->dev); ++ pm_runtime_set_active(ldev->dev); ++ pm_runtime_get_sync(ldev->dev); ++ #endif ++ + dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32)); + + err = lima_clk_init(ldev); +@@ -385,4 +408,12 @@ void lima_device_fini(struct lima_device *ldev) + lima_regulator_fini(ldev); + + lima_clk_fini(ldev); ++ ++ #ifdef CONFIG_MTK_COMBO_CHIP_CONSYS_7623 ++ pm_runtime_set_suspended(ldev->dev); ++ pm_runtime_put_noidle(ldev->dev); ++ pm_runtime_disable(ldev->dev); ++ ++ mtk_set_power(false); ++ #endif + } diff --git a/root/target/linux/mediatek/patches-5.4/0181-drm-Add-get_possible_crtc.patch b/root/target/linux/mediatek/patches-5.4/0181-drm-Add-get_possible_crtc.patch new file mode 100644 index 00000000..ff149dce --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0181-drm-Add-get_possible_crtc.patch @@ -0,0 +1,84 @@ +From 452b508468a46ef0fe7357fab6b000c52fd047d3 Mon Sep 17 00:00:00 2001 +From: Stu Hsieh +Date: Fri, 16 Nov 2018 16:33:00 +0100 +Subject: [PATCH] drm: Add get_possible_crtc API for dpi, dsi + +Test: build pass and run ok + +Signed-off-by: Stu Hsieh +--- + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 40 +++++++++++++++++++++ + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 2 ++ + 2 files changed, 42 insertions(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index efa85973e46b..29796e78b26a 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -237,6 +237,22 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, + }; + ++static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp, ++ const enum mtk_ddp_comp_id *path, ++ unsigned int path_len) ++{ ++ unsigned int i; ++ ++ if (path == NULL) ++ return false; ++ ++ for (i = 0U; i < path_len; i++) ++ if (ddp_comp.id == path[i]) ++ return true; ++ ++ return false; ++} ++ + int mtk_ddp_comp_get_id(struct device_node *node, + enum mtk_ddp_comp_type comp_type) + { +@@ -252,6 +268,30 @@ int mtk_ddp_comp_get_id(struct device_node *node, + return -EINVAL; + } + ++unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, ++ struct mtk_ddp_comp ddp_comp) ++{ ++ struct mtk_drm_private *private = drm->dev_private; ++ unsigned int ret; ++ ++ if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->main_path, ++ private->data->main_len) == true) { ++ ret = BIT(0); ++ } else if (mtk_drm_find_comp_in_ddp(ddp_comp, ++ private->data->ext_path, ++ private->data->ext_len) == true) { ++ ret = BIT(1); ++ } else if (mtk_drm_find_comp_in_ddp(ddp_comp, ++ private->data->third_path, ++ private->data->third_len) == true) { ++ ret = BIT(2); ++ } else { ++ DRM_INFO("Failed to find comp in ddp table\n"); ++ ret = 0; ++ } ++ return ret; ++} ++ + int mtk_ddp_comp_init(struct device *dev, struct device_node *node, + struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, + const struct mtk_ddp_comp_funcs *funcs) +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +index 0ad287f427cc..97be111c3e52 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +@@ -160,6 +160,8 @@ static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp, + + int mtk_ddp_comp_get_id(struct device_node *node, + enum mtk_ddp_comp_type comp_type); ++unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, ++ struct mtk_ddp_comp ddp_comp); + int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node, + struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, + const struct mtk_ddp_comp_funcs *funcs); diff --git a/root/target/linux/mediatek/patches-5.4/0182-drm-change-possible_crtc.patch b/root/target/linux/mediatek/patches-5.4/0182-drm-change-possible_crtc.patch new file mode 100644 index 00000000..c92e18cc --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0182-drm-change-possible_crtc.patch @@ -0,0 +1,45 @@ +From f4ca44932ccf088f225062aafef04d2bd629b2c4 Mon Sep 17 00:00:00 2001 +From: Jitao Shi +Date: Fri, 3 May 2019 17:16:19 +0200 +Subject: [PATCH] drm/mediatek: dpi/dsi: change the getting possible_crtc way + +[Detail] +dpi/dsi get the possible_crtc by +mtk_drm_find_possible_crtc_by_comp(*drm_dev, ddp_comp) + +Test: build pass and boot to logo + +Signed-off-by: Jitao Shi +--- + drivers/gpu/drm/mediatek/mtk_dpi.c | 3 ++- + drivers/gpu/drm/mediatek/mtk_dsi.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index be6d95c5ff25..00d31b5aa09f 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -604,7 +604,8 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) + drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs); + + /* Currently DPI0 is fixed to be driven by OVL1 */ +- dpi->encoder.possible_crtcs = BIT(1); ++ dpi->encoder.possible_crtcs = ++ mtk_drm_find_possible_crtc_by_comp(drm_dev, dpi->ddp_comp); + + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL); + if (ret) { +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 224afb666881..2c2d3643f3e8 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -817,7 +817,8 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi) + * Currently display data paths are statically assigned to a crtc each. + * crtc 0 is OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 + */ +- dsi->encoder.possible_crtcs = 1; ++ dsi->encoder.possible_crtcs = ++ mtk_drm_find_possible_crtc_by_comp(drm, dsi->ddp_comp); + + /* If there's a bridge, attach to it and let it create the connector */ + if (dsi->bridge) { diff --git a/root/target/linux/mediatek/patches-5.4/0183-drm-fix-DRM_INFO.patch b/root/target/linux/mediatek/patches-5.4/0183-drm-fix-DRM_INFO.patch new file mode 100644 index 00000000..98bba9dc --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0183-drm-fix-DRM_INFO.patch @@ -0,0 +1,21 @@ +From 34dd2a86c9e3b3ad1a3a00add409edda2b2ed776 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 1 Oct 2019 11:21:03 +0200 +Subject: [PATCH] drm: fix implicit declaration of function 'DRM_INFO' + +--- + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index 29796e78b26a..e65d83267563 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "mtk_drm_drv.h" + #include "mtk_drm_plane.h" diff --git a/root/target/linux/mediatek/patches-5.4/0184-drm-config-component-output.patch b/root/target/linux/mediatek/patches-5.4/0184-drm-config-component-output.patch new file mode 100644 index 00000000..adc35c7d --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0184-drm-config-component-output.patch @@ -0,0 +1,146 @@ +From 6e3f7375acdcf714d1fcbae1238cd39cc9391560 Mon Sep 17 00:00:00 2001 +From: Bibby Hsieh +Date: Fri, 21 Sep 2018 11:28:22 +0800 +Subject: [PATCH] drm/mediatek: config component output by device node port + +We can select output component by decive node port. +Main path default output component is DSI. +External path default output component is DPI. + +Signed-off-by: Bibby Hsieh + +added small fixes for warnings + +Signed-off-by: Frank Wunderlich +Tested-by: Frank Wunderlich +--- + drivers/gpu/drm/mediatek/mtk_drm_drv.c | 46 ++++++++++++++++++++++---- + drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 +-- + 2 files changed, 42 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +index 352b81a7a670..33511c77b800 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +@@ -21,6 +21,13 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #include "mtk_drm_crtc.h" + #include "mtk_drm_ddp.h" +@@ -121,7 +128,7 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { + .atomic_commit = mtk_atomic_commit, + }; + +-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_RDMA0, + DDP_COMPONENT_COLOR0, +@@ -129,12 +136,12 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = { + DDP_COMPONENT_DSI0, + }; + +-static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { + DDP_COMPONENT_RDMA1, + DDP_COMPONENT_DPI0, + }; + +-static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_AAL0, +@@ -144,7 +151,7 @@ static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { + DDP_COMPONENT_PWM0, + }; + +-static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = { + DDP_COMPONENT_OVL1, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_AAL1, +@@ -160,7 +167,7 @@ static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = { + DDP_COMPONENT_PWM2, + }; + +-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { ++static enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_AAL0, +@@ -171,7 +178,7 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { + DDP_COMPONENT_PWM0, + }; + +-static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = { ++static enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = { + DDP_COMPONENT_OVL1, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_GAMMA, +@@ -510,6 +517,7 @@ static int mtk_drm_probe(struct platform_device *pdev) + + /* Iterate over sibling DISP function blocks */ + for_each_child_of_node(dev->of_node->parent, node) { ++ struct device_node *port, *ep, *remote; + const struct of_device_id *of_id; + enum mtk_ddp_comp_type comp_type; + int comp_id; +@@ -572,6 +580,32 @@ static int mtk_drm_probe(struct platform_device *pdev) + + private->ddp_comp[comp_id] = comp; + } ++ ++ if (comp_type != MTK_DSI && comp_type != MTK_DPI) { ++ port = of_graph_get_port_by_id(node, 0); ++ if (!port) ++ continue; ++ ep = of_get_child_by_name(port, "endpoint"); ++ of_node_put(port); ++ if (!ep) ++ continue; ++ remote = of_graph_get_remote_port_parent(ep); ++ of_node_put(ep); ++ if (!remote) ++ continue; ++ of_id = of_match_node(mtk_ddp_comp_dt_ids, remote); ++ if (!of_id) ++ continue; ++ comp_type = (enum mtk_ddp_comp_type)of_id->data; ++ for (i = 0; i < private->data->main_len - 1; i++) ++ if (private->data->main_path[i] == comp_id) ++ private->data->main_path[i + 1] = ++ mtk_ddp_comp_get_id(node, comp_type); ++ for (i = 0; i < private->data->ext_len - 1; i++) ++ if (private->data->ext_path[i] == comp_id) ++ private->data->ext_path[i + 1] = ++ mtk_ddp_comp_get_id(node, comp_type); ++ } + } + + if (!private->mutex_node) { +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h +index e03fea12ff59..5fb723415ff6 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h +@@ -21,9 +21,9 @@ struct drm_property; + struct regmap; + + struct mtk_mmsys_driver_data { +- const enum mtk_ddp_comp_id *main_path; ++ enum mtk_ddp_comp_id *main_path; + unsigned int main_len; +- const enum mtk_ddp_comp_id *ext_path; ++ enum mtk_ddp_comp_id *ext_path; + unsigned int ext_len; + const enum mtk_ddp_comp_id *third_path; + unsigned int third_len; diff --git a/root/target/linux/mediatek/patches-5.4/0185-drm-fix-boot-up.patch b/root/target/linux/mediatek/patches-5.4/0185-drm-fix-boot-up.patch new file mode 100644 index 00000000..247853f3 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0185-drm-fix-boot-up.patch @@ -0,0 +1,55 @@ +From ba9c6527b05d294bdda7910db224e327f1460166 Mon Sep 17 00:00:00 2001 +From: chunhui dai +Date: Wed, 31 Oct 2018 16:59:34 +0800 +Subject: [PATCH] drm/mediatek: fix boot up for 720 and 480 but 1080 + +- 1080 plg in/out with ng/ok +- support other resolutions like 1280x1024 + +Signed-off-by: chunhui dai +Signed-off-by: Frank Wunderlich +Tested-by: Frank Wunderlich +--- + drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 3 +++ + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 1 + + drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 1 + + 3 files changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +index 5223498502c4..edadb7a700f1 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +@@ -184,6 +184,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) + return PTR_ERR(phy_provider); + } + ++ if (hdmi_phy->conf->pll_default_off) ++ hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); ++ + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, + hdmi_phy->pll); + } +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +index 2d8b3182470d..f472fdeb63dc 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +@@ -22,6 +22,7 @@ struct mtk_hdmi_phy; + struct mtk_hdmi_phy_conf { + bool tz_disabled; + unsigned long flags; ++ bool pll_default_off; + const struct clk_ops *hdmi_phy_clk_ops; + void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); + void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); +diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +index d3cc4022e988..6fbedacfc1e8 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c ++++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +@@ -239,6 +239,7 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) + struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = { + .tz_disabled = true, + .flags = CLK_SET_RATE_GATE, ++ .pll_default_off = true, + .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, + .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, + .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, diff --git a/root/target/linux/mediatek/patches-5.4/0190-thermal-add-sensor.patch b/root/target/linux/mediatek/patches-5.4/0190-thermal-add-sensor.patch new file mode 100644 index 00000000..cc897705 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0190-thermal-add-sensor.patch @@ -0,0 +1,56 @@ +From aa97a44297179ab6ba1aa8f59e781541a320066b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 31 Jan 2020 17:28:04 +0100 +Subject: [PATCH] thermal: mediatek: add sensors-support + +--- + drivers/thermal/mtk_thermal.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c +index d1b066383c45..8cf3a69bfa46 100644 +--- a/drivers/thermal/mtk_thermal.c ++++ b/drivers/thermal/mtk_thermal.c +@@ -23,6 +23,8 @@ + #include + #include + ++#include "thermal_hwmon.h" ++ + /* AUXADC Registers */ + #define AUXADC_CON1_SET_V 0x008 + #define AUXADC_CON1_CLR_V 0x00c +@@ -990,6 +992,13 @@ static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt, + writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1); + } + ++static void mtk_thermal_hwmon_action(void *data) ++{ ++ struct thermal_zone_device *zone = data; ++ ++ thermal_remove_hwmon_sysfs(zone); ++} ++ + static int mtk_thermal_probe(struct platform_device *pdev) + { + int ret, i, ctrl_id; +@@ -1094,6 +1103,19 @@ static int mtk_thermal_probe(struct platform_device *pdev) + goto err_disable_clk_peri_therm; + } + ++ tzdev->tzp->no_hwmon = false; ++ ret = thermal_add_hwmon_sysfs(tzdev); ++ if (ret) ++ dev_err(&pdev->dev,"error in thermal_add_hwmon_sysfs"); ++ //goto err_disable_clk_peri_therm; ++ ++ ret = devm_add_action(&pdev->dev, mtk_thermal_hwmon_action, tzdev); ++ if (ret) { ++ dev_err(&pdev->dev,"error in devm_add_action"); ++ mtk_thermal_hwmon_action(tzdev); ++ //goto err_disable_clk_peri_therm; ++ } ++ + return 0; + + err_disable_clk_peri_therm: diff --git a/root/target/linux/mediatek/patches-5.4/0191-thermal.patch b/root/target/linux/mediatek/patches-5.4/0191-thermal.patch new file mode 100644 index 00000000..01ead975 --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0191-thermal.patch @@ -0,0 +1,35 @@ +From 9847677bda4920bbba15499f28009ce095f02c99 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 31 Jan 2020 18:49:56 +0100 +Subject: [PATCH] thermal: mediatek: execute hwmon-code only if hwmon_thermal + is set + +--- + drivers/thermal/mtk_thermal.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c +index 8cf3a69bfa46..3a646b88f587 100644 +--- a/drivers/thermal/mtk_thermal.c ++++ b/drivers/thermal/mtk_thermal.c +@@ -1103,18 +1103,18 @@ static int mtk_thermal_probe(struct platform_device *pdev) + goto err_disable_clk_peri_therm; + } + ++#ifdef CONFIG_THERMAL_HWMON + tzdev->tzp->no_hwmon = false; + ret = thermal_add_hwmon_sysfs(tzdev); + if (ret) + dev_err(&pdev->dev,"error in thermal_add_hwmon_sysfs"); +- //goto err_disable_clk_peri_therm; + + ret = devm_add_action(&pdev->dev, mtk_thermal_hwmon_action, tzdev); + if (ret) { + dev_err(&pdev->dev,"error in devm_add_action"); + mtk_thermal_hwmon_action(tzdev); +- //goto err_disable_clk_peri_therm; + } ++#endif + + return 0; + diff --git a/root/target/linux/mediatek/patches-5.4/0230-pthread.patch b/root/target/linux/mediatek/patches-5.4/0230-pthread.patch new file mode 100644 index 00000000..ab5523cf --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0230-pthread.patch @@ -0,0 +1,14 @@ +--- a/scripts/Makefile 2020-03-21 22:28:13.290800484 +0800 ++++ b/scripts/Makefile 2020-03-21 22:28:26.230870790 +0800 +@@ -23,8 +23,8 @@ hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFIC + + HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include + HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include +-HOSTLDLIBS_sign-file = -lcrypto +-HOSTLDLIBS_extract-cert = -lcrypto ++HOSTLDLIBS_sign-file = -lcrypto -lpthread ++HOSTLDLIBS_extract-cert = -lcrypto -lpthread + + always := $(hostprogs-y) $(hostprogs-m) + + diff --git a/root/target/linux/mediatek/patches-5.4/0999-lan-to-wan.patch b/root/target/linux/mediatek/patches-5.4/0999-lan-to-wan.patch new file mode 100644 index 00000000..d780caba --- /dev/null +++ b/root/target/linux/mediatek/patches-5.4/0999-lan-to-wan.patch @@ -0,0 +1,49 @@ +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts 2020-04-19 11:02:56.505715879 +0200 ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts 2020-04-19 11:03:53.620780390 +0200 +@@ -196,7 +196,7 @@ + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; +- label = "wan"; ++ label = "lan"; + phy-mode = "rgmii"; + phy-handle = <&ephy0>; + local-mac-address = [00 0a 35 00 00 02]; +@@ -221,31 +221,31 @@ + #address-cells = <1>; + #size-cells = <0>; + +-/* Disabled, is now handled by gmac1 (eth1/wan) via phy-handle! ++/* Disabled, is now handled by gmac1 (eth1/lan) via phy-handle! + port@0 { + reg = <0>; +- label = "wan"; ++ label = "lan"; + }; + */ + + port@1 { + reg = <1>; +- label = "lan0"; ++ label = "wan1"; + }; + + port@2 { + reg = <2>; +- label = "lan1"; ++ label = "wan2"; + }; + + port@3 { + reg = <3>; +- label = "lan2"; ++ label = "wan3"; + }; + + port@4 { + reg = <4>; +- label = "lan3"; ++ label = "wan4"; + }; + + port@6 { diff --git a/root/target/linux/mvebu/config-4.14 b/root/target/linux/mvebu/config-4.14 new file mode 100644 index 00000000..0efd8f5c --- /dev/null +++ b/root/target/linux/mvebu/config-4.14 @@ -0,0 +1,498 @@ +CONFIG_AHCI_MVEBU=y +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARMADA_370_CLK=y +CONFIG_ARMADA_370_XP_IRQ=y +CONFIG_ARMADA_370_XP_TIMER=y +CONFIG_ARMADA_38X_CLK=y +CONFIG_ARMADA_THERMAL=y +CONFIG_ARMADA_XP_CLK=y +CONFIG_ARM_APPENDED_DTB=y +# CONFIG_ARM_ARMADA_37XX_CPUFREQ is not set +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GLOBAL_TIMER=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_MVEBU_V7_CPUIDLE=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y +CONFIG_ATA=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_FEROCEON_L2 is not set +CONFIG_CACHE_L2X0=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PJ4B=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_CHACHA20_NEON is not set +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32_ARM_CE is not set +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_DEV_MARVELL_CESA=y +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256_ARM=y +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +CONFIG_CRYPTO_SHA512_ARM=y +CONFIG_CRYPTO_SIMD=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_MVEBU_UART0=y +# CONFIG_DEBUG_MVEBU_UART0_ALTERNATE is not set +# CONFIG_DEBUG_MVEBU_UART1_ALTERNATE is not set +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=2 +# CONFIG_DEBUG_UART_8250_WORD is not set +CONFIG_DEBUG_UART_PHYS=0xd0012000 +CONFIG_DEBUG_UART_VIRT=0xfec12000 +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_DEBUG_USER=y +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ENGINE_RAID=y +CONFIG_DMA_OF=y +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EXT4_FS=y +CONFIG_EXTCON=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FS_MBCACHE=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MVEBU=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GRO_CELLS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_TWD=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWBM=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_OMAP is not set +CONFIG_HZ_FIXED=0 +CONFIG_HZ_PERIODIC=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MV64XXX=y +# CONFIG_I2C_PXA is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IOMMU_HELPER=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +# CONFIG_IWMMXT is not set +CONFIG_JBD2=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA963X=y +CONFIG_LEDS_TLC591XX=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LIBFDT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MACH_ARMADA_370=y +# CONFIG_MACH_ARMADA_375 is not set +CONFIG_MACH_ARMADA_38X=y +# CONFIG_MACH_ARMADA_39X is not set +CONFIG_MACH_ARMADA_XP=y +# CONFIG_MACH_DOVE is not set +CONFIG_MACH_MVEBU_ANY=y +CONFIG_MACH_MVEBU_V7=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MANGLE_BOOTARGS=y +CONFIG_MARVELL_PHY=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_I2C=y +CONFIG_MEMORY=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_MVSDIO=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_PXAV3=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_PXA3xx=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_MVEBU_CLK_COMMON=y +CONFIG_MVEBU_CLK_COREDIV=y +CONFIG_MVEBU_CLK_CPU=y +CONFIG_MVEBU_DEVBUS=y +CONFIG_MVEBU_MBUS=y +CONFIG_MVMDIO=y +CONFIG_MVNETA=y +CONFIG_MVNETA_BM=y +CONFIG_MVNETA_BM_ENABLE=y +CONFIG_MVPP2=y +CONFIG_MVSW61XX_PHY=y +CONFIG_MV_XOR=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_MV88E6XXX=y +CONFIG_NET_DSA_MV88E6XXX_GLOBAL2=y +CONFIG_NET_DSA_TAG_DSA=y +CONFIG_NET_DSA_TAG_EDSA=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_NO_BOOTMEM=y +CONFIG_NR_CPUS=4 +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_ORION_WATCHDOG=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_MVEBU=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_MVEBU_CP110_COMPHY is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_ARMADA_370=y +CONFIG_PINCTRL_ARMADA_38X=y +CONFIG_PINCTRL_ARMADA_XP=y +CONFIG_PINCTRL_MVEBU=y +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PJ4B_ERRATA_4742=y +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +CONFIG_PL310_ERRATA_753970=y +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_PLAT_ORION=y +CONFIG_PM_OPP=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=11 +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_RATIONAL=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_ARMADA38X=y +CONFIG_RTC_DRV_MV=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_SATA_MV=y +CONFIG_SATA_PMP=y +# CONFIG_SCHED_INFO is not set +CONFIG_SCSI=y +CONFIG_SENSORS_PWM_FAN=y +CONFIG_SENSORS_TMP421=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MVEBU_CONSOLE=y +CONFIG_SERIAL_MVEBU_UART=y +CONFIG_SFP=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SOC_BUS=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +# CONFIG_SPI_ARMADA_3700 is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_ORION=y +CONFIG_SRAM=y +CONFIG_SRAM_EXEC=y +CONFIG_SRCU=y +CONFIG_SWCONFIG=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_ORION=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_LEDS_TRIGGER_USBPORT=y +CONFIG_USB_PHY=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MVEBU=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/root/target/linux/mvebu/config-4.19 b/root/target/linux/mvebu/config-4.19 new file mode 100644 index 00000000..a2d815f9 --- /dev/null +++ b/root/target/linux/mvebu/config-4.19 @@ -0,0 +1,531 @@ +CONFIG_AHCI_MVEBU=y +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARMADA375_USBCLUSTER_PHY=y +CONFIG_ARMADA_370_CLK=y +CONFIG_ARMADA_370_XP_IRQ=y +CONFIG_ARMADA_370_XP_TIMER=y +CONFIG_ARMADA_375_CLK=y +CONFIG_ARMADA_38X_CLK=y +CONFIG_ARMADA_39X_CLK=y +CONFIG_ARMADA_THERMAL=y +CONFIG_ARMADA_XP_CLK=y +CONFIG_ARM_APPENDED_DTB=y +# CONFIG_ARM_ARMADA_37XX_CPUFREQ is not set +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GLOBAL_TIMER=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_MVEBU_V7_CPUIDLE=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y +CONFIG_ATA=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_FEROCEON_L2 is not set +CONFIG_CACHE_L2X0=y +# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_ISOLATION=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PJ4B=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRASH_DUMP=y +CONFIG_CRC16=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_CHACHA20_NEON is not set +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32_ARM_CE is not set +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_DEV_MARVELL_CESA=y +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256_ARM=y +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +CONFIG_CRYPTO_SHA512_ARM=y +CONFIG_CRYPTO_SIMD=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_INCLUDE="debug/8250.S" +CONFIG_DEBUG_MVEBU_UART0=y +# CONFIG_DEBUG_MVEBU_UART0_ALTERNATE is not set +# CONFIG_DEBUG_MVEBU_UART1_ALTERNATE is not set +CONFIG_DEBUG_UART_8250=y +# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set +CONFIG_DEBUG_UART_8250_SHIFT=2 +# CONFIG_DEBUG_UART_8250_WORD is not set +CONFIG_DEBUG_UART_PHYS=0xd0012000 +CONFIG_DEBUG_UART_VIRT=0xfec12000 +CONFIG_DEBUG_UNCOMPRESS=y +CONFIG_DEBUG_USER=y +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ENGINE_RAID=y +CONFIG_DMA_OF=y +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EXT4_FS=y +CONFIG_EXTCON=y +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_SECURITY is not set +# CONFIG_F2FS_FS_XATTR is not set +# CONFIG_F2FS_STAT_FS is not set +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MVEBU=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_SYSFS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWBM=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_OMAP=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_PERIODIC=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MV64XXX=y +# CONFIG_I2C_PXA is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_SRH=y +CONFIG_IPV6=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +# CONFIG_IWMMXT is not set +CONFIG_JBD2=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA963X=y +CONFIG_LEDS_TLC591XX=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MACH_ARMADA_370=y +CONFIG_MACH_ARMADA_375=y +CONFIG_MACH_ARMADA_38X=y +CONFIG_MACH_ARMADA_39X=y +CONFIG_MACH_ARMADA_XP=y +# CONFIG_MACH_DOVE is not set +CONFIG_MACH_MVEBU_ANY=y +CONFIG_MACH_MVEBU_V7=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MANGLE_BOOTARGS=y +CONFIG_MARVELL_PHY=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_I2C=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY=y +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_MVSDIO=y +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_PXAV3=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_MARVELL=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_MVEBU_CLK_COMMON=y +CONFIG_MVEBU_CLK_COREDIV=y +CONFIG_MVEBU_CLK_CPU=y +CONFIG_MVEBU_DEVBUS=y +CONFIG_MVEBU_MBUS=y +CONFIG_MVMDIO=y +CONFIG_MVNETA=y +CONFIG_MVNETA_BM=y +CONFIG_MVNETA_BM_ENABLE=y +CONFIG_MVPP2=y +CONFIG_MVSW61XX_PHY=y +CONFIG_MV_XOR=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_LEGACY=y +CONFIG_NET_DSA_MV88E6XXX=y +CONFIG_NET_DSA_MV88E6XXX_GLOBAL2=y +# CONFIG_NET_DSA_MV88E6XXX_PTP is not set +# CONFIG_NET_DSA_REALTEK_SMI is not set +CONFIG_NET_DSA_TAG_DSA=y +CONFIG_NET_DSA_TAG_EDSA=y +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_SWITCHDEV=y +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NF_LOG_IPV6 is not set +CONFIG_NF_TPROXY_IPV4=y +CONFIG_NLS=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_NO_BOOTMEM=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_ORION_WATCHDOG=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_MVEBU=y +# CONFIG_PCI_V3_SEMI is not set +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_MVEBU_CP110_COMPHY is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_ARMADA_370=y +CONFIG_PINCTRL_ARMADA_375=y +CONFIG_PINCTRL_ARMADA_38X=y +CONFIG_PINCTRL_ARMADA_39X=y +CONFIG_PINCTRL_ARMADA_XP=y +CONFIG_PINCTRL_MVEBU=y +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PJ4B_ERRATA_4742=y +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +CONFIG_PL310_ERRATA_753970=y +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_PLAT_ORION=y +CONFIG_PM_OPP=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=11 +CONFIG_PROC_VMCORE=y +CONFIG_PROC_VMCORE_DEVICE_DUMP=y +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_RATIONAL=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RSEQ=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_ARMADA38X=y +CONFIG_RTC_DRV_MV=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_SATA_MV=y +CONFIG_SATA_PMP=y +CONFIG_SCSI=y +CONFIG_SENSORS_PWM_FAN=y +CONFIG_SENSORS_TMP421=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MVEBU_CONSOLE=y +CONFIG_SERIAL_MVEBU_UART=y +CONFIG_SFP=y +CONFIG_SGL_ALLOC=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SOC_BUS=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +# CONFIG_SPI_ARMADA_3700 is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_ORION=y +CONFIG_SRAM=y +CONFIG_SRAM_EXEC=y +CONFIG_SRCU=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_SWCONFIG=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_ORION=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_LEDS_TRIGGER_USBPORT=y +CONFIG_USB_PHY=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MVEBU=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XDP_SOCKETS=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/root/target/linux/x86/config-4.19 b/root/target/linux/x86/config-4.19 new file mode 100644 index 00000000..80a94b24 --- /dev/null +++ b/root/target/linux/x86/config-4.19 @@ -0,0 +1,500 @@ +# CONFIG_60XX_WDT is not set +# CONFIG_64BIT is not set +# CONFIG_ACPI is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIX is not set +CONFIG_AMD_NB=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" +CONFIG_ARCH_DISCARD_MEMBLOCK=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_ARCH_HAS_REFCOUNT=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_ARCH_RANDOM=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ATA=y +CONFIG_ATA_GENERIC=y +CONFIG_ATA_PIIX=y +CONFIG_BINFMT_MISC=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y +CONFIG_CLKBLD_I8253=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKEVT_I8253=y +CONFIG_CLKSRC_I8253=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMPAT_32=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPU5_WDT is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_CYRIX_32=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_TRANSMETA_32=y +CONFIG_CPU_SUP_UMC_32=y +# CONFIG_CRASHLOG is not set +CONFIG_CRASH_CORE=y +CONFIG_CRC16=y +CONFIG_CRYPTO_AES_586=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CX_ECAT is not set +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_DCDBAS is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_DEBUG_ENTRY is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DEFAULT_IO_DELAY_TYPE=0 +# CONFIG_DELL_RBU is not set +CONFIG_DMA_DIRECT_OPS=y +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +CONFIG_DMI_SYSFS=y +CONFIG_DNOTIFY=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDD is not set +# CONFIG_EUROTECH_WDT is not set +CONFIG_EXT4_FS=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_STAT_FS=y +# CONFIG_F71808E_WDT is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FRAME_POINTER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FUSION=y +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LOGGING is not set +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SPI=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +# CONFIG_GEOS is not set +CONFIG_GLOB=y +# CONFIG_HANGCHECK_TIMER is not set +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_AOUT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ATOMIC_IOMAP=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_COPY_THREAD_TLS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DEBUG_STACKOVERFLOW=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HID=y +CONFIG_HIGHMEM=y +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHPTE is not set +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_TIMER=y +# CONFIG_HP_WATCHDOG is not set +# CONFIG_HUGETLBFS is not set +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_GEODE=y +CONFIG_HW_RANDOM_VIA=y +# CONFIG_HYPERVISOR_GUEST is not set +CONFIG_HZ_PERIODIC=y +CONFIG_I8253_LOCK=y +# CONFIG_I8K is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_IBM_RTL is not set +# CONFIG_IE6XX_WDT is not set +CONFIG_ILLEGAL_POINTER_VALUE=0 +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INSTRUCTION_DECODER=y +# CONFIG_INTEL_PCH_THERMAL is not set +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_INTEL_RDT is not set +# CONFIG_IOSF_MBI is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +# CONFIG_ISA is not set +CONFIG_ISA_DMA_API=y +# CONFIG_IT8712F_WDT is not set +# CONFIG_IT87_WDT is not set +# CONFIG_ITCO_WDT is not set +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_KEXEC=y +CONFIG_KEXEC_CORE=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_LEDS_CLEVO_MAIL is not set +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_M486 is not set +# CONFIG_M586 is not set +CONFIG_M586MMX=y +# CONFIG_M586TSC is not set +# CONFIG_M686 is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_MATOM is not set +# CONFIG_MCORE2 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MELAN is not set +CONFIG_MEMFD_CREATE=y +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=y +CONFIG_MICROCODE_AMD=y +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MIGRATION=y +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MTD is not set +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_NAMESPACES=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_KM=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_NEED_SG_DMA_LENGTH=y +# CONFIG_NET5501 is not set +# CONFIG_NET_NS is not set +CONFIG_NLS=y +# CONFIG_NOHIGHMEM is not set +CONFIG_NO_BOOTMEM=y +CONFIG_NR_CPUS=1 +CONFIG_NR_CPUS_DEFAULT=1 +CONFIG_NR_CPUS_RANGE_BEGIN=1 +CONFIG_NR_CPUS_RANGE_END=1 +# CONFIG_NSC_GPIO is not set +CONFIG_NVRAM=y +# CONFIG_OF is not set +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +# CONFIG_OLPC is not set +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_OUTPUT_FORMAT="elf32-i386" +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PC104=y +# CONFIG_PC8736x_GPIO is not set +# CONFIG_PC87413_WDT is not set +CONFIG_PCI=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GOANY=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +CONFIG_PCI_LABEL=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_PERF_EVENTS=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x1000000 +CONFIG_PMC_ATOM=y +CONFIG_POWER_SUPPLY=y +# CONFIG_PROCESSOR_SELECT is not set +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_RATIONAL=y +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y +CONFIG_RETPOLINE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SBC7240_WDT is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +CONFIG_SCSI=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCx200=y +CONFIG_SCx200HR_TIMER=y +# CONFIG_SCx200_GPIO is not set +# CONFIG_SCx200_WDT is not set +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_SERPORT=y +CONFIG_SG_POOL=y +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_SMSC_SCH311X_WDT is not set +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_TELCLOCK is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TINY_SRCU=y +# CONFIG_TOSHIBA is not set +CONFIG_UNWINDER_FRAME_POINTER=y +# CONFIG_UNWINDER_GUESS is not set +CONFIG_UP_LATE_INIT=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_HID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PCI=y +# CONFIG_USB_OHCI_HCD_PLATFORM is not set +CONFIG_USB_PCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +# CONFIG_USB_XHCI_PLATFORM is not set +# CONFIG_USERIO is not set +# CONFIG_USER_NS is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGA_CONSOLE=y +# CONFIG_VIA_WDT is not set +# CONFIG_VMWARE_VMCI is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_WAFER_WDT is not set +CONFIG_X86=y +CONFIG_X86_32=y +# CONFIG_X86_32_IRIS is not set +CONFIG_X86_32_LAZY_GS=y +CONFIG_X86_ALIGNMENT_16=y +# CONFIG_X86_ANCIENT_MCE is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_CMPXCHG64=y +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +# CONFIG_X86_CPUID is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +CONFIG_X86_F00F_BUG=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_GENERIC=y +# CONFIG_X86_GX_SUSPMOD is not set +# CONFIG_X86_INTEL_PSTATE is not set +CONFIG_X86_INTEL_UMIP=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_IO_APIC=y +CONFIG_X86_L1_CACHE_SHIFT=6 +# CONFIG_X86_LEGACY_VM86 is not set +CONFIG_X86_LOCAL_APIC=y +# CONFIG_X86_LONGRUN is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_AMD=y +# CONFIG_X86_MCE_INJECT is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MINIMUM_CPU_FAMILY=5 +CONFIG_X86_MPPARSE=y +CONFIG_X86_MSR=y +# CONFIG_X86_P4_CLOCKMOD is not set +CONFIG_X86_PAT=y +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_X86_POWERNOW_K6 is not set +# CONFIG_X86_POWERNOW_K7 is not set +# CONFIG_X86_PTDUMP is not set +# CONFIG_X86_REBOOTFIXUPS is not set +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_X86_RESERVE_LOW=64 +# CONFIG_X86_SMAP is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_SPEEDSTEP_ICH is not set +# CONFIG_X86_SPEEDSTEP_SMI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +CONFIG_X86_THERMAL_VECTOR=y +CONFIG_X86_TSC=y +CONFIG_X86_UP_APIC=y +CONFIG_X86_UP_IOAPIC=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_XZ_DEC_X86=y +CONFIG_ZLIB_INFLATE=y diff --git a/sign.sh b/sign.sh new file mode 100755 index 00000000..2d5ca9d0 --- /dev/null +++ b/sign.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +key=${1:-key-build} +path=${2:-x86_64} +[ -d $path/source/bin ] && [ -f "$key" ] && \ + find $path/source/bin \ + \( -name '*.img.gz' -or -name 'Packages' \) \ + -exec $path/source/staging_dir/host/bin/usign -S -m {} -s "$key" \;